Chromium Code Reviews| 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 |