| 1 | /* | 
|---|
| 2 | * Copyright 2011 The Android Open Source Project | 
|---|
| 3 | * | 
|---|
| 4 | * Use of this source code is governed by a BSD-style license that can be | 
|---|
| 5 | * found in the LICENSE file. | 
|---|
| 6 | */ | 
|---|
| 7 |  | 
|---|
| 8 | #ifndef SkFontMgr_android_parser_DEFINED | 
|---|
| 9 | #define SkFontMgr_android_parser_DEFINED | 
|---|
| 10 |  | 
|---|
| 11 | #include "include/core/SkFontMgr.h" | 
|---|
| 12 | #include "include/core/SkString.h" | 
|---|
| 13 | #include "include/core/SkTypes.h" | 
|---|
| 14 | #include "include/private/SkTArray.h" | 
|---|
| 15 | #include "include/private/SkTDArray.h" | 
|---|
| 16 | #include "include/private/SkTHash.h" | 
|---|
| 17 |  | 
|---|
| 18 | #include <climits> | 
|---|
| 19 | #include <limits> | 
|---|
| 20 |  | 
|---|
| 21 | /** \class SkLanguage | 
|---|
| 22 |  | 
|---|
| 23 | The SkLanguage class represents a human written language, and is used by | 
|---|
| 24 | text draw operations to determine which glyph to draw when drawing | 
|---|
| 25 | characters with variants (ie Han-derived characters). | 
|---|
| 26 | */ | 
|---|
| 27 | class SkLanguage { | 
|---|
| 28 | public: | 
|---|
| 29 | SkLanguage() { } | 
|---|
| 30 | SkLanguage(const SkString& tag) : fTag(tag) { } | 
|---|
| 31 | SkLanguage(const char* tag) : fTag(tag) { } | 
|---|
| 32 | SkLanguage(const char* tag, size_t len) : fTag(tag, len) { } | 
|---|
| 33 | SkLanguage(const SkLanguage& b) : fTag(b.fTag) { } | 
|---|
| 34 |  | 
|---|
| 35 | /** Gets a BCP 47 language identifier for this SkLanguage. | 
|---|
| 36 | @return a BCP 47 language identifier representing this language | 
|---|
| 37 | */ | 
|---|
| 38 | const SkString& getTag() const { return fTag; } | 
|---|
| 39 |  | 
|---|
| 40 | /** Performs BCP 47 fallback to return an SkLanguage one step more general. | 
|---|
| 41 | @return an SkLanguage one step more general | 
|---|
| 42 | */ | 
|---|
| 43 | SkLanguage getParent() const; | 
|---|
| 44 |  | 
|---|
| 45 | bool operator==(const SkLanguage& b) const { | 
|---|
| 46 | return fTag == b.fTag; | 
|---|
| 47 | } | 
|---|
| 48 | bool operator!=(const SkLanguage& b) const { | 
|---|
| 49 | return fTag != b.fTag; | 
|---|
| 50 | } | 
|---|
| 51 | SkLanguage& operator=(const SkLanguage& b) { | 
|---|
| 52 | fTag = b.fTag; | 
|---|
| 53 | return *this; | 
|---|
| 54 | } | 
|---|
| 55 |  | 
|---|
| 56 | private: | 
|---|
| 57 | //! BCP 47 language identifier | 
|---|
| 58 | SkString fTag; | 
|---|
| 59 | }; | 
|---|
| 60 |  | 
|---|
| 61 | enum FontVariants { | 
|---|
| 62 | kDefault_FontVariant = 0x01, | 
|---|
| 63 | kCompact_FontVariant = 0x02, | 
|---|
| 64 | kElegant_FontVariant = 0x04, | 
|---|
| 65 | kLast_FontVariant = kElegant_FontVariant, | 
|---|
| 66 | }; | 
|---|
| 67 | typedef uint32_t FontVariant; | 
|---|
| 68 |  | 
|---|
| 69 | // Must remain trivially movable (can be memmoved). | 
|---|
| 70 | struct FontFileInfo { | 
|---|
| 71 | FontFileInfo() : fIndex(0), fWeight(0), fStyle(Style::kAuto) { } | 
|---|
| 72 |  | 
|---|
| 73 | SkString fFileName; | 
|---|
| 74 | int fIndex; | 
|---|
| 75 | int fWeight; | 
|---|
| 76 | enum class Style { kAuto, kNormal, kItalic } fStyle; | 
|---|
| 77 | SkTArray<SkFontArguments::VariationPosition::Coordinate, true> fVariationDesignPosition; | 
|---|
| 78 | }; | 
|---|
| 79 |  | 
|---|
| 80 | /** | 
|---|
| 81 | * A font family provides one or more names for a collection of fonts, each of | 
|---|
| 82 | * which has a different style (normal, italic) or weight (thin, light, bold, | 
|---|
| 83 | * etc). | 
|---|
| 84 | * Some fonts may occur in compact variants for use in the user interface. | 
|---|
| 85 | * Android distinguishes "fallback" fonts to support non-ASCII character sets. | 
|---|
| 86 | */ | 
|---|
| 87 | struct FontFamily { | 
|---|
| 88 | FontFamily(const SkString& basePath, bool isFallbackFont) | 
|---|
| 89 | : fVariant(kDefault_FontVariant) | 
|---|
| 90 | , fOrder(-1) | 
|---|
| 91 | , fIsFallbackFont(isFallbackFont) | 
|---|
| 92 | , fBasePath(basePath) | 
|---|
| 93 | { } | 
|---|
| 94 |  | 
|---|
| 95 | SkTArray<SkString, true> fNames; | 
|---|
| 96 | SkTArray<FontFileInfo, true> fFonts; | 
|---|
| 97 | SkTArray<SkLanguage, true> fLanguages; | 
|---|
| 98 | SkTHashMap<SkString, std::unique_ptr<FontFamily>> fallbackFamilies; | 
|---|
| 99 | FontVariant fVariant; | 
|---|
| 100 | int fOrder; // internal to the parser, not useful to users. | 
|---|
| 101 | bool fIsFallbackFont; | 
|---|
| 102 | SkString fFallbackFor; | 
|---|
| 103 | const SkString fBasePath; | 
|---|
| 104 | }; | 
|---|
| 105 |  | 
|---|
| 106 | namespace SkFontMgr_Android_Parser { | 
|---|
| 107 |  | 
|---|
| 108 | /** Parses system font configuration files and appends result to fontFamilies. */ | 
|---|
| 109 | void GetSystemFontFamilies(SkTDArray<FontFamily*>& fontFamilies); | 
|---|
| 110 |  | 
|---|
| 111 | /** Parses font configuration files and appends result to fontFamilies. */ | 
|---|
| 112 | void GetCustomFontFamilies(SkTDArray<FontFamily*>& fontFamilies, | 
|---|
| 113 | const SkString& basePath, | 
|---|
| 114 | const char* fontsXml, | 
|---|
| 115 | const char* fallbackFontsXml, | 
|---|
| 116 | const char* langFallbackFontsDir = nullptr); | 
|---|
| 117 |  | 
|---|
| 118 | } // SkFontMgr_Android_Parser namespace | 
|---|
| 119 |  | 
|---|
| 120 |  | 
|---|
| 121 | /** Parses a null terminated string into an integer type, checking for overflow. | 
|---|
| 122 | *  http://www.w3.org/TR/html-markup/datatypes.html#common.data.integer.non-negative-def | 
|---|
| 123 | * | 
|---|
| 124 | *  If the string cannot be parsed into 'value', returns false and does not change 'value'. | 
|---|
| 125 | */ | 
|---|
| 126 | template <typename T> static bool parse_non_negative_integer(const char* s, T* value) { | 
|---|
| 127 | static_assert(std::numeric_limits<T>::is_integer, "T_must_be_integer"); | 
|---|
| 128 |  | 
|---|
| 129 | if (*s == '\0') { | 
|---|
| 130 | return false; | 
|---|
| 131 | } | 
|---|
| 132 |  | 
|---|
| 133 | const T nMax = std::numeric_limits<T>::max() / 10; | 
|---|
| 134 | const T dMax = std::numeric_limits<T>::max() - (nMax * 10); | 
|---|
| 135 | T n = 0; | 
|---|
| 136 | for (; *s; ++s) { | 
|---|
| 137 | // Check if digit | 
|---|
| 138 | if (*s < '0' || '9' < *s) { | 
|---|
| 139 | return false; | 
|---|
| 140 | } | 
|---|
| 141 | T d = *s - '0'; | 
|---|
| 142 | // Check for overflow | 
|---|
| 143 | if (n > nMax || (n == nMax && d > dMax)) { | 
|---|
| 144 | return false; | 
|---|
| 145 | } | 
|---|
| 146 | n = (n * 10) + d; | 
|---|
| 147 | } | 
|---|
| 148 | *value = n; | 
|---|
| 149 | return true; | 
|---|
| 150 | } | 
|---|
| 151 |  | 
|---|
| 152 | /** Parses a null terminated string into a signed fixed point value with bias N. | 
|---|
| 153 | * | 
|---|
| 154 | *  Like http://www.w3.org/TR/html-markup/datatypes.html#common.data.float-def , | 
|---|
| 155 | *  but may start with '.' and does not support 'e'. '-?((:digit:+(.:digit:+)?)|(.:digit:+))' | 
|---|
| 156 | * | 
|---|
| 157 | *  Checks for overflow. | 
|---|
| 158 | *  Low bit rounding is not defined (is currently truncate). | 
|---|
| 159 | *  Bias (N) required to allow for the sign bit and 4 bits of integer. | 
|---|
| 160 | * | 
|---|
| 161 | *  If the string cannot be parsed into 'value', returns false and does not change 'value'. | 
|---|
| 162 | */ | 
|---|
| 163 | template <int N, typename T> static bool parse_fixed(const char* s, T* value) { | 
|---|
| 164 | static_assert(std::numeric_limits<T>::is_integer, "T_must_be_integer"); | 
|---|
| 165 | static_assert(std::numeric_limits<T>::is_signed, "T_must_be_signed"); | 
|---|
| 166 | static_assert(sizeof(T) * CHAR_BIT - N >= 5, "N_must_leave_four_bits_plus_sign"); | 
|---|
| 167 |  | 
|---|
| 168 | bool negate = false; | 
|---|
| 169 | if (*s == '-') { | 
|---|
| 170 | ++s; | 
|---|
| 171 | negate = true; | 
|---|
| 172 | } | 
|---|
| 173 | if (*s == '\0') { | 
|---|
| 174 | return false; | 
|---|
| 175 | } | 
|---|
| 176 |  | 
|---|
| 177 | const T nMax = (std::numeric_limits<T>::max() >> N) / 10; | 
|---|
| 178 | const T dMax = (std::numeric_limits<T>::max() >> N) - (nMax * 10); | 
|---|
| 179 | T n = 0; | 
|---|
| 180 | T frac = 0; | 
|---|
| 181 | for (; *s; ++s) { | 
|---|
| 182 | // Check if digit | 
|---|
| 183 | if (*s < '0' || '9' < *s) { | 
|---|
| 184 | // If it wasn't a digit, check if it is a '.' followed by something. | 
|---|
| 185 | if (*s != '.' || s[1] == '\0') { | 
|---|
| 186 | return false; | 
|---|
| 187 | } | 
|---|
| 188 | // Find the end, verify digits. | 
|---|
| 189 | for (++s; *s; ++s) { | 
|---|
| 190 | if (*s < '0' || '9' < *s) { | 
|---|
| 191 | return false; | 
|---|
| 192 | } | 
|---|
| 193 | } | 
|---|
| 194 | // Read back toward the '.'. | 
|---|
| 195 | for (--s; *s != '.'; --s) { | 
|---|
| 196 | T d = *s - '0'; | 
|---|
| 197 | frac = (frac + (d << N)) / 10; // This requires four bits overhead. | 
|---|
| 198 | } | 
|---|
| 199 | break; | 
|---|
| 200 | } | 
|---|
| 201 | T d = *s - '0'; | 
|---|
| 202 | // Check for overflow | 
|---|
| 203 | if (n > nMax || (n == nMax && d > dMax)) { | 
|---|
| 204 | return false; | 
|---|
| 205 | } | 
|---|
| 206 | n = (n * 10) + d; | 
|---|
| 207 | } | 
|---|
| 208 | if (negate) { | 
|---|
| 209 | n = -n; | 
|---|
| 210 | frac = -frac; | 
|---|
| 211 | } | 
|---|
| 212 | *value = SkLeftShift(n, N) + frac; | 
|---|
| 213 | return true; | 
|---|
| 214 | } | 
|---|
| 215 |  | 
|---|
| 216 | #endif /* SkFontMgr_android_parser_DEFINED */ | 
|---|
| 217 |  | 
|---|