diff options
author | Armin Le Grand <alg@apache.org> | 2011-12-19 15:41:21 +0000 |
---|---|---|
committer | Armin Le Grand <alg@apache.org> | 2011-12-19 15:41:21 +0000 |
commit | e2e16715893229b5d0ad2da6c8e84464e0c43a2e (patch) | |
tree | 79d1c632784b3de16fc82c1dfc27c1796a9ef451 /drawinglayer/source | |
parent | ea4f454ed956e08be47783b3bddd7789f905e350 (diff) |
Svg: Reintegrated Svg replacement from /branches/alg/svgreplavement to trunk, first version of Svg stable and done
Diffstat (limited to 'drawinglayer/source')
18 files changed, 2458 insertions, 330 deletions
diff --git a/drawinglayer/source/drawinglayeruno/drawinglayeruno.cxx b/drawinglayer/source/drawinglayeruno/drawinglayeruno.cxx new file mode 100644 index 000000000000..8ead3d1023b9 --- /dev/null +++ b/drawinglayer/source/drawinglayeruno/drawinglayeruno.cxx @@ -0,0 +1,95 @@ +/************************************************************** + * + * 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/drawinglayerdllapi.h> +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/uno/RuntimeException.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/registry/XRegistryKey.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <uno/environment.h> +#include <cppuhelper/factory.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace ::com::sun::star; + +////////////////////////////////////////////////////////////////////////////// +// predefines + +namespace drawinglayer +{ + namespace unorenderer + { + extern uno::Sequence< rtl::OUString > SAL_CALL XPrimitive2DRenderer_getSupportedServiceNames(); + extern rtl::OUString SAL_CALL XPrimitive2DRenderer_getImplementationName(); + extern uno::Reference< uno::XInterface > SAL_CALL XPrimitive2DRenderer_createInstance( const uno::Reference< lang::XMultiServiceFactory > & ); + } // end of namespace unorenderer +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// component_getImplementationEnvironment + +extern "C" +{ + DRAWINGLAYER_DLLPUBLIC void SAL_CALL component_getImplementationEnvironment( const sal_Char ** ppEnvTypeName, uno_Environment ** /* ppEnv */ ) + { + *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; + } +} + +////////////////////////////////////////////////////////////////////////////// +// component_getFactory + +extern "C" +{ + DRAWINGLAYER_DLLPUBLIC void* SAL_CALL component_getFactory( const sal_Char* pImplName, void* pServiceManager, void* /* pRegistryKey */ ) + { + uno::Reference< lang::XSingleServiceFactory > xFactory; + void* pRet = 0; + + if(drawinglayer::unorenderer::XPrimitive2DRenderer_getImplementationName().equalsAscii(pImplName)) + { + xFactory = ::cppu::createSingleFactory( + reinterpret_cast< lang::XMultiServiceFactory * >(pServiceManager), + drawinglayer::unorenderer::XPrimitive2DRenderer_getImplementationName(), + drawinglayer::unorenderer::XPrimitive2DRenderer_createInstance, + drawinglayer::unorenderer::XPrimitive2DRenderer_getSupportedServiceNames()); + } + + if(xFactory.is()) + { + xFactory->acquire(); + pRet = xFactory.get(); + } + + return pRet; + } +} + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/drawinglayeruno/xprimitive2drenderer.cxx b/drawinglayer/source/drawinglayeruno/xprimitive2drenderer.cxx new file mode 100644 index 000000000000..c6667ad2319f --- /dev/null +++ b/drawinglayer/source/drawinglayeruno/xprimitive2drenderer.cxx @@ -0,0 +1,223 @@ +/************************************************************** + * + * 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 <com/sun/star/graphic/XPrimitive2DRenderer.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <cppuhelper/implbase2.hxx> +#include <com/sun/star/xml/sax/XParser.hpp> +#include <com/sun/star/xml/sax/InputSource.hpp> +#include <comphelper/processfactory.hxx> +#include <drawinglayer/geometry/viewinformation2d.hxx> +#include <basegfx/numeric/ftools.hxx> +#include <vcl/bitmapex.hxx> +#include <drawinglayer/tools/converters.hxx> +#include <vcl/canvastools.hxx> +#include <com/sun/star/geometry/RealRectangle2D.hpp> +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <drawinglayer/primitive2d/transformprimitive2d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace ::com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace unorenderer + { + class XPrimitive2DRenderer : public ::cppu::WeakAggImplHelper2< graphic::XPrimitive2DRenderer, lang::XServiceInfo > + { + private: + XPrimitive2DRenderer(const XPrimitive2DRenderer&); + XPrimitive2DRenderer& operator=(const XPrimitive2DRenderer&); + + protected: + public: + XPrimitive2DRenderer(); + virtual ~XPrimitive2DRenderer(); + + // XPrimitive2DRenderer + virtual uno::Reference< rendering::XBitmap > SAL_CALL rasterize( + const uno::Sequence< uno::Reference< graphic::XPrimitive2D > >& Primitive2DSequence, + const uno::Sequence< beans::PropertyValue >& aViewInformationSequence, + ::sal_uInt32 DPI_X, + ::sal_uInt32 DPI_Y, + const ::com::sun::star::geometry::RealRectangle2D& Range, + ::sal_uInt32 MaximumQuadraticPixels) throw (uno::RuntimeException); + + // XServiceInfo + virtual rtl::OUString SAL_CALL getImplementationName() throw(uno::RuntimeException); + virtual ::sal_Bool SAL_CALL supportsService(const rtl::OUString&) throw(uno::RuntimeException); + virtual uno::Sequence< rtl::OUString > SAL_CALL getSupportedServiceNames() throw(uno::RuntimeException); + }; + } // end of namespace unorenderer +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// uno functions + +namespace drawinglayer +{ + namespace unorenderer + { + uno::Sequence< rtl::OUString > XPrimitive2DRenderer_getSupportedServiceNames() + { + static rtl::OUString aServiceName(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.graphic.Primitive2DTools" ) ); + static uno::Sequence< rtl::OUString > aServiceNames( &aServiceName, 1 ); + + return( aServiceNames ); + } + + rtl::OUString XPrimitive2DRenderer_getImplementationName() + { + return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "drawinglayer::unorenderer::XPrimitive2DRenderer" ) ); + } + + uno::Reference< uno::XInterface > SAL_CALL XPrimitive2DRenderer_createInstance(const uno::Reference< lang::XMultiServiceFactory >&) + { + return static_cast< ::cppu::OWeakObject* >(new XPrimitive2DRenderer); + } + } // end of namespace unorenderer +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace unorenderer + { + XPrimitive2DRenderer::XPrimitive2DRenderer() + { + } + + XPrimitive2DRenderer::~XPrimitive2DRenderer() + { + } + + uno::Reference< rendering::XBitmap > XPrimitive2DRenderer::rasterize( + const uno::Sequence< uno::Reference< graphic::XPrimitive2D > >& Primitive2DSequence, + const uno::Sequence< beans::PropertyValue >& aViewInformationSequence, + ::sal_uInt32 DPI_X, + ::sal_uInt32 DPI_Y, + const ::com::sun::star::geometry::RealRectangle2D& Range, + ::sal_uInt32 MaximumQuadraticPixels) throw (uno::RuntimeException) + { + uno::Reference< rendering::XBitmap > XBitmap; + + if(Primitive2DSequence.hasElements()) + { + const basegfx::B2DRange aRange(Range.X1, Range.Y1, Range.X2, Range.Y2); + const double fWidth(aRange.getWidth()); + const double fHeight(aRange.getHeight()); + + if(basegfx::fTools::more(fWidth, 0.0) && basegfx::fTools::more(fHeight, 0.0)) + { + if(0 == DPI_X) + { + DPI_X = 75; + } + + if(0 == DPI_Y) + { + DPI_Y = 75; + } + + if(0 == MaximumQuadraticPixels) + { + MaximumQuadraticPixels = 500000; + } + + const geometry::ViewInformation2D aViewInformation2D(aViewInformationSequence); + const double fFactor100th_mmToInch(2.54/1000.0); + const sal_uInt32 nDiscreteWidth(basegfx::fround((fWidth * fFactor100th_mmToInch) * DPI_X)); + const sal_uInt32 nDiscreteHeight(basegfx::fround((fHeight * fFactor100th_mmToInch) * DPI_Y)); + + basegfx::B2DHomMatrix aEmbedding( + basegfx::tools::createTranslateB2DHomMatrix( + -aRange.getMinX(), + -aRange.getMinY())); + + aEmbedding.scale( + nDiscreteWidth / fWidth, + nDiscreteHeight / fHeight); + + const primitive2d::Primitive2DReference xEmbedRef( + new primitive2d::TransformPrimitive2D( + aEmbedding, + Primitive2DSequence)); + const primitive2d::Primitive2DSequence xEmbedSeq(&xEmbedRef, 1); + + BitmapEx aBitmapEx( + tools::convertToBitmapEx( + xEmbedSeq, + aViewInformation2D, + nDiscreteWidth, + nDiscreteHeight, + MaximumQuadraticPixels)); + + if(!aBitmapEx.IsEmpty()) + { + const uno::Reference< rendering::XGraphicDevice > xGraphicDevice; + + aBitmapEx.SetPrefMapMode(MapMode(MAP_100TH_MM)); + aBitmapEx.SetPrefSize(Size(basegfx::fround(fWidth), basegfx::fround(fHeight))); + XBitmap = vcl::unotools::xBitmapFromBitmapEx(xGraphicDevice, aBitmapEx); + } + } + } + + return XBitmap; + } + + rtl::OUString SAL_CALL XPrimitive2DRenderer::getImplementationName() throw(uno::RuntimeException) + { + return(XPrimitive2DRenderer_getImplementationName()); + } + + sal_Bool SAL_CALL XPrimitive2DRenderer::supportsService(const rtl::OUString& rServiceName) throw(uno::RuntimeException) + { + const uno::Sequence< rtl::OUString > aServices(XPrimitive2DRenderer_getSupportedServiceNames()); + + for(sal_Int32 nService(0); nService < aServices.getLength(); nService++) + { + if(rServiceName == aServices[nService]) + { + return sal_True; + } + } + + return sal_False; + } + + uno::Sequence< rtl::OUString > SAL_CALL XPrimitive2DRenderer::getSupportedServiceNames() throw(uno::RuntimeException) + { + return XPrimitive2DRenderer_getSupportedServiceNames(); + } + + } // end of namespace unorenderer +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive2d/baseprimitive2d.cxx b/drawinglayer/source/primitive2d/baseprimitive2d.cxx index 8f5d7b14a157..868305b45208 100644 --- a/drawinglayer/source/primitive2d/baseprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/baseprimitive2d.cxx @@ -115,6 +115,27 @@ namespace drawinglayer { namespace primitive2d { + // convert helper stl vector of primitives to Primitive2DSequence + Primitive2DSequence Primitive2DVectorToPrimitive2DSequence(const Primitive2DVector& rSource, bool bInvert) + { + const sal_uInt32 nSize(rSource.size()); + Primitive2DSequence aRetval; + + aRetval.realloc(nSize); + + for(sal_uInt32 a(0); a < nSize; a++) + { + aRetval[bInvert ? nSize - 1 - a : a] = rSource[a]; + } + + // all entries taken over to Uno References as owners. To avoid + // errors with users of this mechanism to delete pointers to BasePrimitive2D + // itself, clear given vector + const_cast< Primitive2DVector& >(rSource).clear(); + + return aRetval; + } + // get B2DRange from a given Primitive2DReference basegfx::B2DRange getB2DRangeFromPrimitive2DReference(const Primitive2DReference& rCandidate, const geometry::ViewInformation2D& aViewInformation) { diff --git a/drawinglayer/source/primitive2d/cropprimitive2d.cxx b/drawinglayer/source/primitive2d/cropprimitive2d.cxx new file mode 100644 index 000000000000..f4b6e82b9df0 --- /dev/null +++ b/drawinglayer/source/primitive2d/cropprimitive2d.cxx @@ -0,0 +1,202 @@ +/************************************************************** + * + * 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/cropprimitive2d.hxx> +#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <drawinglayer/primitive2d/transformprimitive2d.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <drawinglayer/primitive2d/maskprimitive2d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive2d + { + CropPrimitive2D::CropPrimitive2D( + const Primitive2DSequence& rChildren, + const basegfx::B2DHomMatrix& rTransformation, + double fCropLeft, + double fCropTop, + double fCropRight, + double fCropBottom) + : GroupPrimitive2D(rChildren), + maTransformation(rTransformation), + mfCropLeft(fCropLeft), + mfCropTop(fCropTop), + mfCropRight(fCropRight), + mfCropBottom(fCropBottom) + { + } + + bool CropPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + { + if(GroupPrimitive2D::operator==(rPrimitive)) + { + const CropPrimitive2D& rCompare = static_cast< const CropPrimitive2D& >(rPrimitive); + + return (getTransformation() == rCompare.getTransformation() + && getCropLeft() == rCompare.getCropLeft() + && getCropTop() == rCompare.getCropTop() + && getCropRight() == rCompare.getCropRight() + && getCropBottom() == rCompare.getCropBottom()); + } + + return false; + } + + Primitive2DSequence CropPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const + { + Primitive2DSequence xRetval; + + if(getChildren().hasElements()) + { + // decompose to have current translate and scale + basegfx::B2DVector aScale, aTranslate; + double fRotate, fShearX; + + getTransformation().decompose(aScale, aTranslate, fRotate, fShearX); + + // detect 180 degree rotation, this is the same as mirrored in X and Y, + // thus change to mirroring. Prefer mirroring here. Use the equal call + // with getSmallValue here, the original which uses rtl::math::approxEqual + // is too correct here. Maybe this changes with enhanced precision in aw080 + // to the better so that this can be reduced to the more precise call again + if(basegfx::fTools::equal(fRotate, F_PI, 0.000000001)) + { + aScale.setX(aScale.getX() * -1.0); + aScale.setY(aScale.getY() * -1.0); + fRotate = 0.0; + } + + // create target translate and scale + const bool bMirroredX(aScale.getX() < 0.0); + const bool bMirroredY(aScale.getY() < 0.0); + basegfx::B2DVector aTargetScale(aScale); + basegfx::B2DVector aTargetTranslate(aTranslate); + + if(bMirroredX) + { + aTargetTranslate.setX(aTargetTranslate.getX() + getCropRight()); + aTargetScale.setX(aTargetScale.getX() - getCropLeft() - getCropRight()); + } + else + { + aTargetTranslate.setX(aTargetTranslate.getX() - getCropLeft()); + aTargetScale.setX(aTargetScale.getX() + getCropRight() + getCropLeft()); + } + + if(bMirroredY) + { + aTargetTranslate.setY(aTargetTranslate.getY() + getCropBottom()); + aTargetScale.setY(aTargetScale.getY() - getCropTop() - getCropBottom()); + } + else + { + aTargetTranslate.setY(aTargetTranslate.getY() - getCropTop()); + aTargetScale.setY(aTargetScale.getY() + getCropBottom() + getCropTop()); + } + + // create ranges to make comparisons + const basegfx::B2DRange aCurrent( + aTranslate.getX(), aTranslate.getY(), + aTranslate.getX() + aScale.getX(), aTranslate.getY() + aScale.getY()); + const basegfx::B2DRange aCropped( + aTargetTranslate.getX(), aTargetTranslate.getY(), + aTargetTranslate.getX() + aTargetScale.getX(), aTargetTranslate.getY() + aTargetScale.getY()); + + if(aCropped.isEmpty()) + { + // nothing to return since cropped content is completely empty + } + else if(aCurrent.equal(aCropped)) + { + // no crop, just use content + xRetval = getChildren(); + } + else + { + // build new combined content transformation + basegfx::B2DHomMatrix aNewObjectTransform(getTransformation()); + + // remove content transform by inverting + aNewObjectTransform.invert(); + + // add target values and original shear/rotate + aNewObjectTransform = basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix( + aTargetScale.getX(), + aTargetScale.getY(), + fShearX, + fRotate, + aTargetTranslate.getX(), + aTargetTranslate.getY()) + * aNewObjectTransform; + + // prepare TransformPrimitive2D with xPrimitive + const Primitive2DReference xTransformPrimitive( + new TransformPrimitive2D( + aNewObjectTransform, + getChildren())); + + if(aCurrent.isInside(aCropped)) + { + // crop just shrunk so that its inside content, + // no need to use a mask since not really cropped. + xRetval = Primitive2DSequence(&xTransformPrimitive, 1); + } + else + { + // mask with original object's bounds + basegfx::B2DPolyPolygon aMaskPolyPolygon(basegfx::tools::createUnitPolygon()); + aMaskPolyPolygon.transform(getTransformation()); + + // create maskPrimitive with aMaskPolyPolygon and aMaskContentVector + const Primitive2DReference xMask( + new MaskPrimitive2D( + aMaskPolyPolygon, + Primitive2DSequence(&xTransformPrimitive, 1))); + + xRetval = Primitive2DSequence(&xMask, 1); + } + } + } + + return xRetval; + } + + // provide unique ID + ImplPrimitrive2DIDBlock(CropPrimitive2D, PRIMITIVE2D_ID_CROPPRIMITIVE2D) + + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive2d/graphicprimitive2d.cxx b/drawinglayer/source/primitive2d/graphicprimitive2d.cxx index f7a3930610d1..0703f9225b45 100644 --- a/drawinglayer/source/primitive2d/graphicprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/graphicprimitive2d.cxx @@ -27,14 +27,14 @@ #include <drawinglayer/primitive2d/graphicprimitive2d.hxx> #include <drawinglayer/animation/animationtiming.hxx> #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> -#include <drawinglayer/primitive2d/rendergraphicprimitive2d.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/maskprimitive2d.hxx> +#include <drawinglayer/primitive2d/cropprimitive2d.hxx> #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> +#include <drawinglayer/primitive2d/maskprimitive2d.hxx> ////////////////////////////////////////////////////////////////////////////// // helper class for animated graphics @@ -259,8 +259,8 @@ namespace drawinglayer aSuppressGraphicAttr.SetRotation(0); aSuppressGraphicAttr.SetMirrorFlags(0); - const GraphicObject& rGraphicObject = getGraphicObject(); - const Graphic aTransformedGraphic(rGraphicObject.GetTransformedGraphic(&aSuppressGraphicAttr)); + const GraphicObject& rGraphicObject = getGraphicObject(); + const Graphic aTransformedGraphic(rGraphicObject.GetTransformedGraphic(&aSuppressGraphicAttr)); switch(aTransformedGraphic.GetType()) { @@ -293,6 +293,32 @@ namespace drawinglayer 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()); + + // 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)); @@ -745,41 +771,31 @@ namespace drawinglayer // create MetafilePrimitive2D const GDIMetaFile& rMetafile = aTransformedGraphic.GetGDIMetaFile(); - if( aTransformedGraphic.IsRenderGraphic() ) + 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 RenderGraphicPrimitive2D( - static_cast< MetaRenderGraphicAction* >(rMetafile.GetAction(0))->GetRenderGraphic(), - aTransform)); - } - else - { - 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)); - } + new MaskPrimitive2D( + basegfx::B2DPolyPolygon(aMaskPolygon), + aChildContent)); } #ifdef USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE } @@ -800,16 +816,6 @@ namespace drawinglayer // check for cropping if(getGraphicAttr().IsCropped()) { - // decompose to get current pos and size - basegfx::B2DVector aScale, aTranslate; - double fRotate, fShearX; - getTransform().decompose(aScale, aTranslate, fRotate, fShearX); - - // create ranges. The current object range is just scale and translate - const basegfx::B2DRange aCurrent( - aTranslate.getX(), aTranslate.getY(), - aTranslate.getX() + aScale.getX(), aTranslate.getY() + aScale.getY()); - // 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); @@ -831,68 +837,31 @@ namespace drawinglayer const double fDivX(aBitmapSize.Width() - getGraphicAttr().GetLeftCrop() - getGraphicAttr().GetRightCrop()); const double fDivY(aBitmapSize.Height() - getGraphicAttr().GetTopCrop() - getGraphicAttr().GetBottomCrop()); + const basegfx::B2DVector aScale(aTransform * basegfx::B2DVector(1.0, 1.0)); if(!basegfx::fTools::equalZero(fDivX)) { - fFactorX = aScale.getX() / fDivX; + fFactorX = fabs(aScale.getX()) / fDivX; } if(!basegfx::fTools::equalZero(fDivY)) { - fFactorY = aScale.getY() / fDivY; + fFactorY = fabs(aScale.getY()) / fDivY; } } - // Create cropped range, describes the bounds of the original graphic - basegfx::B2DRange aCropped; - aCropped.expand(aCurrent.getMinimum() - basegfx::B2DPoint(getGraphicAttr().GetLeftCrop() * fFactorX, getGraphicAttr().GetTopCrop() * fFactorY)); - aCropped.expand(aCurrent.getMaximum() + basegfx::B2DPoint(getGraphicAttr().GetRightCrop() * fFactorX, getGraphicAttr().GetBottomCrop() * fFactorY)); - - if(aCropped.isEmpty()) - { - // nothing to add since cropped bitmap is completely empty - // xPrimitive will not be used - } - else - { - // build new object transformation for transform primitive which contains xPrimitive - basegfx::B2DHomMatrix aNewObjectTransform(getTransform()); - aNewObjectTransform.invert(); - aNewObjectTransform = basegfx::tools::createScaleTranslateB2DHomMatrix( - aCropped.getWidth(), aCropped.getHeight(), - aCropped.getMinX() - aCurrent.getMinX(), aCropped.getMinY() - aCurrent.getMinY()) - * aNewObjectTransform; - - // add shear, rotate and translate using combined matrix to speedup - const basegfx::B2DHomMatrix aCombinedMatrix(basegfx::tools::createShearXRotateTranslateB2DHomMatrix( - fShearX, fRotate, aTranslate.getX(), aTranslate.getY())); - aNewObjectTransform = aCombinedMatrix * aNewObjectTransform; - - // prepare TransformPrimitive2D with xPrimitive - const Primitive2DReference xTransformPrimitive(new TransformPrimitive2D(aNewObjectTransform, Primitive2DSequence(&xPrimitive, 1L))); - - if(aCurrent.isInside(aCropped)) - { - // cropped just got smaller, no need to really use a mask. Add to destination directly - appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, xTransformPrimitive); - } - else - { - // cropped got bigger, mask it with original object's bounds - basegfx::B2DPolyPolygon aMaskPolyPolygon(basegfx::tools::createUnitPolygon()); - aMaskPolyPolygon.transform(getTransform()); - - // create maskPrimitive with aMaskPolyPolygon and aMaskContentVector - const Primitive2DReference xRefB(new MaskPrimitive2D(aMaskPolyPolygon, Primitive2DSequence(&xTransformPrimitive, 1L))); - appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, xRefB); - } - } - } - else - { - // add to decomposition - appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, xPrimitive); + // embed content in cropPrimitive + xPrimitive = new CropPrimitive2D( + Primitive2DSequence(&xPrimitive, 1), + aTransform, + getGraphicAttr().GetLeftCrop() * fFactorX, + getGraphicAttr().GetTopCrop() * fFactorY, + getGraphicAttr().GetRightCrop() * fFactorX, + getGraphicAttr().GetBottomCrop() * fFactorY); } + + // add to decomposition + appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, xPrimitive); } } diff --git a/drawinglayer/source/primitive2d/metafileprimitive2d.cxx b/drawinglayer/source/primitive2d/metafileprimitive2d.cxx index 4d11fe523754..a3eff771d4da 100644 --- a/drawinglayer/source/primitive2d/metafileprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/metafileprimitive2d.cxx @@ -59,7 +59,6 @@ #include <drawinglayer/primitive2d/textlineprimitive2d.hxx> #include <drawinglayer/primitive2d/textstrikeoutprimitive2d.hxx> #include <drawinglayer/primitive2d/epsprimitive2d.hxx> -#include <drawinglayer/primitive2d/rendergraphicprimitive2d.hxx> #include <numeric> ////////////////////////////////////////////////////////////////////////////// @@ -3065,33 +3064,6 @@ namespace break; } - case META_RENDERGRAPHIC_ACTION : - { - const MetaRenderGraphicAction* pA = (const MetaRenderGraphicAction*)pAction; - const Rectangle aRectangle(pA->GetPoint(), pA->GetSize()); - - if(!aRectangle.IsEmpty()) - { - // create object transform - basegfx::B2DHomMatrix aObjectTransform; - - aObjectTransform.set(0, 0, aRectangle.GetWidth()); - aObjectTransform.set(1, 1, aRectangle.GetHeight()); - aObjectTransform.set(0, 2, aRectangle.Left()); - aObjectTransform.set(1, 2, aRectangle.Top()); - - // add current transformation - aObjectTransform = rPropertyHolders.Current().getTransformation() * aObjectTransform; - - // embed using EpsPrimitive - rTargetHolders.Current().append( - new drawinglayer::primitive2d::RenderGraphicPrimitive2D( - pA->GetRenderGraphic(), - aObjectTransform ) ); - } - - break; - } case META_COMMENT_ACTION : { /** CHECKED, WORKS WELL */ diff --git a/drawinglayer/source/primitive2d/patternfillprimitive2d.cxx b/drawinglayer/source/primitive2d/patternfillprimitive2d.cxx new file mode 100644 index 000000000000..3c334d2770c9 --- /dev/null +++ b/drawinglayer/source/primitive2d/patternfillprimitive2d.cxx @@ -0,0 +1,158 @@ +/************************************************************** + * + * 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/patternfillprimitive2d.hxx> +#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> +#include <drawinglayer/primitive2d/transformprimitive2d.hxx> +#include <drawinglayer/primitive2d/polygonprimitive2d.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <drawinglayer/texture/texture.hxx> +#include <drawinglayer/primitive2d/maskprimitive2d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive2d + { + Primitive2DSequence PatternFillPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const + { + Primitive2DSequence aRetval; + + if(getChildren().hasElements()) + { + if(!getReferenceRange().isEmpty() && getReferenceRange().getWidth() > 0.0 && getReferenceRange().getHeight() > 0.0) + { + const basegfx::B2DRange aMaskRange(getMask().getB2DRange()); + + if(!aMaskRange.isEmpty() && aMaskRange.getWidth() > 0.0 && aMaskRange.getHeight() > 0.0) + { + // create tiling matrices + ::std::vector< basegfx::B2DHomMatrix > aMatrices; + texture::GeoTexSvxTiled aTiling(getReferenceRange().getMinimum(), getReferenceRange().getRange()); + aTiling.appendTransformations(aMatrices); + + // check if content needs to be clipped + const basegfx::B2DRange aUnitRange(0.0, 0.0, 1.0, 1.0); + const basegfx::B2DRange aContentRange(getB2DRangeFromPrimitive2DSequence(getChildren(), rViewInformation)); + Primitive2DSequence aContent(getChildren()); + + if(!aUnitRange.isInside(aContentRange)) + { + const Primitive2DReference xRef( + new MaskPrimitive2D( + basegfx::B2DPolyPolygon(basegfx::tools::createPolygonFromRect(aUnitRange)), + aContent)); + + aContent = Primitive2DSequence(&xRef, 1); + } + + // resize result + aRetval.realloc(aMatrices.size()); + + // create one primitive for each matrix + for(sal_uInt32 a(0); a < aMatrices.size(); a++) + { + aRetval[a] = new TransformPrimitive2D( + aMatrices[a], + aContent); + } + + // transform result which is in unit coordinates to mask's object coordiantes + { + const basegfx::B2DHomMatrix aMaskTransform( + basegfx::tools::createScaleTranslateB2DHomMatrix( + aMaskRange.getRange(), + aMaskRange.getMinimum())); + + const Primitive2DReference xRef( + new TransformPrimitive2D( + aMaskTransform, + aRetval)); + + aRetval = Primitive2DSequence(&xRef, 1); + } + + // embed result in mask + { + const Primitive2DReference xRef( + new MaskPrimitive2D( + getMask(), + aRetval)); + + aRetval = Primitive2DSequence(&xRef, 1); + } + + } + } + } + + return aRetval; + } + + PatternFillPrimitive2D::PatternFillPrimitive2D( + const basegfx::B2DPolyPolygon& rMask, + const Primitive2DSequence& rChildren, + const basegfx::B2DRange& rReferenceRange) + : BufferedDecompositionPrimitive2D(), + maMask(rMask), + maChildren(rChildren), + maReferenceRange(rReferenceRange) + { + } + + bool PatternFillPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + { + if(BufferedDecompositionPrimitive2D::operator==(rPrimitive)) + { + const PatternFillPrimitive2D& rCompare = static_cast< const PatternFillPrimitive2D& >(rPrimitive); + + return (getMask() == rCompare.getMask() + && getChildren() == rCompare.getChildren() + && getReferenceRange() == rCompare.getReferenceRange()); + } + + return false; + } + + basegfx::B2DRange PatternFillPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const + { + return getMask().getB2DRange(); + } + + // provide unique ID + ImplPrimitrive2DIDBlock(PatternFillPrimitive2D, PRIMITIVE2D_ID_PATTERNFILLPRIMITIVE2D) + + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive2d/rendergraphicprimitive2d.cxx b/drawinglayer/source/primitive2d/rendergraphicprimitive2d.cxx deleted file mode 100644 index 439937f5d0f5..000000000000 --- a/drawinglayer/source/primitive2d/rendergraphicprimitive2d.cxx +++ /dev/null @@ -1,92 +0,0 @@ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2000, 2010 Oracle and/or its affiliates. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * <http://www.openoffice.org/license.html> - * for a copy of the LGPLv3 License. - * - ************************************************************************/ - -// MARKER(update_precomp.py): autogen include statement, do not remove -#include "precompiled_drawinglayer.hxx" - -#include <drawinglayer/primitive2d/rendergraphicprimitive2d.hxx> -#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> -#include <basegfx/tools/canvastools.hxx> -#include <vcl/rendergraphicrasterizer.hxx> - -////////////////////////////////////////////////////////////////////////////// - -using namespace com::sun::star; - -////////////////////////////////////////////////////////////////////////////// - -namespace drawinglayer -{ - namespace primitive2d - { - RenderGraphicPrimitive2D::RenderGraphicPrimitive2D( - const vcl::RenderGraphic& rRenderGraphic, - const basegfx::B2DHomMatrix& rTransform) - : BasePrimitive2D(), - maRenderGraphic(rRenderGraphic), - maTransform(rTransform) - { - } - - void RenderGraphicPrimitive2D::setCurrentRasterizer() const - { - mapCurrentRasterizer.reset(); - } - - void RenderGraphicPrimitive2D::setCurrentRasterizer( const vcl::RenderGraphicRasterizer& rCurrentRasterizer ) const - { - mapCurrentRasterizer.reset( new vcl::RenderGraphicRasterizer( rCurrentRasterizer ) ); - } - - bool RenderGraphicPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const - { - if(BasePrimitive2D::operator==(rPrimitive)) - { - const RenderGraphicPrimitive2D& rCompare = (RenderGraphicPrimitive2D&)rPrimitive; - - return (getRenderGraphic() == rCompare.getRenderGraphic() - && getTransform() == rCompare.getTransform()); - } - - return false; - } - - basegfx::B2DRange RenderGraphicPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const - { - basegfx::B2DRange aRetval(0.0, 0.0, 1.0, 1.0); - aRetval.transform(maTransform); - return aRetval; - } - - // provide unique ID - ImplPrimitrive2DIDBlock(RenderGraphicPrimitive2D, PRIMITIVE2D_ID_RENDERGRAPHICPRIMITIVE2D) - - } // end of namespace primitive2d -} // end of namespace drawinglayer - -////////////////////////////////////////////////////////////////////////////// -// eof diff --git a/drawinglayer/source/primitive2d/svggradientprimitive2d.cxx b/drawinglayer/source/primitive2d/svggradientprimitive2d.cxx new file mode 100644 index 000000000000..199fc3d3fb03 --- /dev/null +++ b/drawinglayer/source/primitive2d/svggradientprimitive2d.cxx @@ -0,0 +1,1249 @@ +/************************************************************** + * + * 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/svggradientprimitive2d.hxx> +#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> +#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> +#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx> +#include <drawinglayer/primitive2d/polygonprimitive2d.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <drawinglayer/primitive2d/transparenceprimitive2d.hxx> +#include <drawinglayer/primitive2d/transformprimitive2d.hxx> +#include <drawinglayer/primitive2d/maskprimitive2d.hxx> +#include <drawinglayer/geometry/viewinformation2d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive2d + { + Primitive2DSequence SvgGradientHelper::createSingleGradientEntryFill() const + { + const SvgGradientEntryVector& rEntries = getGradientEntries(); + const sal_uInt32 nCount(rEntries.size()); + Primitive2DSequence xRetval; + + if(nCount) + { + const SvgGradientEntry& rSingleEntry = rEntries[nCount - 1]; + const double fOpacity(rSingleEntry.getOpacity()); + + if(fOpacity > 0.0) + { + Primitive2DReference xRef( + new PolyPolygonColorPrimitive2D( + getPolyPolygon(), + rSingleEntry.getColor())); + + if(fOpacity < 1.0) + { + const Primitive2DSequence aContent(&xRef, 1); + + xRef = Primitive2DReference( + new UnifiedTransparencePrimitive2D( + aContent, + 1.0 - fOpacity)); + } + + xRetval = Primitive2DSequence(&xRef, 1); + } + } + else + { + OSL_ENSURE(false, "Single gradient entry construction without entry (!)"); + } + + return xRetval; + } + + void SvgGradientHelper::checkPreconditions() + { + mbPreconditionsChecked = true; + const SvgGradientEntryVector& rEntries = getGradientEntries(); + + if(rEntries.empty()) + { + // no fill at all + } + else + { + const sal_uInt32 nCount(rEntries.size()); + + if(1 == nCount) + { + // fill with single existing color + setSingleEntry(); + } + else + { + // sort maGradientEntries when more than one + std::sort(maGradientEntries.begin(), maGradientEntries.end()); + + // gradient with at least two colors + bool bAllInvisible(true); + + for(sal_uInt32 a(0); a < nCount; a++) + { + const SvgGradientEntry& rCandidate = rEntries[a]; + + if(basegfx::fTools::equalZero(rCandidate.getOpacity())) + { + // invisible + mbFullyOpaque = false; + } + else if(basegfx::fTools::equal(rCandidate.getOpacity(), 1.0)) + { + // completely opaque + bAllInvisible = false; + } + else + { + // opacity + bAllInvisible = false; + mbFullyOpaque = false; + } + } + + if(bAllInvisible) + { + // all invisible, nothing to do + } + else + { + const basegfx::B2DRange aPolyRange(getPolyPolygon().getB2DRange()); + + if(aPolyRange.isEmpty()) + { + // no range to fill, nothing to do + } + else + { + const double fPolyWidth(aPolyRange.getWidth()); + const double fPolyHeight(aPolyRange.getHeight()); + + if(basegfx::fTools::equalZero(fPolyWidth) || basegfx::fTools::equalZero(fPolyHeight)) + { + // no width/height to fill, nothing to do + } + else + { + mbCreatesContent = true; + } + } + } + } + } + } + + double SvgGradientHelper::createRun( + Primitive2DVector& rTargetColor, + Primitive2DVector& rTargetOpacity, + double fPos, + double fMax, + const SvgGradientEntryVector& rEntries, + sal_Int32 nOffset) const + { + const sal_uInt32 nCount(rEntries.size()); + + if(nCount) + { + const SvgGradientEntry& rStart = rEntries[0]; + const bool bCreateStartPad(fPos < 0.0 && Spread_pad == getSpreadMethod()); + const bool bCreateStartFill(rStart.getOffset() > 0.0); + sal_uInt32 nIndex(0); + + if(bCreateStartPad || bCreateStartFill) + { + const SvgGradientEntry aTemp(bCreateStartPad ? fPos : 0.0, rStart.getColor(), rStart.getOpacity()); + + createAtom(rTargetColor, rTargetOpacity, aTemp, rStart, nOffset); + fPos = rStart.getOffset(); + } + + while(fPos < 1.0 && nIndex + 1 < nCount) + { + const SvgGradientEntry& rCandidateA = rEntries[nIndex++]; + const SvgGradientEntry& rCandidateB = rEntries[nIndex]; + + createAtom(rTargetColor, rTargetOpacity, rCandidateA, rCandidateB, nOffset); + fPos = rCandidateB.getOffset(); + } + + const SvgGradientEntry& rEnd = rEntries[nCount - 1]; + const bool bCreateEndPad(fPos < fMax && Spread_pad == getSpreadMethod()); + const bool bCreateEndFill(rEnd.getOffset() < 1.0); + + if(bCreateEndPad || bCreateEndFill) + { + fPos = bCreateEndPad ? fMax : 1.0; + const SvgGradientEntry aTemp(fPos, rEnd.getColor(), rEnd.getOpacity()); + + createAtom(rTargetColor, rTargetOpacity, rEnd, aTemp, nOffset); + } + } + else + { + OSL_ENSURE(false, "GradientAtom creation without ColorStops (!)"); + fPos = fMax; + } + + return fPos; + } + + Primitive2DSequence SvgGradientHelper::createResult( + const Primitive2DVector& rTargetColor, + const Primitive2DVector& rTargetOpacity, + const basegfx::B2DHomMatrix& rUnitGradientToObject, + bool bInvert) const + { + Primitive2DSequence xRetval; + const Primitive2DSequence aTargetColorEntries(Primitive2DVectorToPrimitive2DSequence(rTargetColor, bInvert)); + const Primitive2DSequence aTargetOpacityEntries(Primitive2DVectorToPrimitive2DSequence(rTargetOpacity, bInvert)); + + if(aTargetColorEntries.hasElements()) + { + Primitive2DReference xRefContent; + + if(aTargetOpacityEntries.hasElements()) + { + const Primitive2DReference xRefOpacity = new TransparencePrimitive2D( + aTargetColorEntries, + aTargetOpacityEntries); + + xRefContent = new TransformPrimitive2D( + rUnitGradientToObject, + Primitive2DSequence(&xRefOpacity, 1)); + } + else + { + xRefContent = new TransformPrimitive2D( + rUnitGradientToObject, + aTargetColorEntries); + } + + xRefContent = new MaskPrimitive2D( + getPolyPolygon(), + Primitive2DSequence(&xRefContent, 1)); + + xRetval = Primitive2DSequence(&xRefContent, 1); + } + + return xRetval; + } + + SvgGradientHelper::SvgGradientHelper( + const basegfx::B2DPolyPolygon& rPolyPolygon, + const SvgGradientEntryVector& rGradientEntries, + const basegfx::B2DPoint& rStart, + SpreadMethod aSpreadMethod, + double fOverlapping) + : maPolyPolygon(rPolyPolygon), + maGradientEntries(rGradientEntries), + maStart(rStart), + maSpreadMethod(aSpreadMethod), + mfOverlapping(fOverlapping), + mbPreconditionsChecked(false), + mbCreatesContent(false), + mbSingleEntry(false), + mbFullyOpaque(true) + { + } + + bool SvgGradientHelper::operator==(const SvgGradientHelper& rSvgGradientHelper) const + { + const SvgGradientHelper& rCompare = static_cast< const SvgGradientHelper& >(rSvgGradientHelper); + + return (getPolyPolygon() == rCompare.getPolyPolygon() + && getGradientEntries() == rCompare.getGradientEntries() + && getStart() == rCompare.getStart() + && getSpreadMethod() == rCompare.getSpreadMethod() + && getOverlapping() == rCompare.getOverlapping()); + } + + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive2d + { + void SvgLinearGradientPrimitive2D::checkPreconditions() + { + // call parent + SvgGradientHelper::checkPreconditions(); + + if(getCreatesContent()) + { + // Check Vector + const basegfx::B2DVector aVector(getEnd() - getStart()); + + if(basegfx::fTools::equalZero(aVector.getX()) && basegfx::fTools::equalZero(aVector.getY())) + { + // fill with single color using last stop color + setSingleEntry(); + } + } + } + + void SvgLinearGradientPrimitive2D::ensureGeometry( + basegfx::B2DPolyPolygon& rPolyPolygon, + const SvgGradientEntry& rFrom, + const SvgGradientEntry& rTo, + sal_Int32 nOffset) const + { + if(!rPolyPolygon.count()) + { + rPolyPolygon.append( + basegfx::tools::createPolygonFromRect( + basegfx::B2DRange( + rFrom.getOffset() - getOverlapping() + nOffset, + 0.0, + rTo.getOffset() + getOverlapping() + nOffset, + 1.0))); + } + } + + void SvgLinearGradientPrimitive2D::createAtom( + Primitive2DVector& rTargetColor, + Primitive2DVector& rTargetOpacity, + const SvgGradientEntry& rFrom, + const SvgGradientEntry& rTo, + sal_Int32 nOffset) const + { + // create gradient atom [rFrom.getOffset() .. rTo.getOffset()] with (rFrom.getOffset() > rTo.getOffset()) + if(rFrom.getOffset() == rTo.getOffset()) + { + OSL_ENSURE(false, "SvgGradient Atom creation with no step width (!)"); + } + else + { + const bool bColorChange(rFrom.getColor() != rTo.getColor()); + const bool bOpacityChange(rFrom.getOpacity() != rTo.getOpacity()); + basegfx::B2DPolyPolygon aPolyPolygon; + + if(bColorChange) + { + rTargetColor.push_back( + new SvgLinearAtomPrimitive2D( + rFrom.getColor(), rFrom.getOffset() + nOffset, + rTo.getColor(), rTo.getOffset() + nOffset, + getOverlapping())); + } + else + { + ensureGeometry(aPolyPolygon, rFrom, rTo, nOffset); + rTargetColor.push_back( + new PolyPolygonColorPrimitive2D( + aPolyPolygon, + rFrom.getColor())); + } + + if(bOpacityChange) + { + const double fTransFrom(1.0 - rFrom.getOpacity()); + const double fTransTo(1.0 - rTo.getOpacity()); + + rTargetOpacity.push_back( + new SvgLinearAtomPrimitive2D( + basegfx::BColor(fTransFrom, fTransFrom, fTransFrom), rFrom.getOffset() + nOffset, + basegfx::BColor(fTransTo,fTransTo, fTransTo), rTo.getOffset() + nOffset, + getOverlapping())); + } + else if(!getFullyOpaque()) + { + const double fTransparence(1.0 - rFrom.getOpacity()); + + ensureGeometry(aPolyPolygon, rFrom, rTo, nOffset); + rTargetOpacity.push_back( + new PolyPolygonColorPrimitive2D( + aPolyPolygon, + basegfx::BColor(fTransparence, fTransparence, fTransparence))); + } + } + } + + Primitive2DSequence SvgLinearGradientPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const + { + Primitive2DSequence xRetval; + + if(!getPreconditionsChecked()) + { + const_cast< SvgLinearGradientPrimitive2D* >(this)->checkPreconditions(); + } + + if(getSingleEntry()) + { + // fill with last existing color + xRetval = createSingleGradientEntryFill(); + } + else if(getCreatesContent()) + { + // at least two color stops in range [0.0 .. 1.0], sorted, non-null vector, not completely + // invisible, width and height to fill are not empty + const basegfx::B2DRange aPolyRange(getPolyPolygon().getB2DRange()); + const double fPolyWidth(aPolyRange.getWidth()); + const double fPolyHeight(aPolyRange.getHeight()); + + // create ObjectTransform based on polygon range + const basegfx::B2DHomMatrix aObjectTransform( + basegfx::tools::createScaleTranslateB2DHomMatrix( + fPolyWidth, fPolyHeight, + aPolyRange.getMinX(), aPolyRange.getMinY())); + + // create unit transform from unit vector [0.0 .. 1.0] along the X-Axis to given + // gradient vector defined by Start,End + const basegfx::B2DVector aVector(getEnd() - getStart()); + const double fVectorLength(aVector.getLength()); + basegfx::B2DHomMatrix aUnitGradientToGradient; + + aUnitGradientToGradient.scale(fVectorLength, 1.0); + aUnitGradientToGradient.rotate(atan2(aVector.getY(), aVector.getX())); + aUnitGradientToGradient.translate(getStart().getX(), getStart().getY()); + + // create full transform from unit gradient coordinates to object coordinates + // including the SvgGradient transformation + basegfx::B2DHomMatrix aUnitGradientToObject(aObjectTransform * aUnitGradientToGradient); + + // create inverse from it + basegfx::B2DHomMatrix aObjectToUnitGradient(aUnitGradientToObject); + aObjectToUnitGradient.invert(); + + // back-transform polygon to unit gradient coordinates and get + // UnitRage. This is the range the gradient has to cover + basegfx::B2DPolyPolygon aUnitPoly(getPolyPolygon()); + aUnitPoly.transform(aObjectToUnitGradient); + const basegfx::B2DRange aUnitRange(aUnitPoly.getB2DRange()); + + // prepare result vectors + Primitive2DVector aTargetColor; + Primitive2DVector aTargetOpacity; + + if(basegfx::fTools::more(aUnitRange.getWidth(), 0.0)) + { + // add a pre-multiply to aUnitGradientToObject to allow + // multiplication of the polygon(xl, 0.0, xr, 1.0) + const basegfx::B2DHomMatrix aPreMultiply( + basegfx::tools::createScaleTranslateB2DHomMatrix( + 1.0, aUnitRange.getHeight(), 0.0, aUnitRange.getMinY())); + aUnitGradientToObject = aUnitGradientToObject * aPreMultiply; + + // create central run, may also already do all necessary when + // Spread_pad is set as SpreadMethod and/or the range is smaller + double fPos(createRun(aTargetColor, aTargetOpacity, aUnitRange.getMinX(), aUnitRange.getMaxX(), getGradientEntries(), 0)); + + if(fPos < aUnitRange.getMaxX()) + { + // can only happen when SpreadMethod is Spread_reflect or Spread_repeat, + // else the start and end pads are already created and fPos == aUnitRange.getMaxX(). + // Its possible to express the repeated linear gradient by adding the + // transformed central run. Crete it this way + Primitive2DSequence aTargetColorEntries(Primitive2DVectorToPrimitive2DSequence(aTargetColor)); + Primitive2DSequence aTargetOpacityEntries(Primitive2DVectorToPrimitive2DSequence(aTargetOpacity)); + aTargetColor.clear(); + aTargetOpacity.clear(); + + if(aTargetColorEntries.hasElements()) + { + // add original central run as group primitive + aTargetColor.push_back(new GroupPrimitive2D(aTargetColorEntries)); + + if(aTargetOpacityEntries.hasElements()) + { + aTargetOpacity.push_back(new GroupPrimitive2D(aTargetOpacityEntries)); + } + + // add negative runs + fPos = 0.0; + sal_Int32 nOffset(0); + + while(fPos > aUnitRange.getMinX()) + { + fPos -= 1.0; + nOffset++; + + basegfx::B2DHomMatrix aTransform; + const bool bMirror(Spread_reflect == getSpreadMethod() && (nOffset % 2)); + + if(bMirror) + { + aTransform.scale(-1.0, 1.0); + aTransform.translate(fPos + 1.0, 0.0); + } + else + { + aTransform.translate(fPos, 0.0); + } + + aTargetColor.push_back(new TransformPrimitive2D(aTransform, aTargetColorEntries)); + + if(aTargetOpacityEntries.hasElements()) + { + aTargetOpacity.push_back(new TransformPrimitive2D(aTransform, aTargetOpacityEntries)); + } + } + + // add positive runs + fPos = 1.0; + nOffset = 1; + + while(fPos < aUnitRange.getMaxX()) + { + basegfx::B2DHomMatrix aTransform; + const bool bMirror(Spread_reflect == getSpreadMethod() && (nOffset % 2)); + + if(bMirror) + { + aTransform.scale(-1.0, 1.0); + aTransform.translate(fPos + 1.0, 0.0); + } + else + { + aTransform.translate(fPos, 0.0); + } + + aTargetColor.push_back(new TransformPrimitive2D(aTransform, aTargetColorEntries)); + + if(aTargetOpacityEntries.hasElements()) + { + aTargetOpacity.push_back(new TransformPrimitive2D(aTransform, aTargetOpacityEntries)); + } + + fPos += 1.0; + nOffset++; + } + } + } + } + + xRetval = createResult(aTargetColor, aTargetOpacity, aUnitGradientToObject); + } + + return xRetval; + } + + SvgLinearGradientPrimitive2D::SvgLinearGradientPrimitive2D( + const basegfx::B2DPolyPolygon& rPolyPolygon, + const SvgGradientEntryVector& rGradientEntries, + const basegfx::B2DPoint& rStart, + const basegfx::B2DPoint& rEnd, + SpreadMethod aSpreadMethod, + double fOverlapping) + : BufferedDecompositionPrimitive2D(), + SvgGradientHelper(rPolyPolygon, rGradientEntries, rStart, aSpreadMethod, fOverlapping), + maEnd(rEnd) + { + } + + bool SvgLinearGradientPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + { + const SvgGradientHelper* pSvgGradientHelper = dynamic_cast< const SvgGradientHelper* >(&rPrimitive); + + if(pSvgGradientHelper && SvgGradientHelper::operator==(*pSvgGradientHelper)) + { + const SvgLinearGradientPrimitive2D& rCompare = static_cast< const SvgLinearGradientPrimitive2D& >(rPrimitive); + + return (getEnd() == rCompare.getEnd()); + } + + return false; + } + + basegfx::B2DRange SvgLinearGradientPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const + { + // return ObjectRange + return getPolyPolygon().getB2DRange(); + } + + // provide unique ID + ImplPrimitrive2DIDBlock(SvgLinearGradientPrimitive2D, PRIMITIVE2D_ID_SVGLINEARGRADIENTPRIMITIVE2D) + + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive2d + { + void SvgRadialGradientPrimitive2D::checkPreconditions() + { + // call parent + SvgGradientHelper::checkPreconditions(); + + if(getCreatesContent()) + { + // Check Radius + if(basegfx::fTools::equalZero(getRadius())) + { + // fill with single color using last stop color + setSingleEntry(); + } + } + } + + void SvgRadialGradientPrimitive2D::ensureGeometry( + basegfx::B2DPolyPolygon& rPolyPolygon, + const SvgGradientEntry& rFrom, + const SvgGradientEntry& rTo, + sal_Int32 nOffset) const + { + if(!rPolyPolygon.count()) + { + basegfx::B2DPolygon aPolygonA(basegfx::tools::createPolygonFromUnitCircle()); + basegfx::B2DPolygon aPolygonB(basegfx::tools::createPolygonFromUnitCircle()); + double fScaleFrom(rFrom.getOffset() + nOffset); + const double fScaleTo(rTo.getOffset() + nOffset); + + if(fScaleFrom > getOverlapping()) + { + fScaleFrom -= getOverlapping(); + } + + if(isFocalSet()) + { + const basegfx::B2DVector aTranslateFrom(maFocalVector * (maFocalLength - fScaleFrom)); + const basegfx::B2DVector aTranslateTo(maFocalVector * (maFocalLength - fScaleTo)); + + aPolygonA.transform( + basegfx::tools::createScaleTranslateB2DHomMatrix( + fScaleFrom, + fScaleFrom, + aTranslateFrom.getX(), + aTranslateFrom.getY())); + aPolygonB.transform( + basegfx::tools::createScaleTranslateB2DHomMatrix( + fScaleTo, + fScaleTo, + aTranslateTo.getX(), + aTranslateTo.getY())); + } + else + { + aPolygonA.transform( + basegfx::tools::createScaleB2DHomMatrix( + fScaleFrom, + fScaleFrom)); + aPolygonB.transform( + basegfx::tools::createScaleB2DHomMatrix( + fScaleTo, + fScaleTo)); + } + + // add the outer polygon first + rPolyPolygon.append(aPolygonB); + rPolyPolygon.append(aPolygonA); + } + } + + void SvgRadialGradientPrimitive2D::createAtom( + Primitive2DVector& rTargetColor, + Primitive2DVector& rTargetOpacity, + const SvgGradientEntry& rFrom, + const SvgGradientEntry& rTo, + sal_Int32 nOffset) const + { + // create gradient atom [rFrom.getOffset() .. rTo.getOffset()] with (rFrom.getOffset() > rTo.getOffset()) + if(rFrom.getOffset() == rTo.getOffset()) + { + OSL_ENSURE(false, "SvgGradient Atom creation with no step width (!)"); + } + else + { + const bool bColorChange(rFrom.getColor() != rTo.getColor()); + const bool bOpacityChange(rFrom.getOpacity() != rTo.getOpacity()); + basegfx::B2DPolyPolygon aPolyPolygon; + + if(bColorChange) + { + const double fScaleFrom(rFrom.getOffset() + nOffset); + const double fScaleTo(rTo.getOffset() + nOffset); + + if(isFocalSet()) + { + const basegfx::B2DVector aTranslateFrom(maFocalVector * (maFocalLength - fScaleFrom)); + const basegfx::B2DVector aTranslateTo(maFocalVector * (maFocalLength - fScaleTo)); + + rTargetColor.push_back( + new SvgRadialAtomPrimitive2D( + rFrom.getColor(), fScaleFrom, aTranslateFrom, + rTo.getColor(), fScaleTo, aTranslateTo, + getOverlapping())); + } + else + { + rTargetColor.push_back( + new SvgRadialAtomPrimitive2D( + rFrom.getColor(), fScaleFrom, + rTo.getColor(), fScaleTo, + getOverlapping())); + } + } + else + { + ensureGeometry(aPolyPolygon, rFrom, rTo, nOffset); + rTargetColor.push_back( + new PolyPolygonColorPrimitive2D( + aPolyPolygon, + rFrom.getColor())); + } + + if(bOpacityChange) + { + const double fTransFrom(1.0 - rFrom.getOpacity()); + const double fTransTo(1.0 - rTo.getOpacity()); + const basegfx::BColor aColorFrom(fTransFrom, fTransFrom, fTransFrom); + const basegfx::BColor aColorTo(fTransTo, fTransTo, fTransTo); + const double fScaleFrom(rFrom.getOffset() + nOffset); + const double fScaleTo(rTo.getOffset() + nOffset); + + if(isFocalSet()) + { + const basegfx::B2DVector aTranslateFrom(maFocalVector * (maFocalLength - fScaleFrom)); + const basegfx::B2DVector aTranslateTo(maFocalVector * (maFocalLength - fScaleTo)); + + rTargetOpacity.push_back( + new SvgRadialAtomPrimitive2D( + aColorFrom, fScaleFrom, aTranslateFrom, + aColorTo, fScaleTo, aTranslateTo, + getOverlapping())); + } + else + { + rTargetOpacity.push_back( + new SvgRadialAtomPrimitive2D( + aColorFrom, fScaleFrom, + aColorTo, fScaleTo, + getOverlapping())); + } + } + else if(!getFullyOpaque()) + { + const double fTransparence(1.0 - rFrom.getOpacity()); + + ensureGeometry(aPolyPolygon, rFrom, rTo, nOffset); + rTargetOpacity.push_back( + new PolyPolygonColorPrimitive2D( + aPolyPolygon, + basegfx::BColor(fTransparence, fTransparence, fTransparence))); + } + } + } + + const SvgGradientEntryVector& SvgRadialGradientPrimitive2D::getMirroredGradientEntries() const + { + if(maMirroredGradientEntries.empty() && !getGradientEntries().empty()) + { + const_cast< SvgRadialGradientPrimitive2D* >(this)->createMirroredGradientEntries(); + } + + return maMirroredGradientEntries; + } + + void SvgRadialGradientPrimitive2D::createMirroredGradientEntries() + { + if(maMirroredGradientEntries.empty() && !getGradientEntries().empty()) + { + const sal_uInt32 nCount(getGradientEntries().size()); + maMirroredGradientEntries.clear(); + maMirroredGradientEntries.reserve(nCount); + + for(sal_uInt32 a(0); a < nCount; a++) + { + const SvgGradientEntry& rCandidate = getGradientEntries()[nCount - 1 - a]; + + maMirroredGradientEntries.push_back( + SvgGradientEntry( + 1.0 - rCandidate.getOffset(), + rCandidate.getColor(), + rCandidate.getOpacity())); + } + } + } + + Primitive2DSequence SvgRadialGradientPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const + { + Primitive2DSequence xRetval; + + if(!getPreconditionsChecked()) + { + const_cast< SvgRadialGradientPrimitive2D* >(this)->checkPreconditions(); + } + + if(getSingleEntry()) + { + // fill with last existing color + xRetval = createSingleGradientEntryFill(); + } + else if(getCreatesContent()) + { + // at least two color stops in range [0.0 .. 1.0], sorted, non-null vector, not completely + // invisible, width and height to fill are not empty + const SvgGradientEntryVector& rEntries = getGradientEntries(); + const basegfx::B2DRange aPolyRange(getPolyPolygon().getB2DRange()); + const double fPolyWidth(aPolyRange.getWidth()); + const double fPolyHeight(aPolyRange.getHeight()); + + // create ObjectTransform based on polygon range + const basegfx::B2DHomMatrix aObjectTransform( + basegfx::tools::createScaleTranslateB2DHomMatrix( + fPolyWidth, fPolyHeight, + aPolyRange.getMinX(), aPolyRange.getMinY())); + + // create unit transform from unit vector to given linear gradient vector + basegfx::B2DHomMatrix aUnitGradientToGradient; + + aUnitGradientToGradient.scale(getRadius(), getRadius()); + aUnitGradientToGradient.translate(getStart().getX(), getStart().getY()); + + // create full transform from unit gradient coordinates to object coordinates + // including the SvgGradient transformation + basegfx::B2DHomMatrix aUnitGradientToObject(aObjectTransform * aUnitGradientToGradient); + + // create inverse from it + basegfx::B2DHomMatrix aObjectToUnitGradient(aUnitGradientToObject); + aObjectToUnitGradient.invert(); + + // back-transform polygon to unit gradient coordinates and get + // UnitRage. This is the range the gradient has to cover + basegfx::B2DPolyPolygon aUnitPoly(getPolyPolygon()); + aUnitPoly.transform(aObjectToUnitGradient); + const basegfx::B2DRange aUnitRange(aUnitPoly.getB2DRange()); + + // create range which the gradient has to cover to cover the whole given geometry. + // For circle, go from 0.0 to max radius in all directions (the corners) + double fMax(basegfx::B2DVector(aUnitRange.getMinimum()).getLength()); + fMax = std::max(fMax, basegfx::B2DVector(aUnitRange.getMaximum()).getLength()); + fMax = std::max(fMax, basegfx::B2DVector(aUnitRange.getMinX(), aUnitRange.getMaxY()).getLength()); + fMax = std::max(fMax, basegfx::B2DVector(aUnitRange.getMaxX(), aUnitRange.getMinY()).getLength()); + + // prepare result vectors + Primitive2DVector aTargetColor; + Primitive2DVector aTargetOpacity; + + if(0.0 < fMax) + { + // prepare maFocalVector + if(isFocalSet()) + { + const_cast< SvgRadialGradientPrimitive2D* >(this)->maFocalLength = fMax; + } + + // create central run, may also already do all necessary when + // Spread_pad is set as SpreadMethod and/or the range is smaller + double fPos(createRun(aTargetColor, aTargetOpacity, 0.0, fMax, getGradientEntries(), 0)); + + if(fPos < fMax) + { + // can only happen when SpreadMethod is Spread_reflect or Spread_repeat, + // else the start and end pads are already created and fPos == fMax. + // For radial there is no way to transform the already created + // central run, it needs to be created from 1.0 to fMax + sal_Int32 nOffset(1); + + while(fPos < fMax) + { + const bool bMirror(Spread_reflect == getSpreadMethod() && (nOffset % 2)); + + if(bMirror) + { + createRun(aTargetColor, aTargetOpacity, 0.0, fMax, getMirroredGradientEntries(), nOffset); + } + else + { + createRun(aTargetColor, aTargetOpacity, 0.0, fMax, getGradientEntries(), nOffset); + } + + nOffset++; + fPos += 1.0; + } + } + } + + xRetval = createResult(aTargetColor, aTargetOpacity, aUnitGradientToObject, true); + } + + return xRetval; + } + + SvgRadialGradientPrimitive2D::SvgRadialGradientPrimitive2D( + const basegfx::B2DPolyPolygon& rPolyPolygon, + const SvgGradientEntryVector& rGradientEntries, + const basegfx::B2DPoint& rStart, + double fRadius, + SpreadMethod aSpreadMethod, + const basegfx::B2DPoint* pFocal, + double fOverlapping) + : BufferedDecompositionPrimitive2D(), + SvgGradientHelper(rPolyPolygon, rGradientEntries, rStart, aSpreadMethod, fOverlapping), + mfRadius(fRadius), + maFocal(rStart), + maFocalVector(0.0, 0.0), + maFocalLength(0.0), + maMirroredGradientEntries(), + mbFocalSet(false) + { + if(pFocal) + { + maFocal = *pFocal; + maFocalVector = maFocal - getStart(); + mbFocalSet = true; + } + } + + bool SvgRadialGradientPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + { + const SvgGradientHelper* pSvgGradientHelper = dynamic_cast< const SvgGradientHelper* >(&rPrimitive); + + if(pSvgGradientHelper && SvgGradientHelper::operator==(*pSvgGradientHelper)) + { + const SvgRadialGradientPrimitive2D& rCompare = static_cast< const SvgRadialGradientPrimitive2D& >(rPrimitive); + + if(getRadius() == rCompare.getRadius()) + { + if(isFocalSet() == rCompare.isFocalSet()) + { + if(isFocalSet()) + { + return getFocal() == rCompare.getFocal(); + } + else + { + return true; + } + } + } + } + + return false; + } + + basegfx::B2DRange SvgRadialGradientPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const + { + // return ObjectRange + return getPolyPolygon().getB2DRange(); + } + + // provide unique ID + ImplPrimitrive2DIDBlock(SvgRadialGradientPrimitive2D, PRIMITIVE2D_ID_SVGRADIALGRADIENTPRIMITIVE2D) + + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// SvgLinearAtomPrimitive2D class + +namespace drawinglayer +{ + namespace primitive2d + { + Primitive2DSequence SvgLinearAtomPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const + { + Primitive2DSequence xRetval; + const double fDelta(getOffsetB() - getOffsetA()); + + if(!basegfx::fTools::equalZero(fDelta)) + { + if(getColorA() == getColorB()) + { + const basegfx::B2DPolygon aPolygon( + basegfx::tools::createPolygonFromRect( + basegfx::B2DRange( + getOffsetA() - getOverlapping(), + 0.0, + getOffsetB() + getOverlapping(), + 1.0))); + + xRetval.realloc(1); + xRetval[0] = new PolyPolygonColorPrimitive2D( + basegfx::B2DPolyPolygon(aPolygon), + getColorA()); + } + else + { + // calc discrete length to change color all 2.5 pixels + sal_uInt32 nSteps(basegfx::fround(fDelta / (getDiscreteUnit() * 2.5))); + + // use color distance, assume to do every 3rd + const double fColorDistance(getColorA().getDistance(getColorB())); + const sal_uInt32 nColorSteps(basegfx::fround(fColorDistance * (255.0 * 0.3))); + nSteps = std::min(nSteps, nColorSteps); + + // roughly cut when too big + nSteps = std::min(nSteps, sal_uInt32(100)); + nSteps = std::max(nSteps, sal_uInt32(1)); + + // preapare iteration + double fStart(0.0); + double fStep(fDelta / nSteps); + + xRetval.realloc(nSteps); + + for(sal_uInt32 a(0); a < nSteps; a++, fStart += fStep) + { + const double fLeft(getOffsetA() + fStart); + const double fRight(fLeft + fStep); + const basegfx::B2DPolygon aPolygon( + basegfx::tools::createPolygonFromRect( + basegfx::B2DRange( + fLeft - getOverlapping(), + 0.0, + fRight + getOverlapping(), + 1.0))); + + xRetval[a] = new PolyPolygonColorPrimitive2D( + basegfx::B2DPolyPolygon(aPolygon), + basegfx::interpolate(getColorA(), getColorB(), fStart/fDelta)); + } + } + } + + return xRetval; + } + + bool SvgLinearAtomPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + { + if(DiscreteMetricDependentPrimitive2D::operator==(rPrimitive)) + { + const SvgLinearAtomPrimitive2D& rCompare = static_cast< const SvgLinearAtomPrimitive2D& >(rPrimitive); + + return (getColorA() == rCompare.getColorA() + && getColorB() == rCompare.getColorB() + && getOffsetA() == rCompare.getOffsetA() + && getOffsetB() == rCompare.getOffsetB() + && getOverlapping() == rCompare.getOverlapping()); + } + + return false; + } + + // provide unique ID + ImplPrimitrive2DIDBlock(SvgLinearAtomPrimitive2D, PRIMITIVE2D_ID_SVGLINEARATOMPRIMITIVE2D) + + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// SvgRadialAtomPrimitive2D class + +namespace drawinglayer +{ + namespace primitive2d + { + Primitive2DSequence SvgRadialAtomPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const + { + Primitive2DSequence xRetval; + const double fDeltaScale(getScaleB() - getScaleA()); + + if(!basegfx::fTools::equalZero(fDeltaScale)) + { + if(getColorA() == getColorB()) + { + basegfx::B2DPolygon aPolygonA(basegfx::tools::createPolygonFromUnitCircle()); + basegfx::B2DPolygon aPolygonB(basegfx::tools::createPolygonFromUnitCircle()); + double fScaleA(getScaleA()); + const double fScaleB(getScaleB()); + + if(fScaleA > getOverlapping()) + { + fScaleA -= getOverlapping(); + } + + const bool bUseA(basegfx::fTools::equalZero(fScaleA)); + + if(getTranslateSet()) + { + if(bUseA) + { + aPolygonA.transform( + basegfx::tools::createScaleTranslateB2DHomMatrix( + fScaleA, + fScaleA, + getTranslateA().getX(), + getTranslateA().getY())); + } + + aPolygonB.transform( + basegfx::tools::createScaleTranslateB2DHomMatrix( + fScaleB, + fScaleB, + getTranslateB().getX(), + getTranslateB().getY())); + } + else + { + if(bUseA) + { + aPolygonA.transform( + basegfx::tools::createScaleB2DHomMatrix( + fScaleA, + fScaleA)); + } + + aPolygonB.transform( + basegfx::tools::createScaleB2DHomMatrix( + fScaleB, + fScaleB)); + } + + basegfx::B2DPolyPolygon aPolyPolygon(aPolygonB); + + if(bUseA) + { + aPolyPolygon.append(aPolygonA); + } + + xRetval.realloc(1); + + xRetval[0] = new PolyPolygonColorPrimitive2D( + aPolyPolygon, + getColorA()); + } + else + { + // calc discrete length to change color all 2.5 pixels + sal_uInt32 nSteps(basegfx::fround(fDeltaScale / (getDiscreteUnit() * 2.5))); + + // use color distance, assume to do every 3rd + const double fColorDistance(getColorA().getDistance(getColorB())); + const sal_uInt32 nColorSteps(basegfx::fround(fColorDistance * (255.0 * 0.3))); + nSteps = std::min(nSteps, nColorSteps); + + // roughly cut when too big + nSteps = std::min(nSteps, sal_uInt32(100)); + nSteps = std::max(nSteps, sal_uInt32(1)); + + // preapare iteration + double fStartScale(0.0); + double fStepScale(fDeltaScale / nSteps); + + xRetval.realloc(nSteps); + + for(sal_uInt32 a(0); a < nSteps; a++, fStartScale += fStepScale) + { + double fScaleA(getScaleA() + fStartScale); + const double fScaleB(fScaleA + fStepScale); + const double fUnitScale(fStartScale/fDeltaScale); + basegfx::B2DPolygon aPolygonA(basegfx::tools::createPolygonFromUnitCircle()); + basegfx::B2DPolygon aPolygonB(basegfx::tools::createPolygonFromUnitCircle()); + + if(fScaleA > getOverlapping()) + { + fScaleA -= getOverlapping(); + } + + const bool bUseA(basegfx::fTools::equalZero(fScaleA)); + + if(getTranslateSet()) + { + const double fUnitScaleEnd((fStartScale + fStepScale)/fDeltaScale); + const basegfx::B2DVector aTranslateB(basegfx::interpolate(getTranslateA(), getTranslateB(), fUnitScaleEnd)); + + if(bUseA) + { + const basegfx::B2DVector aTranslateA(basegfx::interpolate(getTranslateA(), getTranslateB(), fUnitScale)); + + aPolygonA.transform( + basegfx::tools::createScaleTranslateB2DHomMatrix( + fScaleA, + fScaleA, + aTranslateA.getX(), + aTranslateA.getY())); + } + + aPolygonB.transform( + basegfx::tools::createScaleTranslateB2DHomMatrix( + fScaleB, + fScaleB, + aTranslateB.getX(), + aTranslateB.getY())); + } + else + { + if(bUseA) + { + aPolygonA.transform( + basegfx::tools::createScaleB2DHomMatrix( + fScaleA, + fScaleA)); + } + + aPolygonB.transform( + basegfx::tools::createScaleB2DHomMatrix( + fScaleB, + fScaleB)); + } + + basegfx::B2DPolyPolygon aPolyPolygon(aPolygonB); + + if(bUseA) + { + aPolyPolygon.append(aPolygonA); + } + + xRetval[nSteps - 1 - a] = new PolyPolygonColorPrimitive2D( + aPolyPolygon, + basegfx::interpolate(getColorA(), getColorB(), fUnitScale)); + } + } + } + + return xRetval; + } + + bool SvgRadialAtomPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + { + if(DiscreteMetricDependentPrimitive2D::operator==(rPrimitive)) + { + const SvgRadialAtomPrimitive2D& rCompare = static_cast< const SvgRadialAtomPrimitive2D& >(rPrimitive); + + return (getColorA() == rCompare.getColorA() + && getColorB() == rCompare.getColorB() + && getScaleA() == rCompare.getScaleA() + && getScaleB() == rCompare.getScaleB() + && getTranslateA() == rCompare.getTranslateA() + && getTranslateB() == rCompare.getTranslateB() + && getOverlapping() == rCompare.getOverlapping()); + } + + return false; + } + + // provide unique ID + ImplPrimitrive2DIDBlock(SvgRadialAtomPrimitive2D, PRIMITIVE2D_ID_SVGRADIALATOMPRIMITIVE2D) + + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive2d/textbreakuphelper.cxx b/drawinglayer/source/primitive2d/textbreakuphelper.cxx new file mode 100644 index 000000000000..4979a9932cc2 --- /dev/null +++ b/drawinglayer/source/primitive2d/textbreakuphelper.cxx @@ -0,0 +1,294 @@ +/************************************************************** + * + * 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/textbreakuphelper.hxx> +#include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx> +#include <com/sun/star/i18n/XBreakIterator.hpp> +#include <comphelper/processfactory.hxx> +#include <com/sun/star/i18n/CharacterIteratorMode.hdl> +#include <com/sun/star/i18n/WordType.hpp> + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive2d + { + TextBreakupHelper::TextBreakupHelper(const Primitive2DReference& rxSource) + : mxSource(rxSource), + mxResult(), + mpSource(dynamic_cast< const TextSimplePortionPrimitive2D* >(rxSource.get())), + maTextLayouter(), + maDecTrans(), + mbNoDXArray() + { + if(mpSource) + { + maDecTrans = mpSource->getTextTransform(); + mbNoDXArray = mpSource->getDXArray().empty(); + + if(mbNoDXArray) + { + // init TextLayouter when no dxarray + maTextLayouter.setFontAttribute( + mpSource->getFontAttribute(), + maDecTrans.getScale().getX(), + maDecTrans.getScale().getY(), + mpSource->getLocale()); + } + } + } + + TextBreakupHelper::~TextBreakupHelper() + { + } + + void TextBreakupHelper::breakupPortion(Primitive2DVector& rTempResult, sal_uInt32 nIndex, sal_uInt32 nLength) + { + if(mpSource && nLength && !(nIndex == mpSource->getTextPosition() && nLength == mpSource->getTextLength())) + { + // prepare values for new portion + basegfx::B2DHomMatrix aNewTransform; + ::std::vector< double > aNewDXArray; + const bool bNewStartIsNotOldStart(nIndex > mpSource->getTextPosition()); + + if(!mbNoDXArray) + { + // prepare new DXArray for the single word + aNewDXArray = ::std::vector< double >( + mpSource->getDXArray().begin() + (nIndex - mpSource->getTextPosition()), + mpSource->getDXArray().begin() + ((nIndex + nLength) - mpSource->getTextPosition())); + } + + if(bNewStartIsNotOldStart) + { + // needs to be moved to a new start position + double fOffset(0.0); + + if(mbNoDXArray) + { + // evaluate using TextLayouter + fOffset = maTextLayouter.getTextWidth(mpSource->getText(), mpSource->getTextPosition(), nIndex); + } + else + { + // get from DXArray + const sal_uInt32 nIndex(static_cast< sal_uInt32 >(nIndex - mpSource->getTextPosition())); + fOffset = mpSource->getDXArray()[nIndex - 1]; + } + + // need offset without FontScale for building the new transformation. The + // new transformation will be multiplied with the current text transformation + // so FontScale would be double + double fOffsetNoScale(fOffset); + const double fFontScaleX(maDecTrans.getScale().getX()); + + if(!basegfx::fTools::equal(fFontScaleX, 1.0) + && !basegfx::fTools::equalZero(fFontScaleX)) + { + fOffsetNoScale /= fFontScaleX; + } + + // apply needed offset to transformation + aNewTransform.translate(fOffsetNoScale, 0.0); + + if(!mbNoDXArray) + { + // DXArray values need to be corrected with the offset, too. Here, + // take the scaled offset since the DXArray is scaled + const sal_uInt32 nArraySize(aNewDXArray.size()); + + for(sal_uInt32 a(0); a < nArraySize; a++) + { + aNewDXArray[a] -= fOffset; + } + } + } + + // add text transformation to new transformation + aNewTransform = maDecTrans.getB2DHomMatrix() * aNewTransform; + + // callback to allow evtl. changes + const bool bCreate(allowChange(rTempResult.size(), aNewTransform, nIndex, nLength)); + + if(bCreate) + { + // check if we have a decorated primitive as source + const TextDecoratedPortionPrimitive2D* pTextDecoratedPortionPrimitive2D = + dynamic_cast< const TextDecoratedPortionPrimitive2D* >(mpSource); + + if(pTextDecoratedPortionPrimitive2D) + { + // create a TextDecoratedPortionPrimitive2D + rTempResult.push_back( + new TextDecoratedPortionPrimitive2D( + aNewTransform, + mpSource->getText(), + nIndex, + nLength, + aNewDXArray, + mpSource->getFontAttribute(), + mpSource->getLocale(), + mpSource->getFontColor(), + + pTextDecoratedPortionPrimitive2D->getOverlineColor(), + pTextDecoratedPortionPrimitive2D->getTextlineColor(), + pTextDecoratedPortionPrimitive2D->getFontOverline(), + pTextDecoratedPortionPrimitive2D->getFontUnderline(), + pTextDecoratedPortionPrimitive2D->getUnderlineAbove(), + pTextDecoratedPortionPrimitive2D->getTextStrikeout(), + pTextDecoratedPortionPrimitive2D->getWordLineMode(), + pTextDecoratedPortionPrimitive2D->getTextEmphasisMark(), + pTextDecoratedPortionPrimitive2D->getEmphasisMarkAbove(), + pTextDecoratedPortionPrimitive2D->getEmphasisMarkBelow(), + pTextDecoratedPortionPrimitive2D->getTextRelief(), + pTextDecoratedPortionPrimitive2D->getShadow())); + } + else + { + // create a SimpleTextPrimitive + rTempResult.push_back( + new TextSimplePortionPrimitive2D( + aNewTransform, + mpSource->getText(), + nIndex, + nLength, + aNewDXArray, + mpSource->getFontAttribute(), + mpSource->getLocale(), + mpSource->getFontColor())); + } + } + } + } + + bool TextBreakupHelper::allowChange(sal_uInt32 nCount, basegfx::B2DHomMatrix& rNewTransform, sal_uInt32 nIndex, sal_uInt32 nLength) + { + return true; + } + + void TextBreakupHelper::breakup(BreakupUnit aBreakupUnit) + { + if(mpSource && mpSource->getTextLength()) + { + Primitive2DVector aTempResult; + static ::com::sun::star::uno::Reference< ::com::sun::star::i18n::XBreakIterator > xBreakIterator; + + if(!xBreakIterator.is()) + { + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xMSF(::comphelper::getProcessServiceFactory()); + xBreakIterator.set(xMSF->createInstance(rtl::OUString::createFromAscii("com.sun.star.i18n.BreakIterator")), ::com::sun::star::uno::UNO_QUERY); + } + + if(xBreakIterator.is()) + { + const rtl::OUString& rTxt = mpSource->getText(); + const sal_Int32 nTextLength(mpSource->getTextLength()); + const ::com::sun::star::lang::Locale& rLocale = mpSource->getLocale(); + const sal_Int32 nTextPosition(mpSource->getTextPosition()); + sal_Int32 nCurrent(nTextPosition); + + switch(aBreakupUnit) + { + case BreakupUnit_character: + { + sal_Int32 nDone; + sal_Int32 nNextCellBreak(xBreakIterator->nextCharacters(rTxt, nTextPosition, rLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, 0, nDone)); + sal_Int32 a(nTextPosition); + + for(; a < nTextPosition + nTextLength; a++) + { + if(a == nNextCellBreak) + { + breakupPortion(aTempResult, nCurrent, a - nCurrent); + nCurrent = a; + nNextCellBreak = xBreakIterator->nextCharacters(rTxt, a, rLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, 1, nDone); + } + } + + breakupPortion(aTempResult, nCurrent, a - nCurrent); + break; + } + case BreakupUnit_word: + { + ::com::sun::star::i18n::Boundary nNextWordBoundary(xBreakIterator->getWordBoundary(rTxt, nTextPosition, rLocale, ::com::sun::star::i18n::WordType::ANY_WORD, sal_True)); + sal_Int32 a(nTextPosition); + + for(; a < nTextPosition + nTextLength; a++) + { + if(a == nNextWordBoundary.endPos) + { + breakupPortion(aTempResult, nCurrent, a - nCurrent); + nCurrent = a; + nNextWordBoundary = xBreakIterator->getWordBoundary(rTxt, a + 1, rLocale, ::com::sun::star::i18n::WordType::ANY_WORD, sal_True); + } + } + + breakupPortion(aTempResult, nCurrent, a - nCurrent); + break; + } + case BreakupUnit_sentence: + { + sal_Int32 nNextSentenceBreak(xBreakIterator->endOfSentence(rTxt, nTextPosition, rLocale)); + sal_Int32 a(nTextPosition); + + for(; a < nTextPosition + nTextLength; a++) + { + if(a == nNextSentenceBreak) + { + breakupPortion(aTempResult, nCurrent, a - nCurrent); + nCurrent = a; + nNextSentenceBreak = xBreakIterator->endOfSentence(rTxt, a + 1, rLocale); + } + } + + breakupPortion(aTempResult, nCurrent, a - nCurrent); + break; + } + } + } + + mxResult = Primitive2DVectorToPrimitive2DSequence(aTempResult); + } + } + + const Primitive2DSequence& TextBreakupHelper::getResult(BreakupUnit aBreakupUnit) const + { + if(mxResult.hasElements()) + { + return mxResult; + } + else if(mpSource) + { + const_cast< TextBreakupHelper* >(this)->breakup(aBreakupUnit); + } + + return mxResult; + } + + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/processor2d/hittestprocessor2d.cxx b/drawinglayer/source/processor2d/hittestprocessor2d.cxx index 855535eb96e8..3b5e266f3bfd 100644 --- a/drawinglayer/source/processor2d/hittestprocessor2d.cxx +++ b/drawinglayer/source/processor2d/hittestprocessor2d.cxx @@ -525,7 +525,6 @@ namespace drawinglayer case PRIMITIVE2D_ID_FILLHATCHPRIMITIVE2D : case PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D : case PRIMITIVE2D_ID_MEDIAPRIMITIVE2D: - case PRIMITIVE2D_ID_RENDERGRAPHICPRIMITIVE2D: { if(!getHitTextOnly()) { diff --git a/drawinglayer/source/processor2d/linegeometryextractor2d.cxx b/drawinglayer/source/processor2d/linegeometryextractor2d.cxx index 65a87c83f4a0..97ecf9da6952 100644 --- a/drawinglayer/source/processor2d/linegeometryextractor2d.cxx +++ b/drawinglayer/source/processor2d/linegeometryextractor2d.cxx @@ -119,7 +119,6 @@ namespace drawinglayer case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D : case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D : case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D : - case PRIMITIVE2D_ID_RENDERGRAPHICPRIMITIVE2D : case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D : case PRIMITIVE2D_ID_MASKPRIMITIVE2D : { diff --git a/drawinglayer/source/processor2d/textaspolygonextractor2d.cxx b/drawinglayer/source/processor2d/textaspolygonextractor2d.cxx index 13cbfcb3badb..59a47fc790a6 100644 --- a/drawinglayer/source/processor2d/textaspolygonextractor2d.cxx +++ b/drawinglayer/source/processor2d/textaspolygonextractor2d.cxx @@ -210,7 +210,6 @@ namespace drawinglayer case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D : case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D : case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D : - case PRIMITIVE2D_ID_RENDERGRAPHICPRIMITIVE2D : case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D : case PRIMITIVE2D_ID_MASKPRIMITIVE2D : { diff --git a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx index c56909e9dfde..63dbabf2bce5 100644 --- a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx @@ -34,7 +34,6 @@ #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> #include <drawinglayer/primitive2d/polygonprimitive2d.hxx> #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> -#include <drawinglayer/primitive2d/rendergraphicprimitive2d.hxx> #include <drawinglayer/primitive2d/metafileprimitive2d.hxx> #include <drawinglayer/primitive2d/maskprimitive2d.hxx> #include <basegfx/polygon/b2dpolygonclipper.hxx> @@ -1284,12 +1283,6 @@ namespace drawinglayer RenderBitmapPrimitive2D(static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate)); break; } - case PRIMITIVE2D_ID_RENDERGRAPHICPRIMITIVE2D : - { - // direct draw of transformed RenderGraphic primitive; use default processing - RenderRenderGraphicPrimitive2D(static_cast< const primitive2d::RenderGraphicPrimitive2D& >(rCandidate)); - break; - } case PRIMITIVE2D_ID_POLYPOLYGONBITMAPPRIMITIVE2D : { // need to handle PolyPolygonBitmapPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END @@ -1657,7 +1650,8 @@ namespace drawinglayer // 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(PolyPolygon(maClipPolyPolygon))); + mpOutputDevice->SetClipRegion(Region(maClipPolyPolygon)); } // recursively paint content diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx index f485aa182bd2..d71090ed7d5b 100644 --- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx @@ -31,7 +31,6 @@ #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> #include <drawinglayer/primitive2d/polygonprimitive2d.hxx> #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> -#include <drawinglayer/primitive2d/rendergraphicprimitive2d.hxx> #include <drawinglayer/primitive2d/fillbitmapprimitive2d.hxx> #include <drawinglayer/primitive2d/metafileprimitive2d.hxx> #include <drawinglayer/primitive2d/maskprimitive2d.hxx> @@ -190,12 +189,6 @@ namespace drawinglayer RenderBitmapPrimitive2D(static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate)); break; } - case PRIMITIVE2D_ID_RENDERGRAPHICPRIMITIVE2D : - { - // direct draw of transformed BitmapEx primitive - RenderRenderGraphicPrimitive2D(static_cast< const primitive2d::RenderGraphicPrimitive2D& >(rCandidate)); - break; - } case PRIMITIVE2D_ID_FILLBITMAPPRIMITIVE2D : { // direct draw of fillBitmapPrimitive diff --git a/drawinglayer/source/processor2d/vclprocessor2d.cxx b/drawinglayer/source/processor2d/vclprocessor2d.cxx index 8027f3284909..dc79dcce648a 100644 --- a/drawinglayer/source/processor2d/vclprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclprocessor2d.cxx @@ -31,7 +31,6 @@ #include <vcl/outdev.hxx> #include <drawinglayer/primitive2d/polygonprimitive2d.hxx> #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> -#include <drawinglayer/primitive2d/rendergraphicprimitive2d.hxx> #include <vclhelperbitmaptransform.hxx> #include <basegfx/polygon/b2dpolygontools.hxx> #include <vclhelperbitmaprender.hxx> @@ -57,7 +56,6 @@ #include <vcl/metric.hxx> #include <drawinglayer/primitive2d/textenumsprimitive2d.hxx> #include <drawinglayer/primitive2d/epsprimitive2d.hxx> -#include <vcl/rendergraphicrasterizer.hxx> ////////////////////////////////////////////////////////////////////////////// // control support @@ -419,75 +417,6 @@ namespace drawinglayer } } - void VclProcessor2D::RenderRenderGraphicPrimitive2D(const primitive2d::RenderGraphicPrimitive2D& rRenderGraphicCandidate) - { - // create local transform - basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation * rRenderGraphicCandidate.getTransform()); - vcl::RenderGraphic aRenderGraphic(rRenderGraphicCandidate.getRenderGraphic()); - bool bPainted(false); - - if(maBColorModifierStack.count()) - { - // !!! TODO - // aRenderGraphic = impModifyRenderGraphic(maBColorModifierStack, aRenderGraphic); - - if(aRenderGraphic.IsEmpty()) - { - // color gets completely replaced, get it - const basegfx::BColor aModifiedColor(maBColorModifierStack.getModifiedColor(basegfx::BColor())); - basegfx::B2DPolygon aPolygon(basegfx::tools::createUnitPolygon()); - aPolygon.transform(aLocalTransform); - - mpOutputDevice->SetFillColor(Color(aModifiedColor)); - mpOutputDevice->SetLineColor(); - mpOutputDevice->DrawPolygon(aPolygon); - - bPainted = true; - } - } - - if(!bPainted) - { - // decompose matrix to check for shear, rotate and mirroring - basegfx::B2DVector aScale, aTranslate; - double fRotate, fShearX; - aLocalTransform.decompose(aScale, aTranslate, fRotate, fShearX); - - basegfx::B2DRange aOutlineRange(0.0, 0.0, 1.0, 1.0); - - if( basegfx::fTools::equalZero( fRotate ) ) - { - aOutlineRange.transform( aLocalTransform ); - } - else - { - // !!! TODO - // if rotated, create the unrotated output rectangle for the GraphicManager paint - /* - const basegfx::B2DHomMatrix aSimpleObjectMatrix(basegfx::tools::createScaleTranslateB2DHomMatrix( - fabs(aScale.getX()), fabs(aScale.getY()), - aTranslate.getX(), aTranslate.getY())); - - aOutlineRange.transform(aSimpleObjectMatrix); - */ - } - - // prepare dest coordinates - const Point aPoint( basegfx::fround(aOutlineRange.getMinX() ), - basegfx::fround(aOutlineRange.getMinY() ) ); - const Size aSize( basegfx::fround(aOutlineRange.getWidth() ), - basegfx::fround(aOutlineRange.getHeight() ) ); - const Size aSizePixel( mpOutputDevice->LogicToPixel( aSize ) ); - const vcl::RenderGraphicRasterizer aRasterizer( aRenderGraphic ); - const BitmapEx aBitmapEx( aRasterizer.Rasterize( aSizePixel, fRotate, fShearX ) ); - - if( !aBitmapEx.IsEmpty() ) - { - mpOutputDevice->DrawBitmapEx( aPoint, aSize, aBitmapEx ); - } - } - } - void VclProcessor2D::RenderFillBitmapPrimitive2D(const primitive2d::FillBitmapPrimitive2D& rFillBitmapCandidate) { const attribute::FillBitmapAttribute& rFillBitmapAttribute(rFillBitmapCandidate.getFillBitmap()); diff --git a/drawinglayer/source/processor3d/shadow3dextractor.cxx b/drawinglayer/source/processor3d/shadow3dextractor.cxx index 572610805e4c..497c020f5894 100644 --- a/drawinglayer/source/processor3d/shadow3dextractor.cxx +++ b/drawinglayer/source/processor3d/shadow3dextractor.cxx @@ -47,25 +47,6 @@ namespace drawinglayer { namespace processor3d { - /// helper to convert from BasePrimitive2DVector to primitive2d::Primitive2DSequence - const primitive2d::Primitive2DSequence Shadow3DExtractingProcessor::getPrimitive2DSequenceFromBasePrimitive2DVector( - const BasePrimitive2DVector& rVector) const - { - const sal_uInt32 nCount(rVector.size()); - primitive2d::Primitive2DSequence aRetval(nCount); - - for(sal_uInt32 a(0); a < nCount; a++) - { - aRetval[a] = rVector[a]; - } - - // all entries taken over; no need to delete entries, just reset to - // mark as empty - const_cast< BasePrimitive2DVector& >(rVector).clear(); - - return aRetval; - } - // as tooling, the process() implementation takes over API handling and calls this // virtual render method when the primitive implementation is BasePrimitive3D-based. void Shadow3DExtractingProcessor::processBasePrimitive3D(const primitive3d::BasePrimitive3D& rCandidate) @@ -79,8 +60,8 @@ namespace drawinglayer const primitive3d::ShadowPrimitive3D& rPrimitive = static_cast< const primitive3d::ShadowPrimitive3D& >(rCandidate); // set new target - BasePrimitive2DVector aNewSubList; - BasePrimitive2DVector* pLastTargetSequence = mpPrimitive2DSequence; + primitive2d::Primitive2DVector aNewSubList; + primitive2d::Primitive2DVector* pLastTargetSequence = mpPrimitive2DSequence; mpPrimitive2DSequence = &aNewSubList; // activate convert @@ -104,7 +85,7 @@ namespace drawinglayer primitive2d::BasePrimitive2D* pNew = new primitive2d::ShadowPrimitive2D( rPrimitive.getShadowTransform(), rPrimitive.getShadowColor(), - getPrimitive2DSequenceFromBasePrimitive2DVector(aNewSubList)); + primitive2d::Primitive2DVectorToPrimitive2DSequence(aNewSubList)); if(basegfx::fTools::more(rPrimitive.getShadowTransparence(), 0.0)) { @@ -328,7 +309,7 @@ namespace drawinglayer const primitive2d::Primitive2DSequence Shadow3DExtractingProcessor::getPrimitive2DSequence() const { - return getPrimitive2DSequenceFromBasePrimitive2DVector(maPrimitive2DSequence); + return Primitive2DVectorToPrimitive2DSequence(maPrimitive2DSequence); } } // end of namespace processor3d diff --git a/drawinglayer/source/tools/converters.cxx b/drawinglayer/source/tools/converters.cxx new file mode 100644 index 000000000000..a7d22a5df698 --- /dev/null +++ b/drawinglayer/source/tools/converters.cxx @@ -0,0 +1,143 @@ +/************************************************************** + * + * 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/tools/converters.hxx> +#include <drawinglayer/geometry/viewinformation2d.hxx> +#include <drawinglayer/processor2d/vclpixelprocessor2d.hxx> +#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <drawinglayer/primitive2d/transformprimitive2d.hxx> +#include <vcl/virdev.hxx> + +#ifdef DBG_UTIL +#include <tools/stream.hxx> +#endif + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace tools + { + BitmapEx DRAWINGLAYER_DLLPUBLIC convertToBitmapEx( + const drawinglayer::primitive2d::Primitive2DSequence& rSeq, + const geometry::ViewInformation2D& rViewInformation2D, + sal_uInt32 nDiscreteWidth, + sal_uInt32 nDiscreteHeight, + sal_uInt32 nMaxQuadratPixels) + { + BitmapEx aRetval; + + if(rSeq.hasElements() && nDiscreteWidth && nDiscreteHeight) + { + // get destination size in pixels + const MapMode aMapModePixel(MAP_PIXEL); + const sal_uInt32 nViewVisibleArea(nDiscreteWidth * nDiscreteHeight); + double fReduceFactor(1.0); + drawinglayer::primitive2d::Primitive2DSequence aSequence(rSeq); + + if(nViewVisibleArea > nMaxQuadratPixels) + { + // reduce render size + fReduceFactor = sqrt((double)nMaxQuadratPixels / (double)nViewVisibleArea); + nDiscreteWidth = basegfx::fround((double)nDiscreteWidth * fReduceFactor); + nDiscreteHeight = basegfx::fround((double)nDiscreteHeight * fReduceFactor); + + const drawinglayer::primitive2d::Primitive2DReference aEmbed( + new drawinglayer::primitive2d::TransformPrimitive2D( + basegfx::tools::createScaleB2DHomMatrix(fReduceFactor, fReduceFactor), + rSeq)); + + aSequence = drawinglayer::primitive2d::Primitive2DSequence(&aEmbed, 1); + } + + const Point aEmptyPoint; + const Size aSizePixel(nDiscreteWidth, nDiscreteHeight); + geometry::ViewInformation2D aViewInformation2D(rViewInformation2D); + VirtualDevice maContent; + + // prepare vdev + maContent.SetOutputSizePixel(aSizePixel, false); + maContent.SetMapMode(aMapModePixel); + maContent.SetAntialiasing(true); + + // set to all white + maContent.SetBackground(Wallpaper(Color(COL_WHITE))); + maContent.Erase(); + + // create processor + processor2d::VclPixelProcessor2D aContentProcessor(aViewInformation2D, maContent); + + // render content + aContentProcessor.process(aSequence); + + // get content + maContent.EnableMapMode(false); + const Bitmap aContent(maContent.GetBitmap(aEmptyPoint, aSizePixel)); + + // prepare for mask creation + maContent.SetMapMode(aMapModePixel); + maContent.SetAntialiasing(true); + + // set alpha to all white (fully transparent) + maContent.Erase(); + + // embed primitives to paint them black + const primitive2d::Primitive2DReference xRef( + new primitive2d::ModifiedColorPrimitive2D( + aSequence, + basegfx::BColorModifier( + basegfx::BColor(0.0, 0.0, 0.0), + 0.5, + basegfx::BCOLORMODIFYMODE_REPLACE))); + const primitive2d::Primitive2DSequence xSeq(&xRef, 1); + + // render + aContentProcessor.process(xSeq); + + // get alpha cahannel from vdev + maContent.EnableMapMode(false); + const AlphaMask aAlphaMask(maContent.GetBitmap(aEmptyPoint, aSizePixel)); + + // create BitmapEx result + aRetval = BitmapEx(aContent, aAlphaMask); + } + +#ifdef DBG_UTIL + static bool bDoSaveForVisualControl(false); + if(bDoSaveForVisualControl) + { + SvFileStream aNew((const String&)String(ByteString( "c:\\test.png" ), RTL_TEXTENCODING_UTF8), STREAM_WRITE|STREAM_TRUNC); + aNew << aRetval; + } +#endif + + return aRetval; + } + + } // end of namespace tools +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof |