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_WIN32) 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 SkScalerContext::Rec& 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 SkScalerContext::Rec& 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 glyph->fWidth = SkToU16(bbox.right - bbox.left); 509 glyph->fHeight = SkToU16(bbox.bottom - bbox.top); 510 glyph->fLeft = SkToS16(bbox.left); 511 glyph->fTop = SkToS16(bbox.top); 512 return true; 513 } 514 515 bool SkScalerContext_DW::isColorGlyph(const SkGlyph& glyph) { 516 SkTScopedComPtr<IDWriteColorGlyphRunEnumerator> colorLayer; 517 return getColorGlyphRun(glyph, &colorLayer); 518 } 519 520 bool SkScalerContext_DW::getColorGlyphRun(const SkGlyph& glyph, 521 IDWriteColorGlyphRunEnumerator** colorGlyph) 522 { 523 FLOAT advance = 0; 524 UINT16 glyphId = glyph.getGlyphID(); 525 526 DWRITE_GLYPH_OFFSET offset; 527 offset.advanceOffset = 0.0f; 528 offset.ascenderOffset = 0.0f; 529 530 DWRITE_GLYPH_RUN run; 531 run.glyphCount = 1; 532 run.glyphAdvances = &advance; 533 run.fontFace = this->getDWriteTypeface()->fDWriteFontFace.get(); 534 run.fontEmSize = SkScalarToFloat(fTextSizeRender); 535 run.bidiLevel = 0; 536 run.glyphIndices = &glyphId; 537 run.isSideways = FALSE; 538 run.glyphOffsets = &offset; 539 540 HRESULT hr = this->getDWriteTypeface()->fFactory2->TranslateColorGlyphRun( 541 0, 0, &run, nullptr, fMeasuringMode, &fXform, 0, colorGlyph); 542 if (hr == DWRITE_E_NOCOLOR) { 543 return false; 544 } 545 HRBM(hr, "Failed to translate color glyph run"); 546 return true; 547 } 548 549 void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) { 550 glyph->fWidth = 0; 551 glyph->fHeight = 0; 552 glyph->fLeft = 0; 553 glyph->fTop = 0; 554 555 this->generateAdvance(glyph); 556 557 if (fIsColorFont && isColorGlyph(*glyph)) { 558 glyph->fMaskFormat = SkMask::kARGB32_Format; 559 } 560 561 RECT bbox; 562 HRVM(this->getBoundingBox(glyph, fRenderingMode, fTextureType, &bbox), 563 "Requested bounding box could not be determined."); 564 565 if (glyph_check_and_set_bounds(glyph, bbox)) { 566 return; 567 } 568 569 // GetAlphaTextureBounds succeeds but returns an empty RECT if there are no 570 // glyphs of the specified texture type. When this happens, try with the 571 // alternate texture type. 572 if (DWRITE_TEXTURE_CLEARTYPE_3x1 == fTextureType) { 573 HRVM(this->getBoundingBox(glyph, 574 DWRITE_RENDERING_MODE_ALIASED, 575 DWRITE_TEXTURE_ALIASED_1x1, 576 &bbox), 577 "Fallback bounding box could not be determined."); 578 if (glyph_check_and_set_bounds(glyph, bbox)) { 579 glyph->fForceBW = 1; 580 } 581 } 582 // TODO: handle the case where a request for DWRITE_TEXTURE_ALIASED_1x1 583 // fails, and try DWRITE_TEXTURE_CLEARTYPE_3x1. 584 } 585 586 void SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* metrics) { 587 if (nullptr == metrics) { 588 return; 589 } 590 591 sk_bzero(metrics, sizeof(*metrics)); 592 593 DWRITE_FONT_METRICS dwfm; 594 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode || 595 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode) 596 { 597 this->getDWriteTypeface()->fDWriteFontFace->GetGdiCompatibleMetrics( 598 fTextSizeRender, 599 1.0f, // pixelsPerDip 600 &fXform, 601 &dwfm); 602 } else { 603 this->getDWriteTypeface()->fDWriteFontFace->GetMetrics(&dwfm); 604 } 605 606 SkScalar upem = SkIntToScalar(dwfm.designUnitsPerEm); 607 608 metrics->fAscent = -fTextSizeRender * SkIntToScalar(dwfm.ascent) / upem; 609 metrics->fDescent = fTextSizeRender * SkIntToScalar(dwfm.descent) / upem; 610 metrics->fLeading = fTextSizeRender * SkIntToScalar(dwfm.lineGap) / upem; 611 metrics->fXHeight = fTextSizeRender * SkIntToScalar(dwfm.xHeight) / upem; 612 metrics->fCapHeight = fTextSizeRender * SkIntToScalar(dwfm.capHeight) / upem; 613 metrics->fUnderlineThickness = fTextSizeRender * SkIntToScalar(dwfm.underlineThickness) / upem; 614 metrics->fUnderlinePosition = -(fTextSizeRender * SkIntToScalar(dwfm.underlinePosition) / upem); 615 616 metrics->fFlags |= SkPaint::FontMetrics::kUnderlineThicknessIsValid_Flag; 617 metrics->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag; 618 619 if (this->getDWriteTypeface()->fDWriteFontFace1.get()) { 620 DWRITE_FONT_METRICS1 dwfm1; 621 this->getDWriteTypeface()->fDWriteFontFace1->GetMetrics(&dwfm1); 622 metrics->fTop = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxTop) / upem; 623 metrics->fBottom = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxBottom) / upem; 624 metrics->fXMin = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxLeft) / upem; 625 metrics->fXMax = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxRight) / upem; 626 627 metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin; 628 return; 629 } 630 631 AutoTDWriteTable<SkOTTableHead> head(this->getDWriteTypeface()->fDWriteFontFace.get()); 632 if (head.fExists && 633 head.fSize >= sizeof(SkOTTableHead) && 634 head->version == SkOTTableHead::version1) 635 { 636 metrics->fTop = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMax) / upem; 637 metrics->fBottom = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMin) / upem; 638 metrics->fXMin = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMin) / upem; 639 metrics->fXMax = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMax) / upem; 640 641 metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin; 642 return; 643 } 644 645 metrics->fTop = metrics->fAscent; 646 metrics->fBottom = metrics->fDescent; 647 } 648 649 /////////////////////////////////////////////////////////////////////////////// 650 651 #include "SkColorPriv.h" 652 653 static void bilevel_to_bw(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph) { 654 const int width = glyph.fWidth; 655 const size_t dstRB = (width + 7) >> 3; 656 uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage); 657 658 int byteCount = width >> 3; 659 int bitCount = width & 7; 660 661 for (int y = 0; y < glyph.fHeight; ++y) { 662 if (byteCount > 0) { 663 for (int i = 0; i < byteCount; ++i) { 664 unsigned byte = 0; 665 byte |= src[0] & (1 << 7); 666 byte |= src[1] & (1 << 6); 667 byte |= src[2] & (1 << 5); 668 byte |= src[3] & (1 << 4); 669 byte |= src[4] & (1 << 3); 670 byte |= src[5] & (1 << 2); 671 byte |= src[6] & (1 << 1); 672 byte |= src[7] & (1 << 0); 673 dst[i] = byte; 674 src += 8; 675 } 676 } 677 if (bitCount > 0) { 678 unsigned byte = 0; 679 unsigned mask = 0x80; 680 for (int i = 0; i < bitCount; i++) { 681 byte |= (src[i]) & mask; 682 mask >>= 1; 683 } 684 dst[byteCount] = byte; 685 } 686 src += bitCount; 687 dst += dstRB; 688 } 689 } 690 691 template<bool APPLY_PREBLEND> 692 static void grayscale_to_a8(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, 693 const uint8_t* table8) { 694 const size_t dstRB = glyph.rowBytes(); 695 const U16CPU width = glyph.fWidth; 696 uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage); 697 698 for (U16CPU y = 0; y < glyph.fHeight; y++) { 699 for (U16CPU i = 0; i < width; i++) { 700 U8CPU a = *(src++); 701 dst[i] = sk_apply_lut_if<APPLY_PREBLEND>(a, table8); 702 } 703 dst = SkTAddOffset<uint8_t>(dst, dstRB); 704 } 705 } 706 707 template<bool APPLY_PREBLEND> 708 static void rgb_to_a8(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, const uint8_t* table8) { 709 const size_t dstRB = glyph.rowBytes(); 710 const U16CPU width = glyph.fWidth; 711 uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage); 712 713 for (U16CPU y = 0; y < glyph.fHeight; y++) { 714 for (U16CPU i = 0; i < width; i++) { 715 U8CPU r = *(src++); 716 U8CPU g = *(src++); 717 U8CPU b = *(src++); 718 dst[i] = sk_apply_lut_if<APPLY_PREBLEND>((r + g + b) / 3, table8); 719 } 720 dst = SkTAddOffset<uint8_t>(dst, dstRB); 721 } 722 } 723 724 template<bool APPLY_PREBLEND, bool RGB> 725 static void rgb_to_lcd16(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, 726 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) { 727 const size_t dstRB = glyph.rowBytes(); 728 const U16CPU width = glyph.fWidth; 729 uint16_t* SK_RESTRICT dst = static_cast<uint16_t*>(glyph.fImage); 730 731 for (U16CPU y = 0; y < glyph.fHeight; y++) { 732 for (U16CPU i = 0; i < width; i++) { 733 U8CPU r, g, b; 734 if (RGB) { 735 r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR); 736 g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG); 737 b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB); 738 } else { 739 b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB); 740 g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG); 741 r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR); 742 } 743 dst[i] = SkPack888ToRGB16(r, g, b); 744 } 745 dst = SkTAddOffset<uint16_t>(dst, dstRB); 746 } 747 } 748 749 const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph, 750 DWRITE_RENDERING_MODE renderingMode, 751 DWRITE_TEXTURE_TYPE textureType) 752 { 753 int sizeNeeded = glyph.fWidth * glyph.fHeight; 754 if (DWRITE_TEXTURE_CLEARTYPE_3x1 == textureType) { 755 sizeNeeded *= 3; 756 } 757 if (sizeNeeded > fBits.count()) { 758 fBits.setCount(sizeNeeded); 759 } 760 761 // erase 762 memset(fBits.begin(), 0, sizeNeeded); 763 764 fXform.dx = SkFixedToFloat(glyph.getSubXFixed()); 765 fXform.dy = SkFixedToFloat(glyph.getSubYFixed()); 766 767 FLOAT advance = 0.0f; 768 769 UINT16 index = glyph.getGlyphID(); 770 771 DWRITE_GLYPH_OFFSET offset; 772 offset.advanceOffset = 0.0f; 773 offset.ascenderOffset = 0.0f; 774 775 DWRITE_GLYPH_RUN run; 776 run.glyphCount = 1; 777 run.glyphAdvances = &advance; 778 run.fontFace = this->getDWriteTypeface()->fDWriteFontFace.get(); 779 run.fontEmSize = SkScalarToFloat(fTextSizeRender); 780 run.bidiLevel = 0; 781 run.glyphIndices = &index; 782 run.isSideways = FALSE; 783 run.glyphOffsets = &offset; 784 { 785 SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis; 786 { 787 SkAutoExclusive l(DWriteFactoryMutex); 788 // IDWriteFactory2::CreateGlyphRunAnalysis is very bad at aliased glyphs. 789 if (this->getDWriteTypeface()->fFactory2 && 790 (fGridFitMode == DWRITE_GRID_FIT_MODE_DISABLED || 791 fAntiAliasMode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)) 792 { 793 HRNM(this->getDWriteTypeface()->fFactory2->CreateGlyphRunAnalysis(&run, 794 &fXform, 795 renderingMode, 796 fMeasuringMode, 797 fGridFitMode, 798 fAntiAliasMode, 799 0.0f, // baselineOriginX, 800 0.0f, // baselineOriginY, 801 &glyphRunAnalysis), 802 "Could not create DW2 glyph run analysis."); 803 } else { 804 HRNM(this->getDWriteTypeface()->fFactory->CreateGlyphRunAnalysis(&run, 805 1.0f, // pixelsPerDip, 806 &fXform, 807 renderingMode, 808 fMeasuringMode, 809 0.0f, // baselineOriginX, 810 0.0f, // baselineOriginY, 811 &glyphRunAnalysis), 812 "Could not create glyph run analysis."); 813 } 814 } 815 //NOTE: this assumes that the glyph has already been measured 816 //with an exact same glyph run analysis. 817 RECT bbox; 818 bbox.left = glyph.fLeft; 819 bbox.top = glyph.fTop; 820 bbox.right = glyph.fLeft + glyph.fWidth; 821 bbox.bottom = glyph.fTop + glyph.fHeight; 822 { 823 Shared l(DWriteFactoryMutex); 824 HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType, 825 &bbox, 826 fBits.begin(), 827 sizeNeeded), 828 "Could not draw mask."); 829 } 830 } 831 return fBits.begin(); 832 } 833 834 void SkScalerContext_DW::generateColorGlyphImage(const SkGlyph& glyph) { 835 SkASSERT(isColorGlyph(glyph)); 836 SkASSERT(glyph.fMaskFormat == SkMask::Format::kARGB32_Format); 837 838 memset(glyph.fImage, 0, glyph.computeImageSize()); 839 840 SkTScopedComPtr<IDWriteColorGlyphRunEnumerator> colorLayers; 841 getColorGlyphRun(glyph, &colorLayers); 842 SkASSERT(colorLayers.get()); 843 844 SkMatrix matrix = fSkXform; 845 matrix.postTranslate(-SkIntToScalar(glyph.fLeft), -SkIntToScalar(glyph.fTop)); 846 SkRasterClip rc(SkIRect::MakeWH(glyph.fWidth, glyph.fHeight)); 847 SkDraw draw; 848 draw.fDst = SkPixmap(SkImageInfo::MakeN32(glyph.fWidth, glyph.fHeight, kPremul_SkAlphaType), 849 glyph.fImage, 850 glyph.ComputeRowBytes(glyph.fWidth, SkMask::Format::kARGB32_Format)); 851 draw.fMatrix = &matrix; 852 draw.fRC = &rc; 853 854 SkPaint paint; 855 if (fRenderingMode != DWRITE_RENDERING_MODE_ALIASED) { 856 paint.setFlags(SkPaint::Flags::kAntiAlias_Flag); 857 } 858 859 BOOL hasNextRun = FALSE; 860 while (SUCCEEDED(colorLayers->MoveNext(&hasNextRun)) && hasNextRun) { 861 const DWRITE_COLOR_GLYPH_RUN* colorGlyph; 862 HRVM(colorLayers->GetCurrentRun(&colorGlyph), "Could not get current color glyph run"); 863 864 SkColor color; 865 if (colorGlyph->paletteIndex != 0xffff) { 866 color = SkColorSetARGB(SkFloatToIntRound(colorGlyph->runColor.a * 255), 867 SkFloatToIntRound(colorGlyph->runColor.r * 255), 868 SkFloatToIntRound(colorGlyph->runColor.g * 255), 869 SkFloatToIntRound(colorGlyph->runColor.b * 255)); 870 } else { 871 // If all components of runColor are 0 or (equivalently) paletteIndex is 0xFFFF then 872 // the 'current brush' is used. fRec.getLuminanceColor() is kinda sorta what is wanted 873 // here, but not really, it will often be the wrong value because it wan't designed for 874 // this. 875 // TODO: implement this fully, bug.skia.org/5788 876 color = fRec.getLuminanceColor(); 877 } 878 paint.setColor(color); 879 880 SkPath path; 881 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath; 882 HRVM(SkDWriteGeometrySink::Create(&path, &geometryToPath), 883 "Could not create geometry to path converter."); 884 { 885 SkAutoExclusive l(DWriteFactoryMutex); 886 HRVM(colorGlyph->glyphRun.fontFace->GetGlyphRunOutline( 887 colorGlyph->glyphRun.fontEmSize, 888 colorGlyph->glyphRun.glyphIndices, 889 colorGlyph->glyphRun.glyphAdvances, 890 colorGlyph->glyphRun.glyphOffsets, 891 colorGlyph->glyphRun.glyphCount, 892 colorGlyph->glyphRun.isSideways, 893 colorGlyph->glyphRun.bidiLevel % 2, //rtl 894 geometryToPath.get()), 895 "Could not create glyph outline."); 896 } 897 draw.drawPath(path, paint, nullptr, true /* pathIsMutable */); 898 } 899 } 900 901 void SkScalerContext_DW::generateImage(const SkGlyph& glyph) { 902 //Create the mask. 903 DWRITE_RENDERING_MODE renderingMode = fRenderingMode; 904 DWRITE_TEXTURE_TYPE textureType = fTextureType; 905 if (glyph.fForceBW) { 906 renderingMode = DWRITE_RENDERING_MODE_ALIASED; 907 textureType = DWRITE_TEXTURE_ALIASED_1x1; 908 } 909 910 if (SkMask::kARGB32_Format == glyph.fMaskFormat) { 911 generateColorGlyphImage(glyph); 912 return; 913 } 914 915 const void* bits = this->drawDWMask(glyph, renderingMode, textureType); 916 if (!bits) { 917 sk_bzero(glyph.fImage, glyph.computeImageSize()); 918 return; 919 } 920 921 //Copy the mask into the glyph. 922 const uint8_t* src = (const uint8_t*)bits; 923 if (DWRITE_RENDERING_MODE_ALIASED == renderingMode) { 924 bilevel_to_bw(src, glyph); 925 const_cast<SkGlyph&>(glyph).fMaskFormat = SkMask::kBW_Format; 926 } else if (!isLCD(fRec)) { 927 if (textureType == DWRITE_TEXTURE_ALIASED_1x1) { 928 if (fPreBlend.isApplicable()) { 929 grayscale_to_a8<true>(src, glyph, fPreBlend.fG); 930 } else { 931 grayscale_to_a8<false>(src, glyph, fPreBlend.fG); 932 } 933 } else { 934 if (fPreBlend.isApplicable()) { 935 rgb_to_a8<true>(src, glyph, fPreBlend.fG); 936 } else { 937 rgb_to_a8<false>(src, glyph, fPreBlend.fG); 938 } 939 } 940 } else { 941 SkASSERT(SkMask::kLCD16_Format == glyph.fMaskFormat); 942 if (fPreBlend.isApplicable()) { 943 if (fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag) { 944 rgb_to_lcd16<true, false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 945 } else { 946 rgb_to_lcd16<true, true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 947 } 948 } else { 949 if (fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag) { 950 rgb_to_lcd16<false, false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 951 } else { 952 rgb_to_lcd16<false, true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 953 } 954 } 955 } 956 } 957 958 void SkScalerContext_DW::generatePath(SkGlyphID glyph, SkPath* path) { 959 SkASSERT(path); 960 961 path->reset(); 962 963 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath; 964 HRVM(SkDWriteGeometrySink::Create(path, &geometryToPath), 965 "Could not create geometry to path converter."); 966 UINT16 glyphId = SkTo<UINT16>(glyph); 967 { 968 SkAutoExclusive l(DWriteFactoryMutex); 969 //TODO: convert to<->from DIUs? This would make a difference if hinting. 970 //It may not be needed, it appears that DirectWrite only hints at em size. 971 HRVM(this->getDWriteTypeface()->fDWriteFontFace->GetGlyphRunOutline( 972 SkScalarToFloat(fTextSizeRender), 973 &glyphId, 974 nullptr, //advances 975 nullptr, //offsets 976 1, //num glyphs 977 FALSE, //sideways 978 FALSE, //rtl 979 geometryToPath.get()), 980 "Could not create glyph outline."); 981 } 982 983 path->transform(fSkXform); 984 } 985 986 #endif//defined(SK_BUILD_FOR_WIN32) 987