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