diff options
author | Armin Le Grand <alg@apache.org> | 2012-10-16 08:44:02 +0000 |
---|---|---|
committer | Armin Le Grand <alg@apache.org> | 2012-10-16 08:44:02 +0000 |
commit | 7a652a2b2ab5e0d37e32185c8c5fac3af482bb76 (patch) | |
tree | 3cf859e86a5d4ba2a39e75d1f5bc65a5d8bc10b2 /drawinglayer | |
parent | 9d483a7b084404ed9df6525f09a3bb600a5859f8 (diff) |
#121194# Better support for graphic fill styles which are not bitmaps (svg, metafiles, ..)
Notes
Notes:
merged as: 37aa7d81aacaae12dfe0fd2ade2779235bbf72f1
Diffstat (limited to 'drawinglayer')
36 files changed, 4163 insertions, 3993 deletions
diff --git a/drawinglayer/Library_drawinglayer.mk b/drawinglayer/Library_drawinglayer.mk index 441f1e7be2be..7279af460e8c 100644 --- a/drawinglayer/Library_drawinglayer.mk +++ b/drawinglayer/Library_drawinglayer.mk @@ -66,7 +66,7 @@ $(eval $(call gb_Library_add_exception_objects,drawinglayer,\ drawinglayer/source/animation/animationtiming \ drawinglayer/source/attribute/fillgradientattribute \ drawinglayer/source/attribute/fillhatchattribute \ - drawinglayer/source/attribute/fillbitmapattribute \ + drawinglayer/source/attribute/fillgraphicattribute \ drawinglayer/source/attribute/fontattribute \ drawinglayer/source/attribute/materialattribute3d \ drawinglayer/source/attribute/sdrallattribute3d \ @@ -78,7 +78,7 @@ $(eval $(call gb_Library_add_exception_objects,drawinglayer,\ drawinglayer/source/attribute/sdrlightattribute3d \ drawinglayer/source/attribute/sdrlightingattribute3d \ drawinglayer/source/attribute/sdrsceneattribute3d \ - drawinglayer/source/attribute/sdrfillbitmapattribute \ + drawinglayer/source/attribute/sdrfillgraphicattribute \ drawinglayer/source/attribute/lineattribute \ drawinglayer/source/attribute/linestartendattribute \ drawinglayer/source/attribute/strokeattribute \ @@ -96,9 +96,10 @@ $(eval $(call gb_Library_add_exception_objects,drawinglayer,\ drawinglayer/source/primitive2d/discreteshadowprimitive2d \ drawinglayer/source/primitive2d/embedded3dprimitive2d \ drawinglayer/source/primitive2d/epsprimitive2d \ - drawinglayer/source/primitive2d/fillbitmapprimitive2d \ + drawinglayer/source/primitive2d/fillgraphicprimitive2d \ drawinglayer/source/primitive2d/fillgradientprimitive2d \ drawinglayer/source/primitive2d/fillhatchprimitive2d \ + drawinglayer/source/primitive2d/graphicprimitivehelper2d \ drawinglayer/source/primitive2d/graphicprimitive2d \ drawinglayer/source/primitive2d/gridprimitive2d \ drawinglayer/source/primitive2d/groupprimitive2d \ @@ -165,7 +166,6 @@ $(eval $(call gb_Library_add_exception_objects,drawinglayer,\ drawinglayer/source/processor2d/vclmetafileprocessor2d \ drawinglayer/source/processor2d/contourextractor2d \ drawinglayer/source/processor2d/linegeometryextractor2d \ - drawinglayer/source/processor2d/canvasprocessor \ drawinglayer/source/processor2d/hittestprocessor2d \ drawinglayer/source/processor2d/textaspolygonextractor2d \ drawinglayer/source/processor2d/objectinfoextractor2d \ diff --git a/drawinglayer/Package_inc.mk b/drawinglayer/Package_inc.mk index 7f677dfda91d..e27a64f3d0fb 100644 --- a/drawinglayer/Package_inc.mk +++ b/drawinglayer/Package_inc.mk @@ -35,10 +35,11 @@ $(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/primitive2d/ $(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/primitive2d/discretebitmapprimitive2d.hxx,drawinglayer/primitive2d/discretebitmapprimitive2d.hxx)) $(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/primitive2d/discreteshadowprimitive2d.hxx,drawinglayer/primitive2d/discreteshadowprimitive2d.hxx)) $(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/primitive2d/embedded3dprimitive2d.hxx,drawinglayer/primitive2d/embedded3dprimitive2d.hxx)) -$(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/primitive2d/fillbitmapprimitive2d.hxx,drawinglayer/primitive2d/fillbitmapprimitive2d.hxx)) +$(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/primitive2d/fillgraphicprimitive2d.hxx,drawinglayer/primitive2d/fillgraphicprimitive2d.hxx)) $(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/primitive2d/fillgradientprimitive2d.hxx,drawinglayer/primitive2d/fillgradientprimitive2d.hxx)) $(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/primitive2d/fillhatchprimitive2d.hxx,drawinglayer/primitive2d/fillhatchprimitive2d.hxx)) $(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/primitive2d/graphicprimitive2d.hxx,drawinglayer/primitive2d/graphicprimitive2d.hxx)) +$(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/primitive2d/graphicprimitivehelper2d.hxx,drawinglayer/primitive2d/graphicprimitivehelper2d.hxx)) $(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/primitive2d/gridprimitive2d.hxx,drawinglayer/primitive2d/gridprimitive2d.hxx)) $(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/primitive2d/groupprimitive2d.hxx,drawinglayer/primitive2d/groupprimitive2d.hxx)) $(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/primitive2d/helplineprimitive2d.hxx,drawinglayer/primitive2d/helplineprimitive2d.hxx)) @@ -104,7 +105,6 @@ $(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/processor2d/ $(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/processor2d/vclprocessor2d.hxx,drawinglayer/processor2d/vclprocessor2d.hxx)) $(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/processor2d/vclpixelprocessor2d.hxx,drawinglayer/processor2d/vclpixelprocessor2d.hxx)) $(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/processor2d/vclmetafileprocessor2d.hxx,drawinglayer/processor2d/vclmetafileprocessor2d.hxx)) -$(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/processor2d/canvasprocessor.hxx,drawinglayer/processor2d/canvasprocessor.hxx)) $(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/processor2d/contourextractor2d.hxx,drawinglayer/processor2d/contourextractor2d.hxx)) $(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/processor2d/linegeometryextractor2d.hxx,drawinglayer/processor2d/linegeometryextractor2d.hxx)) $(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/processor2d/hittestprocessor2d.hxx,drawinglayer/processor2d/hittestprocessor2d.hxx)) @@ -120,7 +120,7 @@ $(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/processor3d/ $(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/attribute/fillgradientattribute.hxx,drawinglayer/attribute/fillgradientattribute.hxx)) $(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/attribute/fillhatchattribute.hxx,drawinglayer/attribute/fillhatchattribute.hxx)) -$(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/attribute/fillbitmapattribute.hxx,drawinglayer/attribute/fillbitmapattribute.hxx)) +$(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/attribute/fillgraphicattribute.hxx,drawinglayer/attribute/fillgraphicattribute.hxx)) $(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/attribute/fontattribute.hxx,drawinglayer/attribute/fontattribute.hxx)) $(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/attribute/materialattribute3d.hxx,drawinglayer/attribute/materialattribute3d.hxx)) $(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/attribute/sdrallattribute3d.hxx,drawinglayer/attribute/sdrallattribute3d.hxx)) @@ -132,7 +132,7 @@ $(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/attribute/sd $(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/attribute/sdrlightattribute3d.hxx,drawinglayer/attribute/sdrlightattribute3d.hxx)) $(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/attribute/sdrlightingattribute3d.hxx,drawinglayer/attribute/sdrlightingattribute3d.hxx)) $(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/attribute/sdrsceneattribute3d.hxx,drawinglayer/attribute/sdrsceneattribute3d.hxx)) -$(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/attribute/sdrfillbitmapattribute.hxx,drawinglayer/attribute/sdrfillbitmapattribute.hxx)) +$(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/attribute/sdrfillgraphicattribute.hxx,drawinglayer/attribute/sdrfillgraphicattribute.hxx)) $(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/attribute/strokeattribute.hxx,drawinglayer/attribute/strokeattribute.hxx)) $(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/attribute/lineattribute.hxx,drawinglayer/attribute/lineattribute.hxx)) $(eval $(call gb_Package_add_file,drawinglayer_inc,inc/drawinglayer/attribute/linestartendattribute.hxx,drawinglayer/attribute/linestartendattribute.hxx)) diff --git a/drawinglayer/inc/drawinglayer/attribute/fillbitmapattribute.hxx b/drawinglayer/inc/drawinglayer/attribute/fillgraphicattribute.hxx index 776b3483b791..9e70ef79b026 100644..100755 --- a/drawinglayer/inc/drawinglayer/attribute/fillbitmapattribute.hxx +++ b/drawinglayer/inc/drawinglayer/attribute/fillgraphicattribute.hxx @@ -21,22 +21,21 @@ -#ifndef INCLUDED_DRAWINGLAYER_ATTRIBUTE_FILLBITMAPATTRIBUTE_HXX -#define INCLUDED_DRAWINGLAYER_ATTRIBUTE_FILLBITMAPATTRIBUTE_HXX +#ifndef INCLUDED_DRAWINGLAYER_ATTRIBUTE_FILLGRAPHICATTRIBUTE_HXX +#define INCLUDED_DRAWINGLAYER_ATTRIBUTE_FILLGRAPHICATTRIBUTE_HXX #include <drawinglayer/drawinglayerdllapi.h> ////////////////////////////////////////////////////////////////////////////// // predefines -class BitmapEx; +class Graphic; namespace basegfx { - class B2DPoint; - class B2DVector; + class B2DRange; } namespace drawinglayer { namespace attribute { - class ImpFillBitmapAttribute; + class ImpFillGraphicAttribute; }} ////////////////////////////////////////////////////////////////////////////// @@ -45,40 +44,42 @@ namespace drawinglayer { namespace attribute { - class DRAWINGLAYER_DLLPUBLIC FillBitmapAttribute + class DRAWINGLAYER_DLLPUBLIC FillGraphicAttribute { private: - ImpFillBitmapAttribute* mpFillBitmapAttribute; + ImpFillGraphicAttribute* mpFillGraphicAttribute; public: /// constructors/assignmentoperator/destructor - FillBitmapAttribute( - const BitmapEx& rBitmapEx, - const basegfx::B2DPoint& rTopLeft, - const basegfx::B2DVector& rSize, - bool bTiling); - FillBitmapAttribute(); - FillBitmapAttribute(const FillBitmapAttribute& rCandidate); - FillBitmapAttribute& operator=(const FillBitmapAttribute& rCandidate); - ~FillBitmapAttribute(); + FillGraphicAttribute( + const Graphic& rGraphic, + const basegfx::B2DRange& rGraphicRange, + bool bTiling = false, + double fOffsetX = 0.0, + double fOffsetY = 0.0); + FillGraphicAttribute(); + FillGraphicAttribute(const FillGraphicAttribute& rCandidate); + FillGraphicAttribute& operator=(const FillGraphicAttribute& rCandidate); + ~FillGraphicAttribute(); // checks if the incarnation is default constructed bool isDefault() const; // compare operator - bool operator==(const FillBitmapAttribute& rCandidate) const; + bool operator==(const FillGraphicAttribute& rCandidate) const; // data read access - const BitmapEx& getBitmapEx() const; - const basegfx::B2DPoint& getTopLeft() const; - const basegfx::B2DVector& getSize() const; + const Graphic& getGraphic() const; + const basegfx::B2DRange& getGraphicRange() const; bool getTiling() const; + double getOffsetX() const; + double getOffsetY() const; }; } // end of namespace attribute } // end of namespace drawinglayer ////////////////////////////////////////////////////////////////////////////// -#endif //INCLUDED_DRAWINGLAYER_ATTRIBUTE_FILLBITMAPATTRIBUTE_HXX +#endif //INCLUDED_DRAWINGLAYER_ATTRIBUTE_FILLGRAPHICATTRIBUTE_HXX // eof diff --git a/drawinglayer/inc/drawinglayer/attribute/sdrfillattribute.hxx b/drawinglayer/inc/drawinglayer/attribute/sdrfillattribute.hxx index bb1576023172..ecf15e0c80ae 100644 --- a/drawinglayer/inc/drawinglayer/attribute/sdrfillattribute.hxx +++ b/drawinglayer/inc/drawinglayer/attribute/sdrfillattribute.hxx @@ -34,7 +34,7 @@ namespace drawinglayer { namespace attribute { class ImpSdrFillAttribute; class FillGradientAttribute; class FillHatchAttribute; - class SdrFillBitmapAttribute; + class SdrFillGraphicAttribute; }} ////////////////////////////////////////////////////////////////////////////// @@ -55,7 +55,7 @@ namespace drawinglayer const basegfx::BColor& rColor, const FillGradientAttribute& rGradient, const FillHatchAttribute& rHatch, - const SdrFillBitmapAttribute& rBitmap); + const SdrFillGraphicAttribute& rFillGraphic); SdrFillAttribute(); SdrFillAttribute(const SdrFillAttribute& rCandidate); SdrFillAttribute& operator=(const SdrFillAttribute& rCandidate); @@ -72,7 +72,7 @@ namespace drawinglayer const basegfx::BColor& getColor() const; const FillGradientAttribute& getGradient() const; const FillHatchAttribute& getHatch() const; - const SdrFillBitmapAttribute& getBitmap() const; + const SdrFillGraphicAttribute& getFillGraphic() const; }; } // end of namespace attribute } // end of namespace drawinglayer diff --git a/drawinglayer/inc/drawinglayer/attribute/sdrfillbitmapattribute.hxx b/drawinglayer/inc/drawinglayer/attribute/sdrfillgraphicattribute.hxx index 6a9e9c4a9121..3a4acac21a80 100644..100755 --- a/drawinglayer/inc/drawinglayer/attribute/sdrfillbitmapattribute.hxx +++ b/drawinglayer/inc/drawinglayer/attribute/sdrfillgraphicattribute.hxx @@ -21,15 +21,15 @@ -#ifndef INCLUDED_DRAWINGLAYER_ATTRIBUTE_SDRFILLBITMAPATTRIBUTE_HXX -#define INCLUDED_DRAWINGLAYER_ATTRIBUTE_SDRFILLBITMAPATTRIBUTE_HXX +#ifndef INCLUDED_DRAWINGLAYER_ATTRIBUTE_SDRFILLGRAPHICATTRIBUTE_HXX +#define INCLUDED_DRAWINGLAYER_ATTRIBUTE_SDRFILLGRAPHICATTRIBUTE_HXX #include <drawinglayer/drawinglayerdllapi.h> ////////////////////////////////////////////////////////////////////////////// // predefines -class BitmapEx; +class Graphic; namespace basegfx { class B2DRange; @@ -37,8 +37,8 @@ namespace basegfx { } namespace drawinglayer { namespace attribute { - class FillBitmapAttribute; - class ImpSdrFillBitmapAttribute; + class FillGraphicAttribute; + class ImpSdrFillGraphicAttribute; }} ////////////////////////////////////////////////////////////////////////////// @@ -47,15 +47,15 @@ namespace drawinglayer { namespace attribute { - class DRAWINGLAYER_DLLPUBLIC SdrFillBitmapAttribute + class DRAWINGLAYER_DLLPUBLIC SdrFillGraphicAttribute { private: - ImpSdrFillBitmapAttribute* mpSdrFillBitmapAttribute; + ImpSdrFillGraphicAttribute* mpSdrFillGraphicAttribute; public: /// constructors/assignmentoperator/destructor - SdrFillBitmapAttribute( - const BitmapEx& rBitmapEx, + SdrFillGraphicAttribute( + const Graphic& rFillGraphic, const basegfx::B2DVector& rSize, const basegfx::B2DVector& rOffset, const basegfx::B2DVector& rOffsetPosition, @@ -63,19 +63,19 @@ namespace drawinglayer bool bTiling, bool bStretch, bool bLogSize); - SdrFillBitmapAttribute(); - SdrFillBitmapAttribute(const SdrFillBitmapAttribute& rCandidate); - SdrFillBitmapAttribute& operator=(const SdrFillBitmapAttribute& rCandidate); - ~SdrFillBitmapAttribute(); + SdrFillGraphicAttribute(); + SdrFillGraphicAttribute(const SdrFillGraphicAttribute& rCandidate); + SdrFillGraphicAttribute& operator=(const SdrFillGraphicAttribute& rCandidate); + ~SdrFillGraphicAttribute(); // checks if the incarnation is default constructed bool isDefault() const; // compare operator - bool operator==(const SdrFillBitmapAttribute& rCandidate) const; + bool operator==(const SdrFillGraphicAttribute& rCandidate) const; // data read access - const BitmapEx& getBitmapEx() const; + const Graphic& getFillGraphic() const; const basegfx::B2DVector& getSize() const; const basegfx::B2DVector& getOffset() const; const basegfx::B2DVector& getOffsetPosition() const; @@ -84,14 +84,14 @@ namespace drawinglayer bool getStretch() const; bool getLogSize() const; - // FillBitmapAttribute generator - FillBitmapAttribute getFillBitmapAttribute(const basegfx::B2DRange& rRange) const; + // FillGraphicAttribute generator + FillGraphicAttribute createFillGraphicAttribute(const basegfx::B2DRange& rRange) const; }; } // end of namespace attribute } // end of namespace drawinglayer ////////////////////////////////////////////////////////////////////////////// -#endif //INCLUDED_DRAWINGLAYER_ATTRIBUTE_SDRFILLBITMAPATTRIBUTE_HXX +#endif //INCLUDED_DRAWINGLAYER_ATTRIBUTE_SDRFILLGRAPHICATTRIBUTE_HXX // eof diff --git a/drawinglayer/inc/drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx b/drawinglayer/inc/drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx index aac9dfb7e170..bc80af9cb3f3 100644 --- a/drawinglayer/inc/drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx +++ b/drawinglayer/inc/drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx @@ -44,7 +44,7 @@ #define PRIMITIVE2D_ID_BITMAPPRIMITIVE2D (PRIMITIVE2D_ID_RANGE_DRAWINGLAYER| 5) #define PRIMITIVE2D_ID_CONTROLPRIMITIVE2D (PRIMITIVE2D_ID_RANGE_DRAWINGLAYER| 6) #define PRIMITIVE2D_ID_EMBEDDED3DPRIMITIVE2D (PRIMITIVE2D_ID_RANGE_DRAWINGLAYER| 7) -#define PRIMITIVE2D_ID_FILLBITMAPPRIMITIVE2D (PRIMITIVE2D_ID_RANGE_DRAWINGLAYER| 8) +#define PRIMITIVE2D_ID_FILLGRAPHICPRIMITIVE2D (PRIMITIVE2D_ID_RANGE_DRAWINGLAYER| 8) #define PRIMITIVE2D_ID_FILLGRADIENTPRIMITIVE2D (PRIMITIVE2D_ID_RANGE_DRAWINGLAYER| 9) #define PRIMITIVE2D_ID_FILLHATCHPRIMITIVE2D (PRIMITIVE2D_ID_RANGE_DRAWINGLAYER| 10) #define PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D (PRIMITIVE2D_ID_RANGE_DRAWINGLAYER| 11) @@ -65,7 +65,7 @@ #define PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D (PRIMITIVE2D_ID_RANGE_DRAWINGLAYER| 26) #define PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D (PRIMITIVE2D_ID_RANGE_DRAWINGLAYER| 27) #define PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D (PRIMITIVE2D_ID_RANGE_DRAWINGLAYER| 28) -#define PRIMITIVE2D_ID_POLYPOLYGONBITMAPPRIMITIVE2D (PRIMITIVE2D_ID_RANGE_DRAWINGLAYER| 29) +#define PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D (PRIMITIVE2D_ID_RANGE_DRAWINGLAYER| 29) #define PRIMITIVE2D_ID_SCENEPRIMITIVE2D (PRIMITIVE2D_ID_RANGE_DRAWINGLAYER| 30) #define PRIMITIVE2D_ID_SHADOWPRIMITIVE2D (PRIMITIVE2D_ID_RANGE_DRAWINGLAYER| 31) #define PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D (PRIMITIVE2D_ID_RANGE_DRAWINGLAYER| 32) diff --git a/drawinglayer/inc/drawinglayer/primitive2d/fillbitmapprimitive2d.hxx b/drawinglayer/inc/drawinglayer/primitive2d/fillgraphicprimitive2d.hxx index 0ce8a3683bda..6658e6d01b43 100644..100755 --- a/drawinglayer/inc/drawinglayer/primitive2d/fillbitmapprimitive2d.hxx +++ b/drawinglayer/inc/drawinglayer/primitive2d/fillgraphicprimitive2d.hxx @@ -21,13 +21,13 @@ -#ifndef INCLUDED_DRAWINGLAYER_PRIMITIVE2D_FILLBITMAPPRIMITIVE2D_HXX -#define INCLUDED_DRAWINGLAYER_PRIMITIVE2D_FILLBITMAPPRIMITIVE2D_HXX +#ifndef INCLUDED_DRAWINGLAYER_PRIMITIVE2D_FILLGRAPHICPRIMITIVE2D_HXX +#define INCLUDED_DRAWINGLAYER_PRIMITIVE2D_FILLGRAPHICPRIMITIVE2D_HXX #include <drawinglayer/drawinglayerdllapi.h> #include <drawinglayer/primitive2d/baseprimitive2d.hxx> #include <basegfx/matrix/b2dhommatrix.hxx> -#include <drawinglayer/attribute/fillbitmapattribute.hxx> +#include <drawinglayer/attribute/fillgraphicattribute.hxx> ////////////////////////////////////////////////////////////////////////////// // FillbitmapPrimitive2D class @@ -36,10 +36,10 @@ namespace drawinglayer { namespace primitive2d { - /** FillBitmapPrimitive2D class + /** FillGraphicPrimitive2D class This class defines a bitmap filling for a rectangular area. The - Range is defined by the Transformation, the fill by the FillBitmapAttribute. + Range is defined by the Transformation, the fill by the FillGraphicAttribute. There, the fill consists of a Bitmap (not transparent) defining the fill data and a Point/Vector pair defining the relative position/size [0.0 .. 1.0] inside the area where the bitmap is positioned. A flag defines then if this @@ -49,14 +49,14 @@ namespace drawinglayer decomposition, but on pixel oututs the areas where the tiled pieces are aligned tend to show up (one overlapping or empty pixel) */ - class DRAWINGLAYER_DLLPUBLIC FillBitmapPrimitive2D : public BufferedDecompositionPrimitive2D + class DRAWINGLAYER_DLLPUBLIC FillGraphicPrimitive2D : public BufferedDecompositionPrimitive2D { private: /// the geometric definition basegfx::B2DHomMatrix maTransformation; /// the fill attributes - attribute::FillBitmapAttribute maFillBitmap; + attribute::FillGraphicAttribute maFillGraphic; protected: /// local decomposition. @@ -64,13 +64,13 @@ namespace drawinglayer public: /// constructor - FillBitmapPrimitive2D( + FillGraphicPrimitive2D( const basegfx::B2DHomMatrix& rTransformation, - const attribute::FillBitmapAttribute& rFillBitmap); + const attribute::FillGraphicAttribute& rFillGraphic); /// data read access const basegfx::B2DHomMatrix& getTransformation() const { return maTransformation; } - const attribute::FillBitmapAttribute& getFillBitmap() const { return maFillBitmap; } + const attribute::FillGraphicAttribute& getFillGraphic() const { return maFillGraphic; } /// compare operator virtual bool operator==( const BasePrimitive2D& rPrimitive ) const; @@ -86,7 +86,7 @@ namespace drawinglayer ////////////////////////////////////////////////////////////////////////////// -#endif //INCLUDED_DRAWINGLAYER_PRIMITIVE2D_FILLBITMAPPRIMITIVE2D_HXX +#endif //INCLUDED_DRAWINGLAYER_PRIMITIVE2D_FILLGRAPHICPRIMITIVE2D_HXX ////////////////////////////////////////////////////////////////////////////// // eof diff --git a/drawinglayer/inc/drawinglayer/primitive2d/graphicprimitivehelper2d.hxx b/drawinglayer/inc/drawinglayer/primitive2d/graphicprimitivehelper2d.hxx new file mode 100755 index 000000000000..e47ad3e331d7 --- /dev/null +++ b/drawinglayer/inc/drawinglayer/primitive2d/graphicprimitivehelper2d.hxx @@ -0,0 +1,60 @@ +/************************************************************** + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + *************************************************************/ + + + +#ifndef INCLUDED_DRAWINGLAYER_PRIMITIVE2D_GRAPHICPRIMITIVEHELPER2D_HXX +#define INCLUDED_DRAWINGLAYER_PRIMITIVE2D_GRAPHICPRIMITIVEHELPER2D_HXX + +#include <drawinglayer/drawinglayerdllapi.h> +#include <drawinglayer/primitive2d/baseprimitive2d.hxx> + +////////////////////////////////////////////////////////////////////////////// +// predefines + +class Graphic; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive2d + { + /** Helper method with supports decomposing a Graphic with all + possible contents to lower level primitives. + + #121194# Unified to use this helper for FillGraphicPrimitive2D + and GraphicPrimitive2D at the same time. It is able to handle + Bitmaps (with the sub-categories animated bitmap, and SVG), + and Metafiles. + */ + Primitive2DSequence create2DDecompositionOfGraphic( + const Graphic& rGraphic, + const basegfx::B2DHomMatrix& rTransform); + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +#endif // INCLUDED_DRAWINGLAYER_PRIMITIVE2D_GRAPHICPRIMITIVEHELPER2D_HXX + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/inc/drawinglayer/primitive2d/polypolygonprimitive2d.hxx b/drawinglayer/inc/drawinglayer/primitive2d/polypolygonprimitive2d.hxx index ebd3a7361506..1fd133d3f629 100644 --- a/drawinglayer/inc/drawinglayer/primitive2d/polypolygonprimitive2d.hxx +++ b/drawinglayer/inc/drawinglayer/primitive2d/polypolygonprimitive2d.hxx @@ -26,7 +26,7 @@ #include <drawinglayer/drawinglayerdllapi.h> #include <drawinglayer/primitive2d/baseprimitive2d.hxx> -#include <drawinglayer/attribute/fillbitmapattribute.hxx> +#include <drawinglayer/attribute/fillgraphicattribute.hxx> #include <basegfx/polygon/b2dpolypolygon.hxx> #include <drawinglayer/attribute/lineattribute.hxx> #include <drawinglayer/attribute/strokeattribute.hxx> @@ -391,26 +391,26 @@ namespace drawinglayer } // end of namespace drawinglayer ////////////////////////////////////////////////////////////////////////////// -// PolyPolygonBitmapPrimitive2D class +// PolyPolygonGraphicPrimitive2D class namespace drawinglayer { namespace primitive2d { - /** PolyPolygonBitmapPrimitive2D class + /** PolyPolygonGraphicPrimitive2D class This primitive defines a PolyPolygon filled with bitmap data (including transparence). The decomosition will create a MaskPrimitive2D - containing a FillBitmapPrimitive2D. + containing a FillGraphicPrimitive2D. */ - class DRAWINGLAYER_DLLPUBLIC PolyPolygonBitmapPrimitive2D : public BufferedDecompositionPrimitive2D + class DRAWINGLAYER_DLLPUBLIC PolyPolygonGraphicPrimitive2D : public BufferedDecompositionPrimitive2D { private: /// the PolyPolygon geometry basegfx::B2DPolyPolygon maPolyPolygon; /// the bitmap fill definition (may include tiling) - attribute::FillBitmapAttribute maFillBitmap; + attribute::FillGraphicAttribute maFillGraphic; protected: /// local decomposition. @@ -418,13 +418,13 @@ namespace drawinglayer public: /// constructor - PolyPolygonBitmapPrimitive2D( + PolyPolygonGraphicPrimitive2D( const basegfx::B2DPolyPolygon& rPolyPolygon, - const attribute::FillBitmapAttribute& rFillBitmap); + const attribute::FillGraphicAttribute& rFillGraphic); /// data read access const basegfx::B2DPolyPolygon& getB2DPolyPolygon() const { return maPolyPolygon; } - const attribute::FillBitmapAttribute& getFillBitmap() const { return maFillBitmap; } + const attribute::FillGraphicAttribute& getFillGraphic() const { return maFillGraphic; } /// compare operator virtual bool operator==(const BasePrimitive2D& rPrimitive) const; diff --git a/drawinglayer/inc/drawinglayer/primitive3d/textureprimitive3d.hxx b/drawinglayer/inc/drawinglayer/primitive3d/textureprimitive3d.hxx index 8dc7cbe66d09..0422251837ca 100644 --- a/drawinglayer/inc/drawinglayer/primitive3d/textureprimitive3d.hxx +++ b/drawinglayer/inc/drawinglayer/primitive3d/textureprimitive3d.hxx @@ -26,7 +26,7 @@ #include <drawinglayer/drawinglayerdllapi.h> #include <drawinglayer/primitive3d/groupprimitive3d.hxx> -#include <drawinglayer/attribute/fillbitmapattribute.hxx> +#include <drawinglayer/attribute/fillgraphicattribute.hxx> #include <basegfx/matrix/b2dhommatrix.hxx> #include <basegfx/vector/b2dvector.hxx> #include <drawinglayer/attribute/fillgradientattribute.hxx> @@ -172,19 +172,19 @@ namespace drawinglayer { private: /// bitmap fill attribute - attribute::FillBitmapAttribute maFillBitmapAttribute; + attribute::FillGraphicAttribute maFillGraphicAttribute; public: /// constructor BitmapTexturePrimitive3D( - const attribute::FillBitmapAttribute& rFillBitmapAttribute, + const attribute::FillGraphicAttribute& rFillGraphicAttribute, const Primitive3DSequence& rChildren, const basegfx::B2DVector& rTextureSize, bool bModulate, bool bFilter); /// data read access - const attribute::FillBitmapAttribute& getFillBitmapAttribute() const { return maFillBitmapAttribute; } + const attribute::FillGraphicAttribute& getFillGraphicAttribute() const { return maFillGraphicAttribute; } /// compare operator virtual bool operator==(const BasePrimitive3D& rPrimitive) const; diff --git a/drawinglayer/inc/drawinglayer/processor2d/canvasprocessor.hxx b/drawinglayer/inc/drawinglayer/processor2d/canvasprocessor.hxx deleted file mode 100644 index 2b3851899448..000000000000 --- a/drawinglayer/inc/drawinglayer/processor2d/canvasprocessor.hxx +++ /dev/null @@ -1,125 +0,0 @@ -/************************************************************** - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - *************************************************************/ - - - -#ifndef _DRAWINGLAYER_PROCESSOR_CANVASPROCESSOR_HXX -#define _DRAWINGLAYER_PROCESSOR_CANVASPROCESSOR_HXX - -#include <drawinglayer/drawinglayerdllapi.h> -#include <drawinglayer/processor2d/baseprocessor2d.hxx> -#include <basegfx/matrix/b2dhommatrix.hxx> -#include <basegfx/color/bcolormodifier.hxx> -#include <svtools/optionsdrawinglayer.hxx> -#include <com/sun/star/rendering/ViewState.hpp> -#include <com/sun/star/rendering/RenderState.hpp> -#include <i18npool/lang.h> -#include <basegfx/polygon/b2dpolypolygon.hxx> -#include <vcl/mapmod.hxx> - -////////////////////////////////////////////////////////////////////////////// -// forward declaration - -namespace basegfx { - class BColor; - class B2DPolygon; -} - -namespace com { namespace sun { namespace star { namespace rendering { - class XCanvas; - class XPolyPolygon2D; -}}}} - -namespace drawinglayer { namespace primitive2d { - class MaskPrimitive2D; - class MetafilePrimitive2D; - class TextSimplePortionPrimitive2D; - class BitmapPrimitive2D; - class TransparencePrimitive2D; - class PolygonStrokePrimitive2D; - class FillBitmapPrimitive2D; - class UnifiedTransparencePrimitive2D; -}} - -////////////////////////////////////////////////////////////////////////////// - -namespace drawinglayer -{ - namespace processor2d - { - /** canvasProcessor2D class - - A basic implementation of a renderer for com::sun::star::rendering::XCanvas - as a target - */ - class DRAWINGLAYER_DLLPUBLIC canvasProcessor2D : public BaseProcessor2D - { - private: - // the (current) destination OutDev and canvas - OutputDevice* mpOutputDevice; - com::sun::star::uno::Reference< com::sun::star::rendering::XCanvas > mxCanvas; - com::sun::star::rendering::ViewState maViewState; - com::sun::star::rendering::RenderState maRenderState; - - // the modifiedColorPrimitive stack - basegfx::BColorModifierStack maBColorModifierStack; - - // SvtOptionsDrawinglayer incarnation to react on diverse settings - const SvtOptionsDrawinglayer maDrawinglayerOpt; - - // the current clipping PolyPolygon from MaskPrimitive2D, always in - // object coordinates - basegfx::B2DPolyPolygon maClipPolyPolygon; - - // determined LanguageType - LanguageType meLang; - - // as tooling, the process() implementation takes over API handling and calls this - // virtual render method when the primitive implementation is BasePrimitive2D-based. - virtual void processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate); - - // direct primitive renderer support - void impRenderMaskPrimitive2D(const primitive2d::MaskPrimitive2D& rMaskCandidate); - void impRenderMetafilePrimitive2D(const primitive2d::MetafilePrimitive2D& rMetaCandidate); - void impRenderTextSimplePortionPrimitive2D(const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate); - void impRenderBitmapPrimitive2D(const primitive2d::BitmapPrimitive2D& rBitmapCandidate); - void impRenderTransparencePrimitive2D(const primitive2d::TransparencePrimitive2D& rTransparenceCandidate); - void impRenderPolygonStrokePrimitive2D(const primitive2d::PolygonStrokePrimitive2D& rPolygonStrokePrimitive); - void impRenderFillBitmapPrimitive2D(const primitive2d::FillBitmapPrimitive2D& rFillBitmapPrimitive2D); - void impRenderUnifiedTransparencePrimitive2D(const primitive2d::UnifiedTransparencePrimitive2D& rUniTransparenceCandidate); - - public: - canvasProcessor2D( - const geometry::ViewInformation2D& rViewInformation, - OutputDevice& rOutDev); - virtual ~canvasProcessor2D(); - - // access to Drawinglayer configuration options - const SvtOptionsDrawinglayer& getOptionsDrawinglayer() const { return maDrawinglayerOpt; } - }; - } // end of namespace processor2d -} // end of namespace drawinglayer - -////////////////////////////////////////////////////////////////////////////// - -#endif //_DRAWINGLAYER_PROCESSOR_CANVASPROCESSOR_HXX - -// eof diff --git a/drawinglayer/inc/drawinglayer/processor2d/vclprocessor2d.hxx b/drawinglayer/inc/drawinglayer/processor2d/vclprocessor2d.hxx index 41fc262299e4..286995436b9a 100644 --- a/drawinglayer/inc/drawinglayer/processor2d/vclprocessor2d.hxx +++ b/drawinglayer/inc/drawinglayer/processor2d/vclprocessor2d.hxx @@ -38,9 +38,9 @@ namespace drawinglayer { namespace primitive2d { class TextSimplePortionPrimitive2D; class PolygonHairlinePrimitive2D; class BitmapPrimitive2D; - class FillBitmapPrimitive2D; + class FillGraphicPrimitive2D; class PolyPolygonGradientPrimitive2D; - class PolyPolygonBitmapPrimitive2D; + class PolyPolygonGraphicPrimitive2D; class PolyPolygonColorPrimitive2D; class MetafilePrimitive2D; class MaskPrimitive2D; @@ -96,9 +96,9 @@ namespace drawinglayer void RenderTextSimpleOrDecoratedPortionPrimitive2D(const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate); void RenderPolygonHairlinePrimitive2D(const primitive2d::PolygonHairlinePrimitive2D& rPolygonCandidate, bool bPixelBased); void RenderBitmapPrimitive2D(const primitive2d::BitmapPrimitive2D& rBitmapCandidate); - void RenderFillBitmapPrimitive2D(const primitive2d::FillBitmapPrimitive2D& rFillBitmapCandidate); + void RenderFillGraphicPrimitive2D(const primitive2d::FillGraphicPrimitive2D& rFillBitmapCandidate); void RenderPolyPolygonGradientPrimitive2D(const primitive2d::PolyPolygonGradientPrimitive2D& rPolygonCandidate); - void RenderPolyPolygonBitmapPrimitive2D(const primitive2d::PolyPolygonBitmapPrimitive2D& rPolygonCandidate); + void RenderPolyPolygonGraphicPrimitive2D(const primitive2d::PolyPolygonGraphicPrimitive2D& rPolygonCandidate); void RenderPolyPolygonColorPrimitive2D(const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate); void RenderMetafilePrimitive2D(const primitive2d::MetafilePrimitive2D& rPolygonCandidate); void RenderMaskPrimitive2DPixel(const primitive2d::MaskPrimitive2D& rMaskCandidate); diff --git a/drawinglayer/inc/drawinglayer/texture/texture.hxx b/drawinglayer/inc/drawinglayer/texture/texture.hxx index d5a4721f6112..aa62d1eb3d58 100644 --- a/drawinglayer/inc/drawinglayer/texture/texture.hxx +++ b/drawinglayer/inc/drawinglayer/texture/texture.hxx @@ -309,16 +309,27 @@ namespace drawinglayer { namespace texture { + // This class applies a tiling to the unit range. The given range + // will be repeated inside the unit range in X and Y and for each + // tile a matrix will be created (by appendTransformations) that + // represents the needed transformation to map a filling in unit + // coordinates to that tile. + // When offsetX is given, every 2nd line will be ofsetted by the + // given percentage value (offsetX has to be 0.0 <= offsetX <= 1.0). + // Accordingly to offsetY. If both are given, offsetX is preferred + // and offsetY is ignored. class DRAWINGLAYER_DLLPUBLIC GeoTexSvxTiled : public GeoTexSvx { protected: - basegfx::B2DPoint maTopLeft; - basegfx::B2DVector maSize; + basegfx::B2DRange maRange; + double mfOffsetX; + double mfOffsetY; public: GeoTexSvxTiled( - const basegfx::B2DPoint& rTopLeft, - const basegfx::B2DVector& rSize); + const basegfx::B2DRange& rRange, + double fOffsetX = 0.0, + double fOffsetY = 0.0); virtual ~GeoTexSvxTiled(); // compare operator diff --git a/drawinglayer/inc/drawinglayer/texture/texture3d.hxx b/drawinglayer/inc/drawinglayer/texture/texture3d.hxx index bda0b17b4c77..33173fc2cf43 100644 --- a/drawinglayer/inc/drawinglayer/texture/texture3d.hxx +++ b/drawinglayer/inc/drawinglayer/texture/texture3d.hxx @@ -26,7 +26,7 @@ #include <drawinglayer/drawinglayerdllapi.h> #include <drawinglayer/texture/texture.hxx> -#include <vcl/bitmap.hxx> +#include <vcl/bitmapex.hxx> ////////////////////////////////////////////////////////////////////////////// // predeclarations @@ -48,7 +48,9 @@ namespace drawinglayer double mfOpacity; public: - GeoTexSvxMono(const basegfx::BColor& rSingleColor, double fOpacity); + GeoTexSvxMono( + const basegfx::BColor& rSingleColor, + double fOpacity); // compare operator virtual bool operator==(const GeoTexSvx& rGeoTexSvx) const; @@ -64,22 +66,32 @@ namespace drawinglayer { namespace texture { - class DRAWINGLAYER_DLLPUBLIC GeoTexSvxBitmap : public GeoTexSvx + class DRAWINGLAYER_DLLPUBLIC GeoTexSvxBitmapEx : public GeoTexSvx { protected: - Bitmap maBitmap; - BitmapReadAccess* mpRead; + BitmapEx maBitmapEx; + BitmapReadAccess* mpReadBitmap; + Bitmap maTransparence; + BitmapReadAccess* mpReadTransparence; basegfx::B2DPoint maTopLeft; basegfx::B2DVector maSize; double mfMulX; double mfMulY; + /// bitfield + bool mbIsAlpha : 1; + bool mbIsTransparent : 1; + // helpers bool impIsValid(const basegfx::B2DPoint& rUV, sal_Int32& rX, sal_Int32& rY) const; + sal_uInt8 impGetTransparence(sal_Int32& rX, sal_Int32& rY) const; public: - GeoTexSvxBitmap(const Bitmap& rBitmap, const basegfx::B2DPoint& rTopLeft, const basegfx::B2DVector& rSize); - virtual ~GeoTexSvxBitmap(); + GeoTexSvxBitmapEx( + const BitmapEx& rBitmapEx, + const basegfx::B2DRange& rRange); + virtual ~GeoTexSvxBitmapEx(); + virtual void modifyBColor(const basegfx::B2DPoint& rUV, basegfx::BColor& rBColor, double& rfOpacity) const; virtual void modifyOpacity(const basegfx::B2DPoint& rUV, double& rfOpacity) const; }; @@ -92,30 +104,26 @@ namespace drawinglayer { namespace texture { - class DRAWINGLAYER_DLLPUBLIC GeoTexSvxBitmapTiled : public GeoTexSvxBitmap + class DRAWINGLAYER_DLLPUBLIC GeoTexSvxBitmapExTiled : public GeoTexSvxBitmapEx { protected: - // helpers - basegfx::B2DPoint impGetCorrected(const basegfx::B2DPoint& rUV) const - { - double fX(fmod(rUV.getX() - maTopLeft.getX(), maSize.getX())); - double fY(fmod(rUV.getY() - maTopLeft.getY(), maSize.getY())); + double mfOffsetX; + double mfOffsetY; - if(fX < 0.0) - { - fX += maSize.getX(); - } + /// bitfield + bool mbUseOffsetX : 1; + bool mbUseOffsetY : 1; - if(fY < 0.0) - { - fY += maSize.getY(); - } - - return basegfx::B2DPoint(fX + maTopLeft.getX(), fY + maTopLeft.getY()); - } + // helpers + basegfx::B2DPoint impGetCorrected(const basegfx::B2DPoint& rUV) const; public: - GeoTexSvxBitmapTiled(const Bitmap& rBitmap, const basegfx::B2DPoint& rTopLeft, const basegfx::B2DVector& rSize); + GeoTexSvxBitmapExTiled( + const BitmapEx& rBitmapEx, + const basegfx::B2DRange& rRange, + double fOffsetX = 0.0, + double fOffsetY = 0.0); + virtual void modifyBColor(const basegfx::B2DPoint& rUV, basegfx::BColor& rBColor, double& rfOpacity) const; virtual void modifyOpacity(const basegfx::B2DPoint& rUV, double& rfOpacity) const; }; diff --git a/drawinglayer/source/attribute/fillbitmapattribute.cxx b/drawinglayer/source/attribute/fillbitmapattribute.cxx deleted file mode 100644 index d0a42828518b..000000000000 --- a/drawinglayer/source/attribute/fillbitmapattribute.cxx +++ /dev/null @@ -1,195 +0,0 @@ -/************************************************************** - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - *************************************************************/ - - - -// MARKER(update_precomp.py): autogen include statement, do not remove -#include "precompiled_drawinglayer.hxx" - -#include <drawinglayer/attribute/fillbitmapattribute.hxx> -#include <vcl/bitmapex.hxx> - -////////////////////////////////////////////////////////////////////////////// - -namespace drawinglayer -{ - namespace attribute - { - class ImpFillBitmapAttribute - { - public: - // refcounter - sal_uInt32 mnRefCount; - - // data definitions - BitmapEx maBitmapEx; - basegfx::B2DPoint maTopLeft; - basegfx::B2DVector maSize; - - // bitfield - unsigned mbTiling : 1; - - ImpFillBitmapAttribute( - const BitmapEx& rBitmapEx, - const basegfx::B2DPoint& rTopLeft, - const basegfx::B2DVector& rSize, - bool bTiling) - : mnRefCount(0), - maBitmapEx(rBitmapEx), - maTopLeft(rTopLeft), - maSize(rSize), - mbTiling(bTiling) - { - } - - bool operator==(const ImpFillBitmapAttribute& rCandidate) const - { - return (maBitmapEx == rCandidate.maBitmapEx - && maTopLeft == rCandidate.maTopLeft - && maSize == rCandidate.maSize - && mbTiling == rCandidate.mbTiling); - } - - // data read access - const BitmapEx& getBitmapEx() const { return maBitmapEx; } - const basegfx::B2DPoint& getTopLeft() const { return maTopLeft; } - const basegfx::B2DVector& getSize() const { return maSize; } - bool getTiling() const { return mbTiling; } - - static ImpFillBitmapAttribute* get_global_default() - { - static ImpFillBitmapAttribute* pDefault = 0; - - if(!pDefault) - { - pDefault = new ImpFillBitmapAttribute( - BitmapEx(), - basegfx::B2DPoint(), - basegfx::B2DVector(), - false); - - // never delete; start with RefCount 1, not 0 - pDefault->mnRefCount++; - } - - return pDefault; - } - }; - - FillBitmapAttribute::FillBitmapAttribute( - const BitmapEx& rBitmapEx, - const basegfx::B2DPoint& rTopLeft, - const basegfx::B2DVector& rSize, - bool bTiling) - : mpFillBitmapAttribute(new ImpFillBitmapAttribute( - rBitmapEx, rTopLeft, rSize, bTiling)) - { - } - - FillBitmapAttribute::FillBitmapAttribute() - : mpFillBitmapAttribute(ImpFillBitmapAttribute::get_global_default()) - { - mpFillBitmapAttribute->mnRefCount++; - } - - FillBitmapAttribute::FillBitmapAttribute(const FillBitmapAttribute& rCandidate) - : mpFillBitmapAttribute(rCandidate.mpFillBitmapAttribute) - { - mpFillBitmapAttribute->mnRefCount++; - } - - FillBitmapAttribute::~FillBitmapAttribute() - { - if(mpFillBitmapAttribute->mnRefCount) - { - mpFillBitmapAttribute->mnRefCount--; - } - else - { - delete mpFillBitmapAttribute; - } - } - - bool FillBitmapAttribute::isDefault() const - { - return mpFillBitmapAttribute == ImpFillBitmapAttribute::get_global_default(); - } - - FillBitmapAttribute& FillBitmapAttribute::operator=(const FillBitmapAttribute& rCandidate) - { - if(rCandidate.mpFillBitmapAttribute != mpFillBitmapAttribute) - { - if(mpFillBitmapAttribute->mnRefCount) - { - mpFillBitmapAttribute->mnRefCount--; - } - else - { - delete mpFillBitmapAttribute; - } - - mpFillBitmapAttribute = rCandidate.mpFillBitmapAttribute; - mpFillBitmapAttribute->mnRefCount++; - } - - return *this; - } - - bool FillBitmapAttribute::operator==(const FillBitmapAttribute& rCandidate) const - { - if(rCandidate.mpFillBitmapAttribute == mpFillBitmapAttribute) - { - return true; - } - - if(rCandidate.isDefault() != isDefault()) - { - return false; - } - - return (*rCandidate.mpFillBitmapAttribute == *mpFillBitmapAttribute); - } - - const BitmapEx& FillBitmapAttribute::getBitmapEx() const - { - return mpFillBitmapAttribute->getBitmapEx(); - } - - const basegfx::B2DPoint& FillBitmapAttribute::getTopLeft() const - { - return mpFillBitmapAttribute->getTopLeft(); - } - - const basegfx::B2DVector& FillBitmapAttribute::getSize() const - { - return mpFillBitmapAttribute->getSize(); - } - - bool FillBitmapAttribute::getTiling() const - { - return mpFillBitmapAttribute->getTiling(); - } - - } // end of namespace attribute -} // end of namespace drawinglayer - -////////////////////////////////////////////////////////////////////////////// -// eof diff --git a/drawinglayer/source/attribute/fillgraphicattribute.cxx b/drawinglayer/source/attribute/fillgraphicattribute.cxx new file mode 100755 index 000000000000..366947652517 --- /dev/null +++ b/drawinglayer/source/attribute/fillgraphicattribute.cxx @@ -0,0 +1,215 @@ +/************************************************************** + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + *************************************************************/ + + + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/attribute/fillgraphicattribute.hxx> +#include <vcl/graph.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace attribute + { + class ImpFillGraphicAttribute + { + public: + // refcounter + sal_uInt32 mnRefCount; + + // data definitions + Graphic maGraphic; + basegfx::B2DRange maGraphicRange; + + // tiling definitions, offsets in X/Y in percent for each 2nd row. + // If both are set, Y is ignored (X has precedence) + double mfOffsetX; + double mfOffsetY; + + // bitfield + unsigned mbTiling : 1; + + ImpFillGraphicAttribute( + const Graphic& rGraphic, + const basegfx::B2DRange& rGraphicRange, + bool bTiling, + double fOffsetX, + double fOffsetY) + : mnRefCount(0), + maGraphic(rGraphic), + maGraphicRange(rGraphicRange), + mbTiling(bTiling), + mfOffsetX(fOffsetX), + mfOffsetY(fOffsetY) + { + } + + // data read access + const Graphic& getGraphic() const { return maGraphic; } + const basegfx::B2DRange& getGraphicRange() const { return maGraphicRange; } + bool getTiling() const { return mbTiling; } + double getOffsetX() const { return mfOffsetX; } + double getOffsetY() const { return mfOffsetY; } + + bool operator==(const ImpFillGraphicAttribute& rCandidate) const + { + return (getGraphic() == rCandidate.getGraphic() + && getGraphicRange() == rCandidate.getGraphicRange() + && getTiling() == rCandidate.getTiling() + && getOffsetX() == rCandidate.getOffsetX() + && getOffsetY() == rCandidate.getOffsetY()); + } + + static ImpFillGraphicAttribute* get_global_default() + { + static ImpFillGraphicAttribute* pDefault = 0; + + if(!pDefault) + { + pDefault = new ImpFillGraphicAttribute( + Graphic(), + basegfx::B2DRange(), + false, + 0.0, + 0.0); + + // never delete; start with RefCount 1, not 0 + pDefault->mnRefCount++; + } + + return pDefault; + } + }; + + FillGraphicAttribute::FillGraphicAttribute( + const Graphic& rGraphic, + const basegfx::B2DRange& rGraphicRange, + bool bTiling, + double fOffsetX, + double fOffsetY) + : mpFillGraphicAttribute( + new ImpFillGraphicAttribute( + rGraphic, + rGraphicRange, + bTiling, + basegfx::clamp(fOffsetX, 0.0, 1.0), + basegfx::clamp(fOffsetY, 0.0, 1.0))) + { + } + + FillGraphicAttribute::FillGraphicAttribute() + : mpFillGraphicAttribute(ImpFillGraphicAttribute::get_global_default()) + { + mpFillGraphicAttribute->mnRefCount++; + } + + FillGraphicAttribute::FillGraphicAttribute(const FillGraphicAttribute& rCandidate) + : mpFillGraphicAttribute(rCandidate.mpFillGraphicAttribute) + { + mpFillGraphicAttribute->mnRefCount++; + } + + FillGraphicAttribute::~FillGraphicAttribute() + { + if(mpFillGraphicAttribute->mnRefCount) + { + mpFillGraphicAttribute->mnRefCount--; + } + else + { + delete mpFillGraphicAttribute; + } + } + + bool FillGraphicAttribute::isDefault() const + { + return mpFillGraphicAttribute == ImpFillGraphicAttribute::get_global_default(); + } + + FillGraphicAttribute& FillGraphicAttribute::operator=(const FillGraphicAttribute& rCandidate) + { + if(rCandidate.mpFillGraphicAttribute != mpFillGraphicAttribute) + { + if(mpFillGraphicAttribute->mnRefCount) + { + mpFillGraphicAttribute->mnRefCount--; + } + else + { + delete mpFillGraphicAttribute; + } + + mpFillGraphicAttribute = rCandidate.mpFillGraphicAttribute; + mpFillGraphicAttribute->mnRefCount++; + } + + return *this; + } + + bool FillGraphicAttribute::operator==(const FillGraphicAttribute& rCandidate) const + { + if(rCandidate.mpFillGraphicAttribute == mpFillGraphicAttribute) + { + return true; + } + + if(rCandidate.isDefault() != isDefault()) + { + return false; + } + + return (*rCandidate.mpFillGraphicAttribute == *mpFillGraphicAttribute); + } + + const Graphic& FillGraphicAttribute::getGraphic() const + { + return mpFillGraphicAttribute->getGraphic(); + } + + const basegfx::B2DRange& FillGraphicAttribute::getGraphicRange() const + { + return mpFillGraphicAttribute->getGraphicRange(); + } + + bool FillGraphicAttribute::getTiling() const + { + return mpFillGraphicAttribute->getTiling(); + } + + double FillGraphicAttribute::getOffsetX() const + { + return mpFillGraphicAttribute->getOffsetX(); + } + + double FillGraphicAttribute::getOffsetY() const + { + return mpFillGraphicAttribute->getOffsetY(); + } + + } // end of namespace attribute +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/attribute/sdrfillattribute.cxx b/drawinglayer/source/attribute/sdrfillattribute.cxx index 0de0bd913da9..61d3209e9600 100644 --- a/drawinglayer/source/attribute/sdrfillattribute.cxx +++ b/drawinglayer/source/attribute/sdrfillattribute.cxx @@ -24,7 +24,7 @@ #include <drawinglayer/attribute/sdrfillattribute.hxx> #include <basegfx/color/bcolor.hxx> -#include <drawinglayer/attribute/sdrfillbitmapattribute.hxx> +#include <drawinglayer/attribute/sdrfillgraphicattribute.hxx> #include <drawinglayer/attribute/fillhatchattribute.hxx> #include <drawinglayer/attribute/fillgradientattribute.hxx> @@ -45,7 +45,7 @@ namespace drawinglayer basegfx::BColor maColor; // fill color FillGradientAttribute maGradient; // fill gradient (if used) FillHatchAttribute maHatch; // fill hatch (if used) - SdrFillBitmapAttribute maBitmap; // fill bitmap (if used) + SdrFillGraphicAttribute maFillGraphic; // fill graphic (if used) public: ImpSdrFillAttribute( @@ -53,13 +53,13 @@ namespace drawinglayer const basegfx::BColor& rColor, const FillGradientAttribute& rGradient, const FillHatchAttribute& rHatch, - const SdrFillBitmapAttribute& rBitmap) + const SdrFillGraphicAttribute& rFillGraphic) : mnRefCount(0), mfTransparence(fTransparence), maColor(rColor), maGradient(rGradient), maHatch(rHatch), - maBitmap(rBitmap) + maFillGraphic(rFillGraphic) { } @@ -68,7 +68,7 @@ namespace drawinglayer const basegfx::BColor& getColor() const { return maColor; } const FillGradientAttribute& getGradient() const { return maGradient; } const FillHatchAttribute& getHatch() const { return maHatch; } - const SdrFillBitmapAttribute& getBitmap() const { return maBitmap; } + const SdrFillGraphicAttribute& getFillGraphic() const { return maFillGraphic; } // compare operator bool operator==(const ImpSdrFillAttribute& rCandidate) const @@ -77,7 +77,7 @@ namespace drawinglayer && getColor() == rCandidate.getColor() && getGradient() == rCandidate.getGradient() && getHatch() == rCandidate.getHatch() - && getBitmap() == rCandidate.getBitmap()); + && getFillGraphic() == rCandidate.getFillGraphic()); } static ImpSdrFillAttribute* get_global_default() @@ -91,7 +91,7 @@ namespace drawinglayer basegfx::BColor(), FillGradientAttribute(), FillHatchAttribute(), - SdrFillBitmapAttribute()); + SdrFillGraphicAttribute()); // never delete; start with RefCount 1, not 0 pDefault->mnRefCount++; @@ -106,9 +106,10 @@ namespace drawinglayer const basegfx::BColor& rColor, const FillGradientAttribute& rGradient, const FillHatchAttribute& rHatch, - const SdrFillBitmapAttribute& rBitmap) - : mpSdrFillAttribute(new ImpSdrFillAttribute( - fTransparence, rColor, rGradient, rHatch, rBitmap)) + const SdrFillGraphicAttribute& rFillGraphic) + : mpSdrFillAttribute( + new ImpSdrFillAttribute( + fTransparence, rColor, rGradient, rHatch, rFillGraphic)) { } @@ -196,9 +197,9 @@ namespace drawinglayer return mpSdrFillAttribute->getHatch(); } - const SdrFillBitmapAttribute& SdrFillAttribute::getBitmap() const + const SdrFillGraphicAttribute& SdrFillAttribute::getFillGraphic() const { - return mpSdrFillAttribute->getBitmap(); + return mpSdrFillAttribute->getFillGraphic(); } } // end of namespace attribute } // end of namespace drawinglayer diff --git a/drawinglayer/source/attribute/sdrfillbitmapattribute.cxx b/drawinglayer/source/attribute/sdrfillgraphicattribute.cxx index f122c7c9c5b5..77fa080158ee 100644..100755 --- a/drawinglayer/source/attribute/sdrfillbitmapattribute.cxx +++ b/drawinglayer/source/attribute/sdrfillgraphicattribute.cxx @@ -24,9 +24,9 @@ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_drawinglayer.hxx" -#include <drawinglayer/attribute/sdrfillbitmapattribute.hxx> -#include <drawinglayer/attribute/fillbitmapattribute.hxx> -#include <vcl/bitmapex.hxx> +#include <drawinglayer/attribute/sdrfillgraphicattribute.hxx> +#include <drawinglayer/attribute/fillgraphicattribute.hxx> +#include <vcl/graph.hxx> ////////////////////////////////////////////////////////////////////////////// @@ -34,14 +34,14 @@ namespace drawinglayer { namespace attribute { - class ImpSdrFillBitmapAttribute + class ImpSdrFillGraphicAttribute { public: // refcounter sal_uInt32 mnRefCount; // data definitions - BitmapEx maBitmapEx; + Graphic maFillGraphic; basegfx::B2DVector maSize; basegfx::B2DVector maOffset; basegfx::B2DVector maOffsetPosition; @@ -52,8 +52,8 @@ namespace drawinglayer unsigned mbStretch : 1; unsigned mbLogSize : 1; - ImpSdrFillBitmapAttribute( - const BitmapEx& rBitmapEx, + ImpSdrFillGraphicAttribute( + const Graphic& rFillGraphic, const basegfx::B2DVector& rSize, const basegfx::B2DVector& rOffset, const basegfx::B2DVector& rOffsetPosition, @@ -62,7 +62,7 @@ namespace drawinglayer bool bStretch, bool bLogSize) : mnRefCount(0), - maBitmapEx(rBitmapEx), + maFillGraphic(rFillGraphic), maSize(rSize), maOffset(rOffset), maOffsetPosition(rOffsetPosition), @@ -74,7 +74,7 @@ namespace drawinglayer } // data read access - const BitmapEx& getBitmapEx() const { return maBitmapEx; } + const Graphic& getFillGraphic() const { return maFillGraphic; } const basegfx::B2DVector& getSize() const { return maSize; } const basegfx::B2DVector& getOffset() const { return maOffset; } const basegfx::B2DVector& getOffsetPosition() const { return maOffsetPosition; } @@ -83,9 +83,9 @@ namespace drawinglayer bool getStretch() const { return mbStretch; } bool getLogSize() const { return mbLogSize; } - bool operator==(const ImpSdrFillBitmapAttribute& rCandidate) const + bool operator==(const ImpSdrFillGraphicAttribute& rCandidate) const { - return (getBitmapEx() == rCandidate.getBitmapEx() + return (getFillGraphic() == rCandidate.getFillGraphic() && getSize() == rCandidate.getSize() && getOffset() == rCandidate.getOffset() && getOffsetPosition() == rCandidate.getOffsetPosition() @@ -95,14 +95,14 @@ namespace drawinglayer && getLogSize() == rCandidate.getLogSize()); } - static ImpSdrFillBitmapAttribute* get_global_default() + static ImpSdrFillGraphicAttribute* get_global_default() { - static ImpSdrFillBitmapAttribute* pDefault = 0; + static ImpSdrFillGraphicAttribute* pDefault = 0; if(!pDefault) { - pDefault = new ImpSdrFillBitmapAttribute( - BitmapEx(), + pDefault = new ImpSdrFillGraphicAttribute( + Graphic(), basegfx::B2DVector(), basegfx::B2DVector(), basegfx::B2DVector(), @@ -119,8 +119,8 @@ namespace drawinglayer } }; - SdrFillBitmapAttribute::SdrFillBitmapAttribute( - const BitmapEx& rBitmapEx, + SdrFillGraphicAttribute::SdrFillGraphicAttribute( + const Graphic& rFillGraphic, const basegfx::B2DVector& rSize, const basegfx::B2DVector& rOffset, const basegfx::B2DVector& rOffsetPosition, @@ -128,9 +128,9 @@ namespace drawinglayer bool bTiling, bool bStretch, bool bLogSize) - : mpSdrFillBitmapAttribute( - new ImpSdrFillBitmapAttribute( - rBitmapEx, + : mpSdrFillGraphicAttribute( + new ImpSdrFillGraphicAttribute( + rFillGraphic, rSize, rOffset, rOffsetPosition, @@ -141,58 +141,58 @@ namespace drawinglayer { } - SdrFillBitmapAttribute::SdrFillBitmapAttribute() - : mpSdrFillBitmapAttribute(ImpSdrFillBitmapAttribute::get_global_default()) + SdrFillGraphicAttribute::SdrFillGraphicAttribute() + : mpSdrFillGraphicAttribute(ImpSdrFillGraphicAttribute::get_global_default()) { - mpSdrFillBitmapAttribute->mnRefCount++; + mpSdrFillGraphicAttribute->mnRefCount++; } - SdrFillBitmapAttribute::SdrFillBitmapAttribute(const SdrFillBitmapAttribute& rCandidate) - : mpSdrFillBitmapAttribute(rCandidate.mpSdrFillBitmapAttribute) + SdrFillGraphicAttribute::SdrFillGraphicAttribute(const SdrFillGraphicAttribute& rCandidate) + : mpSdrFillGraphicAttribute(rCandidate.mpSdrFillGraphicAttribute) { - mpSdrFillBitmapAttribute->mnRefCount++; + mpSdrFillGraphicAttribute->mnRefCount++; } - SdrFillBitmapAttribute::~SdrFillBitmapAttribute() + SdrFillGraphicAttribute::~SdrFillGraphicAttribute() { - if(mpSdrFillBitmapAttribute->mnRefCount) + if(mpSdrFillGraphicAttribute->mnRefCount) { - mpSdrFillBitmapAttribute->mnRefCount--; + mpSdrFillGraphicAttribute->mnRefCount--; } else { - delete mpSdrFillBitmapAttribute; + delete mpSdrFillGraphicAttribute; } } - bool SdrFillBitmapAttribute::isDefault() const + bool SdrFillGraphicAttribute::isDefault() const { - return mpSdrFillBitmapAttribute == ImpSdrFillBitmapAttribute::get_global_default(); + return mpSdrFillGraphicAttribute == ImpSdrFillGraphicAttribute::get_global_default(); } - SdrFillBitmapAttribute& SdrFillBitmapAttribute::operator=(const SdrFillBitmapAttribute& rCandidate) + SdrFillGraphicAttribute& SdrFillGraphicAttribute::operator=(const SdrFillGraphicAttribute& rCandidate) { - if(rCandidate.mpSdrFillBitmapAttribute != mpSdrFillBitmapAttribute) + if(rCandidate.mpSdrFillGraphicAttribute != mpSdrFillGraphicAttribute) { - if(mpSdrFillBitmapAttribute->mnRefCount) + if(mpSdrFillGraphicAttribute->mnRefCount) { - mpSdrFillBitmapAttribute->mnRefCount--; + mpSdrFillGraphicAttribute->mnRefCount--; } else { - delete mpSdrFillBitmapAttribute; + delete mpSdrFillGraphicAttribute; } - mpSdrFillBitmapAttribute = rCandidate.mpSdrFillBitmapAttribute; - mpSdrFillBitmapAttribute->mnRefCount++; + mpSdrFillGraphicAttribute = rCandidate.mpSdrFillGraphicAttribute; + mpSdrFillGraphicAttribute->mnRefCount++; } return *this; } - bool SdrFillBitmapAttribute::operator==(const SdrFillBitmapAttribute& rCandidate) const + bool SdrFillGraphicAttribute::operator==(const SdrFillGraphicAttribute& rCandidate) const { - if(rCandidate.mpSdrFillBitmapAttribute == mpSdrFillBitmapAttribute) + if(rCandidate.mpSdrFillGraphicAttribute == mpSdrFillGraphicAttribute) { return true; } @@ -202,112 +202,60 @@ namespace drawinglayer return false; } - return (*rCandidate.mpSdrFillBitmapAttribute == *mpSdrFillBitmapAttribute); + return (*rCandidate.mpSdrFillGraphicAttribute == *mpSdrFillGraphicAttribute); } - const BitmapEx& SdrFillBitmapAttribute::getBitmapEx() const + const Graphic& SdrFillGraphicAttribute::getFillGraphic() const { - return mpSdrFillBitmapAttribute->getBitmapEx(); + return mpSdrFillGraphicAttribute->getFillGraphic(); } - const basegfx::B2DVector& SdrFillBitmapAttribute::getSize() const + const basegfx::B2DVector& SdrFillGraphicAttribute::getSize() const { - return mpSdrFillBitmapAttribute->getSize(); + return mpSdrFillGraphicAttribute->getSize(); } - const basegfx::B2DVector& SdrFillBitmapAttribute::getOffset() const + const basegfx::B2DVector& SdrFillGraphicAttribute::getOffset() const { - return mpSdrFillBitmapAttribute->getOffset(); + return mpSdrFillGraphicAttribute->getOffset(); } - const basegfx::B2DVector& SdrFillBitmapAttribute::getOffsetPosition() const + const basegfx::B2DVector& SdrFillGraphicAttribute::getOffsetPosition() const { - return mpSdrFillBitmapAttribute->getOffsetPosition(); + return mpSdrFillGraphicAttribute->getOffsetPosition(); } - const basegfx::B2DVector& SdrFillBitmapAttribute::getRectPoint() const + const basegfx::B2DVector& SdrFillGraphicAttribute::getRectPoint() const { - return mpSdrFillBitmapAttribute->getRectPoint(); + return mpSdrFillGraphicAttribute->getRectPoint(); } - bool SdrFillBitmapAttribute::getTiling() const + bool SdrFillGraphicAttribute::getTiling() const { - return mpSdrFillBitmapAttribute->getTiling(); + return mpSdrFillGraphicAttribute->getTiling(); } - bool SdrFillBitmapAttribute::getStretch() const + bool SdrFillGraphicAttribute::getStretch() const { - return mpSdrFillBitmapAttribute->getStretch(); + return mpSdrFillGraphicAttribute->getStretch(); } - bool SdrFillBitmapAttribute::getLogSize() const + bool SdrFillGraphicAttribute::getLogSize() const { - return mpSdrFillBitmapAttribute->getLogSize(); + return mpSdrFillGraphicAttribute->getLogSize(); } - FillBitmapAttribute SdrFillBitmapAttribute::getFillBitmapAttribute(const basegfx::B2DRange& rRange) const + FillGraphicAttribute SdrFillGraphicAttribute::createFillGraphicAttribute(const basegfx::B2DRange& rRange) const { // get logical size of bitmap (before expanding eventually) - BitmapEx aBitmapEx(getBitmapEx()); - const basegfx::B2DVector aLogicalSize(aBitmapEx.GetPrefSize().getWidth(), aBitmapEx.GetPrefSize().getHeight()); - - // get hor/ver shiftings and apply them eventually to the bitmap, but only - // when tiling is on - bool bExpandWidth(false); - bool bExpandHeight(false); - - if(getTiling()) - { - if(0.0 != getOffset().getX() || 0.0 != getOffset().getY()) - { - const sal_uInt32 nWidth(aBitmapEx.GetSizePixel().getWidth()); - const sal_uInt32 nHeight(aBitmapEx.GetSizePixel().getHeight()); - - if(0.0 != getOffset().getX()) - { - bExpandHeight = true; - const sal_uInt32 nOffset(basegfx::fround(((double)nWidth * getOffset().getX()) / 100.0)); - aBitmapEx.Expand(0L, nHeight); - - const Size aSizeA(nOffset, nHeight); - const Rectangle aDstA(Point(0L, nHeight), aSizeA); - const Rectangle aSrcA(Point(nWidth - nOffset, 0L), aSizeA); - aBitmapEx.CopyPixel(aDstA, aSrcA); - - const Size aSizeB(nWidth - nOffset, nHeight); - const Rectangle aDstB(Point(nOffset, nHeight), aSizeB); - const Rectangle aSrcB(Point(0L, 0L), aSizeB); - aBitmapEx.CopyPixel(aDstB, aSrcB); - } - else - { - bExpandWidth = true; - const sal_uInt32 nOffset(basegfx::fround(((double)nHeight * getOffset().getY()) / 100.0)); - aBitmapEx.Expand(nWidth, 0L); - - const Size aSize(nWidth, nHeight); - const Rectangle aDst(Point(nWidth, 0L), aSize); - const Rectangle aSrc(Point(0L, 0L), aSize); - aBitmapEx.CopyPixel(aDst, aSrc); - - const Size aSizeA(nWidth, nOffset); - const Rectangle aDstA(Point(0L, 0L), aSizeA); - const Rectangle aSrcA(Point(nWidth, nHeight - nOffset), aSizeA); - aBitmapEx.CopyPixel(aDstA, aSrcA); - - const Size aSizeB(nWidth, nHeight - nOffset); - const Rectangle aDstB(Point(0L, nOffset), aSizeB); - const Rectangle aSrcB(Point(nWidth, 0L), aSizeB); - aBitmapEx.CopyPixel(aDstB, aSrcB); - } - } - } + Graphic aGraphic(getFillGraphic()); + const basegfx::B2DVector aLogicalSize(aGraphic.GetPrefSize().getWidth(), aGraphic.GetPrefSize().getHeight()); // init values with defaults basegfx::B2DPoint aBitmapSize(1.0, 1.0); basegfx::B2DVector aBitmapTopLeft(0.0, 0.0); - // are canges needed? + // are changes needed? if(getTiling() || !getStretch()) { // init values with range sizes @@ -381,17 +329,6 @@ namespace drawinglayer aBitmapTopLeft.setY(aBitmapTopLeft.getY() + (aBitmapSize.getY() * (getOffsetPosition().getY() * 0.01))); } - // apply expand - if(bExpandWidth) - { - aBitmapSize.setX(aBitmapSize.getX() * 2.0); - } - - if(bExpandHeight) - { - aBitmapSize.setY(aBitmapSize.getY() * 2.0); - } - // apply bitmap size scaling to unit rectangle aBitmapTopLeft.setX(aBitmapTopLeft.getX() / fRangeWidth); aBitmapTopLeft.setY(aBitmapTopLeft.getY() / fRangeHeight); @@ -399,7 +336,17 @@ namespace drawinglayer aBitmapSize.setY(aBitmapSize.getY() / fRangeHeight); } - return FillBitmapAttribute(aBitmapEx, aBitmapTopLeft, aBitmapSize, getTiling()); + // get offset in percent + const double fOffsetX(basegfx::clamp(getOffset().getX() * 0.01, 0.0, 1.0)); + const double fOffsetY(basegfx::clamp(getOffset().getY() * 0.01, 0.0, 1.0)); + + // create FillGraphicAttribute + return FillGraphicAttribute( + aGraphic, + basegfx::B2DRange(aBitmapTopLeft, aBitmapTopLeft + aBitmapSize), + getTiling(), + fOffsetX, + fOffsetY); } } // end of namespace attribute } // end of namespace drawinglayer diff --git a/drawinglayer/source/primitive2d/fillbitmapprimitive2d.cxx b/drawinglayer/source/primitive2d/fillbitmapprimitive2d.cxx deleted file mode 100644 index 58fcc361ecd8..000000000000 --- a/drawinglayer/source/primitive2d/fillbitmapprimitive2d.cxx +++ /dev/null @@ -1,138 +0,0 @@ -/************************************************************** - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - *************************************************************/ - - - -// MARKER(update_precomp.py): autogen include statement, do not remove -#include "precompiled_drawinglayer.hxx" - -#include <drawinglayer/primitive2d/fillbitmapprimitive2d.hxx> -#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> -#include <basegfx/polygon/b2dpolygon.hxx> -#include <basegfx/polygon/b2dpolygontools.hxx> -#include <drawinglayer/texture/texture.hxx> -#include <basegfx/tools/canvastools.hxx> -#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> - -////////////////////////////////////////////////////////////////////////////// - -using namespace com::sun::star; - -////////////////////////////////////////////////////////////////////////////// - -namespace drawinglayer -{ - namespace primitive2d - { - Primitive2DSequence FillBitmapPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const - { - Primitive2DSequence aRetval; - - if(!getFillBitmap().isDefault()) - { - const Size aTileSizePixel(getFillBitmap().getBitmapEx().GetSizePixel()); - - // is there a tile with some size at all? - if(aTileSizePixel.getWidth() && aTileSizePixel.getHeight()) - { - if(getFillBitmap().getTiling()) - { - // get object range and create tiling matrices - ::std::vector< basegfx::B2DHomMatrix > aMatrices; - texture::GeoTexSvxTiled aTiling(getFillBitmap().getTopLeft(), getFillBitmap().getSize()); - aTiling.appendTransformations(aMatrices); - - // resize result - aRetval.realloc(aMatrices.size()); - - // create one primitive for each matrix - for(sal_uInt32 a(0L); a < aMatrices.size(); a++) - { - basegfx::B2DHomMatrix aNewMatrix = aMatrices[a]; - aNewMatrix *= getTransformation(); - - // create bitmap primitive and add to result - const Primitive2DReference xRef( - new BitmapPrimitive2D(getFillBitmap().getBitmapEx(), aNewMatrix)); - - aRetval[a] = xRef; - } - } - else - { - // create new object transform - basegfx::B2DHomMatrix aObjectTransform; - aObjectTransform.set(0L, 0L, getFillBitmap().getSize().getX()); - aObjectTransform.set(1L, 1L, getFillBitmap().getSize().getY()); - aObjectTransform.set(0L, 2L, getFillBitmap().getTopLeft().getX()); - aObjectTransform.set(1L, 2L, getFillBitmap().getTopLeft().getY()); - aObjectTransform *= getTransformation(); - - // create bitmap primitive and add exclusive to decomposition (hand over ownership) - const Primitive2DReference xRef( - new BitmapPrimitive2D(getFillBitmap().getBitmapEx(), aObjectTransform)); - - aRetval = Primitive2DSequence(&xRef, 1L); - } - } - } - - return aRetval; - } - - FillBitmapPrimitive2D::FillBitmapPrimitive2D( - const basegfx::B2DHomMatrix& rTransformation, - const attribute::FillBitmapAttribute& rFillBitmap) - : BufferedDecompositionPrimitive2D(), - maTransformation(rTransformation), - maFillBitmap(rFillBitmap) - { - } - - bool FillBitmapPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const - { - if(BufferedDecompositionPrimitive2D::operator==(rPrimitive)) - { - const FillBitmapPrimitive2D& rCompare = static_cast< const FillBitmapPrimitive2D& >(rPrimitive); - - return (getTransformation() == rCompare.getTransformation() - && getFillBitmap() == rCompare.getFillBitmap()); - } - - return false; - } - - basegfx::B2DRange FillBitmapPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const - { - // return range of it - basegfx::B2DPolygon aPolygon(basegfx::tools::createUnitPolygon()); - aPolygon.transform(getTransformation()); - return basegfx::tools::getRange(aPolygon); - } - - // provide unique ID - ImplPrimitrive2DIDBlock(FillBitmapPrimitive2D, PRIMITIVE2D_ID_FILLBITMAPPRIMITIVE2D) - - } // end of namespace primitive2d -} // end of namespace drawinglayer - -////////////////////////////////////////////////////////////////////////////// -// eof diff --git a/drawinglayer/source/primitive2d/fillgraphicprimitive2d.cxx b/drawinglayer/source/primitive2d/fillgraphicprimitive2d.cxx new file mode 100644 index 000000000000..5da9d85dc4a1 --- /dev/null +++ b/drawinglayer/source/primitive2d/fillgraphicprimitive2d.cxx @@ -0,0 +1,147 @@ +/************************************************************** + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + *************************************************************/ + + + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive2d/fillgraphicprimitive2d.hxx> +#include <drawinglayer/primitive2d/graphicprimitive2d.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <drawinglayer/texture/texture.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> +#include <drawinglayer/primitive2d/metafileprimitive2d.hxx> +#include <drawinglayer/primitive2d/transformprimitive2d.hxx> +#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> +#include <drawinglayer/primitive2d/graphicprimitivehelper2d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive2d + { + Primitive2DSequence FillGraphicPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const + { + Primitive2DSequence aRetval; + const attribute::FillGraphicAttribute& rAttribute = getFillGraphic(); + + if(!rAttribute.isDefault()) + { + const Graphic& rGraphic = rAttribute.getGraphic(); + + if(GRAPHIC_BITMAP == rGraphic.GetType() || GRAPHIC_GDIMETAFILE == rGraphic.GetType()) + { + const Size aSize(rGraphic.GetPrefSize()); + + if(aSize.Width() && aSize.Height()) + { + // we have a graphic (bitmap or metafile) with some size + if(rAttribute.getTiling()) + { + // get object range and create tiling matrices + ::std::vector< basegfx::B2DHomMatrix > aMatrices; + texture::GeoTexSvxTiled aTiling( + rAttribute.getGraphicRange(), + rAttribute.getOffsetX(), + rAttribute.getOffsetY()); + + // get matrices and realloc retval + aTiling.appendTransformations(aMatrices); + aRetval.realloc(aMatrices.size()); + + // prepare content primitive + const Primitive2DSequence xSeq = create2DDecompositionOfGraphic( + rGraphic, + basegfx::B2DHomMatrix()); + + for(sal_uInt32 a(0); a < aMatrices.size(); a++) + { + aRetval[a] = new TransformPrimitive2D( + getTransformation() * aMatrices[a], + xSeq); + } + } + else + { + // add graphic without tiling + const basegfx::B2DHomMatrix aObjectTransform( + getTransformation() * basegfx::tools::createScaleTranslateB2DHomMatrix( + rAttribute.getGraphicRange().getRange(), + rAttribute.getGraphicRange().getMinimum())); + + aRetval = create2DDecompositionOfGraphic( + rGraphic, + aObjectTransform); + } + } + } + } + + return aRetval; + } + + FillGraphicPrimitive2D::FillGraphicPrimitive2D( + const basegfx::B2DHomMatrix& rTransformation, + const attribute::FillGraphicAttribute& rFillGraphic) + : BufferedDecompositionPrimitive2D(), + maTransformation(rTransformation), + maFillGraphic(rFillGraphic) + { + } + + bool FillGraphicPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + { + if(BufferedDecompositionPrimitive2D::operator==(rPrimitive)) + { + const FillGraphicPrimitive2D& rCompare = static_cast< const FillGraphicPrimitive2D& >(rPrimitive); + + return (getTransformation() == rCompare.getTransformation() + && getFillGraphic() == rCompare.getFillGraphic()); + } + + return false; + } + + basegfx::B2DRange FillGraphicPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const + { + // return range of it + basegfx::B2DPolygon aPolygon(basegfx::tools::createUnitPolygon()); + aPolygon.transform(getTransformation()); + + return basegfx::tools::getRange(aPolygon); + } + + // provide unique ID + ImplPrimitrive2DIDBlock(FillGraphicPrimitive2D, PRIMITIVE2D_ID_FILLGRAPHICPRIMITIVE2D) + + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive2d/graphicprimitive2d.cxx b/drawinglayer/source/primitive2d/graphicprimitive2d.cxx index 0703f9225b45..088a31581459 100644 --- a/drawinglayer/source/primitive2d/graphicprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/graphicprimitive2d.cxx @@ -25,187 +25,13 @@ #include "precompiled_drawinglayer.hxx" #include <drawinglayer/primitive2d/graphicprimitive2d.hxx> -#include <drawinglayer/animation/animationtiming.hxx> -#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> -#include <drawinglayer/primitive2d/animatedprimitive2d.hxx> -#include <drawinglayer/primitive2d/metafileprimitive2d.hxx> -#include <drawinglayer/primitive2d/transformprimitive2d.hxx> -#include <basegfx/polygon/b2dpolygon.hxx> -#include <basegfx/polygon/b2dpolygontools.hxx> #include <drawinglayer/primitive2d/cropprimitive2d.hxx> #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> #include <drawinglayer/primitive2d/maskprimitive2d.hxx> - -////////////////////////////////////////////////////////////////////////////// -// helper class for animated graphics - -#include <vcl/animate.hxx> -#include <vcl/graph.hxx> -#include <vcl/virdev.hxx> +#include <drawinglayer/primitive2d/graphicprimitivehelper2d.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> #include <vcl/svapp.hxx> -#include <vcl/metaact.hxx> - -////////////////////////////////////////////////////////////////////////////// -// includes for testing MetafilePrimitive2D::create2DDecomposition - -// this switch defines if the test code is included or not -#undef USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE - -#ifdef USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE -#include <vcl/gradient.hxx> -#include <vcl/pngread.hxx> -#include <vcl/lineinfo.hxx> -#endif // USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE - -////////////////////////////////////////////////////////////////////////////// - -namespace -{ - struct animationStep - { - BitmapEx maBitmapEx; - sal_uInt32 mnTime; - }; - - class animatedBitmapExPreparator - { - ::Animation maAnimation; - ::std::vector< animationStep > maSteps; - - sal_uInt32 generateStepTime(sal_uInt32 nIndex) const; - - public: - animatedBitmapExPreparator(const Graphic& rGraphic); - - sal_uInt32 count() const { return maSteps.size(); } - sal_uInt32 loopCount() const { return (sal_uInt32)maAnimation.GetLoopCount(); } - sal_uInt32 stepTime(sal_uInt32 a) const { return maSteps[a].mnTime; } - const BitmapEx& stepBitmapEx(sal_uInt32 a) const { return maSteps[a].maBitmapEx; } - }; - - sal_uInt32 animatedBitmapExPreparator::generateStepTime(sal_uInt32 nIndex) const - { - const AnimationBitmap& rAnimBitmap = maAnimation.Get(sal_uInt16(nIndex)); - sal_uInt32 nWaitTime(rAnimBitmap.nWait * 10); - - // #115934# - // Take care of special value for MultiPage TIFFs. ATM these shall just - // show their first page. Later we will offer some switching when object - // is selected. - if(ANIMATION_TIMEOUT_ON_CLICK == rAnimBitmap.nWait) - { - // ATM the huge value would block the timer, so - // use a long time to show first page (whole day) - nWaitTime = 100 * 60 * 60 * 24; - } - - // Bad trap: There are animated gifs with no set WaitTime (!). - // In that case use a default value. - if(0L == nWaitTime) - { - nWaitTime = 100L; - } - - return nWaitTime; - } - - animatedBitmapExPreparator::animatedBitmapExPreparator(const Graphic& rGraphic) - : maAnimation(rGraphic.GetAnimation()) - { - OSL_ENSURE(GRAPHIC_BITMAP == rGraphic.GetType() && rGraphic.IsAnimated(), "animatedBitmapExPreparator: graphic is not animated (!)"); - - // #128539# secure access to Animation, looks like there exist animated GIFs out there - // with a step count of zero - if(maAnimation.Count()) - { - VirtualDevice aVirtualDevice(*Application::GetDefaultDevice()); - VirtualDevice aVirtualDeviceMask(*Application::GetDefaultDevice(), 1L); - - // Prepare VirtualDevices and their states - aVirtualDevice.EnableMapMode(sal_False); - aVirtualDeviceMask.EnableMapMode(sal_False); - aVirtualDevice.SetOutputSizePixel(maAnimation.GetDisplaySizePixel()); - aVirtualDeviceMask.SetOutputSizePixel(maAnimation.GetDisplaySizePixel()); - aVirtualDevice.Erase(); - aVirtualDeviceMask.Erase(); - - for(sal_uInt16 a(0L); a < maAnimation.Count(); a++) - { - animationStep aNextStep; - aNextStep.mnTime = generateStepTime(a); - - // prepare step - const AnimationBitmap& rAnimBitmap = maAnimation.Get(sal_uInt16(a)); - - switch(rAnimBitmap.eDisposal) - { - case DISPOSE_NOT: - { - aVirtualDevice.DrawBitmapEx(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx); - Bitmap aMask = rAnimBitmap.aBmpEx.GetMask(); - - if(aMask.IsEmpty()) - { - const Point aEmpty; - const Rectangle aRect(aEmpty, aVirtualDeviceMask.GetOutputSizePixel()); - const Wallpaper aWallpaper(COL_BLACK); - aVirtualDeviceMask.DrawWallpaper(aRect, aWallpaper); - } - else - { - BitmapEx aExpandVisibilityMask = BitmapEx(aMask, aMask); - aVirtualDeviceMask.DrawBitmapEx(rAnimBitmap.aPosPix, aExpandVisibilityMask); - } - - break; - } - case DISPOSE_BACK: - { - // #i70772# react on no mask, for primitives, too. - const Bitmap aMask(rAnimBitmap.aBmpEx.GetMask()); - const Bitmap aContent(rAnimBitmap.aBmpEx.GetBitmap()); - - aVirtualDeviceMask.Erase(); - aVirtualDevice.DrawBitmap(rAnimBitmap.aPosPix, aContent); - - if(aMask.IsEmpty()) - { - const Rectangle aRect(rAnimBitmap.aPosPix, aContent.GetSizePixel()); - aVirtualDeviceMask.SetFillColor(COL_BLACK); - aVirtualDeviceMask.SetLineColor(); - aVirtualDeviceMask.DrawRect(aRect); - } - else - { - aVirtualDeviceMask.DrawBitmap(rAnimBitmap.aPosPix, aMask); - } - - break; - } - case DISPOSE_FULL: - { - aVirtualDevice.DrawBitmapEx(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx); - break; - } - case DISPOSE_PREVIOUS : - { - aVirtualDevice.DrawBitmapEx(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx); - aVirtualDeviceMask.DrawBitmap(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx.GetMask()); - break; - } - } - - // create BitmapEx - Bitmap aMainBitmap = aVirtualDevice.GetBitmap(Point(), aVirtualDevice.GetOutputSizePixel()); - Bitmap aMaskBitmap = aVirtualDeviceMask.GetBitmap(Point(), aVirtualDeviceMask.GetOutputSizePixel()); - aNextStep.maBitmapEx = BitmapEx(aMainBitmap, aMaskBitmap); - - // add to vector - maSteps.push_back(aNextStep); - } - } - } -} // end of anonymous namespace +#include <vcl/outdev.hxx> ////////////////////////////////////////////////////////////////////////////// @@ -225,8 +51,6 @@ namespace drawinglayer if(255L != getGraphicAttr().GetTransparency()) { - Primitive2DReference xPrimitive; - // do not apply mirroring from GraphicAttr to the Metafile by calling // GetTransformedGraphic, this will try to mirror the Metafile using Scale() // at the Metafile. This again calls Scale at the single MetaFile actions, @@ -262,556 +86,11 @@ namespace drawinglayer const GraphicObject& rGraphicObject = getGraphicObject(); const Graphic aTransformedGraphic(rGraphicObject.GetTransformedGraphic(&aSuppressGraphicAttr)); - switch(aTransformedGraphic.GetType()) - { - case GRAPHIC_BITMAP : - { - if(aTransformedGraphic.IsAnimated()) - { - // prepare animation data - animatedBitmapExPreparator aData(aTransformedGraphic); - - if(aData.count()) - { - // create sub-primitives for animated bitmap and the needed animation loop - animation::AnimationEntryLoop aAnimationLoop(aData.loopCount() ? aData.loopCount() : 0xffff); - Primitive2DSequence aBitmapPrimitives(aData.count()); - - for(sal_uInt32 a(0L); a < aData.count(); a++) - { - animation::AnimationEntryFixed aTime((double)aData.stepTime(a), (double)a / (double)aData.count()); - aAnimationLoop.append(aTime); - const Primitive2DReference xRef(new BitmapPrimitive2D(aData.stepBitmapEx(a), aTransform)); - aBitmapPrimitives[a] = xRef; - } - - // prepare animation list - animation::AnimationEntryList aAnimationList; - aAnimationList.append(aAnimationLoop); - - // create and add animated switch primitive - xPrimitive = Primitive2DReference(new AnimatedSwitchPrimitive2D(aAnimationList, aBitmapPrimitives, false)); - } - } - else if(aTransformedGraphic.getSvgData().get()) - { - // embedded Svg fill, create embed transform - const basegfx::B2DRange& rSvgRange(aTransformedGraphic.getSvgData()->getRange()); - - if(basegfx::fTools::more(rSvgRange.getWidth(), 0.0) && basegfx::fTools::more(rSvgRange.getHeight(), 0.0)) - { - // translate back to origin, scale to unit coordinates - basegfx::B2DHomMatrix aEmbedSvg( - basegfx::tools::createTranslateB2DHomMatrix( - -rSvgRange.getMinX(), - -rSvgRange.getMinY())); - - aEmbedSvg.scale( - 1.0 / rSvgRange.getWidth(), - 1.0 / rSvgRange.getHeight()); + aRetval = create2DDecompositionOfGraphic( + aTransformedGraphic, + aTransform); - // apply created object transformation - aEmbedSvg = aTransform * aEmbedSvg; - - // add Svg primitives embedded - xPrimitive = new TransformPrimitive2D( - aEmbedSvg, - aTransformedGraphic.getSvgData()->getPrimitive2DSequence()); - } - } - else - { - xPrimitive = Primitive2DReference(new BitmapPrimitive2D(aTransformedGraphic.GetBitmapEx(), aTransform)); - } - - break; - } - - case GRAPHIC_GDIMETAFILE : - { -#ifdef USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE - static bool bDoTest(false); - - if(bDoTest) - { - // All this is/was test code for testing MetafilePrimitive2D::create2DDecomposition - // extensively. It may be needed again when diverse actions need debugging, so i leave - // it in here, but take it out using USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE. - // Use it by compiling with the code, insert any DrawObject, convert to Metafile. The - // debugger will then stop here (when breakpoint set, of course). You may enter single - // parts of actions and/or change to true what You want to check. - GDIMetaFile aMtf; - VirtualDevice aOut; - const basegfx::B2DRange aRange(getB2DRange(rViewInformation)); - const Rectangle aRectangle( - basegfx::fround(aRange.getMinX()), basegfx::fround(aRange.getMinY()), - basegfx::fround(aRange.getMaxX()), basegfx::fround(aRange.getMaxY())); - const Point aOrigin(aRectangle.TopLeft()); - const Fraction aScaleX(aRectangle.getWidth()); - const Fraction aScaleY(aRectangle.getHeight()); - MapMode aMapMode(MAP_100TH_MM, aOrigin, aScaleX, aScaleY); - - Size aDummySize(2, 2); - aOut.SetOutputSizePixel(aDummySize); - aOut.EnableOutput(FALSE); - aOut.SetMapMode(aMapMode); - - aMtf.Clear(); - aMtf.Record(&aOut); - - const Fraction aNeutralFraction(1, 1); - const MapMode aRelativeMapMode( - MAP_RELATIVE, - Point(-aRectangle.Left(), -aRectangle.Top()), - aNeutralFraction, aNeutralFraction); - aOut.SetMapMode(aRelativeMapMode); - - if(false) - { - const sal_Int32 nHor(aRectangle.getWidth() / 4); - const sal_Int32 nVer(aRectangle.getHeight() / 4); - const Rectangle aCenteredRectangle( - aRectangle.Left() + nHor, aRectangle.Top() + nVer, - aRectangle.Right() - nHor, aRectangle.Bottom() - nVer); - aOut.SetClipRegion(aCenteredRectangle); - } - - if(false) - { - const Rectangle aRightRectangle(aRectangle.TopCenter(), aRectangle.BottomRight()); - aOut.IntersectClipRegion(aRightRectangle); - } - - if(false) - { - const Rectangle aRightRectangle(aRectangle.TopCenter(), aRectangle.BottomRight()); - const Rectangle aBottomRectangle(aRectangle.LeftCenter(), aRectangle.BottomRight()); - Region aRegion(aRightRectangle); - aRegion.Intersect(aBottomRectangle); - aOut.IntersectClipRegion(aRegion); - } - - if(false) - { - const sal_Int32 nHor(aRectangle.getWidth() / 10); - const sal_Int32 nVer(aRectangle.getHeight() / 10); - aOut.MoveClipRegion(nHor, nVer); - } - - if(false) - { - Wallpaper aWallpaper(Color(COL_BLACK)); - aOut.DrawWallpaper(aRectangle, aWallpaper); - } - - if(false) - { - Wallpaper aWallpaper(Gradient(GRADIENT_LINEAR, Color(COL_RED), Color(COL_GREEN))); - aOut.DrawWallpaper(aRectangle, aWallpaper); - } - - if(false) - { - SvFileStream aRead((const String&)String(ByteString( "c:\\test.png" ), RTL_TEXTENCODING_UTF8), STREAM_READ); - vcl::PNGReader aPNGReader(aRead); - BitmapEx aBitmapEx(aPNGReader.Read()); - Wallpaper aWallpaper(aBitmapEx); - aOut.DrawWallpaper(aRectangle, aWallpaper); - } - - if(false) - { - const double fHor(aRectangle.getWidth()); - const double fVer(aRectangle.getHeight()); - Color aColor(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)); - - for(sal_uInt32 a(0); a < 5000; a++) - { - const Point aPoint( - aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)), - aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0))); - - if(!(a % 3)) - { - aColor = Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)); - } - - aOut.DrawPixel(aPoint, aColor); - } - } - - if(false) - { - const double fHor(aRectangle.getWidth()); - const double fVer(aRectangle.getHeight()); - - aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); - aOut.SetFillColor(); - - for(sal_uInt32 a(0); a < 5000; a++) - { - const Point aPoint( - aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)), - aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0))); - aOut.DrawPixel(aPoint); - } - } - - if(false) - { - const double fHor(aRectangle.getWidth()); - const double fVer(aRectangle.getHeight()); - - aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); - aOut.SetFillColor(); - - Point aStart( - aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)), - aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0))); - Point aStop( - aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)), - aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0))); - - LineInfo aLineInfo(LINE_SOLID, basegfx::fround(fHor / 50.0)); - bool bUseLineInfo(false); - - for(sal_uInt32 a(0); a < 20; a++) - { - if(!(a%6)) - { - bUseLineInfo = !bUseLineInfo; - } - - if(!(a%4)) - { - aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); - } - - if(a%3) - { - aStart = aStop; - aStop = Point( - aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)), - aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0))); - } - else - { - aStart = Point( - aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)), - aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0))); - aStop = Point( - aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)), - aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0))); - } - - if(bUseLineInfo) - { - aOut.DrawLine(aStart, aStop, aLineInfo); - } - else - { - aOut.DrawLine(aStart, aStop); - } - } - } - - if(false) - { - aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); - aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); - aOut.DrawRect(aRectangle); - } - - if(false) - { - aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); - aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); - const sal_uInt32 nHor(aRectangle.getWidth() / 10); - const sal_uInt32 nVer(aRectangle.getHeight() / 10); - aOut.DrawRect(aRectangle, nHor, nVer); - } - - if(false) - { - aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); - aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); - aOut.DrawEllipse(aRectangle); - } - - if(false) - { - aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); - aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); - aOut.DrawArc(aRectangle, aRectangle.TopLeft(), aRectangle.BottomCenter()); - } - - if(false) - { - aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); - aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); - aOut.DrawPie(aRectangle, aRectangle.TopLeft(), aRectangle.BottomCenter()); - } - - if(false) - { - aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); - aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); - aOut.DrawChord(aRectangle, aRectangle.TopLeft(), aRectangle.BottomCenter()); - } - - if(false) - { - const double fHor(aRectangle.getWidth()); - const double fVer(aRectangle.getHeight()); - - for(sal_uInt32 b(0); b < 5; b++) - { - const sal_uInt32 nCount(basegfx::fround(rand() * (20 / 32767.0))); - const bool bClose(basegfx::fround(rand() / 32767.0)); - Polygon aPolygon(nCount + (bClose ? 1 : 0)); - - for(sal_uInt32 a(0); a < nCount; a++) - { - const Point aPoint( - aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)), - aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0))); - aPolygon[a] = aPoint; - } - - if(bClose) - { - aPolygon[aPolygon.GetSize() - 1] = aPolygon[0]; - } - - aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); - aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); - - if(!(b%2)) - { - const LineInfo aLineInfo(LINE_SOLID, basegfx::fround(fHor / 50.0)); - aOut.DrawPolyLine(aPolygon, aLineInfo); - } - else - { - aOut.DrawPolyLine(aPolygon); - } - } - } - - if(false) - { - const double fHor(aRectangle.getWidth()); - const double fVer(aRectangle.getHeight()); - - for(sal_uInt32 b(0); b < 5; b++) - { - const sal_uInt32 nCount(basegfx::fround(rand() * (20 / 32767.0))); - const bool bClose(basegfx::fround(rand() / 32767.0)); - Polygon aPolygon(nCount + (bClose ? 1 : 0)); - - for(sal_uInt32 a(0); a < nCount; a++) - { - const Point aPoint( - aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)), - aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0))); - aPolygon[a] = aPoint; - } - - if(bClose) - { - aPolygon[aPolygon.GetSize() - 1] = aPolygon[0]; - } - - aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); - aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); - aOut.DrawPolygon(aPolygon); - } - } - - if(false) - { - const double fHor(aRectangle.getWidth()); - const double fVer(aRectangle.getHeight()); - PolyPolygon aPolyPolygon; - - for(sal_uInt32 b(0); b < 3; b++) - { - const sal_uInt32 nCount(basegfx::fround(rand() * (6 / 32767.0))); - const bool bClose(basegfx::fround(rand() / 32767.0)); - Polygon aPolygon(nCount + (bClose ? 1 : 0)); - - for(sal_uInt32 a(0); a < nCount; a++) - { - const Point aPoint( - aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)), - aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0))); - aPolygon[a] = aPoint; - } - - if(bClose) - { - aPolygon[aPolygon.GetSize() - 1] = aPolygon[0]; - } - - aPolyPolygon.Insert(aPolygon); - } - - aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); - aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); - aOut.DrawPolyPolygon(aPolyPolygon); - } - - if(false) - { - SvFileStream aRead((const String&)String(ByteString( "c:\\test.png" ), RTL_TEXTENCODING_UTF8), STREAM_READ); - vcl::PNGReader aPNGReader(aRead); - BitmapEx aBitmapEx(aPNGReader.Read()); - aOut.DrawBitmapEx(aRectangle.TopLeft(), aBitmapEx); - } - - if(false) - { - SvFileStream aRead((const String&)String(ByteString( "c:\\test.png" ), RTL_TEXTENCODING_UTF8), STREAM_READ); - vcl::PNGReader aPNGReader(aRead); - BitmapEx aBitmapEx(aPNGReader.Read()); - aOut.DrawBitmapEx(aRectangle.TopLeft(), aRectangle.GetSize(), aBitmapEx); - } - - if(false) - { - SvFileStream aRead((const String&)String(ByteString( "c:\\test.png" ), RTL_TEXTENCODING_UTF8), STREAM_READ); - vcl::PNGReader aPNGReader(aRead); - BitmapEx aBitmapEx(aPNGReader.Read()); - const Size aSizePixel(aBitmapEx.GetSizePixel()); - aOut.DrawBitmapEx( - aRectangle.TopLeft(), - aRectangle.GetSize(), - Point(0, 0), - Size(aSizePixel.Width() /2, aSizePixel.Height() / 2), - aBitmapEx); - } - - if(false) - { - const double fHor(aRectangle.getWidth()); - const double fVer(aRectangle.getHeight()); - const Point aPointA( - aRectangle.Left() + basegfx::fround(fHor * 0.2), - aRectangle.Top() + basegfx::fround(fVer * 0.3)); - const Point aPointB( - aRectangle.Left() + basegfx::fround(fHor * 0.2), - aRectangle.Top() + basegfx::fround(fVer * 0.5)); - const Point aPointC( - aRectangle.Left() + basegfx::fround(fHor * 0.2), - aRectangle.Top() + basegfx::fround(fVer * 0.7)); - const String aText(ByteString("Hello, World!"), RTL_TEXTENCODING_UTF8); - - const String aFontName(ByteString("Comic Sans MS"), RTL_TEXTENCODING_UTF8); - Font aFont(aFontName, Size(0, 1000)); - aFont.SetAlign(ALIGN_BASELINE); - aFont.SetColor(COL_RED); - //sal_Int32* pDXArray = new sal_Int32[aText.Len()]; - - aFont.SetOutline(true); - aOut.SetFont(aFont); - aOut.DrawText(aPointA, aText, 0, aText.Len()); - - aFont.SetShadow(true); - aOut.SetFont(aFont); - aOut.DrawText(aPointB, aText, 0, aText.Len()); - - aFont.SetRelief(RELIEF_EMBOSSED); - aOut.SetFont(aFont); - aOut.DrawText(aPointC, aText, 0, aText.Len()); - - //delete pDXArray; - } - - if(false) - { - const double fHor(aRectangle.getWidth()); - const double fVer(aRectangle.getHeight()); - const Point aPointA( - aRectangle.Left() + basegfx::fround(fHor * 0.2), - aRectangle.Top() + basegfx::fround(fVer * 0.3)); - const Point aPointB( - aRectangle.Left() + basegfx::fround(fHor * 0.2), - aRectangle.Top() + basegfx::fround(fVer * 0.5)); - const Point aPointC( - aRectangle.Left() + basegfx::fround(fHor * 0.2), - aRectangle.Top() + basegfx::fround(fVer * 0.7)); - const String aText(ByteString("Hello, World!"), RTL_TEXTENCODING_UTF8); - - const String aFontName(ByteString("Comic Sans MS"), RTL_TEXTENCODING_UTF8); - Font aFont(aFontName, Size(0, 1000)); - aFont.SetAlign(ALIGN_BASELINE); - aFont.SetColor(COL_RED); - - aOut.SetFont(aFont); - const sal_Int32 nWidth(aOut.GetTextWidth(aText, 0, aText.Len())); - aOut.DrawText(aPointA, aText, 0, aText.Len()); - aOut.DrawTextLine(aPointA, nWidth, STRIKEOUT_SINGLE, UNDERLINE_SINGLE, UNDERLINE_SMALLWAVE); - aOut.DrawTextLine(aPointB, nWidth, STRIKEOUT_SINGLE, UNDERLINE_SINGLE, UNDERLINE_SMALLWAVE); - aOut.DrawTextLine(aPointC, nWidth, STRIKEOUT_SINGLE, UNDERLINE_SINGLE, UNDERLINE_SMALLWAVE); - } - - aMtf.Stop(); - aMtf.WindStart(); - aMtf.SetPrefMapMode(MapMode(MAP_100TH_MM)); - aMtf.SetPrefSize(Size(aRectangle.getWidth(), aRectangle.getHeight())); - - xPrimitive = Primitive2DReference( - new MetafilePrimitive2D( - aTransform, - aMtf)); - } - else - { -#endif // USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE - // create MetafilePrimitive2D - const GDIMetaFile& rMetafile = aTransformedGraphic.GetGDIMetaFile(); - - xPrimitive = Primitive2DReference( - new MetafilePrimitive2D( - aTransform, - rMetafile)); - - // #i100357# find out if clipping is needed for this primitive. Unfortunately, - // there exist Metafiles who's content is bigger than the proposed PrefSize set - // at them. This is an error, but we need to work around this - const Size aMetaFilePrefSize(rMetafile.GetPrefSize()); - const Size aMetaFileRealSize( - const_cast< GDIMetaFile& >(rMetafile).GetBoundRect( - *Application::GetDefaultDevice()).GetSize()); - - if(aMetaFileRealSize.getWidth() > aMetaFilePrefSize.getWidth() - || aMetaFileRealSize.getHeight() > aMetaFilePrefSize.getHeight()) - { - // clipping needed. Embed to MaskPrimitive2D. Create childs and mask polygon - const primitive2d::Primitive2DSequence aChildContent(&xPrimitive, 1); - basegfx::B2DPolygon aMaskPolygon(basegfx::tools::createUnitPolygon()); - aMaskPolygon.transform(aTransform); - - xPrimitive = Primitive2DReference( - new MaskPrimitive2D( - basegfx::B2DPolyPolygon(aMaskPolygon), - aChildContent)); - } -#ifdef USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE - } -#endif // USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE - - break; - } - - default: - { - // nothing to create - break; - } - } - - if(xPrimitive.is()) + if(aRetval.getLength()) { // check for cropping if(getGraphicAttr().IsCropped()) @@ -851,17 +130,17 @@ namespace drawinglayer } // embed content in cropPrimitive - xPrimitive = new CropPrimitive2D( - Primitive2DSequence(&xPrimitive, 1), - aTransform, - getGraphicAttr().GetLeftCrop() * fFactorX, - getGraphicAttr().GetTopCrop() * fFactorY, - getGraphicAttr().GetRightCrop() * fFactorX, - getGraphicAttr().GetBottomCrop() * fFactorY); + Primitive2DReference xPrimitive( + new CropPrimitive2D( + aRetval, + aTransform, + getGraphicAttr().GetLeftCrop() * fFactorX, + getGraphicAttr().GetTopCrop() * fFactorY, + getGraphicAttr().GetRightCrop() * fFactorX, + getGraphicAttr().GetBottomCrop() * fFactorY)); + + aRetval = Primitive2DSequence(&xPrimitive, 1); } - - // add to decomposition - appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, xPrimitive); } } diff --git a/drawinglayer/source/primitive2d/graphicprimitivehelper2d.cxx b/drawinglayer/source/primitive2d/graphicprimitivehelper2d.cxx new file mode 100755 index 000000000000..7b93bc0efd88 --- /dev/null +++ b/drawinglayer/source/primitive2d/graphicprimitivehelper2d.cxx @@ -0,0 +1,782 @@ +/************************************************************** + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + *************************************************************/ + + + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive2d/graphicprimitivehelper2d.hxx> +#include <drawinglayer/animation/animationtiming.hxx> +#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> +#include <drawinglayer/primitive2d/animatedprimitive2d.hxx> +#include <drawinglayer/primitive2d/metafileprimitive2d.hxx> +#include <drawinglayer/primitive2d/transformprimitive2d.hxx> +#include <drawinglayer/primitive2d/maskprimitive2d.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> + +////////////////////////////////////////////////////////////////////////////// +// helper class for animated graphics + +#include <vcl/animate.hxx> +#include <vcl/graph.hxx> +#include <vcl/virdev.hxx> +#include <vcl/svapp.hxx> +#include <vcl/metaact.hxx> + +////////////////////////////////////////////////////////////////////////////// +// includes for testing MetafilePrimitive2D::create2DDecomposition + +// this switch defines if the test code is included or not +#undef USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE + +#ifdef USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE +#include <vcl/gradient.hxx> +#include <vcl/pngread.hxx> +#include <vcl/lineinfo.hxx> +#endif // USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE + +////////////////////////////////////////////////////////////////////////////// + +namespace +{ + struct animationStep + { + BitmapEx maBitmapEx; + sal_uInt32 mnTime; + }; + + class animatedBitmapExPreparator + { + ::Animation maAnimation; + ::std::vector< animationStep > maSteps; + + sal_uInt32 generateStepTime(sal_uInt32 nIndex) const; + + public: + animatedBitmapExPreparator(const Graphic& rGraphic); + + sal_uInt32 count() const { return maSteps.size(); } + sal_uInt32 loopCount() const { return (sal_uInt32)maAnimation.GetLoopCount(); } + sal_uInt32 stepTime(sal_uInt32 a) const { return maSteps[a].mnTime; } + const BitmapEx& stepBitmapEx(sal_uInt32 a) const { return maSteps[a].maBitmapEx; } + }; + + sal_uInt32 animatedBitmapExPreparator::generateStepTime(sal_uInt32 nIndex) const + { + const AnimationBitmap& rAnimBitmap = maAnimation.Get(sal_uInt16(nIndex)); + sal_uInt32 nWaitTime(rAnimBitmap.nWait * 10); + + // #115934# + // Take care of special value for MultiPage TIFFs. ATM these shall just + // show their first page. Later we will offer some switching when object + // is selected. + if(ANIMATION_TIMEOUT_ON_CLICK == rAnimBitmap.nWait) + { + // ATM the huge value would block the timer, so + // use a long time to show first page (whole day) + nWaitTime = 100 * 60 * 60 * 24; + } + + // Bad trap: There are animated gifs with no set WaitTime (!). + // In that case use a default value. + if(0L == nWaitTime) + { + nWaitTime = 100L; + } + + return nWaitTime; + } + + animatedBitmapExPreparator::animatedBitmapExPreparator(const Graphic& rGraphic) + : maAnimation(rGraphic.GetAnimation()) + { + OSL_ENSURE(GRAPHIC_BITMAP == rGraphic.GetType() && rGraphic.IsAnimated(), "animatedBitmapExPreparator: graphic is not animated (!)"); + + // #128539# secure access to Animation, looks like there exist animated GIFs out there + // with a step count of zero + if(maAnimation.Count()) + { + VirtualDevice aVirtualDevice(*Application::GetDefaultDevice()); + VirtualDevice aVirtualDeviceMask(*Application::GetDefaultDevice(), 1L); + + // Prepare VirtualDevices and their states + aVirtualDevice.EnableMapMode(sal_False); + aVirtualDeviceMask.EnableMapMode(sal_False); + aVirtualDevice.SetOutputSizePixel(maAnimation.GetDisplaySizePixel()); + aVirtualDeviceMask.SetOutputSizePixel(maAnimation.GetDisplaySizePixel()); + aVirtualDevice.Erase(); + aVirtualDeviceMask.Erase(); + + for(sal_uInt16 a(0L); a < maAnimation.Count(); a++) + { + animationStep aNextStep; + aNextStep.mnTime = generateStepTime(a); + + // prepare step + const AnimationBitmap& rAnimBitmap = maAnimation.Get(sal_uInt16(a)); + + switch(rAnimBitmap.eDisposal) + { + case DISPOSE_NOT: + { + aVirtualDevice.DrawBitmapEx(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx); + Bitmap aMask = rAnimBitmap.aBmpEx.GetMask(); + + if(aMask.IsEmpty()) + { + const Point aEmpty; + const Rectangle aRect(aEmpty, aVirtualDeviceMask.GetOutputSizePixel()); + const Wallpaper aWallpaper(COL_BLACK); + aVirtualDeviceMask.DrawWallpaper(aRect, aWallpaper); + } + else + { + BitmapEx aExpandVisibilityMask = BitmapEx(aMask, aMask); + aVirtualDeviceMask.DrawBitmapEx(rAnimBitmap.aPosPix, aExpandVisibilityMask); + } + + break; + } + case DISPOSE_BACK: + { + // #i70772# react on no mask, for primitives, too. + const Bitmap aMask(rAnimBitmap.aBmpEx.GetMask()); + const Bitmap aContent(rAnimBitmap.aBmpEx.GetBitmap()); + + aVirtualDeviceMask.Erase(); + aVirtualDevice.DrawBitmap(rAnimBitmap.aPosPix, aContent); + + if(aMask.IsEmpty()) + { + const Rectangle aRect(rAnimBitmap.aPosPix, aContent.GetSizePixel()); + aVirtualDeviceMask.SetFillColor(COL_BLACK); + aVirtualDeviceMask.SetLineColor(); + aVirtualDeviceMask.DrawRect(aRect); + } + else + { + aVirtualDeviceMask.DrawBitmap(rAnimBitmap.aPosPix, aMask); + } + + break; + } + case DISPOSE_FULL: + { + aVirtualDevice.DrawBitmapEx(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx); + break; + } + case DISPOSE_PREVIOUS : + { + aVirtualDevice.DrawBitmapEx(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx); + aVirtualDeviceMask.DrawBitmap(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx.GetMask()); + break; + } + } + + // create BitmapEx + Bitmap aMainBitmap = aVirtualDevice.GetBitmap(Point(), aVirtualDevice.GetOutputSizePixel()); + Bitmap aMaskBitmap = aVirtualDeviceMask.GetBitmap(Point(), aVirtualDeviceMask.GetOutputSizePixel()); + aNextStep.maBitmapEx = BitmapEx(aMainBitmap, aMaskBitmap); + + // add to vector + maSteps.push_back(aNextStep); + } + } + } +} // end of anonymous namespace + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive2d + { + Primitive2DSequence create2DDecompositionOfGraphic( + const Graphic& rGraphic, + const basegfx::B2DHomMatrix& rTransform) + { + Primitive2DSequence aRetval; + + switch(rGraphic.GetType()) + { + case GRAPHIC_BITMAP : + { + if(rGraphic.IsAnimated()) + { + // prepare animation data + animatedBitmapExPreparator aData(rGraphic); + + if(aData.count()) + { + // create sub-primitives for animated bitmap and the needed animation loop + animation::AnimationEntryLoop aAnimationLoop(aData.loopCount() ? aData.loopCount() : 0xffff); + Primitive2DSequence aBitmapPrimitives(aData.count()); + + for(sal_uInt32 a(0); a < aData.count(); a++) + { + animation::AnimationEntryFixed aTime((double)aData.stepTime(a), (double)a / (double)aData.count()); + aAnimationLoop.append(aTime); + aBitmapPrimitives[a] = new BitmapPrimitive2D( + aData.stepBitmapEx(a), + rTransform); + } + + // prepare animation list + animation::AnimationEntryList aAnimationList; + aAnimationList.append(aAnimationLoop); + + // create and add animated switch primitive + aRetval.realloc(1); + aRetval[0] = new AnimatedSwitchPrimitive2D( + aAnimationList, + aBitmapPrimitives, + false); + } + } + else if(rGraphic.getSvgData().get()) + { + // embedded Svg fill, create embed transform + const basegfx::B2DRange& rSvgRange(rGraphic.getSvgData()->getRange()); + + if(basegfx::fTools::more(rSvgRange.getWidth(), 0.0) && basegfx::fTools::more(rSvgRange.getHeight(), 0.0)) + { + // translate back to origin, scale to unit coordinates + basegfx::B2DHomMatrix aEmbedSvg( + basegfx::tools::createTranslateB2DHomMatrix( + -rSvgRange.getMinX(), + -rSvgRange.getMinY())); + + aEmbedSvg.scale( + 1.0 / rSvgRange.getWidth(), + 1.0 / rSvgRange.getHeight()); + + // apply created object transformation + aEmbedSvg = rTransform * aEmbedSvg; + + // add Svg primitives embedded + aRetval.realloc(1); + aRetval[0] = new TransformPrimitive2D( + aEmbedSvg, + rGraphic.getSvgData()->getPrimitive2DSequence()); + } + } + else + { + aRetval.realloc(1); + aRetval[0] = new BitmapPrimitive2D( + rGraphic.GetBitmapEx(), + rTransform); + } + + break; + } + + case GRAPHIC_GDIMETAFILE : + { +#ifdef USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE + static bool bDoTest(false); + + if(bDoTest) + { + // All this is/was test code for testing MetafilePrimitive2D::create2DDecomposition + // extensively. It may be needed again when diverse actions need debugging, so i leave + // it in here, but take it out using USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE. + // Use it by compiling with the code, insert any DrawObject, convert to Metafile. The + // debugger will then stop here (when breakpoint set, of course). You may enter single + // parts of actions and/or change to true what You want to check. + GDIMetaFile aMtf; + VirtualDevice aOut; + const basegfx::B2DRange aRange(getB2DRange(rViewInformation)); + const Rectangle aRectangle( + basegfx::fround(aRange.getMinX()), basegfx::fround(aRange.getMinY()), + basegfx::fround(aRange.getMaxX()), basegfx::fround(aRange.getMaxY())); + const Point aOrigin(aRectangle.TopLeft()); + const Fraction aScaleX(aRectangle.getWidth()); + const Fraction aScaleY(aRectangle.getHeight()); + MapMode aMapMode(MAP_100TH_MM, aOrigin, aScaleX, aScaleY); + + Size aDummySize(2, 2); + aOut.SetOutputSizePixel(aDummySize); + aOut.EnableOutput(FALSE); + aOut.SetMapMode(aMapMode); + + aMtf.Clear(); + aMtf.Record(&aOut); + + const Fraction aNeutralFraction(1, 1); + const MapMode aRelativeMapMode( + MAP_RELATIVE, + Point(-aRectangle.Left(), -aRectangle.Top()), + aNeutralFraction, aNeutralFraction); + aOut.SetMapMode(aRelativeMapMode); + + if(false) + { + const sal_Int32 nHor(aRectangle.getWidth() / 4); + const sal_Int32 nVer(aRectangle.getHeight() / 4); + const Rectangle aCenteredRectangle( + aRectangle.Left() + nHor, aRectangle.Top() + nVer, + aRectangle.Right() - nHor, aRectangle.Bottom() - nVer); + aOut.SetClipRegion(aCenteredRectangle); + } + + if(false) + { + const Rectangle aRightRectangle(aRectangle.TopCenter(), aRectangle.BottomRight()); + aOut.IntersectClipRegion(aRightRectangle); + } + + if(false) + { + const Rectangle aRightRectangle(aRectangle.TopCenter(), aRectangle.BottomRight()); + const Rectangle aBottomRectangle(aRectangle.LeftCenter(), aRectangle.BottomRight()); + Region aRegion(aRightRectangle); + aRegion.Intersect(aBottomRectangle); + aOut.IntersectClipRegion(aRegion); + } + + if(false) + { + const sal_Int32 nHor(aRectangle.getWidth() / 10); + const sal_Int32 nVer(aRectangle.getHeight() / 10); + aOut.MoveClipRegion(nHor, nVer); + } + + if(false) + { + Wallpaper aWallpaper(Color(COL_BLACK)); + aOut.DrawWallpaper(aRectangle, aWallpaper); + } + + if(false) + { + Wallpaper aWallpaper(Gradient(GRADIENT_LINEAR, Color(COL_RED), Color(COL_GREEN))); + aOut.DrawWallpaper(aRectangle, aWallpaper); + } + + if(false) + { + SvFileStream aRead((const String&)String(ByteString( "c:\\test.png" ), RTL_TEXTENCODING_UTF8), STREAM_READ); + vcl::PNGReader aPNGReader(aRead); + BitmapEx aBitmapEx(aPNGReader.Read()); + Wallpaper aWallpaper(aBitmapEx); + aOut.DrawWallpaper(aRectangle, aWallpaper); + } + + if(false) + { + const double fHor(aRectangle.getWidth()); + const double fVer(aRectangle.getHeight()); + Color aColor(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)); + + for(sal_uInt32 a(0); a < 5000; a++) + { + const Point aPoint( + aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)), + aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0))); + + if(!(a % 3)) + { + aColor = Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)); + } + + aOut.DrawPixel(aPoint, aColor); + } + } + + if(false) + { + const double fHor(aRectangle.getWidth()); + const double fVer(aRectangle.getHeight()); + + aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); + aOut.SetFillColor(); + + for(sal_uInt32 a(0); a < 5000; a++) + { + const Point aPoint( + aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)), + aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0))); + aOut.DrawPixel(aPoint); + } + } + + if(false) + { + const double fHor(aRectangle.getWidth()); + const double fVer(aRectangle.getHeight()); + + aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); + aOut.SetFillColor(); + + Point aStart( + aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)), + aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0))); + Point aStop( + aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)), + aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0))); + + LineInfo aLineInfo(LINE_SOLID, basegfx::fround(fHor / 50.0)); + bool bUseLineInfo(false); + + for(sal_uInt32 a(0); a < 20; a++) + { + if(!(a%6)) + { + bUseLineInfo = !bUseLineInfo; + } + + if(!(a%4)) + { + aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); + } + + if(a%3) + { + aStart = aStop; + aStop = Point( + aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)), + aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0))); + } + else + { + aStart = Point( + aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)), + aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0))); + aStop = Point( + aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)), + aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0))); + } + + if(bUseLineInfo) + { + aOut.DrawLine(aStart, aStop, aLineInfo); + } + else + { + aOut.DrawLine(aStart, aStop); + } + } + } + + if(false) + { + aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); + aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); + aOut.DrawRect(aRectangle); + } + + if(false) + { + aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); + aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); + const sal_uInt32 nHor(aRectangle.getWidth() / 10); + const sal_uInt32 nVer(aRectangle.getHeight() / 10); + aOut.DrawRect(aRectangle, nHor, nVer); + } + + if(false) + { + aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); + aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); + aOut.DrawEllipse(aRectangle); + } + + if(false) + { + aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); + aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); + aOut.DrawArc(aRectangle, aRectangle.TopLeft(), aRectangle.BottomCenter()); + } + + if(false) + { + aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); + aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); + aOut.DrawPie(aRectangle, aRectangle.TopLeft(), aRectangle.BottomCenter()); + } + + if(false) + { + aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); + aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); + aOut.DrawChord(aRectangle, aRectangle.TopLeft(), aRectangle.BottomCenter()); + } + + if(false) + { + const double fHor(aRectangle.getWidth()); + const double fVer(aRectangle.getHeight()); + + for(sal_uInt32 b(0); b < 5; b++) + { + const sal_uInt32 nCount(basegfx::fround(rand() * (20 / 32767.0))); + const bool bClose(basegfx::fround(rand() / 32767.0)); + Polygon aPolygon(nCount + (bClose ? 1 : 0)); + + for(sal_uInt32 a(0); a < nCount; a++) + { + const Point aPoint( + aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)), + aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0))); + aPolygon[a] = aPoint; + } + + if(bClose) + { + aPolygon[aPolygon.GetSize() - 1] = aPolygon[0]; + } + + aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); + aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); + + if(!(b%2)) + { + const LineInfo aLineInfo(LINE_SOLID, basegfx::fround(fHor / 50.0)); + aOut.DrawPolyLine(aPolygon, aLineInfo); + } + else + { + aOut.DrawPolyLine(aPolygon); + } + } + } + + if(false) + { + const double fHor(aRectangle.getWidth()); + const double fVer(aRectangle.getHeight()); + + for(sal_uInt32 b(0); b < 5; b++) + { + const sal_uInt32 nCount(basegfx::fround(rand() * (20 / 32767.0))); + const bool bClose(basegfx::fround(rand() / 32767.0)); + Polygon aPolygon(nCount + (bClose ? 1 : 0)); + + for(sal_uInt32 a(0); a < nCount; a++) + { + const Point aPoint( + aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)), + aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0))); + aPolygon[a] = aPoint; + } + + if(bClose) + { + aPolygon[aPolygon.GetSize() - 1] = aPolygon[0]; + } + + aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); + aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); + aOut.DrawPolygon(aPolygon); + } + } + + if(false) + { + const double fHor(aRectangle.getWidth()); + const double fVer(aRectangle.getHeight()); + PolyPolygon aPolyPolygon; + + for(sal_uInt32 b(0); b < 3; b++) + { + const sal_uInt32 nCount(basegfx::fround(rand() * (6 / 32767.0))); + const bool bClose(basegfx::fround(rand() / 32767.0)); + Polygon aPolygon(nCount + (bClose ? 1 : 0)); + + for(sal_uInt32 a(0); a < nCount; a++) + { + const Point aPoint( + aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)), + aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0))); + aPolygon[a] = aPoint; + } + + if(bClose) + { + aPolygon[aPolygon.GetSize() - 1] = aPolygon[0]; + } + + aPolyPolygon.Insert(aPolygon); + } + + aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); + aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0))); + aOut.DrawPolyPolygon(aPolyPolygon); + } + + if(false) + { + SvFileStream aRead((const String&)String(ByteString( "c:\\test.png" ), RTL_TEXTENCODING_UTF8), STREAM_READ); + vcl::PNGReader aPNGReader(aRead); + BitmapEx aBitmapEx(aPNGReader.Read()); + aOut.DrawBitmapEx(aRectangle.TopLeft(), aBitmapEx); + } + + if(false) + { + SvFileStream aRead((const String&)String(ByteString( "c:\\test.png" ), RTL_TEXTENCODING_UTF8), STREAM_READ); + vcl::PNGReader aPNGReader(aRead); + BitmapEx aBitmapEx(aPNGReader.Read()); + aOut.DrawBitmapEx(aRectangle.TopLeft(), aRectangle.GetSize(), aBitmapEx); + } + + if(false) + { + SvFileStream aRead((const String&)String(ByteString( "c:\\test.png" ), RTL_TEXTENCODING_UTF8), STREAM_READ); + vcl::PNGReader aPNGReader(aRead); + BitmapEx aBitmapEx(aPNGReader.Read()); + const Size aSizePixel(aBitmapEx.GetSizePixel()); + aOut.DrawBitmapEx( + aRectangle.TopLeft(), + aRectangle.GetSize(), + Point(0, 0), + Size(aSizePixel.Width() /2, aSizePixel.Height() / 2), + aBitmapEx); + } + + if(false) + { + const double fHor(aRectangle.getWidth()); + const double fVer(aRectangle.getHeight()); + const Point aPointA( + aRectangle.Left() + basegfx::fround(fHor * 0.2), + aRectangle.Top() + basegfx::fround(fVer * 0.3)); + const Point aPointB( + aRectangle.Left() + basegfx::fround(fHor * 0.2), + aRectangle.Top() + basegfx::fround(fVer * 0.5)); + const Point aPointC( + aRectangle.Left() + basegfx::fround(fHor * 0.2), + aRectangle.Top() + basegfx::fround(fVer * 0.7)); + const String aText(ByteString("Hello, World!"), RTL_TEXTENCODING_UTF8); + + const String aFontName(ByteString("Comic Sans MS"), RTL_TEXTENCODING_UTF8); + Font aFont(aFontName, Size(0, 1000)); + aFont.SetAlign(ALIGN_BASELINE); + aFont.SetColor(COL_RED); + //sal_Int32* pDXArray = new sal_Int32[aText.Len()]; + + aFont.SetOutline(true); + aOut.SetFont(aFont); + aOut.DrawText(aPointA, aText, 0, aText.Len()); + + aFont.SetShadow(true); + aOut.SetFont(aFont); + aOut.DrawText(aPointB, aText, 0, aText.Len()); + + aFont.SetRelief(RELIEF_EMBOSSED); + aOut.SetFont(aFont); + aOut.DrawText(aPointC, aText, 0, aText.Len()); + + //delete pDXArray; + } + + if(false) + { + const double fHor(aRectangle.getWidth()); + const double fVer(aRectangle.getHeight()); + const Point aPointA( + aRectangle.Left() + basegfx::fround(fHor * 0.2), + aRectangle.Top() + basegfx::fround(fVer * 0.3)); + const Point aPointB( + aRectangle.Left() + basegfx::fround(fHor * 0.2), + aRectangle.Top() + basegfx::fround(fVer * 0.5)); + const Point aPointC( + aRectangle.Left() + basegfx::fround(fHor * 0.2), + aRectangle.Top() + basegfx::fround(fVer * 0.7)); + const String aText(ByteString("Hello, World!"), RTL_TEXTENCODING_UTF8); + + const String aFontName(ByteString("Comic Sans MS"), RTL_TEXTENCODING_UTF8); + Font aFont(aFontName, Size(0, 1000)); + aFont.SetAlign(ALIGN_BASELINE); + aFont.SetColor(COL_RED); + + aOut.SetFont(aFont); + const sal_Int32 nWidth(aOut.GetTextWidth(aText, 0, aText.Len())); + aOut.DrawText(aPointA, aText, 0, aText.Len()); + aOut.DrawTextLine(aPointA, nWidth, STRIKEOUT_SINGLE, UNDERLINE_SINGLE, UNDERLINE_SMALLWAVE); + aOut.DrawTextLine(aPointB, nWidth, STRIKEOUT_SINGLE, UNDERLINE_SINGLE, UNDERLINE_SMALLWAVE); + aOut.DrawTextLine(aPointC, nWidth, STRIKEOUT_SINGLE, UNDERLINE_SINGLE, UNDERLINE_SMALLWAVE); + } + + aMtf.Stop(); + aMtf.WindStart(); + aMtf.SetPrefMapMode(MapMode(MAP_100TH_MM)); + aMtf.SetPrefSize(Size(aRectangle.getWidth(), aRectangle.getHeight())); + + aRetval.realloc(1); + aRetval[0] = new MetafilePrimitive2D( + rTransform, + aMtf); + } + else + { +#endif // USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE + // create MetafilePrimitive2D + const GDIMetaFile& rMetafile = rGraphic.GetGDIMetaFile(); + + aRetval.realloc(1); + aRetval[0] = new MetafilePrimitive2D( + rTransform, + rMetafile); + + // #i100357# find out if clipping is needed for this primitive. Unfortunately, + // there exist Metafiles who's content is bigger than the proposed PrefSize set + // at them. This is an error, but we need to work around this + const Size aMetaFilePrefSize(rMetafile.GetPrefSize()); + const Size aMetaFileRealSize( + const_cast< GDIMetaFile& >(rMetafile).GetBoundRect( + *Application::GetDefaultDevice()).GetSize()); + + if(aMetaFileRealSize.getWidth() > aMetaFilePrefSize.getWidth() + || aMetaFileRealSize.getHeight() > aMetaFilePrefSize.getHeight()) + { + // clipping needed. Embed to MaskPrimitive2D. Create childs and mask polygon + basegfx::B2DPolygon aMaskPolygon(basegfx::tools::createUnitPolygon()); + aMaskPolygon.transform(rTransform); + + aRetval[0] = new MaskPrimitive2D( + basegfx::B2DPolyPolygon(aMaskPolygon), + aRetval); + } +#ifdef USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE + } +#endif // USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE + + break; + } + + default: + { + // nothing to create + break; + } + } + + return aRetval; + } + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive2d/metafileprimitive2d.cxx b/drawinglayer/source/primitive2d/metafileprimitive2d.cxx index 2663043b9f39..11f9fd790f5b 100644 --- a/drawinglayer/source/primitive2d/metafileprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/metafileprimitive2d.cxx @@ -50,7 +50,7 @@ #include <basegfx/polygon/b2dpolygonclipper.hxx> #include <drawinglayer/primitive2d/invertprimitive2d.hxx> #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx> -#include <drawinglayer/primitive2d/fillbitmapprimitive2d.hxx> +#include <drawinglayer/primitive2d/fillgraphicprimitive2d.hxx> #include <drawinglayer/primitive2d/wallpaperprimitive2d.hxx> #include <drawinglayer/primitive2d/textprimitive2d.hxx> #include <drawinglayer/primitive2d/textlayoutdevice.hxx> diff --git a/drawinglayer/source/primitive2d/patternfillprimitive2d.cxx b/drawinglayer/source/primitive2d/patternfillprimitive2d.cxx index 9b0f9ef844f5..8c0893ff3d11 100644 --- a/drawinglayer/source/primitive2d/patternfillprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/patternfillprimitive2d.cxx @@ -57,7 +57,8 @@ namespace drawinglayer { // create tiling matrices ::std::vector< basegfx::B2DHomMatrix > aMatrices; - texture::GeoTexSvxTiled aTiling(getReferenceRange().getMinimum(), getReferenceRange().getRange()); + texture::GeoTexSvxTiled aTiling(getReferenceRange()); + aTiling.appendTransformations(aMatrices); // check if content needs to be clipped diff --git a/drawinglayer/source/primitive2d/polypolygonprimitive2d.cxx b/drawinglayer/source/primitive2d/polypolygonprimitive2d.cxx index 7be70aa83aa1..be8300fdba69 100644 --- a/drawinglayer/source/primitive2d/polypolygonprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/polypolygonprimitive2d.cxx @@ -31,9 +31,11 @@ #include <drawinglayer/primitive2d/maskprimitive2d.hxx> #include <drawinglayer/primitive2d/fillhatchprimitive2d.hxx> #include <basegfx/matrix/b2dhommatrix.hxx> -#include <drawinglayer/primitive2d/fillbitmapprimitive2d.hxx> +#include <drawinglayer/primitive2d/fillgraphicprimitive2d.hxx> #include <drawinglayer/primitive2d/polygonprimitive2d.hxx> #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <vcl/graph.hxx> ////////////////////////////////////////////////////////////////////////////// @@ -510,56 +512,69 @@ namespace drawinglayer { namespace primitive2d { - Primitive2DSequence PolyPolygonBitmapPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const + Primitive2DSequence PolyPolygonGraphicPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const { - if(!getFillBitmap().isDefault()) + if(!getFillGraphic().isDefault()) { - // create SubSequence with FillBitmapPrimitive2D - const basegfx::B2DRange aPolyPolygonRange(getB2DPolyPolygon().getB2DRange()); - basegfx::B2DHomMatrix aNewObjectTransform; - aNewObjectTransform.set(0, 0, aPolyPolygonRange.getWidth()); - aNewObjectTransform.set(1, 1, aPolyPolygonRange.getHeight()); - aNewObjectTransform.set(0, 2, aPolyPolygonRange.getMinX()); - aNewObjectTransform.set(1, 2, aPolyPolygonRange.getMinY()); - FillBitmapPrimitive2D* pNewBitmap = new FillBitmapPrimitive2D(aNewObjectTransform, getFillBitmap()); - const Primitive2DReference xSubRef(pNewBitmap); - const Primitive2DSequence aSubSequence(&xSubRef, 1L); + const Graphic& rGraphic = getFillGraphic().getGraphic(); + const GraphicType aType(rGraphic.GetType()); - // create mask primitive - MaskPrimitive2D* pNewMask = new MaskPrimitive2D(getB2DPolyPolygon(), aSubSequence); - const Primitive2DReference xRef(pNewMask); + // is there a bitmap or a metafile (do we have content)? + if(GRAPHIC_BITMAP == aType || GRAPHIC_GDIMETAFILE == aType) + { + const Size aPrefSize(rGraphic.GetPrefSize()); - return Primitive2DSequence(&xRef, 1); - } - else - { - return Primitive2DSequence(); + // does content have a size? + if(aPrefSize.Width() && aPrefSize.Height()) + { + // create SubSequence with FillGraphicPrimitive2D based on polygon range + const basegfx::B2DRange aPolyPolygonRange(getB2DPolyPolygon().getB2DRange()); + const basegfx::B2DHomMatrix aNewObjectTransform( + basegfx::tools::createScaleTranslateB2DHomMatrix( + aPolyPolygonRange.getRange(), + aPolyPolygonRange.getMinimum())); + const Primitive2DReference xSubRef( + new FillGraphicPrimitive2D( + aNewObjectTransform, + getFillGraphic())); + + // embed to mask primitive + const Primitive2DReference xRef( + new MaskPrimitive2D( + getB2DPolyPolygon(), + Primitive2DSequence(&xSubRef, 1))); + + return Primitive2DSequence(&xRef, 1); + } + } } + + return Primitive2DSequence(); } - PolyPolygonBitmapPrimitive2D::PolyPolygonBitmapPrimitive2D( + PolyPolygonGraphicPrimitive2D::PolyPolygonGraphicPrimitive2D( const basegfx::B2DPolyPolygon& rPolyPolygon, - const attribute::FillBitmapAttribute& rFillBitmap) + const attribute::FillGraphicAttribute& rFillGraphic) : BufferedDecompositionPrimitive2D(), maPolyPolygon(rPolyPolygon), - maFillBitmap(rFillBitmap) + maFillGraphic(rFillGraphic) { } - bool PolyPolygonBitmapPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + bool PolyPolygonGraphicPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const { if(BufferedDecompositionPrimitive2D::operator==(rPrimitive)) { - const PolyPolygonBitmapPrimitive2D& rCompare = (PolyPolygonBitmapPrimitive2D&)rPrimitive; + const PolyPolygonGraphicPrimitive2D& rCompare = (PolyPolygonGraphicPrimitive2D&)rPrimitive; - return (getFillBitmap() == rCompare.getFillBitmap()); + return (getFillGraphic() == rCompare.getFillGraphic()); } return false; } // provide unique ID - ImplPrimitrive2DIDBlock(PolyPolygonBitmapPrimitive2D, PRIMITIVE2D_ID_POLYPOLYGONBITMAPPRIMITIVE2D) + ImplPrimitrive2DIDBlock(PolyPolygonGraphicPrimitive2D, PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D) } // end of namespace primitive2d } // end of namespace drawinglayer diff --git a/drawinglayer/source/primitive2d/wallpaperprimitive2d.cxx b/drawinglayer/source/primitive2d/wallpaperprimitive2d.cxx index bcb81a566ee9..ffb341c4fe64 100644 --- a/drawinglayer/source/primitive2d/wallpaperprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/wallpaperprimitive2d.cxx @@ -27,10 +27,12 @@ #include <drawinglayer/primitive2d/wallpaperprimitive2d.hxx> #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> -#include <drawinglayer/primitive2d/fillbitmapprimitive2d.hxx> +#include <drawinglayer/primitive2d/fillgraphicprimitive2d.hxx> #include <basegfx/polygon/b2dpolygontools.hxx> #include <basegfx/polygon/b2dpolygon.hxx> #include <drawinglayer/primitive2d/maskprimitive2d.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <vcl/graph.hxx> ////////////////////////////////////////////////////////////////////////////// @@ -182,26 +184,23 @@ namespace drawinglayer aRelativeTopLeft.setY(0.5 - aRelativeSize.getY()); } - // prepare FillBitmapAttribute - const attribute::FillBitmapAttribute aFillBitmapAttribute( - getBitmapEx(), - aRelativeTopLeft, - aRelativeSize, + // prepare FillGraphicAttribute + const attribute::FillGraphicAttribute aFillGraphicAttribute( + Graphic(getBitmapEx()), + basegfx::B2DRange(aRelativeTopLeft, aRelativeTopLeft+ aRelativeSize), true); // create ObjectTransform - basegfx::B2DHomMatrix aObjectTransform; - - aObjectTransform.set(0, 0, getLocalObjectRange().getWidth()); - aObjectTransform.set(1, 1, getLocalObjectRange().getHeight()); - aObjectTransform.set(0, 2, getLocalObjectRange().getMinX()); - aObjectTransform.set(1, 2, getLocalObjectRange().getMinY()); + const basegfx::B2DHomMatrix aObjectTransform( + basegfx::tools::createScaleTranslateB2DHomMatrix( + getLocalObjectRange().getRange(), + getLocalObjectRange().getMinimum())); // create FillBitmapPrimitive const drawinglayer::primitive2d::Primitive2DReference xFillBitmap( - new drawinglayer::primitive2d::FillBitmapPrimitive2D( + new drawinglayer::primitive2d::FillGraphicPrimitive2D( aObjectTransform, - aFillBitmapAttribute)); + aFillGraphicAttribute)); aRetval = Primitive2DSequence(&xFillBitmap, 1); // always embed tiled fill to clipping diff --git a/drawinglayer/source/primitive3d/sdrdecompositiontools3d.cxx b/drawinglayer/source/primitive3d/sdrdecompositiontools3d.cxx index 08c79e7c8226..3152efad65f8 100644 --- a/drawinglayer/source/primitive3d/sdrdecompositiontools3d.cxx +++ b/drawinglayer/source/primitive3d/sdrdecompositiontools3d.cxx @@ -32,8 +32,8 @@ #include <basegfx/polygon/b3dpolypolygon.hxx> #include <drawinglayer/primitive3d/polypolygonprimitive3d.hxx> #include <vcl/vclenum.hxx> -#include <drawinglayer/attribute/fillbitmapattribute.hxx> -#include <drawinglayer/attribute/sdrfillbitmapattribute.hxx> +#include <drawinglayer/attribute/fillgraphicattribute.hxx> +#include <drawinglayer/attribute/sdrfillgraphicattribute.hxx> #include <vcl/bmpacc.hxx> #include <basegfx/polygon/b3dpolypolygontools.hxx> #include <drawinglayer/primitive3d/textureprimitive3d.hxx> @@ -208,7 +208,7 @@ namespace drawinglayer // look for and evtl. build texture sub-group primitive if(!rFill.getGradient().isDefault() || !rFill.getHatch().isDefault() - || !rFill.getBitmap().isDefault()) + || !rFill.getFillGraphic().isDefault()) { bool bModulate(::com::sun::star::drawing::TextureMode_MODULATE == aSdr3DObjectAttribute.getTextureMode()); bool bFilter(aSdr3DObjectAttribute.getTextureFilter()); @@ -234,13 +234,13 @@ namespace drawinglayer bModulate, bFilter); } - else // if(!rFill.getBitmap().isDefault()) + else // if(!rFill.getFillGraphic().isDefault()) { // create bitmapTexture3D with sublist, add to local aRetval - basegfx::B2DRange aTexRange(0.0, 0.0, rTextureSize.getX(), rTextureSize.getY()); + const basegfx::B2DRange aTexRange(0.0, 0.0, rTextureSize.getX(), rTextureSize.getY()); pNewTexturePrimitive3D = new BitmapTexturePrimitive3D( - rFill.getBitmap().getFillBitmapAttribute(aTexRange), + rFill.getFillGraphic().createFillGraphicAttribute(aTexRange), aRetval, rTextureSize, bModulate, @@ -313,7 +313,7 @@ namespace drawinglayer basegfx::BColor(), attribute::FillGradientAttribute(), attribute::FillHatchAttribute(), - attribute::SdrFillBitmapAttribute()); + attribute::SdrFillGraphicAttribute()); const Primitive3DReference aHidden( new HiddenGeometryPrimitive3D( diff --git a/drawinglayer/source/primitive3d/textureprimitive3d.cxx b/drawinglayer/source/primitive3d/textureprimitive3d.cxx index 10b525724530..77ffb85991b2 100644 --- a/drawinglayer/source/primitive3d/textureprimitive3d.cxx +++ b/drawinglayer/source/primitive3d/textureprimitive3d.cxx @@ -167,12 +167,12 @@ namespace drawinglayer namespace primitive3d { BitmapTexturePrimitive3D::BitmapTexturePrimitive3D( - const attribute::FillBitmapAttribute& rFillBitmapAttribute, + const attribute::FillGraphicAttribute& rFillGraphicAttribute, const Primitive3DSequence& rChildren, const basegfx::B2DVector& rTextureSize, bool bModulate, bool bFilter) : TexturePrimitive3D(rChildren, rTextureSize, bModulate, bFilter), - maFillBitmapAttribute(rFillBitmapAttribute) + maFillGraphicAttribute(rFillGraphicAttribute) { } @@ -182,7 +182,7 @@ namespace drawinglayer { const BitmapTexturePrimitive3D& rCompare = (BitmapTexturePrimitive3D&)rPrimitive; - return (getFillBitmapAttribute() == rCompare.getFillBitmapAttribute()); + return (getFillGraphicAttribute() == rCompare.getFillGraphicAttribute()); } return false; diff --git a/drawinglayer/source/processor2d/_vclmetafileprocessor2d.cxx b/drawinglayer/source/processor2d/_vclmetafileprocessor2d.cxx new file mode 100644 index 000000000000..a1f00503fd1f --- /dev/null +++ b/drawinglayer/source/processor2d/_vclmetafileprocessor2d.cxx @@ -0,0 +1,2086 @@ +/************************************************************** + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + *************************************************************/ + + + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/processor2d/vclmetafileprocessor2d.hxx> +#include <tools/gen.hxx> +#include <vcl/virdev.hxx> +#include <vcl/gdimtf.hxx> +#include <vcl/gradient.hxx> +#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> +#include <drawinglayer/primitive2d/textprimitive2d.hxx> +#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> +#include <drawinglayer/primitive2d/polygonprimitive2d.hxx> +#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> +#include <drawinglayer/primitive2d/metafileprimitive2d.hxx> +#include <drawinglayer/primitive2d/maskprimitive2d.hxx> +#include <basegfx/polygon/b2dpolygonclipper.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx> +#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx> +#include <drawinglayer/primitive2d/transparenceprimitive2d.hxx> +#include <drawinglayer/primitive2d/fillgradientprimitive2d.hxx> +#include <drawinglayer/processor2d/vclpixelprocessor2d.hxx> +#include <tools/stream.hxx> +#include <drawinglayer/primitive2d/transformprimitive2d.hxx> +#include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx> +#include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx> +#include <vcl/graphictools.hxx> +#include <vcl/metaact.hxx> +#include <drawinglayer/primitive2d/texthierarchyprimitive2d.hxx> +#include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx> +#include <comphelper/processfactory.hxx> +#include <rtl/ustring.hxx> +#include <com/sun/star/i18n/CharacterIteratorMode.hdl> +#include <com/sun/star/i18n/WordType.hpp> +#include <drawinglayer/primitive2d/controlprimitive2d.hxx> +#include <drawinglayer/primitive2d/graphicprimitive2d.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx> +#include <drawinglayer/primitive2d/epsprimitive2d.hxx> +#include <basegfx/polygon/b2dlinegeometry.hxx> + +////////////////////////////////////////////////////////////////////////////// +// for PDFExtOutDevData Graphic support + +#include <vcl/graph.hxx> +#include <vcl/svapp.hxx> +#include <toolkit/helper/formpdfexport.hxx> + +////////////////////////////////////////////////////////////////////////////// +// for Control printing + +#include <com/sun/star/beans/XPropertySet.hpp> + +////////////////////////////////////////////////////////////////////////////// +// for StructureTagPrimitive support in sd's unomodel.cxx + +#include <drawinglayer/primitive2d/structuretagprimitive2d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// +// #112245# definition for maximum allowed point count due to Metafile target. +// To be on the safe side with the old tools polygon, use slightly less then +// the theoretical maximum (bad experiences with tools polygon) + +#define MAX_POLYGON_POINT_COUNT_METAFILE (0x0000fff0) + +////////////////////////////////////////////////////////////////////////////// + +namespace +{ + // #112245# helper to split line polygon in half + void splitLinePolygon( + const basegfx::B2DPolygon& rBasePolygon, + basegfx::B2DPolygon& o_aLeft, + basegfx::B2DPolygon& o_aRight) + { + const sal_uInt32 nCount(rBasePolygon.count()); + + if(nCount) + { + const sal_uInt32 nHalfCount((nCount - 1) >> 1); + + o_aLeft = basegfx::B2DPolygon(rBasePolygon, 0, nHalfCount + 1); + o_aLeft.setClosed(false); + + o_aRight = basegfx::B2DPolygon(rBasePolygon, nHalfCount, nCount - nHalfCount); + o_aRight.setClosed(false); + + if(rBasePolygon.isClosed()) + { + o_aRight.append(rBasePolygon.getB2DPoint(0)); + + if(rBasePolygon.areControlPointsUsed()) + { + o_aRight.setControlPoints( + o_aRight.count() - 1, + rBasePolygon.getPrevControlPoint(0), + rBasePolygon.getNextControlPoint(0)); + } + } + } + else + { + o_aLeft.clear(); + o_aRight.clear(); + } + } + + // #112245# helper to evtl. split filled polygons to maximum metafile point count + bool fillPolyPolygonNeededToBeSplit(basegfx::B2DPolyPolygon& rPolyPolygon) + { + bool bRetval(false); + const sal_uInt32 nPolyCount(rPolyPolygon.count()); + + if(nPolyCount) + { + basegfx::B2DPolyPolygon aSplitted; + + for(sal_uInt32 a(0); a < nPolyCount; a++) + { + const basegfx::B2DPolygon aCandidate(rPolyPolygon.getB2DPolygon(a)); + const sal_uInt32 nPointCount(aCandidate.count()); + bool bNeedToSplit(false); + + if(aCandidate.areControlPointsUsed()) + { + // compare with the maximum for bezier curved polygons + bNeedToSplit = nPointCount > ((MAX_POLYGON_POINT_COUNT_METAFILE / 3L) - 1L); + } + else + { + // compare with the maximum for simple point polygons + bNeedToSplit = nPointCount > (MAX_POLYGON_POINT_COUNT_METAFILE - 1); + } + + if(bNeedToSplit) + { + // need to split the partial polygon + const basegfx::B2DRange aRange(aCandidate.getB2DRange()); + const basegfx::B2DPoint aCenter(aRange.getCenter()); + + if(aRange.getWidth() > aRange.getHeight()) + { + // clip in left and right + const basegfx::B2DPolyPolygon aLeft( + basegfx::tools::clipPolygonOnParallelAxis( + aCandidate, + false, + true, + aCenter.getX(), + false)); + const basegfx::B2DPolyPolygon aRight( + basegfx::tools::clipPolygonOnParallelAxis( + aCandidate, + false, + false, + aCenter.getX(), + false)); + + aSplitted.append(aLeft); + aSplitted.append(aRight); + } + else + { + // clip in top and bottom + const basegfx::B2DPolyPolygon aTop( + basegfx::tools::clipPolygonOnParallelAxis( + aCandidate, + true, + true, + aCenter.getY(), + false)); + const basegfx::B2DPolyPolygon aBottom( + basegfx::tools::clipPolygonOnParallelAxis( + aCandidate, + true, + false, + aCenter.getY(), + false)); + + aSplitted.append(aTop); + aSplitted.append(aBottom); + } + } + else + { + aSplitted.append(aCandidate); + } + } + + if(aSplitted.count() != nPolyCount) + { + rPolyPolygon = aSplitted; + } + } + + return bRetval; + } +} // end of anonymous namespace + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace processor2d + { + Rectangle VclMetafileProcessor2D::impDumpToMetaFile( + const primitive2d::Primitive2DSequence& rContent, + GDIMetaFile& o_rContentMetafile) + { + // Prepare VDev, MetaFile and connections + OutputDevice* pLastOutputDevice = mpOutputDevice; + GDIMetaFile* pLastMetafile = mpMetaFile; + basegfx::B2DRange aPrimitiveRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rContent, getViewInformation2D())); + + // transform primitive range with current transformation (e.g shadow offset) + aPrimitiveRange.transform(maCurrentTransformation); + + const Rectangle aPrimitiveRectangle( + basegfx::fround(aPrimitiveRange.getMinX()), basegfx::fround(aPrimitiveRange.getMinY()), + basegfx::fround(aPrimitiveRange.getMaxX()), basegfx::fround(aPrimitiveRange.getMaxY())); + VirtualDevice aContentVDev; + MapMode aNewMapMode(pLastOutputDevice->GetMapMode()); + + mpOutputDevice = &aContentVDev; + mpMetaFile = &o_rContentMetafile; + aContentVDev.EnableOutput(false); + aContentVDev.SetMapMode(pLastOutputDevice->GetMapMode()); + o_rContentMetafile.Record(&aContentVDev); + aContentVDev.SetLineColor(pLastOutputDevice->GetLineColor()); + aContentVDev.SetFillColor(pLastOutputDevice->GetFillColor()); + aContentVDev.SetFont(pLastOutputDevice->GetFont()); + aContentVDev.SetDrawMode(pLastOutputDevice->GetDrawMode()); + aContentVDev.SetSettings(pLastOutputDevice->GetSettings()); + aContentVDev.SetRefPoint(pLastOutputDevice->GetRefPoint()); + + // dump to MetaFile + process(rContent); + + // cleanups + o_rContentMetafile.Stop(); + o_rContentMetafile.WindStart(); + aNewMapMode.SetOrigin(aPrimitiveRectangle.TopLeft()); + o_rContentMetafile.SetPrefMapMode(aNewMapMode); + o_rContentMetafile.SetPrefSize(aPrimitiveRectangle.GetSize()); + mpOutputDevice = pLastOutputDevice; + mpMetaFile = pLastMetafile; + + return aPrimitiveRectangle; + } + + void VclMetafileProcessor2D::impConvertFillGradientAttributeToVCLGradient( + Gradient& o_rVCLGradient, + const attribute::FillGradientAttribute& rFiGrAtt, + bool bIsTransparenceGradient) + { + if(bIsTransparenceGradient) + { + // it's about transparence channel intensities (black/white), do not use color modifier + o_rVCLGradient.SetStartColor(Color(rFiGrAtt.getStartColor())); + o_rVCLGradient.SetEndColor(Color(rFiGrAtt.getEndColor())); + } + else + { + // use color modifier to influence start/end color of gradient + o_rVCLGradient.SetStartColor(Color(maBColorModifierStack.getModifiedColor(rFiGrAtt.getStartColor()))); + o_rVCLGradient.SetEndColor(Color(maBColorModifierStack.getModifiedColor(rFiGrAtt.getEndColor()))); + } + + o_rVCLGradient.SetAngle(static_cast< sal_uInt16 >(rFiGrAtt.getAngle() * (1.0 / F_PI1800))); + o_rVCLGradient.SetBorder(static_cast< sal_uInt16 >(rFiGrAtt.getBorder() * 100.0)); + o_rVCLGradient.SetOfsX(static_cast< sal_uInt16 >(rFiGrAtt.getOffsetX() * 100.0)); + o_rVCLGradient.SetOfsY(static_cast< sal_uInt16 >(rFiGrAtt.getOffsetY() * 100.0)); + o_rVCLGradient.SetSteps(rFiGrAtt.getSteps()); + + // defaults for intensity; those were computed into the start/end colors already + o_rVCLGradient.SetStartIntensity(100); + o_rVCLGradient.SetEndIntensity(100); + + switch(rFiGrAtt.getStyle()) + { + default : // attribute::GRADIENTSTYLE_LINEAR : + { + o_rVCLGradient.SetStyle(GRADIENT_LINEAR); + break; + } + case attribute::GRADIENTSTYLE_AXIAL : + { + o_rVCLGradient.SetStyle(GRADIENT_AXIAL); + break; + } + case attribute::GRADIENTSTYLE_RADIAL : + { + o_rVCLGradient.SetStyle(GRADIENT_RADIAL); + break; + } + case attribute::GRADIENTSTYLE_ELLIPTICAL : + { + o_rVCLGradient.SetStyle(GRADIENT_ELLIPTICAL); + break; + } + case attribute::GRADIENTSTYLE_SQUARE : + { + o_rVCLGradient.SetStyle(GRADIENT_SQUARE); + break; + } + case attribute::GRADIENTSTYLE_RECT : + { + o_rVCLGradient.SetStyle(GRADIENT_RECT); + break; + } + } + } + + void VclMetafileProcessor2D::impStartSvtGraphicFill(SvtGraphicFill* pSvtGraphicFill) + { + if(pSvtGraphicFill && !mnSvtGraphicFillCount) + { + SvMemoryStream aMemStm; + + aMemStm << *pSvtGraphicFill; + mpMetaFile->AddAction(new MetaCommentAction("XPATHFILL_SEQ_BEGIN", 0, static_cast< const sal_uInt8* >(aMemStm.GetData()), aMemStm.Seek(STREAM_SEEK_TO_END))); + mnSvtGraphicFillCount++; + } + } + + void VclMetafileProcessor2D::impEndSvtGraphicFill(SvtGraphicFill* pSvtGraphicFill) + { + if(pSvtGraphicFill && mnSvtGraphicFillCount) + { + mnSvtGraphicFillCount--; + mpMetaFile->AddAction(new MetaCommentAction("XPATHFILL_SEQ_END")); + delete pSvtGraphicFill; + } + } + + SvtGraphicStroke* VclMetafileProcessor2D::impTryToCreateSvtGraphicStroke( + const basegfx::B2DPolygon& rB2DPolygon, + const basegfx::BColor* pColor, + const attribute::LineAttribute* pLineAttribute, + const attribute::StrokeAttribute* pStrokeAttribute, + const attribute::LineStartEndAttribute* pStart, + const attribute::LineStartEndAttribute* pEnd) + { + SvtGraphicStroke* pRetval = 0; + + if(rB2DPolygon.count() && !mnSvtGraphicStrokeCount) + { + basegfx::BColor aStrokeColor; + basegfx::B2DPolyPolygon aStartArrow; + basegfx::B2DPolyPolygon aEndArrow; + + if(pColor) + { + aStrokeColor = *pColor; + } + else if(pLineAttribute) + { + aStrokeColor = maBColorModifierStack.getModifiedColor(pLineAttribute->getColor()); + } + + // It IS needed to record the stroke color at all in the metafile, + // SvtGraphicStroke has NO entry for stroke color(!) + mpOutputDevice->SetLineColor(Color(aStrokeColor)); + + if(!rB2DPolygon.isClosed()) + { + double fPolyLength(0.0); + + if(pStart && pStart->isActive()) + { + fPolyLength = basegfx::tools::getLength(rB2DPolygon); + + aStartArrow = basegfx::tools::createAreaGeometryForLineStartEnd( + rB2DPolygon, pStart->getB2DPolyPolygon(), true, pStart->getWidth(), + fPolyLength, pStart->isCentered() ? 0.5 : 0.0, 0); + } + + if(pEnd && pEnd->isActive()) + { + if(basegfx::fTools::equalZero(fPolyLength)) + { + fPolyLength = basegfx::tools::getLength(rB2DPolygon); + } + + aEndArrow = basegfx::tools::createAreaGeometryForLineStartEnd( + rB2DPolygon, pEnd->getB2DPolyPolygon(), false, pEnd->getWidth(), + fPolyLength, pEnd->isCentered() ? 0.5 : 0.0, 0); + } + } + + SvtGraphicStroke::JoinType eJoin(SvtGraphicStroke::joinNone); + SvtGraphicStroke::CapType eCap(SvtGraphicStroke::capButt); + double fLineWidth(0.0); + double fMiterLength(0.0); + SvtGraphicStroke::DashArray aDashArray; + + if(pLineAttribute) + { + // pre-fill fLineWidth #119198# Need to apply maCurrentTransformation, too (!) + const basegfx::B2DVector aDiscreteUnit(maCurrentTransformation * basegfx::B2DVector(pLineAttribute->getWidth(), 0.0)); + fLineWidth = aDiscreteUnit.getLength(); + + // pre-fill fMiterLength + fMiterLength = fLineWidth; + + // get Join + switch(pLineAttribute->getLineJoin()) + { + default : // basegfx::B2DLINEJOIN_NONE : + { + eJoin = SvtGraphicStroke::joinNone; + break; + } + case basegfx::B2DLINEJOIN_BEVEL : + { + eJoin = SvtGraphicStroke::joinBevel; + break; + } + case basegfx::B2DLINEJOIN_MIDDLE : + case basegfx::B2DLINEJOIN_MITER : + { + eJoin = SvtGraphicStroke::joinMiter; + // ATM 15 degrees is assumed + fMiterLength /= rtl::math::sin(M_PI * (15.0 / 360.0)); + break; + } + case basegfx::B2DLINEJOIN_ROUND : + { + eJoin = SvtGraphicStroke::joinRound; + break; + } + } + + // get stroke + switch(pLineAttribute->getLineCap()) + { + default: /* com::sun::star::drawing::LineCap_BUTT */ + { + eCap = SvtGraphicStroke::capButt; + break; + } + case com::sun::star::drawing::LineCap_ROUND: + { + eCap = SvtGraphicStroke::capRound; + break; + } + case com::sun::star::drawing::LineCap_SQUARE: + { + eCap = SvtGraphicStroke::capSquare; + break; + } + } + } + + if(pStrokeAttribute) + { + // copy dash array + aDashArray = pStrokeAttribute->getDotDashArray(); + } + + // #i101734# apply current object transformation to created geometry. + // This is a partial fix. When a object transformation is used which + // e.g. contains a scaleX != scaleY, an unproportional scaling would + // have to be applied to the evtl. existing fat line. The current + // concept of PDF export and SvtGraphicStroke usage does simply not + // allow handling such definitions. The only clean way would be to + // add the transformation to SvtGraphicStroke and to handle it there + basegfx::B2DPolygon aB2DPolygon(rB2DPolygon); + + aB2DPolygon.transform(maCurrentTransformation); + aStartArrow.transform(maCurrentTransformation); + aEndArrow.transform(maCurrentTransformation); + + pRetval = new SvtGraphicStroke( + Polygon(aB2DPolygon), + PolyPolygon(aStartArrow), + PolyPolygon(aEndArrow), + mfCurrentUnifiedTransparence, + fLineWidth, + eCap, + eJoin, + fMiterLength, + aDashArray); + } + + return pRetval; + } + + void VclMetafileProcessor2D::impStartSvtGraphicStroke(SvtGraphicStroke* pSvtGraphicStroke) + { + if(pSvtGraphicStroke && !mnSvtGraphicStrokeCount) + { + SvMemoryStream aMemStm; + + aMemStm << *pSvtGraphicStroke; + mpMetaFile->AddAction(new MetaCommentAction("XPATHSTROKE_SEQ_BEGIN", 0, static_cast< const sal_uInt8* >(aMemStm.GetData()), aMemStm.Seek(STREAM_SEEK_TO_END))); + mnSvtGraphicStrokeCount++; + } + } + + void VclMetafileProcessor2D::impEndSvtGraphicStroke(SvtGraphicStroke* pSvtGraphicStroke) + { + if(pSvtGraphicStroke && mnSvtGraphicStrokeCount) + { + mnSvtGraphicStrokeCount--; + mpMetaFile->AddAction(new MetaCommentAction("XPATHSTROKE_SEQ_END")); + delete pSvtGraphicStroke; + } + } + + // init static break iterator + uno::Reference< ::com::sun::star::i18n::XBreakIterator > VclMetafileProcessor2D::mxBreakIterator; + + VclMetafileProcessor2D::VclMetafileProcessor2D(const geometry::ViewInformation2D& rViewInformation, OutputDevice& rOutDev) + : VclProcessor2D(rViewInformation, rOutDev), + mpMetaFile(rOutDev.GetConnectMetaFile()), + mnSvtGraphicFillCount(0), + mnSvtGraphicStrokeCount(0), + mfCurrentUnifiedTransparence(0.0), + mpPDFExtOutDevData(dynamic_cast< vcl::PDFExtOutDevData* >(rOutDev.GetExtOutDevData())) + { + OSL_ENSURE(rOutDev.GetConnectMetaFile(), "VclMetafileProcessor2D: Used on OutDev which has no MetaFile Target (!)"); + // draw to logic coordinates, do not initialize maCurrentTransformation to viewTransformation + // but only to ObjectTransformation. Do not change MapMode of destination. + maCurrentTransformation = rViewInformation.getObjectTransformation(); + } + + VclMetafileProcessor2D::~VclMetafileProcessor2D() + { + // MapMode was not changed, no restore necessary + } + + /*********************************************************************************************** + + Support of MetaCommentActions in the VclMetafileProcessor2D + Found MetaCommentActions and how they are supported: + + XGRAD_SEQ_BEGIN, XGRAD_SEQ_END: + + Used inside OutputDevice::DrawGradient to mark the start and end of a MetaGradientEx action. + It is used in various exporters/importers to have direct access to the gradient before it + is rendered by VCL (and thus fragmented to polygon color actions and others). On that base, e.g. + the Metafile to SdrObject import creates it's gradient objects. + Best (and safest) way to support it here is to use PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D, + map it back to the corresponding tools PolyPolygon and the Gradient and just call + OutputDevice::DrawGradient which creates the necessary compatible actions. + + XPATHFILL_SEQ_BEGIN, XPATHFILL_SEQ_END: + + Two producers, one is vcl/source/gdi/gdimtf.cxx, line 1273. There, it is transformed + inside GDIMetaFile::Rotate, nothing to take care of here. + The second producer is in graphics/svx/source/svdraw/impgrfll.cxx, line 374. This is used + with each incarnation of Imp_GraphicFill when a metafile is recorded, fillstyle is not + XFILL_NONE and not completely transparent. It creates a SvtGraphicFill and streams it + to the comment action. A closing end token is created in the destructor. + Usages of Imp_GraphicFill are in Do_Paint_Object-methods of SdrCircObj, SdrPathObj and + SdrRectObj. + The token users pick various actions from SvtGraphicFill, so it may need to be added for all kind + of filled objects, even simple colored polygons. It is added as extra information; the + Metafile actions between the two tokens are interpreted as output generated from those + fills. Thus, users have the choice to use the SvtGraphicFill info or the created output + actions. + Even for XFillTransparenceItem it is used, thus it may need to be supported in + UnifiedTransparencePrimitive2D, too, when interpreted as normally filled PolyPolygon. + Implemented for: + PRIMITIVE2D_ID_POLYPOLYGONBITMAPPRIMITIVE2D, + PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D, + PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D, + PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D, + and for PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D when detected unified transparence + + XPATHSTROKE_SEQ_BEGIN, XPATHSTROKE_SEQ_END: + + Similar to pathfill, but using SvtGraphicStroke instead. It also has two producers where one + is also the GDIMetaFile::Rotate. Another user is MetaCommentAction::Move which modifies the + contained path accordingly. + The other one is SdrObject::Imp_DrawLineGeometry. It's done when MetaFile is set at OutDev and + only when geometry is a single polygon (!). I see no reason for that; in the PS exporter this + would hinder to make use of PolyPolygon strokes. I will need to add support at: + PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D + PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D + PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D + This can be done hierarchical, too. + Okay, base implementation done based on those three primitives. + + FIELD_SEQ_BEGIN, FIELD_SEQ_END + + Used from slideshow for URLs, created from diverse SvxField implementations inside + createBeginComment()/createEndComment(). createBeginComment() is used from editeng\impedit3.cxx + inside ImpEditEngine::Paint. + Created TextHierarchyFieldPrimitive2D and added needed infos there; it is an group primitive and wraps + text primitives (but is not limited to that). It contains the field type if special actions for the + support of FIELD_SEQ_BEGIN/END are needed; this is the case for Page and URL fields. If more is + needed, it may be supported there. + FIELD_SEQ_BEGIN;PageField + FIELD_SEQ_END + Okay, these are now completely supported by TextHierarchyFieldPrimitive2D. URL works, too. + + XTEXT + + XTEXT_EOC(i) end of character + XTEXT_EOW(i) end of word + XTEXT_EOS(i) end of sentence + + this three are with index and are created with the help of a i18n::XBreakIterator in + ImplDrawWithComments. Simplifying, moving out text painting, reworking to create some + data structure for holding those TEXT infos. + Supported directly by TextSimplePortionPrimitive2D with adding a Locale to the basic text + primitive. In the MetaFileRenderer, the creation is now done (see below). This has the advantage + that this creations do not need to be done for all paints all the time. This would be + expensive since the BreakIterator and it's usage is expensive and for each paint also the + whole character stops would need to be created. + Created only for TextDecoratedPortionPrimitive2D due to XTEXT_EOL and XTEXT_EOP (see below) + + XTEXT_EOL() end of line + XTEXT_EOP() end of paragraph + + First try with boolean marks at TextDecoratedPortionPrimitive2D did not work too well, + i decided to solve it with structure. I added the TextHierarchyPrimitives for this, + namely: + - TextHierarchyLinePrimitive2D: Encapsulates single line + - TextHierarchyParagraphPrimitive2D: Encapsulates single paragraph + - TextHierarchyBlockPrimitive2D: encapsulates object texts (only one ATM) + Those are now supported in hierarchy. This means the MetaFile renderer will support them + by using them, reculrively using their content and adding MetaFile comments as needed. + This also means that when another text layouter will be used it will be necessary to + create/support the same HierarchyPrimitives to support users. + To transport the information using this hierarchy is best suited to all future needs; + the slideshow will be able to profit from it directly when using primitives; all other + renderers not interested in the text structure will just ignore the encapsulations. + + XTEXT_PAINTSHAPE_BEGIN, XTEXT_PAINTSHAPE_END + Supported now by the TextHierarchyBlockPrimitive2D. + + EPSReplacementGraphic: + Only used in goodies\source\filter.vcl\ieps\ieps.cxx and svx\source\xml\xmlgrhlp.cxx to + hold the original EPS which was imported in the same MetaFile as first 2 entries. Only + used to export the original again (if exists). + Not necessary to support with MetaFuleRenderer. + + XTEXT_SCROLLRECT, XTEXT_PAINTRECT + Currently used to get extra MetaFile infos using GraphicExporter which again uses + SdrTextObj::GetTextScrollMetaFileAndRectangle(). ATM works with primitives since + the rectangle data is added directly by the GraphicsExporter as comment. Does not need + to be adapted at once. + When adapting later, the only user - the diashow - should directly use the provided + Anination infos in the appropriate primitives (e.g. AnimatedSwitchPrimitive2D) + + PRNSPOOL_TRANSPARENTBITMAP_BEGIN, PRNSPOOL_TRANSPARENTBITMAP_END + VCL usage when printing PL -> THB. Okay, THB confirms that it is only used as + a fix (hack) while VCL printing. It is needed to not downscale a bitmap which + was explicitely created for the printer already again to some default maximum + bitmap sizes. + Nothing to do here for the primitive renderer. + + Support for vcl::PDFExtOutDevData: + PL knows that SJ did that stuff, it's used to hold a pointer to PDFExtOutDevData at + the OutDev. When set, some extra data is written there. Trying simple PDF export and + watching if i get those infos. + Well, a PDF export does not use e.g. ImpEditEngine::Paint since the PdfFilter uses + the SdXImpressDocument::render and thus uses the VclMetafileProcessor2D. I will check + if i get a PDFExtOutDevData at the target output device. + Indeed, i get one. Checking what all may be done when that extra-device-info is there. + + All in all i have to talk to SJ. I will need to emulate some of those actions, but + i need to discuss which ones. + In the future, all those infos would be taken from the primitive sequence anyways, + thus these extensions would potentially be temporary, too. + Discussed with SJ, added the necessary support and tested it. Details follow. + + - In ImpEditEngine::Paint, paragraph infos and URL stuff is added. + Added in primitive MetaFile renderer. + Checking URL: Indeed, current version exports it, but it is missing in primitive + CWS version. Adding support. + Okay, URLs work. Checked, Done. + + - UnoControlPDFExportContact is only created when PDFExtOutDevData is used at the + target and uno control data is created in UnoControlPDFExportContact::do_PaintObject. + This may be added in primitive MetaFile renderer. + Adding support... + OOps, the necessary helper stuff is in svx/source/form/formpdxexport.cxx in namespace + svxform. Have to talk to FS if this has to be like that. Especially since + ::vcl::PDFWriter::AnyWidget is filled out, which is already part of vcl. + Wrote an eMail to FS, he is on vacation currently. I see no reason why not to move + that stuff to somewhere else, maybe tools or svtools ?!? We will see... + Moved to toolkit, so i have to link against it. I tried VCL first, but it did + not work since VCLUnoHelper::CreateFont is unresolved in VCL (!). Other then the name + may imply, it is defined in toolkit (!). Since toolkit is linked against VCL itself, + the lowest move,ment plave is toolkit. + Checked form control export, it works well. Done. + + - In goodies, in GraphicObject::Draw, when the used Graphic is linked, infos are + generated. I will need to check what happens here with primitives. + To support, use of GraphicPrimitive2D (PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D) may be needed. + Added support, but feature is broken in main version, so i cannot test at all. + Writing a bug to CL (or SJ) and seeing what happens (#i80380#). + SJ took a look and we got it working. Tested VCL MetaFile Renderer based export, + as intended, the original file is exported. Works, Done. + + + + + To be done: + + - Maybe there are more places to take care of for vcl::PDFExtOutDevData! + + + + ****************************************************************************************************/ + + void VclMetafileProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate) + { + switch(rCandidate.getPrimitive2DID()) + { + case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D : + { + // directdraw of wrong spell primitive + // Ignore for VclMetafileProcessor2D, this is for printing and MetaFile recording only + break; + } + case PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D : + { + const primitive2d::GraphicPrimitive2D& rGraphicPrimitive = static_cast< const primitive2d::GraphicPrimitive2D& >(rCandidate); + bool bUsingPDFExtOutDevData(false); + basegfx::B2DVector aTranslate, aScale; + static bool bSuppressPDFExtOutDevDataSupport(false); + + if(mpPDFExtOutDevData && !bSuppressPDFExtOutDevDataSupport) + { + // emulate data handling from UnoControlPDFExportContact, original see + // svtools/source/graphic/grfmgr.cxx + const Graphic& rGraphic = rGraphicPrimitive.getGraphicObject().GetGraphic(); + + if(rGraphic.IsLink()) + { + const GraphicAttr& rAttr = rGraphicPrimitive.getGraphicAttr(); + + if(!rAttr.IsSpecialDrawMode() && !rAttr.IsAdjusted()) + { + const basegfx::B2DHomMatrix& rTransform = rGraphicPrimitive.getTransform(); + double fRotate, fShearX; + rTransform.decompose(aScale, aTranslate, fRotate, fShearX); + + if( basegfx::fTools::equalZero( fRotate ) && ( aScale.getX() > 0.0 ) && ( aScale.getY() > 0.0 ) ) + { + bUsingPDFExtOutDevData = true; + mpPDFExtOutDevData->BeginGroup(); + } + } + } + } + + // process recursively and add MetaFile comment + process(rGraphicPrimitive.get2DDecomposition(getViewInformation2D())); + + if(bUsingPDFExtOutDevData) + { + // emulate data handling from UnoControlPDFExportContact, original see + // svtools/source/graphic/grfmgr.cxx + const basegfx::B2DRange aCurrentRange( + aTranslate.getX(), aTranslate.getY(), + aTranslate.getX() + aScale.getX(), aTranslate.getY() + aScale.getY()); + const Rectangle aCurrentRect( + sal_Int32(floor(aCurrentRange.getMinX())), sal_Int32(floor(aCurrentRange.getMinY())), + sal_Int32(ceil(aCurrentRange.getMaxX())), sal_Int32(ceil(aCurrentRange.getMaxY()))); + const GraphicAttr& rAttr = rGraphicPrimitive.getGraphicAttr(); + Rectangle aCropRect; + + if(rAttr.IsCropped()) + { + // calculate scalings between real image size and logic object size. This + // is necessary since the crop values are relative to original bitmap size + double fFactorX(1.0); + double fFactorY(1.0); + + { + const MapMode aMapMode100thmm(MAP_100TH_MM); + const Size aBitmapSize(Application::GetDefaultDevice()->LogicToLogic( + rGraphicPrimitive.getGraphicObject().GetPrefSize(), + rGraphicPrimitive.getGraphicObject().GetPrefMapMode(), aMapMode100thmm)); + const double fDivX(aBitmapSize.Width() - rAttr.GetLeftCrop() - rAttr.GetRightCrop()); + const double fDivY(aBitmapSize.Height() - rAttr.GetTopCrop() - rAttr.GetBottomCrop()); + + if(!basegfx::fTools::equalZero(fDivX)) + { + fFactorX = aScale.getX() / fDivX; + } + + if(!basegfx::fTools::equalZero(fDivY)) + { + fFactorY = aScale.getY() / fDivY; + } + } + + // calculate crop range and rect + basegfx::B2DRange aCropRange; + aCropRange.expand(aCurrentRange.getMinimum() - basegfx::B2DPoint(rAttr.GetLeftCrop() * fFactorX, rAttr.GetTopCrop() * fFactorY)); + aCropRange.expand(aCurrentRange.getMaximum() + basegfx::B2DPoint(rAttr.GetRightCrop() * fFactorX, rAttr.GetBottomCrop() * fFactorY)); + + aCropRect = Rectangle( + sal_Int32(floor(aCropRange.getMinX())), sal_Int32(floor(aCropRange.getMinY())), + sal_Int32(ceil(aCropRange.getMaxX())), sal_Int32(ceil(aCropRange.getMaxY()))); + } + + mpPDFExtOutDevData->EndGroup(rGraphicPrimitive.getGraphicObject().GetGraphic(), + rAttr.GetTransparency(), + aCurrentRect, + aCropRect); + } + + break; + } + case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D : + { + const primitive2d::ControlPrimitive2D& rControlPrimitive = static_cast< const primitive2d::ControlPrimitive2D& >(rCandidate); + const uno::Reference< awt::XControl >& rXControl(rControlPrimitive.getXControl()); + bool bIsPrintableControl(false); + + // find out if control is printable + if(rXControl.is()) + { + try + { + uno::Reference< beans::XPropertySet > xModelProperties(rXControl->getModel(), uno::UNO_QUERY); + uno::Reference< beans::XPropertySetInfo > xPropertyInfo(xModelProperties.is() + ? xModelProperties->getPropertySetInfo() + : uno::Reference< beans::XPropertySetInfo >()); + const ::rtl::OUString sPrintablePropertyName(RTL_CONSTASCII_USTRINGPARAM("Printable")); + + if(xPropertyInfo.is() && xPropertyInfo->hasPropertyByName(sPrintablePropertyName)) + { + OSL_VERIFY(xModelProperties->getPropertyValue(sPrintablePropertyName) >>= bIsPrintableControl); + } + } + catch(const uno::Exception&) + { + OSL_ENSURE(false, "VclMetafileProcessor2D: No access to printable flag of Control, caught an exception!"); + } + } + + // PDF export and printing only for printable controls + if(bIsPrintableControl) + { + const bool bPDFExport(mpPDFExtOutDevData && mpPDFExtOutDevData->GetIsExportFormFields()); + bool bDoProcessRecursively(true); + + if(bPDFExport) + { + // PDF export. Emulate data handling from UnoControlPDFExportContact + // I have now moved describePDFControl to toolkit, thus i can implement the PDF + // form control support now as follows + ::std::auto_ptr< ::vcl::PDFWriter::AnyWidget > pPDFControl; + ::toolkitform::describePDFControl( rXControl, pPDFControl, *mpPDFExtOutDevData ); + + if(pPDFControl.get()) + { + // still need to fill in the location (is a class Rectangle) + const basegfx::B2DRange aRangeLogic(rControlPrimitive.getB2DRange(getViewInformation2D())); + const Rectangle aRectLogic( + (sal_Int32)floor(aRangeLogic.getMinX()), (sal_Int32)floor(aRangeLogic.getMinY()), + (sal_Int32)ceil(aRangeLogic.getMaxX()), (sal_Int32)ceil(aRangeLogic.getMaxY())); + pPDFControl->Location = aRectLogic; + + Size aFontSize(pPDFControl->TextFont.GetSize()); + aFontSize = mpOutputDevice->LogicToLogic(aFontSize, MapMode(MAP_POINT), mpOutputDevice->GetMapMode()); + pPDFControl->TextFont.SetSize(aFontSize); + + mpPDFExtOutDevData->BeginStructureElement(vcl::PDFWriter::Form); + mpPDFExtOutDevData->CreateControl(*pPDFControl.get()); + mpPDFExtOutDevData->EndStructureElement(); + + // no normal paint needed (see original UnoControlPDFExportContact::do_PaintObject); + // do not process recursively + bDoProcessRecursively = false; + } + else + { + // PDF export did not work, try simple output. + // Fallback to printer output by not setting bDoProcessRecursively + // to false. + } + } + + // #i93169# used flag the wrong way; true means that nothing was done yet + if(bDoProcessRecursively) + { + // printer output + try + { + // remember old graphics and create new + uno::Reference< awt::XView > xControlView(rXControl, uno::UNO_QUERY_THROW); + const uno::Reference< awt::XGraphics > xOriginalGraphics(xControlView->getGraphics()); + const uno::Reference< awt::XGraphics > xNewGraphics(mpOutputDevice->CreateUnoGraphics()); + + if(xNewGraphics.is()) + { + // link graphics and view + xControlView->setGraphics(xNewGraphics); + + // get position + const basegfx::B2DHomMatrix aObjectToDiscrete(getViewInformation2D().getObjectToViewTransformation() * rControlPrimitive.getTransform()); + const basegfx::B2DPoint aTopLeftDiscrete(aObjectToDiscrete * basegfx::B2DPoint(0.0, 0.0)); + + // draw it + xControlView->draw(basegfx::fround(aTopLeftDiscrete.getX()), basegfx::fround(aTopLeftDiscrete.getY())); + bDoProcessRecursively = false; + + // restore original graphics + xControlView->setGraphics(xOriginalGraphics); + } + } + catch( const uno::Exception& ) + { + OSL_ENSURE(false, "VclMetafileProcessor2D: Printing of Control failed, caught an exception!"); + } + } + + // process recursively if not done yet to export as decomposition (bitmap) + if(bDoProcessRecursively) + { + process(rControlPrimitive.get2DDecomposition(getViewInformation2D())); + } + } + + break; + } + case PRIMITIVE2D_ID_TEXTHIERARCHYFIELDPRIMITIVE2D : + { + // support for FIELD_SEQ_BEGIN, FIELD_SEQ_END and URL. It wraps text primitives (but is not limited to) + // thus do the MetafileAction embedding stuff but just handle recursively. + const primitive2d::TextHierarchyFieldPrimitive2D& rFieldPrimitive = static_cast< const primitive2d::TextHierarchyFieldPrimitive2D& >(rCandidate); + static const ByteString aCommentStringCommon("FIELD_SEQ_BEGIN"); + static const ByteString aCommentStringPage("FIELD_SEQ_BEGIN;PageField"); + static const ByteString aCommentStringEnd("FIELD_SEQ_END"); + + switch(rFieldPrimitive.getType()) + { + default : // case drawinglayer::primitive2d::FIELD_TYPE_COMMON : + { + mpMetaFile->AddAction(new MetaCommentAction(aCommentStringCommon)); + break; + } + case drawinglayer::primitive2d::FIELD_TYPE_PAGE : + { + mpMetaFile->AddAction(new MetaCommentAction(aCommentStringPage)); + break; + } + case drawinglayer::primitive2d::FIELD_TYPE_URL : + { + const rtl::OUString& rURL = rFieldPrimitive.getString(); + const String aOldString(rURL); + mpMetaFile->AddAction(new MetaCommentAction(aCommentStringCommon, 0, reinterpret_cast< const sal_uInt8* >(aOldString.GetBuffer()), 2 * aOldString.Len())); + break; + } + } + + // process recursively + const primitive2d::Primitive2DSequence rContent = rFieldPrimitive.get2DDecomposition(getViewInformation2D()); + process(rContent); + + // for the end comment the type is not relevant yet, they are all the same. Just add. + mpMetaFile->AddAction(new MetaCommentAction(aCommentStringEnd)); + + if(mpPDFExtOutDevData && drawinglayer::primitive2d::FIELD_TYPE_URL == rFieldPrimitive.getType()) + { + // emulate data handling from ImpEditEngine::Paint + const basegfx::B2DRange aViewRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rContent, getViewInformation2D())); + const Rectangle aRectLogic( + (sal_Int32)floor(aViewRange.getMinX()), (sal_Int32)floor(aViewRange.getMinY()), + (sal_Int32)ceil(aViewRange.getMaxX()), (sal_Int32)ceil(aViewRange.getMaxY())); + vcl::PDFExtOutDevBookmarkEntry aBookmark; + aBookmark.nLinkId = mpPDFExtOutDevData->CreateLink(aRectLogic); + aBookmark.aBookmark = rFieldPrimitive.getString(); + std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = mpPDFExtOutDevData->GetBookmarks(); + rBookmarks.push_back( aBookmark ); + } + + break; + } + case PRIMITIVE2D_ID_TEXTHIERARCHYLINEPRIMITIVE2D : + { + const primitive2d::TextHierarchyLinePrimitive2D& rLinePrimitive = static_cast< const primitive2d::TextHierarchyLinePrimitive2D& >(rCandidate); + static const ByteString aCommentString("XTEXT_EOL"); + + // process recursively and add MetaFile comment + process(rLinePrimitive.get2DDecomposition(getViewInformation2D())); + mpMetaFile->AddAction(new MetaCommentAction(aCommentString)); + + break; + } + case PRIMITIVE2D_ID_TEXTHIERARCHYBULLETPRIMITIVE2D : + { + // in Outliner::PaintBullet(), a MetafileComment for bullets is added, too. The + // "XTEXT_EOC" is used, use here, too. + const primitive2d::TextHierarchyBulletPrimitive2D& rBulletPrimitive = static_cast< const primitive2d::TextHierarchyBulletPrimitive2D& >(rCandidate); + static const ByteString aCommentString("XTEXT_EOC"); + + // process recursively and add MetaFile comment + process(rBulletPrimitive.get2DDecomposition(getViewInformation2D())); + mpMetaFile->AddAction(new MetaCommentAction(aCommentString)); + + break; + } + case PRIMITIVE2D_ID_TEXTHIERARCHYPARAGRAPHPRIMITIVE2D : + { + const primitive2d::TextHierarchyParagraphPrimitive2D& rParagraphPrimitive = static_cast< const primitive2d::TextHierarchyParagraphPrimitive2D& >(rCandidate); + static const ByteString aCommentString("XTEXT_EOP"); + + if(mpPDFExtOutDevData) + { + // emulate data handling from ImpEditEngine::Paint + mpPDFExtOutDevData->BeginStructureElement( vcl::PDFWriter::Paragraph ); + } + + // process recursively and add MetaFile comment + process(rParagraphPrimitive.get2DDecomposition(getViewInformation2D())); + mpMetaFile->AddAction(new MetaCommentAction(aCommentString)); + + if(mpPDFExtOutDevData) + { + // emulate data handling from ImpEditEngine::Paint + mpPDFExtOutDevData->EndStructureElement(); + } + + break; + } + case PRIMITIVE2D_ID_TEXTHIERARCHYBLOCKPRIMITIVE2D : + { + const primitive2d::TextHierarchyBlockPrimitive2D& rBlockPrimitive = static_cast< const primitive2d::TextHierarchyBlockPrimitive2D& >(rCandidate); + static const ByteString aCommentStringA("XTEXT_PAINTSHAPE_BEGIN"); + static const ByteString aCommentStringB("XTEXT_PAINTSHAPE_END"); + + // add MetaFile comment, process recursively and add MetaFile comment + mpMetaFile->AddAction(new MetaCommentAction(aCommentStringA)); + process(rBlockPrimitive.get2DDecomposition(getViewInformation2D())); + mpMetaFile->AddAction(new MetaCommentAction(aCommentStringB)); + + break; + } + case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D : + case PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D : + { + // for supporting TEXT_ MetaFile actions there is more to do here; get the candidate + const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate = static_cast< const primitive2d::TextSimplePortionPrimitive2D& >(rCandidate); + // const primitive2d::TextDecoratedPortionPrimitive2D* pTextDecoratedCandidate = dynamic_cast< const primitive2d::TextDecoratedPortionPrimitive2D* >(&rCandidate); + + // Adapt evtl. used special DrawMode + const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode()); + adaptTextToFillDrawMode(); + + // directdraw of text simple portion; use default processing + RenderTextSimpleOrDecoratedPortionPrimitive2D(rTextCandidate); + + // restore DrawMode + mpOutputDevice->SetDrawMode(nOriginalDrawMode); + + // #i101169# if(pTextDecoratedCandidate) + { + // support for TEXT_ MetaFile actions only for decorated texts + if(!mxBreakIterator.is()) + { + uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xMSF(::comphelper::getProcessServiceFactory()); + mxBreakIterator.set(xMSF->createInstance(rtl::OUString::createFromAscii("com.sun.star.i18n.BreakIterator")), uno::UNO_QUERY); + } + + if(mxBreakIterator.is()) + { + const rtl::OUString& rTxt = rTextCandidate.getText(); + const sal_Int32 nTextLength(rTextCandidate.getTextLength()); // rTxt.getLength()); + + if(nTextLength) + { + const ::com::sun::star::lang::Locale& rLocale = rTextCandidate.getLocale(); + const sal_Int32 nTextPosition(rTextCandidate.getTextPosition()); + + sal_Int32 nDone; + sal_Int32 nNextCellBreak(mxBreakIterator->nextCharacters(rTxt, nTextPosition, rLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, 0, nDone)); + ::com::sun::star::i18n::Boundary nNextWordBoundary(mxBreakIterator->getWordBoundary(rTxt, nTextPosition, rLocale, ::com::sun::star::i18n::WordType::ANY_WORD, sal_True)); + sal_Int32 nNextSentenceBreak(mxBreakIterator->endOfSentence(rTxt, nTextPosition, rLocale)); + static const ByteString aCommentStringA("XTEXT_EOC"); + static const ByteString aCommentStringB("XTEXT_EOW"); + static const ByteString aCommentStringC("XTEXT_EOS"); + + for(sal_Int32 i(nTextPosition); i < nTextPosition + nTextLength; i++) + { + // create the entries for the respective break positions + if(i == nNextCellBreak) + { + mpMetaFile->AddAction(new MetaCommentAction(aCommentStringA, i - nTextPosition)); + nNextCellBreak = mxBreakIterator->nextCharacters(rTxt, i, rLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, 1, nDone); + } + if(i == nNextWordBoundary.endPos) + { + mpMetaFile->AddAction(new MetaCommentAction(aCommentStringB, i - nTextPosition)); + nNextWordBoundary = mxBreakIterator->getWordBoundary(rTxt, i + 1, rLocale, ::com::sun::star::i18n::WordType::ANY_WORD, sal_True); + } + if(i == nNextSentenceBreak) + { + mpMetaFile->AddAction(new MetaCommentAction(aCommentStringC, i - nTextPosition)); + nNextSentenceBreak = mxBreakIterator->endOfSentence(rTxt, i + 1, rLocale); + } + } + } + } + } + + break; + } + case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D : + { + const primitive2d::PolygonHairlinePrimitive2D& rHairlinePrimitive = static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate); + const basegfx::B2DPolygon& rBasePolygon = rHairlinePrimitive.getB2DPolygon(); + + if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1)) + { + // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points + // per polygon. If there are more, split the polygon in half and call recursively + basegfx::B2DPolygon aLeft, aRight; + splitLinePolygon(rBasePolygon, aLeft, aRight); + const primitive2d::PolygonHairlinePrimitive2D aPLeft(aLeft, rHairlinePrimitive.getBColor()); + const primitive2d::PolygonHairlinePrimitive2D aPRight(aRight, rHairlinePrimitive.getBColor()); + + processBasePrimitive2D(aPLeft); + processBasePrimitive2D(aPRight); + } + else + { + // direct draw of hairline; use default processing + // support SvtGraphicStroke MetaCommentAction + const basegfx::BColor aLineColor(maBColorModifierStack.getModifiedColor(rHairlinePrimitive.getBColor())); + SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke( + rHairlinePrimitive.getB2DPolygon(), + &aLineColor, + 0, 0, 0, 0); + + impStartSvtGraphicStroke(pSvtGraphicStroke); + RenderPolygonHairlinePrimitive2D(static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate), false); + impEndSvtGraphicStroke(pSvtGraphicStroke); + } + break; + } + case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D : + { + const primitive2d::PolygonStrokePrimitive2D& rStrokePrimitive = static_cast< const primitive2d::PolygonStrokePrimitive2D& >(rCandidate); + const basegfx::B2DPolygon& rBasePolygon = rStrokePrimitive.getB2DPolygon(); + + if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1)) + { + // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points + // per polygon. If there are more, split the polygon in half and call recursively + basegfx::B2DPolygon aLeft, aRight; + splitLinePolygon(rBasePolygon, aLeft, aRight); + const primitive2d::PolygonStrokePrimitive2D aPLeft( + aLeft, rStrokePrimitive.getLineAttribute(), rStrokePrimitive.getStrokeAttribute()); + const primitive2d::PolygonStrokePrimitive2D aPRight( + aRight, rStrokePrimitive.getLineAttribute(), rStrokePrimitive.getStrokeAttribute()); + + processBasePrimitive2D(aPLeft); + processBasePrimitive2D(aPRight); + } + else + { + // support SvtGraphicStroke MetaCommentAction + SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke( + rBasePolygon, 0, + &rStrokePrimitive.getLineAttribute(), + &rStrokePrimitive.getStrokeAttribute(), + 0, 0); + + impStartSvtGraphicStroke(pSvtGraphicStroke); + const attribute::LineAttribute& rLine = rStrokePrimitive.getLineAttribute(); + + // create MetaPolyLineActions, but without LINE_DASH + if(basegfx::fTools::more(rLine.getWidth(), 0.0)) + { + const attribute::StrokeAttribute& rStroke = rStrokePrimitive.getStrokeAttribute(); + basegfx::B2DPolyPolygon aHairLinePolyPolygon; + + if(0.0 == rStroke.getFullDotDashLen()) + { + aHairLinePolyPolygon.append(rBasePolygon); + } + else + { + basegfx::tools::applyLineDashing( + rBasePolygon, rStroke.getDotDashArray(), + &aHairLinePolyPolygon, 0, rStroke.getFullDotDashLen()); + } + + const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rLine.getColor())); + mpOutputDevice->SetLineColor(Color(aHairlineColor)); + mpOutputDevice->SetFillColor(); + aHairLinePolyPolygon.transform(maCurrentTransformation); + + // #i113922# LineWidth needs to be transformed, too + const basegfx::B2DVector aDiscreteUnit(maCurrentTransformation * basegfx::B2DVector(rLine.getWidth(), 0.0)); + const double fDiscreteLineWidth(aDiscreteUnit.getLength()); + + LineInfo aLineInfo(LINE_SOLID, basegfx::fround(fDiscreteLineWidth)); + aLineInfo.SetLineJoin(rLine.getLineJoin()); + aLineInfo.SetLineCap(rLine.getLineCap()); + + for(sal_uInt32 a(0); a < aHairLinePolyPolygon.count(); a++) + { + const basegfx::B2DPolygon aCandidate(aHairLinePolyPolygon.getB2DPolygon(a)); + + if(aCandidate.count() > 1) + { + const Polygon aToolsPolygon(aCandidate); + + mpMetaFile->AddAction(new MetaPolyLineAction(aToolsPolygon, aLineInfo)); + } + } + } + else + { + process(rCandidate.get2DDecomposition(getViewInformation2D())); + } + + impEndSvtGraphicStroke(pSvtGraphicStroke); + } + + break; + } + case PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D : + { + const primitive2d::PolygonStrokeArrowPrimitive2D& rStrokeArrowPrimitive = static_cast< const primitive2d::PolygonStrokeArrowPrimitive2D& >(rCandidate); + const basegfx::B2DPolygon& rBasePolygon = rStrokeArrowPrimitive.getB2DPolygon(); + + if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1)) + { + // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points + // per polygon. If there are more, split the polygon in half and call recursively + basegfx::B2DPolygon aLeft, aRight; + splitLinePolygon(rBasePolygon, aLeft, aRight); + const attribute::LineStartEndAttribute aEmpty; + const primitive2d::PolygonStrokeArrowPrimitive2D aPLeft( + aLeft, + rStrokeArrowPrimitive.getLineAttribute(), + rStrokeArrowPrimitive.getStrokeAttribute(), + rStrokeArrowPrimitive.getStart(), + aEmpty); + const primitive2d::PolygonStrokeArrowPrimitive2D aPRight( + aRight, + rStrokeArrowPrimitive.getLineAttribute(), + rStrokeArrowPrimitive.getStrokeAttribute(), + aEmpty, + rStrokeArrowPrimitive.getEnd()); + + processBasePrimitive2D(aPLeft); + processBasePrimitive2D(aPRight); + } + else + { + // support SvtGraphicStroke MetaCommentAction + SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke( + rBasePolygon, 0, + &rStrokeArrowPrimitive.getLineAttribute(), + &rStrokeArrowPrimitive.getStrokeAttribute(), + &rStrokeArrowPrimitive.getStart(), + &rStrokeArrowPrimitive.getEnd()); + + impStartSvtGraphicStroke(pSvtGraphicStroke); + process(rCandidate.get2DDecomposition(getViewInformation2D())); + impEndSvtGraphicStroke(pSvtGraphicStroke); + } + + break; + } + case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D : + { + // direct draw of transformed BitmapEx primitive; use default processing + RenderBitmapPrimitive2D(static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_POLYPOLYGONBITMAPPRIMITIVE2D : + { + // need to handle PolyPolygonBitmapPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END + const primitive2d::PolyPolygonBitmapPrimitive2D& rBitmapCandidate = static_cast< const primitive2d::PolyPolygonBitmapPrimitive2D& >(rCandidate); + basegfx::B2DPolyPolygon aLocalPolyPolygon(rBitmapCandidate.getB2DPolyPolygon()); + + if(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon)) + { + // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points + // per polygon. If there are more use the splitted polygon and call recursively + const primitive2d::PolyPolygonBitmapPrimitive2D aSplitted( + aLocalPolyPolygon, + rBitmapCandidate.getFillBitmap()); + + processBasePrimitive2D(aSplitted); + } + else + { + SvtGraphicFill* pSvtGraphicFill = 0; + + if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count()) + { + aLocalPolyPolygon.transform(maCurrentTransformation); + // calculate transformation. Get real object size, all values in FillBitmapAttribute + // are relative to the unified object + const attribute::FillBitmapAttribute& rFillBitmapAttribute = rBitmapCandidate .getFillBitmap(); + const basegfx::B2DRange aOutlineRange(basegfx::tools::getRange(aLocalPolyPolygon)); + const basegfx::B2DVector aOutlineSize(aOutlineRange.getRange()); + + // get absolute values + const basegfx::B2DVector aFillBitmapSize(rFillBitmapAttribute.getSize() * aOutlineSize); + const basegfx::B2DPoint aFillBitmapTopLeft(rFillBitmapAttribute.getTopLeft() * aOutlineSize); + + // the scaling needs scale from pixel to logic coordinate system + const BitmapEx& rBitmapEx = rFillBitmapAttribute.getBitmapEx(); + Size aBmpSizePixel(rBitmapEx.GetSizePixel()); + + if(!aBmpSizePixel.Width()) + { + aBmpSizePixel.Width() = 1; + } + + if(!aBmpSizePixel.Height()) + { + aBmpSizePixel.Height() = 1; + } + + // setup transformation like in impgrfll + SvtGraphicFill::Transform aTransform; + + // scale values are divided by bitmap pixel sizes + aTransform.matrix[0] = aFillBitmapSize.getX() / aBmpSizePixel.Width(); + aTransform.matrix[4] = aFillBitmapSize.getY() / aBmpSizePixel.Height(); + + // translates are absolute + aTransform.matrix[2] = aFillBitmapTopLeft.getX(); + aTransform.matrix[5] = aFillBitmapTopLeft.getY(); + + // setup fill graphic like in impgrfll + Graphic aFillGraphic = Graphic(rBitmapEx); + aFillGraphic.SetPrefMapMode(MapMode(MAP_PIXEL)); + aFillGraphic.SetPrefSize(aBmpSizePixel); + + pSvtGraphicFill = new SvtGraphicFill( + PolyPolygon(aLocalPolyPolygon), + Color(), + 0.0, + SvtGraphicFill::fillEvenOdd, + SvtGraphicFill::fillTexture, + aTransform, + rFillBitmapAttribute.getTiling(), + SvtGraphicFill::hatchSingle, + Color(), + SvtGraphicFill::gradientLinear, + Color(), + Color(), + 0, + aFillGraphic); + } + + // Do use decomposition; encapsulate with SvtGraphicFill + impStartSvtGraphicFill(pSvtGraphicFill); + process(rCandidate.get2DDecomposition(getViewInformation2D())); + impEndSvtGraphicFill(pSvtGraphicFill); + } + + break; + } + case PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D : + { + // need to handle PolyPolygonHatchPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END + const primitive2d::PolyPolygonHatchPrimitive2D& rHatchCandidate = static_cast< const primitive2d::PolyPolygonHatchPrimitive2D& >(rCandidate); + const attribute::FillHatchAttribute& rFillHatchAttribute = rHatchCandidate.getFillHatch(); + basegfx::B2DPolyPolygon aLocalPolyPolygon(rHatchCandidate.getB2DPolyPolygon()); + + // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points + // per polygon. Split polygon until there are less than that + while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon)) + ; + + if(rFillHatchAttribute.isFillBackground()) + { + // with fixing #i111954# (see below) the possible background + // fill of a hatched object was lost.Generate a background fill + // primitive and render it + const primitive2d::Primitive2DReference xBackground( + new primitive2d::PolyPolygonColorPrimitive2D( + aLocalPolyPolygon, + rHatchCandidate.getBackgroundColor())); + + process(primitive2d::Primitive2DSequence(&xBackground, 1)); + } + + SvtGraphicFill* pSvtGraphicFill = 0; + aLocalPolyPolygon.transform(maCurrentTransformation); + + if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count()) + { + // re-create a VCL hatch as base data + SvtGraphicFill::HatchType eHatch(SvtGraphicFill::hatchSingle); + + switch(rFillHatchAttribute.getStyle()) + { + default: // attribute::HATCHSTYLE_SINGLE : + { + eHatch = SvtGraphicFill::hatchSingle; + break; + } + case attribute::HATCHSTYLE_DOUBLE : + { + eHatch = SvtGraphicFill::hatchDouble; + break; + } + case attribute::HATCHSTYLE_TRIPLE : + { + eHatch = SvtGraphicFill::hatchTriple; + break; + } + } + + SvtGraphicFill::Transform aTransform; + + // scale + aTransform.matrix[0] *= rFillHatchAttribute.getDistance(); + aTransform.matrix[4] *= rFillHatchAttribute.getDistance(); + + // rotate (was never correct in impgrfll anyways, use correct angle now) + aTransform.matrix[0] *= cos(rFillHatchAttribute.getAngle()); + aTransform.matrix[1] *= -sin(rFillHatchAttribute.getAngle()); + aTransform.matrix[3] *= sin(rFillHatchAttribute.getAngle()); + aTransform.matrix[4] *= cos(rFillHatchAttribute.getAngle()); + + pSvtGraphicFill = new SvtGraphicFill( + PolyPolygon(aLocalPolyPolygon), + Color(), + 0.0, + SvtGraphicFill::fillEvenOdd, + SvtGraphicFill::fillHatch, + aTransform, + false, + eHatch, + Color(rFillHatchAttribute.getColor()), + SvtGraphicFill::gradientLinear, + Color(), + Color(), + 0, + Graphic()); + } + + // Do use decomposition; encapsulate with SvtGraphicFill + impStartSvtGraphicFill(pSvtGraphicFill); + + // #i111954# do NOT use decomposition, but use direct VCL-command + // process(rCandidate.get2DDecomposition(getViewInformation2D())); + const PolyPolygon aToolsPolyPolygon(aLocalPolyPolygon); + const HatchStyle aHatchStyle( + attribute::HATCHSTYLE_SINGLE == rFillHatchAttribute.getStyle() ? HATCH_SINGLE : + attribute::HATCHSTYLE_DOUBLE == rFillHatchAttribute.getStyle() ? HATCH_DOUBLE : + HATCH_TRIPLE); + + mpOutputDevice->DrawHatch(aToolsPolyPolygon, + Hatch(aHatchStyle, + Color(rFillHatchAttribute.getColor()), + basegfx::fround(rFillHatchAttribute.getDistance()), + basegfx::fround(rFillHatchAttribute.getAngle() / F_PI1800))); + + impEndSvtGraphicFill(pSvtGraphicFill); + + break; + } + case PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D : + { + basegfx::B2DVector aScale, aTranslate; + double fRotate, fShearX; + + maCurrentTransformation.decompose(aScale, aTranslate, fRotate, fShearX); + + if(!basegfx::fTools::equalZero(fRotate) || !basegfx::fTools::equalZero(fShearX)) + { + // #121185# When rotation or shear is used, a VCL Gradient cannot be used directly. + // This is because VCL Gradient mechanism does *not* support to rotate the gradient + // with objects and this case is not expressable in a Metafile (and cannot be added + // since the FileFormats used, e.g. *.wmf, do not support it either). + // Such cases happen when a graphic object uses a Metafile as graphic information or + // a fill style definition uses a Metafile. In this cases the graphic content is + // rotated with the graphic or filled object; this is not supported by the target + // format of this conversion renderer - Metafiles. + // To solve this, not a Gradient is written, but the decomposition of this object + // is written to the Metafile. This is the PolyPolygons building the gradient fill. + // These will need more space and time, but the result will be as if the Gradient + // was rotated with the object. + // This mechanism is used by all exporters still not using Primtives (e.g. Print, + // Slideshow, Export rto PDF, export to Picture, ...) but relying on Metafile + // transfers. One more reason to *change* these to primitives. + // BTW: One more example how useful the principles of primitives are; the decomposition + // is by definition a simpler, maybe more expensive representation of the same content. + process(rCandidate.get2DDecomposition(getViewInformation2D())); + } + else + { + const primitive2d::PolyPolygonGradientPrimitive2D& rGradientCandidate = static_cast< const primitive2d::PolyPolygonGradientPrimitive2D& >(rCandidate); + basegfx::B2DPolyPolygon aLocalPolyPolygon(rGradientCandidate.getB2DPolyPolygon()); + + // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points + // per polygon. Split polygon until there are less than that + while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon)) + ; + + // for support of MetaCommentActions of the form XGRAD_SEQ_BEGIN, XGRAD_SEQ_END + // it is safest to use the VCL OutputDevice::DrawGradient method which creates those. + // re-create a VCL-gradient from FillGradientPrimitive2D and the needed tools PolyPolygon + Gradient aVCLGradient; + impConvertFillGradientAttributeToVCLGradient(aVCLGradient, rGradientCandidate.getFillGradient(), false); + aLocalPolyPolygon.transform(maCurrentTransformation); + + // #i82145# ATM VCL printing of gradients using curved shapes does not work, + // i submitted the bug with the given ID to THB. When that task is fixed it is + // necessary to again remove this subdivision since it decreases possible + // printing quality (not even resolution-dependent for now). THB will tell + // me when that task is fixed in the master + const PolyPolygon aToolsPolyPolygon(basegfx::tools::adaptiveSubdivideByAngle(aLocalPolyPolygon)); + + // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support + SvtGraphicFill* pSvtGraphicFill = 0; + + if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count()) + { + // setup gradient stuff like in like in impgrfll + SvtGraphicFill::GradientType eGrad(SvtGraphicFill::gradientLinear); + + switch(aVCLGradient.GetStyle()) + { + default : // GRADIENT_LINEAR: + case GRADIENT_AXIAL: + eGrad = SvtGraphicFill::gradientLinear; + break; + case GRADIENT_RADIAL: + case GRADIENT_ELLIPTICAL: + eGrad = SvtGraphicFill::gradientRadial; + break; + case GRADIENT_SQUARE: + case GRADIENT_RECT: + eGrad = SvtGraphicFill::gradientRectangular; + break; + } + + pSvtGraphicFill = new SvtGraphicFill( + aToolsPolyPolygon, + Color(), + 0.0, + SvtGraphicFill::fillEvenOdd, + SvtGraphicFill::fillGradient, + SvtGraphicFill::Transform(), + false, + SvtGraphicFill::hatchSingle, + Color(), + eGrad, + aVCLGradient.GetStartColor(), + aVCLGradient.GetEndColor(), + aVCLGradient.GetSteps(), + Graphic()); + } + + // call VCL directly; encapsulate with SvtGraphicFill + impStartSvtGraphicFill(pSvtGraphicFill); + mpOutputDevice->DrawGradient(aToolsPolyPolygon, aVCLGradient); + impEndSvtGraphicFill(pSvtGraphicFill); + + // NO usage of common own gradient randerer, not used ATM for VCL MetaFile, see text above + // RenderPolyPolygonGradientPrimitive2D(static_cast< const primitive2d::PolyPolygonGradientPrimitive2D& >(rCandidate)); + } + + break; + } + case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D : + { + const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate(static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate)); + basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon()); + + // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points + // per polygon. Split polygon until there are less than that + while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon)) + ; + + const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor())); + aLocalPolyPolygon.transform(maCurrentTransformation); + + // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support + SvtGraphicFill* pSvtGraphicFill = 0; + + if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count()) + { + // setup simple color fill stuff like in impgrfll + pSvtGraphicFill = new SvtGraphicFill( + PolyPolygon(aLocalPolyPolygon), + Color(aPolygonColor), + 0.0, + SvtGraphicFill::fillEvenOdd, + SvtGraphicFill::fillSolid, + SvtGraphicFill::Transform(), + false, + SvtGraphicFill::hatchSingle, + Color(), + SvtGraphicFill::gradientLinear, + Color(), + Color(), + 0, + Graphic()); + } + + // set line and fill color + mpOutputDevice->SetFillColor(Color(aPolygonColor)); + mpOutputDevice->SetLineColor(); + + // call VCL directly; encapsulate with SvtGraphicFill + impStartSvtGraphicFill(pSvtGraphicFill); + mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon); + impEndSvtGraphicFill(pSvtGraphicFill); + + break; + } + case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D : + { + static bool bUseMetaFilePrimitiveDecomposition(true); + + if(bUseMetaFilePrimitiveDecomposition) + { + // use new Metafile decomposition + process(rCandidate.get2DDecomposition(getViewInformation2D())); + } + else + { + // direct draw of MetaFile, use default pocessing + RenderMetafilePrimitive2D(static_cast< const primitive2d::MetafilePrimitive2D& >(rCandidate)); + } + + break; + } + case PRIMITIVE2D_ID_MASKPRIMITIVE2D : + { + // mask group. Special handling for MetaFiles. + const primitive2d::MaskPrimitive2D& rMaskCandidate = static_cast< const primitive2d::MaskPrimitive2D& >(rCandidate); + + if(rMaskCandidate.getChildren().hasElements()) + { + basegfx::B2DPolyPolygon aMask(rMaskCandidate.getMask()); + + if(aMask.count()) + { + // prepare new mask polygon and rescue current one + aMask.transform(maCurrentTransformation); + const basegfx::B2DPolyPolygon aLastClipPolyPolygon(maClipPolyPolygon); + + if(maClipPolyPolygon.count()) + { + // there is already a clip polygon set; build clipped union of + // current mask polygon and new one + maClipPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon( + aMask, + maClipPolyPolygon, + true, // #i106516# we want the inside of aMask, not the outside + false); + } + else + { + // use mask directly + maClipPolyPolygon = aMask; + } + + if(maClipPolyPolygon.count()) + { + // set VCL clip region; subdivide before conversion to tools polygon. Subdivision necessary (!) + // Removed subdivision and fixed in Region::ImplPolyPolyRegionToBandRegionFunc() in VCL where + // the ClipRegion is built from the Polygon. A AdaptiveSubdivide on the source polygon was missing there + mpOutputDevice->Push(PUSH_CLIPREGION); + //mpOutputDevice->SetClipRegion(Region(PolyPolygon(basegfx::tools::adaptiveSubdivideByAngle(maClipPolyPolygon)))); + //mpOutputDevice->SetClipRegion(Region(PolyPolygon(maClipPolyPolygon))); + mpOutputDevice->SetClipRegion(Region(maClipPolyPolygon)); + } + + // recursively paint content + process(rMaskCandidate.getChildren()); + + if(maClipPolyPolygon.count()) + { + // restore VCL clip region + mpOutputDevice->Pop(); + } + + // restore to rescued clip polygon + maClipPolyPolygon = aLastClipPolyPolygon; + } + else + { + // no mask, no clipping. recursively paint content + process(rMaskCandidate.getChildren()); + } + } + + break; + } + case PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D : + { + // modified color group. Force output to unified color. Use default pocessing. + RenderModifiedColorPrimitive2D(static_cast< const primitive2d::ModifiedColorPrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_HIDDENGEOMETRYPRIMITIVE2D : + { + // HiddenGeometryPrimitive2D; to rebuilt the old MetaFile creation, it is necessary to + // not ignore them (as it was thought), but to add a MetaFile entry for them. + basegfx::B2DRange aInvisibleRange(rCandidate.getB2DRange(getViewInformation2D())); + + if(!aInvisibleRange.isEmpty()) + { + aInvisibleRange.transform(maCurrentTransformation); + const Rectangle aRectLogic( + (sal_Int32)floor(aInvisibleRange.getMinX()), (sal_Int32)floor(aInvisibleRange.getMinY()), + (sal_Int32)ceil(aInvisibleRange.getMaxX()), (sal_Int32)ceil(aInvisibleRange.getMaxY())); + + mpOutputDevice->SetFillColor(); + mpOutputDevice->SetLineColor(); + mpOutputDevice->DrawRect(aRectLogic); + } + + break; + } + case PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D : + { + // for metafile: Need to examine what the pure vcl version is doing here actually + // - uses DrawTransparent with metafile for content and a gradient + // - uses DrawTransparent for single PolyPoylgons directly. Can be detected by + // checking the content for single PolyPolygonColorPrimitive2D + const primitive2d::UnifiedTransparencePrimitive2D& rUniTransparenceCandidate = static_cast< const primitive2d::UnifiedTransparencePrimitive2D& >(rCandidate); + const primitive2d::Primitive2DSequence rContent = rUniTransparenceCandidate.getChildren(); + + if(rContent.hasElements()) + { + if(0.0 == rUniTransparenceCandidate.getTransparence()) + { + // not transparent at all, use content + process(rUniTransparenceCandidate.getChildren()); + } + else if(rUniTransparenceCandidate.getTransparence() > 0.0 && rUniTransparenceCandidate.getTransparence() < 1.0) + { + // try to identify a single PolyPolygonColorPrimitive2D in the + // content part of the transparence primitive + const primitive2d::PolyPolygonColorPrimitive2D* pPoPoColor = 0; + static bool bForceToMetafile(false); + + if(!bForceToMetafile && 1 == rContent.getLength()) + { + const primitive2d::Primitive2DReference xReference(rContent[0]); + pPoPoColor = dynamic_cast< const primitive2d::PolyPolygonColorPrimitive2D* >(xReference.get()); + } + + // PolyPolygonGradientPrimitive2D, PolyPolygonHatchPrimitive2D and + // PolyPolygonBitmapPrimitive2D are derived from PolyPolygonColorPrimitive2D. + // Check also for correct ID to exclude derived implementations + if(pPoPoColor && PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D == pPoPoColor->getPrimitive2DID()) + { + // single transparent PolyPolygon identified, use directly + const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(pPoPoColor->getBColor())); + basegfx::B2DPolyPolygon aLocalPolyPolygon(pPoPoColor->getB2DPolyPolygon()); + + // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points + // per polygon. Split polygon until there are less than that + while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon)) + ; + + // now transform + aLocalPolyPolygon.transform(maCurrentTransformation); + + // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support + SvtGraphicFill* pSvtGraphicFill = 0; + + if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count()) + { + // setup simple color with transparence fill stuff like in impgrfll + pSvtGraphicFill = new SvtGraphicFill( + PolyPolygon(aLocalPolyPolygon), + Color(aPolygonColor), + rUniTransparenceCandidate.getTransparence(), + SvtGraphicFill::fillEvenOdd, + SvtGraphicFill::fillSolid, + SvtGraphicFill::Transform(), + false, + SvtGraphicFill::hatchSingle, + Color(), + SvtGraphicFill::gradientLinear, + Color(), + Color(), + 0, + Graphic()); + } + + // set line and fill color + const sal_uInt16 nTransPercentVcl((sal_uInt16)basegfx::fround(rUniTransparenceCandidate.getTransparence() * 100.0)); + mpOutputDevice->SetFillColor(Color(aPolygonColor)); + mpOutputDevice->SetLineColor(); + + // call VCL directly; encapsulate with SvtGraphicFill + impStartSvtGraphicFill(pSvtGraphicFill); + mpOutputDevice->DrawTransparent( + PolyPolygon(aLocalPolyPolygon), + nTransPercentVcl); + impEndSvtGraphicFill(pSvtGraphicFill); + } + else + { + // svae old mfCurrentUnifiedTransparence and set new one + // so that contained SvtGraphicStroke may use the current one + const double fLastCurrentUnifiedTransparence(mfCurrentUnifiedTransparence); + // #i105377# paint the content metafile opaque as the transparency gets + // split of into the gradient below + // mfCurrentUnifiedTransparence = rUniTransparenceCandidate.getTransparence(); + mfCurrentUnifiedTransparence = 0; + + // various content, create content-metafile + GDIMetaFile aContentMetafile; + const Rectangle aPrimitiveRectangle(impDumpToMetaFile(rContent, aContentMetafile)); + + // restore mfCurrentUnifiedTransparence; it may have been used + // while processing the sub-content in impDumpToMetaFile + mfCurrentUnifiedTransparence = fLastCurrentUnifiedTransparence; + + // create uniform VCL gradient for uniform transparency + Gradient aVCLGradient; + const sal_uInt8 nTransPercentVcl((sal_uInt8)basegfx::fround(rUniTransparenceCandidate.getTransparence() * 255.0)); + const Color aTransColor(nTransPercentVcl, nTransPercentVcl, nTransPercentVcl); + + aVCLGradient.SetStyle(GRADIENT_LINEAR); + aVCLGradient.SetStartColor(aTransColor); + aVCLGradient.SetEndColor(aTransColor); + aVCLGradient.SetAngle(0); + aVCLGradient.SetBorder(0); + aVCLGradient.SetOfsX(0); + aVCLGradient.SetOfsY(0); + aVCLGradient.SetStartIntensity(100); + aVCLGradient.SetEndIntensity(100); + aVCLGradient.SetSteps(2); + + // render it to VCL + mpOutputDevice->DrawTransparent( + aContentMetafile, aPrimitiveRectangle.TopLeft(), + aPrimitiveRectangle.GetSize(), aVCLGradient); + } + } + } + + break; + } + case PRIMITIVE2D_ID_TRANSPARENCEPRIMITIVE2D : + { + // for metafile: Need to examine what the pure vcl version is doing here actually + // - uses DrawTransparent with metafile for content and a gradient + // i can detect this here with checking the gradient part for a single + // FillGradientPrimitive2D and reconstruct the gradient. + // If that detection goes wrong, i have to create an transparence-blended bitmap. Eventually + // do that in stripes, else RenderTransparencePrimitive2D may just be used + const primitive2d::TransparencePrimitive2D& rTransparenceCandidate = static_cast< const primitive2d::TransparencePrimitive2D& >(rCandidate); + const primitive2d::Primitive2DSequence rContent = rTransparenceCandidate.getChildren(); + const primitive2d::Primitive2DSequence rTransparence = rTransparenceCandidate.getTransparence(); + + if(rContent.hasElements() && rTransparence.hasElements()) + { + // try to identify a single FillGradientPrimitive2D in the + // transparence part of the primitive + const primitive2d::FillGradientPrimitive2D* pFiGradient = 0; + static bool bForceToBigTransparentVDev(false); + + if(!bForceToBigTransparentVDev && 1 == rTransparence.getLength()) + { + const primitive2d::Primitive2DReference xReference(rTransparence[0]); + pFiGradient = dynamic_cast< const primitive2d::FillGradientPrimitive2D* >(xReference.get()); + } + + // Check also for correct ID to exclude derived implementations + if(pFiGradient && PRIMITIVE2D_ID_FILLGRADIENTPRIMITIVE2D == pFiGradient->getPrimitive2DID()) + { + // various content, create content-metafile + GDIMetaFile aContentMetafile; + const Rectangle aPrimitiveRectangle(impDumpToMetaFile(rContent, aContentMetafile)); + + // re-create a VCL-gradient from FillGradientPrimitive2D + Gradient aVCLGradient; + impConvertFillGradientAttributeToVCLGradient(aVCLGradient, pFiGradient->getFillGradient(), true); + + // render it to VCL + mpOutputDevice->DrawTransparent( + aContentMetafile, aPrimitiveRectangle.TopLeft(), + aPrimitiveRectangle.GetSize(), aVCLGradient); + } + else + { + // sub-transparence group. Draw to VDev first. + // this may get refined to tiling when resolution is too big here + + // need to avoid switching off MapMode stuff here; maybe need another + // tooling class, cannot just do the same as with the pixel renderer. + // Need to experiment... + + // Okay, basic implementation finished and tested. The DPI stuff was hard + // and not easy to find out that it's needed. + // Since this will not yet happen normally (as long as noone constructs + // transparence primitives with non-trivial transparence content) i will for now not + // refine to tiling here. + + basegfx::B2DRange aViewRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rContent, getViewInformation2D())); + aViewRange.transform(maCurrentTransformation); + const Rectangle aRectLogic( + (sal_Int32)floor(aViewRange.getMinX()), (sal_Int32)floor(aViewRange.getMinY()), + (sal_Int32)ceil(aViewRange.getMaxX()), (sal_Int32)ceil(aViewRange.getMaxY())); + const Rectangle aRectPixel(mpOutputDevice->LogicToPixel(aRectLogic)); + Size aSizePixel(aRectPixel.GetSize()); + const Point aEmptyPoint; + VirtualDevice aBufferDevice; + const sal_uInt32 nMaxQuadratPixels(500000); + const sal_uInt32 nViewVisibleArea(aSizePixel.getWidth() * aSizePixel.getHeight()); + double fReduceFactor(1.0); + + if(nViewVisibleArea > nMaxQuadratPixels) + { + // reduce render size + fReduceFactor = sqrt((double)nMaxQuadratPixels / (double)nViewVisibleArea); + aSizePixel = Size(basegfx::fround((double)aSizePixel.getWidth() * fReduceFactor), + basegfx::fround((double)aSizePixel.getHeight() * fReduceFactor)); + } + + if(aBufferDevice.SetOutputSizePixel(aSizePixel)) + { + // create and set MapModes for target devices + MapMode aNewMapMode(mpOutputDevice->GetMapMode()); + aNewMapMode.SetOrigin(Point(-aRectLogic.Left(), -aRectLogic.Top())); + aBufferDevice.SetMapMode(aNewMapMode); + + // prepare view transformation for target renderers + // ATTENTION! Need to apply another scaling because of the potential DPI differences + // between Printer and VDev (mpOutputDevice and aBufferDevice here). + // To get the DPI, LogicToPixel from (1,1) from MAP_INCH needs to be used. + basegfx::B2DHomMatrix aViewTransform(aBufferDevice.GetViewTransformation()); + const Size aDPIOld(mpOutputDevice->LogicToPixel(Size(1, 1), MAP_INCH)); + const Size aDPINew(aBufferDevice.LogicToPixel(Size(1, 1), MAP_INCH)); + const double fDPIXChange((double)aDPIOld.getWidth() / (double)aDPINew.getWidth()); + const double fDPIYChange((double)aDPIOld.getHeight() / (double)aDPINew.getHeight()); + + if(!basegfx::fTools::equal(fDPIXChange, 1.0) || !basegfx::fTools::equal(fDPIYChange, 1.0)) + { + aViewTransform.scale(fDPIXChange, fDPIYChange); + } + + // also take scaling from Size reduction into acount + if(!basegfx::fTools::equal(fReduceFactor, 1.0)) + { + aViewTransform.scale(fReduceFactor, fReduceFactor); + } + + // create view information and pixel renderer. Reuse known ViewInformation + // except new transformation and range + const geometry::ViewInformation2D aViewInfo( + getViewInformation2D().getObjectTransformation(), + aViewTransform, + aViewRange, + getViewInformation2D().getVisualizedPage(), + getViewInformation2D().getViewTime(), + getViewInformation2D().getExtendedInformationSequence()); + + VclPixelProcessor2D aBufferProcessor(aViewInfo, aBufferDevice); + + // draw content using pixel renderer + aBufferProcessor.process(rContent); + const Bitmap aBmContent(aBufferDevice.GetBitmap(aEmptyPoint, aSizePixel)); + + // draw transparence using pixel renderer + aBufferDevice.Erase(); + aBufferProcessor.process(rTransparence); + const AlphaMask aBmAlpha(aBufferDevice.GetBitmap(aEmptyPoint, aSizePixel)); + +#ifdef DBG_UTIL + static bool bDoSaveForVisualControl(false); + if(bDoSaveForVisualControl) + { + SvFileStream aNew(String(ByteString( "c:\\test.bmp" ), RTL_TEXTENCODING_UTF8), STREAM_WRITE|STREAM_TRUNC); + aNew << aBmContent; + } +#endif + + // paint + mpOutputDevice->DrawBitmapEx( + aRectLogic.TopLeft(), + aRectLogic.GetSize(), + BitmapEx(aBmContent, aBmAlpha)); + } + } + } + + break; + } + case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D : + { + // use default transform group pocessing + RenderTransformPrimitive2D(static_cast< const primitive2d::TransformPrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D : + { + // new XDrawPage for ViewInformation2D + RenderPagePreviewPrimitive2D(static_cast< const primitive2d::PagePreviewPrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D : + { + // use default marker array pocessing + RenderMarkerArrayPrimitive2D(static_cast< const primitive2d::MarkerArrayPrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D : + { + // use default point array pocessing + RenderPointArrayPrimitive2D(static_cast< const primitive2d::PointArrayPrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_STRUCTURETAGPRIMITIVE2D : + { + // structured tag primitive + const primitive2d::StructureTagPrimitive2D& rStructureTagCandidate = static_cast< const primitive2d::StructureTagPrimitive2D& >(rCandidate); + const vcl::PDFWriter::StructElement& rTagElement(rStructureTagCandidate.getStructureElement()); + const bool bTagUsed(vcl::PDFWriter::NonStructElement != rTagElement); + + if(mpPDFExtOutDevData && bTagUsed) + { + // write start tag + mpPDFExtOutDevData->BeginStructureElement(rTagElement); + } + + // proccess childs normally + process(rStructureTagCandidate.getChildren()); + + if(mpPDFExtOutDevData && bTagUsed) + { + // write end tag + mpPDFExtOutDevData->EndStructureElement(); + } + + break; + } + case PRIMITIVE2D_ID_EPSPRIMITIVE2D : + { + RenderEpsPrimitive2D(static_cast< const primitive2d::EpsPrimitive2D& >(rCandidate)); + break; + } + default : + { + // process recursively + process(rCandidate.get2DDecomposition(getViewInformation2D())); + break; + } + } + } + } // end of namespace processor2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/processor2d/canvasprocessor.cxx b/drawinglayer/source/processor2d/canvasprocessor.cxx deleted file mode 100644 index 875f28003699..000000000000 --- a/drawinglayer/source/processor2d/canvasprocessor.cxx +++ /dev/null @@ -1,2213 +0,0 @@ -/************************************************************** - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - *************************************************************/ - - - -// MARKER(update_precomp.py): autogen include statement, do not remove -#include "precompiled_drawinglayer.hxx" - -#include <drawinglayer/processor2d/canvasprocessor.hxx> -#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> -#include <drawinglayer/primitive2d/polygonprimitive2d.hxx> -#include <com/sun/star/rendering/XCanvas.hpp> -#include <vcl/canvastools.hxx> -#include <basegfx/tools/canvastools.hxx> -#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> -#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx> -#include <drawinglayer/primitive2d/transformprimitive2d.hxx> -#include <canvas/canvastools.hxx> -#include <svl/ctloptions.hxx> -#include <vcl/svapp.hxx> -#include <drawinglayer/primitive2d/maskprimitive2d.hxx> -#include <basegfx/polygon/b2dpolygonclipper.hxx> -#include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx> -#include <drawinglayer/primitive2d/metafileprimitive2d.hxx> -#include <cppcanvas/basegfxfactory.hxx> -#include <com/sun/star/rendering/XBitmapCanvas.hpp> -#include <cppcanvas/vclfactory.hxx> -#include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx> -#include <drawinglayer/primitive2d/textprimitive2d.hxx> -#include <com/sun/star/rendering/TextDirection.hpp> -#include <vclhelperbitmaptransform.hxx> -#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> -#include <basegfx/polygon/b2dpolygontools.hxx> -#include <drawinglayer/primitive2d/transparenceprimitive2d.hxx> -#include <basegfx/tuple/b2i64tuple.hxx> -#include <basegfx/range/b2irange.hxx> -#include <com/sun/star/rendering/XIntegerReadOnlyBitmap.hpp> -#include <com/sun/star/rendering/PanoseProportion.hpp> -#include <com/sun/star/rendering/CompositeOperation.hpp> -#include <com/sun/star/rendering/StrokeAttributes.hpp> -#include <com/sun/star/rendering/PathJoinType.hpp> -#include <com/sun/star/rendering/PathCapType.hpp> -#include <drawinglayer/primitive2d/fillbitmapprimitive2d.hxx> -#include <com/sun/star/rendering/TexturingMode.hpp> -#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx> -#include <vclhelperbufferdevice.hxx> -#include <drawinglayer/primitive2d/wrongspellprimitive2d.hxx> -#include <helperwrongspellrenderer.hxx> -#include <basegfx/matrix/b2dhommatrixtools.hxx> - -////////////////////////////////////////////////////////////////////////////// - -using namespace com::sun::star; - -////////////////////////////////////////////////////////////////////////////// -// AW: Adding the canvas example from THB here to extract stuff later -/* - // TODO(Q3): share impCreateEmptyBitmapWithPattern() and other - // helper methods with vclprocessor.cxx - Bitmap impCreateEmptyBitmapWithPattern(Bitmap aSource, const Size& aTargetSizePixel) - { - Bitmap aRetval; - BitmapReadAccess* pReadAccess = aSource.AcquireReadAccess(); - - if(pReadAccess) - { - if(aSource.GetBitCount() <= 8) - { - BitmapPalette aPalette(pReadAccess->GetPalette()); - aRetval = Bitmap(aTargetSizePixel, aSource.GetBitCount(), &aPalette); - } - else - { - aRetval = Bitmap(aTargetSizePixel, aSource.GetBitCount()); - } - - delete pReadAccess; - } - - return aRetval; - } - - Bitmap impModifyBitmap(const basegfx::BColorModifier& rModifier, const Bitmap& rSource) - { - Bitmap aRetval(rSource); - - switch(rModifier.getMode()) - { - case basegfx::BCOLORMODIFYMODE_REPLACE : - { - aRetval = impCreateEmptyBitmapWithPattern(aRetval, Size(1L, 1L)); - aRetval.Erase(Color(rModifier.getBColor())); - break; - } - - default : // BCOLORMODIFYMODE_INTERPOLATE, BCOLORMODIFYMODE_GRAY, BCOLORMODIFYMODE_BLACKANDWHITE - { - BitmapWriteAccess* pContent = aRetval.AcquireWriteAccess(); - - if(pContent) - { - for(sal_uInt32 y(0L); y < (sal_uInt32)pContent->Height(); y++) - { - for(sal_uInt32 x(0L); x < (sal_uInt32)pContent->Width(); x++) - { - const Color aColor = pContent->GetPixel(y, x); - const basegfx::BColor aBColor(rModifier.getModifiedColor(aColor.getBColor())); - pContent->SetPixel(y, x, BitmapColor(Color(aBColor))); - } - } - - delete pContent; - } - - break; - } - } - - return aRetval; - } - - Bitmap impModifyBitmap(const basegfx::BColorModifierStack& rBColorModifierStack, const Bitmap& rSource) - { - Bitmap aRetval(rSource); - - for(sal_uInt32 a(rBColorModifierStack.count()); a; ) - { - const basegfx::BColorModifier& rModifier = rBColorModifierStack.getBColorModifier(--a); - aRetval = impModifyBitmap(rModifier, aRetval); - } - - return aRetval; - } - - sal_uInt32 impCalcGradientSteps(sal_uInt32 nSteps, const basegfx::B2DRange& rRange, sal_uInt32 nMaxDist) - { - if(nSteps == 0L) - nSteps = (sal_uInt32)(rRange.getWidth() + rRange.getHeight()) / 8; - - if(nSteps < 2L) - { - nSteps = 2L; - } - - if(nSteps > nMaxDist) - { - nSteps = nMaxDist; - } - - return nSteps; - } - - void canvasProcessor::impDrawGradientSimple( - const basegfx::B2DPolyPolygon& rTargetForm, - const ::std::vector< basegfx::B2DHomMatrix >& rMatrices, - const ::std::vector< basegfx::BColor >& rColors, - const basegfx::B2DPolygon& rUnitPolygon) - { - uno::Reference< rendering::XPolyPolygon2D > xPoly( - basegfx::unotools::xPolyPolygonFromB2DPolygon( - mxCanvas->getDevice(), - rUnitPolygon)); - uno::Reference< rendering::XPolyPolygon2D > xTargetPoly( - basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( - mxCanvas->getDevice(), - rTargetForm)); - - for(sal_uInt32 a(0L); a < rColors.size(); a++) - { - // set correct color - const basegfx::BColor aFillColor(rColors[a]); - - maRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence( - mxCanvas->getDevice(), - aFillColor); - - if(a) - { - if(a - 1L < rMatrices.size()) - { - canvas::tools::setRenderStateTransform( maRenderState, - rMatrices[a - 1L] ); - mxCanvas->fillPolyPolygon(xPoly,maViewState,maRenderState); - } - } - else - { - canvas::tools::setRenderStateTransform( maRenderState, - basegfx::B2DHomMatrix() ); - mxCanvas->fillPolyPolygon(xTargetPoly,maViewState,maRenderState); - } - } - } - - void canvasProcessor::impDrawGradientComplex( - const basegfx::B2DPolyPolygon& rTargetForm, - const ::std::vector< basegfx::B2DHomMatrix >& rMatrices, - const ::std::vector< basegfx::BColor >& rColors, - const basegfx::B2DPolygon& rUnitPolygon) - { - uno::Reference< rendering::XPolyPolygon2D > xPoly( - basegfx::unotools::xPolyPolygonFromB2DPolygon( - mxCanvas->getDevice(), - rUnitPolygon)); - uno::Reference< rendering::XPolyPolygon2D > xTargetPoly( - basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( - mxCanvas->getDevice(), - rTargetForm)); - - maRenderState.Clip = xTargetPoly; - - // draw gradient PolyPolygons - for(std::size_t a = 0L; a < rMatrices.size(); a++) - { - // set correct color - if(rColors.size() > a) - { - const basegfx::BColor aFillColor(rColors[a]); - - maRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence( - mxCanvas->getDevice(), - aFillColor); - } - - canvas::tools::setRenderStateTransform( maRenderState, - rMatrices[a] ); - - if(a) - mxCanvas->fillPolyPolygon(xPoly,maViewState,maRenderState); - else - mxCanvas->fillPolyPolygon(xTargetPoly,maViewState,maRenderState); - } - - maRenderState.Clip.clear(); - } - - void canvasProcessor::impDrawGradient( - const basegfx::B2DPolyPolygon& rTargetForm, - ::drawinglayer::primitive::GradientStyle eGradientStyle, - sal_uInt32 nSteps, - const basegfx::BColor& rStart, - const basegfx::BColor& rEnd, - double fBorder, double fAngle, double fOffsetX, double fOffsetY, bool bSimple) - { - fprintf(stderr,"impDrawGradient\n"); - - basegfx::B2DPolyPolygon aTmp(rTargetForm); - aTmp.transform( maWorldToView ); - const basegfx::B2DRange aOutlineRangePixel(basegfx::tools::getRange(aTmp)); - const basegfx::B2DRange aOutlineRange(basegfx::tools::getRange(rTargetForm)); - - fprintf(stderr,"impDrawGradient: #%d\n",nSteps); - - 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< rendering::XParametricPolyPolygon2DFactory > xFactory( - mxCanvas->getDevice()->getParametricPolyPolygonFactory() ); - - if( xFactory.is() ) - { - fprintf(stderr,"native gradient #1\n"); - - basegfx::B2DHomMatrix aTextureTransformation; - rendering::Texture aTexture; - - aTexture.RepeatModeX = rendering::TexturingMode::CLAMP; - aTexture.RepeatModeY = rendering::TexturingMode::CLAMP; - aTexture.Alpha = 1.0; - - - // setup start/end color values - // ---------------------------- - - const uno::Sequence< double > aStartColor( - basegfx::unotools::colorToDoubleSequence( mxCanvas->getDevice(), - rStart )); - const uno::Sequence< double > aEndColor( - basegfx::unotools::colorToDoubleSequence( mxCanvas->getDevice(), - rEnd )); - - // Setup texture transformation - // ---------------------------- - - const basegfx::B2DRange& rBounds( - basegfx::tools::getRange( rTargetForm )); - - // setup rotation angle. VCL rotates - // counter-clockwise, while canvas transformation - // rotates clockwise - //fAngle = -fAngle; - - switch(eGradientStyle) - { - case ::drawinglayer::primitive::GRADIENTSTYLE_LINEAR: - // FALLTHROUGH intended - case ::drawinglayer::primitive::GRADIENTSTYLE_AXIAL: - { - // standard orientation for VCL linear - // gradient is vertical, thus, rotate 90 - // degrees - fAngle += M_PI/2.0; - - // shrink texture, to account for border - // (only in x direction, linear gradient - // is constant in y direction, anyway) - aTextureTransformation.scale( - basegfx::pruneScaleValue(1.0 - fBorder), - 1.0 ); - - double fBorderX(0.0); - - // determine type of gradient (and necessary - // transformation matrix, should it be emulated by a - // generic gradient) - switch(eGradientStyle) - { - case ::drawinglayer::primitive::GRADIENTSTYLE_LINEAR: - // linear gradients don't respect - // offsets (they are implicitely - // assumed to be 50%). linear - // gradients don't have border on - // both sides, only on the - // startColor side. Gradient is - // invariant in y direction: leave - // y offset alone. - fBorderX = fBorder; - aTexture.Gradient = xFactory->createLinearHorizontalGradient( aStartColor, - aEndColor ); - break; - - case ::drawinglayer::primitive::GRADIENTSTYLE_AXIAL: - // axial gradients have border on - // both sides. Gradient is - // invariant in y direction: leave - // y offset alone. - fBorderX = fBorder * .5; - aTexture.Gradient = xFactory->createAxialHorizontalGradient( aStartColor, - aEndColor ); - break; - } - - // apply border offset values - aTextureTransformation.translate( fBorderX, - 0.0 ); - - // rotate texture according to gradient rotation - aTextureTransformation.translate( -0.5, -0.5 ); - aTextureTransformation.rotate( fAngle ); - - // to let the first strip of a rotated - // gradient start at the _edge_ of the - // bound rect (and not, due to rotation, - // slightly inside), slightly enlarge the - // gradient: - // - // y/2 sin(transparence) + x/2 cos(transparence) - // - // (values to change are not actual - // gradient scales, but original bound - // rect dimensions. Since we still want - // the border setting to apply after that, - // we multiply with that as above for - // nScaleX) - const double nScale( - basegfx::pruneScaleValue( - fabs( rBounds.getHeight()*sin(fAngle) ) + - fabs( rBounds.getWidth()*cos(fAngle) ))); - - aTextureTransformation.scale( nScale, nScale ); - - // translate back origin to center of - // primitive - aTextureTransformation.translate( 0.5*rBounds.getWidth(), - 0.5*rBounds.getHeight() ); - break; - } - - case ::drawinglayer::primitive::GRADIENTSTYLE_RADIAL: - // FALLTHROUGH intended - case ::drawinglayer::primitive::GRADIENTSTYLE_ELLIPTICAL: - // FALLTHROUGH intended - case ::drawinglayer::primitive::GRADIENTSTYLE_SQUARE: - // FALLTHROUGH intended - case ::drawinglayer::primitive::GRADIENTSTYLE_RECT: - { - fprintf(stderr,"native gradient #2\n"); - - // determine scale factors for the gradient (must - // be scaled up from [0,1]x[0,1] rect to object - // bounds). Will potentially changed in switch - // statement below. - // Respect border value, while doing so, the VCL - // gradient's border will effectively shrink the - // resulting gradient. - double nScaleX( rBounds.getWidth() * (1.0 - fBorder) ); - double nScaleY( rBounds.getHeight()* (1.0 - fBorder) ); - - // determine offset values. Since the - // border is divided half-by-half to both - // sides of the gradient, divide - // translation offset by an additional - // factor of 2. Also respect offset here, - // but since VCL gradients have their - // center at [0,0] for zero offset, but - // canvas gradients have their top, left - // edge aligned with the primitive, and - // offset of 50% effectively must yield - // zero shift. Both values will - // potentially be adapted in switch - // statement below. - double nOffsetX( rBounds.getWidth() * - (2.0 * fOffsetX - 1.0 + fBorder)*.5 ); - double nOffsetY( rBounds.getHeight() * - (2.0 * fOffsetY - 1.0 + fBorder)*.5 ); - - // determine type of gradient (and necessary - // transformation matrix, should it be emulated by a - // generic gradient) - switch(eGradientStyle) - { - case ::drawinglayer::primitive::GRADIENTSTYLE_RADIAL: - { - // create isotrophic scaling - if( nScaleX > nScaleY ) - { - nOffsetY -= (nScaleX - nScaleY) * 0.5; - nScaleY = nScaleX; - } - else - { - nOffsetX -= (nScaleY - nScaleX) * 0.5; - nScaleX = nScaleY; - } - - // enlarge gradient to match bound rect diagonal - aTextureTransformation.translate( -0.5, -0.5 ); - const double nScale( hypot(rBounds.getWidth(), - rBounds.getHeight()) / nScaleX ); - aTextureTransformation.scale( nScale, nScale ); - aTextureTransformation.translate( 0.5, 0.5 ); - - aTexture.Gradient = xFactory->createEllipticalGradient( - aEndColor, - aStartColor, - cssgeom::RealRectangle2D(0.0,0.0, - 1.0,1.0) ); - } - break; - - case ::drawinglayer::primitive::GRADIENTSTYLE_ELLIPTICAL: - { - // enlarge gradient slightly - aTextureTransformation.translate( -0.5, -0.5 ); - const double nSqrt2( sqrt(2.0) ); - aTextureTransformation.scale( nSqrt2,nSqrt2 ); - aTextureTransformation.translate( 0.5, 0.5 ); - - aTexture.Gradient = xFactory->createEllipticalGradient( - aEndColor, - aStartColor, - cssgeom::RealRectangle2D( rBounds.getMinX(), - rBounds.getMinY(), - rBounds.getMaxX(), - rBounds.getMaxY() )); - } - break; - - case ::drawinglayer::primitive::GRADIENTSTYLE_SQUARE: - { - // create isotrophic scaling - if( nScaleX > nScaleY ) - { - nOffsetY -= (nScaleX - nScaleY) * 0.5; - nScaleY = nScaleX; - } - else - { - nOffsetX -= (nScaleY - nScaleX) * 0.5; - nScaleX = nScaleY; - } - - aTexture.Gradient = xFactory->createRectangularGradient( - aEndColor, - aStartColor, - cssgeom::RealRectangle2D(0.0,0.0, - 1.0,1.0)); - } - break; - - case ::drawinglayer::primitive::GRADIENTSTYLE_RECT: - { - aTexture.Gradient = xFactory->createRectangularGradient( - aEndColor, - aStartColor, - cssgeom::RealRectangle2D( rBounds.getMinX(), - rBounds.getMinY(), - rBounds.getMaxX(), - rBounds.getMaxY() )); - } - break; - } - - nScaleX = basegfx::pruneScaleValue( nScaleX ); - nScaleY = basegfx::pruneScaleValue( nScaleY ); - - aTextureTransformation.scale( nScaleX, nScaleY ); - - // rotate texture according to gradient rotation - aTextureTransformation.translate( -0.5*nScaleX, -0.5*nScaleY ); - aTextureTransformation.rotate( fAngle ); - aTextureTransformation.translate( 0.5*nScaleX, 0.5*nScaleY ); - - aTextureTransformation.translate( nOffsetX, nOffsetY ); - } - break; - - default: - OSL_ENSURE( false, - "canvasProcessor::impDrawGradient(): 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). - aTextureTransformation.translate( rBounds.getMinX(), - rBounds.getMinY() ); - - basegfx::unotools::affineMatrixFromHomMatrix( aTexture.AffineTransform, - aTextureTransformation ); - uno::Sequence< rendering::Texture > aSeq(1); - aSeq[0] = aTexture; - - mxCanvas->fillTexturedPolyPolygon( - basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( - mxCanvas->getDevice(), - rTargetForm), - maViewState, - maRenderState, - aSeq ); - - // done, using native gradients - return; - } - } - else - { - // make sure steps is not too high/low - nSteps = impCalcGradientSteps(nSteps, - aOutlineRangePixel, - sal_uInt32((rStart.getMaximumDistance(rEnd) * 127.5) + 0.5)); - - - ::std::vector< basegfx::B2DHomMatrix > aMatrices; - ::std::vector< basegfx::BColor > aColors; - basegfx::B2DPolygon aUnitPolygon; - - if( drawinglayer::primitive::GRADIENTSTYLE_RADIAL == eGradientStyle || - drawinglayer::primitive::GRADIENTSTYLE_ELLIPTICAL == eGradientStyle) - { - const basegfx::B2DPoint aCircleCenter(0.5, 0.5); - aUnitPolygon = basegfx::tools::createPolygonFromEllipse(aCircleCenter, 0.5, 0.5); - aUnitPolygon = basegfx::tools::adaptiveSubdivideByAngle(aUnitPolygon); - } - else - { - aUnitPolygon = basegfx::tools::createUnitPolygon(); - } - - // create geometries - switch(eGradientStyle) - { - case ::drawinglayer::primitive::GRADIENTSTYLE_LINEAR: - { - ::drawinglayer::primitive::geoTexSvxGradientLinear aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fAngle); - aGradient.appendTransformations(aMatrices); - aGradient.appendColors(aColors); - break; - } - case ::drawinglayer::primitive::GRADIENTSTYLE_AXIAL: - { - ::drawinglayer::primitive::geoTexSvxGradientAxial aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fAngle); - aGradient.appendTransformations(aMatrices); - aGradient.appendColors(aColors); - break; - } - case ::drawinglayer::primitive::GRADIENTSTYLE_RADIAL: - { - ::drawinglayer::primitive::geoTexSvxGradientRadial aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fOffsetX, fOffsetY); - aGradient.appendTransformations(aMatrices); - aGradient.appendColors(aColors); - break; - } - case ::drawinglayer::primitive::GRADIENTSTYLE_ELLIPTICAL: - { - ::drawinglayer::primitive::geoTexSvxGradientElliptical aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fOffsetX, fOffsetX, fAngle); - aGradient.appendTransformations(aMatrices); - aGradient.appendColors(aColors); - break; - } - case ::drawinglayer::primitive::GRADIENTSTYLE_SQUARE: - { - ::drawinglayer::primitive::geoTexSvxGradientSquare aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fOffsetX, fOffsetX, fAngle); - aGradient.appendTransformations(aMatrices); - aGradient.appendColors(aColors); - break; - } - case ::drawinglayer::primitive::GRADIENTSTYLE_RECT: - { - ::drawinglayer::primitive::geoTexSvxGradientRect aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fOffsetX, fOffsetX, fAngle); - aGradient.appendTransformations(aMatrices); - aGradient.appendColors(aColors); - break; - } - } - - // paint them with mask using the XOR method - if(aMatrices.size()) - { - if(bSimple) - { - impDrawGradientSimple(rTargetForm, aMatrices, aColors, aUnitPolygon); - } - else - { - impDrawGradientComplex(rTargetForm, aMatrices, aColors, aUnitPolygon); - } - } - } - } - - - ////////////////////////////////////////////////////////////////////////////// - // rendering support - - // directdraw of text simple portion - void canvasProcessor::impRender_STXP(const textSimplePortionPrimitive& rTextCandidate) - { - const fontAttributes& rFontAttrs( rTextCandidate.getFontAttribute() ); - rendering::FontRequest aFontRequest; - - aFontRequest.FontDescription.FamilyName = rFontAttrs.maFamilyName; - aFontRequest.FontDescription.StyleName = rFontAttrs.maStyleName; - aFontRequest.FontDescription.IsSymbolFont = rFontAttrs.mbSymbol ? util::TriState_YES : util::TriState_NO; - aFontRequest.FontDescription.IsVertical = rFontAttrs.mbVertical ? util::TriState_YES : util::TriState_NO; - - // TODO(F2): improve vclenum->panose conversion - aFontRequest.FontDescription.FontDescription.Weight = - rFontAttrs.mnWeight; - aFontRequest.FontDescription.FontDescription.Letterform = - rFontAttrs.mbItalic ? 9 : 0; - - // font matrix should only be used for glyph rotations etc. - css::geometry::Matrix2D aFontMatrix; - canvas::tools::setIdentityMatrix2D( aFontMatrix ); - - uno::Reference<rendering::XCanvasFont> xFont( - mxCanvas->createFont( aFontRequest, - uno::Sequence< beans::PropertyValue >(), - aFontMatrix )); - - if( !xFont.is() ) - return; - - uno::Reference<rendering::XTextLayout> xLayout( - xFont->createTextLayout( - rendering::StringContext( rTextCandidate.getText(), - 0, - rTextCandidate.getText().Len() ), - // TODO(F3): Is this sufficient? - rendering::TextDirection::WEAK_LEFT_TO_RIGHT, - 0 )); - if( !xLayout.is() ) - return; - - xLayout->applyLogicalAdvancements( - uno::Sequence<double>(&rTextCandidate.getDXArray()[0], - rTextCandidate.getDXArray().size() )); - - const basegfx::BColor aRGBColor( - maBColorModifierStack.getModifiedColor( - rTextCandidate.getFontColor())); - - maRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence( - mxCanvas->getDevice(), - aRGBColor); - - // get render parameters and paint - mxCanvas->drawTextLayout( xLayout, - maViewState, - maRenderState ); - } - - // direct draw of hairline - void canvasProcessor::impRender_POHL(const polygonHairlinePrimitive& rPolygonCandidate) - { - const basegfx::BColor aRGBColor( - maBColorModifierStack.getModifiedColor( - rPolygonCandidate.getBColor())); - - maRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence( - mxCanvas->getDevice(), - aRGBColor); - - mxCanvas->drawPolyPolygon( basegfx::unotools::xPolyPolygonFromB2DPolygon( - mxCanvas->getDevice(), - rPolygonCandidate.getB2DPolygon()), - maViewState, - maRenderState ); - } - - // direct draw of transformed BitmapEx primitive - void canvasProcessor::impRender_BMPR(const bitmapPrimitive& rBitmapCandidate) - { - BitmapEx aBitmapEx(rBitmapCandidate.getBitmapEx()); - - if(maBColorModifierStack.count()) - { - // TODO(Q3): Share common bmp modification code with - // vclprocessor.cxx - Bitmap aChangedBitmap(impModifyBitmap(maBColorModifierStack, aBitmapEx.GetBitmap())); - - if(aBitmapEx.IsTransparent()) - { - if(aBitmapEx.IsAlpha()) - aBitmapEx = BitmapEx(aChangedBitmap, aBitmapEx.GetAlpha()); - else - aBitmapEx = BitmapEx(aChangedBitmap, aBitmapEx.GetMask()); - } - else - aBitmapEx = BitmapEx(aChangedBitmap); - } - - mxCanvas->drawBitmap( - vcl::unotools::xBitmapFromBitmapEx( mxCanvas->getDevice(), - aBitmapEx ), - maViewState, - maRenderState); - } - - void canvasProcessor::impRender_PPLB(const polyPolygonBitmapPrimitive& rPolyBitmapCandidate ) - { - const fillBitmapAttribute& rFillBmpAttr( rPolyBitmapCandidate.getFillBitmap() ); - const basegfx::B2DPolyPolygon& rPoly( rPolyBitmapCandidate.getB2DPolyPolygon() ); - - // TODO(Q3): Share common bmp modification code with - // vclprocessor.cxx - Bitmap aChangedBitmap( - impModifyBitmap(maBColorModifierStack, - rFillBmpAttr.getBitmap())); - - rendering::Texture aTexture; - const basegfx::B2DVector aBmpSize( rFillBmpAttr.getSize() ); - - const basegfx::B2DRange& rBounds( - basegfx::tools::getRange( rPoly )); - - basegfx::B2DHomMatrix aScale; - aScale.scale( aBmpSize.getX() * rBounds.getWidth(), - aBmpSize.getY() * rBounds.getHeight() ); - - basegfx::unotools::affineMatrixFromHomMatrix( - aTexture.AffineTransform, - aScale ); - - aTexture.Alpha = 1.0; - aTexture.Bitmap = - ::vcl::unotools::xBitmapFromBitmapEx( - mxCanvas->getDevice(), - aChangedBitmap ); - aTexture.RepeatModeX = rendering::TexturingMode::REPEAT; - aTexture.RepeatModeY = rendering::TexturingMode::REPEAT; - - uno::Sequence< rendering::Texture > aSeq(1); - aSeq[0] = aTexture; - - mxCanvas->fillTexturedPolyPolygon( - basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( - mxCanvas->getDevice(), - rPoly), - maViewState, - maRenderState, - aSeq ); - } - - // direct draw of gradient - void canvasProcessor::impRender_PPLG(const polyPolygonGradientPrimitive& rPolygonCandidate) - { - const fillGradientAttribute& rGradient(rPolygonCandidate.getFillGradient()); - basegfx::BColor aStartColor(maBColorModifierStack.getModifiedColor(rGradient.getStartColor())); - basegfx::BColor aEndColor(maBColorModifierStack.getModifiedColor(rGradient.getEndColor())); - basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon()); - - if(aStartColor == aEndColor) - { - // no gradient at all, draw as polygon - - maRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence( - mxCanvas->getDevice(), - aStartColor); - - mxCanvas->drawPolyPolygon( basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( - mxCanvas->getDevice(), - aLocalPolyPolygon), - maViewState, - maRenderState ); - } - else - { - // TODO(F3): if rGradient.getSteps() > 0, render - // gradient manually! - impDrawGradient( - aLocalPolyPolygon, rGradient.getStyle(), rGradient.getSteps(), - aStartColor, aEndColor, rGradient.getBorder(), - -rGradient.getAngle(), rGradient.getOffsetX(), rGradient.getOffsetY(), false); - } - } - - // direct draw of PolyPolygon with color - void canvasProcessor::impRender_PPLC(const polyPolygonColorPrimitive& rPolygonCandidate) - { - const basegfx::BColor aRGBColor( - maBColorModifierStack.getModifiedColor( - rPolygonCandidate.getBColor())); - - maRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence( - mxCanvas->getDevice(), - aRGBColor); - - mxCanvas->fillPolyPolygon( basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( - mxCanvas->getDevice(), - rPolygonCandidate.getB2DPolyPolygon()), - maViewState, - maRenderState ); - } - - // direct draw of MetaFile - void canvasProcessor::impRender_META(const metafilePrimitive& rMetaCandidate) - { - // get metafile (copy it) - GDIMetaFile aMetaFile; - - // TODO(Q3): Share common metafile modification code with - // vclprocessor.cxx - if(maBColorModifierStack.count()) - { - const basegfx::BColor aRGBBaseColor(0, 0, 0); - const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(aRGBBaseColor)); - aMetaFile = rMetaCandidate.getMetaFile().GetMonochromeMtf(Color(aRGBColor)); - } - else - { - aMetaFile = rMetaCandidate.getMetaFile(); - } - - cppcanvas::BitmapCanvasSharedPtr pCanvas( - cppcanvas::VCLFactory::getInstance().createCanvas( - uno::Reference<rendering::XBitmapCanvas>( - mxCanvas, - uno::UNO_QUERY_THROW) )); - cppcanvas::RendererSharedPtr pMtfRenderer( - cppcanvas::VCLFactory::getInstance().createRenderer( - pCanvas, - aMetaFile, - cppcanvas::Renderer::Parameters() )); - if( pMtfRenderer ) - { - pCanvas->setTransformation(maWorldToView); - pMtfRenderer->setTransformation(rMetaCandidate.getTransform()); - pMtfRenderer->draw(); - } - } - - // mask group. Set mask polygon as clip - void canvasProcessor::impRender_MASK(const maskPrimitive& rMaskCandidate) - { - const primitiveVector& rSubList = rMaskCandidate.getPrimitiveVector(); - - if(!rSubList.empty()) - { - // TODO(F3): cannot use state-global renderstate, when recursing! - maRenderState.Clip = - basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( - mxCanvas->getDevice(), - rMaskCandidate.getMask()); - - // paint to it - process(rSubList); - - maRenderState.Clip.clear(); - } - } - - // modified color group. Force output to unified color. - void canvasProcessor::impRender_MCOL(const modifiedColorPrimitive& rModifiedCandidate) - { - const primitiveVector& rSubList = rModifiedCandidate.getPrimitiveVector(); - - if(!rSubList.empty()) - { - maBColorModifierStack.push(rModifiedCandidate.getColorModifier()); - process(rModifiedCandidate.getPrimitiveVector()); - maBColorModifierStack.pop(); - } - } - - // sub-transparence group. Draw to bitmap device first. - void canvasProcessor::impRender_TRPR(const transparencePrimitive& rTransCandidate) - { - const primitiveVector& rSubList = rTransCandidate.getPrimitiveVector(); - - if(!rSubList.empty()) - { - basegfx::B2DRange aRange( - get2DRangeFromVector(rSubList, - getViewInformation())); - aRange.transform(maWorldToView); - const basegfx::B2I64Tuple& rSize( - canvas::tools::spritePixelAreaFromB2DRange(aRange).getRange()); - uno::Reference< rendering::XCanvas > xBitmap( - mxCanvas->getDevice()->createCompatibleAlphaBitmap( - css::geometry::IntegerSize2D(rSize.getX(), - rSize.getY())), - uno::UNO_QUERY_THROW); - - // remember last worldToView and add pixel offset - basegfx::B2DHomMatrix aLastWorldToView(maWorldToView); - basegfx::B2DHomMatrix aPixelOffset; - aPixelOffset.translate(aRange.getMinX(), - aRange.getMinY()); - setWorldToView(aPixelOffset * maWorldToView); - - // remember last canvas, set bitmap as target - uno::Reference< rendering::XCanvas > xLastCanvas( mxCanvas ); - mxCanvas = xBitmap; - - // paint content to it - process(rSubList); - - // TODO(F3): render transparent list to transparence - // channel. Note that the OutDev implementation has a - // shortcoming, in that nested transparency groups - // don't work - transparence is not combined properly. - - // process(rTransCandidate.getTransparenceList()); - - // back to old OutDev and worldToView - mxCanvas = xLastCanvas; - setWorldToView(aLastWorldToView); - - // DUMMY: add transparence modulation value to DeviceColor - // TODO(F3): color management - canvas::tools::setDeviceColor( maRenderState, - 1.0, 1.0, 1.0, 0.5 ); - // finally, draw bitmap - mxCanvas->drawBitmapModulated( - uno::Reference< rendering::XBitmap >( - xBitmap, - uno::UNO_QUERY_THROW), - maViewState, - maRenderState ); - } - } - - // transform group. - void canvasProcessor::impRender_TRN2(const transformPrimitive& rTransformCandidate) - { - // remember current transformation - basegfx::B2DHomMatrix aLastWorldToView(maWorldToView); - - // create new transformations - setWorldToView(maWorldToView * rTransformCandidate.getTransformation()); - - // let break down - process(rTransformCandidate.getPrimitiveVector()); - - // restore transformations - setWorldToView(aLastWorldToView); - } - - // marker - void canvasProcessor::impRender_MARK(const markerPrimitive& rMarkCandidate) - { - const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(rMarkCandidate.getRGBColor())); - - canvas::tools::initRenderState(maMarkerRenderState); - maMarkerRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence( - mxCanvas->getDevice(), - aRGBColor); - - // Markers are special objects - their position is - // determined by the view transformation, but their size - // is always the same - const basegfx::B2DPoint aViewPos(maWorldToView * rMarkCandidate.getPosition()); - - uno::Reference< rendering::XPolyPolygon2D > xMarkerPoly; - uno::Reference< rendering::XPolyPolygon2D > xHighlightMarkerPoly; - switch(rMarkCandidate.getStyle()) - { - default: - case MARKERSTYLE_POINT: - mxCanvas->drawPoint( basegfx::unotools::point2DFromB2DPoint(aViewPos), - maMarkerViewState, - maMarkerRenderState ); - return; - - case MARKERSTYLE_CROSS: - if( !mxCrossMarkerPoly.is() ) - { - basegfx::B2DPolyPolygon aPoly; - basegfx::tools::importFromSvgD( - aPoly, - rtl::OUString::createFromAscii( - "m-1 0 h2 m0 -1 v2" )); - mxCrossMarkerPoly = - basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( - mxCanvas->getDevice(), - aPoly ); - } - xMarkerPoly = mxCrossMarkerPoly; - break; - - case MARKERSTYLE_GLUEPOINT : - if( !mxGluePointPoly.is() ) - { - basegfx::B2DPolyPolygon aPoly; - basegfx::tools::importFromSvgD( - aPoly, - rtl::OUString::createFromAscii( - "m-2 -3 l5 5 m-3 -2 l5 5 m-3 2 l5 -5 m-2 3 l5 -5" )); - mxGluePointPoly = - basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( - mxCanvas->getDevice(), - aPoly ); - } - if( !mxGluePointHighlightPoly.is() ) - { - basegfx::B2DPolyPolygon aPoly; - basegfx::tools::importFromSvgD( - aPoly, - rtl::OUString::createFromAscii( - "m-2 -2 l4 4 m-2 2 l4 -4" )); - mxGluePointHighlightPoly = - basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( - mxCanvas->getDevice(), - aPoly ); - } - xMarkerPoly = mxGluePointPoly; - xHighlightMarkerPoly = mxGluePointHighlightPoly; - break; - } - - basegfx::B2DRange aRange; - rMarkCandidate.getRealtiveViewRange(aRange); - const basegfx::B2DPoint aCenter(aRange.getCenter()); - - basegfx::B2DHomMatrix aTranslate; - aTranslate.translate(aViewPos.getX()+aCenter.getX(), - aViewPos.getY()+aCenter.getY()); - - canvas::tools::setRenderStateTransform( maMarkerRenderState, - aTranslate ); - - - mxCanvas->drawPolyPolygon( xMarkerPoly, - maMarkerViewState, - maMarkerRenderState ); - if( xHighlightMarkerPoly.is() ) - { - // TODO(F3): color management - canvas::tools::setDeviceColor(maMarkerRenderState, - 0.0, 0.0, 1.0, 1.0); - mxCanvas->drawPolyPolygon( xMarkerPoly, - maMarkerViewState, - maMarkerRenderState ); - } - } - - void canvasProcessor::setWorldToView(const basegfx::B2DHomMatrix& rMat) - { - maWorldToView = rMat; - canvas::tools::setViewStateTransform(maViewState, - maWorldToView); - } - - ////////////////////////////////////////////////////////////////////////////// - // internal processing support - - void canvasProcessor::process(const primitiveVector& rSource) - { - primitiveVector::const_iterator aCurr = rSource.begin(); - const primitiveVector::const_iterator aEnd = rSource.end(); - while( aCurr != aEnd ) - { - const referencedPrimitive& rCandidate = *aCurr; - - switch(rCandidate.getID()) - { - case CreatePrimitiveID('S', 'T', 'X', 'P'): - { - // directdraw of text simple portion - impRender_STXP(static_cast< const textSimplePortionPrimitive& >(rCandidate.getBasePrimitive())); - break; - } - - case CreatePrimitiveID('P', 'O', 'H', 'L'): - { - // direct draw of hairline - impRender_POHL(static_cast< const polygonHairlinePrimitive& >(rCandidate.getBasePrimitive())); - break; - } - - case CreatePrimitiveID('B', 'M', 'P', 'R'): - { - // direct draw of transformed BitmapEx primitive - impRender_BMPR(static_cast< const bitmapPrimitive& >(rCandidate.getBasePrimitive())); - break; - } - - case CreatePrimitiveID('F', 'B', 'M', 'P'): - { - OSL_ENSURE(false,"fillBitmapPrimitive not yet implemented"); - break; - } - - case CreatePrimitiveID('P', 'P', 'L', 'B'): - { - // direct draw of polygon with bitmap fill - impRender_PPLB(static_cast< const polyPolygonBitmapPrimitive& >(rCandidate.getBasePrimitive())); - break; - } - - case CreatePrimitiveID('P', 'P', 'L', 'G'): - { - // direct draw of gradient - impRender_PPLG(static_cast< const polyPolygonGradientPrimitive& >(rCandidate.getBasePrimitive())); - break; - } - - case CreatePrimitiveID('P', 'P', 'L', 'C'): - { - // direct draw of PolyPolygon with color - impRender_PPLC(static_cast< const polyPolygonColorPrimitive& >(rCandidate.getBasePrimitive())); - break; - } - - case CreatePrimitiveID('M', 'E', 'T', 'A'): - { - // direct draw of MetaFile - impRender_META(static_cast< const metafilePrimitive& >(rCandidate.getBasePrimitive())); - break; - } - - case CreatePrimitiveID('M', 'A', 'S', 'K'): - { - // mask group. Force output to VDev and create mask from given mask - impRender_MASK(static_cast< const maskPrimitive& >(rCandidate.getBasePrimitive())); - break; - } - - case CreatePrimitiveID('M', 'C', 'O', 'L'): - { - // modified color group. Force output to unified color. - impRender_MCOL(static_cast< const modifiedColorPrimitive& >(rCandidate.getBasePrimitive())); - break; - } - - case CreatePrimitiveID('T', 'R', 'P', 'R'): - { - // sub-transparence group. Draw to VDev first. - impRender_TRPR(static_cast< const transparencePrimitive& >(rCandidate.getBasePrimitive())); - break; - } - - case CreatePrimitiveID('T', 'R', 'N', '2'): - { - // transform group. - impRender_TRN2(static_cast< const transformPrimitive& >(rCandidate.getBasePrimitive())); - break; - } - - case CreatePrimitiveID('M', 'A', 'R', 'K'): - { - // marker - impRender_MARK(static_cast< const markerPrimitive& >(rCandidate.getBasePrimitive())); - break; - } - - case CreatePrimitiveID('A', 'N', 'S', 'W'): - case CreatePrimitiveID('A', 'N', 'B', 'L'): - case CreatePrimitiveID('A', 'N', 'I', 'N'): - { - // check timing, but do not accept - const animatedSwitchPrimitive& rAnimatedCandidate(static_cast< const animatedSwitchPrimitive& >(rCandidate.getBasePrimitive())); - const ::drawinglayer::animation::animationEntryList& rAnimationList = rAnimatedCandidate.getAnimationList(); - const double fNewTime(rAnimationList.getNextEventTime(getViewInformation().getViewTime())); - - // let break down - process(rAnimatedCandidate.getDecomposition(getViewInformation())); - - break; - } - - default: - { - // let break down - process(rCandidate.getBasePrimitive().getDecomposition(getViewInformation())); - } - } - - ++aCurr; - } - } - - canvasProcessor::canvasProcessor( const ::drawinglayer::geometry::viewInformation& rViewInformation, - const uno::Reference<rendering::XCanvas>& rCanvas ) : - processor(rViewInformation), - mxCanvas( rCanvas ), - mxCrossMarkerPoly(), - mxGluePointPoly(), - mxGluePointHighlightPoly(), - maBColorModifierStack(), - maWorldToView(), - maViewState(), - maRenderState(), - maMarkerViewState(), - maMarkerRenderState() - { - canvas::tools::initViewState(maViewState); - canvas::tools::initRenderState(maRenderState); - canvas::tools::initViewState(maMarkerViewState); - canvas::tools::initRenderState(maMarkerRenderState); - - maWorldToView = maViewInformation.getViewTransformation(); - - canvas::tools::setViewStateTransform(maViewState, - maWorldToView); - } - - canvasProcessor::~canvasProcessor() - {} -*/ -////////////////////////////////////////////////////////////////////////////// - -namespace drawinglayer -{ - namespace processor2d - { - ////////////////////////////////////////////////////////////////////////////// - // single primitive renderers - - void canvasProcessor2D::impRenderMaskPrimitive2D(const primitive2d::MaskPrimitive2D& rMaskCandidate) - { - const primitive2d::Primitive2DSequence& rChildren = rMaskCandidate.getChildren(); - static bool bUseMaskBitmapMethod(true); - - if(rChildren.hasElements()) - { - basegfx::B2DPolyPolygon aMask(rMaskCandidate.getMask()); - - if(!aMask.count()) - { - // no mask, no clipping. recursively paint content - process(rChildren); - } - else - { - // there are principally two methods for implementing the mask primitive. One - // is to set a clip polygon at the canvas, the other is to create and use a - // transparence-using XBitmap for content and draw the mask as transparence. Both have their - // advantages and disadvantages, so here are both with a bool allowing simple - // change - if(bUseMaskBitmapMethod) - { - // get logic range of transparent part, clip with ViewRange - basegfx::B2DRange aLogicRange(aMask.getB2DRange()); - - if(!getViewInformation2D().getViewport().isEmpty()) - { - aLogicRange.intersect(getViewInformation2D().getViewport()); - } - - if(!aLogicRange.isEmpty()) - { - // get discrete range of transparent part - basegfx::B2DRange aDiscreteRange(aLogicRange); - aDiscreteRange.transform(getViewInformation2D().getObjectToViewTransformation()); - - // expand to next covering discrete values (pixel bounds) - aDiscreteRange.expand(basegfx::B2DTuple(floor(aDiscreteRange.getMinX()), floor(aDiscreteRange.getMinY()))); - aDiscreteRange.expand(basegfx::B2DTuple(ceil(aDiscreteRange.getMaxX()), ceil(aDiscreteRange.getMaxY()))); - - // use VCL-based buffer device - impBufferDevice aBufferDevice(*mpOutputDevice, aDiscreteRange, false); - - if(aBufferDevice.isVisible()) - { - // remember current OutDev, Canvas and ViewInformation - OutputDevice* pLastOutputDevice = mpOutputDevice; - uno::Reference< rendering::XCanvas > xLastCanvas(mxCanvas); - const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D()); - - // prepare discrete offset for XBitmap, do not forget that the buffer bitmap - // may be truncated to discrete visible pixels - const basegfx::B2DHomMatrix aDiscreteOffset(basegfx::tools::createTranslateB2DHomMatrix( - aDiscreteRange.getMinX() > 0.0 ? -aDiscreteRange.getMinX() : 0.0, - aDiscreteRange.getMinY() > 0.0 ? -aDiscreteRange.getMinY() : 0.0)); - - // create new local ViewInformation2D with new transformation - const geometry::ViewInformation2D aViewInformation2D( - getViewInformation2D().getObjectTransformation(), - aDiscreteOffset * getViewInformation2D().getViewTransformation(), - getViewInformation2D().getViewport(), - getViewInformation2D().getVisualizedPage(), - getViewInformation2D().getViewTime(), - getViewInformation2D().getExtendedInformationSequence()); - updateViewInformation(aViewInformation2D); - - // set OutDev and Canvas to content target - mpOutputDevice = &aBufferDevice.getContent(); - mxCanvas = mpOutputDevice->GetCanvas(); - canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation()); - - // if ViewState transform is changed, the clipping polygon needs to be adapted, too - const basegfx::B2DPolyPolygon aOldClipPolyPolygon(maClipPolyPolygon); - - if(maClipPolyPolygon.count()) - { - maClipPolyPolygon.transform(aDiscreteOffset); - maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon); - } - - // paint content - process(rChildren); - - // draw mask - const basegfx::BColor aBlack(0.0, 0.0, 0.0); - maRenderState.DeviceColor = aBlack.colorToDoubleSequence(mxCanvas->getDevice()); - - if(getOptionsDrawinglayer().IsAntiAliasing()) - { - // with AA, use 8bit AlphaMask to get nice borders - VirtualDevice& rTransparence = aBufferDevice.getTransparence(); - rTransparence.GetCanvas()->fillPolyPolygon( - basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), aMask), - maViewState, maRenderState); - } - else - { - // No AA, use 1bit mask - VirtualDevice& rMask = aBufferDevice.getMask(); - rMask.GetCanvas()->fillPolyPolygon( - basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), aMask), - maViewState, maRenderState); - } - - // back to old color stack, OutDev, Canvas and ViewTransform - mpOutputDevice = pLastOutputDevice; - mxCanvas = xLastCanvas; - updateViewInformation(aLastViewInformation2D); - canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation()); - - // restore clipping polygon - maClipPolyPolygon = aOldClipPolyPolygon; - - if(maClipPolyPolygon.count()) - { - maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon); - } - - // dump buffer to outdev - aBufferDevice.paint(); - } - } - } - else - { - // transform new mask polygon to view coordinates for processing. All masks - // are processed in view coordinates and clipped against each other evtl. to - // create multi-clips - aMask.transform(getViewInformation2D().getObjectTransformation()); - - // remember last current clip polygon - const basegfx::B2DPolyPolygon aLastClipPolyPolygon(maClipPolyPolygon); - - if(maClipPolyPolygon.count()) - { - // there is already a clip polygon set; build clipped union of - // current mask polygon and new one - maClipPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon(aMask, maClipPolyPolygon, false, false); - } - else - { - // use mask directly - maClipPolyPolygon = aMask; - } - - // set at ViewState - if(maClipPolyPolygon.count()) - { - // set new as clip polygon - maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon); - } - else - { - // empty, reset - maViewState.Clip.clear(); - } - - // paint content - process(rChildren); - - // restore local current to rescued clip polygon - maClipPolyPolygon = aLastClipPolyPolygon; - - // set at ViewState - if(maClipPolyPolygon.count()) - { - // set new as clip polygon - maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon); - } - else - { - // empty, reset - maViewState.Clip.clear(); - } - } - } - } - } - - void canvasProcessor2D::impRenderMetafilePrimitive2D(const primitive2d::MetafilePrimitive2D& rMetaCandidate) - { - GDIMetaFile aMetaFile; - - if(maBColorModifierStack.count()) - { - const basegfx::BColor aRGBBaseColor(0, 0, 0); - const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(aRGBBaseColor)); - aMetaFile = rMetaCandidate.getMetaFile().GetMonochromeMtf(Color(aRGBColor)); - } - else - { - aMetaFile = rMetaCandidate.getMetaFile(); - } - - cppcanvas::BitmapCanvasSharedPtr pCanvas(cppcanvas::VCLFactory::getInstance().createCanvas( - uno::Reference<rendering::XBitmapCanvas>(mxCanvas, uno::UNO_QUERY_THROW))); - cppcanvas::RendererSharedPtr pMtfRenderer(cppcanvas::VCLFactory::getInstance().createRenderer( - pCanvas, aMetaFile, cppcanvas::Renderer::Parameters())); - - if(pMtfRenderer) - { - pCanvas->setTransformation(getViewInformation2D().getObjectToViewTransformation()); - pMtfRenderer->setTransformation(rMetaCandidate.getTransform()); - pMtfRenderer->draw(); - } - } - - void canvasProcessor2D::impRenderTextSimplePortionPrimitive2D(const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate) - { - if(rTextCandidate.getTextLength()) - { - double fShearX(0.0); - { - const basegfx::B2DHomMatrix aLocalTransform(getViewInformation2D().getObjectToViewTransformation() * rTextCandidate.getTextTransform()); - basegfx::B2DVector aScale, aTranslate; - double fRotate; - aLocalTransform.decompose(aScale, aTranslate, fRotate, fShearX); - } - - if(!basegfx::fTools::equalZero(fShearX)) - { - // text is sheared. As long as the canvas renderers do not support this, - // use the decomposed primitive - process(rTextCandidate.get2DDecomposition(getViewInformation2D())); - } - else - { - const attribute::FontAttribute& rFontAttr(rTextCandidate.getFontAttribute()); - rendering::FontRequest aFontRequest; - - aFontRequest.FontDescription.FamilyName = rFontAttr.getFamilyName(); - aFontRequest.FontDescription.StyleName = rFontAttr.getStyleName(); - aFontRequest.FontDescription.IsSymbolFont = rFontAttr.getSymbol() ? util::TriState_YES : util::TriState_NO; - aFontRequest.FontDescription.IsVertical = rFontAttr.getVertical() ? util::TriState_YES : util::TriState_NO; - // TODO(F2): improve vclenum->panose conversion - aFontRequest.FontDescription.FontDescription.Weight = static_cast< sal_uInt8 >(rFontAttr.getWeight()); - aFontRequest.FontDescription.FontDescription.Proportion = - rFontAttr.getMonospaced() - ? rendering::PanoseProportion::MONO_SPACED - : rendering::PanoseProportion::ANYTHING; - aFontRequest.FontDescription.FontDescription.Letterform = rFontAttr.getItalic() ? 9 : 0; - - // init CellSize to 1.0, else a default font height will be used - aFontRequest.CellSize = 1.0; - aFontRequest.Locale = rTextCandidate.getLocale(); - - // font matrix should only be used for glyph rotations etc. - com::sun::star::geometry::Matrix2D aFontMatrix; - canvas::tools::setIdentityMatrix2D(aFontMatrix); - - uno::Reference<rendering::XCanvasFont> xFont(mxCanvas->createFont( - aFontRequest, uno::Sequence< beans::PropertyValue >(), aFontMatrix)); - - if(xFont.is()) - { - // got a font, now try to get a TextLayout - const rendering::StringContext aStringContext( - rTextCandidate.getText(), rTextCandidate.getTextPosition(), rTextCandidate.getTextLength()); - uno::Reference<rendering::XTextLayout> xLayout(xFont->createTextLayout( - aStringContext, com::sun::star::rendering::TextDirection::WEAK_LEFT_TO_RIGHT, 0)); - - if(xLayout.is()) - { - // got a text layout, apply DXArray if given - const ::std::vector< double >& rDXArray = rTextCandidate.getDXArray(); - const sal_uInt32 nDXCount(rDXArray.size()); - - if(nDXCount) - { - // DXArray does not need to be adapted to getTextPosition/getTextLength, - // it is already provided correctly - const uno::Sequence< double > aDXSequence(&rDXArray[0], nDXCount); - xLayout->applyLogicalAdvancements(aDXSequence); - } - - // set text color - const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(rTextCandidate.getFontColor())); - maRenderState.DeviceColor = aRGBColor.colorToDoubleSequence(mxCanvas->getDevice()); - - // set text transformation - canvas::tools::setRenderStateTransform(maRenderState, - getViewInformation2D().getObjectTransformation() * rTextCandidate.getTextTransform()); - - // paint - mxCanvas->drawTextLayout(xLayout, maViewState, maRenderState); - } - } - } - } - } - - void canvasProcessor2D::impRenderBitmapPrimitive2D(const primitive2d::BitmapPrimitive2D& rBitmapCandidate) - { - // apply possible color modification to BitmapEx - BitmapEx aModifiedBitmapEx(impModifyBitmapEx(maBColorModifierStack, rBitmapCandidate.getBitmapEx())); - - if(aModifiedBitmapEx.IsEmpty()) - { - // replace with color filled polygon - const basegfx::BColor aModifiedColor(maBColorModifierStack.getModifiedColor(basegfx::BColor())); - const basegfx::B2DPolygon aPolygon(basegfx::tools::createUnitPolygon()); - - maRenderState.DeviceColor = aModifiedColor.colorToDoubleSequence(mxCanvas->getDevice()); - canvas::tools::setRenderStateTransform(maRenderState, - getViewInformation2D().getObjectTransformation() * rBitmapCandidate.getTransform()); - - mxCanvas->fillPolyPolygon(basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( - mxCanvas->getDevice(), basegfx::B2DPolyPolygon(aPolygon)), maViewState, maRenderState); - } - else - { - // adapt object's transformation to the correct scale - basegfx::B2DVector aScale, aTranslate; - double fRotate, fShearX; - const Size aSizePixel(aModifiedBitmapEx.GetSizePixel()); - - if(0 != aSizePixel.Width() && 0 != aSizePixel.Height()) - { - rBitmapCandidate.getTransform().decompose(aScale, aTranslate, fRotate, fShearX); - const basegfx::B2DHomMatrix aNewMatrix(basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix( - aScale.getX() / aSizePixel.Width(), aScale.getY() / aSizePixel.Height(), - fShearX, fRotate, aTranslate.getX(), aTranslate.getY())); - - canvas::tools::setRenderStateTransform(maRenderState, - getViewInformation2D().getObjectTransformation() * aNewMatrix); - - mxCanvas->drawBitmap( - vcl::unotools::xBitmapFromBitmapEx(mxCanvas->getDevice(), aModifiedBitmapEx), - maViewState, maRenderState); - } - } - } - - void canvasProcessor2D::impRenderTransparencePrimitive2D(const primitive2d::TransparencePrimitive2D& rTransparenceCandidate) - { - const primitive2d::Primitive2DSequence& rChildren = rTransparenceCandidate.getChildren(); - const primitive2d::Primitive2DSequence& rTransparence = rTransparenceCandidate.getTransparence(); - - if(rChildren.hasElements() && rTransparence.hasElements()) - { - // get logic range of transparent part and clip with ViewRange - basegfx::B2DRange aLogicRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rChildren, getViewInformation2D())); - - if(!getViewInformation2D().getViewport().isEmpty()) - { - aLogicRange.intersect(getViewInformation2D().getViewport()); - } - - if(!aLogicRange.isEmpty()) - { - // get discrete range of transparent part - basegfx::B2DRange aDiscreteRange(aLogicRange); - aDiscreteRange.transform(getViewInformation2D().getObjectToViewTransformation()); - - // expand to next covering discrete values (pixel bounds) - aDiscreteRange.expand(basegfx::B2DTuple(floor(aDiscreteRange.getMinX()), floor(aDiscreteRange.getMinY()))); - aDiscreteRange.expand(basegfx::B2DTuple(ceil(aDiscreteRange.getMaxX()), ceil(aDiscreteRange.getMaxY()))); - - // use VCL-based buffer device - impBufferDevice aBufferDevice(*mpOutputDevice, aDiscreteRange, false); - - if(aBufferDevice.isVisible()) - { - // remember current OutDev, Canvas and ViewInformation - OutputDevice* pLastOutputDevice = mpOutputDevice; - uno::Reference< rendering::XCanvas > xLastCanvas(mxCanvas); - const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D()); - - // prepare discrete offset for XBitmap, do not forget that the buffer bitmap - // may be truncated to discrete visible pixels - const basegfx::B2DHomMatrix aDiscreteOffset(basegfx::tools::createTranslateB2DHomMatrix( - aDiscreteRange.getMinX() > 0.0 ? -aDiscreteRange.getMinX() : 0.0, - aDiscreteRange.getMinY() > 0.0 ? -aDiscreteRange.getMinY() : 0.0)); - - // create new local ViewInformation2D with new transformation - const geometry::ViewInformation2D aViewInformation2D( - getViewInformation2D().getObjectTransformation(), - aDiscreteOffset * getViewInformation2D().getViewTransformation(), - getViewInformation2D().getViewport(), - getViewInformation2D().getVisualizedPage(), - getViewInformation2D().getViewTime(), - getViewInformation2D().getExtendedInformationSequence()); - updateViewInformation(aViewInformation2D); - - // set OutDev and Canvas to content target - mpOutputDevice = &aBufferDevice.getContent(); - mxCanvas = mpOutputDevice->GetCanvas(); - canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation()); - - // if ViewState transform is changed, the clipping polygon needs to be adapted, too - const basegfx::B2DPolyPolygon aOldClipPolyPolygon(maClipPolyPolygon); - - if(maClipPolyPolygon.count()) - { - maClipPolyPolygon.transform(aDiscreteOffset); - maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon); - } - - // paint content - process(rChildren); - - // set to mask - mpOutputDevice = &aBufferDevice.getTransparence(); - mxCanvas = mpOutputDevice->GetCanvas(); - canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation()); - - // when painting transparence masks, reset the color stack - basegfx::BColorModifierStack aLastBColorModifierStack(maBColorModifierStack); - maBColorModifierStack = basegfx::BColorModifierStack(); - - // paint mask to it (always with transparence intensities, evtl. with AA) - process(rTransparence); - - // back to old color stack, OutDev, Canvas and ViewTransform - maBColorModifierStack = aLastBColorModifierStack; - mpOutputDevice = pLastOutputDevice; - mxCanvas = xLastCanvas; - updateViewInformation(aLastViewInformation2D); - canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation()); - - // restore clipping polygon - maClipPolyPolygon = aOldClipPolyPolygon; - - if(maClipPolyPolygon.count()) - { - maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon); - } - - // dump buffer to outdev - aBufferDevice.paint(); - } - } - } - } - - void canvasProcessor2D::impRenderPolygonStrokePrimitive2D(const primitive2d::PolygonStrokePrimitive2D& rPolygonStrokePrimitive) - { - // support direct fat line geometry. This moves the decomposition to the canvas. - // As long as our canvases are used (which also use basegfx tooling) this makes - // no difference, but potentially canvases may better support this - static bool bSupportFatLineDirectly(true); - bool bOutputDone(false); - - if(bSupportFatLineDirectly) - { - const attribute::LineAttribute& rLineAttribute = rPolygonStrokePrimitive.getLineAttribute(); - const attribute::StrokeAttribute& rStrokeAttribute = rPolygonStrokePrimitive.getStrokeAttribute(); - - if(0.0 < rLineAttribute.getWidth() || 0 != rStrokeAttribute.getDotDashArray().size()) - { - rendering::StrokeAttributes aStrokeAttribute; - - aStrokeAttribute.StrokeWidth = rLineAttribute.getWidth(); - aStrokeAttribute.MiterLimit = 15.0; // degrees; maybe here (15.0 * F_PI180) is needed, not clear in the documentation - const ::std::vector< double >& rDotDashArray = rStrokeAttribute.getDotDashArray(); - - if(rDotDashArray.size()) - { - aStrokeAttribute.DashArray = uno::Sequence< double >(&rDotDashArray[0], rDotDashArray.size()); - } - - switch(rLineAttribute.getLineJoin()) - { - default: // B2DLINEJOIN_NONE, B2DLINEJOIN_MIDDLE - aStrokeAttribute.JoinType = rendering::PathJoinType::NONE; - break; - case basegfx::B2DLINEJOIN_BEVEL: - aStrokeAttribute.JoinType = rendering::PathJoinType::BEVEL; - break; - case basegfx::B2DLINEJOIN_MITER: - aStrokeAttribute.JoinType = rendering::PathJoinType::MITER; - break; - case basegfx::B2DLINEJOIN_ROUND: - aStrokeAttribute.JoinType = rendering::PathJoinType::ROUND; - break; - } - - switch(rLineAttribute.getLineCap()) - { - case com::sun::star::drawing::LineCap_ROUND: - aStrokeAttribute.StartCapType = rendering::PathCapType::ROUND; - aStrokeAttribute.EndCapType = rendering::PathCapType::ROUND; - break; - case com::sun::star::drawing::LineCap_SQUARE: - aStrokeAttribute.StartCapType = rendering::PathCapType::SQUARE; - aStrokeAttribute.EndCapType = rendering::PathCapType::SQUARE; - break; - default: // com::sun::star::drawing::LineCap_BUTT - aStrokeAttribute.StartCapType = rendering::PathCapType::BUTT; - aStrokeAttribute.EndCapType = rendering::PathCapType::BUTT; - break; - } - - const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rLineAttribute.getColor())); - maRenderState.DeviceColor = aHairlineColor.colorToDoubleSequence(mxCanvas->getDevice()); - canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation()); - - mxCanvas->strokePolyPolygon( - basegfx::unotools::xPolyPolygonFromB2DPolygon(mxCanvas->getDevice(), rPolygonStrokePrimitive.getB2DPolygon()), - maViewState, maRenderState, aStrokeAttribute); - - bOutputDone = true; - } - } - - if(!bOutputDone) - { - // process decomposition - process(rPolygonStrokePrimitive.get2DDecomposition(getViewInformation2D())); - } - } - - void canvasProcessor2D::impRenderFillBitmapPrimitive2D(const primitive2d::FillBitmapPrimitive2D& rFillBitmapPrimitive2D) - { - // support tiled fills directly when tiling is on - static bool bSupportFillBitmapDirectly(true); - bool bOutputDone(false); - - if(bSupportFillBitmapDirectly) - { - const attribute::FillBitmapAttribute& rFillBitmapAttribute = rFillBitmapPrimitive2D.getFillBitmap(); - - if(rFillBitmapAttribute.getTiling()) - { - // apply possible color modification to Bitmap - const BitmapEx aChangedBitmapEx(impModifyBitmapEx(maBColorModifierStack, rFillBitmapAttribute.getBitmapEx())); - - if(aChangedBitmapEx.IsEmpty()) - { - // replace with color filled polygon - const basegfx::BColor aModifiedColor(maBColorModifierStack.getModifiedColor(basegfx::BColor())); - const basegfx::B2DPolygon aPolygon(basegfx::tools::createUnitPolygon()); - - maRenderState.DeviceColor = aModifiedColor.colorToDoubleSequence(mxCanvas->getDevice()); - canvas::tools::setRenderStateTransform(maRenderState, - getViewInformation2D().getObjectTransformation() * rFillBitmapPrimitive2D.getTransformation()); - - mxCanvas->fillPolyPolygon(basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( - mxCanvas->getDevice(), basegfx::B2DPolyPolygon(aPolygon)), maViewState, maRenderState); - } - else - { - const Size aSizePixel(aChangedBitmapEx.GetSizePixel()); - - if(0 != aSizePixel.Width() && 0 != aSizePixel.Height()) - { - // create texture matrix from texture to object (where object is unit square here), - // so use values directly - const basegfx::B2DHomMatrix aTextureMatrix(basegfx::tools::createScaleTranslateB2DHomMatrix( - rFillBitmapAttribute.getSize().getX(), rFillBitmapAttribute.getSize().getY(), - rFillBitmapAttribute.getTopLeft().getX(), rFillBitmapAttribute.getTopLeft().getY())); - - // create and fill texture - rendering::Texture aTexture; - - basegfx::unotools::affineMatrixFromHomMatrix(aTexture.AffineTransform, aTextureMatrix); - aTexture.Alpha = 1.0; - aTexture.Bitmap = vcl::unotools::xBitmapFromBitmapEx(mxCanvas->getDevice(), aChangedBitmapEx); - aTexture.RepeatModeX = rendering::TexturingMode::REPEAT; - aTexture.RepeatModeY = rendering::TexturingMode::REPEAT; - - // canvas needs a polygon to fill, create unit rectangle polygon - const basegfx::B2DPolygon aOutlineRectangle(basegfx::tools::createUnitPolygon()); - - // set primitive's transformation as render state transform - canvas::tools::setRenderStateTransform(maRenderState, - getViewInformation2D().getObjectTransformation() * rFillBitmapPrimitive2D.getTransformation()); - - // put texture into a uno sequence for handover - uno::Sequence< rendering::Texture > aSeq(1); - aSeq[0] = aTexture; - - // draw textured rectangle - mxCanvas->fillTexturedPolyPolygon( - basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), basegfx::B2DPolyPolygon(aOutlineRectangle)), - maViewState, maRenderState, aSeq); - } - } - - bOutputDone = true; - } - } - - if(!bOutputDone) - { - // process decomposition - process(rFillBitmapPrimitive2D.get2DDecomposition(getViewInformation2D())); - } - } - - void canvasProcessor2D::impRenderUnifiedTransparencePrimitive2D(const primitive2d::UnifiedTransparencePrimitive2D& rUniTransparenceCandidate) - { - if(0.0 == rUniTransparenceCandidate.getTransparence()) - { - // not transparent at all, directly use content - process(rUniTransparenceCandidate.getChildren()); - } - else if(rUniTransparenceCandidate.getTransparence() > 0.0 && rUniTransparenceCandidate.getTransparence() < 1.0) - { - const primitive2d::Primitive2DSequence rChildren = rUniTransparenceCandidate.getChildren(); - - if(rChildren.hasElements()) - { - bool bOutputDone(false); - - // Detect if a single PolyPolygonColorPrimitive2D is contained; in that case, - // use the fillPolyPolygon method with correctly set transparence. This is a often used - // case, so detectiong it is valuable - if(1 == rChildren.getLength()) - { - const primitive2d::Primitive2DReference xReference(rChildren[0]); - const primitive2d::PolyPolygonColorPrimitive2D* pPoPoColor = dynamic_cast< const primitive2d::PolyPolygonColorPrimitive2D* >(xReference.get()); - - if(pPoPoColor && PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D == pPoPoColor->getPrimitive2DID()) - { - // direct draw of PolyPolygon with color and transparence - const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(pPoPoColor->getBColor())); - - // add transparence modulation value to DeviceColor - uno::Sequence< double > aColor(4); - - aColor[0] = aPolygonColor.getRed(); - aColor[1] = aPolygonColor.getGreen(); - aColor[2] = aPolygonColor.getBlue(); - aColor[3] = 1.0 - rUniTransparenceCandidate.getTransparence(); - maRenderState.DeviceColor = aColor; - - canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation()); - mxCanvas->fillPolyPolygon( - basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), pPoPoColor->getB2DPolyPolygon()), - maViewState, maRenderState); - bOutputDone = true; - } - } - - if(!bOutputDone) - { - // process decomposition. This will be decomposed to an TransparencePrimitive2D - // with the same child context and a single polygon for transparent context. This could be - // directly handled here with known VCL-buffer technology, but would only - // make a small difference compared to directly rendering the TransparencePrimitive2D - // using impRenderTransparencePrimitive2D above. - process(rUniTransparenceCandidate.get2DDecomposition(getViewInformation2D())); - } - } - } - } - - ////////////////////////////////////////////////////////////////////////////// - // internal processing support - - void canvasProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate) - { - switch(rCandidate.getPrimitive2DID()) - { - case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D : - { - // direct draw of hairline - const primitive2d::PolygonHairlinePrimitive2D& rPolygonCandidate = static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate); - const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor())); - - maRenderState.DeviceColor = aHairlineColor.colorToDoubleSequence(mxCanvas->getDevice()); - canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation()); - mxCanvas->drawPolyPolygon( - basegfx::unotools::xPolyPolygonFromB2DPolygon(mxCanvas->getDevice(), rPolygonCandidate.getB2DPolygon()), - maViewState, maRenderState); - - break; - } - case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D : - { - // direct draw of PolyPolygon with color - const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate = static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate); - const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor())); - - maRenderState.DeviceColor = aPolygonColor.colorToDoubleSequence(mxCanvas->getDevice()); - canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation()); - mxCanvas->fillPolyPolygon( - basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), rPolygonCandidate.getB2DPolyPolygon()), - maViewState, maRenderState); - - break; - } - case PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D : - { - // modified color group. Force output to unified color. - const primitive2d::ModifiedColorPrimitive2D& rModifiedCandidate = static_cast< const primitive2d::ModifiedColorPrimitive2D& >(rCandidate); - - if(rModifiedCandidate.getChildren().hasElements()) - { - maBColorModifierStack.push(rModifiedCandidate.getColorModifier()); - process(rModifiedCandidate.getChildren()); - maBColorModifierStack.pop(); - } - - break; - } - case PRIMITIVE2D_ID_MASKPRIMITIVE2D : - { - // mask group - impRenderMaskPrimitive2D(static_cast< const primitive2d::MaskPrimitive2D& >(rCandidate)); - - break; - } - case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D : - { - // transform group. Remember current ViewInformation2D - const primitive2d::TransformPrimitive2D& rTransformCandidate = static_cast< const primitive2d::TransformPrimitive2D& >(rCandidate); - const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D()); - - // create new local ViewInformation2D with new transformation - const geometry::ViewInformation2D aViewInformation2D( - getViewInformation2D().getObjectTransformation() * rTransformCandidate.getTransformation(), - getViewInformation2D().getViewTransformation(), - getViewInformation2D().getViewport(), - getViewInformation2D().getVisualizedPage(), - getViewInformation2D().getViewTime(), - getViewInformation2D().getExtendedInformationSequence()); - updateViewInformation(aViewInformation2D); - - // set at canvas - canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation()); - - // proccess content - process(rTransformCandidate.getChildren()); - - // restore transformations - updateViewInformation(aLastViewInformation2D); - - // restore at canvas - canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation()); - - break; - } - case PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D : - { - // new XDrawPage for ViewInformation2D - const primitive2d::PagePreviewPrimitive2D& rPagePreviewCandidate = static_cast< const primitive2d::PagePreviewPrimitive2D& >(rCandidate); - - // remember current transformation and ViewInformation - const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D()); - - // create new local ViewInformation2D - const geometry::ViewInformation2D aViewInformation2D( - getViewInformation2D().getObjectTransformation(), - getViewInformation2D().getViewTransformation(), - getViewInformation2D().getViewport(), - rPagePreviewCandidate.getXDrawPage(), - getViewInformation2D().getViewTime(), - getViewInformation2D().getExtendedInformationSequence()); - updateViewInformation(aViewInformation2D); - - // proccess decomposed content - process(rPagePreviewCandidate.get2DDecomposition(getViewInformation2D())); - - // restore transformations - updateViewInformation(aLastViewInformation2D); - break; - } - case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D : - { - // MetaFile primitive - impRenderMetafilePrimitive2D(static_cast< const primitive2d::MetafilePrimitive2D& >(rCandidate)); - - break; - } - case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D : - { - // PointArray primitive - const primitive2d::PointArrayPrimitive2D& rPointArrayCandidate = static_cast< const primitive2d::PointArrayPrimitive2D& >(rCandidate); - - // set point color - const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(rPointArrayCandidate.getRGBColor())); - maRenderState.DeviceColor = aRGBColor.colorToDoubleSequence(mxCanvas->getDevice()); - canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation()); - - const std::vector< basegfx::B2DPoint >& rPointVector = rPointArrayCandidate.getPositions(); - const sal_uInt32 nPointCount(rPointVector.size()); - - for(sal_uInt32 a(0); a < nPointCount; a++) - { - const basegfx::B2DPoint& rPoint = rPointVector[a]; - mxCanvas->drawPoint(basegfx::unotools::point2DFromB2DPoint(rPoint), maViewState, maRenderState); - } - - break; - } - case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D : - { - // TextSimplePortion primitive - impRenderTextSimplePortionPrimitive2D(static_cast< const primitive2d::TextSimplePortionPrimitive2D& >(rCandidate)); - - break; - } - case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D : - { - // Bitmap primitive - impRenderBitmapPrimitive2D(static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate)); - - break; - } - case PRIMITIVE2D_ID_TRANSPARENCEPRIMITIVE2D : - { - // Transparence primitive - impRenderTransparencePrimitive2D(static_cast< const primitive2d::TransparencePrimitive2D& >(rCandidate)); - - break; - } - case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D: - { - // PolygonStrokePrimitive - impRenderPolygonStrokePrimitive2D(static_cast< const primitive2d::PolygonStrokePrimitive2D& >(rCandidate)); - - break; - } - case PRIMITIVE2D_ID_FILLBITMAPPRIMITIVE2D : - { - // FillBitmapPrimitive2D - impRenderFillBitmapPrimitive2D(static_cast< const primitive2d::FillBitmapPrimitive2D& >(rCandidate)); - - break; - } - case PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D : - { - // UnifiedTransparencePrimitive2D - impRenderUnifiedTransparencePrimitive2D(static_cast< const primitive2d::UnifiedTransparencePrimitive2D& >(rCandidate)); - - break; - } - case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D : - { - // wrong spell primitive. Handled directly here using VCL since VCL has a nice and - // very direct waveline painting which is needed for this. If VCL is to be avoided, - // this can be removed anytime and the decomposition may be used - const primitive2d::WrongSpellPrimitive2D& rWrongSpellPrimitive = static_cast< const primitive2d::WrongSpellPrimitive2D& >(rCandidate); - - if(!renderWrongSpellPrimitive2D( - rWrongSpellPrimitive, - *mpOutputDevice, - getViewInformation2D().getObjectToViewTransformation(), - maBColorModifierStack)) - { - // fallback to decomposition (MetaFile) - process(rWrongSpellPrimitive.get2DDecomposition(getViewInformation2D())); - } - - break; - } - - // nice to have: - // - // case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D : - // - support FormControls more direct eventually, not sure if this is needed - // with the canvas renderer. The decomposition provides a bitmap representation - // of the control which will work - // - - default : - { - // process recursively - process(rCandidate.get2DDecomposition(getViewInformation2D())); - - break; - } - } - } - - ////////////////////////////////////////////////////////////////////////////// - // process support - - canvasProcessor2D::canvasProcessor2D( - const geometry::ViewInformation2D& rViewInformation, - OutputDevice& rOutDev) - : BaseProcessor2D(rViewInformation), - mpOutputDevice(&rOutDev), - mxCanvas(rOutDev.GetCanvas()), - maViewState(), - maRenderState(), - maBColorModifierStack(), - maDrawinglayerOpt(), - maClipPolyPolygon(), - meLang(LANGUAGE_SYSTEM) - { - const SvtCTLOptions aSvtCTLOptions; - - canvas::tools::initViewState(maViewState); - canvas::tools::initRenderState(maRenderState); - canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation()); - - // set digit language, derived from SvtCTLOptions to have the correct - // number display for arabic/hindi numerals - if(SvtCTLOptions::NUMERALS_HINDI == aSvtCTLOptions.GetCTLTextNumerals()) - { - meLang = LANGUAGE_ARABIC_SAUDI_ARABIA; - } - else if(SvtCTLOptions::NUMERALS_ARABIC == aSvtCTLOptions.GetCTLTextNumerals()) - { - meLang = LANGUAGE_ENGLISH; - } - else - { - meLang = (LanguageType)Application::GetSettings().GetLanguage(); - } - - rOutDev.SetDigitLanguage(meLang); - - // prepare output directly to pixels - mpOutputDevice->Push(PUSH_MAPMODE); - mpOutputDevice->SetMapMode(); - - // react on AntiAliasing settings - if(getOptionsDrawinglayer().IsAntiAliasing()) - { - mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() | ANTIALIASING_ENABLE_B2DDRAW); - } - else - { - mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() & ~ANTIALIASING_ENABLE_B2DDRAW); - } - } - - canvasProcessor2D::~canvasProcessor2D() - { - // restore MapMode - mpOutputDevice->Pop(); - - // restore AntiAliasing - mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() & ~ANTIALIASING_ENABLE_B2DDRAW); - } - } // end of namespace processor2d -} // end of namespace drawinglayer - -////////////////////////////////////////////////////////////////////////////// -// eof diff --git a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx index b39534b739fb..d93dfa5e21b6 100644 --- a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx @@ -590,7 +590,7 @@ namespace drawinglayer Even for XFillTransparenceItem it is used, thus it may need to be supported in UnifiedTransparencePrimitive2D, too, when interpreted as normally filled PolyPolygon. Implemented for: - PRIMITIVE2D_ID_POLYPOLYGONBITMAPPRIMITIVE2D, + PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D, PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D, PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D, PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D, @@ -1300,19 +1300,19 @@ namespace drawinglayer RenderBitmapPrimitive2D(static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate)); break; } - case PRIMITIVE2D_ID_POLYPOLYGONBITMAPPRIMITIVE2D : + case PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D : { - // need to handle PolyPolygonBitmapPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END - const primitive2d::PolyPolygonBitmapPrimitive2D& rBitmapCandidate = static_cast< const primitive2d::PolyPolygonBitmapPrimitive2D& >(rCandidate); + // need to handle PolyPolygonGraphicPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END + const primitive2d::PolyPolygonGraphicPrimitive2D& rBitmapCandidate = static_cast< const primitive2d::PolyPolygonGraphicPrimitive2D& >(rCandidate); basegfx::B2DPolyPolygon aLocalPolyPolygon(rBitmapCandidate.getB2DPolyPolygon()); if(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon)) { // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points // per polygon. If there are more use the splitted polygon and call recursively - const primitive2d::PolyPolygonBitmapPrimitive2D aSplitted( + const primitive2d::PolyPolygonGraphicPrimitive2D aSplitted( aLocalPolyPolygon, - rBitmapCandidate.getFillBitmap()); + rBitmapCandidate.getFillGraphic()); processBasePrimitive2D(aSplitted); } @@ -1322,46 +1322,41 @@ namespace drawinglayer if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count()) { - aLocalPolyPolygon.transform(maCurrentTransformation); - // calculate transformation. Get real object size, all values in FillBitmapAttribute - // are relative to the unified object - const attribute::FillBitmapAttribute& rFillBitmapAttribute = rBitmapCandidate .getFillBitmap(); - const basegfx::B2DRange aOutlineRange(basegfx::tools::getRange(aLocalPolyPolygon)); - const basegfx::B2DVector aOutlineSize(aOutlineRange.getRange()); + // #121194# Changed implementation and checked usages fo convert to metafile, + // presentation start (uses SvtGraphicFill) and printing. - // get absolute values - const basegfx::B2DVector aFillBitmapSize(rFillBitmapAttribute.getSize() * aOutlineSize); - const basegfx::B2DPoint aFillBitmapTopLeft(rFillBitmapAttribute.getTopLeft() * aOutlineSize); + // calculate transformation. Get real object size, all values in FillGraphicAttribute + // are relative to the unified object + aLocalPolyPolygon.transform(maCurrentTransformation); + const basegfx::B2DVector aOutlineSize(aLocalPolyPolygon.getB2DRange().getRange()); // the scaling needs scale from pixel to logic coordinate system - const BitmapEx& rBitmapEx = rFillBitmapAttribute.getBitmapEx(); - Size aBmpSizePixel(rBitmapEx.GetSizePixel()); - - if(!aBmpSizePixel.Width()) - { - aBmpSizePixel.Width() = 1; - } - - if(!aBmpSizePixel.Height()) - { - aBmpSizePixel.Height() = 1; - } + const attribute::FillGraphicAttribute& rFillGraphicAttribute = rBitmapCandidate.getFillGraphic(); + const Size aBmpSizePixel(rFillGraphicAttribute.getGraphic().GetSizePixel()); + + // setup transformation like in impgrfll. Multiply with aOutlineSize + // to get from unit coordinates in rFillGraphicAttribute.getGraphicRange() + // to object coordinates with object's top left being at (0,0). Divide + // by pixel size so that scale from pixel to logic will work in SvtGraphicFill. + const basegfx::B2DVector aTransformScale( + rFillGraphicAttribute.getGraphicRange().getRange() / + basegfx::B2DVector( + std::max(1.0, double(aBmpSizePixel.Width())), + std::max(1.0, double(aBmpSizePixel.Height()))) * + aOutlineSize); + const basegfx::B2DPoint aTransformPosition( + rFillGraphicAttribute.getGraphicRange().getMinimum() * aOutlineSize); // setup transformation like in impgrfll SvtGraphicFill::Transform aTransform; // scale values are divided by bitmap pixel sizes - aTransform.matrix[0] = aFillBitmapSize.getX() / aBmpSizePixel.Width(); - aTransform.matrix[4] = aFillBitmapSize.getY() / aBmpSizePixel.Height(); + aTransform.matrix[0] = aTransformScale.getX(); + aTransform.matrix[4] = aTransformScale.getY(); // translates are absolute - aTransform.matrix[2] = aFillBitmapTopLeft.getX(); - aTransform.matrix[5] = aFillBitmapTopLeft.getY(); - - // setup fill graphic like in impgrfll - Graphic aFillGraphic = Graphic(rBitmapEx); - aFillGraphic.SetPrefMapMode(MapMode(MAP_PIXEL)); - aFillGraphic.SetPrefSize(aBmpSizePixel); + aTransform.matrix[2] = aTransformPosition.getX(); + aTransform.matrix[5] = aTransformPosition.getY(); pSvtGraphicFill = new SvtGraphicFill( PolyPolygon(aLocalPolyPolygon), @@ -1370,14 +1365,14 @@ namespace drawinglayer SvtGraphicFill::fillEvenOdd, SvtGraphicFill::fillTexture, aTransform, - rFillBitmapAttribute.getTiling(), + rFillGraphicAttribute.getTiling(), SvtGraphicFill::hatchSingle, Color(), SvtGraphicFill::gradientLinear, Color(), Color(), 0, - aFillGraphic); + rFillGraphicAttribute.getGraphic()); } // Do use decomposition; encapsulate with SvtGraphicFill @@ -1748,7 +1743,7 @@ namespace drawinglayer } // PolyPolygonGradientPrimitive2D, PolyPolygonHatchPrimitive2D and - // PolyPolygonBitmapPrimitive2D are derived from PolyPolygonColorPrimitive2D. + // PolyPolygonGraphicPrimitive2D are derived from PolyPolygonColorPrimitive2D. // Check also for correct ID to exclude derived implementations if(pPoPoColor && PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D == pPoPoColor->getPrimitive2DID()) { diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx index 92b3351025bf..1c88543168fb 100644 --- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx @@ -31,7 +31,7 @@ #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> #include <drawinglayer/primitive2d/polygonprimitive2d.hxx> #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> -#include <drawinglayer/primitive2d/fillbitmapprimitive2d.hxx> +#include <drawinglayer/primitive2d/fillgraphicprimitive2d.hxx> #include <drawinglayer/primitive2d/metafileprimitive2d.hxx> #include <drawinglayer/primitive2d/maskprimitive2d.hxx> #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx> @@ -186,10 +186,10 @@ namespace drawinglayer RenderBitmapPrimitive2D(static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate)); break; } - case PRIMITIVE2D_ID_FILLBITMAPPRIMITIVE2D : + case PRIMITIVE2D_ID_FILLGRAPHICPRIMITIVE2D : { // direct draw of fillBitmapPrimitive - RenderFillBitmapPrimitive2D(static_cast< const primitive2d::FillBitmapPrimitive2D& >(rCandidate)); + RenderFillGraphicPrimitive2D(static_cast< const primitive2d::FillGraphicPrimitive2D& >(rCandidate)); break; } case PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D : @@ -198,10 +198,10 @@ namespace drawinglayer RenderPolyPolygonGradientPrimitive2D(static_cast< const primitive2d::PolyPolygonGradientPrimitive2D& >(rCandidate)); break; } - case PRIMITIVE2D_ID_POLYPOLYGONBITMAPPRIMITIVE2D : + case PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D : { // direct draw of bitmap - RenderPolyPolygonBitmapPrimitive2D(static_cast< const primitive2d::PolyPolygonBitmapPrimitive2D& >(rCandidate)); + RenderPolyPolygonGraphicPrimitive2D(static_cast< const primitive2d::PolyPolygonGraphicPrimitive2D& >(rCandidate)); break; } case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D : diff --git a/drawinglayer/source/processor2d/vclprocessor2d.cxx b/drawinglayer/source/processor2d/vclprocessor2d.cxx index 80f1344ddf92..c63a8aa5ed9b 100644 --- a/drawinglayer/source/processor2d/vclprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclprocessor2d.cxx @@ -34,8 +34,8 @@ #include <vclhelperbitmaptransform.hxx> #include <basegfx/polygon/b2dpolygontools.hxx> #include <vclhelperbitmaprender.hxx> -#include <drawinglayer/attribute/sdrfillbitmapattribute.hxx> -#include <drawinglayer/primitive2d/fillbitmapprimitive2d.hxx> +#include <drawinglayer/attribute/sdrfillgraphicattribute.hxx> +#include <drawinglayer/primitive2d/fillgraphicprimitive2d.hxx> #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> #include <vclhelpergradient.hxx> #include <drawinglayer/primitive2d/metafileprimitive2d.hxx> @@ -59,6 +59,7 @@ #include <drawinglayer/primitive2d/svggradientprimitive2d.hxx> #include <basegfx/color/bcolor.hxx> #include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <vcl/graph.hxx> ////////////////////////////////////////////////////////////////////////////// // control support @@ -448,122 +449,192 @@ namespace drawinglayer } } - void VclProcessor2D::RenderFillBitmapPrimitive2D(const primitive2d::FillBitmapPrimitive2D& rFillBitmapCandidate) + void VclProcessor2D::RenderFillGraphicPrimitive2D(const primitive2d::FillGraphicPrimitive2D& rFillBitmapCandidate) { - const attribute::FillBitmapAttribute& rFillBitmapAttribute(rFillBitmapCandidate.getFillBitmap()); + const attribute::FillGraphicAttribute& rFillGraphicAttribute(rFillBitmapCandidate.getFillGraphic()); bool bPrimitiveAccepted(false); + static bool bTryTilingDirect = true; - if(rFillBitmapAttribute.getTiling()) - { - // decompose matrix to check for shear, rotate and mirroring - basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation * rFillBitmapCandidate.getTransformation()); - basegfx::B2DVector aScale, aTranslate; - double fRotate, fShearX; - aLocalTransform.decompose(aScale, aTranslate, fRotate, fShearX); + // #121194# when tiling is used and content is bitmap-based, do direct tiling in the + // renderer on pixel base to ensure tight fitting. Do not do this when + // the fill is rotated or sheared. - if(basegfx::fTools::equalZero(fRotate) && basegfx::fTools::equalZero(fShearX)) + // ovveride static bool (for debug) and tiling is active + if(bTryTilingDirect && rFillGraphicAttribute.getTiling()) + { + // content is bitmap(ex) + // + // for SVG support, force decomposition when SVG is present. This will lead to use + // the primitive representation of the svg directly. + // + // when graphic is animated, force decomposition to use the correct graphic, else + // fill style will not be animated + if(GRAPHIC_BITMAP == rFillGraphicAttribute.getGraphic().GetType() + && !rFillGraphicAttribute.getGraphic().getSvgData().get() + && !rFillGraphicAttribute.getGraphic().IsAnimated()) { - // no shear or rotate, draw direct in pixel coordinates - bPrimitiveAccepted = true; - BitmapEx aBitmapEx(rFillBitmapAttribute.getBitmapEx()); - bool bPainted(false); - - if(maBColorModifierStack.count()) + // decompose matrix to check for shear, rotate and mirroring + basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation * rFillBitmapCandidate.getTransformation()); + basegfx::B2DVector aScale, aTranslate; + double fRotate, fShearX; + aLocalTransform.decompose(aScale, aTranslate, fRotate, fShearX); + + // when nopt rotated/sheared + if(basegfx::fTools::equalZero(fRotate) && basegfx::fTools::equalZero(fShearX)) { - aBitmapEx = impModifyBitmapEx(maBColorModifierStack, aBitmapEx); - - if(aBitmapEx.IsEmpty()) - { - // color gets completely replaced, get it - const basegfx::BColor aModifiedColor(maBColorModifierStack.getModifiedColor(basegfx::BColor())); - basegfx::B2DPolygon aPolygon(basegfx::tools::createUnitPolygon()); - aPolygon.transform(aLocalTransform); + // no shear or rotate, draw direct in pixel coordinates + bPrimitiveAccepted = true; - mpOutputDevice->SetFillColor(Color(aModifiedColor)); - mpOutputDevice->SetLineColor(); - mpOutputDevice->DrawPolygon(aPolygon); + // transform object range to device coordinates (pixels). Use + // the device transformation for better accuracy + basegfx::B2DRange aObjectRange(aTranslate, aTranslate + aScale); + aObjectRange.transform(mpOutputDevice->GetViewTransformation()); - bPainted = true; - } - } - - if(!bPainted) - { - const basegfx::B2DPoint aObjTopLeft(aTranslate.getX(), aTranslate.getY()); - const basegfx::B2DPoint aObjBottomRight(aTranslate.getX() + aScale.getX(), aTranslate.getY() + aScale.getY()); - const Point aObjTL(mpOutputDevice->LogicToPixel(Point((sal_Int32)aObjTopLeft.getX(), (sal_Int32)aObjTopLeft.getY()))); - const Point aObjBR(mpOutputDevice->LogicToPixel(Point((sal_Int32)aObjBottomRight.getX(), (sal_Int32)aObjBottomRight.getY()))); - - const basegfx::B2DPoint aBmpTopLeft(aLocalTransform * rFillBitmapAttribute.getTopLeft()); - const basegfx::B2DPoint aBmpBottomRight(aLocalTransform * basegfx::B2DPoint(rFillBitmapAttribute.getTopLeft() + rFillBitmapAttribute.getSize())); - const Point aBmpTL(mpOutputDevice->LogicToPixel(Point((sal_Int32)aBmpTopLeft.getX(), (sal_Int32)aBmpTopLeft.getY()))); - const Point aBmpBR(mpOutputDevice->LogicToPixel(Point((sal_Int32)aBmpBottomRight.getX(), (sal_Int32)aBmpBottomRight.getY()))); - - sal_Int32 nOWidth(aObjBR.X() - aObjTL.X()); - sal_Int32 nOHeight(aObjBR.Y() - aObjTL.Y()); + // extract discrete size of object + const sal_Int32 nOWidth(basegfx::fround(aObjectRange.getWidth())); + const sal_Int32 nOHeight(basegfx::fround(aObjectRange.getHeight())); // only do something when object has a size in discrete units if(nOWidth > 0 && nOHeight > 0) { - sal_Int32 nBWidth(aBmpBR.X() - aBmpTL.X()); - sal_Int32 nBHeight(aBmpBR.Y() - aBmpTL.Y()); + // transform graphic range to device coordinates (pixels). Use + // the device transformation for better accuracy + basegfx::B2DRange aGraphicRange(rFillGraphicAttribute.getGraphicRange()); + aGraphicRange.transform(mpOutputDevice->GetViewTransformation() * aLocalTransform); + + // extract discrete size of graphic + const sal_Int32 nBWidth(basegfx::fround(aGraphicRange.getWidth())); + const sal_Int32 nBHeight(basegfx::fround(aGraphicRange.getHeight())); // only do something when bitmap fill has a size in discrete units if(nBWidth > 0 && nBHeight > 0) { - sal_Int32 nBLeft(aBmpTL.X()); - sal_Int32 nBTop(aBmpTL.Y()); - - if(nBLeft > aObjTL.X()) + // nBWidth, nBHeight is the pixel size of the neede bitmap. To not need to scale it + // in vcl many times, create a size-optimized version + const Size aNeededBitmapSizePixel(nBWidth, nBHeight); + BitmapEx aBitmapEx(rFillGraphicAttribute.getGraphic().GetBitmapEx( + GraphicConversionParameters( + aNeededBitmapSizePixel, // get the correct size immediately + false, // no unlimited size + false, // Use AntiAliasing + false, //SnapHorVerLines + true // ScaleHighQuality + ))); + bool bPainted(false); + + if(maBColorModifierStack.count()) { - nBLeft -= ((nBLeft / nBWidth) + 1L) * nBWidth; - } + // when color modifier, apply to bitmap + aBitmapEx = impModifyBitmapEx(maBColorModifierStack, aBitmapEx); - if(nBLeft + nBWidth <= aObjTL.X()) - { - nBLeft -= (nBLeft / nBWidth) * nBWidth; - } + // impModifyBitmapEx uses empty bitmap as sign to return that + // the content will be completely replaced to mono color, use shortcut + if(aBitmapEx.IsEmpty()) + { + // color gets completely replaced, get it + const basegfx::BColor aModifiedColor(maBColorModifierStack.getModifiedColor(basegfx::BColor())); + basegfx::B2DPolygon aPolygon(basegfx::tools::createUnitPolygon()); + aPolygon.transform(aLocalTransform); - if(nBTop > aObjTL.Y()) - { - nBTop -= ((nBTop / nBHeight) + 1L) * nBHeight; + mpOutputDevice->SetFillColor(Color(aModifiedColor)); + mpOutputDevice->SetLineColor(); + mpOutputDevice->DrawPolygon(aPolygon); + + bPainted = true; + } } - if(nBTop + nBHeight <= aObjTL.Y()) + if(!bPainted) { - nBTop -= (nBTop / nBHeight) * nBHeight; - } + sal_Int32 nBLeft(basegfx::fround(aGraphicRange.getMinX())); + sal_Int32 nBTop(basegfx::fround(aGraphicRange.getMinY())); + const sal_Int32 nOLeft(basegfx::fround(aObjectRange.getMinX())); + const sal_Int32 nOTop(basegfx::fround(aObjectRange.getMinY())); + sal_Int32 nPosX(0); + sal_Int32 nPosY(0); + + if(nBLeft > nOLeft) + { + const sal_Int32 nDiff((nBLeft / nBWidth) + 1); - // nBWidth, nBHeight is the pixel size of the neede bitmap. To not need to scale it - // in vcl many times, create a size-optimized version - const Size aNeededBitmapSizePixel(nBWidth, nBHeight); + nPosX -= nDiff; + nBLeft -= nDiff * nBWidth; + } - if(aNeededBitmapSizePixel != aBitmapEx.GetSizePixel()) - { - aBitmapEx.Scale(aNeededBitmapSizePixel); - } + if(nBLeft + nBWidth <= nOLeft) + { + const sal_Int32 nDiff(-nBLeft / nBWidth); - // prepare OutDev - const Point aEmptyPoint(0, 0); - const Rectangle aVisiblePixel(aEmptyPoint, mpOutputDevice->GetOutputSizePixel()); - const bool bWasEnabled(mpOutputDevice->IsMapModeEnabled()); - mpOutputDevice->EnableMapMode(false); + nPosX += nDiff; + nBLeft += nDiff * nBWidth; + } - for(sal_Int32 nXPos(nBLeft); nXPos < aObjTL.X() + nOWidth; nXPos += nBWidth) - { - for(sal_Int32 nYPos(nBTop); nYPos < aObjTL.Y() + nOHeight; nYPos += nBHeight) + if(nBTop > nOTop) + { + const sal_Int32 nDiff((nBTop / nBHeight) + 1); + + nPosY -= nDiff; + nBTop -= nDiff * nBHeight; + } + + if(nBTop + nBHeight <= nOTop) + { + const sal_Int32 nDiff(-nBTop / nBHeight); + + nPosY += nDiff; + nBTop += nDiff * nBHeight; + } + + // prepare OutDev + const Point aEmptyPoint(0, 0); + const Rectangle aVisiblePixel(aEmptyPoint, mpOutputDevice->GetOutputSizePixel()); + const bool bWasEnabled(mpOutputDevice->IsMapModeEnabled()); + mpOutputDevice->EnableMapMode(false); + + // check if offset is used + const sal_Int32 nOffsetX(basegfx::fround(rFillGraphicAttribute.getOffsetX() * nBWidth)); + + if(nOffsetX) + { + // offset in X, so iterate over Y first and draw lines + for(sal_Int32 nYPos(nBTop); nYPos < nOTop + nOHeight; nYPos += nBHeight, nPosY++) + { + for(sal_Int32 nXPos(nPosY % 2 ? nBLeft - nBWidth + nOffsetX : nBLeft); + nXPos < nOLeft + nOWidth; nXPos += nBWidth) + { + const Rectangle aOutRectPixel(Point(nXPos, nYPos), aNeededBitmapSizePixel); + + if(aOutRectPixel.IsOver(aVisiblePixel)) + { + mpOutputDevice->DrawBitmapEx(aOutRectPixel.TopLeft(), aBitmapEx); + } + } + } + } + else { - const Rectangle aOutRectPixel(Point(nXPos, nYPos), aNeededBitmapSizePixel); + // check if offset is used + const sal_Int32 nOffsetY(basegfx::fround(rFillGraphicAttribute.getOffsetY() * nBHeight)); - if(aOutRectPixel.IsOver(aVisiblePixel)) + // possible offset in Y, so iterate over X first and draw columns + for(sal_Int32 nXPos(nBLeft); nXPos < nOLeft + nOWidth; nXPos += nBWidth, nPosX++) { - mpOutputDevice->DrawBitmapEx(aOutRectPixel.TopLeft(), aBitmapEx); + for(sal_Int32 nYPos(nPosX % 2 ? nBTop - nBHeight + nOffsetY : nBTop); + nYPos < nOTop + nOHeight; nYPos += nBHeight) + { + const Rectangle aOutRectPixel(Point(nXPos, nYPos), aNeededBitmapSizePixel); + + if(aOutRectPixel.IsOver(aVisiblePixel)) + { + mpOutputDevice->DrawBitmapEx(aOutRectPixel.TopLeft(), aBitmapEx); + } + } } } - } - // restore OutDev - mpOutputDevice->EnableMapMode(bWasEnabled); + // restore OutDev + mpOutputDevice->EnableMapMode(bWasEnabled); + } } } } @@ -615,90 +686,105 @@ namespace drawinglayer } } - // direct draw of bitmap - void VclProcessor2D::RenderPolyPolygonBitmapPrimitive2D(const primitive2d::PolyPolygonBitmapPrimitive2D& rPolygonCandidate) + // direct draw of Graphic + void VclProcessor2D::RenderPolyPolygonGraphicPrimitive2D(const primitive2d::PolyPolygonGraphicPrimitive2D& rPolygonCandidate) { bool bDone(false); const basegfx::B2DPolyPolygon& rPolyPolygon = rPolygonCandidate.getB2DPolyPolygon(); - if(rPolyPolygon.count()) + // #121194# Todo: check if this works + if(!rPolyPolygon.count()) { - const attribute::FillBitmapAttribute& rFillBitmapAttribute = rPolygonCandidate.getFillBitmap(); - const BitmapEx& rBitmapEx = rFillBitmapAttribute.getBitmapEx(); + // empty polyPolygon, done + bDone = true; + } + else + { + const attribute::FillGraphicAttribute& rFillGraphicAttribute = rPolygonCandidate.getFillGraphic(); - if(rBitmapEx.IsEmpty()) - { - // empty bitmap, done - bDone = true; - } - else + // try to catch cases where the graphic will be color-modified to a single + // color (e.g. shadow) + switch(rFillGraphicAttribute.getGraphic().GetType()) { - // try to catch cases where the bitmap will be color-modified to a single - // color (e.g. shadow). This would NOT be optimizable with an transparence channel - // at the Bitmap which we do not have here. When this should change, this - // optimization has to be reworked accordingly. - const sal_uInt32 nBColorModifierStackCount(maBColorModifierStack.count()); - - if(nBColorModifierStackCount) + case GRAPHIC_GDIMETAFILE: { - const basegfx::BColorModifier& rTopmostModifier = maBColorModifierStack.getBColorModifier(nBColorModifierStackCount - 1); - - if(basegfx::BCOLORMODIFYMODE_REPLACE == rTopmostModifier.getMode()) + // metafiles are potentially transparent, cannot optimize, not done + break; + } + case GRAPHIC_BITMAP: + { + if(!rFillGraphicAttribute.getGraphic().IsTransparent() && !rFillGraphicAttribute.getGraphic().IsAlpha()) { - // the bitmap fill is in unified color, so we can replace it with - // a single polygon fill. The form of the fill depends on tiling - if(rFillBitmapAttribute.getTiling()) - { - // with tiling, fill the whole PolyPolygon with the modifier color - basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolyPolygon); + // bitmap is not transparent and has no alpha + const sal_uInt32 nBColorModifierStackCount(maBColorModifierStack.count()); - aLocalPolyPolygon.transform(maCurrentTransformation); - mpOutputDevice->SetLineColor(); - mpOutputDevice->SetFillColor(Color(rTopmostModifier.getBColor())); - mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon); - } - else + if(nBColorModifierStackCount) { - // without tiling, only the area common to the bitmap tile and the - // PolyPolygon is filled. Create the bitmap tile area in object - // coordinates. For this, the object transformation needs to be created - // from the already scaled PolyPolygon. The tile area in object - // coordinates wil always be non-rotated, so it's not necessary to - // work with a polygon here - basegfx::B2DRange aTileRange(rFillBitmapAttribute.getTopLeft(), - rFillBitmapAttribute.getTopLeft() + rFillBitmapAttribute.getSize()); - const basegfx::B2DRange aPolyPolygonRange(rPolyPolygon.getB2DRange()); - basegfx::B2DHomMatrix aNewObjectTransform; - - aNewObjectTransform.set(0, 0, aPolyPolygonRange.getWidth()); - aNewObjectTransform.set(1, 1, aPolyPolygonRange.getHeight()); - aNewObjectTransform.set(0, 2, aPolyPolygonRange.getMinX()); - aNewObjectTransform.set(1, 2, aPolyPolygonRange.getMinY()); - aTileRange.transform(aNewObjectTransform); - - // now clip the object polyPolygon against the tile range - // to get the common area (OR) - basegfx::B2DPolyPolygon aTarget = basegfx::tools::clipPolyPolygonOnRange(rPolyPolygon, aTileRange, true, false); - - if(aTarget.count()) + const basegfx::BColorModifier& rTopmostModifier = maBColorModifierStack.getBColorModifier(nBColorModifierStackCount - 1); + + if(basegfx::BCOLORMODIFYMODE_REPLACE == rTopmostModifier.getMode()) { - aTarget.transform(maCurrentTransformation); - mpOutputDevice->SetLineColor(); - mpOutputDevice->SetFillColor(Color(rTopmostModifier.getBColor())); - mpOutputDevice->DrawPolyPolygon(aTarget); + // the bitmap fill is in unified color, so we can replace it with + // a single polygon fill. The form of the fill depends on tiling + if(rFillGraphicAttribute.getTiling()) + { + // with tiling, fill the whole PolyPolygon with the modifier color + basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolyPolygon); + + aLocalPolyPolygon.transform(maCurrentTransformation); + mpOutputDevice->SetLineColor(); + mpOutputDevice->SetFillColor(Color(rTopmostModifier.getBColor())); + mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon); + } + else + { + // without tiling, only the area common to the bitmap tile and the + // PolyPolygon is filled. Create the bitmap tile area in object + // coordinates. For this, the object transformation needs to be created + // from the already scaled PolyPolygon. The tile area in object + // coordinates wil always be non-rotated, so it's not necessary to + // work with a polygon here + basegfx::B2DRange aTileRange(rFillGraphicAttribute.getGraphicRange()); + const basegfx::B2DRange aPolyPolygonRange(rPolyPolygon.getB2DRange()); + const basegfx::B2DHomMatrix aNewObjectTransform( + basegfx::tools::createScaleTranslateB2DHomMatrix( + aPolyPolygonRange.getRange(), + aPolyPolygonRange.getMinimum())); + + aTileRange.transform(aNewObjectTransform); + + // now clip the object polyPolygon against the tile range + // to get the common area + basegfx::B2DPolyPolygon aTarget = basegfx::tools::clipPolyPolygonOnRange( + rPolyPolygon, + aTileRange, + true, + false); + + if(aTarget.count()) + { + aTarget.transform(maCurrentTransformation); + mpOutputDevice->SetLineColor(); + mpOutputDevice->SetFillColor(Color(rTopmostModifier.getBColor())); + mpOutputDevice->DrawPolyPolygon(aTarget); + } + } + + // simplified output executed, we are done + bDone = true; } } - - bDone = true; } + break; + } + default: //GRAPHIC_NONE, GRAPHIC_DEFAULT + { + // empty graphic, we are done + bDone = true; + break; } } } - else - { - // empty polyPolygon, done - bDone = true; - } if(!bDone) { diff --git a/drawinglayer/source/processor3d/defaultprocessor3d.cxx b/drawinglayer/source/processor3d/defaultprocessor3d.cxx index aeb269f69a22..0745920b516f 100644 --- a/drawinglayer/source/processor3d/defaultprocessor3d.cxx +++ b/drawinglayer/source/processor3d/defaultprocessor3d.cxx @@ -41,6 +41,8 @@ #include <vcl/bitmapex.hxx> #include <drawinglayer/attribute/sdrsceneattribute3d.hxx> #include <drawinglayer/attribute/sdrlightingattribute3d.hxx> +#include <vcl/graph.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> ////////////////////////////////////////////////////////////////////////////// @@ -217,21 +219,33 @@ namespace drawinglayer boost::shared_ptr< texture::GeoTexSvx > pOldTex = mpGeoTexSvx; // create texture - const attribute::FillBitmapAttribute& rFillBitmapAttribute = rPrimitive.getFillBitmapAttribute(); + const attribute::FillGraphicAttribute& rFillGraphicAttribute = rPrimitive.getFillGraphicAttribute(); - if(rFillBitmapAttribute.getTiling()) + // #121194# For 3D texture we will use the BitmapRex representation + const BitmapEx aBitmapEx(rFillGraphicAttribute.getGraphic().GetBitmapEx()); + + // create range scaled by texture size + basegfx::B2DRange aGraphicRange(rFillGraphicAttribute.getGraphicRange()); + + aGraphicRange.transform( + basegfx::tools::createScaleB2DHomMatrix( + rPrimitive.getTextureSize())); + + if(rFillGraphicAttribute.getTiling()) { - mpGeoTexSvx.reset(new texture::GeoTexSvxBitmapTiled( - rFillBitmapAttribute.getBitmapEx().GetBitmap(), - rFillBitmapAttribute.getTopLeft() * rPrimitive.getTextureSize(), - rFillBitmapAttribute.getSize() * rPrimitive.getTextureSize())); + mpGeoTexSvx.reset( + new texture::GeoTexSvxBitmapExTiled( + aBitmapEx, + aGraphicRange, + rFillGraphicAttribute.getOffsetX(), + rFillGraphicAttribute.getOffsetY())); } else { - mpGeoTexSvx.reset(new texture::GeoTexSvxBitmap( - rFillBitmapAttribute.getBitmapEx().GetBitmap(), - rFillBitmapAttribute.getTopLeft() * rPrimitive.getTextureSize(), - rFillBitmapAttribute.getSize() * rPrimitive.getTextureSize())); + mpGeoTexSvx.reset( + new texture::GeoTexSvxBitmapEx( + aBitmapEx, + aGraphicRange)); } // process sub-list diff --git a/drawinglayer/source/texture/texture.cxx b/drawinglayer/source/texture/texture.cxx index acabc397f4cb..937018c7ecde 100644 --- a/drawinglayer/source/texture/texture.cxx +++ b/drawinglayer/source/texture/texture.cxx @@ -610,19 +610,16 @@ namespace drawinglayer namespace texture { GeoTexSvxTiled::GeoTexSvxTiled( - const basegfx::B2DPoint& rTopLeft, - const basegfx::B2DVector& rSize) - : maTopLeft(rTopLeft), - maSize(rSize) + const basegfx::B2DRange& rRange, + double fOffsetX, + double fOffsetY) + : maRange(rRange), + mfOffsetX(basegfx::clamp(fOffsetX, 0.0, 1.0)), + mfOffsetY(basegfx::clamp(fOffsetY, 0.0, 1.0)) { - if(basegfx::fTools::lessOrEqual(maSize.getX(), 0.0)) - { - maSize.setX(1.0); - } - - if(basegfx::fTools::lessOrEqual(maSize.getY(), 0.0)) + if(!basegfx::fTools::equalZero(mfOffsetX)) { - maSize.setY(1.0); + mfOffsetY = 0.0; } } @@ -633,48 +630,92 @@ namespace drawinglayer bool GeoTexSvxTiled::operator==(const GeoTexSvx& rGeoTexSvx) const { const GeoTexSvxTiled* pCompare = dynamic_cast< const GeoTexSvxTiled* >(&rGeoTexSvx); + return (pCompare - && maTopLeft == pCompare->maTopLeft - && maSize == pCompare->maSize); + && maRange == pCompare->maRange + && mfOffsetX == pCompare->mfOffsetX + && mfOffsetY == pCompare->mfOffsetY); } void GeoTexSvxTiled::appendTransformations(::std::vector< basegfx::B2DHomMatrix >& rMatrices) { - double fStartX(maTopLeft.getX()); - double fStartY(maTopLeft.getY()); + const double fWidth(maRange.getWidth()); - if(basegfx::fTools::more(fStartX, 0.0)) + if(!basegfx::fTools::equalZero(fWidth)) { - fStartX -= (floor(fStartX / maSize.getX()) + 1.0) * maSize.getX(); - } - - if(basegfx::fTools::less(fStartX + maSize.getX(), 0.0)) - { - fStartX += floor(-fStartX / maSize.getX()) * maSize.getX(); - } + const double fHeight(maRange.getHeight()); - if(basegfx::fTools::more(fStartY, 0.0)) - { - fStartY -= (floor(fStartY / maSize.getY()) + 1.0) * maSize.getY(); - } - - if(basegfx::fTools::less(fStartY + maSize.getY(), 0.0)) - { - fStartY += floor(-fStartY / maSize.getY()) * maSize.getY(); - } - - for(double fPosY(fStartY); basegfx::fTools::less(fPosY, 1.0); fPosY += maSize.getY()) - { - for(double fPosX(fStartX); basegfx::fTools::less(fPosX, 1.0); fPosX += maSize.getX()) + if(!basegfx::fTools::equalZero(fHeight)) { - basegfx::B2DHomMatrix aNew; - - aNew.set(0, 0, maSize.getX()); - aNew.set(1, 1, maSize.getY()); - aNew.set(0, 2, fPosX); - aNew.set(1, 2, fPosY); - - rMatrices.push_back(aNew); + double fStartX(maRange.getMinX()); + double fStartY(maRange.getMinY()); + sal_Int32 nPosX(0); + sal_Int32 nPosY(0); + + if(basegfx::fTools::more(fStartX, 0.0)) + { + const sal_Int32 nDiff(static_cast<sal_Int32>(floor(fStartX / fWidth)) + 1); + + nPosX -= nDiff; + fStartX -= nDiff * fWidth; + } + + if(basegfx::fTools::less(fStartX + fWidth, 0.0)) + { + const sal_Int32 nDiff(static_cast<sal_Int32>(floor(-fStartX / fWidth))); + + nPosX += nDiff; + fStartX += nDiff * fWidth; + } + + if(basegfx::fTools::more(fStartY, 0.0)) + { + const sal_Int32 nDiff(static_cast<sal_Int32>(floor(fStartY / fHeight)) + 1); + + nPosY -= nDiff; + fStartY -= nDiff * fHeight; + } + + if(basegfx::fTools::less(fStartY + fHeight, 0.0)) + { + const sal_Int32 nDiff(static_cast<sal_Int32>(floor(-fStartY / fHeight))); + + nPosY += nDiff; + fStartY += nDiff * fHeight; + } + + if(!basegfx::fTools::equalZero(mfOffsetY)) + { + for(double fPosX(fStartX); basegfx::fTools::less(fPosX, 1.0); fPosX += fWidth, nPosX++) + { + for(double fPosY(nPosX % 2 ? fStartY - fHeight + (mfOffsetY * fHeight) : fStartY); + basegfx::fTools::less(fPosY, 1.0); fPosY += fHeight) + { + rMatrices.push_back( + basegfx::tools::createScaleTranslateB2DHomMatrix( + fWidth, + fHeight, + fPosX, + fPosY)); + } + } + } + else + { + for(double fPosY(fStartY); basegfx::fTools::less(fPosY, 1.0); fPosY += fHeight, nPosY++) + { + for(double fPosX(nPosY % 2 ? fStartX - fWidth + (mfOffsetX * fWidth) : fStartX); + basegfx::fTools::less(fPosX, 1.0); fPosX += fWidth) + { + rMatrices.push_back( + basegfx::tools::createScaleTranslateB2DHomMatrix( + fWidth, + fHeight, + fPosX, + fPosY)); + } + } + } } } } diff --git a/drawinglayer/source/texture/texture3d.cxx b/drawinglayer/source/texture/texture3d.cxx index 3f10cd0d50f5..27cd94984953 100644 --- a/drawinglayer/source/texture/texture3d.cxx +++ b/drawinglayer/source/texture/texture3d.cxx @@ -34,7 +34,9 @@ namespace drawinglayer { namespace texture { - GeoTexSvxMono::GeoTexSvxMono(const basegfx::BColor& rSingleColor, double fOpacity) + GeoTexSvxMono::GeoTexSvxMono( + const basegfx::BColor& rSingleColor, + double fOpacity) : maSingleColor(rSingleColor), mfOpacity(fOpacity) { @@ -43,6 +45,7 @@ namespace drawinglayer bool GeoTexSvxMono::operator==(const GeoTexSvx& rGeoTexSvx) const { const GeoTexSvxMono* pCompare = dynamic_cast< const GeoTexSvxMono* >(&rGeoTexSvx); + return (pCompare && maSingleColor == pCompare->maSingleColor && mfOpacity == pCompare->mfOpacity); @@ -66,56 +69,144 @@ namespace drawinglayer { namespace texture { - GeoTexSvxBitmap::GeoTexSvxBitmap(const Bitmap& rBitmap, const basegfx::B2DPoint& rTopLeft, const basegfx::B2DVector& rSize) - : maBitmap(rBitmap), - mpRead(0L), - maTopLeft(rTopLeft), - maSize(rSize), + GeoTexSvxBitmapEx::GeoTexSvxBitmapEx( + const BitmapEx& rBitmapEx, + const basegfx::B2DRange& rRange) + : maBitmapEx(rBitmapEx), + mpReadBitmap(0), + maTransparence(), + mpReadTransparence(0), + maTopLeft(rRange.getMinimum()), + maSize(rRange.getRange()), mfMulX(0.0), - mfMulY(0.0) + mfMulY(0.0), + mbIsAlpha(false), + mbIsTransparent(maBitmapEx.IsTransparent()) + { + // #121194# Todo: use alpha channel, too (for 3d) + mpReadBitmap = maBitmapEx.GetBitmap().AcquireReadAccess(); + OSL_ENSURE(mpReadBitmap, "GeoTexSvxBitmapEx: Got no read access to Bitmap (!)"); + + if(mbIsTransparent) + { + if(maBitmapEx.IsAlpha()) + { + mbIsAlpha = true; + maTransparence = rBitmapEx.GetAlpha().GetBitmap(); + } + else + { + maTransparence = rBitmapEx.GetMask(); + } + + mpReadTransparence = maTransparence.AcquireReadAccess(); + } + + mfMulX = (double)mpReadBitmap->Width() / maSize.getX(); + mfMulY = (double)mpReadBitmap->Height() / maSize.getY(); + + if(maSize.getX() <= 1.0) + { + maSize.setX(1.0); + } + + if(maSize.getY() <= 1.0) + { + maSize.setY(1.0); + } + } + + GeoTexSvxBitmapEx::~GeoTexSvxBitmapEx() { - mpRead = maBitmap.AcquireReadAccess(); - OSL_ENSURE(mpRead, "GeoTexSvxBitmap: Got no read access to Bitmap (!)"); - mfMulX = (double)mpRead->Width() / maSize.getX(); - mfMulY = (double)mpRead->Height() / maSize.getY(); + delete mpReadTransparence; + delete mpReadBitmap; } - GeoTexSvxBitmap::~GeoTexSvxBitmap() + sal_uInt8 GeoTexSvxBitmapEx::impGetTransparence(sal_Int32& rX, sal_Int32& rY) const { - delete mpRead; + switch(maBitmapEx.GetTransparentType()) + { + case TRANSPARENT_NONE: + { + break; + } + case TRANSPARENT_COLOR: + { + const Color aColor(mpReadBitmap->GetColor(rY, rX)); + + if(maBitmapEx.GetTransparentColor() == aColor) + { + return 255; + } + + break; + } + case TRANSPARENT_BITMAP: + { + OSL_ENSURE(mpReadTransparence, "OOps, transparence type Bitmap, but no read access created in the constructor (?)"); + const BitmapColor aBitmapColor(mpReadTransparence->GetPixel(rY, rX)); + + if(mbIsAlpha) + { + return aBitmapColor.GetIndex(); + } + else + { + if(0x00 != aBitmapColor.GetIndex()) + { + return 255; + } + } + break; + } + } + + return 0; } - bool GeoTexSvxBitmap::impIsValid(const basegfx::B2DPoint& rUV, sal_Int32& rX, sal_Int32& rY) const + bool GeoTexSvxBitmapEx::impIsValid(const basegfx::B2DPoint& rUV, sal_Int32& rX, sal_Int32& rY) const { - if(mpRead) + if(mpReadBitmap) { rX = (sal_Int32)((rUV.getX() - maTopLeft.getX()) * mfMulX); - if(rX >= 0L && rX < mpRead->Width()) + if(rX >= 0L && rX < mpReadBitmap->Width()) { rY = (sal_Int32)((rUV.getY() - maTopLeft.getY()) * mfMulY); - return (rY >= 0L && rY < mpRead->Height()); + return (rY >= 0L && rY < mpReadBitmap->Height()); } } return false; } - void GeoTexSvxBitmap::modifyBColor(const basegfx::B2DPoint& rUV, basegfx::BColor& rBColor, double& rfOpacity) const + void GeoTexSvxBitmapEx::modifyBColor(const basegfx::B2DPoint& rUV, basegfx::BColor& rBColor, double& rfOpacity) const { sal_Int32 nX, nY; if(impIsValid(rUV, nX, nY)) { const double fConvertColor(1.0 / 255.0); - const BitmapColor aBMCol(mpRead->GetColor(nY, nX)); + const BitmapColor aBMCol(mpReadBitmap->GetColor(nY, nX)); const basegfx::BColor aBSource( (double)aBMCol.GetRed() * fConvertColor, (double)aBMCol.GetGreen() * fConvertColor, (double)aBMCol.GetBlue() * fConvertColor); rBColor = aBSource; + + if(mbIsTransparent) + { + // when we have a transparence, make use of it + const sal_uInt8 aLuminance(impGetTransparence(nX, nY)); + + rfOpacity = ((double)(0xff - aLuminance) * (1.0 / 255.0)); + } + else + { + rfOpacity = 1.0; + } } else { @@ -123,16 +214,28 @@ namespace drawinglayer } } - void GeoTexSvxBitmap::modifyOpacity(const basegfx::B2DPoint& rUV, double& rfOpacity) const + void GeoTexSvxBitmapEx::modifyOpacity(const basegfx::B2DPoint& rUV, double& rfOpacity) const { sal_Int32 nX, nY; if(impIsValid(rUV, nX, nY)) { - const BitmapColor aBMCol(mpRead->GetColor(nY, nX)); - const Color aColor(aBMCol.GetRed(), aBMCol.GetGreen(), aBMCol.GetBlue()); + if(mbIsTransparent) + { + // this texture has an alpha part, use it + const sal_uInt8 aLuminance(impGetTransparence(nX, nY)); + const double fNewOpacity((double)(0xff - aLuminance) * (1.0 / 255.0)); + + rfOpacity = 1.0 - ((1.0 - fNewOpacity) * (1.0 - rfOpacity)); + } + else + { + // this texture is a color bitmap used as transparence map + const BitmapColor aBMCol(mpReadBitmap->GetColor(nY, nX)); + const Color aColor(aBMCol.GetRed(), aBMCol.GetGreen(), aBMCol.GetBlue()); - rfOpacity = ((double)(0xff - aColor.GetLuminance()) * (1.0 / 255.0)); + rfOpacity = ((double)(0xff - aColor.GetLuminance()) * (1.0 / 255.0)); + } } else { @@ -148,24 +251,72 @@ namespace drawinglayer { namespace texture { - GeoTexSvxBitmapTiled::GeoTexSvxBitmapTiled(const Bitmap& rBitmap, const basegfx::B2DPoint& rTopLeft, const basegfx::B2DVector& rSize) - : GeoTexSvxBitmap(rBitmap, rTopLeft, rSize) + basegfx::B2DPoint GeoTexSvxBitmapExTiled::impGetCorrected(const basegfx::B2DPoint& rUV) const + { + double fX(rUV.getX() - maTopLeft.getX()); + double fY(rUV.getY() - maTopLeft.getY()); + + if(mbUseOffsetX) + { + const sal_Int32 nCol(static_cast< sal_Int32 >((fY < 0.0 ? maSize.getY() -fY : fY) / maSize.getY())); + + if(nCol % 2) + { + fX += mfOffsetX * maSize.getX(); + } + } + else if(mbUseOffsetY) + { + const sal_Int32 nRow(static_cast< sal_Int32 >((fX < 0.0 ? maSize.getX() -fX : fX) / maSize.getX())); + + if(nRow % 2) + { + fY += mfOffsetY * maSize.getY(); + } + } + + fX = fmod(fX, maSize.getX()); + fY = fmod(fY, maSize.getY()); + + if(fX < 0.0) + { + fX += maSize.getX(); + } + + if(fY < 0.0) + { + fY += maSize.getY(); + } + + return basegfx::B2DPoint(fX + maTopLeft.getX(), fY + maTopLeft.getY()); + } + + GeoTexSvxBitmapExTiled::GeoTexSvxBitmapExTiled( + const BitmapEx& rBitmapEx, + const basegfx::B2DRange& rRange, + double fOffsetX, + double fOffsetY) + : GeoTexSvxBitmapEx(rBitmapEx, rRange), + mfOffsetX(basegfx::clamp(fOffsetX, 0.0, 1.0)), + mfOffsetY(basegfx::clamp(fOffsetY, 0.0, 1.0)), + mbUseOffsetX(!basegfx::fTools::equalZero(mfOffsetX)), + mbUseOffsetY(!mbUseOffsetX && !basegfx::fTools::equalZero(mfOffsetY)) { } - void GeoTexSvxBitmapTiled::modifyBColor(const basegfx::B2DPoint& rUV, basegfx::BColor& rBColor, double& rfOpacity) const + void GeoTexSvxBitmapExTiled::modifyBColor(const basegfx::B2DPoint& rUV, basegfx::BColor& rBColor, double& rfOpacity) const { - if(mpRead) + if(mpReadBitmap) { - GeoTexSvxBitmap::modifyBColor(impGetCorrected(rUV), rBColor, rfOpacity); + GeoTexSvxBitmapEx::modifyBColor(impGetCorrected(rUV), rBColor, rfOpacity); } } - void GeoTexSvxBitmapTiled::modifyOpacity(const basegfx::B2DPoint& rUV, double& rfOpacity) const + void GeoTexSvxBitmapExTiled::modifyOpacity(const basegfx::B2DPoint& rUV, double& rfOpacity) const { - if(mpRead) + if(mpReadBitmap) { - GeoTexSvxBitmap::modifyOpacity(impGetCorrected(rUV), rfOpacity); + GeoTexSvxBitmapEx::modifyOpacity(impGetCorrected(rUV), rfOpacity); } } } // end of namespace texture @@ -177,7 +328,9 @@ namespace drawinglayer { namespace texture { - GeoTexSvxMultiHatch::GeoTexSvxMultiHatch(const primitive3d::HatchTexturePrimitive3D& rPrimitive, double fLogicPixelSize) + GeoTexSvxMultiHatch::GeoTexSvxMultiHatch( + const primitive3d::HatchTexturePrimitive3D& rPrimitive, + double fLogicPixelSize) : mfLogicPixelSize(fLogicPixelSize), mp0(0L), mp1(0L), |