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