1 /****************************************************************************\
2 Part of the XeTeX typesetting system
3 Copyright (c) 1994-2008 by SIL International
4 Copyright (c) 2009-2012 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 <unicode/platform.h> // We need this first
37 #include <unicode/ubidi.h>
38 #include <unicode/utext.h>
39
40 #include <graphite2/Font.h>
41 #include <graphite2/Segment.h>
42 #include <hb-graphite2.h>
43 #include <hb-icu.h>
44 #include <hb-ot.h>
45
46 #include "XeTeX_web.h"
47
48 #include "XeTeXLayoutInterface.h"
49 #include "XeTeXFontInst.h"
50 #ifdef XETEX_MAC
51 #include "XeTeXFontInst_Mac.h"
52 #endif
53 #include "XeTeXFontMgr.h"
54
55 struct XeTeXLayoutEngine_rec
56 {
57 XeTeXFontInst* font;
58 PlatformFontRef fontRef;
59 hb_tag_t script;
60 hb_language_t language;
61 hb_feature_t* features;
62 char** ShaperList; // the requested shapers
63 char* shaper; // the actually used shaper
64 int nFeatures;
65 uint32_t rgbValue;
66 float extend;
67 float slant;
68 float embolden;
69 hb_buffer_t* hbBuffer;
70 };
71
72 /*******************************************************************/
73 /* Glyph bounding box cache to speed up \XeTeXuseglyphmetrics mode */
74 /*******************************************************************/
75 #include <map>
76
77 // key is combined value representing (font_id << 16) + glyph
78 // value is glyph bounding box in TeX points
79 static std::map<uint32_t,GlyphBBox> sGlyphBoxes;
80
81 int
getCachedGlyphBBox(uint16_t fontID,uint16_t glyphID,GlyphBBox * bbox)82 getCachedGlyphBBox(uint16_t fontID, uint16_t glyphID, GlyphBBox* bbox)
83 {
84 uint32_t key = ((uint32_t)fontID << 16) + glyphID;
85 std::map<uint32_t,GlyphBBox>::const_iterator i = sGlyphBoxes.find(key);
86 if (i == sGlyphBoxes.end()) {
87 return 0;
88 }
89 *bbox = i->second;
90 return 1;
91 }
92
93 void
cacheGlyphBBox(uint16_t fontID,uint16_t glyphID,const GlyphBBox * bbox)94 cacheGlyphBBox(uint16_t fontID, uint16_t glyphID, const GlyphBBox* bbox)
95 {
96 uint32_t key = ((uint32_t)fontID << 16) + glyphID;
97 sGlyphBoxes[key] = *bbox;
98 }
99 /*******************************************************************/
100
101 void
terminatefontmanager()102 terminatefontmanager()
103 {
104 XeTeXFontMgr::Terminate();
105 }
106
107 XeTeXFont
createFont(PlatformFontRef fontRef,Fixed pointSize)108 createFont(PlatformFontRef fontRef, Fixed pointSize)
109 {
110 int status = 0;
111 #ifdef XETEX_MAC
112 XeTeXFontInst* font = new XeTeXFontInst_Mac(fontRef, Fix2D(pointSize), status);
113 #else
114 FcChar8* pathname = 0;
115 FcPatternGetString(fontRef, FC_FILE, 0, &pathname);
116 int index;
117 FcPatternGetInteger(fontRef, FC_INDEX, 0, &index);
118 XeTeXFontInst* font = new XeTeXFontInst((const char*)pathname, index, Fix2D(pointSize), status);
119 #endif
120 if (status != 0) {
121 delete font;
122 return NULL;
123 }
124 return (XeTeXFont)font;
125 }
126
127 XeTeXFont
createFontFromFile(const char * filename,int index,Fixed pointSize)128 createFontFromFile(const char* filename, int index, Fixed pointSize)
129 {
130 int status = 0;
131 XeTeXFontInst* font = new XeTeXFontInst(filename, index, Fix2D(pointSize), status);
132 if (status != 0) {
133 delete font;
134 return NULL;
135 }
136 return (XeTeXFont)font;
137 }
138
139 void
setFontLayoutDir(XeTeXFont font,int vertical)140 setFontLayoutDir(XeTeXFont font, int vertical)
141 {
142 ((XeTeXFontInst*)font)->setLayoutDirVertical(vertical != 0);
143 }
144
145 PlatformFontRef
findFontByName(const char * name,char * var,double size)146 findFontByName(const char* name, char* var, double size)
147 {
148 return XeTeXFontMgr::GetFontManager()->findFont(name, var, size);
149 }
150
151 char
getReqEngine()152 getReqEngine()
153 {
154 return XeTeXFontMgr::GetFontManager()->getReqEngine();
155 }
156
157 void
setReqEngine(char reqEngine)158 setReqEngine(char reqEngine)
159 {
160 XeTeXFontMgr::GetFontManager()->setReqEngine(reqEngine);
161 }
162
163 const char*
getFullName(PlatformFontRef fontRef)164 getFullName(PlatformFontRef fontRef)
165 {
166 return XeTeXFontMgr::GetFontManager()->getFullName(fontRef);
167 }
168
169 double
getDesignSize(XeTeXFont font)170 getDesignSize(XeTeXFont font)
171 {
172 return XeTeXFontMgr::GetFontManager()->getDesignSize(font);
173 }
174
175 const char*
getFontFilename(XeTeXLayoutEngine engine,uint32_t * index)176 getFontFilename(XeTeXLayoutEngine engine, uint32_t* index)
177 {
178 return xstrdup(engine->font->getFilename(index));
179 }
180
181 PlatformFontRef
getFontRef(XeTeXLayoutEngine engine)182 getFontRef(XeTeXLayoutEngine engine)
183 {
184 return engine->fontRef;
185 }
186
187 void
deleteFont(XeTeXFont font)188 deleteFont(XeTeXFont font)
189 {
190 delete (XeTeXFontInst*)font;
191 }
192
193 void*
getFontTablePtr(XeTeXFont font,uint32_t tableTag)194 getFontTablePtr(XeTeXFont font, uint32_t tableTag)
195 {
196 return const_cast<void*>(((XeTeXFontInst*)font)->getFontTable(tableTag));
197 }
198
199 Fixed
getSlant(XeTeXFont font)200 getSlant(XeTeXFont font)
201 {
202 float italAngle = ((XeTeXFontInst*)font)->getItalicAngle();
203 return D2Fix(tan(-italAngle * M_PI / 180.0));
204 }
205
206 static unsigned int
getLargerScriptListTable(XeTeXFont font,hb_tag_t ** scriptList)207 getLargerScriptListTable(XeTeXFont font, hb_tag_t** scriptList)
208 {
209 unsigned int rval = 0;
210
211 hb_face_t* face = hb_font_get_face(((XeTeXFontInst*)font)->getHbFont());
212
213 hb_tag_t* scriptListSub = NULL;
214 hb_tag_t* scriptListPos = NULL;
215
216 unsigned int scriptCountSub = hb_ot_layout_table_get_script_tags(face, HB_OT_TAG_GSUB, 0, NULL, NULL);
217 scriptListSub = (hb_tag_t*) xcalloc(scriptCountSub, sizeof(hb_tag_t*));
218 hb_ot_layout_table_get_script_tags(face, HB_OT_TAG_GSUB, 0, &scriptCountSub, scriptListSub);
219
220 unsigned int scriptCountPos = hb_ot_layout_table_get_script_tags(face, HB_OT_TAG_GPOS, 0, NULL, NULL);
221 scriptListPos = (hb_tag_t*) xcalloc(scriptCountPos, sizeof(hb_tag_t*));
222 hb_ot_layout_table_get_script_tags(face, HB_OT_TAG_GSUB, 0, &scriptCountPos, scriptListPos);
223
224 if (scriptCountSub > scriptCountPos) {
225 if (scriptList != NULL)
226 *scriptList = scriptListSub;
227 rval = scriptCountSub;
228 } else {
229 if (scriptList != NULL)
230 *scriptList = scriptListPos;
231 rval = scriptCountPos;
232 }
233
234 return rval;
235 }
236
237 unsigned int
countScripts(XeTeXFont font)238 countScripts(XeTeXFont font)
239 {
240 return getLargerScriptListTable(font, NULL);
241 }
242
243 hb_tag_t
getIndScript(XeTeXFont font,unsigned int index)244 getIndScript(XeTeXFont font, unsigned int index)
245 {
246 hb_tag_t rval = 0;
247
248 hb_tag_t* scriptList;
249
250 unsigned int scriptCount = getLargerScriptListTable(font, &scriptList);
251 if (scriptList != NULL) {
252 if (index < scriptCount)
253 rval = scriptList[index];
254 }
255
256 return rval;
257 }
258
259 unsigned int
countLanguages(XeTeXFont font,hb_tag_t script)260 countLanguages(XeTeXFont font, hb_tag_t script)
261 {
262 unsigned int rval = 0;
263
264 hb_face_t* face = hb_font_get_face(((XeTeXFontInst*)font)->getHbFont());
265 hb_tag_t* scriptList;
266
267 unsigned int scriptCount = getLargerScriptListTable(font, &scriptList);
268 if (scriptList != NULL) {
269 for (int i = 0; i < scriptCount; i++) {
270 if (scriptList[i] == script) {
271 rval += hb_ot_layout_script_get_language_tags (face, HB_OT_TAG_GSUB, i, 0, NULL, NULL);
272 rval += hb_ot_layout_script_get_language_tags (face, HB_OT_TAG_GPOS, i, 0, NULL, NULL);
273 break;
274 }
275 }
276 }
277
278 return rval;
279 }
280
281 hb_tag_t
getIndLanguage(XeTeXFont font,hb_tag_t script,unsigned int index)282 getIndLanguage(XeTeXFont font, hb_tag_t script, unsigned int index)
283 {
284 hb_tag_t rval = 0;
285
286 hb_face_t* face = hb_font_get_face(((XeTeXFontInst*)font)->getHbFont());
287 hb_tag_t* scriptList;
288
289 unsigned int scriptCount = getLargerScriptListTable(font, &scriptList);
290 if (scriptList != NULL) {
291 for (int i = 0; i < scriptCount; i++) {
292 if (scriptList[i] == script) {
293 unsigned int langCount;
294 hb_tag_t* langList;
295
296 langCount = hb_ot_layout_script_get_language_tags(face, HB_OT_TAG_GSUB, i, 0, NULL, NULL);
297 langList = (hb_tag_t*) xcalloc(langCount, sizeof(hb_tag_t*));
298 hb_ot_layout_script_get_language_tags(face, HB_OT_TAG_GSUB, i, 0, &langCount, langList);
299
300 if (index < langCount) {
301 rval = langList[index];
302 break;
303 }
304
305 free(langList);
306
307 langCount = hb_ot_layout_script_get_language_tags(face, HB_OT_TAG_GPOS, i, 0, NULL, NULL);
308 langList = (hb_tag_t*) xcalloc(langCount, sizeof(hb_tag_t*));
309 hb_ot_layout_script_get_language_tags(face, HB_OT_TAG_GPOS, i, 0, &langCount, langList);
310
311 if (index < langCount) {
312 rval = langList[index];
313 break;
314 }
315
316 free(langList);
317 }
318 }
319 }
320
321 return rval;
322 }
323
324 unsigned int
countFeatures(XeTeXFont font,hb_tag_t script,hb_tag_t language)325 countFeatures(XeTeXFont font, hb_tag_t script, hb_tag_t language)
326 {
327 unsigned int rval = 0;
328
329 hb_face_t* face = hb_font_get_face(((XeTeXFontInst*)font)->getHbFont());
330
331 for (int i = 0; i < 2; ++i) {
332 unsigned int scriptIndex, langIndex = 0;
333 hb_tag_t tableTag = i == 0 ? HB_OT_TAG_GSUB : HB_OT_TAG_GPOS;
334 if (hb_ot_layout_table_find_script(face, tableTag, script, &scriptIndex)) {
335 if (hb_ot_layout_script_find_language(face, tableTag, scriptIndex, language, &langIndex) || language == 0) {
336 rval += hb_ot_layout_language_get_feature_tags(face, tableTag, scriptIndex, langIndex, 0, NULL, NULL);
337 }
338 }
339 }
340
341 return rval;
342 }
343
344 hb_tag_t
getIndFeature(XeTeXFont font,hb_tag_t script,hb_tag_t language,unsigned int index)345 getIndFeature(XeTeXFont font, hb_tag_t script, hb_tag_t language, unsigned int index)
346 {
347 hb_tag_t rval = 0;
348
349 hb_face_t* face = hb_font_get_face(((XeTeXFontInst*)font)->getHbFont());
350
351 for (int i = 0; i < 2; ++i) {
352 unsigned int scriptIndex, langIndex = 0;
353 hb_tag_t tableTag = i == 0 ? HB_OT_TAG_GSUB : HB_OT_TAG_GPOS;
354 if (hb_ot_layout_table_find_script(face, tableTag, script, &scriptIndex)) {
355 if (hb_ot_layout_script_find_language(face, tableTag, scriptIndex, language, &langIndex) || language == 0) {
356 unsigned int featCount = hb_ot_layout_language_get_feature_tags(face, tableTag, scriptIndex, langIndex, 0, NULL, NULL);
357 hb_tag_t* featList = (hb_tag_t*) xcalloc(featCount, sizeof(hb_tag_t*));
358 hb_ot_layout_language_get_feature_tags(face, tableTag, scriptIndex, langIndex, 0, &featCount, featList);
359
360 if (index < featCount) {
361 rval = featList[index];
362 break;
363 }
364
365 index -= featCount;
366 }
367 }
368 }
369
370 return rval;
371 }
372
373 uint32_t
countGraphiteFeatures(XeTeXLayoutEngine engine)374 countGraphiteFeatures(XeTeXLayoutEngine engine)
375 {
376 uint32_t rval = 0;
377
378 hb_face_t* hbFace = hb_font_get_face(engine->font->getHbFont());
379 gr_face* grFace = hb_graphite2_face_get_gr_face(hbFace);
380
381 if (grFace != NULL)
382 rval = gr_face_n_fref(grFace);
383
384 return rval;
385 }
386
387 uint32_t
getGraphiteFeatureCode(XeTeXLayoutEngine engine,uint32_t index)388 getGraphiteFeatureCode(XeTeXLayoutEngine engine, uint32_t index)
389 {
390 uint32_t rval = 0;
391
392 hb_face_t* hbFace = hb_font_get_face(engine->font->getHbFont());
393 gr_face* grFace = hb_graphite2_face_get_gr_face(hbFace);
394
395 if (grFace != NULL) {
396 const gr_feature_ref* feature = gr_face_fref(grFace, index);
397 rval = gr_fref_id(feature);
398 }
399
400 return rval;
401 }
402
403 uint32_t
countGraphiteFeatureSettings(XeTeXLayoutEngine engine,uint32_t featureID)404 countGraphiteFeatureSettings(XeTeXLayoutEngine engine, uint32_t featureID)
405 {
406 uint32_t rval = 0;
407
408 hb_face_t* hbFace = hb_font_get_face(engine->font->getHbFont());
409 gr_face* grFace = hb_graphite2_face_get_gr_face(hbFace);
410
411 if (grFace != NULL) {
412 const gr_feature_ref* feature = gr_face_find_fref(grFace, featureID);
413 rval = gr_fref_n_values(feature);
414 }
415
416 return rval;
417 }
418
419 uint32_t
getGraphiteFeatureSettingCode(XeTeXLayoutEngine engine,uint32_t featureID,uint32_t index)420 getGraphiteFeatureSettingCode(XeTeXLayoutEngine engine, uint32_t featureID, uint32_t index)
421 {
422 uint32_t rval = 0;
423
424 hb_face_t* hbFace = hb_font_get_face(engine->font->getHbFont());
425 gr_face* grFace = hb_graphite2_face_get_gr_face(hbFace);
426
427 if (grFace != NULL) {
428 const gr_feature_ref* feature = gr_face_find_fref(grFace, featureID);
429 rval = gr_fref_value(feature, index);
430 }
431
432 return rval;
433 }
434
435 #define tag_from_lang(x) hb_tag_from_string(hb_language_to_string(x), strlen(hb_language_to_string(x)))
436
437 uint32_t
getGraphiteFeatureDefaultSetting(XeTeXLayoutEngine engine,uint32_t featureID)438 getGraphiteFeatureDefaultSetting(XeTeXLayoutEngine engine, uint32_t featureID)
439 {
440 uint32_t rval = 0;
441
442 hb_face_t* hbFace = hb_font_get_face(engine->font->getHbFont());
443 gr_face* grFace = hb_graphite2_face_get_gr_face(hbFace);
444
445 if (grFace != NULL) {
446 const gr_feature_ref* feature = gr_face_find_fref(grFace, featureID);
447 gr_feature_val *featureValues = gr_face_featureval_for_lang (grFace, tag_from_lang(engine->language));
448
449 rval = gr_fref_feature_value(feature, featureValues);
450 }
451
452 return rval;
453 }
454
455 char *
getGraphiteFeatureLabel(XeTeXLayoutEngine engine,uint32_t featureID)456 getGraphiteFeatureLabel(XeTeXLayoutEngine engine, uint32_t featureID)
457 {
458 hb_face_t* hbFace = hb_font_get_face(engine->font->getHbFont());
459 gr_face* grFace = hb_graphite2_face_get_gr_face(hbFace);
460
461 if (grFace != NULL) {
462 const gr_feature_ref* feature = gr_face_find_fref(grFace, featureID);
463 uint32_t len = 0;
464 uint16_t langID = 0x409;
465
466 return (char *) gr_fref_label(feature, &langID, gr_utf8, &len);
467 }
468
469 return NULL;
470 }
471
472 char *
getGraphiteFeatureSettingLabel(XeTeXLayoutEngine engine,uint32_t featureID,uint32_t settingID)473 getGraphiteFeatureSettingLabel(XeTeXLayoutEngine engine, uint32_t featureID, uint32_t settingID)
474 {
475 hb_face_t* hbFace = hb_font_get_face(engine->font->getHbFont());
476 gr_face* grFace = hb_graphite2_face_get_gr_face(hbFace);
477
478 if (grFace != NULL) {
479 const gr_feature_ref* feature = gr_face_find_fref(grFace, featureID);
480 for (int i = 0; i < gr_fref_n_values(feature); i++) {
481 if (settingID == gr_fref_value(feature, i)) {
482 uint32_t len = 0;
483 uint16_t langID = 0x409;
484
485 return (char *) gr_fref_value_label(feature, i, &langID, gr_utf8, &len);
486 }
487 }
488 }
489
490 return NULL;
491 }
492
493 bool
findGraphiteFeature(XeTeXLayoutEngine engine,const char * s,const char * e,hb_tag_t * f,int * v)494 findGraphiteFeature(XeTeXLayoutEngine engine, const char* s, const char* e, hb_tag_t* f, int* v)
495 /* s...e is a "feature=setting" string; look for this in the font */
496 {
497 *f = 0;
498 *v = 0;
499 while (*s == ' ' || *s == '\t')
500 ++s;
501 const char* cp = s;
502 while (cp < e && *cp != '=')
503 ++cp;
504
505 *f = findGraphiteFeatureNamed(engine, s, cp - s);
506 if (*f == -1)
507 return false;
508
509 ++cp;
510 while (cp < e && (*cp == ' ' || *cp == '\t'))
511 ++cp;
512
513 if (cp == e)
514 /* no setting was specified */
515 return false;
516
517 *v = findGraphiteFeatureSettingNamed(engine, *f, cp, e - cp);
518 if (*v == -1)
519 return false;
520
521 return true;
522 }
523
524 long
findGraphiteFeatureNamed(XeTeXLayoutEngine engine,const char * name,int namelength)525 findGraphiteFeatureNamed(XeTeXLayoutEngine engine, const char* name, int namelength)
526 {
527 long rval = -1;
528
529 hb_face_t* hbFace = hb_font_get_face(engine->font->getHbFont());
530 gr_face* grFace = hb_graphite2_face_get_gr_face(hbFace);
531
532 if (grFace != NULL) {
533 for (int i = 0; i < gr_face_n_fref(grFace); i++) {
534 const gr_feature_ref* feature = gr_face_fref(grFace, i);
535 uint32_t len = 0;
536 uint16_t langID = 0x409;
537
538 // the first call is to get the length of the string
539 gr_fref_label(feature, &langID, gr_utf8, &len);
540 char* label = (char*) xmalloc(len);
541 label = (char*) gr_fref_label(feature, &langID, gr_utf8, &len);
542
543 if (strncmp(label, name, namelength) == 0) {
544 rval = gr_fref_id(feature);
545 gr_label_destroy(label);
546 break;
547 }
548
549 gr_label_destroy(label);
550 }
551 }
552
553 return rval;
554 }
555
556 long
findGraphiteFeatureSettingNamed(XeTeXLayoutEngine engine,uint32_t id,const char * name,int namelength)557 findGraphiteFeatureSettingNamed(XeTeXLayoutEngine engine, uint32_t id, const char* name, int namelength)
558 {
559 long rval = -1;
560
561 hb_face_t* hbFace = hb_font_get_face(engine->font->getHbFont());
562 gr_face* grFace = hb_graphite2_face_get_gr_face(hbFace);
563
564 if (grFace != NULL) {
565 const gr_feature_ref* feature = gr_face_find_fref(grFace, id);
566 for (int i = 0; i < gr_fref_n_values(feature); i++) {
567 uint32_t len = 0;
568 uint16_t langID = 0x409;
569
570 // the first call is to get the length of the string
571 gr_fref_value_label(feature, i, &langID, gr_utf8, &len);
572 char* label = (char*) xmalloc(len);
573 label = (char*) gr_fref_value_label(feature, i, &langID, gr_utf8, &len);
574
575 if (strncmp(label, name, namelength) == 0) {
576 rval = gr_fref_value(feature, i);
577 gr_label_destroy(label);
578 break;
579 }
580
581 gr_label_destroy(label);
582 }
583 }
584
585 return rval;
586 }
587
588 float
getGlyphWidth(XeTeXFont font,uint32_t gid)589 getGlyphWidth(XeTeXFont font, uint32_t gid)
590 {
591 return ((XeTeXFontInst*)font)->getGlyphWidth(gid);
592 }
593
594 unsigned int
countGlyphs(XeTeXFont font)595 countGlyphs(XeTeXFont font)
596 {
597 return ((XeTeXFontInst*)font)->getNumGlyphs();
598 }
599
600 XeTeXFont
getFont(XeTeXLayoutEngine engine)601 getFont(XeTeXLayoutEngine engine)
602 {
603 return (XeTeXFont)(engine->font);
604 }
605
606 float
getExtendFactor(XeTeXLayoutEngine engine)607 getExtendFactor(XeTeXLayoutEngine engine)
608 {
609 return engine->extend;
610 }
611
612 float
getSlantFactor(XeTeXLayoutEngine engine)613 getSlantFactor(XeTeXLayoutEngine engine)
614 {
615 return engine->slant;
616 }
617
618 float
getEmboldenFactor(XeTeXLayoutEngine engine)619 getEmboldenFactor(XeTeXLayoutEngine engine)
620 {
621 return engine->embolden;
622 }
623
624 XeTeXLayoutEngine
createLayoutEngine(PlatformFontRef fontRef,XeTeXFont font,hb_tag_t script,char * language,hb_feature_t * features,int nFeatures,char ** shapers,uint32_t rgbValue,float extend,float slant,float embolden)625 createLayoutEngine(PlatformFontRef fontRef, XeTeXFont font, hb_tag_t script, char *language,
626 hb_feature_t* features, int nFeatures, char **shapers, uint32_t rgbValue,
627 float extend, float slant, float embolden)
628 {
629 XeTeXLayoutEngine result = new XeTeXLayoutEngine_rec;
630 result->fontRef = fontRef;
631 result->font = (XeTeXFontInst*)font;
632 result->script = script;
633 result->features = features;
634 result->ShaperList = shapers;
635 result->shaper = NULL;
636 result->nFeatures = nFeatures;
637 result->rgbValue = rgbValue;
638 result->extend = extend;
639 result->slant = slant;
640 result->embolden = embolden;
641 result->hbBuffer = hb_buffer_create();
642
643 // For Graphite fonts treat the language as BCP 47 tag, for OpenType we
644 // treat it as a OT language tag for backward compatibility with pre-0.9999
645 // XeTeX.
646 if (getReqEngine() == 'G')
647 result->language = hb_language_from_string(language, -1);
648 else
649 result->language = hb_ot_tag_to_language(hb_tag_from_string(language, -1));
650
651 free(language);
652
653 return result;
654 }
655
656 void
deleteLayoutEngine(XeTeXLayoutEngine engine)657 deleteLayoutEngine(XeTeXLayoutEngine engine)
658 {
659 hb_buffer_destroy(engine->hbBuffer);
660 delete engine->font;
661 free(engine->shaper);
662 }
663
664 static unsigned int
_decompose_compat(hb_unicode_funcs_t * ufuncs,hb_codepoint_t u,hb_codepoint_t * decomposed,void * user_data)665 _decompose_compat(hb_unicode_funcs_t* ufuncs,
666 hb_codepoint_t u,
667 hb_codepoint_t* decomposed,
668 void* user_data)
669 {
670 return 0;
671 }
672
673 static hb_unicode_funcs_t*
_get_unicode_funcs(void)674 _get_unicode_funcs(void)
675 {
676 static hb_unicode_funcs_t* ufuncs = hb_unicode_funcs_create(hb_icu_get_unicode_funcs());
677 hb_unicode_funcs_set_decompose_compatibility_func(ufuncs, _decompose_compat, NULL, NULL);
678 return ufuncs;
679 }
680
681 static hb_unicode_funcs_t* hbUnicodeFuncs = NULL;
682
683 int
layoutChars(XeTeXLayoutEngine engine,uint16_t chars[],int32_t offset,int32_t count,int32_t max,bool rightToLeft)684 layoutChars(XeTeXLayoutEngine engine, uint16_t chars[], int32_t offset, int32_t count, int32_t max,
685 bool rightToLeft)
686 {
687 bool res;
688 hb_script_t script = HB_SCRIPT_INVALID;
689 hb_direction_t direction = HB_DIRECTION_LTR;
690 hb_segment_properties_t segment_props;
691 hb_shape_plan_t *shape_plan;
692 hb_font_t* hbFont = engine->font->getHbFont();
693 hb_face_t* hbFace = hb_font_get_face(hbFont);
694
695 if (engine->font->getLayoutDirVertical())
696 direction = HB_DIRECTION_TTB;
697 else if (rightToLeft)
698 direction = HB_DIRECTION_RTL;
699
700 script = hb_ot_tag_to_script (engine->script);
701
702 if (hbUnicodeFuncs == NULL)
703 hbUnicodeFuncs = _get_unicode_funcs();
704
705 hb_buffer_reset(engine->hbBuffer);
706 hb_buffer_set_unicode_funcs(engine->hbBuffer, hbUnicodeFuncs);
707 hb_buffer_add_utf16(engine->hbBuffer, chars, max, offset, count);
708 hb_buffer_set_direction(engine->hbBuffer, direction);
709 hb_buffer_set_script(engine->hbBuffer, script);
710 hb_buffer_set_language(engine->hbBuffer, engine->language);
711
712 hb_buffer_guess_segment_properties(engine->hbBuffer);
713 hb_buffer_get_segment_properties(engine->hbBuffer, &segment_props);
714
715 if (engine->ShaperList == NULL) {
716 // HarfBuzz gives graphite2 shaper a priority, so that for hybrid
717 // Graphite/OpenType fonts, Graphite will be used. However, pre-0.9999
718 // XeTeX preferred OpenType over Graphite, so we are doing the same
719 // here for sake of backward compatibility. Since "ot" shaper never
720 // fails, we set the shaper list to just include it.
721 engine->ShaperList = (char**) xcalloc(2, sizeof(char*));
722 engine->ShaperList[0] = (char*) "ot";
723 engine->ShaperList[1] = NULL;
724 }
725
726 shape_plan = hb_shape_plan_create_cached(hbFace, &segment_props, engine->features, engine->nFeatures, engine->ShaperList);
727 res = hb_shape_plan_execute(shape_plan, hbFont, engine->hbBuffer, engine->features, engine->nFeatures);
728
729 if (res) {
730 engine->shaper = strdup(hb_shape_plan_get_shaper(shape_plan));
731 hb_buffer_set_content_type(engine->hbBuffer, HB_BUFFER_CONTENT_TYPE_GLYPHS);
732 } else {
733 // all selected shapers failed, retrying with default
734 // we don't use _cached here as the cached plain will always fail.
735 hb_shape_plan_destroy(shape_plan);
736 shape_plan = hb_shape_plan_create(hbFace, &segment_props, engine->features, engine->nFeatures, NULL);
737 res = hb_shape_plan_execute(shape_plan, hbFont, engine->hbBuffer, engine->features, engine->nFeatures);
738
739 if (res) {
740 engine->shaper = strdup(hb_shape_plan_get_shaper(shape_plan));
741 hb_buffer_set_content_type(engine->hbBuffer, HB_BUFFER_CONTENT_TYPE_GLYPHS);
742 } else {
743 fprintf(stderr, "\nERROR: all shapers failed\n");
744 exit(3);
745 }
746 }
747
748 hb_shape_plan_destroy(shape_plan);
749
750 int glyphCount = hb_buffer_get_length(engine->hbBuffer);
751
752 #ifdef DEBUG
753 char buf[1024];
754 unsigned int consumed;
755
756 printf ("shaper: %s\n", engine->shaper);
757
758 hb_buffer_serialize_flags_t flags = HB_BUFFER_SERIALIZE_FLAGS_DEFAULT;
759 hb_buffer_serialize_format_t format = HB_BUFFER_SERIALIZE_FORMAT_JSON;
760
761 hb_buffer_serialize_glyphs (engine->hbBuffer, 0, glyphCount, buf, sizeof(buf), &consumed, hbFont, format, flags);
762 if (consumed)
763 printf ("buffer glyphs: %s\n", buf);
764 #endif
765
766 return glyphCount;
767 }
768
769 void
getGlyphs(XeTeXLayoutEngine engine,uint32_t glyphs[])770 getGlyphs(XeTeXLayoutEngine engine, uint32_t glyphs[])
771 {
772 int glyphCount = hb_buffer_get_length(engine->hbBuffer);
773 hb_glyph_info_t *hbGlyphs = hb_buffer_get_glyph_infos(engine->hbBuffer, NULL);
774
775 for (int i = 0; i < glyphCount; i++)
776 glyphs[i] = hbGlyphs[i].codepoint;
777 }
778
779 void
getGlyphAdvances(XeTeXLayoutEngine engine,float advances[])780 getGlyphAdvances(XeTeXLayoutEngine engine, float advances[])
781 {
782 int glyphCount = hb_buffer_get_length(engine->hbBuffer);
783 hb_glyph_position_t *hbPositions = hb_buffer_get_glyph_positions(engine->hbBuffer, NULL);
784
785 for (int i = 0; i < glyphCount; i++) {
786 if (engine->font->getLayoutDirVertical())
787 advances[i] = engine->font->unitsToPoints(hbPositions[i].y_advance);
788 else
789 advances[i] = engine->font->unitsToPoints(hbPositions[i].x_advance);
790 }
791 }
792
793 void
getGlyphPositions(XeTeXLayoutEngine engine,FloatPoint positions[])794 getGlyphPositions(XeTeXLayoutEngine engine, FloatPoint positions[])
795 {
796 int glyphCount = hb_buffer_get_length(engine->hbBuffer);
797 hb_glyph_position_t *hbPositions = hb_buffer_get_glyph_positions(engine->hbBuffer, NULL);
798
799 float x = 0, y = 0;
800
801 if (engine->font->getLayoutDirVertical()) {
802 for (int i = 0; i < glyphCount; i++) {
803 positions[i].x = -engine->font->unitsToPoints(x + hbPositions[i].y_offset); /* negative is forwards */
804 positions[i].y = engine->font->unitsToPoints(y - hbPositions[i].x_offset);
805 x += hbPositions[i].y_advance;
806 y += hbPositions[i].x_advance;
807 }
808 positions[glyphCount].x = -engine->font->unitsToPoints(x);
809 positions[glyphCount].y = engine->font->unitsToPoints(y);
810 } else {
811 for (int i = 0; i < glyphCount; i++) {
812 positions[i].x = engine->font->unitsToPoints(x + hbPositions[i].x_offset);
813 positions[i].y = -engine->font->unitsToPoints(y + hbPositions[i].y_offset); /* negative is upwards */
814 x += hbPositions[i].x_advance;
815 y += hbPositions[i].y_advance;
816 }
817 positions[glyphCount].x = engine->font->unitsToPoints(x);
818 positions[glyphCount].y = -engine->font->unitsToPoints(y);
819 }
820
821 if (engine->extend != 1.0 || engine->slant != 0.0)
822 for (int i = 0; i <= glyphCount; ++i)
823 positions[i].x = positions[i].x * engine->extend - positions[i].y * engine->slant;
824 }
825
826 float
getPointSize(XeTeXLayoutEngine engine)827 getPointSize(XeTeXLayoutEngine engine)
828 {
829 return engine->font->getPointSize();
830 }
831
832 void
getAscentAndDescent(XeTeXLayoutEngine engine,float * ascent,float * descent)833 getAscentAndDescent(XeTeXLayoutEngine engine, float* ascent, float* descent)
834 {
835 *ascent = engine->font->getAscent();
836 *descent = engine->font->getDescent();
837 }
838
839 void
getCapAndXHeight(XeTeXLayoutEngine engine,float * capheight,float * xheight)840 getCapAndXHeight(XeTeXLayoutEngine engine, float* capheight, float* xheight)
841 {
842 *capheight = engine->font->getCapHeight();
843 *xheight = engine->font->getXHeight();
844 }
845
846 int
getDefaultDirection(XeTeXLayoutEngine engine)847 getDefaultDirection(XeTeXLayoutEngine engine)
848 {
849 hb_script_t script = hb_buffer_get_script(engine->hbBuffer);
850 if (hb_script_get_horizontal_direction (script) == HB_DIRECTION_RTL)
851 return UBIDI_DEFAULT_RTL;
852 else
853 return UBIDI_DEFAULT_LTR;
854 }
855
856 uint32_t
getRgbValue(XeTeXLayoutEngine engine)857 getRgbValue(XeTeXLayoutEngine engine)
858 {
859 return engine->rgbValue;
860 }
861
862 void
getGlyphBounds(XeTeXLayoutEngine engine,uint32_t glyphID,GlyphBBox * bbox)863 getGlyphBounds(XeTeXLayoutEngine engine, uint32_t glyphID, GlyphBBox* bbox)
864 {
865 engine->font->getGlyphBounds(glyphID, bbox);
866 if (engine->extend != 0.0) {
867 bbox->xMin *= engine->extend;
868 bbox->xMax *= engine->extend;
869 }
870 }
871
872 float
getGlyphWidthFromEngine(XeTeXLayoutEngine engine,uint32_t glyphID)873 getGlyphWidthFromEngine(XeTeXLayoutEngine engine, uint32_t glyphID)
874 {
875 return engine->extend * engine->font->getGlyphWidth(glyphID);
876 }
877
878 void
getGlyphHeightDepth(XeTeXLayoutEngine engine,uint32_t glyphID,float * height,float * depth)879 getGlyphHeightDepth(XeTeXLayoutEngine engine, uint32_t glyphID, float* height, float* depth)
880 {
881 engine->font->getGlyphHeightDepth(glyphID, height, depth);
882 }
883
884 void
getGlyphSidebearings(XeTeXLayoutEngine engine,uint32_t glyphID,float * lsb,float * rsb)885 getGlyphSidebearings(XeTeXLayoutEngine engine, uint32_t glyphID, float* lsb, float* rsb)
886 {
887 engine->font->getGlyphSidebearings(glyphID, lsb, rsb);
888 if (engine->extend != 0.0) {
889 *lsb *= engine->extend;
890 *rsb *= engine->extend;
891 }
892 }
893
894 float
getGlyphItalCorr(XeTeXLayoutEngine engine,uint32_t glyphID)895 getGlyphItalCorr(XeTeXLayoutEngine engine, uint32_t glyphID)
896 {
897 return engine->extend * engine->font->getGlyphItalCorr(glyphID);
898 }
899
900 uint32_t
mapCharToGlyph(XeTeXLayoutEngine engine,uint32_t charCode)901 mapCharToGlyph(XeTeXLayoutEngine engine, uint32_t charCode)
902 {
903 return engine->font->mapCharToGlyph(charCode);
904 }
905
906 int
getFontCharRange(XeTeXLayoutEngine engine,int reqFirst)907 getFontCharRange(XeTeXLayoutEngine engine, int reqFirst)
908 {
909 if (reqFirst)
910 return engine->font->getFirstCharCode();
911 else
912 return engine->font->getLastCharCode();
913 }
914
915 const char*
getGlyphName(XeTeXFont font,uint16_t gid,int * len)916 getGlyphName(XeTeXFont font, uint16_t gid, int* len)
917 {
918 return ((XeTeXFontInst*)font)->getGlyphName(gid, *len);
919 }
920
921 int
mapGlyphToIndex(XeTeXLayoutEngine engine,const char * glyphName)922 mapGlyphToIndex(XeTeXLayoutEngine engine, const char* glyphName)
923 {
924 return engine->font->mapGlyphToIndex(glyphName);
925 }
926
927 static gr_segment* grSegment = NULL;
928 static const gr_slot* grPrevSlot = NULL;
929 static int grTextLen;
930
931 bool
initGraphiteBreaking(XeTeXLayoutEngine engine,const uint16_t * txtPtr,int txtLen)932 initGraphiteBreaking(XeTeXLayoutEngine engine, const uint16_t* txtPtr, int txtLen)
933 {
934 hb_face_t* hbFace = hb_font_get_face(engine->font->getHbFont());
935 gr_face* grFace = hb_graphite2_face_get_gr_face(hbFace);
936 gr_font* grFont = hb_graphite2_font_get_gr_font(engine->font->getHbFont());
937 if (grFace != NULL && grFont != NULL) {
938 if (grSegment != NULL) {
939 gr_seg_destroy(grSegment);
940 grSegment = NULL;
941 grPrevSlot = NULL;
942 }
943
944 gr_feature_val *grFeatureValues = gr_face_featureval_for_lang (grFace, tag_from_lang(engine->language));
945
946 int nFeatures = engine->nFeatures;
947 hb_feature_t *features = engine->features;
948 while (nFeatures--) {
949 const gr_feature_ref *fref = gr_face_find_fref (grFace, features->tag);
950 if (fref)
951 gr_fref_set_feature_value (fref, features->value, grFeatureValues);
952 features++;
953 }
954
955 grSegment = gr_make_seg(grFont, grFace, engine->script, grFeatureValues, gr_utf16, txtPtr, txtLen, 0);
956 grPrevSlot = gr_seg_first_slot(grSegment);
957 grTextLen = txtLen;
958
959 return true;
960 }
961
962 return false;
963 }
964
965 int
findNextGraphiteBreak(void)966 findNextGraphiteBreak(void)
967 {
968 int ret = -1;
969
970 if (grSegment != NULL) {
971 if (grPrevSlot && grPrevSlot != gr_seg_last_slot(grSegment)) {
972 for (const gr_slot* s = gr_slot_next_in_segment(grPrevSlot); s != NULL; s = gr_slot_next_in_segment(s)) {
973 const gr_char_info* ci = NULL;
974 int bw;
975
976 ci = gr_seg_cinfo(grSegment, gr_slot_index(s));
977 bw = gr_cinfo_break_weight(ci);
978 if (bw < gr_breakNone && bw >= gr_breakBeforeWord) {
979 grPrevSlot = s;
980 ret = gr_cinfo_base(ci);
981 } else if (bw > gr_breakNone && bw <= gr_breakWord) {
982 grPrevSlot = gr_slot_next_in_segment(s);
983 ret = gr_cinfo_base(ci) + 1;
984 }
985
986 if (ret != -1)
987 break;
988 }
989
990 if (ret == -1) {
991 grPrevSlot = gr_seg_last_slot(grSegment);
992 ret = grTextLen;
993 }
994 }
995 }
996
997 return ret;
998 }
999
1000 bool
usingGraphite(XeTeXLayoutEngine engine)1001 usingGraphite(XeTeXLayoutEngine engine)
1002 {
1003 if (engine->shaper != NULL && (strcmp("graphite2", engine->shaper) == 0))
1004 return true;
1005 else
1006 return false;
1007 }
1008
1009 bool
usingOpenType(XeTeXLayoutEngine engine)1010 usingOpenType(XeTeXLayoutEngine engine)
1011 {
1012 if (engine->shaper == NULL || (strcmp("ot", engine->shaper) == 0))
1013 return true;
1014 else
1015 return false;
1016 }
1017
1018 bool
isOpenTypeMathFont(XeTeXLayoutEngine engine)1019 isOpenTypeMathFont(XeTeXLayoutEngine engine)
1020 {
1021 if (engine->font->getMathTable() != NULL)
1022 return true;
1023 else
1024 return false;
1025 }
1026