summaryrefslogtreecommitdiff
path: root/Build/source/libs/graphite/src/segment/GrPassActionCode.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/graphite/src/segment/GrPassActionCode.cpp')
-rw-r--r--Build/source/libs/graphite/src/segment/GrPassActionCode.cpp1492
1 files changed, 1492 insertions, 0 deletions
diff --git a/Build/source/libs/graphite/src/segment/GrPassActionCode.cpp b/Build/source/libs/graphite/src/segment/GrPassActionCode.cpp
new file mode 100644
index 00000000000..83c58b27e48
--- /dev/null
+++ b/Build/source/libs/graphite/src/segment/GrPassActionCode.cpp
@@ -0,0 +1,1492 @@
+/*--------------------------------------------------------------------*//*: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: GrPassActionCode.cpp
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+ A continution of the GrPass file, including functions to run the action commands.
+
+This comment could create a merge conflict. It can be removed.
+----------------------------------------------------------------------------------------------*/
+
+//:>********************************************************************************************
+//:> Include files
+//:>********************************************************************************************
+#include "Main.h"
+
+#ifdef _MSC_VER
+#pragma hdrstop
+#endif
+#undef THIS_FILE
+DEFINE_THIS_FILE
+
+//:End Ignore
+
+//:>********************************************************************************************
+//:> Forward declarations
+//:>********************************************************************************************
+
+//:>********************************************************************************************
+//:> Local type definitions
+//:>********************************************************************************************
+
+typedef signed char Int8; // signed value
+typedef unsigned char Uint8; // unsigned value
+
+
+namespace gr
+{
+
+//:>********************************************************************************************
+//:> Methods
+//:>********************************************************************************************
+
+/*----------------------------------------------------------------------------------------------
+ The main function to run a block of action or constraint code and return a result.
+
+ @param ptman - table manager, for generating new slots; NULL when
+ running constraints
+ @param pbStart - address of the first command
+ @param fConstraints - true if we are running constraint tests;
+ false if we are running rule actions
+ @param psstrmIn - input stream
+ @param psstrmOut - output stream; when running constraints, used to access items
+ in the precontext
+ @param islot - slot being processed relative to the start of the rule;
+ used only for constraints; must be 0 for rule actions
+----------------------------------------------------------------------------------------------*/
+int GrPass::RunCommandCode(GrTableManager * ptman,
+ byte * pbStart, bool fConstraints,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut, int islot)
+{
+ byte * pbNext = pbStart;
+
+// std::vector<int> vnStack;
+// vnStack.EnsureSpace(128); // make it nice and big
+ m_vnStack.clear();
+
+ gAssert(fConstraints || islot == 0);
+
+ // There are two states: fMustGet = true means we need to get a slot to work on from
+ // the input; fMustGet = false means we have a slot and we need to do a Next before
+ // we can get the next one.
+ bool fMustGet = !fConstraints;
+
+ bool fInserting = false; // set to true by an Insert command
+
+ int nRet = 0;
+
+ while (true)
+ {
+ ActionCommand op = ActionCommand(*pbNext++);
+ StackMachineFlag smf;
+ nRet = RunOneCommand(ptman, fConstraints, op,
+ &pbNext, &fMustGet, &fInserting,
+ psstrmIn, psstrmOut, islot,
+ m_vnStack, &smf);
+
+ if (smf == ksmfDone)
+ return nRet;
+
+ if (smf == ksmfUnderflow)
+ {
+ Warn("Underflow in Graphite stack machine");
+ gAssert(false);
+ FontException fexptn;
+ fexptn.version = -1;
+ fexptn.subVersion = -1;
+ fexptn.errorCode = kferrUnknown;
+ throw fexptn; // disastrous error in rendering; fall back to dumb rendering
+ }
+ }
+ return nRet; // not needed, but to avoid compiler warning
+}
+
+/*----------------------------------------------------------------------------------------------
+ Perform a single command. Specifically, read the arguments from the byte buffer and the
+ run the appropriate functions.
+
+ @param ptman - table manager, for generating new slots; or NULL
+ @param fConstraints - true if we are running constraints; false if we are running
+ rule actions
+ @param op - command operator
+ @param ppbArg - pointer to first argument
+ @param pfMustGet - state: getting input or processing it; when running constraints,
+ always false
+ @param pfInserting - true if current item is to be inserted, or was inserted
+ @param psstrmIn - input stream
+ @param psstrmOut - output stream
+ @param islot - the slot being processed relative to the beginning of the rule;
+ only relevant for constraint testing, must be 0 for rule actions
+ @param vnStack - the stack of values being manipulated
+ @param psmf - error code, done flag, or continue flag
+----------------------------------------------------------------------------------------------*/
+int GrPass::RunOneCommand(GrTableManager * ptman, bool fConstraints,
+ ActionCommand op, byte ** ppbArg, bool * pfMustGet, bool * pfInserting,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut, int islot,
+ std::vector<int> & vnStack, StackMachineFlag * psmf)
+{
+ *psmf = ksmfContinue;
+
+ // 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;
+ std::vector<int> vnTmp;
+
+ byte * pbNext = *ppbArg;
+
+ int nRet = 0;
+
+ switch (op)
+ {
+ case kopNop:
+ break;
+
+ case kopPushByte:
+ arg1 = Int8(*pbNext++);
+ vnStack.push_back(arg1);
+ break;
+ case kopPushByteU:
+ arg1 = Uint8(*pbNext++);
+ vnStack.push_back(arg1);
+ break;
+ case kopPushShort:
+ arg1 = Int8(*pbNext++);
+ arg2 = Uint8(*pbNext++);
+ vnStack.push_back((arg1 << 8) + arg2);
+ break;
+ case kopPushShortU:
+ arg1 = Uint8(*pbNext++);
+ arg2 = Uint8(*pbNext++);
+ vnStack.push_back((arg1 << 8) + arg2);
+ break;
+ case kopPushLong:
+ arg1 = Int8(*pbNext++);
+ arg2 = Uint8(*pbNext++);
+ arg3 = Uint8(*pbNext++);
+ arg4 = Uint8(*pbNext++);
+ vnStack.push_back((arg1 << 24) + (arg2 << 16) + (arg3 << 8) + arg4);
+ break;
+
+ case kopNeg:
+ case kopTrunc8: case kopTrunc16:
+ case kopNot:
+ DoStackArithmetic1Arg(op, vnStack, psmf);
+ if (*psmf != ksmfContinue)
+ return 0;
+ 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:
+ DoStackArithmetic2Args(op, vnStack, psmf);
+ if (*psmf != ksmfContinue)
+ return 0;
+ break;
+
+ case kopCond:
+ DoConditional(vnStack, psmf);
+ if (*psmf != ksmfContinue)
+ return 0;
+ break;
+
+ case kopNext:
+ if (fConstraints)
+ {
+ gAssert(false);
+ }
+ else
+ {
+ gAssert(!*pfMustGet);
+ DoNext(ptman, 1, psstrmIn, psstrmOut);
+ *pfMustGet = true;
+ *pfInserting = false;
+ }
+ break;
+ case kopNextN:
+ c = Int8(*pbNext++);
+ if (fConstraints)
+ {
+ gAssert(false);
+ }
+ else
+ {
+ gAssert(false); // for now we don't allow anything other than moving one slot
+ gAssert(!*pfMustGet); // forward at a time
+ DoNext(ptman, c, psstrmIn, psstrmOut);
+ *pfMustGet = true;
+ }
+ break;
+ case kopPutGlyph8bitObs:
+ case kopPutGlyph:
+ if (op == kopPutGlyph8bitObs)
+ nOutputClass = Uint8(*pbNext++);
+ else
+ {
+ nOutputClass = (Uint8(*pbNext++) << 8);
+ nOutputClass += Uint8(*pbNext++);
+ }
+ if (fConstraints)
+ {
+ gAssert(false);
+ }
+ else
+ {
+ gAssert(*pfMustGet);
+ DoPutGlyph(ptman, *pfInserting, nOutputClass, psstrmIn, psstrmOut);
+ *pfMustGet = false;
+ }
+ break;
+ case kopPutCopy:
+ nSlotRef = Int8(*pbNext++);
+ if (fConstraints)
+ {
+ gAssert(false);
+ }
+ else
+ {
+ gAssert(*pfMustGet);
+ DoPutCopy(ptman, *pfInserting, nSlotRef, psstrmIn, psstrmOut);
+ *pfMustGet = false;
+ }
+ break;
+ case kopPutSubs8bitObs:
+ case kopPutSubs:
+ nSlotRef = Int8(*pbNext++);
+ if (op == kopPutSubs8bitObs)
+ {
+ nInputClass = Uint8(*pbNext++);
+ nOutputClass = Uint8(*pbNext++);
+ }
+ else
+ {
+ nInputClass = (Uint8(*pbNext++) << 8);
+ nInputClass += Uint8(*pbNext++);
+ nOutputClass = (Uint8(*pbNext++) << 8);
+ nOutputClass += Uint8(*pbNext++);
+ }
+ if (fConstraints)
+ {
+ gAssert(false);
+ }
+ else
+ {
+ gAssert(*pfMustGet);
+ DoPutSubs(ptman, *pfInserting, nSlotRef, nInputClass, nOutputClass,
+ psstrmIn, psstrmOut);
+ *pfMustGet = false;
+ }
+ break;
+ case kopCopyNext:
+ if (fConstraints)
+ {
+ gAssert(false);
+ }
+ else
+ {
+ gAssert(*pfMustGet);
+ gAssert(!*pfInserting); // 0 means copy this slot
+ DoPutCopy(ptman, *pfInserting, 0, psstrmIn, psstrmOut);
+ DoNext(ptman, 1, psstrmIn, psstrmOut);
+ // *pfMustGet still = true
+ }
+ break;
+ case kopInsert:
+ if (fConstraints)
+ {
+ gAssert(false);
+ }
+ else
+ {
+ gAssert(*pfMustGet);
+ *pfInserting = true;
+ // *pfMustGet still = true
+
+ if (ptman->LoggingTransduction())
+ m_pzpst->RecordInsertionAt(psstrmOut->WritePos());
+ }
+ break;
+ case kopDelete:
+ if (fConstraints)
+ {
+ gAssert(false);
+ }
+ else
+ {
+ gAssert(*pfMustGet);
+ DoDelete(ptman, psstrmIn, psstrmOut);
+ *pfMustGet = false;
+ }
+ break;
+ case kopAssoc:
+ c = Uint8(*pbNext++);
+ // std::vector<int> vnTmp;
+ for (i = 0; i < c; i++)
+ vnTmp.push_back(Int8(*pbNext++));
+ if (fConstraints)
+ {
+ gAssert(false);
+ }
+ else
+ {
+ gAssert(!*pfMustGet);
+ DoAssoc(c, vnTmp, *pfInserting, psstrmIn, psstrmOut);
+ }
+ break;
+ case kopCntxtItem:
+ islotArg = Int8(*pbNext++);
+ c = Uint8(*pbNext++);
+ if (fConstraints)
+ {
+ // Old approach:
+ // If this is NOT the relevant item, push TRUE, which causes the subsequent tests
+ // (which are eventually ORed with it) to become irrelevant.
+ //vnStack.Push((int)(islotArg != islot));
+
+ // If this is not the relevant item, skip the specified number of bytes.
+ if (islotArg != islot)
+ {
+ pbNext += c;
+ vnStack.push_back(1);
+ }
+ }
+ else
+ {
+ gAssert(false);
+ }
+ break;
+
+ case kopAttrSet:
+ case kopAttrAdd:
+ case kopAttrSub:
+ case kopAttrSetSlot:
+ slat = SlotAttrName(Uint8(*pbNext++)); // slot attribute ID
+ if (fConstraints)
+ {
+ gAssert(false);
+ }
+ else
+ {
+ gAssert(!*pfMustGet);
+ DoSetAttr(ptman, op, *pfInserting, slat, -1, vnStack, psstrmIn, psstrmOut);
+ if (*psmf != ksmfContinue)
+ return 0;
+ }
+ break;
+ case kopIAttrSet:
+ case kopIAttrAdd:
+ case kopIAttrSub:
+ case kopIAttrSetSlot:
+ slat = SlotAttrName(Uint8(*pbNext++)); // slot attribute ID
+ nIndex = Uint8(*pbNext++); // index; eg, global ID for component
+ if (fConstraints)
+ {
+ gAssert(false);
+ }
+ else
+ {
+ gAssert(!*pfMustGet);
+ DoSetAttr(ptman, op, *pfInserting, slat, nIndex, vnStack,
+ psstrmIn, psstrmOut);
+ if (*psmf != ksmfContinue)
+ return 0;
+ }
+ break;
+
+ case kopPushSlotAttr:
+ slat = SlotAttrName(Uint8(*pbNext++));
+ nSlotRef = Int8(*pbNext++);
+ if (fConstraints)
+ nSlotRef += islot + 1; // +1 to peek ahead to a slot we haven't "got" yet
+ DoPushSlotAttr(ptman, nSlotRef, *pfInserting, slat, -1, vnStack, psstrmIn, psstrmOut);
+ if (*psmf != ksmfContinue)
+ return 0;
+ break;
+ case kopPushISlotAttr:
+ slat = SlotAttrName(Uint8(*pbNext++));
+ nSlotRef = Int8(*pbNext++);
+ nIndex = Uint8(*pbNext++);
+ if (fConstraints)
+ nSlotRef += islot + 1; // +1 to peek ahead to a slot we haven't "got" yet
+ DoPushSlotAttr(ptman, nSlotRef, *pfInserting, slat, nIndex, vnStack, psstrmIn, psstrmOut);
+ if (*psmf != ksmfContinue)
+ return 0;
+ break;
+
+ case kopPushGlyphAttrObs:
+ case kopPushAttToGAttrObs:
+ case kopPushGlyphAttr:
+ case kopPushAttToGlyphAttr:
+ if (op == kopPushGlyphAttrObs || op == kopPushAttToGAttrObs)
+ nGlyphAttr = Uint8(*pbNext++);
+ else {
+ nGlyphAttr = (Uint8(*pbNext++) << 8);
+ nGlyphAttr += Uint8(*pbNext++);
+ }
+ nSlotRef = Int8(*pbNext++);
+ if (fConstraints)
+ nSlotRef += islot + 1; // +1 to peek ahead to a slot we haven't "got" yet
+ if (op == kopPushAttToGlyphAttr || op == kopPushAttToGAttrObs)
+ DoPushAttToGlyphAttr(ptman, nSlotRef, *pfInserting, nGlyphAttr,
+ vnStack, psstrmIn, psstrmOut);
+ else
+ DoPushGlyphAttr(ptman, nSlotRef, *pfInserting, nGlyphAttr, vnStack,
+ psstrmIn, psstrmOut);
+ if (*psmf != ksmfContinue)
+ return 0;
+ break;
+ case kopPushGlyphMetric:
+ case kopPushAttToGlyphMetric:
+ nGlyphAttr = Uint8(*pbNext++);
+ nSlotRef = Int8(*pbNext++);
+ nAttLevel = Int8(*pbNext++);
+ if (fConstraints)
+ nSlotRef += islot + 1; // +1 to peek ahead to a slot we haven't "got" yet
+ if (op == kopPushAttToGlyphMetric)
+ DoPushAttToGlyphMetric(ptman, nSlotRef, *pfInserting, nGlyphAttr, nAttLevel,
+ vnStack, psstrmIn, psstrmOut);
+ else
+ DoPushGlyphMetric(ptman, nSlotRef, *pfInserting, nGlyphAttr, nAttLevel,
+ vnStack, psstrmIn, psstrmOut);
+ if (*psmf != ksmfContinue)
+ return 0;
+ break;
+ case kopPushFeat:
+ nFeat = Uint8(*pbNext++);
+ nSlotRef = Int8(*pbNext++);
+ if (fConstraints)
+ nSlotRef += islot + 1; // +1 to peek ahead to a slot we haven't "got" yet
+// else
+// nSlotRef = 0;
+ DoPushFeatValue(ptman, nSlotRef, *pfInserting, nFeat, vnStack, psstrmIn, psstrmOut);
+ if (*psmf != ksmfContinue)
+ return 0;
+ break;
+ case kopPushProcState:
+ nPState = Uint8(*pbNext++);
+ gAssert(fConstraints);
+ DoPushProcState(ptman, nPState, vnStack);
+ break;
+ case kopPushVersion:
+ vnStack.push_back(kRuleVersion);
+ break;
+ case kopPopRet:
+ if ((*psmf = CheckStack(vnStack, 1)) != ksmfContinue)
+ return 0;
+ nRet = vnStack.back();
+ vnStack.pop_back();
+ if (vnStack.size() != 0)
+ {
+ gAssert(false);
+ *psmf = ksmfStackNotEmptied;
+ }
+ else
+ *psmf = ksmfDone;
+ break;
+ case kopRetZero:
+ nRet = 0;
+ if (vnStack.size() != 0)
+ {
+ gAssert(false);
+ *psmf = ksmfStackNotEmptied;
+ }
+ else
+ *psmf = ksmfDone;
+ break;
+ case kopRetTrue:
+ nRet = 1;
+ if (vnStack.size() != 0)
+ {
+ gAssert(false);
+ *psmf = ksmfStackNotEmptied;
+ }
+ else
+ *psmf = ksmfDone;
+ break;
+
+ default:
+ gAssert(false);
+ }
+
+ *ppbArg = pbNext;
+ return nRet;
+}
+
+/*----------------------------------------------------------------------------------------------
+ Perform arithmetic functions that take two arguments.
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoStackArithmetic2Args(ActionCommand op, std::vector<int> & vnStack,
+ StackMachineFlag * psmf)
+{
+ if ((*psmf = CheckStack(vnStack, 2)) != ksmfContinue)
+ return;
+
+ int nArg2 = vnStack.back();
+ vnStack.pop_back();
+ int nArg1 = vnStack.back();
+ vnStack.pop_back();
+
+ int nResult;
+
+ switch (op)
+ {
+ case kopAdd: nResult = nArg1 + nArg2; break;
+ case kopSub: nResult = nArg1 - nArg2; break;
+ case kopMul: nResult = nArg1 * nArg2; break;
+ case kopDiv: nResult = nArg1 / nArg2; break;
+ case kopMin: nResult = min(nArg1, nArg2); break;
+ case kopMax: nResult = max(nArg1, nArg2); break;
+ case kopAnd: nResult = (nArg1 != 0 && nArg2 != 0)? 1: 0; break;
+ case kopOr: nResult = (nArg1 != 0 || nArg2 != 0)? 1: 0; break;
+ case kopEqual: nResult = (nArg1 == nArg2)? 1: 0; break;
+ case kopNotEq: nResult = (nArg1 != nArg2)? 1: 0; break;
+ case kopLess: nResult = (nArg1 < nArg2)? 1: 0; break;
+ case kopLessEq: nResult = (nArg1 <= nArg2)? 1: 0; break;
+ case kopGtr: nResult = (nArg1 > nArg2)? 1: 0; break;
+ case kopGtrEq: nResult = (nArg1 >= nArg2)? 1: 0; break;
+ default:
+ Assert(false);
+ }
+
+ vnStack.push_back(nResult);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Perform arithmetic functions that take one argument.
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoStackArithmetic1Arg(ActionCommand op, std::vector<int> & vnStack,
+ StackMachineFlag * psmf)
+{
+ if ((*psmf = CheckStack(vnStack, 1)) != ksmfContinue)
+ return;
+
+ int nArg = vnStack.back();
+ vnStack.pop_back();
+ int nResult;
+
+ switch (op)
+ {
+ case kopNeg: nResult = nArg * -1; break;
+ case kopTrunc8: nResult = nArg & 0xFF; break;
+ case kopTrunc16: nResult = nArg & 0xFFFF; break;
+ case kopNot: nResult = (nArg == 0)? 1: 0; break;
+ default:
+ Assert(false);
+ }
+
+ vnStack.push_back(nResult);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Perform the conditional statement.
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoConditional(std::vector<int> & vnStack, StackMachineFlag * psmf)
+{
+ if ((*psmf = CheckStack(vnStack, 3)) != ksmfContinue)
+ return;
+
+ int nArg3 = vnStack.back();
+ vnStack.pop_back();
+ int nArg2 = vnStack.back();
+ vnStack.pop_back();
+ int nArg1 = vnStack.back();
+ vnStack.pop_back();
+
+ if (nArg1 == 0)
+ vnStack.push_back(nArg3);
+ else
+ vnStack.push_back(nArg2);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Check to make sure the stack has the appropriate number of items on it; if not,
+ return a stack error flag.
+----------------------------------------------------------------------------------------------*/
+GrPass::StackMachineFlag GrPass::CheckStack(std::vector<int> & vnStack, int cn)
+{
+ if (signed(vnStack.size()) < cn)
+ return ksmfUnderflow;
+ else
+ return ksmfContinue;
+}
+
+/*----------------------------------------------------------------------------------------------
+ We are finished processing a slot; go on to the next slot, or possibly go backwards.
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoNext(GrTableManager * ptman,
+ int cslot, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ gAssert(cslot == 1); // for now anyway
+}
+
+/*----------------------------------------------------------------------------------------------
+ Set the next glyph to be the given class. There should only be one member of the class,
+ but if there happens to be more than one, just use the first member.
+ All the slot attributes remain unchanged from the current input slot; associations are
+ neutralized.
+
+ @param ptman - table manager, for generating new slots
+ @param fInserting - true if this slot is being inserted, not copied
+ @param nReplacementClass - class from which to take replacement glyph (corresponding to
+ selector slot's glyph's index in selector class)
+ @param psstrmIn / Out - input/output streams
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoPutGlyph(GrTableManager * ptman, bool fInserting, int nReplacementClass,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ EngineState * pengst = ptman->State();
+
+ // If we are exactly at the segment boundary, pass the information on to the output stream.
+ // Note that inserted items always go outside the segment, if they are at the boundary
+ // (you DON'T want them between the segment boundary and the LB slot!).
+ bool fSetSegMin = psstrmIn->AtSegMin() && !fInserting;
+ bool fSetSegLim = psstrmIn->AtSegLim();
+
+ // Slot to copy features and text properties from:
+ GrSlotState * pslotNextInput;
+ if (psstrmIn->AtEndOfContext())
+ {
+ gAssert(fInserting);
+ pslotNextInput = psstrmIn->RuleInputSlot(0, psstrmOut);
+ }
+ else
+ pslotNextInput = (fInserting)? psstrmIn->Peek(): psstrmIn->NextGet();
+
+ gid16 nGlyphReplacement = ptman->GetClassGlyphIDAt(nReplacementClass, 0);
+
+ GrSlotState * pslotNew;
+ if (fInserting)
+ {
+ pengst->NewSlot(nGlyphReplacement, pslotNextInput, m_ipass, &pslotNew);
+ // leave associations empty; eventually they will be "neutralized"
+ }
+ else
+ {
+ pengst->NewSlotCopy(pslotNextInput, m_ipass, &pslotNew);
+ pslotNew->SetGlyphID(nGlyphReplacement);
+ ptman->SetSlotAttrsFromGlyphAttrs(pslotNew);
+ }
+
+ if (fSetSegMin)
+ psstrmOut->SetSegMinToWritePos(false);
+ if (fSetSegLim)
+ psstrmOut->SetSegLimToWritePos(false);
+ psstrmOut->NextPut(pslotNew);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Copy a glyph from the given slot in the input to the output. All the associations and slot
+ attributes are copied from the specified slot as well. Consume a slot from the input
+ (which may or may not be the slot we're copying).
+
+ @param ptman - table manager, for generating new slots
+ @param fInserting - true if this slot is being inserted, not copied
+ @param cslotCopyFrom - slot to copy from
+ @param psstrmIn / Out - input/output streams
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoPutCopy(GrTableManager * ptman, bool fInserting, int cslotCopyFrom,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ EngineState * pengst = ptman->State();
+
+ // If we are exactly at the segment boundary, pass the information on to the output stream.
+ // Note that inserted items always go outside the segment, if they are at the boundary.
+ bool fSetSegMin = psstrmIn->AtSegMin() && !fInserting;
+ bool fSetSegLim = psstrmIn->AtSegLim();
+
+ if (!fInserting)
+ {
+ gAssert(!psstrmIn->AtEndOfContext());
+ // Absorb next slot
+ psstrmIn->NextGet();
+ }
+
+ GrSlotState * pslotCopyFrom = psstrmIn->RuleInputSlot(cslotCopyFrom, psstrmOut);
+
+ GrSlotState * pslotNew;
+ pengst->NewSlotCopy(pslotCopyFrom, m_ipass, &pslotNew);
+
+ if (fSetSegMin)
+ psstrmOut->SetSegMinToWritePos(false);
+ if (fSetSegLim)
+ psstrmOut->SetSegLimToWritePos(false);
+ psstrmOut->NextPut(pslotNew);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Copy the current slot from the input to the output, substituting the corresponding glyph
+ in the output class. All the associations and slot attributes remain unchanged from the
+ current input slot.
+
+ @param ptman - table manager, for generating new slots
+ @param fInserting - true if this slot is being inserted, not copied
+ @param cslotSel - selector slot, relative to current slot
+ @param nSelectorClass - class of selector slot
+ @param nReplacementClass - class from which to take replacement glyph (corresponding to
+ selector slot's glyph's index in selector class)
+ @param psstrmIn / Out - input/output streams
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoPutSubs(GrTableManager * ptman, bool fInserting,
+ int cslotSel, int nSelClass, int nReplacementClass,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ bool fAtSegMin, fAtSegLim;
+ GrSlotState * pslotNextInput;
+ DoPutSubsInit(psstrmIn, psstrmOut, fInserting, &pslotNextInput, &fAtSegMin, &fAtSegLim);
+
+ GrSlotState * pslotInSelector = psstrmIn->RuleInputSlot(cslotSel, psstrmOut);
+
+ gid16 gidSelector = pslotInSelector->GlyphID();
+ int nSelIndex = ptman->GetIndexInGlyphClass(nSelClass, gidSelector);
+ gAssert(nSelIndex != -1);
+ gid16 gidReplacement = (nSelIndex == -1)?
+ gidSelector:
+ ptman->GetClassGlyphIDAt(nReplacementClass, nSelIndex);
+
+ DoPutSubsAux(ptman, fInserting, gidReplacement, psstrmIn, psstrmOut, pslotNextInput,
+ fAtSegMin, fAtSegLim);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Copy the current slot from the input to the output, substituting the corresponding glyph
+ in the output class based on 2 input classes. All the associations and slot attributes
+ remain unchanged from the current input slot.
+
+ @param ptman - table manager, for generating new slots
+ @param fInserting - true if this slot is being inserted, not copied
+ @param cslotSel - selector slot, relative to current slot
+ @param nSelectorClass - class of selector slot
+ @param nReplacementClass - class from which to take replacement glyph (corresponding to
+ selector slot's glyph's index in selector class)
+ @param psstrmIn / Out - input/output streams
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoPutSubs2(GrTableManager * ptman, bool fInserting,
+ int cslotSel1, int nSelClass1, int cslotSel2, int nSelClass2, int nReplacementClass,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ bool fAtSegMin, fAtSegLim;
+ GrSlotState * pslotNextInput;
+ DoPutSubsInit(psstrmIn, psstrmOut, fInserting, &pslotNextInput, &fAtSegMin, &fAtSegLim);
+
+ GrSlotState * pslotInSelector1 = psstrmIn->RuleInputSlot(cslotSel1, psstrmOut);
+ gid16 gidSelector1 = pslotInSelector1->GlyphID();
+ int nSelIndex1 = ptman->GetIndexInGlyphClass(nSelClass1, gidSelector1);
+ gAssert(nSelIndex1 != -1);
+ //size_t cClassLen1 = ptman->NumberOfGlyphsInClass(nSelClass1);
+
+ GrSlotState * pslotInSelector2 = psstrmIn->RuleInputSlot(cslotSel2, psstrmOut);
+ gid16 gidSelector2 = pslotInSelector2->GlyphID();
+ int nSelIndex2 = ptman->GetIndexInGlyphClass(nSelClass2, gidSelector2);
+ gAssert(nSelIndex2 != -1);
+ size_t cClassLen2 = ptman->NumberOfGlyphsInClass(nSelClass2);
+
+ int nSelIndex = (nSelIndex1 == -1 || nSelIndex2 == -1) ?
+ -1 :
+ (nSelIndex1 * static_cast<int>(cClassLen2)) + nSelIndex2;
+
+ gid16 gidReplacement = (nSelIndex == -1)?
+ gidSelector1:
+ ptman->GetClassGlyphIDAt(nReplacementClass, nSelIndex);
+
+ DoPutSubsAux(ptman, fInserting, gidReplacement, psstrmIn, psstrmOut, pslotNextInput,
+ fAtSegMin, fAtSegLim);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Copy the current slot from the input to the output, substituting the corresponding glyph
+ in the output class based on 2 input classes. All the associations and slot attributes
+ remain unchanged from the current input slot.
+
+ @param ptman - table manager, for generating new slots
+ @param fInserting - true if this slot is being inserted, not copied
+ @param cslotSel - selector slot, relative to current slot
+ @param nSelectorClass - class of selector slot
+ @param nReplacementClass - class from which to take replacement glyph (corresponding to
+ selector slot's glyph's index in selector class)
+ @param psstrmIn / Out - input/output streams
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoPutSubs3(GrTableManager * ptman, bool fInserting,
+ int cslotSel1, int nSelClass1, int cslotSel2, int nSelClass2, int cslotSel3, int nSelClass3,
+ int nReplacementClass,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ bool fAtSegMin, fAtSegLim;
+ GrSlotState * pslotNextInput;
+ DoPutSubsInit(psstrmIn, psstrmOut, fInserting, &pslotNextInput, &fAtSegMin, &fAtSegLim);
+
+ GrSlotState * pslotInSelector1 = psstrmIn->RuleInputSlot(cslotSel1, psstrmOut);
+ gid16 gidSelector1 = pslotInSelector1->GlyphID();
+ int nSelIndex1 = ptman->GetIndexInGlyphClass(nSelClass1, gidSelector1);
+ gAssert(nSelIndex1 != -1);
+ //size_t cClassLen1 = ptman->NumberOfGlyphsInClass(nSelClass1);
+
+ GrSlotState * pslotInSelector2 = psstrmIn->RuleInputSlot(cslotSel2, psstrmOut);
+ gid16 gidSelector2 = pslotInSelector2->GlyphID();
+ int nSelIndex2 = ptman->GetIndexInGlyphClass(nSelClass2, gidSelector2);
+ gAssert(nSelIndex2 != -1);
+ size_t cClassLen2 = ptman->NumberOfGlyphsInClass(nSelClass2);
+
+// GrSlotState * pslotInSelector3 = psstrmIn->RuleInputSlot(cslotSel3, psstrmOut);
+// gid16 gidSelector3 = pslotInSelector3->GlyphID();
+ int nSelIndex3 = ptman->GetIndexInGlyphClass(nSelClass3, gidSelector2);
+ gAssert(nSelIndex3 != -1);
+ size_t cClassLen3 = ptman->NumberOfGlyphsInClass(nSelClass3);
+
+ int nSelIndex = (nSelIndex1 == -1 || nSelIndex2 == -1 || nSelIndex3 == -1) ?
+ -1 :
+ (((nSelIndex1 * static_cast<int>(cClassLen2)) + nSelIndex2) * static_cast<int>(cClassLen3)) + nSelIndex3;
+
+ gid16 gidReplacement = (nSelIndex == -1)?
+ gidSelector1:
+ ptman->GetClassGlyphIDAt(nReplacementClass, nSelIndex);
+
+ DoPutSubsAux(ptman, fInserting, gidReplacement, psstrmIn, psstrmOut, pslotNextInput,
+ fAtSegMin, fAtSegLim);
+}
+
+
+/*----------------------------------------------------------------------------------------------
+ Initial common part of all the DoPutSubs... methods.
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoPutSubsInit(GrSlotStream * psstrmIn, GrSlotStream * psstrmOut, bool fInserting,
+ GrSlotState ** ppslotNextInput, bool * pfAtSegMin, bool * pfAtSegLim)
+{
+ // Do this before reading from stream.
+ *pfAtSegMin = psstrmIn->AtSegMin();
+ *pfAtSegLim = psstrmIn->AtSegLim();
+
+ // Slot to copy features and text properties from:
+ if (psstrmIn->AtEndOfContext())
+ {
+ gAssert(fInserting);
+ *ppslotNextInput = psstrmIn->RuleInputSlot(0, psstrmOut);
+ }
+ else
+ *ppslotNextInput = (fInserting)? psstrmIn->Peek(): psstrmIn->NextGet();
+}
+
+/*----------------------------------------------------------------------------------------------
+ Common part of all the DoPutSubs... methods.
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoPutSubsAux(GrTableManager * ptman, bool fInserting, gid16 nGlyphReplacement,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut, GrSlotState * pslotNextInput,
+ bool fAtSegMin, bool fAtSegLim)
+{
+ EngineState * pengst = ptman->State();
+
+ // If we are exactly at the segment boundary, pass the information on to the output stream.
+ // Note that inserted items always go outside the segment, if they are at the boundary.
+ bool fSetSegMin = fAtSegMin && !fInserting;
+ bool fSetSegLim = fAtSegLim;
+
+ GrSlotState * pslotNew;
+ if (fInserting)
+ {
+ pengst->NewSlot(nGlyphReplacement, pslotNextInput, m_ipass, &pslotNew);
+ // leave associations empty; eventually they will be "neutralized"
+ }
+ else
+ {
+ pengst->NewSlotCopy(pslotNextInput, m_ipass, &pslotNew);
+ pslotNew->SetGlyphID(nGlyphReplacement);
+ ptman->SetSlotAttrsFromGlyphAttrs(pslotNew);
+ }
+
+ if (fSetSegMin)
+ psstrmOut->SetSegMinToWritePos(false);
+ if (fSetSegLim)
+ psstrmOut->SetSegLimToWritePos(false);
+ psstrmOut->NextPut(pslotNew);
+}
+
+/*----------------------------------------------------------------------------------------------
+ A slot has just been inserted. Clear all the associations; eventually (unless we go on
+ to set the associations explicitly) we will set its before-assoc to the slot after it
+ and its after-assoc to the slot before it. This makes it basically unselectable.
+ OBSOLETE - handled by slot initialization code
+----------------------------------------------------------------------------------------------*/
+void GrPass::SetNeutralAssocs(GrSlotState * pslotNew, GrSlotStream * psstrmIn)
+{
+ pslotNew->ClearAssocs();
+}
+
+/*----------------------------------------------------------------------------------------------
+ Delete the next slot in the input.
+
+ @param psstrmIn - input stream
+ @param psstrmOut - output stream
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoDelete(GrTableManager * ptman, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ if (psstrmIn->AtSegMin())
+ psstrmOut->SetSegMinToWritePos();
+ if (psstrmIn->AtSegLim())
+ psstrmOut->SetSegLimToWritePos();
+
+ GrSlotState * pslot = psstrmIn->NextGet();
+ pslot->MarkDeleted();
+
+ if (ptman->LoggingTransduction())
+ m_pzpst->RecordDeletionBefore(psstrmOut->WritePos());
+}
+
+/*----------------------------------------------------------------------------------------------
+ Set the associations for the current slot. Any previous associations will be overwritten.
+
+ @param cn - number of associations
+ @param vnAssoc - list of associations
+ @param fInserting - whether current slot was inserted
+ @param psstrmIn / Out - input/output streams
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoAssoc(int cnAssocs, std::vector<int> & vnAssocs, bool fInserting,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ gAssert((unsigned)cnAssocs == vnAssocs.size());
+
+ // Sort the list of associations. It's okay to use a simple bubble sort
+ // since we expect the list to be very short. Ideally we should remove duplicates
+ // too but I don't think duplicates actually hurt anything.
+ for (int i1 = 0; i1 < cnAssocs - 1; i1++)
+ {
+ for (int i2 = i1 + 1; i2 < cnAssocs; i2++)
+ {
+ if (vnAssocs[i2] < vnAssocs[i1])
+ {
+ int nTmp = vnAssocs[i2];
+ vnAssocs[i2] = vnAssocs[i1];
+ vnAssocs[i1] = nTmp;
+ }
+ }
+ }
+
+ std::vector<GrSlotState *> vpslotAssocs;
+ vpslotAssocs.resize(cnAssocs);
+ for (int i = 0; i < cnAssocs; i++)
+ vpslotAssocs[i] = psstrmIn->RuleInputSlot(vnAssocs[i], psstrmOut);
+
+ GrSlotState * pslot = psstrmOut->RuleOutputSlot();
+ pslot->Associate(vpslotAssocs);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Set a slot attribute for the current slot; the value is on the stack.
+
+ @param op - command
+ @param fInserting - whether current slot was inserted
+ @param slat - slot attribute to set
+ @param slati - slot attribute index, or -1 for non-indexed attribute
+ @param vnStack - stack to read value from
+ @param psstrmIn / Out - input/output streams
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoSetAttr(GrTableManager * ptman, ActionCommand op, bool fInserting,
+ SlotAttrName slat, int slati, std::vector<int> & vnStack,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ int nVal = vnStack.back();
+ vnStack.pop_back();
+
+ if (slat == kslatUserDefnV1)
+ slat = kslatUserDefn;
+
+ if (slati != -1 && slat != kslatCompRef && slat != kslatUserDefn)
+ {
+ // Invalid slot attribute index.
+ gAssert(false);
+ slati = -1;
+ }
+
+ if (slati == -1 && (slat == kslatCompRef || slat == kslatUserDefn))
+ {
+ // Missing slot attribute index.
+ gAssert(false);
+ slati = 0;
+ }
+
+ if (slat == kslatPosX || slat == kslatPosY)
+ {
+ // Doesn't make sense to set the pos attribute.
+ gAssert(false);
+ return;
+ }
+
+ GrSlotState * pslotIn = psstrmIn->RuleInputSlot(0, psstrmOut);
+
+ GrSlotState * pslotComp;
+
+ int nOldVal;
+
+ if (op == kopAttrAdd || op == kopAttrSub || op == kopIAttrAdd || op == kopIAttrSub)
+ {
+ // Incrementing or decrementing.
+
+ gAssert(!fInserting);
+
+ switch (slat)
+ {
+ case kslatAdvX: nOldVal = pslotIn->AdvanceX(ptman); break;
+ case kslatAdvY: nOldVal = pslotIn->AdvanceY(ptman); break;
+ case kslatShiftX: nOldVal = pslotIn->ShiftX(); break;
+ case kslatShiftY: nOldVal = pslotIn->ShiftY(); break;
+
+ case kslatAttAtX: nOldVal = pslotIn->AttachAtX(ptman, psstrmIn); break;
+ case kslatAttAtY: nOldVal = pslotIn->AttachAtY(); break;
+ case kslatAttAtXoff: nOldVal = pslotIn->AttachAtXOffset(); break;
+ case kslatAttAtYoff: nOldVal = pslotIn->AttachAtYOffset(); break;
+
+ case kslatAttWithX: nOldVal = pslotIn->AttachWithX(ptman, psstrmIn); break;
+ case kslatAttWithY: nOldVal = pslotIn->AttachWithY(); break;
+ case kslatAttWithXoff: nOldVal = pslotIn->AttachWithXOffset(); break;
+ case kslatAttWithYoff: nOldVal = pslotIn->AttachWithYOffset(); break;
+
+ case kslatUserDefn: nOldVal = pslotIn->UserDefn(slati); break;
+
+ case kslatMeasureSol: nOldVal = pslotIn->MeasureSol(); break;
+ case kslatMeasureEol: nOldVal = pslotIn->MeasureEol(); break;
+
+ case kslatJStretch: nOldVal = pslotIn->JStretch(); break;
+ case kslatJShrink: nOldVal = pslotIn->JShrink(); break;
+ case kslatJStep: nOldVal = pslotIn->JStep(); break;
+ case kslatJWeight: nOldVal = pslotIn->JWeight(); break;
+ case kslatJWidth: nOldVal = pslotIn->JWidth(); break;
+
+ // These are kind of odd, but maybe.
+ case kslatAttLevel: nOldVal = pslotIn->AttachLevel(); break;
+ case kslatBreak: nOldVal = pslotIn->BreakWeight(); break;
+ case kslatDir: nOldVal = pslotIn->Directionality(); break;
+
+ default:
+ // Kind of attribute that it makes no sense to increment.
+ gAssert(false);
+ return;
+ }
+
+ if (op == kopAttrAdd || op == kopIAttrAdd)
+ nVal = nOldVal + nVal;
+ else
+ {
+ gAssert(op == kopAttrSub || op == kopIAttrSub);
+ nVal = nOldVal - nVal;
+ }
+ }
+
+ GrSlotState * pslotOut = psstrmOut->RuleOutputSlot();
+
+ if (pslotOut->IsLineBreak(ptman->LBGlyphID()))
+ {
+ switch (slat)
+ {
+ case kslatAdvX:
+ case kslatAdvY:
+ case kslatShiftX:
+ case kslatShiftY:
+
+ case kslatAttTo:
+ case kslatAttLevel:
+ case kslatAttAtX:
+ case kslatAttAtY:
+ case kslatAttAtGpt:
+ case kslatAttAtXoff:
+ case kslatAttAtYoff:
+ case kslatAttWithX:
+ case kslatAttWithY:
+ case kslatAttWithGpt:
+ case kslatAttWithXoff:
+ case kslatAttWithYoff:
+
+ case kslatMeasureSol:
+ case kslatMeasureEol:
+
+ case kslatJStretch:
+ case kslatJShrink:
+ case kslatJStep:
+ case kslatJWeight:
+ case kslatJWidth:
+ slat = kslatNoEffect;
+ break;
+ default:
+ ; // okay, do nothing
+ }
+ }
+
+ nVal = GrGlyphSubTable::ConvertValueForVersion(nVal, slat, -1, m_fxdVersion);
+
+ switch (slat)
+ {
+ case kslatAdvX: pslotOut->SetAdvanceX(nVal); break;
+ case kslatAdvY: pslotOut->SetAdvanceY(nVal); break;
+ case kslatShiftX: pslotOut->SetShiftX(nVal); break;
+ case kslatShiftY: pslotOut->SetShiftY(nVal); break;
+
+ case kslatAttTo: pslotOut->SetAttachTo(nVal); break;
+ case kslatAttLevel: pslotOut->SetAttachLevel(nVal); break;
+ case kslatAttAtX: pslotOut->SetAttachAtX(nVal); break;
+ case kslatAttAtY: pslotOut->SetAttachAtY(nVal); break;
+ case kslatAttAtGpt: pslotOut->SetAttachAtGpoint(nVal); break;
+ case kslatAttAtXoff: pslotOut->SetAttachAtXOffset(nVal); break;
+ case kslatAttAtYoff: pslotOut->SetAttachAtYOffset(nVal); break;
+ case kslatAttWithX: pslotOut->SetAttachWithX(nVal); break;
+ case kslatAttWithY: pslotOut->SetAttachWithY(nVal); break;
+ case kslatAttWithGpt: pslotOut->SetAttachWithGpoint(nVal); break;
+ case kslatAttWithXoff: pslotOut->SetAttachWithXOffset(nVal); break;
+ case kslatAttWithYoff: pslotOut->SetAttachWithYOffset(nVal); break;
+
+ case kslatUserDefn: pslotOut->SetUserDefn(slati, nVal); break;
+
+ case kslatCompRef:
+ gAssert(nVal - 1 >= psstrmIn->RuleStartReadPos() - psstrmIn->ReadPosForNextGet());
+ pslotComp = psstrmIn->RuleInputSlot(nVal, psstrmOut);
+ pslotOut->SetCompRefSlot(ptman, slati, pslotComp);
+ break;
+
+ case kslatMeasureSol: pslotOut->SetMeasureSol(nVal); break;
+ case kslatMeasureEol: pslotOut->SetMeasureEol(nVal); break;
+
+ case kslatJStretch: pslotOut->SetJStretch(nVal); break;
+ case kslatJShrink: pslotOut->SetJShrink(nVal); break;
+ case kslatJStep: pslotOut->SetJStep(nVal); break;
+ case kslatJWeight: pslotOut->SetJWeight(nVal); break;
+ case kslatJWidth: pslotOut->SetJWidth(nVal); break;
+
+ case kslatBreak: pslotOut->SetBreakWeight(nVal); break;
+ case kslatDir: pslotOut->SetDirectionality(DirCode(nVal)); break;
+ case kslatInsert: pslotOut->SetInsertBefore(bool(nVal)); break;
+
+ case kslatNoEffect:
+ // Do nothing.
+ break;
+
+ default:
+ // Kind of attribute that it makes no sense to set.
+ gAssert(false);
+ return;
+ }
+}
+
+/*----------------------------------------------------------------------------------------------
+ Push value of a slot attribute onto the stack.
+
+ @param nSlotRef - slot whose attribute we are interested in
+ @param fInserting - whether current slot was inserted
+ @param slat - slot attribute to get
+ @param slati - slot attribute index, or -1 for non-indexed attribute
+ @param vnStack - stack to push onto
+ @param psstrmIn - input stream
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoPushSlotAttr(GrTableManager * ptman,
+ int nSlotRef, bool fInserting,
+ SlotAttrName slat, int slati, std::vector<int> & vnStack,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ GrSlotState * pslot = psstrmIn->RuleInputSlot(nSlotRef, psstrmOut, true);
+ if (pslot == NULL)
+ {
+ // Non-existent pre-context item.
+ vnStack.push_back(0);
+ return;
+ }
+
+ int nVal;
+ int xyBogus;
+
+ if (slat == kslatUserDefnV1)
+ slat = kslatUserDefn;
+
+ if (slati != -1 && slat != kslatCompRef && slat != kslatUserDefn)
+ {
+ // Invalid slot attribute index.
+ gAssert(false);
+ slati = -1;
+ }
+
+ if (slati == -1 && (slat == kslatCompRef || slat == kslatUserDefn))
+ {
+ // Missing slot attribute index.
+ gAssert(false);
+ slati = 0;
+ }
+
+ switch (slat)
+ {
+ case kslatAdvX: nVal = pslot->AdvanceX(ptman); break;
+ case kslatAdvY: nVal = pslot->AdvanceY(ptman); break;
+ case kslatShiftX: nVal = pslot->ShiftX(); break;
+ case kslatShiftY: nVal = pslot->ShiftY(); break;
+
+ case kslatPosX: pslot->Position(ptman, psstrmIn, &nVal, &xyBogus); break;
+ case kslatPosY: pslot->Position(ptman, psstrmIn, &xyBogus, &nVal); break;
+
+ case kslatAttTo: nVal = pslot->AttachTo(); break;
+ case kslatAttLevel: nVal = pslot->AttachLevel(); break;
+ case kslatAttAtX: nVal = pslot->AttachAtX(ptman, psstrmIn); break;
+ case kslatAttAtY: nVal = pslot->AttachAtY(); break;
+ case kslatAttAtGpt: nVal = pslot->AttachAtGpoint(); break;
+ case kslatAttAtXoff: nVal = pslot->AttachAtXOffset(); break;
+ case kslatAttAtYoff: nVal = pslot->AttachAtYOffset(); break;
+ case kslatAttWithX: nVal = pslot->AttachWithX(ptman, psstrmIn); break;
+ case kslatAttWithY: nVal = pslot->AttachWithY(); break;
+ case kslatAttWithGpt: nVal = pslot->AttachWithGpoint(); break;
+ case kslatAttWithXoff: nVal = pslot->AttachWithXOffset(); break;
+ case kslatAttWithYoff: nVal = pslot->AttachWithYOffset(); break;
+
+ case kslatMeasureSol: nVal = pslot->MeasureSol(); break;
+ case kslatMeasureEol: nVal = pslot->MeasureEol(); break;
+
+ case kslatJStretch: nVal = pslot->JStretch(); break;
+ case kslatJShrink: nVal = pslot->JShrink(); break;
+ case kslatJStep: nVal = pslot->JStep(); break;
+ case kslatJWeight: nVal = pslot->JWeight(); break;
+ case kslatJWidth: nVal = pslot->JWidth(); break;
+
+ case kslatBreak: nVal = pslot->BreakWeight(); break;
+ case kslatDir: nVal = pslot->Directionality(); break;
+ case kslatInsert: nVal = pslot->InsertBefore(); break;
+
+ case kslatUserDefn: nVal = pslot->UserDefn(slati); break;
+
+ // Currently no way to look up component.X.ref.
+
+ default:
+ // Invalid attribute.
+ gAssert(false);
+ nVal = 0;
+ }
+
+ vnStack.push_back(nVal);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Push value of a glyph attribute onto the stack.
+
+ @param nSlotRef - slot whose attribute we are interested in
+ @param fInserting - whether current slot was inserted
+ @param nGlyphAttr - glyph attribute to get
+ @param vnStack - stack to push onto
+ @param psstrmIn - input stream
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoPushGlyphAttr(GrTableManager * ptman, int nSlotRef, bool fInserting,
+ int nGlyphAttr,
+ std::vector<int> & vnStack, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ GrSlotState * pslot = psstrmIn->RuleInputSlot(nSlotRef, psstrmOut, true);
+ if (pslot == NULL)
+ {
+ // Non-existent pre-context item.
+ vnStack.push_back(0);
+ return;
+ }
+ int nVal = pslot->GlyphAttrValueEmUnits(ptman, nGlyphAttr);
+ vnStack.push_back(nVal);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Push value of a glyph attribute onto the stack. The slot of interest is the slot to
+ which the current slot is attached.
+
+ @param nSlotRef - leaf slot
+ @param fInserting - whether current slot was inserted
+ @param nGlyphAttr - glyph attribute to get
+ @param vnStack - stack to push onto
+ @param psstrmIn - input stream
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoPushAttToGlyphAttr(GrTableManager * ptman, int nSlotRef, bool fInserting,
+ int nGlyphAttr, std::vector<int> & vnStack,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ // Note that it is the slot in the output stream that has
+ // the relevant attach.to attribute set.
+ GrSlotState * pslotLeaf = psstrmOut->RuleOutputSlot(0);
+ int srAttTo = pslotLeaf->AttachTo();
+ if (srAttTo == 0)
+ {
+ gAssert(false);
+ vnStack.push_back(0);
+ return;
+ }
+
+ GrSlotState * pslotRoot = psstrmIn->RuleInputSlot(nSlotRef + srAttTo, psstrmOut);
+ int nVal = pslotRoot->GlyphAttrValueEmUnits(ptman, nGlyphAttr);
+ vnStack.push_back(nVal);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Push value of a glyph metric onto the stack.
+
+ @param nSlotRef - slot whose attribute we are interested in
+ @param fInserting - whether current slot was inserted
+ @param nGlyphAttr - glyph attribute to get
+ @param nAttLevel - for accessing composite metrics
+ @param vnStack - stack to push onto
+ @param psstrmIn - input stream
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoPushGlyphMetric(GrTableManager * ptman, int nSlotRef, bool fInserting,
+ int nGlyphAttr, int nAttLevel,
+ std::vector<int> & vnStack, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ GrSlotState * pslot = psstrmIn->RuleInputSlot(nSlotRef, psstrmOut, true);
+ if (pslot == NULL)
+ {
+ // Non-existent pre-context item.
+ vnStack.push_back(0);
+ return;
+ }
+
+ DoPushGlyphMetricAux(ptman, pslot, nGlyphAttr, nAttLevel, vnStack, psstrmIn);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Push value of a glyph metric onto the stack. The slot of interest is the slot to
+ which the current slot is attached.
+
+ @param nSlotRef - slot whose attribute we are interested in
+ @param fInserting - whether current slot was inserted
+ @param nGlyphAttr - glyph attribute to get
+ @param nAttLevel - for accessing composite metrics
+ @param vnStack - stack to push onto
+ @param psstrmIn - input stream
+ @param psstrmOut - output stream
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoPushAttToGlyphMetric(GrTableManager * ptman, int nSlotRef, bool fInserting,
+ int nGlyphAttr, int nAttLevel,
+ std::vector<int> & vnStack,
+ GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ // Note that it is the slot in the output stream that has
+ // the relevant attach.to attribute set.
+ GrSlotState * pslotLeaf = psstrmOut->RuleOutputSlot(0);
+ int srAttTo = pslotLeaf->AttachTo();
+ if (srAttTo == 0)
+ {
+ gAssert(false);
+ vnStack.push_back(0);
+ return;
+ }
+
+ GrSlotState * pslot = psstrmIn->RuleInputSlot(nSlotRef + srAttTo, psstrmOut);
+
+ DoPushGlyphMetricAux(ptman, pslot, nGlyphAttr, nAttLevel, vnStack, psstrmIn);
+}
+
+/*--------------------------------------------------------------------------------------------*/
+
+void GrPass::DoPushGlyphMetricAux(GrTableManager * ptman,
+ GrSlotState * pslot, int nGlyphAttr, int nAttLevel,
+ std::vector<int> & vnStack, GrSlotStream * psstrmIn)
+{
+ int mVal;
+ GlyphMetric gmet = GlyphMetric(nGlyphAttr);
+ if (nAttLevel == 0 || gmet == kgmetAscent || gmet == kgmetDescent)
+ {
+ mVal = pslot->GlyphMetricEmUnits(ptman, nGlyphAttr);
+ }
+ else
+ {
+ pslot->CalcCompositeMetrics(ptman, psstrmIn, nAttLevel, true);
+
+ float xy;
+ switch (gmet)
+ {
+ case kgmetLsb: xy = pslot->ClusterLsb(psstrmIn); break;
+ case kgmetRsb: xy = pslot->ClusterRsb(psstrmIn); break;
+ case kgmetBbTop: xy = pslot->ClusterBbTop(psstrmIn); break;
+ case kgmetBbBottom: xy = pslot->ClusterBbBottom(psstrmIn); break;
+ case kgmetBbLeft: xy = pslot->ClusterBbLeft(psstrmIn); break;
+ case kgmetBbRight: xy = pslot->ClusterBbRight(psstrmIn); break;
+ case kgmetBbHeight: xy = pslot->ClusterBbHeight(psstrmIn); break;
+ case kgmetBbWidth: xy = pslot->ClusterBbWidth(psstrmIn); break;
+// case kgmetAdvHeight: xy = pslot->ClusterAdvHeight(psstrmIn); break;
+ case kgmetAdvWidth: xy = pslot->ClusterAdvWidth(psstrmIn); break;
+ default:
+ gAssert(false);
+ xy = 0;
+ }
+ mVal = ptman->LogToEmUnits(xy);
+ }
+
+ vnStack.push_back(mVal);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Push a feature value onto the stack. For rule actions, the slot of interest is the
+ current slot.
+
+ @param nSlotRef - slot being examined
+ @param fInserting - whether current slot was inserted
+ @param nFeat - feature of interest
+ @param vnStack - stack to push onto
+ @param psstrmIn - input stream
+ @param psstrmOut - output stream
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoPushFeatValue(GrTableManager * ptman, int nSlotRef, bool fInserting,
+ int nFeat, std::vector<int> & vnStack, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut)
+{
+ gAssert(!fInserting);
+
+ GrSlotState * pslot = psstrmIn->RuleInputSlot(nSlotRef, psstrmOut, true);
+ if (pslot == NULL)
+ {
+ // Non-existent pre-context item.
+ vnStack.push_back(0);
+ return;
+ }
+
+ int nVal = pslot->FeatureValue(nFeat);
+ vnStack.push_back(nVal);
+}
+
+/*----------------------------------------------------------------------------------------------
+ Push a processing-state value onto the stack.
+
+ @param nFeat - feature of interest
+ @param vnStack - stack to push onto
+----------------------------------------------------------------------------------------------*/
+void GrPass::DoPushProcState(GrTableManager * ptman, int nPState, std::vector<int> & vnStack)
+{
+ int nValue;
+ if (nPState == kpstatJustifyMode)
+ {
+ // Convert from internal modes to user modes.
+ int jmodi = ptman->InternalJustificationMode();
+ switch (jmodi)
+ {
+ case kjmodiNormal:
+ case kjmodiCanShrink:
+ nValue = kjmoduNormal;
+ break;
+ case kjmodiMeasure:
+ nValue = kjmoduMeasure;
+ break;
+ case kjmodiJustify:
+ nValue = kjmoduJustify;
+ break;
+ default:
+ gAssert(false);
+ nValue = kjmoduNormal;
+ }
+ }
+ else if (nPState == kpstatJustifyLevel)
+ nValue = 1; // TODO: get justify level from ptman
+ vnStack.push_back(nValue);
+}
+
+} // namespace gr