windows opengl: Introduce OpenGLCompatibleDC.

This is to abstract the compatible DC creation and usage, to be reused in the
native theme rendering.

Change-Id: Id34bba4aeea7f46fc2aa42f292f0a525d753b8d7
diff --git a/include/vcl/salgtype.hxx b/include/vcl/salgtype.hxx
index dc21904..23b8977 100644
--- a/include/vcl/salgtype.hxx
+++ b/include/vcl/salgtype.hxx
@@ -46,6 +46,13 @@ struct SalTwoRect
    long        mnDestY;
    long        mnDestWidth;
    long        mnDestHeight;

    SalTwoRect() {}

    SalTwoRect(long nSrcX, long nSrcY, long nSrcWidth, long nSrcHeight, long nDestX, long nDestY, long nDestWidth, long nDestHeight)
        : mnSrcX(nSrcX), mnSrcY(nSrcY), mnSrcWidth(nSrcWidth), mnSrcHeight(nSrcHeight), mnDestX(nDestX), mnDestY(nDestY), mnDestWidth(nDestWidth), mnDestHeight(nDestHeight)
    {
    }
};

typedef sal_uInt16 SalROPColor;
diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h
index 74e8fe0..831a703 100644
--- a/vcl/inc/win/salgdi.h
+++ b/vcl/inc/win/salgdi.h
@@ -41,6 +41,7 @@ class ImplWinFontEntry;
class ImplFontAttrCache;
class PhysicalFontCollection;
class SalGraphicsImpl;
class WinOpenGLSalGraphicsImpl;

#define RGB_TO_PALRGB(nRGB)         ((nRGB)|0x02000000)
#define PALRGB_TO_RGB(nPalRGB)      ((nPalRGB)&0x00ffffff)
@@ -139,11 +140,43 @@ public:
    bool                    IsGSUBstituted( sal_UCS4 ) const;
};

/** Class that creates (and destroys) a compatible Device Context.

This is to be used for GDI drawing into a DIB that we later use as a texture for OpenGL drawing.
*/
class OpenGLCompatibleDC
{
private:
    /// The compatible DC that we create for our purposes.
    HDC mhCompatibleDC;

    /// DIBSection that we use for the GDI drawing, and later obtain.
    HBITMAP mhBitmap;

    /// DIBSection data.
    sal_uInt8 *mpData;

    /// Mapping between the GDI position and OpenGL, to use for OpenGL drawing.
    SalTwoRect maRects;

    /// The OpenGL-based SalGraphicsImpl where we will draw.  If null, we ignora the drawing, it means it happened directly to the DC..
    WinOpenGLSalGraphicsImpl *mpImpl;

public:
    OpenGLCompatibleDC(SalGraphics &rGraphics, int x, int y, int width, int height);
    ~OpenGLCompatibleDC();

    HDC getCompatibleHDC() { return mhCompatibleDC; }

    /// Call the WinOpenGLSalGraphicsImpl's DrawMask().
    void DrawMask(SalColor color);
};

class WinSalGraphics : public SalGraphics
{
    friend class WinSalGraphicsImpl;
    friend class ScopedFont;
    friend class WinLayout;
    friend class OpenGLCompatibleDC;
private:
    boost::scoped_ptr<SalGraphicsImpl> mpImpl;

diff --git a/vcl/source/outdev/bitmap.cxx b/vcl/source/outdev/bitmap.cxx
index 93c37c4..93a04b8 100644
--- a/vcl/source/outdev/bitmap.cxx
+++ b/vcl/source/outdev/bitmap.cxx
@@ -653,12 +653,12 @@ void OutputDevice::DrawDeviceAlphaBitmap( const Bitmap& rBmp, const AlphaMask& r
        if(bTryDirectPaint)
        {
            Point aRelPt = aOutPt + Point( mnOutOffX, mnOutOffY );
            SalTwoRect aTR = {
            SalTwoRect aTR(
                rSrcPtPixel.X(), rSrcPtPixel.Y(),
                rSrcSizePixel.Width(), rSrcSizePixel.Height(),
                aRelPt.X(), aRelPt.Y(),
                aOutSz.Width(), aOutSz.Height()
            };
                aOutSz.Width(), aOutSz.Height());

            SalBitmap* pSalSrcBmp = rBmp.ImplGetImpBitmap()->ImplGetSalBitmap();
            SalBitmap* pSalAlphaBmp = rAlpha.ImplGetImpBitmap()->ImplGetSalBitmap();

diff --git a/vcl/win/source/gdi/salgdi.cxx b/vcl/win/source/gdi/salgdi.cxx
index 1004fbb..d011f31 100644
--- a/vcl/win/source/gdi/salgdi.cxx
+++ b/vcl/win/source/gdi/salgdi.cxx
@@ -30,6 +30,7 @@
#include <win/saldata.hxx>
#include <win/salgdi.h>
#include <win/salframe.h>
#include <win/salvd.h>
#include <basegfx/matrix/b2dhommatrixtools.hxx>

#include "salgdiimpl.hxx"
@@ -565,6 +566,55 @@ void ImplClearHDCCache( SalData* pData )
    }
}

OpenGLCompatibleDC::OpenGLCompatibleDC(SalGraphics &rGraphics, int x, int y, int width, int height)
    : mhBitmap(0)
    , mpData(NULL)
    , maRects(0, 0, width, height, x, y, width, height)
{
    WinSalGraphics& rWinGraphics = static_cast<WinSalGraphics&>(rGraphics);
    mpImpl = dynamic_cast<WinOpenGLSalGraphicsImpl*>(rWinGraphics.mpImpl.get());

    if (!mpImpl)
    {
        // we avoid the OpenGL drawing, instead we draw directly to the DC
        mhCompatibleDC = rWinGraphics.getHDC();
        return;
    }

    mhCompatibleDC = CreateCompatibleDC(rWinGraphics.getHDC());

    // move the origin so that we always paint at 0,0 - to keep the bitmap
    // small
    OffsetViewportOrgEx(mhCompatibleDC, -x, -y, NULL);

    mhBitmap = WinSalVirtualDevice::ImplCreateVirDevBitmap(mhCompatibleDC, width, height, 32, reinterpret_cast<void **>(&mpData));

    SelectObject(mhCompatibleDC, mhBitmap);
}

OpenGLCompatibleDC::~OpenGLCompatibleDC()
{
    if (mpImpl)
    {
        DeleteObject(mhBitmap);
        DeleteDC(mhCompatibleDC);
    }
}

void OpenGLCompatibleDC::DrawMask(SalColor color)
{
    if (!mpImpl)
        return;

    // turn what's in the mpData into a texture
    OpenGLTexture aTexture(maRects.mnSrcWidth, maRects.mnSrcHeight, GL_RGBA, GL_UNSIGNED_BYTE, mpData);
    CHECK_GL_ERROR();

    mpImpl->PreDraw();
    mpImpl->DrawMask(aTexture, color, maRects);
    mpImpl->PostDraw();
}

WinSalGraphics::WinSalGraphics(WinSalGraphics::Type eType, bool bScreen, HWND hWnd):
    mhLocalDC(0),
    mbPrinter(eType == WinSalGraphics::PRINTER),
diff --git a/vcl/win/source/gdi/winlayout.cxx b/vcl/win/source/gdi/winlayout.cxx
index 1d461e6..8457c55 100644
--- a/vcl/win/source/gdi/winlayout.cxx
+++ b/vcl/win/source/gdi/winlayout.cxx
@@ -27,7 +27,6 @@
#include <vcl/opengl/OpenGLHelper.hxx>
#include <win/salgdi.h>
#include <win/saldata.hxx>
#include <win/salvd.h>

#include "sft.hxx"
#include "sallayout.hxx"
@@ -195,64 +194,28 @@ void WinLayout::DrawText(SalGraphics& rGraphics) const
        Rectangle aRect;
        GetBoundRect(rGraphics, aRect);

