Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Macros | Functions | Variables
SkScalerContext.cpp File Reference
#include "src/core/SkScalerContext.h"
#include "include/core/SkColorType.h"
#include "include/core/SkDrawable.h"
#include "include/core/SkFont.h"
#include "include/core/SkFontMetrics.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkMaskFilter.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPath.h"
#include "include/core/SkPathEffect.h"
#include "include/core/SkPixmap.h"
#include "include/core/SkStrokeRec.h"
#include "include/private/SkColorData.h"
#include "include/private/base/SkAlign.h"
#include "include/private/base/SkCPUTypes.h"
#include "include/private/base/SkDebug.h"
#include "include/private/base/SkFixed.h"
#include "include/private/base/SkMalloc.h"
#include "include/private/base/SkMutex.h"
#include "include/private/base/SkTo.h"
#include "src/base/SkArenaAlloc.h"
#include "src/base/SkAutoMalloc.h"
#include "src/core/SkAutoPixmapStorage.h"
#include "src/core/SkBlitter_A8.h"
#include "src/core/SkDescriptor.h"
#include "src/core/SkDrawBase.h"
#include "src/core/SkFontPriv.h"
#include "src/core/SkGlyph.h"
#include "src/core/SkMaskFilterBase.h"
#include "src/core/SkPaintPriv.h"
#include "src/core/SkRasterClip.h"
#include "src/core/SkTextFormatParams.h"
#include "src/core/SkWriteBuffer.h"
#include "src/utils/SkMatrix22.h"
#include <algorithm>
#include <cstring>
#include <limits>
#include <new>

Go to the source code of this file.

Macros

#define SAMPLES_PER_PIXEL   4
 
#define LCD_PER_PIXEL   3
 
#define SK_MAX_SIZE_FOR_LCDTEXT   48
 

Functions

static SkMutex & mask_gamma_cache_mutex ()
 
static const SkMaskGammacached_mask_gamma (SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma)
 
template<typename D , typename S >
static constexpr D sk_saturate_cast (S s)
 
static void applyLUTToA8Mask (SkMaskBuilder &mask, const uint8_t *lut)
 
static void pack4xHToMask (const SkPixmap &src, SkMaskBuilder &dst, const SkMaskGamma::PreBlend &maskPreBlend, const bool doBGR, const bool doVert)
 
static int convert_8_to_1 (unsigned byte)
 
static uint8_t pack_8_to_1 (const uint8_t alpha[8])
 
static void packA8ToA1 (SkMaskBuilder &dstMask, const uint8_t *src, size_t srcRB)
 
static SkScalar sk_relax (SkScalar x)
 
static SkMask::Format compute_mask_format (const SkFont &font)
 
static bool too_big_for_lcd (const SkScalerContextRec &rec, bool checkPost2x2)
 
static size_t calculate_size_and_flatten (const SkScalerContextRec &rec, const SkScalerContextEffects &effects, SkBinaryWriteBuffer *effectBuffer)
 
static void generate_descriptor (const SkScalerContextRec &rec, const SkBinaryWriteBuffer &effectBuffer, SkDescriptor *desc)
 

Variables

static SkMaskGammagLinearMaskGamma = nullptr
 
static SkMaskGammagMaskGamma = nullptr
 
static SkScalar gContrast = SK_ScalarMin
 
static SkScalar gPaintGamma = SK_ScalarMin
 
static SkScalar gDeviceGamma = SK_ScalarMin
 
const SkScalar gMaxSize2ForLCDText = SK_MAX_SIZE_FOR_LCDTEXT * SK_MAX_SIZE_FOR_LCDTEXT
 

Macro Definition Documentation

◆ LCD_PER_PIXEL

#define LCD_PER_PIXEL   3

◆ SAMPLES_PER_PIXEL

#define SAMPLES_PER_PIXEL   4

◆ SK_MAX_SIZE_FOR_LCDTEXT

#define SK_MAX_SIZE_FOR_LCDTEXT   48

Definition at line 1027 of file SkScalerContext.cpp.

Function Documentation

◆ applyLUTToA8Mask()

static void applyLUTToA8Mask ( SkMaskBuilder mask,
const uint8_t *  lut 
)
static

Definition at line 312 of file SkScalerContext.cpp.

