w32tex
About: TeX Live provides a comprehensive TeX system including all the major TeX-related programs, macro packages, and fonts that are free software. Windows sources.
  Fossies Dox: w32tex-src.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

otfgsub.cc
Go to the documentation of this file.
1 // -*- related-file-name: "../include/efont/otfgsub.hh" -*-
2 
3 /* otfgsub.{cc,hh} -- OpenType GSUB table
4  *
5  * Copyright (c) 2003-2019 Eddie Kohler
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the Free
9  * Software Foundation; either version 2 of the License, or (at your option)
10  * any later version. This program is distributed in the hope that it will be
11  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13  * Public License for more details.
14  */
15 
16 #ifdef HAVE_CONFIG_H
17 # include <config.h>
18 #endif
19 #include <efont/otfgsub.hh>
20 #include <efont/otfname.hh>
21 #include <lcdf/error.hh>
22 #include <lcdf/straccum.hh>
23 #include <errno.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <algorithm>
27 
28 namespace Efont { namespace OpenType {
29 
30 void
32 {
33  switch (t) {
34  case T_GLYPHS:
35  delete[] s.gids;
36  break;
37  case T_COVERAGE:
38  delete s.coverage;
39  break;
40  }
41  t = T_NONE;
42 }
43 
44 void
46 {
47  clear(s, t);
48  if (n == 1)
49  t = T_GLYPH;
50  else if (n > 1) {
51  s.gids = new Glyph[n + 1];
52  s.gids[0] = n;
53  t = T_GLYPHS;
54  }
55 }
56 
57 void
59 {
60  clear(s, t);
61  s.gid = gid;
62  t = T_GLYPH;
63 }
64 
65 void
66 Substitution::assign(Substitute &s, uint8_t &t, int ngids, const Glyph *gids)
67 {
68  clear(s, t);
69  assert(ngids > 0);
70  if (ngids == 1) {
71  s.gid = gids[0];
72  t = T_GLYPH;
73  } else {
74  s.gids = new Glyph[ngids + 1];
75  s.gids[0] = ngids;
76  memcpy(s.gids + 1, gids, ngids * sizeof(Glyph));
77  t = T_GLYPHS;
78  }
79 }
80 
81 void
83 {
84  clear(s, t);
85  s.coverage = new Coverage(coverage);
86  t = T_COVERAGE;
87 }
88 
89 void
91 {
92  if (&s == &os)
93  return;
94  switch (ot) {
95  case T_NONE:
96  clear(s, t);
97  break;
98  case T_GLYPH:
99  assign(s, t, os.gid);
100  break;
101  case T_GLYPHS:
102  assign(s, t, os.gids[0], os.gids + 1);
103  break;
104  case T_COVERAGE:
105  assign(s, t, *os.coverage);
106  break;
107  default:
108  assert(0);
109  }
110 }
111 
113  : _left_is(T_NONE), _in_is(T_NONE), _out_is(T_NONE), _right_is(T_NONE),
114  _alternate(o._alternate)
115 {
117  assign(_in, _in_is, o._in, o._in_is);
118  assign(_out, _out_is, o._out, o._out_is);
120 }
121 
123  : _left_is(T_NONE), _in_is(T_GLYPH), _out_is(T_GLYPH), _right_is(T_NONE)
124 {
125  _in.gid = in;
126  _out.gid = out;
127 }
128 
130  : _left_is(T_NONE), _in_is(T_GLYPH), _out_is(T_NONE), _right_is(T_NONE),
131  _alternate(is_alternate)
132 {
133  assert(out.size() > 0);
134  _in.gid = in;
135  assign(_out, _out_is, out.size(), &out[0]);
136 }
137 
139  : _left_is(T_NONE), _in_is(T_GLYPHS), _out_is(T_GLYPH), _right_is(T_NONE)
140 {
141  _in.gids = new Glyph[3];
142  _in.gids[0] = 2;
143  _in.gids[1] = in1;
144  _in.gids[2] = in2;
145  _out.gid = out;
146 }
147 
149  : _left_is(T_NONE), _in_is(T_NONE), _out_is(T_GLYPH), _right_is(T_NONE)
150 {
151  assert(in.size() > 0);
152  assign(_in, _in_is, in.size(), &in[0]);
153  _out.gid = out;
154 }
155 
157  : _left_is(T_NONE), _in_is(T_NONE), _out_is(T_GLYPH), _right_is(T_NONE)
158 {
159  assert(nin > 0);
160  assign(_in, _in_is, nin, in);
161  _out.gid = out;
162 }
163 
164 Substitution::Substitution(int nleft, int nin, int nout, int nright)
165  : _left_is(T_NONE), _in_is(T_NONE), _out_is(T_NONE), _right_is(T_NONE)
166 {
167  if (nleft)
169  if (nin)
170  assign_space(_in, _in_is, nin);
171  if (nout)
172  assign_space(_out, _out_is, nout);
173  if (nright)
174  assign_space(_right, _right_is, nright);
175 }
176 
178 {
179  clear(_left, _left_is);
180  clear(_in, _in_is);
181  clear(_out, _out_is);
183 }
184 
185 Substitution &
187 {
189  assign(_in, _in_is, o._in, o._in_is);
190  assign(_out, _out_is, o._out, o._out_is);
193  return *this;
194 }
195 
196 bool
198 {
199  switch (t) {
200  case T_NONE:
201  return true;
202  case T_GLYPH:
203  return c.covers(s.gid);
204  case T_GLYPHS:
205  for (int i = 1; i <= s.gids[0]; i++)
206  if (!c.covers(s.gids[i]))
207  return false;
208  return true;
209  case T_COVERAGE:
210  return *s.coverage <= c;
211  default:
212  assert(0);
213  return false;
214  }
215 }
216 
217 bool
219 {
220  switch (t) {
221  case T_NONE:
222  return true;
223  case T_GLYPH:
224  return gs.covers(s.gid);
225  case T_GLYPHS:
226  for (int i = 1; i <= s.gids[0]; i++)
227  if (!gs.covers(s.gids[i]))
228  return false;
229  return true;
230  case T_COVERAGE:
231  for (Coverage::iterator i = s.coverage->begin(); i; i++)
232  if (!gs.covers(*i))
233  return false;
234  return true;
235  default:
236  assert(0);
237  return false;
238  }
239 }
240 
241 bool
243 {
244  return substitute_in(_left, _left_is, c)
245  && substitute_in(_in, _in_is, c)
247 }
248 
249 bool
251 {
252  return substitute_in(_left, _left_is, gs)
253  && substitute_in(_in, _in_is, gs)
254  && substitute_in(_right, _right_is, gs);
255 }
256 
257 Glyph
259 {
260  return (t == T_GLYPH ? s.gid : 0);
261 }
262 
263 Glyph
264 Substitution::extract_glyph(const Substitute &s, int which, uint8_t t) noexcept
265 {
266  switch (t) {
267  case T_GLYPH:
268  return (which == 0 ? s.gid : 0);
269  case T_GLYPHS:
270  return (s.gids[0] > which ? s.gids[which + 1] : 0);
271  case T_COVERAGE:
272  for (Coverage::iterator ci = s.coverage->begin(); ci; ci++, which--)
273  if (which == 0)
274  return *ci;
275  return 0;
276  default:
277  return 0;
278  }
279 }
280 
281 bool
282 Substitution::extract_glyphs(const Substitute &s, uint8_t t, Vector<Glyph> &v, bool coverage_ok) noexcept
283 {
284  switch (t) {
285  case T_GLYPH:
286  v.push_back(s.gid);
287  return true;
288  case T_GLYPHS:
289  for (int i = 1; i <= s.gids[0]; i++)
290  v.push_back(s.gids[i]);
291  return true;
292  case T_COVERAGE:
293  if (coverage_ok) {
294  for (Coverage::iterator i = s.coverage->begin(); i; i++)
295  v.push_back(*i);
296  return true;
297  } else
298  return false;
299  default:
300  return false;
301  }
302 }
303 
304 Glyph *
306 {
307  switch (t) {
308  case T_GLYPH:
309  return const_cast<Glyph *>(&s.gid);
310  case T_GLYPHS:
311  return &s.gids[1];
312  default:
313  return 0;
314  }
315 }
316 
317 int
318 Substitution::extract_nglyphs(const Substitute &s, uint8_t t, bool coverage_ok) noexcept
319 {
320  switch (t) {
321  case T_GLYPH:
322  return 1;
323  case T_GLYPHS:
324  return s.gids[0];
325  case T_COVERAGE:
326  return (coverage_ok ? 1 : 0);
327  default:
328  return 0;
329  }
330 }
331 
332 bool
334 {
335  switch (t) {
336  case T_GLYPH:
337  return (pos == 0 && s.gid == g);
338  case T_GLYPHS:
339  return (pos >= 0 && pos < s.gids[0] && s.gids[1 + pos] == g);
340  case T_COVERAGE:
341  return (pos == 0 && s.coverage->covers(g));
342  default:
343  return false;
344  }
345 }
346 
347 bool
349 {
350  return (_in_is == T_GLYPH && _out_is == T_GLYPH && _in.gid == _out.gid)
351  || (_in_is == T_GLYPHS && _out_is == T_GLYPHS
352  && _in.gids[0] == _out.gids[0]
353  && memcmp(_in.gids, _out.gids, (_in.gids[0] + 1) * sizeof(Glyph)) == 0);
354 }
355 
356 bool
358 {
359  bool ok = true;
360  gs.clear();
361  if (_left_is != T_NONE)
362  ok &= extract_glyphs(_left, _left_is, gs, false);
363  ok &= extract_glyphs(_in, _in_is, gs, false);
364  if (_right_is != T_NONE)
365  ok &= extract_glyphs(_right, _right_is, gs, false);
366  return ok;
367 }
368 
369 bool
371 {
372  bool ok = true;
373  if (_left_is != T_NONE)
374  ok &= extract_glyphs(_left, _left_is, v, false);
375  ok &= extract_glyphs(_out, _out_is, v, false);
376  if (_right_is != T_NONE)
377  ok &= extract_glyphs(_right, _right_is, v, false);
378  return ok;
379 }
380 
381 void
383 {
384  if (lt == T_NONE)
385  assign(s, t, rs, rt);
386  else if (rt == T_NONE)
387  assign(s, t, ls, lt);
388  else if (lt != T_COVERAGE && rt != T_COVERAGE) {
389  int nl = extract_nglyphs(ls, lt, false);
390  int nr = extract_nglyphs(rs, rt, false);
391  Glyph *gids = new Glyph[nl + nr + 1];
392  gids[0] = nl + nr;
393  memcpy(&gids[1], extract_glyphptr(ls, lt), nl * sizeof(Glyph));
394  memcpy(&gids[1 + nl], extract_glyphptr(rs, rt), nr * sizeof(Glyph));
395  clear(s, t);
396  s.gids = gids;
397  t = T_GLYPHS;
398  } else
399  throw Error();
400 }
401 
402 void
404 {
405  Substitute rs;
406  rs.gid = rg;
407  assign_append(s, t, ls, lt, rs, T_GLYPH);
408 }
409 
412 {
413  Substitution s;
414  assign(s._left, s._left_is, _left, _left_is);
415  assign(s._right, s._right_is, _right, _right_is);
416  assign_append(s._in, s._in_is, _in, _in_is, g);
417  assign_append(s._out, s._out_is, _out, _out_is, g);
418  return s;
419 }
420 
421 void
423 {
424  Substitute ls;
425  ls.gid = g;
427 }
428 
429 void
431 {
432  if (_left_is == T_GLYPH)
433  _left_is = T_NONE;
434  else if (_left_is == T_GLYPHS) {
435  if (_left.gids[0] == 2)
437  else {
438  _left.gids[0]--;
439  memmove(_left.gids + 1, _left.gids + 2, _left.gids[0] * sizeof(Glyph));
440  }
441  }
442 }
443 
444 void
446 {
448 }
449 
450 void
452 {
453  if (_right_is == T_GLYPH)
454  _right_is = T_NONE;
455  else if (_right_is == T_GLYPHS) {
456  if (_right.gids[0] == 2)
458  else
459  _right.gids[0]--;
460  }
461 }
462 
463 bool
464 Substitution::out_alter(const Substitution &o, int pos) noexcept
465 {
466  const Glyph *g = out_glyphptr();
467  int ng = out_nglyphs();
468  const Glyph *out_g = o.out_glyphptr();
469  int out_ng = o.out_nglyphs();
470  int in_ng = o.in_nglyphs();
471  if (pos + in_ng > ng || out_ng == 0)
472  return false;
473 
474  // check that input substitution actually matches us
475  for (int i = 0; i < in_ng; i++)
476  if (!o.in_matches(i, g[pos+i]))
477  return false;
478 
479  // actually change output
480  Vector<Glyph> new_g;
481  for (int i = 0; i < pos; i++)
482  new_g.push_back(g[i]);
483  for (int i = 0; i < out_ng; i++)
484  new_g.push_back(out_g[i]);
485  for (int i = pos + in_ng; i < ng; i++)
486  new_g.push_back(g[i]);
487  assign(_out, _out_is, new_g.size(), &new_g[0]);
488 
489  return true;
490 }
491 
492 static void
493 unparse_glyphid(StringAccum &sa, Glyph gid, const Vector<PermString> *gns) noexcept
494 {
495  if (gid > 0 && gns && gns->size() > gid && (*gns)[gid])
496  sa << (*gns)[gid];
497  else
498  sa << "g" << gid;
499 }
500 
501 void
503 {
504  if (t == T_GLYPH)
505  unparse_glyphid(sa, s.gid, gns);
506  else if (t == T_GLYPHS) {
507  for (int i = 1; i <= s.gids[0]; i++) {
508  if (i != 1)
509  sa << ' ';
510  unparse_glyphid(sa, s.gids[i], gns);
511  }
512  } else if (t == T_COVERAGE)
513  sa << "<coverage>";
514  else
515  sa << "-";
516 }
517 
518 void
520 {
521  if (!*this)
522  sa << "NULL[]";
523  else {
524  if (is_single())
525  sa << "SINGLE[";
526  else if (is_ligature())
527  sa << "LIGATURE[";
528  else if (is_multiple())
529  sa << "MULTIPLE[";
530  else if (is_alternate())
531  sa << "ALTERNATE[";
532  else if (is_simple_context())
533  sa << "SIMPLECONTEXT[";
534  else
535  sa << "UNKNOWN[";
536 
537  if (_left_is != T_NONE) {
538  unparse_glyphids(sa, _left, _left_is, gns);
539  sa << " | ";
540  }
541  unparse_glyphids(sa, _in, _in_is, gns);
542  sa << " => ";
543  unparse_glyphids(sa, _out, _out_is, gns);
544  if (_right_is != T_NONE) {
545  sa << " | ";
546  unparse_glyphids(sa, _right, _right_is, gns);
547  }
548 
549  sa << ']';
550  }
551 }
552 
553 String
555 {
556  StringAccum sa;
557  unparse(sa, gns);
558  return sa.take_string();
559 }
560 
561 
562 
563 /**************************
564  * Gsub *
565  * *
566  **************************/
567 
568 Gsub::Gsub(const Data &d, const Font *otf, ErrorHandler *errh)
569  : _chaincontext_reverse_backtrack(false)
570 {
571  // Fixed Version
572  // Offset ScriptList
573  // Offset FeatureList
574  // Offset LookupList
575  if (d.length() == 0)
576  throw BlankTable("GSUB");
577  if (d.u16(0) != 1)
578  throw Format("GSUB");
579  if (_script_list.assign(d.offset_subtable(4), errh) < 0)
580  throw Format("GSUB script list");
581  if (_feature_list.assign(d.offset_subtable(6), errh) < 0)
582  throw Format("GSUB feature list");
583  _lookup_list = d.offset_subtable(8);
584 
585  if (!otf)
586  return;
587 
588  // Check for "correct" chaining context rules, as suggested by Adobe's
589  // OpenType FDK
590  try {
591  Name nametable(otf->table("name"), ErrorHandler::silent_handler());
593  } catch (Error) {
594  }
595 }
596 
597 int
599 {
600  return _lookup_list.u16(0);
601 }
602 
604 Gsub::lookup(unsigned i) const
605 {
606  if (i >= _lookup_list.u16(0))
607  throw Error("GSUB lookup out of range");
608  else
609  return GsubLookup(_lookup_list.offset_subtable(2 + i*2));
610 }
611 
612 
613 /**************************
614  * GsubLookup *
615  * *
616  **************************/
617 
619  : _d(d)
620 {
621  if (_d.length() < 6)
622  throw Format("GSUB Lookup table");
623  _type = _d.u16(0);
624  if (_type == L_EXTENSION && _d.u16(4) != 0) {
625  Data first_subtable = _d.offset_subtable(HEADERSIZE);
626  if (first_subtable.length() < 8 || first_subtable.u16(0) != 1)
627  throw Format("GSUB Extension Lookup table");
628  _type = first_subtable.u16(2);
629  }
630 }
631 
632 Data
634 {
636  if (_d.u16(0) != L_EXTENSION)
637  return subd;
638  else if (subd.length() >= 8 && subd.u16(0) == 1 && subd.u16(2) == _type)
639  return subd.subtable(subd.u32(4));
640  else
641  return Data();
642 }
643 
644 void
646 {
647  int nlookup = _d.u16(4);
648  switch (_type) {
649  case L_SINGLE:
650  for (int i = 0; i < nlookup; i++) {
651  GsubSingle x(subtable(i)); // this pattern makes gcc-3.3.4 happier
652  x.mark_out_glyphs(gmap);
653  }
654  return;
655  case L_MULTIPLE:
656  for (int i = 0; i < nlookup; i++) {
658  x.mark_out_glyphs(gmap);
659  }
660  return;
661  case L_ALTERNATE:
662  for (int i = 0; i < nlookup; i++) {
664  x.mark_out_glyphs(gmap);
665  }
666  return;
667  case L_LIGATURE:
668  for (int i = 0; i < nlookup; i++) {
670  x.mark_out_glyphs(gmap);
671  }
672  return;
673  case L_CONTEXT:
674  for (int i = 0; i < nlookup; i++) {
676  x.mark_out_glyphs(gsub, gmap);
677  }
678  return;
679  case L_CHAIN:
680  for (int i = 0; i < nlookup; i++) {
682  x.mark_out_glyphs(gsub, gmap);
683  }
684  return;
685  }
686 }
687 
688 bool
690 {
691  int nlookup = _d.u16(4);
692  switch (_type) {
693  case L_SINGLE:
694  for (int i = 0; i < nlookup; i++) {
695  GsubSingle x(subtable(i)); // this pattern makes gcc-3.3.4 happier
696  x.unparse(v, limit);
697  }
698  return true;
699  case L_MULTIPLE:
700  for (int i = 0; i < nlookup; i++) {
702  x.unparse(v);
703  }
704  return true;
705  case L_ALTERNATE:
706  for (int i = 0; i < nlookup; i++) {
708  x.unparse(v, true);
709  }
710  return true;
711  case L_LIGATURE:
712  for (int i = 0; i < nlookup; i++) {
714  x.unparse(v);
715  }
716  return true;
717  case L_CONTEXT: {
718  bool understood = true;
719  for (int i = 0; i < nlookup; i++) {
721  understood &= x.unparse(gsub, v, limit);
722  }
723  return understood;
724  }
725  case L_CHAIN: {
726  bool understood = true;
727  for (int i = 0; i < nlookup; i++) {
729  understood &= x.unparse(gsub, v, limit);
730  }
731  return understood;
732  }
733  default:
734  return false;
735  }
736 }
737 
738 bool
739 GsubLookup::apply(const Glyph *g, int pos, int n, Substitution &s) const
740 {
741  int nlookup = _d.u16(4);
742  switch (_type) {
743  case L_SINGLE:
744  for (int i = 0; i < nlookup; i++) {
746  if (x.apply(g, pos, n, s))
747  return true;
748  }
749  return false;
750  case L_MULTIPLE:
751  for (int i = 0; i < nlookup; i++) {
753  if (x.apply(g, pos, n, s))
754  return true;
755  }
756  return false;
757  case L_ALTERNATE:
758  for (int i = 0; i < nlookup; i++) {
760  if (x.apply(g, pos, n, s, true))
761  return true;
762  }
763  return false;
764  case L_LIGATURE:
765  for (int i = 0; i < nlookup; i++) {
767  if (x.apply(g, pos, n, s))
768  return true;
769  }
770  return false;
771  default: // XXX
772  return false;
773  }
774 }
775 
776 
777 /**************************
778  * GsubSingle *
779  * *
780  **************************/
781 
783  : _d(d)
784 {
785  if (_d[0] != 0
786  || (_d[1] != 1 && _d[1] != 2))
787  throw Format("GSUB Single Substitution");
789  if (!coverage.ok()
790  || (_d[1] == 2 && coverage.size() > _d.u16(4)))
791  throw Format("GSUB Single Substitution coverage");
792 }
793 
794 Coverage
796 {
797  return Coverage(_d.offset_subtable(2), 0, false);
798 }
799 
800 Glyph
802 {
803  int ci = coverage().coverage_index(g);
804  if (ci < 0)
805  return g;
806  else if (_d[1] == 1)
807  return g + _d.s16(4);
808  else
809  return _d.u16(HEADERSIZE + FORMAT2_RECSIZE*ci);
810 }
811 
812 void
814 {
815  if (_d[1] == 1) {
816  int delta = _d.s16(4);
817  for (Coverage::iterator i = coverage().begin(); i; i++)
818  gmap[*i + delta] = true;
819  } else {
820  for (Coverage::iterator i = coverage().begin(); i; i++)
821  gmap[_d.u16(HEADERSIZE + i.coverage_index()*FORMAT2_RECSIZE)] = true;
822  }
823 }
824 
825 void
827 {
828  if (_d[1] == 1) {
829  int delta = _d.s16(4);
830  for (Coverage::iterator it = coverage().begin(); it; ++it)
831  if (limit.covers(*it))
832  v.push_back(Substitution(*it, *it + delta));
833  } else {
834  for (Coverage::iterator it = coverage().begin(); it; ++it)
835  if (limit.covers(*it))
836  v.push_back(Substitution(*it, _d.u16(HEADERSIZE + it.coverage_index()*FORMAT2_RECSIZE)));
837  }
838 }
839 
840 bool
841 GsubSingle::apply(const Glyph *g, int pos, int n, Substitution &s) const
842 {
843  int ci;
844  if (pos < n && (ci = coverage().coverage_index(g[pos])) >= 0) {
845  if (_d[1] == 1)
846  s = Substitution(g[pos], g[pos] + _d.s16(4));
847  else
849  return true;
850  } else
851  return false;
852 }
853 
854 
855 /**************************
856  * GsubMultiple *
857  * *
858  **************************/
859 
861  : _d(d)
862 {
863  if (_d[0] != 0 || _d[1] != 1)
864  throw Format("GSUB Multiple Substitution");
866  if (!coverage.ok()
867  || coverage.size() > _d.u16(4))
868  throw Format("GSUB Multiple Substitution coverage");
869 }
870 
871 Coverage
873 {
874  return Coverage(_d.offset_subtable(2), 0, false);
875 }
876 
877 bool
879 {
880  v.clear();
881  int ci = coverage().coverage_index(g);
882  if (ci < 0) {
883  v.push_back(g);
884  return false;
885  } else {
887  for (int i = 0; i < seq.u16(0); i++)
888  v.push_back(seq.u16(SEQ_HEADERSIZE + i*SEQ_RECSIZE));
889  return true;
890  }
891 }
892 
893 void
895 {
896  for (Coverage::iterator i = coverage().begin(); i; ++i) {
897  Data seq = _d.offset_subtable(HEADERSIZE + i.coverage_index()*RECSIZE);
898  for (int j = 0; j < seq.u16(0); ++j)
899  gmap[seq.u16(SEQ_HEADERSIZE + j*SEQ_RECSIZE)] = true;
900  }
901 }
902 
903 void
904 GsubMultiple::unparse(Vector<Substitution> &v, bool is_alternate) const
905 {
907  for (Coverage::iterator i = coverage().begin(); i; i++) {
908  Data seq = _d.offset_subtable(HEADERSIZE + i.coverage_index()*RECSIZE);
909  result.clear();
910  for (int j = 0; j < seq.u16(0); j++)
911  result.push_back(seq.u16(SEQ_HEADERSIZE + j*SEQ_RECSIZE));
912  v.push_back(Substitution(*i, result, is_alternate));
913  }
914 }
915 
916 bool
917 GsubMultiple::apply(const Glyph *g, int pos, int n, Substitution &s, bool is_alternate) const
918 {
919  int ci;
920  if (pos < n && (ci = coverage().coverage_index(g[pos])) >= 0) {
923  for (int j = 0; j < seq.u16(0); j++)
924  result.push_back(seq.u16(SEQ_HEADERSIZE + j*SEQ_RECSIZE));
925  s = Substitution(g[pos], result, is_alternate);
926  return true;
927  } else
928  return false;
929 }
930 
931 
932 /**************************
933  * GsubLigature *
934  * *
935  **************************/
936 
938  : _d(d)
939 {
940  if (_d[0] != 0
941  || _d[1] != 1)
942  throw Format("GSUB Ligature Substitution");
944  if (!coverage.ok()
945  || coverage.size() > _d.u16(4))
946  throw Format("GSUB Ligature Substitution coverage");
947 }
948 
949 Coverage
951 {
952  return Coverage(_d.offset_subtable(2), 0, false);
953 }
954 
955 bool
956 GsubLigature::map(const Vector<Glyph> &gs, Glyph &result, int &consumed) const
957 {
958  assert(gs.size() > 0);
959  result = gs[0];
960  consumed = 1;
961  int ci = coverage().coverage_index(gs[0]);
962  if (ci < 0)
963  return false;
964  Data ligset = _d.offset_subtable(HEADERSIZE + ci*RECSIZE);
965  int nligset = ligset.u16(0);
966  for (int i = 0; i < nligset; i++) {
968  int nlig = lig.u16(2);
969  if (nlig > gs.size() - 1)
970  goto bad;
971  for (int j = 0; j < nlig - 1; j++)
972  if (lig.u16(LIG_HEADERSIZE + j*LIG_RECSIZE) != gs[j + 1])
973  goto bad;
974  result = lig.u16(0);
975  consumed = nlig + 1;
976  return true;
977  bad: ;
978  }
979  return false;
980 }
981 
982 void
984 {
985  for (Coverage::iterator i = coverage().begin(); i; i++) {
986  Data ligset = _d.offset_subtable(HEADERSIZE + i.coverage_index()*RECSIZE);
987  int nligset = ligset.u16(0);
988  Vector<Glyph> components(1, *i);
989  for (int j = 0; j < nligset; j++) {
991  gmap[lig.u16(0)] = true;
992  }
993  }
994 }
995 
996 void
998 {
999  for (Coverage::iterator i = coverage().begin(); i; i++) {
1000  Data ligset = _d.offset_subtable(HEADERSIZE + i.coverage_index()*RECSIZE);
1001  int nligset = ligset.u16(0);
1002  Vector<Glyph> components(1, *i);
1003  for (int j = 0; j < nligset; j++) {
1005  int nlig = lig.u16(2);
1006  components.resize(1);
1007  for (int k = 0; k < nlig - 1; k++)
1008  components.push_back(lig.u16(LIG_HEADERSIZE + k*LIG_RECSIZE));
1009  v.push_back(Substitution(components, lig.u16(0)));
1010  }
1011  }
1012 }
1013 
1014 bool
1015 GsubLigature::apply(const Glyph *g, int pos, int n, Substitution &s) const
1016 {
1017  int ci;
1018  if (pos < n && (ci = coverage().coverage_index(g[pos])) >= 0) {
1019  Data ligset = _d.offset_subtable(HEADERSIZE + ci*RECSIZE);
1020  int nligset = ligset.u16(0);
1021  for (int j = 0; j < nligset; j++) {
1023  int nlig = lig.u16(2);
1024  if (pos + nlig <= n) {
1025  for (int k = 0; k < nlig - 1; k++)
1026  if (lig.u16(LIG_HEADERSIZE + k*LIG_RECSIZE) != g[pos + k + 1])
1027  goto ligature_failed;
1028  s = Substitution(nlig, &g[pos], lig.u16(0));
1029  return true;
1030  }
1031  ligature_failed: ;
1032  }
1033  }
1034  return false;
1035 }
1036 
1037 
1038 /**************************
1039  * GsubContext *
1040  * *
1041  **************************/
1042 
1044  : _d(d)
1045 {
1046  switch (_d.u16(0)) {
1047  case 1:
1048  case 2:
1049  break;
1050  case 3: {
1051  int ninput = _d.u16(2);
1052  if (ninput < 1)
1053  throw Format("GSUB Context Substitution input sequence");
1055  if (!coverage.ok())
1056  throw Format("GSUB Context Substitution coverage");
1057  break;
1058  }
1059  default:
1060  throw Format("GSUB Context Substitution");
1061  }
1062 }
1063 
1064 Coverage
1066 {
1067  if (_d[1] == 3)
1068  return Coverage(_d.offset_subtable(F3_HSIZE), 0, false);
1069  else
1070  return Coverage();
1071 }
1072 
1073 void
1075  int subtab_offset, const Gsub &gsub,
1076  Vector<bool> &gmap)
1077 {
1078  for (int j = 0; j < nsub; ++j) {
1079  int lookup_index = data.u16(subtab_offset + SUBRECSIZE*j + 2);
1080  gsub.lookup(lookup_index).mark_out_glyphs(gsub, gmap);
1081  }
1082 }
1083 
1084 void
1086 {
1087  if (_d.u16(0) != 3) // XXX
1088  return;
1089  int nglyph = _d.u16(2);
1090  int nsubst = _d.u16(4);
1091  subruleset_mark_out_glyphs(_d, nsubst, F3_HSIZE + nglyph*2, gsub, gmap);
1092 }
1093 
1094 bool
1096  int nsub, int subtab_offset,
1097  const Gsub& gsub, Vector<Substitution>& outsubs,
1098  Substitution s) {
1099  Substitution subtab_sub;
1100  int napplied = 0;
1101  for (int j = 0; j < nsub; j++) {
1102  int seq_index = data.u16(subtab_offset + SUBRECSIZE*j);
1103  int lookup_index = data.u16(subtab_offset + SUBRECSIZE*j + 2);
1104  // XXX check seq_index against size of output glyphs?
1105  if (gsub.lookup(lookup_index).apply(s.out_glyphptr(), seq_index, s.out_nglyphs(), subtab_sub)) {
1106  napplied++;
1107  s.out_alter(subtab_sub, seq_index);
1108  }
1109  }
1110  outsubs.push_back(s);
1111  return true;
1112 }
1113 
1114 bool
1116  int nglyph, int glyphtab_offset, const Coverage &limit,
1117  int nsub, int subtab_offset,
1118  const Gsub &gsub, Vector<Substitution> &outsubs,
1119  const Substitution &prototype_sub)
1120 {
1122  subs.push_back(prototype_sub);
1123  Vector<Substitution> work_subs;
1124 
1125  // get array of possible substitutions including contexts
1126  for (int i = 0; i < nglyph; i++) {
1127  assert(!work_subs.size());
1128  Coverage c(data.offset_subtable(glyphtab_offset + i*2));
1129  for (Coverage::iterator ci = (c & limit).begin(); ci; ci++)
1130  for (int j = 0; j < subs.size(); j++)
1131  work_subs.push_back(subs[j].in_out_append_glyph(*ci));
1132  subs.clear();
1133  subs.swap(work_subs);
1134  }
1135 
1136  // now, apply referred lookups to the resulting substitution array
1137  Substitution subtab_sub;
1138  for (int i = 0; i < subs.size(); i++) {
1139  Substitution &s = subs[i];
1140  int napplied = 0;
1141  for (int j = 0; j < nsub; j++) {
1142  int seq_index = data.u16(subtab_offset + SUBRECSIZE*j);
1143  int lookup_index = data.u16(subtab_offset + SUBRECSIZE*j + 2);
1144  // XXX check seq_index against size of output glyphs?
1145  if (gsub.lookup(lookup_index).apply(s.out_glyphptr(), seq_index, s.out_nglyphs(), subtab_sub)) {
1146  napplied++;
1147  s.out_alter(subtab_sub, seq_index);
1148  }
1149  }
1150  // 26.Jun.2003 -- always push substitution back, since the no-op might
1151  // override a following substitution
1152  outsubs.push_back(s);
1153  }
1154 
1155  return true; // XXX
1156 }
1157 
1158 bool
1160 {
1161  if (_d.u16(0) != 3) // XXX
1162  return false;
1163  int nglyph = _d.u16(2);
1164  int nsubst = _d.u16(4);
1165  return f3_unparse(_d, nglyph, F3_HSIZE, limit, nsubst, F3_HSIZE + nglyph*2, gsub, v, Substitution());
1166 }
1167 
1168 
1169 /**************************
1170  * GsubChainContext *
1171  * *
1172  **************************/
1173 
1175  : _d(d)
1176 {
1177  switch (_d.u16(0)) {
1178  case 1: {
1180  if (!coverage.ok()
1181  || coverage.size() != _d.u16(4))
1182  throw Format("ChainContext Substitution coverage");
1183  break;
1184  }
1185  case 2:
1186  break;
1187  case 3: {
1188  int nbacktrack = _d.u16(2);
1189  int input_offset = F3_HSIZE + nbacktrack*2;
1190  int ninput = _d.u16(input_offset);
1191  if (ninput < 1)
1192  throw Format("GSUB ChainContext Substitution input sequence");
1194  if (!coverage.ok())
1195  throw Format("GSUB ChainContext Substitution coverage");
1196  break;
1197  }
1198  default:
1199  throw Format("GSUB ChainContext Substitution");
1200  }
1201 }
1202 
1203 Coverage
1205 {
1206  switch (_d.u16(0)) {
1207  case 1:
1208  return Coverage(_d.offset_subtable(2), 0, false);
1209  case 3: {
1210  int nbacktrack = _d.u16(2);
1211  int input_offset = F3_HSIZE + nbacktrack*2;
1212  return Coverage(_d.offset_subtable(input_offset + F3_INPUT_HSIZE), 0, false);
1213  }
1214  default:
1215  return Coverage();
1216  }
1217 }
1218 
1219 void
1221 {
1222  switch (_d.u16(0)) {
1223  case 1: {
1224  int nsubruleset = _d.u16(4);
1225  for (int i = 0; i != nsubruleset; ++i) {
1226  int srs_offset = _d.u16(6 + i*2);
1227  int nsubrule = _d.u16(srs_offset);
1228  for (int j = 0; j != nsubrule; ++j) {
1229  int subrule_offset = srs_offset + _d.u16(srs_offset + 2 + j*2);
1230  int nbacktrack = _d.u16(subrule_offset);
1231  int input_offset = subrule_offset + 2 + nbacktrack*2;
1232  int ninput = _d.u16(input_offset);
1233  int lookahead_offset = input_offset + 2 + (ninput-1)*2;
1234  int nlookahead = _d.u16(lookahead_offset);
1235  int subst_offset = lookahead_offset + 2 + nlookahead*2;
1236  int nsubst = _d.u16(subst_offset);
1237 
1238  GsubContext::subruleset_mark_out_glyphs(_d, nsubst, subst_offset + 2, gsub, gmap);
1239  }
1240  }
1241  break;
1242  }
1243  case 3: {
1244  int nbacktrack = _d.u16(2);
1245  int input_offset = F3_HSIZE + nbacktrack*2;
1246  int ninput = _d.u16(input_offset);
1247  int lookahead_offset = input_offset + F3_INPUT_HSIZE + ninput*2;
1248  int nlookahead = _d.u16(lookahead_offset);
1249  int subst_offset = lookahead_offset + F3_LOOKAHEAD_HSIZE + nlookahead*2;
1250  int nsubst = _d.u16(subst_offset);
1251 
1252  GsubContext::subruleset_mark_out_glyphs(_d, nsubst, subst_offset + F3_SUBST_HSIZE, gsub, gmap);
1253  break;
1254  }
1255  default:
1256  return;
1257  }
1258 }
1259 
1260 bool
1262 {
1263  Coverage input0_coverage(_d.offset_subtable(2), 0, false);
1264  Coverage::iterator i0iter = input0_coverage.begin();
1265 
1266  for (int i0index = 0; i0index != input0_coverage.size();
1267  ++i0index, ++i0iter) {
1268  int srs_offset = _d.u16(6 + i0index*2);
1269  int nsubrule = _d.u16(srs_offset);
1270  for (int srindex = 0; srindex != nsubrule; ++srindex) {
1271  int sr_offset = srs_offset + _d.u16(srs_offset + 2 + srindex*2);
1272  int nbacktrack = _d.u16(sr_offset);
1273  int input_offset = sr_offset + 2 + nbacktrack*2;
1274  int ninput = _d.u16(input_offset);
1275  int lookahead_offset = input_offset + 2 + (ninput-1)*2;
1276  int nlookahead = _d.u16(lookahead_offset);
1277  int subst_offset = lookahead_offset + 2 + nlookahead*2;
1278  int nsubst = _d.u16(subst_offset);
1279  int subtab_offset = subst_offset + 2;
1280 
1281  Substitution s(nbacktrack, ninput, ninput, nlookahead);
1282  if (gsub.chaincontext_reverse_backtrack()) {
1283  for (int i = 0; i != nbacktrack; ++i)
1284  s.left_glyphptr()[i] = _d.u16(sr_offset + 2 + i*2);
1285  } else {
1286  for (int i = nbacktrack - 1; i != -1; --i)
1287  s.left_glyphptr()[nbacktrack - 1 - i] = _d.u16(sr_offset + 2 + i*2);
1288  }
1289  Glyph* in_begin = s.in_glyphptr();
1290  Glyph* out_begin = s.out_glyphptr();
1291  in_begin[0] = out_begin[0] = *i0iter;
1292  for (int i = 1; i != ninput; ++i)
1293  in_begin[i] = out_begin[i] = _d.u16(input_offset + 2 + (i-1)*2);
1294  for (int i = 0; i != ninput; ++i)
1295  if (!limit.covers(in_begin[i]))
1296  goto skip;
1297  for (int i = 0; i != nlookahead; ++i)
1298  s.right_glyphptr()[i] = _d.u16(lookahead_offset + 2 + i*2);
1299 
1300  // now, apply referred lookups to the resulting substitution array
1301  GsubContext::f1_unparse(_d, nsubst, subtab_offset, gsub, v, s);
1302  skip: ;
1303  }
1304  }
1305 
1306  return true;
1307 }
1308 
1309 bool
1311 {
1312  int nbacktrack = _d.u16(2);
1313  int input_offset = F3_HSIZE + nbacktrack*2;
1314  int ninput = _d.u16(input_offset);
1315  int lookahead_offset = input_offset + F3_INPUT_HSIZE + ninput*2;
1316  int nlookahead = _d.u16(lookahead_offset);
1317  int subst_offset = lookahead_offset + F3_LOOKAHEAD_HSIZE + nlookahead*2;
1318  int nsubst = _d.u16(subst_offset);
1319 
1320  Vector<Coverage> backtrackc;
1321  Vector<Coverage> lookaheadc;
1322  if (gsub.chaincontext_reverse_backtrack()) {
1323  for (int i = 0; i < nbacktrack; i++)
1324  backtrackc.push_back(Coverage(_d.offset_subtable(F3_HSIZE + i*2)) & limit);
1325  } else {
1326  for (int i = nbacktrack - 1; i >= 0; i--)
1327  backtrackc.push_back(Coverage(_d.offset_subtable(F3_HSIZE + i*2)) & limit);
1328  }
1329  for (int i = 0; i < nlookahead; i++)
1330  lookaheadc.push_back(Coverage(_d.offset_subtable(lookahead_offset + F3_LOOKAHEAD_HSIZE + i*2)) & limit);
1331 
1332  // give up if would generate too many substitutions
1333  double n = 1;
1334  for (int i = 0; i < nbacktrack; ++i)
1335  n *= backtrackc[i].size();
1336  for (int i = 0; i < nlookahead; ++i)
1337  n *= lookaheadc[i].size();
1338  for (int i = 0; i < ninput; ++i)
1339  n *= (Coverage(_d.offset_subtable(input_offset + F3_INPUT_HSIZE + i*2)) & limit).size();
1340  if (n > 1000000) // arbitrary cutoff
1341  return false;
1342 
1343  Vector<Coverage::iterator> backtracki;
1344  Vector<Coverage::iterator> lookaheadi;
1345  for (int i = 0; i < nbacktrack; i++)
1346  backtracki.push_back(backtrackc[i].begin());
1347  for (int i = 0; i < nlookahead; i++)
1348  lookaheadi.push_back(lookaheadc[i].begin());
1349 
1350  bool any = false;
1351 
1352  while (1) {
1353 
1354  // run GsubContext
1355  Substitution s(nbacktrack, 0, 0, nlookahead);
1356  Glyph *left_begin = s.left_glyphptr();
1357  for (int i = 0; i < nbacktrack; i++)
1358  left_begin[i] = *backtracki[i];
1359  Glyph *right_begin = s.right_glyphptr();
1360  for (int i = 0; i < nlookahead; i++)
1361  right_begin[i] = *lookaheadi[i];
1362 
1363  any |= GsubContext::f3_unparse(_d, ninput, input_offset + F3_INPUT_HSIZE, limit, nsubst, subst_offset + F3_SUBST_HSIZE, gsub, v, s);
1364 
1365  // step iterators
1366  for (int i = nlookahead - 1; i >= 0; i--) {
1367  lookaheadi[i]++;
1368  if (lookaheadi[i])
1369  goto next;
1370  lookaheadi[i] = lookaheadc[i].begin();
1371  }
1372  for (int i = nbacktrack - 1; i >= 0; i--) {
1373  backtracki[i]++;
1374  if (backtracki[i])
1375  goto next;
1376  backtracki[i] = backtrackc[i].begin();
1377  }
1378  break;
1379 
1380  next: ;
1381  }
1382 
1383  return any;
1384 }
1385 
1386 bool
1388 {
1389  if (_d.u16(0) == 1)
1390  return f1_unparse(gsub, v, limit);
1391  else if (_d.u16(0) == 3)
1392  return f3_unparse(gsub, v, limit);
1393  else
1394  return false;
1395 }
1396 
1397 
1398 }}
int nl
Definition: afm2tfm.c:885
#define next(a)
Definition: aptex-macros.h:924
static char gmap[128]
Definition: asciitopgm.c:19
int size() const noexcept
Definition: otf.cc:847
iterator begin() const
Definition: otf.hh:195
int coverage_index(Glyph) const noexcept
Definition: otf.cc:864
Data offset_subtable(unsigned offset_offset) const
Definition: otfdata.cc:32
static uint16_t u16(const unsigned char *s)
Definition: otfdata.hh:116
Data subtable(unsigned offset) const
Definition: otfdata.cc:24
static int16_t s16(const unsigned char *s)
Definition: otfdata.hh:125
static uint32_t u32(const unsigned char *s)
Definition: otfdata.hh:134
int length() const
Definition: otfdata.hh:73
int assign(const String &, ErrorHandler *=0)
Definition: otf.cc:511
String table(Tag tag) const
Definition: otf.cc:121
bool covers(Glyph g) const
Definition: otf.hh:355
Coverage coverage() const noexcept
Definition: otfgsub.cc:1204
bool f1_unparse(const Gsub &gsub, Vector< Substitution > &subs, const Coverage &limit) const
Definition: otfgsub.cc:1261
void mark_out_glyphs(const Gsub &gsub, Vector< bool > &gmap) const
Definition: otfgsub.cc:1220
bool unparse(const Gsub &gsub, Vector< Substitution > &subs, const Coverage &limit) const
Definition: otfgsub.cc:1387
bool f3_unparse(const Gsub &gsub, Vector< Substitution > &subs, const Coverage &limit) const
Definition: otfgsub.cc:1310
Coverage coverage() const noexcept
Definition: otfgsub.cc:1065
static bool f3_unparse(const Data &data, int nglyph, int glyphtab_offset, const Coverage &limit, int nsub, int subtab_offset, const Gsub &gsub, Vector< Substitution > &outsubs, const Substitution &prototype_sub)
Definition: otfgsub.cc:1115
static void subruleset_mark_out_glyphs(const Data &data, int nsub, int subtab_offset, const Gsub &gsub, Vector< bool > &gmap)
Definition: otfgsub.cc:1074
bool unparse(const Gsub &gsub, Vector< Substitution > &out_subs, const Coverage &limit) const
Definition: otfgsub.cc:1159
static bool f1_unparse(const Data &data, int nsub, int subtab_offset, const Gsub &gsub, Vector< Substitution > &outsubs, Substitution prototype_sub)
Definition: otfgsub.cc:1095
void mark_out_glyphs(const Gsub &gsub, Vector< bool > &gmap) const
Definition: otfgsub.cc:1085
void mark_out_glyphs(Vector< bool > &gmap) const
Definition: otfgsub.cc:983
bool map(const Vector< Glyph > &, Glyph &, int &) const
Definition: otfgsub.cc:956
GsubLigature(const Data &)
Definition: otfgsub.cc:937
void unparse(Vector< Substitution > &) const
Definition: otfgsub.cc:997
bool apply(const Glyph *, int pos, int n, Substitution &) const
Definition: otfgsub.cc:1015
Coverage coverage() const noexcept
Definition: otfgsub.cc:950
bool unparse_automatics(const Gsub &gsub, Vector< Substitution > &subs, const Coverage &limit) const
Definition: otfgsub.cc:689
GsubLookup(const Data &)
Definition: otfgsub.cc:618
Data subtable(int i) const
Definition: otfgsub.cc:633
void mark_out_glyphs(const Gsub &gsub, Vector< bool > &gmap) const
Definition: otfgsub.cc:645
bool apply(const Glyph *, int pos, int n, Substitution &) const
Definition: otfgsub.cc:739
Coverage coverage() const noexcept
Definition: otfgsub.cc:872
GsubMultiple(const Data &)
Definition: otfgsub.cc:860
bool apply(const Glyph *, int pos, int n, Substitution &, bool alternate=false) const
Definition: otfgsub.cc:917
bool map(Glyph, Vector< Glyph > &) const
Definition: otfgsub.cc:878
void unparse(Vector< Substitution > &, bool alternate=false) const
Definition: otfgsub.cc:904
void mark_out_glyphs(Vector< bool > &gmap) const
Definition: otfgsub.cc:894
GsubSingle(const Data &)
Definition: otfgsub.cc:782
Coverage coverage() const noexcept
Definition: otfgsub.cc:795
bool apply(const Glyph *, int pos, int n, Substitution &) const
Definition: otfgsub.cc:841
void mark_out_glyphs(Vector< bool > &gmap) const
Definition: otfgsub.cc:813
Glyph map(Glyph) const
Definition: otfgsub.cc:801
void unparse(Vector< Substitution > &subs, const Coverage &limit) const
Definition: otfgsub.cc:826
bool _chaincontext_reverse_backtrack
Definition: otfgsub.hh:29
int nlookups() const
Definition: otfgsub.cc:598
bool chaincontext_reverse_backtrack() const
Definition: otfgsub.hh:17
FeatureList _feature_list
Definition: otfgsub.hh:27
Gsub(const Data &, const Font *, ErrorHandler *=0)
Definition: otfgsub.cc:568
GsubLookup lookup(unsigned) const
Definition: otfgsub.cc:604
ScriptList _script_list
Definition: otfgsub.hh:26
bool version_chaincontext_reverse_backtrack() const
Definition: otfname.cc:162
int assign(const String &, ErrorHandler *=0)
Definition: otf.cc:366
static bool substitute_in(const Substitute &, uint8_t, const Coverage &)
Definition: otfgsub.cc:197
static void assign_append(Substitute &, uint8_t &, const Substitute &, uint8_t, const Substitute &, uint8_t)
Definition: otfgsub.cc:382
static Glyph extract_glyph(const Substitute &, uint8_t) noexcept
Definition: otfgsub.cc:258
Substitution & operator=(const Substitution &)
Definition: otfgsub.cc:186
static bool matches(const Substitute &, uint8_t, int pos, Glyph) noexcept
Definition: otfgsub.cc:333
bool all_out_glyphs(Vector< Glyph > &gs) const
Definition: otfgsub.cc:370
static Glyph * extract_glyphptr(const Substitute &, uint8_t) noexcept
Definition: otfgsub.cc:305
bool is_simple_context() const
Definition: otfgsub.hh:293
static void unparse_glyphids(StringAccum &, const Substitute &, uint8_t, const Vector< PermString > *) noexcept
Definition: otfgsub.cc:502
static void assign_space(Substitute &, uint8_t &, int)
Definition: otfgsub.cc:45
static bool extract_glyphs(const Substitute &, uint8_t, Vector< Glyph > &, bool coverage_ok) noexcept
Definition: otfgsub.cc:282
bool all_in_glyphs(Vector< Glyph > &gs) const
Definition: otfgsub.cc:357
static int extract_nglyphs(const Substitute &, uint8_t, bool coverage_ok) noexcept
Definition: otfgsub.cc:318
bool out_alter(const Substitution &, int) noexcept
Definition: otfgsub.cc:464
bool context_in(const Coverage &) const
Definition: otfgsub.cc:242
static void clear(Substitute &, uint8_t &)
Definition: otfgsub.cc:31
static void assign(Substitute &, uint8_t &, Glyph)
Definition: otfgsub.cc:58
Substitution in_out_append_glyph(Glyph) const
Definition: otfgsub.cc:411
void unparse(StringAccum &, const Vector< PermString > *=&debug_glyph_names) const
Definition: otfgsub.cc:519
Error reporting class.
Definition: error.hh:86
static ErrorHandler * silent_handler()
Return the global silent ErrorHandler.
Definition: error.hh:167
Efficiently build up Strings from pieces.
Definition: straccum.hh:21
String take_string()
Return a String object with this StringAccum's contents.
Definition: straccum.cc:197
Definition: vector.hh:17
void clear()
Definition: vector.hh:87
iterator begin()
Definition: vector.hh:48
void push_back(const T &x)
Definition: vector.hh:102
void resize(size_type nn, const T &e=T())
Definition: vector.cc:166
size_type size() const
Definition: vector.hh:54
#define n
Definition: t4ht.c:1290
int v
Definition: dviconv.c:10
#define skip(p, c)
Definition: ptexmac.h:70
struct rect data
Definition: dvipdfm.c:64
Flexible error handling classes.
int ot
Definition: fcweight.c:26
Integer_T bad
#define s
Definition: afcover.h:80
static FIELD_PTR begin
Definition: genind.c:37
short nleft
Definition: globals.h:117
#define c(n)
Definition: gpos-common.c:150
#define d(n)
Definition: gpos-common.c:151
#define memcmp(s1, s2, n)
Definition: gsftopk.c:66
#define memmove(d, s, n)
Definition: gsftopk.c:65
#define memcpy(d, s, n)
Definition: gsftopk.c:64
FILE * out
Definition: hbf2gf.c:286
@ T_NONE
Definition: hpcdtoppm.c:92
assert(pcxLoadImage24((char *)((void *) 0), fp, pinfo, hdr))
small capitals from c petite p scientific i
Definition: afcover.h:80
#define const
Definition: ftzconf.h:91
#define false
Definition: ftrandom.c:52
unsigned char uint8_t
Definition: stdint.h:78
#define Error
Definition: type1.c:126
#define Coverage
Definition: aliases.h:58
const int * pos
Definition: combiners.h:905
int Glyph
Definition: otf.hh:9
static void unparse_glyphid(StringAccum &sa, Glyph gid, const Vector< PermString > *gns)
Definition: otfgpos.cc:252
float x
Definition: cordic.py:15
int k
Definition: otp-parser.c:70
static int delta
Definition: pbmtolj.c:36
static int size
Definition: ppmlabel.c:24
int g
Definition: ppmqvga.c:68
static ErrorHandler * errh
Definition: main.cc:71
#define subs(p, n, t)
Definition: interp.c:107
static FILE * in
Definition: squeeze.c:36
Click's StringAccum class, used to construct Strings efficiently from pieces.
A string of characters.
Definition: t1part.c:49
Definition: tfm.c:163
Definition: afm2pl.c:139
Definition: dvips.h:235
int j
Definition: t4ht.c:1589
#define limit(x)
Definition: yuvsplittoppm.c:26