OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2012 Koji Ishii <kojiishi@gmail.com> | |
3 * | |
4 * Redistribution and use in source and binary forms, with or without | |
5 * modification, are permitted provided that the following conditions | |
6 * are met: | |
7 * 1. Redistributions of source code must retain the above copyright | |
8 * notice, this list of conditions and the following disclaimer. | |
9 * 2. Redistributions in binary form must reproduce the above copyright | |
10 * notice, this list of conditions and the following disclaimer in the | |
11 * documentation and/or other materials provided with the distribution. | |
12 * | |
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND AN
Y | |
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR AN
Y | |
17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND O
N | |
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
23 */ | |
24 | |
25 #include "config.h" | |
26 #if ENABLE(OPENTYPE_VERTICAL) | |
27 #include "core/platform/graphics/opentype/OpenTypeVerticalData.h" | |
28 | |
29 #include "platform/SharedBuffer.h" | |
30 #include "core/platform/graphics/SimpleFontData.h" | |
31 #include "platform/fonts/GlyphPage.h" | |
32 #include "platform/fonts/opentype/OpenTypeTypes.h" | |
33 #include "platform/geometry/FloatRect.h" | |
34 #include "wtf/RefPtr.h" | |
35 | |
36 using namespace std; | |
37 | |
38 namespace WebCore { | |
39 namespace OpenType { | |
40 | |
41 const uint32_t GSUBTag = OT_MAKE_TAG('G', 'S', 'U', 'B'); | |
42 const uint32_t HheaTag = OT_MAKE_TAG('h', 'h', 'e', 'a'); | |
43 const uint32_t HmtxTag = OT_MAKE_TAG('h', 'm', 't', 'x'); | |
44 const uint32_t VheaTag = OT_MAKE_TAG('v', 'h', 'e', 'a'); | |
45 const uint32_t VmtxTag = OT_MAKE_TAG('v', 'm', 't', 'x'); | |
46 const uint32_t VORGTag = OT_MAKE_TAG('V', 'O', 'R', 'G'); | |
47 | |
48 const uint32_t DefaultScriptTag = OT_MAKE_TAG('D', 'F', 'L', 'T'); | |
49 | |
50 const uint32_t VertFeatureTag = OT_MAKE_TAG('v', 'e', 'r', 't'); | |
51 | |
52 #pragma pack(1) | |
53 | |
54 struct HheaTable { | |
55 OpenType::Fixed version; | |
56 OpenType::Int16 ascender; | |
57 OpenType::Int16 descender; | |
58 OpenType::Int16 lineGap; | |
59 OpenType::Int16 advanceWidthMax; | |
60 OpenType::Int16 minLeftSideBearing; | |
61 OpenType::Int16 minRightSideBearing; | |
62 OpenType::Int16 xMaxExtent; | |
63 OpenType::Int16 caretSlopeRise; | |
64 OpenType::Int16 caretSlopeRun; | |
65 OpenType::Int16 caretOffset; | |
66 OpenType::Int16 reserved[4]; | |
67 OpenType::Int16 metricDataFormat; | |
68 OpenType::UInt16 numberOfHMetrics; | |
69 }; | |
70 | |
71 struct VheaTable { | |
72 OpenType::Fixed version; | |
73 OpenType::Int16 ascent; | |
74 OpenType::Int16 descent; | |
75 OpenType::Int16 lineGap; | |
76 OpenType::Int16 advanceHeightMax; | |
77 OpenType::Int16 minTopSideBearing; | |
78 OpenType::Int16 minBottomSideBearing; | |
79 OpenType::Int16 yMaxExtent; | |
80 OpenType::Int16 caretSlopeRise; | |
81 OpenType::Int16 caretSlopeRun; | |
82 OpenType::Int16 caretOffset; | |
83 OpenType::Int16 reserved[4]; | |
84 OpenType::Int16 metricDataFormat; | |
85 OpenType::UInt16 numOfLongVerMetrics; | |
86 }; | |
87 | |
88 struct HmtxTable { | |
89 struct Entry { | |
90 OpenType::UInt16 advanceWidth; | |
91 OpenType::Int16 lsb; | |
92 } entries[1]; | |
93 }; | |
94 | |
95 struct VmtxTable { | |
96 struct Entry { | |
97 OpenType::UInt16 advanceHeight; | |
98 OpenType::Int16 topSideBearing; | |
99 } entries[1]; | |
100 }; | |
101 | |
102 struct VORGTable { | |
103 OpenType::UInt16 majorVersion; | |
104 OpenType::UInt16 minorVersion; | |
105 OpenType::Int16 defaultVertOriginY; | |
106 OpenType::UInt16 numVertOriginYMetrics; | |
107 struct VertOriginYMetrics { | |
108 OpenType::UInt16 glyphIndex; | |
109 OpenType::Int16 vertOriginY; | |
110 } vertOriginYMetrics[1]; | |
111 | |
112 size_t requiredSize() const { return sizeof(*this) + sizeof(VertOriginYMetri
cs) * (numVertOriginYMetrics - 1); } | |
113 }; | |
114 | |
115 struct CoverageTable : TableBase { | |
116 OpenType::UInt16 coverageFormat; | |
117 }; | |
118 | |
119 struct Coverage1Table : CoverageTable { | |
120 OpenType::UInt16 glyphCount; | |
121 OpenType::GlyphID glyphArray[1]; | |
122 }; | |
123 | |
124 struct Coverage2Table : CoverageTable { | |
125 OpenType::UInt16 rangeCount; | |
126 struct RangeRecord { | |
127 OpenType::GlyphID start; | |
128 OpenType::GlyphID end; | |
129 OpenType::UInt16 startCoverageIndex; | |
130 } ranges[1]; | |
131 }; | |
132 | |
133 struct SubstitutionSubTable : TableBase { | |
134 OpenType::UInt16 substFormat; | |
135 OpenType::Offset coverageOffset; | |
136 | |
137 const CoverageTable* coverage(const SharedBuffer& buffer) const { return val
idateOffset<CoverageTable>(buffer, coverageOffset); } | |
138 }; | |
139 | |
140 struct SingleSubstitution2SubTable : SubstitutionSubTable { | |
141 OpenType::UInt16 glyphCount; | |
142 OpenType::GlyphID substitute[1]; | |
143 }; | |
144 | |
145 struct LookupTable : TableBase { | |
146 OpenType::UInt16 lookupType; | |
147 OpenType::UInt16 lookupFlag; | |
148 OpenType::UInt16 subTableCount; | |
149 OpenType::Offset subTableOffsets[1]; | |
150 // OpenType::UInt16 markFilteringSet; this field comes after variable length
, so offset is determined dynamically. | |
151 | |
152 bool getSubstitutions(HashMap<Glyph, Glyph>* map, const SharedBuffer& buffer
) const | |
153 { | |
154 uint16_t countSubTable = subTableCount; | |
155 if (!isValidEnd(buffer, &subTableOffsets[countSubTable])) | |
156 return false; | |
157 if (lookupType != 1) // "Single Substitution Subtable" is all what we su
pport | |
158 return false; | |
159 for (uint16_t i = 0; i < countSubTable; ++i) { | |
160 const SubstitutionSubTable* substitution = validateOffset<Substituti
onSubTable>(buffer, subTableOffsets[i]); | |
161 if (!substitution) | |
162 return false; | |
163 const CoverageTable* coverage = substitution->coverage(buffer); | |
164 if (!coverage) | |
165 return false; | |
166 if (substitution->substFormat != 2) // "Single Substitution Format 2
" is all what we support | |
167 return false; | |
168 const SingleSubstitution2SubTable* singleSubstitution2 = validatePtr
<SingleSubstitution2SubTable>(buffer, substitution); | |
169 if (!singleSubstitution2) | |
170 return false; | |
171 uint16_t countTo = singleSubstitution2->glyphCount; | |
172 if (!isValidEnd(buffer, &singleSubstitution2->substitute[countTo])) | |
173 return false; | |
174 switch (coverage->coverageFormat) { | |
175 case 1: { // Coverage Format 1 (e.g., MS Gothic) | |
176 const Coverage1Table* coverage1 = validatePtr<Coverage1Table>(bu
ffer, coverage); | |
177 if (!coverage1) | |
178 return false; | |
179 uint16_t countFrom = coverage1->glyphCount; | |
180 if (!isValidEnd(buffer, &coverage1->glyphArray[countFrom]) || co
untTo != countFrom) | |
181 return false; | |
182 for (uint16_t i = 0; i < countTo; ++i) | |
183 map->set(coverage1->glyphArray[i], singleSubstitution2->subs
titute[i]); | |
184 break; | |
185 } | |
186 case 2: { // Coverage Format 2 (e.g., Adobe Kozuka Gothic) | |
187 const Coverage2Table* coverage2 = validatePtr<Coverage2Table>(bu
ffer, coverage); | |
188 if (!coverage2) | |
189 return false; | |
190 uint16_t countRange = coverage2->rangeCount; | |
191 if (!isValidEnd(buffer, &coverage2->ranges[countRange])) | |
192 return false; | |
193 for (uint16_t i = 0, indexTo = 0; i < countRange; ++i) { | |
194 uint16_t from = coverage2->ranges[i].start; | |
195 uint16_t fromEnd = coverage2->ranges[i].end + 1; // OpenType
"end" is inclusive | |
196 if (indexTo + (fromEnd - from) > countTo) | |
197 return false; | |
198 for (; from != fromEnd; ++from, ++indexTo) | |
199 map->set(from, singleSubstitution2->substitute[indexTo])
; | |
200 } | |
201 break; | |
202 } | |
203 default: | |
204 return false; | |
205 } | |
206 } | |
207 return true; | |
208 } | |
209 }; | |
210 | |
211 struct LookupList : TableBase { | |
212 OpenType::UInt16 lookupCount; | |
213 OpenType::Offset lookupOffsets[1]; | |
214 | |
215 const LookupTable* lookup(uint16_t index, const SharedBuffer& buffer) const | |
216 { | |
217 uint16_t count = lookupCount; | |
218 if (index >= count || !isValidEnd(buffer, &lookupOffsets[count])) | |
219 return 0; | |
220 return validateOffset<LookupTable>(buffer, lookupOffsets[index]); | |
221 } | |
222 }; | |
223 | |
224 struct FeatureTable : TableBase { | |
225 OpenType::Offset featureParams; | |
226 OpenType::UInt16 lookupCount; | |
227 OpenType::UInt16 lookupListIndex[1]; | |
228 | |
229 bool getGlyphSubstitutions(const LookupList* lookups, HashMap<Glyph, Glyph>*
map, const SharedBuffer& buffer) const | |
230 { | |
231 uint16_t count = lookupCount; | |
232 if (!isValidEnd(buffer, &lookupListIndex[count])) | |
233 return false; | |
234 for (uint16_t i = 0; i < count; ++i) { | |
235 const LookupTable* lookup = lookups->lookup(lookupListIndex[i], buff
er); | |
236 if (!lookup || !lookup->getSubstitutions(map, buffer)) | |
237 return false; | |
238 } | |
239 return true; | |
240 } | |
241 }; | |
242 | |
243 struct FeatureList : TableBase { | |
244 OpenType::UInt16 featureCount; | |
245 struct FeatureRecord { | |
246 OpenType::Tag featureTag; | |
247 OpenType::Offset featureOffset; | |
248 } features[1]; | |
249 | |
250 const FeatureTable* feature(uint16_t index, OpenType::Tag tag, const SharedB
uffer& buffer) const | |
251 { | |
252 uint16_t count = featureCount; | |
253 if (index >= count || !isValidEnd(buffer, &features[count])) | |
254 return 0; | |
255 if (features[index].featureTag == tag) | |
256 return validateOffset<FeatureTable>(buffer, features[index].featureO
ffset); | |
257 return 0; | |
258 } | |
259 | |
260 const FeatureTable* findFeature(OpenType::Tag tag, const SharedBuffer& buffe
r) const | |
261 { | |
262 for (uint16_t i = 0; i < featureCount; ++i) { | |
263 if (isValidEnd(buffer, &features[i]) && features[i].featureTag == ta
g) | |
264 return validateOffset<FeatureTable>(buffer, features[i].featureO
ffset); | |
265 } | |
266 return 0; | |
267 } | |
268 }; | |
269 | |
270 struct LangSysTable : TableBase { | |
271 OpenType::Offset lookupOrder; | |
272 OpenType::UInt16 reqFeatureIndex; | |
273 OpenType::UInt16 featureCount; | |
274 OpenType::UInt16 featureIndex[1]; | |
275 | |
276 const FeatureTable* feature(OpenType::Tag featureTag, const FeatureList* fea
tures, const SharedBuffer& buffer) const | |
277 { | |
278 uint16_t count = featureCount; | |
279 if (!isValidEnd(buffer, &featureIndex[count])) | |
280 return 0; | |
281 for (uint16_t i = 0; i < count; ++i) { | |
282 const FeatureTable* featureTable = features->feature(featureIndex[i]
, featureTag, buffer); | |
283 if (featureTable) | |
284 return featureTable; | |
285 } | |
286 return 0; | |
287 } | |
288 }; | |
289 | |
290 struct ScriptTable : TableBase { | |
291 OpenType::Offset defaultLangSysOffset; | |
292 OpenType::UInt16 langSysCount; | |
293 struct LangSysRecord { | |
294 OpenType::Tag langSysTag; | |
295 OpenType::Offset langSysOffset; | |
296 } langSysRecords[1]; | |
297 | |
298 const LangSysTable* defaultLangSys(const SharedBuffer& buffer) const | |
299 { | |
300 uint16_t count = langSysCount; | |
301 if (!isValidEnd(buffer, &langSysRecords[count])) | |
302 return 0; | |
303 uint16_t offset = defaultLangSysOffset; | |
304 if (offset) | |
305 return validateOffset<LangSysTable>(buffer, offset); | |
306 if (count) | |
307 return validateOffset<LangSysTable>(buffer, langSysRecords[0].langSy
sOffset); | |
308 return 0; | |
309 } | |
310 }; | |
311 | |
312 struct ScriptList : TableBase { | |
313 OpenType::UInt16 scriptCount; | |
314 struct ScriptRecord { | |
315 OpenType::Tag scriptTag; | |
316 OpenType::Offset scriptOffset; | |
317 } scripts[1]; | |
318 | |
319 const ScriptTable* script(OpenType::Tag tag, const SharedBuffer& buffer) con
st | |
320 { | |
321 uint16_t count = scriptCount; | |
322 if (!isValidEnd(buffer, &scripts[count])) | |
323 return 0; | |
324 for (uint16_t i = 0; i < count; ++i) { | |
325 if (scripts[i].scriptTag == tag) | |
326 return validateOffset<ScriptTable>(buffer, scripts[i].scriptOffs
et); | |
327 } | |
328 return 0; | |
329 } | |
330 | |
331 const ScriptTable* defaultScript(const SharedBuffer& buffer) const | |
332 { | |
333 uint16_t count = scriptCount; | |
334 if (!count || !isValidEnd(buffer, &scripts[count])) | |
335 return 0; | |
336 const ScriptTable* scriptOfDefaultTag = script(OpenType::DefaultScriptTa
g, buffer); | |
337 if (scriptOfDefaultTag) | |
338 return scriptOfDefaultTag; | |
339 return validateOffset<ScriptTable>(buffer, scripts[0].scriptOffset); | |
340 } | |
341 | |
342 const LangSysTable* defaultLangSys(const SharedBuffer& buffer) const | |
343 { | |
344 const ScriptTable* scriptTable = defaultScript(buffer); | |
345 if (!scriptTable) | |
346 return 0; | |
347 return scriptTable->defaultLangSys(buffer); | |
348 } | |
349 }; | |
350 | |
351 struct GSUBTable : TableBase { | |
352 OpenType::Fixed version; | |
353 OpenType::Offset scriptListOffset; | |
354 OpenType::Offset featureListOffset; | |
355 OpenType::Offset lookupListOffset; | |
356 | |
357 const ScriptList* scriptList(const SharedBuffer& buffer) const { return vali
dateOffset<ScriptList>(buffer, scriptListOffset); } | |
358 const FeatureList* featureList(const SharedBuffer& buffer) const { return va
lidateOffset<FeatureList>(buffer, featureListOffset); } | |
359 const LookupList* lookupList(const SharedBuffer& buffer) const { return vali
dateOffset<LookupList>(buffer, lookupListOffset); } | |
360 | |
361 const LangSysTable* defaultLangSys(const SharedBuffer& buffer) const | |
362 { | |
363 const ScriptList* scripts = scriptList(buffer); | |
364 if (!scripts) | |
365 return 0; | |
366 return scripts->defaultLangSys(buffer); | |
367 } | |
368 | |
369 const FeatureTable* feature(OpenType::Tag featureTag, const SharedBuffer& bu
ffer) const | |
370 { | |
371 const LangSysTable* langSys = defaultLangSys(buffer); | |
372 const FeatureList* features = featureList(buffer); | |
373 if (!features) | |
374 return 0; | |
375 const FeatureTable* feature = 0; | |
376 if (langSys) | |
377 feature = langSys->feature(featureTag, features, buffer); | |
378 if (!feature) { | |
379 // If the font has no langSys table, or has no default script and th
e first script doesn't | |
380 // have the requested feature, then use the first matching feature d
irectly. | |
381 feature = features->findFeature(featureTag, buffer); | |
382 } | |
383 return feature; | |
384 } | |
385 | |
386 bool getVerticalGlyphSubstitutions(HashMap<Glyph, Glyph>* map, const SharedB
uffer& buffer) const | |
387 { | |
388 const FeatureTable* verticalFeatureTable = feature(OpenType::VertFeature
Tag, buffer); | |
389 if (!verticalFeatureTable) | |
390 return false; | |
391 const LookupList* lookups = lookupList(buffer); | |
392 return lookups && verticalFeatureTable->getGlyphSubstitutions(lookups, m
ap, buffer); | |
393 } | |
394 }; | |
395 | |
396 #pragma pack() | |
397 | |
398 } // namespace OpenType | |
399 | |
400 OpenTypeVerticalData::OpenTypeVerticalData(const FontPlatformData& platformData) | |
401 : m_defaultVertOriginY(0) | |
402 { | |
403 loadMetrics(platformData); | |
404 loadVerticalGlyphSubstitutions(platformData); | |
405 } | |
406 | |
407 void OpenTypeVerticalData::loadMetrics(const FontPlatformData& platformData) | |
408 { | |
409 // Load hhea and hmtx to get x-component of vertical origins. | |
410 // If these tables are missing, it's not an OpenType font. | |
411 RefPtr<SharedBuffer> buffer = platformData.openTypeTable(OpenType::HheaTag); | |
412 const OpenType::HheaTable* hhea = OpenType::validateTable<OpenType::HheaTabl
e>(buffer); | |
413 if (!hhea) | |
414 return; | |
415 uint16_t countHmtxEntries = hhea->numberOfHMetrics; | |
416 if (!countHmtxEntries) { | |
417 WTF_LOG_ERROR("Invalid numberOfHMetrics"); | |
418 return; | |
419 } | |
420 | |
421 buffer = platformData.openTypeTable(OpenType::HmtxTag); | |
422 const OpenType::HmtxTable* hmtx = OpenType::validateTable<OpenType::HmtxTabl
e>(buffer, countHmtxEntries); | |
423 if (!hmtx) { | |
424 WTF_LOG_ERROR("hhea exists but hmtx does not (or broken)"); | |
425 return; | |
426 } | |
427 m_advanceWidths.resize(countHmtxEntries); | |
428 for (uint16_t i = 0; i < countHmtxEntries; ++i) | |
429 m_advanceWidths[i] = hmtx->entries[i].advanceWidth; | |
430 | |
431 // Load vhea first. This table is required for fonts that support vertical f
low. | |
432 buffer = platformData.openTypeTable(OpenType::VheaTag); | |
433 const OpenType::VheaTable* vhea = OpenType::validateTable<OpenType::VheaTabl
e>(buffer); | |
434 if (!vhea) | |
435 return; | |
436 uint16_t countVmtxEntries = vhea->numOfLongVerMetrics; | |
437 if (!countVmtxEntries) { | |
438 WTF_LOG_ERROR("Invalid numOfLongVerMetrics"); | |
439 return; | |
440 } | |
441 | |
442 // Load VORG. This table is optional. | |
443 buffer = platformData.openTypeTable(OpenType::VORGTag); | |
444 const OpenType::VORGTable* vorg = OpenType::validateTable<OpenType::VORGTabl
e>(buffer); | |
445 if (vorg && buffer->size() >= vorg->requiredSize()) { | |
446 m_defaultVertOriginY = vorg->defaultVertOriginY; | |
447 uint16_t countVertOriginYMetrics = vorg->numVertOriginYMetrics; | |
448 if (!countVertOriginYMetrics) { | |
449 // Add one entry so that hasVORG() becomes true | |
450 m_vertOriginY.set(0, m_defaultVertOriginY); | |
451 } else { | |
452 for (uint16_t i = 0; i < countVertOriginYMetrics; ++i) { | |
453 const OpenType::VORGTable::VertOriginYMetrics& metrics = vorg->v
ertOriginYMetrics[i]; | |
454 m_vertOriginY.set(metrics.glyphIndex, metrics.vertOriginY); | |
455 } | |
456 } | |
457 } | |
458 | |
459 // Load vmtx then. This table is required for fonts that support vertical fl
ow. | |
460 buffer = platformData.openTypeTable(OpenType::VmtxTag); | |
461 const OpenType::VmtxTable* vmtx = OpenType::validateTable<OpenType::VmtxTabl
e>(buffer, countVmtxEntries); | |
462 if (!vmtx) { | |
463 WTF_LOG_ERROR("vhea exists but vmtx does not (or broken)"); | |
464 return; | |
465 } | |
466 m_advanceHeights.resize(countVmtxEntries); | |
467 for (uint16_t i = 0; i < countVmtxEntries; ++i) | |
468 m_advanceHeights[i] = vmtx->entries[i].advanceHeight; | |
469 | |
470 // VORG is preferred way to calculate vertical origin than vmtx, | |
471 // so load topSideBearing from vmtx only if VORG is missing. | |
472 if (hasVORG()) | |
473 return; | |
474 | |
475 size_t sizeExtra = buffer->size() - sizeof(OpenType::VmtxTable::Entry) * cou
ntVmtxEntries; | |
476 if (sizeExtra % sizeof(OpenType::Int16)) { | |
477 WTF_LOG_ERROR("vmtx has incorrect tsb count"); | |
478 return; | |
479 } | |
480 size_t countTopSideBearings = countVmtxEntries + sizeExtra / sizeof(OpenType
::Int16); | |
481 m_topSideBearings.resize(countTopSideBearings); | |
482 size_t i; | |
483 for (i = 0; i < countVmtxEntries; ++i) | |
484 m_topSideBearings[i] = vmtx->entries[i].topSideBearing; | |
485 if (i < countTopSideBearings) { | |
486 const OpenType::Int16* pTopSideBearingsExtra = reinterpret_cast<const Op
enType::Int16*>(&vmtx->entries[countVmtxEntries]); | |
487 for (; i < countTopSideBearings; ++i, ++pTopSideBearingsExtra) | |
488 m_topSideBearings[i] = *pTopSideBearingsExtra; | |
489 } | |
490 } | |
491 | |
492 void OpenTypeVerticalData::loadVerticalGlyphSubstitutions(const FontPlatformData
& platformData) | |
493 { | |
494 RefPtr<SharedBuffer> buffer = platformData.openTypeTable(OpenType::GSUBTag); | |
495 const OpenType::GSUBTable* gsub = OpenType::validateTable<OpenType::GSUBTabl
e>(buffer); | |
496 if (gsub) | |
497 gsub->getVerticalGlyphSubstitutions(&m_verticalGlyphMap, *buffer.get()); | |
498 } | |
499 | |
500 float OpenTypeVerticalData::advanceHeight(const SimpleFontData* font, Glyph glyp
h) const | |
501 { | |
502 size_t countHeights = m_advanceHeights.size(); | |
503 if (countHeights) { | |
504 uint16_t advanceFUnit = m_advanceHeights[glyph < countHeights ? glyph :
countHeights - 1]; | |
505 float advance = advanceFUnit * font->sizePerUnit(); | |
506 return advance; | |
507 } | |
508 | |
509 // No vertical info in the font file; use height as advance. | |
510 return font->fontMetrics().height(); | |
511 } | |
512 | |
513 void OpenTypeVerticalData::getVerticalTranslationsForGlyphs(const SimpleFontData
* font, const Glyph* glyphs, size_t count, float* outXYArray) const | |
514 { | |
515 size_t countWidths = m_advanceWidths.size(); | |
516 ASSERT(countWidths > 0); | |
517 const FontMetrics& metrics = font->fontMetrics(); | |
518 float sizePerUnit = font->sizePerUnit(); | |
519 float ascent = metrics.ascent(); | |
520 bool useVORG = hasVORG(); | |
521 size_t countTopSideBearings = m_topSideBearings.size(); | |
522 float defaultVertOriginY = std::numeric_limits<float>::quiet_NaN(); | |
523 for (float* end = &(outXYArray[count * 2]); outXYArray != end; ++glyphs, out
XYArray += 2) { | |
524 Glyph glyph = *glyphs; | |
525 uint16_t widthFUnit = m_advanceWidths[glyph < countWidths ? glyph : coun
tWidths - 1]; | |
526 float width = widthFUnit * sizePerUnit; | |
527 outXYArray[0] = -width / 2; | |
528 | |
529 // For Y, try VORG first. | |
530 if (useVORG) { | |
531 int16_t vertOriginYFUnit = m_vertOriginY.get(glyph); | |
532 if (vertOriginYFUnit) { | |
533 outXYArray[1] = -vertOriginYFUnit * sizePerUnit; | |
534 continue; | |
535 } | |
536 if (std::isnan(defaultVertOriginY)) | |
537 defaultVertOriginY = -m_defaultVertOriginY * sizePerUnit; | |
538 outXYArray[1] = defaultVertOriginY; | |
539 continue; | |
540 } | |
541 | |
542 // If no VORG, try vmtx next. | |
543 if (countTopSideBearings) { | |
544 int16_t topSideBearingFUnit = m_topSideBearings[glyph < countTopSide
Bearings ? glyph : countTopSideBearings - 1]; | |
545 float topSideBearing = topSideBearingFUnit * sizePerUnit; | |
546 FloatRect bounds = font->boundsForGlyph(glyph); | |
547 outXYArray[1] = bounds.y() - topSideBearing; | |
548 continue; | |
549 } | |
550 | |
551 // No vertical info in the font file; use ascent as vertical origin. | |
552 outXYArray[1] = -ascent; | |
553 } | |
554 } | |
555 | |
556 void OpenTypeVerticalData::substituteWithVerticalGlyphs(const SimpleFontData* fo
nt, GlyphPage* glyphPage, unsigned offset, unsigned length) const | |
557 { | |
558 const HashMap<Glyph, Glyph>& map = m_verticalGlyphMap; | |
559 if (map.isEmpty()) | |
560 return; | |
561 | |
562 for (unsigned index = offset, end = offset + length; index < end; ++index) { | |
563 Glyph glyph = glyphPage->glyphAt(index); | |
564 if (glyph) { | |
565 ASSERT(glyphPage->glyphDataForIndex(index).fontData == font); | |
566 Glyph to = map.get(glyph); | |
567 if (to) | |
568 glyphPage->setGlyphDataForIndex(index, to, font); | |
569 } | |
570 } | |
571 } | |
572 | |
573 } // namespace WebCore | |
574 #endif // ENABLE(OPENTYPE_VERTICAL) | |
OLD | NEW |