/*--------------------------------------------------------------------*//*:Ignore this sentence. Copyright (C) 1999 - 2008 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.h Responsibility: Sharon Correll Last reviewed: Not yet. Description: The GrPass class and subclasses. ----------------------------------------------------------------------------------------------*/ #ifdef _MSC_VER #pragma once #endif #ifndef PASS_INCLUDED #define PASS_INCLUDED //:End Ignore namespace gr { /*---------------------------------------------------------------------------------------------- This class stores the state of processing in a single pass. Hungarian: zpst ----------------------------------------------------------------------------------------------*/ class PassState { friend class GrPass; friend class GrGlyphGenPass; friend class GrLineBreakPass; friend class GrSubPass; friend class GrBidiPass; friend class GrPosPass; friend class FontMemoryUsage; public: PassState() { } void InitForNewSegment(int ipass, int nMaxChunk); void InitializeLogInfo(); int MaxChunk() { return m_nMaxChunk; } void SetResyncSkip(int c) { m_cslotSkipToResync = c; m_fDidResyncSkip = false; } int NeededToResync() { if (m_fDidResyncSkip) return 0; return m_cslotSkipToResync; } bool DidResyncSkip() { return m_fDidResyncSkip; } bool CanResyncSkip(GrSlotStream * psstrmOutput) { if (m_fDidResyncSkip) return true; // already did it // Are we in the position to do the resync-skip? return m_cslotSkipToResync <= psstrmOutput->WritePos(); } int DoResyncSkip(GrSlotStream * psstrmOutput); void UndoResyncSkip() { m_fDidResyncSkip = false; } void UnwindLogInfo(int islotIn, int islotOut); void RecordRule(int islot, int irul, bool fFired = false); void RecordDeletionBefore(int islot); void RecordInsertionAt(int islot); #ifdef TRACING void LogRulesFiredAndFailed(std::ostream & strmOut, GrSlotStream * psstrmIn); void LogInsertionsAndDeletions(std::ostream & strmOut, GrSlotStream * psstrmOut); void LogXmlRules(std::ostream & strmOut, GrTableManager *, GrSlotStream * psstrmIn, int nIndent); void LogXmlGlyphs(std::ostream & strmOut, GrTableManager * ptman, GrSlotStream * psstrmOut, int ipassJust1, bool fPreJust, bool fPostJust, bool fBidi, bool fBidiNext, int cslotsSkipped, int nIndent); #endif // TRACING protected: int m_ipass; // Used to avoid infinite loops. If m_nRulesSinceAdvance > m_nMaxRuleLoop, // and we have not passed the stream's ReadPosMax, forcibly advance. int m_nRulesSinceAdvance; // Maximum length of chunk, used when unwinding the streams during backtracking. This // must be initialized to m_nMaxRuleContext, but that is not always adequate, because // when there is reprocessing going on the chunks may be longer. int m_nMaxChunk; // Indicates how much of the pass's initial output should be automatically // skipped over in order to resync with a chunk boundary. This handles the situation // where we are reprocessing a little of the previous segment in order to handle // cross-line-boundary contextuals. The goal is to skip over the output until we hit // what we know (from processing the previous segment) is a chunk boundary. // // In most cases (and always when this is the first segment of the // writing system) this number is 0. int m_cslotSkipToResync; bool m_fDidResyncSkip; enum { kHitMaxBackup = -1, kHitMaxRuleLoop = -2 }; // For logging transduction process: record of one rule matched or fired struct RuleRecord { int m_irul; // rule index, or kHitMaxBackup or kHitMaxRuleLoop int m_islot; // slot index of input stream bool m_fFired; }; RuleRecord m_rgrulrec[128]; int m_crulrec; int m_rgcslotDeletions[128]; // number of deletions before slot i in output bool m_rgfInsertion[128]; // true if slot i in output was inserted }; /*---------------------------------------------------------------------------------------------- This class handles finding and applying rules from the pass and storing the results in the appropriate stream. Hungarian: pass ----------------------------------------------------------------------------------------------*/ class GrPass { friend class FontMemoryUsage; protected: // Action command codes; these MUST match the corresponding definitions in the compiler: enum ActionCommand { kopNop = 0, kopPushByte, kopPushByteU, kopPushShort, kopPushShortU, kopPushLong, kopAdd, kopSub, kopMul, kopDiv, kopMin, kopMax, kopNeg, kopTrunc8, kopTrunc16, kopCond, kopAnd, kopOr, kopNot, kopEqual, kopNotEq, kopLess, kopGtr, kopLessEq, kopGtrEq, kopNext, kopNextN, kopCopyNext, kopPutGlyph8bitObs, kopPutSubs8bitObs, kopPutCopy, kopInsert, kopDelete, kopAssoc, kopCntxtItem, kopAttrSet, kopAttrAdd, kopAttrSub, kopAttrSetSlot, kopIAttrSetSlot, kopPushSlotAttr, kopPushGlyphAttrObs,kopPushGlyphMetric, kopPushFeat, kopPushAttToGAttrObs, kopPushAttToGlyphMetric, kopPushISlotAttr, kopPushIGlyphAttr, // not implemented kopPopRet, kopRetZero, kopRetTrue, kopIAttrSet, kopIAttrAdd, kopIAttrSub, kopPushProcState, kopPushVersion, kopPutSubs, kopPutSubs2, kopPutSubs3, kopPutGlyph, kopPushGlyphAttr, kopPushAttToGlyphAttr }; enum StackMachineFlag { ksmfDone = 0, ksmfContinue, ksmfUnderflow, ksmfStackNotEmptied }; public: // Constructor: GrPass(int i); // Destructor: virtual ~GrPass(); int PassNumber() { return m_ipass; } bool ReadFromFont(GrIStream & grstrm, int fxdSilfVersion, int fxdRuleVersion, int nOffset); void InitializeWithNoRules(); virtual void SetTopDirLevel(int n) { // only GrBidiPass does anything interesting } void SetPassState(PassState * pzpst) { m_pzpst = pzpst; } virtual void ExtendOutput(GrTableManager *, GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput, int nslotToGet, TrWsHandling twsh, int * pnRet, int * pcslotGot, int * pislotFinalBreak); int ExtendGlyphIDOutput(GrTableManager *, GrCharStream *, GrSlotStream *, int ichSegLim, int cchwPostXlbContext, LineBrk lb, int cslotToGet, bool fNeedFinalBreak, TrWsHandling twsh, int * pislotFinalBreak); int ExtendFinalOutput(GrTableManager *, GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput, float xsSpaceAllotted, bool fWidthIsCharCount, bool fInfiniteWidth, bool fHaveLineBreak, bool fMustBacktrack, LineBrk lbMax, TrWsHandling twsh, int * pislotLB, float * pxsWidth); int RemoveTrailingWhiteSpace(GrTableManager * ptman, GrSlotStream * psstrmOut, TrWsHandling twsh, int * pislotFinalBreak); virtual int Unwind(GrTableManager * ptman, int islotChanged, GrSlotStream *psstrmInput, GrSlotStream * psstrmOutput, bool fFirst); int MaxBackup() { return m_nMaxBackup; } bool DidResyncSkip() { return m_pzpst->DidResyncSkip(); } int DoResyncSkip(GrSlotStream * psstrmOutput) { return m_pzpst->DoResyncSkip(psstrmOutput); } void UndoResyncSkip() { m_pzpst->UndoResyncSkip(); } void SetResyncSkip(int n) { m_pzpst->SetResyncSkip(n); } virtual void DoCleanUpSegMin(GrTableManager * ptman, GrSlotStream * psstrmIn, int islotInitReadPos, GrSlotStream * psstrmOut) { } virtual bool IsPosPass() { return false; } virtual bool PreBidiPass() = 0; bool RunConstraint(GrTableManager *, int ruln, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut, int cslotPreModContext, int cslotMatched); int RunCommandCode(GrTableManager * ptman, byte * pbStart, bool fConstraints, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut, int islot); protected: int RunOneCommand(GrTableManager * ptman, bool fConstraints, ActionCommand op, byte ** ppbArg, bool * pfMustGet, bool * pfInserting, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut, int islot, std::vector & vnStack, StackMachineFlag * psmf); void DoStackArithmetic2Args(ActionCommand op, std::vector & vnStack, StackMachineFlag * psmf); void DoStackArithmetic1Arg(ActionCommand op, std::vector & vnStack, StackMachineFlag * psmf); void DoConditional(std::vector & vnStack, StackMachineFlag * psmf); StackMachineFlag CheckStack(std::vector & vnStack, int cn); void DoNext(GrTableManager * ptman, int cslot, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut); void DoPutGlyph(GrTableManager * ptman, bool fInserting, int nReplacementClass, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut); void DoPutCopy(GrTableManager * ptman, bool fInserting, int cslotCopyFrom, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut); void DoPutSubs(GrTableManager * ptman, bool fInserting, int cslotSel, int nSelClass, int nReplacementClass, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut); void DoPutSubs2(GrTableManager * ptman, bool fInserting, int cslotSel1, int nSelClass1, int cslotSel2, int nSelClass2, int nReplacementClass, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut); void DoPutSubs3(GrTableManager * ptman, bool fInserting, int cslotSel1, int nSelClass1, int cslotSel2, int nSelClass2, int cslotSel3, int nSelClass3, int nReplacementClass, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut); void DoPutSubsInit(GrSlotStream * psstrmIn, GrSlotStream * psstrmOut, bool fInserting, GrSlotState ** ppslotNextPut, bool * pfAtSegMin, bool * pfAtSegLim); void DoPutSubsAux(GrTableManager * ptman, bool fInserting, gid16 nGlyphReplacement, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut, GrSlotState * pslotNextInput, bool fAtSegMin, bool fAtSegLim); void SetNeutralAssocs(GrSlotState * pslotNew, GrSlotStream * psstrmIn); void DoDelete(GrTableManager * ptman, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut); void DoAssoc(int cnAssocs, std::vector & vnAssocs, bool fInserting, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut); void DoSetAttr(GrTableManager * ptman, ActionCommand op, bool fInserrting, SlotAttrName slat, int slati, std::vector & vnStack, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut); void DoPushSlotAttr(GrTableManager * ptman, int nSlotRef, bool fInserting, SlotAttrName slat, int slati, std::vector & vnStack, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut); void DoPushGlyphAttr(GrTableManager * ptman, int nSlotRef, bool fInserting, int nGlyphAttr, std::vector & vnStack, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut); void DoPushAttToGlyphAttr(GrTableManager * ptman, int nSlotRef, bool fInserting, int nGlyphAttr, std::vector & vnStack, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut); void DoPushGlyphMetric(GrTableManager * ptman, int nSlotRef, bool fInserting, int nGlyphAttr, int nAttLevel, std::vector & vnStack, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut); void DoPushAttToGlyphMetric(GrTableManager * ptman, int nSlotRef, bool fInserting, int nGlyphAttr, int nAttLevel, std::vector & vnStack, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut); void DoPushFeatValue(GrTableManager * ptman, int islot, bool fInsering, int nFeat, std::vector & vnStack, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut); void DoPushProcState(GrTableManager * ptman, int nPState, std::vector & vnStack); protected: void DoPushGlyphMetricAux(GrTableManager * ptman, GrSlotState * pslot, int nGlyphAttr, int nAttLevel, std::vector & vnStack, GrSlotStream * psstrmIn); public: int SortKeyForRule(int ruln) { Assert(ruln < m_crul); return m_prgchwRuleSortKeys[ruln]; } int PreModContextForRule(int ruln) { Assert(ruln < m_crul); return m_prgcritRulePreModContext[ruln]; } int MaxRulePreContext() { if (m_pfsm) return m_pfsm->MaxRulePreContext(); else return 0; } void RecordRuleFailed(int islot, int irul); void RecordRuleFired(int islot, int irul); void RecordHitMaxRuleLoop(int islot); void RecordHitMaxBackup(int islot); #ifdef TRACING void LogRulesFiredAndFailed(std::ostream & strmOut, GrSlotStream * psstrmIn); void LogInsertionsAndDeletions(std::ostream & strmOut, GrSlotStream * psstrmOut); void LogXmlRules(std::ostream & strmOut, GrTableManager * ptman, GrSlotStream * psstrmIn, int nIndent); void LogXmlGlyphs(std::ostream & strmOut, GrTableManager * ptman, GrSlotStream * psstrmOut, int ipassJust1, bool fPreJust, bool fPostJust, int cslotsSkipped, int nIndent); #endif // TRACING protected: int CheckRuleValidity(int ruln); virtual void RunRule(GrTableManager *, int ruln, GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput) = 0; void CheckInputProgress(GrSlotStream* input, GrSlotStream* psstrmOutput, int islotOrigInput); void MapChunks(GrSlotStream * psstrmIn, GrSlotStream * psstrmOut, int islotChunkI, int islotChunkO, int cslotReprocessed); virtual void Unattach(GrSlotStream * psstrmIn, int islotIn, // GrPosPass overrides GrSlotStream * psstrmOut, int islotOut, int islotLB) { } friend class EngineState; // let it call the method below virtual int MaxRuleContext() // GrBidiPass overrides { return m_nMaxRuleContext; } protected: // Instance variables: int m_ipass; // index of pass int m_fxdVersion; // number of items required from previous pass; don't access directly, use the getter // method, because GrBidiPass overrides to always use 1. int m_nMaxRuleContext; GrFSM * m_pfsm; // Finite State Machine to give next rule int m_nMaxRuleLoop; // maximum number of rules to process before forcibly // advancing input position int m_nMaxBackup; int m_crul; // number of rules // rule sort keys, indicating precedence of rules; m_crul of these data16 * m_prgchwRuleSortKeys; // for each rule, the number of items in the context before the first modified item // that the constraints need to be tested on byte * m_prgcritRulePreModContext; // offset for pass-level constraints; just 1 of these data16 m_cbPassConstraint; // offsets for constraint and action code; m_crul+1 of each of these (the last // indicates the total byte count) data16 * m_prgibConstraintStart; data16 * m_prgibActionStart; // blocks of constraint and action code byte * m_prgbPConstraintBlock; // pass-level constraints byte * m_prgbConstraintBlock; // rule constraints byte * m_prgbActionBlock; int m_cbConstraints; // needed for memory instrumentation only int m_cbActions; // needed for memory instrumentation only bool m_fHasDebugStrings; data16 * m_prgibConstraintDebug; // m_crul+1 of these data16 * m_prgibRuleDebug; // m_crul+1 of these bool m_fCheckRules; bool * m_prgfRuleOkay; std::vector m_vnStack; // for stack machine processing (more efficient than creating the // vector each time) // state of process for this pass PassState * m_pzpst; public: #ifdef OLD_TEST_STUFF // For test procedures: StrAnsi m_staBehavior; virtual void SetUpTestData(); // overridden on appropriate subclasses: virtual void SetUpReverseNumbersTest() { Assert(false); } virtual void SetUpBidiNumbersTest() { Assert(false); } virtual void SetUpCrossLineContextTest() { Assert(false); } virtual void SetUpReprocessTest() { Assert(false); } virtual void SetUpLineEdgeContextTest(int ipass) { Assert(false); } virtual void SetUpBidiAlgorithmTest() { Assert(false); } virtual void SetUpPseudoGlyphsTest() { Assert(false); } virtual void SetUpSimpleFSMTest() { Assert(false); } virtual void SetUpRuleActionTest() { Assert(false); } virtual void SetUpRuleAction2Test() { Assert(false); } virtual void SetUpAssocTest() { Assert(false); } virtual void SetUpAssoc2Test() { Assert(false); } virtual void SetUpDefaultAssocTest() { Assert(false); } virtual void SetUpFeatureTest() { Assert(false); } virtual void SetUpLigatureTest() { Assert(false); } virtual void SetUpLigature2Test() { Assert(false); } #endif // OLD_TEST_STUFF }; // end of class GrPass /*---------------------------------------------------------------------------------------------- The initial pass that generates glyph IDs from Unicode input. Hungarian: pass ----------------------------------------------------------------------------------------------*/ class GrGlyphGenPass : public GrPass { friend class FontMemoryUsage; public: GrGlyphGenPass(int ipass) : GrPass(ipass) { } virtual bool PreBidiPass() { return true; } protected: // Irrelevant when generating glyphs. virtual void RunRule(GrTableManager *, int ruln, GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput) { Assert(false); } }; // end of class GrGlyphGenPass /*---------------------------------------------------------------------------------------------- A pass containing rules that set the break weight values. Hungarian: pass ----------------------------------------------------------------------------------------------*/ class GrLineBreakPass : public GrPass { friend class FontMemoryUsage; public: GrLineBreakPass(int ipass) : GrPass(ipass) { } virtual bool PreBidiPass() { return true; } protected: virtual void RunRule(GrTableManager *, int ruln, GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput); public: #ifdef OLD_TEST_STUFF // For test procedures: bool RunTestRules(GrTableManager *, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut); bool RunTestRules(GrTableManager *, int ruln, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut); virtual void SetUpCrossLineContextTest(); bool RunCrossLineContextTest(GrTableManager*, GrSlotStream* psstrmIn, GrSlotStream* psstrmOut); virtual void SetUpReprocessTest(); bool RunReprocessTest(GrTableManager *, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut); virtual void SetUpAssocTest(); virtual void SetUpLigatureTest(); #endif // OLD_TEST_STUFF }; // end of class GrLineBreakPass /*---------------------------------------------------------------------------------------------- A pass containing substitution rules. Hungarian: pass ----------------------------------------------------------------------------------------------*/ class GrSubPass : public GrPass { friend class FontMemoryUsage; public: GrSubPass(int ipass) : GrPass(ipass) { } virtual bool PreBidiPass() { return true; } protected: virtual void RunRule(GrTableManager *, int ruln, GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput); virtual void DoCleanUpSegMin(GrTableManager * ptman, GrSlotStream * psstrmIn, int islotInitReadPos, GrSlotStream * psstrmOut); public: #ifdef OLD_TEST_STUFF // For test procedures: bool RunTestRules(GrTableManager *, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut); bool RunTestRules(GrTableManager *, int ruln, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut); virtual void SetUpReverseNumbersTest(); bool RunReverseNumbersTest(GrTableManager*, GrSlotStream* psstrmIn, GrSlotStream* psstrmOut); virtual void SetUpBidiNumbersTest(); bool RunBidiNumbersTest(GrTableManager*, GrSlotStream* psstrmIn, GrSlotStream* psstrmOut); virtual void SetUpCrossLineContextTest(); bool RunCrossLineContextTest(GrTableManager*, GrSlotStream* psstrmIn, GrSlotStream* psstrmOut); virtual void SetUpReprocessTest(); bool RunReprocessTest(GrTableManager *, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut); virtual void SetUpLineEdgeContextTest(int ipass); bool RunLineEdgeContextTest(GrTableManager *, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut); virtual void SetUpBidiAlgorithmTest(); bool RunBidiAlgorithmTest(GrTableManager *, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut); virtual void SetUpPseudoGlyphsTest(); bool RunPseudoGlyphsTest(GrTableManager *, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut); virtual void SetUpSimpleFSMTest(); bool RunSimpleFSMTest(GrTableManager *, int ruln, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut); virtual void SetUpRuleActionTest(); virtual void SetUpRuleAction2Test(); virtual void SetUpAssocTest(); virtual void SetUpAssoc2Test(); virtual void SetUpDefaultAssocTest(); virtual void SetUpFeatureTest(); virtual void SetUpLigatureTest(); virtual void SetUpLigature2Test(); #endif // OLD_TEST_STUFF }; // end of class GrSubPass /*---------------------------------------------------------------------------------------------- This class is the one the knows how to handle bidi reordering, including backtracking. Hungarian: pass ----------------------------------------------------------------------------------------------*/ class GrBidiPass : public GrSubPass { friend class FontMemoryUsage; public: // Constructor: GrBidiPass(int ipass) : GrSubPass(ipass), m_nTopDirection(0) { } virtual void SetTopDirLevel(int n) { m_nTopDirection = n; } virtual bool PreBidiPass() { return false; } virtual void ExtendOutput(GrTableManager *, GrSlotStream * psstrmI, GrSlotStream * psstrmO, int nslotToGet, TrWsHandling twsh, int * pnRet, int * pcslotGot, int * pislotFinalBreak); virtual int Unwind(GrTableManager * ptman, int islotChanged, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut, bool fFirst); protected: virtual int MaxRuleContext() { return 1; } private: //void OldReverse(int nCurrDirection, // GrSlotStream * psstrmI, int islotI1, int islotI2, // GrSlotStream * psstrmO, int islotO1, int islotO2); int Reverse(GrTableManager * ptman, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut, std::vector & vislotStarts, std::vector & vislotStops); protected: // Instance variables: int m_nTopDirection; // 0 for LTR, 1 for RTL -- CURRENTLY NOT USED; need to // initialize it when we set the writing system direction #ifdef OLD_TEST_STUFF public: // For test procedures: ////virtual void SetUpTestData(); virtual void SetUpBidiNumbersTest(); virtual void SetUpBidiAlgorithmTest(); #endif // OLD_TEST_STUFF }; // end of class GrBidiPass /*---------------------------------------------------------------------------------------------- A pass containing positioning rules. Hungarian: pass ----------------------------------------------------------------------------------------------*/ class GrPosPass : public GrPass { friend class FontMemoryUsage; public: GrPosPass(int ipass) : GrPass(ipass) { } virtual bool IsPosPass() { return true; } virtual bool PreBidiPass() { return false; } protected: virtual void RunRule(GrTableManager *, int ruln, GrSlotStream * psstrmInput, GrSlotStream * psstrmOutput); virtual void Unattach(GrSlotStream * psstrmIn, int islotIn, GrSlotStream * psstrmOut, int islotOut, int islotLB); public: #ifdef OLD_TEST_STUFF // For test procedures: bool RunTestRules(GrTableManager *, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut); bool RunTestRules(GrTableManager *, int ruln, GrSlotStream * psstrmIn, GrSlotStream * psstrmOut); #endif // OLD_TEST_STUFF }; // end of class GrPosPass } // namespace gr #endif // PASS_INCLUDED