summaryrefslogtreecommitdiff
path: root/Build/source/libs/graphite/src/segment/GrSlotStream.h
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/graphite/src/segment/GrSlotStream.h')
-rw-r--r--Build/source/libs/graphite/src/segment/GrSlotStream.h577
1 files changed, 577 insertions, 0 deletions
diff --git a/Build/source/libs/graphite/src/segment/GrSlotStream.h b/Build/source/libs/graphite/src/segment/GrSlotStream.h
new file mode 100644
index 00000000000..006191252dc
--- /dev/null
+++ b/Build/source/libs/graphite/src/segment/GrSlotStream.h
@@ -0,0 +1,577 @@
+/*--------------------------------------------------------------------*//*: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: GrSlotStream.h
+Responsibility: Sharon Correll
+Last reviewed: Not yet.
+
+Description:
+ Classes GrSlotStream and GrSlotState.
+----------------------------------------------------------------------------------------------*/
+#ifdef _MSC_VER
+#pragma once
+#endif
+#ifndef SLOTSTREAM_INCLUDED
+#define SLOTSTREAM_INCLUDED
+
+//:End Ignore
+
+namespace gr
+{
+
+class EngineState;
+class Font;
+
+/*----------------------------------------------------------------------------------------------
+ Each GrSlotStream represents the output of one pass, which also serves as the input
+ of the following pass. Hence it has two positions, a write position for when it is
+ serving as an output stream, and a read position for when it is serving as an input
+ stream. The TableManager holds a list of the streams.
+
+ The reading of slot streams is complicated by two factors. First, it may be necessary
+ to access the "pre-context" items of a rule, which are the slots before the current
+ stream position at the point when the rule is matched. These items will not be modified
+ by the rule, but may have been modified by a previous rule in the same pass, Therefore
+ we need to read these slots from the output stream, rather than the input stream,
+ because the output stream has the current slot attribute values that we want to work with.
+ In order make this happen, we keep track of the read and write positions of
+ the streams at the time the current rule was matched (m_islotRuleStartRead and
+ m_islotRuleStartWrite) and whenever we try to read a slot before m_islotRuleStartRead,
+ we read the corresponding slot from the output stream instead.
+
+ Second, a rule may explicitly set the advance position so that some items are
+ actually reprocessed (and potentially modified) by the same pass. When this happens,
+ we actually copy the slots to reprocess from the output stream back
+ into a temporary buffer (m_vpslotReproc) in the input stream, and set up the stream so
+ that the next read operations will read from the buffer.
+
+ It gets tricky because these two mechanisms can overlap with each other, so care
+ must be taken to read from the right place: the input stream in the normal way,
+ the reprocess buffer, or the output stream. See the RuleInputSlot method.
+
+ Another messy bit of code has to do with maintaining chunks. These are used for
+ backtracking and unwinding after inserting a line-break. Adjacent streams have maps
+ showing how many slots were processed by a single rule; the maps must be consisent
+ between adjacent rules. The following is an example of a pair of valid chunk maps:
+
+ Input stream Output stream
+ Pos next-map prev-map
+ 0 0 0
+ 1 -1 -1
+ 2 2 2
+ 3 4 -1
+ 4 -1 3
+ 5 -1 -1
+ 6 7 -1
+ 7 -1 6
+ 8 -1 -1
+
+ A -1 means that slot is not at the beginning of a chunk. Otherwise, there must be a
+ corresponding value in the parallel map of the adjacent stream--eg, the input stream's
+ next-map(3) == 4 and the output stream's prev-map(4) == 3. Assertions are run
+ regularly to ensure that the chunk maps stay valid.
+
+ So above, the first chunk corresponds to slots 0-1 in the input and 0-1 in the output;
+ two slots were processed by the rule. The second chunk corresponds to slot 2
+ in the input and slots 2-3 in the output (a slot was inserted).
+ The third corresponds to slots 3-5 in the input and 4-6 in the output (three slots
+ processed). The fourth chunk covers slots 6-8 in the input and 7-8 in the output
+ (one slot was deleted).
+
+ ENHANCE SharonC: explain the effect of skipped slots on the chunk maps.
+
+ Hungarian: sstrm
+----------------------------------------------------------------------------------------------*/
+class GrSlotStream {
+
+ friend class GrSlotState;
+ friend class FontMemoryUsage;
+
+public:
+ // Constructor:
+ GrSlotStream(int ipass)
+ {
+ m_ipass = ipass;
+ m_vpslot.clear();
+ m_vislotPrevChunkMap.clear();
+ m_vislotNextChunkMap.clear();
+ m_vpslotReproc.clear();
+ }
+
+ // Destructor:
+ ~GrSlotStream()
+ {
+ ReleaseSlots(0, m_vpslot.size());
+ }
+
+ void ReleaseSlots(int islotMin, int islotLim)
+ {
+ // A slot stream is responsible for deleting the slot states that it created,
+ // that is, the ones whose modified tag equals this stream's pass index.
+ // NO LONGER TRUE - there is a master list of them managed by the GrTableManager.
+// for (int islot = islotMin; islot < islotLim; ++islot)
+// {
+// if (m_vpslot[islot]->m_ipassModified == m_ipass)
+// delete m_vpslot[islot];
+// }
+ }
+
+ // Getters:
+ int WritePos() { return m_islotWritePos; }
+ int ReadPos() { return m_islotReadPos; }
+ bool FullyWritten() { return m_fFullyWritten; }
+
+ int SlotsPresent() { return m_vpslot.size(); }
+
+ // Setters:
+ void SetWritePos(int islot)
+ {
+ m_islotWritePos = islot;
+ }
+ void SetReadPos(int islot)
+ {
+ m_islotReadPos = islot;
+ }
+
+ void Initialize(int ipassPos1, bool fAnythingPrevious)
+ {
+ m_islotWritePos = 0;
+ m_islotReadPos = 0;
+ m_islotReprocPos = -1;
+ m_islotReprocLim = -1;
+ m_islotRuleStartRead = 0;
+ m_islotRuleStartWrite = 0;
+ m_islotReadPosMax = 0;
+ m_cslotSkippedForResync = 0;
+ m_cslotPreSeg = (fAnythingPrevious) ? -1 : 0;
+ m_fFullyWritten = false;
+ m_islotSegMin = -1;
+ m_islotSegLim = -1;
+ m_fUsedByPosPass = (m_ipass + 1 >= ipassPos1);
+ m_fInputToPosPass1 = (m_ipass + 1 == ipassPos1);
+ m_vpslot.clear(); // not responsible for destroying the slots
+ m_vislotPrevChunkMap.clear();
+ m_vislotNextChunkMap.clear();
+ }
+
+public:
+ bool AtEnd();
+ bool AtEndOfContext();
+ void NextPut(GrSlotState* pslot);
+ GrSlotState * NextGet();
+ GrSlotState * Peek(int dislot = 0);
+ GrSlotState * PeekBack(int dislot, bool fNullOkay = false);
+ void Skip(int = 1);
+ GrSlotState * SlotAt(int islot)
+ {
+ return m_vpslot[islot];
+ }
+
+ int OutputOfPass()
+ {
+ return m_ipass;
+ }
+
+ // This function is intended to be used within positioning passes where there is a
+ // one-to-one correspondence beween the slots in consecutive streams.
+ GrSlotState * OutputSlotAt(int islot)
+ {
+ return Peek(islot - ReadPosForNextGet());
+ }
+
+ int ReadPosForNextGet()
+ {
+ return ReadPos() - SlotsToReprocess();
+ }
+
+ // Only valid for streams that are the input or output to a positioning pass.
+ GrSlotState * SlotAtPosPassIndex(int islot)
+ {
+ Assert(GotIndexOffset());
+ Assert(m_fUsedByPosPass);
+ return m_vpslot[islot + m_cslotPreSeg];
+ }
+
+ // Only valid for streams that are the input or output to a positioning pass.
+ bool HasSlotAtPosPassIndex(int islot)
+ {
+ Assert(GotIndexOffset());
+ Assert(m_fUsedByPosPass);
+ return (signed(m_vpslot.size()) > (islot + m_cslotPreSeg));
+ }
+
+ bool AssertValid();
+ void AssertChunkMapsValid(GrSlotStream * psstrmOut);
+ void AssertStreamIndicesValid(GrSlotStream * psstrmIn);
+ void AssertAttachmentsInOutput(int islotMin, int islotLim);
+ bool NoReproc()
+ {
+ return (m_islotReprocPos == -1 || (m_islotReprocPos >= signed(m_vpslotReproc.size())));
+ }
+
+ int SlotsPending();
+ int SlotsPendingInContext();
+ int TotalSlotsPending();
+ bool PastEndOfPositioning(bool fOutput);
+
+ void ClearReprocBuffer()
+ {
+ m_islotReprocPos = -1;
+ m_islotReprocLim = -1;
+ m_vpslotReproc.clear();
+ }
+
+ int ReprocLim()
+ {
+ return m_islotReprocLim;
+ }
+
+ int ReprocMin()
+ {
+ Assert(m_islotReprocPos > -1);
+ return m_islotReprocLim - m_vpslot.size();
+ }
+
+ int RuleStartReadPos()
+ {
+ return m_islotRuleStartRead;
+ }
+
+ void SetRuleStartReadPos()
+ {
+ if (m_islotReprocPos > -1)
+ m_islotRuleStartRead = m_islotReprocLim - SlotsToReprocess();
+ else
+ m_islotRuleStartRead = m_islotReadPos;
+ }
+
+ int RuleStartWritePos()
+ {
+ return m_islotRuleStartWrite;
+ }
+
+ void SetRuleStartWritePos()
+ {
+ m_islotRuleStartWrite = m_islotWritePos;
+ }
+
+ void MarkFullyWritten();
+
+ void SetSegMin(int islot, bool fAdjusting = false)
+ {
+ Assert(fAdjusting || m_islotSegMin == -1 || m_islotSegMin == islot);
+ m_islotSegMin = islot;
+ }
+ void SetSegMinToWritePos(bool fMod = true)
+ {
+ if (m_islotSegMin == -1)
+ m_islotSegMin = m_islotWritePos;
+ else
+ Assert(m_islotSegMin <= m_islotWritePos); // eg, already set to before the initial LB
+ }
+ int SegMin()
+ {
+ return m_islotSegMin;
+ }
+ void SetSegLim(int islot)
+ {
+ m_islotSegLim = islot;
+ }
+ void SetSegLimToWritePos(bool fMod = true)
+ {
+ if (m_islotSegLim > -1 && !fMod)
+ {
+ Assert(m_islotSegLim <= m_islotWritePos);
+ return;
+ }
+ m_islotSegLim = m_islotWritePos;
+ }
+ int SegLimIfKnown()
+ {
+ return m_islotSegLim;
+ }
+ int FinalSegLim()
+ {
+ if (m_islotSegLim > -1)
+ return m_islotSegLim;
+ else
+ return m_islotWritePos;
+ }
+
+ // Return true if we are exactly at the segment min.
+ bool AtSegMin()
+ {
+ if (m_islotSegMin == -1)
+ return false;
+ return (m_islotSegMin == ReadPosForNextGet());
+ }
+
+ // Return true if we are exactly at the segment lim.
+ bool AtSegLim()
+ {
+ if (m_islotSegLim == -1)
+ return false;
+ return (m_islotSegLim == ReadPosForNextGet());
+ }
+
+ int ReadPosMax()
+ {
+ return m_islotReadPosMax;
+ }
+ void SetReadPosMax(int islot)
+ {
+ m_islotReadPosMax = std::max(m_islotReadPosMax, islot);
+ }
+
+ int OldDirLevelRange(EngineState * pengst, int islotStart, int nTopDirection);
+ int DirLevelRange(EngineState * pengst, int islotStart, int nTopDirection,
+ std::vector<int> & vislotStarts, std::vector<int> & vislotStops);
+ int GetSlotDirLevel(EngineState * pengst, int islot,
+ int nOuterLevel, int nCurrLevel, DirCode dircMarker, DirCode dircOverride);
+ DirCode AdjacentStrongCode(EngineState * pengst, int islot, int nInc,
+ DirCode dircPDF, bool fNumbersAreStrong = false);
+ DirCode TerminatorSequence(EngineState * pengst, int islot, int nInc, DirCode dircPDF);
+ DirCode AdjacentNonBndNeutralCode(EngineState * pengst, int islot, int nInc,
+ DirCode dircPDF);
+
+ void CopyOneSlotFrom(GrSlotStream * psstrmPrev);
+ void SimpleCopyFrom(GrSlotStream * psstrmI, int islotInput, int islotOutput);
+
+ bool MoreSpace(GrTableManager * ptman,
+ float xsSpaceAllotted, bool fWidthIsCharCount,
+ bool fIgnoreTrailingWS, TrWsHandling twsh,
+ float * pxsWidth);
+
+ int InsertLineBreak(GrTableManager * ptman,
+ int islotPrevBreak, bool fInsertedLB, int islotStartTry,
+ LineBrk lb, TrWsHandling twsh, int islotMin, LineBrk * plbNextToTry);
+ int MakeSegmentBreak(GrTableManager * ptman,
+ int islotPrevBreak, bool fInsertedLB, int islotStartTry,
+ LineBrk lb, TrWsHandling twsh, int islotMin, LineBrk * plbNextToTry);
+ bool FindSegmentEnd(GrTableManager * ptman,
+ int islotStartTry, LineBrk lb, TrWsHandling twsh, int islotMin,
+ int * pislot, int * pichwSegOffset,
+ LineBrk * plbFound, LineBrk * plbNextToTry);
+ bool HasEarlierBetterBreak(int islotBreak, LineBrk lbFound, gid16 chwLB);
+ LineBrk BreakWeightAt(gid16 chwLB, int islot);
+ void AppendLineBreak(GrTableManager *, GrCharStream * pchstrm,
+ LineBrk, DirCode dirc, int islot, bool fInitial, int ichwSegOffset);
+ int FindFinalLineBreak(gid16 chwLB, int islotMin, int islotLim);
+ void AdjustPrevStreamNextChunkMap(GrTableManager * ptman, int islotMod, int nInc);
+ void AdjustNextChunkMap(int islotMin, int islotMod, int nInc);
+
+ void EnsureLocalCopy(GrTableManager * ptman, GrSlotState * pslot, GrSlotStream * psstrmIn);
+ void ReplaceSlotInReprocessBuffer(GrSlotState * pslotOld, GrSlotState * pslotNew);
+
+ void ZapCalculatedDirLevels(int islotLB);
+
+ int MaxClusterSlot(int islotChunkLim)
+ {
+ return MaxClusterSlot(islotChunkLim - 1, islotChunkLim);
+ }
+ int MaxClusterSlot(int islotChunkMin, int islotChunkLim);
+
+ void UnwindInput( int islot, bool fPreBidiPass);
+ void UnwindOutput(int islot, bool fOutputOfPosPass);
+
+ void MapInputChunk( int islotIn, int islotOut, int islotInLim,
+ bool fReprocessing, bool fBackingUp);
+ void MapOutputChunk(int islotOut, int islotIn, int islotOutLim,
+ bool fReprocessing, int cslotReprocess, bool fBackingUp);
+
+ int LastNextChunkLength();
+
+ int ChunkInPrev(int i)
+ {
+ Assert(i >= 0);
+ Assert(i < signed(m_vislotPrevChunkMap.size()));
+ Assert(i < m_islotWritePos);
+ return m_vislotPrevChunkMap[i];
+ }
+ int ChunkInNext(int i)
+ {
+ Assert(i >= 0);
+ Assert(i < signed(m_vislotNextChunkMap.size()));
+ Assert(i < m_islotReadPos);
+ return m_vislotNextChunkMap[i];
+ }
+
+ int ChunkInNextMin(int islot);
+ int ChunkInNextLim(int islot);
+
+ void ResyncSkip(int nslot);
+ int SlotsSkippedToResync()
+ {
+ return m_cslotSkippedForResync;
+ }
+ void ClearSlotsSkippedToResync()
+ {
+ m_cslotSkippedForResync = 0;
+ }
+
+ int IndexOffset()
+ {
+ Assert(GotIndexOffset()); // should have been calculated
+ return m_cslotPreSeg;
+ }
+ void SetIndexOffset(int c)
+ {
+ m_cslotPreSeg = c;
+ }
+ bool GotIndexOffset()
+ {
+ return (m_cslotPreSeg >= 0);
+ }
+ void CalcIndexOffset(GrTableManager * ptman);
+
+ void SetPosForNextRule(int nslot, GrSlotStream * psstrmInput, bool fOutputOfPosPass);
+ void SetLBContextFlag(GrTableManager * ptman, int islotStart);
+ int SlotsToReprocess();
+
+ void SetNeutralAssociations(gid16 chwLB);
+protected:
+ GrSlotState * FindAssociatedSlot(int islot, int nInc, gid16 chwLB);
+
+ GrSlotState * GetSlotAt(int islot);
+
+public:
+ // Used by the action code:
+ void BackupReadPos(int cslot = 1)
+ {
+ for (int islot = 0; islot < cslot; islot++)
+ {
+ if (m_islotReprocLim > -1 && m_islotReprocLim == m_islotReadPos)
+ {
+ if (m_islotReprocPos == -1)
+ m_islotReprocPos = m_vpslotReproc.size() - 1;
+ else
+ --m_islotReprocPos;
+ Assert(m_islotReprocPos >= 0);
+ }
+ else
+ --m_islotReadPos;
+ }
+ }
+
+ GrSlotState * RuleInputSlot(int dislot = 0, GrSlotStream * psstrmOut = NULL,
+ bool fNullOkay = false);
+ GrSlotState * RuleOutputSlot(int dislot = 0);
+
+ void PutSlotAt(GrSlotState * pslot, int islot)
+ {
+ // Currently only used for the final pass, when applying justify.width to
+ // the advance width.
+ Assert(signed(m_vpslot.size()) > islot);
+ Assert(WritePos() > islot);
+ Assert(ReadPos() <= islot);
+ Assert(SlotsToReprocess() == 0);
+ m_vpslot[islot] = pslot;
+ }
+
+protected:
+ // Instance variables:
+ int m_ipass; // which pass this stream is serving as OUTPUT of
+
+ std::vector<GrSlotState*> m_vpslot; // the slots being processed
+
+ // Chunking information:
+ std::vector<int> m_vislotPrevChunkMap; // chunk mapping into previous stream;
+ // -1 if not at a chunk boundary
+ // (this information is needed for
+ // reinitialization after inserting a line break)
+
+ std::vector<int> m_vislotNextChunkMap; // chunk mapping into next stream, or -1
+ // (this information is needed for backtracking)
+
+ // Since most streams serve as both input and output, there are two positions.
+ // Note that readPos <= writePos always.
+ int m_islotWritePos; // where previous pass should put next output
+ int m_islotReadPos; // where following pass should start processing from
+
+ // When we are reprocessing some of the output from the next stream:
+ std::vector<GrSlotState*> m_vpslotReproc; // temporary buffer
+ int m_islotReprocLim; // the read position corresponding to the end of the reprocess
+ // buffer; -1 if buffer is invalid
+ int m_islotReprocPos; // index into m_vpslotReproc from where we should read next;
+ // -1 if we are not reprocessing
+
+ int m_islotRuleStartRead; // read position when the rule was started; any requests before
+ // this point should access the output stream, because it has
+ // the most up-to-date values.
+ int m_islotRuleStartWrite; // write position when the rule started
+
+ bool m_fFullyWritten; // set to true when we can't get any more from the
+ // previous pass; initially false.
+
+ int m_islotSegMin; // the official min of the segment; -1 if not yet set
+ int m_islotSegLim; // the official lim of the segment; -1 if not yet set
+ // (only set for the output of the final line-break pass
+ // and those beyond)
+
+ int m_cslotSkippedForResync; // number of slots skipped to resync;
+ // specifically, the number of slots' worth of the
+ // next-chunk-map that are invalid, not mapped
+ // to any slots in the following stream
+
+ int m_cslotPreSeg; // number of slots previous to the official beginning of the segment;
+ // -1 if we haven't figured it out yet. Used for keeping streams
+ // in the positioning pass in sync; not particularly useful for
+ // substitution passes, and will possibly be left uncalculated.
+
+ bool m_fUsedByPosPass; // true if this is input to or output from a positioning pass
+ bool m_fInputToPosPass1; // true if this is the input to the first positioning pass
+
+ // Max value of m_islotReadPos; used for recognizing infinite loops and forcibly
+ // advancing (see GrPass::CheckInputProgress).
+ int m_islotReadPosMax;
+
+public:
+ // For transduction logging:
+#ifdef TRACING
+// void LogSlotGlyphs(std::ofstream & strmOut, gid16 chwLB);
+#endif // TRACING
+
+ // For test procedures:
+ int NumberOfSlots() { return m_vpslot.size(); }
+ GrSlotState * LastSlotWritten()
+ {
+ if (m_islotWritePos == 0)
+ return NULL;
+ else
+ return m_vpslot[m_islotWritePos-1];
+ }
+ GrSlotState * LastSlotRead()
+ {
+ if (m_islotReadPos == 0)
+ return NULL;
+ else
+ return m_vpslot[m_islotReadPos-1];
+ }
+
+ gid16 GlyphIDAt(int islot)
+ {
+ return m_vpslot[islot]->m_chwGlyphID;
+ }
+
+ int PreChunk() // answer the number of prepended items that are not in any chunk;
+ // should be obsolete now
+ {
+ int islot;
+ for (islot = 0; islot < m_islotReadPos; ++islot)
+ {
+ if (m_vislotNextChunkMap[islot] != -1)
+ return islot;
+ }
+ Assert(false);
+ return islot;
+ }
+
+}; // end of class GrSlotStream
+
+} // namespace gr
+
+
+#endif // !SLOTSTREAM_INCLUDED