1// SPDX-License-Identifier: MIT OR MPL-2.0 OR LGPL-2.1-or-later OR GPL-2.0-or-later
2// Copyright 2010, SIL International, All rights reserved.
3
4#pragma once
5
6#include "inc/List.h"
7#include "inc/Position.h"
8#include "inc/Intervals.h"
9#include "inc/debug.h"
10
11namespace graphite2 {
12
13class json;
14class Slot;
15class Segment;
16
17#define SLOTCOLSETUINTPROP(x, y) uint16 x() const { return _ ##x; } void y (uint16 v) { _ ##x = v; }
18#define SLOTCOLSETINTPROP(x, y) int16 x() const { return _ ##x; } void y (int16 v) { _ ##x = v; }
19#define SLOTCOLSETPOSITIONPROP(x, y) const Position &x() const { return _ ##x; } void y (const Position &v) { _ ##x = v; }
20
21// Slot attributes related to collision-fixing
22class SlotCollision
23{
24public:
25 enum {
26 // COLL_TESTONLY = 0, // default - test other glyphs for collision with this one, but don't move this one
27 COLL_FIX = 1, // fix collisions involving this glyph
28 COLL_IGNORE = 2, // ignore this glyph altogether
29 COLL_START = 4, // start of range of possible collisions
30 COLL_END = 8, // end of range of possible collisions
31 COLL_KERN = 16, // collisions with this glyph are fixed by adding kerning space after it
32 COLL_ISCOL = 32, // this glyph has a collision
33 COLL_KNOWN = 64, // we've figured out what's happening with this glyph
34 COLL_ISSPACE = 128, // treat this glyph as a space with regard to kerning
35 COLL_TEMPLOCK = 256, // Lock glyphs that have been given priority positioning
36 ////COLL_JUMPABLE = 128, // moving glyphs may jump this stationary glyph in any direction - DELETE
37 ////COLL_OVERLAP = 256, // use maxoverlap to restrict - DELETE
38 };
39
40 // Behavior for the collision.order attribute. To GDL this is an enum, to us it's a bitfield, with only 1 bit set
41 // Allows for easier inversion.
42 enum {
43 SEQ_ORDER_LEFTDOWN = 1,
44 SEQ_ORDER_RIGHTUP = 2,
45 SEQ_ORDER_NOABOVE = 4,
46 SEQ_ORDER_NOBELOW = 8,
47 SEQ_ORDER_NOLEFT = 16,
48 SEQ_ORDER_NORIGHT = 32
49 };
50
51 SlotCollision(Segment *seg, Slot *slot);
52 void initFromSlot(Segment *seg, Slot *slot);
53
54 const Rect &limit() const { return _limit; }
55 void setLimit(const Rect &r) { _limit = r; }
56 SLOTCOLSETPOSITIONPROP(shift, setShift)
57 SLOTCOLSETPOSITIONPROP(offset, setOffset)
58 SLOTCOLSETPOSITIONPROP(exclOffset, setExclOffset)
59 SLOTCOLSETUINTPROP(margin, setMargin)
60 SLOTCOLSETUINTPROP(marginWt, setMarginWt)
61 SLOTCOLSETUINTPROP(flags, setFlags)
62 SLOTCOLSETUINTPROP(exclGlyph, setExclGlyph)
63 SLOTCOLSETUINTPROP(seqClass, setSeqClass)
64 SLOTCOLSETUINTPROP(seqProxClass, setSeqProxClass)
65 SLOTCOLSETUINTPROP(seqOrder, setSeqOrder)
66 SLOTCOLSETINTPROP(seqAboveXoff, setSeqAboveXoff)
67 SLOTCOLSETUINTPROP(seqAboveWt, setSeqAboveWt)
68 SLOTCOLSETINTPROP(seqBelowXlim, setSeqBelowXlim)
69 SLOTCOLSETUINTPROP(seqBelowWt, setSeqBelowWt)
70 SLOTCOLSETUINTPROP(seqValignHt, setSeqValignHt)
71 SLOTCOLSETUINTPROP(seqValignWt, setSeqValignWt)
72
73 float getKern(int dir) const;
74 bool ignore() const;
75
76private:
77 Rect _limit;
78 Position _shift; // adjustment within the given pass
79 Position _offset; // total adjustment for collisions
80 Position _exclOffset;
81 uint16 _margin;
82 uint16 _marginWt;
83 uint16 _flags;
84 uint16 _exclGlyph;
85 uint16 _seqClass;
86 uint16 _seqProxClass;
87 uint16 _seqOrder;
88 int16 _seqAboveXoff;
89 uint16 _seqAboveWt;
90 int16 _seqBelowXlim;
91 uint16 _seqBelowWt;
92 uint16 _seqValignHt;
93 uint16 _seqValignWt;
94
95}; // end of class SlotColllision
96
97struct BBox;
98struct SlantBox;
99
100class ShiftCollider
101{
102public:
103 typedef std::pair<float, float> fpair;
104 typedef Vector<fpair> vfpairs;
105 typedef vfpairs::iterator ivfpairs;
106
107 ShiftCollider(json *dbgout);
108 ~ShiftCollider() throw() { };
109
110 bool initSlot(Segment *seg, Slot *aSlot, const Rect &constraint,
111 float margin, float marginMin, const Position &currShift,
112 const Position &currOffset, int dir, GR_MAYBE_UNUSED json * const dbgout);
113 bool mergeSlot(Segment *seg, Slot *slot, const SlotCollision *cinfo, const Position &currShift, bool isAfter,
114 bool sameCluster, bool &hasCol, bool isExclusion, GR_MAYBE_UNUSED json * const dbgout);
115 Position resolve(Segment *seg, bool &isCol, GR_MAYBE_UNUSED json * const dbgout);
116 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);
117 void removeBox(const Rect &box, const BBox &bb, const SlantBox &sb, const Position &org, int mode);
118 const Position &origin() const { return _origin; }
119
120#if !defined GRAPHITE2_NTRACING
121 void outputJsonDbg(json * const dbgout, Segment *seg, int axis);
122 void outputJsonDbgStartSlot(json * const dbgout, Segment *seg);
123 void outputJsonDbgEndSlot(json * const dbgout, Position resultPos, int bestAxis, bool isCol);
124 void outputJsonDbgOneVector(json * const dbgout, Segment *seg, int axis, float tleft, float bestCost, float bestVal);
125 void outputJsonDbgRawRanges(json * const dbgout, int axis);
126 void outputJsonDbgRemovals(json * const dbgout, int axis, Segment *seg);
127#endif
128
129 CLASS_NEW_DELETE;
130
131protected:
132 Zones _ranges[4]; // possible movements in 4 directions (horizontally, vertically, diagonally);
133 Slot * _target; // the glyph to fix
134 Rect _limit;
135 Position _currShift;
136 Position _currOffset;
137 Position _origin; // Base for all relative calculations
138 float _margin;
139 float _marginWt;
140 float _len[4];
141 uint16 _seqClass;
142 uint16 _seqProxClass;
143 uint16 _seqOrder;
144
145 //bool _scraping[4];
146
147}; // end of class ShiftCollider
148
149inline
150ShiftCollider::ShiftCollider(GR_MAYBE_UNUSED json *dbgout)
151: _target(0),
152 _margin(0.0),
153 _marginWt(0.0),
154 _seqClass(0),
155 _seqProxClass(0),
156 _seqOrder(0)
157{
158#if !defined GRAPHITE2_NTRACING
159 for (int i = 0; i < 4; ++i)
160 _ranges[i].setdebug(dbgout);
161#endif
162}
163
164class KernCollider
165{
166public:
167 KernCollider(json *dbg);
168 ~KernCollider() throw() { };
169 bool initSlot(Segment *seg, Slot *aSlot, const Rect &constraint, float margin,
170 const Position &currShift, const Position &offsetPrev, int dir,
171 float ymin, float ymax, json * const dbgout);
172 bool mergeSlot(Segment *seg, Slot *slot, const Position &currShift, float currSpace, int dir, json * const dbgout);
173 Position resolve(Segment *seg, Slot *slot, int dir, json * const dbgout);
174 void shift(const Position &mv, int dir);
175
176 CLASS_NEW_DELETE;
177
178private:
179 Slot * _target; // the glyph to fix
180 Rect _limit;
181 float _margin;
182 Position _offsetPrev; // kern from a previous pass
183 Position _currShift; // NOT USED??
184 float _miny; // y-coordinates offset by global slot position
185 float _maxy;
186 Vector<float> _edges; // edges of horizontal slices
187 float _sliceWidth; // width of each slice
188 float _mingap;
189 float _xbound; // max or min edge
190 bool _hit;
191
192#if !defined GRAPHITE2_NTRACING
193 // Debugging
194 Segment * _seg;
195 Vector<float> _nearEdges; // closest potential collision in each slice
196 Vector<Slot*> _slotNear;
197#endif
198}; // end of class KernCollider
199
200
201inline
202float sqr(float x) {
203 return x * x;
204}
205
206inline
207KernCollider::KernCollider(GR_MAYBE_UNUSED json *dbg)
208: _target(0),
209 _margin(0.0f),
210 _miny(-1e38f),
211 _maxy(1e38f),
212 _sliceWidth(0.0f),
213 _mingap(0.0f),
214 _xbound(0.0),
215 _hit(false)
216{
217#if !defined GRAPHITE2_NTRACING
218 _seg = 0;
219#endif
220};
221
222}; // end of namespace graphite2
223