summaryrefslogtreecommitdiff
path: root/Build/source/libs/graphite/src/segment/GrPass.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/graphite/src/segment/GrPass.cpp')
-rw-r--r--Build/source/libs/graphite/src/segment/GrPass.cpp1995
1 files changed, 1995 insertions, 0 deletions
diff --git a/Build/source/libs/graphite/src/segment/GrPass.cpp b/Build/source/libs/graphite/src/segment/GrPass.cpp
new file mode 100644
index 00000000000..26eb3a3deb6
--- /dev/null
+++ b/Build/source/libs/graphite/src/segment/GrPass.cpp
@@ -0,0 +1,1995 @@
+/*--------------------------------------------------------------------*//*:Ignore this sentence.
+Copyright (C) 1999, 2001 SIL International. All rights reserved.
+
+Distributable under the terms of either the Common Public License or the
+GNU Lesser General Public License, as specified in the LICENSING.txt file.
+
+File: GrPass.cpp
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+ Implements the GrPass class and subclasses.
+----------------------------------------------------------------------------------------------*/
+
+//:>********************************************************************************************
+//:> Include files
+//:>********************************************************************************************
+#include "Main.h"
+
+#ifdef _MSC_VER
+#pragma hdrstop
+#endif
+#undef THIS_FILE
+DEFINE_THIS_FILE
+
+//:End Ignore
+
+//:>********************************************************************************************
+//:> Forward declarations
+//:>********************************************************************************************
+
+//:>********************************************************************************************
+//:> Local Constants and static variables
+//:>********************************************************************************************
+
+namespace gr
+{
+
+//:>********************************************************************************************
+//:> Methods
+//:>********************************************************************************************
+/*----------------------------------------------------------------------------------------------
+ Constructors and initializers
+----------------------------------------------------------------------------------------------*/
+GrPass::GrPass(int i)
+ : m_ipass(i),
+ m_fxdVersion(0),
+ m_nMaxRuleContext(0),
+ m_pfsm(NULL),
+ m_nMaxRuleLoop(0),
+ m_nMaxBackup(0),
+ m_crul(0),
+ m_prgchwRuleSortKeys(NULL),
+ m_prgcritRulePreModContext(NULL),
+ m_cbPassConstraint(0),
+ m_prgibConstraintStart(NULL),
+ m_prgibActionStart(NULL),
+ m_prgbPConstraintBlock(NULL),
+ m_prgbConstraintBlock(NULL),
+ m_prgbActionBlock(NULL),
+ m_cbConstraints(0),
+ m_cbActions(0),
+ m_prgibConstraintDebug(NULL),
+ m_prgibRuleDebug(NULL),
+ m_fCheckRules(false),
+ m_prgfRuleOkay(NULL),
+ m_vnStack(128),
+ m_pzpst(NULL)
+{
+}
+
+void PassState::InitForNewSegment(int ipass, int nMaxChunk)
+{
+ m_ipass = ipass;
+ m_nRulesSinceAdvance = 0;
+ m_nMaxChunk = nMaxChunk;
+ m_cslotSkipToResync = 0;
+ m_fDidResyncSkip = false;
+ InitializeLogInfo();
+}
+
+void PassState::InitializeLogInfo()
+{
+ m_crulrec = 0;
+ std::fill_n(m_rgcslotDeletions, 128, 0);
+ std::fill_n(m_rgfInsertion, 128, false);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Destructors
+----------------------------------------------------------------------------------------------*/
+GrPass::~GrPass()
+{
+ delete m_pfsm;
+
+ delete[] m_prgchwRuleSortKeys;
+
+ delete[] m_prgcritRulePreModContext;
+
+ delete[] m_prgibConstraintStart;
+ delete[] m_prgibActionStart;
+
+ delete[] m_prgbPConstraintBlock;
+ delete[] m_prgbConstraintBlock;
+ delete[] m_prgbActionBlock;
+
+ delete[] m_prgfRuleOkay;
+
+ delete[] m_prgibConstraintDebug;
+ delete[] m_prgibRuleDebug;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Fill in the pass by reading from the font stream.
+----------------------------------------------------------------------------------------------*/
+bool GrPass::ReadFromFont(GrIStream & grstrm, int fxdSilfVersion, int fxdRuleVersion,
+ int nOffset)
+{
+ long lPassInfoStart;
+ grstrm.GetPositionInFont(&lPassInfoStart);
+
+ m_fxdVersion = fxdSilfVersion;
+
+ m_fCheckRules = (fxdRuleVersion > kRuleVersion);
+
+// Assert(nOffset == lPassInfoStart);
+ if (lPassInfoStart != nOffset)
+ {
+ grstrm.SetPositionInFont(nOffset);
+ }
+
+ // flags - ignore for now
+ //byte bTmp = grstrm.ReadByteFromFont();
+ grstrm.ReadByteFromFont();
+
+ // MaxRuleLoop
+ m_nMaxRuleLoop = grstrm.ReadByteFromFont();
+
+ // max rule context
+ m_nMaxRuleContext = grstrm.ReadByteFromFont();
+
+ // MaxBackup
+ m_nMaxBackup = grstrm.ReadByteFromFont();
+
+ // number of rules
+ m_crul = grstrm.ReadShortFromFont();
+ // TODO: add a sanity check for the number of rules.
+
+ // offset to pass constraint code, relative to start of subtable
+ int nPConstraintOffset = 0;
+ long lFsmPos = -1;
+ if (fxdSilfVersion >= 0x00020000)
+ {
+ if (fxdSilfVersion >= 0x00030000)
+ lFsmPos = grstrm.ReadUShortFromFont() + nOffset; // offset to row info
+ else
+ grstrm.ReadShortFromFont(); // pad bytes
+ nPConstraintOffset = grstrm.ReadIntFromFont();
+ }
+ // offset to rule constraint code, relative to start of subtable
+ //int nConstraintOffset = grstrm.ReadIntFromFont();
+ grstrm.ReadIntFromFont();
+ // offset to action code, relative to start of subtable
+ //int nActionOffset = grstrm.ReadIntFromFont();
+ grstrm.ReadIntFromFont();
+ // offset to debug strings; 0 if stripped
+ //int nDebugOffset = grstrm.ReadIntFromFont();
+ grstrm.ReadIntFromFont();
+
+ // Jump to beginning of FSM, if we have this information.
+ if (fxdSilfVersion >= 0x00030000)
+ grstrm.SetPositionInFont(lFsmPos);
+ else
+ // Otherwise assume that's where we are!
+ Assert(lFsmPos == -1);
+
+ m_pfsm = new GrFSM();
+
+ m_pfsm->ReadFromFont(grstrm, fxdSilfVersion);
+
+ // rule sort keys
+ m_prgchwRuleSortKeys = new data16[m_crul];
+ data16 * pchw = m_prgchwRuleSortKeys;
+ int irul;
+ for (irul = 0; irul < m_crul; irul++, pchw++)
+ {
+ *pchw = grstrm.ReadUShortFromFont();
+ }
+
+ // rule pre-mod-context item counts
+ m_prgcritRulePreModContext = new byte[m_crul];
+ byte * pb = m_prgcritRulePreModContext;
+ for (irul = 0; irul < m_crul; irul++, pb++)
+ {
+ *pb = grstrm.ReadByteFromFont();
+ }
+
+ // constraint offset for pass-level constraints
+ if (fxdSilfVersion >= 0x00020000)
+ {
+ // reserved - pad byte
+ grstrm.ReadByteFromFont();
+ // Note: pass constraints have not been fully implemented.
+ m_cbPassConstraint = grstrm.ReadUShortFromFont();
+ }
+ else
+ m_cbPassConstraint = 0;
+
+ // constraint and action offsets for rules
+ m_prgibConstraintStart = new data16[m_crul + 1];
+ pchw = m_prgibConstraintStart;
+ for (irul = 0; irul <= m_crul; irul++, pchw++)
+ {
+ *pchw = grstrm.ReadUShortFromFont();
+ }
+
+ m_prgibActionStart = new data16[m_crul + 1];
+ pchw = m_prgibActionStart;
+ for (irul = 0; irul <= m_crul; irul++, pchw++)
+ {
+ *pchw = grstrm.ReadUShortFromFont();
+ }
+
+ // FSM state table
+ m_pfsm->ReadStateTableFromFont(grstrm, fxdSilfVersion);
+
+ if (fxdSilfVersion >= 0x00020000)
+ // reserved - pad byte
+ grstrm.ReadByteFromFont();
+
+ // Constraint and action blocks
+ int cb = m_cbPassConstraint;
+ m_prgbPConstraintBlock = new byte[cb];
+ grstrm.ReadBlockFromFont(m_prgbPConstraintBlock, cb);
+ m_cbConstraints = cb;
+
+ cb = m_prgibConstraintStart[m_crul];
+ m_prgbConstraintBlock = new byte[cb];
+ grstrm.ReadBlockFromFont(m_prgbConstraintBlock, cb);
+ m_cbConstraints += cb;
+
+ cb = m_prgibActionStart[m_crul];
+ m_prgbActionBlock = new byte[cb];
+ grstrm.ReadBlockFromFont(m_prgbActionBlock, cb);
+ m_cbActions = cb;
+
+ // Rule-validity flags
+ m_prgfRuleOkay = new bool[m_crul];
+ for (irul = 0; irul < m_crul; irul++)
+ m_prgfRuleOkay[irul] = !m_fCheckRules;
+
+ // TODO SharonC/AlanW: debuggers
+
+ return true;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Initialize a bogus pass with no rules. Currently this is used to make a single positioning
+ pass if there was none in the font.
+----------------------------------------------------------------------------------------------*/
+void GrPass::InitializeWithNoRules()
+{
+ m_crul = 0;
+ m_nMaxRuleContext = 1;
+ m_nMaxRuleLoop = 1;
+ m_nMaxBackup = 0;
+ m_pfsm = NULL;
+ m_prgchwRuleSortKeys = NULL;
+ m_prgcritRulePreModContext = NULL;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Extend the output stream by the given number of characters.
+ (Overridden by GrBidiPass.)
+
+ @param ptman - table manager
+ @param psstrmIn/Out - streams being processed
+ @param cslotNeededByNext - the number of slots being requested by the following pass
+ @param twsh - how we are handling trailing white-space
+ @param pnRet - return value
+ @param pcslotGot - return the number of slots gotten
+ @param pislotFinalBreak - return the index of the final slot, when we are removing
+ the trailing white-space and so the end of the segment
+ will be before the any actual line-break slot
+
+ @return kNextPass if we were able to generated the number requested, or processing is
+ complete; otherwise return the number of slots needed from the previous pass.
+----------------------------------------------------------------------------------------------*/
+void GrPass::ExtendOutput(GrTableManager * ptman,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut,
+ int cslotNeededByNext, TrWsHandling twsh,
+ int * pnRet, int * pcslotGot, int * pislotFinalBreak)
+{
+ // Kludge to generate an error in rendering:
+ //int z = 50;
+ //int t = ((5 * 10) / z) - 1;
+ //if (this->m_ipass == 4)
+ //{
+ // int x; x = z / t;
+ //}
+
+ int islotInitReadPos = psstrmIn->ReadPos();
+ int islotInitWritePos = psstrmOut->WritePos();
+
+ int cslotToGet = max(cslotNeededByNext,
+ m_pzpst->NeededToResync() - psstrmOut->WritePos());
+ int cslotGot = 0;
+
+ gid16 chwLB = ptman->LBGlyphID();
+
+ // While we haven't got the number of slot we've been asked for, and there is enough
+ // available in the input, run rules, filling up the output.
+
+ while ((cslotToGet > 0 && cslotGot < cslotToGet)
+ // Don't leave this pass until we've got the index offset. This is especially
+ // needed for input to the positioning pass, but it doesn't hurt to make it a
+ // general rule.
+ || !psstrmOut->GotIndexOffset()
+ // Don't leave this pass until all the slots to reprocess have been
+ // completely handled.
+ || (psstrmIn->SlotsToReprocess() > 0)
+ // Don't leave this pass until there is a complete cluster in the output
+ || (islotInitWritePos == psstrmOut->WritePos())
+ || (psstrmOut->MaxClusterSlot(islotInitWritePos, psstrmOut->WritePos()) > 0))
+ {
+ int cslotAvailable = psstrmIn->TotalSlotsPending();
+ int cslotNeedMore = MaxRuleContext() - cslotAvailable + ptman->PrevPassMaxBackup(m_ipass);
+
+ // This test should not be necessary, but just in case.
+ if (psstrmIn->PastEndOfPositioning(false))
+ cslotNeedMore = 0; // the input stream is done
+
+ if (// Not enough available in the input:
+ (cslotNeedMore > 0 && !psstrmIn->FullyWritten())
+
+ // && psstrmIn->SegLimIfKnown() == -1) && -- no, because substitution passes may need
+ // to consider slots beyond the seg limit
+
+ // Positioning passes need to know where they are in relation to the initial
+ // line-break.
+ || (IsPosPass() && !psstrmIn->GotIndexOffset())
+
+ // The following can happen on backtracking, when we undo stuff before the
+ // beginning of the segment:
+ || !ptman->Pass(m_ipass - 1)->DidResyncSkip())
+ {
+ // Ask previous pass for more input.
+ *pnRet = max(cslotNeedMore, 1);
+ *pnRet = max(*pnRet, cslotNeededByNext - cslotGot);
+ *pcslotGot = cslotGot;
+ return;
+ }
+
+ Assert(ptman->Pass(m_ipass - 1)->DidResyncSkip());
+
+ bool fDoneThisPass = (cslotAvailable == 0);
+ if (psstrmIn->SlotsToReprocess() == 0)
+ {
+ fDoneThisPass = fDoneThisPass ||
+ psstrmIn->PastEndOfPositioning(false) ||
+ psstrmOut->PastEndOfPositioning(true);
+ }
+
+ if (fDoneThisPass)
+ {
+ // No more input to process--this pass is done.
+ Assert(psstrmIn->SlotsToReprocess() == 0);
+ psstrmIn->ClearReprocBuffer();
+
+ if (twsh == ktwshNoWs && m_ipass == ptman->NumberOfLbPasses())
+ {
+ *pnRet = RemoveTrailingWhiteSpace(ptman, psstrmOut, twsh, pislotFinalBreak);
+ if (*pnRet == kBacktrack) // entire segment was white-space:
+ return; // backtrack, which will fail
+ }
+ DoResyncSkip(psstrmOut);
+ DoCleanUpSegMin(ptman, psstrmIn, islotInitReadPos, psstrmOut);
+ psstrmOut->MarkFullyWritten();
+ *pnRet = kNextPass;
+ *pcslotGot = cslotGot;
+ return;
+ }
+
+ if (twsh == ktwshOnlyWs && m_ipass == ptman->NumberOfLbPasses() + 1)
+ {
+ // Note that this is the first pass after the linebreak pass, so psstrmInput
+ // is the output of the linebreak pass.
+ GrSlotState * pslotNext = psstrmIn->Peek();
+ if (!pslotNext->IsLineBreak(chwLB) &&
+ pslotNext->Directionality() != kdircWhiteSpace &&
+ psstrmIn->SegMin() > -1 && psstrmIn->SegMin() <= psstrmIn->ReadPos())
+ {
+ // We are only allowing white-space in this segment and we hit
+ // something else. Don't process any further.
+ if (psstrmIn->SegLimIfKnown() > -1 &&
+ psstrmIn->SegLimIfKnown() <= psstrmIn->ReadPos())
+ {
+ // Already inserted a line-break; we're done.
+ DoResyncSkip(psstrmOut);
+ psstrmOut->MarkFullyWritten();
+ *pnRet = kNextPass;
+ *pcslotGot = cslotGot;
+ return;
+ }
+ while (psstrmIn->SlotsToReprocess() > 0)
+ {
+ psstrmOut->CopyOneSlotFrom(psstrmIn);
+ psstrmOut->SetPosForNextRule(0, psstrmIn, IsPosPass());
+ }
+ psstrmIn->ClearReprocBuffer();
+ *pnRet = kBacktrack;
+ return;
+ }
+ }
+
+ // Otherwise, we have enough input to run a rule.
+
+ psstrmIn->SetRuleStartReadPos();
+ psstrmOut->SetRuleStartWritePos();
+
+ int ruln = -1;
+ if (m_pfsm)
+ ruln = m_pfsm->GetRuleToApply(ptman, this, psstrmIn, psstrmOut);
+ ruln = CheckRuleValidity(ruln);
+ RunRule(ptman, ruln, psstrmIn, psstrmOut);
+
+ cslotGot = psstrmOut->WritePos() - islotInitWritePos;
+ psstrmOut->CalcIndexOffset(ptman);
+ }
+
+ DoResyncSkip(psstrmOut);
+ DoCleanUpSegMin(ptman, psstrmIn, islotInitReadPos, psstrmOut);
+
+ // We're past the point where we care about anything in the reprocessing buffer.
+ Assert(psstrmIn->NoReproc());
+ psstrmIn->ClearReprocBuffer();
+
+ if (psstrmOut->PastEndOfPositioning(true))
+ psstrmOut->MarkFullyWritten();
+
+ *pnRet = kNextPass;
+ *pcslotGot = cslotGot;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Extend the output stream by the given number of characters.
+ For a GrBidiPass, if we are at a direction change, get the entire
+ range of upstream glyphs, reverse them, and treat them as one chunk.
+ Otherwise just pass one slot through.
+
+ @param ptman - table manager
+ @param psstrmInput/Output - streams being processed
+ @param cslotNeededByNext - the number of slots being requested by the following pass
+ @param twsh - how we are handling trailing white-space
+ @param pnRet - return value
+ @param pcslotGot - return the number of slots gotten
+ @param pislotFinalBreak - not used in this version
+
+ @return 1 if we need more glyphs from the previous pass
+----------------------------------------------------------------------------------------------*/
+void GrBidiPass::ExtendOutput(GrTableManager * ptman,
+ GrSlotStream* psstrmIn, GrSlotStream* psstrmOut,
+ int cslotNeededByNext, TrWsHandling twsh,
+ int * pnRet, int * pcslotGot, int * pislotFinalBreak)
+{
+ Assert(psstrmIn->SlotsToReprocess() == 0);
+
+ int islotInitReadPos = psstrmIn->ReadPos();
+ int islotInitWritePos = psstrmOut->WritePos();
+
+ Assert(m_pzpst->NeededToResync() == 0);
+
+ int cslotToGet = max(cslotNeededByNext,
+ m_pzpst->NeededToResync() - psstrmOut->WritePos());
+ int cslotGot = 0;
+ int nTopDir;
+ if (twsh == ktwshOnlyWs)
+ nTopDir = (ptman->State()->ParaRightToLeft()) ? 1 : 0;
+ else
+ nTopDir = ptman->TopDirectionLevel();
+
+ while (cslotToGet > 0 && cslotGot < cslotToGet)
+ {
+ int islotChunkO = psstrmOut->WritePos();
+ int islotChunkI = psstrmIn->ReadPos();
+
+ // Need at least one character to test.
+ if (psstrmIn->SlotsPending() < 1 || !ptman->Pass(m_ipass-1)->DidResyncSkip())
+ {
+ if (!psstrmIn->FullyWritten())
+ {
+ // Ask previous pass for more input.
+ *pnRet = max(cslotToGet - psstrmIn->SlotsPending(), 1);
+ *pnRet = max(*pnRet, cslotNeededByNext - cslotGot);
+ *pcslotGot = cslotGot;
+ return;
+ }
+ else
+ {
+ Assert(ptman->Pass(m_ipass-1)->DidResyncSkip());
+ Assert(psstrmIn->SlotsToReprocess() == 0);
+ psstrmIn->ClearReprocBuffer();
+ DoResyncSkip(psstrmOut);
+ DoCleanUpSegMin(ptman, psstrmIn, islotInitReadPos, psstrmOut);
+ psstrmOut->MarkFullyWritten();
+ *pnRet = kNextPass;
+ *pcslotGot = cslotGot;
+ return;
+ }
+ }
+
+ std::vector<int> vislotStarts;
+ std::vector<int> vislotStops;
+ int islotReverseLim = psstrmIn->DirLevelRange(ptman->State(),
+ psstrmIn->ReadPos(), nTopDir,
+ vislotStarts, vislotStops);
+ //int islotReverseLim = psstrmIn->OldDirLevelRange(pengst, psstrmIn->ReadPos(), nTopDir);
+ if (islotReverseLim == -1)
+ {
+ // We haven't got the full range of reversed text yet--
+ // ask for more input.
+ *pnRet = max(1, cslotNeededByNext - cslotGot);
+ *pcslotGot = cslotGot;
+ return;
+ }
+
+ // Okay, we have enough input to do the reversal, if any.
+
+ int cslotToReverse = islotReverseLim - psstrmIn->ReadPos();
+
+ // Never reverse the final linebreak; leave it at the end.
+ if (cslotToReverse > 0 && islotReverseLim > 0)
+ {
+ GrSlotState * pslotLast = psstrmIn->SlotAt(islotReverseLim - 1);
+ if (pslotLast->IsFinalLineBreak(ptman->LBGlyphID()))
+ {
+ for (size_t i = 0; i < vislotStops.size(); i++)
+ if (vislotStops.back() == islotReverseLim - 1)
+ vislotStops.back() = islotReverseLim - 2;
+ islotReverseLim--;
+ cslotToReverse--;
+ }
+ }
+
+ psstrmIn->SetRuleStartReadPos();
+ psstrmOut->SetRuleStartWritePos();
+
+ if (cslotToReverse == 0)
+ {
+ psstrmOut->CopyOneSlotFrom(psstrmIn);
+ }
+ else
+ {
+ int islotNextWritePos = psstrmOut->WritePos() + cslotToReverse;
+ int islotNextReadPos = psstrmIn->ReadPos() + cslotToReverse;
+ if (vislotStarts.size() == 0)
+ {
+ Assert(false); // this should have been done by DirLevelRange
+ vislotStarts.push_back(psstrmIn->ReadPos());
+ vislotStops.push_back(islotNextReadPos - 1);
+ }
+ Assert(vislotStarts.back() == psstrmIn->ReadPos());
+ Assert(vislotStops.back() == islotNextReadPos - 1);
+ int cslotNotCopied = Reverse(ptman, psstrmIn, psstrmOut, vislotStarts, vislotStops);
+ //Reverse(nTopDir + 1,
+ // psstrmIn, psstrmIn->ReadPos(), islotReverseLim,
+ // psstrmOut, psstrmOut->WritePos() + cslotToReverse - 1, psstrmOut->WritePos()-1);
+
+ islotNextWritePos -= cslotNotCopied; // bidi markers that are not passed through
+
+ psstrmIn->SetReadPos(islotNextReadPos);
+ psstrmOut->SetWritePos(islotNextWritePos);
+
+ // It's quite strange to have the segment start or end in the middle of stuff to
+ // reverse (because the LB forms a natural terminator), but at any rate,
+ // if that happens, record the segment lim at the corresponding place in the
+ // output stream.
+ int islotSegMinIn = psstrmIn->SegMin();
+ if (islotSegMinIn > -1 &&
+ psstrmIn->ReadPos() - cslotToReverse <= islotSegMinIn &&
+ islotSegMinIn < psstrmIn->ReadPos())
+ {
+ Assert(islotSegMinIn == psstrmIn->ReadPos() - cslotToReverse); // normal situation
+ psstrmOut->SetSegMin(
+ psstrmOut->WritePos() - (psstrmIn->ReadPos() - islotSegMinIn));
+ }
+ int islotSegLimIn = psstrmIn->SegLimIfKnown();
+ if (islotSegLimIn > -1 &&
+ psstrmIn->ReadPos() - cslotToReverse <= islotSegLimIn &&
+ islotSegLimIn < psstrmIn->ReadPos())
+ {
+ Assert(islotSegLimIn == psstrmIn->ReadPos() - cslotToReverse); // normal situation
+ psstrmOut->SetSegLim(
+ psstrmOut->WritePos() - (psstrmIn->ReadPos() - islotSegLimIn));
+ }
+ }
+
+ psstrmOut->SetPosForNextRule(0, psstrmIn, false);
+
+ // Record the chunk mappings:
+ MapChunks(psstrmIn, psstrmOut, islotChunkI, islotChunkO, 0);
+
+ cslotGot = psstrmOut->WritePos() - islotInitWritePos;
+ psstrmOut->CalcIndexOffset(ptman);
+ }
+
+ DoResyncSkip(psstrmOut);
+ DoCleanUpSegMin(ptman, psstrmIn, islotInitReadPos, psstrmOut);
+
+ // We're past the point where we care about anything in the reprocessing buffer.
+ Assert(psstrmIn->NoReproc());
+ psstrmIn->ClearReprocBuffer();
+
+ Assert(psstrmIn->SlotsToReprocess() == 0);
+
+ if (psstrmOut->PastEndOfPositioning(true))
+ psstrmOut->MarkFullyWritten();
+
+ *pnRet = kNextPass;
+ *pcslotGot = cslotGot;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Generate slots containing glyph IDs for the underlying character data,
+ incrementing the input pointer as we go.
+
+ @param ptman - table manager
+ @param pchstrm - input character stream
+ @param psstrmOutput - output slot stream
+ @param ichSegLim - known end of segment, index into the text; or -1;
+ the lim of the of char-stream itself represents
+ the end of the text-source; this lim is the
+ known desired end of the segment
+ @param cchwPostXlbContext - number of characters that may be needed from the following line;
+ valid when ichSegLim > -1
+ @param lb - breakweight to use for inserted LB
+ @param cslotToGet - the number of slots being requested by the following pass
+ @param fNeedFinalBreak - true if the end of the segment needs to be a valid break point
+ @param pislotFinalBreak - the end of this segment
+----------------------------------------------------------------------------------------------*/
+int GrPass::ExtendGlyphIDOutput(GrTableManager * ptman,
+ GrCharStream * pchstrm, GrSlotStream * psstrmOut, int ichSegLim, int cchwPostXlbContext,
+ LineBrk lb, int cslotToGet, bool fNeedFinalBreak, TrWsHandling twsh,
+ int * pislotFinalBreak)
+{
+ EngineState * pengst = ptman->State();
+
+ // This pass should be the glyph-generation pass.
+ Assert(dynamic_cast<GrGlyphGenPass*>(this));
+ Assert(m_pzpst->m_cslotSkipToResync == 0);
+ m_pzpst->m_fDidResyncSkip = true;
+
+ for (int islot = 0; islot < cslotToGet; ++islot)
+ {
+ int islotChunkO = psstrmOut->WritePos();
+ int islotChunkI = pchstrm->SegOffset();
+
+ if (pchstrm->AtEnd()
+ || (ichSegLim > -1 && pchstrm->Pos() == ichSegLim))
+ {
+ if (psstrmOut->SegLimIfKnown() > -1 &&
+ psstrmOut->SegLimIfKnown() <= psstrmOut->WritePos())
+ {
+ // Already found the end of this stream.
+ }
+ else
+ {
+ if (pchstrm->EndLine() && !fNeedFinalBreak)
+ // (if we need a good final break, don't just append an LB;
+ // make it backtrack and find a valid break point)
+ {
+ // Only need to get a good break when we're backtracking; otherwise we
+ // already know it.
+ Assert(ichSegLim == -1 || !fNeedFinalBreak);
+ // Notice that we're cheating here: we're putting the LB in the zeroth
+ // stream instead of in the output of the linebreak table.
+ psstrmOut->AppendLineBreak(ptman, pchstrm,
+ (pchstrm->AtEnd() ? klbWordBreak : lb),
+ ((ptman->RightToLeft()) ? kdircRlb : kdircLlb), -1, false,
+ pchstrm->SegOffset());
+ if (pchstrm->AtEnd())
+ pengst->SetFinalLB();
+ else
+ pengst->SetInsertedLB(true);
+ }
+ else
+ {
+ // Don't actually insert a line-break glyph.
+ psstrmOut->SetSegLimToWritePos();
+ }
+ *pislotFinalBreak = psstrmOut->WritePos() - 1;
+ if (ptman->NumberOfLbPasses() > 0 && pengst->HasInitialLB())
+ {
+ // Because we cheated above: the output stream of the linekbreak table
+ // has an initial LB, which this stream doesn't have. Adjust the position
+ // of the final break to match what it will be in the output of the
+ // lb table.
+ *pislotFinalBreak += 1;
+ }
+ }
+
+ if (twsh == ktwshNoWs && m_ipass == ptman->NumberOfLbPasses())
+ {
+ int nRet = RemoveTrailingWhiteSpace(ptman, psstrmOut, twsh, pislotFinalBreak);
+ if (nRet == kBacktrack) // entire segment was white-space:
+ return kBacktrack; // backtrack, which will fail
+ }
+ if (pchstrm->AtEnd())
+ {
+ psstrmOut->MarkFullyWritten();
+ return kNextPass;
+ }
+ // otherwise we may need a few more characters for line-boundary contextualization.
+ }
+
+ int ichwSegOffset; // offset from the official start of the segment
+ int cchw; // number of 16-bit chars consumed
+ GrFeatureValues fval;
+ int nUnicode = pchstrm->NextGet(ptman, &fval, &ichwSegOffset, &cchw);
+ gid16 chwGlyphID = ptman->GetGlyphIDFromUnicode(nUnicode);
+
+ if (nUnicode == knCR || nUnicode == knLF || nUnicode == knLineSep || nUnicode == knParaSep ||
+ nUnicode == knORC)
+ {
+ // Hard line-break: we're done.
+ // Note that we don't include the hard-break character in this segment.
+ pchstrm->HitHardBreak();
+ pengst->SetHitHardBreak();
+ psstrmOut->MarkFullyWritten();
+ return kNextPass;
+ }
+
+ GrSlotState * pslotNew;
+ ptman->State()->NewSlot(chwGlyphID, fval, 0, ichwSegOffset, nUnicode, &pslotNew);
+
+ psstrmOut->NextPut(pslotNew);
+ psstrmOut->MapInputChunk(islotChunkI, islotChunkO, pchstrm->SegOffset(), false, false);
+ // Mapping the output chunks of the char stream has already been handled by the
+ // char stream.
+
+ }
+
+ psstrmOut->CalcIndexOffset(ptman);
+
+ if (psstrmOut->PastEndOfPositioning(true)
+ || (ichSegLim > -1 && pchstrm->Pos() > ichSegLim + cchwPostXlbContext))
+ {
+ // We have enough for this segment.
+ psstrmOut->MarkFullyWritten();
+ }
+
+ return kNextPass;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Extend the output stream until it is using up the allotted amount of
+ physical space. Return kNextPass when all data has been processed successfully.
+ Return kBacktrack when space overflows, indicating that we need to backtrack
+ and find a break point. Otherwise, return the number of slots we
+ need from the previous pass.
+
+ @param fWidthIsCharCount - kludge for test procedures
+ @param fInfiniteWidth - don't test for more space
+ @param fMustBacktrack - true if we need a good final break and haven't found one yet
+ @param lbMax - max allowed for the final slot
+ @param twsh - how we are handling trailing white-space
+----------------------------------------------------------------------------------------------*/
+int GrPass::ExtendFinalOutput(GrTableManager * ptman,
+ GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput,
+ float xsSpaceAllotted, bool fWidthIsCharCount, bool fInfiniteWidth,
+ bool fHaveLineBreak, bool fMustBacktrack, LineBrk lbMax, TrWsHandling twsh,
+ int * pislotLB, float * pxsWidth)
+{
+ EngineState * pengst = ptman->State();
+
+ // This pass should be the final positioning pass.
+ Assert(dynamic_cast<GrPosPass*>(this));
+
+ // It would be very strange to be positioning based on something that happened in
+ // previous line. -- not true any more, since this will include the max-precontext-length.
+// Assert(m_cslotSkipToResync == 0);
+
+ int islotOutputLB = -1;
+ //int islotInitWritePos = psstrmOutput->WritePos();
+ int islotNoLbUpTo = psstrmOutput->WritePos();;
+
+ while (true)
+ {
+ // Do this right up front, so we are only measuring actual output.
+ if (m_pzpst->CanResyncSkip(psstrmOutput))
+ m_pzpst->DoResyncSkip(psstrmOutput);
+
+ bool fMoreSpace;
+ if (!m_pzpst->DidResyncSkip())
+ fMoreSpace = true;
+ else if (fInfiniteWidth)
+ fMoreSpace = true;
+ else
+ fMoreSpace = psstrmOutput->MoreSpace(ptman,
+ xsSpaceAllotted, fWidthIsCharCount,
+ true, // always ignore trailing white space when we are first making the segment
+ twsh,
+ pxsWidth);
+ if (!fMoreSpace)
+ {
+ // Overflowed available space; backtrack and find a line break.
+ while (psstrmInput->SlotsToReprocess() > 0)
+ {
+ psstrmOutput->CopyOneSlotFrom(psstrmInput);
+ psstrmOutput->SetPosForNextRule(0, psstrmInput, IsPosPass());
+ }
+ psstrmInput->ClearReprocBuffer();
+
+ *pislotLB = -1;
+ pengst->SetExceededSpace();
+ pengst->SetHitHardBreak(false);
+ return kBacktrack;
+ }
+
+ if (islotOutputLB != -1 && psstrmInput->SlotsToReprocess() == 0)
+ {
+ // Hit the inserted line break--we're done.
+ psstrmInput->ClearReprocBuffer();
+ *pislotLB = islotOutputLB;
+ return kNextPass;
+ }
+
+ int nslotAvailable = psstrmInput->SlotsPending();
+ if ((nslotAvailable - ptman->PrevPassMaxBackup(m_ipass)
+ < MaxRuleContext() && !psstrmInput->FullyWritten())
+ || !ptman->Pass(m_ipass-1)->DidResyncSkip())
+ {
+ // Not enough available in the input--ask previous pass for more input.
+ // Ten is an arbitrary value--we ask for more that we really need to cut down
+ // on the number of times we loop between passes.
+ return max(MaxRuleContext() - (nslotAvailable - 10), 1);
+ }
+
+ Assert(ptman->Pass(m_ipass - 1)->DidResyncSkip());
+
+ if (nslotAvailable == 0)
+ {
+ // No more input to process. If we have a valid line-break, or we don't care,
+ // we're done. Otherwise backtrack to find a valid break point.
+ Assert(psstrmInput->SlotsToReprocess() == 0);
+ psstrmInput->ClearReprocBuffer();
+ if (fMustBacktrack)
+ {
+ *pislotLB = -1;
+ return kBacktrack;
+ }
+ else
+ {
+ psstrmOutput->MarkFullyWritten();
+ return kNextPass;
+ }
+ }
+
+ // Otherwise, we have enough input to run a rule.
+
+ psstrmInput->SetRuleStartReadPos();
+ psstrmOutput->SetRuleStartWritePos();
+
+ int ruln = -1;
+ if (m_pfsm)
+ ruln = m_pfsm->GetRuleToApply(ptman, this, psstrmInput, psstrmOutput);
+ ruln = CheckRuleValidity(ruln);
+ RunRule(ptman, ruln, psstrmInput, psstrmOutput);
+
+ if (fHaveLineBreak)
+ {
+ islotOutputLB =
+ psstrmOutput->FindFinalLineBreak(ptman->LBGlyphID(),
+ islotNoLbUpTo, psstrmOutput->WritePos());
+ islotNoLbUpTo = psstrmOutput->WritePos();
+ }
+
+ psstrmOutput->CalcIndexOffset(ptman);
+ }
+
+ Assert(false);
+
+ psstrmInput->ClearReprocBuffer();
+ *pislotLB = -1;
+ return kNextPass;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Remove undesirable trailing white-space.
+----------------------------------------------------------------------------------------------*/
+int GrPass::RemoveTrailingWhiteSpace(GrTableManager * ptman, GrSlotStream * psstrmOut,
+ TrWsHandling twsh, int * pislotFinalBreak)
+{
+ EngineState * pengst = ptman->State();
+
+ Assert(twsh == ktwshNoWs);
+ Assert(m_ipass == ptman->NumberOfLbPasses()); // output of (final) lb pass
+
+ int islotTmp = psstrmOut->FinalSegLim();
+ if (islotTmp <= 0)
+ return kNextPass;
+
+ GrSlotState * pslotLast = psstrmOut->SlotAt(islotTmp-1);
+ if (islotTmp > 0 && pslotLast->IsFinalLineBreak(ptman->LBGlyphID()))
+ {
+ islotTmp--;
+ pslotLast = (islotTmp > 0) ? psstrmOut->SlotAt(islotTmp-1) : NULL;
+ }
+ bool fRemovedWs = false;
+ while (islotTmp > 0 && pslotLast->Directionality() == kdircWhiteSpace)
+ {
+ islotTmp--;
+ pslotLast = (islotTmp > 0) ? psstrmOut->SlotAt(islotTmp-1) : NULL;
+ fRemovedWs = true;
+ }
+ if (fRemovedWs)
+ {
+ if (islotTmp <= 0)
+ {
+ // Entire segment was white-space: backtrack, which will fail.
+ return kBacktrack;
+ }
+ psstrmOut->SetSegLim(islotTmp);
+ *pislotFinalBreak = islotTmp - 1;
+ pengst->SetFinalLB(false);
+ pengst->SetRemovedTrWhiteSpace();
+ ptman->UnwindAndReinit(islotTmp - 1);
+ }
+
+ return kNextPass;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Keep track of whether we're advancing through the input satisfactorily;
+ if not, forcibly advance. This is a safety net to avoid infinite loops; it
+ should never be necessary if they've set up their tables right.
+----------------------------------------------------------------------------------------------*/
+void GrPass::CheckInputProgress(GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput,
+ int islotOrigInput)
+{
+ int islotInput = psstrmInput->ReadPosForNextGet();
+// Assert(islotInput >= islotOrigInput); -- no longer true now that we can back up
+
+ if (islotInput <= psstrmInput->ReadPosMax())
+ {
+ // Didn't advance.
+ if (m_pzpst->m_nRulesSinceAdvance >= m_nMaxRuleLoop)
+ {
+ bool fAdvanced = false;
+ // Forcibly advance. First try to advance to where we backed up from.
+ while (!psstrmInput->AtEnd() &&
+ psstrmInput->ReadPosForNextGet() < psstrmInput->ReadPosMax())
+ {
+ RecordHitMaxRuleLoop(psstrmInput->ReadPosForNextGet());
+ psstrmOutput->CopyOneSlotFrom(psstrmInput);
+ fAdvanced = true;
+ }
+ // If that didn't do anything productive, just advance one slot.
+ if (!fAdvanced && !psstrmInput->AtEndOfContext())
+ {
+ RecordHitMaxRuleLoop(psstrmInput->ReadPosForNextGet());
+ psstrmOutput->CopyOneSlotFrom(psstrmInput);
+ }
+
+ m_pzpst->m_nRulesSinceAdvance = 0;
+ }
+ else m_pzpst->m_nRulesSinceAdvance++;
+ }
+ else m_pzpst->m_nRulesSinceAdvance = 0;
+
+ psstrmInput->SetReadPosMax(islotInput);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Record the chunks in the streams' chunk maps.
+
+ psstrmIn/Out - streams being processed
+ islotChunkIn/Out - start of chunks
+ cslotReprocessed - number of slots to reprocess before the rule was run
+----------------------------------------------------------------------------------------------*/
+void GrPass::MapChunks(GrSlotStream * psstrmIn, GrSlotStream * psstrmOut,
+ int islotChunkIn, int islotChunkOut, int cslotReprocessed)
+{
+ if (islotChunkOut > psstrmOut->WritePos())
+ {
+ // backing up
+ int islotReadPosTmp = psstrmIn->ReadPosForNextGet();
+/// Assert((islotChunkIn - islotReadPosTmp) == (islotChunkOut - psstrmOut->WritePos()));
+// psstrmIn->MapOutputChunk(psstrmOut->WritePos() - 1, islotReadPosTmp - 1,
+// islotChunkOut, true, 0, true);
+// psstrmOut->MapInputChunk(islotReadPosTmp - 1, psstrmOut->WritePos() - 1,
+// islotChunkIn, true, true);
+
+ // Resync.
+ if (psstrmOut->WritePos() == 0)
+ {
+ // Clear all the chunks.
+ psstrmIn->MapOutputChunk(-1, -1, 0, true, 0, true);
+ psstrmOut->MapInputChunk(-1, -1, islotReadPosTmp, true, true);
+ psstrmIn->AssertChunkMapsValid(psstrmOut);
+ return;
+ }
+ else if (islotReadPosTmp == 0)
+ {
+ // Clear all the chunks.
+ psstrmIn->MapOutputChunk(-1, -1, psstrmOut->WritePos(), true, 0, true);
+ psstrmOut->MapInputChunk(-1, -1, 0, true, true);
+ psstrmIn->AssertChunkMapsValid(psstrmOut);
+ return;
+ }
+ // Find the beginning of the current chunk.
+ int islotChunkOutAdj = min(islotChunkOut, psstrmOut->WritePos() - 1);
+ int islotChunkInAdj = psstrmOut->ChunkInPrev(islotChunkOutAdj);
+ while (islotChunkInAdj == -1 && islotChunkOutAdj > 0)
+ islotChunkInAdj = psstrmOut->ChunkInPrev(--islotChunkOutAdj);
+
+ if (islotChunkInAdj == -1)
+ {
+ // Couldn't find the beginning of any chunk; zap them all.
+ psstrmIn->MapOutputChunk(-1, -1, psstrmOut->WritePos(), true, 0, true);
+ psstrmOut->MapInputChunk(-1, -1, psstrmOut->ReadPos(), true, true);
+ psstrmIn->AssertChunkMapsValid(psstrmOut);
+ return;
+ }
+
+ if (psstrmIn->ChunkInNext(islotChunkInAdj) != islotChunkOutAdj)
+ {
+ islotChunkOutAdj = psstrmIn->ChunkInNext(islotChunkInAdj);
+ while (islotChunkOutAdj == -1 && islotChunkInAdj > 0)
+ islotChunkOutAdj = psstrmIn->ChunkInNext(--islotChunkInAdj);
+ }
+
+ psstrmIn->MapOutputChunk(islotChunkOutAdj, islotChunkInAdj,
+ psstrmOut->WritePos(), false, 0, true);
+ psstrmOut->MapInputChunk(islotChunkInAdj, islotChunkOutAdj,
+ psstrmIn->ReadPos(), false, true);
+ }
+ else if (islotChunkOut == psstrmOut->WritePos())
+ // no output generated--continue the previous chunk
+ ;
+ else if (islotChunkIn == psstrmIn->ReadPos())
+ // no input consumed
+ ;
+ else
+ {
+ psstrmIn->MapOutputChunk(islotChunkOut, islotChunkIn, psstrmOut->WritePos(),
+ (cslotReprocessed > 0), cslotReprocessed, false);
+ psstrmOut->MapInputChunk(islotChunkIn, islotChunkOut, psstrmIn->ReadPos(),
+ (cslotReprocessed > 0), false);
+ }
+
+ psstrmIn->AssertChunkMapsValid(psstrmOut);
+
+ m_pzpst->m_nMaxChunk = max(m_pzpst->m_nMaxChunk, psstrmIn->LastNextChunkLength());
+}
+
+/*----------------------------------------------------------------------------------------------
+ This method is something of a kludge. During the course of running the rules we try to
+ keep track of the seg-min location, but sometimes that gets confused due to insertions
+ and deletions at the segment boundaries.
+----------------------------------------------------------------------------------------------*/
+void GrSubPass::DoCleanUpSegMin(GrTableManager * ptman,
+ GrSlotStream * psstrmIn, int islotInitReadPos, GrSlotStream * psstrmOut)
+{
+ int islotSegMinIn = psstrmIn->SegMin();
+ if (islotSegMinIn == -1)
+ return; // input doesn't even know it
+ if (islotInitReadPos > islotSegMinIn)
+ return; // should already have figured it out
+
+ // Otherwise this batch of processing likely set the seg-min on the output stream,
+ // so check it out.
+
+ // First, if the seg-min of the input stream is zero, it should be zero on the output.
+ if (islotSegMinIn == 0)
+ {
+ psstrmOut->SetSegMin(0, true);
+ return;
+ }
+
+ // If there is an initial line-break, the seg-min should be just before it.
+ int islot;
+ if (ptman->State()->HasInitialLB())
+ {
+ gid16 chwLB = ptman->LBGlyphID();
+
+ // Unfortunately, the seg-min from the previous segment can get off, too. :-(
+ // Fix it, while we're at it.
+ if (!psstrmIn->SlotAt(islotSegMinIn)->IsInitialLineBreak(chwLB))
+ {
+ for (islot = 0; islot < psstrmIn->ReadPos(); islot++)
+ if (psstrmIn->SlotAt(islot)->IsInitialLineBreak(chwLB))
+ {
+ psstrmIn->SetSegMin(islot, true);
+ break;
+ }
+ }
+ if (psstrmOut->SegMin() > -1
+ && psstrmOut->SlotAt(psstrmOut->SegMin())->IsInitialLineBreak(chwLB))
+ {
+ return; // already okay
+ }
+ for (islot = 0; islot < psstrmOut->WritePos(); islot++)
+ if (psstrmOut->SlotAt(islot)->IsInitialLineBreak(chwLB))
+ {
+ psstrmOut->SetSegMin(islot, true);
+ return;
+ }
+ Assert(false); // couldn't find it
+ }
+
+ // Otherwise, figure it out using the associations. First observe that the seg-min
+ // will be in the corresponding chunk to the seg-min of the previous pass.
+ int islotChunkMinIn = psstrmIn->ChunkInNextMin(islotSegMinIn);
+ int islotChunkLimIn = psstrmIn->ChunkInNextLim(islotSegMinIn);
+ if (islotChunkMinIn == -1) islotChunkMinIn = 0;
+ if (islotChunkLimIn == -1) islotChunkLimIn = 1;
+
+ int islotChunkMinOut = psstrmIn->ChunkInNext(islotChunkMinIn);
+ int islotChunkLimOut = psstrmIn->ChunkInNext(islotChunkLimIn);
+ if (islotChunkMinOut == -1) islotChunkMinOut = 0;
+ if (islotChunkLimOut == -1) islotChunkLimOut = 1;
+
+ int islotSegMinOut = psstrmOut->SegMin();
+ if (islotSegMinOut == -1)
+ {
+ // No reasonable guess; try to figure it out.
+ for (islot = islotChunkMinOut; islot < islotChunkLimOut; islot++)
+ {
+// GrSlotState * pslotOut = psstrmOut->SlotAt(islot);
+ if (psstrmOut->SlotAt(islot)->BeforeAssoc() == 0)
+ {
+ islotSegMinOut = islot;
+ break;
+ }
+ }
+ if (islotSegMinOut == -1)
+ {
+ // Ick, couldn't figure it out. Let's hope we set it to something reasonable earlier.
+ Assert(psstrmOut->SegMin() > -1);
+ return;
+ }
+ }
+ // else we have a reasonable guess
+
+ // islotSegMinOut is the best or at leastfirst slot in the chunk that maps into the segment.
+ // But if there is an adjacent slot inserted before it and it is in the chunk,
+ // we want to include that also.
+ while (islotSegMinOut > islotChunkMinOut
+ && psstrmOut->SlotAt(islotSegMinOut-1)->BeforeAssoc() >= 0)
+ {
+ islotSegMinOut--;
+ }
+ psstrmOut->SetSegMin(islotSegMinOut, true);
+}
+
+/*----------------------------------------------------------------------------------------------
+ If we are in a state where we are supposed to skip some of the initial output,
+ do so. The purpose of this is to resync when restarting for a segment other than the
+ first. Caller should ensure that there are enough slots to skip.
+----------------------------------------------------------------------------------------------*/
+int PassState::DoResyncSkip(GrSlotStream * psstrmOutput)
+{
+ if (m_fDidResyncSkip)
+ return 0;
+
+ if (m_cslotSkipToResync == 0)
+ {
+ m_fDidResyncSkip = true;
+ return 0;
+ }
+
+ if (!CanResyncSkip(psstrmOutput))
+ {
+ Assert(false); // caller makes sure this doesn't happen
+ return (m_cslotSkipToResync - psstrmOutput->WritePos());
+ }
+
+ psstrmOutput->ResyncSkip(m_cslotSkipToResync);
+ m_fDidResyncSkip = true;
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Run a constraint for a single rule.
+
+ @param ruln - rule to test
+ @param psstrmIn - input stream
+ @param psstrmOut - for accessing items in the pre-context
+ @param cslotPreModContext - the number of items that need to be tested prior to the
+ current stream position
+ @param cslotMatched - the number of items matched after the current stream position
+----------------------------------------------------------------------------------------------*/
+bool GrPass::RunConstraint(GrTableManager * ptman, int ruln,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut,
+ int cslotPreModContext, int cslotMatched)
+{
+ int nRet = 0;
+
+ if (m_prgibConstraintStart == NULL)
+ return true;
+
+ int biStart = int(m_prgibConstraintStart[ruln]);
+ if (biStart == 0)
+ return true; // no constraints
+
+ for (int islot = -cslotPreModContext; islot < cslotMatched; islot++)
+ {
+ nRet = RunCommandCode(ptman, m_prgbConstraintBlock + biStart, true,
+ psstrmIn, psstrmOut, islot);
+
+ if (nRet == 0) // one slot failed
+ return false;
+ }
+
+ return (nRet != 0);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Check that we can interpret all the commands in the rule. If not, return -1 indicating
+ that we don't want to run a rule after all. This can happen when the version of the compiler
+ that generated the font is later than this engine.
+----------------------------------------------------------------------------------------------*/
+int GrPass::CheckRuleValidity(int ruln)
+{
+ if (ruln == -1)
+ return -1;
+
+ if (m_prgfRuleOkay[ruln])
+ return ruln;
+
+ int biStart = m_prgibActionStart[ruln];
+ byte * pbNext = m_prgbActionBlock + biStart;
+
+ // General purpose variables:
+// int arg1, arg2, arg3, arg4;
+ int nSlotRef;
+ int nInputClass;
+ int nOutputClass;
+ int c;
+ int islotArg;
+ int nIndex;
+ int nGlyphAttr;
+ int nAttLevel;
+ int nFeat;
+ int nPState;
+// SlotAttrName slat;
+
+ int i;
+
+// int nRet = 0;
+
+ while (true) // exit by encountering PopRet or RetTrue or RetZero
+ {
+ ActionCommand op = ActionCommand(*pbNext++);
+
+ switch (op)
+ {
+ case kopNop:
+ break;
+
+ case kopPushByte:
+ pbNext++;
+ break;
+ case kopPushByteU:
+ pbNext++;
+ break;
+ case kopPushShort:
+ pbNext++;
+ pbNext++;
+ break;
+ case kopPushShortU:
+ pbNext++;
+ pbNext++;
+ break;
+ case kopPushLong:
+ pbNext++;
+ pbNext++;
+ pbNext++;
+ pbNext++;
+ break;
+
+ case kopNeg:
+ case kopTrunc8: case kopTrunc16:
+ case kopNot:
+ break;
+
+ case kopAdd: case kopSub:
+ case kopMul: case kopDiv:
+ case kopMin: case kopMax:
+ case kopAnd: case kopOr:
+ case kopEqual: case kopNotEq:
+ case kopLess: case kopGtr:
+ case kopLessEq: case kopGtrEq:
+ break;
+
+ case kopCond:
+ break;
+
+ case kopNext:
+ break;
+ case kopNextN:
+ c = *pbNext; pbNext++; // count
+ break;
+ case kopPutGlyph8bitObs:
+ nOutputClass = *pbNext++;
+ break;
+ case kopPutGlyph:
+ pbNext += 2;
+ break;
+ case kopPutCopy:
+ nSlotRef = *pbNext++;
+ break;
+ case kopPutSubs8bitObs:
+ nSlotRef = *pbNext++;
+ nInputClass = *pbNext++;
+ nOutputClass = *pbNext++;
+ break;
+ case kopPutSubs:
+ nSlotRef = *pbNext++;
+ pbNext += 4; // 2 bytes each for classes
+ break;
+ case kopCopyNext:
+ break;
+ case kopInsert:
+ break;
+ case kopDelete:
+ break;
+ case kopAssoc:
+ c = *pbNext; pbNext++;
+ for (i = 0; i < c; i++)
+ pbNext++;
+ break;
+ case kopCntxtItem:
+ islotArg = *pbNext++;
+ c = *pbNext++;
+ break;
+
+ case kopAttrSet:
+ case kopAttrAdd:
+ case kopAttrSub:
+ case kopAttrSetSlot:
+ pbNext++; // slot attribute ID
+ break;
+ case kopIAttrSet:
+ case kopIAttrAdd:
+ case kopIAttrSub:
+ case kopIAttrSetSlot:
+ pbNext++; // slot attribute ID
+ nIndex = *pbNext++; // index; eg, global ID for component
+ break;
+
+ case kopPushSlotAttr:
+ pbNext++;
+ nSlotRef = *pbNext++;
+ break;
+ case kopPushISlotAttr:
+ pbNext++;
+ nSlotRef = *pbNext++;
+ nIndex = *pbNext++;
+ break;
+
+ case kopPushGlyphAttrObs:
+ case kopPushAttToGAttrObs:
+ nGlyphAttr = *pbNext++;
+ nSlotRef = *pbNext++;
+ break;
+ case kopPushGlyphAttr:
+ case kopPushAttToGlyphAttr:
+ *pbNext += 3;
+ break;
+ case kopPushGlyphMetric:
+ case kopPushAttToGlyphMetric:
+ nGlyphAttr = *pbNext++;
+ nSlotRef = *pbNext++;
+ nAttLevel = *pbNext++;
+ break;
+ case kopPushFeat:
+ nFeat = *pbNext++;
+ nSlotRef = *pbNext++;
+ break;
+
+ case kopPushProcState:
+ nPState = *pbNext++;
+ break;
+ case kopPushVersion:
+ break;
+
+ case kopPopRet:
+ case kopRetZero:
+ case kopRetTrue:
+ m_prgfRuleOkay[ruln] = true;
+ return ruln;
+
+ default:
+ // Uninterpretable command:
+ return -1;
+ }
+ }
+
+ return ruln; // to keep compiler from griping
+}
+
+/*----------------------------------------------------------------------------------------------
+ Runs the rule, if any, otherwise just passes one character through.
+ The rule does nothing but set the line-break weights for the slots.
+
+ @param ptman - the table manager that allocates slots
+ @param ruln - number of rule to run; -1 if none applies
+ @param psstrmIn/Out - input/output stream
+----------------------------------------------------------------------------------------------*/
+void GrLineBreakPass::RunRule(GrTableManager * ptman, int ruln,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ // Remember the beginnings of the new chunk:
+ int islotIn = psstrmIn->ReadPos();
+ int islotOut = psstrmOut->WritePos();
+ int cslotReprocessed = psstrmIn->SlotsToReprocess();
+
+ if (ruln == -1)
+ {
+#ifdef OLD_TEST_STUFF
+ if (RunTestRules(ptman, ruln, psstrmIn, psstrmOut))
+#else
+ if (false)
+#endif // OLD_TEST_STUFF
+ {}
+ else
+ // Just pass one glyph through.
+ {
+ psstrmOut->CopyOneSlotFrom(psstrmIn);
+ psstrmOut->SetPosForNextRule(0, psstrmIn, false);
+ }
+ }
+ else
+ {
+ // Run the rule.
+#ifdef OLD_TEST_STUFF
+ if (RunTestRules(ptman, ruln, psstrmIn, psstrmOut))
+#else
+ if (false)
+#endif // OLD_TEST_STUFF
+ {}
+ else
+ {
+ int biStart = m_prgibActionStart[ruln];
+ int iResult = RunCommandCode(ptman, m_prgbActionBlock + biStart, false,
+ psstrmIn, psstrmOut, 0);
+ psstrmOut->SetPosForNextRule(iResult, psstrmIn, false);
+ }
+ }
+
+ CheckInputProgress(psstrmIn, psstrmOut, islotIn);
+
+ MapChunks(psstrmIn, psstrmOut, islotIn, islotOut, cslotReprocessed);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Runs the rule, if any, otherwise just passes one character through.
+ Keeps track of the association information in the slots and chunk
+ mappings for backtracking.
+
+ @param ptman - the table manager that allocates slots
+ @param ruln - number of rule to run; -1 if none applies
+ @param psstrmIn/Out - input / output streams
+----------------------------------------------------------------------------------------------*/
+void GrSubPass::RunRule(GrTableManager * ptman, int ruln,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ // Remember the beginnings of the new chunk:
+ int islotIn = psstrmIn->ReadPosForNextGet();
+ int islotOut = psstrmOut->WritePos();
+ int cslotReprocessed = psstrmIn->SlotsToReprocess();
+
+ if (ruln == -1)
+ {
+#ifdef OLD_TEST_STUFF
+ if (RunTestRules(ptman, ruln, psstrmIn, psstrmOut))
+#else
+ if (false)
+#endif // OLD_TEST_STUFF
+ {}
+ else
+ // Just pass one glyph through.
+ {
+ psstrmOut->CopyOneSlotFrom(psstrmIn);
+ psstrmOut->SetPosForNextRule(0, psstrmIn, false);
+ }
+ }
+ else
+ {
+ // Run the rule.
+#ifdef OLD_TEST_STUFF
+ if (RunTestRules(ptman, ruln, psstrmIn, psstrmOut))
+#else
+ if (false)
+#endif // OLD_TEST_STUFF
+ {}
+ else
+ /****************************/
+ {
+ int biStart = m_prgibActionStart[ruln];
+ int iResult = RunCommandCode(ptman, m_prgbActionBlock + biStart, false,
+ psstrmIn, psstrmOut, 0);
+ psstrmOut->SetPosForNextRule(iResult, psstrmIn, false);
+
+ // Restore if we need line-boundary contextualization based on physical locations
+ ////psstrmOut->SetLBContextFlag(ptman, islotOut);
+ }
+ }
+
+ CheckInputProgress(psstrmIn, psstrmOut, islotIn);
+
+ MapChunks(psstrmIn, psstrmOut, islotIn, islotOut, cslotReprocessed);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Runs the rule, if any, otherwise just positions one character in the standard way.
+ Keeps track of (among other things) the overall physical size of the output
+ and chunk mappings.
+
+ @param ptman - the table manager that allocates slots
+ @param ruln - number of rule to run; -1 if none applies
+ @param psstrmIn / Out - input / output streams
+----------------------------------------------------------------------------------------------*/
+void GrPosPass::RunRule(GrTableManager * ptman, int ruln,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ // Remember the beginnings of the new chunk:
+ int islotIn = psstrmIn->ReadPosForNextGet();
+ int islotOut = psstrmOut->WritePos();
+ int cslotReprocessed = psstrmIn->SlotsToReprocess();
+
+ int iResult = 0;
+
+ Assert(psstrmIn->GotIndexOffset());
+ // Don't do any positioning in anything being processed from the previous line.
+ if (psstrmIn->ReadPosForNextGet() < psstrmIn->IndexOffset())
+ ruln = -1;
+
+ if (ruln == -1)
+ {
+ // Just position one glyph in the standard way.
+ psstrmOut->CopyOneSlotFrom(psstrmIn);
+ iResult = 0;
+ }
+ else
+ {
+ // Run the rule.
+#ifdef OLD_TEST_STUFF
+ if (RunTestRules(ptman, ruln, psstrmIn, psstrmOut))
+#else
+ if (false)
+#endif // OLD_TEST_STUFF
+ {}
+ else
+ {
+ int biStart = m_prgibActionStart[ruln];
+ iResult = RunCommandCode(ptman, m_prgbActionBlock + biStart, false,
+ psstrmIn, psstrmOut, 0);
+ }
+ }
+
+ // Make sure an entire cluster is present in the output stream. Actually there might be
+ // interleaved clusters, which is the purpose for the loop.
+ int dislotClusterMax = 0;
+ do {
+ dislotClusterMax = psstrmIn->MaxClusterSlot(islotIn, psstrmIn->ReadPos());
+ Assert(dislotClusterMax >= 0);
+ for (int islot = 0; islot < dislotClusterMax; islot++)
+ psstrmOut->CopyOneSlotFrom(psstrmIn);
+ iResult -= dislotClusterMax;
+ } while (dislotClusterMax > 0);
+
+ psstrmOut->SetPosForNextRule(iResult, psstrmIn, true);
+
+ // Restore if we need line-boundary contextualization based on physical locations
+ ////psstrmOut->SetLBContextFlag(ptman, islotOut);
+
+ if (ruln > -1)
+ {
+ psstrmOut->CalcIndexOffset(ptman);
+ // Update the attachment trees and cluster metrics for slots modified by this rule.
+ // Note that this loop assumes that the reprocess buffer points to the identical
+ // slot objects as the output stream (not copies of the slots).
+ for (int islot = islotIn - psstrmIn->SlotsSkippedToResync();
+ islot < psstrmOut->WritePos() + psstrmIn->SlotsToReprocess();
+ islot++)
+ {
+ psstrmOut->SlotAt(islot)->HandleModifiedPosition(ptman, psstrmIn, psstrmOut, islot);
+ }
+ }
+
+ CheckInputProgress(psstrmIn, psstrmOut, islotIn);
+
+ MapChunks(psstrmIn, psstrmOut, islotIn, islotOut, cslotReprocessed);
+
+ psstrmOut->AssertStreamIndicesValid(psstrmIn);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Perform the reversal for internal bidirectionality.
+ Caller is responsible for updating the read- and write-positions.
+ Private.
+
+ OBSOLETE
+
+ @param nCurrDirection - direction level of range of reverse
+ @param psstrmIn, psstrmOut - streams
+ @param islotInMin, islotInLim - range to reverse
+ @param islotOutMin,islotOutLim - corresponding output positions; note that islotOutMin
+ will be greater than islotOutLim if we are reversing
+ reversing the slots (direction is odd)
+----------------------------------------------------------------------------------------------*/
+#if 0
+void GrBidiPass::OldReverse(int nCurrDirection,
+ GrSlotStream * psstrmIn, int islotInMin, int islotInLim,
+ GrSlotStream * psstrmOut, int islotOutMin, int islotOutLim)
+{
+ int oInc = (islotOutLim > islotOutMin)? 1: -1; // which direction output is moving in
+ // buffer (if dir is even, oInc == 1;
+ // if odd, oInc == -1)
+
+ int islotITmp = islotInMin;
+ int islotOTmp = islotOutMin;
+
+ while (islotITmp != islotInLim) {
+ // Find end of sub-range at current level to reverse.
+ int islotSubLim = psstrmIn->OldDirLevelRange(NULL, islotITmp, nCurrDirection);
+ Assert(islotSubLim >= 0);
+
+ if (islotSubLim == islotITmp) {
+ // Current slot is at this level--just copy it.
+ psstrmOut->SimpleCopyFrom(psstrmIn, islotITmp, islotOTmp);
+ islotOTmp += oInc;
+ islotITmp++;
+ }
+ else {
+ // There is a sub-range that needs to be reversed.
+ int islotONext = islotOTmp + ((islotSubLim-islotITmp) * oInc);
+ OldReverse(nCurrDirection+1,
+ psstrmIn, islotITmp, islotSubLim,
+ psstrmOut, islotONext - oInc, islotOTmp - oInc);
+ islotOTmp = islotONext;
+ islotITmp = islotSubLim;
+ }
+ }
+}
+#endif
+
+/*----------------------------------------------------------------------------------------------
+ Perform the reversal for internal bidirectionality.
+ Caller is responsible for updating the read- and write-positions.
+ Return the number of slots NOT copied because they were markers.
+ Private.
+
+ @param psstrmIn, psstrmOut - streams
+ @param vislotStarts, vislotStops - indices of ranges to reverse, from inner to outer
+----------------------------------------------------------------------------------------------*/
+int GrBidiPass::Reverse(GrTableManager * ptman,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut,
+ std::vector<int> & vislotStarts, std::vector<int> & vislotStops)
+{
+ Assert(vislotStarts.size() == vislotStops.size());
+
+ std::vector<int> vislotMap; // list of slot indices in the order they should be copied
+ // into the output
+
+ int islotOuterStart = vislotStarts.back();
+ int islotOuterStop = vislotStops.back();
+
+ // Initialize map as if nothing is reversed; eg for [2, 9]: (2 3 4 5 6 7 8 9)
+ int islot;
+ for (islot = 0; islot <= (islotOuterStop - islotOuterStart); islot++)
+ vislotMap.push_back(islot + islotOuterStart);
+
+ // Do the inner reversals first, followed by the outer reversals.
+ size_t iislot;
+ for (iislot = 0; iislot < vislotStarts.size(); iislot++)
+ {
+ // Reverse the run.
+ int islotStart = vislotStarts[iislot] - islotOuterStart;
+ int islotStop = vislotStops[iislot] - islotOuterStart;
+ int islot1, islot2;
+ for (islot1 = islotStart, islot2 = islotStop; islot1 < islot2; islot1++, islot2--)
+ {
+ int islotTmp = vislotMap[islot1];
+ vislotMap[islot1] = vislotMap[islot2];
+ vislotMap[islot2] = islotTmp;
+ }
+ }
+
+ // With vislotStarts = [7, 5, 2] and vislotStops = [8, 8, 9], we get
+ // first: (2 3 4 5 6 8 7 9)
+ // then: (2 3 4 7 8 5 6 9)
+ // and finally: (9 6 5 8 7 4 3 2)
+
+ // Now copy the slots.
+
+ int islotOutStart = psstrmOut->WritePos();
+ int cslotNotCopied = 0;
+ for (iislot = 0; iislot < vislotMap.size(); iislot++)
+ {
+ GrSlotState * pslot = psstrmIn->SlotAt(vislotMap[iislot]);
+ // Don't copy bidi markers unless they have been set to use a specific glyph.
+ if (pslot->IsBidiMarker() && pslot->ActualGlyphForOutput(ptman) == 0)
+ cslotNotCopied++;
+ else
+ psstrmOut->SimpleCopyFrom(psstrmIn, vislotMap[iislot],
+ iislot + islotOutStart - cslotNotCopied);
+ }
+ return cslotNotCopied;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Unwind the output for this pass, given that a change was assumed to have occurred
+ in the input at the given position. Return the position to which we unwound.
+----------------------------------------------------------------------------------------------*/
+int GrPass::Unwind(GrTableManager * ptman,
+ int islotChanged, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut,
+ bool fFirst)
+{
+ // Back up the number of slots required for the longest rule context,
+ // but if we land in the middle of a chunk, go forward to its boundary.
+ int islotIn = max(islotChanged - m_pzpst->MaxChunk(), 0);
+ if (!psstrmIn->NoReproc())
+ islotIn = min(islotIn, psstrmIn->ReprocMin());
+ psstrmIn->ClearReprocBuffer();
+ int islotOut = 0;
+ if (islotIn < psstrmIn->SlotsSkippedToResync() ||
+ islotIn == 0 ||
+ psstrmIn->ReadPos() == 0)
+ {
+ // The next-chunk-map is invalid. The beginning of the chunk is 0.
+ islotIn = 0;
+ islotOut = 0;
+ }
+ else if (islotIn >= psstrmIn->ReadPos())
+ {
+ // No need to unwind.
+ Assert(psstrmIn->NoReproc());
+ return psstrmOut->WritePos();
+ }
+ else
+ {
+ Assert(islotIn < psstrmIn->ReadPos());
+ islotIn = min(islotIn, psstrmIn->ReadPos() - 1);
+ while (islotIn < psstrmIn->ReadPos() &&
+ (islotOut = psstrmIn->ChunkInNext(islotIn)) == -1)
+ {
+ ++islotIn;
+ }
+ if (islotIn == psstrmIn->ReadPos())
+ islotOut = psstrmOut->WritePos();
+ }
+
+ Assert(islotOut != -2); // because the chunk size must be <= than the max-chunk,
+ // so we should never hit the end of the output stream
+
+ // Now we've found a chunk boundary.
+
+// if (fFirst)
+// Unattach(psstrmIn, islotIn, psstrmOut, islotOut, islotChanged);
+// else
+// Unattach(psstrmIn, islotIn, psstrmOut, islotOut, -1);
+
+ psstrmIn->UnwindInput(islotIn, PreBidiPass());
+ psstrmOut->UnwindOutput(islotOut, IsPosPass());
+
+ if (psstrmIn->ReadPos() < psstrmIn->SlotsSkippedToResync())
+ {
+ ptman->Pass(m_ipass - 1)->UndoResyncSkip();
+ psstrmIn->ClearSlotsSkippedToResync();
+ }
+ if (psstrmOut->WritePos() < psstrmOut->SlotsSkippedToResync())
+ {
+ Assert(psstrmOut->SlotsSkippedToResync() == m_pzpst->m_cslotSkipToResync);
+ UndoResyncSkip();
+ psstrmOut->ClearSlotsSkippedToResync();
+ }
+
+ if (ptman->LoggingTransduction())
+ m_pzpst->UnwindLogInfo(islotIn, islotOut);
+
+ return islotOut;
+}
+
+/*----------------------------------------------------------------------------------------------
+ For a GrBidiPass, just unwind to the beginning of the reordered chunk.
+----------------------------------------------------------------------------------------------*/
+int GrBidiPass::Unwind(GrTableManager * ptman,
+ int islotChanged, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut,
+ bool fFirst)
+{
+ int islotIn;
+ int islotOut;
+
+ if (islotChanged == 0)
+ {
+ islotIn = 0;
+ islotOut = 0;
+ }
+ else {
+ islotIn = min(islotChanged, psstrmIn->ReadPos());
+ islotIn = max(islotIn - 1, 0);
+ while (islotIn > 0 && !StrongDir(psstrmIn->SlotAt(islotIn)->Directionality()))
+ {
+ psstrmIn->SlotAt(islotIn)->ZapDirLevel();
+ islotIn--;
+ }
+ Assert(islotIn == 0 || psstrmIn->SlotAt(islotIn)->DirHasBeenProcessed());
+ islotOut = 0;
+ while (islotIn > 0 && (islotOut = psstrmIn->ChunkInNext(islotIn)) == -1)
+ --islotIn;
+ }
+
+ if (islotOut == -1 || islotOut == -2)
+ islotOut = 0;
+
+ // Now we've found a chunk boundary; islotI and islotO are the positions in the
+ // input and output streams, respectively.
+
+ psstrmIn->UnwindInput(islotIn, false);
+ psstrmOut->UnwindOutput(islotOut, false);
+
+ if (psstrmOut->WritePos() < m_pzpst->m_cslotSkipToResync)
+ {
+ Assert(false); // shouldn't be any of this mess for the Bidi pass
+ m_pzpst->m_fDidResyncSkip = false;
+ }
+
+ if (ptman->LoggingTransduction())
+ m_pzpst->UnwindLogInfo(islotIn, islotOut);
+
+ return islotOut;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Reinitialize part of the transduction logging information when we unwind the pass.
+----------------------------------------------------------------------------------------------*/
+void PassState::UnwindLogInfo(int islotIn, int islotOut)
+{
+ while (m_crulrec > 0 && m_rgrulrec[m_crulrec-1].m_islot >= islotIn)
+ {
+ m_crulrec--;
+ m_rgrulrec[m_crulrec].m_islot = 0;
+ m_rgrulrec[m_crulrec].m_irul = 0;
+ m_rgrulrec[m_crulrec].m_fFired = false;
+ }
+
+ for (int islot = islotOut; islot < 128; islot++)
+ {
+ m_rgcslotDeletions[islot] = 0;
+ m_rgfInsertion[islot] = false;
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Undo the side effects of attachments, ie, fix up the attachment trees as we unwind.
+
+ @param islotLB the index of the line-break that was just inserted, or -1 if this is
+ not the first pass to include line-breaks; we want to skip this slot
+ in the processing in this method
+
+ OBSOLETE
+----------------------------------------------------------------------------------------------*/
+//:Ignore
+void GrPosPass::Unattach(GrSlotStream * psstrmIn, int islotIn,
+ GrSlotStream * psstrmOut, int islotOut, int islotLB)
+{
+ // Because this is a positioning pass, there is a one-to-one correspondence between
+ // the slots in the input and the slots in the output. Thus we can make simplifying
+ // assumptions. Specifically, the chunk sizes are equal, except for the possiblity
+ // of a LB slot that we just inserted in the input stream.
+#if 0
+
+#ifdef _DEBUG
+ int islotDiff = (psstrmIn->ReadPos() - islotIn) - (psstrmOut->WritePos() - islotOut);
+ if (islotLB == -1)
+ Assert(islotDiff == 0);
+ else
+ Assert(islotDiff == 1);
+#endif // _DEBUG
+
+ int islotInLp = psstrmIn->ReadPos();
+ int islotOutLp = psstrmOut->WritePos();
+ for ( ; islotInLp-- > islotIn && islotOutLp-- > islotOut; )
+ {
+ if (islotLB == islotInLp)
+ {
+ GrSlotState * pslotTmp = psstrmIn->SlotAt(islotInLp);
+ islotInLp--;
+ }
+
+ GrSlotState * pslotIn = psstrmIn->SlotAt(islotInLp);
+ GrSlotState * pslotOut = psstrmOut->SlotAt(islotOutLp);
+
+ if (pslotIn != pslotOut)
+ {
+ GrSlotState * pslotInRoot = pslotIn->AttachRoot();
+ GrSlotState * pslotOutRoot = pslotOut->AttachRoot();
+
+ if (pslotOutRoot)
+ pslotOutRoot->RemoveLeaf(pslotOut);
+ if (pslotInRoot)
+ pslotInRoot->AddLeaf(pslotIn);
+ }
+ }
+#endif // 0
+}
+//:End Ignore
+
+
+/*----------------------------------------------------------------------------------------------
+ Record the fact that the given rule's constraint failed, for the purpose of logging
+ the transduction process.
+----------------------------------------------------------------------------------------------*/
+void GrPass::RecordRuleFailed(int islot, int irul)
+{
+ m_pzpst->RecordRule(islot, irul, false);
+}
+
+
+/*----------------------------------------------------------------------------------------------
+ Record the fact that the given rule fired, for the purpose of logging
+ the transduction process.
+----------------------------------------------------------------------------------------------*/
+void GrPass::RecordRuleFired(int islot, int irul)
+{
+ m_pzpst->RecordRule(islot, irul, true);
+}
+
+
+/*----------------------------------------------------------------------------------------------
+ Record the fact that we forcibly advanced due to the max-rule-loop.
+----------------------------------------------------------------------------------------------*/
+void GrPass::RecordHitMaxRuleLoop(int islot)
+{
+ m_pzpst->RecordRule(islot, PassState::kHitMaxRuleLoop);
+}
+
+
+/*----------------------------------------------------------------------------------------------
+ Record the fact that we forcibly advanced due to the max-backup.
+
+ In theory it should be possible to call this, but in reality, it is pretty hard to be
+ able to say that there is a rule that would have fired except it was prevent by
+ MaxBackup. So currently this method is not called.
+----------------------------------------------------------------------------------------------*/
+void GrPass::RecordHitMaxBackup(int islot)
+{
+ m_pzpst->RecordRule(islot, PassState::kHitMaxBackup);
+}
+
+
+/*----------------------------------------------------------------------------------------------
+ Record some rule-related activity on a slot.
+----------------------------------------------------------------------------------------------*/
+void PassState::RecordRule(int islot, int irul, bool fFired)
+{
+ if (m_crulrec >= 128)
+ return;
+
+ m_rgrulrec[m_crulrec].m_irul = irul;
+ m_rgrulrec[m_crulrec].m_islot = islot;
+ m_rgrulrec[m_crulrec].m_fFired = true;
+ m_rgrulrec[m_crulrec].m_fFired = fFired;
+ m_crulrec++;
+}
+
+
+/*----------------------------------------------------------------------------------------------
+ Record the fact that a slot was deleted before the given slot (in the output).
+----------------------------------------------------------------------------------------------*/
+void PassState::RecordDeletionBefore(int islot)
+{
+ if (islot >= 128)
+ return;
+
+ (m_rgcslotDeletions[islot])++;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Record the fact that the given slot was inserted into the output.
+----------------------------------------------------------------------------------------------*/
+void PassState::RecordInsertionAt(int islot)
+{
+ if (islot >= 128)
+ return;
+
+ m_rgfInsertion[islot] = true;
+}
+
+} // namespace gr