예제 #1
0
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;
}
예제 #3
0
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;
    }
}
예제 #4
0
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;
}
예제 #5
0
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;
}