• 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/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     uint32_t    fFontID;
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", 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);
296     void        getImage(const SkGlyph&);
297     bool SK_WARN_UNUSED_RESULT getPath(SkPackedGlyphID, SkPath*);
298     void        getFontMetrics(SkFontMetrics*);
299 
300     /** Return the size in bytes of the associated gamma lookup table
301      */
302     static size_t GetGammaLUTSize(SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma,
303                                   int* width, int* height);
304 
305     /** Get the associated gamma lookup table. The 'data' pointer must point to pre-allocated
306      *  memory, with size in bytes greater than or equal to the return value of getGammaLUTSize().
307      *
308      *  If the lookup table hasn't been initialized (e.g., it's linear), this will return false.
309      */
310     static bool   GetGammaLUTData(SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma,
311                                   uint8_t* data);
312 
313     static void MakeRecAndEffects(const SkFont& font, const SkPaint& paint,
314                                   const SkSurfaceProps& surfaceProps,
315                                   SkScalerContextFlags scalerContextFlags,
316                                   const SkMatrix& deviceMatrix,
317                                   SkScalerContextRec* rec,
318                                   SkScalerContextEffects* effects);
319 
320     // 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)321     static void MakeRecAndEffectsFromFont(const SkFont& font,
322                                           SkScalerContextRec* rec,
323                                           SkScalerContextEffects* effects) {
324         SkPaint paint;
325         return MakeRecAndEffects(
326                 font, paint, SkSurfaceProps(),
327                 SkScalerContextFlags::kNone, SkMatrix::I(), rec, effects);
328     }
329 
330     static std::unique_ptr<SkScalerContext> MakeEmpty(
331             sk_sp<SkTypeface> typeface, const SkScalerContextEffects& effects,
332             const SkDescriptor* desc);
333 
334     static SkDescriptor* AutoDescriptorGivenRecAndEffects(
335         const SkScalerContextRec& rec,
336         const SkScalerContextEffects& effects,
337         SkAutoDescriptor* ad);
338 
339     static std::unique_ptr<SkDescriptor> DescriptorGivenRecAndEffects(
340         const SkScalerContextRec& rec,
341         const SkScalerContextEffects& effects);
342 
343     static void DescriptorBufferGiveRec(const SkScalerContextRec& rec, void* buffer);
344     static bool CheckBufferSizeForRec(const SkScalerContextRec& rec,
345                                       const SkScalerContextEffects& effects,
346                                       size_t size);
347 
348     static SkMaskGamma::PreBlend GetMaskPreBlend(const SkScalerContextRec& rec);
349 
getRec()350     const SkScalerContextRec& getRec() const { return fRec; }
351 
getEffects()352     SkScalerContextEffects getEffects() const {
353         return { fPathEffect.get(), fMaskFilter.get() };
354     }
355 
356     /**
357     *  Return the axis (if any) that the baseline for horizontal text should land on.
358     *  As an example, the identity matrix will return kX_SkAxisAlignment
359     */
360     SkAxisAlignment computeAxisAlignmentForHText() const;
361 
362     static SkDescriptor* CreateDescriptorAndEffectsUsingPaint(
363         const SkFont&, const SkPaint&, const SkSurfaceProps&,
364         SkScalerContextFlags scalerContextFlags,
365         const SkMatrix& deviceMatrix, SkAutoDescriptor* ad,
366         SkScalerContextEffects* effects);
367 
368 protected:
369     SkScalerContextRec fRec;
370 
371     /** Generates the contents of glyph.fAdvanceX and glyph.fAdvanceY if it can do so quickly.
372      *  Returns true if it could, false otherwise.
373      */
374     virtual bool generateAdvance(SkGlyph* glyph) = 0;
375 
376     /** Generates the contents of glyph.fWidth, fHeight, fTop, fLeft,
377      *  as well as fAdvanceX and fAdvanceY if not already set.
378      *
379      *  TODO: fMaskFormat is set by internalMakeGlyph later; cannot be set here.
380      */
381     virtual void generateMetrics(SkGlyph* glyph) = 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 change glyph.fMaskFormat if the new image size is
387      *  less than or equal to the old image size.
388      *
389      *  Because glyph.imageSize() will determine the size of fImage,
390      *  generateMetrics will be called before generateImage.
391      */
392     virtual void generateImage(const SkGlyph& glyph) = 0;
393 
394     /** Sets the passed path to the glyph outline.
395      *  If this cannot be done the path is set to empty;
396      *  @return false if this glyph does not have any path.
397      */
398     virtual bool SK_WARN_UNUSED_RESULT generatePath(SkGlyphID glyphId, SkPath* path) = 0;
399 
400     /** Retrieves font metrics. */
401     virtual void generateFontMetrics(SkFontMetrics*) = 0;
402 
forceGenerateImageFromPath()403     void forceGenerateImageFromPath() { fGenerateImageFromPath = true; }
forceOffGenerateImageFromPath()404     void forceOffGenerateImageFromPath() { fGenerateImageFromPath = false; }
405 
406 private:
407     friend class RandomScalerContext;  // For debug purposes
408 
409     static SkScalerContextRec PreprocessRec(const SkTypeface& typeface,
410                                             const SkScalerContextEffects& effects,
411                                             const SkDescriptor& desc);
412 
413     // never null
414     sk_sp<SkTypeface> fTypeface;
415 
416     // optional objects, which may be null
417     sk_sp<SkPathEffect> fPathEffect;
418     sk_sp<SkMaskFilter> fMaskFilter;
419 
420     // if this is set, we draw the image from a path, rather than
421     // calling generateImage.
422     bool fGenerateImageFromPath;
423 
424     /** Returns false if the glyph has no path at all. */
425     bool internalGetPath(SkPackedGlyphID id, SkPath* devPath, bool* hairline);
426     SkGlyph internalMakeGlyph(SkPackedGlyphID packedID, SkMask::Format format);
427 
428     // SkMaskGamma::PreBlend converts linear masks to gamma correcting masks.
429 protected:
430     // Visible to subclasses so that generateImage can apply the pre-blend directly.
431     const SkMaskGamma::PreBlend fPreBlend;
432 };
433 
434 #define kRec_SkDescriptorTag            SkSetFourByteTag('s', 'r', 'e', 'c')
435 #define kEffects_SkDescriptorTag        SkSetFourByteTag('e', 'f', 'c', 't')
436 
437 ///////////////////////////////////////////////////////////////////////////////
438 
getHinting()439 SkFontHinting SkScalerContextRec::getHinting() const {
440     unsigned hint = (fFlags & SkScalerContext::kHinting_Mask) >>
441                                             SkScalerContext::kHinting_Shift;
442     return static_cast<SkFontHinting>(hint);
443 }
444 
setHinting(SkFontHinting hinting)445 void SkScalerContextRec::setHinting(SkFontHinting hinting) {
446     fFlags = (fFlags & ~SkScalerContext::kHinting_Mask) |
447                         (static_cast<unsigned>(hinting) << SkScalerContext::kHinting_Shift);
448 }
449 
450 
451 #endif
452