312 {
313 uint8_t* SK_RESTRICT dst = mask.image();
314 unsigned rowBytes = mask.fRowBytes;
315
316 for (int y = mask.fBounds.height() - 1; y >= 0; --y) {
317 for (int x = mask.fBounds.width() - 1; x >= 0; --x) {
318 dst[x] = lut[dst[x]];
319 }
320 dst += rowBytes;
321 }
322}
#define SK_RESTRICT
Definition SkFeatures.h:42
double y
double x
dst
Definition cp.py:12
constexpr int32_t height() const
Definition SkRect.h:165
constexpr int32_t width() const
Definition SkRect.h:158
uint8_t *& image()
Definition SkMask.h:236
const uint32_t fRowBytes
Definition SkMask.h:43
const SkIRect fBounds
Definition SkMask.h:42

◆ cached_mask_gamma()

static const SkMaskGamma & cached_mask_gamma ( SkScalar  contrast,
SkScalar  paintGamma,
SkScalar  deviceGamma 
)
static

The caller must hold the mask_gamma_cache_mutex() and continue to hold it until the returned SkMaskGamma pointer is refed or forgotten.

Definition at line 129 of file SkScalerContext.cpp.

130 {
131 mask_gamma_cache_mutex().assertHeld();
132 if (0 == contrast && SK_Scalar1 == paintGamma && SK_Scalar1 == deviceGamma) {
133 if (nullptr == gLinearMaskGamma) {
135 }
136 return *gLinearMaskGamma;
137 }
138 if (gContrast != contrast || gPaintGamma != paintGamma || gDeviceGamma != deviceGamma) {
140 gMaskGamma = new SkMaskGamma(contrast, paintGamma, deviceGamma);
142 gPaintGamma = paintGamma;
144 }
145 return *gMaskGamma;
146}
static void SkSafeUnref(T *obj)
Definition SkRefCnt.h:149
#define SK_Scalar1
Definition SkScalar.h:18
static SkScalar gPaintGamma
static SkScalar gDeviceGamma
static SkMutex & mask_gamma_cache_mutex()
static SkScalar gContrast
static SkMaskGamma * gLinearMaskGamma
static SkMaskGamma * gMaskGamma
SkTMaskGamma< 3, 3, 3 > SkMaskGamma

◆ calculate_size_and_flatten()

static size_t calculate_size_and_flatten ( const SkScalerContextRec rec,
const SkScalerContextEffects effects,
SkBinaryWriteBuffer effectBuffer 
)
static

Definition at line 1205 of file SkScalerContext.cpp.

1207 {
1208 size_t descSize = sizeof(rec);
1209 int entryCount = 1;
1210
1211 if (effects.fPathEffect || effects.fMaskFilter) {
1212 if (effects.fPathEffect) { effectBuffer->writeFlattenable(effects.fPathEffect); }
1213 if (effects.fMaskFilter) { effectBuffer->writeFlattenable(effects.fMaskFilter); }
1214 entryCount += 1;
1215 descSize += effectBuffer->bytesWritten();
1216 }
1217
1218 descSize += SkDescriptor::ComputeOverhead(entryCount);
1219 return descSize;
1220}
void writeFlattenable(const SkFlattenable *flattenable) override
size_t bytesWritten() const
static size_t ComputeOverhead(int entryCount)

◆ compute_mask_format()

static SkMask::Format compute_mask_format ( const SkFont font)
static

Definition at line 1011 of file SkScalerContext.cpp.

1011 {
1012 switch (font.getEdging()) {
1014 return SkMask::kBW_Format;
1016 return SkMask::kA8_Format;
1018 return SkMask::kLCD16_Format;
1019 }
1020 SkASSERT(false);
1021 return SkMask::kA8_Format;
1022}
#define SkASSERT(cond)
Definition SkAssert.h:116
@ kAntiAlias
may have transparent pixels on glyph edges
@ kAlias
no transparent pixels on glyph edges
@ kSubpixelAntiAlias
glyph positioned in pixel using transparency
font
Font Metadata and Metrics.
@ kA8_Format
8bits per pixel mask (e.g. antialiasing)
Definition SkMask.h:28
@ kLCD16_Format
565 alpha for r/g/b
Definition SkMask.h:31
@ kBW_Format
1bit per pixel mask (e.g. monochrome)
Definition SkMask.h:27

