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
17struct 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    inline SkPaint::Hinting getHinting() const;
88    inline void setHinting(SkPaint::Hinting);
89
90    SkMask::Format getFormat() const {
91        return static_cast<SkMask::Format>(fMaskFormat);
92    }
93
94    SkColor getLuminanceColor() const {
95        return fLumBits;
96    }
97
98    void setLuminanceColor(SkColor c) {
99        fLumBits = c;
100    }
101};
102
103//The following typedef hides from the rest of the implementation the number of
104//most significant bits to consider when creating mask gamma tables. Two bits
105//per channel was chosen as a balance between fidelity (more bits) and cache
106//sizes (fewer bits). Three bits per channel was chosen when #303942; (used by
107//the Chrome UI) turned out too green.
108typedef SkTMaskGamma<3, 3, 3> SkMaskGamma;
109
110class SkScalerContext {
111public:
112    typedef SkScalerContextRec Rec;
113
114    enum Flags {
115        kFrameAndFill_Flag        = 0x0001,
116        kDevKernText_Flag         = 0x0002,
117        kEmbeddedBitmapText_Flag  = 0x0004,
118        kEmbolden_Flag            = 0x0008,
119        kSubpixelPositioning_Flag = 0x0010,
120        kForceAutohinting_Flag    = 0x0020,  // Use auto instead of bytcode hinting if hinting.
121        kVertical_Flag            = 0x0040,
122
123        // together, these two flags resulting in a two bit value which matches
124        // up with the SkPaint::Hinting enum.
125        kHinting_Shift            = 7, // to shift into the other flags above
126        kHintingBit1_Flag         = 0x0080,
127        kHintingBit2_Flag         = 0x0100,
128
129        // Pixel geometry information.
130        // only meaningful if fMaskFormat is LCD16 or LCD32
131        kLCD_Vertical_Flag        = 0x0200,    // else Horizontal
132        kLCD_BGROrder_Flag        = 0x0400,    // else RGB order
133
134        // Generate A8 from LCD source (for GDI and CoreGraphics).
135        // only meaningful if fMaskFormat is kA8
136        kGenA8FromLCD_Flag        = 0x0800, // could be 0x200 (bit meaning dependent on fMaskFormat)
137    };
138
139    // computed values
140    enum {
141        kHinting_Mask   = kHintingBit1_Flag | kHintingBit2_Flag,
142    };
143
144
145    SkScalerContext(SkTypeface*, const SkDescriptor*);
146    virtual ~SkScalerContext();
147
148    SkTypeface* getTypeface() const { return fTypeface.get(); }
149
150    SkMask::Format getMaskFormat() const {
151        return (SkMask::Format)fRec.fMaskFormat;
152    }
153
154    bool isSubpixel() const {
155        return SkToBool(fRec.fFlags & kSubpixelPositioning_Flag);
156    }
157
158    bool isVertical() const {
159        return SkToBool(fRec.fFlags & kVertical_Flag);
160    }
161
162    /** Return the corresponding glyph for the specified unichar. Since contexts
163        may be chained (under the hood), the glyphID that is returned may in
164        fact correspond to a different font/context. In that case, we use the
165        base-glyph-count to know how to translate back into local glyph space.
166     */
167    uint16_t charToGlyphID(SkUnichar uni) {
168        return generateCharToGlyph(uni);
169    }
170
171    /** Map the glyphID to its glyph index, and then to its char code. Unmapped
172        glyphs return zero.
173    */
174    SkUnichar glyphIDToChar(uint16_t glyphID) {
175        return (glyphID < getGlyphCount()) ? generateGlyphToChar(glyphID) : 0;
176    }
177
178    unsigned    getGlyphCount() { return this->generateGlyphCount(); }
179    void        getAdvance(SkGlyph*);
180    void        getMetrics(SkGlyph*);
181    void        getImage(const SkGlyph&);
182    void        getPath(const SkGlyph&, SkPath*);
183    void        getFontMetrics(SkPaint::FontMetrics*);
184
185    /** Return the size in bytes of the associated gamma lookup table
186     */
187    static size_t GetGammaLUTSize(SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma,
188                                  int* width, int* height);
189
190    /** Get the associated gamma lookup table. The 'data' pointer must point to pre-allocated
191        memory, with size in bytes greater than or equal to the return value of getGammaLUTSize().
192     */
193    static void   GetGammaLUTData(SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma,
194                                  void* data);
195
196    static void MakeRec(const SkPaint&, const SkDeviceProperties* deviceProperties,
197                        const SkMatrix*, Rec* rec);
198    static inline void PostMakeRec(const SkPaint&, Rec*);
199
200    static SkMaskGamma::PreBlend GetMaskPreBlend(const Rec& rec);
201
202protected:
203    Rec         fRec;
204
205    /** Generates the contents of glyph.fAdvanceX and glyph.fAdvanceY.
206     *  May call getMetrics if that would be just as fast.
207     */
208    virtual void generateAdvance(SkGlyph* glyph) = 0;
209
210    /** Generates the contents of glyph.fWidth, fHeight, fTop, fLeft,
211     *  as well as fAdvanceX and fAdvanceY if not already set.
212     *
213     *  TODO: fMaskFormat is set by getMetrics later; cannot be set here.
214     */
215    virtual void generateMetrics(SkGlyph* glyph) = 0;
216
217    /** Generates the contents of glyph.fImage.
218     *  When called, glyph.fImage will be pointing to a pre-allocated,
219     *  uninitialized region of memory of size glyph.computeImageSize().
220     *  This method may change glyph.fMaskFormat if the new image size is
221     *  less than or equal to the old image size.
222     *
223     *  Because glyph.computeImageSize() will determine the size of fImage,
224     *  generateMetrics will be called before generateImage.
225     */
226    virtual void generateImage(const SkGlyph& glyph) = 0;
227
228    /** Sets the passed path to the glyph outline.
229     *  If this cannot be done the path is set to empty;
230     *  this is indistinguishable from a glyph with an empty path.
231     *  This does not set glyph.fPath.
232     *
233     *  TODO: path is always glyph.fPath, no reason to pass separately.
234     */
235    virtual void generatePath(const SkGlyph& glyph, SkPath* path) = 0;
236
237    /** Retrieves font metrics. */
238    virtual void generateFontMetrics(SkPaint::FontMetrics*) = 0;
239
240    /** Returns the number of glyphs in the font. */
241    virtual unsigned generateGlyphCount() = 0;
242
243    /** Returns the glyph id for the given unichar.
244     *  If there is no 1:1 mapping from the unichar to a glyph id, returns 0.
245     */
246    virtual uint16_t generateCharToGlyph(SkUnichar unichar) = 0;
247
248    /** Returns the unichar for the given glyph id.
249     *  If there is no 1:1 mapping from the glyph id to a unichar, returns 0.
250     *  The default implementation always returns 0, indicating failure.
251     */
252    virtual SkUnichar generateGlyphToChar(uint16_t glyphId);
253
254    void forceGenerateImageFromPath() { fGenerateImageFromPath = true; }
255
256private:
257    // never null
258    SkAutoTUnref<SkTypeface> fTypeface;
259
260    // optional object, which may be null
261    SkPathEffect*   fPathEffect;
262    SkMaskFilter*   fMaskFilter;
263    SkRasterizer*   fRasterizer;
264
265    // if this is set, we draw the image from a path, rather than
266    // calling generateImage.
267    bool fGenerateImageFromPath;
268
269    void internalGetPath(const SkGlyph& glyph, SkPath* fillPath,
270                         SkPath* devPath, SkMatrix* fillToDevMatrix);
271
272    // returns the right context from our link-list for this char. If no match
273    // is found it returns NULL. If a match is found then the glyphID param is
274    // set to the glyphID that maps to the provided char.
275    SkScalerContext* getContextFromChar(SkUnichar uni, uint16_t* glyphID);
276
277    // SkMaskGamma::PreBlend converts linear masks to gamma correcting masks.
278protected:
279    // Visible to subclasses so that generateImage can apply the pre-blend directly.
280    const SkMaskGamma::PreBlend fPreBlend;
281private:
282    // When there is a filter, previous steps must create a linear mask
283    // and the pre-blend applied as a final step.
284    const SkMaskGamma::PreBlend fPreBlendForFilter;
285};
286
287#define kRec_SkDescriptorTag            SkSetFourByteTag('s', 'r', 'e', 'c')
288#define kPathEffect_SkDescriptorTag     SkSetFourByteTag('p', 't', 'h', 'e')
289#define kMaskFilter_SkDescriptorTag     SkSetFourByteTag('m', 's', 'k', 'f')
290#define kRasterizer_SkDescriptorTag     SkSetFourByteTag('r', 'a', 's', 't')
291
292///////////////////////////////////////////////////////////////////////////////
293
294enum SkAxisAlignment {
295    kNone_SkAxisAlignment,
296    kX_SkAxisAlignment,
297    kY_SkAxisAlignment
298};
299
300/**
301 *  Return the axis (if any) that the baseline for horizontal text will land on
302 *  after running through the specified matrix.
303 *
304 *  As an example, the identity matrix will return kX_SkAxisAlignment
305 */
306SkAxisAlignment SkComputeAxisAlignmentForHText(const SkMatrix& matrix);
307
308///////////////////////////////////////////////////////////////////////////////
309
310SkPaint::Hinting SkScalerContextRec::getHinting() const {
311    unsigned hint = (fFlags & SkScalerContext::kHinting_Mask) >>
312                                            SkScalerContext::kHinting_Shift;
313    return static_cast<SkPaint::Hinting>(hint);
314}
315
316void SkScalerContextRec::setHinting(SkPaint::Hinting hinting) {
317    fFlags = (fFlags & ~SkScalerContext::kHinting_Mask) |
318                                (hinting << SkScalerContext::kHinting_Shift);
319}
320
321
322#endif
323