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 #include "include/core/SkPaint.h"
9 #include "src/core/SkScalerContext.h"
10 
11 #include "include/core/SkFontMetrics.h"
12 #include "include/core/SkMaskFilter.h"
13 #include "include/core/SkPathEffect.h"
14 #include "include/core/SkStrokeRec.h"
15 #include "include/private/SkColorData.h"
16 #include "include/private/SkTo.h"
17 #include "src/core/SkAutoMalloc.h"
18 #include "src/core/SkAutoPixmapStorage.h"
19 #include "src/core/SkDescriptor.h"
20 #include "src/core/SkDraw.h"
21 #include "src/core/SkFontPriv.h"
22 #include "src/core/SkGlyph.h"
23 #include "src/core/SkMaskGamma.h"
24 #include "src/core/SkMatrixProvider.h"
25 #include "src/core/SkPaintPriv.h"
26 #include "src/core/SkPathPriv.h"
27 #include "src/core/SkRasterClip.h"
28 #include "src/core/SkReadBuffer.h"
29 #include "src/core/SkRectPriv.h"
30 #include "src/core/SkStroke.h"
31 #include "src/core/SkSurfacePriv.h"
32 #include "src/core/SkTextFormatParams.h"
33 #include "src/core/SkWriteBuffer.h"
34 #include "src/utils/SkMatrix22.h"
35 #include <new>
36 
37 ///////////////////////////////////////////////////////////////////////////////
38 
39 #ifdef SK_DEBUG
40     #define DUMP_RECx
41 #endif
42 
PreprocessRec(const SkTypeface & typeface,const SkScalerContextEffects & effects,const SkDescriptor & desc)43 SkScalerContextRec SkScalerContext::PreprocessRec(const SkTypeface& typeface,
44                                                   const SkScalerContextEffects& effects,
45                                                   const SkDescriptor& desc) {
46     SkScalerContextRec rec =
47             *static_cast<const SkScalerContextRec*>(desc.findEntry(kRec_SkDescriptorTag, nullptr));
48 
49     // Allow the typeface to adjust the rec.
50     typeface.onFilterRec(&rec);
51 
52     if (effects.fMaskFilter) {
53         // Pre-blend is not currently applied to filtered text.
54         // The primary filter is blur, for which contrast makes no sense,
55         // and for which the destination guess error is more visible.
56         // Also, all existing users of blur have calibrated for linear.
57         rec.ignorePreBlend();
58     }
59 
60     SkColor lumColor = rec.getLuminanceColor();
61 
62     if (rec.fMaskFormat == SkMask::kA8_Format) {
63         U8CPU lum = SkComputeLuminance(SkColorGetR(lumColor),
64                                        SkColorGetG(lumColor),
65                                        SkColorGetB(lumColor));
66         lumColor = SkColorSetRGB(lum, lum, lum);
67     }
68 
69     // TODO: remove CanonicalColor when we to fix up Chrome layout tests.
70     rec.setLuminanceColor(lumColor);
71 
72     return rec;
73 }
74 
SkScalerContext(sk_sp<SkTypeface> typeface,const SkScalerContextEffects & effects,const SkDescriptor * desc)75 SkScalerContext::SkScalerContext(sk_sp<SkTypeface> typeface, const SkScalerContextEffects& effects,
76                                  const SkDescriptor* desc)
77     : fRec(PreprocessRec(*typeface, effects, *desc))
78     , fTypeface(std::move(typeface))
79     , fPathEffect(sk_ref_sp(effects.fPathEffect))
80     , fMaskFilter(sk_ref_sp(effects.fMaskFilter))
81       // Initialize based on our settings. Subclasses can also force this.
82     , fGenerateImageFromPath(fRec.fFrameWidth >= 0 || fPathEffect != nullptr)
83 
84     , fPreBlend(fMaskFilter ? SkMaskGamma::PreBlend() : SkScalerContext::GetMaskPreBlend(fRec))
85 {
86 #ifdef DUMP_REC
87     SkDebugf("SkScalerContext checksum %x count %d length %d\n",
88              desc->getChecksum(), desc->getCount(), desc->getLength());
89     SkDebugf("%s", fRec.dump().c_str());
90     SkDebugf("  effects %x\n", desc->findEntry(kEffects_SkDescriptorTag, nullptr));
91 #endif
92 }
93 
~SkScalerContext()94 SkScalerContext::~SkScalerContext() {}
95 
96 /**
97  * In order to call cachedDeviceLuminance, cachedPaintLuminance, or
98  * cachedMaskGamma the caller must hold the mask_gamma_cache_mutex and continue
99  * to hold it until the returned pointer is refed or forgotten.
100  */
mask_gamma_cache_mutex()101 static SkMutex& mask_gamma_cache_mutex() {
102     static SkMutex& mutex = *(new SkMutex);
103     return mutex;
104 }
105 
106 static SkMaskGamma* gLinearMaskGamma = nullptr;
107 static SkMaskGamma* gMaskGamma = nullptr;
108 static SkScalar gContrast = SK_ScalarMin;
109 static SkScalar gPaintGamma = SK_ScalarMin;
110 static SkScalar gDeviceGamma = SK_ScalarMin;
111 
112 /**
113  * The caller must hold the mask_gamma_cache_mutex() and continue to hold it until
114  * the returned SkMaskGamma pointer is refed or forgotten.
115  */
cached_mask_gamma(SkScalar contrast,SkScalar paintGamma,SkScalar deviceGamma)116 static const SkMaskGamma& cached_mask_gamma(SkScalar contrast, SkScalar paintGamma,
117                                             SkScalar deviceGamma) {
118     mask_gamma_cache_mutex().assertHeld();
119     if (0 == contrast && SK_Scalar1 == paintGamma && SK_Scalar1 == deviceGamma) {
120         if (nullptr == gLinearMaskGamma) {
121             gLinearMaskGamma = new SkMaskGamma;
122         }
123         return *gLinearMaskGamma;
124     }
125     if (gContrast != contrast || gPaintGamma != paintGamma || gDeviceGamma != deviceGamma) {
126         SkSafeUnref(gMaskGamma);
127         gMaskGamma = new SkMaskGamma(contrast, paintGamma, deviceGamma);
128         gContrast = contrast;
129         gPaintGamma = paintGamma;
130         gDeviceGamma = deviceGamma;
131     }
132     return *gMaskGamma;
133 }
134 
135 /**
136  * Expands fDeviceGamma, fPaintGamma, fContrast, and fLumBits into a mask pre-blend.
137  */
GetMaskPreBlend(const SkScalerContextRec & rec)138 SkMaskGamma::PreBlend SkScalerContext::GetMaskPreBlend(const SkScalerContextRec& rec) {
139     SkAutoMutexExclusive ama(mask_gamma_cache_mutex());
140 
141     const SkMaskGamma& maskGamma = cached_mask_gamma(rec.getContrast(),
142                                                      rec.getPaintGamma(),
143                                                      rec.getDeviceGamma());
144 
145     // TODO: remove CanonicalColor when we to fix up Chrome layout tests.
146     return maskGamma.preBlend(rec.getLuminanceColor());
147 }
148 
GetGammaLUTSize(SkScalar contrast,SkScalar paintGamma,SkScalar deviceGamma,int * width,int * height)149 size_t SkScalerContext::GetGammaLUTSize(SkScalar contrast, SkScalar paintGamma,
150                                         SkScalar deviceGamma, int* width, int* height) {
151     SkAutoMutexExclusive ama(mask_gamma_cache_mutex());
152     const SkMaskGamma& maskGamma = cached_mask_gamma(contrast,
153                                                      paintGamma,
154                                                      deviceGamma);
155 
156     maskGamma.getGammaTableDimensions(width, height);
157     size_t size = (*width)*(*height)*sizeof(uint8_t);
158 
159     return size;
160 }
161 
GetGammaLUTData(SkScalar contrast,SkScalar paintGamma,SkScalar deviceGamma,uint8_t * data)162 bool SkScalerContext::GetGammaLUTData(SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma,
163                                       uint8_t* data) {
164     SkAutoMutexExclusive ama(mask_gamma_cache_mutex());
165     const SkMaskGamma& maskGamma = cached_mask_gamma(contrast,
166                                                      paintGamma,
167                                                      deviceGamma);
168     const uint8_t* gammaTables = maskGamma.getGammaTables();
169     if (!gammaTables) {
170         return false;
171     }
172 
173     int width, height;
174     maskGamma.getGammaTableDimensions(&width, &height);
175     size_t size = width*height * sizeof(uint8_t);
176     memcpy(data, gammaTables, size);
177     return true;
178 }
179 
makeGlyph(SkPackedGlyphID packedID)180 SkGlyph SkScalerContext::makeGlyph(SkPackedGlyphID packedID) {
181     return internalMakeGlyph(packedID, fRec.fMaskFormat);
182 }
183 
internalMakeGlyph(SkPackedGlyphID packedID,SkMask::Format format)184 SkGlyph SkScalerContext::internalMakeGlyph(SkPackedGlyphID packedID, SkMask::Format format) {
185     SkGlyph glyph{packedID};
186     glyph.fMaskFormat = format;
187     bool generatingImageFromPath = fGenerateImageFromPath;
188     if (!generatingImageFromPath) {
189         generateMetrics(&glyph);
190     } else {
191         SkPath devPath;
192         generatingImageFromPath = this->internalGetPath(glyph.getPackedID(), &devPath);
193         if (!generatingImageFromPath) {
194             generateMetrics(&glyph);
195         } else {
196             if (!generateAdvance(&glyph)) {
197                 generateMetrics(&glyph);
198             }
199 
200             // If we are going to create the mask, then we cannot keep the color
201             if (SkMask::kARGB32_Format == glyph.fMaskFormat) {
202                 glyph.fMaskFormat = SkMask::kA8_Format;
203             }
204 
205             const SkIRect ir = devPath.getBounds().roundOut();
206             if (ir.isEmpty() || !SkRectPriv::Is16Bit(ir)) {
207                 goto SK_ERROR;
208             }
209             glyph.fLeft    = ir.fLeft;
210             glyph.fTop     = ir.fTop;
211             glyph.fWidth   = SkToU16(ir.width());
212             glyph.fHeight  = SkToU16(ir.height());
213 
214             const bool a8FromLCD = fRec.fFlags & SkScalerContext::kGenA8FromLCD_Flag;
215             const bool fromLCD = (glyph.fMaskFormat == SkMask::kLCD16_Format) ||
216                                  (glyph.fMaskFormat == SkMask::kA8_Format && a8FromLCD);
217             const bool notEmptyAndFromLCD = 0 < glyph.fWidth && fromLCD;
218             const bool verticalLCD = fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag;
219 
220             const bool hasHairline = fRec.fFrameWidth == 0;
221 
222             const bool needExtraWidth  = (notEmptyAndFromLCD && !verticalLCD) || hasHairline;
223             const bool needExtraHeight = (notEmptyAndFromLCD &&  verticalLCD) || hasHairline;
224             if (needExtraWidth) {
225                 glyph.fWidth += 2;
226                 glyph.fLeft -= 1;
227             }
228             if (needExtraHeight) {
229                 glyph.fHeight += 2;
230                 glyph.fTop -= 1;
231             }
232         }
233     }
234 
235     // if either dimension is empty, zap the image bounds of the glyph
236     if (0 == glyph.fWidth || 0 == glyph.fHeight) {
237         glyph.fWidth   = 0;
238         glyph.fHeight  = 0;
239         glyph.fTop     = 0;
240         glyph.fLeft    = 0;
241         glyph.fMaskFormat = SkMask::kBW_Format;
242         return glyph;
243     }
244 
245     if (fMaskFilter) {
246         SkMask      src = glyph.mask(),
247                     dst;
248         SkMatrix    matrix;
249 
250         fRec.getMatrixFrom2x2(&matrix);
251 
252         src.fImage = nullptr;  // only want the bounds from the filter
253         if (as_MFB(fMaskFilter)->filterMask(&dst, src, matrix, nullptr)) {
254             if (dst.fBounds.isEmpty() || !SkRectPriv::Is16Bit(dst.fBounds)) {
255                 goto SK_ERROR;
256             }
257             SkASSERT(dst.fImage == nullptr);
258             glyph.fLeft    = dst.fBounds.fLeft;
259             glyph.fTop     = dst.fBounds.fTop;
260             glyph.fWidth   = SkToU16(dst.fBounds.width());
261             glyph.fHeight  = SkToU16(dst.fBounds.height());
262             glyph.fMaskFormat = dst.fFormat;
263         }
264     }
265     return glyph;
266 
267 SK_ERROR:
268     // draw nothing 'cause we failed
269     glyph.fLeft     = 0;
270     glyph.fTop      = 0;
271     glyph.fWidth    = 0;
272     glyph.fHeight   = 0;
273     glyph.fMaskFormat = fRec.fMaskFormat;
274     return glyph;
275 }
276 
277 #define SK_SHOW_TEXT_BLIT_COVERAGE 0
278 
applyLUTToA8Mask(const SkMask & mask,const uint8_t * lut)279 static void applyLUTToA8Mask(const SkMask& mask, const uint8_t* lut) {
280     uint8_t* SK_RESTRICT dst = (uint8_t*)mask.fImage;
281     unsigned rowBytes = mask.fRowBytes;
282 
283     for (int y = mask.fBounds.height() - 1; y >= 0; --y) {
284         for (int x = mask.fBounds.width() - 1; x >= 0; --x) {
285             dst[x] = lut[dst[x]];
286         }
287         dst += rowBytes;
288     }
289 }
290 
pack4xHToMask(const SkPixmap & src,const SkMask & dst,const SkMaskGamma::PreBlend & maskPreBlend,const bool doBGR,const bool doVert)291 static void pack4xHToMask(const SkPixmap& src, const SkMask& dst,
292                           const SkMaskGamma::PreBlend& maskPreBlend,
293                           const bool doBGR, const bool doVert) {
294 #define SAMPLES_PER_PIXEL 4
295 #define LCD_PER_PIXEL 3
296     SkASSERT(kAlpha_8_SkColorType == src.colorType());
297 
298     const bool toA8 = SkMask::kA8_Format == dst.fFormat;
299     SkASSERT(SkMask::kLCD16_Format == dst.fFormat || toA8);
300 
301     // doVert in this function means swap x and y when writing to dst.
302     if (doVert) {
303         SkASSERT(src.width() == (dst.fBounds.height() - 2) * 4);
304         SkASSERT(src.height() == dst.fBounds.width());
305     } else {
306         SkASSERT(src.width() == (dst.fBounds.width() - 2) * 4);
307         SkASSERT(src.height() == dst.fBounds.height());
308     }
309 
310     const int sample_width = src.width();
311     const int height = src.height();
312 
313     uint8_t* dstImage = dst.fImage;
314     size_t dstRB = dst.fRowBytes;
315     // An N tap FIR is defined by
316     // out[n] = coeff[0]*x[n] + coeff[1]*x[n-1] + ... + coeff[N]*x[n-N]
317     // or
318     // out[n] = sum(i, 0, N, coeff[i]*x[n-i])
319 
320     // The strategy is to use one FIR (different coefficients) for each of r, g, and b.
321     // This means using every 4th FIR output value of each FIR and discarding the rest.
322     // The FIRs are aligned, and the coefficients reach 5 samples to each side of their 'center'.
323     // (For r and b this is technically incorrect, but the coeffs outside round to zero anyway.)
324 
325     // These are in some fixed point repesentation.
326     // Adding up to more than one simulates ink spread.
327     // For implementation reasons, these should never add up to more than two.
328 
329     // Coefficients determined by a gausian where 5 samples = 3 std deviations (0x110 'contrast').
330     // Calculated using tools/generate_fir_coeff.py
331     // With this one almost no fringing is ever seen, but it is imperceptibly blurry.
332     // The lcd smoothed text is almost imperceptibly different from gray,
333     // but is still sharper on small stems and small rounded corners than gray.
334     // This also seems to be about as wide as one can get and only have a three pixel kernel.
335     // TODO: calculate these at runtime so parameters can be adjusted (esp contrast).
336     static const unsigned int coefficients[LCD_PER_PIXEL][SAMPLES_PER_PIXEL*3] = {
337         //The red subpixel is centered inside the first sample (at 1/6 pixel), and is shifted.
338         { 0x03, 0x0b, 0x1c, 0x33,  0x40, 0x39, 0x24, 0x10,  0x05, 0x01, 0x00, 0x00, },
339         //The green subpixel is centered between two samples (at 1/2 pixel), so is symetric
340         { 0x00, 0x02, 0x08, 0x16,  0x2b, 0x3d, 0x3d, 0x2b,  0x16, 0x08, 0x02, 0x00, },
341         //The blue subpixel is centered inside the last sample (at 5/6 pixel), and is shifted.
342         { 0x00, 0x00, 0x01, 0x05,  0x10, 0x24, 0x39, 0x40,  0x33, 0x1c, 0x0b, 0x03, },
343     };
344 
345     size_t dstPB = toA8 ? sizeof(uint8_t) : sizeof(uint16_t);
346     for (int y = 0; y < height; ++y) {
347         uint8_t* dstP;
348         size_t dstPDelta;
349         if (doVert) {
350             dstP = SkTAddOffset<uint8_t>(dstImage, y * dstPB);
351             dstPDelta = dstRB;
352         } else {
353             dstP = SkTAddOffset<uint8_t>(dstImage, y * dstRB);
354             dstPDelta = dstPB;
355         }
356 
357         const uint8_t* srcP = src.addr8(0, y);
358 
359         // TODO: this fir filter implementation is straight forward, but slow.
360         // It should be possible to make it much faster.
361         for (int sample_x = -4; sample_x < sample_width + 4; sample_x += 4) {
362             int fir[LCD_PER_PIXEL] = { 0 };
363             for (int sample_index = std::max(0, sample_x - 4), coeff_index = sample_index - (sample_x - 4)
364                 ; sample_index < std::min(sample_x + 8, sample_width)
365                 ; ++sample_index, ++coeff_index)
366             {
367                 int sample_value = srcP[sample_index];
368                 for (int subpxl_index = 0; subpxl_index < LCD_PER_PIXEL; ++subpxl_index) {
369                     fir[subpxl_index] += coefficients[subpxl_index][coeff_index] * sample_value;
370                 }
371             }
372             for (int subpxl_index = 0; subpxl_index < LCD_PER_PIXEL; ++subpxl_index) {
373                 fir[subpxl_index] /= 0x100;
374                 fir[subpxl_index] = std::min(fir[subpxl_index], 255);
375             }
376 
377             U8CPU r, g, b;
378             if (doBGR) {
379                 r = fir[2];
380                 g = fir[1];
381                 b = fir[0];
382             } else {
383                 r = fir[0];
384                 g = fir[1];
385                 b = fir[2];
386             }
387 #if SK_SHOW_TEXT_BLIT_COVERAGE
388             r = std::max(r, 10); g = std::max(g, 10); b = std::max(b, 10);
389 #endif
390             if (toA8) {
391                 U8CPU a = (r + g + b) / 3;
392                 if (maskPreBlend.isApplicable()) {
393                     a = maskPreBlend.fG[a];
394                 }
395                 *dstP = a;
396             } else {
397                 if (maskPreBlend.isApplicable()) {
398                     r = maskPreBlend.fR[r];
399                     g = maskPreBlend.fG[g];
400                     b = maskPreBlend.fB[b];
401                 }
402                 *(uint16_t*)dstP = SkPack888ToRGB16(r, g, b);
403             }
404             dstP = SkTAddOffset<uint8_t>(dstP, dstPDelta);
405         }
406     }
407 }
408 
convert_8_to_1(unsigned byte)409 static inline int convert_8_to_1(unsigned byte) {
410     SkASSERT(byte <= 0xFF);
411     return byte >> 7;
412 }
413 
pack_8_to_1(const uint8_t alpha[8])414 static uint8_t pack_8_to_1(const uint8_t alpha[8]) {
415     unsigned bits = 0;
416     for (int i = 0; i < 8; ++i) {
417         bits <<= 1;
418         bits |= convert_8_to_1(alpha[i]);
419     }
420     return SkToU8(bits);
421 }
422 
packA8ToA1(const SkMask & mask,const uint8_t * src,size_t srcRB)423 static void packA8ToA1(const SkMask& mask, const uint8_t* src, size_t srcRB) {
424     const int height = mask.fBounds.height();
425     const int width = mask.fBounds.width();
426     const int octs = width >> 3;
427     const int leftOverBits = width & 7;
428 
429     uint8_t* dst = mask.fImage;
430     const int dstPad = mask.fRowBytes - SkAlign8(width)/8;
431     SkASSERT(dstPad >= 0);
432 
433     SkASSERT(width >= 0);
434     SkASSERT(srcRB >= (size_t)width);
435     const size_t srcPad = srcRB - width;
436 
437     for (int y = 0; y < height; ++y) {
438         for (int i = 0; i < octs; ++i) {
439             *dst++ = pack_8_to_1(src);
440             src += 8;
441         }
442         if (leftOverBits > 0) {
443             unsigned bits = 0;
444             int shift = 7;
445             for (int i = 0; i < leftOverBits; ++i, --shift) {
446                 bits |= convert_8_to_1(*src++) << shift;
447             }
448             *dst++ = bits;
449         }
450         src += srcPad;
451         dst += dstPad;
452     }
453 }
454 
generateMask(const SkMask & mask,const SkPath & path,const SkMaskGamma::PreBlend & maskPreBlend,const bool doBGR,const bool doVert,const bool a8FromLCD,const SkPaint::Style paintStyle)455 static void generateMask(const SkMask& mask, const SkPath& path,
456                          const SkMaskGamma::PreBlend& maskPreBlend,
457                          const bool doBGR, const bool doVert, const bool a8FromLCD,
458                          const SkPaint::Style paintStyle) {
459     SkASSERT(mask.fFormat == SkMask::kBW_Format ||
460              mask.fFormat == SkMask::kA8_Format ||
461              mask.fFormat == SkMask::kLCD16_Format);
462 
463     SkPaint paint;
464     SkPath strokePath;
465     const SkPath* pathToUse = &path;
466 
467     int srcW = mask.fBounds.width();
468     int srcH = mask.fBounds.height();
469     int dstW = srcW;
470     int dstH = srcH;
471 
472     SkMatrix matrix;
473     matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft),
474                         -SkIntToScalar(mask.fBounds.fTop));
475 
476     paint.setStyle(paintStyle);
477     paint.setAntiAlias(SkMask::kBW_Format != mask.fFormat);
478 
479     const bool fromLCD = (mask.fFormat == SkMask::kLCD16_Format) ||
480                          (mask.fFormat == SkMask::kA8_Format && a8FromLCD);
481     const bool intermediateDst = fromLCD || mask.fFormat == SkMask::kBW_Format;
482     if (fromLCD) {
483         if (doVert) {
484             dstW = 4*dstH - 8;
485             dstH = srcW;
486             matrix.setAll(0, 4, -SkIntToScalar(mask.fBounds.fTop + 1) * 4,
487                           1, 0, -SkIntToScalar(mask.fBounds.fLeft),
488                           0, 0, 1);
489         } else {
490             dstW = 4*dstW - 8;
491             matrix.setAll(4, 0, -SkIntToScalar(mask.fBounds.fLeft + 1) * 4,
492                           0, 1, -SkIntToScalar(mask.fBounds.fTop),
493                           0, 0, 1);
494         }
495 
496         // LCD hairline doesn't line up with the pixels, so do it the expensive way.
497         SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
498         if (paintStyle != SkPaint::kFill_Style) {
499             rec.setStrokeStyle(1.0f, paintStyle == SkPaint::kStrokeAndFill_Style);
500             rec.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kRound_Join, 0.0f);
501         }
502         if (rec.needToApply() && rec.applyToPath(&strokePath, path)) {
503             pathToUse = &strokePath;
504             paint.setStyle(SkPaint::kFill_Style);
505         }
506     }
507 
508     SkRasterClip clip;
509     clip.setRect(SkIRect::MakeWH(dstW, dstH));
510 
511     const SkImageInfo info = SkImageInfo::MakeA8(dstW, dstH);
512     SkAutoPixmapStorage dst;
513 
514     if (intermediateDst) {
515         if (!dst.tryAlloc(info)) {
516             // can't allocate offscreen, so empty the mask and return
517             sk_bzero(mask.fImage, mask.computeImageSize());
518             return;
519         }
520     } else {
521         dst.reset(info, mask.fImage, mask.fRowBytes);
522     }
523     sk_bzero(dst.writable_addr(), dst.computeByteSize());
524 
525     SkDraw  draw;
526     SkSimpleMatrixProvider matrixProvider(matrix);
527     draw.fDst            = dst;
528     draw.fRC             = &clip;
529     draw.fMatrixProvider = &matrixProvider;
530     draw.drawPath(*pathToUse, paint);
531 
532     switch (mask.fFormat) {
533         case SkMask::kBW_Format:
534             packA8ToA1(mask, dst.addr8(0, 0), dst.rowBytes());
535             break;
536         case SkMask::kA8_Format:
537             if (fromLCD) {
538                 pack4xHToMask(dst, mask, maskPreBlend, doBGR, doVert);
539             } else if (maskPreBlend.isApplicable()) {
540                 applyLUTToA8Mask(mask, maskPreBlend.fG);
541             }
542             break;
543         case SkMask::kLCD16_Format:
544             pack4xHToMask(dst, mask, maskPreBlend, doBGR, doVert);
545             break;
546         default:
547             break;
548     }
549 }
550 
getImage(const SkGlyph & origGlyph)551 void SkScalerContext::getImage(const SkGlyph& origGlyph) {
552     const SkGlyph* unfilteredGlyph = &origGlyph;
553     // in case we need to call generateImage on a mask-format that is different
554     // (i.e. larger) than what our caller allocated by looking at origGlyph.
555     SkAutoMalloc tmpGlyphImageStorage;
556     SkGlyph tmpGlyph;
557     if (fMaskFilter) {
558         // need the original bounds, sans our maskfilter
559         sk_sp<SkMaskFilter> mf = std::move(fMaskFilter);
560         tmpGlyph = this->internalMakeGlyph(origGlyph.getPackedID(), fRec.fMaskFormat);
561         fMaskFilter = std::move(mf);
562 
563         // Use the origGlyph storage for the temporary unfiltered mask if it will fit.
564         if (tmpGlyph.fMaskFormat == origGlyph.fMaskFormat &&
565             tmpGlyph.imageSize() <= origGlyph.imageSize())
566         {
567             tmpGlyph.fImage = origGlyph.fImage;
568         } else {
569             tmpGlyphImageStorage.reset(tmpGlyph.imageSize());
570             tmpGlyph.fImage = tmpGlyphImageStorage.get();
571         }
572         unfilteredGlyph = &tmpGlyph;
573     }
574 
575     if (!fGenerateImageFromPath) {
576         generateImage(*unfilteredGlyph);
577     } else {
578         SkPath devPath;
579         SkMask mask = unfilteredGlyph->mask();
580 
581         if (!this->internalGetPath(unfilteredGlyph->getPackedID(), &devPath)) {
582             generateImage(*unfilteredGlyph);
583         } else {
584             SkASSERT(SkMask::kARGB32_Format != origGlyph.fMaskFormat);
585             SkASSERT(SkMask::kARGB32_Format != mask.fFormat);
586             const bool doBGR = SkToBool(fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag);
587             const bool doVert = SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag);
588             const bool a8LCD = SkToBool(fRec.fFlags & SkScalerContext::kGenA8FromLCD_Flag);
589             const bool frameAndFill = SkToBool(fRec.fFlags & kFrameAndFill_Flag);
590             const SkPaint::Style paintStyle = fRec.fFrameWidth != 0 ? SkPaint::kFill_Style
591                                             : frameAndFill          ? SkPaint::kStrokeAndFill_Style
592                                             :                         SkPaint::kStroke_Style;
593             generateMask(mask, devPath, fPreBlend, doBGR, doVert, a8LCD, paintStyle);
594         }
595     }
596 
597     if (fMaskFilter) {
598         // k3D_Format should not be mask filtered.
599         SkASSERT(SkMask::k3D_Format != unfilteredGlyph->fMaskFormat);
600 
601         SkMask filteredMask;
602         SkMask srcMask;
603         SkMatrix m;
604         fRec.getMatrixFrom2x2(&m);
605 
606         if (as_MFB(fMaskFilter)->filterMask(&filteredMask, unfilteredGlyph->mask(), m, nullptr)) {
607             // Filter succeeded; filteredMask.fImage was allocated.
608             srcMask = filteredMask;
609         } else if (unfilteredGlyph->fImage == tmpGlyphImageStorage.get()) {
610             // Filter did nothing; unfiltered mask is independent of origGlyph.fImage.
611             srcMask = unfilteredGlyph->mask();
612         } else if (origGlyph.iRect() == unfilteredGlyph->iRect()) {
613             // Filter did nothing; the unfiltered mask is in origGlyph.fImage and matches.
614             return;
615         } else {
616             // Filter did nothing; the unfiltered mask is in origGlyph.fImage and conflicts.
617             srcMask = unfilteredGlyph->mask();
618             size_t imageSize = unfilteredGlyph->imageSize();
619             tmpGlyphImageStorage.reset(imageSize);
620             srcMask.fImage = static_cast<uint8_t*>(tmpGlyphImageStorage.get());
621             memcpy(srcMask.fImage, unfilteredGlyph->fImage, imageSize);
622         }
623 
624         SkASSERT_RELEASE(srcMask.fFormat == origGlyph.fMaskFormat);
625         SkMask dstMask = origGlyph.mask();
626         SkIRect origBounds = dstMask.fBounds;
627 
628         // Find the intersection of src and dst while updating the fImages.
629         if (srcMask.fBounds.fTop < dstMask.fBounds.fTop) {
630             int32_t topDiff = dstMask.fBounds.fTop - srcMask.fBounds.fTop;
631             srcMask.fImage += srcMask.fRowBytes * topDiff;
632             srcMask.fBounds.fTop = dstMask.fBounds.fTop;
633         }
634         if (dstMask.fBounds.fTop < srcMask.fBounds.fTop) {
635             int32_t topDiff = srcMask.fBounds.fTop - dstMask.fBounds.fTop;
636             dstMask.fImage += dstMask.fRowBytes * topDiff;
637             dstMask.fBounds.fTop = srcMask.fBounds.fTop;
638         }
639 
640         if (srcMask.fBounds.fLeft < dstMask.fBounds.fLeft) {
641             int32_t leftDiff = dstMask.fBounds.fLeft - srcMask.fBounds.fLeft;
642             srcMask.fImage += leftDiff;
643             srcMask.fBounds.fLeft = dstMask.fBounds.fLeft;
644         }
645         if (dstMask.fBounds.fLeft < srcMask.fBounds.fLeft) {
646             int32_t leftDiff = srcMask.fBounds.fLeft - dstMask.fBounds.fLeft;
647             dstMask.fImage += leftDiff;
648             dstMask.fBounds.fLeft = srcMask.fBounds.fLeft;
649         }
650 
651         if (srcMask.fBounds.fBottom < dstMask.fBounds.fBottom) {
652             dstMask.fBounds.fBottom = srcMask.fBounds.fBottom;
653         }
654         if (dstMask.fBounds.fBottom < srcMask.fBounds.fBottom) {
655             srcMask.fBounds.fBottom = dstMask.fBounds.fBottom;
656         }
657 
658         if (srcMask.fBounds.fRight < dstMask.fBounds.fRight) {
659             dstMask.fBounds.fRight = srcMask.fBounds.fRight;
660         }
661         if (dstMask.fBounds.fRight < srcMask.fBounds.fRight) {
662             srcMask.fBounds.fRight = dstMask.fBounds.fRight;
663         }
664 
665         SkASSERT(srcMask.fBounds == dstMask.fBounds);
666         int width = srcMask.fBounds.width();
667         int height = srcMask.fBounds.height();
668         int dstRB = dstMask.fRowBytes;
669         int srcRB = srcMask.fRowBytes;
670 
671         const uint8_t* src = srcMask.fImage;
672         uint8_t* dst = dstMask.fImage;
673 
674         if (SkMask::k3D_Format == filteredMask.fFormat) {
675             // we have to copy 3 times as much
676             height *= 3;
677         }
678 
679         // If not filling the full original glyph, clear it out first.
680         if (dstMask.fBounds != origBounds) {
681             sk_bzero(origGlyph.fImage, origGlyph.fHeight * origGlyph.rowBytes());
682         }
683 
684         while (--height >= 0) {
685             memcpy(dst, src, width);
686             src += srcRB;
687             dst += dstRB;
688         }
689         SkMask::FreeImage(filteredMask.fImage);
690     }
691 }
692 
getPath(SkPackedGlyphID glyphID,SkPath * path)693 bool SkScalerContext::getPath(SkPackedGlyphID glyphID, SkPath* path) {
694     return this->internalGetPath(glyphID, path);
695 }
696 
getFontMetrics(SkFontMetrics * fm)697 void SkScalerContext::getFontMetrics(SkFontMetrics* fm) {
698     SkASSERT(fm);
699     this->generateFontMetrics(fm);
700 }
701 
702 ///////////////////////////////////////////////////////////////////////////////
703 
internalGetPath(SkPackedGlyphID glyphID,SkPath * devPath)704 bool SkScalerContext::internalGetPath(SkPackedGlyphID glyphID, SkPath* devPath) {
705     SkPath  path;
706     if (!generatePath(glyphID.glyphID(), &path)) {
707         return false;
708     }
709 
710     if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
711         SkFixed dx = glyphID.getSubXFixed();
712         SkFixed dy = glyphID.getSubYFixed();
713         if (dx | dy) {
714             path.offset(SkFixedToScalar(dx), SkFixedToScalar(dy));
715         }
716     }
717 
718     if (fRec.fFrameWidth >= 0 || fPathEffect != nullptr) {
719         // need the path in user-space, with only the point-size applied
720         // so that our stroking and effects will operate the same way they
721         // would if the user had extracted the path themself, and then
722         // called drawPath
723         SkPath      localPath;
724         SkMatrix    matrix, inverse;
725 
726         fRec.getMatrixFrom2x2(&matrix);
727         if (!matrix.invert(&inverse)) {
728             // assume devPath is already empty.
729             return true;
730         }
731         path.transform(inverse, &localPath);
732         // now localPath is only affected by the paint settings, and not the canvas matrix
733 
734         SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
735 
736         if (fRec.fFrameWidth >= 0) {
737             rec.setStrokeStyle(fRec.fFrameWidth,
738                                SkToBool(fRec.fFlags & kFrameAndFill_Flag));
739             // glyphs are always closed contours, so cap type is ignored,
740             // so we just pass something.
741             rec.setStrokeParams((SkPaint::Cap)fRec.fStrokeCap,
742                                 (SkPaint::Join)fRec.fStrokeJoin,
743                                 fRec.fMiterLimit);
744         }
745 
746         if (fPathEffect) {
747             SkPath effectPath;
748             if (fPathEffect->filterPath(&effectPath, localPath, &rec, nullptr)) {
749                 localPath.swap(effectPath);
750             }
751         }
752 
753         if (rec.needToApply()) {
754             SkPath strokePath;
755             if (rec.applyToPath(&strokePath, localPath)) {
756                 localPath.swap(strokePath);
757             }
758         }
759 
760         // now return stuff to the caller
761         if (devPath) {
762             localPath.transform(matrix, devPath);
763         }
764     } else {   // nothing tricky to do
765         if (devPath) {
766             devPath->swap(path);
767         }
768     }
769 
770     if (devPath) {
771         devPath->updateBoundsCache();
772     }
773     return true;
774 }
775 
776 
getMatrixFrom2x2(SkMatrix * dst) const777 void SkScalerContextRec::getMatrixFrom2x2(SkMatrix* dst) const {
778     dst->setAll(fPost2x2[0][0], fPost2x2[0][1], 0,
779                 fPost2x2[1][0], fPost2x2[1][1], 0,
780                 0,              0,              1);
781 }
782 
getLocalMatrix(SkMatrix * m) const783 void SkScalerContextRec::getLocalMatrix(SkMatrix* m) const {
784     *m = SkFontPriv::MakeTextMatrix(fTextSize, fPreScaleX, fPreSkewX);
785 }
786 
getSingleMatrix(SkMatrix * m) const787 void SkScalerContextRec::getSingleMatrix(SkMatrix* m) const {
788     this->getLocalMatrix(m);
789 
790     //  now concat the device matrix
791     SkMatrix    deviceMatrix;
792     this->getMatrixFrom2x2(&deviceMatrix);
793     m->postConcat(deviceMatrix);
794 }
795 
computeMatrices(PreMatrixScale preMatrixScale,SkVector * s,SkMatrix * sA,SkMatrix * GsA,SkMatrix * G_inv,SkMatrix * A_out)796 bool SkScalerContextRec::computeMatrices(PreMatrixScale preMatrixScale, SkVector* s, SkMatrix* sA,
797                                          SkMatrix* GsA, SkMatrix* G_inv, SkMatrix* A_out)
798 {
799     // A is the 'total' matrix.
800     SkMatrix A;
801     this->getSingleMatrix(&A);
802 
803     // The caller may find the 'total' matrix useful when dealing directly with EM sizes.
804     if (A_out) {
805         *A_out = A;
806     }
807 
808     // GA is the matrix A with rotation removed.
809     SkMatrix GA;
810     bool skewedOrFlipped = A.getSkewX() || A.getSkewY() || A.getScaleX() < 0 || A.getScaleY() < 0;
811     if (skewedOrFlipped) {
812         // QR by Givens rotations. G is Q^T and GA is R. G is rotational (no reflections).
813         // h is where A maps the horizontal baseline.
814         SkPoint h = SkPoint::Make(SK_Scalar1, 0);
815         A.mapPoints(&h, 1);
816 
817         // G is the Givens Matrix for A (rotational matrix where GA[0][1] == 0).
818         SkMatrix G;
819         SkComputeGivensRotation(h, &G);
820 
821         GA = G;
822         GA.preConcat(A);
823 
824         // The 'remainingRotation' is G inverse, which is fairly simple since G is 2x2 rotational.
825         if (G_inv) {
826             G_inv->setAll(
827                 G.get(SkMatrix::kMScaleX), -G.get(SkMatrix::kMSkewX), G.get(SkMatrix::kMTransX),
828                 -G.get(SkMatrix::kMSkewY), G.get(SkMatrix::kMScaleY), G.get(SkMatrix::kMTransY),
829                 G.get(SkMatrix::kMPersp0), G.get(SkMatrix::kMPersp1), G.get(SkMatrix::kMPersp2));
830         }
831     } else {
832         GA = A;
833         if (G_inv) {
834             G_inv->reset();
835         }
836     }
837 
838     // If the 'total' matrix is singular, set the 'scale' to something finite and zero the matrices.
839     // All underlying ports have issues with zero text size, so use the matricies to zero.
840     // If one of the scale factors is less than 1/256 then an EM filling square will
841     // never affect any pixels.
842     // If there are any nonfinite numbers in the matrix, bail out and set the matrices to zero.
843     if (SkScalarAbs(GA.get(SkMatrix::kMScaleX)) <= SK_ScalarNearlyZero ||
844         SkScalarAbs(GA.get(SkMatrix::kMScaleY)) <= SK_ScalarNearlyZero ||
845         !GA.isFinite())
846     {
847         s->fX = SK_Scalar1;
848         s->fY = SK_Scalar1;
849         sA->setScale(0, 0);
850         if (GsA) {
851             GsA->setScale(0, 0);
852         }
853         if (G_inv) {
854             G_inv->reset();
855         }
856         return false;
857     }
858 
859     // At this point, given GA, create s.
860     switch (preMatrixScale) {
861         case kFull_PreMatrixScale:
862             s->fX = SkScalarAbs(GA.get(SkMatrix::kMScaleX));
863             s->fY = SkScalarAbs(GA.get(SkMatrix::kMScaleY));
864             break;
865         case kVertical_PreMatrixScale: {
866             SkScalar yScale = SkScalarAbs(GA.get(SkMatrix::kMScaleY));
867             s->fX = yScale;
868             s->fY = yScale;
869             break;
870         }
871         case kVerticalInteger_PreMatrixScale: {
872             SkScalar realYScale = SkScalarAbs(GA.get(SkMatrix::kMScaleY));
873             SkScalar intYScale = SkScalarRoundToScalar(realYScale);
874             if (intYScale == 0) {
875                 intYScale = SK_Scalar1;
876             }
877             s->fX = intYScale;
878             s->fY = intYScale;
879             break;
880         }
881     }
882 
883     // The 'remaining' matrix sA is the total matrix A without the scale.
884     if (!skewedOrFlipped && (
885             (kFull_PreMatrixScale == preMatrixScale) ||
886             (kVertical_PreMatrixScale == preMatrixScale && A.getScaleX() == A.getScaleY())))
887     {
888         // If GA == A and kFull_PreMatrixScale, sA is identity.
889         // If GA == A and kVertical_PreMatrixScale and A.scaleX == A.scaleY, sA is identity.
890         sA->reset();
891     } else if (!skewedOrFlipped && kVertical_PreMatrixScale == preMatrixScale) {
892         // If GA == A and kVertical_PreMatrixScale, sA.scaleY is SK_Scalar1.
893         sA->reset();
894         sA->setScaleX(A.getScaleX() / s->fY);
895     } else {
896         // TODO: like kVertical_PreMatrixScale, kVerticalInteger_PreMatrixScale with int scales.
897         *sA = A;
898         sA->preScale(SkScalarInvert(s->fX), SkScalarInvert(s->fY));
899     }
900 
901     // The 'remainingWithoutRotation' matrix GsA is the non-rotational part of A without the scale.
902     if (GsA) {
903         *GsA = GA;
904          // G is rotational so reorders with the scale.
905         GsA->preScale(SkScalarInvert(s->fX), SkScalarInvert(s->fY));
906     }
907 
908     return true;
909 }
910 
computeAxisAlignmentForHText() const911 SkAxisAlignment SkScalerContext::computeAxisAlignmentForHText() const {
912     return fRec.computeAxisAlignmentForHText();
913 }
914 
computeAxisAlignmentForHText() const915 SkAxisAlignment SkScalerContextRec::computeAxisAlignmentForHText() const {
916     // Why fPost2x2 can be used here.
917     // getSingleMatrix multiplies in getLocalMatrix, which consists of
918     // * fTextSize (a scale, which has no effect)
919     // * fPreScaleX (a scale in x, which has no effect)
920     // * fPreSkewX (has no effect, but would on vertical text alignment).
921     // In other words, making the text bigger, stretching it along the
922     // horizontal axis, or fake italicizing it does not move the baseline.
923     if (!SkToBool(fFlags & SkScalerContext::kBaselineSnap_Flag)) {
924         return kNone_SkAxisAlignment;
925     }
926 
927     if (0 == fPost2x2[1][0]) {
928         // The x axis is mapped onto the x axis.
929         return kX_SkAxisAlignment;
930     }
931     if (0 == fPost2x2[0][0]) {
932         // The x axis is mapped onto the y axis.
933         return kY_SkAxisAlignment;
934     }
935     return kNone_SkAxisAlignment;
936 }
937 
setLuminanceColor(SkColor c)938 void SkScalerContextRec::setLuminanceColor(SkColor c) {
939     fLumBits = SkMaskGamma::CanonicalColor(
940             SkColorSetRGB(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c)));
941 }
942 
943 /*
944  *  Return the scalar with only limited fractional precision. Used to consolidate matrices
945  *  that vary only slightly when we create our key into the font cache, since the font scaler
946  *  typically returns the same looking resuts for tiny changes in the matrix.
947  */
sk_relax(SkScalar x)948 static SkScalar sk_relax(SkScalar x) {
949     SkScalar n = SkScalarRoundToScalar(x * 1024);
950     return n / 1024.0f;
951 }
952 
compute_mask_format(const SkFont & font)953 static SkMask::Format compute_mask_format(const SkFont& font) {
954     switch (font.getEdging()) {
955         case SkFont::Edging::kAlias:
956             return SkMask::kBW_Format;
957         case SkFont::Edging::kAntiAlias:
958             return SkMask::kA8_Format;
959         case SkFont::Edging::kSubpixelAntiAlias:
960             return SkMask::kLCD16_Format;
961     }
962     SkASSERT(false);
963     return SkMask::kA8_Format;
964 }
965 
966 // Beyond this size, LCD doesn't appreciably improve quality, but it always
967 // cost more RAM and draws slower, so we set a cap.
968 #ifndef SK_MAX_SIZE_FOR_LCDTEXT
969     #define SK_MAX_SIZE_FOR_LCDTEXT    48
970 #endif
971 
972 const SkScalar gMaxSize2ForLCDText = SK_MAX_SIZE_FOR_LCDTEXT * SK_MAX_SIZE_FOR_LCDTEXT;
973 
too_big_for_lcd(const SkScalerContextRec & rec,bool checkPost2x2)974 static bool too_big_for_lcd(const SkScalerContextRec& rec, bool checkPost2x2) {
975     if (checkPost2x2) {
976         SkScalar area = rec.fPost2x2[0][0] * rec.fPost2x2[1][1] -
977                         rec.fPost2x2[1][0] * rec.fPost2x2[0][1];
978         area *= rec.fTextSize * rec.fTextSize;
979         return area > gMaxSize2ForLCDText;
980     } else {
981         return rec.fTextSize > SK_MAX_SIZE_FOR_LCDTEXT;
982     }
983 }
984 
985 // The only reason this is not file static is because it needs the context of SkScalerContext to
986 // access SkPaint::computeLuminanceColor.
MakeRecAndEffects(const SkFont & font,const SkPaint & paint,const SkSurfaceProps & surfaceProps,SkScalerContextFlags scalerContextFlags,const SkMatrix & deviceMatrix,SkScalerContextRec * rec,SkScalerContextEffects * effects)987 void SkScalerContext::MakeRecAndEffects(const SkFont& font, const SkPaint& paint,
988                                         const SkSurfaceProps& surfaceProps,
989                                         SkScalerContextFlags scalerContextFlags,
990                                         const SkMatrix& deviceMatrix,
991                                         SkScalerContextRec* rec,
992                                         SkScalerContextEffects* effects) {
993     SkASSERT(!deviceMatrix.hasPerspective());
994 
995     sk_bzero(rec, sizeof(SkScalerContextRec));
996 
997     SkTypeface* typeface = font.getTypefaceOrDefault();
998 
999     rec->fFontID = typeface->uniqueID();
1000     rec->fTextSize = font.getSize();
1001     rec->fPreScaleX = font.getScaleX();
1002     rec->fPreSkewX  = font.getSkewX();
1003 
1004     bool checkPost2x2 = false;
1005 
1006     const SkMatrix::TypeMask mask = deviceMatrix.getType();
1007     if (mask & SkMatrix::kScale_Mask) {
1008         rec->fPost2x2[0][0] = sk_relax(deviceMatrix.getScaleX());
1009         rec->fPost2x2[1][1] = sk_relax(deviceMatrix.getScaleY());
1010         checkPost2x2 = true;
1011     } else {
1012         rec->fPost2x2[0][0] = rec->fPost2x2[1][1] = SK_Scalar1;
1013     }
1014     if (mask & SkMatrix::kAffine_Mask) {
1015         rec->fPost2x2[0][1] = sk_relax(deviceMatrix.getSkewX());
1016         rec->fPost2x2[1][0] = sk_relax(deviceMatrix.getSkewY());
1017         checkPost2x2 = true;
1018     } else {
1019         rec->fPost2x2[0][1] = rec->fPost2x2[1][0] = 0;
1020     }
1021 
1022     SkPaint::Style  style = paint.getStyle();
1023     SkScalar        strokeWidth = paint.getStrokeWidth();
1024 
1025     unsigned flags = 0;
1026 
1027     if (font.isEmbolden()) {
1028 #ifdef SK_USE_FREETYPE_EMBOLDEN
1029         flags |= SkScalerContext::kEmbolden_Flag;
1030 #else
1031         SkScalar fakeBoldScale = SkScalarInterpFunc(font.getSize(),
1032                                                     kStdFakeBoldInterpKeys,
1033                                                     kStdFakeBoldInterpValues,
1034                                                     kStdFakeBoldInterpLength);
1035         SkScalar extra = font.getSize() * fakeBoldScale;
1036 
1037         if (style == SkPaint::kFill_Style) {
1038             style = SkPaint::kStrokeAndFill_Style;
1039             strokeWidth = extra;    // ignore paint's strokeWidth if it was "fill"
1040         } else {
1041             strokeWidth += extra;
1042         }
1043 #endif
1044     }
1045 
1046     if (style != SkPaint::kFill_Style && strokeWidth >= 0) {
1047         rec->fFrameWidth = strokeWidth;
1048         rec->fMiterLimit = paint.getStrokeMiter();
1049         rec->fStrokeJoin = SkToU8(paint.getStrokeJoin());
1050         rec->fStrokeCap = SkToU8(paint.getStrokeCap());
1051 
1052         if (style == SkPaint::kStrokeAndFill_Style) {
1053             flags |= SkScalerContext::kFrameAndFill_Flag;
1054         }
1055     } else {
1056         rec->fFrameWidth = -1;
1057         rec->fMiterLimit = 0;
1058         rec->fStrokeJoin = 0;
1059         rec->fStrokeCap = 0;
1060     }
1061 
1062     rec->fMaskFormat = compute_mask_format(font);
1063 
1064     if (SkMask::kLCD16_Format == rec->fMaskFormat) {
1065         if (too_big_for_lcd(*rec, checkPost2x2)) {
1066             rec->fMaskFormat = SkMask::kA8_Format;
1067             flags |= SkScalerContext::kGenA8FromLCD_Flag;
1068         } else {
1069             SkPixelGeometry geometry = surfaceProps.pixelGeometry();
1070 
1071             switch (geometry) {
1072                 case kUnknown_SkPixelGeometry:
1073                     // eeek, can't support LCD
1074                     rec->fMaskFormat = SkMask::kA8_Format;
1075                     flags |= SkScalerContext::kGenA8FromLCD_Flag;
1076                     break;
1077                 case kRGB_H_SkPixelGeometry:
1078                     // our default, do nothing.
1079                     break;
1080                 case kBGR_H_SkPixelGeometry:
1081                     flags |= SkScalerContext::kLCD_BGROrder_Flag;
1082                     break;
1083                 case kRGB_V_SkPixelGeometry:
1084                     flags |= SkScalerContext::kLCD_Vertical_Flag;
1085                     break;
1086                 case kBGR_V_SkPixelGeometry:
1087                     flags |= SkScalerContext::kLCD_Vertical_Flag;
1088                     flags |= SkScalerContext::kLCD_BGROrder_Flag;
1089                     break;
1090             }
1091         }
1092     }
1093 
1094     if (font.isEmbeddedBitmaps()) {
1095         flags |= SkScalerContext::kEmbeddedBitmapText_Flag;
1096     }
1097     if (font.isSubpixel()) {
1098         flags |= SkScalerContext::kSubpixelPositioning_Flag;
1099     }
1100     if (font.isForceAutoHinting()) {
1101         flags |= SkScalerContext::kForceAutohinting_Flag;
1102     }
1103     if (font.isLinearMetrics()) {
1104         flags |= SkScalerContext::kLinearMetrics_Flag;
1105     }
1106     if (font.isBaselineSnap()) {
1107         flags |= SkScalerContext::kBaselineSnap_Flag;
1108     }
1109     rec->fFlags = SkToU16(flags);
1110 
1111     // these modify fFlags, so do them after assigning fFlags
1112     rec->setHinting(font.getHinting());
1113     rec->setLuminanceColor(SkPaintPriv::ComputeLuminanceColor(paint));
1114 
1115     // For now always set the paint gamma equal to the device gamma.
1116     // The math in SkMaskGamma can handle them being different,
1117     // but it requires superluminous masks when
1118     // Ex : deviceGamma(x) < paintGamma(x) and x is sufficiently large.
1119     rec->setDeviceGamma(SK_GAMMA_EXPONENT);
1120     rec->setPaintGamma(SK_GAMMA_EXPONENT);
1121 
1122 #ifdef SK_GAMMA_CONTRAST
1123     rec->setContrast(SK_GAMMA_CONTRAST);
1124 #else
1125     // A value of 0.5 for SK_GAMMA_CONTRAST appears to be a good compromise.
1126     // With lower values small text appears washed out (though correctly so).
1127     // With higher values lcd fringing is worse and the smoothing effect of
1128     // partial coverage is diminished.
1129     rec->setContrast(0.5f);
1130 #endif
1131 
1132     if (!SkToBool(scalerContextFlags & SkScalerContextFlags::kFakeGamma)) {
1133         rec->ignoreGamma();
1134     }
1135     if (!SkToBool(scalerContextFlags & SkScalerContextFlags::kBoostContrast)) {
1136         rec->setContrast(0);
1137     }
1138 
1139     new (effects) SkScalerContextEffects{paint};
1140 }
1141 
CreateDescriptorAndEffectsUsingPaint(const SkFont & font,const SkPaint & paint,const SkSurfaceProps & surfaceProps,SkScalerContextFlags scalerContextFlags,const SkMatrix & deviceMatrix,SkAutoDescriptor * ad,SkScalerContextEffects * effects)1142 SkDescriptor* SkScalerContext::CreateDescriptorAndEffectsUsingPaint(
1143     const SkFont& font, const SkPaint& paint, const SkSurfaceProps& surfaceProps,
1144     SkScalerContextFlags scalerContextFlags, const SkMatrix& deviceMatrix, SkAutoDescriptor* ad,
1145     SkScalerContextEffects* effects)
1146 {
1147     SkScalerContextRec rec;
1148     MakeRecAndEffects(font, paint, surfaceProps, scalerContextFlags, deviceMatrix, &rec, effects);
1149     return AutoDescriptorGivenRecAndEffects(rec, *effects, ad);
1150 }
1151 
calculate_size_and_flatten(const SkScalerContextRec & rec,const SkScalerContextEffects & effects,SkBinaryWriteBuffer * effectBuffer)1152 static size_t calculate_size_and_flatten(const SkScalerContextRec& rec,
1153                                          const SkScalerContextEffects& effects,
1154                                          SkBinaryWriteBuffer* effectBuffer) {
1155     size_t descSize = sizeof(rec);
1156     int entryCount = 1;
1157 
1158     if (effects.fPathEffect || effects.fMaskFilter) {
1159         if (effects.fPathEffect) { effectBuffer->writeFlattenable(effects.fPathEffect); }
1160         if (effects.fMaskFilter) { effectBuffer->writeFlattenable(effects.fMaskFilter); }
1161         entryCount += 1;
1162         descSize += effectBuffer->bytesWritten();
1163     }
1164 
1165     descSize += SkDescriptor::ComputeOverhead(entryCount);
1166     return descSize;
1167 }
1168 
generate_descriptor(const SkScalerContextRec & rec,const SkBinaryWriteBuffer & effectBuffer,SkDescriptor * desc)1169 static void generate_descriptor(const SkScalerContextRec& rec,
1170                                 const SkBinaryWriteBuffer& effectBuffer,
1171                                 SkDescriptor* desc) {
1172     desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
1173 
1174     if (effectBuffer.bytesWritten() > 0) {
1175         effectBuffer.writeToMemory(desc->addEntry(kEffects_SkDescriptorTag,
1176                                                   effectBuffer.bytesWritten(),
1177                                                   nullptr));
1178     }
1179 
1180     desc->computeChecksum();
1181 }
1182 
AutoDescriptorGivenRecAndEffects(const SkScalerContextRec & rec,const SkScalerContextEffects & effects,SkAutoDescriptor * ad)1183 SkDescriptor* SkScalerContext::AutoDescriptorGivenRecAndEffects(
1184     const SkScalerContextRec& rec,
1185     const SkScalerContextEffects& effects,
1186     SkAutoDescriptor* ad)
1187 {
1188     SkBinaryWriteBuffer buf;
1189 
1190     ad->reset(calculate_size_and_flatten(rec, effects, &buf));
1191     generate_descriptor(rec, buf, ad->getDesc());
1192 
1193     return ad->getDesc();
1194 }
1195 
DescriptorGivenRecAndEffects(const SkScalerContextRec & rec,const SkScalerContextEffects & effects)1196 std::unique_ptr<SkDescriptor> SkScalerContext::DescriptorGivenRecAndEffects(
1197     const SkScalerContextRec& rec,
1198     const SkScalerContextEffects& effects)
1199 {
1200     SkBinaryWriteBuffer buf;
1201 
1202     auto desc = SkDescriptor::Alloc(calculate_size_and_flatten(rec, effects, &buf));
1203     generate_descriptor(rec, buf, desc.get());
1204 
1205     return desc;
1206 }
1207 
DescriptorBufferGiveRec(const SkScalerContextRec & rec,void * buffer)1208 void SkScalerContext::DescriptorBufferGiveRec(const SkScalerContextRec& rec, void* buffer) {
1209     generate_descriptor(rec, SkBinaryWriteBuffer{}, (SkDescriptor*)buffer);
1210 }
1211 
CheckBufferSizeForRec(const SkScalerContextRec & rec,const SkScalerContextEffects & effects,size_t size)1212 bool SkScalerContext::CheckBufferSizeForRec(const SkScalerContextRec& rec,
1213                                             const SkScalerContextEffects& effects,
1214                                             size_t size) {
1215     SkBinaryWriteBuffer buf;
1216     return size >= calculate_size_and_flatten(rec, effects, &buf);
1217 }
1218 
MakeEmpty(sk_sp<SkTypeface> typeface,const SkScalerContextEffects & effects,const SkDescriptor * desc)1219 std::unique_ptr<SkScalerContext> SkScalerContext::MakeEmpty(
1220         sk_sp<SkTypeface> typeface, const SkScalerContextEffects& effects,
1221         const SkDescriptor* desc) {
1222     class SkScalerContext_Empty : public SkScalerContext {
1223     public:
1224         SkScalerContext_Empty(sk_sp<SkTypeface> typeface, const SkScalerContextEffects& effects,
1225                               const SkDescriptor* desc)
1226                 : SkScalerContext(std::move(typeface), effects, desc) {}
1227 
1228     protected:
1229         bool generateAdvance(SkGlyph* glyph) override {
1230             glyph->zeroMetrics();
1231             return true;
1232         }
1233         void generateMetrics(SkGlyph* glyph) override {
1234             glyph->fMaskFormat = fRec.fMaskFormat;
1235             glyph->zeroMetrics();
1236         }
1237         void generateImage(const SkGlyph& glyph) override {}
1238         bool generatePath(SkGlyphID glyph, SkPath* path) override {
1239             path->reset();
1240             return false;
1241         }
1242         void generateFontMetrics(SkFontMetrics* metrics) override {
1243             if (metrics) {
1244                 sk_bzero(metrics, sizeof(*metrics));
1245             }
1246         }
1247     };
1248 
1249     return std::make_unique<SkScalerContext_Empty>(std::move(typeface), effects, desc);
1250 }
1251 
1252 
1253 
1254 
1255