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 81ee76510f5dbf632d30975fc3509ef4f609156d2mtklein// Despite the name and location, this is portable code. 91ee76510f5dbf632d30975fc3509ef4f609156d2mtklein 1047a1e96b957b50662274360f1a390d76ab3d02ccbungeman#include "SkFontMgr.h" 11c53085413e0b4704aa89cc18396613d59e6ccb4dbungeman#include "SkFontMgr_android_parser.h" 127fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman#include "SkStream.h" 13bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com#include "SkTDArray.h" 148d84c995319dd4a82e4f2054bbd19f968c671ca6bungeman#include "SkTSearch.h" 15f20488b4f2139e6ca09fee7e39b731dd8ab467dbbungeman#include "SkTemplates.h" 1654e63082191f337084f96083ca90d7c35273d6ffbungeman#include "SkTLogic.h" 17bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 18a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen#include <dirent.h> 19f20488b4f2139e6ca09fee7e39b731dd8ab467dbbungeman#include <expat.h> 20bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 217fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman#include <stdlib.h> 22f20488b4f2139e6ca09fee7e39b731dd8ab467dbbungeman#include <string.h> 238d84c995319dd4a82e4f2054bbd19f968c671ca6bungeman 2494fa4b99e2a53e997a90c7808cc5263f1bf40c9ftomhudson#define LMP_SYSTEM_FONTS_FILE "/system/etc/fonts.xml" 2594fa4b99e2a53e997a90c7808cc5263f1bf40c9ftomhudson#define OLD_SYSTEM_FONTS_FILE "/system/etc/system_fonts.xml" 26bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com#define FALLBACK_FONTS_FILE "/system/etc/fallback_fonts.xml" 27bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com#define VENDOR_FONTS_FILE "/vendor/etc/fallback_fonts.xml" 28bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 29a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen#define LOCALE_FALLBACK_FONTS_SYSTEM_DIR "/system/etc" 30a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen#define LOCALE_FALLBACK_FONTS_VENDOR_DIR "/vendor/etc" 31a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen#define LOCALE_FALLBACK_FONTS_PREFIX "fallback_fonts-" 32a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen#define LOCALE_FALLBACK_FONTS_SUFFIX ".xml" 33a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen 347fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman#ifndef SK_FONT_FILE_PREFIX 357fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman# define SK_FONT_FILE_PREFIX "/fonts/" 367fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman#endif 377fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman 38f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson/** 3910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * This file contains TWO 'familyset' handlers: 4010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * One for JB and earlier which works with 4110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * /system/etc/system_fonts.xml 4210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * /system/etc/fallback_fonts.xml 4310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * /vendor/etc/fallback_fonts.xml 4410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * /system/etc/fallback_fonts-XX.xml 4510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * /vendor/etc/fallback_fonts-XX.xml 4610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * and the other for LMP and later which works with 4710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * /system/etc/fonts.xml 4810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * 4910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * If the 'familyset' 'version' attribute is 21 or higher the LMP parser is used, otherwise the JB. 50f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson */ 51f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson 5210b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstruct FamilyData; 5310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 5410b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstruct TagHandler { 5510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /** Called at the start tag. 5610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * Called immediately after the parent tag retuns this handler from a call to 'tag'. 5710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * Allows setting up for handling the tag content and processing attributes. 5896fcdcc219d2a0d3579719b84b28bede76efba64halcanary * If nullptr, will not be called. 5910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman */ 6010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman void (*start)(FamilyData* data, const char* tag, const char** attributes); 6110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 6210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /** Called at the end tag. 6310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * Allows post-processing of any accumulated information. 6410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * This will be the last call made in relation to the current tag. 6596fcdcc219d2a0d3579719b84b28bede76efba64halcanary * If nullptr, will not be called. 6610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman */ 6710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman void (*end)(FamilyData* data, const char* tag); 6810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 6910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /** Called when a nested tag is encountered. 7010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * This is responsible for determining how to handle the tag. 7196fcdcc219d2a0d3579719b84b28bede76efba64halcanary * If the tag is not recognized, return nullptr to skip the tag. 7296fcdcc219d2a0d3579719b84b28bede76efba64halcanary * If nullptr, all nested tags will be skipped. 7310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman */ 7410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const TagHandler* (*tag)(FamilyData* data, const char* tag, const char** attributes); 7510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 7610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /** The character handler for this tag. 7710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * This is only active for character data contained directly in this tag (not sub-tags). 7810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * The first parameter will be castable to a FamilyData*. 7996fcdcc219d2a0d3579719b84b28bede76efba64halcanary * If nullptr, any character data in this tag will be ignored. 8010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman */ 8110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman XML_CharacterDataHandler chars; 827fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman}; 83bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 8410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman/** Represents the current parsing state. */ 85bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.comstruct FamilyData { 867fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman FamilyData(XML_Parser parser, SkTDArray<FontFamily*>& families, 8710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const SkString& basePath, bool isFallback, const char* filename, 8810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const TagHandler* topLevelHandler) 89b6bed17ea81ff8fad68a7db79307bdcbcd4738a8bungeman : fParser(parser) 90b6bed17ea81ff8fad68a7db79307bdcbcd4738a8bungeman , fFamilies(families) 9196fcdcc219d2a0d3579719b84b28bede76efba64halcanary , fCurrentFamily(nullptr) 9296fcdcc219d2a0d3579719b84b28bede76efba64halcanary , fCurrentFontInfo(nullptr) 93efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman , fVersion(0) 947fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman , fBasePath(basePath) 957fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman , fIsFallback(isFallback) 96f61475e95d9bb38f741f9e51221c086250b9ad72bungeman , fFilename(filename) 9710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman , fDepth(1) 9810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman , fSkip(0) 9910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman , fHandler(&topLevelHandler, 1) 1007fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman { }; 101b6bed17ea81ff8fad68a7db79307bdcbcd4738a8bungeman 102b6bed17ea81ff8fad68a7db79307bdcbcd4738a8bungeman XML_Parser fParser; // The expat parser doing the work, owned by caller 103b6bed17ea81ff8fad68a7db79307bdcbcd4738a8bungeman SkTDArray<FontFamily*>& fFamilies; // The array to append families, owned by caller 104b6bed17ea81ff8fad68a7db79307bdcbcd4738a8bungeman SkAutoTDelete<FontFamily> fCurrentFamily; // The family being created, owned by this 1057fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman FontFileInfo* fCurrentFontInfo; // The fontInfo being created, owned by fCurrentFamily 106efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman int fVersion; // The version of the file parsed. 1077fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const SkString& fBasePath; // The current base path. 1087fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const bool fIsFallback; // Indicates the file being parsed is a fallback file 109f61475e95d9bb38f741f9e51221c086250b9ad72bungeman const char* fFilename; // The name of the file currently being parsed. 11010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 11110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman int fDepth; // The current element depth of the parse. 11210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman int fSkip; // The depth to stop skipping, 0 if not skipping. 11310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SkTDArray<const TagHandler*> fHandler; // The stack of current tag handlers. 114bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com}; 115bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 1167fa87cd09f49f1ee9bc27e263038d0f0ae706241bungemanstatic bool memeq(const char* s1, const char* s2, size_t n1, size_t n2) { 1177fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman return n1 == n2 && 0 == memcmp(s1, s2, n1); 1187fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman} 1197fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman#define MEMEQ(c, s, n) memeq(c, s, sizeof(c) - 1, n) 1207fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman 12196fcdcc219d2a0d3579719b84b28bede76efba64halcanary#define ATTS_NON_NULL(a, i) (a[i] != nullptr && a[i+1] != nullptr) 1227fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman 123c53085413e0b4704aa89cc18396613d59e6ccb4dbungeman#define SK_FONTMGR_ANDROID_PARSER_PREFIX "[SkFontMgr Android Parser] " 124f61475e95d9bb38f741f9e51221c086250b9ad72bungeman 125f61475e95d9bb38f741f9e51221c086250b9ad72bungeman#define SK_FONTCONFIGPARSER_WARNING(message, ...) SkDebugf( \ 126c53085413e0b4704aa89cc18396613d59e6ccb4dbungeman SK_FONTMGR_ANDROID_PARSER_PREFIX "%s:%d:%d: warning: " message "\n", \ 127f61475e95d9bb38f741f9e51221c086250b9ad72bungeman self->fFilename, \ 128f61475e95d9bb38f741f9e51221c086250b9ad72bungeman XML_GetCurrentLineNumber(self->fParser), \ 129f61475e95d9bb38f741f9e51221c086250b9ad72bungeman XML_GetCurrentColumnNumber(self->fParser), \ 130f61475e95d9bb38f741f9e51221c086250b9ad72bungeman ##__VA_ARGS__); 131f61475e95d9bb38f741f9e51221c086250b9ad72bungeman 13210b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic bool is_whitespace(char c) { 13310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return c == ' ' || c == '\n'|| c == '\r' || c == '\t'; 13410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman} 135f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson 13610b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic void trim_string(SkString* s) { 13710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman char* str = s->writable_str(); 13810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* start = str; // start is inclusive 13910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* end = start + s->size(); // end is exclusive 14010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman while (is_whitespace(*start)) { ++start; } 14110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (start != end) { 14210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman --end; // make end inclusive 14310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman while (is_whitespace(*end)) { --end; } 14410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman ++end; // make end exclusive 14507544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson } 14610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t len = end - start; 14710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman memmove(str, start, len); 14810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman s->resize(len); 149f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson} 150f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson 15110b063cb91c52fd1f570ee63307fe7e68c1501f1bungemannamespace lmpParser { 152f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson 15341868fe5625fc3bd70daa3f461c881b5db6a9265bungemanstatic const TagHandler axisHandler = { 15441868fe5625fc3bd70daa3f461c881b5db6a9265bungeman /*start*/[](FamilyData* self, const char* tag, const char** attributes) { 15541868fe5625fc3bd70daa3f461c881b5db6a9265bungeman FontFileInfo& file = *self->fCurrentFontInfo; 15647a1e96b957b50662274360f1a390d76ab3d02ccbungeman SkFourByteTag axisTag = SkSetFourByteTag('\0','\0','\0','\0'); 15747a1e96b957b50662274360f1a390d76ab3d02ccbungeman SkFixed axisStyleValue = 0; 15847a1e96b957b50662274360f1a390d76ab3d02ccbungeman bool axisTagIsValid = false; 15947a1e96b957b50662274360f1a390d76ab3d02ccbungeman bool axisStyleValueIsValid = false; 16041868fe5625fc3bd70daa3f461c881b5db6a9265bungeman for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) { 16141868fe5625fc3bd70daa3f461c881b5db6a9265bungeman const char* name = attributes[i]; 16241868fe5625fc3bd70daa3f461c881b5db6a9265bungeman const char* value = attributes[i+1]; 16341868fe5625fc3bd70daa3f461c881b5db6a9265bungeman size_t nameLen = strlen(name); 16441868fe5625fc3bd70daa3f461c881b5db6a9265bungeman if (MEMEQ("tag", name, nameLen)) { 16541868fe5625fc3bd70daa3f461c881b5db6a9265bungeman size_t valueLen = strlen(value); 16641868fe5625fc3bd70daa3f461c881b5db6a9265bungeman if (valueLen == 4) { 16747a1e96b957b50662274360f1a390d76ab3d02ccbungeman axisTag = SkSetFourByteTag(value[0], value[1], value[2], value[3]); 16847a1e96b957b50662274360f1a390d76ab3d02ccbungeman axisTagIsValid = true; 16941868fe5625fc3bd70daa3f461c881b5db6a9265bungeman for (int j = 0; j < file.fAxes.count() - 1; ++j) { 17047a1e96b957b50662274360f1a390d76ab3d02ccbungeman if (file.fAxes[j].fTag == axisTag) { 17147a1e96b957b50662274360f1a390d76ab3d02ccbungeman axisTagIsValid = false; 17241868fe5625fc3bd70daa3f461c881b5db6a9265bungeman SK_FONTCONFIGPARSER_WARNING("'%c%c%c%c' axis specified more than once", 17347a1e96b957b50662274360f1a390d76ab3d02ccbungeman (axisTag >> 24) & 0xFF, 17447a1e96b957b50662274360f1a390d76ab3d02ccbungeman (axisTag >> 16) & 0xFF, 17547a1e96b957b50662274360f1a390d76ab3d02ccbungeman (axisTag >> 8) & 0xFF, 17647a1e96b957b50662274360f1a390d76ab3d02ccbungeman (axisTag ) & 0xFF); 17741868fe5625fc3bd70daa3f461c881b5db6a9265bungeman } 17841868fe5625fc3bd70daa3f461c881b5db6a9265bungeman } 17941868fe5625fc3bd70daa3f461c881b5db6a9265bungeman } else { 18041868fe5625fc3bd70daa3f461c881b5db6a9265bungeman SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid axis tag", value); 18141868fe5625fc3bd70daa3f461c881b5db6a9265bungeman } 18241868fe5625fc3bd70daa3f461c881b5db6a9265bungeman } else if (MEMEQ("stylevalue", name, nameLen)) { 18347a1e96b957b50662274360f1a390d76ab3d02ccbungeman if (parse_fixed<16>(value, &axisStyleValue)) { 18447a1e96b957b50662274360f1a390d76ab3d02ccbungeman axisStyleValueIsValid = true; 18547a1e96b957b50662274360f1a390d76ab3d02ccbungeman } else { 18641868fe5625fc3bd70daa3f461c881b5db6a9265bungeman SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid axis stylevalue", value); 18741868fe5625fc3bd70daa3f461c881b5db6a9265bungeman } 18841868fe5625fc3bd70daa3f461c881b5db6a9265bungeman } 18941868fe5625fc3bd70daa3f461c881b5db6a9265bungeman } 19047a1e96b957b50662274360f1a390d76ab3d02ccbungeman if (axisTagIsValid && axisStyleValueIsValid) { 19147a1e96b957b50662274360f1a390d76ab3d02ccbungeman SkFontMgr::FontParameters::Axis& axis = file.fAxes.push_back(); 19247a1e96b957b50662274360f1a390d76ab3d02ccbungeman axis.fTag = axisTag; 19347a1e96b957b50662274360f1a390d76ab3d02ccbungeman axis.fStyleValue = SkFixedToScalar(axisStyleValue); 19447a1e96b957b50662274360f1a390d76ab3d02ccbungeman } 19541868fe5625fc3bd70daa3f461c881b5db6a9265bungeman }, 19696fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*end*/nullptr, 19796fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*tag*/nullptr, 19896fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*chars*/nullptr, 19941868fe5625fc3bd70daa3f461c881b5db6a9265bungeman}; 20041868fe5625fc3bd70daa3f461c881b5db6a9265bungeman 20110b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic const TagHandler fontHandler = { 20210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*start*/[](FamilyData* self, const char* tag, const char** attributes) { 20310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'weight' (non-negative integer) [default 0] 20410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'style' ("normal", "italic") [default "auto"] 20510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'index' (non-negative integer) [default 0] 20610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // The character data should be a filename. 20710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman FontFileInfo& file = self->fCurrentFamily->fFonts.push_back(); 20810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fCurrentFontInfo = &file; 20910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) { 21010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* name = attributes[i]; 21110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* value = attributes[i+1]; 21210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t nameLen = strlen(name); 21310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("weight", name, nameLen)) { 21410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (!parse_non_negative_integer(value, &file.fWeight)) { 21510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid weight", value); 21610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 21710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("style", name, nameLen)) { 21810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t valueLen = strlen(value); 21910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("normal", value, valueLen)) { 22010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman file.fStyle = FontFileInfo::Style::kNormal; 22110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("italic", value, valueLen)) { 22210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman file.fStyle = FontFileInfo::Style::kItalic; 22310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 22410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("index", name, nameLen)) { 22510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (!parse_non_negative_integer(value, &file.fIndex)) { 22610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid index", value); 22710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 228d3ddea284ec6611a93a6b75e64de39d0bc7e083ctomhudson } 22910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 23010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 23110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*end*/[](FamilyData* self, const char* tag) { 23210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman trim_string(&self->fCurrentFontInfo->fFileName); 23310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 23441868fe5625fc3bd70daa3f461c881b5db6a9265bungeman /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* { 23541868fe5625fc3bd70daa3f461c881b5db6a9265bungeman size_t len = strlen(tag); 23641868fe5625fc3bd70daa3f461c881b5db6a9265bungeman if (MEMEQ("axis", tag, len)) { 23741868fe5625fc3bd70daa3f461c881b5db6a9265bungeman return &axisHandler; 23841868fe5625fc3bd70daa3f461c881b5db6a9265bungeman } 23996fcdcc219d2a0d3579719b84b28bede76efba64halcanary return nullptr; 24041868fe5625fc3bd70daa3f461c881b5db6a9265bungeman }, 24110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*chars*/[](void* data, const char* s, int len) { 24210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman FamilyData* self = static_cast<FamilyData*>(data); 24310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fCurrentFontInfo->fFileName.append(s, len); 24410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 24510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman}; 24610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 24710b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic const TagHandler familyHandler = { 24810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*start*/[](FamilyData* self, const char* tag, const char** attributes) { 24910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'name' (string) [optional] 25010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'lang' (string) [default ""] 25110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'variant' ("elegant", "compact") [default "default"] 25210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // If there is no name, this is a fallback only font. 25310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman FontFamily* family = new FontFamily(self->fBasePath, true); 25410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fCurrentFamily.reset(family); 25510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) { 25610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* name = attributes[i]; 25710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* value = attributes[i+1]; 25810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t nameLen = strlen(name); 259e85a754a4ce9b279159270faa6717932f7a8548fbungeman size_t valueLen = strlen(value); 26010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("name", name, nameLen)) { 26110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SkAutoAsciiToLC tolc(value); 26210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman family->fNames.push_back().set(tolc.lc()); 26310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman family->fIsFallbackFont = false; 26410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("lang", name, nameLen)) { 26510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman family->fLanguage = SkLanguage(value, valueLen); 26610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("variant", name, nameLen)) { 26710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("elegant", value, valueLen)) { 26810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman family->fVariant = kElegant_FontVariant; 26910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("compact", value, valueLen)) { 27010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman family->fVariant = kCompact_FontVariant; 27110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 272b8a1d30a42d13ae83690b2d854a024d9b56e7b71bungeman } 27307544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson } 27410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 27510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*end*/[](FamilyData* self, const char* tag) { 27610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman *self->fFamilies.append() = self->fCurrentFamily.detach(); 27710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 27810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* { 27910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t len = strlen(tag); 28010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("font", tag, len)) { 28110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return &fontHandler; 28210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 28396fcdcc219d2a0d3579719b84b28bede76efba64halcanary return nullptr; 28410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 28596fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*chars*/nullptr, 28610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman}; 28707544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson 288eb2be7fa4413a566212782d8efae5dc225002821bungemanstatic FontFamily* find_family(FamilyData* self, const SkString& familyName) { 2897fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman for (int i = 0; i < self->fFamilies.count(); i++) { 2907fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman FontFamily* candidate = self->fFamilies[i]; 29107544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson for (int j = 0; j < candidate->fNames.count(); j++) { 2927fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman if (candidate->fNames[j] == familyName) { 29307544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson return candidate; 29407544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson } 29507544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson } 29607544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson } 29796fcdcc219d2a0d3579719b84b28bede76efba64halcanary return nullptr; 29807544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson} 29907544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson 30010b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic const TagHandler aliasHandler = { 30110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*start*/[](FamilyData* self, const char* tag, const char** attributes) { 30210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'name' (string) introduces a new family name. 30310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'to' (string) specifies which (previous) family to alias 30410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'weight' (non-negative integer) [optional] 30510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // If it *does not* have a weight, 'name' is an alias for the entire 'to' family. 30610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // If it *does* have a weight, 'name' is a new family consisting of 30710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // the font(s) with 'weight' from the 'to' family. 30810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 30910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SkString aliasName; 31010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SkString to; 31110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman int weight = 0; 31210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) { 31310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* name = attributes[i]; 31410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* value = attributes[i+1]; 31510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t nameLen = strlen(name); 31610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("name", name, nameLen)) { 31710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SkAutoAsciiToLC tolc(value); 31810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman aliasName.set(tolc.lc()); 31910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("to", name, nameLen)) { 32010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman to.set(value); 32110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("weight", name, nameLen)) { 32210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (!parse_non_negative_integer(value, &weight)) { 32310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid weight", value); 32410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 3257fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman } 32607544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson } 32707544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson 32810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // Assumes that the named family is already declared 32910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman FontFamily* targetFamily = find_family(self, to); 33010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (!targetFamily) { 33110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SK_FONTCONFIGPARSER_WARNING("'%s' alias target not found", to.c_str()); 33210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return; 33310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 33407544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson 33510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (weight) { 33610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman FontFamily* family = new FontFamily(targetFamily->fBasePath, self->fIsFallback); 33710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman family->fNames.push_back().set(aliasName); 33807544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson 33910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman for (int i = 0; i < targetFamily->fFonts.count(); i++) { 34010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (targetFamily->fFonts[i].fWeight == weight) { 34110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman family->fFonts.push_back(targetFamily->fFonts[i]); 34210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 34307544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson } 34410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman *self->fFamilies.append() = family; 34510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else { 34610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman targetFamily->fNames.push_back().set(aliasName); 34707544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson } 34810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 34996fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*end*/nullptr, 35096fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*tag*/nullptr, 35196fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*chars*/nullptr, 35210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman}; 353c0727d117e67844f0c8794cc7eaa49a96a015347bungeman 35410b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic const TagHandler familySetHandler = { 35510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*start*/[](FamilyData* self, const char* tag, const char** attributes) { }, 35696fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*end*/nullptr, 35710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* { 35810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t len = strlen(tag); 35910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("family", tag, len)) { 36010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return &familyHandler; 36110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("alias", tag, len)) { 36210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return &aliasHandler; 36310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 36496fcdcc219d2a0d3579719b84b28bede76efba64halcanary return nullptr; 36510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 36696fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*chars*/nullptr, 36710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman}; 368f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson 369f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson} // lmpParser 370f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson 371f79673bbae0a662c1428755e2719dadf944e4ba1tomhudsonnamespace jbParser { 372f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson 37310b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic const TagHandler fileHandler = { 37410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*start*/[](FamilyData* self, const char* tag, const char** attributes) { 37510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'variant' ("elegant", "compact") [default "default"] 37610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'lang' (string) [default ""] 37710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'index' (non-negative integer) [default 0] 37810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // The character data should be a filename. 37910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman FontFamily& currentFamily = *self->fCurrentFamily.get(); 38010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman FontFileInfo& newFileInfo = currentFamily.fFonts.push_back(); 38110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (attributes) { 38210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) { 38310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* name = attributes[i]; 38410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* value = attributes[i+1]; 38510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t nameLen = strlen(name); 38610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t valueLen = strlen(value); 38710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("variant", name, nameLen)) { 38810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const FontVariant prevVariant = currentFamily.fVariant; 38910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("elegant", value, valueLen)) { 39010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman currentFamily.fVariant = kElegant_FontVariant; 39110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("compact", value, valueLen)) { 39210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman currentFamily.fVariant = kCompact_FontVariant; 39310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 39410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (currentFamily.fFonts.count() > 1 && currentFamily.fVariant != prevVariant) { 39510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SK_FONTCONFIGPARSER_WARNING("'%s' unexpected variant found\n" 39610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman "Note: Every font file within a family must have identical variants.", 39710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman value); 39810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 39910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 40010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("lang", name, nameLen)) { 40110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SkLanguage prevLang = currentFamily.fLanguage; 40210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman currentFamily.fLanguage = SkLanguage(value, valueLen); 40310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (currentFamily.fFonts.count() > 1 && currentFamily.fLanguage != prevLang) { 40410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SK_FONTCONFIGPARSER_WARNING("'%s' unexpected language found\n" 40510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman "Note: Every font file within a family must have identical languages.", 40610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman value); 40710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 40810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 40910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("index", name, nameLen)) { 41010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (!parse_non_negative_integer(value, &newFileInfo.fIndex)) { 41110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid index", value); 41210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 41310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 414bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 415bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 41610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fCurrentFontInfo = &newFileInfo; 41710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 41896fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*end*/nullptr, 41996fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*tag*/nullptr, 42010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*chars*/[](void* data, const char* s, int len) { 42110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman FamilyData* self = static_cast<FamilyData*>(data); 42210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fCurrentFontInfo->fFileName.append(s, len); 423bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 42410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman}; 425bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 42610b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic const TagHandler fileSetHandler = { 42796fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*start*/nullptr, 42896fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*end*/nullptr, 42910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* { 43010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t len = strlen(tag); 43110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("file", tag, len)) { 43210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return &fileHandler; 43310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 43496fcdcc219d2a0d3579719b84b28bede76efba64halcanary return nullptr; 43510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 43696fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*chars*/nullptr, 43710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman}; 43810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 43910b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic const TagHandler nameHandler = { 44010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*start*/[](FamilyData* self, const char* tag, const char** attributes) { 44110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // The character data should be a name for the font. 44210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fCurrentFamily->fNames.push_back(); 44310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 44496fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*end*/nullptr, 44596fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*tag*/nullptr, 44610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*chars*/[](void* data, const char* s, int len) { 44710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman FamilyData* self = static_cast<FamilyData*>(data); 44810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SkAutoAsciiToLC tolc(s, len); 44910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fCurrentFamily->fNames.back().append(tolc.lc(), len); 45010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 45110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman}; 45210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 45310b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic const TagHandler nameSetHandler = { 45496fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*start*/nullptr, 45596fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*end*/nullptr, 45610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* { 45710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t len = strlen(tag); 45810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("name", tag, len)) { 45910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return &nameHandler; 46010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 46196fcdcc219d2a0d3579719b84b28bede76efba64halcanary return nullptr; 46210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 46396fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*chars*/nullptr, 46410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman}; 46510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 46610b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic const TagHandler familyHandler = { 46710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*start*/[](FamilyData* self, const char* tag, const char** attributes) { 46810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fCurrentFamily.reset(new FontFamily(self->fBasePath, self->fIsFallback)); 46910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'order' (non-negative integer) [default -1] 4707fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) { 471f61475e95d9bb38f741f9e51221c086250b9ad72bungeman const char* value = attributes[i+1]; 47210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman parse_non_negative_integer(value, &self->fCurrentFamily->fOrder); 47310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 47410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 47510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*end*/[](FamilyData* self, const char* tag) { 47610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman *self->fFamilies.append() = self->fCurrentFamily.detach(); 47710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 47810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* { 47910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t len = strlen(tag); 48010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("nameset", tag, len)) { 48110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return &nameSetHandler; 48210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("fileset", tag, len)) { 48310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return &fileSetHandler; 48410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 48596fcdcc219d2a0d3579719b84b28bede76efba64halcanary return nullptr; 48610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 48796fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*chars*/nullptr, 48810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman}; 4893b6255493e458c6b2c1412af908581f0bf3f6b70djsollen 49010b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic const TagHandler familySetHandler = { 49196fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*start*/nullptr, 49296fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*end*/nullptr, 49310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* { 49410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t len = strlen(tag); 49510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("family", tag, len)) { 49610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return &familyHandler; 49710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 49896fcdcc219d2a0d3579719b84b28bede76efba64halcanary return nullptr; 49910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 50096fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*chars*/nullptr, 50110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman}; 5027fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman 50310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman} // namespace jbParser 50410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 50510b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic const TagHandler topLevelHandler = { 50696fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*start*/nullptr, 50796fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*end*/nullptr, 50810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* { 50910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t len = strlen(tag); 51010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("familyset", tag, len)) { 51110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'version' (non-negative integer) [default 0] 51210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) { 51310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* name = attributes[i]; 51410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t nameLen = strlen(name); 51510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("version", name, nameLen)) { 51610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* value = attributes[i+1]; 51710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (parse_non_negative_integer(value, &self->fVersion)) { 51810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (self->fVersion >= 21) { 51910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return &lmpParser::familySetHandler; 52010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 52110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 5228d84c995319dd4a82e4f2054bbd19f968c671ca6bungeman } 523bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 52410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return &jbParser::familySetHandler; 525bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 52696fcdcc219d2a0d3579719b84b28bede76efba64halcanary return nullptr; 52710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 52896fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*chars*/nullptr, 52910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman}; 530bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 53110b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic void XMLCALL start_element_handler(void *data, const char *tag, const char **attributes) { 5327fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman FamilyData* self = static_cast<FamilyData*>(data); 53310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 53410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (!self->fSkip) { 53510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const TagHandler* parent = self->fHandler.top(); 53696fcdcc219d2a0d3579719b84b28bede76efba64halcanary const TagHandler* child = parent->tag ? parent->tag(self, tag, attributes) : nullptr; 53710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (child) { 53810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (child->start) { 53910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman child->start(self, tag, attributes); 540bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 54110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fHandler.push(child); 54210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman XML_SetCharacterDataHandler(self->fParser, child->chars); 54310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else { 54410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SK_FONTCONFIGPARSER_WARNING("'%s' tag not recognized, skipping", tag); 54596fcdcc219d2a0d3579719b84b28bede76efba64halcanary XML_SetCharacterDataHandler(self->fParser, nullptr); 54610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fSkip = self->fDepth; 547bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 548bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 54910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 55010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman ++self->fDepth; 551bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com} 552bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 5537fa87cd09f49f1ee9bc27e263038d0f0ae706241bungemanstatic void XMLCALL end_element_handler(void* data, const char* tag) { 5547fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman FamilyData* self = static_cast<FamilyData*>(data); 55510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman --self->fDepth; 55610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 55710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (!self->fSkip) { 55810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const TagHandler* child = self->fHandler.top(); 55910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (child->end) { 56010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman child->end(self, tag); 56110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 56210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fHandler.pop(); 56310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const TagHandler* parent = self->fHandler.top(); 56410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman XML_SetCharacterDataHandler(self->fParser, parent->chars); 565bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 566bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 56710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (self->fSkip == self->fDepth) { 56810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fSkip = 0; 56910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const TagHandler* parent = self->fHandler.top(); 57010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman XML_SetCharacterDataHandler(self->fParser, parent->chars); 57110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 57210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman} 573f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson 5747fa87cd09f49f1ee9bc27e263038d0f0ae706241bungemanstatic void XMLCALL xml_entity_decl_handler(void *data, 5757fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const XML_Char *entityName, 5767fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman int is_parameter_entity, 5777fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const XML_Char *value, 5787fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman int value_length, 5797fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const XML_Char *base, 5807fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const XML_Char *systemId, 5817fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const XML_Char *publicId, 5827fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const XML_Char *notationName) 5837fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman{ 5847fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman FamilyData* self = static_cast<FamilyData*>(data); 585f61475e95d9bb38f741f9e51221c086250b9ad72bungeman SK_FONTCONFIGPARSER_WARNING("'%s' entity declaration found, stopping processing", entityName); 5867fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman XML_StopParser(self->fParser, XML_FALSE); 5877fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman} 5887fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman 589eb2be7fa4413a566212782d8efae5dc225002821bungemanstatic const XML_Memory_Handling_Suite sk_XML_alloc = { 590eb2be7fa4413a566212782d8efae5dc225002821bungeman sk_malloc_throw, 591eb2be7fa4413a566212782d8efae5dc225002821bungeman sk_realloc_throw, 592eb2be7fa4413a566212782d8efae5dc225002821bungeman sk_free 593eb2be7fa4413a566212782d8efae5dc225002821bungeman}; 594eb2be7fa4413a566212782d8efae5dc225002821bungeman 595bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com/** 596bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com * This function parses the given filename and stores the results in the given 597efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman * families array. Returns the version of the file, negative if the file does not exist. 598bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com */ 5997fa87cd09f49f1ee9bc27e263038d0f0ae706241bungemanstatic int parse_config_file(const char* filename, SkTDArray<FontFamily*>& families, 6007fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const SkString& basePath, bool isFallback) 6017fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman{ 6027fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman SkFILEStream file(filename); 60350c956791291e7f3cec23721157570b7911336b8djsollen@google.com 604bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com // Some of the files we attempt to parse (in particular, /vendor/etc/fallback_fonts.xml) 605bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com // are optional - failure here is okay because one of these optional files may not exist. 6067fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman if (!file.isValid()) { 607c53085413e0b4704aa89cc18396613d59e6ccb4dbungeman SkDebugf(SK_FONTMGR_ANDROID_PARSER_PREFIX "'%s' could not be opened\n", filename); 608efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman return -1; 609bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 61050c956791291e7f3cec23721157570b7911336b8djsollen@google.com 61154e63082191f337084f96083ca90d7c35273d6ffbungeman SkAutoTCallVProc<skstd::remove_pointer_t<XML_Parser>, XML_ParserFree> parser( 61296fcdcc219d2a0d3579719b84b28bede76efba64halcanary XML_ParserCreate_MM(nullptr, &sk_XML_alloc, nullptr)); 6137fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman if (!parser) { 614c53085413e0b4704aa89cc18396613d59e6ccb4dbungeman SkDebugf(SK_FONTMGR_ANDROID_PARSER_PREFIX "could not create XML parser\n"); 6157fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman return -1; 6167fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman } 6177fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman 61810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman FamilyData self(parser, families, basePath, isFallback, filename, &topLevelHandler); 6197fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman XML_SetUserData(parser, &self); 6207fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman 6217fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman // Disable entity processing, to inhibit internal entity expansion. See expat CVE-2013-0340 6227fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman XML_SetEntityDeclHandler(parser, xml_entity_decl_handler); 6237fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman 624f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson // Start parsing oldschool; switch these in flight if we detect a newer version of the file. 62510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman XML_SetElementHandler(parser, start_element_handler, end_element_handler); 62650c956791291e7f3cec23721157570b7911336b8djsollen@google.com 627eb2be7fa4413a566212782d8efae5dc225002821bungeman // One would assume it would be faster to have a buffer on the stack and call XML_Parse. 628eb2be7fa4413a566212782d8efae5dc225002821bungeman // But XML_Parse will call XML_GetBuffer anyway and memmove the passed buffer into it. 629eb2be7fa4413a566212782d8efae5dc225002821bungeman // (Unless XML_CONTEXT_BYTES is undefined, but all users define it.) 6309a0808fd8e83128403285f391944850d908d7af0bungeman // In debug, buffer a small odd number of bytes to detect slicing in XML_CharacterDataHandler. 6319a0808fd8e83128403285f391944850d908d7af0bungeman static const int bufferSize = 512 SkDEBUGCODE( - 507); 632bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com bool done = false; 633bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com while (!done) { 634eb2be7fa4413a566212782d8efae5dc225002821bungeman void* buffer = XML_GetBuffer(parser, bufferSize); 635eb2be7fa4413a566212782d8efae5dc225002821bungeman if (!buffer) { 636c53085413e0b4704aa89cc18396613d59e6ccb4dbungeman SkDebugf(SK_FONTMGR_ANDROID_PARSER_PREFIX "could not buffer enough to continue\n"); 637eb2be7fa4413a566212782d8efae5dc225002821bungeman return -1; 638eb2be7fa4413a566212782d8efae5dc225002821bungeman } 639eb2be7fa4413a566212782d8efae5dc225002821bungeman size_t len = file.read(buffer, bufferSize); 6407fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman done = file.isAtEnd(); 641eb2be7fa4413a566212782d8efae5dc225002821bungeman XML_Status status = XML_ParseBuffer(parser, len, done); 6427fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman if (XML_STATUS_ERROR == status) { 6437fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman XML_Error error = XML_GetErrorCode(parser); 6447fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman int line = XML_GetCurrentLineNumber(parser); 6457fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman int column = XML_GetCurrentColumnNumber(parser); 6467fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const XML_LChar* errorString = XML_ErrorString(error); 647c53085413e0b4704aa89cc18396613d59e6ccb4dbungeman SkDebugf(SK_FONTMGR_ANDROID_PARSER_PREFIX "%s:%d:%d error %d: %s.\n", 648f61475e95d9bb38f741f9e51221c086250b9ad72bungeman filename, line, column, error, errorString); 6497fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman return -1; 650bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 651bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 6527fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman return self.fVersion; 653bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com} 654bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 655efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman/** Returns the version of the system font file actually found, negative if none. */ 6567fa87cd09f49f1ee9bc27e263038d0f0ae706241bungemanstatic int append_system_font_families(SkTDArray<FontFamily*>& fontFamilies, 6577fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const SkString& basePath) 6587fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman{ 6597a4747f4f62e4896d8f8469e1939b8191fff8d4etomhudson int initialCount = fontFamilies.count(); 6607fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman int version = parse_config_file(LMP_SYSTEM_FONTS_FILE, fontFamilies, basePath, false); 661efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman if (version < 0 || fontFamilies.count() == initialCount) { 6627fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman version = parse_config_file(OLD_SYSTEM_FONTS_FILE, fontFamilies, basePath, false); 66394fa4b99e2a53e997a90c7808cc5263f1bf40c9ftomhudson } 664efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman return version; 665bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com} 666bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 667a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen/** 668a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen * In some versions of Android prior to Android 4.2 (JellyBean MR1 at API 669a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen * Level 17) the fallback fonts for certain locales were encoded in their own 670a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen * XML files with a suffix that identified the locale. We search the provided 671a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen * directory for those files,add all of their entries to the fallback chain, and 672a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen * include the locale as part of each entry. 673a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen */ 674efbad37180c6b6f90d4b7e96a234e8065d2ec395bungemanstatic void append_fallback_font_families_for_locale(SkTDArray<FontFamily*>& fallbackFonts, 6757fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const char* dir, 6767fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const SkString& basePath) 677efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman{ 678c3c694342ad393b88cee5885395f182082aa2ebbbungeman SkAutoTCallIProc<DIR, closedir> fontDirectory(opendir(dir)); 67996fcdcc219d2a0d3579719b84b28bede76efba64halcanary if (nullptr == fontDirectory) { 680c3c694342ad393b88cee5885395f182082aa2ebbbungeman return; 681c3c694342ad393b88cee5885395f182082aa2ebbbungeman } 682a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen 683c3c694342ad393b88cee5885395f182082aa2ebbbungeman for (struct dirent* dirEntry; (dirEntry = readdir(fontDirectory));) { 6849a0808fd8e83128403285f391944850d908d7af0bungeman // The size of the prefix and suffix. 6859a0808fd8e83128403285f391944850d908d7af0bungeman static const size_t fixedLen = sizeof(LOCALE_FALLBACK_FONTS_PREFIX) - 1 6869a0808fd8e83128403285f391944850d908d7af0bungeman + sizeof(LOCALE_FALLBACK_FONTS_SUFFIX) - 1; 6879a0808fd8e83128403285f391944850d908d7af0bungeman 6889a0808fd8e83128403285f391944850d908d7af0bungeman // The size of the prefix, suffix, and a minimum valid language code 6899a0808fd8e83128403285f391944850d908d7af0bungeman static const size_t minSize = fixedLen + 2; 690c3c694342ad393b88cee5885395f182082aa2ebbbungeman 691c3c694342ad393b88cee5885395f182082aa2ebbbungeman SkString fileName(dirEntry->d_name); 692c3c694342ad393b88cee5885395f182082aa2ebbbungeman if (fileName.size() < minSize || 693c3c694342ad393b88cee5885395f182082aa2ebbbungeman !fileName.startsWith(LOCALE_FALLBACK_FONTS_PREFIX) || 694c3c694342ad393b88cee5885395f182082aa2ebbbungeman !fileName.endsWith(LOCALE_FALLBACK_FONTS_SUFFIX)) 695c3c694342ad393b88cee5885395f182082aa2ebbbungeman { 696c3c694342ad393b88cee5885395f182082aa2ebbbungeman continue; 697c3c694342ad393b88cee5885395f182082aa2ebbbungeman } 698a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen 699c3c694342ad393b88cee5885395f182082aa2ebbbungeman SkString locale(fileName.c_str() + sizeof(LOCALE_FALLBACK_FONTS_PREFIX) - 1, 700c3c694342ad393b88cee5885395f182082aa2ebbbungeman fileName.size() - fixedLen); 701a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen 702c3c694342ad393b88cee5885395f182082aa2ebbbungeman SkString absoluteFilename; 703c3c694342ad393b88cee5885395f182082aa2ebbbungeman absoluteFilename.printf("%s/%s", dir, fileName.c_str()); 704a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen 705c3c694342ad393b88cee5885395f182082aa2ebbbungeman SkTDArray<FontFamily*> langSpecificFonts; 706c3c694342ad393b88cee5885395f182082aa2ebbbungeman parse_config_file(absoluteFilename.c_str(), langSpecificFonts, basePath, true); 707a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen 708c3c694342ad393b88cee5885395f182082aa2ebbbungeman for (int i = 0; i < langSpecificFonts.count(); ++i) { 709c3c694342ad393b88cee5885395f182082aa2ebbbungeman FontFamily* family = langSpecificFonts[i]; 710c3c694342ad393b88cee5885395f182082aa2ebbbungeman family->fLanguage = SkLanguage(locale); 711c3c694342ad393b88cee5885395f182082aa2ebbbungeman *fallbackFonts.append() = family; 712a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen } 713a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen } 714a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen} 715a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen 7167fa87cd09f49f1ee9bc27e263038d0f0ae706241bungemanstatic void append_system_fallback_font_families(SkTDArray<FontFamily*>& fallbackFonts, 7177fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const SkString& basePath) 7187fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman{ 7197fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman parse_config_file(FALLBACK_FONTS_FILE, fallbackFonts, basePath, true); 7207fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman append_fallback_font_families_for_locale(fallbackFonts, 7217fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman LOCALE_FALLBACK_FONTS_SYSTEM_DIR, 7227fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman basePath); 723efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman} 724bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 7257fa87cd09f49f1ee9bc27e263038d0f0ae706241bungemanstatic void mixin_vendor_fallback_font_families(SkTDArray<FontFamily*>& fallbackFonts, 7267fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const SkString& basePath) 7277fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman{ 728efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman SkTDArray<FontFamily*> vendorFonts; 7297fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman parse_config_file(VENDOR_FONTS_FILE, vendorFonts, basePath, true); 7307fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman append_fallback_font_families_for_locale(vendorFonts, 7317fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman LOCALE_FALLBACK_FONTS_VENDOR_DIR, 7327fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman basePath); 733a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen 734bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com // This loop inserts the vendor fallback fonts in the correct order in the 735bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com // overall fallbacks list. 736bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com int currentOrder = -1; 737bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com for (int i = 0; i < vendorFonts.count(); ++i) { 738bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com FontFamily* family = vendorFonts[i]; 739d3ddea284ec6611a93a6b75e64de39d0bc7e083ctomhudson int order = family->fOrder; 740bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com if (order < 0) { 741bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com if (currentOrder < 0) { 742bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com // Default case - just add it to the end of the fallback list 743bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com *fallbackFonts.append() = family; 744bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } else { 745bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com // no order specified on this font, but we're incrementing the order 746bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com // based on an earlier order insertion request 747bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com *fallbackFonts.insert(currentOrder++) = family; 748bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 749bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } else { 750bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com // Add the font into the fallback list in the specified order. Set 751bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com // currentOrder for correct placement of other fonts in the vendor list. 752bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com *fallbackFonts.insert(order) = family; 753bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com currentOrder = order + 1; 754bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 755bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 756bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com} 757bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 758c53085413e0b4704aa89cc18396613d59e6ccb4dbungemanvoid SkFontMgr_Android_Parser::GetSystemFontFamilies(SkTDArray<FontFamily*>& fontFamilies) { 759efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman // Version 21 of the system font configuration does not need any fallback configuration files. 7607fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman SkString basePath(getenv("ANDROID_ROOT")); 7617fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman basePath.append(SK_FONT_FILE_PREFIX, sizeof(SK_FONT_FILE_PREFIX) - 1); 7627fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman 7637fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman if (append_system_font_families(fontFamilies, basePath) >= 21) { 764efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman return; 765efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman } 766bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 767bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com // Append all the fallback fonts to system fonts 768bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com SkTDArray<FontFamily*> fallbackFonts; 7697fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman append_system_fallback_font_families(fallbackFonts, basePath); 7707fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman mixin_vendor_fallback_font_families(fallbackFonts, basePath); 7717fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman fontFamilies.append(fallbackFonts.count(), fallbackFonts.begin()); 772bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com} 773bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 774c53085413e0b4704aa89cc18396613d59e6ccb4dbungemanvoid SkFontMgr_Android_Parser::GetCustomFontFamilies(SkTDArray<FontFamily*>& fontFamilies, 775c53085413e0b4704aa89cc18396613d59e6ccb4dbungeman const SkString& basePath, 776c53085413e0b4704aa89cc18396613d59e6ccb4dbungeman const char* fontsXml, 777c53085413e0b4704aa89cc18396613d59e6ccb4dbungeman const char* fallbackFontsXml, 778c53085413e0b4704aa89cc18396613d59e6ccb4dbungeman const char* langFallbackFontsDir) 7797fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman{ 7807fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman if (fontsXml) { 7817fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman parse_config_file(fontsXml, fontFamilies, basePath, false); 782f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson } 7837fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman if (fallbackFontsXml) { 7847fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman parse_config_file(fallbackFontsXml, fontFamilies, basePath, true); 785bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 786c3c694342ad393b88cee5885395f182082aa2ebbbungeman if (langFallbackFontsDir) { 787c3c694342ad393b88cee5885395f182082aa2ebbbungeman append_fallback_font_families_for_locale(fontFamilies, 788c3c694342ad393b88cee5885395f182082aa2ebbbungeman langFallbackFontsDir, 789c3c694342ad393b88cee5885395f182082aa2ebbbungeman basePath); 790c3c694342ad393b88cee5885395f182082aa2ebbbungeman } 791bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com} 7923b6255493e458c6b2c1412af908581f0bf3f6b70djsollen 7933b6255493e458c6b2c1412af908581f0bf3f6b70djsollenSkLanguage SkLanguage::getParent() const { 7943b6255493e458c6b2c1412af908581f0bf3f6b70djsollen SkASSERT(!fTag.isEmpty()); 7953b6255493e458c6b2c1412af908581f0bf3f6b70djsollen const char* tag = fTag.c_str(); 7963b6255493e458c6b2c1412af908581f0bf3f6b70djsollen 7973b6255493e458c6b2c1412af908581f0bf3f6b70djsollen // strip off the rightmost "-.*" 7983b6255493e458c6b2c1412af908581f0bf3f6b70djsollen const char* parentTagEnd = strrchr(tag, '-'); 79996fcdcc219d2a0d3579719b84b28bede76efba64halcanary if (parentTagEnd == nullptr) { 8003b6255493e458c6b2c1412af908581f0bf3f6b70djsollen return SkLanguage(); 8013b6255493e458c6b2c1412af908581f0bf3f6b70djsollen } 8023b6255493e458c6b2c1412af908581f0bf3f6b70djsollen size_t parentTagLen = parentTagEnd - tag; 8033b6255493e458c6b2c1412af908581f0bf3f6b70djsollen return SkLanguage(tag, parentTagLen); 8043b6255493e458c6b2c1412af908581f0bf3f6b70djsollen} 805