[Libreoffice-commits] core.git: Branch 'feature/fixes19' - 4 commits - vcl/inc vcl/Library_vcl.mk vcl/opengl vcl/win

Tomaž Vajngerl tomaz.vajngerl at collabora.co.uk
Mon Apr 4 11:32:16 UTC 2016


 vcl/Library_vcl.mk                     |    1 
 vcl/inc/opengl/AccumulatedTextures.hxx |  113 +++++++++
 vcl/inc/opengl/FixedTextureAtlas.hxx   |    1 
 vcl/inc/opengl/PackedTextureAtlas.hxx  |   36 +++
 vcl/inc/opengl/texture.hxx             |   10 
 vcl/inc/openglgdiimpl.hxx              |    5 
 vcl/inc/win/salgdi.h                   |    5 
 vcl/opengl/FixedTextureAtlas.cxx       |   20 +
 vcl/opengl/PackedTextureAtlas.cxx      |  164 +++++++++++++
 vcl/opengl/gdiimpl.cxx                 |   98 ++++++++
 vcl/opengl/texture.cxx                 |   67 +++++
 vcl/win/source/gdi/salgdi.cxx          |    8 
 vcl/win/source/gdi/winlayout.cxx       |  388 +++++++++++----------------------
 13 files changed, 657 insertions(+), 259 deletions(-)

New commits:
commit 4f599a29bf0d37ec583f7fbb8d37289aa2c2a410
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
Date:   Mon Apr 4 19:29:27 2016 +0900

    opengl: use packed texture atlas for glyph cache in win. backend
    
    Change-Id: I6a627699d49bad47213788877fa3947ad2ef83f4

diff --git a/vcl/inc/opengl/AccumulatedTextures.hxx b/vcl/inc/opengl/AccumulatedTextures.hxx
index 9ce170c..e74c065 100644
--- a/vcl/inc/opengl/AccumulatedTextures.hxx
+++ b/vcl/inc/opengl/AccumulatedTextures.hxx
@@ -11,6 +11,8 @@
 #ifndef INCLUDED_VCL_INC_OPENGL_ACCUMULATEDTEXTURES_H
 #define INCLUDED_VCL_INC_OPENGL_ACCUMULATEDTEXTURES_H
 
+#include <vcl/opengl/OpenGLHelper.hxx>
+
 #include <o3tl/make_unique.hxx>
 #include "opengl/texture.hxx"
 #include <memory>
@@ -34,10 +36,10 @@ struct AccumulatedTexturesEntry
         : maTexture(rTexture)
     {}
 
-    void insert(const SalColor& aColor, const SalTwoRect& r2Rect)
+    void insert(const OpenGLTexture& rTexture, const SalColor& aColor, const SalTwoRect& r2Rect)
     {
         TextureDrawParameters& aDrawParameters = maColorTextureDrawParametersMap[aColor];
-        maTexture.FillCoords<GL_TRIANGLES>(aDrawParameters.maTextureCoords, r2Rect, false);
+        rTexture.FillCoords<GL_TRIANGLES>(aDrawParameters.maTextureCoords, r2Rect, false);
 
         GLfloat nX1 = r2Rect.mnDestX;
         GLfloat nY1 = r2Rect.mnDestY;
@@ -86,19 +88,18 @@ public:
         maEntries.clear();
     }
 
-    void insert(const OpenGLTexture& rTexture, const SalColor& aColor, const SalTwoRect& r2Rect)
+    void insert(OpenGLTexture& rTexture, const SalColor& aColor, const SalTwoRect& r2Rect)
     {
         GLuint nTextureId = rTexture.Id();
 
-        auto iterator = maEntries.find(nTextureId);
-
-        if (iterator == maEntries.end())
+        if (maEntries.find(nTextureId) == maEntries.end())
         {
-            maEntries[nTextureId] = o3tl::make_unique<AccumulatedTexturesEntry>(rTexture);
+            OpenGLTexture aWholeTexture(rTexture.GetWholeTexture());
+            maEntries[nTextureId] = o3tl::make_unique<AccumulatedTexturesEntry>(aWholeTexture);
         }
 
         std::unique_ptr<AccumulatedTexturesEntry>& rEntry = maEntries[nTextureId];
-        rEntry->insert(aColor, r2Rect);
+        rEntry->insert(rTexture, aColor, r2Rect);
     }
 
     AccumulatedTexturesMap& getAccumulatedTexturesMap()
diff --git a/vcl/inc/opengl/texture.hxx b/vcl/inc/opengl/texture.hxx
index c51948d..85f4446 100644
--- a/vcl/inc/opengl/texture.hxx
+++ b/vcl/inc/opengl/texture.hxx
@@ -97,7 +97,7 @@ private:
 
 public:
                     OpenGLTexture();
-                    OpenGLTexture(ImplOpenGLTexture* pImpl, Rectangle aRectangle, int nSlotNumber = 0);
+                    OpenGLTexture(ImplOpenGLTexture* pImpl, Rectangle aRectangle, int nSlotNumber);
 
                     OpenGLTexture( int nWidth, int nHeight, bool bAllocate = true );
                     OpenGLTexture( int nWidth, int nHeight, int nFormat, int nType, void const * pData );
@@ -114,7 +114,7 @@ public:
 
     void            GetCoord( GLfloat* pCoord, const SalTwoRect& rPosAry, bool bInverted=false ) const;
     void            GetWholeCoord( GLfloat* pCoord ) const;
-
+    OpenGLTexture   GetWholeTexture();
     void            Bind();
     void            Unbind();
     void            Read( GLenum nFormat, GLenum nType, sal_uInt8* pData );
@@ -122,6 +122,8 @@ public:
     bool            HasStencil() const;
     GLuint          StencilId() const;
 
+    bool            CopyData(int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData);
+
     void            SaveToFile(const OUString& rFileName);
 
     GLenum          GetFilter() const;
diff --git a/vcl/inc/openglgdiimpl.hxx b/vcl/inc/openglgdiimpl.hxx
index 8d6eb1a..dc0cdc2 100644
--- a/vcl/inc/openglgdiimpl.hxx
+++ b/vcl/inc/openglgdiimpl.hxx
@@ -147,7 +147,7 @@ public:
     void DrawLinearGradient( const Gradient& rGradient, const Rectangle& rRect );
     void DrawAxialGradient( const Gradient& rGradient, const Rectangle& rRect );
     void DrawRadialGradient( const Gradient& rGradient, const Rectangle& rRect );
-    void DeferredTextDraw(const OpenGLTexture& rTexture, const SalColor nMaskColor, const SalTwoRect& rPosAry);
+    void DeferredTextDraw(OpenGLTexture& rTexture, const SalColor nMaskColor, const SalTwoRect& rPosAry);
     void FlushDeferredDrawing(bool bInDraw = false);
 
 public:
diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h
index 3d0046e..a9b5004 100644
--- a/vcl/inc/win/salgdi.h
+++ b/vcl/inc/win/salgdi.h
@@ -173,11 +173,16 @@ public:
 
     SalTwoRect getTwoRect() { return maRects; }
 
+    Size getBitmapSize() { return Size(maRects.mnSrcWidth, maRects.mnSrcHeight); }
+
     /// Reset the DC with the defined color.
     void fill(sal_uInt32 color);
 
     /// Obtain the texture; the caller must delete it after use.
     OpenGLTexture* getTexture();
+
+    /// Copy bitmap data to the texture. Texutre must be initialized and the correct size to hold the bitmap.
+    bool copyToTexture(OpenGLTexture& aTexture);
 };
 
 class WinSalGraphics : public SalGraphics
diff --git a/vcl/opengl/gdiimpl.cxx b/vcl/opengl/gdiimpl.cxx
index 6d95cd2..dae26d6 100644
--- a/vcl/opengl/gdiimpl.cxx
+++ b/vcl/opengl/gdiimpl.cxx
@@ -1569,7 +1569,7 @@ void OpenGLSalGraphicsImpl::DrawMask( OpenGLTexture& rMask, SalColor nMaskColor,
     mpProgram->Clean();
 }
 
-void OpenGLSalGraphicsImpl::DeferredTextDraw(const OpenGLTexture& rTexture, SalColor aMaskColor, const SalTwoRect& rPosAry)
+void OpenGLSalGraphicsImpl::DeferredTextDraw(OpenGLTexture& rTexture, SalColor aMaskColor, const SalTwoRect& rPosAry)
 {
     mpAccumulatedTextures->insert(rTexture, aMaskColor, rPosAry);
 }
@@ -1582,6 +1582,8 @@ void OpenGLSalGraphicsImpl::FlushDeferredDrawing(bool bIsInDraw)
     if (!bIsInDraw)
         PreDraw();
 
+    VCL_GL_INFO("FlushDeferredDrawing");
+
     OpenGLZone aZone;
 
 #if 0 // Draw a background rect under text for debugging - same color shows text from the same texture