◆ convert_8_to_1()

static int convert_8_to_1 ( unsigned  byte)
inlinestatic

Definition at line 444 of file SkScalerContext.cpp.

444 {
445 SkASSERT(byte <= 0xFF);
446 return byte >> 7;
447}

◆ generate_descriptor()

static void generate_descriptor ( const SkScalerContextRec rec,
const SkBinaryWriteBuffer effectBuffer,
SkDescriptor desc 
)
static

Definition at line 1222 of file SkScalerContext.cpp.

1224 {
1225 desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
1226
1227 if (effectBuffer.bytesWritten() > 0) {
1228 effectBuffer.writeToMemory(desc->addEntry(kEffects_SkDescriptorTag,
1229 effectBuffer.bytesWritten(),
1230 nullptr));
1231 }
1232
1233 desc->computeChecksum();
1234}
#define kRec_SkDescriptorTag
#define kEffects_SkDescriptorTag
void writeToMemory(void *dst) const

◆ mask_gamma_cache_mutex()

static SkMutex & mask_gamma_cache_mutex ( )
static

In order to call cachedDeviceLuminance, cachedPaintLuminance, or cachedMaskGamma the caller must hold the mask_gamma_cache_mutex and continue to hold it until the returned pointer is refed or forgotten.

Definition at line 114 of file SkScalerContext.cpp.

114 {
115 static SkMutex& mutex = *(new SkMutex);
116 return mutex;
117}

◆ pack4xHToMask()

static void pack4xHToMask ( const SkPixmap src,
SkMaskBuilder dst,
const SkMaskGamma::PreBlend maskPreBlend,
const bool  doBGR,
const bool  doVert 
)
static

Definition at line 324 of file SkScalerContext.cpp.

