10#if defined(SK_BUILD_FOR_WIN)
54static inline const constexpr bool kSkShowTextBlitCoverage =
false;
62 static SkSharedMutex mutex;
68 explicit Exclusive(SkSharedMutex* maybe_lock)
SK_ACQUIRE(*maybe_lock)
88 fLock->acquireShared();
97 fLock->releaseShared();
102 SkSharedMutex* fLock;
110 Exclusive l(maybe_dw_mutex(*typeface));
121 return (0 != maxp->version.tt.maxSizeOfInstructions);
150 if (numRanges > 1024 ||
158 SkTAfter<const SkOTTableGridAndScanProcedure::GaspRange>(gasp.get());
160 for (uint16_t
i = 0;
i < numRanges; ++
i, ++rangeTable) {
162 if (minPPEM <
size &&
size <= maxPPEM) {
163 range->fMin = minPPEM + 1;
164 range->fMax = maxPPEM;
166 range->fFlags = rangeTable->
flags;
176static bool is_gridfit_only(GaspRange::Behavior
flags) {
177 return flags.raw.value == GaspRange::Behavior::Raw::GridfitMask;
181 Exclusive l(maybe_dw_mutex(*typeface));
195 if (numSizes > 1024 ||
203 SkTAfter<const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable>(eblc.get());
204 for (uint32_t
i = 0;
i < numSizes; ++
i, ++sizeTable) {
206 range.fMin <= sizeTable->
ppemX && sizeTable->
ppemX <= range.fMax)
234 if (numSizes > 1024 ||
242 SkTAfter<const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable>(ebsc.get());
243 for (uint32_t
i = 0;
i < numSizes; ++
i, ++scaleTable) {
245 range.fMin <= scaleTable->
ppemX && scaleTable->
ppemX <= range.fMax) {
256 return 0 ==
a && 0 ==
b;
308 if (gdiTextSize == 0) {
313 bool treatLikeBitmap =
false;
314 bool axisAlignedBitmap =
false;
315 if (bitmapRequested) {
319 GaspRange range(bitmapPPEM, bitmapPPEM, 0, GaspRange::Behavior());
320 if (get_gasp_range(typeface, bitmapPPEM, &range)) {
321 if (!is_gridfit_only(range.fFlags)) {
322 range = GaspRange(bitmapPPEM, bitmapPPEM, 0, GaspRange::Behavior());
325 treatLikeBitmap = has_bitmap_strike(typeface, range);
327 axisAlignedBitmap = is_axis_aligned(fRec);
330 GaspRange range(0, 0xFFFF, 0, GaspRange::Behavior());
334 fTextSizeRender = gdiTextSize;
335 fRenderingMode = DWRITE_RENDERING_MODE_ALIASED;
336 fTextureType = DWRITE_TEXTURE_ALIASED_1x1;
337 fTextSizeMeasure = gdiTextSize;
338 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
342 }
else if (treatLikeBitmap && axisAlignedBitmap) {
343 fTextSizeRender = gdiTextSize;
344 fRenderingMode = DWRITE_RENDERING_MODE_GDI_CLASSIC;
345 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
346 fTextSizeMeasure = gdiTextSize;
347 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
351 }
else if (treatLikeBitmap) {
352 fTextSizeRender = gdiTextSize;
353 fRenderingMode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
354 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
355 fTextSizeMeasure = gdiTextSize;
356 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
362 fTextSizeRender = realTextSize;
363 fRenderingMode = range.fFlags.field.SymmetricSmoothing
364 ? DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC
365 : DWRITE_RENDERING_MODE_NATURAL;
366 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
367 fTextSizeMeasure = realTextSize;
368 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
371 }
else if (realTextSize >
SkIntToScalar(20) || !is_hinted(typeface)) {
372 fTextSizeRender = realTextSize;
373 fRenderingMode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
374 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
375 fTextSizeMeasure = realTextSize;
376 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
388 fTextSizeRender = gdiTextSize;
389 fRenderingMode = DWRITE_RENDERING_MODE_NATURAL;
390 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
391 fTextSizeMeasure = realTextSize;
392 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
396 fAntiAliasMode = DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE;
402 fTextureType = DWRITE_TEXTURE_ALIASED_1x1;
403 fAntiAliasMode = DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE;
407 fGridFitMode = DWRITE_GRID_FIT_MODE_ENABLED;
409 fGridFitMode = DWRITE_GRID_FIT_MODE_DISABLED;
410 if (fRenderingMode != DWRITE_RENDERING_MODE_ALIASED) {
411 fRenderingMode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
415 if (this->isLinearMetrics()) {
416 fTextSizeMeasure = realTextSize;
417 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
421 if (fMeasuringMode != DWRITE_MEASURING_MODE_NATURAL) {
422 constexpr UINT32 CBDTTag = DWRITE_MAKE_OPENTYPE_TAG(
'C',
'B',
'D',
'T');
425 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
433#if DWRITE_CORE || (defined(NTDDI_WIN11_ZN) && NTDDI_VERSION >= NTDDI_WIN11_ZN)
445 DWRITE_COLOR_F dwColor;
446 dwColor.r =
color.fR;
447 dwColor.g =
color.fG;
448 dwColor.b =
color.fB;
449 dwColor.a =
color.fA;
457constexpr bool D2D_RECT_F_is_empty(
const D2D_RECT_F& r) {
458 return r.right <= r.left || r.bottom <= r.top;
461SkMatrix sk_matrix_from(DWRITE_MATRIX
const&
m) {
469SkTileMode sk_tile_mode_from(D2D1_EXTEND_MODE extendMode) {
470 switch (extendMode) {
471 case D2D1_EXTEND_MODE_CLAMP:
473 case D2D1_EXTEND_MODE_WRAP:
475 case D2D1_EXTEND_MODE_MIRROR:
482SkBlendMode sk_blend_mode_from(DWRITE_COLOR_COMPOSITE_MODE compositeMode) {
483 switch (compositeMode) {
484 case DWRITE_COLOR_COMPOSITE_CLEAR:
486 case DWRITE_COLOR_COMPOSITE_SRC:
488 case DWRITE_COLOR_COMPOSITE_DEST:
490 case DWRITE_COLOR_COMPOSITE_SRC_OVER:
492 case DWRITE_COLOR_COMPOSITE_DEST_OVER:
494 case DWRITE_COLOR_COMPOSITE_SRC_IN:
496 case DWRITE_COLOR_COMPOSITE_DEST_IN:
498 case DWRITE_COLOR_COMPOSITE_SRC_OUT:
500 case DWRITE_COLOR_COMPOSITE_DEST_OUT:
502 case DWRITE_COLOR_COMPOSITE_SRC_ATOP:
504 case DWRITE_COLOR_COMPOSITE_DEST_ATOP:
506 case DWRITE_COLOR_COMPOSITE_XOR:
508 case DWRITE_COLOR_COMPOSITE_PLUS:
511 case DWRITE_COLOR_COMPOSITE_SCREEN:
513 case DWRITE_COLOR_COMPOSITE_OVERLAY:
515 case DWRITE_COLOR_COMPOSITE_DARKEN:
517 case DWRITE_COLOR_COMPOSITE_LIGHTEN:
519 case DWRITE_COLOR_COMPOSITE_COLOR_DODGE:
521 case DWRITE_COLOR_COMPOSITE_COLOR_BURN:
523 case DWRITE_COLOR_COMPOSITE_HARD_LIGHT:
525 case DWRITE_COLOR_COMPOSITE_SOFT_LIGHT:
527 case DWRITE_COLOR_COMPOSITE_DIFFERENCE:
529 case DWRITE_COLOR_COMPOSITE_EXCLUSION:
531 case DWRITE_COLOR_COMPOSITE_MULTIPLY:
534 case DWRITE_COLOR_COMPOSITE_HSL_HUE:
536 case DWRITE_COLOR_COMPOSITE_HSL_SATURATION:
538 case DWRITE_COLOR_COMPOSITE_HSL_COLOR:
540 case DWRITE_COLOR_COMPOSITE_HSL_LUMINOSITY:
563D2D1_COLOR_F lerpSkColor(D2D1_COLOR_F c0, D2D1_COLOR_F c1,
float t) {
572 const auto c0_4f =
skvx::float4(c0.r, c0.g, c0.b, c0.a),
574 c_4f = c0_4f + (c1_4f - c0_4f) * t;
586void truncateToStopInterpolating(
SkScalar zeroRadiusStop,
587 std::vector<D2D1_GRADIENT_STOP>& stops,
588 TruncateStops truncateStops) {
589 if (stops.size() <= 1u ||
590 zeroRadiusStop < stops.front().position || stops.back().position < zeroRadiusStop) {
594 auto lcmp = [](D2D1_GRADIENT_STOP
const& stop,
SkScalar position) {
595 return stop.position < position;
597 auto ucmp = [](
SkScalar position, D2D1_GRADIENT_STOP
const& stop) {
598 return position < stop.position;
600 size_t afterIndex = (truncateStops == TruncateStart)
601 ? std::lower_bound(stops.begin(), stops.end(), zeroRadiusStop, lcmp) - stops.begin()
602 : std::upper_bound(stops.begin(), stops.end(), zeroRadiusStop, ucmp) - stops.begin();
604 const float t = (zeroRadiusStop - stops[afterIndex - 1].position) /
605 (stops[afterIndex].position - stops[afterIndex - 1].position);
606 D2D1_COLOR_F lerpColor = lerpSkColor(stops[afterIndex - 1].
color, stops[afterIndex].
color, t);
608 if (truncateStops == TruncateStart) {
609 stops.erase(stops.begin(), stops.begin() + afterIndex);
610 stops.insert(stops.begin(), { 0, lerpColor });
612 stops.erase(stops.begin() + afterIndex, stops.end());
613 stops.insert(stops.end(), { 1, lerpColor });
618bool SkScalerContext_DW::drawColorV1Paint(
SkCanvas& canvas,
619 IDWritePaintReader& reader,
620 DWRITE_PAINT_ELEMENT
const & element)
623 auto drawChildren = [&](uint32_t childCount) ->
bool {
624 if (childCount != 0) {
625 DWRITE_PAINT_ELEMENT childElement;
626 HRB(reader.MoveToFirstChild(&childElement));
627 this->drawColorV1Paint(canvas, reader, childElement);
629 for (uint32_t
i = 1;
i < childCount;
i++) {
630 HRB(reader.MoveToNextSibling(&childElement));
631 this->drawColorV1Paint(canvas, reader, childElement);
634 HRB(reader.MoveToParent());
640 switch (element.paintType) {
641 case DWRITE_PAINT_TYPE_NONE:
644 case DWRITE_PAINT_TYPE_LAYERS: {
646 return drawChildren(element.paint.layers.childCount);
649 case DWRITE_PAINT_TYPE_SOLID_GLYPH: {
652 auto const& solidGlyph = element.paint.solidGlyph;
655 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
657 "Could not create geometry to path converter.");
658 UINT16 glyphId = SkTo<UINT16>(solidGlyph.glyphIndex);
660 Exclusive l(maybe_dw_mutex(*this->getDWriteTypeface()));
661 HRBM(this->getDWriteTypeface()->fDWriteFontFace->GetGlyphRunOutline(
669 geometryToPath.get()),
670 "Could not create glyph outline.");
675 skPaint.
setColor4f(sk_color_from(solidGlyph.color.value));
676 skPaint.
setAntiAlias(fRenderingMode != DWRITE_RENDERING_MODE_ALIASED);
681 case DWRITE_PAINT_TYPE_SOLID: {
685 skPaint.
setColor4f(sk_color_from(element.paint.solid.value));
690 case DWRITE_PAINT_TYPE_LINEAR_GRADIENT: {
691 auto const& linearGradient = element.paint.linearGradient;
695 if (linearGradient.gradientStopCount == 0) {
698 std::vector<D2D1_GRADIENT_STOP> stops;
699 stops.resize(linearGradient.gradientStopCount);
702 HRBM(reader.GetGradientStops(0, stops.size(), stops.data()),
703 "Could not get linear gradient stops.");
705 if (stops.size() == 1) {
710 SkPoint linePositions[2] = { {linearGradient.x0, linearGradient.y0},
711 {linearGradient.x1, linearGradient.y1} };
731 SkVector perpendicularToP2P0 = (p2 - p0);
733 -perpendicularToP2P0.
x());
734 SkVector p3 = p0 + SkVectorProjection((p1 - p0), perpendicularToP2P0);
735 linePositions[1] = p3;
742 SkTileMode tileMode = sk_tile_mode_from(SkTo<D2D1_EXTEND_MODE>(linearGradient.extendMode));
743 SkScalar colorStopRange = stops.back().position - stops.front().position;
746 if (colorStopRange == 0.f) {
758 stops.push_back({ stops.back().position + 1.0f, stops.back().color });
759 colorStopRange = 1.0f;
768 if ((colorStopRange != 1 || stops.front().position != 0.f)) {
771 p0Offset.
scale(stops.front().position);
773 p1Offset.
scale(stops.back().position);
775 linePositions[0] = p0 + p0Offset;
776 linePositions[1] = p0 + p1Offset;
778 SkScalar scaleFactor = 1 / colorStopRange;
779 SkScalar startOffset = stops.front().position;
780 for (D2D1_GRADIENT_STOP& stop : stops) {
781 stop.position = (stop.position - startOffset) * scaleFactor;
785 std::unique_ptr<SkColor4f[]> skColors(
new SkColor4f[stops.size()]);
786 std::unique_ptr<SkScalar[]> skStops(
new SkScalar[stops.size()]);
787 for (
size_t i = 0;
i < stops.size(); ++
i) {
788 skColors[
i] = sk_color_from(stops[
i].
color);
789 skStops[
i] = stops[
i].position;
797 SkGradientShader::Interpolation::InPremul::kNo,
798 SkGradientShader::Interpolation::ColorSpace::kSRGB,
799 SkGradientShader::Interpolation::HueMethod::kShorter
811 case DWRITE_PAINT_TYPE_RADIAL_GRADIENT: {
812 auto const& radialGradient = element.paint.radialGradient;
817 SkScalar startRadius = radialGradient.radius0;
819 SkScalar endRadius = radialGradient.radius1;
821 if (radialGradient.gradientStopCount == 0) {
824 std::vector<D2D1_GRADIENT_STOP> stops;
825 stops.resize(radialGradient.gradientStopCount);
828 HRBM(reader.GetGradientStops(0, stops.size(), stops.data()),
829 "Could not get radial gradient stops.");
831 if (stops.size() == 1) {
837 SkScalar colorStopRange = stops.back().position - stops.front().position;
838 SkTileMode tileMode = sk_tile_mode_from(SkTo<D2D1_EXTEND_MODE>(radialGradient.extendMode));
840 if (colorStopRange == 0.f) {
852 stops.push_back({ stops.back().position + 1.0f, stops.back().color });
853 colorStopRange = 1.0f;
862 if (colorStopRange != 1 || stops.front().position != 0.f) {
870 SkScalar radiusDiff = endRadius - startRadius;
871 SkScalar scaleFactor = 1 / colorStopRange;
872 SkScalar stopsStartOffset = stops.front().position;
875 startOffset.
scale(stops.front().position);
877 endOffset.
scale(stops.back().position);
883 endRadius = startRadius + radiusDiff * stops.back().position;
884 startRadius = startRadius + radiusDiff * stops.front().position;
886 for (
auto& stop : stops) {
887 stop.position = (stop.position - stopsStartOffset) * scaleFactor;
896 if (startRadius < 0 || endRadius < 0) {
897 if (startRadius == endRadius && startRadius < 0) {
904 SkScalar radiusDiff = endRadius - startRadius;
906 TruncateStops truncateSide = TruncateStart;
907 if (startRadius < 0) {
908 truncateSide = TruncateStart;
915 zeroRadiusStop = -startRadius / (endRadius - startRadius);
918 startEndDiff.
scale(zeroRadiusStop);
923 truncateSide = TruncateEnd;
924 zeroRadiusStop = -startRadius / (endRadius - startRadius);
927 startEndDiff.
scale(1 - zeroRadiusStop);
931 if (!(startRadius == 0 && endRadius == 0)) {
932 truncateToStopInterpolating(zeroRadiusStop, stops, truncateSide);
937 if (radiusDiff > 0) {
939 endRadius = radiusDiff;
940 stops.erase(stops.begin(), stops.end() - 1);
943 startRadius = -radiusDiff;
944 stops.erase(stops.begin() + 1, stops.end());
948 if (startRadius < 0 || endRadius < 0) {
949 auto roundIntegerMultiple = [](
SkScalar factorZeroCrossing,
951 int roundedMultiple = factorZeroCrossing > 0
952 ? ceilf(factorZeroCrossing)
953 : floorf(factorZeroCrossing) - 1;
955 roundedMultiple += roundedMultiple < 0 ? -1 : 1;
957 return roundedMultiple;
961 SkScalar radiusDiff = endRadius - startRadius;
962 SkScalar factorZeroCrossing = (startRadius / (startRadius - endRadius));
963 bool inRange = 0.f <= factorZeroCrossing && factorZeroCrossing <= 1.0f;
964 SkScalar direction = inRange && radiusDiff < 0 ? -1.0f : 1.0f;
966 roundIntegerMultiple(factorZeroCrossing * direction, tileMode);
967 startToEnd.
scale(circleProjectionFactor);
968 startRadius += circleProjectionFactor * radiusDiff;
969 endRadius += circleProjectionFactor * radiusDiff;
976 std::unique_ptr<SkColor4f[]> skColors(
new SkColor4f[stops.size()]);
977 std::unique_ptr<SkScalar[]> skStops(
new SkScalar[stops.size()]);
978 for (
size_t i = 0;
i < stops.size(); ++
i) {
979 skColors[
i] = sk_color_from(stops[
i].
color);
980 skStops[
i] = stops[
i].position;
990 SkGradientShader::Interpolation::InPremul::kNo,
991 SkGradientShader::Interpolation::ColorSpace::kSRGB,
992 SkGradientShader::Interpolation::HueMethod::kShorter
999 case DWRITE_PAINT_TYPE_SWEEP_GRADIENT: {
1000 auto const& sweepGradient = element.paint.sweepGradient;
1004 if (sweepGradient.gradientStopCount == 0) {
1007 std::vector<D2D1_GRADIENT_STOP> stops;
1008 stops.resize(sweepGradient.gradientStopCount);
1011 HRBM(reader.GetGradientStops(0, stops.size(), stops.data()),
1012 "Could not get sweep gradient stops");
1014 if (stops.size() == 1) {
1023 SkScalar endAngle = sweepGradient.endAngle;
1042 SkTileMode tileMode = sk_tile_mode_from(SkTo<D2D1_EXTEND_MODE>(sweepGradient.extendMode));
1055 float colorStopRange = stops.back().position - stops.front().position;
1056 if (colorStopRange == 0.f) {
1068 stops.push_back({ stops.back().position + 1.0f, stops.back().color });
1069 colorStopRange = 1.0f;
1073 SkScalar scaleFactor = 1 / colorStopRange;
1074 SkScalar startOffset = stops.front().position;
1076 for (D2D1_GRADIENT_STOP& stop : stops) {
1077 stop.position = (stop.position - startOffset) * scaleFactor;
1088 startAngleScaled = 360.f - startAngleScaled;
1089 endAngleScaled = 360.f - endAngleScaled;
1090 if (startAngleScaled >= endAngleScaled) {
1091 std::swap(startAngleScaled, endAngleScaled);
1093 for (
auto& stop : stops) {
1094 stop.position = 1.0f - stop.position;
1098 std::unique_ptr<SkColor4f[]> skColors(
new SkColor4f[stops.size()]);
1099 std::unique_ptr<SkScalar[]> skStops(
new SkScalar[stops.size()]);
1100 for (
size_t i = 0;
i < stops.size(); ++
i) {
1101 skColors[
i] = sk_color_from(stops[
i].
color);
1102 skStops[
i] = stops[
i].position;
1109 startAngleScaled, endAngleScaled,
1111 SkGradientShader::Interpolation::InPremul::kNo,
1112 SkGradientShader::Interpolation::ColorSpace::kSRGB,
1113 SkGradientShader::Interpolation::HueMethod::kShorter
1120 case DWRITE_PAINT_TYPE_GLYPH: {
1123 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
1125 "Could not create geometry to path converter.");
1126 UINT16 glyphId = SkTo<UINT16>(element.paint.glyph.glyphIndex);
1128 Exclusive l(maybe_dw_mutex(*this->getDWriteTypeface()));
1129 HRBM(this->getDWriteTypeface()->fDWriteFontFace->GetGlyphRunOutline(
1137 geometryToPath.get()),
1138 "Could not create glyph outline.");
1142 canvas.
clipPath(
path, fRenderingMode != DWRITE_RENDERING_MODE_ALIASED);
1148 case DWRITE_PAINT_TYPE_COLOR_GLYPH: {
1149 auto const& colorGlyph = element.paint.colorGlyph;
1152 if (D2D_RECT_F_is_empty(colorGlyph.clipBox)) {
1155 SkRect r = sk_rect_from(colorGlyph.clipBox);
1156 canvas.
clipRect(r, fRenderingMode != DWRITE_RENDERING_MODE_ALIASED);
1163 case DWRITE_PAINT_TYPE_TRANSFORM: {
1165 canvas.
concat(sk_matrix_from(element.paint.transform));
1170 case DWRITE_PAINT_TYPE_COMPOSITE: {
1174 blendModePaint.
setBlendMode(sk_blend_mode_from(element.paint.composite.mode));
1179 DWRITE_PAINT_ELEMENT sourceElement;
1180 DWRITE_PAINT_ELEMENT backdropElement;
1182 HRBM(reader.MoveToFirstChild(&sourceElement),
"Could not move to child.");
1183 HRBM(reader.MoveToNextSibling(&backdropElement),
"Could not move to sibiling.");
1185 this->drawColorV1Paint(canvas, reader, backdropElement);
1187 HRBM(reader.MoveToParent(),
"Could not move to parent.");
1188 HRBM(reader.MoveToFirstChild(&sourceElement),
"Could not move to child.");
1189 canvas.
saveLayer(
nullptr, &blendModePaint);
1190 this->drawColorV1Paint(canvas, reader, sourceElement);
1192 HRBM(reader.MoveToParent(),
"Could not move to parent.");
1202bool SkScalerContext_DW::drawColorV1Image(
const SkGlyph& glyph,
SkCanvas& canvas) {
1210 SkTScopedComPtr<IDWritePaintReader> paintReader;
1211 HRBM(fontFace->CreatePaintReader(DWRITE_GLYPH_IMAGE_FORMATS_COLR_PAINT_TREE,
1212 DWRITE_PAINT_FEATURE_LEVEL_COLR_V1,
1214 "Could not create paint reader.");
1216 DWRITE_PAINT_ELEMENT paintElement;
1218 DWRITE_PAINT_ATTRIBUTES attributes;
1219 HRBM(paintReader->SetCurrentGlyph(glyphIndex, &paintElement, &clipBox, &attributes),
1220 "Could not set current glyph.");
1222 if (paintElement.paintType == DWRITE_PAINT_TYPE_NONE) {
1240 if (D2D_RECT_F_is_empty(clipBox)) {
1243 canvas.
clipRect(sk_rect_from(clipBox));
1251 return this->drawColorV1Paint(canvas, *paintReader, paintElement);
1254bool SkScalerContext_DW::generateColorV1Image(
const SkGlyph& glyph,
void* imageBuffer) {
1265 if constexpr (kSkShowTextBlitCoverage) {
1266 canvas.
clear(0x33FF0000);
1272 return this->drawColorV1Image(glyph, canvas);
1275bool SkScalerContext_DW::generateColorV1PaintBounds(
1277 IDWritePaintReader& reader, DWRITE_PAINT_ELEMENT
const & element)
1280 auto boundChildren = [&](UINT32 childCount) ->
bool {
1281 if (childCount == 0) {
1284 DWRITE_PAINT_ELEMENT childElement;
1285 HRB(reader.MoveToFirstChild(&childElement));
1286 this->generateColorV1PaintBounds(ctm,
bounds, reader, childElement);
1288 for (uint32_t
i = 1;
i < childCount; ++
i) {
1289 HRB(reader.MoveToNextSibling(&childElement));
1290 this->generateColorV1PaintBounds(ctm,
bounds, reader, childElement);
1293 HRB(reader.MoveToParent());
1300 switch (element.paintType) {
1301 case DWRITE_PAINT_TYPE_NONE:
1304 case DWRITE_PAINT_TYPE_LAYERS: {
1306 return boundChildren(element.paint.layers.childCount);
1309 case DWRITE_PAINT_TYPE_SOLID_GLYPH: {
1314 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
1316 "Could not create geometry to path converter.");
1317 UINT16 glyphId = SkTo<UINT16>(element.paint.solidGlyph.glyphIndex);
1319 Exclusive l(maybe_dw_mutex(*this->getDWriteTypeface()));
1320 HRBM(this->getDWriteTypeface()->fDWriteFontFace->GetGlyphRunOutline(
1328 geometryToPath.get()),
1329 "Could not create glyph outline.");
1339 case DWRITE_PAINT_TYPE_SOLID: {
1343 case DWRITE_PAINT_TYPE_LINEAR_GRADIENT: {
1347 case DWRITE_PAINT_TYPE_RADIAL_GRADIENT: {
1351 case DWRITE_PAINT_TYPE_SWEEP_GRADIENT: {
1355 case DWRITE_PAINT_TYPE_GLYPH: {
1358 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
1360 "Could not create geometry to path converter.");
1361 UINT16 glyphId = SkTo<UINT16>(element.paint.glyph.glyphIndex);
1363 Exclusive l(maybe_dw_mutex(*this->getDWriteTypeface()));
1364 HRBM(this->getDWriteTypeface()->fDWriteFontFace->GetGlyphRunOutline(
1372 geometryToPath.get()),
1373 "Could not create glyph outline.");
1383 case DWRITE_PAINT_TYPE_COLOR_GLYPH: {
1386 auto const& colorGlyph = element.paint.colorGlyph;
1387 if (D2D_RECT_F_is_empty(colorGlyph.clipBox)) {
1389 return boundChildren(1);
1391 SkRect r = sk_rect_from(colorGlyph.clipBox);
1397 case DWRITE_PAINT_TYPE_TRANSFORM: {
1399 ctm->
preConcat(sk_matrix_from(element.paint.transform));
1400 return boundChildren(1);
1403 case DWRITE_PAINT_TYPE_COMPOSITE: {
1405 return boundChildren(2);
1421 SkTScopedComPtr<IDWritePaintReader> paintReader;
1424 hr = fontFace->CreatePaintReader(DWRITE_GLYPH_IMAGE_FORMATS_COLR_PAINT_TREE,
1425 DWRITE_PAINT_FEATURE_LEVEL_COLR_V1,
1431 DWRITE_PAINT_ELEMENT paintElement;
1433 DWRITE_PAINT_ATTRIBUTES attributes;
1435 HRBM(paintReader->SetCurrentGlyph(glyphIndex, &paintElement, &clipBox, &attributes),
1436 "Could not set the current glyph.");
1438 if (paintElement.paintType == DWRITE_PAINT_TYPE_NONE) {
1455 if (D2D_RECT_F_is_empty(clipBox)) {
1458 if (!this->generateColorV1PaintBounds(&
matrix, &r, *paintReader, paintElement)) {
1463 *
bounds = sk_rect_from(clipBox);
1471bool SkScalerContext_DW::generateColorV1Metrics(
const SkGlyph&,
SkRect*) {
return false; }
1472bool SkScalerContext_DW::generateColorV1Image(
const SkGlyph&,
void*) {
return false; }
1473bool SkScalerContext_DW::drawColorV1Image(
const SkGlyph&,
SkCanvas&) {
return false; }
1477bool SkScalerContext_DW::setAdvance(
const SkGlyph& glyph,
SkVector* advance) {
1484 if (fGlyphCount <= glyphId) {
1488 DWRITE_GLYPH_METRICS gm;
1490 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
1491 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
1493 Exclusive l(maybe_dw_mutex(*typeface));
1500 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode,
1503 "Could not get gdi compatible glyph metrics.");
1505 Exclusive l(maybe_dw_mutex(*typeface));
1506 HRBM(typeface->
fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm),
1507 "Could not get design metrics.");
1510 DWRITE_FONT_METRICS dwfm;
1512 Shared l(maybe_dw_mutex(*typeface));
1515 SkScalar advanceX = fTextSizeMeasure * gm.advanceWidth / dwfm.designUnitsPerEm;
1517 *advance = { advanceX, 0 };
1518 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
1519 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
1529bool SkScalerContext_DW::generateDWMetrics(
const SkGlyph& glyph,
1530 DWRITE_RENDERING_MODE renderingMode,
1531 DWRITE_TEXTURE_TYPE textureType,
1544 DWRITE_GLYPH_OFFSET
offset;
1545 offset.advanceOffset = 0.0f;
1546 offset.ascenderOffset = 0.0f;
1548 DWRITE_GLYPH_RUN
run;
1550 run.glyphAdvances = &advance;
1554 run.glyphIndices = &glyphId;
1558 SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
1560 Exclusive l(maybe_dw_mutex(*typeface));
1563 (fGridFitMode == DWRITE_GRID_FIT_MODE_DISABLED ||
1564 fAntiAliasMode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE))
1566 HRBM(typeface->
fFactory2->CreateGlyphRunAnalysis(
1576 "Could not create DW2 glyph run analysis.");
1578 HRBM(typeface->
fFactory->CreateGlyphRunAnalysis(&
run,
1586 "Could not create glyph run analysis.");
1591 Shared l(maybe_dw_mutex(*typeface));
1592 HRBM(glyphRunAnalysis->GetAlphaTextureBounds(textureType, &bbox),
1593 "Could not get texture bounds.");
1600 if (bbox.left >= bbox.right || bbox.top >= bbox.bottom) {
1608bool SkScalerContext_DW::getColorGlyphRun(
const SkGlyph& glyph,
1609 IDWriteColorGlyphRunEnumerator** colorGlyph)
1614 DWRITE_GLYPH_OFFSET
offset;
1615 offset.advanceOffset = 0.0f;
1616 offset.ascenderOffset = 0.0f;
1618 DWRITE_GLYPH_RUN
run;
1620 run.glyphAdvances = &advance;
1624 run.glyphIndices = &glyphId;
1628 HRESULT hr = this->getDWriteTypeface()->
fFactory2->TranslateColorGlyphRun(
1629 0, 0, &
run,
nullptr, fMeasuringMode, &fXform, 0, colorGlyph);
1630 if (hr == DWRITE_E_NOCOLOR) {
1633 HRBM(hr,
"Failed to translate color glyph run");
1638 SkTScopedComPtr<IDWriteColorGlyphRunEnumerator> colorLayers;
1639 if (!getColorGlyphRun(glyph, &colorLayers)) {
1646 while (
SUCCEEDED(colorLayers->MoveNext(&hasNextRun)) && hasNextRun) {
1647 const DWRITE_COLOR_GLYPH_RUN* colorGlyph;
1648 HRBM(colorLayers->GetCurrentRun(&colorGlyph),
"Could not get current color glyph run");
1651 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
1653 "Could not create geometry to path converter.");
1655 Exclusive l(maybe_dw_mutex(*this->getDWriteTypeface()));
1656 HRBM(colorGlyph->glyphRun.fontFace->GetGlyphRunOutline(
1657 colorGlyph->glyphRun.fontEmSize,
1658 colorGlyph->glyphRun.glyphIndices,
1659 colorGlyph->glyphRun.glyphAdvances,
1660 colorGlyph->glyphRun.glyphOffsets,
1661 colorGlyph->glyphRun.glyphCount,
1662 colorGlyph->glyphRun.isSideways,
1663 colorGlyph->glyphRun.bidiLevel % 2,
1664 geometryToPath.get()),
1665 "Could not create glyph outline.");
1684 if (!this->drawSVGImage(glyph, *recordingCanvas)) {
1696 SkTScopedComPtr<IDWriteFontFace4> fontFace4;
1697 void* glyphDataContext;
1698 Context(IDWriteFontFace4* face4,
void* context)
1699 : fontFace4(SkRefComPtr(face4))
1700 , glyphDataContext(context)
1704static void ReleaseProc(
const void* ptr,
void* context) {
1706 ctx->fontFace4->ReleaseGlyphImageData(ctx->glyphDataContext);
1712 IDWriteFontFace4* fontFace4 = this->getDWriteTypeface()->
fDWriteFontFace4.get();
1717 DWRITE_GLYPH_IMAGE_FORMATS imageFormats;
1718 HRBM(fontFace4->GetGlyphImageFormats(glyph.
getGlyphID(), 0, UINT32_MAX, &imageFormats),
1719 "Cannot get glyph image formats.");
1720 if (!(imageFormats & DWRITE_GLYPH_IMAGE_FORMATS_PNG)) {
1724 DWRITE_GLYPH_IMAGE_DATA glyphData;
1725 void* glyphDataContext;
1726 HRBM(fontFace4->GetGlyphImageData(glyph.
getGlyphID(),
1728 DWRITE_GLYPH_IMAGE_FORMATS_PNG,
1731 "Glyph image data could not be acquired.");
1735 glyphData.imageDataSize,
1753 matrix.preTranslate(-glyphData.horizontalLeftOrigin.x, -glyphData.horizontalLeftOrigin.y);
1767 mx.extraBits = ScalerContextBits::NONE;
1769 if (!this->setAdvance(glyph, &mx.advance)) {
1775 if (generateColorV1Metrics(glyph, &mx.bounds)) {
1777 mx.extraBits |= ScalerContextBits::COLRv1;
1778 mx.neverRequestPath =
true;
1782 if (generateColorMetrics(glyph, &mx.bounds)) {
1784 mx.extraBits |= ScalerContextBits::COLR;
1785 mx.neverRequestPath =
true;
1789 if (generateSVGMetrics(glyph, &mx.bounds)) {
1791 mx.extraBits |= ScalerContextBits::SVG;
1792 mx.neverRequestPath =
true;
1796 if (generatePngMetrics(glyph, &mx.bounds)) {
1799 mx.neverRequestPath =
true;
1804 if (this->generateDWMetrics(glyph, fRenderingMode, fTextureType, &mx.bounds)) {
1805 mx.extraBits = ScalerContextBits::DW;
1812 if (DWRITE_TEXTURE_ALIASED_1x1 != fTextureType ||
1813 DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE == fAntiAliasMode)
1815 if (this->generateDWMetrics(glyph,
1816 DWRITE_RENDERING_MODE_ALIASED,
1817 DWRITE_TEXTURE_ALIASED_1x1,
1821 mx.extraBits = ScalerContextBits::DW_1;
1829 mx.computeFromPath =
true;
1830 mx.extraBits = ScalerContextBits::PATH;
1835 if (
nullptr == metrics) {
1839 sk_bzero(metrics,
sizeof(*metrics));
1841 DWRITE_FONT_METRICS dwfm;
1842 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
1843 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
1871 SkTScopedComPtr<IDWriteFontFace5> fontFace5;
1872 if (
SUCCEEDED(this->getDWriteTypeface()->fDWriteFontFace->QueryInterface(&fontFace5))) {
1873 if (fontFace5->HasVariations()) {
1880 DWRITE_FONT_METRICS1 dwfm1;
1915void SkScalerContext_DW::BilevelToBW(
const uint8_t*
SK_RESTRICT src,
1916 const SkGlyph& glyph,
void* imageBuffer) {
1918 const size_t dstRB = (
width + 7) >> 3;
1921 int byteCount =
width >> 3;
1922 int bitCount =
width & 7;
1924 for (
int y = 0;
y < glyph.
height(); ++
y) {
1925 if (byteCount > 0) {
1926 for (
int i = 0;
i < byteCount; ++
i) {
1928 byte |=
src[0] & (1 << 7);
1929 byte |=
src[1] & (1 << 6);
1930 byte |=
src[2] & (1 << 5);
1931 byte |=
src[3] & (1 << 4);
1932 byte |=
src[4] & (1 << 3);
1933 byte |=
src[5] & (1 << 2);
1934 byte |=
src[6] & (1 << 1);
1935 byte |=
src[7] & (1 << 0);
1942 unsigned mask = 0x80;
1943 for (
int i = 0;
i < bitCount;
i++) {
1944 byte |= (
src[
i]) & mask;
1947 dst[byteCount] = byte;
1953 if constexpr (kSkShowTextBlitCoverage) {
1954 dst =
static_cast<uint8_t*
>(imageBuffer);
1955 for (
unsigned y = 0;
y < (unsigned)glyph.
height();
y += 2) {
1956 for (
unsigned x = (
y & 0x2);
x < (unsigned)glyph.
width();
x+=4) {
1957 uint8_t&
b =
dst[(dstRB *
y) + (
x >> 3)];
1958 b =
b ^ (1 << (0x7 - (
x & 0x7)));
1964template<
bool APPLY_PREBLEND>
1965void SkScalerContext_DW::GrayscaleToA8(
const uint8_t*
SK_RESTRICT src,
1966 const SkGlyph& glyph,
void* imageBuffer,
1967 const uint8_t* table8) {
1968 const size_t dstRB = glyph.
rowBytes();
1972 for (
int y = 0;
y < glyph.
height();
y++) {
1975 dst[
i] = sk_apply_lut_if<APPLY_PREBLEND>(
a, table8);
1976 if constexpr (kSkShowTextBlitCoverage) {
1977 dst[
i] = std::max<U8CPU>(0x30,
dst[
i]);
1980 dst = SkTAddOffset<uint8_t>(
dst, dstRB);
1984template<
bool APPLY_PREBLEND>
1986 const SkGlyph& glyph,
void* imageBuffer,
1987 const uint8_t* table8) {
1988 const size_t dstRB = glyph.
rowBytes();
1992 for (
int y = 0;
y < glyph.
height();
y++) {
1997 dst[
i] = sk_apply_lut_if<APPLY_PREBLEND>((r + g +
b) / 3, table8);
1998 if constexpr (kSkShowTextBlitCoverage) {
1999 dst[
i] = std::max<U8CPU>(0x30,
dst[
i]);
2002 dst = SkTAddOffset<uint8_t>(
dst, dstRB);
2006template<
bool APPLY_PREBLEND,
bool RGB>
2009 const uint8_t* tableR,
const uint8_t* tableG,
2010 const uint8_t* tableB) {
2011 const size_t dstRB = glyph.
rowBytes();
2015 for (
int y = 0;
y < glyph.
height();
y++) {
2019 r = sk_apply_lut_if<APPLY_PREBLEND>(*(
src++), tableR);
2020 g = sk_apply_lut_if<APPLY_PREBLEND>(*(
src++), tableG);
2021 b = sk_apply_lut_if<APPLY_PREBLEND>(*(
src++), tableB);
2023 b = sk_apply_lut_if<APPLY_PREBLEND>(*(
src++), tableB);
2024 g = sk_apply_lut_if<APPLY_PREBLEND>(*(
src++), tableG);
2025 r = sk_apply_lut_if<APPLY_PREBLEND>(*(
src++), tableR);
2027 if constexpr (kSkShowTextBlitCoverage) {
2028 r = std::max<U8CPU>(0x30, r);
2029 g = std::max<U8CPU>(0x30, g);
2030 b = std::max<U8CPU>(0x30,
b);
2034 dst = SkTAddOffset<uint16_t>(
dst, dstRB);
2038const void* SkScalerContext_DW::getDWMaskBits(
const SkGlyph& glyph,
2039 DWRITE_RENDERING_MODE renderingMode,
2040 DWRITE_TEXTURE_TYPE textureType)
2045 if (DWRITE_TEXTURE_CLEARTYPE_3x1 == textureType) {
2048 if (sizeNeeded > fBits.
size()) {
2049 fBits.
resize(sizeNeeded);
2053 memset(fBits.
begin(), 0, sizeNeeded);
2058 FLOAT advance = 0.0f;
2062 DWRITE_GLYPH_OFFSET
offset;
2063 offset.advanceOffset = 0.0f;
2064 offset.ascenderOffset = 0.0f;
2066 DWRITE_GLYPH_RUN
run;
2068 run.glyphAdvances = &advance;
2072 run.glyphIndices = &index;
2076 SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
2078 Exclusive l(maybe_dw_mutex(*typeface));
2081 (fGridFitMode == DWRITE_GRID_FIT_MODE_DISABLED ||
2082 fAntiAliasMode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE))
2093 "Could not create DW2 glyph run analysis.");
2095 HRNM(typeface->
fFactory->CreateGlyphRunAnalysis(&
run,
2103 "Could not create glyph run analysis.");
2109 bbox.left = glyph.
left();
2110 bbox.top = glyph.
top();
2111 bbox.right = glyph.
left() + glyph.
width();
2112 bbox.bottom = glyph.
top() + glyph.
height();
2114 Shared l(maybe_dw_mutex(*typeface));
2115 HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType,
2119 "Could not draw mask.");
2122 return fBits.
begin();
2125bool SkScalerContext_DW::generateDWImage(
const SkGlyph& glyph,
void* imageBuffer) {
2128 DWRITE_RENDERING_MODE renderingMode = fRenderingMode;
2129 DWRITE_TEXTURE_TYPE textureType = fTextureType;
2130 if (
format == ScalerContextBits::DW_1) {
2131 renderingMode = DWRITE_RENDERING_MODE_ALIASED;
2132 textureType = DWRITE_TEXTURE_ALIASED_1x1;
2134 const void*
bits = this->getDWMaskBits(glyph, renderingMode, textureType);
2141 const uint8_t*
src = (
const uint8_t*)
bits;
2142 if (DWRITE_RENDERING_MODE_ALIASED == renderingMode) {
2144 SkASSERT(DWRITE_TEXTURE_ALIASED_1x1 == textureType);
2145 BilevelToBW(
src, glyph, imageBuffer);
2147 if (textureType == DWRITE_TEXTURE_ALIASED_1x1) {
2164 RGBToLcd16<true, false>(
src, glyph, imageBuffer,
2167 RGBToLcd16<true, true>(
src, glyph, imageBuffer,
2172 RGBToLcd16<false, false>(
src, glyph, imageBuffer,
2175 RGBToLcd16<false, true>(
src, glyph, imageBuffer,
2183bool SkScalerContext_DW::drawColorImage(
const SkGlyph& glyph,
SkCanvas& canvas) {
2184 SkTScopedComPtr<IDWriteColorGlyphRunEnumerator> colorLayers;
2185 if (!getColorGlyphRun(glyph, &colorLayers)) {
2186 SkASSERTF(
false,
"Could not get color layers");
2191 paint.setAntiAlias(fRenderingMode != DWRITE_RENDERING_MODE_ALIASED);
2203 while (
SUCCEEDED(colorLayers->MoveNext(&hasNextRun)) && hasNextRun) {
2204 const DWRITE_COLOR_GLYPH_RUN* colorGlyph;
2205 HRBM(colorLayers->GetCurrentRun(&colorGlyph),
"Could not get current color glyph run");
2208 if (colorGlyph->paletteIndex == 0xffff) {
2210 }
else if (colorGlyph->paletteIndex < paletteEntryCount) {
2211 color = palette[colorGlyph->paletteIndex];
2213 SK_TRACEHR(DWRITE_E_NOCOLOR,
"Invalid palette index.");
2219 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
2221 "Could not create geometry to path converter.");
2223 Exclusive l(maybe_dw_mutex(*this->getDWriteTypeface()));
2224 HRBM(colorGlyph->glyphRun.fontFace->GetGlyphRunOutline(
2225 colorGlyph->glyphRun.fontEmSize,
2226 colorGlyph->glyphRun.glyphIndices,
2227 colorGlyph->glyphRun.glyphAdvances,
2228 colorGlyph->glyphRun.glyphOffsets,
2229 colorGlyph->glyphRun.glyphCount,
2230 colorGlyph->glyphRun.isSideways,
2231 colorGlyph->glyphRun.bidiLevel % 2,
2232 geometryToPath.get()),
2233 "Could not create glyph outline.");
2240bool SkScalerContext_DW::generateColorImage(
const SkGlyph& glyph,
void* imageBuffer) {
2251 if constexpr (kSkShowTextBlitCoverage) {
2252 canvas.
clear(0x33FF0000);
2258 return this->drawColorImage(glyph, canvas);
2261bool SkScalerContext_DW::drawSVGImage(
const SkGlyph& glyph,
SkCanvas& canvas) {
2268 DWRITE_GLYPH_IMAGE_FORMATS imageFormats;
2269 HRBM(fontFace4->GetGlyphImageFormats(glyph.
getGlyphID(), 0, UINT32_MAX, &imageFormats),
2270 "Cannot get glyph image formats.");
2271 if (!(imageFormats & DWRITE_GLYPH_IMAGE_FORMATS_SVG)) {
2280 DWRITE_GLYPH_IMAGE_DATA glyphData;
2281 void* glyphDataContext;
2282 HRBM(fontFace4->GetGlyphImageData(glyph.
getGlyphID(),
2284 DWRITE_GLYPH_IMAGE_FORMATS_SVG,
2287 "Glyph SVG data could not be acquired.");
2288 auto svgDecoder = svgFactory((
const uint8_t*)glyphData.imageData, glyphData.imageDataSize);
2289 fontFace4->ReleaseGlyphImageData(glyphDataContext);
2301 matrix.preTranslate(-glyphData.horizontalLeftOrigin.x, -glyphData.horizontalLeftOrigin.y);
2308 return svgDecoder->render(canvas, upem, glyph.
getGlyphID(),
2312bool SkScalerContext_DW::generateSVGImage(
const SkGlyph& glyph,
void* imageBuffer) {
2323 if constexpr (kSkShowTextBlitCoverage) {
2324 canvas.
clear(0x33FF0000);
2330 return this->drawSVGImage(glyph, canvas);
2333bool SkScalerContext_DW::drawPngImage(
const SkGlyph& glyph,
SkCanvas& canvas) {
2334 IDWriteFontFace4* fontFace4 = this->getDWriteTypeface()->
fDWriteFontFace4.get();
2339 DWRITE_GLYPH_IMAGE_DATA glyphData;
2340 void* glyphDataContext;
2341 HRBM(fontFace4->GetGlyphImageData(glyph.
getGlyphID(),
2343 DWRITE_GLYPH_IMAGE_FORMATS_PNG,
2346 "Glyph image data could not be acquired.");
2349 glyphData.imageDataSize,
2362 SkScalar ratio = fTextSizeRender / glyphData.pixelsPerEm;
2363 canvas.
scale(ratio, ratio);
2364 canvas.
translate(-glyphData.horizontalLeftOrigin.x, -glyphData.horizontalLeftOrigin.y);
2369bool SkScalerContext_DW::generatePngImage(
const SkGlyph& glyph,
void* imageBuffer) {
2382 return this->drawPngImage(glyph, canvas);
2387 if (
format == ScalerContextBits::DW ||
2388 format == ScalerContextBits::DW_1)
2390 this->generateDWImage(glyph, imageBuffer);
2391 }
else if (
format == ScalerContextBits::COLRv1) {
2392 this->generateColorV1Image(glyph, imageBuffer);
2393 }
else if (
format == ScalerContextBits::COLR) {
2394 this->generateColorImage(glyph, imageBuffer);
2395 }
else if (
format == ScalerContextBits::SVG) {
2396 this->generateSVGImage(glyph, imageBuffer);
2398 this->generatePngImage(glyph, imageBuffer);
2399 }
else if (
format == ScalerContextBits::PATH) {
2423 if (fGlyphCount <= glyphID) {
2427 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
2429 "Could not create geometry to path converter.");
2430 UINT16 glyphId = SkTo<UINT16>(glyphID);
2432 Exclusive l(maybe_dw_mutex(*this->getDWriteTypeface()));
2435 HRBM(this->getDWriteTypeface()->fDWriteFontFace->GetGlyphRunOutline(
2443 geometryToPath.get()),
2444 "Could not create glyph outline.");
2447 path->transform(fSkXform);
2456 SkRect onGetBounds()
override {
return fGlyph.
rect(); }
2457 size_t onApproximateBytesUsed()
override {
return sizeof(GlyphDrawable); }
2458 void maybeShowTextBlitCoverage(
SkCanvas* canvas) {
2459 if constexpr (kSkShowTextBlitCoverage) {
2461 paint.setColor(0x3300FF00);
2467 struct COLRv1GlyphDrawable :
public GlyphDrawable {
2468 using GlyphDrawable::GlyphDrawable;
2469 void onDraw(
SkCanvas* canvas)
override {
2470 this->maybeShowTextBlitCoverage(canvas);
2471 fSelf->drawColorV1Image(fGlyph, *canvas);
2474 struct COLRGlyphDrawable :
public GlyphDrawable {
2475 using GlyphDrawable::GlyphDrawable;
2476 void onDraw(
SkCanvas* canvas)
override {
2477 this->maybeShowTextBlitCoverage(canvas);
2478 fSelf->drawColorImage(fGlyph, *canvas);
2481 struct SVGGlyphDrawable :
public GlyphDrawable {
2482 using GlyphDrawable::GlyphDrawable;
2483 void onDraw(
SkCanvas* canvas)
override {
2484 this->maybeShowTextBlitCoverage(canvas);
2485 fSelf->drawSVGImage(fGlyph, *canvas);
2489 if (
format == ScalerContextBits::COLRv1) {
2492 if (
format == ScalerContextBits::COLR) {
2495 if (
format == ScalerContextBits::SVG) {
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
#define PNG(FLAG, ZLIBLEVEL)
sk_bzero(glyphs, sizeof(glyphs))
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
#define SK_ABORT(message,...)
#define SkASSERT_RELEASE(cond)
#define SkASSERTF(cond, fmt,...)
@ kExclusion
rc = s + d - two(s*d), ra = kSrcOver
@ kSaturation
saturation of source with hue and luminosity of destination
@ kColorBurn
darken destination to reflect source
@ kLighten
rc = s + d - min(s*da, d*sa), ra = kSrcOver
@ kHue
hue of source with saturation and luminosity of destination
@ kMultiply
r = s*(1-da) + d*(1-sa) + s*d
@ kColorDodge
brighten destination to reflect source
@ kSrcOver
r = s + (1-sa)*d
@ kXor
r = s*(1-da) + d*(1-sa)
@ kLuminosity
luminosity of source with hue and saturation of destination
@ kSoftLight
lighten or darken, depending on source
@ kDifference
rc = s + d - 2*(min(s*da, d*sa)), ra = kSrcOver
@ kOverlay
multiply or screen, depending on destination
@ kSrcATop
r = s*da + d*(1-sa)
@ kDstATop
r = d*sa + s*(1-da)
@ kDstOver
r = d + (1-da)*s
@ kColor
hue and saturation of source with luminosity of destination
@ kHardLight
multiply or screen, depending on source
@ kDarken
rc = s + d - max(s*da, d*sa), ra = kSrcOver
static U16CPU SkPack888ToRGB16(U8CPU r, U8CPU g, U8CPU b)
constexpr SkColor SK_ColorTRANSPARENT
constexpr SkColor SK_ColorBLACK
static uint16_t SkEndianSwap16(uint16_t value)
#define SkEndian_SwapBE16(n)
static constexpr uint32_t SkEndianSwap32(uint32_t value)
#define SkFixedToScalar(x)
#define SkFixedToFloat(x)
static bool isLCD(const SkScalerContextRec &rec)
@ kNone
glyph outlines unchanged
void swap(sk_sp< T > &a, sk_sp< T > &b)
#define SkScalarTruncToInt(x)
#define SkScalarToFloat(x)
#define SkScalarRoundToInt(x)
#define SkScalarRoundToScalar(x)
#define SK_ScalarInfinity
#define SK_AT_SCOPE_EXIT(stmt)
#define SK_SCOPED_CAPABILITY
#define SK_RELEASE_CAPABILITY(...)
#define SK_ACQUIRE_SHARED(...)
static constexpr bool SkToBool(const T &x)
static SkScalar center(float pos0, float pos1)
SkTScopedComPtr< IDWriteFontFace4 > fDWriteFontFace4
SkTScopedComPtr< IDWriteFontFace2 > fDWriteFontFace2
SkTScopedComPtr< IDWriteFactory2 > fFactory2
SkTScopedComPtr< IDWriteFactory > fFactory
size_t fPaletteEntryCount
std::unique_ptr< SkColor[]> fPalette
IDWriteFontFace7 * fDWriteFontFace7
SkTScopedComPtr< IDWriteFontFace1 > fDWriteFontFace1
std::unique_ptr< DWRITE_COLOR_F[]> fDWPalette
SkTScopedComPtr< IDWriteFontFace > fDWriteFontFace
void setPixels(void *pixels)
bool setInfo(const SkImageInfo &imageInfo, size_t rowBytes=0)
int saveLayer(const SkRect *bounds, const SkPaint *paint)
void drawRect(const SkRect &rect, const SkPaint &paint)
void clipRect(const SkRect &rect, SkClipOp op, bool doAntiAlias)
void translate(SkScalar dx, SkScalar dy)
void drawPaint(const SkPaint &paint)
void clear(SkColor color)
void clipPath(const SkPath &path, SkClipOp op, bool doAntiAlias)
void drawPath(const SkPath &path, const SkPaint &paint)
void scale(SkScalar sx, SkScalar sy)
void concat(const SkMatrix &matrix)
void drawImage(const SkImage *image, SkScalar left, SkScalar top)
static sk_sp< SkColorSpace > MakeSRGB()
static HRESULT Create(SkPath *path, IDWriteGeometrySink **geometryToPath)
static sk_sp< SkData > MakeWithProc(const void *ptr, size_t length, ReleaseProc proc, void *ctx)
uint16_t extraBits() const
SkGlyphID getGlyphID() const
const SkPath * path() const
SkMask::Format maskFormat() const
bool pathIsHairline() const
SkFixed getSubYFixed() const
SkFixed getSubXFixed() const
static sk_sp< SkShader > MakeTwoPointConical(const SkPoint &start, SkScalar startRadius, const SkPoint &end, SkScalar endRadius, const SkColor colors[], const SkScalar pos[], int count, SkTileMode mode, uint32_t flags=0, const SkMatrix *localMatrix=nullptr)
static sk_sp< SkShader > MakeSweep(SkScalar cx, SkScalar cy, const SkColor colors[], const SkScalar pos[], int count, SkTileMode mode, SkScalar startAngle, SkScalar endAngle, uint32_t flags, const SkMatrix *localMatrix)
static sk_sp< SkShader > MakeLinear(const SkPoint pts[2], const SkColor colors[], const SkScalar pos[], int count, SkTileMode mode, uint32_t flags=0, const SkMatrix *localMatrix=nullptr)
std::unique_ptr< SkOpenTypeSVGDecoder >(*)(const uint8_t *svg, size_t length) OpenTypeSVGDecoderFactory
static OpenTypeSVGDecoderFactory GetOpenTypeSVGDecoderFactory()
static SkMatrix Scale(SkScalar sx, SkScalar sy)
SkMatrix & postTranslate(SkScalar dx, SkScalar dy)
void mapVectors(SkVector dst[], const SkVector src[], int count) const
static SkMatrix MakeAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, SkScalar skewY, SkScalar scaleY, SkScalar transY, SkScalar pers0, SkScalar pers1, SkScalar pers2)
SkMatrix & preConcat(const SkMatrix &other)
bool mapRect(SkRect *dst, const SkRect &src, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
void setColor(SkColor color)
void setAntiAlias(bool aa)
@ kFill_Style
set to fill geometry
void setColor4f(const SkColor4f &color, SkColorSpace *colorSpace=nullptr)
void setShader(sk_sp< SkShader > shader)
void setBlendMode(SkBlendMode mode)
SkCanvas * beginRecording(const SkRect &bounds, sk_sp< SkBBoxHierarchy > bbh)
sk_sp< SkPicture > finishRecordingAsPicture()
virtual SkRect cullRect() const =0
void generateImage(const SkGlyph &, void *imageBuffer) override
~SkScalerContext_DW() override
SkScalerContext_DW(sk_sp< DWriteFontTypeface >, const SkScalerContextEffects &, const SkDescriptor *)
sk_sp< SkDrawable > generateDrawable(const SkGlyph &) override
GlyphMetrics generateMetrics(const SkGlyph &, SkArenaAlloc *) override
void generateFontMetrics(SkFontMetrics *) override
bool generatePath(const SkGlyph &, SkPath *) override
@ kEmbeddedBitmapText_Flag
static void GenerateImageFromPath(SkMaskBuilder &dst, const SkPath &path, const SkMaskGamma::PreBlend &maskPreBlend, bool doBGR, bool verticalLCD, bool a8FromLCD, bool hairline)
const SkMaskGamma::PreBlend fPreBlend
bool isApplicable() const
int getUnitsPerEm() const
FlutterSemanticsFlag flags
uint32_t uint32_t * format
static float max(float r, float g, float b)
static float min(float r, float g, float b)
SK_API sk_sp< SkImage > DeferredFromEncodedData(sk_sp< SkData > encoded, std::optional< SkAlphaType > alphaType=std::nullopt)
SK_API std::unique_ptr< SkCodec > Decode(std::unique_ptr< SkStream >, SkCodec::Result *, SkCodecs::DecodeContext=nullptr)
unsigned useCenter Optional< SkMatrix > matrix
Optional< SkRect > bounds
sk_sp< const SkImage > image
sk_sp< SkBlender > blender SkRect rect
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
SkScalar fTop
greatest extent above origin of any glyph bounding box, typically negative; deprecated with variable ...
SkScalar fLeading
distance to add between lines, typically positive or zero
SkScalar fStrikeoutPosition
distance from baseline to bottom of stroke, typically negative
SkScalar fStrikeoutThickness
strikeout thickness
SkScalar fMaxCharWidth
maximum character width, zero if unknown
SkScalar fBottom
greatest extent below origin of any glyph bounding box, typically positive; deprecated with variable ...
uint32_t fFlags
FontMetricsFlags indicating which metrics are valid.
SkScalar fAscent
distance to reserve above baseline, typically negative
SkScalar fXHeight
height of lower-case 'x', zero if unknown, typically negative
SkScalar fUnderlineThickness
underline thickness
@ kStrikeoutPositionIsValid_Flag
set if fStrikeoutPosition is valid
@ kStrikeoutThicknessIsValid_Flag
set if fStrikeoutThickness is valid
@ kUnderlinePositionIsValid_Flag
set if fUnderlinePosition is valid
@ kUnderlineThicknessIsValid_Flag
set if fUnderlineThickness is valid
@ kBoundsInvalid_Flag
set if fTop, fBottom, fXMin, fXMax invalid
SkScalar fDescent
distance to reserve below baseline, typically positive
SkScalar fCapHeight
height of an upper-case letter, zero if unknown, typically negative
SkScalar fXMin
greatest extent to left of origin of any glyph bounding box, typically negative; deprecated with vari...
SkScalar fUnderlinePosition
distance from baseline to top of stroke, typically positive
SkScalar fXMax
greatest extent to right of origin of any glyph bounding box, typically positive; deprecated with var...
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
@ kA8_Format
8bits per pixel mask (e.g. antialiasing)
@ kLCD16_Format
565 alpha for r/g/b
@ kARGB32_Format
SkPMColor.
@ kBW_Format
1bit per pixel mask (e.g. monochrome)
SK_OT_USHORT endGlyphIndex
SK_OT_USHORT startGlyphIndex
static const SK_OT_Fixed version_initial
static const SK_OT_Fixed version_initial
union SkOTTableGridAndScanProcedure::GaspRange::behavior flags
static const SK_OT_USHORT version1
static const SK_OT_USHORT version0
static const SK_OT_Fixed version1
static const SK_OT_Fixed VERSION
static float CrossProduct(const SkVector &a, const SkVector &b)
static float DotProduct(const SkVector &a, const SkVector &b)
static constexpr SkPoint Make(float x, float y)
void scale(float scale, SkPoint *dst) const
constexpr float y() const
constexpr float x() const
static constexpr SkRect MakeEmpty()
static constexpr SkRect MakeLTRB(float l, float t, float r, float b)
uint32_t fForegroundColor
SkMask::Format fMaskFormat
std::shared_ptr< const fml::Mapping > data