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