void Segment::doMirror(uint16 aMirror) { Slot * s; for (s = m_first; s; s = s->next()) { unsigned short g = glyphAttr(s->gid(), aMirror); if (g && (!(dir() & 4) || !glyphAttr(s->gid(), aMirror + 1))) s->setGlyph(this, g); } }
bool CachedFace::runGraphite(Segment *seg, const Silf *pSilf) const { assert(pSilf); pSilf->runGraphite(seg, 0, pSilf->substitutionPass()); unsigned int silfIndex = 0; for (; silfIndex < m_numSilf && &(m_silfs[silfIndex]) != pSilf; ++silfIndex); if (silfIndex == m_numSilf) return false; SegCache * const segCache = m_cacheStore->getOrCreate(silfIndex, seg->getFeatures(0)); if (!segCache) return false; assert(m_cacheStore); // find where the segment can be broken Slot * subSegStartSlot = seg->first(); Slot * subSegEndSlot = subSegStartSlot; uint16 cmapGlyphs[eMaxSpliceSize]; int subSegStart = 0; for (unsigned int i = 0; i < seg->charInfoCount(); ++i) { const unsigned int length = i - subSegStart + 1; if (length < eMaxSpliceSize) cmapGlyphs[length-1] = subSegEndSlot->gid(); else return false; const bool spaceOnly = m_cacheStore->isSpaceGlyph(subSegEndSlot->gid()); // at this stage the character to slot mapping is still 1 to 1 const int breakWeight = seg->charinfo(i)->breakWeight(), nextBreakWeight = (i + 1 < seg->charInfoCount())? seg->charinfo(i+1)->breakWeight() : 0; const uint8 f = seg->charinfo(i)->flags(); if (((spaceOnly || (breakWeight > 0 && breakWeight <= gr_breakWord) || i + 1 == seg->charInfoCount() || ((nextBreakWeight < 0 && nextBreakWeight >= gr_breakBeforeWord) || (subSegEndSlot->next() && m_cacheStore->isSpaceGlyph(subSegEndSlot->next()->gid())))) && f != 1) || f == 2) { // record the next slot before any splicing Slot * nextSlot = subSegEndSlot->next(); // spaces should be left untouched by graphite rules in any sane font if (!spaceOnly) { // found a break position, check for a cache of the sub sequence const SegCacheEntry * entry = segCache->find(cmapGlyphs, length); // TODO disable cache for words at start/end of line with contextuals if (!entry) { SegmentScopeState scopeState = seg->setScope(subSegStartSlot, subSegEndSlot, length); pSilf->runGraphite(seg, pSilf->substitutionPass(), pSilf->numPasses()); if (length < eMaxSpliceSize) { seg->associateChars(); entry = segCache->cache(m_cacheStore, cmapGlyphs, length, seg, subSegStart); } seg->removeScope(scopeState); } else seg->splice(subSegStart, length, subSegStartSlot, subSegEndSlot, entry->first(), entry->glyphLength()); } subSegStartSlot = subSegEndSlot = nextSlot; subSegStart = i + 1; } else { subSegEndSlot = subSegEndSlot->next(); } } return true; }
void Slot::setAttr(Segment *seg, attrCode ind, uint8 subindex, int16 value, const SlotMap & map) { if (!this) return; if (ind == gr_slatUserDefnV1) { ind = gr_slatUserDefn; subindex = 0; } switch (ind) { case gr_slatAdvX : m_advance.x = value; break; case gr_slatAdvY : m_advance.y = value; break; case gr_slatAttTo : { const uint16 idx = uint16(value); if (idx < map.size() && map[idx]) { Slot *other = map[idx]; if (other != this && other->child(this)) { attachTo(other); m_attach = Position(seg->glyphAdvance(other->gid()), 0); } } break; } case gr_slatAttX : m_attach.x = value; break; case gr_slatAttY : m_attach.y = value; break; case gr_slatAttXOff : case gr_slatAttYOff : break; case gr_slatAttWithX : m_with.x = value; break; case gr_slatAttWithY : m_with.y = value; break; case gr_slatAttWithXOff : case gr_slatAttWithYOff : break; case gr_slatAttLevel : m_attLevel = byte(value); break; case gr_slatBreak : seg->charinfo(m_original)->breakWeight(value); break; case gr_slatCompRef : break; // not sure what to do here case gr_slatDir : break; // read only case gr_slatInsert : markInsertBefore(value? true : false); break; case gr_slatPosX : break; // can't set these here case gr_slatPosY : break; case gr_slatShiftX : m_shift.x = value; break; case gr_slatShiftY : m_shift.y = value; break; case gr_slatMeasureSol : break; case gr_slatMeasureEol : break; case gr_slatJStretch : break; // handle these later case gr_slatJShrink : break; case gr_slatJStep : break; case gr_slatJWeight : break; case gr_slatJWidth : m_just = value; break; case gr_slatSegSplit : seg->charinfo(m_original)->addflags(value & 3); break; case gr_slatUserDefn : m_userAttr[subindex] = value; break; default : break; } }
bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass) const { assert(seg != 0); SlotMap map(*seg); FiniteStateMachine fsm(map, seg->getFace()->logger()); vm::Machine m(map); unsigned int initSize = seg->slotCount(); #if !defined GRAPHITE2_NTRACING json * const dbgout = seg->getFace()->logger(); #endif if (lastPass == 0) { if (firstPass == lastPass) return true; lastPass = m_numPasses; } for (size_t i = firstPass; i < lastPass; ++i) { // bidi and mirroring if (i == m_bPass) { #if !defined GRAPHITE2_NTRACING if (dbgout) { *dbgout << json::item << json::object << "id" << -1 << "slots" << json::array; seg->positionSlots(0); for(Slot * s = seg->first(); s; s = s->next()) *dbgout << dslot(seg, s); *dbgout << json::close << "rules" << json::array << json::close << json::close; } #endif if (!(seg->dir() & 2)) seg->bidiPass(m_aBidi, seg->dir() & 1, m_aMirror); else if (m_aMirror) { Slot * s; for (s = seg->first(); s; s = s->next()) { unsigned short g = seg->glyphAttr(s->gid(), m_aMirror); if (g && (!(seg->dir() & 4) || !seg->glyphAttr(s->gid(), m_aMirror + 1))) s->setGlyph(seg, g); } } } #if !defined GRAPHITE2_NTRACING if (dbgout) { *dbgout << json::item << json::object << "id" << i+1 << "slots" << json::array; seg->positionSlots(0); for(Slot * s = seg->first(); s; s = s->next()) *dbgout << dslot(seg, s); *dbgout << json::close; } #endif // test whether to reorder, prepare for positioning m_passes[i].runGraphite(m, fsm); // only subsitution passes can change segment length, cached subsegments are short for their text if (m.status() != vm::Machine::finished || (i < m_pPass && (seg->slotCount() > initSize * MAX_SEG_GROWTH_FACTOR || (seg->slotCount() && seg->slotCount() * MAX_SEG_GROWTH_FACTOR < initSize)))) return false; } return true; }
bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass) const { assert(seg != 0); SlotMap map(*seg); FiniteStateMachine fsm(map); vm::Machine m(map); unsigned int initSize = seg->slotCount(); if (lastPass == 0) { if (firstPass == lastPass) return true; lastPass = m_numPasses; } #if !defined GRAPHITE2_NTRACING if (dbgout) { char version[64]; sprintf(version, "%d.%d.%d", GR2_VERSION_MAJOR, GR2_VERSION_MINOR, GR2_VERSION_BUGFIX); *dbgout << json::object << "version" << version << "passes" << json::array; } #endif for (size_t i = firstPass; i < lastPass; ++i) { // bidi and mirroring if (i == m_bPass) { #if !defined GRAPHITE2_NTRACING if (dbgout) { *dbgout << json::item << json::object << "id" << -1 << "slots" << json::array; seg->positionSlots(0); for(Slot * s = seg->first(); s; s = s->next()) *dbgout << dslot(seg, s); *dbgout << json::close << "rules" << json::array << json::close << json::close; } #endif if (!(seg->dir() & 2)) seg->bidiPass(m_aBidi, seg->dir() & 1, m_aMirror); else if (m_aMirror) { Slot * s; for (s = seg->first(); s; s = s->next()) { unsigned short g = seg->glyphAttr(s->gid(), m_aMirror); if (g && (!(seg->dir() & 4) || !seg->glyphAttr(s->gid(), m_aMirror + 1))) s->setGlyph(seg, g); } } } #if !defined GRAPHITE2_NTRACING if (dbgout) { *dbgout << json::item << json::object << "id" << i+1 << "slots" << json::array; seg->positionSlots(0); for(Slot * s = seg->first(); s; s = s->next()) *dbgout << dslot(seg, s); *dbgout << json::close; } #endif // test whether to reorder, prepare for positioning m_passes[i].runGraphite(m, fsm); // only subsitution passes can change segment length, cached subsegments are short for their text if (m.status() != vm::Machine::finished || (i < m_pPass && (seg->slotCount() > initSize * MAX_SEG_GROWTH_FACTOR || (seg->slotCount() && seg->slotCount() * MAX_SEG_GROWTH_FACTOR < initSize)))) return false; } #if !defined GRAPHITE2_NTRACING if (dbgout) { *dbgout << json::item << json::close // Close up the passes array << "output" << json::array; for(Slot * s = seg->first(); s; s = s->next()) *dbgout << dslot(seg, s); seg->finalise(0); // Call this here to fix up charinfo back indexes. *dbgout << json::close << "advance" << seg->advance() << "chars" << json::array; for(size_t i = 0, n = seg->charInfoCount(); i != n; ++i) *dbgout << json::flat << *seg->charinfo(i); *dbgout << json::close // Close up the chars array << json::close; // Clsoe up the segment object } #endif return true; }