#include "src/ports/SkFontHost_FreeType_common.h"
#include "include/core/SkBitmap.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkColor.h"
#include "include/core/SkDrawable.h"
#include "include/core/SkGraphics.h"
#include "include/core/SkImage.h"
#include "include/core/SkOpenTypeSVGDecoder.h"
#include "include/core/SkPath.h"
#include "include/effects/SkGradientShader.h"
#include "include/pathops/SkPathOps.h"
#include "include/private/SkColorData.h"
#include "include/private/base/SkTo.h"
#include "src/core/SkFDot6.h"
#include "src/core/SkSwizzlePriv.h"
#include "src/core/SkTHash.h"
#include <algorithm>
#include <utility>
#include <vector>
#include <ft2build.h>
#include <freetype/freetype.h>
#include <freetype/ftbitmap.h>
#ifdef FT_COLOR_H
# include <freetype/ftcolor.h>
#endif
#include <freetype/ftimage.h>
#include <freetype/ftoutln.h>
#include <freetype/ftsizes.h>
#include <freetype/ftsynth.h>
usingnamespaceskia_private;
namespace {
[[maybe_unused]] static inline const constexpr bool kSkShowTextBlitCoverage = …;
}
#if defined(FT_CONFIG_OPTION_SVG)
# include <freetype/otsvg.h>
#endif
#ifdef TT_SUPPORT_COLRV1
#if (((FREETYPE_MAJOR) < 2) || \
((FREETYPE_MAJOR) == 2 && (FREETYPE_MINOR) < 11) || \
((FREETYPE_MAJOR) == 2 && (FREETYPE_MINOR) == 11 && (FREETYPE_PATCH) < 1)) && \
!defined(FT_STATIC_CAST)
# undef TT_SUPPORT_COLRV1
#else
# include "src/base/SkScopeExit.h"
#endif
#endif
#ifndef FT_OUTLINE_OVERLAP
#define FT_OUTLINE_OVERLAP …
#endif
#ifndef FT_LOAD_COLOR
#define FT_LOAD_COLOR …
#define FT_PIXEL_MODE_BGRA …
#endif
#ifdef SK_DEBUG
const char* SkTraceFtrGetError(int e) { … }
#endif
#ifdef TT_SUPPORT_COLRV1
bool operator==(const FT_OpaquePaint& a, const FT_OpaquePaint& b) { … }
static_assert …;
constexpr float kColorStopShift = …;
#endif
namespace {
using SkUniqueFTSize = std::unique_ptr<FT_SizeRec, SkFunctionObject<FT_Done_Size>>;
FT_Pixel_Mode compute_pixel_mode(SkMask::Format format) { … }
uint16_t packTriple(U8CPU r, U8CPU g, U8CPU b) { … }
uint16_t grayToRGB16(U8CPU gray) { … }
int bittst(const uint8_t data[], int bitOffset) { … }
template<bool APPLY_PREBLEND>
void copyFT2LCD16(const FT_Bitmap& bitmap, SkMaskBuilder* dstMask, int lcdIsBGR,
const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB)
{ … }
void copyFTBitmap(const FT_Bitmap& srcFTBitmap, SkMaskBuilder* dstMask) { … }
inline int convert_8_to_1(unsigned byte) { … }
uint8_t pack_8_to_1(const uint8_t alpha[8]) { … }
void packA8ToA1(SkMaskBuilder* dstMask, const uint8_t* src, size_t srcRB) { … }
inline SkMask::Format SkMaskFormat_for_SkColorType(SkColorType colorType) { … }
inline SkColorType SkColorType_for_FTPixelMode(FT_Pixel_Mode pixel_mode) { … }
inline SkColorType SkColorType_for_SkMaskFormat(SkMask::Format format) { … }
#ifdef TT_SUPPORT_COLRV1
const uint16_t kForegroundColorPaletteIndex = …;
SkColor4f lerpSkColor(SkColor4f c0, SkColor4f c1, float t) { … }
enum TruncateStops { … };
void truncateToStopInterpolating(SkScalar zeroRadiusStop,
std::vector<SkColor4f>& colors,
std::vector<SkScalar>& stops,
TruncateStops truncateStops) { … }
struct OpaquePaintHasher { … };
VisitedSet;
bool generateFacePathCOLRv1(FT_Face face, SkGlyphID glyphID, SkPath* path);
inline float SkColrV1AlphaToFloat(uint16_t alpha) { … }
inline SkTileMode ToSkTileMode(FT_PaintExtend extendMode) { … }
inline SkBlendMode ToSkBlendMode(FT_Composite_Mode compositeMode) { … }
inline SkMatrix ToSkMatrix(FT_Affine23 affine23) { … }
inline SkPoint SkVectorProjection(SkPoint a, SkPoint b) { … }
bool colrv1_configure_skpaint(FT_Face face,
const SkSpan<SkColor>& palette,
const SkColor foregroundColor,
const FT_COLR_Paint& colrPaint,
SkPaint* paint) { … }
bool colrv1_draw_paint(SkCanvas* canvas,
const SkSpan<SkColor>& palette,
const SkColor foregroundColor,
FT_Face face,
const FT_COLR_Paint& colrPaint) { … }
bool colrv1_draw_glyph_with_path(SkCanvas* canvas,
const SkSpan<SkColor>& palette, SkColor foregroundColor,
FT_Face face,
const FT_COLR_Paint& glyphPaint, const FT_COLR_Paint& fillPaint) { … }
void colrv1_transform(FT_Face face,
const FT_COLR_Paint& colrPaint,
SkCanvas* canvas,
SkMatrix* outTransform = nullptr) { … }
bool colrv1_start_glyph(SkCanvas* canvas,
const SkSpan<SkColor>& palette,
const SkColor foregroundColor,
FT_Face face,
uint16_t glyphId,
FT_Color_Root_Transform rootTransform,
VisitedSet* activePaints);
bool colrv1_traverse_paint(SkCanvas* canvas,
const SkSpan<SkColor>& palette,
const SkColor foregroundColor,
FT_Face face,
FT_OpaquePaint opaquePaint,
VisitedSet* activePaints) { … }
SkPath GetClipBoxPath(FT_Face face, uint16_t glyphId, bool untransformed) { … }
bool colrv1_start_glyph(SkCanvas* canvas,
const SkSpan<SkColor>& palette,
const SkColor foregroundColor,
FT_Face face,
uint16_t glyphId,
FT_Color_Root_Transform rootTransform,
VisitedSet* activePaints) { … }
bool colrv1_start_glyph_bounds(SkMatrix *ctm,
SkRect* bounds,
FT_Face face,
uint16_t glyphId,
FT_Color_Root_Transform rootTransform,
VisitedSet* activePaints);
bool colrv1_traverse_paint_bounds(SkMatrix* ctm,
SkRect* bounds,
FT_Face face,
FT_OpaquePaint opaquePaint,
VisitedSet* activePaints) { … }
bool colrv1_start_glyph_bounds(SkMatrix *ctm,
SkRect* bounds,
FT_Face face,
uint16_t glyphId,
FT_Color_Root_Transform rootTransform,
VisitedSet* activePaints) { … }
#endif
}
void SkScalerContextFTUtils::init(SkColor fgColor, SkScalerContext::Flags flags) { … }
#ifdef TT_SUPPORT_COLRV1
bool SkScalerContextFTUtils::drawCOLRv1Glyph(FT_Face face, const SkGlyph& glyph, uint32_t loadGlyphFlags,
SkSpan<SkColor> palette, SkCanvas* canvas) const { … }
#endif
#ifdef FT_COLOR_H
bool SkScalerContextFTUtils::drawCOLRv0Glyph(FT_Face face, const SkGlyph& glyph, LoadGlyphFlags flags,
SkSpan<SkColor> palette, SkCanvas* canvas) const { … }
#endif
#if defined(FT_CONFIG_OPTION_SVG)
bool SkScalerContextFTUtils::drawSVGGlyph(FT_Face face, const SkGlyph& glyph, LoadGlyphFlags flags,
SkSpan<SkColor> palette, SkCanvas* canvas) const {
SkASSERT(face->glyph->format == FT_GLYPH_FORMAT_SVG);
FT_SVG_Document ftSvg = (FT_SVG_Document)face->glyph->other;
SkMatrix m;
FT_Matrix ftMatrix = ftSvg->transform;
FT_Vector ftOffset = ftSvg->delta;
m.setAll(
SkFixedToFloat(ftMatrix.xx), -SkFixedToFloat(ftMatrix.xy), SkFixedToFloat(ftOffset.x),
-SkFixedToFloat(ftMatrix.yx), SkFixedToFloat(ftMatrix.yy), -SkFixedToFloat(ftOffset.y),
0 , 0 , 1 );
m.postScale(SkFixedToFloat(ftSvg->metrics.x_scale) / 64.0f,
SkFixedToFloat(ftSvg->metrics.y_scale) / 64.0f);
if (this->isSubpixel()) {
m.postTranslate(SkFixedToScalar(glyph.getSubXFixed()),
SkFixedToScalar(glyph.getSubYFixed()));
}
canvas->concat(m);
SkGraphics::OpenTypeSVGDecoderFactory svgFactory = SkGraphics::GetOpenTypeSVGDecoderFactory();
if (!svgFactory) {
return false;
}
auto svgDecoder = svgFactory(ftSvg->svg_document, ftSvg->svg_document_length);
if (!svgDecoder) {
return false;
}
return svgDecoder->render(*canvas, ftSvg->units_per_EM, glyph.getGlyphID(),
fForegroundColor, palette);
}
#endif
void SkScalerContextFTUtils::generateGlyphImage(FT_Face face, const SkGlyph& glyph, void* imageBuffer,
const SkMatrix& bitmapTransform,
const SkMaskGamma::PreBlend& preBlend) const { … }
namespace {
class SkFTGeometrySink { … };
bool generateGlyphPathStatic(FT_Face face, SkPath* path) { … }
bool generateFacePathStatic(FT_Face face, SkGlyphID glyphID,
SkScalerContextFTUtils::LoadGlyphFlags flags, SkPath* path){ … }
#ifdef TT_SUPPORT_COLRV1
bool generateFacePathCOLRv1(FT_Face face, SkGlyphID glyphID, SkPath* path) { … }
#endif
}
bool SkScalerContextFTUtils::generateGlyphPath(FT_Face face, SkPath* path) const { … }
bool SkScalerContextFTUtils::generateFacePath(FT_Face face, SkGlyphID glyphID, LoadGlyphFlags flags,
SkPath* path) const { … }
#ifdef TT_SUPPORT_COLRV1
bool SkScalerContextFTUtils::computeColrV1GlyphBoundingBox(FT_Face face, SkGlyphID glyphID,
SkRect* bounds) { … }
#endif