Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* GRAPHITE2 LICENSING
3 Copyright 2010, SIL International
4 All rights reserved.
6 This library is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2.1 of License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should also have received a copy of the GNU Lesser General Public
17 License along with this library in the file named "LICENSE".
18 If not, write to the Free Software Foundation, 51 Franklin Street,
19 Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
20 internet at http://www.fsf.org/licenses/lgpl.html.
22 Alternatively, the contents of this file may be used under the terms of the
23 Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
24 License, as published by the Free Software Foundation, either version 2
25 of the License or (at your option) any later version.
26 */
27 #include "inc/Main.h"
28 #include "inc/Endian.h"
30 #include "inc/NameTable.h"
31 #include "inc/UtfCodec.h"
33 using namespace graphite2;
35 NameTable::NameTable(const void* data, size_t length, uint16 platformId, uint16 encodingID)
36 : m_platformId(0), m_encodingId(0), m_languageCount(0),
37 m_platformOffset(0), m_platformLastRecord(0), m_nameDataLength(0),
38 m_table(0), m_nameData(NULL)
39 {
40 void *pdata = gralloc<byte>(length);
41 if (!pdata) return;
42 memcpy(pdata, data, length);
43 m_table = reinterpret_cast<const TtfUtil::Sfnt::FontNames*>(pdata);
45 if ((length > sizeof(TtfUtil::Sfnt::FontNames)) &&
46 (length > sizeof(TtfUtil::Sfnt::FontNames) +
47 sizeof(TtfUtil::Sfnt::NameRecord) * ( be::swap<uint16>(m_table->count) - 1)))
48 {
49 uint16 offset = be::swap<uint16>(m_table->string_offset);
50 m_nameData = reinterpret_cast<const uint8*>(pdata) + offset;
51 setPlatformEncoding(platformId, encodingID);
52 m_nameDataLength = length - offset;
53 }
54 else
55 {
56 free(const_cast<TtfUtil::Sfnt::FontNames*>(m_table));
57 m_table = NULL;
58 }
59 }
61 uint16 NameTable::setPlatformEncoding(uint16 platformId, uint16 encodingID)
62 {
63 if (!m_nameData) return 0;
64 uint16 i = 0;
65 uint16 count = be::swap<uint16>(m_table->count);
66 for (; i < count; i++)
67 {
68 if (be::swap<uint16>(m_table->name_record[i].platform_id) == platformId &&
69 be::swap<uint16>(m_table->name_record[i].platform_specific_id) == encodingID)
70 {
71 m_platformOffset = i;
72 break;
73 }
74 }
75 while ((++i < count) &&
76 (be::swap<uint16>(m_table->name_record[i].platform_id) == platformId) &&
77 (be::swap<uint16>(m_table->name_record[i].platform_specific_id) == encodingID))
78 {
79 m_platformLastRecord = i;
80 }
81 m_encodingId = encodingID;
82 m_platformId = platformId;
83 return 0;
84 }
86 void* NameTable::getName(uint16& languageId, uint16 nameId, gr_encform enc, uint32& length)
87 {
88 uint16 anyLang = 0;
89 uint16 enUSLang = 0;
90 uint16 bestLang = 0;
91 if (!m_table)
92 {
93 languageId = 0;
94 length = 0;
95 return NULL;
96 }
97 for (uint16 i = m_platformOffset; i <= m_platformLastRecord; i++)
98 {
99 if (be::swap<uint16>(m_table->name_record[i].name_id) == nameId)
100 {
101 uint16 langId = be::swap<uint16>(m_table->name_record[i].language_id);
102 if (langId == languageId)
103 {
104 bestLang = i;
105 break;
106 }
107 // MS language tags have the language in the lower byte, region in the higher
108 else if ((langId & 0xFF) == (languageId & 0xFF))
109 {
110 bestLang = i;
111 }
112 else if (langId == 0x409)
113 {
114 enUSLang = i;
115 }
116 else
117 {
118 anyLang = i;
119 }
120 }
121 }
122 if (!bestLang)
123 {
124 if (enUSLang) bestLang = enUSLang;
125 else
126 {
127 bestLang = anyLang;
128 if (!anyLang)
129 {
130 languageId = 0;
131 length = 0;
132 return NULL;
133 }
134 }
135 }
136 const TtfUtil::Sfnt::NameRecord & nameRecord = m_table->name_record[bestLang];
137 languageId = be::swap<uint16>(nameRecord.language_id);
138 uint16 utf16Length = be::swap<uint16>(nameRecord.length);
139 uint16 offset = be::swap<uint16>(nameRecord.offset);
140 if(offset + utf16Length > m_nameDataLength)
141 {
142 languageId = 0;
143 length = 0;
144 return NULL;
145 }
146 utf16Length >>= 1; // in utf16 units
147 utf16::codeunit_t * utf16Name = gralloc<utf16::codeunit_t>(utf16Length);
148 if (!utf16Name)
149 {
150 languageId = 0;
151 length = 0;
152 return NULL;
153 }
154 const uint8* pName = m_nameData + offset;
155 for (size_t i = 0; i < utf16Length; i++)
156 {
157 utf16Name[i] = be::read<uint16>(pName);
158 }
159 switch (enc)
160 {
161 case gr_utf8:
162 {
163 utf8::codeunit_t* uniBuffer = gralloc<utf8::codeunit_t>(3 * utf16Length + 1);
164 if (!uniBuffer)
165 {
166 free(utf16Name);
167 languageId = 0;
168 length = 0;
169 return NULL;
170 }
171 utf8::iterator d = uniBuffer;
172 for (utf16::const_iterator s = utf16Name, e = utf16Name + utf16Length; s != e; ++s, ++d)
173 *d = *s;
174 length = d - uniBuffer;
175 uniBuffer[length] = 0;
176 free(utf16Name);
177 return uniBuffer;
178 }
179 case gr_utf16:
180 length = utf16Length;
181 return utf16Name;
182 case gr_utf32:
183 {
184 utf32::codeunit_t * uniBuffer = gralloc<utf32::codeunit_t>(utf16Length + 1);
185 if (!uniBuffer)
186 {
187 free(utf16Name);
188 languageId = 0;
189 length = 0;
190 return NULL;
191 }
192 utf32::iterator d = uniBuffer;
193 for (utf16::const_iterator s = utf16Name, e = utf16Name + utf16Length; s != e; ++s, ++d)
194 *d = *s;
195 length = d - uniBuffer;
196 uniBuffer[length] = 0;
197 free(utf16Name);
198 return uniBuffer;
199 }
200 }
201 free(utf16Name);
202 languageId = 0;
203 length = 0;
204 return NULL;
205 }
207 uint16 NameTable::getLanguageId(const char * bcp47Locale)
208 {
209 size_t localeLength = strlen(bcp47Locale);
210 uint16 localeId = m_locale2Lang.getMsId(bcp47Locale);
211 if (m_table && (be::swap<uint16>(m_table->format) == 1))
212 {
213 const uint8 * pLangEntries = reinterpret_cast<const uint8*>(m_table) +
214 sizeof(TtfUtil::Sfnt::FontNames)
215 + sizeof(TtfUtil::Sfnt::NameRecord) * ( be::swap<uint16>(m_table->count) - 1);
216 uint16 numLangEntries = be::read<uint16>(pLangEntries);
217 const TtfUtil::Sfnt::LangTagRecord * langTag =
218 reinterpret_cast<const TtfUtil::Sfnt::LangTagRecord*>(pLangEntries);
219 if (pLangEntries + numLangEntries * sizeof(TtfUtil::Sfnt::LangTagRecord) <= m_nameData)
220 {
221 for (uint16 i = 0; i < numLangEntries; i++)
222 {
223 uint16 offset = be::swap<uint16>(langTag[i].offset);
224 uint16 length = be::swap<uint16>(langTag[i].length);
225 if ((offset + length <= m_nameDataLength) && (length == 2 * localeLength))
226 {
227 const uint8* pName = m_nameData + offset;
228 bool match = true;
229 for (size_t j = 0; j < localeLength; j++)
230 {
231 uint16 code = be::read<uint16>(pName);
232 if ((code > 0x7F) || (code != bcp47Locale[j]))
233 {
234 match = false;
235 break;
236 }
237 }
238 if (match)
239 return 0x8000 + i;
240 }
241 }
242 }
243 }
244 return localeId;
245 }