52static inline const constexpr bool kSkShowTextBlitCoverage =
false;
53static inline const constexpr bool kSkScalerContextDumpRec =
false;
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))
95 , fGenerateImageFromPath(fRec.fFrameWidth >= 0 || fPathEffect != nullptr)
99 if constexpr (kSkScalerContextDumpRec) {
100 SkDebugf(
"SkScalerContext checksum %x count %u length %u\n",
101 desc->getChecksum(), desc->getCount(), desc->getLength());
115 static SkMutex& mutex = *(
new SkMutex);
170 size_t size = (*width)*(*height)*
sizeof(uint8_t);
189 memcpy(data, gammaTables, size);
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();
206 glyph->fLeft = sk_saturate_cast<int16_t>(r.fLeft);
207 glyph->fTop = sk_saturate_cast<int16_t>(r.fTop);
208 glyph->fWidth = sk_saturate_cast<uint16_t>(r.width());
209 glyph->fHeight = sk_saturate_cast<uint16_t>(r.height());
212 glyph->fLeft = sk_saturate_cast<int16_t>(r.
fLeft);
213 glyph->fTop = sk_saturate_cast<int16_t>(r.
fTop);
214 glyph->fWidth = sk_saturate_cast<uint16_t>(r.
width64());
215 glyph->fHeight = sk_saturate_cast<uint16_t>(r.
height64());
220 const bool verticalLCD,
const bool a8FromLCD,
const bool hairline)
231 if (!bounds.isEmpty()) {
235 const bool needExtraWidth = (fromLCD && !verticalLCD) || hairline;
236 const bool needExtraHeight = (fromLCD && verticalLCD) || hairline;
237 if (needExtraWidth) {
238 bounds.roundOut(&bounds);
241 if (needExtraHeight) {
242 bounds.roundOut(&bounds);
250 auto zeroBounds = [](
SkGlyph& glyph) {
258 glyph.fMaskFormat =
format;
260 SkASSERT(!mx.neverRequestPath || !mx.computeFromPath);
262 glyph.fAdvanceX = mx.advance.fX;
263 glyph.fAdvanceY = mx.advance.fY;
264 glyph.fMaskFormat = mx.maskFormat;
265 glyph.fScalerContextBits = mx.extraBits;
267 if (mx.computeFromPath || (fGenerateImageFromPath && !mx.neverRequestPath)) {
268 SkDEBUGCODE(glyph.fAdvancesBoundsFormatAndInitialPathDone =
true;)
269 this->internalGetPath(glyph, alloc);
270 const SkPath* devPath = glyph.path();
274 const bool hairline = glyph.pathIsHairline();
279 if (mx.neverRequestPath) {
280 glyph.setPath(alloc,
nullptr,
false);
283 SkDEBUGCODE(glyph.fAdvancesBoundsFormatAndInitialPathDone =
true;)
286 if (0 == glyph.fWidth || 0 == glyph.fHeight) {
293 SkMask src(
nullptr, glyph.iRect(), glyph.rowBytes(), glyph.maskFormat());
299 if (
as_MFB(fMaskFilter)->filterMask(&dst, src, matrix,
nullptr)) {
300 if (
dst.fBounds.isEmpty()) {
306 glyph.fMaskFormat =
dst.fFormat;
318 dst[
x] = lut[dst[
x]];
326 const bool doBGR,
const bool doVert) {
327#define SAMPLES_PER_PIXEL 4
328#define LCD_PER_PIXEL 3
336 SkASSERT(src.width() == (dst.fBounds.height() - 2) * 4);
337 SkASSERT(src.height() == dst.fBounds.width());
339 SkASSERT(src.width() == (dst.fBounds.width() - 2) * 4);
340 SkASSERT(src.height() == dst.fBounds.height());
343 const int sample_width = src.width();
344 const int height = src.height();
346 uint8_t* dstImage = dst.image();
347 size_t dstRB = dst.fRowBytes;
371 { 0x03, 0x0b, 0x1c, 0x33, 0x40, 0x39, 0x24, 0x10, 0x05, 0x01, 0x00, 0x00, },
373 { 0x00, 0x02, 0x08, 0x16, 0x2b, 0x3d, 0x3d, 0x2b, 0x16, 0x08, 0x02, 0x00, },
375 { 0x00, 0x00, 0x01, 0x05, 0x10, 0x24, 0x39, 0x40, 0x33, 0x1c, 0x0b, 0x03, },
378 size_t dstPB = toA8 ?
sizeof(uint8_t) :
sizeof(uint16_t);
383 dstP = SkTAddOffset<uint8_t>(dstImage,
y * dstPB);
386 dstP = SkTAddOffset<uint8_t>(dstImage,
y * dstRB);
390 const uint8_t* srcP = src.addr8(0,
y);
394 for (
int sample_x = -4; sample_x < sample_width + 4; sample_x += 4) {
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)
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;
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);
420 if constexpr (kSkShowTextBlitCoverage) {
421 r = std::max(r, 10u);
422 g = std::max(g, 10u);
423 b = std::max(
b, 10u);
428 a = maskPreBlend.
fG[
a];
433 r = maskPreBlend.
fR[r];
434 g = maskPreBlend.
fG[g];
435 b = maskPreBlend.
fB[
b];
439 dstP = SkTAddOffset<uint8_t>(dstP, dstPDelta);
451 for (
int i = 0; i < 8; ++i) {
461 const int octs =
width >> 3;
462 const int leftOverBits =
width & 7;
464 uint8_t* dst = dstMask.
image();
470 const size_t srcPad = srcRB -
width;
473 for (
int i = 0; i < octs; ++i) {
477 if (leftOverBits > 0) {
480 for (
int i = 0; i < leftOverBits; ++i, --shift) {
492 const bool doBGR,
const bool verticalLCD,
const bool a8FromLCD,
const bool hairline)
500 const SkPath* pathToUse = &path;
511 paint.setStroke(hairline);
549 if (intermediateDst) {
550 if (!dst.tryAlloc(
info)) {
558 sk_bzero(dst.writable_addr(), dst.computeByteSize());
569 packA8ToA1(dstMask, dst.addr8(0, 0), dst.rowBytes());
573 pack4xHToMask(dst, dstMask, maskPreBlend, doBGR, verticalLCD);
579 pack4xHToMask(dst, dstMask, maskPreBlend, doBGR, verticalLCD);
587 SkASSERT(origGlyph.fAdvancesBoundsFormatAndInitialPathDone);
589 const SkGlyph* unfilteredGlyph = &origGlyph;
594 SkSTArenaAlloc<
sizeof(SkGlyph::PathData)> tmpGlyphPathDataStorage;
599 fMaskFilter = std::move(mf);
602 if (tmpGlyph.fMaskFormat == origGlyph.fMaskFormat &&
605 tmpGlyph.fImage = origGlyph.fImage;
608 tmpGlyph.fImage = tmpGlyphImageStorage.
get();
610 unfilteredGlyph = &tmpGlyph;
613 if (!fGenerateImageFromPath) {
622 SkMaskBuilder mask(
static_cast<uint8_t*
>(unfilteredGlyph->fImage),
644 if (
as_MFB(fMaskFilter)->filterMask(&srcMask, unfilteredGlyph->
mask(), m,
nullptr)) {
646 srcMaskOwnedImage.reset(srcMask.
image());
647 }
else if (unfilteredGlyph->fImage == tmpGlyphImageStorage.
get()) {
649 srcMask =
SkMaskBuilder(
static_cast<uint8_t*
>(unfilteredGlyph->fImage),
652 }
else if (origGlyph.
iRect() == unfilteredGlyph->
iRect()) {
657 srcMask =
SkMaskBuilder(
static_cast<uint8_t*
>(unfilteredGlyph->fImage),
660 size_t imageSize = unfilteredGlyph->
imageSize();
661 tmpGlyphImageStorage.
reset(imageSize);
662 srcMask.
image() =
static_cast<uint8_t*
>(tmpGlyphImageStorage.
get());
663 memcpy(srcMask.
image(), unfilteredGlyph->fImage, imageSize);
686 srcMask.
image() += leftDiff;
691 dstMask.
image() += leftDiff;
715 const uint8_t* src = srcMask.
fImage;
716 uint8_t* dst = dstMask.
image();
724 if (dstMask.
fBounds != origBounds) {
729 memcpy(dst, src,
width);
737 this->internalGetPath(glyph, alloc);
756 SkASSERT(glyph.fAdvancesBoundsFormatAndInitialPathDone);
764 bool hairline =
false;
792 if (!
matrix.invert(&inverse)) {
793 glyph.
setPath(alloc, &devPath, hairline);
795 path.transform(inverse, &localPath);
812 if (fPathEffect->
filterPath(&effectPath, localPath, &rec,
nullptr, matrix)) {
813 localPath.
swap(effectPath);
817 if (rec.needToApply()) {
819 if (rec.applyToPath(&
strokePath, localPath)) {
825 if (rec.isHairlineStyle()) {
831 glyph.
setPath(alloc, &devPath, hairline);
851 m->postConcat(deviceMatrix);
868 bool skewedOrFlipped =
A.getSkewX() ||
A.getSkewY() ||
A.getScaleX() < 0 ||
A.getScaleY() < 0;
869 if (skewedOrFlipped) {
918 switch (preMatrixScale) {
932 if (intYScale == 0) {
942 if (!skewedOrFlipped && (
1012 switch (font.getEdging()) {
1026#ifndef SK_MAX_SIZE_FOR_LCDTEXT
1027 #define SK_MAX_SIZE_FOR_LCDTEXT 48
1062 bool checkPost2x2 =
false;
1068 checkPost2x2 =
true;
1075 checkPost2x2 =
true;
1085 if (font.isEmbolden()) {
1086#ifdef SK_USE_FREETYPE_EMBOLDEN
1093 SkScalar extra = font.getSize() * fakeBoldScale;
1116 rec->fStrokeJoin = 0;
1117 rec->fStrokeCap = 0;
1152 if (font.isEmbeddedBitmaps()) {
1155 if (font.isSubpixel()) {
1158 if (font.isForceAutoHinting()) {
1161 if (font.isLinearMetrics()) {
1164 if (font.isBaselineSnap()) {
1167 if (typeface->glyphMaskNeedsCurrentColor()) {
1208 size_t descSize =
sizeof(rec);
1233 desc->computeChecksum();
1285 void generateImage(
const SkGlyph&,
void*)
override {}
1286 bool generatePath(
const SkGlyph& glyph,
SkPath* path)
override {
1292 sk_bzero(metrics,
sizeof(*metrics));
1297 return std::make_unique<SkScalerContext_Empty>(std::move(typeface), effects, desc);
static const int strokeWidth
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
static constexpr T SkAlign8(T x)
#define SkASSERT_RELEASE(cond)
SkBlitter * SkA8Blitter_Choose(const SkPixmap &dst, const SkMatrix &ctm, const SkPaint &paint, SkArenaAlloc *alloc, bool drawCoverage, sk_sp< SkShader > clipShader, const SkSurfaceProps &)
static U8CPU SkComputeLuminance(U8CPU r, U8CPU g, U8CPU b)
static U16CPU SkPack888ToRGB16(U8CPU r, U8CPU g, U8CPU b)
@ kAlpha_8_SkColorType
pixel with alpha in 8-bit byte
#define SkColorGetR(color)
#define SkColorGetG(color)
#define SkColorSetRGB(r, g, b)
#define SkColorGetB(color)
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
#define SkFixedToScalar(x)
static void sk_bzero(void *buffer, size_t size)
SkMaskFilterBase * as_MFB(SkMaskFilter *mf)
std::unique_ptr< uint8_t, SkFunctionObject< SkMaskBuilder::FreeImage > > SkAutoMaskFreeImage
void SkComputeGivensRotation(const SkVector &h, SkMatrix *G)
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
static void SkSafeUnref(T *obj)
sk_sp< T > sk_ref_sp(T *obj)
#define SkScalarInvert(x)
#define SK_ScalarNearlyZero
#define SkScalarRoundToScalar(x)
SkScalar SkScalarInterpFunc(SkScalar searchKey, const SkScalar keys[], const SkScalar values[], int length)
static int convert_8_to_1(unsigned byte)
static SkScalar sk_relax(SkScalar x)
static void generate_descriptor(const SkScalerContextRec &rec, const SkBinaryWriteBuffer &effectBuffer, SkDescriptor *desc)
static constexpr D sk_saturate_cast(S s)
#define SK_MAX_SIZE_FOR_LCDTEXT
static void applyLUTToA8Mask(SkMaskBuilder &mask, const uint8_t *lut)
static const SkMaskGamma & cached_mask_gamma(SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma)
static SkScalar gPaintGamma
static SkScalar gDeviceGamma
static void pack4xHToMask(const SkPixmap &src, SkMaskBuilder &dst, const SkMaskGamma::PreBlend &maskPreBlend, const bool doBGR, const bool doVert)
static bool too_big_for_lcd(const SkScalerContextRec &rec, bool checkPost2x2)
const SkScalar gMaxSize2ForLCDText
static SkMutex & mask_gamma_cache_mutex()
static SkScalar gContrast
static SkMask::Format compute_mask_format(const SkFont &font)
static size_t calculate_size_and_flatten(const SkScalerContextRec &rec, const SkScalerContextEffects &effects, SkBinaryWriteBuffer *effectBuffer)
static SkMaskGamma * gLinearMaskGamma
static uint8_t pack_8_to_1(const uint8_t alpha[8])
static void packA8ToA1(SkMaskBuilder &dstMask, const uint8_t *src, size_t srcRB)
#define SAMPLES_PER_PIXEL
static SkMaskGamma * gMaskGamma
SkTMaskGamma< 3, 3, 3 > SkMaskGamma
#define kRec_SkDescriptorTag
#define kEffects_SkDescriptorTag
@ kUnknown_SkPixelGeometry
static const SkScalar kStdFakeBoldInterpValues[]
static const int kStdFakeBoldInterpLength
static const SkScalar kStdFakeBoldInterpKeys[]
constexpr uint16_t SkToU16(S x)
static constexpr bool SkToBool(const T &x)
constexpr uint8_t SkToU8(S x)
static void draw(SkCanvas *canvas, SkRect &target, int x, int y)
SkDescriptor * getDesc() const
void * reset(size_t size=0, OnShrink shrink=kAlloc_OnShrink)
void writeFlattenable(const SkFlattenable *flattenable) override
size_t bytesWritten() const
void writeToMemory(void *dst) const
static std::unique_ptr< SkDescriptor > Alloc(size_t length)
static size_t ComputeOverhead(int entryCount)
BlitterChooser * fBlitterChooser
static SkMatrix MakeTextMatrix(SkScalar size, SkScalar scaleX, SkScalar skewX)
@ kAntiAlias
may have transparent pixels on glyph edges
@ kAlias
no transparent pixels on glyph edges
@ kSubpixelAntiAlias
glyph positioned in pixel using transparency
bool setPathHasBeenCalled() const
const SkPath * path() const
SkMask::Format maskFormat() const
bool setPath(SkArenaAlloc *alloc, SkScalerContext *scalerContext)
bool pathIsHairline() const
SkPackedGlyphID getPackedID() const
static constexpr int kMScaleX
horizontal scale factor
static constexpr int kMTransY
vertical translation
SkScalar getSkewY() const
static constexpr int kMPersp1
input y perspective factor
SkMatrix & setAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, SkScalar skewY, SkScalar scaleY, SkScalar transY, SkScalar persp0, SkScalar persp1, SkScalar persp2)
SkMatrix & setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
SkScalar getSkewX() const
SkScalar getScaleX() const
SkMatrix & preConcat(const SkMatrix &other)
static constexpr int kMPersp0
input x perspective factor
SkScalar getScaleY() const
static constexpr int kMPersp2
perspective bias
static constexpr int kMTransX
horizontal translation
bool hasPerspective() const
static constexpr int kMSkewY
vertical skew factor
SkScalar get(int index) const
static constexpr int kMScaleY
vertical scale factor
static constexpr int kMSkewX
horizontal skew factor
SkMatrix & preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
SkMatrix & setScaleX(SkScalar v)
@ kScale_Mask
scale SkMatrix
@ kAffine_Mask
skew or rotate SkMatrix
static SkColor ComputeLuminanceColor(const SkPaint &)
@ kButt_Cap
no stroke extension
@ kFill_Style
set to fill geometry
@ kStrokeAndFill_Style
sets to stroke and fill geometry
bool filterPath(SkPath *dst, const SkPath &src, SkStrokeRec *, const SkRect *cullR) const
const SkRect & getBounds() const
void transform(const SkMatrix &matrix, SkPath *dst, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
virtual void generateFontMetrics(SkFontMetrics *)=0
SkScalerContext(sk_sp< SkTypeface >, const SkScalerContextEffects &, const SkDescriptor *)
@ kEmbeddedBitmapText_Flag
@ kNeedsForegroundColor_Flag
@ kSubpixelPositioning_Flag
static size_t GetGammaLUTSize(SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma, int *width, int *height)
virtual void generateImage(const SkGlyph &glyph, void *imageBuffer)=0
static void GenerateImageFromPath(SkMaskBuilder &dst, const SkPath &path, const SkMaskGamma::PreBlend &maskPreBlend, bool doBGR, bool verticalLCD, bool a8FromLCD, bool hairline)
static void MakeRecAndEffects(const SkFont &font, const SkPaint &paint, const SkSurfaceProps &surfaceProps, SkScalerContextFlags scalerContextFlags, const SkMatrix &deviceMatrix, SkScalerContextRec *rec, SkScalerContextEffects *effects)
static std::unique_ptr< SkDescriptor > DescriptorGivenRecAndEffects(const SkScalerContextRec &rec, const SkScalerContextEffects &effects)
virtual GlyphMetrics generateMetrics(const SkGlyph &, SkArenaAlloc *)=0
virtual bool generatePath(const SkGlyph &, SkPath *)=0
void getPath(SkGlyph &, SkArenaAlloc *)
const SkMaskGamma::PreBlend fPreBlend
static SkMaskGamma::PreBlend GetMaskPreBlend(const SkScalerContextRec &rec)
static SkDescriptor * CreateDescriptorAndEffectsUsingPaint(const SkFont &, const SkPaint &, const SkSurfaceProps &, SkScalerContextFlags scalerContextFlags, const SkMatrix &deviceMatrix, SkAutoDescriptor *ad, SkScalerContextEffects *effects)
virtual sk_sp< SkDrawable > generateDrawable(const SkGlyph &)
static SkDescriptor * AutoDescriptorGivenRecAndEffects(const SkScalerContextRec &rec, const SkScalerContextEffects &effects, SkAutoDescriptor *ad)
static void GenerateMetricsFromPath(SkGlyph *glyph, const SkPath &path, SkMask::Format format, bool verticalLCD, bool a8FromLCD, bool hairline)
static bool CheckBufferSizeForRec(const SkScalerContextRec &rec, const SkScalerContextEffects &effects, size_t size)
SkAxisAlignment computeAxisAlignmentForHText() const
sk_sp< SkDrawable > getDrawable(SkGlyph &)
static bool GetGammaLUTData(SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma, uint8_t *data)
static std::unique_ptr< SkScalerContext > MakeEmpty(sk_sp< SkTypeface > typeface, const SkScalerContextEffects &effects, const SkDescriptor *desc)
SkGlyph makeGlyph(SkPackedGlyphID, SkArenaAlloc *)
static void DescriptorBufferGiveRec(const SkScalerContextRec &rec, void *buffer)
virtual ~SkScalerContext()
void getFontMetrics(SkFontMetrics *)
void getImage(const SkGlyph &)
static void SaturateGlyphBounds(SkGlyph *glyph, SkRect &&)
const char * c_str() const
void setStrokeStyle(SkScalar width, bool strokeAndFill=false)
bool applyToPath(SkPath *dst, const SkPath &src) const
void setStrokeParams(SkPaint::Cap cap, SkPaint::Join join, SkScalar miterLimit)
SkScalar textGamma() const
SkPixelGeometry pixelGeometry() const
SkScalar textContrast() const
void getGammaTableDimensions(int *tableWidth, int *numTables) const
PreBlend preBlend(SkColor color) const
static SkColor CanonicalColor(SkColor color)
const uint8_t * getGammaTables() const
bool isApplicable() const
SkTypefaceID uniqueID() const
virtual void onFilterRec(SkScalerContextRec *) const =0
FlutterSemanticsFlag flags
static const uint8_t buffer[]
uint32_t uint32_t * format
static void strokePath(SkCanvas *canvas, const SkPath &path)
static float lum(float r, float g, float b)
unsigned useCenter Optional< SkMatrix > matrix
skia_private::AutoTArray< sk_sp< SkImageFilter > > filters TypedMatrix matrix TypedMatrix matrix SkScalar dx
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
constexpr int64_t height64() const
int32_t fBottom
larger y-axis bounds
constexpr int32_t height() const
int32_t fTop
smaller y-axis bounds
constexpr int32_t width() const
constexpr int64_t width64() const
static constexpr SkIRect MakeWH(int32_t w, int32_t h)
int32_t fLeft
smaller x-axis bounds
int32_t fRight
larger x-axis bounds
static SkImageInfo MakeA8(int width, int height)
@ k3D_Format
3 8bit per pixl planes: alpha, mul, add
@ kA8_Format
8bits per pixel mask (e.g. antialiasing)
@ kLCD16_Format
565 alpha for r/g/b
@ kARGB32_Format
SkPMColor.
@ kBW_Format
1bit per pixel mask (e.g. monochrome)
uint8_t const *const fImage
size_t computeImageSize() const
SkFixed getSubXFixed() const
SkFixed getSubYFixed() const
static constexpr SkPoint Make(float x, float y)
SkPathEffect * fPathEffect
SkMaskFilter * fMaskFilter
void setPaintGamma(SkScalar pg)
void getSingleMatrix(SkMatrix *) const
uint32_t fForegroundColor
void getLocalMatrix(SkMatrix *) const
SkAxisAlignment computeAxisAlignmentForHText() const
void setDeviceGamma(SkScalar dg)
SkMask::Format fMaskFormat
void setContrast(SkScalar c)
void getMatrixFrom2x2(SkMatrix *) const
bool computeMatrices(PreMatrixScale preMatrixScale, SkVector *scale, SkMatrix *remaining, SkMatrix *remainingWithoutRotation=nullptr, SkMatrix *remainingRotation=nullptr, SkMatrix *total=nullptr)
SkScalar getPaintGamma() const
SkScalar getContrast() const
SkScalar getDeviceGamma() const
SkColor getLuminanceColor() const
void setHinting(SkFontHinting)
void setLuminanceColor(SkColor c)