diff options
Diffstat (limited to 'Build/source/libs/graphite-engine/src/segment/GrSlotState.cpp')
-rw-r--r-- | Build/source/libs/graphite-engine/src/segment/GrSlotState.cpp | 1411 |
1 files changed, 1411 insertions, 0 deletions
diff --git a/Build/source/libs/graphite-engine/src/segment/GrSlotState.cpp b/Build/source/libs/graphite-engine/src/segment/GrSlotState.cpp new file mode 100644 index 00000000000..892318912e1 --- /dev/null +++ b/Build/source/libs/graphite-engine/src/segment/GrSlotState.cpp @@ -0,0 +1,1411 @@ +/*--------------------------------------------------------------------*//*: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: GrSlotState.cpp +Responsibility: Sharon Correll +Last reviewed: Not yet. + +Description: + GrSlotState class implementation. +-------------------------------------------------------------------------------*//*:End Ignore*/ + +//:>******************************************************************************************** +//:> Include files +//:>******************************************************************************************** +#include "Main.h" + +#ifdef _MSC_VER +#pragma hdrstop +#endif +#undef THIS_FILE +DEFINE_THIS_FILE + +//:>******************************************************************************************** +//:> Forward declarations +//:>******************************************************************************************** + +//:>******************************************************************************************** +//:> Local Constants and static variables +//:>******************************************************************************************** + +namespace gr +{ + +//:>******************************************************************************************** +//:> Methods +//:>******************************************************************************************** + +/*---------------------------------------------------------------------------------------------- + Initialize slots. +----------------------------------------------------------------------------------------------*/ +// standard for pass 0 slots +void GrSlotState::Initialize(gid16 chw, GrEngine * pgreng, + GrFeatureValues fval, int ipass, int ichwSegOffset, int nUnicode) +{ + Assert(ipass == 0); + m_chwGlyphID = chw; + m_chwActual = kInvalidGlyph; + m_xysGlyphWidth = -1; + m_bStyleIndex = byte(fval.m_nStyleIndex); + u_intslot nullSlot; + nullSlot.pslot = NULL; + std::fill_n(PUserDefnBuf(), m_cnUserDefn, nullSlot); + std::fill_n(PCompRefBuf(), m_cnCompPerLig, nullSlot); + std::fill_n(PSlatiBuf(), m_cnCompPerLig, nullSlot); + u_intslot * pFeatBuf = PFeatureBuf(); + for (size_t i = 0; i < m_cnFeat; i++) + pFeatBuf[i].nValue = fval.m_rgnFValues[i]; + + m_ipassModified = ipass; + m_ichwSegOffset = ichwSegOffset; + m_nUnicode = nUnicode; + m_vpslotAssoc.clear(); + pgreng->InitSlot(this, nUnicode); + + switch (nUnicode) + { + case knLRM: m_spsl = kspslLRM; break; + case knRLM: m_spsl = kspslRLM; break; + case knLRO: m_spsl = kspslLRO; break; + case knRLO: m_spsl = kspslRLO; break; + case knLRE: m_spsl = kspslLRE; break; + case knRLE: m_spsl = kspslRLE; break; + case knPDF: m_spsl = kspslPDF; break; + default: + Assert(m_spsl == kspslNone); + m_spsl = kspslNone; + break; + } +} + +// line-break slots +void GrSlotState::Initialize(gid16 chw, GrEngine * pgreng, + GrSlotState * pslotFeat, int ipass, int ichwSegOffset) +{ + m_chwGlyphID = chw; + m_chwActual = kInvalidGlyph; + m_xysGlyphWidth = -1; + u_intslot nullSlot; + nullSlot.pslot = NULL; + std::fill_n(PUserDefnBuf(), m_cnUserDefn, nullSlot); + std::fill_n(PCompRefBuf(), m_cnCompPerLig, nullSlot); + std::fill_n(PSlatiBuf(), m_cnCompPerLig, nullSlot); + CopyFeaturesFrom(pslotFeat); + m_ipassModified = ipass; + m_ichwSegOffset = ichwSegOffset; + m_nUnicode = -1; + m_vpslotAssoc.clear(); + pgreng->InitSlot(this); + // Caller is responsible for setting m_spsl. +} + +// for inserting new slots after pass 0 (under-pos and unicode are irrelevant) +void GrSlotState::Initialize(gid16 chw, GrEngine * pgreng, + GrSlotState * pslotFeat, int ipass) +{ + m_chwGlyphID = chw; + m_chwActual = kInvalidGlyph; + m_xysGlyphWidth = -1; + u_intslot nullSlot; + nullSlot.pslot = NULL; + std::fill_n(PUserDefnBuf(), m_cnUserDefn, nullSlot); + std::fill_n(PCompRefBuf(), m_cnCompPerLig, nullSlot); + std::fill_n(PSlatiBuf(), m_cnCompPerLig, nullSlot); + CopyFeaturesFrom(pslotFeat); + m_ipassModified = ipass; + m_ichwSegOffset = kInvalid; + m_nUnicode = kInvalid; + m_vpslotAssoc.clear(); + pgreng->InitSlot(this); + m_spsl = kspslNone; +} + +/*---------------------------------------------------------------------------------------------- + The slot has been modified by the given pass and therefore is in a new state; + make a new SlotState initialized from the old one. +----------------------------------------------------------------------------------------------*/ +void GrSlotState::InitializeFrom(GrSlotState * pslotOld, int ipass) +{ + m_ipassModified = ipass; + m_pslotPrevState = pslotOld; + m_ichwSegOffset = kInvalid; + m_vpslotAssoc.clear(); + m_vpslotAssoc.push_back(pslotOld); + + m_dislotRootFixed = pslotOld->m_dislotRootFixed; + m_vdislotAttLeaves.resize(pslotOld->m_vdislotAttLeaves.size()); + for (size_t i = 0; i < pslotOld->m_vdislotAttLeaves.size(); i++) + m_vdislotAttLeaves[i] = pslotOld->m_vdislotAttLeaves[i]; + + GrSlotAbstract::CopyFrom(pslotOld); + + ////FixAttachmentTree(pslotOld); +} + +/*---------------------------------------------------------------------------------------------- + Copy the features and style information from the given slot. +----------------------------------------------------------------------------------------------*/ +void GrSlotState::CopyFeaturesFrom(GrSlotState * pslotSrc) +{ + m_bStyleIndex = pslotSrc->m_bStyleIndex; + Assert(m_cnFeat == pslotSrc->m_cnFeat); + std::copy(pslotSrc->PFeatureBuf(), pslotSrc->PFeatureBuf() + m_cnFeat, PFeatureBuf()); +} + +/*---------------------------------------------------------------------------------------------- + Copy the basic information. + Warning: this function will break if GrSlotState and subclasses are given virtual + methods. In that case, we will need to copy from the address of the first variable in + GrSlotAbstract. +----------------------------------------------------------------------------------------------*/ +void GrSlotAbstract::CopyFrom(GrSlotState * pslot) +{ + u_intslot * pnBufSave = m_prgnVarLenBuf; + *this = *pslot; + m_prgnVarLenBuf = pnBufSave; + Assert(m_prgnVarLenBuf); + std::copy(pslot->m_prgnVarLenBuf, pslot->m_prgnVarLenBuf + CExtraSpace(), m_prgnVarLenBuf); +} + +/*---------------------------------------------------------------------------------------------- + Return the ID of the actual glyph that will be used for output and metrics. This is the + same for most glyphs, but will be different for pseudo-glyphs. +----------------------------------------------------------------------------------------------*/ +gid16 GrSlotAbstract::ActualGlyphForOutput(GrTableManager * ptman) +{ + if (m_chwActual == kInvalidGlyph) + m_chwActual = ptman->ActualGlyphForOutput(m_chwGlyphID); + return m_chwActual; +} +/*---------------------------------------------------------------------------------------------- + We are replacing the old slot with the recipient. Replace the pointers in any attachment + root or attached leaf slots. + OBSOLETE +----------------------------------------------------------------------------------------------*/ +void GrSlotState::FixAttachmentTree(GrSlotState * pslotOld) +{ +#if 0 + pslotOld->m_vpslotAttLeaves.CopyTo(m_vpslotAttLeaves); + for (int islot = 0; islot < m_vpslotAttLeaves.Size(); islot++) + { + Assert(m_vpslotAttLeaves[islot]->m_pslotAttRoot == pslotOld); + m_vpslotAttLeaves[islot]->m_pslotAttRoot = this; + } + + m_pslotAttRoot = pslotOld->m_pslotAttRoot; + if (m_pslotAttRoot) + { + for (int islot = 0; islot < m_pslotAttRoot->m_vpslotAttLeaves.Size(); islot++) + { + if (m_pslotAttRoot->m_vpslotAttLeaves[islot] == pslotOld) + { + m_pslotAttRoot->m_vpslotAttLeaves.Delete(islot); + m_pslotAttRoot->m_vpslotAttLeaves.Push(this); + return; + } + } + Assert(false); // didn't find old slot in the list + } +#endif // 0 +} + +/*---------------------------------------------------------------------------------------------- + Make sure all the values are cached that are needed to be copied to the output slots +----------------------------------------------------------------------------------------------*/ +void GrSlotState::EnsureCacheForOutput(GrTableManager * ptman) +{ + // Make sure the actual glyph ID is set. + gid16 gidActual = ActualGlyphForOutput(ptman); + + // Make sure the glyph metrics are stored. + Font * pfont = ptman->State()->GetFont(); + if (IsLineBreak(ptman->LBGlyphID())) + { + GetGlyphMetric(pfont, kgmetAscent, 0); + GetGlyphMetric(pfont, kgmetDescent, 0); + m_xysGlyphX = 0; + m_xysGlyphY = 0; + m_xysGlyphHeight = 0; + m_xysGlyphWidth = 0; + m_xysAdvX = 0; + m_xysAdvY = 0; + m_fIsSpace = true; + } + else + { + //IsSpace(ptman); // cache this flag--doing bb-top below will do it + + GetGlyphMetric(pfont, kgmetAscent, gidActual); + GetGlyphMetric(pfont, kgmetDescent, gidActual); + GetGlyphMetric(pfont, kgmetBbTop, gidActual); + // call above will also cache all the values below + //GetGlyphMetric(pfont, kgmetBbBottom, gidActual); + //GetGlyphMetric(pfont, kgmetBbLeft, gidActual); + //GetGlyphMetric(pfont, kgmetBbRight, gidActual); + //GetGlyphMetric(pfont, kgmetAdvWidth, gidActual); + //GetGlyphMetric(pfont, kgmetAdvHeight, gidActual); + } +} + +/*---------------------------------------------------------------------------------------------- + Set the associations for the slot. +----------------------------------------------------------------------------------------------*/ +void GrSlotState::Associate(GrSlotState * pslot) +{ + m_vpslotAssoc.clear(); + m_vpslotAssoc.push_back(pslot); +} + +void GrSlotState::Associate(GrSlotState * pslotBefore, GrSlotState * pslotAfter) +{ + m_vpslotAssoc.clear(); + m_vpslotAssoc.push_back(pslotBefore); + m_vpslotAssoc.push_back(pslotAfter); +} + +void GrSlotState::Associate(std::vector<GrSlotState*> & vpslot) +{ + m_vpslotAssoc.clear(); + ///vpslot.CopyTo(m_vpslotAssoc); -- bug in CopyTo, so we do it ourselves: + for (size_t islot = 0; islot < vpslot.size(); ++islot) + { + m_vpslotAssoc.push_back(vpslot[islot]); + } + + // Set its character styles and features from the associated slot. + if (vpslot.size() > 0) // && !m_pslotPrevState + { + std::copy(m_vpslotAssoc[0]->PFeatureBuf(), + m_vpslotAssoc[0]->PFeatureBuf() + m_cnFeat, PFeatureBuf()); + } +} + +/*---------------------------------------------------------------------------------------------- + Clear the associations for the slot. +----------------------------------------------------------------------------------------------*/ +void GrSlotState::ClearAssocs() +{ + m_vpslotAssoc.clear(); +} + +/*---------------------------------------------------------------------------------------------- + Return a list of (ie, add into the vector) all the underlying associations, relative + to the official beginning of the segment. +----------------------------------------------------------------------------------------------*/ +void GrSlotState::AllAssocs(std::vector<int> & vichw) +{ + if (PassModified() == 0) + { + Assert(m_ichwSegOffset != kInvalid); + vichw.push_back(m_ichwSegOffset); + } + else + { + for (size_t i = 0; i < m_vpslotAssoc.size(); ++i) + m_vpslotAssoc[i]->AllAssocs(vichw); + } +} + +/*---------------------------------------------------------------------------------------------- + Return the underlying position of the before-association, relative to the official + beginning of the segment. May be -1, if this slot maps to a character in the previous + segment, or >= the length of the segment, if it maps to a character in the following + segment. +----------------------------------------------------------------------------------------------*/ +int GrSlotState::BeforeAssoc() +{ + GrSlotState * pslot = this; + while (pslot->PassModified() > 0) + { + pslot = pslot->RawBeforeAssocSlot(); + if (pslot == NULL) + { + return kPosInfinity; + } + } + Assert(pslot->m_ichwSegOffset != kInvalid); + return pslot->m_ichwSegOffset; +} + +/*---------------------------------------------------------------------------------------------- + Return the underlying position of the after-association, relative to the official + beginning of the segment. May be -1, if this slot maps to a character in the previous + segment, or >= the length of the segment, if it maps to a character in the following + segment. +----------------------------------------------------------------------------------------------*/ +int GrSlotState::AfterAssoc() +{ + GrSlotState * pslot = this; + while (pslot->PassModified() > 0) + { + pslot = pslot->RawAfterAssocSlot(); + if (pslot == NULL) + { + return kNegInfinity; + } + } + Assert(pslot->m_ichwSegOffset != kInvalid); + return pslot->m_ichwSegOffset; +} + +/*---------------------------------------------------------------------------------------------- + It is possible to get into a state where we are associated with an invalid state. + For instance, slot C may be associated with slots B1 and B2, but slot B1 is not associated + with any earlier slot, in which case slot C should remove the association with B1 and just + be associated with B2. +----------------------------------------------------------------------------------------------*/ +void GrSlotState::CleanUpAssocs() +{ + for (size_t i = 0; i < m_vpslotAssoc.size(); i++) + m_vpslotAssoc[i]->CleanUpAssocs(); + + GrSlotState * pslot; + + pslot = RawBeforeAssocSlot(); + while (pslot && BeforeAssoc() == kPosInfinity) + { + // The before association is bogus--delete it. + m_vpslotAssoc.erase(m_vpslotAssoc.begin()); + pslot = RawBeforeAssocSlot(); + } + + pslot = RawAfterAssocSlot(); + while (pslot && AfterAssoc() == kNegInfinity) + { + // The after association is bogus--delete it. + m_vpslotAssoc.pop_back(); + pslot = RawAfterAssocSlot(); + } +} + +/*---------------------------------------------------------------------------------------------- + Fill in the array of the given output slot with the underlying positions of the + ligature components, relative to the official beginning of the segment. + Positions may be < 0, if this slot maps to a character in the previous segment, + or >= the length of the segment, if it maps to a character in the following segment. +----------------------------------------------------------------------------------------------*/ +void GrSlotState::SetComponentRefsFor(GrSlotOutput * pslout, int slatiArg) +{ + if (PassModified() > 0) + { + GrSlotState * pslot; + int slati; + if (HasComponents()) + { + for (int iComponent = 0; iComponent < m_cnCompPerLig; iComponent++) + { + pslot = CompRefSlot(iComponent); + slati = Slati(iComponent); + if (pslot) + { + Assert(slati != -1); + Assert(PassModified() >= pslot->PassModified()); + pslot->SetComponentRefsFor(pslout, slati); + } + } + } + else + { + // Follow the chain back through the passes. + pslot = RawBeforeAssocSlot(); + if (pslot) + { + Assert(PassModified() >= pslot->PassModified()); + // Passing slati here is definitely needed for our Arabic font: for instance when + // you type something like "mla", so the l is transformed into a temporary glyph + // before creating the ligature. However, this seems to have broken something, + // which I will probably find eventually. :-( + pslot->SetComponentRefsFor(pslout, slatiArg); + //pslot->SetComponentRefsFor(pslout, -1); + } + } + } + else + { + Assert(m_ichwSegOffset != kInvalid); + pslout->AddComponentReference(m_ichwSegOffset, slatiArg); + } +} + +/*---------------------------------------------------------------------------------------------- + Fill in the vector with the underlying positions of the + ligature components, relative to the official beginning of the segment. + Positions may be < 0, if this slot maps to a character in the previous segment, + or >= the length of the segment, if it maps to a character in the following segment. + ENHANCE: merge with method above. +----------------------------------------------------------------------------------------------*/ +void GrSlotState::AllComponentRefs(std::vector<int> & vichw) +{ + if (PassModified() > 0) + { + GrSlotState * pslot; + if (HasComponents()) + { + for (int iComponent = 0; iComponent < m_cnCompPerLig; iComponent++) + { + pslot = CompRefSlot(iComponent); + if (pslot) + { + Assert(PassModified() >= pslot->PassModified()); + pslot->AllComponentRefs(vichw); + } + } + } + else + { + // ENHANCE: Strictly speaking we should probably have separate before- + // and after-lists for the components, but I think it would be pretty + // rare to have both deletion and ligatures overlapping, so I'm not + // going to bother with it for now. + //for (int islot = 0; islot < AssocsSize(); islot++) + for (int islot = 0; islot < 1; islot++) + { + m_vpslotAssoc[islot]->AllComponentRefs(vichw); + } + } + } + else + { + Assert(m_ichwSegOffset != kInvalid); + vichw.push_back(m_ichwSegOffset); + } +} + +/*---------------------------------------------------------------------------------------------- + Get the value of the component.???.ref attribute for the slot. + Note that 'i' is the local index for the component as defined for this glyph. +----------------------------------------------------------------------------------------------*/ +GrSlotState * GrSlotAbstract::CompRefSlot(int i) +{ + Assert(i < m_cnCompPerLig); + if (i < m_cnCompPerLig) + return CompRef(i); + else + return NULL; +} + +/*---------------------------------------------------------------------------------------------- + Set the value of the component.???.ref attribute for the slot. +----------------------------------------------------------------------------------------------*/ +void GrSlotState::SetCompRefSlot(GrTableManager * ptman, int slati, GrSlotState * pslotComp) +{ + // Convert the global identifer for the component to the index for this glyph. + int icomp = ptman->ComponentIndexForGlyph(GlyphID(), slati); + Assert(icomp != -1); + if (icomp == -1) + // Component not defined for this glyph--ignore. + return; + Assert(icomp < m_cnCompPerLig); + + if (m_fHasComponents == false) + { + // None have been set yet; initialize them. + for (int iLoop = 0; iLoop < m_cnCompPerLig; iLoop++) + { + SetCompRef(iLoop, NULL); + SetSlati(iLoop, -1); + } + } + + m_fHasComponents = true; + int iLoop; + for (iLoop = 0; iLoop < m_cnCompPerLig; iLoop++) + { + if (Slati(iLoop) == slati) + break; + if (Slati(iLoop) == -1) + break; + } + //if (icomp < m_cnCompPerLig) + if (iLoop < m_cnCompPerLig) + { + //SetCompRef(icomp, pslotComp); + SetCompRef(iLoop, pslotComp); + SetSlati(iLoop, slati); + } +} + +/*---------------------------------------------------------------------------------------------- + Return the underlying position for the slot, relative to the official beginning of the + segment. +----------------------------------------------------------------------------------------------*/ +int GrSlotState::SegOffset() +{ + if (m_ichwSegOffset == kInvalid) + { + Assert(m_pslotPrevState); + Assert(m_ipassModified > 0); + return m_pslotPrevState->SegOffset(); + } + else + { + Assert(m_pslotPrevState == NULL); + Assert(m_ipassModified == 0); + return m_ichwSegOffset; + } +} + +/*---------------------------------------------------------------------------------------------- + Return the value of the glyph attribute (in design units, if this is a measurement). +----------------------------------------------------------------------------------------------*/ +int GrSlotState::GlyphAttrValueEmUnits(GrTableManager * ptman, int nAttrID) +{ + return ptman->GlyphAttrValue(m_chwGlyphID, nAttrID); +} + +/*---------------------------------------------------------------------------------------------- + Return the value of the glyph metric, in design coordinates (ie, based on the font's + em-square). +----------------------------------------------------------------------------------------------*/ +int GrSlotState::GlyphMetricEmUnits(GrTableManager * ptman, int nMetricID) +{ + int mValue; + if (ptman->State()->GetFont()) + { + // Get the actual metric, possibly adjusted for hinting, then convert back to + // design units. + float xysValue = GlyphMetricLogUnits(ptman, nMetricID); + mValue = ptman->LogToEmUnits(xysValue); + } + else + // Ask the font directly. + ////mValue = ??? + mValue = 0; + + return mValue; +} + +/*---------------------------------------------------------------------------------------------- + Return the value of the glyph attribute, converted to source device coordinates. + The attribute is assumed to be one whose value is a measurement. +----------------------------------------------------------------------------------------------*/ +float GrSlotState::GlyphAttrValueLogUnits(GrTableManager * ptman, int nAttrID) +{ + int mValue = GlyphAttrValueEmUnits(ptman, nAttrID); + float xysRet = ptman->EmToLogUnits(mValue); + return xysRet; +} + +/*---------------------------------------------------------------------------------------------- + Return the value of the glyph metric, in the source device's logical units. +----------------------------------------------------------------------------------------------*/ +float GrSlotState::GlyphMetricLogUnits(GrTableManager * ptman, int nMetricID) +{ +#ifdef OLD_TEST_STUFF + if (ptman->GlyphTable() == NULL) + return 0; +#endif // OLD_TEST_STUFF + +#ifdef _DEBUG + if (IsLineBreak(ptman->LBGlyphID())) + { + Warn("Getting metrics of line-break slot"); + } +#endif // _DEBUG + if (IsLineBreak(ptman->LBGlyphID())) + { + return 0; + } + + return GetGlyphMetric(ptman->State()->GetFont(), nMetricID, + ActualGlyphForOutput(ptman)); +} + + +float GrSlotOutput::GlyphMetricLogUnits(Font * pfont, int nMetricID) +{ + Assert(m_chwActual != kInvalidGlyph); + if (m_chwActual == kInvalidGlyph) + return 0; + + return GetGlyphMetric(pfont, nMetricID, m_chwActual); +} + +float GrSlotOutput::GlyphMetricLogUnits(int gmet) +{ + // When the font is not passed as an argument, the values better be cached! + + switch (gmet) + { // There may be off by one errors below, depending on what width and height mean + case kgmetLsb: + return m_xysGlyphX; + case kgmetRsb: + return (m_xysAdvX - m_xysGlyphX - m_xysGlyphWidth); + case kgmetBbTop: + return m_xysGlyphY; + case kgmetBbBottom: + return (m_xysGlyphY - m_xysGlyphHeight); + case kgmetBbLeft: + return m_xysGlyphX; + case kgmetBbRight: + return (m_xysGlyphX + m_xysGlyphWidth); + case kgmetBbHeight: + return m_xysGlyphHeight; + case kgmetBbWidth: + return m_xysGlyphWidth; + case kgmetAdvWidth: + return m_xysAdvX; + case kgmetAdvHeight: + return m_xysAdvY; + default: + Warn("GetGlyphMetric was asked for an illegal metric."); + }; + + return 0; +} + + +float GrSlotAbstract::GetGlyphMetric(Font * pfont, int nMetricID, gid16 chwGlyphID) +{ + //GrResult res; + float xysRet = 0; + + GlyphMetric gmet = GlyphMetric(nMetricID); + + float yAscent, yDescent; + gr::Point ptAdvances; + gr::Rect rectBb; + + if (kgmetAscent == gmet) + { + if (m_xysFontAscent != -1) + return m_xysFontAscent; + //GrResult res = pgg->get_FontAscent(&xysRet); + //if (ResultFailed(res)) + //{ + // WARN(res); + // return 0; + //} + pfont->getFontMetrics(&yAscent); + m_xysFontAscent = xysRet; + if (pfont) + m_xysFontAscent = yAscent; + return xysRet; + } + + if (kgmetDescent == gmet) + { + if (m_xysFontDescent != -1) + return m_xysFontDescent; + //GrResult res = pgg->get_FontDescent(&xysRet); + //if (ResultFailed(res)) + //{ + // WARN(res); + // return 0; + // m_xysFontDescent = xysRet; + //} + pfont->getFontMetrics(NULL, &yDescent); + m_xysFontDescent = xysRet; + if (pfont) + m_xysFontDescent = yDescent; + return xysRet; + } + + if (m_xysGlyphWidth == -1) + { + //res = pgg->GetGlyphMetrics(chwGlyphID, &m_xysGlyphWidth, &m_xysGlyphHeight, + // &m_xysGlyphX, &m_xysGlyphY, &m_xysAdvX, &m_xysAdvY); + //if (ResultFailed(res)) + //{ + // //WARN(res); + // //return 0; + // ThrowHr(WarnHr(res)); + //} + + pfont->getGlyphMetrics(chwGlyphID, rectBb, ptAdvances); + + m_xysGlyphX = rectBb.left; + m_xysGlyphY = rectBb.top; + m_xysGlyphWidth = (rectBb.right - rectBb.left); + m_xysGlyphHeight = (rectBb.top - rectBb.bottom); + m_xysAdvX = ptAdvances.x; + m_xysAdvY = ptAdvances.y; + + m_fIsSpace = (0 == m_xysGlyphX && 0 == m_xysGlyphY); // should agree with test done in IsSpace() below + + if (m_fIsSpace) + { + // White space glyph - only case where nGlyphX == nGlyphY == 0 + // nGlyphWidth & nGlyphHeight are always set to 16 for unknown reasons, so correct. + m_xysGlyphWidth = m_xysGlyphHeight = 0; + } + } + + switch (gmet) + { // There may be off by one errors below, depending on what width and height mean + case kgmetLsb: + return m_xysGlyphX; + case kgmetRsb: + return (m_xysAdvX - m_xysGlyphX - m_xysGlyphWidth); + case kgmetBbTop: + return m_xysGlyphY; + case kgmetBbBottom: + return (m_xysGlyphY - m_xysGlyphHeight); + case kgmetBbLeft: + return m_xysGlyphX; + case kgmetBbRight: + return (m_xysGlyphX + m_xysGlyphWidth); + case kgmetBbHeight: + return m_xysGlyphHeight; + case kgmetBbWidth: + return m_xysGlyphWidth; + case kgmetAdvWidth: + return m_xysAdvX; + case kgmetAdvHeight: + return m_xysAdvY; + default: + Warn("GetGlyphMetric was asked for an illegal metric."); + }; + + return 0; +} + +/*---------------------------------------------------------------------------------------------- + Test the glyph id to see if it is a white space glyph. +----------------------------------------------------------------------------------------------*/ +int GrSlotState::IsSpace(GrTableManager * ptman) +{ + gid16 gidActual = ActualGlyphForOutput(ptman); + + ////if (m_xysGlyphWidth == -1) + ////{ + //// res = ptman->State()->GraphicsObject()->GetGlyphMetrics(gidActual, + //// &m_xysGlyphWidth, &m_xysGlyphHeight, + //// &m_xysGlyphX, &m_xysGlyphY, &m_xysAdvX, &m_xysAdvY); + //// if (ResultFailed(res)) + //// { + //// WARN(res); + //// return 2; // will test as true but can be distinguished by separate value + //// } + + //// gr::Point ptAdvances; + //// gr::Rect rectBb; + //// ptman->State()->Font()->getGlyphMetrics(gidActual, rectBb, ptAdvances); + ////} + + GetGlyphMetric(ptman->State()->GetFont(), kgmetBbLeft, gidActual); + // One call is enough to cache the information. + //GetGlyphMetric(ptman->State()->Font(), kgmetBbBottom, gidActual); + + // should agree with test done in GetGlyphMetric() above + //////m_fIsSpace = (0 == m_xysGlyphX && 0 == m_xysGlyphY); + + return m_fIsSpace; +} + +bool GrSlotOutput::IsSpace() +{ + return m_fIsSpace; +} + +/*---------------------------------------------------------------------------------------------- + If any of the attach attributes have been modified, fix things up. Set up the attachment + tree, and set any needed default positions. Zap the cached positions of any following + glyphs in the stream. + + @param psstrm - the stream in which the modifications were made + @param islotThis - the index of the attached (leaf) slot in the stream; + -1 if we don't know +----------------------------------------------------------------------------------------------*/ +void GrSlotState::HandleModifiedPosition(GrTableManager * ptman, + GrSlotStream * psstrmIn, GrSlotStream * psstrmOut, int islotThis) +{ + if (!m_fAttachMod && !m_fShiftMod) + return; + + if (islotThis == -1) + { + for (int islot = 0; islot < psstrmOut->WritePos(); islot++) + { + if (psstrmOut->SlotAt(islot) == this) + { + islotThis = islot; + break; + } + } + Assert(islotThis > -1); + } + + if (m_fAttachMod) + { + // Attachments. + + // Note that it doesn't make sense to attach a slot to itself, so if the value of + // the attach.to attribute is 0, that means clear the attachment. + GrSlotState * pslotNewRoot = AttachRoot(psstrmOut); + + AttachToRoot(ptman, psstrmOut, pslotNewRoot); + + if (pslotNewRoot) + { + // If this is an attachment with no positions, attach the two glyphs side by side + // in the appropriate order. + bool fRtl = ((pslotNewRoot->PostBidiDirLevel(ptman) % 2) != 0); + if ((fRtl && m_srAttachTo < 0) || (!fRtl && m_srAttachTo > 0)) + { + // The root is on the right, the leaf is on the left. + if (m_mAttachAtX == kNotYetSet && m_nAttachAtGpoint == kNotYetSet) + m_mAttachAtX = 0; + if (m_mAttachWithX == kNotYetSet && m_nAttachWithGpoint == kNotYetSet) + m_mAttachWithX = short(AdvanceX(ptman)); + } + else + { + // The root is on the left, the leaf is on the right. + if (m_mAttachAtX == kNotYetSet && m_nAttachAtGpoint == kNotYetSet) + m_mAttachAtX = short(pslotNewRoot->AdvanceX(ptman)); + if (m_mAttachWithX == kNotYetSet && m_nAttachWithGpoint == kNotYetSet) + m_mAttachWithX = 0; + } + } + } + else + { + // Shifting, or changing the advance width. + Assert(m_fShiftMod); + EnsureLocalAttachmentTree(ptman, psstrmIn, psstrmOut, islotThis); + ZapMetricsAndPositionDownToBase(psstrmOut); + ZapMetricsOfLeaves(psstrmOut); + } + + if (psstrmOut->m_ipass == ptman->NumberOfPasses() - 1) + ptman->InitPosCache(); // cached position is most likely no longer valid + + // Invalidate the positions of this and any following glyphs. + for (int islot = islotThis + 1; islot < psstrmOut->WritePos(); islot++) + psstrmOut->SlotAt(islot)->ZapPosition(); + + m_fAttachMod = false; + m_fShiftMod = false; +} + +/*---------------------------------------------------------------------------------------------- + The shift attribute of a slot has been modified. Make sure any slots that are part of the + same attachment cluster are local to this stream. The reason for this is so that the + position calculations stay consistent within the stream. +----------------------------------------------------------------------------------------------*/ +void GrSlotState::EnsureLocalAttachmentTree(GrTableManager * ptman, + GrSlotStream * psstrmIn, GrSlotStream * psstrmOut, int islotThis) +{ + if (m_dislotRootFixed) + { + GrSlotState * pslotRoot = SlotAtOffset(psstrmOut, m_dislotRootFixed); + psstrmOut->EnsureLocalCopy(ptman, pslotRoot, psstrmIn); + pslotRoot = SlotAtOffset(psstrmOut, m_dislotRootFixed); // get the new one! + pslotRoot->EnsureLocalAttachmentTree(ptman, psstrmIn, psstrmOut, islotThis + m_dislotRootFixed); + } + for (size_t islot = 0; islot < m_vdislotAttLeaves.size(); islot++) + { + GrSlotState * pslotLeaf = SlotAtOffset(psstrmOut, m_vdislotAttLeaves[islot]); + psstrmOut->EnsureLocalCopy(ptman, pslotLeaf, psstrmIn); + } +} + +/*---------------------------------------------------------------------------------------------- + The recipient slot is being attached to the argument slot. + NOTE: the caller is responsible to zap the cached positions of following glyphs + in the stream. +----------------------------------------------------------------------------------------------*/ +void GrSlotState::AttachToRoot(GrTableManager * ptman, GrSlotStream * psstrm, + GrSlotState * pslotNewRoot) +{ + GrSlotState * pslotOldRoot = (m_dislotRootFixed == 0) ? + NULL : + SlotAtOffset(psstrm, m_dislotRootFixed); + + if (pslotOldRoot) + { + if (pslotOldRoot != pslotNewRoot) + pslotOldRoot->RemoveLeaf(m_dislotRootFixed); + pslotOldRoot->ZapMetricsAndPositionDownToBase(psstrm); + pslotOldRoot->ZapMetricsOfLeaves(psstrm); + } + + ZapCompositeMetrics(); + + if (pslotNewRoot && pslotNewRoot != pslotOldRoot) + { + pslotNewRoot->AddLeaf(m_srAttachTo); + pslotNewRoot->ZapMetricsAndPositionDownToBase(psstrm); + pslotNewRoot->ZapMetricsOfLeaves(psstrm); + } + + m_dislotRootFixed = m_srAttachTo; +} + +/*---------------------------------------------------------------------------------------------- + Return the absolute position of the glyph, relative to the start of the segment, + in font design units. +----------------------------------------------------------------------------------------------*/ +void GrSlotState::Position(GrTableManager * ptman, + GrSlotStream * psstrmOut, int * pmXPos, int * pmYPos) +{ + Assert(!m_fAttachMod); // the attachment tree should be set up + Assert(!m_fShiftMod); + + float xsWidth, xsVisWidth; + if (m_xsPositionX == kNegInfFloat || m_ysPositionY == kNegInfFloat) + ptman->CalcPositionsUpTo(psstrmOut->m_ipass, this, &xsWidth, &xsVisWidth); + + *pmXPos = ptman->LogToEmUnits(m_xsPositionX); + *pmYPos = ptman->LogToEmUnits(m_ysPositionY); +} + +/*---------------------------------------------------------------------------------------------- + Recalculate the metrics for this slot, which has attachments on it (or possibly + did in the past). +----------------------------------------------------------------------------------------------*/ +void GrSlotState::AdjustRootMetrics(GrTableManager * ptman, GrSlotStream * psstrm) +{ + Assert(m_dislotRootFixed == m_srAttachTo); + GrSlotState * pslotRoot = AttachRoot(psstrm); + CalcRootMetrics(ptman, psstrm, kPosInfinity); + if (pslotRoot) + pslotRoot->AdjustRootMetrics(ptman, psstrm); +} + +/*---------------------------------------------------------------------------------------------- + Calculate the composite metrics for this slot. + + @param psstrm - stream for which we are calculating it + @param nLevel - attachment level we are asking for; kPosInifinity means all levels + @param fThorough - true: do a thorough recalculation; false: don't recalculate + metrics for leaves (are they assumed to be accurate???) + --currently not used +----------------------------------------------------------------------------------------------*/ +void GrSlotState::CalcCompositeMetrics(GrTableManager * ptman, GrSlotStream * psstrm, + int nLevel, bool fThorough) +{ + if (m_nCompositeLevel == nLevel) + return; + + if (fThorough) + { + Assert(m_dislotRootFixed == m_srAttachTo); + GrSlotState * pslotRoot = AttachRoot(psstrm); + + InitMetrics(ptman, pslotRoot); + + for (size_t islot = 0; islot < m_vdislotAttLeaves.size(); islot++) + { + GrSlotState * pslotLeaf = SlotAtOffset(psstrm, m_vdislotAttLeaves[islot]); + if (pslotLeaf->AttachLevel() <= nLevel) + pslotLeaf->CalcCompositeMetrics(ptman, psstrm, nLevel, fThorough); + else + // this slot will be ignored in the composite metrics + pslotLeaf->ZapRootMetrics(); + } + CalcRootMetrics(ptman, psstrm, nLevel); + + m_nCompositeLevel = nLevel; + } + else + { + Assert(false); // for now + + // Don't bother with the leaves. + InitRootMetrics(ptman); + } +} + +/*---------------------------------------------------------------------------------------------- + Calculate the metrics for this node and all its leaf nodes. +----------------------------------------------------------------------------------------------*/ +void GrSlotState::CalcRootMetrics(GrTableManager * ptman, GrSlotStream * psstrm, int nLevel) +{ + for (size_t idislot = 0; idislot < m_vdislotAttLeaves.size(); idislot++) + { + GrSlotState * pslot = SlotAtOffset(psstrm, m_vdislotAttLeaves[idislot]); + if (pslot->AttachLevel() > nLevel) + continue; + + m_xsClusterXOffset = min(m_xsClusterXOffset, pslot->m_xsClusterXOffset); + if (!pslot->m_fIgnoreAdvance) + { + m_xsClusterAdv = max( + m_xsClusterAdv, + pslot->m_xsClusterAdv + m_xsRootShiftX); + } + m_xsClusterBbLeft = min(m_xsClusterBbLeft, pslot->m_xsClusterBbLeft); + m_xsClusterBbRight = max(m_xsClusterBbRight, pslot->m_xsClusterBbRight); + m_ysClusterBbTop = max(m_ysClusterBbTop, pslot->m_ysClusterBbTop); + m_ysClusterBbBottom = min(m_ysClusterBbBottom, pslot->m_ysClusterBbBottom); + } +} + +/*---------------------------------------------------------------------------------------------- + Reset the cluster metrics of this slot. +----------------------------------------------------------------------------------------------*/ +void GrSlotState::InitMetrics(GrTableManager * ptman, GrSlotState * pslotRoot) +{ + InitLeafMetrics(ptman, pslotRoot); + InitRootMetrics(ptman); +} + +/*---------------------------------------------------------------------------------------------- + Initialize the variables that store the offsets of just this node (ignoring any of its + leaves) relative to the cluster base. +----------------------------------------------------------------------------------------------*/ +void GrSlotState::InitLeafMetrics(GrTableManager * ptman, GrSlotState * pslotRoot) +{ + float xsShiftX = ptman->EmToLogUnits(ShiftX()); + float ysShiftY = ptman->EmToLogUnits(ShiftY()); + + if (ptman->RightToLeft()) + xsShiftX *= -1; + + if (IsBase()) + { + // These two are actually meaningless numbers, for the base, but set them + // to something reasonable. + m_xsOffsetX = xsShiftX; + m_ysOffsetY = ysShiftY; + + m_xsRootShiftX = xsShiftX; + m_ysRootShiftY = ysShiftY; + Assert(!IsLineBreak(ptman->LBGlyphID()) + || (m_xsRootShiftX == 0 && m_ysRootShiftY == 0)); + return; + } + + Assert(!IsLineBreak(ptman->LBGlyphID())); + + // Hint-adjusted logical coordinates equivalent to attach.at and attach.with attributes. + // If attach.at or attach.with attributes were unset, the defaults for a side-by-side + // attachment should have been supplied in HandleModifiedPosition(). + float xsAttAtX, ysAttAtY, xsAttWithX, ysAttWithY; + AttachLogUnits(ptman, pslotRoot, &xsAttAtX, &ysAttAtY, &xsAttWithX, &ysAttWithY); + + m_xsOffsetX = xsAttAtX - xsAttWithX; + m_xsOffsetX += pslotRoot->m_xsOffsetX; + m_xsOffsetX += xsShiftX; + + m_ysOffsetY = ysAttAtY - ysAttWithY; + m_ysOffsetY += pslotRoot->m_ysOffsetY; + m_ysOffsetY += ysShiftY; + + // Cumulative effect of shifts on this and all base nodes: + m_xsRootShiftX = pslotRoot->m_xsRootShiftX + xsShiftX; + m_ysRootShiftY = pslotRoot->m_ysRootShiftY + ysShiftY; +} + +/*---------------------------------------------------------------------------------------------- + Initialize the variables that store the offsets of this node taking into account its + leaves; these are relative to the cluster base. +----------------------------------------------------------------------------------------------*/ +void GrSlotState::InitRootMetrics(GrTableManager * ptman) +{ + if (IsLineBreak(ptman->LBGlyphID())) + { + m_fIgnoreAdvance = true; + m_xsClusterXOffset = 0; + m_xsClusterAdv = 0; + m_xsClusterBbLeft = 0; + m_xsClusterBbRight = 0; + m_ysClusterBbTop = 0; + m_ysClusterBbBottom = 0; + return; + } + + float xsAdvanceX = ptman->EmToLogUnits(AdvanceX(ptman)); + + // If the glyph's advance width is zero, then we NEVER want it to have any affect, + // even if the glyph is attached way out to the right of its base's advance. + m_fIgnoreAdvance = (xsAdvanceX == 0); + + float xsBbLeft = GlyphMetricLogUnits(ptman, kgmetBbLeft); + float xsBbRight = GlyphMetricLogUnits(ptman, kgmetBbRight); + float ysBbTop = GlyphMetricLogUnits(ptman, kgmetBbTop); + float ysBbBottom = GlyphMetricLogUnits(ptman, kgmetBbBottom); + + // Any shifts should be ignored for the sake of calculating actual position or width, + // hence we subtract the cumulative effect of the shifts. + m_xsClusterXOffset = m_xsOffsetX - m_xsRootShiftX; + m_xsClusterAdv = m_xsOffsetX + xsAdvanceX - m_xsRootShiftX; + + m_xsClusterBbLeft = m_xsOffsetX + xsBbLeft; + m_xsClusterBbRight = m_xsOffsetX + xsBbRight; + m_ysClusterBbTop = m_ysOffsetY + ysBbTop; + m_ysClusterBbBottom = m_ysOffsetY + ysBbBottom; +} + +/*---------------------------------------------------------------------------------------------- + X-offset of a single glyph relative to the previous advance position. +----------------------------------------------------------------------------------------------*/ +float GrSlotState::GlyphXOffset(GrSlotStream * psstrm, float fakeItalicRatio) +{ + float xsRet = Base(psstrm)->ClusterRootOffset() + m_xsOffsetX; + + // fake an italic slant + xsRet += m_ysOffsetY * fakeItalicRatio; + + return xsRet; +} + +/*---------------------------------------------------------------------------------------------- + Y-offsets of a single glyph relative to the previous advance position. +----------------------------------------------------------------------------------------------*/ +float GrSlotState::GlyphYOffset(GrSlotStream * psstrm) +{ + return m_ysOffsetY; +} + +/*---------------------------------------------------------------------------------------------- + Return the offset of the last leaf of the cluster, relative to this slot, which is + the base. Return kNegInfinity if there are not enough slots in the stream to tell. +----------------------------------------------------------------------------------------------*/ +int GrSlotState::LastLeafOffset(GrSlotStream * psstrm) +{ + int islotRet = 0; + for (size_t idislot = 0; idislot < m_vdislotAttLeaves.size(); idislot++) + { + int dislot = m_vdislotAttLeaves[idislot]; + Assert(dislot != 0); + if (!psstrm->HasSlotAtPosPassIndex(PosPassIndex() + dislot)) + return kNegInfinity; + GrSlotState * pslotLeaf = SlotAtOffset(psstrm, dislot); + int islotTmp = pslotLeaf->LastLeafOffset(psstrm); + if (islotTmp == kNegInfinity) + return kNegInfinity; + islotRet = max(islotRet, (dislot + islotTmp)); + } + return islotRet; +} + +/*---------------------------------------------------------------------------------------------- + Return the attach positions in the device context's logical units, + adjusted for hinting if possible. + + Note that m_nAttachAt/WithGpoint = 0 is always an invalid value (resulting from a + glyph attribute that was defined in terms of x/y coordinates that didn't map to an + actual on-curve point). Therefore the x/y coordinates should be used to do the + attachment. In the case where we actually want point #0 on the curve, + m_nAttachAt/WithGpoint will have the special value 'kGpointZero' (the glyph attribute + is defined this way). +----------------------------------------------------------------------------------------------*/ +void GrSlotState::AttachLogUnits(GrTableManager * ptman, GrSlotState * pslotRoot, + float * pxsAttAtX, float * pysAttAtY, + float * pxsAttWithX, float * pysAttWithY) +{ + if (m_nAttachAtGpoint == kNotYetSet || m_nAttachAtGpoint == 0) + { + // Use x- and y-coordinates; no adjustment for hinting is done. + int mX = m_mAttachAtX + m_mAttachAtXOffset; + int mY = m_mAttachAtY + m_mAttachAtYOffset; + + *pxsAttAtX = ptman->EmToLogUnits(mX); + *pysAttAtY = ptman->EmToLogUnits(mY); + } + else + { + // Look up the actual on-curve point. + int nGpoint = m_nAttachAtGpoint; + if (nGpoint == kGpointZero) + nGpoint = 0; + bool fImpl = ptman->GPointToXY(pslotRoot->GlyphID(), nGpoint, pxsAttAtX, pysAttAtY); + + // Debuggers: + //int mXTmpAt = m_mAttachAtX + m_mAttachAtXOffset; + //int mYTmpAt = m_mAttachAtY + m_mAttachAtYOffset; + //int xsAttAtXTmp = ptman->EmToLogUnits(mXTmpAt); + //int ysAttAtYTmp = ptman->EmToLogUnits(mYTmpAt); + //fImpl = false; + + if (!fImpl) + { + // Fall back to using x- and y-coordinates; no adjustment for hinting. + int mX = m_mAttachAtX + m_mAttachAtXOffset; + int mY = m_mAttachAtY + m_mAttachAtYOffset; + *pxsAttAtX = ptman->EmToLogUnits(mX); + *pysAttAtY = ptman->EmToLogUnits(mY); + } + else + { + // Adjust by offsets. + *pxsAttAtX += ptman->EmToLogUnits(m_mAttachAtXOffset); + *pysAttAtY += ptman->EmToLogUnits(m_mAttachAtYOffset); + } + } + + if (m_nAttachWithGpoint == kNotYetSet || m_nAttachWithGpoint == 0) + { + // Use x- and y-coordinates; no adjustment for hinting is done. + int mX = m_mAttachWithX + m_mAttachWithXOffset; + int mY = m_mAttachWithY + m_mAttachWithYOffset; + + *pxsAttWithX = ptman->EmToLogUnits(mX); + *pysAttWithY = ptman->EmToLogUnits(mY); + } + else + { + // Look up the actual on-curve point. + int nGpoint = m_nAttachWithGpoint; + if (nGpoint == kGpointZero) + nGpoint = 0; + bool fImpl = ptman->GPointToXY(m_chwGlyphID, nGpoint, pxsAttWithX, pysAttWithY); + + // Debuggers: + //int mXTmpWith = m_mAttachWithX + m_mAttachWithXOffset; + //int mYTmpWith = m_mAttachWithY + m_mAttachWithYOffset; + //int xsAttWithXTmp = ptman->EmToLogUnits(mXTmpWith); + //int ysAttWithYTmp = ptman->EmToLogUnits(mYTmpWith); + //fImpl = false; + + if (!fImpl) + { + // Fall back to using x- and y-coordinates; no adjustment for hinting. + int mX = m_mAttachWithX + m_mAttachWithXOffset; + int mY = m_mAttachWithY + m_mAttachWithYOffset; + *pxsAttWithX = ptman->EmToLogUnits(mX); + *pysAttWithY = ptman->EmToLogUnits(mY); + } + else + { + // Adjust by offsets. + *pxsAttWithX += ptman->EmToLogUnits(m_mAttachWithXOffset); + *pysAttWithY += ptman->EmToLogUnits(m_mAttachWithYOffset); + } + } +} + +/*---------------------------------------------------------------------------------------------- + Return the slot that is 'dislot' slots away from this slot in the given stream. + Only valid for streams that are the input to or output of positioning passes. +----------------------------------------------------------------------------------------------*/ +GrSlotState * GrSlotState::SlotAtOffset(GrSlotStream * psstrm, int dislot) +{ + Assert(psstrm->m_fUsedByPosPass); + return psstrm->SlotAtPosPassIndex(PosPassIndex() + dislot); +} + +/*---------------------------------------------------------------------------------------------- + If the direction level has not been calculated at this point, assume it is the + top direction. This should only happen if there was no bidi pass to set it. + This method should only be called by the positioning passes; it assumes any bidi + pass has been run. +----------------------------------------------------------------------------------------------*/ +int GrSlotState::PostBidiDirLevel(GrTableManager * ptman) +{ + if (m_nDirLevel == -1) + { + Assert(!ptman->HasBidiPass()); + return ptman->TopDirectionLevel(); + } + return m_nDirLevel; +} + +/*---------------------------------------------------------------------------------------------- + Return true if this glyph represents a LRM code. +----------------------------------------------------------------------------------------------*/ +bool GrSlotState::IsLrm() +{ + if (PassModified() == 0) + return (m_nUnicode == knLRM); + return m_pslotPrevState->IsLrm(); +} + +/*---------------------------------------------------------------------------------------------- + Return true if this glyph represents a RLM code. +----------------------------------------------------------------------------------------------*/ +bool GrSlotState::IsRlm() +{ + if (PassModified() == 0) + return (m_nUnicode == knRLM); + return m_pslotPrevState->IsRlm(); +} + + +/*---------------------------------------------------------------------------------------------- + Used by GlyphInfo +----------------------------------------------------------------------------------------------*/ +//float GrSlotOutput::AdvanceX(Segment * pseg) +//{ +// return pseg->EmToLogUnits(m_mAdvanceX); +//} +//float GrSlotOutput::AdvanceY(Segment * pseg) +//{ +// return pseg->EmToLogUnits(m_mAdvanceY); +//} +float GrSlotOutput::MaxStretch(Segment * pseg, int level) +{ + Assert(level == 0); + return (level == 0) ? pseg->EmToLogUnits(m_mJStretch0) : 0; +} +float GrSlotOutput::MaxShrink(Segment * pseg, int level) +{ + Assert(level == 0); + return (level == 0) ? pseg->EmToLogUnits(m_mJShrink0) : 0; +} +float GrSlotOutput::StretchStep(Segment * pseg, int level) +{ + Assert(level == 0); + return (level == 0) ? pseg->EmToLogUnits(m_mJStep0) : 0; +} +int GrSlotOutput::JustWeight(int level) +{ + Assert(level == 0); + return (level == 0) ? m_nJWeight0 : 0; +} +float GrSlotOutput::JustWidth(Segment * pseg, int level) +{ + Assert(level == 0); + return (level == 0) ? pseg->EmToLogUnits(m_mJWidth0) : 0; +} +float GrSlotOutput::MeasureSolLogUnits(Segment * pseg) +{ + return pseg->EmToLogUnits(m_mMeasureSol); +} +float GrSlotOutput::MeasureEolLogUnits(Segment * pseg) +{ + return pseg->EmToLogUnits(m_mMeasureEol); +} + +/*---------------------------------------------------------------------------------------------- + Make a copy of the GrSlotOutput. This is used in making an identical copy of the segment. + Warning: this function will break if GrSlotState and subclasses are given virtual + methods. In that case, we will need to copy from the address of the first variable in + GrSlotAbstract. +----------------------------------------------------------------------------------------------*/ +void GrSlotOutput::ExactCopyFrom(GrSlotOutput * pslout, u_intslot * pnVarLenBuf, int cnExtraPerSlot) +{ + // The chunk of the object from GrSlotAbstract can be copied exactly, + // except for the variable-length buffer. + *this = *pslout; + m_prgnVarLenBuf = pnVarLenBuf; + std::copy(pslout->m_prgnVarLenBuf, pslout->m_prgnVarLenBuf + cnExtraPerSlot, + m_prgnVarLenBuf); + + // Now copy the stuff specific to GrSlotOutput. + m_ichwBeforeAssoc = pslout->m_ichwBeforeAssoc; + m_ichwAfterAssoc = pslout->m_ichwAfterAssoc; + m_cComponents = pslout->m_cComponents; + + for (size_t iislout = 0; iislout < pslout->m_visloutClusterMembers.size(); iislout++) + m_visloutClusterMembers.push_back(pslout->m_visloutClusterMembers[iislout]); + + m_isloutClusterBase = pslout->m_isloutClusterBase; + m_xsClusterXOffset = pslout->m_xsClusterXOffset; + m_xsClusterAdvance = pslout->m_xsClusterAdvance; + m_igbb = pslout->m_igbb; + m_xsAdvanceX = pslout->m_xsAdvanceX; + m_ysAdvanceY = pslout->m_ysAdvanceY; + m_rectBB = pslout->m_rectBB; +} + +/*---------------------------------------------------------------------------------------------- + Shift the glyph to the opposite end of the segment. This is needed for white-space-only + segments whose direction is being changed. +----------------------------------------------------------------------------------------------*/ +void GrSlotOutput::ShiftForDirDepthChange(float dxsSegWidth) +{ + float dxsShift = dxsSegWidth - m_xsAdvanceX - (2 * m_xsPositionX); + int tmp; tmp = (int) dxsShift; + m_xsPositionX += dxsShift; + m_rectBB.left += dxsShift; + m_rectBB.right += dxsShift; +} + +} // namespace gr |