gfx/skia/trunk/src/fonts/SkFontMgr_fontconfig.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /*
michael@0 2 * Copyright 2013 Google Inc.
michael@0 3 *
michael@0 4 * Use of this source code is governed by a BSD-style license that can be
michael@0 5 * found in the LICENSE file.
michael@0 6 */
michael@0 7
michael@0 8 #include "SkFontMgr.h"
michael@0 9 #include "SkFontStyle.h"
michael@0 10 #include "SkFontConfigInterface.h"
michael@0 11 #include "SkFontConfigTypeface.h"
michael@0 12 #include "SkMath.h"
michael@0 13 #include "SkString.h"
michael@0 14 #include "SkTDArray.h"
michael@0 15
michael@0 16 // for now we pull these in directly. eventually we will solely rely on the
michael@0 17 // SkFontConfigInterface instance.
michael@0 18 #include <fontconfig/fontconfig.h>
michael@0 19 #include <unistd.h>
michael@0 20
michael@0 21 // Defined in SkFontHost_FreeType.cpp
michael@0 22 bool find_name_and_attributes(SkStream* stream, SkString* name,
michael@0 23 SkTypeface::Style* style, bool* isFixedWidth);
michael@0 24
michael@0 25 // borrow this global from SkFontHost_fontconfig. eventually that file should
michael@0 26 // go away, and be replaced with this one.
michael@0 27 extern SkFontConfigInterface* SkFontHost_fontconfig_ref_global();
michael@0 28 static SkFontConfigInterface* RefFCI() {
michael@0 29 return SkFontHost_fontconfig_ref_global();
michael@0 30 }
michael@0 31
michael@0 32 // look for the last substring after a '/' and return that, or return null.
michael@0 33 static const char* find_just_name(const char* str) {
michael@0 34 const char* last = strrchr(str, '/');
michael@0 35 return last ? last + 1 : NULL;
michael@0 36 }
michael@0 37
michael@0 38 static bool is_lower(char c) {
michael@0 39 return c >= 'a' && c <= 'z';
michael@0 40 }
michael@0 41
michael@0 42 static int get_int(FcPattern* pattern, const char field[]) {
michael@0 43 int value;
michael@0 44 if (FcPatternGetInteger(pattern, field, 0, &value) != FcResultMatch) {
michael@0 45 value = SK_MinS32;
michael@0 46 }
michael@0 47 return value;
michael@0 48 }
michael@0 49
michael@0 50 static const char* get_name(FcPattern* pattern, const char field[]) {
michael@0 51 const char* name;
michael@0 52 if (FcPatternGetString(pattern, field, 0, (FcChar8**)&name) != FcResultMatch) {
michael@0 53 name = "";
michael@0 54 }
michael@0 55 return name;
michael@0 56 }
michael@0 57
michael@0 58 static bool valid_pattern(FcPattern* pattern) {
michael@0 59 FcBool is_scalable;
michael@0 60 if (FcPatternGetBool(pattern, FC_SCALABLE, 0, &is_scalable) != FcResultMatch || !is_scalable) {
michael@0 61 return false;
michael@0 62 }
michael@0 63
michael@0 64 // fontconfig can also return fonts which are unreadable
michael@0 65 const char* c_filename = get_name(pattern, FC_FILE);
michael@0 66 if (0 == *c_filename) {
michael@0 67 return false;
michael@0 68 }
michael@0 69 if (access(c_filename, R_OK) != 0) {
michael@0 70 return false;
michael@0 71 }
michael@0 72 return true;
michael@0 73 }
michael@0 74
michael@0 75 static bool match_name(FcPattern* pattern, const char family_name[]) {
michael@0 76 return !strcasecmp(family_name, get_name(pattern, FC_FAMILY));
michael@0 77 }
michael@0 78
michael@0 79 static FcPattern** MatchFont(FcFontSet* font_set,
michael@0 80 const char post_config_family[],
michael@0 81 int* count) {
michael@0 82 // Older versions of fontconfig have a bug where they cannot select
michael@0 83 // only scalable fonts so we have to manually filter the results.
michael@0 84
michael@0 85 FcPattern** iter = font_set->fonts;
michael@0 86 FcPattern** stop = iter + font_set->nfont;
michael@0 87 // find the first good match
michael@0 88 for (; iter < stop; ++iter) {
michael@0 89 if (valid_pattern(*iter)) {
michael@0 90 break;
michael@0 91 }
michael@0 92 }
michael@0 93
michael@0 94 if (iter == stop || !match_name(*iter, post_config_family)) {
michael@0 95 return NULL;
michael@0 96 }
michael@0 97
michael@0 98 FcPattern** firstIter = iter++;
michael@0 99 for (; iter < stop; ++iter) {
michael@0 100 if (!valid_pattern(*iter) || !match_name(*iter, post_config_family)) {
michael@0 101 break;
michael@0 102 }
michael@0 103 }
michael@0 104
michael@0 105 *count = iter - firstIter;
michael@0 106 return firstIter;
michael@0 107 }
michael@0 108
michael@0 109 class SkFontStyleSet_FC : public SkFontStyleSet {
michael@0 110 public:
michael@0 111 SkFontStyleSet_FC(FcPattern** matches, int count);
michael@0 112 virtual ~SkFontStyleSet_FC();
michael@0 113
michael@0 114 virtual int count() SK_OVERRIDE { return fRecCount; }
michael@0 115 virtual void getStyle(int index, SkFontStyle*, SkString* style) SK_OVERRIDE;
michael@0 116 virtual SkTypeface* createTypeface(int index) SK_OVERRIDE;
michael@0 117 virtual SkTypeface* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE;
michael@0 118
michael@0 119 private:
michael@0 120 struct Rec {
michael@0 121 SkString fStyleName;
michael@0 122 SkString fFileName;
michael@0 123 SkFontStyle fStyle;
michael@0 124 };
michael@0 125 Rec* fRecs;
michael@0 126 int fRecCount;
michael@0 127 };
michael@0 128
michael@0 129 static int map_range(int value,
michael@0 130 int old_min, int old_max, int new_min, int new_max) {
michael@0 131 SkASSERT(old_min < old_max);
michael@0 132 SkASSERT(new_min < new_max);
michael@0 133 return new_min + SkMulDiv(value - old_min,
michael@0 134 new_max - new_min, old_max - old_min);
michael@0 135 }
michael@0 136
michael@0 137 static SkFontStyle make_fontconfig_style(FcPattern* match) {
michael@0 138 int weight = get_int(match, FC_WEIGHT);
michael@0 139 int width = get_int(match, FC_WIDTH);
michael@0 140 int slant = get_int(match, FC_SLANT);
michael@0 141 // SkDebugf("old weight %d new weight %d\n", weight, map_range(weight, 0, 80, 0, 400));
michael@0 142
michael@0 143 // fontconfig weight seems to be 0..200 or so, so we remap it here
michael@0 144 weight = map_range(weight, 0, 80, 0, 400);
michael@0 145 width = map_range(width, 0, 200, 0, 9);
michael@0 146 return SkFontStyle(weight, width, slant > 0 ? SkFontStyle::kItalic_Slant
michael@0 147 : SkFontStyle::kUpright_Slant);
michael@0 148 }
michael@0 149
michael@0 150 SkFontStyleSet_FC::SkFontStyleSet_FC(FcPattern** matches, int count) {
michael@0 151 fRecCount = count;
michael@0 152 fRecs = SkNEW_ARRAY(Rec, count);
michael@0 153 for (int i = 0; i < count; ++i) {
michael@0 154 fRecs[i].fStyleName.set(get_name(matches[i], FC_STYLE));
michael@0 155 fRecs[i].fFileName.set(get_name(matches[i], FC_FILE));
michael@0 156 fRecs[i].fStyle = make_fontconfig_style(matches[i]);
michael@0 157 }
michael@0 158 }
michael@0 159
michael@0 160 SkFontStyleSet_FC::~SkFontStyleSet_FC() {
michael@0 161 SkDELETE_ARRAY(fRecs);
michael@0 162 }
michael@0 163
michael@0 164 void SkFontStyleSet_FC::getStyle(int index, SkFontStyle* style,
michael@0 165 SkString* styleName) {
michael@0 166 SkASSERT((unsigned)index < (unsigned)fRecCount);
michael@0 167 if (style) {
michael@0 168 *style = fRecs[index].fStyle;
michael@0 169 }
michael@0 170 if (styleName) {
michael@0 171 *styleName = fRecs[index].fStyleName;
michael@0 172 }
michael@0 173 }
michael@0 174
michael@0 175 SkTypeface* SkFontStyleSet_FC::createTypeface(int index) {
michael@0 176 return NULL;
michael@0 177 }
michael@0 178
michael@0 179 SkTypeface* SkFontStyleSet_FC::matchStyle(const SkFontStyle& pattern) {
michael@0 180 return NULL;
michael@0 181 }
michael@0 182
michael@0 183 class SkFontMgr_fontconfig : public SkFontMgr {
michael@0 184 SkAutoTUnref<SkFontConfigInterface> fFCI;
michael@0 185 SkDataTable* fFamilyNames;
michael@0 186
michael@0 187
michael@0 188 public:
michael@0 189 SkFontMgr_fontconfig(SkFontConfigInterface* fci)
michael@0 190 : fFCI(fci)
michael@0 191 , fFamilyNames(fFCI->getFamilyNames()) {}
michael@0 192
michael@0 193 virtual ~SkFontMgr_fontconfig() {
michael@0 194 SkSafeUnref(fFamilyNames);
michael@0 195 }
michael@0 196
michael@0 197 protected:
michael@0 198 virtual int onCountFamilies() const SK_OVERRIDE {
michael@0 199 return fFamilyNames->count();
michael@0 200 }
michael@0 201
michael@0 202 virtual void onGetFamilyName(int index, SkString* familyName) const SK_OVERRIDE {
michael@0 203 familyName->set(fFamilyNames->atStr(index));
michael@0 204 }
michael@0 205
michael@0 206 virtual SkFontStyleSet* onCreateStyleSet(int index) const SK_OVERRIDE {
michael@0 207 return this->onMatchFamily(fFamilyNames->atStr(index));
michael@0 208 }
michael@0 209
michael@0 210 virtual SkFontStyleSet* onMatchFamily(const char familyName[]) const SK_OVERRIDE {
michael@0 211 FcPattern* pattern = FcPatternCreate();
michael@0 212
michael@0 213 FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName);
michael@0 214 #if 0
michael@0 215 FcPatternAddBool(pattern, FC_SCALABLE, FcTrue);
michael@0 216 #endif
michael@0 217 FcConfigSubstitute(NULL, pattern, FcMatchPattern);
michael@0 218 FcDefaultSubstitute(pattern);
michael@0 219
michael@0 220 const char* post_config_family = get_name(pattern, FC_FAMILY);
michael@0 221
michael@0 222 FcResult result;
michael@0 223 FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result);
michael@0 224 if (!font_set) {
michael@0 225 FcPatternDestroy(pattern);
michael@0 226 return NULL;
michael@0 227 }
michael@0 228
michael@0 229 int count;
michael@0 230 FcPattern** match = MatchFont(font_set, post_config_family, &count);
michael@0 231 if (!match) {
michael@0 232 FcPatternDestroy(pattern);
michael@0 233 FcFontSetDestroy(font_set);
michael@0 234 return NULL;
michael@0 235 }
michael@0 236
michael@0 237 FcPatternDestroy(pattern);
michael@0 238
michael@0 239 SkTDArray<FcPattern*> trimmedMatches;
michael@0 240 for (int i = 0; i < count; ++i) {
michael@0 241 const char* justName = find_just_name(get_name(match[i], FC_FILE));
michael@0 242 if (!is_lower(*justName)) {
michael@0 243 *trimmedMatches.append() = match[i];
michael@0 244 }
michael@0 245 }
michael@0 246
michael@0 247 SkFontStyleSet_FC* sset = SkNEW_ARGS(SkFontStyleSet_FC,
michael@0 248 (trimmedMatches.begin(),
michael@0 249 trimmedMatches.count()));
michael@0 250 return sset;
michael@0 251 }
michael@0 252
michael@0 253 virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
michael@0 254 const SkFontStyle&) const SK_OVERRIDE { return NULL; }
michael@0 255 virtual SkTypeface* onMatchFaceStyle(const SkTypeface*,
michael@0 256 const SkFontStyle&) const SK_OVERRIDE { return NULL; }
michael@0 257
michael@0 258 virtual SkTypeface* onCreateFromData(SkData*, int ttcIndex) const SK_OVERRIDE { return NULL; }
michael@0 259
michael@0 260 virtual SkTypeface* onCreateFromStream(SkStream* stream, int ttcIndex) const SK_OVERRIDE {
michael@0 261 const size_t length = stream->getLength();
michael@0 262 if (!length) {
michael@0 263 return NULL;
michael@0 264 }
michael@0 265 if (length >= 1024 * 1024 * 1024) {
michael@0 266 return NULL; // don't accept too large fonts (>= 1GB) for safety.
michael@0 267 }
michael@0 268
michael@0 269 // TODO should the caller give us the style or should we get it from freetype?
michael@0 270 SkTypeface::Style style = SkTypeface::kNormal;
michael@0 271 bool isFixedWidth = false;
michael@0 272 if (!find_name_and_attributes(stream, NULL, &style, &isFixedWidth)) {
michael@0 273 return NULL;
michael@0 274 }
michael@0 275
michael@0 276 SkTypeface* face = SkNEW_ARGS(FontConfigTypeface, (style, isFixedWidth, stream));
michael@0 277 return face;
michael@0 278 }
michael@0 279
michael@0 280 virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const SK_OVERRIDE {
michael@0 281 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path));
michael@0 282 return stream.get() ? this->createFromStream(stream, ttcIndex) : NULL;
michael@0 283 }
michael@0 284
michael@0 285 virtual SkTypeface* onLegacyCreateTypeface(const char familyName[],
michael@0 286 unsigned styleBits) const SK_OVERRIDE {
michael@0 287 return FontConfigTypeface::LegacyCreateTypeface(NULL, familyName,
michael@0 288 (SkTypeface::Style)styleBits);
michael@0 289 }
michael@0 290 };
michael@0 291
michael@0 292 SkFontMgr* SkFontMgr::Factory() {
michael@0 293 SkFontConfigInterface* fci = RefFCI();
michael@0 294 return fci ? SkNEW_ARGS(SkFontMgr_fontconfig, (fci)) : NULL;
michael@0 295 }

mercurial