mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-07 18:04:46 +00:00
Bug 1287552 - part 3 - revise SkFontHost_cairo to properly parse Fontconfig options. r=gw280
MozReview-Commit-ID: 40REybKbB6P --HG-- extra : rebase_source : 95b270ebf8a186f341ef4b6322b6c2296bc73742
This commit is contained in:
parent
02261affef
commit
0956c335eb
@ -115,6 +115,9 @@ DEFINES['SKIA_IMPLEMENTATION'] = 1
|
||||
if not CONFIG['MOZ_ENABLE_SKIA_GPU']:
|
||||
DEFINES['SK_SUPPORT_GPU'] = 0
|
||||
|
||||
if CONFIG['MOZ_TREE_FREETYPE']:
|
||||
DEFINES['SK_CAN_USE_DLOPEN'] = 0
|
||||
|
||||
# Suppress warnings in third-party code.
|
||||
if CONFIG['GNU_CXX'] or CONFIG['CLANG_CL']:
|
||||
CXXFLAGS += [
|
||||
|
@ -639,6 +639,9 @@ DEFINES['SKIA_IMPLEMENTATION'] = 1
|
||||
if not CONFIG['MOZ_ENABLE_SKIA_GPU']:
|
||||
DEFINES['SK_SUPPORT_GPU'] = 0
|
||||
|
||||
if CONFIG['MOZ_TREE_FREETYPE']:
|
||||
DEFINES['SK_CAN_USE_DLOPEN'] = 0
|
||||
|
||||
# Suppress warnings in third-party code.
|
||||
if CONFIG['GNU_CXX'] or CONFIG['CLANG_CL']:
|
||||
CXXFLAGS += [
|
||||
|
@ -2,10 +2,17 @@
|
||||
#define SkTypeface_cairo_DEFINED
|
||||
|
||||
#include <cairo.h>
|
||||
#include <cairo-ft.h>
|
||||
|
||||
#include "SkTypeface.h"
|
||||
|
||||
SK_API extern SkTypeface* SkCreateTypefaceFromCairoFont(cairo_font_face_t* fontFace, const SkFontStyle& style, bool isFixedWidth);
|
||||
SK_API extern void SkInitCairoFT(bool fontHintingEnabled);
|
||||
|
||||
SK_API extern SkTypeface* SkCreateTypefaceFromCairoFTFont(cairo_scaled_font_t* scaledFont);
|
||||
|
||||
#ifdef CAIRO_HAS_FC_FONT
|
||||
SK_API extern SkTypeface* SkCreateTypefaceFromCairoFTFontWithFontconfig(cairo_scaled_font_t* scaledFont, FcPattern* pattern);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -22,15 +22,71 @@
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_OUTLINE_H
|
||||
|
||||
// for FT_GlyphSlot_Embolden
|
||||
#ifdef FT_SYNTHESIS_H
|
||||
#include FT_SYNTHESIS_H
|
||||
#endif
|
||||
|
||||
// for FT_Library_SetLcdFilter
|
||||
#ifdef FT_LCD_FILTER_H
|
||||
#include FT_LCD_FILTER_H
|
||||
#else
|
||||
typedef enum FT_LcdFilter_
|
||||
{
|
||||
FT_LCD_FILTER_NONE = 0,
|
||||
FT_LCD_FILTER_DEFAULT = 1,
|
||||
FT_LCD_FILTER_LIGHT = 2,
|
||||
FT_LCD_FILTER_LEGACY = 16,
|
||||
} FT_LcdFilter;
|
||||
#endif
|
||||
|
||||
#ifndef SK_CAN_USE_DLOPEN
|
||||
#define SK_CAN_USE_DLOPEN 1
|
||||
#endif
|
||||
#if SK_CAN_USE_DLOPEN
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#ifndef SK_FONTHOST_CAIRO_STANDALONE
|
||||
#define SK_FONTHOST_CAIRO_STANDALONE 1
|
||||
#endif
|
||||
|
||||
static cairo_user_data_key_t kSkTypefaceKey;
|
||||
|
||||
static bool gFontHintingEnabled = true;
|
||||
static FT_Error (*gSetLcdFilter)(FT_Library, FT_LcdFilter) = nullptr;
|
||||
static void (*gGlyphSlotEmbolden)(FT_GlyphSlot) = nullptr;
|
||||
|
||||
void SkInitCairoFT(bool fontHintingEnabled)
|
||||
{
|
||||
gFontHintingEnabled = fontHintingEnabled;
|
||||
#if SK_CAN_USE_DLOPEN
|
||||
gSetLcdFilter = (FT_Error (*)(FT_Library, FT_LcdFilter))dlsym(RTLD_DEFAULT, "FT_Library_SetLcdFilter");
|
||||
gGlyphSlotEmbolden = (void (*)(FT_GlyphSlot))dlsym(RTLD_DEFAULT, "FT_GlyphSlot_Embolden");
|
||||
#else
|
||||
gSetLcdFilter = &FT_Library_SetLcdFilter;
|
||||
gGlyphSlotEmbolden = &FT_GlyphSlot_Embolden;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef CAIRO_HAS_FC_FONT
|
||||
typedef struct _FcPattern FcPattern;
|
||||
#endif
|
||||
|
||||
template<> struct SkTUnref<FcPattern> {
|
||||
void operator()(FcPattern* pattern) {
|
||||
#ifdef CAIRO_HAS_FC_FONT
|
||||
if (pattern) {
|
||||
FcPatternDestroy(pattern);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
class SkScalerContext_CairoFT : public SkScalerContext_FreeType_Base {
|
||||
public:
|
||||
SkScalerContext_CairoFT(SkTypeface* typeface, const SkDescriptor* desc);
|
||||
SkScalerContext_CairoFT(SkTypeface* typeface, const SkDescriptor* desc,
|
||||
cairo_font_face_t* fontFace, FcPattern* pattern);
|
||||
virtual ~SkScalerContext_CairoFT();
|
||||
|
||||
protected:
|
||||
@ -42,9 +98,24 @@ protected:
|
||||
virtual void generatePath(const SkGlyph& glyph, SkPath* path) override;
|
||||
virtual void generateFontMetrics(SkPaint::FontMetrics* metrics) override;
|
||||
virtual SkUnichar generateGlyphToChar(uint16_t glyph) override;
|
||||
|
||||
private:
|
||||
bool computeShapeMatrix(const SkMatrix& m);
|
||||
void prepareGlyph(FT_GlyphSlot glyph);
|
||||
void fixVerticalLayoutBearing(FT_GlyphSlot glyph);
|
||||
|
||||
#ifdef CAIRO_HAS_FC_FONT
|
||||
void parsePattern(FcPattern* pattern);
|
||||
void resolvePattern(FcPattern* pattern);
|
||||
#endif
|
||||
|
||||
cairo_scaled_font_t* fScaledFont;
|
||||
uint32_t fLoadGlyphFlags;
|
||||
FT_Int32 fLoadGlyphFlags;
|
||||
FT_LcdFilter fLcdFilter;
|
||||
SkScalar fScaleX;
|
||||
SkScalar fScaleY;
|
||||
FT_Matrix fShapeMatrix;
|
||||
bool fHaveShape;
|
||||
};
|
||||
|
||||
class CairoLockedFTFace {
|
||||
@ -69,6 +140,10 @@ private:
|
||||
FT_Face fFace;
|
||||
};
|
||||
|
||||
template<typename T> static bool isLCD(const T& rec) {
|
||||
return SkMask::kLCD16_Format == rec.fMaskFormat;
|
||||
}
|
||||
|
||||
static bool bothZero(SkScalar a, SkScalar b) {
|
||||
return 0 == a && 0 == b;
|
||||
}
|
||||
@ -82,38 +157,50 @@ static bool isAxisAligned(const SkScalerContext::Rec& rec) {
|
||||
|
||||
class SkCairoFTTypeface : public SkTypeface {
|
||||
public:
|
||||
static SkTypeface* CreateTypeface(cairo_font_face_t* fontFace, const SkFontStyle& style, bool isFixedWidth) {
|
||||
SkASSERT(fontFace != NULL);
|
||||
static SkTypeface* CreateTypeface(cairo_font_face_t* fontFace, FT_Face face,
|
||||
FcPattern* pattern = nullptr) {
|
||||
SkASSERT(fontFace != nullptr);
|
||||
SkASSERT(cairo_font_face_get_type(fontFace) == CAIRO_FONT_TYPE_FT);
|
||||
SkASSERT(face != nullptr);
|
||||
|
||||
SkFontStyle style(face->style_flags & FT_STYLE_FLAG_BOLD ?
|
||||
SkFontStyle::kBold_Weight : SkFontStyle::kNormal_Weight,
|
||||
SkFontStyle::kNormal_Width,
|
||||
face->style_flags & FT_STYLE_FLAG_ITALIC ?
|
||||
SkFontStyle::kItalic_Slant : SkFontStyle::kUpright_Slant);
|
||||
|
||||
bool isFixedWidth = face->face_flags & FT_FACE_FLAG_FIXED_WIDTH;
|
||||
|
||||
SkFontID newId = SkTypefaceCache::NewFontID();
|
||||
|
||||
return new SkCairoFTTypeface(fontFace, style, newId, isFixedWidth);
|
||||
return new SkCairoFTTypeface(style, newId, isFixedWidth, fontFace, pattern);
|
||||
}
|
||||
|
||||
cairo_font_face_t* getFontFace() {
|
||||
return fFontFace;
|
||||
}
|
||||
|
||||
virtual SkStreamAsset* onOpenStream(int*) const override { return NULL; }
|
||||
virtual SkStreamAsset* onOpenStream(int*) const override { return nullptr; }
|
||||
|
||||
virtual SkAdvancedTypefaceMetrics*
|
||||
onGetAdvancedTypefaceMetrics(PerGlyphInfo,
|
||||
const uint32_t*, uint32_t) const override
|
||||
{
|
||||
SkDEBUGCODE(SkDebugf("SkCairoFTTypeface::onGetAdvancedTypefaceMetrics unimplemented\n"));
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual SkScalerContext* onCreateScalerContext(const SkDescriptor* desc) const override
|
||||
{
|
||||
return new SkScalerContext_CairoFT(const_cast<SkCairoFTTypeface*>(this), desc);
|
||||
return new SkScalerContext_CairoFT(const_cast<SkCairoFTTypeface*>(this), desc,
|
||||
fFontFace, fPattern);
|
||||
}
|
||||
|
||||
virtual void onFilterRec(SkScalerContextRec* rec) const override
|
||||
{
|
||||
// No subpixel AA unless enabled in Fontconfig.
|
||||
if (!fPattern && isLCD(*rec)) {
|
||||
rec->fMaskFormat = SkMask::kA8_Format;
|
||||
}
|
||||
|
||||
// rotated text looks bad with hinting, so we disable it as needed
|
||||
if (!isAxisAligned(*rec)) {
|
||||
if (!gFontHintingEnabled || !isAxisAligned(*rec)) {
|
||||
rec->setHinting(SkPaint::kNo_Hinting);
|
||||
}
|
||||
}
|
||||
@ -140,7 +227,7 @@ public:
|
||||
|
||||
virtual SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override
|
||||
{
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual void onGetFamilyName(SkString* familyName) const override
|
||||
@ -160,97 +247,110 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
SkCairoFTTypeface(cairo_font_face_t* fontFace, const SkFontStyle& style, SkFontID id, bool isFixedWidth)
|
||||
SkCairoFTTypeface(const SkFontStyle& style, SkFontID id, bool isFixedWidth,
|
||||
cairo_font_face_t* fontFace, FcPattern* pattern)
|
||||
: SkTypeface(style, id, isFixedWidth)
|
||||
, fFontFace(fontFace)
|
||||
, fPattern(pattern)
|
||||
{
|
||||
cairo_font_face_set_user_data(fFontFace, &kSkTypefaceKey, this, NULL);
|
||||
cairo_font_face_set_user_data(fFontFace, &kSkTypefaceKey, this, nullptr);
|
||||
cairo_font_face_reference(fFontFace);
|
||||
#ifdef CAIRO_HAS_FC_FONT
|
||||
if (fPattern) {
|
||||
FcPatternReference(fPattern);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
~SkCairoFTTypeface()
|
||||
{
|
||||
cairo_font_face_set_user_data(fFontFace, &kSkTypefaceKey, NULL, NULL);
|
||||
cairo_font_face_set_user_data(fFontFace, &kSkTypefaceKey, nullptr, nullptr);
|
||||
cairo_font_face_destroy(fFontFace);
|
||||
}
|
||||
|
||||
cairo_font_face_t* fFontFace;
|
||||
SkAutoTUnref<FcPattern> fPattern;
|
||||
};
|
||||
|
||||
SkTypeface* SkCreateTypefaceFromCairoFont(cairo_font_face_t* fontFace, const SkFontStyle& style, bool isFixedWidth)
|
||||
SkTypeface* SkCreateTypefaceFromCairoFTFontWithFontconfig(cairo_scaled_font_t* scaledFont, FcPattern* pattern)
|
||||
{
|
||||
SkTypeface* typeface = reinterpret_cast<SkTypeface*>(cairo_font_face_get_user_data(fontFace, &kSkTypefaceKey));
|
||||
cairo_font_face_t* fontFace = cairo_scaled_font_get_font_face(scaledFont);
|
||||
SkASSERT(cairo_font_face_status(fontFace) == CAIRO_STATUS_SUCCESS);
|
||||
|
||||
SkTypeface* typeface = reinterpret_cast<SkTypeface*>(cairo_font_face_get_user_data(fontFace, &kSkTypefaceKey));
|
||||
if (typeface) {
|
||||
typeface->ref();
|
||||
} else {
|
||||
typeface = SkCairoFTTypeface::CreateTypeface(fontFace, style, isFixedWidth);
|
||||
SkTypefaceCache::Add(typeface, style);
|
||||
CairoLockedFTFace faceLock(scaledFont);
|
||||
if (FT_Face face = faceLock.getFace()) {
|
||||
typeface = SkCairoFTTypeface::CreateTypeface(fontFace, face, pattern);
|
||||
SkTypefaceCache::Add(typeface, typeface->fontStyle());
|
||||
}
|
||||
}
|
||||
|
||||
return typeface;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool isLCD(const SkScalerContext::Rec& rec) {
|
||||
return SkMask::kLCD16_Format == rec.fMaskFormat;
|
||||
SkTypeface* SkCreateTypefaceFromCairoFTFont(cairo_scaled_font_t* scaledFont)
|
||||
{
|
||||
return SkCreateTypefaceFromCairoFTFontWithFontconfig(scaledFont, nullptr);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
SkScalerContext_CairoFT::SkScalerContext_CairoFT(SkTypeface* typeface, const SkDescriptor* desc)
|
||||
SkScalerContext_CairoFT::SkScalerContext_CairoFT(SkTypeface* typeface, const SkDescriptor* desc,
|
||||
cairo_font_face_t* fontFace, FcPattern* pattern)
|
||||
: SkScalerContext_FreeType_Base(typeface, desc)
|
||||
, fLcdFilter(FT_LCD_FILTER_NONE)
|
||||
{
|
||||
SkMatrix matrix;
|
||||
fRec.getSingleMatrix(&matrix);
|
||||
|
||||
cairo_font_face_t* fontFace = static_cast<SkCairoFTTypeface*>(typeface)->getFontFace();
|
||||
|
||||
cairo_matrix_t fontMatrix, ctMatrix;
|
||||
cairo_matrix_init(&fontMatrix, matrix.getScaleX(), matrix.getSkewY(), matrix.getSkewX(), matrix.getScaleY(), 0.0, 0.0);
|
||||
cairo_matrix_init_scale(&ctMatrix, 1.0, 1.0);
|
||||
cairo_matrix_init_identity(&ctMatrix);
|
||||
|
||||
// We need to ensure that the font options match for hinting, as generateMetrics()
|
||||
// uses the fScaledFont which uses these font options
|
||||
cairo_font_options_t *fontOptions = cairo_font_options_create();
|
||||
fScaledFont = cairo_scaled_font_create(fontFace, &fontMatrix, &ctMatrix, fontOptions);
|
||||
cairo_font_options_destroy(fontOptions);
|
||||
|
||||
computeShapeMatrix(matrix);
|
||||
|
||||
#ifdef CAIRO_HAS_FC_FONT
|
||||
resolvePattern(pattern);
|
||||
#endif
|
||||
|
||||
FT_Int32 loadFlags = FT_LOAD_DEFAULT;
|
||||
|
||||
if (SkMask::kBW_Format == fRec.fMaskFormat) {
|
||||
// See http://code.google.com/p/chromium/issues/detail?id=43252#c24
|
||||
loadFlags = FT_LOAD_TARGET_MONO;
|
||||
if (fRec.getHinting() == SkPaint::kNo_Hinting) {
|
||||
cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_NONE);
|
||||
loadFlags = FT_LOAD_NO_HINTING;
|
||||
loadFlags |= FT_LOAD_NO_HINTING;
|
||||
} else {
|
||||
loadFlags = FT_LOAD_TARGET_MONO;
|
||||
}
|
||||
loadFlags |= FT_LOAD_MONOCHROME;
|
||||
} else {
|
||||
switch (fRec.getHinting()) {
|
||||
case SkPaint::kNo_Hinting:
|
||||
loadFlags = FT_LOAD_NO_HINTING;
|
||||
cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_NONE);
|
||||
loadFlags |= FT_LOAD_NO_HINTING;
|
||||
break;
|
||||
case SkPaint::kSlight_Hinting:
|
||||
loadFlags = FT_LOAD_TARGET_LIGHT; // This implies FORCE_AUTOHINT
|
||||
cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_SLIGHT);
|
||||
break;
|
||||
case SkPaint::kNormal_Hinting:
|
||||
cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_MEDIUM);
|
||||
if (fRec.fFlags & SkScalerContext::kForceAutohinting_Flag) {
|
||||
loadFlags = FT_LOAD_FORCE_AUTOHINT;
|
||||
loadFlags |= FT_LOAD_FORCE_AUTOHINT;
|
||||
}
|
||||
break;
|
||||
case SkPaint::kFull_Hinting:
|
||||
cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_FULL);
|
||||
if (fRec.fFlags & SkScalerContext::kForceAutohinting_Flag) {
|
||||
loadFlags = FT_LOAD_FORCE_AUTOHINT;
|
||||
}
|
||||
if (isLCD(fRec)) {
|
||||
if (SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag)) {
|
||||
if (fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag) {
|
||||
loadFlags = FT_LOAD_TARGET_LCD_V;
|
||||
} else {
|
||||
loadFlags = FT_LOAD_TARGET_LCD;
|
||||
}
|
||||
}
|
||||
if (fRec.fFlags & SkScalerContext::kForceAutohinting_Flag) {
|
||||
loadFlags |= FT_LOAD_FORCE_AUTOHINT;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
SkDebugf("---------- UNKNOWN hinting %d\n", fRec.getHinting());
|
||||
@ -258,8 +358,10 @@ SkScalerContext_CairoFT::SkScalerContext_CairoFT(SkTypeface* typeface, const SkD
|
||||
}
|
||||
}
|
||||
|
||||
fScaledFont = cairo_scaled_font_create(fontFace, &fontMatrix, &ctMatrix, fontOptions);
|
||||
cairo_font_options_destroy(fontOptions);
|
||||
// Disable autohinting to disable hinting even for "tricky" fonts.
|
||||
if (!gFontHintingEnabled) {
|
||||
loadFlags |= FT_LOAD_NO_AUTOHINT;
|
||||
}
|
||||
|
||||
if ((fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag) == 0) {
|
||||
loadFlags |= FT_LOAD_NO_BITMAP;
|
||||
@ -270,6 +372,10 @@ SkScalerContext_CairoFT::SkScalerContext_CairoFT(SkTypeface* typeface, const SkD
|
||||
// See http://code.google.com/p/skia/issues/detail?id=222.
|
||||
loadFlags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
|
||||
|
||||
if (fRec.fFlags & SkScalerContext::kVertical_Flag) {
|
||||
loadFlags |= FT_LOAD_VERTICAL_LAYOUT;
|
||||
}
|
||||
|
||||
#ifdef FT_LOAD_COLOR
|
||||
loadFlags |= FT_LOAD_COLOR;
|
||||
#endif
|
||||
@ -282,6 +388,185 @@ SkScalerContext_CairoFT::~SkScalerContext_CairoFT()
|
||||
cairo_scaled_font_destroy(fScaledFont);
|
||||
}
|
||||
|
||||
#ifdef CAIRO_HAS_FC_FONT
|
||||
void SkScalerContext_CairoFT::parsePattern(FcPattern* pattern)
|
||||
{
|
||||
FcBool antialias, autohint, bitmap, embolden, hinting, vertical;
|
||||
|
||||
if (FcPatternGetBool(pattern, FC_AUTOHINT, 0, &autohint) == FcResultMatch && autohint) {
|
||||
fRec.fFlags |= SkScalerContext::kForceAutohinting_Flag;
|
||||
}
|
||||
if (FcPatternGetBool(pattern, FC_EMBEDDED_BITMAP, 0, &bitmap) == FcResultMatch && bitmap) {
|
||||
fRec.fFlags |= SkScalerContext::kEmbeddedBitmapText_Flag;
|
||||
}
|
||||
if (FcPatternGetBool(pattern, FC_EMBOLDEN, 0, &embolden) == FcResultMatch && embolden) {
|
||||
fRec.fFlags |= SkScalerContext::kEmbolden_Flag;
|
||||
}
|
||||
if (FcPatternGetBool(pattern, FC_VERTICAL_LAYOUT, 0, &vertical) == FcResultMatch && vertical) {
|
||||
fRec.fFlags |= SkScalerContext::kVertical_Flag;
|
||||
}
|
||||
|
||||
if (fRec.fMaskFormat != SkMask::kBW_Format &&
|
||||
(FcPatternGetBool(pattern, FC_ANTIALIAS, 0, &antialias) != FcResultMatch || antialias)) {
|
||||
int rgba;
|
||||
if (!isLCD(fRec) ||
|
||||
FcPatternGetInteger(pattern, FC_RGBA, 0, &rgba) != FcResultMatch) {
|
||||
rgba = FC_RGBA_UNKNOWN;
|
||||
}
|
||||
switch (rgba) {
|
||||
case FC_RGBA_RGB:
|
||||
break;
|
||||
case FC_RGBA_BGR:
|
||||
fRec.fFlags |= SkScalerContext::kLCD_BGROrder_Flag;
|
||||
break;
|
||||
case FC_RGBA_VRGB:
|
||||
fRec.fFlags |= SkScalerContext::kLCD_Vertical_Flag;
|
||||
break;
|
||||
case FC_RGBA_VBGR:
|
||||
fRec.fFlags |= SkScalerContext::kLCD_Vertical_Flag |
|
||||
SkScalerContext::kLCD_BGROrder_Flag;
|
||||
break;
|
||||
default:
|
||||
fRec.fMaskFormat = SkMask::kA8_Format;
|
||||
break;
|
||||
}
|
||||
|
||||
int filter;
|
||||
if (isLCD(fRec)) {
|
||||
if (FcPatternGetInteger(pattern, FC_LCD_FILTER, 0, &filter) != FcResultMatch) {
|
||||
filter = FC_LCD_LEGACY;
|
||||
}
|
||||
switch (filter) {
|
||||
case FC_LCD_NONE:
|
||||
fLcdFilter = FT_LCD_FILTER_NONE;
|
||||
break;
|
||||
case FC_LCD_DEFAULT:
|
||||
fLcdFilter = FT_LCD_FILTER_DEFAULT;
|
||||
break;
|
||||
case FC_LCD_LIGHT:
|
||||
fLcdFilter = FT_LCD_FILTER_LIGHT;
|
||||
break;
|
||||
case FC_LCD_LEGACY:
|
||||
default:
|
||||
fLcdFilter = FT_LCD_FILTER_LEGACY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fRec.fMaskFormat = SkMask::kBW_Format;
|
||||
}
|
||||
|
||||
if (fRec.getHinting() != SkPaint::kNo_Hinting &&
|
||||
(FcPatternGetBool(pattern, FC_HINTING, 0, &hinting) != FcResultMatch || hinting)) {
|
||||
int hintstyle;
|
||||
if (FcPatternGetInteger(pattern, FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch) {
|
||||
hintstyle = FC_HINT_FULL;
|
||||
}
|
||||
switch (hintstyle) {
|
||||
case FC_HINT_NONE:
|
||||
fRec.setHinting(SkPaint::kNo_Hinting);
|
||||
break;
|
||||
case FC_HINT_SLIGHT:
|
||||
fRec.setHinting(SkPaint::kSlight_Hinting);
|
||||
break;
|
||||
case FC_HINT_MEDIUM:
|
||||
default:
|
||||
fRec.setHinting(SkPaint::kNormal_Hinting);
|
||||
break;
|
||||
case FC_HINT_FULL:
|
||||
fRec.setHinting(SkPaint::kFull_Hinting);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SkScalerContext_CairoFT::resolvePattern(FcPattern* pattern)
|
||||
{
|
||||
if (!pattern) {
|
||||
return;
|
||||
}
|
||||
SkAutoTUnref<FcPattern> scalePattern(FcPatternDuplicate(pattern));
|
||||
if (scalePattern) {
|
||||
if (FcPatternAddDouble(scalePattern, FC_PIXEL_SIZE, fScaleY) &&
|
||||
FcConfigSubstitute(nullptr, scalePattern, FcMatchPattern)) {
|
||||
FcDefaultSubstitute(scalePattern);
|
||||
FcResult result;
|
||||
SkAutoTUnref<FcPattern> resolved(FcFontMatch(nullptr, scalePattern, &result));
|
||||
if (resolved) {
|
||||
parsePattern(resolved);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
parsePattern(pattern);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool SkScalerContext_CairoFT::computeShapeMatrix(const SkMatrix& m)
|
||||
{
|
||||
// Compute a shape matrix compatible with Cairo's _compute_transform.
|
||||
// Finds major/minor scales and uses them to normalize the transform.
|
||||
double scaleX = m.getScaleX();
|
||||
double skewX = m.getSkewX();
|
||||
double skewY = m.getSkewY();
|
||||
double scaleY = m.getScaleY();
|
||||
double det = scaleX * scaleY - skewY * skewX;
|
||||
if (!std::isfinite(det)) {
|
||||
fScaleX = fRec.fTextSize * fRec.fPreScaleX;
|
||||
fScaleY = fRec.fTextSize;
|
||||
fHaveShape = false;
|
||||
return false;
|
||||
}
|
||||
double major = det != 0.0 ? hypot(scaleX, skewY) : 0.0;
|
||||
double minor = major != 0.0 ? fabs(det) / major : 0.0;
|
||||
// Limit scales to be above 1pt.
|
||||
major = SkTMax(major, 1.0);
|
||||
minor = SkTMax(minor, 1.0);
|
||||
|
||||
// If the font is not scalable, then choose the best available size.
|
||||
CairoLockedFTFace faceLock(fScaledFont);
|
||||
FT_Face face = faceLock.getFace();
|
||||
if (!FT_IS_SCALABLE(face)) {
|
||||
double bestDist = DBL_MAX;
|
||||
FT_Int bestSize = -1;
|
||||
for (FT_Int i = 0; i < face->num_fixed_sizes; i++) {
|
||||
// Distance is positive if strike is larger than desired size,
|
||||
// or negative if smaller. If previously a found smaller strike,
|
||||
// then prefer a larger strike. Otherwise, minimize distance.
|
||||
double dist = face->available_sizes[i].y_ppem / 64.0 - minor;
|
||||
if (bestDist < 0 ? dist >= bestDist : fabs(dist) <= bestDist) {
|
||||
bestDist = dist;
|
||||
bestSize = i;
|
||||
}
|
||||
}
|
||||
if (bestSize < 0) {
|
||||
fScaleX = fRec.fTextSize * fRec.fPreScaleX;
|
||||
fScaleY = fRec.fTextSize;
|
||||
fHaveShape = false;
|
||||
return false;
|
||||
}
|
||||
major = face->available_sizes[bestSize].x_ppem / 64.0;
|
||||
minor = face->available_sizes[bestSize].y_ppem / 64.0;
|
||||
fHaveShape = true;
|
||||
} else {
|
||||
fHaveShape = !m.isScaleTranslate();
|
||||
}
|
||||
|
||||
fScaleX = SkDoubleToScalar(major);
|
||||
fScaleY = SkDoubleToScalar(minor);
|
||||
|
||||
if (fHaveShape) {
|
||||
// Normalize the transform and convert to fixed-point.
|
||||
double invScaleX = 65536.0 / major;
|
||||
double invScaleY = 65536.0 / minor;
|
||||
fShapeMatrix.xx = (FT_Fixed)(scaleX * invScaleX);
|
||||
fShapeMatrix.yx = -(FT_Fixed)(skewY * invScaleX);
|
||||
fShapeMatrix.xy = -(FT_Fixed)(skewX * invScaleY);
|
||||
fShapeMatrix.yy = (FT_Fixed)(scaleY * invScaleY);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned SkScalerContext_CairoFT::generateGlyphCount()
|
||||
{
|
||||
CairoLockedFTFace faceLock(fScaledFont);
|
||||
@ -299,9 +584,36 @@ void SkScalerContext_CairoFT::generateAdvance(SkGlyph* glyph)
|
||||
generateMetrics(glyph);
|
||||
}
|
||||
|
||||
void SkScalerContext_CairoFT::prepareGlyph(FT_GlyphSlot glyph)
|
||||
{
|
||||
if (fRec.fFlags & SkScalerContext::kEmbolden_Flag &&
|
||||
gGlyphSlotEmbolden) {
|
||||
gGlyphSlotEmbolden(glyph);
|
||||
}
|
||||
if (fRec.fFlags & SkScalerContext::kVertical_Flag) {
|
||||
fixVerticalLayoutBearing(glyph);
|
||||
}
|
||||
}
|
||||
|
||||
void SkScalerContext_CairoFT::fixVerticalLayoutBearing(FT_GlyphSlot glyph)
|
||||
{
|
||||
FT_Vector vector;
|
||||
vector.x = glyph->metrics.vertBearingX - glyph->metrics.horiBearingX;
|
||||
vector.y = -glyph->metrics.vertBearingY - glyph->metrics.horiBearingY;
|
||||
if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
|
||||
if (fHaveShape) {
|
||||
FT_Vector_Transform(&vector, &fShapeMatrix);
|
||||
}
|
||||
FT_Outline_Translate(&glyph->outline, vector.x, vector.y);
|
||||
} else if (glyph->format == FT_GLYPH_FORMAT_BITMAP) {
|
||||
glyph->bitmap_left += SkFDot6Floor(vector.x);
|
||||
glyph->bitmap_top += SkFDot6Floor(vector.y);
|
||||
}
|
||||
}
|
||||
|
||||
void SkScalerContext_CairoFT::generateMetrics(SkGlyph* glyph)
|
||||
{
|
||||
SkASSERT(fScaledFont != NULL);
|
||||
SkASSERT(fScaledFont != nullptr);
|
||||
|
||||
glyph->zeroMetrics();
|
||||
|
||||
@ -313,11 +625,14 @@ void SkScalerContext_CairoFT::generateMetrics(SkGlyph* glyph)
|
||||
return;
|
||||
}
|
||||
|
||||
prepareGlyph(face->glyph);
|
||||
|
||||
switch (face->glyph->format) {
|
||||
case FT_GLYPH_FORMAT_OUTLINE:
|
||||
if (!face->glyph->outline.n_contours) {
|
||||
break;
|
||||
}
|
||||
|
||||
FT_BBox bbox;
|
||||
FT_Outline_Get_CBox(&face->glyph->outline, &bbox);
|
||||
bbox.xMin &= ~63;
|
||||
@ -328,25 +643,72 @@ void SkScalerContext_CairoFT::generateMetrics(SkGlyph* glyph)
|
||||
glyph->fHeight = SkToU16(SkFDot6Floor(bbox.yMax - bbox.yMin));
|
||||
glyph->fTop = -SkToS16(SkFDot6Floor(bbox.yMax));
|
||||
glyph->fLeft = SkToS16(SkFDot6Floor(bbox.xMin));
|
||||
|
||||
if (isLCD(fRec) &&
|
||||
gSetLcdFilter &&
|
||||
(fLcdFilter == FT_LCD_FILTER_DEFAULT ||
|
||||
fLcdFilter == FT_LCD_FILTER_LIGHT)) {
|
||||
if (fRec.fFlags & kLCD_Vertical_Flag) {
|
||||
glyph->fTop -= 1;
|
||||
glyph->fHeight += 2;
|
||||
} else {
|
||||
glyph->fLeft -= 1;
|
||||
glyph->fWidth += 2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FT_GLYPH_FORMAT_BITMAP:
|
||||
glyph->fWidth = SkToU16(face->glyph->bitmap.width);
|
||||
glyph->fHeight = SkToU16(face->glyph->bitmap.rows);
|
||||
glyph->fTop = -SkToS16(face->glyph->bitmap_top);
|
||||
glyph->fLeft = SkToS16(face->glyph->bitmap_left);
|
||||
#ifdef FT_LOAD_COLOR
|
||||
if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) {
|
||||
glyph->fMaskFormat = SkMask::kARGB32_Format;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (isLCD(fRec)) {
|
||||
fRec.fMaskFormat = SkMask::kA8_Format;
|
||||
}
|
||||
|
||||
if (fHaveShape) {
|
||||
// Apply the shape matrix to the glyph's bounding box.
|
||||
SkMatrix matrix;
|
||||
fRec.getSingleMatrix(&matrix);
|
||||
matrix.preScale(SkScalarInvert(fScaleX), SkScalarInvert(fScaleY));
|
||||
SkRect srcRect = SkRect::MakeXYWH(
|
||||
SkIntToScalar(face->glyph->bitmap_left),
|
||||
-SkIntToScalar(face->glyph->bitmap_top),
|
||||
SkIntToScalar(face->glyph->bitmap.width),
|
||||
SkIntToScalar(face->glyph->bitmap.rows));
|
||||
SkRect destRect;
|
||||
matrix.mapRect(&destRect, srcRect);
|
||||
SkIRect glyphRect = destRect.roundOut();
|
||||
glyph->fWidth = SkToU16(glyphRect.width());
|
||||
glyph->fHeight = SkToU16(glyphRect.height());
|
||||
glyph->fTop = SkToS16(SkScalarRoundToInt(destRect.fTop));
|
||||
glyph->fLeft = SkToS16(SkScalarRoundToInt(destRect.fLeft));
|
||||
} else {
|
||||
glyph->fWidth = SkToU16(face->glyph->bitmap.width);
|
||||
glyph->fHeight = SkToU16(face->glyph->bitmap.rows);
|
||||
glyph->fTop = -SkToS16(face->glyph->bitmap_top);
|
||||
glyph->fLeft = SkToS16(face->glyph->bitmap_left);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
SkDEBUGFAIL("unknown glyph format");
|
||||
return;
|
||||
}
|
||||
|
||||
glyph->fAdvanceX = SkFDot6ToFloat(face->glyph->advance.x);
|
||||
glyph->fAdvanceY = -SkFDot6ToFloat(face->glyph->advance.y);
|
||||
if (fRec.fFlags & SkScalerContext::kVertical_Flag) {
|
||||
glyph->fAdvanceX = -SkFDot6ToFloat(face->glyph->advance.x);
|
||||
glyph->fAdvanceY = SkFDot6ToFloat(face->glyph->advance.y);
|
||||
} else {
|
||||
glyph->fAdvanceX = SkFDot6ToFloat(face->glyph->advance.x);
|
||||
glyph->fAdvanceY = -SkFDot6ToFloat(face->glyph->advance.y);
|
||||
}
|
||||
}
|
||||
|
||||
void SkScalerContext_CairoFT::generateImage(const SkGlyph& glyph)
|
||||
{
|
||||
SkASSERT(fScaledFont != NULL);
|
||||
SkASSERT(fScaledFont != nullptr);
|
||||
CairoLockedFTFace faceLock(fScaledFont);
|
||||
FT_Face face = faceLock.getFace();
|
||||
|
||||
@ -357,12 +719,26 @@ void SkScalerContext_CairoFT::generateImage(const SkGlyph& glyph)
|
||||
return;
|
||||
}
|
||||
|
||||
prepareGlyph(face->glyph);
|
||||
|
||||
bool useLcdFilter =
|
||||
face->glyph->format == FT_GLYPH_FORMAT_OUTLINE &&
|
||||
isLCD(glyph) &&
|
||||
gSetLcdFilter;
|
||||
if (useLcdFilter) {
|
||||
gSetLcdFilter(face->glyph->library, fLcdFilter);
|
||||
}
|
||||
|
||||
generateGlyphImage(face, glyph);
|
||||
|
||||
if (useLcdFilter) {
|
||||
gSetLcdFilter(face->glyph->library, FT_LCD_FILTER_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
void SkScalerContext_CairoFT::generatePath(const SkGlyph& glyph, SkPath* path)
|
||||
{
|
||||
SkASSERT(fScaledFont != NULL);
|
||||
SkASSERT(fScaledFont != nullptr);
|
||||
CairoLockedFTFace faceLock(fScaledFont);
|
||||
FT_Face face = faceLock.getFace();
|
||||
|
||||
@ -379,6 +755,8 @@ void SkScalerContext_CairoFT::generatePath(const SkGlyph& glyph, SkPath* path)
|
||||
return;
|
||||
}
|
||||
|
||||
prepareGlyph(face->glyph);
|
||||
|
||||
generateGlyphPath(face, path);
|
||||
}
|
||||
|
||||
@ -389,7 +767,7 @@ void SkScalerContext_CairoFT::generateFontMetrics(SkPaint::FontMetrics* metrics)
|
||||
|
||||
SkUnichar SkScalerContext_CairoFT::generateGlyphToChar(uint16_t glyph)
|
||||
{
|
||||
SkASSERT(fScaledFont != NULL);
|
||||
SkASSERT(fScaledFont != nullptr);
|
||||
CairoLockedFTFace faceLock(fScaledFont);
|
||||
FT_Face face = faceLock.getFace();
|
||||
|
||||
@ -411,6 +789,6 @@ SkUnichar SkScalerContext_CairoFT::generateGlyphToChar(uint16_t glyph)
|
||||
|
||||
SkFontMgr* SkFontMgr::Factory() {
|
||||
// todo
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -112,6 +112,9 @@
|
||||
# include "skia/include/gpu/gl/GrGLInterface.h"
|
||||
# include "SkiaGLGlue.h"
|
||||
# endif
|
||||
# ifdef MOZ_ENABLE_FREETYPE
|
||||
# include "skia/include/ports/SkTypeface_cairo.h"
|
||||
# endif
|
||||
# ifdef __GNUC__
|
||||
# pragma GCC diagnostic pop // -Wshadow
|
||||
# endif
|
||||
@ -671,6 +674,9 @@ gfxPlatform::Init()
|
||||
|
||||
#ifdef USE_SKIA
|
||||
SkGraphics::Init();
|
||||
# ifdef MOZ_ENABLE_FREETYPE
|
||||
SkInitCairoFT(gPlatform->FontHintingEnabled());
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_GL_DEBUG
|
||||
|
Loading…
Reference in New Issue
Block a user