326 {
327#define SAMPLES_PER_PIXEL 4
328#define LCD_PER_PIXEL 3
329 SkASSERT(kAlpha_8_SkColorType == src.colorType());
330
331 const bool toA8 = SkMask::kA8_Format == dst.fFormat;
332 SkASSERT(SkMask::kLCD16_Format == dst.fFormat || toA8);
333
334 // doVert in this function means swap x and y when writing to dst.
335 if (doVert) {
336 SkASSERT(src.width() == (dst.fBounds.height() - 2) * 4);
337 SkASSERT(src.height() == dst.fBounds.width());
338 } else {
339 SkASSERT(src.width() == (dst.fBounds.width() - 2) * 4);
340 SkASSERT(src.height() == dst.fBounds.height());
341 }
342
343 const int sample_width = src.width();
344 const int height = src.height();
345
346 uint8_t* dstImage = dst.image();
347 size_t dstRB = dst.fRowBytes;
348 // An N tap FIR is defined by
349 // out[n] = coeff[0]*x[n] + coeff[1]*x[n-1] + ... + coeff[N]*x[n-N]
350 // or
351 // out[n] = sum(i, 0, N, coeff[i]*x[n-i])
352
353 // The strategy is to use one FIR (different coefficients) for each of r, g, and b.
354 // This means using every 4th FIR output value of each FIR and discarding the rest.
355 // The FIRs are aligned, and the coefficients reach 5 samples to each side of their 'center'.
356 // (For r and b this is technically incorrect, but the coeffs outside round to zero anyway.)
357
358 // These are in some fixed point repesentation.
359 // Adding up to more than one simulates ink spread.
360 // For implementation reasons, these should never add up to more than two.
361
362 // Coefficients determined by a gausian where 5 samples = 3 std deviations (0x110 'contrast').
363 // Calculated using tools/generate_fir_coeff.py
364 // With this one almost no fringing is ever seen, but it is imperceptibly blurry.
365 // The lcd smoothed text is almost imperceptibly different from gray,
366 // but is still sharper on small stems and small rounded corners than gray.
367 // This also seems to be about as wide as one can get and only have a three pixel kernel.
368 // TODO: calculate these at runtime so parameters can be adjusted (esp contrast).
369 static const unsigned int coefficients[LCD_PER_PIXEL][SAMPLES_PER_PIXEL*3] = {
370 //The red subpixel is centered inside the first sample (at 1/6 pixel), and is shifted.
371 { 0x03, 0x0b, 0x1c, 0x33, 0x40, 0x39, 0x24, 0x10, 0x05, 0x01, 0x00, 0x00, },
372 //The green subpixel is centered between two samples (at 1/2 pixel), so is symetric
373 { 0x00, 0x02, 0x08, 0x16, 0x2b, 0x3d, 0x3d, 0x2b, 0x16, 0x08, 0x02, 0x00, },
374 //The blue subpixel is centered inside the last sample (at 5/6 pixel), and is shifted.
375 { 0x00, 0x00, 0x01, 0x05, 0x10, 0x24, 0x39, 0x40, 0x33, 0x1c, 0x0b, 0x03, },
376 };
377
378 size_t dstPB = toA8 ? sizeof(uint8_t) : sizeof(uint16_t);
379 for (int y = 0; y < height; ++y) {
380 uint8_t* dstP;
381 size_t dstPDelta;
382 if (doVert) {
383 dstP = SkTAddOffset<uint8_t>(dstImage, y * dstPB);
384 dstPDelta = dstRB;
385 } else {
386 dstP = SkTAddOffset<uint8_t>(dstImage, y * dstRB);
387 dstPDelta = dstPB;
388 }
389
390 const uint8_t* srcP = src.addr8(0, y);
391
392 // TODO: this fir filter implementation is straight forward, but slow.
393 // It should be possible to make it much faster.
394 for (int sample_x = -4; sample_x < sample_width + 4; sample_x += 4) {
395 int fir[LCD_PER_PIXEL] = { 0 };
396 for (int sample_index = std::max(0, sample_x - 4), coeff_index = sample_index - (sample_x - 4)
397 ; sample_index < std::min(sample_x + 8, sample_width)
398 ; ++sample_index, ++coeff_index)
399 {
400 int sample_value = srcP[sample_index];
401 for (int subpxl_index = 0; subpxl_index < LCD_PER_PIXEL; ++subpxl_index) {
402 fir[subpxl_index] += coefficients[subpxl_index][coeff_index] * sample_value;
403 }
404 }
405 for (int subpxl_index = 0; subpxl_index < LCD_PER_PIXEL; ++subpxl_index) {
406 fir[subpxl_index] /= 0x100;
407 fir[subpxl_index] = std::min(fir[subpxl_index], 255);
408 }
409
410 U8CPU r, g, b;
411 if (doBGR) {
412 r = fir[2];
413 g = fir[1];
414 b = fir[0];
415 } else {
416 r = fir[0];
417 g = fir[1];
418 b = fir[2];
419 }
420 if constexpr (kSkShowTextBlitCoverage) {
421 r = std::max(r, 10u);
422 g = std::max(g, 10u);
423 b = std::max(b, 10u);
424 }
425 if (toA8) {
426 U8CPU a = (r + g + b) / 3;
427 if (maskPreBlend.isApplicable()) {
428 a = maskPreBlend.fG[a];
429 }
430 *dstP = a;
431 } else {
432 if (maskPreBlend.isApplicable()) {
433 r = maskPreBlend.fR[r];
434 g = maskPreBlend.fG[g];
435 b = maskPreBlend.fB[b];
436 }
437 *(uint16_t*)dstP = SkPack888ToRGB16(r, g, b);
438 }
439 dstP = SkTAddOffset<uint8_t>(dstP, dstPDelta);
440 }
441 }
442}
unsigned U8CPU
Definition SkCPUTypes.h:18
static U16CPU SkPack888ToRGB16(U8CPU r, U8CPU g, U8CPU b)
@ kAlpha_8_SkColorType
pixel with alpha in 8-bit byte
Definition SkColorType.h:21
#define LCD_PER_PIXEL
#define SAMPLES_PER_PIXEL
const uint8_t * fG
const uint8_t * fB
bool isApplicable() const
const uint8_t * fR
static bool b
struct MyStruct a[10]
int32_t height

◆ pack_8_to_1()

static uint8_t pack_8_to_1 ( const uint8_t  alpha[8])
static

Definition at line 449 of file SkScalerContext.cpp.

449 {
450 unsigned bits = 0;
451 for (int i = 0; i < 8; ++i) {
452 bits <<= 1;
453 bits |= convert_8_to_1(alpha[i]);
454 }
455 return SkToU8(bits);
456}
static int convert_8_to_1(unsigned byte)
constexpr uint8_t SkToU8(S x)
Definition SkTo.h:22