diff --git a/vcl/opengl/texture.cxx b/vcl/opengl/texture.cxx
index e2c5c5d..1f270bc 100644
--- a/vcl/opengl/texture.cxx
+++ b/vcl/opengl/texture.cxx
@@ -375,26 +375,31 @@ template <>
 void OpenGLTexture::FillCoords<GL_TRIANGLES>(std::vector<GLfloat>& aCoord, const SalTwoRect& rPosAry, bool bInverted) const
 {
     VCL_GL_INFO("Add coord " << Id() << " [" << maRect.Left() << "," << maRect.Top() << "] " << GetWidth() << "x" << GetHeight() );
+    VCL_GL_INFO("   With 2Rect Src  [" << rPosAry.mnSrcX << ", " << rPosAry.mnSrcY << "] wh (" << rPosAry.mnSrcWidth << ", " << rPosAry.mnSrcHeight << ")");
+    VCL_GL_INFO("   With 2Rect Dest [" << rPosAry.mnDestX << ", " << rPosAry.mnDestY << "] wh (" << rPosAry.mnDestWidth << ", " << rPosAry.mnDestHeight << ")");
 
     GLfloat x1 = 0.0f;
     GLfloat x2 = 0.0f;
     GLfloat y1 = 0.0f;
     GLfloat y2 = 0.0f;
 
+    double fTextureWidth(mpImpl->mnWidth);
+    double fTextureHeight(mpImpl->mnHeight);
+
     if (mpImpl)
     {
-        x1 = (maRect.Left() + rPosAry.mnSrcX) / (double) mpImpl->mnWidth;
-        x2 = (maRect.Left() + rPosAry.mnSrcX + rPosAry.mnSrcWidth) / (double) mpImpl->mnWidth;
+        x1 = (maRect.Left() + rPosAry.mnSrcX) / fTextureWidth;
+        x2 = (maRect.Left() + rPosAry.mnSrcX + rPosAry.mnSrcWidth) / fTextureWidth;
 
         if (bInverted)
         {
-            y2 = 1.0f - (maRect.Top() + rPosAry.mnSrcY) / (double) mpImpl->mnHeight;
-            y1 = 1.0f - (maRect.Top() + rPosAry.mnSrcY + rPosAry.mnSrcHeight) / (double) mpImpl->mnHeight;
+            y2 = 1.0f - (maRect.Top() + rPosAry.mnSrcY) / fTextureHeight;
+            y1 = 1.0f - (maRect.Top() + rPosAry.mnSrcY + rPosAry.mnSrcHeight) / fTextureHeight;
         }
         else
         {
-            y1 = 1.0f - (maRect.Top() + rPosAry.mnSrcY) / (double) mpImpl->mnHeight;
-            y2 = 1.0f - (maRect.Top() + rPosAry.mnSrcY + rPosAry.mnSrcHeight) / (double) mpImpl->mnHeight;
+            y1 = 1.0f - (maRect.Top() + rPosAry.mnSrcY) / fTextureHeight;
+            y2 = 1.0f - (maRect.Top() + rPosAry.mnSrcY + rPosAry.mnSrcHeight) / fTextureHeight;
         }
     }
 
@@ -435,6 +440,11 @@ void OpenGLTexture::GetWholeCoord( GLfloat* pCoord ) const
     }
 }
 
+OpenGLTexture OpenGLTexture::GetWholeTexture()
+{
+    return OpenGLTexture(mpImpl, Rectangle(Point(0, 0), Size(mpImpl->mnWidth, mpImpl->mnHeight)), -1);
+}
+
 GLenum OpenGLTexture::GetFilter() const
 {
     if( mpImpl )
@@ -442,6 +452,17 @@ GLenum OpenGLTexture::GetFilter() const
     return GL_NEAREST;
 }
 
+bool OpenGLTexture::CopyData(int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData)
+{
+    if (!pData || mpImpl == nullptr)
+        return false;
+
+    int nX = maRect.Left();
+    int nY = maRect.Top();
+
+    return mpImpl->InsertBuffer(nX, nY, nWidth, nHeight, nFormat, nType, pData);
+}
+
 void OpenGLTexture::SetFilter( GLenum nFilter )
 {
     if( mpImpl )
diff --git a/vcl/win/source/gdi/salgdi.cxx b/vcl/win/source/gdi/salgdi.cxx
index 42ab90e..85d54af 100644
--- a/vcl/win/source/gdi/salgdi.cxx
+++ b/vcl/win/source/gdi/salgdi.cxx
@@ -616,6 +616,14 @@ OpenGLTexture* OpenGLCompatibleDC::getTexture()
     return new OpenGLTexture(maRects.mnSrcWidth, maRects.mnSrcHeight, GL_BGRA, GL_UNSIGNED_BYTE, reinterpret_cast<sal_uInt8*>(mpData));
 }
 
+bool OpenGLCompatibleDC::copyToTexture(OpenGLTexture& aTexture)
+{
+    if (!mpImpl)
+        return false;
+
+    return aTexture.CopyData(maRects.mnSrcWidth, maRects.mnSrcHeight, GL_BGRA, GL_UNSIGNED_BYTE, reinterpret_cast<sal_uInt8*>(mpData));
+}
+
 WinSalGraphics::WinSalGraphics(WinSalGraphics::Type eType, bool bScreen, HWND hWnd, SalGeometryProvider *pProvider):
     mhLocalDC(0),
     mbPrinter(eType == WinSalGraphics::PRINTER),
diff --git a/vcl/win/source/gdi/winlayout.cxx b/vcl/win/source/gdi/winlayout.cxx
index 82c070e..c23f453 100644
--- a/vcl/win/source/gdi/winlayout.cxx
+++ b/vcl/win/source/gdi/winlayout.cxx
@@ -26,6 +26,8 @@
 
 #include <opengl/texture.hxx>
 #include <opengl/win/gdiimpl.hxx>
+#include "opengl/PackedTextureAtlas.hxx"
+
 #include <vcl/opengl/OpenGLHelper.hxx>
 #include <win/salgdi.h>
 #include <win/saldata.hxx>
@@ -74,13 +76,11 @@ const int GLYPH_SPACE_RATIO = 8;
 const int GLYPH_OFFSET_RATIO = GLYPH_SPACE_RATIO * 2;
 }
 
-struct OpenGLGlyphCacheChunk
+struct OpenGLGlyphDrawElement
 {
-    int mnFirstGlyph;           // Must be int to handle non-BMP code points when mbRealGlyphIndices is false
-    int mnGlyphCount;
-    std::vector<Rectangle> maLocation;
-    std::vector<int> maLeftOverhangs;
-    std::shared_ptr<OpenGLTexture> mpTexture;
+    Rectangle maLocation;
+    int maLeftOverhangs;
+    OpenGLTexture maTexture;
     int mnBaselineOffset;
     int mnHeight;
     bool mbVertical;
@@ -97,6 +97,41 @@ struct OpenGLGlyphCacheChunk
     }
 };
 
+class GlyphCache
+{
+private:
+    static PackedTextureAtlasManager sPackedTextureAtlas;
+    std::unordered_map<int, OpenGLGlyphDrawElement> maOpenGLTextureCache;
+
+public:
+    GlyphCache()
+    {}
+
+    void ReserveTextureSpace(OpenGLGlyphDrawElement& rElement, int nWidth, int nHeight)
+    {
+        rElement.maTexture = sPackedTextureAtlas.Reserve(nWidth, nHeight);
+    }
+
+    void PutDrawElementInCache(const OpenGLGlyphDrawElement& rElement, int nGlyphIndex)
+    {
+        assert(!IsGlyphCached(nGlyphIndex));
+        maOpenGLTextureCache[nGlyphIndex] = OpenGLGlyphDrawElement(rElement);
+    }
+
+    OpenGLGlyphDrawElement& GetDrawElement(int nGlyphIndex)
+    {
+        assert(IsGlyphCached(nGlyphIndex));
+        return maOpenGLTextureCache[nGlyphIndex];
+    }
+
+    bool IsGlyphCached(int nGlyphIndex)
+    {
+        return maOpenGLTextureCache.find(nGlyphIndex) != maOpenGLTextureCache.end();
+    }
+};
+
+PackedTextureAtlasManager GlyphCache::sPackedTextureAtlas(2048, 2048);
+
 // win32 specific physical font instance
 class ImplWinFontEntry : public ImplFontEntry
 {
@@ -122,7 +157,6 @@ public:
                             { return maScriptCache; }
 private:
     mutable SCRIPT_CACHE    maScriptCache;
-    std::vector<OpenGLGlyphCacheChunk> maOpenGLGlyphCache;
 
 public:
     int                     GetCachedGlyphWidth( int nCharCode ) const;
@@ -136,9 +170,15 @@ public:
     GLyphyDemo::demo_atlas_t* mpGLyphyAtlas;
     GLyphyDemo::demo_font_t*  mpGLyphyFont;
 
-    bool                    GlyphIsCached(int nGlyphIndex) const;
-    bool                    AddChunkOfGlyphs(bool bRealGlyphIndices, int nGlyphIndex, const WinLayout& rLayout, SalGraphics& rGraphics);
-    const OpenGLGlyphCacheChunk&  GetCachedGlyphChunkFor(int nGlyphIndex) const;
+private:
+    GlyphCache maGlyphCache;
+public:
+    bool CacheGlyphToAtlas(bool bRealGlyphIndices, int nGlyphIndex, const WinLayout& rLayout, SalGraphics& rGraphics);
+
+    GlyphCache& GetGlyphCache()
+    {
+        return maGlyphCache;
+    }
 
 private:
     IntMap                  maWidthMap;
@@ -246,146 +286,16 @@ private:
     HDC               mhDC;
 };
 
