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)  

Pass.cpp
Go to the documentation of this file.
1 /* GRAPHITE2 LICENSING
2 
3  Copyright 2010, SIL International
4  All rights reserved.
5 
6  This library is free software; you can redistribute it and/or modify
7  it under the terms of the GNU Lesser General Public License as published
8  by the Free Software Foundation; either version 2.1 of License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Lesser General Public License for more details.
15 
16  You should also have received a copy of the GNU Lesser General Public
17  License along with this library in the file named "LICENSE".
18  If not, write to the Free Software Foundation, 51 Franklin Street,
19  Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
20  internet at http://www.fsf.org/licenses/lgpl.html.
21 
22 Alternatively, the contents of this file may be used under the terms of the
23 Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
24 License, as published by the Free Software Foundation, either version 2
25 of the License or (at your option) any later version.
26 */
27 #include "inc/Main.h"
28 #include "inc/debug.h"
29 #include "inc/Endian.h"
30 #include "inc/Pass.h"
31 #include <cstring>
32 #include <cstdlib>
33 #include <cassert>
34 #include <cmath>
35 #include "inc/Segment.h"
36 #include "inc/Code.h"
37 #include "inc/Rule.h"
38 #include "inc/Error.h"
39 #include "inc/Collider.h"
40 
41 using namespace graphite2;
42 using vm::Machine;
44 
46 {
47  None = 0,
49  InWord = 2,
50  reserved = 3
51 };
52 
54 : m_silf(0),
55  m_cols(0),
56  m_rules(0),
57  m_ruleMap(0),
58  m_startStates(0),
59  m_transitions(0),
60  m_states(0),
61  m_codes(0),
62  m_progs(0),
63  m_numCollRuns(0),
64  m_kernColls(0),
65  m_iMaxLoop(0),
66  m_numGlyphs(0),
67  m_numRules(0),
68  m_numStates(0),
69  m_numTransition(0),
70  m_numSuccess(0),
71  m_successStart(0),
72  m_numColumns(0),
73  m_minPreCtxt(0),
74  m_maxPreCtxt(0),
75  m_colThreshold(0),
76  m_isReverseDir(false)
77 {
78 }
79 
81 {
82  free(m_cols);
85  free(m_states);
86  free(m_ruleMap);
87 
88  if (m_rules) delete [] m_rules;
89  if (m_codes) delete [] m_codes;
90  free(m_progs);
91 }
92 
93 bool Pass::readPass(const byte * const pass_start, size_t pass_length, size_t subtable_base,
95 {
96  const byte * p = pass_start,
97  * const pass_end = p + pass_length;
98  size_t numRanges;
99 
100  if (e.test(pass_length < 40, E_BADPASSLENGTH)) return face.error(e);
101  // Read in basic values
102  const byte flags = be::read<byte>(p);
103  if (e.test((flags & 0x1f) &&
104  (pt < PASS_TYPE_POSITIONING || !m_silf->aCollision() || !face.glyphs().hasBoxes() || !(m_silf->flags() & 0x20)),
106  return face.error(e);
107  m_numCollRuns = flags & 0x7;
108  m_kernColls = (flags >> 3) & 0x3;
109  m_isReverseDir = (flags >> 5) & 0x1;
110  m_iMaxLoop = be::read<byte>(p);
111  if (m_iMaxLoop < 1) m_iMaxLoop = 1;
112  be::skip<byte>(p,2); // skip maxContext & maxBackup
113  m_numRules = be::read<uint16>(p);
114  if (e.test(!m_numRules && m_numCollRuns == 0, E_BADEMPTYPASS)) return face.error(e);
115  be::skip<uint16>(p); // fsmOffset - not sure why we would want this
116  const byte * const pcCode = pass_start + be::read<uint32>(p) - subtable_base,
117  * const rcCode = pass_start + be::read<uint32>(p) - subtable_base,
118  * const aCode = pass_start + be::read<uint32>(p) - subtable_base;
119  be::skip<uint32>(p);
120  m_numStates = be::read<uint16>(p);
121  m_numTransition = be::read<uint16>(p);
122  m_numSuccess = be::read<uint16>(p);
123  m_numColumns = be::read<uint16>(p);
124  numRanges = be::read<uint16>(p);
125  be::skip<uint16>(p, 3); // skip searchRange, entrySelector & rangeShift.
126  assert(p - pass_start == 40);
127  // Perform some sanity checks.
131  || e.test(m_numRules && numRanges == 0, E_NORANGES)
132  || e.test(m_numColumns > 0x7FFF, E_BADNUMCOLUMNS))
133  return face.error(e);
134 
136  // test for beyond end - 1 to account for reading uint16
137  if (e.test(p + numRanges * 6 - 2 > pass_end, E_BADPASSLENGTH)) return face.error(e);
138  m_numGlyphs = be::peek<uint16>(p + numRanges * 6 - 4) + 1;
139  // Calculate the start of various arrays.
140  const byte * const ranges = p;
141  be::skip<uint16>(p, numRanges*3);
142  const byte * const o_rule_map = p;
143  be::skip<uint16>(p, m_numSuccess + 1);
144 
145  // More sanity checks
146  if (e.test(reinterpret_cast<const byte *>(o_rule_map + m_numSuccess*sizeof(uint16)) > pass_end
147  || p > pass_end, E_BADRULEMAPLEN))
148  return face.error(e);
149  const size_t numEntries = be::peek<uint16>(o_rule_map + m_numSuccess*sizeof(uint16));
150  const byte * const rule_map = p;
151  be::skip<uint16>(p, numEntries);
152 
153  if (e.test(p + 2*sizeof(uint8) > pass_end, E_BADPASSLENGTH)) return face.error(e);
154  m_minPreCtxt = be::read<uint8>(p);
155  m_maxPreCtxt = be::read<uint8>(p);
156  if (e.test(m_minPreCtxt > m_maxPreCtxt, E_BADCTXTLENBOUNDS)) return face.error(e);
157  const byte * const start_states = p;
158  be::skip<int16>(p, m_maxPreCtxt - m_minPreCtxt + 1);
159  const uint16 * const sort_keys = reinterpret_cast<const uint16 *>(p);
160  be::skip<uint16>(p, m_numRules);
161  const byte * const precontext = p;
162  be::skip<byte>(p, m_numRules);
163 
164  if (e.test(p + sizeof(uint16) + sizeof(uint8) > pass_end, E_BADCTXTLENS)) return face.error(e);
165  m_colThreshold = be::read<uint8>(p);
166  if (m_colThreshold == 0) m_colThreshold = 10; // A default
167  const size_t pass_constraint_len = be::read<uint16>(p);
168 
169  const uint16 * const o_constraint = reinterpret_cast<const uint16 *>(p);
170  be::skip<uint16>(p, m_numRules + 1);
171  const uint16 * const o_actions = reinterpret_cast<const uint16 *>(p);
172  be::skip<uint16>(p, m_numRules + 1);
173  const byte * const states = p;
174  if (e.test(2u*m_numTransition*m_numColumns >= (unsigned)(pass_end - p), E_BADPASSLENGTH)
175  || e.test(p >= pass_end, E_BADPASSLENGTH))
176  return face.error(e);
177  be::skip<int16>(p, m_numTransition*m_numColumns);
178  be::skip<uint8>(p);
179  if (e.test(p != pcCode, E_BADPASSCCODEPTR)) return face.error(e);
180  be::skip<byte>(p, pass_constraint_len);
181  if (e.test(p != rcCode, E_BADRULECCODEPTR)
182  || e.test(size_t(rcCode - pcCode) != pass_constraint_len, E_BADCCODELEN)) return face.error(e);
183  be::skip<byte>(p, be::peek<uint16>(o_constraint + m_numRules));
184  if (e.test(p != aCode, E_BADACTIONCODEPTR)) return face.error(e);
185  be::skip<byte>(p, be::peek<uint16>(o_actions + m_numRules));
186 
187  // We should be at the end or within the pass
188  if (e.test(p > pass_end, E_BADPASSLENGTH)) return face.error(e);
189 
190  // Load the pass constraint if there is one.
191  if (pass_constraint_len)
192  {
193  face.error_context(face.error_context() + 1);
194  m_cPConstraint = vm::Machine::Code(true, pcCode, pcCode + pass_constraint_len,
195  precontext[0], be::peek<uint16>(sort_keys), *m_silf, face, PASS_TYPE_UNKNOWN);
196  if (e.test(!m_cPConstraint, E_OUTOFMEM)
197  || e.test(m_cPConstraint.status() != Code::loaded, m_cPConstraint.status() + E_CODEFAILURE))
198  return face.error(e);
199  face.error_context(face.error_context() - 1);
200  }
201  if (m_numRules)
202  {
203  if (!readRanges(ranges, numRanges, e)) return face.error(e);
204  if (!readRules(rule_map, numEntries, precontext, sort_keys,
205  o_constraint, rcCode, o_actions, aCode, face, pt, e)) return false;
206  }
207 #ifdef GRAPHITE2_TELEMETRY
208  telemetry::category _states_cat(face.tele.states);
209 #endif
210  return m_numRules ? readStates(start_states, states, o_rule_map, face, e) : true;
211 }
212 
213 
214 bool Pass::readRules(const byte * rule_map, const size_t num_entries,
215  const byte *precontext, const uint16 * sort_key,
216  const uint16 * o_constraint, const byte *rc_data,
217  const uint16 * o_action, const byte * ac_data,
218  Face & face, passtype pt, Error &e)
219 {
220  const byte * const ac_data_end = ac_data + be::peek<uint16>(o_action + m_numRules);
221  const byte * const rc_data_end = rc_data + be::peek<uint16>(o_constraint + m_numRules);
222 
223  precontext += m_numRules;
224  sort_key += m_numRules;
225  o_constraint += m_numRules;
226  o_action += m_numRules;
227 
228  // Load rules.
229  const byte * ac_begin = 0, * rc_begin = 0,
230  * ac_end = ac_data + be::peek<uint16>(o_action),
231  * rc_end = rc_data + be::peek<uint16>(o_constraint);
232 
233  // Allocate pools
234  m_rules = new Rule [m_numRules];
235  m_codes = new Code [m_numRules*2];
236  int totalSlots = 0;
237  const uint16 *tsort = sort_key;
238  for (int i = 0; i < m_numRules; ++i)
239  totalSlots += be::peek<uint16>(--tsort);
240  const size_t prog_pool_sz = vm::Machine::Code::estimateCodeDataOut(ac_end - ac_data + rc_end - rc_data, 2 * m_numRules, totalSlots);
241  m_progs = gralloc<byte>(prog_pool_sz);
242  byte * prog_pool_free = m_progs,
243  * prog_pool_end = m_progs + prog_pool_sz;
244  if (e.test(!(m_rules && m_codes && m_progs), E_OUTOFMEM)) return face.error(e);
245 
246  Rule * r = m_rules + m_numRules - 1;
247  for (size_t n = m_numRules; r >= m_rules; --n, --r, ac_end = ac_begin, rc_end = rc_begin)
248  {
249  face.error_context((face.error_context() & 0xFFFF00) + EC_ARULE + int((n - 1) << 24));
250  r->preContext = *--precontext;
251  r->sort = be::peek<uint16>(--sort_key);
252 #ifndef NDEBUG
253  r->rule_idx = uint16(n - 1);
254 #endif
255  if (r->sort > 63 || r->preContext >= r->sort || r->preContext > m_maxPreCtxt || r->preContext < m_minPreCtxt)
256  return false;
257  ac_begin = ac_data + be::peek<uint16>(--o_action);
258  --o_constraint;
259  rc_begin = be::peek<uint16>(o_constraint) ? rc_data + be::peek<uint16>(o_constraint) : rc_end;
260 
261  if (ac_begin > ac_end || ac_begin > ac_data_end || ac_end > ac_data_end
262  || rc_begin > rc_end || rc_begin > rc_data_end || rc_end > rc_data_end
263  || vm::Machine::Code::estimateCodeDataOut(ac_end - ac_begin + rc_end - rc_begin, 2, r->sort) > size_t(prog_pool_end - prog_pool_free))
264  return false;
265  r->action = new (m_codes+n*2-2) vm::Machine::Code(false, ac_begin, ac_end, r->preContext, r->sort, *m_silf, face, pt, &prog_pool_free);
266  r->constraint = new (m_codes+n*2-1) vm::Machine::Code(true, rc_begin, rc_end, r->preContext, r->sort, *m_silf, face, pt, &prog_pool_free);
267 
268  if (e.test(!r->action || !r->constraint, E_OUTOFMEM)
269  || e.test(r->action->status() != Code::loaded, r->action->status() + E_CODEFAILURE)
270  || e.test(r->constraint->status() != Code::loaded, r->constraint->status() + E_CODEFAILURE)
271  || e.test(!r->constraint->immutable(), E_MUTABLECCODE))
272  return face.error(e);
273  }
274 
275  byte * const moved_progs = prog_pool_free > m_progs ? static_cast<byte *>(realloc(m_progs, prog_pool_free - m_progs)) : 0;
276  if (e.test(!moved_progs, E_OUTOFMEM))
277  {
278  free(m_progs);
279  m_progs = 0;
280  return face.error(e);
281  }
282 
283  if (moved_progs != m_progs)
284  {
285  for (Code * c = m_codes, * const ce = c + m_numRules*2; c != ce; ++c)
286  {
287  c->externalProgramMoved(moved_progs - m_progs);
288  }
289  m_progs = moved_progs;
290  }
291 
292  // Load the rule entries map
293  face.error_context((face.error_context() & 0xFFFF00) + EC_APASS);
294  //TODO: Coverity: 1315804: FORWARD_NULL
295  RuleEntry * re = m_ruleMap = gralloc<RuleEntry>(num_entries);
296  if (e.test(!re, E_OUTOFMEM)) return face.error(e);
297  for (size_t n = num_entries; n; --n, ++re)
298  {
299  const ptrdiff_t rn = be::read<uint16>(rule_map);
300  if (e.test(rn >= m_numRules, E_BADRULENUM)) return face.error(e);
301  re->rule = m_rules + rn;
302  }
303 
304  return true;
305 }
306 
307 static int cmpRuleEntry(const void *a, const void *b) { return (*(RuleEntry *)a < *(RuleEntry *)b ? -1 :
308  (*(RuleEntry *)b < *(RuleEntry *)a ? 1 : 0)); }
309 
310 bool Pass::readStates(const byte * starts, const byte *states, const byte * o_rule_map, GR_MAYBE_UNUSED Face & face, Error &e)
311 {
312 #ifdef GRAPHITE2_TELEMETRY
313  telemetry::category _states_cat(face.tele.starts);
314 #endif
315  m_startStates = gralloc<uint16>(m_maxPreCtxt - m_minPreCtxt + 1);
316 #ifdef GRAPHITE2_TELEMETRY
317  telemetry::set_category(face.tele.states);
318 #endif
319  m_states = gralloc<State>(m_numStates);
320 #ifdef GRAPHITE2_TELEMETRY
321  telemetry::set_category(face.tele.transitions);
322 #endif
323  m_transitions = gralloc<uint16>(m_numTransition * m_numColumns);
324 
325  if (e.test(!m_startStates || !m_states || !m_transitions, E_OUTOFMEM)) return face.error(e);
326  // load start states
327  for (uint16 * s = m_startStates,
328  * const s_end = s + m_maxPreCtxt - m_minPreCtxt + 1; s != s_end; ++s)
329  {
330  *s = be::read<uint16>(starts);
331  if (e.test(*s >= m_numStates, E_BADSTATE))
332  {
333  face.error_context((face.error_context() & 0xFFFF00) + EC_ASTARTS + int((s - m_startStates) << 24));
334  return face.error(e); // true;
335  }
336  }
337 
338  // load state transition table.
339  for (uint16 * t = m_transitions,
340  * const t_end = t + m_numTransition*m_numColumns; t != t_end; ++t)
341  {
342  *t = be::read<uint16>(states);
343  if (e.test(*t >= m_numStates, E_BADSTATE))
344  {
345  face.error_context((face.error_context() & 0xFFFF00) + EC_ATRANS + int(((t - m_transitions) / m_numColumns) << 8));
346  return face.error(e);
347  }
348  }
349 
350  State * s = m_states,
351  * const success_begin = m_states + m_numStates - m_numSuccess;
352  const RuleEntry * rule_map_end = m_ruleMap + be::peek<uint16>(o_rule_map + m_numSuccess*sizeof(uint16));
353  for (size_t n = m_numStates; n; --n, ++s)
354  {
355  RuleEntry * const begin = s < success_begin ? 0 : m_ruleMap + be::read<uint16>(o_rule_map),
356  * const end = s < success_begin ? 0 : m_ruleMap + be::peek<uint16>(o_rule_map);
357 
358  if (e.test(begin >= rule_map_end || end > rule_map_end || begin > end, E_BADRULEMAPPING))
359  {
360  face.error_context((face.error_context() & 0xFFFF00) + EC_ARULEMAP + int(n << 24));
361  return face.error(e);
362  }
363  s->rules = begin;
364  s->rules_end = (end - begin <= FiniteStateMachine::MAX_RULES)? end :
366  if (begin) // keep UBSan happy can't call qsort with null begin
367  qsort(begin, end - begin, sizeof(RuleEntry), &cmpRuleEntry);
368  }
369 
370  return true;
371 }
372 
373 bool Pass::readRanges(const byte * ranges, size_t num_ranges, Error &e)
374 {
375  m_cols = gralloc<uint16>(m_numGlyphs);
376  if (e.test(!m_cols, E_OUTOFMEM)) return false;
377  memset(m_cols, 0xFF, m_numGlyphs * sizeof(uint16));
378  for (size_t n = num_ranges; n; --n)
379  {
380  uint16 * ci = m_cols + be::read<uint16>(ranges),
381  * ci_end = m_cols + be::read<uint16>(ranges) + 1,
382  col = be::read<uint16>(ranges);
383 
384  if (e.test(ci >= ci_end || ci_end > m_cols+m_numGlyphs || col >= m_numColumns, E_BADRANGE))
385  return false;
386 
387  // A glyph must only belong to one column at a time
388  while (ci != ci_end && *ci == 0xffff)
389  *ci++ = col;
390 
391  if (e.test(ci != ci_end, E_BADRANGE))
392  return false;
393  }
394  return true;
395 }
396 
397 
399 {
400  Slot *s = m.slotMap().segment.first();
401  if (!s || !testPassConstraint(m)) return true;
402  if (reverse)
403  {
404  m.slotMap().segment.reverseSlots();
405  s = m.slotMap().segment.first();
406  }
407  if (m_numRules)
408  {
409  Slot *currHigh = s->next();
410 
411 #if !defined GRAPHITE2_NTRACING
412  if (fsm.dbgout) *fsm.dbgout << "rules" << json::array;
413  json::closer rules_array_closer(fsm.dbgout);
414 #endif
415 
416  m.slotMap().highwater(currHigh);
417  int lc = m_iMaxLoop;
418  do
419  {
420  findNDoRule(s, m, fsm);
421  if (m.status() != Machine::finished) return false;
422  if (s && (s == m.slotMap().highwater() || m.slotMap().highpassed() || --lc == 0)) {
423  if (!lc)
424  s = m.slotMap().highwater();
425  lc = m_iMaxLoop;
426  if (s)
427  m.slotMap().highwater(s->next());
428  }
429  } while (s);
430  }
431  //TODO: Use enums for flags
432  const bool collisions = m_numCollRuns || m_kernColls;
433 
434  if (!collisions || !m.slotMap().segment.hasCollisionInfo())
435  return true;
436 
437  if (m_numCollRuns)
438  {
439  if (!(m.slotMap().segment.flags() & Segment::SEG_INITCOLLISIONS))
440  {
441  m.slotMap().segment.positionSlots(0, 0, 0, m.slotMap().dir(), true);
442 // m.slotMap().segment.flags(m.slotMap().segment.flags() | Segment::SEG_INITCOLLISIONS);
443  }
444  if (!collisionShift(&m.slotMap().segment, m.slotMap().dir(), fsm.dbgout))
445  return false;
446  }
447  if ((m_kernColls) && !collisionKern(&m.slotMap().segment, m.slotMap().dir(), fsm.dbgout))
448  return false;
449  if (collisions && !collisionFinish(&m.slotMap().segment, fsm.dbgout))
450  return false;
451  return true;
452 }
453 
455 {
456  fsm.reset(slot, m_maxPreCtxt);
457  if (fsm.slots.context() < m_minPreCtxt)
458  return false;
459 
461  uint8 free_slots = SlotMap::MAX_SLOTS;
462  do
463  {
464  fsm.slots.pushSlot(slot);
465  if (slot->gid() >= m_numGlyphs
466  || m_cols[slot->gid()] == 0xffffU
467  || --free_slots == 0
468  || state >= m_numTransition)
469  return free_slots != 0;
470 
471  const uint16 * transitions = m_transitions + state*m_numColumns;
472  state = transitions[m_cols[slot->gid()]];
473  if (state >= m_successStart)
475 
476  slot = slot->next();
477  } while (state != 0 && slot);
478 
479  fsm.slots.pushSlot(slot);
480  return true;
481 }
482 
483 #if !defined GRAPHITE2_NTRACING
484 
485 inline
486 Slot * input_slot(const SlotMap & slots, const int n)
487 {
488  Slot * s = slots[slots.context() + n];
489  if (!s->isCopied()) return s;
490 
491  return s->prev() ? s->prev()->next() : (s->next() ? s->next()->prev() : slots.segment.last());
492 }
493 
494 inline
495 Slot * output_slot(const SlotMap & slots, const int n)
496 {
497  Slot * s = slots[slots.context() + n - 1];
498  return s ? s->next() : slots.segment.first();
499 }
500 
501 #endif //!defined GRAPHITE2_NTRACING
502 
503 void Pass::findNDoRule(Slot * & slot, Machine &m, FiniteStateMachine & fsm) const
504 {
505  assert(slot);
506 
507  if (runFSM(fsm, slot))
508  {
509  // Search for the first rule which passes the constraint
510  const RuleEntry * r = fsm.rules.begin(),
511  * const re = fsm.rules.end();
512  while (r != re && !testConstraint(*r->rule, m))
513  {
514  ++r;
515  if (m.status() != Machine::finished)
516  return;
517  }
518 
519 #if !defined GRAPHITE2_NTRACING
520  if (fsm.dbgout)
521  {
522  if (fsm.rules.size() != 0)
523  {
524  *fsm.dbgout << json::item << json::object;
525  dumpRuleEventConsidered(fsm, *r);
526  if (r != re)
527  {
528  const int adv = doAction(r->rule->action, slot, m);
529  dumpRuleEventOutput(fsm, *r->rule, slot);
530  if (r->rule->action->deletes()) fsm.slots.collectGarbage(slot);
531  adjustSlot(adv, slot, fsm.slots);
532  *fsm.dbgout << "cursor" << objectid(dslot(&fsm.slots.segment, slot))
533  << json::close; // Close RuelEvent object
534 
535  return;
536  }
537  else
538  {
539  *fsm.dbgout << json::close // close "considered" array
540  << "output" << json::null
541  << "cursor" << objectid(dslot(&fsm.slots.segment, slot->next()))
542  << json::close;
543  }
544  }
545  }
546  else
547 #endif
548  {
549  if (r != re)
550  {
551  const int adv = doAction(r->rule->action, slot, m);
552  if (m.status() != Machine::finished) return;
553  if (r->rule->action->deletes()) fsm.slots.collectGarbage(slot);
554  adjustSlot(adv, slot, fsm.slots);
555  return;
556  }
557  }
558  }
559 
560  slot = slot->next();
561  return;
562 }
563 
564 #if !defined GRAPHITE2_NTRACING
565 
566 void Pass::dumpRuleEventConsidered(const FiniteStateMachine & fsm, const RuleEntry & re) const
567 {
568  *fsm.dbgout << "considered" << json::array;
569  for (const RuleEntry *r = fsm.rules.begin(); r != &re; ++r)
570  {
571  if (r->rule->preContext > fsm.slots.context())
572  continue;
573  *fsm.dbgout << json::flat << json::object
574  << "id" << r->rule - m_rules
575  << "failed" << true
576  << "input" << json::flat << json::object
577  << "start" << objectid(dslot(&fsm.slots.segment, input_slot(fsm.slots, -r->rule->preContext)))
578  << "length" << r->rule->sort
579  << json::close // close "input"
580  << json::close; // close Rule object
581  }
582 }
583 
584 
585 void Pass::dumpRuleEventOutput(const FiniteStateMachine & fsm, const Rule & r, Slot * const last_slot) const
586 {
588  << "id" << &r - m_rules
589  << "failed" << false
590  << "input" << json::flat << json::object
591  << "start" << objectid(dslot(&fsm.slots.segment, input_slot(fsm.slots, 0)))
592  << "length" << r.sort - r.preContext
593  << json::close // close "input"
594  << json::close // close Rule object
595  << json::close // close considered array
596  << "output" << json::object
597  << "range" << json::flat << json::object
598  << "start" << objectid(dslot(&fsm.slots.segment, input_slot(fsm.slots, 0)))
599  << "end" << objectid(dslot(&fsm.slots.segment, last_slot))
600  << json::close // close "input"
601  << "slots" << json::array;
602  const Position rsb_prepos = last_slot ? last_slot->origin() : fsm.slots.segment.advance();
603  fsm.slots.segment.positionSlots(0, 0, 0, fsm.slots.segment.currdir());
604 
605  for(Slot * slot = output_slot(fsm.slots, 0); slot != last_slot; slot = slot->next())
606  *fsm.dbgout << dslot(&fsm.slots.segment, slot);
607  *fsm.dbgout << json::close // close "slots"
608  << "postshift" << (last_slot ? last_slot->origin() : fsm.slots.segment.advance()) - rsb_prepos
609  << json::close; // close "output" object
610 
611 }
612 
613 #endif
614 
615 
616 inline
617 bool Pass::testPassConstraint(Machine & m) const
618 {
619  if (!m_cPConstraint) return true;
620 
622 
623  m.slotMap().reset(*m.slotMap().segment.first(), 0);
624  m.slotMap().pushSlot(m.slotMap().segment.first());
625  vm::slotref * map = m.slotMap().begin();
626  const uint32 ret = m_cPConstraint.run(m, map);
627 
628 #if !defined GRAPHITE2_NTRACING
629  json * const dbgout = m.slotMap().segment.getFace()->logger();
630  if (dbgout)
631  *dbgout << "constraint" << (ret && m.status() == Machine::finished);
632 #endif
633 
634  return ret && m.status() == Machine::finished;
635 }
636 
637 
638 bool Pass::testConstraint(const Rule & r, Machine & m) const
639 {
640  const uint16 curr_context = m.slotMap().context();
641  if (unsigned(r.sort + curr_context - r.preContext) > m.slotMap().size()
642  || curr_context - r.preContext < 0) return false;
643 
644  vm::slotref * map = m.slotMap().begin() + curr_context - r.preContext;
645  if (map[r.sort - 1] == 0)
646  return false;
647 
648  if (!*r.constraint) return true;
649  assert(r.constraint->constraint());
650  for (int n = r.sort; n && map; --n, ++map)
651  {
652  if (!*map) continue;
653  const int32 ret = r.constraint->run(m, map);
654  if (!ret || m.status() != Machine::finished)
655  return false;
656  }
657 
658  return true;
659 }
660 
661 
663 {
664  for(Slot **s = begin(), *const *const se = end() - 1; s != se; ++s) {
665  Slot *& slot = *s;
666  if(slot && (slot->isDeleted() || slot->isCopied()))
667  {
668  if (slot == aSlot)
669  aSlot = slot->prev() ? slot->prev() : slot->next();
670  segment.freeSlot(slot);
671  }
672  }
673 }
674 
675 
676 
677 int Pass::doAction(const Code *codeptr, Slot * & slot_out, vm::Machine & m) const
678 {
679  assert(codeptr);
680  if (!*codeptr) return 0;
681  SlotMap & smap = m.slotMap();
682  vm::slotref * map = &smap[smap.context()];
683  smap.highpassed(false);
684 
685  int32 ret = codeptr->run(m, map);
686 
687  if (m.status() != Machine::finished)
688  {
689  slot_out = NULL;
690  smap.highwater(0);
691  return 0;
692  }
693 
694  slot_out = *map;
695  return ret;
696 }
697 
698 
699 void Pass::adjustSlot(int delta, Slot * & slot_out, SlotMap & smap) const
700 {
701  if (!slot_out)
702  {
703  if (smap.highpassed() || slot_out == smap.highwater())
704  {
705  slot_out = smap.segment.last();
706  ++delta;
707  if (!smap.highwater() || smap.highwater() == slot_out)
708  smap.highpassed(false);
709  }
710  else
711  {
712  slot_out = smap.segment.first();
713  --delta;
714  }
715  }
716  if (delta < 0)
717  {
718  while (++delta <= 0 && slot_out)
719  {
720  slot_out = slot_out->prev();
721  if (smap.highpassed() && smap.highwater() == slot_out)
722  smap.highpassed(false);
723  }
724  }
725  else if (delta > 0)
726  {
727  while (--delta >= 0 && slot_out)
728  {
729  if (slot_out == smap.highwater() && slot_out)
730  smap.highpassed(true);
731  slot_out = slot_out->next();
732  }
733  }
734 }
735 
736 bool Pass::collisionShift(Segment *seg, int dir, json * const dbgout) const
737 {
738  ShiftCollider shiftcoll(dbgout);
739  // bool isfirst = true;
740  bool hasCollisions = false;
741  Slot *start = seg->first(); // turn on collision fixing for the first slot
742  Slot *end = NULL;
743  bool moved = false;
744 
745 #if !defined GRAPHITE2_NTRACING
746  if (dbgout)
747  *dbgout << "collisions" << json::array
748  << json::flat << json::object << "num-loops" << m_numCollRuns << json::close;
749 #endif
750 
751  while (start)
752  {
753 #if !defined GRAPHITE2_NTRACING
754  if (dbgout) *dbgout << json::object << "phase" << "1" << "moves" << json::array;
755 #endif
756  hasCollisions = false;
757  end = NULL;
758  // phase 1 : position shiftable glyphs, ignoring kernable glyphs
759  for (Slot *s = start; s; s = s->next())
760  {
761  const SlotCollision * c = seg->collisionInfo(s);
763  && !resolveCollisions(seg, s, start, shiftcoll, false, dir, moved, hasCollisions, dbgout))
764  return false;
765  if (s != start && (c->flags() & SlotCollision::COLL_END))
766  {
767  end = s->next();
768  break;
769  }
770  }
771 
772 #if !defined GRAPHITE2_NTRACING
773  if (dbgout)
774  *dbgout << json::close << json::close; // phase-1
775 #endif
776 
777  // phase 2 : loop until happy.
778  for (int i = 0; i < m_numCollRuns - 1; ++i)
779  {
780  if (hasCollisions || moved)
781  {
782 
783 #if !defined GRAPHITE2_NTRACING
784  if (dbgout)
785  *dbgout << json::object << "phase" << "2a" << "loop" << i << "moves" << json::array;
786 #endif
787  // phase 2a : if any shiftable glyphs are in collision, iterate backwards,
788  // fixing them and ignoring other non-collided glyphs. Note that this handles ONLY
789  // glyphs that are actually in collision from phases 1 or 2b, and working backwards
790  // has the intended effect of breaking logjams.
791  if (hasCollisions)
792  {
793  hasCollisions = false;
794  #if 0
795  moved = true;
796  for (Slot *s = start; s != end; s = s->next())
797  {
798  SlotCollision * c = seg->collisionInfo(s);
799  c->setShift(Position(0, 0));
800  }
801  #endif
802  Slot *lend = end ? end->prev() : seg->last();
803  Slot *lstart = start->prev();
804  for (Slot *s = lend; s != lstart; s = s->prev())
805  {
806  SlotCollision * c = seg->collisionInfo(s);
808  == (SlotCollision::COLL_FIX | SlotCollision::COLL_ISCOL)) // ONLY if this glyph is still colliding
809  {
810  if (!resolveCollisions(seg, s, lend, shiftcoll, true, dir, moved, hasCollisions, dbgout))
811  return false;
812  c->setFlags(c->flags() | SlotCollision::COLL_TEMPLOCK);
813  }
814  }
815  }
816 
817 #if !defined GRAPHITE2_NTRACING
818  if (dbgout)
819  *dbgout << json::close << json::close // phase 2a
820  << json::object << "phase" << "2b" << "loop" << i << "moves" << json::array;
821 #endif
822 
823  // phase 2b : redo basic diacritic positioning pass for ALL glyphs. Each successive loop adjusts
824  // glyphs from their current adjusted position, which has the effect of gradually minimizing the
825  // resulting adjustment; ie, the final result will be gradually closer to the original location.
826  // Also it allows more flexibility in the final adjustment, since it is moving along the
827  // possible 8 vectors from successively different starting locations.
828  if (moved)
829  {
830  moved = false;
831  for (Slot *s = start; s != end; s = s->next())
832  {
833  SlotCollision * c = seg->collisionInfo(s);
836  && !resolveCollisions(seg, s, start, shiftcoll, false, dir, moved, hasCollisions, dbgout))
837  return false;
838  else if (c->flags() & SlotCollision::COLL_TEMPLOCK)
839  c->setFlags(c->flags() & ~SlotCollision::COLL_TEMPLOCK);
840  }
841  }
842  // if (!hasCollisions) // no, don't leave yet because phase 2b will continue to improve things
843  // break;
844 #if !defined GRAPHITE2_NTRACING
845  if (dbgout)
846  *dbgout << json::close << json::close; // phase 2
847 #endif
848  }
849  }
850  if (!end)
851  break;
852  start = NULL;
853  for (Slot *s = end->prev(); s; s = s->next())
854  {
855  if (seg->collisionInfo(s)->flags() & SlotCollision::COLL_START)
856  {
857  start = s;
858  break;
859  }
860  }
861  }
862  return true;
863 }
864 
865 bool Pass::collisionKern(Segment *seg, int dir, json * const dbgout) const
866 {
867  Slot *start = seg->first();
868  float ymin = 1e38f;
869  float ymax = -1e38f;
870  const GlyphCache &gc = seg->getFace()->glyphs();
871 
872  // phase 3 : handle kerning of clusters
873 #if !defined GRAPHITE2_NTRACING
874  if (dbgout)
875  *dbgout << json::object << "phase" << "3" << "moves" << json::array;
876 #endif
877 
878  for (Slot *s = seg->first(); s; s = s->next())
879  {
880  if (!gc.check(s->gid()))
881  return false;
882  const SlotCollision * c = seg->collisionInfo(s);
883  const Rect &bbox = seg->theGlyphBBoxTemporary(s->gid());
884  float y = s->origin().y + c->shift().y;
885  if (!(c->flags() & SlotCollision::COLL_ISSPACE))
886  {
887  ymax = max(y + bbox.tr.y, ymax);
888  ymin = min(y + bbox.bl.y, ymin);
889  }
892  resolveKern(seg, s, start, dir, ymin, ymax, dbgout);
893  if (c->flags() & SlotCollision::COLL_END)
894  start = NULL;
895  if (c->flags() & SlotCollision::COLL_START)
896  start = s;
897  }
898 
899 #if !defined GRAPHITE2_NTRACING
900  if (dbgout)
901  *dbgout << json::close << json::close; // phase 3
902 #endif
903  return true;
904 }
905 
906 bool Pass::collisionFinish(Segment *seg, GR_MAYBE_UNUSED json * const dbgout) const
907 {
908  for (Slot *s = seg->first(); s; s = s->next())
909  {
910  SlotCollision *c = seg->collisionInfo(s);
911  if (c->shift().x != 0 || c->shift().y != 0)
912  {
913  const Position newOffset = c->shift();
914  const Position nullPosition(0, 0);
915  c->setOffset(newOffset + c->offset());
916  c->setShift(nullPosition);
917  }
918  }
919 // seg->positionSlots();
920 
921 #if !defined GRAPHITE2_NTRACING
922  if (dbgout)
923  *dbgout << json::close;
924 #endif
925  return true;
926 }
927 
928 // Can slot s be kerned, or is it attached to something that can be kerned?
929 static bool inKernCluster(Segment *seg, Slot *s)
930 {
931  SlotCollision *c = seg->collisionInfo(s);
932  if (c->flags() & SlotCollision::COLL_KERN /** && c->flags() & SlotCollision::COLL_FIX **/ )
933  return true;
934  while (s->attachedTo())
935  {
936  s = s->attachedTo();
937  c = seg->collisionInfo(s);
938  if (c->flags() & SlotCollision::COLL_KERN /** && c->flags() & SlotCollision::COLL_FIX **/ )
939  return true;
940  }
941  return false;
942 }
943 
944 // Fix collisions for the given slot.
945 // Return true if everything was fixed, false if there are still collisions remaining.
946 // isRev means be we are processing backwards.
948  ShiftCollider &coll, GR_MAYBE_UNUSED bool isRev, int dir, bool &moved, bool &hasCol,
949  json * const dbgout) const
950 {
951  Slot * nbor; // neighboring slot
952  SlotCollision *cFix = seg->collisionInfo(slotFix);
953  if (!coll.initSlot(seg, slotFix, cFix->limit(), cFix->margin(), cFix->marginWt(),
954  cFix->shift(), cFix->offset(), dir, dbgout))
955  return false;
956  bool collides = false;
957  // When we're processing forward, ignore kernable glyphs that preceed the target glyph.
958  // When processing backward, don't ignore these until we pass slotFix.
959  bool ignoreForKern = !isRev;
960  bool rtl = dir & 1;
961  Slot *base = slotFix;
962  while (base->attachedTo())
963  base = base->attachedTo();
964  Position zero(0., 0.);
965 
966  // Look for collisions with the neighboring glyphs.
967  for (nbor = start; nbor; nbor = isRev ? nbor->prev() : nbor->next())
968  {
969  SlotCollision *cNbor = seg->collisionInfo(nbor);
970  bool sameCluster = nbor->isChildOf(base);
971  if (nbor != slotFix // don't process if this is the slot of interest
972  && !(cNbor->ignore()) // don't process if ignoring
973  && (nbor == base || sameCluster // process if in the same cluster as slotFix
974  || !inKernCluster(seg, nbor)) // or this cluster is not to be kerned
975 // || (rtl ^ ignoreForKern)) // or it comes before(ltr) or after(rtl)
976  && (!isRev // if processing forwards then good to merge otherwise only:
977  || !(cNbor->flags() & SlotCollision::COLL_FIX) // merge in immovable stuff
978  || ((cNbor->flags() & SlotCollision::COLL_KERN) && !sameCluster) // ignore other kernable clusters
979  || (cNbor->flags() & SlotCollision::COLL_ISCOL)) // test against other collided glyphs
980  && !coll.mergeSlot(seg, nbor, cNbor, cNbor->shift(), !ignoreForKern, sameCluster, collides, false, dbgout))
981  return false;
982  else if (nbor == slotFix)
983  // Switching sides of this glyph - if we were ignoring kernable stuff before, don't anymore.
984  ignoreForKern = !ignoreForKern;
985 
986  if (nbor != start && (cNbor->flags() & (isRev ? SlotCollision::COLL_START : SlotCollision::COLL_END)))
987  break;
988  }
989  bool isCol = false;
990  if (collides || cFix->shift().x != 0.f || cFix->shift().y != 0.f)
991  {
992  Position shift = coll.resolve(seg, isCol, dbgout);
993  // isCol has been set to true if a collision remains.
994  if (std::fabs(shift.x) < 1e38f && std::fabs(shift.y) < 1e38f)
995  {
996  if (sqr(shift.x-cFix->shift().x) + sqr(shift.y-cFix->shift().y) >= m_colThreshold * m_colThreshold)
997  moved = true;
998  cFix->setShift(shift);
999  if (slotFix->firstChild())
1000  {
1001  Rect bbox;
1002  Position here = slotFix->origin() + shift;
1003  float clusterMin = here.x;
1004  slotFix->firstChild()->finalise(seg, NULL, here, bbox, 0, clusterMin, rtl, false);
1005  }
1006  }
1007  }
1008  else
1009  {
1010  // This glyph is not colliding with anything.
1011 #if !defined GRAPHITE2_NTRACING
1012  if (dbgout)
1013  {
1014  *dbgout << json::object
1015  << "missed" << objectid(dslot(seg, slotFix));
1016  coll.outputJsonDbg(dbgout, seg, -1);
1017  *dbgout << json::close;
1018  }
1019 #endif
1020  }
1021 
1022  // Set the is-collision flag bit.
1023  if (isCol)
1025  else
1027  hasCol |= isCol;
1028  return true;
1029 }
1030 
1032  float &ymin, float &ymax, json *const dbgout) const
1033 {
1034  Slot *nbor; // neighboring slot
1035  float currSpace = 0.;
1036  bool collides = false;
1037  unsigned int space_count = 0;
1038  Slot *base = slotFix;
1039  while (base->attachedTo())
1040  base = base->attachedTo();
1041  SlotCollision *cFix = seg->collisionInfo(base);
1042  const GlyphCache &gc = seg->getFace()->glyphs();
1043  const Rect &bbb = seg->theGlyphBBoxTemporary(slotFix->gid());
1044  const float by = slotFix->origin().y + cFix->shift().y;
1045 
1046  if (base != slotFix)
1047  {
1049  return 0;
1050  }
1051  bool seenEnd = (cFix->flags() & SlotCollision::COLL_END) != 0;
1052  bool isInit = false;
1053  KernCollider coll(dbgout);
1054 
1055  ymax = max(by + bbb.tr.y, ymax);
1056  ymin = min(by + bbb.bl.y, ymin);
1057  for (nbor = slotFix->next(); nbor; nbor = nbor->next())
1058  {
1059  if (nbor->isChildOf(base))
1060  continue;
1061  if (!gc.check(nbor->gid()))
1062  return 0.;
1063  const Rect &bb = seg->theGlyphBBoxTemporary(nbor->gid());
1064  SlotCollision *cNbor = seg->collisionInfo(nbor);
1065  if ((bb.bl.y == 0.f && bb.tr.y == 0.f) || (cNbor->flags() & SlotCollision::COLL_ISSPACE))
1066  {
1067  if (m_kernColls == InWord)
1068  break;
1069  // Add space for a space glyph.
1070  currSpace += nbor->advance();
1071  ++space_count;
1072  }
1073  else
1074  {
1075  space_count = 0;
1076  if (nbor != slotFix && !cNbor->ignore())
1077  {
1078  seenEnd = true;
1079  if (!isInit)
1080  {
1081  if (!coll.initSlot(seg, slotFix, cFix->limit(), cFix->margin(),
1082  cFix->shift(), cFix->offset(), dir, ymin, ymax, dbgout))
1083  return 0.;
1084  isInit = true;
1085  }
1086  collides |= coll.mergeSlot(seg, nbor, cNbor->shift(), currSpace, dir, dbgout);
1087  }
1088  }
1089  if (cNbor->flags() & SlotCollision::COLL_END)
1090  {
1091  if (seenEnd && space_count < 2)
1092  break;
1093  else
1094  seenEnd = true;
1095  }
1096  }
1097  if (collides)
1098  {
1099  Position mv = coll.resolve(seg, slotFix, dir, dbgout);
1100  coll.shift(mv, dir);
1101  Position delta = slotFix->advancePos() + mv - cFix->shift();
1102  slotFix->advance(delta);
1103  cFix->setShift(mv);
1104  return mv.x;
1105  }
1106  return 0.;
1107 }
int ptrdiff_t
Definition: CPAL.d:3845
Pass(const TableHeader *inTable, Converter *cnv)
const RuleEntry * begin() const
Definition: Rule.h:200
const RuleEntry * end() const
Definition: Rule.h:206
void accumulate_rules(const State &state)
Definition: Rule.h:218
void reset(Slot *&slot, const short unsigned int max_pre_ctxt)
Definition: Rule.h:179
Position resolve(Segment *seg, Slot *slot, int dir, json *const dbgout)
void shift(const Position &mv, int dir)
Definition: Collider.cpp:1057
bool initSlot(Segment *seg, Slot *aSlot, const Rect &constraint, float margin, const Position &currShift, const Position &offsetPrev, int dir, float ymin, float ymax, json *const dbgout)
bool mergeSlot(Segment *seg, Slot *slot, const Position &currShift, float currSpace, int dir, json *const dbgout)
vm::Machine::Code m_cPConstraint
Definition: Pass.h:111
bool testConstraint(const Rule &r, vm::Machine &) const
bool readPass(const byte *pPass, size_t pass_length, size_t subtable_base, Face &face, enum passtype pt, uint32 version, Error &e)
Definition: Pass.cpp:93
byte m_kernColls
Definition: Pass.h:98
void findNDoRule(Slot *&iSlot, vm::Machine &, FiniteStateMachine &fsm) const
uint16 * m_startStates
Definition: Pass.h:91
bool readStates(const byte *starts, const byte *states, const byte *o_rule_map, Face &, Error &e)
Definition: Pass.cpp:310
uint16 m_successStart
Definition: Pass.h:105
byte m_minPreCtxt
Definition: Pass.h:107
State * m_states
Definition: Pass.h:93
bool collisionFinish(Segment *seg, GR_MAYBE_UNUSED json *const dbgout) const
int doAction(const vm::Machine::Code *codeptr, Slot *&slot_out, vm::Machine &) const
uint16 m_numStates
Definition: Pass.h:102
bool runGraphite(vm::Machine &m, FiniteStateMachine &fsm, bool reverse) const
Definition: Pass.cpp:398
uint16 * m_transitions
Definition: Pass.h:92
void adjustSlot(int delta, Slot *&slot_out, SlotMap &) const
Definition: Pass.cpp:699
byte m_maxPreCtxt
Definition: Pass.h:108
float resolveKern(Segment *seg, Slot *slot, Slot *start, int dir, float &ymin, float &ymax, json *const dbgout) const
Definition: Pass.cpp:1031
bool m_isReverseDir
Definition: Pass.h:110
byte m_numCollRuns
Definition: Pass.h:97
bool runFSM(FiniteStateMachine &fsm, Slot *slot) const
Definition: Pass.cpp:454
uint16 m_numRules
Definition: Pass.h:101
const Silf * m_silf
Definition: Pass.h:87
bool readRules(const byte *rule_map, const size_t num_entries, const byte *precontext, const uint16 *sort_key, const uint16 *o_constraint, const byte *constraint_data, const uint16 *o_action, const byte *action_data, Face &, enum passtype pt, Error &e)
Definition: Pass.cpp:214
uint16 m_numColumns
Definition: Pass.h:106
byte * m_progs
Definition: Pass.h:95
void dumpRuleEventConsidered(const FiniteStateMachine &fsm, const RuleEntry &re) const
Definition: Pass.cpp:566
bool collisionShift(Segment *seg, int dir, json *const dbgout) const
Definition: Pass.cpp:736
bool resolveCollisions(Segment *seg, Slot *slot, Slot *start, ShiftCollider &coll, bool isRev, int dir, bool &moved, bool &hasCol, json *const dbgout) const
Definition: Pass.cpp:947
Rule * m_rules
Definition: Pass.h:89
uint16 * m_cols
Definition: Pass.h:88
vm::Machine::Code * m_codes
Definition: Pass.h:94
bool collisionKern(Segment *seg, int dir, json *const dbgout) const
Definition: Pass.cpp:865
bool readRanges(const byte *ranges, size_t num_ranges, Error &e)
Definition: Pass.cpp:373
bool testPassConstraint(vm::Machine &m) const
void dumpRuleEventOutput(const FiniteStateMachine &fsm, const Rule &r, Slot *os) const
Definition: Pass.cpp:585
uint16 m_numGlyphs
Definition: Pass.h:100
byte m_iMaxLoop
Definition: Pass.h:99
RuleEntry * m_ruleMap
Definition: Pass.h:90
uint16 m_numSuccess
Definition: Pass.h:104
uint16 m_numTransition
Definition: Pass.h:103
byte m_colThreshold
Definition: Pass.h:109
Position tr
Definition: Position.h:65
Position bl
Definition: Position.h:64
Slot * last()
Definition: Segment.h:107
bool currdir() const
Definition: Segment.h:130
Position positionSlots(const Font *font=0, Slot *first=0, Slot *last=0, bool isRtl=false, bool isFinal=true)
Definition: Segment.cpp:288
Slot * first()
Definition: Segment.h:105
Position advance() const
Definition: Segment.h:93
void outputJsonDbg(json *const dbgout, Segment *seg, int axis)
Definition: Collider.cpp:648
Position resolve(Segment *seg, bool &isCol, GR_MAYBE_UNUSED json *const dbgout)
bool initSlot(Segment *seg, Slot *aSlot, const Rect &constraint, float margin, float marginMin, const Position &currShift, const Position &currOffset, int dir, GR_MAYBE_UNUSED json *const dbgout)
Definition: Collider.cpp:50
bool mergeSlot(Segment *seg, Slot *slot, const SlotCollision *cinfo, const Position &currShift, bool isAfter, bool sameCluster, bool &hasCol, bool isExclusion, GR_MAYBE_UNUSED json *const dbgout)
Definition: Collider.cpp:265
byte flags() const
Definition: Silf.h:96
uint16 marginWt() const
Definition: Collider.h:83
const Rect & limit() const
Definition: Collider.h:77
const Position & shift() const
Definition: Collider.h:79
void setFlags(uint16 v)
Definition: Collider.h:84
uint16 margin() const
Definition: Collider.h:82
void setShift(const Position &v)
Definition: Collider.h:79
uint16 flags() const
Definition: Collider.h:84
const Position & offset() const
Definition: Collider.h:80
void pushSlot(Slot *const slot)
Definition: Rule.h:288
Slot ** end()
Definition: Rule.h:262
unsigned short context() const
Definition: Rule.h:274
void collectGarbage(Slot *&aSlot)
Definition: Pass.cpp:662
Slot ** begin()
Definition: Rule.h:255
Segment & segment
Definition: Rule.h:126
Slot * prev() const
Definition: Slot.h:86
bool isChildOf(const Slot *base) const
Definition: Slot.cpp:523
unsigned short gid() const
Definition: Slot.h:72
Slot * firstChild() const
Definition: Slot.h:123
float advance() const
Definition: Slot.h:74
Slot * next() const
Definition: Slot.h:84
Position advancePos() const
Definition: Slot.h:76
Position finalise(const Segment *seg, const Font *font, Position &base, Rect &bbox, uint8 attrLevel, float &clusterMin, bool rtl, bool isFinal, int depth=0)
Definition: Slot.cpp:88
Position origin() const
Definition: Slot.h:73
static void close(json &)
Definition: json.cpp:108
static void flat(json &)
Definition: json.cpp:107
static void array(json &)
Definition: json.cpp:110
static void object(json &)
Definition: json.cpp:109
static void item(json &)
Definition: json.cpp:111
static const std::nullptr_t null
Definition: json.h:69
bool constraint() const
Definition: Code.h:101
int32 run(Machine &m, slotref *&map) const
static size_t estimateCodeDataOut(size_t num_bytecodes, int nRules, int nSlots)
Definition: Code.h:115
status_t status() const
Definition: Code.h:100
#define n
Definition: t4ht.c:1290
#define b
Definition: jpegint.h:372
#define free(a)
Definition: decNumber.cpp:310
void sort_key(void)
Definition: dvispc.c:2085
#define shift
Definition: exp3.c:154
#define s
Definition: afcover.h:80
#define t
Definition: afcover.h:96
static FIELD_PTR begin
Definition: genind.c:37
#define c(n)
Definition: gpos-common.c:150
#define a(n)
Definition: gpos-common.c:148
int base
Definition: gsftopk.c:1502
int col
Definition: gsftopk.c:443
assert(pcxLoadImage24((char *)((void *) 0), fp, pinfo, hdr))
#define NULL
Definition: ftobjs.h:61
small capitals from c petite p
Definition: afcover.h:72
small capitals from c petite p scientific i
Definition: afcover.h:80
FT_BBox bbox
Definition: ftbbox.c:467
FT_Face face
Definition: cffdrivr.c:659
#define false
Definition: ftrandom.c:52
kerning y
Definition: ttdriver.c:212
static int ret
Definition: convert.c:72
#define fabs(x)
Definition: cpascal.h:211
unsigned short uint16
Definition: tiff.h:62
long int32
Definition: tiff.h:67
#define qsort
Definition: includes.h:72
#define realloc
Definition: glob.c:206
dictionary ce
Slot * slotref
Definition: Machine.h:80
Definition: bits.h:30
T min(const T a, const T b)
Definition: Main.h:146
T max(const T a, const T b)
Definition: Main.h:152
float sqr(float x)
Definition: Collider.h:225
@ E_BADRULENUM
Definition: Error.h:113
@ E_OUTOFMEM
Definition: Error.h:60
@ E_BADNUMSUCCESS
Definition: Error.h:99
@ E_BADPASSLENGTH
Definition: Error.h:97
@ E_BADNUMSTATES
Definition: Error.h:100
@ E_BADPASSCCODEPTR
Definition: Error.h:105
@ E_BADRULEMAPLEN
Definition: Error.h:102
@ E_BADNUMTRANS
Definition: Error.h:98
@ E_BADCCODELEN
Definition: Error.h:107
@ E_BADCTXTLENS
Definition: Error.h:104
@ E_NORANGES
Definition: Error.h:101
@ E_MUTABLECCODE
Definition: Error.h:109
@ E_BADSTATE
Definition: Error.h:110
@ E_CODEFAILURE
Definition: Error.h:120
@ E_BADEMPTYPASS
Definition: Error.h:115
@ E_BADRANGE
Definition: Error.h:112
@ E_BADNUMCOLUMNS
Definition: Error.h:118
@ E_BADCOLLISIONPASS
Definition: Error.h:117
@ E_BADACTIONCODEPTR
Definition: Error.h:108
@ E_BADRULECCODEPTR
Definition: Error.h:106
@ E_BADRULEMAPPING
Definition: Error.h:111
@ E_BADCTXTLENBOUNDS
Definition: Error.h:103
gr_uint8 uint8
Definition: Main.h:38
@ EC_ASTARTS
Definition: Error.h:54
@ EC_ARULEMAP
Definition: Error.h:56
@ EC_ARULE
Definition: Error.h:53
@ EC_ATRANS
Definition: Error.h:55
@ EC_APASS
Definition: Error.h:51
passtype
Definition: Code.h:44
@ PASS_TYPE_UNKNOWN
Definition: Code.h:45
std::pair< const Segment *const, const Slot *const > dslot
Definition: debug.h:45
gr_uint16 uint16
Definition: Main.h:40
gr_uint32 uint32
Definition: Main.h:41
gr_int32 int32
Definition: Main.h:44
#define version
Definition: nup.c:10
#define codeptr(v)
Definition: obx.h:93
static int delta
Definition: pbmtolj.c:36
static GBool isInit
Definition: pdftoepdf.cc:133
#define zero
static boolean reverse
Definition: ppagelist.c:30
int r
Definition: ppmqvga.c:68
bstring c int memset(void *s, int c, int length)
static int cmpRuleEntry(const void *a, const void *b)
Definition: Pass.cpp:307
Machine::Code Code
Definition: Pass.cpp:43
Slot * output_slot(const SlotMap &slots, const int n)
Definition: Pass.cpp:495
Slot * input_slot(const SlotMap &slots, const int n)
Definition: Pass.cpp:486
static bool inKernCluster(Segment *seg, Slot *s)
Definition: Pass.cpp:929
KernCollison
Definition: Pass.cpp:46
@ CrossSpace
Definition: Pass.cpp:48
@ reserved
Definition: Pass.cpp:50
@ None
Definition: Pass.cpp:47
@ InWord
Definition: Pass.cpp:49
#define dir
#define map
#define smap
#define flags
#define GR_MAYBE_UNUSED
Definition: Main.h:172
slotref slot
Definition: opcodes.h:237
static unsigned long int lc(mp_ptr rp, gmp_randstate_t rstate)
Definition: randlc2x.c:72
state_type states[100]
Definition: routines.c:44
ShellFileEnvironment e
Definition: sh6.c:388
Definition: nsfix.c:44
const Rule * rule
Definition: Rule.h:69
Definition: sh5.c:97
Definition: gd.c:2418
Definition: paths.h:128
Definition: dvips.h:235
static Vector< int > * sort_keys
Definition: t1rewrit.cc:854
m
Definition: tex4ht.c:3990
@ start
Definition: preamble.c:52
PATTERN * pt
Definition: vlna.c:74
#define end(cp)
Definition: zic.c:71