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 "SkGlyph.h"
14 #include "SkMask.h"
15 #include "SkMaskFilter.h"
16 #include "SkMaskGamma.h"
17 #include "SkMatrix.h"
18 #include "SkPaint.h"
19 #include "SkTypeface.h"
20 #include "SkWriteBuffer.h"
21 
22 class SkAutoDescriptor;
23 class SkDescriptor;
24 class SkMaskFilter;
25 class SkPathEffect;
26 class SkScalerContext;
27 class SkScalerContext_DW;
28 
29 enum SkScalerContextFlags : uint32_t {
30     kNone                      = 0,
31     kFakeGamma                 = 1 << 0,
32     kBoostContrast             = 1 << 1,
33     kFakeGammaAndBoostContrast = kFakeGamma | kBoostContrast,
34 };
35 
36 struct SkScalerContextEffects {
SkScalerContextEffectsSkScalerContextEffects37     SkScalerContextEffects() : fPathEffect(nullptr), fMaskFilter(nullptr) {}
SkScalerContextEffectsSkScalerContextEffects38     SkScalerContextEffects(SkPathEffect* pe, SkMaskFilter* mf)
39         : fPathEffect(pe), fMaskFilter(mf) {}
SkScalerContextEffectsSkScalerContextEffects40     explicit SkScalerContextEffects(const SkPaint& paint)
41         : fPathEffect(paint.getPathEffect())
42         , fMaskFilter(paint.getMaskFilter()) {}
43 
44     SkPathEffect*   fPathEffect;
45     SkMaskFilter*   fMaskFilter;
46 };
47 
48 enum SkAxisAlignment {
49     kNone_SkAxisAlignment,
50     kX_SkAxisAlignment,
51     kY_SkAxisAlignment
52 };
53 
54 /*
55  *  To allow this to be forward-declared, it must be its own typename, rather
56  *  than a nested struct inside SkScalerContext (where it started).
57  */
58 struct SkScalerContextRec {
59 
60     uint32_t    fFontID;
61     SkScalar    fTextSize, fPreScaleX, fPreSkewX;
62     SkScalar    fPost2x2[2][2];
63     SkScalar    fFrameWidth, fMiterLimit;
64 
65 private:
66     //These describe the parameters to create (uniquely identify) the pre-blend.
67     uint32_t      fLumBits;
68     uint8_t       fDeviceGamma; //2.6, (0.0, 4.0) gamma, 0.0 for sRGB
69     uint8_t       fPaintGamma;  //2.6, (0.0, 4.0) gamma, 0.0 for sRGB
70     uint8_t       fContrast;    //0.8+1, [0.0, 1.0] artificial contrast
71     const uint8_t fReservedAlign{0};
72 
73 public:
74 
getDeviceGammaSkScalerContextRec75     SkScalar getDeviceGamma() const {
76         return SkIntToScalar(fDeviceGamma) / (1 << 6);
77     }
setDeviceGammaSkScalerContextRec78     void setDeviceGamma(SkScalar dg) {
79         SkASSERT(0 <= dg && dg < SkIntToScalar(4));
80         fDeviceGamma = SkScalarFloorToInt(dg * (1 << 6));
81     }
82 
getPaintGammaSkScalerContextRec83     SkScalar getPaintGamma() const {
84         return SkIntToScalar(fPaintGamma) / (1 << 6);
85     }
setPaintGammaSkScalerContextRec86     void setPaintGamma(SkScalar pg) {
87         SkASSERT(0 <= pg && pg < SkIntToScalar(4));
88         fPaintGamma = SkScalarFloorToInt(pg * (1 << 6));
89     }
90 
getContrastSkScalerContextRec91     SkScalar getContrast() const {
92         return SkIntToScalar(fContrast) / ((1 << 8) - 1);
93     }
setContrastSkScalerContextRec94     void setContrast(SkScalar c) {
95         SkASSERT(0 <= c && c <= SK_Scalar1);
96         fContrast = SkScalarRoundToInt(c * ((1 << 8) - 1));
97     }
98 
99     /**
100      *  Causes the luminance color to be ignored, and the paint and device
101      *  gamma to be effectively 1.0
102      */
ignoreGammaSkScalerContextRec103     void ignoreGamma() {
104         setLuminanceColor(SK_ColorTRANSPARENT);
105         setPaintGamma(SK_Scalar1);
106         setDeviceGamma(SK_Scalar1);
107     }
108 
109     /**
110      *  Causes the luminance color and contrast to be ignored, and the
111      *  paint and device gamma to be effectively 1.0.
112      */
ignorePreBlendSkScalerContextRec113     void ignorePreBlend() {
114         ignoreGamma();
115         setContrast(0);
116     }
117 
118     uint8_t     fMaskFormat;
119 private:
120     uint8_t     fStrokeJoin : 4;
121     uint8_t     fStrokeCap : 4;
122 
123 public:
124     uint16_t    fFlags;
125 
126     // Warning: when adding members note that the size of this structure
127     // must be a multiple of 4. SkDescriptor requires that its arguments be
128     // multiples of four and this structure is put in an SkDescriptor in
129     // SkPaint::MakeRecAndEffects.
130 
dumpSkScalerContextRec131     SkString dump() const {
132         SkString msg;
133         msg.appendf("Rec\n");
134         msg.appendf("  textsize %g prescale %g preskew %g post [%g %g %g %g]\n",
135                    fTextSize, fPreScaleX, fPreSkewX, fPost2x2[0][0],
136                    fPost2x2[0][1], fPost2x2[1][0], fPost2x2[1][1]);
137         msg.appendf("  frame %g miter %g format %d join %d cap %d flags %#hx\n",
138                    fFrameWidth, fMiterLimit, fMaskFormat, fStrokeJoin, fStrokeCap, fFlags);
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 PreMatrixScale {
148         kFull_PreMatrixScale,  // The underlying port can apply both x and y scale.
149         kVertical_PreMatrixScale,  // The underlying port can only apply a y scale.
150         kVerticalInteger_PreMatrixScale  // 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     inline SkPaint::Hinting getHinting() const;
192     inline void setHinting(SkPaint::Hinting);
193 
getFormatSkScalerContextRec194     SkMask::Format getFormat() const {
195         return static_cast<SkMask::Format>(fMaskFormat);
196     }
197 
198 private:
199     // TODO: get rid of these bad friends.
200     friend class SkScalerContext;
201     friend class SkScalerContext_DW;
202 
getLuminanceColorSkScalerContextRec203     SkColor getLuminanceColor() const {
204         return fLumBits;
205     }
206 
207 
setLuminanceColorSkScalerContextRec208     void setLuminanceColor(SkColor c) {
209         fLumBits = c;
210     }
211 };
212 
213 //The following typedef hides from the rest of the implementation the number of
214 //most significant bits to consider when creating mask gamma tables. Two bits
215 //per channel was chosen as a balance between fidelity (more bits) and cache
216 //sizes (fewer bits). Three bits per channel was chosen when #303942; (used by
217 //the Chrome UI) turned out too green.
218 typedef SkTMaskGamma<3, 3, 3> SkMaskGamma;
219 
220 class SkScalerContext {
221 public:
222     enum Flags {
223         kFrameAndFill_Flag        = 0x0001,
224         kDevKernText_Flag         = 0x0002,
225         kEmbeddedBitmapText_Flag  = 0x0004,
226         kEmbolden_Flag            = 0x0008,
227         kSubpixelPositioning_Flag = 0x0010,
228         kForceAutohinting_Flag    = 0x0020,  // Use auto instead of bytcode hinting if hinting.
229         kVertical_Flag            = 0x0040,
230 
231         // together, these two flags resulting in a two bit value which matches
232         // up with the SkPaint::Hinting enum.
233         kHinting_Shift            = 7, // to shift into the other flags above
234         kHintingBit1_Flag         = 0x0080,
235         kHintingBit2_Flag         = 0x0100,
236 
237         // Pixel geometry information.
238         // only meaningful if fMaskFormat is kLCD16
239         kLCD_Vertical_Flag        = 0x0200,    // else Horizontal
240         kLCD_BGROrder_Flag        = 0x0400,    // else RGB order
241 
242         // Generate A8 from LCD source (for GDI and CoreGraphics).
243         // only meaningful if fMaskFormat is kA8
244         kGenA8FromLCD_Flag        = 0x0800, // could be 0x200 (bit meaning dependent on fMaskFormat)
245     };
246 
247     // computed values
248     enum {
249         kHinting_Mask   = kHintingBit1_Flag | kHintingBit2_Flag,
250     };
251 
252     SkScalerContext(sk_sp<SkTypeface>, const SkScalerContextEffects&, const SkDescriptor*);
253     virtual ~SkScalerContext();
254 
getTypeface()255     SkTypeface* getTypeface() const { return fTypeface.get(); }
256 
getMaskFormat()257     SkMask::Format getMaskFormat() const {
258         return (SkMask::Format)fRec.fMaskFormat;
259     }
260 
isSubpixel()261     bool isSubpixel() const {
262         return SkToBool(fRec.fFlags & kSubpixelPositioning_Flag);
263     }
264 
isVertical()265     bool isVertical() const {
266         return SkToBool(fRec.fFlags & kVertical_Flag);
267     }
268 
269     /** Return the corresponding glyph for the specified unichar. Since contexts
270         may be chained (under the hood), the glyphID that is returned may in
271         fact correspond to a different font/context. In that case, we use the
272         base-glyph-count to know how to translate back into local glyph space.
273      */
charToGlyphID(SkUnichar uni)274     uint16_t charToGlyphID(SkUnichar uni) {
275         return generateCharToGlyph(uni);
276     }
277 
278     /** Map the glyphID to its glyph index, and then to its char code. Unmapped
279         glyphs return zero.
280     */
glyphIDToChar(uint16_t glyphID)281     SkUnichar glyphIDToChar(uint16_t glyphID) {
282         return (glyphID < getGlyphCount()) ? generateGlyphToChar(glyphID) : 0;
283     }
284 
getGlyphCount()285     unsigned    getGlyphCount() { return this->generateGlyphCount(); }
286     void        getAdvance(SkGlyph*);
287     void        getMetrics(SkGlyph*);
288     void        getImage(const SkGlyph&);
289     void        getPath(SkPackedGlyphID, SkPath*);
290     void        getFontMetrics(SkPaint::FontMetrics*);
291 
292     /** Return the size in bytes of the associated gamma lookup table
293      */
294     static size_t GetGammaLUTSize(SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma,
295                                   int* width, int* height);
296 
297     /** Get the associated gamma lookup table. The 'data' pointer must point to pre-allocated
298      *  memory, with size in bytes greater than or equal to the return value of getGammaLUTSize().
299      *
300      *  If the lookup table hasn't been initialized (e.g., it's linear), this will return false.
301      */
302     static bool   GetGammaLUTData(SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma,
303                                   uint8_t* data);
304 
305     static void MakeRecAndEffects(const SkPaint& paint,
306                                   const SkSurfaceProps* surfaceProps,
307                                   const SkMatrix* deviceMatrix,
308                                   SkScalerContextFlags scalerContextFlags,
309                                   SkScalerContextRec* rec,
310                                   SkScalerContextEffects* effects);
311 
312     static SkDescriptor*  MakeDescriptorForPaths(SkFontID fontID,
313                                                  SkAutoDescriptor* ad);
314 
315     static SkDescriptor* AutoDescriptorGivenRecAndEffects(
316         const SkScalerContextRec& rec,
317         const SkScalerContextEffects& effects,
318         SkAutoDescriptor* ad);
319 
320     static std::unique_ptr<SkDescriptor> DescriptorGivenRecAndEffects(
321         const SkScalerContextRec& rec,
322         const SkScalerContextEffects& effects);
323 
324     static void DescriptorBufferGiveRec(const SkScalerContextRec& rec, void* buffer);
325     static bool CheckBufferSizeForRec(const SkScalerContextRec& rec,
326                                       const SkScalerContextEffects& effects,
327                                       size_t size);
328 
329     static SkMaskGamma::PreBlend GetMaskPreBlend(const SkScalerContextRec& rec);
330 
getRec()331     const SkScalerContextRec& getRec() const { return fRec; }
332 
getEffects()333     SkScalerContextEffects getEffects() const {
334         return { fPathEffect.get(), fMaskFilter.get() };
335     }
336 
337     /**
338     *  Return the axis (if any) that the baseline for horizontal text should land on.
339     *  As an example, the identity matrix will return kX_SkAxisAlignment
340     */
341     SkAxisAlignment computeAxisAlignmentForHText();
342 
343     static SkDescriptor* CreateDescriptorAndEffectsUsingPaint(
344         const SkPaint& paint, const SkSurfaceProps* surfaceProps,
345         SkScalerContextFlags scalerContextFlags,
346         const SkMatrix* deviceMatrix, SkAutoDescriptor* ad,
347         SkScalerContextEffects* effects);
348 
349 protected:
350     SkScalerContextRec fRec;
351 
352     /** Generates the contents of glyph.fAdvanceX and glyph.fAdvanceY.
353      *  May call getMetrics if that would be just as fast.
354      */
355     virtual void generateAdvance(SkGlyph* glyph) = 0;
356 
357     /** Generates the contents of glyph.fWidth, fHeight, fTop, fLeft,
358      *  as well as fAdvanceX and fAdvanceY if not already set.
359      *
360      *  TODO: fMaskFormat is set by getMetrics later; cannot be set here.
361      */
362     virtual void generateMetrics(SkGlyph* glyph) = 0;
363 
364     /** Generates the contents of glyph.fImage.
365      *  When called, glyph.fImage will be pointing to a pre-allocated,
366      *  uninitialized region of memory of size glyph.computeImageSize().
367      *  This method may change glyph.fMaskFormat if the new image size is
368      *  less than or equal to the old image size.
369      *
370      *  Because glyph.computeImageSize() will determine the size of fImage,
371      *  generateMetrics will be called before generateImage.
372      */
373     virtual void generateImage(const SkGlyph& glyph) = 0;
374 
375     /** Sets the passed path to the glyph outline.
376      *  If this cannot be done the path is set to empty;
377      *  this is indistinguishable from a glyph with an empty path.
378      */
379     virtual void generatePath(SkGlyphID glyphId, SkPath* path) = 0;
380 
381     /** Retrieves font metrics. */
382     virtual void generateFontMetrics(SkPaint::FontMetrics*) = 0;
383 
384     /** Returns the number of glyphs in the font. */
385     virtual unsigned generateGlyphCount() = 0;
386 
387     /** Returns the glyph id for the given unichar.
388      *  If there is no 1:1 mapping from the unichar to a glyph id, returns 0.
389      */
390     virtual uint16_t generateCharToGlyph(SkUnichar unichar) = 0;
391 
392     /** Returns the unichar for the given glyph id.
393      *  If there is no 1:1 mapping from the glyph id to a unichar, returns 0.
394      *  The default implementation always returns 0, indicating failure.
395      */
396     virtual SkUnichar generateGlyphToChar(uint16_t glyphId);
397 
forceGenerateImageFromPath()398     void forceGenerateImageFromPath() { fGenerateImageFromPath = true; }
forceOffGenerateImageFromPath()399     void forceOffGenerateImageFromPath() { fGenerateImageFromPath = false; }
400 
401 private:
402     friend class SkRandomScalerContext; // For debug purposes
403 
404     // never null
405     sk_sp<SkTypeface> fTypeface;
406 
407     // optional objects, which may be null
408     sk_sp<SkPathEffect> fPathEffect;
409     sk_sp<SkMaskFilter> fMaskFilter;
410 
411     // if this is set, we draw the image from a path, rather than
412     // calling generateImage.
413     bool fGenerateImageFromPath;
414 
415     /** Returns false if the glyph has no path at all. */
416     bool internalGetPath(SkPackedGlyphID id, SkPath* fillPath,
417                          SkPath* devPath, SkMatrix* fillToDevMatrix);
418 
419     // SkMaskGamma::PreBlend converts linear masks to gamma correcting masks.
420 protected:
421     // Visible to subclasses so that generateImage can apply the pre-blend directly.
422     const SkMaskGamma::PreBlend fPreBlend;
423 private:
424     // When there is a filter, previous steps must create a linear mask
425     // and the pre-blend applied as a final step.
426     const SkMaskGamma::PreBlend fPreBlendForFilter;
427 };
428 
429 #define kRec_SkDescriptorTag            SkSetFourByteTag('s', 'r', 'e', 'c')
430 #define kPathEffect_SkDescriptorTag     SkSetFourByteTag('p', 't', 'h', 'e')
431 #define kMaskFilter_SkDescriptorTag     SkSetFourByteTag('m', 's', 'k', 'f')
432 
433 ///////////////////////////////////////////////////////////////////////////////
434 
getHinting()435 SkPaint::Hinting SkScalerContextRec::getHinting() const {
436     unsigned hint = (fFlags & SkScalerContext::kHinting_Mask) >>
437                                             SkScalerContext::kHinting_Shift;
438     return static_cast<SkPaint::Hinting>(hint);
439 }
440 
setHinting(SkPaint::Hinting hinting)441 void SkScalerContextRec::setHinting(SkPaint::Hinting hinting) {
442     fFlags = (fFlags & ~SkScalerContext::kHinting_Mask) |
443                                 (hinting << SkScalerContext::kHinting_Shift);
444 }
445 
446 
447 #endif
448