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 ANY
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 ANY
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 ON
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 "platform/fonts/opentype/OpenTypeVerticalData.h"
28
29 #include "platform/SharedBuffer.h"
30 #include "platform/fonts/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
requiredSizeWebCore::OpenType::VORGTable112 size_t requiredSize() const { return sizeof(*this) + sizeof(VertOriginYMetrics) * (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
coverageWebCore::OpenType::SubstitutionSubTable137 const CoverageTable* coverage(const SharedBuffer& buffer) const { return validateOffset<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
getSubstitutionsWebCore::OpenType::LookupTable152 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 support
158 return false;
159 for (uint16_t i = 0; i < countSubTable; ++i) {
160 const SubstitutionSubTable* substitution = validateOffset<SubstitutionSubTable>(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>(buffer, coverage);
177 if (!coverage1)
178 return false;
179 uint16_t countFrom = coverage1->glyphCount;
180 if (!isValidEnd(buffer, &coverage1->glyphArray[countFrom]) || countTo != countFrom)
181 return false;
182 for (uint16_t i = 0; i < countTo; ++i)
183 map->set(coverage1->glyphArray[i], singleSubstitution2->substitute[i]);
184 break;
185 }
186 case 2: { // Coverage Format 2 (e.g., Adobe Kozuka Gothic)
187 const Coverage2Table* coverage2 = validatePtr<Coverage2Table>(buffer, 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
lookupWebCore::OpenType::LookupList215 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
getGlyphSubstitutionsWebCore::OpenType::FeatureTable229 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], buffer);
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
featureWebCore::OpenType::FeatureList250 const FeatureTable* feature(uint16_t index, OpenType::Tag tag, const SharedBuffer& 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].featureOffset);
257 return 0;
258 }
259
findFeatureWebCore::OpenType::FeatureList260 const FeatureTable* findFeature(OpenType::Tag tag, const SharedBuffer& buffer) const
261 {
262 for (uint16_t i = 0; i < featureCount; ++i) {
263 if (isValidEnd(buffer, &features[i]) && features[i].featureTag == tag)
264 return validateOffset<FeatureTable>(buffer, features[i].featureOffset);
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
featureWebCore::OpenType::LangSysTable276 const FeatureTable* feature(OpenType::Tag featureTag, const FeatureList* features, 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
defaultLangSysWebCore::OpenType::ScriptTable298 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].langSysOffset);
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
scriptWebCore::OpenType::ScriptList319 const ScriptTable* script(OpenType::Tag tag, const SharedBuffer& buffer) const
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].scriptOffset);
327 }
328 return 0;
329 }
330
defaultScriptWebCore::OpenType::ScriptList331 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::DefaultScriptTag, buffer);
337 if (scriptOfDefaultTag)
338 return scriptOfDefaultTag;
339 return validateOffset<ScriptTable>(buffer, scripts[0].scriptOffset);
340 }
341
defaultLangSysWebCore::OpenType::ScriptList342 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
scriptListWebCore::OpenType::GSUBTable357 const ScriptList* scriptList(const SharedBuffer& buffer) const { return validateOffset<ScriptList>(buffer, scriptListOffset); }
featureListWebCore::OpenType::GSUBTable358 const FeatureList* featureList(const SharedBuffer& buffer) const { return validateOffset<FeatureList>(buffer, featureListOffset); }
lookupListWebCore::OpenType::GSUBTable359 const LookupList* lookupList(const SharedBuffer& buffer) const { return validateOffset<LookupList>(buffer, lookupListOffset); }
360
defaultLangSysWebCore::OpenType::GSUBTable361 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
featureWebCore::OpenType::GSUBTable369 const FeatureTable* feature(OpenType::Tag featureTag, const SharedBuffer& buffer) 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 the first script doesn't
380 // have the requested feature, then use the first matching feature directly.
381 feature = features->findFeature(featureTag, buffer);
382 }
383 return feature;
384 }
385
getVerticalGlyphSubstitutionsWebCore::OpenType::GSUBTable386 bool getVerticalGlyphSubstitutions(HashMap<Glyph, Glyph>* map, const SharedBuffer& buffer) const
387 {
388 const FeatureTable* verticalFeatureTable = feature(OpenType::VertFeatureTag, buffer);
389 if (!verticalFeatureTable)
390 return false;
391 const LookupList* lookups = lookupList(buffer);
392 return lookups && verticalFeatureTable->getGlyphSubstitutions(lookups, map, buffer);
393 }
394 };
395
396 #pragma pack()
397
398 } // namespace OpenType
399
OpenTypeVerticalData(const FontPlatformData & platformData)400 OpenTypeVerticalData::OpenTypeVerticalData(const FontPlatformData& platformData)
401 : m_defaultVertOriginY(0)
402 {
403 loadMetrics(platformData);
404 loadVerticalGlyphSubstitutions(platformData);
405 }
406
loadMetrics(const FontPlatformData & platformData)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::HheaTable>(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::HmtxTable>(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 flow.
432 buffer = platformData.openTypeTable(OpenType::VheaTag);
433 const OpenType::VheaTable* vhea = OpenType::validateTable<OpenType::VheaTable>(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::VORGTable>(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->vertOriginYMetrics[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 flow.
460 buffer = platformData.openTypeTable(OpenType::VmtxTag);
461 const OpenType::VmtxTable* vmtx = OpenType::validateTable<OpenType::VmtxTable>(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) * countVmtxEntries;
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 OpenType::Int16*>(&vmtx->entries[countVmtxEntries]);
487 for (; i < countTopSideBearings; ++i, ++pTopSideBearingsExtra)
488 m_topSideBearings[i] = *pTopSideBearingsExtra;
489 }
490 }
491
loadVerticalGlyphSubstitutions(const FontPlatformData & platformData)492 void OpenTypeVerticalData::loadVerticalGlyphSubstitutions(const FontPlatformData& platformData)
493 {
494 RefPtr<SharedBuffer> buffer = platformData.openTypeTable(OpenType::GSUBTag);
495 const OpenType::GSUBTable* gsub = OpenType::validateTable<OpenType::GSUBTable>(buffer);
496 if (gsub)
497 gsub->getVerticalGlyphSubstitutions(&m_verticalGlyphMap, *buffer.get());
498 }
499
advanceHeight(const SimpleFontData * font,Glyph glyph) const500 float OpenTypeVerticalData::advanceHeight(const SimpleFontData* font, Glyph glyph) 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
getVerticalTranslationsForGlyphs(const SimpleFontData * font,const Glyph * glyphs,size_t count,float * outXYArray) const513 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, outXYArray += 2) {
524 Glyph glyph = *glyphs;
525 uint16_t widthFUnit = m_advanceWidths[glyph < countWidths ? glyph : countWidths - 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 < countTopSideBearings ? 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
substituteWithVerticalGlyphs(const SimpleFontData * font,GlyphPage * glyphPage,unsigned offset,unsigned length) const556 void OpenTypeVerticalData::substituteWithVerticalGlyphs(const SimpleFontData* font, 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 GlyphData glyphData = glyphPage->glyphDataForIndex(index);
564 if (glyphData.glyph && glyphData.fontData == font) {
565 Glyph to = map.get(glyphData.glyph);
566 if (to)
567 glyphPage->setGlyphDataForIndex(index, to, font);
568 }
569 }
570 }
571
572 } // namespace WebCore
573 #endif // ENABLE(OPENTYPE_VERTICAL)
574