// If compiling with FreeType before 2.5.0 #ifndef FT_LOAD_COLOR # define FT_LOAD_COLOR ( 1L << 20 ) # define FT_PIXEL_MODE_BGRA 7 #endif
// If compiling with FreeType before 2.12.0 #ifndef FT_FACE_FLAG_SVG // We need the format tag so that we can switch on it and handle a possibly- // newer version of the library at runtime. static constexpr FT_UInt32 FT_IMAGE_TAG(FT_GLYPH_FORMAT_SVG, 'S', 'V', 'G', ' '); #endif
void SkInitCairoFT(bool fontHintingEnabled)
{
gFontHintingEnabled = fontHintingEnabled; #if SK_CAN_USE_DLOPEN
gSetLcdFilter = (FT_Error (*)(FT_Library, FT_LcdFilter))dlsym(RTLD_DEFAULT, "FT_Library_SetLcdFilter"); #else
gSetLcdFilter = &FT_Library_SetLcdFilter; #endif // FT_Library_SetLcdFilter may be provided but have no effect if FreeType // is built without FT_CONFIG_OPTION_SUBPIXEL_RENDERING. if (gSetLcdFilter &&
gSetLcdFilter(nullptr, FT_LCD_FILTER_NONE) == FT_Err_Unimplemented_Feature) {
gSetLcdFilter = nullptr;
}
}
staticbool bothZero(SkScalar a, SkScalar b) { return0 == a && 0 == b;
}
// returns false if there is any non-90-rotation or skew staticbool isAxisAligned(const SkScalerContextRec& rec) { return0 == rec.fPreSkewX &&
(bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
}
class SkCairoFTTypeface : public SkTypeface { public:
std::unique_ptr<SkStreamAsset> onOpenStream(int*) const override { return nullptr; }
void onFilterRec(SkScalerContextRec* rec) const override
{ // rotated text looks bad with hinting, so we disable it as needed if (!gFontHintingEnabled || !isAxisAligned(*rec)) {
rec->setHinting(SkFontHinting::kNone);
}
// Don't apply any gamma so that we match cairo-ft's results.
rec->ignorePreBlend();
}
bool hasColorGlyphs() const override
{ // Check if the font has scalable outlines. If not, then avoid trying // to render it as a path. if (fFTFace) { return !FT_IS_SCALABLE(fFTFace);
} returnfalse;
}
// Always using FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH to get correct // advances, as fontconfig and cairo do. // See http://code.google.com/p/skia/issues/detail?id=222.
loadFlags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
if (fHaveShape) { // Normalize the transform and convert to fixed-point.
fShapeMatrix = m;
fShapeMatrix.preScale(SkDoubleToScalar(1.0 / major), SkDoubleToScalar(1.0 / minor));
if (isLCD(fRec)) { // In FreeType < 2.8.1, LCD filtering, if explicitly used, may // add padding to the glyph. When not used, there is no padding. // As of 2.8.1, LCD filtering is now always supported and may // add padding even if an LCD filter is not explicitly set. // Regardless, if no LCD filtering is used, or if LCD filtering // doesn't add padding, it is safe to modify the glyph's bounds // here. generateGlyphImage will detect if the mask is smaller // than the bounds and clip things appropriately. if (fRec.fFlags & kLCD_Vertical_Flag) {
bounds.outset(0, 1);
} else {
bounds.outset(1, 0);
}
} break; case FT_GLYPH_FORMAT_BITMAP:
mx.neverRequestPath = true;
if (fFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) {
mx.maskFormat = SkMask::kARGB32_Format;
}
if (isLCD(fRec)) {
fRec.fMaskFormat = SkMask::kA8_Format;
}
if (fHaveShape) { // Ensure filtering is preserved when the bitmap is transformed. // Otherwise, the result will look horrifically aliased. if (fRec.fMaskFormat == SkMask::kBW_Format) {
fRec.fMaskFormat = SkMask::kA8_Format;
}
// Apply the shape matrix to the glyph's bounding box.
SkRect srcRect = SkRect::MakeXYWH(
SkIntToScalar(fFTFace->glyph->bitmap_left),
-SkIntToScalar(fFTFace->glyph->bitmap_top),
SkIntToScalar(fFTFace->glyph->bitmap.width),
SkIntToScalar(fFTFace->glyph->bitmap.rows));
SkRect destRect;
fShapeMatrix.mapRect(&destRect, srcRect);
SkIRect glyphRect = destRect.roundOut();
bounds = SkIRect::MakeXYWH(SkScalarRoundToInt(destRect.fLeft),
SkScalarRoundToInt(destRect.fTop),
glyphRect.width(),
glyphRect.height());
} else {
bounds = SkIRect::MakeXYWH(fFTFace->glyph->bitmap_left,
-fFTFace->glyph->bitmap_top,
fFTFace->glyph->bitmap.width,
fFTFace->glyph->bitmap.rows);
} break; case FT_GLYPH_FORMAT_SVG: // We don't support getting glyph bounds for SVG, but at least the advance // should be correctly returned, and we don't want to fire an assertion. break; default:
SkDEBUGFAIL("unknown glyph format"); return mx;
}
if (SkIRect::MakeXYWH(SHRT_MIN, SHRT_MIN, USHRT_MAX, USHRT_MAX).contains(bounds)) {
mx.bounds = SkRect::Make(bounds);
}
uint32_t flags = fLoadGlyphFlags;
flags |= FT_LOAD_NO_BITMAP; // ignore embedded bitmaps so we're sure to get the outline
flags &= ~FT_LOAD_RENDER; // don't scan convert (we just want the outline)
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.