/* GRAPHITE2 LICENSING Copyright 2010, SIL International All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should also have received a copy of the GNU Lesser General Public License along with this library in the file named "LICENSE". If not, write to the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA or visit their web page on the internet at http://www.fsf.org/licenses/lgpl.html. Alternatively, the contents of this file may be used under the terms of the Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public License, as published by the Free Software Foundation, either version 2 of the License or (at your option) any later version. */ #pragma once #include "inc/List.h" #include "inc/Position.h" #include "inc/Intervals.h" #include "inc/debug.h" namespace graphite2 { class json; class Slot; class Segment; #define SLOTCOLSETUINTPROP(x, y) uint16 x() const { return _ ##x; } void y (uint16 v) { _ ##x = v; } #define SLOTCOLSETINTPROP(x, y) int16 x() const { return _ ##x; } void y (int16 v) { _ ##x = v; } #define SLOTCOLSETPOSITIONPROP(x, y) const Position &x() const { return _ ##x; } void y (const Position &v) { _ ##x = v; } // Slot attributes related to collision-fixing class SlotCollision { public: enum { // COLL_TESTONLY = 0, // default - test other glyphs for collision with this one, but don't move this one COLL_FIX = 1, // fix collisions involving this glyph COLL_IGNORE = 2, // ignore this glyph altogether COLL_START = 4, // start of range of possible collisions COLL_END = 8, // end of range of possible collisions COLL_KERN = 16, // collisions with this glyph are fixed by adding kerning space after it COLL_ISCOL = 32, // this glyph has a collision COLL_KNOWN = 64, // we've figured out what's happening with this glyph COLL_ISSPACE = 128, // treat this glyph as a space with regard to kerning COLL_TEMPLOCK = 256, // Lock glyphs that have been given priority positioning ////COLL_JUMPABLE = 128, // moving glyphs may jump this stationary glyph in any direction - DELETE ////COLL_OVERLAP = 256, // use maxoverlap to restrict - DELETE }; // Behavior for the collision.order attribute. To GDL this is an enum, to us it's a bitfield, with only 1 bit set // Allows for easier inversion. enum { SEQ_ORDER_LEFTDOWN = 1, SEQ_ORDER_RIGHTUP = 2, SEQ_ORDER_NOABOVE = 4, SEQ_ORDER_NOBELOW = 8, SEQ_ORDER_NOLEFT = 16, SEQ_ORDER_NORIGHT = 32 }; SlotCollision(Segment *seg, Slot *slot); void initFromSlot(Segment *seg, Slot *slot); const Rect &limit() const { return _limit; } void setLimit(const Rect &r) { _limit = r; } SLOTCOLSETPOSITIONPROP(shift, setShift) SLOTCOLSETPOSITIONPROP(offset, setOffset) SLOTCOLSETPOSITIONPROP(exclOffset, setExclOffset) SLOTCOLSETUINTPROP(margin, setMargin) SLOTCOLSETUINTPROP(marginWt, setMarginWt) SLOTCOLSETUINTPROP(flags, setFlags) SLOTCOLSETUINTPROP(exclGlyph, setExclGlyph) SLOTCOLSETUINTPROP(seqClass, setSeqClass) SLOTCOLSETUINTPROP(seqProxClass, setSeqProxClass) SLOTCOLSETUINTPROP(seqOrder, setSeqOrder) SLOTCOLSETINTPROP(seqAboveXoff, setSeqAboveXoff) SLOTCOLSETUINTPROP(seqAboveWt, setSeqAboveWt) SLOTCOLSETINTPROP(seqBelowXlim, setSeqBelowXlim) SLOTCOLSETUINTPROP(seqBelowWt, setSeqBelowWt) SLOTCOLSETUINTPROP(seqValignHt, setSeqValignHt) SLOTCOLSETUINTPROP(seqValignWt, setSeqValignWt) float getKern(int dir) const; bool ignore() const; private: Rect _limit; Position _shift; // adjustment within the given pass Position _offset; // total adjustment for collisions Position _exclOffset; uint16 _margin; uint16 _marginWt; uint16 _flags; uint16 _exclGlyph; uint16 _seqClass; uint16 _seqProxClass; uint16 _seqOrder; int16 _seqAboveXoff; uint16 _seqAboveWt; int16 _seqBelowXlim; uint16 _seqBelowWt; uint16 _seqValignHt; uint16 _seqValignWt; }; // end of class SlotColllision struct BBox; struct SlantBox; class ShiftCollider { public: typedef std::pair fpair; typedef Vector vfpairs; typedef vfpairs::iterator ivfpairs; ShiftCollider(json *dbgout); ~ShiftCollider() throw() { }; 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); 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); Position resolve(Segment *seg, bool &isCol, GR_MAYBE_UNUSED json * const dbgout); 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); void removeBox(const Rect &box, const BBox &bb, const SlantBox &sb, const Position &org, int mode); const Position &origin() const { return _origin; } #if !defined GRAPHITE2_NTRACING void outputJsonDbg(json * const dbgout, Segment *seg, int axis); void outputJsonDbgStartSlot(json * const dbgout, Segment *seg); void outputJsonDbgEndSlot(json * const dbgout, Position resultPos, int bestAxis, bool isCol); void outputJsonDbgOneVector(json * const dbgout, Segment *seg, int axis, float tleft, float bestCost, float bestVal); void outputJsonDbgRawRanges(json * const dbgout, int axis); void outputJsonDbgRemovals(json * const dbgout, int axis, Segment *seg); #endif CLASS_NEW_DELETE; protected: Zones _ranges[4]; // possible movements in 4 directions (horizontally, vertically, diagonally); Slot * _target; // the glyph to fix Rect _limit; Position _currShift; Position _currOffset; Position _origin; // Base for all relative calculations float _margin; float _marginWt; float _len[4]; uint16 _seqClass; uint16 _seqProxClass; uint16 _seqOrder; //bool _scraping[4]; }; // end of class ShiftCollider inline ShiftCollider::ShiftCollider(GR_MAYBE_UNUSED json *dbgout) : _target(0), _margin(0.0), _marginWt(0.0), _seqClass(0), _seqProxClass(0), _seqOrder(0) { #if !defined GRAPHITE2_NTRACING for (int i = 0; i < 4; ++i) _ranges[i].setdebug(dbgout); #endif } class KernCollider { public: KernCollider(json *dbg); ~KernCollider() throw() { }; 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 resolve(Segment *seg, Slot *slot, int dir, json * const dbgout); void shift(const Position &mv, int dir); CLASS_NEW_DELETE; private: Slot * _target; // the glyph to fix Rect _limit; float _margin; Position _offsetPrev; // kern from a previous pass Position _currShift; // NOT USED?? float _miny; // y-coordinates offset by global slot position float _maxy; Vector _edges; // edges of horizontal slices float _sliceWidth; // width of each slice float _mingap; float _xbound; // max or min edge bool _hit; #if !defined GRAPHITE2_NTRACING // Debugging Segment * _seg; Vector _nearEdges; // closest potential collision in each slice Vector _slotNear; #endif }; // end of class KernCollider inline float sqr(float x) { return x * x; } inline KernCollider::KernCollider(GR_MAYBE_UNUSED json *dbg) : _target(0), _margin(0.0f), _miny(-1e38f), _maxy(1e38f), _sliceWidth(0.0f), _mingap(0.0f), _xbound(0.0), _hit(false) { #if !defined GRAPHITE2_NTRACING _seg = 0; #endif }; }; // end of namespace graphite2