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