Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(272)

Side by Side Diff: src/ports/SkScalerContext_win_dw.cpp

Issue 341343002: Better rendering detection with DirectWrite. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Address comments, add comments. Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « gyp/sfnt.gyp ('k') | src/sfnt/SkOTTable_gasp.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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 }
OLDNEW
« no previous file with comments | « gyp/sfnt.gyp ('k') | src/sfnt/SkOTTable_gasp.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698