Vertical flow support for OpenType fonts with the least platform dependencies
[WebKit-https.git] / Source / WebCore / platform / graphics / opentype / OpenTypeVerticalData.cpp
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 #include "OpenTypeVerticalData.h"
27
28 #include "FloatRect.h"
29 #include "GlyphPage.h"
30 #include "OpenTypeTypes.h"
31 #include "SharedBuffer.h"
32 #include "SimpleFontData.h"
33 #include <wtf/RefPtr.h>
34
35 using namespace std;
36
37 namespace WebCore {
38 namespace OpenType {
39
40 enum {
41     HheaTag = OT_MAKE_TAG('h', 'h', 'e', 'a'),
42     HmtxTag = OT_MAKE_TAG('h', 'm', 't', 'x'),
43     VheaTag = OT_MAKE_TAG('v', 'h', 'e', 'a'),
44     VmtxTag = OT_MAKE_TAG('v', 'm', 't', 'x'),
45     VORGTag = OT_MAKE_TAG('V', 'O', 'R', 'G'),
46 };
47
48 #pragma pack(1)
49
50 struct HheaTable {
51     OpenType::Fixed version;
52     OpenType::Int16 ascender;
53     OpenType::Int16 descender;
54     OpenType::Int16 lineGap;
55     OpenType::Int16 advanceWidthMax;
56     OpenType::Int16 minLeftSideBearing;
57     OpenType::Int16 minRightSideBearing;
58     OpenType::Int16 xMaxExtent;
59     OpenType::Int16 caretSlopeRise;
60     OpenType::Int16 caretSlopeRun;
61     OpenType::Int16 caretOffset;
62     OpenType::Int16 reserved[4];
63     OpenType::Int16 metricDataFormat;
64     OpenType::UInt16 numberOfHMetrics;
65 };
66
67 struct VheaTable {
68     OpenType::Fixed version;
69     OpenType::Int16 ascent;
70     OpenType::Int16 descent;
71     OpenType::Int16 lineGap;
72     OpenType::Int16 advanceHeightMax;
73     OpenType::Int16 minTopSideBearing;
74     OpenType::Int16 minBottomSideBearing;
75     OpenType::Int16 yMaxExtent;
76     OpenType::Int16 caretSlopeRise;
77     OpenType::Int16 caretSlopeRun;
78     OpenType::Int16 caretOffset;
79     OpenType::Int16 reserved[4];
80     OpenType::Int16 metricDataFormat;
81     OpenType::UInt16 numOfLongVerMetrics;
82 };
83
84 struct HmtxTable {
85     struct Entry {
86         OpenType::UInt16 advanceWidth;
87         OpenType::Int16 lsb;
88     } entries[1];
89 };
90
91 struct VmtxTable {
92     struct Entry {
93         OpenType::UInt16 advanceHeight;
94         OpenType::Int16 topSideBearing;
95     } entries[1];
96 };
97
98 struct VORGTable {
99     OpenType::UInt16 majorVersion;
100     OpenType::UInt16 minorVersion;
101     OpenType::Int16 defaultVertOriginY;
102     OpenType::UInt16 numVertOriginYMetrics;
103     struct VertOriginYMetrics {
104         OpenType::UInt16 glyphIndex;
105         OpenType::Int16 vertOriginY;
106     } vertOriginYMetrics[1];
107
108     size_t requiredSize() const { return sizeof(*this) + sizeof(VertOriginYMetrics) * (numVertOriginYMetrics - 1); }
109 };
110
111 #pragma pack()
112
113 } // namespace OpenType
114
115 template <typename T> const T* validatedPtr(const RefPtr<SharedBuffer>& buffer, size_t count = 1)
116 {
117     if (!buffer || buffer->size() < sizeof(T) * count)
118         return 0;
119     return reinterpret_cast<const T*>(buffer->data());
120 }
121
122 OpenTypeVerticalData::OpenTypeVerticalData(const FontPlatformData& platformData)
123     : m_defaultVertOriginY(0)
124 {
125     // Load hhea and hmtx to get x-component of vertical origins.
126     // If these tables are missing, it's not an OpenType font.
127     RefPtr<SharedBuffer> buffer = platformData.openTypeTable(OpenType::HheaTag);
128     const OpenType::HheaTable* hhea = validatedPtr<OpenType::HheaTable>(buffer);
129     if (!hhea)
130         return;
131     uint16_t countHmtxEntries = hhea->numberOfHMetrics;
132     if (!countHmtxEntries) {
133         LOG_ERROR("Invalid numberOfHMetrics");
134         return;
135     }
136
137     buffer = platformData.openTypeTable(OpenType::HmtxTag);
138     const OpenType::HmtxTable* hmtx = validatedPtr<OpenType::HmtxTable>(buffer, countHmtxEntries);
139     if (!hmtx) {
140         LOG_ERROR("hhea exists but hmtx does not (or broken)");
141         return;
142     }
143     m_advanceWidths.resize(countHmtxEntries);
144     for (uint16_t i = 0; i < countHmtxEntries; ++i)
145         m_advanceWidths[i] = hmtx->entries[i].advanceWidth;
146
147     // Load vhea first. This table is required for fonts that support vertical flow.
148     buffer = platformData.openTypeTable(OpenType::VheaTag);
149     const OpenType::VheaTable* vhea = validatedPtr<OpenType::VheaTable>(buffer);
150     if (!vhea)
151         return;
152     uint16_t countVmtxEntries = vhea->numOfLongVerMetrics;
153     if (!countVmtxEntries) {
154         LOG_ERROR("Invalid numOfLongVerMetrics");
155         return;
156     }
157
158     // Load VORG. This table is optional.
159     buffer = platformData.openTypeTable(OpenType::VORGTag);
160     const OpenType::VORGTable* vorg = validatedPtr<OpenType::VORGTable>(buffer);
161     if (vorg && buffer->size() >= vorg->requiredSize()) {
162         m_defaultVertOriginY = vorg->defaultVertOriginY;
163         uint16_t countVertOriginYMetrics = vorg->numVertOriginYMetrics;
164         if (!countVertOriginYMetrics) {
165             // Add one entry so that hasVORG() becomes true
166             m_vertOriginY.set(0, m_defaultVertOriginY);
167         } else {
168             for (uint16_t i = 0; i < countVertOriginYMetrics; ++i) {
169                 const OpenType::VORGTable::VertOriginYMetrics& metrics = vorg->vertOriginYMetrics[i];
170                 m_vertOriginY.set(metrics.glyphIndex, metrics.vertOriginY);
171             }
172         }
173     }
174
175     // Load vmtx then. This table is required for fonts that support vertical flow.
176     buffer = platformData.openTypeTable(OpenType::VmtxTag);
177     const OpenType::VmtxTable* vmtx = validatedPtr<OpenType::VmtxTable>(buffer, countVmtxEntries);
178     if (!vmtx) {
179         LOG_ERROR("vhea exists but vmtx does not (or broken)");
180         return;
181     }
182     m_advanceHeights.resize(countVmtxEntries);
183     for (uint16_t i = 0; i < countVmtxEntries; ++i)
184         m_advanceHeights[i] = vmtx->entries[i].advanceHeight;
185
186     // VORG is preferred way to calculate vertical origin than vmtx,
187     // so load topSideBearing from vmtx only if VORG is missing.
188     if (hasVORG())
189         return;
190
191     size_t sizeExtra = buffer->size() - sizeof(OpenType::VmtxTable::Entry) * countVmtxEntries;
192     if (sizeExtra % sizeof(OpenType::Int16)) {
193         LOG_ERROR("vmtx has incorrect tsb count");
194         return;
195     }
196     size_t countTopSideBearings = countVmtxEntries + sizeExtra / sizeof(OpenType::Int16);
197     m_topSideBearings.resize(countTopSideBearings);
198     size_t i;
199     for (i = 0; i < countVmtxEntries; ++i)
200         m_topSideBearings[i] = vmtx->entries[i].topSideBearing;
201     if (i < countTopSideBearings) {
202         const OpenType::Int16* pTopSideBearingsExtra = reinterpret_cast<const OpenType::Int16*>(&vmtx->entries[countVmtxEntries]);
203         for (; i < countTopSideBearings; ++i, ++pTopSideBearingsExtra)
204             m_topSideBearings[i] = *pTopSideBearingsExtra;
205     }
206 }
207
208 float OpenTypeVerticalData::advanceHeight(const SimpleFontData* font, Glyph glyph) const
209 {
210     size_t countHeights = m_advanceHeights.size();
211     if (countHeights) {
212         uint16_t advanceFUnit = m_advanceHeights[glyph < countHeights ? glyph : countHeights - 1];
213         float advance = advanceFUnit * font->sizePerUnit();
214         return advance;
215     }
216
217     // No vertical info in the font file; use height as advance.
218     return font->fontMetrics().height();
219 }
220
221 void OpenTypeVerticalData::getVerticalTranslationsForGlyphs(const SimpleFontData* font, const Glyph* glyphs, size_t count, float* outXYArray) const
222 {
223     size_t countWidths = m_advanceWidths.size();
224     ASSERT(countWidths > 0);
225     const FontMetrics& metrics = font->fontMetrics();
226     float sizePerUnit = font->sizePerUnit();
227     float ascent = metrics.ascent();
228     bool useVORG = hasVORG();
229     size_t countTopSideBearings = m_topSideBearings.size();
230     float defaultVertOriginY = std::numeric_limits<float>::quiet_NaN();
231     for (float* end = &(outXYArray[count * 2]); outXYArray != end; ++glyphs, outXYArray += 2) {
232         Glyph glyph = *glyphs;
233         uint16_t widthFUnit = m_advanceWidths[glyph < countWidths ? glyph : countWidths - 1];
234         float width = widthFUnit * sizePerUnit;
235         outXYArray[0] = -width / 2;
236
237         // For Y, try VORG first.
238         if (useVORG) {
239             int16_t vertOriginYFUnit = m_vertOriginY.get(glyph);
240             if (vertOriginYFUnit) {
241                 outXYArray[1] = -vertOriginYFUnit * sizePerUnit;
242                 continue;
243             }
244             if (isnan(defaultVertOriginY))
245                 defaultVertOriginY = -m_defaultVertOriginY * sizePerUnit;
246             outXYArray[1] = defaultVertOriginY;
247             continue;
248         }
249
250         // If no VORG, try vmtx next.
251         if (countTopSideBearings) {
252             int16_t topSideBearingFUnit = m_topSideBearings[glyph < countTopSideBearings ? glyph : countTopSideBearings - 1];
253             float topSideBearing = topSideBearingFUnit * sizePerUnit;
254             FloatRect bounds = font->boundsForGlyph(glyph);
255             outXYArray[1] = bounds.y() - topSideBearing;
256             continue;
257         }
258
259         // No vertical info in the font file; use ascent as vertical origin.
260         outXYArray[1] = -ascent;
261     }
262 }
263
264 } // namespace WebCore