OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkTypes.h" | 8 #include "SkTypes.h" |
9 #undef GetGlyphIndices | 9 #undef GetGlyphIndices |
10 | 10 |
11 #include "SkDWrite.h" | 11 #include "SkDWrite.h" |
12 #include "SkDWriteGeometrySink.h" | 12 #include "SkDWriteGeometrySink.h" |
13 #include "SkEndian.h" | 13 #include "SkEndian.h" |
14 #include "SkGlyph.h" | 14 #include "SkGlyph.h" |
15 #include "SkHRESULT.h" | 15 #include "SkHRESULT.h" |
16 #include "SkMaskGamma.h" | 16 #include "SkMaskGamma.h" |
17 #include "SkMatrix22.h" | 17 #include "SkMatrix22.h" |
18 #include "SkOTTable_EBLC.h" | 18 #include "SkOTTable_EBLC.h" |
19 #include "SkOTTable_EBSC.h" | 19 #include "SkOTTable_EBSC.h" |
20 #include "SkOTTable_gasp.h" | |
20 #include "SkPath.h" | 21 #include "SkPath.h" |
21 #include "SkScalerContext.h" | 22 #include "SkScalerContext.h" |
22 #include "SkScalerContext_win_dw.h" | 23 #include "SkScalerContext_win_dw.h" |
23 #include "SkTScopedComPtr.h" | 24 #include "SkTScopedComPtr.h" |
24 #include "SkTypeface_win_dw.h" | 25 #include "SkTypeface_win_dw.h" |
25 | 26 |
26 #include <dwrite.h> | 27 #include <dwrite.h> |
27 | 28 |
28 static bool isLCD(const SkScalerContext::Rec& rec) { | 29 static bool isLCD(const SkScalerContext::Rec& rec) { |
29 return SkMask::kLCD16_Format == rec.fMaskFormat || | 30 return SkMask::kLCD16_Format == rec.fMaskFormat || |
30 SkMask::kLCD32_Format == rec.fMaskFormat; | 31 SkMask::kLCD32_Format == rec.fMaskFormat; |
31 } | 32 } |
32 | 33 |
33 static bool hasBitmapStrike(DWriteFontTypeface* typeface, int size) { | 34 /** A PPEMRange is inclusive, [min, max]. */ |
35 struct PPEMRange { | |
36 int min; | |
37 int max; | |
38 }; | |
39 | |
40 /** If the rendering mode for the specified 'size' is gridfit, | |
41 * then return true and place the gridfit range into 'range'. | |
42 * Otherwise, return false, and leave 'range' alone. | |
43 */ | |
44 static bool renderingModeIsGridfit(DWriteFontTypeface* typeface, int size, PPEMR ange* range) { | |
mtklein
2014/06/23 14:59:20
static void expand_range_if_gridfit_only?
bungeman-skia
2014/06/23 15:13:49
Done.
| |
45 AutoTDWriteTable<SkOTTableGridAndScanProcedure> gasp(typeface->fDWriteFontFa ce.get()); | |
46 if (!gasp.fExists) { | |
47 return false; | |
48 } | |
49 if (gasp.fSize < sizeof(SkOTTableGridAndScanProcedure)) { | |
50 return false; | |
51 } | |
52 if (gasp->version != SkOTTableGridAndScanProcedure::version0 && | |
53 gasp->version != SkOTTableGridAndScanProcedure::version1) | |
54 { | |
55 return false; | |
56 } | |
57 | |
58 uint16_t numRanges = SkEndianSwap16(gasp->numRanges); | |
59 if (numRanges > 1024 || | |
60 gasp.fSize < sizeof(SkOTTableGridAndScanProcedure) + | |
61 sizeof(SkOTTableGridAndScanProcedure::GaspRange) * numRange s) | |
62 { | |
63 return false; | |
64 } | |
65 | |
66 const SkOTTableGridAndScanProcedure::GaspRange* rangeTable = | |
67 SkTAfter<const SkOTTableGridAndScanProcedure::GaspRange>(gasp.get()) ; | |
68 int minPPEM = -1; | |
69 for (uint16_t i = 0; i < numRanges; ++i, ++rangeTable) { | |
70 int maxPPEM = SkEndianSwap16(rangeTable->maxPPEM); | |
71 if (minPPEM < size && size <= maxPPEM && | |
72 rangeTable->flags.raw.value == SkOTTableGridAndScanProcedure::GaspRa nge::behavior::Raw::GridfitMask) | |
mtklein
2014/06/23 14:59:20
// _only_ gridfit
bungeman-skia
2014/06/23 15:13:49
Done.
| |
73 { | |
74 range->min = minPPEM + 1; | |
75 range->max = maxPPEM; | |
76 return true; | |
77 } | |
78 minPPEM = maxPPEM; | |
79 } | |
80 | |
81 return false; | |
82 } | |
83 | |
84 static bool hasBitmapStrike(DWriteFontTypeface* typeface, PPEMRange range) { | |
mtklein
2014/06/23 14:59:20
has_bitmap_strike, etc.
bungeman-skia
2014/06/23 15:13:49
Done.
| |
34 { | 85 { |
35 AutoTDWriteTable<SkOTTableEmbeddedBitmapLocation> eblc(typeface->fDWrite FontFace.get()); | 86 AutoTDWriteTable<SkOTTableEmbeddedBitmapLocation> eblc(typeface->fDWrite FontFace.get()); |
36 if (!eblc.fExists) { | 87 if (!eblc.fExists) { |
37 return false; | 88 return false; |
38 } | 89 } |
39 if (eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation)) { | 90 if (eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation)) { |
40 return false; | 91 return false; |
41 } | 92 } |
42 if (eblc->version != SkOTTableEmbeddedBitmapLocation::version_initial) { | 93 if (eblc->version != SkOTTableEmbeddedBitmapLocation::version_initial) { |
43 return false; | 94 return false; |
44 } | 95 } |
45 | 96 |
46 uint32_t numSizes = SkEndianSwap32(eblc->numSizes); | 97 uint32_t numSizes = SkEndianSwap32(eblc->numSizes); |
47 if (eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation) + | 98 if (numSizes > 1024 || |
99 eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation) + | |
48 sizeof(SkOTTableEmbeddedBitmapLocation::BitmapSizeTable ) * numSizes) | 100 sizeof(SkOTTableEmbeddedBitmapLocation::BitmapSizeTable ) * numSizes) |
49 { | 101 { |
50 return false; | 102 return false; |
51 } | 103 } |
52 | 104 |
53 const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable* sizeTable = | 105 const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable* sizeTable = |
54 SkTAfter<const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable> (eblc.get()); | 106 SkTAfter<const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable> (eblc.get()); |
55 for (uint32_t i = 0; i < numSizes; ++i, ++sizeTable) { | 107 for (uint32_t i = 0; i < numSizes; ++i, ++sizeTable) { |
56 if (sizeTable->ppemX == size && sizeTable->ppemY == size) { | 108 if (sizeTable->ppemX == sizeTable->ppemY && |
109 range.min <= sizeTable->ppemX && sizeTable->ppemX <= range.max) | |
110 { | |
57 // TODO: determine if we should dig through IndexSubTableArray/I ndexSubTable | 111 // TODO: determine if we should dig through IndexSubTableArray/I ndexSubTable |
58 // to determine the actual number of glyphs with bitmaps. | 112 // to determine the actual number of glyphs with bitmaps. |
59 | 113 |
60 // TODO: Ensure that the bitmaps actually cover a significant po rtion of the strike. | 114 // TODO: Ensure that the bitmaps actually cover a significant po rtion of the strike. |
61 | 115 |
62 //TODO: Endure that the bitmaps are bi-level. | 116 // TODO: Ensure that the bitmaps are bi-level? |
63 if (sizeTable->endGlyphIndex >= sizeTable->startGlyphIndex + 3) { | 117 if (sizeTable->endGlyphIndex >= sizeTable->startGlyphIndex + 3) { |
64 return true; | 118 return true; |
65 } | 119 } |
66 } | 120 } |
67 } | 121 } |
68 } | 122 } |
69 | 123 |
70 { | 124 { |
71 AutoTDWriteTable<SkOTTableEmbeddedBitmapScaling> ebsc(typeface->fDWriteF ontFace.get()); | 125 AutoTDWriteTable<SkOTTableEmbeddedBitmapScaling> ebsc(typeface->fDWriteF ontFace.get()); |
72 if (!ebsc.fExists) { | 126 if (!ebsc.fExists) { |
73 return false; | 127 return false; |
74 } | 128 } |
75 if (ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling)) { | 129 if (ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling)) { |
76 return false; | 130 return false; |
77 } | 131 } |
78 if (ebsc->version != SkOTTableEmbeddedBitmapScaling::version_initial) { | 132 if (ebsc->version != SkOTTableEmbeddedBitmapScaling::version_initial) { |
79 return false; | 133 return false; |
80 } | 134 } |
81 | 135 |
82 uint32_t numSizes = SkEndianSwap32(ebsc->numSizes); | 136 uint32_t numSizes = SkEndianSwap32(ebsc->numSizes); |
83 if (ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling) + | 137 if (numSizes > 1024 || |
138 ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling) + | |
84 sizeof(SkOTTableEmbeddedBitmapScaling::BitmapScaleTable ) * numSizes) | 139 sizeof(SkOTTableEmbeddedBitmapScaling::BitmapScaleTable ) * numSizes) |
85 { | 140 { |
86 return false; | 141 return false; |
87 } | 142 } |
88 | 143 |
89 const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable* scaleTable = | 144 const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable* scaleTable = |
90 SkTAfter<const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable> (ebsc.get()); | 145 SkTAfter<const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable> (ebsc.get()); |
91 for (uint32_t i = 0; i < numSizes; ++i, ++scaleTable) { | 146 for (uint32_t i = 0; i < numSizes; ++i, ++scaleTable) { |
92 if (scaleTable->ppemX == size && scaleTable->ppemY == size) { | 147 if (scaleTable->ppemX == scaleTable->ppemY && |
148 range.min <= scaleTable->ppemX && scaleTable->ppemX <= range.max ) { | |
93 // EBSC tables are normally only found in bitmap only fonts. | 149 // EBSC tables are normally only found in bitmap only fonts. |
94 return true; | 150 return true; |
95 } | 151 } |
96 } | 152 } |
97 } | 153 } |
98 | 154 |
99 return false; | 155 return false; |
100 } | 156 } |
101 | 157 |
102 static bool bothZero(SkScalar a, SkScalar b) { | 158 static bool bothZero(SkScalar a, SkScalar b) { |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
152 // gdiTextSize is the size we request when GDI compatible. | 208 // gdiTextSize is the size we request when GDI compatible. |
153 // If the scale is negative, this means the matrix will do the flip anyway. | 209 // If the scale is negative, this means the matrix will do the flip anyway. |
154 SkScalar realTextSize = SkScalarAbs(GA.get(SkMatrix::kMScaleY)); | 210 SkScalar realTextSize = SkScalarAbs(GA.get(SkMatrix::kMScaleY)); |
155 // Due to floating point math, the lower bits are suspect. Round carefully. | 211 // Due to floating point math, the lower bits are suspect. Round carefully. |
156 SkScalar gdiTextSize = SkScalarRoundToScalar(realTextSize * 64.0f) / 64.0f; | 212 SkScalar gdiTextSize = SkScalarRoundToScalar(realTextSize * 64.0f) / 64.0f; |
157 if (gdiTextSize == 0) { | 213 if (gdiTextSize == 0) { |
158 gdiTextSize = SK_Scalar1; | 214 gdiTextSize = SK_Scalar1; |
159 } | 215 } |
160 | 216 |
161 bool bitmapRequested = SkToBool(fRec.fFlags & SkScalerContext::kEmbeddedBitm apText_Flag); | 217 bool bitmapRequested = SkToBool(fRec.fFlags & SkScalerContext::kEmbeddedBitm apText_Flag); |
162 bool hasBitmap = false; | 218 bool treatLikeBitmap = false; |
163 bool axisAlignedBitmap = false; | 219 bool axisAlignedBitmap = false; |
164 if (bitmapRequested) { | 220 if (bitmapRequested) { |
165 hasBitmap = hasBitmapStrike(typeface, SkScalarTruncToInt(gdiTextSize)); | 221 int bitmapPPEM = SkScalarTruncToInt(gdiTextSize); |
222 PPEMRange range = { bitmapPPEM, bitmapPPEM}; | |
mtklein
2014/06/23 14:59:20
This would be a good place to explain why we're do
bungeman-skia
2014/06/23 15:13:49
Done.
| |
223 #ifndef SK_IGNORE_DWRITE_RENDERING_FIX | |
224 renderingModeIsGridfit(typeface, bitmapPPEM, &range); | |
225 #endif | |
226 treatLikeBitmap = hasBitmapStrike(typeface, range); | |
227 | |
166 axisAlignedBitmap = isAxisAligned(fRec); | 228 axisAlignedBitmap = isAxisAligned(fRec); |
167 } | 229 } |
168 | 230 |
169 // If the user requested aliased, do so with aliased compatible metrics. | 231 // If the user requested aliased, do so with aliased compatible metrics. |
170 if (SkMask::kBW_Format == fRec.fMaskFormat) { | 232 if (SkMask::kBW_Format == fRec.fMaskFormat) { |
171 fTextSizeRender = gdiTextSize; | 233 fTextSizeRender = gdiTextSize; |
172 fRenderingMode = DWRITE_RENDERING_MODE_ALIASED; | 234 fRenderingMode = DWRITE_RENDERING_MODE_ALIASED; |
173 fTextureType = DWRITE_TEXTURE_ALIASED_1x1; | 235 fTextureType = DWRITE_TEXTURE_ALIASED_1x1; |
174 fTextSizeMeasure = gdiTextSize; | 236 fTextSizeMeasure = gdiTextSize; |
175 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; | 237 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; |
176 | 238 |
177 // If we can use a bitmap, use gdi classic rendering and measurement. | 239 // If we can use a bitmap, use gdi classic rendering and measurement. |
178 // This will not always provide a bitmap, but matches expected behavior. | 240 // This will not always provide a bitmap, but matches expected behavior. |
179 } else if (hasBitmap && axisAlignedBitmap) { | 241 } else if (treatLikeBitmap && axisAlignedBitmap) { |
180 fTextSizeRender = gdiTextSize; | 242 fTextSizeRender = gdiTextSize; |
181 fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC; | 243 fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC; |
182 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; | 244 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; |
183 fTextSizeMeasure = gdiTextSize; | 245 fTextSizeMeasure = gdiTextSize; |
184 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; | 246 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; |
185 | 247 |
186 // If rotated but the horizontal text could have used a bitmap, | 248 // If rotated but the horizontal text could have used a bitmap, |
187 // render high quality rotated glyphs but measure using bitmap metrics. | 249 // render high quality rotated glyphs but measure using bitmap metrics. |
188 } else if (hasBitmap) { | 250 } else if (treatLikeBitmap) { |
189 fTextSizeRender = gdiTextSize; | 251 fTextSizeRender = gdiTextSize; |
190 fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC; | 252 fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC; |
191 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; | 253 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; |
192 fTextSizeMeasure = gdiTextSize; | 254 fTextSizeMeasure = gdiTextSize; |
193 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; | 255 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; |
194 | 256 |
195 // The normal case is to use natural symmetric rendering and linear metrics. | 257 // The normal case is to use natural symmetric rendering and linear metrics. |
196 } else { | 258 } else { |
197 fTextSizeRender = realTextSize; | 259 fTextSizeRender = realTextSize; |
198 fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC; | 260 fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC; |
(...skipping 411 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
610 NULL, //advances | 672 NULL, //advances |
611 NULL, //offsets | 673 NULL, //offsets |
612 1, //num glyphs | 674 1, //num glyphs |
613 FALSE, //sideways | 675 FALSE, //sideways |
614 FALSE, //rtl | 676 FALSE, //rtl |
615 geometryToPath.get()), | 677 geometryToPath.get()), |
616 "Could not create glyph outline."); | 678 "Could not create glyph outline."); |
617 | 679 |
618 path->transform(fSkXform); | 680 path->transform(fSkXform); |
619 } | 681 } |
OLD | NEW |