1bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com/* 2bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com * Copyright 2011 The Android Open Source Project 3bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com * 4bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com * Use of this source code is governed by a BSD-style license that can be 5bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com * found in the LICENSE file. 6bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com */ 7bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 8bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com#include "SkFontConfigParser_android.h" 97fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman#include "SkFontMgr_android.h" 107fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman#include "SkStream.h" 11bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com#include "SkTDArray.h" 128d84c995319dd4a82e4f2054bbd19f968c671ca6bungeman#include "SkTSearch.h" 13bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com#include "SkTypeface.h" 14bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 15bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com#include <expat.h> 16a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen#include <dirent.h> 17465706820d0d373f76ab4831c286115ee0d86b7arobertphillips#include <stdio.h> 18bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 19465706820d0d373f76ab4831c286115ee0d86b7arobertphillips#include <limits> 207fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman#include <stdlib.h> 218d84c995319dd4a82e4f2054bbd19f968c671ca6bungeman 2294fa4b99e2a53e997a90c7808cc5263f1bf40c9ftomhudson#define LMP_SYSTEM_FONTS_FILE "/system/etc/fonts.xml" 2394fa4b99e2a53e997a90c7808cc5263f1bf40c9ftomhudson#define OLD_SYSTEM_FONTS_FILE "/system/etc/system_fonts.xml" 24bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com#define FALLBACK_FONTS_FILE "/system/etc/fallback_fonts.xml" 25bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com#define VENDOR_FONTS_FILE "/vendor/etc/fallback_fonts.xml" 26bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 27a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen#define LOCALE_FALLBACK_FONTS_SYSTEM_DIR "/system/etc" 28a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen#define LOCALE_FALLBACK_FONTS_VENDOR_DIR "/vendor/etc" 29a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen#define LOCALE_FALLBACK_FONTS_PREFIX "fallback_fonts-" 30a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen#define LOCALE_FALLBACK_FONTS_SUFFIX ".xml" 31a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen 327fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman#ifndef SK_FONT_FILE_PREFIX 337fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman# define SK_FONT_FILE_PREFIX "/fonts/" 347fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman#endif 357fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman 36f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson/** 3710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * This file contains TWO 'familyset' handlers: 3810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * One for JB and earlier which works with 3910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * /system/etc/system_fonts.xml 4010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * /system/etc/fallback_fonts.xml 4110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * /vendor/etc/fallback_fonts.xml 4210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * /system/etc/fallback_fonts-XX.xml 4310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * /vendor/etc/fallback_fonts-XX.xml 4410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * and the other for LMP and later which works with 4510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * /system/etc/fonts.xml 4610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * 4710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * If the 'familyset' 'version' attribute is 21 or higher the LMP parser is used, otherwise the JB. 48f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson */ 49f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson 5010b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstruct FamilyData; 5110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 5210b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstruct TagHandler { 5310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /** Called at the start tag. 5410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * Called immediately after the parent tag retuns this handler from a call to 'tag'. 5510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * Allows setting up for handling the tag content and processing attributes. 5610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * If NULL, will not be called. 5710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman */ 5810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman void (*start)(FamilyData* data, const char* tag, const char** attributes); 5910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 6010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /** Called at the end tag. 6110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * Allows post-processing of any accumulated information. 6210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * This will be the last call made in relation to the current tag. 6310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * If NULL, will not be called. 6410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman */ 6510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman void (*end)(FamilyData* data, const char* tag); 6610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 6710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /** Called when a nested tag is encountered. 6810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * This is responsible for determining how to handle the tag. 6910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * If the tag is not recognized, return NULL to skip the tag. 7010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * If NULL, all nested tags will be skipped. 7110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman */ 7210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const TagHandler* (*tag)(FamilyData* data, const char* tag, const char** attributes); 7310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 7410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /** The character handler for this tag. 7510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * This is only active for character data contained directly in this tag (not sub-tags). 7610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * The first parameter will be castable to a FamilyData*. 7710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * If NULL, any character data in this tag will be ignored. 7810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman */ 7910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman XML_CharacterDataHandler chars; 807fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman}; 81bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 8210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman/** Represents the current parsing state. */ 83bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.comstruct FamilyData { 847fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman FamilyData(XML_Parser parser, SkTDArray<FontFamily*>& families, 8510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const SkString& basePath, bool isFallback, const char* filename, 8610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const TagHandler* topLevelHandler) 87b6bed17ea81ff8fad68a7db79307bdcbcd4738a8bungeman : fParser(parser) 88b6bed17ea81ff8fad68a7db79307bdcbcd4738a8bungeman , fFamilies(families) 89b6bed17ea81ff8fad68a7db79307bdcbcd4738a8bungeman , fCurrentFamily(NULL) 90b6bed17ea81ff8fad68a7db79307bdcbcd4738a8bungeman , fCurrentFontInfo(NULL) 91efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman , fVersion(0) 927fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman , fBasePath(basePath) 937fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman , fIsFallback(isFallback) 94f61475e95d9bb38f741f9e51221c086250b9ad72bungeman , fFilename(filename) 9510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman , fDepth(1) 9610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman , fSkip(0) 9710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman , fHandler(&topLevelHandler, 1) 987fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman { }; 99b6bed17ea81ff8fad68a7db79307bdcbcd4738a8bungeman 100b6bed17ea81ff8fad68a7db79307bdcbcd4738a8bungeman XML_Parser fParser; // The expat parser doing the work, owned by caller 101b6bed17ea81ff8fad68a7db79307bdcbcd4738a8bungeman SkTDArray<FontFamily*>& fFamilies; // The array to append families, owned by caller 102b6bed17ea81ff8fad68a7db79307bdcbcd4738a8bungeman SkAutoTDelete<FontFamily> fCurrentFamily; // The family being created, owned by this 1037fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman FontFileInfo* fCurrentFontInfo; // The fontInfo being created, owned by fCurrentFamily 104efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman int fVersion; // The version of the file parsed. 1057fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const SkString& fBasePath; // The current base path. 1067fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const bool fIsFallback; // Indicates the file being parsed is a fallback file 107f61475e95d9bb38f741f9e51221c086250b9ad72bungeman const char* fFilename; // The name of the file currently being parsed. 10810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 10910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman int fDepth; // The current element depth of the parse. 11010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman int fSkip; // The depth to stop skipping, 0 if not skipping. 11110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SkTDArray<const TagHandler*> fHandler; // The stack of current tag handlers. 112bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com}; 113bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 114465706820d0d373f76ab4831c286115ee0d86b7arobertphillips/** Parses a null terminated string into an integer type, checking for overflow. 115465706820d0d373f76ab4831c286115ee0d86b7arobertphillips * http://www.w3.org/TR/html-markup/datatypes.html#common.data.integer.non-negative-def 116465706820d0d373f76ab4831c286115ee0d86b7arobertphillips * 117465706820d0d373f76ab4831c286115ee0d86b7arobertphillips * If the string cannot be parsed into 'value', returns false and does not change 'value'. 118465706820d0d373f76ab4831c286115ee0d86b7arobertphillips */ 119465706820d0d373f76ab4831c286115ee0d86b7arobertphillipstemplate <typename T> static bool parse_non_negative_integer(const char* s, T* value) { 120465706820d0d373f76ab4831c286115ee0d86b7arobertphillips SK_COMPILE_ASSERT(std::numeric_limits<T>::is_integer, T_must_be_integer); 121465706820d0d373f76ab4831c286115ee0d86b7arobertphillips const T nMax = std::numeric_limits<T>::max() / 10; 122465706820d0d373f76ab4831c286115ee0d86b7arobertphillips const T dMax = std::numeric_limits<T>::max() - (nMax * 10); 123465706820d0d373f76ab4831c286115ee0d86b7arobertphillips T n = 0; 124465706820d0d373f76ab4831c286115ee0d86b7arobertphillips for (; *s; ++s) { 125465706820d0d373f76ab4831c286115ee0d86b7arobertphillips // Check if digit 126465706820d0d373f76ab4831c286115ee0d86b7arobertphillips if (*s < '0' || '9' < *s) { 127465706820d0d373f76ab4831c286115ee0d86b7arobertphillips return false; 128465706820d0d373f76ab4831c286115ee0d86b7arobertphillips } 129465706820d0d373f76ab4831c286115ee0d86b7arobertphillips int d = *s - '0'; 130465706820d0d373f76ab4831c286115ee0d86b7arobertphillips // Check for overflow 131465706820d0d373f76ab4831c286115ee0d86b7arobertphillips if (n > nMax || (n == nMax && d > dMax)) { 132465706820d0d373f76ab4831c286115ee0d86b7arobertphillips return false; 133465706820d0d373f76ab4831c286115ee0d86b7arobertphillips } 134465706820d0d373f76ab4831c286115ee0d86b7arobertphillips n = (n * 10) + d; 135465706820d0d373f76ab4831c286115ee0d86b7arobertphillips } 136465706820d0d373f76ab4831c286115ee0d86b7arobertphillips *value = n; 137465706820d0d373f76ab4831c286115ee0d86b7arobertphillips return true; 138465706820d0d373f76ab4831c286115ee0d86b7arobertphillips} 139465706820d0d373f76ab4831c286115ee0d86b7arobertphillips 1407fa87cd09f49f1ee9bc27e263038d0f0ae706241bungemanstatic bool memeq(const char* s1, const char* s2, size_t n1, size_t n2) { 1417fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman return n1 == n2 && 0 == memcmp(s1, s2, n1); 1427fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman} 1437fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman#define MEMEQ(c, s, n) memeq(c, s, sizeof(c) - 1, n) 1447fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman 1457fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman#define ATTS_NON_NULL(a, i) (a[i] != NULL && a[i+1] != NULL) 1467fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman 147f61475e95d9bb38f741f9e51221c086250b9ad72bungeman#define SK_FONTCONFIGPARSER_PREFIX "[SkFontConfigParser] " 148f61475e95d9bb38f741f9e51221c086250b9ad72bungeman 149f61475e95d9bb38f741f9e51221c086250b9ad72bungeman#define SK_FONTCONFIGPARSER_WARNING(message, ...) SkDebugf( \ 150f61475e95d9bb38f741f9e51221c086250b9ad72bungeman SK_FONTCONFIGPARSER_PREFIX "%s:%d:%d: warning: " message "\n", \ 151f61475e95d9bb38f741f9e51221c086250b9ad72bungeman self->fFilename, \ 152f61475e95d9bb38f741f9e51221c086250b9ad72bungeman XML_GetCurrentLineNumber(self->fParser), \ 153f61475e95d9bb38f741f9e51221c086250b9ad72bungeman XML_GetCurrentColumnNumber(self->fParser), \ 154f61475e95d9bb38f741f9e51221c086250b9ad72bungeman ##__VA_ARGS__); 155f61475e95d9bb38f741f9e51221c086250b9ad72bungeman 15610b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic bool is_whitespace(char c) { 15710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return c == ' ' || c == '\n'|| c == '\r' || c == '\t'; 15810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman} 159f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson 16010b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic void trim_string(SkString* s) { 16110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman char* str = s->writable_str(); 16210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* start = str; // start is inclusive 16310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* end = start + s->size(); // end is exclusive 16410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman while (is_whitespace(*start)) { ++start; } 16510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (start != end) { 16610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman --end; // make end inclusive 16710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman while (is_whitespace(*end)) { --end; } 16810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman ++end; // make end exclusive 16907544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson } 17010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t len = end - start; 17110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman memmove(str, start, len); 17210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman s->resize(len); 173f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson} 174f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson 17510b063cb91c52fd1f570ee63307fe7e68c1501f1bungemannamespace lmpParser { 176f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson 17710b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic const TagHandler fontHandler = { 17810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*start*/[](FamilyData* self, const char* tag, const char** attributes) { 17910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'weight' (non-negative integer) [default 0] 18010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'style' ("normal", "italic") [default "auto"] 18110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'index' (non-negative integer) [default 0] 18210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // The character data should be a filename. 18310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman FontFileInfo& file = self->fCurrentFamily->fFonts.push_back(); 18410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fCurrentFontInfo = &file; 18510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) { 18610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* name = attributes[i]; 18710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* value = attributes[i+1]; 18810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t nameLen = strlen(name); 18910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("weight", name, nameLen)) { 19010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (!parse_non_negative_integer(value, &file.fWeight)) { 19110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid weight", value); 19210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 19310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("style", name, nameLen)) { 19410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t valueLen = strlen(value); 19510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("normal", value, valueLen)) { 19610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman file.fStyle = FontFileInfo::Style::kNormal; 19710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("italic", value, valueLen)) { 19810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman file.fStyle = FontFileInfo::Style::kItalic; 19910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 20010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("index", name, nameLen)) { 20110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (!parse_non_negative_integer(value, &file.fIndex)) { 20210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid index", value); 20310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 204d3ddea284ec6611a93a6b75e64de39d0bc7e083ctomhudson } 20510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 20610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 20710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*end*/[](FamilyData* self, const char* tag) { 20810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman trim_string(&self->fCurrentFontInfo->fFileName); 20910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 210465706820d0d373f76ab4831c286115ee0d86b7arobertphillips /*tag*/NULL, 21110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*chars*/[](void* data, const char* s, int len) { 21210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman FamilyData* self = static_cast<FamilyData*>(data); 21310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fCurrentFontInfo->fFileName.append(s, len); 21410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 21510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman}; 21610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 21710b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic const TagHandler familyHandler = { 21810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*start*/[](FamilyData* self, const char* tag, const char** attributes) { 21910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'name' (string) [optional] 22010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'lang' (string) [default ""] 22110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'variant' ("elegant", "compact") [default "default"] 22210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // If there is no name, this is a fallback only font. 22310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman FontFamily* family = new FontFamily(self->fBasePath, true); 22410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fCurrentFamily.reset(family); 22510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) { 22610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* name = attributes[i]; 22710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* value = attributes[i+1]; 22810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t nameLen = strlen(name); 229e85a754a4ce9b279159270faa6717932f7a8548fbungeman size_t valueLen = strlen(value); 23010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("name", name, nameLen)) { 23110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SkAutoAsciiToLC tolc(value); 23210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman family->fNames.push_back().set(tolc.lc()); 23310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman family->fIsFallbackFont = false; 23410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("lang", name, nameLen)) { 23510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman family->fLanguage = SkLanguage(value, valueLen); 23610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("variant", name, nameLen)) { 23710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("elegant", value, valueLen)) { 23810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman family->fVariant = kElegant_FontVariant; 23910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("compact", value, valueLen)) { 24010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman family->fVariant = kCompact_FontVariant; 24110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 242b8a1d30a42d13ae83690b2d854a024d9b56e7b71bungeman } 24307544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson } 24410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 24510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*end*/[](FamilyData* self, const char* tag) { 24610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman *self->fFamilies.append() = self->fCurrentFamily.detach(); 24710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 24810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* { 24910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t len = strlen(tag); 25010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("font", tag, len)) { 25110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return &fontHandler; 25210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 25310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return NULL; 25410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 25510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*chars*/NULL, 25610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman}; 25707544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson 258eb2be7fa4413a566212782d8efae5dc225002821bungemanstatic FontFamily* find_family(FamilyData* self, const SkString& familyName) { 2597fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman for (int i = 0; i < self->fFamilies.count(); i++) { 2607fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman FontFamily* candidate = self->fFamilies[i]; 26107544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson for (int j = 0; j < candidate->fNames.count(); j++) { 2627fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman if (candidate->fNames[j] == familyName) { 26307544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson return candidate; 26407544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson } 26507544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson } 26607544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson } 26707544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson return NULL; 26807544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson} 26907544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson 27010b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic const TagHandler aliasHandler = { 27110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*start*/[](FamilyData* self, const char* tag, const char** attributes) { 27210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'name' (string) introduces a new family name. 27310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'to' (string) specifies which (previous) family to alias 27410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'weight' (non-negative integer) [optional] 27510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // If it *does not* have a weight, 'name' is an alias for the entire 'to' family. 27610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // If it *does* have a weight, 'name' is a new family consisting of 27710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // the font(s) with 'weight' from the 'to' family. 27810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 27910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SkString aliasName; 28010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SkString to; 28110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman int weight = 0; 28210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) { 28310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* name = attributes[i]; 28410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* value = attributes[i+1]; 28510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t nameLen = strlen(name); 28610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("name", name, nameLen)) { 28710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SkAutoAsciiToLC tolc(value); 28810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman aliasName.set(tolc.lc()); 28910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("to", name, nameLen)) { 29010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman to.set(value); 29110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("weight", name, nameLen)) { 29210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (!parse_non_negative_integer(value, &weight)) { 29310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid weight", value); 29410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 2957fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman } 29607544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson } 29707544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson 29810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // Assumes that the named family is already declared 29910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman FontFamily* targetFamily = find_family(self, to); 30010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (!targetFamily) { 30110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SK_FONTCONFIGPARSER_WARNING("'%s' alias target not found", to.c_str()); 30210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return; 30310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 30407544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson 30510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (weight) { 30610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman FontFamily* family = new FontFamily(targetFamily->fBasePath, self->fIsFallback); 30710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman family->fNames.push_back().set(aliasName); 30807544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson 30910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman for (int i = 0; i < targetFamily->fFonts.count(); i++) { 31010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (targetFamily->fFonts[i].fWeight == weight) { 31110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman family->fFonts.push_back(targetFamily->fFonts[i]); 31210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 31307544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson } 31410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman *self->fFamilies.append() = family; 31510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else { 31610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman targetFamily->fNames.push_back().set(aliasName); 31707544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson } 31810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 31910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*end*/NULL, 32010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*tag*/NULL, 32110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*chars*/NULL, 32210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman}; 323c0727d117e67844f0c8794cc7eaa49a96a015347bungeman 32410b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic const TagHandler familySetHandler = { 32510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*start*/[](FamilyData* self, const char* tag, const char** attributes) { }, 32610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*end*/NULL, 32710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* { 32810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t len = strlen(tag); 32910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("family", tag, len)) { 33010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return &familyHandler; 33110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("alias", tag, len)) { 33210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return &aliasHandler; 33310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 33410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return NULL; 33510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 33610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*chars*/NULL, 33710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman}; 338f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson 339f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson} // lmpParser 340f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson 341f79673bbae0a662c1428755e2719dadf944e4ba1tomhudsonnamespace jbParser { 342f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson 34310b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic const TagHandler fileHandler = { 34410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*start*/[](FamilyData* self, const char* tag, const char** attributes) { 34510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'variant' ("elegant", "compact") [default "default"] 34610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'lang' (string) [default ""] 34710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'index' (non-negative integer) [default 0] 34810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // The character data should be a filename. 34910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman FontFamily& currentFamily = *self->fCurrentFamily.get(); 35010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman FontFileInfo& newFileInfo = currentFamily.fFonts.push_back(); 35110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (attributes) { 35210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) { 35310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* name = attributes[i]; 35410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* value = attributes[i+1]; 35510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t nameLen = strlen(name); 35610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t valueLen = strlen(value); 35710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("variant", name, nameLen)) { 35810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const FontVariant prevVariant = currentFamily.fVariant; 35910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("elegant", value, valueLen)) { 36010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman currentFamily.fVariant = kElegant_FontVariant; 36110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("compact", value, valueLen)) { 36210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman currentFamily.fVariant = kCompact_FontVariant; 36310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 36410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (currentFamily.fFonts.count() > 1 && currentFamily.fVariant != prevVariant) { 36510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SK_FONTCONFIGPARSER_WARNING("'%s' unexpected variant found\n" 36610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman "Note: Every font file within a family must have identical variants.", 36710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman value); 36810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 36910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 37010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("lang", name, nameLen)) { 37110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SkLanguage prevLang = currentFamily.fLanguage; 37210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman currentFamily.fLanguage = SkLanguage(value, valueLen); 37310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (currentFamily.fFonts.count() > 1 && currentFamily.fLanguage != prevLang) { 37410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SK_FONTCONFIGPARSER_WARNING("'%s' unexpected language found\n" 37510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman "Note: Every font file within a family must have identical languages.", 37610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman value); 37710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 37810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 37910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("index", name, nameLen)) { 38010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (!parse_non_negative_integer(value, &newFileInfo.fIndex)) { 38110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid index", value); 38210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 38310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 384bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 385bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 38610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fCurrentFontInfo = &newFileInfo; 38710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 38810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*end*/NULL, 38910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*tag*/NULL, 39010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*chars*/[](void* data, const char* s, int len) { 39110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman FamilyData* self = static_cast<FamilyData*>(data); 39210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fCurrentFontInfo->fFileName.append(s, len); 393bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 39410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman}; 395bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 39610b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic const TagHandler fileSetHandler = { 39710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*start*/NULL, 39810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*end*/NULL, 39910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* { 40010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t len = strlen(tag); 40110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("file", tag, len)) { 40210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return &fileHandler; 40310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 40410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return NULL; 40510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 40610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*chars*/NULL, 40710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman}; 40810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 40910b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic const TagHandler nameHandler = { 41010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*start*/[](FamilyData* self, const char* tag, const char** attributes) { 41110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // The character data should be a name for the font. 41210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fCurrentFamily->fNames.push_back(); 41310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 41410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*end*/NULL, 41510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*tag*/NULL, 41610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*chars*/[](void* data, const char* s, int len) { 41710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman FamilyData* self = static_cast<FamilyData*>(data); 41810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SkAutoAsciiToLC tolc(s, len); 41910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fCurrentFamily->fNames.back().append(tolc.lc(), len); 42010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 42110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman}; 42210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 42310b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic const TagHandler nameSetHandler = { 42410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*start*/NULL, 42510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*end*/NULL, 42610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* { 42710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t len = strlen(tag); 42810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("name", tag, len)) { 42910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return &nameHandler; 43010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 43110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return NULL; 43210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 43310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*chars*/NULL, 43410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman}; 43510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 43610b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic const TagHandler familyHandler = { 43710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*start*/[](FamilyData* self, const char* tag, const char** attributes) { 43810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fCurrentFamily.reset(new FontFamily(self->fBasePath, self->fIsFallback)); 43910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'order' (non-negative integer) [default -1] 4407fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) { 441f61475e95d9bb38f741f9e51221c086250b9ad72bungeman const char* value = attributes[i+1]; 44210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman parse_non_negative_integer(value, &self->fCurrentFamily->fOrder); 44310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 44410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 44510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*end*/[](FamilyData* self, const char* tag) { 44610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman *self->fFamilies.append() = self->fCurrentFamily.detach(); 44710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 44810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* { 44910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t len = strlen(tag); 45010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("nameset", tag, len)) { 45110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return &nameSetHandler; 45210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("fileset", tag, len)) { 45310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return &fileSetHandler; 45410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 45510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return NULL; 45610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 45710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*chars*/NULL, 45810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman}; 4593b6255493e458c6b2c1412af908581f0bf3f6b70djsollen 46010b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic const TagHandler familySetHandler = { 46110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*start*/NULL, 46210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*end*/NULL, 46310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* { 46410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t len = strlen(tag); 46510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("family", tag, len)) { 46610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return &familyHandler; 46710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 46810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return NULL; 46910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 47010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*chars*/NULL, 47110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman}; 4727fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman 47310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman} // namespace jbParser 47410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 47510b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic const TagHandler topLevelHandler = { 47610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*start*/NULL, 47710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*end*/NULL, 47810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* { 47910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t len = strlen(tag); 48010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("familyset", tag, len)) { 48110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'version' (non-negative integer) [default 0] 48210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) { 48310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* name = attributes[i]; 48410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t nameLen = strlen(name); 48510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("version", name, nameLen)) { 48610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* value = attributes[i+1]; 48710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (parse_non_negative_integer(value, &self->fVersion)) { 48810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (self->fVersion >= 21) { 48910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return &lmpParser::familySetHandler; 49010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 49110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 4928d84c995319dd4a82e4f2054bbd19f968c671ca6bungeman } 493bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 49410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return &jbParser::familySetHandler; 495bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 49610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return NULL; 49710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 49810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*chars*/NULL, 49910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman}; 500bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 50110b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic void XMLCALL start_element_handler(void *data, const char *tag, const char **attributes) { 5027fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman FamilyData* self = static_cast<FamilyData*>(data); 50310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 50410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (!self->fSkip) { 50510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const TagHandler* parent = self->fHandler.top(); 50610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const TagHandler* child = parent->tag ? parent->tag(self, tag, attributes) : NULL; 50710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (child) { 50810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (child->start) { 50910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman child->start(self, tag, attributes); 510bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 51110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fHandler.push(child); 51210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman XML_SetCharacterDataHandler(self->fParser, child->chars); 51310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else { 51410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SK_FONTCONFIGPARSER_WARNING("'%s' tag not recognized, skipping", tag); 51510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman XML_SetCharacterDataHandler(self->fParser, NULL); 51610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fSkip = self->fDepth; 517bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 518bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 51910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 52010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman ++self->fDepth; 521bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com} 522bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 5237fa87cd09f49f1ee9bc27e263038d0f0ae706241bungemanstatic void XMLCALL end_element_handler(void* data, const char* tag) { 5247fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman FamilyData* self = static_cast<FamilyData*>(data); 52510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman --self->fDepth; 52610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 52710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (!self->fSkip) { 52810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const TagHandler* child = self->fHandler.top(); 52910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (child->end) { 53010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman child->end(self, tag); 53110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 53210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fHandler.pop(); 53310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const TagHandler* parent = self->fHandler.top(); 53410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman XML_SetCharacterDataHandler(self->fParser, parent->chars); 535bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 536bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 53710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (self->fSkip == self->fDepth) { 53810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fSkip = 0; 53910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const TagHandler* parent = self->fHandler.top(); 54010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman XML_SetCharacterDataHandler(self->fParser, parent->chars); 54110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 54210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman} 543f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson 5447fa87cd09f49f1ee9bc27e263038d0f0ae706241bungemanstatic void XMLCALL xml_entity_decl_handler(void *data, 5457fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const XML_Char *entityName, 5467fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman int is_parameter_entity, 5477fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const XML_Char *value, 5487fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman int value_length, 5497fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const XML_Char *base, 5507fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const XML_Char *systemId, 5517fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const XML_Char *publicId, 5527fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const XML_Char *notationName) 5537fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman{ 5547fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman FamilyData* self = static_cast<FamilyData*>(data); 555f61475e95d9bb38f741f9e51221c086250b9ad72bungeman SK_FONTCONFIGPARSER_WARNING("'%s' entity declaration found, stopping processing", entityName); 5567fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman XML_StopParser(self->fParser, XML_FALSE); 5577fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman} 5587fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman 559eb2be7fa4413a566212782d8efae5dc225002821bungemanstatic const XML_Memory_Handling_Suite sk_XML_alloc = { 560eb2be7fa4413a566212782d8efae5dc225002821bungeman sk_malloc_throw, 561eb2be7fa4413a566212782d8efae5dc225002821bungeman sk_realloc_throw, 562eb2be7fa4413a566212782d8efae5dc225002821bungeman sk_free 563eb2be7fa4413a566212782d8efae5dc225002821bungeman}; 564eb2be7fa4413a566212782d8efae5dc225002821bungeman 5657fa87cd09f49f1ee9bc27e263038d0f0ae706241bungemantemplate<typename T> struct remove_ptr {typedef T type;}; 5667fa87cd09f49f1ee9bc27e263038d0f0ae706241bungemantemplate<typename T> struct remove_ptr<T*> {typedef T type;}; 5677fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman 568bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com/** 569bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com * This function parses the given filename and stores the results in the given 570efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman * families array. Returns the version of the file, negative if the file does not exist. 571bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com */ 5727fa87cd09f49f1ee9bc27e263038d0f0ae706241bungemanstatic int parse_config_file(const char* filename, SkTDArray<FontFamily*>& families, 5737fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const SkString& basePath, bool isFallback) 5747fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman{ 5757fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman SkFILEStream file(filename); 57650c956791291e7f3cec23721157570b7911336b8djsollen@google.com 577bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com // Some of the files we attempt to parse (in particular, /vendor/etc/fallback_fonts.xml) 578bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com // are optional - failure here is okay because one of these optional files may not exist. 5797fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman if (!file.isValid()) { 580f61475e95d9bb38f741f9e51221c086250b9ad72bungeman SkDebugf(SK_FONTCONFIGPARSER_PREFIX "'%s' could not be opened\n", filename); 581efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman return -1; 582bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 58350c956791291e7f3cec23721157570b7911336b8djsollen@google.com 584eb2be7fa4413a566212782d8efae5dc225002821bungeman SkAutoTCallVProc<remove_ptr<XML_Parser>::type, XML_ParserFree> parser( 585eb2be7fa4413a566212782d8efae5dc225002821bungeman XML_ParserCreate_MM(NULL, &sk_XML_alloc, NULL)); 5867fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman if (!parser) { 587f61475e95d9bb38f741f9e51221c086250b9ad72bungeman SkDebugf(SK_FONTCONFIGPARSER_PREFIX "could not create XML parser\n"); 5887fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman return -1; 5897fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman } 5907fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman 59110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman FamilyData self(parser, families, basePath, isFallback, filename, &topLevelHandler); 5927fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman XML_SetUserData(parser, &self); 5937fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman 5947fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman // Disable entity processing, to inhibit internal entity expansion. See expat CVE-2013-0340 5957fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman XML_SetEntityDeclHandler(parser, xml_entity_decl_handler); 5967fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman 597f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson // Start parsing oldschool; switch these in flight if we detect a newer version of the file. 59810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman XML_SetElementHandler(parser, start_element_handler, end_element_handler); 59950c956791291e7f3cec23721157570b7911336b8djsollen@google.com 600eb2be7fa4413a566212782d8efae5dc225002821bungeman // One would assume it would be faster to have a buffer on the stack and call XML_Parse. 601eb2be7fa4413a566212782d8efae5dc225002821bungeman // But XML_Parse will call XML_GetBuffer anyway and memmove the passed buffer into it. 602eb2be7fa4413a566212782d8efae5dc225002821bungeman // (Unless XML_CONTEXT_BYTES is undefined, but all users define it.) 6039a0808fd8e83128403285f391944850d908d7af0bungeman // In debug, buffer a small odd number of bytes to detect slicing in XML_CharacterDataHandler. 6049a0808fd8e83128403285f391944850d908d7af0bungeman static const int bufferSize = 512 SkDEBUGCODE( - 507); 605bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com bool done = false; 606bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com while (!done) { 607eb2be7fa4413a566212782d8efae5dc225002821bungeman void* buffer = XML_GetBuffer(parser, bufferSize); 608eb2be7fa4413a566212782d8efae5dc225002821bungeman if (!buffer) { 609f61475e95d9bb38f741f9e51221c086250b9ad72bungeman SkDebugf(SK_FONTCONFIGPARSER_PREFIX "could not buffer enough to continue\n"); 610eb2be7fa4413a566212782d8efae5dc225002821bungeman return -1; 611eb2be7fa4413a566212782d8efae5dc225002821bungeman } 612eb2be7fa4413a566212782d8efae5dc225002821bungeman size_t len = file.read(buffer, bufferSize); 6137fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman done = file.isAtEnd(); 614eb2be7fa4413a566212782d8efae5dc225002821bungeman XML_Status status = XML_ParseBuffer(parser, len, done); 6157fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman if (XML_STATUS_ERROR == status) { 6167fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman XML_Error error = XML_GetErrorCode(parser); 6177fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman int line = XML_GetCurrentLineNumber(parser); 6187fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman int column = XML_GetCurrentColumnNumber(parser); 6197fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const XML_LChar* errorString = XML_ErrorString(error); 620f61475e95d9bb38f741f9e51221c086250b9ad72bungeman SkDebugf(SK_FONTCONFIGPARSER_PREFIX "%s:%d:%d error %d: %s.\n", 621f61475e95d9bb38f741f9e51221c086250b9ad72bungeman filename, line, column, error, errorString); 6227fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman return -1; 623bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 624bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 6257fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman return self.fVersion; 626bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com} 627bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 628efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman/** Returns the version of the system font file actually found, negative if none. */ 6297fa87cd09f49f1ee9bc27e263038d0f0ae706241bungemanstatic int append_system_font_families(SkTDArray<FontFamily*>& fontFamilies, 6307fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const SkString& basePath) 6317fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman{ 6327a4747f4f62e4896d8f8469e1939b8191fff8d4etomhudson int initialCount = fontFamilies.count(); 6337fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman int version = parse_config_file(LMP_SYSTEM_FONTS_FILE, fontFamilies, basePath, false); 634efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman if (version < 0 || fontFamilies.count() == initialCount) { 6357fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman version = parse_config_file(OLD_SYSTEM_FONTS_FILE, fontFamilies, basePath, false); 63694fa4b99e2a53e997a90c7808cc5263f1bf40c9ftomhudson } 637efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman return version; 638bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com} 639bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 640a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen/** 641a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen * In some versions of Android prior to Android 4.2 (JellyBean MR1 at API 642a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen * Level 17) the fallback fonts for certain locales were encoded in their own 643a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen * XML files with a suffix that identified the locale. We search the provided 644a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen * directory for those files,add all of their entries to the fallback chain, and 645a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen * include the locale as part of each entry. 646a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen */ 647efbad37180c6b6f90d4b7e96a234e8065d2ec395bungemanstatic void append_fallback_font_families_for_locale(SkTDArray<FontFamily*>& fallbackFonts, 6487fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const char* dir, 6497fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const SkString& basePath) 650efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman{ 651a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen#if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) 652a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen // The framework is beyond Android 4.2 and can therefore skip this function 653a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen return; 654a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen#endif 655a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen 656c3c694342ad393b88cee5885395f182082aa2ebbbungeman SkAutoTCallIProc<DIR, closedir> fontDirectory(opendir(dir)); 657c3c694342ad393b88cee5885395f182082aa2ebbbungeman if (NULL == fontDirectory) { 658c3c694342ad393b88cee5885395f182082aa2ebbbungeman return; 659c3c694342ad393b88cee5885395f182082aa2ebbbungeman } 660a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen 661c3c694342ad393b88cee5885395f182082aa2ebbbungeman for (struct dirent* dirEntry; (dirEntry = readdir(fontDirectory));) { 6629a0808fd8e83128403285f391944850d908d7af0bungeman // The size of the prefix and suffix. 6639a0808fd8e83128403285f391944850d908d7af0bungeman static const size_t fixedLen = sizeof(LOCALE_FALLBACK_FONTS_PREFIX) - 1 6649a0808fd8e83128403285f391944850d908d7af0bungeman + sizeof(LOCALE_FALLBACK_FONTS_SUFFIX) - 1; 6659a0808fd8e83128403285f391944850d908d7af0bungeman 6669a0808fd8e83128403285f391944850d908d7af0bungeman // The size of the prefix, suffix, and a minimum valid language code 6679a0808fd8e83128403285f391944850d908d7af0bungeman static const size_t minSize = fixedLen + 2; 668c3c694342ad393b88cee5885395f182082aa2ebbbungeman 669c3c694342ad393b88cee5885395f182082aa2ebbbungeman SkString fileName(dirEntry->d_name); 670c3c694342ad393b88cee5885395f182082aa2ebbbungeman if (fileName.size() < minSize || 671c3c694342ad393b88cee5885395f182082aa2ebbbungeman !fileName.startsWith(LOCALE_FALLBACK_FONTS_PREFIX) || 672c3c694342ad393b88cee5885395f182082aa2ebbbungeman !fileName.endsWith(LOCALE_FALLBACK_FONTS_SUFFIX)) 673c3c694342ad393b88cee5885395f182082aa2ebbbungeman { 674c3c694342ad393b88cee5885395f182082aa2ebbbungeman continue; 675c3c694342ad393b88cee5885395f182082aa2ebbbungeman } 676a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen 677c3c694342ad393b88cee5885395f182082aa2ebbbungeman SkString locale(fileName.c_str() + sizeof(LOCALE_FALLBACK_FONTS_PREFIX) - 1, 678c3c694342ad393b88cee5885395f182082aa2ebbbungeman fileName.size() - fixedLen); 679a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen 680c3c694342ad393b88cee5885395f182082aa2ebbbungeman SkString absoluteFilename; 681c3c694342ad393b88cee5885395f182082aa2ebbbungeman absoluteFilename.printf("%s/%s", dir, fileName.c_str()); 682a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen 683c3c694342ad393b88cee5885395f182082aa2ebbbungeman SkTDArray<FontFamily*> langSpecificFonts; 684c3c694342ad393b88cee5885395f182082aa2ebbbungeman parse_config_file(absoluteFilename.c_str(), langSpecificFonts, basePath, true); 685a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen 686c3c694342ad393b88cee5885395f182082aa2ebbbungeman for (int i = 0; i < langSpecificFonts.count(); ++i) { 687c3c694342ad393b88cee5885395f182082aa2ebbbungeman FontFamily* family = langSpecificFonts[i]; 688c3c694342ad393b88cee5885395f182082aa2ebbbungeman family->fLanguage = SkLanguage(locale); 689c3c694342ad393b88cee5885395f182082aa2ebbbungeman *fallbackFonts.append() = family; 690a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen } 691a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen } 692a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen} 693a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen 6947fa87cd09f49f1ee9bc27e263038d0f0ae706241bungemanstatic void append_system_fallback_font_families(SkTDArray<FontFamily*>& fallbackFonts, 6957fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const SkString& basePath) 6967fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman{ 6977fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman parse_config_file(FALLBACK_FONTS_FILE, fallbackFonts, basePath, true); 6987fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman append_fallback_font_families_for_locale(fallbackFonts, 6997fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman LOCALE_FALLBACK_FONTS_SYSTEM_DIR, 7007fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman basePath); 701efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman} 702bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 7037fa87cd09f49f1ee9bc27e263038d0f0ae706241bungemanstatic void mixin_vendor_fallback_font_families(SkTDArray<FontFamily*>& fallbackFonts, 7047fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const SkString& basePath) 7057fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman{ 706efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman SkTDArray<FontFamily*> vendorFonts; 7077fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman parse_config_file(VENDOR_FONTS_FILE, vendorFonts, basePath, true); 7087fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman append_fallback_font_families_for_locale(vendorFonts, 7097fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman LOCALE_FALLBACK_FONTS_VENDOR_DIR, 7107fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman basePath); 711a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen 712bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com // This loop inserts the vendor fallback fonts in the correct order in the 713bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com // overall fallbacks list. 714bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com int currentOrder = -1; 715bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com for (int i = 0; i < vendorFonts.count(); ++i) { 716bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com FontFamily* family = vendorFonts[i]; 717d3ddea284ec6611a93a6b75e64de39d0bc7e083ctomhudson int order = family->fOrder; 718bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com if (order < 0) { 719bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com if (currentOrder < 0) { 720bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com // Default case - just add it to the end of the fallback list 721bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com *fallbackFonts.append() = family; 722bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } else { 723bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com // no order specified on this font, but we're incrementing the order 724bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com // based on an earlier order insertion request 725bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com *fallbackFonts.insert(currentOrder++) = family; 726bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 727bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } else { 728bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com // Add the font into the fallback list in the specified order. Set 729bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com // currentOrder for correct placement of other fonts in the vendor list. 730bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com *fallbackFonts.insert(order) = family; 731bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com currentOrder = order + 1; 732bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 733bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 734bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com} 735bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 7367fa87cd09f49f1ee9bc27e263038d0f0ae706241bungemanvoid SkFontConfigParser::GetSystemFontFamilies(SkTDArray<FontFamily*>& fontFamilies) { 737efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman // Version 21 of the system font configuration does not need any fallback configuration files. 7387fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman SkString basePath(getenv("ANDROID_ROOT")); 7397fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman basePath.append(SK_FONT_FILE_PREFIX, sizeof(SK_FONT_FILE_PREFIX) - 1); 7407fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman 7417fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman if (append_system_font_families(fontFamilies, basePath) >= 21) { 742efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman return; 743efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman } 744bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 745bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com // Append all the fallback fonts to system fonts 746bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com SkTDArray<FontFamily*> fallbackFonts; 7477fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman append_system_fallback_font_families(fallbackFonts, basePath); 7487fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman mixin_vendor_fallback_font_families(fallbackFonts, basePath); 7497fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman fontFamilies.append(fallbackFonts.count(), fallbackFonts.begin()); 750bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com} 751bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 7527fa87cd09f49f1ee9bc27e263038d0f0ae706241bungemanvoid SkFontConfigParser::GetCustomFontFamilies(SkTDArray<FontFamily*>& fontFamilies, 7537fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const SkString& basePath, 7547fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const char* fontsXml, 755c3c694342ad393b88cee5885395f182082aa2ebbbungeman const char* fallbackFontsXml, 756c3c694342ad393b88cee5885395f182082aa2ebbbungeman const char* langFallbackFontsDir) 7577fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman{ 7587fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman if (fontsXml) { 7597fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman parse_config_file(fontsXml, fontFamilies, basePath, false); 760f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson } 7617fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman if (fallbackFontsXml) { 7627fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman parse_config_file(fallbackFontsXml, fontFamilies, basePath, true); 763bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 764c3c694342ad393b88cee5885395f182082aa2ebbbungeman if (langFallbackFontsDir) { 765c3c694342ad393b88cee5885395f182082aa2ebbbungeman append_fallback_font_families_for_locale(fontFamilies, 766c3c694342ad393b88cee5885395f182082aa2ebbbungeman langFallbackFontsDir, 767c3c694342ad393b88cee5885395f182082aa2ebbbungeman basePath); 768c3c694342ad393b88cee5885395f182082aa2ebbbungeman } 769bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com} 7703b6255493e458c6b2c1412af908581f0bf3f6b70djsollen 7713b6255493e458c6b2c1412af908581f0bf3f6b70djsollenSkLanguage SkLanguage::getParent() const { 7723b6255493e458c6b2c1412af908581f0bf3f6b70djsollen SkASSERT(!fTag.isEmpty()); 7733b6255493e458c6b2c1412af908581f0bf3f6b70djsollen const char* tag = fTag.c_str(); 7743b6255493e458c6b2c1412af908581f0bf3f6b70djsollen 7753b6255493e458c6b2c1412af908581f0bf3f6b70djsollen // strip off the rightmost "-.*" 7763b6255493e458c6b2c1412af908581f0bf3f6b70djsollen const char* parentTagEnd = strrchr(tag, '-'); 7773b6255493e458c6b2c1412af908581f0bf3f6b70djsollen if (parentTagEnd == NULL) { 7783b6255493e458c6b2c1412af908581f0bf3f6b70djsollen return SkLanguage(); 7793b6255493e458c6b2c1412af908581f0bf3f6b70djsollen } 7803b6255493e458c6b2c1412af908581f0bf3f6b70djsollen size_t parentTagLen = parentTagEnd - tag; 7813b6255493e458c6b2c1412af908581f0bf3f6b70djsollen return SkLanguage(tag, parentTagLen); 7823b6255493e458c6b2c1412af908581f0bf3f6b70djsollen} 783