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