vcl/inc/win/salgdi.h | 1 vcl/win/source/gdi/winlayout.cxx | 347 +++++++++++++++++++++++++++++++++++++++ vcl/win/source/gdi/winlayout.hxx | 8 3 files changed, 355 insertions(+), 1 deletion(-)
New commits: commit 239d4e0cbd7d0c4e3504528b8dcf5e10fbea9a0b Author: Tor Lillqvist <[email protected]> Date: Wed Aug 19 09:18:37 2015 +0300 More hacks to glyph rendering for caching with OpenGL on Windows Change-Id: I934ad7453f35909f4c3ad999e33453b5b6032480 diff --git a/vcl/win/source/gdi/winlayout.cxx b/vcl/win/source/gdi/winlayout.cxx index 0ab9cd9..7f4c4a4 100644 --- a/vcl/win/source/gdi/winlayout.cxx +++ b/vcl/win/source/gdi/winlayout.cxx @@ -160,7 +160,10 @@ inline std::basic_ostream<charT, traits> & operator <<( stream << "{"; for (auto i = rCache.cbegin(); i != rCache.cend(); ++i) { - stream << "[" << i->mnFirstGlyph << ".." << (i->mnFirstGlyph + i->mnGlyphCount - 1) << "]"; + stream << "[" << i->mnFirstGlyph; + if (i->mnGlyphCount > 1) + stream << ".." << (i->mnFirstGlyph + i->mnGlyphCount - 1); + stream << "]"; if (i+1 != rCache.cend()) { stream << ","; @@ -278,10 +281,16 @@ bool ImplWinFontEntry::AddChunkOfGlyphs(int nGlyphIndex, const WinLayout& rLayou int totWidth = 0; for (int i = 0; i < nCount; i++) { - aDX[i] = std::abs(aABC[i].abcA) + aABC[i].abcB + std::abs(aABC[i].abcC); + aDX[i] = aABC[i].abcB + std::abs(aABC[i].abcC); + if (i == 0) + aDX[0] += std::abs(aABC[0].abcA); + if (i < nCount-1) + aDX[i] += std::abs(aABC[i+1].abcA); totWidth += aDX[i]; } + SAL_INFO("vcl.gdi.opengl", "aSize=(" << aSize.cx << "," << aSize.cy << ") totWidth=" << totWidth); + if (SelectObject(hDC, hOrigFont) == NULL) SAL_WARN("vcl.gdi", "SelectObject failed: " << WindowsErrorString(GetLastError())); if (!DeleteDC(hDC)) commit df42d08191fd76b38d58a317f9aca804e10df062 Author: Tor Lillqvist <[email protected]> Date: Tue Aug 18 13:43:27 2015 +0300 More hacking on OpenGL glyph caching on Windows Now text looks better, for instance the lower-case "t" glyphs on the Start Centre aren't totally weird any more. But for instance the tip of the hook of "j" leaks into the "i" texture. I guess I really would need to render glyphs one by one. Change-Id: I69ae2d2f7c559530bcfdfc1a4915503fcb3ab4af diff --git a/vcl/win/source/gdi/winlayout.cxx b/vcl/win/source/gdi/winlayout.cxx index e32b8b5..0ab9cd9 100644 --- a/vcl/win/source/gdi/winlayout.cxx +++ b/vcl/win/source/gdi/winlayout.cxx @@ -204,7 +204,7 @@ bool ImplWinFontEntry::AddChunkOfGlyphs(int nGlyphIndex, const WinLayout& rLayou if (nGlyphIndex == DROPPED_OUTGLYPH) return true; - SAL_INFO("vcl.gdi.opengl", "AddChunkOfGlyphs " << this << " " << nGlyphIndex << " old: " << maOpenGLGlyphCache); + SAL_INFO("vcl.gdi.opengl", "this=" << this << " " << nGlyphIndex << " old: " << maOpenGLGlyphCache); auto n = maOpenGLGlyphCache.begin(); while (n != maOpenGLGlyphCache.end() && @@ -262,12 +262,32 @@ bool ImplWinFontEntry::AddChunkOfGlyphs(int nGlyphIndex, const WinLayout& rLayou return false; } + std::vector<ABC> aABC(nCount); + if (!GetCharABCWidthsI(hDC, 0, nCount, aGlyphIndices.data(), aABC.data())) + { + SAL_WARN("vcl.gdi", "GetCharABCWidthsI failed: " << WindowsErrorString(GetLastError())); + return false; + } + + for (int i = 0; i < nCount; i++) + std::cerr << aABC[i].abcA << ":" << aABC[i].abcB << ":" << aABC[i].abcC << " "; + std::cerr << std::endl; + + // Avoid kerning as we want to be able to use individual rectangles for each glyph + std::vector<int> aDX(nCount); + int totWidth = 0; + for (int i = 0; i < nCount; i++) + { + aDX[i] = std::abs(aABC[i].abcA) + aABC[i].abcB + std::abs(aABC[i].abcC); + totWidth += aDX[i]; + } + if (SelectObject(hDC, hOrigFont) == NULL) SAL_WARN("vcl.gdi", "SelectObject failed: " << WindowsErrorString(GetLastError())); if (!DeleteDC(hDC)) SAL_WARN("vcl.gdi", "DeleteDC failed: " << WindowsErrorString(GetLastError())); - OpenGLCompatibleDC aDC(rGraphics, 0, 0, aSize.cx, aSize.cy); + OpenGLCompatibleDC aDC(rGraphics, 0, 0, totWidth, aSize.cy); hOrigFont = SelectFont(aDC.getCompatibleHDC(), rLayout.mhFont); if (hOrigFont == NULL) @@ -279,21 +299,6 @@ bool ImplWinFontEntry::AddChunkOfGlyphs(int nGlyphIndex, const WinLayout& rLayou SetTextColor(aDC.getCompatibleHDC(), RGB(0, 0, 0)); SetBkColor(aDC.getCompatibleHDC(), RGB(255, 255, 255)); - std::vector<ABC> aABC(nCount); - if (!GetCharABCWidthsI(aDC.getCompatibleHDC(), 0, nCount, aGlyphIndices.data(), aABC.data())) - { - SAL_WARN("vcl.gdi", "GetCharABCWidthsI failed: " << WindowsErrorString(GetLastError())); - return false; - } - - for (int i = 0; i < nCount; i++) - std::cerr << aABC[i].abcA << ":" << aABC[i].abcB << ":" << aABC[i].abcC << " "; - std::cerr << std::endl; - - // Avoid kerning as we want to be able to use individual rectangles for each glyph - std::vector<int> aDX(nCount); - for (int i = 0; i < nCount; i++) - aDX[i] = std::abs(aABC[i].abcA) + aABC[i].abcB + std::abs(aABC[i].abcC); if (!ExtTextOutW(aDC.getCompatibleHDC(), 0, 0, ETO_GLYPH_INDEX, NULL, aGlyphIndices.data(), nCount, aDX.data())) { SAL_WARN("vcl.gdi", "ExtTextOutW failed: " << WindowsErrorString(GetLastError())); @@ -317,7 +322,7 @@ bool ImplWinFontEntry::AddChunkOfGlyphs(int nGlyphIndex, const WinLayout& rLayou SelectFont(aDC.getCompatibleHDC(), hOrigFont); - SAL_INFO("vcl.gdi.opengl", "AddChunkOfGlyphs " << this << " now: " << maOpenGLGlyphCache << DumpGlyphBitmap(aChunk, aDC.getCompatibleHDC())); + SAL_INFO("vcl.gdi.opengl", "this=" << this << " now: " << maOpenGLGlyphCache << DumpGlyphBitmap(aChunk, aDC.getCompatibleHDC())); return true; } commit b3c8095de5cf8c8030e3bac0532363def3070c3e Author: Tor Lillqvist <[email protected]> Date: Mon Aug 17 18:23:11 2015 +0300 Add FIXME comment and bin an #if 0 snippet Change-Id: I0bbea4ef62c8e94d8b8f1bfb440712da5839e532 diff --git a/vcl/win/source/gdi/winlayout.cxx b/vcl/win/source/gdi/winlayout.cxx index 6f8b4ca..e32b8b5 100644 --- a/vcl/win/source/gdi/winlayout.cxx +++ b/vcl/win/source/gdi/winlayout.cxx @@ -1579,6 +1579,8 @@ bool UniscribeLayout::DrawCachedGlyphs(SalGraphics& rGraphics) const pImpl->PreDraw(); + // FIXME: This code snippet is mostly copied from the one in + // UniscribeLayout::DrawTextImpl. Should be factored out. int nBaseClusterOffset = 0; int nBaseGlyphPos = -1; for( int nItem = 0; nItem < mnItemCount; ++nItem ) @@ -1626,16 +1628,6 @@ bool UniscribeLayout::DrawCachedGlyphs(SalGraphics& rGraphics) const pImpl->DrawMask(*rChunk.mpTexture, salColor, a2Rects); nAdvance += mpGlyphAdvances[i]; } -#if 0 - ScriptTextOut(hDC, &rScriptCache, - aPos.X(), aPos.Y(), 0, NULL, - &rVisualItem.mpScriptItem->a, NULL, 0, - mpOutGlyphs + nMinGlyphPos, - nEndGlyphPos - nMinGlyphPos, - mpGlyphAdvances + nMinGlyphPos, - mpJustifications ? mpJustifications + nMinGlyphPos : NULL, - mpGlyphOffsets + nMinGlyphPos); -#endif } pImpl->PostDraw(); commit d4ade4aeb60617b620faf21f08605b6feb069cce Author: Tor Lillqvist <[email protected]> Date: Mon Aug 17 17:02:35 2015 +0300 Initial hack for OpenGL glyph caching on Windows Shows text roughly correctly, but many problems. Conditional at run-time on the SAL_ENABLE_GLYPH_CACHING environment variable in addition to SAL_FORCEGL. One obvious thing that needs fixing is making sure that the glyphs are rendered into the texture without overlap. Compensating negative values in the ABC::abcA and ABC::abdC width is not enough. Also, the cache should be changed to actually have "cache" functionality, i.e. entries should expire based on some criterion. Change-Id: I66a37d3354a09011a654f15a7d2bd8efaa14ad1e diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h index 7d05d23..852b470 100644 --- a/vcl/inc/win/salgdi.h +++ b/vcl/inc/win/salgdi.h @@ -187,6 +187,7 @@ class WinSalGraphics : public SalGraphics friend class ScopedFont; friend class OpenGLCompatibleDC; friend class WinLayout; + friend class UniscribeLayout; protected: std::unique_ptr<SalGraphicsImpl> mpImpl; diff --git a/vcl/win/source/gdi/winlayout.cxx b/vcl/win/source/gdi/winlayout.cxx index 89503f3..6f8b4ca 100644 --- a/vcl/win/source/gdi/winlayout.cxx +++ b/vcl/win/source/gdi/winlayout.cxx @@ -22,6 +22,8 @@ #include "osl/module.h" #include "osl/file.h" +#include <comphelper/windowserrorstring.hxx> + #include <opengl/texture.hxx> #include <opengl/win/gdiimpl.hxx> #include <vcl/opengl/OpenGLHelper.hxx> @@ -32,6 +34,8 @@ #include "sallayout.hxx" #include <cstdio> +#include <cstdlib> + #include <sal/alloca.h> #include <algorithm> @@ -54,6 +58,14 @@ typedef std::unordered_map<int,int> IntMap; #include <config_mingw.h> +struct OpenGLGlyphCacheChunk +{ + WORD mnFirstGlyph; + int mnGlyphCount; + std::vector<Rectangle> maLocation; + std::shared_ptr<OpenGLTexture> mpTexture; +}; + // win32 specific physical font instance class ImplWinFontEntry : public ImplFontEntry { @@ -77,6 +89,7 @@ public: { return maScriptCache; } private: mutable SCRIPT_CACHE maScriptCache; + std::vector<OpenGLGlyphCacheChunk> maOpenGLGlyphCache; public: int GetCachedGlyphWidth( int nCharCode ) const; @@ -90,8 +103,74 @@ private: IntMap maWidthMap; mutable int mnMinKashidaWidth; mutable int mnMinKashidaGlyph; + +public: + bool GlyphIsCached(int nGlyphIndex) const; + bool AddChunkOfGlyphs(int nGlyphIndex, const WinLayout& rLayout, SalGraphics& rGraphics); + const OpenGLGlyphCacheChunk& GetCachedGlyphChunkFor(int nGlyphIndex) const; }; +char ColorFor(COLORREF aColor) +{ + if (aColor == RGB(0xFF, 0xFF, 0xFF)) + return ' '; + return '0' + 10*((GetRValue(aColor) + GetGValue(aColor) + GetBValue(aColor)) / (0xFF*3)); +} + +OUString DumpGlyphBitmap(OpenGLGlyphCacheChunk& rChunk, HDC hDC) +{ + HBITMAP hBitmap = static_cast<HBITMAP>(GetCurrentObject(hDC, OBJ_BITMAP)); + if (hBitmap == NULL) + { + SAL_WARN("vcl.gdi", "GetCurrentObject failed: " << WindowsErrorString(GetLastError())); + return ""; + } + + BITMAP aBitmap; + if (!GetObjectW(hBitmap, sizeof(aBitmap), &aBitmap)) + { + SAL_WARN("vcl.gdi", "GetObjectW failed: " << WindowsErrorString(GetLastError())); + return ""; + } + + std::cerr << "Bitmap " << hBitmap << ": " << aBitmap.bmWidth << "x" << aBitmap.bmHeight << ":" << std::endl; + int nPos = 0; + for (int i = 1; i < rChunk.mnGlyphCount && nPos < 75; i++) + { + for (int j = nPos; j < rChunk.maLocation[i].Left(); j++) + std::cerr << " "; + std::cerr << "!"; + nPos = rChunk.maLocation[i].Left() + 1; + } + std::cerr << std::endl; + + for (long y = 0; y < std::min(20l, aBitmap.bmHeight); y++) + { + for (long x = 0; x < std::min(75l, aBitmap.bmWidth); x++) + std::cerr << ColorFor(GetPixel(hDC, x, y)); + std::cerr << std::endl; + } + return ""; +} + +template< typename charT, typename traits > +inline std::basic_ostream<charT, traits> & operator <<( + std::basic_ostream<charT, traits> & stream, const std::vector<OpenGLGlyphCacheChunk>& rCache ) +{ + stream << "{"; + for (auto i = rCache.cbegin(); i != rCache.cend(); ++i) + { + stream << "[" << i->mnFirstGlyph << ".." << (i->mnFirstGlyph + i->mnGlyphCount - 1) << "]"; + if (i+1 != rCache.cend()) + { + stream << ","; + assert(i->mnFirstGlyph + i->mnGlyphCount <= (i+1)->mnFirstGlyph); + } + } + + return stream << "}"; +} + inline void ImplWinFontEntry::CacheGlyphWidth( int nCharCode, int nCharWidth ) { maWidthMap[ nCharCode ] = nCharWidth; @@ -105,6 +184,154 @@ inline int ImplWinFontEntry::GetCachedGlyphWidth( int nCharCode ) const return it->second; } +bool ImplWinFontEntry::GlyphIsCached(int nGlyphIndex) const +{ + if (nGlyphIndex == DROPPED_OUTGLYPH) + return true; + + for (size_t i = 0; i < maOpenGLGlyphCache.size(); i++) + if (nGlyphIndex >= maOpenGLGlyphCache[i].mnFirstGlyph && + nGlyphIndex < maOpenGLGlyphCache[i].mnFirstGlyph + maOpenGLGlyphCache[i].mnGlyphCount) + return true; + + return false; +} + +bool ImplWinFontEntry::AddChunkOfGlyphs(int nGlyphIndex, const WinLayout& rLayout, SalGraphics& rGraphics) +{ + const int DEFAULT_CHUNK_SIZE = 20; + + if (nGlyphIndex == DROPPED_OUTGLYPH) + return true; + + SAL_INFO("vcl.gdi.opengl", "AddChunkOfGlyphs " << this << " " << nGlyphIndex << " old: " << maOpenGLGlyphCache); + + auto n = maOpenGLGlyphCache.begin(); + while (n != maOpenGLGlyphCache.end() && + nGlyphIndex > n->mnFirstGlyph) + ++n; + assert(n == maOpenGLGlyphCache.end() || nGlyphIndex < n->mnFirstGlyph); + + int nCount = DEFAULT_CHUNK_SIZE; + if (n != maOpenGLGlyphCache.end() && nGlyphIndex + nCount >= n->mnFirstGlyph) + nCount = n->mnFirstGlyph - nGlyphIndex; + + if (nCount < DEFAULT_CHUNK_SIZE) + { + if (n == maOpenGLGlyphCache.begin()) + { + nGlyphIndex = std::max(0, n->mnFirstGlyph - DEFAULT_CHUNK_SIZE); + } + else + { + nGlyphIndex = std::max(n[-1].mnFirstGlyph + n[-1].mnGlyphCount, + n->mnFirstGlyph - DEFAULT_CHUNK_SIZE); + } + nCount = n->mnFirstGlyph - nGlyphIndex; + } + + OpenGLGlyphCacheChunk aChunk; + aChunk.mnFirstGlyph = nGlyphIndex; + aChunk.mnGlyphCount = nCount; + + std::vector<WORD> aGlyphIndices(nCount); + for (int i = 0; i < nCount; i++) + aGlyphIndices[i] = nGlyphIndex + i; + + HDC hDC = CreateCompatibleDC(rLayout.mhDC); + if (hDC == NULL) + { + SAL_WARN("vcl.gdi", "CreateCompatibleDC failed: " << WindowsErrorString(GetLastError())); + return false; + } + HFONT hOrigFont = static_cast<HFONT>(SelectObject(hDC, rLayout.mhFont)); + if (hOrigFont == NULL) + { + SAL_WARN("vcl.gdi", "SelectObject failed: " << WindowsErrorString(GetLastError())); + DeleteDC(hDC); + return false; + } + + SIZE aSize; + + if (!GetTextExtentExPointI(hDC, aGlyphIndices.data(), nCount, 0, NULL, NULL, &aSize)) + { + SAL_WARN("vcl.gdi", "GetTextExtentExPointI failed: " << WindowsErrorString(GetLastError())); + SelectObject(hDC, hOrigFont); + DeleteDC(hDC); + return false; + } + + if (SelectObject(hDC, hOrigFont) == NULL) + SAL_WARN("vcl.gdi", "SelectObject failed: " << WindowsErrorString(GetLastError())); + if (!DeleteDC(hDC)) + SAL_WARN("vcl.gdi", "DeleteDC failed: " << WindowsErrorString(GetLastError())); + + OpenGLCompatibleDC aDC(rGraphics, 0, 0, aSize.cx, aSize.cy); + + hOrigFont = SelectFont(aDC.getCompatibleHDC(), rLayout.mhFont); + if (hOrigFont == NULL) + { + SAL_WARN("vcl.gdi", "SelectObject failed: " << WindowsErrorString(GetLastError())); + return false; + } + + SetTextColor(aDC.getCompatibleHDC(), RGB(0, 0, 0)); + SetBkColor(aDC.getCompatibleHDC(), RGB(255, 255, 255)); + + std::vector<ABC> aABC(nCount); + if (!GetCharABCWidthsI(aDC.getCompatibleHDC(), 0, nCount, aGlyphIndices.data(), aABC.data())) + { + SAL_WARN("vcl.gdi", "GetCharABCWidthsI failed: " << WindowsErrorString(GetLastError())); + return false; + } + + for (int i = 0; i < nCount; i++) + std::cerr << aABC[i].abcA << ":" << aABC[i].abcB << ":" << aABC[i].abcC << " "; + std::cerr << std::endl; + + // Avoid kerning as we want to be able to use individual rectangles for each glyph + std::vector<int> aDX(nCount); + for (int i = 0; i < nCount; i++) + aDX[i] = std::abs(aABC[i].abcA) + aABC[i].abcB + std::abs(aABC[i].abcC); + if (!ExtTextOutW(aDC.getCompatibleHDC(), 0, 0, ETO_GLYPH_INDEX, NULL, aGlyphIndices.data(), nCount, aDX.data())) + { + SAL_WARN("vcl.gdi", "ExtTextOutW failed: " << WindowsErrorString(GetLastError())); + return false; + } + + aChunk.maLocation.resize(nCount); + UINT nPos = 0; + for (int i = 0; i < nCount; i++) + { + aChunk.maLocation[i].Left() = nPos; + aChunk.maLocation[i].Right() = nPos + aDX[i]; + nPos = aChunk.maLocation[i].Right(); + aChunk.maLocation[i].Top() = 0; + aChunk.maLocation[i].Bottom() = aSize.cy; + } + + aChunk.mpTexture = std::unique_ptr<OpenGLTexture>(aDC.getTexture()); + + maOpenGLGlyphCache.insert(n, aChunk); + + SelectFont(aDC.getCompatibleHDC(), hOrigFont); + + SAL_INFO("vcl.gdi.opengl", "AddChunkOfGlyphs " << this << " now: " << maOpenGLGlyphCache << DumpGlyphBitmap(aChunk, aDC.getCompatibleHDC())); + + return true; +} + +const OpenGLGlyphCacheChunk& ImplWinFontEntry::GetCachedGlyphChunkFor(int nGlyphIndex) const +{ + auto i = maOpenGLGlyphCache.cbegin(); + while (i != maOpenGLGlyphCache.cend() && nGlyphIndex >= i->mnFirstGlyph + i->mnGlyphCount) + ++i; + assert(i != maOpenGLGlyphCache.cend()); + assert(nGlyphIndex >= i->mnFirstGlyph && nGlyphIndex < i->mnFirstGlyph + i->mnGlyphCount); + return *i; +} + WinLayout::WinLayout(HDC hDC, const ImplWinFontData& rWFD, ImplWinFontEntry& rWFE, bool bUseOpenGL) : mhDC( hDC ), mhFont( (HFONT)GetCurrentObject(hDC,OBJ_FONT) ), @@ -157,6 +384,11 @@ void WinLayout::DrawText(SalGraphics& rGraphics) const // no OpenGL, just classic rendering DrawTextImpl(hDC); } + else if (CacheGlyphs(rGraphics) && + DrawCachedGlyphs(rGraphics)) + { + // Nothing + } else { // We have to render the text to a hidden texture, and draw it. @@ -1311,6 +1543,105 @@ void UniscribeLayout::DrawTextImpl(HDC hDC) const DeleteFont(SelectFont(hDC, hOrigFont)); } +bool UniscribeLayout::CacheGlyphs(SalGraphics& rGraphics) const +{ + const bool bDoGlyphCaching = (std::getenv("SAL_ENABLE_GLYPH_CACHING") != NULL); + + if (!bDoGlyphCaching) + return false; + + for (int i = 0; i < mnGlyphCount; i++) + { + if (mrWinFontEntry.GlyphIsCached(mpOutGlyphs[i])) + continue; + + if (!mrWinFontEntry.AddChunkOfGlyphs(mpOutGlyphs[i], *this, rGraphics)) + return false; + } + + return true; +} + +bool UniscribeLayout::DrawCachedGlyphs(SalGraphics& rGraphics) const +{ + WinSalGraphics& rWinGraphics = static_cast<WinSalGraphics&>(rGraphics); + HDC hDC = rWinGraphics.getHDC(); + + Rectangle aRect; + GetBoundRect(rGraphics, aRect); + + COLORREF color = GetTextColor(hDC); + SalColor salColor = MAKE_SALCOLOR(GetRValue(color), GetGValue(color), GetBValue(color)); + + WinOpenGLSalGraphicsImpl *pImpl = dynamic_cast<WinOpenGLSalGraphicsImpl*>(rWinGraphics.mpImpl.get()); + if (!pImpl) + return false; + + pImpl->PreDraw(); + + int nBaseClusterOffset = 0; + int nBaseGlyphPos = -1; + for( int nItem = 0; nItem < mnItemCount; ++nItem ) + { + const VisualItem& rVisualItem = mpVisualItems[ nItem ]; + + // skip if there is nothing to display + int nMinGlyphPos, nEndGlyphPos; + if( !GetItemSubrange( rVisualItem, nMinGlyphPos, nEndGlyphPos ) ) + continue; + + if( nBaseGlyphPos < 0 ) + { + // adjust draw position relative to cluster start + if( rVisualItem.IsRTL() ) + nBaseGlyphPos = nEndGlyphPos - 1; + else + nBaseGlyphPos = nMinGlyphPos; + + int i = mnMinCharPos; + while( (--i >= rVisualItem.mnMinCharPos) + && (nBaseGlyphPos == mpLogClusters[i]) ) + nBaseClusterOffset += mpCharWidths[i]; + + if( !rVisualItem.IsRTL() ) + nBaseClusterOffset = -nBaseClusterOffset; + } + + // now draw the matching glyphs in this item + Point aRelPos( rVisualItem.mnXOffset + nBaseClusterOffset, 0 ); + Point aPos = GetDrawPosition( aRelPos ); + + int nAdvance = 0; + for (int i = nMinGlyphPos; i < nEndGlyphPos; i++) + { + assert(mrWinFontEntry.GlyphIsCached(mpOutGlyphs[i])); + + const OpenGLGlyphCacheChunk& rChunk = mrWinFontEntry.GetCachedGlyphChunkFor(mpOutGlyphs[i]); + const int n = mpOutGlyphs[i] - rChunk.mnFirstGlyph; + + SalTwoRect a2Rects(rChunk.maLocation[n].Left(), rChunk.maLocation[n].Top(), + rChunk.maLocation[n].GetWidth(), rChunk.maLocation[n].GetHeight(), + nAdvance + aPos.X() + mpGlyphOffsets[i].du, aPos.Y() + mpGlyphOffsets[i].dv - rChunk.maLocation[n].GetHeight(), + rChunk.maLocation[n].GetWidth(), rChunk.maLocation[n].GetHeight()); // ??? + pImpl->DrawMask(*rChunk.mpTexture, salColor, a2Rects); + nAdvance += mpGlyphAdvances[i]; + } +#if 0 + ScriptTextOut(hDC, &rScriptCache, + aPos.X(), aPos.Y(), 0, NULL, + &rVisualItem.mpScriptItem->a, NULL, 0, + mpOutGlyphs + nMinGlyphPos, + nEndGlyphPos - nMinGlyphPos, + mpGlyphAdvances + nMinGlyphPos, + mpJustifications ? mpJustifications + nMinGlyphPos : NULL, + mpGlyphOffsets + nMinGlyphPos); +#endif + } + pImpl->PostDraw(); + + return true; +} + DeviceCoordinate UniscribeLayout::FillDXArray( DeviceCoordinate* pDXArray ) const { // calculate width of the complete layout @@ -1954,6 +2285,16 @@ void GraphiteWinLayout::DrawTextImpl(HDC hDC) const DeleteFont(SelectFont(hDC, hOrigFont)); } +bool GraphiteWinLayout::CacheGlyphs(SalGraphics& /*rGraphics*/) const +{ + return false; +} + +bool GraphiteWinLayout::DrawCachedGlyphs(SalGraphics& /*rGraphics*/) const +{ + return false; +} + sal_Int32 GraphiteWinLayout::GetTextBreak(DeviceCoordinate nMaxWidth, DeviceCoordinate nCharExtra, int nFactor) const { sal_Int32 nBreak = maImpl.GetTextBreak(nMaxWidth, nCharExtra, nFactor); diff --git a/vcl/win/source/gdi/winlayout.hxx b/vcl/win/source/gdi/winlayout.hxx index 7819eae..8855e37 100644 --- a/vcl/win/source/gdi/winlayout.hxx +++ b/vcl/win/source/gdi/winlayout.hxx @@ -54,7 +54,9 @@ public: /// Draw to the provided HDC. virtual void DrawTextImpl(HDC hDC) const = 0; -protected: + virtual bool CacheGlyphs(SalGraphics& rGraphics) const = 0; + virtual bool DrawCachedGlyphs(SalGraphics& rGraphics) const = 0; + HDC mhDC; // WIN32 device handle HFONT mhFont; // WIN32 font handle int mnBaseAdv; // x-offset relative to Layout origin @@ -73,6 +75,8 @@ public: virtual bool LayoutText( ImplLayoutArgs& ) SAL_OVERRIDE; virtual void AdjustLayout( ImplLayoutArgs& ) SAL_OVERRIDE; virtual void DrawTextImpl(HDC hDC) const SAL_OVERRIDE; + virtual bool CacheGlyphs(SalGraphics& rGraphics) const SAL_OVERRIDE; + virtual bool DrawCachedGlyphs(SalGraphics& rGraphics) const SAL_OVERRIDE; virtual int GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, int&, DeviceCoordinate* pGlyphAdvances, int* pCharPosAry, const PhysicalFontFace** pFallbackFonts = NULL ) const SAL_OVERRIDE; @@ -160,6 +164,8 @@ public: virtual bool LayoutText( ImplLayoutArgs& ) SAL_OVERRIDE; // first step of layout virtual void AdjustLayout( ImplLayoutArgs& ) SAL_OVERRIDE; // adjusting after fallback etc. virtual void DrawTextImpl(HDC hDC) const SAL_OVERRIDE; + virtual bool CacheGlyphs(SalGraphics& rGraphics) const SAL_OVERRIDE; + virtual bool DrawCachedGlyphs(SalGraphics& rGraphics) const SAL_OVERRIDE; // methods using string indexing virtual sal_Int32 GetTextBreak(DeviceCoordinate nMaxWidth, DeviceCoordinate nCharExtra=0, int nFactor=1) const SAL_OVERRIDE; _______________________________________________ Libreoffice-commits mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
