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 "SkMask.h"
12#include "SkMaskGamma.h"
13#include "SkMatrix.h"
14#include "SkPaint.h"
15#include "SkTypeface.h"
16
17class SkGlyph;
18class SkDescriptor;
19class SkMaskFilter;
20class SkPathEffect;
21class SkRasterizer;
22
23/*
24 *  To allow this to be forward-declared, it must be its own typename, rather
25 *  than a nested struct inside SkScalerContext (where it started).
26 */
27struct SkScalerContextRec {
28    uint32_t    fFontID;
29    SkScalar    fTextSize, fPreScaleX, fPreSkewX;
30    SkScalar    fPost2x2[2][2];
31    SkScalar    fFrameWidth, fMiterLimit;
32
33    //These describe the parameters to create (uniquely identify) the pre-blend.
34    uint32_t    fLumBits;
35    uint8_t     fDeviceGamma; //2.6, (0.0, 4.0) gamma, 0.0 for sRGB
36    uint8_t     fPaintGamma;  //2.6, (0.0, 4.0) gamma, 0.0 for sRGB
37    uint8_t     fContrast;    //0.8+1, [0.0, 1.0] artificial contrast
38    uint8_t     fReservedAlign;
39
40    SkScalar getDeviceGamma() const {
41        return SkIntToScalar(fDeviceGamma) / (1 << 6);
42    }
43    void setDeviceGamma(SkScalar dg) {
44        SkASSERT(0 <= dg && dg < SkIntToScalar(4));
45        fDeviceGamma = SkScalarFloorToInt(dg * (1 << 6));
46    }
47
48    SkScalar getPaintGamma() const {
49        return SkIntToScalar(fPaintGamma) / (1 << 6);
50    }
51    void setPaintGamma(SkScalar pg) {
52        SkASSERT(0 <= pg && pg < SkIntToScalar(4));
53        fPaintGamma = SkScalarFloorToInt(pg * (1 << 6));
54    }
55
56    SkScalar getContrast() const {
57        return SkIntToScalar(fContrast) / ((1 << 8) - 1);
58    }
59    void setContrast(SkScalar c) {
60        SkASSERT(0 <= c && c <= SK_Scalar1);
61        fContrast = SkScalarRoundToInt(c * ((1 << 8) - 1));
62    }
63
64    /**
65     *  Causes the luminance color and contrast to be ignored, and the
66     *  paint and device gamma to be effectively 1.0.
67     */
68    void ignorePreBlend() {
69        setLuminanceColor(SK_ColorTRANSPARENT);
70        setPaintGamma(SK_Scalar1);
71        setDeviceGamma(SK_Scalar1);
72        setContrast(0);
73    }
74
75    uint8_t     fMaskFormat;
76    uint8_t     fStrokeJoin;
77    uint16_t    fFlags;
78    // Warning: when adding members note that the size of this structure
79    // must be a multiple of 4. SkDescriptor requires that its arguments be
80    // multiples of four and this structure is put in an SkDescriptor in
81    // SkPaint::MakeRec.
82
83    void    getMatrixFrom2x2(SkMatrix*) const;
84    void    getLocalMatrix(SkMatrix*) const;
85    void    getSingleMatrix(SkMatrix*) const;
86
87    /** The kind of scale which will be applied by the underlying port (pre-matrix). */
88    enum PreMatrixScale {
89        kFull_PreMatrixScale,  // The underlying port can apply both x and y scale.
90        kVertical_PreMatrixScale,  // The underlying port can only apply a y scale.
91        kVerticalInteger_PreMatrixScale  // The underlying port can only apply an integer y scale.
92    };
93    /**
94     *  Compute useful matrices for use with sizing in underlying libraries.
95     *
96     *  There are two kinds of text size, a 'requested/logical size' which is like asking for size
97     *  '12' and a 'real' size which is the size after the matrix is applied. The matrices produced
98     *  by this method are based on the 'real' size. This method effectively finds the total device
99     *  matrix and decomposes it in various ways.
100     *
101     *  The most useful decomposition is into 'scale' and 'remaining'. The 'scale' is applied first
102     *  and then the 'remaining' to fully apply the total matrix. This decomposition is useful when
103     *  the text size ('scale') may have meaning apart from the total matrix. This is true when
104     *  hinting, and sometimes true for other properties as well.
105     *
106     *  The second (optional) decomposition is of 'remaining' into a non-rotational part
107     *  'remainingWithoutRotation' and a rotational part 'remainingRotation'. The 'scale' is applied
108     *  first, then 'remainingWithoutRotation', then 'remainingRotation' to fully apply the total
109     *  matrix. This decomposition is helpful when only horizontal metrics can be trusted, so the
110     *  'scale' and 'remainingWithoutRotation' will be handled by the underlying library, but
111     *  the final rotation 'remainingRotation' will be handled manually.
112     *
113     *  The 'total' matrix is also (optionally) available. This is useful in cases where the
114     *  underlying library will not be used, often when working directly with font data.
115     *
116     *  The parameters 'scale' and 'remaining' are required, the other pointers may be NULL.
117     *
118     *  @param preMatrixScale the kind of scale to extract from the total matrix.
119     *  @param scale the scale extracted from the total matrix (both values positive).
120     *  @param remaining apply after scale to apply the total matrix.
121     *  @param remainingWithoutRotation apply after scale to apply the total matrix sans rotation.
122     *  @param remainingRotation apply after remainingWithoutRotation to apply the total matrix.
123     *  @param total the total matrix.
124     */
125    void computeMatrices(PreMatrixScale preMatrixScale,
126                         SkVector* scale, SkMatrix* remaining,
127                         SkMatrix* remainingWithoutRotation = NULL,
128                         SkMatrix* remainingRotation = NULL,
129                         SkMatrix* total = NULL);
130
131    inline SkPaint::Hinting getHinting() const;
132    inline void setHinting(SkPaint::Hinting);
133
134    SkMask::Format getFormat() const {
135        return static_cast<SkMask::Format>(fMaskFormat);
136    }
137
138    SkColor getLuminanceColor() const {
139        return fLumBits;
140    }
141
142    void setLuminanceColor(SkColor c) {
143        fLumBits = c;
144    }
145};
146
147//The following typedef hides from the rest of the implementation the number of
148//most significant bits to consider when creating mask gamma tables. Two bits
149//per channel was chosen as a balance between fidelity (more bits) and cache
150//sizes (fewer bits). Three bits per channel was chosen when #303942; (used by
151//the Chrome UI) turned out too green.
152typedef SkTMaskGamma<3, 3, 3> SkMaskGamma;
153
154class SkScalerContext {
155public:
156    typedef SkScalerContextRec Rec;
157
158    enum Flags {
159        kFrameAndFill_Flag        = 0x0001,
160        kDevKernText_Flag         = 0x0002,
161        kEmbeddedBitmapText_Flag  = 0x0004,
162        kEmbolden_Flag            = 0x0008,
163        kSubpixelPositioning_Flag = 0x0010,
164        kForceAutohinting_Flag    = 0x0020,  // Use auto instead of bytcode hinting if hinting.
165        kVertical_Flag            = 0x0040,
166
167        // together, these two flags resulting in a two bit value which matches
168        // up with the SkPaint::Hinting enum.
169        kHinting_Shift            = 7, // to shift into the other flags above
170        kHintingBit1_Flag         = 0x0080,
171        kHintingBit2_Flag         = 0x0100,
172
173        // Pixel geometry information.
174        // only meaningful if fMaskFormat is kLCD16
175        kLCD_Vertical_Flag        = 0x0200,    // else Horizontal
176        kLCD_BGROrder_Flag        = 0x0400,    // else RGB order
177
178        // Generate A8 from LCD source (for GDI and CoreGraphics).
179        // only meaningful if fMaskFormat is kA8
180        kGenA8FromLCD_Flag        = 0x0800, // could be 0x200 (bit meaning dependent on fMaskFormat)
181    };
182
183    // computed values
184    enum {
185        kHinting_Mask   = kHintingBit1_Flag | kHintingBit2_Flag,
186    };
187
188
189    SkScalerContext(SkTypeface*, const SkDescriptor*);
190    virtual ~SkScalerContext();
191
192    SkTypeface* getTypeface() const { return fTypeface.get(); }
193
194    SkMask::Format getMaskFormat() const {
195        return (SkMask::Format)fRec.fMaskFormat;
196    }
197
198    bool isSubpixel() const {
199        return SkToBool(fRec.fFlags & kSubpixelPositioning_Flag);
200    }
201
202    bool isVertical() const {
203        return SkToBool(fRec.fFlags & kVertical_Flag);
204    }
205
206    /** Return the corresponding glyph for the specified unichar. Since contexts
207        may be chained (under the hood), the glyphID that is returned may in
208        fact correspond to a different font/context. In that case, we use the
209        base-glyph-count to know how to translate back into local glyph space.
210     */
211    uint16_t charToGlyphID(SkUnichar uni) {
212        return generateCharToGlyph(uni);
213    }
214
215    /** Map the glyphID to its glyph index, and then to its char code. Unmapped
216        glyphs return zero.
217    */
218    SkUnichar glyphIDToChar(uint16_t glyphID) {
219        return (glyphID < getGlyphCount()) ? generateGlyphToChar(glyphID) : 0;
220    }
221
222    unsigned    getGlyphCount() { return this->generateGlyphCount(); }
223    void        getAdvance(SkGlyph*);
224    void        getMetrics(SkGlyph*);
225    void        getImage(const SkGlyph&);
226    void        getPath(const SkGlyph&, SkPath*);
227    void        getFontMetrics(SkPaint::FontMetrics*);
228
229    /** Return the size in bytes of the associated gamma lookup table
230     */
231    static size_t GetGammaLUTSize(SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma,
232                                  int* width, int* height);
233
234    /** Get the associated gamma lookup table. The 'data' pointer must point to pre-allocated
235        memory, with size in bytes greater than or equal to the return value of getGammaLUTSize().
236     */
237    static void   GetGammaLUTData(SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma,
238                                  void* data);
239
240    static void MakeRec(const SkPaint&, const SkDeviceProperties* deviceProperties,
241                        const SkMatrix*, Rec* rec);
242    static inline void PostMakeRec(const SkPaint&, Rec*);
243
244    static SkMaskGamma::PreBlend GetMaskPreBlend(const Rec& rec);
245
246    const Rec& getRec() const { return fRec; }
247
248protected:
249    Rec         fRec;
250
251    /** Generates the contents of glyph.fAdvanceX and glyph.fAdvanceY.
252     *  May call getMetrics if that would be just as fast.
253     */
254    virtual void generateAdvance(SkGlyph* glyph) = 0;
255
256    /** Generates the contents of glyph.fWidth, fHeight, fTop, fLeft,
257     *  as well as fAdvanceX and fAdvanceY if not already set.
258     *
259     *  TODO: fMaskFormat is set by getMetrics later; cannot be set here.
260     */
261    virtual void generateMetrics(SkGlyph* glyph) = 0;
262
263    /** Generates the contents of glyph.fImage.
264     *  When called, glyph.fImage will be pointing to a pre-allocated,
265     *  uninitialized region of memory of size glyph.computeImageSize().
266     *  This method may change glyph.fMaskFormat if the new image size is
267     *  less than or equal to the old image size.
268     *
269     *  Because glyph.computeImageSize() will determine the size of fImage,
270     *  generateMetrics will be called before generateImage.
271     */
272    virtual void generateImage(const SkGlyph& glyph) = 0;
273
274    /** Sets the passed path to the glyph outline.
275     *  If this cannot be done the path is set to empty;
276     *  this is indistinguishable from a glyph with an empty path.
277     *  This does not set glyph.fPath.
278     *
279     *  TODO: path is always glyph.fPath, no reason to pass separately.
280     */
281    virtual void generatePath(const SkGlyph& glyph, SkPath* path) = 0;
282
283    /** Retrieves font metrics. */
284    virtual void generateFontMetrics(SkPaint::FontMetrics*) = 0;
285
286    /** Returns the number of glyphs in the font. */
287    virtual unsigned generateGlyphCount() = 0;
288
289    /** Returns the glyph id for the given unichar.
290     *  If there is no 1:1 mapping from the unichar to a glyph id, returns 0.
291     */
292    virtual uint16_t generateCharToGlyph(SkUnichar unichar) = 0;
293
294    /** Returns the unichar for the given glyph id.
295     *  If there is no 1:1 mapping from the glyph id to a unichar, returns 0.
296     *  The default implementation always returns 0, indicating failure.
297     */
298    virtual SkUnichar generateGlyphToChar(uint16_t glyphId);
299
300    void forceGenerateImageFromPath() { fGenerateImageFromPath = true; }
301
302private:
303    // never null
304    SkAutoTUnref<SkTypeface> fTypeface;
305
306    // optional object, which may be null
307    SkPathEffect*   fPathEffect;
308    SkMaskFilter*   fMaskFilter;
309    SkRasterizer*   fRasterizer;
310
311    // if this is set, we draw the image from a path, rather than
312    // calling generateImage.
313    bool fGenerateImageFromPath;
314
315    void internalGetPath(const SkGlyph& glyph, SkPath* fillPath,
316                         SkPath* devPath, SkMatrix* fillToDevMatrix);
317
318    // returns the right context from our link-list for this char. If no match
319    // is found it returns NULL. If a match is found then the glyphID param is
320    // set to the glyphID that maps to the provided char.
321    SkScalerContext* getContextFromChar(SkUnichar uni, uint16_t* glyphID);
322
323    // SkMaskGamma::PreBlend converts linear masks to gamma correcting masks.
324protected:
325    // Visible to subclasses so that generateImage can apply the pre-blend directly.
326    const SkMaskGamma::PreBlend fPreBlend;
327private:
328    // When there is a filter, previous steps must create a linear mask
329    // and the pre-blend applied as a final step.
330    const SkMaskGamma::PreBlend fPreBlendForFilter;
331};
332
333#define kRec_SkDescriptorTag            SkSetFourByteTag('s', 'r', 'e', 'c')
334#define kPathEffect_SkDescriptorTag     SkSetFourByteTag('p', 't', 'h', 'e')
335#define kMaskFilter_SkDescriptorTag     SkSetFourByteTag('m', 's', 'k', 'f')
336#define kRasterizer_SkDescriptorTag     SkSetFourByteTag('r', 'a', 's', 't')
337
338///////////////////////////////////////////////////////////////////////////////
339
340enum SkAxisAlignment {
341    kNone_SkAxisAlignment,
342    kX_SkAxisAlignment,
343    kY_SkAxisAlignment
344};
345
346/**
347 *  Return the axis (if any) that the baseline for horizontal text will land on
348 *  after running through the specified matrix.
349 *
350 *  As an example, the identity matrix will return kX_SkAxisAlignment
351 */
352SkAxisAlignment SkComputeAxisAlignmentForHText(const SkMatrix& matrix);
353
354///////////////////////////////////////////////////////////////////////////////
355
356SkPaint::Hinting SkScalerContextRec::getHinting() const {
357    unsigned hint = (fFlags & SkScalerContext::kHinting_Mask) >>
358                                            SkScalerContext::kHinting_Shift;
359    return static_cast<SkPaint::Hinting>(hint);
360}
361
362void SkScalerContextRec::setHinting(SkPaint::Hinting hinting) {
363    fFlags = (fFlags & ~SkScalerContext::kHinting_Mask) |
364                                (hinting << SkScalerContext::kHinting_Shift);
365}
366
367
368#endif
369