diff options
author | Luboš Luňák <l.lunak@collabora.com> | 2021-03-16 15:04:08 +0100 |
---|---|---|
committer | Luboš Luňák <l.lunak@collabora.com> | 2021-03-17 22:49:33 +0100 |
commit | 7439cabc643de2f07c18adc35056f802997f484a (patch) | |
tree | 1fb8f6bd207a81936617263091dca32d3536f1d6 /vcl/source/gdi | |
parent | 9d02d86e8a9111b7a689062eb9a856146a9e80b1 (diff) |
make SalLayoutGlyphs work with MultiSalLayout
Code that needs to lay out texts repeatedly can cache the result
of SalLayout::GetGlyphs() can reuse it. But GetGlyphs() returns
nullptr for MultiSalLayout, so caching for it doesn't work. Worse
still, it actually increases the number of layout calls, because
there's the initial layout for caching and then each call
will need to do the layout again because of the nullptr that's
not cached.
This commit changes SalLayoutGlyphs to possibly include multiple
SalLayoutGlyphsImpl objects, one for each SalLayout handled
by MultiSalLayout. Changes include making GenericSalLayout
work directly with the Impl class, which avoids an indirection
and simplifies code.
Change-Id: Ic4b19934a8a06d4955b51527fe3777c5e91107b2
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/112590
Tested-by: Jenkins
Reviewed-by: Luboš Luňák <l.lunak@collabora.com>
Diffstat (limited to 'vcl/source/gdi')
-rw-r--r-- | vcl/source/gdi/CommonSalLayout.cxx | 68 | ||||
-rw-r--r-- | vcl/source/gdi/impglyphitem.cxx | 42 | ||||
-rw-r--r-- | vcl/source/gdi/sallayout.cxx | 64 |
3 files changed, 91 insertions, 83 deletions
diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx index 7f557c73b314..2ef3c98d2f9d 100644 --- a/vcl/source/gdi/CommonSalLayout.cxx +++ b/vcl/source/gdi/CommonSalLayout.cxx @@ -57,10 +57,10 @@ static hb_unicode_funcs_t* getUnicodeFuncs() #endif GenericSalLayout::GenericSalLayout(LogicalFontInstance &rFont) - : mpVertGlyphs(nullptr) + : m_GlyphItems(rFont) + , mpVertGlyphs(nullptr) , mbFuzzing(utl::ConfigManager::IsFuzzing()) { - new SalLayoutGlyphsImpl(m_GlyphItems, rFont); } GenericSalLayout::~GenericSalLayout() @@ -190,9 +190,11 @@ std::shared_ptr<vcl::TextLayoutCache> GenericSalLayout::CreateTextLayoutCache(OU return std::make_shared<vcl::TextLayoutCache>(rString.getStr(), rString.getLength()); } -const SalLayoutGlyphs* GenericSalLayout::GetGlyphs() const +SalLayoutGlyphs GenericSalLayout::GetGlyphs() const { - return &m_GlyphItems; + SalLayoutGlyphs glyphs; + glyphs.AppendImpl(m_GlyphItems.clone()); + return glyphs; } void GenericSalLayout::SetNeedFallback(ImplLayoutArgs& rArgs, sal_Int32 nCharPos, bool bRightToLeft) @@ -284,7 +286,7 @@ bool GenericSalLayout::HasVerticalAlternate(sal_UCS4 aChar, sal_UCS4 aVariationS return hb_set_has(mpVertGlyphs, nGlyphIndex) != 0; } -bool GenericSalLayout::LayoutText(ImplLayoutArgs& rArgs, const SalLayoutGlyphs* pGlyphs) +bool GenericSalLayout::LayoutText(ImplLayoutArgs& rArgs, const SalLayoutGlyphsImpl* pGlyphs) { // No need to touch m_GlyphItems at all for an empty string. if (rArgs.mnEndCharPos - rArgs.mnMinCharPos <= 0) @@ -295,7 +297,7 @@ bool GenericSalLayout::LayoutText(ImplLayoutArgs& rArgs, const SalLayoutGlyphs* // Work with pre-computed glyph items. m_GlyphItems = *pGlyphs; // Some flags are set as a side effect of text layout, restore them here. - rArgs.mnFlags |= pGlyphs->Impl()->mnFlags; + rArgs.mnFlags |= pGlyphs->mnFlags; return true; } @@ -303,7 +305,7 @@ bool GenericSalLayout::LayoutText(ImplLayoutArgs& rArgs, const SalLayoutGlyphs* bool isGraphite = GetFont().IsGraphiteFont(); int nGlyphCapacity = 2 * (rArgs.mnEndCharPos - rArgs.mnMinCharPos); - m_GlyphItems.Impl()->reserve(nGlyphCapacity); + m_GlyphItems.reserve(nGlyphCapacity); const int nLength = rArgs.mrStr.getLength(); const sal_Unicode *pStr = rArgs.mrStr.getStr(); @@ -603,7 +605,7 @@ bool GenericSalLayout::LayoutText(ImplLayoutArgs& rArgs, const SalLayoutGlyphs* Point aNewPos(aCurrPos.X() + nXOffset, aCurrPos.Y() + nYOffset); const GlyphItem aGI(nCharPos, nCharCount, nGlyphIndex, aNewPos, nGlyphFlags, nAdvance, nXOffset, &GetFont()); - m_GlyphItems.Impl()->push_back(aGI); + m_GlyphItems.push_back(aGI); aCurrPos.AdjustX(nAdvance ); } @@ -614,7 +616,7 @@ bool GenericSalLayout::LayoutText(ImplLayoutArgs& rArgs, const SalLayoutGlyphs* // Some flags are set as a side effect of text layout, save them here. if (rArgs.mnFlags & SalLayoutFlags::GlyphItemsOnly) - m_GlyphItems.Impl()->mnFlags = rArgs.mnFlags; + m_GlyphItems.mnFlags = rArgs.mnFlags; return true; } @@ -626,7 +628,7 @@ void GenericSalLayout::GetCharWidths(DeviceCoordinate* pCharWidths) const for (int i = 0; i < nCharCount; ++i) pCharWidths[i] = 0; - for (auto const& aGlyphItem : *m_GlyphItems.Impl()) + for (auto const& aGlyphItem : m_GlyphItems) { const int nIndex = aGlyphItem.charPos() - mnMinCharPos; if (nIndex >= nCharCount) @@ -694,31 +696,31 @@ void GenericSalLayout::ApplyDXArray(const ImplLayoutArgs& rArgs) // Apply the DX adjustments to glyph positions and widths. size_t i = 0; - while (i < m_GlyphItems.Impl()->size()) + while (i < m_GlyphItems.size()) { // Accumulate the width difference for all characters corresponding to // this glyph. - int nCharPos = (*m_GlyphItems.Impl())[i].charPos() - mnMinCharPos; + int nCharPos = m_GlyphItems[i].charPos() - mnMinCharPos; DeviceCoordinate nDiff = 0; - for (int j = 0; j < (*m_GlyphItems.Impl())[i].charCount(); j++) + for (int j = 0; j < m_GlyphItems[i].charCount(); j++) nDiff += pNewCharWidths[nCharPos + j] - pOldCharWidths[nCharPos + j]; - if (!(*m_GlyphItems.Impl())[i].IsRTLGlyph()) + if (!m_GlyphItems[i].IsRTLGlyph()) { // Adjust the width and position of the first (leftmost) glyph in // the cluster. - (*m_GlyphItems.Impl())[i].m_nNewWidth += nDiff; - (*m_GlyphItems.Impl())[i].m_aLinearPos.AdjustX(nDelta); + m_GlyphItems[i].m_nNewWidth += nDiff; + m_GlyphItems[i].m_aLinearPos.AdjustX(nDelta); // Adjust the position of the rest of the glyphs in the cluster. - while (++i < m_GlyphItems.Impl()->size()) + while (++i < m_GlyphItems.size()) { - if (!(*m_GlyphItems.Impl())[i].IsInCluster()) + if (!m_GlyphItems[i].IsInCluster()) break; - (*m_GlyphItems.Impl())[i].m_aLinearPos.AdjustX(nDelta); + m_GlyphItems[i].m_aLinearPos.AdjustX(nDelta); } } - else if ((*m_GlyphItems.Impl())[i].IsInCluster()) + else if (m_GlyphItems[i].IsInCluster()) { // RTL glyph in the middle of the cluster, will be handled in the // loop below. @@ -729,34 +731,34 @@ void GenericSalLayout::ApplyDXArray(const ImplLayoutArgs& rArgs) // Adjust the width and position of the first (rightmost) glyph in // the cluster. // For RTL, we put all the adjustment to the left of the glyph. - (*m_GlyphItems.Impl())[i].m_nNewWidth += nDiff; - (*m_GlyphItems.Impl())[i].m_aLinearPos.AdjustX(nDelta + nDiff); + m_GlyphItems[i].m_nNewWidth += nDiff; + m_GlyphItems[i].m_aLinearPos.AdjustX(nDelta + nDiff); // Adjust the X position of all glyphs in the cluster. size_t j = i; while (j > 0) { --j; - if (!(*m_GlyphItems.Impl())[j].IsInCluster()) + if (!m_GlyphItems[j].IsInCluster()) break; - (*m_GlyphItems.Impl())[j].m_aLinearPos.AdjustX(nDelta + nDiff); + m_GlyphItems[j].m_aLinearPos.AdjustX(nDelta + nDiff); } // If this glyph is Kashida-justifiable, then mark this as a // Kashida position. Since this must be a RTL glyph, we mark the // last glyph in the cluster not the first as this would be the // base glyph. - if (bKashidaJustify && (*m_GlyphItems.Impl())[i].AllowKashida() && - nDiff > (*m_GlyphItems.Impl())[i].charCount()) // Rounding errors, 1 pixel per character! + if (bKashidaJustify && m_GlyphItems[i].AllowKashida() && + nDiff > m_GlyphItems[i].charCount()) // Rounding errors, 1 pixel per character! { pKashidas[i] = nDiff; // Move any non-spacing marks attached to this cluster as well. // Looping backward because this is RTL glyph. while (j > 0) { - if (!(*m_GlyphItems.Impl())[j].IsDiacritic()) + if (!m_GlyphItems[j].IsDiacritic()) break; - (*m_GlyphItems.Impl())[j--].m_aLinearPos.AdjustX(nDiff); + m_GlyphItems[j--].m_aLinearPos.AdjustX(nDiff); } } i++; @@ -776,7 +778,7 @@ void GenericSalLayout::ApplyDXArray(const ImplLayoutArgs& rArgs) size_t nInserted = 0; for (auto const& pKashida : pKashidas) { - auto pGlyphIter = m_GlyphItems.Impl()->begin() + nInserted + pKashida.first; + auto pGlyphIter = m_GlyphItems.begin() + nInserted + pKashida.first; // The total Kashida width. DeviceCoordinate nTotalWidth = pKashida.second; @@ -804,7 +806,7 @@ void GenericSalLayout::ApplyDXArray(const ImplLayoutArgs& rArgs) while (nCopies--) { GlyphItem aKashida(nCharPos, 0, nKashidaIndex, aPos, nFlags, nKashidaWidth, 0, &GetFont()); - pGlyphIter = m_GlyphItems.Impl()->insert(pGlyphIter, aKashida); + pGlyphIter = m_GlyphItems.insert(pGlyphIter, aKashida); aPos.AdjustX(nKashidaWidth ); aPos.AdjustX( -nOverlap ); ++pGlyphIter; @@ -815,7 +817,7 @@ void GenericSalLayout::ApplyDXArray(const ImplLayoutArgs& rArgs) bool GenericSalLayout::IsKashidaPosValid(int nCharPos) const { - for (auto pIter = m_GlyphItems.Impl()->begin(); pIter != m_GlyphItems.Impl()->end(); ++pIter) + for (auto pIter = m_GlyphItems.begin(); pIter != m_GlyphItems.end(); ++pIter) { if (pIter->charPos() == nCharPos) { @@ -823,7 +825,7 @@ bool GenericSalLayout::IsKashidaPosValid(int nCharPos) const // changed the text styling in the middle of a word. Since we don’t // do ligatures across layout engine instances, this can’t be a // ligature so it should be fine. - if (pIter == m_GlyphItems.Impl()->begin()) + if (pIter == m_GlyphItems.begin()) return true; // If the character is not supported by this layout, return false @@ -834,7 +836,7 @@ bool GenericSalLayout::IsKashidaPosValid(int nCharPos) const // Search backwards for previous glyph belonging to a different // character. We are looking backwards because we are dealing with // RTL glyphs, which will be in visual order. - for (auto pPrev = pIter - 1; pPrev != m_GlyphItems.Impl()->begin(); --pPrev) + for (auto pPrev = pIter - 1; pPrev != m_GlyphItems.begin(); --pPrev) { if (pPrev->charPos() != nCharPos) { diff --git a/vcl/source/gdi/impglyphitem.cxx b/vcl/source/gdi/impglyphitem.cxx index 4bb53d4a4596..d271032e2ad6 100644 --- a/vcl/source/gdi/impglyphitem.cxx +++ b/vcl/source/gdi/impglyphitem.cxx @@ -23,43 +23,41 @@ #include <unx/freetype_glyphcache.hxx> #endif -SalLayoutGlyphs::SalLayoutGlyphs() - : m_pImpl(nullptr) +SalLayoutGlyphs::~SalLayoutGlyphs() { + for (SalLayoutGlyphsImpl* impl : m_pImpls) + delete impl; } -SalLayoutGlyphs::~SalLayoutGlyphs() { delete m_pImpl; } +SalLayoutGlyphs::SalLayoutGlyphs(SalLayoutGlyphs&& rOther) { std::swap(m_pImpls, rOther.m_pImpls); } -SalLayoutGlyphs::SalLayoutGlyphs(const SalLayoutGlyphs& rOther) -{ - m_pImpl = rOther.m_pImpl ? rOther.m_pImpl->clone(*this) : nullptr; -} - -SalLayoutGlyphs& SalLayoutGlyphs::operator=(const SalLayoutGlyphs& rOther) +SalLayoutGlyphs& SalLayoutGlyphs::operator=(SalLayoutGlyphs&& rOther) { if (this != &rOther) - { - delete m_pImpl; - m_pImpl = rOther.m_pImpl ? rOther.m_pImpl->clone(*this) : nullptr; - } + std::swap(m_pImpls, rOther.m_pImpls); return *this; } -bool SalLayoutGlyphs::IsValid() const { return m_pImpl && m_pImpl->IsValid(); } - -void SalLayoutGlyphs::Invalidate() +bool SalLayoutGlyphs::IsValid() const { - if (m_pImpl) - m_pImpl->Invalidate(); + if (m_pImpls.empty()) + return false; + for (SalLayoutGlyphsImpl* impl : m_pImpls) + if (!impl->IsValid()) + return false; + return true; } -SalLayoutGlyphsImpl* SalLayoutGlyphsImpl::clone(SalLayoutGlyphs& rGlyphs) const +void SalLayoutGlyphs::Invalidate() { - SalLayoutGlyphsImpl* pNew = new SalLayoutGlyphsImpl(rGlyphs, *m_rFontInstance); - *pNew = *this; - return pNew; + // Invalidating is in fact simply clearing. + for (SalLayoutGlyphsImpl* impl : m_pImpls) + delete impl; + m_pImpls.clear(); } +SalLayoutGlyphsImpl* SalLayoutGlyphsImpl::clone() const { return new SalLayoutGlyphsImpl(*this); } + bool SalLayoutGlyphsImpl::IsValid() const { if (!m_rFontInstance.is()) diff --git a/vcl/source/gdi/sallayout.cxx b/vcl/source/gdi/sallayout.cxx index 067672dc5366..cde5cac31730 100644 --- a/vcl/source/gdi/sallayout.cxx +++ b/vcl/source/gdi/sallayout.cxx @@ -647,6 +647,11 @@ bool SalLayout::GetBoundRect(tools::Rectangle& rRect) const return bRet; } +SalLayoutGlyphs SalLayout::GetGlyphs() const +{ + return SalLayoutGlyphs(); // invalid +} + DeviceCoordinate GenericSalLayout::FillDXArray( DeviceCoordinate* pCharWidths ) const { if (pCharWidths) @@ -665,7 +670,7 @@ DeviceCoordinate GenericSalLayout::GetTextWidth() const DeviceCoordinate nMinPos = 0; DeviceCoordinate nMaxPos = 0; - for (auto const& aGlyphItem : *m_GlyphItems.Impl()) + for (auto const& aGlyphItem : m_GlyphItems) { // update the text extent with the glyph extent DeviceCoordinate nXPos = aGlyphItem.m_aLinearPos.getX(); @@ -692,13 +697,13 @@ void GenericSalLayout::Justify( DeviceCoordinate nNewWidth ) return; } // find rightmost glyph, it won't get stretched - std::vector<GlyphItem>::iterator pGlyphIterRight = m_GlyphItems.Impl()->begin(); - pGlyphIterRight += m_GlyphItems.Impl()->size() - 1; + std::vector<GlyphItem>::iterator pGlyphIterRight = m_GlyphItems.begin(); + pGlyphIterRight += m_GlyphItems.size() - 1; std::vector<GlyphItem>::iterator pGlyphIter; // count stretchable glyphs int nStretchable = 0; int nMaxGlyphWidth = 0; - for(pGlyphIter = m_GlyphItems.Impl()->begin(); pGlyphIter != pGlyphIterRight; ++pGlyphIter) + for(pGlyphIter = m_GlyphItems.begin(); pGlyphIter != pGlyphIterRight; ++pGlyphIter) { if( !pGlyphIter->IsDiacritic() ) ++nStretchable; @@ -721,7 +726,7 @@ void GenericSalLayout::Justify( DeviceCoordinate nNewWidth ) { // expand width by distributing space between glyphs evenly int nDeltaSum = 0; - for( pGlyphIter = m_GlyphItems.Impl()->begin(); pGlyphIter != pGlyphIterRight; ++pGlyphIter ) + for( pGlyphIter = m_GlyphItems.begin(); pGlyphIter != pGlyphIterRight; ++pGlyphIter ) { // move glyph to justified position pGlyphIter->m_aLinearPos.AdjustX(nDeltaSum ); @@ -741,9 +746,9 @@ void GenericSalLayout::Justify( DeviceCoordinate nNewWidth ) { // squeeze width by moving glyphs proportionally double fSqueeze = static_cast<double>(nNewWidth) / nOldWidth; - if(m_GlyphItems.Impl()->size() > 1) + if(m_GlyphItems.size() > 1) { - for( pGlyphIter = m_GlyphItems.Impl()->begin(); ++pGlyphIter != pGlyphIterRight;) + for( pGlyphIter = m_GlyphItems.begin(); ++pGlyphIter != pGlyphIterRight;) { int nX = pGlyphIter->m_aLinearPos.getX(); nX = static_cast<int>(nX * fSqueeze); @@ -751,7 +756,7 @@ void GenericSalLayout::Justify( DeviceCoordinate nNewWidth ) } } // adjust glyph widths to new positions - for( pGlyphIter = m_GlyphItems.Impl()->begin(); pGlyphIter != pGlyphIterRight; ++pGlyphIter ) + for( pGlyphIter = m_GlyphItems.begin(); pGlyphIter != pGlyphIterRight; ++pGlyphIter ) pGlyphIter->m_nNewWidth = pGlyphIter[1].m_aLinearPos.getX() - pGlyphIter[0].m_aLinearPos.getX(); } } @@ -804,8 +809,8 @@ void GenericSalLayout::ApplyAsianKerning(const OUString& rStr) const int nLength = rStr.getLength(); tools::Long nOffset = 0; - for (std::vector<GlyphItem>::iterator pGlyphIter = m_GlyphItems.Impl()->begin(), - pGlyphIterEnd = m_GlyphItems.Impl()->end(); + for (std::vector<GlyphItem>::iterator pGlyphIter = m_GlyphItems.begin(), + pGlyphIterEnd = m_GlyphItems.end(); pGlyphIter != pGlyphIterEnd; ++pGlyphIter) { const int n = pGlyphIter->charPos(); @@ -851,7 +856,7 @@ void GenericSalLayout::GetCaretPositions( int nMaxIndex, tools::Long* pCaretXArr pCaretXArray[i] = -1; // calculate caret positions using glyph array - for (auto const& aGlyphItem : *m_GlyphItems.Impl()) + for (auto const& aGlyphItem : m_GlyphItems) { tools::Long nXPos = aGlyphItem.m_aLinearPos.getX(); tools::Long nXRight = nXPos + aGlyphItem.origWidth(); @@ -897,8 +902,8 @@ bool GenericSalLayout::GetNextGlyph(const GlyphItem** pGlyph, Point& rPos, int& nStart, const PhysicalFontFace**) const { - std::vector<GlyphItem>::const_iterator pGlyphIter = m_GlyphItems.Impl()->begin(); - std::vector<GlyphItem>::const_iterator pGlyphIterEnd = m_GlyphItems.Impl()->end(); + std::vector<GlyphItem>::const_iterator pGlyphIter = m_GlyphItems.begin(); + std::vector<GlyphItem>::const_iterator pGlyphIterEnd = m_GlyphItems.end(); pGlyphIter += nStart; // find next glyph in substring @@ -910,7 +915,7 @@ bool GenericSalLayout::GetNextGlyph(const GlyphItem** pGlyph, } // return zero if no more glyph found - if( nStart >= static_cast<int>(m_GlyphItems.Impl()->size()) ) + if( nStart >= static_cast<int>(m_GlyphItems.size()) ) return false; if( pGlyphIter == pGlyphIterEnd ) @@ -932,10 +937,10 @@ bool GenericSalLayout::GetNextGlyph(const GlyphItem** pGlyph, void GenericSalLayout::MoveGlyph( int nStart, tools::Long nNewXPos ) { - if( nStart >= static_cast<int>(m_GlyphItems.Impl()->size()) ) + if( nStart >= static_cast<int>(m_GlyphItems.size()) ) return; - std::vector<GlyphItem>::iterator pGlyphIter = m_GlyphItems.Impl()->begin(); + std::vector<GlyphItem>::iterator pGlyphIter = m_GlyphItems.begin(); pGlyphIter += nStart; // the nNewXPos argument determines the new cell position @@ -948,7 +953,7 @@ void GenericSalLayout::MoveGlyph( int nStart, tools::Long nNewXPos ) // adjust all following glyph positions if needed if( nXDelta != 0 ) { - for( std::vector<GlyphItem>::iterator pGlyphIterEnd = m_GlyphItems.Impl()->end(); pGlyphIter != pGlyphIterEnd; ++pGlyphIter ) + for( std::vector<GlyphItem>::iterator pGlyphIterEnd = m_GlyphItems.end(); pGlyphIter != pGlyphIterEnd; ++pGlyphIter ) { pGlyphIter->m_aLinearPos.AdjustX(nXDelta ); } @@ -957,10 +962,10 @@ void GenericSalLayout::MoveGlyph( int nStart, tools::Long nNewXPos ) void GenericSalLayout::DropGlyph( int nStart ) { - if( nStart >= static_cast<int>(m_GlyphItems.Impl()->size())) + if( nStart >= static_cast<int>(m_GlyphItems.size())) return; - std::vector<GlyphItem>::iterator pGlyphIter = m_GlyphItems.Impl()->begin(); + std::vector<GlyphItem>::iterator pGlyphIter = m_GlyphItems.begin(); pGlyphIter += nStart; pGlyphIter->dropGlyph(); } @@ -969,20 +974,20 @@ void GenericSalLayout::Simplify( bool bIsBase ) { // remove dropped glyphs inplace size_t j = 0; - for(size_t i = 0; i < m_GlyphItems.Impl()->size(); i++ ) + for(size_t i = 0; i < m_GlyphItems.size(); i++ ) { - if (bIsBase && (*m_GlyphItems.Impl())[i].IsDropped()) + if (bIsBase && m_GlyphItems[i].IsDropped()) continue; - if (!bIsBase && (*m_GlyphItems.Impl())[i].glyphId() == 0) + if (!bIsBase && m_GlyphItems[i].glyphId() == 0) continue; if( i != j ) { - (*m_GlyphItems.Impl())[j] = (*m_GlyphItems.Impl())[i]; + m_GlyphItems[j] = m_GlyphItems[i]; } j += 1; } - m_GlyphItems.Impl()->erase(m_GlyphItems.Impl()->begin() + j, m_GlyphItems.Impl()->end()); + m_GlyphItems.erase(m_GlyphItems.begin() + j, m_GlyphItems.end()); } MultiSalLayout::MultiSalLayout( std::unique_ptr<SalLayout> pBaseLayout ) @@ -1023,7 +1028,7 @@ void MultiSalLayout::AddFallback( std::unique_ptr<SalLayout> pFallback, ++mnLevel; } -bool MultiSalLayout::LayoutText( ImplLayoutArgs& rArgs, const SalLayoutGlyphs* ) +bool MultiSalLayout::LayoutText( ImplLayoutArgs& rArgs, const SalLayoutGlyphsImpl* ) { if( mnLevel <= 1 ) return false; @@ -1576,10 +1581,13 @@ bool MultiSalLayout::IsKashidaPosValid(int nCharPos) const return bValid; } -const SalLayoutGlyphs* SalLayout::GetGlyphs() const +SalLayoutGlyphs MultiSalLayout::GetGlyphs() const { - // No access to the glyphs by default. - return nullptr; + SalLayoutGlyphs glyphs; + for( int n = 0; n < mnLevel; ++n ) + glyphs.AppendImpl(mpLayouts[n]->GlyphsImpl().clone()); + return glyphs; } + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |