SkScalerContext_win_dw.cpp (101824B)
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 #include "src/utils/win/SkDWriteNTDDI_VERSION.h" 8 9 #include "include/core/SkTypes.h" 10 #if defined(SK_BUILD_FOR_WIN) 11 12 #undef GetGlyphIndices 13 14 #include "include/codec/SkCodec.h" 15 #include "include/codec/SkPngDecoder.h" 16 #include "include/core/SkBBHFactory.h" 17 #include "include/core/SkBitmap.h" 18 #include "include/core/SkData.h" 19 #include "include/core/SkDrawable.h" 20 #include "include/core/SkFontMetrics.h" 21 #include "include/core/SkGraphics.h" 22 #include "include/core/SkImage.h" 23 #include "include/core/SkOpenTypeSVGDecoder.h" 24 #include "include/core/SkPath.h" 25 #include "include/core/SkPictureRecorder.h" 26 #include "include/core/SkSpan.h" 27 #include "include/effects/SkGradientShader.h" 28 #include "include/private/base/SkMutex.h" 29 #include "include/private/base/SkTo.h" 30 #include "src/base/SkEndian.h" 31 #include "src/base/SkScopeExit.h" 32 #include "src/base/SkSharedMutex.h" 33 #include "src/core/SkDraw.h" 34 #include "src/core/SkGlyph.h" 35 #include "src/core/SkMaskGamma.h" 36 #include "src/core/SkRasterClip.h" 37 #include "src/core/SkScalerContext.h" 38 #include "src/ports/SkScalerContext_win_dw.h" 39 #include "src/ports/SkTypeface_win_dw.h" 40 #include "src/sfnt/SkOTTable_EBLC.h" 41 #include "src/sfnt/SkOTTable_EBSC.h" 42 #include "src/sfnt/SkOTTable_gasp.h" 43 #include "src/sfnt/SkOTTable_maxp.h" 44 #include "src/utils/SkMatrix22.h" 45 #include "src/utils/win/SkDWrite.h" 46 #include "src/utils/win/SkDWriteGeometrySink.h" 47 #include "src/utils/win/SkHRESULT.h" 48 #include "src/utils/win/SkTScopedComPtr.h" 49 50 #include <dwrite.h> 51 #include <dwrite_1.h> 52 #include <dwrite_3.h> 53 54 namespace { 55 static inline const constexpr bool kSkShowTextBlitCoverage = false; 56 57 /* Note: 58 * In versions 8 and 8.1 of Windows, some calls in DWrite are not thread safe. 59 * The mutex returned from maybe_dw_mutex protects the calls that are 60 * problematic. 61 */ 62 static SkSharedMutex* maybe_dw_mutex(DWriteFontTypeface& typeface) { 63 static SkSharedMutex mutex; 64 return typeface.fDWriteFontFace4 ? nullptr : &mutex; 65 } 66 67 class SK_SCOPED_CAPABILITY Exclusive { 68 public: 69 explicit Exclusive(SkSharedMutex* maybe_lock) SK_ACQUIRE(*maybe_lock) 70 : fLock(maybe_lock) { 71 if (fLock) { 72 fLock->acquire(); 73 } 74 } 75 ~Exclusive() SK_RELEASE_CAPABILITY() { 76 if (fLock) { 77 fLock->release(); 78 } 79 } 80 81 private: 82 SkSharedMutex* fLock; 83 }; 84 class SK_SCOPED_CAPABILITY Shared { 85 public: 86 explicit Shared(SkSharedMutex* maybe_lock) SK_ACQUIRE_SHARED(*maybe_lock) 87 : fLock(maybe_lock) { 88 if (fLock) { 89 fLock->acquireShared(); 90 } 91 } 92 93 // You would think this should be SK_RELEASE_SHARED_CAPABILITY, but SK_SCOPED_CAPABILITY 94 // doesn't fully understand the difference between shared and exclusive. 95 // Please review https://reviews.llvm.org/D52578 for more information. 96 ~Shared() SK_RELEASE_CAPABILITY() { 97 if (fLock) { 98 fLock->releaseShared(); 99 } 100 } 101 102 private: 103 SkSharedMutex* fLock; 104 }; 105 106 static bool isLCD(const SkScalerContextRec& rec) { 107 return SkMask::kLCD16_Format == rec.fMaskFormat; 108 } 109 110 static bool is_hinted(DWriteFontTypeface* typeface) { 111 Exclusive l(maybe_dw_mutex(*typeface)); 112 AutoTDWriteTable<SkOTTableMaximumProfile> maxp(typeface->fDWriteFontFace.get()); 113 if (!maxp.fExists) { 114 return false; 115 } 116 if (maxp.fSize < sizeof(SkOTTableMaximumProfile::Version::TT)) { 117 return false; 118 } 119 if (maxp->version.version != SkOTTableMaximumProfile::Version::TT::VERSION) { 120 return false; 121 } 122 return (0 != maxp->version.tt.maxSizeOfInstructions); 123 } 124 125 /** A GaspRange is inclusive, [min, max]. */ 126 struct GaspRange { 127 using Behavior = SkOTTableGridAndScanProcedure::GaspRange::behavior; 128 GaspRange(int min, int max, int version, Behavior flags) 129 : fMin(min), fMax(max), fVersion(version), fFlags(flags) { } 130 int fMin; 131 int fMax; 132 int fVersion; 133 Behavior fFlags; 134 }; 135 136 bool get_gasp_range(DWriteFontTypeface* typeface, int size, GaspRange* range) { 137 AutoTDWriteTable<SkOTTableGridAndScanProcedure> gasp(typeface->fDWriteFontFace.get()); 138 if (!gasp.fExists) { 139 return false; 140 } 141 if (gasp.fSize < sizeof(SkOTTableGridAndScanProcedure)) { 142 return false; 143 } 144 if (gasp->version != SkOTTableGridAndScanProcedure::version0 && 145 gasp->version != SkOTTableGridAndScanProcedure::version1) 146 { 147 return false; 148 } 149 150 uint16_t numRanges = SkEndianSwap16(gasp->numRanges); 151 if (numRanges > 1024 || 152 gasp.fSize < sizeof(SkOTTableGridAndScanProcedure) + 153 sizeof(SkOTTableGridAndScanProcedure::GaspRange) * numRanges) 154 { 155 return false; 156 } 157 158 const SkOTTableGridAndScanProcedure::GaspRange* rangeTable = 159 SkTAfter<const SkOTTableGridAndScanProcedure::GaspRange>(gasp.get()); 160 int minPPEM = -1; 161 for (uint16_t i = 0; i < numRanges; ++i, ++rangeTable) { 162 int maxPPEM = SkEndianSwap16(rangeTable->maxPPEM); 163 if (minPPEM < size && size <= maxPPEM) { 164 range->fMin = minPPEM + 1; 165 range->fMax = maxPPEM; 166 range->fVersion = SkEndian_SwapBE16(gasp->version); 167 range->fFlags = rangeTable->flags; 168 return true; 169 } 170 minPPEM = maxPPEM; 171 } 172 return false; 173 } 174 /** If the rendering mode for the specified 'size' is gridfit, then place 175 * the gridfit range into 'range'. Otherwise, leave 'range' alone. 176 */ 177 static bool is_gridfit_only(GaspRange::Behavior flags) { 178 return flags.raw.value == GaspRange::Behavior::Raw::GridfitMask; 179 } 180 181 static bool has_bitmap_strike(DWriteFontTypeface* typeface, GaspRange range) { 182 Exclusive l(maybe_dw_mutex(*typeface)); 183 { 184 AutoTDWriteTable<SkOTTableEmbeddedBitmapLocation> eblc(typeface->fDWriteFontFace.get()); 185 if (!eblc.fExists) { 186 return false; 187 } 188 if (eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation)) { 189 return false; 190 } 191 if (eblc->version != SkOTTableEmbeddedBitmapLocation::version_initial) { 192 return false; 193 } 194 195 uint32_t numSizes = SkEndianSwap32(eblc->numSizes); 196 if (numSizes > 1024 || 197 eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation) + 198 sizeof(SkOTTableEmbeddedBitmapLocation::BitmapSizeTable) * numSizes) 199 { 200 return false; 201 } 202 203 const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable* sizeTable = 204 SkTAfter<const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable>(eblc.get()); 205 for (uint32_t i = 0; i < numSizes; ++i, ++sizeTable) { 206 if (sizeTable->ppemX == sizeTable->ppemY && 207 range.fMin <= sizeTable->ppemX && sizeTable->ppemX <= range.fMax) 208 { 209 // TODO: determine if we should dig through IndexSubTableArray/IndexSubTable 210 // to determine the actual number of glyphs with bitmaps. 211 212 // TODO: Ensure that the bitmaps actually cover a significant portion of the strike. 213 214 // TODO: Ensure that the bitmaps are bi-level? 215 if (sizeTable->endGlyphIndex >= sizeTable->startGlyphIndex + 3) { 216 return true; 217 } 218 } 219 } 220 } 221 222 { 223 AutoTDWriteTable<SkOTTableEmbeddedBitmapScaling> ebsc(typeface->fDWriteFontFace.get()); 224 if (!ebsc.fExists) { 225 return false; 226 } 227 if (ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling)) { 228 return false; 229 } 230 if (ebsc->version != SkOTTableEmbeddedBitmapScaling::version_initial) { 231 return false; 232 } 233 234 uint32_t numSizes = SkEndianSwap32(ebsc->numSizes); 235 if (numSizes > 1024 || 236 ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling) + 237 sizeof(SkOTTableEmbeddedBitmapScaling::BitmapScaleTable) * numSizes) 238 { 239 return false; 240 } 241 242 const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable* scaleTable = 243 SkTAfter<const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable>(ebsc.get()); 244 for (uint32_t i = 0; i < numSizes; ++i, ++scaleTable) { 245 if (scaleTable->ppemX == scaleTable->ppemY && 246 range.fMin <= scaleTable->ppemX && scaleTable->ppemX <= range.fMax) { 247 // EBSC tables are normally only found in bitmap only fonts. 248 return true; 249 } 250 } 251 } 252 253 return false; 254 } 255 256 static bool both_zero(SkScalar a, SkScalar b) { 257 return 0 == a && 0 == b; 258 } 259 260 // returns false if there is any non-90-rotation or skew 261 static bool is_axis_aligned(const SkScalerContextRec& rec) { 262 return 0 == rec.fPreSkewX && 263 (both_zero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) || 264 both_zero(rec.fPost2x2[0][0], rec.fPost2x2[1][1])); 265 } 266 267 } //namespace 268 269 SkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface& typefaceRef, 270 const SkScalerContextEffects& effects, 271 const SkDescriptor* desc) 272 : SkScalerContext(typefaceRef, effects, desc) 273 { 274 DWriteFontTypeface* typeface = this->getDWriteTypeface(); 275 fGlyphCount = typeface->fDWriteFontFace->GetGlyphCount(); 276 277 fClearTypeLevel = int(typeface->GetClearTypeLevel() * 256); 278 279 // In general, all glyphs should use DWriteFontFace::GetRecommendedRenderingMode 280 // except when bi-level rendering is requested or there are embedded 281 // bi-level bitmaps (and the embedded bitmap flag is set and no rotation). 282 // 283 // DirectWrite's IDWriteFontFace::GetRecommendedRenderingMode does not do 284 // this. As a result, determine the actual size of the text and then see if 285 // there are any embedded bi-level bitmaps of that size. If there are, then 286 // force bitmaps by requesting bi-level rendering. 287 // 288 // FreeType allows for separate ppemX and ppemY, but DirectWrite assumes 289 // square pixels and only uses ppemY. Therefore the transform must track any 290 // non-uniform x-scale. 291 // 292 // Also, rotated glyphs should have the same absolute advance widths as 293 // horizontal glyphs and the subpixel flag should not affect glyph shapes. 294 295 SkVector scale; 296 fRec.computeMatrices(SkScalerContextRec::PreMatrixScale::kVertical, &scale, &fSkXform); 297 298 fXform.m11 = SkScalarToFloat(fSkXform.getScaleX()); 299 fXform.m12 = SkScalarToFloat(fSkXform.getSkewY()); 300 fXform.m21 = SkScalarToFloat(fSkXform.getSkewX()); 301 fXform.m22 = SkScalarToFloat(fSkXform.getScaleY()); 302 fXform.dx = 0; 303 fXform.dy = 0; 304 305 // realTextSize is the actual device size we want (as opposed to the size the user requested). 306 // gdiTextSize is the size we request when GDI compatible. 307 // If the scale is negative, this means the matrix will do the flip anyway. 308 const SkScalar realTextSize = scale.fY; 309 // Due to floating point math, the lower bits are suspect. Round carefully. 310 SkScalar gdiTextSize = SkScalarRoundToScalar(realTextSize * 64.0f) / 64.0f; 311 if (gdiTextSize == 0) { 312 gdiTextSize = SK_Scalar1; 313 } 314 315 bool bitmapRequested = SkToBool(fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag); 316 bool treatLikeBitmap = false; 317 bool axisAlignedBitmap = false; 318 if (bitmapRequested) { 319 // When embedded bitmaps are requested, treat the entire range like 320 // a bitmap strike if the range is gridfit only and contains a bitmap. 321 int bitmapPPEM = SkScalarTruncToInt(gdiTextSize); 322 GaspRange range(bitmapPPEM, bitmapPPEM, 0, GaspRange::Behavior()); 323 if (get_gasp_range(typeface, bitmapPPEM, &range)) { 324 if (!is_gridfit_only(range.fFlags)) { 325 range = GaspRange(bitmapPPEM, bitmapPPEM, 0, GaspRange::Behavior()); 326 } 327 } 328 treatLikeBitmap = has_bitmap_strike(typeface, range); 329 330 axisAlignedBitmap = is_axis_aligned(fRec); 331 } 332 333 GaspRange range(0, 0xFFFF, 0, GaspRange::Behavior()); 334 335 // If the user requested aliased, do so with aliased compatible metrics. 336 if (SkMask::kBW_Format == fRec.fMaskFormat) { 337 fTextSizeRender = gdiTextSize; 338 fRenderingMode = DWRITE_RENDERING_MODE_ALIASED; 339 fTextureType = DWRITE_TEXTURE_ALIASED_1x1; 340 fTextSizeMeasure = gdiTextSize; 341 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; 342 343 // If we can use a bitmap, use gdi classic rendering and measurement. 344 // This will not always provide a bitmap, but matches expected behavior. 345 } else if ((treatLikeBitmap && axisAlignedBitmap) || typeface->ForceGDI()) { 346 fTextSizeRender = gdiTextSize; 347 fRenderingMode = DWRITE_RENDERING_MODE_GDI_CLASSIC; 348 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; 349 fTextSizeMeasure = gdiTextSize; 350 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; 351 352 // If rotated but the horizontal text could have used a bitmap, 353 // render high quality rotated glyphs but measure using bitmap metrics. 354 } else if (treatLikeBitmap) { 355 fTextSizeRender = gdiTextSize; 356 fRenderingMode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC; 357 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; 358 fTextSizeMeasure = gdiTextSize; 359 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; 360 361 // Force symmetric if the font is above the threshold or there is an explicit mode. 362 // Here we check if the size exceeds 20 before checking the GASP table to match the 363 // results of calling GetRecommendedRenderingMode/Direct2D, which skip looking at 364 // the GASP table if the text is too large. 365 } else if (realTextSize > SkIntToScalar(20) || 366 typeface->GetRenderingMode() == DWRITE_RENDERING_MODE_NATURAL || 367 typeface->GetRenderingMode() == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC) { 368 fTextSizeRender = realTextSize; 369 fRenderingMode = typeface->GetRenderingMode() == DWRITE_RENDERING_MODE_NATURAL ? 370 DWRITE_RENDERING_MODE_NATURAL : DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC; 371 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; 372 fTextSizeMeasure = realTextSize; 373 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL; 374 // If the font has a gasp table version 1, use it to determine symmetric rendering. 375 } else if (get_gasp_range(typeface, SkScalarRoundToInt(gdiTextSize), &range) && 376 range.fVersion >= 1) { 377 fTextSizeRender = realTextSize; 378 fRenderingMode = !range.fFlags.field.SymmetricSmoothing ? 379 DWRITE_RENDERING_MODE_NATURAL : DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC; 380 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; 381 fTextSizeMeasure = realTextSize; 382 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL; 383 // Fonts with hints, no gasp or gasp version 0, and below 20px get non-symmetric rendering. 384 // Often such fonts have hints which were only tested with GDI ClearType classic. 385 // Some of these fonts rely on drop out control in the y direction in order to be legible. 386 // Tenor Sans 387 // https://fonts.google.com/specimen/Tenor+Sans 388 // Gill Sans W04 389 // https://cdn.leagueoflegends.com/lolkit/1.1.9/resources/fonts/gill-sans-w04-book.woff 390 // https://na.leagueoflegends.com/en/news/game-updates/patch/patch-410-notes 391 // See https://crbug.com/385897 392 } else { 393 if (is_hinted(typeface)) { 394 fTextSizeRender = gdiTextSize; 395 fRenderingMode = DWRITE_RENDERING_MODE_NATURAL; 396 } else { 397 // Unhinted but with no gasp and below 20px defaults to symmetric for 398 // GetRecommendedRenderingMode. 399 fTextSizeRender = realTextSize; 400 fRenderingMode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC; 401 } 402 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; 403 fTextSizeMeasure = realTextSize; 404 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL; 405 } 406 407 // DirectWrite2 allows for grayscale hinting. 408 fAntiAliasMode = DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE; 409 if (typeface->fFactory2 && typeface->fDWriteFontFace2 && 410 SkMask::kA8_Format == fRec.fMaskFormat && 411 !(fRec.fFlags & SkScalerContext::kGenA8FromLCD_Flag)) 412 { 413 // DWRITE_TEXTURE_ALIASED_1x1 is now misnamed, it must also be used with grayscale. 414 fTextureType = DWRITE_TEXTURE_ALIASED_1x1; 415 fAntiAliasMode = DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE; 416 } 417 418 // DirectWrite2 allows hinting to be disabled. 419 fGridFitMode = DWRITE_GRID_FIT_MODE_ENABLED; 420 if (fRec.getHinting() == SkFontHinting::kNone) { 421 fGridFitMode = DWRITE_GRID_FIT_MODE_DISABLED; 422 if (fRenderingMode != DWRITE_RENDERING_MODE_ALIASED) { 423 fRenderingMode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC; 424 } 425 } 426 427 if (this->isLinearMetrics()) { 428 fTextSizeMeasure = realTextSize; 429 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL; 430 } 431 432 // The GDI measuring modes don't seem to work well with CBDT fonts (DWrite.dll 10.0.18362.836). 433 if (fMeasuringMode != DWRITE_MEASURING_MODE_NATURAL) { 434 constexpr UINT32 CBDTTag = DWRITE_MAKE_OPENTYPE_TAG('C','B','D','T'); 435 AutoDWriteTable CBDT(typeface->fDWriteFontFace.get(), CBDTTag); 436 if (CBDT.fExists) { 437 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL; 438 } 439 } 440 } 441 442 SkScalerContext_DW::~SkScalerContext_DW() { 443 } 444 445 #if !SK_DISABLE_DIRECTWRITE_COLRv1 && (DWRITE_CORE || (defined(NTDDI_WIN11_ZN) && NTDDI_VERSION >= NTDDI_WIN11_ZN)) 446 447 namespace { 448 SkColor4f sk_color_from(DWRITE_COLOR_F const& color) { 449 // DWRITE_COLOR_F and SkColor4f are laid out the same and this should be a no-op. 450 return SkColor4f{ color.r, color.g, color.b, color.a }; 451 } 452 DWRITE_COLOR_F dw_color_from(SkColor4f const& color) { 453 // DWRITE_COLOR_F and SkColor4f are laid out the same and this should be a no-op. 454 // Avoid brace initialization as DWRITE_COLOR_F can be defined as four floats (dxgitype.h, 455 // d3d9types.h) or four unions of two floats (dwrite_2.h, d3dtypes.h). The type changed in 456 // Direct3D 10, but the change does not appear to be documented. 457 DWRITE_COLOR_F dwColor; 458 dwColor.r = color.fR; 459 dwColor.g = color.fG; 460 dwColor.b = color.fB; 461 dwColor.a = color.fA; 462 return dwColor; 463 } 464 465 SkRect sk_rect_from(D2D_RECT_F const& rect) { 466 // D2D_RECT_F and SkRect are both y-down and laid the same so this should be a no-op. 467 return SkRect{ rect.left, rect.top, rect.right, rect.bottom }; 468 } 469 constexpr bool D2D_RECT_F_is_empty(const D2D_RECT_F& r) { 470 return r.right <= r.left || r.bottom <= r.top; 471 } 472 473 SkMatrix sk_matrix_from(DWRITE_MATRIX const& m) { 474 // DWRITE_MATRIX and SkMatrix are y-down. However DWRITE_MATRIX is affine only. 475 return SkMatrix::MakeAll( 476 m.m11, m.m21, m.dx, 477 m.m12, m.m22, m.dy, 478 0, 0, 1); 479 } 480 481 SkTileMode sk_tile_mode_from(D2D1_EXTEND_MODE extendMode) { 482 switch (extendMode) { 483 case D2D1_EXTEND_MODE_CLAMP: 484 return SkTileMode::kClamp; 485 case D2D1_EXTEND_MODE_WRAP: 486 return SkTileMode::kRepeat; 487 case D2D1_EXTEND_MODE_MIRROR: 488 return SkTileMode::kMirror; 489 default: 490 return SkTileMode::kClamp; 491 } 492 } 493 494 SkBlendMode sk_blend_mode_from(DWRITE_COLOR_COMPOSITE_MODE compositeMode) { 495 switch (compositeMode) { 496 case DWRITE_COLOR_COMPOSITE_CLEAR: 497 return SkBlendMode::kClear; 498 case DWRITE_COLOR_COMPOSITE_SRC: 499 return SkBlendMode::kSrc; 500 case DWRITE_COLOR_COMPOSITE_DEST: 501 return SkBlendMode::kDst; 502 case DWRITE_COLOR_COMPOSITE_SRC_OVER: 503 return SkBlendMode::kSrcOver; 504 case DWRITE_COLOR_COMPOSITE_DEST_OVER: 505 return SkBlendMode::kDstOver; 506 case DWRITE_COLOR_COMPOSITE_SRC_IN: 507 return SkBlendMode::kSrcIn; 508 case DWRITE_COLOR_COMPOSITE_DEST_IN: 509 return SkBlendMode::kDstIn; 510 case DWRITE_COLOR_COMPOSITE_SRC_OUT: 511 return SkBlendMode::kSrcOut; 512 case DWRITE_COLOR_COMPOSITE_DEST_OUT: 513 return SkBlendMode::kDstOut; 514 case DWRITE_COLOR_COMPOSITE_SRC_ATOP: 515 return SkBlendMode::kSrcATop; 516 case DWRITE_COLOR_COMPOSITE_DEST_ATOP: 517 return SkBlendMode::kDstATop; 518 case DWRITE_COLOR_COMPOSITE_XOR: 519 return SkBlendMode::kXor; 520 case DWRITE_COLOR_COMPOSITE_PLUS: 521 return SkBlendMode::kPlus; 522 523 case DWRITE_COLOR_COMPOSITE_SCREEN: 524 return SkBlendMode::kScreen; 525 case DWRITE_COLOR_COMPOSITE_OVERLAY: 526 return SkBlendMode::kOverlay; 527 case DWRITE_COLOR_COMPOSITE_DARKEN: 528 return SkBlendMode::kDarken; 529 case DWRITE_COLOR_COMPOSITE_LIGHTEN: 530 return SkBlendMode::kLighten; 531 case DWRITE_COLOR_COMPOSITE_COLOR_DODGE: 532 return SkBlendMode::kColorDodge; 533 case DWRITE_COLOR_COMPOSITE_COLOR_BURN: 534 return SkBlendMode::kColorBurn; 535 case DWRITE_COLOR_COMPOSITE_HARD_LIGHT: 536 return SkBlendMode::kHardLight; 537 case DWRITE_COLOR_COMPOSITE_SOFT_LIGHT: 538 return SkBlendMode::kSoftLight; 539 case DWRITE_COLOR_COMPOSITE_DIFFERENCE: 540 return SkBlendMode::kDifference; 541 case DWRITE_COLOR_COMPOSITE_EXCLUSION: 542 return SkBlendMode::kExclusion; 543 case DWRITE_COLOR_COMPOSITE_MULTIPLY: 544 return SkBlendMode::kMultiply; 545 546 case DWRITE_COLOR_COMPOSITE_HSL_HUE: 547 return SkBlendMode::kHue; 548 case DWRITE_COLOR_COMPOSITE_HSL_SATURATION: 549 return SkBlendMode::kSaturation; 550 case DWRITE_COLOR_COMPOSITE_HSL_COLOR: 551 return SkBlendMode::kColor; 552 case DWRITE_COLOR_COMPOSITE_HSL_LUMINOSITY: 553 return SkBlendMode::kLuminosity; 554 default: 555 return SkBlendMode::kDst; 556 } 557 } 558 559 inline SkPoint SkVectorProjection(SkPoint a, SkPoint b) { 560 SkScalar length = b.length(); 561 if (!length) { 562 return SkPoint(); 563 } 564 SkPoint bNormalized = b; 565 bNormalized.normalize(); 566 bNormalized.scale(SkPoint::DotProduct(a, b) / length); 567 return bNormalized; 568 } 569 570 // This linear interpolation is used for calculating a truncated color line in special edge cases. 571 // This interpolation needs to be kept in sync with what the gradient shader would normally do when 572 // truncating and drawing color lines. When drawing into N32 surfaces, this is expected to be true. 573 // If that changes, or if we support other color spaces in CPAL tables at some point, this needs to 574 // be looked at. 575 D2D1_COLOR_F lerpSkColor(D2D1_COLOR_F c0, D2D1_COLOR_F c1, float t) { 576 // Due to the floating point calculation in the caller, when interpolating between very narrow 577 // stops, we may get values outside the interpolation range, guard against these. 578 if (t < 0) { 579 return c0; 580 } 581 if (t > 1) { 582 return c1; 583 } 584 const auto c0_4f = skvx::float4(c0.r, c0.g, c0.b, c0.a), 585 c1_4f = skvx::float4(c1.r, c1.g, c1.b, c1.a), 586 c_4f = c0_4f + (c1_4f - c0_4f) * t; 587 D2D1_COLOR_F r; 588 c_4f.store(&r); 589 return r; 590 } 591 592 enum TruncateStops { 593 TruncateStart, 594 TruncateEnd, 595 }; 596 // Truncate a vector of color stops at a previously computed stop position and insert at that 597 // position the color interpolated between the surrounding stops. 598 void truncateToStopInterpolating(SkScalar zeroRadiusStop, 599 std::vector<D2D1_GRADIENT_STOP>& stops, 600 TruncateStops truncateStops) { 601 if (stops.size() <= 1u || 602 zeroRadiusStop < stops.front().position || stops.back().position < zeroRadiusStop) { 603 return; 604 } 605 606 auto lcmp = [](D2D1_GRADIENT_STOP const& stop, SkScalar position) { 607 return stop.position < position; 608 }; 609 auto ucmp = [](SkScalar position, D2D1_GRADIENT_STOP const& stop) { 610 return position < stop.position; 611 }; 612 size_t afterIndex = (truncateStops == TruncateStart) 613 ? std::lower_bound(stops.begin(), stops.end(), zeroRadiusStop, lcmp) - stops.begin() 614 : std::upper_bound(stops.begin(), stops.end(), zeroRadiusStop, ucmp) - stops.begin(); 615 616 const float t = (zeroRadiusStop - stops[afterIndex - 1].position) / 617 (stops[afterIndex].position - stops[afterIndex - 1].position); 618 D2D1_COLOR_F lerpColor = lerpSkColor(stops[afterIndex - 1].color, stops[afterIndex].color, t); 619 620 if (truncateStops == TruncateStart) { 621 stops.erase(stops.begin(), stops.begin() + afterIndex); 622 stops.insert(stops.begin(), { 0, lerpColor }); 623 } else { 624 stops.erase(stops.begin() + afterIndex, stops.end()); 625 stops.insert(stops.end(), { 1, lerpColor }); 626 } 627 } 628 } // namespace 629 630 bool SkScalerContext_DW::drawColorV1Paint(SkCanvas& canvas, 631 IDWritePaintReader& reader, 632 DWRITE_PAINT_ELEMENT const & element) 633 { 634 // Helper to draw the specified number of children. 635 auto drawChildren = [&](uint32_t childCount) -> bool { 636 if (childCount != 0) { 637 DWRITE_PAINT_ELEMENT childElement; 638 HRB(reader.MoveToFirstChild(&childElement)); 639 this->drawColorV1Paint(canvas, reader, childElement); 640 641 for (uint32_t i = 1; i < childCount; i++) { 642 HRB(reader.MoveToNextSibling(&childElement)); 643 this->drawColorV1Paint(canvas, reader, childElement); 644 } 645 646 HRB(reader.MoveToParent()); 647 } 648 return true; 649 }; 650 651 SkAutoCanvasRestore restoreCanvas(&canvas, true); 652 switch (element.paintType) { 653 case DWRITE_PAINT_TYPE_NONE: 654 return true; 655 656 case DWRITE_PAINT_TYPE_LAYERS: { 657 // A layers paint element has a variable number of children. 658 return drawChildren(element.paint.layers.childCount); 659 } 660 661 case DWRITE_PAINT_TYPE_SOLID_GLYPH: { 662 // A solid glyph paint element has no children. 663 // glyphIndex, color.value, color.paletteEntryIndex, color.alpha, color.colorAttributes 664 auto const& solidGlyph = element.paint.solidGlyph; 665 666 SkPathBuilder builder; 667 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath; 668 HRBM(SkDWriteGeometrySink::Create(&builder, &geometryToPath), 669 "Could not create geometry to path converter."); 670 UINT16 glyphId = SkTo<UINT16>(solidGlyph.glyphIndex); 671 { 672 Exclusive l(maybe_dw_mutex(*this->getDWriteTypeface())); 673 HRBM(this->getDWriteTypeface()->fDWriteFontFace->GetGlyphRunOutline( 674 SkScalarToFloat(fTextSizeRender), 675 &glyphId, 676 nullptr, //advances 677 nullptr, //offsets 678 1, //num glyphs 679 FALSE, //sideways 680 FALSE, //rtl 681 geometryToPath.get()), 682 "Could not create glyph outline."); 683 } 684 685 builder.transform(SkMatrix::Scale(1.0f / fTextSizeRender, 1.0f / fTextSizeRender)); 686 SkPaint skPaint; 687 skPaint.setColor4f(sk_color_from(solidGlyph.color.value)); 688 skPaint.setAntiAlias(fRenderingMode != DWRITE_RENDERING_MODE_ALIASED); 689 canvas.drawPath(builder.detach(), skPaint); 690 return true; 691 } 692 693 case DWRITE_PAINT_TYPE_SOLID: { 694 // A solid paint element has no children. 695 // value, paletteEntryIndex, alphaMultiplier, colorAttributes 696 SkPaint skPaint; 697 skPaint.setColor4f(sk_color_from(element.paint.solid.value)); 698 canvas.drawPaint(skPaint); 699 return true; 700 } 701 702 case DWRITE_PAINT_TYPE_LINEAR_GRADIENT: { 703 auto const& linearGradient = element.paint.linearGradient; 704 // A linear gradient paint element has no children. 705 // x0, y0, x1, y1, x2, y2, extendMode, gradientStopCount, [colorStops] 706 707 if (linearGradient.gradientStopCount == 0) { 708 return true; 709 } 710 std::vector<D2D1_GRADIENT_STOP> stops; 711 stops.resize(linearGradient.gradientStopCount); 712 713 // If success stops will be ordered. 714 HRBM(reader.GetGradientStops(0, stops.size(), stops.data()), 715 "Could not get linear gradient stops."); 716 SkPaint skPaint; 717 if (stops.size() == 1) { 718 skPaint.setColor4f(sk_color_from(stops[0].color)); 719 canvas.drawPaint(skPaint); 720 return true; 721 } 722 SkPoint linePositions[2] = { {linearGradient.x0, linearGradient.y0}, 723 {linearGradient.x1, linearGradient.y1} }; 724 SkPoint p0 = linePositions[0]; 725 SkPoint p1 = linePositions[1]; 726 SkPoint p2 = SkPoint::Make(linearGradient.x2, linearGradient.y2); 727 728 // If p0p1 or p0p2 are degenerate probably nothing should be drawn. 729 // If p0p1 and p0p2 are parallel then one side is the first color and the other side is 730 // the last color, depending on the direction. 731 // For now, just use the first color. 732 if (p1 == p0 || p2 == p0 || !SkPoint::CrossProduct(p1 - p0, p2 - p0)) { 733 skPaint.setColor4f(sk_color_from(stops[0].color)); 734 canvas.drawPaint(skPaint); 735 return true; 736 } 737 738 // Follow implementation note in nanoemoji: 739 // https://github.com/googlefonts/nanoemoji/blob/0ac6e7bb4d8202db692574d8530a9b643f1b3b3c/src/nanoemoji/svg.py#L188 740 // to compute a new gradient end point P3 as the orthogonal 741 // projection of the vector from p0 to p1 onto a line perpendicular 742 // to line p0p2 and passing through p0. 743 SkVector perpendicularToP2P0 = (p2 - p0); 744 perpendicularToP2P0 = SkPoint::Make( perpendicularToP2P0.y(), 745 -perpendicularToP2P0.x()); 746 SkVector p3 = p0 + SkVectorProjection((p1 - p0), perpendicularToP2P0); 747 linePositions[1] = p3; 748 749 // Project/scale points according to stop extrema along p0p3 line, 750 // p3 being the result of the projection above, then scale stops to 751 // to [0, 1] range so that repeat modes work. The Skia linear 752 // gradient shader performs the repeat modes over the 0 to 1 range, 753 // that's why we need to scale the stops to within that range. 754 SkTileMode tileMode = sk_tile_mode_from(SkTo<D2D1_EXTEND_MODE>(linearGradient.extendMode)); 755 SkScalar colorStopRange = stops.back().position - stops.front().position; 756 // If the color stops are all at the same offset position, repeat and reflect modes 757 // become meaningless. 758 if (colorStopRange == 0.f) { 759 if (tileMode != SkTileMode::kClamp) { 760 //skPaint.setColor(SK_ColorTRANSPARENT); 761 return true; 762 } else { 763 // Insert duplicated fake color stop in pad case at +1.0f to enable the projection 764 // of circles for an originally 0-length color stop range. Adding this stop will 765 // paint the equivalent gradient, because: All font specified color stops are in the 766 // same spot, mode is pad, so everything before this spot is painted with the first 767 // color, everything after this spot is painted with the last color. Not adding this 768 // stop will skip the projection and result in specifying non-normalized color stops 769 // to the shader. 770 stops.push_back({ stops.back().position + 1.0f, stops.back().color }); 771 colorStopRange = 1.0f; 772 } 773 } 774 SkASSERT(colorStopRange != 0.f); 775 776 // If the colorStopRange is 0 at this point, the default behavior of the shader is to 777 // clamp to 1 color stops that are above 1, clamp to 0 for color stops that are below 0, 778 // and repeat the outer color stops at 0 and 1 if the color stops are inside the 779 // range. That will result in the correct rendering. 780 if ((colorStopRange != 1 || stops.front().position != 0.f)) { 781 SkVector p0p3 = p3 - p0; 782 SkVector p0Offset = p0p3; 783 p0Offset.scale(stops.front().position); 784 SkVector p1Offset = p0p3; 785 p1Offset.scale(stops.back().position); 786 787 linePositions[0] = p0 + p0Offset; 788 linePositions[1] = p0 + p1Offset; 789 790 SkScalar scaleFactor = 1 / colorStopRange; 791 SkScalar startOffset = stops.front().position; 792 for (D2D1_GRADIENT_STOP& stop : stops) { 793 stop.position = (stop.position - startOffset) * scaleFactor; 794 } 795 } 796 797 std::unique_ptr<SkColor4f[]> skColors(new SkColor4f[stops.size()]); 798 std::unique_ptr<SkScalar[]> skStops(new SkScalar[stops.size()]); 799 for (size_t i = 0; i < stops.size(); ++i) { 800 skColors[i] = sk_color_from(stops[i].color); 801 skStops[i] = stops[i].position; 802 } 803 804 sk_sp<SkShader> shader(SkGradientShader::MakeLinear( 805 linePositions, 806 skColors.get(), SkColorSpace::MakeSRGB(), skStops.get(), stops.size(), 807 tileMode, 808 SkGradientShader::Interpolation{ 809 SkGradientShader::Interpolation::InPremul::kNo, 810 SkGradientShader::Interpolation::ColorSpace::kSRGB, 811 SkGradientShader::Interpolation::HueMethod::kShorter 812 }, 813 nullptr)); 814 815 SkASSERT(shader); 816 // An opaque color is needed to ensure the gradient is not modulated by alpha. 817 skPaint.setColor(SK_ColorBLACK); 818 skPaint.setShader(shader); 819 canvas.drawPaint(skPaint); 820 return true; 821 } 822 823 case DWRITE_PAINT_TYPE_RADIAL_GRADIENT: { 824 auto const& radialGradient = element.paint.radialGradient; 825 // A radial gradient paint element has no children. 826 // x0, y0, radius0, x1, y1, radius1, extendMode, gradientStopCount, [colorsStops] 827 828 SkPoint start = SkPoint::Make(radialGradient.x0, radialGradient.y0); 829 SkScalar startRadius = radialGradient.radius0; 830 SkPoint end = SkPoint::Make(radialGradient.x1, radialGradient.y1); 831 SkScalar endRadius = radialGradient.radius1; 832 833 if (radialGradient.gradientStopCount == 0) { 834 return true; 835 } 836 std::vector<D2D1_GRADIENT_STOP> stops; 837 stops.resize(radialGradient.gradientStopCount); 838 839 // If success stops will be ordered. 840 HRBM(reader.GetGradientStops(0, stops.size(), stops.data()), 841 "Could not get radial gradient stops."); 842 SkPaint skPaint; 843 if (stops.size() == 1) { 844 skPaint.setColor4f(sk_color_from(stops[0].color)); 845 canvas.drawPaint(skPaint); 846 return true; 847 } 848 849 SkScalar colorStopRange = stops.back().position - stops.front().position; 850 SkTileMode tileMode = sk_tile_mode_from(SkTo<D2D1_EXTEND_MODE>(radialGradient.extendMode)); 851 852 if (colorStopRange == 0.f) { 853 if (tileMode != SkTileMode::kClamp) { 854 //skPaint.setColor(SK_ColorTRANSPARENT); 855 return true; 856 } else { 857 // Insert duplicated fake color stop in pad case at +1.0f to enable the projection 858 // of circles for an originally 0-length color stop range. Adding this stop will 859 // paint the equivalent gradient, because: All font specified color stops are in the 860 // same spot, mode is pad, so everything before this spot is painted with the first 861 // color, everything after this spot is painted with the last color. Not adding this 862 // stop will skip the projection and result in specifying non-normalized color stops 863 // to the shader. 864 stops.push_back({ stops.back().position + 1.0f, stops.back().color }); 865 colorStopRange = 1.0f; 866 } 867 } 868 SkASSERT(colorStopRange != 0.f); 869 870 // If the colorStopRange is 0 at this point, the default behavior of the shader is to 871 // clamp to 1 color stops that are above 1, clamp to 0 for color stops that are below 0, 872 // and repeat the outer color stops at 0 and 1 if the color stops are inside the 873 // range. That will result in the correct rendering. 874 if (colorStopRange != 1 || stops.front().position != 0.f) { 875 // For the Skia two-point caonical shader to understand the 876 // COLRv1 color stops we need to scale stops to 0 to 1 range and 877 // interpolate new centers and radii. Otherwise the shader 878 // clamps stops outside the range to 0 and 1 (larger interval) 879 // or repeats the outer stops at 0 and 1 if the (smaller 880 // interval). 881 SkVector startToEnd = end - start; 882 SkScalar radiusDiff = endRadius - startRadius; 883 SkScalar scaleFactor = 1 / colorStopRange; 884 SkScalar stopsStartOffset = stops.front().position; 885 886 SkVector startOffset = startToEnd; 887 startOffset.scale(stops.front().position); 888 SkVector endOffset = startToEnd; 889 endOffset.scale(stops.back().position); 890 891 // The order of the following computations is important in order to avoid 892 // overwriting start or startRadius before the second reassignment. 893 end = start + endOffset; 894 start = start + startOffset; 895 endRadius = startRadius + radiusDiff * stops.back().position; 896 startRadius = startRadius + radiusDiff * stops.front().position; 897 898 for (auto& stop : stops) { 899 stop.position = (stop.position - stopsStartOffset) * scaleFactor; 900 } 901 } 902 903 // For negative radii, interpolation is needed to prepare parameters suitable 904 // for invoking the shader. Implementation below as resolution discussed in 905 // https://github.com/googlefonts/colr-gradients-spec/issues/367. 906 // Truncate to manually interpolated color for tile mode clamp, otherwise 907 // calculate positive projected circles. 908 if (startRadius < 0 || endRadius < 0) { 909 if (startRadius == endRadius && startRadius < 0) { 910 //skPaint.setColor(SK_ColorTRANSPARENT); 911 return true; 912 } 913 914 if (tileMode == SkTileMode::kClamp) { 915 SkVector startToEnd = end - start; 916 SkScalar radiusDiff = endRadius - startRadius; 917 SkScalar zeroRadiusStop = 0.f; 918 TruncateStops truncateSide = TruncateStart; 919 if (startRadius < 0) { 920 truncateSide = TruncateStart; 921 922 // Compute color stop position where radius is = 0. After the scaling 923 // of stop positions to the normal 0,1 range that we have done above, 924 // the size of the radius as a function of the color stops is: r(x) = r0 925 // + x*(r1-r0) Solving this function for r(x) = 0, we get: x = -r0 / 926 // (r1-r0) 927 zeroRadiusStop = -startRadius / (endRadius - startRadius); 928 startRadius = 0.f; 929 SkVector startEndDiff = end - start; 930 startEndDiff.scale(zeroRadiusStop); 931 start = start + startEndDiff; 932 } 933 934 if (endRadius < 0) { 935 truncateSide = TruncateEnd; 936 zeroRadiusStop = -startRadius / (endRadius - startRadius); 937 endRadius = 0.f; 938 SkVector startEndDiff = end - start; 939 startEndDiff.scale(1 - zeroRadiusStop); 940 end = end - startEndDiff; 941 } 942 943 if (!(startRadius == 0 && endRadius == 0)) { 944 truncateToStopInterpolating(zeroRadiusStop, stops, truncateSide); 945 } else { 946 // If both radii have become negative and where clamped to 0, we need to 947 // produce a single color cone, otherwise the shader colors the whole 948 // plane in a single color when two radii are specified as 0. 949 if (radiusDiff > 0) { 950 end = start + startToEnd; 951 endRadius = radiusDiff; 952 stops.erase(stops.begin(), stops.end() - 1); 953 } else { 954 start -= startToEnd; 955 startRadius = -radiusDiff; 956 stops.erase(stops.begin() + 1, stops.end()); 957 } 958 } 959 } else { 960 if (startRadius < 0 || endRadius < 0) { 961 auto roundIntegerMultiple = [](SkScalar factorZeroCrossing, 962 SkTileMode tileMode) { 963 int roundedMultiple = factorZeroCrossing > 0 964 ? ceilf(factorZeroCrossing) 965 : floorf(factorZeroCrossing) - 1; 966 if (tileMode == SkTileMode::kMirror && roundedMultiple % 2 != 0) { 967 roundedMultiple += roundedMultiple < 0 ? -1 : 1; 968 } 969 return roundedMultiple; 970 }; 971 972 SkVector startToEnd = end - start; 973 SkScalar radiusDiff = endRadius - startRadius; 974 SkScalar factorZeroCrossing = (startRadius / (startRadius - endRadius)); 975 bool inRange = 0.f <= factorZeroCrossing && factorZeroCrossing <= 1.0f; 976 SkScalar direction = inRange && radiusDiff < 0 ? -1.0f : 1.0f; 977 SkScalar circleProjectionFactor = 978 roundIntegerMultiple(factorZeroCrossing * direction, tileMode); 979 startToEnd.scale(circleProjectionFactor); 980 startRadius += circleProjectionFactor * radiusDiff; 981 endRadius += circleProjectionFactor * radiusDiff; 982 start += startToEnd; 983 end += startToEnd; 984 } 985 } 986 } 987 988 std::unique_ptr<SkColor4f[]> skColors(new SkColor4f[stops.size()]); 989 std::unique_ptr<SkScalar[]> skStops(new SkScalar[stops.size()]); 990 for (size_t i = 0; i < stops.size(); ++i) { 991 skColors[i] = sk_color_from(stops[i].color); 992 skStops[i] = stops[i].position; 993 } 994 995 // An opaque color is needed to ensure the gradient is not modulated by alpha. 996 skPaint.setColor(SK_ColorBLACK); 997 skPaint.setShader(SkGradientShader::MakeTwoPointConical( 998 start, startRadius, end, endRadius, 999 skColors.get(), SkColorSpace::MakeSRGB(), skStops.get(), stops.size(), 1000 tileMode, 1001 SkGradientShader::Interpolation{ 1002 SkGradientShader::Interpolation::InPremul::kNo, 1003 SkGradientShader::Interpolation::ColorSpace::kSRGB, 1004 SkGradientShader::Interpolation::HueMethod::kShorter 1005 }, 1006 nullptr)); 1007 canvas.drawPaint(skPaint); 1008 return true; 1009 } 1010 1011 case DWRITE_PAINT_TYPE_SWEEP_GRADIENT: { 1012 auto const& sweepGradient = element.paint.sweepGradient; 1013 // A sweep gradient paint element has no children. 1014 // centerX, centerY, startAngle, endAngle, extendMode, gradientStopCount, [colorStops] 1015 1016 if (sweepGradient.gradientStopCount == 0) { 1017 return true; 1018 } 1019 std::vector<D2D1_GRADIENT_STOP> stops; 1020 stops.resize(sweepGradient.gradientStopCount); 1021 1022 // If success stops will be ordered. 1023 HRBM(reader.GetGradientStops(0, stops.size(), stops.data()), 1024 "Could not get sweep gradient stops"); 1025 SkPaint skPaint; 1026 if (stops.size() == 1) { 1027 skPaint.setColor4f(sk_color_from(stops[0].color)); 1028 canvas.drawPaint(skPaint); 1029 return true; 1030 } 1031 1032 SkPoint center = SkPoint::Make(sweepGradient.centerX, sweepGradient.centerY); 1033 1034 SkScalar startAngle = sweepGradient.startAngle; 1035 SkScalar endAngle = sweepGradient.endAngle; 1036 // OpenType 1.9.1 adds a shift to the angle to ease specification of a 0 to 360 1037 // degree sweep. This appears to already be applied by DW. 1038 //startAngle += 180.0f; 1039 //endAngle += 180.0f; 1040 1041 // An opaque color is needed to ensure the gradient is not modulated by alpha. 1042 skPaint.setColor(SK_ColorBLACK); 1043 1044 // New (Var)SweepGradient implementation compliant with OpenType 1.9.1 from here. 1045 1046 // The shader expects stops from 0 to 1, so we need to account for 1047 // minimum and maximum stop positions being different from 0 and 1048 // 1. We do that by scaling minimum and maximum stop positions to 1049 // the 0 to 1 interval and scaling the angles inverse proportionally. 1050 1051 // 1) Scale angles to their equivalent positions if stops were from 0 to 1. 1052 1053 SkScalar sectorAngle = endAngle - startAngle; 1054 SkTileMode tileMode = sk_tile_mode_from(SkTo<D2D1_EXTEND_MODE>(sweepGradient.extendMode)); 1055 if (sectorAngle == 0 && tileMode != SkTileMode::kClamp) { 1056 // "If the ColorLine's extend mode is reflect or repeat and start and end angle 1057 // are equal, nothing is drawn.". 1058 //skPaint.setColor(SK_ColorTRANSPARENT); 1059 return true; 1060 } 1061 1062 SkScalar startAngleScaled = startAngle + sectorAngle * stops.front().position; 1063 SkScalar endAngleScaled = startAngle + sectorAngle * stops.back().position; 1064 1065 // 2) Scale stops accordingly to 0 to 1 range. 1066 1067 float colorStopRange = stops.back().position - stops.front().position; 1068 if (colorStopRange == 0.f) { 1069 if (tileMode != SkTileMode::kClamp) { 1070 //skPaint.setColor(SK_ColorTRANSPARENT); 1071 return true; 1072 } else { 1073 // Insert duplicated fake color stop in pad case at +1.0f to feed the shader correct 1074 // values and enable painting a pad sweep gradient with two colors. Adding this stop 1075 // will paint the equivalent gradient, because: All font specified color stops are 1076 // in the same spot, mode is pad, so everything before this spot is painted with the 1077 // first color, everything after this spot is painted with the last color. Not 1078 // adding this stop will skip the projection and result in specifying non-normalized 1079 // color stops to the shader. 1080 stops.push_back({ stops.back().position + 1.0f, stops.back().color }); 1081 colorStopRange = 1.0f; 1082 } 1083 } 1084 1085 SkScalar scaleFactor = 1 / colorStopRange; 1086 SkScalar startOffset = stops.front().position; 1087 1088 for (D2D1_GRADIENT_STOP& stop : stops) { 1089 stop.position = (stop.position - startOffset) * scaleFactor; 1090 } 1091 1092 /* https://docs.microsoft.com/en-us/typography/opentype/spec/colr#sweep-gradients 1093 * "The angles are expressed in counter-clockwise degrees from 1094 * the direction of the positive x-axis on the design 1095 * grid. [...] The color line progresses from the start angle 1096 * to the end angle in the counter-clockwise direction;" - 1097 * Convert angles and stops from counter-clockwise to clockwise 1098 * for the shader if the gradient is not already reversed due to 1099 * start angle being larger than end angle. */ 1100 startAngleScaled = 360.f - startAngleScaled; 1101 endAngleScaled = 360.f - endAngleScaled; 1102 if (startAngleScaled >= endAngleScaled) { 1103 std::swap(startAngleScaled, endAngleScaled); 1104 std::reverse(stops.begin(), stops.end()); 1105 for (auto& stop : stops) { 1106 stop.position = 1.0f - stop.position; 1107 } 1108 } 1109 1110 std::unique_ptr<SkColor4f[]> skColors(new SkColor4f[stops.size()]); 1111 std::unique_ptr<SkScalar[]> skStops(new SkScalar[stops.size()]); 1112 for (size_t i = 0; i < stops.size(); ++i) { 1113 skColors[i] = sk_color_from(stops[i].color); 1114 skStops[i] = stops[i].position; 1115 } 1116 1117 skPaint.setShader(SkGradientShader::MakeSweep( 1118 center.x(), center.y(), 1119 skColors.get(), SkColorSpace::MakeSRGB(), skStops.get(), stops.size(), 1120 tileMode, 1121 startAngleScaled, endAngleScaled, 1122 SkGradientShader::Interpolation{ 1123 SkGradientShader::Interpolation::InPremul::kNo, 1124 SkGradientShader::Interpolation::ColorSpace::kSRGB, 1125 SkGradientShader::Interpolation::HueMethod::kShorter 1126 }, 1127 nullptr)); 1128 canvas.drawPaint(skPaint); 1129 return true; 1130 } 1131 1132 case DWRITE_PAINT_TYPE_GLYPH: { 1133 // A glyph paint element has one child, which is the fill for the glyph shape glyphIndex. 1134 SkPathBuilder builder; 1135 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath; 1136 HRBM(SkDWriteGeometrySink::Create(&builder, &geometryToPath), 1137 "Could not create geometry to path converter."); 1138 UINT16 glyphId = SkTo<UINT16>(element.paint.glyph.glyphIndex); 1139 { 1140 Exclusive l(maybe_dw_mutex(*this->getDWriteTypeface())); 1141 HRBM(this->getDWriteTypeface()->fDWriteFontFace->GetGlyphRunOutline( 1142 SkScalarToFloat(fTextSizeRender), 1143 &glyphId, 1144 nullptr, //advances 1145 nullptr, //offsets 1146 1, //num glyphs 1147 FALSE, //sideways 1148 FALSE, //rtl 1149 geometryToPath.get()), 1150 "Could not create glyph outline."); 1151 } 1152 1153 builder.transform(SkMatrix::Scale(1.0f / fTextSizeRender, 1.0f / fTextSizeRender)); 1154 canvas.clipPath(builder.detach(), fRenderingMode != DWRITE_RENDERING_MODE_ALIASED); 1155 1156 drawChildren(1); 1157 return true; 1158 } 1159 1160 case DWRITE_PAINT_TYPE_COLOR_GLYPH: { 1161 auto const& colorGlyph = element.paint.colorGlyph; 1162 // A color glyph paint element has one child, the root of the paint tree for glyphIndex. 1163 // glyphIndex, clipBox 1164 if (D2D_RECT_F_is_empty(colorGlyph.clipBox)) { 1165 // Does not have a clip box 1166 } else { 1167 SkRect r = sk_rect_from(colorGlyph.clipBox); 1168 canvas.clipRect(r, fRenderingMode != DWRITE_RENDERING_MODE_ALIASED); 1169 } 1170 1171 drawChildren(1); 1172 return true; 1173 } 1174 1175 case DWRITE_PAINT_TYPE_TRANSFORM: { 1176 // A transform paint element always has one child, the transformed content. 1177 canvas.concat(sk_matrix_from(element.paint.transform)); 1178 drawChildren(1); 1179 return true; 1180 } 1181 1182 case DWRITE_PAINT_TYPE_COMPOSITE: { 1183 // A composite paint element has two children, the source and destination of the operation. 1184 1185 SkPaint blendModePaint; 1186 blendModePaint.setBlendMode(sk_blend_mode_from(element.paint.composite.mode)); 1187 1188 SkAutoCanvasRestore acr(&canvas, false); 1189 1190 // Need to visit the second child first and do savelayers, so manually handle children. 1191 DWRITE_PAINT_ELEMENT sourceElement; 1192 DWRITE_PAINT_ELEMENT backdropElement; 1193 1194 HRBM(reader.MoveToFirstChild(&sourceElement), "Could not move to child."); 1195 HRBM(reader.MoveToNextSibling(&backdropElement), "Could not move to sibiling."); 1196 canvas.saveLayer(nullptr, nullptr); 1197 this->drawColorV1Paint(canvas, reader, backdropElement); 1198 1199 HRBM(reader.MoveToParent(), "Could not move to parent."); 1200 HRBM(reader.MoveToFirstChild(&sourceElement), "Could not move to child."); 1201 canvas.saveLayer(nullptr, &blendModePaint); 1202 this->drawColorV1Paint(canvas, reader, sourceElement); 1203 1204 HRBM(reader.MoveToParent(), "Could not move to parent."); 1205 1206 return true; 1207 } 1208 1209 default: 1210 return false; 1211 } 1212 } 1213 1214 bool SkScalerContext_DW::drawColorV1Image(const SkGlyph& glyph, SkCanvas& canvas) { 1215 DWriteFontTypeface* typeface = this->getDWriteTypeface(); 1216 IDWriteFontFace7* fontFace = typeface->fDWriteFontFace7/*.get()*/; 1217 if (!fontFace) { 1218 return false; 1219 } 1220 UINT32 glyphIndex = glyph.getGlyphID(); 1221 1222 SkTScopedComPtr<IDWritePaintReader> paintReader; 1223 HRBM(fontFace->CreatePaintReader(DWRITE_GLYPH_IMAGE_FORMATS_COLR_PAINT_TREE, 1224 DWRITE_PAINT_FEATURE_LEVEL_COLR_V1, 1225 &paintReader), 1226 "Could not create paint reader."); 1227 1228 DWRITE_PAINT_ELEMENT paintElement; 1229 D2D_RECT_F clipBox; 1230 DWRITE_PAINT_ATTRIBUTES attributes; 1231 HRBM(paintReader->SetCurrentGlyph(glyphIndex, &paintElement, &clipBox, &attributes), 1232 "Could not set current glyph."); 1233 1234 if (paintElement.paintType == DWRITE_PAINT_TYPE_NONE) { 1235 // Does not have paint layers, try another format. 1236 return false; 1237 } 1238 1239 // All coordinates (including top level clip) are reported in "em"s (1 == em). 1240 // Size up all em units to the current size and transform. 1241 // Get glyph paths at render size, divide out the render size to get em units. 1242 1243 SkMatrix matrix = fSkXform; 1244 SkScalar scale = fTextSizeRender; 1245 matrix.preScale(scale, scale); 1246 if (this->isSubpixel()) { 1247 matrix.postTranslate(SkFixedToScalar(glyph.getSubXFixed()), 1248 SkFixedToScalar(glyph.getSubYFixed())); 1249 } 1250 canvas.concat(matrix); 1251 1252 if (D2D_RECT_F_is_empty(clipBox)) { 1253 // Does not have a clip box 1254 } else { 1255 canvas.clipRect(sk_rect_from(clipBox)); 1256 } 1257 1258 // The DirectWrite interface returns resolved colors if these are provided. 1259 // Indexes and alphas are reported but there is no reason to duplicate the color calculation. 1260 paintReader->SetTextColor(dw_color_from(SkColor4f::FromColor(fRec.fForegroundColor))); 1261 paintReader->SetCustomColorPalette(typeface->fDWPalette.get(), typeface->fPaletteEntryCount); 1262 1263 return this->drawColorV1Paint(canvas, *paintReader, paintElement); 1264 } 1265 1266 bool SkScalerContext_DW::generateColorV1Image(const SkGlyph& glyph, void* imageBuffer) { 1267 SkASSERT(glyph.maskFormat() == SkMask::Format::kARGB32_Format); 1268 1269 SkBitmap dstBitmap; 1270 // TODO: mark this as sRGB when the blits will be sRGB. 1271 dstBitmap.setInfo(SkImageInfo::Make(glyph.width(), glyph.height(), 1272 kN32_SkColorType, kPremul_SkAlphaType), 1273 glyph.rowBytes()); 1274 dstBitmap.setPixels(imageBuffer); 1275 1276 SkCanvas canvas(dstBitmap); 1277 if constexpr (kSkShowTextBlitCoverage) { 1278 canvas.clear(0x33FF0000); 1279 } else { 1280 canvas.clear(SK_ColorTRANSPARENT); 1281 } 1282 canvas.translate(-SkIntToScalar(glyph.left()), -SkIntToScalar(glyph.top())); 1283 1284 return this->drawColorV1Image(glyph, canvas); 1285 } 1286 1287 bool SkScalerContext_DW::generateColorV1PaintBounds( 1288 SkMatrix* ctm, SkRect* bounds, 1289 IDWritePaintReader& reader, DWRITE_PAINT_ELEMENT const & element) 1290 { 1291 // Helper to iterate over the specified number of children. 1292 auto boundChildren = [&](UINT32 childCount) -> bool { 1293 if (childCount == 0) { 1294 return true; 1295 } 1296 DWRITE_PAINT_ELEMENT childElement; 1297 HRB(reader.MoveToFirstChild(&childElement)); 1298 this->generateColorV1PaintBounds(ctm, bounds, reader, childElement); 1299 1300 for (uint32_t i = 1; i < childCount; ++i) { 1301 HRB(reader.MoveToNextSibling(&childElement)); 1302 this->generateColorV1PaintBounds(ctm, bounds, reader, childElement); 1303 } 1304 1305 HRB(reader.MoveToParent()); 1306 return true; 1307 }; 1308 1309 SkMatrix restoreMatrix = *ctm; 1310 SK_AT_SCOPE_EXIT(*ctm = restoreMatrix); 1311 1312 switch (element.paintType) { 1313 case DWRITE_PAINT_TYPE_NONE: 1314 return false; 1315 1316 case DWRITE_PAINT_TYPE_LAYERS: { 1317 // A layers paint element has a variable number of children. 1318 return boundChildren(element.paint.layers.childCount); 1319 } 1320 1321 case DWRITE_PAINT_TYPE_SOLID_GLYPH: { 1322 // A solid glyph paint element has no children. 1323 // glyphIndex, color.value, color.paletteEntryIndex, color.alpha, color.colorAttributes 1324 1325 SkPathBuilder builder; 1326 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath; 1327 HRBM(SkDWriteGeometrySink::Create(&builder, &geometryToPath), 1328 "Could not create geometry to path converter."); 1329 UINT16 glyphId = SkTo<UINT16>(element.paint.solidGlyph.glyphIndex); 1330 { 1331 Exclusive l(maybe_dw_mutex(*this->getDWriteTypeface())); 1332 HRBM(this->getDWriteTypeface()->fDWriteFontFace->GetGlyphRunOutline( 1333 SkScalarToFloat(fTextSizeRender), 1334 &glyphId, 1335 nullptr, //advances 1336 nullptr, //offsets 1337 1, //num glyphs 1338 FALSE, //sideways 1339 FALSE, //rtl 1340 geometryToPath.get()), 1341 "Could not create glyph outline."); 1342 } 1343 1344 SkMatrix t = *ctm; 1345 t.preConcat(SkMatrix::Scale(1.0f / fTextSizeRender, 1.0f / fTextSizeRender)); 1346 builder.transform(t); 1347 bounds->join(builder.detach().getBounds()); 1348 return true; 1349 } 1350 1351 case DWRITE_PAINT_TYPE_SOLID: { 1352 return true; 1353 } 1354 1355 case DWRITE_PAINT_TYPE_LINEAR_GRADIENT: { 1356 return true; 1357 } 1358 1359 case DWRITE_PAINT_TYPE_RADIAL_GRADIENT: { 1360 return true; 1361 } 1362 1363 case DWRITE_PAINT_TYPE_SWEEP_GRADIENT: { 1364 return true; 1365 } 1366 1367 case DWRITE_PAINT_TYPE_GLYPH: { 1368 // A glyph paint element has one child, which is the fill for the glyph shape glyphIndex. 1369 SkPathBuilder builder; 1370 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath; 1371 HRBM(SkDWriteGeometrySink::Create(&builder, &geometryToPath), 1372 "Could not create geometry to path converter."); 1373 UINT16 glyphId = SkTo<UINT16>(element.paint.glyph.glyphIndex); 1374 { 1375 Exclusive l(maybe_dw_mutex(*this->getDWriteTypeface())); 1376 HRBM(this->getDWriteTypeface()->fDWriteFontFace->GetGlyphRunOutline( 1377 SkScalarToFloat(fTextSizeRender), 1378 &glyphId, 1379 nullptr, //advances 1380 nullptr, //offsets 1381 1, //num glyphs 1382 FALSE, //sideways 1383 FALSE, //rtl 1384 geometryToPath.get()), 1385 "Could not create glyph outline."); 1386 } 1387 1388 SkMatrix t = *ctm; 1389 t.preConcat(SkMatrix::Scale(1.0f / fTextSizeRender, 1.0f / fTextSizeRender)); 1390 builder.transform(t); 1391 bounds->join(builder.detach().getBounds()); 1392 return true; 1393 } 1394 1395 case DWRITE_PAINT_TYPE_COLOR_GLYPH: { 1396 // A color glyph paint element has one child, which is the root 1397 // of the paint tree for the glyph specified by glyphIndex. 1398 auto const& colorGlyph = element.paint.colorGlyph; 1399 if (D2D_RECT_F_is_empty(colorGlyph.clipBox)) { 1400 // Does not have a clip box 1401 return boundChildren(1); 1402 } 1403 SkRect r = sk_rect_from(colorGlyph.clipBox); 1404 ctm->mapRect(r); 1405 bounds->join(r); 1406 return true; 1407 } 1408 1409 case DWRITE_PAINT_TYPE_TRANSFORM: { 1410 // A transform paint element always has one child, which is the transformed content. 1411 ctm->preConcat(sk_matrix_from(element.paint.transform)); 1412 return boundChildren(1); 1413 } 1414 1415 case DWRITE_PAINT_TYPE_COMPOSITE: { 1416 // A composite paint element has two children, the source and destination of the operation. 1417 return boundChildren(2); 1418 } 1419 1420 default: 1421 return false; 1422 } 1423 } 1424 1425 bool SkScalerContext_DW::generateColorV1Metrics(const SkGlyph& glyph, SkRect* bounds) { 1426 DWriteFontTypeface* typeface = this->getDWriteTypeface(); 1427 IDWriteFontFace7* fontFace = typeface->fDWriteFontFace7/*.get()*/; 1428 if (!fontFace) { 1429 return false; 1430 } 1431 UINT32 glyphIndex = glyph.getGlyphID(); 1432 1433 SkTScopedComPtr<IDWritePaintReader> paintReader; 1434 HRESULT hr; 1435 // No message on failure here, since this will fail if the font has no color glyphs. 1436 hr = fontFace->CreatePaintReader(DWRITE_GLYPH_IMAGE_FORMATS_COLR_PAINT_TREE, 1437 DWRITE_PAINT_FEATURE_LEVEL_COLR_V1, 1438 &paintReader); 1439 if (FAILED(hr)) { 1440 return false; 1441 } 1442 1443 DWRITE_PAINT_ELEMENT paintElement; 1444 D2D_RECT_F clipBox; 1445 DWRITE_PAINT_ATTRIBUTES attributes; 1446 // If the glyph is not color this will succeed but return paintType NONE. 1447 HRBM(paintReader->SetCurrentGlyph(glyphIndex, &paintElement, &clipBox, &attributes), 1448 "Could not set the current glyph."); 1449 1450 if (paintElement.paintType == DWRITE_PAINT_TYPE_NONE) { 1451 // Does not have paint layers, try another format. 1452 return false; 1453 } 1454 1455 // All coordinates (including top level clip) are reported in "em"s (1 == em). 1456 // Size up all em units to the current size and transform. 1457 1458 SkMatrix matrix = fSkXform; 1459 SkScalar scale = fTextSizeRender; 1460 matrix.preScale(scale, scale); 1461 if (this->isSubpixel()) { 1462 matrix.postTranslate(SkFixedToScalar(glyph.getSubXFixed()), 1463 SkFixedToScalar(glyph.getSubYFixed())); 1464 } 1465 1466 SkRect r; 1467 if (D2D_RECT_F_is_empty(clipBox)) { 1468 // Does not have a clip box. 1469 r = SkRect::MakeEmpty(); 1470 if (!this->generateColorV1PaintBounds(&matrix, &r, *paintReader, paintElement)) { 1471 return false; 1472 } 1473 *bounds = r; 1474 } else { 1475 *bounds = sk_rect_from(clipBox); 1476 matrix.mapRect(bounds); 1477 } 1478 return true; 1479 } 1480 1481 #else // !SK_DISABLE_DIRECTWRITE_COLRv1 && (DWRITE_CORE || (defined(NTDDI_WIN11_ZN) && NTDDI_VERSION >= NTDDI_WIN11_ZN)) 1482 1483 bool SkScalerContext_DW::generateColorV1Metrics(const SkGlyph&, SkRect*) { return false; } 1484 bool SkScalerContext_DW::generateColorV1Image(const SkGlyph&, void*) { return false; } 1485 bool SkScalerContext_DW::drawColorV1Image(const SkGlyph&, SkCanvas&) { return false; } 1486 1487 #endif // !SK_DISABLE_DIRECTWRITE_COLRv1 && (DWRITE_CORE || (defined(NTDDI_WIN11_ZN) && NTDDI_VERSION >= NTDDI_WIN11_ZN)) 1488 1489 bool SkScalerContext_DW::setAdvance(const SkGlyph& glyph, SkVector* advance) { 1490 *advance = {0, 0}; 1491 UINT16 glyphId = glyph.getGlyphID(); 1492 DWriteFontTypeface* typeface = this->getDWriteTypeface(); 1493 1494 // DirectWrite treats all out of bounds glyph ids as having the same data as glyph 0. 1495 // For consistency with all other backends, treat out of range glyph ids as an error. 1496 if (fGlyphCount <= glyphId) { 1497 return false; 1498 } 1499 1500 DWRITE_GLYPH_METRICS gm; 1501 1502 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode || 1503 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode) 1504 { 1505 Exclusive l(maybe_dw_mutex(*typeface)); 1506 HRBM(typeface->fDWriteFontFace->GetGdiCompatibleGlyphMetrics( 1507 fTextSizeMeasure, 1508 1.0f, // pixelsPerDip 1509 // This parameter does not act like the lpmat2 parameter to GetGlyphOutlineW. 1510 // If it did then GsA here and G_inv below to mapVectors. 1511 nullptr, 1512 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode, 1513 &glyphId, 1, 1514 &gm), 1515 "Could not get gdi compatible glyph metrics."); 1516 } else { 1517 Exclusive l(maybe_dw_mutex(*typeface)); 1518 HRBM(typeface->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm), 1519 "Could not get design metrics."); 1520 } 1521 1522 DWRITE_FONT_METRICS dwfm; 1523 { 1524 Shared l(maybe_dw_mutex(*typeface)); 1525 typeface->fDWriteFontFace->GetMetrics(&dwfm); 1526 } 1527 SkScalar advanceX = fTextSizeMeasure * gm.advanceWidth / dwfm.designUnitsPerEm; 1528 1529 *advance = { advanceX, 0 }; 1530 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode || 1531 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode) 1532 { 1533 // DirectWrite produced 'compatible' metrics, but while close, 1534 // the end result is not always an integer as it would be with GDI. 1535 advance->fX = SkScalarRoundToScalar(advance->fX); 1536 } 1537 *advance = fSkXform.mapVector(*advance); 1538 return true; 1539 } 1540 1541 bool SkScalerContext_DW::generateDWMetrics(const SkGlyph& glyph, 1542 DWRITE_RENDERING_MODE renderingMode, 1543 DWRITE_TEXTURE_TYPE textureType, 1544 SkRect* bounds) 1545 { 1546 DWriteFontTypeface* typeface = this->getDWriteTypeface(); 1547 1548 //Measure raster size. 1549 fXform.dx = SkFixedToFloat(glyph.getSubXFixed()); 1550 fXform.dy = SkFixedToFloat(glyph.getSubYFixed()); 1551 1552 FLOAT advance = 0; 1553 1554 UINT16 glyphId = glyph.getGlyphID(); 1555 1556 DWRITE_GLYPH_OFFSET offset; 1557 offset.advanceOffset = 0.0f; 1558 offset.ascenderOffset = 0.0f; 1559 1560 DWRITE_GLYPH_RUN run; 1561 run.glyphCount = 1; 1562 run.glyphAdvances = &advance; 1563 run.fontFace = typeface->fDWriteFontFace.get(); 1564 run.fontEmSize = SkScalarToFloat(fTextSizeRender); 1565 run.bidiLevel = 0; 1566 run.glyphIndices = &glyphId; 1567 run.isSideways = FALSE; 1568 run.glyphOffsets = &offset; 1569 1570 SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis; 1571 { 1572 Exclusive l(maybe_dw_mutex(*typeface)); 1573 // IDWriteFactory2::CreateGlyphRunAnalysis is very bad at aliased glyphs. 1574 if (typeface->fFactory2 && 1575 (fGridFitMode == DWRITE_GRID_FIT_MODE_DISABLED || 1576 fAntiAliasMode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)) 1577 { 1578 HRBM(typeface->fFactory2->CreateGlyphRunAnalysis( 1579 &run, 1580 &fXform, 1581 renderingMode, 1582 fMeasuringMode, 1583 fGridFitMode, 1584 fAntiAliasMode, 1585 0.0f, // baselineOriginX, 1586 0.0f, // baselineOriginY, 1587 &glyphRunAnalysis), 1588 "Could not create DW2 glyph run analysis."); 1589 } else { 1590 HRBM(typeface->fFactory->CreateGlyphRunAnalysis(&run, 1591 1.0f, // pixelsPerDip, 1592 &fXform, 1593 renderingMode, 1594 fMeasuringMode, 1595 0.0f, // baselineOriginX, 1596 0.0f, // baselineOriginY, 1597 &glyphRunAnalysis), 1598 "Could not create glyph run analysis."); 1599 } 1600 } 1601 RECT bbox; 1602 { 1603 Shared l(maybe_dw_mutex(*typeface)); 1604 HRBM(glyphRunAnalysis->GetAlphaTextureBounds(textureType, &bbox), 1605 "Could not get texture bounds."); 1606 } 1607 1608 // GetAlphaTextureBounds succeeds but sometimes returns empty bounds like 1609 // { 0x80000000, 0x80000000, 0x80000000, 0x80000000 } 1610 // for small but not quite zero and large (but not really large) glyphs, 1611 // Only set as non-empty if the returned bounds are non-empty. 1612 if (bbox.left >= bbox.right || bbox.top >= bbox.bottom) { 1613 return false; 1614 } 1615 1616 *bounds = SkRect::MakeLTRB(bbox.left, bbox.top, bbox.right, bbox.bottom); 1617 return true; 1618 } 1619 1620 bool SkScalerContext_DW::getColorGlyphRun(const SkGlyph& glyph, 1621 IDWriteColorGlyphRunEnumerator** colorGlyph) 1622 { 1623 FLOAT advance = 0; 1624 UINT16 glyphId = glyph.getGlyphID(); 1625 1626 DWRITE_GLYPH_OFFSET offset; 1627 offset.advanceOffset = 0.0f; 1628 offset.ascenderOffset = 0.0f; 1629 1630 DWRITE_GLYPH_RUN run; 1631 run.glyphCount = 1; 1632 run.glyphAdvances = &advance; 1633 run.fontFace = this->getDWriteTypeface()->fDWriteFontFace.get(); 1634 run.fontEmSize = SkScalarToFloat(fTextSizeRender); 1635 run.bidiLevel = 0; 1636 run.glyphIndices = &glyphId; 1637 run.isSideways = FALSE; 1638 run.glyphOffsets = &offset; 1639 1640 HRESULT hr = this->getDWriteTypeface()->fFactory2->TranslateColorGlyphRun( 1641 0, 0, &run, nullptr, fMeasuringMode, &fXform, 0, colorGlyph); 1642 if (hr == DWRITE_E_NOCOLOR) { 1643 return false; 1644 } 1645 HRBM(hr, "Failed to translate color glyph run"); 1646 return true; 1647 } 1648 1649 bool SkScalerContext_DW::generateColorMetrics(const SkGlyph& glyph, SkRect* bounds) { 1650 SkTScopedComPtr<IDWriteColorGlyphRunEnumerator> colorLayers; 1651 if (!getColorGlyphRun(glyph, &colorLayers)) { 1652 return false; 1653 } 1654 SkASSERT(colorLayers.get()); 1655 1656 *bounds = SkRect::MakeEmpty(); 1657 BOOL hasNextRun = FALSE; 1658 while (SUCCEEDED(colorLayers->MoveNext(&hasNextRun)) && hasNextRun) { 1659 const DWRITE_COLOR_GLYPH_RUN* colorGlyph; 1660 HRBM(colorLayers->GetCurrentRun(&colorGlyph), "Could not get current color glyph run"); 1661 1662 SkPathBuilder builder; 1663 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath; 1664 HRBM(SkDWriteGeometrySink::Create(&builder, &geometryToPath), 1665 "Could not create geometry to path converter."); 1666 { 1667 Exclusive l(maybe_dw_mutex(*this->getDWriteTypeface())); 1668 HRBM(colorGlyph->glyphRun.fontFace->GetGlyphRunOutline( 1669 colorGlyph->glyphRun.fontEmSize, 1670 colorGlyph->glyphRun.glyphIndices, 1671 colorGlyph->glyphRun.glyphAdvances, 1672 colorGlyph->glyphRun.glyphOffsets, 1673 colorGlyph->glyphRun.glyphCount, 1674 colorGlyph->glyphRun.isSideways, 1675 colorGlyph->glyphRun.bidiLevel % 2, //rtl 1676 geometryToPath.get()), 1677 "Could not create glyph outline."); 1678 } 1679 bounds->join(builder.detach().getBounds()); 1680 } 1681 SkMatrix matrix = fSkXform; 1682 if (this->isSubpixel()) { 1683 matrix.postTranslate(SkFixedToScalar(glyph.getSubXFixed()), 1684 SkFixedToScalar(glyph.getSubYFixed())); 1685 } 1686 matrix.mapRect(bounds); 1687 return true; 1688 } 1689 1690 #ifdef USE_SVG 1691 bool SkScalerContext_DW::generateSVGMetrics(const SkGlyph& glyph, SkRect* bounds) { 1692 SkPictureRecorder recorder; 1693 SkRect infiniteRect = SkRect::MakeLTRB(-SK_ScalarInfinity, -SK_ScalarInfinity, 1694 SK_ScalarInfinity, SK_ScalarInfinity); 1695 sk_sp<SkBBoxHierarchy> bboxh = SkRTreeFactory()(); 1696 SkCanvas* recordingCanvas = recorder.beginRecording(infiniteRect, bboxh); 1697 if (!this->drawSVGImage(glyph, *recordingCanvas)) { 1698 return false; 1699 } 1700 sk_sp<SkPicture> pic = recorder.finishRecordingAsPicture(); 1701 *bounds = pic->cullRect(); 1702 SkASSERT(bounds->isFinite()); 1703 bounds->roundOut(bounds); 1704 return true; 1705 } 1706 #endif 1707 1708 #ifdef USE_PNG 1709 namespace { 1710 struct Context { 1711 SkTScopedComPtr<IDWriteFontFace4> fontFace4; 1712 void* glyphDataContext; 1713 Context(IDWriteFontFace4* face4, void* context) 1714 : fontFace4(SkRefComPtr(face4)) 1715 , glyphDataContext(context) 1716 {} 1717 }; 1718 1719 static void ReleaseProc(const void* ptr, void* context) { 1720 Context* ctx = (Context*)context; 1721 ctx->fontFace4->ReleaseGlyphImageData(ctx->glyphDataContext); 1722 delete ctx; 1723 } 1724 } 1725 1726 bool SkScalerContext_DW::generatePngMetrics(const SkGlyph& glyph, SkRect* bounds) { 1727 IDWriteFontFace4* fontFace4 = this->getDWriteTypeface()->fDWriteFontFace4.get(); 1728 if (!fontFace4) { 1729 return false; 1730 } 1731 1732 DWRITE_GLYPH_IMAGE_FORMATS imageFormats; 1733 HRBM(fontFace4->GetGlyphImageFormats(glyph.getGlyphID(), 0, UINT32_MAX, &imageFormats), 1734 "Cannot get glyph image formats."); 1735 if (!(imageFormats & DWRITE_GLYPH_IMAGE_FORMATS_PNG)) { 1736 return false; 1737 } 1738 1739 DWRITE_GLYPH_IMAGE_DATA glyphData; 1740 void* glyphDataContext; 1741 HRBM(fontFace4->GetGlyphImageData(glyph.getGlyphID(), 1742 fTextSizeRender, 1743 DWRITE_GLYPH_IMAGE_FORMATS_PNG, 1744 &glyphData, 1745 &glyphDataContext), 1746 "Glyph image data could not be acquired."); 1747 1748 Context* context = new Context(fontFace4, glyphDataContext); 1749 sk_sp<SkData> data = SkData::MakeWithProc(glyphData.imageData, 1750 glyphData.imageDataSize, 1751 &ReleaseProc, 1752 context); 1753 1754 std::unique_ptr<SkCodec> codec = SkPngDecoder::Decode(std::move(data), nullptr); 1755 if (!codec) { 1756 return false; 1757 } 1758 1759 SkImageInfo info = codec->getInfo(); 1760 *bounds = SkRect::Make(info.bounds()); 1761 1762 SkMatrix matrix = fSkXform; 1763 SkScalar scale = fTextSizeRender / glyphData.pixelsPerEm; 1764 matrix.preScale(scale, scale); 1765 matrix.preTranslate(-glyphData.horizontalLeftOrigin.x, -glyphData.horizontalLeftOrigin.y); 1766 if (this->isSubpixel()) { 1767 matrix.postTranslate(SkFixedToScalar(glyph.getSubXFixed()), 1768 SkFixedToScalar(glyph.getSubYFixed())); 1769 } 1770 matrix.mapRect(bounds); 1771 bounds->roundOut(bounds); 1772 return true; 1773 } 1774 #endif 1775 1776 SkScalerContext::GlyphMetrics SkScalerContext_DW::generateMetrics(const SkGlyph& glyph, 1777 SkArenaAlloc* alloc) { 1778 GlyphMetrics mx(glyph.maskFormat()); 1779 1780 mx.extraBits = ScalerContextBits::NONE; 1781 1782 if (!this->setAdvance(glyph, &mx.advance)) { 1783 return mx; 1784 } 1785 1786 DWriteFontTypeface* typeface = this->getDWriteTypeface(); 1787 if (typeface->fIsColorFont) { 1788 if (generateColorV1Metrics(glyph, &mx.bounds)) { 1789 mx.maskFormat = SkMask::kARGB32_Format; 1790 mx.extraBits |= ScalerContextBits::COLRv1; 1791 mx.neverRequestPath = true; 1792 return mx; 1793 } 1794 1795 if (generateColorMetrics(glyph, &mx.bounds)) { 1796 mx.maskFormat = SkMask::kARGB32_Format; 1797 mx.extraBits |= ScalerContextBits::COLR; 1798 mx.neverRequestPath = true; 1799 return mx; 1800 } 1801 1802 #ifdef USE_SVG 1803 if (generateSVGMetrics(glyph, &mx.bounds)) { 1804 mx.maskFormat = SkMask::kARGB32_Format; 1805 mx.extraBits |= ScalerContextBits::SVG; 1806 mx.neverRequestPath = true; 1807 return mx; 1808 } 1809 #endif 1810 1811 #ifdef USE_PNG 1812 if (generatePngMetrics(glyph, &mx.bounds)) { 1813 mx.maskFormat = SkMask::kARGB32_Format; 1814 mx.extraBits |= ScalerContextBits::PNG; 1815 mx.neverRequestPath = true; 1816 return mx; 1817 } 1818 #endif 1819 } 1820 1821 if (this->generateDWMetrics(glyph, fRenderingMode, fTextureType, &mx.bounds)) { 1822 mx.extraBits = ScalerContextBits::DW; 1823 return mx; 1824 } 1825 1826 // GetAlphaTextureBounds succeeds but returns an empty RECT if there are no 1827 // glyphs of the specified texture type or it is too big for smoothing. 1828 // When this happens, try with the alternate texture type. 1829 if (DWRITE_TEXTURE_ALIASED_1x1 != fTextureType || 1830 DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE == fAntiAliasMode) 1831 { 1832 if (this->generateDWMetrics(glyph, 1833 DWRITE_RENDERING_MODE_ALIASED, 1834 DWRITE_TEXTURE_ALIASED_1x1, 1835 &mx.bounds)) 1836 { 1837 mx.maskFormat = SkMask::kBW_Format; 1838 mx.extraBits = ScalerContextBits::DW_1; 1839 return mx; 1840 } 1841 } 1842 // TODO: Try DWRITE_TEXTURE_CLEARTYPE_3x1 if DWRITE_TEXTURE_ALIASED_1x1 fails 1843 1844 // GetAlphaTextureBounds can fail for various reasons. 1845 // As a fallback, attempt to generate the metrics and image from the path. 1846 mx.computeFromPath = true; 1847 mx.extraBits = ScalerContextBits::PATH; 1848 return mx; 1849 } 1850 1851 void SkScalerContext_DW::generateFontMetrics(SkFontMetrics* metrics) { 1852 if (nullptr == metrics) { 1853 return; 1854 } 1855 1856 sk_bzero(metrics, sizeof(*metrics)); 1857 1858 DWRITE_FONT_METRICS dwfm; 1859 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode || 1860 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode) 1861 { 1862 this->getDWriteTypeface()->fDWriteFontFace->GetGdiCompatibleMetrics( 1863 fTextSizeRender, 1864 1.0f, // pixelsPerDip 1865 &fXform, 1866 &dwfm); 1867 } else { 1868 this->getDWriteTypeface()->fDWriteFontFace->GetMetrics(&dwfm); 1869 } 1870 1871 SkScalar upem = SkIntToScalar(dwfm.designUnitsPerEm); 1872 1873 metrics->fAscent = -fTextSizeRender * SkIntToScalar(dwfm.ascent) / upem; 1874 metrics->fDescent = fTextSizeRender * SkIntToScalar(dwfm.descent) / upem; 1875 metrics->fLeading = fTextSizeRender * SkIntToScalar(dwfm.lineGap) / upem; 1876 metrics->fXHeight = fTextSizeRender * SkIntToScalar(dwfm.xHeight) / upem; 1877 metrics->fCapHeight = fTextSizeRender * SkIntToScalar(dwfm.capHeight) / upem; 1878 metrics->fUnderlineThickness = fTextSizeRender * SkIntToScalar(dwfm.underlineThickness) / upem; 1879 metrics->fUnderlinePosition = -(fTextSizeRender * SkIntToScalar(dwfm.underlinePosition) / upem); 1880 metrics->fStrikeoutThickness = fTextSizeRender * SkIntToScalar(dwfm.strikethroughThickness) / upem; 1881 metrics->fStrikeoutPosition = -(fTextSizeRender * SkIntToScalar(dwfm.strikethroughPosition) / upem); 1882 1883 metrics->fFlags |= SkFontMetrics::kUnderlineThicknessIsValid_Flag; 1884 metrics->fFlags |= SkFontMetrics::kUnderlinePositionIsValid_Flag; 1885 metrics->fFlags |= SkFontMetrics::kStrikeoutThicknessIsValid_Flag; 1886 metrics->fFlags |= SkFontMetrics::kStrikeoutPositionIsValid_Flag; 1887 1888 SkTScopedComPtr<IDWriteFontFace5> fontFace5; 1889 if (SUCCEEDED(this->getDWriteTypeface()->fDWriteFontFace->QueryInterface(&fontFace5))) { 1890 if (fontFace5->HasVariations()) { 1891 // The bounds are only valid for the default variation. 1892 metrics->fFlags |= SkFontMetrics::kBoundsInvalid_Flag; 1893 } 1894 } 1895 1896 if (this->getDWriteTypeface()->fDWriteFontFace1.get()) { 1897 DWRITE_FONT_METRICS1 dwfm1; 1898 this->getDWriteTypeface()->fDWriteFontFace1->GetMetrics(&dwfm1); 1899 metrics->fTop = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxTop) / upem; 1900 metrics->fBottom = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxBottom) / upem; 1901 metrics->fXMin = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxLeft) / upem; 1902 metrics->fXMax = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxRight) / upem; 1903 1904 metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin; 1905 return; 1906 } 1907 1908 AutoTDWriteTable<SkOTTableHead> head(this->getDWriteTypeface()->fDWriteFontFace.get()); 1909 if (head.fExists && 1910 head.fSize >= sizeof(SkOTTableHead) && 1911 head->version == SkOTTableHead::version1) 1912 { 1913 metrics->fTop = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMax) / upem; 1914 metrics->fBottom = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMin) / upem; 1915 metrics->fXMin = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMin) / upem; 1916 metrics->fXMax = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMax) / upem; 1917 1918 metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin; 1919 return; 1920 } 1921 1922 // The real bounds weren't actually available. 1923 metrics->fFlags |= SkFontMetrics::kBoundsInvalid_Flag; 1924 metrics->fTop = metrics->fAscent; 1925 metrics->fBottom = metrics->fDescent; 1926 } 1927 1928 /////////////////////////////////////////////////////////////////////////////// 1929 1930 #include "src/core/SkColorData.h" 1931 1932 void SkScalerContext_DW::BilevelToBW(const uint8_t* SK_RESTRICT src, 1933 const SkGlyph& glyph, void* imageBuffer) { 1934 const int width = glyph.width(); 1935 const size_t dstRB = (width + 7) >> 3; 1936 uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(imageBuffer); 1937 1938 int byteCount = width >> 3; 1939 int bitCount = width & 7; 1940 1941 for (int y = 0; y < glyph.height(); ++y) { 1942 if (byteCount > 0) { 1943 for (int i = 0; i < byteCount; ++i) { 1944 unsigned byte = 0; 1945 byte |= src[0] & (1 << 7); 1946 byte |= src[1] & (1 << 6); 1947 byte |= src[2] & (1 << 5); 1948 byte |= src[3] & (1 << 4); 1949 byte |= src[4] & (1 << 3); 1950 byte |= src[5] & (1 << 2); 1951 byte |= src[6] & (1 << 1); 1952 byte |= src[7] & (1 << 0); 1953 dst[i] = byte; 1954 src += 8; 1955 } 1956 } 1957 if (bitCount > 0) { 1958 unsigned byte = 0; 1959 unsigned mask = 0x80; 1960 for (int i = 0; i < bitCount; i++) { 1961 byte |= (src[i]) & mask; 1962 mask >>= 1; 1963 } 1964 dst[byteCount] = byte; 1965 } 1966 src += bitCount; 1967 dst += dstRB; 1968 } 1969 1970 if constexpr (kSkShowTextBlitCoverage) { 1971 dst = static_cast<uint8_t*>(imageBuffer); 1972 for (unsigned y = 0; y < (unsigned)glyph.height(); y += 2) { 1973 for (unsigned x = (y & 0x2); x < (unsigned)glyph.width(); x+=4) { 1974 uint8_t& b = dst[(dstRB * y) + (x >> 3)]; 1975 b = b ^ (1 << (0x7 - (x & 0x7))); 1976 } 1977 } 1978 } 1979 } 1980 1981 template<bool APPLY_PREBLEND> 1982 void SkScalerContext_DW::GrayscaleToA8(const uint8_t* SK_RESTRICT src, 1983 const SkGlyph& glyph, void* imageBuffer, 1984 const uint8_t* table8) { 1985 const size_t dstRB = glyph.rowBytes(); 1986 const int width = glyph.width(); 1987 uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(imageBuffer); 1988 1989 for (int y = 0; y < glyph.height(); y++) { 1990 for (int i = 0; i < width; i++) { 1991 U8CPU a = *(src++); 1992 dst[i] = sk_apply_lut_if<APPLY_PREBLEND>(a, table8); 1993 if constexpr (kSkShowTextBlitCoverage) { 1994 dst[i] = std::max<U8CPU>(0x30, dst[i]); 1995 } 1996 } 1997 dst = SkTAddOffset<uint8_t>(dst, dstRB); 1998 } 1999 } 2000 2001 template<bool APPLY_PREBLEND> 2002 void SkScalerContext_DW::RGBToA8(const uint8_t* SK_RESTRICT src, 2003 const SkGlyph& glyph, void* imageBuffer, 2004 const uint8_t* table8) { 2005 const size_t dstRB = glyph.rowBytes(); 2006 const int width = glyph.width(); 2007 uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(imageBuffer); 2008 2009 for (int y = 0; y < glyph.height(); y++) { 2010 for (int i = 0; i < width; i++) { 2011 // Ignore the R, B channels. It looks the closest to what 2012 // D2D with grayscale AA has. But there's no way 2013 // to just get a grayscale AA alpha texture from a glyph run. 2014 U8CPU g = src[1]; 2015 src += 3; 2016 2017 dst[i] = sk_apply_lut_if<APPLY_PREBLEND>(g, table8); 2018 if constexpr (kSkShowTextBlitCoverage) { 2019 dst[i] = std::max<U8CPU>(0x30, dst[i]); 2020 } 2021 } 2022 dst = SkTAddOffset<uint8_t>(dst, dstRB); 2023 } 2024 } 2025 2026 template<bool APPLY_PREBLEND, bool RGB> 2027 void SkScalerContext_DW::RGBToLcd16(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, 2028 void* imageBuffer, 2029 const uint8_t* tableR, const uint8_t* tableG, 2030 const uint8_t* tableB, int clearTypeLevel) { 2031 const size_t dstRB = glyph.rowBytes(); 2032 const int width = glyph.width(); 2033 uint16_t* SK_RESTRICT dst = static_cast<uint16_t*>(imageBuffer); 2034 2035 for (int y = 0; y < glyph.height(); y++) { 2036 for (int i = 0; i < width; i++) { 2037 int r, g, b; 2038 if (RGB) { 2039 r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR); 2040 g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG); 2041 b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB); 2042 } else { 2043 b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB); 2044 g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG); 2045 r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR); 2046 } 2047 if constexpr (kSkShowTextBlitCoverage) { 2048 r = std::max<U8CPU>(0x30, r); 2049 g = std::max<U8CPU>(0x30, g); 2050 b = std::max<U8CPU>(0x30, b); 2051 } 2052 r = g + (((r - g) * clearTypeLevel) >> 8); 2053 b = g + (((b - g) * clearTypeLevel) >> 8); 2054 dst[i] = SkPack888ToRGB16(r, g, b); 2055 } 2056 dst = SkTAddOffset<uint16_t>(dst, dstRB); 2057 } 2058 } 2059 2060 const void* SkScalerContext_DW::getDWMaskBits(const SkGlyph& glyph, 2061 DWRITE_RENDERING_MODE renderingMode, 2062 DWRITE_TEXTURE_TYPE textureType) 2063 { 2064 DWriteFontTypeface* typeface = this->getDWriteTypeface(); 2065 2066 int sizeNeeded = glyph.width() * glyph.height(); 2067 if (DWRITE_TEXTURE_CLEARTYPE_3x1 == textureType) { 2068 sizeNeeded *= 3; 2069 } 2070 if (sizeNeeded > fBits.size()) { 2071 fBits.resize(sizeNeeded); 2072 } 2073 2074 // erase 2075 memset(fBits.begin(), 0, sizeNeeded); 2076 2077 fXform.dx = SkFixedToFloat(glyph.getSubXFixed()); 2078 fXform.dy = SkFixedToFloat(glyph.getSubYFixed()); 2079 2080 FLOAT advance = 0.0f; 2081 2082 UINT16 index = glyph.getGlyphID(); 2083 2084 DWRITE_GLYPH_OFFSET offset; 2085 offset.advanceOffset = 0.0f; 2086 offset.ascenderOffset = 0.0f; 2087 2088 DWRITE_GLYPH_RUN run; 2089 run.glyphCount = 1; 2090 run.glyphAdvances = &advance; 2091 run.fontFace = typeface->fDWriteFontFace.get(); 2092 run.fontEmSize = SkScalarToFloat(fTextSizeRender); 2093 run.bidiLevel = 0; 2094 run.glyphIndices = &index; 2095 run.isSideways = FALSE; 2096 run.glyphOffsets = &offset; 2097 { 2098 SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis; 2099 { 2100 Exclusive l(maybe_dw_mutex(*typeface)); 2101 // IDWriteFactory2::CreateGlyphRunAnalysis is very bad at aliased glyphs. 2102 if (typeface->fFactory2 && 2103 (fGridFitMode == DWRITE_GRID_FIT_MODE_DISABLED || 2104 fAntiAliasMode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)) 2105 { 2106 HRNM(typeface->fFactory2->CreateGlyphRunAnalysis(&run, 2107 &fXform, 2108 renderingMode, 2109 fMeasuringMode, 2110 fGridFitMode, 2111 fAntiAliasMode, 2112 0.0f, // baselineOriginX, 2113 0.0f, // baselineOriginY, 2114 &glyphRunAnalysis), 2115 "Could not create DW2 glyph run analysis."); 2116 } else { 2117 HRNM(typeface->fFactory->CreateGlyphRunAnalysis(&run, 2118 1.0f, // pixelsPerDip, 2119 &fXform, 2120 renderingMode, 2121 fMeasuringMode, 2122 0.0f, // baselineOriginX, 2123 0.0f, // baselineOriginY, 2124 &glyphRunAnalysis), 2125 "Could not create glyph run analysis."); 2126 } 2127 } 2128 //NOTE: this assumes that the glyph has already been measured 2129 //with an exact same glyph run analysis. 2130 RECT bbox; 2131 bbox.left = glyph.left(); 2132 bbox.top = glyph.top(); 2133 bbox.right = glyph.left() + glyph.width(); 2134 bbox.bottom = glyph.top() + glyph.height(); 2135 { 2136 Shared l(maybe_dw_mutex(*typeface)); 2137 HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType, 2138 &bbox, 2139 fBits.begin(), 2140 sizeNeeded), 2141 "Could not draw mask."); 2142 } 2143 } 2144 return fBits.begin(); 2145 } 2146 2147 bool SkScalerContext_DW::generateDWImage(const SkGlyph& glyph, void* imageBuffer) { 2148 //Create the mask. 2149 ScalerContextBits::value_type format = glyph.extraBits(); 2150 DWRITE_RENDERING_MODE renderingMode = fRenderingMode; 2151 DWRITE_TEXTURE_TYPE textureType = fTextureType; 2152 if (format == ScalerContextBits::DW_1) { 2153 renderingMode = DWRITE_RENDERING_MODE_ALIASED; 2154 textureType = DWRITE_TEXTURE_ALIASED_1x1; 2155 } 2156 const void* bits = this->getDWMaskBits(glyph, renderingMode, textureType); 2157 if (!bits) { 2158 sk_bzero(imageBuffer, glyph.imageSize()); 2159 return false; 2160 } 2161 2162 //Copy the mask into the glyph. 2163 const uint8_t* src = (const uint8_t*)bits; 2164 if (DWRITE_RENDERING_MODE_ALIASED == renderingMode) { 2165 SkASSERT(SkMask::kBW_Format == glyph.maskFormat()); 2166 SkASSERT(DWRITE_TEXTURE_ALIASED_1x1 == textureType); 2167 BilevelToBW(src, glyph, imageBuffer); 2168 } else if (!isLCD(fRec)) { 2169 if (textureType == DWRITE_TEXTURE_ALIASED_1x1) { 2170 if (fPreBlend.isApplicable()) { 2171 GrayscaleToA8<true>(src, glyph, imageBuffer, fPreBlend.fG); 2172 } else { 2173 GrayscaleToA8<false>(src, glyph, imageBuffer, fPreBlend.fG); 2174 } 2175 } else { 2176 if (fPreBlend.isApplicable()) { 2177 RGBToA8<true>(src, glyph, imageBuffer, fPreBlend.fG); 2178 } else { 2179 RGBToA8<false>(src, glyph, imageBuffer, fPreBlend.fG); 2180 } 2181 } 2182 } else { 2183 SkASSERT(SkMask::kLCD16_Format == glyph.maskFormat()); 2184 if (fPreBlend.isApplicable()) { 2185 if (fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag) { 2186 RGBToLcd16<true, false>(src, glyph, imageBuffer, 2187 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB, fClearTypeLevel); 2188 } else { 2189 RGBToLcd16<true, true>(src, glyph, imageBuffer, 2190 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB, fClearTypeLevel); 2191 } 2192 } else { 2193 if (fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag) { 2194 RGBToLcd16<false, false>(src, glyph, imageBuffer, 2195 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB, fClearTypeLevel); 2196 } else { 2197 RGBToLcd16<false, true>(src, glyph, imageBuffer, 2198 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB, fClearTypeLevel); 2199 } 2200 } 2201 } 2202 return true; 2203 } 2204 2205 bool SkScalerContext_DW::drawColorImage(const SkGlyph& glyph, SkCanvas& canvas) { 2206 SkTScopedComPtr<IDWriteColorGlyphRunEnumerator> colorLayers; 2207 if (!getColorGlyphRun(glyph, &colorLayers)) { 2208 SkASSERTF(false, "Could not get color layers"); 2209 return false; 2210 } 2211 2212 SkPaint paint; 2213 paint.setAntiAlias(fRenderingMode != DWRITE_RENDERING_MODE_ALIASED); 2214 2215 if (this->isSubpixel()) { 2216 canvas.translate(SkFixedToScalar(glyph.getSubXFixed()), 2217 SkFixedToScalar(glyph.getSubYFixed())); 2218 } 2219 canvas.concat(fSkXform); 2220 2221 DWriteFontTypeface* typeface = this->getDWriteTypeface(); 2222 size_t paletteEntryCount = typeface->fPaletteEntryCount; 2223 SkColor* palette = typeface->fPalette.get(); 2224 BOOL hasNextRun = FALSE; 2225 while (SUCCEEDED(colorLayers->MoveNext(&hasNextRun)) && hasNextRun) { 2226 const DWRITE_COLOR_GLYPH_RUN* colorGlyph; 2227 HRBM(colorLayers->GetCurrentRun(&colorGlyph), "Could not get current color glyph run"); 2228 2229 SkColor color; 2230 if (colorGlyph->paletteIndex == 0xffff) { 2231 color = fRec.fForegroundColor; 2232 } else if (colorGlyph->paletteIndex < paletteEntryCount) { 2233 color = palette[colorGlyph->paletteIndex]; 2234 } else { 2235 SK_TRACEHR(DWRITE_E_NOCOLOR, "Invalid palette index."); 2236 color = SK_ColorBLACK; 2237 } 2238 paint.setColor(color); 2239 2240 SkPathBuilder builder; 2241 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath; 2242 HRBM(SkDWriteGeometrySink::Create(&builder, &geometryToPath), 2243 "Could not create geometry to path converter."); 2244 { 2245 Exclusive l(maybe_dw_mutex(*this->getDWriteTypeface())); 2246 HRBM(colorGlyph->glyphRun.fontFace->GetGlyphRunOutline( 2247 colorGlyph->glyphRun.fontEmSize, 2248 colorGlyph->glyphRun.glyphIndices, 2249 colorGlyph->glyphRun.glyphAdvances, 2250 colorGlyph->glyphRun.glyphOffsets, 2251 colorGlyph->glyphRun.glyphCount, 2252 colorGlyph->glyphRun.isSideways, 2253 colorGlyph->glyphRun.bidiLevel % 2, //rtl 2254 geometryToPath.get()), 2255 "Could not create glyph outline."); 2256 } 2257 canvas.drawPath(builder.detach(), paint); 2258 } 2259 return true; 2260 } 2261 2262 bool SkScalerContext_DW::generateColorImage(const SkGlyph& glyph, void* imageBuffer) { 2263 SkASSERT(glyph.maskFormat() == SkMask::Format::kARGB32_Format); 2264 2265 SkBitmap dstBitmap; 2266 // TODO: mark this as sRGB when the blits will be sRGB. 2267 dstBitmap.setInfo(SkImageInfo::Make(glyph.width(), glyph.height(), 2268 kN32_SkColorType, kPremul_SkAlphaType), 2269 glyph.rowBytes()); 2270 dstBitmap.setPixels(imageBuffer); 2271 2272 SkCanvas canvas(dstBitmap); 2273 if constexpr (kSkShowTextBlitCoverage) { 2274 canvas.clear(0x33FF0000); 2275 } else { 2276 canvas.clear(SK_ColorTRANSPARENT); 2277 } 2278 canvas.translate(-SkIntToScalar(glyph.left()), -SkIntToScalar(glyph.top())); 2279 2280 return this->drawColorImage(glyph, canvas); 2281 } 2282 2283 bool SkScalerContext_DW::drawSVGImage(const SkGlyph& glyph, SkCanvas& canvas) { 2284 DWriteFontTypeface* typeface = this->getDWriteTypeface(); 2285 IDWriteFontFace4* fontFace4 = typeface->fDWriteFontFace4.get(); 2286 if (!fontFace4) { 2287 return false; 2288 } 2289 2290 DWRITE_GLYPH_IMAGE_FORMATS imageFormats; 2291 HRBM(fontFace4->GetGlyphImageFormats(glyph.getGlyphID(), 0, UINT32_MAX, &imageFormats), 2292 "Cannot get glyph image formats."); 2293 if (!(imageFormats & DWRITE_GLYPH_IMAGE_FORMATS_SVG)) { 2294 return false; 2295 } 2296 2297 SkGraphics::OpenTypeSVGDecoderFactory svgFactory = SkGraphics::GetOpenTypeSVGDecoderFactory(); 2298 if (!svgFactory) { 2299 return false; 2300 } 2301 2302 DWRITE_GLYPH_IMAGE_DATA glyphData; 2303 void* glyphDataContext; 2304 HRBM(fontFace4->GetGlyphImageData(glyph.getGlyphID(), 2305 fTextSizeRender, 2306 DWRITE_GLYPH_IMAGE_FORMATS_SVG, 2307 &glyphData, 2308 &glyphDataContext), 2309 "Glyph SVG data could not be acquired."); 2310 auto svgDecoder = svgFactory((const uint8_t*)glyphData.imageData, glyphData.imageDataSize); 2311 fontFace4->ReleaseGlyphImageData(glyphDataContext); 2312 if (!svgDecoder) { 2313 return false; 2314 } 2315 2316 size_t paletteEntryCount = typeface->fPaletteEntryCount; 2317 SkColor* palette = typeface->fPalette.get(); 2318 int upem = typeface->getUnitsPerEm(); 2319 2320 SkMatrix matrix = fSkXform; 2321 SkScalar scale = fTextSizeRender / upem; 2322 matrix.preScale(scale, scale); 2323 matrix.preTranslate(-glyphData.horizontalLeftOrigin.x, -glyphData.horizontalLeftOrigin.y); 2324 if (this->isSubpixel()) { 2325 matrix.postTranslate(SkFixedToScalar(glyph.getSubXFixed()), 2326 SkFixedToScalar(glyph.getSubYFixed())); 2327 } 2328 canvas.concat(matrix); 2329 2330 return svgDecoder->render(canvas, upem, glyph.getGlyphID(), 2331 fRec.fForegroundColor, SkSpan(palette, paletteEntryCount)); 2332 } 2333 2334 bool SkScalerContext_DW::generateSVGImage(const SkGlyph& glyph, void* imageBuffer) { 2335 SkASSERT(glyph.maskFormat() == SkMask::Format::kARGB32_Format); 2336 2337 SkBitmap dstBitmap; 2338 // TODO: mark this as sRGB when the blits will be sRGB. 2339 dstBitmap.setInfo(SkImageInfo::Make(glyph.width(), glyph.height(), 2340 kN32_SkColorType, kPremul_SkAlphaType), 2341 glyph.rowBytes()); 2342 dstBitmap.setPixels(imageBuffer); 2343 2344 SkCanvas canvas(dstBitmap); 2345 if constexpr (kSkShowTextBlitCoverage) { 2346 canvas.clear(0x33FF0000); 2347 } else { 2348 canvas.clear(SK_ColorTRANSPARENT); 2349 } 2350 canvas.translate(-SkIntToScalar(glyph.left()), -SkIntToScalar(glyph.top())); 2351 2352 return this->drawSVGImage(glyph, canvas); 2353 } 2354 2355 #ifdef USE_PNG 2356 bool SkScalerContext_DW::drawPngImage(const SkGlyph& glyph, SkCanvas& canvas) { 2357 IDWriteFontFace4* fontFace4 = this->getDWriteTypeface()->fDWriteFontFace4.get(); 2358 if (!fontFace4) { 2359 return false; 2360 } 2361 2362 DWRITE_GLYPH_IMAGE_DATA glyphData; 2363 void* glyphDataContext; 2364 HRBM(fontFace4->GetGlyphImageData(glyph.getGlyphID(), 2365 fTextSizeRender, 2366 DWRITE_GLYPH_IMAGE_FORMATS_PNG, 2367 &glyphData, 2368 &glyphDataContext), 2369 "Glyph image data could not be acquired."); 2370 Context* context = new Context(fontFace4, glyphDataContext); 2371 sk_sp<SkData> data = SkData::MakeWithProc(glyphData.imageData, 2372 glyphData.imageDataSize, 2373 &ReleaseProc, 2374 context); 2375 sk_sp<SkImage> image = SkImages::DeferredFromEncodedData(std::move(data)); 2376 if (!image) { 2377 return false; 2378 } 2379 2380 if (this->isSubpixel()) { 2381 canvas.translate(SkFixedToScalar(glyph.getSubXFixed()), 2382 SkFixedToScalar(glyph.getSubYFixed())); 2383 } 2384 canvas.concat(fSkXform); 2385 SkScalar ratio = fTextSizeRender / glyphData.pixelsPerEm; 2386 canvas.scale(ratio, ratio); 2387 canvas.translate(-glyphData.horizontalLeftOrigin.x, -glyphData.horizontalLeftOrigin.y); 2388 canvas.drawImage(image, 0, 0); 2389 return true; 2390 } 2391 2392 bool SkScalerContext_DW::generatePngImage(const SkGlyph& glyph, void* imageBuffer) { 2393 SkASSERT(glyph.maskFormat() == SkMask::Format::kARGB32_Format); 2394 2395 SkBitmap dstBitmap; 2396 dstBitmap.setInfo(SkImageInfo::Make(glyph.width(), glyph.height(), 2397 kN32_SkColorType, kPremul_SkAlphaType), 2398 glyph.rowBytes()); 2399 dstBitmap.setPixels(imageBuffer); 2400 2401 SkCanvas canvas(dstBitmap); 2402 canvas.clear(SK_ColorTRANSPARENT); 2403 canvas.translate(-glyph.left(), -glyph.top()); 2404 2405 return this->drawPngImage(glyph, canvas); 2406 } 2407 #endif 2408 2409 void SkScalerContext_DW::generateImage(const SkGlyph& glyph, void* imageBuffer) { 2410 ScalerContextBits::value_type format = glyph.extraBits(); 2411 if (format == ScalerContextBits::DW || 2412 format == ScalerContextBits::DW_1) 2413 { 2414 this->generateDWImage(glyph, imageBuffer); 2415 } else if (format == ScalerContextBits::COLRv1) { 2416 this->generateColorV1Image(glyph, imageBuffer); 2417 } else if (format == ScalerContextBits::COLR) { 2418 this->generateColorImage(glyph, imageBuffer); 2419 #ifdef USE_SVG 2420 } else if (format == ScalerContextBits::SVG) { 2421 this->generateSVGImage(glyph, imageBuffer); 2422 #endif 2423 #ifdef USE_PNG 2424 } else if (format == ScalerContextBits::PNG) { 2425 this->generatePngImage(glyph, imageBuffer); 2426 #endif 2427 } else if (format == ScalerContextBits::PATH) { 2428 this->generateImageFromPath(glyph, imageBuffer); 2429 } else { 2430 SK_ABORT("Bad format"); 2431 } 2432 } 2433 2434 std::optional<SkScalerContext::GeneratedPath> 2435 SkScalerContext_DW::generatePath(const SkGlyph& glyph) { 2436 SkGlyphID glyphID = glyph.getGlyphID(); 2437 2438 // DirectWrite treats all out of bounds glyph ids as having the same data as glyph 0. 2439 // For consistency with all other backends, treat out of range glyph ids as an error. 2440 if (fGlyphCount <= glyphID) { 2441 return {}; 2442 } 2443 2444 SkPathBuilder builder; 2445 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath; 2446 HR_GENERAL(SkDWriteGeometrySink::Create(&builder, &geometryToPath), 2447 "Could not create geometry to path converter.", {}); 2448 UINT16 glyphId = SkTo<UINT16>(glyphID); 2449 { 2450 Exclusive l(maybe_dw_mutex(*this->getDWriteTypeface())); 2451 //TODO: convert to<->from DIUs? This would make a difference if hinting. 2452 //It may not be needed, it appears that DirectWrite only hints at em size. 2453 HR_GENERAL(this->getDWriteTypeface()->fDWriteFontFace->GetGlyphRunOutline( 2454 SkScalarToFloat(fTextSizeRender), 2455 &glyphId, 2456 nullptr, //advances 2457 nullptr, //offsets 2458 1, //num glyphs 2459 FALSE, //sideways 2460 FALSE, //rtl 2461 geometryToPath.get()), 2462 "Could not create glyph outline.", {}); 2463 } 2464 2465 builder.transform(fSkXform); 2466 return {{builder.detach(), false}}; 2467 } 2468 2469 sk_sp<SkDrawable> SkScalerContext_DW::generateDrawable(const SkGlyph& glyph) { 2470 struct GlyphDrawable : public SkDrawable { 2471 SkScalerContext_DW* fSelf; 2472 SkGlyph fGlyph; 2473 GlyphDrawable(SkScalerContext_DW* self, const SkGlyph& glyph) : fSelf(self), fGlyph(glyph){} 2474 SkRect onGetBounds() override { return fGlyph.rect(); } 2475 size_t onApproximateBytesUsed() override { return sizeof(GlyphDrawable); } 2476 void maybeShowTextBlitCoverage(SkCanvas* canvas) { 2477 if constexpr (kSkShowTextBlitCoverage) { 2478 SkPaint paint; 2479 paint.setColor(0x3300FF00); 2480 paint.setStyle(SkPaint::kFill_Style); 2481 canvas->drawRect(this->onGetBounds(), paint); 2482 } 2483 } 2484 }; 2485 struct COLRv1GlyphDrawable : public GlyphDrawable { 2486 using GlyphDrawable::GlyphDrawable; 2487 void onDraw(SkCanvas* canvas) override { 2488 this->maybeShowTextBlitCoverage(canvas); 2489 fSelf->drawColorV1Image(fGlyph, *canvas); 2490 } 2491 }; 2492 struct COLRGlyphDrawable : public GlyphDrawable { 2493 using GlyphDrawable::GlyphDrawable; 2494 void onDraw(SkCanvas* canvas) override { 2495 this->maybeShowTextBlitCoverage(canvas); 2496 fSelf->drawColorImage(fGlyph, *canvas); 2497 } 2498 }; 2499 struct SVGGlyphDrawable : public GlyphDrawable { 2500 using GlyphDrawable::GlyphDrawable; 2501 void onDraw(SkCanvas* canvas) override { 2502 this->maybeShowTextBlitCoverage(canvas); 2503 fSelf->drawSVGImage(fGlyph, *canvas); 2504 } 2505 }; 2506 ScalerContextBits::value_type format = glyph.extraBits(); 2507 if (format == ScalerContextBits::COLRv1) { 2508 return sk_sp<SkDrawable>(new COLRv1GlyphDrawable(this, glyph)); 2509 } 2510 if (format == ScalerContextBits::COLR) { 2511 return sk_sp<SkDrawable>(new COLRGlyphDrawable(this, glyph)); 2512 } 2513 if (format == ScalerContextBits::SVG) { 2514 return sk_sp<SkDrawable>(new SVGGlyphDrawable(this, glyph)); 2515 } 2516 return nullptr; 2517 } 2518 2519 #endif//defined(SK_BUILD_FOR_WIN)