◆ packA8ToA1()

static void packA8ToA1 ( SkMaskBuilder dstMask,
const uint8_t *  src,
size_t  srcRB 
)
static

Definition at line 458 of file SkScalerContext.cpp.

458 {
459 const int height = dstMask.fBounds.height();
460 const int width = dstMask.fBounds.width();
461 const int octs = width >> 3;
462 const int leftOverBits = width & 7;
463
464 uint8_t* dst = dstMask.image();
465 const int dstPad = dstMask.fRowBytes - SkAlign8(width)/8;
466 SkASSERT(dstPad >= 0);
467
468 SkASSERT(width >= 0);
469 SkASSERT(srcRB >= (size_t)width);
470 const size_t srcPad = srcRB - width;
471
472 for (int y = 0; y < height; ++y) {
473 for (int i = 0; i < octs; ++i) {
474 *dst++ = pack_8_to_1(src);
475 src += 8;
476 }
477 if (leftOverBits > 0) {
478 unsigned bits = 0;
479 int shift = 7;
480 for (int i = 0; i < leftOverBits; ++i, --shift) {
481 bits |= convert_8_to_1(*src++) << shift;
482 }
483 *dst++ = bits;
484 }
485 src += srcPad;
486 dst += dstPad;
487 }
488}
static constexpr T SkAlign8(T x)
Definition SkAlign.h:17
static uint8_t pack_8_to_1(const uint8_t alpha[8])
int32_t width

◆ sk_relax()

static SkScalar sk_relax ( SkScalar  x)
static

Definition at line 1006 of file SkScalerContext.cpp.

1006 {
1007 SkScalar n = SkScalarRoundToScalar(x * 1024);
1008 return n / 1024.0f;
1009}
#define SkScalarRoundToScalar(x)
Definition SkScalar.h:32
float SkScalar
Definition extension.cpp:12

◆ sk_saturate_cast()

template<typename D , typename S >
static constexpr D sk_saturate_cast ( s)
staticconstexpr

Return the closest D for the given S. Returns std::numeric_limits<D>::max() for NaN.

Definition at line 198 of file SkScalerContext.cpp.

198 {
199 static_assert(std::is_integral_v<D>);
200 s = s < std::numeric_limits<D>::max() ? s : std::numeric_limits<D>::max();
201 s = s > std::numeric_limits<D>::min() ? s : std::numeric_limits<D>::min();
202 return (D)s;
203}
struct MyStruct s
static float max(float r, float g, float b)
Definition hsl.cpp:49
Definition ref_ptr.h:256

◆ too_big_for_lcd()

static bool too_big_for_lcd ( const SkScalerContextRec rec,
bool  checkPost2x2 
)
static

Definition at line 1032 of file SkScalerContext.cpp.

1032 {
1033 if (checkPost2x2) {
1034 SkScalar area = rec.fPost2x2[0][0] * rec.fPost2x2[1][1] -
1035 rec.fPost2x2[1][0] * rec.fPost2x2[0][1];
1036 area *= rec.fTextSize * rec.fTextSize;
1037 return area > gMaxSize2ForLCDText;
1038 } else {
1040 }
1041}
#define SK_MAX_SIZE_FOR_LCDTEXT
const SkScalar gMaxSize2ForLCDText
SkScalar fPost2x2[2][2]

Variable Documentation

◆ gContrast

SkScalar gContrast = SK_ScalarMin
static

Definition at line 121 of file SkScalerContext.cpp.

◆ gDeviceGamma

SkScalar gDeviceGamma = SK_ScalarMin
static

Definition at line 123 of file SkScalerContext.cpp.

◆ gLinearMaskGamma

SkMaskGamma* gLinearMaskGamma = nullptr
static

Definition at line 119 of file SkScalerContext.cpp.

◆ gMaskGamma

SkMaskGamma* gMaskGamma = nullptr
static

Definition at line 120 of file SkScalerContext.cpp.

◆ gMaxSize2ForLCDText

Definition at line 1030 of file SkScalerContext.cpp.

◆ gPaintGamma

SkScalar gPaintGamma = SK_ScalarMin
static

Definition at line 122 of file SkScalerContext.cpp.