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