harfbuzz/src/graphite2/src/inc/Collider.h

225 lines
7.5 KiB
C++

// SPDX-License-Identifier: MIT
// Copyright 2010, SIL International, All rights reserved.
#pragma once
#include <cstdint>
#include <iterator>
#include "inc/vector.hpp"
#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_t x() const { return _ ##x; } void y (uint16_t v) { _ ##x = v; }
#define SLOTCOLSETINTPROP(x, y) int16_t x() const { return _ ##x; } void y (int16_t 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_t _margin;
uint16_t _marginWt;
uint16_t _flags;
uint16_t _exclGlyph;
uint16_t _seqClass;
uint16_t _seqProxClass;
uint16_t _seqOrder;
int16_t _seqAboveXoff;
uint16_t _seqAboveWt;
int16_t _seqBelowXlim;
uint16_t _seqBelowWt;
uint16_t _seqValignHt;
uint16_t _seqValignWt;
}; // end of class SlotColllision
struct BBox;
struct SlantBox;
class ShiftCollider
{
public:
typedef std::pair<float, float> fpair;
typedef vector<fpair> 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_t _seqClass;
uint16_t _seqProxClass;
uint16_t _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<float> _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<float> _nearEdges; // closest potential collision in each slice
vector<Slot*> _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