diff options
author | 2015-05-20 09:21:04 -0700 | |
---|---|---|
committer | 2015-05-20 09:21:04 -0700 | |
commit | 41868fe5625fc3bd70daa3f461c881b5db6a9265 (patch) | |
tree | 6f6d670bbf415a70c152b0a6332a0428fb0d77b4 /src | |
parent | d223eb36a0be2bb5a278a483d6289a16b28eaf1a (diff) |
Font variations.
Multiple Master and TrueType fonts support variation axes.
This implements back-end support for axes on platforms which
support it.
Committed: https://skia.googlesource.com/skia/+/05773ed30920c0214d1433c07cf6360a05476c97
Committed: https://skia.googlesource.com/skia/+/3489ee0f4fa34f124f9de090d12bdc2107d52aa9
Review URL: https://codereview.chromium.org/1027373002
Diffstat (limited to 'src')
-rw-r--r-- | src/core/SkAdvancedTypefaceMetrics.h | 2 | ||||
-rw-r--r-- | src/core/SkFontDescriptor.cpp | 42 | ||||
-rw-r--r-- | src/core/SkFontDescriptor.h | 50 | ||||
-rw-r--r-- | src/core/SkFontMgr.cpp | 15 | ||||
-rw-r--r-- | src/core/SkTypeface.cpp | 28 | ||||
-rw-r--r-- | src/fonts/SkFontMgr_fontconfig.cpp | 2 | ||||
-rw-r--r-- | src/pdf/SkPDFFont.cpp | 4 | ||||
-rw-r--r-- | src/ports/SkFontConfigParser_android.cpp | 73 | ||||
-rw-r--r-- | src/ports/SkFontConfigParser_android.h | 105 | ||||
-rw-r--r-- | src/ports/SkFontHost_FreeType.cpp | 84 | ||||
-rw-r--r-- | src/ports/SkFontHost_FreeType_common.h | 10 | ||||
-rw-r--r-- | src/ports/SkFontHost_fontconfig.cpp | 1 | ||||
-rw-r--r-- | src/ports/SkFontHost_linux.cpp | 7 | ||||
-rwxr-xr-x | src/ports/SkFontHost_mac.cpp | 205 | ||||
-rw-r--r-- | src/ports/SkFontMgr_android.cpp | 119 | ||||
-rw-r--r-- | src/ports/SkFontMgr_fontconfig.cpp | 43 | ||||
-rw-r--r-- | src/ports/SkTypeface_win_dw.cpp | 1 |
17 files changed, 672 insertions, 119 deletions
diff --git a/src/core/SkAdvancedTypefaceMetrics.h b/src/core/SkAdvancedTypefaceMetrics.h index 34c5211ba4..877a2d60fb 100644 --- a/src/core/SkAdvancedTypefaceMetrics.h +++ b/src/core/SkAdvancedTypefaceMetrics.h @@ -43,7 +43,7 @@ public: enum FontFlags { kEmpty_FontFlag = 0x0, //!<No flags set - kMultiMaster_FontFlag = 0x1, //!<May be true for Type1 or CFF fonts. + kMultiMaster_FontFlag = 0x1, //!<May be true for Type1, CFF, or TrueType fonts. kNotEmbeddable_FontFlag = 0x2, //!<May not be embedded. kNotSubsettable_FontFlag = 0x4, //!<May not be subset. }; diff --git a/src/core/SkFontDescriptor.cpp b/src/core/SkFontDescriptor.cpp index 4a6b5db837..cb149b98a9 100644 --- a/src/core/SkFontDescriptor.cpp +++ b/src/core/SkFontDescriptor.cpp @@ -17,12 +17,13 @@ enum { // These count backwards from 0xFF, so as not to collide with the SFNT // defines for names in its 'name' table. + kFontAxes = 0xFC, kFontIndex = 0xFD, kFontFileName = 0xFE, // Remove when MIN_PICTURE_VERSION > 41 kSentinel = 0xFF, }; -SkFontDescriptor::SkFontDescriptor(SkTypeface::Style style) : fFontIndex(0), fStyle(style) { } +SkFontDescriptor::SkFontDescriptor(SkTypeface::Style style) : fStyle(style) { } static void read_string(SkStream* stream, SkString* string) { const uint32_t length = SkToU32(stream->readPackedUInt()); @@ -40,8 +41,7 @@ static void skip_string(SkStream* stream) { } } -static void write_string(SkWStream* stream, const SkString& string, - uint32_t id) { +static void write_string(SkWStream* stream, const SkString& string, uint32_t id) { if (!string.isEmpty()) { stream->writePackedUInt(id); stream->writePackedUInt(string.size()); @@ -58,9 +58,12 @@ static void write_uint(SkWStream* stream, size_t n, uint32_t id) { stream->writePackedUInt(n); } -SkFontDescriptor::SkFontDescriptor(SkStream* stream) : fFontIndex(0) { +SkFontDescriptor::SkFontDescriptor(SkStream* stream) { fStyle = (SkTypeface::Style)stream->readPackedUInt(); + SkAutoSTMalloc<4, SkFixed> axis; + size_t axisCount = 0; + size_t index = 0; for (size_t id; (id = stream->readPackedUInt()) != kSentinel;) { switch (id) { case kFontFamilyName: @@ -72,8 +75,15 @@ SkFontDescriptor::SkFontDescriptor(SkStream* stream) : fFontIndex(0) { case kPostscriptName: read_string(stream, &fPostscriptName); break; + case kFontAxes: + axisCount = read_uint(stream); + axis.reset(axisCount); + for (size_t i = 0; i < axisCount; ++i) { + axis[i] = read_uint(stream); + } + break; case kFontIndex: - fFontIndex = read_uint(stream); + index = read_uint(stream); break; case kFontFileName: // Remove when MIN_PICTURE_VERSION > 41 skip_string(stream); @@ -88,7 +98,8 @@ SkFontDescriptor::SkFontDescriptor(SkStream* stream) : fFontIndex(0) { if (length > 0) { SkAutoTUnref<SkData> data(SkData::NewUninitialized(length)); if (stream->read(data->writable_data(), length) == length) { - fFontData.reset(SkNEW_ARGS(SkMemoryStream, (data))); + fFontData.reset(new SkFontData(SkNEW_ARGS(SkMemoryStream, (data)), index, + axis, axisCount)); } } } @@ -99,16 +110,25 @@ void SkFontDescriptor::serialize(SkWStream* stream) { write_string(stream, fFamilyName, kFontFamilyName); write_string(stream, fFullName, kFullName); write_string(stream, fPostscriptName, kPostscriptName); - if (fFontIndex) { - write_uint(stream, fFontIndex, kFontIndex); + if (fFontData.get()) { + if (fFontData->getIndex()) { + write_uint(stream, fFontData->getIndex(), kFontIndex); + } + if (fFontData->getAxisCount()) { + write_uint(stream, fFontData->getAxisCount(), kFontAxes); + for (int i = 0; i < fFontData->getAxisCount(); ++i) { + stream->writePackedUInt(fFontData->getAxis()[i]); + } + } } stream->writePackedUInt(kSentinel); - if (fFontData) { - size_t length = fFontData->getLength(); + if (fFontData.get() && fFontData->hasStream()) { + SkAutoTDelete<SkStreamAsset> fontData(fFontData->detachStream()); + size_t length = fontData->getLength(); stream->writePackedUInt(length); - stream->writeStream(fFontData, length); + stream->writeStream(fontData, length); } else { stream->writePackedUInt(0); } diff --git a/src/core/SkFontDescriptor.h b/src/core/SkFontDescriptor.h index 66707ddd3c..933a36a095 100644 --- a/src/core/SkFontDescriptor.h +++ b/src/core/SkFontDescriptor.h @@ -12,7 +12,42 @@ #include "SkString.h" #include "SkTypeface.h" -class SkFontDescriptor { +class SkFontData { +public: + /** This takes ownership of 'stream'. Makes a copy of the data in 'axis'. */ + SkFontData(SkStreamAsset* stream, int index, const SkFixed axis[], int axisCount) + : fStream(stream), fIndex(index), fAxisCount(axisCount), fAxis(axisCount) + { + for (int i = 0; i < axisCount; ++i) { + fAxis[i] = axis[i]; + } + } + SkFontData(const SkFontData& that) + : fStream(that.fStream->duplicate()) + , fIndex(that.fIndex) + , fAxisCount(that.fAxisCount) + , fAxis(fAxisCount) + { + for (int i = 0; i < fAxisCount; ++i) { + fAxis[i] = that.fAxis[i]; + } + } + bool hasStream() const { return fStream.get() != NULL; } + SkStreamAsset* duplicateStream() const { return fStream->duplicate(); } + SkStreamAsset* detachStream() { return fStream.detach(); } + SkStreamAsset* getStream() { return fStream.get(); } + int getIndex() const { return fIndex; } + int getAxisCount() const { return fAxisCount; } + const SkFixed* getAxis() const { return fAxis.get(); } + +private: + SkAutoTDelete<SkStreamAsset> fStream; + int fIndex; + int fAxisCount; + SkAutoSTMalloc<4, SkFixed> fAxis; +}; + +class SkFontDescriptor : SkNoncopyable { public: SkFontDescriptor(SkTypeface::Style = SkTypeface::kNormal); // Does not affect ownership of SkStream. @@ -27,25 +62,20 @@ public: const char* getFullName() const { return fFullName.c_str(); } const char* getPostscriptName() const { return fPostscriptName.c_str(); } bool hasFontData() const { return fFontData.get() != NULL; } - // Transfers ownership to the caller. - SkStreamAsset* transferFontData() { return fFontData.detach(); } - int getFontIndex() const { return fFontIndex; } + SkFontData* detachFontData() { return fFontData.detach(); } void setFamilyName(const char* name) { fFamilyName.set(name); } void setFullName(const char* name) { fFullName.set(name); } void setPostscriptName(const char* name) { fPostscriptName.set(name); } /** Set the font data only if it is necessary for serialization. - * This method takes ownership of the stream (both reference and cursor). - */ - void setFontData(SkStreamAsset* stream) { fFontData.reset(stream); } - void setFontIndex(int index) { fFontIndex = index; } + * This method takes ownership of the font data. */ + void setFontData(SkFontData* data) { fFontData.reset(data); } private: SkString fFamilyName; SkString fFullName; SkString fPostscriptName; - SkAutoTDelete<SkStreamAsset> fFontData; - int fFontIndex; + SkAutoTDelete<SkFontData> fFontData; SkTypeface::Style fStyle; }; diff --git a/src/core/SkFontMgr.cpp b/src/core/SkFontMgr.cpp index a03e05e0e4..33da1db376 100644 --- a/src/core/SkFontMgr.cpp +++ b/src/core/SkFontMgr.cpp @@ -5,6 +5,7 @@ * found in the LICENSE file. */ +#include "SkFontDescriptor.h" #include "SkFontMgr.h" #include "SkLazyPtr.h" #include "SkStream.h" @@ -133,6 +134,20 @@ SkTypeface* SkFontMgr::createFromStream(SkStreamAsset* stream, int ttcIndex) con return this->onCreateFromStream(stream, ttcIndex); } +SkTypeface* SkFontMgr::createFromFontData(SkFontData* data) const { + if (NULL == data) { + return NULL; + } + return this->onCreateFromFontData(data); +} + +// This implementation is temporary until it can be made pure virtual. +SkTypeface* SkFontMgr::onCreateFromFontData(SkFontData* data) const { + SkTypeface* ret = this->createFromStream(data->detachStream(), data->getIndex()); + delete data; + return ret; +} + SkTypeface* SkFontMgr::createFromFile(const char path[], int ttcIndex) const { if (NULL == path) { return NULL; diff --git a/src/core/SkTypeface.cpp b/src/core/SkTypeface.cpp index 0f5d70b1a8..342c41553d 100644 --- a/src/core/SkTypeface.cpp +++ b/src/core/SkTypeface.cpp @@ -143,6 +143,11 @@ SkTypeface* SkTypeface::CreateFromStream(SkStreamAsset* stream, int index) { return fm->createFromStream(stream, index); } +SkTypeface* SkTypeface::CreateFromFontData(SkFontData* data) { + SkAutoTUnref<SkFontMgr> fm(SkFontMgr::RefDefault()); + return fm->createFromFontData(data); +} + SkTypeface* SkTypeface::CreateFromFile(const char path[], int index) { SkAutoTUnref<SkFontMgr> fm(SkFontMgr::RefDefault()); return fm->createFromFile(path, index); @@ -157,9 +162,7 @@ void SkTypeface::serialize(SkWStream* wstream) const { // Embed font data if it's a local font. if (isLocal && !desc.hasFontData()) { - int ttcIndex; - desc.setFontData(this->onOpenStream(&ttcIndex)); - desc.setFontIndex(ttcIndex); + desc.setFontData(this->onCreateFontData()); } desc.serialize(wstream); } @@ -171,18 +174,16 @@ void SkTypeface::serializeForcingEmbedding(SkWStream* wstream) const { // Always embed font data. if (!desc.hasFontData()) { - int ttcIndex; - desc.setFontData(this->onOpenStream(&ttcIndex)); - desc.setFontIndex(ttcIndex); + desc.setFontData(this->onCreateFontData()); } desc.serialize(wstream); } SkTypeface* SkTypeface::Deserialize(SkStream* stream) { SkFontDescriptor desc(stream); - SkStreamAsset* data = desc.transferFontData(); + SkFontData* data = desc.detachFontData(); if (data) { - SkTypeface* typeface = SkTypeface::CreateFromStream(data, desc.getFontIndex()); + SkTypeface* typeface = SkTypeface::CreateFromFontData(data); if (typeface) { return typeface; } @@ -218,6 +219,17 @@ SkStreamAsset* SkTypeface::openStream(int* ttcIndex) const { return this->onOpenStream(ttcIndex); } +SkFontData* SkTypeface::createFontData() const { + return this->onCreateFontData(); +} + +// This implementation is temporary until this method can be made pure virtual. +SkFontData* SkTypeface::onCreateFontData() const { + int index; + SkAutoTDelete<SkStreamAsset> stream(this->onOpenStream(&index)); + return new SkFontData(stream.detach(), index, NULL, 0); +}; + int SkTypeface::charsToGlyphs(const void* chars, Encoding encoding, uint16_t glyphs[], int glyphCount) const { if (glyphCount <= 0) { diff --git a/src/fonts/SkFontMgr_fontconfig.cpp b/src/fonts/SkFontMgr_fontconfig.cpp index 9bdc9272f3..9294990c98 100644 --- a/src/fonts/SkFontMgr_fontconfig.cpp +++ b/src/fonts/SkFontMgr_fontconfig.cpp @@ -308,7 +308,7 @@ protected: // TODO should the caller give us the style or should we get it from freetype? SkFontStyle style; bool isFixedWidth = false; - if (!fScanner.scanFont(stream, 0, NULL, &style, &isFixedWidth)) { + if (!fScanner.scanFont(stream, 0, NULL, &style, &isFixedWidth, NULL)) { return NULL; } diff --git a/src/pdf/SkPDFFont.cpp b/src/pdf/SkPDFFont.cpp index e531df06bc..9fed9d6d8e 100644 --- a/src/pdf/SkPDFFont.cpp +++ b/src/pdf/SkPDFFont.cpp @@ -885,9 +885,7 @@ SkPDFFont* SkPDFFont::Create(SkPDFCanon* canon, SkAdvancedTypefaceMetrics::FontType type = info ? info->fType : SkAdvancedTypefaceMetrics::kOther_Font; - if (info && - (info->fFlags & SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag)) { - NOT_IMPLEMENTED(true, true); + if (info && (info->fFlags & SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag)) { return new SkPDFType3Font(info, typeface, glyphID); } if (type == SkAdvancedTypefaceMetrics::kType1CID_Font || diff --git a/src/ports/SkFontConfigParser_android.cpp b/src/ports/SkFontConfigParser_android.cpp index 73e4c47738..3825a72903 100644 --- a/src/ports/SkFontConfigParser_android.cpp +++ b/src/ports/SkFontConfigParser_android.cpp @@ -14,9 +14,7 @@ #include <expat.h> #include <dirent.h> -#include <stdio.h> -#include <limits> #include <stdlib.h> #define LMP_SYSTEM_FONTS_FILE "/system/etc/fonts.xml" @@ -111,32 +109,6 @@ struct FamilyData { SkTDArray<const TagHandler*> fHandler; // The stack of current tag handlers. }; -/** Parses a null terminated string into an integer type, checking for overflow. - * http://www.w3.org/TR/html-markup/datatypes.html#common.data.integer.non-negative-def - * - * If the string cannot be parsed into 'value', returns false and does not change 'value'. - */ -template <typename T> static bool parse_non_negative_integer(const char* s, T* value) { - SK_COMPILE_ASSERT(std::numeric_limits<T>::is_integer, T_must_be_integer); - const T nMax = std::numeric_limits<T>::max() / 10; - const T dMax = std::numeric_limits<T>::max() - (nMax * 10); - T n = 0; - for (; *s; ++s) { - // Check if digit - if (*s < '0' || '9' < *s) { - return false; - } - int d = *s - '0'; - // Check for overflow - if (n > nMax || (n == nMax && d > dMax)) { - return false; - } - n = (n * 10) + d; - } - *value = n; - return true; -} - static bool memeq(const char* s1, const char* s2, size_t n1, size_t n2) { return n1 == n2 && 0 == memcmp(s1, s2, n1); } @@ -174,6 +146,43 @@ static void trim_string(SkString* s) { namespace lmpParser { +static const TagHandler axisHandler = { + /*start*/[](FamilyData* self, const char* tag, const char** attributes) { + FontFileInfo& file = *self->fCurrentFontInfo; + FontFileInfo::Axis& axis = file.fAxes.push_back(); + for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) { + const char* name = attributes[i]; + const char* value = attributes[i+1]; + size_t nameLen = strlen(name); + if (MEMEQ("tag", name, nameLen)) { + size_t valueLen = strlen(value); + if (valueLen == 4) { + SkFourByteTag tag = SkSetFourByteTag(value[0], value[1], value[2], value[3]); + for (int j = 0; j < file.fAxes.count() - 1; ++j) { + if (file.fAxes[j].fTag == tag) { + SK_FONTCONFIGPARSER_WARNING("'%c%c%c%c' axis specified more than once", + (tag >> 24) & 0xFF, + (tag >> 16) & 0xFF, + (tag >> 8) & 0xFF, + (tag ) & 0xFF); + } + } + axis.fTag = SkSetFourByteTag(value[0], value[1], value[2], value[3]); + } else { + SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid axis tag", value); + } + } else if (MEMEQ("stylevalue", name, nameLen)) { + if (!parse_fixed<16>(value, &axis.fValue)) { + SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid axis stylevalue", value); + } + } + } + }, + /*end*/NULL, + /*tag*/NULL, + /*chars*/NULL, +}; + static const TagHandler fontHandler = { /*start*/[](FamilyData* self, const char* tag, const char** attributes) { // 'weight' (non-negative integer) [default 0] @@ -207,7 +216,13 @@ static const TagHandler fontHandler = { /*end*/[](FamilyData* self, const char* tag) { trim_string(&self->fCurrentFontInfo->fFileName); }, - /*tag*/NULL, + /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* { + size_t len = strlen(tag); + if (MEMEQ("axis", tag, len)) { + return &axisHandler; + } + return NULL; + }, /*chars*/[](void* data, const char* s, int len) { FamilyData* self = static_cast<FamilyData*>(data); self->fCurrentFontInfo->fFileName.append(s, len); diff --git a/src/ports/SkFontConfigParser_android.h b/src/ports/SkFontConfigParser_android.h index dd856bf733..c1327ff74e 100644 --- a/src/ports/SkFontConfigParser_android.h +++ b/src/ports/SkFontConfigParser_android.h @@ -12,6 +12,9 @@ #include "SkString.h" #include "SkTDArray.h" +#include <climits> +#include <limits> + /** \class SkLanguage The SkLanguage class represents a human written language, and is used by @@ -68,6 +71,12 @@ struct FontFileInfo { int fIndex; int fWeight; enum class Style { kAuto, kNormal, kItalic } fStyle; + struct Axis { + Axis() : fTag(SkSetFourByteTag('\0','\0','\0','\0')), fValue(0) { } + SkFourByteTag fTag; + SkFixed fValue; + }; + SkSTArray<4, Axis, true> fAxes; }; /** @@ -108,4 +117,100 @@ void GetCustomFontFamilies(SkTDArray<FontFamily*>& fontFamilies, } // SkFontConfigParser namespace + +/** Parses a null terminated string into an integer type, checking for overflow. + * http://www.w3.org/TR/html-markup/datatypes.html#common.data.integer.non-negative-def + * + * If the string cannot be parsed into 'value', returns false and does not change 'value'. + */ +template <typename T> static bool parse_non_negative_integer(const char* s, T* value) { + SK_COMPILE_ASSERT(std::numeric_limits<T>::is_integer, T_must_be_integer); + + if (*s == '\0') { + return false; + } + + const T nMax = std::numeric_limits<T>::max() / 10; + const T dMax = std::numeric_limits<T>::max() - (nMax * 10); + T n = 0; + for (; *s; ++s) { + // Check if digit + if (*s < '0' || '9' < *s) { + return false; + } + T d = *s - '0'; + // Check for overflow + if (n > nMax || (n == nMax && d > dMax)) { + return false; + } + n = (n * 10) + d; + } + *value = n; + return true; +} + +/** Parses a null terminated string into a signed fixed point value with bias N. + * + * Like http://www.w3.org/TR/html-markup/datatypes.html#common.data.float-def , + * but may start with '.' and does not support 'e'. '-?((:digit:+(.:digit:+)?)|(.:digit:+))' + * + * Checks for overflow. + * Low bit rounding is not defined (is currently truncate). + * Bias (N) required to allow for the sign bit and 4 bits of integer. + * + * If the string cannot be parsed into 'value', returns false and does not change 'value'. + */ +template <int N, typename T> static bool parse_fixed(const char* s, T* value) { + SK_COMPILE_ASSERT(std::numeric_limits<T>::is_integer, T_must_be_integer); + SK_COMPILE_ASSERT(std::numeric_limits<T>::is_signed, T_must_be_signed); + SK_COMPILE_ASSERT(sizeof(T) * CHAR_BIT - N >= 5, N_must_leave_four_bits_plus_sign); + + bool negate = false; + if (*s == '-') { + ++s; + negate = true; + } + if (*s == '\0') { + return false; + } + + const T nMax = (std::numeric_limits<T>::max() >> N) / 10; + const T dMax = (std::numeric_limits<T>::max() >> N) - (nMax * 10); + T n = 0; + T frac = 0; + for (; *s; ++s) { + // Check if digit + if (*s < '0' || '9' < *s) { + // If it wasn't a digit, check if it is a '.' followed by something. + if (*s != '.' || s[1] == '\0') { + return false; + } + // Find the end, verify digits. + for (++s; *s; ++s) { + if (*s < '0' || '9' < *s) { + return false; + } + } + // Read back toward the '.'. + for (--s; *s != '.'; --s) { + T d = *s - '0'; + frac = (frac + (d << N)) / 10; // This requires four bits overhead. + } + break; + } + T d = *s - '0'; + // Check for overflow + if (n > nMax || (n == nMax && d > dMax)) { + return false; + } + n = (n * 10) + d; + } + if (negate) { + n = -n; + frac = -frac; + } + *value = (n << N) + frac; + return true; +} + #endif /* SKFONTCONFIGPARSER_ANDROID_H_ */ diff --git a/src/ports/SkFontHost_FreeType.cpp b/src/ports/SkFontHost_FreeType.cpp index 5c53b9d913..e02e338cfc 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 @@ -40,6 +42,10 @@ #include FT_TYPE1_TABLES_H #include FT_XFREE86_H +#if !defined(SK_BUILD_FOR_ANDROID) || defined(SK_ANDROID_FREETYPE_HAS_MM) +# define SK_FREETYPE_HAS_MM 1 +#endif + // FT_LOAD_COLOR and the corresponding FT_Pixel_Mode::FT_PIXEL_MODE_BGRA // were introduced in FreeType 2.5.0. // The following may be removed once FreeType 2.5.0 is required to build. @@ -273,6 +279,39 @@ SkFaceRec::SkFaceRec(SkStreamAsset* stream, uint32_t fontID) fFTStream.close = sk_ft_stream_close; } +#if SK_FREETYPE_HAS_MM +static void ft_face_setup_axes(FT_Face face, const SkFontData& data) { + if (!(face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) { + return; + } + + SkDEBUGCODE( + FT_MM_Var* variations = NULL; + if (FT_Get_MM_Var(face, &variations)) { + SkDEBUGF(("INFO: font %s claims variations, but none found.\n", face->family_name)); + return; + } + SkAutoFree autoFreeVariations(variations); + + if (static_cast<FT_UInt>(data.getAxisCount()) != variations->num_axis) { + SkDEBUGF(("INFO: font %s has %d variations, but %d were specified.\n", + face->family_name, variations->num_axis, data.getAxisCount())); + return; + } + ) + + SkAutoSTMalloc<4, FT_Fixed> coords(data.getAxisCount()); + for (int i = 0; i < data.getAxisCount(); ++i) { + coords[i] = data.getAxis()[i]; + } + if (FT_Set_Var_Design_Coordinates(face, data.getAxisCount(), coords.get())) { + SkDEBUGF(("INFO: font %s has variations, but specified variations could not be set.\n", + face->family_name)); + return; + } +} +#endif + // Will return 0 on failure // Caller must lock gFTMutex before calling this function. static SkFaceRec* ref_ft_face(const SkTypeface* typeface) { @@ -289,34 +328,38 @@ static SkFaceRec* ref_ft_face(const SkTypeface* typeface) { rec = rec->fNext; } - int face_index; - SkStreamAsset* stream = typeface->openStream(&face_index); - if (NULL == stream) { + SkAutoTDelete<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->detachStream(), 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); - if (err) { // bad filename, try the default font + FT_Error err = FT_Open_Face(gFTLibrary->library(), &args, data->getIndex(), &rec->fFace); + if (err) { SkDEBUGF(("ERROR: unable to open font '%x'\n", fontID)); SkDELETE(rec); return NULL; } SkASSERT(rec->fFace); + +#if SK_FREETYPE_HAS_MM + ft_face_setup_axes(rec->fFace, *data); +#endif + rec->fNext = gFaceRecHead; gFaceRecHead = rec; return rec; @@ -1649,7 +1692,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, + SkString* name, SkFontStyle* style, bool* isFixedPitch, AxisDefinitions* axes) const { SkAutoMutexAcquire libraryLock(fLibraryMutex); @@ -1725,6 +1769,28 @@ bool SkTypeface_FreeType::Scanner::scanFont( *isFixedPitch = FT_IS_FIXED_WIDTH(face); } +#if SK_FREETYPE_HAS_MM + if (axes && face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) { + FT_MM_Var* variations = NULL; + FT_Error err = FT_Get_MM_Var(face, &variations); + if (err) { + SkDEBUGF(("INFO: font %s claims to have variations, but none found.\n", + face->family_name)); + 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].fTag = ftAxis.tag; + (*axes)[i].fMinimum = ftAxis.minimum; + (*axes)[i].fDefault = ftAxis.def; + (*axes)[i].fMaximum = ftAxis.maximum; + } + } +#endif + FT_Done_Face(face); return true; } diff --git a/src/ports/SkFontHost_FreeType_common.h b/src/ports/SkFontHost_FreeType_common.h index 857d2c8990..8ae872c1da 100644 --- a/src/ports/SkFontHost_FreeType_common.h +++ b/src/ports/SkFontHost_FreeType_common.h @@ -43,9 +43,17 @@ public: public: Scanner(); ~Scanner(); + struct AxisDefinition { + SkFourByteTag fTag; + SkFixed fMinimum; + SkFixed fDefault; + SkFixed fMaximum; + }; + using AxisDefinitions = SkSTArray<4, AxisDefinition, true>; bool recognizedFont(SkStream* stream, int* numFonts) const; bool scanFont(SkStream* stream, int ttcIndex, - SkString* name, SkFontStyle* style, bool* isFixedPitch) const; + SkString* name, SkFontStyle* style, bool* isFixedPitch, + AxisDefinitions* axes) const; private: FT_Face openFace(SkStream* stream, int ttcIndex, FT_Stream ftStream) const; FT_Library fLibrary; diff --git a/src/ports/SkFontHost_fontconfig.cpp b/src/ports/SkFontHost_fontconfig.cpp index fa74f5121f..2fdb16e364 100644 --- a/src/ports/SkFontHost_fontconfig.cpp +++ b/src/ports/SkFontHost_fontconfig.cpp @@ -155,6 +155,5 @@ void FontConfigTypeface::onGetFontDescriptor(SkFontDescriptor* desc, SkString name; this->getFamilyName(&name); desc->setFamilyName(name.c_str()); - desc->setFontIndex(this->getIdentity().fTTCIndex); *isLocalStream = SkToBool(this->getLocalStream()); } diff --git a/src/ports/SkFontHost_linux.cpp b/src/ports/SkFontHost_linux.cpp index da2c2d00d1..b4404ca745 100644 --- a/src/ports/SkFontHost_linux.cpp +++ b/src/ports/SkFontHost_linux.cpp @@ -39,7 +39,6 @@ protected: void onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const override { desc->setFamilyName(fFamilyName.c_str()); - desc->setFontIndex(fIndex); *isLocal = !this->isSysFont(); } @@ -306,7 +305,7 @@ protected: bool isFixedPitch; SkFontStyle style; SkString name; - if (fScanner.scanFont(stream, ttcIndex, &name, &style, &isFixedPitch)) { + if (fScanner.scanFont(stream, ttcIndex, &name, &style, &isFixedPitch, NULL)) { return SkNEW_ARGS(SkTypeface_Stream, (style, isFixedPitch, false, name, stream.detach(), ttcIndex)); } else { @@ -405,7 +404,7 @@ private: bool isFixedPitch; SkString realname; SkFontStyle style = SkFontStyle(); // avoid uninitialized warning - if (!scanner.scanFont(stream, faceIndex, &realname, &style, &isFixedPitch)) { + if (!scanner.scanFont(stream, faceIndex, &realname, &style, &isFixedPitch, NULL)) { SkDebugf("---- failed to open <%s> <%d> as a font\n", filename.c_str(), faceIndex); continue; @@ -491,7 +490,7 @@ private: bool isFixedPitch; SkString realname; SkFontStyle style = SkFontStyle(); // avoid uninitialized warning - if (!scanner.scanFont(stream, faceIndex, &realname, &style, &isFixedPitch)) { + if (!scanner.scanFont(stream, faceIndex, &realname, &style, &isFixedPitch, NULL)) { SkDebugf("---- failed to open <%d> <%d> as a font\n", index, faceIndex); return; } diff --git a/src/ports/SkFontHost_mac.cpp b/src/ports/SkFontHost_mac.cpp index 3c7be46364..ff23b99905 100755 --- a/src/ports/SkFontHost_mac.cpp +++ b/src/ports/SkFontHost_mac.cpp @@ -428,10 +428,12 @@ static const uint32_t SkCTFontColorGlyphsTrait = (1 << 13); class SkTypeface_Mac : public SkTypeface { public: SkTypeface_Mac(const SkFontStyle& fs, bool isFixedPitch, - CTFontRef fontRef, const char requestedName[], bool isLocalStream) + CTFontRef fontRef, const char requestedName[], bool isLocalStream, + CGFontRef originatingCGFontRef = NULL) : SkTypeface(fs, SkTypefaceCache::NewFontID(), isFixedPitch) , fRequestedName(requestedName) , fFontRef(fontRef) // caller has already called CFRetain for us + , fOriginatingCGFontRef(originatingCGFontRef) , fHasColorGlyphs(SkToBool(CTFontGetSymbolicTraits(fFontRef) & SkCTFontColorGlyphsTrait)) , fIsLocalStream(isLocalStream) { @@ -440,11 +442,13 @@ public: SkString fRequestedName; AutoCFRelease<CTFontRef> fFontRef; + AutoCFRelease<CGFontRef> fOriginatingCGFontRef; const bool fHasColorGlyphs; protected: int onGetUPEM() const override; SkStreamAsset* onOpenStream(int* ttcIndex) const override; + SkFontData* onCreateFontData() const override; void onGetFamilyName(SkString* familyName) const override; SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override; int onGetTableTags(SkFontTableTag tags[]) const override; @@ -467,12 +471,15 @@ private: }; /** Creates a typeface without searching the cache. Takes ownership of the CTFontRef. */ -static SkTypeface* NewFromFontRef(CTFontRef fontRef, const char name[], bool isLocalStream) { +static SkTypeface* NewFromFontRef(CTFontRef fontRef, const char name[], bool isLocalStream, + CGFontRef originatingCGFontRef = NULL) +{ SkASSERT(fontRef); bool isFixedPitch; SkFontStyle style = SkFontStyle(computeStyleBits(fontRef, &isFixedPitch)); - return new SkTypeface_Mac(style, isFixedPitch, fontRef, name, isLocalStream); + return new SkTypeface_Mac(style, isFixedPitch, fontRef, name, isLocalStream, + originatingCGFontRef); } static bool find_by_CTFontRef(SkTypeface* cached, const SkFontStyle&, void* context) { @@ -1752,6 +1759,115 @@ SkStreamAsset* SkTypeface_Mac::onOpenStream(int* ttcIndex) const { return stream; } +struct NonDefaultAxesContext { + SkFixed* axisValue; + CFArrayRef cgAxes; +}; +static void set_non_default_axes(CFTypeRef key, CFTypeRef value, void* context) { + NonDefaultAxesContext* self = static_cast<NonDefaultAxesContext*>(context); + + if (CFGetTypeID(key) != CFStringGetTypeID() || CFGetTypeID(value) != CFNumberGetTypeID()) { + return; + } + + // The key is a CFString which is a string from the 'name' table. + // Search the cgAxes for an axis with this name, and use its index to store the value. + CFIndex keyIndex = -1; + CFStringRef keyString = static_cast<CFStringRef>(key); + for (CFIndex i = 0; i < CFArrayGetCount(self->cgAxes); ++i) { + CFTypeRef cgAxis = CFArrayGetValueAtIndex(self->cgAxes, i); + if (CFGetTypeID(cgAxis) != CFDictionaryGetTypeID()) { + continue; + } + + CFDictionaryRef cgAxisDict = static_cast<CFDictionaryRef>(cgAxis); + CFTypeRef cgAxisName = CFDictionaryGetValue(cgAxisDict, kCGFontVariationAxisName); + if (!cgAxisName || CFGetTypeID(cgAxisName) != CFStringGetTypeID()) { + continue; + } + CFStringRef cgAxisNameString = static_cast<CFStringRef>(cgAxisName); + if (CFStringCompare(keyString, cgAxisNameString, 0) == kCFCompareEqualTo) { + keyIndex = i; + break; + } + } + if (keyIndex == -1) { + return; + } + + CFNumberRef valueNumber = static_cast<CFNumberRef>(value); + double valueDouble; + if (!CFNumberGetValue(valueNumber, kCFNumberDoubleType, &valueDouble) || + valueDouble < SkFixedToDouble(SK_FixedMin) || SkFixedToDouble(SK_FixedMax) < valueDouble) + { + return; + } + self->axisValue[keyIndex] = SkDoubleToFixed(valueDouble); +} +static bool get_variations(CTFontRef fFontRef, CFIndex* cgAxisCount, + SkAutoSTMalloc<4, SkFixed>* axisValues) +{ + // CTFontCopyVariationAxes and CTFontCopyVariation do not work when applied to fonts which + // started life with CGFontCreateWithDataProvider (they simply always return NULL). + // As a result, we are limited to CGFontCopyVariationAxes and CGFontCopyVariations. + AutoCFRelease<CGFontRef> cgFont(CTFontCopyGraphicsFont(fFontRef, NULL)); + + AutoCFRelease<CFDictionaryRef> cgVariations(CGFontCopyVariations(cgFont)); + // If a font has no variations CGFontCopyVariations returns NULL (instead of an empty dict). + if (!cgVariations.get()) { + return false; + } + + AutoCFRelease<CFArrayRef> cgAxes(CGFontCopyVariationAxes(cgFont)); + *cgAxisCount = CFArrayGetCount(cgAxes); + axisValues->reset(*cgAxisCount); + + // Set all of the axes to their default values. + // Fail if any default value cannot be determined. + for (CFIndex i = 0; i < *cgAxisCount; ++i) { + CFTypeRef cgAxis = CFArrayGetValueAtIndex(cgAxes, i); + if (CFGetTypeID(cgAxis) != CFDictionaryGetTypeID()) { + return false; + } + + CFDictionaryRef cgAxisDict = static_cast<CFDictionaryRef>(cgAxis); + CFTypeRef axisDefaultValue = CFDictionaryGetValue(cgAxisDict, + kCGFontVariationAxisDefaultValue); + if (!axisDefaultValue || CFGetTypeID(axisDefaultValue) != CFNumberGetTypeID()) { + return false; + } + CFNumberRef axisDefaultValueNumber = static_cast<CFNumberRef>(axisDefaultValue); + double axisDefaultValueDouble; + if (!CFNumberGetValue(axisDefaultValueNumber, kCFNumberDoubleType, &axisDefaultValueDouble)) + { + return false; + } + if (axisDefaultValueDouble < SkFixedToDouble(SK_FixedMin) || + SkFixedToDouble(SK_FixedMax) < axisDefaultValueDouble) + { + return false; + } + (*axisValues)[(int)i] = SkDoubleToFixed(axisDefaultValueDouble); + } + + // Override the default values with the given font's stated axis values. + NonDefaultAxesContext c = { axisValues->get(), cgAxes.get() }; + CFDictionaryApplyFunction(cgVariations, set_non_default_axes, &c); + + return true; +} +SkFontData* SkTypeface_Mac::onCreateFontData() const { + int index; + SkAutoTDelete<SkStreamAsset> stream(this->onOpenStream(&index)); + + CFIndex cgAxisCount; + SkAutoSTMalloc<4, SkFixed> axisValues; + if (get_variations(fFontRef, &cgAxisCount, &axisValues)) { + return new SkFontData(stream.detach(), index, axisValues.get(), cgAxisCount); + } + return new SkFontData(stream.detach(), index, NULL, 0); +} + /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// @@ -2247,6 +2363,89 @@ protected: return create_from_dataProvider(pr); } + static CFDictionaryRef get_axes(CGFontRef cg, SkFontData* fontData) { + AutoCFRelease<CFArrayRef> cgAxes(CGFontCopyVariationAxes(cg)); + if (!cgAxes) { + return NULL; + } + + CFIndex axisCount = CFArrayGetCount(cgAxes); + if (0 == axisCount || axisCount != fontData->getAxisCount()) { + return NULL; + } + + CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorDefault, axisCount, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + for (int i = 0; i < fontData->getAxisCount(); ++i) { + CFTypeRef axisInfo = CFArrayGetValueAtIndex(cgAxes, i); + if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) { + return NULL; + } + CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo); + + CFTypeRef axisName = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisName); + if (!axisName || CFGetTypeID(axisName) != CFStringGetTypeID()) { + return NULL; + } + + // The variation axes can be set to any value, but cg will effectively pin them. + // Pin them here to normalize. + CFTypeRef min = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisMinValue); + CFTypeRef max = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisMaxValue); + if (!min || CFGetTypeID(min) != CFNumberGetTypeID() || + !max || CFGetTypeID(max) != CFNumberGetTypeID()) + { + return NULL; + } + CFNumberRef minNumber = static_cast<CFNumberRef>(min); + CFNumberRef maxNumber = static_cast<CFNumberRef>(max); + double minDouble; + double maxDouble; + if (!CFNumberGetValue(minNumber, kCFNumberDoubleType, &minDouble) || + !CFNumberGetValue(maxNumber, kCFNumberDoubleType, &maxDouble)) + { + return NULL; + } + double value = SkTPin(SkFixedToDouble(fontData->getAxis()[i]), minDouble, maxDouble); + CFNumberRef valueNumber = CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, + &value); + + CFDictionaryAddValue(dict, axisName, valueNumber); + CFRelease(valueNumber); + } + return dict; + } + SkTypeface* onCreateFromFontData(SkFontData* data) const override { + SkAutoTDelete<SkFontData> fontData(data); + SkStreamAsset* stream = fontData->detachStream(); + AutoCFRelease<CGDataProviderRef> provider(SkCreateDataProviderFromStream(stream)); + if (NULL == provider) { + return NULL; + } + AutoCFRelease<CGFontRef> cg(CGFontCreateWithDataProvider(provider)); + if (NULL == cg) { + return NULL; + } + + AutoCFRelease<CFDictionaryRef> cgVariations(get_axes(cg, fontData)); + // The CGFontRef returned by CGFontCreateCopyWithVariations when the passed CGFontRef was + // created from a data provider does not appear to have any ownership of the underlying + // data. The original CGFontRef must be kept alive until the copy will no longer be used. + AutoCFRelease<CGFontRef> cgVariant; + if (cgVariations) { + cgVariant.reset(CGFontCreateCopyWithVariations(cg, cgVariations)); + } else { + cgVariant.reset(cg.detach()); + } + + CTFontRef ct = CTFontCreateWithGraphicsFont(cgVariant, 0, NULL, NULL); + if (!ct) { + return NULL; + } + return NewFromFontRef(ct, NULL, true, cg.detach()); + } + SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override { AutoCFRelease<CGDataProviderRef> pr(CGDataProviderCreateWithFilename(path)); if (NULL == pr) { diff --git a/src/ports/SkFontMgr_android.cpp b/src/ports/SkFontMgr_android.cpp index ae1b663e26..a67c6814ea 100644 --- a/src/ports/SkFontMgr_android.cpp +++ b/src/ports/SkFontMgr_android.cpp @@ -27,20 +27,18 @@ static const char* gTestBasePath = NULL; class SkTypeface_Android : public SkTypeface_FreeType { public: - SkTypeface_Android(int index, - const SkFontStyle& style, + SkTypeface_Android(const SkFontStyle& style, bool isFixedPitch, const SkString& familyName) : INHERITED(style, SkTypefaceCache::NewFontID(), isFixedPitch) - , fIndex(index) - , fFamilyName(familyName) { } + , fFamilyName(familyName) + { } protected: void onGetFamilyName(SkString* familyName) const override { *familyName = fFamilyName; } - int fIndex; SkString fFamilyName; private: @@ -51,30 +49,37 @@ class SkTypeface_AndroidSystem : public SkTypeface_Android { public: SkTypeface_AndroidSystem(const SkString& pathName, int index, + const SkFixed* axes, int axesCount, const SkFontStyle& style, bool isFixedPitch, const SkString& familyName, const SkLanguage& lang, FontVariant variantStyle) - : INHERITED(index, style, isFixedPitch, familyName) + : INHERITED(style, isFixedPitch, familyName) , fPathName(pathName) + , fIndex(index) + , fAxes(axes, axesCount) , fLang(lang) , fVariantStyle(variantStyle) { } - virtual void onGetFontDescriptor(SkFontDescriptor* desc, - bool* serialize) const override { + virtual void onGetFontDescriptor(SkFontDescriptor* desc, bool* serialize) const override { SkASSERT(desc); SkASSERT(serialize); desc->setFamilyName(fFamilyName.c_str()); - desc->setFontIndex(fIndex); *serialize = false; } SkStreamAsset* onOpenStream(int* ttcIndex) const override { *ttcIndex = fIndex; return SkStream::NewFromFile(fPathName.c_str()); } + SkFontData* onCreateFontData() const override { + return new SkFontData(SkStream::NewFromFile(fPathName.c_str()), fIndex, + fAxes.begin(), fAxes.count()); + } const SkString fPathName; + int fIndex; + const SkSTArray<4, SkFixed, true> fAxes; const SkLanguage fLang; const FontVariant fVariantStyle; @@ -83,13 +88,13 @@ public: class SkTypeface_AndroidStream : public SkTypeface_Android { public: - SkTypeface_AndroidStream(SkStreamAsset* stream, - int index, + SkTypeface_AndroidStream(SkFontData* data, const SkFontStyle& style, bool isFixedPitch, const SkString& familyName) - : INHERITED(index, style, isFixedPitch, familyName) - , fStream(stream) { } + : INHERITED(style, isFixedPitch, familyName) + , fData(data) + { } virtual void onGetFontDescriptor(SkFontDescriptor* desc, bool* serialize) const override { @@ -100,21 +105,24 @@ public: } SkStreamAsset* onOpenStream(int* ttcIndex) const override { - *ttcIndex = fIndex; - return fStream->duplicate(); + *ttcIndex = fData->getIndex(); + return fData->duplicateStream(); } -private: - SkAutoTDelete<SkStreamAsset> fStream; + SkFontData* onCreateFontData() const override { + return new SkFontData(*fData.get()); + } +private: + const SkAutoTDelete<const SkFontData> fData; typedef SkTypeface_Android INHERITED; }; class SkFontStyleSet_Android : public SkFontStyleSet { + typedef SkTypeface_FreeType::Scanner Scanner; + public: - explicit SkFontStyleSet_Android(const FontFamily& family, - const SkTypeface_FreeType::Scanner& scanner) - { + explicit SkFontStyleSet_Android(const FontFamily& family, const Scanner& scanner) { const SkString* cannonicalFamilyName = NULL; if (family.fNames.count() > 0) { cannonicalFamilyName = &family.fNames[0]; @@ -137,7 +145,10 @@ public: SkString familyName; SkFontStyle style; bool isFixedWidth; - if (!scanner.scanFont(stream.get(), ttcIndex, &familyName, &style, &isFixedWidth)) { + Scanner::AxisDefinitions axisDefinitions; + if (!scanner.scanFont(stream.get(), ttcIndex, + &familyName, &style, &isFixedWidth, &axisDefinitions)) + { SkDEBUGF(("Requested font file %s exists, but is not a valid font.\n", pathName.c_str())); continue; @@ -166,8 +177,57 @@ public: familyName = *cannonicalFamilyName; } + SkAutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.count()); + for (int i = 0; i < axisDefinitions.count(); ++i) { + const Scanner::AxisDefinition& axisDefinition = axisDefinitions[i]; + axisValues[i] = axisDefinition.fDefault; + for (int j = 0; j < fontFile.fAxes.count(); ++j) { + const FontFileInfo::Axis& axisSpecified = fontFile.fAxes[j]; + if (axisDefinition.fTag == axisSpecified.fTag) { + axisValues[i] = SkTPin(axisSpecified.fValue, axisDefinition.fMinimum, + axisDefinition.fMaximum); + if (axisValues[i] != axisSpecified.fValue) { + SkDEBUGF(("Requested font axis value out of range: " + "%s '%c%c%c%c' %f; pinned to %f.\n", + familyName.c_str(), + (axisDefinition.fTag >> 24) & 0xFF, + (axisDefinition.fTag >> 16) & 0xFF, + (axisDefinition.fTag >> 8) & 0xFF, + (axisDefinition.fTag ) & 0xFF, + SkFixedToDouble(axisSpecified.fValue), + SkFixedToDouble(axisValues[i]))); + } + break; + } + } + // TODO: warn on defaulted axis? + } + + SkDEBUGCODE ( + // Check for axis specified, but not matched in font. + for (int i = 0; i < fontFile.fAxes.count(); ++i) { + SkFourByteTag skTag = fontFile.fAxes[i].fTag; + bool found = false; + for (int j = 0; j < axisDefinitions.count(); ++j) { + if (skTag == axisDefinitions[j].fTag) { + found = true; + break; + } + } + if (!found) { + SkDEBUGF(("Requested font axis not found: %s '%c%c%c%c'\n", + familyName.c_str(), + (skTag >> 24) & 0xFF, + (skTag >> 16) & 0xFF, + (skTag >> 8) & 0xFF, + (skTag ) & 0xFF)); + } + } + ) + fStyles.push_back().reset(SkNEW_ARGS(SkTypeface_AndroidSystem, (pathName, ttcIndex, + axisValues.get(), axisDefinitions.count(), style, isFixedWidth, familyName, lang, variant))); } @@ -411,11 +471,22 @@ protected: bool isFixedPitch; SkFontStyle style; SkString name; - if (!fScanner.scanFont(stream, ttcIndex, &name, &style, &isFixedPitch)) { + if (!fScanner.scanFont(stream, ttcIndex, &name, &style, &isFixedPitch, NULL)) { + return NULL; + } + SkFontData* data(new SkFontData(stream.detach(), ttcIndex, NULL, 0)); + return SkNEW_ARGS(SkTypeface_AndroidStream, (data, style, isFixedPitch, name)); + } + + SkTypeface* onCreateFromFontData(SkFontData* data) const override { + SkStreamAsset* stream(data->getStream()); + bool isFixedPitch; + SkFontStyle style; + SkString name; + if (!fScanner.scanFont(stream, data->getIndex(), &name, &style, &isFixedPitch, NULL)) { return NULL; } - return SkNEW_ARGS(SkTypeface_AndroidStream, (stream.detach(), ttcIndex, - style, isFixedPitch, name)); + return SkNEW_ARGS(SkTypeface_AndroidStream, (data, style, isFixedPitch, name)); } diff --git a/src/ports/SkFontMgr_fontconfig.cpp b/src/ports/SkFontMgr_fontconfig.cpp index f03e5acaf1..3baec41cb5 100644 --- a/src/ports/SkFontMgr_fontconfig.cpp +++ b/src/ports/SkFontMgr_fontconfig.cpp @@ -375,11 +375,10 @@ static void fcpattern_from_skfontstyle(SkFontStyle style, FcPattern* pattern) { class SkTypeface_stream : public SkTypeface_FreeType { public: - /** @param stream does not take ownership of the reference, does take ownership of the stream.*/ - SkTypeface_stream(const SkFontStyle& style, bool fixedWidth, int index, SkStreamAsset* stream) + /** @param data takes ownership of the font data.*/ + SkTypeface_stream(SkFontData* data, const SkFontStyle& style, bool fixedWidth) : INHERITED(style, SkTypefaceCache::NewFontID(), fixedWidth) - , fStream(stream) - , fIndex(index) + , fData(data) { }; void onGetFamilyName(SkString* familyName) const override { @@ -387,18 +386,20 @@ public: } void onGetFontDescriptor(SkFontDescriptor* desc, bool* serialize) const override { - desc->setFontIndex(fIndex); *serialize = true; } SkStreamAsset* onOpenStream(int* ttcIndex) const override { - *ttcIndex = fIndex; - return fStream->duplicate(); + *ttcIndex = fData->getIndex(); + return fData->duplicateStream(); + } + + SkFontData* onCreateFontData() const override { + return new SkFontData(*fData.get()); } private: - SkAutoTDelete<SkStreamAsset> fStream; - int fIndex; + const SkAutoTDelete<const SkFontData> fData; typedef SkTypeface_FreeType INHERITED; }; @@ -420,7 +421,6 @@ public: desc->setFamilyName(get_string(fPattern, FC_FAMILY)); desc->setFullName(get_string(fPattern, FC_FULLNAME)); desc->setPostscriptName(get_string(fPattern, FC_POSTSCRIPT_NAME)); - desc->setFontIndex(get_int(fPattern, FC_INDEX, 0)); *serialize = false; } @@ -822,12 +822,12 @@ protected: SkFontStyle style; bool isFixedWidth = false; - if (!fScanner.scanFont(stream, ttcIndex, NULL, &style, &isFixedWidth)) { + if (!fScanner.scanFont(stream, ttcIndex, NULL, &style, &isFixedWidth, NULL)) { return NULL; } - return SkNEW_ARGS(SkTypeface_stream, (style, isFixedWidth, ttcIndex, - static_cast<SkStreamAsset*>(stream.detach()))); + return SkNEW_ARGS(SkTypeface_stream, (new SkFontData(stream.detach(), ttcIndex, NULL, 0), + style, isFixedWidth)); } SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const override { @@ -838,6 +838,23 @@ protected: return this->createFromStream(SkStream::NewFromFile(path), ttcIndex); } + SkTypeface* onCreateFromFontData(SkFontData* fontData) const override { + SkStreamAsset* stream(fontData->getStream()); + const size_t length = stream->getLength(); + if (length <= 0 || (1u << 30) < length) { + return NULL; + } + + const int ttcIndex = fontData->getIndex(); + SkFontStyle style; + bool isFixedWidth = false; + if (!fScanner.scanFont(stream, ttcIndex, NULL, &style, &isFixedWidth, NULL)) { + return NULL; + } + + return SkNEW_ARGS(SkTypeface_stream, (fontData, style, isFixedWidth)); + } + virtual SkTypeface* onLegacyCreateTypeface(const char familyName[], unsigned styleBits) const override { bool bold = styleBits & SkTypeface::kBold; diff --git a/src/ports/SkTypeface_win_dw.cpp b/src/ports/SkTypeface_win_dw.cpp index cf45c16b80..25de1b6578 100644 --- a/src/ports/SkTypeface_win_dw.cpp +++ b/src/ports/SkTypeface_win_dw.cpp @@ -42,7 +42,6 @@ void DWriteFontTypeface::onGetFontDescriptor(SkFontDescriptor* desc, sk_get_locale_string(familyNames.get(), NULL/*fMgr->fLocaleName.get()*/, &utf8FamilyName); desc->setFamilyName(utf8FamilyName.c_str()); - desc->setFontIndex(fDWriteFontFace->GetIndex()); *isLocalStream = SkToBool(fDWriteFontFileLoader.get()); } |