        const int origin_x = aRect.Left();
        const int origin_y = aRect.Top();
        const int width = aRect.GetWidth();
        const int height = aRect.GetHeight();
        const int bpp = 32;
        OpenGLCompatibleDC aDC(rGraphics, aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight());

        HDC compatibleDC = CreateCompatibleDC(hDC);

        // move the origin so that we always paint at 0,0 - to keep the bitmap
        // small
        OffsetViewportOrgEx(compatibleDC, -origin_x, -origin_y, NULL);

        sal_uInt8 *data;
        HBITMAP hBitmap = WinSalVirtualDevice::ImplCreateVirDevBitmap(compatibleDC, width, height, bpp, reinterpret_cast<void **>(&data));
        // we are making changes to the DC, make sure we got a new one
        assert(aDC.getCompatibleHDC() != hDC);

        // setup the hidden DC with black color and white background, we will
        // use the result of the text drawing later as a mask only
        HGDIOBJ hBitmapOld = SelectObject(compatibleDC, hBitmap);
        SelectFont(compatibleDC, mhFont);
        SelectFont(aDC.getCompatibleHDC(), mhFont);

        SetTextColor(compatibleDC, RGB(0, 0, 0));
        SetBkColor(compatibleDC, RGB(255, 255, 255));
        SetTextColor(aDC.getCompatibleHDC(), RGB(0, 0, 0));
        SetBkColor(aDC.getCompatibleHDC(), RGB(255, 255, 255));

        UINT nTextAlign = GetTextAlign(hDC);
        SetTextAlign(compatibleDC, nTextAlign);
        SetTextAlign(aDC.getCompatibleHDC(), nTextAlign);

        // the actual drawing
        DrawTextImpl(compatibleDC);
        DrawTextImpl(aDC.getCompatibleHDC());

        SelectObject(compatibleDC, hBitmapOld);
        COLORREF color = GetTextColor(hDC);
        SalColor salColor = MAKE_SALCOLOR(GetRValue(color), GetGValue(color), GetBValue(color));

        // and turn it into a texture
        OpenGLTexture aTexture(width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);
        CHECK_GL_ERROR();

        WinOpenGLSalGraphicsImpl *pImpl = dynamic_cast<WinOpenGLSalGraphicsImpl*>(rWinGraphics.mpImpl.get());
        if (pImpl)
        {
            SalTwoRect aRects;
            aRects.mnSrcX = 0;
            aRects.mnSrcY = 0;
            aRects.mnSrcWidth = width;
            aRects.mnSrcHeight = height;
            aRects.mnDestX = origin_x;
            aRects.mnDestY = origin_y;
            aRects.mnDestWidth = width;
            aRects.mnDestHeight = height;

            COLORREF color = GetTextColor(hDC);
            SalColor salColor = MAKE_SALCOLOR(GetRValue(color), GetGValue(color), GetBValue(color));

            pImpl->PreDraw();
            pImpl->DrawMask(aTexture, salColor, aRects);
            pImpl->PostDraw();
        }

        DeleteObject(hBitmap);
        DeleteDC(compatibleDC);
        aDC.DrawMask(salColor);
    }
}