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 "SkGlyph.h"
14 #include "SkMask.h"
15 #include "SkMaskFilter.h"
16 #include "SkMaskGamma.h"
17 #include "SkMatrix.h"
18 #include "SkPaint.h"
19 #include "SkTypeface.h"
20 #include "SkWriteBuffer.h"
21
22 class SkAutoDescriptor;
23 class SkDescriptor;
24 class SkMaskFilter;
25 class SkPathEffect;
26 class SkScalerContext;
27 class SkScalerContext_DW;
28
29 enum SkScalerContextFlags : uint32_t {
30 kNone = 0,
31 kFakeGamma = 1 << 0,
32 kBoostContrast = 1 << 1,
33 kFakeGammaAndBoostContrast = kFakeGamma | kBoostContrast,
34 };
35
36 struct SkScalerContextEffects {
SkScalerContextEffectsSkScalerContextEffects37 SkScalerContextEffects() : fPathEffect(nullptr), fMaskFilter(nullptr) {}
SkScalerContextEffectsSkScalerContextEffects38 SkScalerContextEffects(SkPathEffect* pe, SkMaskFilter* mf)
39 : fPathEffect(pe), fMaskFilter(mf) {}
SkScalerContextEffectsSkScalerContextEffects40 explicit SkScalerContextEffects(const SkPaint& paint)
41 : fPathEffect(paint.getPathEffect())
42 , fMaskFilter(paint.getMaskFilter()) {}
43
44 SkPathEffect* fPathEffect;
45 SkMaskFilter* fMaskFilter;
46 };
47
48 enum SkAxisAlignment {
49 kNone_SkAxisAlignment,
50 kX_SkAxisAlignment,
51 kY_SkAxisAlignment
52 };
53
54 /*
55 * To allow this to be forward-declared, it must be its own typename, rather
56 * than a nested struct inside SkScalerContext (where it started).
57 */
58 struct SkScalerContextRec {
59
60 uint32_t fFontID;
61 SkScalar fTextSize, fPreScaleX, fPreSkewX;
62 SkScalar fPost2x2[2][2];
63 SkScalar fFrameWidth, fMiterLimit;
64
65 private:
66 //These describe the parameters to create (uniquely identify) the pre-blend.
67 uint32_t fLumBits;
68 uint8_t fDeviceGamma; //2.6, (0.0, 4.0) gamma, 0.0 for sRGB
69 uint8_t fPaintGamma; //2.6, (0.0, 4.0) gamma, 0.0 for sRGB
70 uint8_t fContrast; //0.8+1, [0.0, 1.0] artificial contrast
71 const uint8_t fReservedAlign{0};
72
73 public:
74
getDeviceGammaSkScalerContextRec75 SkScalar getDeviceGamma() const {
76 return SkIntToScalar(fDeviceGamma) / (1 << 6);
77 }
setDeviceGammaSkScalerContextRec78 void setDeviceGamma(SkScalar dg) {
79 SkASSERT(0 <= dg && dg < SkIntToScalar(4));
80 fDeviceGamma = SkScalarFloorToInt(dg * (1 << 6));
81 }
82
getPaintGammaSkScalerContextRec83 SkScalar getPaintGamma() const {
84 return SkIntToScalar(fPaintGamma) / (1 << 6);
85 }
setPaintGammaSkScalerContextRec86 void setPaintGamma(SkScalar pg) {
87 SkASSERT(0 <= pg && pg < SkIntToScalar(4));
88 fPaintGamma = SkScalarFloorToInt(pg * (1 << 6));
89 }
90
getContrastSkScalerContextRec91 SkScalar getContrast() const {
92 return SkIntToScalar(fContrast) / ((1 << 8) - 1);
93 }
setContrastSkScalerContextRec94 void setContrast(SkScalar c) {
95 SkASSERT(0 <= c && c <= SK_Scalar1);
96 fContrast = SkScalarRoundToInt(c * ((1 << 8) - 1));
97 }
98
99 /**
100 * Causes the luminance color to be ignored, and the paint and device
101 * gamma to be effectively 1.0
102 */
ignoreGammaSkScalerContextRec103 void ignoreGamma() {
104 setLuminanceColor(SK_ColorTRANSPARENT);
105 setPaintGamma(SK_Scalar1);
106 setDeviceGamma(SK_Scalar1);
107 }
108
109 /**
110 * Causes the luminance color and contrast to be ignored, and the
111 * paint and device gamma to be effectively 1.0.
112 */
ignorePreBlendSkScalerContextRec113 void ignorePreBlend() {
114 ignoreGamma();
115 setContrast(0);
116 }
117
118 uint8_t fMaskFormat;
119 private:
120 uint8_t fStrokeJoin : 4;
121 uint8_t fStrokeCap : 4;
122
123 public:
124 uint16_t fFlags;
125
126 // Warning: when adding members note that the size of this structure
127 // must be a multiple of 4. SkDescriptor requires that its arguments be
128 // multiples of four and this structure is put in an SkDescriptor in
129 // SkPaint::MakeRecAndEffects.
130
dumpSkScalerContextRec131 SkString dump() const {
132 SkString msg;
133 msg.appendf("Rec\n");
134 msg.appendf(" textsize %g prescale %g preskew %g post [%g %g %g %g]\n",
135 fTextSize, fPreScaleX, fPreSkewX, fPost2x2[0][0],
136 fPost2x2[0][1], fPost2x2[1][0], fPost2x2[1][1]);
137 msg.appendf(" frame %g miter %g format %d join %d cap %d flags %#hx\n",
138 fFrameWidth, fMiterLimit, fMaskFormat, fStrokeJoin, fStrokeCap, fFlags);
139 return msg;
140 }
141
142 void getMatrixFrom2x2(SkMatrix*) const;
143 void getLocalMatrix(SkMatrix*) const;
144 void getSingleMatrix(SkMatrix*) const;
145
146 /** The kind of scale which will be applied by the underlying port (pre-matrix). */
147 enum PreMatrixScale {
148 kFull_PreMatrixScale, // The underlying port can apply both x and y scale.
149 kVertical_PreMatrixScale, // The underlying port can only apply a y scale.
150 kVerticalInteger_PreMatrixScale // The underlying port can only apply an integer y scale.
151 };
152 /**
153 * Compute useful matrices for use with sizing in underlying libraries.
154 *
155 * There are two kinds of text size, a 'requested/logical size' which is like asking for size
156 * '12' and a 'real' size which is the size after the matrix is applied. The matrices produced
157 * by this method are based on the 'real' size. This method effectively finds the total device
158 * matrix and decomposes it in various ways.
159 *
160 * The most useful decomposition is into 'scale' and 'remaining'. The 'scale' is applied first
161 * and then the 'remaining' to fully apply the total matrix. This decomposition is useful when
162 * the text size ('scale') may have meaning apart from the total matrix. This is true when
163 * hinting, and sometimes true for other properties as well.
164 *
165 * The second (optional) decomposition is of 'remaining' into a non-rotational part
166 * 'remainingWithoutRotation' and a rotational part 'remainingRotation'. The 'scale' is applied
167 * first, then 'remainingWithoutRotation', then 'remainingRotation' to fully apply the total
168 * matrix. This decomposition is helpful when only horizontal metrics can be trusted, so the
169 * 'scale' and 'remainingWithoutRotation' will be handled by the underlying library, but
170 * the final rotation 'remainingRotation' will be handled manually.
171 *
172 * The 'total' matrix is also (optionally) available. This is useful in cases where the
173 * underlying library will not be used, often when working directly with font data.
174 *
175 * The parameters 'scale' and 'remaining' are required, the other pointers may be nullptr.
176 *
177 * @param preMatrixScale the kind of scale to extract from the total matrix.
178 * @param scale the scale extracted from the total matrix (both values positive).
179 * @param remaining apply after scale to apply the total matrix.
180 * @param remainingWithoutRotation apply after scale to apply the total matrix sans rotation.
181 * @param remainingRotation apply after remainingWithoutRotation to apply the total matrix.
182 * @param total the total matrix.
183 * @return false if the matrix was singular. The output will be valid but not invertible.
184 */
185 bool computeMatrices(PreMatrixScale preMatrixScale,
186 SkVector* scale, SkMatrix* remaining,
187 SkMatrix* remainingWithoutRotation = nullptr,
188 SkMatrix* remainingRotation = nullptr,
189 SkMatrix* total = nullptr);
190
191 inline SkPaint::Hinting getHinting() const;
192 inline void setHinting(SkPaint::Hinting);
193
getFormatSkScalerContextRec194 SkMask::Format getFormat() const {
195 return static_cast<SkMask::Format>(fMaskFormat);
196 }
197
198 private:
199 // TODO: get rid of these bad friends.
200 friend class SkScalerContext;
201 friend class SkScalerContext_DW;
202
getLuminanceColorSkScalerContextRec203 SkColor getLuminanceColor() const {
204 return fLumBits;
205 }
206
207
setLuminanceColorSkScalerContextRec208 void setLuminanceColor(SkColor c) {
209 fLumBits = c;
210 }
211 };
212
213 //The following typedef hides from the rest of the implementation the number of
214 //most significant bits to consider when creating mask gamma tables. Two bits
215 //per channel was chosen as a balance between fidelity (more bits) and cache
216 //sizes (fewer bits). Three bits per channel was chosen when #303942; (used by
217 //the Chrome UI) turned out too green.
218 typedef SkTMaskGamma<3, 3, 3> SkMaskGamma;
219
220 class SkScalerContext {
221 public:
222 enum Flags {
223 kFrameAndFill_Flag = 0x0001,
224 kDevKernText_Flag = 0x0002,
225 kEmbeddedBitmapText_Flag = 0x0004,
226 kEmbolden_Flag = 0x0008,
227 kSubpixelPositioning_Flag = 0x0010,
228 kForceAutohinting_Flag = 0x0020, // Use auto instead of bytcode hinting if hinting.
229 kVertical_Flag = 0x0040,
230
231 // together, these two flags resulting in a two bit value which matches
232 // up with the SkPaint::Hinting enum.
233 kHinting_Shift = 7, // to shift into the other flags above
234 kHintingBit1_Flag = 0x0080,
235 kHintingBit2_Flag = 0x0100,
236
237 // Pixel geometry information.
238 // only meaningful if fMaskFormat is kLCD16
239 kLCD_Vertical_Flag = 0x0200, // else Horizontal
240 kLCD_BGROrder_Flag = 0x0400, // else RGB order
241
242 // Generate A8 from LCD source (for GDI and CoreGraphics).
243 // only meaningful if fMaskFormat is kA8
244 kGenA8FromLCD_Flag = 0x0800, // could be 0x200 (bit meaning dependent on fMaskFormat)
245 };
246
247 // computed values
248 enum {
249 kHinting_Mask = kHintingBit1_Flag | kHintingBit2_Flag,
250 };
251
252 SkScalerContext(sk_sp<SkTypeface>, const SkScalerContextEffects&, const SkDescriptor*);
253 virtual ~SkScalerContext();
254
getTypeface()255 SkTypeface* getTypeface() const { return fTypeface.get(); }
256
getMaskFormat()257 SkMask::Format getMaskFormat() const {
258 return (SkMask::Format)fRec.fMaskFormat;
259 }
260
isSubpixel()261 bool isSubpixel() const {
262 return SkToBool(fRec.fFlags & kSubpixelPositioning_Flag);
263 }
264
isVertical()265 bool isVertical() const {
266 return SkToBool(fRec.fFlags & kVertical_Flag);
267 }
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
278 /** Map the glyphID to its glyph index, and then to its char code. Unmapped
279 glyphs return zero.
280 */
glyphIDToChar(uint16_t glyphID)281 SkUnichar glyphIDToChar(uint16_t glyphID) {
282 return (glyphID < getGlyphCount()) ? generateGlyphToChar(glyphID) : 0;
283 }
284
getGlyphCount()285 unsigned getGlyphCount() { return this->generateGlyphCount(); }
286 void getAdvance(SkGlyph*);
287 void getMetrics(SkGlyph*);
288 void getImage(const SkGlyph&);
289 void getPath(SkPackedGlyphID, SkPath*);
290 void getFontMetrics(SkPaint::FontMetrics*);
291
292 /** Return the size in bytes of the associated gamma lookup table
293 */
294 static size_t GetGammaLUTSize(SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma,
295 int* width, int* height);
296
297 /** Get the associated gamma lookup table. The 'data' pointer must point to pre-allocated
298 * memory, with size in bytes greater than or equal to the return value of getGammaLUTSize().
299 *
300 * If the lookup table hasn't been initialized (e.g., it's linear), this will return false.
301 */
302 static bool GetGammaLUTData(SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma,
303 uint8_t* data);
304
305 static void MakeRecAndEffects(const SkPaint& paint,
306 const SkSurfaceProps* surfaceProps,
307 const SkMatrix* deviceMatrix,
308 SkScalerContextFlags scalerContextFlags,
309 SkScalerContextRec* rec,
310 SkScalerContextEffects* effects);
311
312 static SkDescriptor* MakeDescriptorForPaths(SkFontID fontID,
313 SkAutoDescriptor* ad);
314
315 static SkDescriptor* AutoDescriptorGivenRecAndEffects(
316 const SkScalerContextRec& rec,
317 const SkScalerContextEffects& effects,
318 SkAutoDescriptor* ad);
319
320 static std::unique_ptr<SkDescriptor> DescriptorGivenRecAndEffects(
321 const SkScalerContextRec& rec,
322 const SkScalerContextEffects& effects);
323
324 static void DescriptorBufferGiveRec(const SkScalerContextRec& rec, void* buffer);
325 static bool CheckBufferSizeForRec(const SkScalerContextRec& rec,
326 const SkScalerContextEffects& effects,
327 size_t size);
328
329 static SkMaskGamma::PreBlend GetMaskPreBlend(const SkScalerContextRec& rec);
330
getRec()331 const SkScalerContextRec& getRec() const { return fRec; }
332
getEffects()333 SkScalerContextEffects getEffects() const {
334 return { fPathEffect.get(), fMaskFilter.get() };
335 }
336
337 /**
338 * Return the axis (if any) that the baseline for horizontal text should land on.
339 * As an example, the identity matrix will return kX_SkAxisAlignment
340 */
341 SkAxisAlignment computeAxisAlignmentForHText();
342
343 static SkDescriptor* CreateDescriptorAndEffectsUsingPaint(
344 const SkPaint& paint, const SkSurfaceProps* surfaceProps,
345 SkScalerContextFlags scalerContextFlags,
346 const SkMatrix* deviceMatrix, SkAutoDescriptor* ad,
347 SkScalerContextEffects* effects);
348
349 protected:
350 SkScalerContextRec fRec;
351
352 /** Generates the contents of glyph.fAdvanceX and glyph.fAdvanceY.
353 * May call getMetrics if that would be just as fast.
354 */
355 virtual void generateAdvance(SkGlyph* glyph) = 0;
356
357 /** Generates the contents of glyph.fWidth, fHeight, fTop, fLeft,
358 * as well as fAdvanceX and fAdvanceY if not already set.
359 *
360 * TODO: fMaskFormat is set by getMetrics later; cannot be set here.
361 */
362 virtual void generateMetrics(SkGlyph* glyph) = 0;
363
364 /** Generates the contents of glyph.fImage.
365 * When called, glyph.fImage will be pointing to a pre-allocated,
366 * uninitialized region of memory of size glyph.computeImageSize().
367 * This method may change glyph.fMaskFormat if the new image size is
368 * less than or equal to the old image size.
369 *
370 * Because glyph.computeImageSize() will determine the size of fImage,
371 * generateMetrics will be called before generateImage.
372 */
373 virtual void generateImage(const SkGlyph& glyph) = 0;
374
375 /** Sets the passed path to the glyph outline.
376 * If this cannot be done the path is set to empty;
377 * this is indistinguishable from a glyph with an empty path.
378 */
379 virtual void generatePath(SkGlyphID glyphId, SkPath* path) = 0;
380
381 /** Retrieves font metrics. */
382 virtual void generateFontMetrics(SkPaint::FontMetrics*) = 0;
383
384 /** Returns the number of glyphs in the font. */
385 virtual unsigned generateGlyphCount() = 0;
386
387 /** Returns the glyph id for the given unichar.
388 * If there is no 1:1 mapping from the unichar to a glyph id, returns 0.
389 */
390 virtual uint16_t generateCharToGlyph(SkUnichar unichar) = 0;
391
392 /** Returns the unichar for the given glyph id.
393 * If there is no 1:1 mapping from the glyph id to a unichar, returns 0.
394 * The default implementation always returns 0, indicating failure.
395 */
396 virtual SkUnichar generateGlyphToChar(uint16_t glyphId);
397
forceGenerateImageFromPath()398 void forceGenerateImageFromPath() { fGenerateImageFromPath = true; }
forceOffGenerateImageFromPath()399 void forceOffGenerateImageFromPath() { fGenerateImageFromPath = false; }
400
401 private:
402 friend class SkRandomScalerContext; // For debug purposes
403
404 // never null
405 sk_sp<SkTypeface> fTypeface;
406
407 // optional objects, which may be null
408 sk_sp<SkPathEffect> fPathEffect;
409 sk_sp<SkMaskFilter> fMaskFilter;
410
411 // if this is set, we draw the image from a path, rather than
412 // calling generateImage.
413 bool fGenerateImageFromPath;
414
415 /** Returns false if the glyph has no path at all. */
416 bool internalGetPath(SkPackedGlyphID id, SkPath* fillPath,
417 SkPath* devPath, SkMatrix* fillToDevMatrix);
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 private:
424 // When there is a filter, previous steps must create a linear mask
425 // and the pre-blend applied as a final step.
426 const SkMaskGamma::PreBlend fPreBlendForFilter;
427 };
428
429 #define kRec_SkDescriptorTag SkSetFourByteTag('s', 'r', 'e', 'c')
430 #define kPathEffect_SkDescriptorTag SkSetFourByteTag('p', 't', 'h', 'e')
431 #define kMaskFilter_SkDescriptorTag SkSetFourByteTag('m', 's', 'k', 'f')
432
433 ///////////////////////////////////////////////////////////////////////////////
434
getHinting()435 SkPaint::Hinting SkScalerContextRec::getHinting() const {
436 unsigned hint = (fFlags & SkScalerContext::kHinting_Mask) >>
437 SkScalerContext::kHinting_Shift;
438 return static_cast<SkPaint::Hinting>(hint);
439 }
440
setHinting(SkPaint::Hinting hinting)441 void SkScalerContextRec::setHinting(SkPaint::Hinting hinting) {
442 fFlags = (fFlags & ~SkScalerContext::kHinting_Mask) |
443 (hinting << SkScalerContext::kHinting_Shift);
444 }
445
446
447 #endif
448