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