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