1 /* 2 * Copyright 2011 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkTypes.h" 9 #if defined(SK_BUILD_FOR_WIN) 10 11 #undef GetGlyphIndices 12 13 #include "SkDraw.h" 14 #include "SkDWrite.h" 15 #include "SkDWriteGeometrySink.h" 16 #include "SkEndian.h" 17 #include "SkGlyph.h" 18 #include "SkHRESULT.h" 19 #include "SkMaskGamma.h" 20 #include "SkMatrix22.h" 21 #include "SkMutex.h" 22 #include "SkOTTable_EBLC.h" 23 #include "SkOTTable_EBSC.h" 24 #include "SkOTTable_gasp.h" 25 #include "SkOTTable_maxp.h" 26 #include "SkPath.h" 27 #include "SkRasterClip.h" 28 #include "SkScalerContext.h" 29 #include "SkScalerContext_win_dw.h" 30 #include "SkSharedMutex.h" 31 #include "SkTScopedComPtr.h" 32 #include "SkTypeface_win_dw.h" 33 34 #include <dwrite.h> 35 #include <dwrite_1.h> 36 37 /* Note: 38 * In versions 8 and 8.1 of Windows, some calls in DWrite are not thread safe. 39 * The DWriteFactoryMutex protects the calls that are problematic. 40 */ 41 static SkSharedMutex DWriteFactoryMutex; 42 43 typedef SkAutoSharedMutexShared Shared; 44 45 static bool isLCD(const SkScalerContextRec& rec) { 46 return SkMask::kLCD16_Format == rec.fMaskFormat; 47 } 48 49 static bool is_hinted(DWriteFontTypeface* typeface) { 50 SkAutoExclusive l(DWriteFactoryMutex); 51 AutoTDWriteTable<SkOTTableMaximumProfile> maxp(typeface->fDWriteFontFace.get()); 52 if (!maxp.fExists) { 53 return false; 54 } 55 if (maxp.fSize < sizeof(SkOTTableMaximumProfile::Version::TT)) { 56 return false; 57 } 58 if (maxp->version.version != SkOTTableMaximumProfile::Version::TT::VERSION) { 59 return false; 60 } 61 return (0 != maxp->version.tt.maxSizeOfInstructions); 62 } 63 64 /** A GaspRange is inclusive, [min, max]. */ 65 struct GaspRange { 66 using Behavior = SkOTTableGridAndScanProcedure::GaspRange::behavior; 67 GaspRange(int min, int max, int version, Behavior flags) 68 : fMin(min), fMax(max), fVersion(version), fFlags(flags) { } 69 int fMin; 70 int fMax; 71 int fVersion; 72 Behavior fFlags; 73 }; 74 75 bool get_gasp_range(DWriteFontTypeface* typeface, int size, GaspRange* range) { 76 AutoTDWriteTable<SkOTTableGridAndScanProcedure> gasp(typeface->fDWriteFontFace.get()); 77 if (!gasp.fExists) { 78 return false; 79 } 80 if (gasp.fSize < sizeof(SkOTTableGridAndScanProcedure)) { 81 return false; 82 } 83 if (gasp->version != SkOTTableGridAndScanProcedure::version0 && 84 gasp->version != SkOTTableGridAndScanProcedure::version1) 85 { 86 return false; 87 } 88 89 uint16_t numRanges = SkEndianSwap16(gasp->numRanges); 90 if (numRanges > 1024 || 91 gasp.fSize < sizeof(SkOTTableGridAndScanProcedure) + 92 sizeof(SkOTTableGridAndScanProcedure::GaspRange) * numRanges) 93 { 94 return false; 95 } 96 97 const SkOTTableGridAndScanProcedure::GaspRange* rangeTable = 98 SkTAfter<const SkOTTableGridAndScanProcedure::GaspRange>(gasp.get()); 99 int minPPEM = -1; 100 for (uint16_t i = 0; i < numRanges; ++i, ++rangeTable) { 101 int maxPPEM = SkEndianSwap16(rangeTable->maxPPEM); 102 if (minPPEM < size && size <= maxPPEM) { 103 range->fMin = minPPEM + 1; 104 range->fMax = maxPPEM; 105 range->fVersion = SkEndian_SwapBE16(gasp->version); 106 range->fFlags = rangeTable->flags; 107 return true; 108 } 109 minPPEM = maxPPEM; 110 } 111 return false; 112 } 113 /** If the rendering mode for the specified 'size' is gridfit, then place 114 * the gridfit range into 'range'. Otherwise, leave 'range' alone. 115 */ 116 static bool is_gridfit_only(GaspRange::Behavior flags) { 117 return flags.raw.value == GaspRange::Behavior::Raw::GridfitMask; 118 } 119 120 static bool has_bitmap_strike(DWriteFontTypeface* typeface, GaspRange range) { 121 SkAutoExclusive l(DWriteFactoryMutex); 122 { 123 AutoTDWriteTable<SkOTTableEmbeddedBitmapLocation> eblc(typeface->fDWriteFontFace.get()); 124 if (!eblc.fExists) { 125 return false; 126 } 127 if (eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation)) { 128 return false; 129 } 130 if (eblc->version != SkOTTableEmbeddedBitmapLocation::version_initial) { 131 return false; 132 } 133 134 uint32_t numSizes = SkEndianSwap32(eblc->numSizes); 135 if (numSizes > 1024 || 136 eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation) + 137 sizeof(SkOTTableEmbeddedBitmapLocation::BitmapSizeTable) * numSizes) 138 { 139 return false; 140 } 141 142 const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable* sizeTable = 143 SkTAfter<const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable>(eblc.get()); 144 for (uint32_t i = 0; i < numSizes; ++i, ++sizeTable) { 145 if (sizeTable->ppemX == sizeTable->ppemY && 146 range.fMin <= sizeTable->ppemX && sizeTable->ppemX <= range.fMax) 147 { 148 // TODO: determine if we should dig through IndexSubTableArray/IndexSubTable 149 // to determine the actual number of glyphs with bitmaps. 150 151 // TODO: Ensure that the bitmaps actually cover a significant portion of the strike. 152 153 // TODO: Ensure that the bitmaps are bi-level? 154 if (sizeTable->endGlyphIndex >= sizeTable->startGlyphIndex + 3) { 155 return true; 156 } 157 } 158 } 159 } 160 161 { 162 AutoTDWriteTable<SkOTTableEmbeddedBitmapScaling> ebsc(typeface->fDWriteFontFace.get()); 163 if (!ebsc.fExists) { 164 return false; 165 } 166 if (ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling)) { 167 return false; 168 } 169 if (ebsc->version != SkOTTableEmbeddedBitmapScaling::version_initial) { 170 return false; 171 } 172 173 uint32_t numSizes = SkEndianSwap32(ebsc->numSizes); 174 if (numSizes > 1024 || 175 ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling) + 176 sizeof(SkOTTableEmbeddedBitmapScaling::BitmapScaleTable) * numSizes) 177 { 178 return false; 179 } 180 181 const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable* scaleTable = 182 SkTAfter<const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable>(ebsc.get()); 183 for (uint32_t i = 0; i < numSizes; ++i, ++scaleTable) { 184 if (scaleTable->ppemX == scaleTable->ppemY && 185 range.fMin <= scaleTable->ppemX && scaleTable->ppemX <= range.fMax) { 186 // EBSC tables are normally only found in bitmap only fonts. 187 return true; 188 } 189 } 190 } 191 192 return false; 193 } 194 195 static bool both_zero(SkScalar a, SkScalar b) { 196 return 0 == a && 0 == b; 197 } 198 199 // returns false if there is any non-90-rotation or skew 200 static bool is_axis_aligned(const SkScalerContextRec& rec) { 201 return 0 == rec.fPreSkewX && 202 (both_zero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) || 203 both_zero(rec.fPost2x2[0][0], rec.fPost2x2[1][1])); 204 } 205 206 SkScalerContext_DW::SkScalerContext_DW(sk_sp<DWriteFontTypeface> typefaceRef, 207 const SkScalerContextEffects& effects, 208 const SkDescriptor* desc) 209 : SkScalerContext(std::move(typefaceRef), effects, desc) 210 , fGlyphCount(-1) { 211 212 DWriteFontTypeface* typeface = this->getDWriteTypeface(); 213 fIsColorFont = typeface->fFactory2 && 214 typeface->fDWriteFontFace2 && 215 typeface->fDWriteFontFace2->IsColorFont(); 216 217 // In general, all glyphs should use NATURAL_SYMMETRIC 218 // except when bi-level rendering is requested or there are embedded 219 // bi-level bitmaps (and the embedded bitmap flag is set and no rotation). 220 // 221 // DirectWrite's IDWriteFontFace::GetRecommendedRenderingMode does not do 222 // this. As a result, determine the actual size of the text and then see if 223 // there are any embedded bi-level bitmaps of that size. If there are, then 224 // force bitmaps by requesting bi-level rendering. 225 // 226 // FreeType allows for separate ppemX and ppemY, but DirectWrite assumes 227 // square pixels and only uses ppemY. Therefore the transform must track any 228 // non-uniform x-scale. 229 // 230 // Also, rotated glyphs should have the same absolute advance widths as 231 // horizontal glyphs and the subpixel flag should not affect glyph shapes. 232 233 SkVector scale; 234 fRec.computeMatrices(SkScalerContextRec::kVertical_PreMatrixScale, &scale, &fSkXform); 235 236 fXform.m11 = SkScalarToFloat(fSkXform.getScaleX()); 237 fXform.m12 = SkScalarToFloat(fSkXform.getSkewY()); 238 fXform.m21 = SkScalarToFloat(fSkXform.getSkewX()); 239 fXform.m22 = SkScalarToFloat(fSkXform.getScaleY()); 240 fXform.dx = 0; 241 fXform.dy = 0; 242 243 // realTextSize is the actual device size we want (as opposed to the size the user requested). 244 // gdiTextSize is the size we request when GDI compatible. 245 // If the scale is negative, this means the matrix will do the flip anyway. 246 const SkScalar realTextSize = scale.fY; 247 // Due to floating point math, the lower bits are suspect. Round carefully. 248 SkScalar gdiTextSize = SkScalarRoundToScalar(realTextSize * 64.0f) / 64.0f; 249 if (gdiTextSize == 0) { 250 gdiTextSize = SK_Scalar1; 251 } 252 253 bool bitmapRequested = SkToBool(fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag); 254 bool treatLikeBitmap = false; 255 bool axisAlignedBitmap = false; 256 if (bitmapRequested) { 257 // When embedded bitmaps are requested, treat the entire range like 258 // a bitmap strike if the range is gridfit only and contains a bitmap. 259 int bitmapPPEM = SkScalarTruncToInt(gdiTextSize); 260 GaspRange range(bitmapPPEM, bitmapPPEM, 0, GaspRange::Behavior()); 261 if (get_gasp_range(typeface, bitmapPPEM, &range)) { 262 if (!is_gridfit_only(range.fFlags)) { 263 range = GaspRange(bitmapPPEM, bitmapPPEM, 0, GaspRange::Behavior()); 264 } 265 } 266 treatLikeBitmap = has_bitmap_strike(typeface, range); 267 268 axisAlignedBitmap = is_axis_aligned(fRec); 269 } 270 271 GaspRange range(0, 0xFFFF, 0, GaspRange::Behavior()); 272 273 // If the user requested aliased, do so with aliased compatible metrics. 274 if (SkMask::kBW_Format == fRec.fMaskFormat) { 275 fTextSizeRender = gdiTextSize; 276 fRenderingMode = DWRITE_RENDERING_MODE_ALIASED; 277 fTextureType = DWRITE_TEXTURE_ALIASED_1x1; 278 fTextSizeMeasure = gdiTextSize; 279 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; 280 281 // If we can use a bitmap, use gdi classic rendering and measurement. 282 // This will not always provide a bitmap, but matches expected behavior. 283 } else if (treatLikeBitmap && axisAlignedBitmap) { 284 fTextSizeRender = gdiTextSize; 285 fRenderingMode = DWRITE_RENDERING_MODE_GDI_CLASSIC; 286 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; 287 fTextSizeMeasure = gdiTextSize; 288 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; 289 290 // If rotated but the horizontal text could have used a bitmap, 291 // render high quality rotated glyphs but measure using bitmap metrics. 292 } else if (treatLikeBitmap) { 293 fTextSizeRender = gdiTextSize; 294 fRenderingMode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC; 295 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; 296 fTextSizeMeasure = gdiTextSize; 297 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; 298 299 // If the font has a gasp table version 1, use it to determine symmetric rendering. 300 } else if (get_gasp_range(typeface, SkScalarRoundToInt(gdiTextSize), &range) && 301 range.fVersion >= 1) 302 { 303 fTextSizeRender = realTextSize; 304 fRenderingMode = range.fFlags.field.SymmetricSmoothing 305 ? DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC 306 : DWRITE_RENDERING_MODE_NATURAL; 307 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; 308 fTextSizeMeasure = realTextSize; 309 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL; 310 311 // If the requested size is above 20px or there are no bytecode hints, use symmetric rendering. 312 } else if (realTextSize > SkIntToScalar(20) || !is_hinted(typeface)) { 313 fTextSizeRender = realTextSize; 314 fRenderingMode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC; 315 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; 316 fTextSizeMeasure = realTextSize; 317 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL; 318 319 // Fonts with hints, no gasp or gasp version 0, and below 20px get non-symmetric rendering. 320 // Often such fonts have hints which were only tested with GDI ClearType classic. 321 // Some of these fonts rely on drop out control in the y direction in order to be legible. 322 // Tenor Sans 323 // https://fonts.google.com/specimen/Tenor+Sans 324 // Gill Sans W04 325 // https://cdn.leagueoflegends.com/lolkit/1.1.9/resources/fonts/gill-sans-w04-book.woff 326 // https://na.leagueoflegends.com/en/news/game-updates/patch/patch-410-notes 327 // See https://crbug.com/385897 328 } else { 329 fTextSizeRender = gdiTextSize; 330 fRenderingMode = DWRITE_RENDERING_MODE_NATURAL; 331 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; 332 fTextSizeMeasure = realTextSize; 333 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL; 334 } 335 336 // DirectWrite2 allows for grayscale hinting. 337 fAntiAliasMode = DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE; 338 if (typeface->fFactory2 && typeface->fDWriteFontFace2 && 339 SkMask::kA8_Format == fRec.fMaskFormat && 340 !(fRec.fFlags & SkScalerContext::kGenA8FromLCD_Flag)) 341 { 342 // DWRITE_TEXTURE_ALIASED_1x1 is now misnamed, it must also be used with grayscale. 343 fTextureType = DWRITE_TEXTURE_ALIASED_1x1; 344 fAntiAliasMode = DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE; 345 } 346 347 // DirectWrite2 allows hinting to be disabled. 348 fGridFitMode = DWRITE_GRID_FIT_MODE_ENABLED; 349 if (fRec.getHinting() == SkPaint::kNo_Hinting) { 350 fGridFitMode = DWRITE_GRID_FIT_MODE_DISABLED; 351 if (fRenderingMode != DWRITE_RENDERING_MODE_ALIASED) { 352 fRenderingMode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC; 353 } 354 } 355 356 if (this->isSubpixel()) { 357 fTextSizeMeasure = realTextSize; 358 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL; 359 } 360 } 361 362 SkScalerContext_DW::~SkScalerContext_DW() { 363 } 364 365 unsigned SkScalerContext_DW::generateGlyphCount() { 366 if (fGlyphCount < 0) { 367 fGlyphCount = this->getDWriteTypeface()->fDWriteFontFace->GetGlyphCount(); 368 } 369 return fGlyphCount; 370 } 371 372 uint16_t SkScalerContext_DW::generateCharToGlyph(SkUnichar uni) { 373 uint16_t index = 0; 374 UINT32* uniPtr = reinterpret_cast<UINT32*>(&uni); 375 this->getDWriteTypeface()->fDWriteFontFace->GetGlyphIndices(uniPtr, 1, &index); 376 return index; 377 } 378 379 void SkScalerContext_DW::generateAdvance(SkGlyph* glyph) { 380 //Delta is the difference between the right/left side bearing metric 381 //and where the right/left side bearing ends up after hinting. 382 //DirectWrite does not provide this information. 383 glyph->fRsbDelta = 0; 384 glyph->fLsbDelta = 0; 385 386 glyph->fAdvanceX = 0; 387 glyph->fAdvanceY = 0; 388 389 uint16_t glyphId = glyph->getGlyphID(); 390 DWRITE_GLYPH_METRICS gm; 391 392 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode || 393 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode) 394 { 395 SkAutoExclusive l(DWriteFactoryMutex); 396 HRVM(this->getDWriteTypeface()->fDWriteFontFace->GetGdiCompatibleGlyphMetrics( 397 fTextSizeMeasure, 398 1.0f, // pixelsPerDip 399 // This parameter does not act like the lpmat2 parameter to GetGlyphOutlineW. 400 // If it did then GsA here and G_inv below to mapVectors. 401 nullptr, 402 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode, 403 &glyphId, 1, 404 &gm), 405 "Could not get gdi compatible glyph metrics."); 406 } else { 407 SkAutoExclusive l(DWriteFactoryMutex); 408 HRVM(this->getDWriteTypeface()->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm), 409 "Could not get design metrics."); 410 } 411 412 DWRITE_FONT_METRICS dwfm; 413 { 414 Shared l(DWriteFactoryMutex); 415 this->getDWriteTypeface()->fDWriteFontFace->GetMetrics(&dwfm); 416 } 417 SkScalar advanceX = fTextSizeMeasure * gm.advanceWidth / dwfm.designUnitsPerEm; 418 419 SkVector advance = { advanceX, 0 }; 420 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode || 421 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode) 422 { 423 // DirectWrite produced 'compatible' metrics, but while close, 424 // the end result is not always an integer as it would be with GDI. 425 advance.fX = SkScalarRoundToScalar(advance.fX); 426 } 427 fSkXform.mapVectors(&advance, 1); 428 429 glyph->fAdvanceX = SkScalarToFloat(advance.fX); 430 glyph->fAdvanceY = SkScalarToFloat(advance.fY); 431 } 432 433 HRESULT SkScalerContext_DW::getBoundingBox(SkGlyph* glyph, 434 DWRITE_RENDERING_MODE renderingMode, 435 DWRITE_TEXTURE_TYPE textureType, 436 RECT* bbox) 437 { 438 //Measure raster size. 439 fXform.dx = SkFixedToFloat(glyph->getSubXFixed()); 440 fXform.dy = SkFixedToFloat(glyph->getSubYFixed()); 441 442 FLOAT advance = 0; 443 444 UINT16 glyphId = glyph->getGlyphID(); 445 446 DWRITE_GLYPH_OFFSET offset; 447 offset.advanceOffset = 0.0f; 448 offset.ascenderOffset = 0.0f; 449 450 DWRITE_GLYPH_RUN run; 451 run.glyphCount = 1; 452 run.glyphAdvances = &advance; 453 run.fontFace = this->getDWriteTypeface()->fDWriteFontFace.get(); 454 run.fontEmSize = SkScalarToFloat(fTextSizeRender); 455 run.bidiLevel = 0; 456 run.glyphIndices = &glyphId; 457 run.isSideways = FALSE; 458 run.glyphOffsets = &offset; 459 460 SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis; 461 { 462 SkAutoExclusive l(DWriteFactoryMutex); 463 // IDWriteFactory2::CreateGlyphRunAnalysis is very bad at aliased glyphs. 464 if (this->getDWriteTypeface()->fFactory2 && 465 (fGridFitMode == DWRITE_GRID_FIT_MODE_DISABLED || 466 fAntiAliasMode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)) 467 { 468 HRM(this->getDWriteTypeface()->fFactory2->CreateGlyphRunAnalysis( 469 &run, 470 &fXform, 471 renderingMode, 472 fMeasuringMode, 473 fGridFitMode, 474 fAntiAliasMode, 475 0.0f, // baselineOriginX, 476 0.0f, // baselineOriginY, 477 &glyphRunAnalysis), 478 "Could not create DW2 glyph run analysis."); 479 } else { 480 HRM(this->getDWriteTypeface()->fFactory->CreateGlyphRunAnalysis(&run, 481 1.0f, // pixelsPerDip, 482 &fXform, 483 renderingMode, 484 fMeasuringMode, 485 0.0f, // baselineOriginX, 486 0.0f, // baselineOriginY, 487 &glyphRunAnalysis), 488 "Could not create glyph run analysis."); 489 } 490 } 491 { 492 Shared l(DWriteFactoryMutex); 493 HRM(glyphRunAnalysis->GetAlphaTextureBounds(textureType, bbox), 494 "Could not get texture bounds."); 495 } 496 return S_OK; 497 } 498 499 /** GetAlphaTextureBounds succeeds but sometimes returns empty bounds like 500 * { 0x80000000, 0x80000000, 0x80000000, 0x80000000 } 501 * for small, but not quite zero, sized glyphs. 502 * Only set as non-empty if the returned bounds are non-empty. 503 */ 504 static bool glyph_check_and_set_bounds(SkGlyph* glyph, const RECT& bbox) { 505 if (bbox.left >= bbox.right || bbox.top >= bbox.bottom) { 506 return false; 507 } 508 509 // We're trying to pack left and top into int16_t, 510 // and width and height into uint16_t, after outsetting by 1. 511 if (!SkIRect::MakeXYWH(-32767, -32767, 65535, 65535).contains( 512 SkIRect::MakeLTRB(bbox.left, bbox.top, bbox.right, bbox.bottom))) { 513 return false; 514 } 515 516 glyph->fWidth = SkToU16(bbox.right - bbox.left); 517 glyph->fHeight = SkToU16(bbox.bottom - bbox.top); 518 glyph->fLeft = SkToS16(bbox.left); 519 glyph->fTop = SkToS16(bbox.top); 520 return true; 521 } 522 523 bool SkScalerContext_DW::isColorGlyph(const SkGlyph& glyph) { 524 SkTScopedComPtr<IDWriteColorGlyphRunEnumerator> colorLayer; 525 return getColorGlyphRun(glyph, &colorLayer); 526 } 527 528 bool SkScalerContext_DW::getColorGlyphRun(const SkGlyph& glyph, 529 IDWriteColorGlyphRunEnumerator** colorGlyph) 530 { 531 FLOAT advance = 0; 532 UINT16 glyphId = glyph.getGlyphID(); 533 534 DWRITE_GLYPH_OFFSET offset; 535 offset.advanceOffset = 0.0f; 536 offset.ascenderOffset = 0.0f; 537 538 DWRITE_GLYPH_RUN run; 539 run.glyphCount = 1; 540 run.glyphAdvances = &advance; 541 run.fontFace = this->getDWriteTypeface()->fDWriteFontFace.get(); 542 run.fontEmSize = SkScalarToFloat(fTextSizeRender); 543 run.bidiLevel = 0; 544 run.glyphIndices = &glyphId; 545 run.isSideways = FALSE; 546 run.glyphOffsets = &offset; 547 548 HRESULT hr = this->getDWriteTypeface()->fFactory2->TranslateColorGlyphRun( 549 0, 0, &run, nullptr, fMeasuringMode, &fXform, 0, colorGlyph); 550 if (hr == DWRITE_E_NOCOLOR) { 551 return false; 552 } 553 HRBM(hr, "Failed to translate color glyph run"); 554 return true; 555 } 556 557 void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) { 558 glyph->fWidth = 0; 559 glyph->fHeight = 0; 560 glyph->fLeft = 0; 561 glyph->fTop = 0; 562 563 this->generateAdvance(glyph); 564 565 if (fIsColorFont && isColorGlyph(*glyph)) { 566 glyph->fMaskFormat = SkMask::kARGB32_Format; 567 } 568 569 RECT bbox; 570 HRVM(this->getBoundingBox(glyph, fRenderingMode, fTextureType, &bbox), 571 "Requested bounding box could not be determined."); 572 573 if (glyph_check_and_set_bounds(glyph, bbox)) { 574 return; 575 } 576 577 // GetAlphaTextureBounds succeeds but returns an empty RECT if there are no 578 // glyphs of the specified texture type. When this happens, try with the 579 // alternate texture type. 580 if (DWRITE_TEXTURE_CLEARTYPE_3x1 == fTextureType) { 581 HRVM(this->getBoundingBox(glyph, 582 DWRITE_RENDERING_MODE_ALIASED, 583 DWRITE_TEXTURE_ALIASED_1x1, 584 &bbox), 585 "Fallback bounding box could not be determined."); 586 if (glyph_check_and_set_bounds(glyph, bbox)) { 587 glyph->fForceBW = 1; 588 } 589 } 590 // TODO: handle the case where a request for DWRITE_TEXTURE_ALIASED_1x1 591 // fails, and try DWRITE_TEXTURE_CLEARTYPE_3x1. 592 } 593 594 void SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* metrics) { 595 if (nullptr == metrics) { 596 return; 597 } 598 599 sk_bzero(metrics, sizeof(*metrics)); 600 601 DWRITE_FONT_METRICS dwfm; 602 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode || 603 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode) 604 { 605 this->getDWriteTypeface()->fDWriteFontFace->GetGdiCompatibleMetrics( 606 fTextSizeRender, 607 1.0f, // pixelsPerDip 608 &fXform, 609 &dwfm); 610 } else { 611 this->getDWriteTypeface()->fDWriteFontFace->GetMetrics(&dwfm); 612 } 613 614 SkScalar upem = SkIntToScalar(dwfm.designUnitsPerEm); 615 616 metrics->fAscent = -fTextSizeRender * SkIntToScalar(dwfm.ascent) / upem; 617 metrics->fDescent = fTextSizeRender * SkIntToScalar(dwfm.descent) / upem; 618 metrics->fLeading = fTextSizeRender * SkIntToScalar(dwfm.lineGap) / upem; 619 metrics->fXHeight = fTextSizeRender * SkIntToScalar(dwfm.xHeight) / upem; 620 metrics->fCapHeight = fTextSizeRender * SkIntToScalar(dwfm.capHeight) / upem; 621 metrics->fUnderlineThickness = fTextSizeRender * SkIntToScalar(dwfm.underlineThickness) / upem; 622 metrics->fUnderlinePosition = -(fTextSizeRender * SkIntToScalar(dwfm.underlinePosition) / upem); 623 metrics->fStrikeoutThickness = fTextSizeRender * SkIntToScalar(dwfm.strikethroughThickness) / upem; 624 metrics->fStrikeoutPosition = -(fTextSizeRender * SkIntToScalar(dwfm.strikethroughPosition) / upem); 625 626 metrics->fFlags |= SkPaint::FontMetrics::kUnderlineThicknessIsValid_Flag; 627 metrics->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag; 628 metrics->fFlags |= SkPaint::FontMetrics::kStrikeoutThicknessIsValid_Flag; 629 metrics->fFlags |= SkPaint::FontMetrics::kStrikeoutPositionIsValid_Flag; 630 631 if (this->getDWriteTypeface()->fDWriteFontFace1.get()) { 632 DWRITE_FONT_METRICS1 dwfm1; 633 this->getDWriteTypeface()->fDWriteFontFace1->GetMetrics(&dwfm1); 634 metrics->fTop = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxTop) / upem; 635 metrics->fBottom = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxBottom) / upem; 636 metrics->fXMin = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxLeft) / upem; 637 metrics->fXMax = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxRight) / upem; 638 639 metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin; 640 return; 641 } 642 643 AutoTDWriteTable<SkOTTableHead> head(this->getDWriteTypeface()->fDWriteFontFace.get()); 644 if (head.fExists && 645 head.fSize >= sizeof(SkOTTableHead) && 646 head->version == SkOTTableHead::version1) 647 { 648 metrics->fTop = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMax) / upem; 649 metrics->fBottom = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMin) / upem; 650 metrics->fXMin = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMin) / upem; 651 metrics->fXMax = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMax) / upem; 652 653 metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin; 654 return; 655 } 656 657 metrics->fTop = metrics->fAscent; 658 metrics->fBottom = metrics->fDescent; 659 } 660 661 /////////////////////////////////////////////////////////////////////////////// 662 663 #include "SkColorData.h" 664 665 static void bilevel_to_bw(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph) { 666 const int width = glyph.fWidth; 667 const size_t dstRB = (width + 7) >> 3; 668 uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage); 669 670 int byteCount = width >> 3; 671 int bitCount = width & 7; 672 673 for (int y = 0; y < glyph.fHeight; ++y) { 674 if (byteCount > 0) { 675 for (int i = 0; i < byteCount; ++i) { 676 unsigned byte = 0; 677 byte |= src[0] & (1 << 7); 678 byte |= src[1] & (1 << 6); 679 byte |= src[2] & (1 << 5); 680 byte |= src[3] & (1 << 4); 681 byte |= src[4] & (1 << 3); 682 byte |= src[5] & (1 << 2); 683 byte |= src[6] & (1 << 1); 684 byte |= src[7] & (1 << 0); 685 dst[i] = byte; 686 src += 8; 687 } 688 } 689 if (bitCount > 0) { 690 unsigned byte = 0; 691 unsigned mask = 0x80; 692 for (int i = 0; i < bitCount; i++) { 693 byte |= (src[i]) & mask; 694 mask >>= 1; 695 } 696 dst[byteCount] = byte; 697 } 698 src += bitCount; 699 dst += dstRB; 700 } 701 } 702 703 template<bool APPLY_PREBLEND> 704 static void grayscale_to_a8(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, 705 const uint8_t* table8) { 706 const size_t dstRB = glyph.rowBytes(); 707 const U16CPU width = glyph.fWidth; 708 uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage); 709 710 for (U16CPU y = 0; y < glyph.fHeight; y++) { 711 for (U16CPU i = 0; i < width; i++) { 712 U8CPU a = *(src++); 713 dst[i] = sk_apply_lut_if<APPLY_PREBLEND>(a, table8); 714 } 715 dst = SkTAddOffset<uint8_t>(dst, dstRB); 716 } 717 } 718 719 template<bool APPLY_PREBLEND> 720 static void rgb_to_a8(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, const uint8_t* table8) { 721 const size_t dstRB = glyph.rowBytes(); 722 const U16CPU width = glyph.fWidth; 723 uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage); 724 725 for (U16CPU y = 0; y < glyph.fHeight; y++) { 726 for (U16CPU i = 0; i < width; i++) { 727 U8CPU r = *(src++); 728 U8CPU g = *(src++); 729 U8CPU b = *(src++); 730 dst[i] = sk_apply_lut_if<APPLY_PREBLEND>((r + g + b) / 3, table8); 731 } 732 dst = SkTAddOffset<uint8_t>(dst, dstRB); 733 } 734 } 735 736 template<bool APPLY_PREBLEND, bool RGB> 737 static void rgb_to_lcd16(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, 738 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) { 739 const size_t dstRB = glyph.rowBytes(); 740 const U16CPU width = glyph.fWidth; 741 uint16_t* SK_RESTRICT dst = static_cast<uint16_t*>(glyph.fImage); 742 743 for (U16CPU y = 0; y < glyph.fHeight; y++) { 744 for (U16CPU i = 0; i < width; i++) { 745 U8CPU r, g, b; 746 if (RGB) { 747 r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR); 748 g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG); 749 b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB); 750 } else { 751 b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB); 752 g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG); 753 r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR); 754 } 755 dst[i] = SkPack888ToRGB16(r, g, b); 756 } 757 dst = SkTAddOffset<uint16_t>(dst, dstRB); 758 } 759 } 760 761 const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph, 762 DWRITE_RENDERING_MODE renderingMode, 763 DWRITE_TEXTURE_TYPE textureType) 764 { 765 int sizeNeeded = glyph.fWidth * glyph.fHeight; 766 if (DWRITE_TEXTURE_CLEARTYPE_3x1 == textureType) { 767 sizeNeeded *= 3; 768 } 769 if (sizeNeeded > fBits.count()) { 770 fBits.setCount(sizeNeeded); 771 } 772 773 // erase 774 memset(fBits.begin(), 0, sizeNeeded); 775 776 fXform.dx = SkFixedToFloat(glyph.getSubXFixed()); 777 fXform.dy = SkFixedToFloat(glyph.getSubYFixed()); 778 779 FLOAT advance = 0.0f; 780 781 UINT16 index = glyph.getGlyphID(); 782 783 DWRITE_GLYPH_OFFSET offset; 784 offset.advanceOffset = 0.0f; 785 offset.ascenderOffset = 0.0f; 786 787 DWRITE_GLYPH_RUN run; 788 run.glyphCount = 1; 789 run.glyphAdvances = &advance; 790 run.fontFace = this->getDWriteTypeface()->fDWriteFontFace.get(); 791 run.fontEmSize = SkScalarToFloat(fTextSizeRender); 792 run.bidiLevel = 0; 793 run.glyphIndices = &index; 794 run.isSideways = FALSE; 795 run.glyphOffsets = &offset; 796 { 797 SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis; 798 { 799 SkAutoExclusive l(DWriteFactoryMutex); 800 // IDWriteFactory2::CreateGlyphRunAnalysis is very bad at aliased glyphs. 801 if (this->getDWriteTypeface()->fFactory2 && 802 (fGridFitMode == DWRITE_GRID_FIT_MODE_DISABLED || 803 fAntiAliasMode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)) 804 { 805 HRNM(this->getDWriteTypeface()->fFactory2->CreateGlyphRunAnalysis(&run, 806 &fXform, 807 renderingMode, 808 fMeasuringMode, 809 fGridFitMode, 810 fAntiAliasMode, 811 0.0f, // baselineOriginX, 812 0.0f, // baselineOriginY, 813 &glyphRunAnalysis), 814 "Could not create DW2 glyph run analysis."); 815 } else { 816 HRNM(this->getDWriteTypeface()->fFactory->CreateGlyphRunAnalysis(&run, 817 1.0f, // pixelsPerDip, 818 &fXform, 819 renderingMode, 820 fMeasuringMode, 821 0.0f, // baselineOriginX, 822 0.0f, // baselineOriginY, 823 &glyphRunAnalysis), 824 "Could not create glyph run analysis."); 825 } 826 } 827 //NOTE: this assumes that the glyph has already been measured 828 //with an exact same glyph run analysis. 829 RECT bbox; 830 bbox.left = glyph.fLeft; 831 bbox.top = glyph.fTop; 832 bbox.right = glyph.fLeft + glyph.fWidth; 833 bbox.bottom = glyph.fTop + glyph.fHeight; 834 { 835 Shared l(DWriteFactoryMutex); 836 HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType, 837 &bbox, 838 fBits.begin(), 839 sizeNeeded), 840 "Could not draw mask."); 841 } 842 } 843 return fBits.begin(); 844 } 845 846 void SkScalerContext_DW::generateColorGlyphImage(const SkGlyph& glyph) { 847 SkASSERT(isColorGlyph(glyph)); 848 SkASSERT(glyph.fMaskFormat == SkMask::Format::kARGB32_Format); 849 850 memset(glyph.fImage, 0, glyph.computeImageSize()); 851 852 SkTScopedComPtr<IDWriteColorGlyphRunEnumerator> colorLayers; 853 getColorGlyphRun(glyph, &colorLayers); 854 SkASSERT(colorLayers.get()); 855 856 SkMatrix matrix = fSkXform; 857 matrix.postTranslate(-SkIntToScalar(glyph.fLeft), -SkIntToScalar(glyph.fTop)); 858 SkRasterClip rc(SkIRect::MakeWH(glyph.fWidth, glyph.fHeight)); 859 SkDraw draw; 860 draw.fDst = SkPixmap(SkImageInfo::MakeN32(glyph.fWidth, glyph.fHeight, kPremul_SkAlphaType), 861 glyph.fImage, 862 glyph.ComputeRowBytes(glyph.fWidth, SkMask::Format::kARGB32_Format)); 863 draw.fMatrix = &matrix; 864 draw.fRC = &rc; 865 866 SkPaint paint; 867 if (fRenderingMode != DWRITE_RENDERING_MODE_ALIASED) { 868 paint.setFlags(SkPaint::Flags::kAntiAlias_Flag); 869 } 870 871 BOOL hasNextRun = FALSE; 872 while (SUCCEEDED(colorLayers->MoveNext(&hasNextRun)) && hasNextRun) { 873 const DWRITE_COLOR_GLYPH_RUN* colorGlyph; 874 HRVM(colorLayers->GetCurrentRun(&colorGlyph), "Could not get current color glyph run"); 875 876 SkColor color; 877 if (colorGlyph->paletteIndex != 0xffff) { 878 color = SkColorSetARGB(sk_float_round2int(colorGlyph->runColor.a * 255), 879 sk_float_round2int(colorGlyph->runColor.r * 255), 880 sk_float_round2int(colorGlyph->runColor.g * 255), 881 sk_float_round2int(colorGlyph->runColor.b * 255)); 882 } else { 883 // If all components of runColor are 0 or (equivalently) paletteIndex is 0xFFFF then 884 // the 'current brush' is used. fRec.getLuminanceColor() is kinda sorta what is wanted 885 // here, but not really, it will often be the wrong value because it wan't designed for 886 // this. 887 // TODO: implement this fully, bug.skia.org/5788 888 color = fRec.getLuminanceColor(); 889 } 890 paint.setColor(color); 891 892 SkPath path; 893 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath; 894 HRVM(SkDWriteGeometrySink::Create(&path, &geometryToPath), 895 "Could not create geometry to path converter."); 896 { 897 SkAutoExclusive l(DWriteFactoryMutex); 898 HRVM(colorGlyph->glyphRun.fontFace->GetGlyphRunOutline( 899 colorGlyph->glyphRun.fontEmSize, 900 colorGlyph->glyphRun.glyphIndices, 901 colorGlyph->glyphRun.glyphAdvances, 902 colorGlyph->glyphRun.glyphOffsets, 903 colorGlyph->glyphRun.glyphCount, 904 colorGlyph->glyphRun.isSideways, 905 colorGlyph->glyphRun.bidiLevel % 2, //rtl 906 geometryToPath.get()), 907 "Could not create glyph outline."); 908 } 909 draw.drawPath(path, paint, nullptr, true /* pathIsMutable */); 910 } 911 } 912 913 void SkScalerContext_DW::generateImage(const SkGlyph& glyph) { 914 //Create the mask. 915 DWRITE_RENDERING_MODE renderingMode = fRenderingMode; 916 DWRITE_TEXTURE_TYPE textureType = fTextureType; 917 if (glyph.fForceBW) { 918 renderingMode = DWRITE_RENDERING_MODE_ALIASED; 919 textureType = DWRITE_TEXTURE_ALIASED_1x1; 920 } 921 922 if (SkMask::kARGB32_Format == glyph.fMaskFormat) { 923 generateColorGlyphImage(glyph); 924 return; 925 } 926 927 const void* bits = this->drawDWMask(glyph, renderingMode, textureType); 928 if (!bits) { 929 sk_bzero(glyph.fImage, glyph.computeImageSize()); 930 return; 931 } 932 933 //Copy the mask into the glyph. 934 const uint8_t* src = (const uint8_t*)bits; 935 if (DWRITE_RENDERING_MODE_ALIASED == renderingMode) { 936 bilevel_to_bw(src, glyph); 937 const_cast<SkGlyph&>(glyph).fMaskFormat = SkMask::kBW_Format; 938 } else if (!isLCD(fRec)) { 939 if (textureType == DWRITE_TEXTURE_ALIASED_1x1) { 940 if (fPreBlend.isApplicable()) { 941 grayscale_to_a8<true>(src, glyph, fPreBlend.fG); 942 } else { 943 grayscale_to_a8<false>(src, glyph, fPreBlend.fG); 944 } 945 } else { 946 if (fPreBlend.isApplicable()) { 947 rgb_to_a8<true>(src, glyph, fPreBlend.fG); 948 } else { 949 rgb_to_a8<false>(src, glyph, fPreBlend.fG); 950 } 951 } 952 } else { 953 SkASSERT(SkMask::kLCD16_Format == glyph.fMaskFormat); 954 if (fPreBlend.isApplicable()) { 955 if (fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag) { 956 rgb_to_lcd16<true, false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 957 } else { 958 rgb_to_lcd16<true, true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 959 } 960 } else { 961 if (fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag) { 962 rgb_to_lcd16<false, false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 963 } else { 964 rgb_to_lcd16<false, true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 965 } 966 } 967 } 968 } 969 970 void SkScalerContext_DW::generatePath(SkGlyphID glyph, SkPath* path) { 971 SkASSERT(path); 972 973 path->reset(); 974 975 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath; 976 HRVM(SkDWriteGeometrySink::Create(path, &geometryToPath), 977 "Could not create geometry to path converter."); 978 UINT16 glyphId = SkTo<UINT16>(glyph); 979 { 980 SkAutoExclusive l(DWriteFactoryMutex); 981 //TODO: convert to<->from DIUs? This would make a difference if hinting. 982 //It may not be needed, it appears that DirectWrite only hints at em size. 983 HRVM(this->getDWriteTypeface()->fDWriteFontFace->GetGlyphRunOutline( 984 SkScalarToFloat(fTextSizeRender), 985 &glyphId, 986 nullptr, //advances 987 nullptr, //offsets 988 1, //num glyphs 989 FALSE, //sideways 990 FALSE, //rtl 991 geometryToPath.get()), 992 "Could not create glyph outline."); 993 } 994 995 path->transform(fSkXform); 996 } 997 998 #endif//defined(SK_BUILD_FOR_WIN) 999