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 "SkFont.h"
14 #include "SkFontTypes.h"
15 #include "SkGlyph.h"
16 #include "SkMacros.h"
17 #include "SkMask.h"
18 #include "SkMaskFilter.h"
19 #include "SkMaskGamma.h"
20 #include "SkMatrix.h"
21 #include "SkPaint.h"
22 #include "SkStrikeInterface.h"
23 #include "SkSurfacePriv.h"
24 #include "SkTypeface.h"
25 #include "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 private:
62     //These describe the parameters to create (uniquely identify) the pre-blend.
63     uint32_t      fLumBits;
64     uint8_t       fDeviceGamma; //2.6, (0.0, 4.0) gamma, 0.0 for sRGB
65     uint8_t       fPaintGamma;  //2.6, (0.0, 4.0) gamma, 0.0 for sRGB
66     uint8_t       fContrast;    //0.8+1, [0.0, 1.0] artificial contrast
67     const uint8_t fReservedAlign{0};
68 
69 public:
70 
getDeviceGammaSkScalerContextRec71     SkScalar getDeviceGamma() const {
72         return SkIntToScalar(fDeviceGamma) / (1 << 6);
73     }
setDeviceGammaSkScalerContextRec74     void setDeviceGamma(SkScalar dg) {
75         SkASSERT(0 <= dg && dg < SkIntToScalar(4));
76         fDeviceGamma = SkScalarFloorToInt(dg * (1 << 6));
77     }
78 
getPaintGammaSkScalerContextRec79     SkScalar getPaintGamma() const {
80         return SkIntToScalar(fPaintGamma) / (1 << 6);
81     }
setPaintGammaSkScalerContextRec82     void setPaintGamma(SkScalar pg) {
83         SkASSERT(0 <= pg && pg < SkIntToScalar(4));
84         fPaintGamma = SkScalarFloorToInt(pg * (1 << 6));
85     }
86 
getContrastSkScalerContextRec87     SkScalar getContrast() const {
88         sk_ignore_unused_variable(fReservedAlign);
89         return SkIntToScalar(fContrast) / ((1 << 8) - 1);
90     }
setContrastSkScalerContextRec91     void setContrast(SkScalar c) {
92         SkASSERT(0 <= c && c <= SK_Scalar1);
93         fContrast = SkScalarRoundToInt(c * ((1 << 8) - 1));
94     }
95 
96     /**
97      *  Causes the luminance color to be ignored, and the paint and device
98      *  gamma to be effectively 1.0
99      */
ignoreGammaSkScalerContextRec100     void ignoreGamma() {
101         setLuminanceColor(SK_ColorTRANSPARENT);
102         setPaintGamma(SK_Scalar1);
103         setDeviceGamma(SK_Scalar1);
104     }
105 
106     /**
107      *  Causes the luminance color and contrast to be ignored, and the
108      *  paint and device gamma to be effectively 1.0.
109      */
ignorePreBlendSkScalerContextRec110     void ignorePreBlend() {
111         ignoreGamma();
112         setContrast(0);
113     }
114 
115     uint8_t     fMaskFormat;
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 %g prescale %g preskew %g post [%g %g %g %g]\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         return msg;
139     }
140 
141     void    getMatrixFrom2x2(SkMatrix*) const;
142     void    getLocalMatrix(SkMatrix*) const;
143     void    getSingleMatrix(SkMatrix*) const;
144 
145     /** The kind of scale which will be applied by the underlying port (pre-matrix). */
146     enum PreMatrixScale {
147         kFull_PreMatrixScale,  // The underlying port can apply both x and y scale.
148         kVertical_PreMatrixScale,  // The underlying port can only apply a y scale.
149         kVerticalInteger_PreMatrixScale  // The underlying port can only apply an integer y scale.
150     };
151     /**
152      *  Compute useful matrices for use with sizing in underlying libraries.
153      *
154      *  There are two kinds of text size, a 'requested/logical size' which is like asking for size
155      *  '12' and a 'real' size which is the size after the matrix is applied. The matrices produced
156      *  by this method are based on the 'real' size. This method effectively finds the total device
157      *  matrix and decomposes it in various ways.
158      *
159      *  The most useful decomposition is into 'scale' and 'remaining'. The 'scale' is applied first
160      *  and then the 'remaining' to fully apply the total matrix. This decomposition is useful when
161      *  the text size ('scale') may have meaning apart from the total matrix. This is true when
162      *  hinting, and sometimes true for other properties as well.
163      *
164      *  The second (optional) decomposition is of 'remaining' into a non-rotational part
165      *  'remainingWithoutRotation' and a rotational part 'remainingRotation'. The 'scale' is applied
166      *  first, then 'remainingWithoutRotation', then 'remainingRotation' to fully apply the total
167      *  matrix. This decomposition is helpful when only horizontal metrics can be trusted, so the
168      *  'scale' and 'remainingWithoutRotation' will be handled by the underlying library, but
169      *  the final rotation 'remainingRotation' will be handled manually.
170      *
171      *  The 'total' matrix is also (optionally) available. This is useful in cases where the
172      *  underlying library will not be used, often when working directly with font data.
173      *
174      *  The parameters 'scale' and 'remaining' are required, the other pointers may be nullptr.
175      *
176      *  @param preMatrixScale the kind of scale to extract from the total matrix.
177      *  @param scale the scale extracted from the total matrix (both values positive).
178      *  @param remaining apply after scale to apply the total matrix.
179      *  @param remainingWithoutRotation apply after scale to apply the total matrix sans rotation.
180      *  @param remainingRotation apply after remainingWithoutRotation to apply the total matrix.
181      *  @param total the total matrix.
182      *  @return false if the matrix was singular. The output will be valid but not invertible.
183      */
184     bool computeMatrices(PreMatrixScale preMatrixScale,
185                          SkVector* scale, SkMatrix* remaining,
186                          SkMatrix* remainingWithoutRotation = nullptr,
187                          SkMatrix* remainingRotation = nullptr,
188                          SkMatrix* total = nullptr);
189 
190     SkAxisAlignment computeAxisAlignmentForHText() const;
191 
192     inline SkFontHinting getHinting() const;
193     inline void setHinting(SkFontHinting);
194 
getFormatSkScalerContextRec195     SkMask::Format getFormat() const {
196         return static_cast<SkMask::Format>(fMaskFormat);
197     }
198 
getLuminanceColorSkScalerContextRec199     SkColor getLuminanceColor() const {
200         return fLumBits;
201     }
202 
203     // setLuminanceColor forces the alpha to be 0xFF because the blitter that draws the glyph
204     // will apply the alpha from the paint. Don't apply the alpha twice.
setLuminanceColorSkScalerContextRec205     void setLuminanceColor(SkColor c) {
206         fLumBits = SkColorSetRGB(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c));
207     }
208 
209 private:
210     // TODO: remove
211     friend class SkScalerContext;
212 };
213 SK_END_REQUIRE_DENSE
214 
215 //The following typedef hides from the rest of the implementation the number of
216 //most significant bits to consider when creating mask gamma tables. Two bits
217 //per channel was chosen as a balance between fidelity (more bits) and cache
218 //sizes (fewer bits). Three bits per channel was chosen when #303942; (used by
219 //the Chrome UI) turned out too green.
220 typedef SkTMaskGamma<3, 3, 3> SkMaskGamma;
221 
222 class SkScalerContext {
223 public:
224     enum Flags {
225         kFrameAndFill_Flag        = 0x0001,
226         kUnused                   = 0x0002,
227         kEmbeddedBitmapText_Flag  = 0x0004,
228         kEmbolden_Flag            = 0x0008,
229         kSubpixelPositioning_Flag = 0x0010,
230         kForceAutohinting_Flag    = 0x0020,  // Use auto instead of bytcode hinting if hinting.
231 
232         // together, these two flags resulting in a two bit value which matches
233         // up with the SkPaint::Hinting enum.
234         kHinting_Shift            = 7, // to shift into the other flags above
235         kHintingBit1_Flag         = 0x0080,
236         kHintingBit2_Flag         = 0x0100,
237 
238         // Pixel geometry information.
239         // only meaningful if fMaskFormat is kLCD16
240         kLCD_Vertical_Flag        = 0x0200,    // else Horizontal
241         kLCD_BGROrder_Flag        = 0x0400,    // else RGB order
242 
243         // Generate A8 from LCD source (for GDI and CoreGraphics).
244         // only meaningful if fMaskFormat is kA8
245         kGenA8FromLCD_Flag        = 0x0800, // could be 0x200 (bit meaning dependent on fMaskFormat)
246     };
247 
248     // computed values
249     enum {
250         kHinting_Mask   = kHintingBit1_Flag | kHintingBit2_Flag,
251     };
252 
253     SkScalerContext(sk_sp<SkTypeface>, const SkScalerContextEffects&, const SkDescriptor*);
254     virtual ~SkScalerContext();
255 
getTypeface()256     SkTypeface* getTypeface() const { return fTypeface.get(); }
257 
getMaskFormat()258     SkMask::Format getMaskFormat() const {
259         return (SkMask::Format)fRec.fMaskFormat;
260     }
261 
isSubpixel()262     bool isSubpixel() const {
263         return SkToBool(fRec.fFlags & kSubpixelPositioning_Flag);
264     }
265 
266     // DEPRECATED
isVertical()267     bool isVertical() const { return false; }
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 
getGlyphCount()278     unsigned    getGlyphCount() { return this->generateGlyphCount(); }
279     void        getAdvance(SkGlyph*);
280     void        getMetrics(SkGlyph*);
281     void        getImage(const SkGlyph&);
282     bool SK_WARN_UNUSED_RESULT getPath(SkPackedGlyphID, SkPath*);
283     void        getFontMetrics(SkFontMetrics*);
284 
285     /** Return the size in bytes of the associated gamma lookup table
286      */
287     static size_t GetGammaLUTSize(SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma,
288                                   int* width, int* height);
289 
290     /** Get the associated gamma lookup table. The 'data' pointer must point to pre-allocated
291      *  memory, with size in bytes greater than or equal to the return value of getGammaLUTSize().
292      *
293      *  If the lookup table hasn't been initialized (e.g., it's linear), this will return false.
294      */
295     static bool   GetGammaLUTData(SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma,
296                                   uint8_t* data);
297 
298     static void MakeRecAndEffects(const SkFont& font, const SkPaint& paint,
299                                   const SkSurfaceProps& surfaceProps,
300                                   SkScalerContextFlags scalerContextFlags,
301                                   const SkMatrix& deviceMatrix,
302                                   SkScalerContextRec* rec,
303                                   SkScalerContextEffects* effects);
304 
305     // 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)306     static void MakeRecAndEffectsFromFont(const SkFont& font,
307                                           SkScalerContextRec* rec,
308                                           SkScalerContextEffects* effects) {
309         SkPaint paint;
310         return MakeRecAndEffects(
311                 font, paint, SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType),
312                 SkScalerContextFlags::kNone, SkMatrix::I(), rec, effects);
313     }
314 
315     static SkDescriptor*  MakeDescriptorForPaths(SkFontID fontID,
316                                                  SkAutoDescriptor* ad);
317 
318     static SkDescriptor* AutoDescriptorGivenRecAndEffects(
319         const SkScalerContextRec& rec,
320         const SkScalerContextEffects& effects,
321         SkAutoDescriptor* ad);
322 
323     static std::unique_ptr<SkDescriptor> DescriptorGivenRecAndEffects(
324         const SkScalerContextRec& rec,
325         const SkScalerContextEffects& effects);
326 
327     static void DescriptorBufferGiveRec(const SkScalerContextRec& rec, void* buffer);
328     static bool CheckBufferSizeForRec(const SkScalerContextRec& rec,
329                                       const SkScalerContextEffects& effects,
330                                       size_t size);
331 
332     static SkMaskGamma::PreBlend GetMaskPreBlend(const SkScalerContextRec& rec);
333 
getRec()334     const SkScalerContextRec& getRec() const { return fRec; }
335 
getEffects()336     SkScalerContextEffects getEffects() const {
337         return { fPathEffect.get(), fMaskFilter.get() };
338     }
339 
340     /**
341     *  Return the axis (if any) that the baseline for horizontal text should land on.
342     *  As an example, the identity matrix will return kX_SkAxisAlignment
343     */
344     SkAxisAlignment computeAxisAlignmentForHText() const;
345 
346     static SkDescriptor* CreateDescriptorAndEffectsUsingPaint(
347         const SkFont&, const SkPaint&, const SkSurfaceProps&,
348         SkScalerContextFlags scalerContextFlags,
349         const SkMatrix& deviceMatrix, SkAutoDescriptor* ad,
350         SkScalerContextEffects* effects);
351 
352 protected:
353     SkScalerContextRec fRec;
354 
355     /** Generates the contents of glyph.fAdvanceX and glyph.fAdvanceY if it can do so quickly.
356      *  Returns true if it could, false otherwise.
357      */
358     virtual bool generateAdvance(SkGlyph* glyph) = 0;
359 
360     /** Generates the contents of glyph.fWidth, fHeight, fTop, fLeft,
361      *  as well as fAdvanceX and fAdvanceY if not already set.
362      *
363      *  TODO: fMaskFormat is set by getMetrics later; cannot be set here.
364      */
365     virtual void generateMetrics(SkGlyph* glyph) = 0;
366 
367     /** Generates the contents of glyph.fImage.
368      *  When called, glyph.fImage will be pointing to a pre-allocated,
369      *  uninitialized region of memory of size glyph.computeImageSize().
370      *  This method may change glyph.fMaskFormat if the new image size is
371      *  less than or equal to the old image size.
372      *
373      *  Because glyph.computeImageSize() will determine the size of fImage,
374      *  generateMetrics will be called before generateImage.
375      */
376     virtual void generateImage(const SkGlyph& glyph) = 0;
377 
378     /** Sets the passed path to the glyph outline.
379      *  If this cannot be done the path is set to empty;
380      *  @return false if this glyph does not have any path.
381      */
382     virtual bool SK_WARN_UNUSED_RESULT generatePath(SkGlyphID glyphId, SkPath* path) = 0;
383 
384     /** Retrieves font metrics. */
385     virtual void generateFontMetrics(SkFontMetrics*) = 0;
386 
387     /** Returns the number of glyphs in the font. */
388     virtual unsigned generateGlyphCount() = 0;
389 
390     /** Returns the glyph id for the given unichar.
391      *  If there is no 1:1 mapping from the unichar to a glyph id, returns 0.
392      */
393     virtual uint16_t generateCharToGlyph(SkUnichar unichar) = 0;
394 
forceGenerateImageFromPath()395     void forceGenerateImageFromPath() { fGenerateImageFromPath = true; }
forceOffGenerateImageFromPath()396     void forceOffGenerateImageFromPath() { fGenerateImageFromPath = false; }
397 
398 private:
399     friend class SkRandomScalerContext; // For debug purposes
400 
401     static SkScalerContextRec PreprocessRec(const SkTypeface& typeface,
402                                             const SkScalerContextEffects& effects,
403                                             const SkDescriptor& desc);
404 
405     // never null
406     sk_sp<SkTypeface> fTypeface;
407 
408     // optional objects, which may be null
409     sk_sp<SkPathEffect> fPathEffect;
410     sk_sp<SkMaskFilter> fMaskFilter;
411 
412     // if this is set, we draw the image from a path, rather than
413     // calling generateImage.
414     bool fGenerateImageFromPath;
415 
416     /** Returns false if the glyph has no path at all. */
417     bool internalGetPath(SkPackedGlyphID id, SkPath* devPath);
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 };
424 
425 #define kRec_SkDescriptorTag            SkSetFourByteTag('s', 'r', 'e', 'c')
426 #define kEffects_SkDescriptorTag        SkSetFourByteTag('e', 'f', 'c', 't')
427 
428 ///////////////////////////////////////////////////////////////////////////////
429 
getHinting()430 SkFontHinting SkScalerContextRec::getHinting() const {
431     unsigned hint = (fFlags & SkScalerContext::kHinting_Mask) >>
432                                             SkScalerContext::kHinting_Shift;
433     return static_cast<SkFontHinting>(hint);
434 }
435 
setHinting(SkFontHinting hinting)436 void SkScalerContextRec::setHinting(SkFontHinting hinting) {
437     fFlags = (fFlags & ~SkScalerContext::kHinting_Mask) |
438                         (static_cast<unsigned>(hinting) << SkScalerContext::kHinting_Shift);
439 }
440 
441 
442 #endif
443