-
-#ifdef SAL_LOG_INFO
-
-namespace {
-
-char ColorFor(COLORREF aColor)
-{
-    if (aColor == RGB(0xFF, 0xFF, 0xFF))
-        return ' ';
-    else if (aColor == RGB(0x00, 0x00, 0x00))
-        return 'X';
-
-    return '0' + (10*(GetRValue(aColor) + GetGValue(aColor) + GetBValue(aColor))) / (0xFF*3);
-}
-
-void DumpGlyphBitmap(HDC hDC, const OpenGLGlyphCacheChunk& rChunk)
-{
-    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;
-    }
-
-    SAL_INFO("vcl.gdi.opengl", "Bitmap " << hBitmap << ": " << aBitmap.bmWidth << "x" << aBitmap.bmHeight << ":");
-
-    std::ostringstream sLine("\n", std::ios_base::ate);
-    for (long y = 0; y < aBitmap.bmHeight; y++)
-    {
-        if (y == rChunk.mnBaselineOffset + rChunk.getExtraOffset())
-            sLine << "-";
-        else
-            sLine << ColorFor(GetPixel(hDC, 0, y));
-        for (long x = 1; x < std::min(75l, aBitmap.bmWidth); x++)
-            sLine << ColorFor(GetPixel(hDC, x, y));
-        if (y < aBitmap.bmHeight - 1)
-            sLine << "\n";
-    }
-    SAL_INFO("vcl.gdi.opengl", sLine.str());
-}
-
-} // anonymous namespace
-
-#endif // SAL_LOG_INFO
-
-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;
-        if (i->mnGlyphCount > 1)
-            stream << ".." << (i->mnFirstGlyph + i->mnGlyphCount - 1);
-        stream << "]";
-        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;
-}
-
-inline int ImplWinFontEntry::GetCachedGlyphWidth( int nCharCode ) const
-{
-    IntMap::const_iterator it = maWidthMap.find( nCharCode );
-    if( it == maWidthMap.end() )
-        return -1;
-    return it->second;
-}
-
-bool ImplWinFontEntry::GlyphIsCached(int nGlyphIndex) const
+bool ImplWinFontEntry::CacheGlyphToAtlas(bool bRealGlyphIndices, int nGlyphIndex, const WinLayout& rLayout, SalGraphics& rGraphics)
 {
     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(bool bRealGlyphIndices, int nGlyphIndex, const WinLayout& rLayout, SalGraphics& rGraphics)
-{
-    const int DEFAULT_CHUNK_SIZE = 40;
-
-    if (nGlyphIndex == DROPPED_OUTGLYPH)
-        return true;
-
-    SAL_INFO("vcl.gdi.opengl", "this=" << this << " " << nGlyphIndex << " old: " << maOpenGLGlyphCache);
-
-    auto n = maOpenGLGlyphCache.begin();
-    while (n != maOpenGLGlyphCache.end() &&
-           nGlyphIndex > n->mnFirstGlyph)
-        ++n;
-    assert(n == maOpenGLGlyphCache.end() || nGlyphIndex < n->mnFirstGlyph);
+    OpenGLGlyphDrawElement aElement;
+    aElement.mbRealGlyphIndices = bRealGlyphIndices;
 
-    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;
-    aChunk.mbRealGlyphIndices = bRealGlyphIndices;
-
-    std::vector<uint32_t> aCodePointsOrGlyphIndices(nCount);
-    for (int i = 0; i < nCount; i++)
-        aCodePointsOrGlyphIndices[i] = nGlyphIndex + i;
+    std::vector<uint32_t> aCodePointsOrGlyphIndices(1);
+    aCodePointsOrGlyphIndices[0] = nGlyphIndex;
 
     HDC hDC = CreateCompatibleDC(rLayout.mhDC);
     if (hDC == NULL)
@@ -424,7 +334,7 @@ bool ImplWinFontEntry::AddChunkOfGlyphs(bool bRealGlyphIndices, int nGlyphIndex,
             return false;
         }
     }
-    std::vector<WORD> aGlyphIndices(nCount);
+    std::vector<WORD> aGlyphIndices(1);
     // Fetch the ink boxes and calculate the size of the atlas.
     if (!bRealGlyphIndices)
     {
@@ -436,69 +346,60 @@ bool ImplWinFontEntry::AddChunkOfGlyphs(bool bRealGlyphIndices, int nGlyphIndex,
     }
     else
     {
-        for (int i = 0; i < nCount; i++)
-            aGlyphIndices[i] = aCodePointsOrGlyphIndices[i];
+        aGlyphIndices[0] = aCodePointsOrGlyphIndices[0];
     }
     Rectangle bounds(0, 0, 0, 0);
-    auto aInkBoxes = pTxt->GetGlyphInkBoxes(aGlyphIndices.data(), aGlyphIndices.data() + nCount);
+    auto aInkBoxes = pTxt->GetGlyphInkBoxes(aGlyphIndices.data(), aGlyphIndices.data() + 1);
     for (auto &box : aInkBoxes)
         bounds.Union(box + Point(bounds.Right(), 0));
 
     // bounds.Top() is the offset from the baseline at (0,0) to the top of the
     // inkbox.
-    aChunk.mnBaselineOffset = -bounds.Top();
-    aChunk.mnHeight = bounds.getHeight();
-    aChunk.mbVertical = false;
-
-    aChunk.maLeftOverhangs.resize(nCount);
-    aChunk.maLocation.resize(nCount);
+    aElement.mnBaselineOffset = -bounds.Top();
+    aElement.mnHeight = bounds.getHeight();
+    aElement.mbVertical = false;
 
     // Try hard to avoid overlap as we want to be able to use
     // individual rectangles for each glyph. The ABC widths don't
     // take anti-aliasing into consideration. Let's hope that leaving
     // "extra" space between glyphs will help.
-    std::vector<float> aGlyphAdv(nCount);   // offsets between glyphs
-    std::vector<DWRITE_GLYPH_OFFSET> aGlyphOffset(nCount, DWRITE_GLYPH_OFFSET{0.0f,0.0f});
-    std::vector<int> aEnds(nCount); // end of each glyph box
+    std::vector<float> aGlyphAdv(1);   // offsets between glyphs
+    std::vector<DWRITE_GLYPH_OFFSET> aGlyphOffset(1, DWRITE_GLYPH_OFFSET{0.0f, 0.0f});
+    std::vector<int> aEnds(1); // end of each glyph box
     float totWidth = 0;
-    for (int i = 0; i < nCount; ++i)
     {
-        int overhang = aInkBoxes[i].Left();
-        int blackWidth = aInkBoxes[i].getWidth(); // width of non-AA pixels
-        aChunk.maLeftOverhangs[i] = overhang;
+        int overhang = aInkBoxes[0].Left();
+        int blackWidth = aInkBoxes[0].getWidth(); // width of non-AA pixels
+        aElement.maLeftOverhangs = overhang;
 
-        aGlyphAdv[i] = blackWidth + aChunk.getExtraSpace();
-        aGlyphOffset[i].advanceOffset = -overhang;
+        aGlyphAdv[0] = blackWidth + aElement.getExtraSpace();
+        aGlyphOffset[0].advanceOffset = -overhang;
 
-        totWidth += aGlyphAdv[i];
-        aEnds[i] = totWidth;
+        totWidth += aGlyphAdv[0];
+        aEnds[0] = totWidth;
     }
-
     // Leave extra space also at top and bottom
-    int nBitmapWidth = totWidth,
-        nBitmapHeight = bounds.getHeight() + aChunk.getExtraSpace();
+    int nBitmapWidth = totWidth;
+    int nBitmapHeight = bounds.getHeight() + aElement.getExtraSpace();
 
-    aChunk.maLocation.resize(nCount);
     UINT nPos = 0;
-    for (int i = 0; i < nCount; i++)
+
+    // FIXME: really I don't get why 'vertical' makes any difference [!] what does it mean !?
+    if (aElement.mbVertical)
     {
-        // FIXME: really I don't get why 'vertical' makes any difference [!] what does it mean !?
-        if (aChunk.mbVertical)
-        {
-            aChunk.maLocation[i].Left() = 0;
-            aChunk.maLocation[i].Right() = nBitmapWidth;
-            aChunk.maLocation[i].Top() = nPos;
-            aChunk.maLocation[i].Bottom() = nPos + aGlyphAdv[i] + aChunk.maLeftOverhangs[i];
-        }
-        else
-        {
-            aChunk.maLocation[i].Left() = nPos;
-            aChunk.maLocation[i].Right() = aEnds[i];
-            aChunk.maLocation[i].Top() = 0;
-            aChunk.maLocation[i].Bottom() = bounds.getHeight() + aChunk.getExtraSpace();
-        }
-        nPos = aEnds[i];
+        aElement.maLocation.Left() = 0;
+        aElement.maLocation.Right() = nBitmapWidth;
+        aElement.maLocation.Top() = nPos;
+        aElement.maLocation.Bottom() = nPos + aGlyphAdv[0] + aElement.maLeftOverhangs;
+    }
+    else
+    {
+        aElement.maLocation.Left() = nPos;
+        aElement.maLocation.Right() = aEnds[0];
+        aElement.maLocation.Top() = 0;
+        aElement.maLocation.Bottom() = bounds.getHeight() + aElement.getExtraSpace();
     }
+    nPos = aEnds[0];
 
     OpenGLCompatibleDC aDC(rGraphics, 0, 0, nBitmapWidth, nBitmapHeight);
 
@@ -519,11 +420,15 @@ bool ImplWinFontEntry::AddChunkOfGlyphs(bool bRealGlyphIndices, int nGlyphIndex,
         return false;
     }
 
-    D2D1_POINT_2F baseline = { aChunk.getExtraOffset(), aChunk.getExtraOffset() + aChunk.mnBaselineOffset };
+    D2D1_POINT_2F baseline = {
+        aElement.getExtraOffset(),
+        aElement.getExtraOffset() + aElement.mnBaselineOffset
+    };
+
     DWRITE_GLYPH_RUN glyphs = {
         pTxt->GetFontFace(),
         pTxt->GetEmHeight(),
-        nCount,
+        1,
         aGlyphIndices.data(),
         aGlyphAdv.data(),
         aGlyphOffset.data(),
@@ -533,11 +438,11 @@ bool ImplWinFontEntry::AddChunkOfGlyphs(bool bRealGlyphIndices, int nGlyphIndex,
 
     pRT->BeginDraw();
     pRT->DrawGlyphRun(baseline, &glyphs, pBrush);
-    HRESULT hr = pRT->EndDraw();
+    HRESULT hResult = pRT->EndDraw();
 
     pBrush->Release();
 
-    switch (hr)
+    switch (hResult)
     {
     case S_OK:
         break;
@@ -554,27 +459,28 @@ bool ImplWinFontEntry::AddChunkOfGlyphs(bool bRealGlyphIndices, int nGlyphIndex,
 
     pTxt->ReleaseFont();
 
-    aChunk.mpTexture = std::unique_ptr<OpenGLTexture>(aDC.getTexture());
-
-    maOpenGLGlyphCache.insert(n, aChunk);
+    maGlyphCache.ReserveTextureSpace(aElement, nBitmapWidth, nBitmapHeight);
+    aDC.copyToTexture(aElement.maTexture);
+    maGlyphCache.PutDrawElementInCache(aElement, nGlyphIndex);
 
     SelectFont(aDC.getCompatibleHDC(), hOrigFont);
     if (hNonAntialiasedFont != NULL)
         DeleteObject(hNonAntialiasedFont);
 
-#ifdef SAL_LOG_INFO
-    SAL_INFO("vcl.gdi.opengl", "this=" << this << " now: " << maOpenGLGlyphCache);
-    DumpGlyphBitmap(aDC.getCompatibleHDC(), aChunk);
+    return true;
+}
 
-    {
-        std::ostringstream sLine;
-        for (int i = 0; i < nCount; i++)
-            sLine << aGlyphAdv[i] << ":" << aChunk.maLeftOverhangs[i] << " ";
-        SAL_INFO("vcl.gdi.opengl", "DX:offset : " << sLine.str());
-    }
-#endif
+inline void ImplWinFontEntry::CacheGlyphWidth( int nCharCode, int nCharWidth )
+{
+    maWidthMap[ nCharCode ] = nCharWidth;
+}
 
-    return true;
+inline int ImplWinFontEntry::GetCachedGlyphWidth( int nCharCode ) const
+{
+    IntMap::const_iterator it = maWidthMap.find( nCharCode );
+    if( it == maWidthMap.end() )
+        return -1;
+    return it->second;
 }
 
 SimpleWinLayout::SimpleWinLayout(HDC hDC, BYTE nCharSet, const ImplWinFontData& rWinFontData,
@@ -1273,16 +1179,6 @@ void SimpleWinLayout::Simplify( bool /*bIsBase*/ )
         mnWidth = mnBaseAdv = 0;
 }
 
-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;
-}
-
 void ImplWinFontEntry::setupGLyphy(HDC hDC)
 {
     if (mbGLyphySetupCalled)
@@ -1513,10 +1409,10 @@ bool SimpleWinLayout::CacheGlyphs(SalGraphics& rGraphics) const
             nCodePoint = mpOutGlyphs[i];
         }
 
-        if (mrWinFontEntry.GlyphIsCached(nCodePoint))
+        if (mrWinFontEntry.GetGlyphCache().IsGlyphCached(nCodePoint))
             continue;
 
-        if (!mrWinFontEntry.AddChunkOfGlyphs(false, nCodePoint, *this, rGraphics))
+        if (!mrWinFontEntry.CacheGlyphToAtlas(false, nCodePoint, *this, rGraphics))
             return false;
     }
 
@@ -1559,18 +1455,16 @@ bool SimpleWinLayout::DrawCachedGlyphs(SalGraphics& rGraphics) const
             nCodePoint = mpOutGlyphs[i];
         }
 
-        assert(mrWinFontEntry.GlyphIsCached(nCodePoint));
-
-        const OpenGLGlyphCacheChunk& rChunk = mrWinFontEntry.GetCachedGlyphChunkFor(nCodePoint);
-        const int n = nCodePoint - rChunk.mnFirstGlyph;
+        OpenGLGlyphDrawElement& rElement(mrWinFontEntry.GetGlyphCache().GetDrawElement(nCodePoint));
+        OpenGLTexture& rTexture = rElement.maTexture;
 
-        SalTwoRect a2Rects(rChunk.maLocation[n].Left(), rChunk.maLocation[n].Top(),
-                           rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight(),
-                           nAdvance + aPos.X() - rChunk.getExtraOffset() + rChunk.maLeftOverhangs[n],
-                           aPos.Y() - rChunk.mnBaselineOffset - rChunk.getExtraOffset(),
-                           rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight()); // ???
+        SalTwoRect a2Rects(0, 0,
+                           rTexture.GetWidth(), rTexture.GetHeight(),
+                           nAdvance + aPos.X() - rElement.getExtraOffset() + rElement.maLeftOverhangs,
+                           aPos.Y() - rElement.mnBaselineOffset - rElement.getExtraOffset(),
+                           rTexture.GetWidth(), rTexture.GetHeight());
 
-        pImpl->DeferredTextDraw(*rChunk.mpTexture, salColor, a2Rects);
+        pImpl->DeferredTextDraw(rTexture, salColor, a2Rects);
 
         nAdvance += mpGlyphAdvances[i];
     }
@@ -3045,28 +2939,30 @@ bool UniscribeLayout::DrawCachedGlyphsUsingTextures(SalGraphics& rGraphics) cons
             if (mpOutGlyphs[i] == DROPPED_OUTGLYPH)
                 continue;
 
-            assert(mrWinFontEntry.GlyphIsCached(mpOutGlyphs[i]));
+            OpenGLGlyphDrawElement& rElement = mrWinFontEntry.GetGlyphCache().GetDrawElement(mpOutGlyphs[i]);
+            OpenGLTexture& rTexture = rElement.maTexture;
 
-            const OpenGLGlyphCacheChunk& rChunk = mrWinFontEntry.GetCachedGlyphChunkFor(mpOutGlyphs[i]);
-            const int n = mpOutGlyphs[i] - rChunk.mnFirstGlyph;
-
-            if (rChunk.mbVertical)
+            if (rElement.mbVertical)
             {
-                SalTwoRect a2Rects(rChunk.maLocation[n].Left(), rChunk.maLocation[n].Top(),
-                                   rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight(),
-                                   aPos.X() + rChunk.maLeftOverhangs[n], nAdvance + aPos.Y(),
-                                   rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight()); // ???
-                pImpl->DeferredTextDraw(*rChunk.mpTexture, salColor, a2Rects);
+                SalTwoRect a2Rects(0, 0,
+                                   rTexture.GetWidth(), rTexture.GetHeight(),
+                                   aPos.X() + rElement.maLeftOverhangs,
+                                   nAdvance + aPos.Y(),
+                                   rTexture.GetWidth(), rTexture.GetHeight());
+
+                pImpl->DeferredTextDraw(rTexture, salColor, a2Rects);
             }
             else
             {
-                SalTwoRect a2Rects(rChunk.maLocation[n].Left(), rChunk.maLocation[n].Top(),
-                                   rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight(),
-                                   nAdvance + aPos.X() + mpGlyphOffsets[i].du - rChunk.getExtraOffset() + rChunk.maLeftOverhangs[n],
-                                   aPos.Y() + mpGlyphOffsets[i].dv - rChunk.mnBaselineOffset - rChunk.getExtraOffset(),
-                                   rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight()); // ???
-                pImpl->DeferredTextDraw(*rChunk.mpTexture, salColor, a2Rects);
+                SalTwoRect a2Rects(0, 0,
+                                   rTexture.GetWidth(), rTexture.GetHeight(),
+                                   nAdvance + aPos.X() + mpGlyphOffsets[i].du - rElement.getExtraOffset() + rElement.maLeftOverhangs,
+                                   aPos.Y() + mpGlyphOffsets[i].dv - rElement.mnBaselineOffset - rElement.getExtraOffset(),
+                                   rTexture.GetWidth(), rTexture.GetHeight());
+
+                pImpl->DeferredTextDraw(rTexture, salColor, a2Rects);
             }
+
             nAdvance += pGlyphWidths[i];
         }
     }
