зеркало из https://github.com/mozilla/moz-skia.git
Add support for kEmbeddedBitmapText_Flag to DirectWrite.
R=reed@google.com Review URL: https://codereview.chromium.org/263503004 git-svn-id: http://skia.googlecode.com/svn/trunk@14518 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
Родитель
1d146d431a
Коммит
058670b1e5
|
@ -22,7 +22,10 @@
|
|||
#include "SkGlyph.h"
|
||||
#include "SkHRESULT.h"
|
||||
#include "SkMaskGamma.h"
|
||||
#include "SkMatrix22.h"
|
||||
#include "SkOnce.h"
|
||||
#include "SkOTTable_EBLC.h"
|
||||
#include "SkOTTable_EBSC.h"
|
||||
#include "SkOTTable_head.h"
|
||||
#include "SkOTTable_hhea.h"
|
||||
#include "SkOTTable_OS_2.h"
|
||||
|
@ -449,7 +452,22 @@ private:
|
|||
const void* drawDWMask(const SkGlyph& glyph);
|
||||
|
||||
SkTDArray<uint8_t> fBits;
|
||||
/** The total matrix without the text height scale. */
|
||||
SkMatrix fSkXform;
|
||||
/** The total matrix without the text height scale. */
|
||||
DWRITE_MATRIX fXform;
|
||||
/** The non-rotational part of total matrix without the text height scale.
|
||||
* This is used to find the magnitude of gdi compatible advances.
|
||||
*/
|
||||
DWRITE_MATRIX fGsA;
|
||||
/** The inverse of the rotational part of the total matrix.
|
||||
* This is used to find the direction of gdi compatible advances.
|
||||
*/
|
||||
SkMatrix fG_inv;
|
||||
/** The text size to render with. */
|
||||
SkScalar fTextSizeRender;
|
||||
/** The text size to measure with. */
|
||||
SkScalar fTextSizeMeasure;
|
||||
SkAutoTUnref<DWriteFontTypeface> fTypeface;
|
||||
int fGlyphCount;
|
||||
DWRITE_RENDERING_MODE fRenderingMode;
|
||||
|
@ -570,32 +588,224 @@ static bool FindByDWriteFont(SkTypeface* face, SkTypeface::Style requestedStyle,
|
|||
wcscmp(dwFaceFontNameChar.get(), dwFontNameChar.get()) == 0;
|
||||
}
|
||||
|
||||
class AutoDWriteTable {
|
||||
public:
|
||||
AutoDWriteTable(IDWriteFontFace* fontFace, UINT32 beTag) : fFontFace(fontFace), fExists(FALSE) {
|
||||
// Any errors are ignored, user must check fExists anyway.
|
||||
fontFace->TryGetFontTable(beTag,
|
||||
reinterpret_cast<const void **>(&fData), &fSize, &fLock, &fExists);
|
||||
}
|
||||
~AutoDWriteTable() {
|
||||
if (fExists) {
|
||||
fFontFace->ReleaseFontTable(fLock);
|
||||
}
|
||||
}
|
||||
|
||||
const uint8_t* fData;
|
||||
UINT32 fSize;
|
||||
BOOL fExists;
|
||||
private:
|
||||
// Borrowed reference, the user must ensure the fontFace stays alive.
|
||||
IDWriteFontFace* fFontFace;
|
||||
void* fLock;
|
||||
};
|
||||
template<typename T> class AutoTDWriteTable : public AutoDWriteTable {
|
||||
public:
|
||||
static const UINT32 tag = DWRITE_MAKE_OPENTYPE_TAG(T::TAG0, T::TAG1, T::TAG2, T::TAG3);
|
||||
AutoTDWriteTable(IDWriteFontFace* fontFace) : AutoDWriteTable(fontFace, tag) { }
|
||||
|
||||
const T* get() const { return reinterpret_cast<const T*>(fData); }
|
||||
const T* operator->() const { return reinterpret_cast<const T*>(fData); }
|
||||
};
|
||||
|
||||
static bool hasBitmapStrike(DWriteFontTypeface* typeface, int size) {
|
||||
{
|
||||
AutoTDWriteTable<SkOTTableEmbeddedBitmapLocation> eblc(typeface->fDWriteFontFace.get());
|
||||
if (!eblc.fExists) {
|
||||
return false;
|
||||
}
|
||||
if (eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation)) {
|
||||
return false;
|
||||
}
|
||||
if (eblc->version != SkOTTableEmbeddedBitmapLocation::version_initial) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t numSizes = SkEndianSwap32(eblc->numSizes);
|
||||
if (eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation) +
|
||||
sizeof(SkOTTableEmbeddedBitmapLocation::BitmapSizeTable) * numSizes)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable* sizeTable =
|
||||
SkTAfter<const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable>(eblc.get());
|
||||
for (uint32_t i = 0; i < numSizes; ++i, ++sizeTable) {
|
||||
if (sizeTable->ppemX == size && sizeTable->ppemY == size) {
|
||||
// TODO: determine if we should dig through IndexSubTableArray/IndexSubTable
|
||||
// to determine the actual number of glyphs with bitmaps.
|
||||
|
||||
// TODO: Ensure that the bitmaps actually cover a significant portion of the strike.
|
||||
|
||||
//TODO: Endure that the bitmaps are bi-level.
|
||||
if (sizeTable->endGlyphIndex >= sizeTable->startGlyphIndex + 3) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
AutoTDWriteTable<SkOTTableEmbeddedBitmapScaling> ebsc(typeface->fDWriteFontFace.get());
|
||||
if (!ebsc.fExists) {
|
||||
return false;
|
||||
}
|
||||
if (ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling)) {
|
||||
return false;
|
||||
}
|
||||
if (ebsc->version != SkOTTableEmbeddedBitmapScaling::version_initial) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t numSizes = SkEndianSwap32(ebsc->numSizes);
|
||||
if (ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling) +
|
||||
sizeof(SkOTTableEmbeddedBitmapScaling::BitmapScaleTable) * numSizes)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable* scaleTable =
|
||||
SkTAfter<const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable>(ebsc.get());
|
||||
for (uint32_t i = 0; i < numSizes; ++i, ++scaleTable) {
|
||||
if (scaleTable->ppemX == size && scaleTable->ppemY == size) {
|
||||
// EBSC tables are normally only found in bitmap only fonts.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool bothZero(SkScalar a, SkScalar b) {
|
||||
return 0 == a && 0 == b;
|
||||
}
|
||||
|
||||
// returns false if there is any non-90-rotation or skew
|
||||
static bool isAxisAligned(const SkScalerContext::Rec& rec) {
|
||||
return 0 == rec.fPreSkewX &&
|
||||
(bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
|
||||
bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
|
||||
}
|
||||
|
||||
SkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface* typeface,
|
||||
const SkDescriptor* desc)
|
||||
: SkScalerContext(typeface, desc)
|
||||
, fTypeface(SkRef(typeface))
|
||||
, fGlyphCount(-1) {
|
||||
|
||||
fXform.m11 = SkScalarToFloat(fRec.fPost2x2[0][0]);
|
||||
fXform.m12 = SkScalarToFloat(fRec.fPost2x2[1][0]);
|
||||
fXform.m21 = SkScalarToFloat(fRec.fPost2x2[0][1]);
|
||||
fXform.m22 = SkScalarToFloat(fRec.fPost2x2[1][1]);
|
||||
fXform.dx = 0;
|
||||
fXform.dy = 0;
|
||||
// In general, all glyphs should use CLEARTYPE_NATURAL_SYMMETRIC
|
||||
// except when bi-level rendering is requested or there are embedded
|
||||
// bi-level bitmaps (and the embedded bitmap flag is set and no rotation).
|
||||
//
|
||||
// DirectWrite's IDWriteFontFace::GetRecommendedRenderingMode does not do
|
||||
// this. As a result, determine the actual size of the text and then see if
|
||||
// there are any embedded bi-level bitmaps of that size. If there are, then
|
||||
// force bitmaps by requesting bi-level rendering.
|
||||
//
|
||||
// FreeType allows for separate ppemX and ppemY, but DirectWrite assumes
|
||||
// square pixels and only uses ppemY. Therefore the transform must track any
|
||||
// non-uniform x-scale.
|
||||
//
|
||||
// Also, rotated glyphs should have the same absolute advance widths as
|
||||
// horizontal glyphs and the subpixel flag should not affect glyph shapes.
|
||||
|
||||
if (SkMask::kBW_Format == fRec.fMaskFormat) {
|
||||
// A is the total matrix.
|
||||
SkMatrix A;
|
||||
fRec.getSingleMatrix(&A);
|
||||
|
||||
// h is where A maps the horizontal baseline.
|
||||
SkPoint h = SkPoint::Make(SK_Scalar1, 0);
|
||||
A.mapPoints(&h, 1);
|
||||
|
||||
// G is the Givens Matrix for A (rotational matrix where GA[0][1] == 0).
|
||||
SkMatrix G;
|
||||
SkComputeGivensRotation(h, &G);
|
||||
|
||||
// GA is the matrix A with rotation removed.
|
||||
SkMatrix GA(G);
|
||||
GA.preConcat(A);
|
||||
|
||||
// realTextSize is the actual device size we want (as opposed to the size the user requested).
|
||||
// gdiTextSize is the size we request when GDI compatible.
|
||||
// If the scale is negative, this means the matrix will do the flip anyway.
|
||||
SkScalar realTextSize = SkScalarAbs(GA.get(SkMatrix::kMScaleY));
|
||||
// Due to floating point math, the lower bits are suspect. Round carefully.
|
||||
SkScalar roundedTextSize = SkScalarRoundToScalar(realTextSize * 64.0f) / 64.0f;
|
||||
SkScalar gdiTextSize = SkScalarFloorToScalar(roundedTextSize);
|
||||
if (gdiTextSize == 0) {
|
||||
gdiTextSize = SK_Scalar1;
|
||||
}
|
||||
|
||||
bool hasBitmap = fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag &&
|
||||
hasBitmapStrike(typeface, SkScalarTruncToInt(gdiTextSize));
|
||||
bool axisAligned = isAxisAligned(fRec);
|
||||
bool isBiLevel = SkMask::kBW_Format == fRec.fMaskFormat || (hasBitmap && axisAligned);
|
||||
|
||||
if (isBiLevel) {
|
||||
fTextSizeRender = gdiTextSize;
|
||||
fRenderingMode = DWRITE_RENDERING_MODE_ALIASED;
|
||||
fTextureType = DWRITE_TEXTURE_ALIASED_1x1;
|
||||
fTextSizeMeasure = gdiTextSize;
|
||||
fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
|
||||
} else {
|
||||
} else if (hasBitmap) {
|
||||
// If rotated but the horizontal text would have used a bitmap,
|
||||
// render high quality rotated glyphs using the bitmap metrics.
|
||||
fTextSizeRender = gdiTextSize;
|
||||
fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
|
||||
fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
|
||||
fTextSizeMeasure = gdiTextSize;
|
||||
fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
|
||||
} else {
|
||||
fTextSizeRender = realTextSize;
|
||||
fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
|
||||
fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
|
||||
fTextSizeMeasure = realTextSize;
|
||||
fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
|
||||
}
|
||||
|
||||
if (this->isSubpixel()) {
|
||||
fTextSizeMeasure = realTextSize;
|
||||
fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
|
||||
}
|
||||
|
||||
// Remove the realTextSize, as that is the text height scale currently in A.
|
||||
SkScalar scale = SkScalarInvert(realTextSize);
|
||||
|
||||
// fSkXform is the total matrix A without the text height scale.
|
||||
fSkXform = A;
|
||||
fSkXform.preScale(scale, scale); //remove the text height scale.
|
||||
|
||||
fXform.m11 = SkScalarToFloat(fSkXform.getScaleX());
|
||||
fXform.m12 = SkScalarToFloat(fSkXform.getSkewY());
|
||||
fXform.m21 = SkScalarToFloat(fSkXform.getSkewX());
|
||||
fXform.m22 = SkScalarToFloat(fSkXform.getScaleY());
|
||||
fXform.dx = 0;
|
||||
fXform.dy = 0;
|
||||
|
||||
// GsA is the non-rotational part of A without the text height scale.
|
||||
SkMatrix GsA(GA);
|
||||
GsA.preScale(scale, scale); //remove text height scale, G is rotational so reorders with scale.
|
||||
|
||||
fGsA.m11 = SkScalarToFloat(GsA.get(SkMatrix::kMScaleX));
|
||||
fGsA.m12 = SkScalarToFloat(GsA.get(SkMatrix::kMSkewY)); // This should be ~0.
|
||||
fGsA.m21 = SkScalarToFloat(GsA.get(SkMatrix::kMSkewX));
|
||||
fGsA.m22 = SkScalarToFloat(GsA.get(SkMatrix::kMScaleY));
|
||||
|
||||
// fG_inv is G inverse, which is fairly simple since G is 2x2 rotational.
|
||||
fG_inv.setAll(G.get(SkMatrix::kMScaleX), -G.get(SkMatrix::kMSkewX), G.get(SkMatrix::kMTransX),
|
||||
-G.get(SkMatrix::kMSkewY), G.get(SkMatrix::kMScaleY), G.get(SkMatrix::kMTransY),
|
||||
G.get(SkMatrix::kMPersp0), G.get(SkMatrix::kMPersp1), G.get(SkMatrix::kMPersp2));
|
||||
}
|
||||
|
||||
SkScalerContext_DW::~SkScalerContext_DW() {
|
||||
|
@ -631,9 +841,9 @@ void SkScalerContext_DW::generateAdvance(SkGlyph* glyph) {
|
|||
DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
|
||||
{
|
||||
HRVM(fTypeface->fDWriteFontFace->GetGdiCompatibleGlyphMetrics(
|
||||
fRec.fTextSize,
|
||||
fTextSizeMeasure,
|
||||
1.0f, // pixelsPerDip
|
||||
&fXform,
|
||||
&fGsA,
|
||||
DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode,
|
||||
&glyphId, 1,
|
||||
&gm),
|
||||
|
@ -645,7 +855,7 @@ void SkScalerContext_DW::generateAdvance(SkGlyph* glyph) {
|
|||
|
||||
DWRITE_FONT_METRICS dwfm;
|
||||
fTypeface->fDWriteFontFace->GetMetrics(&dwfm);
|
||||
SkScalar advanceX = SkScalarMulDiv(fRec.fTextSize,
|
||||
SkScalar advanceX = SkScalarMulDiv(fTextSizeMeasure,
|
||||
SkIntToScalar(gm.advanceWidth),
|
||||
SkIntToScalar(dwfm.designUnitsPerEm));
|
||||
|
||||
|
@ -654,9 +864,13 @@ void SkScalerContext_DW::generateAdvance(SkGlyph* glyph) {
|
|||
}
|
||||
|
||||
SkVector vecs[1] = { { advanceX, 0 } };
|
||||
SkMatrix mat;
|
||||
fRec.getMatrixFrom2x2(&mat);
|
||||
mat.mapVectors(vecs, SK_ARRAY_COUNT(vecs));
|
||||
if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
|
||||
DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
|
||||
{
|
||||
fG_inv.mapVectors(vecs, SK_ARRAY_COUNT(vecs));
|
||||
} else {
|
||||
fSkXform.mapVectors(vecs, SK_ARRAY_COUNT(vecs));
|
||||
}
|
||||
|
||||
glyph->fAdvanceX = SkScalarToFixed(vecs[0].fX);
|
||||
glyph->fAdvanceY = SkScalarToFixed(vecs[0].fY);
|
||||
|
@ -683,7 +897,7 @@ void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) {
|
|||
run.glyphCount = 1;
|
||||
run.glyphAdvances = &advance;
|
||||
run.fontFace = fTypeface->fDWriteFontFace.get();
|
||||
run.fontEmSize = SkScalarToFloat(fRec.fTextSize);
|
||||
run.fontEmSize = SkScalarToFloat(fTextSizeRender);
|
||||
run.bidiLevel = 0;
|
||||
run.glyphIndices = &glyphId;
|
||||
run.isSideways = FALSE;
|
||||
|
@ -728,7 +942,7 @@ void SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* mx,
|
|||
DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
|
||||
{
|
||||
fTypeface->fDWriteFontFace->GetGdiCompatibleMetrics(
|
||||
fRec.fTextSize,
|
||||
fTextSizeRender,
|
||||
1.0f, // pixelsPerDip
|
||||
&fXform,
|
||||
&dwfm);
|
||||
|
@ -738,28 +952,28 @@ void SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* mx,
|
|||
|
||||
SkScalar upem = SkIntToScalar(dwfm.designUnitsPerEm);
|
||||
if (mx) {
|
||||
mx->fTop = -fRec.fTextSize * SkIntToScalar(dwfm.ascent) / upem;
|
||||
mx->fTop = -fTextSizeRender * SkIntToScalar(dwfm.ascent) / upem;
|
||||
mx->fAscent = mx->fTop;
|
||||
mx->fDescent = fRec.fTextSize * SkIntToScalar(dwfm.descent) / upem;
|
||||
mx->fDescent = fTextSizeRender * SkIntToScalar(dwfm.descent) / upem;
|
||||
mx->fBottom = mx->fDescent;
|
||||
mx->fLeading = fRec.fTextSize * SkIntToScalar(dwfm.lineGap) / upem;
|
||||
mx->fXHeight = fRec.fTextSize * SkIntToScalar(dwfm.xHeight) / upem;
|
||||
mx->fUnderlineThickness = fRec.fTextSize * SkIntToScalar(dwfm.underlinePosition) / upem;
|
||||
mx->fUnderlinePosition = -(fRec.fTextSize * SkIntToScalar(dwfm.underlineThickness) / upem);
|
||||
mx->fLeading = fTextSizeRender * SkIntToScalar(dwfm.lineGap) / upem;
|
||||
mx->fXHeight = fTextSizeRender * SkIntToScalar(dwfm.xHeight) / upem;
|
||||
mx->fUnderlineThickness = fTextSizeRender * SkIntToScalar(dwfm.underlinePosition) / upem;
|
||||
mx->fUnderlinePosition = -(fTextSizeRender * SkIntToScalar(dwfm.underlineThickness) / upem);
|
||||
|
||||
mx->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag;
|
||||
mx->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
|
||||
}
|
||||
|
||||
if (my) {
|
||||
my->fTop = -fRec.fTextSize * SkIntToScalar(dwfm.ascent) / upem;
|
||||
my->fTop = -fTextSizeRender * SkIntToScalar(dwfm.ascent) / upem;
|
||||
my->fAscent = my->fTop;
|
||||
my->fDescent = fRec.fTextSize * SkIntToScalar(dwfm.descent) / upem;
|
||||
my->fDescent = fTextSizeRender * SkIntToScalar(dwfm.descent) / upem;
|
||||
my->fBottom = my->fDescent;
|
||||
my->fLeading = fRec.fTextSize * SkIntToScalar(dwfm.lineGap) / upem;
|
||||
my->fXHeight = fRec.fTextSize * SkIntToScalar(dwfm.xHeight) / upem;
|
||||
my->fUnderlineThickness = fRec.fTextSize * SkIntToScalar(dwfm.underlinePosition) / upem;
|
||||
my->fUnderlinePosition = -(fRec.fTextSize * SkIntToScalar(dwfm.underlineThickness) / upem);
|
||||
my->fLeading = fTextSizeRender * SkIntToScalar(dwfm.lineGap) / upem;
|
||||
my->fXHeight = fTextSizeRender * SkIntToScalar(dwfm.xHeight) / upem;
|
||||
my->fUnderlineThickness = fTextSizeRender * SkIntToScalar(dwfm.underlinePosition) / upem;
|
||||
my->fUnderlinePosition = -(fTextSizeRender * SkIntToScalar(dwfm.underlineThickness) / upem);
|
||||
|
||||
my->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag;
|
||||
my->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
|
||||
|
@ -888,7 +1102,7 @@ const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph) {
|
|||
run.glyphCount = 1;
|
||||
run.glyphAdvances = &advance;
|
||||
run.fontFace = fTypeface->fDWriteFontFace.get();
|
||||
run.fontEmSize = SkScalarToFloat(fRec.fTextSize);
|
||||
run.fontEmSize = SkScalarToFloat(fTextSizeRender);
|
||||
run.bidiLevel = 0;
|
||||
run.glyphIndices = &index;
|
||||
run.isSideways = FALSE;
|
||||
|
@ -966,7 +1180,7 @@ void SkScalerContext_DW::generatePath(const SkGlyph& glyph, SkPath* path) {
|
|||
uint16_t glyphId = glyph.getGlyphID();
|
||||
//TODO: convert to<->from DIUs? This would make a difference if hinting.
|
||||
//It may not be needed, it appears that DirectWrite only hints at em size.
|
||||
HRVM(fTypeface->fDWriteFontFace->GetGlyphRunOutline(SkScalarToFloat(fRec.fTextSize),
|
||||
HRVM(fTypeface->fDWriteFontFace->GetGlyphRunOutline(SkScalarToFloat(fTextSizeRender),
|
||||
&glyphId,
|
||||
NULL, //advances
|
||||
NULL, //offsets
|
||||
|
@ -976,9 +1190,7 @@ void SkScalerContext_DW::generatePath(const SkGlyph& glyph, SkPath* path) {
|
|||
geometryToPath.get()),
|
||||
"Could not create glyph outline.");
|
||||
|
||||
SkMatrix mat;
|
||||
fRec.getMatrixFrom2x2(&mat);
|
||||
path->transform(mat);
|
||||
path->transform(fSkXform);
|
||||
}
|
||||
|
||||
void DWriteFontTypeface::onGetFontDescriptor(SkFontDescriptor* desc,
|
||||
|
@ -1146,28 +1358,6 @@ int DWriteFontTypeface::onGetTableTags(SkFontTableTag tags[]) const {
|
|||
return stream.get() ? SkFontStream::GetTableTags(stream, ttcIndex, tags) : 0;
|
||||
}
|
||||
|
||||
class AutoDWriteTable {
|
||||
public:
|
||||
AutoDWriteTable(IDWriteFontFace* fontFace, UINT32 beTag) : fFontFace(fontFace), fExists(FALSE) {
|
||||
// Any errors are ignored, user must check fExists anyway.
|
||||
fontFace->TryGetFontTable(beTag,
|
||||
reinterpret_cast<const void **>(&fData), &fSize, &fLock, &fExists);
|
||||
}
|
||||
~AutoDWriteTable() {
|
||||
if (fExists) {
|
||||
fFontFace->ReleaseFontTable(fLock);
|
||||
}
|
||||
}
|
||||
|
||||
const uint8_t* fData;
|
||||
UINT32 fSize;
|
||||
BOOL fExists;
|
||||
private:
|
||||
// Borrowed reference, the user must ensure the fontFace stays alive.
|
||||
IDWriteFontFace* fFontFace;
|
||||
void* fLock;
|
||||
};
|
||||
|
||||
size_t DWriteFontTypeface::onGetTableData(SkFontTableTag tag, size_t offset,
|
||||
size_t length, void* data) const
|
||||
{
|
||||
|
@ -1260,7 +1450,6 @@ void DWriteFontTypeface::onFilterRec(SkScalerContext::Rec* rec) const {
|
|||
|
||||
unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag |
|
||||
SkScalerContext::kForceAutohinting_Flag |
|
||||
SkScalerContext::kEmbeddedBitmapText_Flag |
|
||||
SkScalerContext::kEmbolden_Flag |
|
||||
SkScalerContext::kLCD_BGROrder_Flag |
|
||||
SkScalerContext::kLCD_Vertical_Flag;
|
||||
|
@ -1362,14 +1551,6 @@ static bool getWidthAdvance(IDWriteFontFace* fontFace, int gId, int16_t* advance
|
|||
return true;
|
||||
}
|
||||
|
||||
template<typename T> class AutoTDWriteTable : public AutoDWriteTable {
|
||||
public:
|
||||
static const UINT32 tag = DWRITE_MAKE_OPENTYPE_TAG(T::TAG0, T::TAG1, T::TAG2, T::TAG3);
|
||||
AutoTDWriteTable(IDWriteFontFace* fontFace) : AutoDWriteTable(fontFace, tag) { }
|
||||
|
||||
const T* operator->() const { return reinterpret_cast<const T*>(fData); }
|
||||
};
|
||||
|
||||
SkAdvancedTypefaceMetrics* DWriteFontTypeface::onGetAdvancedTypefaceMetrics(
|
||||
SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
|
||||
const uint32_t* glyphIDs,
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright 2014 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkOTTable_EBDT_DEFINED
|
||||
#define SkOTTable_EBDT_DEFINED
|
||||
|
||||
#include "SkEndian.h"
|
||||
#include "SkOTTableTypes.h"
|
||||
#include "SkOTTable_head.h"
|
||||
#include "SkOTTable_loca.h"
|
||||
#include "SkTypedEnum.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
struct SkOTTableEmbeddedBitmapData {
|
||||
static const SK_OT_CHAR TAG0 = 'E';
|
||||
static const SK_OT_CHAR TAG1 = 'B';
|
||||
static const SK_OT_CHAR TAG2 = 'D';
|
||||
static const SK_OT_CHAR TAG3 = 'T';
|
||||
static const SK_OT_ULONG TAG = SkOTTableTAG<SkOTTableEmbeddedBitmapData>::value;
|
||||
|
||||
SK_OT_Fixed version;
|
||||
static const SK_OT_Fixed version_initial = SkTEndian_SwapBE32(0x00020000);
|
||||
|
||||
struct BigGlyphMetrics {
|
||||
SK_OT_BYTE height;
|
||||
SK_OT_BYTE width;
|
||||
SK_OT_CHAR horiBearingX;
|
||||
SK_OT_CHAR horiBearingY;
|
||||
SK_OT_BYTE horiAdvance;
|
||||
SK_OT_CHAR vertBearingX;
|
||||
SK_OT_CHAR vertBearingY;
|
||||
SK_OT_BYTE vertAdvance;
|
||||
};
|
||||
|
||||
struct SmallGlyphMetrics {
|
||||
SK_OT_BYTE height;
|
||||
SK_OT_BYTE width;
|
||||
SK_OT_CHAR bearingX;
|
||||
SK_OT_CHAR bearingY;
|
||||
SK_OT_BYTE advance;
|
||||
};
|
||||
|
||||
// Small metrics, byte-aligned data.
|
||||
struct Format1 {
|
||||
SmallGlyphMetrics smallGlyphMetrics;
|
||||
//SK_OT_BYTE[] byteAlignedBitmap;
|
||||
};
|
||||
|
||||
// Small metrics, bit-aligned data.
|
||||
struct Format2 {
|
||||
SmallGlyphMetrics smallGlyphMetrics;
|
||||
//SK_OT_BYTE[] bitAlignedBitmap;
|
||||
};
|
||||
|
||||
// Format 3 is not used.
|
||||
|
||||
// EBLC metrics (IndexSubTable::header::indexFormat 2 or 5), compressed data.
|
||||
// Only used on Mac.
|
||||
struct Format4 {
|
||||
SK_OT_ULONG whiteTreeOffset;
|
||||
SK_OT_ULONG blackTreeOffset;
|
||||
SK_OT_ULONG glyphDataOffset;
|
||||
};
|
||||
|
||||
// EBLC metrics (IndexSubTable::header::indexFormat 2 or 5), bit-aligned data.
|
||||
struct Format5 {
|
||||
//SK_OT_BYTE[] bitAlignedBitmap;
|
||||
};
|
||||
|
||||
// Big metrics, byte-aligned data.
|
||||
struct Format6 {
|
||||
BigGlyphMetrics bigGlyphMetrics;
|
||||
//SK_OT_BYTE[] byteAlignedBitmap;
|
||||
};
|
||||
|
||||
// Big metrics, bit-aligned data.
|
||||
struct Format7 {
|
||||
BigGlyphMetrics bigGlyphMetrics;
|
||||
//SK_OT_BYTE[] bitAlignedBitmap;
|
||||
};
|
||||
|
||||
struct EBDTComponent {
|
||||
SK_OT_USHORT glyphCode; // Component glyph code
|
||||
SK_OT_CHAR xOffset; // Position of component left
|
||||
SK_OT_CHAR yOffset; // Position of component top
|
||||
};
|
||||
|
||||
struct Format8 {
|
||||
SmallGlyphMetrics smallMetrics; // Metrics information for the glyph
|
||||
SK_OT_BYTE pad; // Pad to short boundary
|
||||
SK_OT_USHORT numComponents; // Number of components
|
||||
//EBDTComponent componentArray[numComponents]; // Glyph code, offset array
|
||||
};
|
||||
|
||||
struct Format9 {
|
||||
BigGlyphMetrics bigMetrics; // Metrics information for the glyph
|
||||
SK_OT_USHORT numComponents; // Number of components
|
||||
//EBDTComponent componentArray[numComponents]; // Glyph code, offset array
|
||||
};
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* Copyright 2014 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkOTTable_EBLC_DEFINED
|
||||
#define SkOTTable_EBLC_DEFINED
|
||||
|
||||
#include "SkEndian.h"
|
||||
#include "SkOTTable_EBDT.h"
|
||||
#include "SkOTTableTypes.h"
|
||||
#include "SkTypedEnum.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
struct SkOTTableEmbeddedBitmapLocation {
|
||||
static const SK_OT_CHAR TAG0 = 'E';
|
||||
static const SK_OT_CHAR TAG1 = 'B';
|
||||
static const SK_OT_CHAR TAG2 = 'L';
|
||||
static const SK_OT_CHAR TAG3 = 'C';
|
||||
static const SK_OT_ULONG TAG = SkOTTableTAG<SkOTTableEmbeddedBitmapLocation>::value;
|
||||
|
||||
SK_OT_Fixed version;
|
||||
static const SK_OT_Fixed version_initial = SkTEndian_SwapBE32(0x00020000);
|
||||
|
||||
SK_OT_ULONG numSizes;
|
||||
|
||||
struct SbitLineMetrics {
|
||||
SK_OT_CHAR ascender;
|
||||
SK_OT_CHAR descender;
|
||||
SK_OT_BYTE widthMax;
|
||||
SK_OT_CHAR caretSlopeNumerator;
|
||||
SK_OT_CHAR caretSlopeDenominator;
|
||||
SK_OT_CHAR caretOffset;
|
||||
SK_OT_CHAR minOriginSB;
|
||||
SK_OT_CHAR minAdvanceSB;
|
||||
SK_OT_CHAR maxBeforeBL;
|
||||
SK_OT_CHAR minAfterBL;
|
||||
SK_OT_CHAR pad1;
|
||||
SK_OT_CHAR pad2;
|
||||
};
|
||||
|
||||
struct BitmapSizeTable {
|
||||
SK_OT_ULONG indexSubTableArrayOffset; //offset to indexSubtableArray from beginning of EBLC.
|
||||
SK_OT_ULONG indexTablesSize; //number of bytes in corresponding index subtables and array
|
||||
SK_OT_ULONG numberOfIndexSubTables; //an index subtable for each range or format change
|
||||
SK_OT_ULONG colorRef; //not used; set to 0.
|
||||
SbitLineMetrics hori; //line metrics for text rendered horizontally
|
||||
SbitLineMetrics vert; //line metrics for text rendered vertically
|
||||
SK_OT_USHORT startGlyphIndex; //lowest glyph index for this size
|
||||
SK_OT_USHORT endGlyphIndex; //highest glyph index for this size
|
||||
SK_OT_BYTE ppemX; //horizontal pixels per Em
|
||||
SK_OT_BYTE ppemY; //vertical pixels per Em
|
||||
struct BitDepth {
|
||||
SK_TYPED_ENUM(Value, SK_OT_BYTE,
|
||||
((BW, 1))
|
||||
((Gray4, 2))
|
||||
((Gray16, 4))
|
||||
((Gray256, 8))
|
||||
SK_SEQ_END,
|
||||
SK_SEQ_END)
|
||||
SK_OT_BYTE value;
|
||||
} bitDepth; //the Microsoft rasterizer v.1.7 or greater supports
|
||||
union Flags {
|
||||
struct Field {
|
||||
//0-7
|
||||
SK_OT_BYTE_BITFIELD(
|
||||
Horizontal, // Horizontal small glyph metrics
|
||||
Vertical, // Vertical small glyph metrics
|
||||
Reserved02,
|
||||
Reserved03,
|
||||
Reserved04,
|
||||
Reserved05,
|
||||
Reserved06,
|
||||
Reserved07)
|
||||
} field;
|
||||
struct Raw {
|
||||
static const SK_OT_CHAR Horizontal = 1u << 0;
|
||||
static const SK_OT_CHAR Vertical = 1u << 1;
|
||||
SK_OT_CHAR value;
|
||||
} raw;
|
||||
} flags;
|
||||
}; //bitmapSizeTable[numSizes];
|
||||
|
||||
struct IndexSubTableArray {
|
||||
SK_OT_USHORT firstGlyphIndex; //first glyph code of this range
|
||||
SK_OT_USHORT lastGlyphIndex; //last glyph code of this range (inclusive)
|
||||
SK_OT_ULONG additionalOffsetToIndexSubtable; //add to BitmapSizeTable::indexSubTableArrayOffset to get offset from beginning of 'EBLC'
|
||||
}; //indexSubTableArray[BitmapSizeTable::numberOfIndexSubTables];
|
||||
|
||||
struct IndexSubHeader {
|
||||
SK_OT_USHORT indexFormat; //format of this indexSubTable
|
||||
SK_OT_USHORT imageFormat; //format of 'EBDT' image data
|
||||
SK_OT_ULONG imageDataOffset; //offset to image data in 'EBDT' table
|
||||
};
|
||||
|
||||
// Variable metrics glyphs with 4 byte offsets
|
||||
struct IndexSubTable1 {
|
||||
IndexSubHeader header;
|
||||
//SK_OT_ULONG offsetArray[lastGlyphIndex - firstGlyphIndex + 1 + 1]; //last element points to one past end of last glyph
|
||||
//glyphData = offsetArray[glyphIndex - firstGlyphIndex] + imageDataOffset
|
||||
};
|
||||
|
||||
// All Glyphs have identical metrics
|
||||
struct IndexSubTable2 {
|
||||
IndexSubHeader header;
|
||||
SK_OT_ULONG imageSize; // all glyphs are of the same size
|
||||
SkOTTableEmbeddedBitmapData::BigGlyphMetrics bigMetrics; // all glyphs have the same metrics; glyph data may be compressed, byte-aligned, or bit-aligned
|
||||
};
|
||||
|
||||
// Variable metrics glyphs with 2 byte offsets
|
||||
struct IndexSubTable3 {
|
||||
IndexSubHeader header;
|
||||
//SK_OT_USHORT offsetArray[lastGlyphIndex - firstGlyphIndex + 1 + 1]; //last element points to one past end of last glyph, may have extra element to force even number of elements
|
||||
//glyphData = offsetArray[glyphIndex - firstGlyphIndex] + imageDataOffset
|
||||
};
|
||||
|
||||
// Variable metrics glyphs with sparse glyph codes
|
||||
struct IndexSubTable4 {
|
||||
IndexSubHeader header;
|
||||
SK_OT_ULONG numGlyphs;
|
||||
struct CodeOffsetPair {
|
||||
SK_OT_USHORT glyphCode;
|
||||
SK_OT_USHORT offset; //location in EBDT
|
||||
}; //glyphArray[numGlyphs+1]
|
||||
};
|
||||
|
||||
// Constant metrics glyphs with sparse glyph codes
|
||||
struct IndexSubTable5 {
|
||||
IndexSubHeader header;
|
||||
SK_OT_ULONG imageSize; //all glyphs have the same data size
|
||||
SkOTTableEmbeddedBitmapData::BigGlyphMetrics bigMetrics; //all glyphs have the same metrics
|
||||
SK_OT_ULONG numGlyphs;
|
||||
//SK_OT_USHORT glyphCodeArray[numGlyphs] //must have even number of entries (set pad to 0)
|
||||
};
|
||||
|
||||
union IndexSubTable {
|
||||
IndexSubHeader header;
|
||||
IndexSubTable1 format1;
|
||||
IndexSubTable2 format2;
|
||||
IndexSubTable3 format3;
|
||||
IndexSubTable4 format4;
|
||||
IndexSubTable5 format5;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright 2014 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkOTTable_EBSC_DEFINED
|
||||
#define SkOTTable_EBSC_DEFINED
|
||||
|
||||
#include "SkEndian.h"
|
||||
#include "SkOTTable_EBLC.h"
|
||||
#include "SkOTTableTypes.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
struct SkOTTableEmbeddedBitmapScaling {
|
||||
static const SK_OT_CHAR TAG0 = 'E';
|
||||
static const SK_OT_CHAR TAG1 = 'S';
|
||||
static const SK_OT_CHAR TAG2 = 'B';
|
||||
static const SK_OT_CHAR TAG3 = 'C';
|
||||
static const SK_OT_ULONG TAG = SkOTTableTAG<SkOTTableEmbeddedBitmapScaling>::value;
|
||||
|
||||
SK_OT_Fixed version;
|
||||
static const SK_OT_Fixed version_initial = SkTEndian_SwapBE32(0x00020000);
|
||||
|
||||
SK_OT_ULONG numSizes;
|
||||
|
||||
struct BitmapScaleTable {
|
||||
SkOTTableEmbeddedBitmapLocation::SbitLineMetrics hori;
|
||||
SkOTTableEmbeddedBitmapLocation::SbitLineMetrics vert;
|
||||
SK_OT_BYTE ppemX; //target horizontal pixels per EM
|
||||
SK_OT_BYTE ppemY; //target vertical pixels per EM
|
||||
SK_OT_BYTE substitutePpemX; //use bitmaps of this size
|
||||
SK_OT_BYTE substitutePpemY; //use bitmaps of this size
|
||||
}; //bitmapScaleTable[numSizes];
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif
|
Загрузка…
Ссылка в новой задаче