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