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
17 class SkGlyph;
18 class SkDescriptor;
19 class SkMaskFilter;
20 class SkPathEffect;
21 class 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 */
27 struct 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
getDeviceGammaSkScalerContextRec40 SkScalar getDeviceGamma() const {
41 return SkIntToScalar(fDeviceGamma) / (1 << 6);
42 }
setDeviceGammaSkScalerContextRec43 void setDeviceGamma(SkScalar dg) {
44 SkASSERT(0 <= dg && dg < SkIntToScalar(4));
45 fDeviceGamma = SkScalarFloorToInt(dg * (1 << 6));
46 }
47
getPaintGammaSkScalerContextRec48 SkScalar getPaintGamma() const {
49 return SkIntToScalar(fPaintGamma) / (1 << 6);
50 }
setPaintGammaSkScalerContextRec51 void setPaintGamma(SkScalar pg) {
52 SkASSERT(0 <= pg && pg < SkIntToScalar(4));
53 fPaintGamma = SkScalarFloorToInt(pg * (1 << 6));
54 }
55
getContrastSkScalerContextRec56 SkScalar getContrast() const {
57 return SkIntToScalar(fContrast) / ((1 << 8) - 1);
58 }
setContrastSkScalerContextRec59 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 */
ignorePreBlendSkScalerContextRec68 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 nullptr.
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 = nullptr,
128 SkMatrix* remainingRotation = nullptr,
129 SkMatrix* total = nullptr);
130
131 inline SkPaint::Hinting getHinting() const;
132 inline void setHinting(SkPaint::Hinting);
133
getFormatSkScalerContextRec134 SkMask::Format getFormat() const {
135 return static_cast<SkMask::Format>(fMaskFormat);
136 }
137
getLuminanceColorSkScalerContextRec138 SkColor getLuminanceColor() const {
139 return fLumBits;
140 }
141
setLuminanceColorSkScalerContextRec142 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.
152 typedef SkTMaskGamma<3, 3, 3> SkMaskGamma;
153
154 class SkScalerContext {
155 public:
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
getTypeface()192 SkTypeface* getTypeface() const { return fTypeface.get(); }
193
getMaskFormat()194 SkMask::Format getMaskFormat() const {
195 return (SkMask::Format)fRec.fMaskFormat;
196 }
197
isSubpixel()198 bool isSubpixel() const {
199 return SkToBool(fRec.fFlags & kSubpixelPositioning_Flag);
200 }
201
isVertical()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 */
charToGlyphID(SkUnichar uni)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 */
glyphIDToChar(uint16_t glyphID)218 SkUnichar glyphIDToChar(uint16_t glyphID) {
219 return (glyphID < getGlyphCount()) ? generateGlyphToChar(glyphID) : 0;
220 }
221
getGlyphCount()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 SkSurfaceProps* surfaceProps,
241 const SkMatrix*, Rec* rec);
242 static inline void PostMakeRec(const SkPaint&, Rec*);
243
244 static SkMaskGamma::PreBlend GetMaskPreBlend(const Rec& rec);
245
getRec()246 const Rec& getRec() const { return fRec; }
247
248 protected:
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
forceGenerateImageFromPath()300 void forceGenerateImageFromPath() { fGenerateImageFromPath = true; }
forceOffGenerateImageFromPath()301 void forceOffGenerateImageFromPath() { fGenerateImageFromPath = false; }
302
303 private:
304 friend class SkRandomScalerContext; // For debug purposes
305
306 // never null
307 SkAutoTUnref<SkTypeface> fTypeface;
308
309 // optional object, which may be null
310 SkPathEffect* fPathEffect;
311 SkMaskFilter* fMaskFilter;
312 SkRasterizer* fRasterizer;
313
314 // if this is set, we draw the image from a path, rather than
315 // calling generateImage.
316 bool fGenerateImageFromPath;
317
318 void internalGetPath(const SkGlyph& glyph, SkPath* fillPath,
319 SkPath* devPath, SkMatrix* fillToDevMatrix);
320
321 // returns the right context from our link-list for this char. If no match
322 // is found it returns nullptr. If a match is found then the glyphID param is
323 // set to the glyphID that maps to the provided char.
324 SkScalerContext* getContextFromChar(SkUnichar uni, uint16_t* glyphID);
325
326 // SkMaskGamma::PreBlend converts linear masks to gamma correcting masks.
327 protected:
328 // Visible to subclasses so that generateImage can apply the pre-blend directly.
329 const SkMaskGamma::PreBlend fPreBlend;
330 private:
331 // When there is a filter, previous steps must create a linear mask
332 // and the pre-blend applied as a final step.
333 const SkMaskGamma::PreBlend fPreBlendForFilter;
334 };
335
336 #define kRec_SkDescriptorTag SkSetFourByteTag('s', 'r', 'e', 'c')
337 #define kPathEffect_SkDescriptorTag SkSetFourByteTag('p', 't', 'h', 'e')
338 #define kMaskFilter_SkDescriptorTag SkSetFourByteTag('m', 's', 'k', 'f')
339 #define kRasterizer_SkDescriptorTag SkSetFourByteTag('r', 'a', 's', 't')
340
341 ///////////////////////////////////////////////////////////////////////////////
342
343 enum SkAxisAlignment {
344 kNone_SkAxisAlignment,
345 kX_SkAxisAlignment,
346 kY_SkAxisAlignment
347 };
348
349 /**
350 * Return the axis (if any) that the baseline for horizontal text will land on
351 * after running through the specified matrix.
352 *
353 * As an example, the identity matrix will return kX_SkAxisAlignment
354 */
355 SkAxisAlignment SkComputeAxisAlignmentForHText(const SkMatrix& matrix);
356
357 ///////////////////////////////////////////////////////////////////////////////
358
getHinting()359 SkPaint::Hinting SkScalerContextRec::getHinting() const {
360 unsigned hint = (fFlags & SkScalerContext::kHinting_Mask) >>
361 SkScalerContext::kHinting_Shift;
362 return static_cast<SkPaint::Hinting>(hint);
363 }
364
setHinting(SkPaint::Hinting hinting)365 void SkScalerContextRec::setHinting(SkPaint::Hinting hinting) {
366 fFlags = (fFlags & ~SkScalerContext::kHinting_Mask) |
367 (hinting << SkScalerContext::kHinting_Shift);
368 }
369
370
371 #endif
372