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 106c71e0a065c2eb32139682bb1ca1cbbeb02ebcb9benjaminwagner#include "SkFixed.h" 1147a1e96b957b50662274360f1a390d76ab3d02ccbungeman#include "SkFontMgr.h" 12c53085413e0b4704aa89cc18396613d59e6ccb4dbungeman#include "SkFontMgr_android_parser.h" 13b549cc38c8404c58642ada75c0b24907702cc005Herb Derby#include "SkMalloc.h" 1422cffcace2ad526f55ba2579e65836d38f009d1abungeman#include "SkOSFile.h" 157fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman#include "SkStream.h" 16bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com#include "SkTDArray.h" 178d84c995319dd4a82e4f2054bbd19f968c671ca6bungeman#include "SkTSearch.h" 18f20488b4f2139e6ca09fee7e39b731dd8ab467dbbungeman#include "SkTemplates.h" 1954e63082191f337084f96083ca90d7c35273d6ffbungeman#include "SkTLogic.h" 20bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 21f20488b4f2139e6ca09fee7e39b731dd8ab467dbbungeman#include <expat.h> 22bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 237fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman#include <stdlib.h> 24f20488b4f2139e6ca09fee7e39b731dd8ab467dbbungeman#include <string.h> 258d84c995319dd4a82e4f2054bbd19f968c671ca6bungeman 2694fa4b99e2a53e997a90c7808cc5263f1bf40c9ftomhudson#define LMP_SYSTEM_FONTS_FILE "/system/etc/fonts.xml" 2794fa4b99e2a53e997a90c7808cc5263f1bf40c9ftomhudson#define OLD_SYSTEM_FONTS_FILE "/system/etc/system_fonts.xml" 28bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com#define FALLBACK_FONTS_FILE "/system/etc/fallback_fonts.xml" 29bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com#define VENDOR_FONTS_FILE "/vendor/etc/fallback_fonts.xml" 30bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 31a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen#define LOCALE_FALLBACK_FONTS_SYSTEM_DIR "/system/etc" 32a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen#define LOCALE_FALLBACK_FONTS_VENDOR_DIR "/vendor/etc" 33a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen#define LOCALE_FALLBACK_FONTS_PREFIX "fallback_fonts-" 34a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen#define LOCALE_FALLBACK_FONTS_SUFFIX ".xml" 35a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen 367fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman#ifndef SK_FONT_FILE_PREFIX 377fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman# define SK_FONT_FILE_PREFIX "/fonts/" 387fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman#endif 397fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman 40f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson/** 4110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * This file contains TWO 'familyset' handlers: 4210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * One for JB and earlier which works with 4310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * /system/etc/system_fonts.xml 4410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * /system/etc/fallback_fonts.xml 4510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * /vendor/etc/fallback_fonts.xml 4610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * /system/etc/fallback_fonts-XX.xml 4710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * /vendor/etc/fallback_fonts-XX.xml 4810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * and the other for LMP and later which works with 4910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * /system/etc/fonts.xml 5010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * 5110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * If the 'familyset' 'version' attribute is 21 or higher the LMP parser is used, otherwise the JB. 52f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson */ 53f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson 5410b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstruct FamilyData; 5510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 5610b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstruct TagHandler { 5710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /** Called at the start tag. 5810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * Called immediately after the parent tag retuns this handler from a call to 'tag'. 5910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * Allows setting up for handling the tag content and processing attributes. 6096fcdcc219d2a0d3579719b84b28bede76efba64halcanary * If nullptr, will not be called. 6110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman */ 6210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman void (*start)(FamilyData* data, const char* tag, const char** attributes); 6310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 6410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /** Called at the end tag. 6510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * Allows post-processing of any accumulated information. 6610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * This will be the last call made in relation to the current tag. 6796fcdcc219d2a0d3579719b84b28bede76efba64halcanary * If nullptr, will not be called. 6810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman */ 6910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman void (*end)(FamilyData* data, const char* tag); 7010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 7110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /** Called when a nested tag is encountered. 7210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * This is responsible for determining how to handle the tag. 7396fcdcc219d2a0d3579719b84b28bede76efba64halcanary * If the tag is not recognized, return nullptr to skip the tag. 7496fcdcc219d2a0d3579719b84b28bede76efba64halcanary * If nullptr, all nested tags will be skipped. 7510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman */ 7610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const TagHandler* (*tag)(FamilyData* data, const char* tag, const char** attributes); 7710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 7810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /** The character handler for this tag. 7910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * This is only active for character data contained directly in this tag (not sub-tags). 8010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman * The first parameter will be castable to a FamilyData*. 8196fcdcc219d2a0d3579719b84b28bede76efba64halcanary * If nullptr, any character data in this tag will be ignored. 8210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman */ 8310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman XML_CharacterDataHandler chars; 847fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman}; 85bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 8610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman/** Represents the current parsing state. */ 87bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.comstruct FamilyData { 887fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman FamilyData(XML_Parser parser, SkTDArray<FontFamily*>& families, 8910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const SkString& basePath, bool isFallback, const char* filename, 9010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const TagHandler* topLevelHandler) 91b6bed17ea81ff8fad68a7db79307bdcbcd4738a8bungeman : fParser(parser) 92b6bed17ea81ff8fad68a7db79307bdcbcd4738a8bungeman , fFamilies(families) 9396fcdcc219d2a0d3579719b84b28bede76efba64halcanary , fCurrentFamily(nullptr) 9496fcdcc219d2a0d3579719b84b28bede76efba64halcanary , fCurrentFontInfo(nullptr) 95efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman , fVersion(0) 967fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman , fBasePath(basePath) 977fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman , fIsFallback(isFallback) 98f61475e95d9bb38f741f9e51221c086250b9ad72bungeman , fFilename(filename) 9910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman , fDepth(1) 10010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman , fSkip(0) 10110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman , fHandler(&topLevelHandler, 1) 102fc6c37b981daeece7474ce61070c707c37eefa62Mike Klein { } 103b6bed17ea81ff8fad68a7db79307bdcbcd4738a8bungeman 104145dbcd165d9d27298eb8888bc240e2d06a95464Ben Wagner XML_Parser fParser; // The expat parser doing the work, owned by caller 105145dbcd165d9d27298eb8888bc240e2d06a95464Ben Wagner SkTDArray<FontFamily*>& fFamilies; // The array to append families, owned by caller 106145dbcd165d9d27298eb8888bc240e2d06a95464Ben Wagner std::unique_ptr<FontFamily> fCurrentFamily; // The family being created, owned by this 107145dbcd165d9d27298eb8888bc240e2d06a95464Ben Wagner FontFileInfo* fCurrentFontInfo; // The info being created, owned by fCurrentFamily 108145dbcd165d9d27298eb8888bc240e2d06a95464Ben Wagner int fVersion; // The version of the file parsed. 109145dbcd165d9d27298eb8888bc240e2d06a95464Ben Wagner const SkString& fBasePath; // The current base path. 110145dbcd165d9d27298eb8888bc240e2d06a95464Ben Wagner const bool fIsFallback; // The file being parsed is a fallback file 111145dbcd165d9d27298eb8888bc240e2d06a95464Ben Wagner const char* fFilename; // The name of the file currently being parsed. 112145dbcd165d9d27298eb8888bc240e2d06a95464Ben Wagner 113145dbcd165d9d27298eb8888bc240e2d06a95464Ben Wagner int fDepth; // The current element depth of the parse. 114145dbcd165d9d27298eb8888bc240e2d06a95464Ben Wagner int fSkip; // The depth to stop skipping, 0 if not skipping. 115145dbcd165d9d27298eb8888bc240e2d06a95464Ben Wagner SkTDArray<const TagHandler*> fHandler; // The stack of current tag handlers. 116bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com}; 117bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 1187fa87cd09f49f1ee9bc27e263038d0f0ae706241bungemanstatic bool memeq(const char* s1, const char* s2, size_t n1, size_t n2) { 1197fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman return n1 == n2 && 0 == memcmp(s1, s2, n1); 1207fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman} 1217fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman#define MEMEQ(c, s, n) memeq(c, s, sizeof(c) - 1, n) 1227fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman 12396fcdcc219d2a0d3579719b84b28bede76efba64halcanary#define ATTS_NON_NULL(a, i) (a[i] != nullptr && a[i+1] != nullptr) 1247fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman 125c53085413e0b4704aa89cc18396613d59e6ccb4dbungeman#define SK_FONTMGR_ANDROID_PARSER_PREFIX "[SkFontMgr Android Parser] " 126f61475e95d9bb38f741f9e51221c086250b9ad72bungeman 127f61475e95d9bb38f741f9e51221c086250b9ad72bungeman#define SK_FONTCONFIGPARSER_WARNING(message, ...) SkDebugf( \ 128c53085413e0b4704aa89cc18396613d59e6ccb4dbungeman SK_FONTMGR_ANDROID_PARSER_PREFIX "%s:%d:%d: warning: " message "\n", \ 129f61475e95d9bb38f741f9e51221c086250b9ad72bungeman self->fFilename, \ 130f61475e95d9bb38f741f9e51221c086250b9ad72bungeman XML_GetCurrentLineNumber(self->fParser), \ 131f61475e95d9bb38f741f9e51221c086250b9ad72bungeman XML_GetCurrentColumnNumber(self->fParser), \ 132f61475e95d9bb38f741f9e51221c086250b9ad72bungeman ##__VA_ARGS__); 133f61475e95d9bb38f741f9e51221c086250b9ad72bungeman 13410b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic bool is_whitespace(char c) { 13510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return c == ' ' || c == '\n'|| c == '\r' || c == '\t'; 13610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman} 137f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson 13810b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic void trim_string(SkString* s) { 13910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman char* str = s->writable_str(); 14010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* start = str; // start is inclusive 14110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* end = start + s->size(); // end is exclusive 14210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman while (is_whitespace(*start)) { ++start; } 14310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (start != end) { 14410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman --end; // make end inclusive 14510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman while (is_whitespace(*end)) { --end; } 14610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman ++end; // make end exclusive 14707544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson } 14810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t len = end - start; 14910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman memmove(str, start, len); 15010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman s->resize(len); 151f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson} 152f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson 15310b063cb91c52fd1f570ee63307fe7e68c1501f1bungemannamespace lmpParser { 154f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson 15541868fe5625fc3bd70daa3f461c881b5db6a9265bungemanstatic const TagHandler axisHandler = { 15641868fe5625fc3bd70daa3f461c881b5db6a9265bungeman /*start*/[](FamilyData* self, const char* tag, const char** attributes) { 15741868fe5625fc3bd70daa3f461c881b5db6a9265bungeman FontFileInfo& file = *self->fCurrentFontInfo; 15847a1e96b957b50662274360f1a390d76ab3d02ccbungeman SkFourByteTag axisTag = SkSetFourByteTag('\0','\0','\0','\0'); 15947a1e96b957b50662274360f1a390d76ab3d02ccbungeman SkFixed axisStyleValue = 0; 16047a1e96b957b50662274360f1a390d76ab3d02ccbungeman bool axisTagIsValid = false; 16147a1e96b957b50662274360f1a390d76ab3d02ccbungeman bool axisStyleValueIsValid = false; 16241868fe5625fc3bd70daa3f461c881b5db6a9265bungeman for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) { 16341868fe5625fc3bd70daa3f461c881b5db6a9265bungeman const char* name = attributes[i]; 16441868fe5625fc3bd70daa3f461c881b5db6a9265bungeman const char* value = attributes[i+1]; 16541868fe5625fc3bd70daa3f461c881b5db6a9265bungeman size_t nameLen = strlen(name); 16641868fe5625fc3bd70daa3f461c881b5db6a9265bungeman if (MEMEQ("tag", name, nameLen)) { 16741868fe5625fc3bd70daa3f461c881b5db6a9265bungeman size_t valueLen = strlen(value); 16841868fe5625fc3bd70daa3f461c881b5db6a9265bungeman if (valueLen == 4) { 16947a1e96b957b50662274360f1a390d76ab3d02ccbungeman axisTag = SkSetFourByteTag(value[0], value[1], value[2], value[3]); 17047a1e96b957b50662274360f1a390d76ab3d02ccbungeman axisTagIsValid = true; 171fc497343cbcbd526f77da913ae2feca0e1b1b866Ben Wagner for (int j = 0; j < file.fVariationDesignPosition.count() - 1; ++j) { 172fc497343cbcbd526f77da913ae2feca0e1b1b866Ben Wagner if (file.fVariationDesignPosition[j].axis == axisTag) { 17347a1e96b957b50662274360f1a390d76ab3d02ccbungeman axisTagIsValid = false; 17441868fe5625fc3bd70daa3f461c881b5db6a9265bungeman SK_FONTCONFIGPARSER_WARNING("'%c%c%c%c' axis specified more than once", 17547a1e96b957b50662274360f1a390d76ab3d02ccbungeman (axisTag >> 24) & 0xFF, 17647a1e96b957b50662274360f1a390d76ab3d02ccbungeman (axisTag >> 16) & 0xFF, 17747a1e96b957b50662274360f1a390d76ab3d02ccbungeman (axisTag >> 8) & 0xFF, 17847a1e96b957b50662274360f1a390d76ab3d02ccbungeman (axisTag ) & 0xFF); 17941868fe5625fc3bd70daa3f461c881b5db6a9265bungeman } 18041868fe5625fc3bd70daa3f461c881b5db6a9265bungeman } 18141868fe5625fc3bd70daa3f461c881b5db6a9265bungeman } else { 18241868fe5625fc3bd70daa3f461c881b5db6a9265bungeman SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid axis tag", value); 18341868fe5625fc3bd70daa3f461c881b5db6a9265bungeman } 18441868fe5625fc3bd70daa3f461c881b5db6a9265bungeman } else if (MEMEQ("stylevalue", name, nameLen)) { 18547a1e96b957b50662274360f1a390d76ab3d02ccbungeman if (parse_fixed<16>(value, &axisStyleValue)) { 18647a1e96b957b50662274360f1a390d76ab3d02ccbungeman axisStyleValueIsValid = true; 18747a1e96b957b50662274360f1a390d76ab3d02ccbungeman } else { 18841868fe5625fc3bd70daa3f461c881b5db6a9265bungeman SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid axis stylevalue", value); 18941868fe5625fc3bd70daa3f461c881b5db6a9265bungeman } 19041868fe5625fc3bd70daa3f461c881b5db6a9265bungeman } 19141868fe5625fc3bd70daa3f461c881b5db6a9265bungeman } 19247a1e96b957b50662274360f1a390d76ab3d02ccbungeman if (axisTagIsValid && axisStyleValueIsValid) { 193fc497343cbcbd526f77da913ae2feca0e1b1b866Ben Wagner auto& coordinate = file.fVariationDesignPosition.push_back(); 194fc497343cbcbd526f77da913ae2feca0e1b1b866Ben Wagner coordinate.axis = axisTag; 195fc497343cbcbd526f77da913ae2feca0e1b1b866Ben Wagner coordinate.value = SkFixedToScalar(axisStyleValue); 19647a1e96b957b50662274360f1a390d76ab3d02ccbungeman } 19741868fe5625fc3bd70daa3f461c881b5db6a9265bungeman }, 19896fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*end*/nullptr, 19996fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*tag*/nullptr, 20096fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*chars*/nullptr, 20141868fe5625fc3bd70daa3f461c881b5db6a9265bungeman}; 20241868fe5625fc3bd70daa3f461c881b5db6a9265bungeman 20310b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic const TagHandler fontHandler = { 20410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*start*/[](FamilyData* self, const char* tag, const char** attributes) { 20510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'weight' (non-negative integer) [default 0] 20610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'style' ("normal", "italic") [default "auto"] 20710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'index' (non-negative integer) [default 0] 20810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // The character data should be a filename. 20910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman FontFileInfo& file = self->fCurrentFamily->fFonts.push_back(); 21010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fCurrentFontInfo = &file; 21110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) { 21210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* name = attributes[i]; 21310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* value = attributes[i+1]; 21410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t nameLen = strlen(name); 21510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("weight", name, nameLen)) { 21610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (!parse_non_negative_integer(value, &file.fWeight)) { 21710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid weight", value); 21810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 21910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("style", name, nameLen)) { 22010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t valueLen = strlen(value); 22110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("normal", value, valueLen)) { 22210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman file.fStyle = FontFileInfo::Style::kNormal; 22310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("italic", value, valueLen)) { 22410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman file.fStyle = FontFileInfo::Style::kItalic; 22510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 22610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("index", name, nameLen)) { 22710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (!parse_non_negative_integer(value, &file.fIndex)) { 22810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid index", value); 22910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 230d3ddea284ec6611a93a6b75e64de39d0bc7e083ctomhudson } 23110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 23210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 23310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*end*/[](FamilyData* self, const char* tag) { 23410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman trim_string(&self->fCurrentFontInfo->fFileName); 23510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 23641868fe5625fc3bd70daa3f461c881b5db6a9265bungeman /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* { 23741868fe5625fc3bd70daa3f461c881b5db6a9265bungeman size_t len = strlen(tag); 23841868fe5625fc3bd70daa3f461c881b5db6a9265bungeman if (MEMEQ("axis", tag, len)) { 23941868fe5625fc3bd70daa3f461c881b5db6a9265bungeman return &axisHandler; 24041868fe5625fc3bd70daa3f461c881b5db6a9265bungeman } 24196fcdcc219d2a0d3579719b84b28bede76efba64halcanary return nullptr; 24241868fe5625fc3bd70daa3f461c881b5db6a9265bungeman }, 24310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*chars*/[](void* data, const char* s, int len) { 24410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman FamilyData* self = static_cast<FamilyData*>(data); 24510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fCurrentFontInfo->fFileName.append(s, len); 24610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 24710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman}; 24810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 24910b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic const TagHandler familyHandler = { 25010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*start*/[](FamilyData* self, const char* tag, const char** attributes) { 25110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'name' (string) [optional] 252aee878d767a3965ee6409be9c72bb9ae6266bf52Ben Wagner // 'lang' (space separated string) [default ""] 25310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'variant' ("elegant", "compact") [default "default"] 25410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // If there is no name, this is a fallback only font. 25510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman FontFamily* family = new FontFamily(self->fBasePath, true); 25610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fCurrentFamily.reset(family); 25710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) { 25810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* name = attributes[i]; 25910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* value = attributes[i+1]; 26010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t nameLen = strlen(name); 261e85a754a4ce9b279159270faa6717932f7a8548fbungeman size_t valueLen = strlen(value); 26210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("name", name, nameLen)) { 26310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SkAutoAsciiToLC tolc(value); 26410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman family->fNames.push_back().set(tolc.lc()); 26510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman family->fIsFallbackFont = false; 26610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("lang", name, nameLen)) { 267aee878d767a3965ee6409be9c72bb9ae6266bf52Ben Wagner size_t i = 0; 268aee878d767a3965ee6409be9c72bb9ae6266bf52Ben Wagner while (true) { 269aee878d767a3965ee6409be9c72bb9ae6266bf52Ben Wagner for (; i < valueLen && is_whitespace(value[i]); ++i) { } 270aee878d767a3965ee6409be9c72bb9ae6266bf52Ben Wagner if (i == valueLen) { break; } 271aee878d767a3965ee6409be9c72bb9ae6266bf52Ben Wagner size_t j; 272aee878d767a3965ee6409be9c72bb9ae6266bf52Ben Wagner for (j = i + 1; j < valueLen && !is_whitespace(value[j]); ++j) { } 273aee878d767a3965ee6409be9c72bb9ae6266bf52Ben Wagner family->fLanguages.emplace_back(value + i, j - i); 274aee878d767a3965ee6409be9c72bb9ae6266bf52Ben Wagner i = j; 275aee878d767a3965ee6409be9c72bb9ae6266bf52Ben Wagner if (i == valueLen) { break; } 276aee878d767a3965ee6409be9c72bb9ae6266bf52Ben Wagner } 27710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("variant", name, nameLen)) { 27810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("elegant", value, valueLen)) { 27910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman family->fVariant = kElegant_FontVariant; 28010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("compact", value, valueLen)) { 28110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman family->fVariant = kCompact_FontVariant; 28210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 283b8a1d30a42d13ae83690b2d854a024d9b56e7b71bungeman } 28407544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson } 28510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 28610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*end*/[](FamilyData* self, const char* tag) { 28718300a3aa7cb6eb55d21bb0450dffa58b6fc062cmtklein *self->fFamilies.append() = self->fCurrentFamily.release(); 28810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 28910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* { 29010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t len = strlen(tag); 29110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("font", tag, len)) { 29210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return &fontHandler; 29310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 29496fcdcc219d2a0d3579719b84b28bede76efba64halcanary return nullptr; 29510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 29696fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*chars*/nullptr, 29710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman}; 29807544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson 299eb2be7fa4413a566212782d8efae5dc225002821bungemanstatic FontFamily* find_family(FamilyData* self, const SkString& familyName) { 3007fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman for (int i = 0; i < self->fFamilies.count(); i++) { 3017fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman FontFamily* candidate = self->fFamilies[i]; 30207544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson for (int j = 0; j < candidate->fNames.count(); j++) { 3037fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman if (candidate->fNames[j] == familyName) { 30407544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson return candidate; 30507544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson } 30607544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson } 30707544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson } 30896fcdcc219d2a0d3579719b84b28bede76efba64halcanary return nullptr; 30907544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson} 31007544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson 31110b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic const TagHandler aliasHandler = { 31210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*start*/[](FamilyData* self, const char* tag, const char** attributes) { 31310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'name' (string) introduces a new family name. 31410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'to' (string) specifies which (previous) family to alias 31510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'weight' (non-negative integer) [optional] 31610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // If it *does not* have a weight, 'name' is an alias for the entire 'to' family. 31710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // If it *does* have a weight, 'name' is a new family consisting of 31810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // the font(s) with 'weight' from the 'to' family. 31910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 32010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SkString aliasName; 32110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SkString to; 32210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman int weight = 0; 32310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) { 32410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* name = attributes[i]; 32510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* value = attributes[i+1]; 32610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t nameLen = strlen(name); 32710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("name", name, nameLen)) { 32810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SkAutoAsciiToLC tolc(value); 32910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman aliasName.set(tolc.lc()); 33010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("to", name, nameLen)) { 33110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman to.set(value); 33210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("weight", name, nameLen)) { 33310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (!parse_non_negative_integer(value, &weight)) { 33410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid weight", value); 33510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 3367fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman } 33707544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson } 33807544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson 33910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // Assumes that the named family is already declared 34010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman FontFamily* targetFamily = find_family(self, to); 34110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (!targetFamily) { 34210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SK_FONTCONFIGPARSER_WARNING("'%s' alias target not found", to.c_str()); 34310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return; 34410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 34507544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson 34610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (weight) { 34710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman FontFamily* family = new FontFamily(targetFamily->fBasePath, self->fIsFallback); 34810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman family->fNames.push_back().set(aliasName); 34907544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson 35010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman for (int i = 0; i < targetFamily->fFonts.count(); i++) { 35110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (targetFamily->fFonts[i].fWeight == weight) { 35210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman family->fFonts.push_back(targetFamily->fFonts[i]); 35310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 35407544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson } 35510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman *self->fFamilies.append() = family; 35610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else { 35710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman targetFamily->fNames.push_back().set(aliasName); 35807544757c9fcf0f359f1686a3779eb2e75dd5b36tomhudson } 35910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 36096fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*end*/nullptr, 36196fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*tag*/nullptr, 36296fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*chars*/nullptr, 36310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman}; 364c0727d117e67844f0c8794cc7eaa49a96a015347bungeman 36510b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic const TagHandler familySetHandler = { 36610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*start*/[](FamilyData* self, const char* tag, const char** attributes) { }, 36796fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*end*/nullptr, 36810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* { 36910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t len = strlen(tag); 37010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("family", tag, len)) { 37110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return &familyHandler; 37210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("alias", tag, len)) { 37310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return &aliasHandler; 37410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 37596fcdcc219d2a0d3579719b84b28bede76efba64halcanary return nullptr; 37610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 37796fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*chars*/nullptr, 37810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman}; 379f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson 380f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson} // lmpParser 381f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson 382f79673bbae0a662c1428755e2719dadf944e4ba1tomhudsonnamespace jbParser { 383f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson 38410b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic const TagHandler fileHandler = { 38510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*start*/[](FamilyData* self, const char* tag, const char** attributes) { 38610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'variant' ("elegant", "compact") [default "default"] 38710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'lang' (string) [default ""] 38810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'index' (non-negative integer) [default 0] 38910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // The character data should be a filename. 39010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman FontFamily& currentFamily = *self->fCurrentFamily.get(); 39110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman FontFileInfo& newFileInfo = currentFamily.fFonts.push_back(); 39210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (attributes) { 39310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) { 39410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* name = attributes[i]; 39510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* value = attributes[i+1]; 39610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t nameLen = strlen(name); 39710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t valueLen = strlen(value); 39810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("variant", name, nameLen)) { 39910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const FontVariant prevVariant = currentFamily.fVariant; 40010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("elegant", value, valueLen)) { 40110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman currentFamily.fVariant = kElegant_FontVariant; 40210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("compact", value, valueLen)) { 40310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman currentFamily.fVariant = kCompact_FontVariant; 40410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 40510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (currentFamily.fFonts.count() > 1 && currentFamily.fVariant != prevVariant) { 40610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SK_FONTCONFIGPARSER_WARNING("'%s' unexpected variant found\n" 40710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman "Note: Every font file within a family must have identical variants.", 40810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman value); 40910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 41010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 41110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("lang", name, nameLen)) { 412aee878d767a3965ee6409be9c72bb9ae6266bf52Ben Wagner SkLanguage currentLanguage = SkLanguage(value, valueLen); 413aee878d767a3965ee6409be9c72bb9ae6266bf52Ben Wagner bool showWarning = false; 414aee878d767a3965ee6409be9c72bb9ae6266bf52Ben Wagner if (currentFamily.fLanguages.empty()) { 415aee878d767a3965ee6409be9c72bb9ae6266bf52Ben Wagner showWarning = (currentFamily.fFonts.count() > 1); 416aee878d767a3965ee6409be9c72bb9ae6266bf52Ben Wagner currentFamily.fLanguages.push_back(std::move(currentLanguage)); 417aee878d767a3965ee6409be9c72bb9ae6266bf52Ben Wagner } else if (currentFamily.fLanguages[0] != currentLanguage) { 418aee878d767a3965ee6409be9c72bb9ae6266bf52Ben Wagner showWarning = true; 419aee878d767a3965ee6409be9c72bb9ae6266bf52Ben Wagner currentFamily.fLanguages[0] = std::move(currentLanguage); 420aee878d767a3965ee6409be9c72bb9ae6266bf52Ben Wagner } 421aee878d767a3965ee6409be9c72bb9ae6266bf52Ben Wagner if (showWarning) { 42210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SK_FONTCONFIGPARSER_WARNING("'%s' unexpected language found\n" 42310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman "Note: Every font file within a family must have identical languages.", 42410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman value); 42510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 42610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 42710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("index", name, nameLen)) { 42810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (!parse_non_negative_integer(value, &newFileInfo.fIndex)) { 42910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid index", value); 43010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 43110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 432bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 433bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 43410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fCurrentFontInfo = &newFileInfo; 43510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 43696fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*end*/nullptr, 43796fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*tag*/nullptr, 43810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*chars*/[](void* data, const char* s, int len) { 43910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman FamilyData* self = static_cast<FamilyData*>(data); 44010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fCurrentFontInfo->fFileName.append(s, len); 441bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 44210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman}; 443bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 44410b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic const TagHandler fileSetHandler = { 44596fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*start*/nullptr, 44696fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*end*/nullptr, 44710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* { 44810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t len = strlen(tag); 44910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("file", tag, len)) { 45010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return &fileHandler; 45110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 45296fcdcc219d2a0d3579719b84b28bede76efba64halcanary return nullptr; 45310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 45496fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*chars*/nullptr, 45510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman}; 45610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 45710b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic const TagHandler nameHandler = { 45810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*start*/[](FamilyData* self, const char* tag, const char** attributes) { 45910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // The character data should be a name for the font. 46010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fCurrentFamily->fNames.push_back(); 46110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 46296fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*end*/nullptr, 46396fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*tag*/nullptr, 46410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*chars*/[](void* data, const char* s, int len) { 46510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman FamilyData* self = static_cast<FamilyData*>(data); 46610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SkAutoAsciiToLC tolc(s, len); 46710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fCurrentFamily->fNames.back().append(tolc.lc(), len); 46810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 46910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman}; 47010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 47110b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic const TagHandler nameSetHandler = { 47296fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*start*/nullptr, 47396fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*end*/nullptr, 47410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* { 47510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t len = strlen(tag); 47610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("name", tag, len)) { 47710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return &nameHandler; 47810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 47996fcdcc219d2a0d3579719b84b28bede76efba64halcanary return nullptr; 48010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 48196fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*chars*/nullptr, 48210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman}; 48310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 48410b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic const TagHandler familyHandler = { 48510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*start*/[](FamilyData* self, const char* tag, const char** attributes) { 48610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fCurrentFamily.reset(new FontFamily(self->fBasePath, self->fIsFallback)); 48710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'order' (non-negative integer) [default -1] 4887fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) { 489f61475e95d9bb38f741f9e51221c086250b9ad72bungeman const char* value = attributes[i+1]; 49010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman parse_non_negative_integer(value, &self->fCurrentFamily->fOrder); 49110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 49210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 49310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*end*/[](FamilyData* self, const char* tag) { 49418300a3aa7cb6eb55d21bb0450dffa58b6fc062cmtklein *self->fFamilies.append() = self->fCurrentFamily.release(); 49510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 49610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* { 49710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t len = strlen(tag); 49810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("nameset", tag, len)) { 49910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return &nameSetHandler; 50010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else if (MEMEQ("fileset", tag, len)) { 50110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return &fileSetHandler; 50210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 50396fcdcc219d2a0d3579719b84b28bede76efba64halcanary return nullptr; 50410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 50596fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*chars*/nullptr, 50610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman}; 5073b6255493e458c6b2c1412af908581f0bf3f6b70djsollen 50810b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic const TagHandler familySetHandler = { 50996fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*start*/nullptr, 51096fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*end*/nullptr, 51110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* { 51210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t len = strlen(tag); 51310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("family", tag, len)) { 51410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return &familyHandler; 51510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 51696fcdcc219d2a0d3579719b84b28bede76efba64halcanary return nullptr; 51710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 51896fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*chars*/nullptr, 51910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman}; 5207fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman 52110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman} // namespace jbParser 52210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 52310b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic const TagHandler topLevelHandler = { 52496fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*start*/nullptr, 52596fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*end*/nullptr, 52610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* { 52710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t len = strlen(tag); 52810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("familyset", tag, len)) { 52910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman // 'version' (non-negative integer) [default 0] 53010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) { 53110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* name = attributes[i]; 53210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman size_t nameLen = strlen(name); 53310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (MEMEQ("version", name, nameLen)) { 53410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const char* value = attributes[i+1]; 53510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (parse_non_negative_integer(value, &self->fVersion)) { 53610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (self->fVersion >= 21) { 53710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return &lmpParser::familySetHandler; 53810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 53910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 5408d84c995319dd4a82e4f2054bbd19f968c671ca6bungeman } 541bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 54210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman return &jbParser::familySetHandler; 543bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 54496fcdcc219d2a0d3579719b84b28bede76efba64halcanary return nullptr; 54510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman }, 54696fcdcc219d2a0d3579719b84b28bede76efba64halcanary /*chars*/nullptr, 54710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman}; 548bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 54910b063cb91c52fd1f570ee63307fe7e68c1501f1bungemanstatic void XMLCALL start_element_handler(void *data, const char *tag, const char **attributes) { 5507fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman FamilyData* self = static_cast<FamilyData*>(data); 55110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 55210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (!self->fSkip) { 55310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const TagHandler* parent = self->fHandler.top(); 55496fcdcc219d2a0d3579719b84b28bede76efba64halcanary const TagHandler* child = parent->tag ? parent->tag(self, tag, attributes) : nullptr; 55510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (child) { 55610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (child->start) { 55710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman child->start(self, tag, attributes); 558bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 55910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fHandler.push(child); 56010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman XML_SetCharacterDataHandler(self->fParser, child->chars); 56110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } else { 56210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman SK_FONTCONFIGPARSER_WARNING("'%s' tag not recognized, skipping", tag); 56396fcdcc219d2a0d3579719b84b28bede76efba64halcanary XML_SetCharacterDataHandler(self->fParser, nullptr); 56410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fSkip = self->fDepth; 565bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 566bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 56710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 56810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman ++self->fDepth; 569bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com} 570bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 5717fa87cd09f49f1ee9bc27e263038d0f0ae706241bungemanstatic void XMLCALL end_element_handler(void* data, const char* tag) { 5727fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman FamilyData* self = static_cast<FamilyData*>(data); 57310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman --self->fDepth; 57410b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman 57510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (!self->fSkip) { 57610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const TagHandler* child = self->fHandler.top(); 57710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (child->end) { 57810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman child->end(self, tag); 57910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 58010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fHandler.pop(); 58110b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const TagHandler* parent = self->fHandler.top(); 58210b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman XML_SetCharacterDataHandler(self->fParser, parent->chars); 583bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 584bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 58510b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman if (self->fSkip == self->fDepth) { 58610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman self->fSkip = 0; 58710b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman const TagHandler* parent = self->fHandler.top(); 58810b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman XML_SetCharacterDataHandler(self->fParser, parent->chars); 58910b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman } 59010b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman} 591f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson 5927fa87cd09f49f1ee9bc27e263038d0f0ae706241bungemanstatic void XMLCALL xml_entity_decl_handler(void *data, 5937fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const XML_Char *entityName, 5947fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman int is_parameter_entity, 5957fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const XML_Char *value, 5967fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman int value_length, 5977fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const XML_Char *base, 5987fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const XML_Char *systemId, 5997fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const XML_Char *publicId, 6007fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const XML_Char *notationName) 6017fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman{ 6027fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman FamilyData* self = static_cast<FamilyData*>(data); 603f61475e95d9bb38f741f9e51221c086250b9ad72bungeman SK_FONTCONFIGPARSER_WARNING("'%s' entity declaration found, stopping processing", entityName); 6047fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman XML_StopParser(self->fParser, XML_FALSE); 6057fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman} 6067fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman 607eb2be7fa4413a566212782d8efae5dc225002821bungemanstatic const XML_Memory_Handling_Suite sk_XML_alloc = { 608eb2be7fa4413a566212782d8efae5dc225002821bungeman sk_malloc_throw, 609eb2be7fa4413a566212782d8efae5dc225002821bungeman sk_realloc_throw, 610eb2be7fa4413a566212782d8efae5dc225002821bungeman sk_free 611eb2be7fa4413a566212782d8efae5dc225002821bungeman}; 612eb2be7fa4413a566212782d8efae5dc225002821bungeman 613bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com/** 614bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com * This function parses the given filename and stores the results in the given 615efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman * families array. Returns the version of the file, negative if the file does not exist. 616bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com */ 6177fa87cd09f49f1ee9bc27e263038d0f0ae706241bungemanstatic int parse_config_file(const char* filename, SkTDArray<FontFamily*>& families, 6187fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const SkString& basePath, bool isFallback) 6197fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman{ 6207fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman SkFILEStream file(filename); 62150c956791291e7f3cec23721157570b7911336b8djsollen@google.com 622bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com // Some of the files we attempt to parse (in particular, /vendor/etc/fallback_fonts.xml) 623bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com // are optional - failure here is okay because one of these optional files may not exist. 6247fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman if (!file.isValid()) { 625c53085413e0b4704aa89cc18396613d59e6ccb4dbungeman SkDebugf(SK_FONTMGR_ANDROID_PARSER_PREFIX "'%s' could not be opened\n", filename); 626efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman return -1; 627bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 62850c956791291e7f3cec23721157570b7911336b8djsollen@google.com 62954e63082191f337084f96083ca90d7c35273d6ffbungeman SkAutoTCallVProc<skstd::remove_pointer_t<XML_Parser>, XML_ParserFree> parser( 63096fcdcc219d2a0d3579719b84b28bede76efba64halcanary XML_ParserCreate_MM(nullptr, &sk_XML_alloc, nullptr)); 6317fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman if (!parser) { 632c53085413e0b4704aa89cc18396613d59e6ccb4dbungeman SkDebugf(SK_FONTMGR_ANDROID_PARSER_PREFIX "could not create XML parser\n"); 6337fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman return -1; 6347fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman } 6357fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman 63610b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman FamilyData self(parser, families, basePath, isFallback, filename, &topLevelHandler); 6377fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman XML_SetUserData(parser, &self); 6387fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman 6397fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman // Disable entity processing, to inhibit internal entity expansion. See expat CVE-2013-0340 6407fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman XML_SetEntityDeclHandler(parser, xml_entity_decl_handler); 6417fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman 642f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson // Start parsing oldschool; switch these in flight if we detect a newer version of the file. 64310b063cb91c52fd1f570ee63307fe7e68c1501f1bungeman XML_SetElementHandler(parser, start_element_handler, end_element_handler); 64450c956791291e7f3cec23721157570b7911336b8djsollen@google.com 645eb2be7fa4413a566212782d8efae5dc225002821bungeman // One would assume it would be faster to have a buffer on the stack and call XML_Parse. 646eb2be7fa4413a566212782d8efae5dc225002821bungeman // But XML_Parse will call XML_GetBuffer anyway and memmove the passed buffer into it. 647eb2be7fa4413a566212782d8efae5dc225002821bungeman // (Unless XML_CONTEXT_BYTES is undefined, but all users define it.) 6489a0808fd8e83128403285f391944850d908d7af0bungeman // In debug, buffer a small odd number of bytes to detect slicing in XML_CharacterDataHandler. 6499a0808fd8e83128403285f391944850d908d7af0bungeman static const int bufferSize = 512 SkDEBUGCODE( - 507); 650bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com bool done = false; 651bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com while (!done) { 652eb2be7fa4413a566212782d8efae5dc225002821bungeman void* buffer = XML_GetBuffer(parser, bufferSize); 653eb2be7fa4413a566212782d8efae5dc225002821bungeman if (!buffer) { 654c53085413e0b4704aa89cc18396613d59e6ccb4dbungeman SkDebugf(SK_FONTMGR_ANDROID_PARSER_PREFIX "could not buffer enough to continue\n"); 655eb2be7fa4413a566212782d8efae5dc225002821bungeman return -1; 656eb2be7fa4413a566212782d8efae5dc225002821bungeman } 657eb2be7fa4413a566212782d8efae5dc225002821bungeman size_t len = file.read(buffer, bufferSize); 6587fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman done = file.isAtEnd(); 659eb2be7fa4413a566212782d8efae5dc225002821bungeman XML_Status status = XML_ParseBuffer(parser, len, done); 6607fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman if (XML_STATUS_ERROR == status) { 6617fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman XML_Error error = XML_GetErrorCode(parser); 6627fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman int line = XML_GetCurrentLineNumber(parser); 6637fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman int column = XML_GetCurrentColumnNumber(parser); 6647fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const XML_LChar* errorString = XML_ErrorString(error); 665c53085413e0b4704aa89cc18396613d59e6ccb4dbungeman SkDebugf(SK_FONTMGR_ANDROID_PARSER_PREFIX "%s:%d:%d error %d: %s.\n", 666f61475e95d9bb38f741f9e51221c086250b9ad72bungeman filename, line, column, error, errorString); 6677fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman return -1; 668bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 669bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 6707fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman return self.fVersion; 671bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com} 672bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 673efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman/** Returns the version of the system font file actually found, negative if none. */ 6747fa87cd09f49f1ee9bc27e263038d0f0ae706241bungemanstatic int append_system_font_families(SkTDArray<FontFamily*>& fontFamilies, 6757fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const SkString& basePath) 6767fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman{ 6777a4747f4f62e4896d8f8469e1939b8191fff8d4etomhudson int initialCount = fontFamilies.count(); 6787fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman int version = parse_config_file(LMP_SYSTEM_FONTS_FILE, fontFamilies, basePath, false); 679efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman if (version < 0 || fontFamilies.count() == initialCount) { 6807fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman version = parse_config_file(OLD_SYSTEM_FONTS_FILE, fontFamilies, basePath, false); 68194fa4b99e2a53e997a90c7808cc5263f1bf40c9ftomhudson } 682efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman return version; 683bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com} 684bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 685a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen/** 686a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen * In some versions of Android prior to Android 4.2 (JellyBean MR1 at API 687a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen * Level 17) the fallback fonts for certain locales were encoded in their own 688a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen * XML files with a suffix that identified the locale. We search the provided 689a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen * directory for those files,add all of their entries to the fallback chain, and 690a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen * include the locale as part of each entry. 691a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen */ 692efbad37180c6b6f90d4b7e96a234e8065d2ec395bungemanstatic void append_fallback_font_families_for_locale(SkTDArray<FontFamily*>& fallbackFonts, 6937fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const char* dir, 6947fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const SkString& basePath) 695efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman{ 69622cffcace2ad526f55ba2579e65836d38f009d1abungeman SkOSFile::Iter iter(dir, nullptr); 69722cffcace2ad526f55ba2579e65836d38f009d1abungeman SkString fileName; 69822cffcace2ad526f55ba2579e65836d38f009d1abungeman while (iter.next(&fileName, false)) { 6999a0808fd8e83128403285f391944850d908d7af0bungeman // The size of the prefix and suffix. 7009a0808fd8e83128403285f391944850d908d7af0bungeman static const size_t fixedLen = sizeof(LOCALE_FALLBACK_FONTS_PREFIX) - 1 7019a0808fd8e83128403285f391944850d908d7af0bungeman + sizeof(LOCALE_FALLBACK_FONTS_SUFFIX) - 1; 7029a0808fd8e83128403285f391944850d908d7af0bungeman 7039a0808fd8e83128403285f391944850d908d7af0bungeman // The size of the prefix, suffix, and a minimum valid language code 7049a0808fd8e83128403285f391944850d908d7af0bungeman static const size_t minSize = fixedLen + 2; 705c3c694342ad393b88cee5885395f182082aa2ebbbungeman 706c3c694342ad393b88cee5885395f182082aa2ebbbungeman if (fileName.size() < minSize || 707c3c694342ad393b88cee5885395f182082aa2ebbbungeman !fileName.startsWith(LOCALE_FALLBACK_FONTS_PREFIX) || 708c3c694342ad393b88cee5885395f182082aa2ebbbungeman !fileName.endsWith(LOCALE_FALLBACK_FONTS_SUFFIX)) 709c3c694342ad393b88cee5885395f182082aa2ebbbungeman { 710c3c694342ad393b88cee5885395f182082aa2ebbbungeman continue; 711c3c694342ad393b88cee5885395f182082aa2ebbbungeman } 712a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen 713c3c694342ad393b88cee5885395f182082aa2ebbbungeman SkString locale(fileName.c_str() + sizeof(LOCALE_FALLBACK_FONTS_PREFIX) - 1, 714c3c694342ad393b88cee5885395f182082aa2ebbbungeman fileName.size() - fixedLen); 715a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen 716c3c694342ad393b88cee5885395f182082aa2ebbbungeman SkString absoluteFilename; 717c3c694342ad393b88cee5885395f182082aa2ebbbungeman absoluteFilename.printf("%s/%s", dir, fileName.c_str()); 718a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen 719c3c694342ad393b88cee5885395f182082aa2ebbbungeman SkTDArray<FontFamily*> langSpecificFonts; 720c3c694342ad393b88cee5885395f182082aa2ebbbungeman parse_config_file(absoluteFilename.c_str(), langSpecificFonts, basePath, true); 721a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen 722c3c694342ad393b88cee5885395f182082aa2ebbbungeman for (int i = 0; i < langSpecificFonts.count(); ++i) { 723c3c694342ad393b88cee5885395f182082aa2ebbbungeman FontFamily* family = langSpecificFonts[i]; 724aee878d767a3965ee6409be9c72bb9ae6266bf52Ben Wagner family->fLanguages.emplace_back(locale); 725c3c694342ad393b88cee5885395f182082aa2ebbbungeman *fallbackFonts.append() = family; 726a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen } 727a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen } 728a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen} 729a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen 7307fa87cd09f49f1ee9bc27e263038d0f0ae706241bungemanstatic void append_system_fallback_font_families(SkTDArray<FontFamily*>& fallbackFonts, 7317fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const SkString& basePath) 7327fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman{ 7337fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman parse_config_file(FALLBACK_FONTS_FILE, fallbackFonts, basePath, true); 7347fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman append_fallback_font_families_for_locale(fallbackFonts, 7357fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman LOCALE_FALLBACK_FONTS_SYSTEM_DIR, 7367fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman basePath); 737efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman} 738bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 7397fa87cd09f49f1ee9bc27e263038d0f0ae706241bungemanstatic void mixin_vendor_fallback_font_families(SkTDArray<FontFamily*>& fallbackFonts, 7407fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman const SkString& basePath) 7417fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman{ 742efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman SkTDArray<FontFamily*> vendorFonts; 7437fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman parse_config_file(VENDOR_FONTS_FILE, vendorFonts, basePath, true); 7447fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman append_fallback_font_families_for_locale(vendorFonts, 7457fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman LOCALE_FALLBACK_FONTS_VENDOR_DIR, 7467fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman basePath); 747a6c27bc5bd3b213d1e315c0bd9bbdcd75cec6900djsollen 748bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com // This loop inserts the vendor fallback fonts in the correct order in the 749bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com // overall fallbacks list. 750bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com int currentOrder = -1; 751bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com for (int i = 0; i < vendorFonts.count(); ++i) { 752bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com FontFamily* family = vendorFonts[i]; 753d3ddea284ec6611a93a6b75e64de39d0bc7e083ctomhudson int order = family->fOrder; 754bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com if (order < 0) { 755bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com if (currentOrder < 0) { 756bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com // Default case - just add it to the end of the fallback list 757bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com *fallbackFonts.append() = family; 758bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } else { 759bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com // no order specified on this font, but we're incrementing the order 760bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com // based on an earlier order insertion request 761bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com *fallbackFonts.insert(currentOrder++) = family; 762bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 763bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } else { 764bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com // Add the font into the fallback list in the specified order. Set 765bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com // currentOrder for correct placement of other fonts in the vendor list. 766bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com *fallbackFonts.insert(order) = family; 767bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com currentOrder = order + 1; 768bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 769bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 770bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com} 771bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 772c53085413e0b4704aa89cc18396613d59e6ccb4dbungemanvoid SkFontMgr_Android_Parser::GetSystemFontFamilies(SkTDArray<FontFamily*>& fontFamilies) { 773efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman // Version 21 of the system font configuration does not need any fallback configuration files. 7747fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman SkString basePath(getenv("ANDROID_ROOT")); 7757fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman basePath.append(SK_FONT_FILE_PREFIX, sizeof(SK_FONT_FILE_PREFIX) - 1); 7767fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman 7777fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman if (append_system_font_families(fontFamilies, basePath) >= 21) { 778efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman return; 779efbad37180c6b6f90d4b7e96a234e8065d2ec395bungeman } 780bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 781bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com // Append all the fallback fonts to system fonts 782bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com SkTDArray<FontFamily*> fallbackFonts; 7837fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman append_system_fallback_font_families(fallbackFonts, basePath); 7847fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman mixin_vendor_fallback_font_families(fallbackFonts, basePath); 7857fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman fontFamilies.append(fallbackFonts.count(), fallbackFonts.begin()); 786bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com} 787bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com 788c53085413e0b4704aa89cc18396613d59e6ccb4dbungemanvoid SkFontMgr_Android_Parser::GetCustomFontFamilies(SkTDArray<FontFamily*>& fontFamilies, 789c53085413e0b4704aa89cc18396613d59e6ccb4dbungeman const SkString& basePath, 790c53085413e0b4704aa89cc18396613d59e6ccb4dbungeman const char* fontsXml, 791c53085413e0b4704aa89cc18396613d59e6ccb4dbungeman const char* fallbackFontsXml, 792c53085413e0b4704aa89cc18396613d59e6ccb4dbungeman const char* langFallbackFontsDir) 7937fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman{ 7947fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman if (fontsXml) { 7957fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman parse_config_file(fontsXml, fontFamilies, basePath, false); 796f79673bbae0a662c1428755e2719dadf944e4ba1tomhudson } 7977fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman if (fallbackFontsXml) { 7987fa87cd09f49f1ee9bc27e263038d0f0ae706241bungeman parse_config_file(fallbackFontsXml, fontFamilies, basePath, true); 799bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com } 800c3c694342ad393b88cee5885395f182082aa2ebbbungeman if (langFallbackFontsDir) { 801c3c694342ad393b88cee5885395f182082aa2ebbbungeman append_fallback_font_families_for_locale(fontFamilies, 802c3c694342ad393b88cee5885395f182082aa2ebbbungeman langFallbackFontsDir, 803c3c694342ad393b88cee5885395f182082aa2ebbbungeman basePath); 804c3c694342ad393b88cee5885395f182082aa2ebbbungeman } 805bfae9d373ccc9cf47fd70757092962c7850fadf4djsollen@google.com} 8063b6255493e458c6b2c1412af908581f0bf3f6b70djsollen 8073b6255493e458c6b2c1412af908581f0bf3f6b70djsollenSkLanguage SkLanguage::getParent() const { 8083b6255493e458c6b2c1412af908581f0bf3f6b70djsollen SkASSERT(!fTag.isEmpty()); 8093b6255493e458c6b2c1412af908581f0bf3f6b70djsollen const char* tag = fTag.c_str(); 8103b6255493e458c6b2c1412af908581f0bf3f6b70djsollen 8113b6255493e458c6b2c1412af908581f0bf3f6b70djsollen // strip off the rightmost "-.*" 8123b6255493e458c6b2c1412af908581f0bf3f6b70djsollen const char* parentTagEnd = strrchr(tag, '-'); 81396fcdcc219d2a0d3579719b84b28bede76efba64halcanary if (parentTagEnd == nullptr) { 8143b6255493e458c6b2c1412af908581f0bf3f6b70djsollen return SkLanguage(); 8153b6255493e458c6b2c1412af908581f0bf3f6b70djsollen } 8163b6255493e458c6b2c1412af908581f0bf3f6b70djsollen size_t parentTagLen = parentTagEnd - tag; 8173b6255493e458c6b2c1412af908581f0bf3f6b70djsollen return SkLanguage(tag, parentTagLen); 8183b6255493e458c6b2c1412af908581f0bf3f6b70djsollen} 819