• 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 "SkMask.h"
12 #include "SkMaskGamma.h"
13 #include "SkMatrix.h"
14 #include "SkPaint.h"
15 
16 #ifdef SK_BUILD_FOR_ANDROID
17     #include "SkLanguage.h"
18     //For SkFontID
19     #include "SkTypeface.h"
20 #endif
21 
22 struct SkGlyph;
23 class SkDescriptor;
24 class SkMaskFilter;
25 class SkPathEffect;
26 class SkRasterizer;
27 
28 /*
29  *  To allow this to be forward-declared, it must be its own typename, rather
30  *  than a nested struct inside SkScalerContext (where it started).
31  */
32 struct SkScalerContextRec {
33     uint32_t    fOrigFontID;
34     uint32_t    fFontID;
35     SkScalar    fTextSize, fPreScaleX, fPreSkewX;
36     SkScalar    fPost2x2[2][2];
37     SkScalar    fFrameWidth, fMiterLimit;
38 #ifdef SK_SUPPORT_HINTING_SCALE_FACTOR
39     SkScalar    fHintingScaleFactor;
40 #endif
41 #ifdef SK_BUILD_FOR_ANDROID
42     SkLanguage fLanguage;
43     SkPaint::FontVariant fFontVariant;
44 #endif
45 
46     //These describe the parameters to create (uniquely identify) the pre-blend.
47     uint32_t    fLumBits;
48     uint8_t     fDeviceGamma; //2.6, (0.0, 4.0) gamma, 0.0 for sRGB
49     uint8_t     fPaintGamma;  //2.6, (0.0, 4.0) gamma, 0.0 for sRGB
50     uint8_t     fContrast;    //0.8+1, [0.0, 1.0] artificial contrast
51     uint8_t     fReservedAlign;
52 
getDeviceGammaSkScalerContextRec53     SkScalar getDeviceGamma() const {
54         return SkIntToScalar(fDeviceGamma) / (1 << 6);
55     }
setDeviceGammaSkScalerContextRec56     void setDeviceGamma(SkScalar dg) {
57         SkASSERT(0 <= dg && dg < SkIntToScalar(4));
58         fDeviceGamma = SkScalarFloorToInt(dg * (1 << 6));
59     }
60 
getPaintGammaSkScalerContextRec61     SkScalar getPaintGamma() const {
62         return SkIntToScalar(fPaintGamma) / (1 << 6);
63     }
setPaintGammaSkScalerContextRec64     void setPaintGamma(SkScalar pg) {
65         SkASSERT(0 <= pg && pg < SkIntToScalar(4));
66         fPaintGamma = SkScalarFloorToInt(pg * (1 << 6));
67     }
68 
getContrastSkScalerContextRec69     SkScalar getContrast() const {
70         return SkIntToScalar(fContrast) / ((1 << 8) - 1);
71     }
setContrastSkScalerContextRec72     void setContrast(SkScalar c) {
73         SkASSERT(0 <= c && c <= SK_Scalar1);
74         fContrast = SkScalarRoundToInt(c * ((1 << 8) - 1));
75     }
76 
77     /**
78      *  Causes the luminance color and contrast to be ignored, and the
79      *  paint and device gamma to be effectively 1.0.
80      */
ignorePreBlendSkScalerContextRec81     void ignorePreBlend() {
82         setLuminanceColor(SK_ColorTRANSPARENT);
83         setPaintGamma(SK_Scalar1);
84         setDeviceGamma(SK_Scalar1);
85         setContrast(0);
86     }
87 
88     uint8_t     fMaskFormat;
89     uint8_t     fStrokeJoin;
90     uint16_t    fFlags;
91     // Warning: when adding members note that the size of this structure
92     // must be a multiple of 4. SkDescriptor requires that its arguments be
93     // multiples of four and this structure is put in an SkDescriptor in
94     // SkPaint::MakeRec.
95 
96     void    getMatrixFrom2x2(SkMatrix*) const;
97     void    getLocalMatrix(SkMatrix*) const;
98     void    getSingleMatrix(SkMatrix*) const;
99 
100     inline SkPaint::Hinting getHinting() const;
101     inline void setHinting(SkPaint::Hinting);
102 
getFormatSkScalerContextRec103     SkMask::Format getFormat() const {
104         return static_cast<SkMask::Format>(fMaskFormat);
105     }
106 
getLuminanceColorSkScalerContextRec107     SkColor getLuminanceColor() const {
108         return fLumBits;
109     }
110 
setLuminanceColorSkScalerContextRec111     void setLuminanceColor(SkColor c) {
112         fLumBits = c;
113     }
114 };
115 
116 //The following typedef hides from the rest of the implementation the number of
117 //most significant bits to consider when creating mask gamma tables. Two bits
118 //per channel was chosen as a balance between fidelity (more bits) and cache
119 //sizes (fewer bits). Three bits per channel was chosen when #303942; (used by
120 //the Chrome UI) turned out too green.
121 typedef SkTMaskGamma<3, 3, 3> SkMaskGamma;
122 
123 class SkScalerContext {
124 public:
125     typedef SkScalerContextRec Rec;
126 
127     enum Flags {
128         kFrameAndFill_Flag        = 0x0001,
129         kDevKernText_Flag         = 0x0002,
130         kEmbeddedBitmapText_Flag  = 0x0004,
131         kEmbolden_Flag            = 0x0008,
132         kSubpixelPositioning_Flag = 0x0010,
133         kAutohinting_Flag         = 0x0020,
134         kVertical_Flag            = 0x0040,
135 
136         // together, these two flags resulting in a two bit value which matches
137         // up with the SkPaint::Hinting enum.
138         kHinting_Shift            = 7, // to shift into the other flags above
139         kHintingBit1_Flag         = 0x0080,
140         kHintingBit2_Flag         = 0x0100,
141 
142         // these should only ever be set if fMaskFormat is LCD16 or LCD32
143         kLCD_Vertical_Flag        = 0x0200,    // else Horizontal
144         kLCD_BGROrder_Flag        = 0x0400,    // else RGB order
145 
146         // Generate A8 from LCD source (for GDI), only meaningful if fMaskFormat is kA8
147         // Perhaps we can store this (instead) in fMaskFormat, in hight bit?
148         kGenA8FromLCD_Flag        = 0x0800,
149     };
150 
151     // computed values
152     enum {
153         kHinting_Mask   = kHintingBit1_Flag | kHintingBit2_Flag,
154     };
155 
156 
157     SkScalerContext(const SkDescriptor* desc);
158     virtual ~SkScalerContext();
159 
getMaskFormat()160     SkMask::Format getMaskFormat() const {
161         return (SkMask::Format)fRec.fMaskFormat;
162     }
163 
isSubpixel()164     bool isSubpixel() const {
165         return SkToBool(fRec.fFlags & kSubpixelPositioning_Flag);
166     }
167 
168     // remember our glyph offset/base
setBaseGlyphCount(unsigned baseGlyphCount)169     void setBaseGlyphCount(unsigned baseGlyphCount) {
170         fBaseGlyphCount = baseGlyphCount;
171     }
172 
173     /** Return the corresponding glyph for the specified unichar. Since contexts
174         may be chained (under the hood), the glyphID that is returned may in
175         fact correspond to a different font/context. In that case, we use the
176         base-glyph-count to know how to translate back into local glyph space.
177      */
178     uint16_t charToGlyphID(SkUnichar uni);
179 
180     /** Map the glyphID to its glyph index, and then to its char code. Unmapped
181         glyphs return zero.
182     */
183     SkUnichar glyphIDToChar(uint16_t glyphID);
184 
getGlyphCount()185     unsigned    getGlyphCount() { return this->generateGlyphCount(); }
186     void        getAdvance(SkGlyph*);
187     void        getMetrics(SkGlyph*);
188     void        getImage(const SkGlyph&);
189     void        getPath(const SkGlyph&, SkPath*);
190     void        getFontMetrics(SkPaint::FontMetrics* mX,
191                                SkPaint::FontMetrics* mY);
192 
193 #ifdef SK_BUILD_FOR_ANDROID
194     unsigned getBaseGlyphCount(SkUnichar charCode);
195 
196     // This function must be public for SkTypeface_android.h, but should not be
197     // called by other callers
198     SkFontID findTypefaceIdForChar(SkUnichar uni);
199 #endif
200 
201     static inline void MakeRec(const SkPaint&, const SkDeviceProperties* deviceProperties,
202                                const SkMatrix*, Rec* rec);
203     static inline void PostMakeRec(const SkPaint&, Rec*);
204 
205     static SkScalerContext* Create(const SkDescriptor*);
206     static SkMaskGamma::PreBlend GetMaskPreBlend(const Rec& rec);
207 
208 protected:
209     Rec         fRec;
210     unsigned    fBaseGlyphCount;
211 
212     virtual unsigned generateGlyphCount() = 0;
213     virtual uint16_t generateCharToGlyph(SkUnichar) = 0;
214     virtual void generateAdvance(SkGlyph*) = 0;
215     virtual void generateMetrics(SkGlyph*) = 0;
216     virtual void generateImage(const SkGlyph&) = 0;
217     virtual void generatePath(const SkGlyph&, SkPath*) = 0;
218     virtual void generateFontMetrics(SkPaint::FontMetrics* mX,
219                                      SkPaint::FontMetrics* mY) = 0;
220     // default impl returns 0, indicating failure.
221     virtual SkUnichar generateGlyphToChar(uint16_t);
222 
forceGenerateImageFromPath()223     void forceGenerateImageFromPath() { fGenerateImageFromPath = true; }
224 
225 private:
226     SkScalerContext* getContextFromChar(SkUnichar uni, unsigned& glyphID);
227 
228     SkPathEffect*   fPathEffect;
229     SkMaskFilter*   fMaskFilter;
230     SkRasterizer*   fRasterizer;
231 
232     // if this is set, we draw the image from a path, rather than
233     // calling generateImage.
234     bool fGenerateImageFromPath;
235 
236     void internalGetPath(const SkGlyph& glyph, SkPath* fillPath,
237                          SkPath* devPath, SkMatrix* fillToDevMatrix);
238 
239     // return the next context, treating fNextContext as a cache of the answer
240     SkScalerContext* getNextContext();
241 
242     // returns the right context from our link-list for this glyph. If no match
243     // is found, just returns the original context (this)
244     SkScalerContext* getGlyphContext(const SkGlyph& glyph);
245 
246     // link-list of context, to handle missing chars. null-terminated.
247     SkScalerContext* fNextContext;
248 
249     // SkMaskGamma::PreBlend converts linear masks to gamma correcting masks.
250 protected:
251     // Visible to subclasses so that generateImage can apply the pre-blend directly.
252     const SkMaskGamma::PreBlend fPreBlend;
253 private:
254     // When there is a filter, previous steps must create a linear mask
255     // and the pre-blend applied as a final step.
256     const SkMaskGamma::PreBlend fPreBlendForFilter;
257 };
258 
259 #define kRec_SkDescriptorTag            SkSetFourByteTag('s', 'r', 'e', 'c')
260 #define kPathEffect_SkDescriptorTag     SkSetFourByteTag('p', 't', 'h', 'e')
261 #define kMaskFilter_SkDescriptorTag     SkSetFourByteTag('m', 's', 'k', 'f')
262 #define kRasterizer_SkDescriptorTag     SkSetFourByteTag('r', 'a', 's', 't')
263 
264 ///////////////////////////////////////////////////////////////////////////////
265 
266 enum SkAxisAlignment {
267     kNone_SkAxisAlignment,
268     kX_SkAxisAlignment,
269     kY_SkAxisAlignment
270 };
271 
272 /**
273  *  Return the axis (if any) that the baseline for horizontal text will land on
274  *  after running through the specified matrix.
275  *
276  *  As an example, the identity matrix will return kX_SkAxisAlignment
277  */
278 SkAxisAlignment SkComputeAxisAlignmentForHText(const SkMatrix& matrix);
279 
280 ///////////////////////////////////////////////////////////////////////////////
281 
getHinting()282 SkPaint::Hinting SkScalerContextRec::getHinting() const {
283     unsigned hint = (fFlags & SkScalerContext::kHinting_Mask) >>
284                                             SkScalerContext::kHinting_Shift;
285     return static_cast<SkPaint::Hinting>(hint);
286 }
287 
setHinting(SkPaint::Hinting hinting)288 void SkScalerContextRec::setHinting(SkPaint::Hinting hinting) {
289     fFlags = (fFlags & ~SkScalerContext::kHinting_Mask) |
290                                 (hinting << SkScalerContext::kHinting_Shift);
291 }
292 
293 
294 #endif
295