Flutter Engine
The Flutter Engine
SkScalerContext.h
Go to the documentation of this file.
1/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef SkScalerContext_DEFINED
9#define SkScalerContext_DEFINED
10
14#include "include/core/SkRect.h"
25#include "src/core/SkGlyph.h"
26#include "src/core/SkMask.h"
28
29#include <cstddef>
30#include <cstdint>
31#include <memory>
32#include <utility>
33
34class SkArenaAlloc;
36class SkDescriptor;
37class SkDrawable;
38class SkFont;
39class SkMaskFilter;
40class SkPath;
41class SkPathEffect;
42enum class SkFontHinting;
43struct SkFontMetrics;
44
45//The following typedef hides from the rest of the implementation the number of
46//most significant bits to consider when creating mask gamma tables. Two bits
47//per channel was chosen as a balance between fidelity (more bits) and cache
48//sizes (fewer bits). Three bits per channel was chosen when #303942; (used by
49//the Chrome UI) turned out too green.
51
52enum class SkScalerContextFlags : uint32_t {
53 kNone = 0,
54 kFakeGamma = 1 << 0,
55 kBoostContrast = 1 << 1,
57};
59
60/*
61 * To allow this to be forward-declared, it must be its own typename, rather
62 * than a nested struct inside SkScalerContext (where it started).
63 *
64 * SkScalerContextRec must be dense, and all bytes must be set to a know quantity because this
65 * structure is used to calculate a checksum.
66 */
73
74 // This will be set if to the paint's foreground color if
75 // kNeedsForegroundColor is set, which will usually be the case for COLRv0 and
76 // COLRv1 fonts.
78
79private:
80 //These describe the parameters to create (uniquely identify) the pre-blend.
81 uint32_t fLumBits;
82 uint8_t fDeviceGamma; //2.6, (0.0, 4.0) gamma, 0.0 for sRGB
83 const uint8_t fReservedAlign2{0};
84 uint8_t fContrast; //0.8+1, [0.0, 1.0] artificial contrast
85 const uint8_t fReservedAlign{0};
86
87 static constexpr SkScalar ExternalGammaFromInternal(uint8_t g) {
88 return SkIntToScalar(g) / (1 << 6);
89 }
90 static constexpr uint8_t InternalGammaFromExternal(SkScalar g) {
91 // C++23 use constexpr std::floor
92 return static_cast<uint8_t>(g * (1 << 6));
93 }
94 static constexpr SkScalar ExternalContrastFromInternal(uint8_t c) {
95 return SkIntToScalar(c) / ((1 << 8) - 1);
96 }
97 static constexpr uint8_t InternalContrastFromExternal(SkScalar c) {
98 // C++23 use constexpr std::round
99 return static_cast<uint8_t>((c * ((1 << 8) - 1)) + 0.5f);
100 }
101public:
103 sk_ignore_unused_variable(fReservedAlign2);
106 fDeviceGamma = InternalGammaFromExternal(g);
107 }
108
110 sk_ignore_unused_variable(fReservedAlign);
113 fContrast = InternalContrastFromExternal(c);
114 }
115
116 static const SkMaskGamma& CachedMaskGamma(uint8_t contrast, uint8_t gamma);
118 return CachedMaskGamma(fContrast, fDeviceGamma);
119 }
120
121 /**
122 * Causes the luminance color to be ignored, and the paint and device
123 * gamma to be effectively 1.0
124 */
125 void ignoreGamma() {
128 }
129
130 /**
131 * Causes the luminance color and contrast to be ignored, and the
132 * paint and device gamma to be effectively 1.0.
133 */
135 ignoreGamma();
136 setContrast(0);
137 }
138
140
141private:
142 uint8_t fStrokeJoin : 4;
143 uint8_t fStrokeCap : 4;
144
145public:
146 uint16_t fFlags;
147
148 // Warning: when adding members note that the size of this structure
149 // must be a multiple of 4. SkDescriptor requires that its arguments be
150 // multiples of four and this structure is put in an SkDescriptor in
151 // SkPaint::MakeRecAndEffects.
152
153 SkString dump() const {
154 SkString msg;
155 msg.appendf(" Rec\n");
156 msg.appendf(" textsize %a prescale %a preskew %a post [%a %a %a %a]\n",
158 fPost2x2[0][1], fPost2x2[1][0], fPost2x2[1][1]);
159 msg.appendf(" frame %g miter %g format %d join %d cap %d flags %#hx\n",
160 fFrameWidth, fMiterLimit, fMaskFormat, fStrokeJoin, fStrokeCap, fFlags);
161 msg.appendf(" lum bits %x, device gamma %d, contrast %d\n", fLumBits,
162 fDeviceGamma, fContrast);
163 msg.appendf(" foreground color %x\n", fForegroundColor);
164 return msg;
165 }
166
167 void getMatrixFrom2x2(SkMatrix*) const;
168 void getLocalMatrix(SkMatrix*) const;
169 void getSingleMatrix(SkMatrix*) const;
170
171 /** The kind of scale which will be applied by the underlying port (pre-matrix). */
172 enum class PreMatrixScale {
173 kFull, // The underlying port can apply both x and y scale.
174 kVertical, // The underlying port can only apply a y scale.
175 kVerticalInteger // The underlying port can only apply an integer y scale.
176 };
177 /**
178 * Compute useful matrices for use with sizing in underlying libraries.
179 *
180 * There are two kinds of text size, a 'requested/logical size' which is like asking for size
181 * '12' and a 'real' size which is the size after the matrix is applied. The matrices produced
182 * by this method are based on the 'real' size. This method effectively finds the total device
183 * matrix and decomposes it in various ways.
184 *
185 * The most useful decomposition is into 'scale' and 'remaining'. The 'scale' is applied first
186 * and then the 'remaining' to fully apply the total matrix. This decomposition is useful when
187 * the text size ('scale') may have meaning apart from the total matrix. This is true when
188 * hinting, and sometimes true for other properties as well.
189 *
190 * The second (optional) decomposition is of 'remaining' into a non-rotational part
191 * 'remainingWithoutRotation' and a rotational part 'remainingRotation'. The 'scale' is applied
192 * first, then 'remainingWithoutRotation', then 'remainingRotation' to fully apply the total
193 * matrix. This decomposition is helpful when only horizontal metrics can be trusted, so the
194 * 'scale' and 'remainingWithoutRotation' will be handled by the underlying library, but
195 * the final rotation 'remainingRotation' will be handled manually.
196 *
197 * The 'total' matrix is also (optionally) available. This is useful in cases where the
198 * underlying library will not be used, often when working directly with font data.
199 *
200 * The parameters 'scale' and 'remaining' are required, the other pointers may be nullptr.
201 *
202 * @param preMatrixScale the kind of scale to extract from the total matrix.
203 * @param scale the scale extracted from the total matrix (both values positive).
204 * @param remaining apply after scale to apply the total matrix.
205 * @param remainingWithoutRotation apply after scale to apply the total matrix sans rotation.
206 * @param remainingRotation apply after remainingWithoutRotation to apply the total matrix.
207 * @param total the total matrix.
208 * @return false if the matrix was singular. The output will be valid but not invertible.
209 */
210 bool computeMatrices(PreMatrixScale preMatrixScale,
211 SkVector* scale, SkMatrix* remaining,
212 SkMatrix* remainingWithoutRotation = nullptr,
213 SkMatrix* remainingRotation = nullptr,
214 SkMatrix* total = nullptr);
215
217
218 inline SkFontHinting getHinting() const;
219 inline void setHinting(SkFontHinting);
220
222 return fMaskFormat;
223 }
224
226 return fLumBits;
227 }
228
229 // setLuminanceColor forces the alpha to be 0xFF because the blitter that draws the glyph
230 // will apply the alpha from the paint. Don't apply the alpha twice.
232
233private:
234 // TODO: remove
235 friend class SkScalerContext;
236};
238
239// TODO: rename SkScalerContextEffects -> SkStrikeEffects
243 : fPathEffect(pe), fMaskFilter(mf) {}
245 : fPathEffect(paint.getPathEffect())
246 , fMaskFilter(paint.getMaskFilter()) {}
247
250};
251
253public:
254 enum Flags {
256 kUnused = 0x0002,
260 kForceAutohinting_Flag = 0x0020, // Use auto instead of bytcode hinting if hinting.
261
262 // together, these two flags resulting in a two bit value which matches
263 // up with the SkPaint::Hinting enum.
264 kHinting_Shift = 7, // to shift into the other flags above
267
268 // Pixel geometry information.
269 // only meaningful if fMaskFormat is kLCD16
270 kLCD_Vertical_Flag = 0x0200, // else Horizontal
271 kLCD_BGROrder_Flag = 0x0400, // else RGB order
272
273 // Generate A8 from LCD source (for GDI and CoreGraphics).
274 // only meaningful if fMaskFormat is kA8
275 kGenA8FromLCD_Flag = 0x0800, // could be 0x200 (bit meaning dependent on fMaskFormat)
278
280 };
281
282 // computed values
283 enum {
285 };
286
288 virtual ~SkScalerContext();
289
290 SkTypeface* getTypeface() const { return fTypeface.get(); }
291
293 return fRec.fMaskFormat;
294 }
295
296 bool isSubpixel() const {
298 }
299
300 bool isLinearMetrics() const {
302 }
303
304 // DEPRECATED
305 bool isVertical() const { return false; }
306
308 void getImage(const SkGlyph&);
312
313 /** Return the size in bytes of the associated gamma lookup table
314 */
315 static size_t GetGammaLUTSize(SkScalar contrast, SkScalar deviceGamma,
316 int* width, int* height);
317
318 /** Get the associated gamma lookup table. The 'data' pointer must point to pre-allocated
319 * memory, with size in bytes greater than or equal to the return value of getGammaLUTSize().
320 *
321 * If the lookup table hasn't been initialized (e.g., it's linear), this will return false.
322 */
323 static bool GetGammaLUTData(SkScalar contrast, SkScalar deviceGamma, uint8_t* data);
324
325 static void MakeRecAndEffects(const SkFont& font, const SkPaint& paint,
326 const SkSurfaceProps& surfaceProps,
327 SkScalerContextFlags scalerContextFlags,
328 const SkMatrix& deviceMatrix,
330 SkScalerContextEffects* effects);
331
332 // If we are creating rec and effects from a font only, then there is no device around either.
335 SkScalerContextEffects* effects) {
337 return MakeRecAndEffects(
340 }
341
342 static std::unique_ptr<SkScalerContext> MakeEmpty(
343 sk_sp<SkTypeface> typeface, const SkScalerContextEffects& effects,
344 const SkDescriptor* desc);
345
347 const SkScalerContextRec& rec,
348 const SkScalerContextEffects& effects,
349 SkAutoDescriptor* ad);
350
351 static std::unique_ptr<SkDescriptor> DescriptorGivenRecAndEffects(
352 const SkScalerContextRec& rec,
353 const SkScalerContextEffects& effects);
354
355 static void DescriptorBufferGiveRec(const SkScalerContextRec& rec, void* buffer);
356 static bool CheckBufferSizeForRec(const SkScalerContextRec& rec,
357 const SkScalerContextEffects& effects,
358 size_t size);
359
361
362 const SkScalerContextRec& getRec() const { return fRec; }
363
365 return { fPathEffect.get(), fMaskFilter.get() };
366 }
367
368 /**
369 * Return the axis (if any) that the baseline for horizontal text should land on.
370 * As an example, the identity matrix will return SkAxisAlignment::kX.
371 */
373
375 const SkFont&, const SkPaint&, const SkSurfaceProps&,
376 SkScalerContextFlags scalerContextFlags,
377 const SkMatrix& deviceMatrix, SkAutoDescriptor* ad,
378 SkScalerContextEffects* effects);
379
380protected:
382
387 uint16_t extraBits;
390
392 : advance{0, 0}
393 , bounds{0, 0, 0, 0}
395 , extraBits(0)
398 {}
399 };
400
402
403 static void GenerateMetricsFromPath(
404 SkGlyph* glyph, const SkPath& path, SkMask::Format format,
405 bool verticalLCD, bool a8FromLCD, bool hairline);
406
407 static void SaturateGlyphBounds(SkGlyph* glyph, SkRect&&);
408 static void SaturateGlyphBounds(SkGlyph* glyph, SkIRect const &);
409
410 /** Generates the contents of glyph.fImage.
411 * When called, glyph.fImage will be pointing to a pre-allocated,
412 * uninitialized region of memory of size glyph.imageSize().
413 * This method may not change glyph.fMaskFormat.
414 *
415 * Because glyph.imageSize() will determine the size of fImage,
416 * generateMetrics will be called before generateImage.
417 */
418 virtual void generateImage(const SkGlyph& glyph, void* imageBuffer) = 0;
419 static void GenerateImageFromPath(
420 SkMaskBuilder& dst, const SkPath& path, const SkMaskGamma::PreBlend& maskPreBlend,
421 bool doBGR, bool verticalLCD, bool a8FromLCD, bool hairline);
422
423 /** Sets the passed path to the glyph outline.
424 * If this cannot be done the path is set to empty;
425 * Does not apply subpixel positioning to the path.
426 * @return false if this glyph does not have any path.
427 */
428 [[nodiscard]] virtual bool generatePath(const SkGlyph&, SkPath*) = 0;
429
430 /** Returns the drawable for the glyph (if any).
431 *
432 * The generated drawable will be lifetime scoped to the lifetime of this scaler context.
433 * This means the drawable may refer to the scaler context and associated font data.
434 *
435 * The drawable does not need to be flattenable (e.g. implement getFactory and getTypeName).
436 * Any necessary serialization will be done with makePictureSnapshot.
437 */
438 virtual sk_sp<SkDrawable> generateDrawable(const SkGlyph&); // TODO: = 0
439
440 /** Retrieves font metrics. */
442
443 void forceGenerateImageFromPath() { fGenerateImageFromPath = true; }
444 void forceOffGenerateImageFromPath() { fGenerateImageFromPath = false; }
445
446private:
447 friend class PathText; // For debug purposes
448 friend class PathTextBench; // For debug purposes
449 friend class RandomScalerContext; // For debug purposes
450
451 static SkScalerContextRec PreprocessRec(const SkTypeface&,
453 const SkDescriptor&);
454
455 // never null
456 sk_sp<SkTypeface> fTypeface;
457
458 // optional objects, which may be null
459 sk_sp<SkPathEffect> fPathEffect;
460 sk_sp<SkMaskFilter> fMaskFilter;
461
462 // if this is set, we draw the image from a path, rather than
463 // calling generateImage.
464 bool fGenerateImageFromPath;
465
466 void internalGetPath(SkGlyph&, SkArenaAlloc*);
468
469protected:
470 // SkMaskGamma::PreBlend converts linear masks to gamma correcting masks.
471 // Visible to subclasses so that generateImage can apply the pre-blend directly.
473};
474
475#define kRec_SkDescriptorTag SkSetFourByteTag('s', 'r', 'e', 'c')
476#define kEffects_SkDescriptorTag SkSetFourByteTag('e', 'f', 'c', 't')
477
478///////////////////////////////////////////////////////////////////////////////
479
481 unsigned hint = (fFlags & SkScalerContext::kHinting_Mask) >>
483 return static_cast<SkFontHinting>(hint);
484}
485
488 (static_cast<unsigned>(hinting) << SkScalerContext::kHinting_Shift);
489}
490
491
492#endif
#define SkASSERT(cond)
Definition: SkAssert.h:116
uint32_t SkColor
Definition: SkColor.h:37
constexpr SkColor SK_ColorTRANSPARENT
Definition: SkColor.h:99
constexpr SkColor SK_ColorBLACK
Definition: SkColor.h:103
SkFontHinting
Definition: SkFontTypes.h:18
SkAxisAlignment
Definition: SkGlyph.h:218
#define SK_MAKE_BITFIELD_OPS(X)
Definition: SkMacros.h:66
#define SK_BEGIN_REQUIRE_DENSE
Definition: SkMacros.h:37
#define SK_END_REQUIRE_DENSE
Definition: SkMacros.h:38
#define SK_Scalar1
Definition: SkScalar.h:18
#define SkIntToScalar(x)
Definition: SkScalar.h:57
SkTMaskGamma< 3, 3, 3 > SkMaskGamma
SkScalerContextFlags
void sk_ignore_unused_variable(const T &)
Definition: SkTemplates.h:37
static constexpr bool SkToBool(const T &x)
Definition: SkTo.h:35
uint32_t SkTypefaceID
Definition: SkTypeface.h:38
Definition: SkFont.h:35
static const SkMatrix & I()
Definition: SkMatrix.cpp:1544
Definition: SkPath.h:59
void forceGenerateImageFromPath()
virtual void generateFontMetrics(SkFontMetrics *)=0
SkScalerContext(sk_sp< SkTypeface >, const SkScalerContextEffects &, const SkDescriptor *)
SkScalerContextRec fRec
virtual void generateImage(const SkGlyph &glyph, void *imageBuffer)=0
static void GenerateImageFromPath(SkMaskBuilder &dst, const SkPath &path, const SkMaskGamma::PreBlend &maskPreBlend, bool doBGR, bool verticalLCD, bool a8FromLCD, bool hairline)
static void MakeRecAndEffects(const SkFont &font, const SkPaint &paint, const SkSurfaceProps &surfaceProps, SkScalerContextFlags scalerContextFlags, const SkMatrix &deviceMatrix, SkScalerContextRec *rec, SkScalerContextEffects *effects)
SkMask::Format getMaskFormat() const
static std::unique_ptr< SkDescriptor > DescriptorGivenRecAndEffects(const SkScalerContextRec &rec, const SkScalerContextEffects &effects)
virtual GlyphMetrics generateMetrics(const SkGlyph &, SkArenaAlloc *)=0
virtual bool generatePath(const SkGlyph &, SkPath *)=0
void getPath(SkGlyph &, SkArenaAlloc *)
const SkMaskGamma::PreBlend fPreBlend
static SkMaskGamma::PreBlend GetMaskPreBlend(const SkScalerContextRec &rec)
SkTypeface * getTypeface() const
static SkDescriptor * CreateDescriptorAndEffectsUsingPaint(const SkFont &, const SkPaint &, const SkSurfaceProps &, SkScalerContextFlags scalerContextFlags, const SkMatrix &deviceMatrix, SkAutoDescriptor *ad, SkScalerContextEffects *effects)
virtual sk_sp< SkDrawable > generateDrawable(const SkGlyph &)
static SkDescriptor * AutoDescriptorGivenRecAndEffects(const SkScalerContextRec &rec, const SkScalerContextEffects &effects, SkAutoDescriptor *ad)
static void MakeRecAndEffectsFromFont(const SkFont &font, SkScalerContextRec *rec, SkScalerContextEffects *effects)
const SkScalerContextRec & getRec() const
static void GenerateMetricsFromPath(SkGlyph *glyph, const SkPath &path, SkMask::Format format, bool verticalLCD, bool a8FromLCD, bool hairline)
static bool CheckBufferSizeForRec(const SkScalerContextRec &rec, const SkScalerContextEffects &effects, size_t size)
bool isSubpixel() const
SkScalerContextEffects getEffects() const
static size_t GetGammaLUTSize(SkScalar contrast, SkScalar deviceGamma, int *width, int *height)
friend class PathText
SkAxisAlignment computeAxisAlignmentForHText() const
sk_sp< SkDrawable > getDrawable(SkGlyph &)
static std::unique_ptr< SkScalerContext > MakeEmpty(sk_sp< SkTypeface > typeface, const SkScalerContextEffects &effects, const SkDescriptor *desc)
bool isVertical() const
SkGlyph makeGlyph(SkPackedGlyphID, SkArenaAlloc *)
static void DescriptorBufferGiveRec(const SkScalerContextRec &rec, void *buffer)
virtual ~SkScalerContext()
bool isLinearMetrics() const
void forceOffGenerateImageFromPath()
void getFontMetrics(SkFontMetrics *)
static bool GetGammaLUTData(SkScalar contrast, SkScalar deviceGamma, uint8_t *data)
void getImage(const SkGlyph &)
static void SaturateGlyphBounds(SkGlyph *glyph, SkRect &&)
void void void appendf(const char format[],...) SK_PRINTF_LIKE(2
Definition: SkString.cpp:550
static constexpr SkScalar kMaxContrastInclusive
static constexpr SkScalar kMaxGammaExclusive
static constexpr SkScalar kMinGammaInclusive
static constexpr SkScalar kMinContrastInclusive
T * get() const
Definition: SkRefCnt.h:303
const Paint & paint
Definition: color_source.cc:38
float SkScalar
Definition: extension.cpp:12
uint32_t uint32_t * format
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
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 to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
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
Definition: switches.h:259
font
Font Metadata and Metrics.
dst
Definition: cp.py:12
int32_t height
int32_t width
const Scalar scale
Definition: SkRect.h:32
Format
Definition: SkMask.h:26
SkPathEffect * fPathEffect
SkScalerContextEffects(const SkPaint &paint)
SkScalerContextEffects(SkPathEffect *pe, SkMaskFilter *mf)
SkMaskFilter * fMaskFilter
void getSingleMatrix(SkMatrix *) const
void getLocalMatrix(SkMatrix *) const
void setDeviceGamma(SkScalar g)
static const SkMaskGamma & CachedMaskGamma(uint8_t contrast, uint8_t gamma)
SkAxisAlignment computeAxisAlignmentForHText() const
SkMask::Format fMaskFormat
void setContrast(SkScalar c)
SkMask::Format getFormat() const
void getMatrixFrom2x2(SkMatrix *) const
bool computeMatrices(PreMatrixScale preMatrixScale, SkVector *scale, SkMatrix *remaining, SkMatrix *remainingWithoutRotation=nullptr, SkMatrix *remainingRotation=nullptr, SkMatrix *total=nullptr)
const SkMaskGamma & cachedMaskGamma() const
SkTypefaceID fTypefaceID
SkScalar fPost2x2[2][2]
SkColor getLuminanceColor() const
SkString dump() const
SkFontHinting getHinting() const
void setHinting(SkFontHinting)
void setLuminanceColor(SkColor c)
GlyphMetrics(SkMask::Format format)
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63