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