Use "= default" to denote default constructor or destructor
[WebKit-https.git] / Source / WebCore / platform / graphics / opentype / OpenTypeMathData.cpp
1 /*
2  * Copyright (C) 2014 Frederic Wang (fred.wang@free.fr). All rights reserved.
3  * Copyright (C) 2016 Igalia S.L. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28 #include "OpenTypeMathData.h"
29
30 #include "Font.h"
31 #include "FontPlatformData.h"
32 #if ENABLE(OPENTYPE_MATH)
33 #include "OpenTypeTypes.h"
34 #endif
35 #include "SharedBuffer.h"
36
37
38 namespace WebCore {
39 using namespace std;
40
41 #if ENABLE(OPENTYPE_MATH)
42 namespace OpenType {
43
44 #if PLATFORM(COCOA)
45 const FourCharCode MATHTag = 'MATH';
46 #else
47 const uint32_t MATHTag = OT_MAKE_TAG('M', 'A', 'T', 'H');
48 #endif
49
50 #pragma pack(1)
51
52 struct MathValueRecord {
53     OpenType::Int16 value;
54     OpenType::Offset deviceTableOffset;
55 };
56
57 struct MathConstants {
58     OpenType::Int16 intConstants[OpenTypeMathData::ScriptScriptPercentScaleDown - OpenTypeMathData::ScriptPercentScaleDown + 1];
59     OpenType::UInt16 uIntConstants[OpenTypeMathData::DisplayOperatorMinHeight - OpenTypeMathData::DelimitedSubFormulaMinHeight + 1];
60     OpenType::MathValueRecord mathValuesConstants[OpenTypeMathData::RadicalKernAfterDegree - OpenTypeMathData::MathLeading + 1];
61     OpenType::UInt16 radicalDegreeBottomRaisePercent;
62 };
63
64 struct MathItalicsCorrectionInfo : TableWithCoverage {
65     OpenType::Offset coverageOffset;
66     OpenType::UInt16 italicsCorrectionCount;
67     OpenType::MathValueRecord italicsCorrection[1]; // There are italicsCorrectionCount italic correction values.
68
69     int16_t getItalicCorrection(const SharedBuffer& buffer, Glyph glyph) const
70     {
71         uint16_t count = uint16_t(italicsCorrectionCount);
72         if (!isValidEnd(buffer, &italicsCorrection[count]))
73             return 0;
74
75         uint16_t offset = coverageOffset;
76         if (!offset)
77             return 0;
78         const CoverageTable* coverage = validateOffset<CoverageTable>(buffer, offset);
79         if (!coverage)
80             return 0;
81
82         // We determine the index in the italicsCorrection table.
83         uint32_t i;
84         if (!getCoverageIndex(buffer, coverage, glyph, i) || i >= count)
85             return 0;
86
87         return int16_t(italicsCorrection[i].value);
88     }
89 };
90
91 struct MathGlyphInfo : TableWithCoverage {
92     OpenType::Offset mathItalicsCorrectionInfoOffset;
93     OpenType::Offset mathTopAccentAttachmentOffset;
94     OpenType::Offset extendedShapeCoverageOffset;
95     OpenType::Offset mathKernInfoOffset;
96
97     const MathItalicsCorrectionInfo* mathItalicsCorrectionInfo(const SharedBuffer& buffer) const
98     {
99         uint16_t offset = mathItalicsCorrectionInfoOffset;
100         if (offset)
101             return validateOffset<MathItalicsCorrectionInfo>(buffer, offset);
102         return nullptr;
103     }
104 };
105
106 struct GlyphAssembly : TableBase {
107     OpenType::MathValueRecord italicsCorrection;
108     OpenType::UInt16 partCount;
109     struct GlyphPartRecord {
110         OpenType::GlyphID glyph;
111         OpenType::UInt16 startConnectorLength;
112         OpenType::UInt16 endConnectorLength;
113         OpenType::UInt16 fullAdvance;
114         OpenType::UInt16 partFlags;
115     } partRecords[1]; // There are partCount GlyphPartRecord's.
116
117     // PartFlags enumeration currently uses only one bit:
118     // 0x0001 If set, the part can be skipped or repeated.
119     // 0xFFFE Reserved.
120     enum {
121         PartFlagsExtender = 0x01
122     };
123
124     void getAssemblyParts(const SharedBuffer& buffer, Vector<OpenTypeMathData::AssemblyPart>& assemblyParts) const
125     {
126         uint16_t count = partCount;
127         if (!isValidEnd(buffer, &partRecords[count]))
128             return;
129         assemblyParts.resize(count);
130         for (uint16_t i = 0; i < count; i++) {
131             assemblyParts[i].glyph = partRecords[i].glyph;
132             uint16_t flag = partRecords[i].partFlags;
133             assemblyParts[i].isExtender = flag & PartFlagsExtender;
134         }
135     }
136
137 };
138
139 struct MathGlyphConstruction : TableBase {
140     OpenType::Offset glyphAssemblyOffset;
141     OpenType::UInt16 variantCount;
142     struct MathGlyphVariantRecord {
143         OpenType::GlyphID variantGlyph;
144         OpenType::UInt16 advanceMeasurement;
145     } mathGlyphVariantRecords[1]; // There are variantCount MathGlyphVariantRecord's.
146
147     void getSizeVariants(const SharedBuffer& buffer, Vector<Glyph>& variants) const
148     {
149         uint16_t count = variantCount;
150         if (!isValidEnd(buffer, &mathGlyphVariantRecords[count]))
151             return;
152         variants.resize(count);
153         for (uint16_t i = 0; i < count; i++)
154             variants[i] = mathGlyphVariantRecords[i].variantGlyph;
155     }
156
157     void getAssemblyParts(const SharedBuffer& buffer, Vector<OpenTypeMathData::AssemblyPart>& assemblyParts) const
158     {
159         uint16_t offset = glyphAssemblyOffset;
160         const GlyphAssembly* glyphAssembly = validateOffset<GlyphAssembly>(buffer, offset);
161         if (glyphAssembly)
162             glyphAssembly->getAssemblyParts(buffer, assemblyParts);
163     }
164 };
165
166 struct MathVariants : TableWithCoverage {
167     OpenType::UInt16 minConnectorOverlap;
168     OpenType::Offset verticalGlyphCoverageOffset;
169     OpenType::Offset horizontalGlyphCoverageOffset;
170     OpenType::UInt16 verticalGlyphCount;
171     OpenType::UInt16 horizontalGlyphCount;
172     OpenType::Offset mathGlyphConstructionsOffset[1]; // There are verticalGlyphCount vertical glyph contructions and horizontalGlyphCount vertical glyph contructions.
173
174     const MathGlyphConstruction* mathGlyphConstruction(const SharedBuffer& buffer, Glyph glyph, bool isVertical) const
175     {
176         uint32_t count = uint16_t(verticalGlyphCount) + uint16_t(horizontalGlyphCount);
177         if (!isValidEnd(buffer, &mathGlyphConstructionsOffset[count]))
178             return nullptr;
179
180         // We determine the coverage table for the specified glyph.
181         uint16_t coverageOffset = isVertical ? verticalGlyphCoverageOffset : horizontalGlyphCoverageOffset;
182         if (!coverageOffset)
183             return nullptr;
184         const CoverageTable* coverage = validateOffset<CoverageTable>(buffer, coverageOffset);
185         if (!coverage)
186             return nullptr;
187
188         // We determine the index in the mathGlyphConstructionsOffset table.
189         uint32_t i;
190         if (!getCoverageIndex(buffer, coverage, glyph, i))
191             return nullptr;
192         count = isVertical ? verticalGlyphCount : horizontalGlyphCount;
193         if (i >= count)
194             return nullptr;
195         if (!isVertical)
196             i += uint16_t(verticalGlyphCount);
197
198         return validateOffset<MathGlyphConstruction>(buffer, mathGlyphConstructionsOffset[i]);
199     }
200 };
201
202 struct MATHTable : TableBase {
203     OpenType::Fixed version;
204     OpenType::Offset mathConstantsOffset;
205     OpenType::Offset mathGlyphInfoOffset;
206     OpenType::Offset mathVariantsOffset;
207
208     const MathConstants* mathConstants(const SharedBuffer& buffer) const
209     {
210         uint16_t offset = mathConstantsOffset;
211         if (offset)
212             return validateOffset<MathConstants>(buffer, offset);
213         return nullptr;
214     }
215
216     const MathGlyphInfo* mathGlyphInfo(const SharedBuffer& buffer) const
217     {
218         uint16_t offset = mathGlyphInfoOffset;
219         if (offset)
220             return validateOffset<MathGlyphInfo>(buffer, offset);
221         return nullptr;
222     }
223
224     const MathVariants* mathVariants(const SharedBuffer& buffer) const
225     {
226         uint16_t offset = mathVariantsOffset;
227         if (offset)
228             return validateOffset<MathVariants>(buffer, offset);
229         return nullptr;
230     }
231 };
232
233 #pragma pack()
234
235 } // namespace OpenType
236 #endif // ENABLE(OPENTYPE_MATH)
237
238 #if ENABLE(OPENTYPE_MATH)
239 OpenTypeMathData::OpenTypeMathData(const FontPlatformData& font)
240 {
241     m_mathBuffer = font.openTypeTable(OpenType::MATHTag);
242     const OpenType::MATHTable* math = OpenType::validateTable<OpenType::MATHTable>(m_mathBuffer);
243     if (!math) {
244         m_mathBuffer = nullptr;
245         return;
246     }
247
248     const OpenType::MathConstants* mathConstants = math->mathConstants(*m_mathBuffer);
249     if (!mathConstants) {
250         m_mathBuffer = nullptr;
251         return;
252     }
253
254     const OpenType::MathVariants* mathVariants = math->mathVariants(*m_mathBuffer);
255     if (!mathVariants)
256         m_mathBuffer = nullptr;
257 #elif USE(HARFBUZZ)
258 OpenTypeMathData::OpenTypeMathData(const FontPlatformData& font)
259 {
260     HarfBuzzFace* face = font.harfBuzzFace();
261     if (face) {
262         m_mathFont.reset(face->createFont());
263         if (!hb_ot_math_has_data(hb_font_get_face(m_mathFont.get())))
264             m_mathFont.release();
265     }
266 #else
267 OpenTypeMathData::OpenTypeMathData(const FontPlatformData&)
268 {
269 #endif
270 }
271
272 OpenTypeMathData::~OpenTypeMathData() = default;
273
274 #if ENABLE(OPENTYPE_MATH)
275 float OpenTypeMathData::getMathConstant(const Font& font, MathConstant constant) const
276 {
277     int32_t value = 0;
278
279     const OpenType::MATHTable* math = OpenType::validateTable<OpenType::MATHTable>(m_mathBuffer);
280     ASSERT(math);
281     const OpenType::MathConstants* mathConstants = math->mathConstants(*m_mathBuffer);
282     ASSERT(mathConstants);
283
284     if (constant >= 0 && constant <= ScriptScriptPercentScaleDown)
285         value = int16_t(mathConstants->intConstants[constant]);
286     else if (constant >= DelimitedSubFormulaMinHeight && constant <= DisplayOperatorMinHeight)
287         value = uint16_t(mathConstants->uIntConstants[constant - DelimitedSubFormulaMinHeight]);
288     else if (constant >= MathLeading && constant <= RadicalKernAfterDegree)
289         value = int16_t(mathConstants->mathValuesConstants[constant - MathLeading].value);
290     else if (constant == RadicalDegreeBottomRaisePercent)
291         value = uint16_t(mathConstants->radicalDegreeBottomRaisePercent);
292
293     if (constant == ScriptPercentScaleDown || constant == ScriptScriptPercentScaleDown || constant == RadicalDegreeBottomRaisePercent)
294         return value / 100.0;
295
296     return value * font.sizePerUnit();
297 #elif USE(HARFBUZZ)
298 float OpenTypeMathData::getMathConstant(const Font&, MathConstant constant) const
299 {
300     hb_position_t value = hb_ot_math_get_constant(m_mathFont.get(), static_cast<hb_ot_math_constant_t>(constant));
301     if (constant == ScriptPercentScaleDown || constant == ScriptScriptPercentScaleDown || constant == RadicalDegreeBottomRaisePercent)
302         return value / 100.0;
303
304     return value / 65536.0;
305 #else
306 float OpenTypeMathData::getMathConstant(const Font&, MathConstant) const
307 {
308     ASSERT_NOT_REACHED();
309     return 0;
310 #endif
311 }
312
313 #if ENABLE(OPENTYPE_MATH)
314 float OpenTypeMathData::getItalicCorrection(const Font& font, Glyph glyph) const
315 {
316     const OpenType::MATHTable* math = OpenType::validateTable<OpenType::MATHTable>(m_mathBuffer);
317     ASSERT(math);
318     const OpenType::MathGlyphInfo* mathGlyphInfo = math->mathGlyphInfo(*m_mathBuffer);
319     if (!mathGlyphInfo)
320         return 0;
321
322     const OpenType::MathItalicsCorrectionInfo* mathItalicsCorrectionInfo = mathGlyphInfo->mathItalicsCorrectionInfo(*m_mathBuffer);
323     if (!mathItalicsCorrectionInfo)
324         return 0;
325
326     return mathItalicsCorrectionInfo->getItalicCorrection(*m_mathBuffer, glyph) * font.sizePerUnit();
327 #elif USE(HARFBUZZ)
328 float OpenTypeMathData::getItalicCorrection(const Font&, Glyph glyph) const
329 {
330     return hb_ot_math_get_glyph_italics_correction(m_mathFont.get(), glyph) / 65536.0;
331 #else
332 float OpenTypeMathData::getItalicCorrection(const Font&, Glyph) const
333 {
334     ASSERT_NOT_REACHED();
335     return 0;
336 #endif
337 }
338
339 #if ENABLE(OPENTYPE_MATH)
340 void OpenTypeMathData::getMathVariants(Glyph glyph, bool isVertical, Vector<Glyph>& sizeVariants, Vector<AssemblyPart>& assemblyParts) const
341 {
342     sizeVariants.clear();
343     assemblyParts.clear();
344     const OpenType::MATHTable* math = OpenType::validateTable<OpenType::MATHTable>(m_mathBuffer);
345     ASSERT(math);
346     const OpenType::MathVariants* mathVariants = math->mathVariants(*m_mathBuffer);
347     ASSERT(mathVariants);
348
349     const OpenType::MathGlyphConstruction* mathGlyphConstruction = mathVariants->mathGlyphConstruction(*m_mathBuffer, glyph, isVertical);
350     if (!mathGlyphConstruction)
351         return;
352
353     mathGlyphConstruction->getSizeVariants(*m_mathBuffer, sizeVariants);
354     mathGlyphConstruction->getAssemblyParts(*m_mathBuffer, assemblyParts);
355 #elif USE(HARFBUZZ)
356 void OpenTypeMathData::getMathVariants(Glyph glyph, bool isVertical, Vector<Glyph>& sizeVariants, Vector<AssemblyPart>& assemblyParts) const
357 {
358     hb_direction_t direction = isVertical ? HB_DIRECTION_BTT : HB_DIRECTION_LTR;
359
360     sizeVariants.clear();
361     hb_ot_math_glyph_variant_t variants[10];
362     unsigned variantsSize = WTF_ARRAY_LENGTH(variants);
363     unsigned count;
364     unsigned offset = 0;
365     do {
366         count = variantsSize;
367         hb_ot_math_get_glyph_variants(m_mathFont.get(), glyph, direction, offset, &count, variants);
368         offset += count;
369         for (unsigned i = 0; i < count; i++)
370             sizeVariants.append(variants[i].glyph);
371     } while (count == variantsSize);
372
373     assemblyParts.clear();
374     hb_ot_math_glyph_part_t parts[10];
375     unsigned partsSize = WTF_ARRAY_LENGTH(parts);
376     offset = 0;
377     do {
378         count = partsSize;
379         hb_ot_math_get_glyph_assembly(m_mathFont.get(), glyph, direction, offset, &count, parts, nullptr);
380         offset += count;
381         for (unsigned i = 0; i < count; i++) {
382             AssemblyPart assemblyPart;
383             assemblyPart.glyph = parts[i].glyph;
384             assemblyPart.isExtender = parts[i].flags & HB_MATH_GLYPH_PART_FLAG_EXTENDER;
385             assemblyParts.append(assemblyPart);
386         }
387     } while (count == partsSize);
388 #else
389 void OpenTypeMathData::getMathVariants(Glyph, bool, Vector<Glyph>&, Vector<AssemblyPart>&) const
390 {
391     ASSERT_NOT_REACHED();
392 #endif
393 }
394
395 } // namespace WebCore