diff options
Diffstat (limited to 'Build/source/libs/graphite/src/segment/TransductionLog.cpp')
-rw-r--r-- | Build/source/libs/graphite/src/segment/TransductionLog.cpp | 2091 |
1 files changed, 2091 insertions, 0 deletions
diff --git a/Build/source/libs/graphite/src/segment/TransductionLog.cpp b/Build/source/libs/graphite/src/segment/TransductionLog.cpp new file mode 100644 index 00000000000..73273ae3feb --- /dev/null +++ b/Build/source/libs/graphite/src/segment/TransductionLog.cpp @@ -0,0 +1,2091 @@ +/*--------------------------------------------------------------------*//*:Ignore this sentence. +Copyright (C) 2000 - 2008 SIL International. All rights reserved. + +Distributable under the terms of either the Common Public License or the +GNU Lesser General Public License, as specified in the LICENSING.txt file. + +File: TransductionLog.cpp +Responsibility: Sharon Correll +Last reviewed: Not yet. + +Description: + Contains the functions for writing a log of the transduction process. +----------------------------------------------------------------------------------------------*/ + +//:>******************************************************************************************** +//:> Include files +//:>******************************************************************************************** +#include "Main.h" + +#ifdef _MSC_VER +#pragma hdrstop +#endif + +#include <math.h> + +#undef THIS_FILE +DEFINE_THIS_FILE + +//:End Ignore + +//:>******************************************************************************************** +//:> Forward declarations +//:>******************************************************************************************** + +//:>******************************************************************************************** +//:> Local Constants and static variables +//:>******************************************************************************************** + +namespace gr +{ + +//:>******************************************************************************************** +//:> Methods +//:>******************************************************************************************** + +#define SP_PER_SLOT 7 +#define LEADING_SP 15 +#define MAX_SLOTS 128 + +/*---------------------------------------------------------------------------------------------- + Output a file showing a log of the transduction process and the resulting segment. +----------------------------------------------------------------------------------------------*/ +//bool GrTableManager::WriteTransductionLog(GrCharStream * pchstrm, Segment * psegRet, +// int cbPrevSegDat, byte * pbPrevSegDat, byte * pbNextSegDat, int * pcbNextSegDat) +//{ +//#ifdef TRACING +// std::string staFile; +// if (!LogFileName(staFile)) +// return false; +// +// std::ofstream strmOut; +// if (cbPrevSegDat > 0) +// strmOut.open(staFile.c_str(), std::ios::app); // append +// else +// strmOut.open(staFile.c_str()); +// if (strmOut.fail()) +// return false; +// +// WriteXductnLog(strmOut, pchstrm, psegRet, cbPrevSegDat, pbPrevSegDat); +// +// strmOut.close(); +// return true; +//#else +// return false; +//#endif // TRACING +//} + +bool GrTableManager::WriteTransductionLog(std::ostream * pstrmLog, + GrCharStream * pchstrm, Segment * psegRet, int cbPrevSegDat, byte * pbPrevSegDat) +{ +#ifdef TRACING + if (!pstrmLog) + return false; + std::ostream & strmOut = *pstrmLog; + WriteXductnLog(strmOut, pchstrm, psegRet, cbPrevSegDat, pbPrevSegDat); + return true; +#else + return false; +#endif // TRACING +} + +/*---------------------------------------------------------------------------------------------- + Append to the file, showing the surface/underlying mappings. This must be done after + figuring out all the associations. + + Also write the final glyph positions, since they are now determined. +----------------------------------------------------------------------------------------------*/ +//bool GrTableManager::WriteAssociationLog(GrCharStream * pchstrm, Segment * psegRet) +//{ +//#ifdef TRACING +// std::string staFile; +// if (!LogFileName(staFile)) +// return false; +// +// std::ofstream strmOut; +// strmOut.open(staFile.c_str(), std::ios::app); // append +// if (strmOut.fail()) +// return false; +// +// LogFinalPositions(strmOut); +// +// strmOut << "\n\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n\n"; +// +// psegRet->LogUnderlyingToSurface(this, strmOut, pchstrm); +// psegRet->LogSurfaceToUnderlying(this, strmOut); +// +// strmOut << "\n\n=======================================================================\n\n"; +// +// strmOut.close(); +// return true; +//#else +// return false; +//#endif // TRACING +//} + + +bool GrTableManager::WriteAssociationLog(std::ostream * pstrmLog, + GrCharStream * pchstrm, Segment * psegRet) +{ +#ifdef TRACING + if (!pstrmLog) + return false; + + std::ostream & strmOut = *pstrmLog; + + psegRet->LogUnderlyingToSurface(this, strmOut, pchstrm); + psegRet->LogSurfaceToUnderlying(this, strmOut); + + strmOut << "\n\n=======================================================================\n\n"; + + return true; +#else + return false; +#endif // TRACING +} + +#ifdef TRACING + +/*---------------------------------------------------------------------------------------------- + Generate the name of the file where the log will be written. It goes in the directory + defined by either the TEMP or TMP environment variable. + + TODO: remove +----------------------------------------------------------------------------------------------*/ +//bool GrTableManager::LogFileName(std::string & staFile) +//{ +// char * pchTmpEnv = getenv("TEMP"); +// if (pchTmpEnv == 0) +// pchTmpEnv = getenv("TMP"); +// if (pchTmpEnv == 0) +// return false; +// +// staFile.assign(pchTmpEnv); +// if (staFile[staFile.size() - 1] != '\\') +// staFile.append("\\"); +// staFile.append("gr_xductn.log"); +// +// return true; +//} + +/*---------------------------------------------------------------------------------------------- + Output a file showing a log of the transduction process and the resulting segment. +----------------------------------------------------------------------------------------------*/ +void GrTableManager::WriteXductnLog(std::ostream & strmOut, + GrCharStream * pchstrm, Segment * psegRet, + int cbPrevSegDat, byte * pbPrevSegDat) +{ + if (cbPrevSegDat == 0) + LogUnderlying(strmOut, pchstrm, 0); + else + { + Assert(*(pbPrevSegDat + 4) == 0); // skip offset for first pass + LogUnderlying(strmOut, pchstrm, *(pbPrevSegDat + 3)); + } + + LogPass1Input(strmOut); + + for (int ipass = 1; ipass < m_cpass; ipass++) + { + if (cbPrevSegDat == 0) + LogPassOutput(strmOut, ipass, 0); + else + LogPassOutput(strmOut, ipass, *(pbPrevSegDat + 4 + ipass)); + } + + LogFinalPositions(strmOut); + + strmOut << "\n\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n\n"; +} + +/*---------------------------------------------------------------------------------------------- + Write out a log of the underlying input. +----------------------------------------------------------------------------------------------*/ +void GrTableManager::LogUnderlying(std::ostream & strmOut, GrCharStream * pchstrm, + int cchwBackup) +{ + strmOut << "UNDERLYING INPUT\n\n"; + + int rgnChars[MAX_SLOTS]; + bool rgfNewRun[MAX_SLOTS]; + std::fill_n(rgfNewRun, MAX_SLOTS, false); + GrFeatureValues rgfval[MAX_SLOTS]; + int cchwMaxRawChars; + + int cnUtf32 = pchstrm->GetLogData(this, rgnChars, rgfNewRun, rgfval, + cchwBackup, &cchwMaxRawChars); + cnUtf32 = min(cnUtf32, MAX_SLOTS); + + int ichw; + + // For UTF-8 and surrogate representation: + utf16 rgchwChars2[MAX_SLOTS]; + utf16 rgchwChars3[MAX_SLOTS]; + utf16 rgchwChars4[MAX_SLOTS]; + utf16 rgchwChars5[MAX_SLOTS]; + utf16 rgchwChars6[MAX_SLOTS]; + int rgcchwRaw[MAX_SLOTS]; + + if (cchwMaxRawChars > 1) + { + cchwMaxRawChars = min(cchwMaxRawChars, 6); // max of 6 raw (UTF-8 or UTF-16) chars per slot + pchstrm->GetLogDataRaw(this, cnUtf32, cchwBackup, cchwMaxRawChars, + rgnChars, rgchwChars2, rgchwChars3, rgchwChars4, rgchwChars5, rgchwChars6, + rgcchwRaw); + } + else + { + for (ichw = 0; ichw < cnUtf32; ichw++) + { + rgcchwRaw[ichw] = 1; + rgchwChars2[ichw] = 0; + rgchwChars3[ichw] = 0; + rgchwChars4[ichw] = 0; + rgchwChars5[ichw] = 0; + rgchwChars6[ichw] = 0; + } + } + + LogUnderlyingHeader(strmOut, pchstrm->Min(), (pchstrm->Min() + cnUtf32 - cchwBackup), + cchwBackup, rgcchwRaw); + + // Text + strmOut << "Text: "; // 15 spaces + for (ichw = 0; ichw < cnUtf32; ichw++) + { + if (rgnChars[ichw] < 0x0100 && rgchwChars2[ichw] == 0) // ANSI + strmOut << (char)rgnChars[ichw] << " "; // 6 spaces + else if (rgnChars[ichw] == knLRM) + strmOut << "<LRM> "; + else if (rgnChars[ichw] == knRLM) + strmOut << "<RLM> "; + else if (rgnChars[ichw] == knLRO) + strmOut << "<LRO> "; + else if (rgnChars[ichw] == knRLO) + strmOut << "<RLO> "; + else if (rgnChars[ichw] == knLRE) + strmOut << "<LRE> "; + else if (rgnChars[ichw] == knRLE) + strmOut << "<RLE> "; + else if (rgnChars[ichw] == knPDF) + strmOut << "<PDF> "; + else + strmOut << " "; + } + strmOut << "\n"; + + // Unicode + strmOut << "Unicode: "; + for (ichw = 0; ichw < cnUtf32; ichw++) + LogHexInTable(strmOut, utf16(rgnChars[ichw])); + strmOut << "\n"; + for (int icchRaw = 2; icchRaw <= cchwMaxRawChars; icchRaw++) + { + strmOut << " "; + for (ichw = 0; ichw < cnUtf32; ichw++) + { + utf16 chw; + switch (icchRaw) + { + case 2: chw = rgchwChars2[ichw]; break; + case 3: chw = rgchwChars3[ichw]; break; + case 4: chw = rgchwChars4[ichw]; break; + case 5: chw = rgchwChars5[ichw]; break; + case 6: chw = rgchwChars6[ichw]; break; + default: chw = 0; + } + if (chw == 0) + strmOut << " "; + else + LogHexInTable(strmOut, chw); + } + strmOut << "\n"; + } + + // Runs + strmOut << "Runs: "; + int crun = 0; + for (ichw = 0; ichw < cnUtf32; ichw++) + { + if (rgfNewRun[ichw]) + { + crun++; + strmOut << "|" << crun << ((crun < 10) ? " " : " "); + } + else + strmOut << " "; + } + strmOut << "\n"; + + // Features + strmOut << "Features and character properties:\n"; + crun = 0; + for (ichw = 0; ichw < cnUtf32; ichw++) + { + if (rgfNewRun[ichw]) + { + crun++; + strmOut << " Run " << crun << ": "; + rgfval[ichw].WriteXductnLog(this, strmOut); + + } + } +} + + +void GrFeatureValues::WriteXductnLog(GrTableManager * ptman, std::ostream & strmOut) +{ + bool fFirst = true; + for (int i = 0; i < kMaxFeatures; i++) + { + if (m_rgnFValues[i] != 0) + { + GrFeature * pfeat = ptman->Feature(i); + if (!fFirst) + strmOut << ","; + strmOut << pfeat->ID() << "=" << m_rgnFValues[i]; + fFirst = false; + } + } + if (fFirst) + strmOut << "all features=0"; + + strmOut << "\n\n"; +} + +/*---------------------------------------------------------------------------------------------- + Loop through the input stream of underlying characters, storing information in the + arrays for the log. + ENHANCE SharonC: do we need to show the underline properties? +----------------------------------------------------------------------------------------------*/ +int GrCharStream::GetLogData(GrTableManager * ptman, int * rgchl, bool * rgfNewRun, + GrFeatureValues * rgfval, int cchrBackup, int * pcchrMax) +{ + Assert(cchrBackup <= m_cchrBackedUp); + + int ichrPosToStop = m_ichrPos; + int ichrStart = m_ichrMin - max(cchrBackup, m_cchrBackedUp); + + *pcchrMax = 0; + + // Restart the stream. + m_ichrPos = ichrStart; + m_ichrRunMin = 0; + m_ichrRunLim = 0; + m_ichrRunOffset = kPosInfinity; + m_vislotNextChunkMap.clear(); + + int cchrSkipBackup = m_cchrBackedUp - cchrBackup; + + int c = 0; + int cchr = 0; + + while (m_ichrPos < ichrPosToStop) + { + if ((c < MAX_SLOTS) && (m_ichrPos >= m_ichrRunLim)) + { + rgfNewRun[c] = true; + } + + GrFeatureValues fval; + int ichrOffset, cchrThis; + int chl = NextGet(ptman, &fval, &ichrOffset, &cchrThis); + cchr += cchrThis; + if (cchr <= cchrSkipBackup) + {} // ignore - this is before the pre-segment stuff that we want to skip + else if (c < MAX_SLOTS) + { + rgchl[c] = chl; + *pcchrMax = max(*pcchrMax, cchrThis); + if (rgfNewRun[c]) + { + rgfval[c] = fval; + } + c++; + } + } + + ////return (m_ichwPos - (m_ichwMin - cchwBackup)); + return c; +} + +/*---------------------------------------------------------------------------------------------- + If any of the characters are comprised of surrogates or UTF-8, fill in the arrays with + the raw (UTF-16 or UTF-8) chars for display. To do this we get the raw characters + directly from the text source. +----------------------------------------------------------------------------------------------*/ +void GrCharStream::GetLogDataRaw(GrTableManager * ptman, int cchl, int cchrBackup, + int cchrMaxRaw, int * prgchl, + utf16 * prgchw2, utf16 * prgchw3, utf16 * prgchw4, utf16 * prgchw5, utf16 * prgchw6, + int * prgcchr) +{ + for (int i = 0; i < cchl; i++) + { + prgchw2[i] = 0; + } + + int ichrLim = m_ichrPos; + int ichrMin = m_ichrMin - cchrBackup; + + int cchrRange = ichrLim - ichrMin; + int ichr; + utf16 * prgchwRunText = new utf16[cchrRange]; + utf8 * prgchsRunText8 = NULL; + + UtfType utf = m_pgts->utfEncodingForm(); + + switch (utf) + { + case kutf8: + prgchsRunText8 = new utf8[cchrRange]; + m_pgts->fetch(ichrMin, cchrRange, prgchsRunText8); + for (int ichr = 0; ichr < cchrRange; ichr++) + prgchwRunText[ichr] = (utf16)prgchsRunText8[ichr]; // zero-extend into UTF-16 buffer + break; + case kutf16: + m_pgts->fetch(ichrMin, cchrRange, prgchwRunText); + break; + default: + case kutf32: // this method should never have been called + Assert(false); + for (int ichrLp = 0; ichrLp < cchrRange; ichrLp++) + { + prgcchr[ichrLp] = 1; + prgchw2[ichrLp] = 0; + prgchw3[ichrLp] = 0; + prgchw4[ichrLp] = 0; + prgchw5[ichrLp] = 0; + prgchw6[ichrLp] = 0; + } + return; + } + + ichr = ichrMin; + int ichl = 0; + while (ichr < ichrLim) + { + int cchrThis = 1; + // Replace 32-bit char with (first) 16-bit or 8-bit char. + prgchl[ichl] = (int)prgchwRunText[ichr - ichrMin]; + prgcchr[ichr] = cchrThis; + ichr++; + + while (!AtUnicodeCharBoundary(prgchwRunText, cchrRange, ichr - ichrMin, utf)) + { + cchrThis++; + switch (cchrThis) + { + case 2: prgchw2[ichl] = prgchwRunText[ichr - ichrMin]; break; + case 3: prgchw3[ichl] = prgchwRunText[ichr - ichrMin]; break; + case 4: prgchw4[ichl] = prgchwRunText[ichr - ichrMin]; break; + case 5: prgchw5[ichl] = prgchwRunText[ichr - ichrMin]; break; + case 6: prgchw6[ichl] = prgchwRunText[ichr - ichrMin]; break; + default: + break; + } + prgcchr[ichr] = cchrThis; + ichr++; + } + switch (cchrThis) + { + case 1: + prgchw2[ichl] = 0; + // fall through + case 2: + prgchw3[ichl] = 0; + // fall through + case 3: + prgchw4[ichl] = 0; + // fall through + case 4: + prgchw5[ichl] = 0; + // fall through + case 5: + prgchw6[ichl] = 0; + } + ichl++; + } + + delete[] prgchwRunText; + delete[] prgchsRunText8; +} + +/*---------------------------------------------------------------------------------------------- + Output the glyph IDs generated by the glyph generation pass (pass 0). +----------------------------------------------------------------------------------------------*/ +void GrTableManager::LogPass1Input(std::ostream & strmOut) +{ + strmOut << "INPUT TO PASS 1\n\n"; + + GrSlotStream * psstrm = OutputStream(0); + + LogSlotHeader(strmOut, psstrm->WritePos(), SP_PER_SLOT, LEADING_SP); + + LogSlotGlyphs(strmOut, psstrm); + + strmOut << "\n"; +} + +/*---------------------------------------------------------------------------------------------- + Output the the results of pass. +----------------------------------------------------------------------------------------------*/ +void GrTableManager::LogPassOutput(std::ostream & strmOut, int ipass, int cslotSkipped) +{ + strmOut << "\n"; + + GrPass * ppass = Pass(ipass); + GrSlotStream * psstrmIn = InputStream(ipass); + GrSlotStream * psstrmOut = OutputStream(ipass); + + int islot; + // Mark each slot with its index in the input and output streams. + for (islot = 0; islot < psstrmIn->ReadPos(); islot++) + psstrmIn->SlotAt(islot)->m_islotTmpIn = islot; + + for (islot = 0; islot < psstrmOut->WritePos(); islot++) + psstrmOut->SlotAt(islot)->m_islotTmpOut = islot; + + if (!dynamic_cast<GrBidiPass *>(ppass)) + ppass->LogRulesFiredAndFailed(strmOut, psstrmIn); + + strmOut << "\nOUTPUT OF PASS " << ipass; + if (dynamic_cast<GrBidiPass *>(ppass)) + strmOut << " (bidi)"; + else if (dynamic_cast<GrSubPass *>(ppass)) + { + if (ipass >= m_ipassJust1) + strmOut << " (justification)"; + else + strmOut << " (substitution)"; + } + else if (dynamic_cast<GrPosPass *>(ppass)) + strmOut << " (positioning)"; + else if (dynamic_cast<GrLineBreakPass *>(ppass)) + strmOut << " (linebreak)"; + strmOut << "\n"; + + ppass->LogInsertionsAndDeletions(strmOut, psstrmOut); + + LogSlotHeader(strmOut, psstrmOut->WritePos(), SP_PER_SLOT, LEADING_SP); + + LogSlotGlyphs(strmOut, psstrmOut); + + bool fAnyPseudos = false; + if (dynamic_cast<GrPosPass *>(ppass)) + { + for (islot = 0; islot < psstrmOut->WritePos(); islot++) + { + GrSlotState * pslotTmp = psstrmOut->SlotAt(islot); + if (pslotTmp->GlyphID() != pslotTmp->ActualGlyphForOutput(this)) + { + fAnyPseudos = true; + break; + } + } + } + if (fAnyPseudos) + { + strmOut << "Actual glyphs: "; + for (islot = 0; islot < psstrmOut->WritePos(); islot++) + { + GrSlotState * pslotTmp = psstrmOut->SlotAt(islot); + if (pslotTmp->GlyphID() != pslotTmp->ActualGlyphForOutput(this)) + LogHexInTable(strmOut, pslotTmp->ActualGlyphForOutput(this)); + else + strmOut << " "; + } + strmOut << "\n"; + } + + LogAttributes(strmOut, ipass); + + // Do this later, after we're sure the positions have been set: + //if (ipass == m_cpass - 1) + // LogFinalPositions(strmOut); + + if (cslotSkipped > 0) + { + strmOut << "\n "; + for (islot = 0; islot < cslotSkipped; islot++) + strmOut << "SKIP "; + strmOut << "\n"; + } + + // If this was the pass just before the justification routines get run, output a + // special line that just shows the results, ie, the values of justify.width. + // TODO: adjust this when measure mode get functioning. + if (ipass == m_ipassJust1 - 1 && ShouldLogJustification() + && m_engst.m_jmodi == kjmodiJustify) + { + strmOut << "\nJUSTIFICATION\n\n"; + LogSlotHeader(strmOut, psstrmOut->WritePos(), SP_PER_SLOT, LEADING_SP); + LogSlotGlyphs(strmOut, psstrmOut); + LogAttributes(strmOut, ipass, true); + } +} + +/*---------------------------------------------------------------------------------------------- + Write the list of rules fired and failed for a given pass. +----------------------------------------------------------------------------------------------*/ +void GrPass::LogRulesFiredAndFailed(std::ostream & strmOut, GrSlotStream * psstrmIn) +{ + m_pzpst->LogRulesFiredAndFailed(strmOut, psstrmIn); +} + +void PassState::LogRulesFiredAndFailed(std::ostream & strmOut, GrSlotStream * psstrmIn) +{ + + strmOut << "PASS " << m_ipass << "\n\n" << "Rules matched: "; + if (m_crulrec == 0) + strmOut << "none"; + strmOut << "\n"; + + for (int irulrec = 0; irulrec < m_crulrec; irulrec++) + { + if (m_rgrulrec[irulrec].m_fFired) + strmOut << " * "; + else + strmOut << " "; + + strmOut << m_rgrulrec[irulrec].m_islot << ". "; + + if (m_rgrulrec[irulrec].m_irul == PassState::kHitMaxRuleLoop) + strmOut << "hit MaxRuleLoop\n"; + else if (m_rgrulrec[irulrec].m_irul == PassState::kHitMaxBackup) + strmOut << "hit MaxBackup\n"; + else + { + strmOut << "rule " << m_ipass << "." << m_rgrulrec[irulrec].m_irul; + + if (m_rgrulrec[irulrec].m_fFired) + strmOut << " FIRED\n"; + else + strmOut << " failed\n"; + } + } +} + +/*---------------------------------------------------------------------------------------------- + Write out the marks on top of the slot table indicating insertions and deletions. +----------------------------------------------------------------------------------------------*/ +void GrPass::LogInsertionsAndDeletions(std::ostream & strmOut, GrSlotStream * psstrmOut) +{ + m_pzpst->LogInsertionsAndDeletions(strmOut, psstrmOut); +} + +void PassState::LogInsertionsAndDeletions(std::ostream & strmOut, GrSlotStream * psstrmOut) +{ + int cslotDel = m_rgcslotDeletions[0]; + bool fIns; + if (cslotDel > 1) + strmOut << "\n DEL-" << cslotDel; + else if (cslotDel == 1) + strmOut << "\n DEL "; + else + strmOut << "\n "; + + for (int islot = 0; islot < psstrmOut->WritePos(); islot++) + { + cslotDel = (islot + 1 >= MAX_SLOTS) ? 0 : m_rgcslotDeletions[islot + 1]; + fIns = (islot >= MAX_SLOTS) ? 0 : m_rgfInsertion[islot]; + + if (fIns) + { + strmOut << "INS"; + if (cslotDel > 0) + { + if (cslotDel > 1) + strmOut << "/D-" << cslotDel; + else + strmOut << "/DEL"; + } + else + strmOut << " "; + + } + else if (cslotDel > 0) + { + if (cslotDel >= 10) + strmOut << "DEL-" << cslotDel << " "; + else if (cslotDel > 1) + strmOut << " DEL-" << cslotDel << " "; + else + strmOut << " DEL "; + } + else + strmOut << " "; + } + + strmOut << "\n"; +} + +/*---------------------------------------------------------------------------------------------- + Write out a line for each slot attribute that changed during the pass. + + @param fJustWidths - a special pass that writes out just the effects of the justification + routines, ie, the values of justify.width +----------------------------------------------------------------------------------------------*/ +void GrTableManager::LogAttributes(std::ostream & strmOut, int ipass, + bool fJustWidths) +{ + // Figure out which slot attributes were modified for some slot during the pass. + bool * prgfMods = new bool[kslatMax + NumUserDefn() - 1]; + + bool fPreJust = (!fJustWidths && ipass == m_ipassJust1 - 1 && ShouldLogJustification()); + bool fPostJust = ((fJustWidths || ipass == m_ipassJust1) && ShouldLogJustification()); + + int ccomp; // max number of components per slot + int cassoc; // max number of associations per slot + SlotAttrsModified(ipass, prgfMods, fPreJust, &ccomp, &cassoc); + + if (fPreJust) + { + // prgfMods[kslatJStretch] = true; + // prgfMods[kslatJShrink] = true; + // prgfMods[kslatJStep] = true; + // prgfMods[kslatWeight] = true; + prgfMods[kslatJWidth] = false; // output j.width in its own line (we call this + // method with fJustWidths == true) + } + else if (fPostJust) + prgfMods[kslatJWidth] = true; + + GrPass * ppass = Pass(ipass); + GrPass * ppassNext = (ipass < m_cpass - 1) ? Pass(ipass + 1) : NULL; + GrSlotStream * psstrm = OutputStream(ipass); + + if (fJustWidths) + {} + else if (dynamic_cast<GrBidiPass *>(ppass)) + { + // Special stuff for Bidi pass: + // Log value of directionality attribute. + strmOut << "directionality "; + int islot; + for (islot = 0; islot < psstrm->WritePos(); islot++) + { + GrSlotState * pslot = psstrm->SlotAt(islot); + LogDirCodeInTable(strmOut, pslot->DirProcessed()); + } + strmOut << "\n"; + + // Log final direction level for bidi pass. + strmOut << "dir level "; + for (islot = 0; islot < psstrm->WritePos(); islot++) + { + GrSlotState * pslot = psstrm->SlotAt(islot); + LogInTable(strmOut, pslot->DirLevel()); + } + strmOut << "\n"; + } + else if (ppassNext && dynamic_cast<GrBidiPass *>(ppassNext)) + { + // Next pass is Bidi: log input values of directionality attribute that are input for it. + strmOut << "directionality "; + for (int islot = 0; islot < psstrm->WritePos(); islot++) + { + GrSlotState * pslot = psstrm->SlotAt(islot); + LogDirCodeInTable(strmOut, pslot->Directionality()); + } + strmOut << "\n"; + } + + for (int slat = 0; slat < kslatMax + NumUserDefn() - 1; slat++) + { + int cIndexLim = 1; + if (slat == kslatCompRef) + cIndexLim = ccomp; + else if (slat == kslatUserDefn) + cIndexLim = 1; // kMaxUserDefinedSlotAttributes; + + if (fJustWidths && slat != kslatJWidth) + continue; + + bool fValidAttr = true; + for (int iIndex = 0; iIndex < cIndexLim; iIndex++) + { + if (prgfMods[slat]) + { + switch(slat) + { + case kslatAdvX: strmOut << "advance.x "; break; + case kslatAdvY: strmOut << "advance.y "; break; + case kslatAttTo: strmOut << "att.to "; break; + case kslatAttAtX: strmOut << "att.at.x "; break; + case kslatAttAtY: strmOut << "att.at.y "; break; + case kslatAttAtGpt: strmOut << "att.at.gpt "; break; + case kslatAttAtXoff: strmOut << "att.at.xoff "; break; + case kslatAttAtYoff: strmOut << "att.at.yoff "; break; + case kslatAttWithX: strmOut << "att.with.x "; break; + case kslatAttWithY: strmOut << "att.with.y "; break; + case kslatAttWithGpt: strmOut << "att.with.gpt "; break; + case kslatAttWithXoff: strmOut << "att.with.xoff "; break; + case kslatAttWithYoff: strmOut << "att.with.yoff "; break; + case kslatAttLevel: strmOut << "att.level "; break; + case kslatBreak: strmOut << "breakweight "; break; + case kslatCompRef: strmOut << "component " << iIndex + 1 // 1-based + << " "; break; + case kslatDir: strmOut << "dir "; break; + case kslatInsert: strmOut << "insert "; break; + case kslatMeasureSol: strmOut << "measure.sol "; break; + case kslatMeasureEol: strmOut << "measure.eol "; break; + case kslatJStretch: strmOut << "j.stretch "; break; + case kslatJShrink: strmOut << "j.shrink "; break; + case kslatJStep: strmOut << "j.step "; break; + case kslatJWeight: strmOut << "j.weight "; break; + case kslatJWidth: strmOut << "j.width "; break; + case kslatPosX: + case kslatPosY: + Assert(false); + break; + case kslatShiftX: strmOut << "shift.x "; break; + case kslatShiftY: strmOut << "shift.y "; break; + default: + if (kslatUserDefn <= slat && + slat < kslatUserDefn + NumUserDefn()) + { + strmOut << "user" << (slat - kslatUserDefn + 1) // 1-based + << ((iIndex >= 9) ? " " : " "); + } + else + { + // Invalid attribute: + Warn("bad slot attribute"); + fValidAttr = false; + break; + } + } + + if (!fValidAttr) + break; // out of iIndex loop + + for (int islot = 0; islot < psstrm->WritePos(); islot++) + { + GrSlotState * pslot = psstrm->SlotAt(islot); + pslot->LogSlotAttributeValue(this, strmOut, ipass, slat, iIndex, + fPreJust, fPostJust); + } + + strmOut << "\n"; + } + } + } + + if (fJustWidths) + goto LDone; + + for (int iassoc = 0; iassoc < cassoc; iassoc++) + { + // Log associations. Put them on one line it that will work; otherwise use several. + bool fBoth = (cassoc <= 2); + bool fAfter = (iassoc == (cassoc - 1)); + if (fBoth) + strmOut << "assocs "; + else if (iassoc == 0) + strmOut << "assocs-before "; + else if (fAfter) + strmOut << " -after "; + else + strmOut << " -other "; + + for (int islot = 0; islot < psstrm->WritePos(); islot++) + { + GrSlotState * pslot = psstrm->SlotAt(islot); + pslot->LogAssociation(this, strmOut, ipass, iassoc, fBoth, fAfter); + } + + strmOut << "\n"; + + if (fBoth) + break; + } + + if (cassoc == 0 && dynamic_cast<GrBidiPass *>(ppass)) + { + strmOut << "assocs "; + + // Log associations for all slots moved during the Bidi pass. + for (int islot = 0; islot < psstrm->WritePos(); islot++) + { + GrSlotState * pslot = psstrm->SlotAt(islot); + if (pslot->m_islotTmpIn != pslot->m_islotTmpOut) + LogInTable(strmOut, pslot->m_islotTmpIn); + else + strmOut << " "; + } + + strmOut << "\n"; + } + +LDone: + + delete[] prgfMods; +} + +/*---------------------------------------------------------------------------------------------- + Write out the final positions. +----------------------------------------------------------------------------------------------*/ +void GrTableManager::LogFinalPositions(std::ostream & strmOut) +{ + GrSlotStream * psstrm = OutputStream(m_cpass - 1); + + strmOut << "x position "; + for (int islot = 0; islot < psstrm->WritePos(); islot++) + { + GrSlotState * pslot = psstrm->SlotAt(islot); + if (pslot->IsLineBreak(LBGlyphID())) + { + strmOut << " "; + continue; + } + LogInTable(strmOut, pslot->XPosition()); + } + strmOut << "\n"; + + strmOut << "y position "; + for (int islot = 0; islot < psstrm->WritePos(); islot++) + { + GrSlotState * pslot = psstrm->SlotAt(islot); + if (pslot->IsLineBreak(LBGlyphID())) + { + strmOut << " "; + continue; + } + LogInTable(strmOut, pslot->YPosition()); + } + strmOut << "\n"; +} +#endif // TRACING + +/*---------------------------------------------------------------------------------------------- + Write out the final underlying-to-surface associations. +----------------------------------------------------------------------------------------------*/ +void Segment::LogUnderlyingToSurface(GrTableManager * ptman, std::ostream & strmOut, + GrCharStream * pchstrm) +{ +#ifdef TRACING + strmOut << "\n\nUNDERLYING TO SURFACE MAPPINGS\n\n"; + + size_t cassocs = 0; + int fLigs = false; + int ichw; + for (ichw = 0; ichw < (m_ichwAssocsLim - m_ichwAssocsMin); ichw++) + { + if (m_prgpvisloutAssocs[ichw]) + cassocs = max(cassocs, m_prgpvisloutAssocs[ichw]->size()); + if (m_prgisloutLigature[ichw] != kNegInfinity) + fLigs = true; + } + +// ptman->LogSlotHeader(strmOut, m_ichwAssocsLim, SP_PER_SLOT, LEADING_SP, m_ichwAssocsMin); + ptman->LogUnderlyingHeader(strmOut, pchstrm->Min(), (pchstrm->Min() + m_ichwAssocsLim), + -m_ichwAssocsMin, NULL); + + int rgnChars[MAX_SLOTS]; + bool rgfNewRun[MAX_SLOTS]; + std::fill_n(rgfNewRun, MAX_SLOTS, false); + GrFeatureValues rgfval[MAX_SLOTS]; + int cchwMaxRawChars; + + int cchw = pchstrm->GetLogData(ptman, rgnChars, rgfNewRun, rgfval, + -m_ichwAssocsMin, &cchwMaxRawChars); + cchw = min(cchw, MAX_SLOTS); + + utf16 rgchwChars2[MAX_SLOTS]; + utf16 rgchwChars3[MAX_SLOTS]; + utf16 rgchwChars4[MAX_SLOTS]; + utf16 rgchwChars5[MAX_SLOTS]; + utf16 rgchwChars6[MAX_SLOTS]; + int rgcchwRaw[MAX_SLOTS]; + if (cchwMaxRawChars > 1) + { + cchwMaxRawChars = min(cchwMaxRawChars, 6); + pchstrm->GetLogDataRaw(ptman, cchw, -m_ichwAssocsMin, cchwMaxRawChars, + rgnChars, rgchwChars2, rgchwChars3, rgchwChars4, rgchwChars5, rgchwChars6, + rgcchwRaw); + } + else + { + for (ichw = 0 ; ichw <(m_ichwAssocsLim - m_ichwAssocsMin); ichw++) + { + rgcchwRaw[ichw] = 1; + rgchwChars2[ichw] = 0; + rgchwChars3[ichw] = 0; + rgchwChars4[ichw] = 0; + rgchwChars5[ichw] = 0; + rgchwChars6[ichw] = 0; + } + } + + // Text + strmOut << "Text: "; // 15 spaces + int inUtf32 = 0; + for (ichw = 0; ichw < (m_ichwAssocsLim - m_ichwAssocsMin); ichw++) + { + utf16 chw, chwNext; + switch (rgcchwRaw[ichw]) + { + default: + case 1: chw = utf16(rgnChars[inUtf32]); chwNext = rgchwChars2[inUtf32]; break; + case 2: chw = rgchwChars2[inUtf32]; chwNext = rgchwChars3[inUtf32]; break; + case 3: chw = rgchwChars3[inUtf32]; chwNext = rgchwChars4[inUtf32]; break; + case 4: chw = rgchwChars4[inUtf32]; chwNext = rgchwChars5[inUtf32]; break; + case 5: chw = rgchwChars5[inUtf32]; chwNext = rgchwChars6[inUtf32]; break; + case 6: chw = rgchwChars6[inUtf32]; chwNext = 0; break; + } + if (rgcchwRaw[ichw] == 1 && chwNext == 0 && chw < 0x0100) // ANSI + strmOut << (char)chw << " "; // 6 spaces + else + strmOut << " "; // 7 spaces + if (chwNext == 0) + inUtf32++; + } + strmOut << "\n"; + + // Unicode + strmOut << "Unicode: "; + inUtf32 = 0; + for (ichw = 0; ichw < (m_ichwAssocsLim - m_ichwAssocsMin); ichw++) + { + utf16 chw, chwNext; + switch (rgcchwRaw[ichw]) + { + default: + case 1: chw = utf16(rgnChars[inUtf32]); chwNext = rgchwChars2[inUtf32]; break; + case 2: chw = rgchwChars2[inUtf32]; chwNext = rgchwChars3[inUtf32]; break; + case 3: chw = rgchwChars3[inUtf32]; chwNext = rgchwChars4[inUtf32]; break; + case 4: chw = rgchwChars4[inUtf32]; chwNext = rgchwChars5[inUtf32]; break; + case 5: chw = rgchwChars5[inUtf32]; chwNext = rgchwChars6[inUtf32]; break; + case 6: chw = rgchwChars6[inUtf32]; chwNext = 0; break; + } + ptman->LogHexInTable(strmOut, chw, chwNext != 0); + if (chwNext == 0) + inUtf32++; + } + strmOut << "\n"; + + strmOut << "before "; + for (ichw = 0; ichw < (m_ichwAssocsLim - m_ichwAssocsMin); ichw++) + { + if (rgcchwRaw[ichw] > 1) + // continuation of Unicode codepoint + strmOut << " "; + else if (m_prgisloutBefore[ichw] == kNegInfinity) + strmOut << "<-- "; + else if (m_prgisloutBefore[ichw] == kPosInfinity) + strmOut << "--> "; + else + ptman->LogInTable(strmOut, m_prgisloutBefore[ichw]); + } + strmOut <<"\n"; + + for (int ix = 1; ix < signed(cassocs) - 1; ix++) //(cassocs > 2) + { + if (ix == 1) + strmOut << "other "; + else + strmOut << " "; + for (ichw = 0; ichw < (m_ichwAssocsLim - m_ichwAssocsMin); ichw++) + { + std::vector<int> * pvislout = m_prgpvisloutAssocs[ichw]; + if (pvislout == NULL) + strmOut << " "; + else if (signed(pvislout->size()) <= ix) + strmOut << " "; + else if ((*pvislout)[ix] != m_prgisloutAfter[ichw]) + ptman->LogInTable(strmOut, (*pvislout)[ix]); + else + strmOut << " "; + } + strmOut << "\n"; + } + + strmOut << "after "; + for (ichw = 0; ichw < (m_ichwAssocsLim - m_ichwAssocsMin); ichw++) + { + if (rgcchwRaw[ichw] > 1) + // continuation of Unicode codepoint + strmOut << " "; + else if (m_prgisloutAfter[ichw] == kNegInfinity) + strmOut << "<-- "; + else if (m_prgisloutAfter[ichw] == kPosInfinity) + strmOut << "--> "; + else + ptman->LogInTable(strmOut, m_prgisloutAfter[ichw]); + } + strmOut <<"\n"; + + if (fLigs) + { + strmOut << "ligature "; + for (ichw = 0; ichw < (m_ichwAssocsLim - m_ichwAssocsMin); ichw++) + { + if (rgcchwRaw[ichw] > 1) + // continuation of Unicode codepoint + strmOut << " "; + else if (m_prgisloutLigature[ichw] != kNegInfinity) + ptman->LogInTable(strmOut, m_prgisloutLigature[ichw]); + else + strmOut << " "; + } + strmOut << "\n"; + + strmOut << "component "; + for (ichw = 0; ichw < (m_ichwAssocsLim - m_ichwAssocsMin); ichw++) + { + if (rgcchwRaw[ichw] > 1) + // continuation of Unicode codepoint + strmOut << " "; + else if (m_prgisloutLigature[ichw] != kNegInfinity) + ptman->LogInTable(strmOut, m_prgiComponent[ichw] + 1); // 1-based + else + strmOut << " "; + } + strmOut << "\n"; + } + + strmOut << "\n"; +#endif +} + +/*---------------------------------------------------------------------------------------------- + Write out the final surface-to-underlying associations. +----------------------------------------------------------------------------------------------*/ +void Segment::LogSurfaceToUnderlying(GrTableManager * ptman, std::ostream & strmOut) +{ +#ifdef TRACING + strmOut << "\nSURFACE TO UNDERLYING MAPPINGS\n\n"; + + ptman->LogSlotHeader(strmOut, m_cslout, SP_PER_SLOT, LEADING_SP); + + int ccomp = 0; + + strmOut << "Glyph IDs: "; + int islout; + for (islout = 0; islout < m_cslout; islout++) + { + GrSlotOutput * psloutTmp = m_prgslout + islout; + if (psloutTmp->SpecialSlotFlag() == kspslLbInitial || + psloutTmp->SpecialSlotFlag() == kspslLbFinal) + { + strmOut << "# "; + } + else + { + ptman->LogHexInTable(strmOut, psloutTmp->GlyphID()); + ccomp = max(ccomp, psloutTmp->NumberOfComponents()); + } + } + strmOut << "\n"; + + bool fAnyPseudos = false; + for (islout = 0; islout < m_cslout; islout++) + { + GrSlotOutput * psloutTmp = m_prgslout + islout; + if (psloutTmp->GlyphID() != psloutTmp->ActualGlyphForOutput(ptman)) + { + fAnyPseudos = true; + break; + } + } + if (fAnyPseudos) + { + strmOut << "Actual glyphs: "; + for (int islout = 0; islout < m_cslout; islout++) + { + GrSlotOutput * psloutTmp = m_prgslout + islout; + if (psloutTmp->GlyphID() != psloutTmp->ActualGlyphForOutput(ptman)) + ptman->LogHexInTable(strmOut, psloutTmp->ActualGlyphForOutput(ptman)); + else + strmOut << " "; + } + strmOut << "\n"; + } + + strmOut << "before "; + for (islout = 0; islout < m_cslout; islout++) + { + GrSlotOutput * psloutTmp = m_prgslout + islout; + if (psloutTmp->SpecialSlotFlag() == kspslLbInitial || + psloutTmp->SpecialSlotFlag() == kspslLbFinal) + { + strmOut << " "; + } + else + ptman->LogInTable(strmOut, psloutTmp->BeforeAssoc()); + } + strmOut << "\n"; + + strmOut << "after "; + for (islout = 0; islout < m_cslout; islout++) + { + GrSlotOutput * psloutTmp = m_prgslout + islout; + if (psloutTmp->SpecialSlotFlag() == kspslLbInitial || + psloutTmp->SpecialSlotFlag() == kspslLbFinal) + { + strmOut << " "; + } + else + ptman->LogInTable(strmOut, psloutTmp->AfterAssoc()); + } + strmOut << "\n"; + + for (int icomp = 0; icomp < ccomp; icomp++) + { + strmOut << "component " << icomp + 1 // 1=based + << " "; + for (islout = 0; islout < m_cslout; islout++) + { + GrSlotOutput * psloutTmp = m_prgslout + islout; + if (psloutTmp->SpecialSlotFlag() == kspslLbInitial || + psloutTmp->SpecialSlotFlag() == kspslLbFinal) + { + strmOut << " "; + } + else if (icomp < psloutTmp->NumberOfComponents()) + ptman->LogInTable(strmOut, psloutTmp->UnderlyingComponent(icomp)); + else + strmOut << " "; + } + strmOut << "\n"; + } +#endif +} + +#ifdef TRACING +/*---------------------------------------------------------------------------------------------- + Write out the header lines for the underlying data. +----------------------------------------------------------------------------------------------*/ +void GrTableManager::LogUnderlyingHeader(std::ostream & strmOut, int iMin, + int iLim, int cBackup, int * prgichr) +{ + strmOut << "string "; + int i, iLabel; + int * pichr = prgichr; + for (i = iMin - cBackup, iLabel = i; i < iLim; i++, iLabel++, pichr++) + { + while (prgichr && *pichr > 1) + { + // continuation of upper-plane char + iLabel++; + pichr++; + } + LogInTable(strmOut, iLabel); + } + strmOut << "\n"; + + strmOut << "segment "; + pichr = prgichr; + for (i = 0 - cBackup, iLabel = i; i < (iLim - iMin); i++, iLabel++, pichr++) + { + while (prgichr && *pichr > 1) + { + // continuation of upper-plane char + iLabel++; + pichr++; + } + LogInTable(strmOut, iLabel); + } + strmOut << "\n\n"; +} + +/*---------------------------------------------------------------------------------------------- + Write out the header lines for the slot contents. +----------------------------------------------------------------------------------------------*/ +void GrTableManager::LogSlotHeader(std::ostream & strmOut, int islotLim, + int cspPerSlot, int cspLeading, int islotMin) +{ + islotLim = min(islotLim, MAX_SLOTS); + + int isp, islot; + + for (isp = 0; isp < cspLeading; isp++) + strmOut << " "; + + for (islot = islotMin; islot < islotLim; islot++) + LogInTable(strmOut, islot); + strmOut << "\n\n"; + +/**** + if (cslot >= 100) + { + for (isp = 0; isp < cspLeading; isp++) + strmOut << " "; + + for (islot = 0; islot < 100; islot++) + { + for (isp = 0; isp < cspPerSlot; isp++) + strmOut << " "; + } + + for (islot = 100; islot < cslot; islot++) + { + strmOut << "1"; + for (isp = 1; isp < cspPerSlot; isp++) + strmOut << " "; + } + } + + if (cslot > 10) + { + for (isp = 0; isp < cspLeading; isp++) + strmOut << " "; + + for (islot = 0; islot < 10; islot++) + { + for (isp = 0; isp < cspPerSlot; isp++) + strmOut << " "; + } + + for (islot = 10; islot < cslot; islot++) + { + if (true) // (islot % 10 == 0) + { + if (islot >= 100) + strmOut << ((islot - 100) / 10); + else + strmOut << (islot / 10); + } + else + strmOut << " "; + + for (isp = 1; isp < cspPerSlot; isp++) + strmOut << " "; + } + strmOut << "\n"; + } + + for (isp = 0; isp < cspLeading; isp++) + strmOut << " "; + + for (islot = 0; islot < cslot; islot++) + { + strmOut << (islot % 10); + for (isp = 1; isp < cspPerSlot; isp++) + strmOut << " "; + + } + strmOut << "\n"; +****/ +} + +/*---------------------------------------------------------------------------------------------- + Write out the glyph numbers for the given stream. +----------------------------------------------------------------------------------------------*/ +void GrTableManager::LogSlotGlyphs(std::ostream & strmOut, GrSlotStream * psstrm) +{ + strmOut << "Glyph IDs: "; + int islot; + for (islot = 0; islot < psstrm->WritePos(); islot++) + { + GrSlotState * pslotTmp = psstrm->SlotAt(islot); + if (pslotTmp->IsLineBreak(LBGlyphID())) + strmOut << "# "; + else + LogHexInTable(strmOut, pslotTmp->GlyphID()); + } + strmOut << "\n"; +} + +/*---------------------------------------------------------------------------------------------- + Return flags indicating which attributes were modified for some slot during the pass + and therefore need a line in the log file. + + The 'pfMods' array has one flag per slot attribute; the final group are the user- + definable attributes. 'pccomp' returns the maximum number of ligature components + in this pass. Associations are assumed to have changed if anything else for the slot did. +----------------------------------------------------------------------------------------------*/ +void GrTableManager::SlotAttrsModified(int ipass, bool * rgfMods, bool fPreJust, + int * pccomp, int * pcassoc) +{ + // Zero the flags + std::fill_n(rgfMods, kslatMax + NumUserDefn() - 1, false); + *pccomp = 0; + *pcassoc = 0; + + //GrSlotStream * psstrmIn = InputStream(ipass); + GrSlotStream * psstrmOut = OutputStream(ipass); + + for (int islot = 0; islot < psstrmOut->WritePos(); islot++) + { + GrSlotState * pslot = psstrmOut->SlotAt(islot); + Assert(pslot->PassModified() <= ipass); + if (pslot->PassModified() < ipass && !fPreJust) + continue; // not modified during this pass + + pslot->SlotAttrsModified(rgfMods, fPreJust, pccomp, pcassoc); + } +} + +void GrSlotState::SlotAttrsModified(bool * rgfMods, bool fPreJust, int * pccomp, int * pcassoc) +{ + // To handle reprocessing, in which case there may be a chain of slots modified + // in the same pass: + GrSlotState * pslotPrev = m_pslotPrevState; + while (pslotPrev && pslotPrev->PassModified() == PassModified()) + pslotPrev = pslotPrev->m_pslotPrevState; + + if (!pslotPrev) + { + // Inserted slot? + if (m_fAdvXSet) + rgfMods[kslatAdvX] = true; + if (m_fAdvYSet) + rgfMods[kslatAdvY] = true; + + if (m_srAttachTo != 0) + rgfMods[kslatAttTo] = true; + + if (m_mAttachAtX != kNotYetSet || m_mAttachAtY != 0) + { // always do these in pairs + rgfMods[kslatAttAtX] = true; + rgfMods[kslatAttAtY] = true; + } + if (m_nAttachAtGpoint != kNotYetSet) + rgfMods[kslatAttAtGpt] = true; + if (m_mAttachAtXOffset != 0 || m_mAttachAtYOffset != 0) + { // always do these in pairs + rgfMods[kslatAttAtXoff] = true; + rgfMods[kslatAttAtYoff] = true; + } + + if (m_mAttachWithX != kNotYetSet || m_mAttachWithY != 0) + { // always do these in pairs + rgfMods[kslatAttWithX] = true; + rgfMods[kslatAttWithY] = true; + } + if (m_nAttachWithGpoint != kNotYetSet) + rgfMods[kslatAttWithGpt] = true; + if (m_mAttachWithXOffset != 0 || m_mAttachWithYOffset != 0) + { // always do these in pairs + rgfMods[kslatAttWithXoff] = true; + rgfMods[kslatAttWithYoff] = true; + } + + if (m_nAttachLevel != 0) + rgfMods[kslatAttLevel] = true; + + if (m_lb != kNotYetSet8) + rgfMods[kslatBreak] = true; + if (m_dirc != kNotYetSet8) + rgfMods[kslatDir] = true; + if (m_fInsertBefore != true) + rgfMods[kslatInsert] = true; + + if (m_mMeasureSol != kNotYetSet && m_mMeasureSol != 0) + rgfMods[kslatMeasureSol] = true; + if (m_mMeasureEol != kNotYetSet && m_mMeasureEol != 0) + rgfMods[kslatMeasureEol] = true; + + if (m_mJStretch0 != kNotYetSet && m_mJStretch0 != 0) + rgfMods[kslatJStretch] = true; + if (m_mJShrink0 != kNotYetSet && m_mJShrink0 != 0) + rgfMods[kslatJShrink] = true; + if (m_mJStep0 != kNotYetSet && m_mJStep0 != 0) + rgfMods[kslatJStep] = true; + if (m_nJWeight0 != byte(kNotYetSet) && + m_nJWeight0 != 0 && m_nJWeight0 != 1) + rgfMods[kslatJWeight] = true; + if (m_mJWidth0 != kNotYetSet && m_mJWidth0 != 0) + rgfMods[kslatJWidth] = true; + + if (m_mShiftX != 0) + rgfMods[kslatShiftX] = true; + if (m_mShiftY != 0) + rgfMods[kslatShiftY] = true; + + int i; + for (i = 0; i < m_cnCompPerLig; i++) + { + if (CompRef(i) != NULL) + rgfMods[kslatCompRef] = true; + if (CompRef(i)) + *pccomp = max(*pccomp, i + 1); // max number of ligatures in this pass + } + + for (i = 0; i < m_cnUserDefn; i++) + { + if (UserDefn(i) != 0) + rgfMods[kslatUserDefn + i] = true; + } + } + else + { + if (m_fAdvXSet && m_mAdvanceX != pslotPrev->m_mAdvanceX) + rgfMods[kslatAdvX] = true; + if (m_fAdvYSet && m_mAdvanceY != pslotPrev->m_mAdvanceY) + rgfMods[kslatAdvY] = true; + + if (m_srAttachTo != pslotPrev->m_srAttachTo) + rgfMods[kslatAttTo] = true; + + if (m_mAttachAtX != pslotPrev->m_mAttachAtX || m_mAttachAtY != pslotPrev->m_mAttachAtY) + { + rgfMods[kslatAttAtX] = true; + rgfMods[kslatAttAtY] = true; + } + if (m_nAttachAtGpoint != pslotPrev->m_nAttachAtGpoint) + rgfMods[kslatAttAtGpt] = true; + if (m_mAttachAtXOffset != pslotPrev->m_mAttachAtXOffset || + m_mAttachAtYOffset != pslotPrev->m_mAttachAtYOffset) + { + rgfMods[kslatAttAtXoff] = true; + rgfMods[kslatAttAtYoff] = true; + } + + if (m_mAttachWithX != pslotPrev->m_mAttachWithX || + m_mAttachWithY != pslotPrev->m_mAttachWithY) + { + rgfMods[kslatAttWithX] = true; + rgfMods[kslatAttWithY] = true; + } + if (m_nAttachWithGpoint != pslotPrev->m_nAttachWithGpoint) + rgfMods[kslatAttWithGpt] = true; + if (m_mAttachWithXOffset != pslotPrev->m_mAttachWithXOffset || + m_mAttachWithYOffset != pslotPrev->m_mAttachWithYOffset) + { + rgfMods[kslatAttWithXoff] = true; + rgfMods[kslatAttWithYoff] = true; + } + + if (m_nAttachLevel != pslotPrev->m_nAttachLevel) + rgfMods[kslatAttLevel] = true; + + if (m_lb != pslotPrev->m_lb) + rgfMods[kslatBreak] = true; + if (m_dirc != pslotPrev->m_dirc) + rgfMods[kslatDir] = true; + if (m_fInsertBefore != pslotPrev->m_fInsertBefore) + rgfMods[kslatInsert] = true; + + if (m_mMeasureSol != pslotPrev->m_mMeasureSol) + rgfMods[kslatMeasureSol] = true; + if (m_mMeasureEol != pslotPrev->m_mMeasureEol) + rgfMods[kslatMeasureEol] = true; + + if (m_mJStretch0 != pslotPrev->m_mJStretch0 || (fPreJust && m_mJStretch0 != 0)) + rgfMods[kslatJStretch] = true; + if (m_mJShrink0 != pslotPrev->m_mJShrink0 || (fPreJust && m_mJShrink0 != 0)) + rgfMods[kslatJShrink] = true; + if (m_mJStep0 != pslotPrev->m_mJStep0 || (fPreJust && m_mJStep0 != 0)) + rgfMods[kslatJStep] = true; + if (m_nJWeight0 != pslotPrev->m_nJWeight0 || (fPreJust && m_nJWeight0 != 0)) + rgfMods[kslatJWeight] = true; + if (m_mJWidth0 != pslotPrev->m_mJWidth0) + rgfMods[kslatJWidth] = true; + + if (m_mShiftX != pslotPrev->m_mShiftX) + rgfMods[kslatShiftX] = true; + if (m_mShiftY != pslotPrev->m_mShiftY) + rgfMods[kslatShiftY] = true; + + int i; + for (i = 0; i < m_cnCompPerLig; i++) + { + if (CompRef(i) != pslotPrev->CompRef(i)) + rgfMods[kslatCompRef] = true; + if (CompRef(i)) + *pccomp = max(*pccomp, i + 1); // max number of ligatures in this pass + } + + for (i = 0; i < m_cnUserDefn; i++) + { + if (UserDefn(i) != pslotPrev->UserDefn(i)) + rgfMods[kslatUserDefn + i] = true; + } + } + + *pcassoc = max(*pcassoc, AssocsSize()); +} + +/*---------------------------------------------------------------------------------------------- + Log the value of the slot attribute for the given slot, if it changed. +----------------------------------------------------------------------------------------------*/ +void GrSlotState::LogSlotAttributeValue(GrTableManager * ptman, + std::ostream & strmOut, int ipass, int slat, int iIndex, + bool fPreJust, bool fPostJust) +{ + if (m_ipassModified != ipass && !fPreJust && !fPostJust) + { + strmOut << " "; + return; + } + + // To handle reprocessing, in which case there may be a chain of slots modified + // in the same pass: + GrSlotState * pslotPrev = m_pslotPrevState; + while (pslotPrev && pslotPrev->PassModified() == PassModified()) + pslotPrev = pslotPrev->m_pslotPrevState; + + // General-purpose variables for em-unit attributes: + int mThis = 0; + int mPrev = 0; + switch (slat) + { + case kslatShiftX: + mThis = m_mShiftX; + mPrev = (pslotPrev) ? pslotPrev->m_mShiftX : 0; + break; + case kslatShiftY: + mThis = m_mShiftY; + mPrev = (pslotPrev) ? pslotPrev->m_mShiftY : 0; + break; + case kslatMeasureSol: + mThis = m_mMeasureSol; + mPrev = (pslotPrev) ? pslotPrev->m_mMeasureSol : 0; + break; + case kslatMeasureEol: + mThis = m_mMeasureEol; + mPrev = (pslotPrev) ? pslotPrev->m_mMeasureEol : 0; + break; + case kslatJStretch: + mThis = m_mJStretch0; + mPrev = (pslotPrev) ? pslotPrev->m_mJStretch0 : 0; + mPrev = (fPreJust && mThis > 0) ? -1 : mPrev; // log it even if it didn't change + break; + case kslatJShrink: + mThis = m_mJShrink0; + mPrev = (pslotPrev) ? pslotPrev->m_mJShrink0 : 0; + mPrev = (fPreJust && mThis > 0) ? -1 : mPrev; // log it even if it didn't change + break; + case kslatJStep: + mThis = m_mJStep0; + mPrev = (pslotPrev) ? pslotPrev->m_mJStep0 : 0; + mPrev = (fPreJust && mThis > 1) ? -1 : mPrev; // log it even if it didn't change + break; + case kslatJWeight: + mThis = m_nJWeight0; + mPrev = (pslotPrev) ? pslotPrev->m_nJWeight0 : 0; + mPrev = (fPreJust && mThis > 1) ? -1 : mPrev; // log it even if it didn't change + break; + case kslatJWidth: + mThis = m_mJWidth0; + mPrev = (pslotPrev) ? pslotPrev->m_mJWidth0 : 0; + mPrev = (fPostJust && mThis > 0) ? -1 : mPrev; // log it even if it didn't change + break; + default: + // don't use these variables + break; + } + + switch (slat) + { + case kslatAdvX: + if (m_fAdvXSet && (!pslotPrev || m_mAdvanceX != pslotPrev->m_mAdvanceX)) + { + ptman->LogInTable(strmOut, m_mAdvanceX); + return; + } + break; + case kslatAdvY: + if (m_fAdvYSet && (!pslotPrev || m_mAdvanceY != pslotPrev->m_mAdvanceY)) + { + ptman->LogInTable(strmOut, m_mAdvanceY); + return; + } + break; + + case kslatAttTo: + if (m_srAttachTo != (pslotPrev ? pslotPrev->m_srAttachTo : 0)) + { + ptman->LogInTable(strmOut, m_srAttachTo); + return; + } + break; + + case kslatAttAtX: // always do these in pairs + case kslatAttAtY: + if (m_mAttachAtX != (pslotPrev ? pslotPrev->m_mAttachAtX : kNotYetSet) || + m_mAttachAtY != (pslotPrev ? pslotPrev->m_mAttachAtY : 0)) + { + ptman->LogInTable(strmOut, + ((slat == kslatAttAtX) ? m_mAttachAtX : m_mAttachAtY)); + return; + } + break; + case kslatAttAtGpt: + if (m_nAttachAtGpoint != (pslotPrev ? pslotPrev->m_nAttachAtGpoint : kNotYetSet)) + { + ptman->LogInTable(strmOut, + ((m_nAttachAtGpoint == kGpointZero) ? 0 : m_nAttachAtGpoint)); + return; + } + break; + case kslatAttAtXoff: // always do these in pairs + case kslatAttAtYoff: + if (m_mAttachAtXOffset != (pslotPrev ? pslotPrev->m_mAttachAtXOffset : 0) || + m_mAttachAtYOffset != (pslotPrev ? pslotPrev->m_mAttachAtYOffset : 0)) + { + ptman->LogInTable(strmOut, + ((slat == kslatAttAtXoff) ? m_mAttachAtXOffset : m_mAttachAtYOffset)); + return; + } + break; + + case kslatAttWithX: // always do these in pairs + case kslatAttWithY: + if (m_mAttachWithX != (pslotPrev ? pslotPrev->m_mAttachWithX : kNotYetSet) || + m_mAttachWithY != (pslotPrev ? pslotPrev->m_mAttachWithY : 0)) + { + ptman->LogInTable(strmOut, + ((slat == kslatAttWithX) ? m_mAttachWithX : m_mAttachWithY)); + return; + } + break; + case kslatAttWithGpt: + if (m_nAttachWithGpoint != (pslotPrev ? pslotPrev->m_nAttachWithGpoint : kNotYetSet)) + { + ptman->LogInTable(strmOut, + ((m_nAttachWithGpoint == kGpointZero) ? 0 : m_nAttachWithGpoint)); + return; + } + break; + case kslatAttWithXoff: // always do these in pairs + case kslatAttWithYoff: + if (m_mAttachWithXOffset != (pslotPrev ? pslotPrev->m_mAttachWithXOffset : 0) || + m_mAttachWithYOffset != (pslotPrev ? pslotPrev->m_mAttachWithYOffset : 0)) + { + ptman->LogInTable(strmOut, + ((slat == kslatAttWithXoff) ? m_mAttachWithXOffset : m_mAttachWithYOffset)); + return; + } + break; + + case kslatAttLevel: + if (m_nAttachLevel != (pslotPrev ? pslotPrev->m_nAttachLevel : 0)) + { + ptman->LogInTable(strmOut, m_nAttachLevel); + return; + } + break; + + case kslatBreak: + if (m_lb != (pslotPrev ? pslotPrev->m_lb : kNotYetSet8)) + { + ptman->LogBreakWeightInTable(strmOut, m_lb); + return; + } + break; + case kslatDir: + if (m_dirc != (pslotPrev ? pslotPrev->m_dirc : kNotYetSet8)) + { + ptman->LogDirCodeInTable(strmOut, m_dirc); + return; + } + break; + case kslatInsert: + if (m_fInsertBefore != (pslotPrev ? pslotPrev->m_fInsertBefore : true)) + { + if (m_fInsertBefore) + strmOut << "true "; + else + strmOut << "false "; + return; + } + break; + + case kslatJWeight: + if (m_mJStretch0 == 0 && m_mJShrink0 == 0) + mPrev = mThis; // don't log; weight is irrelevant + // fall through + case kslatShiftX: + case kslatShiftY: + case kslatMeasureSol: + case kslatMeasureEol: + case kslatJStretch: + case kslatJShrink: + case kslatJStep: + case kslatJWidth: + if (mThis != mPrev) + { + ptman->LogInTable(strmOut, mThis); + return; + } + break; + + case kslatCompRef: + if (CompRef(iIndex) != (pslotPrev ? pslotPrev->CompRef(iIndex) : 0)) + { + GrSlotState * pslotComp = reinterpret_cast<GrSlotState *>(CompRef(iIndex)); + ptman->LogInTable(strmOut, pslotComp->m_islotTmpIn); + return; + } + break; + + default: + if (kslatUserDefn <= slat && slat <= kslatUserDefn + m_cnUserDefn) + { + int iTmp = slat - kslatUserDefn; + if (UserDefn(iTmp) != (pslotPrev ? pslotPrev->UserDefn(iTmp) : 0)) + { + ptman->LogInTable(strmOut, UserDefn(iTmp)); + return; + } + } + else + gAssert(false); + } + + strmOut << " "; +} + +/*---------------------------------------------------------------------------------------------- + Log the value of the association, if the slot changed. +----------------------------------------------------------------------------------------------*/ +void GrSlotState::LogAssociation(GrTableManager * ptman, + std::ostream & strmOut, int ipass, int iassoc, bool fBoth, bool fAfter) +{ + if (m_ipassModified != ipass) + { + strmOut << " "; + return; + } + + if (fBoth) + { + GrSlotState * pslotBefore = AssocSlot(0); + GrSlotState * pslotAfter = AssocSlot(m_vpslotAssoc.size() - 1); + + int nBefore, nAfter; + + int csp = 4; + if (pslotBefore) + { + nBefore = pslotBefore->m_islotTmpIn; + strmOut << nBefore; + if (nBefore > 99) csp--; + if (nBefore > 9) csp--; + } + else + { + strmOut << "??"; + csp--; + } + if (pslotAfter) + { + nAfter = pslotAfter->m_islotTmpIn; + strmOut << "/" << nAfter; + if (nAfter > 99) csp--; + if (nAfter > 9) csp--; + } + else + { + if (pslotBefore) + { + strmOut << "/" << "??"; + csp--; + } + else + csp = 5; + } + + for (int isp = 0; isp < csp; isp++) + strmOut << " "; + } + + else if (fAfter) + { + Assert(m_vpslotAssoc.size()); + GrSlotState * pslotAfter = AssocSlot(m_vpslotAssoc.size() - 1); + + if (pslotAfter) + { + int nAfter = pslotAfter->m_islotTmpIn; + ptman->LogInTable(strmOut, nAfter); + } + else + strmOut << "?? "; + } + else if (iassoc < signed(m_vpslotAssoc.size() - 1)) + { + GrSlotState * pslot = AssocSlot(iassoc); + + if (pslot) + { + int n = pslot->m_islotTmpIn; + ptman->LogInTable(strmOut, n); + } + else + strmOut << "?? "; + } + else + strmOut << " "; +} + +/*---------------------------------------------------------------------------------------------- + Write a hex value (a glyphID or Unicode codepoint) into the table. +----------------------------------------------------------------------------------------------*/ +void GrTableManager::LogInTable(std::ostream & strmOut, int n) +{ + if (n == kNegInfinity) + { + strmOut << "-inf "; + return; + } + if (n == kPosInfinity) + { + strmOut << "+inf "; + return; + } + if (n > 999999) + { + strmOut << "****** "; + return; + } + if (n < -99999) + { + strmOut << "-***** "; + return; + } + + strmOut << n; + int csp = SP_PER_SLOT - 1; + + if (abs(n) > 99999) csp--; + if (abs(n) > 9999) csp--; + if (abs(n) > 999) csp--; + if (abs(n) > 99) csp--; + if (abs(n) > 9) csp--; + + if (n < 0) csp--; + + for (int isp = 0; isp < csp; isp++) + strmOut << " "; +} + +void GrTableManager::LogInTable(std::ostream & strmOut, float n) +{ + if (n == kNegInfFloat) + { + strmOut << "-inf "; + return; + } + if (n == kPosInfFloat) + { + strmOut << "+inf "; + return; + } + if (n > 9999) + { + strmOut << "****.* "; + return; + } + if (n < -999) + { + strmOut << "-***.* "; + return; + } + + int csp = SP_PER_SLOT - 4; + + int nInt = (int)(fabsf(n)); + int nTenths = (int)fabsf((fabsf(n) - float(nInt) + 0.05f) * 10); + if (nTenths >= 10) + { + nTenths = 0; + nInt++; + } + + if (nInt >= 1000) csp--; + if (nInt >= 100) csp--; + if (nInt >= 10) csp--; + + if (n < 0) csp--; + + for (int isp = 0; isp < csp; isp++) + strmOut << " "; + if (n < 0) + strmOut << "-"; + strmOut << nInt << "." << nTenths << " "; +} + +/*---------------------------------------------------------------------------------------------- + Write a hex value (a glyphID or Unicode codepoint) into the table. +----------------------------------------------------------------------------------------------*/ +void GrTableManager::LogHexInTable(std::ostream & strmOut, utf16 chw, bool fPlus) +{ + //char rgch[20]; + if (chw <= 0x0fff) strmOut << "0"; + if (chw <= 0x00ff) strmOut << "0"; + if (chw <= 0x000f) strmOut << "0"; + + strmOut << std::hex << chw << std::dec; + + for (int i = 4; i < SP_PER_SLOT - 2; i++) + strmOut << " "; + + if (fPlus) + strmOut << "+ "; + else + strmOut << " "; +} + +/*---------------------------------------------------------------------------------------------- + Write a directionality code to the table. +----------------------------------------------------------------------------------------------*/ +void GrTableManager::LogDirCodeInTable(std::ostream & strmOut, int dirc) +{ + switch (dirc) + { + case kdircUnknown: strmOut << "??? "; break; + case kdircNeutral: strmOut << "ON "; break; + case kdircL: strmOut << "L "; break; + case kdircR: strmOut << "R "; break; + case kdircRArab: strmOut << "AR "; break; + case kdircEuroNum: strmOut << "EN "; break; + case kdircEuroSep: strmOut << "ES "; break; + case kdircEuroTerm: strmOut << "ET "; break; + case kdircArabNum: strmOut << "AN "; break; + case kdircComSep: strmOut << "CS "; break; + case kdircWhiteSpace: strmOut << "WS "; break; + case kdircBndNeutral: strmOut << "BN "; break; + case kdircNSM: strmOut << "NSM "; break; + case kdircLRO: strmOut << "LRO "; break; + case kdircRLO: strmOut << "RLO "; break; + case kdircLRE: strmOut << "LRE "; break; + case kdircRLE: strmOut << "RLE "; break; + case kdircPDF: strmOut << "PDF "; break; + case kdircPdfL: strmOut << "PDF-L "; break; + case kdircPdfR: strmOut << "PDF-R "; break; + case kdircLlb: strmOut << "L "; break; + case kdircRlb: strmOut << "R "; break; + default: LogInTable(strmOut, dirc); break; + } +} + +/*---------------------------------------------------------------------------------------------- + Write a breakweight code to the table. +----------------------------------------------------------------------------------------------*/ +void GrTableManager::LogBreakWeightInTable(std::ostream & strmOut, int lb) +{ + if (lb < 0) + { + lb = lb * -1; + switch (lb) + { + case klbWsBreak: strmOut << "-ws "; break; + case klbWordBreak: strmOut << "-word "; break; + case klbHyphenBreak: strmOut << "-intra "; break; + case klbLetterBreak: strmOut << "-lettr "; break; + case klbClipBreak: strmOut << "-clip "; break; + default: LogInTable(strmOut, lb*-1); break; + } + } + else + { + switch (lb) + { + case klbNoBreak: strmOut << "none "; break; + case klbWsBreak: strmOut << "ws "; break; + case klbWordBreak: strmOut << "word "; break; + case klbHyphenBreak: strmOut << "intra "; break; + case klbLetterBreak: strmOut << "letter "; break; + case klbClipBreak: strmOut << "clip "; break; + default: LogInTable(strmOut, lb); break; + } + } +} + +#endif // TRACING + +} // namespace gr |