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