1 /****************************************************************************\
2 Part of the XeTeX typesetting system
3 Copyright (c) 1994-2008 by SIL International
4 Copyright (c) 2009 by Jonathan Kew
5 Copyright (c) 2012-2015 by Khaled Hosny
6
7 SIL Author(s): Jonathan Kew
8
9 Permission is hereby granted, free of charge, to any person obtaining
10 a copy of this software and associated documentation files (the
11 "Software"), to deal in the Software without restriction, including
12 without limitation the rights to use, copy, modify, merge, publish,
13 distribute, sublicense, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to
15 the following conditions:
16
17 The above copyright notice and this permission notice shall be
18 included in all copies or substantial portions of the Software.
19
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE
24 FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
25 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
28 Except as contained in this notice, the name of the copyright holders
29 shall not be used in advertising or otherwise to promote the sale,
30 use or other dealings in this Software without prior written
31 authorization from the copyright holders.
32 \****************************************************************************/
33
34 #include <w2c/config.h>
35
36 #include <assert.h>
37
38 #include "XeTeXOTMath.h"
39
40 #include "XeTeX_web.h"
41 #include "XeTeXLayoutInterface.h"
42 #include "XeTeXFontInst.h"
43 #include "XeTeXswap.h"
44
getCoverage(const Coverage * coverage,GlyphID g)45 static int32_t getCoverage(const Coverage* coverage, GlyphID g)
46 {
47 if (SWAP(coverage->format) == 1) {
48 const CoverageFormat1 *table = (const CoverageFormat1 *) coverage;
49 for (int i = 0; i < SWAP(table->glyphCount); i++) {
50 if (SWAP(table->glyphArray[i]) == g)
51 return i;
52 }
53 } else if (SWAP(coverage->format) == 2) {
54 const CoverageFormat2 *table = (const CoverageFormat2 *) coverage;
55 for (int i = 0; i < SWAP(table->rangeCount); i++) {
56 if (SWAP(table->rangeArray[i].start) <= g && SWAP(table->rangeArray[i].end) >= g)
57 return SWAP(table->rangeArray[i].startCoverageIndex) + (g - SWAP(table->rangeArray[i].start));
58 }
59 }
60
61 return -1;
62 }
63
getMathConstant(XeTeXFontInst * fontInst,mathConstantIndex whichConstant)64 static int16_t getMathConstant(XeTeXFontInst* fontInst, mathConstantIndex whichConstant)
65 {
66 const char* table = fontInst->getMathTable();
67 if (table == NULL)
68 return 0;
69
70 const uint16_t* constants = (const uint16_t*)(table + SWAP(((const MathTableHeader*)table)->mathConstants));
71
72 if (whichConstant < firstMathValueRecord) {
73 /* it's a simple 16-bit value */
74 return SWAP(constants[whichConstant]);
75 }
76 else if (whichConstant <= lastMathValueRecord) {
77 const MathValueRecord* valueRecords = (const MathValueRecord*)
78 ((char*)constants + firstMathValueRecord * sizeof(uint16_t) - firstMathValueRecord * sizeof(MathValueRecord));
79 return SWAP(valueRecords[whichConstant].value);
80 }
81 else if (whichConstant <= lastMathConstant) {
82 return SWAP(constants[whichConstant + (lastMathValueRecord - firstMathValueRecord + 1)]);
83 }
84 else
85 return 0; /* or abort, with "internal error" or something */
86 }
87
88 int
get_ot_math_constant(int f,int n)89 get_ot_math_constant(int f, int n)
90 {
91 int rval = 0;
92
93 if (fontarea[f] == OTGR_FONT_FLAG) {
94 XeTeXFontInst* font = (XeTeXFontInst*)getFont((XeTeXLayoutEngine)fontlayoutengine[f]);
95 rval = getMathConstant(font, (mathConstantIndex)n);
96 /* scale according to font size, except the ones that are percentages */
97 if (n > scriptScriptPercentScaleDown && n < radicalDegreeBottomRaisePercent)
98 rval = D2Fix(font->unitsToPoints(rval));
99 }
100 return rval;
101 }
102
103 /* fontdimen IDs for math symbols font (family 2) */
104 #define math_x_height 5
105 #define math_quad 6
106 #define num1 8 /* numerator shift-up in display styles */
107 #define num2 9 /* numerator shift-up in non-display, non-\.{\\atop} */
108 #define num3 10 /* numerator shift-up in non-display \.{\\atop} */
109 #define denom1 11 /* denominator shift-down in display styles */
110 #define denom2 12 /* denominator shift-down in non-display styles */
111 #define sup1 13 /* superscript shift-up in uncramped display style */
112 #define sup2 14 /* superscript shift-up in uncramped non-display */
113 #define sup3 15 /* superscript shift-up in cramped styles */
114 #define sub1 16 /* subscript shift-down if superscript is absent */
115 #define sub2 17 /* subscript shift-down if superscript is present */
116 #define sup_drop 18 /* superscript baseline below top of large box */
117 #define sub_drop 19 /* subscript baseline below bottom of large box */
118 #define delim1 20 /* size of \.{\\atopwithdelims} delimiters */
119 #define delim2 21 /* size of \.{\\atopwithdelims} delimiters in non-displays */
120 #define axis_height 22 /* height of fraction lines above the baseline */
121
122 const mathConstantIndex TeX_sym_to_OT_map[] = {
123 unknown,
124 unknown,
125 unknown,
126 unknown,
127 unknown,
128 accentBaseHeight, // x-height
129 unknown, // quad
130 unknown,
131 fractionNumeratorDisplayStyleShiftUp,
132 fractionNumeratorShiftUp,
133 stackTopShiftUp,
134 fractionDenominatorDisplayStyleShiftDown,
135 fractionDenominatorShiftDown,
136 superscriptShiftUp, // ??
137 superscriptShiftUp, // ??
138 superscriptShiftUpCramped,
139 subscriptShiftDown, // ??
140 subscriptShiftDown, // ??
141 superscriptBaselineDropMax, // ??
142 subscriptBaselineDropMin, // ??
143 delimitedSubFormulaMinHeight,
144 unknown, // using quad instead for now
145 axisHeight
146 };
147
148 int
get_native_mathsy_param(int f,int n)149 get_native_mathsy_param(int f, int n)
150 {
151 int rval = 0;
152
153 if (n == math_quad || n == delim2)
154 rval = fontsize[f];
155 else {
156 if (n < sizeof(TeX_sym_to_OT_map) / sizeof(mathConstantIndex)) {
157 mathConstantIndex ot_index = TeX_sym_to_OT_map[n];
158 if (ot_index != unknown)
159 rval = get_ot_math_constant(f, (int)ot_index);
160 }
161 }
162 // fprintf(stderr, " math_sy(%d, %d) returns %.3f\n", f, n, Fix2D(rval));
163
164 return rval;
165 }
166
167 /* fontdimen IDs for math extension font (family 3) */
168 #define default_rule_thickness 8 /* thickness of \.{\\over} bars */
169 #define big_op_spacing1 9 /* minimum clearance above a displayed op */
170 #define big_op_spacing2 10 /* minimum clearance below a displayed op */
171 #define big_op_spacing3 11 /* minimum baselineskip above displayed op */
172 #define big_op_spacing4 12 /* minimum baselineskip below displayed op */
173 #define big_op_spacing5 13 /* padding above and below displayed limits */
174
175 const mathConstantIndex TeX_ext_to_OT_map[] = {
176 unknown,
177 unknown,
178 unknown,
179 unknown,
180 unknown,
181 accentBaseHeight, // x-height
182 unknown, // quad
183 unknown,
184 fractionRuleThickness, // default_rule_thickness
185 upperLimitGapMin, // big_op_spacing1
186 lowerLimitGapMin, // big_op_spacing2
187 upperLimitBaselineRiseMin, // big_op_spacing3
188 lowerLimitBaselineDropMin, // big_op_spacing4
189 stackGapMin // big_op_spacing5
190 };
191
192 int
get_native_mathex_param(int f,int n)193 get_native_mathex_param(int f, int n)
194 {
195 int rval = 0;
196
197 if (n == math_quad)
198 rval = fontsize[f];
199 else {
200 if (n < sizeof(TeX_ext_to_OT_map) / sizeof(mathConstantIndex)) {
201 mathConstantIndex ot_index = TeX_ext_to_OT_map[n];
202 if (ot_index != unknown)
203 rval = get_ot_math_constant(f, (int)ot_index);
204 }
205 }
206 // fprintf(stderr, " math_ex(%d, %d) returns %.3f\n", f, n, Fix2D(rval));
207
208 return rval;
209 }
210
211 int
get_ot_math_variant(int f,int g,int v,integer * adv,int horiz)212 get_ot_math_variant(int f, int g, int v, integer* adv, int horiz)
213 {
214 int rval = g;
215 *adv = -1;
216
217 if (fontarea[f] == OTGR_FONT_FLAG) {
218 XeTeXFontInst* font = (XeTeXFontInst*)getFont((XeTeXLayoutEngine)fontlayoutengine[f]);
219
220 const char* table = font->getMathTable();
221 if (table == NULL)
222 return rval;
223
224 uint16_t offset = SWAP(((const MathTableHeader*)table)->mathVariants);
225 if (offset == 0)
226 return rval;
227 const MathVariants* variants = (const MathVariants*)(table + offset);
228
229 offset = horiz ? SWAP(variants->horizGlyphCoverage) : SWAP(variants->vertGlyphCoverage);
230 if (offset == 0)
231 return rval;
232 const Coverage* coverage = (const Coverage*)(((const char*)variants) + offset);
233
234 int32_t index = getCoverage(coverage, g);
235 if (index >= 0) {
236 if (horiz)
237 index += SWAP(variants->vertGlyphCount);
238 const MathGlyphConstruction* construction = (const MathGlyphConstruction*)(((const char*)variants)
239 + SWAP(variants->vertGlyphConstruction[index]));
240 if (v < SWAP(construction->variantCount)) {
241 rval = SWAP(construction->mathGlyphVariantRecord[v].variantGlyph);
242 *adv = D2Fix(font->unitsToPoints(SWAP(construction->mathGlyphVariantRecord[v].advanceMeasurement)));
243 }
244 }
245 }
246
247 return rval;
248 }
249
250 void*
get_ot_assembly_ptr(int f,int g,int horiz)251 get_ot_assembly_ptr(int f, int g, int horiz)
252 {
253 void* rval = NULL;
254
255 if (fontarea[f] == OTGR_FONT_FLAG) {
256 XeTeXFontInst* font = (XeTeXFontInst*)getFont((XeTeXLayoutEngine)fontlayoutengine[f]);
257
258 const char* table = font->getMathTable();
259 if (table == NULL)
260 return rval;
261
262 uint16_t offset = SWAP(((const MathTableHeader*)table)->mathVariants);
263 if (offset == 0)
264 return rval;
265 const MathVariants* variants = (const MathVariants*)(table + offset);
266
267 offset = horiz ? SWAP(variants->horizGlyphCoverage) : SWAP(variants->vertGlyphCoverage);
268 if (offset == 0)
269 return rval;
270 const Coverage* coverage = (const Coverage*)(((const char*)variants) + offset);
271
272 int32_t index = getCoverage(coverage, g);
273 if (index >= 0) {
274 if (horiz)
275 index += SWAP(variants->vertGlyphCount);
276 const MathGlyphConstruction* construction = (const MathGlyphConstruction*)(((const char*)variants)
277 + SWAP(variants->vertGlyphConstruction[index]));
278 offset = SWAP(construction->glyphAssembly);
279 if (offset != 0)
280 rval = (void*)(((const char*)construction) + offset);
281 }
282 }
283
284 return rval;
285 }
286
287 int
get_ot_math_ital_corr(int f,int g)288 get_ot_math_ital_corr(int f, int g)
289 {
290 int rval = 0;
291
292 if (fontarea[f] == OTGR_FONT_FLAG) {
293 XeTeXFontInst* font = (XeTeXFontInst*)getFont((XeTeXLayoutEngine)fontlayoutengine[f]);
294
295 const char* table = font->getMathTable();
296 if (table == NULL)
297 return rval;
298
299 uint16_t offset = SWAP(((const MathTableHeader*)table)->mathGlyphInfo);
300 if (offset == 0)
301 return rval;
302 const MathGlyphInfo* glyphInfo = (const MathGlyphInfo*)(table + offset);
303
304 offset = SWAP(glyphInfo->mathItalicsCorrectionInfo);
305 if (offset == 0)
306 return rval;
307 const MathItalicsCorrectionInfo* italCorrInfo = (const MathItalicsCorrectionInfo*)(((const char*)glyphInfo) + offset);
308
309 offset = SWAP(italCorrInfo->coverage);
310 if (offset == 0)
311 return rval;
312 const Coverage* coverage = (const Coverage*)(((const char*)italCorrInfo) + offset);
313
314 int32_t index = getCoverage(coverage, g);
315 if (index >= 0 && index < SWAP(italCorrInfo->italicsCorrectionCount))
316 rval = D2Fix(font->unitsToPoints(SWAP(italCorrInfo->italicsCorrection[index].value)));
317 }
318
319 return rval;
320 }
321
322 int
get_ot_math_accent_pos(int f,int g)323 get_ot_math_accent_pos(int f, int g)
324 {
325 int rval = 0x7fffffffUL;
326
327 if (fontarea[f] == OTGR_FONT_FLAG) {
328 XeTeXFontInst* font = (XeTeXFontInst*)getFont((XeTeXLayoutEngine)fontlayoutengine[f]);
329
330 const char* table = font->getMathTable();
331 if (table == NULL)
332 return rval;
333
334 uint16_t offset = SWAP(((const MathTableHeader*)table)->mathGlyphInfo);
335 if (offset == 0)
336 return rval;
337 const MathGlyphInfo* glyphInfo = (const MathGlyphInfo*)(table + offset);
338
339 offset = SWAP(glyphInfo->mathTopAccentAttachment);
340 if (offset == 0)
341 return rval;
342 const MathTopAccentAttachment* accentAttachment = (const MathTopAccentAttachment*)(((const char*)glyphInfo) + offset);
343
344 offset = SWAP(accentAttachment->coverage);
345 if (offset == 0)
346 return rval;
347 const Coverage* coverage = (const Coverage*)(((const char*)accentAttachment) + offset);
348
349 int32_t index = getCoverage(coverage, g);
350 if (index >= 0 && index < SWAP(accentAttachment->topAccentAttachmentCount)) {
351 rval = (int16_t)SWAP(accentAttachment->topAccentAttachment[index].value);
352 rval = D2Fix(font->unitsToPoints(rval));
353 }
354 }
355
356 return rval;
357 }
358
359 int
ot_min_connector_overlap(int f)360 ot_min_connector_overlap(int f)
361 {
362 int rval = 0;
363
364 if (fontarea[f] == OTGR_FONT_FLAG) {
365 XeTeXFontInst* font = (XeTeXFontInst*)getFont((XeTeXLayoutEngine)fontlayoutengine[f]);
366
367 const char* table = font->getMathTable();
368 if (table == NULL)
369 return rval;
370
371 uint16_t offset = SWAP(((const MathTableHeader*)table)->mathVariants);
372 if (offset == 0)
373 return rval;
374 const MathVariants* variants = (const MathVariants*)(table + offset);
375
376 rval = D2Fix(font->unitsToPoints(SWAP(variants->minConnectorOverlap)));
377 }
378
379 return rval;
380 }
381
382 typedef enum {
383 topRight,
384 topLeft,
385 bottomRight,
386 bottomLeft,
387 } MathKernSide;
388
389 static int
getMathKernAt(int f,int g,MathKernSide side,int height)390 getMathKernAt(int f, int g, MathKernSide side, int height)
391 {
392 int rval = 0;
393 if (fontarea[f] == OTGR_FONT_FLAG) {
394 XeTeXFontInst* font = (XeTeXFontInst*)getFont((XeTeXLayoutEngine)fontlayoutengine[f]);
395
396 const char* table = font->getMathTable();
397 if (table == NULL)
398 return rval;
399
400 uint16_t offset = SWAP(((const MathTableHeader*)table)->mathGlyphInfo);
401 if (offset == 0)
402 return rval;
403
404 const MathGlyphInfo* glyphInfo = (const MathGlyphInfo*)(table + offset);
405
406 offset = SWAP(glyphInfo->mathKernInfo);
407 if (offset == 0)
408 return rval;
409
410 const MathKernInfo* mathKernInfo = (const MathKernInfo*)(((const char*)glyphInfo) + offset);
411
412 offset = SWAP(mathKernInfo->coverage);
413 if (offset == 0)
414 return rval;
415
416 const Coverage* coverage = (const Coverage*)(((const char*)mathKernInfo) + offset);
417
418 int32_t index = getCoverage(coverage, g);
419 if (index >= 0 && index < SWAP(mathKernInfo->kernInfoCount)) {
420 if (side == topRight)
421 offset = SWAP(mathKernInfo->kernInfo[index].topRight);
422 else if (side == bottomRight)
423 offset = SWAP(mathKernInfo->kernInfo[index].bottomRight);
424 else if (side == topLeft)
425 offset = SWAP(mathKernInfo->kernInfo[index].topLeft);
426 else if (side == bottomLeft)
427 offset = SWAP(mathKernInfo->kernInfo[index].bottomLeft);
428 else
429 assert(0); // we should not reach here
430
431 if (offset == 0)
432 return rval;
433
434 const MathKernTable* kernTable = (const MathKernTable*)(((const char*)mathKernInfo) + offset);
435
436 uint16_t count = SWAP(kernTable->heightCount);
437
438 // XXX: the following makes no sense WRT my understanding of the
439 // spec! it is just how things worked for me.
440 if (count == 0)
441 rval = SWAP(kernTable->kern[-1].value);
442 else if (height < SWAP(kernTable->height[0].value))
443 rval = SWAP(kernTable->kern[1].value);
444 else if (height > SWAP(kernTable->height[count].value))
445 rval = SWAP(kernTable->kern[count+1].value);
446 else {
447 for (int i = 0; i < count; i++) {
448 if (height > SWAP(kernTable->height[i].value)) {
449 rval = SWAP(kernTable->kern[i+1].value);
450 break;
451 }
452 }
453 }
454
455 //fprintf(stderr, " kern: %f %f\n", font->unitsToPoints(height), font->unitsToPoints(rval));
456 }
457 }
458
459 return rval;
460 }
461
462 static float
glyph_height(int f,int g)463 glyph_height(int f, int g)
464 {
465 float rval = 0.0;
466
467 if (fontarea[f] == OTGR_FONT_FLAG) {
468 XeTeXLayoutEngine engine = (XeTeXLayoutEngine)fontlayoutengine[f];
469 getGlyphHeightDepth(engine, g, &rval, NULL);
470 }
471
472 return rval;
473 }
474
475 static float
glyph_depth(int f,int g)476 glyph_depth(int f, int g)
477 {
478 float rval = 0.0;
479
480 if (fontarea[f] == OTGR_FONT_FLAG) {
481 XeTeXLayoutEngine engine = (XeTeXLayoutEngine)fontlayoutengine[f];
482 getGlyphHeightDepth(engine, g, NULL, &rval);
483 }
484
485 return rval;
486 }
487
488 // keep in sync with xetex.web
489 #define sup_cmd 0
490 #define sub_cmd 1
491
492 int
get_ot_math_kern(int f,int g,int sf,int sg,int cmd,int shift)493 get_ot_math_kern(int f, int g, int sf, int sg, int cmd, int shift)
494 {
495 int rval = 0;
496
497 if (fontarea[f] == OTGR_FONT_FLAG) {
498 XeTeXFontInst* font = (XeTeXFontInst*)getFont((XeTeXLayoutEngine)fontlayoutengine[f]);
499 int kern = 0, skern = 0;
500 float corr_height_top = 0.0, corr_height_bot = 0.0;
501
502 shift = Fix2D(shift);
503
504 if (cmd == sup_cmd) { // superscript
505 corr_height_top = font->pointsToUnits(glyph_height(f, g));
506 corr_height_bot = -font->pointsToUnits(glyph_depth(sf, sg) + shift);
507
508 kern = getMathKernAt(f, g, topRight, corr_height_top);
509 skern = getMathKernAt(sf, sg, bottomLeft, corr_height_top);
510 rval = kern + skern;
511
512 kern = getMathKernAt(f, g, topRight, corr_height_bot);
513 skern = getMathKernAt(sf, sg, bottomLeft, corr_height_bot);
514 if ((kern + skern) < rval)
515 rval = kern + skern;
516
517 } else if (cmd == sub_cmd) { // subscript
518 corr_height_top = font->pointsToUnits(glyph_height(sf, sg) - shift);
519 corr_height_bot = -font->pointsToUnits(glyph_depth(f, g));
520
521 kern = getMathKernAt(f, g, bottomRight, corr_height_top);
522 skern = getMathKernAt(sf, sg, topLeft, corr_height_top);
523 rval = kern + skern;
524
525 kern = getMathKernAt(f, g, bottomRight, corr_height_bot);
526 skern = getMathKernAt(sf, sg, topLeft, corr_height_bot);
527 if ((kern + skern) < rval)
528 rval = kern + skern;
529
530 } else {
531 assert(0); // we should not reach here
532 }
533
534 rval = D2Fix(font->unitsToPoints(rval));
535 }
536
537 return rval;
538 }
539
540 int
ot_part_count(const GlyphAssembly * a)541 ot_part_count(const GlyphAssembly* a)
542 {
543 return SWAP(a->partCount);
544 }
545
546 int
ot_part_glyph(const GlyphAssembly * a,int i)547 ot_part_glyph(const GlyphAssembly* a, int i)
548 {
549 return SWAP(a->partRecords[i].glyph);
550 }
551
552 int
ot_part_is_extender(const GlyphAssembly * a,int i)553 ot_part_is_extender(const GlyphAssembly* a, int i)
554 {
555 return (SWAP(a->partRecords[i].partFlags) & fExtender) != 0;
556 }
557
558 int
ot_part_start_connector(int f,const GlyphAssembly * a,int i)559 ot_part_start_connector(int f, const GlyphAssembly* a, int i)
560 {
561 int rval = 0;
562
563 if (fontarea[f] == OTGR_FONT_FLAG) {
564 XeTeXFontInst* font = (XeTeXFontInst*)getFont((XeTeXLayoutEngine)fontlayoutengine[f]);
565 rval = D2Fix(font->unitsToPoints(SWAP(a->partRecords[i].startConnectorLength)));
566 }
567
568 return rval;
569 }
570
571 int
ot_part_end_connector(int f,const GlyphAssembly * a,int i)572 ot_part_end_connector(int f, const GlyphAssembly* a, int i)
573 {
574 int rval = 0;
575
576 if (fontarea[f] == OTGR_FONT_FLAG) {
577 XeTeXFontInst* font = (XeTeXFontInst*)getFont((XeTeXLayoutEngine)fontlayoutengine[f]);
578 rval = D2Fix(font->unitsToPoints(SWAP(a->partRecords[i].endConnectorLength)));
579 }
580
581 return rval;
582 }
583
584 int
ot_part_full_advance(int f,const GlyphAssembly * a,int i)585 ot_part_full_advance(int f, const GlyphAssembly* a, int i)
586 {
587 int rval = 0;
588
589 if (fontarea[f] == OTGR_FONT_FLAG) {
590 XeTeXFontInst* font = (XeTeXFontInst*)getFont((XeTeXLayoutEngine)fontlayoutengine[f]);
591 rval = D2Fix(font->unitsToPoints(SWAP(a->partRecords[i].fullAdvance)));
592 }
593
594 return rval;
595 }
596