commit 9fe0b040befd1f4e9c9a8588752b79b130ef1182
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
Date:   Mon Apr 4 19:27:12 2016 +0900

    opengl: texture atlas efficiently packs textures
    
    Change-Id: I66b3eddadb172da26aa1a62f2a795895769db93b

diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index 5b5c969..7f0b95d 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -135,6 +135,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
 	vcl/opengl/program \
 	vcl/opengl/texture \
 	vcl/opengl/FixedTextureAtlas \
+    vcl/opengl/PackedTextureAtlas \
     vcl/source/opengl/OpenGLContext \
     vcl/source/opengl/OpenGLHelper \
     vcl/source/window/cairo_cairo \
diff --git a/vcl/inc/opengl/FixedTextureAtlas.hxx b/vcl/inc/opengl/FixedTextureAtlas.hxx
index 5b22b619..8d104a7 100644
--- a/vcl/inc/opengl/FixedTextureAtlas.hxx
+++ b/vcl/inc/opengl/FixedTextureAtlas.hxx
@@ -28,6 +28,7 @@ public:
     FixedTextureAtlasManager(int nWidthFactor, int nHeightFactor, int nTextureSize);
     ~FixedTextureAtlasManager();
     OpenGLTexture InsertBuffer(int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData);
+    OpenGLTexture Reserve(int nWidth, int nHeight);
 
     int GetSubtextureSize()
     {
diff --git a/vcl/inc/opengl/PackedTextureAtlas.hxx b/vcl/inc/opengl/PackedTextureAtlas.hxx
new file mode 100644
index 0000000..2d75052
--- /dev/null
+++ b/vcl/inc/opengl/PackedTextureAtlas.hxx
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#ifndef INCLUDED_VCL_INC_OPENGL_PACKEDTEXTUREATLAS_HXX
+#define INCLUDED_VCL_INC_OPENGL_PACKEDTEXTUREATLAS_HXX
+
+#include "opengl/texture.hxx"
+
+struct PackedTexture;
+
+class VCL_PLUGIN_PUBLIC PackedTextureAtlasManager
+{
+    std::vector<std::unique_ptr<PackedTexture>> maPackedTextures;
+
+    int mnTextureWidth;
+    int mnTextureHeight;
+
+    void CreateNewTexture();
+
+public:
+    PackedTextureAtlasManager(int nTextureWidth, int nTextureHeight);
+    ~PackedTextureAtlasManager();
+    OpenGLTexture InsertBuffer(int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData);
+    OpenGLTexture Reserve(int nWidth, int nHeight);
+};
+
+#endif // INCLUDED_VCL_INC_OPENGL_PACKEDTEXTUREATLAS_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/opengl/FixedTextureAtlas.cxx b/vcl/opengl/FixedTextureAtlas.cxx
index 80c1cfe..1ed8311 100644
--- a/vcl/opengl/FixedTextureAtlas.cxx
+++ b/vcl/opengl/FixedTextureAtlas.cxx
@@ -42,7 +42,7 @@ void FixedTextureAtlasManager::CreateNewTexture()
     mpTextures.back()->InitializeSlots(mWidthFactor * mHeightFactor);
 }
 
