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)  

Collider.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 <algorithm>
28 #include <limits>
29 #include <cmath>
30 #include <string>
31 #include <functional>
32 #include "inc/Collider.h"
33 #include "inc/Segment.h"
34 #include "inc/Slot.h"
35 #include "inc/GlyphCache.h"
36 #include "inc/Sparse.h"
37 
38 #define ISQRT2 0.707106781f
39 
40 // Possible rounding error for subbox boundaries: 0.016 = 1/64 = 1/256 * 4
41 // (values in font range from 0..256)
42 // #define SUBBOX_RND_ERR 0.016
43 
44 using namespace graphite2;
45 
46 //// SHIFT-COLLIDER ////
47 
48 // Initialize the Collider to hold the basic movement limits for the
49 // target slot, the one we are focusing on fixing.
50 bool ShiftCollider::initSlot(Segment *seg, Slot *aSlot, const Rect &limit, float margin, float marginWeight,
51  const Position &currShift, const Position &currOffset, int dir, GR_MAYBE_UNUSED json * const dbgout)
52 {
53  int i;
54  float mx, mn;
55  float a, shift;
56  const GlyphCache &gc = seg->getFace()->glyphs();
57  unsigned short gid = aSlot->gid();
58  if (!gc.check(gid))
59  return false;
60  const BBox &bb = gc.getBoundingBBox(gid);
61  const SlantBox &sb = gc.getBoundingSlantBox(gid);
62  //float sx = aSlot->origin().x + currShift.x;
63  //float sy = aSlot->origin().y + currShift.y;
64  if (currOffset.x != 0.f || currOffset.y != 0.f)
65  _limit = Rect(limit.bl - currOffset, limit.tr - currOffset);
66  else
67  _limit = limit;
68  // For a ShiftCollider, these indices indicate which vector we are moving by:
69  // each _ranges represents absolute space with respect to the origin of the slot. Thus take into account true origins but subtract the vmin for the slot
70  for (i = 0; i < 4; ++i)
71  {
72  switch (i) {
73  case 0 : // x direction
74  mn = _limit.bl.x + currOffset.x;
75  mx = _limit.tr.x + currOffset.x;
76  _len[i] = bb.xa - bb.xi;
77  a = currOffset.y + currShift.y;
78  _ranges[i].initialise<XY>(mn, mx, margin, marginWeight, a);
79  break;
80  case 1 : // y direction
81  mn = _limit.bl.y + currOffset.y;
82  mx = _limit.tr.y + currOffset.y;
83  _len[i] = bb.ya - bb.yi;
84  a = currOffset.x + currShift.x;
85  _ranges[i].initialise<XY>(mn, mx, margin, marginWeight, a);
86  break;
87  case 2 : // sum (negatively sloped diagonal boundaries)
88  // pick closest x,y limit boundaries in s direction
89  shift = currOffset.x + currOffset.y + currShift.x + currShift.y;
90  mn = -2 * min(currShift.x - _limit.bl.x, currShift.y - _limit.bl.y) + shift;
91  mx = 2 * min(_limit.tr.x - currShift.x, _limit.tr.y - currShift.y) + shift;
92  _len[i] = sb.sa - sb.si;
93  a = currOffset.x - currOffset.y + currShift.x - currShift.y;
94  _ranges[i].initialise<SD>(mn, mx, margin / ISQRT2, marginWeight, a);
95  break;
96  case 3 : // diff (positively sloped diagonal boundaries)
97  // pick closest x,y limit boundaries in d direction
98  shift = currOffset.x - currOffset.y + currShift.x - currShift.y;
99  mn = -2 * min(currShift.x - _limit.bl.x, _limit.tr.y - currShift.y) + shift;
100  mx = 2 * min(_limit.tr.x - currShift.x, currShift.y - _limit.bl.y) + shift;
101  _len[i] = sb.da - sb.di;
102  a = currOffset.x + currOffset.y + currShift.x + currShift.y;
103  _ranges[i].initialise<SD>(mn, mx, margin / ISQRT2, marginWeight, a);
104  break;
105  }
106  }
107 
108  _target = aSlot;
109  if ((dir & 1) == 0)
110  {
111  // For LTR, switch and negate x limits.
112  _limit.bl.x = -1 * limit.tr.x;
113  //_limit.tr.x = -1 * limit.bl.x;
114  }
115  _currOffset = currOffset;
116  _currShift = currShift;
117  _origin = aSlot->origin() - currOffset; // the original anchor position of the glyph
118 
119  _margin = margin;
120  _marginWt = marginWeight;
121 
122  SlotCollision *c = seg->collisionInfo(aSlot);
123  _seqClass = c->seqClass();
124  _seqProxClass = c->seqProxClass();
125  _seqOrder = c->seqOrder();
126  return true;
127 }
128 
129 template <class O>
130 float sdm(float vi, float va, float mx, float my, O op)
131 {
132  float res = 2 * mx - vi;
133  if (op(res, vi + 2 * my))
134  {
135  res = va + 2 * my;
136  if (op(res, 2 * mx - va))
137  res = mx + my;
138  }
139  return res;
140 }
141 
142 // Mark an area with a cost that can vary along the x or y axis. The region is expressed in terms of the centre of the target glyph in each axis
143 void ShiftCollider::addBox_slope(bool isx, const Rect &box, const BBox &bb, const SlantBox &sb, const Position &org, float weight, float m, bool minright, int axis)
144 {
145  float a, c;
146  switch (axis) {
147  case 0 :
148  if (box.bl.y < org.y + bb.ya && box.tr.y > org.y + bb.yi && box.width() > 0)
149  {
150  a = org.y + 0.5f * (bb.yi + bb.ya);
151  c = 0.5f * (bb.xi + bb.xa);
152  if (isx)
153  _ranges[axis].weighted<XY>(box.bl.x - c, box.tr.x - c, weight, a, m,
154  (minright ? box.tr.x : box.bl.x) - c, a, 0, false);
155  else
156  _ranges[axis].weighted<XY>(box.bl.x - c, box.tr.x - c, weight, a, 0, 0, org.y,
157  m * (a * a + sqr((minright ? box.tr.y : box.bl.y) - 0.5f * (bb.yi + bb.ya))), false);
158  }
159  break;
160  case 1 :
161  if (box.bl.x < org.x + bb.xa && box.tr.x > org.x + bb.xi && box.height() > 0)
162  {
163  a = org.x + 0.5f * (bb.xi + bb.xa);
164  c = 0.5f * (bb.yi + bb.ya);
165  if (isx)
166  _ranges[axis].weighted<XY>(box.bl.y - c, box.tr.y - c, weight, a, 0, 0, org.x,
167  m * (a * a + sqr((minright ? box.tr.x : box.bl.x) - 0.5f * (bb.xi + bb.xa))), false);
168  else
169  _ranges[axis].weighted<XY>(box.bl.y - c, box.tr.y - c, weight, a, m,
170  (minright ? box.tr.y : box.bl.y) - c, a, 0, false);
171  }
172  break;
173  case 2 :
174  if (box.bl.x - box.tr.y < org.x - org.y + sb.da && box.tr.x - box.bl.y > org.x - org.y + sb.di)
175  {
176  float d = org.x - org.y + 0.5f * (sb.di + sb.da);
177  c = 0.5f * (sb.si + sb.sa);
178  float smax = min(2 * box.tr.x - d, 2 * box.tr.y + d);
179  float smin = max(2 * box.bl.x - d, 2 * box.bl.y + d);
180  if (smin > smax) return;
181  float si;
182  a = d;
183  if (isx)
184  si = 2 * (minright ? box.tr.x : box.bl.x) - a;
185  else
186  si = 2 * (minright ? box.tr.y : box.bl.y) + a;
187  _ranges[axis].weighted<SD>(smin - c, smax - c, weight / 2, a, m / 2, si, 0, 0, isx);
188  }
189  break;
190  case 3 :
191  if (box.bl.x + box.bl.y < org.x + org.y + sb.sa && box.tr.x + box.tr.y > org.x + org.y + sb.si)
192  {
193  float s = org.x + org.y + 0.5f * (sb.si + sb.sa);
194  c = 0.5f * (sb.di + sb.da);
195  float dmax = min(2 * box.tr.x - s, s - 2 * box.bl.y);
196  float dmin = max(2 * box.bl.x - s, s - 2 * box.tr.y);
197  if (dmin > dmax) return;
198  float di;
199  a = s;
200  if (isx)
201  di = 2 * (minright ? box.tr.x : box.bl.x) - a;
202  else
203  di = 2 * (minright ? box.tr.y : box.bl.y) + a;
204  _ranges[axis].weighted<SD>(dmin - c, dmax - c, weight / 2, a, m / 2, di, 0, 0, !isx);
205  }
206  break;
207  default :
208  break;
209  }
210  return;
211 }
212 
213 // Mark an area with an absolute cost, making it completely inaccessible.
214 inline void ShiftCollider::removeBox(const Rect &box, const BBox &bb, const SlantBox &sb, const Position &org, int axis)
215 {
216  float c;
217  switch (axis) {
218  case 0 :
219  if (box.bl.y < org.y + bb.ya && box.tr.y > org.y + bb.yi && box.width() > 0)
220  {
221  c = 0.5f * (bb.xi + bb.xa);
222  _ranges[axis].exclude(box.bl.x - c, box.tr.x - c);
223  }
224  break;
225  case 1 :
226  if (box.bl.x < org.x + bb.xa && box.tr.x > org.x + bb.xi && box.height() > 0)
227  {
228  c = 0.5f * (bb.yi + bb.ya);
229  _ranges[axis].exclude(box.bl.y - c, box.tr.y - c);
230  }
231  break;
232  case 2 :
233  if (box.bl.x - box.tr.y < org.x - org.y + sb.da && box.tr.x - box.bl.y > org.x - org.y + sb.di
234  && box.width() > 0 && box.height() > 0)
235  {
236  float di = org.x - org.y + sb.di;
237  float da = org.x - org.y + sb.da;
238  float smax = sdm(di, da, box.tr.x, box.tr.y, std::greater<float>());
239  float smin = sdm(da, di, box.bl.x, box.bl.y, std::less<float>());
240  c = 0.5f * (sb.si + sb.sa);
241  _ranges[axis].exclude(smin - c, smax - c);
242  }
243  break;
244  case 3 :
245  if (box.bl.x + box.bl.y < org.x + org.y + sb.sa && box.tr.x + box.tr.y > org.x + org.y + sb.si
246  && box.width() > 0 && box.height() > 0)
247  {
248  float si = org.x + org.y + sb.si;
249  float sa = org.x + org.y + sb.sa;
250  float dmax = sdm(si, sa, box.tr.x, -box.bl.y, std::greater<float>());
251  float dmin = sdm(sa, si, box.bl.x, -box.tr.y, std::less<float>());
252  c = 0.5f * (sb.di + sb.da);
253  _ranges[axis].exclude(dmin - c, dmax - c);
254  }
255  break;
256  default :
257  break;
258  }
259  return;
260 }
261 
262 // Adjust the movement limits for the target to avoid having it collide
263 // with the given neighbor slot. Also determine if there is in fact a collision
264 // between the target and the given slot.
265 bool ShiftCollider::mergeSlot(Segment *seg, Slot *slot, const SlotCollision *cslot, const Position &currShift,
266  bool isAfter, // slot is logically after _target
267  bool sameCluster, bool &hasCol, bool isExclusion,
268  GR_MAYBE_UNUSED json * const dbgout )
269 {
270  bool isCol = false;
271  const float sx = slot->origin().x - _origin.x + currShift.x;
272  const float sy = slot->origin().y - _origin.y + currShift.y;
273  const float sd = sx - sy;
274  const float ss = sx + sy;
275  float vmin, vmax;
276  float omin, omax, otmin, otmax;
277  float cmin, cmax; // target limits
278  float torg;
279  const GlyphCache &gc = seg->getFace()->glyphs();
280  const unsigned short gid = slot->gid();
281  if (!gc.check(gid))
282  return false;
283  const BBox &bb = gc.getBoundingBBox(gid);
284 
285  // SlotCollision * cslot = seg->collisionInfo(slot);
286  int orderFlags = 0;
287  bool sameClass = _seqProxClass == 0 && cslot->seqClass() == _seqClass;
288  if (sameCluster && _seqClass
289  && (sameClass || (_seqProxClass != 0 && cslot->seqClass() == _seqProxClass)))
290  // Force the target glyph to be in the specified direction from the slot we're testing.
291  orderFlags = _seqOrder;
292 
293  // short circuit if only interested in direct collision and we are out of range
294  if (orderFlags || (sx + bb.xa + _margin >= _limit.bl.x && sx + bb.xi - _margin <= _limit.tr.x)
295  || (sy + bb.ya + _margin >= _limit.bl.y && sy + bb.yi - _margin <= _limit.tr.y))
296 
297  {
298  const float tx = _currOffset.x + _currShift.x;
299  const float ty = _currOffset.y + _currShift.y;
300  const float td = tx - ty;
301  const float ts = tx + ty;
302  const SlantBox &sb = gc.getBoundingSlantBox(gid);
303  const unsigned short tgid = _target->gid();
304  const BBox &tbb = gc.getBoundingBBox(tgid);
305  const SlantBox &tsb = gc.getBoundingSlantBox(tgid);
306  float seq_above_wt = cslot->seqAboveWt();
307  float seq_below_wt = cslot->seqBelowWt();
308  float seq_valign_wt = cslot->seqValignWt();
309  float lmargin;
310  // if isAfter, invert orderFlags for diagonal orders.
311  if (isAfter)
312  {
313  // invert appropriate bits
314  orderFlags ^= (sameClass ? 0x3F : 0x3);
315  // consider 2 bits at a time, non overlapping. If both bits set, clear them
316  orderFlags = orderFlags ^ ((((orderFlags >> 1) & orderFlags) & 0x15) * 3);
317  }
318 
319 #if !defined GRAPHITE2_NTRACING
320  if (dbgout)
321  dbgout->setenv(0, slot);
322 #endif
323 
324  // Process main bounding octabox.
325  for (int i = 0; i < 4; ++i)
326  {
327  switch (i) {
328  case 0 : // x direction
329  vmin = max(max(bb.xi - tbb.xa + sx, sb.di - tsb.da + ty + sd), sb.si - tsb.sa - ty + ss);
330  vmax = min(min(bb.xa - tbb.xi + sx, sb.da - tsb.di + ty + sd), sb.sa - tsb.si - ty + ss);
331  otmin = tbb.yi + ty;
332  otmax = tbb.ya + ty;
333  omin = bb.yi + sy;
334  omax = bb.ya + sy;
335  torg = _currOffset.x;
336  cmin = _limit.bl.x + torg;
337  cmax = _limit.tr.x - tbb.xi + tbb.xa + torg;
338  lmargin = _margin;
339  break;
340  case 1 : // y direction
341  vmin = max(max(bb.yi - tbb.ya + sy, tsb.di - sb.da + tx - sd), sb.si - tsb.sa - tx + ss);
342  vmax = min(min(bb.ya - tbb.yi + sy, tsb.da - sb.di + tx - sd), sb.sa - tsb.si - tx + ss);
343  otmin = tbb.xi + tx;
344  otmax = tbb.xa + tx;
345  omin = bb.xi + sx;
346  omax = bb.xa + sx;
347  torg = _currOffset.y;
348  cmin = _limit.bl.y + torg;
349  cmax = _limit.tr.y - tbb.yi + tbb.ya + torg;
350  lmargin = _margin;
351  break;
352  case 2 : // sum - moving along the positively-sloped vector, so the boundaries are the
353  // negatively-sloped boundaries.
354  vmin = max(max(sb.si - tsb.sa + ss, 2 * (bb.yi - tbb.ya + sy) + td), 2 * (bb.xi - tbb.xa + sx) - td);
355  vmax = min(min(sb.sa - tsb.si + ss, 2 * (bb.ya - tbb.yi + sy) + td), 2 * (bb.xa - tbb.xi + sx) - td);
356  otmin = tsb.di + td;
357  otmax = tsb.da + td;
358  omin = sb.di + sd;
359  omax = sb.da + sd;
360  torg = _currOffset.x + _currOffset.y;
361  cmin = _limit.bl.x + _limit.bl.y + torg;
362  cmax = _limit.tr.x + _limit.tr.y - tsb.si + tsb.sa + torg;
363  lmargin = _margin / ISQRT2;
364  break;
365  case 3 : // diff - moving along the negatively-sloped vector, so the boundaries are the
366  // positively-sloped boundaries.
367  vmin = max(max(sb.di - tsb.da + sd, 2 * (bb.xi - tbb.xa + sx) - ts), -2 * (bb.ya - tbb.yi + sy) + ts);
368  vmax = min(min(sb.da - tsb.di + sd, 2 * (bb.xa - tbb.xi + sx) - ts), -2 * (bb.yi - tbb.ya + sy) + ts);
369  otmin = tsb.si + ts;
370  otmax = tsb.sa + ts;
371  omin = sb.si + ss;
372  omax = sb.sa + ss;
373  torg = _currOffset.x - _currOffset.y;
374  cmin = _limit.bl.x - _limit.tr.y + torg;
375  cmax = _limit.tr.x - _limit.bl.y - tsb.di + tsb.da + torg;
376  lmargin = _margin / ISQRT2;
377  break;
378  default :
379  continue;
380  }
381 
382 #if !defined GRAPHITE2_NTRACING
383  if (dbgout)
384  dbgout->setenv(1, reinterpret_cast<void *>(-1));
385 #define DBGTAG(x) if (dbgout) dbgout->setenv(1, reinterpret_cast<void *>(-x));
386 #else
387 #define DBGTAG(x)
388 #endif
389 
390  if (orderFlags)
391  {
392  Position org(tx, ty);
393  float xminf = _limit.bl.x + _currOffset.x + tbb.xi;
394  float xpinf = _limit.tr.x + _currOffset.x + tbb.xa;
395  float ypinf = _limit.tr.y + _currOffset.y + tbb.ya;
396  float yminf = _limit.bl.y + _currOffset.y + tbb.yi;
397  switch (orderFlags) {
399  {
400  float r1Xedge = cslot->seqAboveXoff() + 0.5f * (bb.xi + bb.xa) + sx;
401  float r3Xedge = cslot->seqBelowXlim() + bb.xa + sx + 0.5f * (tbb.xa - tbb.xi);
402  float r2Yedge = 0.5f * (bb.yi + bb.ya) + sy;
403 
404  // DBGTAG(1x) means the regions are up and right
405  // region 1
406  DBGTAG(11)
407  addBox_slope(true, Rect(Position(xminf, r2Yedge), Position(r1Xedge, ypinf)),
408  tbb, tsb, org, 0, seq_above_wt, true, i);
409  // region 2
410  DBGTAG(12)
411  removeBox(Rect(Position(xminf, yminf), Position(r3Xedge, r2Yedge)), tbb, tsb, org, i);
412  // region 3, which end is zero is irrelevant since m weight is 0
413  DBGTAG(13)
414  addBox_slope(true, Rect(Position(r3Xedge, yminf), Position(xpinf, r2Yedge - cslot->seqValignHt())),
415  tbb, tsb, org, seq_below_wt, 0, true, i);
416  // region 4
417  DBGTAG(14)
418  addBox_slope(false, Rect(Position(sx + bb.xi, r2Yedge), Position(xpinf, r2Yedge + cslot->seqValignHt())),
419  tbb, tsb, org, 0, seq_valign_wt, true, i);
420  // region 5
421  DBGTAG(15)
422  addBox_slope(false, Rect(Position(sx + bb.xi, r2Yedge - cslot->seqValignHt()), Position(xpinf, r2Yedge)),
423  tbb, tsb, org, seq_below_wt, seq_valign_wt, false, i);
424  break;
425  }
426  case SlotCollision::SEQ_ORDER_LEFTDOWN :
427  {
428  float r1Xedge = 0.5f * (bb.xi + bb.xa) + cslot->seqAboveXoff() + sx;
429  float r3Xedge = bb.xi - cslot->seqBelowXlim() + sx - 0.5f * (tbb.xa - tbb.xi);
430  float r2Yedge = 0.5f * (bb.yi + bb.ya) + sy;
431  // DBGTAG(2x) means the regions are up and right
432  // region 1
433  DBGTAG(21)
434  addBox_slope(true, Rect(Position(r1Xedge, yminf), Position(xpinf, r2Yedge)),
435  tbb, tsb, org, 0, seq_above_wt, false, i);
436  // region 2
437  DBGTAG(22)
438  removeBox(Rect(Position(r3Xedge, r2Yedge), Position(xpinf, ypinf)), tbb, tsb, org, i);
439  // region 3
440  DBGTAG(23)
441  addBox_slope(true, Rect(Position(xminf, r2Yedge - cslot->seqValignHt()), Position(r3Xedge, ypinf)),
442  tbb, tsb, org, seq_below_wt, 0, false, i);
443  // region 4
444  DBGTAG(24)
445  addBox_slope(false, Rect(Position(xminf, r2Yedge), Position(sx + bb.xa, r2Yedge + cslot->seqValignHt())),
446  tbb, tsb, org, 0, seq_valign_wt, true, i);
447  // region 5
448  DBGTAG(25)
449  addBox_slope(false, Rect(Position(xminf, r2Yedge - cslot->seqValignHt()),
450  Position(sx + bb.xa, r2Yedge)), tbb, tsb, org, seq_below_wt, seq_valign_wt, false, i);
451  break;
452  }
453  case SlotCollision::SEQ_ORDER_NOABOVE : // enforce neighboring glyph being above
454  DBGTAG(31);
455  removeBox(Rect(Position(bb.xi - tbb.xa + sx, sy + bb.ya),
456  Position(bb.xa - tbb.xi + sx, ypinf)), tbb, tsb, org, i);
457  break;
458  case SlotCollision::SEQ_ORDER_NOBELOW : // enforce neighboring glyph being below
459  DBGTAG(32);
460  removeBox(Rect(Position(bb.xi - tbb.xa + sx, yminf),
461  Position(bb.xa - tbb.xi + sx, sy + bb.yi)), tbb, tsb, org, i);
462  break;
463  case SlotCollision::SEQ_ORDER_NOLEFT : // enforce neighboring glyph being to the left
464  DBGTAG(33)
465  removeBox(Rect(Position(xminf, bb.yi - tbb.ya + sy),
466  Position(bb.xi - tbb.xa + sx, bb.ya - tbb.yi + sy)), tbb, tsb, org, i);
467  break;
468  case SlotCollision::SEQ_ORDER_NORIGHT : // enforce neighboring glyph being to the right
469  DBGTAG(34)
470  removeBox(Rect(Position(bb.xa - tbb.xi + sx, bb.yi - tbb.ya + sy),
471  Position(xpinf, bb.ya - tbb.yi + sy)), tbb, tsb, org, i);
472  break;
473  default :
474  break;
475  }
476  }
477 
478  if (vmax < cmin - lmargin || vmin > cmax + lmargin || omax < otmin - lmargin || omin > otmax + lmargin)
479  continue;
480 
481  // Process sub-boxes that are defined for this glyph.
482  // We only need to do this if there was in fact a collision with the main octabox.
483  uint8 numsub = gc.numSubBounds(gid);
484  if (numsub > 0)
485  {
486  bool anyhits = false;
487  for (int j = 0; j < numsub; ++j)
488  {
489  const BBox &sbb = gc.getSubBoundingBBox(gid, j);
490  const SlantBox &ssb = gc.getSubBoundingSlantBox(gid, j);
491  switch (i) {
492  case 0 : // x
493  vmin = max(max(sbb.xi-tbb.xa+sx, ssb.di-tsb.da+sd+ty), ssb.si-tsb.sa+ss-ty);
494  vmax = min(min(sbb.xa-tbb.xi+sx, ssb.da-tsb.di+sd+ty), ssb.sa-tsb.si+ss-ty);
495  omin = sbb.yi + sy;
496  omax = sbb.ya + sy;
497  break;
498  case 1 : // y
499  vmin = max(max(sbb.yi-tbb.ya+sy, tsb.di-ssb.da-sd+tx), ssb.si-tsb.sa+ss-tx);
500  vmax = min(min(sbb.ya-tbb.yi+sy, tsb.da-ssb.di-sd+tx), ssb.sa-tsb.si+ss-tx);
501  omin = sbb.xi + sx;
502  omax = sbb.xa + sx;
503  break;
504  case 2 : // sum
505  vmin = max(max(ssb.si-tsb.sa+ss, 2*(sbb.yi-tbb.ya+sy)+td), 2*(sbb.xi-tbb.xa+sx)-td);
506  vmax = min(min(ssb.sa-tsb.si+ss, 2*(sbb.ya-tbb.yi+sy)+td), 2*(sbb.xa-tbb.xi+sx)-td);
507  omin = ssb.di + sd;
508  omax = ssb.da + sd;
509  break;
510  case 3 : // diff
511  vmin = max(max(ssb.di-tsb.da+sd, 2*(sbb.xi-tbb.xa+sx)-ts), -2*(sbb.ya-tbb.yi+sy)+ts);
512  vmax = min(min(ssb.da-tsb.di+sd, 2*(sbb.xa-tbb.xi+sx)-ts), -2*(sbb.yi-tbb.ya+sy)+ts);
513  omin = ssb.si + ss;
514  omax = ssb.sa + ss;
515  break;
516  }
517  if (vmax < cmin - lmargin || vmin > cmax + lmargin || omax < otmin - lmargin || omin > otmax + lmargin)
518  continue;
519 
520 #if !defined GRAPHITE2_NTRACING
521  if (dbgout)
522  dbgout->setenv(1, reinterpret_cast<void *>(j));
523 #endif
524  if (omin > otmax)
525  _ranges[i].weightedAxis(i, vmin - lmargin, vmax + lmargin, 0, 0, 0, 0, 0,
526  sqr(lmargin - omin + otmax) * _marginWt, false);
527  else if (omax < otmin)
528  _ranges[i].weightedAxis(i, vmin - lmargin, vmax + lmargin, 0, 0, 0, 0, 0,
529  sqr(lmargin - otmin + omax) * _marginWt, false);
530  else
531  _ranges[i].exclude_with_margins(vmin, vmax, i);
532  anyhits = true;
533  }
534  if (anyhits)
535  isCol = true;
536  }
537  else // no sub-boxes
538  {
539 #if !defined GRAPHITE2_NTRACING
540  if (dbgout)
541  dbgout->setenv(1, reinterpret_cast<void *>(-1));
542 #endif
543  isCol = true;
544  if (omin > otmax)
545  _ranges[i].weightedAxis(i, vmin - lmargin, vmax + lmargin, 0, 0, 0, 0, 0,
546  sqr(lmargin - omin + otmax) * _marginWt, false);
547  else if (omax < otmin)
548  _ranges[i].weightedAxis(i, vmin - lmargin, vmax + lmargin, 0, 0, 0, 0, 0,
549  sqr(lmargin - otmin + omax) * _marginWt, false);
550  else
551  _ranges[i].exclude_with_margins(vmin, vmax, i);
552 
553  }
554  }
555  }
556  bool res = true;
557  if (cslot->exclGlyph() > 0 && gc.check(cslot->exclGlyph()) && !isExclusion)
558  {
559  // Set up the bogus slot representing the exclusion glyph.
560  Slot *exclSlot = seg->newSlot();
561  if (!exclSlot)
562  return res;
563  exclSlot->setGlyph(seg, cslot->exclGlyph());
564  Position exclOrigin(slot->origin() + cslot->exclOffset());
565  exclSlot->origin(exclOrigin);
566  SlotCollision exclInfo(seg, exclSlot);
567  res &= mergeSlot(seg, exclSlot, &exclInfo, currShift, isAfter, sameCluster, isCol, true, dbgout );
568  seg->freeSlot(exclSlot);
569  }
570  hasCol |= isCol;
571  return res;
572 
573 } // end of ShiftCollider::mergeSlot
574 
575 
576 // Figure out where to move the target glyph to, and return the amount to shift by.
578 {
579  float tbase;
580  float totalCost = (float)(std::numeric_limits<float>::max() / 2);
581  Position resultPos = Position(0, 0);
582 #if !defined GRAPHITE2_NTRACING
583  int bestAxis = -1;
584  if (dbgout)
585  {
586  outputJsonDbgStartSlot(dbgout, seg);
587  *dbgout << "vectors" << json::array;
588  }
589 #endif
590  isCol = true;
591  for (int i = 0; i < 4; ++i)
592  {
593  float bestCost = -1;
594  float bestPos;
595  // Calculate the margin depending on whether we are moving diagonally or not:
596  switch (i) {
597  case 0 : // x direction
598  tbase = _currOffset.x;
599  break;
600  case 1 : // y direction
601  tbase = _currOffset.y;
602  break;
603  case 2 : // sum (negatively-sloped diagonals)
604  tbase = _currOffset.x + _currOffset.y;
605  break;
606  case 3 : // diff (positively-sloped diagonals)
607  tbase = _currOffset.x - _currOffset.y;
608  break;
609  }
610  Position testp;
611  bestPos = _ranges[i].closest(0, bestCost) - tbase; // Get the best relative position
612 #if !defined GRAPHITE2_NTRACING
613  if (dbgout)
614  outputJsonDbgOneVector(dbgout, seg, i, tbase, bestCost, bestPos) ;
615 #endif
616  if (bestCost >= 0.0f)
617  {
618  isCol = false;
619  switch (i) {
620  case 0 : testp = Position(bestPos, _currShift.y); break;
621  case 1 : testp = Position(_currShift.x, bestPos); break;
622  case 2 : testp = Position(0.5f * (_currShift.x - _currShift.y + bestPos), 0.5f * (_currShift.y - _currShift.x + bestPos)); break;
623  case 3 : testp = Position(0.5f * (_currShift.x + _currShift.y + bestPos), 0.5f * (_currShift.x + _currShift.y - bestPos)); break;
624  }
625  if (bestCost < totalCost - 0.01f)
626  {
627  totalCost = bestCost;
628  resultPos = testp;
629 #if !defined GRAPHITE2_NTRACING
630  bestAxis = i;
631 #endif
632  }
633  }
634  } // end of loop over 4 directions
635 
636 #if !defined GRAPHITE2_NTRACING
637  if (dbgout)
638  outputJsonDbgEndSlot(dbgout, resultPos, bestAxis, isCol);
639 #endif
640 
641  return resultPos;
642 
643 } // end of ShiftCollider::resolve
644 
645 
646 #if !defined GRAPHITE2_NTRACING
647 
648 void ShiftCollider::outputJsonDbg(json * const dbgout, Segment *seg, int axis)
649 {
650  int axisMax = axis;
651  if (axis < 0) // output all axes
652  {
653  *dbgout << "gid" << _target->gid()
654  << "limit" << _limit
655  << "target" << json::object
656  << "origin" << _target->origin()
657  << "margin" << _margin
658  << "bbox" << seg->theGlyphBBoxTemporary(_target->gid())
659  << "slantbox" << seg->getFace()->glyphs().slant(_target->gid())
660  << json::close; // target object
661  *dbgout << "ranges" << json::array;
662  axis = 0;
663  axisMax = 3;
664  }
665  for (int iAxis = axis; iAxis <= axisMax; ++iAxis)
666  {
667  *dbgout << json::flat << json::array << _ranges[iAxis].position();
668  for (Zones::const_iterator s = _ranges[iAxis].begin(), e = _ranges[iAxis].end(); s != e; ++s)
669  *dbgout << json::flat << json::array
670  << Position(s->x, s->xm) << s->sm << s->smx << s->c
671  << json::close;
672  *dbgout << json::close;
673  }
674  if (axis < axisMax) // looped through the _ranges array for all axes
675  *dbgout << json::close; // ranges array
676 }
677 
679 {
680  *dbgout << json::object // slot - not closed till the end of the caller method
681  << "slot" << objectid(dslot(seg, _target))
682  << "gid" << _target->gid()
683  << "limit" << _limit
684  << "target" << json::object
685  << "origin" << _origin
686  << "currShift" << _currShift
687  << "currOffset" << seg->collisionInfo(_target)->offset()
688  << "bbox" << seg->theGlyphBBoxTemporary(_target->gid())
689  << "slantBox" << seg->getFace()->glyphs().slant(_target->gid())
690  << "fix" << "shift";
691  *dbgout << json::close; // target object
692 }
693 
695  Position resultPos, int bestAxis, bool isCol)
696 {
697  *dbgout << json::close // vectors array
698  << "result" << resultPos
699  //<< "scraping" << _scraping[bestAxis]
700  << "bestAxis" << bestAxis
701  << "stillBad" << isCol
702  << json::close; // slot object
703 }
704 
705 void ShiftCollider::outputJsonDbgOneVector(json * const dbgout, Segment *seg, int axis,
706  float tleft, float bestCost, float bestVal)
707 {
708  const char * label;
709  switch (axis)
710  {
711  case 0: label = "x"; break;
712  case 1: label = "y"; break;
713  case 2: label = "sum (NE-SW)"; break;
714  case 3: label = "diff (NW-SE)"; break;
715  default: label = "???"; break;
716  }
717 
718  *dbgout << json::object // vector
719  << "direction" << label
720  << "targetMin" << tleft;
721 
722  outputJsonDbgRemovals(dbgout, axis, seg);
723 
724  *dbgout << "ranges";
725  outputJsonDbg(dbgout, seg, axis);
726 
727  *dbgout << "bestCost" << bestCost
728  << "bestVal" << bestVal + tleft
729  << json::close; // vectors object
730 }
731 
732 void ShiftCollider::outputJsonDbgRemovals(json * const dbgout, int axis, Segment *seg)
733 {
734  *dbgout << "removals" << json::array;
735  _ranges[axis].jsonDbgOut(seg);
736  *dbgout << json::close; // removals array
737 }
738 
739 #endif // !defined GRAPHITE2_NTRACING
740 
741 
742 //// KERN-COLLIDER ////
743 
744 inline
745 static float localmax (float al, float au, float bl, float bu, float x)
746 {
747  if (al < bl)
748  { if (au < bu) return au < x ? au : x; }
749  else if (au > bu) return bl < x ? bl : x;
750  return x;
751 }
752 
753 inline
754 static float localmin(float al, float au, float bl, float bu, float x)
755 {
756  if (bl > al)
757  { if (bu > au) return bl > x ? bl : x; }
758  else if (au > bu) return al > x ? al : x;
759  return x;
760 }
761 
762 // Return the given edge of the glyph at height y, taking any slant box into account.
763 static float get_edge(Segment *seg, const Slot *s, const Position &shift, float y, float width, float margin, bool isRight)
764 {
765  const GlyphCache &gc = seg->getFace()->glyphs();
766  unsigned short gid = s->gid();
767  float sx = s->origin().x + shift.x;
768  float sy = s->origin().y + shift.y;
769  uint8 numsub = gc.numSubBounds(gid);
770  float res = isRight ? (float)-1e38 : (float)1e38;
771 
772  if (numsub > 0)
773  {
774  for (int i = 0; i < numsub; ++i)
775  {
776  const BBox &sbb = gc.getSubBoundingBBox(gid, i);
777  const SlantBox &ssb = gc.getSubBoundingSlantBox(gid, i);
778  if (sy + sbb.yi - margin > y + width / 2 || sy + sbb.ya + margin < y - width / 2)
779  continue;
780  if (isRight)
781  {
782  float x = sx + sbb.xa + margin;
783  if (x > res)
784  {
785  float td = sx - sy + ssb.da + margin + y;
786  float ts = sx + sy + ssb.sa + margin - y;
787  x = localmax(td - width / 2, td + width / 2, ts - width / 2, ts + width / 2, x);
788  if (x > res)
789  res = x;
790  }
791  }
792  else
793  {
794  float x = sx + sbb.xi - margin;
795  if (x < res)
796  {
797  float td = sx - sy + ssb.di - margin + y;
798  float ts = sx + sy + ssb.si - margin - y;
799  x = localmin(td - width / 2, td + width / 2, ts - width / 2, ts + width / 2, x);
800  if (x < res)
801  res = x;
802  }
803  }
804  }
805  }
806  else
807  {
808  const BBox &bb = gc.getBoundingBBox(gid);
809  const SlantBox &sb = gc.getBoundingSlantBox(gid);
810  if (sy + bb.yi - margin > y + width / 2 || sy + bb.ya + margin < y - width / 2)
811  return res;
812  float td = sx - sy + y;
813  float ts = sx + sy - y;
814  if (isRight)
815  res = localmax(td + sb.da - width / 2, td + sb.da + width / 2, ts + sb.sa - width / 2, ts + sb.sa + width / 2, sx + bb.xa) + margin;
816  else
817  res = localmin(td + sb.di - width / 2, td + sb.di + width / 2, ts + sb.si - width / 2, ts + sb.si + width / 2, sx + bb.xi) - margin;
818  }
819  return res;
820 }
821 
822 
823 bool KernCollider::initSlot(Segment *seg, Slot *aSlot, const Rect &limit, float margin,
824  const Position &currShift, const Position &offsetPrev, int dir,
825  float ymin, float ymax, GR_MAYBE_UNUSED json * const dbgout)
826 {
827  const GlyphCache &gc = seg->getFace()->glyphs();
828  const Slot *base = aSlot;
829  // const Slot *last = aSlot;
830  const Slot *s;
831  int numSlices;
832  while (base->attachedTo())
833  base = base->attachedTo();
834  if (margin < 10) margin = 10;
835 
836  _limit = limit;
837  _offsetPrev = offsetPrev; // kern from a previous pass
838 
839  // Calculate the height of the glyph and how many horizontal slices to use.
840  if (_maxy >= 1e37f)
841  {
842  _sliceWidth = margin / 1.5f;
843  _maxy = ymax + margin;
844  _miny = ymin - margin;
845  numSlices = int((_maxy - _miny + 2) / (_sliceWidth / 1.5f) + 1.f); // +2 helps with rounding errors
846  _edges.clear();
847  _edges.insert(_edges.begin(), numSlices, (dir & 1) ? 1e38f : -1e38f);
848  _xbound = (dir & 1) ? (float)1e38f : (float)-1e38f;
849  }
850  else if (_maxy != ymax || _miny != ymin)
851  {
852  if (_miny != ymin)
853  {
854  numSlices = int((ymin - margin - _miny) / _sliceWidth - 1);
855  _miny += numSlices * _sliceWidth;
856  if (numSlices < 0)
857  _edges.insert(_edges.begin(), -numSlices, (dir & 1) ? 1e38f : -1e38f);
858  else if ((unsigned)numSlices < _edges.size()) // this shouldn't fire since we always grow the range
859  {
860  Vector<float>::iterator e = _edges.begin();
861  while (numSlices--)
862  ++e;
863  _edges.erase(_edges.begin(), e);
864  }
865  }
866  if (_maxy != ymax)
867  {
868  numSlices = int((ymax + margin - _miny) / _sliceWidth + 1);
869  _maxy = numSlices * _sliceWidth + _miny;
870  if (numSlices > (int)_edges.size())
871  _edges.insert(_edges.end(), numSlices - _edges.size(), (dir & 1) ? 1e38f : -1e38f);
872  else if (numSlices < (int)_edges.size()) // this shouldn't fire since we always grow the range
873  {
874  while ((int)_edges.size() > numSlices)
875  _edges.pop_back();
876  }
877  }
878  goto done;
879  }
880  numSlices = int(_edges.size());
881 
882 #if !defined GRAPHITE2_NTRACING
883  // Debugging
884  _seg = seg;
885  _slotNear.clear();
886  _slotNear.insert(_slotNear.begin(), numSlices, NULL);
887  _nearEdges.clear();
888  _nearEdges.insert(_nearEdges.begin(), numSlices, (dir & 1) ? -1e38f : +1e38f);
889 #endif
890 
891  // Determine the trailing edge of each slice (ie, left edge for a RTL glyph).
892  for (s = base; s; s = s->nextInCluster(s))
893  {
894  SlotCollision *c = seg->collisionInfo(s);
895  if (!gc.check(s->gid()))
896  return false;
897  const BBox &bs = gc.getBoundingBBox(s->gid());
898  float x = s->origin().x + c->shift().x + ((dir & 1) ? bs.xi : bs.xa);
899  // Loop over slices.
900  // Note smin might not be zero if glyph s is not at the bottom of the cluster; similarly for smax.
901  float toffset = c->shift().y - _miny + 1 + s->origin().y;
902  int smin = max(0, int((bs.yi + toffset) / _sliceWidth));
903  int smax = min(numSlices - 1, int((bs.ya + toffset) / _sliceWidth + 1));
904  for (int i = smin; i <= smax; ++i)
905  {
906  float t;
907  float y = _miny - 1 + (i + .5f) * _sliceWidth; // vertical center of slice
908  if ((dir & 1) && x < _edges[i])
909  {
910  t = get_edge(seg, s, c->shift(), y, _sliceWidth, margin, false);
911  if (t < _edges[i])
912  {
913  _edges[i] = t;
914  if (t < _xbound)
915  _xbound = t;
916  }
917  }
918  else if (!(dir & 1) && x > _edges[i])
919  {
920  t = get_edge(seg, s, c->shift(), y, _sliceWidth, margin, true);
921  if (t > _edges[i])
922  {
923  _edges[i] = t;
924  if (t > _xbound)
925  _xbound = t;
926  }
927  }
928  }
929  }
930  done:
931  _mingap = (float)1e37; // less than 1e38 s.t. 1e38-_mingap is really big
932  _target = aSlot;
933  _margin = margin;
934  _currShift = currShift;
935  return true;
936 } // end of KernCollider::initSlot
937 
938 
939 // Determine how much the target slot needs to kern away from the given slot.
940 // In other words, merge information from given slot's position with what the target slot knows
941 // about how it can kern.
942 // Return false if we know there is no collision, true if we think there might be one.
943 bool KernCollider::mergeSlot(Segment *seg, Slot *slot, const Position &currShift, float currSpace, int dir, GR_MAYBE_UNUSED json * const dbgout)
944 {
945  int rtl = (dir & 1) * 2 - 1;
946  if (!seg->getFace()->glyphs().check(slot->gid()))
947  return false;
948  const Rect &bb = seg->theGlyphBBoxTemporary(slot->gid());
949  const float sx = slot->origin().x + currShift.x;
950  float x = (sx + (rtl > 0 ? bb.tr.x : bb.bl.x)) * rtl;
951  // this isn't going to reduce _mingap so skip
952  if (_hit && x < rtl * (_xbound - _mingap - currSpace))
953  return false;
954 
955  const float sy = slot->origin().y + currShift.y;
956  int smin = max(1, int((bb.bl.y + (1 - _miny + sy)) / _sliceWidth + 1)) - 1;
957  int smax = min((int)_edges.size() - 2, int((bb.tr.y + (1 - _miny + sy)) / _sliceWidth + 1)) + 1;
958  if (smin > smax)
959  return false;
960  bool collides = false;
961  bool nooverlap = true;
962 
963  for (int i = smin; i <= smax; ++i)
964  {
965  float here = _edges[i] * rtl;
966  if (here > (float)9e37)
967  continue;
968  if (!_hit || x > here - _mingap - currSpace)
969  {
970  float y = (float)(_miny - 1 + (i + .5f) * _sliceWidth); // vertical center of slice
971  // 2 * currSpace to account for the space that is already separating them and the space we want to add
972  float m = get_edge(seg, slot, currShift, y, _sliceWidth, 0., rtl > 0) * rtl + 2 * currSpace;
973  if (m < (float)-8e37) // only true if the glyph has a gap in it
974  continue;
975  nooverlap = false;
976  float t = here - m;
977  // _mingap is positive to shrink
978  if (t < _mingap || (!_hit && !collides))
979  {
980  _mingap = t;
981  collides = true;
982  }
983 #if !defined GRAPHITE2_NTRACING
984  // Debugging - remember the closest neighboring edge for this slice.
985  if (m > rtl * _nearEdges[i])
986  {
987  _slotNear[i] = slot;
988  _nearEdges[i] = m * rtl;
989  }
990 #endif
991  }
992  else
993  nooverlap = false;
994  }
995  if (nooverlap)
996  _mingap = max(_mingap, _xbound - rtl * (currSpace + _margin + x));
997  if (collides && !nooverlap)
998  _hit = true;
999  return collides | nooverlap; // note that true is not a necessarily reliable value
1000 
1001 } // end of KernCollider::mergeSlot
1002 
1003 
1004 // Return the amount to kern by.
1006  int dir, GR_MAYBE_UNUSED json * const dbgout)
1007 {
1008  float resultNeeded = (1 - 2 * (dir & 1)) * _mingap;
1009  // float resultNeeded = (1 - 2 * (dir & 1)) * (_mingap - margin);
1010  float result = min(_limit.tr.x - _offsetPrev.x, max(resultNeeded, _limit.bl.x - _offsetPrev.x));
1011 
1012 #if !defined GRAPHITE2_NTRACING
1013  if (dbgout)
1014  {
1015  *dbgout << json::object // slot
1016  << "slot" << objectid(dslot(seg, _target))
1017  << "gid" << _target->gid()
1018  << "limit" << _limit
1019  << "miny" << _miny
1020  << "maxy" << _maxy
1021  << "slicewidth" << _sliceWidth
1022  << "target" << json::object
1023  << "origin" << _target->origin()
1024  //<< "currShift" << _currShift
1025  << "offsetPrev" << _offsetPrev
1026  << "bbox" << seg->theGlyphBBoxTemporary(_target->gid())
1027  << "slantBox" << seg->getFace()->glyphs().slant(_target->gid())
1028  << "fix" << "kern"
1029  << json::close; // target object
1030 
1031  *dbgout << "slices" << json::array;
1032  for (int is = 0; is < (int)_edges.size(); is++)
1033  {
1034  *dbgout << json::flat << json::object
1035  << "i" << is
1036  << "targetEdge" << _edges[is]
1037  << "neighbor" << objectid(dslot(seg, _slotNear[is]))
1038  << "nearEdge" << _nearEdges[is]
1039  << json::close;
1040  }
1041  *dbgout << json::close; // slices array
1042 
1043  *dbgout
1044  << "xbound" << _xbound
1045  << "minGap" << _mingap
1046  << "needed" << resultNeeded
1047  << "result" << result
1048  << "stillBad" << (result != resultNeeded)
1049  << json::close; // slot object
1050  }
1051 #endif
1052 
1053  return Position(result, 0.);
1054 
1055 } // end of KernCollider::resolve
1056 
1057 void KernCollider::shift(const Position &mv, int dir)
1058 {
1059  for (Vector<float>::iterator e = _edges.begin(); e != _edges.end(); ++e)
1060  *e += mv.x;
1061  _xbound += (1 - 2 * (dir & 1)) * mv.x;
1062 }
1063 
1064 //// SLOT-COLLISION ////
1065 
1066 // Initialize the collision attributes for the given slot.
1068 {
1069  initFromSlot(seg, slot);
1070 }
1071 
1073 {
1074  // Initialize slot attributes from glyph attributes.
1075  // The order here must match the order in the grcompiler code,
1076  // GrcSymbolTable::AssignInternalGlyphAttrIDs.
1077  uint16 gid = slot->gid();
1078  uint16 aCol = seg->silf()->aCollision(); // flags attr ID
1079  const GlyphFace * glyphFace = seg->getFace()->glyphs().glyphSafe(gid);
1080  if (!glyphFace)
1081  return;
1082  const sparse &p = glyphFace->attrs();
1083  _flags = p[aCol];
1084  _limit = Rect(Position(int16(p[aCol+1]), int16(p[aCol+2])),
1085  Position(int16(p[aCol+3]), int16(p[aCol+4])));
1086  _margin = p[aCol+5];
1087  _marginWt = p[aCol+6];
1088 
1089  _seqClass = p[aCol+7];
1090  _seqProxClass = p[aCol+8];
1091  _seqOrder = p[aCol+9];
1092  _seqAboveXoff = p[aCol+10];
1093  _seqAboveWt = p[aCol+11];
1094  _seqBelowXlim = p[aCol+12];
1095  _seqBelowWt = p[aCol+13];
1096  _seqValignHt = p[aCol+14];
1097  _seqValignWt = p[aCol+15];
1098 
1099  // These attributes do not have corresponding glyph attribute:
1100  _exclGlyph = 0;
1101  _exclOffset = Position(0, 0);
1102 }
1103 
1104 float SlotCollision::getKern(int dir) const
1105 {
1106  if ((_flags & SlotCollision::COLL_KERN) != 0)
1107  return float(_shift.x * ((dir & 1) ? -1 : 1));
1108  else
1109  return 0;
1110 }
1111 
1112 bool SlotCollision::ignore() const
1113 {
1115 }
#define width(a)
Definition: aptex-macros.h:198
END END END break
Definition: bibtex-3.c:1974
static char mx
Definition: bmpfont.h:51
T * iterator
Definition: vector.hh:29
const sparse & attrs() const
Definition: GlyphFace.h:53
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)
Position tr
Definition: Position.h:65
Position bl
Definition: Position.h:64
void outputJsonDbgOneVector(json *const dbgout, Segment *seg, int axis, float tleft, float bestCost, float bestVal)
Definition: Collider.cpp:705
void addBox_slope(bool isx, const Rect &box, const BBox &bb, const SlantBox &sb, const Position &org, float weight, float m, bool minright, int mode)
Definition: Collider.cpp:143
void outputJsonDbg(json *const dbgout, Segment *seg, int axis)
Definition: Collider.cpp:648
void outputJsonDbgEndSlot(json *const dbgout, Position resultPos, int bestAxis, bool isCol)
void outputJsonDbgStartSlot(json *const dbgout, Segment *seg)
Definition: Collider.cpp:678
Position resolve(Segment *seg, bool &isCol, GR_MAYBE_UNUSED json *const dbgout)
void outputJsonDbgRemovals(json *const dbgout, int axis, Segment *seg)
Definition: Collider.cpp:732
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
void removeBox(const Rect &box, const BBox &bb, const SlantBox &sb, const Position &org, int mode)
Definition: Collider.cpp:214
int16 seqBelowXlim() const
Definition: Collider.h:91
const Position & exclOffset() const
Definition: Collider.h:81
SlotCollision(Segment *seg, Slot *slot)
Definition: Collider.cpp:1067
void initFromSlot(Segment *seg, Slot *slot)
Definition: Collider.cpp:1072
float getKern(int dir) const
Definition: Collider.cpp:1104
uint16 exclGlyph() const
Definition: Collider.h:85
uint16 seqBelowWt() const
Definition: Collider.h:92
uint16 seqValignWt() const
Definition: Collider.h:94
uint16 seqAboveWt() const
Definition: Collider.h:90
int16 seqAboveXoff() const
Definition: Collider.h:89
uint16 seqClass() const
Definition: Collider.h:86
unsigned short gid() const
Definition: Slot.h:72
void setGlyph(Segment *seg, uint16 glyphid, const GlyphFace *theGlyph=NULL)
Definition: Slot.cpp:452
Position origin() const
Definition: Slot.h:73
void initialise(float xmin, float xmax, float margin_len, float margin_weight, float ao)
Definition: Intervals.h:160
void weightedAxis(int axis, float xmin, float xmax, float f, float a0, float mi, float xi, float ai, float c, bool nega)
Definition: Intervals.h:188
void exclude_with_margins(float xmin, float xmax, int axis)
Definition: Intervals.cpp:67
void exclude(float xmin, float xmax)
Definition: Intervals.h:176
void jsonDbgOut(Segment *seg) const
Definition: Intervals.cpp:277
void weighted(float xmin, float xmax, float f, float a0, float mi, float xi, float ai, float c, bool nega)
Definition: Intervals.h:182
float closest(float origin, float &cost) const
Definition: Intervals.cpp:204
Position position() const
Definition: Intervals.h:107
exclusions::const_iterator const_iterator
Definition: Intervals.h:84
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
#define shift
Definition: exp3.c:154
#define dmin(a, b)
Definition: f2c.h:171
#define dmax(a, b)
Definition: f2c.h:172
#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
#define d(n)
Definition: gpos-common.c:151
int base
Definition: gsftopk.c:1502
#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
#define true
Definition: ftrandom.c:51
#define false
Definition: ftrandom.c:52
kerning y
Definition: ttdriver.c:212
unsigned short uint16
Definition: tiff.h:62
unsigned char uint8
Definition: tiff.h:60
#define O(_t, _a, _f)
Definition: makeint.h:501
float x
Definition: cordic.py:15
Definition: bits.h:30
gr_int16 int16
Definition: Main.h:43
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
std::pair< const Segment *const, const Slot *const > dslot
Definition: debug.h:45
#define max(a, b)
Definition: pbmto4425.c:11
#define res(length)
Definition: picttoppm.c:287
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro pixld1_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl else error unsupported endif endm macro pixld2_s mem_operand if mov asr add asl add asl mov asr sub UNIT_X add asl mov asr add asl add asl mov asr add UNIT_X add asl else pixld1_s mem_operand pixld1_s mem_operand endif endm macro pixld0_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl endif endm macro pixld_s_internal mem_operand if mem_operand pixld2_s mem_operand pixdeinterleave basereg elseif mem_operand elseif mem_operand elseif mem_operand elseif mem_operand pixld0_s mem_operand else pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else error unsupported mem_operand if bpp mem_operand endif endm macro vuzp8 reg2 vuzp d d &reg2 endm macro vzip8 reg2 vzip d d &reg2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld if[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro fetch_mask_pixblock pixld mask_basereg pixblock_size MASK endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1(dst_w_bpp<=(lowbit *8)) &&((lowbit *8)<(pixblock_size *dst_w_bpp)) .if lowbit< 16 tst DST_R
int margin
Definition: ppmtosixel.c:32
float sdm(float vi, float va, float mx, float my, O op)
Definition: Collider.cpp:130
#define dir
#define seg
#define flags
#define GR_MAYBE_UNUSED
Definition: Main.h:172
slotref slot
Definition: opcodes.h:237
#define ISQRT2
Definition: Collider.cpp:38
static float localmax(float al, float au, float bl, float bu, float x)
Definition: Collider.cpp:745
static float localmin(float al, float au, float bl, float bu, float x)
Definition: Collider.cpp:754
#define DBGTAG(x)
static float get_edge(Segment *seg, const Slot *s, const Position &shift, float y, float width, float margin, bool isRight)
Definition: Collider.cpp:763
ShellFileEnvironment e
Definition: sh6.c:388
Definition: jquant2.c:258
Definition: sh5.c:97
Definition: sh.h:1226
Definition: sh2.c:920
Definition: gd.c:2418
Definition: dvips.h:235
struct def_label label[1024]
Definition: t1part.c:286
int j
Definition: t4ht.c:1589
#define is
Definition: tex2xindy.c:759
m
Definition: tex4ht.c:3990
op
Definition: tex4ht.c:3129
return() int(((double) *(font_tbl[cur_fnt].wtbl+(int)(*(font_tbl[cur_fnt].char_wi+(int)(ch - font_tbl[cur_fnt].char_f)% 256)))/(double)(1L<< 20)) *(double) font_tbl[cur_fnt].scale)
Bool__ isAfter(const Transition t, int64_t thresh)
Definition: tz2icu.cpp:1194
#define limit(x)
Definition: yuvsplittoppm.c:26
#define end(cp)
Definition: zic.c:71