From 73443fd278811837650160482c34c15e8830f0d3 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 15 Mar 2016 10:18:15 +0200 Subject: tdf#97319: Handle surrogate pairs in glyph caching for SimpleWinLayout (For UniscribeLayout we use glyph indices.) Change-Id: Id1907cb766b9285d32e484049bec1b99159c5768 --- vcl/win/gdi/winlayout.cxx | 49 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/vcl/win/gdi/winlayout.cxx b/vcl/win/gdi/winlayout.cxx index 56df8947c2f8..9aa23acd41e5 100644 --- a/vcl/win/gdi/winlayout.cxx +++ b/vcl/win/gdi/winlayout.cxx @@ -76,7 +76,7 @@ const int GLYPH_OFFSET_RATIO = GLYPH_SPACE_RATIO * 2; struct OpenGLGlyphCacheChunk { - WORD mnFirstGlyph; + int mnFirstGlyph; // Must be int to handle non-BMP code points when mbRealGlyphIndices is false int mnGlyphCount; std::vector maLocation; std::vector maLeftOverhangs; @@ -383,9 +383,9 @@ bool WinFontInstance::AddChunkOfGlyphs(bool bRealGlyphIndices, int nGlyphIndex, aChunk.mnGlyphCount = nCount; aChunk.mbRealGlyphIndices = bRealGlyphIndices; - std::vector aGlyphIndices(nCount); + std::vector aCodePointsOrGlyphIndices(nCount); for (int i = 0; i < nCount; i++) - aGlyphIndices[i] = nGlyphIndex + i; + aCodePointsOrGlyphIndices[i] = nGlyphIndex + i; HDC hDC = CreateCompatibleDC(rLayout.mhDC); if (hDC == NULL) @@ -424,18 +424,21 @@ bool WinFontInstance::AddChunkOfGlyphs(bool bRealGlyphIndices, int nGlyphIndex, return false; } } + std::vector aGlyphIndices(nCount); // Fetch the ink boxes and calculate the size of the atlas. if (!bRealGlyphIndices) { - // FIXME First convert from UTF16 to utf32 - std::vector aCodePoints(aGlyphIndices.begin(), aGlyphIndices.end()); - aGlyphIndices.resize(aCodePoints.size()); - if (!SUCCEEDED(pTxt->GetFontFace()->GetGlyphIndices(aCodePoints.data(), aCodePoints.size(), aGlyphIndices.data()))) + if (!SUCCEEDED(pTxt->GetFontFace()->GetGlyphIndices(aCodePointsOrGlyphIndices.data(), aCodePointsOrGlyphIndices.size(), aGlyphIndices.data()))) { pTxt->ReleaseFont(); return false; } } + else + { + for (int i = 0; i < nCount; i++) + aGlyphIndices[i] = aCodePointsOrGlyphIndices[i]; + } Rectangle bounds(0, 0, 0, 0); auto aInkBoxes = pTxt->GetGlyphInkBoxes(aGlyphIndices.data(), aGlyphIndices.data() + nCount); for (auto &box : aInkBoxes) @@ -1491,10 +1494,21 @@ bool SimpleWinLayout::CacheGlyphs(SalGraphics& rGraphics) const for (int i = 0; i < mnGlyphCount; i++) { - if (mrWinFontEntry.GlyphIsCached(mpOutGlyphs[i])) + int nCodePoint; + if (i < mnGlyphCount-1 && rtl::isHighSurrogate(mpOutGlyphs[i]) && rtl::isLowSurrogate(mpOutGlyphs[i+1])) + { + nCodePoint = rtl::combineSurrogates(mpOutGlyphs[i], mpOutGlyphs[i+1]); + i++; + } + else + { + nCodePoint = mpOutGlyphs[i]; + } + + if (mrWinFontEntry.GlyphIsCached(nCodePoint)) continue; - if (!mrWinFontEntry.AddChunkOfGlyphs(false, mpOutGlyphs[i], *this, rGraphics)) + if (!mrWinFontEntry.AddChunkOfGlyphs(false, nCodePoint, *this, rGraphics)) return false; } @@ -1528,10 +1542,21 @@ bool SimpleWinLayout::DrawCachedGlyphs(SalGraphics& rGraphics) const if (mpOutGlyphs[i] == DROPPED_OUTGLYPH) continue; - assert(mrWinFontEntry.GlyphIsCached(mpOutGlyphs[i])); + int nCodePoint; + if (i < mnGlyphCount-1 && rtl::isHighSurrogate(mpOutGlyphs[i]) && rtl::isLowSurrogate(mpOutGlyphs[i+1])) + { + nCodePoint = rtl::combineSurrogates(mpOutGlyphs[i], mpOutGlyphs[i+1]); + i++; + } + else + { + nCodePoint = mpOutGlyphs[i]; + } + + assert(mrWinFontEntry.GlyphIsCached(nCodePoint)); - const OpenGLGlyphCacheChunk& rChunk = mrWinFontEntry.GetCachedGlyphChunkFor(mpOutGlyphs[i]); - const int n = mpOutGlyphs[i] - rChunk.mnFirstGlyph; + const OpenGLGlyphCacheChunk& rChunk = mrWinFontEntry.GetCachedGlyphChunkFor(nCodePoint); + const int n = nCodePoint - rChunk.mnFirstGlyph; SalTwoRect a2Rects(rChunk.maLocation[n].Left(), rChunk.maLocation[n].Top(), rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight(), -- cgit v1.2.3