-OpenGLTexture FixedTextureAtlasManager::InsertBuffer(int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData)
+OpenGLTexture FixedTextureAtlasManager::Reserve(int nWidth, int nHeight)
 {
     ImplOpenGLTexture* pTexture = nullptr;
 
@@ -71,14 +71,18 @@ OpenGLTexture FixedTextureAtlasManager::InsertBuffer(int nWidth, int nHeight, in
 
     Rectangle aRectangle(Point(nX, nY), Size(nWidth, nHeight));
 
-    // If available, copy the image data to the texture
-    if (pData)
-    {
-        if (!pTexture->InsertBuffer(nX, nY, nWidth, nHeight, nFormat, nType, pData))
-            return OpenGLTexture();
-    }
-
     return OpenGLTexture(pTexture, aRectangle, nSlot);
 }
 
+OpenGLTexture FixedTextureAtlasManager::InsertBuffer(int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData)
+{
+    OpenGLTexture aTexture = Reserve(nWidth, nHeight);
+    if (pData == nullptr)
+        return aTexture;
+
+    aTexture.CopyData(nWidth, nHeight, nFormat, nType, pData);
+
+    return aTexture;
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/opengl/PackedTextureAtlas.cxx b/vcl/opengl/PackedTextureAtlas.cxx
new file mode 100644
index 0000000..60fa1e9
--- /dev/null
+++ b/vcl/opengl/PackedTextureAtlas.cxx
@@ -0,0 +1,164 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include <sal/config.h>
+#include <vcl/opengl/OpenGLContext.hxx>
+#include <vcl/opengl/OpenGLHelper.hxx>
+
+#include "opengl/framebuffer.hxx"
+#include "opengl/texture.hxx"
+
+#include "opengl/PackedTextureAtlas.hxx"
+
+struct Node
+{
+    Rectangle mRectangle;
+    std::unique_ptr<Node> mLeftNode;
+    std::unique_ptr<Node> mRightNode;
+    bool mOccupied;
+
+    Node(Rectangle& aRectangle);
+
+    bool isLeaf();
+    Node* insert(int nWidth, int nHeight, int nPadding);
+};
+
+Node::Node(Rectangle& aRectangle)
+    : mRectangle(aRectangle)
+    , mLeftNode()
+    , mRightNode()
+    , mOccupied(false)
+{}
+
+bool Node::isLeaf()
+{
+    return mLeftNode.get()  == nullptr &&
+           mRightNode.get() == nullptr;
+}
+
+Node* Node::insert(int nWidth, int nHeight, int nPadding)
+{
+    if (!isLeaf())
+    {
+        Node* pNewNode = mLeftNode->insert(nWidth, nHeight, nPadding);
+
+        if (pNewNode != nullptr)
+            return pNewNode;
+
+        return mRightNode->insert(nWidth, nHeight, nPadding);
+    }
+    else
+    {
+        if (mOccupied)
+        {
+            return nullptr;
+        }
+
+        if (nWidth > mRectangle.GetWidth() || nHeight > mRectangle.GetHeight())
+        {   // does not fit
+            return nullptr;
+        }
+
+        if (nWidth == mRectangle.GetWidth() && nHeight == mRectangle.GetHeight())
+        {   // perfect fit
+            mOccupied = true;
+            return this;
+        }
+
+        int dw = mRectangle.GetWidth() - nWidth;
+        int dh = mRectangle.GetHeight() - nHeight;
+
+        Rectangle aLeftRect;
+        Rectangle aRightRect;
+        if (dw > dh)
+        {
+            aLeftRect = Rectangle(Point(mRectangle.Left(), mRectangle.Top()),
+                                  Size(nWidth, mRectangle.GetHeight()));
+            aRightRect = Rectangle(Point(nPadding + mRectangle.Left() + nWidth, mRectangle.Top()),
+                                   Size(mRectangle.GetWidth() - nWidth - nPadding, mRectangle.GetHeight()));
+        }
+        else
+        {
+            aLeftRect = Rectangle(Point(mRectangle.Left(), mRectangle.Top()),
+                                  Size(mRectangle.GetWidth(), nHeight));
+            aRightRect = Rectangle(Point(mRectangle.Left(), nPadding + mRectangle.Top() + nHeight),
+                                   Size(mRectangle.GetWidth(), mRectangle.GetHeight() - nHeight - nPadding));
+        }
+
+        mLeftNode.reset(new Node(aLeftRect));
+        mRightNode.reset(new Node(aRightRect));
+
+        return mLeftNode->insert(nWidth, nHeight, nPadding);
+    }
+}
+
+struct PackedTexture
+{
+    std::unique_ptr<Node> mpRootNode;
+    ImplOpenGLTexture* mpTexture;
+};
+
+PackedTextureAtlasManager::PackedTextureAtlasManager(int nTextureWidth, int nTextureHeight)
+    : mnTextureWidth(nTextureWidth)
+    , mnTextureHeight(nTextureHeight)
+{
+}
+
+PackedTextureAtlasManager::~PackedTextureAtlasManager()
+{
+    for (std::unique_ptr<PackedTexture>& pPackedTexture : maPackedTextures)
+    {
+        // Free texture early in VCL shutdown while we have a context.
+        pPackedTexture->mpTexture->Dispose();
+        pPackedTexture->mpTexture->DecreaseRefCount(0);
+    }
+}
+
+void PackedTextureAtlasManager::CreateNewTexture()
+{
+    std::unique_ptr<PackedTexture> pPackedTexture(new PackedTexture);
+    pPackedTexture->mpTexture = new ImplOpenGLTexture(mnTextureWidth, mnTextureHeight, true);
+    Rectangle aInitialRect(Point(0, 0), Size(mnTextureWidth, mnTextureHeight));
+    pPackedTexture->mpRootNode.reset(new Node(aInitialRect));
+    maPackedTextures.push_back(std::move(pPackedTexture));
+}
+
+OpenGLTexture PackedTextureAtlasManager::Reserve(int nWidth, int nHeight)
+{
+    for (std::unique_ptr<PackedTexture>& pPackedTexture : maPackedTextures)
+    {
+        Node* pNode = pPackedTexture->mpRootNode->insert(nWidth, nHeight, 1);
+        if (pNode != nullptr)
+        {
+            return OpenGLTexture(pPackedTexture->mpTexture, pNode->mRectangle, -1);
+        }
+    }
+    CreateNewTexture();
+    std::unique_ptr<PackedTexture>& pPackedTexture = maPackedTextures.back();
+    Node* pNode = pPackedTexture->mpRootNode->insert(nWidth, nHeight, 1);
+    if (pNode != nullptr)
+    {
+        return OpenGLTexture(pPackedTexture->mpTexture, pNode->mRectangle, -1);
+    }
+    return OpenGLTexture();
+}
+
+OpenGLTexture PackedTextureAtlasManager::InsertBuffer(int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData)
+{
+    OpenGLTexture aTexture = Reserve(nWidth, nHeight);
+    if (aTexture && pData == nullptr)
+        return aTexture;
+
+    aTexture.CopyData(nWidth, nHeight, nFormat, nType, pData);
+
+    return aTexture;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 2b6b469b269793cfe71fbc8bf845dd21fa4da22e
Author: Tomaz Vajngerl <tomaz.vajngerl at collabora.com>
Date:   Mon Mar 14 23:01:10 2016 +0100

    opengl: optimize text texture drawing
    
    Change-Id: I795779fa90fd147df8bfb9310ac2b9ce99c85b35

diff --git a/vcl/inc/opengl/AccumulatedTextures.hxx b/vcl/inc/opengl/AccumulatedTextures.hxx
index 3fe327c..9ce170c 100644
--- a/vcl/inc/opengl/AccumulatedTextures.hxx
+++ b/vcl/inc/opengl/AccumulatedTextures.hxx
@@ -15,10 +15,20 @@
 #include "opengl/texture.hxx"
 #include <memory>
 
+struct TextureDrawParameters
+{
+    std::vector<GLfloat> maVertices;
+    std::vector<GLfloat> maTextureCoords;
+    GLint getNumberOfVertices()
+    {
+        return maVertices.size() / 2;
+    }
+};
+
 struct AccumulatedTexturesEntry
 {
     OpenGLTexture maTexture;
-    std::unordered_map<SalColor, std::vector<SalTwoRect>> maColorTwoRectMap;
+    std::unordered_map<SalColor, TextureDrawParameters> maColorTextureDrawParametersMap;
 
     AccumulatedTexturesEntry(const OpenGLTexture& rTexture)
         : maTexture(rTexture)
@@ -26,7 +36,32 @@ struct AccumulatedTexturesEntry
 
     void insert(const SalColor& aColor, const SalTwoRect& r2Rect)
     {
-        maColorTwoRectMap[aColor].push_back(r2Rect);
+        TextureDrawParameters& aDrawParameters = maColorTextureDrawParametersMap[aColor];
+        maTexture.FillCoords<GL_TRIANGLES>(aDrawParameters.maTextureCoords, r2Rect, false);
+
+        GLfloat nX1 = r2Rect.mnDestX;
+        GLfloat nY1 = r2Rect.mnDestY;
+        GLfloat nX2 = r2Rect.mnDestX + r2Rect.mnDestWidth;
+        GLfloat nY2 = r2Rect.mnDestY + r2Rect.mnDestHeight;
+
+        auto& rVertices = aDrawParameters.maVertices;
+        rVertices.push_back(nX1);
+        rVertices.push_back(nY1);
+
+        rVertices.push_back(nX2);
+        rVertices.push_back(nY1);
+
+        rVertices.push_back(nX1);
+        rVertices.push_back(nY2);
+
+        rVertices.push_back(nX1);
+        rVertices.push_back(nY2);
+
+        rVertices.push_back(nX2);
+        rVertices.push_back(nY1);
+
+        rVertices.push_back(nX2);
+        rVertices.push_back(nY2);
     }
 };
 
diff --git a/vcl/inc/opengl/texture.hxx b/vcl/inc/opengl/texture.hxx
index 9388918..c51948d 100644
--- a/vcl/inc/opengl/texture.hxx
+++ b/vcl/inc/opengl/texture.hxx
@@ -111,6 +111,7 @@ public:
     GLuint          Id() const;
     int             GetWidth() const;
     int             GetHeight() const;
+
     void            GetCoord( GLfloat* pCoord, const SalTwoRect& rPosAry, bool bInverted=false ) const;
     void            GetWholeCoord( GLfloat* pCoord ) const;
 
@@ -130,6 +131,9 @@ public:
     OpenGLTexture&  operator=( const OpenGLTexture& rTexture );
     bool            operator==( const OpenGLTexture& rTexture ) const;
     bool            operator!=( const OpenGLTexture& rTexture ) const;
+
+    template<GLenum type>
+    void FillCoords(std::vector<GLfloat>& aCoordVector, const SalTwoRect& rPosAry, bool bInverted) const;
 };
 
 #endif // INCLUDED_VCL_INC_OPENGL_TEXTURE_H
diff --git a/vcl/opengl/gdiimpl.cxx b/vcl/opengl/gdiimpl.cxx
index f0af6f3..6d95cd2 100644
--- a/vcl/opengl/gdiimpl.cxx
+++ b/vcl/opengl/gdiimpl.cxx
@@ -1608,16 +1608,15 @@ void OpenGLSalGraphicsImpl::FlushDeferredDrawing(bool bIsInDraw)
         }
         aUseColor = aColorForTextureMap[rTexture.Id()];
 
-
-
         if (!UseSolid(MAKE_SALCOLOR(aUseColor.GetRed(), aUseColor.GetGreen(), aUseColor.GetBlue())))
             return;
-        for (auto rColorTwoRectPair: rPair.second->maColorTwoRectMap)
+        for (auto rColorTwoRectPair: rPair.second->maColorTextureDrawParametersMap)
         {
-            for (SalTwoRect& rPosAry : rColorTwoRectPair.second)
-            {
-                DrawRect(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth, rPosAry.mnDestHeight);
-            }
+            TextureDrawParameters& rParameters = rColorTwoRectPair.second;
+            ApplyProgramMatrices();
+            mpProgram->SetTextureCoord(rParameters.maTextureCoords.data());
+            mpProgram->SetVertices(rParameters.maVertices.data());
+            glDrawArrays(GL_TRIANGLES, 0, rParameters.getNumberOfVertices());
         }
     }
 #endif
