xref: /aosp_15_r20/external/skia/src/core/SkScalerContext.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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 #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(sk_sp<SkTypeface> typeface,const SkScalerContextEffects & effects,const SkDescriptor * desc)89 SkScalerContext::SkScalerContext(sk_sp<SkTypeface> typeface, const SkScalerContextEffects& effects,
90                                  const SkDescriptor* desc)
91     : fRec(PreprocessRec(*typeface, effects, *desc))
92     , fTypeface(std::move(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     draw.drawPath(*pathToUse, paint);
570 
571     switch (dstMask.fFormat) {
572         case SkMask::kBW_Format:
573             packA8ToA1(dstMask, dst.addr8(0, 0), dst.rowBytes());
574             break;
575         case SkMask::kA8_Format:
576             if (fromLCD) {
577                 pack4xHToMask(dst, dstMask, maskPreBlend, doBGR, verticalLCD);
578             } else if (maskPreBlend.isApplicable()) {
579                 applyLUTToA8Mask(dstMask, maskPreBlend.fG);
580             }
581             break;
582         case SkMask::kLCD16_Format:
583             pack4xHToMask(dst, dstMask, maskPreBlend, doBGR, verticalLCD);
584             break;
585         default:
586             break;
587     }
588 }
589 
getImage(const SkGlyph & origGlyph)590 void SkScalerContext::getImage(const SkGlyph& origGlyph) {
591     SkASSERT(origGlyph.fAdvancesBoundsFormatAndInitialPathDone);
592 
593     const SkGlyph* unfilteredGlyph = &origGlyph;
594     // in case we need to call generateImage on a mask-format that is different
595     // (i.e. larger) than what our caller allocated by looking at origGlyph.
596     SkAutoMalloc tmpGlyphImageStorage;
597     SkGlyph tmpGlyph;
598     SkSTArenaAlloc<sizeof(SkGlyph::PathData)> tmpGlyphPathDataStorage;
599     if (fMaskFilter) {
600         // need the original bounds, sans our maskfilter
601         sk_sp<SkMaskFilter> mf = std::move(fMaskFilter);
602         tmpGlyph = this->makeGlyph(origGlyph.getPackedID(), &tmpGlyphPathDataStorage);
603         fMaskFilter = std::move(mf);
604 
605         // Use the origGlyph storage for the temporary unfiltered mask if it will fit.
606         if (tmpGlyph.fMaskFormat == origGlyph.fMaskFormat &&
607             tmpGlyph.imageSize() <= origGlyph.imageSize())
608         {
609             tmpGlyph.fImage = origGlyph.fImage;
610         } else {
611             tmpGlyphImageStorage.reset(tmpGlyph.imageSize());
612             tmpGlyph.fImage = tmpGlyphImageStorage.get();
613         }
614         unfilteredGlyph = &tmpGlyph;
615     }
616 
617     if (!fGenerateImageFromPath) {
618         generateImage(*unfilteredGlyph, unfilteredGlyph->fImage);
619     } else {
620         SkASSERT(origGlyph.setPathHasBeenCalled());
621         const SkPath* devPath = origGlyph.path();
622 
623         if (!devPath) {
624             generateImage(*unfilteredGlyph, unfilteredGlyph->fImage);
625         } else {
626             SkMaskBuilder mask(static_cast<uint8_t*>(unfilteredGlyph->fImage),
627                                unfilteredGlyph->iRect(), unfilteredGlyph->rowBytes(),
628                                unfilteredGlyph->maskFormat());
629             SkASSERT(SkMask::kARGB32_Format != origGlyph.fMaskFormat);
630             SkASSERT(SkMask::kARGB32_Format != mask.fFormat);
631             const bool doBGR = SkToBool(fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag);
632             const bool doVert = SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag);
633             const bool a8LCD = SkToBool(fRec.fFlags & SkScalerContext::kGenA8FromLCD_Flag);
634             const bool hairline = origGlyph.pathIsHairline();
635             GenerateImageFromPath(mask, *devPath, fPreBlend, doBGR, doVert, a8LCD, hairline);
636         }
637     }
638 
639     if (fMaskFilter) {
640         // k3D_Format should not be mask filtered.
641         SkASSERT(SkMask::k3D_Format != unfilteredGlyph->fMaskFormat);
642 
643         SkMaskBuilder srcMask;
644         SkAutoMaskFreeImage srcMaskOwnedImage(nullptr);
645         SkMatrix m;
646         fRec.getMatrixFrom2x2(&m);
647 
648         if (as_MFB(fMaskFilter)->filterMask(&srcMask, unfilteredGlyph->mask(), m, nullptr)) {
649             // Filter succeeded; srcMask.fImage was allocated.
650             srcMaskOwnedImage.reset(srcMask.image());
651         } else if (unfilteredGlyph->fImage == tmpGlyphImageStorage.get()) {
652             // Filter did nothing; unfiltered mask is independent of origGlyph.fImage.
653             srcMask = SkMaskBuilder(static_cast<uint8_t*>(unfilteredGlyph->fImage),
654                                     unfilteredGlyph->iRect(), unfilteredGlyph->rowBytes(),
655                                     unfilteredGlyph->maskFormat());
656         } else if (origGlyph.iRect() == unfilteredGlyph->iRect()) {
657             // Filter did nothing; the unfiltered mask is in origGlyph.fImage and matches.
658             return;
659         } else {
660             // Filter did nothing; the unfiltered mask is in origGlyph.fImage and conflicts.
661             srcMask = SkMaskBuilder(static_cast<uint8_t*>(unfilteredGlyph->fImage),
662                                     unfilteredGlyph->iRect(), unfilteredGlyph->rowBytes(),
663                                     unfilteredGlyph->maskFormat());
664             size_t imageSize = unfilteredGlyph->imageSize();
665             tmpGlyphImageStorage.reset(imageSize);
666             srcMask.image() = static_cast<uint8_t*>(tmpGlyphImageStorage.get());
667             memcpy(srcMask.image(), unfilteredGlyph->fImage, imageSize);
668         }
669 
670         SkASSERT_RELEASE(srcMask.fFormat == origGlyph.fMaskFormat);
671         SkMaskBuilder dstMask = SkMaskBuilder(static_cast<uint8_t*>(origGlyph.fImage),
672                                               origGlyph.iRect(), origGlyph.rowBytes(),
673                                               origGlyph.maskFormat());
674         SkIRect origBounds = dstMask.fBounds;
675 
676         // Find the intersection of src and dst while updating the fImages.
677         if (srcMask.fBounds.fTop < dstMask.fBounds.fTop) {
678             int32_t topDiff = dstMask.fBounds.fTop - srcMask.fBounds.fTop;
679             srcMask.image() += srcMask.fRowBytes * topDiff;
680             srcMask.bounds().fTop = dstMask.fBounds.fTop;
681         }
682         if (dstMask.fBounds.fTop < srcMask.fBounds.fTop) {
683             int32_t topDiff = srcMask.fBounds.fTop - dstMask.fBounds.fTop;
684             dstMask.image() += dstMask.fRowBytes * topDiff;
685             dstMask.bounds().fTop = srcMask.fBounds.fTop;
686         }
687 
688         if (srcMask.fBounds.fLeft < dstMask.fBounds.fLeft) {
689             int32_t leftDiff = dstMask.fBounds.fLeft - srcMask.fBounds.fLeft;
690             srcMask.image() += leftDiff;
691             srcMask.bounds().fLeft = dstMask.fBounds.fLeft;
692         }
693         if (dstMask.fBounds.fLeft < srcMask.fBounds.fLeft) {
694             int32_t leftDiff = srcMask.fBounds.fLeft - dstMask.fBounds.fLeft;
695             dstMask.image() += leftDiff;
696             dstMask.bounds().fLeft = srcMask.fBounds.fLeft;
697         }
698 
699         if (srcMask.fBounds.fBottom < dstMask.fBounds.fBottom) {
700             dstMask.bounds().fBottom = srcMask.fBounds.fBottom;
701         }
702         if (dstMask.fBounds.fBottom < srcMask.fBounds.fBottom) {
703             srcMask.bounds().fBottom = dstMask.fBounds.fBottom;
704         }
705 
706         if (srcMask.fBounds.fRight < dstMask.fBounds.fRight) {
707             dstMask.bounds().fRight = srcMask.fBounds.fRight;
708         }
709         if (dstMask.fBounds.fRight < srcMask.fBounds.fRight) {
710             srcMask.bounds().fRight = dstMask.fBounds.fRight;
711         }
712 
713         SkASSERT(srcMask.fBounds == dstMask.fBounds);
714         int width = srcMask.fBounds.width();
715         int height = srcMask.fBounds.height();
716         int dstRB = dstMask.fRowBytes;
717         int srcRB = srcMask.fRowBytes;
718 
719         const uint8_t* src = srcMask.fImage;
720         uint8_t* dst = dstMask.image();
721 
722         if (SkMask::k3D_Format == srcMask.fFormat) {
723             // we have to copy 3 times as much
724             height *= 3;
725         }
726 
727         // If not filling the full original glyph, clear it out first.
728         if (dstMask.fBounds != origBounds) {
729             sk_bzero(origGlyph.fImage, origGlyph.fHeight * origGlyph.rowBytes());
730         }
731 
732         while (--height >= 0) {
733             memcpy(dst, src, width);
734             src += srcRB;
735             dst += dstRB;
736         }
737     }
738 }
739 
getPath(SkGlyph & glyph,SkArenaAlloc * alloc)740 void SkScalerContext::getPath(SkGlyph& glyph, SkArenaAlloc* alloc) {
741     this->internalGetPath(glyph, alloc);
742 }
743 
getDrawable(SkGlyph & glyph)744 sk_sp<SkDrawable> SkScalerContext::getDrawable(SkGlyph& glyph) {
745     return this->generateDrawable(glyph);
746 }
747 //TODO: make pure virtual
generateDrawable(const SkGlyph &)748 sk_sp<SkDrawable> SkScalerContext::generateDrawable(const SkGlyph&) {
749     return nullptr;
750 }
751 
getFontMetrics(SkFontMetrics * fm)752 void SkScalerContext::getFontMetrics(SkFontMetrics* fm) {
753     SkASSERT(fm);
754     this->generateFontMetrics(fm);
755 }
756 
757 ///////////////////////////////////////////////////////////////////////////////
758 
internalGetPath(SkGlyph & glyph,SkArenaAlloc * alloc)759 void SkScalerContext::internalGetPath(SkGlyph& glyph, SkArenaAlloc* alloc) {
760     SkASSERT(glyph.fAdvancesBoundsFormatAndInitialPathDone);
761 
762     if (glyph.setPathHasBeenCalled()) {
763         return;
764     }
765 
766     SkPath path;
767     SkPath devPath;
768     bool hairline = false;
769     bool pathModified = false;
770 
771     SkPackedGlyphID glyphID = glyph.getPackedID();
772     if (!generatePath(glyph, &path, &pathModified)) {
773         glyph.setPath(alloc, (SkPath*)nullptr, hairline, pathModified);
774         return;
775     }
776 
777     if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
778         SkFixed dx = glyphID.getSubXFixed();
779         SkFixed dy = glyphID.getSubYFixed();
780         if (dx | dy) {
781             pathModified = true;
782             path.offset(SkFixedToScalar(dx), SkFixedToScalar(dy));
783         }
784     }
785 
786     if (fRec.fFrameWidth < 0 && fPathEffect == nullptr) {
787         devPath.swap(path);
788     } else {
789         pathModified = true; // It could still end up the same, but it's probably going to change.
790 
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, pathModified);
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, pathModified);
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 
useStrokeForFakeBold()1009 void SkScalerContextRec::useStrokeForFakeBold() {
1010     if (!SkToBool(fFlags & SkScalerContext::kEmbolden_Flag)) {
1011         return;
1012     }
1013     fFlags &= ~SkScalerContext::kEmbolden_Flag;
1014 
1015     SkScalar fakeBoldScale = SkScalarInterpFunc(fTextSize,
1016                                                 kStdFakeBoldInterpKeys,
1017                                                 kStdFakeBoldInterpValues,
1018                                                 kStdFakeBoldInterpLength);
1019     SkScalar extra = fTextSize * fakeBoldScale;
1020 
1021     if (fFrameWidth >= 0) {
1022         fFrameWidth += extra;
1023     } else {
1024         fFlags |= SkScalerContext::kFrameAndFill_Flag;
1025         fFrameWidth = extra;
1026         SkPaint paint;
1027         fMiterLimit = paint.getStrokeMiter();
1028         fStrokeJoin = SkToU8(paint.getStrokeJoin());
1029         fStrokeCap = SkToU8(paint.getStrokeCap());
1030     }
1031 }
1032 
1033 /*
1034  *  Return the scalar with only limited fractional precision. Used to consolidate matrices
1035  *  that vary only slightly when we create our key into the font cache, since the font scaler
1036  *  typically returns the same looking resuts for tiny changes in the matrix.
1037  */
sk_relax(SkScalar x)1038 static SkScalar sk_relax(SkScalar x) {
1039     SkScalar n = SkScalarRoundToScalar(x * 1024);
1040     return n / 1024.0f;
1041 }
1042 
compute_mask_format(const SkFont & font)1043 static SkMask::Format compute_mask_format(const SkFont& font) {
1044     switch (font.getEdging()) {
1045         case SkFont::Edging::kAlias:
1046             return SkMask::kBW_Format;
1047         case SkFont::Edging::kAntiAlias:
1048             return SkMask::kA8_Format;
1049         case SkFont::Edging::kSubpixelAntiAlias:
1050             return SkMask::kLCD16_Format;
1051     }
1052     SkASSERT(false);
1053     return SkMask::kA8_Format;
1054 }
1055 
1056 // Beyond this size, LCD doesn't appreciably improve quality, but it always
1057 // cost more RAM and draws slower, so we set a cap.
1058 #ifndef SK_MAX_SIZE_FOR_LCDTEXT
1059     #define SK_MAX_SIZE_FOR_LCDTEXT    48
1060 #endif
1061 
1062 const SkScalar gMaxSize2ForLCDText = SK_MAX_SIZE_FOR_LCDTEXT * SK_MAX_SIZE_FOR_LCDTEXT;
1063 
too_big_for_lcd(const SkScalerContextRec & rec,bool checkPost2x2)1064 static bool too_big_for_lcd(const SkScalerContextRec& rec, bool checkPost2x2) {
1065     if (checkPost2x2) {
1066         SkScalar area = rec.fPost2x2[0][0] * rec.fPost2x2[1][1] -
1067                         rec.fPost2x2[1][0] * rec.fPost2x2[0][1];
1068         area *= rec.fTextSize * rec.fTextSize;
1069         return area > gMaxSize2ForLCDText;
1070     } else {
1071         return rec.fTextSize > SK_MAX_SIZE_FOR_LCDTEXT;
1072     }
1073 }
1074 
1075 // The only reason this is not file static is because it needs the context of SkScalerContext to
1076 // access SkPaint::computeLuminanceColor.
MakeRecAndEffects(const SkFont & font,const SkPaint & paint,const SkSurfaceProps & surfaceProps,SkScalerContextFlags scalerContextFlags,const SkMatrix & deviceMatrix,SkScalerContextRec * rec,SkScalerContextEffects * effects)1077 void SkScalerContext::MakeRecAndEffects(const SkFont& font, const SkPaint& paint,
1078                                         const SkSurfaceProps& surfaceProps,
1079                                         SkScalerContextFlags scalerContextFlags,
1080                                         const SkMatrix& deviceMatrix,
1081                                         SkScalerContextRec* rec,
1082                                         SkScalerContextEffects* effects) {
1083     SkASSERT(!deviceMatrix.hasPerspective());
1084 
1085     sk_bzero(rec, sizeof(SkScalerContextRec));
1086 
1087     SkTypeface* typeface = font.getTypeface();
1088 
1089     rec->fTypefaceID = typeface->uniqueID();
1090     rec->fTextSize = font.getSize();
1091     rec->fPreScaleX = font.getScaleX();
1092     rec->fPreSkewX  = font.getSkewX();
1093 
1094     bool checkPost2x2 = false;
1095 
1096     const SkMatrix::TypeMask mask = deviceMatrix.getType();
1097     if (mask & SkMatrix::kScale_Mask) {
1098         rec->fPost2x2[0][0] = sk_relax(deviceMatrix.getScaleX());
1099         rec->fPost2x2[1][1] = sk_relax(deviceMatrix.getScaleY());
1100         checkPost2x2 = true;
1101     } else {
1102         rec->fPost2x2[0][0] = rec->fPost2x2[1][1] = SK_Scalar1;
1103     }
1104     if (mask & SkMatrix::kAffine_Mask) {
1105         rec->fPost2x2[0][1] = sk_relax(deviceMatrix.getSkewX());
1106         rec->fPost2x2[1][0] = sk_relax(deviceMatrix.getSkewY());
1107         checkPost2x2 = true;
1108     } else {
1109         rec->fPost2x2[0][1] = rec->fPost2x2[1][0] = 0;
1110     }
1111 
1112     SkPaint::Style  style = paint.getStyle();
1113     SkScalar        strokeWidth = paint.getStrokeWidth();
1114 
1115     unsigned flags = 0;
1116 
1117     if (font.isEmbolden()) {
1118         flags |= SkScalerContext::kEmbolden_Flag;
1119     }
1120 
1121     if (style != SkPaint::kFill_Style && strokeWidth >= 0) {
1122         rec->fFrameWidth = strokeWidth;
1123         rec->fMiterLimit = paint.getStrokeMiter();
1124         rec->fStrokeJoin = SkToU8(paint.getStrokeJoin());
1125         rec->fStrokeCap = SkToU8(paint.getStrokeCap());
1126 
1127         if (style == SkPaint::kStrokeAndFill_Style) {
1128             flags |= SkScalerContext::kFrameAndFill_Flag;
1129         }
1130     } else {
1131         rec->fFrameWidth = -1;
1132         rec->fMiterLimit = 0;
1133         rec->fStrokeJoin = 0;
1134         rec->fStrokeCap = 0;
1135     }
1136 
1137     rec->fMaskFormat = compute_mask_format(font);
1138 
1139     if (SkMask::kLCD16_Format == rec->fMaskFormat) {
1140         if (too_big_for_lcd(*rec, checkPost2x2)) {
1141             rec->fMaskFormat = SkMask::kA8_Format;
1142             flags |= SkScalerContext::kGenA8FromLCD_Flag;
1143         } else {
1144             SkPixelGeometry geometry = surfaceProps.pixelGeometry();
1145 
1146             switch (geometry) {
1147                 case kUnknown_SkPixelGeometry:
1148                     // eeek, can't support LCD
1149                     rec->fMaskFormat = SkMask::kA8_Format;
1150                     flags |= SkScalerContext::kGenA8FromLCD_Flag;
1151                     break;
1152                 case kRGB_H_SkPixelGeometry:
1153                     // our default, do nothing.
1154                     break;
1155                 case kBGR_H_SkPixelGeometry:
1156                     flags |= SkScalerContext::kLCD_BGROrder_Flag;
1157                     break;
1158                 case kRGB_V_SkPixelGeometry:
1159                     flags |= SkScalerContext::kLCD_Vertical_Flag;
1160                     break;
1161                 case kBGR_V_SkPixelGeometry:
1162                     flags |= SkScalerContext::kLCD_Vertical_Flag;
1163                     flags |= SkScalerContext::kLCD_BGROrder_Flag;
1164                     break;
1165             }
1166         }
1167     }
1168 
1169     if (font.isEmbeddedBitmaps()) {
1170         flags |= SkScalerContext::kEmbeddedBitmapText_Flag;
1171     }
1172     if (font.isSubpixel()) {
1173         flags |= SkScalerContext::kSubpixelPositioning_Flag;
1174     }
1175     if (font.isForceAutoHinting()) {
1176         flags |= SkScalerContext::kForceAutohinting_Flag;
1177     }
1178     if (font.isLinearMetrics()) {
1179         flags |= SkScalerContext::kLinearMetrics_Flag;
1180     }
1181     if (font.isBaselineSnap()) {
1182         flags |= SkScalerContext::kBaselineSnap_Flag;
1183     }
1184     if (typeface->glyphMaskNeedsCurrentColor()) {
1185         flags |= SkScalerContext::kNeedsForegroundColor_Flag;
1186         rec->fForegroundColor = paint.getColor();
1187     }
1188     rec->fFlags = SkToU16(flags);
1189 
1190     // these modify fFlags, so do them after assigning fFlags
1191     rec->setHinting(font.getHinting());
1192     rec->setLuminanceColor(SkPaintPriv::ComputeLuminanceColor(paint));
1193 
1194     // The paint color is always converted to the device colr space,
1195     // so the paint gamma is now always equal to the device gamma.
1196     // The math in SkMaskGamma can handle them being different,
1197     // but it requires superluminous masks when
1198     // Ex : deviceGamma(x) < paintGamma(x) and x is sufficiently large.
1199     rec->setDeviceGamma(surfaceProps.textGamma());
1200     rec->setContrast(surfaceProps.textContrast());
1201 
1202     if (!SkToBool(scalerContextFlags & SkScalerContextFlags::kFakeGamma)) {
1203         rec->ignoreGamma();
1204     }
1205     if (!SkToBool(scalerContextFlags & SkScalerContextFlags::kBoostContrast)) {
1206         rec->setContrast(0);
1207     }
1208 
1209     new (effects) SkScalerContextEffects{paint};
1210 }
1211 
CreateDescriptorAndEffectsUsingPaint(const SkFont & font,const SkPaint & paint,const SkSurfaceProps & surfaceProps,SkScalerContextFlags scalerContextFlags,const SkMatrix & deviceMatrix,SkAutoDescriptor * ad,SkScalerContextEffects * effects)1212 SkDescriptor* SkScalerContext::CreateDescriptorAndEffectsUsingPaint(
1213     const SkFont& font, const SkPaint& paint, const SkSurfaceProps& surfaceProps,
1214     SkScalerContextFlags scalerContextFlags, const SkMatrix& deviceMatrix, SkAutoDescriptor* ad,
1215     SkScalerContextEffects* effects)
1216 {
1217     SkScalerContextRec rec;
1218     MakeRecAndEffects(font, paint, surfaceProps, scalerContextFlags, deviceMatrix, &rec, effects);
1219     return AutoDescriptorGivenRecAndEffects(rec, *effects, ad);
1220 }
1221 
calculate_size_and_flatten(const SkScalerContextRec & rec,const SkScalerContextEffects & effects,SkBinaryWriteBuffer * effectBuffer)1222 static size_t calculate_size_and_flatten(const SkScalerContextRec& rec,
1223                                          const SkScalerContextEffects& effects,
1224                                          SkBinaryWriteBuffer* effectBuffer) {
1225     size_t descSize = sizeof(rec);
1226     int entryCount = 1;
1227 
1228     if (effects.fPathEffect || effects.fMaskFilter) {
1229         if (effects.fPathEffect) { effectBuffer->writeFlattenable(effects.fPathEffect); }
1230         if (effects.fMaskFilter) { effectBuffer->writeFlattenable(effects.fMaskFilter); }
1231         entryCount += 1;
1232         descSize += effectBuffer->bytesWritten();
1233     }
1234 
1235     descSize += SkDescriptor::ComputeOverhead(entryCount);
1236     return descSize;
1237 }
1238 
generate_descriptor(const SkScalerContextRec & rec,const SkBinaryWriteBuffer & effectBuffer,SkDescriptor * desc)1239 static void generate_descriptor(const SkScalerContextRec& rec,
1240                                 const SkBinaryWriteBuffer& effectBuffer,
1241                                 SkDescriptor* desc) {
1242     desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
1243 
1244     if (effectBuffer.bytesWritten() > 0) {
1245         effectBuffer.writeToMemory(desc->addEntry(kEffects_SkDescriptorTag,
1246                                                   effectBuffer.bytesWritten(),
1247                                                   nullptr));
1248     }
1249 
1250     desc->computeChecksum();
1251 }
1252 
AutoDescriptorGivenRecAndEffects(const SkScalerContextRec & rec,const SkScalerContextEffects & effects,SkAutoDescriptor * ad)1253 SkDescriptor* SkScalerContext::AutoDescriptorGivenRecAndEffects(
1254     const SkScalerContextRec& rec,
1255     const SkScalerContextEffects& effects,
1256     SkAutoDescriptor* ad)
1257 {
1258     SkBinaryWriteBuffer buf({});
1259 
1260     ad->reset(calculate_size_and_flatten(rec, effects, &buf));
1261     generate_descriptor(rec, buf, ad->getDesc());
1262 
1263     return ad->getDesc();
1264 }
1265 
DescriptorGivenRecAndEffects(const SkScalerContextRec & rec,const SkScalerContextEffects & effects)1266 std::unique_ptr<SkDescriptor> SkScalerContext::DescriptorGivenRecAndEffects(
1267     const SkScalerContextRec& rec,
1268     const SkScalerContextEffects& effects)
1269 {
1270     SkBinaryWriteBuffer buf({});
1271 
1272     auto desc = SkDescriptor::Alloc(calculate_size_and_flatten(rec, effects, &buf));
1273     generate_descriptor(rec, buf, desc.get());
1274 
1275     return desc;
1276 }
1277 
DescriptorBufferGiveRec(const SkScalerContextRec & rec,void * buffer)1278 void SkScalerContext::DescriptorBufferGiveRec(const SkScalerContextRec& rec, void* buffer) {
1279     generate_descriptor(rec, SkBinaryWriteBuffer({}), (SkDescriptor*)buffer);
1280 }
1281 
CheckBufferSizeForRec(const SkScalerContextRec & rec,const SkScalerContextEffects & effects,size_t size)1282 bool SkScalerContext::CheckBufferSizeForRec(const SkScalerContextRec& rec,
1283                                             const SkScalerContextEffects& effects,
1284                                             size_t size) {
1285     SkBinaryWriteBuffer buf({});
1286     return size >= calculate_size_and_flatten(rec, effects, &buf);
1287 }
1288 
MakeEmpty(sk_sp<SkTypeface> typeface,const SkScalerContextEffects & effects,const SkDescriptor * desc)1289 std::unique_ptr<SkScalerContext> SkScalerContext::MakeEmpty(
1290         sk_sp<SkTypeface> typeface, const SkScalerContextEffects& effects,
1291         const SkDescriptor* desc) {
1292     class SkScalerContext_Empty : public SkScalerContext {
1293     public:
1294         SkScalerContext_Empty(sk_sp<SkTypeface> typeface, const SkScalerContextEffects& effects,
1295                               const SkDescriptor* desc)
1296                 : SkScalerContext(std::move(typeface), effects, desc) {}
1297 
1298     protected:
1299         GlyphMetrics generateMetrics(const SkGlyph& glyph, SkArenaAlloc*) override {
1300             return {glyph.maskFormat()};
1301         }
1302         void generateImage(const SkGlyph&, void*) override {}
1303         bool generatePath(const SkGlyph& glyph, SkPath* path, bool* modified) override {
1304             path->reset();
1305             return false;
1306         }
1307         void generateFontMetrics(SkFontMetrics* metrics) override {
1308             if (metrics) {
1309                 sk_bzero(metrics, sizeof(*metrics));
1310             }
1311         }
1312     };
1313 
1314     return std::make_unique<SkScalerContext_Empty>(std::move(typeface), effects, desc);
1315 }
1316 
1317 
1318 
1319 
1320