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