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 "OpenTypeVerticalData.h"
28
29#include "FloatRect.h"
30#include "GlyphPage.h"
31#include "OpenTypeTypes.h"
32#include "SharedBuffer.h"
33#include "SimpleFontData.h"
34#include <wtf/RefPtr.h>
35
36using namespace std;
37
38namespace WebCore {
39namespace OpenType {
40
41const uint32_t GSUBTag = OT_MAKE_TAG('G', 'S', 'U', 'B');
42const uint32_t HheaTag = OT_MAKE_TAG('h', 'h', 'e', 'a');
43const uint32_t HmtxTag = OT_MAKE_TAG('h', 'm', 't', 'x');
44const uint32_t VheaTag = OT_MAKE_TAG('v', 'h', 'e', 'a');
45const uint32_t VmtxTag = OT_MAKE_TAG('v', 'm', 't', 'x');
46const uint32_t VORGTag = OT_MAKE_TAG('V', 'O', 'R', 'G');
47
48const uint32_t DefaultScriptTag = OT_MAKE_TAG('D', 'F', 'L', 'T');
49
50const uint32_t VertFeatureTag = OT_MAKE_TAG('v', 'e', 'r', 't');
51
52#pragma pack(1)
53
54struct 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
71struct 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
88struct HmtxTable {
89    struct Entry {
90        OpenType::UInt16 advanceWidth;
91        OpenType::Int16 lsb;
92    } entries[1];
93};
94
95struct VmtxTable {
96    struct Entry {
97        OpenType::UInt16 advanceHeight;
98        OpenType::Int16 topSideBearing;
99    } entries[1];
100};
101
102struct 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(VertOriginYMetrics) * (numVertOriginYMetrics - 1); }
113};
114
115struct SubstitutionSubTable : TableBase {
116    OpenType::UInt16 substFormat;
117    OpenType::Offset coverageOffset;
118
119    const CoverageTable* coverage(const SharedBuffer& buffer) const { return validateOffset<CoverageTable>(buffer, coverageOffset); }
120};
121
122struct SingleSubstitution2SubTable : SubstitutionSubTable {
123    OpenType::UInt16 glyphCount;
124    OpenType::GlyphID substitute[1];
125};
126
127struct LookupTable : TableBase {
128    OpenType::UInt16 lookupType;
129    OpenType::UInt16 lookupFlag;
130    OpenType::UInt16 subTableCount;
131    OpenType::Offset subTableOffsets[1];
132    // OpenType::UInt16 markFilteringSet; this field comes after variable length, so offset is determined dynamically.
133
134    bool getSubstitutions(HashMap<Glyph, Glyph>* map, const SharedBuffer& buffer) const
135    {
136        uint16_t countSubTable = subTableCount;
137        if (!isValidEnd(buffer, &subTableOffsets[countSubTable]))
138            return false;
139        if (lookupType != 1) // "Single Substitution Subtable" is all what we support
140            return false;
141        for (uint16_t i = 0; i < countSubTable; ++i) {
142            const SubstitutionSubTable* substitution = validateOffset<SubstitutionSubTable>(buffer, subTableOffsets[i]);
143            if (!substitution)
144                return false;
145            const CoverageTable* coverage = substitution->coverage(buffer);
146            if (!coverage)
147                return false;
148            if (substitution->substFormat != 2) // "Single Substitution Format 2" is all what we support
149                return false;
150            const SingleSubstitution2SubTable* singleSubstitution2 = validatePtr<SingleSubstitution2SubTable>(buffer, substitution);
151            if (!singleSubstitution2)
152                return false;
153            uint16_t countTo = singleSubstitution2->glyphCount;
154            if (!isValidEnd(buffer, &singleSubstitution2->substitute[countTo]))
155                return false;
156            switch (coverage->coverageFormat) {
157            case 1: { // Coverage Format 1 (e.g., MS Gothic)
158                const Coverage1Table* coverage1 = validatePtr<Coverage1Table>(buffer, coverage);
159                if (!coverage1)
160                    return false;
161                uint16_t countFrom = coverage1->glyphCount;
162                if (!isValidEnd(buffer, &coverage1->glyphArray[countFrom]) || countTo != countFrom)
163                    return false;
164                for (uint16_t i = 0; i < countTo; ++i)
165                    map->set(coverage1->glyphArray[i], singleSubstitution2->substitute[i]);
166                break;
167            }
168            case 2: { // Coverage Format 2 (e.g., Adobe Kozuka Gothic)
169                const Coverage2Table* coverage2 = validatePtr<Coverage2Table>(buffer, coverage);
170                if (!coverage2)
171                    return false;
172                uint16_t countRange = coverage2->rangeCount;
173                if (!isValidEnd(buffer, &coverage2->ranges[countRange]))
174                    return false;
175                for (uint16_t i = 0, indexTo = 0; i < countRange; ++i) {
176                    uint16_t from = coverage2->ranges[i].start;
177                    uint16_t fromEnd = coverage2->ranges[i].end + 1; // OpenType "end" is inclusive
178                    if (indexTo + (fromEnd - from) > countTo)
179                        return false;
180                    for (; from != fromEnd; ++from, ++indexTo)
181                        map->set(from, singleSubstitution2->substitute[indexTo]);
182                }
183                break;
184            }
185            default:
186                return false;
187            }
188        }
189        return true;
190    }
191};
192
193struct LookupList : TableBase {
194    OpenType::UInt16 lookupCount;
195    OpenType::Offset lookupOffsets[1];
196
197    const LookupTable* lookup(uint16_t index, const SharedBuffer& buffer) const
198    {
199        uint16_t count = lookupCount;
200        if (index >= count || !isValidEnd(buffer, &lookupOffsets[count]))
201            return 0;
202        return validateOffset<LookupTable>(buffer, lookupOffsets[index]);
203    }
204};
205
206struct FeatureTable : TableBase {
207    OpenType::Offset featureParams;
208    OpenType::UInt16 lookupCount;
209    OpenType::UInt16 lookupListIndex[1];
210
211    bool getGlyphSubstitutions(const LookupList* lookups, HashMap<Glyph, Glyph>* map, const SharedBuffer& buffer) const
212    {
213        uint16_t count = lookupCount;
214        if (!isValidEnd(buffer, &lookupListIndex[count]))
215            return false;
216        for (uint16_t i = 0; i < count; ++i) {
217            const LookupTable* lookup = lookups->lookup(lookupListIndex[i], buffer);
218            if (!lookup || !lookup->getSubstitutions(map, buffer))
219                return false;
220        }
221        return true;
222    }
223};
224
225struct FeatureList : TableBase {
226    OpenType::UInt16 featureCount;
227    struct FeatureRecord {
228        OpenType::Tag featureTag;
229        OpenType::Offset featureOffset;
230    } features[1];
231
232    const FeatureTable* feature(uint16_t index, OpenType::Tag tag, const SharedBuffer& buffer) const
233    {
234        uint16_t count = featureCount;
235        if (index >= count || !isValidEnd(buffer, &features[count]))
236            return 0;
237        if (features[index].featureTag == tag)
238            return validateOffset<FeatureTable>(buffer, features[index].featureOffset);
239        return 0;
240    }
241
242    const FeatureTable* findFeature(OpenType::Tag tag, const SharedBuffer& buffer) const
243    {
244        for (uint16_t i = 0; i < featureCount; ++i) {
245            if (isValidEnd(buffer, &features[i]) && features[i].featureTag == tag)
246                return validateOffset<FeatureTable>(buffer, features[i].featureOffset);
247        }
248        return 0;
249    }
250};
251
252struct LangSysTable : TableBase {
253    OpenType::Offset lookupOrder;
254    OpenType::UInt16 reqFeatureIndex;
255    OpenType::UInt16 featureCount;
256    OpenType::UInt16 featureIndex[1];
257
258    const FeatureTable* feature(OpenType::Tag featureTag, const FeatureList* features, const SharedBuffer& buffer) const
259    {
260        uint16_t count = featureCount;
261        if (!isValidEnd(buffer, &featureIndex[count]))
262            return 0;
263        for (uint16_t i = 0; i < count; ++i) {
264            const FeatureTable* featureTable = features->feature(featureIndex[i], featureTag, buffer);
265            if (featureTable)
266                return featureTable;
267        }
268        return 0;
269    }
270};
271
272struct ScriptTable : TableBase {
273    OpenType::Offset defaultLangSysOffset;
274    OpenType::UInt16 langSysCount;
275    struct LangSysRecord {
276        OpenType::Tag langSysTag;
277        OpenType::Offset langSysOffset;
278    } langSysRecords[1];
279
280    const LangSysTable* defaultLangSys(const SharedBuffer& buffer) const
281    {
282        uint16_t count = langSysCount;
283        if (!isValidEnd(buffer, &langSysRecords[count]))
284            return 0;
285        uint16_t offset = defaultLangSysOffset;
286        if (offset)
287            return validateOffset<LangSysTable>(buffer, offset);
288        if (count)
289            return validateOffset<LangSysTable>(buffer, langSysRecords[0].langSysOffset);
290        return 0;
291    }
292};
293
294struct ScriptList : TableBase {
295    OpenType::UInt16 scriptCount;
296    struct ScriptRecord {
297        OpenType::Tag scriptTag;
298        OpenType::Offset scriptOffset;
299    } scripts[1];
300
301    const ScriptTable* script(OpenType::Tag tag, const SharedBuffer& buffer) const
302    {
303        uint16_t count = scriptCount;
304        if (!isValidEnd(buffer, &scripts[count]))
305            return 0;
306        for (uint16_t i = 0; i < count; ++i) {
307            if (scripts[i].scriptTag == tag)
308                return validateOffset<ScriptTable>(buffer, scripts[i].scriptOffset);
309        }
310        return 0;
311    }
312
313    const ScriptTable* defaultScript(const SharedBuffer& buffer) const
314    {
315        uint16_t count = scriptCount;
316        if (!count || !isValidEnd(buffer, &scripts[count]))
317            return 0;
318        const ScriptTable* scriptOfDefaultTag = script(OpenType::DefaultScriptTag, buffer);
319        if (scriptOfDefaultTag)
320            return scriptOfDefaultTag;
321        return validateOffset<ScriptTable>(buffer, scripts[0].scriptOffset);
322    }
323
324    const LangSysTable* defaultLangSys(const SharedBuffer& buffer) const
325    {
326        const ScriptTable* scriptTable = defaultScript(buffer);
327        if (!scriptTable)
328            return 0;
329        return scriptTable->defaultLangSys(buffer);
330    }
331};
332
333struct GSUBTable : TableBase {
334    OpenType::Fixed version;
335    OpenType::Offset scriptListOffset;
336    OpenType::Offset featureListOffset;
337    OpenType::Offset lookupListOffset;
338
339    const ScriptList* scriptList(const SharedBuffer& buffer) const { return validateOffset<ScriptList>(buffer, scriptListOffset); }
340    const FeatureList* featureList(const SharedBuffer& buffer) const { return validateOffset<FeatureList>(buffer, featureListOffset); }
341    const LookupList* lookupList(const SharedBuffer& buffer) const { return validateOffset<LookupList>(buffer, lookupListOffset); }
342
343    const LangSysTable* defaultLangSys(const SharedBuffer& buffer) const
344    {
345        const ScriptList* scripts = scriptList(buffer);
346        if (!scripts)
347            return 0;
348        return scripts->defaultLangSys(buffer);
349    }
350
351    const FeatureTable* feature(OpenType::Tag featureTag, const SharedBuffer& buffer) const
352    {
353        const LangSysTable* langSys = defaultLangSys(buffer);
354        const FeatureList* features = featureList(buffer);
355        if (!features)
356            return 0;
357        const FeatureTable* feature = 0;
358        if (langSys)
359            feature = langSys->feature(featureTag, features, buffer);
360        if (!feature) {
361            // If the font has no langSys table, or has no default script and the first script doesn't
362            // have the requested feature, then use the first matching feature directly.
363            feature = features->findFeature(featureTag, buffer);
364        }
365        return feature;
366    }
367
368    bool getVerticalGlyphSubstitutions(HashMap<Glyph, Glyph>* map, const SharedBuffer& buffer) const
369    {
370        const FeatureTable* verticalFeatureTable = feature(OpenType::VertFeatureTag, buffer);
371        if (!verticalFeatureTable)
372            return false;
373        const LookupList* lookups = lookupList(buffer);
374        return lookups && verticalFeatureTable->getGlyphSubstitutions(lookups, map, buffer);
375    }
376};
377
378#pragma pack()
379
380} // namespace OpenType
381
382OpenTypeVerticalData::OpenTypeVerticalData(const FontPlatformData& platformData)
383    : m_defaultVertOriginY(0)
384{
385    loadMetrics(platformData);
386    loadVerticalGlyphSubstitutions(platformData);
387}
388
389void OpenTypeVerticalData::loadMetrics(const FontPlatformData& platformData)
390{
391    // Load hhea and hmtx to get x-component of vertical origins.
392    // If these tables are missing, it's not an OpenType font.
393    RefPtr<SharedBuffer> buffer = platformData.openTypeTable(OpenType::HheaTag);
394    const OpenType::HheaTable* hhea = OpenType::validateTable<OpenType::HheaTable>(buffer);
395    if (!hhea)
396        return;
397    uint16_t countHmtxEntries = hhea->numberOfHMetrics;
398    if (!countHmtxEntries) {
399        LOG_ERROR("Invalid numberOfHMetrics");
400        return;
401    }
402
403    buffer = platformData.openTypeTable(OpenType::HmtxTag);
404    const OpenType::HmtxTable* hmtx = OpenType::validateTable<OpenType::HmtxTable>(buffer, countHmtxEntries);
405    if (!hmtx) {
406        LOG_ERROR("hhea exists but hmtx does not (or broken)");
407        return;
408    }
409    m_advanceWidths.resize(countHmtxEntries);
410    for (uint16_t i = 0; i < countHmtxEntries; ++i)
411        m_advanceWidths[i] = hmtx->entries[i].advanceWidth;
412
413    // Load vhea first. This table is required for fonts that support vertical flow.
414    buffer = platformData.openTypeTable(OpenType::VheaTag);
415    const OpenType::VheaTable* vhea = OpenType::validateTable<OpenType::VheaTable>(buffer);
416    if (!vhea)
417        return;
418    uint16_t countVmtxEntries = vhea->numOfLongVerMetrics;
419    if (!countVmtxEntries) {
420        LOG_ERROR("Invalid numOfLongVerMetrics");
421        return;
422    }
423
424    // Load VORG. This table is optional.
425    buffer = platformData.openTypeTable(OpenType::VORGTag);
426    const OpenType::VORGTable* vorg = OpenType::validateTable<OpenType::VORGTable>(buffer);
427    if (vorg && buffer->size() >= vorg->requiredSize()) {
428        m_defaultVertOriginY = vorg->defaultVertOriginY;
429        uint16_t countVertOriginYMetrics = vorg->numVertOriginYMetrics;
430        if (!countVertOriginYMetrics) {
431            // Add one entry so that hasVORG() becomes true
432            m_vertOriginY.set(0, m_defaultVertOriginY);
433        } else {
434            for (uint16_t i = 0; i < countVertOriginYMetrics; ++i) {
435                const OpenType::VORGTable::VertOriginYMetrics& metrics = vorg->vertOriginYMetrics[i];
436                m_vertOriginY.set(metrics.glyphIndex, metrics.vertOriginY);
437            }
438        }
439    }
440
441    // Load vmtx then. This table is required for fonts that support vertical flow.
442    buffer = platformData.openTypeTable(OpenType::VmtxTag);
443    const OpenType::VmtxTable* vmtx = OpenType::validateTable<OpenType::VmtxTable>(buffer, countVmtxEntries);
444    if (!vmtx) {
445        LOG_ERROR("vhea exists but vmtx does not (or broken)");
446        return;
447    }
448    m_advanceHeights.resize(countVmtxEntries);
449    for (uint16_t i = 0; i < countVmtxEntries; ++i)
450        m_advanceHeights[i] = vmtx->entries[i].advanceHeight;
451
452    // VORG is preferred way to calculate vertical origin than vmtx,
453    // so load topSideBearing from vmtx only if VORG is missing.
454    if (hasVORG())
455        return;
456
457    size_t sizeExtra = buffer->size() - sizeof(OpenType::VmtxTable::Entry) * countVmtxEntries;
458    if (sizeExtra % sizeof(OpenType::Int16)) {
459        LOG_ERROR("vmtx has incorrect tsb count");
460        return;
461    }
462    size_t countTopSideBearings = countVmtxEntries + sizeExtra / sizeof(OpenType::Int16);
463    m_topSideBearings.resize(countTopSideBearings);
464    size_t i;
465    for (i = 0; i < countVmtxEntries; ++i)
466        m_topSideBearings[i] = vmtx->entries[i].topSideBearing;
467    if (i < countTopSideBearings) {
468        const OpenType::Int16* pTopSideBearingsExtra = reinterpret_cast<const OpenType::Int16*>(&vmtx->entries[countVmtxEntries]);
469        for (; i < countTopSideBearings; ++i, ++pTopSideBearingsExtra)
470            m_topSideBearings[i] = *pTopSideBearingsExtra;
471    }
472}
473
474void OpenTypeVerticalData::loadVerticalGlyphSubstitutions(const FontPlatformData& platformData)
475{
476    RefPtr<SharedBuffer> buffer = platformData.openTypeTable(OpenType::GSUBTag);
477    const OpenType::GSUBTable* gsub = OpenType::validateTable<OpenType::GSUBTable>(buffer);
478    if (gsub)
479        gsub->getVerticalGlyphSubstitutions(&m_verticalGlyphMap, *buffer.get());
480}
481
482float OpenTypeVerticalData::advanceHeight(const SimpleFontData* font, Glyph glyph) const
483{
484    size_t countHeights = m_advanceHeights.size();
485    if (countHeights) {
486        uint16_t advanceFUnit = m_advanceHeights[glyph < countHeights ? glyph : countHeights - 1];
487        float advance = advanceFUnit * font->sizePerUnit();
488        return advance;
489    }
490
491    // No vertical info in the font file; use height as advance.
492    return font->fontMetrics().height();
493}
494
495void OpenTypeVerticalData::getVerticalTranslationsForGlyphs(const SimpleFontData* font, const Glyph* glyphs, size_t count, float* outXYArray) const
496{
497    size_t countWidths = m_advanceWidths.size();
498    ASSERT(countWidths > 0);
499    const FontMetrics& metrics = font->fontMetrics();
500    float sizePerUnit = font->sizePerUnit();
501    float ascent = metrics.ascent();
502    bool useVORG = hasVORG();
503    size_t countTopSideBearings = m_topSideBearings.size();
504    float defaultVertOriginY = std::numeric_limits<float>::quiet_NaN();
505    for (float* end = &(outXYArray[count * 2]); outXYArray != end; ++glyphs, outXYArray += 2) {
506        Glyph glyph = *glyphs;
507        uint16_t widthFUnit = m_advanceWidths[glyph < countWidths ? glyph : countWidths - 1];
508        float width = widthFUnit * sizePerUnit;
509        outXYArray[0] = -width / 2;
510
511        // For Y, try VORG first.
512        if (useVORG) {
513            int16_t vertOriginYFUnit = m_vertOriginY.get(glyph);
514            if (vertOriginYFUnit) {
515                outXYArray[1] = -vertOriginYFUnit * sizePerUnit;
516                continue;
517            }
518            if (std::isnan(defaultVertOriginY))
519                defaultVertOriginY = -m_defaultVertOriginY * sizePerUnit;
520            outXYArray[1] = defaultVertOriginY;
521            continue;
522        }
523
524        // If no VORG, try vmtx next.
525        if (countTopSideBearings) {
526            int16_t topSideBearingFUnit = m_topSideBearings[glyph < countTopSideBearings ? glyph : countTopSideBearings - 1];
527            float topSideBearing = topSideBearingFUnit * sizePerUnit;
528            FloatRect bounds = font->boundsForGlyph(glyph);
529            outXYArray[1] = bounds.y() - topSideBearing;
530            continue;
531        }
532
533        // No vertical info in the font file; use ascent as vertical origin.
534        outXYArray[1] = -ascent;
535    }
536}
537
538void OpenTypeVerticalData::substituteWithVerticalGlyphs(const SimpleFontData* font, GlyphPage* glyphPage, unsigned offset, unsigned length) const
539{
540    const HashMap<Glyph, Glyph>& map = m_verticalGlyphMap;
541    if (map.isEmpty())
542        return;
543
544    for (unsigned index = offset, end = offset + length; index < end; ++index) {
545        Glyph glyph = glyphPage->glyphAt(index);
546        if (glyph) {
547            ASSERT(glyphPage->glyphDataForIndex(index).fontData == font);
548            Glyph to = map.get(glyph);
549            if (to)
550                glyphPage->setGlyphDataForIndex(index, to, font);
551        }
552    }
553}
554
555} // namespace WebCore
556#endif // ENABLE(OPENTYPE_VERTICAL)
557