@@ -1629,31 +1628,14 @@ void OpenGLSalGraphicsImpl::FlushDeferredDrawing(bool bIsInDraw)
     {
         OpenGLTexture& rTexture = rPair.second->maTexture;
         mpProgram->SetTexture("sampler", rTexture);
-        for (auto& rColorTwoRectPair: rPair.second->maColorTwoRectMap)
+        for (auto& rColorTwoRectPair: rPair.second->maColorTextureDrawParametersMap)
         {
             mpProgram->SetColor("color", rColorTwoRectPair.first, 0);
-            for (SalTwoRect& rPosAry : rColorTwoRectPair.second)
-            {
-                GLfloat pTexCoord[8];
-                rTexture.GetCoord(pTexCoord, rPosAry, false);
-                mpProgram->SetTextureCoord(pTexCoord);
-
-                GLfloat nX1 = rPosAry.mnDestX;
-                GLfloat nY1 = rPosAry.mnDestY;
-                GLfloat nX2 = rPosAry.mnDestX + rPosAry.mnDestWidth;
-                GLfloat nY2 = rPosAry.mnDestY + rPosAry.mnDestHeight;
-
-                GLfloat pVertices[] =
-                {
-                    nX1, nY2,
-                    nX1, nY1,
-                    nX2, nY1,
-                    nX2, nY2
-                };
-                ApplyProgramMatrices();
-                mpProgram->SetVertices(pVertices);
-                glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-            }
+            TextureDrawParameters& rParameters = rColorTwoRectPair.second;
+            ApplyProgramMatrices();
+            mpProgram->SetTextureCoord(rParameters.maTextureCoords.data());
+            mpProgram->SetVertices(rParameters.maVertices.data());
+            glDrawArrays(GL_TRIANGLES, 0, rParameters.getNumberOfVertices());
         }
     }
     mpProgram->Clean();
diff --git a/vcl/opengl/texture.cxx b/vcl/opengl/texture.cxx
index ffaaf09..e2c5c5d 100644
--- a/vcl/opengl/texture.cxx
+++ b/vcl/opengl/texture.cxx
@@ -371,6 +371,52 @@ void OpenGLTexture::GetCoord( GLfloat* pCoord, const SalTwoRect& rPosAry, bool b
     }
 }
 
