Alternatively,thecontentsofthisfilemaybeusedunderthetermsofthe MozillaPublicLicense(http://mozilla.org/MPL) or the GNU General Public License,aspublishedbytheFreeSoftwareFoundation,eitherversion2 oftheLicenseor(atyouroption)anylaterversion.
*/ #include <algorithm> #include <limits> #include <cmath> #include <string> #include <functional> #include"inc/Collider.h" #include"inc/Segment.h" #include"inc/Slot.h" #include"inc/GlyphCache.h" #include"inc/Sparse.h"
#define ISQRT2 0.707106781f
// Possible rounding error for subbox boundaries: 0.016 = 1/64 = 1/256 * 4 // (values in font range from 0..256) // #define SUBBOX_RND_ERR 0.016
usingnamespace graphite2;
//// SHIFT-COLLIDER ////
// Initialize the Collider to hold the basic movement limits for the // target slot, the one we are focusing on fixing. bool ShiftCollider::initSlot(Segment *seg, Slot *aSlot, const Rect &limit, float margin, float marginWeight, const Position &currShift, const Position &currOffset, int dir, GR_MAYBE_UNUSED json * const dbgout)
{ int i; float mx, mn; float a, shift; const GlyphCache &gc = seg->getFace()->glyphs(); unsignedshort gid = aSlot->gid(); if (!gc.check(gid)) returnfalse; const BBox &bb = gc.getBoundingBBox(gid); const SlantBox &sb = gc.getBoundingSlantBox(gid); //float sx = aSlot->origin().x + currShift.x; //float sy = aSlot->origin().y + currShift.y; if (currOffset.x != 0.f || currOffset.y != 0.f)
_limit = Rect(limit.bl - currOffset, limit.tr - currOffset); else
_limit = limit; // For a ShiftCollider, these indices indicate which vector we are moving by: // 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 for (i = 0; i < 4; ++i)
{ switch (i) { case0 : // x direction
mn = _limit.bl.x + currOffset.x;
mx = _limit.tr.x + currOffset.x;
_len[i] = bb.xa - bb.xi;
a = currOffset.y + currShift.y;
_ranges[i].initialise<XY>(mn, mx, margin, marginWeight, a); break; case1 : // y direction
mn = _limit.bl.y + currOffset.y;
mx = _limit.tr.y + currOffset.y;
_len[i] = bb.ya - bb.yi;
a = currOffset.x + currShift.x;
_ranges[i].initialise<XY>(mn, mx, margin, marginWeight, a); break; case2 : // sum (negatively sloped diagonal boundaries) // pick closest x,y limit boundaries in s direction
shift = currOffset.x + currOffset.y + currShift.x + currShift.y;
mn = -2 * min(currShift.x - _limit.bl.x, currShift.y - _limit.bl.y) + shift;
mx = 2 * min(_limit.tr.x - currShift.x, _limit.tr.y - currShift.y) + shift;
_len[i] = sb.sa - sb.si;
a = currOffset.x - currOffset.y + currShift.x - currShift.y;
_ranges[i].initialise<SD>(mn, mx, margin / ISQRT2, marginWeight, a); break; case3 : // diff (positively sloped diagonal boundaries) // pick closest x,y limit boundaries in d direction
shift = currOffset.x - currOffset.y + currShift.x - currShift.y;
mn = -2 * min(currShift.x - _limit.bl.x, _limit.tr.y - currShift.y) + shift;
mx = 2 * min(_limit.tr.x - currShift.x, currShift.y - _limit.bl.y) + shift;
_len[i] = sb.da - sb.di;
a = currOffset.x + currOffset.y + currShift.x + currShift.y;
_ranges[i].initialise<SD>(mn, mx, margin / ISQRT2, marginWeight, a); break;
}
}
_target = aSlot; if ((dir & 1) == 0)
{ // For LTR, switch and negate x limits.
_limit.bl.x = -1 * limit.tr.x; //_limit.tr.x = -1 * limit.bl.x;
}
_currOffset = currOffset;
_currShift = currShift;
_origin = aSlot->origin() - currOffset; // the original anchor position of the glyph
// Adjust the movement limits for the target to avoid having it collide // with the given neighbor slot. Also determine if there is in fact a collision // between the target and the given slot. bool ShiftCollider::mergeSlot(Segment *seg, Slot *slot, const SlotCollision *cslot, const Position &currShift, bool isAfter, // slot is logically after _target bool sameCluster, bool &hasCol, bool isExclusion,
GR_MAYBE_UNUSED json * const dbgout )
{ bool isCol = false; constfloat sx = slot->origin().x - _origin.x + currShift.x; constfloat sy = slot->origin().y - _origin.y + currShift.y; constfloat sd = sx - sy; constfloat ss = sx + sy; float vmin, vmax; float omin, omax, otmin, otmax; float cmin, cmax; // target limits float torg; const GlyphCache &gc = seg->getFace()->glyphs(); constunsignedshort gid = slot->gid(); if (!gc.check(gid)) returnfalse; const BBox &bb = gc.getBoundingBBox(gid);
// SlotCollision * cslot = seg->collisionInfo(slot); int orderFlags = 0; bool sameClass = _seqProxClass == 0 && cslot->seqClass() == _seqClass; if (sameCluster && _seqClass
&& (sameClass || (_seqProxClass != 0 && cslot->seqClass() == _seqProxClass))) // Force the target glyph to be in the specified direction from the slot we're testing.
orderFlags = _seqOrder;
// short circuit if only interested in direct collision and we are out of range if (orderFlags || (sx + bb.xa + _margin >= _limit.bl.x && sx + bb.xi - _margin <= _limit.tr.x)
|| (sy + bb.ya + _margin >= _limit.bl.y && sy + bb.yi - _margin <= _limit.tr.y))
{ constfloat tx = _currOffset.x + _currShift.x; constfloat ty = _currOffset.y + _currShift.y; constfloat td = tx - ty; constfloat ts = tx + ty; const SlantBox &sb = gc.getBoundingSlantBox(gid); constunsignedshort tgid = _target->gid(); const BBox &tbb = gc.getBoundingBBox(tgid); const SlantBox &tsb = gc.getBoundingSlantBox(tgid); float seq_above_wt = cslot->seqAboveWt(); float seq_below_wt = cslot->seqBelowWt(); float seq_valign_wt = cslot->seqValignWt(); float lmargin; // if isAfter, invert orderFlags for diagonal orders. if (isAfter)
{ // invert appropriate bits
orderFlags ^= (sameClass ? 0x3F : 0x3); // consider 2 bits at a time, non overlapping. If both bits set, clear them
orderFlags = orderFlags ^ ((((orderFlags >> 1) & orderFlags) & 0x15) * 3);
}
#if !defined GRAPHITE2_NTRACING if (dbgout)
dbgout->setenv(0, slot); #endif
// Determine the trailing edge of each slice (ie, left edge for a RTL glyph). for (s = base; s; s = s->nextInCluster(s))
{
SlotCollision *c = seg->collisionInfo(s); if (!gc.check(s->gid())) returnfalse; const BBox &bs = gc.getBoundingBBox(s->gid()); float x = s->origin().x + c->shift().x + ((dir & 1) ? bs.xi : bs.xa); // Loop over slices. // Note smin might not be zero if glyph s is not at the bottom of the cluster; similarly for smax. float toffset = c->shift().y - _miny + 1 + s->origin().y; int smin = max(0, int((bs.yi + toffset) / _sliceWidth)); int smax = min(numSlices - 1, int((bs.ya + toffset) / _sliceWidth + 1)); for (int i = smin; i <= smax; ++i)
{ float t; float y = _miny - 1 + (i + .5f) * _sliceWidth; // vertical center of slice if ((dir & 1) && x < _edges[i])
{
t = get_edge(seg, s, c->shift(), y, _sliceWidth, margin, false); if (t < _edges[i])
{
_edges[i] = t; if (t < _xbound)
_xbound = t;
}
} elseif (!(dir & 1) && x > _edges[i])
{
t = get_edge(seg, s, c->shift(), y, _sliceWidth, margin, true); if (t > _edges[i])
{
_edges[i] = t; if (t > _xbound)
_xbound = t;
}
}
}
}
done:
_mingap = (float)1e37; // less than 1e38 s.t. 1e38-_mingap is really big
_target = aSlot;
_margin = margin;
_currShift = currShift; returntrue;
} // end of KernCollider::initSlot
// Determine how much the target slot needs to kern away from the given slot. // In other words, merge information from given slot's position with what the target slot knows // about how it can kern. // Return false if we know there is no collision, true if we think there might be one. bool KernCollider::mergeSlot(Segment *seg, Slot *slot, const Position &currShift, float currSpace, int dir, GR_MAYBE_UNUSED json * const dbgout)
{ int rtl = (dir & 1) * 2 - 1; if (!seg->getFace()->glyphs().check(slot->gid())) returnfalse; const Rect &bb = seg->theGlyphBBoxTemporary(slot->gid()); constfloat sx = slot->origin().x + currShift.x; float x = (sx + (rtl > 0 ? bb.tr.x : bb.bl.x)) * rtl; // this isn't going to reduce _mingap so skip if (_hit && x < rtl * (_xbound - _mingap - currSpace)) returnfalse;
for (int i = smin; i <= smax; ++i)
{ float here = _edges[i] * rtl; if (here > (float)9e37) continue; if (!_hit || x > here - _mingap - currSpace)
{ float y = (float)(_miny - 1 + (i + .5f) * _sliceWidth); // vertical center of slice // 2 * currSpace to account for the space that is already separating them and the space we want to add float m = get_edge(seg, slot, currShift, y, _sliceWidth, 0., rtl > 0) * rtl + 2 * currSpace; if (m < (float)-8e37) // only true if the glyph has a gap in it continue;
nooverlap = false; float t = here - m; // _mingap is positive to shrink if (t < _mingap || (!_hit && !collides))
{
_mingap = t;
collides = true;
} #if !defined GRAPHITE2_NTRACING // Debugging - remember the closest neighboring edge for this slice. if (m > rtl * _nearEdges[i])
{
_slotNear[i] = slot;
_nearEdges[i] = m * rtl;
} #endif
} else
nooverlap = false;
} if (nooverlap)
_mingap = max(_mingap, _xbound - rtl * (currSpace + _margin + x)); if (collides && !nooverlap)
_hit = true; return collides | nooverlap; // note that true is not a necessarily reliable value
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.