Flutter Engine
The Flutter Engine
SkTypeface_fontations.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2023 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 */
8
13#include "include/core/SkData.h"
21#include "src/core/SkFontPriv.h"
24
25namespace {
26
27[[maybe_unused]] static inline const constexpr bool kSkShowTextBlitCoverage = false;
28
29sk_sp<SkData> streamToData(const std::unique_ptr<SkStreamAsset>& font_data) {
30 // TODO(drott): From a stream this causes a full read/copy. Make sure
31 // we can instantiate this directly from the decompressed buffer that
32 // Blink has after OTS and woff2 decompression.
33 font_data->rewind();
34 return SkData::MakeFromStream(font_data.get(), font_data->getLength());
35}
36
37rust::Box<::fontations_ffi::BridgeFontRef> make_bridge_font_ref(sk_sp<SkData> fontData,
38 uint32_t index) {
39 rust::Slice<const uint8_t> slice{fontData->bytes(), fontData->size()};
40 return fontations_ffi::make_font_ref(slice, index);
41}
42
43static_assert(sizeof(fontations_ffi::SkiaDesignCoordinate) ==
45 sizeof(fontations_ffi::SkiaDesignCoordinate::axis) ==
49 offsetof(fontations_ffi::SkiaDesignCoordinate, axis) ==
51 offsetof(fontations_ffi::SkiaDesignCoordinate, value) ==
53 "Struct fontations_ffi::SkiaDesignCoordinate must match "
54 "SkFontArguments::VariationPosition::Coordinate.");
55
56rust::Box<fontations_ffi::BridgeNormalizedCoords> make_normalized_coords(
57 fontations_ffi::BridgeFontRef const& bridgeFontRef,
58 const SkFontArguments::VariationPosition& variationPosition) {
59 // Cast is safe because of static_assert matching the structs above.
60 rust::Slice<const fontations_ffi::SkiaDesignCoordinate> coordinates(
61 reinterpret_cast<const fontations_ffi::SkiaDesignCoordinate*>(
62 variationPosition.coordinates),
63 variationPosition.coordinateCount);
64 return resolve_into_normalized_coords(bridgeFontRef, coordinates);
65}
66
67SkMatrix SkMatrixFromFontationsTransform(const fontations_ffi::Transform& transformArg) {
68 return SkMatrix::MakeAll(transformArg.xx,
69 -transformArg.xy,
70 transformArg.dx,
71 -transformArg.yx,
72 transformArg.yy,
73 -transformArg.dy,
74 0.f,
75 0.f,
76 1.0f);
77}
78
79bool isLCD(const SkScalerContextRec& rec) { return SkMask::kLCD16_Format == rec.fMaskFormat; }
80
81bool bothZero(SkScalar a, SkScalar b) { return 0 == a && 0 == b; }
82
83bool isAxisAligned(const SkScalerContextRec& rec) {
84 return 0 == rec.fPreSkewX && (bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
85 bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
86}
87
88} // namespace
89
90sk_sp<SkTypeface> SkTypeface_Make_Fontations(std::unique_ptr<SkStreamAsset> fontData,
91 const SkFontArguments& args) {
92 return SkTypeface_Fontations::MakeFromStream(std::move(fontData), args);
93}
94
95SkTypeface_Fontations::SkTypeface_Fontations(
96 sk_sp<SkData> fontData,
97 const SkFontStyle& style,
98 uint32_t ttcIndex,
99 rust::Box<fontations_ffi::BridgeFontRef>&& fontRef,
100 rust::Box<fontations_ffi::BridgeMappingIndex>&& mappingIndex,
101 rust::Box<fontations_ffi::BridgeNormalizedCoords>&& normalizedCoords,
102 rust::Box<fontations_ffi::BridgeOutlineCollection>&& outlines,
103 rust::Vec<uint32_t>&& palette)
104 : SkTypeface(style, true)
105 , fFontData(std::move(fontData))
106 , fTtcIndex(ttcIndex)
107 , fBridgeFontRef(std::move(fontRef))
108 , fMappingIndex(std::move(mappingIndex))
109 , fBridgeNormalizedCoords(std::move(normalizedCoords))
110 , fOutlines(std::move(outlines))
111 , fPalette(std::move(palette)) {}
112
114 const SkFontArguments& args) {
115 return MakeFromData(streamToData(stream), args);
116}
117
119 const SkFontArguments& args) {
120 uint32_t ttcIndex = args.getCollectionIndex();
121 rust::Box<fontations_ffi::BridgeFontRef> bridgeFontRef = make_bridge_font_ref(data, ttcIndex);
122 if (!fontations_ffi::font_ref_is_valid(*bridgeFontRef)) {
123 return nullptr;
124 }
125
126 rust::Box<fontations_ffi::BridgeMappingIndex> mappingIndex =
127 fontations_ffi::make_mapping_index(*bridgeFontRef);
128
129 SkFontArguments::VariationPosition variationPosition = args.getVariationDesignPosition();
130 std::unique_ptr<SkFontArguments::VariationPosition::Coordinate[]> concatenatedCoords = nullptr;
131 // Handle FreeType behaviour of upper 15 bits of collection index
132 // representing a named instance choice. If so, prepopulate the variation
133 // coordinates with the values from the named instance and append the user
134 // coordinates after that so they can override the named instance's
135 // coordinates.
136 if (args.getCollectionIndex() & 0xFFFF0000) {
137 size_t numNamedInstanceCoords =
138 fontations_ffi::coordinates_for_shifted_named_instance_index(
139 *bridgeFontRef,
140 args.getCollectionIndex(),
141 rust::cxxbridge1::Slice<fontations_ffi::SkiaDesignCoordinate>());
142 concatenatedCoords.reset(
144 [numNamedInstanceCoords + variationPosition.coordinateCount]);
145
146 rust::cxxbridge1::Slice<fontations_ffi::SkiaDesignCoordinate> targetSlice(
147 reinterpret_cast<fontations_ffi::SkiaDesignCoordinate*>(concatenatedCoords.get()),
148 numNamedInstanceCoords);
149 size_t retrievedNamedInstanceCoords =
150 fontations_ffi::coordinates_for_shifted_named_instance_index(
151 *bridgeFontRef, args.getCollectionIndex(), targetSlice);
152 if (numNamedInstanceCoords != retrievedNamedInstanceCoords) {
153 return nullptr;
154 }
155 for (int i = 0; i < variationPosition.coordinateCount; ++i) {
156 concatenatedCoords[numNamedInstanceCoords + i] = variationPosition.coordinates[i];
157 }
158 variationPosition.coordinateCount += numNamedInstanceCoords;
159 variationPosition.coordinates = concatenatedCoords.get();
160 }
161
162 rust::Box<fontations_ffi::BridgeNormalizedCoords> normalizedCoords =
163 make_normalized_coords(*bridgeFontRef, variationPosition);
164 SkFontStyle style;
165 fontations_ffi::BridgeFontStyle fontStyle;
166 if (fontations_ffi::get_font_style(*bridgeFontRef, *normalizedCoords, fontStyle)) {
169 static_cast<SkFontStyle::Slant>(fontStyle.slant));
170 }
171 rust::Box<fontations_ffi::BridgeOutlineCollection> outlines =
172 fontations_ffi::get_outline_collection(*bridgeFontRef);
173
174 rust::Slice<const fontations_ffi::PaletteOverride> paletteOverrides(
175 reinterpret_cast<const ::fontations_ffi::PaletteOverride*>(args.getPalette().overrides),
176 args.getPalette().overrideCount);
177 rust::Vec<uint32_t> palette =
178 resolve_palette(*bridgeFontRef, args.getPalette().index, paletteOverrides);
179
181 style,
182 ttcIndex,
183 std::move(bridgeFontRef),
184 std::move(mappingIndex),
185 std::move(normalizedCoords),
186 std::move(outlines),
187 std::move(palette)));
188}
189
190namespace sk_fontations {
191
192// Path sanitization ported from SkFTGeometrySink.
193void PathGeometrySink::going_to(SkPoint point) {
194 if (!fStarted) {
195 fStarted = true;
196 fPath.moveTo(fCurrent);
197 }
198 fCurrent = point;
199}
200
201bool PathGeometrySink::current_is_not(SkPoint point) { return fCurrent != point; }
202
203void PathGeometrySink::move_to(float x, float y) {
204 if (fStarted) {
205 fPath.close();
206 fStarted = false;
207 }
209}
210
211void PathGeometrySink::line_to(float x, float y) {
213 if (current_is_not(pt0)) {
214 going_to(pt0);
215 fPath.lineTo(pt0);
216 }
217}
218
219void PathGeometrySink::quad_to(float cx0, float cy0, float x, float y) {
222 if (current_is_not(pt0) || current_is_not(pt1)) {
223 going_to(pt1);
224 fPath.quadTo(pt0, pt1);
225 }
226}
227void PathGeometrySink::curve_to(float cx0, float cy0, float cx1, float cy1, float x, float y) {
231 if (current_is_not(pt0) || current_is_not(pt1) || current_is_not(pt2)) {
232 going_to(pt2);
233 fPath.cubicTo(pt0, pt1, pt2);
234 }
235}
236
238
239SkPath PathGeometrySink::into_inner() && { return std::move(fPath); }
240
242 : fAxisArray(axisArray), fAxisCount(axisCount) {}
243
245 size_t i, uint32_t axisTag, float min, float def, float max, bool hidden) {
246 if (i >= fAxisCount) {
247 return false;
248 }
249 SkFontParameters::Variation::Axis& axis = fAxisArray[i];
250 axis.tag = axisTag;
251 axis.min = min;
252 axis.def = def;
253 axis.max = max;
254 axis.setHidden(hidden);
255 return true;
256}
257
258size_t AxisWrapper::size() const { return fAxisCount; }
259
260} // namespace sk_fontations
261
263 return fontations_ffi::units_per_em_or_zero(*fBridgeFontRef);
264}
265
267 rust::String readFamilyName = fontations_ffi::family_name(*fBridgeFontRef);
268 *familyName = SkString(readFamilyName.data(), readFamilyName.size());
269}
270
272 rust::String readPsName;
273 if (fontations_ffi::postscript_name(*fBridgeFontRef, readPsName)) {
274 if (postscriptName) {
275 *postscriptName = SkString(readPsName.data(), readPsName.size());
276 }
277 return true;
278 }
279
280 return false;
281}
282
284 fGlyphMasksMayNeedCurrentColorOnce([this] {
285 static constexpr SkFourByteTag COLRTag = SkSetFourByteTag('C', 'O', 'L', 'R');
286 fGlyphMasksMayNeedCurrentColor = this->getTableSize(COLRTag) > 0;
287 });
288 return fGlyphMasksMayNeedCurrentColor;
289}
290
292 int count,
293 SkGlyphID glyphs[]) const {
294 sk_bzero(glyphs, count * sizeof(glyphs[0]));
295
296 for (int i = 0; i < count; ++i) {
297 glyphs[i] = fontations_ffi::lookup_glyph_or_zero(*fBridgeFontRef, *fMappingIndex, chars[i]);
298 }
299}
301 return fontations_ffi::num_glyphs(*fBridgeFontRef);
302}
303
305 size_t numGlyphs = SkToSizeT(onCountGlyphs());
306 if (!codepointForGlyphMap) {
307 SkASSERT(numGlyphs == 0);
308 }
309 rust::Slice<uint32_t> codepointForGlyphSlice{reinterpret_cast<uint32_t*>(codepointForGlyphMap),
310 numGlyphs};
311 fontations_ffi::fill_glyph_to_unicode_map(*fBridgeFontRef, codepointForGlyphSlice);
312}
313
315 // Opportunistic hinting downgrades copied from SkFontHost_FreeType.cpp
316 SkFontHinting h = rec->getHinting();
317 if (SkFontHinting::kFull == h && !isLCD(*rec)) {
318 // Collapse full->normal hinting if we're not doing LCD.
320 }
321
322 // Rotated text looks bad with hinting, so we disable it as needed.
323 if (!isAxisAligned(*rec)) {
325 }
326 rec->setHinting(h);
327}
328
330public:
332 rust::Box<::fontations_ffi::BridgeLocalizedStrings> bridge_localized_strings)
333 : fBridgeLocalizedStrings(std::move(bridge_localized_strings)) {}
334 bool next(SkTypeface::LocalizedString* localized_string) override {
335 fontations_ffi::BridgeLocalizedName localizedName;
336 if (!fontations_ffi::localized_name_next(*fBridgeLocalizedStrings, localizedName)) {
337 return false;
338 }
339 localized_string->fString =
340 SkString(localizedName.string.data(), localizedName.string.size());
341 localized_string->fLanguage =
342 SkString(localizedName.language.data(), localizedName.language.size());
343 return true;
344 }
345
346private:
347 rust::Box<::fontations_ffi::BridgeLocalizedStrings> fBridgeLocalizedStrings;
348};
349
351 return new SkrifaLocalizedStrings(fontations_ffi::get_localized_strings(*fBridgeFontRef));
352}
353
355public:
357 const SkScalerContextEffects& effects,
358 const SkDescriptor* desc)
359 : SkScalerContext(face, effects, desc)
360 , fBridgeFontRef(
361 static_cast<SkTypeface_Fontations*>(this->getTypeface())->getBridgeFontRef())
362 , fBridgeNormalizedCoords(static_cast<SkTypeface_Fontations*>(this->getTypeface())
363 ->getBridgeNormalizedCoords())
364 , fOutlines(static_cast<SkTypeface_Fontations*>(this->getTypeface())->getOutlines())
365 , fPalette(static_cast<SkTypeface_Fontations*>(this->getTypeface())->getPalette())
366 , fHintingInstance(fontations_ffi::no_hinting_instance()) {
367 fRec.getSingleMatrix(&fMatrix);
368
370 SkMatrix remainingMatrix;
373
374 fDoLinearMetrics = this->isLinearMetrics();
377 fHintingInstance = fontations_ffi::no_hinting_instance();
378 fDoLinearMetrics = true;
379 } else {
380 fHintingInstance = fontations_ffi::make_mono_hinting_instance(
381 fOutlines, scale.fY, fBridgeNormalizedCoords);
382 fDoLinearMetrics = false;
383 }
384 } else {
385 switch (fRec.getHinting()) {
387 fHintingInstance = fontations_ffi::no_hinting_instance();
388 fDoLinearMetrics = true;
389 break;
391 // Unhinted metrics.
392 fHintingInstance = fontations_ffi::make_hinting_instance(
393 fOutlines,
394 scale.fY,
395 fBridgeNormalizedCoords,
396 false /* do_lcd_antialiasing */,
397 false /* lcd_orientation_vertical */,
398 true /* preserve_linear_metrics */);
399 fDoLinearMetrics = true;
400 break;
402 // No hinting to subpixel coordinates.
403 fHintingInstance = fontations_ffi::make_hinting_instance(
404 fOutlines,
405 scale.fY,
406 fBridgeNormalizedCoords,
407 false /* do_lcd_antialiasing */,
408 false /* lcd_orientation_vertical */,
409 fDoLinearMetrics /* preserve_linear_metrics */);
410 break;
412 // Attempt to make use of hinting to subpixel coordinates.
413 fHintingInstance = fontations_ffi::make_hinting_instance(
414 fOutlines,
415 scale.fY,
416 fBridgeNormalizedCoords,
417 isLCD(fRec) /* do_lcd_antialiasing */,
420 kLCD_Vertical_Flag) /* lcd_orientation_vertical */,
421 fDoLinearMetrics /* preserve_linear_metrics */);
422 }
423 }
424 }
425
426 // yScale is only used if hintinInstance is set to Unhinted,
427 // otherwise the size is controlled by the configured hintingInstance.
428 // hintingInstance argument is needed as COLRv1 drawing performs unhinted,
429 // unscaled path retrieval.
431 uint16_t glyphId,
432 SkPath* path,
433 float yScale,
434 const fontations_ffi::BridgeHintingInstance& hintingInstance) {
436 fontations_ffi::BridgeScalerMetrics scalerMetrics;
437
438 if (!fontations_ffi::get_path(fOutlines,
439 glyphId,
440 yScale,
441 fBridgeNormalizedCoords,
442 hintingInstance,
443 pathWrapper,
444 scalerMetrics)) {
445 return false;
446 }
447 *path = std::move(pathWrapper).into_inner();
448
449 // See https://issues.skia.org/345178242 for details:
450 // The FreeType backend performs a path simplification here based on the
451 // equivalent of what we have here as scalerMetrics.has_overlaps
452 // Since PathOps::Simplify fails or at times produces incorrect simplified
453 // contours, skip that step here.
454 return true;
455 }
456
457protected:
459 using value_type = uint16_t;
460 static const constexpr value_type PATH = 1;
461 static const constexpr value_type COLRv0 = 2;
462 static const constexpr value_type COLRv1 = 3;
463 static const constexpr value_type BITMAP = 4;
464 };
465
467 GlyphMetrics mx(glyph.maskFormat());
468
469 bool has_colrv1_glyph =
470 fontations_ffi::has_colrv1_glyph(fBridgeFontRef, glyph.getGlyphID());
471 bool has_colrv0_glyph =
472 fontations_ffi::has_colrv0_glyph(fBridgeFontRef, glyph.getGlyphID());
473 bool has_bitmap_glyph =
474 fontations_ffi::has_bitmap_glyph(fBridgeFontRef, glyph.getGlyphID());
475
476 // Local overrides for color fonts etc. may alter the request for linear metrics.
477 bool doLinearMetrics = fDoLinearMetrics;
478
479 if (has_bitmap_glyph) {
480 // Bitmap advance metrics can originate from different strike sizes in the bitmap
481 // font and are thus not linearly scaling with font size.
482 doLinearMetrics = false;
483 }
484 if (has_colrv0_glyph || has_colrv1_glyph) {
485 // We prefer color vector glyphs, and hinting is disabled for those.
486 doLinearMetrics = true;
487 }
488
490 SkMatrix remainingMatrix;
493 return mx;
494 }
495 float x_advance = 0.0f;
496 x_advance = fontations_ffi::unhinted_advance_width_or_zero(
497 fBridgeFontRef, scale.y(), fBridgeNormalizedCoords, glyph.getGlyphID());
498 if (!doLinearMetrics) {
499 float hinted_advance = 0;
500 fontations_ffi::scaler_hinted_advance_width(
501 fOutlines, *fHintingInstance, glyph.getGlyphID(), hinted_advance);
502 // TODO(drott): Remove this workaround for fontations returning 0
503 // for a space glyph without contours, compare
504 // https://github.com/googlefonts/fontations/issues/905
505 if (hinted_advance != x_advance && hinted_advance != 0) {
506 x_advance = hinted_advance;
507 }
508 }
509 mx.advance = remainingMatrix.mapXY(x_advance, SkFloatToScalar(0.f));
510
511 if (has_colrv1_glyph || has_colrv0_glyph) {
514 mx.neverRequestPath = true;
515
516 fontations_ffi::ClipBox clipBox;
517 if (has_colrv1_glyph && fontations_ffi::get_colrv1_clip_box(fBridgeFontRef,
518 fBridgeNormalizedCoords,
519 glyph.getGlyphID(),
520 scale.y(),
521 clipBox)) {
522 // Flip y.
523 SkRect boundsRect = SkRect::MakeLTRB(
524 clipBox.x_min, -clipBox.y_max, clipBox.x_max, -clipBox.y_min);
525
526 if (!remainingMatrix.isIdentity()) {
527 SkPath boundsPath = SkPath::Rect(boundsRect);
528 boundsPath.transform(remainingMatrix);
529 boundsRect = boundsPath.getBounds();
530 }
531
532 boundsRect.roundOut(&mx.bounds);
533
534 } else {
535 uint16_t upem = fontations_ffi::units_per_em_or_zero(fBridgeFontRef);
536 if (upem == 0) {
538 } else {
539 SkMatrix fullTransform;
540 fRec.getSingleMatrix(&fullTransform);
541 fullTransform.preScale(1.f / upem, 1.f / upem);
542
543 sk_fontations::BoundsPainter boundsPainter(*this, fullTransform, upem);
544 bool result = fontations_ffi::draw_colr_glyph(fBridgeFontRef,
545 fBridgeNormalizedCoords,
546 glyph.getGlyphID(),
547 boundsPainter);
548 if (result) {
549 boundsPainter.getBoundingBox().roundOut(&mx.bounds);
550 } else {
552 }
553 }
554 }
555 } else if (has_bitmap_glyph) {
557 mx.neverRequestPath = true;
559
560 rust::cxxbridge1::Box<fontations_ffi::BridgeBitmapGlyph> bitmap_glyph =
561 fontations_ffi::bitmap_glyph(fBridgeFontRef, glyph.getGlyphID(), scale.fY);
562 rust::cxxbridge1::Slice<const uint8_t> png_data =
563 fontations_ffi::png_data(*bitmap_glyph);
564 SkASSERT(png_data.size());
565
566 const fontations_ffi::BitmapMetrics bitmapMetrics =
567 fontations_ffi::bitmap_metrics(*bitmap_glyph);
568
569 std::unique_ptr<SkCodec> codec = SkPngDecoder::Decode(
570 SkData::MakeWithoutCopy(png_data.data(), png_data.size()), nullptr);
571 if (!codec) {
572 return mx;
573 }
574
575 SkImageInfo info = codec->getInfo();
576
577 SkRect bounds = SkRect::Make(info.bounds());
578 SkMatrix matrix = remainingMatrix;
579
580 // We deal with two scale factors here: Scaling from font units to
581 // device pixels, and scaling the embedded PNG from its number of
582 // rows to a specific size, depending on the ppem values in the
583 // bitmap glyph information.
584 SkScalar imageToSize = scale.fY / bitmapMetrics.ppem_y;
585 float fontUnitsToSize = scale.fY / fontations_ffi::units_per_em_or_zero(fBridgeFontRef);
586
587 // The offset from origin is given in font units, so requires a
588 // different scale factor than the scaling of the image.
589 matrix.preTranslate( bitmapMetrics.bearing_x * fontUnitsToSize,
590 -bitmapMetrics.bearing_y * fontUnitsToSize);
591 matrix.preScale(imageToSize, imageToSize);
592 matrix.preTranslate( bitmapMetrics.inner_bearing_x,
593 -bitmapMetrics.inner_bearing_y);
594
595 // For sbix bitmap glyphs, the origin is the bottom left of the image.
596 float heightAdjustment =
597 bitmapMetrics.placement_origin_bottom_left ? bounds.height() : 0;
598 matrix.preTranslate(0, -heightAdjustment);
599
600 if (this->isSubpixel()) {
603 }
604 matrix.mapRect(&bounds);
605 mx.bounds = SkRect::Make(bounds.roundOut());
606
607 if (SkIsFinite(bitmapMetrics.advance)) {
608 mx.advance = matrix.mapVector(bitmapMetrics.advance, 0);
609 }
610 } else {
612 mx.computeFromPath = true;
613 }
614 return mx;
615 }
616
617 void generatePngImage(const SkGlyph& glyph, void* imageBuffer) {
619 SkBitmap dstBitmap;
620 dstBitmap.setInfo(
622 glyph.width(), glyph.height(), kN32_SkColorType, kPremul_SkAlphaType),
623 glyph.rowBytes());
624 dstBitmap.setPixels(imageBuffer);
625
626 SkCanvas canvas(dstBitmap);
627
628 canvas.translate(-glyph.left(), -glyph.top());
629
631 SkMatrix remainingMatrix;
634 return;
635 }
636
637 rust::cxxbridge1::Box<fontations_ffi::BridgeBitmapGlyph> bitmap_glyph =
638 fontations_ffi::bitmap_glyph(fBridgeFontRef, glyph.getGlyphID(), scale.fY);
639 rust::cxxbridge1::Slice<const uint8_t> png_data = fontations_ffi::png_data(*bitmap_glyph);
640 SkASSERT(png_data.size());
641
642 std::unique_ptr<SkCodec> codec = SkPngDecoder::Decode(
643 SkData::MakeWithoutCopy(png_data.data(), png_data.size()), nullptr);
644
645 if (!codec) {
646 return;
647 }
648
649 auto [glyph_image, result] = codec->getImage();
651 return;
652 }
653
655 canvas.concat(remainingMatrix);
656
657 if (this->isSubpixel()) {
658 canvas.translate(SkFixedToScalar(glyph.getSubXFixed()),
660 }
661 const fontations_ffi::BitmapMetrics bitmapMetrics =
662 fontations_ffi::bitmap_metrics(*bitmap_glyph);
663
664 // We need two different scale factors here, one for font units to size,
665 // one for scaling the embedded PNG, see generateMetrics() for details.
666 SkScalar imageScaleFactor = scale.fY / bitmapMetrics.ppem_y;
667
668 float fontUnitsToSize = scale.fY / fontations_ffi::units_per_em_or_zero(fBridgeFontRef);
669 canvas.translate( bitmapMetrics.bearing_x * fontUnitsToSize,
670 -bitmapMetrics.bearing_y * fontUnitsToSize);
671 canvas.scale(imageScaleFactor, imageScaleFactor);
672 canvas.translate( bitmapMetrics.inner_bearing_x,
673 -bitmapMetrics.inner_bearing_y);
674
675 float heightAdjustment =
676 bitmapMetrics.placement_origin_bottom_left ? glyph_image->height() : 0;
677
678 canvas.translate(0, -heightAdjustment);
679
681 canvas.drawImage(glyph_image, 0, 0, sampling);
682 }
683
684 void generateImage(const SkGlyph& glyph, void* imageBuffer) override {
687 const SkPath* devPath = glyph.path();
688 SkASSERT_RELEASE(devPath);
689 SkMaskBuilder mask(static_cast<uint8_t*>(imageBuffer),
690 glyph.iRect(),
691 glyph.rowBytes(),
692 glyph.maskFormat());
697 const bool hairline = glyph.pathIsHairline();
698 GenerateImageFromPath(mask, *devPath, fPreBlend, doBGR, doVert, a8LCD, hairline);
699
702 SkBitmap dstBitmap;
703 dstBitmap.setInfo(
705 glyph.width(), glyph.height(), kN32_SkColorType, kPremul_SkAlphaType),
706 glyph.rowBytes());
707 dstBitmap.setPixels(imageBuffer);
708
709 SkCanvas canvas(dstBitmap);
710 if constexpr (kSkShowTextBlitCoverage) {
711 canvas.clear(0x33FF0000);
712 } else {
714 }
715 canvas.translate(-glyph.left(), -glyph.top());
716
717 drawCOLRGlyph(glyph, fRec.fForegroundColor, &canvas);
718 } else if (format == ScalerContextBits::BITMAP) {
719 generatePngImage(glyph, imageBuffer);
720 } else {
721 SK_ABORT("Bad format");
722 }
723 }
724
725 bool generatePath(const SkGlyph& glyph, SkPath* path) override {
727
729 SkMatrix remainingMatrix;
732 return false;
733 }
735 glyph.getGlyphID(), path, scale.y(), *fHintingInstance);
736 if (!result) {
737 return false;
738 }
739
740 *path = path->makeTransform(remainingMatrix);
741 return true;
742 }
743
744 bool drawCOLRGlyph(const SkGlyph& glyph, SkColor foregroundColor, SkCanvas* canvas) {
745 uint16_t upem = fontations_ffi::units_per_em_or_zero(fBridgeFontRef);
746 if (upem == 0) {
747 return false;
748 }
749
750 SkMatrix scalerMatrix;
751 fRec.getSingleMatrix(&scalerMatrix);
752 SkAutoCanvasRestore autoRestore(canvas, true /* doSave */);
753
754 // Scale down so that COLR operations can happen in glyph coordinates.
755 SkMatrix upemToPpem = SkMatrix::Scale(1.f / upem, 1.f / upem);
756 scalerMatrix.preConcat(upemToPpem);
757 canvas->concat(scalerMatrix);
758 SkPaint defaultPaint;
759 defaultPaint.setColor(SK_ColorRED);
760 sk_fontations::ColorPainter colorPainter(*this, *canvas, fPalette, foregroundColor,
762 bool result = fontations_ffi::draw_colr_glyph(
763 fBridgeFontRef, fBridgeNormalizedCoords, glyph.getGlyphID(), colorPainter);
764 return result;
765 }
766
768 struct GlyphDrawable : public SkDrawable {
770 SkGlyph fGlyph;
771 GlyphDrawable(SkFontationsScalerContext* self, const SkGlyph& glyph)
772 : fSelf(self), fGlyph(glyph) {}
773 SkRect onGetBounds() override { return fGlyph.rect(); }
774 size_t onApproximateBytesUsed() override { return sizeof(GlyphDrawable); }
775 void maybeShowTextBlitCoverage(SkCanvas* canvas) {
776 if constexpr (kSkShowTextBlitCoverage) {
778 paint.setColor(0x3300FF00);
779 paint.setStyle(SkPaint::kFill_Style);
780 canvas->drawRect(this->onGetBounds(), paint);
781 }
782 }
783 };
784 struct ColrGlyphDrawable : public GlyphDrawable {
785 using GlyphDrawable::GlyphDrawable;
786 void onDraw(SkCanvas* canvas) override {
787 this->maybeShowTextBlitCoverage(canvas);
788 fSelf->drawCOLRGlyph(fGlyph, fSelf->fRec.fForegroundColor, canvas);
789 }
790 };
793 return sk_sp<SkDrawable>(new ColrGlyphDrawable(this, glyph));
794 }
795 return nullptr;
796 }
797
798 void generateFontMetrics(SkFontMetrics* out_metrics) override {
800 SkMatrix remainingMatrix;
803 fontations_ffi::Metrics metrics =
804 fontations_ffi::get_skia_metrics(fBridgeFontRef, scale.fY, fBridgeNormalizedCoords);
805 out_metrics->fTop = -metrics.top;
806 out_metrics->fAscent = -metrics.ascent;
807 out_metrics->fDescent = -metrics.descent;
808 out_metrics->fBottom = -metrics.bottom;
809 out_metrics->fLeading = metrics.leading;
810 out_metrics->fAvgCharWidth = metrics.avg_char_width;
811 out_metrics->fMaxCharWidth = metrics.max_char_width;
812 out_metrics->fXMin = metrics.x_min;
813 out_metrics->fXMax = metrics.x_max;
814 out_metrics->fXHeight = -metrics.x_height;
815 out_metrics->fCapHeight = -metrics.cap_height;
816 out_metrics->fFlags = 0;
817 if (fontations_ffi::table_data(fBridgeFontRef,
818 SkSetFourByteTag('f', 'v', 'a', 'r'),
819 0,
820 rust::Slice<uint8_t>())) {
822 }
823 auto setMetric = [](float& dstMetric, const float srcMetric,
825 {
826 if (std::isnan(srcMetric)) {
827 dstMetric = 0;
828 } else {
829 dstMetric = srcMetric;
830 flags |= flag;
831 }
832 };
833 setMetric(out_metrics->fUnderlinePosition, -metrics.underline_position,
835 setMetric(out_metrics->fUnderlineThickness, metrics.underline_thickness,
837
838 setMetric(out_metrics->fStrikeoutPosition, -metrics.strikeout_position,
840 setMetric(out_metrics->fStrikeoutThickness, metrics.strikeout_thickness,
842 }
843
844private:
845 SkMatrix fMatrix;
846 sk_sp<SkData> fFontData = nullptr;
847 const fontations_ffi::BridgeFontRef& fBridgeFontRef;
848 const fontations_ffi::BridgeNormalizedCoords& fBridgeNormalizedCoords;
849 const fontations_ffi::BridgeOutlineCollection& fOutlines;
850 const SkSpan<const SkColor> fPalette;
851 rust::Box<fontations_ffi::BridgeHintingInstance> fHintingInstance;
852 bool fDoLinearMetrics = false;
853
855};
856
857std::unique_ptr<SkStreamAsset> SkTypeface_Fontations::onOpenStream(int* ttcIndex) const {
858 *ttcIndex = fTtcIndex;
859 return std::make_unique<SkMemoryStream>(fFontData);
860}
861
863 // Matching DWrite implementation, return self if ttc index mismatches.
864 if (fTtcIndex != SkTo<uint32_t>(args.getCollectionIndex())) {
865 return sk_ref_sp(this);
866 }
867
868 int numAxes = onGetVariationDesignPosition(nullptr, 0);
869 auto fusedDesignPosition =
870 std::make_unique<SkFontArguments::VariationPosition::Coordinate[]>(numAxes);
871 int retrievedAxes = onGetVariationDesignPosition(fusedDesignPosition.get(), numAxes);
872 if (numAxes != retrievedAxes) {
873 return nullptr;
874 }
875
876 // We know the internally retrieved axes are normalized, contain a value for every possible
877 // axis, other axes do not exist, so we only need to override any of those.
878 for (int i = 0; i < numAxes; ++i) {
879 const SkFontArguments::VariationPosition& argPosition = args.getVariationDesignPosition();
880 for (int j = 0; j < argPosition.coordinateCount; ++j) {
881 if (fusedDesignPosition[i].axis == argPosition.coordinates[j].axis) {
882 fusedDesignPosition[i].value = argPosition.coordinates[j].value;
883 }
884 }
885 }
886
887 SkFontArguments fusedArgs;
888 fusedArgs.setVariationDesignPosition({fusedDesignPosition.get(), SkToInt(numAxes)});
889 fusedArgs.setPalette(args.getPalette());
890
891 rust::cxxbridge1::Box<fontations_ffi::BridgeNormalizedCoords> normalized_args =
892 make_normalized_coords(*fBridgeFontRef, fusedArgs.getVariationDesignPosition());
893
894 if (!fontations_ffi::normalized_coords_equal(*normalized_args, *fBridgeNormalizedCoords)) {
895 return MakeFromData(fFontData, fusedArgs);
896 }
897
898 // TODO(crbug.com/skia/330149870): Palette differences are not fused, see DWrite backend impl.
899 rust::Slice<const fontations_ffi::PaletteOverride> argPaletteOverrides(
900 reinterpret_cast<const fontations_ffi::PaletteOverride*>(args.getPalette().overrides),
901 args.getPalette().overrideCount);
902 rust::Vec<uint32_t> newPalette =
903 resolve_palette(*fBridgeFontRef, args.getPalette().index, argPaletteOverrides);
904
905 if (fPalette.size() != newPalette.size() ||
906 memcmp(fPalette.data(), newPalette.data(), fPalette.size() * sizeof(fPalette[0]))) {
907 return MakeFromData(fFontData, fusedArgs);
908 }
909
910 return sk_ref_sp(this);
911}
912
913std::unique_ptr<SkScalerContext> SkTypeface_Fontations::onCreateScalerContext(
914 const SkScalerContextEffects& effects, const SkDescriptor* desc) const {
915 return std::make_unique<SkFontationsScalerContext>(
916 sk_ref_sp(const_cast<SkTypeface_Fontations*>(this)), effects, desc);
917}
918
919std::unique_ptr<SkAdvancedTypefaceMetrics> SkTypeface_Fontations::onGetAdvancedMetrics() const {
920 std::unique_ptr<SkAdvancedTypefaceMetrics> info(new SkAdvancedTypefaceMetrics);
921
922 if (!fontations_ffi::is_embeddable(*fBridgeFontRef)) {
924 }
925
926 if (!fontations_ffi::is_subsettable(*fBridgeFontRef)) {
928 }
929
930 if (fontations_ffi::table_data(
931 *fBridgeFontRef, SkSetFourByteTag('f', 'v', 'a', 'r'), 0, rust::Slice<uint8_t>())) {
933 }
934
935 // Metrics information.
936 fontations_ffi::Metrics metrics =
937 fontations_ffi::get_unscaled_metrics(*fBridgeFontRef, *fBridgeNormalizedCoords);
938 info->fAscent = metrics.ascent;
939 info->fDescent = metrics.descent;
940 info->fCapHeight = metrics.cap_height;
941
942 info->fBBox = SkIRect::MakeLTRB((int32_t)metrics.x_min,
943 (int32_t)metrics.top,
944 (int32_t)metrics.x_max,
945 (int32_t)metrics.bottom);
946
947 // Style information.
948 if (fontations_ffi::is_fixed_pitch(*fBridgeFontRef)) {
950 }
951
952 fontations_ffi::BridgeFontStyle fontStyle;
953 if (fontations_ffi::get_font_style(*fBridgeFontRef, *fBridgeNormalizedCoords, fontStyle)) {
954 if (fontStyle.slant == SkFontStyle::Slant::kItalic_Slant) {
956 }
957 }
958
959 if (fontations_ffi::is_serif_style(*fBridgeFontRef)) {
961 } else if (fontations_ffi::is_script_style(*fBridgeFontRef)) {
963 }
964
965 info->fItalicAngle = fontations_ffi::italic_angle(*fBridgeFontRef);
966
967 return info;
968}
969
971 SkString familyName;
972 onGetFamilyName(&familyName);
973 desc->setFamilyName(familyName.c_str());
974 desc->setStyle(this->fontStyle());
975 desc->setFactoryId(FactoryId);
976
977 // TODO: keep the index to emit here
978 desc->setPaletteIndex(0);
980 // TODO: omit override when palette[n] == CPAL[paletteIndex][n]
981 size_t paletteOverrideCount = palette.size();
982 auto overrides = desc->setPaletteEntryOverrides(paletteOverrideCount);
983 for (size_t i = 0; i < paletteOverrideCount; ++i) {
984 overrides[i] = {(uint16_t)i, palette[i]};
985 }
986
987 *serialize = true;
988}
989
991 size_t offset,
992 size_t length,
993 void* data) const {
994 rust::Slice<uint8_t> dataSlice;
995 if (data) {
996 dataSlice = rust::Slice<uint8_t>(reinterpret_cast<uint8_t*>(data), length);
997 }
998 size_t copied = fontations_ffi::table_data(*fBridgeFontRef, tag, offset, dataSlice);
999 // If data is nullptr, the Rust side doesn't see a length limit.
1000 return std::min(copied, length);
1001}
1002
1004 uint16_t numTables = fontations_ffi::table_tags(*fBridgeFontRef, rust::Slice<uint32_t>());
1005 if (!tags) {
1006 return numTables;
1007 }
1008 rust::Slice<uint32_t> copyToTags(tags, numTables);
1009 return fontations_ffi::table_tags(*fBridgeFontRef, copyToTags);
1010}
1011
1013 SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const {
1014 rust::Slice<fontations_ffi::SkiaDesignCoordinate> copyToCoordinates;
1015 if (coordinates) {
1016 copyToCoordinates = rust::Slice<fontations_ffi::SkiaDesignCoordinate>(
1017 reinterpret_cast<fontations_ffi::SkiaDesignCoordinate*>(coordinates),
1018 coordinateCount);
1019 }
1020 return fontations_ffi::variation_position(*fBridgeNormalizedCoords, copyToCoordinates);
1021}
1022
1024 SkFontParameters::Variation::Axis parameters[], int parameterCount) const {
1025 sk_fontations::AxisWrapper axisWrapper(parameters, parameterCount);
1026 return fontations_ffi::populate_axes(*fBridgeFontRef, axisWrapper);
1027}
1028
1029namespace sk_fontations {
1030
1031namespace {
1032
1033const uint16_t kForegroundColorPaletteIndex = 0xFFFF;
1034
1035void populateStopsAndColors(std::vector<SkScalar>& dest_stops,
1036 std::vector<SkColor4f>& dest_colors,
1037 const SkSpan<const SkColor>& palette,
1038 SkColor foregroundColor,
1039 fontations_ffi::BridgeColorStops& color_stops) {
1040 SkASSERT(dest_stops.size() == 0);
1041 SkASSERT(dest_colors.size() == 0);
1042 size_t num_color_stops = fontations_ffi::num_color_stops(color_stops);
1043 dest_stops.reserve(num_color_stops);
1044 dest_colors.reserve(num_color_stops);
1045
1046 fontations_ffi::ColorStop color_stop;
1047 while (fontations_ffi::next_color_stop(color_stops, color_stop)) {
1048 dest_stops.push_back(color_stop.stop);
1049 SkColor4f dest_color;
1050 if (color_stop.palette_index == kForegroundColorPaletteIndex) {
1051 dest_color = SkColor4f::FromColor(foregroundColor);
1052 } else {
1053 dest_color = SkColor4f::FromColor(palette[color_stop.palette_index]);
1054 }
1055 dest_color.fA *= color_stop.alpha;
1056 dest_colors.push_back(dest_color);
1057 }
1058}
1059
1060SkColor4f lerpSkColor(SkColor4f c0, SkColor4f c1, float t) {
1061 // Due to the floating point calculation in the caller, when interpolating between very
1062 // narrow stops, we may get values outside the interpolation range, guard against these.
1063 if (t < 0) {
1064 return c0;
1065 }
1066 if (t > 1) {
1067 return c1;
1068 }
1069
1070 const auto c0_4f = skvx::float4::Load(c0.vec());
1071 const auto c1_4f = skvx::float4::Load(c1.vec());
1072 const auto c_4f = c0_4f + (c1_4f - c0_4f) * t;
1073
1074 SkColor4f l;
1075 c_4f.store(l.vec());
1076 return l;
1077}
1078
1079enum TruncateStops { TruncateStart, TruncateEnd };
1080
1081// Truncate a vector of color stops at a previously computed stop position and insert at that
1082// position the color interpolated between the surrounding stops.
1083void truncateToStopInterpolating(SkScalar zeroRadiusStop,
1084 std::vector<SkColor4f>& colors,
1085 std::vector<SkScalar>& stops,
1086 TruncateStops truncateStops) {
1087 if (stops.size() <= 1u || zeroRadiusStop < stops.front() || stops.back() < zeroRadiusStop) {
1088 return;
1089 }
1090
1091 size_t afterIndex =
1092 (truncateStops == TruncateStart)
1093 ? std::lower_bound(stops.begin(), stops.end(), zeroRadiusStop) - stops.begin()
1094 : std::upper_bound(stops.begin(), stops.end(), zeroRadiusStop) - stops.begin();
1095
1096 const float t =
1097 (zeroRadiusStop - stops[afterIndex - 1]) / (stops[afterIndex] - stops[afterIndex - 1]);
1098 SkColor4f lerpColor = lerpSkColor(colors[afterIndex - 1], colors[afterIndex], t);
1099
1100 if (truncateStops == TruncateStart) {
1101 stops.erase(stops.begin(), stops.begin() + afterIndex);
1102 colors.erase(colors.begin(), colors.begin() + afterIndex);
1103 stops.insert(stops.begin(), 0);
1104 colors.insert(colors.begin(), lerpColor);
1105 } else {
1106 stops.erase(stops.begin() + afterIndex, stops.end());
1107 colors.erase(colors.begin() + afterIndex, colors.end());
1108 stops.insert(stops.end(), 1);
1109 colors.insert(colors.end(), lerpColor);
1110 }
1111}
1112
1113// https://learn.microsoft.com/en-us/typography/opentype/spec/colr#format-32-paintcomposite
1114inline SkBlendMode ToSkBlendMode(uint16_t colrV1CompositeMode) {
1115 switch (colrV1CompositeMode) {
1116 case 0:
1117 return SkBlendMode::kClear;
1118 case 1:
1119 return SkBlendMode::kSrc;
1120 case 2:
1121 return SkBlendMode::kDst;
1122 case 3:
1123 return SkBlendMode::kSrcOver;
1124 case 4:
1125 return SkBlendMode::kDstOver;
1126 case 5:
1127 return SkBlendMode::kSrcIn;
1128 case 6:
1129 return SkBlendMode::kDstIn;
1130 case 7:
1131 return SkBlendMode::kSrcOut;
1132 case 8:
1133 return SkBlendMode::kDstOut;
1134 case 9:
1135 return SkBlendMode::kSrcATop;
1136 case 10:
1137 return SkBlendMode::kDstATop;
1138 case 11:
1139 return SkBlendMode::kXor;
1140 case 12:
1141 return SkBlendMode::kPlus;
1142 case 13:
1143 return SkBlendMode::kScreen;
1144 case 14:
1145 return SkBlendMode::kOverlay;
1146 case 15:
1147 return SkBlendMode::kDarken;
1148 case 16:
1149 return SkBlendMode::kLighten;
1150 case 17:
1152 case 18:
1154 case 19:
1156 case 20:
1158 case 21:
1160 case 22:
1162 case 23:
1164 case 24:
1165 return SkBlendMode::kHue;
1166 case 25:
1168 case 26:
1169 return SkBlendMode::kColor;
1170 case 27:
1172 default:
1173 return SkBlendMode::kDst;
1174 }
1175}
1176
1177inline SkTileMode ToSkTileMode(uint8_t extendMode) {
1178 switch (extendMode) {
1179 case 1:
1180 return SkTileMode::kRepeat;
1181 case 2:
1182 return SkTileMode::kMirror;
1183 default:
1184 return SkTileMode::kClamp;
1185 }
1186}
1187} // namespace
1188
1190 SkCanvas& canvas,
1191 SkSpan<const SkColor> palette,
1192 SkColor foregroundColor,
1193 bool antialias,
1194 uint16_t upem)
1195 : fScalerContext(scaler_context)
1196 , fCanvas(canvas)
1197 , fPalette(palette)
1198 , fForegroundColor(foregroundColor)
1199 , fAntialias(antialias)
1200 , fUpem(upem) {}
1201
1203 fCanvas.save();
1204 fCanvas.concat(SkMatrixFromFontationsTransform(transform_arg));
1205}
1206
1208
1209void ColorPainter::push_clip_glyph(uint16_t glyph_id) {
1210 fCanvas.save();
1211 SkPath path;
1212 fScalerContext.generateYScalePathForGlyphId(glyph_id, &path, fUpem, *fontations_ffi::no_hinting_instance());
1213 fCanvas.clipPath(path, fAntialias);
1214}
1215
1216void ColorPainter::push_clip_rectangle(float x_min, float y_min, float x_max, float y_max) {
1217 fCanvas.save();
1218 SkRect clipRect = SkRect::MakeLTRB(x_min, -y_min, x_max, -y_max);
1219 fCanvas.clipRect(clipRect, fAntialias);
1220}
1221
1222void ColorPainter::pop_clip() { fCanvas.restore(); }
1223
1224void ColorPainter::configure_solid_paint(uint16_t palette_index, float alpha, SkPaint& paint) {
1225 paint.setAntiAlias(fAntialias);
1227 if (palette_index == kForegroundColorPaletteIndex) {
1228 color = SkColor4f::FromColor(fForegroundColor);
1229 } else {
1230 color = SkColor4f::FromColor(fPalette[palette_index]);
1231 }
1232 color.fA *= alpha;
1233 paint.setShader(nullptr);
1234 paint.setColor(color);
1235}
1236
1237void ColorPainter::fill_solid(uint16_t palette_index, float alpha) {
1238 SkPaint paint;
1239 configure_solid_paint(palette_index, alpha, paint);
1240 fCanvas.drawPaint(paint);
1241}
1242
1243void ColorPainter::fill_glyph_solid(uint16_t glyph_id, uint16_t palette_index, float alpha) {
1244 SkPath path;
1245 fScalerContext.generateYScalePathForGlyphId(glyph_id, &path, fUpem, *fontations_ffi::no_hinting_instance());
1246
1247 SkPaint paint;
1248 configure_solid_paint(palette_index, alpha, paint);
1249 fCanvas.drawPath(path, paint);
1250}
1251
1252void ColorPainter::configure_linear_paint(const fontations_ffi::FillLinearParams& linear_params,
1253 fontations_ffi::BridgeColorStops& bridge_stops,
1254 uint8_t extend_mode,
1255 SkPaint& paint,
1256 SkMatrix* paintTransform) {
1257 paint.setAntiAlias(fAntialias);
1258
1259 std::vector<SkScalar> stops;
1260 std::vector<SkColor4f> colors;
1261
1262 populateStopsAndColors(stops, colors, fPalette, fForegroundColor, bridge_stops);
1263
1264 if (stops.size() == 1) {
1265 paint.setColor(colors[0]);
1266 return;
1267 }
1268
1269 SkPoint linePositions[2] = {
1270 SkPoint::Make(SkFloatToScalar(linear_params.x0), -SkFloatToScalar(linear_params.y0)),
1271 SkPoint::Make(SkFloatToScalar(linear_params.x1), -SkFloatToScalar(linear_params.y1))};
1272 SkTileMode tileMode = ToSkTileMode(extend_mode);
1273
1275 linePositions,
1276 colors.data(),
1278 stops.data(),
1279 stops.size(),
1280 tileMode,
1281 SkGradientShader::Interpolation{SkGradientShader::Interpolation::InPremul::kNo,
1282 SkGradientShader::Interpolation::ColorSpace::kSRGB,
1283 SkGradientShader::Interpolation::HueMethod::kShorter},
1284 paintTransform));
1285
1286 SkASSERT(shader);
1287 // An opaque color is needed to ensure the gradient is not modulated by alpha.
1288 paint.setColor(SK_ColorBLACK);
1289 paint.setShader(shader);
1290}
1291
1292void ColorPainter::fill_linear(const fontations_ffi::FillLinearParams& linear_params,
1293 fontations_ffi::BridgeColorStops& bridge_stops,
1294 uint8_t extend_mode) {
1295 SkPaint paint;
1296
1297 configure_linear_paint(linear_params, bridge_stops, extend_mode, paint);
1298
1299 fCanvas.drawPaint(paint);
1300}
1301
1302void ColorPainter::fill_glyph_linear(uint16_t glyph_id,
1304 const fontations_ffi::FillLinearParams& linear_params,
1305 fontations_ffi::BridgeColorStops& bridge_stops,
1306 uint8_t extend_mode) {
1307 SkPath path;
1308 fScalerContext.generateYScalePathForGlyphId(glyph_id, &path, fUpem, *fontations_ffi::no_hinting_instance());
1309
1310 SkPaint paint;
1311 SkMatrix paintTransform = SkMatrixFromFontationsTransform(transform);
1312 configure_linear_paint(linear_params, bridge_stops, extend_mode, paint, &paintTransform);
1313 fCanvas.drawPath(path, paint);
1314}
1315
1316void ColorPainter::configure_radial_paint(
1317 const fontations_ffi::FillRadialParams& fill_radial_params,
1318 fontations_ffi::BridgeColorStops& bridge_stops,
1319 uint8_t extend_mode,
1320 SkPaint& paint,
1321 SkMatrix* paintTransform) {
1322 paint.setAntiAlias(fAntialias);
1323
1324 SkPoint start = SkPoint::Make(fill_radial_params.x0, -fill_radial_params.y0);
1325 SkPoint end = SkPoint::Make(fill_radial_params.x1, -fill_radial_params.y1);
1326
1327 float startRadius = fill_radial_params.r0;
1328 float endRadius = fill_radial_params.r1;
1329
1330 std::vector<SkScalar> stops;
1331 std::vector<SkColor4f> colors;
1332
1333 populateStopsAndColors(stops, colors, fPalette, fForegroundColor, bridge_stops);
1334
1335 // Draw single color if there's only one stop.
1336 if (stops.size() == 1) {
1337 paint.setColor(colors[0]);
1338 fCanvas.drawPaint(paint);
1339 return;
1340 }
1341
1342 SkTileMode tileMode = ToSkTileMode(extend_mode);
1343
1344 // For negative radii, interpolation is needed to prepare parameters suitable
1345 // for invoking the shader. Implementation below as resolution discussed in
1346 // https://github.com/googlefonts/colr-gradients-spec/issues/367.
1347 // Truncate to manually interpolated color for tile mode clamp, otherwise
1348 // calculate positive projected circles.
1349 if (startRadius < 0 || endRadius < 0) {
1350 if (startRadius == endRadius && startRadius < 0) {
1351 paint.setColor(SK_ColorTRANSPARENT);
1352 // return true;
1353 return;
1354 }
1355
1356 if (tileMode == SkTileMode::kClamp) {
1357 SkVector startToEnd = end - start;
1358 SkScalar radiusDiff = endRadius - startRadius;
1359 SkScalar zeroRadiusStop = 0.f;
1360 TruncateStops truncateSide = TruncateStart;
1361 if (startRadius < 0) {
1362 truncateSide = TruncateStart;
1363
1364 // Compute color stop position where radius is = 0. After the scaling
1365 // of stop positions to the normal 0,1 range that we have done above,
1366 // the size of the radius as a function of the color stops is: r(x) = r0
1367 // + x*(r1-r0) Solving this function for r(x) = 0, we get: x = -r0 /
1368 // (r1-r0)
1369 zeroRadiusStop = -startRadius / (endRadius - startRadius);
1370 startRadius = 0.f;
1371 SkVector startEndDiff = end - start;
1372 startEndDiff.scale(zeroRadiusStop);
1373 start = start + startEndDiff;
1374 }
1375
1376 if (endRadius < 0) {
1377 truncateSide = TruncateEnd;
1378 zeroRadiusStop = -startRadius / (endRadius - startRadius);
1379 endRadius = 0.f;
1380 SkVector startEndDiff = end - start;
1381 startEndDiff.scale(1 - zeroRadiusStop);
1382 end = end - startEndDiff;
1383 }
1384
1385 if (!(startRadius == 0 && endRadius == 0)) {
1386 truncateToStopInterpolating(zeroRadiusStop, colors, stops, truncateSide);
1387 } else {
1388 // If both radii have become negative and where clamped to 0, we need to
1389 // produce a single color cone, otherwise the shader colors the whole
1390 // plane in a single color when two radii are specified as 0.
1391 if (radiusDiff > 0) {
1392 end = start + startToEnd;
1393 endRadius = radiusDiff;
1394 colors.erase(colors.begin(), colors.end() - 1);
1395 stops.erase(stops.begin(), stops.end() - 1);
1396 } else {
1397 start -= startToEnd;
1398 startRadius = -radiusDiff;
1399 colors.erase(colors.begin() + 1, colors.end());
1400 stops.erase(stops.begin() + 1, stops.end());
1401 }
1402 }
1403 } else {
1404 if (startRadius < 0 || endRadius < 0) {
1405 auto roundIntegerMultiple = [](SkScalar factorZeroCrossing, SkTileMode tileMode) {
1406 int roundedMultiple = factorZeroCrossing > 0 ? ceilf(factorZeroCrossing)
1407 : floorf(factorZeroCrossing) - 1;
1408 if (tileMode == SkTileMode::kMirror && roundedMultiple % 2 != 0) {
1409 roundedMultiple += roundedMultiple < 0 ? -1 : 1;
1410 }
1411 return roundedMultiple;
1412 };
1413
1414 SkVector startToEnd = end - start;
1415 SkScalar radiusDiff = endRadius - startRadius;
1416 SkScalar factorZeroCrossing = (startRadius / (startRadius - endRadius));
1417 bool inRange = 0.f <= factorZeroCrossing && factorZeroCrossing <= 1.0f;
1418 SkScalar direction = inRange && radiusDiff < 0 ? -1.0f : 1.0f;
1419 SkScalar circleProjectionFactor =
1420 roundIntegerMultiple(factorZeroCrossing * direction, tileMode);
1421 startToEnd.scale(circleProjectionFactor);
1422 startRadius += circleProjectionFactor * radiusDiff;
1423 endRadius += circleProjectionFactor * radiusDiff;
1424 start += startToEnd;
1425 end += startToEnd;
1426 }
1427 }
1428 }
1429
1430 // An opaque color is needed to ensure the gradient is not modulated by alpha.
1431 paint.setColor(SK_ColorBLACK);
1432
1434 start,
1435 startRadius,
1436 end,
1437 endRadius,
1438 colors.data(),
1440 stops.data(),
1441 stops.size(),
1442 tileMode,
1443 SkGradientShader::Interpolation{SkGradientShader::Interpolation::InPremul::kNo,
1444 SkGradientShader::Interpolation::ColorSpace::kSRGB,
1445 SkGradientShader::Interpolation::HueMethod::kShorter},
1446 paintTransform));
1447}
1448
1449void ColorPainter::fill_radial(const fontations_ffi::FillRadialParams& fill_radial_params,
1450 fontations_ffi::BridgeColorStops& bridge_stops,
1451 uint8_t extend_mode) {
1452 SkPaint paint;
1453
1454 configure_radial_paint(fill_radial_params, bridge_stops, extend_mode, paint);
1455
1456 fCanvas.drawPaint(paint);
1457}
1458
1459void ColorPainter::fill_glyph_radial(uint16_t glyph_id,
1461 const fontations_ffi::FillRadialParams& fill_radial_params,
1462 fontations_ffi::BridgeColorStops& bridge_stops,
1463 uint8_t extend_mode) {
1464 SkPath path;
1465 fScalerContext.generateYScalePathForGlyphId(glyph_id, &path, fUpem, *fontations_ffi::no_hinting_instance());
1466
1467 SkPaint paint;
1468 SkMatrix paintTransform = SkMatrixFromFontationsTransform(transform);
1469 configure_radial_paint(fill_radial_params, bridge_stops, extend_mode, paint, &paintTransform);
1470 fCanvas.drawPath(path, paint);
1471}
1472
1473void ColorPainter::configure_sweep_paint(const fontations_ffi::FillSweepParams& sweep_params,
1474 fontations_ffi::BridgeColorStops& bridge_stops,
1475 uint8_t extend_mode,
1476 SkPaint& paint,
1477 SkMatrix* paintTransform) {
1478 paint.setAntiAlias(fAntialias);
1479
1480 SkPoint center = SkPoint::Make(sweep_params.x0, -sweep_params.y0);
1481
1482 std::vector<SkScalar> stops;
1483 std::vector<SkColor4f> colors;
1484
1485 populateStopsAndColors(stops, colors, fPalette, fForegroundColor, bridge_stops);
1486
1487 if (stops.size() == 1) {
1488 paint.setColor(colors[0]);
1489 fCanvas.drawPaint(paint);
1490 return;
1491 }
1492
1493 // An opaque color is needed to ensure the gradient is not modulated by alpha.
1494 paint.setColor(SK_ColorBLACK);
1495 SkTileMode tileMode = ToSkTileMode(extend_mode);
1496
1497 paint.setColor(SK_ColorBLACK);
1499 center.x(),
1500 center.y(),
1501 colors.data(),
1503 stops.data(),
1504 stops.size(),
1505 tileMode,
1506 sweep_params.start_angle,
1507 sweep_params.end_angle,
1508 SkGradientShader::Interpolation{SkGradientShader::Interpolation::InPremul::kNo,
1509 SkGradientShader::Interpolation::ColorSpace::kSRGB,
1510 SkGradientShader::Interpolation::HueMethod::kShorter},
1511 paintTransform));
1512}
1513
1514void ColorPainter::fill_sweep(const fontations_ffi::FillSweepParams& sweep_params,
1515 fontations_ffi::BridgeColorStops& bridge_stops,
1516 uint8_t extend_mode) {
1517 SkPaint paint;
1518
1519 configure_sweep_paint(sweep_params, bridge_stops, extend_mode, paint);
1520
1521 fCanvas.drawPaint(paint);
1522}
1523
1524void ColorPainter::fill_glyph_sweep(uint16_t glyph_id,
1526 const fontations_ffi::FillSweepParams& sweep_params,
1527 fontations_ffi::BridgeColorStops& bridge_stops,
1528 uint8_t extend_mode) {
1529 SkPath path;
1530 fScalerContext.generateYScalePathForGlyphId(glyph_id, &path, fUpem, *fontations_ffi::no_hinting_instance());
1531
1532 SkPaint paint;
1533 SkMatrix paintTransform = SkMatrixFromFontationsTransform(transform);
1534 configure_sweep_paint(sweep_params, bridge_stops, extend_mode, paint, &paintTransform);
1535 fCanvas.drawPath(path, paint);
1536}
1537
1538void ColorPainter::push_layer(uint8_t compositeMode) {
1539 SkPaint paint;
1540 paint.setBlendMode(ToSkBlendMode(compositeMode));
1541 fCanvas.saveLayer(nullptr, &paint);
1542}
1543
1545
1547 SkMatrix initialTransfom,
1548 uint16_t upem)
1549 : fScalerContext(scaler_context)
1550 , fCurrentTransform(initialTransfom)
1551 , fUpem(upem)
1552 , fBounds(SkRect::MakeEmpty()) {}
1553
1555
1556// fontations_ffi::ColorPainter interface.
1558 SkMatrix transform = SkMatrix::MakeAll(transform_arg.xx,
1559 -transform_arg.xy,
1560 transform_arg.dx,
1561 -transform_arg.yx,
1562 transform_arg.yy,
1563 -transform_arg.dy,
1564 0.f,
1565 0.f,
1566 1.0f);
1567 fCurrentTransform.preConcat(transform);
1568 bool invertResult = transform.invert(&fStackTopTransformInverse);
1569 SkASSERT(invertResult);
1570}
1572 fCurrentTransform.preConcat(fStackTopTransformInverse);
1573 fStackTopTransformInverse = SkMatrix();
1574}
1575
1576void BoundsPainter::push_clip_glyph(uint16_t glyph_id) {
1577 SkPath path;
1578 fScalerContext.generateYScalePathForGlyphId(glyph_id, &path, fUpem, *fontations_ffi::no_hinting_instance());
1579 path.transform(fCurrentTransform);
1580 fBounds.join(path.getBounds());
1581}
1582
1583void BoundsPainter::push_clip_rectangle(float x_min, float y_min, float x_max, float y_max) {
1584 SkRect clipRect = SkRect::MakeLTRB(x_min, -y_min, x_max, -y_max);
1585 SkPath rectPath = SkPath::Rect(clipRect);
1586 rectPath.transform(fCurrentTransform);
1587 fBounds.join(rectPath.getBounds());
1588}
1589
1590void BoundsPainter::fill_glyph_solid(uint16_t glyph_id, uint16_t, float) {
1591 push_clip_glyph(glyph_id);
1592 pop_clip();
1593}
1594
1597 const fontations_ffi::FillRadialParams&,
1598 fontations_ffi::BridgeColorStops&,
1599 uint8_t) {
1600 push_clip_glyph(glyph_id);
1601 pop_clip();
1602}
1605 const fontations_ffi::FillLinearParams&,
1606 fontations_ffi::BridgeColorStops&,
1607 uint8_t) {
1608 push_clip_glyph(glyph_id);
1609 pop_clip();
1610}
1611
1612void BoundsPainter::fill_glyph_sweep(uint16_t glyph_id,
1614 const fontations_ffi::FillSweepParams&,
1615 fontations_ffi::BridgeColorStops&,
1616 uint8_t) {
1617 push_clip_glyph(glyph_id);
1618 pop_clip();
1619}
1620
1621} // namespace sk_fontations
SkPath fPath
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
sk_bzero(glyphs, sizeof(glyphs))
uint16_t glyphs[5]
Definition: FontMgrTest.cpp:46
int count
Definition: FontMgrTest.cpp:50
const SkRect fBounds
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
#define SK_ABORT(message,...)
Definition: SkAssert.h:70
#define SkASSERT_RELEASE(cond)
Definition: SkAssert.h:100
#define SkASSERT(cond)
Definition: SkAssert.h:116
SkBlendMode
Definition: SkBlendMode.h:38
@ kSrcOut
r = s * (1-da)
@ 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
@ kPlus
r = min(s + d, 1)
@ kLighten
rc = s + d - min(s*da, d*sa), ra = kSrcOver
@ kHue
hue of source with saturation and luminosity of destination
@ kDstIn
r = d * sa
@ kMultiply
r = s*(1-da) + d*(1-sa) + s*d
@ kColorDodge
brighten destination to reflect source
@ kScreen
r = s + d - s*d
@ 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
@ kDstOut
r = d * (1-sa)
@ kDarken
rc = s + d - max(s*da, d*sa), ra = kSrcOver
@ kSrcIn
r = s * da
@ kClear
r = 0
uint32_t SkColor
Definition: SkColor.h:37
constexpr SkColor SK_ColorTRANSPARENT
Definition: SkColor.h:99
constexpr SkColor SK_ColorRED
Definition: SkColor.h:126
constexpr SkColor SK_ColorBLACK
Definition: SkColor.h:103
#define SkFixedToScalar(x)
Definition: SkFixed.h:124
static bool SkIsFinite(T x, Pack... values)
static bool isLCD(const SkScalerContextRec &rec)
static bool bothZero(SkScalar a, SkScalar b)
static bool isAxisAligned(const SkScalerContextRec &rec)
SkFontHinting
Definition: SkFontTypes.h:18
@ kNormal
glyph outlines modified to improve constrast
@ kNone
glyph outlines unchanged
@ kSlight
minimal modification to improve constrast
@ kFull
modifies glyph outlines for maximum constrast
sk_sp< T > sk_ref_sp(T *obj)
Definition: SkRefCnt.h:381
#define SkFloatToScalar(x)
Definition: SkScalar.h:62
SkTileMode
Definition: SkTileMode.h:13
constexpr size_t SkToSizeT(S x)
Definition: SkTo.h:31
constexpr int SkToInt(S x)
Definition: SkTo.h:29
static constexpr bool SkToBool(const T &x)
Definition: SkTo.h:35
uint32_t SkFontTableTag
Definition: SkTypeface.h:41
sk_sp< SkTypeface > SkTypeface_Make_Fontations(std::unique_ptr< SkStreamAsset > fontData, const SkFontArguments &args)
int32_t SkUnichar
Definition: SkTypes.h:175
uint16_t SkGlyphID
Definition: SkTypes.h:179
uint32_t SkFourByteTag
Definition: SkTypes.h:166
static constexpr SkFourByteTag SkSetFourByteTag(char a, char b, char c, char d)
Definition: SkTypes.h:167
static SkPath get_path()
Definition: bug12866.cpp:14
void setPixels(void *pixels)
Definition: SkBitmap.cpp:207
bool setInfo(const SkImageInfo &imageInfo, size_t rowBytes=0)
Definition: SkBitmap.cpp:114
int saveLayer(const SkRect *bounds, const SkPaint *paint)
Definition: SkCanvas.cpp:496
void drawRect(const SkRect &rect, const SkPaint &paint)
Definition: SkCanvas.cpp:1673
void clipRect(const SkRect &rect, SkClipOp op, bool doAntiAlias)
Definition: SkCanvas.cpp:1361
void restore()
Definition: SkCanvas.cpp:461
void translate(SkScalar dx, SkScalar dy)
Definition: SkCanvas.cpp:1278
void drawPaint(const SkPaint &paint)
Definition: SkCanvas.cpp:1668
void clear(SkColor color)
Definition: SkCanvas.h:1199
void clipPath(const SkPath &path, SkClipOp op, bool doAntiAlias)
Definition: SkCanvas.cpp:1456
int save()
Definition: SkCanvas.cpp:447
void drawPath(const SkPath &path, const SkPaint &paint)
Definition: SkCanvas.cpp:1747
void scale(SkScalar sx, SkScalar sy)
Definition: SkCanvas.cpp:1289
void concat(const SkMatrix &matrix)
Definition: SkCanvas.cpp:1318
void drawImage(const SkImage *image, SkScalar left, SkScalar top)
Definition: SkCanvas.h:1528
static sk_sp< SkColorSpace > MakeSRGB()
static sk_sp< SkData > MakeWithoutCopy(const void *data, size_t length)
Definition: SkData.h:116
const uint8_t * bytes() const
Definition: SkData.h:43
static sk_sp< SkData > MakeFromStream(SkStream *, size_t size)
Definition: SkData.cpp:208
size_t size() const
Definition: SkData.h:30
void setFactoryId(SkTypeface::FactoryId factoryId)
Slant slant() const
Definition: SkFontStyle.h:64
int width() const
Definition: SkFontStyle.h:63
int weight() const
Definition: SkFontStyle.h:62
sk_sp< SkDrawable > generateDrawable(const SkGlyph &glyph) override
void generateImage(const SkGlyph &glyph, void *imageBuffer) override
bool drawCOLRGlyph(const SkGlyph &glyph, SkColor foregroundColor, SkCanvas *canvas)
void generatePngImage(const SkGlyph &glyph, void *imageBuffer)
SkFontationsScalerContext(sk_sp< SkTypeface_Fontations > face, const SkScalerContextEffects &effects, const SkDescriptor *desc)
void generateFontMetrics(SkFontMetrics *out_metrics) override
bool generateYScalePathForGlyphId(uint16_t glyphId, SkPath *path, float yScale, const fontations_ffi::BridgeHintingInstance &hintingInstance)
GlyphMetrics generateMetrics(const SkGlyph &glyph, SkArenaAlloc *) override
bool generatePath(const SkGlyph &glyph, SkPath *path) override
int top() const
Definition: SkGlyph.h:511
size_t rowBytes() const
Definition: SkGlyph.cpp:233
uint16_t extraBits() const
Definition: SkGlyph.h:519
SkGlyphID getGlyphID() const
Definition: SkGlyph.h:429
const SkPath * path() const
Definition: SkGlyph.cpp:284
SkMask::Format maskFormat() const
Definition: SkGlyph.h:500
SkRect rect() const
Definition: SkGlyph.h:506
bool pathIsHairline() const
Definition: SkGlyph.cpp:293
int height() const
Definition: SkGlyph.h:513
SkFixed getSubYFixed() const
Definition: SkGlyph.h:432
SkFixed getSubXFixed() const
Definition: SkGlyph.h:431
SkIRect iRect() const
Definition: SkGlyph.h:505
int width() const
Definition: SkGlyph.h:512
int left() const
Definition: SkGlyph.h:510
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)
static SkMatrix Scale(SkScalar sx, SkScalar sy)
Definition: SkMatrix.h:75
SkMatrix & postTranslate(SkScalar dx, SkScalar dy)
Definition: SkMatrix.cpp:281
static SkMatrix MakeAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, SkScalar skewY, SkScalar scaleY, SkScalar transY, SkScalar pers0, SkScalar pers1, SkScalar pers2)
Definition: SkMatrix.h:179
void mapXY(SkScalar x, SkScalar y, SkPoint *result) const
Definition: SkMatrix.cpp:777
SkMatrix & preConcat(const SkMatrix &other)
Definition: SkMatrix.cpp:674
SkMatrix & preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
Definition: SkMatrix.cpp:315
bool isIdentity() const
Definition: SkMatrix.h:223
void setColor(SkColor color)
Definition: SkPaint.cpp:119
@ kFill_Style
set to fill geometry
Definition: SkPaint.h:193
Definition: SkPath.h:59
static SkPath Rect(const SkRect &, SkPathDirection=SkPathDirection::kCW, unsigned startIndex=0)
Definition: SkPath.cpp:3586
SkPath & moveTo(SkScalar x, SkScalar y)
Definition: SkPath.cpp:688
SkPath & lineTo(SkScalar x, SkScalar y)
Definition: SkPath.cpp:728
SkPath & quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2)
Definition: SkPath.cpp:746
const SkRect & getBounds() const
Definition: SkPath.cpp:430
SkPath & cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar x3, SkScalar y3)
Definition: SkPath.cpp:799
SkPath & close()
Definition: SkPath.cpp:823
void transform(const SkMatrix &matrix, SkPath *dst, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
Definition: SkPath.cpp:1711
SkScalerContextRec fRec
static void GenerateImageFromPath(SkMaskBuilder &dst, const SkPath &path, const SkMaskGamma::PreBlend &maskPreBlend, bool doBGR, bool verticalLCD, bool a8FromLCD, bool hairline)
const SkMaskGamma::PreBlend fPreBlend
SkTypeface * getTypeface() const
bool isSubpixel() const
bool isLinearMetrics() const
constexpr size_t size() const
Definition: SkSpan_impl.h:95
const char * c_str() const
Definition: SkString.h:133
void onGetFontDescriptor(SkFontDescriptor *, bool *) const override
int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const override
static sk_sp< SkTypeface > MakeFromStream(std::unique_ptr< SkStreamAsset >, const SkFontArguments &)
int onCountGlyphs() const override
SkSpan< const SkColor > getPalette() const
int onGetUPEM() const override
void onCharsToGlyphs(const SkUnichar *chars, int count, SkGlyphID glyphs[]) const override
std::unique_ptr< SkAdvancedTypefaceMetrics > onGetAdvancedMetrics() const override
bool onGlyphMaskNeedsCurrentColor() const override
int onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[], int parameterCount) const override
sk_sp< SkTypeface > onMakeClone(const SkFontArguments &args) const override
void onFilterRec(SkScalerContextRec *) const override
int onGetTableTags(SkFontTableTag tags[]) const override
void getGlyphToUnicodeMap(SkUnichar *) const override
std::unique_ptr< SkScalerContext > onCreateScalerContext(const SkScalerContextEffects &effects, const SkDescriptor *desc) const override
void onGetFamilyName(SkString *familyName) const override
static sk_sp< SkTypeface > MakeFromData(sk_sp< SkData > fontData, const SkFontArguments &)
size_t onGetTableData(SkFontTableTag, size_t, size_t, void *) const override
std::unique_ptr< SkStreamAsset > onOpenStream(int *ttcIndex) const override
bool onGetPostScriptName(SkString *) const override
SkTypeface::LocalizedStrings * onCreateFamilyNameIterator() const override
SkFontStyle fontStyle() const
Definition: SkTypeface.h:55
void serialize(SkWStream *, SerializeBehavior=SerializeBehavior::kIncludeDataIfLocal) const
Definition: SkTypeface.cpp:202
size_t getTableSize(SkFontTableTag) const
Definition: SkTypeface.cpp:309
SkFourByteTag FactoryId
Definition: SkTypeface.h:335
SkrifaLocalizedStrings(rust::Box<::fontations_ffi::BridgeLocalizedStrings > bridge_localized_strings)
bool next(SkTypeface::LocalizedString *localized_string) override
bool populate_axis(size_t i, uint32_t axisTag, float min, float def, float max, bool hidden) override
virtual void fill_glyph_radial(uint16_t glyph_id, const fontations_ffi::Transform &, const fontations_ffi::FillRadialParams &, fontations_ffi::BridgeColorStops &, uint8_t) override
virtual void push_transform(const fontations_ffi::Transform &transform) override
virtual void push_clip_rectangle(float x_min, float y_min, float x_max, float y_max) override
virtual void fill_glyph_linear(uint16_t glyph_id, const fontations_ffi::Transform &, const fontations_ffi::FillLinearParams &, fontations_ffi::BridgeColorStops &, uint8_t) override
virtual void fill_glyph_sweep(uint16_t glyph_id, const fontations_ffi::Transform &, const fontations_ffi::FillSweepParams &, fontations_ffi::BridgeColorStops &, uint8_t) override
virtual void fill_glyph_solid(uint16_t glyph_id, uint16_t, float) override
virtual void push_clip_glyph(uint16_t glyph_id) override
virtual void pop_transform() override
virtual void fill_radial(const fontations_ffi::FillRadialParams &fill_radial_params, fontations_ffi::BridgeColorStops &, uint8_t extend_mode) override
virtual void fill_glyph_radial(uint16_t glyph_id, const fontations_ffi::Transform &transform, const fontations_ffi::FillRadialParams &fill_radial_params, fontations_ffi::BridgeColorStops &stops, uint8_t) override
virtual void fill_glyph_linear(uint16_t glyph_id, const fontations_ffi::Transform &transform, const fontations_ffi::FillLinearParams &fill_linear_params, fontations_ffi::BridgeColorStops &stops, uint8_t) override
virtual void fill_solid(uint16_t palette_index, float alpha) override
virtual void fill_glyph_sweep(uint16_t glyph_id, const fontations_ffi::Transform &transform, const fontations_ffi::FillSweepParams &fill_sweep_params, fontations_ffi::BridgeColorStops &stops, uint8_t) override
virtual void push_layer(uint8_t compositeMode) override
virtual void pop_transform() override
virtual void fill_sweep(const fontations_ffi::FillSweepParams &fill_sweep_params, fontations_ffi::BridgeColorStops &, uint8_t extend_mode) override
virtual void fill_linear(const fontations_ffi::FillLinearParams &fill_linear_params, fontations_ffi::BridgeColorStops &, uint8_t extend_mode) override
virtual void fill_glyph_solid(uint16_t glyph_id, uint16_t palette_index, float alpha) override
virtual void push_clip_rectangle(float x_min, float y_min, float x_max, float y_max) override
virtual void push_transform(const fontations_ffi::Transform &transform) override
virtual void push_clip_glyph(uint16_t glyph_id) override
void line_to(float x, float y) override
void move_to(float x, float y) override
void curve_to(float cx0, float cy0, float cx1, float cy1, float x, float y) override
void quad_to(float cx0, float cy0, float x, float y) override
const Paint & paint
Definition: color_source.cc:38
DlColor color
@ kSuccess
Definition: embedder.h:73
float SkScalar
Definition: extension.cpp:12
static bool b
struct MyStruct a[10]
FlutterSemanticsFlag flag
FlutterSemanticsFlag flags
glong glong end
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
uint8_t value
GAsyncResult * result
uint32_t uint32_t * format
static float max(float r, float g, float b)
Definition: hsl.cpp:49
static float min(float r, float g, float b)
Definition: hsl.cpp:48
size_t length
double y
double x
SK_API std::unique_ptr< SkCodec > Decode(std::unique_ptr< SkStream >, SkCodec::Result *, SkCodecs::DecodeContext=nullptr)
unsigned useCenter Optional< SkMatrix > matrix
Definition: SkRecords.h:258
Optional< SkRect > bounds
Definition: SkRecords.h:189
clipRect(r.rect, r.opAA.op(), r.opAA.aa())) template<> void Draw
PODArray< SkColor > colors
Definition: SkRecords.h:276
SkSamplingOptions sampling
Definition: SkRecords.h:337
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
Definition: switches.h:57
const uint32_t extend_mode[]
Definition: colrv1.cpp:203
skgpu::graphite::Transform Transform
Definition: ref_ptr.h:256
static SkColor4f transform(SkColor4f c, SkColorSpace *src, SkColorSpace *dst)
Definition: p3.cpp:47
SkScalar h
const Scalar scale
SeparatedVector2 offset
@ kNotEmbeddable_FontFlag
May not be embedded.
@ kNotSubsettable_FontFlag
May not be subset.
@ kVariable_FontFlag
May be true for Type1, CFF, or TrueType fonts.
SkFontArguments & setVariationDesignPosition(VariationPosition position)
SkFontArguments & setPalette(Palette palette)
VariationPosition getVariationDesignPosition() const
SkScalar fTop
greatest extent above origin of any glyph bounding box, typically negative; deprecated with variable ...
Definition: SkFontMetrics.h:53
SkScalar fLeading
distance to add between lines, typically positive or zero
Definition: SkFontMetrics.h:57
SkScalar fAvgCharWidth
average character width, zero if unknown
Definition: SkFontMetrics.h:58
SkScalar fStrikeoutPosition
distance from baseline to bottom of stroke, typically negative
Definition: SkFontMetrics.h:67
SkScalar fStrikeoutThickness
strikeout thickness
Definition: SkFontMetrics.h:66
SkScalar fMaxCharWidth
maximum character width, zero if unknown
Definition: SkFontMetrics.h:59
SkScalar fBottom
greatest extent below origin of any glyph bounding box, typically positive; deprecated with variable ...
Definition: SkFontMetrics.h:56
uint32_t fFlags
FontMetricsFlags indicating which metrics are valid.
Definition: SkFontMetrics.h:52
SkScalar fAscent
distance to reserve above baseline, typically negative
Definition: SkFontMetrics.h:54
SkScalar fXHeight
height of lower-case 'x', zero if unknown, typically negative
Definition: SkFontMetrics.h:62
SkScalar fUnderlineThickness
underline thickness
Definition: SkFontMetrics.h:64
@ kStrikeoutPositionIsValid_Flag
set if fStrikeoutPosition is valid
Definition: SkFontMetrics.h:48
@ kStrikeoutThicknessIsValid_Flag
set if fStrikeoutThickness is valid
Definition: SkFontMetrics.h:47
@ kUnderlinePositionIsValid_Flag
set if fUnderlinePosition is valid
Definition: SkFontMetrics.h:46
@ kUnderlineThicknessIsValid_Flag
set if fUnderlineThickness is valid
Definition: SkFontMetrics.h:45
@ kBoundsInvalid_Flag
set if fTop, fBottom, fXMin, fXMax invalid
Definition: SkFontMetrics.h:49
SkScalar fDescent
distance to reserve below baseline, typically positive
Definition: SkFontMetrics.h:55
SkScalar fCapHeight
height of an upper-case letter, zero if unknown, typically negative
Definition: SkFontMetrics.h:63
SkScalar fXMin
greatest extent to left of origin of any glyph bounding box, typically negative; deprecated with vari...
Definition: SkFontMetrics.h:60
SkScalar fUnderlinePosition
distance from baseline to top of stroke, typically positive
Definition: SkFontMetrics.h:65
SkScalar fXMax
greatest extent to right of origin of any glyph bounding box, typically positive; deprecated with var...
Definition: SkFontMetrics.h:61
static constexpr SkIRect MakeLTRB(int32_t l, int32_t t, int32_t r, int32_t b)
Definition: SkRect.h:91
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
@ kLCD16_Format
565 alpha for r/g/b
Definition: SkMask.h:31
@ kARGB32_Format
SkPMColor.
Definition: SkMask.h:30
@ kBW_Format
1bit per pixel mask (e.g. monochrome)
Definition: SkMask.h:27
const Format fFormat
Definition: SkMask.h:44
static constexpr SkPoint Make(float x, float y)
Definition: SkPoint_impl.h:173
void scale(float scale, SkPoint *dst) const
Definition: SkPoint.cpp:17
static SkRect Make(const SkISize &size)
Definition: SkRect.h:669
static constexpr SkRect MakeEmpty()
Definition: SkRect.h:595
void roundOut(SkIRect *dst) const
Definition: SkRect.h:1241
void join(const SkRect &r)
Definition: SkRect.cpp:126
static constexpr SkRect MakeLTRB(float l, float t, float r, float b)
Definition: SkRect.h:646
void getSingleMatrix(SkMatrix *) const
SkMask::Format fMaskFormat
bool computeMatrices(PreMatrixScale preMatrixScale, SkVector *scale, SkMatrix *remaining, SkMatrix *remainingWithoutRotation=nullptr, SkMatrix *remainingRotation=nullptr, SkMatrix *total=nullptr)
SkScalar fPost2x2[2][2]
SkFontHinting getHinting() const
void setHinting(SkFontHinting)
static SKVX_ALWAYS_INLINE Vec Load(const void *ptr)
Definition: SkVx.h:109
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63