summaryrefslogtreecommitdiff
path: root/canvas
diff options
context:
space:
mode:
authorThorsten Behrens <tbehrens@suse.com>2012-01-31 01:07:48 +0100
committerThorsten Behrens <tbehrens@suse.com>2013-10-07 17:33:45 +0200
commite52f1bd7b34fc73f52aadf1d33efa6685a0b22e8 (patch)
tree6457d6bf15886430264fa805d7e56352484e8813 /canvas
parent21ec9beae29b19b8ec6f0a16fd0e708e4f210208 (diff)
Add opengl canvas implementation.
Adds opengl canvas implementation - display-list-based, all rendering done as textured geometry. Needs shader support. Currently compiles and works on Linux, Mac should be ~easy to add, win32 eventually. Change-Id: Ibf3eb88d6a36a91b2960a3a6320d708160e4fc14
Diffstat (limited to 'canvas')
-rw-r--r--canvas/Library_oglcanvas.mk69
-rw-r--r--canvas/Module_canvas.mk6
-rw-r--r--canvas/source/opengl/ogl_bitmapcanvashelper.cxx101
-rw-r--r--canvas/source/opengl/ogl_bitmapcanvashelper.hxx103
-rw-r--r--canvas/source/opengl/ogl_buffercontext.hxx34
-rw-r--r--canvas/source/opengl/ogl_canvasbitmap.cxx55
-rw-r--r--canvas/source/opengl/ogl_canvasbitmap.hxx78
-rw-r--r--canvas/source/opengl/ogl_canvascustomsprite.cxx261
-rw-r--r--canvas/source/opengl/ogl_canvascustomsprite.hxx100
-rw-r--r--canvas/source/opengl/ogl_canvasfont.cxx81
-rw-r--r--canvas/source/opengl/ogl_canvasfont.hxx68
-rw-r--r--canvas/source/opengl/ogl_canvashelper.cxx1011
-rw-r--r--canvas/source/opengl/ogl_canvashelper.hxx238
-rw-r--r--canvas/source/opengl/ogl_canvastools.cxx139
-rw-r--r--canvas/source/opengl/ogl_canvastools.hxx38
-rw-r--r--canvas/source/opengl/ogl_spritecanvas.cxx195
-rw-r--r--canvas/source/opengl/ogl_spritecanvas.hxx118
-rw-r--r--canvas/source/opengl/ogl_spritedevicehelper.cxx1249
-rw-r--r--canvas/source/opengl/ogl_spritedevicehelper.hxx179
-rw-r--r--canvas/source/opengl/ogl_textlayout.cxx215
-rw-r--r--canvas/source/opengl/ogl_textlayout.hxx79
-rw-r--r--canvas/source/opengl/ogl_texturecache.cxx124
-rw-r--r--canvas/source/opengl/ogl_texturecache.hxx64
-rw-r--r--canvas/source/opengl/ogl_tools.hxx31
-rw-r--r--canvas/source/opengl/oglcanvas.component16
25 files changed, 4652 insertions, 0 deletions
diff --git a/canvas/Library_oglcanvas.mk b/canvas/Library_oglcanvas.mk
new file mode 100644
index 000000000000..fca6996f70d3
--- /dev/null
+++ b/canvas/Library_oglcanvas.mk
@@ -0,0 +1,69 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_Library_Library,oglcanvas))
+
+$(eval $(call gb_Library_set_componentfile,oglcanvas,canvas/source/opengl/oglcanvas))
+
+$(eval $(call gb_Library_use_sdk_api,oglcanvas))
+
+$(eval $(call gb_Library_use_libraries,oglcanvas,\
+ sal \
+ cppu \
+ basegfx \
+ cppuhelper \
+ comphelper \
+ vcl \
+ tk \
+ tl \
+ i18nlangtag \
+ canvastools \
+ $(gb_UWINAPI) \
+))
+
+$(eval $(call gb_Library_add_exception_objects,oglcanvas,\
+ canvas/source/opengl/ogl_bitmapcanvashelper \
+ canvas/source/opengl/ogl_canvasbitmap \
+ canvas/source/opengl/ogl_canvascustomsprite \
+ canvas/source/opengl/ogl_canvasfont \
+ canvas/source/opengl/ogl_canvashelper \
+ canvas/source/opengl/ogl_canvastools \
+ canvas/source/opengl/ogl_spritecanvas \
+ canvas/source/opengl/ogl_spritedevicehelper \
+ canvas/source/opengl/ogl_textlayout \
+ canvas/source/opengl/ogl_texturecache \
+))
+
+$(eval $(call gb_Library_use_externals,oglcanvas,\
+ boost_headers \
+))
+
+ifeq ($(strip $(OS)),MACOSX)
+$(eval $(call gb_Library_use_system_darwin_frameworks,oglcanvas,\
+ Cocoa \
+ GLUT \
+ OpenGL \
+))
+
+else ifeq ($(strip $(OS)),WNT)
+$(eval $(call gb_Library_use_system_win32_libs,oglcanvas,\
+ gdi32 \
+ glu32 \
+ opengl32 \
+))
+
+else
+$(eval $(call gb_Library_add_libs,oglcanvas,\
+ -lGL \
+ -lGLU \
+ -lX11 \
+))
+endif
+
+# vim: set noet sw=4 ts=4:
diff --git a/canvas/Module_canvas.mk b/canvas/Module_canvas.mk
index 0bc364e532ce..510cb98b2004 100644
--- a/canvas/Module_canvas.mk
+++ b/canvas/Module_canvas.mk
@@ -32,6 +32,12 @@ $(eval $(call gb_Module_add_targets,canvas,\
))
endif
+ifeq ($(ENABLE_OPENGL),TRUE)
+$(eval $(call gb_Module_add_targets,canvas,\
+ Library_oglcanvas \
+))
+endif
+
ifneq ($(ENABLE_DIRECTX),)
$(eval $(call gb_Module_add_targets,canvas,\
Library_directx9canvas \
diff --git a/canvas/source/opengl/ogl_bitmapcanvashelper.cxx b/canvas/source/opengl/ogl_bitmapcanvashelper.cxx
new file mode 100644
index 000000000000..1d132cbd257f
--- /dev/null
+++ b/canvas/source/opengl/ogl_bitmapcanvashelper.cxx
@@ -0,0 +1,101 @@
+/* -*- 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 "ogl_bitmapcanvashelper.hxx"
+
+#include <canvas/debug.hxx>
+#include <canvas/canvastools.hxx>
+#include <tools/diagnose_ex.h>
+
+
+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);
+ }
+
+ void BitmapCanvasHelper::copyRect( const rendering::XCanvas* /*pCanvas*/,
+ const uno::Reference< rendering::XBitmapCanvas >& /*sourceCanvas*/,
+ const geometry::RealRectangle2D& /*sourceRect*/,
+ const rendering::ViewState& /*sourceViewState*/,
+ const rendering::RenderState& /*sourceRenderState*/,
+ const geometry::RealRectangle2D& /*destRect*/,
+ const rendering::ViewState& /*destViewState*/,
+ const rendering::RenderState& /*destRenderState*/ )
+ {
+ // TODO(F2): copyRect NYI
+ }
+
+ geometry::IntegerSize2D BitmapCanvasHelper::getSize()
+ {
+ return maSize;
+ }
+
+ uno::Reference< rendering::XBitmap > BitmapCanvasHelper::getScaledBitmap( const geometry::RealSize2D& /*newSize*/,
+ sal_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 >();
+ }
+
+ void BitmapCanvasHelper::setData( const uno::Sequence< sal_Int8 >& /*data*/,
+ const rendering::IntegerBitmapLayout& /*bitmapLayout*/,
+ const geometry::IntegerRectangle2D& /*rect*/ )
+ {
+ // TODO(F2): NYI - and improbable to ever be
+ }
+
+ void BitmapCanvasHelper::setPixel( const uno::Sequence< sal_Int8 >& /*color*/,
+ const rendering::IntegerBitmapLayout& /*bitmapLayout*/,
+ const geometry::IntegerPoint2D& /*pos*/ )
+ {
+ // TODO(F2): NYI - and improbable to ever be
+ }
+
+ 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()
+ {
+ return ::canvas::tools::getStdMemoryLayout(getSize());
+ }
+
+ bool BitmapCanvasHelper::hasAlpha() const
+ {
+ return true;
+ }
+
+}
+
+/* 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 000000000000..50781c3bb491
--- /dev/null
+++ b/canvas/source/opengl/ogl_bitmapcanvashelper.hxx
@@ -0,0 +1,103 @@
+/* -*- 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 OGL_BITMAPCANVASHELPER_HXX_
+#define OGL_BITMAPCANVASHELPER_HXX_
+
+#include <com/sun/star/rendering/XBitmapCanvas.hpp>
+#include <com/sun/star/rendering/XIntegerBitmap.hpp>
+
+#include <basegfx/vector/b2isize.hxx>
+#include <basegfx/vector/b2dsize.hxx>
+
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include <vector>
+
+#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( ::com::sun::star::rendering::XGraphicDevice& rDevice,
+ SpriteDeviceHelper& rDeviceHelper,
+ const ::com::sun::star::geometry::IntegerSize2D& rSize );
+
+ // BitmapCanvasHelper functionality
+ // ================================
+
+ void copyRect( const ::com::sun::star::rendering::XCanvas* rCanvas,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XBitmapCanvas >& sourceCanvas,
+ const ::com::sun::star::geometry::RealRectangle2D& sourceRect,
+ const ::com::sun::star::rendering::ViewState& sourceViewState,
+ const ::com::sun::star::rendering::RenderState& sourceRenderState,
+ const ::com::sun::star::geometry::RealRectangle2D& destRect,
+ const ::com::sun::star::rendering::ViewState& destViewState,
+ const ::com::sun::star::rendering::RenderState& destRenderState );
+
+ ::com::sun::star::geometry::IntegerSize2D getSize();
+
+ ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmapCanvas > queryBitmapCanvas();
+
+ ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmap >
+ getScaledBitmap( const ::com::sun::star::geometry::RealSize2D& newSize,
+ sal_Bool beFast );
+
+ ::com::sun::star::uno::Sequence< sal_Int8 >
+ getData( ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout,
+ const ::com::sun::star::geometry::IntegerRectangle2D& rect );
+
+ void setData( const ::com::sun::star::uno::Sequence< sal_Int8 >& data,
+ const ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout,
+ const ::com::sun::star::geometry::IntegerRectangle2D& rect );
+
+ void setPixel( const ::com::sun::star::uno::Sequence< sal_Int8 >& color,
+ const ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout,
+ const ::com::sun::star::geometry::IntegerPoint2D& pos );
+
+ ::com::sun::star::uno::Sequence< sal_Int8 >
+ getPixel( ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout,
+ const ::com::sun::star::geometry::IntegerPoint2D& pos );
+
+ ::com::sun::star::rendering::IntegerBitmapLayout getMemoryLayout();
+
+ bool hasAlpha() const;
+
+ private:
+ ::com::sun::star::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 000000000000..b9964126f025
--- /dev/null
+++ b/canvas/source/opengl/ogl_buffercontext.hxx
@@ -0,0 +1,34 @@
+/* -*- 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 OGL_BUFFERCONTEXT_HXX_
+#define OGL_BUFFERCONTEXT_HXX_
+
+#include <sal/config.h>
+#include <boost/shared_ptr.hpp>
+
+namespace oglcanvas
+{
+ struct IBufferContext
+ {
+ virtual ~IBufferContext() {}
+
+ /// start render to buffer. changes gl current context
+ virtual bool startBufferRendering() = 0;
+
+ /// end render to buffer. switches to window context, and selects rendered texture
+ virtual bool endBufferRendering() = 0;
+ };
+
+ typedef ::boost::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 000000000000..d78baf58bd97
--- /dev/null
+++ b/canvas/source/opengl/ogl_canvasbitmap.cxx
@@ -0,0 +1,55 @@
+/* -*- 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 "ogl_canvasbitmap.hxx"
+
+#include <canvas/debug.hxx>
+#include <canvas/canvastools.hxx>
+#include <tools/diagnose_ex.h>
+
+
+using namespace ::com::sun::star;
+
+namespace oglcanvas
+{
+ CanvasBitmap::CanvasBitmap( const geometry::IntegerSize2D& rSize,
+ const SpriteCanvasRef& rDevice,
+ SpriteDeviceHelper& rDeviceHelper,
+ bool bHasAlpha ) :
+ mpDevice( rDevice ),
+ mbHasAlpha( bHasAlpha )
+ {
+ ENSURE_OR_THROW( mpDevice.is(),
+ "CanvasBitmap::CanvasBitmap(): Invalid surface or device" );
+
+ maCanvasHelper.init( *mpDevice.get(), rDeviceHelper, rSize );
+ }
+
+ CanvasBitmap::CanvasBitmap( const CanvasBitmap& rSrc ) :
+ mpDevice( rSrc.mpDevice ),
+ mbHasAlpha( rSrc.mbHasAlpha )
+ {
+ maCanvasHelper = rSrc.maCanvasHelper;
+ }
+
+ void SAL_CALL 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 000000000000..b874bde8da42
--- /dev/null
+++ b/canvas/source/opengl/ogl_canvasbitmap.hxx
@@ -0,0 +1,78 @@
+/* -*- 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 OGL_CANVASBITMAP_HXX
+#define OGL_CANVASBITMAP_HXX
+
+#include <cppuhelper/compbase2.hxx>
+
+#include <com/sun/star/rendering/XBitmapCanvas.hpp>
+#include <com/sun/star/rendering/XIntegerBitmap.hpp>
+
+#include <canvas/base/integerbitmapbase.hxx>
+#include <canvas/base/disambiguationhelper.hxx>
+#include <basegfx/vector/b2isize.hxx>
+
+#include <boost/shared_ptr.hpp>
+
+#include "ogl_bitmapcanvashelper.hxx"
+#include "ogl_spritecanvas.hxx"
+
+
+/* Definition of CanvasBitmap class */
+
+namespace oglcanvas
+{
+ typedef ::cppu::WeakComponentImplHelper2< ::com::sun::star::rendering::XBitmapCanvas,
+ ::com::sun::star::rendering::XIntegerBitmap > CanvasBitmapBase_Base;
+ typedef ::canvas::IntegerBitmapBase<
+ ::canvas::DisambiguationHelper< 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 ::com::sun::star::geometry::IntegerSize2D& rSize,
+ const SpriteCanvasRef& rDevice,
+ SpriteDeviceHelper& rDeviceHelper,
+ bool bHasAlpha );
+
+ /** Create verbatim copy (including all recorded actions)
+ */
+ CanvasBitmap( const CanvasBitmap& rSrc );
+
+ /// Dispose all internal references
+ virtual void disposeThis();
+
+ /** Write out recorded actions
+ */
+ bool renderRecordedActions() const;
+
+ private:
+ /** MUST hold here, too, since CanvasHelper only contains a
+ raw pointer (without refcounting)
+ */
+ SpriteCanvasRef mpDevice;
+ bool mbHasAlpha;
+ };
+}
+
+#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 000000000000..7c0867176438
--- /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 "ogl_canvascustomsprite.hxx"
+#include "ogl_canvastools.hxx"
+#include "ogl_tools.hxx"
+
+#include <canvas/debug.hxx>
+#include <canvas/verbosetrace.hxx>
+#include <canvas/verifyinput.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <canvas/canvastools.hxx>
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/tools/canvastools.hxx>
+#include <basegfx/polygon/b2dpolygonclipper.hxx>
+#include <basegfx/polygon/b2dpolygontriangulator.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <GL/glext.h>
+
+
+using namespace ::com::sun::star;
+
+namespace oglcanvas
+{
+ CanvasCustomSprite::CanvasCustomSprite( const ::com::sun::star::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.get(),
+ rDeviceHelper );
+ }
+
+ void SAL_CALL CanvasCustomSprite::disposeThis()
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ mpSpriteCanvas.clear();
+
+ // forward to parent
+ CanvasCustomSpriteBaseT::disposeThis();
+ }
+
+ void SAL_CALL CanvasCustomSprite::setAlpha( double alpha ) throw (lang::IllegalArgumentException,
+ uno::RuntimeException)
+ {
+ 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 ) throw (lang::IllegalArgumentException,
+ uno::RuntimeException)
+ {
+ canvas::tools::verifyArgs(aNewPos, viewState, renderState,
+ BOOST_CURRENT_FUNCTION,
+ 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 ) throw (lang::IllegalArgumentException,
+ uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ maTransformation = aTransformation;
+ }
+
+ void SAL_CALL CanvasCustomSprite::clip( const uno::Reference< rendering::XPolyPolygon2D >& xClip ) throw (uno::RuntimeException)
+ {
+ mxClip = xClip;
+ }
+
+ void SAL_CALL CanvasCustomSprite::setPriority( double nPriority ) throw (uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ mfPriority = nPriority;
+ }
+
+ void SAL_CALL CanvasCustomSprite::show() throw (uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if( mpSpriteCanvas.is() )
+ mpSpriteCanvas->show(this);
+ }
+
+ void SAL_CALL CanvasCustomSprite::hide() throw (uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if( mpSpriteCanvas.is() )
+ mpSpriteCanvas->hide(this);
+ }
+
+ uno::Reference< rendering::XCanvas > SAL_CALL CanvasCustomSprite::getContentCanvas() throw (uno::RuntimeException)
+ {
+ 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() )
+ {
+ // drats. need to render to temp surface before, and then
+ // composite that to screen
+
+ // TODO(P3): buffer pbuffer, maybe even keep content
+ // (in a 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();
+
+ 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::B2DPolygon& rTriangulatedPolygon(
+ ::basegfx::triangulator::triangulate(
+ ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(mxClip)));
+
+ basegfx::B2DPolygon rTriangleList(
+ basegfx::tools::clipTriangleListOnRange(
+ rTriangulatedPolygon,
+ basegfx::B2DRange(
+ 0,0,
+ aSpriteSizePixel.getX(),
+ aSpriteSizePixel.getY())));
+
+ glBegin(GL_TRIANGLES);
+ for( sal_uInt32 i=0; i<rTriangulatedPolygon.count(); i++ )
+ {
+ const ::basegfx::B2DPoint& rPt( rTriangulatedPolygon.getB2DPoint(i) );
+ const double s(rPt.getX()/fWidth);
+ const double t(rPt.getY()/fHeight);
+ glTexCoord2f(s,t); glVertex2d(rPt.getX(), rPt.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 000000000000..a96ce6494d08
--- /dev/null
+++ b/canvas/source/opengl/ogl_canvascustomsprite.hxx
@@ -0,0 +1,100 @@
+/* -*- 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 OGL_CANVASCUSTOMSPRITE_HXX
+#define OGL_CANVASCUSTOMSPRITE_HXX
+
+#include <cppuhelper/compbase2.hxx>
+#include <comphelper/uno3.hxx>
+
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/rendering/XCustomSprite.hpp>
+#include <com/sun/star/rendering/XPolyPolygon2D.hpp>
+
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/vector/b2isize.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+
+#include <canvas/base/disambiguationhelper.hxx>
+
+#include "ogl_spritecanvas.hxx"
+#include "ogl_canvashelper.hxx"
+
+
+namespace oglcanvas
+{
+ typedef ::cppu::WeakComponentImplHelper2< ::com::sun::star::rendering::XCustomSprite,
+ ::com::sun::star::rendering::XCanvas > CanvasCustomSpriteBase_Base;
+ typedef ::canvas::CanvasBase<
+ ::canvas::DisambiguationHelper< 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 ::com::sun::star::geometry::RealSize2D& rSpriteSize,
+ const SpriteCanvasRef& rRefDevice,
+ SpriteDeviceHelper& rDeviceHelper );
+
+ virtual void disposeThis();
+
+ // XSprite
+ virtual void SAL_CALL setAlpha( double alpha ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL move( const ::com::sun::star::geometry::RealPoint2D& aNewPos, const ::com::sun::star::rendering::ViewState& viewState, const ::com::sun::star::rendering::RenderState& renderState ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL transform( const ::com::sun::star::geometry::AffineMatrix2D& aTransformation ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL clip( const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XPolyPolygon2D >& aClip ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL setPriority( double nPriority ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL show() throw (::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL hide() throw (::com::sun::star::uno::RuntimeException);
+
+ // XCustomSprite
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCanvas > SAL_CALL getContentCanvas() throw (::com::sun::star::uno::RuntimeException);
+
+ 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 ::com::sun::star::geometry::RealSize2D maSize;
+
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XPolyPolygon2D > mxClip;
+ ::com::sun::star::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 000000000000..d465919ab2b3
--- /dev/null
+++ b/canvas/source/opengl/ogl_canvasfont.cxx
@@ -0,0 +1,81 @@
+/* -*- 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 "ogl_canvasfont.hxx"
+#include "ogl_textlayout.hxx"
+
+#include <com/sun/star/rendering/XSpriteCanvas.hpp>
+#include <com/sun/star/rendering/PanoseWeight.hpp>
+
+
+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 ),
+ maFontMatrix( fontMatrix )
+ {
+ }
+
+ void SAL_CALL CanvasFont::disposing()
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ }
+
+ uno::Reference< rendering::XTextLayout > SAL_CALL CanvasFont::createTextLayout( const rendering::StringContext& aText,
+ sal_Int8 nDirection,
+ sal_Int64 nRandomSeed ) throw (uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ return new TextLayout( aText, nDirection, nRandomSeed, ImplRef( this ) );
+ }
+
+ uno::Sequence< double > SAL_CALL CanvasFont::getAvailableSizes( ) throw (uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // TODO
+ return uno::Sequence< double >();
+ }
+
+ uno::Sequence< beans::PropertyValue > SAL_CALL CanvasFont::getExtraFontProperties( ) throw (uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // TODO
+ return uno::Sequence< beans::PropertyValue >();
+ }
+
+ rendering::FontRequest SAL_CALL CanvasFont::getFontRequest( ) throw (uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ return maFontRequest;
+ }
+
+ rendering::FontMetrics SAL_CALL CanvasFont::getFontMetrics( ) throw (uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // TODO
+ return rendering::FontMetrics();
+ }
+
+ const ::com::sun::star::geometry::Matrix2D& CanvasFont::getFontMatrix() const
+ {
+ return maFontMatrix;
+ }
+}
+
+/* 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 000000000000..9a262975cf11
--- /dev/null
+++ b/canvas/source/opengl/ogl_canvasfont.hxx
@@ -0,0 +1,68 @@
+/* -*- 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 OGL_CANVASFONT_HXX
+#define OGL_CANVASFONT_HXX
+
+#include <comphelper/implementationreference.hxx>
+
+#include <cppuhelper/compbase1.hxx>
+#include <comphelper/broadcasthelper.hxx>
+
+#include <com/sun/star/rendering/XCanvas.hpp>
+#include <com/sun/star/rendering/XCanvasFont.hpp>
+
+#include <rtl/ref.hxx>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+
+
+/* Definition of CanvasFont class */
+
+namespace oglcanvas
+{
+ class SpriteCanvas;
+
+ typedef ::cppu::WeakComponentImplHelper1< ::com::sun::star::rendering::XCanvasFont > CanvasFontBaseT;
+
+ class CanvasFont : public ::comphelper::OBaseMutex,
+ public CanvasFontBaseT,
+ private ::boost::noncopyable
+ {
+ public:
+ typedef ::comphelper::ImplementationReference<
+ CanvasFont,
+ ::com::sun::star::rendering::XCanvasFont > ImplRef;
+
+ CanvasFont( const ::com::sun::star::rendering::FontRequest& fontRequest,
+ const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& extraFontProperties,
+ const ::com::sun::star::geometry::Matrix2D& fontMatrix );
+
+ /// Dispose all internal references
+ virtual void SAL_CALL disposing();
+
+ // XCanvasFont
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XTextLayout > SAL_CALL createTextLayout( const ::com::sun::star::rendering::StringContext& aText, sal_Int8 nDirection, sal_Int64 nRandomSeed ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::rendering::FontRequest SAL_CALL getFontRequest( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::rendering::FontMetrics SAL_CALL getFontMetrics( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< double > SAL_CALL getAvailableSizes( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > SAL_CALL getExtraFontProperties( ) throw (::com::sun::star::uno::RuntimeException);
+
+ const ::com::sun::star::geometry::Matrix2D& getFontMatrix() const;
+
+ private:
+ ::com::sun::star::rendering::FontRequest maFontRequest;
+ ::com::sun::star::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 000000000000..ae349b999839
--- /dev/null
+++ b/canvas/source/opengl/ogl_canvashelper.cxx
@@ -0,0 +1,1011 @@
+/* -*- 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/.
+ */
+
+#define GL_GLEXT_PROTOTYPES
+
+#include "ogl_canvashelper.hxx"
+
+#include <rtl/crc.h>
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <basegfx/tools/canvastools.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/polygon/b2dpolygontriangulator.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+
+#include <com/sun/star/rendering/TexturingMode.hpp>
+#include <com/sun/star/rendering/CompositeOperation.hpp>
+#include <com/sun/star/rendering/RepaintResult.hpp>
+#include <com/sun/star/rendering/PathCapType.hpp>
+#include <com/sun/star/rendering/PathJoinType.hpp>
+
+#include <vcl/virdev.hxx>
+#include <vcl/metric.hxx>
+#include <vcl/font.hxx>
+
+#include "ogl_canvasfont.hxx"
+#include "ogl_canvastools.hxx"
+#include "ogl_canvasbitmap.hxx"
+#include "ogl_spritecanvas.hxx"
+#include "ogl_texturecache.hxx"
+#include "ogl_tools.hxx"
+
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <GL/glext.h>
+
+#include <boost/scoped_array.hpp>
+
+
+using namespace ::com::sun::star;
+
+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;
+
+ ::boost::function6< bool,
+ const CanvasHelper&,
+ const ::basegfx::B2DHomMatrix&,
+ GLenum,
+ GLenum,
+ const rendering::ARGBColor&,
+ const ::basegfx::B2DPolyPolygonVector& > maFunction;
+ };
+
+ namespace
+ {
+ bool lcl_drawPoint( const CanvasHelper& /*rHelper*/,
+ const ::basegfx::B2DHomMatrix& rTransform,
+ GLenum eSrcBlend,
+ GLenum eDstBlend,
+ const rendering::ARGBColor& rColor,
+ const geometry::RealPoint2D& rPoint )
+ {
+ TransformationPreserver aPreserver;
+ setupState(rTransform, eSrcBlend, eDstBlend, rColor);
+
+ glBegin(GL_POINTS);
+ glVertex2d(rPoint.X, rPoint.Y);
+ glEnd();
+
+ return true;
+ }
+
+ 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);
+
+ ::basegfx::B2DPolyPolygonVector::const_iterator aCurr=rPolyPolygons.begin();
+ const ::basegfx::B2DPolyPolygonVector::const_iterator aEnd=rPolyPolygons.end();
+ while( aCurr != aEnd )
+ renderPolyPolygon(*aCurr++);
+
+ 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);
+
+ ::basegfx::B2DPolyPolygonVector::const_iterator aCurr=rPolyPolygons.begin();
+ const ::basegfx::B2DPolyPolygonVector::const_iterator aEnd=rPolyPolygons.end();
+ while( aCurr != aEnd )
+ {
+ glBegin(GL_TRIANGLES);
+ renderComplexPolyPolygon(*aCurr++);
+ 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;
+ ::basegfx::B2DPolyPolygonVector::const_iterator aCurr=rPolyPolygons.begin();
+ const ::basegfx::B2DPolyPolygonVector::const_iterator aEnd=rPolyPolygons.end();
+ while( aCurr != aEnd )
+ aBounds.expand(::basegfx::tools::getRange(*aCurr++));
+ 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::GRADIENT_LINEAR:
+ rHelper.getDeviceHelper()->useLinearGradientShader(pColors,
+ rValues.maStops,
+ aTextureTransform);
+ break;
+
+ case ::canvas::ParametricPolyPolygon::GRADIENT_ELLIPTICAL:
+ rHelper.getDeviceHelper()->useRadialGradientShader(pColors,
+ rValues.maStops,
+ aTextureTransform);
+ break;
+
+ case ::canvas::ParametricPolyPolygon::GRADIENT_RECTANGULAR:
+ rHelper.getDeviceHelper()->useRectangularGradientShader(pColors,
+ rValues.maStops,
+ aTextureTransform);
+ break;
+
+ default:
+ ENSURE_OR_THROW( false,
+ "CanvasHelper lcl_fillGradientPolyPolygon(): Unexpected case" );
+ }
+
+
+ aCurr=rPolyPolygons.begin();
+ while( aCurr != aEnd )
+ {
+ glBegin(GL_TRIANGLES);
+ renderComplexPolyPolygon(*aCurr++);
+ 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;
+ ::basegfx::B2DPolyPolygonVector::const_iterator aCurr=rPolyPolygons.begin();
+ const ::basegfx::B2DPolyPolygonVector::const_iterator aEnd=rPolyPolygons.end();
+ while( aCurr != aEnd )
+ aBounds.expand(::basegfx::tools::getRange(*aCurr++));
+ 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);
+
+ aCurr=rPolyPolygons.begin();
+ while( aCurr != aEnd )
+ {
+ glBegin(GL_TRIANGLES);
+ renderComplexPolyPolygon(*aCurr++);
+ glEnd();
+ }
+
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glDisable(GL_TEXTURE_2D);
+
+ return true;
+ }
+ }
+
+ CanvasHelper::CanvasHelper() :
+ mpDevice( NULL ),
+ 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 = NULL;
+ mpDeviceHelper = NULL;
+ }
+
+ void CanvasHelper::init( rendering::XGraphicDevice& rDevice,
+ SpriteDeviceHelper& rDeviceHelper )
+ {
+ mpDevice = &rDevice;
+ mpDeviceHelper = &rDeviceHelper;
+ }
+
+ void CanvasHelper::clear()
+ {
+ mpRecordedActions->clear();
+ }
+
+ void CanvasHelper::drawPoint( const rendering::XCanvas* /*pCanvas*/,
+ const geometry::RealPoint2D& aPoint,
+ const rendering::ViewState& viewState,
+ const rendering::RenderState& renderState )
+ {
+ if( mpDevice )
+ {
+ mpRecordedActions->push_back( Action() );
+ Action& rAct=mpRecordedActions->back();
+
+ setupGraphicsState( rAct, viewState, renderState );
+ rAct.maFunction = ::boost::bind(&lcl_drawPoint,
+ _1,_2,_3,_4,_5,
+ aPoint);
+ }
+ }
+
+ 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 = ::boost::bind(&lcl_drawLine,
+ _1,_2,_3,_4,_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 )
+ {
+ mpRecordedActions->push_back( Action() );
+ Action& rAct=mpRecordedActions->back();
+
+ setupGraphicsState( rAct, viewState, renderState );
+
+ // TODO(F2): subdivide&render whole curve
+ rAct.maFunction = ::boost::bind(&lcl_drawLine,
+ _1,_2,_3,_4,_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 >(NULL);
+ }
+
+ 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 >(NULL);
+ }
+
+ 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 >(NULL);
+ }
+
+ 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 >(NULL);
+ }
+
+ 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 >(NULL);
+ }
+
+ 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 >(NULL);
+ }
+
+ 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 = ::boost::bind(&lcl_fillGradientPolyPolygon,
+ _1,_2,_3,_4,
+ rValues,
+ textures[0],
+ _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 = ::boost::bind(&lcl_fillTexturedPolyPolygon,
+ _1,_2,_3,_4,
+ textures[0],
+ aSize,
+ aARGBBytes,
+ rtl_crc32(0,
+ aARGBBytes.getConstArray(),
+ aARGBBytes.getLength()),
+ _6);
+ }
+ // TODO(F1): handle non-integer case
+ }
+ }
+ }
+
+ // TODO(P1): Provide caching here.
+ return uno::Reference< rendering::XCachedPrimitive >(NULL);
+ }
+
+ 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 >(NULL);
+ }
+
+ 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 >(NULL);
+ }
+
+ 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 )
+ {
+ VirtualDevice aVDev;
+ aVDev.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();
+ ::Font aFont(
+ rFontRequest.FontDescription.FamilyName,
+ rFontRequest.FontDescription.StyleName,
+ Size( 0, ::basegfx::fround(rFontRequest.CellSize)));
+
+ aFont.SetAlign( ALIGN_BASELINE );
+ aFont.SetCharSet( (rFontRequest.FontDescription.IsSymbolFont==util::TriState_YES) ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE );
+ aFont.SetVertical( (rFontRequest.FontDescription.IsVertical==util::TriState_YES) ? true : false );
+ aFont.SetWeight( static_cast<FontWeight>(rFontRequest.FontDescription.FontDescription.Weight) );
+ aFont.SetItalic( (rFontRequest.FontDescription.FontDescription.Letterform<=8) ? ITALIC_NONE : ITALIC_NORMAL );
+
+ // adjust to stretched font
+ if(!::rtl::math::approxEqual(rFontMatrix.m00, rFontMatrix.m11))
+ {
+ const Size aSize = aVDev.GetFontMetric( aFont ).GetSize();
+ 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.SetWidth( nNewWidth );
+ }
+
+ // set font
+ aVDev.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.getLength() )
+ {
+ // create the DXArray
+ const sal_Int32 nLen( aLogicalAdvancements.getLength() );
+ ::boost::scoped_array<sal_Int32> pDXArray( new sal_Int32[nLen] );
+ for( sal_Int32 i=0; i<nLen; ++i )
+ pDXArray[i] = basegfx::fround( aLogicalAdvancements[i] );
+
+ // get the glyphs
+ aVDev.GetTextOutlines(rAct.maPolyPolys,
+ rTxt.Text,
+ 0,
+ (xub_StrLen)rTxt.StartPosition,
+ (xub_StrLen)rTxt.Length,
+ true,
+ 0,
+ pDXArray.get() );
+ }
+ else
+ {
+ // get the glyphs
+ aVDev.GetTextOutlines(rAct.maPolyPolys,
+ rTxt.Text,
+ 0,
+ (xub_StrLen)rTxt.StartPosition,
+ (xub_StrLen)rTxt.Length );
+ }
+
+ // own copy, for thread safety
+ std::for_each(rAct.maPolyPolys.begin(),
+ rAct.maPolyPolys.end(),
+ ::boost::mem_fn(&::basegfx::B2DPolyPolygon::makeUnique));
+
+ rAct.maFunction = &lcl_fillPolyPolygon;
+ }
+ }
+
+ // TODO
+ return uno::Reference< rendering::XCachedPrimitive >(NULL);
+ }
+
+ 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 = ::boost::bind(&lcl_drawOwnBitmap,
+ _1,_2,_3,_4,_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 = ::boost::bind(&lcl_drawGenericBitmap,
+ _1,_2,_3,_4,_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 >(NULL);
+ }
+
+ 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);
+ }
+
+ uno::Reference< rendering::XGraphicDevice > CanvasHelper::getDevice()
+ {
+ return uno::Reference< rendering::XGraphicDevice >(mpDevice);
+ }
+
+ 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
+ ::basegfx::B2DHomMatrix aTransform;
+ ::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:
+ // FALLTHROUGH intended - but correct?!
+ 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;
+ }
+
+ o_action.maARGBColor =
+ mpDevice->getDeviceColorSpace()->convertToARGB(renderState.DeviceColor)[0];
+ }
+
+ void CanvasHelper::flush() const
+ {
+ }
+
+ bool CanvasHelper::renderRecordedActions() const
+ {
+ std::vector<Action>::const_iterator aCurr(mpRecordedActions->begin());
+ const std::vector<Action>::const_iterator aEnd(mpRecordedActions->end());
+ while( aCurr != aEnd )
+ {
+ if( !aCurr->maFunction( *this,
+ aCurr->maTransform,
+ aCurr->meSrcBlendMode,
+ aCurr->meDstBlendMode,
+ aCurr->maARGBColor,
+ aCurr->maPolyPolys ) )
+ return false;
+
+ ++aCurr;
+ }
+
+ 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 000000000000..b7280ac1c9a1
--- /dev/null
+++ b/canvas/source/opengl/ogl_canvashelper.hxx
@@ -0,0 +1,238 @@
+/* -*- 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 OGL_CANVASHELPER_HXX_
+#define OGL_CANVASHELPER_HXX_
+
+#include <com/sun/star/rendering/XCanvas.hpp>
+
+#include <basegfx/vector/b2isize.hxx>
+#include <basegfx/vector/b2dsize.hxx>
+
+#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( ::com::sun::star::rendering::XGraphicDevice& rDevice,
+ SpriteDeviceHelper& rDeviceHelper );
+
+ // CanvasHelper functionality
+ // ==========================
+
+ // XCanvas (only providing, not implementing the
+ // interface. Also note subtle method parameter differences)
+ void clear();
+ void drawPoint( const ::com::sun::star::rendering::XCanvas* pCanvas,
+ const ::com::sun::star::geometry::RealPoint2D& aPoint,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState );
+ void drawLine( const ::com::sun::star::rendering::XCanvas* pCanvas,
+ const ::com::sun::star::geometry::RealPoint2D& aStartPoint,
+ const ::com::sun::star::geometry::RealPoint2D& aEndPoint,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState );
+ void drawBezier( const ::com::sun::star::rendering::XCanvas* pCanvas,
+ const ::com::sun::star::geometry::RealBezierSegment2D& aBezierSegment,
+ const ::com::sun::star::geometry::RealPoint2D& aEndPoint,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState );
+ ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive >
+ drawPolyPolygon( const ::com::sun::star::rendering::XCanvas* pCanvas,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState );
+ ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive >
+ strokePolyPolygon( const ::com::sun::star::rendering::XCanvas* pCanvas,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState,
+ const ::com::sun::star::rendering::StrokeAttributes& strokeAttributes );
+ ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive >
+ strokeTexturedPolyPolygon( const ::com::sun::star::rendering::XCanvas* pCanvas,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState,
+ const ::com::sun::star::uno::Sequence<
+ ::com::sun::star::rendering::Texture >& textures,
+ const ::com::sun::star::rendering::StrokeAttributes& strokeAttributes );
+ ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive >
+ strokeTextureMappedPolyPolygon( const ::com::sun::star::rendering::XCanvas* pCanvas,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState,
+ const ::com::sun::star::uno::Sequence<
+ ::com::sun::star::rendering::Texture >& textures,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::geometry::XMapping2D >& xMapping,
+ const ::com::sun::star::rendering::StrokeAttributes& strokeAttributes );
+ ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XPolyPolygon2D >
+ queryStrokeShapes( const ::com::sun::star::rendering::XCanvas* pCanvas,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState,
+ const ::com::sun::star::rendering::StrokeAttributes& strokeAttributes );
+ ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive >
+ fillPolyPolygon( const ::com::sun::star::rendering::XCanvas* pCanvas,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState );
+ ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive >
+ fillTexturedPolyPolygon( const ::com::sun::star::rendering::XCanvas* pCanvas,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState,
+ const ::com::sun::star::uno::Sequence<
+ ::com::sun::star::rendering::Texture >& textures );
+ ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive >
+ fillTextureMappedPolyPolygon( const ::com::sun::star::rendering::XCanvas* pCanvas,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState,
+ const ::com::sun::star::uno::Sequence<
+ ::com::sun::star::rendering::Texture >& textures,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::geometry::XMapping2D >& xMapping );
+
+ ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCanvasFont > SAL_CALL
+ createFont( const ::com::sun::star::rendering::XCanvas* pCanvas,
+ const ::com::sun::star::rendering::FontRequest& fontRequest,
+ const ::com::sun::star::uno::Sequence<
+ ::com::sun::star::beans::PropertyValue >& extraFontProperties,
+ const ::com::sun::star::geometry::Matrix2D& fontMatrix );
+
+ ::com::sun::star::uno::Sequence< ::com::sun::star::rendering::FontInfo >
+ queryAvailableFonts( const ::com::sun::star::rendering::XCanvas* pCanvas,
+ const ::com::sun::star::rendering::FontInfo& aFilter,
+ const ::com::sun::star::uno::Sequence<
+ ::com::sun::star::beans::PropertyValue >& aFontProperties );
+
+ ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive >
+ drawText( const ::com::sun::star::rendering::XCanvas* pCanvas,
+ const ::com::sun::star::rendering::StringContext& text,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XCanvasFont >& xFont,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState,
+ sal_Int8 textDirection );
+
+ ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive >
+ drawTextLayout( const ::com::sun::star::rendering::XCanvas* pCanvas,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XTextLayout >& layoutetText,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState );
+
+ ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive >
+ drawBitmap( const ::com::sun::star::rendering::XCanvas* pCanvas,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XBitmap >& xBitmap,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState );
+ ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive >
+ drawBitmapModulated( const ::com::sun::star::rendering::XCanvas* pCanvas,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XBitmap >& xBitmap,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState );
+ ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice >
+ getDevice();
+
+ // Flush drawing queue to screen
+ void flush() const;
+
+ /** Called from XCanvas base classes, to notify that content
+ is _about_ to change
+ */
+ void modifying() {}
+
+ /** Write out recorded actions
+ */
+ bool renderRecordedActions() const;
+
+ /** Retrieve number of recorded actions
+ */
+ size_t getRecordedActionCount() const;
+
+ SpriteDeviceHelper* getDeviceHelper() const { return mpDeviceHelper; }
+ ::com::sun::star::rendering::XGraphicDevice* getDevice() const { return mpDevice; }
+
+ struct Action;
+ typedef o3tl::cow_wrapper< std::vector<Action>,
+ o3tl::ThreadSafeRefCountingPolicy > RecordVectorT;
+
+ private:
+ // declared, but not defined
+ CanvasHelper( const CanvasHelper& );
+
+ void setupGraphicsState( Action& o_action,
+ const ::com::sun::star::rendering::ViewState& viewState,
+ const ::com::sun::star::rendering::RenderState& renderState );
+
+ /** Phyical output device
+
+ Deliberately not a refcounted reference, because of
+ potential circular references for spritecanvas.
+ */
+ ::com::sun::star::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 000000000000..a3a73dba820b
--- /dev/null
+++ b/canvas/source/opengl/ogl_canvastools.cxx
@@ -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/.
+ */
+
+#define GL_GLEXT_PROTOTYPES
+
+#include "ogl_canvastools.hxx"
+
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <basegfx/tools/canvastools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/tools/tools.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/polygon/b2dpolygontriangulator.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+
+#include <com/sun/star/rendering/ARGBColor.hpp>
+
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <GL/glext.h>
+
+
+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::B2DPolygon& rTriangulatedPolygon(
+ ::basegfx::triangulator::triangulate(aPolyPoly));
+
+ for( sal_uInt32 i=0; i<rTriangulatedPolygon.count(); i++ )
+ {
+ const ::basegfx::B2DPoint& rPt( rTriangulatedPolygon.getB2DPoint(i) );
+ const double s(rPt.getX()/nWidth);
+ const double t(rPt.getY()/nHeight);
+ glTexCoord2f(s,t); glVertex2d(rPt.getX(), rPt.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 + 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( size_t i=0; i<rNumbers.size(); ++i )
+ {
+ aTmp.identity();
+ aTmp.translate(0,y);
+ y += 1.2*scale;
+
+ basegfx::B2DPolyPolygon aPoly=
+ basegfx::tools::number2PolyPolygon(rNumbers[i],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 000000000000..458bddd1d1e6
--- /dev/null
+++ b/canvas/source/opengl/ogl_canvastools.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 OGL_CANVASTOOLS_HXX
+#define OGL_CANVASTOOLS_HXX
+
+#include <sal/config.h>
+#include <vector>
+
+namespace com { namespace sun { namespace star { namespace 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,
+ unsigned int eSrcBlend,
+ unsigned int 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 000000000000..a3d114bbbabb
--- /dev/null
+++ b/canvas/source/opengl/ogl_spritecanvas.cxx
@@ -0,0 +1,195 @@
+/* -*- 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 "ogl_spritecanvas.hxx"
+
+#include <canvas/debug.hxx>
+#include <canvas/verbosetrace.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <osl/mutex.hxx>
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/registry/XRegistryKey.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <com/sun/star/lang/NoSupportException.hpp>
+
+#include <toolkit/helper/vclunohelper.hxx>
+#include <cppuhelper/factory.hxx>
+#include <cppuhelper/implementationentry.hxx>
+#include <comphelper/servicedecl.hxx>
+
+#include "ogl_canvascustomsprite.hxx"
+
+#include <GL/gl.h>
+#include <GL/glext.h>
+
+#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 oglcanvas
+{
+ SpriteCanvas::SpriteCanvas( const uno::Sequence< uno::Any >& aArguments,
+ const uno::Reference< uno::XComponentContext >& rxContext ) :
+ maArguments(aArguments),
+ mxComponentContext( rxContext )
+ {
+ }
+
+ void SpriteCanvas::initialize()
+ {
+ // Only call initialize when not in probe mode
+ if( maArguments.getLength() == 0 )
+ return;
+
+ VERBOSE_TRACE( "SpriteCanvas::initialize called" );
+
+ /* aArguments:
+ 0: ptr to creating instance (Window or VirtualDevice)
+ 1: SystemEnvData as a streamed Any (or empty for VirtualDevice)
+ 2: current bounds of creating instance
+ 3: bool, denoting always on top state for Window (always false for VirtualDevice)
+ 4: XWindow for creating Window (or empty for VirtualDevice)
+ 5: SystemGraphicsData as a streamed Any
+ */
+ ENSURE_ARG_OR_THROW( maArguments.getLength() >= 5 &&
+ maArguments[4].getValueTypeClass() == uno::TypeClass_INTERFACE,
+ "OpenGL SpriteCanvas::initialize: wrong number of arguments, or wrong types" );
+
+ uno::Reference< awt::XWindow > xParentWindow;
+ maArguments[4] >>= xParentWindow;
+ Window* pParentWindow = VCLUnoHelper::GetWindow(xParentWindow);
+ if( !pParentWindow )
+ throw lang::NoSupportException(
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
+ "Parent window not VCL window, or canvas out-of-process!")),
+ NULL);
+
+ awt::Rectangle aRect;
+ maArguments[2] >>= aRect;
+
+ // setup helper
+ maDeviceHelper.init( *pParentWindow,
+ *this,
+ aRect );
+ maCanvasHelper.init( *this, maDeviceHelper );
+ maArguments.realloc(0);
+ }
+
+ void SAL_CALL SpriteCanvas::disposeThis()
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ mxComponentContext.clear();
+
+ // forward to parent
+ SpriteCanvasBaseT::disposeThis();
+ }
+
+ ::sal_Bool SAL_CALL SpriteCanvas::showBuffer( ::sal_Bool bUpdateAll ) throw (uno::RuntimeException)
+ {
+ ::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 ? false : SpriteCanvasBaseT::showBuffer( bUpdateAll );
+ }
+
+ ::sal_Bool SAL_CALL SpriteCanvas::switchBuffer( ::sal_Bool bUpdateAll ) throw (uno::RuntimeException)
+ {
+ ::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 ? false : SpriteCanvasBaseT::switchBuffer( bUpdateAll );
+ }
+
+ uno::Reference< rendering::XAnimatedSprite > SAL_CALL SpriteCanvas::createSpriteFromAnimation(
+ const uno::Reference< rendering::XAnimation >& /*animation*/ ) throw (lang::IllegalArgumentException,
+ uno::RuntimeException)
+ {
+ return uno::Reference< rendering::XAnimatedSprite >();
+ }
+
+ uno::Reference< rendering::XAnimatedSprite > SAL_CALL SpriteCanvas::createSpriteFromBitmaps(
+ const uno::Sequence< uno::Reference< rendering::XBitmap > >& /*animationBitmaps*/,
+ ::sal_Int8 /*interpolationMode*/ ) throw (lang::IllegalArgumentException,
+ rendering::VolatileContentDestroyedException,
+ uno::RuntimeException)
+ {
+ return uno::Reference< rendering::XAnimatedSprite >();
+ }
+
+ uno::Reference< rendering::XCustomSprite > SAL_CALL SpriteCanvas::createCustomSprite(
+ const geometry::RealSize2D& spriteSize ) throw (lang::IllegalArgumentException,
+ uno::RuntimeException)
+ {
+ return uno::Reference< rendering::XCustomSprite >(
+ new CanvasCustomSprite(spriteSize, this, maDeviceHelper) );
+ }
+
+ uno::Reference< rendering::XSprite > SAL_CALL SpriteCanvas::createClonedSprite(
+ const uno::Reference< rendering::XSprite >& /*original*/ ) throw (lang::IllegalArgumentException,
+ uno::RuntimeException)
+ {
+ return uno::Reference< rendering::XSprite >();
+ }
+
+ sal_Bool SAL_CALL SpriteCanvas::updateScreen( sal_Bool bUpdateAll ) throw (uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return maDeviceHelper.showBuffer(mbIsVisible, bUpdateAll);
+ }
+
+ ::rtl::OUString SAL_CALL SpriteCanvas::getServiceName( ) throw (uno::RuntimeException)
+ {
+ return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( 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);
+ }
+
+ bool SpriteCanvas::renderRecordedActions() const
+ {
+ return maCanvasHelper.renderRecordedActions();
+ }
+
+ static uno::Reference<uno::XInterface> initCanvas( SpriteCanvas* pCanvas )
+ {
+ uno::Reference<uno::XInterface> xRet(static_cast<cppu::OWeakObject*>(pCanvas));
+ pCanvas->initialize();
+ return xRet;
+ }
+
+ namespace sdecl = comphelper::service_decl;
+ sdecl::class_<SpriteCanvas, sdecl::with_args<true> > serviceImpl(&initCanvas);
+ const sdecl::ServiceDecl oglSpriteCanvasDecl(
+ serviceImpl,
+ SPRITECANVAS_IMPLEMENTATION_NAME,
+ SPRITECANVAS_SERVICE_NAME );
+}
+
+// The C shared lib entry points
+COMPHELPER_SERVICEDECL_EXPORTS1(oglcanvas, 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 000000000000..6efc6dbe8fb1
--- /dev/null
+++ b/canvas/source/opengl/ogl_spritecanvas.hxx
@@ -0,0 +1,118 @@
+/* -*- 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 OGL_SPRITECANVAS_HXX_
+#define 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/compbase8.hxx>
+#include <comphelper/uno3.hxx>
+
+#include <canvas/base/spritecanvasbase.hxx>
+#include <canvas/base/disambiguationhelper.hxx>
+#include <canvas/base/bufferedgraphicdevicebase.hxx>
+
+#include "ogl_spritedevicehelper.hxx"
+#include "ogl_canvashelper.hxx"
+
+
+namespace oglcanvas
+{
+ class CanvasCustomSprite;
+
+ typedef ::cppu::WeakComponentImplHelper8< ::com::sun::star::rendering::XSpriteCanvas,
+ ::com::sun::star::rendering::XGraphicDevice,
+ ::com::sun::star::lang::XMultiServiceFactory,
+ ::com::sun::star::rendering::XBufferController,
+ ::com::sun::star::awt::XWindowListener,
+ ::com::sun::star::util::XUpdatable,
+ ::com::sun::star::beans::XPropertySet,
+ ::com::sun::star::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 ::com::sun::star::uno::Sequence<
+ ::com::sun::star::uno::Any >& aArguments,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::uno::XComponentContext >& rxContext );
+
+ void initialize();
+
+ /// Dispose all internal references
+ virtual void disposeThis();
+
+ // 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 ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::sal_Bool SAL_CALL switchBuffer( ::sal_Bool bUpdateAll ) throw (::com::sun::star::uno::RuntimeException);
+
+ // XSpriteCanvas
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XAnimatedSprite > SAL_CALL createSpriteFromAnimation( const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XAnimation >& animation ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XAnimatedSprite > SAL_CALL createSpriteFromBitmaps( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmap > >& animationBitmaps, ::sal_Int8 interpolationMode ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::rendering::VolatileContentDestroyedException, ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCustomSprite > SAL_CALL createCustomSprite( const ::com::sun::star::geometry::RealSize2D& spriteSize ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XSprite > SAL_CALL createClonedSprite( const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XSprite >& original ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual ::sal_Bool SAL_CALL updateScreen( ::sal_Bool bUpdateAll ) throw (::com::sun::star::uno::RuntimeException);
+
+ // XServiceName
+ virtual ::rtl::OUString SAL_CALL getServiceName( ) throw (::com::sun::star::uno::RuntimeException);
+
+ void show( const ::rtl::Reference< CanvasCustomSprite >& );
+ void hide( const ::rtl::Reference< CanvasCustomSprite >& );
+
+ /** Write out recorded actions
+ */
+ bool renderRecordedActions() const;
+
+ private:
+ ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > maArguments;
+ ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > mxComponentContext;
+ };
+
+ 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 000000000000..cb96f2e6cf94
--- /dev/null
+++ b/canvas/source/opengl/ogl_spritedevicehelper.cxx
@@ -0,0 +1,1249 @@
+/* -*- 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 "ogl_spritedevicehelper.hxx"
+#include "ogl_spritecanvas.hxx"
+#include "ogl_canvasbitmap.hxx"
+#include "ogl_canvastools.hxx"
+#include "ogl_canvascustomsprite.hxx"
+#include "ogl_texturecache.hxx"
+
+#include <canvas/verbosetrace.hxx>
+#include <basegfx/tools/canvastools.hxx>
+#include <basegfx/tools/unopolypolygon.hxx>
+
+#include <osl/mutex.hxx>
+#include <rtl/instance.hxx>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/lang/NoSupportException.hpp>
+#include <com/sun/star/rendering/XColorSpace.hpp>
+#include <com/sun/star/rendering/XIntegerBitmapColorSpace.hpp>
+
+#include <vcl/sysdata.hxx>
+#include <vcl/syschild.hxx>
+#include <vcl/canvastools.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+
+#define GL_GLEXT_PROTOTYPES
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <GL/glext.h>
+
+namespace unx
+{
+ #include <X11/keysym.h>
+ #include <X11/X.h>
+ #include <GL/glx.h>
+ #include <GL/glxext.h>
+}
+
+
+using namespace ::com::sun::star;
+
+static bool lcl_bErrorTriggered=false;
+static int lcl_XErrorHandler( unx::Display*, unx::XErrorEvent* )
+{
+ lcl_bErrorTriggered = true;
+ return 0;
+}
+
+/** Dummy vertex processing. Simply uses default pipeline for vertex
+ transformation, and forwards texture coodinates to fragment shader
+ */
+static const char dummyVertexShader[] =
+{
+ "varying vec2 v_textureCoords2d; "
+ "void main(void) "
+ "{ "
+ " gl_Position = ftransform(); "
+ " v_textureCoords2d = gl_MultiTexCoord0.st; "
+ "} "
+};
+
+/** Two-color linear gradient
+ */
+static const char linearTwoColorGradientFragmentShader[] =
+{
+ "#version 120 \n"
+ "uniform vec4 v_startColor4d; "
+ "uniform vec4 v_endColor4d; "
+ "uniform mat3x2 m_transform; "
+ "varying vec2 v_textureCoords2d; "
+ "void main(void) "
+ "{ "
+ " gl_FragColor = mix(v_startColor4d, "
+ " v_endColor4d, "
+ " clamp( "
+ " (m_transform * vec3(v_textureCoords2d,1)).s, "
+ " 0.0, 1.0)); "
+ "} "
+};
+
+/** N-color linear gradient
+ */
+static const char linearMultiColorGradientFragmentShader[] =
+{
+ "#version 120 \n"
+ "uniform int i_nColors; "
+ "uniform sampler1D t_colorArray4d; "
+ "uniform sampler1D t_stopArray1d; "
+ "uniform mat3x2 m_transform; "
+ "varying vec2 v_textureCoords2d; "
+ " "
+ "int findBucket(float t) "
+ "{ "
+ " int nMinBucket=0; "
+ " while( nMinBucket < i_nColors && "
+ " texture1D(t_stopArray1d, nMinBucket).s < t ) "
+ " ++nMinBucket; "
+ " return max(nMinBucket-1,0); "
+ "} "
+ " "
+ "void main(void) "
+ "{ "
+ " const float fAlpha = "
+ " clamp( (m_transform * vec3(v_textureCoords2d,1)).s, "
+ " 0.0, 1.0 ); "
+ " "
+ " const int nMinBucket=findBucket( fAlpha ); "
+ " "
+ " const float fLerp = "
+ " (fAlpha-texture1D(t_stopArray1d, nMinBucket).s) / "
+ " (texture1D(t_stopArray1d, nMinBucket+1).s - "
+ " texture1D(t_stopArray1d, nMinBucket).s); "
+ " "
+ " gl_FragColor = mix(texture1D(t_colorArray4d, nMinBucket), "
+ " texture1D(t_colorArray4d, nMinBucket+1), "
+ " fLerp); "
+ "} "
+};
+
+/** Two-color radial gradient
+ */
+static const char radialTwoColorGradientFragmentShader[] =
+{
+ "#version 120 \n"
+ "uniform vec4 v_startColor4d; "
+ "uniform vec4 v_endColor4d; "
+ "uniform mat3x2 m_transform; "
+ "varying vec2 v_textureCoords2d; "
+ "const vec2 v_center2d = vec2(0,0); "
+ "void main(void) "
+ "{ "
+ " gl_FragColor = mix(v_startColor4d, "
+ " v_endColor4d, "
+ " 1.0 - distance( "
+ " vec2( "
+ " m_transform * vec3(v_textureCoords2d,1)), "
+ " v_center2d)); "
+ "} "
+};
+
+/** Multi-color radial gradient
+ */
+static const char radialMultiColorGradientFragmentShader[] =
+{
+ "#version 120 \n"
+ "uniform int i_nColors; "
+ "uniform sampler1D t_colorArray4d; "
+ "uniform sampler1D t_stopArray1d; "
+ "uniform mat3x2 m_transform; "
+ "varying vec2 v_textureCoords2d; "
+ "const vec2 v_center2d = vec2(0,0); "
+ " "
+ "int findBucket(float t) "
+ "{ "
+ " int nMinBucket=0; "
+ " while( nMinBucket < i_nColors && "
+ " texture1D(t_stopArray1d, nMinBucket).s < t ) "
+ " ++nMinBucket; "
+ " return max(nMinBucket-1,0); "
+ "} "
+ " "
+ "void main(void) "
+ "{ "
+ " const float fAlpha = "
+ " clamp( 1.0 - distance( "
+ " vec2( m_transform * vec3(v_textureCoords2d,1)), "
+ " v_center2d), "
+ " 0.0, 1.0 ); "
+ " "
+ " const int nMinBucket=findBucket( fAlpha ); "
+ " "
+ " const float fLerp = "
+ " (fAlpha-texture1D(t_stopArray1d, nMinBucket).s) / "
+ " (texture1D(t_stopArray1d, nMinBucket+1).s - "
+ " texture1D(t_stopArray1d, nMinBucket).s); "
+ " "
+ " gl_FragColor = mix(texture1D(t_colorArray4d, nMinBucket), "
+ " texture1D(t_colorArray4d, nMinBucket+1), "
+ " fLerp); "
+ "} "
+};
+
+/** Two-color rectangular gradient
+ */
+static const char rectangularTwoColorGradientFragmentShader[] =
+{
+ "#version 120 \n"
+ "uniform vec4 v_startColor4d; "
+ "uniform vec4 v_endColor4d; "
+ "uniform mat3x2 m_transform; "
+ "varying vec2 v_textureCoords2d; "
+ "void main(void) "
+ "{ "
+ " const vec2 v = abs( vec2(m_transform * vec3(v_textureCoords2d,1)) ); "
+ " const float t = max(v.x, v.y); "
+ " gl_FragColor = mix(v_startColor4d, "
+ " v_endColor4d, "
+ " 1.0-t); "
+ "} "
+};
+
+/** Multi-color rectangular gradient
+ */
+static const char rectangularMultiColorGradientFragmentShader[] =
+{
+ "#version 120 \n"
+ "uniform int i_nColors; "
+ "uniform sampler1D t_colorArray4d; "
+ "uniform sampler1D t_stopArray1d; "
+ "uniform mat3x2 m_transform; "
+ "varying vec2 v_textureCoords2d; "
+ " "
+ "int findBucket(float t) "
+ "{ "
+ " int nMinBucket=0; "
+ " while( nMinBucket < i_nColors && "
+ " texture1D(t_stopArray1d, nMinBucket).s < t ) "
+ " ++nMinBucket; "
+ " return max(nMinBucket-1,0); "
+ "} "
+ " "
+ "void main(void) "
+ "{ "
+ " const vec2 v = abs( vec2(m_transform * vec3(v_textureCoords2d,1)) ); "
+ " const float fAlpha = 1 - max(v.x, v.y); "
+ " "
+ " const int nMinBucket=findBucket( fAlpha ); "
+ " "
+ " const float fLerp = "
+ " (fAlpha-texture1D(t_stopArray1d, nMinBucket).s) / "
+ " (texture1D(t_stopArray1d, nMinBucket+1).s - "
+ " texture1D(t_stopArray1d, nMinBucket).s); "
+ " "
+ " gl_FragColor = mix(texture1D(t_colorArray4d, nMinBucket), "
+ " texture1D(t_colorArray4d, nMinBucket+1), "
+ " fLerp); "
+ "} "
+};
+
+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, bool bMirror=false)
+{
+ // use whole window
+ glViewport( 0,0,
+ (GLsizei)rSize.Width(),
+ (GLsizei)rSize.Height() );
+
+ // model coordinate system is already in device pixel
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslated(-1.0, (bMirror ? -1.0 : 1.0), 0.0);
+ glScaled( 2.0 / rSize.Width(),
+ (bMirror ? 2.0 : -2.0) / rSize.Height(),
+ 1.0 );
+
+ // clear to black
+ glClearColor(0,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+}
+
+static boost::shared_ptr<SystemChildWindow> createChildWindow( unx::XVisualInfo*& viWin,
+ unx::XVisualInfo*& viPB,
+ void*& fbConfig,
+ Window& rWindow,
+ unx::Display* pDisplay,
+ int nScreen )
+{
+ // select appropriate visual
+ static int winAttrList3[] =
+ {
+ GLX_RGBA,//only TrueColor or DirectColor
+ //single buffered
+ GLX_RED_SIZE,4,//use the maximum red bits, with a minimum of 4 bits
+ GLX_GREEN_SIZE,4,//use the maximum green bits, with a minimum of 4 bits
+ GLX_BLUE_SIZE,4,//use the maximum blue bits, with a minimum of 4 bits
+ GLX_DEPTH_SIZE,0,//no depth buffer
+ None
+ };
+ static int pBufAttrList3[] =
+ {
+ GLX_DOUBLEBUFFER,False,// never doublebuffer pbuffer
+ GLX_RED_SIZE,4,//use the maximum red bits, with a minimum of 4 bits
+ GLX_GREEN_SIZE,4,//use the maximum green bits, with a minimum of 4 bits
+ GLX_BLUE_SIZE,4,//use the maximum blue bits, with a minimum of 4 bits
+ GLX_ALPHA_SIZE,4,
+ GLX_DEPTH_SIZE,0,//no depth buffer
+ GLX_RENDER_TYPE, GLX_RGBA_BIT,
+ GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT,
+ None
+ };
+ static int winAttrList2[] =
+ {
+ GLX_RGBA,//only TrueColor or DirectColor
+ /// single buffered
+ GLX_RED_SIZE,4,/// use the maximum red bits, with a minimum of 4 bits
+ GLX_GREEN_SIZE,4,/// use the maximum green bits, with a minimum of 4 bits
+ GLX_BLUE_SIZE,4,/// use the maximum blue bits, with a minimum of 4 bits
+ GLX_DEPTH_SIZE,1,/// use the maximum depth bits, making sure there is a depth buffer
+ None
+ };
+ static int pBufAttrList2[] =
+ {
+ GLX_DOUBLEBUFFER,False,// never doublebuffer pbuffer
+ GLX_RED_SIZE,4,/// use the maximum red bits, with a minimum of 4 bits
+ GLX_GREEN_SIZE,4,/// use the maximum green bits, with a minimum of 4 bits
+ GLX_BLUE_SIZE,4,/// use the maximum blue bits, with a minimum of 4 bits
+ GLX_ALPHA_SIZE,4,
+ GLX_DEPTH_SIZE,1,/// use the maximum depth bits, making sure there is a depth buffer
+ GLX_RENDER_TYPE, GLX_RGBA_BIT,
+ GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT,
+ None
+ };
+ static int winAttrList1[] =
+ {
+ GLX_RGBA,//only TrueColor or DirectColor
+ GLX_DOUBLEBUFFER,/// only double buffer
+ GLX_RED_SIZE,4,/// use the maximum red bits, with a minimum of 4 bits
+ GLX_GREEN_SIZE,4,/// use the maximum green bits, with a minimum of 4 bits
+ GLX_BLUE_SIZE,4,/// use the maximum blue bits, with a minimum of 4 bits
+ GLX_DEPTH_SIZE,0,/// no depth buffer
+ None
+ };
+ static int pBufAttrList1[] =
+ {
+ GLX_DOUBLEBUFFER,False,// never doublebuffer pbuffer
+ GLX_RED_SIZE,4,/// use the maximum red bits, with a minimum of 4 bits
+ GLX_GREEN_SIZE,4,/// use the maximum green bits, with a minimum of 4 bits
+ GLX_BLUE_SIZE,4,/// use the maximum blue bits, with a minimum of 4 bits
+ GLX_ALPHA_SIZE,4,
+ GLX_DEPTH_SIZE,0,/// no depth buffer
+ GLX_RENDER_TYPE, GLX_RGBA_BIT,
+ GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT,
+ None
+ };
+ static int winAttrList0[] =
+ {
+ GLX_RGBA,//only TrueColor or DirectColor
+ GLX_DOUBLEBUFFER,// only double buffer
+ GLX_RED_SIZE,4,// use the maximum red bits, with a minimum of 4 bits
+ GLX_GREEN_SIZE,4,// use the maximum green bits, with a minimum of 4 bits
+ GLX_BLUE_SIZE,4,// use the maximum blue bits, with a minimum of 4 bits
+ GLX_DEPTH_SIZE,1,// use the maximum depth bits, making sure there is a depth buffer
+ None
+ };
+ static int pBufAttrList0[] =
+ {
+ GLX_DOUBLEBUFFER,False,// never doublebuffer pbuffer
+ GLX_RED_SIZE,4,// use the maximum red bits, with a minimum of 4 bits
+ GLX_GREEN_SIZE,4,// use the maximum green bits, with a minimum of 4 bits
+ GLX_BLUE_SIZE,4,// use the maximum blue bits, with a minimum of 4 bits
+ GLX_ALPHA_SIZE,4,
+ GLX_DEPTH_SIZE,1,// use the maximum depth bits, making sure there is a depth buffer
+ GLX_RENDER_TYPE, GLX_RGBA_BIT,
+ GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT,
+ None
+ };
+ static int* winAttrTable[] =
+ {
+ winAttrList0,
+ winAttrList1,
+ winAttrList2,
+ winAttrList3,
+ NULL
+ };
+ static int* pBufAttrTable[] =
+ {
+ pBufAttrList0,
+ pBufAttrList1,
+ pBufAttrList2,
+ pBufAttrList3,
+ NULL
+ };
+ int** pWinAttributeTable = winAttrTable;
+ int** pBufAttributeTable = pBufAttrTable;
+
+ boost::shared_ptr<SystemChildWindow> pResult;
+ unx::GLXFBConfig* fbConfigs=NULL;
+ int nConfigs, nVal;
+ while( *pWinAttributeTable && *pBufAttributeTable )
+ {
+ // try to find a window visual for the current set of
+ // attributes
+ viWin = unx::glXChooseVisual( pDisplay,
+ nScreen,
+ *pWinAttributeTable );
+ if( viWin )
+ {
+ // try to find a framebuffer config for the current set of
+ // attributes
+ fbConfigs = glXChooseFBConfig( pDisplay,
+ nScreen,
+ *pBufAttributeTable,
+ &nConfigs );
+ // don't use glXGetFBConfigs, that does not list alpha-configs
+ // fbConfigs = unx::glXGetFBConfigs(pDisplay, nScreen, &nConfigs);
+ for(int i=0; i<nConfigs; i++)
+ {
+ viPB = glXGetVisualFromFBConfig(pDisplay, fbConfigs[i]);
+ if( viPB && viPB->visualid != viWin->visualid )
+ {
+ glXGetFBConfigAttrib(pDisplay,
+ fbConfigs[i],
+ GLX_DRAWABLE_TYPE,
+ &nVal);
+
+ if( (GLX_PBUFFER_BIT|GLX_WINDOW_BIT|GLX_PIXMAP_BIT)
+ == (nVal & (GLX_PBUFFER_BIT|GLX_WINDOW_BIT|GLX_PIXMAP_BIT)) )
+ {
+ SystemWindowData winData;
+ winData.nSize = sizeof(winData);
+ SAL_INFO("canvas.ogl", "using VisualID " << viWin->visualid << " for OpenGL canvas");
+ winData.pVisual = (void*)(viWin->visual);
+ pResult.reset( new SystemChildWindow(&rWindow, 0, &winData, false) );
+
+ if( pResult->GetSystemData() )
+ {
+ fbConfig = &fbConfigs[i];
+ return pResult;
+ }
+
+ pResult.reset();
+ }
+
+ XFree(viPB);
+ }
+ }
+
+ XFree(viWin);
+ }
+
+ ++pWinAttributeTable;
+ ++pBufAttributeTable;
+ }
+
+ return pResult;
+}
+
+
+namespace oglcanvas
+{
+ /** Compile shader program
+
+ Code courtesy rodo
+ */
+ void SpriteDeviceHelper::compileShader(unsigned int& o_rShaderHandle,
+ unsigned int eShaderType,
+ const char* pShaderSourceCode)
+ {
+ GLint nCompileStatus;
+ char log[1024];
+
+ o_rShaderHandle = glCreateShader( eShaderType );
+ glShaderSource( o_rShaderHandle, 1, &pShaderSourceCode, NULL );
+ glCompileShader( o_rShaderHandle );
+ glGetShaderInfoLog( o_rShaderHandle, sizeof(log), NULL, log );
+ SAL_INFO("canvas.ogl", "shader compile log: " << log);
+
+ glGetShaderiv( o_rShaderHandle, GL_COMPILE_STATUS, &nCompileStatus );
+ if( !nCompileStatus )
+ {
+ glDeleteShader(o_rShaderHandle);
+ o_rShaderHandle=0;
+ }
+ }
+
+ /** Link vertex & fragment shaders
+
+ Code courtesy rodo
+ */
+ void SpriteDeviceHelper::linkShaders(unsigned int& o_rProgramHandle,
+ unsigned int nVertexProgramId,
+ unsigned int nFragmentProgramId)
+ {
+ if( !nVertexProgramId || !nFragmentProgramId )
+ return;
+
+ o_rProgramHandle = glCreateProgram();
+ glAttachShader( o_rProgramHandle, nVertexProgramId );
+ glAttachShader( o_rProgramHandle, nFragmentProgramId );
+
+ char log[1024];
+ GLint nProgramLinked;
+
+ glLinkProgram( o_rProgramHandle );
+ glGetProgramInfoLog( o_rProgramHandle, sizeof(log), NULL, log );
+ SAL_INFO("canvas.ogl", "shader program link log: " << log);
+ glGetProgramiv( o_rProgramHandle, GL_LINK_STATUS, &nProgramLinked );
+
+ if( !nProgramLinked )
+ {
+ glDeleteProgram(o_rProgramHandle);
+ o_rProgramHandle=0;
+ }
+ }
+
+ SpriteDeviceHelper::SpriteDeviceHelper() :
+ mpDevice(NULL),
+ mpSpriteCanvas(NULL),
+ maActiveSprites(),
+ maLastUpdate(),
+ mpChildWindow(),
+ mpDisplay(NULL),
+ mpGLContext(NULL),
+ mpGLPBufContext(NULL),
+ mpFBConfig(NULL),
+ mpTextureCache(new TextureCache()),
+ mnDummyVertexProgram(0),
+ mnLinearTwoColorGradientFragmentProgram(0),
+ mnLinearMultiColorGradientFragmentProgram(0),
+ mnRadialTwoColorGradientFragmentProgram(0),
+ mnRadialMultiColorGradientFragmentProgram(0),
+ mnRectangularTwoColorGradientFragmentProgram(0),
+ mnRectangularMultiColorGradientFragmentProgram(0),
+ mnLinearTwoColorGradientProgram(0),
+ mnLinearMultiColorGradientProgram(0),
+ mnRadialTwoColorGradientProgram(0),
+ mnRadialMultiColorGradientProgram(0),
+ mnRectangularTwoColorGradientProgram(0),
+ mnRectangularMultiColorGradientProgram(0)
+ {}
+
+ void SpriteDeviceHelper::init( Window& rWindow,
+ SpriteCanvas& rSpriteCanvas,
+ const awt::Rectangle& rViewArea )
+ {
+ mpSpriteCanvas = &rSpriteCanvas;
+
+ rSpriteCanvas.setWindow(
+ uno::Reference<awt::XWindow2>(
+ VCLUnoHelper::GetInterface(&rWindow),
+ uno::UNO_QUERY_THROW) );
+
+ // init OpenGL
+ const SystemEnvData* sysData(rWindow.GetSystemData());
+ unx::Display* pDisplay=reinterpret_cast<unx::Display*>(sysData->pDisplay);
+ mpDisplay=pDisplay;
+ if( !unx::glXQueryExtension(pDisplay, NULL, NULL) )
+ return;
+
+ unx::Window xWindow = sysData->aWindow;
+ unx::XWindowAttributes xAttr;
+ unx::XGetWindowAttributes( pDisplay, xWindow, &xAttr );
+ int nScreen = XScreenNumberOfScreen( xAttr.screen );
+
+ unx::Window childXWindow=0;
+ unx::XVisualInfo* viWin=NULL;
+ unx::XVisualInfo* viPB=NULL;
+ mpChildWindow=createChildWindow(viWin,viPB,mpFBConfig,
+ rWindow,pDisplay,nScreen);
+
+ // tweak SysChild window to act as an input-transparent
+ // overlay
+ if( mpChildWindow )
+ {
+ childXWindow=mpChildWindow->GetSystemData()->aWindow;
+ mpChildWindow->SetMouseTransparent(true);
+ mpChildWindow->SetParentClipMode( PARENTCLIPMODE_NOCLIP );
+ mpChildWindow->EnableEraseBackground(false);
+ mpChildWindow->SetControlForeground();
+ mpChildWindow->SetControlBackground();
+ mpChildWindow->EnablePaint(false);
+
+ unx::GLXContext pContext1 =
+ glXCreateContext(pDisplay,
+ viWin,
+ 0,
+ GL_TRUE);
+ mpGLContext = pContext1;
+
+ unx::GLXContext pContext2 =
+ glXCreateContext( pDisplay,
+ viPB,
+ pContext1,
+ GL_TRUE );
+ mpGLPBufContext = pContext2;
+
+ XFree(viWin);
+ XFree(viPB);
+
+ if( !glXMakeCurrent( pDisplay,
+ childXWindow,
+ pContext1) )
+ {
+ glXDestroyContext(pDisplay, pContext1);
+ glXDestroyContext(pDisplay, pContext2);
+ throw lang::NoSupportException(
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
+ "Could not select OpenGL context!") ),NULL);
+ }
+
+ const GLubyte* extensions=glGetString( GL_EXTENSIONS );
+ if( gluCheckExtension((const GLubyte*)"GLX_SGI_swap_control", extensions) )
+ {
+ // try to enable vsync
+ typedef GLint (*glXSwapIntervalProc)(GLint);
+ glXSwapIntervalProc glXSwapInterval =
+ (glXSwapIntervalProc) unx::glXGetProcAddress((const GLubyte*)"glXSwapIntervalSGI");
+ if( glXSwapInterval )
+ {
+ int (*oldHandler)(unx::Display*, unx::XErrorEvent*);
+
+ // synchronize on global mutex - no other ogl
+ // canvas instance permitted to enter here
+ {
+ ::osl::MutexGuard aGuard( *::osl::Mutex::getGlobalMutex() );
+
+ // replace error handler temporarily
+ oldHandler = unx::XSetErrorHandler( lcl_XErrorHandler );
+
+ lcl_bErrorTriggered = false;
+
+ // Note: if this fails, so be it. Buggy
+ // drivers will then not have vsync.
+ glXSwapInterval(1);
+
+ // sync so that we possibly get an XError
+ unx::glXWaitGL();
+ XSync(pDisplay, false);
+
+ unx::XSetErrorHandler( oldHandler );
+ }
+ }
+ }
+
+ // init window context
+ initContext();
+
+ // compile & link shaders - code courtesy rodo
+ compileShader(mnDummyVertexProgram,
+ GL_VERTEX_SHADER,
+ dummyVertexShader);
+ compileShader(mnLinearTwoColorGradientFragmentProgram,
+ GL_FRAGMENT_SHADER,
+ linearTwoColorGradientFragmentShader);
+ compileShader(mnLinearMultiColorGradientFragmentProgram,
+ GL_FRAGMENT_SHADER,
+ linearMultiColorGradientFragmentShader);
+ compileShader(mnRadialTwoColorGradientFragmentProgram,
+ GL_FRAGMENT_SHADER,
+ radialTwoColorGradientFragmentShader);
+ compileShader(mnRadialMultiColorGradientFragmentProgram,
+ GL_FRAGMENT_SHADER,
+ radialMultiColorGradientFragmentShader);
+ compileShader(mnRectangularTwoColorGradientFragmentProgram,
+ GL_FRAGMENT_SHADER,
+ rectangularTwoColorGradientFragmentShader);
+ compileShader(mnRectangularMultiColorGradientFragmentProgram,
+ GL_FRAGMENT_SHADER,
+ rectangularMultiColorGradientFragmentShader);
+ linkShaders(mnLinearTwoColorGradientProgram,
+ mnDummyVertexProgram,
+ mnLinearTwoColorGradientFragmentProgram);
+ linkShaders(mnLinearMultiColorGradientProgram,
+ mnDummyVertexProgram,
+ mnLinearMultiColorGradientFragmentProgram);
+ linkShaders(mnRadialTwoColorGradientProgram,
+ mnDummyVertexProgram,
+ mnRadialTwoColorGradientFragmentProgram);
+ linkShaders(mnRadialMultiColorGradientProgram,
+ mnDummyVertexProgram,
+ mnRadialMultiColorGradientFragmentProgram);
+ linkShaders(mnRectangularTwoColorGradientProgram,
+ mnDummyVertexProgram,
+ mnRectangularTwoColorGradientFragmentProgram);
+ linkShaders(mnRectangularMultiColorGradientProgram,
+ mnDummyVertexProgram,
+ mnRectangularMultiColorGradientFragmentProgram);
+
+ glXMakeCurrent(pDisplay, None, NULL);
+ }
+
+ if( !mpGLContext || glGetError() != GL_NO_ERROR )
+ throw lang::NoSupportException(
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
+ "Could not create OpenGL context, or an error occurred doing so!") ),NULL);
+
+ notifySizeUpdate(rViewArea);
+ mpChildWindow->Show();
+ // TODO(E3): check for GL_ARB_imaging extension
+ }
+
+ void SpriteDeviceHelper::disposing()
+ {
+ // release all references
+ mpSpriteCanvas = NULL;
+ mpDevice = NULL;
+ mpTextureCache.reset();
+
+ if( mpGLContext )
+ {
+ glDeleteProgram( mnRectangularTwoColorGradientProgram );
+ glDeleteProgram( mnRectangularMultiColorGradientProgram );
+ glDeleteProgram( mnRadialTwoColorGradientProgram );
+ glDeleteProgram( mnRadialMultiColorGradientProgram );
+ glDeleteProgram( mnLinearTwoColorGradientProgram );
+ glDeleteProgram( mnLinearMultiColorGradientProgram );
+ glDeleteShader( mnRectangularTwoColorGradientFragmentProgram );
+ glDeleteShader( mnRectangularMultiColorGradientFragmentProgram );
+ glDeleteShader( mnRadialTwoColorGradientFragmentProgram );
+ glDeleteShader( mnRadialMultiColorGradientFragmentProgram );
+ glDeleteShader( mnLinearTwoColorGradientFragmentProgram );
+ glDeleteShader( mnLinearMultiColorGradientFragmentProgram );
+ glDeleteShader( mnDummyVertexProgram );
+
+ glXDestroyContext(reinterpret_cast<unx::Display*>(mpDisplay),
+ reinterpret_cast<unx::GLXContext>(mpGLContext));
+ }
+
+ mpDisplay = NULL;
+ mpGLContext = NULL;
+ mpChildWindow.reset();
+ }
+
+ geometry::RealSize2D SpriteDeviceHelper::getPhysicalResolution()
+ {
+ if( !mpChildWindow )
+ return ::canvas::tools::createInfiniteSize2D(); // we're disposed
+
+ // Map a one-by-one millimeter box to pixel
+ const MapMode aOldMapMode( mpChildWindow->GetMapMode() );
+ mpChildWindow->SetMapMode( MapMode(MAP_MM) );
+ const Size aPixelSize( mpChildWindow->LogicToPixel(Size(1,1)) );
+ mpChildWindow->SetMapMode( aOldMapMode );
+
+ return ::vcl::unotools::size2DFromSize( aPixelSize );
+ }
+
+ geometry::RealSize2D SpriteDeviceHelper::getPhysicalSize()
+ {
+ if( !mpChildWindow )
+ return ::canvas::tools::createInfiniteSize2D(); // we're disposed
+
+ // Map the pixel dimensions of the output window to millimeter
+ const MapMode aOldMapMode( mpChildWindow->GetMapMode() );
+ mpChildWindow->SetMapMode( MapMode(MAP_MM) );
+ const Size aLogSize( mpChildWindow->PixelToLogic(mpChildWindow->GetOutputSizePixel()) );
+ mpChildWindow->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,
+ false ) );
+ }
+
+ 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,
+ true ) );
+ }
+
+ uno::Reference< rendering::XVolatileBitmap > SpriteDeviceHelper::createVolatileAlphaBitmap(
+ const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/,
+ const geometry::IntegerSize2D& /*size*/ )
+ {
+ return uno::Reference< rendering::XVolatileBitmap >();
+ }
+
+ sal_Bool SpriteDeviceHelper::hasFullScreenMode()
+ {
+ // TODO(F3): offer fullscreen mode the XCanvas way
+ return false;
+ }
+
+ sal_Bool SpriteDeviceHelper::enterFullScreenMode( sal_Bool /*bEnter*/ )
+ {
+ // TODO(F3): offer fullscreen mode the XCanvas way
+ return false;
+ }
+
+ ::sal_Int32 SpriteDeviceHelper::createBuffers( ::sal_Int32 /*nBuffers*/ )
+ {
+ // TODO(F3): implement XBufferStrategy interface. For now, we
+ // _always_ will have exactly one backbuffer
+ return 1;
+ }
+
+ void SpriteDeviceHelper::destroyBuffers()
+ {
+ // TODO(F3): implement XBufferStrategy interface. For now, we
+ // _always_ will have exactly one backbuffer
+ }
+
+ 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;
+ }
+ };
+ }
+
+ ::sal_Bool SpriteDeviceHelper::showBuffer( bool bIsVisible, ::sal_Bool /*bUpdateAll*/ )
+ {
+ // hidden or disposed?
+ if( !bIsVisible || !mpChildWindow || !mpSpriteCanvas )
+ return false;
+
+ if( !activateWindowContext() )
+ return false;
+
+ const ::Size& rOutputSize=mpChildWindow->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());
+ std::for_each(aSprites.begin(),
+ aSprites.end(),
+ boost::mem_fn(&CanvasCustomSprite::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 );
+
+ // switch buffer, sync etc.
+ const unx::Window aXWindow=mpChildWindow->GetSystemData()->aWindow;
+ unx::glXSwapBuffers(reinterpret_cast<unx::Display*>(mpDisplay),
+ aXWindow);
+ mpChildWindow->Show();
+ unx::glXWaitGL();
+ XSync( reinterpret_cast<unx::Display*>(mpDisplay), false );
+
+ // 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;
+ }
+
+ ::sal_Bool SpriteDeviceHelper::switchBuffer( bool bIsVisible, ::sal_Bool bUpdateAll )
+ {
+ // no difference for VCL canvas
+ return showBuffer( bIsVisible, bUpdateAll );
+ }
+
+ uno::Any SpriteDeviceHelper::isAccelerated() const
+ {
+ return ::com::sun::star::uno::makeAny(false);
+ }
+
+ uno::Any SpriteDeviceHelper::getDeviceHandle() const
+ {
+ return uno::Any();
+ }
+
+ uno::Any SpriteDeviceHelper::getSurfaceHandle() const
+ {
+ return uno::Any();
+ }
+
+ uno::Reference<rendering::XColorSpace> SpriteDeviceHelper::getColorSpace() const
+ {
+ // always the same
+ return uno::Reference<rendering::XColorSpace>(
+ ::canvas::tools::getStdColorSpace(),
+ uno::UNO_QUERY);
+ }
+
+ void SpriteDeviceHelper::notifySizeUpdate( const awt::Rectangle& rBounds )
+ {
+ if( mpChildWindow )
+ mpChildWindow->setPosSizePixel(
+ 0,0,rBounds.Width,rBounds.Height);
+ }
+
+ void SpriteDeviceHelper::dumpScreenContent() const
+ {
+ SAL_INFO("canvas.ogl", BOOST_CURRENT_FUNCTION );
+ }
+
+ 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);
+ }
+
+ bool SpriteDeviceHelper::activatePBufferContext(const ::basegfx::B2IVector& rSize,
+ unsigned int PBuffer) const
+ {
+ if( !glXMakeCurrent( reinterpret_cast<unx::Display*>(mpDisplay),
+ PBuffer,
+ reinterpret_cast<unx::GLXContext>(mpGLPBufContext)) )
+ {
+ SAL_INFO("canvas.ogl", "SpriteDeviceHelper::activatePBufferContext(): cannot activate GL context");
+ return false;
+ }
+
+ initContext();
+ initTransformation(
+ ::Size(
+ rSize.getX(),
+ rSize.getY()),
+ true);
+
+ return true;
+ }
+
+ bool SpriteDeviceHelper::activateWindowContext() const
+ {
+ const unx::Window aXWindow=mpChildWindow->GetSystemData()->aWindow;
+ if( !glXMakeCurrent( reinterpret_cast<unx::Display*>(mpDisplay),
+ aXWindow,
+ reinterpret_cast<unx::GLXContext>(mpGLContext)) )
+ {
+ SAL_INFO("canvas.ogl", "SpriteDeviceHelper::activateWindowContext(): cannot activate GL context");
+ return false;
+ }
+
+ return true;
+ }
+
+ bool SpriteDeviceHelper::updatePBufferTexture( const ::basegfx::B2IVector& rSize,
+ unsigned int nTextId ) const
+ {
+ glBindTexture( GL_TEXTURE_2D, nTextId );
+ glEnable(GL_TEXTURE_2D);
+ glCopyTexSubImage2D( GL_TEXTURE_2D,
+ 0, 0, 0, 0, 0,
+ rSize.getX(),
+ rSize.getY() );
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ return true;
+ }
+
+ namespace
+ {
+ class BufferContextImpl : public IBufferContext
+ {
+ ::basegfx::B2IVector maSize;
+ const SpriteDeviceHelper& mrDeviceHelper;
+ unx::GLXPbuffer mpPBuffer;
+ unx::Display* mpDisplay;
+ unsigned int mnTexture;
+
+ virtual bool startBufferRendering()
+ {
+ return mrDeviceHelper.activatePBufferContext(maSize,mpPBuffer);
+ }
+
+ virtual bool endBufferRendering()
+ {
+ mrDeviceHelper.updatePBufferTexture(maSize,mnTexture);
+ if( !mrDeviceHelper.activateWindowContext() )
+ return false;
+
+ glBindTexture( GL_TEXTURE_2D, mnTexture );
+
+ return true;
+ }
+
+ public:
+ BufferContextImpl(const SpriteDeviceHelper& rDeviceHelper,
+ unx::GLXPbuffer pBuffer,
+ unx::Display* pDisplay,
+ const ::basegfx::B2IVector& rSize) :
+ maSize(rSize),
+ mrDeviceHelper(rDeviceHelper),
+ mpPBuffer(pBuffer),
+ mpDisplay(pDisplay),
+ mnTexture(0)
+ {
+ glGenTextures( 1, &mnTexture );
+#if 1
+ glBindTexture( GL_TEXTURE_2D, mnTexture );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA,
+ maSize.getX(), maSize.getY(),
+ 0, GL_RGBA, GL_UNSIGNED_BYTE, new int[maSize.getX()*maSize.getY()] );
+#endif
+ }
+
+ ~BufferContextImpl()
+ {
+#if 0
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glDeleteTextures( 1, &mnTexture );
+ glXDestroyPbuffer( mpDisplay, mpPBuffer );
+#endif
+ }
+ };
+ }
+
+ IBufferContextSharedPtr SpriteDeviceHelper::createBufferContext(const ::basegfx::B2IVector& rSize) const
+ {
+ int pBufAttribs[] =
+ {
+ GLX_PBUFFER_WIDTH, rSize.getX(),
+ GLX_PBUFFER_HEIGHT, rSize.getY(),
+ GLX_LARGEST_PBUFFER, False,
+ None
+ };
+
+ unx::GLXPbuffer pBuffer;
+ pBuffer = unx::glXCreatePbuffer( reinterpret_cast<unx::Display*>(mpDisplay),
+ *reinterpret_cast<unx::GLXFBConfig*>(mpFBConfig),
+ pBufAttribs );
+
+ IBufferContextSharedPtr pRet;
+ if( pBuffer )
+ pRet.reset(new BufferContextImpl(
+ *this,
+ pBuffer,
+ reinterpret_cast<unx::Display*>(mpDisplay),
+ rSize));
+
+ return pRet;
+ }
+
+ 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 000000000000..c87bdf84d18f
--- /dev/null
+++ b/canvas/source/opengl/ogl_spritedevicehelper.hxx
@@ -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/.
+ */
+
+#ifndef OGL_SPRITEDEVICEHELPER_HXX
+#define OGL_SPRITEDEVICEHELPER_HXX
+
+#include <rtl/ref.hxx>
+#include <canvas/elapsedtime.hxx>
+#include <com/sun/star/rendering/XGraphicDevice.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include "ogl_buffercontext.hxx"
+
+#include <set>
+
+
+class Window;
+class SystemChildWindow;
+namespace basegfx{ class B2IVector; class B2DHomMatrix; }
+namespace com { namespace sun { namespace star {
+ namespace awt { struct Rectangle; }
+ namespace geometry { struct AffineMatrix2D; }
+}}}
+
+namespace oglcanvas
+{
+ class TextureCache;
+ class SpriteCanvas;
+ class CanvasCustomSprite;
+ class CanvasHelper;
+
+ class SpriteDeviceHelper : private ::boost::noncopyable
+ {
+ public:
+ SpriteDeviceHelper();
+
+ void init( Window& rWindow,
+ SpriteCanvas& rSpriteCanvas,
+ const ::com::sun::star::awt::Rectangle& rViewArea );
+
+ /// Dispose all internal references
+ void disposing();
+
+ // XWindowGraphicDevice
+ ::com::sun::star::geometry::RealSize2D getPhysicalResolution();
+ ::com::sun::star::geometry::RealSize2D getPhysicalSize();
+ ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XLinePolyPolygon2D > createCompatibleLinePolyPolygon(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice >& rDevice,
+ const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::geometry::RealPoint2D > >& points );
+ ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBezierPolyPolygon2D > createCompatibleBezierPolyPolygon(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice >& rDevice,
+ const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::geometry::RealBezierSegment2D > >& points );
+ ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmap > createCompatibleBitmap(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice >& rDevice,
+ const ::com::sun::star::geometry::IntegerSize2D& size );
+ ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XVolatileBitmap > createVolatileBitmap(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice >& rDevice,
+ const ::com::sun::star::geometry::IntegerSize2D& size );
+ ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmap > createCompatibleAlphaBitmap(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice >& rDevice,
+ const ::com::sun::star::geometry::IntegerSize2D& size );
+ ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XVolatileBitmap > createVolatileAlphaBitmap(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice >& rDevice,
+ const ::com::sun::star::geometry::IntegerSize2D& size );
+
+ sal_Bool hasFullScreenMode( );
+ sal_Bool enterFullScreenMode( sal_Bool bEnter );
+
+ ::sal_Int32 createBuffers( ::sal_Int32 nBuffers );
+ void destroyBuffers( );
+ ::sal_Bool showBuffer( bool bIsVisible, ::sal_Bool bUpdateAll );
+ ::sal_Bool switchBuffer( bool bIsVisible, ::sal_Bool bUpdateAll );
+
+ ::com::sun::star::uno::Any isAccelerated() const;
+ ::com::sun::star::uno::Any getDeviceHandle() const;
+ ::com::sun::star::uno::Any getSurfaceHandle() const;
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XColorSpace > getColorSpace() const;
+
+ void notifySizeUpdate( const ::com::sun::star::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 ::com::sun::star::rendering::ARGBColor* pColors,
+ const ::com::sun::star::uno::Sequence< double >& rStops,
+ const ::basegfx::B2DHomMatrix& rTexTransform );
+ /// enable radial gradient shader "texture" with given parameters
+ void useRadialGradientShader( const ::com::sun::star::rendering::ARGBColor* pColors,
+ const ::com::sun::star::uno::Sequence< double >& rStops,
+ const ::basegfx::B2DHomMatrix& rTexTransform );
+ /// enable rectangular gradient shader "texture" with given parameters
+ void useRectangularGradientShader( const ::com::sun::star::rendering::ARGBColor* pColors,
+ const ::com::sun::star::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;
+
+ ////////////////////////////////////////////////////////
+
+ // nobody except IBufferContext implementations are supposed
+ // to use this
+ bool activatePBufferContext(const ::basegfx::B2IVector& rSize,
+ unsigned int PBuffer) const;
+ bool activateWindowContext() const;
+ bool updatePBufferTexture( const ::basegfx::B2IVector&,
+ unsigned int ) const;
+
+ private:
+ void resize( const ::basegfx::B2IVector& rNewSize );
+
+ void compileShader(unsigned int& o_rShaderHandle,
+ unsigned int eShaderType,
+ const char* pShaderSourceCode);
+ void linkShaders(unsigned int& o_rProgramHandle,
+ unsigned int nVertexProgramId,
+ unsigned int nFragmentProgramId);
+
+ /** Phyical output device
+
+ Deliberately not a refcounted reference, because of
+ potential circular references for canvas. Needed to
+ create bitmaps
+ */
+ com::sun::star::rendering::XGraphicDevice* mpDevice;
+
+ /// 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;
+
+ boost::shared_ptr<SystemChildWindow> mpChildWindow;
+ void* mpDisplay;
+ void* mpGLContext;
+ void* mpGLPBufContext;
+ void* mpFBConfig;
+
+ boost::shared_ptr<TextureCache> mpTextureCache;
+
+ unsigned int mnDummyVertexProgram;
+
+ unsigned int mnLinearTwoColorGradientFragmentProgram;
+ unsigned int mnLinearMultiColorGradientFragmentProgram;
+ unsigned int mnRadialTwoColorGradientFragmentProgram;
+ unsigned int mnRadialMultiColorGradientFragmentProgram;
+ unsigned int mnRectangularTwoColorGradientFragmentProgram;
+ unsigned int mnRectangularMultiColorGradientFragmentProgram;
+ unsigned int mnLinearTwoColorGradientProgram;
+ unsigned int mnLinearMultiColorGradientProgram;
+ unsigned int mnRadialTwoColorGradientProgram;
+ unsigned int mnRadialMultiColorGradientProgram;
+ unsigned int mnRectangularTwoColorGradientProgram;
+ unsigned int mnRectangularMultiColorGradientProgram;
+ };
+}
+
+#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 000000000000..42f8d97221ea
--- /dev/null
+++ b/canvas/source/opengl/ogl_textlayout.cxx
@@ -0,0 +1,215 @@
+/* -*- 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 "ogl_textlayout.hxx"
+
+#include <canvas/debug.hxx>
+#include <canvas/verbosetrace.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/numeric/ftools.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.reset();
+ }
+
+ // XTextLayout
+ uno::Sequence< uno::Reference< rendering::XPolyPolygon2D > > SAL_CALL TextLayout::queryTextShapes( ) throw (uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // TODO
+ return uno::Sequence< uno::Reference< rendering::XPolyPolygon2D > >();
+ }
+
+ uno::Sequence< geometry::RealRectangle2D > SAL_CALL TextLayout::queryInkMeasures( ) throw (uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // TODO
+ return uno::Sequence< geometry::RealRectangle2D >();
+ }
+
+ uno::Sequence< geometry::RealRectangle2D > SAL_CALL TextLayout::queryMeasures( ) throw (uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // TODO
+ return uno::Sequence< geometry::RealRectangle2D >();
+ }
+
+ uno::Sequence< double > SAL_CALL TextLayout::queryLogicalAdvancements( ) throw (uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ return maLogicalAdvancements;
+ }
+
+ void SAL_CALL TextLayout::applyLogicalAdvancements( const uno::Sequence< double >& aAdvancements ) throw (lang::IllegalArgumentException, uno::RuntimeException)
+ {
+ ::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( ) throw (uno::RuntimeException)
+ {
+ ::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.getLength() )
+ {
+ 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*/ ) throw (lang::IllegalArgumentException, uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // TODO
+ return 0.0;
+ }
+
+ double SAL_CALL TextLayout::combinedJustify( const uno::Sequence< uno::Reference< rendering::XTextLayout > >& /*aNextLayouts*/,
+ double /*nSize*/ ) throw (lang::IllegalArgumentException, uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // TODO
+ return 0.0;
+ }
+
+ rendering::TextHit SAL_CALL TextLayout::getTextHit( const geometry::RealPoint2D& /*aHitPoint*/ ) throw (uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // TODO
+ return rendering::TextHit();
+ }
+
+ rendering::Caret SAL_CALL TextLayout::getCaret( sal_Int32 /*nInsertionIndex*/,
+ sal_Bool /*bExcludeLigatures*/ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // TODO
+ return rendering::Caret();
+ }
+
+ sal_Int32 SAL_CALL TextLayout::getNextInsertionIndex( sal_Int32 /*nStartIndex*/,
+ sal_Int32 /*nCaretAdvancement*/,
+ sal_Bool /*bExcludeLigatures*/ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // TODO
+ return 0;
+ }
+
+ uno::Reference< rendering::XPolyPolygon2D > SAL_CALL TextLayout::queryVisualHighlighting( sal_Int32 /*nStartIndex*/,
+ sal_Int32 /*nEndIndex*/ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // TODO
+ return uno::Reference< rendering::XPolyPolygon2D >();
+ }
+
+ uno::Reference< rendering::XPolyPolygon2D > SAL_CALL TextLayout::queryLogicalHighlighting( sal_Int32 /*nStartIndex*/,
+ sal_Int32 /*nEndIndex*/ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // TODO
+ return uno::Reference< rendering::XPolyPolygon2D >();
+ }
+
+ double SAL_CALL TextLayout::getBaselineOffset( ) throw (uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // TODO
+ return 0.0;
+ }
+
+ sal_Int8 SAL_CALL TextLayout::getMainTextDirection( ) throw (uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ return mnTextDirection;
+ }
+
+ uno::Reference< rendering::XCanvasFont > SAL_CALL TextLayout::getFont( ) throw (uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ return mpFont.getRef();
+ }
+
+ rendering::StringContext SAL_CALL TextLayout::getText( ) throw (uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ return maText;
+ }
+
+ bool TextLayout::draw( const rendering::ViewState& /*rViewState*/,
+ const rendering::RenderState& /*rRenderState*/,
+ const uno::Reference< rendering::XGraphicDevice >& /*xGraphicDevice*/ ) const
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // TODO
+
+ return true;
+ }
+}
+
+/* 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 000000000000..64c50f7f2bb8
--- /dev/null
+++ b/canvas/source/opengl/ogl_textlayout.hxx
@@ -0,0 +1,79 @@
+/* -*- 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 OGL_TEXTLAYOUT_HXX
+#define OGL_TEXTLAYOUT_HXX
+
+#include <cppuhelper/compbase1.hxx>
+#include <comphelper/broadcasthelper.hxx>
+
+#include <com/sun/star/rendering/XTextLayout.hpp>
+
+#include <basegfx/vector/b2isize.hxx>
+
+#include <boost/utility.hpp>
+
+#include "ogl_canvasfont.hxx"
+
+
+/* Definition of TextLayout class */
+
+namespace oglcanvas
+{
+ typedef ::cppu::WeakComponentImplHelper1< ::com::sun::star::rendering::XTextLayout > TextLayoutBaseT;
+
+ class TextLayout : public ::comphelper::OBaseMutex,
+ public TextLayoutBaseT,
+ private ::boost::noncopyable
+ {
+ public:
+ TextLayout( const ::com::sun::star::rendering::StringContext& aText,
+ sal_Int8 nDirection,
+ sal_Int64 nRandomSeed,
+ const CanvasFont::ImplRef& rFont );
+
+ /// Dispose all internal references
+ virtual void SAL_CALL disposing();
+
+ // XTextLayout
+ virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XPolyPolygon2D > > SAL_CALL queryTextShapes( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::com::sun::star::geometry::RealRectangle2D > SAL_CALL queryInkMeasures( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::com::sun::star::geometry::RealRectangle2D > SAL_CALL queryMeasures( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< double > SAL_CALL queryLogicalAdvancements( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL applyLogicalAdvancements( const ::com::sun::star::uno::Sequence< double >& aAdvancements ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::geometry::RealRectangle2D SAL_CALL queryTextBounds( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual double SAL_CALL justify( double nSize ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual double SAL_CALL combinedJustify( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XTextLayout > >& aNextLayouts, double nSize ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::rendering::TextHit SAL_CALL getTextHit( const ::com::sun::star::geometry::RealPoint2D& aHitPoint ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::rendering::Caret SAL_CALL getCaret( sal_Int32 nInsertionIndex, sal_Bool bExcludeLigatures ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException);
+ virtual sal_Int32 SAL_CALL getNextInsertionIndex( sal_Int32 nStartIndex, sal_Int32 nCaretAdvancement, sal_Bool bExcludeLigatures ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XPolyPolygon2D > SAL_CALL queryVisualHighlighting( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XPolyPolygon2D > SAL_CALL queryLogicalHighlighting( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException);
+ virtual double SAL_CALL getBaselineOffset( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual sal_Int8 SAL_CALL getMainTextDirection( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCanvasFont > SAL_CALL getFont( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::rendering::StringContext SAL_CALL getText( ) throw (::com::sun::star::uno::RuntimeException);
+
+ bool draw( const ::com::sun::star::rendering::ViewState& rViewState,
+ const ::com::sun::star::rendering::RenderState& rRenderState,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XGraphicDevice >& xGraphicDevice ) const;
+
+ private:
+ ::com::sun::star::rendering::StringContext maText;
+ ::com::sun::star::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 000000000000..952f36a231ce
--- /dev/null
+++ b/canvas/source/opengl/ogl_texturecache.cxx
@@ -0,0 +1,124 @@
+/* -*- 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/.
+ */
+
+#define GL_GLEXT_PROTOTYPES
+
+#include "ogl_texturecache.hxx"
+
+#include <com/sun/star/geometry/IntegerSize2D.hpp>
+
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <GL/glext.h>
+
+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
+ TextureCacheMapT::const_iterator aCurr=maCache.begin();
+ const TextureCacheMapT::const_iterator aEnd=maCache.end();
+ while( aCurr != aEnd )
+ {
+ glDeleteTextures(1, &aCurr->second.nTexture);
+ ++aCurr;
+ }
+
+ 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"
+ TextureCacheMapT::iterator aNext;
+ TextureCacheMapT::iterator aCurr=maCache.begin();
+ const TextureCacheMapT::iterator aEnd=maCache.end();
+ while( aCurr != aEnd )
+ {
+ aNext=aCurr; ++aNext;
+ if( aCurr->second.bOld )
+ {
+ glDeleteTextures(1, &aCurr->second.nTexture);
+ maCache.erase(aCurr);
+ }
+ else
+ {
+ aCurr->second.bOld = true;
+ }
+ aCurr=aNext;
+ }
+
+ 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 000000000000..0f81a2603ae2
--- /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 OGL_TEXTURECACHE_HXX
+#define OGL_TEXTURECACHE_HXX
+
+#include <sal/types.h>
+#include <unordered_map>
+
+namespace com { namespace sun { namespace 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
+
+ Everytime 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 ::com::sun::star::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 000000000000..d61ab45dd447
--- /dev/null
+++ b/canvas/source/opengl/ogl_tools.hxx
@@ -0,0 +1,31 @@
+/* -*- 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 OGL_CANVAS_TOOLS_HXX
+#define OGL_CANVAS_TOOLS_HXX
+
+#include <sal/config.h>
+#include <GL/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 000000000000..bd2d1039cb78
--- /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" 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>