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, then place | |
41 * the gridfit range into 'range'. Otherwise, leave 'range' alone. | |
42 */ | |
43 static void expand_range_if_gridfit_only(DWriteFontTypeface* typeface, int size, PPEMRange* range) { | |
44 AutoTDWriteTable<SkOTTableGridAndScanProcedure> gasp(typeface->fDWriteFontFa ce.get()); | |
45 if (!gasp.fExists) { | |
46 return; | |
47 } | |
48 if (gasp.fSize < sizeof(SkOTTableGridAndScanProcedure)) { | |
49 return; | |
50 } | |
51 if (gasp->version != SkOTTableGridAndScanProcedure::version0 && | |
52 gasp->version != SkOTTableGridAndScanProcedure::version1) | |
53 { | |
54 return ; | |
55 } | |
56 | |
57 uint16_t numRanges = SkEndianSwap16(gasp->numRanges); | |
58 if (numRanges > 1024 || | |
59 gasp.fSize < sizeof(SkOTTableGridAndScanProcedure) + | |
60 sizeof(SkOTTableGridAndScanProcedure::GaspRange) * numRange s) | |
61 { | |
62 return; | |
63 } | |
64 | |
65 const SkOTTableGridAndScanProcedure::GaspRange* rangeTable = | |
66 SkTAfter<const SkOTTableGridAndScanProcedure::GaspRange>(gasp.get()) ; | |
67 int minPPEM = -1; | |
68 for (uint16_t i = 0; i < numRanges; ++i, ++rangeTable) { | |
69 int maxPPEM = SkEndianSwap16(rangeTable->maxPPEM); | |
70 // Test that the size is in range and the range is gridfit only. | |
71 if (minPPEM < size && size <= maxPPEM && | |
72 rangeTable->flags.raw.value == SkOTTableGridAndScanProcedure::GaspRa nge::behavior::Raw::GridfitMask) | |
73 { | |
74 range->min = minPPEM + 1; | |
75 range->max = maxPPEM; | |
76 return; | |
77 } | |
78 minPPEM = maxPPEM; | |
79 } | |
80 | |
81 return; | |
mtklein
2014/06/23 15:20:34
This _may_ be redundant.
| |
82 } | |
83 | |
84 static bool has_bitmap_strike(DWriteFontTypeface* typeface, PPEMRange range) { | |
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 both_zero(SkScalar a, SkScalar b) { |
103 return 0 == a && 0 == b; | 159 return 0 == a && 0 == b; |
104 } | 160 } |
105 | 161 |
106 // returns false if there is any non-90-rotation or skew | 162 // returns false if there is any non-90-rotation or skew |
107 static bool isAxisAligned(const SkScalerContext::Rec& rec) { | 163 static bool is_axis_aligned(const SkScalerContext::Rec& rec) { |
108 return 0 == rec.fPreSkewX && | 164 return 0 == rec.fPreSkewX && |
109 (bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) || | 165 (both_zero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) || |
110 bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1])); | 166 both_zero(rec.fPost2x2[0][0], rec.fPost2x2[1][1])); |
111 } | 167 } |
112 | 168 |
113 SkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface* typeface, | 169 SkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface* typeface, |
114 const SkDescriptor* desc) | 170 const SkDescriptor* desc) |
115 : SkScalerContext(typeface, desc) | 171 : SkScalerContext(typeface, desc) |
116 , fTypeface(SkRef(typeface)) | 172 , fTypeface(SkRef(typeface)) |
117 , fGlyphCount(-1) { | 173 , fGlyphCount(-1) { |
118 | 174 |
119 // In general, all glyphs should use CLEARTYPE_NATURAL_SYMMETRIC | 175 // In general, all glyphs should use CLEARTYPE_NATURAL_SYMMETRIC |
120 // except when bi-level rendering is requested or there are embedded | 176 // except when bi-level rendering is requested or there are embedded |
(...skipping 31 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 // When embedded bitmaps are requested, treat the entire range like |
166 axisAlignedBitmap = isAxisAligned(fRec); | 222 // a bitmap strike if the range is gridfit only and contains a bitmap. |
223 int bitmapPPEM = SkScalarTruncToInt(gdiTextSize); | |
224 PPEMRange range = { bitmapPPEM, bitmapPPEM }; | |
225 #ifndef SK_IGNORE_DWRITE_RENDERING_FIX | |
226 expand_range_if_gridfit_only(typeface, bitmapPPEM, &range); | |
227 #endif | |
228 treatLikeBitmap = has_bitmap_strike(typeface, range); | |
229 | |
230 axisAlignedBitmap = is_axis_aligned(fRec); | |
167 } | 231 } |
168 | 232 |
169 // If the user requested aliased, do so with aliased compatible metrics. | 233 // If the user requested aliased, do so with aliased compatible metrics. |
170 if (SkMask::kBW_Format == fRec.fMaskFormat) { | 234 if (SkMask::kBW_Format == fRec.fMaskFormat) { |
171 fTextSizeRender = gdiTextSize; | 235 fTextSizeRender = gdiTextSize; |
172 fRenderingMode = DWRITE_RENDERING_MODE_ALIASED; | 236 fRenderingMode = DWRITE_RENDERING_MODE_ALIASED; |
173 fTextureType = DWRITE_TEXTURE_ALIASED_1x1; | 237 fTextureType = DWRITE_TEXTURE_ALIASED_1x1; |
174 fTextSizeMeasure = gdiTextSize; | 238 fTextSizeMeasure = gdiTextSize; |
175 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; | 239 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; |
176 | 240 |
177 // If we can use a bitmap, use gdi classic rendering and measurement. | 241 // If we can use a bitmap, use gdi classic rendering and measurement. |
178 // This will not always provide a bitmap, but matches expected behavior. | 242 // This will not always provide a bitmap, but matches expected behavior. |
179 } else if (hasBitmap && axisAlignedBitmap) { | 243 } else if (treatLikeBitmap && axisAlignedBitmap) { |
180 fTextSizeRender = gdiTextSize; | 244 fTextSizeRender = gdiTextSize; |
181 fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC; | 245 fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC; |
182 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; | 246 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; |
183 fTextSizeMeasure = gdiTextSize; | 247 fTextSizeMeasure = gdiTextSize; |
184 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; | 248 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; |
185 | 249 |
186 // If rotated but the horizontal text could have used a bitmap, | 250 // If rotated but the horizontal text could have used a bitmap, |
187 // render high quality rotated glyphs but measure using bitmap metrics. | 251 // render high quality rotated glyphs but measure using bitmap metrics. |
188 } else if (hasBitmap) { | 252 } else if (treatLikeBitmap) { |
189 fTextSizeRender = gdiTextSize; | 253 fTextSizeRender = gdiTextSize; |
190 fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC; | 254 fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC; |
191 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; | 255 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; |
192 fTextSizeMeasure = gdiTextSize; | 256 fTextSizeMeasure = gdiTextSize; |
193 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; | 257 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; |
194 | 258 |
195 // The normal case is to use natural symmetric rendering and linear metrics. | 259 // The normal case is to use natural symmetric rendering and linear metrics. |
196 } else { | 260 } else { |
197 fTextSizeRender = realTextSize; | 261 fTextSizeRender = realTextSize; |
198 fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC; | 262 fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC; |
(...skipping 411 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
610 NULL, //advances | 674 NULL, //advances |
611 NULL, //offsets | 675 NULL, //offsets |
612 1, //num glyphs | 676 1, //num glyphs |
613 FALSE, //sideways | 677 FALSE, //sideways |
614 FALSE, //rtl | 678 FALSE, //rtl |
615 geometryToPath.get()), | 679 geometryToPath.get()), |
616 "Could not create glyph outline."); | 680 "Could not create glyph outline."); |
617 | 681 |
618 path->transform(fSkXform); | 682 path->transform(fSkXform); |
619 } | 683 } |
OLD | NEW |