summaryrefslogtreecommitdiffstats
path: root/canvas/source/opengl
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
commit940b4d1848e8c70ab7642901a68594e8016caffc (patch)
treeeb72f344ee6c3d9b80a7ecc079ea79e9fba8676d /canvas/source/opengl
parentInitial commit. (diff)
downloadlibreoffice-upstream.tar.xz
libreoffice-upstream.zip
Adding upstream version 1:7.0.4.upstream/1%7.0.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'canvas/source/opengl')
-rw-r--r--canvas/source/opengl/ogl_bitmapcanvashelper.cxx65
-rw-r--r--canvas/source/opengl/ogl_bitmapcanvashelper.hxx74
-rw-r--r--canvas/source/opengl/ogl_buffercontext.hxx38
-rw-r--r--canvas/source/opengl/ogl_canvasbitmap.cxx52
-rw-r--r--canvas/source/opengl/ogl_canvasbitmap.hxx75
-rw-r--r--canvas/source/opengl/ogl_canvascustomsprite.cxx261
-rw-r--r--canvas/source/opengl/ogl_canvascustomsprite.hxx95
-rw-r--r--canvas/source/opengl/ogl_canvasfont.cxx69
-rw-r--r--canvas/source/opengl/ogl_canvasfont.hxx64
-rw-r--r--canvas/source/opengl/ogl_canvashelper.cxx947
-rw-r--r--canvas/source/opengl/ogl_canvashelper.hxx222
-rw-r--r--canvas/source/opengl/ogl_canvastools.cxx148
-rw-r--r--canvas/source/opengl/ogl_canvastools.hxx40
-rw-r--r--canvas/source/opengl/ogl_spritecanvas.cxx179
-rw-r--r--canvas/source/opengl/ogl_spritecanvas.hxx117
-rw-r--r--canvas/source/opengl/ogl_spritedevicehelper.cxx555
-rw-r--r--canvas/source/opengl/ogl_spritedevicehelper.hxx139
-rw-r--r--canvas/source/opengl/ogl_textlayout.cxx180
-rw-r--r--canvas/source/opengl/ogl_textlayout.hxx73
-rw-r--r--canvas/source/opengl/ogl_texturecache.cxx117
-rw-r--r--canvas/source/opengl/ogl_texturecache.hxx64
-rw-r--r--canvas/source/opengl/ogl_tools.hxx30
-rw-r--r--canvas/source/opengl/oglcanvas.component16
23 files changed, 3620 insertions, 0 deletions
diff --git a/canvas/source/opengl/ogl_bitmapcanvashelper.cxx b/canvas/source/opengl/ogl_bitmapcanvashelper.cxx
new file mode 100644
index 000000000..0b95dfb2a
--- /dev/null
+++ b/canvas/source/opengl/ogl_bitmapcanvashelper.cxx
@@ -0,0 +1,65 @@
+/* -*- 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 <canvas/canvastools.hxx>
+
+#include "ogl_bitmapcanvashelper.hxx"
+
+
+using namespace ::com::sun::star;
+
+namespace oglcanvas
+{
+ BitmapCanvasHelper::BitmapCanvasHelper()
+ {}
+
+ void BitmapCanvasHelper::disposing()
+ {
+ CanvasHelper::disposing();
+ }
+
+ void BitmapCanvasHelper::init( rendering::XGraphicDevice& rDevice,
+ SpriteDeviceHelper& rDeviceHelper,
+ const geometry::IntegerSize2D& rSize )
+ {
+ maSize = rSize;
+ CanvasHelper::init(rDevice,rDeviceHelper);
+ }
+
+ uno::Reference< rendering::XBitmap > BitmapCanvasHelper::getScaledBitmap( const geometry::RealSize2D& /*newSize*/,
+ bool /*beFast*/ )
+ {
+ // TODO(F1):
+ return uno::Reference< rendering::XBitmap >();
+ }
+
+ uno::Sequence< sal_Int8 > BitmapCanvasHelper::getData( rendering::IntegerBitmapLayout& /*bitmapLayout*/,
+ const geometry::IntegerRectangle2D& /*rect*/ )
+ {
+ // TODO(F2): NYI - and improbable to ever be
+ return uno::Sequence< sal_Int8 >();
+ }
+
+ uno::Sequence< sal_Int8 > BitmapCanvasHelper::getPixel( rendering::IntegerBitmapLayout& /*bitmapLayout*/,
+ const geometry::IntegerPoint2D& /*pos*/ )
+ {
+ // TODO(F2): NYI - and improbable to ever be
+ return uno::Sequence< sal_Int8 >();
+ }
+
+ rendering::IntegerBitmapLayout BitmapCanvasHelper::getMemoryLayout() const
+ {
+ return ::canvas::tools::getStdMemoryLayout(getSize());
+ }
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/canvas/source/opengl/ogl_bitmapcanvashelper.hxx b/canvas/source/opengl/ogl_bitmapcanvashelper.hxx
new file mode 100644
index 000000000..08258174b
--- /dev/null
+++ b/canvas/source/opengl/ogl_bitmapcanvashelper.hxx
@@ -0,0 +1,74 @@
+/* -*- 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_CANVAS_SOURCE_OPENGL_OGL_BITMAPCANVASHELPER_HXX
+#define INCLUDED_CANVAS_SOURCE_OPENGL_OGL_BITMAPCANVASHELPER_HXX
+
+#include <com/sun/star/geometry/IntegerPoint2D.hpp>
+#include <com/sun/star/geometry/IntegerRectangle2D.hpp>
+#include <com/sun/star/rendering/IntegerBitmapLayout.hpp>
+
+#include "ogl_canvashelper.hxx"
+
+namespace oglcanvas
+{
+ /** Helper class for basic canvas functionality. */
+ class BitmapCanvasHelper : public CanvasHelper
+ {
+ public:
+ BitmapCanvasHelper();
+
+ /// Release all references
+ void disposing();
+
+ /** Initialize canvas helper
+
+ This method late-initializes the canvas helper, providing
+ it with the necessary device and output objects. Note that
+ the CanvasHelper does <em>not</em> take ownership of the
+ passed rDevice reference, nor does it perform any
+ reference counting. Thus, to prevent the reference counted
+ SpriteCanvas object from deletion, the user of this class
+ is responsible for holding ref-counted references itself!
+
+ @param rDevice
+ Reference device this canvas is associated with
+
+ */
+ void init( css::rendering::XGraphicDevice& rDevice,
+ SpriteDeviceHelper& rDeviceHelper,
+ const css::geometry::IntegerSize2D& rSize );
+
+ // BitmapCanvasHelper functionality
+ // ================================
+
+ const css::geometry::IntegerSize2D& getSize() const { return maSize; }
+
+ css::uno::Reference< css::rendering::XBitmap >
+ getScaledBitmap( const css::geometry::RealSize2D& newSize,
+ bool beFast );
+
+ css::uno::Sequence< sal_Int8 >
+ getData( css::rendering::IntegerBitmapLayout& bitmapLayout,
+ const css::geometry::IntegerRectangle2D& rect );
+
+ css::uno::Sequence< sal_Int8 >
+ getPixel( css::rendering::IntegerBitmapLayout& bitmapLayout,
+ const css::geometry::IntegerPoint2D& pos );
+
+ css::rendering::IntegerBitmapLayout getMemoryLayout() const;
+
+ private:
+ css::geometry::IntegerSize2D maSize;
+ };
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/canvas/source/opengl/ogl_buffercontext.hxx b/canvas/source/opengl/ogl_buffercontext.hxx
new file mode 100644
index 000000000..717adb1d6
--- /dev/null
+++ b/canvas/source/opengl/ogl_buffercontext.hxx
@@ -0,0 +1,38 @@
+/* -*- 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_CANVAS_SOURCE_OPENGL_OGL_BUFFERCONTEXT_HXX
+#define INCLUDED_CANVAS_SOURCE_OPENGL_OGL_BUFFERCONTEXT_HXX
+
+#include <epoxy/gl.h>
+
+#include <sal/config.h>
+#include <memory>
+
+namespace oglcanvas
+{
+ struct IBufferContext
+ {
+ virtual ~IBufferContext() {}
+
+ /// start render to buffer. changes current framebuffer
+ virtual void startBufferRendering() = 0;
+
+ /// end render to buffer. switches to default framebuffer
+ virtual void endBufferRendering() = 0;
+
+ virtual GLuint getTextureId() = 0;
+ };
+
+ typedef std::shared_ptr<IBufferContext> IBufferContextSharedPtr;
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/canvas/source/opengl/ogl_canvasbitmap.cxx b/canvas/source/opengl/ogl_canvasbitmap.cxx
new file mode 100644
index 000000000..2a476ec91
--- /dev/null
+++ b/canvas/source/opengl/ogl_canvasbitmap.cxx
@@ -0,0 +1,52 @@
+/* -*- 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 <tools/diagnose_ex.h>
+
+#include "ogl_canvasbitmap.hxx"
+
+
+using namespace ::com::sun::star;
+
+namespace oglcanvas
+{
+ CanvasBitmap::CanvasBitmap( const geometry::IntegerSize2D& rSize,
+ const SpriteCanvasRef& rDevice,
+ SpriteDeviceHelper& rDeviceHelper ) :
+ mpDevice( rDevice )
+ {
+ ENSURE_OR_THROW( mpDevice.is(),
+ "CanvasBitmap::CanvasBitmap(): Invalid surface or device" );
+
+ maCanvasHelper.init( *mpDevice, rDeviceHelper, rSize );
+ }
+
+ CanvasBitmap::CanvasBitmap( const CanvasBitmap& rSrc ) :
+ mpDevice( rSrc.mpDevice )
+ {
+ maCanvasHelper = rSrc.maCanvasHelper;
+ }
+
+ void CanvasBitmap::disposeThis()
+ {
+ mpDevice.clear();
+
+ // forward to parent
+ CanvasBitmapBaseT::disposeThis();
+ }
+
+ bool CanvasBitmap::renderRecordedActions() const
+ {
+ return maCanvasHelper.renderRecordedActions();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/canvas/source/opengl/ogl_canvasbitmap.hxx b/canvas/source/opengl/ogl_canvasbitmap.hxx
new file mode 100644
index 000000000..72ac619c5
--- /dev/null
+++ b/canvas/source/opengl/ogl_canvasbitmap.hxx
@@ -0,0 +1,75 @@
+/* -*- 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_CANVAS_SOURCE_OPENGL_OGL_CANVASBITMAP_HXX
+#define INCLUDED_CANVAS_SOURCE_OPENGL_OGL_CANVASBITMAP_HXX
+
+#include <cppuhelper/compbase.hxx>
+
+#include <com/sun/star/rendering/XBitmapCanvas.hpp>
+#include <com/sun/star/rendering/XIntegerBitmap.hpp>
+
+#include <base/integerbitmapbase.hxx>
+#include <base/basemutexhelper.hxx>
+#include <base/bitmapcanvasbase.hxx>
+
+#include "ogl_bitmapcanvashelper.hxx"
+#include "ogl_spritecanvas.hxx"
+
+
+/* Definition of CanvasBitmap class */
+
+namespace oglcanvas
+{
+ typedef ::cppu::WeakComponentImplHelper< css::rendering::XBitmapCanvas,
+ css::rendering::XIntegerBitmap > CanvasBitmapBase_Base;
+ typedef ::canvas::IntegerBitmapBase<
+ canvas::BitmapCanvasBase2<
+ ::canvas::BaseMutexHelper< CanvasBitmapBase_Base >,
+ BitmapCanvasHelper,
+ ::osl::MutexGuard,
+ ::cppu::OWeakObject> > CanvasBitmapBaseT;
+
+ class CanvasBitmap : public CanvasBitmapBaseT
+ {
+ public:
+ /** Create a canvas bitmap for the given surface
+
+ @param rSize
+ Size of the bitmap
+
+ @param rDevice
+ Reference device, with which bitmap should be compatible
+ */
+ CanvasBitmap( const css::geometry::IntegerSize2D& rSize,
+ const SpriteCanvasRef& rDevice,
+ SpriteDeviceHelper& rDeviceHelper );
+
+ /** Create verbatim copy (including all recorded actions)
+ */
+ CanvasBitmap( const CanvasBitmap& rSrc );
+
+ /// Dispose all internal references
+ virtual void disposeThis() override;
+
+ /** Write out recorded actions
+ */
+ bool renderRecordedActions() const;
+
+ private:
+ /** MUST hold here, too, since CanvasHelper only contains a
+ raw pointer (without refcounting)
+ */
+ SpriteCanvasRef mpDevice;
+ };
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/canvas/source/opengl/ogl_canvascustomsprite.cxx b/canvas/source/opengl/ogl_canvascustomsprite.cxx
new file mode 100644
index 000000000..c7ca59b28
--- /dev/null
+++ b/canvas/source/opengl/ogl_canvascustomsprite.cxx
@@ -0,0 +1,261 @@
+/* -*- 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 <epoxy/gl.h>
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/polygon/b2dpolygontriangulator.hxx>
+#include <basegfx/utils/canvastools.hxx>
+#include <canvas/canvastools.hxx>
+#include <verifyinput.hxx>
+#include <tools/diagnose_ex.h>
+
+#include "ogl_canvascustomsprite.hxx"
+#include "ogl_canvastools.hxx"
+#include "ogl_tools.hxx"
+
+using namespace ::com::sun::star;
+
+namespace oglcanvas
+{
+ CanvasCustomSprite::CanvasCustomSprite( const css::geometry::RealSize2D& rSpriteSize,
+ const SpriteCanvasRef& rRefDevice,
+ SpriteDeviceHelper& rDeviceHelper ) :
+ mpSpriteCanvas( rRefDevice ),
+ maSize(rSpriteSize),
+ mxClip(),
+ maTransformation(),
+ maPosition(),
+ mfAlpha(0.0),
+ mfPriority(0.0)
+ {
+ ENSURE_OR_THROW( rRefDevice.get(),
+ "CanvasCustomSprite::CanvasCustomSprite(): Invalid sprite canvas" );
+
+ ::canvas::tools::setIdentityAffineMatrix2D(maTransformation);
+ maCanvasHelper.init( *rRefDevice,
+ rDeviceHelper );
+ }
+
+ void CanvasCustomSprite::disposeThis()
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ mpSpriteCanvas.clear();
+
+ // forward to parent
+ CanvasCustomSpriteBaseT::disposeThis();
+ }
+
+ void SAL_CALL CanvasCustomSprite::setAlpha( double alpha )
+ {
+ canvas::tools::verifyRange( alpha, 0.0, 1.0 );
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ mfAlpha = alpha;
+ }
+
+ void SAL_CALL CanvasCustomSprite::move( const geometry::RealPoint2D& aNewPos,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ canvas::tools::verifyArgs(aNewPos, viewState, renderState,
+ OSL_THIS_FUNC,
+ static_cast< ::cppu::OWeakObject* >(this));
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ ::basegfx::B2DHomMatrix aTransform;
+ ::canvas::tools::mergeViewAndRenderTransform(aTransform,
+ viewState,
+ renderState);
+
+ // convert position to device pixel
+ maPosition = ::basegfx::unotools::b2DPointFromRealPoint2D(aNewPos);
+ maPosition *= aTransform;
+ }
+
+ void SAL_CALL CanvasCustomSprite::transform( const geometry::AffineMatrix2D& aTransformation )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ maTransformation = aTransformation;
+ }
+
+ void SAL_CALL CanvasCustomSprite::clip( const uno::Reference< rendering::XPolyPolygon2D >& xClip )
+ {
+ mxClip = xClip;
+ }
+
+ void SAL_CALL CanvasCustomSprite::setPriority( double nPriority )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ mfPriority = nPriority;
+ }
+
+ void SAL_CALL CanvasCustomSprite::show()
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if( mpSpriteCanvas.is() )
+ mpSpriteCanvas->show(this);
+ }
+
+ void SAL_CALL CanvasCustomSprite::hide()
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if( mpSpriteCanvas.is() )
+ mpSpriteCanvas->hide(this);
+ }
+
+ uno::Reference< rendering::XCanvas > SAL_CALL CanvasCustomSprite::getContentCanvas()
+ {
+ return this;
+ }
+
+ bool CanvasCustomSprite::renderSprite() const
+ {
+ if( ::basegfx::fTools::equalZero( mfAlpha ) )
+ return true;
+
+ TransformationPreserver aPreserver1;
+ const ::basegfx::B2IVector aSpriteSizePixel(
+ ::canvas::tools::roundUp( maSize.Width ),
+ ::canvas::tools::roundUp( maSize.Height ));
+
+ // translate sprite to output position
+ glTranslated(maPosition.getX(), maPosition.getY(), 0);
+
+ {
+ TransformationPreserver aPreserver2;
+
+ // apply sprite content transformation matrix
+ double aGLTransform[] =
+ {
+ maTransformation.m00, maTransformation.m10, 0, 0,
+ maTransformation.m01, maTransformation.m11, 0, 0,
+ 0, 0, 1, 0,
+ maTransformation.m02, maTransformation.m12, 0, 1
+ };
+ glMultMatrixd(aGLTransform);
+
+ IBufferContextSharedPtr pBufferContext;
+ if( mfAlpha != 1.0 || mxClip.is() )
+ {
+ // drafts. Need to render to temp surface before, and then
+ // composite that to screen
+
+ // TODO(P3): buffer texture
+ pBufferContext = maCanvasHelper.getDeviceHelper()->createBufferContext(aSpriteSizePixel);
+ pBufferContext->startBufferRendering();
+ }
+
+ // this ends up in pBufferContext, if that one's "current"
+ if( !maCanvasHelper.renderRecordedActions() )
+ return false;
+
+ if( pBufferContext )
+ {
+ // content ended up in background buffer - compose to
+ // screen now. Calls below switches us back to window
+ // context, and binds to generated, dynamic texture
+ pBufferContext->endBufferRendering();
+ GLuint nTexture = pBufferContext->getTextureId();
+ glBindTexture(GL_TEXTURE_2D, nTexture);
+
+ glEnable(GL_TEXTURE_2D);
+ glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_MAG_FILTER,
+ GL_NEAREST);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA,
+ GL_ONE_MINUS_SRC_ALPHA);
+
+ // blend against fixed vertex color; texture alpha is multiplied in
+ glColor4f(1,1,1,mfAlpha);
+
+ if( mxClip.is() )
+ {
+ const double fWidth=maSize.Width;
+ const double fHeight=maSize.Height;
+
+ // TODO(P3): buffer triangulation
+ const ::basegfx::triangulator::B2DTriangleVector rTriangulatedPolygon(
+ ::basegfx::triangulator::triangulate(
+ ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(mxClip)));
+
+ glBegin(GL_TRIANGLES);
+ for( size_t i=0; i<rTriangulatedPolygon.size(); i++ )
+ {
+ const::basegfx::triangulator::B2DTriangle& rCandidate(rTriangulatedPolygon[i]);
+ glTexCoord2f(
+ rCandidate.getA().getX()/fWidth,
+ rCandidate.getA().getY()/fHeight);
+ glVertex2d(
+ rCandidate.getA().getX(),
+ rCandidate.getA().getY());
+
+ glTexCoord2f(
+ rCandidate.getB().getX()/fWidth,
+ rCandidate.getB().getY()/fHeight);
+ glVertex2d(
+ rCandidate.getB().getX(),
+ rCandidate.getB().getY());
+
+ glTexCoord2f(
+ rCandidate.getC().getX()/fWidth,
+ rCandidate.getC().getY()/fHeight);
+ glVertex2d(
+ rCandidate.getC().getX(),
+ rCandidate.getC().getY());
+ }
+ glEnd();
+ }
+ else
+ {
+ const double fWidth=maSize.Width/aSpriteSizePixel.getX();
+ const double fHeight=maSize.Height/aSpriteSizePixel.getY();
+
+ glBegin(GL_TRIANGLE_STRIP);
+ glTexCoord2f(0,0); glVertex2d(0,0);
+ glTexCoord2f(0,fHeight); glVertex2d(0, aSpriteSizePixel.getY());
+ glTexCoord2f(fWidth,0); glVertex2d(aSpriteSizePixel.getX(),0);
+ glTexCoord2f(fWidth,fHeight); glVertex2d(aSpriteSizePixel.getX(),aSpriteSizePixel.getY());
+ glEnd();
+ }
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glDisable(GL_TEXTURE_2D);
+ }
+ }
+
+ glColor4f(1,0,0,1);
+ glBegin(GL_LINE_STRIP);
+ glVertex2d(-2,-2);
+ glVertex2d(-2,maSize.Height+4);
+ glVertex2d(maSize.Width+4,maSize.Height+4);
+ glVertex2d(maSize.Width+4,-2);
+ glVertex2d(-2,-2);
+ glVertex2d(maSize.Width+4,maSize.Height+4);
+ glEnd();
+
+ std::vector<double> aVec;
+ aVec.push_back(mfAlpha);
+ aVec.push_back(mfPriority);
+ aVec.push_back(maCanvasHelper.getRecordedActionCount());
+ renderOSD( aVec, 10 );
+
+ return true;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/canvas/source/opengl/ogl_canvascustomsprite.hxx b/canvas/source/opengl/ogl_canvascustomsprite.hxx
new file mode 100644
index 000000000..0f0a7693c
--- /dev/null
+++ b/canvas/source/opengl/ogl_canvascustomsprite.hxx
@@ -0,0 +1,95 @@
+/* -*- 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_CANVAS_SOURCE_OPENGL_OGL_CANVASCUSTOMSPRITE_HXX
+#define INCLUDED_CANVAS_SOURCE_OPENGL_OGL_CANVASCUSTOMSPRITE_HXX
+
+#include <cppuhelper/compbase.hxx>
+
+#include <com/sun/star/rendering/XCustomSprite.hpp>
+#include <com/sun/star/rendering/XPolyPolygon2D.hpp>
+
+#include <basegfx/point/b2dpoint.hxx>
+
+#include <base/basemutexhelper.hxx>
+
+#include "ogl_spritecanvas.hxx"
+#include "ogl_canvashelper.hxx"
+
+
+namespace oglcanvas
+{
+ typedef ::cppu::WeakComponentImplHelper< css::rendering::XCustomSprite,
+ css::rendering::XCanvas > CanvasCustomSpriteBase_Base;
+ typedef ::canvas::CanvasBase<
+ ::canvas::BaseMutexHelper< CanvasCustomSpriteBase_Base >,
+ CanvasHelper,
+ ::osl::MutexGuard,
+ ::cppu::OWeakObject > CanvasCustomSpriteBaseT;
+
+ /* Definition of CanvasCustomSprite class */
+
+ class CanvasCustomSprite : public CanvasCustomSpriteBaseT
+ {
+ public:
+ /** Create a custom sprite
+
+ @param rSpriteSize
+ Size of the sprite in pixel
+
+ @param rRefDevice
+ Associated output device
+
+ @param rSpriteCanvas
+ Target canvas
+
+ @param rDevice
+ Target DX device
+ */
+ CanvasCustomSprite( const css::geometry::RealSize2D& rSpriteSize,
+ const SpriteCanvasRef& rRefDevice,
+ SpriteDeviceHelper& rDeviceHelper );
+
+ virtual void disposeThis() override;
+
+ // XSprite
+ virtual void SAL_CALL setAlpha( double alpha ) override;
+ virtual void SAL_CALL move( const css::geometry::RealPoint2D& aNewPos, const css::rendering::ViewState& viewState, const css::rendering::RenderState& renderState ) override;
+ virtual void SAL_CALL transform( const css::geometry::AffineMatrix2D& aTransformation ) override;
+ virtual void SAL_CALL clip( const css::uno::Reference< css::rendering::XPolyPolygon2D >& aClip ) override;
+ virtual void SAL_CALL setPriority( double nPriority ) override;
+ virtual void SAL_CALL show() override;
+ virtual void SAL_CALL hide() override;
+
+ // XCustomSprite
+ virtual css::uno::Reference< css::rendering::XCanvas > SAL_CALL getContentCanvas() override;
+
+ double getPriority() const { return mfPriority; }
+
+ /// Render sprite content at sprite position
+ bool renderSprite() const;
+
+ private:
+ /** MUST hold here, too, since CanvasHelper only contains a
+ raw pointer (without refcounting)
+ */
+ SpriteCanvasRef mpSpriteCanvas;
+ const css::geometry::RealSize2D maSize;
+
+ css::uno::Reference< css::rendering::XPolyPolygon2D > mxClip;
+ css::geometry::AffineMatrix2D maTransformation;
+ ::basegfx::B2DPoint maPosition;
+ double mfAlpha;
+ double mfPriority;
+ };
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/canvas/source/opengl/ogl_canvasfont.cxx b/canvas/source/opengl/ogl_canvasfont.cxx
new file mode 100644
index 000000000..764b848cf
--- /dev/null
+++ b/canvas/source/opengl/ogl_canvasfont.cxx
@@ -0,0 +1,69 @@
+/* -*- 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 <com/sun/star/rendering/FontMetrics.hpp>
+#include <canvas/canvastools.hxx>
+
+#include "ogl_canvasfont.hxx"
+#include "ogl_textlayout.hxx"
+
+using namespace ::com::sun::star;
+
+namespace oglcanvas
+{
+ CanvasFont::CanvasFont( const rendering::FontRequest& rFontRequest,
+ const uno::Sequence< beans::PropertyValue >& extraFontProperties,
+ const geometry::Matrix2D& fontMatrix ) :
+ CanvasFontBaseT( m_aMutex ),
+ maFontRequest( rFontRequest ),
+ mnEmphasisMark(0),
+ maFontMatrix( fontMatrix )
+ {
+ ::canvas::tools::extractExtraFontProperties(extraFontProperties, mnEmphasisMark);
+ }
+
+ uno::Reference< rendering::XTextLayout > SAL_CALL CanvasFont::createTextLayout( const rendering::StringContext& aText,
+ sal_Int8 nDirection,
+ sal_Int64 nRandomSeed )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ return new TextLayout( aText, nDirection, nRandomSeed, ImplRef( this ) );
+ }
+
+ uno::Sequence< double > SAL_CALL CanvasFont::getAvailableSizes( )
+ {
+ // TODO
+ return uno::Sequence< double >();
+ }
+
+ uno::Sequence< beans::PropertyValue > SAL_CALL CanvasFont::getExtraFontProperties( )
+ {
+ // TODO
+ return uno::Sequence< beans::PropertyValue >();
+ }
+
+ rendering::FontRequest SAL_CALL CanvasFont::getFontRequest( )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ return maFontRequest;
+ }
+
+ rendering::FontMetrics SAL_CALL CanvasFont::getFontMetrics( )
+ {
+ // TODO
+ return rendering::FontMetrics();
+ }
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/canvas/source/opengl/ogl_canvasfont.hxx b/canvas/source/opengl/ogl_canvasfont.hxx
new file mode 100644
index 000000000..c7d44b863
--- /dev/null
+++ b/canvas/source/opengl/ogl_canvasfont.hxx
@@ -0,0 +1,64 @@
+/* -*- 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_CANVAS_SOURCE_OPENGL_OGL_CANVASFONT_HXX
+#define INCLUDED_CANVAS_SOURCE_OPENGL_OGL_CANVASFONT_HXX
+
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+
+#include <com/sun/star/rendering/XCanvasFont.hpp>
+#include <com/sun/star/geometry/Matrix2D.hpp>
+
+#include <rtl/ref.hxx>
+
+
+/* Definition of CanvasFont class */
+
+namespace oglcanvas
+{
+ class SpriteCanvas;
+
+ typedef ::cppu::WeakComponentImplHelper< css::rendering::XCanvasFont > CanvasFontBaseT;
+
+ class CanvasFont : public ::cppu::BaseMutex,
+ public CanvasFontBaseT
+ {
+ public:
+ typedef rtl::Reference<CanvasFont> ImplRef;
+
+ /// make noncopyable
+ CanvasFont(const CanvasFont&) = delete;
+ const CanvasFont& operator=(const CanvasFont&) = delete;
+
+ CanvasFont( const css::rendering::FontRequest& fontRequest,
+ const css::uno::Sequence< css::beans::PropertyValue >& extraFontProperties,
+ const css::geometry::Matrix2D& fontMatrix );
+
+ // XCanvasFont
+ virtual css::uno::Reference< css::rendering::XTextLayout > SAL_CALL createTextLayout( const css::rendering::StringContext& aText, sal_Int8 nDirection, sal_Int64 nRandomSeed ) override;
+ virtual css::rendering::FontRequest SAL_CALL getFontRequest( ) override;
+ virtual css::rendering::FontMetrics SAL_CALL getFontMetrics( ) override;
+ virtual css::uno::Sequence< double > SAL_CALL getAvailableSizes( ) override;
+ virtual css::uno::Sequence< css::beans::PropertyValue > SAL_CALL getExtraFontProperties( ) override;
+
+ const css::geometry::Matrix2D& getFontMatrix() const { return maFontMatrix; }
+
+ sal_uInt32 getEmphasisMark() const { return mnEmphasisMark; }
+
+ private:
+ css::rendering::FontRequest maFontRequest;
+ sal_uInt32 mnEmphasisMark;
+ css::geometry::Matrix2D maFontMatrix;
+ };
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/canvas/source/opengl/ogl_canvashelper.cxx b/canvas/source/opengl/ogl_canvashelper.cxx
new file mode 100644
index 000000000..6dcf933f0
--- /dev/null
+++ b/canvas/source/opengl/ogl_canvashelper.cxx
@@ -0,0 +1,947 @@
+/* -*- 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 <memory>
+#include <functional>
+#include <epoxy/gl.h>
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/utils/canvastools.hxx>
+#include <com/sun/star/rendering/CompositeOperation.hpp>
+#include <rtl/crc.h>
+#include <rtl/math.hxx>
+#include <tools/diagnose_ex.h>
+#include <vcl/font.hxx>
+#include <vcl/metric.hxx>
+#include <vcl/virdev.hxx>
+
+#include "ogl_canvasbitmap.hxx"
+#include "ogl_canvasfont.hxx"
+#include "ogl_canvastools.hxx"
+#include "ogl_texturecache.hxx"
+#include "ogl_tools.hxx"
+
+#include "ogl_canvashelper.hxx"
+
+using namespace ::com::sun::star;
+using namespace std::placeholders;
+
+namespace oglcanvas
+{
+ /* Concepts:
+ =========
+
+ This OpenGL canvas implementation tries to keep all render
+ output as high-level as possible, i.e. geometry data and
+ externally-provided bitmaps. Therefore, calls at the
+ XCanvas-interfaces are not immediately transformed into colored
+ pixel inside some GL buffer, but are retained simply with their
+ call parameters. Only after XSpriteCanvas::updateScreen() has
+ been called, this all gets transferred to the OpenGL subsystem
+ and converted to a visible scene. The big advantage is, this
+ makes sprite modifications practically zero-overhead, and saves
+ a lot on texture memory (compared to the directx canvas, which
+ immediately dumps every render call into a texture).
+
+ The drawback, of course, is that complex images churn a lot of
+ GPU cycles on every re-rendering.
+
+ For the while, I'll be using immediate mode, i.e. transfer data
+ over and over again to the OpenGL subsystem. Alternatively,
+ there are display lists, which at least keep the data on the
+ server, or even better, vertex buffers, which copy geometry
+ data over en bloc.
+
+ Next todo: put polygon geometry into vertex buffer (LRU cache
+ necessary?) - or, rather, buffer objects! prune entries older
+ than one updateScreen() call)
+
+ Text: http://www.opengl.org/resources/features/fontsurvey/
+ */
+
+ struct CanvasHelper::Action
+ {
+ ::basegfx::B2DHomMatrix maTransform;
+ GLenum meSrcBlendMode;
+ GLenum meDstBlendMode;
+ rendering::ARGBColor maARGBColor;
+ ::basegfx::B2DPolyPolygonVector maPolyPolys;
+
+ std::function< bool (
+ const CanvasHelper&,
+ const ::basegfx::B2DHomMatrix&,
+ GLenum,
+ GLenum,
+ const rendering::ARGBColor&,
+ const ::basegfx::B2DPolyPolygonVector&)> maFunction;
+ };
+
+ namespace
+ {
+ bool lcl_drawLine( const CanvasHelper& /*rHelper*/,
+ const ::basegfx::B2DHomMatrix& rTransform,
+ GLenum eSrcBlend,
+ GLenum eDstBlend,
+ const rendering::ARGBColor& rColor,
+ const geometry::RealPoint2D& rStartPoint,
+ const geometry::RealPoint2D& rEndPoint )
+ {
+ TransformationPreserver aPreserver;
+ setupState(rTransform, eSrcBlend, eDstBlend, rColor);
+
+ glBegin(GL_LINES);
+ glVertex2d(rStartPoint.X, rStartPoint.Y);
+ glVertex2d(rEndPoint.X, rEndPoint.Y);
+ glEnd();
+
+ return true;
+ }
+
+ bool lcl_drawPolyPolygon( const CanvasHelper& /*rHelper*/,
+ const ::basegfx::B2DHomMatrix& rTransform,
+ GLenum eSrcBlend,
+ GLenum eDstBlend,
+ const rendering::ARGBColor& rColor,
+ const ::basegfx::B2DPolyPolygonVector& rPolyPolygons )
+ {
+ TransformationPreserver aPreserver;
+ setupState(rTransform, eSrcBlend, eDstBlend, rColor);
+
+ for( const auto& rPoly : rPolyPolygons )
+ renderPolyPolygon( rPoly );
+
+ return true;
+ }
+
+ bool lcl_fillPolyPolygon( const CanvasHelper& /*rHelper*/,
+ const ::basegfx::B2DHomMatrix& rTransform,
+ GLenum eSrcBlend,
+ GLenum eDstBlend,
+ const rendering::ARGBColor& rColor,
+ const ::basegfx::B2DPolyPolygonVector& rPolyPolygons )
+ {
+ TransformationPreserver aPreserver;
+ setupState(rTransform, eSrcBlend, eDstBlend, rColor);
+
+ for( const auto& rPoly : rPolyPolygons )
+ {
+ glBegin( GL_TRIANGLES );
+ renderComplexPolyPolygon( rPoly );
+ glEnd();
+ }
+
+ return true;
+ }
+
+ bool lcl_fillGradientPolyPolygon( const CanvasHelper& rHelper,
+ const ::basegfx::B2DHomMatrix& rTransform,
+ GLenum eSrcBlend,
+ GLenum eDstBlend,
+ const ::canvas::ParametricPolyPolygon::Values& rValues,
+ const rendering::Texture& rTexture,
+ const ::basegfx::B2DPolyPolygonVector& rPolyPolygons )
+ {
+ TransformationPreserver aPreserver;
+ setupState(rTransform, eSrcBlend, eDstBlend, rendering::ARGBColor());
+
+ // convert to weird canvas textur coordinate system (not
+ // [0,1]^2, but path coordinate system)
+ ::basegfx::B2DHomMatrix aTextureTransform;
+ ::basegfx::unotools::homMatrixFromAffineMatrix( aTextureTransform,
+ rTexture.AffineTransform );
+ ::basegfx::B2DRange aBounds;
+ for( const auto& rPoly : rPolyPolygons )
+ aBounds.expand( ::basegfx::utils::getRange( rPoly ) );
+ aTextureTransform.translate(-aBounds.getMinX(), -aBounds.getMinY());
+ aTextureTransform.scale(1/aBounds.getWidth(), 1/aBounds.getHeight());
+
+ const sal_Int32 nNumCols=rValues.maColors.getLength();
+ uno::Sequence< rendering::ARGBColor > aColors(nNumCols);
+ rendering::ARGBColor* const pColors=aColors.getArray();
+ rendering::ARGBColor* pCurrCol=pColors;
+ for( sal_Int32 i=0; i<nNumCols; ++i )
+ *pCurrCol++ = rHelper.getDevice()->getDeviceColorSpace()->convertToARGB(rValues.maColors[i])[0];
+
+ OSL_ASSERT(nNumCols == rValues.maStops.getLength());
+
+ switch( rValues.meType )
+ {
+ case ::canvas::ParametricPolyPolygon::GradientType::Linear:
+ rHelper.getDeviceHelper()->useLinearGradientShader(pColors,
+ rValues.maStops,
+ aTextureTransform);
+ break;
+
+ case ::canvas::ParametricPolyPolygon::GradientType::Elliptical:
+ rHelper.getDeviceHelper()->useRadialGradientShader(pColors,
+ rValues.maStops,
+ aTextureTransform);
+ break;
+
+ case ::canvas::ParametricPolyPolygon::GradientType::Rectangular:
+ rHelper.getDeviceHelper()->useRectangularGradientShader(pColors,
+ rValues.maStops,
+ aTextureTransform);
+ break;
+
+ default:
+ ENSURE_OR_THROW( false,
+ "CanvasHelper lcl_fillGradientPolyPolygon(): Unexpected case" );
+ }
+
+
+ for( const auto& rPoly : rPolyPolygons )
+ {
+ glBegin(GL_TRIANGLES);
+ renderComplexPolyPolygon( rPoly );
+ glEnd();
+ }
+
+ glUseProgram(0);
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+
+ return true;
+ }
+
+ bool lcl_drawOwnBitmap( const CanvasHelper& /*rHelper*/,
+ const ::basegfx::B2DHomMatrix& rTransform,
+ GLenum eSrcBlend,
+ GLenum eDstBlend,
+ const rendering::ARGBColor& rColor,
+ const CanvasBitmap& rBitmap )
+ {
+ TransformationPreserver aPreserver;
+ setupState(rTransform, eSrcBlend, eDstBlend, rColor);
+
+ return rBitmap.renderRecordedActions();
+ }
+
+ bool lcl_drawGenericBitmap( const CanvasHelper& rHelper,
+ const ::basegfx::B2DHomMatrix& rTransform,
+ GLenum eSrcBlend,
+ GLenum eDstBlend,
+ const rendering::ARGBColor& rColor,
+ const geometry::IntegerSize2D& rPixelSize,
+ const uno::Sequence<sal_Int8>& rPixelData,
+ sal_uInt32 nPixelCrc32 )
+ {
+ TransformationPreserver aPreserver;
+ setupState(rTransform, eSrcBlend, eDstBlend, rColor);
+
+ const unsigned int nTexId=rHelper.getDeviceHelper()->getTextureCache().getTexture(
+ rPixelSize, rPixelData.getConstArray(), nPixelCrc32);
+
+ glBindTexture(GL_TEXTURE_2D, nTexId);
+ glEnable(GL_TEXTURE_2D);
+ glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_MAG_FILTER,
+ GL_NEAREST);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA,
+ GL_ONE_MINUS_SRC_ALPHA);
+
+ // blend against fixed vertex color; texture alpha is multiplied in
+ glColor4f(1,1,1,1);
+
+ glBegin(GL_TRIANGLE_STRIP);
+ glTexCoord2f(0,0); glVertex2d(0,0);
+ glTexCoord2f(0,1); glVertex2d(0, rPixelSize.Height);
+ glTexCoord2f(1,0); glVertex2d(rPixelSize.Width,0);
+ glTexCoord2f(1,1); glVertex2d(rPixelSize.Width,rPixelSize.Height);
+ glEnd();
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glDisable(GL_TEXTURE_2D);
+
+ return true;
+ }
+
+ bool lcl_fillTexturedPolyPolygon( const CanvasHelper& rHelper,
+ const ::basegfx::B2DHomMatrix& rTransform,
+ GLenum eSrcBlend,
+ GLenum eDstBlend,
+ const rendering::Texture& rTexture,
+ const geometry::IntegerSize2D& rPixelSize,
+ const uno::Sequence<sal_Int8>& rPixelData,
+ sal_uInt32 nPixelCrc32,
+ const ::basegfx::B2DPolyPolygonVector& rPolyPolygons )
+ {
+ TransformationPreserver aPreserver;
+ setupState(rTransform, eSrcBlend, eDstBlend, rendering::ARGBColor());
+
+ const unsigned int nTexId=rHelper.getDeviceHelper()->getTextureCache().getTexture(
+ rPixelSize, rPixelData.getConstArray(), nPixelCrc32);
+
+ glBindTexture(GL_TEXTURE_2D, nTexId);
+ glEnable(GL_TEXTURE_2D);
+ glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_MAG_FILTER,
+ GL_NEAREST);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA,
+ GL_ONE_MINUS_SRC_ALPHA);
+
+ // convert to weird canvas textur coordinate system (not
+ // [0,1]^2, but path coordinate system)
+ ::basegfx::B2DHomMatrix aTextureTransform;
+ ::basegfx::unotools::homMatrixFromAffineMatrix( aTextureTransform,
+ rTexture.AffineTransform );
+ ::basegfx::B2DRange aBounds;
+ for( const auto& rPolyPolygon : rPolyPolygons )
+ aBounds.expand( ::basegfx::utils::getRange( rPolyPolygon ) );
+ aTextureTransform.translate(-aBounds.getMinX(), -aBounds.getMinY());
+ aTextureTransform.scale(1/aBounds.getWidth(), 1/aBounds.getHeight());
+ aTextureTransform.invert();
+
+ glMatrixMode(GL_TEXTURE);
+ double aTexTransform[] =
+ {
+ aTextureTransform.get(0,0), aTextureTransform.get(1,0), 0, 0,
+ aTextureTransform.get(0,1), aTextureTransform.get(1,1), 0, 0,
+ 0, 0, 1, 0,
+ aTextureTransform.get(0,2), aTextureTransform.get(1,2), 0, 1
+ };
+ glLoadMatrixd(aTexTransform);
+
+ // blend against fixed vertex color; texture alpha is multiplied in
+ glColor4f(1,1,1,rTexture.Alpha);
+
+ for( const auto& rPolyPolygon : rPolyPolygons )
+ {
+ glBegin(GL_TRIANGLES);
+ renderComplexPolyPolygon( rPolyPolygon );
+ glEnd();
+ }
+
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glDisable(GL_TEXTURE_2D);
+
+ return true;
+ }
+ }
+
+ CanvasHelper::CanvasHelper() :
+ mpDevice( nullptr ),
+ mpDeviceHelper( nullptr ),
+ mpRecordedActions()
+ {}
+
+ CanvasHelper::~CanvasHelper()
+ {}
+
+ CanvasHelper& CanvasHelper::operator=( const CanvasHelper& rSrc )
+ {
+ mpDevice = rSrc.mpDevice;
+ mpDeviceHelper = rSrc.mpDeviceHelper;
+ mpRecordedActions = rSrc.mpRecordedActions;
+ return *this;
+ }
+
+ void CanvasHelper::disposing()
+ {
+ RecordVectorT aThrowaway;
+ mpRecordedActions.swap( aThrowaway );
+ mpDevice = nullptr;
+ mpDeviceHelper = nullptr;
+ }
+
+ void CanvasHelper::init( rendering::XGraphicDevice& rDevice,
+ SpriteDeviceHelper& rDeviceHelper )
+ {
+ mpDevice = &rDevice;
+ mpDeviceHelper = &rDeviceHelper;
+ }
+
+ void CanvasHelper::clear()
+ {
+ mpRecordedActions->clear();
+ }
+
+ void CanvasHelper::drawLine( const rendering::XCanvas* /*pCanvas*/,
+ const geometry::RealPoint2D& aStartPoint,
+ const geometry::RealPoint2D& aEndPoint,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ if( mpDevice )
+ {
+ mpRecordedActions->push_back( Action() );
+ Action& rAct=mpRecordedActions->back();
+
+ setupGraphicsState( rAct, viewState, renderState );
+ rAct.maFunction = std::bind(&lcl_drawLine,
+ std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5,
+ aStartPoint, aEndPoint);
+ }
+ }
+
+ void CanvasHelper::drawBezier( const rendering::XCanvas* /*pCanvas*/,
+ const geometry::RealBezierSegment2D& aBezierSegment,
+ const geometry::RealPoint2D& aEndPoint,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ if( !mpDevice )
+ return;
+
+ mpRecordedActions->push_back( Action() );
+ Action& rAct=mpRecordedActions->back();
+
+ setupGraphicsState( rAct, viewState, renderState );
+
+ // TODO(F2): subdivide&render whole curve
+ rAct.maFunction = std::bind(&lcl_drawLine,
+ std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5,
+ geometry::RealPoint2D(
+ aBezierSegment.Px,
+ aBezierSegment.Py),
+ aEndPoint);
+ }
+
+ uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawPolyPolygon( const rendering::XCanvas* /*pCanvas*/,
+ const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ ENSURE_OR_THROW( xPolyPolygon.is(),
+ "CanvasHelper::drawPolyPolygon: polygon is NULL");
+
+ if( mpDevice )
+ {
+ mpRecordedActions->push_back( Action() );
+ Action& rAct=mpRecordedActions->back();
+
+ setupGraphicsState( rAct, viewState, renderState );
+ rAct.maPolyPolys.push_back(
+ ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(xPolyPolygon));
+ rAct.maPolyPolys.back().makeUnique(); // own copy, for thread safety
+
+ rAct.maFunction = &lcl_drawPolyPolygon;
+ }
+
+ // TODO(P1): Provide caching here.
+ return uno::Reference< rendering::XCachedPrimitive >(nullptr);
+ }
+
+ uno::Reference< rendering::XCachedPrimitive > CanvasHelper::strokePolyPolygon( const rendering::XCanvas* /*pCanvas*/,
+ const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState,
+ const rendering::StrokeAttributes& /*strokeAttributes*/ )
+ {
+ ENSURE_OR_THROW( xPolyPolygon.is(),
+ "CanvasHelper::strokePolyPolygon: polygon is NULL");
+
+ if( mpDevice )
+ {
+ mpRecordedActions->push_back( Action() );
+ Action& rAct=mpRecordedActions->back();
+
+ setupGraphicsState( rAct, viewState, renderState );
+ rAct.maPolyPolys.push_back(
+ ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(xPolyPolygon));
+ rAct.maPolyPolys.back().makeUnique(); // own copy, for thread safety
+
+ // TODO(F3): fallback to drawPolyPolygon currently
+ rAct.maFunction = &lcl_drawPolyPolygon;
+ }
+
+ // TODO(P1): Provide caching here.
+ return uno::Reference< rendering::XCachedPrimitive >(nullptr);
+ }
+
+ uno::Reference< rendering::XCachedPrimitive > CanvasHelper::strokeTexturedPolyPolygon( const rendering::XCanvas* /*pCanvas*/,
+ const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/,
+ const rendering::ViewState& /*viewState*/,
+ const rendering::RenderState& /*renderState*/,
+ const uno::Sequence< rendering::Texture >& /*textures*/,
+ const rendering::StrokeAttributes& /*strokeAttributes*/ )
+ {
+ // TODO
+ return uno::Reference< rendering::XCachedPrimitive >(nullptr);
+ }
+
+ uno::Reference< rendering::XCachedPrimitive > CanvasHelper::strokeTextureMappedPolyPolygon( const rendering::XCanvas* /*pCanvas*/,
+ const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/,
+ const rendering::ViewState& /*viewState*/,
+ const rendering::RenderState& /*renderState*/,
+ const uno::Sequence< rendering::Texture >& /*textures*/,
+ const uno::Reference< geometry::XMapping2D >& /*xMapping*/,
+ const rendering::StrokeAttributes& /*strokeAttributes*/ )
+ {
+ // TODO
+ return uno::Reference< rendering::XCachedPrimitive >(nullptr);
+ }
+
+ uno::Reference< rendering::XPolyPolygon2D > CanvasHelper::queryStrokeShapes( const rendering::XCanvas* /*pCanvas*/,
+ const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/,
+ const rendering::ViewState& /*viewState*/,
+ const rendering::RenderState& /*renderState*/,
+ const rendering::StrokeAttributes& /*strokeAttributes*/ )
+ {
+ // TODO
+ return uno::Reference< rendering::XPolyPolygon2D >(nullptr);
+ }
+
+ uno::Reference< rendering::XCachedPrimitive > CanvasHelper::fillPolyPolygon( const rendering::XCanvas* /*pCanvas*/,
+ const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ ENSURE_OR_THROW( xPolyPolygon.is(),
+ "CanvasHelper::fillPolyPolygon: polygon is NULL");
+
+ if( mpDevice )
+ {
+ mpRecordedActions->push_back( Action() );
+ Action& rAct=mpRecordedActions->back();
+
+ setupGraphicsState( rAct, viewState, renderState );
+ rAct.maPolyPolys.push_back(
+ ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(xPolyPolygon));
+ rAct.maPolyPolys.back().makeUnique(); // own copy, for thread safety
+
+ rAct.maFunction = &lcl_fillPolyPolygon;
+ }
+
+ // TODO(P1): Provide caching here.
+ return uno::Reference< rendering::XCachedPrimitive >(nullptr);
+ }
+
+ uno::Reference< rendering::XCachedPrimitive > CanvasHelper::fillTexturedPolyPolygon( const rendering::XCanvas* /*pCanvas*/,
+ const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState,
+ const uno::Sequence< rendering::Texture >& textures )
+ {
+ ENSURE_OR_THROW( xPolyPolygon.is(),
+ "CanvasHelper::fillPolyPolygon: polygon is NULL");
+
+ if( mpDevice )
+ {
+ mpRecordedActions->push_back( Action() );
+ Action& rAct=mpRecordedActions->back();
+
+ setupGraphicsState( rAct, viewState, renderState );
+ rAct.maPolyPolys.push_back(
+ ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(xPolyPolygon));
+ rAct.maPolyPolys.back().makeUnique(); // own copy, for thread safety
+
+ // TODO(F1): Multi-texturing
+ if( textures[0].Gradient.is() )
+ {
+ // try to cast XParametricPolyPolygon2D reference to
+ // our implementation class.
+ ::canvas::ParametricPolyPolygon* pGradient =
+ dynamic_cast< ::canvas::ParametricPolyPolygon* >( textures[0].Gradient.get() );
+
+ if( pGradient )
+ {
+ // copy state from Gradient polypoly locally
+ // (given object might change!)
+ const ::canvas::ParametricPolyPolygon::Values& rValues(
+ pGradient->getValues() );
+
+ rAct.maFunction = std::bind(&lcl_fillGradientPolyPolygon,
+ std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4,
+ rValues,
+ textures[0],
+ std::placeholders::_6);
+ }
+ else
+ {
+ // TODO(F1): The generic case is missing here
+ ENSURE_OR_THROW( false,
+ "CanvasHelper::fillTexturedPolyPolygon(): unknown parametric polygon encountered" );
+ }
+ }
+ else if( textures[0].Bitmap.is() )
+ {
+ // own bitmap?
+ CanvasBitmap* pOwnBitmap=dynamic_cast<CanvasBitmap*>(textures[0].Bitmap.get());
+ if( pOwnBitmap )
+ {
+ // TODO(F2): own texture bitmap
+ }
+ else
+ {
+ // TODO(P3): Highly inefficient - simply copies pixel data
+
+ uno::Reference< rendering::XIntegerReadOnlyBitmap > xIntegerBitmap(
+ textures[0].Bitmap,
+ uno::UNO_QUERY);
+ if( xIntegerBitmap.is() )
+ {
+ const geometry::IntegerSize2D aSize=xIntegerBitmap->getSize();
+ rendering::IntegerBitmapLayout aLayout;
+ uno::Sequence<sal_Int8> aPixelData=
+ xIntegerBitmap->getData(
+ aLayout,
+ geometry::IntegerRectangle2D(0,0,aSize.Width,aSize.Height));
+
+ // force-convert color to ARGB8888 int color space
+ uno::Sequence<sal_Int8> aARGBBytes(
+ aLayout.ColorSpace->convertToIntegerColorSpace(
+ aPixelData,
+ canvas::tools::getStdColorSpace()));
+
+ rAct.maFunction = std::bind(&lcl_fillTexturedPolyPolygon,
+ std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4,
+ textures[0],
+ aSize,
+ aARGBBytes,
+ rtl_crc32(0,
+ aARGBBytes.getConstArray(),
+ aARGBBytes.getLength()),
+ std::placeholders::_6);
+ }
+ // TODO(F1): handle non-integer case
+ }
+ }
+ }
+
+ // TODO(P1): Provide caching here.
+ return uno::Reference< rendering::XCachedPrimitive >(nullptr);
+ }
+
+ uno::Reference< rendering::XCachedPrimitive > CanvasHelper::fillTextureMappedPolyPolygon( const rendering::XCanvas* /*pCanvas*/,
+ const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/,
+ const rendering::ViewState& /*viewState*/,
+ const rendering::RenderState& /*renderState*/,
+ const uno::Sequence< rendering::Texture >& /*textures*/,
+ const uno::Reference< geometry::XMapping2D >& /*xMapping*/ )
+ {
+ // TODO
+ return uno::Reference< rendering::XCachedPrimitive >(nullptr);
+ }
+
+ uno::Reference< rendering::XCanvasFont > CanvasHelper::createFont( const rendering::XCanvas* /*pCanvas*/,
+ const rendering::FontRequest& fontRequest,
+ const uno::Sequence< beans::PropertyValue >& extraFontProperties,
+ const geometry::Matrix2D& fontMatrix )
+ {
+ if( mpDevice )
+ return uno::Reference< rendering::XCanvasFont >(
+ new CanvasFont(fontRequest, extraFontProperties, fontMatrix ) );
+
+ return uno::Reference< rendering::XCanvasFont >();
+ }
+
+ uno::Sequence< rendering::FontInfo > CanvasHelper::queryAvailableFonts( const rendering::XCanvas* /*pCanvas*/,
+ const rendering::FontInfo& /*aFilter*/,
+ const uno::Sequence< beans::PropertyValue >& /*aFontProperties*/ )
+ {
+ // TODO
+ return uno::Sequence< rendering::FontInfo >();
+ }
+
+ uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawText( const rendering::XCanvas* /*pCanvas*/,
+ const rendering::StringContext& /*text*/,
+ const uno::Reference< rendering::XCanvasFont >& /*xFont*/,
+ const rendering::ViewState& /*viewState*/,
+ const rendering::RenderState& /*renderState*/,
+ sal_Int8 /*textDirection*/ )
+ {
+ // TODO - but not used from slideshow
+ return uno::Reference< rendering::XCachedPrimitive >(nullptr);
+ }
+
+ uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawTextLayout( const rendering::XCanvas* /*pCanvas*/,
+ const uno::Reference< rendering::XTextLayout >& xLayoutetText,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ ENSURE_OR_THROW( xLayoutetText.is(),
+ "CanvasHelper::drawTextLayout: text is NULL");
+
+ if( mpDevice )
+ {
+ ScopedVclPtrInstance< VirtualDevice > pVDev;
+ pVDev->EnableOutput(false);
+
+ CanvasFont* pFont=dynamic_cast<CanvasFont*>(xLayoutetText->getFont().get());
+ const rendering::StringContext& rTxt=xLayoutetText->getText();
+ if( pFont && rTxt.Length )
+ {
+ // create the font
+ const rendering::FontRequest& rFontRequest = pFont->getFontRequest();
+ const geometry::Matrix2D& rFontMatrix = pFont->getFontMatrix();
+ vcl::Font aFont(
+ rFontRequest.FontDescription.FamilyName,
+ rFontRequest.FontDescription.StyleName,
+ Size( 0, ::basegfx::fround(rFontRequest.CellSize)));
+
+ aFont.SetAlignment( ALIGN_BASELINE );
+ aFont.SetCharSet( (rFontRequest.FontDescription.IsSymbolFont==util::TriState_YES) ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE );
+ aFont.SetVertical( rFontRequest.FontDescription.IsVertical==util::TriState_YES );
+ aFont.SetWeight( static_cast<FontWeight>(rFontRequest.FontDescription.FontDescription.Weight) );
+ aFont.SetItalic( (rFontRequest.FontDescription.FontDescription.Letterform<=8) ? ITALIC_NONE : ITALIC_NORMAL );
+
+ if (pFont->getEmphasisMark())
+ aFont.SetEmphasisMark(FontEmphasisMark(pFont->getEmphasisMark()));
+
+ // adjust to stretched font
+ if(!::rtl::math::approxEqual(rFontMatrix.m00, rFontMatrix.m11))
+ {
+ const Size aSize = pVDev->GetFontMetric( aFont ).GetFontSize();
+ const double fDividend( rFontMatrix.m10 + rFontMatrix.m11 );
+ double fStretch = rFontMatrix.m00 + rFontMatrix.m01;
+
+ if( !::basegfx::fTools::equalZero( fDividend) )
+ fStretch /= fDividend;
+
+ const sal_Int32 nNewWidth = ::basegfx::fround( aSize.Width() * fStretch );
+
+ aFont.SetAverageFontWidth( nNewWidth );
+ }
+
+ // set font
+ pVDev->SetFont(aFont);
+
+ mpRecordedActions->push_back( Action() );
+ Action& rAct=mpRecordedActions->back();
+
+ setupGraphicsState( rAct, viewState, renderState );
+
+ // handle custom spacing, if there
+ uno::Sequence<double> aLogicalAdvancements=xLayoutetText->queryLogicalAdvancements();
+ if( aLogicalAdvancements.hasElements() )
+ {
+ // create the DXArray
+ const sal_Int32 nLen( aLogicalAdvancements.getLength() );
+ std::unique_ptr<long[]> pDXArray( new long[nLen] );
+ for( sal_Int32 i=0; i<nLen; ++i )
+ pDXArray[i] = basegfx::fround( aLogicalAdvancements[i] );
+
+ // get the glyphs
+ pVDev->GetTextOutlines(rAct.maPolyPolys,
+ rTxt.Text,
+ 0,
+ rTxt.StartPosition,
+ rTxt.Length,
+ 0,
+ pDXArray.get() );
+ }
+ else
+ {
+ // get the glyphs
+ pVDev->GetTextOutlines(rAct.maPolyPolys,
+ rTxt.Text,
+ 0,
+ rTxt.StartPosition,
+ rTxt.Length );
+ }
+
+ // own copy, for thread safety
+ for( auto& rPoly : rAct.maPolyPolys )
+ rPoly.makeUnique();
+
+ rAct.maFunction = &lcl_fillPolyPolygon;
+ }
+ }
+
+ // TODO
+ return uno::Reference< rendering::XCachedPrimitive >(nullptr);
+ }
+
+ uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawBitmap( const rendering::XCanvas* /*pCanvas*/,
+ const uno::Reference< rendering::XBitmap >& xBitmap,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ ENSURE_OR_THROW( xBitmap.is(),
+ "CanvasHelper::drawBitmap: bitmap is NULL");
+
+ if( mpDevice )
+ {
+ // own bitmap?
+ CanvasBitmap* pOwnBitmap=dynamic_cast<CanvasBitmap*>(xBitmap.get());
+ if( pOwnBitmap )
+ {
+ // insert as transformed copy of bitmap action vector -
+ // during rendering, this gets rendered into a temporary
+ // buffer, and then composited to the front
+ mpRecordedActions->push_back( Action() );
+ Action& rAct=mpRecordedActions->back();
+
+ setupGraphicsState( rAct, viewState, renderState );
+ rAct.maFunction = std::bind(&lcl_drawOwnBitmap,
+ std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5,
+ *pOwnBitmap);
+ }
+ else
+ {
+ // TODO(P3): Highly inefficient - simply copies pixel data
+
+ uno::Reference< rendering::XIntegerReadOnlyBitmap > xIntegerBitmap(
+ xBitmap, uno::UNO_QUERY);
+ if( xIntegerBitmap.is() )
+ {
+ const geometry::IntegerSize2D aSize=xBitmap->getSize();
+ rendering::IntegerBitmapLayout aLayout;
+ uno::Sequence<sal_Int8> aPixelData=
+ xIntegerBitmap->getData(
+ aLayout,
+ geometry::IntegerRectangle2D(0,0,aSize.Width,aSize.Height));
+
+ // force-convert color to ARGB8888 int color space
+ uno::Sequence<sal_Int8> aARGBBytes(
+ aLayout.ColorSpace->convertToIntegerColorSpace(
+ aPixelData,
+ canvas::tools::getStdColorSpace()));
+
+ mpRecordedActions->push_back( Action() );
+ Action& rAct=mpRecordedActions->back();
+
+ setupGraphicsState( rAct, viewState, renderState );
+ rAct.maFunction = std::bind(&lcl_drawGenericBitmap,
+ std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5,
+ aSize, aARGBBytes,
+ rtl_crc32(0,
+ aARGBBytes.getConstArray(),
+ aARGBBytes.getLength()));
+ }
+ // TODO(F1): handle non-integer case
+ }
+ }
+
+ // TODO(P1): Provide caching here.
+ return uno::Reference< rendering::XCachedPrimitive >(nullptr);
+ }
+
+ uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawBitmapModulated( const rendering::XCanvas* pCanvas,
+ const uno::Reference< rendering::XBitmap >& xBitmap,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ // TODO(F3): remove this wart altogether
+ return drawBitmap(pCanvas, xBitmap, viewState, renderState);
+ }
+
+
+ void CanvasHelper::setupGraphicsState( Action& o_action,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ ENSURE_OR_THROW( mpDevice,
+ "CanvasHelper::setupGraphicsState: reference device invalid" );
+
+ // TODO(F3): clipping
+ // TODO(P2): think about caching transformations between canvas calls
+
+ // setup overall transform only now. View clip above was
+ // relative to view transform
+ ::canvas::tools::mergeViewAndRenderTransform(o_action.maTransform,
+ viewState,
+ renderState);
+ // setup compositing - mapping courtesy David Reveman
+ // (glitz_operator.c)
+ switch( renderState.CompositeOperation )
+ {
+ case rendering::CompositeOperation::OVER:
+ o_action.meSrcBlendMode=GL_ONE;
+ o_action.meDstBlendMode=GL_ONE_MINUS_SRC_ALPHA;
+ break;
+ case rendering::CompositeOperation::CLEAR:
+ o_action.meSrcBlendMode=GL_ZERO;
+ o_action.meDstBlendMode=GL_ZERO;
+ break;
+ case rendering::CompositeOperation::SOURCE:
+ o_action.meSrcBlendMode=GL_ONE;
+ o_action.meDstBlendMode=GL_ZERO;
+ break;
+ case rendering::CompositeOperation::UNDER:
+ case rendering::CompositeOperation::DESTINATION:
+ o_action.meSrcBlendMode=GL_ZERO;
+ o_action.meDstBlendMode=GL_ONE;
+ break;
+ case rendering::CompositeOperation::INSIDE:
+ o_action.meSrcBlendMode=GL_DST_ALPHA;
+ o_action.meDstBlendMode=GL_ZERO;
+ break;
+ case rendering::CompositeOperation::INSIDE_REVERSE:
+ o_action.meSrcBlendMode=GL_ONE_MINUS_DST_ALPHA;
+ o_action.meDstBlendMode=GL_ZERO;
+ break;
+ case rendering::CompositeOperation::OUTSIDE:
+ o_action.meSrcBlendMode=GL_ONE_MINUS_DST_ALPHA;
+ o_action.meDstBlendMode=GL_ONE;
+ break;
+ case rendering::CompositeOperation::OUTSIDE_REVERSE:
+ o_action.meSrcBlendMode=GL_ZERO;
+ o_action.meDstBlendMode=GL_ONE_MINUS_SRC_ALPHA;
+ break;
+ case rendering::CompositeOperation::ATOP:
+ o_action.meSrcBlendMode=GL_DST_ALPHA;
+ o_action.meDstBlendMode=GL_ONE_MINUS_SRC_ALPHA;
+ break;
+ case rendering::CompositeOperation::ATOP_REVERSE:
+ o_action.meSrcBlendMode=GL_ONE_MINUS_DST_ALPHA;
+ o_action.meDstBlendMode=GL_SRC_ALPHA;
+ break;
+ case rendering::CompositeOperation::XOR:
+ o_action.meSrcBlendMode=GL_ONE_MINUS_DST_ALPHA;
+ o_action.meDstBlendMode=GL_ONE_MINUS_SRC_ALPHA;
+ break;
+ case rendering::CompositeOperation::ADD:
+ o_action.meSrcBlendMode=GL_ONE;
+ o_action.meDstBlendMode=GL_ONE;
+ break;
+ case rendering::CompositeOperation::SATURATE:
+ o_action.meSrcBlendMode=GL_SRC_ALPHA_SATURATE;
+ o_action.meDstBlendMode=GL_SRC_ALPHA_SATURATE;
+ break;
+
+ default:
+ ENSURE_OR_THROW( false, "CanvasHelper::setupGraphicsState: unexpected mode" );
+ break;
+ }
+
+ if (renderState.DeviceColor.hasElements())
+ o_action.maARGBColor =
+ mpDevice->getDeviceColorSpace()->convertToARGB(renderState.DeviceColor)[0];
+ }
+
+ bool CanvasHelper::renderRecordedActions() const
+ {
+ for( const auto& rRecordedAction : *mpRecordedActions )
+ {
+ if( !rRecordedAction.maFunction( *this,
+ rRecordedAction.maTransform,
+ rRecordedAction.meSrcBlendMode,
+ rRecordedAction.meDstBlendMode,
+ rRecordedAction.maARGBColor,
+ rRecordedAction.maPolyPolys ) )
+ return false;
+ }
+
+ return true;
+ }
+
+ size_t CanvasHelper::getRecordedActionCount() const
+ {
+ return mpRecordedActions->size();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/canvas/source/opengl/ogl_canvashelper.hxx b/canvas/source/opengl/ogl_canvashelper.hxx
new file mode 100644
index 000000000..26ec3f71e
--- /dev/null
+++ b/canvas/source/opengl/ogl_canvashelper.hxx
@@ -0,0 +1,222 @@
+/* -*- 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_CANVAS_SOURCE_OPENGL_OGL_CANVASHELPER_HXX
+#define INCLUDED_CANVAS_SOURCE_OPENGL_OGL_CANVASHELPER_HXX
+
+#include <com/sun/star/rendering/XCanvas.hpp>
+
+#include <o3tl/cow_wrapper.hxx>
+#include <vector>
+
+namespace oglcanvas
+{
+ class SpriteDeviceHelper;
+
+ /** Helper class for basic canvas functionality. */
+ class CanvasHelper
+ {
+ public:
+ CanvasHelper();
+
+ // outline because of incomplete type Action
+ ~CanvasHelper();
+ CanvasHelper& operator=( const CanvasHelper& );
+
+ /// Release all references
+ void disposing();
+
+ /** Initialize canvas helper
+
+ This method late-initializes the canvas helper, providing
+ it with the necessary device and output objects. Note that
+ the CanvasHelper does <em>not</em> take ownership of the
+ passed rDevice reference, nor does it perform any
+ reference counting. Thus, to prevent the reference counted
+ SpriteCanvas object from deletion, the user of this class
+ is responsible for holding ref-counted references itself!
+
+ @param rDevice
+ Reference device this canvas is associated with
+
+ */
+ void init( css::rendering::XGraphicDevice& rDevice,
+ SpriteDeviceHelper& rDeviceHelper );
+
+ // CanvasHelper functionality
+ // ==========================
+
+ // XCanvas (only providing, not implementing the
+ // interface. Also note subtle method parameter differences)
+ void clear();
+ void drawLine( const css::rendering::XCanvas* pCanvas,
+ const css::geometry::RealPoint2D& aStartPoint,
+ const css::geometry::RealPoint2D& aEndPoint,
+ const css::rendering::ViewState& viewState,
+ const css::rendering::RenderState& renderState );
+ void drawBezier( const css::rendering::XCanvas* pCanvas,
+ const css::geometry::RealBezierSegment2D& aBezierSegment,
+ const css::geometry::RealPoint2D& aEndPoint,
+ const css::rendering::ViewState& viewState,
+ const css::rendering::RenderState& renderState );
+ css::uno::Reference< css::rendering::XCachedPrimitive >
+ drawPolyPolygon( const css::rendering::XCanvas* pCanvas,
+ const css::uno::Reference<
+ css::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const css::rendering::ViewState& viewState,
+ const css::rendering::RenderState& renderState );
+ css::uno::Reference< css::rendering::XCachedPrimitive >
+ strokePolyPolygon( const css::rendering::XCanvas* pCanvas,
+ const css::uno::Reference<
+ css::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const css::rendering::ViewState& viewState,
+ const css::rendering::RenderState& renderState,
+ const css::rendering::StrokeAttributes& strokeAttributes );
+ css::uno::Reference< css::rendering::XCachedPrimitive >
+ strokeTexturedPolyPolygon( const css::rendering::XCanvas* pCanvas,
+ const css::uno::Reference<
+ css::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const css::rendering::ViewState& viewState,
+ const css::rendering::RenderState& renderState,
+ const css::uno::Sequence<
+ css::rendering::Texture >& textures,
+ const css::rendering::StrokeAttributes& strokeAttributes );
+ css::uno::Reference< css::rendering::XCachedPrimitive >
+ strokeTextureMappedPolyPolygon( const css::rendering::XCanvas* pCanvas,
+ const css::uno::Reference<
+ css::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const css::rendering::ViewState& viewState,
+ const css::rendering::RenderState& renderState,
+ const css::uno::Sequence<
+ css::rendering::Texture >& textures,
+ const css::uno::Reference<
+ css::geometry::XMapping2D >& xMapping,
+ const css::rendering::StrokeAttributes& strokeAttributes );
+ css::uno::Reference< css::rendering::XPolyPolygon2D >
+ queryStrokeShapes( const css::rendering::XCanvas* pCanvas,
+ const css::uno::Reference<
+ css::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const css::rendering::ViewState& viewState,
+ const css::rendering::RenderState& renderState,
+ const css::rendering::StrokeAttributes& strokeAttributes );
+ css::uno::Reference< css::rendering::XCachedPrimitive >
+ fillPolyPolygon( const css::rendering::XCanvas* pCanvas,
+ const css::uno::Reference<
+ css::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const css::rendering::ViewState& viewState,
+ const css::rendering::RenderState& renderState );
+ css::uno::Reference< css::rendering::XCachedPrimitive >
+ fillTexturedPolyPolygon( const css::rendering::XCanvas* pCanvas,
+ const css::uno::Reference<
+ css::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const css::rendering::ViewState& viewState,
+ const css::rendering::RenderState& renderState,
+ const css::uno::Sequence<
+ css::rendering::Texture >& textures );
+ css::uno::Reference< css::rendering::XCachedPrimitive >
+ fillTextureMappedPolyPolygon( const css::rendering::XCanvas* pCanvas,
+ const css::uno::Reference<
+ css::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const css::rendering::ViewState& viewState,
+ const css::rendering::RenderState& renderState,
+ const css::uno::Sequence<
+ css::rendering::Texture >& textures,
+ const css::uno::Reference<
+ css::geometry::XMapping2D >& xMapping );
+
+ css::uno::Reference< css::rendering::XCanvasFont >
+ createFont( const css::rendering::XCanvas* pCanvas,
+ const css::rendering::FontRequest& fontRequest,
+ const css::uno::Sequence<
+ css::beans::PropertyValue >& extraFontProperties,
+ const css::geometry::Matrix2D& fontMatrix );
+
+ css::uno::Sequence< css::rendering::FontInfo >
+ queryAvailableFonts( const css::rendering::XCanvas* pCanvas,
+ const css::rendering::FontInfo& aFilter,
+ const css::uno::Sequence<
+ css::beans::PropertyValue >& aFontProperties );
+
+ css::uno::Reference< css::rendering::XCachedPrimitive >
+ drawText( const css::rendering::XCanvas* pCanvas,
+ const css::rendering::StringContext& text,
+ const css::uno::Reference<
+ css::rendering::XCanvasFont >& xFont,
+ const css::rendering::ViewState& viewState,
+ const css::rendering::RenderState& renderState,
+ sal_Int8 textDirection );
+
+ css::uno::Reference< css::rendering::XCachedPrimitive >
+ drawTextLayout( const css::rendering::XCanvas* pCanvas,
+ const css::uno::Reference<
+ css::rendering::XTextLayout >& layoutetText,
+ const css::rendering::ViewState& viewState,
+ const css::rendering::RenderState& renderState );
+
+ css::uno::Reference< css::rendering::XCachedPrimitive >
+ drawBitmap( const css::rendering::XCanvas* pCanvas,
+ const css::uno::Reference<
+ css::rendering::XBitmap >& xBitmap,
+ const css::rendering::ViewState& viewState,
+ const css::rendering::RenderState& renderState );
+ css::uno::Reference< css::rendering::XCachedPrimitive >
+ drawBitmapModulated( const css::rendering::XCanvas* pCanvas,
+ const css::uno::Reference<
+ css::rendering::XBitmap >& xBitmap,
+ const css::rendering::ViewState& viewState,
+ const css::rendering::RenderState& renderState );
+ css::uno::Reference< css::rendering::XGraphicDevice >
+ getDevice() { return css::uno::Reference< css::rendering::XGraphicDevice >(mpDevice); }
+
+ /** Write out recorded actions
+ */
+ bool renderRecordedActions() const;
+
+ /** Retrieve number of recorded actions
+ */
+ size_t getRecordedActionCount() const;
+
+ SpriteDeviceHelper* getDeviceHelper() const { return mpDeviceHelper; }
+ css::rendering::XGraphicDevice* getDevice() const { return mpDevice; }
+
+ struct Action;
+ typedef o3tl::cow_wrapper< std::vector<Action>,
+ o3tl::ThreadSafeRefCountingPolicy > RecordVectorT;
+
+ private:
+ CanvasHelper( const CanvasHelper& ) = delete;
+
+ void setupGraphicsState( Action& o_action,
+ const css::rendering::ViewState& viewState,
+ const css::rendering::RenderState& renderState );
+
+ /** Phyical output device
+
+ Deliberately not a refcounted reference, because of
+ potential circular references for spritecanvas.
+ */
+ css::rendering::XGraphicDevice* mpDevice;
+
+ /** Internal helper - used for a few global GL objects,
+ e.g. shader programs; and caches
+ */
+ SpriteDeviceHelper* mpDeviceHelper;
+
+ /** Ptr to array of recorded render calls
+
+ Gets shared copy-on-write, when this CanvasHelper is
+ copied (used e.g. for CanvasBitmap)
+ */
+ RecordVectorT mpRecordedActions;
+ };
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/canvas/source/opengl/ogl_canvastools.cxx b/canvas/source/opengl/ogl_canvastools.cxx
new file mode 100644
index 000000000..c5fbe0255
--- /dev/null
+++ b/canvas/source/opengl/ogl_canvastools.cxx
@@ -0,0 +1,148 @@
+/* -*- 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 <epoxy/gl.h>
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolygontriangulator.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/utils/tools.hxx>
+#include <com/sun/star/rendering/ARGBColor.hpp>
+
+#include "ogl_canvastools.hxx"
+
+using namespace ::com::sun::star;
+
+namespace oglcanvas
+{
+ /// triangulates polygon before
+ void renderComplexPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPoly )
+ {
+ ::basegfx::B2DPolyPolygon aPolyPoly(rPolyPoly);
+ if( aPolyPoly.areControlPointsUsed() )
+ aPolyPoly = rPolyPoly.getDefaultAdaptiveSubdivision();
+ const ::basegfx::B2DRange& rBounds(aPolyPoly.getB2DRange());
+ const double nWidth=rBounds.getWidth();
+ const double nHeight=rBounds.getHeight();
+ const ::basegfx::triangulator::B2DTriangleVector rTriangulatedPolygon(
+ ::basegfx::triangulator::triangulate(aPolyPoly));
+
+ for( size_t i=0; i<rTriangulatedPolygon.size(); i++ )
+ {
+ const::basegfx::triangulator::B2DTriangle& rCandidate(rTriangulatedPolygon[i]);
+ glTexCoord2f(
+ rCandidate.getA().getX()/nWidth,
+ rCandidate.getA().getY()/nHeight);
+ glVertex2d(
+ rCandidate.getA().getX(),
+ rCandidate.getA().getY());
+
+ glTexCoord2f(
+ rCandidate.getB().getX()/nWidth,
+ rCandidate.getB().getY()/nHeight);
+ glVertex2d(
+ rCandidate.getB().getX(),
+ rCandidate.getB().getY());
+
+ glTexCoord2f(
+ rCandidate.getC().getX()/nWidth,
+ rCandidate.getC().getY()/nHeight);
+ glVertex2d(
+ rCandidate.getC().getX(),
+ rCandidate.getC().getY());
+ }
+ }
+
+ /** only use this for line polygons.
+
+ better not leave triangulation to OpenGL. also, ignores texturing
+ */
+ void renderPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPoly )
+ {
+ ::basegfx::B2DPolyPolygon aPolyPoly(rPolyPoly);
+ if( aPolyPoly.areControlPointsUsed() )
+ aPolyPoly = rPolyPoly.getDefaultAdaptiveSubdivision();
+
+ for( sal_uInt32 i=0; i<aPolyPoly.count(); i++ )
+ {
+ glBegin(GL_LINE_STRIP);
+
+ const ::basegfx::B2DPolygon& rPolygon( aPolyPoly.getB2DPolygon(i) );
+
+ const sal_uInt32 nPts=rPolygon.count();
+ const sal_uInt32 nExtPts=nPts + int(rPolygon.isClosed());
+ for( sal_uInt32 j=0; j<nExtPts; j++ )
+ {
+ const ::basegfx::B2DPoint& rPt( rPolygon.getB2DPoint( j % nPts ) );
+ glVertex2d(rPt.getX(), rPt.getY());
+ }
+
+ glEnd();
+ }
+ }
+
+ void setupState( const ::basegfx::B2DHomMatrix& rTransform,
+ GLenum eSrcBlend,
+ GLenum eDstBlend,
+ const rendering::ARGBColor& rColor )
+ {
+ double aGLTransform[] =
+ {
+ rTransform.get(0,0), rTransform.get(1,0), 0, 0,
+ rTransform.get(0,1), rTransform.get(1,1), 0, 0,
+ 0, 0, 1, 0,
+ rTransform.get(0,2), rTransform.get(1,2), 0, 1
+ };
+ glMultMatrixd(aGLTransform);
+
+ glEnable(GL_BLEND);
+ glBlendFunc(eSrcBlend, eDstBlend);
+
+ glColor4d(rColor.Red,
+ rColor.Green,
+ rColor.Blue,
+ rColor.Alpha);
+
+ // GL 1.2:
+ // glBlendEquation( GLenum mode );
+ // glBlendColor( GLclampf red, GLclampf green,GLclampf blue, GLclampf alpha );
+ // glConvolutionFilter1D
+ // glConvolutionFilter2D
+ // glSeparableFilter2D
+ }
+
+ void renderOSD( const std::vector<double>& rNumbers, double scale )
+ {
+ double y=4.0;
+ basegfx::B2DHomMatrix aTmp;
+ basegfx::B2DHomMatrix aScaleShear;
+ aScaleShear.shearX(-0.1);
+ aScaleShear.scale(scale,scale);
+
+ for(double rNumber : rNumbers)
+ {
+ aTmp.identity();
+ aTmp.translate(0,y);
+ y += 1.2*scale;
+
+ basegfx::B2DPolyPolygon aPoly=
+ basegfx::utils::number2PolyPolygon(rNumber,10,3);
+
+ aTmp=aTmp*aScaleShear;
+ aPoly.transform(aTmp);
+
+ glColor4f(0,1,0,1);
+ renderPolyPolygon(aPoly);
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/canvas/source/opengl/ogl_canvastools.hxx b/canvas/source/opengl/ogl_canvastools.hxx
new file mode 100644
index 000000000..1ee15a9ba
--- /dev/null
+++ b/canvas/source/opengl/ogl_canvastools.hxx
@@ -0,0 +1,40 @@
+/* -*- 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_CANVAS_SOURCE_OPENGL_OGL_CANVASTOOLS_HXX
+#define INCLUDED_CANVAS_SOURCE_OPENGL_OGL_CANVASTOOLS_HXX
+
+#include <sal/config.h>
+#include <vector>
+
+#include <epoxy/gl.h>
+
+namespace com::sun::star::rendering {
+ struct ARGBColor;
+}
+namespace basegfx {
+ class B2DPolyPolygon;
+ class B2DHomMatrix;
+}
+
+namespace oglcanvas
+{
+ void renderComplexPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPoly );
+ void renderPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPoly );
+ void setupState( const ::basegfx::B2DHomMatrix& rTransform,
+ GLenum eSrcBlend,
+ GLenum eDstBlend,
+ const com::sun::star::rendering::ARGBColor& rColor );
+
+ void renderOSD( const std::vector<double>& rNumbers, double scale );
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/canvas/source/opengl/ogl_spritecanvas.cxx b/canvas/source/opengl/ogl_spritecanvas.cxx
new file mode 100644
index 000000000..1c4881246
--- /dev/null
+++ b/canvas/source/opengl/ogl_spritecanvas.cxx
@@ -0,0 +1,179 @@
+/* -*- 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 <sal/log.hxx>
+
+#include <com/sun/star/lang/NoSupportException.hpp>
+#include <comphelper/servicedecl.hxx>
+#include <osl/mutex.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <tools/diagnose_ex.h>
+
+#include "ogl_canvascustomsprite.hxx"
+#include "ogl_spritecanvas.hxx"
+
+#define SPRITECANVAS_SERVICE_NAME "com.sun.star.rendering.SpriteCanvas.OGL"
+#define SPRITECANVAS_IMPLEMENTATION_NAME "com.sun.star.comp.rendering.SpriteCanvas.OGL"
+
+
+using namespace ::com::sun::star;
+
+namespace sdecl = comphelper::service_decl;
+
+namespace oglcanvas
+{
+ SpriteCanvas::SpriteCanvas( const uno::Sequence< uno::Any >& aArguments,
+ const uno::Reference< uno::XComponentContext >& /*rxContext*/ ) :
+ maArguments(aArguments)
+ {
+ }
+
+ void SpriteCanvas::initialize()
+ {
+ // Only call initialize when not in probe mode
+ if( !maArguments.hasElements() )
+ return;
+
+ SAL_INFO("canvas.ogl", "SpriteCanvas::initialize called" );
+
+ /* aArguments:
+ 0: ptr to creating instance (Window or VirtualDevice)
+ 1: current bounds of creating instance
+ 2: bool, denoting always on top state for Window (always false for VirtualDevice)
+ 3: XWindow for creating Window (or empty for VirtualDevice)
+ 4: SystemGraphicsData as a streamed Any
+ */
+ ENSURE_ARG_OR_THROW( maArguments.getLength() >= 4 &&
+ maArguments[3].getValueTypeClass() == uno::TypeClass_INTERFACE,
+ "OpenGL SpriteCanvas::initialize: wrong number of arguments, or wrong types" );
+
+ uno::Reference< awt::XWindow > xParentWindow;
+ maArguments[3] >>= xParentWindow;
+ VclPtr<vcl::Window> pParentWindow = VCLUnoHelper::GetWindow(xParentWindow);
+ if( !pParentWindow )
+ throw lang::NoSupportException(
+ "Parent window not VCL window, or canvas out-of-process!", nullptr);
+
+ awt::Rectangle aRect;
+ maArguments[1] >>= aRect;
+
+ // setup helper
+ maDeviceHelper.init( *pParentWindow,
+ *this,
+ aRect );
+ maCanvasHelper.init( *this, maDeviceHelper );
+ maArguments.realloc(0);
+ }
+
+ void SpriteCanvas::disposeThis()
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // forward to parent
+ SpriteCanvasBaseT::disposeThis();
+ }
+
+ sal_Bool SAL_CALL SpriteCanvas::showBuffer( sal_Bool bUpdateAll )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // avoid repaints on hidden window (hidden: not mapped to
+ // screen). Return failure, since the screen really has _not_
+ // been updated (caller should try again later)
+ return mbIsVisible && SpriteCanvasBaseT::showBuffer( bUpdateAll );
+ }
+
+ sal_Bool SAL_CALL SpriteCanvas::switchBuffer( sal_Bool bUpdateAll )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // avoid repaints on hidden window (hidden: not mapped to
+ // screen). Return failure, since the screen really has _not_
+ // been updated (caller should try again later)
+ return mbIsVisible && SpriteCanvasBaseT::switchBuffer( bUpdateAll );
+ }
+
+ uno::Reference< rendering::XAnimatedSprite > SAL_CALL SpriteCanvas::createSpriteFromAnimation(
+ const uno::Reference< rendering::XAnimation >& /*animation*/ )
+ {
+ return uno::Reference< rendering::XAnimatedSprite >();
+ }
+
+ uno::Reference< rendering::XAnimatedSprite > SAL_CALL SpriteCanvas::createSpriteFromBitmaps(
+ const uno::Sequence< uno::Reference< rendering::XBitmap > >& /*animationBitmaps*/,
+ ::sal_Int8 /*interpolationMode*/ )
+ {
+ return uno::Reference< rendering::XAnimatedSprite >();
+ }
+
+ uno::Reference< rendering::XCustomSprite > SAL_CALL SpriteCanvas::createCustomSprite(
+ const geometry::RealSize2D& spriteSize )
+ {
+ return uno::Reference< rendering::XCustomSprite >(
+ new CanvasCustomSprite(spriteSize, this, maDeviceHelper) );
+ }
+
+ uno::Reference< rendering::XSprite > SAL_CALL SpriteCanvas::createClonedSprite(
+ const uno::Reference< rendering::XSprite >& /*original*/ )
+ {
+ return uno::Reference< rendering::XSprite >();
+ }
+
+ sal_Bool SAL_CALL SpriteCanvas::updateScreen(sal_Bool bUpdateAll)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return maDeviceHelper.showBuffer(mbIsVisible, bUpdateAll);
+ }
+
+ OUString SAL_CALL SpriteCanvas::getServiceName( )
+ {
+ return SPRITECANVAS_SERVICE_NAME;
+ }
+
+ void SpriteCanvas::show( const ::rtl::Reference< CanvasCustomSprite >& xSprite )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ maDeviceHelper.show(xSprite);
+ }
+
+ void SpriteCanvas::hide( const ::rtl::Reference< CanvasCustomSprite >& xSprite )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ maDeviceHelper.hide(xSprite);
+ }
+
+ void SpriteCanvas::renderRecordedActions() const
+ {
+ maCanvasHelper.renderRecordedActions();
+ }
+
+ static uno::Reference<uno::XInterface> initCanvas( SpriteCanvas* pCanvas )
+ {
+ uno::Reference<uno::XInterface> xRet(static_cast<cppu::OWeakObject*>(pCanvas));
+ pCanvas->initialize();
+ return xRet;
+ }
+
+ sdecl::class_<SpriteCanvas, sdecl::with_args<true> > const serviceImpl(&initCanvas);
+ const sdecl::ServiceDecl oglSpriteCanvasDecl(
+ serviceImpl,
+ SPRITECANVAS_IMPLEMENTATION_NAME,
+ SPRITECANVAS_SERVICE_NAME );
+}
+
+// The C shared lib entry points
+extern "C"
+SAL_DLLPUBLIC_EXPORT void* oglcanvas_component_getFactory( char const* pImplName,
+ void*, void* )
+{
+ return sdecl::component_getFactoryHelper( pImplName, {&oglcanvas::oglSpriteCanvasDecl} );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/canvas/source/opengl/ogl_spritecanvas.hxx b/canvas/source/opengl/ogl_spritecanvas.hxx
new file mode 100644
index 000000000..245575b86
--- /dev/null
+++ b/canvas/source/opengl/ogl_spritecanvas.hxx
@@ -0,0 +1,117 @@
+/* -*- 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_CANVAS_SOURCE_OPENGL_OGL_SPRITECANVAS_HXX
+#define INCLUDED_CANVAS_SOURCE_OPENGL_OGL_SPRITECANVAS_HXX
+
+#include <rtl/ref.hxx>
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/lang/XServiceName.hpp>
+#include <com/sun/star/awt/XWindowListener.hpp>
+#include <com/sun/star/util/XUpdatable.hpp>
+#include <com/sun/star/rendering/XSpriteCanvas.hpp>
+#include <com/sun/star/rendering/XGraphicDevice.hpp>
+#include <com/sun/star/rendering/XBufferController.hpp>
+
+#include <cppuhelper/compbase.hxx>
+#include <comphelper/uno3.hxx>
+
+#include <base/canvasbase.hxx>
+#include <base/disambiguationhelper.hxx>
+#include <base/bufferedgraphicdevicebase.hxx>
+
+#include "ogl_spritedevicehelper.hxx"
+#include "ogl_canvashelper.hxx"
+
+
+namespace oglcanvas
+{
+ class CanvasCustomSprite;
+
+ typedef ::cppu::WeakComponentImplHelper< css::rendering::XSpriteCanvas,
+ css::rendering::XGraphicDevice,
+ css::lang::XMultiServiceFactory,
+ css::rendering::XBufferController,
+ css::awt::XWindowListener,
+ css::util::XUpdatable,
+ css::beans::XPropertySet,
+ css::lang::XServiceName > WindowGraphicDeviceBase_Base;
+ typedef ::canvas::BufferedGraphicDeviceBase<
+ ::canvas::DisambiguationHelper< WindowGraphicDeviceBase_Base >,
+ SpriteDeviceHelper,
+ ::osl::MutexGuard,
+ ::cppu::OWeakObject > SpriteCanvasDeviceBaseT;
+
+ typedef ::canvas::CanvasBase< SpriteCanvasDeviceBaseT,
+ CanvasHelper,
+ ::osl::MutexGuard,
+ ::cppu::OWeakObject > SpriteCanvasBaseT;
+
+ /** Product of this component's factory.
+
+ The SpriteCanvas object combines the actual Window canvas with
+ the XGraphicDevice interface. This is because there's a
+ one-to-one relation between them, anyway, since each window
+ can have exactly one canvas and one associated
+ XGraphicDevice. And to avoid messing around with circular
+ references, this is implemented as one single object.
+ */
+ class SpriteCanvas : public SpriteCanvasBaseT
+ {
+ public:
+ SpriteCanvas( const css::uno::Sequence<
+ css::uno::Any >& aArguments,
+ const css::uno::Reference<
+ css::uno::XComponentContext >& rxContext );
+
+ void initialize();
+
+ /// Dispose all internal references
+ virtual void disposeThis() override;
+
+ // Forwarding the XComponent implementation to the
+ // cppu::ImplHelper templated base
+ // Classname Base doing refcounting Base implementing the XComponent interface
+ // | | |
+ // V V V
+ DECLARE_UNO3_XCOMPONENT_AGG_DEFAULTS( SpriteCanvas, WindowGraphicDeviceBase_Base, ::cppu::WeakComponentImplHelperBase )
+
+ // XBufferController (partial)
+ virtual sal_Bool SAL_CALL showBuffer( sal_Bool bUpdateAll ) override;
+ virtual sal_Bool SAL_CALL switchBuffer( sal_Bool bUpdateAll ) override;
+
+ // XSpriteCanvas
+ virtual css::uno::Reference< css::rendering::XAnimatedSprite > SAL_CALL createSpriteFromAnimation( const css::uno::Reference< css::rendering::XAnimation >& animation ) override;
+ virtual css::uno::Reference< css::rendering::XAnimatedSprite > SAL_CALL createSpriteFromBitmaps( const css::uno::Sequence< css::uno::Reference< css::rendering::XBitmap > >& animationBitmaps, ::sal_Int8 interpolationMode ) override;
+ virtual css::uno::Reference< css::rendering::XCustomSprite > SAL_CALL createCustomSprite( const css::geometry::RealSize2D& spriteSize ) override;
+ virtual css::uno::Reference< css::rendering::XSprite > SAL_CALL createClonedSprite( const css::uno::Reference< css::rendering::XSprite >& original ) override;
+ virtual sal_Bool SAL_CALL updateScreen( sal_Bool bUpdateAll ) override;
+
+ // XServiceName
+ virtual OUString SAL_CALL getServiceName( ) override;
+
+ void show( const ::rtl::Reference< CanvasCustomSprite >& );
+ void hide( const ::rtl::Reference< CanvasCustomSprite >& );
+
+ /** Write out recorded actions
+ */
+ void renderRecordedActions() const;
+
+ private:
+ css::uno::Sequence< css::uno::Any > maArguments;
+ };
+
+ typedef ::rtl::Reference< SpriteCanvas > SpriteCanvasRef;
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/canvas/source/opengl/ogl_spritedevicehelper.cxx b/canvas/source/opengl/ogl_spritedevicehelper.cxx
new file mode 100644
index 000000000..6a1d935c9
--- /dev/null
+++ b/canvas/source/opengl/ogl_spritedevicehelper.cxx
@@ -0,0 +1,555 @@
+/* -*- 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 <sal/log.hxx>
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/utils/canvastools.hxx>
+#include <basegfx/utils/unopolypolygon.hxx>
+#include <com/sun/star/awt/XTopWindow.hpp>
+#include <com/sun/star/rendering/XIntegerBitmapColorSpace.hpp>
+#include <com/sun/star/uno/Reference.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/opengl/OpenGLHelper.hxx>
+#include <vcl/syschild.hxx>
+
+#include "ogl_spritedevicehelper.hxx"
+#include "ogl_spritecanvas.hxx"
+#include "ogl_canvasbitmap.hxx"
+#include "ogl_canvastools.hxx"
+#include "ogl_canvascustomsprite.hxx"
+#include "ogl_texturecache.hxx"
+
+#include <iterator>
+
+using namespace ::com::sun::star;
+
+static void initContext()
+{
+ // need the backside for mirror effects
+ glDisable(GL_CULL_FACE);
+
+ // no perspective, we're 2D
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+
+ // misc preferences
+ glEnable(GL_POINT_SMOOTH);
+ glEnable(GL_LINE_SMOOTH);
+ glEnable(GL_POLYGON_SMOOTH);
+ glHint(GL_POINT_SMOOTH_HINT,GL_NICEST);
+ glHint(GL_LINE_SMOOTH_HINT,GL_NICEST);
+ glHint(GL_POLYGON_SMOOTH_HINT,GL_NICEST);
+ glShadeModel(GL_FLAT);
+}
+
+static void initTransformation(const ::Size& rSize)
+{
+ // use whole window
+ glViewport( 0,0,
+ static_cast<GLsizei>(rSize.Width()),
+ static_cast<GLsizei>(rSize.Height()) );
+
+ // model coordinate system is already in device pixel
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslated(-1.0, 1.0, 0.0);
+ glScaled( 2.0 / rSize.Width(),
+ -2.0 / rSize.Height(),
+ 1.0 );
+
+ // clear to black
+ glClearColor(0,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+}
+
+namespace oglcanvas
+{
+
+ SpriteDeviceHelper::SpriteDeviceHelper() :
+ mpSpriteCanvas(nullptr),
+ maActiveSprites(),
+ maLastUpdate(),
+ mpTextureCache(std::make_shared<TextureCache>()),
+ mnLinearTwoColorGradientProgram(0),
+ mnLinearMultiColorGradientProgram(0),
+ mnRadialTwoColorGradientProgram(0),
+ mnRadialMultiColorGradientProgram(0),
+ mnRectangularTwoColorGradientProgram(0),
+ mnRectangularMultiColorGradientProgram(0),
+ mxContext(OpenGLContext::Create())
+ {}
+
+ SpriteDeviceHelper::~SpriteDeviceHelper()
+ { mxContext->dispose(); }
+
+ void SpriteDeviceHelper::init( vcl::Window& rWindow,
+ SpriteCanvas& rSpriteCanvas,
+ const awt::Rectangle& rViewArea )
+ {
+ mpSpriteCanvas = &rSpriteCanvas;
+
+ rSpriteCanvas.setWindow(
+ uno::Reference<awt::XWindow2>(
+ VCLUnoHelper::GetInterface(&rWindow),
+ uno::UNO_QUERY_THROW) );
+
+ mxContext->requestLegacyContext();
+ mxContext->init(&rWindow);
+ // init window context
+ initContext();
+
+ mnLinearMultiColorGradientProgram =
+ OpenGLHelper::LoadShaders("dummyVertexShader", "linearMultiColorGradientFragmentShader");
+
+ mnLinearTwoColorGradientProgram =
+ OpenGLHelper::LoadShaders("dummyVertexShader", "linearTwoColorGradientFragmentShader");
+
+ mnRadialMultiColorGradientProgram =
+ OpenGLHelper::LoadShaders("dummyVertexShader", "radialMultiColorGradientFragmentShader");
+
+ mnRadialTwoColorGradientProgram =
+ OpenGLHelper::LoadShaders("dummyVertexShader", "radialTwoColorGradientFragmentShader");
+
+ mnRectangularMultiColorGradientProgram =
+ OpenGLHelper::LoadShaders("dummyVertexShader", "rectangularMultiColorGradientFragmentShader");
+
+ mnRectangularTwoColorGradientProgram =
+ OpenGLHelper::LoadShaders("dummyVertexShader", "rectangularTwoColorGradientFragmentShader");
+
+ mxContext->makeCurrent();
+
+ notifySizeUpdate(rViewArea);
+ // TODO(E3): check for GL_ARB_imaging extension
+ }
+
+ void SpriteDeviceHelper::disposing()
+ {
+ // release all references
+ mpSpriteCanvas = nullptr;
+ mpTextureCache.reset();
+
+ if( mxContext->isInitialized() )
+ {
+ glDeleteProgram( mnRectangularTwoColorGradientProgram );
+ glDeleteProgram( mnRectangularMultiColorGradientProgram );
+ glDeleteProgram( mnRadialTwoColorGradientProgram );
+ glDeleteProgram( mnRadialMultiColorGradientProgram );
+ glDeleteProgram( mnLinearTwoColorGradientProgram );
+ glDeleteProgram( mnLinearMultiColorGradientProgram );
+ }
+ }
+
+ geometry::RealSize2D SpriteDeviceHelper::getPhysicalResolution()
+ {
+ if( !mxContext->isInitialized() )
+ return ::canvas::tools::createInfiniteSize2D(); // we're disposed
+
+ // Map a one-by-one millimeter box to pixel
+ SystemChildWindow* pChildWindow = mxContext->getChildWindow();
+ const MapMode aOldMapMode( pChildWindow->GetMapMode() );
+ pChildWindow->SetMapMode( MapMode(MapUnit::MapMM) );
+ const Size aPixelSize( pChildWindow->LogicToPixel(Size(1,1)) );
+ pChildWindow->SetMapMode( aOldMapMode );
+
+ return vcl::unotools::size2DFromSize( aPixelSize );
+ }
+
+ geometry::RealSize2D SpriteDeviceHelper::getPhysicalSize()
+ {
+ if( !mxContext->isInitialized() )
+ return ::canvas::tools::createInfiniteSize2D(); // we're disposed
+
+ // Map the pixel dimensions of the output window to millimeter
+ SystemChildWindow* pChildWindow = mxContext->getChildWindow();
+ const MapMode aOldMapMode( pChildWindow->GetMapMode() );
+ pChildWindow->SetMapMode( MapMode(MapUnit::MapMM) );
+ const Size aLogSize( pChildWindow->PixelToLogic(pChildWindow->GetOutputSizePixel()) );
+ pChildWindow->SetMapMode( aOldMapMode );
+
+ return vcl::unotools::size2DFromSize( aLogSize );
+ }
+
+ uno::Reference< rendering::XLinePolyPolygon2D > SpriteDeviceHelper::createCompatibleLinePolyPolygon(
+ const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/,
+ const uno::Sequence< uno::Sequence< geometry::RealPoint2D > >& points )
+ {
+ // disposed?
+ if( !mpSpriteCanvas )
+ return uno::Reference< rendering::XLinePolyPolygon2D >(); // we're disposed
+
+ return uno::Reference< rendering::XLinePolyPolygon2D >(
+ new ::basegfx::unotools::UnoPolyPolygon(
+ ::basegfx::unotools::polyPolygonFromPoint2DSequenceSequence( points )));
+ }
+
+ uno::Reference< rendering::XBezierPolyPolygon2D > SpriteDeviceHelper::createCompatibleBezierPolyPolygon(
+ const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/,
+ const uno::Sequence< uno::Sequence< geometry::RealBezierSegment2D > >& points )
+ {
+ // disposed?
+ if( !mpSpriteCanvas )
+ return uno::Reference< rendering::XBezierPolyPolygon2D >(); // we're disposed
+
+ return uno::Reference< rendering::XBezierPolyPolygon2D >(
+ new ::basegfx::unotools::UnoPolyPolygon(
+ ::basegfx::unotools::polyPolygonFromBezier2DSequenceSequence( points ) ) );
+ }
+
+ uno::Reference< rendering::XBitmap > SpriteDeviceHelper::createCompatibleBitmap(
+ const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/,
+ const geometry::IntegerSize2D& size )
+ {
+ // disposed?
+ if( !mpSpriteCanvas )
+ return uno::Reference< rendering::XBitmap >(); // we're disposed
+
+ return uno::Reference< rendering::XBitmap >(
+ new CanvasBitmap( size,
+ mpSpriteCanvas,
+ *this ) );
+ }
+
+ uno::Reference< rendering::XVolatileBitmap > SpriteDeviceHelper::createVolatileBitmap(
+ const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/,
+ const geometry::IntegerSize2D& /*size*/ )
+ {
+ return uno::Reference< rendering::XVolatileBitmap >();
+ }
+
+ uno::Reference< rendering::XBitmap > SpriteDeviceHelper::createCompatibleAlphaBitmap(
+ const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/,
+ const geometry::IntegerSize2D& size )
+ {
+ // disposed?
+ if( !mpSpriteCanvas )
+ return uno::Reference< rendering::XBitmap >(); // we're disposed
+
+ return uno::Reference< rendering::XBitmap >(
+ new CanvasBitmap( size,
+ mpSpriteCanvas,
+ *this ) );
+ }
+
+ uno::Reference< rendering::XVolatileBitmap > SpriteDeviceHelper::createVolatileAlphaBitmap(
+ const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/,
+ const geometry::IntegerSize2D& /*size*/ )
+ {
+ return uno::Reference< rendering::XVolatileBitmap >();
+ }
+
+ namespace
+ {
+ /** Functor providing a StrictWeakOrdering for XSprites (over
+ priority)
+ */
+ struct SpriteComparator
+ {
+ bool operator()( const ::rtl::Reference<CanvasCustomSprite>& rLHS,
+ const ::rtl::Reference<CanvasCustomSprite>& rRHS ) const
+ {
+ const double nPrioL( rLHS->getPriority() );
+ const double nPrioR( rRHS->getPriority() );
+
+ // if prios are equal, tie-break on ptr value
+ return nPrioL == nPrioR ? rLHS.get() < rRHS.get() : nPrioL < nPrioR;
+ }
+ };
+ }
+
+ bool SpriteDeviceHelper::showBuffer( bool bIsVisible, SAL_UNUSED_PARAMETER bool /*bUpdateAll*/ )
+ {
+ // hidden or disposed?
+ if( !bIsVisible || !mxContext->isInitialized() || !mpSpriteCanvas )
+ return false;
+
+ mxContext->makeCurrent();
+
+ SystemChildWindow* pChildWindow = mxContext->getChildWindow();
+ const ::Size& rOutputSize = pChildWindow->GetSizePixel();
+ initTransformation(rOutputSize);
+
+ // render the actual spritecanvas content
+ mpSpriteCanvas->renderRecordedActions();
+
+ // render all sprites (in order of priority) on top of that
+ std::vector< ::rtl::Reference<CanvasCustomSprite> > aSprites;
+ std::copy(maActiveSprites.begin(),
+ maActiveSprites.end(),
+ std::back_insert_iterator<
+ std::vector< ::rtl::Reference< CanvasCustomSprite > > >(aSprites));
+ std::sort(aSprites.begin(),
+ aSprites.end(),
+ SpriteComparator());
+ for( const auto& rSprite : aSprites )
+ rSprite->renderSprite();
+
+
+ // frame counter, other info
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslated(-1.0, 1.0, 0.0);
+ glScaled( 2.0 / rOutputSize.Width(),
+ -2.0 / rOutputSize.Height(),
+ 1.0 );
+
+ const double denominator( maLastUpdate.getElapsedTime() );
+ maLastUpdate.reset();
+
+ const double fps(denominator == 0.0 ? 100.0 : 1.0/denominator);
+ std::vector<double> aVec; aVec.push_back(fps);
+ aVec.push_back(maActiveSprites.size());
+ aVec.push_back(mpTextureCache->getCacheSize());
+ aVec.push_back(mpTextureCache->getCacheMissCount());
+ aVec.push_back(mpTextureCache->getCacheHitCount());
+ renderOSD( aVec, 20 );
+
+ /*
+ * TODO: moggi: fix it!
+ // switch buffer, sync etc.
+ const unx::Window aXWindow=pChildWindow->GetSystemData()->aWindow;
+ unx::glXSwapBuffers(reinterpret_cast<unx::Display*>(mpDisplay),
+ aXWindow);
+ pChildWindow->Show();
+ unx::glXWaitGL();
+ XSync( reinterpret_cast<unx::Display*>(mpDisplay), false );
+ */
+ mxContext->swapBuffers();
+
+ // flush texture cache, such that it does not build up
+ // indefinitely.
+ // TODO: have max cache size/LRU time in config, prune only on
+ // demand
+ mpTextureCache->prune();
+
+ return true;
+ }
+
+ bool SpriteDeviceHelper::switchBuffer( bool bIsVisible, bool bUpdateAll )
+ {
+ // no difference for VCL canvas
+ return showBuffer( bIsVisible, bUpdateAll );
+ }
+
+ uno::Any SpriteDeviceHelper::isAccelerated() const
+ {
+ return css::uno::Any(false);
+ }
+
+ uno::Any SpriteDeviceHelper::getDeviceHandle() const
+ {
+ const SystemChildWindow* pChildWindow = mxContext->getChildWindow();
+ return uno::Any( reinterpret_cast< sal_Int64 >(pChildWindow) );
+ }
+
+ uno::Any SpriteDeviceHelper::getSurfaceHandle() const
+ {
+ return uno::Any();
+ }
+
+ uno::Reference<rendering::XColorSpace> SpriteDeviceHelper::getColorSpace() const
+ {
+ // always the same
+ return ::canvas::tools::getStdColorSpace();
+ }
+
+ void SpriteDeviceHelper::notifySizeUpdate( const awt::Rectangle& rBounds )
+ {
+ if( mxContext->isInitialized() )
+ {
+ SystemChildWindow* pChildWindow = mxContext->getChildWindow();
+ pChildWindow->setPosSizePixel(
+ 0,0,rBounds.Width,rBounds.Height);
+ }
+ }
+
+ void SpriteDeviceHelper::dumpScreenContent() const
+ {
+ SAL_INFO("canvas.ogl", OSL_THIS_FUNC );
+ }
+
+ void SpriteDeviceHelper::show( const ::rtl::Reference< CanvasCustomSprite >& xSprite )
+ {
+ maActiveSprites.insert(xSprite);
+ }
+
+ void SpriteDeviceHelper::hide( const ::rtl::Reference< CanvasCustomSprite >& xSprite )
+ {
+ maActiveSprites.erase(xSprite);
+ }
+
+ static void setupUniforms( unsigned int nProgramId,
+ const ::basegfx::B2DHomMatrix& rTexTransform )
+ {
+ const GLint nTransformLocation = glGetUniformLocation(nProgramId,
+ "m_transform" );
+ // OGL is column-major
+ float aTexTransform[] =
+ {
+ float(rTexTransform.get(0,0)), float(rTexTransform.get(1,0)),
+ float(rTexTransform.get(0,1)), float(rTexTransform.get(1,1)),
+ float(rTexTransform.get(0,2)), float(rTexTransform.get(1,2))
+ };
+ glUniformMatrix3x2fv(nTransformLocation,1,false,aTexTransform);
+ }
+
+ static void setupUniforms( unsigned int nProgramId,
+ const rendering::ARGBColor* pColors,
+ const uno::Sequence< double >& rStops,
+ const ::basegfx::B2DHomMatrix& rTexTransform )
+ {
+ glUseProgram(nProgramId);
+
+ GLuint nColorsTexture;
+ glActiveTexture(GL_TEXTURE0);
+ glGenTextures(1, &nColorsTexture);
+ glBindTexture(GL_TEXTURE_1D, nColorsTexture);
+
+ const sal_Int32 nColors=rStops.getLength();
+ glTexImage1D( GL_TEXTURE_1D, 0, GL_RGBA, nColors, 0, GL_RGBA, GL_DOUBLE, pColors );
+ glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+
+ GLuint nStopsTexture;
+ glActiveTexture(GL_TEXTURE1);
+ glGenTextures(1, &nStopsTexture);
+ glBindTexture(GL_TEXTURE_1D, nStopsTexture);
+
+ glTexImage1D( GL_TEXTURE_1D, 0, GL_ALPHA, nColors, 0, GL_ALPHA, GL_DOUBLE, rStops.getConstArray() );
+ glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+
+ const GLint nColorArrayLocation = glGetUniformLocation(nProgramId,
+ "t_colorArray4d" );
+ glUniform1i( nColorArrayLocation, 0 ); // unit 0
+
+ const GLint nStopArrayLocation = glGetUniformLocation(nProgramId,
+ "t_stopArray1d" );
+ glUniform1i( nStopArrayLocation, 1 ); // unit 1
+
+ const GLint nNumColorLocation = glGetUniformLocation(nProgramId,
+ "i_nColors" );
+ glUniform1i( nNumColorLocation, nColors-1 );
+
+ setupUniforms(nProgramId,rTexTransform);
+ }
+
+ static void setupUniforms( unsigned int nProgramId,
+ const rendering::ARGBColor& rStartColor,
+ const rendering::ARGBColor& rEndColor,
+ const ::basegfx::B2DHomMatrix& rTexTransform )
+ {
+ glUseProgram(nProgramId);
+
+ const GLint nStartColorLocation = glGetUniformLocation(nProgramId,
+ "v_startColor4d" );
+ glUniform4f(nStartColorLocation,
+ rStartColor.Red,
+ rStartColor.Green,
+ rStartColor.Blue,
+ rStartColor.Alpha);
+
+ const GLint nEndColorLocation = glGetUniformLocation(nProgramId,
+ "v_endColor4d" );
+ glUniform4f(nEndColorLocation,
+ rEndColor.Red,
+ rEndColor.Green,
+ rEndColor.Blue,
+ rEndColor.Alpha);
+
+ setupUniforms(nProgramId,rTexTransform);
+ }
+
+ void SpriteDeviceHelper::useLinearGradientShader( const rendering::ARGBColor* pColors,
+ const uno::Sequence< double >& rStops,
+ const ::basegfx::B2DHomMatrix& rTexTransform )
+ {
+ if( rStops.getLength() > 2 )
+ setupUniforms(mnLinearMultiColorGradientProgram, pColors, rStops, rTexTransform);
+ else
+ setupUniforms(mnLinearTwoColorGradientProgram, pColors[0], pColors[1], rTexTransform);
+ }
+
+ void SpriteDeviceHelper::useRadialGradientShader( const rendering::ARGBColor* pColors,
+ const uno::Sequence< double >& rStops,
+ const ::basegfx::B2DHomMatrix& rTexTransform )
+ {
+ if( rStops.getLength() > 2 )
+ setupUniforms(mnRadialMultiColorGradientProgram, pColors, rStops, rTexTransform);
+ else
+ setupUniforms(mnRadialTwoColorGradientProgram, pColors[0], pColors[1], rTexTransform);
+ }
+
+ void SpriteDeviceHelper::useRectangularGradientShader( const rendering::ARGBColor* pColors,
+ const uno::Sequence< double >& rStops,
+ const ::basegfx::B2DHomMatrix& rTexTransform )
+ {
+ if( rStops.getLength() > 2 )
+ setupUniforms(mnRectangularMultiColorGradientProgram, pColors, rStops, rTexTransform);
+ else
+ setupUniforms(mnRectangularTwoColorGradientProgram, pColors[0], pColors[1], rTexTransform);
+ }
+
+ namespace
+ {
+
+ class BufferContextImpl : public IBufferContext
+ {
+ GLuint mnFrambufferId;
+ GLuint mnDepthId;
+ GLuint mnTextureId;
+
+ virtual void startBufferRendering() override
+ {
+ glBindFramebuffer(GL_FRAMEBUFFER, mnFrambufferId);
+ }
+
+ virtual void endBufferRendering() override
+ {
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ }
+
+ virtual GLuint getTextureId() override
+ {
+ return mnTextureId;
+ }
+
+ public:
+ explicit BufferContextImpl(const ::basegfx::B2IVector& rSize) :
+ mnFrambufferId(0),
+ mnDepthId(0),
+ mnTextureId(0)
+ {
+ OpenGLHelper::createFramebuffer(rSize.getX(), rSize.getY(), mnFrambufferId,
+ mnDepthId, mnTextureId);
+ }
+
+ virtual ~BufferContextImpl() override
+ {
+ glDeleteTextures(1, &mnTextureId);
+ glDeleteRenderbuffers(1, &mnDepthId);
+ glDeleteFramebuffers(1, &mnFrambufferId);
+ }
+ };
+ }
+
+ IBufferContextSharedPtr SpriteDeviceHelper::createBufferContext(const ::basegfx::B2IVector& rSize) const
+ {
+ return std::make_shared<BufferContextImpl>(rSize);
+ }
+
+ TextureCache& SpriteDeviceHelper::getTextureCache() const
+ {
+ return *mpTextureCache;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/canvas/source/opengl/ogl_spritedevicehelper.hxx b/canvas/source/opengl/ogl_spritedevicehelper.hxx
new file mode 100644
index 000000000..a4dd4d77e
--- /dev/null
+++ b/canvas/source/opengl/ogl_spritedevicehelper.hxx
@@ -0,0 +1,139 @@
+/* -*- 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_CANVAS_SOURCE_OPENGL_OGL_SPRITEDEVICEHELPER_HXX
+#define INCLUDED_CANVAS_SOURCE_OPENGL_OGL_SPRITEDEVICEHELPER_HXX
+
+#include <vcl/opengl/OpenGLContext.hxx>
+
+#include <rtl/ref.hxx>
+#include <canvas/elapsedtime.hxx>
+#include <com/sun/star/rendering/XGraphicDevice.hpp>
+
+#include "ogl_buffercontext.hxx"
+
+#include <set>
+
+namespace vcl { class Window; }
+class SystemChildWindow;
+namespace basegfx{ class B2IVector; class B2DHomMatrix; }
+namespace com::sun::star {
+ namespace awt { struct Rectangle; }
+ namespace geometry { struct AffineMatrix2D; }
+}
+
+namespace oglcanvas
+{
+ class TextureCache;
+ class SpriteCanvas;
+ class CanvasCustomSprite;
+ class CanvasHelper;
+
+ class SpriteDeviceHelper
+ {
+ public:
+ SpriteDeviceHelper();
+ ~SpriteDeviceHelper();
+
+ /// make noncopyable
+ SpriteDeviceHelper(const SpriteDeviceHelper&) = delete;
+ const SpriteDeviceHelper& operator=(const SpriteDeviceHelper&) = delete;
+
+ void init( vcl::Window& rWindow,
+ SpriteCanvas& rSpriteCanvas,
+ const css::awt::Rectangle& rViewArea );
+
+ /// Dispose all internal references
+ void disposing();
+
+ // XWindowGraphicDevice
+ css::geometry::RealSize2D getPhysicalResolution();
+ css::geometry::RealSize2D getPhysicalSize();
+ css::uno::Reference< css::rendering::XLinePolyPolygon2D > createCompatibleLinePolyPolygon(
+ const css::uno::Reference< css::rendering::XGraphicDevice >& rDevice,
+ const css::uno::Sequence< css::uno::Sequence< css::geometry::RealPoint2D > >& points );
+ css::uno::Reference< css::rendering::XBezierPolyPolygon2D > createCompatibleBezierPolyPolygon(
+ const css::uno::Reference< css::rendering::XGraphicDevice >& rDevice,
+ const css::uno::Sequence< css::uno::Sequence< css::geometry::RealBezierSegment2D > >& points );
+ css::uno::Reference< css::rendering::XBitmap > createCompatibleBitmap(
+ const css::uno::Reference< css::rendering::XGraphicDevice >& rDevice,
+ const css::geometry::IntegerSize2D& size );
+ css::uno::Reference< css::rendering::XVolatileBitmap > createVolatileBitmap(
+ const css::uno::Reference< css::rendering::XGraphicDevice >& rDevice,
+ const css::geometry::IntegerSize2D& size );
+ css::uno::Reference< css::rendering::XBitmap > createCompatibleAlphaBitmap(
+ const css::uno::Reference< css::rendering::XGraphicDevice >& rDevice,
+ const css::geometry::IntegerSize2D& size );
+ css::uno::Reference< css::rendering::XVolatileBitmap > createVolatileAlphaBitmap(
+ const css::uno::Reference< css::rendering::XGraphicDevice >& rDevice,
+ const css::geometry::IntegerSize2D& size );
+
+ bool showBuffer( bool bIsVisible, bool bUpdateAll );
+ bool switchBuffer( bool bIsVisible, bool bUpdateAll );
+
+ css::uno::Any isAccelerated() const;
+ css::uno::Any getDeviceHandle() const;
+ css::uno::Any getSurfaceHandle() const;
+ css::uno::Reference<
+ css::rendering::XColorSpace > getColorSpace() const;
+
+ void notifySizeUpdate( const css::awt::Rectangle& rBounds );
+
+ /** called when DumpScreenContent property is enabled on
+ XGraphicDevice, and writes out bitmaps of current screen.
+ */
+ void dumpScreenContent() const;
+
+ void show( const ::rtl::Reference< CanvasCustomSprite >& );
+ void hide( const ::rtl::Reference< CanvasCustomSprite >& );
+
+ /// enable linear gradient shader "texture" with given parameters
+ void useLinearGradientShader( const css::rendering::ARGBColor* pColors,
+ const css::uno::Sequence< double >& rStops,
+ const ::basegfx::B2DHomMatrix& rTexTransform );
+ /// enable radial gradient shader "texture" with given parameters
+ void useRadialGradientShader( const css::rendering::ARGBColor* pColors,
+ const css::uno::Sequence< double >& rStops,
+ const ::basegfx::B2DHomMatrix& rTexTransform );
+ /// enable rectangular gradient shader "texture" with given parameters
+ void useRectangularGradientShader( const css::rendering::ARGBColor* pColors,
+ const css::uno::Sequence< double >& rStops,
+ const ::basegfx::B2DHomMatrix& rTexTransform );
+
+ /// create a pbuffer context (for rendering into background surface)
+ IBufferContextSharedPtr createBufferContext(const ::basegfx::B2IVector& rSize) const;
+
+ /// Get instance of internal texture cache
+ TextureCache& getTextureCache() const;
+
+ private:
+ /// Pointer to sprite canvas (owner of this helper), needed to create bitmaps
+ SpriteCanvas* mpSpriteCanvas;
+
+ std::set< ::rtl::Reference< CanvasCustomSprite > > maActiveSprites;
+
+ /// For the frame counter timings
+ ::canvas::tools::ElapsedTime maLastUpdate;
+
+ std::shared_ptr<TextureCache> mpTextureCache;
+
+ unsigned int mnLinearTwoColorGradientProgram;
+ unsigned int mnLinearMultiColorGradientProgram;
+ unsigned int mnRadialTwoColorGradientProgram;
+ unsigned int mnRadialMultiColorGradientProgram;
+ unsigned int mnRectangularTwoColorGradientProgram;
+ unsigned int mnRectangularMultiColorGradientProgram;
+
+ rtl::Reference<OpenGLContext> mxContext;
+ };
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/canvas/source/opengl/ogl_textlayout.cxx b/canvas/source/opengl/ogl_textlayout.cxx
new file mode 100644
index 000000000..aa5a35296
--- /dev/null
+++ b/canvas/source/opengl/ogl_textlayout.cxx
@@ -0,0 +1,180 @@
+/* -*- 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 <sal/log.hxx>
+
+#include <tools/diagnose_ex.h>
+
+#include "ogl_textlayout.hxx"
+
+using namespace ::com::sun::star;
+
+namespace oglcanvas
+{
+ TextLayout::TextLayout( const rendering::StringContext& aText,
+ sal_Int8 nDirection,
+ sal_Int64 /*nRandomSeed*/,
+ const CanvasFont::ImplRef& rFont ) :
+ TextLayoutBaseT( m_aMutex ),
+ maText( aText ),
+ maLogicalAdvancements(),
+ mpFont( rFont ),
+ mnTextDirection( nDirection )
+ {
+ }
+
+ void SAL_CALL TextLayout::disposing()
+ {
+ mpFont.clear();
+ }
+
+ // XTextLayout
+ uno::Sequence< uno::Reference< rendering::XPolyPolygon2D > > SAL_CALL TextLayout::queryTextShapes( )
+ {
+ // TODO
+ return uno::Sequence< uno::Reference< rendering::XPolyPolygon2D > >();
+ }
+
+ uno::Sequence< geometry::RealRectangle2D > SAL_CALL TextLayout::queryInkMeasures( )
+ {
+ // TODO
+ return uno::Sequence< geometry::RealRectangle2D >();
+ }
+
+ uno::Sequence< geometry::RealRectangle2D > SAL_CALL TextLayout::queryMeasures( )
+ {
+ // TODO
+ return uno::Sequence< geometry::RealRectangle2D >();
+ }
+
+ uno::Sequence< double > SAL_CALL TextLayout::queryLogicalAdvancements( )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ return maLogicalAdvancements;
+ }
+
+ void SAL_CALL TextLayout::applyLogicalAdvancements( const uno::Sequence< double >& aAdvancements )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if( aAdvancements.getLength() != maText.Length )
+ {
+ SAL_INFO("canvas.ogl", "TextLayout::applyLogicalAdvancements(): mismatching number of advancements");
+ throw lang::IllegalArgumentException();
+ }
+
+ maLogicalAdvancements = aAdvancements;
+ }
+
+ geometry::RealRectangle2D SAL_CALL TextLayout::queryTextBounds( )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ ENSURE_OR_THROW( mpFont.get(),
+ "TextLayout::queryTextBounds(): invalid font" );
+
+ // fake text bounds by either taking the advancement values,
+ // or assuming square glyph boxes (width similar to height)
+ const rendering::FontRequest& rFontRequest( mpFont->getFontRequest() );
+ const double nFontSize( std::max( rFontRequest.CellSize,
+ rFontRequest.ReferenceAdvancement ) );
+ if( maLogicalAdvancements.hasElements() )
+ {
+ return geometry::RealRectangle2D( 0, -nFontSize/2,
+ maLogicalAdvancements[ maLogicalAdvancements.getLength()-1 ],
+ nFontSize/2 );
+ }
+ else
+ {
+ return geometry::RealRectangle2D( 0, -nFontSize/2,
+ nFontSize * maText.Length,
+ nFontSize/2 );
+ }
+ }
+
+ double SAL_CALL TextLayout::justify( double /*nSize*/ )
+ {
+ // TODO
+ return 0.0;
+ }
+
+ double SAL_CALL TextLayout::combinedJustify( const uno::Sequence< uno::Reference< rendering::XTextLayout > >& /*aNextLayouts*/,
+ double /*nSize*/ )
+ {
+ // TODO
+ return 0.0;
+ }
+
+ rendering::TextHit SAL_CALL TextLayout::getTextHit( const geometry::RealPoint2D& /*aHitPoint*/ )
+ {
+ // TODO
+ return rendering::TextHit();
+ }
+
+ rendering::Caret SAL_CALL TextLayout::getCaret( sal_Int32 /*nInsertionIndex*/,
+ sal_Bool /*bExcludeLigatures*/ )
+ {
+ // TODO
+ return rendering::Caret();
+ }
+
+ sal_Int32 SAL_CALL TextLayout::getNextInsertionIndex( sal_Int32 /*nStartIndex*/,
+ sal_Int32 /*nCaretAdvancement*/,
+ sal_Bool /*bExcludeLigatures*/ )
+ {
+ // TODO
+ return 0;
+ }
+
+ uno::Reference< rendering::XPolyPolygon2D > SAL_CALL TextLayout::queryVisualHighlighting( sal_Int32 /*nStartIndex*/,
+ sal_Int32 /*nEndIndex*/ )
+ {
+ // TODO
+ return uno::Reference< rendering::XPolyPolygon2D >();
+ }
+
+ uno::Reference< rendering::XPolyPolygon2D > SAL_CALL TextLayout::queryLogicalHighlighting( sal_Int32 /*nStartIndex*/,
+ sal_Int32 /*nEndIndex*/ )
+ {
+ // TODO
+ return uno::Reference< rendering::XPolyPolygon2D >();
+ }
+
+ double SAL_CALL TextLayout::getBaselineOffset( )
+ {
+ // TODO
+ return 0.0;
+ }
+
+ sal_Int8 SAL_CALL TextLayout::getMainTextDirection( )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ return mnTextDirection;
+ }
+
+ uno::Reference< rendering::XCanvasFont > SAL_CALL TextLayout::getFont( )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ return mpFont.get();
+ }
+
+ rendering::StringContext SAL_CALL TextLayout::getText( )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ return maText;
+ }
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/canvas/source/opengl/ogl_textlayout.hxx b/canvas/source/opengl/ogl_textlayout.hxx
new file mode 100644
index 000000000..8c7a289d6
--- /dev/null
+++ b/canvas/source/opengl/ogl_textlayout.hxx
@@ -0,0 +1,73 @@
+/* -*- 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_CANVAS_SOURCE_OPENGL_OGL_TEXTLAYOUT_HXX
+#define INCLUDED_CANVAS_SOURCE_OPENGL_OGL_TEXTLAYOUT_HXX
+
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+
+#include <com/sun/star/rendering/XTextLayout.hpp>
+
+#include "ogl_canvasfont.hxx"
+
+
+/* Definition of TextLayout class */
+
+namespace oglcanvas
+{
+ typedef ::cppu::WeakComponentImplHelper< css::rendering::XTextLayout > TextLayoutBaseT;
+
+ class TextLayout : public ::cppu::BaseMutex,
+ public TextLayoutBaseT
+ {
+ public:
+ TextLayout( const css::rendering::StringContext& aText,
+ sal_Int8 nDirection,
+ sal_Int64 nRandomSeed,
+ const CanvasFont::ImplRef& rFont );
+
+ /// make noncopyable
+ TextLayout(const TextLayout&) = delete;
+ const TextLayout& operator=(const TextLayout&) = delete;
+
+ /// Dispose all internal references
+ virtual void SAL_CALL disposing() override;
+
+ // XTextLayout
+ virtual css::uno::Sequence< css::uno::Reference< css::rendering::XPolyPolygon2D > > SAL_CALL queryTextShapes( ) override;
+ virtual css::uno::Sequence< css::geometry::RealRectangle2D > SAL_CALL queryInkMeasures( ) override;
+ virtual css::uno::Sequence< css::geometry::RealRectangle2D > SAL_CALL queryMeasures( ) override;
+ virtual css::uno::Sequence< double > SAL_CALL queryLogicalAdvancements( ) override;
+ virtual void SAL_CALL applyLogicalAdvancements( const css::uno::Sequence< double >& aAdvancements ) override;
+ virtual css::geometry::RealRectangle2D SAL_CALL queryTextBounds( ) override;
+ virtual double SAL_CALL justify( double nSize ) override;
+ virtual double SAL_CALL combinedJustify( const css::uno::Sequence< css::uno::Reference< css::rendering::XTextLayout > >& aNextLayouts, double nSize ) override;
+ virtual css::rendering::TextHit SAL_CALL getTextHit( const css::geometry::RealPoint2D& aHitPoint ) override;
+ virtual css::rendering::Caret SAL_CALL getCaret( sal_Int32 nInsertionIndex, sal_Bool bExcludeLigatures ) override;
+ virtual sal_Int32 SAL_CALL getNextInsertionIndex( sal_Int32 nStartIndex, sal_Int32 nCaretAdvancement, sal_Bool bExcludeLigatures ) override;
+ virtual css::uno::Reference< css::rendering::XPolyPolygon2D > SAL_CALL queryVisualHighlighting( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) override;
+ virtual css::uno::Reference< css::rendering::XPolyPolygon2D > SAL_CALL queryLogicalHighlighting( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) override;
+ virtual double SAL_CALL getBaselineOffset( ) override;
+ virtual sal_Int8 SAL_CALL getMainTextDirection( ) override;
+ virtual css::uno::Reference< css::rendering::XCanvasFont > SAL_CALL getFont( ) override;
+ virtual css::rendering::StringContext SAL_CALL getText( ) override;
+
+ private:
+ css::rendering::StringContext maText;
+ css::uno::Sequence< double > maLogicalAdvancements;
+ CanvasFont::ImplRef mpFont;
+ sal_Int8 mnTextDirection;
+ };
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/canvas/source/opengl/ogl_texturecache.cxx b/canvas/source/opengl/ogl_texturecache.cxx
new file mode 100644
index 000000000..43fb7d8e2
--- /dev/null
+++ b/canvas/source/opengl/ogl_texturecache.cxx
@@ -0,0 +1,117 @@
+/* -*- 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 <epoxy/gl.h>
+
+#include <com/sun/star/geometry/IntegerSize2D.hpp>
+
+#include "ogl_texturecache.hxx"
+
+
+using namespace ::com::sun::star;
+
+namespace oglcanvas
+{
+ TextureCache::TextureCache() :
+ maCache(101),
+ mnMissCount(0),
+ mnHitCount(0)
+ {}
+
+ TextureCache::~TextureCache()
+ {
+ flush();
+ }
+
+ void TextureCache::flush()
+ {
+ // un-bind any texture
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ // delete all cached textures
+ for( const auto& rCache : maCache )
+ {
+ glDeleteTextures( 1, &rCache.second.nTexture );
+ }
+
+ maCache.clear();
+ mnMissCount = 0;
+ mnHitCount = 0;
+ }
+
+ void TextureCache::prune()
+ {
+ // un-bind any texture
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ // delete already "old" textures, mark "new" entries "old"
+ const TextureCacheMapT::const_iterator aEnd = maCache.end();
+ for( auto aCurr = maCache.begin(); aCurr != aEnd; /* increment managed in loop */)
+ {
+ if( aCurr->second.bOld )
+ {
+ glDeleteTextures( 1, &aCurr->second.nTexture );
+ aCurr = maCache.erase( aCurr );
+ }
+ else
+ {
+ aCurr->second.bOld = true;
+ ++aCurr;
+ }
+ }
+
+ mnMissCount = 0;
+ mnHitCount = 0;
+ }
+
+ unsigned int TextureCache::getTexture( const geometry::IntegerSize2D& rPixelSize,
+ const sal_Int8* pPixel,
+ sal_uInt32 nPixelCrc32) const
+ {
+ unsigned int nTexture(0);
+
+ // texture already cached?
+ TextureCacheMapT::iterator aCacheEntry;
+ if( (aCacheEntry=maCache.find(nPixelCrc32)) == maCache.end() )
+ {
+ // nope, insert new entry
+ glGenTextures(1, &nTexture);
+ glBindTexture(GL_TEXTURE_2D, nTexture);
+
+ // TODO(E3): handle limited texture sizes -
+ // glGetIntegerv(GL_MAX_TEXTURE_SIZE)
+ glTexImage2D(GL_TEXTURE_2D,
+ 0,
+ 4,
+ rPixelSize.Width,
+ rPixelSize.Height,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_INT_8_8_8_8_REV,
+ pPixel);
+
+ maCache[nPixelCrc32].nTexture = nTexture;
+ ++mnMissCount;
+
+ return nTexture;
+ }
+ else
+ {
+ nTexture = aCacheEntry->second.nTexture;
+ aCacheEntry->second.bOld = false;
+ ++mnHitCount;
+ }
+
+ return nTexture;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/canvas/source/opengl/ogl_texturecache.hxx b/canvas/source/opengl/ogl_texturecache.hxx
new file mode 100644
index 000000000..adef65760
--- /dev/null
+++ b/canvas/source/opengl/ogl_texturecache.hxx
@@ -0,0 +1,64 @@
+/* -*- 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_CANVAS_SOURCE_OPENGL_OGL_TEXTURECACHE_HXX
+#define INCLUDED_CANVAS_SOURCE_OPENGL_OGL_TEXTURECACHE_HXX
+
+#include <sal/types.h>
+#include <unordered_map>
+
+namespace com::sun::star {
+ namespace geometry { struct IntegerSize2D; }
+}
+
+namespace oglcanvas
+{
+ class TextureCache
+ {
+ public:
+ TextureCache();
+ ~TextureCache();
+
+ /// clear whole cache, reset statistic counters
+ void flush();
+
+ /** prune old entries from cache
+
+ Every time this method is called, all cache entries are set
+ to "old". If subsequently not used by getTexture(),
+ they'll be entitled for expunge on the next prune()
+ call. Resets statistic counters.
+ */
+ void prune();
+
+ /// Statistics
+ size_t getCacheSize() const { return maCache.size(); };
+ sal_uInt32 getCacheMissCount() const { return mnMissCount; }
+ sal_uInt32 getCacheHitCount() const { return mnHitCount; }
+
+ unsigned int getTexture( const css::geometry::IntegerSize2D& rPixelSize,
+ const sal_Int8* pPixel,
+ sal_uInt32 nPixelCrc32) const;
+ private:
+ struct CacheEntry
+ {
+ CacheEntry() : nTexture(0), bOld(false) {}
+ unsigned int nTexture;
+ bool bOld;
+ };
+ typedef std::unordered_map<sal_uInt32,CacheEntry> TextureCacheMapT;
+ mutable TextureCacheMapT maCache;
+ mutable sal_uInt32 mnMissCount;
+ mutable sal_uInt32 mnHitCount;
+ };
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/canvas/source/opengl/ogl_tools.hxx b/canvas/source/opengl/ogl_tools.hxx
new file mode 100644
index 000000000..469a5be78
--- /dev/null
+++ b/canvas/source/opengl/ogl_tools.hxx
@@ -0,0 +1,30 @@
+/* -*- 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_CANVAS_SOURCE_OPENGL_OGL_TOOLS_HXX
+#define INCLUDED_CANVAS_SOURCE_OPENGL_OGL_TOOLS_HXX
+
+#include <sal/config.h>
+#include <epoxy/gl.h>
+
+namespace oglcanvas
+{
+ struct TransformationPreserver
+ {
+ TransformationPreserver()
+ { glPushMatrix(); }
+
+ ~TransformationPreserver()
+ { glPopMatrix(); }
+ };
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/canvas/source/opengl/oglcanvas.component b/canvas/source/opengl/oglcanvas.component
new file mode 100644
index 000000000..af3dfebaf
--- /dev/null
+++ b/canvas/source/opengl/oglcanvas.component
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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/.
+ *
+-->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ prefix="oglcanvas" xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.rendering.SpriteCanvas.OGL">
+ <service name="com.sun.star.rendering.SpriteCanvas.OGL"/>
+ </implementation>
+</component>