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