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
11 #include <memory>
12
13 #include "include/core/SkFont.h"
14 #include "include/core/SkFontTypes.h"
15 #include "include/core/SkMaskFilter.h"
16 #include "include/core/SkMatrix.h"
17 #include "include/core/SkPaint.h"
18 #include "include/core/SkTypeface.h"
19 #include "include/private/SkMacros.h"
20 #include "src/core/SkGlyph.h"
21 #include "src/core/SkMask.h"
22 #include "src/core/SkMaskGamma.h"
23 #include "src/core/SkStrikeForGPU.h"
24 #include "src/core/SkSurfacePriv.h"
25 #include "src/core/SkWriteBuffer.h"
26
27 class SkAutoDescriptor;
28 class SkDescriptor;
29 class SkMaskFilter;
30 class SkPathEffect;
31 class SkScalerContext;
32 class SkScalerContext_DW;
33
34 enum SkScalerContextFlags : uint32_t {
35 kNone = 0,
36 kFakeGamma = 1 << 0,
37 kBoostContrast = 1 << 1,
38 kFakeGammaAndBoostContrast = kFakeGamma | kBoostContrast,
39 };
40
41 enum SkAxisAlignment : uint32_t {
42 kNone_SkAxisAlignment,
43 kX_SkAxisAlignment,
44 kY_SkAxisAlignment
45 };
46
47 /*
48 * To allow this to be forward-declared, it must be its own typename, rather
49 * than a nested struct inside SkScalerContext (where it started).
50 *
51 * SkScalerContextRec must be dense, and all bytes must be set to a know quantity because this
52 * structure is used to calculate a checksum.
53 */
54 SK_BEGIN_REQUIRE_DENSE
55 struct SkScalerContextRec {
56 SkTypefaceID fTypefaceID;
57 SkScalar fTextSize, fPreScaleX, fPreSkewX;
58 SkScalar fPost2x2[2][2];
59 SkScalar fFrameWidth, fMiterLimit;
60
61 // This will be set if to the paint's foreground color if
62 // kNeedsForegroundColor is set, which will usually be the case for COLRv0 and
63 // COLRv1 fonts.
64 uint32_t fForegroundColor{SK_ColorBLACK};
65
66 private:
67 //These describe the parameters to create (uniquely identify) the pre-blend.
68 uint32_t fLumBits;
69 uint8_t fDeviceGamma; //2.6, (0.0, 4.0) gamma, 0.0 for sRGB
70 uint8_t fPaintGamma; //2.6, (0.0, 4.0) gamma, 0.0 for sRGB
71 uint8_t fContrast; //0.8+1, [0.0, 1.0] artificial contrast
72 const uint8_t fReservedAlign{0};
73
74 public:
75
getDeviceGammaSkScalerContextRec76 SkScalar getDeviceGamma() const {
77 return SkIntToScalar(fDeviceGamma) / (1 << 6);
78 }
setDeviceGammaSkScalerContextRec79 void setDeviceGamma(SkScalar dg) {
80 SkASSERT(0 <= dg && dg < SkIntToScalar(4));
81 fDeviceGamma = SkScalarFloorToInt(dg * (1 << 6));
82 }
83
getPaintGammaSkScalerContextRec84 SkScalar getPaintGamma() const {
85 return SkIntToScalar(fPaintGamma) / (1 << 6);
86 }
setPaintGammaSkScalerContextRec87 void setPaintGamma(SkScalar pg) {
88 SkASSERT(0 <= pg && pg < SkIntToScalar(4));
89 fPaintGamma = SkScalarFloorToInt(pg * (1 << 6));
90 }
91
getContrastSkScalerContextRec92 SkScalar getContrast() const {
93 sk_ignore_unused_variable(fReservedAlign);
94 return SkIntToScalar(fContrast) / ((1 << 8) - 1);
95 }
setContrastSkScalerContextRec96 void setContrast(SkScalar c) {
97 SkASSERT(0 <= c && c <= SK_Scalar1);
98 fContrast = SkScalarRoundToInt(c * ((1 << 8) - 1));
99 }
100
101 /**
102 * Causes the luminance color to be ignored, and the paint and device
103 * gamma to be effectively 1.0
104 */
ignoreGammaSkScalerContextRec105 void ignoreGamma() {
106 setLuminanceColor(SK_ColorTRANSPARENT);
107 setPaintGamma(SK_Scalar1);
108 setDeviceGamma(SK_Scalar1);
109 }
110
111 /**
112 * Causes the luminance color and contrast to be ignored, and the
113 * paint and device gamma to be effectively 1.0.
114 */
ignorePreBlendSkScalerContextRec115 void ignorePreBlend() {
116 ignoreGamma();
117 setContrast(0);
118 }
119
120 SkMask::Format fMaskFormat;
121
122 private:
123 uint8_t fStrokeJoin : 4;
124 uint8_t fStrokeCap : 4;
125
126 public:
127 uint16_t fFlags;
128
129 // Warning: when adding members note that the size of this structure
130 // must be a multiple of 4. SkDescriptor requires that its arguments be
131 // multiples of four and this structure is put in an SkDescriptor in
132 // SkPaint::MakeRecAndEffects.
133
dumpSkScalerContextRec134 SkString dump() const {
135 SkString msg;
136 msg.appendf(" Rec\n");
137 msg.appendf(" textsize %a prescale %a preskew %a post [%a %a %a %a]\n",
138 fTextSize, fPreScaleX, fPreSkewX, fPost2x2[0][0],
139 fPost2x2[0][1], fPost2x2[1][0], fPost2x2[1][1]);
140 msg.appendf(" frame %g miter %g format %d join %d cap %d flags %#hx\n",
141 fFrameWidth, fMiterLimit, fMaskFormat, fStrokeJoin, fStrokeCap, fFlags);
142 msg.appendf(" lum bits %x, device gamma %d, paint gamma %d contrast %d\n", fLumBits,
143 fDeviceGamma, fPaintGamma, fContrast);
144 msg.appendf(" foreground color %x\n", fForegroundColor);
145 return msg;
146 }
147
148 void getMatrixFrom2x2(SkMatrix*) const;
149 void getLocalMatrix(SkMatrix*) const;
150 void getSingleMatrix(SkMatrix*) const;
151
152 /** The kind of scale which will be applied by the underlying port (pre-matrix). */
153 enum PreMatrixScale {
154 kFull_PreMatrixScale, // The underlying port can apply both x and y scale.
155 kVertical_PreMatrixScale, // The underlying port can only apply a y scale.
156 kVerticalInteger_PreMatrixScale // The underlying port can only apply an integer y scale.
157 };
158 /**
159 * Compute useful matrices for use with sizing in underlying libraries.
160 *
161 * There are two kinds of text size, a 'requested/logical size' which is like asking for size
162 * '12' and a 'real' size which is the size after the matrix is applied. The matrices produced
163 * by this method are based on the 'real' size. This method effectively finds the total device
164 * matrix and decomposes it in various ways.
165 *
166 * The most useful decomposition is into 'scale' and 'remaining'. The 'scale' is applied first
167 * and then the 'remaining' to fully apply the total matrix. This decomposition is useful when
168 * the text size ('scale') may have meaning apart from the total matrix. This is true when
169 * hinting, and sometimes true for other properties as well.
170 *
171 * The second (optional) decomposition is of 'remaining' into a non-rotational part
172 * 'remainingWithoutRotation' and a rotational part 'remainingRotation'. The 'scale' is applied
173 * first, then 'remainingWithoutRotation', then 'remainingRotation' to fully apply the total
174 * matrix. This decomposition is helpful when only horizontal metrics can be trusted, so the
175 * 'scale' and 'remainingWithoutRotation' will be handled by the underlying library, but
176 * the final rotation 'remainingRotation' will be handled manually.
177 *
178 * The 'total' matrix is also (optionally) available. This is useful in cases where the
179 * underlying library will not be used, often when working directly with font data.
180 *
181 * The parameters 'scale' and 'remaining' are required, the other pointers may be nullptr.
182 *
183 * @param preMatrixScale the kind of scale to extract from the total matrix.
184 * @param scale the scale extracted from the total matrix (both values positive).
185 * @param remaining apply after scale to apply the total matrix.
186 * @param remainingWithoutRotation apply after scale to apply the total matrix sans rotation.
187 * @param remainingRotation apply after remainingWithoutRotation to apply the total matrix.
188 * @param total the total matrix.
189 * @return false if the matrix was singular. The output will be valid but not invertible.
190 */
191 bool computeMatrices(PreMatrixScale preMatrixScale,
192 SkVector* scale, SkMatrix* remaining,
193 SkMatrix* remainingWithoutRotation = nullptr,
194 SkMatrix* remainingRotation = nullptr,
195 SkMatrix* total = nullptr);
196
197 SkAxisAlignment computeAxisAlignmentForHText() const;
198
199 inline SkFontHinting getHinting() const;
200 inline void setHinting(SkFontHinting);
201
getFormatSkScalerContextRec202 SkMask::Format getFormat() const {
203 return fMaskFormat;
204 }
205
getLuminanceColorSkScalerContextRec206 SkColor getLuminanceColor() const {
207 return fLumBits;
208 }
209
210 // setLuminanceColor forces the alpha to be 0xFF because the blitter that draws the glyph
211 // will apply the alpha from the paint. Don't apply the alpha twice.
212 void setLuminanceColor(SkColor c);
213
214 private:
215 // TODO: remove
216 friend class SkScalerContext;
217 };
218 SK_END_REQUIRE_DENSE
219
220 // TODO: rename SkScalerContextEffects -> SkStrikeEffects
221 struct SkScalerContextEffects {
SkScalerContextEffectsSkScalerContextEffects222 SkScalerContextEffects() : fPathEffect(nullptr), fMaskFilter(nullptr) {}
SkScalerContextEffectsSkScalerContextEffects223 SkScalerContextEffects(SkPathEffect* pe, SkMaskFilter* mf)
224 : fPathEffect(pe), fMaskFilter(mf) {}
SkScalerContextEffectsSkScalerContextEffects225 explicit SkScalerContextEffects(const SkPaint& paint)
226 : fPathEffect(paint.getPathEffect())
227 , fMaskFilter(paint.getMaskFilter()) {}
228
229 SkPathEffect* fPathEffect;
230 SkMaskFilter* fMaskFilter;
231 };
232
233 //The following typedef hides from the rest of the implementation the number of
234 //most significant bits to consider when creating mask gamma tables. Two bits
235 //per channel was chosen as a balance between fidelity (more bits) and cache
236 //sizes (fewer bits). Three bits per channel was chosen when #303942; (used by
237 //the Chrome UI) turned out too green.
238 typedef SkTMaskGamma<3, 3, 3> SkMaskGamma;
239
240 class SkScalerContext {
241 public:
242 enum Flags {
243 kFrameAndFill_Flag = 0x0001,
244 kUnused = 0x0002,
245 kEmbeddedBitmapText_Flag = 0x0004,
246 kEmbolden_Flag = 0x0008,
247 kSubpixelPositioning_Flag = 0x0010,
248 kForceAutohinting_Flag = 0x0020, // Use auto instead of bytcode hinting if hinting.
249
250 // together, these two flags resulting in a two bit value which matches
251 // up with the SkPaint::Hinting enum.
252 kHinting_Shift = 7, // to shift into the other flags above
253 kHintingBit1_Flag = 0x0080,
254 kHintingBit2_Flag = 0x0100,
255
256 // Pixel geometry information.
257 // only meaningful if fMaskFormat is kLCD16
258 kLCD_Vertical_Flag = 0x0200, // else Horizontal
259 kLCD_BGROrder_Flag = 0x0400, // else RGB order
260
261 // Generate A8 from LCD source (for GDI and CoreGraphics).
262 // only meaningful if fMaskFormat is kA8
263 kGenA8FromLCD_Flag = 0x0800, // could be 0x200 (bit meaning dependent on fMaskFormat)
264 kLinearMetrics_Flag = 0x1000,
265 kBaselineSnap_Flag = 0x2000,
266
267 kNeedsForegroundColor_Flag = 0x4000,
268 };
269
270 // computed values
271 enum {
272 kHinting_Mask = kHintingBit1_Flag | kHintingBit2_Flag,
273 };
274
275 SkScalerContext(sk_sp<SkTypeface>, const SkScalerContextEffects&, const SkDescriptor*);
276 virtual ~SkScalerContext();
277
getTypeface()278 SkTypeface* getTypeface() const { return fTypeface.get(); }
279
getMaskFormat()280 SkMask::Format getMaskFormat() const {
281 return fRec.fMaskFormat;
282 }
283
isSubpixel()284 bool isSubpixel() const {
285 return SkToBool(fRec.fFlags & kSubpixelPositioning_Flag);
286 }
287
isLinearMetrics()288 bool isLinearMetrics() const {
289 return SkToBool(fRec.fFlags & kLinearMetrics_Flag);
290 }
291
292 // DEPRECATED
isVertical()293 bool isVertical() const { return false; }
294
295 SkGlyph makeGlyph(SkPackedGlyphID, SkArenaAlloc*);
296 void getImage(const SkGlyph&);
297 void getPath(SkGlyph&, SkArenaAlloc*);
298 sk_sp<SkDrawable> getDrawable(SkGlyph&);
299 void getFontMetrics(SkFontMetrics*);
300
301 /** Return the size in bytes of the associated gamma lookup table
302 */
303 static size_t GetGammaLUTSize(SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma,
304 int* width, int* height);
305
306 /** Get the associated gamma lookup table. The 'data' pointer must point to pre-allocated
307 * memory, with size in bytes greater than or equal to the return value of getGammaLUTSize().
308 *
309 * If the lookup table hasn't been initialized (e.g., it's linear), this will return false.
310 */
311 static bool GetGammaLUTData(SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma,
312 uint8_t* data);
313
314 static void MakeRecAndEffects(const SkFont& font, const SkPaint& paint,
315 const SkSurfaceProps& surfaceProps,
316 SkScalerContextFlags scalerContextFlags,
317 const SkMatrix& deviceMatrix,
318 SkScalerContextRec* rec,
319 SkScalerContextEffects* effects);
320
321 // If we are creating rec and effects from a font only, then there is no device around either.
MakeRecAndEffectsFromFont(const SkFont & font,SkScalerContextRec * rec,SkScalerContextEffects * effects)322 static void MakeRecAndEffectsFromFont(const SkFont& font,
323 SkScalerContextRec* rec,
324 SkScalerContextEffects* effects) {
325 SkPaint paint;
326 return MakeRecAndEffects(
327 font, paint, SkSurfaceProps(),
328 SkScalerContextFlags::kNone, SkMatrix::I(), rec, effects);
329 }
330
331 static std::unique_ptr<SkScalerContext> MakeEmpty(
332 sk_sp<SkTypeface> typeface, const SkScalerContextEffects& effects,
333 const SkDescriptor* desc);
334
335 static SkDescriptor* AutoDescriptorGivenRecAndEffects(
336 const SkScalerContextRec& rec,
337 const SkScalerContextEffects& effects,
338 SkAutoDescriptor* ad);
339
340 static std::unique_ptr<SkDescriptor> DescriptorGivenRecAndEffects(
341 const SkScalerContextRec& rec,
342 const SkScalerContextEffects& effects);
343
344 static void DescriptorBufferGiveRec(const SkScalerContextRec& rec, void* buffer);
345 static bool CheckBufferSizeForRec(const SkScalerContextRec& rec,
346 const SkScalerContextEffects& effects,
347 size_t size);
348
349 static SkMaskGamma::PreBlend GetMaskPreBlend(const SkScalerContextRec& rec);
350
getRec()351 const SkScalerContextRec& getRec() const { return fRec; }
352
getEffects()353 SkScalerContextEffects getEffects() const {
354 return { fPathEffect.get(), fMaskFilter.get() };
355 }
356
357 /**
358 * Return the axis (if any) that the baseline for horizontal text should land on.
359 * As an example, the identity matrix will return kX_SkAxisAlignment
360 */
361 SkAxisAlignment computeAxisAlignmentForHText() const;
362
363 static SkDescriptor* CreateDescriptorAndEffectsUsingPaint(
364 const SkFont&, const SkPaint&, const SkSurfaceProps&,
365 SkScalerContextFlags scalerContextFlags,
366 const SkMatrix& deviceMatrix, SkAutoDescriptor* ad,
367 SkScalerContextEffects* effects);
368
369 protected:
370 SkScalerContextRec fRec;
371
372 /** Generates the contents of glyph.fAdvanceX and glyph.fAdvanceY if it can do so quickly.
373 * Returns true if it could, false otherwise.
374 */
375 virtual bool generateAdvance(SkGlyph* glyph) = 0;
376
377 /** Generates the contents of glyph.fWidth, fHeight, fTop, fLeft,
378 * as well as fAdvanceX and fAdvanceY if not already set.
379 * The fMaskFormat will already be set to a requested format but may be changed.
380 */
381 virtual void generateMetrics(SkGlyph* glyph, SkArenaAlloc*) = 0;
382
383 /** Generates the contents of glyph.fImage.
384 * When called, glyph.fImage will be pointing to a pre-allocated,
385 * uninitialized region of memory of size glyph.imageSize().
386 * This method may not change glyph.fMaskFormat.
387 *
388 * Because glyph.imageSize() will determine the size of fImage,
389 * generateMetrics will be called before generateImage.
390 */
391 virtual void generateImage(const SkGlyph& glyph) = 0;
392
393 /** Sets the passed path to the glyph outline.
394 * If this cannot be done the path is set to empty;
395 * Does not apply subpixel positioning to the path.
396 * @return false if this glyph does not have any path.
397 */
398 virtual bool SK_WARN_UNUSED_RESULT generatePath(const SkGlyph&, SkPath*) = 0;
399
400 /** Returns the drawable for the glyph (if any).
401 *
402 * The generated drawable will be lifetime scoped to the lifetime of this scaler context.
403 * This means the drawable may refer to the scaler context and associated font data.
404 *
405 * The drawable does not need to be flattenable (e.g. implement getFactory and getTypeName).
406 * Any necessary serialization will be done with newPictureSnapshot.
407 */
408 virtual sk_sp<SkDrawable> generateDrawable(const SkGlyph&); // TODO: = 0
409
410 /** Retrieves font metrics. */
411 virtual void generateFontMetrics(SkFontMetrics*) = 0;
412
forceGenerateImageFromPath()413 void forceGenerateImageFromPath() { fGenerateImageFromPath = true; }
forceOffGenerateImageFromPath()414 void forceOffGenerateImageFromPath() { fGenerateImageFromPath = false; }
415
416 private:
417 friend class PathText; // For debug purposes
418 friend class PathTextBench; // For debug purposes
419 friend class RandomScalerContext; // For debug purposes
420
421 static SkScalerContextRec PreprocessRec(const SkTypeface&,
422 const SkScalerContextEffects&,
423 const SkDescriptor&);
424
425 // never null
426 sk_sp<SkTypeface> fTypeface;
427
428 // optional objects, which may be null
429 sk_sp<SkPathEffect> fPathEffect;
430 sk_sp<SkMaskFilter> fMaskFilter;
431
432 // if this is set, we draw the image from a path, rather than
433 // calling generateImage.
434 bool fGenerateImageFromPath;
435
436 /** Returns false if the glyph has no path at all. */
437 void internalGetPath(SkGlyph&, SkArenaAlloc*);
438 SkGlyph internalMakeGlyph(SkPackedGlyphID, SkMask::Format, SkArenaAlloc*);
439
440 // SkMaskGamma::PreBlend converts linear masks to gamma correcting masks.
441 protected:
442 // Visible to subclasses so that generateImage can apply the pre-blend directly.
443 const SkMaskGamma::PreBlend fPreBlend;
444 };
445
446 #define kRec_SkDescriptorTag SkSetFourByteTag('s', 'r', 'e', 'c')
447 #define kEffects_SkDescriptorTag SkSetFourByteTag('e', 'f', 'c', 't')
448
449 ///////////////////////////////////////////////////////////////////////////////
450
getHinting()451 SkFontHinting SkScalerContextRec::getHinting() const {
452 unsigned hint = (fFlags & SkScalerContext::kHinting_Mask) >>
453 SkScalerContext::kHinting_Shift;
454 return static_cast<SkFontHinting>(hint);
455 }
456
setHinting(SkFontHinting hinting)457 void SkScalerContextRec::setHinting(SkFontHinting hinting) {
458 fFlags = (fFlags & ~SkScalerContext::kHinting_Mask) |
459 (static_cast<unsigned>(hinting) << SkScalerContext::kHinting_Shift);
460 }
461
462
463 #endif
464