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