summaryrefslogtreecommitdiff
path: root/Build/source/libs/graphite-engine/src/segment/GrTableManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/graphite-engine/src/segment/GrTableManager.cpp')
-rw-r--r--Build/source/libs/graphite-engine/src/segment/GrTableManager.cpp2691
1 files changed, 0 insertions, 2691 deletions
diff --git a/Build/source/libs/graphite-engine/src/segment/GrTableManager.cpp b/Build/source/libs/graphite-engine/src/segment/GrTableManager.cpp
deleted file mode 100644
index fde364e7e2e..00000000000
--- a/Build/source/libs/graphite-engine/src/segment/GrTableManager.cpp
+++ /dev/null
@@ -1,2691 +0,0 @@
-/*--------------------------------------------------------------------*//*: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: GrTableManager.cpp
-Responsibility: Sharon Correll
-Last reviewed: Not yet.
-
-Description:
- GrTableManager, which handles the interactions between passes, including the demand-pull
- algorithm.
--------------------------------------------------------------------------------*//*:End Ignore*/
-
-//:>********************************************************************************************
-//:> Include files
-//:>********************************************************************************************
-#include "Main.h"
-
-#ifdef _MSC_VER
-#pragma hdrstop
-#endif
-#undef THIS_FILE
-DEFINE_THIS_FILE
-//#ifndef _WIN32
-#include <stdlib.h>
-#include <math.h>
-//#endif
-
-//:>********************************************************************************************
-//:> Forward declarations
-//:>********************************************************************************************
-
-//:>********************************************************************************************
-//:> Local Constants and static variables
-//:>********************************************************************************************
-
-namespace gr
-{
-
-//:>********************************************************************************************
-//:> Methods
-//:>********************************************************************************************
-
-/*----------------------------------------------------------------------------------------------
- Constructors and initializers
-----------------------------------------------------------------------------------------------*/
-EngineState::EngineState()
- : m_ipassJustCalled(-1),
- m_fStartLineContext(false),
- m_fEndLineContext(false),
- ////m_pgg(NULL),
- m_cslotPreSeg(0),
- m_islotblkCurr(-1),
- m_islotNext(kSlotBlockSize),
- m_fInitialLB(false),
- m_fFinalLB(false),
- m_fInsertedLB(false),
- m_fExceededSpace(false),
- m_fHitHardBreak(false),
- m_fRemovedWhtsp(false),
- m_dxsShrinkPossible(GrSlotState::kNotYetSet),
- m_islotPosNext(-1),
- m_xsPosXNext(0),
- m_ysPosYNext(0),
- m_dxsTotWidthSoFar(0),
- m_dxsVisWidthSoFar(0),
- m_prgzpst(NULL),
- m_prgpsstrm(NULL)
-{
- m_vslotblk.clear();
- m_vprgnSlotVarLenBufs.clear();
-}
-
-void EngineState::Initialize(GrEngine * pgreng, GrTableManager * ptman)
-{
- m_ptman = ptman;
- m_cpass = ptman->NumberOfPasses(); // duplicate for convenience
-
- m_cUserDefn = pgreng->NumUserDefn();
- m_cFeat = pgreng->NumFeat();
- m_cCompPerLig = pgreng->NumCompPerLig();
-
- if (m_prgzpst)
- delete[] m_prgzpst;
- m_prgzpst = new PassState[m_cpass];
- ptman->StorePassStates(m_prgzpst);
-}
-
-/*----------------------------------------------------------------------------------------------
- Destructors
-----------------------------------------------------------------------------------------------*/
-GrTableManager::~GrTableManager()
-{
- for (int ipass = 0; ipass < m_cpass; ++ipass)
- delete Pass(ipass);
-
- delete[] m_prgppass;
-}
-
-EngineState::~EngineState()
-{
- DestroySlotBlocks();
-
- delete[] m_prgzpst;
-
- if (m_prgpsstrm)
- {
- for (int isstrm = 0; isstrm < m_cpass; ++isstrm)
- delete OutputStream(isstrm);
-
- delete[] m_prgpsstrm;
- }
-}
-
-/*----------------------------------------------------------------------------------------------
- Delete all the slots.
-----------------------------------------------------------------------------------------------*/
-void EngineState::DestroySlotBlocks()
-{
- Assert(m_vslotblk.size() == m_vprgnSlotVarLenBufs.size());
- for (size_t islotblk = 0; islotblk < m_vslotblk.size(); ++islotblk)
- {
- delete[] m_vslotblk[islotblk];
- delete[] m_vprgnSlotVarLenBufs[islotblk];
- }
- m_vslotblk.clear();
- m_vprgnSlotVarLenBufs.clear();
-}
-
-/*----------------------------------------------------------------------------------------------
- Create the passes, and them fill them in by reading from the file stream.
-----------------------------------------------------------------------------------------------*/
-bool GrTableManager::CreateAndReadPasses(GrIStream & grstrm,
- int fxdSilfVersion, int fxdRuleVersion,
- int cpassFont, long lSubTableStart, int * rgnPassOffsets,
- int ipassSub1Font, int ipassPos1Font, int ipassJust1Font, byte ipassPostBidiFont)
-{
- Assert(ipassSub1Font <= ipassJust1Font);
- Assert(ipassJust1Font <= ipassPos1Font);
- Assert(ipassPos1Font <= cpassFont);
- if (ipassSub1Font > ipassJust1Font || ipassJust1Font > ipassPos1Font
- || ipassPos1Font > cpassFont)
- {
- return false; // bad table
- }
-
- // Adjusted indices based on the fact that we have a glyph generation pass that is
- // pass 0, and possibly a bidi pass:
- m_cpass = cpassFont + 1;
- int ipassLB1, ipassSub1, ipassBidi, ipassPos1, ipassJust1;
- ipassLB1 = 1;
- ipassSub1 = ipassSub1Font + 1;
- if (ipassPostBidiFont == 0xFF)
- {
- // No bidi pass.
- m_fBidi = false;
- // Add 1 below to account for the glyph-generation pass.
- ipassPos1 = ipassPos1Font + 1;
- ipassJust1 = ipassJust1Font + 1;
- ipassBidi = ipassJust1;
- }
- else
- {
- m_fBidi = true;
- m_cpass++;
- Assert(ipassPostBidiFont == ipassJust1Font);
- ipassJust1 = ipassJust1Font + 2;
- ipassPos1 = ipassPos1Font + 2;
- ipassBidi = ipassJust1 - 1;
- }
-
- // Always make at least one positioning pass, even if there are no rules.
- if (ipassPos1 == m_cpass)
- {
- m_cpass++;
- }
-
- m_prgppass = new GrPass*[m_cpass + 1];
- m_prgppass[0] = new GrGlyphGenPass(0);
-
- int ipass = 1;
- int ipassFont = 0;
- m_cpassLB = 0;
- m_ipassJust1 = 1;
- m_ipassPos1 = 1;
- for ( ; ipass < m_cpass; ipass++, ipassFont++)
- {
- if (ipass < ipassSub1)
- {
- m_prgppass[ipass] = new GrLineBreakPass(ipass);
- m_prgppass[ipass]->ReadFromFont(grstrm, fxdSilfVersion, fxdRuleVersion,
- lSubTableStart + rgnPassOffsets[ipassFont]);
- m_cpassLB++;
- m_ipassJust1++;
- m_ipassPos1++;
- }
- else if (ipassSub1 <= ipass && ipass < ipassBidi)
- {
- m_prgppass[ipass] = new GrSubPass(ipass);
- m_prgppass[ipass]->ReadFromFont(grstrm, fxdSilfVersion, fxdRuleVersion,
- lSubTableStart + rgnPassOffsets[ipassFont]);
- m_ipassJust1++;
- m_ipassPos1++;
- }
- else if (ipassBidi == ipass && ipass < ipassJust1)
- {
- m_prgppass[ipass] = new GrBidiPass(ipass);
- m_prgppass[ipass]->SetTopDirLevel(TopDirectionLevel());
- ipassFont--; // no corresponding pass in font
- m_ipassJust1++;
- m_ipassPos1++;
- }
- else if (ipassJust1 <= ipass && ipass < ipassPos1)
- {
- // A justification pass is, in essence, a substitution pass.
- m_prgppass[ipass] = new GrSubPass(ipass);
- m_prgppass[ipass]->ReadFromFont(grstrm, fxdSilfVersion, fxdRuleVersion,
- lSubTableStart + rgnPassOffsets[ipassFont]);
- m_ipassPos1++;
- }
- else if (ipassPos1 <= ipass)
- {
- m_prgppass[ipass] = new GrPosPass(ipass);
- if (ipassFont < cpassFont)
- {
- m_prgppass[ipass]->ReadFromFont(grstrm, fxdSilfVersion, fxdRuleVersion,
- lSubTableStart + rgnPassOffsets[ipassFont]);
- }
- else
- {
- // No positioning pass in font: create a bogus one.
- m_prgppass[ipass]->InitializeWithNoRules();
- }
- }
- else
- {
- Assert(false);
- return false; // bad table
- }
- }
-
- return true;
-}
-
-/*----------------------------------------------------------------------------------------------
- Create passes corresponding to an invalid font.
-----------------------------------------------------------------------------------------------*/
-void GrTableManager::CreateEmpty()
-{
- m_cpass = 2;
-
- m_prgppass = new GrPass*[2];
- m_prgppass[0] = new GrGlyphGenPass(0);
-
- m_prgppass[1] = new GrPosPass(1);
- m_prgppass[1]->InitializeWithNoRules();
-
- m_ipassPos1 = 1;
- m_cpassLB = 0;
- m_fBidi = false;
-
- m_engst.CreateEmpty();
-}
-
-void EngineState::CreateEmpty()
-{
- m_fStartLineContext = false;
- m_fEndLineContext = false;
-}
-
-/*----------------------------------------------------------------------------------------------
- Create the slot streams corresponding to the passes.
-----------------------------------------------------------------------------------------------*/
-void EngineState::CreateSlotStreams()
-{
- if (m_prgpsstrm)
- return;
-
- m_prgpsstrm = new GrSlotStream * [m_cpass];
- for (int ipass = 0; ipass < m_cpass; ++ipass)
- {
- m_prgpsstrm[ipass] = new GrSlotStream(ipass);
- }
-}
-
-/*----------------------------------------------------------------------------------------------
- Store information about the pass-states in the pass objects.
-----------------------------------------------------------------------------------------------*/
-void GrTableManager::StorePassStates(PassState * rgzpst)
-{
- for (int ipass = 0; ipass < m_cpass; ipass++)
- Pass(ipass)->SetPassState(rgzpst + ipass);
-}
-
-/*----------------------------------------------------------------------------------------------
- Demand-driven loop: with goal of filling up final slot stream, loop backward and forward
- filling up slot streams until final stream has reached physical capacity.
-
- @param pgjus - justification agent; NULL if justification is of no interest
- @param jmodi - (internal) justification mode
- @param fStartLine, fEndLine
- @param ichSegLim - known end of segment; -1 when using backtracking
- @param dxWidthRequested - available width; when justifying, exact width desired
- @param dxUnjustifiedWidth - when justifying, what the width would be normally
- @param fNeedFinalBreak - true if the end of the segment needs to be a valid break point
- @param fMoreText - true if char stream doesn't go up to text-stream lim
- @param ichFontLim - end of the range that could be rendered by this font
- @param fInfiniteWidth - used for "measured" segments
- @param fWidthIsCharCount - kludge for test procedures: the width is a character count,
- not a pixel count
- @param lbPref - try for longest segment ending with this breakweight
- - when justifying, lb to assume
- @param lbMax - max (last resort) breakweight if no preferred break possible
- @param ichwCallerBtLim - caller's backtrack lim; -1 if caller is not backtracking
- @param twsh - how to handle trailing white-space
- @param fParaRtl - overall paragraph direction
- @param nDirDepth - direction depth of this segment
-----------------------------------------------------------------------------------------------*/
-void GrTableManager::Run(Segment * psegNew, Font * pfont,
- GrCharStream * pchstrm, IGrJustifier * pgjus, int jmodi,
- LayoutEnvironment & layout,
- int ichSegLim,
- float dxWidthRequested, float dxUnjustifiedWidth,
- bool fNeedFinalBreak, bool fMoreText, int ichFontLim,
- bool fInfiniteWidth, bool fWidthIsCharCount,
- int ichwCallerBtLim,
- int nDirDepth, SegEnd estJ)
-{
- bool fStartLine = layout.startOfLine();
- bool fEndLine = layout.endOfLine();
- LineBrk lbPref = layout.bestBreak();
- LineBrk lbMax = layout.worstBreak();
- TrWsHandling twsh = layout.trailingWs();
- bool fParaRtl = layout.rightToLeft();
- Segment * psegPrev = layout.prevSegment();
- Segment * psegInit = layout.segmentForInit();
- std::ostream * pstrmLog = layout.loggingStream();
-
- m_engst.Initialize(Engine(), this); // do this after the tables have been fully read
- m_engst.m_jmodi = jmodi;
- m_engst.m_ipassJustCalled = -1;
- m_engst.m_twsh = twsh;
- m_engst.m_fParaRtl = fParaRtl;
- m_engst.m_dxsShrinkPossible = GrSlotState::kNotYetSet;
- m_fLogging = (pstrmLog != NULL);
-
- int cbPrev;
- byte * pbPrevSegDat = NULL;
- if (psegPrev)
- cbPrev = psegPrev->NextSegInitBuffer(&pbPrevSegDat);
- else if (psegInit)
- cbPrev = psegInit->ThisSegInitBuffer(&pbPrevSegDat);
- else
- cbPrev = 0;
-
- if (pchstrm->IsEmpty())
- {
- m_engst.m_lbPrevEnd = klbNoBreak;
- InitSegmentAsEmpty(psegNew, pfont, pchstrm, fStartLine, fEndLine);
- psegNew->SetWidths(0, 0);
- psegNew->SetUpOutputArrays(pfont, this, NULL, 0, 0, 0, twsh,
- fParaRtl, nDirDepth, true);
- psegNew->SetLayout(layout);
- return;
- }
-
- int islotUnderBreak = -1; // position of inserted or final break point in underlying
- // data; none so far (if an actual LB has been inserted,
- // this is the index of that slot; otherwise it is the
- // index of the last valid slot)
- int islotSurfaceBreak = -1; // position of line break in surface stream; none so far
- LineBrk lbBestToTry = lbPref;
- LineBrk lbFound = klbNoBreak;
-
- float dxMaxWidth = dxWidthRequested;
-
- if (m_engst.m_jmodi == kjmodiJustify)
- {
- Assert(fInfiniteWidth);
- lbBestToTry = klbClipBreak;
- lbFound = lbPref;
- }
-
- float dxWidth;
-
- std::vector<int> vnslotNeeded;
- vnslotNeeded.resize(m_cpass);
-
- m_engst.InitializeStreams(this, pchstrm, cbPrev, pbPrevSegDat, fNeedFinalBreak, &islotUnderBreak);
-
- int ipassCurr;
- int nNeedInput; // kNextPass: go on to the next pass
- // kBacktrack: need to insert a line break
- // > 0: need more input from previous pass
-
- int cchwPostXlbContext = m_pgreng->PostXlbContext();
- if (ichSegLim > -1)
- {
- // When we know exactly where the end of the segment will be, get as much as
- // we need from the character stream, and then fill up the remaining streams.
- // (3 below is an arbitrary number; we just want to get slightly more than
- // we really need.)
- vnslotNeeded[0] = ichSegLim - pchstrm->Min() + cchwPostXlbContext + 3;
- for (int ipass = 1; ipass < m_cpass; ipass++)
- vnslotNeeded[ipass] = 10000;
- // Start at pass 0.
- ipassCurr = 0;
- }
- else
- {
- // When we're doing line-breaking to find the end of the segment, use the
- // demand-driven approach that tries to fill up the available space.
- vnslotNeeded[m_cpass - 1] = 1;
-
- // Start at the last pass. (It might be more efficient to start at the first pass and
- // generate a small arbitrary number of glyphs.)
- ipassCurr = m_cpass - 1;
- }
-
- while (ipassCurr < m_cpass)
- {
- if (ipassCurr == 0)
- {
- int nNeedNow = vnslotNeeded[0];
- // Zeroth pass: generate glyph IDs from the underlying input.
- nNeedInput = Pass(0)->ExtendGlyphIDOutput(this,
- pchstrm, OutputStream(0), ichSegLim, cchwPostXlbContext, lbPref,
- nNeedNow, fNeedFinalBreak, m_engst.m_twsh, &islotUnderBreak);
- Assert(nNeedInput == kNextPass || nNeedInput == kBacktrack);
- vnslotNeeded[0] -= nNeedNow;
- }
- else if (ipassCurr < m_cpass - 1)
- {
- // Middle pass.
- int cslotNeedNow = vnslotNeeded[ipassCurr];
- cslotNeedNow = max(1, cslotNeedNow);
- int cslotGot;
- Pass(ipassCurr)->ExtendOutput(this,
- InputStream(ipassCurr), OutputStream(ipassCurr), cslotNeedNow, twsh,
- &nNeedInput, &cslotGot, &islotUnderBreak);
- vnslotNeeded[ipassCurr] -= cslotGot;
- //if (nNeedInput != kNextPass && nNeedInput != kBacktrack)
- // nNeedInput = max(nNeedInput, cslotNeedNow - cslotGot);
- }
- else // (ipassCurr == m_cpass - 1)
- {
- // Final pass: position and test allotted space.
- float dxWidthWShrink = dxMaxWidth;
- if (m_engst.m_dxsShrinkPossible != GrSlotState::kNotYetSet)
- dxWidthWShrink += (int)m_engst.m_dxsShrinkPossible;
- nNeedInput = Pass(ipassCurr)->ExtendFinalOutput(this,
- InputStream(ipassCurr), OutputStream(ipassCurr),
- dxWidthWShrink, fWidthIsCharCount, fInfiniteWidth,
- (islotUnderBreak > -1), (fNeedFinalBreak && lbFound == klbNoBreak),
- lbMax, twsh,
- &islotSurfaceBreak, &dxWidth);
- }
-
- if (m_engst.m_jmodi == kjmodiJustify)
- {
- if (ipassCurr < m_ipassJust1 && !OutputStream(ipassCurr)->FullyWritten())
- {
- // When justifying, fill up all the streams up to the point where we need
- // to interact with the justification routine.
- // I think this code is obsolete.
- int nStillNeed = 1000;
- if ((ipassCurr == 1 && nNeedInput != kNextPass) || ipassCurr == 0)
- nStillNeed = ichSegLim - (pchstrm->Pos() - pchstrm->Min())
- + cchwPostXlbContext + 3;
- if (nStillNeed > 0)
- {
- if (nNeedInput == kNextPass)
- ipassCurr++; // repeat this pass
- nNeedInput = nStillNeed;
- }
- }
- else if (nNeedInput == kNextPass && ipassCurr + 1 == m_ipassJust1)
- {
- CallJustifier(pgjus, ipassCurr, dxUnjustifiedWidth, dxWidthRequested, fEndLine);
- }
- }
- DetermineShrink(pgjus, ipassCurr);
-
- if (nNeedInput == kBacktrack)
- {
- // Final output has overflowed its space--find (or adjust) the break point.
-
- bool fFoundBreak = Backtrack(&islotUnderBreak,
- &lbBestToTry, lbMax, twsh, fMoreText, ichwCallerBtLim, &lbFound);
- if (!fFoundBreak)
- {
- // Nothing will fit. Initialize the new segment just enough so that
- // we can delete it.
- InitSegmentToDelete(psegNew, pfont, pchstrm);
- return;
- }
- }
- else if (nNeedInput == kNextPass)
- {
- // This pass is sufficiently full--return to following pass.
- ipassCurr++;
- }
- else
- {
- // Get more input from previous pass.
- ipassCurr--;
- vnslotNeeded[ipassCurr] = nNeedInput;
- }
- }
-
- // At this point we have fully transduced all the text for this segment.
-
- // Figure out why we broke the segment and what the caller is supposed to do about it.
- SegEnd est;
- if (m_engst.m_jmodi == kjmodiJustify)
- {
- // Don't change what was passed in.
- est = estJ;
- }
- else if (m_engst.m_fRemovedWhtsp) // (islotUnderBreak > -1 && twsh == ktwshNoWs)
- {
- Assert(!m_engst.m_fInsertedLB);
- est = kestMoreWhtsp;
- }
-
- else if (m_engst.m_fHitHardBreak)
- {
- est = kestHardBreak;
- }
-
- else if (!m_engst.m_fExceededSpace && !fMoreText)
- // Rendered to the end of the original requested range.
- est = kestNoMore;
-
-// else if (!m_fExceededSpace && !fNextIsSameWs && fMoreText)
-// // Writing system break; may be more room on the line. But see tweak below.
-// *pest = kestWsBreak;
-
- else if (m_engst.m_fExceededSpace)
- {
- // Exceeded available space, found a legal break.
- if (twsh == ktwshNoWs && m_engst.m_fRemovedWhtsp)
- est = kestMoreWhtsp;
- else
- est = kestMoreLines;
- }
-
- else if (twsh == ktwshOnlyWs)
- {
- est = kestOkayBreak; // but see tweak below
- }
-
- else
- {
- // Broke because of something like a font change. Determine whether this is a legal
- // break or not.
- // TODO SharonC: handle the situation where it is legal to break BEFORE the first
- // character of the following segment.
- Assert(fMoreText);
- //Assert(fNextIsSameWs);
- if (ichwCallerBtLim > -1)
- {
- Assert(m_engst.m_fInsertedLB);
- }
- else if (ichSegLim > -1)
- {
- // We stopped where caller said to.
- Assert(fInfiniteWidth);
- }
- else
- {
- Assert(!m_engst.m_fInsertedLB);
- Assert(islotUnderBreak == -1 || m_engst.m_fFinalLB);
- }
- int islotTmp = OutputStream(m_cpass - 1)->WritePos();
- GrSlotState * pslotTmp;
- if (m_engst.m_fFinalLB || m_engst.m_fInsertedLB)
- pslotTmp = OutputStream(m_cpass-1)->SlotAt(islotTmp - 2);
- else
- pslotTmp = OutputStream(m_cpass-1)->SlotAt(islotTmp - 1);
-
- if (abs(pslotTmp->BreakWeight()) <= lbPref)
- est = kestOkayBreak;
-
- else if (abs(pslotTmp->BreakWeight()) > lbMax)
- est = kestBadBreak;
-
- else if (OutputStream(m_cpassLB)->HasEarlierBetterBreak(islotUnderBreak, lbFound,
- this->LBGlyphID()))
- {
- est = kestBadBreak;
- }
- else
- est = kestOkayBreak;
-
- // We no longer have the ability to know whether or not the next segment will use
- // the same writing system.
- //if (est == kestBadBreak && m_engst.m_fExceededSpace && !fNextIsSameWs && fMoreText)
- // est = kestWsBreak;
- }
-
- // Make a segment out of it and return it.
- int dichSegLen;
- InitNewSegment(psegNew, pfont, pchstrm, pgjus,
- islotUnderBreak, islotSurfaceBreak, fStartLine, fEndLine, ichFontLim, lbFound, est,
- &dichSegLen);
- if (psegNew->segmentTermination() == kestNothingFit)
- {
- return;
- }
- else if (psegNew->segmentTermination() == kestHardBreak &&
- psegNew->startCharacter() == psegNew->stopCharacter())
- {
- // Empty segment caused by a hard-break.
- m_engst.m_lbPrevEnd = klbNoBreak;
- psegNew->SetWidths(0, 0);
- psegNew->SetUpOutputArrays(pfont, this, NULL, 0, 0, 0, twsh,
- fParaRtl, nDirDepth, true);
- psegNew->SetLayout(layout);
- return;
- }
-
- psegNew->RecordInitializationForThisSeg(cbPrev, pbPrevSegDat);
-
- if ((est == kestNoMore || est == kestWsBreak) && twsh == ktwshOnlyWs &&
- dichSegLen < pchstrm->Lim() - pchstrm->Min())
- {
- // If we are asking for white-space only, and we didn't use up everything in the font
- // range, we could possibly have gotten an initial white-space only segment
- // (as opposed to a writing system break).
- est = kestOkayBreak;
- psegNew->FixTermination(est);
- }
-
- SetFinalPositions(psegNew, fWidthIsCharCount);
-
- // Do this before fixing up the associations below, so we can see the raw ones produced by the
- // rules themselves.
- //if (m_pgreng->LoggingTransduction())
- // WriteTransductionLog(pchstrm, *ppsegRet,
- // cbPrev, pbPrevSegDat, pbNextSegDat, pcbNextSegDat);
- WriteTransductionLog(pstrmLog, pchstrm, psegNew, cbPrev, pbPrevSegDat);
-
- RecordAssocsAndOutput(pfont, psegNew, twsh, fParaRtl, nDirDepth);
-
- // Do this after fixing up the associations.
- //if (m_pgreng->LoggingTransduction())
- // WriteAssociationLog(pchstrm, *ppsegRet);
- WriteAssociationLog(pstrmLog, pchstrm, psegNew);
-
- psegNew->SetLayout(layout);
-}
-
-/*----------------------------------------------------------------------------------------------
- Create a new segment to return.
-
- @param pchstrm - input stream
- @param pgjus - justification agent, in case this segment needs to be
- stretched or shrunk
- @param islotLBStreamBreak - position of inserted line break slot (which should be equal
- to the position in the glyph generation stream);
- -1 if no line-break was inserted (we rendered to the
- end of the range)
- @param islotSurfaceBreak - position of line break slot in final (surface) stream
- @param fStartLine - does this segment start a line?
- @param fEndLine - does this segment end a line?
- @param ichFontLim - end of range that could be rendered by this font
- @param lbEndFound - line break found; possibly adjusted here
- @param est - why did the segment terminate
-----------------------------------------------------------------------------------------------*/
-void GrTableManager::InitNewSegment(Segment * psegNew,
- Font * pfont, GrCharStream * pchstrm, IGrJustifier * pgjus,
- int islotLBStreamBreak, int islotSurfaceBreak, bool fStartLine, bool fEndLine, int ichFontLim,
- LineBrk lbEndFound, SegEnd est, int * pdichSegLen)
-{
- LineBrk lbStart = m_engst.m_lbPrevEnd;
- LineBrk lbEnd = lbEndFound;
- if (est == kestBadBreak)
- lbEnd = klbLetterBreak;
-
- int ichwMin = pchstrm->Min();
- int ichwLim;
-
-// int cslotPreSegStream0 = m_cslotPreSeg;
-// if (m_fInitialLB && m_cpassLB > 0)
-// {
-// // Initial LB is included in m_cslotPreSeg, but is not in stream 0.
-// // --Not really needed, because both islotLBStreamBreak and m_cslotPreSeg take
-// // the initial LB into account if it is there.
-// cslotPreSegStream0--;
-// }
-
- // No longer have to subtract this, because the chunk map takes it into
- // consideration.
- //int cslotPreInitialLB = m_cslotPreSeg - (m_fInitialLB ? 1 : 0);
-
- //int ichwOldTmp;
-
- if (m_engst.m_fInsertedLB)
- {
- Assert(islotLBStreamBreak > -1);
- int ichwSegLim = m_engst.LbSlotToSegLim(islotLBStreamBreak, pchstrm, m_cpassLB);
- ichwLim = ichwSegLim + pchstrm->Min(); // - cslotPreInitialLB;
-
- // Old result, for debugging:
- //ichwOldTmp = islotLBStreamBreak + pchstrm->Min() - m_cslotPreSeg;
- }
- else if (m_engst.m_fFinalLB || islotLBStreamBreak == -1)
- ichwLim = pchstrm->Lim();
- else
- {
- int ichwSegLim = m_engst.LbSlotToSegLim(islotLBStreamBreak, pchstrm, m_cpassLB);
- ichwLim = ichwSegLim + pchstrm->Min(); // - cslotPreInitialLB;
-
- // Old result, for debugging:
- // islotLBStreamBreak is the last slot in the segment, not the LB glyph; hence +1.
- //ichwOldTmp = islotLBStreamBreak + pchstrm->Min() - m_cslotPreSeg + 1;
- }
-
- *pdichSegLen = ichwLim - ichwMin;
-
- if (ichwMin >= ichwLim)
- {
- if (est == kestHardBreak)
- {
- // Empty segment cause by a hard-break.
- InitSegmentAsEmpty(psegNew, pfont, pchstrm, fStartLine, fEndLine);
- psegNew->FixTermination(est);
- }
- else
- {
- // Invalid empty segment.
- Assert(ichwMin == ichwLim);
- InitSegmentToDelete(psegNew, pfont, pchstrm);
- }
- return;
- }
-
- Assert(psegNew);
-
- psegNew->Initialize(pchstrm->TextSrc(),
- ichwMin, ichwLim,
- lbStart, lbEnd, est, fStartLine, fEndLine, m_pgreng->RightToLeft());
-
- psegNew->SetEngine(m_pgreng);
- psegNew->SetFont(pfont);
- psegNew->SetJustifier(pgjus);
- psegNew->SetFaceName(m_pgreng->FaceName(), m_pgreng->BaseFaceName());
-
- bool fNextSegNeedsContext =
- !(est == kestNoMore || est == kestWsBreak
- || ichwLim >= pchstrm->Lim() || ichwLim >= ichFontLim);
-
- InitializeForNextSeg(psegNew, islotLBStreamBreak, islotSurfaceBreak, lbEnd,
- fNextSegNeedsContext, pchstrm);
-
- psegNew->SetPreContext(0 - m_pgreng->PreXlbContext());
-}
-
-/*----------------------------------------------------------------------------------------------
- The newly created segment is invalid, for instance, because we were backtracking and
- couldn't find a valid break point. Initialize it just enough so that it can be
- deleted by the client.
-----------------------------------------------------------------------------------------------*/
-void GrTableManager::InitSegmentToDelete(Segment * psegNew, Font * pfont,
- GrCharStream * pchstrm)
-{
- psegNew->Initialize(pchstrm->TextSrc(), 0, 0,
- klbClipBreak, klbClipBreak, kestNothingFit, false, false,
- m_pgreng->RightToLeft());
-
- psegNew->SetEngine(m_pgreng);
- psegNew->SetFont(pfont);
- psegNew->SetJustifier(NULL); // can't justify an empty segment
- psegNew->SetFaceName(m_pgreng->FaceName(), m_pgreng->BaseFaceName());
- psegNew->SetPreContext(0);
-}
-
-/*----------------------------------------------------------------------------------------------
- Map from the given slot (which is generally the final LB slot) to the end of the segment,
- taking into account the fact that a single slot may represent two 16-bit surrogates.
-
- There are several approaches that seem reasonable but do NOT work. (I tried them!)
- You can't calculate it directly from the length of the streams, because that doesn't take
- into account the possible presence of surrogate pairs in the character stream. You can't
- use the chunk map at the point of the LB, because if a rule spanned a LB the chunk won't
- have ended there and so there won't be any valid information.
-
- What seems to work is to figure out the slot(s) in the zeroth stream using the associations
- and then use the segment offset for this slot. This should be reliable because there is
- always a one-to-one correspondence between glyphs in the line-break passes (ie, no
- insertions or deletions), so the associations should be dependable and straightforward.
-----------------------------------------------------------------------------------------------*/
-int EngineState::LbSlotToSegLim(int islotLB, GrCharStream * pchstrm, int cpassLB)
-{
- Assert(islotLB < OutputStream(cpassLB)->WritePos());
-
- // Figure out the corresponding characters in the zeroth stream. These should be straight-
- // forward to figure out because no substitutions are permitted in the LB passes.
- // I do the slots before and after the LB, if possible, as a sanity check.
- GrSlotStream * psstrmLB = OutputStream(cpassLB);
- GrSlotState * pslotPreLB = (m_fFinalLB || m_fInsertedLB) ?
- psstrmLB->SlotAt(islotLB - 1) :
- psstrmLB->SlotAt(islotLB);
- GrSlotState * pslotPostLB = (psstrmLB->WritePos() > islotLB + 1) ?
- psstrmLB->SlotAt(islotLB + 1) :
- NULL;
-
- int ichwPreLB = pslotPreLB->AfterAssoc();
-
- int ichwSegLim;
- if (pslotPostLB)
- {
- ichwSegLim = pslotPostLB->BeforeAssoc();
- Assert(ichwPreLB + 1 == ichwSegLim
- || ichwPreLB + 2 == ichwSegLim); // in case of a surrogate
- }
- else
- {
- ichwSegLim = ichwPreLB + 1;
- while (!pchstrm->AtUnicodeCharBoundary(ichwSegLim))
- ichwSegLim++;
- Assert(pchstrm->AtUnicodeCharBoundary(ichwSegLim));
- }
-
- // Old buggy routine that doesn't handle the case where a rule (and hence the chunk map) did
- // not end at the LB character:
- // Map backwards through the LB pass streams, if any.
- //int islotAdjusted = islotLB + 1; // after the LB
- //for (int ipass = m_cpassLB; ipass > 0; ipass--)
- //{
- // islotAdjusted = ChunkInPrev(ipass, islotAdjusted, pchstrm);
- //}
- //
- //int ichwSegLim = ChunkInPrev(0, islotAdjusted, pchstrm);
-
- // Mapping from 32-bit to 16-bit should only increase the index. Except that there
- // may be a LB in the slot stream that is not in the character stream, so it could be
- // one less.
- Assert(ichwSegLim + m_cslotPreSeg >= islotLB - 1);
-
- return ichwSegLim;
-}
-
-/*----------------------------------------------------------------------------------------------
- Return the chunk mapping into the previous stream, taking into account the fact that it
- is not recorded for the write-position.
-----------------------------------------------------------------------------------------------*/
-int GrTableManager::ChunkInPrev(int ipass, int islot, GrCharStream * pchstrm)
-{
- GrSlotStream * psstrmOut = OutputStream(ipass);
- GrSlotStream * psstrmIn = (ipass == 0) ? NULL : InputStream(ipass);
-
- int islotTmp = islot;
- int islotAdjusted;
- do {
- if (islot >= psstrmOut->WritePos())
- {
- Assert(islot == psstrmOut->WritePos());
- islotAdjusted = (ipass == 0) ? pchstrm->SegOffset() : psstrmIn->ReadPos();
- Assert(islotAdjusted > -1);
- }
- else
- islotAdjusted = psstrmOut->ChunkInPrev(islotTmp);
- islotTmp--;
- } while (islotAdjusted == -1);
-
- return islotAdjusted;
-}
-
-/*----------------------------------------------------------------------------------------------
- Create a new segment corresponding to an empty string.
-
- @param pchstrm - input stream
- @param fStartLine - does this segment start a line?
- @param fEndLine - does this segment end a line?
-----------------------------------------------------------------------------------------------*/
-void GrTableManager::InitSegmentAsEmpty(Segment * psegNew, Font * pfont,
- GrCharStream * pchstrm, bool fStartLine, bool fEndLine)
-{
- LineBrk lbStart = m_engst.m_lbPrevEnd;
- LineBrk lbEnd = klbNoBreak;
-
- int ichwMin = 0;
- int ichwLim = 0;
-
- Assert(psegNew);
-
- psegNew->Initialize(pchstrm->TextSrc(), ichwMin, ichwLim,
- lbStart, lbEnd, kestNoMore, fStartLine, fEndLine, m_pgreng->RightToLeft());
-
- psegNew->SetEngine(m_pgreng);
- psegNew->SetFont(pfont);
- psegNew->SetJustifier(NULL); // can't justify an empty segment
- psegNew->SetFaceName(m_pgreng->FaceName(), m_pgreng->BaseFaceName());
-
- byte pbNextSegDat[256];
- int cbNextSegDat;
- int * pcbNextSegDat = &cbNextSegDat;
-
- // Initialization for (theoretical) next segment.
- byte * pb = pbNextSegDat;
- *pb++ = byte(lbEnd);
- *pb++ = kdircNeutral;
- *pb++ = kdircNeutral;
- *pb++ = 0;
- for (int ipass = 0; ipass < m_cpass; ipass++)
- *pb++ = 0;
- *pcbNextSegDat = 0;
- psegNew->RecordInitializationForNextSeg(*pcbNextSegDat, pbNextSegDat);
-
- psegNew->SetPreContext(0);
-}
-
-/*----------------------------------------------------------------------------------------------
- Find a line-break and unwind the passes. Return true if we were able to
- backtrack successfully (which may have meant using a less-than-optimal line-break).
- Return false if no line-break could be found (because maxBreakWeight did not allow
- letter breaks or clipping--generally because there was already something on this
- line).
-
- @param pislotPrevBreak - position of previously-created break, -1 if none;
- this is the index of the line-break glyph if any,
- or the index of the last slot in the segment;
- adjusted to contain the position of the newly
- found break
- @param plbMin - minimum (best) line break weight to try
- @param lbMax - maximum (worst possible) line break weight
- @param twsh - how to handle trailing white-space
- @param fMoreText - true if char stream doesn't go up to original lim
- @param ichwCallerBtLim - caller's backtrack lim; -1 if caller is not backtracking
- @param plbFound - kind of line-break created
-----------------------------------------------------------------------------------------------*/
-bool GrTableManager::Backtrack(int * pislotPrevBreak,
- LineBrk * plbMin, LineBrk lbMax, TrWsHandling twsh, bool fMoreText,
- int ichwCallerBtLim,
- LineBrk * plbFound)
-{
- int islotStartTry;
- //if (*pislotPrevBreak == ichwCallerBtLim - 1)
- //{
- // islotStartTry = *pislotPrevBreak;
- //}
- //else
- if (*pislotPrevBreak == -1)
- {
- // If no line break has been found so far, figure out where to start trying based
- // on where the final stream choked.
- GrSlotStream * psstrmFinal = OutputStream(m_cpass-1);
- if ((islotStartTry
- = m_engst.TraceStreamZeroPos(psstrmFinal->WritePos()-1, TopDirectionLevel()))
- == -1)
- {
- // Just start looking at the end of what's been generated.
- islotStartTry = OutputStream(m_cpassLB)->ReadPos() - 1;
- }
- }
- else
- {
- // Start just before previous line break.
- if (m_engst.m_fInsertedLB || m_engst.m_fFinalLB)
- islotStartTry = *pislotPrevBreak - 2; // skip inserted LB and previous slot
- else
- islotStartTry = *pislotPrevBreak - 1; // skip previous slot
- }
- if (ichwCallerBtLim > -1 && islotStartTry > ichwCallerBtLim - 1)
- {
- islotStartTry = ichwCallerBtLim - 1;
- }
-
- // Determine if we want to insert an actual line-break "glyph". Don't do that if
- // we are omitting trailing white space or we are at a writing-system or font break.
- bool fInsertLB;
- if (twsh == ktwshNoWs)
- // omitting trailing white-space
- fInsertLB = false;
- else if (twsh == ktwshOnlyWs)
- // trailing white-space segment
- fInsertLB = true;
- else if (ichwCallerBtLim > -1)
- // backtracking
- fInsertLB = true;
- else if (*pislotPrevBreak > -1)
- // no longer at the edge of the writing system or font
- fInsertLB = true;
- else if (!fMoreText)
- // at final edge of total range to render
- fInsertLB = true;
- else
- fInsertLB = false;
-
- // Try to insert a line-break in the output of the (final) line-break pass (if any, or
- // the output of the glyph-generation pass). First try the preferred (strictest)
- // break weight and gradually relax.
- LineBrk lb = *plbMin;
- Assert(*plbMin <= lbMax);
- GrSlotStream * psstrmLB = OutputStream(m_cpassLB);
- islotStartTry = min(islotStartTry, psstrmLB->WritePos() - 1);
- int islotNewBreak = -1;
- while (lb <= lbMax)
- {
- LineBrk lbNextToTry;
- if (fInsertLB)
- {
- islotNewBreak = psstrmLB->InsertLineBreak(this,
- *pislotPrevBreak, m_engst.m_fInsertedLB, islotStartTry,
- lb, twsh, m_engst.m_cslotPreSeg, &lbNextToTry);
- }
- else
- {
- islotNewBreak = psstrmLB->MakeSegmentBreak(this,
- *pislotPrevBreak, m_engst.m_fInsertedLB, islotStartTry,
- lb, twsh, m_engst.m_cslotPreSeg, &lbNextToTry);
- }
- if (islotNewBreak > -1)
- break;
- if (lb >= lbMax)
- break;
- lb = IncLineBreak(lb); // relax the break weight
- }
-
- if (islotNewBreak == -1)
- {
- return false;
- }
-
- // We've successfully inserted a line break.
-
- if (fInsertLB)
- m_engst.m_fInsertedLB = true;
-
- m_engst.m_fFinalLB = false;
-
- UnwindAndReinit(islotNewBreak);
-
- *pislotPrevBreak = islotNewBreak;
- *plbMin = lb; // return the best break we were able to find, so we don't keep trying
- // for a better one when we know now that we can't find it
- *plbFound = lb;
-
- return true;
-}
-
-/*----------------------------------------------------------------------------------------------
- This method is called after backtracking or removing trailing white-space.
- Unwind the following slot streams as necessary depending on where the change was made.
-
- @param islotNewBreak - in output of (final) line-break pass
-----------------------------------------------------------------------------------------------*/
-void GrTableManager::UnwindAndReinit(int islotNewBreak)
-{
- OutputStream(m_cpassLB)->ZapCalculatedDirLevels(islotNewBreak);
-
- // Mark the passes before the line-break pass as fully written, so that if there
- // isn't a line-break glyph to intercept, we don't keep trying to get more input
- // from them.
- int ipass;
- for (ipass = 1; ipass < m_cpassLB + 1; ++ipass)
- {
- InputStream(ipass)->MarkFullyWritten();
- }
-
- // Unwind the passes to the changed positions.
- // Note that we don't need to unwind pass 0, since all it does is generate glyph IDs.
- // Also we don't need to unwind the line-break passes, because conceptually they happen
- // before the break is inserted.
-
- int islotChgPos = islotNewBreak;
- bool fFirst = true;
- for (ipass = m_cpassLB + 1 ; ipass < m_cpass ; ++ipass)
- {
- islotChgPos =
- Pass(ipass)->Unwind(this, islotChgPos, InputStream(ipass), OutputStream(ipass),
- fFirst);
- fFirst = false;
- }
- // For anything that may have been skipped in the final output:
- OutputStream(m_cpass - 1)->SetReadPos(0);
- OutputStream(m_cpass - 1)->SetReadPosMax(0);
- Pass(m_cpass - 1)->UndoResyncSkip();
- OutputStream(m_cpass - 1)->ClearSlotsSkippedToResync();
-
- m_engst.InitPosCache();
-
- m_engst.m_dxsShrinkPossible = GrSlotState::kNotYetSet; // recalculate it
-}
-
-/*----------------------------------------------------------------------------------------------
- Store information in the newly created segment that will allow us to reinitalize
- the streams in order to process the next segment, appropriately handling any
- cross-line-boundary contextuals.
-
- The information required is the number of glyphs in the first stream that must
- be reprocessed, and a skip-offset between each stream indicating the beginning
- of chunk boundaries.
-
- In most cases, where there are no cross-line-boundary contextuals, all these numbers
- will be zero.
-
- The buffer generated is of the following format (all are 1 byte, unsigned):
- end breakweight
- previous strong directionality code
- previous terminator dir code
- restart backup
- skip offsets for each pass
- This format must match what is generated by InitializeStreams.
-
- @param pseg - newly created segment
- @param islotUnderBreak - position of line break inserted in underlying stream (output
- of glyph-generation pass--stream 0); -1 if we rendered to
- the end of the range
- @param islotSurfaceBreak - position of line break in surface stream;
- -1 if we rendered to the end of the range
- @param lbEnd - kind of line-break at the end of this segment
- @param fNextSegNeedsContext - true if we need to remember the context for the next seg
- @param pchstrm - character stream input for this segment
- @param cbNextMax - amount of space available in the buffer
- @param pbNextSegDat - buffer for initializing next segment
- @param pcbNextSegDat - amount of space used in buffer
-----------------------------------------------------------------------------------------------*/
-void GrTableManager::InitializeForNextSeg(Segment * pseg,
- int islotUnderBreak, int islotSurfaceBreak, LineBrk lbEnd,
- bool fNextSegNeedsContext, GrCharStream * pchstrm)
-{
- byte pbNextSegDat[256];
- int cbNextSegDat;
- int * pcbNextSegDat = &cbNextSegDat;
-
- std::vector<int> vcslotSkipOffsets;
- vcslotSkipOffsets.resize(m_cpass);
-
- byte * pb = pbNextSegDat;
-
- if (!fNextSegNeedsContext)
- {
- // No contextualization between this segment and the next, whatever kind of renderer
- // it might use.
- *pcbNextSegDat = 0;
- return;
- }
-
- gid16 chwLB = LBGlyphID();
-
- int islotUnderLim = islotUnderBreak;
- if (!m_engst.m_fInsertedLB && !m_engst.m_fFinalLB)
- // Then islotUnderBreak is the position of the last slot in the segment; increment
- // to get the lim in stream zero.
- islotUnderLim++;
-
- int islotSurfaceLim = islotSurfaceBreak;
- if (islotSurfaceLim == -1)
- islotSurfaceLim = OutputStream(m_cpass - 1)->FinalSegLim();
-
- *pb++ = byte(lbEnd);
-
- // Find previous strong and terminator directionality codes.
-
- GrSlotStream * psstrm = OutputStream(m_cpass - 1);
- DirCode dircStrong = kdircNeutral;
- DirCode dircTerm = kdircNeutral;
- int islot;
- for (islot = islotSurfaceLim; islot-- > 0; )
- {
- GrSlotState * pslot = psstrm->SlotAt(islot);
- DirCode dirc = pslot->Directionality();
- if (dircTerm == kdircNeutral && dirc == kdircEuroTerm)
- dircTerm = dirc;
- if (StrongDir(dirc))
- {
- dircStrong = dirc;
- break;
- }
- }
- *pb++ = byte(dircStrong);
- *pb++ = byte(dircTerm);
-
- // Record how much of each pass to redo in the next segment.
- // The basic algorithm is described in the "WR Data Transform Engine" document.
- // But here we are doing a variation on what is described there. We are calculating
- // the backup locations for BOTH the rule start locations and the necessary pre-contexts.
- // It is the precontext values that are recorded for use by the following segment. But we
- // also calculate the positions for the rule-start locations to make sure there is enough
- // pre-context at each pass.
-
- int islotRS = islotSurfaceLim; // rule-start positions
- int islotPC = islotRS; // to handle pre-context positions
-
- // If line-breaks are irrelevant to this font, we don't need to bother.
- bool fGiveUp = !m_pgreng->LineBreakFlag();
-
- int ipass;
- for (ipass = m_cpass - 1; ipass >= 0 && !fGiveUp; --ipass)
- {
- GrSlotStream * psstrmIn = (ipass == 0) ? NULL : InputStream(ipass);
- GrSlotStream * psstrmOut = OutputStream(ipass);
- int islotBackupMin = (ipass == 0) ? 0 : psstrmOut->SegMin();
- if (ipass >= m_cpassLB && m_engst.m_fInitialLB)
- islotBackupMin++; // how far we can back up--not before the start of this segment
-
- int islotPrevRS = 0; // corresponding slot in the previous stream for rule-start position
- int islotPrevPC = 0; // same for pre-context position
-
- // Initially we have to include at least this many prior slots:
- int cslotSkipOffset = 0;
-
- if (islotRS == psstrmOut->WritePos())
- {
- islotPrevRS = (ipass == 0) ? pchstrm->Pos() : psstrmIn->ReadPos();
- }
- else
- {
- // Ignore the final line-break, because it is explicitly inserted during
- // the (final) line-break pass.
-// if (ipass == m_cpassLB && psstrm->SlotAt(islotRS)->IsFinalLineBreak(chwLB))
-// {
-// Assert(islotRS > 0);
-// islotRS--;
-// }
- // Ignore the chunk in the pass that generated the line break that corresponds
- // to the inserted line break being chunked with the previous glyph--we don't
- // want to treat that as a cross-line-boundary contextual!
- if (ipass == m_cpassLB && psstrmOut->SlotAt(islotRS)->IsFinalLineBreak(chwLB))
- {
-// Assert(psstrm->ChunkInPrev(islotRS) == -1);
- if (islotRS + 1 == psstrmOut->WritePos())
- islotPrevRS = (ipass == 0) ? pchstrm->SegOffset() : psstrmIn->ReadPos();
- else
- islotPrevRS = psstrmOut->ChunkInPrev(islotRS + 1);
- }
- else
- {
- // Back up to the beginning of a chunk.
- while (islotRS >= islotBackupMin &&
- (islotPrevRS = psstrmOut->ChunkInPrev(islotRS)) == -1)
- {
- --islotRS;
- //++cslotSkipOffset;
- }
- }
- }
- if (islotPrevRS == -1 || islotRS < islotBackupMin) // hit the start of the segment
- {
- // In order to get enough context to be sure to run the same rules again,
- // we'd have to back up into the previous segment. Too complicated, so give up.
- fGiveUp = true;
- break;
- }
-
- int cslotPreContext = Pass(ipass)->MaxRulePreContext();
-LBackupPC:
- if (islotPC == psstrmOut->WritePos())
- {
- islotPrevPC = (ipass == 0) ? pchstrm->Pos() : psstrmIn->ReadPos();
- }
- else
- {
- if (ipass == m_cpassLB && psstrmOut->SlotAt(islotPC)->IsFinalLineBreak(chwLB))
- {
- if (islotPC+1 == psstrmOut->WritePos())
- islotPrevPC = (ipass == 0) ? pchstrm->SegOffset() : psstrmIn->ReadPos();
- else
- islotPrevPC = psstrmOut->ChunkInPrev(islotPC+1);
- }
- else
- {
- // Back up to the beginning of a chunk; also make sure there are enough slots
- // to handle the required pre-context for this pass.
- while (islotPC >= islotBackupMin &&
- ((islotPrevPC = psstrmOut->ChunkInPrev(islotPC)) == -1 ||
- islotPrevRS - islotPrevPC < cslotPreContext))
- {
- --islotPC;
- ++cslotSkipOffset;
- }
- }
- }
- if (islotPC >= islotBackupMin && islotPrevRS - islotPrevPC < cslotPreContext)
- {
- --islotPC;
- ++cslotSkipOffset;
- goto LBackupPC;
- }
- if (islotPrevPC == -1 || islotPC < islotBackupMin) // hit the start of the segment
- {
- fGiveUp = true;
- break;
- }
-
- vcslotSkipOffsets[ipass] = cslotSkipOffset;
-
- islotRS = islotPrevRS;
- islotPC = islotPrevPC;
-
- if (ipass == 0)
- {
- // Convert from underlying chars to stream-zero slots.
- islotRS += m_engst.m_cslotPreSeg;
- islotPC += m_engst.m_cslotPreSeg;
- }
- }
-
- // The following should be the case unless they tried to position contextually across
- // the line break boundary, which is a very strange thing to do! - no longer true,
- // because the pre-context is now included in this count, and it normal to have
- // a pre-context in the final positioning pass.
- //Assert(vcslotSkipOffsets[m_cpass-1] == 0);
-
- // Also no adjustments are made by the glyph-generation pass, so this should always
- // be true:
- Assert(vcslotSkipOffsets[0] == 0);
-
- // The number of slots in the underlying input previous to the line-break
- // that must be reprocessed:
- int cslotPreLB = islotUnderLim - islotPC;
-
- if (fGiveUp)
- {
- // We can't reasonably provide enough context, so don't try to do it at all.
- cslotPreLB = 0;
- for (ipass = 0; ipass < m_cpass; ipass++)
- vcslotSkipOffsets[ipass] = 0;
- }
-
- Assert(cslotPreLB >= 0);
- Assert(cslotPreLB < 0xFF);
-
- *pb++ = byte(cslotPreLB);
- for (ipass = 0; ipass < m_cpass; ipass++)
- *pb++ = byte(vcslotSkipOffsets[ipass]);
-
- *pcbNextSegDat = 4 + m_cpass;
-
- pseg->RecordInitializationForNextSeg(*pcbNextSegDat, pbNextSegDat);
-}
-/*----------------------------------------------------------------------------------------------
- Make sure the final positions are set for every glyph.
-----------------------------------------------------------------------------------------------*/
-void GrTableManager::SetFinalPositions(Segment * pseg, bool fWidthIsCharCount)
-{
- float xsTotalWidth, xsVisWidth;
-
-#ifdef OLD_TEST_STUFF
- if (fWidthIsCharCount)
- xsTotalWidth = xsVisWidth = 0;
- else
-#endif // OLD_TEST_STUFF
-
- // Make sure the final positions are set for every glyph.
- CalcPositionsUpTo(m_cpass-1, reinterpret_cast<GrSlotState *>(NULL),
- &xsTotalWidth, &xsVisWidth);
- pseg->SetWidths(xsVisWidth, xsTotalWidth);
-}
-
-/*----------------------------------------------------------------------------------------------
- Calculate the associations, and record the output slots in the segment.
-----------------------------------------------------------------------------------------------*/
-void GrTableManager::RecordAssocsAndOutput(Font * pfont, Segment * pseg,
- TrWsHandling twsh, bool fParaRtl, int nDirDepth)
-{
- int cchwUnderlying = pseg->stopCharacter() - pseg->startCharacter();
- GrSlotStream * psstrmFinal = OutputStream(m_cpass-1);
- int csloutSurface = psstrmFinal->WritePos() - psstrmFinal->IndexOffset(); // # of output slots
-
- psstrmFinal->SetNeutralAssociations(LBGlyphID());
-
- pseg->SetUpOutputArrays(pfont, this, psstrmFinal, cchwUnderlying, csloutSurface, LBGlyphID(),
- twsh, fParaRtl, nDirDepth);
-
- // Set underlying-to-surface assocations in the segment.
- CalculateAssociations(pseg, csloutSurface);
-}
-
-/*----------------------------------------------------------------------------------------------
- Calculate the underlying-to-surface associations and ligature mappings.
- Assumes the arrays have been properly initialized.
-----------------------------------------------------------------------------------------------*/
-void GrTableManager::CalculateAssociations(Segment * pseg, int csloutSurface)
-{
- GrSlotStream * psstrmFinal = OutputStream(m_cpass-1);
-
- std::vector<int> vichwAssocs;
- std::vector<int> vichwComponents;
-
- for (int islot = psstrmFinal->IndexOffset(); islot < psstrmFinal->WritePos(); islot++)
- {
- GrSlotState * pslot = psstrmFinal->SlotAt(islot);
- int islout = islot - psstrmFinal->IndexOffset();
- if (!pslot->IsLineBreak(LBGlyphID()))
- {
- vichwAssocs.clear();
- pslot->AllAssocs(vichwAssocs);
-
- size_t iichw;
- for (iichw = 0; iichw < vichwAssocs.size(); ++iichw)
- {
- pseg->RecordSurfaceAssoc(vichwAssocs[iichw], islout, 0);
- }
-
- vichwComponents.clear();
- if (pslot->HasComponents())
- pslot->AllComponentRefs(vichwComponents);
-
- for (iichw = 0; iichw < vichwComponents.size(); iichw++)
- {
- pseg->RecordLigature(vichwComponents[iichw], islout, iichw);
- }
- }
- }
-
- AdjustAssocsForOverlaps(pseg);
- pseg->CleanUpAssocsVectors();
-
-// pseg->AdjustForOverlapsWithPrevSeg(); // for any characters officially in the
- // previous segment but rendered in this one,
- // or vice versa
-
- // TODO SharonC: for all characters that are right-to-left in the underlying stream,
- // reverse the before and after flags in the segment.
-}
-
-/*----------------------------------------------------------------------------------------------
- For any slots associated with characters in the new segment but not rendered in the
- segment, adjust the underlying-to-surface mappings accordingly. Ie, set the before
- mapping to kNegInfinity for slots at the beginning of the streams, and set the
- after mapping to kPosInfinity for slots at the end of the streams.
-
- TODO SharonC: Rework this method more carefully to handle each slot exactly once. The current
- approach could possibly, for instance, process a slot that is inserted in one pass
- and deleted in the next.
-----------------------------------------------------------------------------------------------*/
-void GrTableManager::AdjustAssocsForOverlaps(Segment * pseg)
-{
- if (!m_engst.m_fInitialLB && !m_engst.m_fFinalLB && !m_engst.m_fInsertedLB)
- // no cross-line contextualization possible
- return;
-
- gid16 chwLB = LBGlyphID();
- std::vector<int> vichwAssocs;
-
- // Process any slots output by any substitution pass (or later) on either side of the
- // line-breaks. These are the relevant slots that are rendered in the previous and
- // following segments.
- for (int ipass = m_cpass; ipass-- > m_cpassLB + 1; )
- {
- GrSlotStream * psstrm = OutputStream(ipass);
- int islotMin = (ipass == m_cpass - 1) ? psstrm->IndexOffset() : 0;
-
- if (m_engst.m_fInitialLB)
- {
- for (int islot = islotMin; ; islot++)
- {
- GrSlotState * pslot = psstrm->SlotAt(islot);
- if (pslot->IsInitialLineBreak(chwLB))
- break;
- Assert(!pslot->IsFinalLineBreak(chwLB));
- if (pslot->PassModified() != ipass)
- continue;
-
- vichwAssocs.clear();
- pslot->AllAssocs(vichwAssocs);
- for (size_t iichw = 0; iichw < vichwAssocs.size(); ++iichw)
- pseg->MarkSlotInPrevSeg(vichwAssocs[iichw], islot);
- }
- }
-
- if ((m_engst.m_fFinalLB || m_engst.m_fInsertedLB) && ipass > m_cpassLB)
- {
- for (int islot = psstrm->WritePos(); islot-- > islotMin ; )
- {
- GrSlotState * pslot = psstrm->SlotAt(islot);
- if (pslot->IsFinalLineBreak(chwLB))
- break;
- Assert(!pslot->IsInitialLineBreak(chwLB));
- if (pslot->PassModified() != ipass)
- continue;
-
- vichwAssocs.clear();
- pslot->AllAssocs(vichwAssocs);
- for (size_t iichw = 0; iichw < vichwAssocs.size(); ++iichw)
- pseg->MarkSlotInNextSeg(vichwAssocs[iichw], islot);
- }
- }
- }
-}
-
-/*----------------------------------------------------------------------------------------------
- Initialize all the streams. In particular, process the information about the
- skip-offsets to handle segments other than the first.
-
- @param cbPrev - number of bytes in the pbPrevSegDat buffer
- @param pbPrevSegDat - buffer in the following format (all are 1 byte, unsigned):
- prev seg's end breakweight
- prev seg's previous strong directionality code
- prev seg's previous terminator dir code
- restart backup
- skip offsets for each pass
- This format must match what is generated by InitializeForNextSeg.
-----------------------------------------------------------------------------------------------*/
-void EngineState::InitializeStreams(GrTableManager * ptman,
- GrCharStream * pchstrm,
- int cbPrev, byte * pbPrevSegDat, bool fNeedFinalBreak, int * pislotFinalBreak)
-{
- int cpassLB = ptman->NumberOfLbPasses();
- int ipassPos1 = ptman->FirstPosPass();
-
- CreateSlotStreams();
-
- int cslotBackup = 0;
-
- InitForNewSegment(ptman);
-
- if (cbPrev == 0)
- {
- m_lbPrevEnd = klbNoBreak;
- m_dircInitialStrongDir = kdircNeutral;
- m_dircInitialTermDir = kdircNeutral;
- for (int ipass = 0; ipass < m_cpass; ++ipass)
- {
- OutputStream(ipass)->Initialize(ipassPos1, false);
- m_prgzpst[ipass].SetResyncSkip(0);
-
- if (ptman->LoggingTransduction())
- m_prgzpst[ipass].InitializeLogInfo();
- }
- }
- else
- {
- Assert(cbPrev >= 4);
- byte * pb = pbPrevSegDat;
-
- m_lbPrevEnd = LineBrk(*pb++);
-
- // Directionality codes from the previous segment.
- m_dircInitialStrongDir = DirCode((int)*pb++);
- m_dircInitialTermDir = DirCode((int)*pb++);
-
- cslotBackup = (int)*pb++;
- Assert((cbPrev == 4 || cslotBackup == 0) || cbPrev == m_cpass + 4);
-
- for (int ipass = 0; ipass < m_cpass; ++ipass)
- {
- OutputStream(ipass)->Initialize(ipassPos1, true);
- if (cbPrev == 4)
- m_prgzpst[ipass].SetResyncSkip(0); // different writing system
- else
- m_prgzpst[ipass].SetResyncSkip(*pb++);
-
- if (ptman->LoggingTransduction())
- m_prgzpst[ipass].InitializeLogInfo();
- }
-
- pchstrm->Backup(cslotBackup);
- }
-
- if (cbPrev > 0 || pchstrm->StartLine())
- {
- // Go ahead and run the initial line-break passes (if any), and then insert
- // a line-break at the appropriate place where the new segment will begin.
- int cslotToGet = cslotBackup;
-LGetMore:
- ptman->Pass(0)->ExtendGlyphIDOutput(ptman, pchstrm, OutputStream(0),
- -1, 0, klbWordBreak,
- cslotToGet, fNeedFinalBreak, m_twsh, pislotFinalBreak);
- OutputStream(0)->SetSegMin(cslotBackup);
- for (int ipass = 1; ipass <= cpassLB; ipass++)
- {
- if (cslotToGet > 0)
- {
- int nRet = kNextPass;
- int cslotGot;
- ptman->Pass(ipass)->ExtendOutput(ptman,
- InputStream(ipass), OutputStream(ipass),
- cslotToGet, m_twsh, &nRet, &cslotGot, pislotFinalBreak);
- if (nRet != kNextPass)
- {
- cslotToGet = 1;
- goto LGetMore;
- }
- }
- OutputStream(ipass)->SetSegMin(cslotBackup);
- }
- Assert(OutputStream(cpassLB)->WritePos() >= cslotBackup);
- m_cslotPreSeg = cslotBackup;
- if (pchstrm->StartLine())
- {
- OutputStream(cpassLB)->AppendLineBreak(ptman, pchstrm, m_lbPrevEnd,
- (ptman->RightToLeft() ? kdircRlb : kdircLlb), cslotBackup, true, -1);
- SetInitialLB();
- m_cslotPreSeg++;
- if (cpassLB > 0 && *pislotFinalBreak > -1)
- // See corresponding kludge in GrPass::ExtendGlyphIDOutput.
- *pislotFinalBreak += 1;
- }
- else
- {
- OutputStream(cpassLB)->SetSegMin(cslotBackup);
- }
- OutputStream(cpassLB)->CalcIndexOffset(ptman);
- }
-
- else
- {
- Assert(cslotBackup == 0);
- OutputStream(0)->SetSegMin(0);
- m_cslotPreSeg = 0;
- }
-}
-
-/*----------------------------------------------------------------------------------------------
- Reinitialize as we start to generate a new segment.
-----------------------------------------------------------------------------------------------*/
-void EngineState::InitForNewSegment(GrTableManager * ptman)
-{
- // Set up a fresh batch of slots.
- DestroySlotBlocks();
- m_islotblkCurr = -1;
- m_islotNext = kSlotBlockSize;
-
- m_fInitialLB = false;
- m_fFinalLB = false;
- m_fInsertedLB = false;
- m_fExceededSpace = false;
- m_fHitHardBreak = false;
- m_fRemovedWhtsp = false;
- InitPosCache();
- //////m_pgg = pgg;
-
- for (int ipass = 0; ipass < m_cpass; ipass++)
- m_prgzpst[ipass].InitForNewSegment(ipass, ptman->Pass(ipass)->MaxRuleContext());
-}
-
-/*----------------------------------------------------------------------------------------------
- Calculate the position in stream zero of the given slot in the final stream,
- based on the associations. (This will be the same as the position at the end of the
- line-break passes, which is really what we want.)
-
- @param islotFinal - index of the final slot in the final stream
-----------------------------------------------------------------------------------------------*/
-int EngineState::TraceStreamZeroPos(int islotFinal, int nTopDir)
-{
- GrSlotStream * psstrmFinal = OutputStream(m_cpass - 1);
- if (psstrmFinal->WritePos() == 0)
- return -1;
-
- GrSlotState * pslot = psstrmFinal->SlotAt(islotFinal);
-
- // If we're in the middle of reordered bidi stuff, just use the end of the stream.
- if (pslot->DirLevel() > nTopDir)
- return -1;
-
- int islot = pslot->BeforeAssoc();
- if (islot == kPosInfinity || islot < 0)
- return -1;
- return islot + m_cslotPreSeg;
-}
-
-/*----------------------------------------------------------------------------------------------
- Return the next higher (more relaxed, less desirable) line break weight.
-----------------------------------------------------------------------------------------------*/
-LineBrk GrTableManager::IncLineBreak(LineBrk lb)
-{
- Assert(lb != klbClipBreak);
- return (LineBrk)((int)lb + 1);
-}
-
-/*----------------------------------------------------------------------------------------------
- Return a pointer to a slot that is near the current position in the given stream.
- Return NULL if no slots have been output at all.
- This is used for initializing features of line-break slots.
- @param ipassArg - pass at which to start looking
- @param islot - slot to look for; -1 if considering the current position
-----------------------------------------------------------------------------------------------*/
-GrSlotState * EngineState::AnAdjacentSlot(int ipassArg, int islot)
-{
- int ipass = ipassArg;
- while (ipass >= 0)
- {
- GrSlotStream * psstrm = OutputStream(ipass);
- if (psstrm->NumberOfSlots() > 0)
- {
- if (islot == -1)
- {
- if (psstrm->AtEnd())
- return psstrm->SlotAt(psstrm->WritePos() - 1);
- else
- return psstrm->Peek();
- }
- else
- {
- if (psstrm->WritePos() <= islot)
- return psstrm->SlotAt(psstrm->WritePos() - 1);
- else
- return psstrm->SlotAt(islot);
- }
- }
- ipass--;
- }
- return NULL;
-}
-
-/*----------------------------------------------------------------------------------------------
- Simple access methods.
-----------------------------------------------------------------------------------------------*/
-GrEngine * GrTableManager::Engine()
-{
- return m_pgreng;
-}
-
-EngineState * GrTableManager::State()
-{
- return &m_engst;
-}
-
-GrEngine * EngineState::Engine()
-{
- return m_ptman->Engine();
-}
-
-GrTableManager * EngineState::TableManager()
-{
- return m_ptman;
-}
-
-/*----------------------------------------------------------------------------------------------
- Memory management for slots
-----------------------------------------------------------------------------------------------*/
-
-// standard for pass 0 slots
-void EngineState::NewSlot(
- gid16 gID, GrFeatureValues fval, int ipass, int ichwSegOffset, int nUnicode,
- GrSlotState ** ppslotRet)
-{
- NextSlot(ppslotRet);
- (*ppslotRet)->Initialize(gID, Engine(), fval, ipass, ichwSegOffset, nUnicode);
-}
-
-// line-break slots
-void EngineState::NewSlot(
- gid16 gID, GrSlotState * pslotFeat, int ipass, int ichwSegOffset,
- GrSlotState ** ppslotRet)
-{
- NextSlot(ppslotRet);
- (*ppslotRet)->Initialize(gID, Engine(), pslotFeat, ipass, ichwSegOffset);
-}
-
-// for inserting new slots after pass 0 (under-pos and unicode are irrelevant)
-void EngineState::NewSlot(
- gid16 gID, GrSlotState * pslotFeat, int ipass,
- GrSlotState ** ppslotRet)
-{
- NextSlot(ppslotRet);
- (*ppslotRet)->Initialize(gID, Engine(), pslotFeat, ipass);
-}
-
-// for making a new version of the slot initialized from the old
-void EngineState::NewSlotCopy(GrSlotState * pslotCopyFrom, int ipass,
- GrSlotState ** ppslotRet)
-{
- NextSlot(ppslotRet);
- (*ppslotRet)->InitializeFrom(pslotCopyFrom, ipass);
-}
-
-void EngineState::NextSlot(GrSlotState ** ppslotRet)
-{
- int cnExtraPerSlot = m_cUserDefn + (m_cCompPerLig * 2) + m_cFeat;
- if (m_islotNext >= kSlotBlockSize)
- {
- // Allocate a new block of slots
- GrSlotState * slotblkNew = new GrSlotState[kSlotBlockSize];
- u_intslot * prgnSlotBuf = new u_intslot[kSlotBlockSize * cnExtraPerSlot];
-
- m_vslotblk.push_back(slotblkNew);
- m_vprgnSlotVarLenBufs.push_back(prgnSlotBuf);
- m_islotblkCurr++;
- m_islotNext = 0;
- Assert((unsigned)m_islotblkCurr == m_vslotblk.size()-1);
- }
-
- *ppslotRet = m_vslotblk[m_islotblkCurr] + m_islotNext;
- (*ppslotRet)->BasicInitialize(m_cUserDefn, m_cCompPerLig, m_cFeat,
- (m_vprgnSlotVarLenBufs[m_islotblkCurr] + (m_islotNext * cnExtraPerSlot)));
- m_islotNext++;
-}
-
-/*----------------------------------------------------------------------------------------------
- Convert the number of font design units into source device logical units.
-----------------------------------------------------------------------------------------------*/
-float GrTableManager::EmToLogUnits(int m)
-{
- return m_engst.EmToLogUnits(m);
-}
-
-float EngineState::EmToLogUnits(int m)
-{
- if (m == 0)
- return 0;
-
- float xysFontEmSquare;
- m_pfont->getFontMetrics(NULL, NULL, &xysFontEmSquare);
-
- // mEmUnits should be equal to the design units in the font's em square
- int mEmUnits = Engine()->GetFontEmUnits();
- if (mEmUnits <= 0)
- {
- Warn("Failed to obtain font em-units");
- return (float)m;
- }
-
- return GrEngine::GrIFIMulDiv(m, xysFontEmSquare, mEmUnits);
-}
-
-/*----------------------------------------------------------------------------------------------
- Convert the source device coordinates to font design units.
-----------------------------------------------------------------------------------------------*/
-int GrTableManager::LogToEmUnits(float xys)
-{
- return m_engst.LogToEmUnits(xys);
-}
-
-int EngineState::LogToEmUnits(float xys)
-{
- if (xys == 0)
- return 0;
-
- float xysFontEmSquare;
- m_pfont->getFontMetrics(NULL, NULL, &xysFontEmSquare);
-
- // mEmUnits should be equal to the design units in the font's em square
- int mEmUnits = Engine()->GetFontEmUnits();
- if (mEmUnits < 0)
- {
- Warn("Failed to obtain font em-units");
- return (int)xys;
- }
-
- return GrEngine::GrFIFMulDiv(xys, mEmUnits, xysFontEmSquare);
-}
-
-/*----------------------------------------------------------------------------------------------
- Find the coordinates for a given glyph point.
- Return true on success, false otherwise.
-----------------------------------------------------------------------------------------------*/
-bool GrTableManager::GPointToXY(gid16 chwGlyphID, int nGPoint, float * pxs, float * pys)
-{
- return m_engst.GPointToXY(chwGlyphID, nGPoint, pxs, pys);
-}
-
-bool EngineState::GPointToXY(gid16 chwGlyphID, int nGPoint, float * pxs, float * pys)
-{
- *pxs = INT_MIN;
- *pys = INT_MIN;
- Point pointRet;
- m_pfont->getGlyphPoint(chwGlyphID, nGPoint, pointRet);
- *pxs = pointRet.x;
- *pys = pointRet.y;
-
- return true;
-}
-
-/*----------------------------------------------------------------------------------------------
- Call the justification routines.
-----------------------------------------------------------------------------------------------*/
-void GrTableManager::CallJustifier(IGrJustifier * pgjus, int ipassCurr,
- float dxUnjustified, float dxJustified, bool fEndLine)
-{
- // Indicates the stream the justification routines will read and modify:
- m_engst.m_ipassJustCalled = ipassCurr;
-
- int iGlyphMin = OutputStream(ipassCurr)->SegMin();
- int iGlyphLim = OutputStream(ipassCurr)->SegLimIfKnown();
- if (iGlyphLim == -1)
- iGlyphLim = OutputStream(ipassCurr)->WritePos();
-
- GrSlotStream * psstrm = OutputStream(ipassCurr);
- if (m_pgreng->BasicJustification() && fEndLine)
- UnstretchTrailingWs(psstrm, iGlyphLim);
-
- pgjus->adjustGlyphWidths(m_pgreng, iGlyphMin, iGlyphLim, dxUnjustified, dxJustified);
-
- // After returning, reading and modifying slot attributes is not permitted:
- m_engst.m_ipassJustCalled = -1;
-}
-
-/*----------------------------------------------------------------------------------------------
- For the basic justification approach, remove stretch from the trailing whitespace.
-----------------------------------------------------------------------------------------------*/
-void GrTableManager::UnstretchTrailingWs(GrSlotStream * psstrm, int iGlyphLim)
-{
- int islot = iGlyphLim - 1;
- while (islot >= 0)
- {
- GrSlotState * pslot = psstrm->SlotAt(islot);
- if (pslot->IsLineBreak(LBGlyphID()))
- { } // keep looking for the trailing space
- else if (pslot->IsSpace(this))
- pslot->SetJStretch(0); // TODO: do this at level 0
- else
- // something other than space--quit
- return;
- islot--;
- }
-}
-
-/*----------------------------------------------------------------------------------------------
- Determine how much shrink is permissible.
-
- This method is really used only for testing the shrink mechanism, since at this time
- we don't allow low-end justification to do any shrinking.
-----------------------------------------------------------------------------------------------*/
-void GrTableManager::DetermineShrink(IGrJustifier * pgjus, int ipassCurr)
-{
- if (m_engst.m_dxsShrinkPossible != GrSlotState::kNotYetSet)
- return;
-
- if (m_engst.m_jmodi != kjmodiCanShrink || pgjus == NULL)
- {
- m_engst.m_dxsShrinkPossible = 0;
- return;
- }
-
- if (ipassCurr != m_ipassJust1 - 1)
- return;
-
- GrSlotStream * psstrm = OutputStream(ipassCurr);
- if (!psstrm->FullyWritten())
- return;
-
- // Normally just answer 0. To test shrinking, turn on the code below.
- m_engst.m_dxsShrinkPossible = 0;
-
-#if TEST_SHRINK
- int mTotal = 0;
- int mShrink = 0;
- int islotLim = psstrm->SegLimIfKnown();
- if (islotLim == -1)
- islotLim = psstrm->WritePos();
- for ( ; islotLim >= 0; islotLim--)
- {
- // Trailing white space is not shrinkable.
- GrSlotState * pslot = psstrm->SlotAt(islotLim - 1);
- if (pslot->IsLineBreak(LBGlyphID()))
- continue;
- if (!pslot->IsSpace(this))
- break;
- }
- int islot;
- for (islot = psstrm->SegMin(); islot < islotLim; islot++)
- {
- GrSlotState * pslot = psstrm->SlotAt(islot);
- if (pslot->IsLineBreak(LBGlyphID()))
- continue;
- mTotal += pslot->AdvanceX(this);
- mShrink += pslot->JShrink();
- }
-
- // Say that we are allowed to shrink up to 10% of the width of the segment.
- mShrink = min(mShrink, mTotal/10);
- m_engst.m_dxsShrinkPossible = EmToLogUnits(mShrink);
-#endif // TEST_SHRINK
-}
-
-/*----------------------------------------------------------------------------------------------
- Return the attribute of the given slot, back to the justification routine. Return
- logical units.
-----------------------------------------------------------------------------------------------*/
-GrResult EngineState::GetGlyphAttrForJustification(int iGlyph, int jgat, int nLevel,
- float * pValueRet)
-{
- GrResult res;
- int valueRetInt = 0;
- switch(jgat)
- {
- case kjgatWeight:
- case kjgatStretchInSteps:
- case kjgatBreak:
- res = GetGlyphAttrForJustification(iGlyph, jgat, nLevel, &valueRetInt);
- *pValueRet = (float)valueRetInt;
- return res;
- default:
- break;
- }
-
- if (m_ipassJustCalled == -1)
- return kresUnexpected;
-
- if (nLevel != 1)
- return kresInvalidArg;
-
- GrSlotStream * psstrm = OutputStream(m_ipassJustCalled);
-
- if (iGlyph < -1 || iGlyph >= psstrm->WritePos())
- return kresInvalidArg;
-
- GrSlotState * pslot = psstrm->SlotAt(iGlyph);
-
- // bool fConvertUnits = true;
-
- switch(jgat)
- {
- case kjgatStretch:
- *pValueRet = EmToLogUnits(pslot->JStretch());
- break;
- case kjgatShrink:
- *pValueRet = EmToLogUnits(pslot->JShrink());
- break;
- case kjgatStep:
- *pValueRet = EmToLogUnits(pslot->JStep());
- break;
- default:
- return kresNotImpl;
- }
- return kresOk;
-}
-
-GrResult EngineState::GetGlyphAttrForJustification(int iGlyph, int jgat, int nLevel,
- int * pValueRet)
-{
- GrResult res;
- float valueRetFloat;
- switch(jgat)
- {
- case kjgatStretch:
- case kjgatShrink:
- case kjgatStep:
- res = GetGlyphAttrForJustification(iGlyph, jgat, nLevel, &valueRetFloat);
- *pValueRet = GrEngine::RoundFloat(valueRetFloat);
- return res;
- default:
- break;
- }
-
- if (m_ipassJustCalled == -1)
- return kresUnexpected;
-
- if (nLevel != 1)
- return kresInvalidArg;
-
- GrSlotStream * psstrm = OutputStream(m_ipassJustCalled);
-
- if (iGlyph < -1 || iGlyph >= psstrm->WritePos())
- return kresInvalidArg;
-
- GrSlotState * pslot = psstrm->SlotAt(iGlyph);
-
- int mStretch, mStep;
- //float xsStretch, xsStep;
-
- switch(jgat)
- {
- case kjgatWeight:
- *pValueRet = pslot->JWeight();
- break;
- case kjgatStretchInSteps:
- // ???? should this be calculated in terms of logical units??
- // Probably doesn't matter, since the logical units are floating point, so the
- // level of precision is about the same.
- mStretch = pslot->JStretch();
- mStep = pslot->JStep();
- if (mStep == 0)
- return kresUnexpected;
- *pValueRet = int(mStretch / mStep); // round down
- break;
- //case kjgatStretchInSteps:
- // xsStretch = EmToLogUnits(pslot->JStretch());
- // xsStep = EmToLogUnits(pslot->JStep());
- // if (xsStep == 0)
- // return kresUnexpected;
- // *pValueRet = int(xsStretch / xsStep); // round down
- // break;
- case kjgatBreak:
- *pValueRet = pslot->BreakWeight();
- break;
- default:
- return kresNotImpl;
- }
- return kresOk;
-}
-
-/*----------------------------------------------------------------------------------------------
- Set the attribute of the given slot, for the justification routine.
-----------------------------------------------------------------------------------------------*/
-GrResult EngineState::SetGlyphAttrForJustification(int iGlyph, int jgat, int nLevel,
- float value)
-{
- GrResult res;
- int valueInt;
- switch(jgat)
- {
- case kjgatWeight:
- case kjgatStretchInSteps:
- case kjgatBreak:
- valueInt = (int)value;
- res = SetGlyphAttrForJustification(iGlyph, jgat, nLevel, valueInt);
- return res;
- default:
- break;
- }
-
- if (m_ipassJustCalled == -1)
- return kresUnexpected;
-
- if (nLevel != 1)
- return kresInvalidArg;
-
- GrSlotStream * psstrm = OutputStream(m_ipassJustCalled);
-
- if (iGlyph < -1 || iGlyph >= psstrm->WritePos())
- return kresInvalidArg;
-
- GrSlotState * pslot = psstrm->SlotAt(iGlyph);
-
- int mValue = LogToEmUnits(value);
- mValue = min(mValue, 0xFFFF); // truncate to an unsigned short
-
- // Review: do we really want to allow them to set stretch/shrink/step/weight? The normal
- // thing for them to do is set width.
- switch(jgat)
- {
- case kjgatStretch:
- pslot->SetJStretch(mValue);
- break;
- case kjgatShrink:
- pslot->SetJShrink(mValue);
- break;
- case kjgatStep:
- pslot->SetJStep(mValue);
- break;
- case kjgatWidth:
- pslot->SetJWidth(mValue);
- break;
- default:
- return kresNotImpl;
- }
- return kresOk;
-}
-
-GrResult EngineState::SetGlyphAttrForJustification(int iGlyph, int jgat, int nLevel,
- int value)
-{
- GrResult res;
- float valueFloat;
- switch(jgat)
- {
- case kjgatStretch:
- case kjgatShrink:
- case kjgatStep:
- case kjgatWidth:
- valueFloat = (float)value;
- res = SetGlyphAttrForJustification(iGlyph, jgat, nLevel, valueFloat);
- return res;
- default:
- break;
- }
-
- if (m_ipassJustCalled == -1)
- return kresUnexpected;
-
- if (nLevel != 1)
- return kresInvalidArg;
-
- GrSlotStream * psstrm = OutputStream(m_ipassJustCalled);
-
- if (iGlyph < -1 || iGlyph >= psstrm->WritePos())
- return kresInvalidArg;
-
- GrSlotState * pslot = psstrm->SlotAt(iGlyph);
-
- int mValue, cSteps;
- switch(jgat)
- {
- case kjgatWeight:
- pslot->SetJWeight(value);
- break;
- case kjgatWidthInSteps:
- cSteps = value;
- mValue = pslot->JStep();
- if (mValue == 0)
- return kresUnexpected;
- pslot->SetJWidth(mValue * cSteps);
- break;
- default:
- return kresNotImpl;
- }
- return kresOk;
-}
-
-//:>--------------------------------------------------------------------------------------------
-//:> Functions to forward to the engine.
-//:>------------------------------------------------------------------------------------------*/
-gid16 GrTableManager::GetGlyphIDFromUnicode(int nUnicode)
-{
- return m_pgreng->GetGlyphIDFromUnicode(nUnicode);
-}
-
-/*--------------------------------------------------------------------------------------------*/
-
-gid16 GrTableManager::ActualGlyphForOutput(utf16 chw)
-{
- return m_pgreng->ActualGlyphForOutput(chw);
-}
-
-/*--------------------------------------------------------------------------------------------*/
-
-GrGlyphTable * GrTableManager::GlyphTable()
-{
- return m_pgreng->GlyphTable();
-}
-
-/*--------------------------------------------------------------------------------------------*/
-
-gid16 GrTableManager::LBGlyphID()
-{
- return m_pgreng->LBGlyphID();
-}
-
-/*--------------------------------------------------------------------------------------------*/
-
-gid16 GrTableManager::GetClassGlyphIDAt(int nClass, int nIndex)
-{
- return m_pgreng->GetClassGlyphIDAt(nClass, nIndex);
-}
-
-/*--------------------------------------------------------------------------------------------*/
-
-int GrTableManager::GetIndexInGlyphClass(int nClass, gid16 chwGlyphID)
-{
- return m_pgreng->GetIndexInGlyphClass(nClass, chwGlyphID);
-}
-
-/*--------------------------------------------------------------------------------------------*/
-
-size_t GrTableManager::NumberOfGlyphsInClass(int nClass)
-{
- return m_pgreng->NumberOfGlyphsInClass(nClass);
-}
-
-/*--------------------------------------------------------------------------------------------*/
-
-void GrTableManager::SetSlotAttrsFromGlyphAttrs(GrSlotState * pslot)
-{
- m_pgreng->SetSlotAttrsFromGlyphAttrs(pslot);
-}
-
-/*--------------------------------------------------------------------------------------------*/
-
-int GrTableManager::NumFeat()
-{
- return m_pgreng->NumFeat();
-}
-
-/*--------------------------------------------------------------------------------------------*/
-
-int GrTableManager::DefaultForFeatureAt(int ifeat)
-{
- return m_pgreng->DefaultForFeatureAt(ifeat);
-}
-
-/*--------------------------------------------------------------------------------------------*/
-
-void GrTableManager::DefaultsForLanguage(isocode lgcode,
- std::vector<featid> & vnFeats, std::vector<int> & vnValues)
-{
- return m_pgreng->DefaultsForLanguage(lgcode, vnFeats, vnValues);
-}
-
-/*--------------------------------------------------------------------------------------------*/
-
-GrFeature * GrTableManager::FeatureWithID(featid nID, int * pifeat)
-{
- return m_pgreng->FeatureWithID(nID, pifeat);
-}
-
-/*--------------------------------------------------------------------------------------------*/
-
-GrFeature * GrTableManager::Feature(int ifeat)
-{
- return m_pgreng->Feature(ifeat);
-}
-
-/*--------------------------------------------------------------------------------------------*/
-
-bool GrTableManager::RightToLeft()
-{
- if (m_engst.WhiteSpaceOnly())
- return m_engst.m_fParaRtl;
- else
- return m_pgreng->RightToLeft();
-}
-
-/*--------------------------------------------------------------------------------------------*/
-
-int GrTableManager::TopDirectionLevel()
-{
- return m_pgreng->TopDirectionLevel();
-}
-
-/*--------------------------------------------------------------------------------------------*/
-
-float GrTableManager::VerticalOffset()
-{
- return m_pgreng->VerticalOffset();
-}
-
-/*--------------------------------------------------------------------------------------------*/
-
-int GrTableManager::NumUserDefn()
-{
- return m_pgreng->NumUserDefn();
-}
-
-/*--------------------------------------------------------------------------------------------*/
-
-int GrTableManager::NumCompPerLig()
-{
- return m_pgreng->NumCompPerLig();
-}
-
-/*--------------------------------------------------------------------------------------------*/
-
-int GrTableManager::ComponentIndexForGlyph(gid16 chwGlyphID, int nCompID)
-{
- return m_pgreng->ComponentIndexForGlyph(chwGlyphID, nCompID);
-}
-
-/*--------------------------------------------------------------------------------------------*/
-
-int GrTableManager::GlyphAttrValue(gid16 chwGlyphID, int nAttrID)
-{
- return m_pgreng->GlyphAttrValue(chwGlyphID, nAttrID);
-}
-
-/*--------------------------------------------------------------------------------------------*/
-
-bool GrTableManager::LoggingTransduction()
-{
- return m_fLogging;
- //return m_pgreng->LoggingTransduction();
-}
-
-/*----------------------------------------------------------------------------------------------
- Calculate the positions of the glyphs up to the given slot, within the output of the given
- pass. If the slot is NULL, go all the way to the end of what has been generated.
-
- @param ipass - index of pass needing positioning; normally this will be the
- final pass, but it could be another if positions are
- requested by the rules themselves
- @param pslotLast - last slot that needs to be positioned, or NULL
- @param pxsWidth - return the total width used so far
- @param psxVisibleWidth - return the visible width so far
-
- MOVE to EngineState
-----------------------------------------------------------------------------------------------*/
-void GrTableManager::CalcPositionsUpTo(int ipass, GrSlotState * pslotLast,
- float * pxsWidth, float * pxsVisibleWidth)
-{
- Assert(ipass >= m_ipassPos1 - 1);
-
- int isstrm = ipass;
- GrSlotStream * psstrm = OutputStream(isstrm);
- Assert(psstrm->GotIndexOffset());
- if (psstrm->WritePos() <= psstrm->IndexOffset())
- {
- Assert(psstrm->WritePos() == 0);
- *pxsWidth = 0;
- *pxsVisibleWidth = 0;
- return;
- }
- if (!pslotLast)
- {
- pslotLast = psstrm->SlotAt(psstrm->WritePos() - 1);
- }
- Assert(pslotLast);
-
- // First set positions of all base slots.
-
- int islot = psstrm->IndexOffset();
- GrSlotState * pslot;
- float xs = 0;
- float ys = VerticalOffset();
- *pxsWidth = 0;
- *pxsVisibleWidth = 0;
-
- bool fLast = false;
- bool fLastBase = false;
-
- bool fFakeItalic = m_pgreng->FakeItalic();
- float fakeItalicRatio = 0;
- if (fFakeItalic)
- fakeItalicRatio = State()->GetFont()->fakeItalicRatio();
- bool fBasicJust = m_pgreng->BasicJustification();
-
- // Figure out how to know when to stop.
- // We need to calculate up to the base of the last leaf slot, if it happens
- // to be later in the stream than the last actual slot passed in.
- if (!psstrm->HasSlotAtPosPassIndex(pslotLast->AttachRootPosPassIndex()))
- return;
- GrSlotState * pslotLastBase = pslotLast->Base(psstrm);
-
- if (ipass == m_cpass - 1 && m_engst.m_islotPosNext > -1)
- {
- // For final pass, initialize from cache of previous calculations.
- islot = m_engst.m_islotPosNext;
- xs = m_engst.m_xsPosXNext;
- ys = m_engst.m_ysPosYNext;
- *pxsWidth = m_engst.m_dxsTotWidthSoFar;
- *pxsVisibleWidth = m_engst.m_dxsVisWidthSoFar;
-
- if (psstrm->SlotsPresent() <= islot)
- return;
-
- if (pslotLastBase->PosPassIndex() == GrSlotAbstract::kNotYetSet)
- {
- Assert(false); // I think this case is handled above
- return; // can't position this slot yet; its base has not been processed
- }
-
- if (pslotLastBase->PosPassIndex() + psstrm->IndexOffset() < islot)
- {
- fLastBase = true;
- if (pslotLast == pslotLastBase)
- fLast = true;
- }
- }
-
- std::vector<GrSlotState *> vpslotAttached;
-
- bool fRtl = RightToLeft();
-
- while (!fLast || !fLastBase)
- {
- Assert(islot < psstrm->SlotsPresent());
-
- pslot = (isstrm == ipass) ? psstrm->SlotAt(islot) : psstrm->OutputSlotAt(islot);
-
- if (!pslot->IsBase())
- {
- // This slot is attached to another; it will be positioned strictly
- // relative to that one. This happens in the loop below.
- vpslotAttached.push_back(pslot);
- }
- else
- {
- // Base character.
-
- bool fLB = pslot->IsLineBreak(LBGlyphID());
- if (InternalJustificationMode() == kjmodiJustify && fBasicJust
- && ipass == m_cpass - 1 && !fLB)
- {
- m_engst.AddJWidthToAdvance(psstrm, &pslot, islot, &pslotLast, &pslotLastBase);
- }
-
- // Make sure the metrics are the complete ones.
- pslot->CalcCompositeMetrics(this, psstrm, kPosInfinity, true);
-
- float xsInc = pslot->GlyphXOffset(psstrm, fakeItalicRatio);
- float ysInc = pslot->GlyphYOffset(psstrm);
- float xsAdvX = pslot->ClusterAdvWidth(psstrm);
- float ysAdvY = (fLB) ?
- 0 :
- EmToLogUnits(pslot->AdvanceY(this));
-
- if (fRtl)
- {
- xs -= xsAdvX;
- ys -= ysAdvY;
- pslot->SetXPos(xs + xsInc);
- pslot->SetYPos(ys + ysInc);
- }
- else
- {
- pslot->SetXPos(xs + xsInc);
- pslot->SetYPos(ys + ysInc);
- xs += xsAdvX;
- ys += ysAdvY;
- }
-
- *pxsWidth = max(*pxsWidth, fabsf(xs));
- if (!IsWhiteSpace(pslot))
- *pxsVisibleWidth = *pxsWidth;
-
- if (isstrm == m_cpass - 1)
- {
- // For the final output pass, cache the results of the calculation so far.
- // Only do this for slots that have actually been processed by the final
- // pass, because others may have intermediate values that may be changed
- // later.
- m_engst.m_islotPosNext = pslot->PosPassIndex() + psstrm->IndexOffset() + 1;
- m_engst.m_xsPosXNext = xs;
- m_engst.m_ysPosYNext = ys;
- m_engst.m_dxsTotWidthSoFar = *pxsWidth;
- m_engst.m_dxsVisWidthSoFar = *pxsVisibleWidth;
- }
- }
-
- // Need to have calculated both the last leaf and the last base (if they happen to
- // be different); if so, we're done.
- if (pslot == pslotLast)
- fLast = true;
- if (pslot == pslotLastBase)
- fLastBase = true;
-
- islot++;
- }
-
- Assert(fLast);
- Assert(fLastBase);
-
- // Now set positions of non-base slots, relative to their bases.
-
- for (size_t ipslot = 0; ipslot < vpslotAttached.size(); ipslot++)
- {
- GrSlotState * pslot = vpslotAttached[ipslot];
- GrSlotState * pslotBase = pslot->Base(psstrm);
- if (pslotBase->XPosition() == kNegInfinity || pslotBase->YPosition() == kNegInfinity)
- {
- Assert(false);
- continue;
- }
- float xsCluster = pslotBase->XPosition() - pslotBase->GlyphXOffset(psstrm, fakeItalicRatio);
- float ysCluster = pslotBase->YPosition() - pslotBase->GlyphYOffset(psstrm);
- float xsInc = pslot->GlyphXOffset(psstrm, fakeItalicRatio);
- float ysInc = pslot->GlyphYOffset(psstrm);
- pslot->SetXPos(xsCluster + xsInc);
- pslot->SetYPos(ysCluster + ysInc);
-
- // My theory is that we don't need to adjust *pxsWidth here, because the width of
- // any non-base slots should be factored into the advance width of their cluster
- // base, which was handled above.
- }
-}
-
-/*----------------------------------------------------------------------------------------------
- Return true if the given slot is white space.
-----------------------------------------------------------------------------------------------*/
-bool GrTableManager::IsWhiteSpace(GrSlotState * pslot)
-{
- if (pslot->IsLineBreak(LBGlyphID()))
- return true;
- return pslot->IsSpace(this);
-}
-
-/*----------------------------------------------------------------------------------------------
- When doing basic justification, apply the value of justify.width to the advance width.
- This happens during the final positioning routine.
-----------------------------------------------------------------------------------------------*/
-void EngineState::AddJWidthToAdvance(GrSlotStream * psstrm, GrSlotState ** ppslot, int islot,
- GrSlotState ** ppslotLast, GrSlotState ** ppslotLastBase)
-{
- Assert(psstrm->OutputOfPass() == m_cpass - 1); // only used for final stream
- if ((*ppslot)->JWidth() > 0)
- {
- if ((*ppslot)->PassModified() != m_cpass - 1)
- {
- // Replace the slot with a new slot, so it gets marked properly with the
- // pass in which it was modified. (Otherwise the debug log gets screwed up.)
- GrSlotState * pslotNew;
- NewSlotCopy((*ppslot), m_cpass - 1, &pslotNew);
- psstrm->PutSlotAt(pslotNew, islot);
- if (*ppslot == *ppslotLast)
- *ppslotLast = pslotNew;
- if (*ppslot == *ppslotLastBase)
- *ppslotLastBase = pslotNew;
- *ppslot = pslotNew;
- }
- (*ppslot)->AddJWidthToAdvance(TableManager());
- }
-}
-
-
-//:>********************************************************************************************
-//:> Debuggers and utilities
-//:>********************************************************************************************
-
-//:Ignore
-#if 0
-void GrTableManager::TempDebug()
-{
- for (int ipass = 0; ipass < m_cpass; ++ipass)
- {
- int wpos = OutputStream(ipass)->WritePos();
- int rpos = OutputStream(ipass)->ReadPos();
- GrSlotState * wslot = OutputStream(ipass)->LastSlotWritten();
- GrSlotState * rslot = OutputStream(ipass)->LastSlotRead();
-
- }
-}
-#endif
-/*----------------------------------------------------------------------------------------------
- Given a character index in the original string, locate the corresponding line-break slot
- in the final surface stream. The character index must be one before which there is a
- line-break (seg lim), or the beginning or the end of the string.
- TODO SharonC: fix the bugs
-----------------------------------------------------------------------------------------------*/
-int GrTableManager::SurfaceLineBreakSlot(int ichw, GrCharStream * pchstrm, bool fInitial)
-{
- if (ichw == 0)
- {
- Assert(fInitial);
- return -1; // no initial line break
- }
- if (ichw == pchstrm->Lim())
- {
- Assert(!fInitial);
- return -1; // no terminating line break
- }
-
- int islotIn = pchstrm->SegOffset(ichw);
- Assert(islotIn >= 0);
- islotIn += (fInitial? m_engst.m_cslotPreSeg - 1: m_engst.m_cslotPreSeg);
-
- gid16 chwLBGlyphID = LBGlyphID();
-
- // Now islotIn is the position in stream 0;
-
- for (int ipass = 1; ipass < m_cpass; ++ipass)
- {
- int islotChunkMin;
- int islotChunkLim;
- GrSlotStream * psstrmOut = OutputStream(ipass);
-
- GrSlotStream * psstrmIn = InputStream(ipass);
- if (fInitial)
- islotIn = max(islotIn, psstrmIn->PreChunk());
- int islotT = psstrmIn->ChunkInNextMin(islotIn);
- islotChunkMin = psstrmIn->ChunkInNext(islotT);
- islotChunkMin = (islotChunkMin == -1)? 0: islotChunkMin;
-
- islotT = psstrmIn->ChunkInNextLim(islotIn);
- Assert(islotT <= psstrmIn->ReadPos());
- if (islotT == psstrmIn->ReadPos())
- islotChunkLim = psstrmOut->WritePos();
- else
- islotChunkLim = psstrmIn->ChunkInNext(islotT);
-
- int islotOut;
- for (islotOut = islotChunkMin; islotOut < islotChunkLim; ++islotOut)
- {
- gid16 chw = psstrmOut->GlyphIDAt(islotOut);
- if (chw == chwLBGlyphID)
- break;
- }
- Assert(psstrmOut->GlyphIDAt(islotOut) == chwLBGlyphID);
-
- islotIn = islotOut;
- }
- return islotIn;
-}
-
-/*----------------------------------------------------------------------------------------------
- Generate a debugger string showing the chunk boundaries for the given stream.
-----------------------------------------------------------------------------------------------*/
-std::wstring GrTableManager::ChunkDebugString(int ipass)
-{
- GrSlotStream * psstrm = OutputStream(ipass);
- std::wstring stuRet;
- //utf16 chwN = '\\';
- //utf16 chwR = '^';
-
- gid16 chwLBGlyphID = LBGlyphID();
-
- for (int islot = 0; islot < psstrm->WritePos(); islot++)
- {
- if (psstrm->ChunkInPrev(islot) != -1)
- {
- if (psstrm->ChunkInNext(islot) != -1)
- stuRet.append(L">");
- else
- stuRet.append(L"\\");
- }
- else if (psstrm->ChunkInNext(islot) != -1)
- stuRet.append(L"/");
- else
- stuRet.append(L" ");
-
-// if (islot == psstrm->ReadPos())
-// stuRet.Append(&chwR, 1);
-
- wchar_t chw = psstrm->SlotAt(islot)->GlyphID();
- if (chw == chwLBGlyphID)
- stuRet.append(L"#");
- else
- stuRet.append(&chw, 1);
- }
- return stuRet;
-}
-
-} // namespace gr
-
-//:End Ignore