gfx/skia/trunk/src/ports/SkFontConfigInterface_direct.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/ports/SkFontConfigInterface_direct.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,736 @@
     1.4 +/*
     1.5 + * Copyright 2009 Google Inc.
     1.6 + *
     1.7 + * Use of this source code is governed by a BSD-style license that can be
     1.8 + * found in the LICENSE file.
     1.9 + */
    1.10 +
    1.11 +/* migrated from chrome/src/skia/ext/SkFontHost_fontconfig_direct.cpp */
    1.12 +
    1.13 +#include <string>
    1.14 +#include <unistd.h>
    1.15 +#include <fcntl.h>
    1.16 +
    1.17 +#include <fontconfig/fontconfig.h>
    1.18 +
    1.19 +#include "SkBuffer.h"
    1.20 +#include "SkFontConfigInterface.h"
    1.21 +#include "SkStream.h"
    1.22 +
    1.23 +size_t SkFontConfigInterface::FontIdentity::writeToMemory(void* addr) const {
    1.24 +    size_t size = sizeof(fID) + sizeof(fTTCIndex);
    1.25 +    size += sizeof(int32_t) + sizeof(int32_t) + sizeof(uint8_t); // weight, width, italic
    1.26 +    size += sizeof(int32_t) + fString.size();    // store length+data
    1.27 +    if (addr) {
    1.28 +        SkWBuffer buffer(addr, size);
    1.29 +
    1.30 +        buffer.write32(fID);
    1.31 +        buffer.write32(fTTCIndex);
    1.32 +        buffer.write32(fString.size());
    1.33 +        buffer.write32(fStyle.weight());
    1.34 +        buffer.write32(fStyle.width());
    1.35 +        buffer.write8(fStyle.slant());
    1.36 +        buffer.write(fString.c_str(), fString.size());
    1.37 +        buffer.padToAlign4();
    1.38 +
    1.39 +        SkASSERT(buffer.pos() == size);
    1.40 +    }
    1.41 +    return size;
    1.42 +}
    1.43 +
    1.44 +size_t SkFontConfigInterface::FontIdentity::readFromMemory(const void* addr,
    1.45 +                                                           size_t size) {
    1.46 +    SkRBuffer buffer(addr, size);
    1.47 +
    1.48 +    (void)buffer.readU32(&fID);
    1.49 +    (void)buffer.readS32(&fTTCIndex);
    1.50 +    uint32_t strLen, weight, width;
    1.51 +    (void)buffer.readU32(&strLen);
    1.52 +    (void)buffer.readU32(&weight);
    1.53 +    (void)buffer.readU32(&width);
    1.54 +    uint8_t u8;
    1.55 +    (void)buffer.readU8(&u8);
    1.56 +    SkFontStyle::Slant slant = (SkFontStyle::Slant)u8;
    1.57 +    fStyle = SkFontStyle(weight, width, slant);
    1.58 +    fString.resize(strLen);
    1.59 +    (void)buffer.read(fString.writable_str(), strLen);
    1.60 +    buffer.skipToAlign4();
    1.61 +
    1.62 +    return buffer.pos();    // the actual number of bytes read
    1.63 +}
    1.64 +
    1.65 +#ifdef SK_DEBUG
    1.66 +static void make_iden(SkFontConfigInterface::FontIdentity* iden) {
    1.67 +    iden->fID = 10;
    1.68 +    iden->fTTCIndex = 2;
    1.69 +    iden->fString.set("Hello world");
    1.70 +    iden->fStyle = SkFontStyle(300, 6, SkFontStyle::kItalic_Slant);
    1.71 +}
    1.72 +
    1.73 +static void test_writeToMemory(const SkFontConfigInterface::FontIdentity& iden0,
    1.74 +                               int initValue) {
    1.75 +    SkFontConfigInterface::FontIdentity iden1;
    1.76 +
    1.77 +    size_t size0 = iden0.writeToMemory(NULL);
    1.78 +
    1.79 +    SkAutoMalloc storage(size0);
    1.80 +    memset(storage.get(), initValue, size0);
    1.81 +
    1.82 +    size_t size1 = iden0.writeToMemory(storage.get());
    1.83 +    SkASSERT(size0 == size1);
    1.84 +
    1.85 +    SkASSERT(iden0 != iden1);
    1.86 +    size_t size2 = iden1.readFromMemory(storage.get(), size1);
    1.87 +    SkASSERT(size2 == size1);
    1.88 +    SkASSERT(iden0 == iden1);
    1.89 +}
    1.90 +
    1.91 +static void fontconfiginterface_unittest() {
    1.92 +    SkFontConfigInterface::FontIdentity iden0, iden1;
    1.93 +
    1.94 +    SkASSERT(iden0 == iden1);
    1.95 +
    1.96 +    make_iden(&iden0);
    1.97 +    SkASSERT(iden0 != iden1);
    1.98 +
    1.99 +    make_iden(&iden1);
   1.100 +    SkASSERT(iden0 == iden1);
   1.101 +
   1.102 +    test_writeToMemory(iden0, 0);
   1.103 +    test_writeToMemory(iden0, 0);
   1.104 +}
   1.105 +#endif
   1.106 +
   1.107 +class SkFontConfigInterfaceDirect : public SkFontConfigInterface {
   1.108 +public:
   1.109 +            SkFontConfigInterfaceDirect();
   1.110 +    virtual ~SkFontConfigInterfaceDirect();
   1.111 +
   1.112 +    virtual bool matchFamilyName(const char familyName[],
   1.113 +                                 SkTypeface::Style requested,
   1.114 +                                 FontIdentity* outFontIdentifier,
   1.115 +                                 SkString* outFamilyName,
   1.116 +                                 SkTypeface::Style* outStyle) SK_OVERRIDE;
   1.117 +    virtual SkStream* openStream(const FontIdentity&) SK_OVERRIDE;
   1.118 +
   1.119 +    // new APIs
   1.120 +    virtual SkDataTable* getFamilyNames() SK_OVERRIDE;
   1.121 +    virtual bool matchFamilySet(const char inFamilyName[],
   1.122 +                                SkString* outFamilyName,
   1.123 +                                SkTArray<FontIdentity>*) SK_OVERRIDE;
   1.124 +
   1.125 +private:
   1.126 +    SkMutex mutex_;
   1.127 +};
   1.128 +
   1.129 +SkFontConfigInterface* SkFontConfigInterface::GetSingletonDirectInterface() {
   1.130 +    static SkFontConfigInterface* gDirect;
   1.131 +    if (NULL == gDirect) {
   1.132 +        static SkMutex gMutex;
   1.133 +        SkAutoMutexAcquire ac(gMutex);
   1.134 +
   1.135 +        if (NULL == gDirect) {
   1.136 +            gDirect = new SkFontConfigInterfaceDirect;
   1.137 +        }
   1.138 +    }
   1.139 +    return gDirect;
   1.140 +}
   1.141 +
   1.142 +///////////////////////////////////////////////////////////////////////////////
   1.143 +
   1.144 +// Returns the string from the pattern, or NULL
   1.145 +static const char* get_name(FcPattern* pattern, const char field[],
   1.146 +                            int index = 0) {
   1.147 +    const char* name;
   1.148 +    if (FcPatternGetString(pattern, field, index,
   1.149 +                           (FcChar8**)&name) != FcResultMatch) {
   1.150 +        name = NULL;
   1.151 +    }
   1.152 +    return name;
   1.153 +}
   1.154 +
   1.155 +///////////////////////////////////////////////////////////////////////////////
   1.156 +
   1.157 +namespace {
   1.158 +
   1.159 +// Equivalence classes, used to match the Liberation and other fonts
   1.160 +// with their metric-compatible replacements.  See the discussion in
   1.161 +// GetFontEquivClass().
   1.162 +enum FontEquivClass
   1.163 +{
   1.164 +    OTHER,
   1.165 +    SANS,
   1.166 +    SERIF,
   1.167 +    MONO,
   1.168 +    SYMBOL,
   1.169 +    PGOTHIC,
   1.170 +    GOTHIC,
   1.171 +    PMINCHO,
   1.172 +    MINCHO,
   1.173 +    SIMSUN,
   1.174 +    NSIMSUN,
   1.175 +    SIMHEI,
   1.176 +    PMINGLIU,
   1.177 +    MINGLIU,
   1.178 +    PMINGLIUHK,
   1.179 +    MINGLIUHK,
   1.180 +    CAMBRIA,
   1.181 +    CALIBRI,
   1.182 +};
   1.183 +
   1.184 +// Match the font name against a whilelist of fonts, returning the equivalence
   1.185 +// class.
   1.186 +FontEquivClass GetFontEquivClass(const char* fontname)
   1.187 +{
   1.188 +    // It would be nice for fontconfig to tell us whether a given suggested
   1.189 +    // replacement is a "strong" match (that is, an equivalent font) or
   1.190 +    // a "weak" match (that is, fontconfig's next-best attempt at finding a
   1.191 +    // substitute).  However, I played around with the fontconfig API for
   1.192 +    // a good few hours and could not make it reveal this information.
   1.193 +    //
   1.194 +    // So instead, we hardcode.  Initially this function emulated
   1.195 +    //   /etc/fonts/conf.d/30-metric-aliases.conf
   1.196 +    // from my Ubuntu system, but we're better off being very conservative.
   1.197 +
   1.198 +    // Arimo, Tinos and Cousine are a set of fonts metric-compatible with
   1.199 +    // Arial, Times New Roman and Courier New  with a character repertoire
   1.200 +    // much larger than Liberation. Note that Cousine is metrically
   1.201 +    // compatible with Courier New, but the former is sans-serif while
   1.202 +    // the latter is serif.
   1.203 +
   1.204 +
   1.205 +    struct FontEquivMap {
   1.206 +        FontEquivClass clazz;
   1.207 +        const char name[40];
   1.208 +    };
   1.209 +
   1.210 +    static const FontEquivMap kFontEquivMap[] = {
   1.211 +        { SANS, "Arial" },
   1.212 +        { SANS, "Arimo" },
   1.213 +        { SANS, "Liberation Sans" },
   1.214 +
   1.215 +        { SERIF, "Times New Roman" },
   1.216 +        { SERIF, "Tinos" },
   1.217 +        { SERIF, "Liberation Serif" },
   1.218 +
   1.219 +        { MONO, "Courier New" },
   1.220 +        { MONO, "Cousine" },
   1.221 +        { MONO, "Liberation Mono" },
   1.222 +
   1.223 +        { SYMBOL, "Symbol" },
   1.224 +        { SYMBOL, "Symbol Neu" },
   1.225 +
   1.226 +        // MS Pゴシック
   1.227 +        { PGOTHIC, "MS PGothic" },
   1.228 +        { PGOTHIC, "\xef\xbc\xad\xef\xbc\xb3 \xef\xbc\xb0"
   1.229 +                   "\xe3\x82\xb4\xe3\x82\xb7\xe3\x83\x83\xe3\x82\xaf" },
   1.230 +        { PGOTHIC, "IPAPGothic" },
   1.231 +        { PGOTHIC, "MotoyaG04Gothic" },
   1.232 +
   1.233 +        // MS ゴシック
   1.234 +        { GOTHIC, "MS Gothic" },
   1.235 +        { GOTHIC, "\xef\xbc\xad\xef\xbc\xb3 "
   1.236 +                  "\xe3\x82\xb4\xe3\x82\xb7\xe3\x83\x83\xe3\x82\xaf" },
   1.237 +        { GOTHIC, "IPAGothic" },
   1.238 +        { GOTHIC, "MotoyaG04GothicMono" },
   1.239 +
   1.240 +        // MS P明朝
   1.241 +        { PMINCHO, "MS PMincho" },
   1.242 +        { PMINCHO, "\xef\xbc\xad\xef\xbc\xb3 \xef\xbc\xb0"
   1.243 +                   "\xe6\x98\x8e\xe6\x9c\x9d"},
   1.244 +        { PMINCHO, "IPAPMincho" },
   1.245 +        { PMINCHO, "MotoyaG04Mincho" },
   1.246 +
   1.247 +        // MS 明朝
   1.248 +        { MINCHO, "MS Mincho" },
   1.249 +        { MINCHO, "\xef\xbc\xad\xef\xbc\xb3 \xe6\x98\x8e\xe6\x9c\x9d" },
   1.250 +        { MINCHO, "IPAMincho" },
   1.251 +        { MINCHO, "MotoyaG04MinchoMono" },
   1.252 +
   1.253 +        // 宋体
   1.254 +        { SIMSUN, "Simsun" },
   1.255 +        { SIMSUN, "\xe5\xae\x8b\xe4\xbd\x93" },
   1.256 +        { SIMSUN, "MSung GB18030" },
   1.257 +        { SIMSUN, "Song ASC" },
   1.258 +
   1.259 +        // 新宋体
   1.260 +        { NSIMSUN, "NSimsun" },
   1.261 +        { NSIMSUN, "\xe6\x96\xb0\xe5\xae\x8b\xe4\xbd\x93" },
   1.262 +        { NSIMSUN, "MSung GB18030" },
   1.263 +        { NSIMSUN, "N Song ASC" },
   1.264 +
   1.265 +        // 黑体
   1.266 +        { SIMHEI, "Simhei" },
   1.267 +        { SIMHEI, "\xe9\xbb\x91\xe4\xbd\x93" },
   1.268 +        { SIMHEI, "MYingHeiGB18030" },
   1.269 +        { SIMHEI, "MYingHeiB5HK" },
   1.270 +
   1.271 +        // 新細明體
   1.272 +        { PMINGLIU, "PMingLiU"},
   1.273 +        { PMINGLIU, "\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94" },
   1.274 +        { PMINGLIU, "MSung B5HK"},
   1.275 +
   1.276 +        // 細明體
   1.277 +        { MINGLIU, "MingLiU"},
   1.278 +        { MINGLIU, "\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94" },
   1.279 +        { MINGLIU, "MSung B5HK"},
   1.280 +
   1.281 +        // 新細明體
   1.282 +        { PMINGLIUHK, "PMingLiU_HKSCS"},
   1.283 +        { PMINGLIUHK, "\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94_HKSCS" },
   1.284 +        { PMINGLIUHK, "MSung B5HK"},
   1.285 +
   1.286 +        // 細明體
   1.287 +        { MINGLIUHK, "MingLiU_HKSCS"},
   1.288 +        { MINGLIUHK, "\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94_HKSCS" },
   1.289 +        { MINGLIUHK, "MSung B5HK"},
   1.290 +
   1.291 +        // Cambria
   1.292 +        { CAMBRIA, "Cambria" },
   1.293 +        { CAMBRIA, "Caladea" },
   1.294 +
   1.295 +        // Calibri
   1.296 +        { CALIBRI, "Calibri" },
   1.297 +        { CALIBRI, "Carlito" },
   1.298 +    };
   1.299 +
   1.300 +    static const size_t kFontCount =
   1.301 +        sizeof(kFontEquivMap)/sizeof(kFontEquivMap[0]);
   1.302 +
   1.303 +    // TODO(jungshik): If this loop turns out to be hot, turn
   1.304 +    // the array to a static (hash)map to speed it up.
   1.305 +    for (size_t i = 0; i < kFontCount; ++i) {
   1.306 +        if (strcasecmp(kFontEquivMap[i].name, fontname) == 0)
   1.307 +            return kFontEquivMap[i].clazz;
   1.308 +    }
   1.309 +    return OTHER;
   1.310 +}
   1.311 +
   1.312 +
   1.313 +// Return true if |font_a| and |font_b| are visually and at the metrics
   1.314 +// level interchangeable.
   1.315 +bool IsMetricCompatibleReplacement(const char* font_a, const char* font_b)
   1.316 +{
   1.317 +    FontEquivClass class_a = GetFontEquivClass(font_a);
   1.318 +    FontEquivClass class_b = GetFontEquivClass(font_b);
   1.319 +
   1.320 +    return class_a != OTHER && class_a == class_b;
   1.321 +}
   1.322 +
   1.323 +// Normally we only return exactly the font asked for. In last-resort
   1.324 +// cases, the request either doesn't specify a font or is one of the
   1.325 +// basic font names like "Sans", "Serif" or "Monospace". This function
   1.326 +// tells you whether a given request is for such a fallback.
   1.327 +bool IsFallbackFontAllowed(const std::string& family) {
   1.328 +  const char* family_cstr = family.c_str();
   1.329 +  return family.empty() ||
   1.330 +         strcasecmp(family_cstr, "sans") == 0 ||
   1.331 +         strcasecmp(family_cstr, "serif") == 0 ||
   1.332 +         strcasecmp(family_cstr, "monospace") == 0;
   1.333 +}
   1.334 +
   1.335 +static bool valid_pattern(FcPattern* pattern) {
   1.336 +#ifdef SK_FONT_CONFIG_ONLY_ALLOW_SCALABLE_FONTS
   1.337 +    FcBool is_scalable;
   1.338 +    if (FcPatternGetBool(pattern, FC_SCALABLE, 0, &is_scalable) != FcResultMatch
   1.339 +        || !is_scalable) {
   1.340 +        return false;
   1.341 +    }
   1.342 +#endif
   1.343 +
   1.344 +    // fontconfig can also return fonts which are unreadable
   1.345 +    const char* c_filename = get_name(pattern, FC_FILE);
   1.346 +    if (!c_filename) {
   1.347 +        return false;
   1.348 +    }
   1.349 +    if (access(c_filename, R_OK) != 0) {
   1.350 +        return false;
   1.351 +    }
   1.352 +    return true;
   1.353 +}
   1.354 +
   1.355 +// Find matching font from |font_set| for the given font family.
   1.356 +FcPattern* MatchFont(FcFontSet* font_set,
   1.357 +                     const char* post_config_family,
   1.358 +                     const std::string& family) {
   1.359 +  // Older versions of fontconfig have a bug where they cannot select
   1.360 +  // only scalable fonts so we have to manually filter the results.
   1.361 +  FcPattern* match = NULL;
   1.362 +  for (int i = 0; i < font_set->nfont; ++i) {
   1.363 +    FcPattern* current = font_set->fonts[i];
   1.364 +    if (valid_pattern(current)) {
   1.365 +      match = current;
   1.366 +      break;
   1.367 +    }
   1.368 +  }
   1.369 +
   1.370 +  if (match && !IsFallbackFontAllowed(family)) {
   1.371 +    bool acceptable_substitute = false;
   1.372 +    for (int id = 0; id < 255; ++id) {
   1.373 +      const char* post_match_family = get_name(match, FC_FAMILY, id);
   1.374 +      if (!post_match_family)
   1.375 +        break;
   1.376 +      acceptable_substitute =
   1.377 +          (strcasecmp(post_config_family, post_match_family) == 0 ||
   1.378 +           // Workaround for Issue 12530:
   1.379 +           //   requested family: "Bitstream Vera Sans"
   1.380 +           //   post_config_family: "Arial"
   1.381 +           //   post_match_family: "Bitstream Vera Sans"
   1.382 +           // -> We should treat this case as a good match.
   1.383 +           strcasecmp(family.c_str(), post_match_family) == 0) ||
   1.384 +           IsMetricCompatibleReplacement(family.c_str(), post_match_family);
   1.385 +      if (acceptable_substitute)
   1.386 +        break;
   1.387 +    }
   1.388 +    if (!acceptable_substitute)
   1.389 +      return NULL;
   1.390 +  }
   1.391 +
   1.392 +  return match;
   1.393 +}
   1.394 +
   1.395 +// Retrieves |is_bold|, |is_italic| and |font_family| properties from |font|.
   1.396 +SkTypeface::Style GetFontStyle(FcPattern* font) {
   1.397 +    int resulting_bold;
   1.398 +    if (FcPatternGetInteger(font, FC_WEIGHT, 0, &resulting_bold))
   1.399 +        resulting_bold = FC_WEIGHT_NORMAL;
   1.400 +
   1.401 +    int resulting_italic;
   1.402 +    if (FcPatternGetInteger(font, FC_SLANT, 0, &resulting_italic))
   1.403 +        resulting_italic = FC_SLANT_ROMAN;
   1.404 +
   1.405 +    // If we ask for an italic font, fontconfig might take a roman font and set
   1.406 +    // the undocumented property FC_MATRIX to a skew matrix. It'll then say
   1.407 +    // that the font is italic or oblique. So, if we see a matrix, we don't
   1.408 +    // believe that it's italic.
   1.409 +    FcValue matrix;
   1.410 +    const bool have_matrix = FcPatternGet(font, FC_MATRIX, 0, &matrix) == 0;
   1.411 +
   1.412 +    // If we ask for an italic font, fontconfig might take a roman font and set
   1.413 +    // FC_EMBOLDEN.
   1.414 +    FcValue embolden;
   1.415 +    const bool have_embolden = FcPatternGet(font, FC_EMBOLDEN, 0, &embolden) == 0;
   1.416 +
   1.417 +    int styleBits = 0;
   1.418 +    if (resulting_bold > FC_WEIGHT_MEDIUM && !have_embolden) {
   1.419 +        styleBits |= SkTypeface::kBold;
   1.420 +    }
   1.421 +    if (resulting_italic > FC_SLANT_ROMAN && !have_matrix) {
   1.422 +        styleBits |= SkTypeface::kItalic;
   1.423 +    }
   1.424 +
   1.425 +    return (SkTypeface::Style)styleBits;
   1.426 +}
   1.427 +
   1.428 +}  // anonymous namespace
   1.429 +
   1.430 +///////////////////////////////////////////////////////////////////////////////
   1.431 +
   1.432 +#define kMaxFontFamilyLength    2048
   1.433 +
   1.434 +SkFontConfigInterfaceDirect::SkFontConfigInterfaceDirect() {
   1.435 +    SkAutoMutexAcquire ac(mutex_);
   1.436 +
   1.437 +    FcInit();
   1.438 +
   1.439 +    SkDEBUGCODE(fontconfiginterface_unittest();)
   1.440 +}
   1.441 +
   1.442 +SkFontConfigInterfaceDirect::~SkFontConfigInterfaceDirect() {
   1.443 +}
   1.444 +
   1.445 +bool SkFontConfigInterfaceDirect::matchFamilyName(const char familyName[],
   1.446 +                                                  SkTypeface::Style style,
   1.447 +                                                  FontIdentity* outIdentity,
   1.448 +                                                  SkString* outFamilyName,
   1.449 +                                                  SkTypeface::Style* outStyle) {
   1.450 +    std::string familyStr(familyName ? familyName : "");
   1.451 +    if (familyStr.length() > kMaxFontFamilyLength) {
   1.452 +        return false;
   1.453 +    }
   1.454 +
   1.455 +    SkAutoMutexAcquire ac(mutex_);
   1.456 +
   1.457 +    FcPattern* pattern = FcPatternCreate();
   1.458 +
   1.459 +    if (familyName) {
   1.460 +        FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName);
   1.461 +    }
   1.462 +    FcPatternAddInteger(pattern, FC_WEIGHT,
   1.463 +                        (style & SkTypeface::kBold) ? FC_WEIGHT_BOLD
   1.464 +                                                    : FC_WEIGHT_NORMAL);
   1.465 +    FcPatternAddInteger(pattern, FC_SLANT,
   1.466 +                        (style & SkTypeface::kItalic) ? FC_SLANT_ITALIC
   1.467 +                                                      : FC_SLANT_ROMAN);
   1.468 +    FcPatternAddBool(pattern, FC_SCALABLE, FcTrue);
   1.469 +
   1.470 +    FcConfigSubstitute(NULL, pattern, FcMatchPattern);
   1.471 +    FcDefaultSubstitute(pattern);
   1.472 +
   1.473 +    // Font matching:
   1.474 +    // CSS often specifies a fallback list of families:
   1.475 +    //    font-family: a, b, c, serif;
   1.476 +    // However, fontconfig will always do its best to find *a* font when asked
   1.477 +    // for something so we need a way to tell if the match which it has found is
   1.478 +    // "good enough" for us. Otherwise, we can return NULL which gets piped up
   1.479 +    // and lets WebKit know to try the next CSS family name. However, fontconfig
   1.480 +    // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we
   1.481 +    // wish to support that.
   1.482 +    //
   1.483 +    // Thus, if a specific family is requested we set @family_requested. Then we
   1.484 +    // record two strings: the family name after config processing and the
   1.485 +    // family name after resolving. If the two are equal, it's a good match.
   1.486 +    //
   1.487 +    // So consider the case where a user has mapped Arial to Helvetica in their
   1.488 +    // config.
   1.489 +    //    requested family: "Arial"
   1.490 +    //    post_config_family: "Helvetica"
   1.491 +    //    post_match_family: "Helvetica"
   1.492 +    //      -> good match
   1.493 +    //
   1.494 +    // and for a missing font:
   1.495 +    //    requested family: "Monaco"
   1.496 +    //    post_config_family: "Monaco"
   1.497 +    //    post_match_family: "Times New Roman"
   1.498 +    //      -> BAD match
   1.499 +    //
   1.500 +    // However, we special-case fallback fonts; see IsFallbackFontAllowed().
   1.501 +
   1.502 +    const char* post_config_family = get_name(pattern, FC_FAMILY);
   1.503 +    if (!post_config_family) {
   1.504 +        // we can just continue with an empty name, e.g. default font
   1.505 +        post_config_family = "";
   1.506 +    }
   1.507 +
   1.508 +    FcResult result;
   1.509 +    FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result);
   1.510 +    if (!font_set) {
   1.511 +        FcPatternDestroy(pattern);
   1.512 +        return false;
   1.513 +    }
   1.514 +
   1.515 +    FcPattern* match = MatchFont(font_set, post_config_family, familyStr);
   1.516 +    if (!match) {
   1.517 +        FcPatternDestroy(pattern);
   1.518 +        FcFontSetDestroy(font_set);
   1.519 +        return false;
   1.520 +    }
   1.521 +
   1.522 +    FcPatternDestroy(pattern);
   1.523 +
   1.524 +    // From here out we just extract our results from 'match'
   1.525 +
   1.526 +    post_config_family = get_name(match, FC_FAMILY);
   1.527 +    if (!post_config_family) {
   1.528 +        FcFontSetDestroy(font_set);
   1.529 +        return false;
   1.530 +    }
   1.531 +
   1.532 +    const char* c_filename = get_name(match, FC_FILE);
   1.533 +    if (!c_filename) {
   1.534 +        FcFontSetDestroy(font_set);
   1.535 +        return false;
   1.536 +    }
   1.537 +
   1.538 +    int face_index;
   1.539 +    if (FcPatternGetInteger(match, FC_INDEX, 0, &face_index) != FcResultMatch) {
   1.540 +        FcFontSetDestroy(font_set);
   1.541 +        return false;
   1.542 +    }
   1.543 +
   1.544 +    FcFontSetDestroy(font_set);
   1.545 +
   1.546 +    if (outIdentity) {
   1.547 +        outIdentity->fTTCIndex = face_index;
   1.548 +        outIdentity->fString.set(c_filename);
   1.549 +    }
   1.550 +    if (outFamilyName) {
   1.551 +        outFamilyName->set(post_config_family);
   1.552 +    }
   1.553 +    if (outStyle) {
   1.554 +        *outStyle = GetFontStyle(match);
   1.555 +    }
   1.556 +    return true;
   1.557 +}
   1.558 +
   1.559 +SkStream* SkFontConfigInterfaceDirect::openStream(const FontIdentity& identity) {
   1.560 +    return SkStream::NewFromFile(identity.fString.c_str());
   1.561 +}
   1.562 +
   1.563 +///////////////////////////////////////////////////////////////////////////////
   1.564 +
   1.565 +static bool find_name(const SkTDArray<const char*>& list, const char* str) {
   1.566 +    int count = list.count();
   1.567 +    for (int i = 0; i < count; ++i) {
   1.568 +        if (!strcmp(list[i], str)) {
   1.569 +            return true;
   1.570 +        }
   1.571 +    }
   1.572 +    return false;
   1.573 +}
   1.574 +
   1.575 +SkDataTable* SkFontConfigInterfaceDirect::getFamilyNames() {
   1.576 +    SkAutoMutexAcquire ac(mutex_);
   1.577 +
   1.578 +    FcPattern* pat = FcPatternCreate();
   1.579 +    SkAutoTCallVProc<FcPattern, FcPatternDestroy> autoDestroyPat(pat);
   1.580 +    if (NULL == pat) {
   1.581 +        return NULL;
   1.582 +    }
   1.583 +
   1.584 +    FcObjectSet* os = FcObjectSetBuild(FC_FAMILY, (char *)0);
   1.585 +    SkAutoTCallVProc<FcObjectSet, FcObjectSetDestroy> autoDestroyOs(os);
   1.586 +    if (NULL == os) {
   1.587 +        return NULL;
   1.588 +    }
   1.589 +
   1.590 +    FcFontSet* fs = FcFontList(NULL, pat, os);
   1.591 +    SkAutoTCallVProc<FcFontSet, FcFontSetDestroy> autoDestroyFs(fs);
   1.592 +    if (NULL == fs) {
   1.593 +        return NULL;
   1.594 +    }
   1.595 +
   1.596 +    SkTDArray<const char*> names;
   1.597 +    SkTDArray<size_t> sizes;
   1.598 +    for (int i = 0; i < fs->nfont; ++i) {
   1.599 +        FcPattern* match = fs->fonts[i];
   1.600 +        const char* famName = get_name(match, FC_FAMILY);
   1.601 +        if (famName && !find_name(names, famName)) {
   1.602 +            *names.append() = famName;
   1.603 +            *sizes.append() = strlen(famName) + 1;
   1.604 +        }
   1.605 +    }
   1.606 +
   1.607 +    return SkDataTable::NewCopyArrays((const void*const*)names.begin(),
   1.608 +                                      sizes.begin(), names.count());
   1.609 +}
   1.610 +
   1.611 +bool SkFontConfigInterfaceDirect::matchFamilySet(const char inFamilyName[],
   1.612 +                                                 SkString* outFamilyName,
   1.613 +                                                 SkTArray<FontIdentity>* ids) {
   1.614 +    SkAutoMutexAcquire ac(mutex_);
   1.615 +
   1.616 +#if 0
   1.617 +    std::string familyStr(familyName ? familyName : "");
   1.618 +    if (familyStr.length() > kMaxFontFamilyLength) {
   1.619 +        return false;
   1.620 +    }
   1.621 +
   1.622 +    SkAutoMutexAcquire ac(mutex_);
   1.623 +
   1.624 +    FcPattern* pattern = FcPatternCreate();
   1.625 +
   1.626 +    if (familyName) {
   1.627 +        FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName);
   1.628 +    }
   1.629 +    FcPatternAddBool(pattern, FC_SCALABLE, FcTrue);
   1.630 +
   1.631 +    FcConfigSubstitute(NULL, pattern, FcMatchPattern);
   1.632 +    FcDefaultSubstitute(pattern);
   1.633 +
   1.634 +    // Font matching:
   1.635 +    // CSS often specifies a fallback list of families:
   1.636 +    //    font-family: a, b, c, serif;
   1.637 +    // However, fontconfig will always do its best to find *a* font when asked
   1.638 +    // for something so we need a way to tell if the match which it has found is
   1.639 +    // "good enough" for us. Otherwise, we can return NULL which gets piped up
   1.640 +    // and lets WebKit know to try the next CSS family name. However, fontconfig
   1.641 +    // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we
   1.642 +    // wish to support that.
   1.643 +    //
   1.644 +    // Thus, if a specific family is requested we set @family_requested. Then we
   1.645 +    // record two strings: the family name after config processing and the
   1.646 +    // family name after resolving. If the two are equal, it's a good match.
   1.647 +    //
   1.648 +    // So consider the case where a user has mapped Arial to Helvetica in their
   1.649 +    // config.
   1.650 +    //    requested family: "Arial"
   1.651 +    //    post_config_family: "Helvetica"
   1.652 +    //    post_match_family: "Helvetica"
   1.653 +    //      -> good match
   1.654 +    //
   1.655 +    // and for a missing font:
   1.656 +    //    requested family: "Monaco"
   1.657 +    //    post_config_family: "Monaco"
   1.658 +    //    post_match_family: "Times New Roman"
   1.659 +    //      -> BAD match
   1.660 +    //
   1.661 +    // However, we special-case fallback fonts; see IsFallbackFontAllowed().
   1.662 +
   1.663 +    const char* post_config_family = get_name(pattern, FC_FAMILY);
   1.664 +
   1.665 +    FcResult result;
   1.666 +    FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result);
   1.667 +    if (!font_set) {
   1.668 +        FcPatternDestroy(pattern);
   1.669 +        return false;
   1.670 +    }
   1.671 +
   1.672 +    FcPattern* match = MatchFont(font_set, post_config_family, familyStr);
   1.673 +    if (!match) {
   1.674 +        FcPatternDestroy(pattern);
   1.675 +        FcFontSetDestroy(font_set);
   1.676 +        return false;
   1.677 +    }
   1.678 +
   1.679 +    FcPatternDestroy(pattern);
   1.680 +
   1.681 +    // From here out we just extract our results from 'match'
   1.682 +
   1.683 +    if (FcPatternGetString(match, FC_FAMILY, 0, &post_config_family) != FcResultMatch) {
   1.684 +        FcFontSetDestroy(font_set);
   1.685 +        return false;
   1.686 +    }
   1.687 +
   1.688 +    FcChar8* c_filename;
   1.689 +    if (FcPatternGetString(match, FC_FILE, 0, &c_filename) != FcResultMatch) {
   1.690 +        FcFontSetDestroy(font_set);
   1.691 +        return false;
   1.692 +    }
   1.693 +
   1.694 +    int face_index;
   1.695 +    if (FcPatternGetInteger(match, FC_INDEX, 0, &face_index) != FcResultMatch) {
   1.696 +        FcFontSetDestroy(font_set);
   1.697 +        return false;
   1.698 +    }
   1.699 +
   1.700 +    FcFontSetDestroy(font_set);
   1.701 +
   1.702 +    if (outIdentity) {
   1.703 +        outIdentity->fTTCIndex = face_index;
   1.704 +        outIdentity->fString.set((const char*)c_filename);
   1.705 +    }
   1.706 +    if (outFamilyName) {
   1.707 +        outFamilyName->set((const char*)post_config_family);
   1.708 +    }
   1.709 +    if (outStyle) {
   1.710 +        *outStyle = GetFontStyle(match);
   1.711 +    }
   1.712 +    return true;
   1.713 +
   1.714 +////////////////////
   1.715 +
   1.716 +        int count;
   1.717 +        FcPattern** match = MatchFont(font_set, post_config_family, &count);
   1.718 +        if (!match) {
   1.719 +            FcPatternDestroy(pattern);
   1.720 +            FcFontSetDestroy(font_set);
   1.721 +            return NULL;
   1.722 +        }
   1.723 +
   1.724 +        FcPatternDestroy(pattern);
   1.725 +
   1.726 +        SkTDArray<FcPattern*> trimmedMatches;
   1.727 +        for (int i = 0; i < count; ++i) {
   1.728 +            const char* justName = find_just_name(get_name(match[i], FC_FILE));
   1.729 +            if (!is_lower(*justName)) {
   1.730 +                *trimmedMatches.append() = match[i];
   1.731 +            }
   1.732 +        }
   1.733 +
   1.734 +        SkFontStyleSet_FC* sset = SkNEW_ARGS(SkFontStyleSet_FC,
   1.735 +                                             (trimmedMatches.begin(),
   1.736 +                                              trimmedMatches.count()));
   1.737 +#endif
   1.738 +    return false;
   1.739 +}

mercurial