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, | |
| 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 |