m.slotMap().highwater(currHigh); int lc = m_iMaxLoop; do
{
findNDoRule(s, m, fsm); if (m.status() != Machine::finished) returnfalse; if (s && (s == m.slotMap().highwater() || m.slotMap().highpassed() || --lc == 0)) { if (!lc)
s = m.slotMap().highwater();
lc = m_iMaxLoop; if (s)
m.slotMap().highwater(s->next());
}
} while (s);
} //TODO: Use enums for flags constbool collisions = m_numCollRuns || m_kernColls;
if (!collisions || !m.slotMap().segment.hasCollisionInfo()) returntrue;
if (m_numCollRuns)
{ if (!(m.slotMap().segment.flags() & Segment::SEG_INITCOLLISIONS))
{
m.slotMap().segment.positionSlots(0, 0, 0, m.slotMap().dir(), true); // m.slotMap().segment.flags(m.slotMap().segment.flags() | Segment::SEG_INITCOLLISIONS);
} if (!collisionShift(&m.slotMap().segment, m.slotMap().dir(), fsm.dbgout)) returnfalse;
} if ((m_kernColls) && !collisionKern(&m.slotMap().segment, m.slotMap().dir(), fsm.dbgout)) returnfalse; if (collisions && !collisionFinish(&m.slotMap().segment, fsm.dbgout)) returnfalse; returntrue;
}
if (runFSM(fsm, slot))
{ // Search for the first rule which passes the constraint const RuleEntry * r = fsm.rules.begin(),
* const re = fsm.rules.end(); while (r != re && !testConstraint(*r->rule, m))
{
++r; if (m.status() != Machine::finished) return;
}
#if !defined GRAPHITE2_NTRACING if (fsm.dbgout)
{ if (fsm.rules.size() != 0)
{
*fsm.dbgout << json::item << json::object;
dumpRuleEventConsidered(fsm, *r); if (r != re)
{ constint adv = doAction(r->rule->action, slot, m);
dumpRuleEventOutput(fsm, *r->rule, slot); if (r->rule->action->deletes()) fsm.slots.collectGarbage(slot);
adjustSlot(adv, slot, fsm.slots);
*fsm.dbgout << "cursor" << objectid(dslot(&fsm.slots.segment, slot))
<< json::close; // Close RuelEvent object
if (!*r.constraint) returntrue;
assert(r.constraint->constraint()); for (int n = r.sort; n && map; --n, ++map)
{ if (!*map) continue; const int32 ret = r.constraint->run(m, map); if (!ret || m.status() != Machine::finished) returnfalse;
}
// phase 2 : loop until happy. for (int i = 0; i < m_numCollRuns - 1; ++i)
{ if (hasCollisions || moved)
{
#if !defined GRAPHITE2_NTRACING if (dbgout)
*dbgout << json::object << "phase" << "2a" << "loop" << i << "moves" << json::array; #endif // phase 2a : if any shiftable glyphs are in collision, iterate backwards, // fixing them and ignoring other non-collided glyphs. Note that this handles ONLY // glyphs that are actually in collision from phases 1 or 2b, and working backwards // has the intended effect of breaking logjams. if (hasCollisions)
{
hasCollisions = false; #if0
moved = true; for (Slot *s = start; s != end; s = s->next())
{
SlotCollision * c = seg->collisionInfo(s);
c->setShift(Position(0, 0));
} #endif
Slot *lend = end ? end->prev() : seg->last();
Slot *lstart = start->prev(); for (Slot *s = lend; s != lstart; s = s->prev())
{
SlotCollision * c = seg->collisionInfo(s); if (start && (c->flags() & (SlotCollision::COLL_FIX | SlotCollision::COLL_KERN | SlotCollision::COLL_ISCOL))
== (SlotCollision::COLL_FIX | SlotCollision::COLL_ISCOL)) // ONLY if this glyph is still colliding
{ if (!resolveCollisions(seg, s, lend, shiftcoll, true, dir, moved, hasCollisions, dbgout)) returnfalse;
c->setFlags(c->flags() | SlotCollision::COLL_TEMPLOCK);
}
}
}
// phase 2b : redo basic diacritic positioning pass for ALL glyphs. Each successive loop adjusts // glyphs from their current adjusted position, which has the effect of gradually minimizing the // resulting adjustment; ie, the final result will be gradually closer to the original location. // Also it allows more flexibility in the final adjustment, since it is moving along the // possible 8 vectors from successively different starting locations. if (moved)
{
moved = false; for (Slot *s = start; s != end; s = s->next())
{
SlotCollision * c = seg->collisionInfo(s); if (start && (c->flags() & (SlotCollision::COLL_FIX | SlotCollision::COLL_TEMPLOCK
| SlotCollision::COLL_KERN)) == SlotCollision::COLL_FIX
&& !resolveCollisions(seg, s, start, shiftcoll, false, dir, moved, hasCollisions, dbgout)) returnfalse; elseif (c->flags() & SlotCollision::COLL_TEMPLOCK)
c->setFlags(c->flags() & ~SlotCollision::COLL_TEMPLOCK);
}
} // if (!hasCollisions) // no, don't leave yet because phase 2b will continue to improve things // break; #if !defined GRAPHITE2_NTRACING if (dbgout)
*dbgout << json::close << json::close; // phase 2 #endif
}
} if (!end) break;
start = NULL; for (Slot *s = end->prev(); s; s = s->next())
{ if (seg->collisionInfo(s)->flags() & SlotCollision::COLL_START)
{
start = s; break;
}
}
} returntrue;
}
// Can slot s be kerned, or is it attached to something that can be kerned? staticbool inKernCluster(Segment *seg, Slot *s)
{
SlotCollision *c = seg->collisionInfo(s); if (c->flags() & SlotCollision::COLL_KERN /** && c->flags() & SlotCollision::COLL_FIX **/ ) returntrue; while (s->attachedTo())
{
s = s->attachedTo();
c = seg->collisionInfo(s); if (c->flags() & SlotCollision::COLL_KERN /** && c->flags() & SlotCollision::COLL_FIX **/ ) returntrue;
} returnfalse;
}
// Fix collisions for the given slot. // Return true if everything was fixed, false if there are still collisions remaining. // isRev means be we are processing backwards. bool Pass::resolveCollisions(Segment *seg, Slot *slotFix, Slot *start,
ShiftCollider &coll, GR_MAYBE_UNUSED bool isRev, int dir, bool &moved, bool &hasCol,
json * const dbgout) const
{
Slot * nbor; // neighboring slot
SlotCollision *cFix = seg->collisionInfo(slotFix); if (!coll.initSlot(seg, slotFix, cFix->limit(), cFix->margin(), cFix->marginWt(),
cFix->shift(), cFix->offset(), dir, dbgout)) returnfalse; bool collides = false; // When we're processing forward, ignore kernable glyphs that preceed the target glyph. // When processing backward, don't ignore these until we pass slotFix. bool ignoreForKern = !isRev; bool rtl = dir & 1;
Slot *base = slotFix; while (base->attachedTo())
base = base->attachedTo();
Position zero(0., 0.);
// Look for collisions with the neighboring glyphs. for (nbor = start; nbor; nbor = isRev ? nbor->prev() : nbor->next())
{
SlotCollision *cNbor = seg->collisionInfo(nbor); bool sameCluster = nbor->isChildOf(base); if (nbor != slotFix // don't process if this is the slot of interest
&& !(cNbor->ignore()) // don't process if ignoring
&& (nbor == base || sameCluster // process if in the same cluster as slotFix
|| !inKernCluster(seg, nbor)) // or this cluster is not to be kerned // || (rtl ^ ignoreForKern)) // or it comes before(ltr) or after(rtl)
&& (!isRev // if processing forwards then good to merge otherwise only:
|| !(cNbor->flags() & SlotCollision::COLL_FIX) // merge in immovable stuff
|| ((cNbor->flags() & SlotCollision::COLL_KERN) && !sameCluster) // ignore other kernable clusters
|| (cNbor->flags() & SlotCollision::COLL_ISCOL)) // test against other collided glyphs
&& !coll.mergeSlot(seg, nbor, cNbor, cNbor->shift(), !ignoreForKern, sameCluster, collides, false, dbgout)) returnfalse; elseif (nbor == slotFix) // Switching sides of this glyph - if we were ignoring kernable stuff before, don't anymore.
ignoreForKern = !ignoreForKern;
if (nbor != start && (cNbor->flags() & (isRev ? SlotCollision::COLL_START : SlotCollision::COLL_END))) break;
} bool isCol = false; if (collides || cFix->shift().x != 0.f || cFix->shift().y != 0.f)
{
Position shift = coll.resolve(seg, isCol, dbgout); // isCol has been set to true if a collision remains. if (std::fabs(shift.x) < 1e38f && std::fabs(shift.y) < 1e38f)
{ if (sqr(shift.x-cFix->shift().x) + sqr(shift.y-cFix->shift().y) >= m_colThreshold * m_colThreshold)
moved = true;
cFix->setShift(shift); if (slotFix->firstChild())
{
Rect bbox;
Position here = slotFix->origin() + shift; float clusterMin = here.x;
slotFix->firstChild()->finalise(seg, NULL, here, bbox, 0, clusterMin, rtl, false);
}
}
} else
{ // This glyph is not colliding with anything. #if !defined GRAPHITE2_NTRACING if (dbgout)
{
*dbgout << json::object
<< "missed" << objectid(dslot(seg, slotFix));
coll.outputJsonDbg(dbgout, seg, -1);
*dbgout << json::close;
} #endif
}
// Set the is-collision flag bit. if (isCol)
{ cFix->setFlags(cFix->flags() | SlotCollision::COLL_ISCOL | SlotCollision::COLL_KNOWN); } else
{ cFix->setFlags((cFix->flags() & ~SlotCollision::COLL_ISCOL) | SlotCollision::COLL_KNOWN); }
hasCol |= isCol; returntrue;
}
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.