gfx/skia/patches/archive/0007-Bug-719872-Old-Android-FontHost.patch

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 From 6982ad469adcdfa2b7bdbf8bbd843bc22d3832fc Mon Sep 17 00:00:00 2001
michael@0 2 From: George Wright <gwright@mozilla.com>
michael@0 3 Date: Fri, 18 May 2012 14:52:40 -0400
michael@0 4 Subject: [PATCH 07/10] Bug 755869 - [10] Re-apply bug 719872 - Fix crash
michael@0 5 on Android by reverting to older FontHost impl
michael@0 6 r=mattwoodrow
michael@0 7
michael@0 8 ---
michael@0 9 gfx/skia/Makefile.in | 5 +-
michael@0 10 gfx/skia/src/ports/SkFontHost_android_old.cpp | 664 +++++++++++++++++++++++++
michael@0 11 2 files changed, 668 insertions(+), 1 deletions(-)
michael@0 12 create mode 100644 gfx/skia/src/ports/SkFontHost_android_old.cpp
michael@0 13
michael@0 14 diff --git a/gfx/skia/Makefile.in b/gfx/skia/Makefile.in
michael@0 15 index 9da098a..8184f1c 100644
michael@0 16 --- a/gfx/skia/Makefile.in
michael@0 17 +++ b/gfx/skia/Makefile.in
michael@0 18 @@ -327,7 +327,10 @@ endif
michael@0 19 ifeq (android,$(MOZ_WIDGET_TOOLKIT))
michael@0 20 CPPSRCS += \
michael@0 21 SkDebug_android.cpp \
michael@0 22 - SkFontHost_none.cpp \
michael@0 23 + SkFontHost_android_old.cpp \
michael@0 24 + SkFontHost_gamma.cpp \
michael@0 25 + SkFontHost_FreeType.cpp \
michael@0 26 + SkFontHost_tables.cpp \
michael@0 27 SkMMapStream.cpp \
michael@0 28 SkTime_Unix.cpp \
michael@0 29 SkThread_pthread.cpp \
michael@0 30 diff --git a/gfx/skia/src/ports/SkFontHost_android_old.cpp b/gfx/skia/src/ports/SkFontHost_android_old.cpp
michael@0 31 new file mode 100644
michael@0 32 index 0000000..b5c4f3c
michael@0 33 --- /dev/null
michael@0 34 +++ b/gfx/skia/src/ports/SkFontHost_android_old.cpp
michael@0 35 @@ -0,0 +1,664 @@
michael@0 36 +
michael@0 37 +/*
michael@0 38 + * Copyright 2006 The Android Open Source Project
michael@0 39 + *
michael@0 40 + * Use of this source code is governed by a BSD-style license that can be
michael@0 41 + * found in the LICENSE file.
michael@0 42 + */
michael@0 43 +
michael@0 44 +
michael@0 45 +#include "SkFontHost.h"
michael@0 46 +#include "SkDescriptor.h"
michael@0 47 +#include "SkMMapStream.h"
michael@0 48 +#include "SkPaint.h"
michael@0 49 +#include "SkString.h"
michael@0 50 +#include "SkStream.h"
michael@0 51 +#include "SkThread.h"
michael@0 52 +#include "SkTSearch.h"
michael@0 53 +#include <stdio.h>
michael@0 54 +
michael@0 55 +#define FONT_CACHE_MEMORY_BUDGET (768 * 1024)
michael@0 56 +
michael@0 57 +#ifndef SK_FONT_FILE_PREFIX
michael@0 58 + #define SK_FONT_FILE_PREFIX "/fonts/"
michael@0 59 +#endif
michael@0 60 +
michael@0 61 +bool find_name_and_attributes(SkStream* stream, SkString* name, SkTypeface::Style* style,
michael@0 62 + bool* isFixedWidth);
michael@0 63 +
michael@0 64 +static void GetFullPathForSysFonts(SkString* full, const char name[]) {
michael@0 65 + full->set(getenv("ANDROID_ROOT"));
michael@0 66 + full->append(SK_FONT_FILE_PREFIX);
michael@0 67 + full->append(name);
michael@0 68 +}
michael@0 69 +
michael@0 70 +///////////////////////////////////////////////////////////////////////////////
michael@0 71 +
michael@0 72 +struct FamilyRec;
michael@0 73 +
michael@0 74 +/* This guy holds a mapping of a name -> family, used for looking up fonts.
michael@0 75 + Since it is stored in a stretchy array that doesn't preserve object
michael@0 76 + semantics, we don't use constructor/destructors, but just have explicit
michael@0 77 + helpers to manage our internal bookkeeping.
michael@0 78 +*/
michael@0 79 +struct NameFamilyPair {
michael@0 80 + const char* fName; // we own this
michael@0 81 + FamilyRec* fFamily; // we don't own this, we just reference it
michael@0 82 +
michael@0 83 + void construct(const char name[], FamilyRec* family) {
michael@0 84 + fName = strdup(name);
michael@0 85 + fFamily = family; // we don't own this, so just record the referene
michael@0 86 + }
michael@0 87 +
michael@0 88 + void destruct() {
michael@0 89 + free((char*)fName);
michael@0 90 + // we don't own family, so just ignore our reference
michael@0 91 + }
michael@0 92 +};
michael@0 93 +
michael@0 94 +// we use atomic_inc to grow this for each typeface we create
michael@0 95 +static int32_t gUniqueFontID;
michael@0 96 +
michael@0 97 +// this is the mutex that protects these globals
michael@0 98 +static SkMutex gFamilyMutex;
michael@0 99 +static FamilyRec* gFamilyHead;
michael@0 100 +static SkTDArray<NameFamilyPair> gNameList;
michael@0 101 +
michael@0 102 +struct FamilyRec {
michael@0 103 + FamilyRec* fNext;
michael@0 104 + SkTypeface* fFaces[4];
michael@0 105 +
michael@0 106 + FamilyRec()
michael@0 107 + {
michael@0 108 + fNext = gFamilyHead;
michael@0 109 + memset(fFaces, 0, sizeof(fFaces));
michael@0 110 + gFamilyHead = this;
michael@0 111 + }
michael@0 112 +};
michael@0 113 +
michael@0 114 +static SkTypeface* find_best_face(const FamilyRec* family,
michael@0 115 + SkTypeface::Style style) {
michael@0 116 + SkTypeface* const* faces = family->fFaces;
michael@0 117 +
michael@0 118 + if (faces[style] != NULL) { // exact match
michael@0 119 + return faces[style];
michael@0 120 + }
michael@0 121 + // look for a matching bold
michael@0 122 + style = (SkTypeface::Style)(style ^ SkTypeface::kItalic);
michael@0 123 + if (faces[style] != NULL) {
michael@0 124 + return faces[style];
michael@0 125 + }
michael@0 126 + // look for the plain
michael@0 127 + if (faces[SkTypeface::kNormal] != NULL) {
michael@0 128 + return faces[SkTypeface::kNormal];
michael@0 129 + }
michael@0 130 + // look for anything
michael@0 131 + for (int i = 0; i < 4; i++) {
michael@0 132 + if (faces[i] != NULL) {
michael@0 133 + return faces[i];
michael@0 134 + }
michael@0 135 + }
michael@0 136 + // should never get here, since the faces list should not be empty
michael@0 137 + SkASSERT(!"faces list is empty");
michael@0 138 + return NULL;
michael@0 139 +}
michael@0 140 +
michael@0 141 +static FamilyRec* find_family(const SkTypeface* member) {
michael@0 142 + FamilyRec* curr = gFamilyHead;
michael@0 143 + while (curr != NULL) {
michael@0 144 + for (int i = 0; i < 4; i++) {
michael@0 145 + if (curr->fFaces[i] == member) {
michael@0 146 + return curr;
michael@0 147 + }
michael@0 148 + }
michael@0 149 + curr = curr->fNext;
michael@0 150 + }
michael@0 151 + return NULL;
michael@0 152 +}
michael@0 153 +
michael@0 154 +/* Returns the matching typeface, or NULL. If a typeface is found, its refcnt
michael@0 155 + is not modified.
michael@0 156 + */
michael@0 157 +static SkTypeface* find_from_uniqueID(uint32_t uniqueID) {
michael@0 158 + FamilyRec* curr = gFamilyHead;
michael@0 159 + while (curr != NULL) {
michael@0 160 + for (int i = 0; i < 4; i++) {
michael@0 161 + SkTypeface* face = curr->fFaces[i];
michael@0 162 + if (face != NULL && face->uniqueID() == uniqueID) {
michael@0 163 + return face;
michael@0 164 + }
michael@0 165 + }
michael@0 166 + curr = curr->fNext;
michael@0 167 + }
michael@0 168 + return NULL;
michael@0 169 +}
michael@0 170 +
michael@0 171 +/* Remove reference to this face from its family. If the resulting family
michael@0 172 + is empty (has no faces), return that family, otherwise return NULL
michael@0 173 +*/
michael@0 174 +static FamilyRec* remove_from_family(const SkTypeface* face) {
michael@0 175 + FamilyRec* family = find_family(face);
michael@0 176 + SkASSERT(family->fFaces[face->style()] == face);
michael@0 177 + family->fFaces[face->style()] = NULL;
michael@0 178 +
michael@0 179 + for (int i = 0; i < 4; i++) {
michael@0 180 + if (family->fFaces[i] != NULL) { // family is non-empty
michael@0 181 + return NULL;
michael@0 182 + }
michael@0 183 + }
michael@0 184 + return family; // return the empty family
michael@0 185 +}
michael@0 186 +
michael@0 187 +// maybe we should make FamilyRec be doubly-linked
michael@0 188 +static void detach_and_delete_family(FamilyRec* family) {
michael@0 189 + FamilyRec* curr = gFamilyHead;
michael@0 190 + FamilyRec* prev = NULL;
michael@0 191 +
michael@0 192 + while (curr != NULL) {
michael@0 193 + FamilyRec* next = curr->fNext;
michael@0 194 + if (curr == family) {
michael@0 195 + if (prev == NULL) {
michael@0 196 + gFamilyHead = next;
michael@0 197 + } else {
michael@0 198 + prev->fNext = next;
michael@0 199 + }
michael@0 200 + SkDELETE(family);
michael@0 201 + return;
michael@0 202 + }
michael@0 203 + prev = curr;
michael@0 204 + curr = next;
michael@0 205 + }
michael@0 206 + SkASSERT(!"Yikes, couldn't find family in our list to remove/delete");
michael@0 207 +}
michael@0 208 +
michael@0 209 +static SkTypeface* find_typeface(const char name[], SkTypeface::Style style) {
michael@0 210 + NameFamilyPair* list = gNameList.begin();
michael@0 211 + int count = gNameList.count();
michael@0 212 +
michael@0 213 + int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0]));
michael@0 214 +
michael@0 215 + if (index >= 0) {
michael@0 216 + return find_best_face(list[index].fFamily, style);
michael@0 217 + }
michael@0 218 + return NULL;
michael@0 219 +}
michael@0 220 +
michael@0 221 +static SkTypeface* find_typeface(const SkTypeface* familyMember,
michael@0 222 + SkTypeface::Style style) {
michael@0 223 + const FamilyRec* family = find_family(familyMember);
michael@0 224 + return family ? find_best_face(family, style) : NULL;
michael@0 225 +}
michael@0 226 +
michael@0 227 +static void add_name(const char name[], FamilyRec* family) {
michael@0 228 + SkAutoAsciiToLC tolc(name);
michael@0 229 + name = tolc.lc();
michael@0 230 +
michael@0 231 + NameFamilyPair* list = gNameList.begin();
michael@0 232 + int count = gNameList.count();
michael@0 233 +
michael@0 234 + int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0]));
michael@0 235 +
michael@0 236 + if (index < 0) {
michael@0 237 + list = gNameList.insert(~index);
michael@0 238 + list->construct(name, family);
michael@0 239 + }
michael@0 240 +}
michael@0 241 +
michael@0 242 +static void remove_from_names(FamilyRec* emptyFamily)
michael@0 243 +{
michael@0 244 +#ifdef SK_DEBUG
michael@0 245 + for (int i = 0; i < 4; i++) {
michael@0 246 + SkASSERT(emptyFamily->fFaces[i] == NULL);
michael@0 247 + }
michael@0 248 +#endif
michael@0 249 +
michael@0 250 + SkTDArray<NameFamilyPair>& list = gNameList;
michael@0 251 +
michael@0 252 + // must go backwards when removing
michael@0 253 + for (int i = list.count() - 1; i >= 0; --i) {
michael@0 254 + NameFamilyPair* pair = &list[i];
michael@0 255 + if (pair->fFamily == emptyFamily) {
michael@0 256 + pair->destruct();
michael@0 257 + list.remove(i);
michael@0 258 + }
michael@0 259 + }
michael@0 260 +}
michael@0 261 +
michael@0 262 +///////////////////////////////////////////////////////////////////////////////
michael@0 263 +
michael@0 264 +class FamilyTypeface : public SkTypeface {
michael@0 265 +public:
michael@0 266 + FamilyTypeface(Style style, bool sysFont, SkTypeface* familyMember,
michael@0 267 + bool isFixedWidth)
michael@0 268 + : SkTypeface(style, sk_atomic_inc(&gUniqueFontID) + 1, isFixedWidth) {
michael@0 269 + fIsSysFont = sysFont;
michael@0 270 +
michael@0 271 + SkAutoMutexAcquire ac(gFamilyMutex);
michael@0 272 +
michael@0 273 + FamilyRec* rec = NULL;
michael@0 274 + if (familyMember) {
michael@0 275 + rec = find_family(familyMember);
michael@0 276 + SkASSERT(rec);
michael@0 277 + } else {
michael@0 278 + rec = SkNEW(FamilyRec);
michael@0 279 + }
michael@0 280 + rec->fFaces[style] = this;
michael@0 281 + }
michael@0 282 +
michael@0 283 + virtual ~FamilyTypeface() {
michael@0 284 + SkAutoMutexAcquire ac(gFamilyMutex);
michael@0 285 +
michael@0 286 + // remove us from our family. If the family is now empty, we return
michael@0 287 + // that and then remove that family from the name list
michael@0 288 + FamilyRec* family = remove_from_family(this);
michael@0 289 + if (NULL != family) {
michael@0 290 + remove_from_names(family);
michael@0 291 + detach_and_delete_family(family);
michael@0 292 + }
michael@0 293 + }
michael@0 294 +
michael@0 295 + bool isSysFont() const { return fIsSysFont; }
michael@0 296 +
michael@0 297 + virtual SkStream* openStream() = 0;
michael@0 298 + virtual const char* getUniqueString() const = 0;
michael@0 299 + virtual const char* getFilePath() const = 0;
michael@0 300 +
michael@0 301 +private:
michael@0 302 + bool fIsSysFont;
michael@0 303 +
michael@0 304 + typedef SkTypeface INHERITED;
michael@0 305 +};
michael@0 306 +
michael@0 307 +///////////////////////////////////////////////////////////////////////////////
michael@0 308 +
michael@0 309 +class StreamTypeface : public FamilyTypeface {
michael@0 310 +public:
michael@0 311 + StreamTypeface(Style style, bool sysFont, SkTypeface* familyMember,
michael@0 312 + SkStream* stream, bool isFixedWidth)
michael@0 313 + : INHERITED(style, sysFont, familyMember, isFixedWidth) {
michael@0 314 + SkASSERT(stream);
michael@0 315 + stream->ref();
michael@0 316 + fStream = stream;
michael@0 317 + }
michael@0 318 + virtual ~StreamTypeface() {
michael@0 319 + fStream->unref();
michael@0 320 + }
michael@0 321 +
michael@0 322 + // overrides
michael@0 323 + virtual SkStream* openStream() {
michael@0 324 + // we just ref our existing stream, since the caller will call unref()
michael@0 325 + // when they are through
michael@0 326 + fStream->ref();
michael@0 327 + // must rewind each time, since the caller assumes a "new" stream
michael@0 328 + fStream->rewind();
michael@0 329 + return fStream;
michael@0 330 + }
michael@0 331 + virtual const char* getUniqueString() const { return NULL; }
michael@0 332 + virtual const char* getFilePath() const { return NULL; }
michael@0 333 +
michael@0 334 +private:
michael@0 335 + SkStream* fStream;
michael@0 336 +
michael@0 337 + typedef FamilyTypeface INHERITED;
michael@0 338 +};
michael@0 339 +
michael@0 340 +class FileTypeface : public FamilyTypeface {
michael@0 341 +public:
michael@0 342 + FileTypeface(Style style, bool sysFont, SkTypeface* familyMember,
michael@0 343 + const char path[], bool isFixedWidth)
michael@0 344 + : INHERITED(style, sysFont, familyMember, isFixedWidth) {
michael@0 345 + SkString fullpath;
michael@0 346 +
michael@0 347 + if (sysFont) {
michael@0 348 + GetFullPathForSysFonts(&fullpath, path);
michael@0 349 + path = fullpath.c_str();
michael@0 350 + }
michael@0 351 + fPath.set(path);
michael@0 352 + }
michael@0 353 +
michael@0 354 + // overrides
michael@0 355 + virtual SkStream* openStream() {
michael@0 356 + SkStream* stream = SkNEW_ARGS(SkMMAPStream, (fPath.c_str()));
michael@0 357 +
michael@0 358 + // check for failure
michael@0 359 + if (stream->getLength() <= 0) {
michael@0 360 + SkDELETE(stream);
michael@0 361 + // maybe MMAP isn't supported. try FILE
michael@0 362 + stream = SkNEW_ARGS(SkFILEStream, (fPath.c_str()));
michael@0 363 + if (stream->getLength() <= 0) {
michael@0 364 + SkDELETE(stream);
michael@0 365 + stream = NULL;
michael@0 366 + }
michael@0 367 + }
michael@0 368 + return stream;
michael@0 369 + }
michael@0 370 + virtual const char* getUniqueString() const {
michael@0 371 + const char* str = strrchr(fPath.c_str(), '/');
michael@0 372 + if (str) {
michael@0 373 + str += 1; // skip the '/'
michael@0 374 + }
michael@0 375 + return str;
michael@0 376 + }
michael@0 377 + virtual const char* getFilePath() const {
michael@0 378 + return fPath.c_str();
michael@0 379 + }
michael@0 380 +
michael@0 381 +private:
michael@0 382 + SkString fPath;
michael@0 383 +
michael@0 384 + typedef FamilyTypeface INHERITED;
michael@0 385 +};
michael@0 386 +
michael@0 387 +///////////////////////////////////////////////////////////////////////////////
michael@0 388 +///////////////////////////////////////////////////////////////////////////////
michael@0 389 +
michael@0 390 +static bool get_name_and_style(const char path[], SkString* name,
michael@0 391 + SkTypeface::Style* style,
michael@0 392 + bool* isFixedWidth, bool isExpected) {
michael@0 393 + SkString fullpath;
michael@0 394 + GetFullPathForSysFonts(&fullpath, path);
michael@0 395 +
michael@0 396 + SkMMAPStream stream(fullpath.c_str());
michael@0 397 + if (stream.getLength() > 0) {
michael@0 398 + find_name_and_attributes(&stream, name, style, isFixedWidth);
michael@0 399 + return true;
michael@0 400 + }
michael@0 401 + else {
michael@0 402 + SkFILEStream stream(fullpath.c_str());
michael@0 403 + if (stream.getLength() > 0) {
michael@0 404 + find_name_and_attributes(&stream, name, style, isFixedWidth);
michael@0 405 + return true;
michael@0 406 + }
michael@0 407 + }
michael@0 408 +
michael@0 409 + if (isExpected) {
michael@0 410 + SkDebugf("---- failed to open <%s> as a font\n", fullpath.c_str());
michael@0 411 + }
michael@0 412 + return false;
michael@0 413 +}
michael@0 414 +
michael@0 415 +// used to record our notion of the pre-existing fonts
michael@0 416 +struct FontInitRec {
michael@0 417 + const char* fFileName;
michael@0 418 + const char* const* fNames; // null-terminated list
michael@0 419 +};
michael@0 420 +
michael@0 421 +static const char* gSansNames[] = {
michael@0 422 + "sans-serif", "arial", "helvetica", "tahoma", "verdana", NULL
michael@0 423 +};
michael@0 424 +
michael@0 425 +static const char* gSerifNames[] = {
michael@0 426 + "serif", "times", "times new roman", "palatino", "georgia", "baskerville",
michael@0 427 + "goudy", "fantasy", "cursive", "ITC Stone Serif", NULL
michael@0 428 +};
michael@0 429 +
michael@0 430 +static const char* gMonoNames[] = {
michael@0 431 + "monospace", "courier", "courier new", "monaco", NULL
michael@0 432 +};
michael@0 433 +
michael@0 434 +// deliberately empty, but we use the address to identify fallback fonts
michael@0 435 +static const char* gFBNames[] = { NULL };
michael@0 436 +
michael@0 437 +/* Fonts must be grouped by family, with the first font in a family having the
michael@0 438 + list of names (even if that list is empty), and the following members having
michael@0 439 + null for the list. The names list must be NULL-terminated
michael@0 440 +*/
michael@0 441 +static const FontInitRec gSystemFonts[] = {
michael@0 442 + { "DroidSans.ttf", gSansNames },
michael@0 443 + { "DroidSans-Bold.ttf", NULL },
michael@0 444 + { "DroidSerif-Regular.ttf", gSerifNames },
michael@0 445 + { "DroidSerif-Bold.ttf", NULL },
michael@0 446 + { "DroidSerif-Italic.ttf", NULL },
michael@0 447 + { "DroidSerif-BoldItalic.ttf", NULL },
michael@0 448 + { "DroidSansMono.ttf", gMonoNames },
michael@0 449 + /* These are optional, and can be ignored if not found in the file system.
michael@0 450 + These are appended to gFallbackFonts[] as they are seen, so we list
michael@0 451 + them in the order we want them to be accessed by NextLogicalFont().
michael@0 452 + */
michael@0 453 + { "DroidSansArabic.ttf", gFBNames },
michael@0 454 + { "DroidSansHebrew.ttf", gFBNames },
michael@0 455 + { "DroidSansThai.ttf", gFBNames },
michael@0 456 + { "MTLmr3m.ttf", gFBNames }, // Motoya Japanese Font
michael@0 457 + { "MTLc3m.ttf", gFBNames }, // Motoya Japanese Font
michael@0 458 + { "DroidSansJapanese.ttf", gFBNames },
michael@0 459 + { "DroidSansFallback.ttf", gFBNames }
michael@0 460 +};
michael@0 461 +
michael@0 462 +#define DEFAULT_NAMES gSansNames
michael@0 463 +
michael@0 464 +// these globals are assigned (once) by load_system_fonts()
michael@0 465 +static FamilyRec* gDefaultFamily;
michael@0 466 +static SkTypeface* gDefaultNormal;
michael@0 467 +
michael@0 468 +/* This is sized conservatively, assuming that it will never be a size issue.
michael@0 469 + It will be initialized in load_system_fonts(), and will be filled with the
michael@0 470 + fontIDs that can be used for fallback consideration, in sorted order (sorted
michael@0 471 + meaning element[0] should be used first, then element[1], etc. When we hit
michael@0 472 + a fontID==0 in the array, the list is done, hence our allocation size is
michael@0 473 + +1 the total number of possible system fonts. Also see NextLogicalFont().
michael@0 474 + */
michael@0 475 +static uint32_t gFallbackFonts[SK_ARRAY_COUNT(gSystemFonts)+1];
michael@0 476 +
michael@0 477 +/* Called once (ensured by the sentinel check at the beginning of our body).
michael@0 478 + Initializes all the globals, and register the system fonts.
michael@0 479 + */
michael@0 480 +static void load_system_fonts() {
michael@0 481 + // check if we've already be called
michael@0 482 + if (NULL != gDefaultNormal) {
michael@0 483 + return;
michael@0 484 + }
michael@0 485 +
michael@0 486 + const FontInitRec* rec = gSystemFonts;
michael@0 487 + SkTypeface* firstInFamily = NULL;
michael@0 488 + int fallbackCount = 0;
michael@0 489 +
michael@0 490 + for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
michael@0 491 + // if we're the first in a new family, clear firstInFamily
michael@0 492 + if (rec[i].fNames != NULL) {
michael@0 493 + firstInFamily = NULL;
michael@0 494 + }
michael@0 495 +
michael@0 496 + bool isFixedWidth;
michael@0 497 + SkString name;
michael@0 498 + SkTypeface::Style style;
michael@0 499 +
michael@0 500 + // we expect all the fonts, except the "fallback" fonts
michael@0 501 + bool isExpected = (rec[i].fNames != gFBNames);
michael@0 502 + if (!get_name_and_style(rec[i].fFileName, &name, &style,
michael@0 503 + &isFixedWidth, isExpected)) {
michael@0 504 + continue;
michael@0 505 + }
michael@0 506 +
michael@0 507 + SkTypeface* tf = SkNEW_ARGS(FileTypeface,
michael@0 508 + (style,
michael@0 509 + true, // system-font (cannot delete)
michael@0 510 + firstInFamily, // what family to join
michael@0 511 + rec[i].fFileName,
michael@0 512 + isFixedWidth) // filename
michael@0 513 + );
michael@0 514 +
michael@0 515 + if (rec[i].fNames != NULL) {
michael@0 516 + // see if this is one of our fallback fonts
michael@0 517 + if (rec[i].fNames == gFBNames) {
michael@0 518 + // SkDebugf("---- adding %s as fallback[%d] fontID %d\n",
michael@0 519 + // rec[i].fFileName, fallbackCount, tf->uniqueID());
michael@0 520 + gFallbackFonts[fallbackCount++] = tf->uniqueID();
michael@0 521 + }
michael@0 522 +
michael@0 523 + firstInFamily = tf;
michael@0 524 + FamilyRec* family = find_family(tf);
michael@0 525 + const char* const* names = rec[i].fNames;
michael@0 526 +
michael@0 527 + // record the default family if this is it
michael@0 528 + if (names == DEFAULT_NAMES) {
michael@0 529 + gDefaultFamily = family;
michael@0 530 + }
michael@0 531 + // add the names to map to this family
michael@0 532 + while (*names) {
michael@0 533 + add_name(*names, family);
michael@0 534 + names += 1;
michael@0 535 + }
michael@0 536 + }
michael@0 537 + }
michael@0 538 +
michael@0 539 + // do this after all fonts are loaded. This is our default font, and it
michael@0 540 + // acts as a sentinel so we only execute load_system_fonts() once
michael@0 541 + gDefaultNormal = find_best_face(gDefaultFamily, SkTypeface::kNormal);
michael@0 542 + // now terminate our fallback list with the sentinel value
michael@0 543 + gFallbackFonts[fallbackCount] = 0;
michael@0 544 +}
michael@0 545 +
michael@0 546 +///////////////////////////////////////////////////////////////////////////////
michael@0 547 +
michael@0 548 +void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
michael@0 549 + const char* name = ((FamilyTypeface*)face)->getUniqueString();
michael@0 550 +
michael@0 551 + stream->write8((uint8_t)face->style());
michael@0 552 +
michael@0 553 + if (NULL == name || 0 == *name) {
michael@0 554 + stream->writePackedUInt(0);
michael@0 555 +// SkDebugf("--- fonthost serialize null\n");
michael@0 556 + } else {
michael@0 557 + uint32_t len = strlen(name);
michael@0 558 + stream->writePackedUInt(len);
michael@0 559 + stream->write(name, len);
michael@0 560 +// SkDebugf("--- fonthost serialize <%s> %d\n", name, face->style());
michael@0 561 + }
michael@0 562 +}
michael@0 563 +
michael@0 564 +SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
michael@0 565 + load_system_fonts();
michael@0 566 +
michael@0 567 + int style = stream->readU8();
michael@0 568 +
michael@0 569 + int len = stream->readPackedUInt();
michael@0 570 + if (len > 0) {
michael@0 571 + SkString str;
michael@0 572 + str.resize(len);
michael@0 573 + stream->read(str.writable_str(), len);
michael@0 574 +
michael@0 575 + const FontInitRec* rec = gSystemFonts;
michael@0 576 + for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
michael@0 577 + if (strcmp(rec[i].fFileName, str.c_str()) == 0) {
michael@0 578 + // backup until we hit the fNames
michael@0 579 + for (int j = i; j >= 0; --j) {
michael@0 580 + if (rec[j].fNames != NULL) {
michael@0 581 + return SkFontHost::CreateTypeface(NULL,
michael@0 582 + rec[j].fNames[0], (SkTypeface::Style)style);
michael@0 583 + }
michael@0 584 + }
michael@0 585 + }
michael@0 586 + }
michael@0 587 + }
michael@0 588 + return NULL;
michael@0 589 +}
michael@0 590 +
michael@0 591 +///////////////////////////////////////////////////////////////////////////////
michael@0 592 +
michael@0 593 +SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
michael@0 594 + const char familyName[],
michael@0 595 + SkTypeface::Style style) {
michael@0 596 + load_system_fonts();
michael@0 597 +
michael@0 598 + SkAutoMutexAcquire ac(gFamilyMutex);
michael@0 599 +
michael@0 600 + // clip to legal style bits
michael@0 601 + style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic);
michael@0 602 +
michael@0 603 + SkTypeface* tf = NULL;
michael@0 604 +
michael@0 605 + if (NULL != familyFace) {
michael@0 606 + tf = find_typeface(familyFace, style);
michael@0 607 + } else if (NULL != familyName) {
michael@0 608 +// SkDebugf("======= familyName <%s>\n", familyName);
michael@0 609 + tf = find_typeface(familyName, style);
michael@0 610 + }
michael@0 611 +
michael@0 612 + if (NULL == tf) {
michael@0 613 + tf = find_best_face(gDefaultFamily, style);
michael@0 614 + }
michael@0 615 +
michael@0 616 + // we ref(), since the symantic is to return a new instance
michael@0 617 + tf->ref();
michael@0 618 + return tf;
michael@0 619 +}
michael@0 620 +
michael@0 621 +SkStream* SkFontHost::OpenStream(uint32_t fontID) {
michael@0 622 + SkAutoMutexAcquire ac(gFamilyMutex);
michael@0 623 +
michael@0 624 + FamilyTypeface* tf = (FamilyTypeface*)find_from_uniqueID(fontID);
michael@0 625 + SkStream* stream = tf ? tf->openStream() : NULL;
michael@0 626 +
michael@0 627 + if (stream && stream->getLength() == 0) {
michael@0 628 + stream->unref();
michael@0 629 + stream = NULL;
michael@0 630 + }
michael@0 631 + return stream;
michael@0 632 +}
michael@0 633 +
michael@0 634 +size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
michael@0 635 + int32_t* index) {
michael@0 636 + SkAutoMutexAcquire ac(gFamilyMutex);
michael@0 637 +
michael@0 638 + FamilyTypeface* tf = (FamilyTypeface*)find_from_uniqueID(fontID);
michael@0 639 + const char* src = tf ? tf->getFilePath() : NULL;
michael@0 640 +
michael@0 641 + if (src) {
michael@0 642 + size_t size = strlen(src);
michael@0 643 + if (path) {
michael@0 644 + memcpy(path, src, SkMin32(size, length));
michael@0 645 + }
michael@0 646 + if (index) {
michael@0 647 + *index = 0; // we don't have collections (yet)
michael@0 648 + }
michael@0 649 + return size;
michael@0 650 + } else {
michael@0 651 + return 0;
michael@0 652 + }
michael@0 653 +}
michael@0 654 +
michael@0 655 +SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
michael@0 656 + load_system_fonts();
michael@0 657 +
michael@0 658 + /* First see if fontID is already one of our fallbacks. If so, return
michael@0 659 + its successor. If fontID is not in our list, then return the first one
michael@0 660 + in our list. Note: list is zero-terminated, and returning zero means
michael@0 661 + we have no more fonts to use for fallbacks.
michael@0 662 + */
michael@0 663 + const uint32_t* list = gFallbackFonts;
michael@0 664 + for (int i = 0; list[i] != 0; i++) {
michael@0 665 + if (list[i] == currFontID) {
michael@0 666 + return list[i+1];
michael@0 667 + }
michael@0 668 + }
michael@0 669 + return list[0];
michael@0 670 +}
michael@0 671 +
michael@0 672 +///////////////////////////////////////////////////////////////////////////////
michael@0 673 +
michael@0 674 +SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
michael@0 675 + if (NULL == stream || stream->getLength() <= 0) {
michael@0 676 + return NULL;
michael@0 677 + }
michael@0 678 +
michael@0 679 + bool isFixedWidth;
michael@0 680 + SkString name;
michael@0 681 + SkTypeface::Style style;
michael@0 682 + find_name_and_attributes(stream, &name, &style, &isFixedWidth);
michael@0 683 +
michael@0 684 + if (!name.isEmpty()) {
michael@0 685 + return SkNEW_ARGS(StreamTypeface, (style, false, NULL, stream, isFixedWidth));
michael@0 686 + } else {
michael@0 687 + return NULL;
michael@0 688 + }
michael@0 689 +}
michael@0 690 +
michael@0 691 +SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
michael@0 692 + SkStream* stream = SkNEW_ARGS(SkMMAPStream, (path));
michael@0 693 + SkTypeface* face = SkFontHost::CreateTypefaceFromStream(stream);
michael@0 694 + // since we created the stream, we let go of our ref() here
michael@0 695 + stream->unref();
michael@0 696 + return face;
michael@0 697 +}
michael@0 698 +
michael@0 699 +///////////////////////////////////////////////////////////////////////////////
michael@0 700 --
michael@0 701 1.7.5.4
michael@0 702

mercurial