+template <>
+void OpenGLTexture::FillCoords<GL_TRIANGLES>(std::vector<GLfloat>& aCoord, const SalTwoRect& rPosAry, bool bInverted) const
+{
+    VCL_GL_INFO("Add coord " << Id() << " [" << maRect.Left() << "," << maRect.Top() << "] " << GetWidth() << "x" << GetHeight() );
+
+    GLfloat x1 = 0.0f;
+    GLfloat x2 = 0.0f;
+    GLfloat y1 = 0.0f;
+    GLfloat y2 = 0.0f;
+
+    if (mpImpl)
+    {
+        x1 = (maRect.Left() + rPosAry.mnSrcX) / (double) mpImpl->mnWidth;
+        x2 = (maRect.Left() + rPosAry.mnSrcX + rPosAry.mnSrcWidth) / (double) mpImpl->mnWidth;
+
+        if (bInverted)
+        {
+            y2 = 1.0f - (maRect.Top() + rPosAry.mnSrcY) / (double) mpImpl->mnHeight;
+            y1 = 1.0f - (maRect.Top() + rPosAry.mnSrcY + rPosAry.mnSrcHeight) / (double) mpImpl->mnHeight;
+        }
+        else
+        {
+            y1 = 1.0f - (maRect.Top() + rPosAry.mnSrcY) / (double) mpImpl->mnHeight;
+            y2 = 1.0f - (maRect.Top() + rPosAry.mnSrcY + rPosAry.mnSrcHeight) / (double) mpImpl->mnHeight;
+        }
+    }
+
+    aCoord.push_back(x1);
+    aCoord.push_back(y1);
+
+    aCoord.push_back(x2);
+    aCoord.push_back(y1);
+
+    aCoord.push_back(x1);
+    aCoord.push_back(y2);
+
+    aCoord.push_back(x1);
+    aCoord.push_back(y2);
+
+    aCoord.push_back(x2);
+    aCoord.push_back(y1);
+
+    aCoord.push_back(x2);
+    aCoord.push_back(y2);
+}
+
 void OpenGLTexture::GetWholeCoord( GLfloat* pCoord ) const
 {
     if( GetWidth() != mpImpl->mnWidth || GetHeight() != mpImpl->mnHeight )
commit 421bf0509406272d6ac2efd78a5a334a22e03e81
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.com>
Date:   Mon Mar 14 11:42:21 2016 +0100

    opengl: draw text with minimum texture switching
    
    In GL we need to draw characters into a bitmap and upload that to
    the GPU. This is expensive so we cache characters in texture
    atlases. Until now when we have drawn from a texture atlas we
    have always done this sequentially for every character and changed
    textures atlases quite extensively. This is quite bad for
    performance. This change deferrs drawing as long as possible and
    sorts drawing commands per texture so when we need to draw we
    draw with minimum texture rebinding.
    
    Change-Id: I237beaa9f3c3a4bcbd9750e107f017911c967704

diff --git a/vcl/inc/opengl/AccumulatedTextures.hxx b/vcl/inc/opengl/AccumulatedTextures.hxx
new file mode 100644
index 0000000..3fe327c
--- /dev/null
+++ b/vcl/inc/opengl/AccumulatedTextures.hxx
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#ifndef INCLUDED_VCL_INC_OPENGL_ACCUMULATEDTEXTURES_H
+#define INCLUDED_VCL_INC_OPENGL_ACCUMULATEDTEXTURES_H
+
+#include <o3tl/make_unique.hxx>
+#include "opengl/texture.hxx"
+#include <memory>
+
+struct AccumulatedTexturesEntry
+{
+    OpenGLTexture maTexture;
+    std::unordered_map<SalColor, std::vector<SalTwoRect>> maColorTwoRectMap;
+
+    AccumulatedTexturesEntry(const OpenGLTexture& rTexture)
+        : maTexture(rTexture)
+    {}
+
+    void insert(const SalColor& aColor, const SalTwoRect& r2Rect)
+    {
+        maColorTwoRectMap[aColor].push_back(r2Rect);
+    }
+};
+
+class AccumulatedTextures
+{
+private:
+    typedef std::unordered_map<GLuint, std::unique_ptr<AccumulatedTexturesEntry>> AccumulatedTexturesMap;
+
+    AccumulatedTexturesMap maEntries;
+
+public:
+    AccumulatedTextures()
+    {}
+
+    bool empty()
+    {
+        return maEntries.empty();
+    }
+
+    void clear()
+    {
+        maEntries.clear();
+    }
+
+    void insert(const OpenGLTexture& rTexture, const SalColor& aColor, const SalTwoRect& r2Rect)
+    {
+        GLuint nTextureId = rTexture.Id();
+
+        auto iterator = maEntries.find(nTextureId);
+
+        if (iterator == maEntries.end())
+        {
+            maEntries[nTextureId] = o3tl::make_unique<AccumulatedTexturesEntry>(rTexture);
+        }
+
+        std::unique_ptr<AccumulatedTexturesEntry>& rEntry = maEntries[nTextureId];
+        rEntry->insert(aColor, r2Rect);
+    }
+
+    AccumulatedTexturesMap& getAccumulatedTexturesMap()
+    {
+        return maEntries;
+    }
+};
+
+#endif // INCLUDED_VCL_INC_OPENGL_TEXTURE_H
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/openglgdiimpl.hxx b/vcl/inc/openglgdiimpl.hxx
index ca8232a..8d6eb1a 100644
--- a/vcl/inc/openglgdiimpl.hxx
+++ b/vcl/inc/openglgdiimpl.hxx
@@ -28,6 +28,7 @@
 #include "opengl/program.hxx"
 #include "opengl/texture.hxx"
 #include "regionband.hxx"
+#include "opengl/AccumulatedTextures.hxx"
 
 #include <vcl/opengl/OpenGLContext.hxx>
 
@@ -99,6 +100,8 @@ protected:
     SalColor mProgramSolidColor;
     double mProgramSolidTransparency;
 
+    std::unique_ptr<AccumulatedTextures> mpAccumulatedTextures;
+
     void ImplInitClipRegion();
     void ImplSetClipBit( const vcl::Region& rClip, GLuint nMask );
     void ImplDrawLineAA( double nX1, double nY1, double nX2, double nY2, bool edge = false );
@@ -144,6 +147,8 @@ public:
     void DrawLinearGradient( const Gradient& rGradient, const Rectangle& rRect );
     void DrawAxialGradient( const Gradient& rGradient, const Rectangle& rRect );
     void DrawRadialGradient( const Gradient& rGradient, const Rectangle& rRect );
+    void DeferredTextDraw(const OpenGLTexture& rTexture, const SalColor nMaskColor, const SalTwoRect& rPosAry);
+    void FlushDeferredDrawing(bool bInDraw = false);
 
 public:
     // get the width of the device
diff --git a/vcl/opengl/gdiimpl.cxx b/vcl/opengl/gdiimpl.cxx
index 59545f8e..f0af6f3 100644
--- a/vcl/opengl/gdiimpl.cxx
+++ b/vcl/opengl/gdiimpl.cxx
@@ -83,6 +83,7 @@ OpenGLSalGraphicsImpl::OpenGLSalGraphicsImpl(SalGraphics& rParent, SalGeometryPr
     , mnDrawCountAtFlush(0)
     , mProgramSolidColor(SALCOLOR_NONE)
     , mProgramSolidTransparency(0.0)
+    , mpAccumulatedTextures(new AccumulatedTextures)
 {
 }
 
@@ -203,6 +204,8 @@ void OpenGLSalGraphicsImpl::PreDraw(XOROption eOpt)
     glViewport( 0, 0, GetWidth(), GetHeight() );
     CHECK_GL_ERROR();
 
+    FlushDeferredDrawing(true);
+
     ImplInitClipRegion();
     CHECK_GL_ERROR();
 
@@ -353,6 +356,11 @@ const vcl::Region& OpenGLSalGraphicsImpl::getClipRegion() const
 bool OpenGLSalGraphicsImpl::setClipRegion( const vcl::Region& rClip )
 {
     VCL_GL_INFO( "::setClipRegion " << rClip );
+    if (maClipRegion == rClip)
+        return true;
+
+    FlushDeferredDrawing();
+
     maClipRegion = rClip;
 
     mbUseStencil = false;
@@ -369,6 +377,11 @@ bool OpenGLSalGraphicsImpl::setClipRegion( const vcl::Region& rClip )
 void OpenGLSalGraphicsImpl::ResetClipRegion()
 {
     VCL_GL_INFO( "::ResetClipRegion" );
+    if (maClipRegion.IsEmpty())
+        return;
+
+    FlushDeferredDrawing();
+
     maClipRegion.SetEmpty();
     mbUseScissor = false;
     mbUseStencil = false;
@@ -1556,6 +1569,99 @@ void OpenGLSalGraphicsImpl::DrawMask( OpenGLTexture& rMask, SalColor nMaskColor,
     mpProgram->Clean();
 }
 
+void OpenGLSalGraphicsImpl::DeferredTextDraw(const OpenGLTexture& rTexture, SalColor aMaskColor, const SalTwoRect& rPosAry)
+{
+    mpAccumulatedTextures->insert(rTexture, aMaskColor, rPosAry);
+}
+
+void OpenGLSalGraphicsImpl::FlushDeferredDrawing(bool bIsInDraw)
+{
+    if (mpAccumulatedTextures->empty())
+        return;
+
+    if (!bIsInDraw)
+        PreDraw();
+
+    OpenGLZone aZone;
+
+#if 0 // Draw a background rect under text for debugging - same color shows text from the same texture
+    static sal_uInt8 r = 0xBE;
+    static sal_uInt8 g = 0xF0;
+    static sal_uInt8 b = 0xFF;
+    static std::unordered_map<GLuint, Color> aColorForTextureMap;
+
+
+    for (auto& rPair : mpAccumulatedTextures->getAccumulatedTexturesMap())
+    {
+        OpenGLTexture& rTexture = rPair.second->maTexture;
+        Color aUseColor;
+        if (aColorForTextureMap.find(rTexture.Id()) == aColorForTextureMap.end())
+        {
+            Color aColor(r, g, b);
+            sal_uInt16 h,s,br;
+            aColor.RGBtoHSB(h, s, br);
+            aColor = Color::HSBtoRGB((h + 40) % 360, s, br);
+            r = aColor.GetRed();
+            g = aColor.GetGreen();
+            b = aColor.GetBlue();
+            aColorForTextureMap[rTexture.Id()] = aColor;
+        }
+        aUseColor = aColorForTextureMap[rTexture.Id()];
+
+
+
+        if (!UseSolid(MAKE_SALCOLOR(aUseColor.GetRed(), aUseColor.GetGreen(), aUseColor.GetBlue())))
+            return;
+        for (auto rColorTwoRectPair: rPair.second->maColorTwoRectMap)
+        {
+            for (SalTwoRect& rPosAry : rColorTwoRectPair.second)
+            {
+                DrawRect(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth, rPosAry.mnDestHeight);
+            }
+        }
+    }
+#endif
+
+    if( !UseProgram( "textureVertexShader", "maskFragmentShader" ) )
+        return;
+    mpProgram->SetBlendMode(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    for (auto& rPair : mpAccumulatedTextures->getAccumulatedTexturesMap())
+    {
+        OpenGLTexture& rTexture = rPair.second->maTexture;
+        mpProgram->SetTexture("sampler", rTexture);
+        for (auto& rColorTwoRectPair: rPair.second->maColorTwoRectMap)
+        {
+            mpProgram->SetColor("color", rColorTwoRectPair.first, 0);
+            for (SalTwoRect& rPosAry : rColorTwoRectPair.second)
+            {
+                GLfloat pTexCoord[8];
+                rTexture.GetCoord(pTexCoord, rPosAry, false);
+                mpProgram->SetTextureCoord(pTexCoord);
+
+                GLfloat nX1 = rPosAry.mnDestX;
+                GLfloat nY1 = rPosAry.mnDestY;
+                GLfloat nX2 = rPosAry.mnDestX + rPosAry.mnDestWidth;
+                GLfloat nY2 = rPosAry.mnDestY + rPosAry.mnDestHeight;
+
+                GLfloat pVertices[] =
+                {
+                    nX1, nY2,
+                    nX1, nY1,
+                    nX2, nY1,
+                    nX2, nY2
+                };
+                ApplyProgramMatrices();
+                mpProgram->SetVertices(pVertices);
+                glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+            }
+        }
+    }
+    mpProgram->Clean();
+    mpAccumulatedTextures->clear();
+    if (!bIsInDraw)
+        PostDraw();
+}
+
 void OpenGLSalGraphicsImpl::DrawLinearGradient( const Gradient& rGradient, const Rectangle& rRect )
 {
     OpenGLZone aZone;
@@ -1919,6 +2025,8 @@ void OpenGLSalGraphicsImpl::DoCopyBits( const SalTwoRect& rPosAry, OpenGLSalGrap
 {
     VCL_GL_INFO( "::copyBits" );
 
+    rImpl.FlushDeferredDrawing();
+
     if( !rImpl.maOffscreenTex )
     {
         VCL_GL_INFO( "::copyBits - skipping copy of un-initialized framebuffer contents of size "
@@ -2015,6 +2123,8 @@ SalBitmap* OpenGLSalGraphicsImpl::getBitmap( long nX, long nY, long nWidth, long
 
 SalColor OpenGLSalGraphicsImpl::getPixel( long nX, long nY )
 {
+    FlushDeferredDrawing();
+
     char pixel[3] = { 0, 0, 0 };
 
     PreDraw( XOROption::IMPLEMENT_XOR );
@@ -2271,6 +2381,8 @@ bool OpenGLSalGraphicsImpl::drawGradient(const tools::PolyPolygon& rPolyPoly,
 
 void OpenGLSalGraphicsImpl::flush()
 {
+    FlushDeferredDrawing();
+
     if( IsOffscreen() )
         return;
 
@@ -2285,6 +2397,8 @@ void OpenGLSalGraphicsImpl::flush()
 
 void OpenGLSalGraphicsImpl::doFlush()
 {
+    FlushDeferredDrawing();
+
     if( IsOffscreen() )
         return;
 
diff --git a/vcl/win/source/gdi/winlayout.cxx b/vcl/win/source/gdi/winlayout.cxx
index 3b1f081..82c070e 100644
--- a/vcl/win/source/gdi/winlayout.cxx
+++ b/vcl/win/source/gdi/winlayout.cxx
@@ -347,7 +347,7 @@ bool ImplWinFontEntry::GlyphIsCached(int nGlyphIndex) const
 
 bool ImplWinFontEntry::AddChunkOfGlyphs(bool bRealGlyphIndices, int nGlyphIndex, const WinLayout& rLayout, SalGraphics& rGraphics)
 {
-    const int DEFAULT_CHUNK_SIZE = 20;
+    const int DEFAULT_CHUNK_SIZE = 40;
 
     if (nGlyphIndex == DROPPED_OUTGLYPH)
         return true;
@@ -1538,8 +1538,6 @@ bool SimpleWinLayout::DrawCachedGlyphs(SalGraphics& rGraphics) const
     if (!pImpl)
         return false;
 
-    pImpl->PreDraw();
-
     HFONT hOrigFont = DisableFontScaling();
     Point aPos = GetDrawPosition( Point( mnBaseAdv, 0 ) );
 
@@ -1571,7 +1569,8 @@ bool SimpleWinLayout::DrawCachedGlyphs(SalGraphics& rGraphics) const
                            nAdvance + aPos.X() - rChunk.getExtraOffset() + rChunk.maLeftOverhangs[n],
                            aPos.Y() - rChunk.mnBaselineOffset - rChunk.getExtraOffset(),
                            rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight()); // ???
-        pImpl->DrawMask(*rChunk.mpTexture, salColor, a2Rects);
+
+        pImpl->DeferredTextDraw(*rChunk.mpTexture, salColor, a2Rects);
 
         nAdvance += mpGlyphAdvances[i];
     }
@@ -1579,8 +1578,6 @@ bool SimpleWinLayout::DrawCachedGlyphs(SalGraphics& rGraphics) const
     if( hOrigFont )
         DeleteFont(SelectFont(hDC, hOrigFont));
 
-    pImpl->PostDraw();
-
     return true;
 }
 
@@ -3001,8 +2998,6 @@ bool UniscribeLayout::DrawCachedGlyphsUsingTextures(SalGraphics& rGraphics) cons
     if (!pImpl)
         return false;
 
-    pImpl->PreDraw();
-
     // FIXME: This code snippet is mostly copied from the one in
     // UniscribeLayout::DrawTextImpl. Should be factored out.
     int nBaseClusterOffset = 0;
@@ -3061,7 +3056,7 @@ bool UniscribeLayout::DrawCachedGlyphsUsingTextures(SalGraphics& rGraphics) cons
                                    rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight(),
                                    aPos.X() + rChunk.maLeftOverhangs[n], nAdvance + aPos.Y(),
                                    rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight()); // ???
-                pImpl->DrawMask(*rChunk.mpTexture, salColor, a2Rects);
+                pImpl->DeferredTextDraw(*rChunk.mpTexture, salColor, a2Rects);
             }
             else
             {
@@ -3070,12 +3065,11 @@ bool UniscribeLayout::DrawCachedGlyphsUsingTextures(SalGraphics& rGraphics) cons
                                    nAdvance + aPos.X() + mpGlyphOffsets[i].du - rChunk.getExtraOffset() + rChunk.maLeftOverhangs[n],
                                    aPos.Y() + mpGlyphOffsets[i].dv - rChunk.mnBaselineOffset - rChunk.getExtraOffset(),
                                    rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight()); // ???
-                pImpl->DrawMask(*rChunk.mpTexture, salColor, a2Rects);
+                pImpl->DeferredTextDraw(*rChunk.mpTexture, salColor, a2Rects);
             }
             nAdvance += pGlyphWidths[i];
         }
     }
-    pImpl->PostDraw();
 
     return true;
 }


More information about the Libreoffice-commits mailing list