Index: src/ports/SkFontHost_FreeType.cpp |
diff --git a/src/ports/SkFontHost_FreeType.cpp b/src/ports/SkFontHost_FreeType.cpp |
index 4b8345a94ccb2bf19c984e0ae665b171b7ad5627..14f7cf9f125562c03a0c3584d0bda94fd941e13b 100644 |
--- a/src/ports/SkFontHost_FreeType.cpp |
+++ b/src/ports/SkFontHost_FreeType.cpp |
@@ -11,6 +11,7 @@ |
#include "SkColorPriv.h" |
#include "SkDescriptor.h" |
#include "SkFDot6.h" |
+#include "SkFontDescriptor.h" |
#include "SkFontHost_FreeType_common.h" |
#include "SkGlyph.h" |
#include "SkMask.h" |
@@ -33,6 +34,7 @@ |
#include FT_FREETYPE_H |
#include FT_LCD_FILTER_H |
#include FT_MODULE_H |
+#include FT_MULTIPLE_MASTERS_H |
#include FT_OUTLINE_H |
#include FT_SIZES_H |
#include FT_SYSTEM_H |
@@ -273,6 +275,36 @@ SkFaceRec::SkFaceRec(SkStreamAsset* stream, uint32_t fontID) |
fFTStream.close = sk_ft_stream_close; |
} |
+static void ft_face_setup_axes(FT_Face face, const SkFontData& data) { |
+ if (!(face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) { |
+ return; |
+ } |
+ SkDEBUGF(("INFO: font is mm!\n")); |
+ |
+ FT_MM_Var* variations = NULL; |
+ FT_Error err = FT_Get_MM_Var(face, &variations); |
+ if (err) { |
+ SkDEBUGF(("INFO: font is mm, but has no variations!\n")); |
+ return; |
+ } |
+ SkAutoFree autoFreeVariations(variations); |
+ |
+ if (static_cast<FT_UInt>(data.getAxisCount()) != variations->num_axis) { |
+ SkDEBUGF(("INFO: font is mm, but has different number of variations!\n")); |
+ return; |
+ } |
+ |
+ SkAutoSTMalloc<16, FT_Fixed> coords(variations->num_axis); |
+ for (FT_UInt i = 0; i < variations->num_axis; ++i) { |
+ coords[i] = data.getAxis()[i]; |
+ } |
+ err = FT_Set_Var_Design_Coordinates(face, variations->num_axis, coords.get()); |
+ if (err) { |
+ SkDEBUGF(("INFO: font is mm, but has no variations!\n")); |
+ return; |
+ } |
+} |
+ |
// Will return 0 on failure |
// Caller must lock gFTMutex before calling this function. |
static SkFaceRec* ref_ft_face(const SkTypeface* typeface) { |
@@ -289,34 +321,36 @@ static SkFaceRec* ref_ft_face(const SkTypeface* typeface) { |
rec = rec->fNext; |
} |
- int face_index; |
- SkStreamAsset* stream = typeface->openStream(&face_index); |
- if (NULL == stream) { |
+ SkFontData* data = typeface->createFontData(); |
+ if (NULL == data || !data->hasStream()) { |
return NULL; |
} |
// this passes ownership of stream to the rec |
- rec = SkNEW_ARGS(SkFaceRec, (stream, fontID)); |
+ rec = SkNEW_ARGS(SkFaceRec, (data->transferStream(), fontID)); |
FT_Open_Args args; |
memset(&args, 0, sizeof(args)); |
- const void* memoryBase = stream->getMemoryBase(); |
+ const void* memoryBase = rec->fSkStream->getMemoryBase(); |
if (memoryBase) { |
args.flags = FT_OPEN_MEMORY; |
args.memory_base = (const FT_Byte*)memoryBase; |
- args.memory_size = stream->getLength(); |
+ args.memory_size = rec->fSkStream->getLength(); |
} else { |
args.flags = FT_OPEN_STREAM; |
args.stream = &rec->fFTStream; |
} |
- FT_Error err = FT_Open_Face(gFTLibrary->library(), &args, face_index, &rec->fFace); |
+ FT_Error err = FT_Open_Face(gFTLibrary->library(), &args, data->getIndex(), &rec->fFace); |
if (err) { // bad filename, try the default font |
SkDEBUGF(("ERROR: unable to open font '%x'\n", fontID)); |
SkDELETE(rec); |
return NULL; |
} |
SkASSERT(rec->fFace); |
+ |
+ ft_face_setup_axes(rec->fFace, *data); |
+ |
rec->fNext = gFaceRecHead; |
gFaceRecHead = rec; |
return rec; |
@@ -1650,7 +1684,8 @@ bool SkTypeface_FreeType::Scanner::recognizedFont(SkStream* stream, int* numFace |
#include "SkTSearch.h" |
bool SkTypeface_FreeType::Scanner::scanFont( |
- SkStream* stream, int ttcIndex, SkString* name, SkFontStyle* style, bool* isFixedPitch) const |
+ SkStream* stream, int ttcIndex, const SkFontStyle::Axis* specifiedAxes, int specifiedAxesCount, |
+ SkString* name, SkFontStyle* style, bool* isFixedPitch, SkTArray<SkFixed, true>* axes) const |
{ |
SkAutoMutexAcquire libraryLock(fLibraryMutex); |
@@ -1726,6 +1761,75 @@ bool SkTypeface_FreeType::Scanner::scanFont( |
*isFixedPitch = FT_IS_FIXED_WIDTH(face); |
} |
+ if (axes && face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) { |
+ SkDEBUGF(("INFO: scanning mm font!\n")); |
+ |
+ FT_MM_Var* variations = NULL; |
+ FT_Error err = FT_Get_MM_Var(face, &variations); |
+ if (err) { |
+ SkDEBUGF(("INFO: font is mm, but has no variations!\n")); |
+ return false; |
+ } |
+ SkAutoFree autoFreeVariations(variations); |
+ |
+ axes->reset(variations->num_axis); |
+ for (FT_UInt i = 0; i < variations->num_axis; ++i) { |
+ const FT_Var_Axis& ftAxis = variations->axis[i]; |
+ (*axes)[i] = ftAxis.def; |
+ for (int j = 0; j < specifiedAxesCount; ++j) { |
+ if (ftAxis.tag == specifiedAxes[j].tag) { |
+ (*axes)[i] = SkTPin(specifiedAxes[j].value, (SkFixed)ftAxis.minimum, (SkFixed)ftAxis.maximum); |
+ if ((*axes)[i] != specifiedAxes[j].value) { |
+ SkDEBUGF(("Axis value out of range for: %s '%c%c%c%c' %f; pinned to %f.\n", |
+ face->family_name, |
+ (ftAxis.tag >> 24) & 0xFF, |
+ (ftAxis.tag >> 16) & 0xFF, |
+ (ftAxis.tag >> 8) & 0xFF, |
+ (ftAxis.tag ) & 0xFF, |
+ SkFixedToDouble(specifiedAxes[j].value), |
+ SkFixedToDouble((*axes)[i]))); |
+ } |
+ break; |
+ } |
+ } |
+ } |
+ |
+ SkDEBUGCODE ( |
+ // Check for axis specified, but not matched in font. |
+ for (int i = 0; i < specifiedAxesCount; ++i) { |
+ SkFourByteTag skTag = specifiedAxes[i].tag; |
+ bool found = false; |
+ for (FT_UInt j = 0; j < variations->num_axis; ++j) { |
+ if (skTag == variations->axis[j].tag) { |
+ found = true; |
+ } |
+ } |
+ if (!found) { |
+ SkDEBUGF(("Axis not in font: %s '%c%c%c%c'\n", |
+ face->family_name, |
+ (skTag >> 24) & 0xFF, |
+ (skTag >> 16) & 0xFF, |
+ (skTag >> 8) & 0xFF, |
+ (skTag ) & 0xFF)); |
+ } |
+ } |
+ // Check for an axis specified more than once. |
+ for (int i = 0; i < specifiedAxesCount; ++i) { |
+ SkFourByteTag skTag = specifiedAxes[i].tag; |
+ for (int j = i+1; j < specifiedAxesCount; ++j) { |
+ if (skTag == specifiedAxes[j].tag) { |
+ SkDEBUGF(("Specified axis more than once: %s '%c%c%c%c'\n", |
+ face->family_name, |
+ (skTag >> 24) & 0xFF, |
+ (skTag >> 16) & 0xFF, |
+ (skTag >> 8) & 0xFF, |
+ (skTag ) & 0xFF)); |
+ } |
+ } |
+ } |
+ ) |
+ } |
+ |
FT_Done_Face(face); |
return true; |
} |