| Index: src/ports/SkFontConfigInterface_direct.cpp
|
| diff --git a/src/ports/SkFontConfigInterface_direct.cpp b/src/ports/SkFontConfigInterface_direct.cpp
|
| deleted file mode 100644
|
| index 8a8e4a1b538dfcfa270ed40b24d9f60adb3be023..0000000000000000000000000000000000000000
|
| --- a/src/ports/SkFontConfigInterface_direct.cpp
|
| +++ /dev/null
|
| @@ -1,739 +0,0 @@
|
| -/*
|
| - * Copyright 2009 Google Inc.
|
| - *
|
| - * Use of this source code is governed by a BSD-style license that can be
|
| - * found in the LICENSE file.
|
| - */
|
| -
|
| -/* migrated from chrome/src/skia/ext/SkFontHost_fontconfig_direct.cpp */
|
| -
|
| -#include "SkBuffer.h"
|
| -#include "SkDataTable.h"
|
| -#include "SkFontConfigInterface.h"
|
| -#include "SkFontStyle.h"
|
| -#include "SkMutex.h"
|
| -#include "SkStream.h"
|
| -#include "SkString.h"
|
| -#include "SkTArray.h"
|
| -#include "SkTDArray.h"
|
| -#include "SkTemplates.h"
|
| -#include "SkTypeface.h"
|
| -#include "SkTypes.h"
|
| -
|
| -#include <fontconfig/fontconfig.h>
|
| -#include <unistd.h>
|
| -
|
| -size_t SkFontConfigInterface::FontIdentity::writeToMemory(void* addr) const {
|
| - size_t size = sizeof(fID) + sizeof(fTTCIndex);
|
| - size += sizeof(int32_t) + sizeof(int32_t) + sizeof(uint8_t); // weight, width, italic
|
| - size += sizeof(int32_t) + fString.size(); // store length+data
|
| - if (addr) {
|
| - SkWBuffer buffer(addr, size);
|
| -
|
| - buffer.write32(fID);
|
| - buffer.write32(fTTCIndex);
|
| - buffer.write32(fString.size());
|
| - buffer.write32(fStyle.weight());
|
| - buffer.write32(fStyle.width());
|
| - buffer.write8(fStyle.slant());
|
| - buffer.write(fString.c_str(), fString.size());
|
| - buffer.padToAlign4();
|
| -
|
| - SkASSERT(buffer.pos() == size);
|
| - }
|
| - return size;
|
| -}
|
| -
|
| -size_t SkFontConfigInterface::FontIdentity::readFromMemory(const void* addr,
|
| - size_t size) {
|
| - SkRBuffer buffer(addr, size);
|
| -
|
| - (void)buffer.readU32(&fID);
|
| - (void)buffer.readS32(&fTTCIndex);
|
| - uint32_t strLen, weight, width;
|
| - (void)buffer.readU32(&strLen);
|
| - (void)buffer.readU32(&weight);
|
| - (void)buffer.readU32(&width);
|
| - uint8_t u8;
|
| - (void)buffer.readU8(&u8);
|
| - SkFontStyle::Slant slant = (SkFontStyle::Slant)u8;
|
| - fStyle = SkFontStyle(weight, width, slant);
|
| - fString.resize(strLen);
|
| - (void)buffer.read(fString.writable_str(), strLen);
|
| - buffer.skipToAlign4();
|
| -
|
| - return buffer.pos(); // the actual number of bytes read
|
| -}
|
| -
|
| -#ifdef SK_DEBUG
|
| -static void make_iden(SkFontConfigInterface::FontIdentity* iden) {
|
| - iden->fID = 10;
|
| - iden->fTTCIndex = 2;
|
| - iden->fString.set("Hello world");
|
| - iden->fStyle = SkFontStyle(300, 6, SkFontStyle::kItalic_Slant);
|
| -}
|
| -
|
| -static void test_writeToMemory(const SkFontConfigInterface::FontIdentity& iden0,
|
| - int initValue) {
|
| - SkFontConfigInterface::FontIdentity iden1;
|
| -
|
| - size_t size0 = iden0.writeToMemory(nullptr);
|
| -
|
| - SkAutoMalloc storage(size0);
|
| - memset(storage.get(), initValue, size0);
|
| -
|
| - size_t size1 = iden0.writeToMemory(storage.get());
|
| - SkASSERT(size0 == size1);
|
| -
|
| - SkASSERT(iden0 != iden1);
|
| - size_t size2 = iden1.readFromMemory(storage.get(), size1);
|
| - SkASSERT(size2 == size1);
|
| - SkASSERT(iden0 == iden1);
|
| -}
|
| -
|
| -static void fontconfiginterface_unittest() {
|
| - SkFontConfigInterface::FontIdentity iden0, iden1;
|
| -
|
| - SkASSERT(iden0 == iden1);
|
| -
|
| - make_iden(&iden0);
|
| - SkASSERT(iden0 != iden1);
|
| -
|
| - make_iden(&iden1);
|
| - SkASSERT(iden0 == iden1);
|
| -
|
| - test_writeToMemory(iden0, 0);
|
| - test_writeToMemory(iden0, 0);
|
| -}
|
| -#endif
|
| -
|
| -class SkFontConfigInterfaceDirect : public SkFontConfigInterface {
|
| -public:
|
| - SkFontConfigInterfaceDirect();
|
| - virtual ~SkFontConfigInterfaceDirect();
|
| -
|
| - virtual bool matchFamilyName(const char familyName[],
|
| - SkTypeface::Style requested,
|
| - FontIdentity* outFontIdentifier,
|
| - SkString* outFamilyName,
|
| - SkTypeface::Style* outStyle) override;
|
| - SkStreamAsset* openStream(const FontIdentity&) override;
|
| -
|
| - // new APIs
|
| - SkDataTable* getFamilyNames() override;
|
| - virtual bool matchFamilySet(const char inFamilyName[],
|
| - SkString* outFamilyName,
|
| - SkTArray<FontIdentity>*) override;
|
| -
|
| -private:
|
| - SkMutex mutex_;
|
| -};
|
| -
|
| -SkFontConfigInterface* SkFontConfigInterface::GetSingletonDirectInterface(SkBaseMutex* mutex) {
|
| - SkAutoMutexAcquire ac(mutex);
|
| - static SkFontConfigInterfaceDirect* singleton = nullptr;
|
| - if (singleton == nullptr) {
|
| - singleton = new SkFontConfigInterfaceDirect;
|
| - }
|
| - return singleton;
|
| -}
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -
|
| -// Returns the string from the pattern, or nullptr
|
| -static const char* get_name(FcPattern* pattern, const char field[],
|
| - int index = 0) {
|
| - const char* name;
|
| - if (FcPatternGetString(pattern, field, index,
|
| - (FcChar8**)&name) != FcResultMatch) {
|
| - name = nullptr;
|
| - }
|
| - return name;
|
| -}
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -
|
| -namespace {
|
| -
|
| -// Equivalence classes, used to match the Liberation and other fonts
|
| -// with their metric-compatible replacements. See the discussion in
|
| -// GetFontEquivClass().
|
| -enum FontEquivClass
|
| -{
|
| - OTHER,
|
| - SANS,
|
| - SERIF,
|
| - MONO,
|
| - SYMBOL,
|
| - PGOTHIC,
|
| - GOTHIC,
|
| - PMINCHO,
|
| - MINCHO,
|
| - SIMSUN,
|
| - NSIMSUN,
|
| - SIMHEI,
|
| - PMINGLIU,
|
| - MINGLIU,
|
| - PMINGLIUHK,
|
| - MINGLIUHK,
|
| - CAMBRIA,
|
| - CALIBRI,
|
| -};
|
| -
|
| -// Match the font name against a whilelist of fonts, returning the equivalence
|
| -// class.
|
| -FontEquivClass GetFontEquivClass(const char* fontname)
|
| -{
|
| - // It would be nice for fontconfig to tell us whether a given suggested
|
| - // replacement is a "strong" match (that is, an equivalent font) or
|
| - // a "weak" match (that is, fontconfig's next-best attempt at finding a
|
| - // substitute). However, I played around with the fontconfig API for
|
| - // a good few hours and could not make it reveal this information.
|
| - //
|
| - // So instead, we hardcode. Initially this function emulated
|
| - // /etc/fonts/conf.d/30-metric-aliases.conf
|
| - // from my Ubuntu system, but we're better off being very conservative.
|
| -
|
| - // Arimo, Tinos and Cousine are a set of fonts metric-compatible with
|
| - // Arial, Times New Roman and Courier New with a character repertoire
|
| - // much larger than Liberation. Note that Cousine is metrically
|
| - // compatible with Courier New, but the former is sans-serif while
|
| - // the latter is serif.
|
| -
|
| -
|
| - struct FontEquivMap {
|
| - FontEquivClass clazz;
|
| - const char name[40];
|
| - };
|
| -
|
| - static const FontEquivMap kFontEquivMap[] = {
|
| - { SANS, "Arial" },
|
| - { SANS, "Arimo" },
|
| - { SANS, "Liberation Sans" },
|
| -
|
| - { SERIF, "Times New Roman" },
|
| - { SERIF, "Tinos" },
|
| - { SERIF, "Liberation Serif" },
|
| -
|
| - { MONO, "Courier New" },
|
| - { MONO, "Cousine" },
|
| - { MONO, "Liberation Mono" },
|
| -
|
| - { SYMBOL, "Symbol" },
|
| - { SYMBOL, "Symbol Neu" },
|
| -
|
| - // MS Pゴシック
|
| - { PGOTHIC, "MS PGothic" },
|
| - { PGOTHIC, "\xef\xbc\xad\xef\xbc\xb3 \xef\xbc\xb0"
|
| - "\xe3\x82\xb4\xe3\x82\xb7\xe3\x83\x83\xe3\x82\xaf" },
|
| - { PGOTHIC, "Noto Sans CJK JP" },
|
| - { PGOTHIC, "IPAPGothic" },
|
| - { PGOTHIC, "MotoyaG04Gothic" },
|
| -
|
| - // MS ゴシック
|
| - { GOTHIC, "MS Gothic" },
|
| - { GOTHIC, "\xef\xbc\xad\xef\xbc\xb3 "
|
| - "\xe3\x82\xb4\xe3\x82\xb7\xe3\x83\x83\xe3\x82\xaf" },
|
| - { GOTHIC, "Noto Sans Mono CJK JP" },
|
| - { GOTHIC, "IPAGothic" },
|
| - { GOTHIC, "MotoyaG04GothicMono" },
|
| -
|
| - // MS P明朝
|
| - { PMINCHO, "MS PMincho" },
|
| - { PMINCHO, "\xef\xbc\xad\xef\xbc\xb3 \xef\xbc\xb0"
|
| - "\xe6\x98\x8e\xe6\x9c\x9d"},
|
| - { PMINCHO, "IPAPMincho" },
|
| - { PMINCHO, "MotoyaG04Mincho" },
|
| -
|
| - // MS 明朝
|
| - { MINCHO, "MS Mincho" },
|
| - { MINCHO, "\xef\xbc\xad\xef\xbc\xb3 \xe6\x98\x8e\xe6\x9c\x9d" },
|
| - { MINCHO, "IPAMincho" },
|
| - { MINCHO, "MotoyaG04MinchoMono" },
|
| -
|
| - // 宋体
|
| - { SIMSUN, "Simsun" },
|
| - { SIMSUN, "\xe5\xae\x8b\xe4\xbd\x93" },
|
| - { SIMSUN, "MSung GB18030" },
|
| - { SIMSUN, "Song ASC" },
|
| -
|
| - // 新宋体
|
| - { NSIMSUN, "NSimsun" },
|
| - { NSIMSUN, "\xe6\x96\xb0\xe5\xae\x8b\xe4\xbd\x93" },
|
| - { NSIMSUN, "MSung GB18030" },
|
| - { NSIMSUN, "N Song ASC" },
|
| -
|
| - // 黑体
|
| - { SIMHEI, "Simhei" },
|
| - { SIMHEI, "\xe9\xbb\x91\xe4\xbd\x93" },
|
| - { SIMHEI, "Noto Sans CJK SC" },
|
| - { SIMHEI, "MYingHeiGB18030" },
|
| - { SIMHEI, "MYingHeiB5HK" },
|
| -
|
| - // 新細明體
|
| - { PMINGLIU, "PMingLiU"},
|
| - { PMINGLIU, "\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94" },
|
| - { PMINGLIU, "MSung B5HK"},
|
| -
|
| - // 細明體
|
| - { MINGLIU, "MingLiU"},
|
| - { MINGLIU, "\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94" },
|
| - { MINGLIU, "MSung B5HK"},
|
| -
|
| - // 新細明體
|
| - { PMINGLIUHK, "PMingLiU_HKSCS"},
|
| - { PMINGLIUHK, "\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94_HKSCS" },
|
| - { PMINGLIUHK, "MSung B5HK"},
|
| -
|
| - // 細明體
|
| - { MINGLIUHK, "MingLiU_HKSCS"},
|
| - { MINGLIUHK, "\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94_HKSCS" },
|
| - { MINGLIUHK, "MSung B5HK"},
|
| -
|
| - // Cambria
|
| - { CAMBRIA, "Cambria" },
|
| - { CAMBRIA, "Caladea" },
|
| -
|
| - // Calibri
|
| - { CALIBRI, "Calibri" },
|
| - { CALIBRI, "Carlito" },
|
| - };
|
| -
|
| - static const size_t kFontCount =
|
| - sizeof(kFontEquivMap)/sizeof(kFontEquivMap[0]);
|
| -
|
| - // TODO(jungshik): If this loop turns out to be hot, turn
|
| - // the array to a static (hash)map to speed it up.
|
| - for (size_t i = 0; i < kFontCount; ++i) {
|
| - if (strcasecmp(kFontEquivMap[i].name, fontname) == 0)
|
| - return kFontEquivMap[i].clazz;
|
| - }
|
| - return OTHER;
|
| -}
|
| -
|
| -
|
| -// Return true if |font_a| and |font_b| are visually and at the metrics
|
| -// level interchangeable.
|
| -bool IsMetricCompatibleReplacement(const char* font_a, const char* font_b)
|
| -{
|
| - FontEquivClass class_a = GetFontEquivClass(font_a);
|
| - FontEquivClass class_b = GetFontEquivClass(font_b);
|
| -
|
| - return class_a != OTHER && class_a == class_b;
|
| -}
|
| -
|
| -// Normally we only return exactly the font asked for. In last-resort
|
| -// cases, the request either doesn't specify a font or is one of the
|
| -// basic font names like "Sans", "Serif" or "Monospace". This function
|
| -// tells you whether a given request is for such a fallback.
|
| -bool IsFallbackFontAllowed(const SkString& family) {
|
| - const char* family_cstr = family.c_str();
|
| - return family.isEmpty() ||
|
| - strcasecmp(family_cstr, "sans") == 0 ||
|
| - strcasecmp(family_cstr, "serif") == 0 ||
|
| - strcasecmp(family_cstr, "monospace") == 0;
|
| -}
|
| -
|
| -static bool valid_pattern(FcPattern* pattern) {
|
| -#ifdef SK_FONT_CONFIG_ONLY_ALLOW_SCALABLE_FONTS
|
| - FcBool is_scalable;
|
| - if (FcPatternGetBool(pattern, FC_SCALABLE, 0, &is_scalable) != FcResultMatch
|
| - || !is_scalable) {
|
| - return false;
|
| - }
|
| -#endif
|
| -
|
| - // fontconfig can also return fonts which are unreadable
|
| - const char* c_filename = get_name(pattern, FC_FILE);
|
| - if (!c_filename) {
|
| - return false;
|
| - }
|
| - if (access(c_filename, R_OK) != 0) {
|
| - return false;
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -// Find matching font from |font_set| for the given font family.
|
| -FcPattern* MatchFont(FcFontSet* font_set,
|
| - const char* post_config_family,
|
| - const SkString& family) {
|
| - // Older versions of fontconfig have a bug where they cannot select
|
| - // only scalable fonts so we have to manually filter the results.
|
| - FcPattern* match = nullptr;
|
| - for (int i = 0; i < font_set->nfont; ++i) {
|
| - FcPattern* current = font_set->fonts[i];
|
| - if (valid_pattern(current)) {
|
| - match = current;
|
| - break;
|
| - }
|
| - }
|
| -
|
| - if (match && !IsFallbackFontAllowed(family)) {
|
| - bool acceptable_substitute = false;
|
| - for (int id = 0; id < 255; ++id) {
|
| - const char* post_match_family = get_name(match, FC_FAMILY, id);
|
| - if (!post_match_family)
|
| - break;
|
| - acceptable_substitute =
|
| - (strcasecmp(post_config_family, post_match_family) == 0 ||
|
| - // Workaround for Issue 12530:
|
| - // requested family: "Bitstream Vera Sans"
|
| - // post_config_family: "Arial"
|
| - // post_match_family: "Bitstream Vera Sans"
|
| - // -> We should treat this case as a good match.
|
| - strcasecmp(family.c_str(), post_match_family) == 0) ||
|
| - IsMetricCompatibleReplacement(family.c_str(), post_match_family);
|
| - if (acceptable_substitute)
|
| - break;
|
| - }
|
| - if (!acceptable_substitute)
|
| - return nullptr;
|
| - }
|
| -
|
| - return match;
|
| -}
|
| -
|
| -// Retrieves |is_bold|, |is_italic| and |font_family| properties from |font|.
|
| -SkTypeface::Style GetFontStyle(FcPattern* font) {
|
| - int resulting_bold;
|
| - if (FcPatternGetInteger(font, FC_WEIGHT, 0, &resulting_bold))
|
| - resulting_bold = FC_WEIGHT_NORMAL;
|
| -
|
| - int resulting_italic;
|
| - if (FcPatternGetInteger(font, FC_SLANT, 0, &resulting_italic))
|
| - resulting_italic = FC_SLANT_ROMAN;
|
| -
|
| - // If we ask for an italic font, fontconfig might take a roman font and set
|
| - // the undocumented property FC_MATRIX to a skew matrix. It'll then say
|
| - // that the font is italic or oblique. So, if we see a matrix, we don't
|
| - // believe that it's italic.
|
| - FcValue matrix;
|
| - const bool have_matrix = FcPatternGet(font, FC_MATRIX, 0, &matrix) == 0;
|
| -
|
| - // If we ask for an italic font, fontconfig might take a roman font and set
|
| - // FC_EMBOLDEN.
|
| - FcValue embolden;
|
| - const bool have_embolden = FcPatternGet(font, FC_EMBOLDEN, 0, &embolden) == 0;
|
| -
|
| - int styleBits = 0;
|
| - if (resulting_bold > FC_WEIGHT_MEDIUM && !have_embolden) {
|
| - styleBits |= SkTypeface::kBold;
|
| - }
|
| - if (resulting_italic > FC_SLANT_ROMAN && !have_matrix) {
|
| - styleBits |= SkTypeface::kItalic;
|
| - }
|
| -
|
| - return (SkTypeface::Style)styleBits;
|
| -}
|
| -
|
| -} // anonymous namespace
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -
|
| -#define kMaxFontFamilyLength 2048
|
| -
|
| -SkFontConfigInterfaceDirect::SkFontConfigInterfaceDirect() {
|
| - SkAutoMutexAcquire ac(mutex_);
|
| -
|
| - FcInit();
|
| -
|
| - SkDEBUGCODE(fontconfiginterface_unittest();)
|
| -}
|
| -
|
| -SkFontConfigInterfaceDirect::~SkFontConfigInterfaceDirect() {
|
| -}
|
| -
|
| -bool SkFontConfigInterfaceDirect::matchFamilyName(const char familyName[],
|
| - SkTypeface::Style style,
|
| - FontIdentity* outIdentity,
|
| - SkString* outFamilyName,
|
| - SkTypeface::Style* outStyle) {
|
| - SkString familyStr(familyName ? familyName : "");
|
| - if (familyStr.size() > kMaxFontFamilyLength) {
|
| - return false;
|
| - }
|
| -
|
| - SkAutoMutexAcquire ac(mutex_);
|
| -
|
| - FcPattern* pattern = FcPatternCreate();
|
| -
|
| - if (familyName) {
|
| - FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName);
|
| - }
|
| - FcPatternAddInteger(pattern, FC_WEIGHT,
|
| - (style & SkTypeface::kBold) ? FC_WEIGHT_BOLD
|
| - : FC_WEIGHT_NORMAL);
|
| - FcPatternAddInteger(pattern, FC_SLANT,
|
| - (style & SkTypeface::kItalic) ? FC_SLANT_ITALIC
|
| - : FC_SLANT_ROMAN);
|
| - FcPatternAddBool(pattern, FC_SCALABLE, FcTrue);
|
| -
|
| - FcConfigSubstitute(nullptr, pattern, FcMatchPattern);
|
| - FcDefaultSubstitute(pattern);
|
| -
|
| - // Font matching:
|
| - // CSS often specifies a fallback list of families:
|
| - // font-family: a, b, c, serif;
|
| - // However, fontconfig will always do its best to find *a* font when asked
|
| - // for something so we need a way to tell if the match which it has found is
|
| - // "good enough" for us. Otherwise, we can return nullptr which gets piped up
|
| - // and lets WebKit know to try the next CSS family name. However, fontconfig
|
| - // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we
|
| - // wish to support that.
|
| - //
|
| - // Thus, if a specific family is requested we set @family_requested. Then we
|
| - // record two strings: the family name after config processing and the
|
| - // family name after resolving. If the two are equal, it's a good match.
|
| - //
|
| - // So consider the case where a user has mapped Arial to Helvetica in their
|
| - // config.
|
| - // requested family: "Arial"
|
| - // post_config_family: "Helvetica"
|
| - // post_match_family: "Helvetica"
|
| - // -> good match
|
| - //
|
| - // and for a missing font:
|
| - // requested family: "Monaco"
|
| - // post_config_family: "Monaco"
|
| - // post_match_family: "Times New Roman"
|
| - // -> BAD match
|
| - //
|
| - // However, we special-case fallback fonts; see IsFallbackFontAllowed().
|
| -
|
| - const char* post_config_family = get_name(pattern, FC_FAMILY);
|
| - if (!post_config_family) {
|
| - // we can just continue with an empty name, e.g. default font
|
| - post_config_family = "";
|
| - }
|
| -
|
| - FcResult result;
|
| - FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result);
|
| - if (!font_set) {
|
| - FcPatternDestroy(pattern);
|
| - return false;
|
| - }
|
| -
|
| - FcPattern* match = MatchFont(font_set, post_config_family, familyStr);
|
| - if (!match) {
|
| - FcPatternDestroy(pattern);
|
| - FcFontSetDestroy(font_set);
|
| - return false;
|
| - }
|
| -
|
| - FcPatternDestroy(pattern);
|
| -
|
| - // From here out we just extract our results from 'match'
|
| -
|
| - post_config_family = get_name(match, FC_FAMILY);
|
| - if (!post_config_family) {
|
| - FcFontSetDestroy(font_set);
|
| - return false;
|
| - }
|
| -
|
| - const char* c_filename = get_name(match, FC_FILE);
|
| - if (!c_filename) {
|
| - FcFontSetDestroy(font_set);
|
| - return false;
|
| - }
|
| -
|
| - int face_index;
|
| - if (FcPatternGetInteger(match, FC_INDEX, 0, &face_index) != FcResultMatch) {
|
| - FcFontSetDestroy(font_set);
|
| - return false;
|
| - }
|
| -
|
| - FcFontSetDestroy(font_set);
|
| -
|
| - if (outIdentity) {
|
| - outIdentity->fTTCIndex = face_index;
|
| - outIdentity->fString.set(c_filename);
|
| - }
|
| - if (outFamilyName) {
|
| - outFamilyName->set(post_config_family);
|
| - }
|
| - if (outStyle) {
|
| - *outStyle = GetFontStyle(match);
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -SkStreamAsset* SkFontConfigInterfaceDirect::openStream(const FontIdentity& identity) {
|
| - return SkStream::NewFromFile(identity.fString.c_str());
|
| -}
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -
|
| -static bool find_name(const SkTDArray<const char*>& list, const char* str) {
|
| - int count = list.count();
|
| - for (int i = 0; i < count; ++i) {
|
| - if (!strcmp(list[i], str)) {
|
| - return true;
|
| - }
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -SkDataTable* SkFontConfigInterfaceDirect::getFamilyNames() {
|
| - SkAutoMutexAcquire ac(mutex_);
|
| -
|
| - FcPattern* pat = FcPatternCreate();
|
| - SkAutoTCallVProc<FcPattern, FcPatternDestroy> autoDestroyPat(pat);
|
| - if (nullptr == pat) {
|
| - return nullptr;
|
| - }
|
| -
|
| - FcObjectSet* os = FcObjectSetBuild(FC_FAMILY, (char *)0);
|
| - SkAutoTCallVProc<FcObjectSet, FcObjectSetDestroy> autoDestroyOs(os);
|
| - if (nullptr == os) {
|
| - return nullptr;
|
| - }
|
| -
|
| - FcFontSet* fs = FcFontList(nullptr, pat, os);
|
| - SkAutoTCallVProc<FcFontSet, FcFontSetDestroy> autoDestroyFs(fs);
|
| - if (nullptr == fs) {
|
| - return nullptr;
|
| - }
|
| -
|
| - SkTDArray<const char*> names;
|
| - SkTDArray<size_t> sizes;
|
| - for (int i = 0; i < fs->nfont; ++i) {
|
| - FcPattern* match = fs->fonts[i];
|
| - const char* famName = get_name(match, FC_FAMILY);
|
| - if (famName && !find_name(names, famName)) {
|
| - *names.append() = famName;
|
| - *sizes.append() = strlen(famName) + 1;
|
| - }
|
| - }
|
| -
|
| - return SkDataTable::NewCopyArrays((const void*const*)names.begin(),
|
| - sizes.begin(), names.count());
|
| -}
|
| -
|
| -bool SkFontConfigInterfaceDirect::matchFamilySet(const char inFamilyName[],
|
| - SkString* outFamilyName,
|
| - SkTArray<FontIdentity>* ids) {
|
| - SkAutoMutexAcquire ac(mutex_);
|
| -
|
| -#if 0
|
| - SkString familyStr(familyName ? familyName : "");
|
| - if (familyStr.size() > kMaxFontFamilyLength) {
|
| - return false;
|
| - }
|
| -
|
| - SkAutoMutexAcquire ac(mutex_);
|
| -
|
| - FcPattern* pattern = FcPatternCreate();
|
| -
|
| - if (familyName) {
|
| - FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName);
|
| - }
|
| - FcPatternAddBool(pattern, FC_SCALABLE, FcTrue);
|
| -
|
| - FcConfigSubstitute(nullptr, pattern, FcMatchPattern);
|
| - FcDefaultSubstitute(pattern);
|
| -
|
| - // Font matching:
|
| - // CSS often specifies a fallback list of families:
|
| - // font-family: a, b, c, serif;
|
| - // However, fontconfig will always do its best to find *a* font when asked
|
| - // for something so we need a way to tell if the match which it has found is
|
| - // "good enough" for us. Otherwise, we can return nullptr which gets piped up
|
| - // and lets WebKit know to try the next CSS family name. However, fontconfig
|
| - // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we
|
| - // wish to support that.
|
| - //
|
| - // Thus, if a specific family is requested we set @family_requested. Then we
|
| - // record two strings: the family name after config processing and the
|
| - // family name after resolving. If the two are equal, it's a good match.
|
| - //
|
| - // So consider the case where a user has mapped Arial to Helvetica in their
|
| - // config.
|
| - // requested family: "Arial"
|
| - // post_config_family: "Helvetica"
|
| - // post_match_family: "Helvetica"
|
| - // -> good match
|
| - //
|
| - // and for a missing font:
|
| - // requested family: "Monaco"
|
| - // post_config_family: "Monaco"
|
| - // post_match_family: "Times New Roman"
|
| - // -> BAD match
|
| - //
|
| - // However, we special-case fallback fonts; see IsFallbackFontAllowed().
|
| -
|
| - const char* post_config_family = get_name(pattern, FC_FAMILY);
|
| -
|
| - FcResult result;
|
| - FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result);
|
| - if (!font_set) {
|
| - FcPatternDestroy(pattern);
|
| - return false;
|
| - }
|
| -
|
| - FcPattern* match = MatchFont(font_set, post_config_family, familyStr);
|
| - if (!match) {
|
| - FcPatternDestroy(pattern);
|
| - FcFontSetDestroy(font_set);
|
| - return false;
|
| - }
|
| -
|
| - FcPatternDestroy(pattern);
|
| -
|
| - // From here out we just extract our results from 'match'
|
| -
|
| - if (FcPatternGetString(match, FC_FAMILY, 0, &post_config_family) != FcResultMatch) {
|
| - FcFontSetDestroy(font_set);
|
| - return false;
|
| - }
|
| -
|
| - FcChar8* c_filename;
|
| - if (FcPatternGetString(match, FC_FILE, 0, &c_filename) != FcResultMatch) {
|
| - FcFontSetDestroy(font_set);
|
| - return false;
|
| - }
|
| -
|
| - int face_index;
|
| - if (FcPatternGetInteger(match, FC_INDEX, 0, &face_index) != FcResultMatch) {
|
| - FcFontSetDestroy(font_set);
|
| - return false;
|
| - }
|
| -
|
| - FcFontSetDestroy(font_set);
|
| -
|
| - if (outIdentity) {
|
| - outIdentity->fTTCIndex = face_index;
|
| - outIdentity->fString.set((const char*)c_filename);
|
| - }
|
| - if (outFamilyName) {
|
| - outFamilyName->set((const char*)post_config_family);
|
| - }
|
| - if (outStyle) {
|
| - *outStyle = GetFontStyle(match);
|
| - }
|
| - return true;
|
| -
|
| -////////////////////
|
| -
|
| - int count;
|
| - FcPattern** match = MatchFont(font_set, post_config_family, &count);
|
| - if (!match) {
|
| - FcPatternDestroy(pattern);
|
| - FcFontSetDestroy(font_set);
|
| - return nullptr;
|
| - }
|
| -
|
| - FcPatternDestroy(pattern);
|
| -
|
| - SkTDArray<FcPattern*> trimmedMatches;
|
| - for (int i = 0; i < count; ++i) {
|
| - const char* justName = find_just_name(get_name(match[i], FC_FILE));
|
| - if (!is_lower(*justName)) {
|
| - *trimmedMatches.append() = match[i];
|
| - }
|
| - }
|
| -
|
| - SkFontStyleSet_FC* sset = new SkFontStyleSet_FC (trimmedMatches.begin(), trimmedMatches.count());
|
| -#endif
|
| - return false;
|
| -}
|
|
|