diff options
Diffstat (limited to 'cppcanvas')
80 files changed, 16702 insertions, 0 deletions
diff --git a/cppcanvas/Library_cppcanvas.mk b/cppcanvas/Library_cppcanvas.mk new file mode 100644 index 000000000000..6493829f4d80 --- /dev/null +++ b/cppcanvas/Library_cppcanvas.mk @@ -0,0 +1,92 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2011 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +$(eval $(call gb_Library_Library,cppcanvas)) + +$(eval $(call gb_Library_add_package_headers,cppcanvas,cppcanvas_inc)) + +$(eval $(call gb_Library_add_precompiled_header,cppcanvas,$(SRCDIR)/cppcanvas/inc/pch/precompiled_cppcanvas)) + +$(eval $(call gb_Library_set_include,cppcanvas,\ + -I$(realpath $(SRCDIR)/cppcanvas/inc) \ + -I$(realpath $(SRCDIR)/cppcanvas/inc/pch) \ + -I$(realpath $(SRCDIR)/cppcanvas/source/inc) \ + $$(INCLUDE) \ +)) + +$(eval $(call gb_Library_add_api,cppcanvas,\ + offapi \ + udkapi \ +)) +$(eval $(call gb_Library_add_defs,cppcanvas,\ + -DCPPCANVAS_DLLIMPLEMENTATION \ +)) + +$(eval $(call gb_Library_add_linked_libs,cppcanvas,\ + basegfx \ + canvastools \ + comphelper \ + cppu \ + cppuhelper \ + i18nisolang1 \ + sal \ + svt \ + tl \ + vcl \ + $(gb_STDLIBS) \ +)) + +$(eval $(call gb_Library_add_exception_objects,cppcanvas,\ + cppcanvas/source/mtfrenderer/bitmapaction \ + cppcanvas/source/mtfrenderer/cachedprimitivebase \ + cppcanvas/source/mtfrenderer/emfplus \ + cppcanvas/source/mtfrenderer/implrenderer \ + cppcanvas/source/mtfrenderer/lineaction \ + cppcanvas/source/mtfrenderer/mtftools \ + cppcanvas/source/mtfrenderer/pointaction \ + cppcanvas/source/mtfrenderer/polypolyaction \ + cppcanvas/source/mtfrenderer/rendergraphicaction \ + cppcanvas/source/mtfrenderer/textaction \ + cppcanvas/source/mtfrenderer/transparencygroupaction \ + cppcanvas/source/tools/canvasgraphichelper \ + cppcanvas/source/tools/tools \ + cppcanvas/source/wrapper/basegfxfactory \ + cppcanvas/source/wrapper/implbitmap \ + cppcanvas/source/wrapper/implbitmapcanvas \ + cppcanvas/source/wrapper/implcanvas \ + cppcanvas/source/wrapper/implcolor \ + cppcanvas/source/wrapper/implcustomsprite \ + cppcanvas/source/wrapper/implfont \ + cppcanvas/source/wrapper/implpolypolygon \ + cppcanvas/source/wrapper/implsprite \ + cppcanvas/source/wrapper/implspritecanvas \ + cppcanvas/source/wrapper/impltext \ + cppcanvas/source/wrapper/vclfactory \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/cppcanvas/Library_mtfrenderer.mk b/cppcanvas/Library_mtfrenderer.mk new file mode 100644 index 000000000000..52e2387ccdc5 --- /dev/null +++ b/cppcanvas/Library_mtfrenderer.mk @@ -0,0 +1,52 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2011 Novell Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +$(eval $(call gb_Library_Library,mtfrenderer)) + +$(eval $(call gb_Library_set_componentfile,mtfrenderer,cppcanvas/source/uno/mtfrenderer)) + +$(eval $(call gb_Library_add_linked_libs,mtfrenderer,\ + sal \ + cppu \ + cppuhelper \ + comphelper \ + cppcanvas \ + basegfx \ + $(gb_STDLIBS) \ +)) + +$(eval $(call gb_Library_add_api,mtfrenderer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Library_add_exception_objects,mtfrenderer,\ + cppcanvas/source/uno/uno_mtfrenderer \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/cppcanvas/Makefile b/cppcanvas/Makefile new file mode 100644 index 000000000000..b912f2f0532b --- /dev/null +++ b/cppcanvas/Makefile @@ -0,0 +1,39 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2011 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +ifeq ($(strip $(SOLARENV)),) +$(error No environment set!) +endif + +gb_PARTIALBUILD := T +GBUILDDIR := $(SOLARENV)/gbuild +include $(GBUILDDIR)/gbuild.mk + +$(eval $(call gb_Module_make_global_targets,$(shell ls $(dir $(realpath $(firstword $(MAKEFILE_LIST))))/Module*.mk))) + +# vim: set noet sw=4 ts=4: diff --git a/cppcanvas/Module_cppcanvas.mk b/cppcanvas/Module_cppcanvas.mk new file mode 100644 index 000000000000..edf7d83c9f3e --- /dev/null +++ b/cppcanvas/Module_cppcanvas.mk @@ -0,0 +1,37 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2011 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +$(eval $(call gb_Module_Module,cppcanvas)) + +$(eval $(call gb_Module_add_targets,cppcanvas,\ + Library_cppcanvas \ + Library_mtfrenderer \ + Package_inc \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/cppcanvas/Package_inc.mk b/cppcanvas/Package_inc.mk new file mode 100644 index 000000000000..090fc6cb974f --- /dev/null +++ b/cppcanvas/Package_inc.mk @@ -0,0 +1,46 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2011 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +$(eval $(call gb_Package_Package,cppcanvas_inc,$(SRCDIR)/cppcanvas/inc)) +$(eval $(call gb_Package_add_file,cppcanvas_inc,inc/cppcanvas/canvas.hxx,cppcanvas/canvas.hxx)) +$(eval $(call gb_Package_add_file,cppcanvas_inc,inc/cppcanvas/sprite.hxx,cppcanvas/sprite.hxx)) +$(eval $(call gb_Package_add_file,cppcanvas_inc,inc/cppcanvas/vclfactory.hxx,cppcanvas/vclfactory.hxx)) +$(eval $(call gb_Package_add_file,cppcanvas_inc,inc/cppcanvas/font.hxx,cppcanvas/font.hxx)) +$(eval $(call gb_Package_add_file,cppcanvas_inc,inc/cppcanvas/customsprite.hxx,cppcanvas/customsprite.hxx)) +$(eval $(call gb_Package_add_file,cppcanvas_inc,inc/cppcanvas/canvasgraphic.hxx,cppcanvas/canvasgraphic.hxx)) +$(eval $(call gb_Package_add_file,cppcanvas_inc,inc/cppcanvas/polypolygon.hxx,cppcanvas/polypolygon.hxx)) +$(eval $(call gb_Package_add_file,cppcanvas_inc,inc/cppcanvas/color.hxx,cppcanvas/color.hxx)) +$(eval $(call gb_Package_add_file,cppcanvas_inc,inc/cppcanvas/spritecanvas.hxx,cppcanvas/spritecanvas.hxx)) +$(eval $(call gb_Package_add_file,cppcanvas_inc,inc/cppcanvas/text.hxx,cppcanvas/text.hxx)) +$(eval $(call gb_Package_add_file,cppcanvas_inc,inc/cppcanvas/renderer.hxx,cppcanvas/renderer.hxx)) +$(eval $(call gb_Package_add_file,cppcanvas_inc,inc/cppcanvas/basegfxfactory.hxx,cppcanvas/basegfxfactory.hxx)) +$(eval $(call gb_Package_add_file,cppcanvas_inc,inc/cppcanvas/bitmap.hxx,cppcanvas/bitmap.hxx)) +$(eval $(call gb_Package_add_file,cppcanvas_inc,inc/cppcanvas/bitmapcanvas.hxx,cppcanvas/bitmapcanvas.hxx)) +$(eval $(call gb_Package_add_file,cppcanvas_inc,inc/cppcanvas/cppcanvasdllapi.h,cppcanvas/cppcanvasdllapi.h)) + +# vim: set noet sw=4 ts=4: diff --git a/cppcanvas/inc/cppcanvas/basegfxfactory.hxx b/cppcanvas/inc/cppcanvas/basegfxfactory.hxx new file mode 100644 index 000000000000..5cb87aaeb5d3 --- /dev/null +++ b/cppcanvas/inc/cppcanvas/basegfxfactory.hxx @@ -0,0 +1,108 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_BASEGFXFACTORY_HXX +#define _CPPCANVAS_BASEGFXFACTORY_HXX + +#include <cppcanvas/canvas.hxx> +#include <cppcanvas/bitmapcanvas.hxx> +#include <cppcanvas/spritecanvas.hxx> +#include <cppcanvas/polypolygon.hxx> +#include <cppcanvas/bitmap.hxx> +#include <cppcanvas/renderer.hxx> +#include <cppcanvas/text.hxx> +#include <cppcanvas/sprite.hxx> +#include <basegfx/vector/b2isize.hxx> + +#include <cppcanvas/cppcanvasdllapi.h> + +namespace basegfx +{ + class B2DPolygon; + class B2DPolyPolygon; +} + +namespace rtl +{ + class OUString; +} + +/* Definition of BaseGfxFactory class */ + +namespace cppcanvas +{ + /** The BaseGfxFactory creates Canvas objects for various basegfx + primitives, such as polygons and bitmaps (not yet + implemented). + + Please note that the objects created for a specific Canvas can + only be drawn on exactly that canvas. You have to regenerate + them for different canvases. + */ + class CPPCANVAS_DLLPUBLIC BaseGfxFactory + { + public: + static BaseGfxFactory& getInstance(); + + /** Create a polygon from a ::basegfx::B2DPolygon + + The created polygon initially has the same size in user + coordinate space as the source polygon + */ + PolyPolygonSharedPtr createPolyPolygon( const CanvasSharedPtr&, const ::basegfx::B2DPolygon& rPoly ) const; + PolyPolygonSharedPtr createPolyPolygon( const CanvasSharedPtr&, const ::basegfx::B2DPolyPolygon& rPoly ) const; + + /** Create an uninitialized bitmap with the given size + */ + BitmapSharedPtr createBitmap( const CanvasSharedPtr&, const ::basegfx::B2ISize& rSize ) const; + + /** Create an uninitialized alpha bitmap with the given size + */ + BitmapSharedPtr createAlphaBitmap( const CanvasSharedPtr&, const ::basegfx::B2ISize& rSize ) const; + + /** Create a text portion with the given content string + */ + TextSharedPtr createText( const CanvasSharedPtr&, const ::rtl::OUString& ) const; + + private: + friend struct InitInstance2; + + // singleton + BaseGfxFactory(); + ~BaseGfxFactory(); + + // default: disabled copy/assignment + BaseGfxFactory(const BaseGfxFactory&); + BaseGfxFactory& operator=( const BaseGfxFactory& ); + }; + +} + +#endif /* _CPPCANVAS_BASEGFXFACTORY_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/inc/cppcanvas/bitmap.hxx b/cppcanvas/inc/cppcanvas/bitmap.hxx new file mode 100644 index 000000000000..425428b24ab5 --- /dev/null +++ b/cppcanvas/inc/cppcanvas/bitmap.hxx @@ -0,0 +1,83 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_BITMAP_HXX +#define _CPPCANVAS_BITMAP_HXX + +#include <com/sun/star/uno/Reference.hxx> + +#include <boost/shared_ptr.hpp> +#include <cppcanvas/canvasgraphic.hxx> +#include <cppcanvas/bitmapcanvas.hxx> + +namespace com { namespace sun { namespace star { namespace rendering +{ + class XBitmap; +} } } } + + +/* Definition of Bitmap interface */ + +namespace cppcanvas +{ + + /** This interface defines a Bitmap canvas object + + Consider this object part of the view, and not of the model + data, as this bitmap can only be painted on its parent canvas + */ + class Bitmap : public virtual CanvasGraphic + { + public: + /** Render to parent canvas, with global alpha. + + This method renders the content to the parent canvas, + i.e. the canvas this object was constructed for. + + @param nAlphaModulation + Global alpha value, with which each pixel alpha value gets + multiplied. For a normal, opaque bitmap, this will make + the bitmap appear transparent with the given alpha value + (value must be in the range [0,1]). + + @return whether the rendering finished successfully. + */ + virtual bool drawAlphaModulated( double nAlphaModulation ) const = 0; + + virtual BitmapCanvasSharedPtr getBitmapCanvas() const = 0; + + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XBitmap > getUNOBitmap() const = 0; + }; + + typedef ::boost::shared_ptr< ::cppcanvas::Bitmap > BitmapSharedPtr; +} + +#endif /* _CPPCANVAS_BITMAP_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/inc/cppcanvas/bitmapcanvas.hxx b/cppcanvas/inc/cppcanvas/bitmapcanvas.hxx new file mode 100644 index 000000000000..4221833bc29e --- /dev/null +++ b/cppcanvas/inc/cppcanvas/bitmapcanvas.hxx @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_BITMAPCANVAS_HXX +#define _CPPCANVAS_BITMAPCANVAS_HXX + +#include <sal/types.h> +#include <osl/diagnose.h> + +#include <boost/shared_ptr.hpp> +#include <basegfx/vector/b2isize.hxx> +#include <cppcanvas/canvas.hxx> + + +/* Definition of BitmapCanvas */ + +namespace cppcanvas +{ + class BitmapCanvas; + + // forward declaration, since cloneBitmapCanvas() also references BitmapCanvas + typedef ::boost::shared_ptr< BitmapCanvas > BitmapCanvasSharedPtr; + + /** BitmapCanvas interface + */ + class BitmapCanvas : public virtual Canvas + { + public: + virtual ::basegfx::B2ISize getSize() const = 0; + + // shared_ptr does not allow for covariant return types + BitmapCanvasSharedPtr cloneBitmapCanvas() const + { + BitmapCanvasSharedPtr p( ::boost::dynamic_pointer_cast< BitmapCanvas >(this->clone()) ); + OSL_ENSURE(p.get(), "BitmapCanvas::cloneBitmapCanvas(): dynamic cast failed"); + return p; + } + }; + +} + +#endif /* _CPPCANVAS_BITMAPCANVAS_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/inc/cppcanvas/canvas.hxx b/cppcanvas/inc/cppcanvas/canvas.hxx new file mode 100644 index 000000000000..385006fdba46 --- /dev/null +++ b/cppcanvas/inc/cppcanvas/canvas.hxx @@ -0,0 +1,119 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_CANVAS_HXX +#define _CPPCANVAS_CANVAS_HXX + +#include <com/sun/star/uno/Reference.hxx> + +#include <boost/shared_ptr.hpp> +#include <cppcanvas/font.hxx> +#include <cppcanvas/color.hxx> + +namespace rtl +{ + class OUString; +} + +namespace basegfx +{ + class B2DHomMatrix; + class B2DPolyPolygon; +} + +namespace com { namespace sun { namespace star { namespace rendering +{ + class XCanvas; + struct ViewState; +} } } } + + +/* Definition of BitmapCanvas */ + +namespace cppcanvas +{ + class PolyPolygon; + class Canvas; + + // forward declaration, since PolyPolygon also references Canvas + typedef ::boost::shared_ptr< PolyPolygon > PolyPolygonSharedPtr; + + // forward declaration, since cloneCanvas() also references Canvas + typedef ::boost::shared_ptr< Canvas > CanvasSharedPtr; + + /** Canvas interface + */ + class Canvas + { + public: + enum + { + /** Extra pixel used when canvas anti-aliases. + + Enlarge the bounding box of drawing primitives by this + amount in both dimensions, and on both sides of the + bounds, to account for extra pixel touched outside the + actual primitive bounding box, when the canvas + performs anti-aliasing. + */ + ANTIALIASING_EXTRA_SIZE=2 + }; + + virtual ~Canvas() {} + + virtual void setTransformation( const ::basegfx::B2DHomMatrix& rMatrix ) = 0; + virtual ::basegfx::B2DHomMatrix getTransformation() const = 0; + + virtual void setClip( const ::basegfx::B2DPolyPolygon& rClipPoly ) = 0; + virtual void setClip() = 0; + + /** Get current clip + + @return NULL, if no clip is set, otherwise the current clip poly-polygon + */ + virtual ::basegfx::B2DPolyPolygon const* getClip() const = 0; + + virtual FontSharedPtr createFont( const ::rtl::OUString& rFontName, const double& rCellSize ) const = 0; + + virtual ColorSharedPtr createColor() const = 0; + + virtual CanvasSharedPtr clone() const = 0; + virtual void clear() const = 0; + + // this should be considered private. if RTTI gets enabled + // someday, remove that to a separate interface + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XCanvas > getUNOCanvas() const = 0; + virtual ::com::sun::star::rendering::ViewState getViewState() const = 0; + }; + +} + +#endif /* _CPPCANVAS_CANVAS_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/inc/cppcanvas/canvasgraphic.hxx b/cppcanvas/inc/cppcanvas/canvasgraphic.hxx new file mode 100644 index 000000000000..4ae43fb4334c --- /dev/null +++ b/cppcanvas/inc/cppcanvas/canvasgraphic.hxx @@ -0,0 +1,173 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_CANVASGRAPHIC_HXX +#define _CPPCANVAS_CANVASGRAPHIC_HXX + +#include <sal/types.h> + +#include <boost/shared_ptr.hpp> +#include <cppcanvas/color.hxx> +#include <cppcanvas/canvas.hxx> + +namespace basegfx +{ + class B2DHomMatrix; + class B2DPolyPolygon; +} + + +/* Definition of CanvasGraphic interface */ + +namespace cppcanvas +{ + // forward declaration, since PolyPolygon also derives from CanvasGraphic + typedef ::boost::shared_ptr< class PolyPolygon > PolyPolygonSharedPtr; + + + /** This interface defines basic properties of + objects that can be painted on a Canvas + */ + class CanvasGraphic + { + public: + + /** These enums determine how the primitive color is combined + with the background. When performing this calculations, it + is assumed that all color values are premultiplied with + the corresponding alpha values (if no alpha is specified, + 1.0 is assumed). Then, the following general compositing + operation is performed: + + C = Ca * Fa + Cb * Fb + + where C is the result color, Ca and Cb are the input + colors, premultiplied with alpha, and Fa and Fb are + described for the different composite modes (wherein Aa + and Ab denote source and destination alpha, respectively). + */ + enum CompositeOp + { + /// Clear destination. Fa = Fb = 0. + CLEAR, + + /// Copy source as-is to destination. Fa = 1, Fb = 0. + SOURCE, + + /// Leave destination as-is. Fa = 0, Fb = 1. + DESTINATION, + + /// Copy source over destination. Fa = 1, Fb = 1-Aa. + OVER, + + /// Copy source under destination. Fa = 1-Ab, Fb = 1. + UNDER, + + /// Copy source to destination, but limited to where the destination is. Fa = Ab, Fb = 0. + INSIDE, + + /// Leave destination as is, but only where source was. Fa = 0, Fb = Aa. + INSIDE_REVERSE, + + /// Copy source to destination, but limited to where destination is not. Fa = 1-Ab, Fb = 0. + OUTSIDE, + + /// Leave destination as is, but only where source has not been. Fa = 0, Fb = 1-Aa. + OUTSIDE_REVERSE, + + /// Copy source over destination, but only where destination is. Keep destination. Fa = Ab, Fb = 1-Aa. + ATOP, + + /// Copy destination over source, but only where source is. Keep source. Fa = 1-Ab, Fb = Aa. + ATOP_REVERSE, + + /// Take only parts where either source or destination, but not both are. Fa = 1-Ab, Fb = 1-Aa. + XOR, + + /** simply add contributions of both source and destination. The + resulting color values are limited to the permissible color + range, and clipped to the maximal value, if exceeded. Fa = 1, Fb = 1. + */ + ADD, + + /// Fa = min(1,(1-Ab)/Aa), Fb = 1 + SATURATE + }; + + virtual ~CanvasGraphic() {} + + /** Set object transformation matrix + */ + virtual void setTransformation( const ::basegfx::B2DHomMatrix& rMatrix ) = 0; + /** Get object transformation matrix + */ + virtual ::basegfx::B2DHomMatrix getTransformation() const = 0; + + /** Set object clipping polygon + */ + virtual void setClip( const ::basegfx::B2DPolyPolygon& rClipPoly ) = 0; + /** Clear object clipping polygon + */ + virtual void setClip() = 0; + /** Get object clipping polygon + + @return NULL, if no clip is set; otherwise, the current clip poly-polygon is returned + */ + virtual ::basegfx::B2DPolyPolygon const* getClip() const = 0; + + /** Set object color + */ + virtual void setRGBAColor( Color::IntSRGBA ) = 0; + /** Get object color + */ + virtual Color::IntSRGBA getRGBAColor() const = 0; + + /** Set object composite mode + */ + virtual void setCompositeOp( CompositeOp aOp ) = 0; + /** Get object composite mode + */ + virtual CompositeOp getCompositeOp() const = 0; + + /** Render to parent canvas + + This method renders the content to the parent canvas, + i.e. the canvas this object was constructed for. + + @return whether the rendering finished successfully. + */ + virtual bool draw() const = 0; + + }; + + typedef ::boost::shared_ptr< ::cppcanvas::CanvasGraphic > CanvasGraphicSharedPtr; +} + +#endif /* _CPPCANVAS_CANVASGRAPHIC_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/inc/cppcanvas/color.hxx b/cppcanvas/inc/cppcanvas/color.hxx new file mode 100644 index 000000000000..6a8e872f328d --- /dev/null +++ b/cppcanvas/inc/cppcanvas/color.hxx @@ -0,0 +1,98 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_COLOR_HXX +#define _CPPCANVAS_COLOR_HXX + +#include <com/sun/star/uno/Sequence.hxx> + +#include <boost/shared_ptr.hpp> + + +/* Definition of Color class */ + +namespace cppcanvas +{ + class Color + { + public: + /** Color in the sRGB color space, plus alpha channel + + The four bytes of the sal_uInt32 are allocated as follows + to the color channels and alpha: 0xRRGGBBAA. + */ + typedef sal_uInt32 IntSRGBA; + + virtual ~Color() {} + + virtual IntSRGBA getIntSRGBA( ::com::sun::star::uno::Sequence< double >& rDeviceColor ) const = 0; + virtual ::com::sun::star::uno::Sequence< double > getDeviceColor( IntSRGBA aSRGBA ) const = 0; + }; + + typedef ::boost::shared_ptr< ::cppcanvas::Color > ColorSharedPtr; + + inline sal_uInt8 getRed( Color::IntSRGBA nCol ) + { + return static_cast<sal_uInt8>( (nCol&0xFF000000U) >> 24U ); + } + + inline sal_uInt8 getGreen( Color::IntSRGBA nCol ) + { + return static_cast<sal_uInt8>( (nCol&0x00FF0000U) >> 16U ); + } + + inline sal_uInt8 getBlue( Color::IntSRGBA nCol ) + { + return static_cast<sal_uInt8>( (nCol&0x0000FF00U) >> 8U ); + } + + inline sal_uInt8 getAlpha( Color::IntSRGBA nCol ) + { + return static_cast<sal_uInt8>( nCol&0x000000FFU ); + } + + inline Color::IntSRGBA makeColor( sal_uInt8 nRed, sal_uInt8 nGreen, sal_uInt8 nBlue, sal_uInt8 nAlpha ) + { + return (nRed << 24U)|(nGreen << 16U)|(nBlue << 8U)|(nAlpha); + } + + inline sal_Int32 unMakeColor( sal_uInt8 nAlpha, sal_uInt8 nRed, sal_uInt8 nGreen, sal_uInt8 nBlue) + { + return (nAlpha << 24U)|(nRed << 16U)|(nGreen << 8U)|(nBlue); + } + + inline sal_Int32 makeColorARGB( sal_uInt8 nAlpha, sal_uInt8 nRed, sal_uInt8 nGreen, sal_uInt8 nBlue) + { + return (nAlpha << 24U)|(nRed << 16U)|(nGreen << 8U)|(nBlue); + } + +} + +#endif /* _CPPCANVAS_COLOR_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/inc/cppcanvas/cppcanvasdllapi.h b/cppcanvas/inc/cppcanvas/cppcanvasdllapi.h new file mode 100644 index 000000000000..aeaf68b73330 --- /dev/null +++ b/cppcanvas/inc/cppcanvas/cppcanvasdllapi.h @@ -0,0 +1,39 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#ifndef INCLUDED_CPPCANVASDLLAPI_H
+#define INCLUDED_CPPCANVASDLLAPI_H
+
+#if defined CPPCANVAS_DLLIMPLEMENTATION
+
+#define CPPCANVAS_DLLPUBLIC SAL_DLLPUBLIC_EXPORT
+#else
+#define CPPCANVAS_DLLPUBLIC SAL_DLLPUBLIC_IMPORT
+#endif
+#define CPPCANVAS_DLLPRIVATE SAL_DLLPRIVATE
+
+#endif
diff --git a/cppcanvas/inc/cppcanvas/customsprite.hxx b/cppcanvas/inc/cppcanvas/customsprite.hxx new file mode 100644 index 000000000000..bd92fbd6f76a --- /dev/null +++ b/cppcanvas/inc/cppcanvas/customsprite.hxx @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_CUSTOMSPRITE_HXX +#define _CPPCANVAS_CUSTOMSPRITE_HXX + +#include <sal/types.h> + +#include <boost/shared_ptr.hpp> +#include <cppcanvas/sprite.hxx> +#include <cppcanvas/canvas.hxx> + + +/* Definition of CustomSprite class */ + +namespace cppcanvas +{ + + class CustomSprite : public virtual Sprite + { + public: + + virtual CanvasSharedPtr getContentCanvas() const = 0; + }; + + typedef ::boost::shared_ptr< ::cppcanvas::CustomSprite > CustomSpriteSharedPtr; +} + +#endif /* _CPPCANVAS_CUSTOMSPRITE_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/inc/cppcanvas/font.hxx b/cppcanvas/inc/cppcanvas/font.hxx new file mode 100644 index 000000000000..b8d864321fd8 --- /dev/null +++ b/cppcanvas/inc/cppcanvas/font.hxx @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_FONT_HXX +#define _CPPCANVAS_FONT_HXX + +#include <com/sun/star/uno/Reference.hxx> + +#include <boost/shared_ptr.hpp> + +namespace rtl +{ + class OUString; +} + +namespace com { namespace sun { namespace star { namespace rendering +{ + class XCanvasFont; +} } } } + +/* Definition of Font class */ + +namespace cppcanvas +{ + + class Font + { + public: + virtual ~Font() {} + + virtual ::rtl::OUString getName() const = 0; + virtual double getCellSize() const = 0; + + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XCanvasFont > getUNOFont() const = 0; + }; + + typedef ::boost::shared_ptr< ::cppcanvas::Font > FontSharedPtr; +} + +#endif /* _CPPCANVAS_FONT_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/inc/cppcanvas/polypolygon.hxx b/cppcanvas/inc/cppcanvas/polypolygon.hxx new file mode 100644 index 000000000000..0adc9426b692 --- /dev/null +++ b/cppcanvas/inc/cppcanvas/polypolygon.hxx @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_POLYPOLYGON_HXX +#define _CPPCANVAS_POLYPOLYGON_HXX + +#include <com/sun/star/uno/Reference.hxx> + +#include <boost/shared_ptr.hpp> +#include <cppcanvas/canvasgraphic.hxx> + +namespace basegfx +{ + class B2DPolygon; + class B2DPolyPolygon; +} + +namespace com { namespace sun { namespace star { namespace rendering +{ + class XPolyPolygon2D; +} } } } + + +/* Definition of PolyPolygon interface */ + +namespace cppcanvas +{ + + /** This interface defines a PolyPolygon canvas object + + Consider this object part of the view, and not of the model + data. Although the given polygon is typically copied and held + internally (to facilitate migration to incompatible canvases), + ::basegfx::B2DPolygon et al. are ref-counted copy-on-write + classes, i.e. memory shouldn't be wasted. On the other hand, + the API polygon created internally _does_ necessarily + duplicate the data held, but can be easily flushed away via + flush(). + */ + class PolyPolygon : public virtual CanvasGraphic + { + public: + virtual void addPolygon( const ::basegfx::B2DPolygon& rPoly ) = 0; + virtual void addPolyPolygon( const ::basegfx::B2DPolyPolygon& rPoly ) = 0; + + /** Set polygon fill color + */ + virtual void setRGBAFillColor( Color::IntSRGBA ) = 0; + /** Set polygon line color + */ + virtual void setRGBALineColor( Color::IntSRGBA ) = 0; + /** Get polygon fill color + */ + virtual Color::IntSRGBA getRGBAFillColor() const = 0; + /** Get polygon line color + */ + virtual Color::IntSRGBA getRGBALineColor() const = 0; + + virtual void setStrokeWidth( const double& rStrokeWidth ) = 0; + virtual double getStrokeWidth() const = 0; + + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XPolyPolygon2D > getUNOPolyPolygon() const = 0; + }; + + typedef ::boost::shared_ptr< ::cppcanvas::PolyPolygon > PolyPolygonSharedPtr; +} + +#endif /* _CPPCANVAS_POLYPOLYGON_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/inc/cppcanvas/renderer.hxx b/cppcanvas/inc/cppcanvas/renderer.hxx new file mode 100644 index 000000000000..a01b438670a8 --- /dev/null +++ b/cppcanvas/inc/cppcanvas/renderer.hxx @@ -0,0 +1,153 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_RENDERER_HXX +#define _CPPCANVAS_RENDERER_HXX + +#include <sal/types.h> +#include <rtl/ustring.hxx> + +#include <boost/shared_ptr.hpp> +#include <boost/optional.hpp> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <cppcanvas/canvasgraphic.hxx> +#include <cppcanvas/color.hxx> + +namespace basegfx +{ + class B2DRange; +} + +/* Definition of Renderer interface */ + +namespace cppcanvas +{ + + class Renderer : public virtual CanvasGraphic + { + public: + /** Render subset of metafile to given canvas + + This method renders the given subset of the content to the + associated canvas. + + @param nStartIndex + The index of the first action to be rendered (the indices + correspond roughly to the action indices of the + originating GDIMetaFile. Note, although, that certain + actions, e.g. text, accounts for more than one index: a + text produces as many addressable indices as it has + characters). + + @param nEndIndex + The index of the first action _not_ painted anymore, + i.e. the action after the last action rendered (the + indices correspond roughly to the action indices of the + originating GDIMetaFile. Note, although, that certain + actions, e.g. text, accounts for more than one index: a + text produces as many addressable indices as it has + characters). + + @return whether the rendering finished successfully. + */ + virtual bool drawSubset( sal_Int32 nStartIndex, + sal_Int32 nEndIndex ) const = 0; + + /** Query bounding box of metafile subset + + This method queries the actual bounding box of the given + subset, when rendered on the associated canvas. + + @param nStartIndex + The index of the first action to be rendered (the indices + correspond roughly to the action indices of the + originating GDIMetaFile. Note, although, that certain + actions, e.g. text, accounts for more than one index: a + text produces as many addressable indices as it has + characters). + + @param nEndIndex + The index of the first action _not_ painted anymore, + i.e. the action after the last action rendered (the + indices correspond roughly to the action indices of the + originating GDIMetaFile. Note, although, that certain + actions, e.g. text, accounts for more than one index: a + text produces as many addressable indices as it has + characters). + + @return the bounding box of the specified subset + */ + virtual ::basegfx::B2DRange getSubsetArea( sal_Int32 nStartIndex, + sal_Int32 nEndIndex ) const = 0; + + /** Parameters for the Renderer + */ + struct Parameters + { + /// Optionally forces the fill color attribute for all actions + ::boost::optional< Color::IntSRGBA > maFillColor; + + /// Optionally forces the line color attribute for all actions + ::boost::optional< Color::IntSRGBA > maLineColor; + + /// Optionally forces the text color attribute for all actions + ::boost::optional< Color::IntSRGBA > maTextColor; + + /// Optionally forces the given fontname for all text actions + ::boost::optional< ::rtl::OUString > maFontName; + + /** Optionally transforms all text output actions with the + given matrix (in addition to the overall canvas + transformation). + + Note that the matrix given here is applied to the unit + rect coordinate system, i.e. the metafile is assumed + to be contained in the unit rect. + */ + ::boost::optional< ::basegfx::B2DHomMatrix > maTextTransformation; + + /// Optionally forces the given font weight for all text actions + ::boost::optional< sal_Int8 > maFontWeight; + + /// Optionally forces the given font letter form (italics etc.) for all text actions + ::boost::optional< sal_Int8 > maFontLetterForm; + + /// Optionally forces the given font proportion (condensed, monospaced etc.) for all text actions + ::boost::optional< sal_Int8 > maFontProportion; + + /// Optionally forces underlining for all text actions + ::boost::optional< bool > maFontUnderline; + }; + }; + + typedef ::boost::shared_ptr< ::cppcanvas::Renderer > RendererSharedPtr; +} + +#endif /* _CPPCANVAS_RENDERER_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/inc/cppcanvas/sprite.hxx b/cppcanvas/inc/cppcanvas/sprite.hxx new file mode 100644 index 000000000000..08c2beb2286a --- /dev/null +++ b/cppcanvas/inc/cppcanvas/sprite.hxx @@ -0,0 +1,119 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_SPRITE_HXX +#define _CPPCANVAS_SPRITE_HXX + +#include <com/sun/star/uno/Reference.hxx> + +#include <boost/shared_ptr.hpp> + +namespace basegfx +{ + class B2DHomMatrix; + class B2DPolyPolygon; + class B2DPoint; +} + +namespace com { namespace sun { namespace star { namespace rendering +{ + class XSprite; +} } } } + + +/* Definition of Sprite class */ + +namespace cppcanvas +{ + + class Sprite + { + public: + virtual ~Sprite() {} + + virtual void setAlpha( const double& rAlpha ) = 0; + + /** Set the sprite position on screen + + This method differs from the XSprite::move() insofar, as + no viewstate/renderstate transformations are applied to + the specified position. The given position is interpreted + in device coordinates (i.e. screen pixel) + */ + virtual void movePixel( const ::basegfx::B2DPoint& rNewPos ) = 0; + + /** Set the sprite position on screen + + This method sets the sprite position in the view + coordinate system of the parent canvas + */ + virtual void move( const ::basegfx::B2DPoint& rNewPos ) = 0; + + virtual void transform( const ::basegfx::B2DHomMatrix& rMatrix ) = 0; + + /** Set output clipping + + This method differs from the XSprite::clip() insofar, as + no viewstate/renderstate transformations are applied to + the specified clip polygon. The given polygon is + interpreted in device coordinates (i.e. screen pixel) + */ + virtual void setClipPixel( const ::basegfx::B2DPolyPolygon& rClipPoly ) = 0; + + /** Set output clipping + + This method applies the clip poly-polygon interpreted in + the view coordinate system of the parent canvas. + */ + virtual void setClip( const ::basegfx::B2DPolyPolygon& rClipPoly ) = 0; + + virtual void setClip() = 0; + + virtual void show() = 0; + virtual void hide() = 0; + + /** Change the sprite priority + + @param fPriority + New sprite priority. The higher the priority, the further + towards the viewer the sprite appears. That is, sprites + with higher priority appear before ones with lower + priority. + */ + virtual void setPriority( double fPriority ) = 0; + + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XSprite > getUNOSprite() const = 0; + }; + + typedef ::boost::shared_ptr< ::cppcanvas::Sprite > SpriteSharedPtr; +} + +#endif /* _CPPCANVAS_SPRITE_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/inc/cppcanvas/spritecanvas.hxx b/cppcanvas/inc/cppcanvas/spritecanvas.hxx new file mode 100644 index 000000000000..df29d4345a85 --- /dev/null +++ b/cppcanvas/inc/cppcanvas/spritecanvas.hxx @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_SPRITECANVAS_HXX +#define _CPPCANVAS_SPRITECANVAS_HXX + +#include <sal/types.h> +#include <osl/diagnose.h> +#include <basegfx/vector/b2dsize.hxx> + +#include <boost/shared_ptr.hpp> + + +#include <cppcanvas/bitmapcanvas.hxx> +#include <cppcanvas/sprite.hxx> +#include <cppcanvas/customsprite.hxx> + +namespace com { namespace sun { namespace star { namespace rendering +{ + class XSpriteCanvas; +} } } } + + +/* Definition of SpriteCanvas */ + +namespace cppcanvas +{ + class SpriteCanvas; + + // forward declaration, since cloneSpriteCanvas() also references SpriteCanvas + typedef ::boost::shared_ptr< ::cppcanvas::SpriteCanvas > SpriteCanvasSharedPtr; + + /** SpriteCanvas interface + */ + class SpriteCanvas : public virtual BitmapCanvas + { + public: + virtual bool updateScreen( bool bUpdateAll ) const = 0; + + virtual CustomSpriteSharedPtr createCustomSprite( const ::basegfx::B2DSize& ) const = 0; + virtual SpriteSharedPtr createClonedSprite( const SpriteSharedPtr& ) const = 0; + + // shared_ptr does not allow for covariant return types + SpriteCanvasSharedPtr cloneSpriteCanvas() const + { + SpriteCanvasSharedPtr p( ::boost::dynamic_pointer_cast< SpriteCanvas >(this->clone()) ); + OSL_ENSURE(p.get(), "SpriteCanvas::cloneSpriteCanvas(): dynamic cast failed"); + return p; + } + + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XSpriteCanvas > getUNOSpriteCanvas() const = 0; + }; + +} + +#endif /* _CPPCANVAS_SPRITECANVAS_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/inc/cppcanvas/text.hxx b/cppcanvas/inc/cppcanvas/text.hxx new file mode 100644 index 000000000000..1787103141ae --- /dev/null +++ b/cppcanvas/inc/cppcanvas/text.hxx @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_TEXT_HXX +#define _CPPCANVAS_TEXT_HXX + +#include <boost/shared_ptr.hpp> +#include <cppcanvas/canvasgraphic.hxx> + + +namespace rtl +{ + class OUString; +} + + +/* Definition of Text interface */ + +namespace cppcanvas +{ + class Text : public virtual CanvasGraphic + { + public: + virtual void setFont( const FontSharedPtr& ) = 0; + virtual FontSharedPtr getFont() = 0; + }; + + typedef ::boost::shared_ptr< ::cppcanvas::Text > TextSharedPtr; +} + +#endif /* _CPPCANVAS_TEXT_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/inc/cppcanvas/vclfactory.hxx b/cppcanvas/inc/cppcanvas/vclfactory.hxx new file mode 100644 index 000000000000..14d9e6cbd5a8 --- /dev/null +++ b/cppcanvas/inc/cppcanvas/vclfactory.hxx @@ -0,0 +1,151 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_VCLFACTORY_HXX +#define _CPPCANVAS_VCLFACTORY_HXX + +#include <cppcanvas/canvas.hxx> +#include <cppcanvas/bitmapcanvas.hxx> +#include <cppcanvas/spritecanvas.hxx> +#include <cppcanvas/polypolygon.hxx> +#include <cppcanvas/bitmap.hxx> +#include <cppcanvas/renderer.hxx> +#include <cppcanvas/text.hxx> +#include <cppcanvas/sprite.hxx> + +#include <cppcanvas/cppcanvasdllapi.h> + +class Window; +class Bitmap; +class BitmapEx; +class Polygon; +class PolyPolygon; +class Size; +class Graphic; +class GDIMetaFile; +class Animation; + +namespace rtl +{ + class OUString; +} +namespace com { namespace sun { namespace star { namespace rendering +{ + class XBitmapCanvas; + class XSpriteCanvas; +} } } } + +/* Definition of VCLFactory class */ + +namespace cppcanvas +{ + /** The VCLFactory creates Canvas objects for various VCL + OutputDevice primitives, such as windows, polygons, bitmaps + and metafiles. + + Please note that the objects created for a specific Canvas can + only be drawn on exactly that canvas. You have to regenerate + them for different canvases. + */ + class CPPCANVAS_DLLPUBLIC VCLFactory + { + public: + static VCLFactory& getInstance(); + + BitmapCanvasSharedPtr createCanvas( const ::Window& rVCLWindow ); + BitmapCanvasSharedPtr createCanvas( const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XBitmapCanvas >& xCanvas ); + + SpriteCanvasSharedPtr createSpriteCanvas( const ::Window& rVCLWindow ) const; + SpriteCanvasSharedPtr createSpriteCanvas( const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XSpriteCanvas >& xCanvas ) const; + SpriteCanvasSharedPtr createFullscreenSpriteCanvas( const ::Window& rVCLWindow, const Size& rFullscreenSize ) const; + + /** Create a polygon from a tools::Polygon + + The created polygon initially has the same size in user + coordinate space as the source polygon + */ + PolyPolygonSharedPtr createPolyPolygon( const CanvasSharedPtr&, const ::Polygon& rPoly ) const; + PolyPolygonSharedPtr createPolyPolygon( const CanvasSharedPtr&, const ::PolyPolygon& rPoly ) const; + + /** Create an uninitialized bitmap with the given size + */ + BitmapSharedPtr createBitmap( const CanvasSharedPtr&, const ::Size& rSize ) const; + + /** Create an uninitialized alpha bitmap with the given size + */ + BitmapSharedPtr createAlphaBitmap( const CanvasSharedPtr&, const ::Size& rSize ) const; + + /** Create a bitmap from a VCL Bitmap + */ + BitmapSharedPtr createBitmap( const CanvasSharedPtr&, const ::Bitmap& rBitmap ) const; + BitmapSharedPtr createBitmap( const CanvasSharedPtr&, const ::BitmapEx& rBmpEx ) const; + + /** Create a renderer object from a Graphic + + The created renderer initially draws the graphic + one-by-one units large, in user coordinate space + */ + RendererSharedPtr createRenderer( const CanvasSharedPtr& rCanvas, + const ::Graphic& rGraphic, + const Renderer::Parameters& rParms ) const; + /** Create a renderer object from a Metafile + + The created renderer initially draws the metafile + one-by-one units large, in user coordinate space + */ + RendererSharedPtr createRenderer( const CanvasSharedPtr& rCanvas, + const ::GDIMetaFile& rMtf, + const Renderer::Parameters& rParms ) const; + + /** Create an animated sprite from a VCL animation + */ + SpriteSharedPtr createAnimatedSprite( const SpriteCanvasSharedPtr&, const ::Animation& rAnim ) const; + + /** Create a text portion with the given content string + */ + TextSharedPtr createText( const CanvasSharedPtr&, const ::rtl::OUString& ) const; + + private: + friend struct InitInstance; + + // singleton + VCLFactory(); + ~VCLFactory(); + + // default: disabled copy/assignment + VCLFactory(const VCLFactory&); + VCLFactory& operator=( const VCLFactory& ); + }; + +} + +#endif /* _CPPCANVAS_VCLFACTORY_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/inc/pch/precompiled_cppcanvas.cxx b/cppcanvas/inc/pch/precompiled_cppcanvas.cxx new file mode 100644 index 000000000000..04b6f76e6ab5 --- /dev/null +++ b/cppcanvas/inc/pch/precompiled_cppcanvas.cxx @@ -0,0 +1,31 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_cppcanvas.hxx" + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/inc/pch/precompiled_cppcanvas.hxx b/cppcanvas/inc/pch/precompiled_cppcanvas.hxx new file mode 100644 index 000000000000..87c94a92a0ff --- /dev/null +++ b/cppcanvas/inc/pch/precompiled_cppcanvas.hxx @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): Generated on 2006-09-01 17:49:36.717845 + +#ifdef PRECOMPILED_HEADERS +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/prj/build.lst b/cppcanvas/prj/build.lst new file mode 100644 index 000000000000..bab151c5c142 --- /dev/null +++ b/cppcanvas/prj/build.lst @@ -0,0 +1,2 @@ +cx cppcanvas : comphelper cppuhelper offapi tools vcl basegfx canvas NULL +cx cppcanvas\prj nmake - all cx_prj NULL diff --git a/cppcanvas/prj/d.lst b/cppcanvas/prj/d.lst new file mode 100644 index 000000000000..c103198198f6 --- /dev/null +++ b/cppcanvas/prj/d.lst @@ -0,0 +1,2 @@ +..\%__SRC%\lib\lib*.* %_DEST%\lib\lib*.* +..\%__SRC%\misc\mtfrenderer.component %_DEST%\xml\mtfrenderer.component diff --git a/cppcanvas/prj/makefile.mk b/cppcanvas/prj/makefile.mk new file mode 100644 index 000000000000..d4cf94ec9f4e --- /dev/null +++ b/cppcanvas/prj/makefile.mk @@ -0,0 +1,40 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=.. +TARGET=prj + +.INCLUDE : settings.mk + +.IF "$(VERBOSE)"!="" +VERBOSEFLAG := +.ELSE +VERBOSEFLAG := -s +.ENDIF + +all: + cd $(PRJ) && $(GNUMAKE) $(VERBOSEFLAG) -r -j$(GMAKE_MODULE_PARALLELISM) $(gb_MAKETARGET) && $(GNUMAKE) $(VERBOSEFLAG) -r deliverlog diff --git a/cppcanvas/source/inc/action.hxx b/cppcanvas/source/inc/action.hxx new file mode 100644 index 000000000000..971cfcb4609f --- /dev/null +++ b/cppcanvas/source/inc/action.hxx @@ -0,0 +1,165 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_ACTION_HXX +#define _CPPCANVAS_ACTION_HXX + +#include <sal/types.h> + +#include <boost/shared_ptr.hpp> + +namespace basegfx +{ + class B2DHomMatrix; + class B2DRange; +} + + +/* Definition of Action interface */ + +namespace cppcanvas +{ + namespace internal + { + /** Interface for internal render actions + + This interface is implemented by all objects generated + from the metafile renderer, and corresponds roughly to the + VCL meta action. + */ + class Action + { + public: + /** Used for rendering action subsets + + There are several cases where an Action might have + subsettable content, e.g. text, or referenced + metafiles, like the transparent action. + + Generally, at the metafile renderer, all actions are + 'flattened' out, i.e. a meta action rendering the + string "Hello" counts five indices, and a transparent + action containing a metafile with 100 actions counts + at least 100 indices (contained transparency or text + actions recursively add to this value). From the + outside, the subset to render is referenced via this + flat index range + */ + struct Subset + { + /** Denotes start of the subset. + + The index given here specifies the first subaction + to render. + */ + sal_Int32 mnSubsetBegin; + + /** Denotes end of the subset + + The index given here specifies the first subaction + <em>not<em> to render, i.e. one action behind the + subset to be rendered + */ + sal_Int32 mnSubsetEnd; + }; + + virtual ~Action() {} + + /** Render this action to the associated canvas + + @param rTransformation + Transformation matrix to apply before rendering + + @return true, if rendering was successful. If + rendering failed, false is returned. + */ + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const = 0; + + /** Render the given part of the action to the associated + canvas. + + @param rTransformation + Transformation matrix to apply before rendering + + @param rSubset + Subset of the action to render. See Subset description + for index semantics. + + @return true, if rendering was successful. If the + specified subset is invalid for this action, or if + rendering failed for other reasons, false is returned. + */ + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const = 0; + + /** Query bounds of this action on the associated canvas + + @param rTransformation + Transformation matrix to apply + + @return the bounds for this action in device + coordinate space. + */ + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const = 0; + + /** Query bounds for the given part of the action on the + associated canvas. + + @param rTransformation + Transformation matrix to apply. + + @param rSubset + Subset of the action to query. See Subset description + for index semantics. + + @return the bounds for the given subset in device + coordinate space. + */ + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const = 0; + + /** Query action count. + + This method returns the number of subset actions + contained in this action. The render( Subset ) method + must accept subset ranges up to the value returned + here. + + @return the number of subset actions + */ + virtual sal_Int32 getActionCount() const = 0; + }; + + typedef ::boost::shared_ptr< Action > ActionSharedPtr; + + } +} + +#endif /* _CPPCANVAS_ACTION_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/inc/canvasgraphichelper.hxx b/cppcanvas/source/inc/canvasgraphichelper.hxx new file mode 100644 index 000000000000..6d49939be1b7 --- /dev/null +++ b/cppcanvas/source/inc/canvasgraphichelper.hxx @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_CANVASGRAPHICHELPER_HXX +#define _CPPCANVAS_CANVASGRAPHICHELPER_HXX + +#include <com/sun/star/rendering/RenderState.hpp> +#include <basegfx/polygon/b2dpolypolygon.hxx> + +#include <cppcanvas/canvasgraphic.hxx> + +#include <boost/optional.hpp> + +namespace com { namespace sun { namespace star { namespace rendering +{ + class XGraphicDevice; +} } } } + + +/* Definition of CanvasGraphicHelper class */ + +namespace cppcanvas +{ + + namespace internal + { + + class CanvasGraphicHelper : public virtual CanvasGraphic + { + public: + CanvasGraphicHelper( const CanvasSharedPtr& rParentCanvas ); + + // CanvasGraphic implementation + virtual void setTransformation( const ::basegfx::B2DHomMatrix& rMatrix ); + virtual ::basegfx::B2DHomMatrix getTransformation() const; + virtual void setClip( const ::basegfx::B2DPolyPolygon& rClipPoly ); + virtual void setClip(); + virtual ::basegfx::B2DPolyPolygon const* getClip() const; + virtual void setRGBAColor( Color::IntSRGBA ); + virtual Color::IntSRGBA getRGBAColor() const; + virtual void setCompositeOp( CompositeOp aOp ); + virtual CompositeOp getCompositeOp() const; + + protected: + // for our clients + // =============== + CanvasSharedPtr getCanvas() const; + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice > getGraphicDevice() const; + const ::com::sun::star::rendering::RenderState& getRenderState() const; + + private: + mutable ::com::sun::star::rendering::RenderState maRenderState; + + boost::optional<basegfx::B2DPolyPolygon> maClipPolyPolygon; + CanvasSharedPtr mpCanvas; + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice > mxGraphicDevice; + }; + + } +} + +#endif /* _CPPCANVAS_CANVASGRAPHICHELPER_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/inc/implrenderer.hxx b/cppcanvas/source/inc/implrenderer.hxx new file mode 100644 index 000000000000..3c1ec6de127f --- /dev/null +++ b/cppcanvas/source/inc/implrenderer.hxx @@ -0,0 +1,327 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_IMPLRENDERER_HXX +#define _CPPCANVAS_IMPLRENDERER_HXX + +#include <sal/types.h> + +#include <boost/shared_ptr.hpp> +#include <cppcanvas/renderer.hxx> +#include <cppcanvas/canvas.hxx> + +#include <canvasgraphichelper.hxx> +#include <action.hxx> + +#include <vector> + +class GDIMetaFile; +class VirtualDevice; +class Gradient; +class BitmapEx; +class MapMode; +class Size; +class Rectangle; +class Font; +class PolyPolygon; +class Point; +class MetaCommentAction; + +namespace basegfx { + class B2DPolyPolygon; + class B2DPolygon; +} + +namespace cppcanvas +{ + + namespace internal + { + struct OutDevState; + struct ActionFactoryParameters; + struct EMFPObject; + struct XForm; + + // state stack of OutputDevice, to correctly handle + // push/pop actions + typedef ::std::vector< OutDevState > VectorOfOutDevStates; + + // EMF+ + // TODO: replace? + struct XForm + { + float eM11; + float eM12; + float eM21; + float eM22; + float eDx; + float eDy; + XForm() + { + SetIdentity (); + }; + + void SetIdentity () + { + eM11 = eM22 = 1.0f; + eDx = eDy = eM12 = eM21 = 0.0f; + } + + void Set (float m11, float m12, float dx, float m21, float m22, float dy) + { + eM11 = m11; + eM12 = m12; + eDx = dx; + eM21 = m21; + eM22 = m22; + eDy = dy; + } + + void Set (XForm f) + { + eM11 = f.eM11; + eM12 = f.eM12; + eM21 = f.eM21; + eM22 = f.eM22; + eDx = f.eDx; + eDy = f.eDy; + } + + void Multiply (float m11, float m12, float dx, float m21, float m22, float dy) + { + eM11 = eM11*m11 + eM12*m21; + eM12 = eM11*m12 + eM12*m22; + eM21 = eM21*m11 + eM22*m21; + eM22 = eM21*m12 + eM22*m22; + eDx *= eDx*m11 + eDy*m21 + dx; + eDy *= eDx*m12 + eDy*m22 + dy; + } + + void Multiply (XForm f) + { + eM11 = eM11*f.eM11 + eM12*f.eM21; + eM12 = eM11*f.eM12 + eM12*f.eM22; + eM21 = eM21*f.eM11 + eM22*f.eM21; + eM22 = eM21*f.eM12 + eM22*f.eM22; + eDx *= eDx*f.eM11 + eDy*f.eM21 + f.eDx; + eDy *= eDx*f.eM12 + eDy*f.eM22 + f.eDy; + } + +#ifdef OSL_BIGENDIAN +// currently unused +static float GetSwapFloat( SvStream& rSt ) +{ + float fTmp; + sal_Int8* pPtr = (sal_Int8*)&fTmp; + rSt >> pPtr[3] >> pPtr[2] >> pPtr[1] >> pPtr[0]; // Little Endian <-> Big Endian switch + return fTmp; +} +#endif + + friend SvStream& operator>>( SvStream& rIn, XForm& rXForm ) + { + if ( sizeof( float ) != 4 ) + { + OSL_FAIL( "EnhWMFReader::sizeof( float ) != 4" ); + rXForm = XForm(); + } + else + { +#ifdef OSL_BIGENDIAN + rXForm.eM11 = GetSwapFloat( rIn ); + rXForm.eM12 = GetSwapFloat( rIn ); + rXForm.eM21 = GetSwapFloat( rIn ); + rXForm.eM22 = GetSwapFloat( rIn ); + rXForm.eDx = GetSwapFloat( rIn ); + rXForm.eDy = GetSwapFloat( rIn ); +#else + rIn >> rXForm.eM11 >> rXForm.eM12 >> rXForm.eM21 >> rXForm.eM22 + >> rXForm.eDx >> rXForm.eDy; +#endif + } + return rIn; + } + }; + + class ImplRenderer : public virtual Renderer, protected CanvasGraphicHelper + { + public: + ImplRenderer( const CanvasSharedPtr& rCanvas, + const GDIMetaFile& rMtf, + const Parameters& rParms ); + ImplRenderer( const CanvasSharedPtr& rCanvas, + const BitmapEx& rBmpEx, + const Parameters& rParms ); + + virtual ~ImplRenderer(); + + virtual bool draw() const; + virtual bool drawSubset( sal_Int32 nStartIndex, + sal_Int32 nEndIndex ) const; + virtual ::basegfx::B2DRange getSubsetArea( sal_Int32 nStartIndex, + sal_Int32 nEndIndex ) const; + + + // element of the Renderer's action vector. Need to be + // public, since some functors need it, too. + struct MtfAction + { + MtfAction( const ActionSharedPtr& rAction, + sal_Int32 nOrigIndex ) : + mpAction( rAction ), + mnOrigIndex( nOrigIndex ) + { + } + + ActionSharedPtr mpAction; + sal_Int32 mnOrigIndex; + }; + + // prefetched and prepared canvas actions + // (externally not visible) + typedef ::std::vector< MtfAction > ActionVector; + + /* EMF+ */ + void ReadRectangle (SvStream& s, float& x, float& y, float &width, float& height, sal_uInt32 flags = 0); + void ReadPoint (SvStream& s, float& x, float& y, sal_uInt32 flags = 0); + void MapToDevice (double &x, double &y); + ::basegfx::B2DPoint Map (::basegfx::B2DPoint& p); + ::basegfx::B2DPoint Map (double ix, double iy); + ::basegfx::B2DSize MapSize (double iwidth, double iheight); + ::basegfx::B2DRange MapRectangle (double ix, double iy, double iwidth, double iheight); + + private: + // default: disabled copy/assignment + ImplRenderer(const ImplRenderer&); + ImplRenderer& operator=( const ImplRenderer& ); + + void updateClipping( const ::basegfx::B2DPolyPolygon& rClipPoly, + const ActionFactoryParameters& rParms, + bool bIntersect ); + + void updateClipping( const ::Rectangle& rClipRect, + const ActionFactoryParameters& rParms, + bool bIntersect ); + + ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XCanvasFont > createFont( double& o_rFontRotation, + const ::Font& rFont, + const ActionFactoryParameters& rParms ) const; + bool createActions( GDIMetaFile& rMtf, + const ActionFactoryParameters& rParms, + bool bSubsettableActions ); + bool createFillAndStroke( const ::basegfx::B2DPolyPolygon& rPolyPoly, + const ActionFactoryParameters& rParms ); + bool createFillAndStroke( const ::basegfx::B2DPolygon& rPoly, + const ActionFactoryParameters& rParms ); + void skipContent( GDIMetaFile& rMtf, + const char* pCommentString, + sal_Int32& io_rCurrActionIndex ) const; + + bool isActionContained( GDIMetaFile& rMtf, + const char* pCommentString, + sal_uInt16 nType ) const; + + void createGradientAction( const ::PolyPolygon& rPoly, + const ::Gradient& rGradient, + const ActionFactoryParameters& rParms, + bool bIsPolygonRectangle, + bool bSubsettableActions ); + + void createTextAction( const ::Point& rStartPoint, + const String rString, + int nIndex, + int nLength, + const sal_Int32* pCharWidths, + const ActionFactoryParameters& rParms, + bool bSubsettable ); + + bool getSubsetIndices( sal_Int32& io_rStartIndex, + sal_Int32& io_rEndIndex, + ActionVector::const_iterator& o_rRangeBegin, + ActionVector::const_iterator& o_rRangeEnd ) const; + + void processObjectRecord(SvMemoryStream& rObjectStream, sal_uInt16 flags); + void processEMFPlus( MetaCommentAction* pAct, const ActionFactoryParameters& rFactoryParms, OutDevState& rState, const CanvasSharedPtr& rCanvas ); + void EMFPPlusFillPolygon (::basegfx::B2DPolyPolygon& polygon, const ActionFactoryParameters& rParms, OutDevState& rState, const CanvasSharedPtr& rCanvas, bool isColor, sal_uInt32 brushIndexOrColor); + + ActionVector maActions; + + /* EMF+ */ + XForm aBaseTransform; + XForm aWorldTransform; + EMFPObject* aObjects [256]; + float fPageScale; + sal_Int32 nOriginX; + sal_Int32 nOriginY; + sal_Int32 nHDPI; + sal_Int32 nVDPI; + ::PolyPolygon aClippingPolygon; + /* EMF+ emf header info */ + sal_Int32 nFrameLeft; + sal_Int32 nFrameTop; + sal_Int32 nFrameRight; + sal_Int32 nFrameBottom; + sal_Int32 nPixX; + sal_Int32 nPixY; + sal_Int32 nMmX; + sal_Int32 nMmY; + /* multipart object data */ + bool mbMultipart; + sal_uInt16 mMFlags; + SvMemoryStream mMStream; + }; + + + /// Common parameters when creating actions + struct ActionFactoryParameters + { + ActionFactoryParameters( VectorOfOutDevStates& rStates, + const CanvasSharedPtr& rCanvas, + ::VirtualDevice& rVDev, + const Renderer::Parameters& rParms, + sal_Int32& io_rCurrActionIndex ) : + mrStates(rStates), + mrCanvas(rCanvas), + mrVDev(rVDev), + mrParms(rParms), + mrCurrActionIndex(io_rCurrActionIndex) + {} + + VectorOfOutDevStates& mrStates; + const CanvasSharedPtr& mrCanvas; + ::VirtualDevice& mrVDev; + const Renderer::Parameters& mrParms; + sal_Int32& mrCurrActionIndex; + }; + } +} + +#endif /* _CPPCANVAS_IMPLRENDERER_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/inc/tools.hxx b/cppcanvas/source/inc/tools.hxx new file mode 100644 index 000000000000..bdd9848822fa --- /dev/null +++ b/cppcanvas/source/inc/tools.hxx @@ -0,0 +1,59 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_TOOLS_HXX +#define _CPPCANVAS_TOOLS_HXX + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <cppcanvas/color.hxx> + +namespace com { namespace sun { namespace star { namespace rendering +{ + class XGraphicDevice; +} } } } + + +namespace cppcanvas +{ + namespace tools + { + ::com::sun::star::uno::Sequence< double > + intSRGBAToDoubleSequence( const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XGraphicDevice >&, + Color::IntSRGBA ); + + Color::IntSRGBA doubleSequenceToIntSRGBA( const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XGraphicDevice >& rDevice, + const ::com::sun::star::uno::Sequence< double >& rColor ); + } +} + +#endif /* _CPPCANVAS_TOOLS_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/mtfrenderer/bitmapaction.cxx b/cppcanvas/source/mtfrenderer/bitmapaction.cxx new file mode 100644 index 000000000000..cbbd817cc0ec --- /dev/null +++ b/cppcanvas/source/mtfrenderer/bitmapaction.cxx @@ -0,0 +1,241 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cppcanvas.hxx" + +#include <rtl/logfile.hxx> +#include <com/sun/star/rendering/XBitmap.hpp> +#include <com/sun/star/rendering/RepaintResult.hpp> +#include <com/sun/star/rendering/XCachedPrimitive.hpp> +#include <vcl/bitmapex.hxx> +#include <tools/gen.hxx> +#include <vcl/canvastools.hxx> +#include <canvas/canvastools.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/vector/b2dsize.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/range/b2drange.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <boost/utility.hpp> +#include "cachedprimitivebase.hxx" +#include "bitmapaction.hxx" +#include "outdevstate.hxx" +#include "mtftools.hxx" +#include <basegfx/matrix/b2dhommatrixtools.hxx> + + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace internal + { + namespace + { + + class BitmapAction : public CachedPrimitiveBase + { + public: + BitmapAction( const ::BitmapEx&, + const ::basegfx::B2DPoint& rDstPoint, + const CanvasSharedPtr&, + const OutDevState& ); + BitmapAction( const ::BitmapEx&, + const ::basegfx::B2DPoint& rDstPoint, + const ::basegfx::B2DVector& rDstSize, + const CanvasSharedPtr&, + const OutDevState& ); + + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual sal_Int32 getActionCount() const; + + private: + using Action::render; + virtual bool render( uno::Reference< rendering::XCachedPrimitive >& rCachedPrimitive, + const ::basegfx::B2DHomMatrix& rTransformation ) const; + + uno::Reference< rendering::XBitmap > mxBitmap; + CanvasSharedPtr mpCanvas; + rendering::RenderState maState; + }; + + + BitmapAction::BitmapAction( const ::BitmapEx& rBmpEx, + const ::basegfx::B2DPoint& rDstPoint, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) : + CachedPrimitiveBase( rCanvas, true ), + mxBitmap( ::vcl::unotools::xBitmapFromBitmapEx( rCanvas->getUNOCanvas()->getDevice(), + rBmpEx ) ), + mpCanvas( rCanvas ), + maState() + { + tools::initRenderState(maState,rState); + + // Setup transformation such that the next render call is + // moved rPoint away. + const basegfx::B2DHomMatrix aLocalTransformation(basegfx::tools::createTranslateB2DHomMatrix(rDstPoint)); + ::canvas::tools::appendToRenderState( maState, + aLocalTransformation ); + + // correct clip (which is relative to original transform) + tools::modifyClip( maState, + rState, + rCanvas, + rDstPoint, + NULL, + NULL ); + } + + BitmapAction::BitmapAction( const ::BitmapEx& rBmpEx, + const ::basegfx::B2DPoint& rDstPoint, + const ::basegfx::B2DVector& rDstSize, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) : + CachedPrimitiveBase( rCanvas, true ), + mxBitmap( ::vcl::unotools::xBitmapFromBitmapEx( rCanvas->getUNOCanvas()->getDevice(), + rBmpEx ) ), + mpCanvas( rCanvas ), + maState() + { + tools::initRenderState(maState,rState); + + // Setup transformation such that the next render call is + // moved rPoint away, and scaled according to the ratio + // given by src and dst size. + const ::Size aBmpSize( rBmpEx.GetSizePixel() ); + + const ::basegfx::B2DVector aScale( rDstSize.getX() / aBmpSize.Width(), + rDstSize.getY() / aBmpSize.Height() ); + const basegfx::B2DHomMatrix aLocalTransformation(basegfx::tools::createScaleTranslateB2DHomMatrix( + aScale, rDstPoint)); + ::canvas::tools::appendToRenderState( maState, aLocalTransformation ); + + // correct clip (which is relative to original transform) + tools::modifyClip( maState, + rState, + rCanvas, + rDstPoint, + &aScale, + NULL ); + } + + bool BitmapAction::render( uno::Reference< rendering::XCachedPrimitive >& rCachedPrimitive, + const ::basegfx::B2DHomMatrix& rTransformation ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::BitmapAction::render()" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::BitmapAction: 0x%X", this ); + + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + rCachedPrimitive = mpCanvas->getUNOCanvas()->drawBitmap( mxBitmap, + mpCanvas->getViewState(), + aLocalState ); + + return true; + } + + bool BitmapAction::render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + // bitmap only contains a single action, fail if subset + // requests different range + if( rSubset.mnSubsetBegin != 0 || + rSubset.mnSubsetEnd != 1 ) + return false; + + return CachedPrimitiveBase::render( rTransformation ); + } + + ::basegfx::B2DRange BitmapAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + const geometry::IntegerSize2D aSize( mxBitmap->getSize() ); + + return tools::calcDevicePixelBounds( ::basegfx::B2DRange( 0,0, + aSize.Width, + aSize.Height ), + mpCanvas->getViewState(), + aLocalState ); + } + + ::basegfx::B2DRange BitmapAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + // bitmap only contains a single action, empty bounds + // if subset requests different range + if( rSubset.mnSubsetBegin != 0 || + rSubset.mnSubsetEnd != 1 ) + return ::basegfx::B2DRange(); + + return getBounds( rTransformation ); + } + + sal_Int32 BitmapAction::getActionCount() const + { + return 1; + } + } + + ActionSharedPtr BitmapActionFactory::createBitmapAction( const ::BitmapEx& rBmpEx, + const ::basegfx::B2DPoint& rDstPoint, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) + { + return ActionSharedPtr( new BitmapAction(rBmpEx, + rDstPoint, + rCanvas, + rState ) ); + } + + ActionSharedPtr BitmapActionFactory::createBitmapAction( const ::BitmapEx& rBmpEx, + const ::basegfx::B2DPoint& rDstPoint, + const ::basegfx::B2DVector& rDstSize, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) + { + return ActionSharedPtr( new BitmapAction(rBmpEx, + rDstPoint, + rDstSize, + rCanvas, + rState ) ); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/mtfrenderer/bitmapaction.hxx b/cppcanvas/source/mtfrenderer/bitmapaction.hxx new file mode 100644 index 000000000000..e6c7b83ee626 --- /dev/null +++ b/cppcanvas/source/mtfrenderer/bitmapaction.hxx @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_BITMAPACTION_HXX +#define _CPPCANVAS_BITMAPACTION_HXX + +#include <cppcanvas/canvas.hxx> +#include <action.hxx> + +namespace basegfx { + class B2DPoint; + class B2DVector; +} +class BitmapEx; + +/* Definition of internal::BitmapActionFactory class */ + +namespace cppcanvas +{ + namespace internal + { + struct OutDevState; + + /** Creates encapsulated converters between GDIMetaFile and + XCanvas. The Canvas argument is deliberately placed at the + constructor, to force reconstruction of this object for a + new canvas. This considerably eases internal state + handling, since a lot of the internal state (e.g. fonts, + text layout) is Canvas-dependent. + */ + class BitmapActionFactory + { + public: + /// Unscaled bitmap action, only references destination point + static ActionSharedPtr createBitmapAction( const ::BitmapEx&, + const ::basegfx::B2DPoint& rDstPoint, + const CanvasSharedPtr&, + const OutDevState& ); + + /// Scaled bitmap action, dest point and dest size + static ActionSharedPtr createBitmapAction( const ::BitmapEx&, + const ::basegfx::B2DPoint& rDstPoint, + const ::basegfx::B2DVector& rDstSize, + const CanvasSharedPtr&, + const OutDevState& ); + + private: + // static factory, disable big four + BitmapActionFactory(); + ~BitmapActionFactory(); + BitmapActionFactory(const BitmapActionFactory&); + BitmapActionFactory& operator=( const BitmapActionFactory& ); + }; + } +} + +#endif /*_CPPCANVAS_BITMAPACTION_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/mtfrenderer/cachedprimitivebase.cxx b/cppcanvas/source/mtfrenderer/cachedprimitivebase.cxx new file mode 100644 index 000000000000..9cd01fc42a03 --- /dev/null +++ b/cppcanvas/source/mtfrenderer/cachedprimitivebase.cxx @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cppcanvas.hxx" + +#include <rtl/logfile.hxx> + +#include <com/sun/star/rendering/RepaintResult.hpp> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <canvas/canvastools.hxx> +#include <cppcanvas/canvas.hxx> + +#include "cachedprimitivebase.hxx" + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace internal + { + CachedPrimitiveBase::CachedPrimitiveBase( const CanvasSharedPtr& rCanvas, + bool bOnlyRedrawWithSameTransform ) : + mpCanvas( rCanvas ), + mxCachedPrimitive(), + maLastTransformation(), + mbOnlyRedrawWithSameTransform( bOnlyRedrawWithSameTransform ) + { + // TODO(F2): also store last view transform, and refuse to + // redraw if changed. + } + + bool CachedPrimitiveBase::render( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::CachedPrimitiveBase::render()" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::CachedPrimitiveBase: 0x%X", this ); + + const rendering::ViewState& rViewState( mpCanvas->getViewState() ); + ::basegfx::B2DHomMatrix aTotalTransform; + + ::canvas::tools::getViewStateTransform( aTotalTransform, + rViewState ); + aTotalTransform *= rTransformation; + + // can we use the cached primitive? For that, it must be + // present in the first place, and, if + // mbOnlyRedrawWithSameTransform is true, the overall + // transformation must be the same. + if( mxCachedPrimitive.is() && + (!mbOnlyRedrawWithSameTransform || + maLastTransformation == aTotalTransform) ) + { + if( mxCachedPrimitive->redraw( rViewState ) == + rendering::RepaintResult::REDRAWN ) + { + // cached repaint succeeded, done. + return true; + } + } + + maLastTransformation = aTotalTransform; + + // delegate rendering to derived classes + return render( mxCachedPrimitive, + rTransformation ); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/mtfrenderer/cachedprimitivebase.hxx b/cppcanvas/source/mtfrenderer/cachedprimitivebase.hxx new file mode 100644 index 000000000000..8cef77f1dd26 --- /dev/null +++ b/cppcanvas/source/mtfrenderer/cachedprimitivebase.hxx @@ -0,0 +1,98 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_CACHEDPRIMITIVEBASE_HXX +#define _CPPCANVAS_CACHEDPRIMITIVEBASE_HXX + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/rendering/XCanvas.hpp> + +#include <cppcanvas/canvas.hxx> +#include <boost/utility.hpp> + +#include "action.hxx" + +namespace basegfx { class B2DHomMatrix; } + + +/* Definition of internal::CachedPrimitiveBase class */ + +namespace cppcanvas +{ + namespace internal + { + /** Base class providing cached re-rendering, if XCanvas + returns XCachedPrimitive + + Derive from this class and implement private render() + method to perform the actual primitive rendering. Return + cached primitive into given reference. Next time this + class' public render() method gets called, the cached + representation is taken. + */ + class CachedPrimitiveBase : public Action, + private ::boost::noncopyable + { + public: + /** Constructor + + @param rCanvas + Canvas on which this primitive is to appear + + @param bOnlyRedrawWithSameTransform + When true, this class only reuses the cached + primitive, if the overall transformation stays the + same. Otherwise, repaints are always performed via the + cached primitive. + */ + CachedPrimitiveBase( const CanvasSharedPtr& rCanvas, + bool bOnlyRedrawWithSameTransform ); + virtual ~CachedPrimitiveBase() {} + + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const; + + protected: + using Action::render; + + private: + virtual bool render( ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XCachedPrimitive >& rCachedPrimitive, + const ::basegfx::B2DHomMatrix& rTransformation ) const = 0; + + CanvasSharedPtr mpCanvas; + mutable ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XCachedPrimitive > mxCachedPrimitive; + mutable ::basegfx::B2DHomMatrix maLastTransformation; + const bool mbOnlyRedrawWithSameTransform; + }; + } +} + +#endif /*_CPPCANVAS_CACHEDPRIMITIVEBASE_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/mtfrenderer/emfplus.cxx b/cppcanvas/source/mtfrenderer/emfplus.cxx new file mode 100644 index 000000000000..26581c9c911a --- /dev/null +++ b/cppcanvas/source/mtfrenderer/emfplus.cxx @@ -0,0 +1,1648 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2010 Novell, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <tools/stream.hxx> +#include <vcl/metaact.hxx> +#include <svtools/filter.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/tools/gradienttools.hxx> +#include <basegfx/tools/tools.hxx> +#include <basegfx/numeric/ftools.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/vector/b2dsize.hxx> +#include <basegfx/range/b2drange.hxx> +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <vcl/canvastools.hxx> +#include <rtl/ustring.hxx> +#include <sal/alloca.h> + +#include <com/sun/star/rendering/XCanvas.hpp> +#include <com/sun/star/rendering/TexturingMode.hpp> + +#include <bitmapaction.hxx> +#include <implrenderer.hxx> +#include <outdevstate.hxx> +#include <polypolyaction.hxx> +#include <textaction.hxx> + +#define EmfPlusRecordTypeHeader 16385 +#define EmfPlusRecordTypeEndOfFile 16386 +#define EmfPlusRecordTypeGetDC 16388 +#define EmfPlusRecordTypeObject 16392 +#define EmfPlusRecordTypeFillRects 16394 +#define EmfPlusRecordTypeFillPolygon 16396 +#define EmfPlusRecordTypeDrawLines 16397 +#define EmfPlusRecordTypeFillPath 16404 +#define EmfPlusRecordTypeDrawPath 16405 +#define EmfPlusRecordTypeDrawImagePoints 16411 +#define EmfPlusRecordTypeDrawString 16412 +#define EmfPlusRecordTypeSetRenderingOrigin 16413 +#define EmfPlusRecordTypeSetAntiAliasMode 16414 +#define EmfPlusRecordTypeSetTextRenderingHint 16415 +#define EmfPlusRecordTypeSetInterpolationMode 16417 +#define EmfPlusRecordTypeSetPixelOffsetMode 16418 +#define EmfPlusRecordTypeSetCompositingQuality 16420 +#define EmfPlusRecordTypeSave 16421 +#define EmfPlusRecordTypeSetWorldTransform 16426 +#define EmfPlusRecordTypeResetWorldTransform 16427 +#define EmfPlusRecordTypeMultiplyWorldTransform 16428 +#define EmfPlusRecordTypeSetPageTransform 16432 +#define EmfPlusRecordTypeSetClipPath 16435 +#define EmfPlusRecordTypeSetClipRegion 16436 +#define EmfPlusRecordTypeDrawDriverString 16438 + +#define EmfPlusObjectTypeBrush 0x100 +#define EmfPlusObjectTypePen 0x200 +#define EmfPlusObjectTypePath 0x300 +#define EmfPlusObjectTypeRegion 0x400 +#define EmfPlusObjectTypeImage 0x500 +#define EmfPlusObjectTypeFont 0x600 +#define EmfPlusObjectTypeStringFormat 0x700 +#define EmfPlusObjectTypeImageAttributes 0x800 + +#define EmfPlusRegionInitialStateRectangle 0x10000000 +#define EmfPlusRegionInitialStatePath 0x10000001 +#define EmfPlusRegionInitialStateEmpty 0x10000002 +#define EmfPlusRegionInitialStateInfinite 0x10000003 + +#if OSL_DEBUG_LEVEL > 1 +#define EMFP_DEBUG(x) x +#else +#define EMFP_DEBUG(x) +#endif + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace internal + { + + EMFP_DEBUG (void dumpWords (SvStream& s, int i) + { + sal_uInt32 pos = s.Tell (); + sal_Int16 data; + for (; i > 0; i --) { + s >> data; + printf ("EMF+\tdata: %04hX\n", data); + } + s.Seek (pos); + }); + + struct EMFPObject + { + }; + + struct EMFPPath : public EMFPObject + { + ::basegfx::B2DPolyPolygon aPolygon; + sal_Int32 nPoints; + float* pPoints; + sal_uInt8* pPointTypes; + + public: + EMFPPath (sal_Int32 _nPoints, bool bLines = false) + { + if( _nPoints<0 || sal_uInt32(_nPoints)>SAL_MAX_INT32/(2*sizeof(float)) ) + _nPoints = SAL_MAX_INT32/(2*sizeof(float)); + nPoints = _nPoints; + pPoints = new float [nPoints*2]; + if (!bLines) + pPointTypes = new sal_uInt8 [_nPoints]; + else + pPointTypes = NULL; + } + + ~EMFPPath () + { + delete [] pPoints; + delete [] pPointTypes; + } + + // TODO: remove rR argument when debug code is not longer needed + void Read (SvStream& s, sal_uInt32 pathFlags, ImplRenderer& rR) + { + for (int i = 0; i < nPoints; i ++) { + if (pathFlags & 0x4000) { + // points are stored in short 16bit integer format + sal_uInt16 x, y; + + s >> x >> y; + EMFP_DEBUG (printf ("EMF+\tpoint [x,y]: %hd,%hd\n", x, y)); + pPoints [i*2] = x; + pPoints [i*2 + 1] = y; + } else { + // points are stored in Single (float) format + s >> pPoints [i*2] >> pPoints [i*2 + 1]; + EMFP_DEBUG (printf ("EMF+\tpoint [x,y]: %f,%f\n", pPoints [i*2], pPoints [i*2 + 1])); + } + } + + if (pPointTypes) + for (int i = 0; i < nPoints; i ++) { + s >> pPointTypes [i]; + EMFP_DEBUG (printf ("EMF+\tpoint type: %x\n", pPointTypes [i])); + } + + aPolygon.clear (); + + // debug code + const ::basegfx::B2DRectangle aBounds (::basegfx::tools::getRange (GetPolygon (rR))); + EMFP_DEBUG (printf ("EMF+\tpolygon bounding box: %f,%f %fx%f (mapped)\n", aBounds.getMinX (), aBounds.getMinY (), aBounds.getWidth (), aBounds.getHeight ())); + } + + ::basegfx::B2DPolyPolygon& GetPolygon (ImplRenderer& rR, bool bMapIt = true) + { + ::basegfx::B2DPolygon polygon; + + aPolygon.clear (); + + int last_normal = 0, p = 0; + ::basegfx::B2DPoint prev, mapped; + bool hasPrev = false; + for (int i = 0; i < nPoints; i ++) { + if (p && pPointTypes && (pPointTypes [i] == 0)) { + aPolygon.append (polygon); + last_normal = i; + p = 0; + polygon.clear (); + } + + if (bMapIt) + mapped = rR.Map (pPoints [i*2], pPoints [i*2 + 1]); + else + mapped = ::basegfx::B2DPoint (pPoints [i*2], pPoints [i*2 + 1]); + //EMFP_DEBUG (printf ("polygon point: %f,%f mapped: %f,%f\n", pPoints [i*2], pPoints [i*2 + 1], mapped.getX (), mapped.getY ())); + if (pPointTypes) { + if ((pPointTypes [i] & 0x07) == 3) { + if (((i - last_normal )% 3) == 1) { + polygon.setNextControlPoint (p - 1, mapped); + continue; + } else if (((i - last_normal) % 3) == 2) { + prev = mapped; + hasPrev = true; + continue; + } + } else + last_normal = i; + } + polygon.append (mapped); + if (hasPrev) { + polygon.setPrevControlPoint (p, prev); + hasPrev = false; + } + p ++; + if (pPointTypes && (pPointTypes [i] & 0x80)) { // closed polygon + polygon.setClosed (true); + aPolygon.append (polygon); + last_normal = i + 1; + p = 0; + polygon.clear (); + } + } + + if (polygon.count ()) + aPolygon.append (polygon); + + return aPolygon; + } + }; + + struct EMFPRegion : public EMFPObject + { + sal_Int32 parts; + sal_Int32 *combineMode; + sal_Int32 initialState; + EMFPPath *initialPath; + float ix, iy, iw, ih; + + EMFPRegion () + { + combineMode = NULL; + initialPath = NULL; + } + + ~EMFPRegion () + { + if (combineMode) { + delete [] combineMode; + combineMode = NULL; + } + if (initialPath) { + delete initialPath; + initialPath = NULL; + } + } + + void Read (SvStream& s) + { + sal_uInt32 header; + + s >> header >> parts; + + EMFP_DEBUG (printf ("EMF+\tregion\n")); + EMFP_DEBUG (printf ("EMF+\theader: 0x%08x parts: %d\n", header, parts)); + + if (parts) { + if( parts<0 || sal_uInt32(parts)>SAL_MAX_INT32/sizeof(sal_Int32) ) + parts = SAL_MAX_INT32/sizeof(sal_Int32); + + combineMode = new sal_Int32 [parts]; + + for (int i = 0; i < parts; i ++) { + s >> combineMode [i]; + EMFP_DEBUG (printf ("EMF+\tcombine mode [%d]: 0x%08x\n", i, combineMode [i])); + } + } + + s >> initialState; + EMFP_DEBUG (printf ("EMF+\tinitial state: 0x%08x\n", initialState)); + } + }; + + struct EMFPBrush : public EMFPObject + { + ::Color solidColor; + sal_uInt32 type; + sal_uInt32 additionalFlags; + + /* linear gradient */ + sal_Int32 wrapMode; + float areaX, areaY, areaWidth, areaHeight; + ::Color secondColor; // first color is stored in solidColor; + XForm transformation; + bool hasTransformation; + sal_Int32 blendPoints; + float* blendPositions; + float* blendFactors; + sal_Int32 colorblendPoints; + float* colorblendPositions; + ::Color* colorblendColors; + sal_Int32 surroundColorsNumber; + ::Color* surroundColors; + EMFPPath *path; + + public: + EMFPBrush () + { + blendPositions = NULL; + colorblendPositions = NULL; + colorblendColors = NULL; + surroundColors = NULL; + path = NULL; + hasTransformation = false; + } + + ~EMFPBrush () + { + if (blendPositions != NULL) { + delete[] blendPositions; + blendPositions = NULL; + } + if (colorblendPositions != NULL) { + delete[] colorblendPositions; + colorblendPositions = NULL; + } + if (colorblendColors != NULL) { + delete[] colorblendColors; + colorblendColors = NULL; + } + if (surroundColors != NULL) { + delete[] surroundColors; + surroundColors = NULL; + } + if (path) { + delete path; + path = NULL; + } + } + + sal_uInt32 GetType() const { return type; } + const ::Color& GetColor() const { return solidColor; } + + void Read (SvStream& s, ImplRenderer& rR) + { + sal_uInt32 header; + + s >> header >> type; + + EMFP_DEBUG (printf ("EMF+\tbrush\nEMF+\theader: 0x%08x type: %d\n", header, type)); + + switch (type) { + case 0: + { + sal_uInt32 color; + + s >> color; + solidColor = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff); + EMFP_DEBUG (printf ("EMF+\tsolid color: 0x%08x\n", color)); + + break; + } + // path gradient + case 3: + { + s >> additionalFlags >> wrapMode; + + EMFP_DEBUG (printf ("EMF+\tpath gradient, additional flags: 0x%02x\n", additionalFlags)); + + sal_uInt32 color; + + s >> color; + solidColor = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff); + EMFP_DEBUG (printf ("EMF+\tcenter color: 0x%08x\n", color)); + + s >> areaX >> areaY; + EMFP_DEBUG (printf ("EMF+\tcenter point: %f,%f\n", areaX, areaY)); + + s >> surroundColorsNumber; + EMFP_DEBUG (printf ("EMF+\tsurround colors: %d\n", surroundColorsNumber)); + + if( surroundColorsNumber<0 || sal_uInt32(surroundColorsNumber)>SAL_MAX_INT32/sizeof(::Color) ) + surroundColorsNumber = SAL_MAX_INT32/sizeof(::Color); + + surroundColors = new ::Color [surroundColorsNumber]; + for (int i = 0; i < surroundColorsNumber; i++) { + s >> color; + surroundColors[i] = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff); + if (i == 0) + secondColor = surroundColors [0]; + EMFP_DEBUG (printf ("EMF+\tsurround color[%d]: 0x%08x\n", i, color)); + } + + if (additionalFlags & 0x01) { + sal_Int32 pathLength; + + s >> pathLength; + EMFP_DEBUG (printf ("EMF+\tpath length: %d\n", pathLength)); + + sal_uInt32 pos = s.Tell (); + EMFP_DEBUG (dumpWords (s, 32)); + + sal_uInt32 pathHeader; + sal_Int32 pathPoints, pathFlags; + s >> pathHeader >> pathPoints >> pathFlags; + + EMFP_DEBUG (printf ("EMF+\tpath (brush path gradient)\n")); + EMFP_DEBUG (printf ("EMF+\theader: 0x%08x points: %d additional flags: 0x%08x\n", pathHeader, pathPoints, pathFlags)); + + path = new EMFPPath (pathPoints); + path->Read (s, pathFlags, rR); + + s.Seek (pos + pathLength); + + const ::basegfx::B2DRectangle aBounds (::basegfx::tools::getRange (path->GetPolygon (rR, false))); + areaWidth = aBounds.getWidth (); + areaHeight = aBounds.getHeight (); + + EMFP_DEBUG (printf ("EMF+\tpolygon bounding box: %f,%f %fx%f\n", aBounds.getMinX (), aBounds.getMinY (), aBounds.getWidth (), aBounds.getHeight ())); + + + if (additionalFlags & 0x02) { + EMFP_DEBUG (printf ("EMF+\tuse transformation\n", color)); + s >> transformation; + hasTransformation = true; + EMFP_DEBUG (printf ("EMF+\tm11: %f m12: %f\nEMF+\tm21: %f m22: %f\nEMF+\tdx: %f dy: %f\n", + transformation.eM11, transformation.eM12, + transformation.eM21, transformation.eM22, + transformation.eDx, transformation.eDy)); + } + if (additionalFlags & 0x08) { + s >> blendPoints; + EMFP_DEBUG (printf ("EMF+\tuse blend, points: %d\n", blendPoints)); + if( blendPoints<0 || sal_uInt32(blendPoints)>SAL_MAX_INT32/(2*sizeof(float)) ) + blendPoints = SAL_MAX_INT32/(2*sizeof(float)); + blendPositions = new float [2*blendPoints]; + blendFactors = blendPositions + blendPoints; + for (int i=0; i < blendPoints; i ++) { + s >> blendPositions [i]; + EMFP_DEBUG (printf ("EMF+\tposition[%d]: %f\n", i, blendPositions [i])); + } + for (int i=0; i < blendPoints; i ++) { + s >> blendFactors [i]; + EMFP_DEBUG (printf ("EMF+\tfactor[%d]: %f\n", i, blendFactors [i])); + } + } + + if (additionalFlags & 0x04) { + s >> colorblendPoints; + EMFP_DEBUG (printf ("EMF+\tuse color blend, points: %d\n", colorblendPoints)); + if( colorblendPoints<0 || sal_uInt32(colorblendPoints)>SAL_MAX_INT32/sizeof(float) ) + colorblendPoints = SAL_MAX_INT32/sizeof(float); + if( sal_uInt32(colorblendPoints)>SAL_MAX_INT32/sizeof(::Color) ) + colorblendPoints = SAL_MAX_INT32/sizeof(::Color); + colorblendPositions = new float [colorblendPoints]; + colorblendColors = new ::Color [colorblendPoints]; + for (int i=0; i < colorblendPoints; i ++) { + s >> colorblendPositions [i]; + EMFP_DEBUG (printf ("EMF+\tposition[%d]: %f\n", i, colorblendPositions [i])); + } + for (int i=0; i < colorblendPoints; i ++) { + s >> color; + colorblendColors [i] = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff); + EMFP_DEBUG (printf ("EMF+\tcolor[%d]: 0x%08x\n", i, color)); + } + } + } else { + EMFP_DEBUG (dumpWords (s, 1024)); + } + break; + } + // linear gradient + case 4: + { + s >> additionalFlags >> wrapMode; + + EMFP_DEBUG (printf ("EMF+\tlinear gradient, additional flags: 0x%02x\n", additionalFlags)); + + s >> areaX >> areaY >> areaWidth >> areaHeight; + + EMFP_DEBUG (printf ("EMF+\tarea: %f,%f - %fx%f\n", areaX, areaY, areaWidth, areaHeight)); + + sal_uInt32 color; + + s >> color; + solidColor = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff); + EMFP_DEBUG (printf ("EMF+\tfirst color: 0x%08x\n", color)); + + s >> color; + secondColor = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff); + EMFP_DEBUG (printf ("EMF+\tsecond color: 0x%08x\n", color)); + + // repeated colors, unknown meaning, see http://www.aces.uiuc.edu/~jhtodd/Metafile/MetafileRecords/ObjectBrush.html + s >> color; + s >> color; + + if (additionalFlags & 0x02) { + EMFP_DEBUG (printf ("EMF+\tuse transformation\n", color)); + s >> transformation; + hasTransformation = true; + EMFP_DEBUG (printf ("EMF+\tm11: %f m12: %f\nEMF+\tm21: %f m22: %f\nEMF+\tdx: %f dy: %f\n", + transformation.eM11, transformation.eM12, + transformation.eM21, transformation.eM22, + transformation.eDx, transformation.eDy)); + } + if (additionalFlags & 0x08) { + s >> blendPoints; + EMFP_DEBUG (printf ("EMF+\tuse blend, points: %d\n", blendPoints)); + if( blendPoints<0 || sal_uInt32(blendPoints)>SAL_MAX_INT32/(2*sizeof(float)) ) + blendPoints = SAL_MAX_INT32/(2*sizeof(float)); + blendPositions = new float [2*blendPoints]; + blendFactors = blendPositions + blendPoints; + for (int i=0; i < blendPoints; i ++) { + s >> blendPositions [i]; + EMFP_DEBUG (printf ("EMF+\tposition[%d]: %f\n", i, blendPositions [i])); + } + for (int i=0; i < blendPoints; i ++) { + s >> blendFactors [i]; + EMFP_DEBUG (printf ("EMF+\tfactor[%d]: %f\n", i, blendFactors [i])); + } + } + + if (additionalFlags & 0x04) { + s >> colorblendPoints; + EMFP_DEBUG (printf ("EMF+\tuse color blend, points: %d\n", colorblendPoints)); + if( colorblendPoints<0 || sal_uInt32(colorblendPoints)>SAL_MAX_INT32/sizeof(float) ) + colorblendPoints = SAL_MAX_INT32/sizeof(float); + if( sal_uInt32(colorblendPoints)>SAL_MAX_INT32/sizeof(::Color) ) + colorblendPoints = sal_uInt32(SAL_MAX_INT32)/sizeof(::Color); + colorblendPositions = new float [colorblendPoints]; + colorblendColors = new ::Color [colorblendPoints]; + for (int i=0; i < colorblendPoints; i ++) { + s >> colorblendPositions [i]; + EMFP_DEBUG (printf ("EMF+\tposition[%d]: %f\n", i, colorblendPositions [i])); + } + for (int i=0; i < colorblendPoints; i ++) { + s >> color; + colorblendColors [i] = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff); + EMFP_DEBUG (printf ("EMF+\tcolor[%d]: 0x%08x\n", i, color)); + } + } + + break; + } + default: + EMFP_DEBUG (printf ("EMF+\tunhandled brush type: %d\n", type)); + } + } + }; + + struct EMFPPen : public EMFPBrush + { + XForm transformation; + float width; + sal_Int32 startCap; + sal_Int32 endCap; + sal_Int32 lineJoin; + float mitterLimit; + sal_Int32 dashStyle; + sal_Int32 dashCap; + float dashOffset; + sal_Int32 dashPatternLen; + float *dashPattern; + sal_Int32 alignment; + sal_Int32 compoundArrayLen; + float *compoundArray; + sal_Int32 customStartCapLen; + sal_uInt8 *customStartCap; + sal_Int32 customEndCapLen; + sal_uInt8 *customEndCap; + + public: + EMFPPen () : EMFPBrush () + { + } + + void SetStrokeAttributes (rendering::StrokeAttributes& rStrokeAttributes, ImplRenderer& rR, const OutDevState& rState) + { + rStrokeAttributes.StrokeWidth = (rState.mapModeTransform * rR.MapSize (width, 0)).getX (); + } + + void Read (SvStream& s, ImplRenderer& rR, sal_Int32, sal_Int32 ) + { + sal_uInt32 header, unknown, penFlags, unknown2; + int i; + + s >> header >> unknown >> penFlags >> unknown2 >> width; + + EMFP_DEBUG (printf ("EMF+\tpen\nEMF+\theader: 0x%08x unknown: 0x%08x additional flags: 0x%08x unknown: 0x%08x width: %f\n", header, unknown, penFlags, unknown2, width)); + + if (penFlags & 1) + s >> transformation; + + if (penFlags & 2) + s >> startCap; + else + startCap = 0; + + if (penFlags & 4) + s >> endCap; + else + endCap = 0; + + if (penFlags & 8) + s >> lineJoin; + else + lineJoin = 0; + + if (penFlags & 16) + s >> mitterLimit; + else + mitterLimit = 0; + + if (penFlags & 32) + s >> dashStyle; + else + dashStyle = 0; + + if (penFlags & 64) + s >> dashCap; + else + dashCap = 0; + + if (penFlags & 128) + s >> dashOffset; + else + dashOffset = 0; + + if (penFlags & 256) { + s >> dashPatternLen; + if( dashPatternLen<0 || sal_uInt32(dashPatternLen)>SAL_MAX_INT32/sizeof(float) ) + dashPatternLen = SAL_MAX_INT32/sizeof(float); + dashPattern = new float [dashPatternLen]; + for (i = 0; i < dashPatternLen; i++) + s >> dashPattern [i]; + } else + dashPatternLen = 0; + + if (penFlags & 512) + s >> alignment; + else + alignment = 0; + + if (penFlags & 1024) { + s >> compoundArrayLen; + if( compoundArrayLen<0 || sal_uInt32(compoundArrayLen)>SAL_MAX_INT32/sizeof(float) ) + compoundArrayLen = SAL_MAX_INT32/sizeof(float); + compoundArray = new float [compoundArrayLen]; + for (i = 0; i < compoundArrayLen; i++) + s >> compoundArray [i]; + } else + compoundArrayLen = 0; + + if (penFlags & 2048) { + s >> customStartCapLen; + if( customStartCapLen<0 ) + customStartCapLen=0; + customStartCap = new sal_uInt8 [customStartCapLen]; + for (i = 0; i < customStartCapLen; i++) + s >> customStartCap [i]; + } else + customStartCapLen = 0; + + if (penFlags & 4096) { + s >> customEndCapLen; + if( customEndCapLen<0 ) + customEndCapLen=0; + customEndCap = new sal_uInt8 [customEndCapLen]; + for (i = 0; i < customEndCapLen; i++) + s >> customEndCap [i]; + } else + customEndCapLen = 0; + + EMFPBrush::Read (s, rR); + } + }; + + struct EMFPImage : public EMFPObject + { + sal_uInt32 type; + sal_Int32 width; + sal_Int32 height; + sal_Int32 stride; + sal_Int32 pixelFormat; + Graphic graphic; + + + void Read (SvMemoryStream &s) + { + sal_uInt32 header, unknown; + + s >> header >> type; + + EMFP_DEBUG (printf ("EMF+\timage\nEMF+\theader: 0x%08x type: 0x%08x\n", header, type)); + + if (type == 1) { // bitmap + s >> width >> height >> stride >> pixelFormat >> unknown; + EMFP_DEBUG (printf ("EMF+\tbitmap width: %d height: %d stride: %d pixelFormat: 0x%08x\n", width, height, stride, pixelFormat)); + if (width == 0) { // non native formats + GraphicFilter filter; + + filter.ImportGraphic (graphic, String (), s); + EMFP_DEBUG (printf ("EMF+\tbitmap width: %d height: %d\n", graphic.GetBitmap ().GetSizePixel ().Width (), graphic.GetBitmap ().GetSizePixel ().Height ())); + } + + } else if (type == 2) { + sal_Int32 mfType, mfSize; + + s >> mfType >> mfSize; + EMFP_DEBUG (printf ("EMF+\tmetafile type: %d dataSize: %d\n", mfType, mfSize)); + + GraphicFilter filter; + SvMemoryStream mfStream (((char *)s.GetData()) + s.Tell(), mfSize, STREAM_READ); + + filter.ImportGraphic (graphic, String (), mfStream); + + // debug code - write the stream to debug file /tmp/emf-stream.emf + EMFP_DEBUG(mfStream.Seek(0); + SvFileStream file( UniString::CreateFromAscii( "/tmp/emf-embedded-stream.emf" ), STREAM_WRITE | STREAM_TRUNC ); + + mfStream >> file; + file.Flush(); + file.Close()); + } + } + }; + + struct EMFPFont : public EMFPObject + { + sal_uInt32 version; + float emSize; + sal_uInt32 sizeUnit; + sal_Int32 fontFlags; + rtl::OUString family; + + void Read (SvMemoryStream &s) + { + sal_uInt32 header; + sal_uInt32 reserved; + sal_uInt32 length; + + s >> header >> emSize >> sizeUnit >> fontFlags >> reserved >> length; + + OSL_ASSERT( ( header >> 12 ) == 0xdbc01 ); + + EMFP_DEBUG (printf ("EMF+\tfont\nEMF+\theader: 0x%08x version: 0x%08x size: %f unit: 0x%08x\n", header >> 12, header & 0x1fff, emSize, sizeUnit)); + EMFP_DEBUG (printf ("EMF+\tflags: 0x%08x reserved: 0x%08x length: 0x%08x\n", fontFlags, reserved, length)); + + if( length > 0 && length < 0x4000 ) { + sal_Unicode *chars = (sal_Unicode *) alloca( sizeof( sal_Unicode ) * length ); + + for( sal_uInt32 i = 0; i < length; i++ ) + s >> chars[ i ]; + + family = ::rtl::OUString( chars, length ); + EMFP_DEBUG (printf ("EMF+\tfamily: %s\n", rtl::OUStringToOString( family, RTL_TEXTENCODING_UTF8).getStr())); + } + } + }; + + void ImplRenderer::ReadRectangle (SvStream& s, float& x, float& y, float &width, float& height, sal_uInt32 flags) + { + if (flags & 0x4000) { + sal_Int16 ix, iy, iw, ih; + + s >> ix >> iy >> iw >> ih; + + x = ix; + y = iy; + width = iw; + height = ih; + } else + s >> x >> y >> width >> height; + } + + void ImplRenderer::ReadPoint (SvStream& s, float& x, float& y, sal_uInt32 flags) + { + if (flags & 0x4000) { + sal_Int16 ix, iy; + + s >> ix >> iy; + + x = ix; + y = iy; + } else + s >> x >> y; + } + + void ImplRenderer::MapToDevice (double& x, double& y) + { + // TODO: other untis + x = 100*nMmX*x/nPixX; + y = 100*nMmY*y/nPixY; + } + + ::basegfx::B2DPoint ImplRenderer::Map (::basegfx::B2DPoint& p) + { + return Map (p.getX (), p.getY ()); + } + + ::basegfx::B2DPoint ImplRenderer::Map (double ix, double iy) + { + double x, y; + + x = ix*aWorldTransform.eM11 + iy*aWorldTransform.eM21 + aWorldTransform.eDx; + y = ix*aWorldTransform.eM12 + iy*aWorldTransform.eM22 + aWorldTransform.eDy; + + MapToDevice (x, y); + + x -= nFrameLeft; + y -= nFrameTop; + + x *= aBaseTransform.eM11; + y *= aBaseTransform.eM22; + + return ::basegfx::B2DPoint (x, y); + } + + ::basegfx::B2DSize ImplRenderer::MapSize (double iwidth, double iheight) + { + double w, h; + + w = iwidth*aWorldTransform.eM11 + iheight*aWorldTransform.eM21; + h = iwidth*aWorldTransform.eM12 + iheight*aWorldTransform.eM22; + + MapToDevice (w, h); + + w *= aBaseTransform.eM11; + h *= aBaseTransform.eM22; + + return ::basegfx::B2DSize (w, h); + } + + ::basegfx::B2DRange ImplRenderer::MapRectangle (double ix, double iy, double iwidth, double iheight) + { + double x, y, w, h; + + x = ix*aWorldTransform.eM11 + iy*aWorldTransform.eM21 + aWorldTransform.eDx; + y = ix*aWorldTransform.eM12 + iy*aWorldTransform.eM22 + aWorldTransform.eDy; + w = iwidth*aWorldTransform.eM11 + iheight*aWorldTransform.eM21; + h = iwidth*aWorldTransform.eM12 + iheight*aWorldTransform.eM22; + + MapToDevice (x, y); + MapToDevice (w, h); + + x -= nFrameLeft; + y -= nFrameTop; + + x *= aBaseTransform.eM11; + y *= aBaseTransform.eM22; + w *= aBaseTransform.eM11; + h *= aBaseTransform.eM22; + + return ::basegfx::B2DRange (x, y, x + w, y + h); + } + +#define COLOR(x) \ + ::vcl::unotools::colorToDoubleSequence( ::Color (0xff - (x >> 24), \ + (x >> 16) & 0xff, \ + (x >> 8) & 0xff, \ + x & 0xff), \ + rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace()); +#define SET_FILL_COLOR(x) \ + rState.fillColor = COLOR(x); +#define SET_LINE_COLOR(x) \ + rState.lineColor = COLOR(x); +#define SET_TEXT_COLOR(x) \ + rState.textColor = COLOR(x); + + void ImplRenderer::EMFPPlusFillPolygon (::basegfx::B2DPolyPolygon& polygon, const ActionFactoryParameters& rParms, + OutDevState& rState, const CanvasSharedPtr& rCanvas, bool isColor, sal_uInt32 brushIndexOrColor) + { + ::basegfx::B2DPolyPolygon localPolygon (polygon); + + EMFP_DEBUG (printf ("EMF+\tfill polygon\n")); + + localPolygon.transform( rState.mapModeTransform ); + + ActionSharedPtr pPolyAction; + + if (isColor) { + EMFP_DEBUG (printf ("EMF+\t\tcolor fill\n")); + + rState.isFillColorSet = true; + rState.isLineColorSet = false; + SET_FILL_COLOR(brushIndexOrColor); + + pPolyAction = ActionSharedPtr ( internal::PolyPolyActionFactory::createPolyPolyAction( localPolygon, rParms.mrCanvas, rState ) ); + + } else { + rState.isFillColorSet = true; + // extract UseBrush + EMFPBrush* brush = (EMFPBrush*) aObjects [brushIndexOrColor]; + EMFP_DEBUG (printf ("EMF+\tbrush fill slot: %d (type: %d)\n", brushIndexOrColor, brush->GetType ())); + + // give up in case something wrong happened + if( !brush ) + return; + + rState.isFillColorSet = false; + rState.isLineColorSet = false; + + if (brush->type == 3 || brush->type == 4) { + + if (brush->type == 3 && !(brush->additionalFlags & 0x1)) + return; // we are unable to parse these brushes yet + + ::basegfx::B2DHomMatrix aTextureTransformation; + ::basegfx::B2DHomMatrix aWorldTransformation; + ::basegfx::B2DHomMatrix aBaseTransformation; + rendering::Texture aTexture; + + aWorldTransformation.set (0, 0, aWorldTransform.eM11); + aWorldTransformation.set (0, 1, aWorldTransform.eM21); + aWorldTransformation.set (0, 2, aWorldTransform.eDx); + aWorldTransformation.set (1, 0, aWorldTransform.eM12); + aWorldTransformation.set (1, 1, aWorldTransform.eM22); + aWorldTransformation.set (1, 2, aWorldTransform.eDy); + + aBaseTransformation.set (0, 0, aBaseTransform.eM11); + aBaseTransformation.set (0, 1, aBaseTransform.eM21); + aBaseTransformation.set (0, 2, aBaseTransform.eDx); + aBaseTransformation.set (1, 0, aBaseTransform.eM12); + aBaseTransformation.set (1, 1, aBaseTransform.eM22); + aBaseTransformation.set (1, 2, aBaseTransform.eDy); + + if (brush->type == 4) { + aTextureTransformation.scale (brush->areaWidth, brush->areaHeight); + aTextureTransformation.translate (brush->areaX, brush->areaY); + } else { + aTextureTransformation.translate (-0.5, -0.5); + aTextureTransformation.scale (brush->areaWidth, brush->areaHeight); + aTextureTransformation.translate (brush->areaX,brush->areaY); + } + + if (brush->hasTransformation) { + ::basegfx::B2DHomMatrix aTransformation; + + aTransformation.set (0, 0, brush->transformation.eM11); + aTransformation.set (0, 1, brush->transformation.eM21); + aTransformation.set (0, 2, brush->transformation.eDx); + aTransformation.set (1, 0, brush->transformation.eM12); + aTransformation.set (1, 1, brush->transformation.eM22); + aTransformation.set (1, 2, brush->transformation.eDy); + + aTextureTransformation *= aTransformation; + } + + aTextureTransformation *= aWorldTransformation; + aTextureTransformation.scale (100.0*nMmX/nPixX, 100.0*nMmY/nPixY); + aTextureTransformation.translate (-nFrameLeft, -nFrameTop); + aTextureTransformation *= rState.mapModeTransform; + aTextureTransformation *= aBaseTransformation; + + aTexture.RepeatModeX = rendering::TexturingMode::CLAMP; + aTexture.RepeatModeY = rendering::TexturingMode::CLAMP; + aTexture.Alpha = 1.0; + + basegfx::ODFGradientInfo aGradInfo; + rtl::OUString aGradientService; + + const uno::Sequence< double > aStartColor( + ::vcl::unotools::colorToDoubleSequence( brush->solidColor, + rParms.mrCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() ) ); + const uno::Sequence< double > aEndColor( + ::vcl::unotools::colorToDoubleSequence( brush->secondColor, + rParms.mrCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() ) ); + uno::Sequence< uno::Sequence < double > > aColors (2); + uno::Sequence< double > aStops (2); + + if (brush->blendPositions) { + EMFP_DEBUG (printf ("EMF+\t\tuse blend\n")); + aColors.realloc (brush->blendPoints); + aStops.realloc (brush->blendPoints); + int length = aStartColor.getLength (); + uno::Sequence< double > aColor (length); + + OSL_ASSERT (length == aEndColor.getLength()); + + for (int i = 0; i < brush->blendPoints; i++) { + aStops[i] = brush->blendPositions [i]; + + for (int j = 0; j < length; j++) { + if (brush->type == 4) { +// // gamma correction +// if (brush->additionalFlags & 0x80) +// aColor [j] = pow (aStartColor [j]*(1 - brush->blendFactors[i]) + aEndColor [j]*brush->blendFactors[i], 1/2.2); +// else + aColor [j] = aStartColor [j]*(1 - brush->blendFactors[i]) + aEndColor [j]*brush->blendFactors[i]; + } else + aColor [j] = aStartColor [j]*brush->blendFactors[i] + aEndColor [j]*(1 - brush->blendFactors[i]); + } + + aColors[i] = aColor; + } + } else if (brush->colorblendPositions) { + EMFP_DEBUG (printf ("EMF+\t\tuse color blend\n")); + aColors.realloc (brush->colorblendPoints); + aStops.realloc (brush->colorblendPoints); + + for (int i = 0; i < brush->colorblendPoints; i++) { + aStops[i] = brush->colorblendPositions [i]; + aColors[(brush->type == 4) ? i : brush->colorblendPoints - 1 - i] = ::vcl::unotools::colorToDoubleSequence( brush->colorblendColors [i], + rParms.mrCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() ); + } + } else { + aStops[0] = 0.0; + aStops[1] = 1.0; + + if (brush->type == 4) { + aColors[0] = aStartColor; + aColors[1] = aEndColor; + } else { + aColors[1] = aStartColor; + aColors[0] = aEndColor; + } + } + + EMFP_DEBUG (printf ("EMF+\t\tset gradient\n")); + basegfx::B2DRange aBoundsRectangle (0, 0, 1, 1); + if (brush->type == 4) { + aGradientService = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("LinearGradient")); + basegfx::tools::createLinearODFGradientInfo( aGradInfo, + aBoundsRectangle, + aStops.getLength(), + 0, + 0 ); + + } else { + aGradientService = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("EllipticalGradient")); + basegfx::tools::createEllipticalODFGradientInfo( aGradInfo, + aBoundsRectangle, + ::basegfx::B2DVector( 0, 0 ), + aStops.getLength(), + 0, + 0 ); + } + + uno::Reference< lang::XMultiServiceFactory > xFactory( + rParms.mrCanvas->getUNOCanvas()->getDevice()->getParametricPolyPolygonFactory() ); + + if( xFactory.is() ) { + uno::Sequence<uno::Any> args( 3 ); + beans::PropertyValue aProp; + aProp.Name = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Colors")); + aProp.Value <<= aColors; + args[0] <<= aProp; + aProp.Name = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Stops")); + aProp.Value <<= aStops; + args[1] <<= aProp; + aProp.Name = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AspectRatio")); + aProp.Value <<= static_cast<sal_Int32>(1); + args[2] <<= aProp; + + aTexture.Gradient.set( + xFactory->createInstanceWithArguments( aGradientService, + args ), + uno::UNO_QUERY); + } + + ::basegfx::unotools::affineMatrixFromHomMatrix( aTexture.AffineTransform, + aTextureTransformation ); + + if( aTexture.Gradient.is() ) + pPolyAction = + ActionSharedPtr ( internal::PolyPolyActionFactory::createPolyPolyAction( localPolygon, + rParms.mrCanvas, + rState, + aTexture ) ); + } + } + + if( pPolyAction ) + { + EMFP_DEBUG (printf ("EMF+\t\tadd poly action\n")); + + maActions.push_back( + MtfAction( + pPolyAction, + rParms.mrCurrActionIndex ) ); + + rParms.mrCurrActionIndex += pPolyAction->getActionCount()-1; + } + } + + void ImplRenderer::processObjectRecord(SvMemoryStream& rObjectStream, sal_uInt16 flags) + { + EMFP_DEBUG (sal_uInt32 objectLen); + sal_uInt32 index; + + EMFP_DEBUG (printf ("EMF+ Object slot: %hd flags: %hx\n", flags & 0xff, flags & 0xff00)); + + index = flags & 0xff; + if (aObjects [index] != NULL) { + delete aObjects [index]; + aObjects [index] = NULL; + } + + switch (flags & 0x7f00) { + case EmfPlusObjectTypeBrush: + { + EMFPBrush *brush; + aObjects [index] = brush = new EMFPBrush (); + brush->Read (rObjectStream, *this); + + break; + } + case EmfPlusObjectTypePen: + { + EMFPPen *pen; + aObjects [index] = pen = new EMFPPen (); + pen->Read (rObjectStream, *this, nHDPI, nVDPI); + + break; + } + case EmfPlusObjectTypePath: + sal_uInt32 header, pathFlags; + sal_Int32 points; + + rObjectStream >> header >> points >> pathFlags; + + EMFP_DEBUG (printf ("EMF+\tpath\n")); + EMFP_DEBUG (printf ("EMF+\theader: 0x%08x points: %d additional flags: 0x%08x\n", header, points, pathFlags)); + + EMFPPath *path; + aObjects [index] = path = new EMFPPath (points); + path->Read (rObjectStream, pathFlags, *this); + + break; + case EmfPlusObjectTypeRegion: { + EMFPRegion *region; + + aObjects [index] = region = new EMFPRegion (); + region->Read (rObjectStream); + + break; + } + case EmfPlusObjectTypeImage: + { + EMFPImage *image; + aObjects [index] = image = new EMFPImage (); + image->Read (rObjectStream); + + break; + } + case EmfPlusObjectTypeFont: + { + EMFPFont *font; + aObjects [index] = font = new EMFPFont (); + font->Read (rObjectStream); + + break; + } + default: + EMFP_DEBUG (printf ("EMF+\tObject unhandled flags: 0x%04x\n", flags & 0xff00)); + break; + } + } + + void ImplRenderer::processEMFPlus( MetaCommentAction* pAct, const ActionFactoryParameters& rFactoryParms, + OutDevState& rState, const CanvasSharedPtr& rCanvas ) + { + sal_uInt32 length = pAct->GetDataSize (); + SvMemoryStream rMF ((void*) pAct->GetData (), length, STREAM_READ); + + length -= 4; + + while (length > 0) { + sal_uInt16 type, flags; + sal_uInt32 size, dataSize; + sal_uInt32 next; + + rMF >> type >> flags >> size >> dataSize; + + next = rMF.Tell() + ( size - 12 ); + + EMFP_DEBUG (printf ("EMF+ record size: %d type: %04hx flags: %04hx data size: %d\n", size, type, flags, dataSize)); + + if (type == EmfPlusRecordTypeObject && ((mbMultipart && (flags & 0x7fff) == (mMFlags & 0x7fff)) || (flags & 0x8000))) { + if (!mbMultipart) { + mbMultipart = true; + mMFlags = flags; + mMStream.Seek(0); + } + + // 1st 4 bytes are unknown + mMStream.Write (((const char *)rMF.GetData()) + rMF.Tell() + 4, dataSize - 4); + EMFP_DEBUG (printf ("EMF+ read next object part size: %d type: %04hx flags: %04hx data size: %d\n", size, type, flags, dataSize)); + } else { + if (mbMultipart) { + EMFP_DEBUG (printf ("EMF+ multipart record flags: %04hx\n", mMFlags)); + mMStream.Seek (0); + processObjectRecord (mMStream, mMFlags); + } + mbMultipart = false; + } + + if (type != EmfPlusRecordTypeObject || !(flags & 0x8000)) + switch (type) { + case EmfPlusRecordTypeHeader: + sal_uInt32 header, version; + + rMF >> header >> version >> nHDPI >> nVDPI; + + EMFP_DEBUG (printf ("EMF+ Header\n")); + EMFP_DEBUG (printf ("EMF+\theader: 0x%08x version: %d horizontal DPI: %d vertical DPI: %d dual: %d\n", header, version, nHDPI, nVDPI, flags & 1)); + + break; + case EmfPlusRecordTypeEndOfFile: + EMFP_DEBUG (printf ("EMF+ EndOfFile\n")); + break; + case EmfPlusRecordTypeGetDC: + EMFP_DEBUG (printf ("EMF+ GetDC\n")); + EMFP_DEBUG (printf ("EMF+\talready used in svtools wmf/emf filter parser\n")); + break; + case EmfPlusRecordTypeObject: + processObjectRecord (rMF, flags); + break; + case EmfPlusRecordTypeFillPath: + { + sal_uInt32 index = flags & 0xff; + sal_uInt32 brushIndexOrColor; + + rMF >> brushIndexOrColor; + + EMFP_DEBUG (printf ("EMF+ FillPath slot: %d\n", index)); + + EMFPPlusFillPolygon (((EMFPPath*) aObjects [index])->GetPolygon (*this), rFactoryParms, rState, rCanvas, flags & 0x8000, brushIndexOrColor); + } + break; + case EmfPlusRecordTypeFillRects: + { + EMFP_DEBUG (printf ("EMF+ FillRects\n")); + + sal_uInt32 brushIndexOrColor; + sal_Int32 rectangles; + ::basegfx::B2DPolygon polygon; + + rMF >> brushIndexOrColor >> rectangles; + + EMFP_DEBUG (printf ("EMF+\t%s: 0x%08x\n", (flags & 0x8000) ? "color" : "brush index", brushIndexOrColor)); + + for (int i=0; i < rectangles; i++) { + if (flags & 0x4000) { + /* 16bit integers */ + sal_Int16 x, y, width, height; + + rMF >> x >> y >> width >> height; + + polygon.append (Map (x, y)); + polygon.append (Map (x + width, y)); + polygon.append (Map (x + width, y + height)); + polygon.append (Map (x, y + height)); + + EMFP_DEBUG (printf ("EMF+\trectangle: %d,%d %dx%d\n", x, y, width, height)); + } else { + /* Single's */ + float x, y, width, height; + + rMF >> x >> y >> width >> height; + + polygon.append (Map (x, y)); + polygon.append (Map (x + width, y)); + polygon.append (Map (x + width, y + height)); + polygon.append (Map (x, y + height)); + + EMFP_DEBUG (printf ("EMF+\trectangle: %f,%f %fx%f\n", x, y, width, height)); + } + + ::basegfx::B2DPolyPolygon polyPolygon (polygon); + + EMFPPlusFillPolygon (polyPolygon, rFactoryParms, rState, rCanvas, flags & 0x8000, brushIndexOrColor); + } + break; + } + case EmfPlusRecordTypeFillPolygon: + { + EMFP_DEBUG (sal_uInt8 index = flags & 0xff); + sal_uInt32 brushIndexOrColor; + EMFP_DEBUG (sal_Int32 brushIndex); + sal_Int32 points; + EMFP_DEBUG (sal_uInt32 color); + EMFP_DEBUG (sal_uInt16 transparency = 0); + + rMF >> brushIndexOrColor; + rMF >> points; + + EMFP_DEBUG (printf ("EMF+ FillPolygon in slot: %d points: %d\n", index, points)); + EMFP_DEBUG (printf ("EMF+\twith solid color (ARGB): 0x%08X\n", color)); + + EMFPPath path (points, true); + path.Read (rMF, flags, *this); + + + EMFPPlusFillPolygon (path.GetPolygon (*this), rFactoryParms, rState, rCanvas, flags & 0x8000, brushIndexOrColor); + + break; + } + case EmfPlusRecordTypeDrawLines: + { + sal_uInt32 index = flags & 0xff; + sal_uInt32 points; + + rMF >> points; + + EMFP_DEBUG (printf ("EMF+ DrawLines in slot: %d points: %d\n", index, points)); + + EMFPPath path (points, true); + path.Read (rMF, flags, *this); + + EMFPPen* pen = (EMFPPen*) aObjects [index]; + + rState.isFillColorSet = false; + rState.isLineColorSet = true; + rState.lineColor = ::vcl::unotools::colorToDoubleSequence (pen->GetColor (), + rCanvas->getUNOCanvas ()->getDevice()->getDeviceColorSpace() ); + ::basegfx::B2DPolyPolygon& polygon (path.GetPolygon (*this)); + + polygon.transform( rState.mapModeTransform ); + + rendering::StrokeAttributes aStrokeAttributes; + + pen->SetStrokeAttributes (aStrokeAttributes, *this, rState); + + ActionSharedPtr pPolyAction( + internal::PolyPolyActionFactory::createPolyPolyAction( + polygon, rFactoryParms.mrCanvas, rState, aStrokeAttributes ) ); + + if( pPolyAction ) + { + maActions.push_back( + MtfAction( + pPolyAction, + rFactoryParms.mrCurrActionIndex ) ); + + rFactoryParms.mrCurrActionIndex += pPolyAction->getActionCount()-1; + } + + break; + } + case EmfPlusRecordTypeDrawPath: + { + sal_uInt32 penIndex; + + rMF >> penIndex; + + EMFP_DEBUG (printf ("EMF+ DrawPath\n")); + EMFP_DEBUG (printf ("EMF+\tpen: %d\n", penIndex)); + + EMFPPath* path = (EMFPPath*) aObjects [flags & 0xff]; + EMFPPen* pen = (EMFPPen*) aObjects [penIndex]; + + rState.isFillColorSet = false; + rState.isLineColorSet = true; + rState.lineColor = ::vcl::unotools::colorToDoubleSequence (pen->GetColor (), + rCanvas->getUNOCanvas ()->getDevice()->getDeviceColorSpace()); + ::basegfx::B2DPolyPolygon& polygon (path->GetPolygon (*this)); + + polygon.transform( rState.mapModeTransform ); + rendering::StrokeAttributes aStrokeAttributes; + + pen->SetStrokeAttributes (aStrokeAttributes, *this, rState); + + ActionSharedPtr pPolyAction( + internal::PolyPolyActionFactory::createPolyPolyAction( + polygon, rFactoryParms.mrCanvas, rState, aStrokeAttributes ) ); + + if( pPolyAction ) + { + maActions.push_back( + MtfAction( + pPolyAction, + rFactoryParms.mrCurrActionIndex ) ); + + rFactoryParms.mrCurrActionIndex += pPolyAction->getActionCount()-1; + } + break; + } + case EmfPlusRecordTypeDrawImagePoints: + { + sal_uInt32 attrIndex; + sal_Int32 sourceUnit; + + rMF >> attrIndex >> sourceUnit; + + EMFP_DEBUG (printf ("EMF+ DrawImagePoints attributes index: %d source unit: %d\n", attrIndex, sourceUnit)); + EMFP_DEBUG (printf ("EMF+\tTODO: use image attributes\n")); + + if (sourceUnit == 2 && aObjects [flags & 0xff]) { // we handle only GraphicsUnit.Pixel now + EMFPImage& image = *(EMFPImage *) aObjects [flags & 0xff]; + float sx, sy, sw, sh; + sal_Int32 unknown; + + ReadRectangle (rMF, sx, sy, sw, sh); + + rMF >> unknown; + + EMFP_DEBUG (printf ("EMF+ DrawImagePoints source rectangle: %f,%f %fx%f unknown: 0x%08x\n", sx, sy, sw, sh, unknown)); + + if (unknown == 3) { // it probably means number of points defining destination rectangle + float x1, y1, x2, y2, x3, y3; + + ReadPoint (rMF, x1, y1); + ReadPoint (rMF, x2, y2); + ReadPoint (rMF, x3, y3); + + BitmapEx aBmp( image.graphic.GetBitmapEx () ); + const Rectangle aCropRect (::vcl::unotools::pointFromB2DPoint (Map (sx, sy)), + ::vcl::unotools::sizeFromB2DSize (MapSize(sw, sh))); + aBmp.Crop( aCropRect ); + + + Size aSize( aBmp.GetSizePixel() ); + if( aSize.Width() > 0 && aSize.Height() > 0 ) { + ActionSharedPtr pBmpAction ( + internal::BitmapActionFactory::createBitmapAction ( + aBmp, + rState.mapModeTransform * Map (x1, y1), + rState.mapModeTransform * MapSize(x2 - x1, y3 - y1), + rCanvas, + rState)); + + if( pBmpAction ) { + maActions.push_back( MtfAction( pBmpAction, + rFactoryParms.mrCurrActionIndex ) ); + + rFactoryParms.mrCurrActionIndex += pBmpAction->getActionCount()-1; + } + } else { + EMFP_DEBUG (printf ("EMF+ warning: empty bitmap\n")); + } + } else { + EMFP_DEBUG (printf ("EMF+ DrawImagePoints TODO (fixme)\n")); + } + } + break; + } + case EmfPlusRecordTypeDrawString: + EMFP_DEBUG (printf ("EMF+ DrawString\n")); + EMFP_DEBUG (printf ("EMF+\tTODO\n")); + break; + case EmfPlusRecordTypeSetPageTransform: + rMF >> fPageScale; + + EMFP_DEBUG (printf ("EMF+ SetPageTransform\n")); + EMFP_DEBUG (printf ("EMF+\tscale: %f unit: %d\n", fPageScale, flags)); + EMFP_DEBUG (printf ("EMF+\tTODO\n")); + break; + case EmfPlusRecordTypeSetRenderingOrigin: + rMF >> nOriginX >> nOriginY; + EMFP_DEBUG (printf ("EMF+ SetRenderingOrigin\n")); + EMFP_DEBUG (printf ("EMF+\torigin [x,y]: %d,%d\n", nOriginX, nOriginY)); + break; + case EmfPlusRecordTypeSetTextRenderingHint: + EMFP_DEBUG (printf ("EMF+ SetTextRenderingHint\n")); + EMFP_DEBUG (printf ("EMF+\tTODO\n")); + break; + case EmfPlusRecordTypeSetAntiAliasMode: + EMFP_DEBUG (printf ("EMF+ SetAntiAliasMode\n")); + EMFP_DEBUG (printf ("EMF+\tTODO\n")); + break; + case EmfPlusRecordTypeSetInterpolationMode: + EMFP_DEBUG (printf ("EMF+ InterpolationMode\n")); + EMFP_DEBUG (printf ("EMF+\tTODO\n")); + break; + case EmfPlusRecordTypeSetPixelOffsetMode: + EMFP_DEBUG (printf ("EMF+ SetPixelOffsetMode\n")); + EMFP_DEBUG (printf ("EMF+\tTODO\n")); + break; + case EmfPlusRecordTypeSetCompositingQuality: + EMFP_DEBUG (printf ("EMF+ SetCompositingQuality\n")); + EMFP_DEBUG (printf ("EMF+\tTODO\n")); + break; + case EmfPlusRecordTypeSave: + EMFP_DEBUG (printf ("EMF+ Save\n")); + EMFP_DEBUG (printf ("EMF+\tTODO\n")); + break; + case EmfPlusRecordTypeSetWorldTransform: { + EMFP_DEBUG (printf ("EMF+ SetWorldTransform\n")); + XForm transform; + rMF >> transform; + aWorldTransform.Set (transform); + EMFP_DEBUG (printf ("EMF+\tm11: %f m12: %f\nEMF+\tm21: %f m22: %f\nEMF+\tdx: %f dy: %f\n", + aWorldTransform.eM11, aWorldTransform.eM12, + aWorldTransform.eM21, aWorldTransform.eM22, + aWorldTransform.eDx, aWorldTransform.eDy)); + break; + } + case EmfPlusRecordTypeResetWorldTransform: + EMFP_DEBUG (printf ("EMF+ ResetWorldTransform\n")); + aWorldTransform.SetIdentity (); + break; + case EmfPlusRecordTypeMultiplyWorldTransform: { + EMFP_DEBUG (printf ("EMF+ MultiplyWorldTransform\n")); + XForm transform; + rMF >> transform; + + EMFP_DEBUG (printf ("EMF+\tmatrix m11: %f m12: %f\nEMF+\tm21: %f m22: %f\nEMF+\tdx: %f dy: %f\n", + transform.eM11, transform.eM12, + transform.eM21, transform.eM22, + transform.eDx, transform.eDy)); + + if (flags & 0x2000) // post multiply + aWorldTransform.Multiply (transform); + else { // pre multiply + transform.Multiply (aWorldTransform); + aWorldTransform.Set (transform); + } + EMFP_DEBUG (printf ("EMF+\tresult world matrix m11: %f m12: %f\nEMF+\tm21: %f m22: %f\nEMF+\tdx: %f dy: %f\n", + aWorldTransform.eM11, aWorldTransform.eM12, + aWorldTransform.eM21, aWorldTransform.eM22, + aWorldTransform.eDx, aWorldTransform.eDy)); + break; + } + case EmfPlusRecordTypeSetClipPath: + { + EMFP_DEBUG (printf ("EMF+ SetClipPath\n")); + EMFP_DEBUG (printf ("EMF+\tpath in slot: %d\n", flags & 0xff)); + + EMFPPath& path = *(EMFPPath*) aObjects [flags & 0xff]; + ::basegfx::B2DPolyPolygon& clipPoly (path.GetPolygon (*this)); + + clipPoly.transform (rState.mapModeTransform); + updateClipping (clipPoly, rFactoryParms, false); + + break; + } + case EmfPlusRecordTypeSetClipRegion: { + EMFP_DEBUG (printf ("EMF+ SetClipRegion\n")); + EMFP_DEBUG (printf ("EMF+\tregion in slot: %d combine mode: %d\n", flags & 0xff, (flags & 0xff00) >> 8)); + EMFPRegion& region = *(EMFPRegion*) aObjects [flags & 0xff]; + + // reset clip + if (region.parts == 0 && region.initialState == EmfPlusRegionInitialStateInfinite) { + updateClipping (::basegfx::B2DPolyPolygon (), rFactoryParms, false); + } else { + EMFP_DEBUG (printf ("EMF+\tTODO\n")); + } + break; + } + case EmfPlusRecordTypeDrawDriverString: { + EMFP_DEBUG (printf ("EMF+ DrawDriverString, flags: 0x%04x\n", flags)); + sal_uInt32 brushIndexOrColor; + sal_uInt32 optionFlags; + sal_uInt32 hasMatrix; + sal_uInt32 glyphsCount; + + rMF >> brushIndexOrColor >> optionFlags >> hasMatrix >> glyphsCount; + + EMFP_DEBUG (printf ("EMF+\t%s: 0x%08x\n", (flags & 0x8000) ? "color" : "brush index", brushIndexOrColor)); + EMFP_DEBUG (printf ("EMF+\toption flags: 0x%08x\n", optionFlags)); + EMFP_DEBUG (printf ("EMF+\thas matrix: %d\n", hasMatrix)); + EMFP_DEBUG (printf ("EMF+\tglyphs: %d\n", glyphsCount)); + + if( ( optionFlags & 1 ) && glyphsCount > 0 ) { + sal_uInt16 *chars = new sal_uInt16[glyphsCount]; + float *charsPosX = new float[glyphsCount]; + float *charsPosY = new float[glyphsCount]; + + for( sal_uInt32 i=0; i<glyphsCount; i++) { + rMF >> chars[i]; + EMFP_DEBUG (printf ("EMF+\tglyph[%d]: 0x%04x\n", + i, chars[i])); + } + for( sal_uInt32 i=0; i<glyphsCount; i++) { + rMF >> charsPosX[i] >> charsPosY[i]; + EMFP_DEBUG (printf ("EMF+\tglyphPosition[%d]: %f, %f\n", i, charsPosX[i], charsPosY[i])); + } + + XForm transform; + if( hasMatrix ) { + rMF >> transform; + EMFP_DEBUG (printf ("EMF+\tmatrix:: %f, %f, %f, %f, %f, %f\n", transform.eM11, transform.eM12, transform.eM21, transform.eM22, transform.eDx, transform.eDy)); + } + + // create and add the text action + XubString text( chars, glyphsCount ); + + EMFPFont *font = (EMFPFont*) aObjects[ flags & 0xff ]; + + rendering::FontRequest aFontRequest; + aFontRequest.FontDescription.FamilyName = font->family; + aFontRequest.CellSize = (rState.mapModeTransform*MapSize( font->emSize, 0 )).getX(); + rState.xFont = rFactoryParms.mrCanvas->getUNOCanvas()->createFont( aFontRequest, + uno::Sequence< beans::PropertyValue >(), + geometry::Matrix2D() ); + if( flags & 0x8000 ) + SET_TEXT_COLOR(brushIndexOrColor); + + ActionSharedPtr pTextAction( + TextActionFactory::createTextAction( + ::vcl::unotools::pointFromB2DPoint ( Map( charsPosX[0], charsPosY[0] ) ), + ::Size(), + ::Color(), + ::Size(), + ::Color(), + text, + 0, + glyphsCount, + NULL, + rFactoryParms.mrVDev, + rFactoryParms.mrCanvas, + rState, + rFactoryParms.mrParms, + false ) ); + + if( pTextAction ) + { + EMFP_DEBUG (printf ("EMF+\t\tadd text action\n")); + + maActions.push_back( + MtfAction( + pTextAction, + rFactoryParms.mrCurrActionIndex ) ); + + rFactoryParms.mrCurrActionIndex += pTextAction->getActionCount()-1; + } + + delete[] chars; + delete[] charsPosX; + delete[] charsPosY; + } else { + EMFP_DEBUG (printf ("EMF+\tTODO: fonts (non-unicode glyphs chars)\n")); + } + + break; + } + default: + EMFP_DEBUG (printf ("EMF+ unhandled record type: %d\n", type)); + EMFP_DEBUG (printf ("EMF+\tTODO\n")); + } + + rMF.Seek (next); + + length -= size; + } + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/mtfrenderer/implrenderer.cxx b/cppcanvas/source/mtfrenderer/implrenderer.cxx new file mode 100644 index 000000000000..46f3e404ea8c --- /dev/null +++ b/cppcanvas/source/mtfrenderer/implrenderer.cxx @@ -0,0 +1,3242 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cppcanvas.hxx" + +#include <canvas/debug.hxx> +#include <tools/diagnose_ex.h> +#include <canvas/verbosetrace.hxx> +#include <osl/mutex.hxx> +#include <osl/mutex.hxx> +#include <vcl/svapp.hxx> +#include <rtl/logfile.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/anytostring.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <cppcanvas/canvas.hxx> +#include <com/sun/star/rendering/XGraphicDevice.hpp> +#include <com/sun/star/rendering/TexturingMode.hpp> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/geometry/RealPoint2D.hpp> +#include <com/sun/star/rendering/PanoseProportion.hpp> +#include <com/sun/star/rendering/ViewState.hpp> +#include <com/sun/star/rendering/RenderState.hpp> +#include <com/sun/star/rendering/XCanvasFont.hpp> +#include <com/sun/star/rendering/XPolyPolygon2D.hpp> +#include <com/sun/star/rendering/XCanvas.hpp> +#include <com/sun/star/rendering/PathCapType.hpp> +#include <com/sun/star/rendering/PathJoinType.hpp> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/tools/gradienttools.hxx> +#include <basegfx/numeric/ftools.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/vector/b2dsize.hxx> +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/tuple/b2dtuple.hxx> +#include <basegfx/polygon/b2dpolygonclipper.hxx> +#include <basegfx/polygon/b2dpolypolygoncutter.hxx> +#include <canvas/canvastools.hxx> +#include <vcl/canvastools.hxx> +#include <vcl/salbtype.hxx> +#include <vcl/gdimtf.hxx> +#include <vcl/metaact.hxx> +#include <vcl/virdev.hxx> +#include <vcl/metric.hxx> +#include <vcl/graphictools.hxx> +#include <tools/poly.hxx> +#include <i18npool/mslangid.hxx> +#include <implrenderer.hxx> +#include <tools.hxx> +#include <outdevstate.hxx> +#include <action.hxx> +#include <bitmapaction.hxx> +#include <lineaction.hxx> +#include <pointaction.hxx> +#include <polypolyaction.hxx> +#include <rendergraphicaction.hxx> +#include <textaction.hxx> +#include <transparencygroupaction.hxx> +#include <vector> +#include <algorithm> +#include <iterator> +#include <boost/scoped_array.hpp> +#include "mtftools.hxx" +#include "outdevstate.hxx" +#include <basegfx/matrix/b2dhommatrixtools.hxx> + +#if OSL_DEBUG_LEVEL > 1 +#define EMFP_DEBUG(x) x +#else +#define EMFP_DEBUG(x) +#endif + +using namespace ::com::sun::star; + + +// free support functions +// ====================== +namespace +{ + template < class MetaActionType > void setStateColor( MetaActionType* pAct, + bool& rIsColorSet, + uno::Sequence< double >& rColorSequence, + const cppcanvas::CanvasSharedPtr& rCanvas ) + { + // set rIsColorSet and check for true at the same time + if( (rIsColorSet=pAct->IsSetting()) != false ) + { + ::Color aColor( pAct->GetColor() ); + + // force alpha part of color to + // opaque. transparent painting is done + // explicitely via META_TRANSPARENT_ACTION + aColor.SetTransparency(0); + //aColor.SetTransparency(128); + + rColorSequence = ::vcl::unotools::colorToDoubleSequence( + aColor, + rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() ); + } + } + + + // state stack manipulators + // ------------------------ + void clearStateStack( ::cppcanvas::internal::VectorOfOutDevStates& rStates ) + { + rStates.clear(); + const ::cppcanvas::internal::OutDevState aDefaultState; + rStates.push_back( aDefaultState ); + } + + ::cppcanvas::internal::OutDevState& getState( ::cppcanvas::internal::VectorOfOutDevStates& rStates ) + { + return rStates.back(); + } + + const ::cppcanvas::internal::OutDevState& getState( const ::cppcanvas::internal::VectorOfOutDevStates& rStates ) + { + return rStates.back(); + } + + void pushState( ::cppcanvas::internal::VectorOfOutDevStates& rStates, + sal_uInt16 nFlags ) + { + rStates.push_back( getState( rStates ) ); + getState( rStates ).pushFlags = nFlags; + } + + void popState( ::cppcanvas::internal::VectorOfOutDevStates& rStates ) + { + if( getState( rStates ).pushFlags != PUSH_ALL ) + { + // a state is pushed which is incomplete, i.e. does not + // restore everything to the previous stack level when + // popped. + // That means, we take the old state, and restore every + // OutDevState member whose flag is set, from the new to the + // old state. Then the new state gets overwritten by the + // calculated state + + // preset to-be-calculated new state with old state + ::cppcanvas::internal::OutDevState aCalculatedNewState( getState( rStates ) ); + + // selectively copy to-be-restored content over saved old + // state + rStates.pop_back(); + + const ::cppcanvas::internal::OutDevState& rNewState( getState( rStates ) ); + + if( (aCalculatedNewState.pushFlags & PUSH_LINECOLOR) ) + { + aCalculatedNewState.lineColor = rNewState.lineColor; + aCalculatedNewState.isLineColorSet = rNewState.isLineColorSet; + } + + if( (aCalculatedNewState.pushFlags & PUSH_FILLCOLOR) ) + { + aCalculatedNewState.fillColor = rNewState.fillColor; + aCalculatedNewState.isFillColorSet = rNewState.isFillColorSet; + } + + if( (aCalculatedNewState.pushFlags & PUSH_FONT) ) + { + aCalculatedNewState.xFont = rNewState.xFont; + aCalculatedNewState.fontRotation = rNewState.fontRotation; + aCalculatedNewState.textReliefStyle = rNewState.textReliefStyle; + aCalculatedNewState.textOverlineStyle = rNewState.textOverlineStyle; + aCalculatedNewState.textUnderlineStyle = rNewState.textUnderlineStyle; + aCalculatedNewState.textStrikeoutStyle = rNewState.textStrikeoutStyle; + aCalculatedNewState.textEmphasisMarkStyle = rNewState.textEmphasisMarkStyle; + aCalculatedNewState.isTextEffectShadowSet = rNewState.isTextEffectShadowSet; + aCalculatedNewState.isTextWordUnderlineSet = rNewState.isTextWordUnderlineSet; + aCalculatedNewState.isTextOutlineModeSet = rNewState.isTextOutlineModeSet; + } + + if( (aCalculatedNewState.pushFlags & PUSH_TEXTCOLOR) ) + { + aCalculatedNewState.textColor = rNewState.textColor; + } + + if( (aCalculatedNewState.pushFlags & PUSH_MAPMODE) ) + { + aCalculatedNewState.mapModeTransform = rNewState.mapModeTransform; + } + + if( (aCalculatedNewState.pushFlags & PUSH_CLIPREGION) ) + { + aCalculatedNewState.clip = rNewState.clip; + aCalculatedNewState.clipRect = rNewState.clipRect; + aCalculatedNewState.xClipPoly = rNewState.xClipPoly; + } + + // TODO(F2): Raster ops NYI + // if( (aCalculatedNewState.pushFlags & PUSH_RASTEROP) ) + // { + // } + + if( (aCalculatedNewState.pushFlags & PUSH_TEXTFILLCOLOR) ) + { + aCalculatedNewState.textFillColor = rNewState.textFillColor; + aCalculatedNewState.isTextFillColorSet = rNewState.isTextFillColorSet; + } + + if( (aCalculatedNewState.pushFlags & PUSH_TEXTALIGN) ) + { + aCalculatedNewState.textReferencePoint = rNewState.textReferencePoint; + } + + // TODO(F1): Refpoint handling NYI + // if( (aCalculatedNewState.pushFlags & PUSH_REFPOINT) ) + // { + // } + + if( (aCalculatedNewState.pushFlags & PUSH_TEXTLINECOLOR) ) + { + aCalculatedNewState.textLineColor = rNewState.textLineColor; + aCalculatedNewState.isTextLineColorSet = rNewState.isTextLineColorSet; + } + + if( (aCalculatedNewState.pushFlags & PUSH_TEXTLAYOUTMODE) ) + { + aCalculatedNewState.textAlignment = rNewState.textAlignment; + aCalculatedNewState.textDirection = rNewState.textDirection; + } + + // TODO(F2): Text language handling NYI + // if( (aCalculatedNewState.pushFlags & PUSH_TEXTLANGUAGE) ) + // { + // } + + // always copy push mode + aCalculatedNewState.pushFlags = rNewState.pushFlags; + + // flush to stack + getState( rStates ) = aCalculatedNewState; + } + else + { + rStates.pop_back(); + } + } + + void setupStrokeAttributes( rendering::StrokeAttributes& o_rStrokeAttributes, + const ::cppcanvas::internal::ActionFactoryParameters& rParms, + const LineInfo& rLineInfo ) + { + const ::basegfx::B2DSize aWidth( rLineInfo.GetWidth(), 0 ); + o_rStrokeAttributes.StrokeWidth = + (getState( rParms.mrStates ).mapModeTransform * aWidth).getX(); + + // setup reasonable defaults + o_rStrokeAttributes.MiterLimit = 15.0; // 1.0 was no good default; GDI+'s limit is 10.0, our's is 15.0 + o_rStrokeAttributes.StartCapType = rendering::PathCapType::BUTT; + o_rStrokeAttributes.EndCapType = rendering::PathCapType::BUTT; + + switch(rLineInfo.GetLineJoin()) + { + default: // B2DLINEJOIN_NONE, B2DLINEJOIN_MIDDLE + o_rStrokeAttributes.JoinType = rendering::PathJoinType::NONE; + break; + case basegfx::B2DLINEJOIN_BEVEL: + o_rStrokeAttributes.JoinType = rendering::PathJoinType::BEVEL; + break; + case basegfx::B2DLINEJOIN_MITER: + o_rStrokeAttributes.JoinType = rendering::PathJoinType::MITER; + break; + case basegfx::B2DLINEJOIN_ROUND: + o_rStrokeAttributes.JoinType = rendering::PathJoinType::ROUND; + break; + } + + if( LINE_DASH == rLineInfo.GetStyle() ) + { + const ::cppcanvas::internal::OutDevState& rState( getState( rParms.mrStates ) ); + + // TODO(F1): Interpret OutDev::GetRefPoint() for the start of the dashing. + + // interpret dash info only if explicitely enabled as + // style + const ::basegfx::B2DSize aDistance( rLineInfo.GetDistance(), 0 ); + const double nDistance( (rState.mapModeTransform * aDistance).getX() ); + + const ::basegfx::B2DSize aDashLen( rLineInfo.GetDashLen(), 0 ); + const double nDashLen( (rState.mapModeTransform * aDashLen).getX() ); + + const ::basegfx::B2DSize aDotLen( rLineInfo.GetDotLen(), 0 ); + const double nDotLen( (rState.mapModeTransform * aDotLen).getX() ); + + const sal_Int32 nNumArryEntries( 2*rLineInfo.GetDashCount() + + 2*rLineInfo.GetDotCount() ); + + o_rStrokeAttributes.DashArray.realloc( nNumArryEntries ); + double* pDashArray = o_rStrokeAttributes.DashArray.getArray(); + + + // iteratively fill dash array, first with dashs, then + // with dots. + // =================================================== + + sal_Int32 nCurrEntry=0; + + for( sal_Int32 i=0; i<rLineInfo.GetDashCount(); ++i ) + { + pDashArray[nCurrEntry++] = nDashLen; + pDashArray[nCurrEntry++] = nDistance; + } + for( sal_Int32 i=0; i<rLineInfo.GetDotCount(); ++i ) + { + pDashArray[nCurrEntry++] = nDotLen; + pDashArray[nCurrEntry++] = nDistance; + } + } + } + + + /** Create masked BitmapEx, where the white areas of rBitmap are + transparent, and the other appear in rMaskColor. + */ + BitmapEx createMaskBmpEx( const Bitmap& rBitmap, + const ::Color& rMaskColor ) + { + const ::Color aWhite( COL_WHITE ); + BitmapPalette aBiLevelPalette(2); + aBiLevelPalette[0] = aWhite; + aBiLevelPalette[1] = rMaskColor; + + Bitmap aMask( rBitmap.CreateMask( aWhite )); + Bitmap aSolid( rBitmap.GetSizePixel(), + 1, + &aBiLevelPalette ); + aSolid.Erase( rMaskColor ); + + return BitmapEx( aSolid, aMask ); + } + + /** Shameless rip from vcl/source/gdi/outdev3.cxx + + Should consolidate, into something like basetxt... + */ + sal_Unicode getLocalizedChar( sal_Unicode nChar, LanguageType eLang ) + { + // currently only conversion from ASCII digits is interesting + if( (nChar < '0') || ('9' < nChar) ) + return nChar; + + sal_Unicode nOffset(0); + // eLang & LANGUAGE_MASK_PRIMARY catches language independent of region. + // CAVEAT! To some like Mongolian MS assigned the same primary language + // although the script type is different! + switch( eLang & LANGUAGE_MASK_PRIMARY ) + { + default: + break; + + case LANGUAGE_ARABIC_SAUDI_ARABIA & LANGUAGE_MASK_PRIMARY: + case LANGUAGE_URDU & LANGUAGE_MASK_PRIMARY: + case LANGUAGE_PUNJABI & LANGUAGE_MASK_PRIMARY: //??? + nOffset = 0x0660 - '0'; // arabic/persian/urdu + break; + case LANGUAGE_BENGALI & LANGUAGE_MASK_PRIMARY: + nOffset = 0x09E6 - '0'; // bengali + break; + case LANGUAGE_BURMESE & LANGUAGE_MASK_PRIMARY: + nOffset = 0x1040 - '0'; // burmese + break; + case LANGUAGE_HINDI & LANGUAGE_MASK_PRIMARY: + nOffset = 0x0966 - '0'; // devanagari + break; + case LANGUAGE_GUJARATI & LANGUAGE_MASK_PRIMARY: + nOffset = 0x0AE6 - '0'; // gujarati + break; + case LANGUAGE_KANNADA & LANGUAGE_MASK_PRIMARY: + nOffset = 0x0CE6 - '0'; // kannada + break; + case LANGUAGE_KHMER & LANGUAGE_MASK_PRIMARY: + nOffset = 0x17E0 - '0'; // khmer + break; + case LANGUAGE_LAO & LANGUAGE_MASK_PRIMARY: + nOffset = 0x0ED0 - '0'; // lao + break; + case LANGUAGE_MALAYALAM & LANGUAGE_MASK_PRIMARY: + nOffset = 0x0D66 - '0'; // malayalam + break; + case LANGUAGE_MONGOLIAN & LANGUAGE_MASK_PRIMARY: + if (eLang == LANGUAGE_MONGOLIAN_MONGOLIAN) + nOffset = 0x1810 - '0'; // mongolian + else + nOffset = 0; // mongolian cyrillic + break; + case LANGUAGE_ORIYA & LANGUAGE_MASK_PRIMARY: + nOffset = 0x0B66 - '0'; // oriya + break; + case LANGUAGE_TAMIL & LANGUAGE_MASK_PRIMARY: + nOffset = 0x0BE7 - '0'; // tamil + break; + case LANGUAGE_TELUGU & LANGUAGE_MASK_PRIMARY: + nOffset = 0x0C66 - '0'; // telugu + break; + case LANGUAGE_THAI & LANGUAGE_MASK_PRIMARY: + nOffset = 0x0E50 - '0'; // thai + break; + case LANGUAGE_TIBETAN & LANGUAGE_MASK_PRIMARY: + nOffset = 0x0F20 - '0'; // tibetan + break; + } + + nChar = sal::static_int_cast<sal_Unicode>(nChar + nOffset); + return nChar; + } + + void convertToLocalizedNumerals( XubString& rStr, + LanguageType eTextLanguage ) + { + const sal_Unicode* pBase = rStr.GetBuffer(); + const sal_Unicode* pBegin = pBase + 0; + const xub_StrLen nEndIndex = rStr.Len(); + const sal_Unicode* pEnd = pBase + nEndIndex; + + for( ; pBegin < pEnd; ++pBegin ) + { + // TODO: are there non-digit localizations? + if( (*pBegin >= '0') && (*pBegin <= '9') ) + { + // translate characters to local preference + sal_Unicode cChar = getLocalizedChar( *pBegin, eTextLanguage ); + if( cChar != *pBegin ) + rStr.SetChar( sal::static_int_cast<sal_uInt16>(pBegin - pBase), cChar ); + } + } + } +} + + +namespace cppcanvas +{ + namespace internal + { + bool ImplRenderer::createFillAndStroke( const ::basegfx::B2DPolyPolygon& rPolyPoly, + const ActionFactoryParameters& rParms ) + { + const OutDevState& rState( getState( rParms.mrStates ) ); + if( (!rState.isLineColorSet && + !rState.isFillColorSet) || + (rState.lineColor.getLength() == 0 && + rState.fillColor.getLength() == 0) ) + { + return false; + } + + ActionSharedPtr pPolyAction( + internal::PolyPolyActionFactory::createPolyPolyAction( + rPolyPoly, rParms.mrCanvas, rState ) ); + + if( pPolyAction ) + { + maActions.push_back( + MtfAction( + pPolyAction, + rParms.mrCurrActionIndex ) ); + + rParms.mrCurrActionIndex += pPolyAction->getActionCount()-1; + } + + return true; + } + + bool ImplRenderer::createFillAndStroke( const ::basegfx::B2DPolygon& rPoly, + const ActionFactoryParameters& rParms ) + { + return createFillAndStroke( ::basegfx::B2DPolyPolygon( rPoly ), + rParms ); + } + + void ImplRenderer::skipContent( GDIMetaFile& rMtf, + const char* pCommentString, + sal_Int32& io_rCurrActionIndex ) const + { + ENSURE_OR_THROW( pCommentString, + "ImplRenderer::skipContent(): NULL string given" ); + + MetaAction* pCurrAct; + while( (pCurrAct=rMtf.NextAction()) != NULL ) + { + // increment action index, we've skipped an action. + ++io_rCurrActionIndex; + + if( pCurrAct->GetType() == META_COMMENT_ACTION && + static_cast<MetaCommentAction*>(pCurrAct)->GetComment().CompareIgnoreCaseToAscii( + pCommentString ) == COMPARE_EQUAL ) + { + // requested comment found, done + return; + } + } + + // EOF + return; + } + + bool ImplRenderer::isActionContained( GDIMetaFile& rMtf, + const char* pCommentString, + sal_uInt16 nType ) const + { + ENSURE_OR_THROW( pCommentString, + "ImplRenderer::isActionContained(): NULL string given" ); + + bool bRet( false ); + + // at least _one_ call to GDIMetaFile::NextAction() is + // executed + sal_uIntPtr nPos( 1 ); + + MetaAction* pCurrAct; + while( (pCurrAct=rMtf.NextAction()) != NULL ) + { + if( pCurrAct->GetType() == nType ) + { + bRet = true; // action type found + break; + } + + if( pCurrAct->GetType() == META_COMMENT_ACTION && + static_cast<MetaCommentAction*>(pCurrAct)->GetComment().CompareIgnoreCaseToAscii( + pCommentString ) == COMPARE_EQUAL ) + { + // delimiting end comment found, done + bRet = false; // not yet found + break; + } + + ++nPos; + } + + // rewind metafile to previous position (this method must + // not change the current metaaction) + while( nPos-- ) + rMtf.WindPrev(); + + if( !pCurrAct ) + { + // EOF, and not yet found + bRet = false; + } + + return bRet; + } + + void ImplRenderer::createGradientAction( const ::PolyPolygon& rPoly, + const ::Gradient& rGradient, + const ActionFactoryParameters& rParms, + bool bIsPolygonRectangle, + bool bSubsettableActions ) + { + DBG_TESTSOLARMUTEX(); + + ::basegfx::B2DPolyPolygon aDevicePoly( rPoly.getB2DPolyPolygon() ); + aDevicePoly.transform( getState( rParms.mrStates ).mapModeTransform ); + + // decide, whether this gradient can be rendered natively + // by the canvas, or must be emulated via VCL gradient + // action extraction. + const sal_uInt16 nSteps( rGradient.GetSteps() ); + + if( // step count is infinite, can use native canvas + // gradients here + nSteps == 0 || + // step count is sufficiently high, such that no + // discernible difference should be visible. + nSteps > 64 ) + { + uno::Reference< lang::XMultiServiceFactory> xFactory( + rParms.mrCanvas->getUNOCanvas()->getDevice()->getParametricPolyPolygonFactory() ); + + if( xFactory.is() ) + { + rendering::Texture aTexture; + + aTexture.RepeatModeX = rendering::TexturingMode::CLAMP; + aTexture.RepeatModeY = rendering::TexturingMode::CLAMP; + aTexture.Alpha = 1.0; + + + // setup start/end color values + // ---------------------------- + + // scale color coefficients with gradient intensities + const sal_uInt16 nStartIntensity( rGradient.GetStartIntensity() ); + ::Color aVCLStartColor( rGradient.GetStartColor() ); + aVCLStartColor.SetRed( (sal_uInt8)(aVCLStartColor.GetRed() * nStartIntensity / 100) ); + aVCLStartColor.SetGreen( (sal_uInt8)(aVCLStartColor.GetGreen() * nStartIntensity / 100) ); + aVCLStartColor.SetBlue( (sal_uInt8)(aVCLStartColor.GetBlue() * nStartIntensity / 100) ); + + const sal_uInt16 nEndIntensity( rGradient.GetEndIntensity() ); + ::Color aVCLEndColor( rGradient.GetEndColor() ); + aVCLEndColor.SetRed( (sal_uInt8)(aVCLEndColor.GetRed() * nEndIntensity / 100) ); + aVCLEndColor.SetGreen( (sal_uInt8)(aVCLEndColor.GetGreen() * nEndIntensity / 100) ); + aVCLEndColor.SetBlue( (sal_uInt8)(aVCLEndColor.GetBlue() * nEndIntensity / 100) ); + + uno::Reference<rendering::XColorSpace> xColorSpace( + rParms.mrCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace()); + const uno::Sequence< double > aStartColor( + ::vcl::unotools::colorToDoubleSequence( aVCLStartColor, + xColorSpace )); + const uno::Sequence< double > aEndColor( + ::vcl::unotools::colorToDoubleSequence( aVCLEndColor, + xColorSpace )); + + uno::Sequence< uno::Sequence < double > > aColors(2); + uno::Sequence< double > aStops(2); + + if( rGradient.GetStyle() == GRADIENT_AXIAL ) + { + aStops.realloc(3); + aColors.realloc(3); + + aStops[0] = 0.0; + aStops[1] = 0.5; + aStops[2] = 1.0; + + aColors[0] = aEndColor; + aColors[1] = aStartColor; + aColors[2] = aEndColor; + } + else + { + aStops[0] = 0.0; + aStops[1] = 1.0; + + aColors[0] = aStartColor; + aColors[1] = aEndColor; + } + + const ::basegfx::B2DRectangle aBounds( + ::basegfx::tools::getRange(aDevicePoly) ); + const ::basegfx::B2DVector aOffset( + rGradient.GetOfsX() / 100.0, + rGradient.GetOfsY() / 100.0); + double fRotation( rGradient.GetAngle() * M_PI / 1800.0 ); + const double fBorder( rGradient.GetBorder() / 100.0 ); + + basegfx::B2DHomMatrix aRot90; + aRot90.rotate(M_PI_2); + + basegfx::ODFGradientInfo aGradInfo; + rtl::OUString aGradientService; + switch( rGradient.GetStyle() ) + { + case GRADIENT_LINEAR: + basegfx::tools::createLinearODFGradientInfo(aGradInfo, + aBounds, + nSteps, + fBorder, + fRotation); + // map odf to svg gradient orientation - x + // instead of y direction + aGradInfo.maTextureTransform = aGradInfo.maTextureTransform * aRot90; + aGradientService = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("LinearGradient")); + break; + + case GRADIENT_AXIAL: + { + // Adapt the border so that it is suitable + // for the axial gradient. An axial + // gradient consists of two linear + // gradients. Each of those covers half + // of the total size. In order to + // compensate for the condensed display of + // the linear gradients, we have to + // enlarge the area taken up by the actual + // gradient (1-fBorder). After that we + // have to turn the result back into a + // border value, hence the second (left + // most 1-... + const double fAxialBorder (1-2*(1-fBorder)); + basegfx::tools::createAxialODFGradientInfo(aGradInfo, + aBounds, + nSteps, + fAxialBorder, + fRotation); + // map odf to svg gradient orientation - x + // instead of y direction + aGradInfo.maTextureTransform = aGradInfo.maTextureTransform * aRot90; + + // map odf axial gradient to 3-stop linear + // gradient - shift left by 0.5 + basegfx::B2DHomMatrix aShift; + aShift.translate(-0.5,0); + aGradInfo.maTextureTransform = aGradInfo.maTextureTransform * aShift; + + aGradientService = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("LinearGradient")); + break; + } + + case GRADIENT_RADIAL: + basegfx::tools::createRadialODFGradientInfo(aGradInfo, + aBounds, + aOffset, + nSteps, + fBorder); + aGradientService = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("EllipticalGradient")); + break; + + case GRADIENT_ELLIPTICAL: + basegfx::tools::createEllipticalODFGradientInfo(aGradInfo, + aBounds, + aOffset, + nSteps, + fBorder, + fRotation); + aGradientService = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("EllipticalGradient")); + break; + + case GRADIENT_SQUARE: + basegfx::tools::createSquareODFGradientInfo(aGradInfo, + aBounds, + aOffset, + nSteps, + fBorder, + fRotation); + aGradientService = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("RectangularGradient")); + break; + + case GRADIENT_RECT: + basegfx::tools::createRectangularODFGradientInfo(aGradInfo, + aBounds, + aOffset, + nSteps, + fBorder, + fRotation); + aGradientService = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("RectangularGradient")); + break; + + default: + ENSURE_OR_THROW( false, + "ImplRenderer::createGradientAction(): Unexpected gradient type" ); + break; + } + + // As the texture coordinate space is relative to + // the polygon coordinate space (NOT to the + // polygon itself), move gradient to the start of + // the actual polygon. If we skip this, the + // gradient will always display at the origin, and + // not within the polygon bound (which might be + // miles away from the origin). + aGradInfo.maTextureTransform.translate( aBounds.getMinX(), + aBounds.getMinY() ); + ::basegfx::unotools::affineMatrixFromHomMatrix( aTexture.AffineTransform, + aGradInfo.maTextureTransform ); + + uno::Sequence<uno::Any> args(3); + beans::PropertyValue aProp; + aProp.Name = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Colors")); + aProp.Value <<= aColors; + args[0] <<= aProp; + aProp.Name = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Stops")); + aProp.Value <<= aStops; + args[1] <<= aProp; + aProp.Name = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AspectRatio")); + aProp.Value <<= aGradInfo.mfAspectRatio; + args[2] <<= aProp; + + aTexture.Gradient.set( + xFactory->createInstanceWithArguments(aGradientService, + args), + uno::UNO_QUERY); + if( aTexture.Gradient.is() ) + { + ActionSharedPtr pPolyAction( + internal::PolyPolyActionFactory::createPolyPolyAction( + aDevicePoly, + rParms.mrCanvas, + getState( rParms.mrStates ), + aTexture ) ); + + if( pPolyAction ) + { + maActions.push_back( + MtfAction( + pPolyAction, + rParms.mrCurrActionIndex ) ); + + rParms.mrCurrActionIndex += pPolyAction->getActionCount()-1; + } + + // done, using native gradients + return; + } + } + } + + // cannot currently use native canvas gradients, as a + // finite step size is given (this funny feature is not + // supported by the XCanvas API) + pushState( rParms.mrStates, PUSH_ALL ); + + if( !bIsPolygonRectangle ) + { + // only clip, if given polygon is not a rectangle in + // the first place (the gradient is always limited to + // the given bound rect) + updateClipping( + aDevicePoly, + rParms, + true ); + } + + GDIMetaFile aTmpMtf; + rParms.mrVDev.AddGradientActions( rPoly.GetBoundRect(), + rGradient, + aTmpMtf ); + + createActions( aTmpMtf, rParms, bSubsettableActions ); + + popState( rParms.mrStates ); + } + + uno::Reference< rendering::XCanvasFont > ImplRenderer::createFont( double& o_rFontRotation, + const ::Font& rFont, + const ActionFactoryParameters& rParms ) const + { + rendering::FontRequest aFontRequest; + + if( rParms.mrParms.maFontName.is_initialized() ) + aFontRequest.FontDescription.FamilyName = *rParms.mrParms.maFontName; + else + aFontRequest.FontDescription.FamilyName = rFont.GetName(); + + aFontRequest.FontDescription.StyleName = rFont.GetStyleName(); + + aFontRequest.FontDescription.IsSymbolFont = (rFont.GetCharSet() == RTL_TEXTENCODING_SYMBOL) ? util::TriState_YES : util::TriState_NO; + aFontRequest.FontDescription.IsVertical = rFont.IsVertical() ? util::TriState_YES : util::TriState_NO; + + // TODO(F2): improve vclenum->panose conversion + aFontRequest.FontDescription.FontDescription.Weight = + rParms.mrParms.maFontWeight.is_initialized() ? + *rParms.mrParms.maFontWeight : + ::canvas::tools::numeric_cast<sal_Int8>( ::basegfx::fround( rFont.GetWeight() ) ); + aFontRequest.FontDescription.FontDescription.Letterform = + rParms.mrParms.maFontLetterForm.is_initialized() ? + *rParms.mrParms.maFontLetterForm : + (rFont.GetItalic() == ITALIC_NONE) ? 0 : 9; + aFontRequest.FontDescription.FontDescription.Proportion = + rParms.mrParms.maFontProportion.is_initialized() ? + *rParms.mrParms.maFontProportion : + (rFont.GetPitch() == PITCH_FIXED) + ? rendering::PanoseProportion::MONO_SPACED + : rendering::PanoseProportion::ANYTHING; + + LanguageType aLang = rFont.GetLanguage(); + aFontRequest.Locale = MsLangId::convertLanguageToLocale(aLang, false); + + // setup state-local text transformation, + // if the font be rotated + const short nFontAngle( rFont.GetOrientation() ); + if( nFontAngle != 0 ) + { + // set to unity transform rotated by font angle + const double nAngle( nFontAngle * (F_PI / 1800.0) ); + o_rFontRotation = -nAngle; + } + else + { + o_rFontRotation = 0.0; + } + + geometry::Matrix2D aFontMatrix; + ::canvas::tools::setIdentityMatrix2D( aFontMatrix ); + + // TODO(F2): use correct scale direction, font + // height might be width or anything else + + // TODO(Q3): This code smells of programming by + // coincidence (the next two if statements) + const ::Size rFontSizeLog( rFont.GetSize() ); + const sal_Int32 nFontWidthLog = rFontSizeLog.Width(); + if( nFontWidthLog != 0 ) + { + ::Font aTestFont = rFont; + aTestFont.SetWidth( 0 ); + sal_Int32 nNormalWidth = rParms.mrVDev.GetFontMetric( aTestFont ).GetWidth(); + if( nNormalWidth != nFontWidthLog ) + if( nNormalWidth ) + aFontMatrix.m00 = (double)nFontWidthLog / nNormalWidth; + } + + // #i52608# apply map mode scale also to font matrix - an + // anisotrophic mapmode must be reflected in an + // anisotrophic font matrix scale. + const OutDevState& rState( getState( rParms.mrStates ) ); + if( !::basegfx::fTools::equal( + rState.mapModeTransform.get(0,0), + rState.mapModeTransform.get(1,1)) ) + { + const double nScaleX( rState.mapModeTransform.get(0,0) ); + const double nScaleY( rState.mapModeTransform.get(1,1) ); + + // note: no reason to check for division by zero, we + // always have the value closer (or equal) to zero as + // the nominator. + if( fabs(nScaleX) < fabs(nScaleY) ) + aFontMatrix.m00 *= nScaleX / nScaleY; + else + aFontMatrix.m11 *= nScaleY / nScaleX; + } + aFontRequest.CellSize = (rState.mapModeTransform * ::vcl::unotools::b2DSizeFromSize(rFontSizeLog)).getY(); + + return rParms.mrCanvas->getUNOCanvas()->createFont( aFontRequest, + uno::Sequence< beans::PropertyValue >(), + aFontMatrix ); + } + + // create text effects such as shadow/relief/embossed + void ImplRenderer::createTextAction( const ::Point& rStartPoint, + const String rString, + int nIndex, + int nLength, + const sal_Int32* pCharWidths, + const ActionFactoryParameters& rParms, + bool bSubsettableActions ) + { + ENSURE_OR_THROW( nIndex >= 0 && nLength <= rString.Len() + nIndex, + "ImplRenderer::createTextWithEffectsAction(): Invalid text index" ); + + if( !nLength ) + return; // zero-length text, no visible output + + const OutDevState& rState( getState( rParms.mrStates ) ); + + // TODO(F2): implement all text effects + // if( rState.textAlignment ); // TODO(F2): NYI + + ::Color aShadowColor( COL_AUTO ); + ::Color aReliefColor( COL_AUTO ); + ::Size aShadowOffset; + ::Size aReliefOffset; + + uno::Reference<rendering::XColorSpace> xColorSpace( + rParms.mrCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() ); + + if( rState.isTextEffectShadowSet ) + { + // calculate shadow offset (similar to outdev3.cxx) + // TODO(F3): better match with outdev3.cxx + sal_Int32 nShadowOffset = static_cast<sal_Int32>(1.5 + ((rParms.mrVDev.GetFont().GetHeight()-24.0)/24.0)); + if( nShadowOffset < 1 ) + nShadowOffset = 1; + + aShadowOffset.setWidth( nShadowOffset ); + aShadowOffset.setHeight( nShadowOffset ); + + // determine shadow color (from outdev3.cxx) + ::Color aTextColor = ::vcl::unotools::doubleSequenceToColor( + rState.textColor, xColorSpace ); + bool bIsDark = (aTextColor.GetColor() == COL_BLACK) + || (aTextColor.GetLuminance() < 8); + + aShadowColor = bIsDark ? COL_LIGHTGRAY : COL_BLACK; + aShadowColor.SetTransparency( aTextColor.GetTransparency() ); + } + + if( rState.textReliefStyle ) + { + // calculate relief offset (similar to outdev3.cxx) + sal_Int32 nReliefOffset = rParms.mrVDev.PixelToLogic( Size( 1, 1 ) ).Height(); + nReliefOffset += nReliefOffset/2; + if( nReliefOffset < 1 ) + nReliefOffset = 1; + + if( rState.textReliefStyle == RELIEF_ENGRAVED ) + nReliefOffset = -nReliefOffset; + + aReliefOffset.setWidth( nReliefOffset ); + aReliefOffset.setHeight( nReliefOffset ); + + // determine relief color (from outdev3.cxx) + ::Color aTextColor = ::vcl::unotools::doubleSequenceToColor( + rState.textColor, xColorSpace ); + + aReliefColor = ::Color( COL_LIGHTGRAY ); + + // we don't have a automatic color, so black is always + // drawn on white (literally copied from + // vcl/source/gdi/outdev3.cxx) + if( aTextColor.GetColor() == COL_BLACK ) + { + aTextColor = ::Color( COL_WHITE ); + getState( rParms.mrStates ).textColor = + ::vcl::unotools::colorToDoubleSequence( + aTextColor, xColorSpace ); + } + + if( aTextColor.GetColor() == COL_WHITE ) + aReliefColor = ::Color( COL_BLACK ); + aReliefColor.SetTransparency( aTextColor.GetTransparency() ); + } + + // create the actual text action + ActionSharedPtr pTextAction( + TextActionFactory::createTextAction( + rStartPoint, + aReliefOffset, + aReliefColor, + aShadowOffset, + aShadowColor, + rString, + nIndex, + nLength, + pCharWidths, + rParms.mrVDev, + rParms.mrCanvas, + rState, + rParms.mrParms, + bSubsettableActions ) ); + + ActionSharedPtr pStrikeoutTextAction; + + if ( rState.textStrikeoutStyle == STRIKEOUT_X || rState.textStrikeoutStyle == STRIKEOUT_SLASH ) + { + long nWidth = rParms.mrVDev.GetTextWidth( rString,nIndex,nLength ); + + xub_Unicode pChars[5]; + if ( rState.textStrikeoutStyle == STRIKEOUT_X ) + pChars[0] = 'X'; + else + pChars[0] = '/'; + pChars[3]=pChars[2]=pChars[1]=pChars[0]; + + long nStrikeoutWidth = nWidth; + String aStrikeoutTest( pChars, 4 ); + + if( aStrikeoutTest.Len() ) + { + nStrikeoutWidth = ( rParms.mrVDev.GetTextWidth( aStrikeoutTest ) + 2 ) / 4; + aStrikeoutTest.Erase(); + + if( nStrikeoutWidth <= 0 ) + nStrikeoutWidth = 1; + } + + long nMaxWidth = nStrikeoutWidth/2; + if ( nMaxWidth < 2 ) + nMaxWidth = 2; + nMaxWidth += nWidth + 1; + + long nFullStrikeoutWidth = 0; + String aStrikeoutText( pChars, 0 ); + while( (nFullStrikeoutWidth+=nStrikeoutWidth ) < nMaxWidth+1 ) + aStrikeoutText += pChars[0]; + + + xub_StrLen nLen = aStrikeoutText.Len(); + + if( nLen ) + { + long nInterval = ( nWidth - nStrikeoutWidth * nLen ) / nLen; + nStrikeoutWidth += nInterval; + sal_Int32* pStrikeoutCharWidths = new sal_Int32[nLen]; + + for ( int i = 0;i<nLen; i++) + { + pStrikeoutCharWidths[i] = nStrikeoutWidth; + } + + for ( int i = 1;i< nLen; i++ ) + { + pStrikeoutCharWidths[ i ] += pStrikeoutCharWidths[ i-1 ]; + } + + sal_Int32 nStartPos = 0; + + pStrikeoutTextAction = + TextActionFactory::createTextAction( + rStartPoint, + aReliefOffset, + aReliefColor, + aShadowOffset, + aShadowColor, + aStrikeoutText, + nStartPos, + aStrikeoutText.Len(), + pStrikeoutCharWidths, + rParms.mrVDev, + rParms.mrCanvas, + rState, + rParms.mrParms, + bSubsettableActions ) ; + } + } + + if( pTextAction ) + { + maActions.push_back( + MtfAction( + pTextAction, + rParms.mrCurrActionIndex ) ); + + if ( pStrikeoutTextAction ) + { + maActions.push_back( + MtfAction( + pStrikeoutTextAction, + rParms.mrCurrActionIndex ) ); + } + + rParms.mrCurrActionIndex += pTextAction->getActionCount()-1; + } + } + + void ImplRenderer::updateClipping( const ::basegfx::B2DPolyPolygon& rClipPoly, + const ActionFactoryParameters& rParms, + bool bIntersect ) + { + ::cppcanvas::internal::OutDevState& rState( getState( rParms.mrStates ) ); + ::basegfx::B2DPolyPolygon aClipPoly( rClipPoly ); + + const bool bEmptyClipRect( rState.clipRect.IsEmpty() ); + const bool bEmptyClipPoly( rState.clip.count() == 0 ); + + ENSURE_OR_THROW( bEmptyClipPoly || bEmptyClipRect, + "ImplRenderer::updateClipping(): Clip rect and polygon are both set!" ); + + if( !bIntersect || + (bEmptyClipRect && bEmptyClipPoly) ) + { + rState.clip = rClipPoly; + } + else + { + if( !bEmptyClipRect ) + { + // TODO(P3): Use Liang-Barsky polygon clip here, + // after all, one object is just a rectangle! + + // convert rect to polygon beforehand, must revert + // to general polygon clipping here. + rState.clip = ::basegfx::B2DPolyPolygon( + ::basegfx::tools::createPolygonFromRect( + // #121100# VCL rectangular clips always + // include one more pixel to the right + // and the bottom + ::basegfx::B2DRectangle( rState.clipRect.Left(), + rState.clipRect.Top(), + rState.clipRect.Right()+1, + rState.clipRect.Bottom()+1 ) ) ); + } + + // AW: Simplified + rState.clip = basegfx::tools::clipPolyPolygonOnPolyPolygon( + aClipPoly, rState.clip, true, false); + } + + // by now, our clip resides in the OutDevState::clip + // poly-polygon. + rState.clipRect.SetEmpty(); + + if( rState.clip.count() == 0 ) + { + if( rState.clipRect.IsEmpty() ) + { + rState.xClipPoly.clear(); + } + else + { + rState.xClipPoly = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + rParms.mrCanvas->getUNOCanvas()->getDevice(), + ::basegfx::B2DPolyPolygon( + ::basegfx::tools::createPolygonFromRect( + // #121100# VCL rectangular clips + // always include one more pixel to + // the right and the bottom + ::basegfx::B2DRectangle( rState.clipRect.Left(), + rState.clipRect.Top(), + rState.clipRect.Right()+1, + rState.clipRect.Bottom()+1 ) ) ) ); + } + } + else + { + rState.xClipPoly = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + rParms.mrCanvas->getUNOCanvas()->getDevice(), + rState.clip ); + } + } + + void ImplRenderer::updateClipping( const ::Rectangle& rClipRect, + const ActionFactoryParameters& rParms, + bool bIntersect ) + { + ::cppcanvas::internal::OutDevState& rState( getState( rParms.mrStates ) ); + + const bool bEmptyClipRect( rState.clipRect.IsEmpty() ); + const bool bEmptyClipPoly( rState.clip.count() == 0 ); + + ENSURE_OR_THROW( bEmptyClipPoly || bEmptyClipRect, + "ImplRenderer::updateClipping(): Clip rect and polygon are both set!" ); + + if( !bIntersect || + (bEmptyClipRect && bEmptyClipPoly) ) + { + rState.clipRect = rClipRect; + rState.clip.clear(); + } + else if( bEmptyClipPoly ) + { + rState.clipRect.Intersection( rClipRect ); + rState.clip.clear(); + } + else + { + // TODO(P3): Handle a fourth case here, when all clip + // polygons are rectangular, once B2DMultiRange's + // sweep line implementation is done. + + // general case: convert to polygon and clip + // ----------------------------------------- + + // convert rect to polygon beforehand, must revert + // to general polygon clipping here. + ::basegfx::B2DPolyPolygon aClipPoly( + ::basegfx::tools::createPolygonFromRect( + ::basegfx::B2DRectangle( rClipRect.Left(), + rClipRect.Top(), + rClipRect.Right(), + rClipRect.Bottom() ) ) ); + + rState.clipRect.SetEmpty(); + + // AW: Simplified + rState.clip = basegfx::tools::clipPolyPolygonOnPolyPolygon( + aClipPoly, rState.clip, true, false); + } + + if( rState.clip.count() == 0 ) + { + if( rState.clipRect.IsEmpty() ) + { + rState.xClipPoly.clear(); + } + else + { + rState.xClipPoly = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + rParms.mrCanvas->getUNOCanvas()->getDevice(), + ::basegfx::B2DPolyPolygon( + ::basegfx::tools::createPolygonFromRect( + // #121100# VCL rectangular clips + // always include one more pixel to + // the right and the bottom + ::basegfx::B2DRectangle( rState.clipRect.Left(), + rState.clipRect.Top(), + rState.clipRect.Right()+1, + rState.clipRect.Bottom()+1 ) ) ) ); + } + } + else + { + rState.xClipPoly = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + rParms.mrCanvas->getUNOCanvas()->getDevice(), + rState.clip ); + } + } + + bool ImplRenderer::createActions( GDIMetaFile& rMtf, + const ActionFactoryParameters& rFactoryParms, + bool bSubsettableActions ) + { + /* TODO(P2): interpret mtf-comments + ================================ + + - gradient fillings (do that via comments) + + - think about mapping. _If_ we do everything in logical + coordinates (which would solve the probs for stroke + widths and text offsets), then we would have to + recalc scaling for every drawing operation. This is + because the outdev map mode might change at any time. + Also keep in mind, that, although we've double precision + float arithmetic now, different offsets might still + generate different roundings (aka + 'OutputDevice::SetPixelOffset()) + + */ + + // alias common parameters + VectorOfOutDevStates& rStates(rFactoryParms.mrStates); + const CanvasSharedPtr& rCanvas(rFactoryParms.mrCanvas); + ::VirtualDevice& rVDev(rFactoryParms.mrVDev); + const Parameters& rParms(rFactoryParms.mrParms); + sal_Int32& io_rCurrActionIndex(rFactoryParms.mrCurrActionIndex); + + + // Loop over every metaaction + // ========================== + MetaAction* pCurrAct; + + // TODO(P1): think about caching + for( pCurrAct=rMtf.FirstAction(); + pCurrAct; + pCurrAct = rMtf.NextAction() ) + { + // execute every action, to keep VDev state up-to-date + // currently used only for + // - the map mode + // - the line/fill color when processing a META_TRANSPARENT_ACTION + // - SetFont to process font metric specific actions + pCurrAct->Execute( &rVDev ); + + EMFP_DEBUG(printf("MTF\trecord type: %x\n", pCurrAct->GetType())); + + switch( pCurrAct->GetType() ) + { + // ------------------------------------------------------------ + + // In the first part of this monster-switch, we + // handle all state-changing meta actions. These + // are all handled locally. + + // ------------------------------------------------------------ + + case META_PUSH_ACTION: + { + MetaPushAction* pPushAction = static_cast<MetaPushAction*>(pCurrAct); + pushState( rStates, + pPushAction->GetFlags() ); + } + break; + + case META_POP_ACTION: + popState( rStates ); + break; + + case META_TEXTLANGUAGE_ACTION: + // FALLTHROUGH intended + case META_REFPOINT_ACTION: + // handled via pCurrAct->Execute( &rVDev ) + break; + + case META_MAPMODE_ACTION: + // modify current mapModeTransformation + // transformation, such that subsequent + // coordinates map correctly + tools::calcLogic2PixelAffineTransform( getState( rStates ).mapModeTransform, + rVDev ); + break; + + // monitor clip regions, to assemble clip polygon on our own + case META_CLIPREGION_ACTION: + { + MetaClipRegionAction* pClipAction = static_cast<MetaClipRegionAction*>(pCurrAct); + + if( !pClipAction->IsClipping() ) + { + // clear clipping + getState( rStates ).clip.clear(); + } + else + { + if( !pClipAction->GetRegion().HasPolyPolygon() ) + { + VERBOSE_TRACE( "ImplRenderer::createActions(): non-polygonal clip " + "region encountered, falling back to bounding box!" ); + + // #121806# explicitely kept integer + Rectangle aClipRect( + rVDev.LogicToPixel( + pClipAction->GetRegion().GetBoundRect() ) ); + + // intersect current clip with given rect + updateClipping( + aClipRect, + rFactoryParms, + false ); + } + else + { + // set new clip polygon (don't intersect + // with old one, just set it) + + // #121806# explicitely kept integer + updateClipping( + rVDev.LogicToPixel( + pClipAction->GetRegion().GetPolyPolygon() ).getB2DPolyPolygon(), + rFactoryParms, + false ); + } + } + + break; + } + + case META_ISECTRECTCLIPREGION_ACTION: + { + MetaISectRectClipRegionAction* pClipAction = static_cast<MetaISectRectClipRegionAction*>(pCurrAct); + + // #121806# explicitely kept integer + Rectangle aClipRect( + rVDev.LogicToPixel( pClipAction->GetRect() ) ); + + // intersect current clip with given rect + updateClipping( + aClipRect, + rFactoryParms, + true ); + + break; + } + + case META_ISECTREGIONCLIPREGION_ACTION: + { + MetaISectRegionClipRegionAction* pClipAction = static_cast<MetaISectRegionClipRegionAction*>(pCurrAct); + + if( !pClipAction->GetRegion().HasPolyPolygon() ) + { + VERBOSE_TRACE( "ImplRenderer::createActions(): non-polygonal clip " + "region encountered, falling back to bounding box!" ); + + // #121806# explicitely kept integer + Rectangle aClipRect( + rVDev.LogicToPixel( pClipAction->GetRegion().GetBoundRect() ) ); + + // intersect current clip with given rect + updateClipping( + aClipRect, + rFactoryParms, + true ); + } + else + { + // intersect current clip with given clip polygon + + // #121806# explicitely kept integer + updateClipping( + rVDev.LogicToPixel( + pClipAction->GetRegion().GetPolyPolygon() ).getB2DPolyPolygon(), + rFactoryParms, + true ); + } + + break; + } + + case META_MOVECLIPREGION_ACTION: + // TODO(F2): NYI + break; + + case META_LINECOLOR_ACTION: + if( !rParms.maLineColor.is_initialized() ) + { + setStateColor( static_cast<MetaLineColorAction*>(pCurrAct), + getState( rStates ).isLineColorSet, + getState( rStates ).lineColor, + rCanvas ); + } + break; + + case META_FILLCOLOR_ACTION: + if( !rParms.maFillColor.is_initialized() ) + { + setStateColor( static_cast<MetaFillColorAction*>(pCurrAct), + getState( rStates ).isFillColorSet, + getState( rStates ).fillColor, + rCanvas ); + } + break; + + case META_TEXTCOLOR_ACTION: + { + if( !rParms.maTextColor.is_initialized() ) + { + // Text color is set unconditionally, thus, no + // use of setStateColor here + ::Color aColor( static_cast<MetaTextColorAction*>(pCurrAct)->GetColor() ); + + // force alpha part of color to + // opaque. transparent painting is done + // explicitely via META_TRANSPARENT_ACTION + aColor.SetTransparency(0); + + getState( rStates ).textColor = + ::vcl::unotools::colorToDoubleSequence( + aColor, + rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() ); + } + } + break; + + case META_TEXTFILLCOLOR_ACTION: + if( !rParms.maTextColor.is_initialized() ) + { + setStateColor( static_cast<MetaTextFillColorAction*>(pCurrAct), + getState( rStates ).isTextFillColorSet, + getState( rStates ).textFillColor, + rCanvas ); + } + break; + + case META_TEXTLINECOLOR_ACTION: + if( !rParms.maTextColor.is_initialized() ) + { + setStateColor( static_cast<MetaTextLineColorAction*>(pCurrAct), + getState( rStates ).isTextLineColorSet, + getState( rStates ).textLineColor, + rCanvas ); + } + break; + + case META_TEXTALIGN_ACTION: + { + ::cppcanvas::internal::OutDevState& rState = getState( rStates ); + const TextAlign eTextAlign( static_cast<MetaTextAlignAction*>(pCurrAct)->GetTextAlign() ); + + rState.textReferencePoint = eTextAlign; + } + break; + + case META_FONT_ACTION: + { + ::cppcanvas::internal::OutDevState& rState = getState( rStates ); + const ::Font& rFont( static_cast<MetaFontAction*>(pCurrAct)->GetFont() ); + + rState.xFont = createFont( rState.fontRotation, + rFont, + rFactoryParms ); + + // TODO(Q2): define and use appropriate enumeration types + rState.textReliefStyle = (sal_Int8)rFont.GetRelief(); + rState.textOverlineStyle = (sal_Int8)rFont.GetOverline(); + rState.textUnderlineStyle = rParms.maFontUnderline.is_initialized() ? + (*rParms.maFontUnderline ? (sal_Int8)UNDERLINE_SINGLE : (sal_Int8)UNDERLINE_NONE) : + (sal_Int8)rFont.GetUnderline(); + rState.textStrikeoutStyle = (sal_Int8)rFont.GetStrikeout(); + rState.textEmphasisMarkStyle = (sal_Int8)rFont.GetEmphasisMark(); + rState.isTextEffectShadowSet = (rFont.IsShadow() != sal_False); + rState.isTextWordUnderlineSet = (rFont.IsWordLineMode() != sal_False); + rState.isTextOutlineModeSet = (rFont.IsOutline() != sal_False); + } + break; + + case META_RASTEROP_ACTION: + // TODO(F2): NYI + break; + + case META_LAYOUTMODE_ACTION: + { + // TODO(F2): A lot is missing here + int nLayoutMode = static_cast<MetaLayoutModeAction*>(pCurrAct)->GetLayoutMode(); + ::cppcanvas::internal::OutDevState& rState = getState( rStates ); + switch( nLayoutMode & (TEXT_LAYOUT_BIDI_RTL|TEXT_LAYOUT_BIDI_STRONG) ) + { + case TEXT_LAYOUT_BIDI_LTR: + rState.textDirection = rendering::TextDirection::WEAK_LEFT_TO_RIGHT; + break; + + case (TEXT_LAYOUT_BIDI_LTR | TEXT_LAYOUT_BIDI_STRONG): + rState.textDirection = rendering::TextDirection::STRONG_LEFT_TO_RIGHT; + break; + + case TEXT_LAYOUT_BIDI_RTL: + rState.textDirection = rendering::TextDirection::WEAK_RIGHT_TO_LEFT; + break; + + case (TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_BIDI_STRONG): + rState.textDirection = rendering::TextDirection::STRONG_RIGHT_TO_LEFT; + break; + } + + rState.textAlignment = 0; // TODO(F2): rendering::TextAlignment::LEFT_ALIGNED; + if( (nLayoutMode & (TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_TEXTORIGIN_RIGHT) ) + && !(nLayoutMode & TEXT_LAYOUT_TEXTORIGIN_LEFT ) ) + { + rState.textAlignment = 1; // TODO(F2): rendering::TextAlignment::RIGHT_ALIGNED; + } + } + break; + + // ------------------------------------------------------------ + + // In the second part of this monster-switch, we + // handle all recursing meta actions. These are the + // ones generating a metafile by themselves, which is + // then processed by recursively calling this method. + + // ------------------------------------------------------------ + + case META_GRADIENT_ACTION: + { + MetaGradientAction* pGradAct = static_cast<MetaGradientAction*>(pCurrAct); + createGradientAction( ::Polygon( pGradAct->GetRect() ), + pGradAct->GetGradient(), + rFactoryParms, + true, + bSubsettableActions ); + } + break; + + case META_HATCH_ACTION: + { + // TODO(F2): use native Canvas hatches here + GDIMetaFile aTmpMtf; + + rVDev.AddHatchActions( static_cast<MetaHatchAction*>(pCurrAct)->GetPolyPolygon(), + static_cast<MetaHatchAction*>(pCurrAct)->GetHatch(), + aTmpMtf ); + createActions( aTmpMtf, rFactoryParms, + bSubsettableActions ); + } + break; + + case META_EPS_ACTION: + { + MetaEPSAction* pAct = static_cast<MetaEPSAction*>(pCurrAct); + const GDIMetaFile& rSubstitute = pAct->GetSubstitute(); + + // #121806# explicitely kept integer + const Size aMtfSize( rSubstitute.GetPrefSize() ); + const Size aMtfSizePixPre( rVDev.LogicToPixel( aMtfSize, + rSubstitute.GetPrefMapMode() ) ); + + // #i44110# correct null-sized output - there + // are metafiles which have zero size in at + // least one dimension + const Size aMtfSizePix( ::std::max( aMtfSizePixPre.Width(), 1L ), + ::std::max( aMtfSizePixPre.Height(), 1L ) ); + + // Setup local transform, such that the + // metafile renders itself into the given + // output rectangle + pushState( rStates, PUSH_ALL ); + + rVDev.Push(); + rVDev.SetMapMode( rSubstitute.GetPrefMapMode() ); + + const ::Point& rPos( rVDev.LogicToPixel( pAct->GetPoint() ) ); + const ::Size& rSize( rVDev.LogicToPixel( pAct->GetSize() ) ); + + getState( rStates ).transform.translate( rPos.X(), + rPos.Y() ); + getState( rStates ).transform.scale( (double)rSize.Width() / aMtfSizePix.Width(), + (double)rSize.Height() / aMtfSizePix.Height() ); + + createActions( const_cast<GDIMetaFile&>(pAct->GetSubstitute()), + rFactoryParms, + bSubsettableActions ); + + rVDev.Pop(); + popState( rStates ); + } + break; + + // handle metafile comments, to retrieve + // meta-information for gradients, fills and + // strokes. May skip actions, and may recurse. + case META_COMMENT_ACTION: + { + MetaCommentAction* pAct = static_cast<MetaCommentAction*>(pCurrAct); + + // Handle gradients + if ( pAct->GetComment().CompareIgnoreCaseToAscii( "XGRAD_SEQ_BEGIN" ) == COMPARE_EQUAL ) + { + MetaGradientExAction* pGradAction = NULL; + bool bDone( false ); + while( !bDone && + (pCurrAct=rMtf.NextAction()) != NULL ) + { + switch( pCurrAct->GetType() ) + { + // extract gradient info + case META_GRADIENTEX_ACTION: + pGradAction = static_cast<MetaGradientExAction*>(pCurrAct); + break; + + // skip broken-down rendering, output gradient when sequence is ended + case META_COMMENT_ACTION: + if( static_cast<MetaCommentAction*>(pCurrAct)->GetComment().CompareIgnoreCaseToAscii( "XGRAD_SEQ_END" ) == COMPARE_EQUAL ) + { + bDone = true; + + if( pGradAction ) + { + createGradientAction( pGradAction->GetPolyPolygon(), + pGradAction->GetGradient(), + rFactoryParms, + false, + bSubsettableActions ); + } + } + break; + } + } + } + // TODO(P2): Handle drawing layer strokes, via + // XPATHSTROKE_SEQ_BEGIN comment + + // Handle drawing layer fills + else if( pAct->GetComment().Equals( "XPATHFILL_SEQ_BEGIN" ) ) + { + const sal_uInt8* pData = pAct->GetData(); + if ( pData ) + { + SvMemoryStream aMemStm( (void*)pData, pAct->GetDataSize(), STREAM_READ ); + + SvtGraphicFill aFill; + aMemStm >> aFill; + + // TODO(P2): Also handle gradients and + // hatches like this + + // only evaluate comment for pure + // bitmap fills. If a transparency + // gradient is involved (denoted by + // the FloatTransparent action), take + // the normal meta actions. + if( aFill.getFillType() == SvtGraphicFill::fillTexture && + !isActionContained( rMtf, + "XPATHFILL_SEQ_END", + META_FLOATTRANSPARENT_ACTION ) ) + { + rendering::Texture aTexture; + + // TODO(F1): the SvtGraphicFill + // can also transport metafiles + // here, handle that case, too + Graphic aGraphic; + aFill.getGraphic( aGraphic ); + + BitmapEx aBmpEx( aGraphic.GetBitmapEx() ); + const ::Size aBmpSize( aBmpEx.GetSizePixel() ); + + ::SvtGraphicFill::Transform aTransform; + aFill.getTransform( aTransform ); + + ::basegfx::B2DHomMatrix aMatrix; + + // convert to basegfx matrix + aMatrix.set(0,0, aTransform.matrix[ 0 ] ); + aMatrix.set(0,1, aTransform.matrix[ 1 ] ); + aMatrix.set(0,2, aTransform.matrix[ 2 ] ); + aMatrix.set(1,0, aTransform.matrix[ 3 ] ); + aMatrix.set(1,1, aTransform.matrix[ 4 ] ); + aMatrix.set(1,2, aTransform.matrix[ 5 ] ); + + ::basegfx::B2DHomMatrix aScale; + aScale.scale( aBmpSize.Width(), + aBmpSize.Height() ); + + // post-multiply with the bitmap + // size (XCanvas' texture assumes + // the given bitmap to be + // normalized to [0,1]x[0,1] + // rectangle) + aMatrix = aMatrix * aScale; + + // pre-multiply with the + // logic-to-pixel scale factor + // (the metafile comment works in + // logical coordinates). + ::basegfx::B2DHomMatrix aLogic2PixelTransform; + aMatrix *= tools::calcLogic2PixelLinearTransform( aLogic2PixelTransform, + rVDev ); + + ::basegfx::unotools::affineMatrixFromHomMatrix( + aTexture.AffineTransform, + aMatrix ); + + aTexture.Alpha = 1.0 - aFill.getTransparency(); + aTexture.Bitmap = + ::vcl::unotools::xBitmapFromBitmapEx( + rCanvas->getUNOCanvas()->getDevice(), + aBmpEx ); + if( aFill.isTiling() ) + { + aTexture.RepeatModeX = rendering::TexturingMode::REPEAT; + aTexture.RepeatModeY = rendering::TexturingMode::REPEAT; + } + else + { + aTexture.RepeatModeX = rendering::TexturingMode::NONE; + aTexture.RepeatModeY = rendering::TexturingMode::NONE; + } + + ::PolyPolygon aPath; + aFill.getPath( aPath ); + + ::basegfx::B2DPolyPolygon aPoly( aPath.getB2DPolyPolygon() ); + aPoly.transform( getState( rStates ).mapModeTransform ); + ActionSharedPtr pPolyAction( + internal::PolyPolyActionFactory::createPolyPolyAction( + aPoly, + rCanvas, + getState( rStates ), + aTexture ) ); + + if( pPolyAction ) + { + maActions.push_back( + MtfAction( + pPolyAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pPolyAction->getActionCount()-1; + } + + // skip broken-down render output + skipContent( rMtf, + "XPATHFILL_SEQ_END", + io_rCurrActionIndex ); + } + } + } + // Handle drawing layer fills + else if( pAct->GetComment().Equals( "EMF_PLUS" ) ) { + static int count = -1, limit = 0x7fffffff; + if (count == -1) { + count = 0; + if (char *env = getenv ("EMF_PLUS_LIMIT")) { + limit = atoi (env); + EMFP_DEBUG (printf ("EMF+ records limit: %d\n", limit)); + } + } + EMFP_DEBUG (printf ("EMF+ passed to canvas mtf renderer, size: %d\n", pAct->GetDataSize ())); + if (count < limit) + processEMFPlus( pAct, rFactoryParms, getState( rStates ), rCanvas ); + count ++; + } else if( pAct->GetComment().Equals( "EMF_PLUS_HEADER_INFO" ) ) { + EMFP_DEBUG (printf ("EMF+ passed to canvas mtf renderer - header info, size: %d\n", pAct->GetDataSize ())); + + SvMemoryStream rMF ((void*) pAct->GetData (), pAct->GetDataSize (), STREAM_READ); + + rMF >> nFrameLeft >> nFrameTop >> nFrameRight >> nFrameBottom; + EMFP_DEBUG (printf ("EMF+ picture frame: %d,%d - %d,%d\n", nFrameLeft, nFrameTop, nFrameRight, nFrameBottom)); + rMF >> nPixX >> nPixY >> nMmX >> nMmY; + EMFP_DEBUG (printf ("EMF+ ref device pixel size: %dx%d mm size: %dx%d\n", nPixX, nPixY, nMmX, nMmY)); + + rMF >> aBaseTransform; + //aWorldTransform.Set (aBaseTransform); + } + } + break; + + // ------------------------------------------------------------ + + // In the third part of this monster-switch, we + // handle all 'acting' meta actions. These are all + // processed by constructing function objects for + // them, which will later ease caching. + + // ------------------------------------------------------------ + + case META_POINT_ACTION: + { + const OutDevState& rState( getState( rStates ) ); + if( rState.lineColor.getLength() ) + { + ActionSharedPtr pPointAction( + internal::PointActionFactory::createPointAction( + rState.mapModeTransform * ::vcl::unotools::b2DPointFromPoint( + static_cast<MetaPointAction*>(pCurrAct)->GetPoint() ), + rCanvas, + rState ) ); + + if( pPointAction ) + { + maActions.push_back( + MtfAction( + pPointAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pPointAction->getActionCount()-1; + } + } + } + break; + + case META_PIXEL_ACTION: + { + const OutDevState& rState( getState( rStates ) ); + if( rState.lineColor.getLength() ) + { + ActionSharedPtr pPointAction( + internal::PointActionFactory::createPointAction( + rState.mapModeTransform * ::vcl::unotools::b2DPointFromPoint( + static_cast<MetaPixelAction*>(pCurrAct)->GetPoint() ), + rCanvas, + rState, + static_cast<MetaPixelAction*>(pCurrAct)->GetColor() ) ); + + if( pPointAction ) + { + maActions.push_back( + MtfAction( + pPointAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pPointAction->getActionCount()-1; + } + } + } + break; + + case META_LINE_ACTION: + { + const OutDevState& rState( getState( rStates ) ); + if( rState.lineColor.getLength() ) + { + MetaLineAction* pLineAct = static_cast<MetaLineAction*>(pCurrAct); + + const LineInfo& rLineInfo( pLineAct->GetLineInfo() ); + + const ::basegfx::B2DPoint aStartPoint( + rState.mapModeTransform * ::vcl::unotools::b2DPointFromPoint( pLineAct->GetStartPoint() )); + const ::basegfx::B2DPoint aEndPoint( + rState.mapModeTransform * ::vcl::unotools::b2DPointFromPoint( pLineAct->GetEndPoint() )); + + ActionSharedPtr pLineAction; + + if( rLineInfo.IsDefault() ) + { + // plain hair line + pLineAction = + internal::LineActionFactory::createLineAction( + aStartPoint, + aEndPoint, + rCanvas, + rState ); + + if( pLineAction ) + { + maActions.push_back( + MtfAction( + pLineAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pLineAction->getActionCount()-1; + } + } + else if( LINE_NONE != rLineInfo.GetStyle() ) + { + // 'thick' line + rendering::StrokeAttributes aStrokeAttributes; + + setupStrokeAttributes( aStrokeAttributes, + rFactoryParms, + rLineInfo ); + + // XCanvas can only stroke polygons, + // not simple lines - thus, handle + // this case via the polypolygon + // action + ::basegfx::B2DPolygon aPoly; + aPoly.append( aStartPoint ); + aPoly.append( aEndPoint ); + pLineAction = + internal::PolyPolyActionFactory::createPolyPolyAction( + ::basegfx::B2DPolyPolygon( aPoly ), + rCanvas, rState, aStrokeAttributes ); + + if( pLineAction ) + { + maActions.push_back( + MtfAction( + pLineAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pLineAction->getActionCount()-1; + } + } + // else: line style is default + // (i.e. invisible), don't generate action + } + } + break; + + case META_RECT_ACTION: + { + const Rectangle& rRect( + static_cast<MetaRectAction*>(pCurrAct)->GetRect() ); + + if( rRect.IsEmpty() ) + break; + + const OutDevState& rState( getState( rStates ) ); + const ::basegfx::B2DPoint aTopLeftPixel( + rState.mapModeTransform * ::vcl::unotools::b2DPointFromPoint( rRect.TopLeft() ) ); + const ::basegfx::B2DPoint aBottomRightPixel( + rState.mapModeTransform * ::vcl::unotools::b2DPointFromPoint( rRect.BottomRight() ) + + // #121100# OutputDevice::DrawRect() fills + // rectangles Apple-like, i.e. with one + // additional pixel to the right and bottom. + ::basegfx::B2DPoint(1,1) ); + + createFillAndStroke( ::basegfx::tools::createPolygonFromRect( + ::basegfx::B2DRange( aTopLeftPixel, + aBottomRightPixel )), + rFactoryParms ); + break; + } + + case META_ROUNDRECT_ACTION: + { + const Rectangle& rRect( + static_cast<MetaRoundRectAction*>(pCurrAct)->GetRect()); + + if( rRect.IsEmpty() ) + break; + + ::basegfx::B2DPolygon aPoly( + ::basegfx::tools::createPolygonFromRect( + ::basegfx::B2DRange( + ::vcl::unotools::b2DPointFromPoint( rRect.TopLeft() ), + ::vcl::unotools::b2DPointFromPoint( rRect.BottomRight() ) + + ::basegfx::B2DPoint(1,1) ), + ( (double) static_cast<MetaRoundRectAction*>(pCurrAct)->GetHorzRound() ) / rRect.GetWidth(), + ( (double) static_cast<MetaRoundRectAction*>(pCurrAct)->GetVertRound() ) / rRect.GetHeight() ) ); + aPoly.transform( getState( rStates ).mapModeTransform ); + + createFillAndStroke( aPoly, + rFactoryParms ); + } + break; + + case META_ELLIPSE_ACTION: + { + const Rectangle& rRect( + static_cast<MetaEllipseAction*>(pCurrAct)->GetRect() ); + + if( rRect.IsEmpty() ) + break; + + const ::basegfx::B2DRange aRange( + ::vcl::unotools::b2DPointFromPoint( rRect.TopLeft() ), + ::vcl::unotools::b2DPointFromPoint( rRect.BottomRight() ) + + ::basegfx::B2DPoint(1,1) ); + + ::basegfx::B2DPolygon aPoly( + ::basegfx::tools::createPolygonFromEllipse( + aRange.getCenter(), + aRange.getWidth(), + aRange.getHeight() )); + aPoly.transform( getState( rStates ).mapModeTransform ); + + createFillAndStroke( aPoly, + rFactoryParms ); + } + break; + + case META_ARC_ACTION: + { + // TODO(F1): Missing basegfx functionality. Mind empty rects! + const Polygon aToolsPoly( static_cast<MetaArcAction*>(pCurrAct)->GetRect(), + static_cast<MetaArcAction*>(pCurrAct)->GetStartPoint(), + static_cast<MetaArcAction*>(pCurrAct)->GetEndPoint(), POLY_ARC ); + ::basegfx::B2DPolygon aPoly( aToolsPoly.getB2DPolygon() ); + aPoly.transform( getState( rStates ).mapModeTransform ); + + createFillAndStroke( aPoly, + rFactoryParms ); + } + break; + + case META_PIE_ACTION: + { + // TODO(F1): Missing basegfx functionality. Mind empty rects! + const Polygon aToolsPoly( static_cast<MetaPieAction*>(pCurrAct)->GetRect(), + static_cast<MetaPieAction*>(pCurrAct)->GetStartPoint(), + static_cast<MetaPieAction*>(pCurrAct)->GetEndPoint(), POLY_PIE ); + ::basegfx::B2DPolygon aPoly( aToolsPoly.getB2DPolygon() ); + aPoly.transform( getState( rStates ).mapModeTransform ); + + createFillAndStroke( aPoly, + rFactoryParms ); + } + break; + + case META_CHORD_ACTION: + { + // TODO(F1): Missing basegfx functionality. Mind empty rects! + const Polygon aToolsPoly( static_cast<MetaChordAction*>(pCurrAct)->GetRect(), + static_cast<MetaChordAction*>(pCurrAct)->GetStartPoint(), + static_cast<MetaChordAction*>(pCurrAct)->GetEndPoint(), POLY_CHORD ); + ::basegfx::B2DPolygon aPoly( aToolsPoly.getB2DPolygon() ); + aPoly.transform( getState( rStates ).mapModeTransform ); + + createFillAndStroke( aPoly, + rFactoryParms ); + } + break; + + case META_POLYLINE_ACTION: + { + const OutDevState& rState( getState( rStates ) ); + if( rState.lineColor.getLength() || + rState.fillColor.getLength() ) + { + MetaPolyLineAction* pPolyLineAct = static_cast<MetaPolyLineAction*>(pCurrAct); + + const LineInfo& rLineInfo( pPolyLineAct->GetLineInfo() ); + ::basegfx::B2DPolygon aPoly( pPolyLineAct->GetPolygon().getB2DPolygon() ); + aPoly.transform( rState.mapModeTransform ); + + ActionSharedPtr pLineAction; + + if( rLineInfo.IsDefault() ) + { + // plain hair line polygon + pLineAction = + internal::PolyPolyActionFactory::createLinePolyPolyAction( + ::basegfx::B2DPolyPolygon(aPoly), + rCanvas, + rState ); + + if( pLineAction ) + { + maActions.push_back( + MtfAction( + pLineAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pLineAction->getActionCount()-1; + } + } + else if( LINE_NONE != rLineInfo.GetStyle() ) + { + // 'thick' line polygon + rendering::StrokeAttributes aStrokeAttributes; + + setupStrokeAttributes( aStrokeAttributes, + rFactoryParms, + rLineInfo ); + + pLineAction = + internal::PolyPolyActionFactory::createPolyPolyAction( + ::basegfx::B2DPolyPolygon(aPoly), + rCanvas, + rState, + aStrokeAttributes ) ; + + if( pLineAction ) + { + maActions.push_back( + MtfAction( + pLineAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pLineAction->getActionCount()-1; + } + } + // else: line style is default + // (i.e. invisible), don't generate action + } + } + break; + + case META_POLYGON_ACTION: + { + ::basegfx::B2DPolygon aPoly( static_cast<MetaPolygonAction*>(pCurrAct)->GetPolygon().getB2DPolygon() ); + aPoly.transform( getState( rStates ).mapModeTransform ); + createFillAndStroke( aPoly, + rFactoryParms ); + } + break; + + case META_POLYPOLYGON_ACTION: + { + ::basegfx::B2DPolyPolygon aPoly( static_cast<MetaPolyPolygonAction*>(pCurrAct)->GetPolyPolygon().getB2DPolyPolygon() ); + aPoly.transform( getState( rStates ).mapModeTransform ); + createFillAndStroke( aPoly, + rFactoryParms ); + } + break; + + case META_BMP_ACTION: + { + MetaBmpAction* pAct = static_cast<MetaBmpAction*>(pCurrAct); + + ActionSharedPtr pBmpAction( + internal::BitmapActionFactory::createBitmapAction( + pAct->GetBitmap(), + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ), + rCanvas, + getState( rStates ) ) ); + + if( pBmpAction ) + { + maActions.push_back( + MtfAction( + pBmpAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pBmpAction->getActionCount()-1; + } + } + break; + + case META_BMPSCALE_ACTION: + { + MetaBmpScaleAction* pAct = static_cast<MetaBmpScaleAction*>(pCurrAct); + + ActionSharedPtr pBmpAction( + internal::BitmapActionFactory::createBitmapAction( + pAct->GetBitmap(), + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ), + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DSizeFromSize( pAct->GetSize() ), + rCanvas, + getState( rStates ) ) ); + + if( pBmpAction ) + { + maActions.push_back( + MtfAction( + pBmpAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pBmpAction->getActionCount()-1; + } + } + break; + + case META_BMPSCALEPART_ACTION: + { + MetaBmpScalePartAction* pAct = static_cast<MetaBmpScalePartAction*>(pCurrAct); + + // crop bitmap to given source rectangle (no + // need to copy and convert the whole bitmap) + Bitmap aBmp( pAct->GetBitmap() ); + const Rectangle aCropRect( pAct->GetSrcPoint(), + pAct->GetSrcSize() ); + aBmp.Crop( aCropRect ); + + ActionSharedPtr pBmpAction( + internal::BitmapActionFactory::createBitmapAction( + aBmp, + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DPointFromPoint( pAct->GetDestPoint() ), + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DSizeFromSize( pAct->GetDestSize() ), + rCanvas, + getState( rStates ) ) ); + + if( pBmpAction ) + { + maActions.push_back( + MtfAction( + pBmpAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pBmpAction->getActionCount()-1; + } + } + break; + + case META_BMPEX_ACTION: + { + MetaBmpExAction* pAct = static_cast<MetaBmpExAction*>(pCurrAct); + + ActionSharedPtr pBmpAction( + internal::BitmapActionFactory::createBitmapAction( + pAct->GetBitmapEx(), + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ), + rCanvas, + getState( rStates ) ) ); + + if( pBmpAction ) + { + maActions.push_back( + MtfAction( + pBmpAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pBmpAction->getActionCount()-1; + } + } + break; + + case META_BMPEXSCALE_ACTION: + { + MetaBmpExScaleAction* pAct = static_cast<MetaBmpExScaleAction*>(pCurrAct); + + ActionSharedPtr pBmpAction( + internal::BitmapActionFactory::createBitmapAction( + pAct->GetBitmapEx(), + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ), + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DSizeFromSize( pAct->GetSize() ), + rCanvas, + getState( rStates ) ) ); + + if( pBmpAction ) + { + maActions.push_back( + MtfAction( + pBmpAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pBmpAction->getActionCount()-1; + } + } + break; + + case META_BMPEXSCALEPART_ACTION: + { + MetaBmpExScalePartAction* pAct = static_cast<MetaBmpExScalePartAction*>(pCurrAct); + + // crop bitmap to given source rectangle (no + // need to copy and convert the whole bitmap) + BitmapEx aBmp( pAct->GetBitmapEx() ); + const Rectangle aCropRect( pAct->GetSrcPoint(), + pAct->GetSrcSize() ); + aBmp.Crop( aCropRect ); + + ActionSharedPtr pBmpAction( + internal::BitmapActionFactory::createBitmapAction( + aBmp, + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DPointFromPoint( pAct->GetDestPoint() ), + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DSizeFromSize( pAct->GetDestSize() ), + rCanvas, + getState( rStates ) ) ); + + if( pBmpAction ) + { + maActions.push_back( + MtfAction( + pBmpAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pBmpAction->getActionCount()-1; + } + } + break; + + case META_MASK_ACTION: + { + MetaMaskAction* pAct = static_cast<MetaMaskAction*>(pCurrAct); + + // create masked BitmapEx right here, as the + // canvas does not provide equivalent + // functionality + BitmapEx aBmp( createMaskBmpEx( pAct->GetBitmap(), + pAct->GetColor() )); + + ActionSharedPtr pBmpAction( + internal::BitmapActionFactory::createBitmapAction( + aBmp, + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ), + rCanvas, + getState( rStates ) ) ); + + if( pBmpAction ) + { + maActions.push_back( + MtfAction( + pBmpAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pBmpAction->getActionCount()-1; + } + } + break; + + case META_MASKSCALE_ACTION: + { + MetaMaskScaleAction* pAct = static_cast<MetaMaskScaleAction*>(pCurrAct); + + // create masked BitmapEx right here, as the + // canvas does not provide equivalent + // functionality + BitmapEx aBmp( createMaskBmpEx( pAct->GetBitmap(), + pAct->GetColor() )); + + ActionSharedPtr pBmpAction( + internal::BitmapActionFactory::createBitmapAction( + aBmp, + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ), + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DSizeFromSize( pAct->GetSize() ), + rCanvas, + getState( rStates ) ) ); + + if( pBmpAction ) + { + maActions.push_back( + MtfAction( + pBmpAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pBmpAction->getActionCount()-1; + } + } + break; + + case META_MASKSCALEPART_ACTION: + { + MetaMaskScalePartAction* pAct = static_cast<MetaMaskScalePartAction*>(pCurrAct); + + // create masked BitmapEx right here, as the + // canvas does not provide equivalent + // functionality + BitmapEx aBmp( createMaskBmpEx( pAct->GetBitmap(), + pAct->GetColor() )); + + // crop bitmap to given source rectangle (no + // need to copy and convert the whole bitmap) + const Rectangle aCropRect( pAct->GetSrcPoint(), + pAct->GetSrcSize() ); + aBmp.Crop( aCropRect ); + + ActionSharedPtr pBmpAction( + internal::BitmapActionFactory::createBitmapAction( + aBmp, + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DPointFromPoint( pAct->GetDestPoint() ), + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DSizeFromSize( pAct->GetDestSize() ), + rCanvas, + getState( rStates ) ) ); + + if( pBmpAction ) + { + maActions.push_back( + MtfAction( + pBmpAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pBmpAction->getActionCount()-1; + } + } + break; + + case META_GRADIENTEX_ACTION: + // TODO(F1): use native Canvas gradients here + // action is ignored here, because redundant to META_GRADIENT_ACTION + break; + + case META_WALLPAPER_ACTION: + // TODO(F2): NYI + break; + + case META_TRANSPARENT_ACTION: + { + const OutDevState& rState( getState( rStates ) ); + if( rState.lineColor.getLength() || + rState.fillColor.getLength() ) + { + MetaTransparentAction* pAct = static_cast<MetaTransparentAction*>(pCurrAct); + ::basegfx::B2DPolyPolygon aPoly( pAct->GetPolyPolygon().getB2DPolyPolygon() ); + aPoly.transform( rState.mapModeTransform ); + + ActionSharedPtr pPolyAction( + internal::PolyPolyActionFactory::createPolyPolyAction( + aPoly, + rCanvas, + rState, + pAct->GetTransparence() ) ); + + if( pPolyAction ) + { + maActions.push_back( + MtfAction( + pPolyAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pPolyAction->getActionCount()-1; + } + } + } + break; + + case META_FLOATTRANSPARENT_ACTION: + { + MetaFloatTransparentAction* pAct = static_cast<MetaFloatTransparentAction*>(pCurrAct); + + internal::MtfAutoPtr pMtf( + new ::GDIMetaFile( pAct->GetGDIMetaFile() ) ); + + // TODO(P2): Use native canvas gradients here (saves a lot of UNO calls) + internal::GradientAutoPtr pGradient( + new Gradient( pAct->GetGradient() ) ); + + DBG_TESTSOLARMUTEX(); + + ActionSharedPtr pFloatTransAction( + internal::TransparencyGroupActionFactory::createTransparencyGroupAction( + pMtf, + pGradient, + rParms, + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ), + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DSizeFromSize( pAct->GetSize() ), + rCanvas, + getState( rStates ) ) ); + + if( pFloatTransAction ) + { + maActions.push_back( + MtfAction( + pFloatTransAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pFloatTransAction->getActionCount()-1; + } + } + break; + + case META_TEXT_ACTION: + { + MetaTextAction* pAct = static_cast<MetaTextAction*>(pCurrAct); + XubString sText = XubString( pAct->GetText() ); + + if( rVDev.GetDigitLanguage()) + convertToLocalizedNumerals ( sText,rVDev.GetDigitLanguage() ); + + createTextAction( + pAct->GetPoint(), + sText, + pAct->GetIndex(), + pAct->GetLen() == (sal_uInt16)STRING_LEN ? pAct->GetText().Len() - pAct->GetIndex() : pAct->GetLen(), + NULL, + rFactoryParms, + bSubsettableActions ); + } + break; + + case META_TEXTARRAY_ACTION: + { + MetaTextArrayAction* pAct = static_cast<MetaTextArrayAction*>(pCurrAct); + XubString sText = XubString( pAct->GetText() ); + + if( rVDev.GetDigitLanguage()) + convertToLocalizedNumerals ( sText,rVDev.GetDigitLanguage() ); + + createTextAction( + pAct->GetPoint(), + sText, + pAct->GetIndex(), + pAct->GetLen() == (sal_uInt16)STRING_LEN ? pAct->GetText().Len() - pAct->GetIndex() : pAct->GetLen(), + pAct->GetDXArray(), + rFactoryParms, + bSubsettableActions ); + } + break; + + case META_TEXTLINE_ACTION: + { + MetaTextLineAction* pAct = static_cast<MetaTextLineAction*>(pCurrAct); + + const OutDevState& rState( getState( rStates ) ); + const ::Size aBaselineOffset( tools::getBaselineOffset( rState, + rVDev ) ); + const ::Point aStartPoint( pAct->GetStartPoint() ); + const ::basegfx::B2DSize aSize( rState.mapModeTransform * + ::basegfx::B2DSize(pAct->GetWidth(), + 0 )); + + ActionSharedPtr pPolyAction( + PolyPolyActionFactory::createPolyPolyAction( + tools::createTextLinesPolyPolygon( + rState.mapModeTransform * + ::basegfx::B2DPoint( + ::vcl::unotools::b2DPointFromPoint(pAct->GetStartPoint()) + + ::vcl::unotools::b2DSizeFromSize(aBaselineOffset)), + aSize.getX(), + tools::createTextLineInfo( rVDev, + rState )), + rCanvas, + rState ) ); + + if( pPolyAction.get() ) + { + maActions.push_back( + MtfAction( + pPolyAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pPolyAction->getActionCount()-1; + } + } + break; + + case META_TEXTRECT_ACTION: + { + MetaTextRectAction* pAct = static_cast<MetaTextRectAction*>(pCurrAct); + + pushState( rStates, PUSH_ALL ); + + // use the VDev to break up the text rect + // action into readily formatted lines + GDIMetaFile aTmpMtf; + rVDev.AddTextRectActions( pAct->GetRect(), + pAct->GetText(), + pAct->GetStyle(), + aTmpMtf ); + + createActions( aTmpMtf, + rFactoryParms, + bSubsettableActions ); + + popState( rStates ); + + break; + } + + case META_STRETCHTEXT_ACTION: + { + MetaStretchTextAction* pAct = static_cast<MetaStretchTextAction*>(pCurrAct); + XubString sText = XubString( pAct->GetText() ); + + if( rVDev.GetDigitLanguage()) + convertToLocalizedNumerals ( sText,rVDev.GetDigitLanguage() ); + + const sal_uInt16 nLen( pAct->GetLen() == (sal_uInt16)STRING_LEN ? + pAct->GetText().Len() - pAct->GetIndex() : pAct->GetLen() ); + + // #i70897# Nothing to do, actually... + if( nLen == 0 ) + break; + + // have to fit the text into the given + // width. This is achieved by internally + // generating a DX array, and uniformly + // distributing the excess/insufficient width + // to every logical character. + ::boost::scoped_array< sal_Int32 > pDXArray( new sal_Int32[nLen] ); + + rVDev.GetTextArray( pAct->GetText(), pDXArray.get(), + pAct->GetIndex(), pAct->GetLen() ); + + const sal_Int32 nWidthDifference( pAct->GetWidth() - pDXArray[ nLen-1 ] ); + + // Last entry of pDXArray contains total width of the text + sal_Int32* p=pDXArray.get(); + for( sal_uInt16 i=1; i<=nLen; ++i ) + { + // calc ratio for every array entry, to + // distribute rounding errors 'evenly' + // across the characters. Note that each + // entry represents the 'end' position of + // the corresponding character, thus, we + // let i run from 1 to nLen. + *p++ += (sal_Int32)i*nWidthDifference/nLen; + } + + createTextAction( + pAct->GetPoint(), + sText, + pAct->GetIndex(), + pAct->GetLen() == (sal_uInt16)STRING_LEN ? pAct->GetText().Len() - pAct->GetIndex() : pAct->GetLen(), + pDXArray.get(), + rFactoryParms, + bSubsettableActions ); + } + break; + + case META_RENDERGRAPHIC_ACTION: + { + MetaRenderGraphicAction* pAct = static_cast<MetaRenderGraphicAction*>(pCurrAct); + + ActionSharedPtr pRenderGraphicAction( + internal::RenderGraphicActionFactory::createRenderGraphicAction( + pAct->GetRenderGraphic(), + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ), + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DSizeFromSize( pAct->GetSize() ), + rCanvas, + getState( rStates ) ) ); + + if( pRenderGraphicAction ) + { + maActions.push_back( + MtfAction( + pRenderGraphicAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pRenderGraphicAction->getActionCount()-1; + } + } + break; + + default: + OSL_FAIL( "Unknown meta action type encountered" ); + break; + } + + // increment action index (each mtf action counts _at + // least_ one. Some count for more, therefore, + // io_rCurrActionIndex is sometimes incremented by + // pAct->getActionCount()-1 above, the -1 being the + // correction for the unconditional increment here). + ++io_rCurrActionIndex; + } + + return true; + } + + + namespace + { + class ActionRenderer + { + public: + ActionRenderer( const ::basegfx::B2DHomMatrix& rTransformation ) : + maTransformation( rTransformation ), + mbRet( true ) + { + } + + bool result() const + { + return mbRet; + } + + void operator()( const ::cppcanvas::internal::ImplRenderer::MtfAction& rAction ) + { + // ANDing the result. We want to fail if at least + // one action failed. + mbRet &= rAction.mpAction->render( maTransformation ); + } + + void operator()( const ::cppcanvas::internal::ImplRenderer::MtfAction& rAction, + const Action::Subset& rSubset ) + { + // ANDing the result. We want to fail if at least + // one action failed. + mbRet &= rAction.mpAction->render( maTransformation, + rSubset ); + } + + private: + ::basegfx::B2DHomMatrix maTransformation; + bool mbRet; + }; + + class AreaQuery + { + public: + AreaQuery( const ::basegfx::B2DHomMatrix& rTransformation ) : + maTransformation( rTransformation ), + maBounds() + { + } + + bool result() const + { + return true; // nothing can fail here + } + + void operator()( const ::cppcanvas::internal::ImplRenderer::MtfAction& rAction ) + { + maBounds.expand( rAction.mpAction->getBounds( maTransformation ) ); + } + + void operator()( const ::cppcanvas::internal::ImplRenderer::MtfAction& rAction, + const Action::Subset& rSubset ) + { + maBounds.expand( rAction.mpAction->getBounds( maTransformation, + rSubset ) ); + } + + ::basegfx::B2DRange getBounds() const + { + return maBounds; + } + + private: + ::basegfx::B2DHomMatrix maTransformation; + ::basegfx::B2DRange maBounds; + }; + + // Doing that via inline class. Compilers tend to not inline free + // functions. + struct UpperBoundActionIndexComparator + { + bool operator()( const ::cppcanvas::internal::ImplRenderer::MtfAction& rLHS, + const ::cppcanvas::internal::ImplRenderer::MtfAction& rRHS ) + { + const sal_Int32 nLHSCount( rLHS.mpAction ? + rLHS.mpAction->getActionCount() : 0 ); + const sal_Int32 nRHSCount( rRHS.mpAction ? + rRHS.mpAction->getActionCount() : 0 ); + + // compare end of action range, to have an action selected + // by lower_bound even if the requested index points in + // the middle of the action's range + return rLHS.mnOrigIndex + nLHSCount < rRHS.mnOrigIndex + nRHSCount; + } + }; + + /** Algorithm to apply given functor to a subset range + + @tpl Functor + + Functor to call for each element of the subset + range. Must provide the following method signatures: + bool result() (returning false if operation failed) + + */ + template< typename Functor > bool + forSubsetRange( Functor& rFunctor, + ImplRenderer::ActionVector::const_iterator aRangeBegin, + ImplRenderer::ActionVector::const_iterator aRangeEnd, + sal_Int32 nStartIndex, + sal_Int32 nEndIndex, + const ImplRenderer::ActionVector::const_iterator& rEnd ) + { + if( aRangeBegin == aRangeEnd ) + { + // only a single action. Setup subset, and call functor + Action::Subset aSubset; + aSubset.mnSubsetBegin = ::std::max( sal_Int32( 0 ), + nStartIndex - aRangeBegin->mnOrigIndex ); + aSubset.mnSubsetEnd = ::std::min( aRangeBegin->mpAction->getActionCount(), + nEndIndex - aRangeBegin->mnOrigIndex ); + + ENSURE_OR_RETURN_FALSE( aSubset.mnSubsetBegin >= 0 && aSubset.mnSubsetEnd >= 0, + "ImplRenderer::forSubsetRange(): Invalid indices" ); + + rFunctor( *aRangeBegin, aSubset ); + } + else + { + // more than one action. + + // render partial first, full intermediate, and + // partial last action + Action::Subset aSubset; + aSubset.mnSubsetBegin = ::std::max( sal_Int32( 0 ), + nStartIndex - aRangeBegin->mnOrigIndex ); + aSubset.mnSubsetEnd = aRangeBegin->mpAction->getActionCount(); + + ENSURE_OR_RETURN_FALSE( aSubset.mnSubsetBegin >= 0 && aSubset.mnSubsetEnd >= 0, + "ImplRenderer::forSubsetRange(): Invalid indices" ); + + rFunctor( *aRangeBegin, aSubset ); + + // first action rendered, skip to next + ++aRangeBegin; + + // render full middle actions + while( aRangeBegin != aRangeEnd ) + rFunctor( *aRangeBegin++ ); + + if( aRangeEnd == rEnd || + aRangeEnd->mnOrigIndex > nEndIndex ) + { + // aRangeEnd denotes end of action vector, + // + // or + // + // nEndIndex references something _after_ + // aRangeBegin, but _before_ aRangeEnd + // + // either way: no partial action left + return rFunctor.result(); + } + + aSubset.mnSubsetBegin = 0; + aSubset.mnSubsetEnd = nEndIndex - aRangeEnd->mnOrigIndex; + + ENSURE_OR_RETURN_FALSE( aSubset.mnSubsetBegin >= 0 && aSubset.mnSubsetEnd >= 0, + "ImplRenderer::forSubsetRange(): Invalid indices" ); + + rFunctor( *aRangeEnd, aSubset ); + } + + return rFunctor.result(); + } + } + + bool ImplRenderer::getSubsetIndices( sal_Int32& io_rStartIndex, + sal_Int32& io_rEndIndex, + ActionVector::const_iterator& o_rRangeBegin, + ActionVector::const_iterator& o_rRangeEnd ) const + { + ENSURE_OR_RETURN_FALSE( io_rStartIndex<=io_rEndIndex, + "ImplRenderer::getSubsetIndices(): invalid action range" ); + + ENSURE_OR_RETURN_FALSE( !maActions.empty(), + "ImplRenderer::getSubsetIndices(): no actions to render" ); + + const sal_Int32 nMinActionIndex( maActions.front().mnOrigIndex ); + const sal_Int32 nMaxActionIndex( maActions.back().mnOrigIndex + + maActions.back().mpAction->getActionCount() ); + + // clip given range to permissible values (there might be + // ranges before and behind the valid indices) + io_rStartIndex = ::std::max( nMinActionIndex, + io_rStartIndex ); + io_rEndIndex = ::std::min( nMaxActionIndex, + io_rEndIndex ); + + if( io_rStartIndex == io_rEndIndex || + io_rStartIndex > io_rEndIndex ) + { + // empty range, don't render anything. The second + // condition e.g. happens if the requested range lies + // fully before or behind the valid action indices. + return false; + } + + + const ActionVector::const_iterator aBegin( maActions.begin() ); + const ActionVector::const_iterator aEnd( maActions.end() ); + + + // find start and end action + // ========================= + o_rRangeBegin = ::std::lower_bound( aBegin, aEnd, + MtfAction( ActionSharedPtr(), io_rStartIndex ), + UpperBoundActionIndexComparator() ); + o_rRangeEnd = ::std::lower_bound( aBegin, aEnd, + MtfAction( ActionSharedPtr(), io_rEndIndex ), + UpperBoundActionIndexComparator() ); + return true; + } + + + // Public methods + // ==================================================================== + + ImplRenderer::ImplRenderer( const CanvasSharedPtr& rCanvas, + const GDIMetaFile& rMtf, + const Parameters& rParams ) : + CanvasGraphicHelper( rCanvas ), + maActions() + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::ImplRenderer::ImplRenderer(mtf)" ); + + OSL_ENSURE( rCanvas.get() != NULL && rCanvas->getUNOCanvas().is(), + "ImplRenderer::ImplRenderer(): Invalid canvas" ); + OSL_ENSURE( rCanvas->getUNOCanvas()->getDevice().is(), + "ImplRenderer::ImplRenderer(): Invalid graphic device" ); + + // make sure canvas and graphic device are valid; action + // creation don't check that every time + if( rCanvas.get() == NULL || + !rCanvas->getUNOCanvas().is() || + !rCanvas->getUNOCanvas()->getDevice().is() ) + { + // leave actions empty + return; + } + + VectorOfOutDevStates aStateStack; + + VirtualDevice aVDev; + aVDev.EnableOutput( sal_False ); + + // Setup VDev for state tracking and mapping + // ========================================= + + aVDev.SetMapMode( rMtf.GetPrefMapMode() ); + + const Size aMtfSize( rMtf.GetPrefSize() ); + const Size aMtfSizePixPre( aVDev.LogicToPixel( aMtfSize, + rMtf.GetPrefMapMode() ) ); + const Point aEmptyPt; + const Point aMtfOriginPix( aVDev.LogicToPixel( aEmptyPt ) ); + + // #i44110# correct null-sized output - there are shapes + // which have zero size in at least one dimension + const Size aMtfSizePix( ::std::max( aMtfSizePixPre.Width(), 1L ), + ::std::max( aMtfSizePixPre.Height(), 1L ) ); + + sal_Int32 nCurrActions(0); + ActionFactoryParameters aParms(aStateStack, + rCanvas, + aVDev, + rParams, + nCurrActions ); + + // init state stack + clearStateStack( aStateStack ); + + // Setup local state, such that the metafile renders + // itself into a one-by-one square at the origin for + // identity view and render transformations + getState( aStateStack ).transform.scale( 1.0 / aMtfSizePix.Width(), + 1.0 / aMtfSizePix.Height() ); + + tools::calcLogic2PixelAffineTransform( getState( aStateStack ).mapModeTransform, + aVDev ); + + ColorSharedPtr pColor( getCanvas()->createColor() ); + + // setup default text color to black + getState( aStateStack ).textColor = + getState( aStateStack ).textFillColor = + getState( aStateStack ).textLineColor = pColor->getDeviceColor( 0x000000FF ); + + // apply overrides from the Parameters struct + if( rParams.maFillColor.is_initialized() ) + { + getState( aStateStack ).isFillColorSet = true; + getState( aStateStack ).fillColor = pColor->getDeviceColor( *rParams.maFillColor ); + } + if( rParams.maLineColor.is_initialized() ) + { + getState( aStateStack ).isLineColorSet = true; + getState( aStateStack ).lineColor = pColor->getDeviceColor( *rParams.maLineColor ); + } + if( rParams.maTextColor.is_initialized() ) + { + getState( aStateStack ).isTextFillColorSet = true; + getState( aStateStack ).isTextLineColorSet = true; + getState( aStateStack ).textColor = + getState( aStateStack ).textFillColor = + getState( aStateStack ).textLineColor = pColor->getDeviceColor( *rParams.maTextColor ); + } + if( rParams.maFontName.is_initialized() || + rParams.maFontWeight.is_initialized() || + rParams.maFontLetterForm.is_initialized() || + rParams.maFontUnderline.is_initialized() || + rParams.maFontProportion.is_initialized() ) + { + ::cppcanvas::internal::OutDevState& rState = getState( aStateStack ); + + rState.xFont = createFont( rState.fontRotation, + ::Font(), // default font + aParms ); + } + + /* EMF+ */ + memset (aObjects, 0, sizeof (aObjects)); + mbMultipart = false; + + createActions( const_cast<GDIMetaFile&>(rMtf), // HACK(Q2): + // we're + // changing + // the + // current + // action + // in + // createActions! + aParms, + true // TODO(P1): make subsettability configurable + ); + } + + ImplRenderer::ImplRenderer( const CanvasSharedPtr& rCanvas, + const BitmapEx& rBmpEx, + const Parameters& rParams ) : + CanvasGraphicHelper( rCanvas ), + maActions() + { + // TODO(F3): property modification parameters are + // currently ignored for Bitmaps + (void)rParams; + + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::ImplRenderer::ImplRenderer(bitmap)" ); + + OSL_ENSURE( rCanvas.get() != NULL && rCanvas->getUNOCanvas().is(), + "ImplRenderer::ImplRenderer(): Invalid canvas" ); + OSL_ENSURE( rCanvas->getUNOCanvas()->getDevice().is(), + "ImplRenderer::ImplRenderer(): Invalid graphic device" ); + + // make sure canvas and graphic device are valid; action + // creation don't check that every time + if( rCanvas.get() == NULL || + !rCanvas->getUNOCanvas().is() || + !rCanvas->getUNOCanvas()->getDevice().is() ) + { + // leave actions empty + return; + } + + OutDevState aState; + + const Size aBmpSize( rBmpEx.GetSizePixel() ); + + // Setup local state, such that the bitmap renders itself + // into a one-by-one square for identity view and render + // transformations + aState.transform.scale( 1.0 / aBmpSize.Width(), + 1.0 / aBmpSize.Height() ); + + // create a single action for the provided BitmapEx + maActions.push_back( + MtfAction( + BitmapActionFactory::createBitmapAction( + rBmpEx, + ::basegfx::B2DPoint(), + rCanvas, + aState), + 0 ) ); + } + + ImplRenderer::~ImplRenderer() + { + } + + bool ImplRenderer::drawSubset( sal_Int32 nStartIndex, + sal_Int32 nEndIndex ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::ImplRenderer::drawSubset()" ); + + ActionVector::const_iterator aRangeBegin; + ActionVector::const_iterator aRangeEnd; + + try + { + if( !getSubsetIndices( nStartIndex, nEndIndex, + aRangeBegin, aRangeEnd ) ) + return true; // nothing to render (but _that_ was successful) + + // now, aRangeBegin references the action in which the + // subset rendering must start, and aRangeEnd references + // the action in which the subset rendering must end (it + // might also end right at the start of the referenced + // action, such that zero of that action needs to be + // rendered). + + + // render subset of actions + // ======================== + + ::basegfx::B2DHomMatrix aMatrix; + ::canvas::tools::getRenderStateTransform( aMatrix, + getRenderState() ); + + ActionRenderer aRenderer( aMatrix ); + + return forSubsetRange( aRenderer, + aRangeBegin, + aRangeEnd, + nStartIndex, + nEndIndex, + maActions.end() ); + } + catch( uno::Exception& ) + { + OSL_FAIL( rtl::OUStringToOString( + comphelper::anyToString( cppu::getCaughtException() ), + RTL_TEXTENCODING_UTF8 ).getStr() ); + + // convert error to return value + return false; + } + } + + ::basegfx::B2DRange ImplRenderer::getSubsetArea( sal_Int32 nStartIndex, + sal_Int32 nEndIndex ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::ImplRenderer::getSubsetArea()" ); + + ActionVector::const_iterator aRangeBegin; + ActionVector::const_iterator aRangeEnd; + + if( !getSubsetIndices( nStartIndex, nEndIndex, + aRangeBegin, aRangeEnd ) ) + return ::basegfx::B2DRange(); // nothing to render -> empty range + + // now, aRangeBegin references the action in which the + // subset querying must start, and aRangeEnd references + // the action in which the subset querying must end (it + // might also end right at the start of the referenced + // action, such that zero of that action needs to be + // queried). + + + // query bounds for subset of actions + // ================================== + + ::basegfx::B2DHomMatrix aMatrix; + ::canvas::tools::getRenderStateTransform( aMatrix, + getRenderState() ); + + AreaQuery aQuery( aMatrix ); + forSubsetRange( aQuery, + aRangeBegin, + aRangeEnd, + nStartIndex, + nEndIndex, + maActions.end() ); + + return aQuery.getBounds(); + } + + bool ImplRenderer::draw() const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::ImplRenderer::draw()" ); + + ::basegfx::B2DHomMatrix aMatrix; + ::canvas::tools::getRenderStateTransform( aMatrix, + getRenderState() ); + + try + { + return ::std::for_each( maActions.begin(), maActions.end(), ActionRenderer( aMatrix ) ).result(); + } + catch( uno::Exception& ) + { + OSL_FAIL( rtl::OUStringToOString( + comphelper::anyToString( cppu::getCaughtException() ), + RTL_TEXTENCODING_UTF8 ).getStr() ); + + return false; + } + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/mtfrenderer/lineaction.cxx b/cppcanvas/source/mtfrenderer/lineaction.cxx new file mode 100644 index 000000000000..7639fe352511 --- /dev/null +++ b/cppcanvas/source/mtfrenderer/lineaction.cxx @@ -0,0 +1,170 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cppcanvas.hxx" + +#include <lineaction.hxx> +#include <outdevstate.hxx> + +#include <rtl/logfile.hxx> +#include <com/sun/star/rendering/XCanvas.hpp> + +#include <tools/gen.hxx> +#include <vcl/canvastools.hxx> + +#include <basegfx/range/b2drange.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <canvas/canvastools.hxx> + +#include <boost/utility.hpp> + +#include <cppcanvas/canvas.hxx> + +#include <mtftools.hxx> + + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace internal + { + namespace + { + class LineAction : public Action, private ::boost::noncopyable + { + public: + LineAction( const ::basegfx::B2DPoint&, + const ::basegfx::B2DPoint&, + const CanvasSharedPtr&, + const OutDevState& ); + + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual sal_Int32 getActionCount() const; + + private: + ::basegfx::B2DPoint maStartPoint; + ::basegfx::B2DPoint maEndPoint; + CanvasSharedPtr mpCanvas; + rendering::RenderState maState; + }; + + LineAction::LineAction( const ::basegfx::B2DPoint& rStartPoint, + const ::basegfx::B2DPoint& rEndPoint, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) : + maStartPoint( rStartPoint ), + maEndPoint( rEndPoint ), + mpCanvas( rCanvas ), + maState() + { + tools::initRenderState(maState,rState); + maState.DeviceColor = rState.lineColor; + } + + bool LineAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::LineAction::render()" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::LineAction: 0x%X", this ); + + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + mpCanvas->getUNOCanvas()->drawLine( ::basegfx::unotools::point2DFromB2DPoint(maStartPoint), + ::basegfx::unotools::point2DFromB2DPoint(maEndPoint), + mpCanvas->getViewState(), + aLocalState ); + + return true; + } + + bool LineAction::render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + // line only contains a single action, fail if subset + // requests different range + if( rSubset.mnSubsetBegin != 0 || + rSubset.mnSubsetEnd != 1 ) + return false; + + return render( rTransformation ); + } + + ::basegfx::B2DRange LineAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + return tools::calcDevicePixelBounds( ::basegfx::B2DRange( maStartPoint, + maEndPoint ), + mpCanvas->getViewState(), + aLocalState ); + } + + ::basegfx::B2DRange LineAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + // line only contains a single action, empty bounds + // if subset requests different range + if( rSubset.mnSubsetBegin != 0 || + rSubset.mnSubsetEnd != 1 ) + return ::basegfx::B2DRange(); + + return getBounds( rTransformation ); + } + + sal_Int32 LineAction::getActionCount() const + { + return 1; + } + } + + ActionSharedPtr LineActionFactory::createLineAction( const ::basegfx::B2DPoint& rStartPoint, + const ::basegfx::B2DPoint& rEndPoint, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) + { + return ActionSharedPtr( new LineAction( rStartPoint, + rEndPoint, + rCanvas, + rState) ); + } + + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/mtfrenderer/lineaction.hxx b/cppcanvas/source/mtfrenderer/lineaction.hxx new file mode 100644 index 000000000000..810c8cb4fe03 --- /dev/null +++ b/cppcanvas/source/mtfrenderer/lineaction.hxx @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_LINEACTION_HXX +#define _CPPCANVAS_LINEACTION_HXX + +#include <action.hxx> +#include <cppcanvas/canvas.hxx> + +namespace basegfx { + class B2DPoint; +} + + +/* Definition of internal::LineActionFactory class */ + +namespace cppcanvas +{ + namespace internal + { + struct OutDevState; + + /** Creates encapsulated converters between GDIMetaFile and + XCanvas. The Canvas argument is deliberately placed at the + constructor, to force reconstruction of this object for a + new canvas. This considerably eases internal state + handling, since a lot of the internal state (e.g. fonts, + text layout) is Canvas-dependent. + */ + class LineActionFactory + { + public: + /// Plain hair line from point 1 to point 2 + static ActionSharedPtr createLineAction( const ::basegfx::B2DPoint&, + const ::basegfx::B2DPoint&, + const CanvasSharedPtr&, + const OutDevState& ); + + private: + // static factory, disable big four + LineActionFactory(); + ~LineActionFactory(); + LineActionFactory(const LineActionFactory&); + LineActionFactory& operator=( const LineActionFactory& ); + }; + } +} + +#endif /* _CPPCANVAS_LINEACTION_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/mtfrenderer/mtftools.cxx b/cppcanvas/source/mtfrenderer/mtftools.cxx new file mode 100644 index 000000000000..4810268b7ca7 --- /dev/null +++ b/cppcanvas/source/mtfrenderer/mtftools.cxx @@ -0,0 +1,696 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cppcanvas.hxx" + +#include <canvas/debug.hxx> +#include <tools/diagnose_ex.h> +#include <canvas/verbosetrace.hxx> +#include <com/sun/star/rendering/RenderState.hpp> +#include <com/sun/star/rendering/XCanvas.hpp> +#include <basegfx/numeric/ftools.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/vector/b2dvector.hxx> +#include <canvas/canvastools.hxx> +#include <vcl/gdimtf.hxx> +#include <vcl/metaact.hxx> +#include <vcl/virdev.hxx> +#include <vcl/metric.hxx> +#include <tools/poly.hxx> +#include "mtftools.hxx" +#include "outdevstate.hxx" +#include "polypolyaction.hxx" +#include <basegfx/matrix/b2dhommatrixtools.hxx> + + + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace tools + { + void initRenderState( rendering::RenderState& renderState, + const ::cppcanvas::internal::OutDevState& outdevState ) + { + ::canvas::tools::initRenderState( renderState ); + ::canvas::tools::setRenderStateTransform( renderState, + outdevState.transform ); + renderState.Clip = outdevState.xClipPoly; + } + + ::Size getBaselineOffset( const ::cppcanvas::internal::OutDevState& outdevState, + const VirtualDevice& rVDev ) + { + const ::FontMetric& aMetric = rVDev.GetFontMetric(); + + // calc offset for text output, the XCanvas always renders + // baseline offset. + switch( outdevState.textReferencePoint ) + { + case ALIGN_TOP: + return ::Size( 0, + aMetric.GetIntLeading() + aMetric.GetAscent() ); + + default: + ENSURE_OR_THROW( false, + "tools::getBaselineOffset(): Unexpected TextAlign value" ); + // FALLTHROUGH intended (to calm compiler warning - case won't happen) + case ALIGN_BASELINE: + return ::Size( 0, 0 ); + + case ALIGN_BOTTOM: + return ::Size( 0, + -aMetric.GetDescent() ); + + } + } + + ::basegfx::B2DHomMatrix& calcLogic2PixelLinearTransform( ::basegfx::B2DHomMatrix& o_rMatrix, + const VirtualDevice& rVDev ) + { + // select size value in the middle of the available range, + // to have headroom both when map mode scales up, and when + // it scales down. + const ::Size aSizeLogic( 0x00010000L, + 0x00010000L ); + + const ::Size aSizePixel( rVDev.LogicToPixel( aSizeLogic ) ); + + o_rMatrix = basegfx::tools::createScaleB2DHomMatrix( + aSizePixel.Width() / (double)aSizeLogic.Width(), + aSizePixel.Height() / (double)aSizeLogic.Height() ); + + return o_rMatrix; + } + + ::basegfx::B2DHomMatrix& calcLogic2PixelAffineTransform( ::basegfx::B2DHomMatrix& o_rMatrix, + const VirtualDevice& rVDev ) + { + // retrieves scale + calcLogic2PixelLinearTransform(o_rMatrix, rVDev); + + // translate according to curr map mode/pref map mode offset + const ::Point aEmptyPoint; + const ::Point& rTranslatedPoint( + rVDev.LogicToPixel( aEmptyPoint )); + + o_rMatrix.translate(rTranslatedPoint.X(), + rTranslatedPoint.Y()); + + return o_rMatrix; + } + + bool modifyClip( rendering::RenderState& o_rRenderState, + const struct ::cppcanvas::internal::OutDevState& rOutdevState, + const CanvasSharedPtr& rCanvas, + const ::basegfx::B2DPoint& rOffset, + const ::basegfx::B2DVector* pScaling, + const double* pRotation ) + { + const ::Point aEmptyPoint; + + const bool bOffsetting( !rOffset.equalZero() ); + const bool bScaling( pScaling && + pScaling->getX() != 1.0 && + pScaling->getY() != 1.0 ); + const bool bRotation( pRotation && + *pRotation != 0.0 ); + + if( !bOffsetting && !bScaling && !bRotation ) + return false; // nothing to do + + if( rOutdevState.clip.count() ) + { + // general polygon case + + ::basegfx::B2DPolyPolygon aLocalClip( rOutdevState.clip ); + ::basegfx::B2DHomMatrix aTransform; + + if( bOffsetting ) + aTransform.translate( -rOffset.getX(), + -rOffset.getY() ); + if( bScaling ) + aTransform.scale( 1.0/pScaling->getX(), 1.0/pScaling->getY() ); + + if( bRotation ) + aTransform.rotate( - *pRotation ); + + aLocalClip.transform( aTransform ); + + o_rRenderState.Clip = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + rCanvas->getUNOCanvas()->getDevice(), + aLocalClip ); + + return true; + } + else if( !rOutdevState.clipRect.IsEmpty() ) + { + // simple rect case + + const ::Rectangle aLocalClipRect( rOutdevState.clipRect ); + + if( bRotation ) + { + // rotation involved - convert to polygon first, + // then transform that + ::basegfx::B2DPolygon aLocalClip( + ::basegfx::tools::createPolygonFromRect( + ::basegfx::B2DRectangle( + (double)(aLocalClipRect.Left()), + (double)(aLocalClipRect.Top()), + (double)(aLocalClipRect.Right()), + (double)(aLocalClipRect.Bottom()) ) ) ); + ::basegfx::B2DHomMatrix aTransform; + + if( bOffsetting ) + aTransform.translate( -rOffset.getX(), + -rOffset.getY() ); + if( bScaling ) + aTransform.scale( 1.0/pScaling->getX(), 1.0/pScaling->getY() ); + + aTransform.rotate( - *pRotation ); + + aLocalClip.transform( aTransform ); + + o_rRenderState.Clip = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + rCanvas->getUNOCanvas()->getDevice(), + ::basegfx::B2DPolyPolygon( aLocalClip ) ); + } + else if( bScaling ) + { + // scale and offset - do it on the fly, have to + // convert to float anyway. + o_rRenderState.Clip = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + rCanvas->getUNOCanvas()->getDevice(), + ::basegfx::B2DPolyPolygon( + ::basegfx::tools::createPolygonFromRect( + ::basegfx::B2DRectangle( + (double)(aLocalClipRect.Left() - rOffset.getX())/pScaling->getX(), + (double)(aLocalClipRect.Top() - rOffset.getY())/pScaling->getY(), + (double)(aLocalClipRect.Right() - rOffset.getX())/pScaling->getX(), + (double)(aLocalClipRect.Bottom() - rOffset.getY())/pScaling->getY() ) ) ) ); + } + else + { + // offset only - do it on the fly, have to convert + // to float anyway. + o_rRenderState.Clip = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + rCanvas->getUNOCanvas()->getDevice(), + ::basegfx::B2DPolyPolygon( + ::basegfx::tools::createPolygonFromRect( + ::basegfx::B2DRectangle( aLocalClipRect.Left() - rOffset.getX(), + aLocalClipRect.Top() - rOffset.getY(), + aLocalClipRect.Right() - rOffset.getX(), + aLocalClipRect.Bottom() - rOffset.getY() ) ) ) ); + } + + return true; + } + + // empty clip, nothing to do + return false; + } + + bool modifyClip( rendering::RenderState& o_rRenderState, + const struct ::cppcanvas::internal::OutDevState& rOutdevState, + const CanvasSharedPtr& rCanvas, + const ::Point& rOffset, + const ::basegfx::B2DVector* pScaling, + const double* pRotation ) + { + return modifyClip( o_rRenderState, + rOutdevState, + rCanvas, + ::basegfx::B2DPoint( rOffset.X(), + rOffset.Y() ), + pScaling, + pRotation ); + } + + bool modifyClip( rendering::RenderState& o_rRenderState, + const struct ::cppcanvas::internal::OutDevState& rOutdevState, + const CanvasSharedPtr& rCanvas, + const ::basegfx::B2DHomMatrix& rTransform ) + { + if( !rTransform.isIdentity() || + !rTransform.isInvertible() ) + return false; // nothing to do + + ::basegfx::B2DPolyPolygon aLocalClip; + + if( rOutdevState.clip.count() ) + { + aLocalClip = rOutdevState.clip; + } + else if( !rOutdevState.clipRect.IsEmpty() ) + { + const ::Rectangle aLocalClipRect( rOutdevState.clipRect ); + + aLocalClip = ::basegfx::B2DPolyPolygon( + ::basegfx::tools::createPolygonFromRect( + ::basegfx::B2DRectangle( + aLocalClipRect.Left(), + aLocalClipRect.Top(), + aLocalClipRect.Right(), + aLocalClipRect.Bottom() ) ) ); + } + else + { + // empty clip, nothing to do + return false; + } + + // invert transformation and modify + ::basegfx::B2DHomMatrix aLocalTransform( rTransform ); + aLocalTransform.invert(); + + aLocalClip.transform( aLocalTransform ); + + o_rRenderState.Clip = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + rCanvas->getUNOCanvas()->getDevice(), + aLocalClip ); + + return true; + } + + // create overline/underline/strikeout line info struct + TextLineInfo createTextLineInfo( const ::VirtualDevice& rVDev, + const ::cppcanvas::internal::OutDevState& rState ) + { + const sal_Bool bOldMode( rVDev.IsMapModeEnabled() ); + + // #i68512# Force metric regeneration with mapmode enabled + // (prolly OutDev bug) + rVDev.GetFontMetric(); + + // will restore map mode below + const_cast< ::VirtualDevice& >(rVDev).EnableMapMode( sal_False ); + + const ::FontMetric aMetric = rVDev.GetFontMetric(); + + TextLineInfo aTextInfo( + (aMetric.GetDescent() + 2) / 4.0, + ((aMetric.GetIntLeading() + 1.5) / 3.0), + (aMetric.GetIntLeading() / 2.0) - aMetric.GetAscent(), + aMetric.GetDescent() / 2.0, + (aMetric.GetIntLeading() - aMetric.GetAscent()) / 3.0, + rState.textOverlineStyle, + rState.textUnderlineStyle, + rState.textStrikeoutStyle ); + + const_cast< ::VirtualDevice& >(rVDev).EnableMapMode( bOldMode ); + + return aTextInfo; + } + + namespace + { + void appendRect( ::basegfx::B2DPolyPolygon& o_rPoly, + const ::basegfx::B2DPoint& rStartPos, + const double nX1, + const double nY1, + const double nX2, + const double nY2 ) + { + const double x( rStartPos.getX() ); + const double y( rStartPos.getY() ); + + o_rPoly.append( + ::basegfx::tools::createPolygonFromRect( + ::basegfx::B2DRectangle( x + nX1, y + nY1, x + nX2, y + nY2 ) ) ); + } + + void appendRect( ::basegfx::B2DPolyPolygon& o_rPoly, + const double nX1, + const double nY1, + const double nX2, + const double nY2 ) + { + o_rPoly.append( + ::basegfx::tools::createPolygonFromRect( + ::basegfx::B2DRectangle( nX1, nY1, nX2, nY2 ) ) ); + } + + void appendDashes( ::basegfx::B2DPolyPolygon& o_rPoly, + const double nX, + const double nY, + const double nLineWidth, + const double nLineHeight, + const double nDashWidth, + const double nDashSkip ) + { + const sal_Int32 nNumLoops( + static_cast< sal_Int32 >( + ::std::max( 1.0, + nLineWidth / nDashSkip ) + .5) ); + + double x = nX; + for( sal_Int32 i=0; i<nNumLoops; ++i ) + { + appendRect( o_rPoly, + x, nY, + x + nDashWidth, nY + nLineHeight ); + + x += nDashSkip; + } + } + } + + // create line actions for text such as underline and + // strikeout + ::basegfx::B2DPolyPolygon createTextLinesPolyPolygon( const ::basegfx::B2DPoint rStartPos, + const double& rLineWidth, + const TextLineInfo& rTextLineInfo ) + { + // fill the polypolygon with all text lines + ::basegfx::B2DPolyPolygon aTextLinesPolyPoly; + + switch( rTextLineInfo.mnOverlineStyle ) + { + case UNDERLINE_NONE: // nothing to do + // FALLTHROUGH intended + case UNDERLINE_DONTKNOW: + break; + + case UNDERLINE_SMALLWAVE: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_WAVE: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_SINGLE: + appendRect( + aTextLinesPolyPoly, + rStartPos, + 0, + rTextLineInfo.mnOverlineOffset, + rLineWidth, + rTextLineInfo.mnOverlineOffset + rTextLineInfo.mnOverlineHeight ); + break; + + case UNDERLINE_BOLDDOTTED: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_BOLDDASH: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_BOLDLONGDASH: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_BOLDDASHDOT: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_BOLDDASHDOTDOT:// TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_BOLDWAVE: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_BOLD: + appendRect( + aTextLinesPolyPoly, + rStartPos, + 0, + rTextLineInfo.mnOverlineOffset - rTextLineInfo.mnOverlineHeight, + rLineWidth, + rTextLineInfo.mnOverlineOffset + rTextLineInfo.mnOverlineHeight ); + break; + + case UNDERLINE_DOUBLEWAVE: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_DOUBLE: + appendRect( + aTextLinesPolyPoly, + rStartPos, + 0, + rTextLineInfo.mnOverlineOffset - rTextLineInfo.mnOverlineHeight * 2.0 , + rLineWidth, + rTextLineInfo.mnOverlineOffset - rTextLineInfo.mnOverlineHeight ); + + appendRect( + aTextLinesPolyPoly, + rStartPos, + 0, + rTextLineInfo.mnOverlineOffset + rTextLineInfo.mnOverlineHeight, + rLineWidth, + rTextLineInfo.mnOverlineOffset + rTextLineInfo.mnOverlineHeight * 2.0 ); + break; + + case UNDERLINE_DASHDOTDOT: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_DOTTED: + appendDashes( + aTextLinesPolyPoly, + rStartPos.getX(), + rStartPos.getY() + rTextLineInfo.mnOverlineOffset, + rLineWidth, + rTextLineInfo.mnOverlineHeight, + rTextLineInfo.mnOverlineHeight, + 2*rTextLineInfo.mnOverlineHeight ); + break; + + case UNDERLINE_DASHDOT: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_DASH: + appendDashes( + aTextLinesPolyPoly, + rStartPos.getX(), + rStartPos.getY() + rTextLineInfo.mnOverlineOffset, + rLineWidth, + rTextLineInfo.mnOverlineHeight, + 3*rTextLineInfo.mnOverlineHeight, + 6*rTextLineInfo.mnOverlineHeight ); + break; + + case UNDERLINE_LONGDASH: + appendDashes( + aTextLinesPolyPoly, + rStartPos.getX(), + rStartPos.getY() + rTextLineInfo.mnOverlineOffset, + rLineWidth, + rTextLineInfo.mnOverlineHeight, + 6*rTextLineInfo.mnOverlineHeight, + 12*rTextLineInfo.mnOverlineHeight ); + break; + + default: + ENSURE_OR_THROW( false, + "::cppcanvas::internal::createTextLinesPolyPolygon(): Unexpected overline case" ); + } + + switch( rTextLineInfo.mnUnderlineStyle ) + { + case UNDERLINE_NONE: // nothing to do + // FALLTHROUGH intended + case UNDERLINE_DONTKNOW: + break; + + case UNDERLINE_SMALLWAVE: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_WAVE: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_SINGLE: + appendRect( + aTextLinesPolyPoly, + rStartPos, + 0, + rTextLineInfo.mnUnderlineOffset, + rLineWidth, + rTextLineInfo.mnUnderlineOffset + rTextLineInfo.mnLineHeight ); + break; + + case UNDERLINE_BOLDDOTTED: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_BOLDDASH: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_BOLDLONGDASH: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_BOLDDASHDOT: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_BOLDDASHDOTDOT:// TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_BOLDWAVE: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_BOLD: + appendRect( + aTextLinesPolyPoly, + rStartPos, + 0, + rTextLineInfo.mnUnderlineOffset, + rLineWidth, + rTextLineInfo.mnUnderlineOffset + 2*rTextLineInfo.mnLineHeight ); + break; + + case UNDERLINE_DOUBLEWAVE: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_DOUBLE: + appendRect( + aTextLinesPolyPoly, + rStartPos, + 0, + rTextLineInfo.mnUnderlineOffset - rTextLineInfo.mnLineHeight, + rLineWidth, + rTextLineInfo.mnUnderlineOffset ); + + appendRect( + aTextLinesPolyPoly, + rStartPos, + 0, + rTextLineInfo.mnUnderlineOffset + 2*rTextLineInfo.mnLineHeight, + rLineWidth, + rTextLineInfo.mnUnderlineOffset + 3*rTextLineInfo.mnLineHeight ); + break; + + case UNDERLINE_DASHDOTDOT: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_DOTTED: + appendDashes( + aTextLinesPolyPoly, + rStartPos.getX(), + rStartPos.getY() + rTextLineInfo.mnUnderlineOffset, + rLineWidth, + rTextLineInfo.mnLineHeight, + rTextLineInfo.mnLineHeight, + 2*rTextLineInfo.mnLineHeight ); + break; + + case UNDERLINE_DASHDOT: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_DASH: + appendDashes( + aTextLinesPolyPoly, + rStartPos.getX(), + rStartPos.getY() + rTextLineInfo.mnUnderlineOffset, + rLineWidth, + rTextLineInfo.mnLineHeight, + 3*rTextLineInfo.mnLineHeight, + 6*rTextLineInfo.mnLineHeight ); + break; + + case UNDERLINE_LONGDASH: + appendDashes( + aTextLinesPolyPoly, + rStartPos.getX(), + rStartPos.getY() + rTextLineInfo.mnUnderlineOffset, + rLineWidth, + rTextLineInfo.mnLineHeight, + 6*rTextLineInfo.mnLineHeight, + 12*rTextLineInfo.mnLineHeight ); + break; + + default: + ENSURE_OR_THROW( false, + "::cppcanvas::internal::createTextLinesPolyPolygon(): Unexpected underline case" ); + } + + switch( rTextLineInfo.mnStrikeoutStyle ) + { + case STRIKEOUT_NONE: // nothing to do + // FALLTHROUGH intended + case STRIKEOUT_DONTKNOW: + break; + + case STRIKEOUT_SLASH: // TODO(Q1): we should handle this in the text layer + // FALLTHROUGH intended + case STRIKEOUT_X: + break; + + case STRIKEOUT_SINGLE: + appendRect( + aTextLinesPolyPoly, + rStartPos, + 0, + rTextLineInfo.mnStrikeoutOffset, + rLineWidth, + rTextLineInfo.mnStrikeoutOffset + rTextLineInfo.mnLineHeight ); + break; + + case STRIKEOUT_BOLD: + appendRect( + aTextLinesPolyPoly, + rStartPos, + 0, + rTextLineInfo.mnStrikeoutOffset, + rLineWidth, + rTextLineInfo.mnStrikeoutOffset + 2*rTextLineInfo.mnLineHeight ); + break; + + case STRIKEOUT_DOUBLE: + appendRect( + aTextLinesPolyPoly, + rStartPos, + 0, + rTextLineInfo.mnStrikeoutOffset - rTextLineInfo.mnLineHeight, + rLineWidth, + rTextLineInfo.mnStrikeoutOffset ); + + appendRect( + aTextLinesPolyPoly, + rStartPos, + 0, + rTextLineInfo.mnStrikeoutOffset + 2*rTextLineInfo.mnLineHeight, + rLineWidth, + rTextLineInfo.mnStrikeoutOffset + 3*rTextLineInfo.mnLineHeight ); + break; + + default: + ENSURE_OR_THROW( false, + "::cppcanvas::internal::createTextLinesPolyPolygon(): Unexpected strikeout case" ); + } + + return aTextLinesPolyPoly; + } + + ::basegfx::B2DRange calcDevicePixelBounds( const ::basegfx::B2DRange& rBounds, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + ::basegfx::B2DHomMatrix aTransform; + ::canvas::tools::mergeViewAndRenderTransform( aTransform, + viewState, + renderState ); + + ::basegfx::B2DRange aTransformedBounds; + return ::canvas::tools::calcTransformedRectBounds( aTransformedBounds, + rBounds, + aTransform ); + } + + // create line actions for text such as underline and + // strikeout + ::basegfx::B2DPolyPolygon createTextLinesPolyPolygon( const double& rStartOffset, + const double& rLineWidth, + const TextLineInfo& rTextLineInfo ) + { + return createTextLinesPolyPolygon( + ::basegfx::B2DPoint( rStartOffset, + 0.0 ), + rLineWidth, + rTextLineInfo ); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/mtfrenderer/mtftools.hxx b/cppcanvas/source/mtfrenderer/mtftools.hxx new file mode 100644 index 000000000000..8d466f1d9e7e --- /dev/null +++ b/cppcanvas/source/mtfrenderer/mtftools.hxx @@ -0,0 +1,273 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_RENDERER_MTFTOOLS_HXX +#define _CPPCANVAS_RENDERER_MTFTOOLS_HXX + +#include <action.hxx> +#include <cppcanvas/canvas.hxx> + + +class VirtualDevice; +class Point; +class Size; + +namespace basegfx +{ + class B2DVector; + class B2DPoint; +} +namespace com { namespace sun { namespace star { namespace rendering +{ + struct RenderState; +} } } } + + +namespace cppcanvas +{ + namespace internal + { + struct OutDevState; + } + + namespace tools + { + /** Init render state from OutDevState + + This method initializes the given render state object, + sets up the transformation and the clip from the + OutDevState. + */ + void initRenderState( ::com::sun::star::rendering::RenderState& renderState, + const ::cppcanvas::internal::OutDevState& outdevState ); + + /** Calc output offset relative to baseline + + The XCanvas API always renders text relative to its + baseline. This method calculates an offset in logical + coordinates, depending on the OutDevState's + textReferencePoint and the font currently set, to offset + the text from the baseline. + + @param outdevState + State to take textReferencePoint from + + @param rVDev + VDev to obtain font metrics from. + */ + ::Size getBaselineOffset( const ::cppcanvas::internal::OutDevState& outdevState, + const VirtualDevice& rVDev ); + + /** Construct a matrix that converts from logical to pixel + coordinate system. + + This method calculates a matrix that approximates the + VirtualDevice's LogicToPixel conversion (disregarding any + offset components, thus the 'linear' in the method name - + the returned matrix is guaranteed to be linear). + + @param o_rMatrix + This matrix will receive the calculated transform, and is + also returned from this method. + + @return the calculated transformation matrix. + */ + ::basegfx::B2DHomMatrix& calcLogic2PixelLinearTransform( ::basegfx::B2DHomMatrix& o_rMatrix, + const VirtualDevice& rVDev ); + + /** Construct a matrix that converts from logical to pixel + coordinate system. + + This method calculates a matrix that approximates the + VirtualDevice's LogicToPixel conversion. + + @param o_rMatrix + This matrix will receive the calculated transform, and is + also returned from this method. + + @return the calculated transformation matrix. + */ + ::basegfx::B2DHomMatrix& calcLogic2PixelAffineTransform( ::basegfx::B2DHomMatrix& o_rMatrix, + const VirtualDevice& rVDev ); + + /** This method modifies the clip, to cancel the given + transformation. + + As the clip is relative to the render state + transformation, offsetting or scaling the render state + must modify the clip, to keep it at the same position + relative to the primitive at hand + + @param o_rRenderState + Render state to change the clip in + + @param rOutdevState + Input state. Is used to retrieve the original clip from + + @param rOffset + The clip is offsetted by the negative of this value. + + @param pScaling + The clip is inversely scaled by this value (if given) + + @param pRotation + The clip is inversely rotated by this value (if given) + + @return true, if the clip has changed, false if not + */ + bool modifyClip( ::com::sun::star::rendering::RenderState& o_rRenderState, + const struct ::cppcanvas::internal::OutDevState& rOutdevState, + const CanvasSharedPtr& rCanvas, + const ::Point& rOffset, + const ::basegfx::B2DVector* pScaling, + const double* pRotation ); + + /** This method modifies the clip, to cancel the given + transformation. + + As the clip is relative to the render state + transformation, offsetting or scaling the render state + must modify the clip, to keep it at the same position + relative to the primitive at hand + + @param o_rRenderState + Render state to change the clip in + + @param rOutdevState + Input state. Is used to retrieve the original clip from + + @param rOffset + The clip is offsetted by the negative of this value. + + @param pScaling + The clip is inversely scaled by this value (if given) + + @param pRotation + The clip is inversely rotated by this value (if given) + + @return true, if the clip has changed, false if not + */ + bool modifyClip( ::com::sun::star::rendering::RenderState& o_rRenderState, + const struct ::cppcanvas::internal::OutDevState& rOutdevState, + const CanvasSharedPtr& rCanvas, + const ::basegfx::B2DPoint& rOffset, + const ::basegfx::B2DVector* pScaling, + const double* pRotation ); + + /** This method modifies the clip, to cancel the given + transformation. + + As the clip is relative to the render state + transformation, transforming the render state further must + modify the clip, to keep it at the same position relative + to the primitive at hand + + @param o_rRenderState + Render state to change the clip in + + @param rOutdevState + Input state. Is used to retrieve the original clip from + + @param rTransform + The clip is transformed by the inverse of this value. + + @return true, if the clip has changed, false if not + */ + bool modifyClip( ::com::sun::star::rendering::RenderState& o_rRenderState, + const struct ::cppcanvas::internal::OutDevState& rOutdevState, + const CanvasSharedPtr& rCanvas, + const ::basegfx::B2DHomMatrix& rTransform ); + + struct TextLineInfo + { + TextLineInfo( const double& rLineHeight, + const double& rOverlineHeight, + const double& rOverlineOffset, + const double& rUnderlineOffset, + const double& rStrikeoutOffset, + sal_Int8 nOverlineStyle, + sal_Int8 nUnderlineStyle, + sal_Int8 nStrikeoutStyle ) : + mnLineHeight( rLineHeight ), + mnOverlineHeight( rOverlineHeight ), + mnOverlineOffset( rOverlineOffset ), + mnUnderlineOffset( rUnderlineOffset ), + mnStrikeoutOffset( rStrikeoutOffset ), + mnOverlineStyle( nOverlineStyle ), + mnUnderlineStyle( nUnderlineStyle ), + mnStrikeoutStyle( nStrikeoutStyle ) + { + } + + double mnLineHeight; + double mnOverlineHeight; + double mnOverlineOffset; + double mnUnderlineOffset; + double mnStrikeoutOffset; + sal_Int8 mnOverlineStyle; + sal_Int8 mnUnderlineStyle; + sal_Int8 mnStrikeoutStyle; + }; + + /** Transform given bounds to device coordinate system. + */ + ::basegfx::B2DRange calcDevicePixelBounds( const ::basegfx::B2DRange& rBounds, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + + /** Generate text underline/strikeout info struct from OutDev + state. + */ + TextLineInfo createTextLineInfo( const ::VirtualDevice& rVDev, + const ::cppcanvas::internal::OutDevState& rState ); + + /** Create a poly-polygon representing the given combination + of overline, strikeout and underline. + + @param rStartOffset + Offset in X direction, where the underline starts + + @param rLineWidth + Width of the line of text to overline/strikeout/underline + + @param rTextLineInfo + Common info needed for overline/strikeout/underline generation + */ + ::basegfx::B2DPolyPolygon createTextLinesPolyPolygon( const double& rStartOffset, + const double& rLineWidth, + const TextLineInfo& rTextLineInfo ); + + ::basegfx::B2DPolyPolygon createTextLinesPolyPolygon( const ::basegfx::B2DPoint rStartPos, + const double& rLineWidth, + const TextLineInfo& rTextLineInfo ); + } +} + +#endif /* _CPPCANVAS_RENDERER_MTFTOOLS_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/mtfrenderer/outdevstate.hxx b/cppcanvas/source/mtfrenderer/outdevstate.hxx new file mode 100644 index 000000000000..b0e79d2684dc --- /dev/null +++ b/cppcanvas/source/mtfrenderer/outdevstate.hxx @@ -0,0 +1,136 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_OUTDEVSTATE_HXX +#define _CPPCANVAS_OUTDEVSTATE_HXX + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/Sequence.hxx> + +#include <com/sun/star/rendering/StringContext.hpp> +#include <com/sun/star/rendering/RenderState.hpp> +#include <com/sun/star/rendering/XPolyPolygon2D.hpp> +#include <com/sun/star/rendering/XCanvasFont.hpp> +#include <com/sun/star/rendering/TextDirection.hpp> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <vcl/fntstyle.hxx> +#include <vcl/vclenum.hxx> +#include <vcl/outdev.hxx> +#include <vcl/outdev.hxx> + + +namespace cppcanvas +{ + namespace internal + { + struct OutDevState + { + OutDevState() : + clip(), + clipRect(), + xClipPoly(), + + lineColor(), + fillColor(), + textColor(), + textFillColor(), + textLineColor(), + + xFont(), + transform(), + mapModeTransform(), + fontRotation(0.0), + + textEmphasisMarkStyle(EMPHASISMARK_NONE), + pushFlags(PUSH_ALL), + textDirection(::com::sun::star::rendering::TextDirection::WEAK_LEFT_TO_RIGHT), + textAlignment(0), // TODO(Q2): Synchronize with implrenderer + // and possibly new rendering::TextAlignment + textReliefStyle(RELIEF_NONE), + textOverlineStyle(UNDERLINE_NONE), + textUnderlineStyle(UNDERLINE_NONE), + textStrikeoutStyle(STRIKEOUT_NONE), + textReferencePoint(ALIGN_BASELINE), + + isTextOutlineModeSet( false ), + isTextEffectShadowSet( false ), + isTextWordUnderlineSet( false ), + + isLineColorSet( false ), + isFillColorSet( false ), + isTextFillColorSet( false ), + isTextLineColorSet( false ) + { + } + + ::basegfx::B2DPolyPolygon clip; + ::Rectangle clipRect; + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XPolyPolygon2D > xClipPoly; + + ::com::sun::star::uno::Sequence< double > lineColor; + ::com::sun::star::uno::Sequence< double > fillColor; + ::com::sun::star::uno::Sequence< double > textColor; + ::com::sun::star::uno::Sequence< double > textFillColor; + ::com::sun::star::uno::Sequence< double > textLineColor; + + /** Current font. + + @attention Beware, this member can be NULL, and + nevertheless text output is generated. + */ + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCanvasFont > xFont; + ::basegfx::B2DHomMatrix transform; + ::basegfx::B2DHomMatrix mapModeTransform; + double fontRotation; + + sal_uInt16 textEmphasisMarkStyle; + sal_uInt16 pushFlags; + sal_Int8 textDirection; + sal_Int8 textAlignment; + sal_Int8 textReliefStyle; + sal_Int8 textOverlineStyle; + sal_Int8 textUnderlineStyle; + sal_Int8 textStrikeoutStyle; + TextAlign textReferencePoint; + + bool isTextOutlineModeSet; + bool isTextEffectShadowSet; + bool isTextWordUnderlineSet; + + bool isLineColorSet; + bool isFillColorSet; + bool isTextFillColorSet; + bool isTextLineColorSet; + }; + } +} + +#endif /* _CPPCANVAS_OUTDEVSTATE_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/mtfrenderer/pointaction.cxx b/cppcanvas/source/mtfrenderer/pointaction.cxx new file mode 100644 index 000000000000..8a2edbdf35ba --- /dev/null +++ b/cppcanvas/source/mtfrenderer/pointaction.cxx @@ -0,0 +1,190 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cppcanvas.hxx" + +#include <rtl/logfile.hxx> +#include <com/sun/star/rendering/XCanvas.hpp> + +#include <tools/gen.hxx> +#include <vcl/canvastools.hxx> + +#include <basegfx/range/b2drange.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <canvas/canvastools.hxx> + +#include <boost/utility.hpp> + +#include "pointaction.hxx" +#include "outdevstate.hxx" +#include "cppcanvas/canvas.hxx" +#include "mtftools.hxx" + + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace internal + { + namespace + { + class PointAction : public Action, private ::boost::noncopyable + { + public: + PointAction( const ::basegfx::B2DPoint&, + const CanvasSharedPtr&, + const OutDevState& ); + PointAction( const ::basegfx::B2DPoint&, + const CanvasSharedPtr&, + const OutDevState&, + const ::Color& ); + + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual sal_Int32 getActionCount() const; + + private: + // default: disabled copy/assignment + PointAction(const PointAction&); + PointAction& operator = ( const PointAction& ); + + ::basegfx::B2DPoint maPoint; + CanvasSharedPtr mpCanvas; + ::com::sun::star::rendering::RenderState maState; + }; + + PointAction::PointAction( const ::basegfx::B2DPoint& rPoint, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) : + maPoint( rPoint ), + mpCanvas( rCanvas ), + maState() + { + tools::initRenderState(maState,rState); + maState.DeviceColor = rState.lineColor; + } + + PointAction::PointAction( const ::basegfx::B2DPoint& rPoint, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const ::Color& rAltColor ) : + maPoint( rPoint ), + mpCanvas( rCanvas ), + maState() + { + tools::initRenderState(maState,rState); + maState.DeviceColor = ::vcl::unotools::colorToDoubleSequence( + rAltColor, + rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() ); + } + + bool PointAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::PointAction::render()" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::PointAction: 0x%X", this ); + + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + mpCanvas->getUNOCanvas()->drawPoint( ::basegfx::unotools::point2DFromB2DPoint(maPoint), + mpCanvas->getViewState(), + aLocalState ); + + return true; + } + + bool PointAction::render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + // point only contains a single action, fail if subset + // requests different range + if( rSubset.mnSubsetBegin != 0 || + rSubset.mnSubsetEnd != 1 ) + return false; + + return render( rTransformation ); + } + + ::basegfx::B2DRange PointAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + return tools::calcDevicePixelBounds( ::basegfx::B2DRange( maPoint.getX()-1, + maPoint.getY()-1, + maPoint.getX()+1, + maPoint.getY()+1 ), + mpCanvas->getViewState(), + aLocalState ); + } + + ::basegfx::B2DRange PointAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + // point only contains a single action, empty bounds + // if subset requests different range + if( rSubset.mnSubsetBegin != 0 || + rSubset.mnSubsetEnd != 1 ) + return ::basegfx::B2DRange(); + + return getBounds( rTransformation ); + } + + sal_Int32 PointAction::getActionCount() const + { + return 1; + } + } + + ActionSharedPtr PointActionFactory::createPointAction( const ::basegfx::B2DPoint& rPoint, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) + { + return ActionSharedPtr( new PointAction( rPoint, rCanvas, rState ) ); + } + + ActionSharedPtr PointActionFactory::createPointAction( const ::basegfx::B2DPoint& rPoint, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const ::Color& rColor ) + { + return ActionSharedPtr( new PointAction( rPoint, rCanvas, rState, rColor ) ); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/mtfrenderer/pointaction.hxx b/cppcanvas/source/mtfrenderer/pointaction.hxx new file mode 100644 index 000000000000..b17b1eea5a43 --- /dev/null +++ b/cppcanvas/source/mtfrenderer/pointaction.hxx @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_POINTACTION_HXX +#define _CPPCANVAS_POINTACTION_HXX + +#include <action.hxx> +#include <cppcanvas/canvas.hxx> + +class Color; +namespace basegfx { + class B2DPoint; +} + +/* Definition of internal::PointActionFactory class */ + +namespace cppcanvas +{ + namespace internal + { + struct OutDevState; + + /** Creates encapsulated converters between GDIMetaFile and + XCanvas. The Canvas argument is deliberately placed at the + constructor, to force reconstruction of this object for a + new canvas. This considerably eases internal state + handling, since a lot of the internal state (e.g. fonts, + text layout) is Canvas-dependent. + */ + class PointActionFactory + { + public: + /// Point in current color + static ActionSharedPtr createPointAction( const ::basegfx::B2DPoint&, + const CanvasSharedPtr&, + const OutDevState& ); + + /// Point in given color + static ActionSharedPtr createPointAction( const ::basegfx::B2DPoint&, + const CanvasSharedPtr&, + const OutDevState&, + const ::Color& ); + + private: + // static factory, disable big four + PointActionFactory(); + ~PointActionFactory(); + PointActionFactory(const PointActionFactory&); + PointActionFactory& operator=( const PointActionFactory& ); + }; + } +} + +#endif /* _CPPCANVAS_POINTACTION_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/mtfrenderer/polypolyaction.cxx b/cppcanvas/source/mtfrenderer/polypolyaction.cxx new file mode 100644 index 000000000000..5b04576d46a8 --- /dev/null +++ b/cppcanvas/source/mtfrenderer/polypolyaction.cxx @@ -0,0 +1,527 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cppcanvas.hxx" + +#include <rtl/logfile.hxx> + +#include <com/sun/star/rendering/XCanvas.hpp> +#include <com/sun/star/rendering/TexturingMode.hpp> + +#include <tools/gen.hxx> +#include <vcl/canvastools.hxx> + +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <canvas/canvastools.hxx> + +#include <boost/utility.hpp> + +#include "cachedprimitivebase.hxx" +#include "polypolyaction.hxx" +#include "outdevstate.hxx" +#include "mtftools.hxx" + + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace internal + { + namespace + { + class PolyPolyAction : public CachedPrimitiveBase + { + public: + PolyPolyAction( const ::basegfx::B2DPolyPolygon&, + const CanvasSharedPtr&, + const OutDevState&, + bool bFill, + bool bStroke ); + PolyPolyAction( const ::basegfx::B2DPolyPolygon&, + const CanvasSharedPtr&, + const OutDevState&, + bool bFill, + bool bStroke, + int nTransparency ); + + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual sal_Int32 getActionCount() const; + + private: + using Action::render; + virtual bool render( uno::Reference< rendering::XCachedPrimitive >& rCachedPrimitive, + const ::basegfx::B2DHomMatrix& rTransformation ) const; + + const uno::Reference< rendering::XPolyPolygon2D > mxPolyPoly; + const ::basegfx::B2DRange maBounds; + const CanvasSharedPtr mpCanvas; + + // stroke color is now implicit: the maState.DeviceColor member + rendering::RenderState maState; + + uno::Sequence< double > maFillColor; + }; + + PolyPolyAction::PolyPolyAction( const ::basegfx::B2DPolyPolygon& rPolyPoly, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + bool bFill, + bool bStroke ) : + CachedPrimitiveBase( rCanvas, false ), + mxPolyPoly( ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( rCanvas->getUNOCanvas()->getDevice(), rPolyPoly) ), + maBounds( ::basegfx::tools::getRange(rPolyPoly) ), + mpCanvas( rCanvas ), + maState(), + maFillColor() + { + tools::initRenderState(maState,rState); + + if( bFill ) + maFillColor = rState.fillColor; + + if( bStroke ) + maState.DeviceColor = rState.lineColor; + } + + PolyPolyAction::PolyPolyAction( const ::basegfx::B2DPolyPolygon& rPolyPoly, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + bool bFill, + bool bStroke, + int nTransparency ) : + CachedPrimitiveBase( rCanvas, false ), + mxPolyPoly( ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( rCanvas->getUNOCanvas()->getDevice(), rPolyPoly) ), + maBounds( ::basegfx::tools::getRange(rPolyPoly) ), + mpCanvas( rCanvas ), + maState(), + maFillColor() + { + tools::initRenderState(maState,rState); + + if( bFill ) + { + maFillColor = rState.fillColor; + + if( maFillColor.getLength() < 4 ) + maFillColor.realloc( 4 ); + + // TODO(F1): Color management + // adapt fill color transparency + maFillColor[3] = 1.0 - nTransparency / 100.0; + } + + if( bStroke ) + { + maState.DeviceColor = rState.lineColor; + + if( maState.DeviceColor.getLength() < 4 ) + maState.DeviceColor.realloc( 4 ); + + // TODO(F1): Color management + // adapt fill color transparency + maState.DeviceColor[3] = 1.0 - nTransparency / 100.0; + } + } + + bool PolyPolyAction::render( uno::Reference< rendering::XCachedPrimitive >& rCachedPrimitive, + const ::basegfx::B2DHomMatrix& rTransformation ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::PolyPolyAction::render()" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::PolyPolyAction: 0x%X", this ); + + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + if( maFillColor.getLength() ) + { + // TODO(E3): Use DBO's finalizer here, + // fillPolyPolygon() might throw + const uno::Sequence< double > aTmpColor( aLocalState.DeviceColor ); + aLocalState.DeviceColor = maFillColor; + + rCachedPrimitive = mpCanvas->getUNOCanvas()->fillPolyPolygon( mxPolyPoly, + mpCanvas->getViewState(), + aLocalState ); + + aLocalState.DeviceColor = aTmpColor; + } + + if( aLocalState.DeviceColor.getLength() ) + { + rCachedPrimitive = mpCanvas->getUNOCanvas()->drawPolyPolygon( mxPolyPoly, + mpCanvas->getViewState(), + aLocalState ); + } + + return true; + } + + bool PolyPolyAction::render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + // TODO(F1): Split up poly-polygon into polygons, or even + // line segments, when subsets are requested. + + // polygon only contains a single action, fail if subset + // requests different range + if( rSubset.mnSubsetBegin != 0 || + rSubset.mnSubsetEnd != 1 ) + return false; + + return CachedPrimitiveBase::render( rTransformation ); + } + + ::basegfx::B2DRange PolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + return tools::calcDevicePixelBounds( + maBounds, + mpCanvas->getViewState(), + aLocalState ); + } + + ::basegfx::B2DRange PolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + // TODO(F1): Split up poly-polygon into polygons, or even + // line segments, when subsets are requested. + + // polygon only contains a single action, empty bounds + // if subset requests different range + if( rSubset.mnSubsetBegin != 0 || + rSubset.mnSubsetEnd != 1 ) + return ::basegfx::B2DRange(); + + return getBounds( rTransformation ); + } + + sal_Int32 PolyPolyAction::getActionCount() const + { + // TODO(F1): Split up poly-polygon into polygons, or even + // line segments, when subsets are requested. + return 1; + } + + + // ------------------------------------------------------------------------------- + + class TexturedPolyPolyAction : public CachedPrimitiveBase + { + public: + TexturedPolyPolyAction( const ::basegfx::B2DPolyPolygon& rPoly, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const rendering::Texture& rTexture ); + + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual sal_Int32 getActionCount() const; + + private: + using Action::render; + virtual bool render( uno::Reference< rendering::XCachedPrimitive >& rCachedPrimitive, + const ::basegfx::B2DHomMatrix& rTransformation ) const; + + const uno::Reference< rendering::XPolyPolygon2D > mxPolyPoly; + const ::basegfx::B2DRectangle maBounds; + const CanvasSharedPtr mpCanvas; + + // stroke color is now implicit: the maState.DeviceColor member + rendering::RenderState maState; + const rendering::Texture maTexture; + }; + + TexturedPolyPolyAction::TexturedPolyPolyAction( const ::basegfx::B2DPolyPolygon& rPolyPoly, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const rendering::Texture& rTexture ) : + CachedPrimitiveBase( rCanvas, true ), + mxPolyPoly( ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( rCanvas->getUNOCanvas()->getDevice(), rPolyPoly) ), + maBounds( ::basegfx::tools::getRange(rPolyPoly) ), + mpCanvas( rCanvas ), + maState(), + maTexture( rTexture ) + { + tools::initRenderState(maState,rState); + } + + bool TexturedPolyPolyAction::render( uno::Reference< rendering::XCachedPrimitive >& rCachedPrimitive, + const ::basegfx::B2DHomMatrix& rTransformation ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::PolyPolyAction::render()" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::PolyPolyAction: 0x%X", this ); + + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + uno::Sequence< rendering::Texture > aSeq(1); + aSeq[0] = maTexture; + + rCachedPrimitive = mpCanvas->getUNOCanvas()->fillTexturedPolyPolygon( mxPolyPoly, + mpCanvas->getViewState(), + aLocalState, + aSeq ); + return true; + } + + bool TexturedPolyPolyAction::render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + // TODO(F1): Split up poly-polygon into polygons, or even + // line segments, when subsets are requested. + + // polygon only contains a single action, fail if subset + // requests different range + if( rSubset.mnSubsetBegin != 0 || + rSubset.mnSubsetEnd != 1 ) + return false; + + return CachedPrimitiveBase::render( rTransformation ); + } + + ::basegfx::B2DRange TexturedPolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + return tools::calcDevicePixelBounds( + maBounds, + mpCanvas->getViewState(), + aLocalState ); + } + + ::basegfx::B2DRange TexturedPolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + // TODO(F1): Split up poly-polygon into polygons, or even + // line segments, when subsets are requested. + + // polygon only contains a single action, empty bounds + // if subset requests different range + if( rSubset.mnSubsetBegin != 0 || + rSubset.mnSubsetEnd != 1 ) + return ::basegfx::B2DRange(); + + return getBounds( rTransformation ); + } + + sal_Int32 TexturedPolyPolyAction::getActionCount() const + { + // TODO(F1): Split up poly-polygon into polygons, or even + // line segments, when subsets are requested. + return 1; + } + + // ------------------------------------------------------------------------------- + + class StrokedPolyPolyAction : public CachedPrimitiveBase + { + public: + StrokedPolyPolyAction( const ::basegfx::B2DPolyPolygon& rPoly, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const rendering::StrokeAttributes& rStrokeAttributes ); + + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual sal_Int32 getActionCount() const; + + private: + using Action::render; + virtual bool render( uno::Reference< rendering::XCachedPrimitive >& rCachedPrimitive, + const ::basegfx::B2DHomMatrix& rTransformation ) const; + + const uno::Reference< rendering::XPolyPolygon2D > mxPolyPoly; + const ::basegfx::B2DRectangle maBounds; + const CanvasSharedPtr mpCanvas; + rendering::RenderState maState; + const rendering::StrokeAttributes maStrokeAttributes; + }; + + StrokedPolyPolyAction::StrokedPolyPolyAction( const ::basegfx::B2DPolyPolygon& rPolyPoly, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const rendering::StrokeAttributes& rStrokeAttributes ) : + CachedPrimitiveBase( rCanvas, false ), + mxPolyPoly( ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( rCanvas->getUNOCanvas()->getDevice(), rPolyPoly) ), + maBounds( ::basegfx::tools::getRange(rPolyPoly) ), + mpCanvas( rCanvas ), + maState(), + maStrokeAttributes( rStrokeAttributes ) + { + tools::initRenderState(maState,rState); + maState.DeviceColor = rState.lineColor; + } + + bool StrokedPolyPolyAction::render( uno::Reference< rendering::XCachedPrimitive >& rCachedPrimitive, + const ::basegfx::B2DHomMatrix& rTransformation ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::PolyPolyAction::render()" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::PolyPolyAction: 0x%X", this ); + + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + rCachedPrimitive = mpCanvas->getUNOCanvas()->strokePolyPolygon( mxPolyPoly, + mpCanvas->getViewState(), + aLocalState, + maStrokeAttributes ); + return true; + } + + bool StrokedPolyPolyAction::render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + // TODO(F1): Split up poly-polygon into polygons, or even + // line segments, when subsets are requested. + + // polygon only contains a single action, fail if subset + // requests different range + if( rSubset.mnSubsetBegin != 0 || + rSubset.mnSubsetEnd != 1 ) + return false; + + return CachedPrimitiveBase::render( rTransformation ); + } + + ::basegfx::B2DRange StrokedPolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + return tools::calcDevicePixelBounds( + maBounds, + mpCanvas->getViewState(), + aLocalState ); + } + + ::basegfx::B2DRange StrokedPolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + // TODO(F1): Split up poly-polygon into polygons, or even + // line segments, when subsets are requested. + + // polygon only contains a single action, empty bounds + // if subset requests different range + if( rSubset.mnSubsetBegin != 0 || + rSubset.mnSubsetEnd != 1 ) + return ::basegfx::B2DRange(); + + return getBounds( rTransformation ); + } + + sal_Int32 StrokedPolyPolyAction::getActionCount() const + { + // TODO(F1): Split up poly-polygon into polygons, or even + // line segments, when subsets are requested. + return 1; + } + } + + ActionSharedPtr PolyPolyActionFactory::createPolyPolyAction( const ::basegfx::B2DPolyPolygon& rPoly, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) + { + OSL_ENSURE( rState.isLineColorSet || rState.isFillColorSet, + "PolyPolyActionFactory::createPolyPolyAction() with empty line and fill color" ); + return ActionSharedPtr( new PolyPolyAction( rPoly, rCanvas, rState, + rState.isFillColorSet, + rState.isLineColorSet ) ); + } + + ActionSharedPtr PolyPolyActionFactory::createPolyPolyAction( const ::basegfx::B2DPolyPolygon& rPoly, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const rendering::Texture& rTexture ) + { + return ActionSharedPtr( new TexturedPolyPolyAction( rPoly, rCanvas, rState, rTexture ) ); + } + + ActionSharedPtr PolyPolyActionFactory::createLinePolyPolyAction( const ::basegfx::B2DPolyPolygon& rPoly, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) + { + OSL_ENSURE( rState.isLineColorSet, + "PolyPolyActionFactory::createLinePolyPolyAction() called with empty line color" ); + + return ActionSharedPtr( new PolyPolyAction( rPoly, rCanvas, rState, + false, + rState.isLineColorSet ) ); + } + + ActionSharedPtr PolyPolyActionFactory::createPolyPolyAction( const ::basegfx::B2DPolyPolygon& rPoly, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const rendering::StrokeAttributes& rStrokeAttributes ) + { + OSL_ENSURE( rState.isLineColorSet, + "PolyPolyActionFactory::createPolyPolyAction() for strokes called with empty line color" ); + return ActionSharedPtr( new StrokedPolyPolyAction( rPoly, rCanvas, rState, rStrokeAttributes ) ); + } + + ActionSharedPtr PolyPolyActionFactory::createPolyPolyAction( const ::basegfx::B2DPolyPolygon& rPoly, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + int nTransparency ) + { + OSL_ENSURE( rState.isLineColorSet || rState.isFillColorSet, + "PolyPolyActionFactory::createPolyPolyAction() with empty line and fill color" ); + return ActionSharedPtr( new PolyPolyAction( rPoly, rCanvas, rState, + rState.isFillColorSet, + rState.isLineColorSet, + nTransparency ) ); + } + + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/mtfrenderer/polypolyaction.hxx b/cppcanvas/source/mtfrenderer/polypolyaction.hxx new file mode 100644 index 000000000000..a38ba92a8752 --- /dev/null +++ b/cppcanvas/source/mtfrenderer/polypolyaction.hxx @@ -0,0 +1,104 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_POLYPOLYACTION_HXX +#define _CPPCANVAS_POLYPOLYACTION_HXX + +#include <action.hxx> +#include <cppcanvas/canvas.hxx> + + +namespace basegfx { + class B2DPolyPolygon; +} +namespace com { namespace sun { namespace star { namespace rendering +{ + struct Texture; + struct StrokeAttributes; +} } } } + + +/* Definition of internal::PolyPolyActionFactory class */ + +namespace cppcanvas +{ + namespace internal + { + struct OutDevState; + + /** Creates encapsulated converters between GDIMetaFile and + XCanvas. The Canvas argument is deliberately placed at the + constructor, to force reconstruction of this object for a + new canvas. This considerably eases internal state + handling, since a lot of the internal state (e.g. fonts, + text layout) is Canvas-dependent. + */ + class PolyPolyActionFactory + { + public: + /// Create polygon, fill/stroke according to state + static ActionSharedPtr createPolyPolyAction( const ::basegfx::B2DPolyPolygon&, + const CanvasSharedPtr&, + const OutDevState& ); + + /// Create texture-filled polygon + static ActionSharedPtr createPolyPolyAction( const ::basegfx::B2DPolyPolygon&, + const CanvasSharedPtr&, + const OutDevState&, + const ::com::sun::star::rendering::Texture& ); + + /// Create line polygon (always stroked, not filled) + static ActionSharedPtr createLinePolyPolyAction( const ::basegfx::B2DPolyPolygon&, + const CanvasSharedPtr&, + const OutDevState& ); + + /// Create stroked polygon + static ActionSharedPtr createPolyPolyAction( const ::basegfx::B2DPolyPolygon&, + const CanvasSharedPtr&, + const OutDevState&, + const ::com::sun::star::rendering::StrokeAttributes& ); + + /// For transparent painting of the given polygon (normally, we take the colors always opaque) + static ActionSharedPtr createPolyPolyAction( const ::basegfx::B2DPolyPolygon&, + const CanvasSharedPtr&, + const OutDevState&, + int nTransparency ); + + private: + // static factory, disable big four + PolyPolyActionFactory(); + ~PolyPolyActionFactory(); + PolyPolyActionFactory(const PolyPolyActionFactory&); + PolyPolyActionFactory& operator=( const PolyPolyActionFactory& ); + }; + } +} + +#endif /* _CPPCANVAS_POLYPOLYACTION_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/mtfrenderer/rendergraphicaction.cxx b/cppcanvas/source/mtfrenderer/rendergraphicaction.cxx new file mode 100644 index 000000000000..764d3eabc6af --- /dev/null +++ b/cppcanvas/source/mtfrenderer/rendergraphicaction.cxx @@ -0,0 +1,201 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cppcanvas.hxx" + +#include <rtl/logfile.hxx> +#include <com/sun/star/rendering/XBitmap.hpp> +#include <com/sun/star/rendering/RepaintResult.hpp> +#include <com/sun/star/rendering/XCachedPrimitive.hpp> +#include <vcl/rendergraphicrasterizer.hxx> +#include <tools/gen.hxx> +#include <vcl/canvastools.hxx> +#include <canvas/canvastools.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/vector/b2dsize.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/range/b2drange.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <boost/utility.hpp> +#include "cachedprimitivebase.hxx" +#include "rendergraphicaction.hxx" +#include "outdevstate.hxx" +#include "mtftools.hxx" +#include <basegfx/matrix/b2dhommatrixtools.hxx> + + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace internal + { + namespace + { + + class RenderGraphicAction : public CachedPrimitiveBase + { + public: + RenderGraphicAction( const ::vcl::RenderGraphic& rRenderGraphic, + const ::basegfx::B2DPoint& rDstPoint, + const ::basegfx::B2DVector& rDstSize, + const CanvasSharedPtr&, + const OutDevState& ); + + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual sal_Int32 getActionCount() const; + + private: + using Action::render; + virtual bool render( uno::Reference< rendering::XCachedPrimitive >& rCachedPrimitive, + const ::basegfx::B2DHomMatrix& rTransformation ) const; + + ::vcl::RenderGraphic maRenderGraphic; + uno::Reference< rendering::XBitmap > mxBitmap; + CanvasSharedPtr mpCanvas; + rendering::RenderState maState; + }; + + RenderGraphicAction::RenderGraphicAction( const ::vcl::RenderGraphic& rRenderGraphic, + const ::basegfx::B2DPoint& rDstPoint, + const ::basegfx::B2DVector& rDstSize, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) : + CachedPrimitiveBase( rCanvas, true ), + maRenderGraphic( rRenderGraphic ), + mpCanvas( rCanvas ) + { + tools::initRenderState( maState,rState ); + + const ::vcl::RenderGraphicRasterizer aRasterizer( rRenderGraphic ); + const BitmapEx aBmpEx( aRasterizer.Rasterize( ::vcl::unotools::sizeFromB2DSize( rDstSize ) ) ); + const Size aRasteredSizePixel( aBmpEx.GetSizePixel() ); + + if( aRasteredSizePixel.Width() && aRasteredSizePixel.Height() ) + { + const ::basegfx::B2DVector aScale( rDstSize.getX() / aRasteredSizePixel.Width(), + rDstSize.getY() / aRasteredSizePixel.Height() ); + const basegfx::B2DHomMatrix aLocalTransformation( + basegfx::tools::createScaleTranslateB2DHomMatrix( aScale, rDstPoint)) ; + + ::canvas::tools::appendToRenderState( maState, aLocalTransformation ); + + // correct clip (which is relative to original transform) + tools::modifyClip( maState, rState, rCanvas, rDstPoint, &aScale, NULL ); + + mxBitmap = ::vcl::unotools::xBitmapFromBitmapEx( rCanvas->getUNOCanvas()->getDevice(), aBmpEx ); + } + } + + bool RenderGraphicAction::render( uno::Reference< rendering::XCachedPrimitive >& rCachedPrimitive, + const ::basegfx::B2DHomMatrix& rTransformation ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::RenderGraphicAction::render()" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::RenderGraphicAction: 0x%X", this ); + + if( mxBitmap.is() ) + { + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + rCachedPrimitive = mpCanvas->getUNOCanvas()->drawBitmap( mxBitmap, + mpCanvas->getViewState(), + aLocalState ); + } + + return true; + } + + bool RenderGraphicAction::render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + // rendergraphic only contains a single action, fail if subset + // requests different range + if( rSubset.mnSubsetBegin != 0 || + rSubset.mnSubsetEnd != 1 ) + return false; + + return CachedPrimitiveBase::render( rTransformation ); + } + + ::basegfx::B2DRange RenderGraphicAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + ::basegfx::B2DRange aRet; + + if( mxBitmap.is() ) + { + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + geometry::IntegerSize2D aSize( mxBitmap->getSize() ); + + aRet = tools::calcDevicePixelBounds( ::basegfx::B2DRange( 0, 0, aSize.Width, aSize.Height ), + mpCanvas->getViewState(), aLocalState ); + } + + return( aRet ); + } + + ::basegfx::B2DRange RenderGraphicAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + // rendergraphic only contains a single action, empty bounds + // if subset requests different range + if( rSubset.mnSubsetBegin != 0 || + rSubset.mnSubsetEnd != 1 ) + return ::basegfx::B2DRange(); + + return getBounds( rTransformation ); + } + + sal_Int32 RenderGraphicAction::getActionCount() const + { + return 1; + } + } + + ActionSharedPtr RenderGraphicActionFactory::createRenderGraphicAction( const ::vcl::RenderGraphic& rRenderGraphic, + const ::basegfx::B2DPoint& rDstPoint, + const ::basegfx::B2DVector& rDstSize, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) + { + return ActionSharedPtr( new RenderGraphicAction(rRenderGraphic, + rDstPoint, + rDstSize, + rCanvas, + rState ) ); + } + } +} diff --git a/cppcanvas/source/mtfrenderer/rendergraphicaction.hxx b/cppcanvas/source/mtfrenderer/rendergraphicaction.hxx new file mode 100644 index 000000000000..f1e2dccdfe0d --- /dev/null +++ b/cppcanvas/source/mtfrenderer/rendergraphicaction.hxx @@ -0,0 +1,77 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_RENDERGRAPHICACTION_HXX +#define _CPPCANVAS_RENDERGRAPHICACTION_HXX + +#include <cppcanvas/canvas.hxx> +#include <action.hxx> + +namespace basegfx { + class B2DPoint; + class B2DVector; +} +namespace vcl { + class RenderGraphic; +} + +/* Definition of internal::RenderGraphicActionFactory class */ + +namespace cppcanvas +{ + namespace internal + { + struct OutDevState; + + /** Creates encapsulated converters between GDIMetaFile and + XCanvas. The Canvas argument is deliberately placed at the + constructor, to force reconstruction of this object for a + new canvas. This considerably eases internal state + handling, since a lot of the internal state (e.g. fonts, + text layout) is Canvas-dependent. + */ + class RenderGraphicActionFactory + { + public: + /// Scaled rendergraphic action, dest point and dest size + static ActionSharedPtr createRenderGraphicAction( const ::vcl::RenderGraphic& rRenderGraphic, + const ::basegfx::B2DPoint& rDstPoint, + const ::basegfx::B2DVector& rDstSize, + const CanvasSharedPtr&, + const OutDevState& ); + + private: + // static factory, disable big four + RenderGraphicActionFactory(); + ~RenderGraphicActionFactory(); + RenderGraphicActionFactory(const RenderGraphicActionFactory&); + RenderGraphicActionFactory& operator=( const RenderGraphicActionFactory& ); + }; + } +} + +#endif /*_CPPCANVAS_RENDERGRAPHICACTION_HXX */ diff --git a/cppcanvas/source/mtfrenderer/textaction.cxx b/cppcanvas/source/mtfrenderer/textaction.cxx new file mode 100644 index 000000000000..a80306df3e05 --- /dev/null +++ b/cppcanvas/source/mtfrenderer/textaction.cxx @@ -0,0 +1,2299 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cppcanvas.hxx" + +#include <canvas/debug.hxx> +#include <tools/diagnose_ex.h> +#include <canvas/verbosetrace.hxx> + +#include <rtl/logfile.hxx> + +#include <com/sun/star/rendering/PathCapType.hpp> +#include <com/sun/star/rendering/PathJoinType.hpp> +#include <com/sun/star/rendering/XCanvas.hpp> +#include <com/sun/star/rendering/XCanvasFont.hpp> + +#include <basegfx/numeric/ftools.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/vector/b2dsize.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> + +#include <tools/gen.hxx> +#include <vcl/canvastools.hxx> +#include <vcl/virdev.hxx> + +#include <basegfx/tools/canvastools.hxx> +#include <canvas/canvastools.hxx> + +#include <boost/scoped_array.hpp> +#include <boost/bind.hpp> +#include <boost/utility.hpp> + +#include "textaction.hxx" +#include "outdevstate.hxx" +#include "mtftools.hxx" + + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace internal + { + namespace + { + void init( rendering::RenderState& o_rRenderState, + const ::basegfx::B2DPoint& rStartPoint, + const OutDevState& rState, + const CanvasSharedPtr& rCanvas ) + { + tools::initRenderState(o_rRenderState,rState); + + // #i36950# Offset clip back to origin (as it's also moved + // by rStartPoint) + // #i53964# Also take VCL font rotation into account, + // since this, opposed to the FontMatrix rotation + // elsewhere, _does_ get incorporated into the render + // state transform. + tools::modifyClip( o_rRenderState, + rState, + rCanvas, + rStartPoint, + NULL, + &rState.fontRotation ); + + basegfx::B2DHomMatrix aLocalTransformation(basegfx::tools::createRotateB2DHomMatrix(rState.fontRotation)); + aLocalTransformation.translate( rStartPoint.getX(), + rStartPoint.getY() ); + ::canvas::tools::appendToRenderState( o_rRenderState, + aLocalTransformation ); + + o_rRenderState.DeviceColor = rState.textColor; + } + + void init( rendering::RenderState& o_rRenderState, + const ::basegfx::B2DPoint& rStartPoint, + const OutDevState& rState, + const CanvasSharedPtr& rCanvas, + const ::basegfx::B2DHomMatrix& rTextTransform ) + { + init( o_rRenderState, rStartPoint, rState, rCanvas ); + + // TODO(F2): Also inversely-transform clip with + // rTextTransform (which is actually rather hard, as the + // text transform is _prepended_ to the render state)! + + // prepend extra font transform to render state + // (prepend it, because it's interpreted in the unit + // rect coordinate space) + ::canvas::tools::prependToRenderState( o_rRenderState, + rTextTransform ); + } + + void init( rendering::RenderState& o_rRenderState, + uno::Reference< rendering::XCanvasFont >& o_rFont, + const ::basegfx::B2DPoint& rStartPoint, + const OutDevState& rState, + const CanvasSharedPtr& rCanvas ) + { + // ensure that o_rFont is valid. It is possible that + // text actions are generated without previously + // setting a font. Then, just take a default font + if( !o_rFont.is() ) + { + // Use completely default FontRequest + const rendering::FontRequest aFontRequest; + + geometry::Matrix2D aFontMatrix; + ::canvas::tools::setIdentityMatrix2D( aFontMatrix ); + + o_rFont = rCanvas->getUNOCanvas()->createFont( + aFontRequest, + uno::Sequence< beans::PropertyValue >(), + aFontMatrix ); + } + + init( o_rRenderState, + rStartPoint, + rState, + rCanvas ); + } + + void init( rendering::RenderState& o_rRenderState, + uno::Reference< rendering::XCanvasFont >& o_rFont, + const ::basegfx::B2DPoint& rStartPoint, + const OutDevState& rState, + const CanvasSharedPtr& rCanvas, + const ::basegfx::B2DHomMatrix& rTextTransform ) + { + init( o_rRenderState, o_rFont, rStartPoint, rState, rCanvas ); + + // TODO(F2): Also inversely-transform clip with + // rTextTransform (which is actually rather hard, as the + // text transform is _prepended_ to the render state)! + + // prepend extra font transform to render state + // (prepend it, because it's interpreted in the unit + // rect coordinate space) + ::canvas::tools::prependToRenderState( o_rRenderState, + rTextTransform ); + } + + ::basegfx::B2DPolyPolygon textLinesFromLogicalOffsets( const uno::Sequence< double >& rOffsets, + const tools::TextLineInfo& rTextLineInfo ) + { + return tools::createTextLinesPolyPolygon( + 0.0, + // extract character cell furthest to the right + *(::std::max_element( + rOffsets.getConstArray(), + rOffsets.getConstArray() + rOffsets.getLength() )), + rTextLineInfo ); + } + + uno::Sequence< double > setupDXArray( const sal_Int32* pCharWidths, + sal_Int32 nLen, + const OutDevState& rState ) + { + // convert character widths from logical units + uno::Sequence< double > aCharWidthSeq( nLen ); + double* pOutputWidths( aCharWidthSeq.getArray() ); + + // #143885# maintain (nearly) full precision of DX + // array, by circumventing integer-based + // OutDev-mapping + const double nScale( rState.mapModeTransform.get(0,0) ); + for( int i = 0; i < nLen; ++i ) + { + // TODO(F2): use correct scale direction + *pOutputWidths++ = *pCharWidths++ * nScale; + } + + return aCharWidthSeq; + } + + uno::Sequence< double > setupDXArray( const ::String& rText, + sal_Int32 nStartPos, + sal_Int32 nLen, + VirtualDevice& rVDev, + const OutDevState& rState ) + { + // no external DX array given, create one from given + // string + ::boost::scoped_array< sal_Int32 > pCharWidths( new sal_Int32[nLen] ); + + rVDev.GetTextArray( rText, pCharWidths.get(), + static_cast<sal_uInt16>(nStartPos), + static_cast<sal_uInt16>(nLen) ); + + return setupDXArray( pCharWidths.get(), nLen, rState ); + } + + ::basegfx::B2DPoint adaptStartPoint( const ::basegfx::B2DPoint& rStartPoint, + const OutDevState& rState, + const uno::Sequence< double >& rOffsets ) + { + ::basegfx::B2DPoint aLocalPoint( rStartPoint ); + + if( rState.textAlignment ) + { + // text origin is right, not left. Modify start point + // accordingly, because XCanvas::drawTextLayout() + // always aligns left! + + const double nOffset( rOffsets[ rOffsets.getLength()-1 ] ); + + // correct start point for rotated text: rotate around + // former start point + aLocalPoint.setX( aLocalPoint.getX() + cos( rState.fontRotation )*nOffset ); + aLocalPoint.setY( aLocalPoint.getY() + sin( rState.fontRotation )*nOffset ); + } + + return aLocalPoint; + } + + /** Perform common setup for array text actions + + This method creates the XTextLayout object and + initializes it, e.g. with the logical advancements. + */ + void initArrayAction( rendering::RenderState& o_rRenderState, + uno::Reference< rendering::XTextLayout >& o_rTextLayout, + const ::basegfx::B2DPoint& rStartPoint, + const ::rtl::OUString& rText, + sal_Int32 nStartPos, + sal_Int32 nLen, + const uno::Sequence< double >& rOffsets, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const ::basegfx::B2DHomMatrix* pTextTransform ) + { + ENSURE_OR_THROW( rOffsets.getLength(), + "::cppcanvas::internal::initArrayAction(): zero-length DX array" ); + + const ::basegfx::B2DPoint aLocalStartPoint( + adaptStartPoint( rStartPoint, rState, rOffsets ) ); + + uno::Reference< rendering::XCanvasFont > xFont( rState.xFont ); + + if( pTextTransform ) + init( o_rRenderState, xFont, aLocalStartPoint, rState, rCanvas, *pTextTransform ); + else + init( o_rRenderState, xFont, aLocalStartPoint, rState, rCanvas ); + + o_rTextLayout = xFont->createTextLayout( + rendering::StringContext( rText, nStartPos, nLen ), + rState.textDirection, + 0 ); + + ENSURE_OR_THROW( o_rTextLayout.is(), + "::cppcanvas::internal::initArrayAction(): Invalid font" ); + + o_rTextLayout->applyLogicalAdvancements( rOffsets ); + } + + double getLineWidth( ::VirtualDevice& rVDev, + const OutDevState& rState, + const rendering::StringContext& rStringContext ) + { + // TODO(F2): use correct scale direction + const ::basegfx::B2DSize aSize( rVDev.GetTextWidth( rStringContext.Text, + static_cast<sal_uInt16>(rStringContext.StartPosition), + static_cast<sal_uInt16>(rStringContext.Length) ), + 0 ); + + return (rState.mapModeTransform * aSize).getX(); + } + + uno::Sequence< double > + calcSubsetOffsets( rendering::RenderState& io_rRenderState, + double& o_rMinPos, + double& o_rMaxPos, + const uno::Reference< rendering::XTextLayout >& rOrigTextLayout, + const ::cppcanvas::internal::Action::Subset& rSubset ) + { + ENSURE_OR_THROW( rSubset.mnSubsetEnd > rSubset.mnSubsetBegin, + "::cppcanvas::internal::calcSubsetOffsets(): invalid subset range range" ); + + uno::Sequence< double > aOrigOffsets( rOrigTextLayout->queryLogicalAdvancements() ); + const double* pOffsets( aOrigOffsets.getConstArray() ); + + ENSURE_OR_THROW( aOrigOffsets.getLength() >= rSubset.mnSubsetEnd, + "::cppcanvas::internal::calcSubsetOffsets(): invalid subset range range" ); + + // TODO(F3): It currently seems that for RTL text, the + // DX offsets are nevertheless increasing in logical + // text order (I'd expect they are decreasing, + // mimicking the fact that the text is output + // right-to-left). This breaks text effects for ALL + // RTL languages. + + // determine leftmost position in given subset range - + // as the DX array contains the output positions + // starting with the second character (the first is + // assumed to have output position 0), correct begin + // iterator. + const double nMinPos( rSubset.mnSubsetBegin <= 0 ? 0 : + *(::std::min_element( pOffsets+rSubset.mnSubsetBegin-1, + pOffsets+rSubset.mnSubsetEnd )) ); + + // determine rightmost position in given subset range + // - as the DX array contains the output positions + // starting with the second character (the first is + // assumed to have output position 0), correct begin + // iterator. + const double nMaxPos( + *(::std::max_element( pOffsets + (rSubset.mnSubsetBegin <= 0 ? + 0 : rSubset.mnSubsetBegin-1), + pOffsets + rSubset.mnSubsetEnd )) ); + + + // adapt render state, to move text output to given offset + // ------------------------------------------------------- + + // TODO(F1): Strictly speaking, we also have to adapt + // the clip here, which normally should _not_ move + // with the output offset. Neglected for now, as it + // does not matter for drawing layer output + + if( rSubset.mnSubsetBegin > 0 ) + { + ::basegfx::B2DHomMatrix aTranslation; + if( rOrigTextLayout->getFont()->getFontRequest().FontDescription.IsVertical ) + { + // vertical text -> offset in y direction + aTranslation.translate( 0.0, nMinPos ); + } + else + { + // horizontal text -> offset in x direction + aTranslation.translate( nMinPos, 0.0 ); + } + + ::canvas::tools::appendToRenderState( io_rRenderState, + aTranslation ); + } + + + // reduce DX array to given substring + // ---------------------------------- + + const sal_Int32 nNewElements( rSubset.mnSubsetEnd - rSubset.mnSubsetBegin ); + uno::Sequence< double > aAdaptedOffsets( nNewElements ); + double* pAdaptedOffsets( aAdaptedOffsets.getArray() ); + + // move to new output position (subtract nMinPos, + // which is the new '0' position), copy only the range + // as given by rSubset. + ::std::transform( pOffsets + rSubset.mnSubsetBegin, + pOffsets + rSubset.mnSubsetEnd, + pAdaptedOffsets, + ::boost::bind( ::std::minus<double>(), + _1, + nMinPos ) ); + + o_rMinPos = nMinPos; + o_rMaxPos = nMaxPos; + + return aAdaptedOffsets; + } + + uno::Reference< rendering::XTextLayout > + createSubsetLayout( const rendering::StringContext& rOrigContext, + const ::cppcanvas::internal::Action::Subset& rSubset, + const uno::Reference< rendering::XTextLayout >& rOrigTextLayout ) + { + // create temporary new text layout with subset string + // --------------------------------------------------- + + const sal_Int32 nNewStartPos( rOrigContext.StartPosition + ::std::min( + rSubset.mnSubsetBegin, rOrigContext.Length-1 ) ); + const sal_Int32 nNewLength( ::std::max( + ::std::min( + rSubset.mnSubsetEnd - rSubset.mnSubsetBegin, + rOrigContext.Length ), + sal_Int32( 0 ) ) ); + + const rendering::StringContext aContext( rOrigContext.Text, + nNewStartPos, + nNewLength ); + + uno::Reference< rendering::XTextLayout > xTextLayout( + rOrigTextLayout->getFont()->createTextLayout( aContext, + rOrigTextLayout->getMainTextDirection(), + 0 ), + uno::UNO_QUERY_THROW ); + + return xTextLayout; + } + + /** Setup subset text layout + + @param io_rTextLayout + Must contain original (full set) text layout on input, + will contain subsetted text layout (or empty + reference, for empty subsets) on output. + + @param io_rRenderState + Must contain original render state on input, will + contain shifted render state concatenated with + rTransformation on output. + + @param rTransformation + Additional transformation, to be prepended to render + state + + @param rSubset + Subset to prepare + */ + void createSubsetLayout( uno::Reference< rendering::XTextLayout >& io_rTextLayout, + rendering::RenderState& io_rRenderState, + double& o_rMinPos, + double& o_rMaxPos, + const ::basegfx::B2DHomMatrix& rTransformation, + const Action::Subset& rSubset ) + { + ::canvas::tools::prependToRenderState(io_rRenderState, rTransformation); + + if( rSubset.mnSubsetBegin == rSubset.mnSubsetEnd ) + { + // empty range, empty layout + io_rTextLayout.clear(); + + return; + } + + ENSURE_OR_THROW( io_rTextLayout.is(), + "createSubsetLayout(): Invalid input layout" ); + + const rendering::StringContext& rOrigContext( io_rTextLayout->getText() ); + + if( rSubset.mnSubsetBegin == 0 && + rSubset.mnSubsetEnd == rOrigContext.Length ) + { + // full range, no need for subsetting + return; + } + + uno::Reference< rendering::XTextLayout > xTextLayout( + createSubsetLayout( rOrigContext, rSubset, io_rTextLayout ) ); + + if( xTextLayout.is() ) + { + xTextLayout->applyLogicalAdvancements( + calcSubsetOffsets( io_rRenderState, + o_rMinPos, + o_rMaxPos, + io_rTextLayout, + rSubset ) ); + } + + io_rTextLayout = xTextLayout; + } + + + /** Interface for renderEffectText functor below. + + This is interface is used from the renderEffectText() + method below, to call the client implementation. + */ + class TextRenderer + { + public: + virtual ~TextRenderer() {} + + /// Render text with given RenderState + virtual bool operator()( const rendering::RenderState& rRenderState ) const = 0; + }; + + /** Render effect text. + + @param rRenderer + Functor object, will be called to render the actual + part of the text effect (the text itself and the means + to render it are unknown to this method) + */ + bool renderEffectText( const TextRenderer& rRenderer, + const rendering::RenderState& rRenderState, + const rendering::ViewState& /*rViewState*/, + const uno::Reference< rendering::XCanvas >& xCanvas, + const ::Color& rShadowColor, + const ::basegfx::B2DSize& rShadowOffset, + const ::Color& rReliefColor, + const ::basegfx::B2DSize& rReliefOffset ) + { + ::Color aEmptyColor( COL_AUTO ); + uno::Reference<rendering::XColorSpace> xColorSpace( + xCanvas->getDevice()->getDeviceColorSpace() ); + + // draw shadow text, if enabled + if( rShadowColor != aEmptyColor ) + { + rendering::RenderState aShadowState( rRenderState ); + ::basegfx::B2DHomMatrix aTranslate; + + aTranslate.translate( rShadowOffset.getX(), + rShadowOffset.getY() ); + + ::canvas::tools::appendToRenderState(aShadowState, aTranslate); + + aShadowState.DeviceColor = + ::vcl::unotools::colorToDoubleSequence( rShadowColor, + xColorSpace ); + + rRenderer( aShadowState ); + } + + // draw relief text, if enabled + if( rReliefColor != aEmptyColor ) + { + rendering::RenderState aReliefState( rRenderState ); + ::basegfx::B2DHomMatrix aTranslate; + + aTranslate.translate( rReliefOffset.getX(), + rReliefOffset.getY() ); + + ::canvas::tools::appendToRenderState(aReliefState, aTranslate); + + aReliefState.DeviceColor = + ::vcl::unotools::colorToDoubleSequence( rReliefColor, + xColorSpace ); + + rRenderer( aReliefState ); + } + + // draw normal text + rRenderer( rRenderState ); + + return true; + } + + + ::basegfx::B2DRange calcEffectTextBounds( const ::basegfx::B2DRange& rTextBounds, + const ::basegfx::B2DRange& rLineBounds, + const ::basegfx::B2DSize& rReliefOffset, + const ::basegfx::B2DSize& rShadowOffset, + const rendering::RenderState& rRenderState, + const rendering::ViewState& rViewState ) + { + ::basegfx::B2DRange aBounds( rTextBounds ); + + // add extends of text lines + aBounds.expand( rLineBounds ); + + // TODO(Q3): Provide this functionality at the B2DRange + ::basegfx::B2DRange aTotalBounds( aBounds ); + aTotalBounds.expand( + ::basegfx::B2DRange( aBounds.getMinX() + rReliefOffset.getX(), + aBounds.getMinY() + rReliefOffset.getY(), + aBounds.getMaxX() + rReliefOffset.getX(), + aBounds.getMaxY() + rReliefOffset.getY() ) ); + aTotalBounds.expand( + ::basegfx::B2DRange( aBounds.getMinX() + rShadowOffset.getX(), + aBounds.getMinY() + rShadowOffset.getY(), + aBounds.getMaxX() + rShadowOffset.getX(), + aBounds.getMaxY() + rShadowOffset.getY() ) ); + + return tools::calcDevicePixelBounds( aTotalBounds, + rViewState, + rRenderState ); + } + + void initEffectLinePolyPolygon( ::basegfx::B2DSize& o_rOverallSize, + uno::Reference< rendering::XPolyPolygon2D >& o_rTextLines, + const CanvasSharedPtr& rCanvas, + const uno::Sequence< double >& rOffsets, + const tools::TextLineInfo rLineInfo ) + { + const ::basegfx::B2DPolyPolygon aPoly( + textLinesFromLogicalOffsets( + rOffsets, + rLineInfo ) ); + + o_rOverallSize = ::basegfx::tools::getRange( aPoly ).getRange(); + + o_rTextLines = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + rCanvas->getUNOCanvas()->getDevice(), + aPoly ); + } + + void initEffectLinePolyPolygon( ::basegfx::B2DSize& o_rOverallSize, + uno::Reference< rendering::XPolyPolygon2D >& o_rTextLines, + const CanvasSharedPtr& rCanvas, + double nLineWidth, + const tools::TextLineInfo rLineInfo ) + { + const ::basegfx::B2DPolyPolygon aPoly( + tools::createTextLinesPolyPolygon( 0.0, nLineWidth, + rLineInfo ) ); + + o_rOverallSize = ::basegfx::tools::getRange( aPoly ).getRange(); + + o_rTextLines = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + rCanvas->getUNOCanvas()->getDevice(), + aPoly ); + } + + + // ------------------------------------------------------------------------- + + class TextAction : public Action, private ::boost::noncopyable + { + public: + TextAction( const ::basegfx::B2DPoint& rStartPoint, + const ::rtl::OUString& rString, + sal_Int32 nStartPos, + sal_Int32 nLen, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ); + + TextAction( const ::basegfx::B2DPoint& rStartPoint, + const ::rtl::OUString& rString, + sal_Int32 nStartPos, + sal_Int32 nLen, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const ::basegfx::B2DHomMatrix& rTextTransform ); + + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual sal_Int32 getActionCount() const; + + private: + // TODO(P2): This is potentially a real mass object + // (every character might be a separate TextAction), + // thus, make it as lightweight as possible. For + // example, share common RenderState among several + // TextActions, maybe using maOffsets for the + // translation. + + uno::Reference< rendering::XCanvasFont > mxFont; + const rendering::StringContext maStringContext; + const CanvasSharedPtr mpCanvas; + rendering::RenderState maState; + const sal_Int8 maTextDirection; + }; + + TextAction::TextAction( const ::basegfx::B2DPoint& rStartPoint, + const ::rtl::OUString& rString, + sal_Int32 nStartPos, + sal_Int32 nLen, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) : + mxFont( rState.xFont ), + maStringContext( rString, nStartPos, nLen ), + mpCanvas( rCanvas ), + maState(), + maTextDirection( rState.textDirection ) + { + init( maState, mxFont, + rStartPoint, + rState, rCanvas ); + + ENSURE_OR_THROW( mxFont.is(), + "::cppcanvas::internal::TextAction(): Invalid font" ); + } + + TextAction::TextAction( const ::basegfx::B2DPoint& rStartPoint, + const ::rtl::OUString& rString, + sal_Int32 nStartPos, + sal_Int32 nLen, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const ::basegfx::B2DHomMatrix& rTextTransform ) : + mxFont( rState.xFont ), + maStringContext( rString, nStartPos, nLen ), + mpCanvas( rCanvas ), + maState(), + maTextDirection( rState.textDirection ) + { + init( maState, mxFont, + rStartPoint, + rState, rCanvas, rTextTransform ); + + ENSURE_OR_THROW( mxFont.is(), + "::cppcanvas::internal::TextAction(): Invalid font" ); + } + + bool TextAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::TextAction::render()" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::TextAction: 0x%X", this ); + + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + mpCanvas->getUNOCanvas()->drawText( maStringContext, mxFont, + mpCanvas->getViewState(), aLocalState, maTextDirection ); + + return true; + } + + bool TextAction::render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& /*rSubset*/ ) const + { + OSL_FAIL( "TextAction::render(): Subset not supported by this object" ); + + // TODO(P1): Retrieve necessary font metric info for + // TextAction from XCanvas. Currently, the + // TextActionFactory does not generate this object for + // _subsettable_ text + return render( rTransformation ); + } + + ::basegfx::B2DRange TextAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + // create XTextLayout, to have the + // XTextLayout::queryTextBounds() method available + uno::Reference< rendering::XTextLayout > xTextLayout( + mxFont->createTextLayout( + maStringContext, + maTextDirection, + 0 ) ); + + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + return tools::calcDevicePixelBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D( + xTextLayout->queryTextBounds() ), + mpCanvas->getViewState(), + aLocalState ); + } + + ::basegfx::B2DRange TextAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& /*rSubset*/ ) const + { + OSL_FAIL( "TextAction::getBounds(): Subset not supported by this object" ); + + // TODO(P1): Retrieve necessary font metric info for + // TextAction from XCanvas. Currently, the + // TextActionFactory does not generate this object for + // _subsettable_ text + return getBounds( rTransformation ); + } + + sal_Int32 TextAction::getActionCount() const + { + // TODO(P1): Retrieve necessary font metric info for + // TextAction from XCanvas. Currently, the + // TextActionFactory does not generate this object for + // _subsettable_ text + return 1; + } + + + // ------------------------------------------------------------------------- + + class EffectTextAction : + public Action, + public TextRenderer, + private ::boost::noncopyable + { + public: + EffectTextAction( const ::basegfx::B2DPoint& rStartPoint, + const ::basegfx::B2DSize& rReliefOffset, + const ::Color& rReliefColor, + const ::basegfx::B2DSize& rShadowOffset, + const ::Color& rShadowColor, + const ::rtl::OUString& rText, + sal_Int32 nStartPos, + sal_Int32 nLen, + VirtualDevice& rVDev, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ); + + EffectTextAction( const ::basegfx::B2DPoint& rStartPoint, + const ::basegfx::B2DSize& rReliefOffset, + const ::Color& rReliefColor, + const ::basegfx::B2DSize& rShadowOffset, + const ::Color& rShadowColor, + const ::rtl::OUString& rText, + sal_Int32 nStartPos, + sal_Int32 nLen, + VirtualDevice& rVDev, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const ::basegfx::B2DHomMatrix& rTextTransform ); + + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual sal_Int32 getActionCount() const; + + private: + /// Interface TextRenderer + virtual bool operator()( const rendering::RenderState& rRenderState ) const; + + // TODO(P2): This is potentially a real mass object + // (every character might be a separate TextAction), + // thus, make it as lightweight as possible. For + // example, share common RenderState among several + // TextActions, maybe using maOffsets for the + // translation. + + uno::Reference< rendering::XCanvasFont > mxFont; + const rendering::StringContext maStringContext; + const CanvasSharedPtr mpCanvas; + rendering::RenderState maState; + const tools::TextLineInfo maTextLineInfo; + ::basegfx::B2DSize maLinesOverallSize; + const double mnLineWidth; + uno::Reference< rendering::XPolyPolygon2D > mxTextLines; + const ::basegfx::B2DSize maReliefOffset; + const ::Color maReliefColor; + const ::basegfx::B2DSize maShadowOffset; + const ::Color maShadowColor; + const sal_Int8 maTextDirection; + }; + + EffectTextAction::EffectTextAction( const ::basegfx::B2DPoint& rStartPoint, + const ::basegfx::B2DSize& rReliefOffset, + const ::Color& rReliefColor, + const ::basegfx::B2DSize& rShadowOffset, + const ::Color& rShadowColor, + const ::rtl::OUString& rText, + sal_Int32 nStartPos, + sal_Int32 nLen, + VirtualDevice& rVDev, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) : + mxFont( rState.xFont ), + maStringContext( rText, nStartPos, nLen ), + mpCanvas( rCanvas ), + maState(), + maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ), + maLinesOverallSize(), + mnLineWidth( getLineWidth( rVDev, rState, maStringContext ) ), + mxTextLines(), + maReliefOffset( rReliefOffset ), + maReliefColor( rReliefColor ), + maShadowOffset( rShadowOffset ), + maShadowColor( rShadowColor ), + maTextDirection( rState.textDirection ) + { + initEffectLinePolyPolygon( maLinesOverallSize, + mxTextLines, + rCanvas, + mnLineWidth, + maTextLineInfo ); + + init( maState, mxFont, + rStartPoint, + rState, rCanvas ); + + ENSURE_OR_THROW( mxFont.is() && mxTextLines.is(), + "::cppcanvas::internal::EffectTextAction(): Invalid font or lines" ); + } + + EffectTextAction::EffectTextAction( const ::basegfx::B2DPoint& rStartPoint, + const ::basegfx::B2DSize& rReliefOffset, + const ::Color& rReliefColor, + const ::basegfx::B2DSize& rShadowOffset, + const ::Color& rShadowColor, + const ::rtl::OUString& rText, + sal_Int32 nStartPos, + sal_Int32 nLen, + VirtualDevice& rVDev, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const ::basegfx::B2DHomMatrix& rTextTransform ) : + mxFont( rState.xFont ), + maStringContext( rText, nStartPos, nLen ), + mpCanvas( rCanvas ), + maState(), + maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ), + maLinesOverallSize(), + mnLineWidth( getLineWidth( rVDev, rState, maStringContext ) ), + mxTextLines(), + maReliefOffset( rReliefOffset ), + maReliefColor( rReliefColor ), + maShadowOffset( rShadowOffset ), + maShadowColor( rShadowColor ), + maTextDirection( rState.textDirection ) + { + initEffectLinePolyPolygon( maLinesOverallSize, + mxTextLines, + rCanvas, + mnLineWidth, + maTextLineInfo ); + + init( maState, mxFont, + rStartPoint, + rState, rCanvas, rTextTransform ); + + ENSURE_OR_THROW( mxFont.is() && mxTextLines.is(), + "::cppcanvas::internal::EffectTextAction(): Invalid font or lines" ); + } + + bool EffectTextAction::operator()( const rendering::RenderState& rRenderState ) const + { + const rendering::ViewState& rViewState( mpCanvas->getViewState() ); + const uno::Reference< rendering::XCanvas >& rCanvas( mpCanvas->getUNOCanvas() ); + + rCanvas->fillPolyPolygon( mxTextLines, + rViewState, + rRenderState ); + + rCanvas->drawText( maStringContext, mxFont, + rViewState, + rRenderState, + maTextDirection ); + + return true; + } + + bool EffectTextAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::EffectTextAction::render()" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::EffectTextAction: 0x%X", this ); + + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + return renderEffectText( *this, + aLocalState, + mpCanvas->getViewState(), + mpCanvas->getUNOCanvas(), + maShadowColor, + maShadowOffset, + maReliefColor, + maReliefOffset ); + } + + bool EffectTextAction::render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& /*rSubset*/ ) const + { + OSL_FAIL( "EffectTextAction::render(): Subset not supported by this object" ); + + // TODO(P1): Retrieve necessary font metric info for + // TextAction from XCanvas. Currently, the + // TextActionFactory does not generate this object for + // subsettable text + return render( rTransformation ); + } + + ::basegfx::B2DRange EffectTextAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + // create XTextLayout, to have the + // XTextLayout::queryTextBounds() method available + uno::Reference< rendering::XTextLayout > xTextLayout( + mxFont->createTextLayout( + maStringContext, + maTextDirection, + 0 ) ); + + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + return calcEffectTextBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D( + xTextLayout->queryTextBounds() ), + ::basegfx::B2DRange( 0,0, + maLinesOverallSize.getX(), + maLinesOverallSize.getY() ), + maReliefOffset, + maShadowOffset, + aLocalState, + mpCanvas->getViewState() ); + } + + ::basegfx::B2DRange EffectTextAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& /*rSubset*/ ) const + { + OSL_FAIL( "EffectTextAction::getBounds(): Subset not supported by this object" ); + + // TODO(P1): Retrieve necessary font metric info for + // TextAction from XCanvas. Currently, the + // TextActionFactory does not generate this object for + // _subsettable_ text + return getBounds( rTransformation ); + } + + sal_Int32 EffectTextAction::getActionCount() const + { + // TODO(P1): Retrieve necessary font metric info for + // TextAction from XCanvas. Currently, the + // TextActionFactory does not generate this object for + // subsettable text + return 1; + } + + + // ------------------------------------------------------------------------- + + class TextArrayAction : public Action, private ::boost::noncopyable + { + public: + TextArrayAction( const ::basegfx::B2DPoint& rStartPoint, + const ::rtl::OUString& rString, + sal_Int32 nStartPos, + sal_Int32 nLen, + const uno::Sequence< double >& rOffsets, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ); + + TextArrayAction( const ::basegfx::B2DPoint& rStartPoint, + const ::rtl::OUString& rString, + sal_Int32 nStartPos, + sal_Int32 nLen, + const uno::Sequence< double >& rOffsets, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const ::basegfx::B2DHomMatrix& rTextTransform ); + + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual sal_Int32 getActionCount() const; + + private: + // TODO(P2): This is potentially a real mass object + // (every character might be a separate TextAction), + // thus, make it as lightweight as possible. For + // example, share common RenderState among several + // TextActions, maybe using maOffsets for the + // translation. + + uno::Reference< rendering::XTextLayout > mxTextLayout; + const CanvasSharedPtr mpCanvas; + rendering::RenderState maState; + }; + + TextArrayAction::TextArrayAction( const ::basegfx::B2DPoint& rStartPoint, + const ::rtl::OUString& rString, + sal_Int32 nStartPos, + sal_Int32 nLen, + const uno::Sequence< double >& rOffsets, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) : + mxTextLayout(), + mpCanvas( rCanvas ), + maState() + { + initArrayAction( maState, + mxTextLayout, + rStartPoint, + rString, + nStartPos, + nLen, + rOffsets, + rCanvas, + rState, NULL ); + } + + TextArrayAction::TextArrayAction( const ::basegfx::B2DPoint& rStartPoint, + const ::rtl::OUString& rString, + sal_Int32 nStartPos, + sal_Int32 nLen, + const uno::Sequence< double >& rOffsets, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const ::basegfx::B2DHomMatrix& rTextTransform ) : + mxTextLayout(), + mpCanvas( rCanvas ), + maState() + { + initArrayAction( maState, + mxTextLayout, + rStartPoint, + rString, + nStartPos, + nLen, + rOffsets, + rCanvas, + rState, + &rTextTransform ); + } + + bool TextArrayAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::TextArrayAction::render()" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::TextArrayAction: 0x%X", this ); + + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + mpCanvas->getUNOCanvas()->drawTextLayout( mxTextLayout, + mpCanvas->getViewState(), + aLocalState ); + + return true; + } + + bool TextArrayAction::render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::TextArrayAction::render( subset )" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::TextArrayAction: 0x%X", this ); + + rendering::RenderState aLocalState( maState ); + uno::Reference< rendering::XTextLayout > xTextLayout( mxTextLayout ); + + double nDummy0, nDummy1; + createSubsetLayout( xTextLayout, + aLocalState, + nDummy0, + nDummy1, + rTransformation, + rSubset ); + + if( !xTextLayout.is() ) + return true; // empty layout, render nothing + + mpCanvas->getUNOCanvas()->drawTextLayout( xTextLayout, + mpCanvas->getViewState(), + aLocalState ); + + return true; + } + + ::basegfx::B2DRange TextArrayAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + return tools::calcDevicePixelBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D( + mxTextLayout->queryTextBounds() ), + mpCanvas->getViewState(), + aLocalState ); + } + + ::basegfx::B2DRange TextArrayAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::TextArrayAction::getBounds( subset )" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::TextArrayAction: 0x%X", this ); + + rendering::RenderState aLocalState( maState ); + uno::Reference< rendering::XTextLayout > xTextLayout( mxTextLayout ); + + double nDummy0, nDummy1; + createSubsetLayout( xTextLayout, + aLocalState, + nDummy0, + nDummy1, + rTransformation, + rSubset ); + + if( !xTextLayout.is() ) + return ::basegfx::B2DRange(); // empty layout, empty bounds + + return tools::calcDevicePixelBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D( + xTextLayout->queryTextBounds() ), + mpCanvas->getViewState(), + aLocalState ); + } + + sal_Int32 TextArrayAction::getActionCount() const + { + const rendering::StringContext& rOrigContext( mxTextLayout->getText() ); + + return rOrigContext.Length; + } + + + // ------------------------------------------------------------------------- + + class EffectTextArrayAction : + public Action, + public TextRenderer, + private ::boost::noncopyable + { + public: + EffectTextArrayAction( const ::basegfx::B2DPoint& rStartPoint, + const ::basegfx::B2DSize& rReliefOffset, + const ::Color& rReliefColor, + const ::basegfx::B2DSize& rShadowOffset, + const ::Color& rShadowColor, + const ::rtl::OUString& rText, + sal_Int32 nStartPos, + sal_Int32 nLen, + const uno::Sequence< double >& rOffsets, + VirtualDevice& rVDev, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ); + EffectTextArrayAction( const ::basegfx::B2DPoint& rStartPoint, + const ::basegfx::B2DSize& rReliefOffset, + const ::Color& rReliefColor, + const ::basegfx::B2DSize& rShadowOffset, + const ::Color& rShadowColor, + const ::rtl::OUString& rText, + sal_Int32 nStartPos, + sal_Int32 nLen, + const uno::Sequence< double >& rOffsets, + VirtualDevice& rVDev, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const ::basegfx::B2DHomMatrix& rTextTransform ); + + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual sal_Int32 getActionCount() const; + + private: + // TextRenderer interface + virtual bool operator()( const rendering::RenderState& rRenderState ) const; + + // TODO(P2): This is potentially a real mass object + // (every character might be a separate TextAction), + // thus, make it as lightweight as possible. For + // example, share common RenderState among several + // TextActions, maybe using maOffsets for the + // translation. + + uno::Reference< rendering::XTextLayout > mxTextLayout; + const CanvasSharedPtr mpCanvas; + rendering::RenderState maState; + const tools::TextLineInfo maTextLineInfo; + ::basegfx::B2DSize maLinesOverallSize; + uno::Reference< rendering::XPolyPolygon2D > mxTextLines; + const ::basegfx::B2DSize maReliefOffset; + const ::Color maReliefColor; + const ::basegfx::B2DSize maShadowOffset; + const ::Color maShadowColor; + }; + + EffectTextArrayAction::EffectTextArrayAction( const ::basegfx::B2DPoint& rStartPoint, + const ::basegfx::B2DSize& rReliefOffset, + const ::Color& rReliefColor, + const ::basegfx::B2DSize& rShadowOffset, + const ::Color& rShadowColor, + const ::rtl::OUString& rText, + sal_Int32 nStartPos, + sal_Int32 nLen, + const uno::Sequence< double >& rOffsets, + VirtualDevice& rVDev, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) : + mxTextLayout(), + mpCanvas( rCanvas ), + maState(), + maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ), + maLinesOverallSize(), + mxTextLines(), + maReliefOffset( rReliefOffset ), + maReliefColor( rReliefColor ), + maShadowOffset( rShadowOffset ), + maShadowColor( rShadowColor ) + { + initEffectLinePolyPolygon( maLinesOverallSize, + mxTextLines, + rCanvas, + rOffsets, + maTextLineInfo ); + + initArrayAction( maState, + mxTextLayout, + rStartPoint, + rText, + nStartPos, + nLen, + rOffsets, + rCanvas, + rState, NULL ); + } + + EffectTextArrayAction::EffectTextArrayAction( const ::basegfx::B2DPoint& rStartPoint, + const ::basegfx::B2DSize& rReliefOffset, + const ::Color& rReliefColor, + const ::basegfx::B2DSize& rShadowOffset, + const ::Color& rShadowColor, + const ::rtl::OUString& rText, + sal_Int32 nStartPos, + sal_Int32 nLen, + const uno::Sequence< double >& rOffsets, + VirtualDevice& rVDev, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const ::basegfx::B2DHomMatrix& rTextTransform ) : + mxTextLayout(), + mpCanvas( rCanvas ), + maState(), + maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ), + maLinesOverallSize(), + mxTextLines(), + maReliefOffset( rReliefOffset ), + maReliefColor( rReliefColor ), + maShadowOffset( rShadowOffset ), + maShadowColor( rShadowColor ) + { + initEffectLinePolyPolygon( maLinesOverallSize, + mxTextLines, + rCanvas, + rOffsets, + maTextLineInfo ); + + initArrayAction( maState, + mxTextLayout, + rStartPoint, + rText, + nStartPos, + nLen, + rOffsets, + rCanvas, + rState, + &rTextTransform ); + } + + bool EffectTextArrayAction::operator()( const rendering::RenderState& rRenderState ) const + { + const rendering::ViewState& rViewState( mpCanvas->getViewState() ); + const uno::Reference< rendering::XCanvas >& rCanvas( mpCanvas->getUNOCanvas() ); + + rCanvas->fillPolyPolygon( mxTextLines, + rViewState, + rRenderState ); + + rCanvas->drawTextLayout( mxTextLayout, + rViewState, + rRenderState ); + + return true; + } + + bool EffectTextArrayAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::EffectTextArrayAction::render()" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::EffectTextArrayAction: 0x%X", this ); + + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + return renderEffectText( *this, + aLocalState, + mpCanvas->getViewState(), + mpCanvas->getUNOCanvas(), + maShadowColor, + maShadowOffset, + maReliefColor, + maReliefOffset ); + } + + class EffectTextArrayRenderHelper : public TextRenderer + { + public: + EffectTextArrayRenderHelper( const uno::Reference< rendering::XCanvas >& rCanvas, + const uno::Reference< rendering::XTextLayout >& rTextLayout, + const uno::Reference< rendering::XPolyPolygon2D >& rLinePolygon, + const rendering::ViewState& rViewState ) : + mrCanvas( rCanvas ), + mrTextLayout( rTextLayout ), + mrLinePolygon( rLinePolygon ), + mrViewState( rViewState ) + { + } + + // TextRenderer interface + virtual bool operator()( const rendering::RenderState& rRenderState ) const + { + mrCanvas->fillPolyPolygon( mrLinePolygon, + mrViewState, + rRenderState ); + + mrCanvas->drawTextLayout( mrTextLayout, + mrViewState, + rRenderState ); + + return true; + } + + private: + const uno::Reference< rendering::XCanvas >& mrCanvas; + const uno::Reference< rendering::XTextLayout >& mrTextLayout; + const uno::Reference< rendering::XPolyPolygon2D >& mrLinePolygon; + const rendering::ViewState& mrViewState; + }; + + bool EffectTextArrayAction::render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::EffectTextArrayAction::render( subset )" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::EffectTextArrayAction: 0x%X", this ); + + rendering::RenderState aLocalState( maState ); + uno::Reference< rendering::XTextLayout > xTextLayout( mxTextLayout ); + const geometry::RealRectangle2D aTextBounds( mxTextLayout->queryTextBounds() ); + + double nMinPos(0.0); + double nMaxPos(aTextBounds.X2 - aTextBounds.X1); + + createSubsetLayout( xTextLayout, + aLocalState, + nMinPos, + nMaxPos, + rTransformation, + rSubset ); + + if( !xTextLayout.is() ) + return true; // empty layout, render nothing + + + // create and setup local line polygon + // =================================== + + uno::Reference< rendering::XCanvas > xCanvas( mpCanvas->getUNOCanvas() ); + const rendering::ViewState& rViewState( mpCanvas->getViewState() ); + + uno::Reference< rendering::XPolyPolygon2D > xTextLines( + ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + xCanvas->getDevice(), + tools::createTextLinesPolyPolygon( + 0.0, nMaxPos - nMinPos, + maTextLineInfo ) ) ); + + + // render everything + // ================= + + return renderEffectText( + EffectTextArrayRenderHelper( xCanvas, + xTextLayout, + xTextLines, + rViewState ), + aLocalState, + rViewState, + xCanvas, + maShadowColor, + maShadowOffset, + maReliefColor, + maReliefOffset ); + } + + ::basegfx::B2DRange EffectTextArrayAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + return calcEffectTextBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D( + mxTextLayout->queryTextBounds() ), + ::basegfx::B2DRange( 0,0, + maLinesOverallSize.getX(), + maLinesOverallSize.getY() ), + maReliefOffset, + maShadowOffset, + aLocalState, + mpCanvas->getViewState() ); + } + + ::basegfx::B2DRange EffectTextArrayAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::EffectTextArrayAction::getBounds( subset )" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::EffectTextArrayAction: 0x%X", this ); + + rendering::RenderState aLocalState( maState ); + uno::Reference< rendering::XTextLayout > xTextLayout( mxTextLayout ); + const geometry::RealRectangle2D aTextBounds( mxTextLayout->queryTextBounds() ); + + double nMinPos(0.0); + double nMaxPos(aTextBounds.X2 - aTextBounds.X1); + + createSubsetLayout( xTextLayout, + aLocalState, + nMinPos, + nMaxPos, + rTransformation, + rSubset ); + + if( !xTextLayout.is() ) + return ::basegfx::B2DRange(); // empty layout, empty bounds + + + // create and setup local line polygon + // =================================== + + const ::basegfx::B2DPolyPolygon aPoly( + tools::createTextLinesPolyPolygon( + 0.0, nMaxPos - nMinPos, + maTextLineInfo ) ); + + return calcEffectTextBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D( + xTextLayout->queryTextBounds() ), + ::basegfx::tools::getRange( aPoly ), + maReliefOffset, + maShadowOffset, + aLocalState, + mpCanvas->getViewState() ); + } + + sal_Int32 EffectTextArrayAction::getActionCount() const + { + const rendering::StringContext& rOrigContext( mxTextLayout->getText() ); + + return rOrigContext.Length; + } + + + // ------------------------------------------------------------------------- + + class OutlineAction : + public Action, + public TextRenderer, + private ::boost::noncopyable + { + public: + OutlineAction( const ::basegfx::B2DPoint& rStartPoint, + const ::basegfx::B2DSize& rReliefOffset, + const ::Color& rReliefColor, + const ::basegfx::B2DSize& rShadowOffset, + const ::Color& rShadowColor, + const ::basegfx::B2DRectangle& rOutlineBounds, + const uno::Reference< rendering::XPolyPolygon2D >& rTextPoly, + const ::std::vector< sal_Int32 >& rPolygonGlyphMap, + const uno::Sequence< double >& rOffsets, + VirtualDevice& rVDev, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ); + OutlineAction( const ::basegfx::B2DPoint& rStartPoint, + const ::basegfx::B2DSize& rReliefOffset, + const ::Color& rReliefColor, + const ::basegfx::B2DSize& rShadowOffset, + const ::Color& rShadowColor, + const ::basegfx::B2DRectangle& rOutlineBounds, + const uno::Reference< rendering::XPolyPolygon2D >& rTextPoly, + const ::std::vector< sal_Int32 >& rPolygonGlyphMap, + const uno::Sequence< double >& rOffsets, + VirtualDevice& rVDev, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const ::basegfx::B2DHomMatrix& rTextTransform ); + + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual sal_Int32 getActionCount() const; + + private: + // TextRenderer interface + virtual bool operator()( const rendering::RenderState& rRenderState ) const; + + // TODO(P2): This is potentially a real mass object + // (every character might be a separate TextAction), + // thus, make it as lightweight as possible. For + // example, share common RenderState among several + // TextActions, maybe using maOffsets for the + // translation. + + uno::Reference< rendering::XPolyPolygon2D > mxTextPoly; + + /** This vector denotes the index of the start polygon + for the respective glyph sequence. + + To get a polygon index range for a given character + index i, take [ maPolygonGlyphMap[i], + maPolygonGlyphMap[i+1] ). Note that this is wrong + for BiDi + */ + const ::std::vector< sal_Int32 > maPolygonGlyphMap; + const uno::Sequence< double > maOffsets; + const CanvasSharedPtr mpCanvas; + rendering::RenderState maState; + double mnOutlineWidth; + const uno::Sequence< double > maFillColor; + const tools::TextLineInfo maTextLineInfo; + ::basegfx::B2DSize maLinesOverallSize; + const ::basegfx::B2DRectangle maOutlineBounds; + uno::Reference< rendering::XPolyPolygon2D > mxTextLines; + const ::basegfx::B2DSize maReliefOffset; + const ::Color maReliefColor; + const ::basegfx::B2DSize maShadowOffset; + const ::Color maShadowColor; + }; + + double calcOutlineWidth( const OutDevState& rState, + VirtualDevice& rVDev ) + { + const ::basegfx::B2DSize aFontSize( 0, + rVDev.GetFont().GetHeight() / 64.0 ); + + const double nOutlineWidth( + (rState.mapModeTransform * aFontSize).getY() ); + + return nOutlineWidth < 1.0 ? 1.0 : nOutlineWidth; + } + + OutlineAction::OutlineAction( const ::basegfx::B2DPoint& rStartPoint, + const ::basegfx::B2DSize& rReliefOffset, + const ::Color& rReliefColor, + const ::basegfx::B2DSize& rShadowOffset, + const ::Color& rShadowColor, + const ::basegfx::B2DRectangle& rOutlineBounds, + const uno::Reference< rendering::XPolyPolygon2D >& rTextPoly, + const ::std::vector< sal_Int32 >& rPolygonGlyphMap, + const uno::Sequence< double >& rOffsets, + VirtualDevice& rVDev, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) : + mxTextPoly( rTextPoly ), + maPolygonGlyphMap( rPolygonGlyphMap ), + maOffsets( rOffsets ), + mpCanvas( rCanvas ), + maState(), + mnOutlineWidth( calcOutlineWidth(rState,rVDev) ), + maFillColor( + ::vcl::unotools::colorToDoubleSequence( + ::Color( COL_WHITE ), + rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() )), + maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ), + maLinesOverallSize(), + maOutlineBounds( rOutlineBounds ), + mxTextLines(), + maReliefOffset( rReliefOffset ), + maReliefColor( rReliefColor ), + maShadowOffset( rShadowOffset ), + maShadowColor( rShadowColor ) + { + initEffectLinePolyPolygon( maLinesOverallSize, + mxTextLines, + rCanvas, + rOffsets, + maTextLineInfo ); + + init( maState, + rStartPoint, + rState, + rCanvas ); + } + + OutlineAction::OutlineAction( const ::basegfx::B2DPoint& rStartPoint, + const ::basegfx::B2DSize& rReliefOffset, + const ::Color& rReliefColor, + const ::basegfx::B2DSize& rShadowOffset, + const ::Color& rShadowColor, + const ::basegfx::B2DRectangle& rOutlineBounds, + const uno::Reference< rendering::XPolyPolygon2D >& rTextPoly, + const ::std::vector< sal_Int32 >& rPolygonGlyphMap, + const uno::Sequence< double >& rOffsets, + VirtualDevice& rVDev, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const ::basegfx::B2DHomMatrix& rTextTransform ) : + mxTextPoly( rTextPoly ), + maPolygonGlyphMap( rPolygonGlyphMap ), + maOffsets( rOffsets ), + mpCanvas( rCanvas ), + maState(), + mnOutlineWidth( calcOutlineWidth(rState,rVDev) ), + maFillColor( + ::vcl::unotools::colorToDoubleSequence( + ::Color( COL_WHITE ), + rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() )), + maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ), + maLinesOverallSize(), + maOutlineBounds( rOutlineBounds ), + mxTextLines(), + maReliefOffset( rReliefOffset ), + maReliefColor( rReliefColor ), + maShadowOffset( rShadowOffset ), + maShadowColor( rShadowColor ) + { + initEffectLinePolyPolygon( maLinesOverallSize, + mxTextLines, + rCanvas, + rOffsets, + maTextLineInfo ); + + init( maState, + rStartPoint, + rState, + rCanvas, + rTextTransform ); + } + + bool OutlineAction::operator()( const rendering::RenderState& rRenderState ) const + { + const rendering::ViewState& rViewState( mpCanvas->getViewState() ); + const uno::Reference< rendering::XCanvas >& rCanvas( mpCanvas->getUNOCanvas() ); + + rendering::StrokeAttributes aStrokeAttributes; + + aStrokeAttributes.StrokeWidth = mnOutlineWidth; + aStrokeAttributes.MiterLimit = 1.0; + aStrokeAttributes.StartCapType = rendering::PathCapType::BUTT; + aStrokeAttributes.EndCapType = rendering::PathCapType::BUTT; + aStrokeAttributes.JoinType = rendering::PathJoinType::MITER; + + rendering::RenderState aLocalState( rRenderState ); + aLocalState.DeviceColor = maFillColor; + + // TODO(P1): implement caching + + // background of text + rCanvas->fillPolyPolygon( mxTextPoly, + rViewState, + aLocalState ); + + // border line of text + rCanvas->strokePolyPolygon( mxTextPoly, + rViewState, + rRenderState, + aStrokeAttributes ); + + // underlines/strikethrough - background + rCanvas->fillPolyPolygon( mxTextLines, + rViewState, + aLocalState ); + // underlines/strikethrough - border + rCanvas->strokePolyPolygon( mxTextLines, + rViewState, + rRenderState, + aStrokeAttributes ); + + return true; + } + + bool OutlineAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::EffectTextArrayAction::render()" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::EffectTextArrayAction: 0x%X", this ); + + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + return renderEffectText( *this, + aLocalState, + mpCanvas->getViewState(), + mpCanvas->getUNOCanvas(), + maShadowColor, + maShadowOffset, + maReliefColor, + maReliefOffset ); + } + + class OutlineTextArrayRenderHelper : public TextRenderer + { + public: + OutlineTextArrayRenderHelper( const uno::Reference< rendering::XCanvas >& rCanvas, + const uno::Reference< rendering::XPolyPolygon2D >& rTextPolygon, + const uno::Reference< rendering::XPolyPolygon2D >& rLinePolygon, + const rendering::ViewState& rViewState, + double nOutlineWidth ) : + maFillColor( + ::vcl::unotools::colorToDoubleSequence( + ::Color( COL_WHITE ), + rCanvas->getDevice()->getDeviceColorSpace() )), + mnOutlineWidth( nOutlineWidth ), + mrCanvas( rCanvas ), + mrTextPolygon( rTextPolygon ), + mrLinePolygon( rLinePolygon ), + mrViewState( rViewState ) + { + } + + // TextRenderer interface + virtual bool operator()( const rendering::RenderState& rRenderState ) const + { + rendering::StrokeAttributes aStrokeAttributes; + + aStrokeAttributes.StrokeWidth = mnOutlineWidth; + aStrokeAttributes.MiterLimit = 1.0; + aStrokeAttributes.StartCapType = rendering::PathCapType::BUTT; + aStrokeAttributes.EndCapType = rendering::PathCapType::BUTT; + aStrokeAttributes.JoinType = rendering::PathJoinType::MITER; + + rendering::RenderState aLocalState( rRenderState ); + aLocalState.DeviceColor = maFillColor; + + // TODO(P1): implement caching + + // background of text + mrCanvas->fillPolyPolygon( mrTextPolygon, + mrViewState, + aLocalState ); + + // border line of text + mrCanvas->strokePolyPolygon( mrTextPolygon, + mrViewState, + rRenderState, + aStrokeAttributes ); + + // underlines/strikethrough - background + mrCanvas->fillPolyPolygon( mrLinePolygon, + mrViewState, + aLocalState ); + // underlines/strikethrough - border + mrCanvas->strokePolyPolygon( mrLinePolygon, + mrViewState, + rRenderState, + aStrokeAttributes ); + + return true; + } + + private: + const uno::Sequence< double > maFillColor; + double mnOutlineWidth; + const uno::Reference< rendering::XCanvas >& mrCanvas; + const uno::Reference< rendering::XPolyPolygon2D >& mrTextPolygon; + const uno::Reference< rendering::XPolyPolygon2D >& mrLinePolygon; + const rendering::ViewState& mrViewState; + }; + + bool OutlineAction::render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::OutlineAction::render( subset )" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::OutlineAction: 0x%X", this ); + + if( rSubset.mnSubsetBegin == rSubset.mnSubsetEnd ) + return true; // empty range, render nothing + +#if 1 + // TODO(F3): Subsetting NYI for outline text! + return render( rTransformation ); +#else + const rendering::StringContext rOrigContext( mxTextLayout->getText() ); + + if( rSubset.mnSubsetBegin == 0 && + rSubset.mnSubsetEnd == rOrigContext.Length ) + { + // full range, no need for subsetting + return render( rTransformation ); + } + + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + + // create and setup local Text polygon + // =================================== + + uno::Reference< rendering::XPolyPolygon2D > xTextPolygon(); + + // TODO(P3): Provide an API method for that! + + if( !xTextLayout.is() ) + return false; + + // render everything + // ================= + + return renderEffectText( + OutlineTextArrayRenderHelper( + xCanvas, + mnOutlineWidth, + xTextLayout, + xTextLines, + rViewState ), + aLocalState, + rViewState, + xCanvas, + maShadowColor, + maShadowOffset, + maReliefColor, + maReliefOffset ); +#endif + } + + ::basegfx::B2DRange OutlineAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + return calcEffectTextBounds( maOutlineBounds, + ::basegfx::B2DRange( 0,0, + maLinesOverallSize.getX(), + maLinesOverallSize.getY() ), + maReliefOffset, + maShadowOffset, + aLocalState, + mpCanvas->getViewState() ); + } + + ::basegfx::B2DRange OutlineAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& /*rSubset*/ ) const + { + OSL_FAIL( "OutlineAction::getBounds(): Subset not yet supported by this object" ); + + return getBounds( rTransformation ); + } + + sal_Int32 OutlineAction::getActionCount() const + { + // TODO(F3): Subsetting NYI for outline text! + return maOffsets.getLength(); + } + + + // ====================================================================== + // + // Action factory methods + // + // ====================================================================== + + /** Create an outline action + + This method extracts the polygonal outline from the + text, and creates a properly setup OutlineAction from + it. + */ + ActionSharedPtr createOutline( const ::basegfx::B2DPoint& rStartPoint, + const ::basegfx::B2DSize& rReliefOffset, + const ::Color& rReliefColor, + const ::basegfx::B2DSize& rShadowOffset, + const ::Color& rShadowColor, + const String& rText, + sal_Int32 nStartPos, + sal_Int32 nLen, + const sal_Int32* pDXArray, + VirtualDevice& rVDev, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const Renderer::Parameters& rParms ) + { + // operate on raw DX array here (in logical coordinate + // system), to have a higher resolution + // PolyPolygon. That polygon is then converted to + // device coordinate system. + + // #i68512# Temporarily switch off font rotation + // (which is already contained in the render state + // transformation matrix - otherwise, glyph polygons + // will be rotated twice) + const ::Font aOrigFont( rVDev.GetFont() ); + ::Font aUnrotatedFont( aOrigFont ); + aUnrotatedFont.SetOrientation(0); + rVDev.SetFont( aUnrotatedFont ); + + // TODO(F3): Don't understand parameter semantics of + // GetTextOutlines() + ::basegfx::B2DPolyPolygon aResultingPolyPolygon; + PolyPolyVector aVCLPolyPolyVector; + const bool bHaveOutlines( rVDev.GetTextOutlines( aVCLPolyPolyVector, rText, + static_cast<sal_uInt16>(nStartPos), + static_cast<sal_uInt16>(nStartPos), + static_cast<sal_uInt16>(nLen), + sal_True, 0, pDXArray ) ); + rVDev.SetFont(aOrigFont); + + if( !bHaveOutlines ) + return ActionSharedPtr(); + + ::std::vector< sal_Int32 > aPolygonGlyphMap; + + // first glyph starts at polygon index 0 + aPolygonGlyphMap.push_back( 0 ); + + // remove offsetting from mapmode transformation + // (outline polygons must stay at origin, only need to + // be scaled) + ::basegfx::B2DHomMatrix aMapModeTransform( + rState.mapModeTransform ); + aMapModeTransform.set(0,2, 0.0); + aMapModeTransform.set(1,2, 0.0); + + PolyPolyVector::const_iterator aIter( aVCLPolyPolyVector.begin() ); + const PolyPolyVector::const_iterator aEnd( aVCLPolyPolyVector.end() ); + for( ; aIter!= aEnd; ++aIter ) + { + ::basegfx::B2DPolyPolygon aPolyPolygon; + + aPolyPolygon = aIter->getB2DPolyPolygon(); + aPolyPolygon.transform( aMapModeTransform ); + + // append result to collecting polypoly + for( sal_uInt32 i=0; i<aPolyPolygon.count(); ++i ) + { + // #i47795# Ensure closed polygons (since + // FreeType returns the glyph outlines + // open) + const ::basegfx::B2DPolygon& rPoly( aPolyPolygon.getB2DPolygon( i ) ); + const sal_uInt32 nCount( rPoly.count() ); + if( nCount<3 || + rPoly.isClosed() ) + { + // polygon either degenerate, or + // already closed. + aResultingPolyPolygon.append( rPoly ); + } + else + { + ::basegfx::B2DPolygon aPoly(rPoly); + aPoly.setClosed(true); + + aResultingPolyPolygon.append( aPoly ); + } + } + + // TODO(F3): Depending on the semantics of + // GetTextOutlines(), this here is wrong! + + // calc next glyph index + aPolygonGlyphMap.push_back( aResultingPolyPolygon.count() ); + } + + const uno::Sequence< double > aCharWidthSeq( + pDXArray ? + setupDXArray( pDXArray, nLen, rState ) : + setupDXArray( rText, + nStartPos, + nLen, + rVDev, + rState )); + const uno::Reference< rendering::XPolyPolygon2D > xTextPoly( + ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + rCanvas->getUNOCanvas()->getDevice(), + aResultingPolyPolygon ) ); + + if( rParms.maTextTransformation.is_initialized() ) + { + return ActionSharedPtr( + new OutlineAction( + rStartPoint, + rReliefOffset, + rReliefColor, + rShadowOffset, + rShadowColor, + ::basegfx::tools::getRange(aResultingPolyPolygon), + xTextPoly, + aPolygonGlyphMap, + aCharWidthSeq, + rVDev, + rCanvas, + rState, + *rParms.maTextTransformation ) ); + } + else + { + return ActionSharedPtr( + new OutlineAction( + rStartPoint, + rReliefOffset, + rReliefColor, + rShadowOffset, + rShadowColor, + ::basegfx::tools::getRange(aResultingPolyPolygon), + xTextPoly, + aPolygonGlyphMap, + aCharWidthSeq, + rVDev, + rCanvas, + rState ) ); + } + } + + } // namespace + + + // --------------------------------------------------------------------------------- + + ActionSharedPtr TextActionFactory::createTextAction( const ::Point& rStartPoint, + const ::Size& rReliefOffset, + const ::Color& rReliefColor, + const ::Size& rShadowOffset, + const ::Color& rShadowColor, + const String& rText, + sal_Int32 nStartPos, + sal_Int32 nLen, + const sal_Int32* pDXArray, + VirtualDevice& rVDev, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const Renderer::Parameters& rParms, + bool bSubsettable ) + { + const ::Size aBaselineOffset( tools::getBaselineOffset( rState, + rVDev ) ); + // #143885# maintain (nearly) full precision positioning, + // by circumventing integer-based OutDev-mapping + const ::basegfx::B2DPoint aStartPoint( + rState.mapModeTransform * + ::basegfx::B2DPoint(rStartPoint.X() + aBaselineOffset.Width(), + rStartPoint.Y() + aBaselineOffset.Height()) ); + + const ::basegfx::B2DSize aReliefOffset( + rState.mapModeTransform * ::vcl::unotools::b2DSizeFromSize( rReliefOffset ) ); + const ::basegfx::B2DSize aShadowOffset( + rState.mapModeTransform * ::vcl::unotools::b2DSizeFromSize( rShadowOffset ) ); + + if( rState.isTextOutlineModeSet ) + { + return createOutline( + aStartPoint, + aReliefOffset, + rReliefColor, + aShadowOffset, + rShadowColor, + rText, + nStartPos, + nLen, + pDXArray, + rVDev, + rCanvas, + rState, + rParms ); + } + + // convert DX array to device coordinate system (and + // create it in the first place, if pDXArray is NULL) + const uno::Sequence< double > aCharWidths( + pDXArray ? + setupDXArray( pDXArray, nLen, rState ) : + setupDXArray( rText, + nStartPos, + nLen, + rVDev, + rState )); + + // determine type of text action to create + // ======================================= + + const ::Color aEmptyColor( COL_AUTO ); + + // no DX array, and no need to subset - no need to store + // DX array, then. + if( !pDXArray && !bSubsettable ) + { + // effects, or not? + if( !rState.textOverlineStyle && + !rState.textUnderlineStyle && + !rState.textStrikeoutStyle && + rReliefColor == aEmptyColor && + rShadowColor == aEmptyColor ) + { + // nope + if( rParms.maTextTransformation.is_initialized() ) + { + return ActionSharedPtr( new TextAction( + aStartPoint, + rText, + nStartPos, + nLen, + rCanvas, + rState, + *rParms.maTextTransformation ) ); + } + else + { + return ActionSharedPtr( new TextAction( + aStartPoint, + rText, + nStartPos, + nLen, + rCanvas, + rState ) ); + } + } + else + { + // at least one of the effects requested + if( rParms.maTextTransformation.is_initialized() ) + return ActionSharedPtr( new EffectTextAction( + aStartPoint, + aReliefOffset, + rReliefColor, + aShadowOffset, + rShadowColor, + rText, + nStartPos, + nLen, + rVDev, + rCanvas, + rState, + *rParms.maTextTransformation ) ); + else + return ActionSharedPtr( new EffectTextAction( + aStartPoint, + aReliefOffset, + rReliefColor, + aShadowOffset, + rShadowColor, + rText, + nStartPos, + nLen, + rVDev, + rCanvas, + rState ) ); + } + } + else + { + // DX array necessary - any effects? + if( !rState.textOverlineStyle && + !rState.textUnderlineStyle && + !rState.textStrikeoutStyle && + rReliefColor == aEmptyColor && + rShadowColor == aEmptyColor ) + { + // nope + if( rParms.maTextTransformation.is_initialized() ) + return ActionSharedPtr( new TextArrayAction( + aStartPoint, + rText, + nStartPos, + nLen, + aCharWidths, + rCanvas, + rState, + *rParms.maTextTransformation ) ); + else + return ActionSharedPtr( new TextArrayAction( + aStartPoint, + rText, + nStartPos, + nLen, + aCharWidths, + rCanvas, + rState ) ); + } + else + { + // at least one of the effects requested + if( rParms.maTextTransformation.is_initialized() ) + return ActionSharedPtr( new EffectTextArrayAction( + aStartPoint, + aReliefOffset, + rReliefColor, + aShadowOffset, + rShadowColor, + rText, + nStartPos, + nLen, + aCharWidths, + rVDev, + rCanvas, + rState, + *rParms.maTextTransformation ) ); + else + return ActionSharedPtr( new EffectTextArrayAction( + aStartPoint, + aReliefOffset, + rReliefColor, + aShadowOffset, + rShadowColor, + rText, + nStartPos, + nLen, + aCharWidths, + rVDev, + rCanvas, + rState ) ); + } + } +#if defined __GNUC__ +#if __GNUC__ == 4 && __GNUC_MINOR__ >= 1 + // Unreachable; to avoid bogus warning: + return ActionSharedPtr(); +#endif +#endif + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/mtfrenderer/textaction.hxx b/cppcanvas/source/mtfrenderer/textaction.hxx new file mode 100644 index 000000000000..390752d23ce1 --- /dev/null +++ b/cppcanvas/source/mtfrenderer/textaction.hxx @@ -0,0 +1,105 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_TEXTACTION_HXX +#define _CPPCANVAS_TEXTACTION_HXX + +#include <com/sun/star/uno/Sequence.hxx> + +#include <action.hxx> +#include <cppcanvas/canvas.hxx> +#include <cppcanvas/renderer.hxx> +#include <tools/poly.hxx> +#include <tools/gen.hxx> + +class VirtualDevice; +class Point; +class Color; +class String; + + +/* Definition of internal::TextActionFactory class */ + +namespace cppcanvas +{ + namespace internal + { + struct OutDevState; + + /** Creates encapsulated converters between GDIMetaFile and + XCanvas. The Canvas argument is deliberately placed at the + constructor, to force reconstruction of this object for a + new canvas. This considerably eases internal state + handling, since a lot of the internal state (e.g. fonts, + text layout) is Canvas-dependent. + */ + class TextActionFactory + { + public: + /** Create text action, optionally shadow/relief effect + + Note that this method accepts all coordinates in + logical coordinates. + + @param pDXArray + Pointer to array of logical character offsets (or NULL) + + @param bSubsettable + When this parameter is set to true, the generated + action might consume slightly more memory, but is + subsettable (Action::render( Subset ) works on + characters) + */ + static ActionSharedPtr createTextAction( const ::Point& rStartPoint, + const ::Size& rReliefOffset, + const ::Color& rReliefColor, + const ::Size& rShadowOffset, + const ::Color& rShadowColor, + const ::String& rText, + sal_Int32 nStartPos, + sal_Int32 nLen, + const sal_Int32* pDXArray, + VirtualDevice& rVDev, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const Renderer::Parameters& rParms, + bool bSubsettable ); + + private: + // static factory, disable big four + TextActionFactory(); + ~TextActionFactory(); + TextActionFactory(const TextActionFactory&); + TextActionFactory& operator=( const TextActionFactory& ); + }; + } +} + +#endif /* _CPPCANVAS_TEXTACTION_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/mtfrenderer/transparencygroupaction.cxx b/cppcanvas/source/mtfrenderer/transparencygroupaction.cxx new file mode 100644 index 000000000000..482b2a430dc1 --- /dev/null +++ b/cppcanvas/source/mtfrenderer/transparencygroupaction.cxx @@ -0,0 +1,579 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cppcanvas.hxx" + +#include <tools/gen.hxx> + +#include <canvas/debug.hxx> +#include <canvas/verbosetrace.hxx> +#include <canvas/canvastools.hxx> + +#include <rtl/logfile.hxx> + +#include <com/sun/star/rendering/XBitmap.hpp> +#include <com/sun/star/rendering/XCanvas.hpp> + +#include <rtl/math.hxx> + +#include <vcl/metaact.hxx> +#include <vcl/bitmapex.hxx> +#include <vcl/canvastools.hxx> +#include <vcl/svapp.hxx> +#include <vcl/outdev.hxx> +#include <vcl/virdev.hxx> +#include <vcl/virdev.hxx> +#include <vcl/gdimtf.hxx> +#include <vcl/gradient.hxx> + +#include <canvas/canvastools.hxx> + +#include <basegfx/range/b2drange.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/vector/b2dsize.hxx> +#include <basegfx/numeric/ftools.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/tuple/b2dtuple.hxx> +#include <basegfx/tools/canvastools.hxx> + +#include <boost/utility.hpp> + +#include "transparencygroupaction.hxx" +#include "outdevstate.hxx" +#include "mtftools.hxx" +#include "cppcanvas/vclfactory.hxx" + + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace internal + { + // free support functions + // ====================== + namespace + { + class TransparencyGroupAction : public Action, private ::boost::noncopyable + { + public: + /** Create new transparency group action. + + @param rGroupMtf + Metafile that groups all actions to be rendered + transparent + + @param rParms + Render parameters + + @param rDstPoint + Left, top edge of destination, in current state + coordinate system + + @param rDstSize + Size of the transparency group object, in current + state coordinate system. + + @param nAlpha + Alpha value, must be in the range [0,1] + */ + TransparencyGroupAction( MtfAutoPtr& rGroupMtf, + const Renderer::Parameters& rParms, + const ::basegfx::B2DPoint& rDstPoint, + const ::basegfx::B2DVector& rDstSize, + double nAlpha, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ); + + /** Create new transparency group action. + + @param rGroupMtf + Metafile that groups all actions to be rendered + transparent. + + @param rAlphaGradient + VCL gradient, to be rendered into the action's alpha + channel. + + @param rParms + Render parameters + + @param rDstPoint + Left, top edge of destination, in current state + coordinate system + + @param rDstSize + Size of the transparency group object, in current + state coordinate system. + */ + TransparencyGroupAction( MtfAutoPtr& rGroupMtf, + GradientAutoPtr& rAlphaGradient, + const Renderer::Parameters& rParms, + const ::basegfx::B2DPoint& rDstPoint, + const ::basegfx::B2DVector& rDstSize, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ); + + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual sal_Int32 getActionCount() const; + + private: + MtfAutoPtr mpGroupMtf; + GradientAutoPtr mpAlphaGradient; + + const Renderer::Parameters maParms; + + const ::basegfx::B2DSize maDstSize; + + mutable uno::Reference< rendering::XBitmap > mxBufferBitmap; // contains last rendered version + mutable ::basegfx::B2DHomMatrix maLastTransformation; // contains last active transformation + mutable Subset maLastSubset; // contains last effective subset + + // transformation for + // mxBufferBitmap content + CanvasSharedPtr mpCanvas; + rendering::RenderState maState; + const double mnAlpha; + }; + + + /** Setup transformation such that the next render call is + moved rPoint away, and scaled according to the ratio + given by src and dst size. + */ + void implSetupTransform( rendering::RenderState& rRenderState, + const ::basegfx::B2DPoint& rDstPoint ) + { + ::basegfx::B2DHomMatrix aLocalTransformation; + + aLocalTransformation.translate( rDstPoint.getX(), + rDstPoint.getY() ); + ::canvas::tools::appendToRenderState( rRenderState, + aLocalTransformation ); + } + + TransparencyGroupAction::TransparencyGroupAction( MtfAutoPtr& rGroupMtf, + const Renderer::Parameters& rParms, + const ::basegfx::B2DPoint& rDstPoint, + const ::basegfx::B2DVector& rDstSize, + double nAlpha, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) : + mpGroupMtf( rGroupMtf ), + mpAlphaGradient(), + maParms( rParms ), + maDstSize( rDstSize ), + mxBufferBitmap(), + maLastTransformation(), + mpCanvas( rCanvas ), + maState(), + mnAlpha( nAlpha ) + { + tools::initRenderState(maState,rState); + implSetupTransform( maState, rDstPoint ); + + // correct clip (which is relative to original transform) + tools::modifyClip( maState, + rState, + rCanvas, + rDstPoint, + NULL, + NULL ); + + maLastSubset.mnSubsetBegin = 0; + maLastSubset.mnSubsetEnd = -1; + } + + TransparencyGroupAction::TransparencyGroupAction( MtfAutoPtr& rGroupMtf, + GradientAutoPtr& rAlphaGradient, + const Renderer::Parameters& rParms, + const ::basegfx::B2DPoint& rDstPoint, + const ::basegfx::B2DVector& rDstSize, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) : + mpGroupMtf( rGroupMtf ), + mpAlphaGradient( rAlphaGradient ), + maParms( rParms ), + maDstSize( rDstSize ), + mxBufferBitmap(), + maLastTransformation(), + mpCanvas( rCanvas ), + maState(), + mnAlpha( 1.0 ) + { + tools::initRenderState(maState,rState); + implSetupTransform( maState, rDstPoint ); + + // correct clip (which is relative to original transform) + tools::modifyClip( maState, + rState, + rCanvas, + rDstPoint, + NULL, + NULL ); + + maLastSubset.mnSubsetBegin = 0; + maLastSubset.mnSubsetEnd = -1; + } + + // TODO(P3): The whole float transparency handling is a mess, + // this should be refactored. What's more, the old idea of + // having only internal 'metaactions', and not the original + // GDIMetaFile now looks a lot less attractive. Try to move + // into the direction of having a direct GDIMetaFile2XCanvas + // renderer, and maybe a separate metafile XCanvas + // implementation. + bool TransparencyGroupAction::render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::TransparencyGroupAction::render()" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::TransparencyGroupAction: 0x%X", this ); + + // determine overall transformation matrix (render, view, + // and passed transformation) + ::basegfx::B2DHomMatrix aTransform; + ::canvas::tools::getRenderStateTransform( aTransform, maState ); + aTransform = rTransformation * aTransform; + + ::basegfx::B2DHomMatrix aTotalTransform; + ::canvas::tools::getViewStateTransform( aTotalTransform, mpCanvas->getViewState() ); + aTotalTransform = aTotalTransform * aTransform; + + // since pure translational changes to the transformation + // does not matter, remove them before comparing + aTotalTransform.set( 0, 2, 0.0 ); + aTotalTransform.set( 1, 2, 0.0 ); + + // if there's no buffer bitmap, or as soon as the + // total transformation changes, we've got to + // re-render the bitmap + if( !mxBufferBitmap.is() || + aTotalTransform != maLastTransformation || + rSubset.mnSubsetBegin != maLastSubset.mnSubsetBegin || + rSubset.mnSubsetEnd != maLastSubset.mnSubsetEnd ) + { + DBG_TESTSOLARMUTEX(); + + // determine total scaling factor of the + // transformation matrix - need to make the bitmap + // large enough + ::basegfx::B2DTuple aScale; + ::basegfx::B2DTuple aTranslate; + double nRotate; + double nShearX; + if( !aTotalTransform.decompose( aScale, + aTranslate, + nRotate, + nShearX ) ) + { + OSL_FAIL( "TransparencyGroupAction::render(): non-decomposable transformation" ); + return false; + } + + // output size of metafile + ::Size aOutputSizePixel( ::basegfx::fround( aScale.getX() * maDstSize.getX() ), + ::basegfx::fround( aScale.getY() * maDstSize.getY() ) ); + + // pixel size of cache bitmap: round up to nearest int + ::Size aBitmapSizePixel( static_cast<sal_Int32>( aScale.getX() * maDstSize.getX() )+1, + static_cast<sal_Int32>( aScale.getY() * maDstSize.getY() )+1 ); + + ::Point aEmptyPoint; + + // render our content into an appropriately sized + // VirtualDevice with alpha channel + VirtualDevice aVDev( + *::Application::GetDefaultDevice(), 0, 0 ); + aVDev.SetOutputSizePixel( aBitmapSizePixel ); + aVDev.SetMapMode(); + + if( rSubset.mnSubsetBegin != 0 || + rSubset.mnSubsetEnd != -1 ) + { + // true subset - extract referenced + // metaactions from mpGroupMtf + GDIMetaFile aMtf; + MetaAction* pCurrAct; + int nCurrActionIndex; + + // extract subset actions + for( nCurrActionIndex=0, + pCurrAct=mpGroupMtf->FirstAction(); + pCurrAct; + ++nCurrActionIndex, pCurrAct = mpGroupMtf->NextAction() ) + { + switch( pCurrAct->GetType() ) + { + case META_PUSH_ACTION: + case META_POP_ACTION: + case META_CLIPREGION_ACTION: + case META_ISECTRECTCLIPREGION_ACTION: + case META_ISECTREGIONCLIPREGION_ACTION: + case META_MOVECLIPREGION_ACTION: + case META_LINECOLOR_ACTION: + case META_FILLCOLOR_ACTION: + case META_TEXTCOLOR_ACTION: + case META_TEXTFILLCOLOR_ACTION: + case META_TEXTLINECOLOR_ACTION: + case META_TEXTALIGN_ACTION: + case META_FONT_ACTION: + case META_RASTEROP_ACTION: + case META_REFPOINT_ACTION: + case META_LAYOUTMODE_ACTION: + // state-changing action - copy as-is + aMtf.AddAction( pCurrAct->Clone() ); + break; + + case META_GRADIENT_ACTION: + case META_HATCH_ACTION: + case META_EPS_ACTION: + case META_COMMENT_ACTION: + case META_POINT_ACTION: + case META_PIXEL_ACTION: + case META_LINE_ACTION: + case META_RECT_ACTION: + case META_ROUNDRECT_ACTION: + case META_ELLIPSE_ACTION: + case META_ARC_ACTION: + case META_PIE_ACTION: + case META_CHORD_ACTION: + case META_POLYLINE_ACTION: + case META_POLYGON_ACTION: + case META_POLYPOLYGON_ACTION: + case META_BMP_ACTION: + case META_BMPSCALE_ACTION: + case META_BMPSCALEPART_ACTION: + case META_BMPEX_ACTION: + case META_BMPEXSCALE_ACTION: + case META_BMPEXSCALEPART_ACTION: + case META_MASK_ACTION: + case META_MASKSCALE_ACTION: + case META_MASKSCALEPART_ACTION: + case META_GRADIENTEX_ACTION: + case META_WALLPAPER_ACTION: + case META_TRANSPARENT_ACTION: + case META_FLOATTRANSPARENT_ACTION: + case META_TEXT_ACTION: + case META_TEXTARRAY_ACTION: + case META_TEXTLINE_ACTION: + case META_TEXTRECT_ACTION: + case META_STRETCHTEXT_ACTION: + case META_RENDERGRAPHIC_ACTION: + // output-generating action - only + // copy, if we're within the + // requested subset + if( rSubset.mnSubsetBegin <= nCurrActionIndex && + rSubset.mnSubsetEnd > nCurrActionIndex ) + { + aMtf.AddAction( pCurrAct->Clone() ); + } + break; + + default: + OSL_FAIL( "Unknown meta action type encountered" ); + break; + } + } + + aVDev.DrawTransparent( aMtf, + aEmptyPoint, + aOutputSizePixel, + *mpAlphaGradient ); + } + else + { + // no subsetting - render whole mtf + aVDev.DrawTransparent( *mpGroupMtf, + aEmptyPoint, + aOutputSizePixel, + *mpAlphaGradient ); + } + + + // update buffered bitmap and transformation + BitmapSharedPtr aBmp( VCLFactory::getInstance().createBitmap( + mpCanvas, + aVDev.GetBitmapEx( + aEmptyPoint, + aBitmapSizePixel ) ) ); + mxBufferBitmap = aBmp->getUNOBitmap(); + maLastTransformation = aTotalTransform; + maLastSubset = rSubset; + } + + // determine target transformation (we can't simply pass + // aTotalTransform as assembled above, since we must take + // the canvas' view state as is, it might contain clipping + // (which, in turn, is relative to the view + // transformation)) + + // given that aTotalTransform is the identity + // transformation, we could simply render our bitmap + // as-is. Now, since the mxBufferBitmap content already + // accounts for scale changes in the overall + // transformation, we must factor this out + // before. Generally, the transformation matrix should be + // structured like this: + // Translation*Rotation*Shear*Scale. Thus, to neutralize + // the contained scaling, we've got to right-multiply with + // the inverse. + ::basegfx::B2ISize aBmpSize( + ::basegfx::unotools::b2ISizeFromIntegerSize2D( mxBufferBitmap->getSize() ) ); + + ::basegfx::B2DHomMatrix aScaleCorrection; + aScaleCorrection.scale( (double)maDstSize.getX() / aBmpSize.getX(), + (double)maDstSize.getY() / aBmpSize.getY() ); + aTransform = aTransform * aScaleCorrection; + + rendering::RenderState aLocalState( maState ); + ::canvas::tools::setRenderStateTransform(aLocalState, aTransform); + + if( ::rtl::math::approxEqual(mnAlpha, 1.0) ) + { + // no further alpha changes necessary -> draw directly + mpCanvas->getUNOCanvas()->drawBitmap( mxBufferBitmap, + mpCanvas->getViewState(), + aLocalState ); + } + else + { + // add alpha modulation value to DeviceColor + uno::Sequence<rendering::ARGBColor> aCols(1); + aCols[0] = rendering::ARGBColor( mnAlpha, 1.0, 1.0, 1.0); + aLocalState.DeviceColor = + mpCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace()->convertFromARGB( + aCols); + + mpCanvas->getUNOCanvas()->drawBitmapModulated( mxBufferBitmap, + mpCanvas->getViewState(), + aLocalState ); + } + + return true; + } + + // TODO(P3): The whole float transparency handling is a mess, + // this should be refactored. What's more, the old idea of + // having only internal 'metaactions', and not the original + // GDIMetaFile now looks a lot less attractive. Try to move + // into the direction of having a direct GDIMetaFile2XCanvas + // renderer, and maybe a separate metafile XCanvas + // implementation. + bool TransparencyGroupAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + Subset aSubset; + + aSubset.mnSubsetBegin = 0; + aSubset.mnSubsetEnd = -1; + + return render( rTransformation, aSubset ); + } + + ::basegfx::B2DRange TransparencyGroupAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + return tools::calcDevicePixelBounds( + ::basegfx::B2DRange( 0,0, + maDstSize.getX(), + maDstSize.getY() ), + mpCanvas->getViewState(), + aLocalState ); + } + + ::basegfx::B2DRange TransparencyGroupAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + // TODO(F3): Currently, the bounds for + // TransparencyGroupAction subsets equal those of the + // full set, although this action is able to render + // true subsets. + + // polygon only contains a single action, empty bounds + // if subset requests different range + if( rSubset.mnSubsetBegin != 0 || + rSubset.mnSubsetEnd != 1 ) + return ::basegfx::B2DRange(); + + return getBounds( rTransformation ); + } + + sal_Int32 TransparencyGroupAction::getActionCount() const + { + return mpGroupMtf.get() ? mpGroupMtf->GetActionSize() : 0; + } + + } + + ActionSharedPtr TransparencyGroupActionFactory::createTransparencyGroupAction( MtfAutoPtr& rGroupMtf, + const Renderer::Parameters& rParms, + const ::basegfx::B2DPoint& rDstPoint, + const ::basegfx::B2DVector& rDstSize, + double nAlpha, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) + { + return ActionSharedPtr( new TransparencyGroupAction(rGroupMtf, + rParms, + rDstPoint, + rDstSize, + nAlpha, + rCanvas, + rState ) ); + } + + ActionSharedPtr TransparencyGroupActionFactory::createTransparencyGroupAction( MtfAutoPtr& rGroupMtf, + GradientAutoPtr& rAlphaGradient, + const Renderer::Parameters& rParms, + const ::basegfx::B2DPoint& rDstPoint, + const ::basegfx::B2DVector& rDstSize, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) + { + return ActionSharedPtr( new TransparencyGroupAction(rGroupMtf, + rAlphaGradient, + rParms, + rDstPoint, + rDstSize, + rCanvas, + rState ) ); + } + + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/mtfrenderer/transparencygroupaction.hxx b/cppcanvas/source/mtfrenderer/transparencygroupaction.hxx new file mode 100644 index 000000000000..dd629011cfa2 --- /dev/null +++ b/cppcanvas/source/mtfrenderer/transparencygroupaction.hxx @@ -0,0 +1,143 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_TRANSPARENCYGROUPACTION_HXX +#define _CPPCANVAS_TRANSPARENCYGROUPACTION_HXX + +#include <cppcanvas/canvas.hxx> +#include <cppcanvas/renderer.hxx> +#include <action.hxx> + +#include <memory> // auto_ptr + +namespace basegfx { + class B2DPoint; + class B2DVector; +} + +class GDIMetaFile; +class Gradient; + + +/* Definition of internal::TransparencyGroupActionFactory class */ + +namespace cppcanvas +{ + namespace internal + { + struct OutDevState; + + typedef ::std::auto_ptr< GDIMetaFile > MtfAutoPtr; + typedef ::std::auto_ptr< Gradient > GradientAutoPtr; + + /** Transparency group action. + + This action groups a bunch of other actions, to be + rendered with the given transparency setting against the + background. + + Creates encapsulated converters between GDIMetaFile and + XCanvas. The Canvas argument is deliberately placed at the + constructor, to force reconstruction of this object for a + new canvas. This considerably eases internal state + handling, since a lot of the internal state (e.g. fonts, + text layout) is Canvas-dependent. + */ + class TransparencyGroupActionFactory + { + public: + /** Create new transparency group action. + + @param rGroupMtf + Metafile that groups all actions to be rendered + transparent + + @param rParms + Render parameters + + @param rDstPoint + Left, top edge of destination, in current state + coordinate system + + @param rDstSize + Size of the transparency group object, in current + state coordinate system. + + @param nAlpha + Alpha value, must be in the range [0,1] + */ + static ActionSharedPtr createTransparencyGroupAction( MtfAutoPtr& rGroupMtf, + const Renderer::Parameters& rParms, + const ::basegfx::B2DPoint& rDstPoint, + const ::basegfx::B2DVector& rDstSize, + double nAlpha, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ); + + /** Create new transparency group action. + + @param rGroupMtf + Metafile that groups all actions to be rendered + transparent. + + @param rAlphaGradient + VCL gradient, to be rendered into the action's alpha + channel. + + @param rParms + Render parameters + + @param rDstPoint + Left, top edge of destination, in current state + coordinate system + + @param rDstSize + Size of the transparency group object, in current + state coordinate system. + */ + static ActionSharedPtr createTransparencyGroupAction( MtfAutoPtr& rGroupMtf, + GradientAutoPtr& rAlphaGradient, + const Renderer::Parameters& rParms, + const ::basegfx::B2DPoint& rDstPoint, + const ::basegfx::B2DVector& rDstSize, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ); + + private: + // static factory, disable big four + TransparencyGroupActionFactory(); + ~TransparencyGroupActionFactory(); + TransparencyGroupActionFactory(const TransparencyGroupActionFactory&); + TransparencyGroupActionFactory& operator=( const TransparencyGroupActionFactory& ); + }; + } +} + +#endif /*_CPPCANVAS_TRANSPARENCYGROUPACTION_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/tools/canvasgraphichelper.cxx b/cppcanvas/source/tools/canvasgraphichelper.cxx new file mode 100644 index 000000000000..4888960c0d96 --- /dev/null +++ b/cppcanvas/source/tools/canvasgraphichelper.cxx @@ -0,0 +1,154 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cppcanvas.hxx" + +#include <canvasgraphichelper.hxx> + +#include <com/sun/star/rendering/XGraphicDevice.hpp> +#include <com/sun/star/rendering/XCanvas.hpp> +#include <com/sun/star/rendering/XPolyPolygon2D.hpp> + +#include <canvas/canvastools.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> + +#include <cppcanvas/polypolygon.hxx> +#include "tools.hxx" + + +using namespace ::com::sun::star; + +/* Implementation of CanvasGraphicHelper class */ + +namespace cppcanvas +{ + + namespace internal + { + CanvasGraphicHelper::CanvasGraphicHelper( const CanvasSharedPtr& rParentCanvas ) : + maClipPolyPolygon(), + mpCanvas( rParentCanvas ), + mxGraphicDevice() + { + OSL_ENSURE( mpCanvas.get() != NULL && + mpCanvas->getUNOCanvas().is(), + "CanvasGraphicHelper::CanvasGraphicHelper: no valid canvas" ); + + if( mpCanvas.get() != NULL && + mpCanvas->getUNOCanvas().is() ) + { + mxGraphicDevice = mpCanvas->getUNOCanvas()->getDevice(); + } + + ::canvas::tools::initRenderState( maRenderState ); + } + + void CanvasGraphicHelper::setTransformation( const ::basegfx::B2DHomMatrix& rMatrix ) + { + ::canvas::tools::setRenderStateTransform( maRenderState, rMatrix ); + } + + ::basegfx::B2DHomMatrix CanvasGraphicHelper::getTransformation() const + { + ::basegfx::B2DHomMatrix aMatrix; + return ::canvas::tools::getRenderStateTransform( aMatrix, + maRenderState ); + } + + void CanvasGraphicHelper::setClip( const ::basegfx::B2DPolyPolygon& rClipPoly ) + { + // TODO(T3): not thread-safe. B2DPolyPolygon employs copy-on-write + maClipPolyPolygon.reset( rClipPoly ); + maRenderState.Clip.clear(); + } + + void CanvasGraphicHelper::setClip() + { + maClipPolyPolygon.reset(); + maRenderState.Clip.clear(); + } + + ::basegfx::B2DPolyPolygon const* CanvasGraphicHelper::getClip() const + { + return !maClipPolyPolygon ? NULL : &(*maClipPolyPolygon); + } + + const rendering::RenderState& CanvasGraphicHelper::getRenderState() const + { + if( maClipPolyPolygon && !maRenderState.Clip.is() ) + { + uno::Reference< rendering::XCanvas > xCanvas( mpCanvas->getUNOCanvas() ); + if( !xCanvas.is() ) + return maRenderState; + + maRenderState.Clip = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + xCanvas->getDevice(), + *maClipPolyPolygon ); + } + + return maRenderState; + } + + void CanvasGraphicHelper::setRGBAColor( Color::IntSRGBA aColor ) + { + maRenderState.DeviceColor = tools::intSRGBAToDoubleSequence( mxGraphicDevice, + aColor ); + } + + Color::IntSRGBA CanvasGraphicHelper::getRGBAColor() const + { + return tools::doubleSequenceToIntSRGBA( mxGraphicDevice, + maRenderState.DeviceColor ); + } + + void CanvasGraphicHelper::setCompositeOp( CompositeOp aOp ) + { + maRenderState.CompositeOperation = (sal_Int8)aOp; + } + + CanvasGraphic::CompositeOp CanvasGraphicHelper::getCompositeOp() const + { + return static_cast<CompositeOp>(maRenderState.CompositeOperation); + } + + CanvasSharedPtr CanvasGraphicHelper::getCanvas() const + { + return mpCanvas; + } + + uno::Reference< rendering::XGraphicDevice > CanvasGraphicHelper::getGraphicDevice() const + { + return mxGraphicDevice; + } + + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/tools/tools.cxx b/cppcanvas/source/tools/tools.cxx new file mode 100644 index 000000000000..bea26d8e55e8 --- /dev/null +++ b/cppcanvas/source/tools/tools.cxx @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cppcanvas.hxx" + +#include <tools.hxx> + + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace tools + { + uno::Sequence< double > intSRGBAToDoubleSequence( const uno::Reference< rendering::XGraphicDevice >&, + Color::IntSRGBA aColor ) + { + uno::Sequence< double > aRes( 4 ); + + aRes[0] = getRed(aColor) / 255.0; + aRes[1] = getGreen(aColor) / 255.0; + aRes[2] = getBlue(aColor) / 255.0; + aRes[3] = getAlpha(aColor) / 255.0; + + return aRes; + } + + Color::IntSRGBA doubleSequenceToIntSRGBA( const uno::Reference< rendering::XGraphicDevice >&, + const uno::Sequence< double >& rColor ) + { + return makeColor( static_cast<sal_uInt8>( 255*rColor[0] + .5 ), + static_cast<sal_uInt8>( 255*rColor[1] + .5 ), + static_cast<sal_uInt8>( 255*rColor[2] + .5 ), + static_cast<sal_uInt8>( 255*rColor[3] + .5 ) ); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/uno/exports.dxp b/cppcanvas/source/uno/exports.dxp new file mode 100644 index 000000000000..70033078921a --- /dev/null +++ b/cppcanvas/source/uno/exports.dxp @@ -0,0 +1 @@ +component_getFactory diff --git a/cppcanvas/source/uno/exports.map b/cppcanvas/source/uno/exports.map new file mode 100644 index 000000000000..f1ded4b70d9a --- /dev/null +++ b/cppcanvas/source/uno/exports.map @@ -0,0 +1,7 @@ +UDK_3_0_0 { + global: +_ZTI*; _ZTS*; # weak RTTI symbols for C++ exceptions + component_getFactory; + local: + *; +}; diff --git a/cppcanvas/source/uno/makefile.mk b/cppcanvas/source/uno/makefile.mk new file mode 100644 index 000000000000..5e06f4f1c839 --- /dev/null +++ b/cppcanvas/source/uno/makefile.mk @@ -0,0 +1,70 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2010 Novell, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=cppcanvas +TARGET=mtfrenderer +ENABLE_EXCEPTIONS=TRUE + + +# --- Settings ----------------------------------------------------------- + +.INCLUDE : settings.mk + +# --- Common ---------------------------------------------------------- + +.IF "$(verbose)"!="" || "$(VERBOSE)"!="" +CDEFS+= -DVERBOSE +.ENDIF + +SLOFILES = $(SLO)$/uno_mtfrenderer.obj + +SHL1TARGET=$(TARGET).uno + +SHL1STDLIBS= $(SALLIB) $(CPPULIB) $(CPPUHELPERLIB) $(COMPHELPERLIB) $(CPPCANVASLIB) $(BASEGFXLIB) + +SHL1IMPLIB=i$(TARGET) +SHL1LIBS=$(SLB)$/$(TARGET).lib +SHL1DEF=$(MISC)$/$(SHL1TARGET).def + +SHL1VERSIONMAP=exports.map + +DEF1NAME=$(SHL1TARGET) +DEF1EXPORTFILE=exports.dxp + +# ========================================================================== + +.INCLUDE : target.mk + +$(MISC)/mtfrenderer.component .ERRREMOVE : $(SOLARENV)/bin/createcomponent.xslt \ + mtfrenderer.component + $(XSLTPROC) --nonet --stringparam uri \ + '$(COMPONENTPREFIX_BASIS_NATIVE)$(SHL1TARGETN:f)' -o $@ \ + $(SOLARENV)/bin/createcomponent.xslt mtfrenderer.component + +ALLTAR : $(MISC)/mtfrenderer.component diff --git a/cppcanvas/source/uno/mtfrenderer.component b/cppcanvas/source/uno/mtfrenderer.component new file mode 100644 index 000000000000..68bf37e1b933 --- /dev/null +++ b/cppcanvas/source/uno/mtfrenderer.component @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<component loader="com.sun.star.loader.SharedLibrary" prefix="mtfrenderer" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.rendering.MtfRenderer"> + <service name="com.sun.star.rendering.MtfRenderer"/> + </implementation> +</component> diff --git a/cppcanvas/source/uno/uno_mtfrenderer.cxx b/cppcanvas/source/uno/uno_mtfrenderer.cxx new file mode 100644 index 000000000000..596b5e7c82b4 --- /dev/null +++ b/cppcanvas/source/uno/uno_mtfrenderer.cxx @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2010 Novell, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "uno_mtfrenderer.hxx" +#include <cppcanvas/vclfactory.hxx> +#include <comphelper/servicedecl.hxx> +#include <cppuhelper/factory.hxx> + +using namespace ::com::sun::star; + +void MtfRenderer::setMetafile (const uno::Sequence< sal_Int8 >& /*rMtf*/) throw (uno::RuntimeException) +{ + // printf ("MtfRenderer::setMetafile unimplemented, use fast property set or implement me\n"); +} + +void MtfRenderer::draw (double fScaleX, double fScaleY) throw (uno::RuntimeException) +{ + if (mpMetafile && mxCanvas.get()) { + cppcanvas::VCLFactory& factory = cppcanvas::VCLFactory::getInstance(); + cppcanvas::BitmapCanvasSharedPtr canvas = factory.createCanvas (mxCanvas); + cppcanvas::RendererSharedPtr renderer = factory.createRenderer (canvas, *mpMetafile, cppcanvas::Renderer::Parameters ()); + ::basegfx::B2DHomMatrix aMatrix; + aMatrix.scale( fScaleX, fScaleY ); + canvas->setTransformation( aMatrix ); + renderer->draw (); + } +} + +void MtfRenderer::setFastPropertyValue( sal_Int32 nHandle, const uno::Any& aAny) throw (uno::RuntimeException) +{ + if (nHandle == 0) { + mpMetafile = (GDIMetaFile*) *reinterpret_cast<const sal_Int64*>(aAny.getValue()); + } +} + +MtfRenderer::MtfRenderer (uno::Sequence<uno::Any> const& aArgs, uno::Reference<uno::XComponentContext> const&) : MtfRendererBase (m_aMutex), mpMetafile (NULL) +{ + if( aArgs.getLength() == 1 ) { + aArgs[0] >>= mxCanvas; + } +} + +namespace sdecl = comphelper::service_decl; +#if defined (__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ <= 3) + sdecl::class_<MtfRenderer, sdecl::with_args<true> > serviceImpl; + const sdecl::ServiceDecl MtfRendererDecl( + serviceImpl, +#else + const sdecl::ServiceDecl MtfRendererDecl( + sdecl::class_<MtfRenderer, sdecl::with_args<true> >(), +#endif + "com.sun.star.comp.rendering.MtfRenderer", + "com.sun.star.rendering.MtfRenderer" ); + +// The C shared lib entry points +extern "C" +{ +SAL_DLLPUBLIC_EXPORT void* SAL_CALL mtfrenderer_component_getFactory( sal_Char const* pImplName, + ::com::sun::star::lang::XMultiServiceFactory* pServiceManager, + ::com::sun::star::registry::XRegistryKey* pRegistryKey ) +{ + return component_getFactoryHelper( pImplName, pServiceManager, pRegistryKey, MtfRendererDecl ); +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/uno/uno_mtfrenderer.hxx b/cppcanvas/source/uno/uno_mtfrenderer.hxx new file mode 100644 index 000000000000..e462c6732cc4 --- /dev/null +++ b/cppcanvas/source/uno/uno_mtfrenderer.hxx @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2010 Novell, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _UNO_MTF_RENDERER_HXX_ +#define _UNO_MTF_RENDERER_HXX_ +#include <com/sun/star/rendering/MtfRenderer.hpp> +#include <com/sun/star/rendering/XBitmapCanvas.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/beans/XFastPropertySet.hpp> +#include <cppuhelper/compbase2.hxx> +#include <cppuhelper/basemutex.hxx> +#include <vcl/gdimtf.hxx> + +typedef cppu::WeakComponentImplHelper2<com::sun::star::rendering::XMtfRenderer, com::sun::star::beans::XFastPropertySet> MtfRendererBase; + +class MtfRenderer : private cppu::BaseMutex, public MtfRendererBase +{ +public: + MtfRenderer (com::sun::star::uno::Sequence<com::sun::star::uno::Any> const& args, + com::sun::star::uno::Reference<com::sun::star::uno::XComponentContext> const&); + + // XMtfRenderer iface + void SAL_CALL setMetafile (const ::com::sun::star::uno::Sequence< sal_Int8 >& rMtf) throw (::com::sun::star::uno::RuntimeException); + void SAL_CALL draw (double fScaleX, double fScaleY) throw (::com::sun::star::uno::RuntimeException); + + // XFastPropertySet + // setFastPropertyValue (0, GDIMetaFile*) is used to speedup the rendering + virtual ::com::sun::star::uno::Any SAL_CALL getFastPropertyValue(sal_Int32 /*nHandle*/) throw (::com::sun::star::uno::RuntimeException) { return ::com::sun::star::uno::Any(); } + virtual void SAL_CALL setFastPropertyValue(sal_Int32 nHandle, const ::com::sun::star::uno::Any&) throw (::com::sun::star::uno::RuntimeException); + +private: + GDIMetaFile* mpMetafile; + com::sun::star::uno::Reference<com::sun::star::rendering::XBitmapCanvas> mxCanvas; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/wrapper/basegfxfactory.cxx b/cppcanvas/source/wrapper/basegfxfactory.cxx new file mode 100644 index 000000000000..c65a4216b522 --- /dev/null +++ b/cppcanvas/source/wrapper/basegfxfactory.cxx @@ -0,0 +1,167 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cppcanvas.hxx" + +#include <rtl/instance.hxx> +#include <osl/getglobalmutex.hxx> +#include <osl/diagnose.h> + +#include <com/sun/star/rendering/InterpolationMode.hpp> + +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/tools/canvastools.hxx> + +#include <cppcanvas/basegfxfactory.hxx> + +#include "implpolypolygon.hxx" +#include "implbitmap.hxx" +#include "impltext.hxx" + + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + /* Singleton handling */ + struct InitInstance2 + { + BaseGfxFactory* operator()() + { + return new BaseGfxFactory(); + } + }; + + BaseGfxFactory& BaseGfxFactory::getInstance() + { + return *rtl_Instance< BaseGfxFactory, InitInstance2, ::osl::MutexGuard, + ::osl::GetGlobalMutex >::create( + InitInstance2(), ::osl::GetGlobalMutex()); + } + + BaseGfxFactory::BaseGfxFactory() + { + } + + BaseGfxFactory::~BaseGfxFactory() + { + } + + PolyPolygonSharedPtr BaseGfxFactory::createPolyPolygon( const CanvasSharedPtr& rCanvas, + const ::basegfx::B2DPolygon& rPoly ) const + { + OSL_ENSURE( rCanvas.get() != NULL && + rCanvas->getUNOCanvas().is(), + "BaseGfxFactory::createPolyPolygon(): Invalid canvas" ); + + if( rCanvas.get() == NULL ) + return PolyPolygonSharedPtr(); + + uno::Reference< rendering::XCanvas > xCanvas( rCanvas->getUNOCanvas() ); + if( !xCanvas.is() ) + return PolyPolygonSharedPtr(); + + return PolyPolygonSharedPtr( + new internal::ImplPolyPolygon( rCanvas, + ::basegfx::unotools::xPolyPolygonFromB2DPolygon( + xCanvas->getDevice(), + rPoly) ) ); + } + + PolyPolygonSharedPtr BaseGfxFactory::createPolyPolygon( const CanvasSharedPtr& rCanvas, + const ::basegfx::B2DPolyPolygon& rPolyPoly ) const + { + OSL_ENSURE( rCanvas.get() != NULL && + rCanvas->getUNOCanvas().is(), + "BaseGfxFactory::createPolyPolygon(): Invalid canvas" ); + + if( rCanvas.get() == NULL ) + return PolyPolygonSharedPtr(); + + uno::Reference< rendering::XCanvas > xCanvas( rCanvas->getUNOCanvas() ); + if( !xCanvas.is() ) + return PolyPolygonSharedPtr(); + + return PolyPolygonSharedPtr( + new internal::ImplPolyPolygon( rCanvas, + ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + xCanvas->getDevice(), + rPolyPoly) ) ); + } + + BitmapSharedPtr BaseGfxFactory::createBitmap( const CanvasSharedPtr& rCanvas, + const ::basegfx::B2ISize& rSize ) const + { + OSL_ENSURE( rCanvas.get() != NULL && + rCanvas->getUNOCanvas().is(), + "BaseGfxFactory::createBitmap(): Invalid canvas" ); + + if( rCanvas.get() == NULL ) + return BitmapSharedPtr(); + + uno::Reference< rendering::XCanvas > xCanvas( rCanvas->getUNOCanvas() ); + if( !xCanvas.is() ) + return BitmapSharedPtr(); + + return BitmapSharedPtr( + new internal::ImplBitmap( rCanvas, + xCanvas->getDevice()->createCompatibleBitmap( + ::basegfx::unotools::integerSize2DFromB2ISize(rSize) ) ) ); + } + + BitmapSharedPtr BaseGfxFactory::createAlphaBitmap( const CanvasSharedPtr& rCanvas, + const ::basegfx::B2ISize& rSize ) const + { + OSL_ENSURE( rCanvas.get() != NULL && + rCanvas->getUNOCanvas().is(), + "BaseGfxFactory::createBitmap(): Invalid canvas" ); + + if( rCanvas.get() == NULL ) + return BitmapSharedPtr(); + + uno::Reference< rendering::XCanvas > xCanvas( rCanvas->getUNOCanvas() ); + if( !xCanvas.is() ) + return BitmapSharedPtr(); + + return BitmapSharedPtr( + new internal::ImplBitmap( rCanvas, + xCanvas->getDevice()->createCompatibleAlphaBitmap( + ::basegfx::unotools::integerSize2DFromB2ISize(rSize) ) ) ); + } + + TextSharedPtr BaseGfxFactory::createText( const CanvasSharedPtr& rCanvas, const ::rtl::OUString& rText ) const + { + return TextSharedPtr( new internal::ImplText( rCanvas, + rText ) ); + } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/wrapper/implbitmap.cxx b/cppcanvas/source/wrapper/implbitmap.cxx new file mode 100644 index 000000000000..bf00e0f673c6 --- /dev/null +++ b/cppcanvas/source/wrapper/implbitmap.cxx @@ -0,0 +1,129 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cppcanvas.hxx" + +#include "implbitmap.hxx" +#include "implbitmapcanvas.hxx" + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <canvas/canvastools.hxx> + + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + + namespace internal + { + + ImplBitmap::ImplBitmap( const CanvasSharedPtr& rParentCanvas, + const uno::Reference< rendering::XBitmap >& rBitmap ) : + CanvasGraphicHelper( rParentCanvas ), + mxBitmap( rBitmap ), + mpBitmapCanvas() + { + OSL_ENSURE( mxBitmap.is(), "ImplBitmap::ImplBitmap: no valid bitmap" ); + + uno::Reference< rendering::XBitmapCanvas > xBitmapCanvas( rBitmap, + uno::UNO_QUERY ); + if( xBitmapCanvas.is() ) + mpBitmapCanvas.reset( new ImplBitmapCanvas( + uno::Reference< rendering::XBitmapCanvas >(rBitmap, + uno::UNO_QUERY) ) ); + } + + ImplBitmap::~ImplBitmap() + { + } + + bool ImplBitmap::draw() const + { + CanvasSharedPtr pCanvas( getCanvas() ); + + OSL_ENSURE( pCanvas.get() != NULL && + pCanvas->getUNOCanvas().is(), + "ImplBitmap::draw: invalid canvas" ); + + if( pCanvas.get() == NULL || + !pCanvas->getUNOCanvas().is() ) + { + return false; + } + + // TODO(P1): implement caching + pCanvas->getUNOCanvas()->drawBitmap( mxBitmap, + pCanvas->getViewState(), + getRenderState() ); + + return true; + } + + bool ImplBitmap::drawAlphaModulated( double nAlphaModulation ) const + { + CanvasSharedPtr pCanvas( getCanvas() ); + + OSL_ENSURE( pCanvas.get() != NULL && + pCanvas->getUNOCanvas().is(), + "ImplBitmap::drawAlphaModulated(): invalid canvas" ); + + if( pCanvas.get() == NULL || + !pCanvas->getUNOCanvas().is() ) + { + return false; + } + + rendering::RenderState aLocalState( getRenderState() ); + uno::Sequence<rendering::ARGBColor> aCol(1); + aCol[0] = rendering::ARGBColor( nAlphaModulation, 1.0, 1.0, 1.0 ); + aLocalState.DeviceColor = + pCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace()->convertFromARGB(aCol); + + // TODO(P1): implement caching + pCanvas->getUNOCanvas()->drawBitmapModulated( mxBitmap, + pCanvas->getViewState(), + aLocalState ); + + return true; + } + + BitmapCanvasSharedPtr ImplBitmap::getBitmapCanvas() const + { + return mpBitmapCanvas; + } + + uno::Reference< rendering::XBitmap > ImplBitmap::getUNOBitmap() const + { + return mxBitmap; + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/wrapper/implbitmap.hxx b/cppcanvas/source/wrapper/implbitmap.hxx new file mode 100644 index 000000000000..c27d095d1888 --- /dev/null +++ b/cppcanvas/source/wrapper/implbitmap.hxx @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_IMPLBITMAP_HXX +#define _CPPCANVAS_IMPLBITMAP_HXX + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/rendering/XBitmap.hpp> +#include <com/sun/star/rendering/XGraphicDevice.hpp> + +#include <cppcanvas/bitmap.hxx> +#include <canvasgraphichelper.hxx> + + +/*Definition of ImplBitmap */ + +namespace cppcanvas +{ + + namespace internal + { + // share partial CanvasGraphic implementation from CanvasGraphicHelper + class ImplBitmap : public virtual ::cppcanvas::Bitmap, protected CanvasGraphicHelper + { + public: + + ImplBitmap( const CanvasSharedPtr& rParentCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XBitmap >& rBitmap ); + + virtual ~ImplBitmap(); + + // CanvasGraphic implementation (that was not already implemented by CanvasGraphicHelper) + virtual bool draw() const; + virtual bool drawAlphaModulated( double nAlphaModulation ) const; + + virtual BitmapCanvasSharedPtr getBitmapCanvas() const; + + // Bitmap implementation + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XBitmap > getUNOBitmap() const; + + private: + // default: disabled copy/assignment + ImplBitmap(const ImplBitmap&); + ImplBitmap& operator=( const ImplBitmap& ); + + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmap > mxBitmap; + BitmapCanvasSharedPtr mpBitmapCanvas; + }; + } +} + +#endif /* _CPPCANVAS_IMPLBITMAP_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/wrapper/implbitmapcanvas.cxx b/cppcanvas/source/wrapper/implbitmapcanvas.cxx new file mode 100644 index 000000000000..6aa08a9334d0 --- /dev/null +++ b/cppcanvas/source/wrapper/implbitmapcanvas.cxx @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cppcanvas.hxx" + +#include <com/sun/star/rendering/XCanvas.hpp> +#include <com/sun/star/rendering/XBitmapCanvas.hpp> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/tools/canvastools.hxx> + +#include "implbitmapcanvas.hxx" + + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace internal + { + ImplBitmapCanvas::ImplBitmapCanvas( const uno::Reference< rendering::XBitmapCanvas >& rCanvas ) : + ImplCanvas( uno::Reference< rendering::XCanvas >(rCanvas, + uno::UNO_QUERY) ), + mxBitmapCanvas( rCanvas ), + mxBitmap( rCanvas, + uno::UNO_QUERY ) + { + OSL_ENSURE( mxBitmapCanvas.is(), "ImplBitmapCanvas::ImplBitmapCanvas(): Invalid canvas" ); + OSL_ENSURE( mxBitmap.is(), "ImplBitmapCanvas::ImplBitmapCanvas(): Invalid bitmap" ); + } + + ImplBitmapCanvas::~ImplBitmapCanvas() + { + } + + ::basegfx::B2ISize ImplBitmapCanvas::getSize() const + { + OSL_ENSURE( mxBitmap.is(), "ImplBitmapCanvas::getSize(): Invalid canvas" ); + return ::basegfx::unotools::b2ISizeFromIntegerSize2D( mxBitmap->getSize() ); + } + + CanvasSharedPtr ImplBitmapCanvas::clone() const + { + return BitmapCanvasSharedPtr( new ImplBitmapCanvas( *this ) ); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/wrapper/implbitmapcanvas.hxx b/cppcanvas/source/wrapper/implbitmapcanvas.hxx new file mode 100644 index 000000000000..5b1b625630a0 --- /dev/null +++ b/cppcanvas/source/wrapper/implbitmapcanvas.hxx @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_IMPLBITMAPCANVAS_HXX +#define _CPPCANVAS_IMPLBITMAPCANVAS_HXX + +#include <com/sun/star/rendering/XBitmapCanvas.hpp> +#include <com/sun/star/rendering/XBitmap.hpp> + +#include <boost/shared_ptr.hpp> +#include <basegfx/vector/b2dsize.hxx> +#include <cppcanvas/bitmapcanvas.hxx> + +#include <implcanvas.hxx> + + +namespace cppcanvas +{ + namespace internal + { + // share Canvas implementation from ImplCanvas + class ImplBitmapCanvas : public virtual BitmapCanvas, protected virtual ImplCanvas + { + public: + ImplBitmapCanvas( const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XBitmapCanvas >& rCanvas ); + virtual ~ImplBitmapCanvas(); + + virtual ::basegfx::B2ISize getSize() const; + + virtual CanvasSharedPtr clone() const; + + // take compiler-provided default copy constructor + //ImplBitmapCanvas(const ImplBitmapCanvas&); + + private: + // default: disabled assignment + ImplBitmapCanvas& operator=( const ImplBitmapCanvas& ); + + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmapCanvas > mxBitmapCanvas; + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmap > mxBitmap; + }; + } +} + +#endif /* _CPPCANVAS_IMPLBITMAPCANVAS_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/wrapper/implcanvas.cxx b/cppcanvas/source/wrapper/implcanvas.cxx new file mode 100644 index 000000000000..2fb6debc0eae --- /dev/null +++ b/cppcanvas/source/wrapper/implcanvas.cxx @@ -0,0 +1,144 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cppcanvas.hxx" + +#include <rtl/ustring.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/tools/canvastools.hxx> + +#include <com/sun/star/rendering/XCanvas.hpp> + +#include <canvas/canvastools.hxx> +#include <cppcanvas/polypolygon.hxx> + +#include "implfont.hxx" +#include "implcolor.hxx" +#include "implcanvas.hxx" + + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace internal + { + + ImplCanvas::ImplCanvas( const uno::Reference< rendering::XCanvas >& xCanvas ) : + maViewState(), + maClipPolyPolygon(), + mxCanvas( xCanvas ) + { + OSL_ENSURE( mxCanvas.is(), "Canvas::Canvas() invalid XCanvas" ); + + ::canvas::tools::initViewState( maViewState ); + } + + ImplCanvas::~ImplCanvas() + { + } + + void ImplCanvas::setTransformation( const ::basegfx::B2DHomMatrix& rMatrix ) + { + ::canvas::tools::setViewStateTransform( maViewState, rMatrix ); + } + + ::basegfx::B2DHomMatrix ImplCanvas::getTransformation() const + { + ::basegfx::B2DHomMatrix aMatrix; + return ::canvas::tools::getViewStateTransform( aMatrix, + maViewState ); + } + + void ImplCanvas::setClip( const ::basegfx::B2DPolyPolygon& rClipPoly ) + { + // TODO(T3): not thread-safe. B2DPolyPolygon employs copy-on-write + maClipPolyPolygon.reset( rClipPoly ); + maViewState.Clip.clear(); + } + + void ImplCanvas::setClip() + { + maClipPolyPolygon.reset(); + maViewState.Clip.clear(); + } + + ::basegfx::B2DPolyPolygon const* ImplCanvas::getClip() const + { + return !maClipPolyPolygon ? NULL : &(*maClipPolyPolygon); + } + + FontSharedPtr ImplCanvas::createFont( const ::rtl::OUString& rFontName, const double& rCellSize ) const + { + return FontSharedPtr( new ImplFont( getUNOCanvas(), rFontName, rCellSize ) ); + } + + ColorSharedPtr ImplCanvas::createColor() const + { + return ColorSharedPtr( new ImplColor( getUNOCanvas()->getDevice() ) ); + } + + CanvasSharedPtr ImplCanvas::clone() const + { + return CanvasSharedPtr( new ImplCanvas( *this ) ); + } + + void ImplCanvas::clear() const + { + OSL_ENSURE( mxCanvas.is(), "ImplCanvas::clear(): Invalid XCanvas" ); + mxCanvas->clear(); + } + + uno::Reference< rendering::XCanvas > ImplCanvas::getUNOCanvas() const + { + OSL_ENSURE( mxCanvas.is(), "ImplCanvas::getUNOCanvas(): Invalid XCanvas" ); + + return mxCanvas; + } + + rendering::ViewState ImplCanvas::getViewState() const + { + if( maClipPolyPolygon && !maViewState.Clip.is() ) + { + if( !mxCanvas.is() ) + return maViewState; + + maViewState.Clip = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + mxCanvas->getDevice(), + *maClipPolyPolygon ); + } + + return maViewState; + } + + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/wrapper/implcanvas.hxx b/cppcanvas/source/wrapper/implcanvas.hxx new file mode 100644 index 000000000000..481a5541441c --- /dev/null +++ b/cppcanvas/source/wrapper/implcanvas.hxx @@ -0,0 +1,107 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_IMPLCANVAS_HXX +#define _CPPCANVAS_IMPLCANVAS_HXX + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/rendering/ViewState.hpp> +#include <cppcanvas/canvas.hxx> + +#include <boost/optional.hpp> + +namespace rtl +{ + class OUString; +} + +namespace basegfx +{ + class B2DHomMatrix; + class B2DPolyPolygon; +} + +namespace com { namespace sun { namespace star { namespace rendering +{ + class XCanvas; +} } } } + + +/* Definition of ImplCanvas */ + +namespace cppcanvas +{ + + namespace internal + { + + class ImplCanvas : public virtual Canvas + { + public: + ImplCanvas( const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XCanvas >& rCanvas ); + virtual ~ImplCanvas(); + + virtual void setTransformation( const ::basegfx::B2DHomMatrix& rMatrix ); + virtual ::basegfx::B2DHomMatrix getTransformation() const; + + virtual void setClip( const ::basegfx::B2DPolyPolygon& rClipPoly ); + virtual void setClip(); + virtual ::basegfx::B2DPolyPolygon const* getClip() const; + + virtual FontSharedPtr createFont( const ::rtl::OUString& rFontName, const double& rCellSize ) const; + + virtual ColorSharedPtr createColor() const; + + virtual CanvasSharedPtr clone() const; + + virtual void clear() const; + + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XCanvas > getUNOCanvas() const; + + virtual ::com::sun::star::rendering::ViewState getViewState() const; + + // take compiler-provided default copy constructor + //ImplCanvas(const ImplCanvas&); + + private: + // default: disabled assignment + ImplCanvas& operator=( const ImplCanvas& ); + + mutable ::com::sun::star::rendering::ViewState maViewState; + boost::optional<basegfx::B2DPolyPolygon> maClipPolyPolygon; + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCanvas > mxCanvas; + }; + + } +} + +#endif /* _CPPCANVAS_IMPLCANVAS_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/wrapper/implcolor.cxx b/cppcanvas/source/wrapper/implcolor.cxx new file mode 100644 index 000000000000..c474deee2420 --- /dev/null +++ b/cppcanvas/source/wrapper/implcolor.cxx @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cppcanvas.hxx" + +#include <implcolor.hxx> +#include <tools.hxx> + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace internal + { + + ImplColor::ImplColor( const uno::Reference< rendering::XGraphicDevice >& rDevice ) : + mxDevice( rDevice ) + { + OSL_ENSURE( mxDevice.is(), "ImplColor::ImplColor(): Invalid graphic device" ); + } + + ImplColor::~ImplColor() + { + } + + Color::IntSRGBA ImplColor::getIntSRGBA( uno::Sequence< double >& rDeviceColor ) const + { + OSL_ENSURE( mxDevice.is(), "ImplColor::getIntSRGBA(): Invalid graphic device" ); + + // TODO(F1): Color space handling + return tools::doubleSequenceToIntSRGBA( mxDevice, rDeviceColor ); + } + + uno::Sequence< double > ImplColor::getDeviceColor( Color::IntSRGBA aSRGBA ) const + { + OSL_ENSURE( mxDevice.is(), "ImplColor::getDeviceColor(): Invalid graphic device" ); + + // TODO(F1): Color space handling + return tools::intSRGBAToDoubleSequence( mxDevice, aSRGBA ); + } + + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/wrapper/implcolor.hxx b/cppcanvas/source/wrapper/implcolor.hxx new file mode 100644 index 000000000000..3bc47da73d01 --- /dev/null +++ b/cppcanvas/source/wrapper/implcolor.hxx @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_IMPLCOLOR_HXX +#define _CPPCANVAS_IMPLCOLOR_HXX + +#include <com/sun/star/uno/Sequence.hxx> + +#include <boost/shared_ptr.hpp> + +#include <com/sun/star/rendering/XGraphicDevice.hpp> +#include <cppcanvas/color.hxx> + + +/* Definition of Color class */ + +namespace cppcanvas +{ + namespace internal + { + class ImplColor : public Color + { + public: + ImplColor( const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XGraphicDevice >& rDevice ); + virtual ~ImplColor(); + + virtual IntSRGBA getIntSRGBA( ::com::sun::star::uno::Sequence< double >& rDeviceColor ) const; + virtual ::com::sun::star::uno::Sequence< double > getDeviceColor( IntSRGBA aSRGBA ) const; + + private: + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice > mxDevice; + }; + + } +} + +#endif /* _CPPCANVAS_IMPLCOLOR_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/wrapper/implcustomsprite.cxx b/cppcanvas/source/wrapper/implcustomsprite.cxx new file mode 100644 index 000000000000..e41e728e40ce --- /dev/null +++ b/cppcanvas/source/wrapper/implcustomsprite.cxx @@ -0,0 +1,85 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cppcanvas.hxx" + +#include <basegfx/polygon/b2dpolypolygon.hxx> + +#include "implcustomsprite.hxx" +#include "implcanvas.hxx" + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace internal + { + ImplCustomSprite::ImplCustomSprite( const uno::Reference< rendering::XSpriteCanvas >& rParentCanvas, + const uno::Reference< rendering::XCustomSprite >& rSprite, + const ImplSpriteCanvas::TransformationArbiterSharedPtr& rTransformArbiter ) : + ImplSprite( rParentCanvas, + uno::Reference< rendering::XSprite >(rSprite, + uno::UNO_QUERY), + rTransformArbiter ), + mpLastCanvas(), + mxCustomSprite( rSprite ) + { + OSL_ENSURE( rParentCanvas.is(), "ImplCustomSprite::ImplCustomSprite(): Invalid canvas" ); + OSL_ENSURE( mxCustomSprite.is(), "ImplCustomSprite::ImplCustomSprite(): Invalid sprite" ); + } + + ImplCustomSprite::~ImplCustomSprite() + { + } + + CanvasSharedPtr ImplCustomSprite::getContentCanvas() const + { + OSL_ENSURE( mxCustomSprite.is(), "ImplCustomSprite::getContentCanvas(): Invalid sprite" ); + + if( !mxCustomSprite.is() ) + return CanvasSharedPtr(); + + uno::Reference< rendering::XCanvas > xCanvas( mxCustomSprite->getContentCanvas() ); + + if( !xCanvas.is() ) + return CanvasSharedPtr(); + + // cache content canvas C++ wrapper + if( mpLastCanvas.get() == NULL || + mpLastCanvas->getUNOCanvas() != xCanvas ) + { + mpLastCanvas = CanvasSharedPtr( new ImplCanvas( xCanvas ) ); + } + + return mpLastCanvas; + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/wrapper/implcustomsprite.hxx b/cppcanvas/source/wrapper/implcustomsprite.hxx new file mode 100644 index 000000000000..fe40c017b83c --- /dev/null +++ b/cppcanvas/source/wrapper/implcustomsprite.hxx @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_IMPLCUSTOMSPRITE_HXX +#define _CPPCANVAS_IMPLCUSTOMSPRITE_HXX + +#include <sal/types.h> + +#include <boost/shared_ptr.hpp> +#include <cppcanvas/canvas.hxx> +#include <cppcanvas/customsprite.hxx> + +#include <implsprite.hxx> +#include <implspritecanvas.hxx> + + +namespace cppcanvas +{ + namespace internal + { + // share Sprite implementation of ImplSprite + class ImplCustomSprite : public virtual CustomSprite, protected virtual ImplSprite + { + public: + ImplCustomSprite( const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XSpriteCanvas >& rParentCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XCustomSprite >& rSprite, + const ImplSpriteCanvas::TransformationArbiterSharedPtr& rTransformArbiter ); + virtual ~ImplCustomSprite(); + + virtual CanvasSharedPtr getContentCanvas() const; + + private: + // default: disabled copy/assignment + ImplCustomSprite(const ImplCustomSprite&); + ImplCustomSprite& operator=( const ImplCustomSprite& ); + + mutable CanvasSharedPtr mpLastCanvas; + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCustomSprite > mxCustomSprite; + }; + } +} + +#endif /* _CPPCANVAS_IMPLCUSTOMSPRITE_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/wrapper/implfont.cxx b/cppcanvas/source/wrapper/implfont.cxx new file mode 100644 index 000000000000..b466cfabd068 --- /dev/null +++ b/cppcanvas/source/wrapper/implfont.cxx @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cppcanvas.hxx" + +#include <implfont.hxx> +#include <canvas/canvastools.hxx> + + +using namespace ::com::sun::star; + +/* Definition of Font class */ + +namespace cppcanvas +{ + namespace internal + { + + ImplFont::ImplFont( const uno::Reference< rendering::XCanvas >& rCanvas, + const ::rtl::OUString& rFontName, + const double& rCellSize ) : + mxCanvas( rCanvas ), + mxFont( NULL ) + { + OSL_ENSURE( mxCanvas.is(), "ImplFont::ImplFont(): Invalid Canvas" ); + + rendering::FontRequest aFontRequest; + aFontRequest.FontDescription.FamilyName = rFontName; + aFontRequest.CellSize = rCellSize; + + geometry::Matrix2D aFontMatrix; + ::canvas::tools::setIdentityMatrix2D( aFontMatrix ); + + mxFont = mxCanvas->createFont( aFontRequest, + uno::Sequence< beans::PropertyValue >(), + aFontMatrix ); + } + + + ImplFont::~ImplFont() + { + } + + ::rtl::OUString ImplFont::getName() const + { + OSL_ENSURE( mxFont.is(), "ImplFont::getName(): Invalid Font" ); + + return mxFont->getFontRequest().FontDescription.FamilyName; + } + + double ImplFont::getCellSize() const + { + OSL_ENSURE( mxFont.is(), "ImplFont::getCellSize(): Invalid Font" ); + + return mxFont->getFontRequest().CellSize; + } + + uno::Reference< rendering::XCanvasFont > ImplFont::getUNOFont() const + { + OSL_ENSURE( mxFont.is(), "ImplFont::getUNOFont(): Invalid Font" ); + + return mxFont; + } + + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/wrapper/implfont.hxx b/cppcanvas/source/wrapper/implfont.hxx new file mode 100644 index 000000000000..589bab707e84 --- /dev/null +++ b/cppcanvas/source/wrapper/implfont.hxx @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_IMPLFONT_HXX +#define _CPPCANVAS_IMPLFONT_HXX + +#include <com/sun/star/uno/Reference.hxx> + +#include <boost/shared_ptr.hpp> + +#include <com/sun/star/rendering/XCanvas.hpp> +#include <cppcanvas/font.hxx> + +namespace rtl +{ + class OUString; +} + +namespace com { namespace sun { namespace star { namespace rendering +{ + class XCanvasFont; +} } } } + +/* Definition of Font class */ + +namespace cppcanvas +{ + + namespace internal + { + + class ImplFont : public Font + { + public: + ImplFont( const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XCanvas >& rCanvas, + const ::rtl::OUString& rFontName, + const double& rCellSize ); + + virtual ~ImplFont(); + + virtual ::rtl::OUString getName() const; + virtual double getCellSize() const; + + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XCanvasFont > getUNOFont() const; + + private: + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCanvas > mxCanvas; + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCanvasFont > mxFont; + }; + } +} + +#endif /* _CPPCANVAS_IMPLFONT_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/wrapper/implpolypolygon.cxx b/cppcanvas/source/wrapper/implpolypolygon.cxx new file mode 100644 index 000000000000..ac1fa728378c --- /dev/null +++ b/cppcanvas/source/wrapper/implpolypolygon.cxx @@ -0,0 +1,204 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cppcanvas.hxx" + +#include <rtl/math.hxx> + +#include <com/sun/star/rendering/XCanvas.hpp> +#include <com/sun/star/rendering/PathJoinType.hpp> +#include <com/sun/star/rendering/PathCapType.hpp> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/tools/canvastools.hxx> + +#include "implpolypolygon.hxx" +#include "tools.hxx" + + +using namespace ::com::sun::star; + + +namespace cppcanvas +{ + namespace internal + { + ImplPolyPolygon::ImplPolyPolygon( const CanvasSharedPtr& rParentCanvas, + const uno::Reference< rendering::XPolyPolygon2D >& rPolyPoly ) : + CanvasGraphicHelper( rParentCanvas ), + mxPolyPoly( rPolyPoly ), + maStrokeAttributes(1.0, + 10.0, + uno::Sequence< double >(), + uno::Sequence< double >(), + rendering::PathCapType::ROUND, + rendering::PathCapType::ROUND, + rendering::PathJoinType::ROUND ), + maFillColor(), + maStrokeColor(), + mbFillColorSet( false ), + mbStrokeColorSet( false ) + { + OSL_ENSURE( mxPolyPoly.is(), "PolyPolygonImpl::PolyPolygonImpl: no valid polygon" ); + } + + ImplPolyPolygon::~ImplPolyPolygon() + { + } + + void ImplPolyPolygon::addPolygon( const ::basegfx::B2DPolygon& rPoly ) + { + OSL_ENSURE( mxPolyPoly.is(), + "ImplPolyPolygon::addPolygon(): Invalid polygon" ); + + if( !mxPolyPoly.is() ) + return; + + uno::Reference< rendering::XGraphicDevice > xDevice( getGraphicDevice() ); + + OSL_ENSURE( xDevice.is(), + "ImplPolyPolygon::addPolygon(): Invalid graphic device" ); + + if( !xDevice.is() ) + return; + + mxPolyPoly->addPolyPolygon( geometry::RealPoint2D(0.0, 0.0), + ::basegfx::unotools::xPolyPolygonFromB2DPolygon( + xDevice, + rPoly) ); + } + + void ImplPolyPolygon::addPolyPolygon( const ::basegfx::B2DPolyPolygon& rPoly ) + { + OSL_ENSURE( mxPolyPoly.is(), + "ImplPolyPolygon::addPolyPolygon(): Invalid polygon" ); + + if( !mxPolyPoly.is() ) + return; + + uno::Reference< rendering::XGraphicDevice > xDevice( getGraphicDevice() ); + + OSL_ENSURE( xDevice.is(), + "ImplPolyPolygon::addPolyPolygon(): Invalid graphic device" ); + + if( !xDevice.is() ) + return; + + mxPolyPoly->addPolyPolygon( geometry::RealPoint2D(0.0, 0.0), + ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + xDevice, + rPoly) ); + } + + void ImplPolyPolygon::setRGBAFillColor( Color::IntSRGBA aColor ) + { + maFillColor = tools::intSRGBAToDoubleSequence( getGraphicDevice(), + aColor ); + mbFillColorSet = true; + } + + void ImplPolyPolygon::setRGBALineColor( Color::IntSRGBA aColor ) + { + maStrokeColor = tools::intSRGBAToDoubleSequence( getGraphicDevice(), + aColor ); + mbStrokeColorSet = true; + } + + Color::IntSRGBA ImplPolyPolygon::getRGBAFillColor() const + { + return tools::doubleSequenceToIntSRGBA( getGraphicDevice(), + maFillColor ); + } + + Color::IntSRGBA ImplPolyPolygon::getRGBALineColor() const + { + return tools::doubleSequenceToIntSRGBA( getGraphicDevice(), + maStrokeColor ); + } + + void ImplPolyPolygon::setStrokeWidth( const double& rStrokeWidth ) + { + maStrokeAttributes.StrokeWidth = rStrokeWidth; + } + + double ImplPolyPolygon::getStrokeWidth() const + { + return maStrokeAttributes.StrokeWidth; + } + + bool ImplPolyPolygon::draw() const + { + CanvasSharedPtr pCanvas( getCanvas() ); + + OSL_ENSURE( pCanvas.get() != NULL && + pCanvas->getUNOCanvas().is(), + "ImplBitmap::draw: invalid canvas" ); + + if( pCanvas.get() == NULL || + !pCanvas->getUNOCanvas().is() ) + return false; + + if( mbFillColorSet ) + { + rendering::RenderState aLocalState( getRenderState() ); + aLocalState.DeviceColor = maFillColor; + + pCanvas->getUNOCanvas()->fillPolyPolygon( mxPolyPoly, + pCanvas->getViewState(), + aLocalState ); + } + + if( mbStrokeColorSet ) + { + rendering::RenderState aLocalState( getRenderState() ); + aLocalState.DeviceColor = maStrokeColor; + + if( ::rtl::math::approxEqual(maStrokeAttributes.StrokeWidth, 1.0) ) + pCanvas->getUNOCanvas()->drawPolyPolygon( mxPolyPoly, + pCanvas->getViewState(), + aLocalState ); + else + pCanvas->getUNOCanvas()->strokePolyPolygon( mxPolyPoly, + pCanvas->getViewState(), + aLocalState, + maStrokeAttributes ); + } + + return true; + } + + uno::Reference< rendering::XPolyPolygon2D > ImplPolyPolygon::getUNOPolyPolygon() const + { + return mxPolyPoly; + } + + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/wrapper/implpolypolygon.hxx b/cppcanvas/source/wrapper/implpolypolygon.hxx new file mode 100644 index 000000000000..7d89039f29c7 --- /dev/null +++ b/cppcanvas/source/wrapper/implpolypolygon.hxx @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CANVAS_IMPLPOLYPOLYGON_HXX +#define _CANVAS_IMPLPOLYPOLYGON_HXX + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/rendering/XPolyPolygon2D.hpp> +#include <com/sun/star/rendering/XGraphicDevice.hpp> +#include <com/sun/star/rendering/StrokeAttributes.hpp> + +#include <cppcanvas/polypolygon.hxx> +#include <canvasgraphichelper.hxx> + +namespace com { namespace sun { namespace star { namespace rendering +{ + struct RealPoint2D; +} } } } + + +namespace cppcanvas +{ + namespace internal + { + + class ImplPolyPolygon : public virtual ::cppcanvas::PolyPolygon, protected CanvasGraphicHelper + { + public: + ImplPolyPolygon( const CanvasSharedPtr& rParentCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XPolyPolygon2D >& rPolyPoly ); + + virtual ~ImplPolyPolygon(); + + virtual void addPolygon( const ::basegfx::B2DPolygon& rPoly ); + virtual void addPolyPolygon( const ::basegfx::B2DPolyPolygon& rPoly ); + + virtual void setRGBAFillColor( Color::IntSRGBA ); + virtual void setRGBALineColor( Color::IntSRGBA ); + virtual Color::IntSRGBA getRGBAFillColor() const; + virtual Color::IntSRGBA getRGBALineColor() const; + + virtual void setStrokeWidth( const double& rStrokeWidth ); + virtual double getStrokeWidth() const; + + virtual bool draw() const; + + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XPolyPolygon2D > getUNOPolyPolygon() const; + + private: + // default: disabled copy/assignment + ImplPolyPolygon(const ImplPolyPolygon&); + ImplPolyPolygon& operator= ( const ImplPolyPolygon& ); + + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XPolyPolygon2D > mxPolyPoly; + + ::com::sun::star::rendering::StrokeAttributes maStrokeAttributes; + + ::com::sun::star::uno::Sequence< double > maFillColor; + ::com::sun::star::uno::Sequence< double > maStrokeColor; + bool mbFillColorSet; + bool mbStrokeColorSet; + }; + + } +} + +#endif /* _CANVAS_IMPLPOLYPOLYGON_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/wrapper/implsprite.cxx b/cppcanvas/source/wrapper/implsprite.cxx new file mode 100644 index 000000000000..f2f5fba781bd --- /dev/null +++ b/cppcanvas/source/wrapper/implsprite.cxx @@ -0,0 +1,239 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cppcanvas.hxx" + +#include <com/sun/star/rendering/XSprite.hpp> +#include <com/sun/star/rendering/XAnimatedSprite.hpp> + +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <canvas/canvastools.hxx> + +#include "implsprite.hxx" + + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace internal + { + + ImplSprite::ImplSprite( const uno::Reference< rendering::XSpriteCanvas >& rParentCanvas, + const uno::Reference< rendering::XSprite >& rSprite, + const ImplSpriteCanvas::TransformationArbiterSharedPtr& rTransformArbiter ) : + mxGraphicDevice(), + mxSprite( rSprite ), + mxAnimatedSprite(), + mpTransformArbiter( rTransformArbiter ) + { + // Avoiding ternary operator in initializer list (Solaris + // compiler bug, when function call and temporary is + // involved) + if( rParentCanvas.is() ) + mxGraphicDevice = rParentCanvas->getDevice(); + + OSL_ENSURE( rParentCanvas.is() , "ImplSprite::ImplSprite(): Invalid canvas"); + OSL_ENSURE( mxGraphicDevice.is(), "ImplSprite::ImplSprite(): Invalid graphic device"); + OSL_ENSURE( mxSprite.is(), "ImplSprite::ImplSprite(): Invalid sprite"); + OSL_ENSURE( mpTransformArbiter.get(), "ImplSprite::ImplSprite(): Invalid transformation arbiter"); + } + + ImplSprite::ImplSprite( const uno::Reference< rendering::XSpriteCanvas >& rParentCanvas, + const uno::Reference< rendering::XAnimatedSprite >& rSprite, + const ImplSpriteCanvas::TransformationArbiterSharedPtr& rTransformArbiter ) : + mxGraphicDevice(), + mxSprite( uno::Reference< rendering::XSprite >(rSprite, + uno::UNO_QUERY) ), + mxAnimatedSprite( rSprite ), + mpTransformArbiter( rTransformArbiter ) + { + // Avoiding ternary operator in initializer list (Solaris + // compiler bug, when function call and temporary is + // involved) + if( rParentCanvas.is() ) + mxGraphicDevice = rParentCanvas->getDevice(); + + OSL_ENSURE( rParentCanvas.is() , "ImplSprite::ImplSprite(): Invalid canvas"); + OSL_ENSURE( mxGraphicDevice.is(), "ImplSprite::ImplSprite(): Invalid graphic device"); + OSL_ENSURE( mxSprite.is(), "ImplSprite::ImplSprite(): Invalid sprite"); + OSL_ENSURE( mpTransformArbiter.get(), "ImplSprite::ImplSprite(): Invalid transformation arbiter"); + } + + ImplSprite::~ImplSprite() + { + // hide the sprite on the canvas. If we don't hide the + // sprite, it will stay on the canvas forever, since the + // canvas naturally keeps a list of visible sprites + // (otherwise, it wouldn't be able to paint them + // autonomously) + if( mxSprite.is() ) + mxSprite->hide(); + } + + void ImplSprite::setAlpha( const double& rAlpha ) + { + OSL_ENSURE( mxSprite.is(), "ImplSprite::setAlpha(): Invalid sprite"); + + if( mxSprite.is() ) + mxSprite->setAlpha( rAlpha ); + } + + void ImplSprite::movePixel( const ::basegfx::B2DPoint& rNewPos ) + { + OSL_ENSURE( mxSprite.is(), "ImplSprite::movePixel(): Invalid sprite"); + + if( mxSprite.is() ) + { + rendering::ViewState aViewState; + rendering::RenderState aRenderState; + + ::canvas::tools::initViewState( aViewState ); + ::canvas::tools::initRenderState( aRenderState ); + + mxSprite->move( ::basegfx::unotools::point2DFromB2DPoint( rNewPos ), + aViewState, + aRenderState ); + } + } + + void ImplSprite::move( const ::basegfx::B2DPoint& rNewPos ) + { + OSL_ENSURE( mxSprite.is(), "ImplSprite::move(): Invalid sprite"); + + if( mxSprite.is() ) + { + rendering::ViewState aViewState; + rendering::RenderState aRenderState; + + ::canvas::tools::initViewState( aViewState ); + ::canvas::tools::initRenderState( aRenderState ); + + ::canvas::tools::setViewStateTransform( aViewState, + mpTransformArbiter->getTransformation() ); + + mxSprite->move( ::basegfx::unotools::point2DFromB2DPoint( rNewPos ), + aViewState, + aRenderState ); + } + } + + void ImplSprite::transform( const ::basegfx::B2DHomMatrix& rMatrix ) + { + OSL_ENSURE( mxSprite.is(), "ImplSprite::transform(): Invalid sprite"); + + if( mxSprite.is() ) + { + geometry::AffineMatrix2D aMatrix; + + mxSprite->transform( ::basegfx::unotools::affineMatrixFromHomMatrix( aMatrix, + rMatrix ) ); + } + } + + void ImplSprite::setClipPixel( const ::basegfx::B2DPolyPolygon& rClipPoly ) + { + OSL_ENSURE( mxGraphicDevice.is(), "ImplSprite::setClip(): Invalid canvas"); + OSL_ENSURE( mxSprite.is(), "ImplSprite::transform(): Invalid sprite"); + + if( mxSprite.is() && mxGraphicDevice.is() ) + mxSprite->clip( ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( mxGraphicDevice, + rClipPoly ) ); + } + + void ImplSprite::setClip( const ::basegfx::B2DPolyPolygon& rClipPoly ) + { + OSL_ENSURE( mxGraphicDevice.is(), "ImplSprite::setClip(): Invalid canvas"); + OSL_ENSURE( mxSprite.is(), "ImplSprite::transform(): Invalid sprite"); + + if( mxSprite.is() && mxGraphicDevice.is() ) + { + ::basegfx::B2DPolyPolygon aTransformedClipPoly( rClipPoly ); + + // extract linear part of canvas view transformation (linear means: + // without translational components) + ::basegfx::B2DHomMatrix aViewTransform( mpTransformArbiter->getTransformation() ); + aViewTransform.set( 0, 2, 0.0 ); + aViewTransform.set( 1, 2, 0.0 ); + + // transform polygon from view to device coordinate space + aTransformedClipPoly.transform( aViewTransform ); + + mxSprite->clip( ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( mxGraphicDevice, + aTransformedClipPoly ) ); + } + } + + void ImplSprite::setClip() + { + OSL_ENSURE( mxGraphicDevice.is(), "ImplSprite::setClip(): Invalid canvas"); + OSL_ENSURE( mxSprite.is(), "ImplSprite::setClip(): Invalid sprite"); + + if( mxSprite.is() && mxGraphicDevice.is() ) + mxSprite->clip( uno::Reference< rendering::XPolyPolygon2D >() ); + } + + void ImplSprite::show() + { + OSL_ENSURE( mxSprite.is(), "ImplSprite::show(): Invalid sprite"); + + if( mxSprite.is() ) + mxSprite->show(); + } + + void ImplSprite::hide() + { + OSL_ENSURE( mxSprite.is(), "ImplSprite::hide(): Invalid sprite"); + + if( mxSprite.is() ) + mxSprite->hide(); + } + + void ImplSprite::setPriority( double fPriority ) + { + OSL_ENSURE( mxSprite.is(), "ImplSprite::setPriority(): Invalid sprite"); + + if( mxSprite.is() ) + mxSprite->setPriority(fPriority); + } + + uno::Reference< rendering::XSprite > ImplSprite::getUNOSprite() const + { + return mxSprite; + } + + uno::Reference< rendering::XGraphicDevice > ImplSprite::getGraphicDevice() const + { + return mxGraphicDevice; + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/wrapper/implsprite.hxx b/cppcanvas/source/wrapper/implsprite.hxx new file mode 100644 index 000000000000..1397791d1f82 --- /dev/null +++ b/cppcanvas/source/wrapper/implsprite.hxx @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_IMPLSPRITE_HXX +#define _CPPCANVAS_IMPLSPRITE_HXX + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/rendering/XSpriteCanvas.hpp> +#include <com/sun/star/rendering/XSprite.hpp> + +#include <boost/shared_ptr.hpp> +#include <cppcanvas/sprite.hxx> + +#include <implspritecanvas.hxx> + + +namespace cppcanvas +{ + namespace internal + { + class ImplSprite : public virtual Sprite + { + public: + ImplSprite( const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XSpriteCanvas >& rParentCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XSprite >& rSprite, + const ImplSpriteCanvas::TransformationArbiterSharedPtr& rTransformArbiter ); + ImplSprite( const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XSpriteCanvas >& rParentCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XAnimatedSprite >& rSprite, + const ImplSpriteCanvas::TransformationArbiterSharedPtr& rTransformArbiter ); + virtual ~ImplSprite(); + + virtual void setAlpha( const double& rAlpha ); + virtual void movePixel( const ::basegfx::B2DPoint& rNewPos ); + virtual void move( const ::basegfx::B2DPoint& rNewPos ); + virtual void transform( const ::basegfx::B2DHomMatrix& rMatrix ); + virtual void setClipPixel( const ::basegfx::B2DPolyPolygon& rClipPoly ); + virtual void setClip( const ::basegfx::B2DPolyPolygon& rClipPoly ); + virtual void setClip(); + + virtual void show(); + virtual void hide(); + + virtual void setPriority( double fPriority ); + + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XSprite > getUNOSprite() const; + + ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XGraphicDevice > + getGraphicDevice() const; + + private: + // default: disabled copy/assignment + ImplSprite(const ImplSprite&); + ImplSprite& operator=( const ImplSprite& ); + + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice > mxGraphicDevice; + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XSprite > mxSprite; + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XAnimatedSprite > mxAnimatedSprite; + ImplSpriteCanvas::TransformationArbiterSharedPtr mpTransformArbiter; + }; + } +} + +#endif /* _CPPCANVAS_IMPLSPRITE_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/wrapper/implspritecanvas.cxx b/cppcanvas/source/wrapper/implspritecanvas.cxx new file mode 100644 index 000000000000..cc8cf5bdefcc --- /dev/null +++ b/cppcanvas/source/wrapper/implspritecanvas.cxx @@ -0,0 +1,162 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cppcanvas.hxx" +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <com/sun/star/rendering/InterpolationMode.hpp> + +#include <implspritecanvas.hxx> +#include <implcustomsprite.hxx> + + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace internal + { + ImplSpriteCanvas::TransformationArbiter::TransformationArbiter() : + maTransformation() + { + } + + void ImplSpriteCanvas::TransformationArbiter::setTransformation( const ::basegfx::B2DHomMatrix& rViewTransform ) + { + maTransformation = rViewTransform; + } + + ::basegfx::B2DHomMatrix ImplSpriteCanvas::TransformationArbiter::getTransformation() const + { + return maTransformation; + } + + + ImplSpriteCanvas::ImplSpriteCanvas( const uno::Reference< rendering::XSpriteCanvas >& rCanvas ) : + ImplCanvas( uno::Reference< rendering::XCanvas >(rCanvas, + uno::UNO_QUERY) ), + ImplBitmapCanvas( uno::Reference< rendering::XBitmapCanvas >(rCanvas, + uno::UNO_QUERY) ), + mxSpriteCanvas( rCanvas ), + mpTransformArbiter( new TransformationArbiter() ) + { + OSL_ENSURE( mxSpriteCanvas.is(), "ImplSpriteCanvas::ImplSpriteCanvas(): Invalid canvas" ); + } + + ImplSpriteCanvas::ImplSpriteCanvas(const ImplSpriteCanvas& rOrig) : + Canvas(), + BitmapCanvas(), + SpriteCanvas(), + ImplCanvas( rOrig ), + ImplBitmapCanvas( rOrig ), + mxSpriteCanvas( rOrig.getUNOSpriteCanvas() ), + mpTransformArbiter( new TransformationArbiter() ) + { + OSL_ENSURE( mxSpriteCanvas.is(), "ImplSpriteCanvas::ImplSpriteCanvas( const ImplSpriteCanvas& ): Invalid canvas" ); + + mpTransformArbiter->setTransformation( getTransformation() ); + } + + ImplSpriteCanvas::~ImplSpriteCanvas() + { + } + + void ImplSpriteCanvas::setTransformation( const ::basegfx::B2DHomMatrix& rMatrix ) + { + mpTransformArbiter->setTransformation( rMatrix ); + + ImplCanvas::setTransformation( rMatrix ); + } + + bool ImplSpriteCanvas::updateScreen( bool bUpdateAll ) const + { + OSL_ENSURE( mxSpriteCanvas.is(), "ImplSpriteCanvas::updateScreen(): Invalid canvas" ); + + if( !mxSpriteCanvas.is() ) + return false; + + return mxSpriteCanvas->updateScreen( bUpdateAll ); + } + + CustomSpriteSharedPtr ImplSpriteCanvas::createCustomSprite( const ::basegfx::B2DSize& rSize ) const + { + OSL_ENSURE( mxSpriteCanvas.is(), "ImplSpriteCanvas::createCustomSprite(): Invalid canvas" ); + + if( !mxSpriteCanvas.is() ) + return CustomSpriteSharedPtr(); + + return CustomSpriteSharedPtr( + new ImplCustomSprite( mxSpriteCanvas, + mxSpriteCanvas->createCustomSprite( ::basegfx::unotools::size2DFromB2DSize(rSize) ), + mpTransformArbiter ) ); + } + + SpriteSharedPtr ImplSpriteCanvas::createClonedSprite( const SpriteSharedPtr& rSprite ) const + { + OSL_ENSURE( mxSpriteCanvas.is(), "ImplSpriteCanvas::createCustomSprite(): Invalid canvas" ); + OSL_ENSURE( rSprite.get() != NULL && rSprite->getUNOSprite().is(), + "ImplSpriteCanvas::createCustomSprite(): Invalid sprite" ); + + if( !mxSpriteCanvas.is() || + rSprite.get() == NULL || + !rSprite->getUNOSprite().is() ) + { + return SpriteSharedPtr(); + } + + return SpriteSharedPtr( + new ImplSprite( mxSpriteCanvas, + mxSpriteCanvas->createClonedSprite( rSprite->getUNOSprite() ), + mpTransformArbiter ) ); + } + + SpriteSharedPtr ImplSpriteCanvas::createSpriteFromBitmaps( const uno::Sequence< uno::Reference< rendering::XBitmap > >& rAnimationBitmaps, + sal_Int8 nInterpolationMode ) + { + return SpriteSharedPtr( new internal::ImplSprite( mxSpriteCanvas, + mxSpriteCanvas->createSpriteFromBitmaps( rAnimationBitmaps, + nInterpolationMode ), + mpTransformArbiter ) ); + } + + CanvasSharedPtr ImplSpriteCanvas::clone() const + { + return SpriteCanvasSharedPtr( new ImplSpriteCanvas( *this ) ); + } + + uno::Reference< rendering::XSpriteCanvas > ImplSpriteCanvas::getUNOSpriteCanvas() const + { + return mxSpriteCanvas; + } + + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/wrapper/implspritecanvas.hxx b/cppcanvas/source/wrapper/implspritecanvas.hxx new file mode 100644 index 000000000000..d308b313b7dd --- /dev/null +++ b/cppcanvas/source/wrapper/implspritecanvas.hxx @@ -0,0 +1,109 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_IMPLSPRITECANVAS_HXX +#define _CPPCANVAS_IMPLSPRITECANVAS_HXX + +#include <com/sun/star/rendering/XSpriteCanvas.hpp> +#include <basegfx/vector/b2dsize.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> + +#include <boost/shared_ptr.hpp> + + +#include <cppcanvas/spritecanvas.hxx> + +#include <implbitmapcanvas.hxx> + + +namespace cppcanvas +{ + namespace internal + { + class ImplSpriteCanvas : public virtual SpriteCanvas, protected virtual ImplBitmapCanvas + { + public: + ImplSpriteCanvas( const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XSpriteCanvas >& rCanvas ); + ImplSpriteCanvas(const ImplSpriteCanvas&); + + virtual ~ImplSpriteCanvas(); + + virtual void setTransformation( const ::basegfx::B2DHomMatrix& rMatrix ); + + virtual bool updateScreen( bool bUpdateAll ) const; + + virtual CustomSpriteSharedPtr createCustomSprite( const ::basegfx::B2DSize& ) const; + virtual SpriteSharedPtr createClonedSprite( const SpriteSharedPtr& ) const; + + SpriteSharedPtr createSpriteFromBitmaps( + const ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XBitmap > >& animationBitmaps, + sal_Int8 interpolationMode ); + + virtual CanvasSharedPtr clone() const; + + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XSpriteCanvas > getUNOSpriteCanvas() const; + + /** This class passes the view transformation + to child sprites + + This helper class is necessary, because the + ImplSpriteCanvas object cannot hand out shared ptrs of + itself, but has somehow pass an object to child + sprites those can query for the canvas' view transform. + */ + class TransformationArbiter + { + public: + TransformationArbiter(); + + void setTransformation( const ::basegfx::B2DHomMatrix& rViewTransform ); + ::basegfx::B2DHomMatrix getTransformation() const; + + private: + ::basegfx::B2DHomMatrix maTransformation; + }; + + typedef ::boost::shared_ptr< TransformationArbiter > TransformationArbiterSharedPtr; + + private: + // default: disabled assignment + ImplSpriteCanvas& operator=( const ImplSpriteCanvas& ); + + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XSpriteCanvas > mxSpriteCanvas; + TransformationArbiterSharedPtr mpTransformArbiter; + }; + } +} + +#endif /* _CPPCANVAS_IMPLSPRITECANVAS_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/wrapper/impltext.cxx b/cppcanvas/source/wrapper/impltext.cxx new file mode 100644 index 000000000000..68592105c14a --- /dev/null +++ b/cppcanvas/source/wrapper/impltext.cxx @@ -0,0 +1,98 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cppcanvas.hxx" + +#include <impltext.hxx> +#include <canvas/canvastools.hxx> + +#include <com/sun/star/rendering/TextDirection.hpp> +#include <com/sun/star/rendering/XCanvas.hpp> +#include <com/sun/star/rendering/StringContext.hpp> +#include <rtl/ustring.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> + + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace internal + { + + ImplText::ImplText( const CanvasSharedPtr& rParentCanvas, + const ::rtl::OUString& rText ) : + CanvasGraphicHelper( rParentCanvas ), + mpFont(), + maText(rText) + { + } + + ImplText::~ImplText() + { + } + + bool ImplText::draw() const + { + CanvasSharedPtr pCanvas( getCanvas() ); + + OSL_ENSURE( pCanvas.get() != NULL && + pCanvas->getUNOCanvas().is(), + "ImplBitmap::draw: invalid canvas" ); + + rendering::StringContext aText; + aText.Text = maText; + aText.StartPosition = 0; + aText.Length = maText.getLength(); + + // TODO(P1): implement caching + // TODO(F2): where to get current BiDi status? + sal_Int8 nBidiOption = rendering::TextDirection::WEAK_LEFT_TO_RIGHT; + pCanvas->getUNOCanvas()->drawText( aText, + mpFont->getUNOFont(), + pCanvas->getViewState(), + getRenderState(), + nBidiOption ); + + return true; + } + + void ImplText::setFont( const FontSharedPtr& rFont ) + { + mpFont = rFont; + } + + FontSharedPtr ImplText::getFont() + { + return mpFont; + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/wrapper/impltext.hxx b/cppcanvas/source/wrapper/impltext.hxx new file mode 100644 index 000000000000..a45e7dab2114 --- /dev/null +++ b/cppcanvas/source/wrapper/impltext.hxx @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CANVAS_IMPLTEXT_HXX +#define _CANVAS_IMPLTEXT_HXX + +#include <com/sun/star/rendering/RenderState.hpp> +#include <com/sun/star/rendering/StringContext.hpp> +#include <com/sun/star/rendering/XCanvas.hpp> +#include <com/sun/star/rendering/XCanvasFont.hpp> + +#include <cppcanvas/text.hxx> +#include <canvasgraphichelper.hxx> + + +namespace cppcanvas +{ + namespace internal + { + + class ImplText : public virtual ::cppcanvas::Text, protected CanvasGraphicHelper + { + public: + + ImplText( const CanvasSharedPtr& rParentCanvas, + const ::rtl::OUString& rText ); + + virtual ~ImplText(); + + virtual bool draw() const; + + virtual void setFont( const FontSharedPtr& ); + virtual FontSharedPtr getFont(); + + private: + // default: disabled copy/assignment + ImplText(const ImplText&); + ImplText& operator= ( const ImplText& ); + + FontSharedPtr mpFont; + ::rtl::OUString maText; + }; + } +} + +#endif /* _CANVAS_IMPLTEXT_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppcanvas/source/wrapper/vclfactory.cxx b/cppcanvas/source/wrapper/vclfactory.cxx new file mode 100644 index 000000000000..c0646d0fdba5 --- /dev/null +++ b/cppcanvas/source/wrapper/vclfactory.cxx @@ -0,0 +1,366 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cppcanvas.hxx" +#include <rtl/instance.hxx> +#include <osl/getglobalmutex.hxx> +#include <osl/diagnose.h> +#include <com/sun/star/rendering/InterpolationMode.hpp> +#include <vcl/window.hxx> +#include <vcl/graph.hxx> +#include <vcl/canvastools.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> + +#include <cppcanvas/vclfactory.hxx> + +#include <implbitmapcanvas.hxx> +#include <implspritecanvas.hxx> +#include <implpolypolygon.hxx> +#include <implbitmap.hxx> +#include <implrenderer.hxx> +#include <impltext.hxx> +#include <implsprite.hxx> + + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + /* Singleton handling */ + struct InitInstance + { + VCLFactory* operator()() + { + return new VCLFactory(); + } + }; + + VCLFactory& VCLFactory::getInstance() + { + return *rtl_Instance< VCLFactory, InitInstance, ::osl::MutexGuard, + ::osl::GetGlobalMutex >::create( + InitInstance(), ::osl::GetGlobalMutex()); + } + + VCLFactory::VCLFactory() + { + } + + VCLFactory::~VCLFactory() + { + } + + BitmapCanvasSharedPtr VCLFactory::createCanvas( const ::Window& rVCLWindow ) + { + return BitmapCanvasSharedPtr( + new internal::ImplBitmapCanvas( + uno::Reference< rendering::XBitmapCanvas >( + rVCLWindow.GetCanvas(), + uno::UNO_QUERY) ) ); + } + + BitmapCanvasSharedPtr VCLFactory::createCanvas( const uno::Reference< rendering::XBitmapCanvas >& xCanvas ) + { + return BitmapCanvasSharedPtr( + new internal::ImplBitmapCanvas( xCanvas ) ); + } + + SpriteCanvasSharedPtr VCLFactory::createSpriteCanvas( const ::Window& rVCLWindow ) const + { + return SpriteCanvasSharedPtr( + new internal::ImplSpriteCanvas( + uno::Reference< rendering::XSpriteCanvas >( + rVCLWindow.GetSpriteCanvas(), + uno::UNO_QUERY) ) ); + } + + SpriteCanvasSharedPtr VCLFactory::createSpriteCanvas( const uno::Reference< rendering::XSpriteCanvas >& xCanvas ) const + { + return SpriteCanvasSharedPtr( + new internal::ImplSpriteCanvas( xCanvas ) ); + } + + SpriteCanvasSharedPtr VCLFactory::createFullscreenSpriteCanvas( const ::Window& rVCLWindow, + const Size& rFullscreenSize ) const + { + return SpriteCanvasSharedPtr( + new internal::ImplSpriteCanvas( + uno::Reference< rendering::XSpriteCanvas >( + rVCLWindow.GetFullscreenSpriteCanvas( rFullscreenSize ), + uno::UNO_QUERY) ) ); + } + + PolyPolygonSharedPtr VCLFactory::createPolyPolygon( const CanvasSharedPtr& rCanvas, + const ::Polygon& rPoly ) const + { + OSL_ENSURE( rCanvas.get() != NULL && + rCanvas->getUNOCanvas().is(), + "VCLFactory::createPolyPolygon(): Invalid canvas" ); + + if( rCanvas.get() == NULL ) + return PolyPolygonSharedPtr(); + + uno::Reference< rendering::XCanvas > xCanvas( rCanvas->getUNOCanvas() ); + if( !xCanvas.is() ) + return PolyPolygonSharedPtr(); + + return PolyPolygonSharedPtr( + new internal::ImplPolyPolygon( rCanvas, + ::vcl::unotools::xPolyPolygonFromPolygon( + xCanvas->getDevice(), + rPoly) ) ); + } + + PolyPolygonSharedPtr VCLFactory::createPolyPolygon( const CanvasSharedPtr& rCanvas, + const ::PolyPolygon& rPolyPoly ) const + { + OSL_ENSURE( rCanvas.get() != NULL && + rCanvas->getUNOCanvas().is(), + "VCLFactory::createPolyPolygon(): Invalid canvas" ); + + if( rCanvas.get() == NULL ) + return PolyPolygonSharedPtr(); + + uno::Reference< rendering::XCanvas > xCanvas( rCanvas->getUNOCanvas() ); + if( !xCanvas.is() ) + return PolyPolygonSharedPtr(); + + return PolyPolygonSharedPtr( + new internal::ImplPolyPolygon( rCanvas, + ::vcl::unotools::xPolyPolygonFromPolyPolygon( + xCanvas->getDevice(), + rPolyPoly) ) ); + } + + BitmapSharedPtr VCLFactory::createBitmap( const CanvasSharedPtr& rCanvas, + const ::Size& rSize ) const + { + OSL_ENSURE( rCanvas.get() != NULL && + rCanvas->getUNOCanvas().is(), + "VCLFactory::createBitmap(): Invalid canvas" ); + + if( rCanvas.get() == NULL ) + return BitmapSharedPtr(); + + uno::Reference< rendering::XCanvas > xCanvas( rCanvas->getUNOCanvas() ); + if( !xCanvas.is() ) + return BitmapSharedPtr(); + + return BitmapSharedPtr( + new internal::ImplBitmap( rCanvas, + xCanvas->getDevice()->createCompatibleBitmap( + ::vcl::unotools::integerSize2DFromSize(rSize) ) ) ); + } + + BitmapSharedPtr VCLFactory::createAlphaBitmap( const CanvasSharedPtr& rCanvas, + const ::Size& rSize ) const + { + OSL_ENSURE( rCanvas.get() != NULL && + rCanvas->getUNOCanvas().is(), + "VCLFactory::createBitmap(): Invalid canvas" ); + + if( rCanvas.get() == NULL ) + return BitmapSharedPtr(); + + uno::Reference< rendering::XCanvas > xCanvas( rCanvas->getUNOCanvas() ); + if( !xCanvas.is() ) + return BitmapSharedPtr(); + + return BitmapSharedPtr( + new internal::ImplBitmap( rCanvas, + xCanvas->getDevice()->createCompatibleAlphaBitmap( + ::vcl::unotools::integerSize2DFromSize(rSize) ) ) ); + } + + BitmapSharedPtr VCLFactory::createBitmap( const CanvasSharedPtr& rCanvas, + const ::Bitmap& rBitmap ) const + { + OSL_ENSURE( rCanvas.get() != NULL && + rCanvas->getUNOCanvas().is(), + "VCLFactory::createBitmap(): Invalid canvas" ); + + if( rCanvas.get() == NULL ) + return BitmapSharedPtr(); + + uno::Reference< rendering::XCanvas > xCanvas( rCanvas->getUNOCanvas() ); + if( !xCanvas.is() ) + return BitmapSharedPtr(); + + return BitmapSharedPtr( new internal::ImplBitmap( rCanvas, + ::vcl::unotools::xBitmapFromBitmap( + xCanvas->getDevice(), + rBitmap) ) ); + } + + BitmapSharedPtr VCLFactory::createBitmap( const CanvasSharedPtr& rCanvas, + const ::BitmapEx& rBmpEx ) const + { + OSL_ENSURE( rCanvas.get() != NULL && + rCanvas->getUNOCanvas().is(), + "VCLFactory::createBitmap(): Invalid canvas" ); + + if( rCanvas.get() == NULL ) + return BitmapSharedPtr(); + + uno::Reference< rendering::XCanvas > xCanvas( rCanvas->getUNOCanvas() ); + if( !xCanvas.is() ) + return BitmapSharedPtr(); + + return BitmapSharedPtr( new internal::ImplBitmap( rCanvas, + ::vcl::unotools::xBitmapFromBitmapEx( + xCanvas->getDevice(), + rBmpEx) ) ); + } + + RendererSharedPtr VCLFactory::createRenderer( const CanvasSharedPtr& rCanvas, + const ::Graphic& rGraphic, + const Renderer::Parameters& rParms ) const + { + OSL_ENSURE( rCanvas.get() != NULL && + rCanvas->getUNOCanvas().is(), + "VCLFactory::createRenderer(): Invalid canvas" ); + + if( rCanvas.get() == NULL ) + return RendererSharedPtr(); + + uno::Reference< rendering::XCanvas > xCanvas( rCanvas->getUNOCanvas() ); + if( !xCanvas.is() ) + return RendererSharedPtr(); + + if( rGraphic.GetType() == GRAPHIC_GDIMETAFILE ) + return RendererSharedPtr( new internal::ImplRenderer( rCanvas, + rGraphic.GetGDIMetaFile(), + rParms ) ); + else + return RendererSharedPtr( new internal::ImplRenderer( rCanvas, + rGraphic.GetBitmapEx(), + rParms ) ); + } + + RendererSharedPtr VCLFactory::createRenderer( const CanvasSharedPtr& rCanvas, + const ::GDIMetaFile& rMtf, + const Renderer::Parameters& rParms ) const + { + return RendererSharedPtr( new internal::ImplRenderer( rCanvas, + rMtf, + rParms ) ); + } + + SpriteSharedPtr VCLFactory::createAnimatedSprite( const SpriteCanvasSharedPtr& rCanvas, const ::Animation& rAnim ) const + { + OSL_ENSURE( rCanvas.get() != NULL && + rCanvas->getUNOCanvas().is(), + "VCLFactory::createAnimatedSprite(): Invalid canvas" ); + + if( rCanvas.get() == NULL ) + return SpriteSharedPtr(); + + uno::Reference< rendering::XCanvas > xCanvas( rCanvas->getUNOCanvas() ); + if( !xCanvas.is() ) + return SpriteSharedPtr(); + + uno::Reference< rendering::XSpriteCanvas > xSpriteCanvas( rCanvas->getUNOSpriteCanvas() ); + if( !xSpriteCanvas.is() ) + return SpriteSharedPtr(); + + if( rAnim.IsEmpty() ) + return SpriteSharedPtr(); + + internal::ImplSpriteCanvas* pSpriteCanvas = dynamic_cast< internal::ImplSpriteCanvas* >( rCanvas.get() ); + if( !pSpriteCanvas ) + return SpriteSharedPtr(); + + const sal_uInt16 nBitmaps( rAnim.Count() ); + uno::Sequence< uno::Reference< rendering::XBitmap > > aBitmapSequence( nBitmaps ); + uno::Reference< rendering::XBitmap >* pBitmaps = aBitmapSequence.getArray(); + + unsigned int i; + BitmapEx aBmpEx; + BitmapEx aRestoreBuffer; + aBmpEx.SetSizePixel( rAnim.GetDisplaySizePixel() ); + aRestoreBuffer.SetSizePixel( rAnim.GetDisplaySizePixel() ); + aBmpEx.Erase( ::Color( 255, 0,0,0 ) ); // clear alpha channel + aRestoreBuffer = aBmpEx; + const Point aEmptyPoint; + + for( i=0; i<nBitmaps; ++i ) + { + const AnimationBitmap& rAnimBmp( rAnim.Get((sal_uInt16)i) ); + + // Handle dispose according to GIF spec: a + // DISPOSE_PREVIOUS does _not_ mean to revert to the + // previous frame, but to revert to the last frame with + // DISPOSE_NOT + + // dispose previous + if( rAnimBmp.eDisposal == DISPOSE_BACK ) + { + // simply clear bitmap to transparent + aBmpEx.Erase( ::Color( 255, 0,0,0 ) ); + } + else if( rAnimBmp.eDisposal == DISPOSE_PREVIOUS ) + { + // copy in last known full frame + aBmpEx = aRestoreBuffer; + } + // I have exactly _no_ idea what DISPOSE_FULL is supposed + // to do. It's apparently not set anywhere in our code + OSL_ENSURE( rAnimBmp.eDisposal!=DISPOSE_FULL, + "VCLFactory::createAnimatedSprite(): Somebody set the deprecated DISPOSE_FULL at the Animation" ); + + // update display + aBmpEx.CopyPixel( Rectangle( rAnimBmp.aPosPix, + rAnimBmp.aSizePix ), + Rectangle( aEmptyPoint, + rAnimBmp.aSizePix ), + &rAnimBmp.aBmpEx ); + + // store last DISPOSE_NOT frame, for later + // DISPOSE_PREVIOUS updates + if( rAnimBmp.eDisposal == DISPOSE_NOT ) + aRestoreBuffer = aBmpEx; + + pBitmaps[i] = ::vcl::unotools::xBitmapFromBitmapEx( + xCanvas->getDevice(), + aBmpEx); + } + + return pSpriteCanvas->createSpriteFromBitmaps( aBitmapSequence, + rendering::InterpolationMode::NEAREST_NEIGHBOR ); + } + + TextSharedPtr VCLFactory::createText( const CanvasSharedPtr& rCanvas, const ::rtl::OUString& rText ) const + { + return TextSharedPtr( new internal::ImplText( rCanvas, + rText ) ); + } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |