summaryrefslogtreecommitdiff
path: root/drawinglayer/source/primitive2d
diff options
context:
space:
mode:
Diffstat (limited to 'drawinglayer/source/primitive2d')
-rw-r--r--drawinglayer/source/primitive2d/animatedprimitive2d.cxx227
-rw-r--r--drawinglayer/source/primitive2d/backgroundcolorprimitive2d.cxx119
-rw-r--r--drawinglayer/source/primitive2d/baseprimitive2d.cxx281
-rw-r--r--drawinglayer/source/primitive2d/bitmapprimitive2d.cxx84
-rw-r--r--drawinglayer/source/primitive2d/borderlineprimitive2d.cxx257
-rw-r--r--drawinglayer/source/primitive2d/chartprimitive2d.cxx85
-rw-r--r--drawinglayer/source/primitive2d/controlprimitive2d.cxx386
-rw-r--r--drawinglayer/source/primitive2d/discretebitmapprimitive2d.cxx119
-rw-r--r--drawinglayer/source/primitive2d/embedded3dprimitive2d.cxx171
-rw-r--r--drawinglayer/source/primitive2d/epsprimitive2d.cxx106
-rw-r--r--drawinglayer/source/primitive2d/fillbitmapprimitive2d.cxx145
-rw-r--r--drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx301
-rw-r--r--drawinglayer/source/primitive2d/fillhatchprimitive2d.cxx164
-rw-r--r--drawinglayer/source/primitive2d/graphicprimitive2d.cxx945
-rw-r--r--drawinglayer/source/primitive2d/gridprimitive2d.cxx323
-rw-r--r--drawinglayer/source/primitive2d/groupprimitive2d.cxx82
-rw-r--r--drawinglayer/source/primitive2d/helplineprimitive2d.cxx225
-rw-r--r--drawinglayer/source/primitive2d/hiddengeometryprimitive2d.cxx78
-rw-r--r--drawinglayer/source/primitive2d/invertprimitive2d.cxx60
-rw-r--r--drawinglayer/source/primitive2d/makefile.mk89
-rw-r--r--drawinglayer/source/primitive2d/markerarrayprimitive2d.cxx160
-rw-r--r--drawinglayer/source/primitive2d/maskprimitive2d.cxx79
-rw-r--r--drawinglayer/source/primitive2d/mediaprimitive2d.cxx166
-rw-r--r--drawinglayer/source/primitive2d/metafileprimitive2d.cxx3259
-rw-r--r--drawinglayer/source/primitive2d/modifiedcolorprimitive2d.cxx74
-rw-r--r--drawinglayer/source/primitive2d/pagepreviewprimitive2d.cxx186
-rw-r--r--drawinglayer/source/primitive2d/pointarrayprimitive2d.cxx96
-rw-r--r--drawinglayer/source/primitive2d/polygonprimitive2d.cxx642
-rw-r--r--drawinglayer/source/primitive2d/polypolygonprimitive2d.cxx575
-rw-r--r--drawinglayer/source/primitive2d/primitivetools2d.cxx173
-rw-r--r--drawinglayer/source/primitive2d/sceneprimitive2d.cxx483
-rw-r--r--drawinglayer/source/primitive2d/sdrdecompositiontools2d.cxx133
-rw-r--r--drawinglayer/source/primitive2d/shadowprimitive2d.cxx109
-rw-r--r--drawinglayer/source/primitive2d/structuretagprimitive2d.cxx62
-rw-r--r--drawinglayer/source/primitive2d/textdecoratedprimitive2d.cxx610
-rw-r--r--drawinglayer/source/primitive2d/texteffectprimitive2d.cxx242
-rw-r--r--drawinglayer/source/primitive2d/textenumsprimitive2d.cxx124
-rw-r--r--drawinglayer/source/primitive2d/texthierarchyprimitive2d.cxx161
-rw-r--r--drawinglayer/source/primitive2d/textlayoutdevice.cxx496
-rw-r--r--drawinglayer/source/primitive2d/textlineprimitive2d.cxx312
-rw-r--r--drawinglayer/source/primitive2d/textprimitive2d.cxx348
-rw-r--r--drawinglayer/source/primitive2d/textstrikeoutprimitive2d.cxx289
-rw-r--r--drawinglayer/source/primitive2d/transformprimitive2d.cxx82
-rw-r--r--drawinglayer/source/primitive2d/transparenceprimitive2d.cxx81
-rw-r--r--drawinglayer/source/primitive2d/unifiedtransparenceprimitive2d.cxx139
-rw-r--r--drawinglayer/source/primitive2d/wallpaperprimitive2d.cxx272
-rw-r--r--drawinglayer/source/primitive2d/wrongspellprimitive2d.cxx125
47 files changed, 13725 insertions, 0 deletions
diff --git a/drawinglayer/source/primitive2d/animatedprimitive2d.cxx b/drawinglayer/source/primitive2d/animatedprimitive2d.cxx
new file mode 100644
index 000000000000..75544c00792f
--- /dev/null
+++ b/drawinglayer/source/primitive2d/animatedprimitive2d.cxx
@@ -0,0 +1,227 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/animatedprimitive2d.hxx>
+#include <drawinglayer/animation/animationtiming.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ AnimatedSwitchPrimitive2D::AnimatedSwitchPrimitive2D(
+ const animation::AnimationEntry& rAnimationEntry,
+ const Primitive2DSequence& rChildren,
+ bool bIsTextAnimation)
+ : GroupPrimitive2D(rChildren),
+ mpAnimationEntry(0),
+ mbIsTextAnimation(bIsTextAnimation)
+ {
+ // clone given animation description
+ mpAnimationEntry = rAnimationEntry.clone();
+ }
+
+ AnimatedSwitchPrimitive2D::~AnimatedSwitchPrimitive2D()
+ {
+ // delete cloned animation description
+ delete mpAnimationEntry;
+ }
+
+ bool AnimatedSwitchPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(GroupPrimitive2D::operator==(rPrimitive))
+ {
+ const AnimatedSwitchPrimitive2D& rCompare = static_cast< const AnimatedSwitchPrimitive2D& >(rPrimitive);
+
+ return (getAnimationEntry() == rCompare.getAnimationEntry());
+ }
+
+ return false;
+ }
+
+ Primitive2DSequence AnimatedSwitchPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ if(getChildren().hasElements())
+ {
+ const double fState(getAnimationEntry().getStateAtTime(rViewInformation.getViewTime()));
+ const sal_uInt32 nLen(getChildren().getLength());
+ sal_uInt32 nIndex(basegfx::fround(fState * (double)nLen));
+
+ if(nIndex >= nLen)
+ {
+ nIndex = nLen - 1L;
+ }
+
+ const Primitive2DReference xRef(getChildren()[nIndex], uno::UNO_QUERY_THROW);
+ return Primitive2DSequence(&xRef, 1L);
+ }
+
+ return Primitive2DSequence();
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(AnimatedSwitchPrimitive2D, PRIMITIVE2D_ID_ANIMATEDSWITCHPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ AnimatedBlinkPrimitive2D::AnimatedBlinkPrimitive2D(
+ const animation::AnimationEntry& rAnimationEntry,
+ const Primitive2DSequence& rChildren,
+ bool bIsTextAnimation)
+ : AnimatedSwitchPrimitive2D(rAnimationEntry, rChildren, bIsTextAnimation)
+ {
+ }
+
+ Primitive2DSequence AnimatedBlinkPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ if(getChildren().hasElements())
+ {
+ const double fState(getAnimationEntry().getStateAtTime(rViewInformation.getViewTime()));
+
+ if(fState < 0.5)
+ {
+ return getChildren();
+ }
+ }
+
+ return Primitive2DSequence();
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(AnimatedBlinkPrimitive2D, PRIMITIVE2D_ID_ANIMATEDBLINKPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ AnimatedInterpolatePrimitive2D::AnimatedInterpolatePrimitive2D(
+ const std::vector< basegfx::B2DHomMatrix >& rmMatrixStack,
+ const animation::AnimationEntry& rAnimationEntry,
+ const Primitive2DSequence& rChildren,
+ bool bIsTextAnimation)
+ : AnimatedSwitchPrimitive2D(rAnimationEntry, rChildren, bIsTextAnimation),
+ maMatrixStack()
+ {
+ // copy matrices to locally pre-decomposed matrix stack
+ const sal_uInt32 nCount(rmMatrixStack.size());
+ maMatrixStack.reserve(nCount);
+
+ for(sal_uInt32 a(0L); a < nCount; a++)
+ {
+ maMatrixStack.push_back(basegfx::tools::B2DHomMatrixBufferedDecompose(rmMatrixStack[a]));
+ }
+ }
+
+ Primitive2DSequence AnimatedInterpolatePrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ const sal_uInt32 nSize(maMatrixStack.size());
+
+ if(nSize)
+ {
+ double fState(getAnimationEntry().getStateAtTime(rViewInformation.getViewTime()));
+
+ if(fState < 0.0)
+ {
+ fState = 0.0;
+ }
+ else if(fState > 1.0)
+ {
+ fState = 1.0;
+ }
+
+ const double fIndex(fState * (double)(nSize - 1L));
+ const sal_uInt32 nIndA(sal_uInt32(floor(fIndex)));
+ const double fOffset(fIndex - (double)nIndA);
+ basegfx::B2DHomMatrix aTargetTransform;
+ std::vector< basegfx::tools::B2DHomMatrixBufferedDecompose >::const_iterator aMatA(maMatrixStack.begin() + nIndA);
+
+ if(basegfx::fTools::equalZero(fOffset))
+ {
+ // use matrix from nIndA directly
+ aTargetTransform = aMatA->getB2DHomMatrix();
+ }
+ else
+ {
+ // interpolate. Get involved buffered decomposed matrices
+ const sal_uInt32 nIndB((nIndA + 1L) % nSize);
+ std::vector< basegfx::tools::B2DHomMatrixBufferedDecompose >::const_iterator aMatB(maMatrixStack.begin() + nIndB);
+
+ // interpolate for fOffset [0.0 .. 1.0[
+ const basegfx::B2DVector aScale(basegfx::interpolate(aMatA->getScale(), aMatB->getScale(), fOffset));
+ const basegfx::B2DVector aTranslate(basegfx::interpolate(aMatA->getTranslate(), aMatB->getTranslate(), fOffset));
+ const double fRotate(((aMatB->getRotate() - aMatA->getRotate()) * fOffset) + aMatA->getRotate());
+ const double fShearX(((aMatB->getShearX() - aMatA->getShearX()) * fOffset) + aMatA->getShearX());
+
+ // build matrix for state
+ aTargetTransform = basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
+ aScale, fShearX, fRotate, aTranslate);
+ }
+
+ // create new transform primitive reference, return new sequence
+ const Primitive2DReference xRef(new TransformPrimitive2D(aTargetTransform, getChildren()));
+ return Primitive2DSequence(&xRef, 1L);
+ }
+ else
+ {
+ return getChildren();
+ }
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(AnimatedInterpolatePrimitive2D, PRIMITIVE2D_ID_ANIMATEDINTERPOLATEPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/backgroundcolorprimitive2d.cxx b/drawinglayer/source/primitive2d/backgroundcolorprimitive2d.cxx
new file mode 100644
index 000000000000..fd73f52ccfdb
--- /dev/null
+++ b/drawinglayer/source/primitive2d/backgroundcolorprimitive2d.cxx
@@ -0,0 +1,119 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/backgroundcolorprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
+#include <basegfx/tools/canvastools.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence BackgroundColorPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ if(!rViewInformation.getViewport().isEmpty())
+ {
+ const basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(rViewInformation.getViewport()));
+ const Primitive2DReference xRef(new PolyPolygonColorPrimitive2D(basegfx::B2DPolyPolygon(aOutline), getBColor()));
+ return Primitive2DSequence(&xRef, 1L);
+ }
+ else
+ {
+ return Primitive2DSequence();
+ }
+ }
+
+ BackgroundColorPrimitive2D::BackgroundColorPrimitive2D(
+ const basegfx::BColor& rBColor)
+ : BufferedDecompositionPrimitive2D(),
+ maBColor(rBColor),
+ maLastViewport()
+ {
+ }
+
+ bool BackgroundColorPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const BackgroundColorPrimitive2D& rCompare = (BackgroundColorPrimitive2D&)rPrimitive;
+
+ return (getBColor() == rCompare.getBColor());
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange BackgroundColorPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ // always as big as the view
+ return rViewInformation.getViewport();
+ }
+
+ Primitive2DSequence BackgroundColorPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if(getBuffered2DDecomposition().hasElements() && (maLastViewport != rViewInformation.getViewport()))
+ {
+ // conditions of last local decomposition have changed, delete
+ const_cast< BackgroundColorPrimitive2D* >(this)->setBuffered2DDecomposition(Primitive2DSequence());
+ }
+
+ if(!getBuffered2DDecomposition().hasElements())
+ {
+ // remember ViewRange
+ const_cast< BackgroundColorPrimitive2D* >(this)->maLastViewport = rViewInformation.getViewport();
+ }
+
+ // use parent implementation
+ return BufferedDecompositionPrimitive2D::get2DDecomposition(rViewInformation);
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(BackgroundColorPrimitive2D, PRIMITIVE2D_ID_BACKGROUNDCOLORPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/baseprimitive2d.cxx b/drawinglayer/source/primitive2d/baseprimitive2d.cxx
new file mode 100644
index 000000000000..f655fec22972
--- /dev/null
+++ b/drawinglayer/source/primitive2d/baseprimitive2d.cxx
@@ -0,0 +1,281 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/baseprimitive2d.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <basegfx/tools/canvastools.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ BasePrimitive2D::BasePrimitive2D()
+ : BasePrimitive2DImplBase(m_aMutex)
+ {
+ }
+
+ BasePrimitive2D::~BasePrimitive2D()
+ {
+ }
+
+ bool BasePrimitive2D::operator==( const BasePrimitive2D& rPrimitive ) const
+ {
+ return (getPrimitive2DID() == rPrimitive.getPrimitive2DID());
+ }
+
+ basegfx::B2DRange BasePrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ return getB2DRangeFromPrimitive2DSequence(get2DDecomposition(rViewInformation), rViewInformation);
+ }
+
+ Primitive2DSequence BasePrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ return Primitive2DSequence();
+ }
+
+ Primitive2DSequence SAL_CALL BasePrimitive2D::getDecomposition( const uno::Sequence< beans::PropertyValue >& rViewParameters ) throw ( uno::RuntimeException )
+ {
+ const geometry::ViewInformation2D aViewInformation(rViewParameters);
+ return get2DDecomposition(aViewInformation);
+ }
+
+ com::sun::star::geometry::RealRectangle2D SAL_CALL BasePrimitive2D::getRange( const uno::Sequence< beans::PropertyValue >& rViewParameters ) throw ( uno::RuntimeException )
+ {
+ const geometry::ViewInformation2D aViewInformation(rViewParameters);
+ return basegfx::unotools::rectangle2DFromB2DRectangle(getB2DRange(aViewInformation));
+ }
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence BufferedDecompositionPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ return Primitive2DSequence();
+ }
+
+ BufferedDecompositionPrimitive2D::BufferedDecompositionPrimitive2D()
+ : BasePrimitive2D(),
+ maBuffered2DDecomposition()
+ {
+ }
+
+ Primitive2DSequence BufferedDecompositionPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if(!getBuffered2DDecomposition().hasElements())
+ {
+ const Primitive2DSequence aNewSequence(create2DDecomposition(rViewInformation));
+ const_cast< BufferedDecompositionPrimitive2D* >(this)->setBuffered2DDecomposition(aNewSequence);
+ }
+
+ return getBuffered2DDecomposition();
+ }
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// tooling
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ // get B2DRange from a given Primitive2DReference
+ basegfx::B2DRange getB2DRangeFromPrimitive2DReference(const Primitive2DReference& rCandidate, const geometry::ViewInformation2D& aViewInformation)
+ {
+ basegfx::B2DRange aRetval;
+
+ if(rCandidate.is())
+ {
+ // try to get C++ implementation base
+ const BasePrimitive2D* pCandidate(dynamic_cast< BasePrimitive2D* >(rCandidate.get()));
+
+ if(pCandidate)
+ {
+ // use it if possible
+ aRetval.expand(pCandidate->getB2DRange(aViewInformation));
+ }
+ else
+ {
+ // use UNO API call instead
+ const uno::Sequence< beans::PropertyValue >& rViewParameters(aViewInformation.getViewInformationSequence());
+ aRetval.expand(basegfx::unotools::b2DRectangleFromRealRectangle2D(rCandidate->getRange(rViewParameters)));
+ }
+ }
+
+ return aRetval;
+ }
+
+ // get B2DRange from a given Primitive2DSequence
+ basegfx::B2DRange getB2DRangeFromPrimitive2DSequence(const Primitive2DSequence& rCandidate, const geometry::ViewInformation2D& aViewInformation)
+ {
+ basegfx::B2DRange aRetval;
+
+ if(rCandidate.hasElements())
+ {
+ const sal_Int32 nCount(rCandidate.getLength());
+
+ for(sal_Int32 a(0L); a < nCount; a++)
+ {
+ aRetval.expand(getB2DRangeFromPrimitive2DReference(rCandidate[a], aViewInformation));
+ }
+ }
+
+ return aRetval;
+ }
+
+ bool arePrimitive2DReferencesEqual(const Primitive2DReference& rxA, const Primitive2DReference& rxB)
+ {
+ const sal_Bool bAIs(rxA.is());
+
+ if(bAIs != rxB.is())
+ {
+ return false;
+ }
+
+ if(!bAIs)
+ {
+ return true;
+ }
+
+ const BasePrimitive2D* pA(dynamic_cast< const BasePrimitive2D* >(rxA.get()));
+ const BasePrimitive2D* pB(dynamic_cast< const BasePrimitive2D* >(rxB.get()));
+ const bool bAEqualZero(pA == 0L);
+
+ if(bAEqualZero != (pB == 0L))
+ {
+ return false;
+ }
+
+ if(bAEqualZero)
+ {
+ return false;
+ }
+
+ return (pA->operator==(*pB));
+ }
+
+ bool arePrimitive2DSequencesEqual(const Primitive2DSequence& rA, const Primitive2DSequence& rB)
+ {
+ const sal_Bool bAHasElements(rA.hasElements());
+
+ if(bAHasElements != rB.hasElements())
+ {
+ return false;
+ }
+
+ if(!bAHasElements)
+ {
+ return true;
+ }
+
+ const sal_Int32 nCount(rA.getLength());
+
+ if(nCount != rB.getLength())
+ {
+ return false;
+ }
+
+ for(sal_Int32 a(0L); a < nCount; a++)
+ {
+ if(!arePrimitive2DReferencesEqual(rA[a], rB[a]))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ // concatenate sequence
+ void appendPrimitive2DSequenceToPrimitive2DSequence(Primitive2DSequence& rDest, const Primitive2DSequence& rSource)
+ {
+ if(rSource.hasElements())
+ {
+ if(rDest.hasElements())
+ {
+ const sal_Int32 nSourceCount(rSource.getLength());
+ const sal_Int32 nDestCount(rDest.getLength());
+ const sal_Int32 nTargetCount(nSourceCount + nDestCount);
+ sal_Int32 nInsertPos(nDestCount);
+
+ rDest.realloc(nTargetCount);
+
+ for(sal_Int32 a(0L); a < nSourceCount; a++)
+ {
+ if(rSource[a].is())
+ {
+ rDest[nInsertPos++] = rSource[a];
+ }
+ }
+
+ if(nInsertPos != nTargetCount)
+ {
+ rDest.realloc(nInsertPos);
+ }
+ }
+ else
+ {
+ rDest = rSource;
+ }
+ }
+ }
+
+ // concatenate single Primitive2D
+ void appendPrimitive2DReferenceToPrimitive2DSequence(Primitive2DSequence& rDest, const Primitive2DReference& rSource)
+ {
+ if(rSource.is())
+ {
+ const sal_Int32 nDestCount(rDest.getLength());
+ rDest.realloc(nDestCount + 1L);
+ rDest[nDestCount] = rSource;
+ }
+ }
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/bitmapprimitive2d.cxx b/drawinglayer/source/primitive2d/bitmapprimitive2d.cxx
new file mode 100644
index 000000000000..3efbd0de0223
--- /dev/null
+++ b/drawinglayer/source/primitive2d/bitmapprimitive2d.cxx
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
+#include <basegfx/tools/canvastools.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ BitmapPrimitive2D::BitmapPrimitive2D(
+ const BitmapEx& rBitmapEx,
+ const basegfx::B2DHomMatrix& rTransform)
+ : BasePrimitive2D(),
+ maBitmapEx(rBitmapEx),
+ maTransform(rTransform)
+ {
+ }
+
+ bool BitmapPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BasePrimitive2D::operator==(rPrimitive))
+ {
+ const BitmapPrimitive2D& rCompare = (BitmapPrimitive2D&)rPrimitive;
+
+ return (getBitmapEx() == rCompare.getBitmapEx()
+ && getTransform() == rCompare.getTransform());
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange BitmapPrimitive2D::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(BitmapPrimitive2D, PRIMITIVE2D_ID_BITMAPPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
new file mode 100644
index 000000000000..cb026ccf6caf
--- /dev/null
+++ b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
@@ -0,0 +1,257 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/borderlineprimitive2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
+#include <svtools/borderhelper.hxx>
+#include <numeric>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence BorderLinePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ Primitive2DSequence xRetval;
+
+ if(!getStart().equal(getEnd()) && (getCreateInside() || getCreateOutside()))
+ {
+ if(isInsideUsed())
+ {
+ // get data and vectors
+ const double fWidth(getWidth());
+ basegfx::B2DVector aVector(getEnd() - getStart());
+ aVector.normalize();
+ const basegfx::B2DVector aPerpendicular(basegfx::getPerpendicular(aVector));
+
+ if(isOutsideUsed())
+ {
+ // both used, double line definition. Create left and right offset
+ xRetval.realloc(getCreateInside() && getCreateOutside() ? 2 : 1);
+ sal_uInt32 nInsert(0);
+
+ if(getCreateInside())
+ {
+ // create geometry for left
+ const basegfx::B2DVector aLeftOff(aPerpendicular * (0.5 * (getCorrectedLeftWidth() - fWidth)));
+ const basegfx::B2DPoint aTmpStart(getStart() + aLeftOff - (getExtendInnerStart() * aVector));
+ const basegfx::B2DPoint aTmpEnd(getEnd() + aLeftOff + (getExtendInnerEnd() * aVector));
+ basegfx::B2DPolygon aLeft;
+
+ if(leftIsHairline())
+ {
+ // create hairline primitive
+ aLeft.append(aTmpStart);
+ aLeft.append(aTmpEnd);
+
+ xRetval[nInsert++] = Primitive2DReference(new PolygonHairlinePrimitive2D(
+ aLeft,
+ getRGBColor()));
+ }
+ else
+ {
+ // create filled polygon primitive. Already tried to create thick lines
+ // with the correct LineWidth, but this leads to problems when no AA
+ // is available and fat line special case reductions between 0.5 < x < 2.5 line widths
+ // are executed due to the FilledPolygon-do-not-paint-their-bottom-and-right-lines.
+ const basegfx::B2DVector aLineWidthOffset((getCorrectedLeftWidth() * 0.5) * aPerpendicular);
+
+ aLeft.append(aTmpStart + aLineWidthOffset);
+ aLeft.append(aTmpEnd + aLineWidthOffset);
+ aLeft.append(aTmpEnd - aLineWidthOffset);
+ aLeft.append(aTmpStart - aLineWidthOffset);
+ aLeft.setClosed(true);
+
+ xRetval[nInsert++] = Primitive2DReference(new PolyPolygonColorPrimitive2D(
+ basegfx::B2DPolyPolygon(aLeft), getRGBColor()));
+ }
+ }
+
+ if(getCreateOutside())
+ {
+ // create geometry for right
+ const basegfx::B2DVector aRightOff(aPerpendicular * (0.5 * (fWidth - getCorrectedRightWidth())));
+ const basegfx::B2DPoint aTmpStart(getStart() + aRightOff - (getExtendOuterStart() * aVector));
+ const basegfx::B2DPoint aTmpEnd(getEnd() + aRightOff + (getExtendOuterEnd() * aVector));
+ basegfx::B2DPolygon aRight;
+
+ if(rightIsHairline())
+ {
+ // create hairline primitive
+ aRight.append(aTmpStart);
+ aRight.append(aTmpEnd);
+
+ xRetval[nInsert++] = Primitive2DReference(new PolygonHairlinePrimitive2D(
+ aRight,
+ getRGBColor()));
+ }
+ else
+ {
+ // create filled polygon primitive
+ const basegfx::B2DVector aLineWidthOffset((getCorrectedRightWidth() * 0.5) * aPerpendicular);
+
+ aRight.append(aTmpStart + aLineWidthOffset);
+ aRight.append(aTmpEnd + aLineWidthOffset);
+ aRight.append(aTmpEnd - aLineWidthOffset);
+ aRight.append(aTmpStart - aLineWidthOffset);
+ aRight.setClosed(true);
+
+ xRetval[nInsert++] = Primitive2DReference(new PolyPolygonColorPrimitive2D(
+ basegfx::B2DPolyPolygon(aRight), getRGBColor()));
+ }
+ }
+ }
+ else
+ {
+ // single line, create geometry
+ basegfx::B2DPolygon aPolygon;
+ const double fMaxExtStart(::std::max(getExtendInnerStart(), getExtendOuterStart()));
+ const double fMaxExtEnd(::std::max(getExtendInnerEnd(), getExtendOuterEnd()));
+ const basegfx::B2DPoint aTmpStart(getStart() - (fMaxExtStart * aVector));
+ const basegfx::B2DPoint aTmpEnd(getEnd() + (fMaxExtEnd * aVector));
+ xRetval.realloc(1);
+
+ if(leftIsHairline())
+ {
+ // create hairline primitive
+ aPolygon.append(aTmpStart);
+ aPolygon.append(aTmpEnd);
+
+ xRetval[0] = Primitive2DReference(new PolygonHairlinePrimitive2D(
+ aPolygon,
+ getRGBColor()));
+ }
+ else
+ {
+ // create filled polygon primitive
+ const basegfx::B2DVector aLineWidthOffset((getCorrectedLeftWidth() * 0.5) * aPerpendicular);
+
+ aPolygon.append( aTmpStart );
+ aPolygon.append( aTmpEnd );
+
+ basegfx::B2DPolyPolygon aDashed = svtools::ApplyLineDashing(
+ aPolygon, getStyle(), MAP_100TH_MM );
+ for (sal_uInt32 i = 0; i < aDashed.count(); i++ )
+ {
+ basegfx::B2DPolygon aDash = aDashed.getB2DPolygon( i );
+ basegfx::B2DPoint aDashStart = aDash.getB2DPoint( 0 );
+ basegfx::B2DPoint aDashEnd = aDash.getB2DPoint( aDash.count() - 1 );
+
+ basegfx::B2DPolygon aDashPolygon;
+ aDashPolygon.append( aDashStart + aLineWidthOffset );
+ aDashPolygon.append( aDashEnd + aLineWidthOffset );
+ aDashPolygon.append( aDashEnd - aLineWidthOffset );
+ aDashPolygon.append( aDashStart - aLineWidthOffset );
+ aDashPolygon.setClosed( true );
+
+ aDashed.setB2DPolygon( i, aDashPolygon );
+ }
+
+ xRetval[0] = Primitive2DReference(new PolyPolygonColorPrimitive2D(
+ basegfx::B2DPolyPolygon( aDashed ), getRGBColor()));
+ }
+ }
+ }
+ }
+
+ return xRetval;
+ }
+
+ BorderLinePrimitive2D::BorderLinePrimitive2D(
+ const basegfx::B2DPoint& rStart,
+ const basegfx::B2DPoint& rEnd,
+ double fLeftWidth,
+ double fDistance,
+ double fRightWidth,
+ double fExtendInnerStart,
+ double fExtendInnerEnd,
+ double fExtendOuterStart,
+ double fExtendOuterEnd,
+ bool bCreateInside,
+ bool bCreateOutside,
+ const basegfx::BColor& rRGBColor,
+ const short nStyle)
+ : BufferedDecompositionPrimitive2D(),
+ maStart(rStart),
+ maEnd(rEnd),
+ mfLeftWidth(fLeftWidth),
+ mfDistance(fDistance),
+ mfRightWidth(fRightWidth),
+ mfExtendInnerStart(fExtendInnerStart),
+ mfExtendInnerEnd(fExtendInnerEnd),
+ mfExtendOuterStart(fExtendOuterStart),
+ mfExtendOuterEnd(fExtendOuterEnd),
+ maRGBColor(rRGBColor),
+ mnStyle(nStyle),
+ mbCreateInside(bCreateInside),
+ mbCreateOutside(bCreateOutside)
+ {
+ }
+
+ bool BorderLinePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const BorderLinePrimitive2D& rCompare = (BorderLinePrimitive2D&)rPrimitive;
+
+ return (getStart() == rCompare.getStart()
+ && getEnd() == rCompare.getEnd()
+ && getLeftWidth() == rCompare.getLeftWidth()
+ && getDistance() == rCompare.getDistance()
+ && getRightWidth() == rCompare.getRightWidth()
+ && getExtendInnerStart() == rCompare.getExtendInnerStart()
+ && getExtendInnerEnd() == rCompare.getExtendInnerEnd()
+ && getExtendOuterStart() == rCompare.getExtendOuterStart()
+ && getExtendOuterEnd() == rCompare.getExtendOuterEnd()
+ && getCreateInside() == rCompare.getCreateInside()
+ && getCreateOutside() == rCompare.getCreateOutside()
+ && getRGBColor() == rCompare.getRGBColor()
+ && getStyle() == rCompare.getStyle());
+ }
+
+ return false;
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(BorderLinePrimitive2D, PRIMITIVE2D_ID_BORDERLINEPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/chartprimitive2d.cxx b/drawinglayer/source/primitive2d/chartprimitive2d.cxx
new file mode 100644
index 000000000000..23957295df55
--- /dev/null
+++ b/drawinglayer/source/primitive2d/chartprimitive2d.cxx
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/chartprimitive2d.hxx>
+#include <basegfx/tools/canvastools.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ ChartPrimitive2D::ChartPrimitive2D(
+ const uno::Reference< frame::XModel >& rxChartModel,
+ const basegfx::B2DHomMatrix& rTransformation,
+ const Primitive2DSequence& rChildren)
+ : GroupPrimitive2D(rChildren),
+ mxChartModel(rxChartModel),
+ maTransformation(rTransformation)
+ {
+ }
+
+ bool ChartPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(GroupPrimitive2D::operator==(rPrimitive))
+ {
+ const ChartPrimitive2D& rCompare = static_cast< const ChartPrimitive2D& >(rPrimitive);
+
+ return (getChartModel() == rCompare.getChartModel()
+ && getTransformation() == rCompare.getTransformation());
+ }
+
+ return false;
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(ChartPrimitive2D, PRIMITIVE2D_ID_CHARTPRIMITIVE2D)
+
+ basegfx::B2DRange ChartPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ basegfx::B2DRange aRetval(0.0, 0.0, 1.0, 1.0);
+ aRetval.transform(getTransformation());
+ return aRetval;
+ }
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/controlprimitive2d.cxx b/drawinglayer/source/primitive2d/controlprimitive2d.cxx
new file mode 100644
index 000000000000..126542142ab6
--- /dev/null
+++ b/drawinglayer/source/primitive2d/controlprimitive2d.cxx
@@ -0,0 +1,386 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/controlprimitive2d.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <comphelper/processfactory.hxx>
+#include <com/sun/star/awt/XWindow2.hpp>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/svapp.hxx>
+#include <com/sun/star/awt/PosSize.hpp>
+#include <vcl/bitmapex.hxx>
+#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
+#include <tools/diagnose_ex.h>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
+#include <toolkit/awt/vclxwindow.hxx>
+#include <vcl/window.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ void ControlPrimitive2D::createXControl()
+ {
+ if(!mxXControl.is() && getControlModel().is())
+ {
+ uno::Reference< beans::XPropertySet > xSet(getControlModel(), uno::UNO_QUERY);
+
+ if(xSet.is())
+ {
+ uno::Any aValue(xSet->getPropertyValue(rtl::OUString::createFromAscii("DefaultControl")));
+ rtl::OUString aUnoControlTypeName;
+
+ if(aValue >>= aUnoControlTypeName)
+ {
+ if(aUnoControlTypeName.getLength())
+ {
+ uno::Reference< lang::XMultiServiceFactory > xFactory( comphelper::getProcessServiceFactory() );
+
+ if(xFactory.is())
+ {
+ uno::Reference< awt::XControl > xXControl(xFactory->createInstance(aUnoControlTypeName), uno::UNO_QUERY);
+
+ if(xXControl.is())
+ {
+ xXControl->setModel(getControlModel());
+
+ // remember XControl
+ mxXControl = xXControl;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Primitive2DReference ControlPrimitive2D::createBitmapDecomposition(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ Primitive2DReference xRetval;
+ const uno::Reference< awt::XControl >& rXControl(getXControl());
+
+ if(rXControl.is())
+ {
+ uno::Reference< awt::XWindow > xControlWindow(rXControl, uno::UNO_QUERY);
+
+ if(xControlWindow.is())
+ {
+ // get decomposition to get size
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ getTransform().decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // get absolute discrete size (no mirror or rotate here)
+ aScale = basegfx::absolute(aScale);
+ basegfx::B2DVector aDiscreteSize(rViewInformation.getObjectToViewTransformation() * aScale);
+
+ // limit to a maximum square size, e.g. 300x150 pixels (45000)
+ const SvtOptionsDrawinglayer aDrawinglayerOpt;
+ const double fDiscreteMax(aDrawinglayerOpt.GetQuadraticFormControlRenderLimit());
+ const double fDiscreteQuadratic(aDiscreteSize.getX() * aDiscreteSize.getY());
+ const bool bScaleUsed(fDiscreteQuadratic > fDiscreteMax);
+ double fFactor(1.0);
+
+ if(bScaleUsed)
+ {
+ // get factor and adapt to scaled size
+ fFactor = sqrt(fDiscreteMax / fDiscreteQuadratic);
+ aDiscreteSize *= fFactor;
+ }
+
+ // go to integer
+ const sal_Int32 nSizeX(basegfx::fround(aDiscreteSize.getX()));
+ const sal_Int32 nSizeY(basegfx::fround(aDiscreteSize.getY()));
+
+ if(nSizeX > 0 && nSizeY > 0)
+ {
+ // prepare VirtualDevice
+ VirtualDevice aVirtualDevice(*Application::GetDefaultDevice());
+ const Size aSizePixel(nSizeX, nSizeY);
+ aVirtualDevice.SetOutputSizePixel(aSizePixel);
+
+ // set size at control
+ xControlWindow->setPosSize(0, 0, nSizeX, nSizeY, awt::PosSize::POSSIZE);
+
+ // get graphics and view
+ uno::Reference< awt::XGraphics > xGraphics(aVirtualDevice.CreateUnoGraphics());
+ uno::Reference< awt::XView > xControlView(rXControl, uno::UNO_QUERY);
+
+ if(xGraphics.is() && xControlView.is())
+ {
+ // link graphics and view
+ xControlView->setGraphics(xGraphics);
+
+ { // #i93162# For painting the control setting a Zoom (using setZoom() at the xControlView)
+ // is needed to define the font size. Normally this is done in
+ // ViewObjectContactOfUnoControl::createPrimitive2DSequence by using positionControlForPaint().
+ // For some reason the difference between MAP_TWIPS and MAP_100TH_MM still plays
+ // a role there so that for Draw/Impress/Calc (the MAP_100TH_MM users) i need to set a zoom
+ // here, too. The factor includes the needed scale, but is calculated by pure comparisons. It
+ // is somehow related to the twips/100thmm relationship.
+ bool bUserIs100thmm(false);
+ const uno::Reference< awt::XControl > xControl(xControlView, uno::UNO_QUERY);
+
+ if(xControl.is())
+ {
+ uno::Reference< awt::XWindowPeer > xWindowPeer(xControl->getPeer());
+
+ if(xWindowPeer.is())
+ {
+ VCLXWindow* pVCLXWindow = VCLXWindow::GetImplementation(xWindowPeer);
+
+ if(pVCLXWindow)
+ {
+ Window* pWindow = pVCLXWindow->GetWindow();
+
+ if(pWindow)
+ {
+ pWindow = pWindow->GetParent();
+
+ if(pWindow)
+ {
+ if(MAP_100TH_MM == pWindow->GetMapMode().GetMapUnit())
+ {
+ bUserIs100thmm = true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if(bUserIs100thmm)
+ {
+ // calc screen zoom for text display. fFactor is already added indirectly in aDiscreteSize
+ basegfx::B2DVector aScreenZoom(
+ basegfx::fTools::equalZero(aScale.getX()) ? 1.0 : aDiscreteSize.getX() / aScale.getX(),
+ basegfx::fTools::equalZero(aScale.getY()) ? 1.0 : aDiscreteSize.getY() / aScale.getY());
+ static double fZoomScale(28.0); // do not ask for this constant factor, but it gets the zoom right
+ aScreenZoom *= fZoomScale;
+
+ // set zoom at control view for text scaling
+ xControlView->setZoom((float)aScreenZoom.getX(), (float)aScreenZoom.getY());
+ }
+ }
+
+ try
+ {
+ // try to paint it to VirtualDevice
+ xControlView->draw(0, 0);
+
+ // get bitmap
+ const Bitmap aContent(aVirtualDevice.GetBitmap(Point(), aSizePixel));
+
+ // to avoid scaling, use the Bitmap pixel size as primitive size
+ const Size aBitmapSize(aContent.GetSizePixel());
+ basegfx::B2DVector aBitmapSizeLogic(
+ rViewInformation.getInverseObjectToViewTransformation() *
+ basegfx::B2DVector(aBitmapSize.getWidth() - 1, aBitmapSize.getHeight() - 1));
+
+ if(bScaleUsed)
+ {
+ // if scaled adapt to scaled size
+ aBitmapSizeLogic /= fFactor;
+ }
+
+ // short form for scale and translate transformation
+ const basegfx::B2DHomMatrix aBitmapTransform(basegfx::tools::createScaleTranslateB2DHomMatrix(
+ aBitmapSizeLogic.getX(), aBitmapSizeLogic.getY(), aTranslate.getX(), aTranslate.getY()));
+
+ // create primitive
+ xRetval = new BitmapPrimitive2D(BitmapEx(aContent), aBitmapTransform);
+ }
+ catch( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION();
+ }
+ }
+ }
+ }
+ }
+
+ return xRetval;
+ }
+
+ Primitive2DReference ControlPrimitive2D::createPlaceholderDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ // create a gray placeholder hairline polygon in object size
+ basegfx::B2DRange aObjectRange(0.0, 0.0, 1.0, 1.0);
+ aObjectRange.transform(getTransform());
+ const basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(aObjectRange));
+ const basegfx::BColor aGrayTone(0xc0 / 255.0, 0xc0 / 255.0, 0xc0 / 255.0);
+
+ // The replacement object may also get a text like 'empty group' here later
+ Primitive2DReference xRetval(new PolygonHairlinePrimitive2D(aOutline, aGrayTone));
+
+ return xRetval;
+ }
+
+ Primitive2DSequence ControlPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ // try to create a bitmap decomposition. If that fails for some reason,
+ // at least create a replacement decomposition.
+ Primitive2DReference xReference(createBitmapDecomposition(rViewInformation));
+
+ if(!xReference.is())
+ {
+ xReference = createPlaceholderDecomposition(rViewInformation);
+ }
+
+ return Primitive2DSequence(&xReference, 1L);
+ }
+
+ ControlPrimitive2D::ControlPrimitive2D(
+ const basegfx::B2DHomMatrix& rTransform,
+ const uno::Reference< awt::XControlModel >& rxControlModel)
+ : BufferedDecompositionPrimitive2D(),
+ maTransform(rTransform),
+ mxControlModel(rxControlModel),
+ mxXControl(),
+ maLastViewScaling()
+ {
+ }
+
+ ControlPrimitive2D::ControlPrimitive2D(
+ const basegfx::B2DHomMatrix& rTransform,
+ const uno::Reference< awt::XControlModel >& rxControlModel,
+ const uno::Reference< awt::XControl >& rxXControl)
+ : BufferedDecompositionPrimitive2D(),
+ maTransform(rTransform),
+ mxControlModel(rxControlModel),
+ mxXControl(rxXControl),
+ maLastViewScaling()
+ {
+ }
+
+ const uno::Reference< awt::XControl >& ControlPrimitive2D::getXControl() const
+ {
+ if(!mxXControl.is())
+ {
+ const_cast< ControlPrimitive2D* >(this)->createXControl();
+ }
+
+ return mxXControl;
+ }
+
+ bool ControlPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ // use base class compare operator
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const ControlPrimitive2D& rCompare = (ControlPrimitive2D&)rPrimitive;
+
+ if(getTransform() == rCompare.getTransform())
+ {
+ // check if ControlModel references both are/are not
+ bool bRetval(getControlModel().is() == rCompare.getControlModel().is());
+
+ if(bRetval && getControlModel().is())
+ {
+ // both exist, check for equality
+ bRetval = (getControlModel() == rCompare.getControlModel());
+ }
+
+ if(bRetval)
+ {
+ // check if XControl references both are/are not
+ bRetval = (getXControl().is() == rCompare.getXControl().is());
+ }
+
+ if(bRetval && getXControl().is())
+ {
+ // both exist, check for equality
+ bRetval = (getXControl() == rCompare.getXControl());
+ }
+
+ return bRetval;
+ }
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange ControlPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ // simply derivate from unit range
+ basegfx::B2DRange aRetval(0.0, 0.0, 1.0, 1.0);
+ aRetval.transform(getTransform());
+ return aRetval;
+ }
+
+ Primitive2DSequence ControlPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ // this primitive is view-dependent related to the scaling. If scaling has changed,
+ // destroy existing decomposition. To detect change, use size of unit size in view coordinates
+ ::osl::MutexGuard aGuard( m_aMutex );
+ const basegfx::B2DVector aNewScaling(rViewInformation.getObjectToViewTransformation() * basegfx::B2DVector(1.0, 1.0));
+
+ if(getBuffered2DDecomposition().hasElements())
+ {
+ if(!maLastViewScaling.equal(aNewScaling))
+ {
+ // conditions of last local decomposition have changed, delete
+ const_cast< ControlPrimitive2D* >(this)->setBuffered2DDecomposition(Primitive2DSequence());
+ }
+ }
+
+ if(!getBuffered2DDecomposition().hasElements())
+ {
+ // remember ViewTransformation
+ const_cast< ControlPrimitive2D* >(this)->maLastViewScaling = aNewScaling;
+ }
+
+ // use parent implementation
+ return BufferedDecompositionPrimitive2D::get2DDecomposition(rViewInformation);
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(ControlPrimitive2D, PRIMITIVE2D_ID_CONTROLPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/discretebitmapprimitive2d.cxx b/drawinglayer/source/primitive2d/discretebitmapprimitive2d.cxx
new file mode 100644
index 000000000000..a00a1e47f9e0
--- /dev/null
+++ b/drawinglayer/source/primitive2d/discretebitmapprimitive2d.cxx
@@ -0,0 +1,119 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/discretebitmapprimitive2d.hxx>
+#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence DiscreteBitmapPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ // use getViewTransformation() and getObjectTransformation() from
+ // ObjectAndViewTransformationDependentPrimitive2D to create a BitmapPrimitive2D
+ // with the correct mapping
+ Primitive2DSequence xRetval;
+
+ if(!getBitmapEx().IsEmpty())
+ {
+ // get discrete size
+ const Size& rSizePixel = getBitmapEx().GetSizePixel();
+ const basegfx::B2DVector aDiscreteSize(rSizePixel.Width(), rSizePixel.Height());
+
+ // get inverse ViewTransformation
+ basegfx::B2DHomMatrix aInverseViewTransformation(getViewTransformation());
+ aInverseViewTransformation.invert();
+
+ // get size and position in world coordinates
+ const basegfx::B2DVector aWorldSize(aInverseViewTransformation * aDiscreteSize);
+ const basegfx::B2DPoint aWorldTopLeft(getObjectTransformation() * getTopLeft());
+
+ // build object matrix in world coordinates so that the top-left
+ // position remains, but eventual transformations (e.g. rotations)
+ // in the ObjectToView stack remain and get correctly applied
+ basegfx::B2DHomMatrix aObjectTransform;
+
+ aObjectTransform.set(0, 0, aWorldSize.getX());
+ aObjectTransform.set(1, 1, aWorldSize.getY());
+ aObjectTransform.set(0, 2, aWorldTopLeft.getX());
+ aObjectTransform.set(1, 2, aWorldTopLeft.getY());
+
+ // get inverse ObjectTransformation
+ basegfx::B2DHomMatrix aInverseObjectTransformation(getObjectTransformation());
+ aInverseObjectTransformation.invert();
+
+ // transform to object coordinate system
+ aObjectTransform = aInverseObjectTransformation * aObjectTransform;
+
+ // create BitmapPrimitive2D with now object-local coordinate data
+ const Primitive2DReference xRef(new BitmapPrimitive2D(getBitmapEx(), aObjectTransform));
+ xRetval = Primitive2DSequence(&xRef, 1);
+ }
+
+ return xRetval;
+ }
+
+ DiscreteBitmapPrimitive2D::DiscreteBitmapPrimitive2D(
+ const BitmapEx& rBitmapEx,
+ const basegfx::B2DPoint& rTopLeft)
+ : ObjectAndViewTransformationDependentPrimitive2D(),
+ maBitmapEx(rBitmapEx),
+ maTopLeft(rTopLeft)
+ {
+ }
+
+ bool DiscreteBitmapPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(ObjectAndViewTransformationDependentPrimitive2D::operator==(rPrimitive))
+ {
+ const DiscreteBitmapPrimitive2D& rCompare = (DiscreteBitmapPrimitive2D&)rPrimitive;
+
+ return (getBitmapEx() == rCompare.getBitmapEx()
+ && getTopLeft() == rCompare.getTopLeft());
+ }
+
+ return false;
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(DiscreteBitmapPrimitive2D, PRIMITIVE2D_ID_DISCRETEBITMAPPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/embedded3dprimitive2d.cxx b/drawinglayer/source/primitive2d/embedded3dprimitive2d.cxx
new file mode 100644
index 000000000000..e2e2b3bd2151
--- /dev/null
+++ b/drawinglayer/source/primitive2d/embedded3dprimitive2d.cxx
@@ -0,0 +1,171 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/embedded3dprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/color/bcolor.hxx>
+#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
+#include <basegfx/tools/canvastools.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+#include <drawinglayer/geometry/viewinformation3d.hxx>
+#include <drawinglayer/processor3d/shadow3dextractor.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ bool Embedded3DPrimitive2D::impGetShadow3D(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ osl::MutexGuard aGuard( m_aMutex );
+
+ // create on demand
+ if(!mbShadow3DChecked && getChildren3D().hasElements())
+ {
+ // create shadow extraction processor
+ processor3d::Shadow3DExtractingProcessor aShadowProcessor(
+ getViewInformation3D(),
+ getObjectTransformation(),
+ getLightNormal(),
+ getShadowSlant(),
+ getScene3DRange());
+
+ // process local primitives
+ aShadowProcessor.process(getChildren3D());
+
+ // fetch result and set checked flag
+ const_cast< Embedded3DPrimitive2D* >(this)->maShadowPrimitives = aShadowProcessor.getPrimitive2DSequence();
+ const_cast< Embedded3DPrimitive2D* >(this)->mbShadow3DChecked = true;
+ }
+
+ // return if there are shadow primitives
+ return maShadowPrimitives.hasElements();
+ }
+
+ Primitive2DSequence Embedded3DPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ // use info to create a yellow 2d rectangle, similar to empty 3d scenes and/or groups
+ const basegfx::B2DRange aLocal2DRange(getB2DRange(rViewInformation));
+ const basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(aLocal2DRange));
+ const basegfx::BColor aYellow(1.0, 1.0, 0.0);
+ const Primitive2DReference xRef(new PolygonHairlinePrimitive2D(aOutline, aYellow));
+
+ return Primitive2DSequence(&xRef, 1L);
+ }
+
+ Embedded3DPrimitive2D::Embedded3DPrimitive2D(
+ const primitive3d::Primitive3DSequence& rxChildren3D,
+ const basegfx::B2DHomMatrix& rObjectTransformation,
+ const geometry::ViewInformation3D& rViewInformation3D,
+ const basegfx::B3DVector& rLightNormal,
+ double fShadowSlant,
+ const basegfx::B3DRange& rScene3DRange)
+ : BufferedDecompositionPrimitive2D(),
+ mxChildren3D(rxChildren3D),
+ maObjectTransformation(rObjectTransformation),
+ maViewInformation3D(rViewInformation3D),
+ maLightNormal(rLightNormal),
+ mfShadowSlant(fShadowSlant),
+ maScene3DRange(rScene3DRange),
+ maShadowPrimitives(),
+ maB2DRange(),
+ mbShadow3DChecked(false)
+ {
+ maLightNormal.normalize();
+ }
+
+ bool Embedded3DPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const Embedded3DPrimitive2D& rCompare = static_cast< const Embedded3DPrimitive2D& >(rPrimitive);
+
+ return (primitive3d::arePrimitive3DSequencesEqual(getChildren3D(), rCompare.getChildren3D())
+ && getObjectTransformation() == rCompare.getObjectTransformation()
+ && getViewInformation3D() == rCompare.getViewInformation3D()
+ && getLightNormal() == rCompare.getLightNormal()
+ && getShadowSlant() == rCompare.getShadowSlant()
+ && getScene3DRange() == rCompare.getScene3DRange());
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange Embedded3DPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ if(maB2DRange.isEmpty())
+ {
+ // use the 3d transformation stack to create a projection of the 3D range
+ basegfx::B3DRange a3DRange(primitive3d::getB3DRangeFromPrimitive3DSequence(getChildren3D(), getViewInformation3D()));
+ a3DRange.transform(getViewInformation3D().getObjectToView());
+
+ // create 2d range from projected 3d and transform with scene's object transformation
+ basegfx::B2DRange aNewRange;
+ aNewRange.expand(basegfx::B2DPoint(a3DRange.getMinX(), a3DRange.getMinY()));
+ aNewRange.expand(basegfx::B2DPoint(a3DRange.getMaxX(), a3DRange.getMaxY()));
+ aNewRange.transform(getObjectTransformation());
+
+ // cehck for 3D shadows and their 2D projections. If those exist, they need to be
+ // taken into account
+ if(impGetShadow3D(rViewInformation))
+ {
+ const basegfx::B2DRange aShadow2DRange(getB2DRangeFromPrimitive2DSequence(maShadowPrimitives, rViewInformation));
+
+ if(!aShadow2DRange.isEmpty())
+ {
+ aNewRange.expand(aShadow2DRange);
+ }
+ }
+
+ // assign to buffered value
+ const_cast< Embedded3DPrimitive2D* >(this)->maB2DRange = aNewRange;
+ }
+
+ return maB2DRange;
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(Embedded3DPrimitive2D, PRIMITIVE2D_ID_EMBEDDED3DPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/epsprimitive2d.cxx b/drawinglayer/source/primitive2d/epsprimitive2d.cxx
new file mode 100644
index 000000000000..eba693ddc031
--- /dev/null
+++ b/drawinglayer/source/primitive2d/epsprimitive2d.cxx
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/epsprimitive2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+#include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence EpsPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ Primitive2DSequence xRetval;
+ const GDIMetaFile& rSubstituteContent = getMetaFile();
+
+ if(rSubstituteContent.GetActionCount())
+ {
+ // the default decomposition will use the Metafile replacement visualisation.
+ // To really use the Eps data, a renderer has to know and interpret this primitive
+ // directly.
+ xRetval.realloc(1);
+
+ xRetval[0] = Primitive2DReference(
+ new MetafilePrimitive2D(
+ getEpsTransform(),
+ rSubstituteContent));
+ }
+
+ return xRetval;
+ }
+
+ EpsPrimitive2D::EpsPrimitive2D(
+ const basegfx::B2DHomMatrix& rEpsTransform,
+ const GfxLink& rGfxLink,
+ const GDIMetaFile& rMetaFile)
+ : BufferedDecompositionPrimitive2D(),
+ maEpsTransform(rEpsTransform),
+ maGfxLink(rGfxLink),
+ maMetaFile(rMetaFile)
+ {
+ }
+
+ bool EpsPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const EpsPrimitive2D& rCompare = (EpsPrimitive2D&)rPrimitive;
+
+ return (getEpsTransform() == rCompare.getEpsTransform()
+ && getGfxLink().IsEqual(rCompare.getGfxLink())
+ && getMetaFile() == rCompare.getMetaFile());
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange EpsPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ // use own implementation to quickly answer the getB2DRange question.
+ basegfx::B2DRange aRetval(0.0, 0.0, 1.0, 1.0);
+ aRetval.transform(getEpsTransform());
+
+ return aRetval;
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(EpsPrimitive2D, PRIMITIVE2D_ID_EPSPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/fillbitmapprimitive2d.cxx b/drawinglayer/source/primitive2d/fillbitmapprimitive2d.cxx
new file mode 100644
index 000000000000..8a4d70b9590c
--- /dev/null
+++ b/drawinglayer/source/primitive2d/fillbitmapprimitive2d.cxx
@@ -0,0 +1,145 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/fillbitmapprimitive2d.hxx>
+#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <drawinglayer/texture/texture.hxx>
+#include <basegfx/tools/canvastools.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence FillBitmapPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ Primitive2DSequence aRetval;
+
+ if(!getFillBitmap().isDefault())
+ {
+ const Size aTileSizePixel(getFillBitmap().getBitmapEx().GetSizePixel());
+
+ // is there a tile with some size at all?
+ if(aTileSizePixel.getWidth() && aTileSizePixel.getHeight())
+ {
+ if(getFillBitmap().getTiling())
+ {
+ // get object range and create tiling matrices
+ ::std::vector< basegfx::B2DHomMatrix > aMatrices;
+ texture::GeoTexSvxTiled aTiling(getFillBitmap().getTopLeft(), getFillBitmap().getSize());
+ aTiling.appendTransformations(aMatrices);
+
+ // resize result
+ aRetval.realloc(aMatrices.size());
+
+ // create one primitive for each matrix
+ for(sal_uInt32 a(0L); a < aMatrices.size(); a++)
+ {
+ basegfx::B2DHomMatrix aNewMatrix = aMatrices[a];
+ aNewMatrix *= getTransformation();
+
+ // create bitmap primitive and add to result
+ const Primitive2DReference xRef(
+ new BitmapPrimitive2D(getFillBitmap().getBitmapEx(), aNewMatrix));
+
+ aRetval[a] = xRef;
+ }
+ }
+ else
+ {
+ // create new object transform
+ basegfx::B2DHomMatrix aObjectTransform;
+ aObjectTransform.set(0L, 0L, getFillBitmap().getSize().getX());
+ aObjectTransform.set(1L, 1L, getFillBitmap().getSize().getY());
+ aObjectTransform.set(0L, 2L, getFillBitmap().getTopLeft().getX());
+ aObjectTransform.set(1L, 2L, getFillBitmap().getTopLeft().getY());
+ aObjectTransform *= getTransformation();
+
+ // create bitmap primitive and add exclusive to decomposition (hand over ownership)
+ const Primitive2DReference xRef(
+ new BitmapPrimitive2D(getFillBitmap().getBitmapEx(), aObjectTransform));
+
+ aRetval = Primitive2DSequence(&xRef, 1L);
+ }
+ }
+ }
+
+ return aRetval;
+ }
+
+ FillBitmapPrimitive2D::FillBitmapPrimitive2D(
+ const basegfx::B2DHomMatrix& rTransformation,
+ const attribute::FillBitmapAttribute& rFillBitmap)
+ : BufferedDecompositionPrimitive2D(),
+ maTransformation(rTransformation),
+ maFillBitmap(rFillBitmap)
+ {
+ }
+
+ bool FillBitmapPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const FillBitmapPrimitive2D& rCompare = static_cast< const FillBitmapPrimitive2D& >(rPrimitive);
+
+ return (getTransformation() == rCompare.getTransformation()
+ && getFillBitmap() == rCompare.getFillBitmap());
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange FillBitmapPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ // return range of it
+ basegfx::B2DPolygon aPolygon(basegfx::tools::createUnitPolygon());
+ aPolygon.transform(getTransformation());
+ return basegfx::tools::getRange(aPolygon);
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(FillBitmapPrimitive2D, PRIMITIVE2D_ID_FILLBITMAPPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx b/drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx
new file mode 100644
index 000000000000..b75f9a6e0de1
--- /dev/null
+++ b/drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx
@@ -0,0 +1,301 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/fillgradientprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <drawinglayer/texture/texture.hxx>
+#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
+#include <basegfx/tools/canvastools.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ void FillGradientPrimitive2D::generateMatricesAndColors(
+ std::vector< basegfx::B2DHomMatrix >& rMatrices,
+ std::vector< basegfx::BColor >& rColors) const
+ {
+ rMatrices.clear();
+ rColors.clear();
+
+ // make sure steps is not too high/low
+ const basegfx::BColor aStart(getFillGradient().getStartColor());
+ const basegfx::BColor aEnd(getFillGradient().getEndColor());
+ const sal_uInt32 nMaxSteps(sal_uInt32((aStart.getMaximumDistance(aEnd) * 127.5) + 0.5));
+ sal_uInt32 nSteps(getFillGradient().getSteps());
+
+ if(nSteps == 0)
+ {
+ nSteps = nMaxSteps;
+ }
+
+ if(nSteps < 2)
+ {
+ nSteps = 2;
+ }
+
+ if(nSteps > nMaxSteps)
+ {
+ nSteps = nMaxSteps;
+ }
+
+ switch(getFillGradient().getStyle())
+ {
+ case attribute::GRADIENTSTYLE_LINEAR:
+ {
+ texture::GeoTexSvxGradientLinear aGradient(getObjectRange(), aStart, aEnd, nSteps, getFillGradient().getBorder(), getFillGradient().getAngle());
+ aGradient.appendTransformations(rMatrices);
+ aGradient.appendColors(rColors);
+ break;
+ }
+ case attribute::GRADIENTSTYLE_AXIAL:
+ {
+ texture::GeoTexSvxGradientAxial aGradient(getObjectRange(), aStart, aEnd, nSteps, getFillGradient().getBorder(), getFillGradient().getAngle());
+ aGradient.appendTransformations(rMatrices);
+ aGradient.appendColors(rColors);
+ break;
+ }
+ case attribute::GRADIENTSTYLE_RADIAL:
+ {
+ texture::GeoTexSvxGradientRadial aGradient(getObjectRange(), aStart, aEnd, nSteps, getFillGradient().getBorder(), getFillGradient().getOffsetX(), getFillGradient().getOffsetY());
+ aGradient.appendTransformations(rMatrices);
+ aGradient.appendColors(rColors);
+ break;
+ }
+ case attribute::GRADIENTSTYLE_ELLIPTICAL:
+ {
+ texture::GeoTexSvxGradientElliptical aGradient(getObjectRange(), aStart, aEnd, nSteps, getFillGradient().getBorder(), getFillGradient().getOffsetX(), getFillGradient().getOffsetY(), getFillGradient().getAngle());
+ aGradient.appendTransformations(rMatrices);
+ aGradient.appendColors(rColors);
+ break;
+ }
+ case attribute::GRADIENTSTYLE_SQUARE:
+ {
+ texture::GeoTexSvxGradientSquare aGradient(getObjectRange(), aStart, aEnd, nSteps, getFillGradient().getBorder(), getFillGradient().getOffsetX(), getFillGradient().getOffsetY(), getFillGradient().getAngle());
+ aGradient.appendTransformations(rMatrices);
+ aGradient.appendColors(rColors);
+ break;
+ }
+ case attribute::GRADIENTSTYLE_RECT:
+ {
+ texture::GeoTexSvxGradientRect aGradient(getObjectRange(), aStart, aEnd, nSteps, getFillGradient().getBorder(), getFillGradient().getOffsetX(), getFillGradient().getOffsetY(), getFillGradient().getAngle());
+ aGradient.appendTransformations(rMatrices);
+ aGradient.appendColors(rColors);
+ break;
+ }
+ }
+ }
+
+ Primitive2DSequence FillGradientPrimitive2D::createOverlappingFill(
+ const std::vector< basegfx::B2DHomMatrix >& rMatrices,
+ const std::vector< basegfx::BColor >& rColors,
+ const basegfx::B2DPolygon& rUnitPolygon) const
+ {
+ // prepare return value
+ Primitive2DSequence aRetval(rColors.size() ? rMatrices.size() + 1 : rMatrices.size());
+
+ // create solid fill with start color
+ if(rColors.size())
+ {
+ // create primitive
+ const Primitive2DReference xRef(
+ new PolyPolygonColorPrimitive2D(
+ basegfx::B2DPolyPolygon(basegfx::tools::createPolygonFromRect(getObjectRange())),
+ rColors[0]));
+ aRetval[0] = xRef;
+ }
+
+ // create solid fill steps
+ for(sal_uInt32 a(0); a < rMatrices.size(); a++)
+ {
+ // create part polygon
+ basegfx::B2DPolygon aNewPoly(rUnitPolygon);
+ aNewPoly.transform(rMatrices[a]);
+
+ // create solid fill
+ const Primitive2DReference xRef(
+ new PolyPolygonColorPrimitive2D(
+ basegfx::B2DPolyPolygon(aNewPoly),
+ rColors[a + 1]));
+ aRetval[a + 1] = xRef;
+ }
+
+ return aRetval;
+ }
+
+ Primitive2DSequence FillGradientPrimitive2D::createNonOverlappingFill(
+ const std::vector< basegfx::B2DHomMatrix >& rMatrices,
+ const std::vector< basegfx::BColor >& rColors,
+ const basegfx::B2DPolygon& rUnitPolygon) const
+ {
+ // prepare return value
+ Primitive2DSequence aRetval;
+ const sal_uInt32 nMatricesSize(rMatrices.size());
+
+ if(nMatricesSize)
+ {
+ basegfx::B2DPolygon aOuterPoly(rUnitPolygon);
+ aOuterPoly.transform(rMatrices[0]);
+ basegfx::B2DPolyPolygon aCombinedPolyPoly(aOuterPoly);
+ const sal_uInt32 nEntryCount(rColors.size() ? rMatrices.size() + 1 : rMatrices.size());
+ sal_uInt32 nIndex(0);
+
+ aRetval.realloc(nEntryCount);
+
+ if(rColors.size())
+ {
+ basegfx::B2DRange aOuterPolyRange(aOuterPoly.getB2DRange());
+ aOuterPolyRange.expand(getObjectRange());
+ aCombinedPolyPoly.append(basegfx::tools::createPolygonFromRect(aOuterPolyRange));
+ aRetval[nIndex++] = Primitive2DReference(new PolyPolygonColorPrimitive2D(aCombinedPolyPoly, rColors[0]));
+ aCombinedPolyPoly = basegfx::B2DPolyPolygon(aOuterPoly);
+ }
+
+ for(sal_uInt32 a(1); a < nMatricesSize - 1; a++)
+ {
+ basegfx::B2DPolygon aInnerPoly(rUnitPolygon);
+ aInnerPoly.transform(rMatrices[a]);
+ aCombinedPolyPoly.append(aInnerPoly);
+ aRetval[nIndex++] = Primitive2DReference(new PolyPolygonColorPrimitive2D(aCombinedPolyPoly, rColors[a]));
+ aCombinedPolyPoly = basegfx::B2DPolyPolygon(aInnerPoly);
+ }
+
+ if(rColors.size())
+ {
+ aRetval[nIndex] = Primitive2DReference(new PolyPolygonColorPrimitive2D(
+ aCombinedPolyPoly, rColors[rColors.size() - 1]));
+ }
+ }
+
+ return aRetval;
+ }
+
+ Primitive2DSequence FillGradientPrimitive2D::createFill(bool bOverlapping) const
+ {
+ // prepare shape of the Unit Polygon
+ basegfx::B2DPolygon aUnitPolygon;
+
+ if(attribute::GRADIENTSTYLE_RADIAL == getFillGradient().getStyle()
+ || attribute::GRADIENTSTYLE_ELLIPTICAL == getFillGradient().getStyle())
+ {
+ aUnitPolygon = basegfx::tools::createPolygonFromCircle(
+ basegfx::B2DPoint(0,0), 1);
+ }
+ else if(attribute::GRADIENTSTYLE_LINEAR == maFillGradient.getStyle())
+ {
+ aUnitPolygon = basegfx::tools::createPolygonFromRect(basegfx::B2DRange(0, 0, 1, 1));
+ }
+ else
+ {
+ aUnitPolygon = basegfx::tools::createPolygonFromRect(basegfx::B2DRange(-1, -1, 1, 1));
+ }
+
+ // get the transform matrices and colors (where colors
+ // will have one more entry that matrices)
+ std::vector< basegfx::B2DHomMatrix > aMatrices;
+ std::vector< basegfx::BColor > aColors;
+ generateMatricesAndColors(aMatrices, aColors);
+
+ if(bOverlapping)
+ {
+ return createOverlappingFill(aMatrices, aColors, aUnitPolygon);
+ }
+ else
+ {
+ return createNonOverlappingFill(aMatrices, aColors, aUnitPolygon);
+ }
+ }
+
+ Primitive2DSequence FillGradientPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ // default creates overlapping fill which works with AntiAliasing and without.
+ // The non-overlapping version does not create single filled polygons, but
+ // PolyPolygons where each one describes a 'ring' for the gradient such
+ // that the rings will not overlap. This is useful fir the old XOR-paint
+ // 'trick' of VCL which is recorded in Metafiles; so this version may be
+ // used from the MetafilePrimitive2D in it's decomposition.
+
+ if(!getFillGradient().isDefault())
+ {
+ return createFill(true);
+ }
+ else
+ {
+ return Primitive2DSequence();
+ }
+ }
+
+ FillGradientPrimitive2D::FillGradientPrimitive2D(
+ const basegfx::B2DRange& rObjectRange,
+ const attribute::FillGradientAttribute& rFillGradient)
+ : BufferedDecompositionPrimitive2D(),
+ maObjectRange(rObjectRange),
+ maFillGradient(rFillGradient)
+ {
+ }
+
+ bool FillGradientPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const FillGradientPrimitive2D& rCompare = (FillGradientPrimitive2D&)rPrimitive;
+
+ return (getObjectRange() == rCompare.getObjectRange()
+ && getFillGradient() == rCompare.getFillGradient());
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange FillGradientPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ // return ObjectRange
+ return getObjectRange();
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(FillGradientPrimitive2D, PRIMITIVE2D_ID_FILLGRADIENTPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/fillhatchprimitive2d.cxx b/drawinglayer/source/primitive2d/fillhatchprimitive2d.cxx
new file mode 100644
index 000000000000..1e0e9fdff90f
--- /dev/null
+++ b/drawinglayer/source/primitive2d/fillhatchprimitive2d.cxx
@@ -0,0 +1,164 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/fillhatchprimitive2d.hxx>
+#include <drawinglayer/texture/texture.hxx>
+#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/tools/canvastools.hxx>
+#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence FillHatchPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ Primitive2DSequence aRetval;
+ if(!getFillHatch().isDefault())
+ {
+ // create hatch
+ const basegfx::BColor aHatchColor(getFillHatch().getColor());
+ const double fAngle(getFillHatch().getAngle());
+ ::std::vector< basegfx::B2DHomMatrix > aMatrices;
+
+ // get hatch transformations
+ switch(getFillHatch().getStyle())
+ {
+ case attribute::HATCHSTYLE_TRIPLE:
+ {
+ // rotated 45 degrees
+ texture::GeoTexSvxHatch aHatch(getObjectRange(), getFillHatch().getDistance(), fAngle - F_PI4);
+ aHatch.appendTransformations(aMatrices);
+
+ // fall-through by purpose
+ }
+ case attribute::HATCHSTYLE_DOUBLE:
+ {
+ // rotated 90 degrees
+ texture::GeoTexSvxHatch aHatch(getObjectRange(), getFillHatch().getDistance(), fAngle - F_PI2);
+ aHatch.appendTransformations(aMatrices);
+
+ // fall-through by purpose
+ }
+ case attribute::HATCHSTYLE_SINGLE:
+ {
+ // angle as given
+ texture::GeoTexSvxHatch aHatch(getObjectRange(), getFillHatch().getDistance(), fAngle);
+ aHatch.appendTransformations(aMatrices);
+ }
+ }
+
+ // prepare return value
+ const bool bFillBackground(getFillHatch().isFillBackground());
+ aRetval.realloc(bFillBackground ? aMatrices.size() + 1L : aMatrices.size());
+
+ // evtl. create filled background
+ if(bFillBackground)
+ {
+ // create primitive for background
+ const Primitive2DReference xRef(
+ new PolyPolygonColorPrimitive2D(
+ basegfx::B2DPolyPolygon(
+ basegfx::tools::createPolygonFromRect(getObjectRange())), getBColor()));
+ aRetval[0] = xRef;
+ }
+
+ // create primitives
+ const basegfx::B2DPoint aStart(0.0, 0.0);
+ const basegfx::B2DPoint aEnd(1.0, 0.0);
+
+ for(sal_uInt32 a(0L); a < aMatrices.size(); a++)
+ {
+ const basegfx::B2DHomMatrix& rMatrix = aMatrices[a];
+ basegfx::B2DPolygon aNewLine;
+
+ aNewLine.append(rMatrix * aStart);
+ aNewLine.append(rMatrix * aEnd);
+
+ // create hairline
+ const Primitive2DReference xRef(new PolygonHairlinePrimitive2D(aNewLine, aHatchColor));
+ aRetval[bFillBackground ? (a + 1) : a] = xRef;
+ }
+ }
+
+ return aRetval;
+ }
+
+ FillHatchPrimitive2D::FillHatchPrimitive2D(
+ const basegfx::B2DRange& rObjectRange,
+ const basegfx::BColor& rBColor,
+ const attribute::FillHatchAttribute& rFillHatch)
+ : BufferedDecompositionPrimitive2D(),
+ maObjectRange(rObjectRange),
+ maFillHatch(rFillHatch),
+ maBColor(rBColor)
+ {
+ }
+
+ bool FillHatchPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const FillHatchPrimitive2D& rCompare = (FillHatchPrimitive2D&)rPrimitive;
+
+ return (getObjectRange() == rCompare.getObjectRange()
+ && getFillHatch() == rCompare.getFillHatch()
+ && getBColor() == rCompare.getBColor());
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange FillHatchPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ // return ObjectRange
+ return getObjectRange();
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(FillHatchPrimitive2D, PRIMITIVE2D_ID_FILLHATCHPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/graphicprimitive2d.cxx b/drawinglayer/source/primitive2d/graphicprimitive2d.cxx
new file mode 100644
index 000000000000..8a9e73d5adc9
--- /dev/null
+++ b/drawinglayer/source/primitive2d/graphicprimitive2d.cxx
@@ -0,0 +1,945 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/graphicprimitive2d.hxx>
+#include <drawinglayer/animation/animationtiming.hxx>
+#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
+#include <drawinglayer/primitive2d/animatedprimitive2d.hxx>
+#include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+// helper class for animated graphics
+
+#include <vcl/animate.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/svapp.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+// includes for testing MetafilePrimitive2D::create2DDecomposition
+
+// this switch defines if the test code is included or not
+#undef USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE
+
+#ifdef USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE
+#include <vcl/gradient.hxx>
+#include <vcl/pngread.hxx>
+#include <vcl/lineinfo.hxx>
+#endif // USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace
+{
+ struct animationStep
+ {
+ BitmapEx maBitmapEx;
+ sal_uInt32 mnTime;
+ };
+
+ class animatedBitmapExPreparator
+ {
+ ::Animation maAnimation;
+ ::std::vector< animationStep > maSteps;
+
+ sal_uInt32 generateStepTime(sal_uInt32 nIndex) const;
+
+ public:
+ animatedBitmapExPreparator(const Graphic& rGraphic);
+
+ sal_uInt32 count() const { return maSteps.size(); }
+ sal_uInt32 loopCount() const { return (sal_uInt32)maAnimation.GetLoopCount(); }
+ sal_uInt32 stepTime(sal_uInt32 a) const { return maSteps[a].mnTime; }
+ const BitmapEx& stepBitmapEx(sal_uInt32 a) const { return maSteps[a].maBitmapEx; }
+ };
+
+ sal_uInt32 animatedBitmapExPreparator::generateStepTime(sal_uInt32 nIndex) const
+ {
+ const AnimationBitmap& rAnimBitmap = maAnimation.Get(sal_uInt16(nIndex));
+ sal_uInt32 nWaitTime(rAnimBitmap.nWait * 10);
+
+ // #115934#
+ // Take care of special value for MultiPage TIFFs. ATM these shall just
+ // show their first page. Later we will offer some switching when object
+ // is selected.
+ if(ANIMATION_TIMEOUT_ON_CLICK == rAnimBitmap.nWait)
+ {
+ // ATM the huge value would block the timer, so
+ // use a long time to show first page (whole day)
+ nWaitTime = 100 * 60 * 60 * 24;
+ }
+
+ // Bad trap: There are animated gifs with no set WaitTime (!).
+ // In that case use a default value.
+ if(0L == nWaitTime)
+ {
+ nWaitTime = 100L;
+ }
+
+ return nWaitTime;
+ }
+
+ animatedBitmapExPreparator::animatedBitmapExPreparator(const Graphic& rGraphic)
+ : maAnimation(rGraphic.GetAnimation())
+ {
+ OSL_ENSURE(GRAPHIC_BITMAP == rGraphic.GetType() && rGraphic.IsAnimated(), "animatedBitmapExPreparator: graphic is not animated (!)");
+
+ // #128539# secure access to Animation, looks like there exist animated GIFs out there
+ // with a step count of zero
+ if(maAnimation.Count())
+ {
+ VirtualDevice aVirtualDevice(*Application::GetDefaultDevice());
+ VirtualDevice aVirtualDeviceMask(*Application::GetDefaultDevice(), 1L);
+
+ // Prepare VirtualDevices and their states
+ aVirtualDevice.EnableMapMode(sal_False);
+ aVirtualDeviceMask.EnableMapMode(sal_False);
+ aVirtualDevice.SetOutputSizePixel(maAnimation.GetDisplaySizePixel());
+ aVirtualDeviceMask.SetOutputSizePixel(maAnimation.GetDisplaySizePixel());
+ aVirtualDevice.Erase();
+ aVirtualDeviceMask.Erase();
+
+ for(sal_uInt16 a(0L); a < maAnimation.Count(); a++)
+ {
+ animationStep aNextStep;
+ aNextStep.mnTime = generateStepTime(a);
+
+ // prepare step
+ const AnimationBitmap& rAnimBitmap = maAnimation.Get(sal_uInt16(a));
+
+ switch(rAnimBitmap.eDisposal)
+ {
+ case DISPOSE_NOT:
+ {
+ aVirtualDevice.DrawBitmapEx(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx);
+ Bitmap aMask = rAnimBitmap.aBmpEx.GetMask();
+
+ if(aMask.IsEmpty())
+ {
+ const Point aEmpty;
+ const Rectangle aRect(aEmpty, aVirtualDeviceMask.GetOutputSizePixel());
+ const Wallpaper aWallpaper(COL_BLACK);
+ aVirtualDeviceMask.DrawWallpaper(aRect, aWallpaper);
+ }
+ else
+ {
+ BitmapEx aExpandVisibilityMask = BitmapEx(aMask, aMask);
+ aVirtualDeviceMask.DrawBitmapEx(rAnimBitmap.aPosPix, aExpandVisibilityMask);
+ }
+
+ break;
+ }
+ case DISPOSE_BACK:
+ {
+ // #i70772# react on no mask, for primitives, too.
+ const Bitmap aMask(rAnimBitmap.aBmpEx.GetMask());
+ const Bitmap aContent(rAnimBitmap.aBmpEx.GetBitmap());
+
+ aVirtualDeviceMask.Erase();
+ aVirtualDevice.DrawBitmap(rAnimBitmap.aPosPix, aContent);
+
+ if(aMask.IsEmpty())
+ {
+ const Rectangle aRect(rAnimBitmap.aPosPix, aContent.GetSizePixel());
+ aVirtualDeviceMask.SetFillColor(COL_BLACK);
+ aVirtualDeviceMask.SetLineColor();
+ aVirtualDeviceMask.DrawRect(aRect);
+ }
+ else
+ {
+ aVirtualDeviceMask.DrawBitmap(rAnimBitmap.aPosPix, aMask);
+ }
+
+ break;
+ }
+ case DISPOSE_FULL:
+ {
+ aVirtualDevice.DrawBitmapEx(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx);
+ break;
+ }
+ case DISPOSE_PREVIOUS :
+ {
+ aVirtualDevice.DrawBitmapEx(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx);
+ aVirtualDeviceMask.DrawBitmap(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx.GetMask());
+ break;
+ }
+ }
+
+ // create BitmapEx
+ Bitmap aMainBitmap = aVirtualDevice.GetBitmap(Point(), aVirtualDevice.GetOutputSizePixel());
+ Bitmap aMaskBitmap = aVirtualDeviceMask.GetBitmap(Point(), aVirtualDeviceMask.GetOutputSizePixel());
+ aNextStep.maBitmapEx = BitmapEx(aMainBitmap, aMaskBitmap);
+
+ // add to vector
+ maSteps.push_back(aNextStep);
+ }
+ }
+ }
+} // end of anonymous namespace
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence GraphicPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D&
+#ifdef USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE
+ rViewInformation
+#else
+ /*rViewInformation*/
+#endif // USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE
+ ) const
+ {
+ Primitive2DSequence aRetval;
+
+ if(255L != getGraphicAttr().GetTransparency())
+ {
+ Primitive2DReference xPrimitive;
+
+ // do not apply mirroring from GraphicAttr to the Metafile by calling
+ // GetTransformedGraphic, this will try to mirror the Metafile using Scale()
+ // at the Metafile. This again calls Scale at the single MetaFile actions,
+ // but this implementation never worked. I reworked that implementations,
+ // but for security reasons i will try not to use it.
+ basegfx::B2DHomMatrix aTransform(getTransform());
+
+ if(getGraphicAttr().IsMirrored())
+ {
+ // content needs mirroring
+ const bool bHMirr(getGraphicAttr().GetMirrorFlags() & BMP_MIRROR_HORZ);
+ const bool bVMirr(getGraphicAttr().GetMirrorFlags() & BMP_MIRROR_VERT);
+
+ // mirror by applying negative scale to the unit primitive and
+ // applying the object transformation on it.
+ aTransform = basegfx::tools::createScaleB2DHomMatrix(
+ bHMirr ? -1.0 : 1.0,
+ bVMirr ? -1.0 : 1.0);
+ aTransform.translate(
+ bHMirr ? 1.0 : 0.0,
+ bVMirr ? 1.0 : 0.0);
+ aTransform = getTransform() * aTransform;
+ }
+
+ // Get transformed graphic. Suppress rotation and cropping, only filtering is needed
+ // here (and may be replaced later on). Cropping is handled below as mask primitive (if set).
+ // Also need to suppress mirroring, it is part of the transformation now (see above).
+ GraphicAttr aSuppressGraphicAttr(getGraphicAttr());
+ aSuppressGraphicAttr.SetCrop(0, 0, 0, 0);
+ aSuppressGraphicAttr.SetRotation(0);
+ aSuppressGraphicAttr.SetMirrorFlags(0);
+ const Graphic aTransformedGraphic(getGraphicObject().GetTransformedGraphic(&aSuppressGraphicAttr));
+
+ switch(aTransformedGraphic.GetType())
+ {
+ case GRAPHIC_BITMAP :
+ {
+ if(aTransformedGraphic.IsAnimated())
+ {
+ // prepare animation data
+ animatedBitmapExPreparator aData(aTransformedGraphic);
+
+ if(aData.count())
+ {
+ // create sub-primitives for animated bitmap and the needed animation loop
+ animation::AnimationEntryLoop aAnimationLoop(aData.loopCount() ? aData.loopCount() : 0xffff);
+ Primitive2DSequence aBitmapPrimitives(aData.count());
+
+ for(sal_uInt32 a(0L); a < aData.count(); a++)
+ {
+ animation::AnimationEntryFixed aTime((double)aData.stepTime(a), (double)a / (double)aData.count());
+ aAnimationLoop.append(aTime);
+ const Primitive2DReference xRef(new BitmapPrimitive2D(aData.stepBitmapEx(a), aTransform));
+ aBitmapPrimitives[a] = xRef;
+ }
+
+ // prepare animation list
+ animation::AnimationEntryList aAnimationList;
+ aAnimationList.append(aAnimationLoop);
+
+ // create and add animated switch primitive
+ xPrimitive = Primitive2DReference(new AnimatedSwitchPrimitive2D(aAnimationList, aBitmapPrimitives, false));
+ }
+ }
+ else
+ {
+ xPrimitive = Primitive2DReference(new BitmapPrimitive2D(aTransformedGraphic.GetBitmapEx(), aTransform));
+ }
+
+ break;
+ }
+
+ case GRAPHIC_GDIMETAFILE :
+ {
+#ifdef USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE
+ static bool bDoTest(false);
+
+ if(bDoTest)
+ {
+ // All this is/was test code for testing MetafilePrimitive2D::create2DDecomposition
+ // extensively. It may be needed again when diverse actions need debugging, so i leave
+ // it in here, but take it out using USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE.
+ // Use it by compiling with the code, insert any DrawObject, convert to Metafile. The
+ // debugger will then stop here (when breakpoint set, of course). You may enter single
+ // parts of actions and/or change to true what You want to check.
+ GDIMetaFile aMtf;
+ VirtualDevice aOut;
+ const basegfx::B2DRange aRange(getB2DRange(rViewInformation));
+ const Rectangle aRectangle(
+ basegfx::fround(aRange.getMinX()), basegfx::fround(aRange.getMinY()),
+ basegfx::fround(aRange.getMaxX()), basegfx::fround(aRange.getMaxY()));
+ const Point aOrigin(aRectangle.TopLeft());
+ const Fraction aScaleX(aRectangle.getWidth());
+ const Fraction aScaleY(aRectangle.getHeight());
+ MapMode aMapMode(MAP_100TH_MM, aOrigin, aScaleX, aScaleY);
+
+ Size aDummySize(2, 2);
+ aOut.SetOutputSizePixel(aDummySize);
+ aOut.EnableOutput(FALSE);
+ aOut.SetMapMode(aMapMode);
+
+ aMtf.Clear();
+ aMtf.Record(&aOut);
+
+ const Fraction aNeutralFraction(1, 1);
+ const MapMode aRelativeMapMode(
+ MAP_RELATIVE,
+ Point(-aRectangle.Left(), -aRectangle.Top()),
+ aNeutralFraction, aNeutralFraction);
+ aOut.SetMapMode(aRelativeMapMode);
+
+ if(false)
+ {
+ const sal_Int32 nHor(aRectangle.getWidth() / 4);
+ const sal_Int32 nVer(aRectangle.getHeight() / 4);
+ const Rectangle aCenteredRectangle(
+ aRectangle.Left() + nHor, aRectangle.Top() + nVer,
+ aRectangle.Right() - nHor, aRectangle.Bottom() - nVer);
+ aOut.SetClipRegion(aCenteredRectangle);
+ }
+
+ if(false)
+ {
+ const Rectangle aRightRectangle(aRectangle.TopCenter(), aRectangle.BottomRight());
+ aOut.IntersectClipRegion(aRightRectangle);
+ }
+
+ if(false)
+ {
+ const Rectangle aRightRectangle(aRectangle.TopCenter(), aRectangle.BottomRight());
+ const Rectangle aBottomRectangle(aRectangle.LeftCenter(), aRectangle.BottomRight());
+ Region aRegion(aRightRectangle);
+ aRegion.Intersect(aBottomRectangle);
+ aOut.IntersectClipRegion(aRegion);
+ }
+
+ if(false)
+ {
+ const sal_Int32 nHor(aRectangle.getWidth() / 10);
+ const sal_Int32 nVer(aRectangle.getHeight() / 10);
+ aOut.MoveClipRegion(nHor, nVer);
+ }
+
+ if(false)
+ {
+ Wallpaper aWallpaper(Color(COL_BLACK));
+ aOut.DrawWallpaper(aRectangle, aWallpaper);
+ }
+
+ if(false)
+ {
+ Wallpaper aWallpaper(Gradient(GRADIENT_LINEAR, Color(COL_RED), Color(COL_GREEN)));
+ aOut.DrawWallpaper(aRectangle, aWallpaper);
+ }
+
+ if(false)
+ {
+ SvFileStream aRead((const String&)String(ByteString( "c:\\test.png" ), RTL_TEXTENCODING_UTF8), STREAM_READ);
+ vcl::PNGReader aPNGReader(aRead);
+ BitmapEx aBitmapEx(aPNGReader.Read());
+ Wallpaper aWallpaper(aBitmapEx);
+ aOut.DrawWallpaper(aRectangle, aWallpaper);
+ }
+
+ if(false)
+ {
+ const double fHor(aRectangle.getWidth());
+ const double fVer(aRectangle.getHeight());
+ Color aColor(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0));
+
+ for(sal_uInt32 a(0); a < 5000; a++)
+ {
+ const Point aPoint(
+ aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)),
+ aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0)));
+
+ if(!(a % 3))
+ {
+ aColor = Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0));
+ }
+
+ aOut.DrawPixel(aPoint, aColor);
+ }
+ }
+
+ if(false)
+ {
+ const double fHor(aRectangle.getWidth());
+ const double fVer(aRectangle.getHeight());
+
+ aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
+ aOut.SetFillColor();
+
+ for(sal_uInt32 a(0); a < 5000; a++)
+ {
+ const Point aPoint(
+ aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)),
+ aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0)));
+ aOut.DrawPixel(aPoint);
+ }
+ }
+
+ if(false)
+ {
+ const double fHor(aRectangle.getWidth());
+ const double fVer(aRectangle.getHeight());
+
+ aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
+ aOut.SetFillColor();
+
+ Point aStart(
+ aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)),
+ aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0)));
+ Point aStop(
+ aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)),
+ aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0)));
+
+ LineInfo aLineInfo(LINE_SOLID, basegfx::fround(fHor / 50.0));
+ bool bUseLineInfo(false);
+
+ for(sal_uInt32 a(0); a < 20; a++)
+ {
+ if(!(a%6))
+ {
+ bUseLineInfo = !bUseLineInfo;
+ }
+
+ if(!(a%4))
+ {
+ aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
+ }
+
+ if(a%3)
+ {
+ aStart = aStop;
+ aStop = Point(
+ aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)),
+ aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0)));
+ }
+ else
+ {
+ aStart = Point(
+ aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)),
+ aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0)));
+ aStop = Point(
+ aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)),
+ aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0)));
+ }
+
+ if(bUseLineInfo)
+ {
+ aOut.DrawLine(aStart, aStop, aLineInfo);
+ }
+ else
+ {
+ aOut.DrawLine(aStart, aStop);
+ }
+ }
+ }
+
+ if(false)
+ {
+ aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
+ aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
+ aOut.DrawRect(aRectangle);
+ }
+
+ if(false)
+ {
+ aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
+ aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
+ const sal_uInt32 nHor(aRectangle.getWidth() / 10);
+ const sal_uInt32 nVer(aRectangle.getHeight() / 10);
+ aOut.DrawRect(aRectangle, nHor, nVer);
+ }
+
+ if(false)
+ {
+ aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
+ aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
+ aOut.DrawEllipse(aRectangle);
+ }
+
+ if(false)
+ {
+ aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
+ aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
+ aOut.DrawArc(aRectangle, aRectangle.TopLeft(), aRectangle.BottomCenter());
+ }
+
+ if(false)
+ {
+ aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
+ aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
+ aOut.DrawPie(aRectangle, aRectangle.TopLeft(), aRectangle.BottomCenter());
+ }
+
+ if(false)
+ {
+ aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
+ aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
+ aOut.DrawChord(aRectangle, aRectangle.TopLeft(), aRectangle.BottomCenter());
+ }
+
+ if(false)
+ {
+ const double fHor(aRectangle.getWidth());
+ const double fVer(aRectangle.getHeight());
+
+ for(sal_uInt32 b(0); b < 5; b++)
+ {
+ const sal_uInt32 nCount(basegfx::fround(rand() * (20 / 32767.0)));
+ const bool bClose(basegfx::fround(rand() / 32767.0));
+ Polygon aPolygon(nCount + (bClose ? 1 : 0));
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ const Point aPoint(
+ aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)),
+ aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0)));
+ aPolygon[a] = aPoint;
+ }
+
+ if(bClose)
+ {
+ aPolygon[aPolygon.GetSize() - 1] = aPolygon[0];
+ }
+
+ aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
+ aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
+
+ if(!(b%2))
+ {
+ const LineInfo aLineInfo(LINE_SOLID, basegfx::fround(fHor / 50.0));
+ aOut.DrawPolyLine(aPolygon, aLineInfo);
+ }
+ else
+ {
+ aOut.DrawPolyLine(aPolygon);
+ }
+ }
+ }
+
+ if(false)
+ {
+ const double fHor(aRectangle.getWidth());
+ const double fVer(aRectangle.getHeight());
+
+ for(sal_uInt32 b(0); b < 5; b++)
+ {
+ const sal_uInt32 nCount(basegfx::fround(rand() * (20 / 32767.0)));
+ const bool bClose(basegfx::fround(rand() / 32767.0));
+ Polygon aPolygon(nCount + (bClose ? 1 : 0));
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ const Point aPoint(
+ aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)),
+ aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0)));
+ aPolygon[a] = aPoint;
+ }
+
+ if(bClose)
+ {
+ aPolygon[aPolygon.GetSize() - 1] = aPolygon[0];
+ }
+
+ aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
+ aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
+ aOut.DrawPolygon(aPolygon);
+ }
+ }
+
+ if(false)
+ {
+ const double fHor(aRectangle.getWidth());
+ const double fVer(aRectangle.getHeight());
+ PolyPolygon aPolyPolygon;
+
+ for(sal_uInt32 b(0); b < 3; b++)
+ {
+ const sal_uInt32 nCount(basegfx::fround(rand() * (6 / 32767.0)));
+ const bool bClose(basegfx::fround(rand() / 32767.0));
+ Polygon aPolygon(nCount + (bClose ? 1 : 0));
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ const Point aPoint(
+ aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)),
+ aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0)));
+ aPolygon[a] = aPoint;
+ }
+
+ if(bClose)
+ {
+ aPolygon[aPolygon.GetSize() - 1] = aPolygon[0];
+ }
+
+ aPolyPolygon.Insert(aPolygon);
+ }
+
+ aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
+ aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
+ aOut.DrawPolyPolygon(aPolyPolygon);
+ }
+
+ if(false)
+ {
+ SvFileStream aRead((const String&)String(ByteString( "c:\\test.png" ), RTL_TEXTENCODING_UTF8), STREAM_READ);
+ vcl::PNGReader aPNGReader(aRead);
+ BitmapEx aBitmapEx(aPNGReader.Read());
+ aOut.DrawBitmapEx(aRectangle.TopLeft(), aBitmapEx);
+ }
+
+ if(false)
+ {
+ SvFileStream aRead((const String&)String(ByteString( "c:\\test.png" ), RTL_TEXTENCODING_UTF8), STREAM_READ);
+ vcl::PNGReader aPNGReader(aRead);
+ BitmapEx aBitmapEx(aPNGReader.Read());
+ aOut.DrawBitmapEx(aRectangle.TopLeft(), aRectangle.GetSize(), aBitmapEx);
+ }
+
+ if(false)
+ {
+ SvFileStream aRead((const String&)String(ByteString( "c:\\test.png" ), RTL_TEXTENCODING_UTF8), STREAM_READ);
+ vcl::PNGReader aPNGReader(aRead);
+ BitmapEx aBitmapEx(aPNGReader.Read());
+ const Size aSizePixel(aBitmapEx.GetSizePixel());
+ aOut.DrawBitmapEx(
+ aRectangle.TopLeft(),
+ aRectangle.GetSize(),
+ Point(0, 0),
+ Size(aSizePixel.Width() /2, aSizePixel.Height() / 2),
+ aBitmapEx);
+ }
+
+ if(false)
+ {
+ const double fHor(aRectangle.getWidth());
+ const double fVer(aRectangle.getHeight());
+ const Point aPointA(
+ aRectangle.Left() + basegfx::fround(fHor * 0.2),
+ aRectangle.Top() + basegfx::fround(fVer * 0.3));
+ const Point aPointB(
+ aRectangle.Left() + basegfx::fround(fHor * 0.2),
+ aRectangle.Top() + basegfx::fround(fVer * 0.5));
+ const Point aPointC(
+ aRectangle.Left() + basegfx::fround(fHor * 0.2),
+ aRectangle.Top() + basegfx::fround(fVer * 0.7));
+ const String aText(ByteString("Hello, World!"), RTL_TEXTENCODING_UTF8);
+
+ const String aFontName(ByteString("Comic Sans MS"), RTL_TEXTENCODING_UTF8);
+ Font aFont(aFontName, Size(0, 1000));
+ aFont.SetAlign(ALIGN_BASELINE);
+ aFont.SetColor(COL_RED);
+ //sal_Int32* pDXArray = new sal_Int32[aText.Len()];
+
+ aFont.SetOutline(true);
+ aOut.SetFont(aFont);
+ aOut.DrawText(aPointA, aText, 0, aText.Len());
+
+ aFont.SetShadow(true);
+ aOut.SetFont(aFont);
+ aOut.DrawText(aPointB, aText, 0, aText.Len());
+
+ aFont.SetRelief(RELIEF_EMBOSSED);
+ aOut.SetFont(aFont);
+ aOut.DrawText(aPointC, aText, 0, aText.Len());
+
+ //delete pDXArray;
+ }
+
+ if(false)
+ {
+ const double fHor(aRectangle.getWidth());
+ const double fVer(aRectangle.getHeight());
+ const Point aPointA(
+ aRectangle.Left() + basegfx::fround(fHor * 0.2),
+ aRectangle.Top() + basegfx::fround(fVer * 0.3));
+ const Point aPointB(
+ aRectangle.Left() + basegfx::fround(fHor * 0.2),
+ aRectangle.Top() + basegfx::fround(fVer * 0.5));
+ const Point aPointC(
+ aRectangle.Left() + basegfx::fround(fHor * 0.2),
+ aRectangle.Top() + basegfx::fround(fVer * 0.7));
+ const String aText(ByteString("Hello, World!"), RTL_TEXTENCODING_UTF8);
+
+ const String aFontName(ByteString("Comic Sans MS"), RTL_TEXTENCODING_UTF8);
+ Font aFont(aFontName, Size(0, 1000));
+ aFont.SetAlign(ALIGN_BASELINE);
+ aFont.SetColor(COL_RED);
+
+ aOut.SetFont(aFont);
+ const sal_Int32 nWidth(aOut.GetTextWidth(aText, 0, aText.Len()));
+ aOut.DrawText(aPointA, aText, 0, aText.Len());
+ aOut.DrawTextLine(aPointA, nWidth, STRIKEOUT_SINGLE, UNDERLINE_SINGLE, UNDERLINE_SMALLWAVE);
+ aOut.DrawTextLine(aPointB, nWidth, STRIKEOUT_SINGLE, UNDERLINE_SINGLE, UNDERLINE_SMALLWAVE);
+ aOut.DrawTextLine(aPointC, nWidth, STRIKEOUT_SINGLE, UNDERLINE_SINGLE, UNDERLINE_SMALLWAVE);
+ }
+
+ aMtf.Stop();
+ aMtf.WindStart();
+ aMtf.SetPrefMapMode(MapMode(MAP_100TH_MM));
+ aMtf.SetPrefSize(Size(aRectangle.getWidth(), aRectangle.getHeight()));
+
+ xPrimitive = Primitive2DReference(
+ new MetafilePrimitive2D(
+ aTransform,
+ aMtf));
+ }
+ else
+ {
+#endif // USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE
+ // create MetafilePrimitive2D
+ const Graphic aGraphic(getGraphicObject().GetGraphic());
+ const GDIMetaFile& rMetafile = aTransformedGraphic.GetGDIMetaFile();
+
+ xPrimitive = Primitive2DReference(
+ new MetafilePrimitive2D(
+ aTransform,
+ rMetafile));
+
+ // #i100357# find out if clipping is needed for this primitive. Unfortunately,
+ // there exist Metafiles who's content is bigger than the proposed PrefSize set
+ // at them. This is an error, but we need to work around this
+ const Size aMetaFilePrefSize(rMetafile.GetPrefSize());
+ const Size aMetaFileRealSize(
+ const_cast< GDIMetaFile& >(rMetafile).GetBoundRect(
+ *Application::GetDefaultDevice()).GetSize());
+
+ if(aMetaFileRealSize.getWidth() > aMetaFilePrefSize.getWidth()
+ || aMetaFileRealSize.getHeight() > aMetaFilePrefSize.getHeight())
+ {
+ // clipping needed. Embed to MaskPrimitive2D. Create childs and mask polygon
+ const primitive2d::Primitive2DSequence aChildContent(&xPrimitive, 1);
+ basegfx::B2DPolygon aMaskPolygon(basegfx::tools::createUnitPolygon());
+ aMaskPolygon.transform(aTransform);
+
+ xPrimitive = Primitive2DReference(
+ new MaskPrimitive2D(
+ basegfx::B2DPolyPolygon(aMaskPolygon),
+ aChildContent));
+ }
+#ifdef USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE
+ }
+#endif // USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE
+
+ break;
+ }
+
+ default:
+ {
+ // nothing to create
+ break;
+ }
+ }
+
+ if(xPrimitive.is())
+ {
+ // 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);
+ double fFactorY(1.0);
+
+ {
+ const MapMode aMapMode100thmm(MAP_100TH_MM);
+ Size aBitmapSize(getGraphicObject().GetPrefSize());
+
+ // #i95968# better support PrefMapMode; special for MAP_PIXEL was missing
+ if(MAP_PIXEL == getGraphicObject().GetPrefMapMode().GetMapUnit())
+ {
+ aBitmapSize = Application::GetDefaultDevice()->PixelToLogic(aBitmapSize, aMapMode100thmm);
+ }
+ else
+ {
+ aBitmapSize = Application::GetDefaultDevice()->LogicToLogic(aBitmapSize, getGraphicObject().GetPrefMapMode(), aMapMode100thmm);
+ }
+
+ const double fDivX(aBitmapSize.Width() - getGraphicAttr().GetLeftCrop() - getGraphicAttr().GetRightCrop());
+ const double fDivY(aBitmapSize.Height() - getGraphicAttr().GetTopCrop() - getGraphicAttr().GetBottomCrop());
+
+ if(!basegfx::fTools::equalZero(fDivX))
+ {
+ fFactorX = aScale.getX() / fDivX;
+ }
+
+ if(!basegfx::fTools::equalZero(fDivY))
+ {
+ fFactorY = 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);
+ }
+ }
+ }
+
+ return aRetval;
+ }
+
+ GraphicPrimitive2D::GraphicPrimitive2D(
+ const basegfx::B2DHomMatrix& rTransform,
+ const GraphicObject& rGraphicObject,
+ const GraphicAttr& rGraphicAttr)
+ : BufferedDecompositionPrimitive2D(),
+ maTransform(rTransform),
+ maGraphicObject(rGraphicObject),
+ maGraphicAttr(rGraphicAttr)
+ {
+ }
+
+ GraphicPrimitive2D::GraphicPrimitive2D(
+ const basegfx::B2DHomMatrix& rTransform,
+ const GraphicObject& rGraphicObject)
+ : BufferedDecompositionPrimitive2D(),
+ maTransform(rTransform),
+ maGraphicObject(rGraphicObject),
+ maGraphicAttr()
+ {
+ }
+
+ bool GraphicPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const GraphicPrimitive2D& rCompare = (GraphicPrimitive2D&)rPrimitive;
+
+ return (getTransform() == rCompare.getTransform()
+ && getGraphicObject() == rCompare.getGraphicObject()
+ && getGraphicAttr() == rCompare.getGraphicAttr());
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange GraphicPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ basegfx::B2DRange aRetval(0.0, 0.0, 1.0, 1.0);
+ aRetval.transform(getTransform());
+ return aRetval;
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(GraphicPrimitive2D, PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/gridprimitive2d.cxx b/drawinglayer/source/primitive2d/gridprimitive2d.cxx
new file mode 100644
index 000000000000..6c0fd1948a37
--- /dev/null
+++ b/drawinglayer/source/primitive2d/gridprimitive2d.cxx
@@ -0,0 +1,323 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/gridprimitive2d.hxx>
+#include <basegfx/tools/canvastools.hxx>
+#include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx>
+#include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence GridPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ Primitive2DSequence aRetval;
+
+ if(!rViewInformation.getViewport().isEmpty() && getWidth() > 0.0 && getHeight() > 0.0)
+ {
+ // decompose grid matrix to get logic size
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ getTransform().decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // create grid matrix which transforms from scaled logic to view
+ basegfx::B2DHomMatrix aRST(basegfx::tools::createShearXRotateTranslateB2DHomMatrix(
+ fShearX, fRotate, aTranslate.getX(), aTranslate.getY()));
+ aRST *= rViewInformation.getObjectToViewTransformation();
+
+ // get step widths
+ double fStepX(getWidth());
+ double fStepY(getHeight());
+ const double fMinimalStep(10.0);
+
+ // guarantee a step width of 10.0
+ if(basegfx::fTools::less(fStepX, fMinimalStep))
+ {
+ fStepX = fMinimalStep;
+ }
+
+ if(basegfx::fTools::less(fStepY, fMinimalStep))
+ {
+ fStepY = fMinimalStep;
+ }
+
+ // get relative distances in view coordinates
+ double fViewStepX((rViewInformation.getObjectToViewTransformation() * basegfx::B2DVector(fStepX, 0.0)).getLength());
+ double fViewStepY((rViewInformation.getObjectToViewTransformation() * basegfx::B2DVector(0.0, fStepY)).getLength());
+ double fSmallStepX(1.0), fViewSmallStepX(1.0), fSmallStepY(1.0), fViewSmallStepY(1.0);
+ sal_uInt32 nSmallStepsX(0L), nSmallStepsY(0L);
+
+ // setup subdivisions
+ if(getSubdivisionsX())
+ {
+ fSmallStepX = fStepX / getSubdivisionsX();
+ fViewSmallStepX = fViewStepX / getSubdivisionsX();
+ }
+
+ if(getSubdivisionsY())
+ {
+ fSmallStepY = fStepY / getSubdivisionsY();
+ fViewSmallStepY = fViewStepY / getSubdivisionsY();
+ }
+
+ // correct step width
+ while(fViewStepX < getSmallestViewDistance())
+ {
+ fViewStepX *= 2.0;
+ fStepX *= 2.0;
+ }
+
+ while(fViewStepY < getSmallestViewDistance())
+ {
+ fViewStepY *= 2.0;
+ fStepY *= 2.0;
+ }
+
+ // correct small step width
+ if(getSubdivisionsX())
+ {
+ while(fViewSmallStepX < getSmallestSubdivisionViewDistance())
+ {
+ fViewSmallStepX *= 2.0;
+ fSmallStepX *= 2.0;
+ }
+
+ nSmallStepsX = (sal_uInt32)(fStepX / fSmallStepX);
+ }
+
+ if(getSubdivisionsY())
+ {
+ while(fViewSmallStepY < getSmallestSubdivisionViewDistance())
+ {
+ fViewSmallStepY *= 2.0;
+ fSmallStepY *= 2.0;
+ }
+
+ nSmallStepsY = (sal_uInt32)(fStepY / fSmallStepY);
+ }
+
+ // prepare point vectors for point and cross markers
+ std::vector< basegfx::B2DPoint > aPositionsPoint;
+ std::vector< basegfx::B2DPoint > aPositionsCross;
+
+ for(double fX(0.0); fX < aScale.getX(); fX += fStepX)
+ {
+ const bool bXZero(basegfx::fTools::equalZero(fX));
+
+ for(double fY(0.0); fY < aScale.getY(); fY += fStepY)
+ {
+ const bool bYZero(basegfx::fTools::equalZero(fY));
+
+ if(!bXZero && !bYZero)
+ {
+ // get discrete position and test against 3x3 area surrounding it
+ // since it's a cross
+ const double fHalfCrossSize(3.0 * 0.5);
+ const basegfx::B2DPoint aViewPos(aRST * basegfx::B2DPoint(fX, fY));
+ const basegfx::B2DRange aDiscreteRangeCross(
+ aViewPos.getX() - fHalfCrossSize, aViewPos.getY() - fHalfCrossSize,
+ aViewPos.getX() + fHalfCrossSize, aViewPos.getY() + fHalfCrossSize);
+
+ if(rViewInformation.getDiscreteViewport().overlaps(aDiscreteRangeCross))
+ {
+ const basegfx::B2DPoint aLogicPos(rViewInformation.getInverseObjectToViewTransformation() * aViewPos);
+ aPositionsCross.push_back(aLogicPos);
+ }
+ }
+
+ if(getSubdivisionsX() && !bYZero)
+ {
+ double fF(fX + fSmallStepX);
+
+ for(sal_uInt32 a(1L); a < nSmallStepsX && fF < aScale.getX(); a++, fF += fSmallStepX)
+ {
+ const basegfx::B2DPoint aViewPos(aRST * basegfx::B2DPoint(fF, fY));
+
+ if(rViewInformation.getDiscreteViewport().isInside(aViewPos))
+ {
+ const basegfx::B2DPoint aLogicPos(rViewInformation.getInverseObjectToViewTransformation() * aViewPos);
+ aPositionsPoint.push_back(aLogicPos);
+ }
+ }
+ }
+
+ if(getSubdivisionsY() && !bXZero)
+ {
+ double fF(fY + fSmallStepY);
+
+ for(sal_uInt32 a(1L); a < nSmallStepsY && fF < aScale.getY(); a++, fF += fSmallStepY)
+ {
+ const basegfx::B2DPoint aViewPos(aRST * basegfx::B2DPoint(fX, fF));
+
+ if(rViewInformation.getDiscreteViewport().isInside(aViewPos))
+ {
+ const basegfx::B2DPoint aLogicPos(rViewInformation.getInverseObjectToViewTransformation() * aViewPos);
+ aPositionsPoint.push_back(aLogicPos);
+ }
+ }
+ }
+ }
+ }
+
+ // prepare return value
+ const sal_uInt32 nCountPoint(aPositionsPoint.size());
+ const sal_uInt32 nCountCross(aPositionsCross.size());
+ const sal_uInt32 nRetvalCount((nCountPoint ? 1 : 0) + (nCountCross ? 1 : 0));
+ sal_uInt32 nInsertCounter(0);
+
+ aRetval.realloc(nRetvalCount);
+
+ // add PointArrayPrimitive2D if point markers were added
+ if(nCountPoint)
+ {
+ aRetval[nInsertCounter++] = Primitive2DReference(new PointArrayPrimitive2D(aPositionsPoint, getBColor()));
+ }
+
+ // add MarkerArrayPrimitive2D if cross markers were added
+ if(nCountCross)
+ {
+ if(!getSubdivisionsX() && !getSubdivisionsY())
+ {
+ // no subdivisions, so fall back to points at grid positions, no need to
+ // visualize a difference between divisions and sub-divisions
+ aRetval[nInsertCounter++] = Primitive2DReference(new PointArrayPrimitive2D(aPositionsCross, getBColor()));
+ }
+ else
+ {
+ aRetval[nInsertCounter++] = Primitive2DReference(new MarkerArrayPrimitive2D(aPositionsCross, getCrossMarker()));
+ }
+ }
+ }
+
+ return aRetval;
+ }
+
+ GridPrimitive2D::GridPrimitive2D(
+ const basegfx::B2DHomMatrix& rTransform,
+ double fWidth,
+ double fHeight,
+ double fSmallestViewDistance,
+ double fSmallestSubdivisionViewDistance,
+ sal_uInt32 nSubdivisionsX,
+ sal_uInt32 nSubdivisionsY,
+ const basegfx::BColor& rBColor,
+ const BitmapEx& rCrossMarker)
+ : BufferedDecompositionPrimitive2D(),
+ maTransform(rTransform),
+ mfWidth(fWidth),
+ mfHeight(fHeight),
+ mfSmallestViewDistance(fSmallestViewDistance),
+ mfSmallestSubdivisionViewDistance(fSmallestSubdivisionViewDistance),
+ mnSubdivisionsX(nSubdivisionsX),
+ mnSubdivisionsY(nSubdivisionsY),
+ maBColor(rBColor),
+ maCrossMarker(rCrossMarker),
+ maLastObjectToViewTransformation(),
+ maLastViewport()
+ {
+ }
+
+ bool GridPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const GridPrimitive2D& rCompare = (GridPrimitive2D&)rPrimitive;
+
+ return (getTransform() == rCompare.getTransform()
+ && getWidth() == rCompare.getWidth()
+ && getHeight() == rCompare.getHeight()
+ && getSmallestViewDistance() == rCompare.getSmallestViewDistance()
+ && getSmallestSubdivisionViewDistance() == rCompare.getSmallestSubdivisionViewDistance()
+ && getSubdivisionsX() == rCompare.getSubdivisionsX()
+ && getSubdivisionsY() == rCompare.getSubdivisionsY()
+ && getBColor() == rCompare.getBColor()
+ && getCrossMarker() == rCompare.getCrossMarker());
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange GridPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ // get object's range
+ basegfx::B2DRange aUnitRange(0.0, 0.0, 1.0, 1.0);
+ aUnitRange.transform(getTransform());
+
+ // intersect with visible part
+ aUnitRange.intersect(rViewInformation.getViewport());
+
+ return aUnitRange;
+ }
+
+ Primitive2DSequence GridPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if(getBuffered2DDecomposition().hasElements())
+ {
+ if(maLastViewport != rViewInformation.getViewport() || maLastObjectToViewTransformation != rViewInformation.getObjectToViewTransformation())
+ {
+ // conditions of last local decomposition have changed, delete
+ const_cast< GridPrimitive2D* >(this)->setBuffered2DDecomposition(Primitive2DSequence());
+ }
+ }
+
+ if(!getBuffered2DDecomposition().hasElements())
+ {
+ // remember ViewRange and ViewTransformation
+ const_cast< GridPrimitive2D* >(this)->maLastObjectToViewTransformation = rViewInformation.getObjectToViewTransformation();
+ const_cast< GridPrimitive2D* >(this)->maLastViewport = rViewInformation.getViewport();
+ }
+
+ // use parent implementation
+ return BufferedDecompositionPrimitive2D::get2DDecomposition(rViewInformation);
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(GridPrimitive2D, PRIMITIVE2D_ID_GRIDPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/groupprimitive2d.cxx b/drawinglayer/source/primitive2d/groupprimitive2d.cxx
new file mode 100644
index 000000000000..abb6989a5763
--- /dev/null
+++ b/drawinglayer/source/primitive2d/groupprimitive2d.cxx
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/groupprimitive2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ GroupPrimitive2D::GroupPrimitive2D( const Primitive2DSequence& rChildren )
+ : BasePrimitive2D(),
+ maChildren(rChildren)
+ {
+ }
+
+ /** The compare opertator uses the Sequence::==operator, so only checking if
+ the rererences are equal. All non-equal references are interpreted as
+ non-equal.
+ */
+ bool GroupPrimitive2D::operator==( const BasePrimitive2D& rPrimitive ) const
+ {
+ if(BasePrimitive2D::operator==(rPrimitive))
+ {
+ const GroupPrimitive2D& rCompare = static_cast< const GroupPrimitive2D& >(rPrimitive);
+
+ return (arePrimitive2DSequencesEqual(getChildren(), rCompare.getChildren()));
+ }
+
+ return false;
+ }
+
+ /// default: just return children, so all renderers not supporting group will use it's content
+ Primitive2DSequence GroupPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ return getChildren();
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(GroupPrimitive2D, PRIMITIVE2D_ID_GROUPPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/helplineprimitive2d.cxx b/drawinglayer/source/primitive2d/helplineprimitive2d.cxx
new file mode 100644
index 000000000000..45559b7c1b50
--- /dev/null
+++ b/drawinglayer/source/primitive2d/helplineprimitive2d.cxx
@@ -0,0 +1,225 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/helplineprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygonclipper.hxx>
+#include <basegfx/tools/canvastools.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence HelplinePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ std::vector< BasePrimitive2D* > aTempPrimitiveTarget;
+
+ if(!rViewInformation.getViewport().isEmpty() && !getDirection().equalZero())
+ {
+ // position to view coordinates, DashLen and DashLen in logic
+ const basegfx::B2DPoint aViewPosition(rViewInformation.getObjectToViewTransformation() * getPosition());
+
+ switch(getStyle())
+ {
+ default : // HELPLINESTYLE2D_POINT
+ {
+ const double fViewFixValue(15.0);
+ basegfx::B2DVector aNormalizedDirection(getDirection());
+ aNormalizedDirection.normalize();
+ aNormalizedDirection *= fViewFixValue;
+ const basegfx::B2DPoint aStartA(aViewPosition - aNormalizedDirection);
+ const basegfx::B2DPoint aEndA(aViewPosition + aNormalizedDirection);
+ basegfx::B2DPolygon aLineA;
+ aLineA.append(aStartA);
+ aLineA.append(aEndA);
+ aLineA.transform(rViewInformation.getInverseObjectToViewTransformation());
+ PolygonMarkerPrimitive2D* pNewA = new PolygonMarkerPrimitive2D(aLineA, getRGBColA(), getRGBColB(), getDiscreteDashLength());
+ aTempPrimitiveTarget.push_back(pNewA);
+
+ const basegfx::B2DVector aPerpendicularNormalizedDirection(basegfx::getPerpendicular(aNormalizedDirection));
+ const basegfx::B2DPoint aStartB(aViewPosition - aPerpendicularNormalizedDirection);
+ const basegfx::B2DPoint aEndB(aViewPosition + aPerpendicularNormalizedDirection);
+ basegfx::B2DPolygon aLineB;
+ aLineB.append(aStartB);
+ aLineB.append(aEndB);
+ aLineB.transform(rViewInformation.getInverseObjectToViewTransformation());
+ PolygonMarkerPrimitive2D* pNewB = new PolygonMarkerPrimitive2D(aLineB, getRGBColA(), getRGBColB(), getDiscreteDashLength());
+ aTempPrimitiveTarget.push_back(pNewB);
+
+ break;
+ }
+ case HELPLINESTYLE2D_LINE :
+ {
+ basegfx::B2DPolygon aLine;
+
+ if(basegfx::areParallel(getDirection(), basegfx::B2DVector(1.0, 0.0)))
+ {
+ // parallel to X-Axis, get cuts with Y-Axes
+ const double fCutA((rViewInformation.getDiscreteViewport().getMinX() - aViewPosition.getX()) / getDirection().getX());
+ const double fCutB((rViewInformation.getDiscreteViewport().getMaxX() - aViewPosition.getX()) / getDirection().getX());
+ const basegfx::B2DPoint aPosA(aViewPosition + (fCutA * getDirection()));
+ const basegfx::B2DPoint aPosB(aViewPosition + (fCutB * getDirection()));
+ const bool bBothLeft(aPosA.getX() < rViewInformation.getDiscreteViewport().getMinX() && aPosB.getX() < rViewInformation.getDiscreteViewport().getMinX());
+ const bool bBothRight(aPosA.getX() > rViewInformation.getDiscreteViewport().getMaxX() && aPosB.getX() < rViewInformation.getDiscreteViewport().getMaxX());
+
+ if(!bBothLeft && !bBothRight)
+ {
+ aLine.append(aPosA);
+ aLine.append(aPosB);
+ }
+ }
+ else
+ {
+ // get cuts with X-Axes
+ const double fCutA((rViewInformation.getDiscreteViewport().getMinY() - aViewPosition.getY()) / getDirection().getY());
+ const double fCutB((rViewInformation.getDiscreteViewport().getMaxY() - aViewPosition.getY()) / getDirection().getY());
+ const basegfx::B2DPoint aPosA(aViewPosition + (fCutA * getDirection()));
+ const basegfx::B2DPoint aPosB(aViewPosition + (fCutB * getDirection()));
+ const bool bBothAbove(aPosA.getY() < rViewInformation.getDiscreteViewport().getMinY() && aPosB.getY() < rViewInformation.getDiscreteViewport().getMinY());
+ const bool bBothBelow(aPosA.getY() > rViewInformation.getDiscreteViewport().getMaxY() && aPosB.getY() < rViewInformation.getDiscreteViewport().getMaxY());
+
+ if(!bBothAbove && !bBothBelow)
+ {
+ aLine.append(aPosA);
+ aLine.append(aPosB);
+ }
+ }
+
+ if(aLine.count())
+ {
+ // clip against visible area
+ const basegfx::B2DPolyPolygon aResult(basegfx::tools::clipPolygonOnRange(aLine, rViewInformation.getDiscreteViewport(), true, true));
+
+ for(sal_uInt32 a(0L); a < aResult.count(); a++)
+ {
+ basegfx::B2DPolygon aPart(aResult.getB2DPolygon(a));
+ aPart.transform(rViewInformation.getInverseObjectToViewTransformation());
+ PolygonMarkerPrimitive2D* pNew = new PolygonMarkerPrimitive2D(aPart, getRGBColA(), getRGBColB(), getDiscreteDashLength());
+ aTempPrimitiveTarget.push_back(pNew);
+ }
+ }
+
+ break;
+ }
+ }
+ }
+
+ // prepare return value
+ Primitive2DSequence aRetval(aTempPrimitiveTarget.size());
+
+ for(sal_uInt32 a(0L); a < aTempPrimitiveTarget.size(); a++)
+ {
+ const Primitive2DReference xRef(aTempPrimitiveTarget[a]);
+ aRetval[a] = xRef;
+ }
+
+ return aRetval;
+ }
+
+ HelplinePrimitive2D::HelplinePrimitive2D(
+ const basegfx::B2DPoint& rPosition,
+ const basegfx::B2DVector& rDirection,
+ HelplineStyle2D eStyle,
+ const basegfx::BColor& rRGBColA,
+ const basegfx::BColor& rRGBColB,
+ double fDiscreteDashLength)
+ : BufferedDecompositionPrimitive2D(),
+ maPosition(rPosition),
+ maDirection(rDirection),
+ meStyle(eStyle),
+ maRGBColA(rRGBColA),
+ maRGBColB(rRGBColB),
+ mfDiscreteDashLength(fDiscreteDashLength),
+ maLastObjectToViewTransformation(),
+ maLastViewport()
+ {
+ }
+
+ bool HelplinePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const HelplinePrimitive2D& rCompare = (HelplinePrimitive2D&)rPrimitive;
+
+ return (getPosition() == rCompare.getPosition()
+ && getDirection() == rCompare.getDirection()
+ && getStyle() == rCompare.getStyle()
+ && getRGBColA() == rCompare.getRGBColA()
+ && getRGBColB() == rCompare.getRGBColB()
+ && getDiscreteDashLength() == rCompare.getDiscreteDashLength());
+ }
+
+ return false;
+ }
+
+ Primitive2DSequence HelplinePrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if(getBuffered2DDecomposition().hasElements())
+ {
+ if(maLastViewport != rViewInformation.getViewport() || maLastObjectToViewTransformation != rViewInformation.getObjectToViewTransformation())
+ {
+ // conditions of last local decomposition have changed, delete
+ const_cast< HelplinePrimitive2D* >(this)->setBuffered2DDecomposition(Primitive2DSequence());
+ }
+ }
+
+ if(!getBuffered2DDecomposition().hasElements())
+ {
+ // remember ViewRange and ViewTransformation
+ const_cast< HelplinePrimitive2D* >(this)->maLastObjectToViewTransformation = rViewInformation.getObjectToViewTransformation();
+ const_cast< HelplinePrimitive2D* >(this)->maLastViewport = rViewInformation.getViewport();
+ }
+
+ // use parent implementation
+ return BufferedDecompositionPrimitive2D::get2DDecomposition(rViewInformation);
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(HelplinePrimitive2D, PRIMITIVE2D_ID_HELPLINEPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/hiddengeometryprimitive2d.cxx b/drawinglayer/source/primitive2d/hiddengeometryprimitive2d.cxx
new file mode 100644
index 000000000000..b40c3a7ae13c
--- /dev/null
+++ b/drawinglayer/source/primitive2d/hiddengeometryprimitive2d.cxx
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: hittestprimitive3d.cxx,v $
+ *
+ * $Revision: 1.1.2.1 $
+ *
+ * last change: $Author: aw $ $Date: 2008/09/25 17:12:14 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library 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 for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/hiddengeometryprimitive2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ HiddenGeometryPrimitive2D::HiddenGeometryPrimitive2D(
+ const Primitive2DSequence& rChildren)
+ : GroupPrimitive2D(rChildren)
+ {
+ }
+
+ basegfx::B2DRange HiddenGeometryPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ return getB2DRangeFromPrimitive2DSequence(getChildren(), rViewInformation);
+ }
+
+ Primitive2DSequence HiddenGeometryPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ return Primitive2DSequence();
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(HiddenGeometryPrimitive2D, PRIMITIVE2D_ID_HIDDENGEOMETRYPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/invertprimitive2d.cxx b/drawinglayer/source/primitive2d/invertprimitive2d.cxx
new file mode 100644
index 000000000000..dc1f10fbc075
--- /dev/null
+++ b/drawinglayer/source/primitive2d/invertprimitive2d.cxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/invertprimitive2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ InvertPrimitive2D::InvertPrimitive2D(
+ const Primitive2DSequence& rChildren)
+ : GroupPrimitive2D(rChildren)
+ {
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(InvertPrimitive2D, PRIMITIVE2D_ID_INVERTPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/makefile.mk b/drawinglayer/source/primitive2d/makefile.mk
new file mode 100644
index 000000000000..bca5805ae6eb
--- /dev/null
+++ b/drawinglayer/source/primitive2d/makefile.mk
@@ -0,0 +1,89 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..
+PRJNAME=drawinglayer
+TARGET=primitive2d
+ENABLE_EXCEPTIONS=TRUE
+
+# --- Settings ----------------------------------
+
+.INCLUDE : settings.mk
+
+# --- Files -------------------------------------
+
+SLOFILES= \
+ $(SLO)$/transparenceprimitive2d.obj \
+ $(SLO)$/animatedprimitive2d.obj \
+ $(SLO)$/baseprimitive2d.obj \
+ $(SLO)$/backgroundcolorprimitive2d.obj \
+ $(SLO)$/bitmapprimitive2d.obj \
+ $(SLO)$/borderlineprimitive2d.obj \
+ $(SLO)$/chartprimitive2d.obj \
+ $(SLO)$/controlprimitive2d.obj \
+ $(SLO)$/discretebitmapprimitive2d.obj \
+ $(SLO)$/embedded3dprimitive2d.obj \
+ $(SLO)$/epsprimitive2d.obj \
+ $(SLO)$/fillbitmapprimitive2d.obj \
+ $(SLO)$/fillgradientprimitive2d.obj \
+ $(SLO)$/fillhatchprimitive2d.obj \
+ $(SLO)$/graphicprimitive2d.obj \
+ $(SLO)$/gridprimitive2d.obj \
+ $(SLO)$/groupprimitive2d.obj \
+ $(SLO)$/helplineprimitive2d.obj \
+ $(SLO)$/hiddengeometryprimitive2d.obj \
+ $(SLO)$/invertprimitive2d.obj \
+ $(SLO)$/markerarrayprimitive2d.obj \
+ $(SLO)$/pointarrayprimitive2d.obj \
+ $(SLO)$/maskprimitive2d.obj \
+ $(SLO)$/mediaprimitive2d.obj \
+ $(SLO)$/metafileprimitive2d.obj \
+ $(SLO)$/modifiedcolorprimitive2d.obj \
+ $(SLO)$/pagepreviewprimitive2d.obj \
+ $(SLO)$/polypolygonprimitive2d.obj \
+ $(SLO)$/polygonprimitive2d.obj \
+ $(SLO)$/primitivetools2d.obj \
+ $(SLO)$/sceneprimitive2d.obj \
+ $(SLO)$/sdrdecompositiontools2d.obj \
+ $(SLO)$/shadowprimitive2d.obj \
+ $(SLO)$/structuretagprimitive2d.obj \
+ $(SLO)$/texteffectprimitive2d.obj \
+ $(SLO)$/textenumsprimitive2d.obj \
+ $(SLO)$/textlayoutdevice.obj \
+ $(SLO)$/textlineprimitive2d.obj \
+ $(SLO)$/textprimitive2d.obj \
+ $(SLO)$/textstrikeoutprimitive2d.obj \
+ $(SLO)$/textdecoratedprimitive2d.obj \
+ $(SLO)$/texthierarchyprimitive2d.obj \
+ $(SLO)$/transformprimitive2d.obj \
+ $(SLO)$/unifiedtransparenceprimitive2d.obj \
+ $(SLO)$/wallpaperprimitive2d.obj \
+ $(SLO)$/wrongspellprimitive2d.obj
+
+# --- Targets ----------------------------------
+
+.INCLUDE : target.mk
diff --git a/drawinglayer/source/primitive2d/markerarrayprimitive2d.cxx b/drawinglayer/source/primitive2d/markerarrayprimitive2d.cxx
new file mode 100644
index 000000000000..5aa3beebd076
--- /dev/null
+++ b/drawinglayer/source/primitive2d/markerarrayprimitive2d.cxx
@@ -0,0 +1,160 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence MarkerArrayPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ Primitive2DSequence xRetval;
+ const std::vector< basegfx::B2DPoint >& rPositions = getPositions();
+ const sal_uInt32 nMarkerCount(rPositions.size());
+
+ if(nMarkerCount && !getMarker().IsEmpty())
+ {
+ // get pixel size
+ Size aBitmapSize(getMarker().GetSizePixel());
+
+ if(aBitmapSize.Width() && aBitmapSize.Height())
+ {
+ // get logic half pixel size
+ basegfx::B2DVector aLogicHalfSize(rViewInformation.getInverseObjectToViewTransformation() *
+ basegfx::B2DVector(aBitmapSize.getWidth() - 1.0, aBitmapSize.getHeight() - 1.0));
+
+ // use half size for expand
+ aLogicHalfSize *= 0.5;
+
+ // number of primitives is known; realloc accordingly
+ xRetval.realloc(nMarkerCount);
+
+ for(sal_uInt32 a(0); a < nMarkerCount; a++)
+ {
+ const basegfx::B2DPoint& rPosition(rPositions[a]);
+ const basegfx::B2DRange aRange(rPosition - aLogicHalfSize, rPosition + aLogicHalfSize);
+ basegfx::B2DHomMatrix aTransform;
+
+ aTransform.set(0, 0, aRange.getWidth());
+ aTransform.set(1, 1, aRange.getHeight());
+ aTransform.set(0, 2, aRange.getMinX());
+ aTransform.set(1, 2, aRange.getMinY());
+
+ xRetval[a] = Primitive2DReference(new BitmapPrimitive2D(getMarker(), aTransform));
+ }
+ }
+ }
+
+ return xRetval;
+ }
+
+ MarkerArrayPrimitive2D::MarkerArrayPrimitive2D(
+ const std::vector< basegfx::B2DPoint >& rPositions,
+ const BitmapEx& rMarker)
+ : BufferedDecompositionPrimitive2D(),
+ maPositions(rPositions),
+ maMarker(rMarker)
+ {
+ }
+
+ bool MarkerArrayPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const MarkerArrayPrimitive2D& rCompare = (MarkerArrayPrimitive2D&)rPrimitive;
+
+ return (getPositions() == rCompare.getPositions()
+ && getMarker() == rCompare.getMarker());
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange MarkerArrayPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ basegfx::B2DRange aRetval;
+
+ if(getPositions().size())
+ {
+ // get the basic range from the position vector
+ for(std::vector< basegfx::B2DPoint >::const_iterator aIter(getPositions().begin()); aIter != getPositions().end(); aIter++)
+ {
+ aRetval.expand(*aIter);
+ }
+
+ if(!getMarker().IsEmpty())
+ {
+ // get pixel size
+ const Size aBitmapSize(getMarker().GetSizePixel());
+
+ if(aBitmapSize.Width() && aBitmapSize.Height())
+ {
+ // get logic half size
+ basegfx::B2DVector aLogicHalfSize(rViewInformation.getInverseObjectToViewTransformation() *
+ basegfx::B2DVector(aBitmapSize.getWidth(), aBitmapSize.getHeight()));
+
+ // use half size for expand
+ aLogicHalfSize *= 0.5;
+
+ // apply aLogicHalfSize
+ aRetval.expand(aRetval.getMinimum() - aLogicHalfSize);
+ aRetval.expand(aRetval.getMaximum() + aLogicHalfSize);
+ }
+ }
+ }
+
+ return aRetval;
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(MarkerArrayPrimitive2D, PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/maskprimitive2d.cxx b/drawinglayer/source/primitive2d/maskprimitive2d.cxx
new file mode 100644
index 000000000000..ab1d36f3ccc2
--- /dev/null
+++ b/drawinglayer/source/primitive2d/maskprimitive2d.cxx
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ MaskPrimitive2D::MaskPrimitive2D(
+ const basegfx::B2DPolyPolygon& rMask,
+ const Primitive2DSequence& rChildren)
+ : GroupPrimitive2D(rChildren),
+ maMask(rMask)
+ {
+ }
+
+ bool MaskPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(GroupPrimitive2D::operator==(rPrimitive))
+ {
+ const MaskPrimitive2D& rCompare = static_cast< const MaskPrimitive2D& >(rPrimitive);
+
+ return (getMask() == rCompare.getMask());
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange MaskPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ return getMask().getB2DRange();
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(MaskPrimitive2D, PRIMITIVE2D_ID_MASKPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/mediaprimitive2d.cxx b/drawinglayer/source/primitive2d/mediaprimitive2d.cxx
new file mode 100644
index 000000000000..4c69061e819e
--- /dev/null
+++ b/drawinglayer/source/primitive2d/mediaprimitive2d.cxx
@@ -0,0 +1,166 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/mediaprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
+#include <avmedia/mediawindow.hxx>
+#include <svtools/grfmgr.hxx>
+#include <drawinglayer/primitive2d/graphicprimitive2d.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+#include <drawinglayer/primitive2d/hiddengeometryprimitive2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence MediaPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ Primitive2DSequence xRetval(1);
+
+ // create background object
+ basegfx::B2DPolygon aBackgroundPolygon(basegfx::tools::createUnitPolygon());
+ aBackgroundPolygon.transform(getTransform());
+ const Primitive2DReference xRefBackground(
+ new PolyPolygonColorPrimitive2D(
+ basegfx::B2DPolyPolygon(aBackgroundPolygon),
+ getBackgroundColor()));
+ xRetval[0] = xRefBackground;
+
+ // try to get graphic snapshot
+ const Graphic aGraphic(avmedia::MediaWindow::grabFrame(getURL(), true));
+
+ if(GRAPHIC_BITMAP == aGraphic.GetType() || GRAPHIC_GDIMETAFILE == aGraphic.GetType())
+ {
+ const GraphicObject aGraphicObject(aGraphic);
+ const GraphicAttr aGraphicAttr;
+ xRetval.realloc(2);
+ xRetval[0] = xRefBackground;
+ xRetval[1] = Primitive2DReference(new GraphicPrimitive2D(getTransform(), aGraphicObject, aGraphicAttr));
+ }
+
+ if(getDiscreteBorder())
+ {
+ const basegfx::B2DVector aDiscreteInLogic(rViewInformation.getInverseObjectToViewTransformation() *
+ basegfx::B2DVector((double)getDiscreteBorder(), (double)getDiscreteBorder()));
+ const double fDiscreteSize(aDiscreteInLogic.getX() + aDiscreteInLogic.getY());
+
+ basegfx::B2DRange aSourceRange(0.0, 0.0, 1.0, 1.0);
+ aSourceRange.transform(getTransform());
+
+ basegfx::B2DRange aDestRange(aSourceRange);
+ aDestRange.grow(-0.5 * fDiscreteSize);
+
+ if(basegfx::fTools::equalZero(aDestRange.getWidth()) || basegfx::fTools::equalZero(aDestRange.getHeight()))
+ {
+ // shrunk primitive has no content (zero size in X or Y), nothing to display. Still create
+ // invisible content for HitTest and BoundRect
+ const Primitive2DReference xHiddenLines(new HiddenGeometryPrimitive2D(xRetval));
+
+ xRetval = Primitive2DSequence(&xHiddenLines, 1);
+ }
+ else
+ {
+ // create transformation matrix from original range to shrunk range
+ basegfx::B2DHomMatrix aTransform;
+ aTransform.translate(-aSourceRange.getMinX(), -aSourceRange.getMinY());
+ aTransform.scale(aDestRange.getWidth() / aSourceRange.getWidth(), aDestRange.getHeight() / aSourceRange.getHeight());
+ aTransform.translate(aDestRange.getMinX(), aDestRange.getMinY());
+
+ // add transform primitive
+ const Primitive2DReference aScaled(new TransformPrimitive2D(aTransform, xRetval));
+ xRetval = Primitive2DSequence(&aScaled, 1L);
+ }
+ }
+
+ return xRetval;
+ }
+
+ MediaPrimitive2D::MediaPrimitive2D(
+ const basegfx::B2DHomMatrix& rTransform,
+ const rtl::OUString& rURL,
+ const basegfx::BColor& rBackgroundColor,
+ sal_uInt32 nDiscreteBorder)
+ : BufferedDecompositionPrimitive2D(),
+ maTransform(rTransform),
+ maURL(rURL),
+ maBackgroundColor(rBackgroundColor),
+ mnDiscreteBorder(nDiscreteBorder)
+ {
+ }
+
+ bool MediaPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const MediaPrimitive2D& rCompare = (MediaPrimitive2D&)rPrimitive;
+
+ return (getTransform() == rCompare.getTransform()
+ && getURL() == rCompare.getURL()
+ && getBackgroundColor() == rCompare.getBackgroundColor()
+ && getDiscreteBorder() == rCompare.getDiscreteBorder());
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange MediaPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ basegfx::B2DRange aRetval(0.0, 0.0, 1.0, 1.0);
+ aRetval.transform(getTransform());
+
+ if(getDiscreteBorder())
+ {
+ const basegfx::B2DVector aDiscreteInLogic(rViewInformation.getInverseObjectToViewTransformation() *
+ basegfx::B2DVector((double)getDiscreteBorder(), (double)getDiscreteBorder()));
+ const double fDiscreteSize(aDiscreteInLogic.getX() + aDiscreteInLogic.getY());
+
+ aRetval.grow(-0.5 * fDiscreteSize);
+ }
+
+ return aRetval;
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(MediaPrimitive2D, PRIMITIVE2D_ID_MEDIAPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/metafileprimitive2d.cxx b/drawinglayer/source/primitive2d/metafileprimitive2d.cxx
new file mode 100644
index 000000000000..ffb90a570080
--- /dev/null
+++ b/drawinglayer/source/primitive2d/metafileprimitive2d.cxx
@@ -0,0 +1,3259 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
+#include <basegfx/tools/canvastools.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+#include <basegfx/color/bcolor.hxx>
+#include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx>
+#include <vcl/lineinfo.hxx>
+#include <drawinglayer/attribute/lineattribute.hxx>
+#include <drawinglayer/attribute/strokeattribute.hxx>
+#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
+#include <vcl/metaact.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <drawinglayer/primitive2d/discretebitmapprimitive2d.hxx>
+#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
+#include <vcl/salbtype.hxx>
+#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
+#include <drawinglayer/primitive2d/fillgradientprimitive2d.hxx>
+#include <vcl/svapp.hxx>
+#include <drawinglayer/primitive2d/transparenceprimitive2d.hxx>
+#include <drawinglayer/primitive2d/fillhatchprimitive2d.hxx>
+#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygonclipper.hxx>
+#include <drawinglayer/primitive2d/invertprimitive2d.hxx>
+#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
+#include <drawinglayer/primitive2d/fillbitmapprimitive2d.hxx>
+#include <drawinglayer/primitive2d/wallpaperprimitive2d.hxx>
+#include <drawinglayer/primitive2d/textprimitive2d.hxx>
+#include <drawinglayer/primitive2d/textlayoutdevice.hxx>
+#include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
+#include <i18npool/mslangid.hxx>
+#include <drawinglayer/primitive2d/textlineprimitive2d.hxx>
+#include <drawinglayer/primitive2d/textstrikeoutprimitive2d.hxx>
+#include <drawinglayer/primitive2d/epsprimitive2d.hxx>
+#include <numeric>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace
+{
+ /** helper class for graphic context
+
+ This class allows to hold a complete status of classic
+ VCL OutputDevice stati. This data is needed for correct
+ interpretation of the MetaFile action flow.
+ */
+ class PropertyHolder
+ {
+ private:
+ /// current transformation (aka MapMode)
+ basegfx::B2DHomMatrix maTransformation;
+ MapUnit maMapUnit;
+
+ /// current colors
+ basegfx::BColor maLineColor;
+ basegfx::BColor maFillColor;
+ basegfx::BColor maTextColor;
+ basegfx::BColor maTextFillColor;
+ basegfx::BColor maTextLineColor;
+ basegfx::BColor maOverlineColor;
+
+ /// clipping
+ basegfx::B2DPolyPolygon maClipPolyPoygon;
+
+ /// font, etc.
+ Font maFont;
+ RasterOp maRasterOp;
+ sal_uInt32 mnLayoutMode;
+ LanguageType maLanguageType;
+ sal_uInt16 mnPushFlags;
+
+ /// bitfield
+ /// contains all active markers
+ bool mbLineColor : 1;
+ bool mbFillColor : 1;
+ bool mbTextColor : 1;
+ bool mbTextFillColor : 1;
+ bool mbTextLineColor : 1;
+ bool mbOverlineColor : 1;
+ bool mbClipPolyPolygonActive : 1;
+
+ public:
+ PropertyHolder()
+ : maTransformation(),
+ maMapUnit(MAP_100TH_MM),
+ maLineColor(),
+ maFillColor(),
+ maTextColor(COL_BLACK),
+ maTextFillColor(),
+ maTextLineColor(),
+ maOverlineColor(),
+ maClipPolyPoygon(),
+ maFont(),
+ maRasterOp(ROP_OVERPAINT),
+ mnLayoutMode(0),
+ maLanguageType(0),
+ mnPushFlags(0),
+ mbLineColor(false),
+ mbFillColor(false),
+ mbTextColor(true),
+ mbTextFillColor(false),
+ mbTextLineColor(false),
+ mbOverlineColor(false),
+ mbClipPolyPolygonActive(false)
+ {
+ }
+
+ ~PropertyHolder()
+ {
+ }
+
+ /// read/write accesses
+ const basegfx::B2DHomMatrix& getTransformation() const { return maTransformation; }
+ void setTransformation(const basegfx::B2DHomMatrix& rNew) { if(rNew != maTransformation) maTransformation = rNew; }
+
+ MapUnit getMapUnit() const { return maMapUnit; }
+ void setMapUnit(MapUnit eNew) { if(eNew != maMapUnit) maMapUnit = eNew; }
+
+ const basegfx::BColor& getLineColor() const { return maLineColor; }
+ void setLineColor(const basegfx::BColor& rNew) { if(rNew != maLineColor) maLineColor = rNew; }
+ bool getLineColorActive() const { return mbLineColor; }
+ void setLineColorActive(bool bNew) { if(bNew != mbLineColor) mbLineColor = bNew; }
+
+ const basegfx::BColor& getFillColor() const { return maFillColor; }
+ void setFillColor(const basegfx::BColor& rNew) { if(rNew != maFillColor) maFillColor = rNew; }
+ bool getFillColorActive() const { return mbFillColor; }
+ void setFillColorActive(bool bNew) { if(bNew != mbFillColor) mbFillColor = bNew; }
+
+ const basegfx::BColor& getTextColor() const { return maTextColor; }
+ void setTextColor(const basegfx::BColor& rNew) { if(rNew != maTextColor) maTextColor = rNew; }
+ bool getTextColorActive() const { return mbTextColor; }
+ void setTextColorActive(bool bNew) { if(bNew != mbTextColor) mbTextColor = bNew; }
+
+ const basegfx::BColor& getTextFillColor() const { return maTextFillColor; }
+ void setTextFillColor(const basegfx::BColor& rNew) { if(rNew != maTextFillColor) maTextFillColor = rNew; }
+ bool getTextFillColorActive() const { return mbTextFillColor; }
+ void setTextFillColorActive(bool bNew) { if(bNew != mbTextFillColor) mbTextFillColor = bNew; }
+
+ const basegfx::BColor& getTextLineColor() const { return maTextLineColor; }
+ void setTextLineColor(const basegfx::BColor& rNew) { if(rNew != maTextLineColor) maTextLineColor = rNew; }
+ bool getTextLineColorActive() const { return mbTextLineColor; }
+ void setTextLineColorActive(bool bNew) { if(bNew != mbTextLineColor) mbTextLineColor = bNew; }
+
+ const basegfx::BColor& getOverlineColor() const { return maOverlineColor; }
+ void setOverlineColor(const basegfx::BColor& rNew) { if(rNew != maOverlineColor) maOverlineColor = rNew; }
+ bool getOverlineColorActive() const { return mbOverlineColor; }
+ void setOverlineColorActive(bool bNew) { if(bNew != mbOverlineColor) mbOverlineColor = bNew; }
+
+ const basegfx::B2DPolyPolygon& getClipPolyPolygon() const { return maClipPolyPoygon; }
+ void setClipPolyPolygon(const basegfx::B2DPolyPolygon& rNew) { if(rNew != maClipPolyPoygon) maClipPolyPoygon = rNew; }
+ bool getClipPolyPolygonActive() const { return mbClipPolyPolygonActive; }
+ void setClipPolyPolygonActive(bool bNew) { if(bNew != mbClipPolyPolygonActive) mbClipPolyPolygonActive = bNew; }
+
+ const Font& getFont() const { return maFont; }
+ void setFont(const Font& rFont) { if(rFont != maFont) maFont = rFont; }
+
+ const RasterOp& getRasterOp() const { return maRasterOp; }
+ void setRasterOp(const RasterOp& rRasterOp) { if(rRasterOp != maRasterOp) maRasterOp = rRasterOp; }
+ bool isRasterOpInvert() const { return (ROP_XOR == maRasterOp || ROP_INVERT == maRasterOp); }
+ bool isRasterOpForceBlack() const { return ROP_0 == maRasterOp; }
+ bool isRasterOpActive() const { return isRasterOpInvert() || isRasterOpForceBlack(); }
+
+ sal_uInt32 getLayoutMode() const { return mnLayoutMode; }
+ void setLayoutMode(sal_uInt32 nNew) { if(nNew != mnLayoutMode) mnLayoutMode = nNew; }
+
+ LanguageType getLanguageType() const { return maLanguageType; }
+ void setLanguageType(LanguageType aNew) { if(aNew != maLanguageType) maLanguageType = aNew; }
+
+ sal_uInt16 getPushFlags() const { return mnPushFlags; }
+ void setPushFlags(sal_uInt16 nNew) { if(nNew != mnPushFlags) mnPushFlags = nNew; }
+
+ bool getLineOrFillActive() const { return (mbLineColor || mbFillColor); }
+ };
+} // end of anonymous namespace
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace
+{
+ /** stack for properites
+
+ This class builds a stack based on the PropertyHolder
+ class. It encapsulates the pointer/new/delete usage to
+ make it safe and implements the push/pop as needed by a
+ VCL Metafile interpreter. The critical part here are the
+ flag values VCL OutputDevice uses here; not all stuff is
+ pushed and thus needs to be copied at pop.
+ */
+ class PropertyHolders
+ {
+ private:
+ std::vector< PropertyHolder* > maPropertyHolders;
+
+ public:
+ PropertyHolders()
+ {
+ maPropertyHolders.push_back(new PropertyHolder());
+ }
+
+ sal_uInt32 size()
+ {
+ return maPropertyHolders.size();
+ }
+
+ void PushDefault()
+ {
+ PropertyHolder* pNew = new PropertyHolder();
+ maPropertyHolders.push_back(pNew);
+ }
+
+ void Push(sal_uInt16 nPushFlags)
+ {
+ if(nPushFlags)
+ {
+ OSL_ENSURE(maPropertyHolders.size(), "PropertyHolders: PUSH with no property holders (!)");
+ if ( !maPropertyHolders.empty() )
+ {
+ PropertyHolder* pNew = new PropertyHolder(*maPropertyHolders.back());
+ pNew->setPushFlags(nPushFlags);
+ maPropertyHolders.push_back(pNew);
+ }
+ }
+ }
+
+ void Pop()
+ {
+ OSL_ENSURE(maPropertyHolders.size(), "PropertyHolders: POP with no property holders (!)");
+ const sal_uInt32 nSize(maPropertyHolders.size());
+
+ if(nSize)
+ {
+ const PropertyHolder* pTip = maPropertyHolders.back();
+ const sal_uInt16 nPushFlags(pTip->getPushFlags());
+
+ if(nPushFlags)
+ {
+ if(nSize > 1)
+ {
+ // copy back content for all non-set flags
+ PropertyHolder* pLast = maPropertyHolders[nSize - 2];
+
+ if(PUSH_ALL != nPushFlags)
+ {
+ if(!(nPushFlags & PUSH_LINECOLOR ))
+ {
+ pLast->setLineColor(pTip->getLineColor());
+ pLast->setLineColorActive(pTip->getLineColorActive());
+ }
+ if(!(nPushFlags & PUSH_FILLCOLOR ))
+ {
+ pLast->setFillColor(pTip->getFillColor());
+ pLast->setFillColorActive(pTip->getFillColorActive());
+ }
+ if(!(nPushFlags & PUSH_FONT ))
+ {
+ pLast->setFont(pTip->getFont());
+ }
+ if(!(nPushFlags & PUSH_TEXTCOLOR ))
+ {
+ pLast->setTextColor(pTip->getTextColor());
+ pLast->setTextColorActive(pTip->getTextColorActive());
+ }
+ if(!(nPushFlags & PUSH_MAPMODE ))
+ {
+ pLast->setTransformation(pTip->getTransformation());
+ pLast->setMapUnit(pTip->getMapUnit());
+ }
+ if(!(nPushFlags & PUSH_CLIPREGION ))
+ {
+ pLast->setClipPolyPolygon(pTip->getClipPolyPolygon());
+ pLast->setClipPolyPolygonActive(pTip->getClipPolyPolygonActive());
+ }
+ if(!(nPushFlags & PUSH_RASTEROP ))
+ {
+ pLast->setRasterOp(pTip->getRasterOp());
+ }
+ if(!(nPushFlags & PUSH_TEXTFILLCOLOR ))
+ {
+ pLast->setTextFillColor(pTip->getTextFillColor());
+ pLast->setTextFillColorActive(pTip->getTextFillColorActive());
+ }
+ if(!(nPushFlags & PUSH_TEXTALIGN ))
+ {
+ if(pLast->getFont().GetAlign() != pTip->getFont().GetAlign())
+ {
+ Font aFont(pLast->getFont());
+ aFont.SetAlign(pTip->getFont().GetAlign());
+ pLast->setFont(aFont);
+ }
+ }
+ if(!(nPushFlags & PUSH_REFPOINT ))
+ {
+ // not supported
+ }
+ if(!(nPushFlags & PUSH_TEXTLINECOLOR ))
+ {
+ pLast->setTextLineColor(pTip->getTextLineColor());
+ pLast->setTextLineColorActive(pTip->getTextLineColorActive());
+ }
+ if(!(nPushFlags & PUSH_TEXTLAYOUTMODE ))
+ {
+ pLast->setLayoutMode(pTip->getLayoutMode());
+ }
+ if(!(nPushFlags & PUSH_TEXTLANGUAGE ))
+ {
+ pLast->setLanguageType(pTip->getLanguageType());
+ }
+ if(!(nPushFlags & PUSH_OVERLINECOLOR ))
+ {
+ pLast->setOverlineColor(pTip->getOverlineColor());
+ pLast->setOverlineColorActive(pTip->getOverlineColorActive());
+ }
+ }
+ }
+ }
+
+ // execute the pop
+ delete maPropertyHolders.back();
+ maPropertyHolders.pop_back();
+ }
+ }
+
+ PropertyHolder& Current()
+ {
+ static PropertyHolder aDummy;
+ OSL_ENSURE(maPropertyHolders.size(), "PropertyHolders: CURRENT with no property holders (!)");
+ return maPropertyHolders.empty() ? aDummy : *maPropertyHolders.back();
+ }
+
+ ~PropertyHolders()
+ {
+ while(maPropertyHolders.size())
+ {
+ delete maPropertyHolders.back();
+ maPropertyHolders.pop_back();
+ }
+ }
+ };
+} // end of anonymous namespace
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace
+{
+ /** helper to convert a Region to a B2DPolyPolygon
+ when it does not yet contain one. In the future
+ this may be expanded to merge the polygons created
+ from rectangles or use a special algo to directly turn
+ the spans of regions to a single, already merged
+ PolyPolygon.
+ */
+ basegfx::B2DPolyPolygon getB2DPolyPolygonFromRegion(const Region& rRegion)
+ {
+ basegfx::B2DPolyPolygon aRetval;
+
+ if(!rRegion.IsEmpty())
+ {
+ Region aRegion(rRegion);
+ aRetval = aRegion.GetB2DPolyPolygon();
+
+ if(!aRetval.count())
+ {
+ RegionHandle aRegionHandle(aRegion.BeginEnumRects());
+ Rectangle aRegionRectangle;
+
+ while(aRegion.GetEnumRects(aRegionHandle, aRegionRectangle))
+ {
+ if(!aRegionRectangle.IsEmpty())
+ {
+ const basegfx::B2DRange aRegionRange(
+ aRegionRectangle.Left(), aRegionRectangle.Top(),
+ aRegionRectangle.Right(), aRegionRectangle.Bottom());
+ aRetval.append(basegfx::tools::createPolygonFromRect(aRegionRange));
+ }
+ }
+
+ aRegion.EndEnumRects(aRegionHandle);
+ }
+ }
+
+ return aRetval;
+ }
+} // end of anonymous namespace
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace
+{
+ /** Helper class to buffer and hold a Primive target vector. It
+ encapsulates the new/delete functionality and aloows to work
+ on pointers of the implementation classes. All data will
+ be converted to uno sequences of uno references when accessing the
+ data.
+ */
+ class TargetHolder
+ {
+ private:
+ std::vector< drawinglayer::primitive2d::BasePrimitive2D* > aTargets;
+
+ public:
+ TargetHolder()
+ : aTargets()
+ {
+ }
+
+ ~TargetHolder()
+ {
+ const sal_uInt32 nCount(aTargets.size());
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ delete aTargets[a];
+ }
+ }
+
+ sal_uInt32 size()
+ {
+ return aTargets.size();
+ }
+
+ void append(drawinglayer::primitive2d::BasePrimitive2D* pCandidate)
+ {
+ if(pCandidate)
+ {
+ aTargets.push_back(pCandidate);
+ }
+ }
+
+ drawinglayer::primitive2d::Primitive2DSequence getPrimitive2DSequence(const PropertyHolder& rPropertyHolder)
+ {
+ const sal_uInt32 nCount(aTargets.size());
+ drawinglayer::primitive2d::Primitive2DSequence xRetval(nCount);
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ xRetval[a] = aTargets[a];
+ }
+
+ // All Targets were pointers, but do not need to be deleted since they
+ // were converted to UNO API references now, so they stay as long as
+ // referenced. Do NOT delete the C++ implementation classes here, but clear
+ // the buffer to not delete them in the destructor.
+ aTargets.clear();
+
+ if(xRetval.hasElements() && rPropertyHolder.getClipPolyPolygonActive())
+ {
+ const basegfx::B2DPolyPolygon& rClipPolyPolygon = rPropertyHolder.getClipPolyPolygon();
+
+ if(rClipPolyPolygon.count())
+ {
+ const drawinglayer::primitive2d::Primitive2DReference xMask(
+ new drawinglayer::primitive2d::MaskPrimitive2D(
+ rClipPolyPolygon,
+ xRetval));
+
+ xRetval = drawinglayer::primitive2d::Primitive2DSequence(&xMask, 1);
+ }
+ }
+
+ return xRetval;
+ }
+ };
+} // end of anonymous namespace
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace
+{
+ /** Helper class which builds a stack on the TargetHolder class */
+ class TargetHolders
+ {
+ private:
+ std::vector< TargetHolder* > maTargetHolders;
+
+ public:
+ TargetHolders()
+ {
+ maTargetHolders.push_back(new TargetHolder());
+ }
+
+ sal_uInt32 size()
+ {
+ return maTargetHolders.size();
+ }
+
+ void Push()
+ {
+ maTargetHolders.push_back(new TargetHolder());
+ }
+
+ void Pop()
+ {
+ OSL_ENSURE(maTargetHolders.size(), "TargetHolders: POP with no property holders (!)");
+ if(maTargetHolders.size())
+ {
+ delete maTargetHolders.back();
+ maTargetHolders.pop_back();
+ }
+ }
+
+ TargetHolder& Current()
+ {
+ OSL_ENSURE(maTargetHolders.size(), "TargetHolders: CURRENT with no property holders (!)");
+ return *maTargetHolders.back();
+ }
+
+ ~TargetHolders()
+ {
+ while(maTargetHolders.size())
+ {
+ delete maTargetHolders.back();
+ maTargetHolders.pop_back();
+ }
+ }
+ };
+} // end of anonymous namespace
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ /** NonOverlappingFillGradientPrimitive2D class
+
+ This is a special version of the FillGradientPrimitive2D which decomposes
+ to a non-overlapping geometry version of the gradient. This needs to be
+ used to support the old XOR paint-'trick'.
+
+ It does not need an own identifier since a renderer who wants to interpret
+ it itself may do so. It just overloads the decomposition of the C++
+ implementation class to do an alternative decomposition.
+ */
+ class NonOverlappingFillGradientPrimitive2D : public FillGradientPrimitive2D
+ {
+ protected:
+ /// local decomposition.
+ virtual Primitive2DSequence create2DDecomposition(
+ const geometry::ViewInformation2D& rViewInformation) const;
+
+ public:
+ /// constructor
+ NonOverlappingFillGradientPrimitive2D(
+ const basegfx::B2DRange& rObjectRange,
+ const attribute::FillGradientAttribute& rFillGradient)
+ : FillGradientPrimitive2D(rObjectRange, rFillGradient)
+ {
+ }
+ };
+
+ Primitive2DSequence NonOverlappingFillGradientPrimitive2D::create2DDecomposition(
+ const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ if(!getFillGradient().isDefault())
+ {
+ return createFill(false);
+ }
+ else
+ {
+ return Primitive2DSequence();
+ }
+ }
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace
+{
+ /** helper to convert a MapMode to a transformation */
+ basegfx::B2DHomMatrix getTransformFromMapMode(const MapMode& rMapMode)
+ {
+ basegfx::B2DHomMatrix aMapping;
+ const Fraction aNoScale(1, 1);
+ const Point& rOrigin(rMapMode.GetOrigin());
+
+ if(0 != rOrigin.X() || 0 != rOrigin.Y())
+ {
+ aMapping.translate(rOrigin.X(), rOrigin.Y());
+ }
+
+ if(rMapMode.GetScaleX() != aNoScale || rMapMode.GetScaleY() != aNoScale)
+ {
+ aMapping.scale(
+ double(rMapMode.GetScaleX()),
+ double(rMapMode.GetScaleY()));
+ }
+
+ return aMapping;
+ }
+
+ /** helper to create a PointArrayPrimitive2D based on current context */
+ void createPointArrayPrimitive(
+ const std::vector< basegfx::B2DPoint >& rPositions,
+ TargetHolder& rTarget,
+ PropertyHolder& rProperties,
+ basegfx::BColor aBColor)
+ {
+ if(rPositions.size())
+ {
+ if(rProperties.getTransformation().isIdentity())
+ {
+ rTarget.append(
+ new drawinglayer::primitive2d::PointArrayPrimitive2D(
+ rPositions,
+ aBColor));
+ }
+ else
+ {
+ std::vector< basegfx::B2DPoint > aPositions(rPositions);
+
+ for(sal_uInt32 a(0); a < aPositions.size(); a++)
+ {
+ aPositions[a] = rProperties.getTransformation() * aPositions[a];
+ }
+
+ rTarget.append(
+ new drawinglayer::primitive2d::PointArrayPrimitive2D(
+ aPositions,
+ aBColor));
+ }
+ }
+ }
+
+ /** helper to create a PolygonHairlinePrimitive2D based on current context */
+ void createHairlinePrimitive(
+ const basegfx::B2DPolygon& rLinePolygon,
+ TargetHolder& rTarget,
+ PropertyHolder& rProperties)
+ {
+ if(rLinePolygon.count())
+ {
+ basegfx::B2DPolygon aLinePolygon(rLinePolygon);
+ aLinePolygon.transform(rProperties.getTransformation());
+ rTarget.append(
+ new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
+ aLinePolygon,
+ rProperties.getLineColor()));
+ }
+ }
+
+ /** helper to create a PolyPolygonColorPrimitive2D based on current context */
+ void createFillPrimitive(
+ const basegfx::B2DPolyPolygon& rFillPolyPolygon,
+ TargetHolder& rTarget,
+ PropertyHolder& rProperties)
+ {
+ if(rFillPolyPolygon.count())
+ {
+ basegfx::B2DPolyPolygon aFillPolyPolygon(rFillPolyPolygon);
+ aFillPolyPolygon.transform(rProperties.getTransformation());
+ rTarget.append(
+ new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
+ aFillPolyPolygon,
+ rProperties.getFillColor()));
+ }
+ }
+
+ /** helper to create a PolygonStrokePrimitive2D based on current context */
+ void createLinePrimitive(
+ const basegfx::B2DPolygon& rLinePolygon,
+ const LineInfo& rLineInfo,
+ TargetHolder& rTarget,
+ PropertyHolder& rProperties)
+ {
+ if(rLinePolygon.count())
+ {
+ const bool bDashDotUsed(LINE_DASH == rLineInfo.GetStyle());
+ const bool bWidthUsed(rLineInfo.GetWidth() > 1);
+
+ if(bDashDotUsed || bWidthUsed)
+ {
+ basegfx::B2DPolygon aLinePolygon(rLinePolygon);
+ aLinePolygon.transform(rProperties.getTransformation());
+ const drawinglayer::attribute::LineAttribute aLineAttribute(
+ rProperties.getLineColor(),
+ bWidthUsed ? rLineInfo.GetWidth() : 0.0,
+ rLineInfo.GetLineJoin());
+
+ if(bDashDotUsed)
+ {
+ ::std::vector< double > fDotDashArray;
+ const double fDashLen(rLineInfo.GetDashLen());
+ const double fDotLen(rLineInfo.GetDotLen());
+ const double fDistance(rLineInfo.GetDistance());
+
+ for(sal_uInt16 a(0); a < rLineInfo.GetDashCount(); a++)
+ {
+ fDotDashArray.push_back(fDashLen);
+ fDotDashArray.push_back(fDistance);
+ }
+
+ for(sal_uInt16 b(0); b < rLineInfo.GetDotCount(); b++)
+ {
+ fDotDashArray.push_back(fDotLen);
+ fDotDashArray.push_back(fDistance);
+ }
+
+ const double fAccumulated(::std::accumulate(fDotDashArray.begin(), fDotDashArray.end(), 0.0));
+ const drawinglayer::attribute::StrokeAttribute aStrokeAttribute(
+ fDotDashArray,
+ fAccumulated);
+
+ rTarget.append(
+ new drawinglayer::primitive2d::PolygonStrokePrimitive2D(
+ aLinePolygon,
+ aLineAttribute,
+ aStrokeAttribute));
+ }
+ else
+ {
+ rTarget.append(
+ new drawinglayer::primitive2d::PolygonStrokePrimitive2D(
+ aLinePolygon,
+ aLineAttribute));
+ }
+ }
+ else
+ {
+ createHairlinePrimitive(rLinePolygon, rTarget, rProperties);
+ }
+ }
+ }
+
+ /** helper to create needed line and fill primitives based on current context */
+ void createHairlineAndFillPrimitive(
+ const basegfx::B2DPolygon& rPolygon,
+ TargetHolder& rTarget,
+ PropertyHolder& rProperties)
+ {
+ if(rProperties.getFillColorActive())
+ {
+ createFillPrimitive(basegfx::B2DPolyPolygon(rPolygon), rTarget, rProperties);
+ }
+
+ if(rProperties.getLineColorActive())
+ {
+ createHairlinePrimitive(rPolygon, rTarget, rProperties);
+ }
+ }
+
+ /** helper to create needed line and fill primitives based on current context */
+ void createHairlineAndFillPrimitive(
+ const basegfx::B2DPolyPolygon& rPolyPolygon,
+ TargetHolder& rTarget,
+ PropertyHolder& rProperties)
+ {
+ if(rProperties.getFillColorActive())
+ {
+ createFillPrimitive(rPolyPolygon, rTarget, rProperties);
+ }
+
+ if(rProperties.getLineColorActive())
+ {
+ for(sal_uInt32 a(0); a < rPolyPolygon.count(); a++)
+ {
+ createHairlinePrimitive(rPolyPolygon.getB2DPolygon(a), rTarget, rProperties);
+ }
+ }
+ }
+
+ /** helper to create DiscreteBitmapPrimitive2D based on current context.
+ The DiscreteBitmapPrimitive2D is especially created for this usage
+ since no other usage defines a bitmap visualisation based on top-left
+ position and size in pixels. At the end it will create a view-dependent
+ transformed embedding of a BitmapPrimitive2D.
+ */
+ void createBitmapExPrimitive(
+ const BitmapEx& rBitmapEx,
+ const Point& rPoint,
+ TargetHolder& rTarget,
+ PropertyHolder& rProperties)
+ {
+ if(!rBitmapEx.IsEmpty())
+ {
+ basegfx::B2DPoint aPoint(rPoint.X(), rPoint.Y());
+ aPoint = rProperties.getTransformation() * aPoint;
+
+ rTarget.append(
+ new drawinglayer::primitive2d::DiscreteBitmapPrimitive2D(
+ rBitmapEx,
+ aPoint));
+ }
+ }
+
+ /** helper to create BitmapPrimitive2D based on current context */
+ void createBitmapExPrimitive(
+ const BitmapEx& rBitmapEx,
+ const Point& rPoint,
+ const Size& rSize,
+ TargetHolder& rTarget,
+ PropertyHolder& rProperties)
+ {
+ if(!rBitmapEx.IsEmpty())
+ {
+ basegfx::B2DHomMatrix aObjectTransform;
+
+ aObjectTransform.set(0, 0, rSize.Width());
+ aObjectTransform.set(1, 1, rSize.Height());
+ aObjectTransform.set(0, 2, rPoint.X());
+ aObjectTransform.set(1, 2, rPoint.Y());
+
+ aObjectTransform = rProperties.getTransformation() * aObjectTransform;
+
+ rTarget.append(
+ new drawinglayer::primitive2d::BitmapPrimitive2D(
+ rBitmapEx,
+ aObjectTransform));
+ }
+ }
+
+ /** helper to create a regular BotmapEx from a MaskAction (definitions
+ which use a bitmap without transparence but define one of the colors as
+ transparent)
+ */
+ BitmapEx createMaskBmpEx(const Bitmap& rBitmap, const Color& rMaskColor)
+ {
+ const Color aWhite(COL_WHITE);
+ BitmapPalette aBiLevelPalette(2);
+
+ aBiLevelPalette[0] = aWhite;
+ aBiLevelPalette[1] = rMaskColor;
+
+ Bitmap aMask(rBitmap.CreateMask(aWhite));
+ Bitmap aSolid(rBitmap.GetSizePixel(), 1, &aBiLevelPalette);
+
+ aSolid.Erase(rMaskColor);
+
+ return BitmapEx(aSolid, aMask);
+ }
+
+ /** helper to convert from a VCL Gradient definition to the corresponding
+ data for primitive representation
+ */
+ drawinglayer::attribute::FillGradientAttribute createFillGradientAttribute(const Gradient& rGradient)
+ {
+ const Color aStartColor(rGradient.GetStartColor());
+ const sal_uInt16 nStartIntens(rGradient.GetStartIntensity());
+ basegfx::BColor aStart(aStartColor.getBColor());
+
+ if(nStartIntens != 100)
+ {
+ const basegfx::BColor aBlack;
+ aStart = interpolate(aBlack, aStart, (double)nStartIntens * 0.01);
+ }
+
+ const Color aEndColor(rGradient.GetEndColor());
+ const sal_uInt16 nEndIntens(rGradient.GetEndIntensity());
+ basegfx::BColor aEnd(aEndColor.getBColor());
+
+ if(nEndIntens != 100)
+ {
+ const basegfx::BColor aBlack;
+ aEnd = interpolate(aBlack, aEnd, (double)nEndIntens * 0.01);
+ }
+
+ drawinglayer::attribute::GradientStyle aGradientStyle(drawinglayer::attribute::GRADIENTSTYLE_RECT);
+
+ switch(rGradient.GetStyle())
+ {
+ case GRADIENT_LINEAR :
+ {
+ aGradientStyle = drawinglayer::attribute::GRADIENTSTYLE_LINEAR;
+ break;
+ }
+ case GRADIENT_AXIAL :
+ {
+ aGradientStyle = drawinglayer::attribute::GRADIENTSTYLE_AXIAL;
+ break;
+ }
+ case GRADIENT_RADIAL :
+ {
+ aGradientStyle = drawinglayer::attribute::GRADIENTSTYLE_RADIAL;
+ break;
+ }
+ case GRADIENT_ELLIPTICAL :
+ {
+ aGradientStyle = drawinglayer::attribute::GRADIENTSTYLE_ELLIPTICAL;
+ break;
+ }
+ case GRADIENT_SQUARE :
+ {
+ aGradientStyle = drawinglayer::attribute::GRADIENTSTYLE_SQUARE;
+ break;
+ }
+ default : // GRADIENT_RECT
+ {
+ aGradientStyle = drawinglayer::attribute::GRADIENTSTYLE_RECT;
+ break;
+ }
+ }
+
+ return drawinglayer::attribute::FillGradientAttribute(
+ aGradientStyle,
+ (double)rGradient.GetBorder() * 0.01,
+ (double)rGradient.GetOfsX() * 0.01,
+ (double)rGradient.GetOfsY() * 0.01,
+ (double)rGradient.GetAngle() * F_PI1800,
+ aStart,
+ aEnd,
+ rGradient.GetSteps());
+ }
+
+ /** helper to convert from a VCL Hatch definition to the corresponding
+ data for primitive representation
+ */
+ drawinglayer::attribute::FillHatchAttribute createFillHatchAttribute(const Hatch& rHatch)
+ {
+ drawinglayer::attribute::HatchStyle aHatchStyle(drawinglayer::attribute::HATCHSTYLE_SINGLE);
+
+ switch(rHatch.GetStyle())
+ {
+ default : // case HATCH_SINGLE :
+ {
+ aHatchStyle = drawinglayer::attribute::HATCHSTYLE_SINGLE;
+ break;
+ }
+ case HATCH_DOUBLE :
+ {
+ aHatchStyle = drawinglayer::attribute::HATCHSTYLE_DOUBLE;
+ break;
+ }
+ case HATCH_TRIPLE :
+ {
+ aHatchStyle = drawinglayer::attribute::HATCHSTYLE_TRIPLE;
+ break;
+ }
+ }
+
+ return drawinglayer::attribute::FillHatchAttribute(
+ aHatchStyle,
+ (double)rHatch.GetDistance(),
+ (double)rHatch.GetAngle() * F_PI1800,
+ rHatch.GetColor().getBColor(),
+ false);
+ }
+
+ /** helper to take needed action on ClipRegion change. This method needs to be called
+ on any Region change, e.g. at the obvious actions doing this, but also at pop-calls
+ whcih change the Region of the current context. It takes care of creating the
+ current embeddec context, set the new Region at the context and eventually prepare
+ a new target for embracing new geometry to the current region
+ */
+ void HandleNewClipRegion(
+ const basegfx::B2DPolyPolygon& rClipPolyPolygon,
+ TargetHolders& rTargetHolders,
+ PropertyHolders& rPropertyHolders)
+ {
+ const bool bNewActive(rClipPolyPolygon.count());
+
+ // #i108636# The handlig of new ClipPolyPolygons was not done as good as possible
+ // in the first version of this interpreter; e.g. when a ClipPolyPolygon was set
+ // initially and then using a lot of push/pop actions, the pop always leads
+ // to setting a 'new' ClipPolyPolygon which indeed is the return to the ClipPolyPolygon
+ // of the properties next on the stack.
+ //
+ // This ClipPolyPolygon is identical to the current one, so there is no need to
+ // create a MaskPrimitive2D containing the up-to-now created primitives, but
+ // this was done before. While this does not lead to wrong primitive
+ // representations of the metafile data, it creates unneccesarily expensive
+ // representations. Just detecting when no really 'new' ClipPolyPolygon gets set
+ // solves the problem.
+
+ if(!rPropertyHolders.Current().getClipPolyPolygonActive() && !bNewActive)
+ {
+ // no active ClipPolyPolygon exchanged by no new one, done
+ return;
+ }
+
+ if(rPropertyHolders.Current().getClipPolyPolygonActive() && bNewActive)
+ {
+ // active ClipPolyPolygon and new active ClipPolyPolygon
+ if(rPropertyHolders.Current().getClipPolyPolygon() == rClipPolyPolygon)
+ {
+ // new is the same as old, done
+ return;
+ }
+ }
+
+ // Here the old and the new are definitively different, maybe
+ // old one and/or new one is not active.
+
+ // Handle deletion of old ClipPolyPolygon. The process evtl. created primitives which
+ // belong to this active ClipPolyPolygon. These need to be embedded to a
+ // MaskPrimitive2D accordingly.
+ if(rPropertyHolders.Current().getClipPolyPolygonActive() && rTargetHolders.size() > 1)
+ {
+ drawinglayer::primitive2d::Primitive2DSequence aSubContent;
+
+ if(rPropertyHolders.Current().getClipPolyPolygon().count()
+ && rTargetHolders.Current().size())
+ {
+ aSubContent = rTargetHolders.Current().getPrimitive2DSequence(
+ rPropertyHolders.Current());
+ }
+
+ rTargetHolders.Pop();
+
+ if(aSubContent.hasElements())
+ {
+ rTargetHolders.Current().append(
+ new drawinglayer::primitive2d::GroupPrimitive2D(
+ aSubContent));
+ }
+ }
+
+ // apply new settings to current properties by setting
+ // the new region now
+ rPropertyHolders.Current().setClipPolyPolygonActive(bNewActive);
+
+ if(bNewActive)
+ {
+ rPropertyHolders.Current().setClipPolyPolygon(rClipPolyPolygon);
+
+ // prepare new content holder for new active region
+ rTargetHolders.Push();
+ }
+ }
+
+ /** helper to handle the change of RasterOp. It takes care of encapsulating all current
+ geometry to the current RasterOp (if changed) and needs to be called on any RasterOp
+ change. It will also start a new geometry target to embrace to the new RasterOp if
+ a changuing RasterOp is used. Currently, ROP_XOR and ROP_INVERT are supported using
+ InvertPrimitive2D, and ROP_0 by using a ModifiedColorPrimitive2D to force to black paint
+ */
+ void HandleNewRasterOp(
+ RasterOp aRasterOp,
+ TargetHolders& rTargetHolders,
+ PropertyHolders& rPropertyHolders)
+ {
+ // check if currently active
+ if(rPropertyHolders.Current().isRasterOpActive() && rTargetHolders.size() > 1)
+ {
+ drawinglayer::primitive2d::Primitive2DSequence aSubContent;
+
+ if(rTargetHolders.Current().size())
+ {
+ aSubContent = rTargetHolders.Current().getPrimitive2DSequence(rPropertyHolders.Current());
+ }
+
+ rTargetHolders.Pop();
+
+ if(aSubContent.hasElements())
+ {
+ if(rPropertyHolders.Current().isRasterOpForceBlack())
+ {
+ // force content to black
+ rTargetHolders.Current().append(
+ new drawinglayer::primitive2d::ModifiedColorPrimitive2D(
+ aSubContent,
+ basegfx::BColorModifier(basegfx::BColor(0.0, 0.0, 0.0))));
+ }
+ else // if(rPropertyHolders.Current().isRasterOpInvert())
+ {
+ // invert content
+ rTargetHolders.Current().append(
+ new drawinglayer::primitive2d::InvertPrimitive2D(
+ aSubContent));
+ }
+ }
+ }
+
+ // apply new settings
+ rPropertyHolders.Current().setRasterOp(aRasterOp);
+
+ // check if now active
+ if(rPropertyHolders.Current().isRasterOpActive())
+ {
+ // prepare new content holder for new invert
+ rTargetHolders.Push();
+ }
+ }
+
+ /** helper to create needed data to emulate the VCL Wallpaper Metafile action.
+ It is a quite mighty action. This helper is for simple color filled background.
+ */
+ drawinglayer::primitive2d::BasePrimitive2D* CreateColorWallpaper(
+ const basegfx::B2DRange& rRange,
+ const basegfx::BColor& rColor,
+ PropertyHolder& rPropertyHolder)
+ {
+ basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(rRange));
+ aOutline.transform(rPropertyHolder.getTransformation());
+
+ return new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
+ basegfx::B2DPolyPolygon(aOutline),
+ rColor);
+ }
+
+ /** helper to create needed data to emulate the VCL Wallpaper Metafile action.
+ It is a quite mighty action. This helper is for gradient filled background.
+ */
+ drawinglayer::primitive2d::BasePrimitive2D* CreateGradientWallpaper(
+ const basegfx::B2DRange& rRange,
+ const Gradient& rGradient,
+ PropertyHolder& rPropertyHolder)
+ {
+ const drawinglayer::attribute::FillGradientAttribute aAttribute(createFillGradientAttribute(rGradient));
+
+ if(aAttribute.getStartColor() == aAttribute.getEndColor())
+ {
+ // not really a gradient. Create filled rectangle
+ return CreateColorWallpaper(rRange, aAttribute.getStartColor(), rPropertyHolder);
+ }
+ else
+ {
+ // really a gradient
+ drawinglayer::primitive2d::BasePrimitive2D* pRetval =
+ new drawinglayer::primitive2d::FillGradientPrimitive2D(
+ rRange,
+ aAttribute);
+
+ if(!rPropertyHolder.getTransformation().isIdentity())
+ {
+ const drawinglayer::primitive2d::Primitive2DReference xPrim(pRetval);
+ const drawinglayer::primitive2d::Primitive2DSequence xSeq(&xPrim, 1);
+
+ pRetval = new drawinglayer::primitive2d::TransformPrimitive2D(
+ rPropertyHolder.getTransformation(),
+ xSeq);
+ }
+
+ return pRetval;
+ }
+ }
+
+ /** helper to create needed data to emulate the VCL Wallpaper Metafile action.
+ It is a quite mighty action. This helper decides if color and/or gradient
+ background is needed for the wnated bitmap fill and then creates the needed
+ WallpaperBitmapPrimitive2D. This primitive was created for this purpose and
+ takes over all needed logic of orientations and tiling.
+ */
+ void CreateAndAppendBitmapWallpaper(
+ basegfx::B2DRange aWallpaperRange,
+ const Wallpaper& rWallpaper,
+ TargetHolder& rTarget,
+ PropertyHolder& rProperty)
+ {
+ const BitmapEx aBitmapEx(rWallpaper.GetBitmap());
+ const WallpaperStyle eWallpaperStyle(rWallpaper.GetStyle());
+
+ // if bitmap visualisation is transparent, maybe background
+ // needs to be filled. Create background
+ if(aBitmapEx.IsTransparent()
+ || (WALLPAPER_TILE != eWallpaperStyle && WALLPAPER_SCALE != eWallpaperStyle))
+ {
+ if(rWallpaper.IsGradient())
+ {
+ rTarget.append(
+ CreateGradientWallpaper(
+ aWallpaperRange,
+ rWallpaper.GetGradient(),
+ rProperty));
+ }
+ else if(!rWallpaper.GetColor().GetTransparency())
+ {
+ rTarget.append(
+ CreateColorWallpaper(
+ aWallpaperRange,
+ rWallpaper.GetColor().getBColor(),
+ rProperty));
+ }
+ }
+
+ // use wallpaper rect if set
+ if(rWallpaper.IsRect() && !rWallpaper.GetRect().IsEmpty())
+ {
+ aWallpaperRange = basegfx::B2DRange(
+ rWallpaper.GetRect().Left(), rWallpaper.GetRect().Top(),
+ rWallpaper.GetRect().Right(), rWallpaper.GetRect().Bottom());
+ }
+
+ drawinglayer::primitive2d::BasePrimitive2D* pBitmapWallpaperFill =
+ new drawinglayer::primitive2d::WallpaperBitmapPrimitive2D(
+ aWallpaperRange,
+ aBitmapEx,
+ eWallpaperStyle);
+
+ if(rProperty.getTransformation().isIdentity())
+ {
+ // add directly
+ rTarget.append(pBitmapWallpaperFill);
+ }
+ else
+ {
+ // when a transformation is set, embed to it
+ const drawinglayer::primitive2d::Primitive2DReference xPrim(pBitmapWallpaperFill);
+
+ rTarget.append(
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ rProperty.getTransformation(),
+ drawinglayer::primitive2d::Primitive2DSequence(&xPrim, 1)));
+ }
+ }
+
+ /** helper to decide UnderlineAbove for text primitives */
+ bool isUnderlineAbove(const Font& rFont)
+ {
+ if(!rFont.IsVertical())
+ {
+ return false;
+ }
+
+ if((LANGUAGE_JAPANESE == rFont.GetLanguage()) || (LANGUAGE_JAPANESE == rFont.GetCJKContextLanguage()))
+ {
+ // the underline is right for Japanese only
+ return true;
+ }
+
+ return false;
+ }
+
+ void createFontAttributeTransformAndAlignment(
+ drawinglayer::attribute::FontAttribute& rFontAttribute,
+ basegfx::B2DHomMatrix& rTextTransform,
+ basegfx::B2DVector& rAlignmentOffset,
+ PropertyHolder& rProperty)
+ {
+ const Font& rFont = rProperty.getFont();
+ basegfx::B2DVector aFontScaling;
+
+ rFontAttribute = drawinglayer::attribute::FontAttribute(
+ drawinglayer::primitive2d::getFontAttributeFromVclFont(
+ aFontScaling,
+ rFont,
+ 0 != (rProperty.getLayoutMode() & TEXT_LAYOUT_BIDI_RTL),
+ 0 != (rProperty.getLayoutMode() & TEXT_LAYOUT_BIDI_STRONG)));
+
+ // add FontScaling
+ rTextTransform.scale(aFontScaling.getX(), aFontScaling.getY());
+
+ // take text align into account
+ if(ALIGN_BASELINE != rFont.GetAlign())
+ {
+ drawinglayer::primitive2d::TextLayouterDevice aTextLayouterDevice;
+ aTextLayouterDevice.setFont(rFont);
+
+ if(ALIGN_TOP == rFont.GetAlign())
+ {
+ rAlignmentOffset.setY(aTextLayouterDevice.getFontAscent());
+ }
+ else // ALIGN_BOTTOM
+ {
+ rAlignmentOffset.setY(-aTextLayouterDevice.getFontDescent());
+ }
+
+ rTextTransform.translate(rAlignmentOffset.getX(), rAlignmentOffset.getY());
+ }
+
+ // add FontRotation (if used)
+ if(rFont.GetOrientation())
+ {
+ rTextTransform.rotate(-rFont.GetOrientation() * F_PI1800);
+ }
+ }
+
+ /** helper which takes complete care for creating the needed text primitives. It
+ takes care of decorated stuff and all the geometry adaptions needed
+ */
+ void proccessMetaTextAction(
+ const Point& rTextStartPosition,
+ const XubString& rText,
+ sal_uInt16 nTextStart,
+ sal_uInt16 nTextLength,
+ const ::std::vector< double >& rDXArray,
+ TargetHolder& rTarget,
+ PropertyHolder& rProperty)
+ {
+ drawinglayer::primitive2d::BasePrimitive2D* pResult = 0;
+ const Font& rFont = rProperty.getFont();
+ basegfx::B2DVector aAlignmentOffset(0.0, 0.0);
+
+ if(nTextLength)
+ {
+ drawinglayer::attribute::FontAttribute aFontAttribute;
+ basegfx::B2DHomMatrix aTextTransform;
+
+ // fill parameters derived from current font
+ createFontAttributeTransformAndAlignment(
+ aFontAttribute,
+ aTextTransform,
+ aAlignmentOffset,
+ rProperty);
+
+ // add TextStartPosition
+ aTextTransform.translate(rTextStartPosition.X(), rTextStartPosition.Y());
+
+ // prepare FontColor and Locale
+ const basegfx::BColor aFontColor(rProperty.getTextColor());
+ const com::sun::star::lang::Locale aLocale(MsLangId::convertLanguageToLocale(rProperty.getLanguageType()));
+ const bool bWordLineMode(rFont.IsWordLineMode());
+
+ const bool bDecoratedIsNeeded(
+ UNDERLINE_NONE != rFont.GetOverline()
+ || UNDERLINE_NONE != rFont.GetUnderline()
+ || STRIKEOUT_NONE != rFont.GetStrikeout()
+ || EMPHASISMARK_NONE != (rFont.GetEmphasisMark() & EMPHASISMARK_STYLE)
+ || RELIEF_NONE != rFont.GetRelief()
+ || rFont.IsShadow()
+ || bWordLineMode);
+
+ if(bDecoratedIsNeeded)
+ {
+ // prepare overline, underline and srikeout data
+ const drawinglayer::primitive2d::TextLine eFontOverline(drawinglayer::primitive2d::mapFontUnderlineToTextLine(rFont.GetOverline()));
+ const drawinglayer::primitive2d::TextLine eFontUnderline(drawinglayer::primitive2d::mapFontUnderlineToTextLine(rFont.GetUnderline()));
+ const drawinglayer::primitive2d::TextStrikeout eTextStrikeout(drawinglayer::primitive2d::mapFontStrikeoutToTextStrikeout(rFont.GetStrikeout()));
+
+ // check UndelineAbove
+ const bool bUnderlineAbove(drawinglayer::primitive2d::TEXT_LINE_NONE != eFontUnderline && isUnderlineAbove(rFont));
+
+ // prepare emphasis mark data
+ drawinglayer::primitive2d::TextEmphasisMark eTextEmphasisMark(drawinglayer::primitive2d::TEXT_EMPHASISMARK_NONE);
+
+ switch(rFont.GetEmphasisMark() & EMPHASISMARK_STYLE)
+ {
+ case EMPHASISMARK_DOT : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_EMPHASISMARK_DOT; break;
+ case EMPHASISMARK_CIRCLE : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_EMPHASISMARK_CIRCLE; break;
+ case EMPHASISMARK_DISC : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_EMPHASISMARK_DISC; break;
+ case EMPHASISMARK_ACCENT : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_EMPHASISMARK_ACCENT; break;
+ }
+
+ const bool bEmphasisMarkAbove(rFont.GetEmphasisMark() & EMPHASISMARK_POS_ABOVE);
+ const bool bEmphasisMarkBelow(rFont.GetEmphasisMark() & EMPHASISMARK_POS_BELOW);
+
+ // prepare font relief data
+ drawinglayer::primitive2d::TextRelief eTextRelief(drawinglayer::primitive2d::TEXT_RELIEF_NONE);
+
+ switch(rFont.GetRelief())
+ {
+ case RELIEF_EMBOSSED : eTextRelief = drawinglayer::primitive2d::TEXT_RELIEF_EMBOSSED; break;
+ case RELIEF_ENGRAVED : eTextRelief = drawinglayer::primitive2d::TEXT_RELIEF_ENGRAVED; break;
+ default : break; // RELIEF_NONE, FontRelief_FORCE_EQUAL_SIZE
+ }
+
+ // prepare shadow/outline data
+ const bool bShadow(rFont.IsShadow());
+
+ // TextDecoratedPortionPrimitive2D is needed, create one
+ pResult = new drawinglayer::primitive2d::TextDecoratedPortionPrimitive2D(
+
+ // attributes for TextSimplePortionPrimitive2D
+ aTextTransform,
+ rText,
+ nTextStart,
+ nTextLength,
+ rDXArray,
+ aFontAttribute,
+ aLocale,
+ aFontColor,
+
+ // attributes for TextDecoratedPortionPrimitive2D
+ rProperty.getOverlineColorActive() ? rProperty.getOverlineColor() : aFontColor,
+ rProperty.getTextLineColorActive() ? rProperty.getTextLineColor() : aFontColor,
+ eFontOverline,
+ eFontUnderline,
+ bUnderlineAbove,
+ eTextStrikeout,
+ bWordLineMode,
+ eTextEmphasisMark,
+ bEmphasisMarkAbove,
+ bEmphasisMarkBelow,
+ eTextRelief,
+ bShadow);
+ }
+ else
+ {
+ // TextSimplePortionPrimitive2D is enough
+ pResult = new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
+ aTextTransform,
+ rText,
+ nTextStart,
+ nTextLength,
+ rDXArray,
+ aFontAttribute,
+ aLocale,
+ aFontColor);
+ }
+ }
+
+ if(pResult && rProperty.getTextFillColorActive())
+ {
+ // text background is requested, add and encapsulate both to new primitive
+ drawinglayer::primitive2d::TextLayouterDevice aTextLayouterDevice;
+ aTextLayouterDevice.setFont(rFont);
+
+ // get text width
+ double fTextWidth(0.0);
+
+ if(rDXArray.empty())
+ {
+ fTextWidth = aTextLayouterDevice.getTextWidth(rText, nTextStart, nTextLength);
+ }
+ else
+ {
+ fTextWidth = rDXArray.back();
+ }
+
+ if(basegfx::fTools::more(fTextWidth, 0.0))
+ {
+ // build text range
+ const basegfx::B2DRange aTextRange(
+ 0.0, -aTextLayouterDevice.getFontAscent(),
+ fTextWidth, aTextLayouterDevice.getFontDescent());
+
+ // create Transform
+ basegfx::B2DHomMatrix aTextTransform;
+
+ aTextTransform.translate(aAlignmentOffset.getX(), aAlignmentOffset.getY());
+
+ if(rFont.GetOrientation())
+ {
+ aTextTransform.rotate(-rFont.GetOrientation() * F_PI1800);
+ }
+
+ aTextTransform.translate(rTextStartPosition.X(), rTextStartPosition.Y());
+
+ // prepare Primitive2DSequence, put text in foreground
+ drawinglayer::primitive2d::Primitive2DSequence aSequence(2);
+ aSequence[1] = drawinglayer::primitive2d::Primitive2DReference(pResult);
+
+ // prepare filled polygon
+ basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(aTextRange));
+ aOutline.transform(aTextTransform);
+
+ aSequence[0] = drawinglayer::primitive2d::Primitive2DReference(
+ new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
+ basegfx::B2DPolyPolygon(aOutline),
+ rProperty.getTextFillColor()));
+
+ // set as group at pResult
+ pResult = new drawinglayer::primitive2d::GroupPrimitive2D(aSequence);
+ }
+ }
+
+ if(pResult)
+ {
+ // add created text primitive to target
+ if(rProperty.getTransformation().isIdentity())
+ {
+ rTarget.append(pResult);
+ }
+ else
+ {
+ // when a transformation is set, embed to it
+ const drawinglayer::primitive2d::Primitive2DReference aReference(pResult);
+
+ rTarget.append(
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ rProperty.getTransformation(),
+ drawinglayer::primitive2d::Primitive2DSequence(&aReference, 1)));
+ }
+ }
+ }
+
+ /** helper which takes complete care for creating the needed textLine primitives */
+ void proccessMetaTextLineAction(
+ const MetaTextLineAction& rAction,
+ TargetHolder& rTarget,
+ PropertyHolder& rProperty)
+ {
+ const double fLineWidth(fabs((double)rAction.GetWidth()));
+
+ if(fLineWidth > 0.0)
+ {
+ const drawinglayer::primitive2d::TextLine aOverlineMode(drawinglayer::primitive2d::mapFontUnderlineToTextLine(rAction.GetOverline()));
+ const drawinglayer::primitive2d::TextLine aUnderlineMode(drawinglayer::primitive2d::mapFontUnderlineToTextLine(rAction.GetUnderline()));
+ const drawinglayer::primitive2d::TextStrikeout aTextStrikeout(drawinglayer::primitive2d::mapFontStrikeoutToTextStrikeout(rAction.GetStrikeout()));
+
+ const bool bOverlineUsed(drawinglayer::primitive2d::TEXT_LINE_NONE != aOverlineMode);
+ const bool bUnderlineUsed(drawinglayer::primitive2d::TEXT_LINE_NONE != aUnderlineMode);
+ const bool bStrikeoutUsed(drawinglayer::primitive2d::TEXT_STRIKEOUT_NONE != aTextStrikeout);
+
+ if(bUnderlineUsed || bStrikeoutUsed || bOverlineUsed)
+ {
+ std::vector< drawinglayer::primitive2d::BasePrimitive2D* > aTargetVector;
+ basegfx::B2DVector aAlignmentOffset(0.0, 0.0);
+ drawinglayer::attribute::FontAttribute aFontAttribute;
+ basegfx::B2DHomMatrix aTextTransform;
+
+ // fill parameters derived from current font
+ createFontAttributeTransformAndAlignment(
+ aFontAttribute,
+ aTextTransform,
+ aAlignmentOffset,
+ rProperty);
+
+ // add TextStartPosition
+ aTextTransform.translate(rAction.GetStartPoint().X(), rAction.GetStartPoint().Y());
+
+ // prepare TextLayouter (used in most cases)
+ drawinglayer::primitive2d::TextLayouterDevice aTextLayouter;
+ aTextLayouter.setFont(rProperty.getFont());
+
+ if(bOverlineUsed)
+ {
+ // create primitive geometry for overline
+ aTargetVector.push_back(
+ new drawinglayer::primitive2d::TextLinePrimitive2D(
+ aTextTransform,
+ fLineWidth,
+ aTextLayouter.getOverlineOffset(),
+ aTextLayouter.getOverlineHeight(),
+ aOverlineMode,
+ rProperty.getOverlineColor()));
+ }
+
+ if(bUnderlineUsed)
+ {
+ // create primitive geometry for underline
+ aTargetVector.push_back(
+ new drawinglayer::primitive2d::TextLinePrimitive2D(
+ aTextTransform,
+ fLineWidth,
+ aTextLayouter.getUnderlineOffset(),
+ aTextLayouter.getUnderlineHeight(),
+ aUnderlineMode,
+ rProperty.getTextLineColor()));
+ }
+
+ if(bStrikeoutUsed)
+ {
+ // create primitive geometry for strikeout
+ if(drawinglayer::primitive2d::TEXT_STRIKEOUT_SLASH == aTextStrikeout
+ || drawinglayer::primitive2d::TEXT_STRIKEOUT_X == aTextStrikeout)
+ {
+ // strikeout with character
+ const sal_Unicode aStrikeoutChar(
+ drawinglayer::primitive2d::TEXT_STRIKEOUT_SLASH == aTextStrikeout ? '/' : 'X');
+ const com::sun::star::lang::Locale aLocale(MsLangId::convertLanguageToLocale(
+ rProperty.getLanguageType()));
+
+ aTargetVector.push_back(
+ new drawinglayer::primitive2d::TextCharacterStrikeoutPrimitive2D(
+ aTextTransform,
+ fLineWidth,
+ rProperty.getTextColor(),
+ aStrikeoutChar,
+ aFontAttribute,
+ aLocale));
+ }
+ else
+ {
+ // strikeout with geometry
+ aTargetVector.push_back(
+ new drawinglayer::primitive2d::TextGeometryStrikeoutPrimitive2D(
+ aTextTransform,
+ fLineWidth,
+ rProperty.getTextColor(),
+ aTextLayouter.getUnderlineHeight(),
+ aTextLayouter.getStrikeoutOffset(),
+ aTextStrikeout));
+ }
+ }
+
+ if(aTargetVector.size())
+ {
+ // add created text primitive to target
+ if(rProperty.getTransformation().isIdentity())
+ {
+ for(sal_uInt32 a(0); a < aTargetVector.size(); a++)
+ {
+ rTarget.append(aTargetVector[a]);
+ }
+ }
+ else
+ {
+ // when a transformation is set, embed to it
+ drawinglayer::primitive2d::Primitive2DSequence xTargets(aTargetVector.size());
+
+ for(sal_uInt32 a(0); a < aTargetVector.size(); a++)
+ {
+ xTargets[a] = drawinglayer::primitive2d::Primitive2DReference(aTargetVector[a]);
+ }
+
+ rTarget.append(
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ rProperty.getTransformation(),
+ xTargets));
+ }
+ }
+ }
+ }
+
+ }
+
+ /** This is the main interpreter method. It is designed to handle the given Metafile
+ completely inside the given context and target. It may use and modify the context and
+ target. This design allows to call itself recursively wich adapted contexts and
+ targets as e.g. needed for the META_FLOATTRANSPARENT_ACTION where the content is expressed
+ as a metafile as sub-content.
+
+ This interpreter is as free of VCL functionality as possible. It uses VCL data classes
+ (else reading the data would not be possible), but e.g. does NOT use a local OutputDevice
+ as most other MetaFile interpreters/exporters do to hold and work with the current context.
+ This is necessary to be able to get away from the strong internal VCL-binding.
+
+ It tries to combine e.g. pixel and/or point actions and to stitch together single line primitives
+ where possible (which is not trivial with the possible line geometry definitions).
+
+ It tries to handle clipping no longer as Regions and spans of Rectangles, but as PolyPolygon
+ ClipRegions with (where possible) high precision by using the best possible data quality
+ from the Region. The Region is unavoidable as data container, but nowadays allows the transport
+ of Polygon-based clip regions. Where this is not used, a Polygon is constructed from the
+ Region ranges. All primitive clipping uses the MaskPrimitive2D with Polygon-based clipping.
+
+ I have marked the single MetaActions with:
+
+ SIMPLE, DONE:
+ Simple, e.g nothing to do or value setting in the context
+
+ CHECKED, WORKS WELL:
+ Thoroughly tested with extra written test code which created a replacement
+ Metafile just to test this action in various combinations
+
+ NEEDS IMPLEMENTATION:
+ Not implemented and asserted, but also no usage found, neither in own Metafile
+ creations, nor in EMF/WMF imports (checked with a whole bunch of critical EMF/WMF
+ bugdocs)
+
+ For more commens, see the single action implementations.
+ */
+ void interpretMetafile(
+ const GDIMetaFile& rMetaFile,
+ TargetHolders& rTargetHolders,
+ PropertyHolders& rPropertyHolders,
+ const drawinglayer::geometry::ViewInformation2D& rViewInformation)
+ {
+ const sal_uInt32 nCount(rMetaFile.GetActionCount());
+
+ for(sal_uInt32 nAction(0); nAction < nCount; nAction++)
+ {
+ MetaAction* pAction = rMetaFile.GetAction(nAction);
+
+ switch(pAction->GetType())
+ {
+ case META_NULL_ACTION :
+ {
+ /** SIMPLE, DONE */
+ break;
+ }
+ case META_PIXEL_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ std::vector< basegfx::B2DPoint > aPositions;
+ Color aLastColor(COL_BLACK);
+
+ while(META_PIXEL_ACTION == pAction->GetType() && nAction < nCount)
+ {
+ const MetaPixelAction* pA = (const MetaPixelAction*)pAction;
+
+ if(pA->GetColor() != aLastColor)
+ {
+ if(aPositions.size())
+ {
+ createPointArrayPrimitive(aPositions, rTargetHolders.Current(), rPropertyHolders.Current(), aLastColor.getBColor());
+ aPositions.clear();
+ }
+
+ aLastColor = pA->GetColor();
+ }
+
+ const Point& rPoint = pA->GetPoint();
+ aPositions.push_back(basegfx::B2DPoint(rPoint.X(), rPoint.Y()));
+ nAction++; if(nAction < nCount) pAction = rMetaFile.GetAction(nAction);
+ }
+
+ nAction--;
+
+ if(aPositions.size())
+ {
+ createPointArrayPrimitive(aPositions, rTargetHolders.Current(), rPropertyHolders.Current(), aLastColor.getBColor());
+ }
+
+ break;
+ }
+ case META_POINT_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ if(rPropertyHolders.Current().getLineColorActive())
+ {
+ std::vector< basegfx::B2DPoint > aPositions;
+
+ while(META_POINT_ACTION == pAction->GetType() && nAction < nCount)
+ {
+ const MetaPointAction* pA = (const MetaPointAction*)pAction;
+ const Point& rPoint = pA->GetPoint();
+ aPositions.push_back(basegfx::B2DPoint(rPoint.X(), rPoint.Y()));
+ nAction++; if(nAction < nCount) pAction = rMetaFile.GetAction(nAction);
+ }
+
+ nAction--;
+
+ if(aPositions.size())
+ {
+ createPointArrayPrimitive(aPositions, rTargetHolders.Current(), rPropertyHolders.Current(), rPropertyHolders.Current().getLineColor());
+ }
+ }
+
+ break;
+ }
+ case META_LINE_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ if(rPropertyHolders.Current().getLineColorActive())
+ {
+ basegfx::B2DPolygon aLinePolygon;
+ LineInfo aLineInfo;
+
+ while(META_LINE_ACTION == pAction->GetType() && nAction < nCount)
+ {
+ const MetaLineAction* pA = (const MetaLineAction*)pAction;
+ const Point& rStartPoint = pA->GetStartPoint();
+ const Point& rEndPoint = pA->GetEndPoint();
+ const basegfx::B2DPoint aStart(rStartPoint.X(), rStartPoint.Y());
+ const basegfx::B2DPoint aEnd(rEndPoint.X(), rEndPoint.Y());
+
+ if(aLinePolygon.count())
+ {
+ if(pA->GetLineInfo() == aLineInfo
+ && aStart == aLinePolygon.getB2DPoint(aLinePolygon.count() - 1))
+ {
+ aLinePolygon.append(aEnd);
+ }
+ else
+ {
+ aLineInfo.SetLineJoin(basegfx::B2DLINEJOIN_NONE); // It were lines; force to NONE
+ createLinePrimitive(aLinePolygon, aLineInfo, rTargetHolders.Current(), rPropertyHolders.Current());
+ aLinePolygon.clear();
+ aLineInfo = pA->GetLineInfo();
+ aLinePolygon.append(aStart);
+ aLinePolygon.append(aEnd);
+ }
+ }
+ else
+ {
+ aLineInfo = pA->GetLineInfo();
+ aLinePolygon.append(aStart);
+ aLinePolygon.append(aEnd);
+ }
+
+ nAction++; if(nAction < nCount) pAction = rMetaFile.GetAction(nAction);
+ }
+
+ nAction--;
+
+ if(aLinePolygon.count())
+ {
+ aLineInfo.SetLineJoin(basegfx::B2DLINEJOIN_NONE); // It were lines; force to NONE
+ createLinePrimitive(aLinePolygon, aLineInfo, rTargetHolders.Current(), rPropertyHolders.Current());
+ }
+ }
+
+ break;
+ }
+ case META_RECT_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ if(rPropertyHolders.Current().getLineOrFillActive())
+ {
+ const MetaRectAction* pA = (const MetaRectAction*)pAction;
+ const Rectangle& rRectangle = pA->GetRect();
+
+ if(!rRectangle.IsEmpty())
+ {
+ const basegfx::B2DRange aRange(rRectangle.Left(), rRectangle.Top(), rRectangle.Right(), rRectangle.Bottom());
+
+ if(!aRange.isEmpty())
+ {
+ const basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(aRange));
+ createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
+ }
+ }
+ }
+
+ break;
+ }
+ case META_ROUNDRECT_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ /** The original OutputDevice::DrawRect paints nothing when nHor or nVer is zero; but just
+ because the tools::Polygon operator creating the rounding does produce nonsense. I assume
+ this an error and create an unrounded rectangle in that case (implicit in
+ createPolygonFromRect)
+ */
+ if(rPropertyHolders.Current().getLineOrFillActive())
+ {
+ const MetaRoundRectAction* pA = (const MetaRoundRectAction*)pAction;
+ const Rectangle& rRectangle = pA->GetRect();
+
+ if(!rRectangle.IsEmpty())
+ {
+ const basegfx::B2DRange aRange(rRectangle.Left(), rRectangle.Top(), rRectangle.Right(), rRectangle.Bottom());
+
+ if(!aRange.isEmpty())
+ {
+ const sal_uInt32 nHor(pA->GetHorzRound());
+ const sal_uInt32 nVer(pA->GetVertRound());
+ basegfx::B2DPolygon aOutline;
+
+ if(nHor || nVer)
+ {
+ double fRadiusX((nHor * 2.0) / (aRange.getWidth() > 0.0 ? aRange.getWidth() : 1.0));
+ double fRadiusY((nVer * 2.0) / (aRange.getHeight() > 0.0 ? aRange.getHeight() : 1.0));
+ fRadiusX = std::max(0.0, std::min(1.0, fRadiusX));
+ fRadiusY = std::max(0.0, std::min(1.0, fRadiusY));
+
+ aOutline = basegfx::tools::createPolygonFromRect(aRange, fRadiusX, fRadiusY);
+ }
+ else
+ {
+ aOutline = basegfx::tools::createPolygonFromRect(aRange);
+ }
+
+ createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
+ }
+ }
+ }
+
+ break;
+ }
+ case META_ELLIPSE_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ if(rPropertyHolders.Current().getLineOrFillActive())
+ {
+ const MetaEllipseAction* pA = (const MetaEllipseAction*)pAction;
+ const Rectangle& rRectangle = pA->GetRect();
+
+ if(!rRectangle.IsEmpty())
+ {
+ const basegfx::B2DRange aRange(rRectangle.Left(), rRectangle.Top(), rRectangle.Right(), rRectangle.Bottom());
+
+ if(!aRange.isEmpty())
+ {
+ const basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromEllipse(
+ aRange.getCenter(), aRange.getWidth() * 0.5, aRange.getHeight() * 0.5));
+
+ createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
+ }
+ }
+ }
+
+ break;
+ }
+ case META_ARC_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ if(rPropertyHolders.Current().getLineColorActive())
+ {
+ const MetaArcAction* pA = (const MetaArcAction*)pAction;
+ const Polygon aToolsPoly(pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_ARC);
+ const basegfx::B2DPolygon aOutline(aToolsPoly.getB2DPolygon());
+
+ createHairlinePrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
+ }
+
+ break;
+ }
+ case META_PIE_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ if(rPropertyHolders.Current().getLineOrFillActive())
+ {
+ const MetaPieAction* pA = (const MetaPieAction*)pAction;
+ const Polygon aToolsPoly(pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_PIE);
+ const basegfx::B2DPolygon aOutline(aToolsPoly.getB2DPolygon());
+
+ createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
+ }
+
+ break;
+ }
+ case META_CHORD_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ if(rPropertyHolders.Current().getLineOrFillActive())
+ {
+ const MetaChordAction* pA = (const MetaChordAction*)pAction;
+ const Polygon aToolsPoly(pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_CHORD);
+ const basegfx::B2DPolygon aOutline(aToolsPoly.getB2DPolygon());
+
+ createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
+ }
+
+ break;
+ }
+ case META_POLYLINE_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ if(rPropertyHolders.Current().getLineColorActive())
+ {
+ const MetaPolyLineAction* pA = (const MetaPolyLineAction*)pAction;
+ createLinePrimitive(pA->GetPolygon().getB2DPolygon(), pA->GetLineInfo(), rTargetHolders.Current(), rPropertyHolders.Current());
+ }
+
+ break;
+ }
+ case META_POLYGON_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ if(rPropertyHolders.Current().getLineOrFillActive())
+ {
+ const MetaPolygonAction* pA = (const MetaPolygonAction*)pAction;
+ basegfx::B2DPolygon aOutline(pA->GetPolygon().getB2DPolygon());
+
+ // the metafile play interprets the polygons from MetaPolygonAction
+ // always as closed and always paints an edge from last to first point,
+ // so force to closed here to emulate that
+ if(aOutline.count() > 1 && !aOutline.isClosed())
+ {
+ aOutline.setClosed(true);
+ }
+
+ createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
+ }
+
+ break;
+ }
+ case META_POLYPOLYGON_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ if(rPropertyHolders.Current().getLineOrFillActive())
+ {
+ const MetaPolyPolygonAction* pA = (const MetaPolyPolygonAction*)pAction;
+ basegfx::B2DPolyPolygon aPolyPolygonOutline(pA->GetPolyPolygon().getB2DPolyPolygon());
+
+ // the metafile play interprets the single polygons from MetaPolyPolygonAction
+ // always as closed and always paints an edge from last to first point,
+ // so force to closed here to emulate that
+ for(sal_uInt32 b(0); b < aPolyPolygonOutline.count(); b++)
+ {
+ basegfx::B2DPolygon aPolygonOutline(aPolyPolygonOutline.getB2DPolygon(b));
+
+ if(aPolygonOutline.count() > 1 && !aPolygonOutline.isClosed())
+ {
+ aPolygonOutline.setClosed(true);
+ aPolyPolygonOutline.setB2DPolygon(b, aPolygonOutline);
+ }
+ }
+
+ createHairlineAndFillPrimitive(aPolyPolygonOutline, rTargetHolders.Current(), rPropertyHolders.Current());
+ }
+
+ break;
+ }
+ case META_TEXT_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ const MetaTextAction* pA = (const MetaTextAction*)pAction;
+ sal_uInt32 nTextLength(pA->GetLen());
+ const sal_uInt32 nTextIndex(pA->GetIndex());
+ const sal_uInt32 nStringLength(pA->GetText().Len());
+
+ if(nTextLength + nTextIndex > nStringLength)
+ {
+ nTextLength = nStringLength - nTextIndex;
+ }
+
+ if(nTextLength && rPropertyHolders.Current().getTextColorActive())
+ {
+ const std::vector< double > aDXArray;
+ proccessMetaTextAction(
+ pA->GetPoint(),
+ pA->GetText(),
+ nTextIndex,
+ nTextLength,
+ aDXArray,
+ rTargetHolders.Current(),
+ rPropertyHolders.Current());
+ }
+
+ break;
+ }
+ case META_TEXTARRAY_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ const MetaTextArrayAction* pA = (const MetaTextArrayAction*)pAction;
+ sal_uInt32 nTextLength(pA->GetLen());
+ const sal_uInt32 nTextIndex(pA->GetIndex());
+ const sal_uInt32 nStringLength(pA->GetText().Len());
+
+ if(nTextLength + nTextIndex > nStringLength)
+ {
+ nTextLength = nTextIndex > nStringLength ? 0 : nStringLength - nTextIndex;
+ }
+
+ if(nTextLength && rPropertyHolders.Current().getTextColorActive())
+ {
+ // preapare DXArray (if used)
+ std::vector< double > aDXArray;
+ sal_Int32* pDXArray = pA->GetDXArray();
+
+ if(pDXArray)
+ {
+ aDXArray.reserve(nTextLength);
+
+ for(sal_uInt32 a(0); a < nTextLength; a++)
+ {
+ aDXArray.push_back((double)(*(pDXArray + a)));
+ }
+ }
+
+ proccessMetaTextAction(
+ pA->GetPoint(),
+ pA->GetText(),
+ nTextIndex,
+ nTextLength,
+ aDXArray,
+ rTargetHolders.Current(),
+ rPropertyHolders.Current());
+ }
+
+ break;
+ }
+ case META_STRETCHTEXT_ACTION :
+ {
+ // #i108440# StarMath uses MetaStretchTextAction, thus support is needed.
+ // It looks as if it pretty never really uses a width different from
+ // the default text-layout width, but it's not possible to be sure.
+ // Implemented getting the DXArray and checking for scale at all. If
+ // scale is more than 3.5% different, scale the DXArray before usage.
+ // New status:
+
+ /** CHECKED, WORKS WELL */
+ const MetaStretchTextAction* pA = (const MetaStretchTextAction*)pAction;
+ sal_uInt32 nTextLength(pA->GetLen());
+ const sal_uInt32 nTextIndex(pA->GetIndex());
+ const sal_uInt32 nStringLength(pA->GetText().Len());
+
+ if(nTextLength + nTextIndex > nStringLength)
+ {
+ nTextLength = nStringLength - nTextIndex;
+ }
+
+ if(nTextLength && rPropertyHolders.Current().getTextColorActive())
+ {
+ drawinglayer::primitive2d::TextLayouterDevice aTextLayouterDevice;
+ aTextLayouterDevice.setFont(rPropertyHolders.Current().getFont());
+
+ ::std::vector< double > aTextArray(
+ aTextLayouterDevice.getTextArray(
+ pA->GetText(),
+ nTextIndex,
+ nTextLength));
+
+ if(!aTextArray.empty())
+ {
+ const double fTextLength(aTextArray.back());
+
+ if(0.0 != fTextLength && pA->GetWidth())
+ {
+ const double fRelative(pA->GetWidth() / fTextLength);
+
+ if(fabs(fRelative - 1.0) >= 0.035)
+ {
+ // when derivation is more than 3,5% from default text size,
+ // scale the DXArray
+ for(sal_uInt32 a(0); a < aTextArray.size(); a++)
+ {
+ aTextArray[a] *= fRelative;
+ }
+ }
+ }
+ }
+
+ proccessMetaTextAction(
+ pA->GetPoint(),
+ pA->GetText(),
+ nTextIndex,
+ nTextLength,
+ aTextArray,
+ rTargetHolders.Current(),
+ rPropertyHolders.Current());
+ }
+
+ break;
+ }
+ case META_TEXTRECT_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ // OSL_ENSURE(false, "META_TEXTRECT_ACTION requested (!)");
+ const MetaTextRectAction* pA = (const MetaTextRectAction*)pAction;
+ const Rectangle& rRectangle = pA->GetRect();
+ const sal_uInt32 nStringLength(pA->GetText().Len());
+
+ if(!rRectangle.IsEmpty() && 0 != nStringLength)
+ {
+ // The problem with this action is that it describes unlayouted text
+ // and the layout capabilities are in EditEngine/Outliner in SVX. The
+ // same problem is true for VCL which internally has implementations
+ // to layout text in this case. There exists even a call
+ // OutputDevice::AddTextRectActions(...) to create the needed actions
+ // as 'sub-content' of a Metafile. Unfortunately i do not have an
+ // OutputDevice here since this interpreter tries to work without
+ // VCL AFAP.
+ // Since AddTextRectActions is the only way as long as we do not have
+ // a simple text layouter available, i will try to add it to the
+ // TextLayouterDevice isloation.
+ drawinglayer::primitive2d::TextLayouterDevice aTextLayouterDevice;
+ aTextLayouterDevice.setFont(rPropertyHolders.Current().getFont());
+ GDIMetaFile aGDIMetaFile;
+
+ aTextLayouterDevice.addTextRectActions(
+ rRectangle, pA->GetText(), pA->GetStyle(), aGDIMetaFile);
+
+ if(aGDIMetaFile.GetActionCount())
+ {
+ // cerate sub-content
+ drawinglayer::primitive2d::Primitive2DSequence xSubContent;
+ {
+ rTargetHolders.Push();
+ // #i# for sub-Mteafile contents, do start with new, default render state
+ rPropertyHolders.PushDefault();
+ interpretMetafile(aGDIMetaFile, rTargetHolders, rPropertyHolders, rViewInformation);
+ xSubContent = rTargetHolders.Current().getPrimitive2DSequence(rPropertyHolders.Current());
+ rPropertyHolders.Pop();
+ rTargetHolders.Pop();
+ }
+
+ if(xSubContent.hasElements())
+ {
+ // add with transformation
+ rTargetHolders.Current().append(
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ rPropertyHolders.Current().getTransformation(),
+ xSubContent));
+ }
+ }
+ }
+
+ break;
+ }
+ case META_BMP_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ const MetaBmpAction* pA = (const MetaBmpAction*)pAction;
+ const BitmapEx aBitmapEx(pA->GetBitmap());
+
+ createBitmapExPrimitive(aBitmapEx, pA->GetPoint(), rTargetHolders.Current(), rPropertyHolders.Current());
+
+ break;
+ }
+ case META_BMPSCALE_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ const MetaBmpScaleAction* pA = (const MetaBmpScaleAction*)pAction;
+ const Bitmap aBitmapEx(pA->GetBitmap());
+
+ createBitmapExPrimitive(aBitmapEx, pA->GetPoint(), pA->GetSize(), rTargetHolders.Current(), rPropertyHolders.Current());
+
+ break;
+ }
+ case META_BMPSCALEPART_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ const MetaBmpScalePartAction* pA = (const MetaBmpScalePartAction*)pAction;
+ const Bitmap& rBitmap = pA->GetBitmap();
+
+ if(!rBitmap.IsEmpty())
+ {
+ Bitmap aCroppedBitmap(rBitmap);
+ const Rectangle aCropRectangle(pA->GetSrcPoint(), pA->GetSrcSize());
+
+ if(!aCropRectangle.IsEmpty())
+ {
+ aCroppedBitmap.Crop(aCropRectangle);
+ }
+
+ const BitmapEx aCroppedBitmapEx(aCroppedBitmap);
+ createBitmapExPrimitive(aCroppedBitmapEx, pA->GetDestPoint(), pA->GetDestSize(), rTargetHolders.Current(), rPropertyHolders.Current());
+ }
+
+ break;
+ }
+ case META_BMPEX_ACTION :
+ {
+ /** CHECKED, WORKS WELL: Simply same as META_BMP_ACTION */
+ const MetaBmpExAction* pA = (const MetaBmpExAction*)pAction;
+ const BitmapEx& rBitmapEx = pA->GetBitmapEx();
+
+ createBitmapExPrimitive(rBitmapEx, pA->GetPoint(), rTargetHolders.Current(), rPropertyHolders.Current());
+
+ break;
+ }
+ case META_BMPEXSCALE_ACTION :
+ {
+ /** CHECKED, WORKS WELL: Simply same as META_BMPSCALE_ACTION */
+ const MetaBmpExScaleAction* pA = (const MetaBmpExScaleAction*)pAction;
+ const BitmapEx& rBitmapEx = pA->GetBitmapEx();
+
+ createBitmapExPrimitive(rBitmapEx, pA->GetPoint(), pA->GetSize(), rTargetHolders.Current(), rPropertyHolders.Current());
+
+ break;
+ }
+ case META_BMPEXSCALEPART_ACTION :
+ {
+ /** CHECKED, WORKS WELL: Simply same as META_BMPSCALEPART_ACTION */
+ const MetaBmpExScalePartAction* pA = (const MetaBmpExScalePartAction*)pAction;
+ const BitmapEx& rBitmapEx = pA->GetBitmapEx();
+
+ if(!rBitmapEx.IsEmpty())
+ {
+ BitmapEx aCroppedBitmapEx(rBitmapEx);
+ const Rectangle aCropRectangle(pA->GetSrcPoint(), pA->GetSrcSize());
+
+ if(!aCropRectangle.IsEmpty())
+ {
+ aCroppedBitmapEx.Crop(aCropRectangle);
+ }
+
+ createBitmapExPrimitive(aCroppedBitmapEx, pA->GetDestPoint(), pA->GetDestSize(), rTargetHolders.Current(), rPropertyHolders.Current());
+ }
+
+ break;
+ }
+ case META_MASK_ACTION :
+ {
+ /** CHECKED, WORKS WELL: Simply same as META_BMP_ACTION */
+ const MetaMaskAction* pA = (const MetaMaskAction*)pAction;
+ const BitmapEx aBitmapEx(createMaskBmpEx(pA->GetBitmap(), pA->GetColor()));
+
+ createBitmapExPrimitive(aBitmapEx, pA->GetPoint(), rTargetHolders.Current(), rPropertyHolders.Current());
+
+ break;
+ }
+ case META_MASKSCALE_ACTION :
+ {
+ /** CHECKED, WORKS WELL: Simply same as META_BMPSCALE_ACTION */
+ const MetaMaskScaleAction* pA = (const MetaMaskScaleAction*)pAction;
+ const BitmapEx aBitmapEx(createMaskBmpEx(pA->GetBitmap(), pA->GetColor()));
+
+ createBitmapExPrimitive(aBitmapEx, pA->GetPoint(), pA->GetSize(), rTargetHolders.Current(), rPropertyHolders.Current());
+
+ break;
+ }
+ case META_MASKSCALEPART_ACTION :
+ {
+ /** CHECKED, WORKS WELL: Simply same as META_BMPSCALEPART_ACTION */
+ const MetaMaskScalePartAction* pA = (const MetaMaskScalePartAction*)pAction;
+ const Bitmap& rBitmap = pA->GetBitmap();
+
+ if(!rBitmap.IsEmpty())
+ {
+ Bitmap aCroppedBitmap(rBitmap);
+ const Rectangle aCropRectangle(pA->GetSrcPoint(), pA->GetSrcSize());
+
+ if(!aCropRectangle.IsEmpty())
+ {
+ aCroppedBitmap.Crop(aCropRectangle);
+ }
+
+ const BitmapEx aCroppedBitmapEx(createMaskBmpEx(aCroppedBitmap, pA->GetColor()));
+ createBitmapExPrimitive(aCroppedBitmapEx, pA->GetDestPoint(), pA->GetDestSize(), rTargetHolders.Current(), rPropertyHolders.Current());
+ }
+
+ break;
+ }
+ case META_GRADIENT_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ const MetaGradientAction* pA = (const MetaGradientAction*)pAction;
+ const Rectangle& rRectangle = pA->GetRect();
+
+ if(!rRectangle.IsEmpty())
+ {
+ basegfx::B2DRange aRange(rRectangle.Left(), rRectangle.Top(), rRectangle.Right(), rRectangle.Bottom());
+
+ if(!aRange.isEmpty())
+ {
+ const Gradient& rGradient = pA->GetGradient();
+ const drawinglayer::attribute::FillGradientAttribute aAttribute(createFillGradientAttribute(rGradient));
+ basegfx::B2DPolyPolygon aOutline(basegfx::tools::createPolygonFromRect(aRange));
+
+ if(aAttribute.getStartColor() == aAttribute.getEndColor())
+ {
+ // not really a gradient. Create filled rectangle
+ createFillPrimitive(
+ aOutline,
+ rTargetHolders.Current(),
+ rPropertyHolders.Current());
+ }
+ else
+ {
+ // really a gradient
+ aRange.transform(rPropertyHolders.Current().getTransformation());
+ drawinglayer::primitive2d::Primitive2DSequence xGradient(1);
+
+ if(rPropertyHolders.Current().isRasterOpInvert())
+ {
+ // use a special version of FillGradientPrimitive2D which creates
+ // non-overlapping geometry on decomposition to makethe old XOR
+ // paint 'trick' work.
+ xGradient[0] = drawinglayer::primitive2d::Primitive2DReference(
+ new drawinglayer::primitive2d::NonOverlappingFillGradientPrimitive2D(
+ aRange,
+ aAttribute));
+ }
+ else
+ {
+ xGradient[0] = drawinglayer::primitive2d::Primitive2DReference(
+ new drawinglayer::primitive2d::FillGradientPrimitive2D(
+ aRange,
+ aAttribute));
+ }
+
+ // #i112300# clip against polygon representing the rectangle from
+ // the action. This is implicitely done using a temp Clipping in VCL
+ // when a MetaGradientAction is executed
+ aOutline.transform(rPropertyHolders.Current().getTransformation());
+ rTargetHolders.Current().append(
+ new drawinglayer::primitive2d::MaskPrimitive2D(
+ aOutline,
+ xGradient));
+ }
+ }
+ }
+
+ break;
+ }
+ case META_HATCH_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ const MetaHatchAction* pA = (const MetaHatchAction*)pAction;
+ basegfx::B2DPolyPolygon aOutline(pA->GetPolyPolygon().getB2DPolyPolygon());
+
+ if(aOutline.count())
+ {
+ const Hatch& rHatch = pA->GetHatch();
+ const drawinglayer::attribute::FillHatchAttribute aAttribute(createFillHatchAttribute(rHatch));
+
+ aOutline.transform(rPropertyHolders.Current().getTransformation());
+
+ const basegfx::B2DRange aObjectRange(aOutline.getB2DRange());
+ const drawinglayer::primitive2d::Primitive2DReference aFillHatch(
+ new drawinglayer::primitive2d::FillHatchPrimitive2D(
+ aObjectRange,
+ basegfx::BColor(),
+ aAttribute));
+
+ rTargetHolders.Current().append(
+ new drawinglayer::primitive2d::MaskPrimitive2D(
+ aOutline,
+ drawinglayer::primitive2d::Primitive2DSequence(&aFillHatch, 1)));
+ }
+
+ break;
+ }
+ case META_WALLPAPER_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ const MetaWallpaperAction* pA = (const MetaWallpaperAction*)pAction;
+ Rectangle aWallpaperRectangle(pA->GetRect());
+
+ if(!aWallpaperRectangle.IsEmpty())
+ {
+ const Wallpaper& rWallpaper = pA->GetWallpaper();
+ const WallpaperStyle eWallpaperStyle(rWallpaper.GetStyle());
+ basegfx::B2DRange aWallpaperRange(
+ aWallpaperRectangle.Left(), aWallpaperRectangle.Top(),
+ aWallpaperRectangle.Right(), aWallpaperRectangle.Bottom());
+
+ if(WALLPAPER_NULL != eWallpaperStyle)
+ {
+ if(rWallpaper.IsBitmap())
+ {
+ // create bitmap background. Caution: This
+ // also will create gradient/color background(s)
+ // when the bitmap is transparent or not tiled
+ CreateAndAppendBitmapWallpaper(
+ aWallpaperRange,
+ rWallpaper,
+ rTargetHolders.Current(),
+ rPropertyHolders.Current());
+ }
+ else if(rWallpaper.IsGradient())
+ {
+ // create gradient background
+ rTargetHolders.Current().append(
+ CreateGradientWallpaper(
+ aWallpaperRange,
+ rWallpaper.GetGradient(),
+ rPropertyHolders.Current()));
+ }
+ else if(!rWallpaper.GetColor().GetTransparency())
+ {
+ // create color background
+ rTargetHolders.Current().append(
+ CreateColorWallpaper(
+ aWallpaperRange,
+ rWallpaper.GetColor().getBColor(),
+ rPropertyHolders.Current()));
+ }
+ }
+ }
+
+ break;
+ }
+ case META_CLIPREGION_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ const MetaClipRegionAction* pA = (const MetaClipRegionAction*)pAction;
+
+ if(pA->IsClipping())
+ {
+ // new clipping. Get PolyPolygon and transform with current transformation
+ basegfx::B2DPolyPolygon aNewClipPolyPolygon(getB2DPolyPolygonFromRegion(pA->GetRegion()));
+
+ aNewClipPolyPolygon.transform(rPropertyHolders.Current().getTransformation());
+ HandleNewClipRegion(aNewClipPolyPolygon, rTargetHolders, rPropertyHolders);
+ }
+ else
+ {
+ // end clipping
+ const basegfx::B2DPolyPolygon aEmptyPolyPolygon;
+
+ HandleNewClipRegion(aEmptyPolyPolygon, rTargetHolders, rPropertyHolders);
+ }
+
+ break;
+ }
+ case META_ISECTRECTCLIPREGION_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ const MetaISectRectClipRegionAction* pA = (const MetaISectRectClipRegionAction*)pAction;
+ const Rectangle& rRectangle = pA->GetRect();
+
+ if(rRectangle.IsEmpty())
+ {
+ // intersect with empty rectangle will always give empty
+ // ClipPolyPolygon; start new clipping with empty PolyPolygon
+ const basegfx::B2DPolyPolygon aEmptyPolyPolygon;
+
+ HandleNewClipRegion(aEmptyPolyPolygon, rTargetHolders, rPropertyHolders);
+ }
+ else
+ {
+ // create transformed ClipRange
+ basegfx::B2DRange aClipRange(
+ rRectangle.Left(), rRectangle.Top(),
+ rRectangle.Right(), rRectangle.Bottom());
+
+ aClipRange.transform(rPropertyHolders.Current().getTransformation());
+
+ if(rPropertyHolders.Current().getClipPolyPolygonActive())
+ {
+ if(0 == rPropertyHolders.Current().getClipPolyPolygon().count())
+ {
+ // nothing to do, empty active clipPolyPolygon will stay
+ // empty when intersecting
+ }
+ else
+ {
+ // AND existing region and new ClipRange
+ const basegfx::B2DPolyPolygon aOriginalPolyPolygon(
+ rPropertyHolders.Current().getClipPolyPolygon());
+ basegfx::B2DPolyPolygon aClippedPolyPolygon;
+
+ if(aOriginalPolyPolygon.count())
+ {
+ aClippedPolyPolygon = basegfx::tools::clipPolyPolygonOnRange(
+ aOriginalPolyPolygon,
+ aClipRange,
+ true,
+ false);
+ }
+
+ if(aClippedPolyPolygon != aOriginalPolyPolygon)
+ {
+ // start new clipping with intersected region
+ HandleNewClipRegion(
+ aClippedPolyPolygon,
+ rTargetHolders,
+ rPropertyHolders);
+ }
+ }
+ }
+ else
+ {
+ // start new clipping with ClipRange
+ const basegfx::B2DPolyPolygon aNewClipPolyPolygon(
+ basegfx::tools::createPolygonFromRect(aClipRange));
+
+ HandleNewClipRegion(aNewClipPolyPolygon, rTargetHolders, rPropertyHolders);
+ }
+ }
+
+ break;
+ }
+ case META_ISECTREGIONCLIPREGION_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ const MetaISectRegionClipRegionAction* pA = (const MetaISectRegionClipRegionAction*)pAction;
+ const Region& rNewRegion = pA->GetRegion();
+
+ if(rNewRegion.IsEmpty())
+ {
+ // intersect with empty region will always give empty
+ // region; start new clipping with empty PolyPolygon
+ const basegfx::B2DPolyPolygon aEmptyPolyPolygon;
+
+ HandleNewClipRegion(aEmptyPolyPolygon, rTargetHolders, rPropertyHolders);
+ }
+ else
+ {
+ // get new ClipPolyPolygon, transform it with current transformation
+ basegfx::B2DPolyPolygon aNewClipPolyPolygon(getB2DPolyPolygonFromRegion(rNewRegion));
+ aNewClipPolyPolygon.transform(rPropertyHolders.Current().getTransformation());
+
+ if(rPropertyHolders.Current().getClipPolyPolygonActive())
+ {
+ if(0 == rPropertyHolders.Current().getClipPolyPolygon().count())
+ {
+ // nothing to do, empty active clipPolyPolygon will stay empty
+ // when intersecting with any region
+ }
+ else
+ {
+ // AND existing and new region
+ const basegfx::B2DPolyPolygon aOriginalPolyPolygon(
+ rPropertyHolders.Current().getClipPolyPolygon());
+ basegfx::B2DPolyPolygon aClippedPolyPolygon;
+
+ if(aOriginalPolyPolygon.count())
+ {
+ aClippedPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon(
+ aOriginalPolyPolygon, aNewClipPolyPolygon, true, false);
+ }
+
+ if(aClippedPolyPolygon != aOriginalPolyPolygon)
+ {
+ // start new clipping with intersected ClipPolyPolygon
+ HandleNewClipRegion(aClippedPolyPolygon, rTargetHolders, rPropertyHolders);
+ }
+ }
+ }
+ else
+ {
+ // start new clipping with new ClipPolyPolygon
+ HandleNewClipRegion(aNewClipPolyPolygon, rTargetHolders, rPropertyHolders);
+ }
+ }
+
+ break;
+ }
+ case META_MOVECLIPREGION_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ const MetaMoveClipRegionAction* pA = (const MetaMoveClipRegionAction*)pAction;
+
+ if(rPropertyHolders.Current().getClipPolyPolygonActive())
+ {
+ if(0 == rPropertyHolders.Current().getClipPolyPolygon().count())
+ {
+ // nothing to do
+ }
+ else
+ {
+ const sal_Int32 nHor(pA->GetHorzMove());
+ const sal_Int32 nVer(pA->GetVertMove());
+
+ if(0 != nHor || 0 != nVer)
+ {
+ // prepare translation, add current transformation
+ basegfx::B2DVector aVector(pA->GetHorzMove(), pA->GetVertMove());
+ aVector *= rPropertyHolders.Current().getTransformation();
+ basegfx::B2DHomMatrix aTransform(
+ basegfx::tools::createTranslateB2DHomMatrix(aVector));
+
+ // transform existing region
+ basegfx::B2DPolyPolygon aClipPolyPolygon(
+ rPropertyHolders.Current().getClipPolyPolygon());
+
+ aClipPolyPolygon.transform(aTransform);
+ HandleNewClipRegion(aClipPolyPolygon, rTargetHolders, rPropertyHolders);
+ }
+ }
+ }
+
+ break;
+ }
+ case META_LINECOLOR_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ const MetaLineColorAction* pA = (const MetaLineColorAction*)pAction;
+ const bool bActive(pA->IsSetting());
+
+ rPropertyHolders.Current().setLineColorActive(bActive);
+ if(bActive)
+ rPropertyHolders.Current().setLineColor(pA->GetColor().getBColor());
+
+ break;
+ }
+ case META_FILLCOLOR_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ const MetaFillColorAction* pA = (const MetaFillColorAction*)pAction;
+ const bool bActive(pA->IsSetting());
+
+ rPropertyHolders.Current().setFillColorActive(bActive);
+ if(bActive)
+ rPropertyHolders.Current().setFillColor(pA->GetColor().getBColor());
+
+ break;
+ }
+ case META_TEXTCOLOR_ACTION :
+ {
+ /** SIMPLE, DONE */
+ const MetaTextColorAction* pA = (const MetaTextColorAction*)pAction;
+ const bool bActivate(COL_TRANSPARENT != pA->GetColor().GetColor());
+
+ rPropertyHolders.Current().setTextColorActive(bActivate);
+ rPropertyHolders.Current().setTextColor(pA->GetColor().getBColor());
+
+ break;
+ }
+ case META_TEXTFILLCOLOR_ACTION :
+ {
+ /** SIMPLE, DONE */
+ const MetaTextFillColorAction* pA = (const MetaTextFillColorAction*)pAction;
+ const bool bWithColorArgument(pA->IsSetting());
+
+ if(bWithColorArgument)
+ {
+ // emulate OutputDevice::SetTextFillColor(...) WITH argument
+ const Color& rFontFillColor = pA->GetColor();
+ rPropertyHolders.Current().setTextFillColor(rFontFillColor.getBColor());
+ rPropertyHolders.Current().setTextFillColorActive(COL_TRANSPARENT != rFontFillColor.GetColor());
+ }
+ else
+ {
+ // emulate SetFillColor() <- NO argument (!)
+ rPropertyHolders.Current().setTextFillColorActive(false);
+ }
+
+ break;
+ }
+ case META_TEXTALIGN_ACTION :
+ {
+ /** SIMPLE, DONE */
+ const MetaTextAlignAction* pA = (const MetaTextAlignAction*)pAction;
+ const TextAlign aNewTextAlign = pA->GetTextAlign();
+
+ // TextAlign is applied to the current font (as in
+ // OutputDevice::SetTextAlign which would be used when
+ // playing the Metafile)
+ if(rPropertyHolders.Current().getFont().GetAlign() != aNewTextAlign)
+ {
+ Font aNewFont(rPropertyHolders.Current().getFont());
+ aNewFont.SetAlign(aNewTextAlign);
+ rPropertyHolders.Current().setFont(aNewFont);
+ }
+
+ break;
+ }
+ case META_MAPMODE_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ // the most necessary MapMode to be interpreted is MAP_RELATIVE,
+ // but also the others may occur. Even not yet supported ones
+ // may need to be added here later
+ const MetaMapModeAction* pA = (const MetaMapModeAction*)pAction;
+ const MapMode& rMapMode = pA->GetMapMode();
+ basegfx::B2DHomMatrix aMapping;
+
+ if(MAP_RELATIVE == rMapMode.GetMapUnit())
+ {
+ aMapping = getTransformFromMapMode(rMapMode);
+ }
+ else
+ {
+ switch(rMapMode.GetMapUnit())
+ {
+ case MAP_100TH_MM :
+ {
+ if(MAP_TWIP == rPropertyHolders.Current().getMapUnit())
+ {
+ // MAP_TWIP -> MAP_100TH_MM
+ const double fTwipTo100thMm(127.0 / 72.0);
+ aMapping.scale(fTwipTo100thMm, fTwipTo100thMm);
+ }
+ break;
+ }
+ case MAP_TWIP :
+ {
+ if(MAP_100TH_MM == rPropertyHolders.Current().getMapUnit())
+ {
+ // MAP_100TH_MM -> MAP_TWIP
+ const double f100thMmToTwip(72.0 / 127.0);
+ aMapping.scale(f100thMmToTwip, f100thMmToTwip);
+ }
+ break;
+ }
+ default :
+ {
+ OSL_ENSURE(false, "interpretMetafile: META_MAPMODE_ACTION with unsupported MapUnit (!)");
+ break;
+ }
+ }
+
+ aMapping = getTransformFromMapMode(rMapMode) * aMapping;
+ rPropertyHolders.Current().setMapUnit(rMapMode.GetMapUnit());
+ }
+
+ if(!aMapping.isIdentity())
+ {
+ aMapping = aMapping * rPropertyHolders.Current().getTransformation();
+ rPropertyHolders.Current().setTransformation(aMapping);
+ }
+
+ break;
+ }
+ case META_FONT_ACTION :
+ {
+ /** SIMPLE, DONE */
+ const MetaFontAction* pA = (const MetaFontAction*)pAction;
+ rPropertyHolders.Current().setFont(pA->GetFont());
+ Size aFontSize(pA->GetFont().GetSize());
+
+ if(0 == aFontSize.Height())
+ {
+ // this should not happen but i got Metafiles where this was the
+ // case. A height needs to be guessed (similar to OutputDevice::ImplNewFont())
+ Font aCorrectedFont(pA->GetFont());
+
+ // guess 16 pixel (as in VCL)
+ aFontSize = Size(0, 16);
+
+ // convert to target MapUnit if not pixels
+ aFontSize = Application::GetDefaultDevice()->LogicToLogic(
+ aFontSize, MAP_PIXEL, rPropertyHolders.Current().getMapUnit());
+
+ aCorrectedFont.SetSize(aFontSize);
+ rPropertyHolders.Current().setFont(aCorrectedFont);
+ }
+
+ // older Metafiles have no META_TEXTCOLOR_ACTION which defines
+ // the FontColor now, so use the Font's color when not transparent
+ const Color& rFontColor = pA->GetFont().GetColor();
+ const bool bActivate(COL_TRANSPARENT != rFontColor.GetColor());
+
+ if(bActivate)
+ {
+ rPropertyHolders.Current().setTextColor(rFontColor.getBColor());
+ }
+
+ // caution: do NOT decativate here on transparet, see
+ // OutputDevice::SetFont(..) for more info
+ // rPropertyHolders.Current().setTextColorActive(bActivate);
+
+ // for fill color emulate a MetaTextFillColorAction with !transparent as bool,
+ // see OutputDevice::SetFont(..) the if(mpMetaFile) case
+ if(bActivate)
+ {
+ const Color& rFontFillColor = pA->GetFont().GetFillColor();
+ rPropertyHolders.Current().setTextFillColor(rFontFillColor.getBColor());
+ rPropertyHolders.Current().setTextFillColorActive(COL_TRANSPARENT != rFontFillColor.GetColor());
+ }
+ else
+ {
+ rPropertyHolders.Current().setTextFillColorActive(false);
+ }
+
+ break;
+ }
+ case META_PUSH_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ const MetaPushAction* pA = (const MetaPushAction*)pAction;
+ rPropertyHolders.Push(pA->GetFlags());
+
+ break;
+ }
+ case META_POP_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ const bool bRegionMayChange(rPropertyHolders.Current().getPushFlags() & PUSH_CLIPREGION);
+ const bool bRasterOpMayChange(rPropertyHolders.Current().getPushFlags() & PUSH_RASTEROP);
+
+ if(bRegionMayChange && rPropertyHolders.Current().getClipPolyPolygonActive())
+ {
+ // end evtl. clipping
+ const basegfx::B2DPolyPolygon aEmptyPolyPolygon;
+
+ HandleNewClipRegion(aEmptyPolyPolygon, rTargetHolders, rPropertyHolders);
+ }
+
+ if(bRasterOpMayChange && rPropertyHolders.Current().isRasterOpActive())
+ {
+ // end evtl. RasterOp
+ HandleNewRasterOp(ROP_OVERPAINT, rTargetHolders, rPropertyHolders);
+ }
+
+ rPropertyHolders.Pop();
+
+ if(bRasterOpMayChange && rPropertyHolders.Current().isRasterOpActive())
+ {
+ // start evtl. RasterOp
+ HandleNewRasterOp(rPropertyHolders.Current().getRasterOp(), rTargetHolders, rPropertyHolders);
+ }
+
+ if(bRegionMayChange && rPropertyHolders.Current().getClipPolyPolygonActive())
+ {
+ // start evtl. clipping
+ HandleNewClipRegion(
+ rPropertyHolders.Current().getClipPolyPolygon(), rTargetHolders, rPropertyHolders);
+ }
+
+ break;
+ }
+ case META_RASTEROP_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ const MetaRasterOpAction* pA = (const MetaRasterOpAction*)pAction;
+ const RasterOp aRasterOp = pA->GetRasterOp();
+
+ HandleNewRasterOp(aRasterOp, rTargetHolders, rPropertyHolders);
+
+ break;
+ }
+ case META_TRANSPARENT_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ const MetaTransparentAction* pA = (const MetaTransparentAction*)pAction;
+ const basegfx::B2DPolyPolygon aOutline(pA->GetPolyPolygon().getB2DPolyPolygon());
+
+ if(aOutline.count())
+ {
+ const sal_uInt16 nTransparence(pA->GetTransparence());
+
+ if(0 == nTransparence)
+ {
+ // not transparent
+ createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
+ }
+ else if(nTransparence >= 100)
+ {
+ // fully or more than transparent
+ }
+ else
+ {
+ // transparent. Create new target
+ rTargetHolders.Push();
+
+ // create primitives there and get them
+ createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
+ const drawinglayer::primitive2d::Primitive2DSequence aSubContent(
+ rTargetHolders.Current().getPrimitive2DSequence(rPropertyHolders.Current()));
+
+ // back to old target
+ rTargetHolders.Pop();
+
+ if(aSubContent.hasElements())
+ {
+ rTargetHolders.Current().append(
+ new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
+ aSubContent,
+ nTransparence * 0.01));
+ }
+ }
+ }
+
+ break;
+ }
+ case META_EPS_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ // To support this action, i have added a EpsPrimitive2D which will
+ // by default decompose to the Metafile replacement data. To support
+ // this EPS on screen, the renderer visualizing this has to support
+ // that primitive and visualize the Eps file (e.g. printing)
+ const MetaEPSAction* pA = (const MetaEPSAction*)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::EpsPrimitive2D(
+ aObjectTransform,
+ pA->GetLink(),
+ pA->GetSubstitute()));
+ }
+
+ break;
+ }
+ case META_REFPOINT_ACTION :
+ {
+ /** SIMPLE, DONE */
+ // only used for hatch and line pattern offsets, pretty much no longer
+ // supported today
+ // const MetaRefPointAction* pA = (const MetaRefPointAction*)pAction;
+ break;
+ }
+ case META_TEXTLINECOLOR_ACTION :
+ {
+ /** SIMPLE, DONE */
+ const MetaTextLineColorAction* pA = (const MetaTextLineColorAction*)pAction;
+ const bool bActive(pA->IsSetting());
+
+ rPropertyHolders.Current().setTextLineColorActive(bActive);
+ if(bActive)
+ rPropertyHolders.Current().setTextLineColor(pA->GetColor().getBColor());
+
+ break;
+ }
+ case META_TEXTLINE_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ // actually creates overline, underline and strikeouts, so
+ // these should be isolated from TextDecoratedPortionPrimitive2D
+ // to own primitives. Done, available now.
+ //
+ // This Metaaction seems not to be used (was not used in any
+ // checked files). It's used in combination with the current
+ // Font.
+ const MetaTextLineAction* pA = (const MetaTextLineAction*)pAction;
+
+ proccessMetaTextLineAction(
+ *pA,
+ rTargetHolders.Current(),
+ rPropertyHolders.Current());
+
+ break;
+ }
+ case META_FLOATTRANSPARENT_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ const MetaFloatTransparentAction* pA = (const MetaFloatTransparentAction*)pAction;
+ const Rectangle aTargetRectangle(pA->GetPoint(), pA->GetSize());
+
+ if(!aTargetRectangle.IsEmpty())
+ {
+ const GDIMetaFile& rContent = pA->GetGDIMetaFile();
+
+ if(rContent.GetActionCount())
+ {
+ // create the sub-content with no embedding specific to the
+ // sub-metafile, this seems not to be used.
+ drawinglayer::primitive2d::Primitive2DSequence xSubContent;
+ {
+ rTargetHolders.Push();
+ // #i# for sub-Mteafile contents, do start with new, default render state
+ rPropertyHolders.PushDefault();
+ interpretMetafile(rContent, rTargetHolders, rPropertyHolders, rViewInformation);
+ xSubContent = rTargetHolders.Current().getPrimitive2DSequence(rPropertyHolders.Current());
+ rPropertyHolders.Pop();
+ rTargetHolders.Pop();
+ }
+
+ if(xSubContent.hasElements())
+ {
+ // check if gradient is a real gradient
+ const Gradient& rGradient = pA->GetGradient();
+ const drawinglayer::attribute::FillGradientAttribute aAttribute(createFillGradientAttribute(rGradient));
+
+ if(aAttribute.getStartColor() == aAttribute.getEndColor())
+ {
+ // not really a gradient; create UnifiedTransparencePrimitive2D
+ rTargetHolders.Current().append(
+ new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
+ xSubContent,
+ aAttribute.getStartColor().luminance()));
+ }
+ else
+ {
+ // really a gradient. Create gradient sub-content (with correct scaling)
+ basegfx::B2DRange aRange(
+ aTargetRectangle.Left(), aTargetRectangle.Top(),
+ aTargetRectangle.Right(), aTargetRectangle.Bottom());
+ aRange.transform(rPropertyHolders.Current().getTransformation());
+
+ // prepare gradient for transparent content
+ const drawinglayer::primitive2d::Primitive2DReference xTransparence(
+ new drawinglayer::primitive2d::FillGradientPrimitive2D(
+ aRange,
+ aAttribute));
+
+ // create transparence primitive
+ rTargetHolders.Current().append(
+ new drawinglayer::primitive2d::TransparencePrimitive2D(
+ xSubContent,
+ drawinglayer::primitive2d::Primitive2DSequence(&xTransparence, 1)));
+ }
+ }
+ }
+ }
+
+ break;
+ }
+ case META_GRADIENTEX_ACTION :
+ {
+ /** SIMPLE, DONE */
+ // This is only a data holder which is interpreted inside comment actions,
+ // see META_COMMENT_ACTION for more info
+ // const MetaGradientExAction* pA = (const MetaGradientExAction*)pAction;
+ break;
+ }
+ case META_LAYOUTMODE_ACTION :
+ {
+ /** SIMPLE, DONE */
+ const MetaLayoutModeAction* pA = (const MetaLayoutModeAction*)pAction;
+ rPropertyHolders.Current().setLayoutMode(pA->GetLayoutMode());
+ break;
+ }
+ case META_TEXTLANGUAGE_ACTION :
+ {
+ /** SIMPLE, DONE */
+ const MetaTextLanguageAction* pA = (const MetaTextLanguageAction*)pAction;
+ rPropertyHolders.Current().setLanguageType(pA->GetTextLanguage());
+ break;
+ }
+ case META_OVERLINECOLOR_ACTION :
+ {
+ /** SIMPLE, DONE */
+ const MetaOverlineColorAction* pA = (const MetaOverlineColorAction*)pAction;
+ const bool bActive(pA->IsSetting());
+
+ rPropertyHolders.Current().setOverlineColorActive(bActive);
+ if(bActive)
+ rPropertyHolders.Current().setOverlineColor(pA->GetColor().getBColor());
+
+ break;
+ }
+ case META_COMMENT_ACTION :
+ {
+ /** CHECKED, WORKS WELL */
+ // I already implemented
+ // XPATHFILL_SEQ_BEGIN, XPATHFILL_SEQ_END
+ // XPATHSTROKE_SEQ_BEGIN, XPATHSTROKE_SEQ_END,
+ // but opted to remove these again; it works well without them
+ // and makes the code less dependent from those Metafile Add-Ons
+ const MetaCommentAction* pA = (const MetaCommentAction*)pAction;
+
+ if(COMPARE_EQUAL == pA->GetComment().CompareIgnoreCaseToAscii("XGRAD_SEQ_BEGIN"))
+ {
+ // XGRAD_SEQ_BEGIN, XGRAD_SEQ_END should be supported since the
+ // pure recorded paint of the gradients uses the XOR paint functionality
+ // ('trick'). This is (and will be) broblematic with AntAliasing, so it's
+ // better to use this info
+ const MetaGradientExAction* pMetaGradientExAction = 0;
+ bool bDone(false);
+ sal_uInt32 b(nAction + 1);
+
+ for(; !bDone && b < nCount; b++)
+ {
+ pAction = rMetaFile.GetAction(b);
+
+ if(META_GRADIENTEX_ACTION == pAction->GetType())
+ {
+ pMetaGradientExAction = (const MetaGradientExAction*)pAction;
+ }
+ else if(META_COMMENT_ACTION == pAction->GetType())
+ {
+ if(COMPARE_EQUAL == ((const MetaCommentAction*)pAction)->GetComment().CompareIgnoreCaseToAscii("XGRAD_SEQ_END"))
+ {
+ bDone = true;
+ }
+ }
+ }
+
+ if(bDone && pMetaGradientExAction)
+ {
+ // consume actions and skip forward
+ nAction = b - 1;
+
+ // get geometry data
+ basegfx::B2DPolyPolygon aPolyPolygon(pMetaGradientExAction->GetPolyPolygon().getB2DPolyPolygon());
+
+ if(aPolyPolygon.count())
+ {
+ // transform geometry
+ aPolyPolygon.transform(rPropertyHolders.Current().getTransformation());
+
+ // get and check if gradient is a real gradient
+ const Gradient& rGradient = pMetaGradientExAction->GetGradient();
+ const drawinglayer::attribute::FillGradientAttribute aAttribute(createFillGradientAttribute(rGradient));
+
+ if(aAttribute.getStartColor() == aAttribute.getEndColor())
+ {
+ // not really a gradient
+ rTargetHolders.Current().append(
+ new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
+ aPolyPolygon,
+ aAttribute.getStartColor()));
+ }
+ else
+ {
+ // really a gradient
+ rTargetHolders.Current().append(
+ new drawinglayer::primitive2d::PolyPolygonGradientPrimitive2D(
+ aPolyPolygon,
+ aAttribute));
+ }
+ }
+ }
+ }
+
+ break;
+ }
+ default:
+ {
+ OSL_ENSURE(false, "Unknown MetaFile Action (!)");
+ break;
+ }
+ }
+ }
+ }
+} // end of anonymous namespace
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence MetafilePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ // prepare target and porperties; each will have one default entry
+ TargetHolders aTargetHolders;
+ PropertyHolders aPropertyHolders;
+
+ // set target MapUnit at Properties
+ aPropertyHolders.Current().setMapUnit(getMetaFile().GetPrefMapMode().GetMapUnit());
+
+ // interpret the Metafile
+ interpretMetafile(getMetaFile(), aTargetHolders, aPropertyHolders, rViewInformation);
+
+ // get the content. There should be ony one target, as in the start condition,
+ // but iterating will be the right thing to do when some push/pop is not closed
+ Primitive2DSequence xRetval;
+
+ while(aTargetHolders.size() > 1)
+ {
+ appendPrimitive2DSequenceToPrimitive2DSequence(xRetval,
+ aTargetHolders.Current().getPrimitive2DSequence(aPropertyHolders.Current()));
+ aTargetHolders.Pop();
+ }
+
+ appendPrimitive2DSequenceToPrimitive2DSequence(xRetval,
+ aTargetHolders.Current().getPrimitive2DSequence(aPropertyHolders.Current()));
+
+ if(xRetval.hasElements())
+ {
+ // get target size
+ const Rectangle aMtfTarget(getMetaFile().GetPrefMapMode().GetOrigin(), getMetaFile().GetPrefSize());
+
+ // create transformation
+ basegfx::B2DHomMatrix aAdaptedTransform;
+
+ aAdaptedTransform.translate(-aMtfTarget.Left(), -aMtfTarget.Top());
+ aAdaptedTransform.scale(
+ aMtfTarget.getWidth() ? 1.0 / aMtfTarget.getWidth() : 1.0,
+ aMtfTarget.getHeight() ? 1.0 / aMtfTarget.getHeight() : 1.0);
+ aAdaptedTransform = getTransform() * aAdaptedTransform;
+
+ // embed to target transformation
+ const Primitive2DReference aEmbeddedTransform(
+ new TransformPrimitive2D(
+ aAdaptedTransform,
+ xRetval));
+
+ xRetval = Primitive2DSequence(&aEmbeddedTransform, 1);
+ }
+
+ return xRetval;
+ }
+
+ MetafilePrimitive2D::MetafilePrimitive2D(
+ const basegfx::B2DHomMatrix& rMetaFileTransform,
+ const GDIMetaFile& rMetaFile)
+ : BufferedDecompositionPrimitive2D(),
+ maMetaFileTransform(rMetaFileTransform),
+ maMetaFile(rMetaFile)
+ {
+ }
+
+ bool MetafilePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const MetafilePrimitive2D& rCompare = (MetafilePrimitive2D&)rPrimitive;
+
+ return (getTransform() == rCompare.getTransform()
+ && getMetaFile() == rCompare.getMetaFile());
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange MetafilePrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ // use own implementation to quickly answer the getB2DRange question. The
+ // MetafilePrimitive2D assumes that all geometry is inside of the shape. If
+ // this is not the case (i have already seen some wrong Metafiles) it should
+ // be embedded to a MaskPrimitive2D
+ basegfx::B2DRange aRetval(0.0, 0.0, 1.0, 1.0);
+ aRetval.transform(getTransform());
+
+ return aRetval;
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(MetafilePrimitive2D, PRIMITIVE2D_ID_METAFILEPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/modifiedcolorprimitive2d.cxx b/drawinglayer/source/primitive2d/modifiedcolorprimitive2d.cxx
new file mode 100644
index 000000000000..d43403be1409
--- /dev/null
+++ b/drawinglayer/source/primitive2d/modifiedcolorprimitive2d.cxx
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ ModifiedColorPrimitive2D::ModifiedColorPrimitive2D(
+ const Primitive2DSequence& rChildren,
+ const basegfx::BColorModifier& rColorModifier)
+ : GroupPrimitive2D(rChildren),
+ maColorModifier(rColorModifier)
+ {
+ }
+
+ bool ModifiedColorPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(GroupPrimitive2D::operator==(rPrimitive))
+ {
+ const ModifiedColorPrimitive2D& rCompare = (ModifiedColorPrimitive2D&)rPrimitive;
+
+ return (getColorModifier() == rCompare.getColorModifier());
+ }
+
+ return false;
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(ModifiedColorPrimitive2D, PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/pagepreviewprimitive2d.cxx b/drawinglayer/source/primitive2d/pagepreviewprimitive2d.cxx
new file mode 100644
index 000000000000..e28f5debcbfd
--- /dev/null
+++ b/drawinglayer/source/primitive2d/pagepreviewprimitive2d.cxx
@@ -0,0 +1,186 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence PagePreviewPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ Primitive2DSequence xRetval;
+ Primitive2DSequence aContent(getPageContent());
+
+ if(aContent.hasElements()
+ && basegfx::fTools::more(getContentWidth(), 0.0)
+ && basegfx::fTools::more(getContentHeight(), 0.0))
+ {
+ // the decomposed matrix will be needed
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ getTransform().decompose(aScale, aTranslate, fRotate, fShearX);
+
+ if(basegfx::fTools::more(aScale.getX(), 0.0) && basegfx::fTools::more(aScale.getY(), 0.0))
+ {
+ // check if content overlaps with tageted size and needs to be embedded with a
+ // clipping primitive
+ const basegfx::B2DRange aRealContentRange(getB2DRangeFromPrimitive2DSequence(aContent, rViewInformation));
+ const basegfx::B2DRange aAllowedContentRange(0.0, 0.0, getContentWidth(), getContentHeight());
+
+ if(!aAllowedContentRange.isInside(aRealContentRange))
+ {
+ const Primitive2DReference xReferenceA(
+ new MaskPrimitive2D(
+ basegfx::B2DPolyPolygon(
+ basegfx::tools::createPolygonFromRect(aAllowedContentRange)), aContent));
+ aContent = Primitive2DSequence(&xReferenceA, 1);
+ }
+
+ // create a mapping from content to object.
+ basegfx::B2DHomMatrix aPageTrans;
+
+ if(getKeepAspectRatio())
+ {
+ // #i101075# when keeping the aspect ratio is wanted, it is necessary to calculate
+ // an equidistant scaling in X and Y and a corresponding translation to
+ // center the output. Calculate needed scale factors
+ const double fScaleX(aScale.getX() / getContentWidth());
+ const double fScaleY(aScale.getY() / getContentHeight());
+
+ // to keep the aspect, use the smaller scale and adapt missing size by translation
+ if(fScaleX < fScaleY)
+ {
+ // height needs to be adapted
+ const double fNeededHeight(aScale.getY() / fScaleX);
+ const double fSpaceToAdd(fNeededHeight - getContentHeight());
+
+ aPageTrans.translate(0.0, fSpaceToAdd * 0.5);
+ aPageTrans.scale(fScaleX, aScale.getY() / fNeededHeight);
+ }
+ else
+ {
+ // width needs to be adapted
+ const double fNeededWidth(aScale.getX() / fScaleY);
+ const double fSpaceToAdd(fNeededWidth - getContentWidth());
+
+ aPageTrans.translate(fSpaceToAdd * 0.5, 0.0);
+ aPageTrans.scale(aScale.getX() / fNeededWidth, fScaleY);
+ }
+
+ // add the missing object transformation aspects
+ const basegfx::B2DHomMatrix aCombined(basegfx::tools::createShearXRotateTranslateB2DHomMatrix(
+ fShearX, fRotate, aTranslate.getX(), aTranslate.getY()));
+ aPageTrans = aCombined * aPageTrans;
+ }
+ else
+ {
+ // completely scale to PageObject size. Scale to unit size.
+ aPageTrans.scale(1.0/ getContentWidth(), 1.0 / getContentHeight());
+
+ // apply object matrix
+ aPageTrans *= getTransform();
+ }
+
+ // embed in necessary transformation to map from SdrPage to SdrPageObject
+ const Primitive2DReference xReferenceB(new TransformPrimitive2D(aPageTrans, aContent));
+ xRetval = Primitive2DSequence(&xReferenceB, 1);
+ }
+ }
+
+ return xRetval;
+ }
+
+ PagePreviewPrimitive2D::PagePreviewPrimitive2D(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XDrawPage >& rxDrawPage,
+ const basegfx::B2DHomMatrix& rTransform,
+ double fContentWidth,
+ double fContentHeight,
+ const Primitive2DSequence& rPageContent,
+ bool bKeepAspectRatio)
+ : BufferedDecompositionPrimitive2D(),
+ mxDrawPage(rxDrawPage),
+ maPageContent(rPageContent),
+ maTransform(rTransform),
+ mfContentWidth(fContentWidth),
+ mfContentHeight(fContentHeight),
+ mbKeepAspectRatio(bKeepAspectRatio)
+ {
+ }
+
+ bool PagePreviewPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BasePrimitive2D::operator==(rPrimitive))
+ {
+ const PagePreviewPrimitive2D& rCompare = static_cast< const PagePreviewPrimitive2D& >(rPrimitive);
+
+ return (getXDrawPage() == rCompare.getXDrawPage()
+ && getPageContent() == rCompare.getPageContent()
+ && getTransform() == rCompare.getTransform()
+ && getContentWidth() == rCompare.getContentWidth()
+ && getContentHeight() == rCompare.getContentHeight()
+ && getKeepAspectRatio() == rCompare.getKeepAspectRatio());
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange PagePreviewPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation`*/) const
+ {
+ // nothing is allowed to stick out of a PagePreviewPrimitive, thus we
+ // can quickly deliver our range here
+ basegfx::B2DRange aRetval(0.0, 0.0, 1.0, 1.0);
+ aRetval.transform(getTransform());
+ return aRetval;
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(PagePreviewPrimitive2D, PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/pointarrayprimitive2d.cxx b/drawinglayer/source/primitive2d/pointarrayprimitive2d.cxx
new file mode 100644
index 000000000000..df508d4a6377
--- /dev/null
+++ b/drawinglayer/source/primitive2d/pointarrayprimitive2d.cxx
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ PointArrayPrimitive2D::PointArrayPrimitive2D(
+ const std::vector< basegfx::B2DPoint >& rPositions,
+ const basegfx::BColor& rRGBColor)
+ : BasePrimitive2D(),
+ maPositions(rPositions),
+ maRGBColor(rRGBColor),
+ maB2DRange()
+ {
+ }
+
+ bool PointArrayPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BasePrimitive2D::operator==(rPrimitive))
+ {
+ const PointArrayPrimitive2D& rCompare = (PointArrayPrimitive2D&)rPrimitive;
+
+ return (getPositions() == rCompare.getPositions()
+ && getRGBColor() == rCompare.getRGBColor());
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange PointArrayPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ if(maB2DRange.isEmpty())
+ {
+ basegfx::B2DRange aNewRange;
+
+ // get the basic range from the position vector
+ for(std::vector< basegfx::B2DPoint >::const_iterator aIter(getPositions().begin()); aIter != getPositions().end(); aIter++)
+ {
+ aNewRange.expand(*aIter);
+ }
+
+ // assign to buffered value
+ const_cast< PointArrayPrimitive2D* >(this)->maB2DRange = aNewRange;
+ }
+
+ return maB2DRange;
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(PointArrayPrimitive2D, PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/polygonprimitive2d.cxx b/drawinglayer/source/primitive2d/polygonprimitive2d.cxx
new file mode 100644
index 000000000000..79a280f00df4
--- /dev/null
+++ b/drawinglayer/source/primitive2d/polygonprimitive2d.cxx
@@ -0,0 +1,642 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
+#include <basegfx/tools/canvastools.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <basegfx/polygon/b2dlinegeometry.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ PolygonHairlinePrimitive2D::PolygonHairlinePrimitive2D(
+ const basegfx::B2DPolygon& rPolygon,
+ const basegfx::BColor& rBColor)
+ : BasePrimitive2D(),
+ maPolygon(rPolygon),
+ maBColor(rBColor)
+ {
+ }
+
+ bool PolygonHairlinePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BasePrimitive2D::operator==(rPrimitive))
+ {
+ const PolygonHairlinePrimitive2D& rCompare = (PolygonHairlinePrimitive2D&)rPrimitive;
+
+ return (getB2DPolygon() == rCompare.getB2DPolygon()
+ && getBColor() == rCompare.getBColor());
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange PolygonHairlinePrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ // this is a hairline, thus the line width is view-dependent. Get range of polygon
+ // as base size
+ basegfx::B2DRange aRetval(getB2DPolygon().getB2DRange());
+
+ if(!aRetval.isEmpty())
+ {
+ // Calculate view-dependent hairline width
+ const basegfx::B2DVector aDiscreteSize(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 0.0));
+ const double fDiscreteHalfLineWidth(aDiscreteSize.getLength() * 0.5);
+
+ if(basegfx::fTools::more(fDiscreteHalfLineWidth, 0.0))
+ {
+ aRetval.grow(fDiscreteHalfLineWidth);
+ }
+ }
+
+ // return range
+ return aRetval;
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(PolygonHairlinePrimitive2D, PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence PolygonMarkerPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ // calculate logic DashLength
+ const basegfx::B2DVector aDashVector(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(getDiscreteDashLength(), 0.0));
+ const double fLogicDashLength(aDashVector.getX());
+
+ if(fLogicDashLength > 0.0 && !getRGBColorA().equal(getRGBColorB()))
+ {
+ // apply dashing; get line and gap snippets
+ ::std::vector< double > aDash;
+ basegfx::B2DPolyPolygon aDashedPolyPolyA;
+ basegfx::B2DPolyPolygon aDashedPolyPolyB;
+
+ aDash.push_back(fLogicDashLength);
+ aDash.push_back(fLogicDashLength);
+ basegfx::tools::applyLineDashing(getB2DPolygon(), aDash, &aDashedPolyPolyA, &aDashedPolyPolyB, 2.0 * fLogicDashLength);
+
+ // prepare return value
+ Primitive2DSequence aRetval(2);
+
+ aRetval[0] = Primitive2DReference(new PolyPolygonHairlinePrimitive2D(aDashedPolyPolyA, getRGBColorA()));
+ aRetval[1] = Primitive2DReference(new PolyPolygonHairlinePrimitive2D(aDashedPolyPolyB, getRGBColorB()));
+
+ return aRetval;
+ }
+ else
+ {
+ const Primitive2DReference xRef(new PolygonHairlinePrimitive2D(getB2DPolygon(), getRGBColorA()));
+ return Primitive2DSequence(&xRef, 1L);
+ }
+ }
+
+ PolygonMarkerPrimitive2D::PolygonMarkerPrimitive2D(
+ const basegfx::B2DPolygon& rPolygon,
+ const basegfx::BColor& rRGBColorA,
+ const basegfx::BColor& rRGBColorB,
+ double fDiscreteDashLength)
+ : BufferedDecompositionPrimitive2D(),
+ maPolygon(rPolygon),
+ maRGBColorA(rRGBColorA),
+ maRGBColorB(rRGBColorB),
+ mfDiscreteDashLength(fDiscreteDashLength),
+ maLastInverseObjectToViewTransformation()
+ {
+ }
+
+ bool PolygonMarkerPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const PolygonMarkerPrimitive2D& rCompare = (PolygonMarkerPrimitive2D&)rPrimitive;
+
+ return (getB2DPolygon() == rCompare.getB2DPolygon()
+ && getRGBColorA() == rCompare.getRGBColorA()
+ && getRGBColorB() == rCompare.getRGBColorB()
+ && getDiscreteDashLength() == rCompare.getDiscreteDashLength());
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange PolygonMarkerPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ // this is a hairline, thus the line width is view-dependent. Get range of polygon
+ // as base size
+ basegfx::B2DRange aRetval(getB2DPolygon().getB2DRange());
+
+ if(!aRetval.isEmpty())
+ {
+ // Calculate view-dependent hairline width
+ const basegfx::B2DVector aDiscreteSize(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 0.0));
+ const double fDiscreteHalfLineWidth(aDiscreteSize.getLength() * 0.5);
+
+ if(basegfx::fTools::more(fDiscreteHalfLineWidth, 0.0))
+ {
+ aRetval.grow(fDiscreteHalfLineWidth);
+ }
+ }
+
+ // return range
+ return aRetval;
+ }
+
+ Primitive2DSequence PolygonMarkerPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ bool bNeedNewDecomposition(false);
+
+ if(getBuffered2DDecomposition().hasElements())
+ {
+ if(rViewInformation.getInverseObjectToViewTransformation() != maLastInverseObjectToViewTransformation)
+ {
+ bNeedNewDecomposition = true;
+ }
+ }
+
+ if(bNeedNewDecomposition)
+ {
+ // conditions of last local decomposition have changed, delete
+ const_cast< PolygonMarkerPrimitive2D* >(this)->setBuffered2DDecomposition(Primitive2DSequence());
+ }
+
+ if(!getBuffered2DDecomposition().hasElements())
+ {
+ // remember last used InverseObjectToViewTransformation
+ PolygonMarkerPrimitive2D* pThat = const_cast< PolygonMarkerPrimitive2D* >(this);
+ pThat->maLastInverseObjectToViewTransformation = rViewInformation.getInverseObjectToViewTransformation();
+ }
+
+ // use parent implementation
+ return BufferedDecompositionPrimitive2D::get2DDecomposition(rViewInformation);
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(PolygonMarkerPrimitive2D, PRIMITIVE2D_ID_POLYGONMARKERPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence PolygonStrokePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ if(getB2DPolygon().count())
+ {
+ // #i102241# try to simplify before usage
+ const basegfx::B2DPolygon aB2DPolygon(basegfx::tools::simplifyCurveSegments(getB2DPolygon()));
+ basegfx::B2DPolyPolygon aHairLinePolyPolygon;
+
+ if(getStrokeAttribute().isDefault() || 0.0 == getStrokeAttribute().getFullDotDashLen())
+ {
+ // no line dashing, just copy
+ aHairLinePolyPolygon.append(aB2DPolygon);
+ }
+ else
+ {
+ // apply LineStyle
+ basegfx::tools::applyLineDashing(
+ aB2DPolygon, getStrokeAttribute().getDotDashArray(),
+ &aHairLinePolyPolygon, 0, getStrokeAttribute().getFullDotDashLen());
+ }
+
+ const sal_uInt32 nCount(aHairLinePolyPolygon.count());
+
+ if(!getLineAttribute().isDefault() && getLineAttribute().getWidth())
+ {
+ // create fat line data
+ const double fHalfLineWidth(getLineAttribute().getWidth() / 2.0);
+ const basegfx::B2DLineJoin aLineJoin(getLineAttribute().getLineJoin());
+ basegfx::B2DPolyPolygon aAreaPolyPolygon;
+
+ for(sal_uInt32 a(0L); a < nCount; a++)
+ {
+ // New version of createAreaGeometry; now creates bezier polygons
+ aAreaPolyPolygon.append(basegfx::tools::createAreaGeometry(
+ aHairLinePolyPolygon.getB2DPolygon(a), fHalfLineWidth, aLineJoin));
+ }
+
+ // prepare return value
+ Primitive2DSequence aRetval(aAreaPolyPolygon.count());
+
+ // create primitive
+ for(sal_uInt32 b(0L); b < aAreaPolyPolygon.count(); b++)
+ {
+ // put into single polyPolygon primitives to make clear that this is NOT meant
+ // to be painted as a single PolyPolygon (XORed as fill rule). Alternatively, a
+ // melting process may be used here one day.
+ const basegfx::B2DPolyPolygon aNewPolyPolygon(aAreaPolyPolygon.getB2DPolygon(b));
+ static bool bTestByUsingRandomColor(false);
+ const basegfx::BColor aColor(bTestByUsingRandomColor
+ ? basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)
+ : getLineAttribute().getColor());
+ const Primitive2DReference xRef(new PolyPolygonColorPrimitive2D(aNewPolyPolygon, aColor));
+ aRetval[b] = xRef;
+ }
+
+ return aRetval;
+ }
+ else
+ {
+ // prepare return value
+ const Primitive2DReference xRef(
+ new PolyPolygonHairlinePrimitive2D(
+ aHairLinePolyPolygon,
+ getLineAttribute().getColor()));
+
+ return Primitive2DSequence(&xRef, 1);
+ }
+ }
+ else
+ {
+ return Primitive2DSequence();
+ }
+ }
+
+ PolygonStrokePrimitive2D::PolygonStrokePrimitive2D(
+ const basegfx::B2DPolygon& rPolygon,
+ const attribute::LineAttribute& rLineAttribute,
+ const attribute::StrokeAttribute& rStrokeAttribute)
+ : BufferedDecompositionPrimitive2D(),
+ maPolygon(rPolygon),
+ maLineAttribute(rLineAttribute),
+ maStrokeAttribute(rStrokeAttribute)
+ {
+ }
+
+ PolygonStrokePrimitive2D::PolygonStrokePrimitive2D(
+ const basegfx::B2DPolygon& rPolygon,
+ const attribute::LineAttribute& rLineAttribute)
+ : BufferedDecompositionPrimitive2D(),
+ maPolygon(rPolygon),
+ maLineAttribute(rLineAttribute),
+ maStrokeAttribute()
+ {
+ }
+
+ bool PolygonStrokePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const PolygonStrokePrimitive2D& rCompare = (PolygonStrokePrimitive2D&)rPrimitive;
+
+ return (getB2DPolygon() == rCompare.getB2DPolygon()
+ && getLineAttribute() == rCompare.getLineAttribute()
+ && getStrokeAttribute() == rCompare.getStrokeAttribute());
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange PolygonStrokePrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ basegfx::B2DRange aRetval;
+
+ if(getLineAttribute().getWidth())
+ {
+ if(basegfx::B2DLINEJOIN_MITER == getLineAttribute().getLineJoin())
+ {
+ // if line is mitered, use parent call since mitered line
+ // geometry may use more space than the geometry grown by half line width
+ aRetval = BufferedDecompositionPrimitive2D::getB2DRange(rViewInformation);
+ }
+ else
+ {
+ // for all other B2DLINEJOIN_* get the range from the base geometry
+ // and expand by half the line width
+ aRetval = getB2DPolygon().getB2DRange();
+ aRetval.grow(getLineAttribute().getWidth() * 0.5);
+ }
+ }
+ else
+ {
+ // this is a hairline, thus the line width is view-dependent. Get range of polygon
+ // as base size
+ aRetval = getB2DPolygon().getB2DRange();
+
+ if(!aRetval.isEmpty())
+ {
+ // Calculate view-dependent hairline width
+ const basegfx::B2DVector aDiscreteSize(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 0.0));
+ const double fDiscreteHalfLineWidth(aDiscreteSize.getLength() * 0.5);
+
+ if(basegfx::fTools::more(fDiscreteHalfLineWidth, 0.0))
+ {
+ aRetval.grow(fDiscreteHalfLineWidth);
+ }
+ }
+ }
+
+ return aRetval;
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(PolygonStrokePrimitive2D, PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence PolygonWavePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ Primitive2DSequence aRetval;
+
+ if(getB2DPolygon().count())
+ {
+ const bool bHasWidth(!basegfx::fTools::equalZero(getWaveWidth()));
+ const bool bHasHeight(!basegfx::fTools::equalZero(getWaveHeight()));
+
+ if(bHasWidth && bHasHeight)
+ {
+ // create waveline curve
+ const basegfx::B2DPolygon aWaveline(basegfx::tools::createWaveline(getB2DPolygon(), getWaveWidth(), getWaveHeight()));
+ const Primitive2DReference xRef(new PolygonStrokePrimitive2D(aWaveline, getLineAttribute(), getStrokeAttribute()));
+ aRetval = Primitive2DSequence(&xRef, 1);
+ }
+ else
+ {
+ // flat waveline, decompose to simple line primitive
+ const Primitive2DReference xRef(new PolygonStrokePrimitive2D(getB2DPolygon(), getLineAttribute(), getStrokeAttribute()));
+ aRetval = Primitive2DSequence(&xRef, 1);
+ }
+ }
+
+ return aRetval;
+ }
+
+ PolygonWavePrimitive2D::PolygonWavePrimitive2D(
+ const basegfx::B2DPolygon& rPolygon,
+ const attribute::LineAttribute& rLineAttribute,
+ const attribute::StrokeAttribute& rStrokeAttribute,
+ double fWaveWidth,
+ double fWaveHeight)
+ : PolygonStrokePrimitive2D(rPolygon, rLineAttribute, rStrokeAttribute),
+ mfWaveWidth(fWaveWidth),
+ mfWaveHeight(fWaveHeight)
+ {
+ if(mfWaveWidth < 0.0)
+ {
+ mfWaveWidth = 0.0;
+ }
+
+ if(mfWaveHeight < 0.0)
+ {
+ mfWaveHeight = 0.0;
+ }
+ }
+
+ PolygonWavePrimitive2D::PolygonWavePrimitive2D(
+ const basegfx::B2DPolygon& rPolygon,
+ const attribute::LineAttribute& rLineAttribute,
+ double fWaveWidth,
+ double fWaveHeight)
+ : PolygonStrokePrimitive2D(rPolygon, rLineAttribute),
+ mfWaveWidth(fWaveWidth),
+ mfWaveHeight(fWaveHeight)
+ {
+ if(mfWaveWidth < 0.0)
+ {
+ mfWaveWidth = 0.0;
+ }
+
+ if(mfWaveHeight < 0.0)
+ {
+ mfWaveHeight = 0.0;
+ }
+ }
+
+ bool PolygonWavePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(PolygonStrokePrimitive2D::operator==(rPrimitive))
+ {
+ const PolygonWavePrimitive2D& rCompare = (PolygonWavePrimitive2D&)rPrimitive;
+
+ return (getWaveWidth() == rCompare.getWaveWidth()
+ && getWaveHeight() == rCompare.getWaveHeight());
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange PolygonWavePrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ // get range of parent
+ basegfx::B2DRange aRetval(PolygonStrokePrimitive2D::getB2DRange(rViewInformation));
+
+ // if WaveHeight, grow by it
+ if(basegfx::fTools::more(getWaveHeight(), 0.0))
+ {
+ aRetval.grow(getWaveHeight());
+ }
+
+ // if line width, grow by it
+ if(basegfx::fTools::more(getLineAttribute().getWidth(), 0.0))
+ {
+ aRetval.grow(getLineAttribute().getWidth() * 0.5);
+ }
+
+ return aRetval;
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(PolygonWavePrimitive2D, PRIMITIVE2D_ID_POLYGONWAVEPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence PolygonStrokeArrowPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ // copy local polygon, it may be changed
+ basegfx::B2DPolygon aLocalPolygon(getB2DPolygon());
+ aLocalPolygon.removeDoublePoints();
+ basegfx::B2DPolyPolygon aArrowA;
+ basegfx::B2DPolyPolygon aArrowB;
+
+ if(!aLocalPolygon.isClosed() && aLocalPolygon.count() > 1)
+ {
+ // apply arrows
+ const double fPolyLength(basegfx::tools::getLength(aLocalPolygon));
+ double fStart(0.0);
+ double fEnd(0.0);
+
+ if(!getStart().isDefault() && getStart().isActive())
+ {
+ // create start arrow primitive and consume
+ aArrowA = basegfx::tools::createAreaGeometryForLineStartEnd(
+ aLocalPolygon, getStart().getB2DPolyPolygon(), true, getStart().getWidth(),
+ fPolyLength, getStart().isCentered() ? 0.5 : 0.0, &fStart);
+
+ // create some overlapping
+ fStart *= 0.8;
+ }
+
+ if(!getEnd().isDefault() && getEnd().isActive())
+ {
+ // create end arrow primitive and consume
+ aArrowB = basegfx::tools::createAreaGeometryForLineStartEnd(
+ aLocalPolygon, getEnd().getB2DPolyPolygon(), false, getEnd().getWidth(),
+ fPolyLength, getEnd().isCentered() ? 0.5 : 0.0, &fEnd);
+
+ // create some overlapping
+ fEnd *= 0.8;
+ }
+
+ if(0.0 != fStart || 0.0 != fEnd)
+ {
+ // build new poly, consume something from old poly
+ aLocalPolygon = basegfx::tools::getSnippetAbsolute(aLocalPolygon, fStart, fPolyLength - fEnd, fPolyLength);
+ }
+ }
+
+ // prepare return value
+ Primitive2DSequence aRetval(1L + (aArrowA.count() ? 1L : 0L) + (aArrowB.count() ? 1L : 0L));
+ sal_uInt32 nInd(0L);
+
+ // add shaft
+ const Primitive2DReference xRefShaft(new
+ PolygonStrokePrimitive2D(
+ aLocalPolygon, getLineAttribute(), getStrokeAttribute()));
+ aRetval[nInd++] = xRefShaft;
+
+ if(aArrowA.count())
+ {
+ const Primitive2DReference xRefA(
+ new PolyPolygonColorPrimitive2D(
+ aArrowA, getLineAttribute().getColor()));
+ aRetval[nInd++] = xRefA;
+ }
+
+ if(aArrowB.count())
+ {
+ const Primitive2DReference xRefB(
+ new PolyPolygonColorPrimitive2D(
+ aArrowB, getLineAttribute().getColor()));
+ aRetval[nInd++] = xRefB;
+ }
+
+ return aRetval;
+ }
+
+ PolygonStrokeArrowPrimitive2D::PolygonStrokeArrowPrimitive2D(
+ const basegfx::B2DPolygon& rPolygon,
+ const attribute::LineAttribute& rLineAttribute,
+ const attribute::StrokeAttribute& rStrokeAttribute,
+ const attribute::LineStartEndAttribute& rStart,
+ const attribute::LineStartEndAttribute& rEnd)
+ : PolygonStrokePrimitive2D(rPolygon, rLineAttribute, rStrokeAttribute),
+ maStart(rStart),
+ maEnd(rEnd)
+ {
+ }
+
+ PolygonStrokeArrowPrimitive2D::PolygonStrokeArrowPrimitive2D(
+ const basegfx::B2DPolygon& rPolygon,
+ const attribute::LineAttribute& rLineAttribute,
+ const attribute::LineStartEndAttribute& rStart,
+ const attribute::LineStartEndAttribute& rEnd)
+ : PolygonStrokePrimitive2D(rPolygon, rLineAttribute),
+ maStart(rStart),
+ maEnd(rEnd)
+ {
+ }
+
+ bool PolygonStrokeArrowPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(PolygonStrokePrimitive2D::operator==(rPrimitive))
+ {
+ const PolygonStrokeArrowPrimitive2D& rCompare = (PolygonStrokeArrowPrimitive2D&)rPrimitive;
+
+ return (getStart() == rCompare.getStart()
+ && getEnd() == rCompare.getEnd());
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange PolygonStrokeArrowPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ basegfx::B2DRange aRetval;
+
+ if(getStart().isActive() || getEnd().isActive())
+ {
+ // use decomposition when line start/end is used
+ return BufferedDecompositionPrimitive2D::getB2DRange(rViewInformation);
+ }
+ else
+ {
+ // get range from parent
+ return PolygonStrokePrimitive2D::getB2DRange(rViewInformation);
+ }
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(PolygonStrokeArrowPrimitive2D, PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/polypolygonprimitive2d.cxx b/drawinglayer/source/primitive2d/polypolygonprimitive2d.cxx
new file mode 100644
index 000000000000..98966c70a3b7
--- /dev/null
+++ b/drawinglayer/source/primitive2d/polypolygonprimitive2d.cxx
@@ -0,0 +1,575 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/tools/canvastools.hxx>
+#include <drawinglayer/primitive2d/fillgradientprimitive2d.hxx>
+#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
+#include <drawinglayer/primitive2d/fillhatchprimitive2d.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <drawinglayer/primitive2d/fillbitmapprimitive2d.hxx>
+#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence PolyPolygonHairlinePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ const basegfx::B2DPolyPolygon aPolyPolygon(getB2DPolyPolygon());
+ const sal_uInt32 nCount(aPolyPolygon.count());
+
+ if(nCount)
+ {
+ Primitive2DSequence aRetval(nCount);
+
+ for(sal_uInt32 a(0L); a < nCount; a++)
+ {
+ aRetval[a] = Primitive2DReference(new PolygonHairlinePrimitive2D(aPolyPolygon.getB2DPolygon(a), getBColor()));
+ }
+
+ return aRetval;
+ }
+ else
+ {
+ return Primitive2DSequence();
+ }
+ }
+
+ PolyPolygonHairlinePrimitive2D::PolyPolygonHairlinePrimitive2D(const basegfx::B2DPolyPolygon& rPolyPolygon, const basegfx::BColor& rBColor)
+ : BufferedDecompositionPrimitive2D(),
+ maPolyPolygon(rPolyPolygon),
+ maBColor(rBColor)
+ {
+ }
+
+ bool PolyPolygonHairlinePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const PolyPolygonHairlinePrimitive2D& rCompare = (PolyPolygonHairlinePrimitive2D&)rPrimitive;
+
+ return (getB2DPolyPolygon() == rCompare.getB2DPolyPolygon()
+ && getBColor() == rCompare.getBColor());
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange PolyPolygonHairlinePrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ // return range
+ return basegfx::tools::getRange(getB2DPolyPolygon());
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(PolyPolygonHairlinePrimitive2D, PRIMITIVE2D_ID_POLYPOLYGONHAIRLINEPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence PolyPolygonMarkerPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ const basegfx::B2DPolyPolygon aPolyPolygon(getB2DPolyPolygon());
+ const sal_uInt32 nCount(aPolyPolygon.count());
+
+ if(nCount)
+ {
+ Primitive2DSequence aRetval(nCount);
+
+ for(sal_uInt32 a(0L); a < nCount; a++)
+ {
+ aRetval[a] = Primitive2DReference(new PolygonMarkerPrimitive2D(aPolyPolygon.getB2DPolygon(a), getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
+ }
+
+ return aRetval;
+ }
+ else
+ {
+ return Primitive2DSequence();
+ }
+ }
+
+ PolyPolygonMarkerPrimitive2D::PolyPolygonMarkerPrimitive2D(
+ const basegfx::B2DPolyPolygon& rPolyPolygon,
+ const basegfx::BColor& rRGBColorA,
+ const basegfx::BColor& rRGBColorB,
+ double fDiscreteDashLength)
+ : BufferedDecompositionPrimitive2D(),
+ maPolyPolygon(rPolyPolygon),
+ maRGBColorA(rRGBColorA),
+ maRGBColorB(rRGBColorB),
+ mfDiscreteDashLength(fDiscreteDashLength)
+ {
+ }
+
+ bool PolyPolygonMarkerPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const PolyPolygonMarkerPrimitive2D& rCompare = (PolyPolygonMarkerPrimitive2D&)rPrimitive;
+
+ return (getB2DPolyPolygon() == rCompare.getB2DPolyPolygon()
+ && getRGBColorA() == rCompare.getRGBColorA()
+ && getRGBColorB() == rCompare.getRGBColorB()
+ && getDiscreteDashLength() == rCompare.getDiscreteDashLength());
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange PolyPolygonMarkerPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ // return range
+ return basegfx::tools::getRange(getB2DPolyPolygon());
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(PolyPolygonMarkerPrimitive2D, PRIMITIVE2D_ID_POLYPOLYGONMARKERPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence PolyPolygonStrokePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ const basegfx::B2DPolyPolygon aPolyPolygon(getB2DPolyPolygon());
+ const sal_uInt32 nCount(aPolyPolygon.count());
+
+ if(nCount)
+ {
+ Primitive2DSequence aRetval(nCount);
+
+ for(sal_uInt32 a(0L); a < nCount; a++)
+ {
+ aRetval[a] = Primitive2DReference(
+ new PolygonStrokePrimitive2D(
+ aPolyPolygon.getB2DPolygon(a), getLineAttribute(), getStrokeAttribute()));
+ }
+
+ return aRetval;
+ }
+ else
+ {
+ return Primitive2DSequence();
+ }
+ }
+
+ PolyPolygonStrokePrimitive2D::PolyPolygonStrokePrimitive2D(
+ const basegfx::B2DPolyPolygon& rPolyPolygon,
+ const attribute::LineAttribute& rLineAttribute,
+ const attribute::StrokeAttribute& rStrokeAttribute)
+ : BufferedDecompositionPrimitive2D(),
+ maPolyPolygon(rPolyPolygon),
+ maLineAttribute(rLineAttribute),
+ maStrokeAttribute(rStrokeAttribute)
+ {
+ }
+
+ PolyPolygonStrokePrimitive2D::PolyPolygonStrokePrimitive2D(
+ const basegfx::B2DPolyPolygon& rPolyPolygon,
+ const attribute::LineAttribute& rLineAttribute)
+ : BufferedDecompositionPrimitive2D(),
+ maPolyPolygon(rPolyPolygon),
+ maLineAttribute(rLineAttribute),
+ maStrokeAttribute()
+ {
+ }
+
+ bool PolyPolygonStrokePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const PolyPolygonStrokePrimitive2D& rCompare = (PolyPolygonStrokePrimitive2D&)rPrimitive;
+
+ return (getB2DPolyPolygon() == rCompare.getB2DPolyPolygon()
+ && getLineAttribute() == rCompare.getLineAttribute()
+ && getStrokeAttribute() == rCompare.getStrokeAttribute());
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange PolyPolygonStrokePrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ // get range of it (subdivided)
+ basegfx::B2DRange aRetval(basegfx::tools::getRange(getB2DPolyPolygon()));
+
+ // if width, grow by line width
+ if(getLineAttribute().getWidth())
+ {
+ aRetval.grow(getLineAttribute().getWidth() / 2.0);
+ }
+
+ return aRetval;
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(PolyPolygonStrokePrimitive2D, PRIMITIVE2D_ID_POLYPOLYGONSTROKEPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence PolyPolygonStrokeArrowPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ const basegfx::B2DPolyPolygon aPolyPolygon(getB2DPolyPolygon());
+ const sal_uInt32 nCount(aPolyPolygon.count());
+
+ if(nCount)
+ {
+ Primitive2DSequence aRetval(nCount);
+
+ for(sal_uInt32 a(0L); a < nCount; a++)
+ {
+ const basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(a));
+
+ if(aPolygon.isClosed())
+ {
+ // no need for PolygonStrokeArrowPrimitive2D when polygon is closed
+ aRetval[a] = Primitive2DReference(
+ new PolygonStrokePrimitive2D(aPolygon, getLineAttribute(), getStrokeAttribute()));
+ }
+ else
+ {
+ aRetval[a] = Primitive2DReference(
+ new PolygonStrokeArrowPrimitive2D(aPolygon, getLineAttribute(),
+ getStrokeAttribute(), getStart(), getEnd()));
+ }
+ }
+
+ return aRetval;
+ }
+ else
+ {
+ return Primitive2DSequence();
+ }
+ }
+
+ PolyPolygonStrokeArrowPrimitive2D::PolyPolygonStrokeArrowPrimitive2D(
+ const basegfx::B2DPolyPolygon& rPolyPolygon,
+ const attribute::LineAttribute& rLineAttribute,
+ const attribute::StrokeAttribute& rStrokeAttribute,
+ const attribute::LineStartEndAttribute& rStart,
+ const attribute::LineStartEndAttribute& rEnd)
+ : PolyPolygonStrokePrimitive2D(rPolyPolygon, rLineAttribute, rStrokeAttribute),
+ maStart(rStart),
+ maEnd(rEnd)
+ {
+ }
+
+ PolyPolygonStrokeArrowPrimitive2D::PolyPolygonStrokeArrowPrimitive2D(
+ const basegfx::B2DPolyPolygon& rPolyPolygon,
+ const attribute::LineAttribute& rLineAttribute,
+ const attribute::LineStartEndAttribute& rStart,
+ const attribute::LineStartEndAttribute& rEnd)
+ : PolyPolygonStrokePrimitive2D(rPolyPolygon, rLineAttribute),
+ maStart(rStart),
+ maEnd(rEnd)
+ {
+ }
+
+ bool PolyPolygonStrokeArrowPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(PolyPolygonStrokePrimitive2D::operator==(rPrimitive))
+ {
+ const PolyPolygonStrokeArrowPrimitive2D& rCompare = (PolyPolygonStrokeArrowPrimitive2D&)rPrimitive;
+
+ return (getStart() == rCompare.getStart()
+ && getEnd() == rCompare.getEnd());
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange PolyPolygonStrokeArrowPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ basegfx::B2DRange aRetval;
+
+ if(getStart().isActive() || getEnd().isActive())
+ {
+ // use decomposition when line start/end is used
+ return BufferedDecompositionPrimitive2D::getB2DRange(rViewInformation);
+ }
+ else
+ {
+ // get range from parent
+ return PolyPolygonStrokePrimitive2D::getB2DRange(rViewInformation);
+ }
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(PolyPolygonStrokeArrowPrimitive2D, PRIMITIVE2D_ID_POLYPOLYGONSTROKEARROWPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ PolyPolygonColorPrimitive2D::PolyPolygonColorPrimitive2D(
+ const basegfx::B2DPolyPolygon& rPolyPolygon,
+ const basegfx::BColor& rBColor)
+ : BasePrimitive2D(),
+ maPolyPolygon(rPolyPolygon),
+ maBColor(rBColor)
+ {
+ }
+
+ bool PolyPolygonColorPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BasePrimitive2D::operator==(rPrimitive))
+ {
+ const PolyPolygonColorPrimitive2D& rCompare = (PolyPolygonColorPrimitive2D&)rPrimitive;
+
+ return (getB2DPolyPolygon() == rCompare.getB2DPolyPolygon()
+ && getBColor() == rCompare.getBColor());
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange PolyPolygonColorPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ // return range
+ return basegfx::tools::getRange(getB2DPolyPolygon());
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(PolyPolygonColorPrimitive2D, PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence PolyPolygonGradientPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ if(!getFillGradient().isDefault())
+ {
+ // create SubSequence with FillGradientPrimitive2D
+ const basegfx::B2DRange aPolyPolygonRange(getB2DPolyPolygon().getB2DRange());
+ FillGradientPrimitive2D* pNewGradient = new FillGradientPrimitive2D(aPolyPolygonRange, getFillGradient());
+ const Primitive2DReference xSubRef(pNewGradient);
+ const Primitive2DSequence aSubSequence(&xSubRef, 1L);
+
+ // create mask primitive
+ MaskPrimitive2D* pNewMask = new MaskPrimitive2D(getB2DPolyPolygon(), aSubSequence);
+ const Primitive2DReference xRef(pNewMask);
+
+ return Primitive2DSequence(&xRef, 1);
+ }
+ else
+ {
+ return Primitive2DSequence();
+ }
+ }
+
+ PolyPolygonGradientPrimitive2D::PolyPolygonGradientPrimitive2D(
+ const basegfx::B2DPolyPolygon& rPolyPolygon,
+ const attribute::FillGradientAttribute& rFillGradient)
+ : BufferedDecompositionPrimitive2D(),
+ maPolyPolygon(rPolyPolygon),
+ maFillGradient(rFillGradient)
+ {
+ }
+
+ bool PolyPolygonGradientPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const PolyPolygonGradientPrimitive2D& rCompare = (PolyPolygonGradientPrimitive2D&)rPrimitive;
+
+ return (getFillGradient() == rCompare.getFillGradient());
+ }
+
+ return false;
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(PolyPolygonGradientPrimitive2D, PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence PolyPolygonHatchPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ if(!getFillHatch().isDefault())
+ {
+ // create SubSequence with FillHatchPrimitive2D
+ const basegfx::B2DRange aPolyPolygonRange(getB2DPolyPolygon().getB2DRange());
+ FillHatchPrimitive2D* pNewHatch = new FillHatchPrimitive2D(aPolyPolygonRange, getBackgroundColor(), getFillHatch());
+ const Primitive2DReference xSubRef(pNewHatch);
+ const Primitive2DSequence aSubSequence(&xSubRef, 1L);
+
+ // create mask primitive
+ MaskPrimitive2D* pNewMask = new MaskPrimitive2D(getB2DPolyPolygon(), aSubSequence);
+ const Primitive2DReference xRef(pNewMask);
+
+ return Primitive2DSequence(&xRef, 1);
+ }
+ else
+ {
+ return Primitive2DSequence();
+ }
+ }
+
+ PolyPolygonHatchPrimitive2D::PolyPolygonHatchPrimitive2D(
+ const basegfx::B2DPolyPolygon& rPolyPolygon,
+ const basegfx::BColor& rBackgroundColor,
+ const attribute::FillHatchAttribute& rFillHatch)
+ : BufferedDecompositionPrimitive2D(),
+ maPolyPolygon(rPolyPolygon),
+ maBackgroundColor(rBackgroundColor),
+ maFillHatch(rFillHatch)
+ {
+ }
+
+ bool PolyPolygonHatchPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const PolyPolygonHatchPrimitive2D& rCompare = (PolyPolygonHatchPrimitive2D&)rPrimitive;
+
+ return (getBackgroundColor() == rCompare.getBackgroundColor()
+ && getFillHatch() == rCompare.getFillHatch());
+ }
+
+ return false;
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(PolyPolygonHatchPrimitive2D, PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence PolyPolygonBitmapPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ if(!getFillBitmap().isDefault())
+ {
+ // create SubSequence with FillBitmapPrimitive2D
+ const basegfx::B2DRange aPolyPolygonRange(getB2DPolyPolygon().getB2DRange());
+ basegfx::B2DHomMatrix aNewObjectTransform;
+ aNewObjectTransform.set(0, 0, aPolyPolygonRange.getWidth());
+ aNewObjectTransform.set(1, 1, aPolyPolygonRange.getHeight());
+ aNewObjectTransform.set(0, 2, aPolyPolygonRange.getMinX());
+ aNewObjectTransform.set(1, 2, aPolyPolygonRange.getMinY());
+ FillBitmapPrimitive2D* pNewBitmap = new FillBitmapPrimitive2D(aNewObjectTransform, getFillBitmap());
+ const Primitive2DReference xSubRef(pNewBitmap);
+ const Primitive2DSequence aSubSequence(&xSubRef, 1L);
+
+ // create mask primitive
+ MaskPrimitive2D* pNewMask = new MaskPrimitive2D(getB2DPolyPolygon(), aSubSequence);
+ const Primitive2DReference xRef(pNewMask);
+
+ return Primitive2DSequence(&xRef, 1);
+ }
+ else
+ {
+ return Primitive2DSequence();
+ }
+ }
+
+ PolyPolygonBitmapPrimitive2D::PolyPolygonBitmapPrimitive2D(
+ const basegfx::B2DPolyPolygon& rPolyPolygon,
+ const attribute::FillBitmapAttribute& rFillBitmap)
+ : BufferedDecompositionPrimitive2D(),
+ maPolyPolygon(rPolyPolygon),
+ maFillBitmap(rFillBitmap)
+ {
+ }
+
+ bool PolyPolygonBitmapPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const PolyPolygonBitmapPrimitive2D& rCompare = (PolyPolygonBitmapPrimitive2D&)rPrimitive;
+
+ return (getFillBitmap() == rCompare.getFillBitmap());
+ }
+
+ return false;
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(PolyPolygonBitmapPrimitive2D, PRIMITIVE2D_ID_POLYPOLYGONBITMAPPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/primitivetools2d.cxx b/drawinglayer/source/primitive2d/primitivetools2d.cxx
new file mode 100644
index 000000000000..03425a2ead73
--- /dev/null
+++ b/drawinglayer/source/primitive2d/primitivetools2d.cxx
@@ -0,0 +1,173 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/primitivetools2d.hxx>
+#include <basegfx/vector/b2dvector.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence DiscreteMetricDependentPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // get the current DiscreteUnit
+ const double fDiscreteUnit((rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 0.0)).getLength());
+
+ if(getBuffered2DDecomposition().hasElements() && !basegfx::fTools::equal(fDiscreteUnit, getDiscreteUnit()))
+ {
+ // conditions of last local decomposition have changed, delete
+ const_cast< DiscreteMetricDependentPrimitive2D* >(this)->setBuffered2DDecomposition(Primitive2DSequence());
+ }
+
+ if(!getBuffered2DDecomposition().hasElements())
+ {
+ // remember new valid DiscreteUnit
+ const_cast< DiscreteMetricDependentPrimitive2D* >(this)->mfDiscreteUnit = fDiscreteUnit;
+ }
+
+ // call base implementation
+ return BufferedDecompositionPrimitive2D::get2DDecomposition(rViewInformation);
+ }
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence ViewportDependentPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // get the current Viewport
+ const basegfx::B2DRange& rViewport = rViewInformation.getViewport();
+
+ if(getBuffered2DDecomposition().hasElements() && !rViewport.equal(getViewport()))
+ {
+ // conditions of last local decomposition have changed, delete
+ const_cast< ViewportDependentPrimitive2D* >(this)->setBuffered2DDecomposition(Primitive2DSequence());
+ }
+
+ if(!getBuffered2DDecomposition().hasElements())
+ {
+ // remember new valid DiscreteUnit
+ const_cast< ViewportDependentPrimitive2D* >(this)->maViewport = rViewport;
+ }
+
+ // call base implementation
+ return BufferedDecompositionPrimitive2D::get2DDecomposition(rViewInformation);
+ }
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence ViewTransformationDependentPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // get the current ViewTransformation
+ const basegfx::B2DHomMatrix& rViewTransformation = rViewInformation.getViewTransformation();
+
+ if(getBuffered2DDecomposition().hasElements() && rViewTransformation != getViewTransformation())
+ {
+ // conditions of last local decomposition have changed, delete
+ const_cast< ViewTransformationDependentPrimitive2D* >(this)->setBuffered2DDecomposition(Primitive2DSequence());
+ }
+
+ if(!getBuffered2DDecomposition().hasElements())
+ {
+ // remember new valid ViewTransformation
+ const_cast< ViewTransformationDependentPrimitive2D* >(this)->maViewTransformation = rViewTransformation;
+ }
+
+ // call base implementation
+ return BufferedDecompositionPrimitive2D::get2DDecomposition(rViewInformation);
+ }
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence ObjectAndViewTransformationDependentPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // get the current ViewTransfromation
+ const basegfx::B2DHomMatrix& rViewTransformation = rViewInformation.getViewTransformation();
+
+ if(getBuffered2DDecomposition().hasElements() && rViewTransformation != getViewTransformation())
+ {
+ // conditions of last local decomposition have changed, delete
+ const_cast< ObjectAndViewTransformationDependentPrimitive2D* >(this)->setBuffered2DDecomposition(Primitive2DSequence());
+ }
+
+ // get the current ObjectTransformation
+ const basegfx::B2DHomMatrix& rObjectTransformation = rViewInformation.getObjectTransformation();
+
+ if(getBuffered2DDecomposition().hasElements() && rObjectTransformation != getObjectTransformation())
+ {
+ // conditions of last local decomposition have changed, delete
+ const_cast< ObjectAndViewTransformationDependentPrimitive2D* >(this)->setBuffered2DDecomposition(Primitive2DSequence());
+ }
+
+ if(!getBuffered2DDecomposition().hasElements())
+ {
+ // remember new valid ViewTransformation, and ObjectTransformation
+ const_cast< ObjectAndViewTransformationDependentPrimitive2D* >(this)->maViewTransformation = rViewTransformation;
+ const_cast< ObjectAndViewTransformationDependentPrimitive2D* >(this)->maObjectTransformation = rObjectTransformation;
+ }
+
+ // call base implementation
+ return BufferedDecompositionPrimitive2D::get2DDecomposition(rViewInformation);
+ }
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/sceneprimitive2d.cxx b/drawinglayer/source/primitive2d/sceneprimitive2d.cxx
new file mode 100644
index 000000000000..f9959744c29d
--- /dev/null
+++ b/drawinglayer/source/primitive2d/sceneprimitive2d.cxx
@@ -0,0 +1,483 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/sceneprimitive2d.hxx>
+#include <basegfx/tools/canvastools.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygonclipper.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
+#include <drawinglayer/processor3d/zbufferprocessor3d.hxx>
+#include <drawinglayer/processor3d/shadow3dextractor.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
+#include <drawinglayer/processor3d/geometry2dextractor.hxx>
+#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ bool ScenePrimitive2D::impGetShadow3D(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // create on demand
+ if(!mbShadow3DChecked && getChildren3D().hasElements())
+ {
+ basegfx::B3DVector aLightNormal;
+ const double fShadowSlant(getSdrSceneAttribute().getShadowSlant());
+ const basegfx::B3DRange aScene3DRange(primitive3d::getB3DRangeFromPrimitive3DSequence(getChildren3D(), getViewInformation3D()));
+
+ if(maSdrLightingAttribute.getLightVector().size())
+ {
+ // get light normal from first light and normalize
+ aLightNormal = maSdrLightingAttribute.getLightVector()[0].getDirection();
+ aLightNormal.normalize();
+ }
+
+ // create shadow extraction processor
+ processor3d::Shadow3DExtractingProcessor aShadowProcessor(
+ getViewInformation3D(),
+ getObjectTransformation(),
+ aLightNormal,
+ fShadowSlant,
+ aScene3DRange);
+
+ // process local primitives
+ aShadowProcessor.process(getChildren3D());
+
+ // fetch result and set checked flag
+ const_cast< ScenePrimitive2D* >(this)->maShadowPrimitives = aShadowProcessor.getPrimitive2DSequence();
+ const_cast< ScenePrimitive2D* >(this)->mbShadow3DChecked = true;
+ }
+
+ // return if there are shadow primitives
+ return maShadowPrimitives.hasElements();
+ }
+
+ void ScenePrimitive2D::calculateDiscreteSizes(
+ const geometry::ViewInformation2D& rViewInformation,
+ basegfx::B2DRange& rDiscreteRange,
+ basegfx::B2DRange& rVisibleDiscreteRange,
+ basegfx::B2DRange& rUnitVisibleRange) const
+ {
+ // use unit range and transform to discrete coordinates
+ rDiscreteRange = basegfx::B2DRange(0.0, 0.0, 1.0, 1.0);
+ rDiscreteRange.transform(rViewInformation.getObjectToViewTransformation() * getObjectTransformation());
+
+ // clip it against discrete Viewport (if set)
+ rVisibleDiscreteRange = rDiscreteRange;
+
+ if(!rViewInformation.getViewport().isEmpty())
+ {
+ rVisibleDiscreteRange.intersect(rViewInformation.getDiscreteViewport());
+ }
+
+ if(rVisibleDiscreteRange.isEmpty())
+ {
+ rUnitVisibleRange = rVisibleDiscreteRange;
+ }
+ else
+ {
+ // create UnitVisibleRange containing unit range values [0.0 .. 1.0] describing
+ // the relative position of rVisibleDiscreteRange inside rDiscreteRange
+ const double fDiscreteScaleFactorX(basegfx::fTools::equalZero(rDiscreteRange.getWidth()) ? 1.0 : 1.0 / rDiscreteRange.getWidth());
+ const double fDiscreteScaleFactorY(basegfx::fTools::equalZero(rDiscreteRange.getHeight()) ? 1.0 : 1.0 / rDiscreteRange.getHeight());
+
+ const double fMinX(basegfx::fTools::equal(rVisibleDiscreteRange.getMinX(), rDiscreteRange.getMinX())
+ ? 0.0
+ : (rVisibleDiscreteRange.getMinX() - rDiscreteRange.getMinX()) * fDiscreteScaleFactorX);
+ const double fMinY(basegfx::fTools::equal(rVisibleDiscreteRange.getMinY(), rDiscreteRange.getMinY())
+ ? 0.0
+ : (rVisibleDiscreteRange.getMinY() - rDiscreteRange.getMinY()) * fDiscreteScaleFactorY);
+
+ const double fMaxX(basegfx::fTools::equal(rVisibleDiscreteRange.getMaxX(), rDiscreteRange.getMaxX())
+ ? 1.0
+ : (rVisibleDiscreteRange.getMaxX() - rDiscreteRange.getMinX()) * fDiscreteScaleFactorX);
+ const double fMaxY(basegfx::fTools::equal(rVisibleDiscreteRange.getMaxY(), rDiscreteRange.getMaxY())
+ ? 1.0
+ : (rVisibleDiscreteRange.getMaxY() - rDiscreteRange.getMinY()) * fDiscreteScaleFactorY);
+
+ rUnitVisibleRange = basegfx::B2DRange(fMinX, fMinY, fMaxX, fMaxY);
+ }
+ }
+
+ Primitive2DSequence ScenePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ Primitive2DSequence aRetval;
+
+ // create 2D shadows from contained 3D primitives. This creates the shadow primitives on demand and tells if
+ // there are some or not. Do this at start, the shadow might still be visible even when the scene is not
+ if(impGetShadow3D(rViewInformation))
+ {
+ // test visibility
+ const basegfx::B2DRange aShadow2DRange(
+ getB2DRangeFromPrimitive2DSequence(maShadowPrimitives, rViewInformation));
+ const basegfx::B2DRange aViewRange(
+ rViewInformation.getViewport());
+
+ if(aViewRange.isEmpty() || aShadow2DRange.overlaps(aViewRange))
+ {
+ // add extracted 2d shadows (before 3d scene creations itself)
+ aRetval = maShadowPrimitives;
+ }
+ }
+
+ // get the involved ranges (see helper method calculateDiscreteSizes for details)
+ basegfx::B2DRange aDiscreteRange;
+ basegfx::B2DRange aVisibleDiscreteRange;
+ basegfx::B2DRange aUnitVisibleRange;
+
+ calculateDiscreteSizes(rViewInformation, aDiscreteRange, aVisibleDiscreteRange, aUnitVisibleRange);
+
+ if(!aVisibleDiscreteRange.isEmpty())
+ {
+ // test if discrete view size (pixel) maybe too big and limit it
+ double fViewSizeX(aVisibleDiscreteRange.getWidth());
+ double fViewSizeY(aVisibleDiscreteRange.getHeight());
+ const double fViewVisibleArea(fViewSizeX * fViewSizeY);
+ const SvtOptionsDrawinglayer aDrawinglayerOpt;
+ const double fMaximumVisibleArea(aDrawinglayerOpt.GetQuadratic3DRenderLimit());
+ double fReduceFactor(1.0);
+
+ if(fViewVisibleArea > fMaximumVisibleArea)
+ {
+ fReduceFactor = sqrt(fMaximumVisibleArea / fViewVisibleArea);
+ fViewSizeX *= fReduceFactor;
+ fViewSizeY *= fReduceFactor;
+ }
+
+ if(rViewInformation.getReducedDisplayQuality())
+ {
+ // when reducing the visualisation is allowed (e.g. an OverlayObject
+ // only needed for dragging), reduce resolution extra
+ // to speed up dragging interactions
+ const double fArea(fViewSizeX * fViewSizeY);
+ double fReducedVisualisationFactor(1.0 / (sqrt(fArea) * (1.0 / 170.0)));
+
+ if(fReducedVisualisationFactor > 1.0)
+ {
+ fReducedVisualisationFactor = 1.0;
+ }
+ else if(fReducedVisualisationFactor < 0.20)
+ {
+ fReducedVisualisationFactor = 0.20;
+ }
+
+ if(fReducedVisualisationFactor != 1.0)
+ {
+ fReduceFactor *= fReducedVisualisationFactor;
+ fViewSizeX *= fReducedVisualisationFactor;
+ fViewSizeY *= fReducedVisualisationFactor;
+ }
+ }
+
+ // calculate logic render size in world coordinates for usage in renderer
+ basegfx::B2DVector aLogicRenderSize(
+ aDiscreteRange.getWidth() * fReduceFactor,
+ aDiscreteRange.getHeight() * fReduceFactor);
+ aLogicRenderSize *= rViewInformation.getInverseObjectToViewTransformation();
+
+ // determine the oversample value
+ static sal_uInt16 nDefaultOversampleValue(3);
+ const sal_uInt16 nOversampleValue(aDrawinglayerOpt.IsAntiAliasing() ? nDefaultOversampleValue : 0);
+
+ // use default 3D primitive processor to create BitmapEx for aUnitVisiblePart and process
+ processor3d::ZBufferProcessor3D aZBufferProcessor3D(
+ getViewInformation3D(),
+ rViewInformation,
+ getSdrSceneAttribute(),
+ getSdrLightingAttribute(),
+ aLogicRenderSize.getX(),
+ aLogicRenderSize.getY(),
+ aUnitVisibleRange,
+ nOversampleValue);
+
+ aZBufferProcessor3D.process(getChildren3D());
+ aZBufferProcessor3D.finish();
+
+ const_cast< ScenePrimitive2D* >(this)->maOldRenderedBitmap = aZBufferProcessor3D.getBitmapEx();
+ const Size aBitmapSizePixel(maOldRenderedBitmap.GetSizePixel());
+
+ if(aBitmapSizePixel.getWidth() && aBitmapSizePixel.getHeight())
+ {
+ // create transform for the created bitmap in discrete coordinates first.
+ basegfx::B2DHomMatrix aNew2DTransform;
+
+ aNew2DTransform.set(0, 0, aVisibleDiscreteRange.getWidth());
+ aNew2DTransform.set(1, 1, aVisibleDiscreteRange.getHeight());
+ aNew2DTransform.set(0, 2, aVisibleDiscreteRange.getMinX());
+ aNew2DTransform.set(1, 2, aVisibleDiscreteRange.getMinY());
+
+ // transform back to world coordinates for usage in primitive creation
+ aNew2DTransform *= rViewInformation.getInverseObjectToViewTransformation();
+
+ // create bitmap primitive and add
+ const Primitive2DReference xRef(new BitmapPrimitive2D(maOldRenderedBitmap, aNew2DTransform));
+ appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, xRef);
+
+ // test: Allow to add an outline in the debugger when tests are needed
+ static bool bAddOutlineToCreated3DSceneRepresentation(false);
+
+ if(bAddOutlineToCreated3DSceneRepresentation)
+ {
+ basegfx::B2DPolygon aOutline(basegfx::tools::createUnitPolygon());
+ aOutline.transform(aNew2DTransform);
+ const Primitive2DReference xRef2(new PolygonHairlinePrimitive2D(aOutline, basegfx::BColor(1.0, 0.0, 0.0)));
+ appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, xRef2);
+ }
+ }
+ }
+
+ return aRetval;
+ }
+
+ Primitive2DSequence ScenePrimitive2D::getGeometry2D() const
+ {
+ Primitive2DSequence aRetval;
+
+ // create 2D projected geometry from 3D geometry
+ if(getChildren3D().hasElements())
+ {
+ // create 2D geometry extraction processor
+ processor3d::Geometry2DExtractingProcessor aGeometryProcessor(
+ getViewInformation3D(),
+ getObjectTransformation());
+
+ // process local primitives
+ aGeometryProcessor.process(getChildren3D());
+
+ // fetch result
+ aRetval = aGeometryProcessor.getPrimitive2DSequence();
+ }
+
+ return aRetval;
+ }
+
+ Primitive2DSequence ScenePrimitive2D::getShadow2D(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ Primitive2DSequence aRetval;
+
+ // create 2D shadows from contained 3D primitives
+ if(impGetShadow3D(rViewInformation))
+ {
+ // add extracted 2d shadows (before 3d scene creations itself)
+ aRetval = maShadowPrimitives;
+ }
+
+ return aRetval;
+ }
+
+ bool ScenePrimitive2D::tryToCheckLastVisualisationDirectHit(const basegfx::B2DPoint& rLogicHitPoint, bool& o_rResult) const
+ {
+ if(!maOldRenderedBitmap.IsEmpty() && !maOldUnitVisiblePart.isEmpty())
+ {
+ basegfx::B2DHomMatrix aInverseSceneTransform(getObjectTransformation());
+ aInverseSceneTransform.invert();
+ const basegfx::B2DPoint aRelativePoint(aInverseSceneTransform * rLogicHitPoint);
+
+ if(maOldUnitVisiblePart.isInside(aRelativePoint))
+ {
+ // calculate coordinates relative to visualized part
+ double fDivisorX(maOldUnitVisiblePart.getWidth());
+ double fDivisorY(maOldUnitVisiblePart.getHeight());
+
+ if(basegfx::fTools::equalZero(fDivisorX))
+ {
+ fDivisorX = 1.0;
+ }
+
+ if(basegfx::fTools::equalZero(fDivisorY))
+ {
+ fDivisorY = 1.0;
+ }
+
+ const double fRelativeX((aRelativePoint.getX() - maOldUnitVisiblePart.getMinX()) / fDivisorX);
+ const double fRelativeY((aRelativePoint.getY() - maOldUnitVisiblePart.getMinY()) / fDivisorY);
+
+ // combine with real BitmapSizePixel to get bitmap coordinates
+ const Size aBitmapSizePixel(maOldRenderedBitmap.GetSizePixel());
+ const sal_Int32 nX(basegfx::fround(fRelativeX * aBitmapSizePixel.Width()));
+ const sal_Int32 nY(basegfx::fround(fRelativeY * aBitmapSizePixel.Height()));
+
+ // try to get a statement about transparency in that pixel
+ o_rResult = (0xff != maOldRenderedBitmap.GetTransparency(nX, nY));
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ ScenePrimitive2D::ScenePrimitive2D(
+ const primitive3d::Primitive3DSequence& rxChildren3D,
+ const attribute::SdrSceneAttribute& rSdrSceneAttribute,
+ const attribute::SdrLightingAttribute& rSdrLightingAttribute,
+ const basegfx::B2DHomMatrix& rObjectTransformation,
+ const geometry::ViewInformation3D& rViewInformation3D)
+ : BufferedDecompositionPrimitive2D(),
+ mxChildren3D(rxChildren3D),
+ maSdrSceneAttribute(rSdrSceneAttribute),
+ maSdrLightingAttribute(rSdrLightingAttribute),
+ maObjectTransformation(rObjectTransformation),
+ maViewInformation3D(rViewInformation3D),
+ maShadowPrimitives(),
+ mbShadow3DChecked(false),
+ mfOldDiscreteSizeX(0.0),
+ mfOldDiscreteSizeY(0.0),
+ maOldUnitVisiblePart(),
+ maOldRenderedBitmap()
+ {
+ }
+
+ bool ScenePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const ScenePrimitive2D& rCompare = (ScenePrimitive2D&)rPrimitive;
+
+ return (primitive3d::arePrimitive3DSequencesEqual(getChildren3D(), rCompare.getChildren3D())
+ && getSdrSceneAttribute() == rCompare.getSdrSceneAttribute()
+ && getSdrLightingAttribute() == rCompare.getSdrLightingAttribute()
+ && getObjectTransformation() == rCompare.getObjectTransformation()
+ && getViewInformation3D() == rCompare.getViewInformation3D());
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange ScenePrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ // transform unit range to discrete coordinate range
+ basegfx::B2DRange aRetval(0.0, 0.0, 1.0, 1.0);
+ aRetval.transform(rViewInformation.getObjectToViewTransformation() * getObjectTransformation());
+
+ // force to discrete expanded bounds (it grows, so expanding works perfectly well)
+ aRetval.expand(basegfx::B2DTuple(floor(aRetval.getMinX()), floor(aRetval.getMinY())));
+ aRetval.expand(basegfx::B2DTuple(ceil(aRetval.getMaxX()), ceil(aRetval.getMaxY())));
+
+ // transform back from discrete (view) to world coordinates
+ aRetval.transform(rViewInformation.getInverseObjectToViewTransformation());
+
+ // expand by evtl. existing shadow primitives
+ if(impGetShadow3D(rViewInformation))
+ {
+ const basegfx::B2DRange aShadow2DRange(getB2DRangeFromPrimitive2DSequence(maShadowPrimitives, rViewInformation));
+
+ if(!aShadow2DRange.isEmpty())
+ {
+ aRetval.expand(aShadow2DRange);
+ }
+ }
+
+ return aRetval;
+ }
+
+ Primitive2DSequence ScenePrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // get the involved ranges (see helper method calculateDiscreteSizes for details)
+ basegfx::B2DRange aDiscreteRange;
+ basegfx::B2DRange aUnitVisibleRange;
+ bool bNeedNewDecomposition(false);
+ bool bDiscreteSizesAreCalculated(false);
+
+ if(getBuffered2DDecomposition().hasElements())
+ {
+ basegfx::B2DRange aVisibleDiscreteRange;
+ calculateDiscreteSizes(rViewInformation, aDiscreteRange, aVisibleDiscreteRange, aUnitVisibleRange);
+ bDiscreteSizesAreCalculated = true;
+
+ // needs to be painted when the new part is not part of the last
+ // decomposition
+ if(!maOldUnitVisiblePart.isInside(aUnitVisibleRange))
+ {
+ bNeedNewDecomposition = true;
+ }
+
+ // display has changed and cannot be reused when resolution got bigger. It
+ // can be reused when resolution got smaller, though.
+ if(!bNeedNewDecomposition)
+ {
+ if(basegfx::fTools::more(aDiscreteRange.getWidth(), mfOldDiscreteSizeX) ||
+ basegfx::fTools::more(aDiscreteRange.getHeight(), mfOldDiscreteSizeY))
+ {
+ bNeedNewDecomposition = true;
+ }
+ }
+ }
+
+ if(bNeedNewDecomposition)
+ {
+ // conditions of last local decomposition have changed, delete
+ const_cast< ScenePrimitive2D* >(this)->setBuffered2DDecomposition(Primitive2DSequence());
+ }
+
+ if(!getBuffered2DDecomposition().hasElements())
+ {
+ if(!bDiscreteSizesAreCalculated)
+ {
+ basegfx::B2DRange aVisibleDiscreteRange;
+ calculateDiscreteSizes(rViewInformation, aDiscreteRange, aVisibleDiscreteRange, aUnitVisibleRange);
+ }
+
+ // remember last used NewDiscreteSize and NewUnitVisiblePart
+ ScenePrimitive2D* pThat = const_cast< ScenePrimitive2D* >(this);
+ pThat->mfOldDiscreteSizeX = aDiscreteRange.getWidth();
+ pThat->mfOldDiscreteSizeY = aDiscreteRange.getHeight();
+ pThat->maOldUnitVisiblePart = aUnitVisibleRange;
+ }
+
+ // use parent implementation
+ return BufferedDecompositionPrimitive2D::get2DDecomposition(rViewInformation);
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(ScenePrimitive2D, PRIMITIVE2D_ID_SCENEPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/sdrdecompositiontools2d.cxx b/drawinglayer/source/primitive2d/sdrdecompositiontools2d.cxx
new file mode 100644
index 000000000000..315015e589bc
--- /dev/null
+++ b/drawinglayer/source/primitive2d/sdrdecompositiontools2d.cxx
@@ -0,0 +1,133 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: sdrdecompositiontools3d.cxx,v $
+ *
+ * $Revision: 1.7 $
+ *
+ * last change: $Author: aw $ $Date: 2008-05-27 14:11:21 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library 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 for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/hiddengeometryprimitive2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DReference createHiddenGeometryPrimitives2D(
+ bool bFilled,
+ const basegfx::B2DHomMatrix& rMatrix)
+ {
+ const basegfx::B2DPolygon aUnitOutline(basegfx::tools::createUnitPolygon());
+
+ return createHiddenGeometryPrimitives2D(
+ bFilled,
+ basegfx::B2DPolyPolygon(aUnitOutline),
+ rMatrix);
+ }
+
+ Primitive2DReference createHiddenGeometryPrimitives2D(
+ bool bFilled,
+ const basegfx::B2DPolyPolygon& rPolyPolygon)
+ {
+ return createHiddenGeometryPrimitives2D(
+ bFilled,
+ rPolyPolygon,
+ basegfx::B2DHomMatrix());
+ }
+
+ Primitive2DReference createHiddenGeometryPrimitives2D(
+ bool bFilled,
+ const basegfx::B2DRange& rRange)
+ {
+ return createHiddenGeometryPrimitives2D(
+ bFilled,
+ rRange,
+ basegfx::B2DHomMatrix());
+ }
+
+ Primitive2DReference createHiddenGeometryPrimitives2D(
+ bool bFilled,
+ const basegfx::B2DRange& rRange,
+ const basegfx::B2DHomMatrix& rMatrix)
+ {
+ const basegfx::B2DPolyPolygon aOutline(basegfx::tools::createPolygonFromRect(rRange));
+
+ return createHiddenGeometryPrimitives2D(
+ bFilled,
+ aOutline,
+ rMatrix);
+ }
+
+ Primitive2DReference createHiddenGeometryPrimitives2D(
+ bool bFilled,
+ const basegfx::B2DPolyPolygon& rPolyPolygon,
+ const basegfx::B2DHomMatrix& rMatrix)
+ {
+ // create fill or line primitive
+ Primitive2DReference xReference;
+ basegfx::B2DPolyPolygon aScaledOutline(rPolyPolygon);
+ aScaledOutline.transform(rMatrix);
+
+ if(bFilled)
+ {
+ xReference = new PolyPolygonColorPrimitive2D(
+ basegfx::B2DPolyPolygon(aScaledOutline),
+ basegfx::BColor(0.0, 0.0, 0.0));
+ }
+ else
+ {
+ const basegfx::BColor aGrayTone(0xc0 / 255.0, 0xc0 / 255.0, 0xc0 / 255.0);
+
+ xReference = new PolyPolygonHairlinePrimitive2D(
+ aScaledOutline,
+ aGrayTone);
+ }
+
+ // create HiddenGeometryPrimitive2D
+ return Primitive2DReference(
+ new HiddenGeometryPrimitive2D(Primitive2DSequence(&xReference, 1)));
+ }
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/shadowprimitive2d.cxx b/drawinglayer/source/primitive2d/shadowprimitive2d.cxx
new file mode 100644
index 000000000000..c0d436964e89
--- /dev/null
+++ b/drawinglayer/source/primitive2d/shadowprimitive2d.cxx
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/shadowprimitive2d.hxx>
+#include <basegfx/color/bcolormodifier.hxx>
+#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <basegfx/tools/canvastools.hxx>
+#include <drawinglayer/primitive2d/transparenceprimitive2d.hxx>
+#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ ShadowPrimitive2D::ShadowPrimitive2D(
+ const basegfx::B2DHomMatrix& rShadowTransform,
+ const basegfx::BColor& rShadowColor,
+ const Primitive2DSequence& rChildren)
+ : GroupPrimitive2D(rChildren),
+ maShadowTransform(rShadowTransform),
+ maShadowColor(rShadowColor)
+ {
+ }
+
+ bool ShadowPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BasePrimitive2D::operator==(rPrimitive))
+ {
+ const ShadowPrimitive2D& rCompare = static_cast< const ShadowPrimitive2D& >(rPrimitive);
+
+ return (getShadowTransform() == rCompare.getShadowTransform()
+ && getShadowColor() == rCompare.getShadowColor());
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange ShadowPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ basegfx::B2DRange aRetval(getB2DRangeFromPrimitive2DSequence(getChildren(), rViewInformation));
+ aRetval.transform(getShadowTransform());
+ return aRetval;
+ }
+
+ Primitive2DSequence ShadowPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ Primitive2DSequence aRetval;
+
+ if(getChildren().hasElements())
+ {
+ // create a modifiedColorPrimitive containing the shadow color and the content
+ const basegfx::BColorModifier aBColorModifier(getShadowColor());
+ const Primitive2DReference xRefA(new ModifiedColorPrimitive2D(getChildren(), aBColorModifier));
+ const Primitive2DSequence aSequenceB(&xRefA, 1L);
+
+ // build transformed primitiveVector with shadow offset and add to target
+ const Primitive2DReference xRefB(new TransformPrimitive2D(getShadowTransform(), aSequenceB));
+ aRetval = Primitive2DSequence(&xRefB, 1L);
+ }
+
+ return aRetval;
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(ShadowPrimitive2D, PRIMITIVE2D_ID_SHADOWPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/structuretagprimitive2d.cxx b/drawinglayer/source/primitive2d/structuretagprimitive2d.cxx
new file mode 100644
index 000000000000..4e26a06e02b7
--- /dev/null
+++ b/drawinglayer/source/primitive2d/structuretagprimitive2d.cxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/structuretagprimitive2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ StructureTagPrimitive2D::StructureTagPrimitive2D(
+ const vcl::PDFWriter::StructElement& rStructureElement,
+ const Primitive2DSequence& rChildren)
+ : GroupPrimitive2D(rChildren),
+ maStructureElement(rStructureElement)
+ {
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(StructureTagPrimitive2D, PRIMITIVE2D_ID_STRUCTURETAGPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/textdecoratedprimitive2d.cxx b/drawinglayer/source/primitive2d/textdecoratedprimitive2d.cxx
new file mode 100644
index 000000000000..2457e8f7be78
--- /dev/null
+++ b/drawinglayer/source/primitive2d/textdecoratedprimitive2d.cxx
@@ -0,0 +1,610 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
+#include <drawinglayer/primitive2d/textlayoutdevice.hxx>
+#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
+#include <drawinglayer/attribute/strokeattribute.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <comphelper/processfactory.hxx>
+#include <com/sun/star/i18n/WordType.hpp>
+#include <drawinglayer/primitive2d/texteffectprimitive2d.hxx>
+#include <drawinglayer/primitive2d/shadowprimitive2d.hxx>
+#include <com/sun/star/i18n/XBreakIterator.hpp>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <drawinglayer/primitive2d/textlineprimitive2d.hxx>
+#include <drawinglayer/primitive2d/textstrikeoutprimitive2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ void TextDecoratedPortionPrimitive2D::impCreateGeometryContent(
+ std::vector< Primitive2DReference >& rTarget,
+ basegfx::tools::B2DHomMatrixBufferedOnDemandDecompose& rDecTrans,
+ const String& rText,
+ xub_StrLen aTextPosition,
+ xub_StrLen aTextLength,
+ const ::std::vector< double >& rDXArray,
+ const attribute::FontAttribute& rFontAttribute) const
+ {
+ // create the SimpleTextPrimitive needed in any case
+ rTarget.push_back(Primitive2DReference(
+ new TextSimplePortionPrimitive2D(
+ rDecTrans.getB2DHomMatrix(),
+ rText,
+ aTextPosition,
+ aTextLength,
+ rDXArray,
+ rFontAttribute,
+ getLocale(),
+ getFontColor())));
+
+ // see if something else needs to be done
+ const bool bOverlineUsed(TEXT_LINE_NONE != getFontOverline());
+ const bool bUnderlineUsed(TEXT_LINE_NONE != getFontUnderline());
+ const bool bStrikeoutUsed(TEXT_STRIKEOUT_NONE != getTextStrikeout());
+
+ if(bUnderlineUsed || bStrikeoutUsed || bOverlineUsed)
+ {
+ // common preparations
+ TextLayouterDevice aTextLayouter;
+
+ // TextLayouterDevice is needed to get metrics for text decorations like
+ // underline/strikeout/emphasis marks from it. For setup, the font size is needed
+ aTextLayouter.setFontAttribute(
+ getFontAttribute(),
+ rDecTrans.getScale().getX(),
+ rDecTrans.getScale().getY(),
+ getLocale());
+
+ // get text width
+ double fTextWidth(0.0);
+
+ if(rDXArray.empty())
+ {
+ fTextWidth = aTextLayouter.getTextWidth(rText, aTextPosition, aTextLength);
+ }
+ else
+ {
+ fTextWidth = rDXArray.back() * rDecTrans.getScale().getX();
+ const double fFontScaleX(rDecTrans.getScale().getX());
+
+ if(!basegfx::fTools::equal(fFontScaleX, 1.0)
+ && !basegfx::fTools::equalZero(fFontScaleX))
+ {
+ // need to take FontScaling out of the DXArray
+ fTextWidth /= fFontScaleX;
+ }
+ }
+
+ if(bOverlineUsed)
+ {
+ // create primitive geometry for overline
+ rTarget.push_back(Primitive2DReference(
+ new TextLinePrimitive2D(
+ rDecTrans.getB2DHomMatrix(),
+ fTextWidth,
+ aTextLayouter.getOverlineOffset(),
+ aTextLayouter.getOverlineHeight(),
+ getFontOverline(),
+ getOverlineColor())));
+ }
+
+ if(bUnderlineUsed)
+ {
+ // create primitive geometry for underline
+ rTarget.push_back(Primitive2DReference(
+ new TextLinePrimitive2D(
+ rDecTrans.getB2DHomMatrix(),
+ fTextWidth,
+ aTextLayouter.getUnderlineOffset(),
+ aTextLayouter.getUnderlineHeight(),
+ getFontUnderline(),
+ getTextlineColor())));
+ }
+
+ if(bStrikeoutUsed)
+ {
+ // create primitive geometry for strikeout
+ if(TEXT_STRIKEOUT_SLASH == getTextStrikeout() || TEXT_STRIKEOUT_X == getTextStrikeout())
+ {
+ // strikeout with character
+ const sal_Unicode aStrikeoutChar(TEXT_STRIKEOUT_SLASH == getTextStrikeout() ? '/' : 'X');
+
+ rTarget.push_back(Primitive2DReference(
+ new TextCharacterStrikeoutPrimitive2D(
+ rDecTrans.getB2DHomMatrix(),
+ fTextWidth,
+ getFontColor(),
+ aStrikeoutChar,
+ getFontAttribute(),
+ getLocale())));
+ }
+ else
+ {
+ // strikeout with geometry
+ rTarget.push_back(Primitive2DReference(
+ new TextGeometryStrikeoutPrimitive2D(
+ rDecTrans.getB2DHomMatrix(),
+ fTextWidth,
+ getFontColor(),
+ aTextLayouter.getUnderlineHeight(),
+ aTextLayouter.getStrikeoutOffset(),
+ getTextStrikeout())));
+ }
+ }
+ }
+
+ // TODO: Handle Font Emphasis Above/Below
+ }
+
+ void TextDecoratedPortionPrimitive2D::impCorrectTextBoundary(::com::sun::star::i18n::Boundary& rNextWordBoundary) const
+ {
+ // truncate aNextWordBoundary to min/max possible values. This is necessary since the word start may be
+ // before/after getTextPosition() when a long string is the content and getTextPosition()
+ // is right inside a word. Same for end.
+ const sal_Int32 aMinPos(static_cast< sal_Int32 >(getTextPosition()));
+ const sal_Int32 aMaxPos(aMinPos + static_cast< sal_Int32 >(getTextLength()));
+
+ if(rNextWordBoundary.startPos < aMinPos)
+ {
+ rNextWordBoundary.startPos = aMinPos;
+ }
+ else if(rNextWordBoundary.startPos > aMaxPos)
+ {
+ rNextWordBoundary.startPos = aMaxPos;
+ }
+
+ if(rNextWordBoundary.endPos < aMinPos)
+ {
+ rNextWordBoundary.endPos = aMinPos;
+ }
+ else if(rNextWordBoundary.endPos > aMaxPos)
+ {
+ rNextWordBoundary.endPos = aMaxPos;
+ }
+ }
+
+ void TextDecoratedPortionPrimitive2D::impSplitSingleWords(
+ std::vector< Primitive2DReference >& rTarget,
+ basegfx::tools::B2DHomMatrixBufferedOnDemandDecompose& rDecTrans) const
+ {
+ // break iterator support
+ // made static so it only needs to be fetched once, even with many single
+ // constructed VclMetafileProcessor2D. It's still incarnated on demand,
+ // but exists for OOo runtime now by purpose.
+ static ::com::sun::star::uno::Reference< ::com::sun::star::i18n::XBreakIterator > xLocalBreakIterator;
+
+ if(!xLocalBreakIterator.is())
+ {
+ ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xMSF(::comphelper::getProcessServiceFactory());
+ xLocalBreakIterator.set(xMSF->createInstance(rtl::OUString::createFromAscii("com.sun.star.i18n.BreakIterator")), ::com::sun::star::uno::UNO_QUERY);
+ }
+
+ if(xLocalBreakIterator.is() && getTextLength())
+ {
+ // init word iterator, get first word and truncate to possibilities
+ ::com::sun::star::i18n::Boundary aNextWordBoundary(xLocalBreakIterator->getWordBoundary(
+ getText(), getTextPosition(), getLocale(), ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True));
+
+ if(aNextWordBoundary.endPos == getTextPosition())
+ {
+ // backward hit, force next word
+ aNextWordBoundary = xLocalBreakIterator->getWordBoundary(
+ getText(), getTextPosition() + 1, getLocale(), ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True);
+ }
+
+ impCorrectTextBoundary(aNextWordBoundary);
+
+ // prepare new font attributes WITHOUT outline
+ const attribute::FontAttribute aNewFontAttribute(
+ getFontAttribute().getFamilyName(),
+ getFontAttribute().getStyleName(),
+ getFontAttribute().getWeight(),
+ getFontAttribute().getSymbol(),
+ getFontAttribute().getVertical(),
+ getFontAttribute().getItalic(),
+ getFontAttribute().getMonospaced(),
+ false, // no outline anymore, handled locally
+ getFontAttribute().getRTL(),
+ getFontAttribute().getBiDiStrong());
+
+ if(aNextWordBoundary.startPos == getTextPosition() && aNextWordBoundary.endPos == getTextLength())
+ {
+ // it IS only a single word, handle as one word
+ impCreateGeometryContent(rTarget, rDecTrans, getText(), getTextPosition(), getTextLength(), getDXArray(), aNewFontAttribute);
+ }
+ else
+ {
+ // prepare TextLayouter
+ const bool bNoDXArray(getDXArray().empty());
+ TextLayouterDevice aTextLayouter;
+
+ if(bNoDXArray)
+ {
+ // ..but only completely when no DXArray
+ aTextLayouter.setFontAttribute(
+ getFontAttribute(),
+ rDecTrans.getScale().getX(),
+ rDecTrans.getScale().getY(),
+ getLocale());
+ }
+
+ // do iterate over single words
+ while(aNextWordBoundary.startPos != aNextWordBoundary.endPos)
+ {
+ // prepare values for new portion
+ const xub_StrLen nNewTextStart(static_cast< xub_StrLen >(aNextWordBoundary.startPos));
+ const xub_StrLen nNewTextEnd(static_cast< xub_StrLen >(aNextWordBoundary.endPos));
+
+ // prepare transform for the single word
+ basegfx::B2DHomMatrix aNewTransform;
+ ::std::vector< double > aNewDXArray;
+ const bool bNewStartIsNotOldStart(nNewTextStart > getTextPosition());
+
+ if(!bNoDXArray)
+ {
+ // prepare new DXArray for the single word
+ aNewDXArray = ::std::vector< double >(
+ getDXArray().begin() + static_cast< sal_uInt32 >(nNewTextStart - getTextPosition()),
+ getDXArray().begin() + static_cast< sal_uInt32 >(nNewTextEnd - getTextPosition()));
+ }
+
+ if(bNewStartIsNotOldStart)
+ {
+ // needs to be moved to a new start position
+ double fOffset(0.0);
+
+ if(bNoDXArray)
+ {
+ // evaluate using TextLayouter
+ fOffset = aTextLayouter.getTextWidth(getText(), getTextPosition(), nNewTextStart);
+ }
+ else
+ {
+ // get from DXArray
+ const sal_uInt32 nIndex(static_cast< sal_uInt32 >(nNewTextStart - getTextPosition()));
+ fOffset = 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(rDecTrans.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(!bNoDXArray)
+ {
+ // 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 *= rDecTrans.getB2DHomMatrix();
+
+ // create geometry content for the single word. Do not forget
+ // to use the new transformation
+ basegfx::tools::B2DHomMatrixBufferedOnDemandDecompose aDecTrans(aNewTransform);
+
+ impCreateGeometryContent(rTarget, aDecTrans, getText(), nNewTextStart,
+ nNewTextEnd - nNewTextStart, aNewDXArray, aNewFontAttribute);
+
+ if(aNextWordBoundary.endPos >= getTextPosition() + getTextLength())
+ {
+ // end reached
+ aNextWordBoundary.startPos = aNextWordBoundary.endPos;
+ }
+ else
+ {
+ // get new word portion
+ const sal_Int32 nLastEndPos(aNextWordBoundary.endPos);
+
+ aNextWordBoundary = xLocalBreakIterator->getWordBoundary(
+ getText(), aNextWordBoundary.endPos, getLocale(),
+ ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True);
+
+ if(nLastEndPos == aNextWordBoundary.endPos)
+ {
+ // backward hit, force next word
+ aNextWordBoundary = xLocalBreakIterator->getWordBoundary(
+ getText(), nLastEndPos + 1, getLocale(),
+ ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True);
+ }
+
+ impCorrectTextBoundary(aNextWordBoundary);
+ }
+ }
+ }
+ }
+ }
+
+ Primitive2DSequence TextDecoratedPortionPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ std::vector< Primitive2DReference > aNewPrimitives;
+ basegfx::tools::B2DHomMatrixBufferedOnDemandDecompose aDecTrans(getTextTransform());
+ Primitive2DSequence aRetval;
+
+ // create basic geometry such as SimpleTextPrimitive, Overline, Underline,
+ // Strikeout, etc...
+ if(getWordLineMode())
+ {
+ // support for single word mode
+ impSplitSingleWords(aNewPrimitives, aDecTrans);
+ }
+ else
+ {
+ // prepare new font attributes WITHOUT outline
+ const attribute::FontAttribute aNewFontAttribute(
+ getFontAttribute().getFamilyName(),
+ getFontAttribute().getStyleName(),
+ getFontAttribute().getWeight(),
+ getFontAttribute().getSymbol(),
+ getFontAttribute().getVertical(),
+ getFontAttribute().getItalic(),
+ false, // no outline anymore, handled locally
+ getFontAttribute().getRTL(),
+ getFontAttribute().getBiDiStrong());
+
+ // handle as one word
+ impCreateGeometryContent(aNewPrimitives, aDecTrans, getText(), getTextPosition(), getTextLength(), getDXArray(), aNewFontAttribute);
+ }
+
+ // convert to Primitive2DSequence
+ const sal_uInt32 nMemberCount(aNewPrimitives.size());
+
+ if(nMemberCount)
+ {
+ aRetval.realloc(nMemberCount);
+
+ for(sal_uInt32 a(0); a < nMemberCount; a++)
+ {
+ aRetval[a] = aNewPrimitives[a];
+ }
+ }
+
+ // Handle Shadow, Outline and TextRelief
+ if(aRetval.hasElements())
+ {
+ // outline AND shadow depend on NO TextRelief (see dialog)
+ const bool bHasTextRelief(TEXT_RELIEF_NONE != getTextRelief());
+ const bool bHasShadow(!bHasTextRelief && getShadow());
+ const bool bHasOutline(!bHasTextRelief && getFontAttribute().getOutline());
+
+ if(bHasShadow || bHasTextRelief || bHasOutline)
+ {
+ Primitive2DReference aShadow;
+
+ if(bHasShadow)
+ {
+ // create shadow with current content (in aRetval). Text shadow
+ // is constant, relative to font size, rotated with the text and has a
+ // constant color.
+ // shadow parameter values
+ static double fFactor(1.0 / 24.0);
+ const double fTextShadowOffset(aDecTrans.getScale().getY() * fFactor);
+ static basegfx::BColor aShadowColor(0.3, 0.3, 0.3);
+
+ // preapare shadow transform matrix
+ const basegfx::B2DHomMatrix aShadowTransform(basegfx::tools::createTranslateB2DHomMatrix(
+ fTextShadowOffset, fTextShadowOffset));
+
+ // create shadow primitive
+ aShadow = Primitive2DReference(new ShadowPrimitive2D(
+ aShadowTransform,
+ aShadowColor,
+ aRetval));
+ }
+
+ if(bHasTextRelief)
+ {
+ // create emboss using an own helper primitive since this will
+ // be view-dependent
+ const basegfx::BColor aBBlack(0.0, 0.0, 0.0);
+ const bool bDefaultTextColor(aBBlack == getFontColor());
+ TextEffectStyle2D aTextEffectStyle2D(TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED);
+
+ if(bDefaultTextColor)
+ {
+ if(TEXT_RELIEF_ENGRAVED == getTextRelief())
+ {
+ aTextEffectStyle2D = TEXTEFFECTSTYLE2D_RELIEF_ENGRAVED_DEFAULT;
+ }
+ else
+ {
+ aTextEffectStyle2D = TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED_DEFAULT;
+ }
+ }
+ else
+ {
+ if(TEXT_RELIEF_ENGRAVED == getTextRelief())
+ {
+ aTextEffectStyle2D = TEXTEFFECTSTYLE2D_RELIEF_ENGRAVED;
+ }
+ else
+ {
+ aTextEffectStyle2D = TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED;
+ }
+ }
+
+ Primitive2DReference aNewTextEffect(new TextEffectPrimitive2D(
+ aRetval,
+ aDecTrans.getTranslate(),
+ aDecTrans.getRotate(),
+ aTextEffectStyle2D));
+ aRetval = Primitive2DSequence(&aNewTextEffect, 1);
+ }
+ else if(bHasOutline)
+ {
+ // create outline using an own helper primitive since this will
+ // be view-dependent
+ Primitive2DReference aNewTextEffect(new TextEffectPrimitive2D(
+ aRetval,
+ aDecTrans.getTranslate(),
+ aDecTrans.getRotate(),
+ TEXTEFFECTSTYLE2D_OUTLINE));
+ aRetval = Primitive2DSequence(&aNewTextEffect, 1);
+ }
+
+ if(aShadow.is())
+ {
+ // put shadow in front if there is one to paint timely before
+ // but placed behind content
+ const Primitive2DSequence aContent(aRetval);
+ aRetval = Primitive2DSequence(&aShadow, 1);
+ appendPrimitive2DSequenceToPrimitive2DSequence(aRetval, aContent);
+ }
+ }
+ }
+
+ return aRetval;
+ }
+
+ TextDecoratedPortionPrimitive2D::TextDecoratedPortionPrimitive2D(
+
+ // TextSimplePortionPrimitive2D parameters
+ const basegfx::B2DHomMatrix& rNewTransform,
+ const String& rText,
+ xub_StrLen aTextPosition,
+ xub_StrLen aTextLength,
+ const ::std::vector< double >& rDXArray,
+ const attribute::FontAttribute& rFontAttribute,
+ const ::com::sun::star::lang::Locale& rLocale,
+ const basegfx::BColor& rFontColor,
+
+ // local parameters
+ const basegfx::BColor& rOverlineColor,
+ const basegfx::BColor& rTextlineColor,
+ TextLine eFontOverline,
+ TextLine eFontUnderline,
+ bool bUnderlineAbove,
+ TextStrikeout eTextStrikeout,
+ bool bWordLineMode,
+ TextEmphasisMark eTextEmphasisMark,
+ bool bEmphasisMarkAbove,
+ bool bEmphasisMarkBelow,
+ TextRelief eTextRelief,
+ bool bShadow)
+ : TextSimplePortionPrimitive2D(rNewTransform, rText, aTextPosition, aTextLength, rDXArray, rFontAttribute, rLocale, rFontColor),
+ maOverlineColor(rOverlineColor),
+ maTextlineColor(rTextlineColor),
+ meFontOverline(eFontOverline),
+ meFontUnderline(eFontUnderline),
+ meTextStrikeout(eTextStrikeout),
+ meTextEmphasisMark(eTextEmphasisMark),
+ meTextRelief(eTextRelief),
+ mbUnderlineAbove(bUnderlineAbove),
+ mbWordLineMode(bWordLineMode),
+ mbEmphasisMarkAbove(bEmphasisMarkAbove),
+ mbEmphasisMarkBelow(bEmphasisMarkBelow),
+ mbShadow(bShadow)
+ {
+ }
+
+ bool TextDecoratedPortionPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(TextSimplePortionPrimitive2D::operator==(rPrimitive))
+ {
+ const TextDecoratedPortionPrimitive2D& rCompare = (TextDecoratedPortionPrimitive2D&)rPrimitive;
+
+ return (getOverlineColor() == rCompare.getOverlineColor()
+ && getTextlineColor() == rCompare.getTextlineColor()
+ && getFontOverline() == rCompare.getFontOverline()
+ && getFontUnderline() == rCompare.getFontUnderline()
+ && getTextStrikeout() == rCompare.getTextStrikeout()
+ && getTextEmphasisMark() == rCompare.getTextEmphasisMark()
+ && getTextRelief() == rCompare.getTextRelief()
+ && getUnderlineAbove() == rCompare.getUnderlineAbove()
+ && getWordLineMode() == rCompare.getWordLineMode()
+ && getEmphasisMarkAbove() == rCompare.getEmphasisMarkAbove()
+ && getEmphasisMarkBelow() == rCompare.getEmphasisMarkBelow()
+ && getShadow() == rCompare.getShadow());
+ }
+
+ return false;
+ }
+
+ // #i96475#
+ // Added missing implementation. Decorations may (will) stick out of the text's
+ // inking area, so add them if needed
+ basegfx::B2DRange TextDecoratedPortionPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ const bool bDecoratedIsNeeded(
+ TEXT_LINE_NONE != getFontOverline()
+ || TEXT_LINE_NONE != getFontUnderline()
+ || TEXT_STRIKEOUT_NONE != getTextStrikeout()
+ || TEXT_EMPHASISMARK_NONE != getTextEmphasisMark()
+ || TEXT_RELIEF_NONE != getTextRelief()
+ || getShadow());
+
+ if(bDecoratedIsNeeded)
+ {
+ // decoration is used, fallback to BufferedDecompositionPrimitive2D::getB2DRange which uses
+ // the own local decomposition for computation and thus creates all necessary
+ // geometric objects
+ return BufferedDecompositionPrimitive2D::getB2DRange(rViewInformation);
+ }
+ else
+ {
+ // no relevant decoration used, fallback to TextSimplePortionPrimitive2D::getB2DRange
+ return TextSimplePortionPrimitive2D::getB2DRange(rViewInformation);
+ }
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(TextDecoratedPortionPrimitive2D, PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/texteffectprimitive2d.cxx b/drawinglayer/source/primitive2d/texteffectprimitive2d.cxx
new file mode 100644
index 000000000000..cf29d00e3b9a
--- /dev/null
+++ b/drawinglayer/source/primitive2d/texteffectprimitive2d.cxx
@@ -0,0 +1,242 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/texteffectprimitive2d.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ static double fDiscreteSize(1.1);
+
+ Primitive2DSequence TextEffectPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ Primitive2DSequence aRetval;
+
+ // get the distance of one discrete units from target display. Use between 1.0 and sqrt(2) to
+ // have good results on rotated objects, too
+ const basegfx::B2DVector aDistance(rViewInformation.getInverseObjectToViewTransformation() *
+ basegfx::B2DVector(fDiscreteSize, fDiscreteSize));
+ const basegfx::B2DVector aDiagonalDistance(aDistance * (1.0 / 1.44));
+
+ switch(getTextEffectStyle2D())
+ {
+ case TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED:
+ case TEXTEFFECTSTYLE2D_RELIEF_ENGRAVED:
+ case TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED_DEFAULT:
+ case TEXTEFFECTSTYLE2D_RELIEF_ENGRAVED_DEFAULT:
+ {
+ // prepare transform of sub-group back to (0,0) and align to X-Axis
+ basegfx::B2DHomMatrix aBackTransform(basegfx::tools::createTranslateB2DHomMatrix(
+ -getRotationCenter().getX(), -getRotationCenter().getY()));
+ aBackTransform.rotate(-getDirection());
+
+ // prepare transform of sub-group back to it's position and rotation
+ basegfx::B2DHomMatrix aForwardTransform(basegfx::tools::createRotateB2DHomMatrix(getDirection()));
+ aForwardTransform.translate(getRotationCenter().getX(), getRotationCenter().getY());
+
+ // create transformation for one discrete unit
+ const bool bEmbossed(
+ TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED == getTextEffectStyle2D()
+ || TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED_DEFAULT == getTextEffectStyle2D());
+ const bool bDefaultTextColor(
+ TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED_DEFAULT == getTextEffectStyle2D()
+ || TEXTEFFECTSTYLE2D_RELIEF_ENGRAVED_DEFAULT == getTextEffectStyle2D());
+ basegfx::B2DHomMatrix aTransform(aBackTransform);
+ aRetval.realloc(2);
+
+ if(bEmbossed)
+ {
+ // to bottom-right
+ aTransform.translate(aDiagonalDistance.getX(), aDiagonalDistance.getY());
+ }
+ else
+ {
+ // to top-left
+ aTransform.translate(-aDiagonalDistance.getX(), -aDiagonalDistance.getY());
+ }
+
+ aTransform *= aForwardTransform;
+
+ if(bDefaultTextColor)
+ {
+ // emboss/engrave in black, original forced to white
+ const basegfx::BColorModifier aBColorModifierToGray(basegfx::BColor(0.0));
+ const Primitive2DReference xModifiedColor(new ModifiedColorPrimitive2D(getTextContent(), aBColorModifierToGray));
+ aRetval[0] = Primitive2DReference(new TransformPrimitive2D(aTransform, Primitive2DSequence(&xModifiedColor, 1)));
+
+ // add original, too
+ const basegfx::BColorModifier aBColorModifierToWhite(basegfx::BColor(1.0));
+ aRetval[1] = Primitive2DReference(new ModifiedColorPrimitive2D(getTextContent(), aBColorModifierToWhite));
+ }
+ else
+ {
+ // emboss/engrave in gray, keep original's color
+ const basegfx::BColorModifier aBColorModifierToGray(basegfx::BColor(0.75)); // 192
+ const Primitive2DReference xModifiedColor(new ModifiedColorPrimitive2D(getTextContent(), aBColorModifierToGray));
+ aRetval[0] = Primitive2DReference(new TransformPrimitive2D(aTransform, Primitive2DSequence(&xModifiedColor, 1)));
+
+ // add original, too
+ aRetval[1] = Primitive2DReference(new GroupPrimitive2D(getTextContent()));
+ }
+
+ break;
+ }
+ case TEXTEFFECTSTYLE2D_OUTLINE:
+ {
+ // create transform primitives in all directions
+ basegfx::B2DHomMatrix aTransform;
+ aRetval.realloc(9);
+
+ aTransform.set(0, 2, aDistance.getX());
+ aTransform.set(1, 2, 0.0);
+ aRetval[0] = Primitive2DReference(new TransformPrimitive2D(aTransform, getTextContent()));
+
+ aTransform.set(0, 2, aDiagonalDistance.getX());
+ aTransform.set(1, 2, aDiagonalDistance.getY());
+ aRetval[1] = Primitive2DReference(new TransformPrimitive2D(aTransform, getTextContent()));
+
+ aTransform.set(0, 2, 0.0);
+ aTransform.set(1, 2, aDistance.getY());
+ aRetval[2] = Primitive2DReference(new TransformPrimitive2D(aTransform, getTextContent()));
+
+ aTransform.set(0, 2, -aDiagonalDistance.getX());
+ aTransform.set(1, 2, aDiagonalDistance.getY());
+ aRetval[3] = Primitive2DReference(new TransformPrimitive2D(aTransform, getTextContent()));
+
+ aTransform.set(0, 2, -aDistance.getX());
+ aTransform.set(1, 2, 0.0);
+ aRetval[4] = Primitive2DReference(new TransformPrimitive2D(aTransform, getTextContent()));
+
+ aTransform.set(0, 2, -aDiagonalDistance.getX());
+ aTransform.set(1, 2, -aDiagonalDistance.getY());
+ aRetval[5] = Primitive2DReference(new TransformPrimitive2D(aTransform, getTextContent()));
+
+ aTransform.set(0, 2, 0.0);
+ aTransform.set(1, 2, -aDistance.getY());
+ aRetval[6] = Primitive2DReference(new TransformPrimitive2D(aTransform, getTextContent()));
+
+ aTransform.set(0, 2, aDiagonalDistance.getX());
+ aTransform.set(1, 2, -aDiagonalDistance.getY());
+ aRetval[7] = Primitive2DReference(new TransformPrimitive2D(aTransform, getTextContent()));
+
+ // at last, place original over it, but force to white
+ const basegfx::BColorModifier aBColorModifierToWhite(basegfx::BColor(1.0, 1.0, 1.0));
+ aRetval[8] = Primitive2DReference(new ModifiedColorPrimitive2D(getTextContent(), aBColorModifierToWhite));
+
+ break;
+ }
+ }
+
+ return aRetval;
+ }
+
+ TextEffectPrimitive2D::TextEffectPrimitive2D(
+ const Primitive2DSequence& rTextContent,
+ const basegfx::B2DPoint& rRotationCenter,
+ double fDirection,
+ TextEffectStyle2D eTextEffectStyle2D)
+ : BufferedDecompositionPrimitive2D(),
+ maTextContent(rTextContent),
+ maRotationCenter(rRotationCenter),
+ mfDirection(fDirection),
+ meTextEffectStyle2D(eTextEffectStyle2D)
+ {
+ }
+
+ bool TextEffectPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BasePrimitive2D::operator==(rPrimitive))
+ {
+ const TextEffectPrimitive2D& rCompare = (TextEffectPrimitive2D&)rPrimitive;
+
+ return (getTextContent() == rCompare.getTextContent()
+ && getRotationCenter() == rCompare.getRotationCenter()
+ && getDirection() == rCompare.getDirection()
+ && getTextEffectStyle2D() == rCompare.getTextEffectStyle2D());
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange TextEffectPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ // get range of content and grow by used fDiscreteSize. That way it is not necessary to ask
+ // the whole decomposition for it's ranges (which may be expensive with outline mode which
+ // then will ask 9 times at nearly the same content. This may even be refined here using the
+ // TextEffectStyle information, e.g. for TEXTEFFECTSTYLE2D_RELIEF the grow needs only to
+ // be in two directions
+ basegfx::B2DRange aRetval(getB2DRangeFromPrimitive2DSequence(getTextContent(), rViewInformation));
+ aRetval.grow(fDiscreteSize);
+
+ return aRetval;
+ }
+
+ Primitive2DSequence TextEffectPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if(getBuffered2DDecomposition().hasElements())
+ {
+ if(maLastObjectToViewTransformation != rViewInformation.getObjectToViewTransformation())
+ {
+ // conditions of last local decomposition have changed, delete
+ const_cast< TextEffectPrimitive2D* >(this)->setBuffered2DDecomposition(Primitive2DSequence());
+ }
+ }
+
+ if(!getBuffered2DDecomposition().hasElements())
+ {
+ // remember ViewRange and ViewTransformation
+ const_cast< TextEffectPrimitive2D* >(this)->maLastObjectToViewTransformation = rViewInformation.getObjectToViewTransformation();
+ }
+
+ // use parent implementation
+ return BufferedDecompositionPrimitive2D::get2DDecomposition(rViewInformation);
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(TextEffectPrimitive2D, PRIMITIVE2D_ID_TEXTEFFECTPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/textenumsprimitive2d.cxx b/drawinglayer/source/primitive2d/textenumsprimitive2d.cxx
new file mode 100644
index 000000000000..5247d4404ece
--- /dev/null
+++ b/drawinglayer/source/primitive2d/textenumsprimitive2d.cxx
@@ -0,0 +1,124 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/textenumsprimitive2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ TextLine mapFontUnderlineToTextLine(FontUnderline eLineStyle)
+ {
+ switch(eLineStyle)
+ {
+ case UNDERLINE_SINGLE: return TEXT_LINE_SINGLE;
+ case UNDERLINE_DOUBLE: return TEXT_LINE_DOUBLE;
+ case UNDERLINE_DOTTED: return TEXT_LINE_DOTTED;
+ case UNDERLINE_DASH: return TEXT_LINE_DASH;
+ case UNDERLINE_LONGDASH: return TEXT_LINE_LONGDASH;
+ case UNDERLINE_DASHDOT: return TEXT_LINE_DASHDOT;
+ case UNDERLINE_DASHDOTDOT: return TEXT_LINE_DASHDOTDOT;
+ case UNDERLINE_SMALLWAVE: return TEXT_LINE_SMALLWAVE;
+ case UNDERLINE_WAVE: return TEXT_LINE_WAVE;
+ case UNDERLINE_DOUBLEWAVE: return TEXT_LINE_DOUBLEWAVE;
+ case UNDERLINE_BOLD: return TEXT_LINE_BOLD;
+ case UNDERLINE_BOLDDOTTED: return TEXT_LINE_BOLDDOTTED;
+ case UNDERLINE_BOLDDASH: return TEXT_LINE_BOLDDASH;
+ case UNDERLINE_BOLDLONGDASH: return TEXT_LINE_BOLDLONGDASH;
+ case UNDERLINE_BOLDDASHDOT: return TEXT_LINE_BOLDDASHDOT;
+ case UNDERLINE_BOLDDASHDOTDOT: return TEXT_LINE_BOLDDASHDOTDOT;
+ case UNDERLINE_BOLDWAVE: return TEXT_LINE_BOLDWAVE;
+ // FontUnderline_FORCE_EQUAL_SIZE, UNDERLINE_DONTKNOW, UNDERLINE_NONE
+ default: return TEXT_LINE_NONE;
+ }
+ }
+
+ FontUnderline mapTextLineToFontUnderline(TextLine eLineStyle)
+ {
+ switch(eLineStyle)
+ {
+ default: /*TEXT_LINE_NONE*/ return UNDERLINE_NONE;
+ case TEXT_LINE_SINGLE: return UNDERLINE_SINGLE;
+ case TEXT_LINE_DOUBLE: return UNDERLINE_DOUBLE;
+ case TEXT_LINE_DOTTED: return UNDERLINE_DOTTED;
+ case TEXT_LINE_DASH: return UNDERLINE_DASH;
+ case TEXT_LINE_LONGDASH: return UNDERLINE_LONGDASH;
+ case TEXT_LINE_DASHDOT: return UNDERLINE_DASHDOT;
+ case TEXT_LINE_DASHDOTDOT: return UNDERLINE_DASHDOTDOT;
+ case TEXT_LINE_SMALLWAVE: return UNDERLINE_SMALLWAVE;
+ case TEXT_LINE_WAVE: return UNDERLINE_WAVE;
+ case TEXT_LINE_DOUBLEWAVE: return UNDERLINE_DOUBLEWAVE;
+ case TEXT_LINE_BOLD: return UNDERLINE_BOLD;
+ case TEXT_LINE_BOLDDOTTED: return UNDERLINE_BOLDDOTTED;
+ case TEXT_LINE_BOLDDASH: return UNDERLINE_BOLDDASH;
+ case TEXT_LINE_BOLDLONGDASH: return UNDERLINE_LONGDASH;
+ case TEXT_LINE_BOLDDASHDOT: return UNDERLINE_BOLDDASHDOT;
+ case TEXT_LINE_BOLDDASHDOTDOT:return UNDERLINE_BOLDDASHDOT;
+ case TEXT_LINE_BOLDWAVE: return UNDERLINE_BOLDWAVE;
+ }
+ }
+
+ TextStrikeout mapFontStrikeoutToTextStrikeout(FontStrikeout eFontStrikeout)
+ {
+ switch(eFontStrikeout)
+ {
+ case STRIKEOUT_SINGLE: return TEXT_STRIKEOUT_SINGLE;
+ case STRIKEOUT_DOUBLE: return TEXT_STRIKEOUT_DOUBLE;
+ case STRIKEOUT_BOLD: return TEXT_STRIKEOUT_BOLD;
+ case STRIKEOUT_SLASH: return TEXT_STRIKEOUT_SLASH;
+ case STRIKEOUT_X: return TEXT_STRIKEOUT_X;
+ // FontStrikeout_FORCE_EQUAL_SIZE, STRIKEOUT_NONE, STRIKEOUT_DONTKNOW
+ default: return TEXT_STRIKEOUT_NONE;
+ }
+ }
+
+ FontStrikeout mapTextStrikeoutToFontStrikeout(TextStrikeout eTextStrikeout)
+ {
+ switch(eTextStrikeout)
+ {
+ default: /*case primitive2d::TEXT_STRIKEOUT_NONE*/ return STRIKEOUT_NONE;
+ case TEXT_STRIKEOUT_SINGLE: return STRIKEOUT_SINGLE;
+ case TEXT_STRIKEOUT_DOUBLE: return STRIKEOUT_DOUBLE;
+ case TEXT_STRIKEOUT_BOLD: return STRIKEOUT_BOLD;
+ case TEXT_STRIKEOUT_SLASH: return STRIKEOUT_SLASH;
+ case TEXT_STRIKEOUT_X: return STRIKEOUT_X;
+ }
+ }
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/texthierarchyprimitive2d.cxx b/drawinglayer/source/primitive2d/texthierarchyprimitive2d.cxx
new file mode 100644
index 000000000000..896b37252fdc
--- /dev/null
+++ b/drawinglayer/source/primitive2d/texthierarchyprimitive2d.cxx
@@ -0,0 +1,161 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/texthierarchyprimitive2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ TextHierarchyLinePrimitive2D::TextHierarchyLinePrimitive2D(const Primitive2DSequence& rChildren)
+ : GroupPrimitive2D(rChildren)
+ {
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(TextHierarchyLinePrimitive2D, PRIMITIVE2D_ID_TEXTHIERARCHYLINEPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ TextHierarchyParagraphPrimitive2D::TextHierarchyParagraphPrimitive2D(const Primitive2DSequence& rChildren)
+ : GroupPrimitive2D(rChildren)
+ {
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(TextHierarchyParagraphPrimitive2D, PRIMITIVE2D_ID_TEXTHIERARCHYPARAGRAPHPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ TextHierarchyBulletPrimitive2D::TextHierarchyBulletPrimitive2D(const Primitive2DSequence& rChildren)
+ : GroupPrimitive2D(rChildren)
+ {
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(TextHierarchyBulletPrimitive2D, PRIMITIVE2D_ID_TEXTHIERARCHYBULLETPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ TextHierarchyBlockPrimitive2D::TextHierarchyBlockPrimitive2D(const Primitive2DSequence& rChildren)
+ : GroupPrimitive2D(rChildren)
+ {
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(TextHierarchyBlockPrimitive2D, PRIMITIVE2D_ID_TEXTHIERARCHYBLOCKPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ TextHierarchyFieldPrimitive2D::TextHierarchyFieldPrimitive2D(
+ const Primitive2DSequence& rChildren,
+ const FieldType& rFieldType,
+ const rtl::OUString& rString)
+ : GroupPrimitive2D(rChildren),
+ meType(rFieldType),
+ maString(rString)
+ {
+ }
+
+ bool TextHierarchyFieldPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(GroupPrimitive2D::operator==(rPrimitive))
+ {
+ const TextHierarchyFieldPrimitive2D& rCompare = (TextHierarchyFieldPrimitive2D&)rPrimitive;
+
+ return (getType() == rCompare.getType()
+ && getString() == rCompare.getString());
+ }
+
+ return false;
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(TextHierarchyFieldPrimitive2D, PRIMITIVE2D_ID_TEXTHIERARCHYFIELDPRIMITIVE2D)
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ TextHierarchyEditPrimitive2D::TextHierarchyEditPrimitive2D(const Primitive2DSequence& rChildren)
+ : GroupPrimitive2D(rChildren)
+ {
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(TextHierarchyEditPrimitive2D, PRIMITIVE2D_ID_TEXTHIERARCHYEDITPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/textlayoutdevice.cxx b/drawinglayer/source/primitive2d/textlayoutdevice.cxx
new file mode 100644
index 000000000000..c3435333a3d3
--- /dev/null
+++ b/drawinglayer/source/primitive2d/textlayoutdevice.cxx
@@ -0,0 +1,496 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/textlayoutdevice.hxx>
+#include <vcl/timer.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/font.hxx>
+#include <vcl/metric.hxx>
+#include <i18npool/mslangid.hxx>
+#include <drawinglayer/primitive2d/textprimitive2d.hxx>
+#include <vcl/svapp.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+// VDev RevDevice provider
+
+namespace
+{
+ class ImpTimedRefDev : public Timer
+ {
+ ImpTimedRefDev** mppStaticPointerOnMe;
+ VirtualDevice* mpVirDev;
+ sal_uInt32 mnUseCount;
+
+ public:
+ ImpTimedRefDev(ImpTimedRefDev** ppStaticPointerOnMe);
+ ~ImpTimedRefDev();
+ virtual void Timeout();
+
+ VirtualDevice& acquireVirtualDevice();
+ void releaseVirtualDevice();
+ };
+
+ ImpTimedRefDev::ImpTimedRefDev(ImpTimedRefDev** ppStaticPointerOnMe)
+ : mppStaticPointerOnMe(ppStaticPointerOnMe),
+ mpVirDev(0L),
+ mnUseCount(0L)
+ {
+ SetTimeout(3L * 60L * 1000L); // three minutes
+ Start();
+ }
+
+ ImpTimedRefDev::~ImpTimedRefDev()
+ {
+ OSL_ENSURE(0L == mnUseCount, "destruction of a still used ImpTimedRefDev (!)");
+
+ if(mppStaticPointerOnMe && *mppStaticPointerOnMe)
+ {
+ *mppStaticPointerOnMe = 0L;
+ }
+
+ if(mpVirDev)
+ {
+ delete mpVirDev;
+ }
+ }
+
+ void ImpTimedRefDev::Timeout()
+ {
+ // for obvious reasons, do not call anything after this
+ delete (this);
+ }
+
+ VirtualDevice& ImpTimedRefDev::acquireVirtualDevice()
+ {
+ if(!mpVirDev)
+ {
+ mpVirDev = new VirtualDevice();
+ mpVirDev->SetReferenceDevice( VirtualDevice::REFDEV_MODE_MSO1 );
+ }
+
+ if(!mnUseCount)
+ {
+ Stop();
+ }
+
+ mnUseCount++;
+
+ return *mpVirDev;
+ }
+
+ void ImpTimedRefDev::releaseVirtualDevice()
+ {
+ OSL_ENSURE(mnUseCount, "mismatch call number to releaseVirtualDevice() (!)");
+ mnUseCount--;
+
+ if(!mnUseCount)
+ {
+ Start();
+ }
+ }
+} // end of anonymous namespace
+
+//////////////////////////////////////////////////////////////////////////////
+// access to one global ImpTimedRefDev incarnation in namespace drawinglayer::primitive
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ // static pointer here
+ static ImpTimedRefDev* pImpGlobalRefDev = 0L;
+
+ // static methods here
+ VirtualDevice& acquireGlobalVirtualDevice()
+ {
+ if(!pImpGlobalRefDev)
+ {
+ pImpGlobalRefDev = new ImpTimedRefDev(&pImpGlobalRefDev);
+ }
+
+ return pImpGlobalRefDev->acquireVirtualDevice();
+ }
+
+ void releaseGlobalVirtualDevice()
+ {
+ OSL_ENSURE(pImpGlobalRefDev, "releaseGlobalVirtualDevice() without prior acquireGlobalVirtualDevice() call(!)");
+ pImpGlobalRefDev->releaseVirtualDevice();
+ }
+
+ TextLayouterDevice::TextLayouterDevice()
+ : mrDevice(acquireGlobalVirtualDevice())
+ {
+ }
+
+ TextLayouterDevice::~TextLayouterDevice()
+ {
+ releaseGlobalVirtualDevice();
+ }
+
+ void TextLayouterDevice::setFont(const Font& rFont)
+ {
+ mrDevice.SetFont( rFont );
+ }
+
+ void TextLayouterDevice::setFontAttribute(
+ const attribute::FontAttribute& rFontAttribute,
+ double fFontScaleX,
+ double fFontScaleY,
+ const ::com::sun::star::lang::Locale& rLocale)
+ {
+ setFont(getVclFontFromFontAttribute(
+ rFontAttribute,
+ fFontScaleX,
+ fFontScaleY,
+ 0.0,
+ rLocale));
+ }
+
+ double TextLayouterDevice::getOverlineOffset() const
+ {
+ const ::FontMetric& rMetric = mrDevice.GetFontMetric();
+ double fRet = (rMetric.GetIntLeading() / 2.0) - rMetric.GetAscent();
+ return fRet;
+ }
+
+ double TextLayouterDevice::getUnderlineOffset() const
+ {
+ const ::FontMetric& rMetric = mrDevice.GetFontMetric();
+ double fRet = rMetric.GetDescent() / 2.0;
+ return fRet;
+ }
+
+ double TextLayouterDevice::getStrikeoutOffset() const
+ {
+ const ::FontMetric& rMetric = mrDevice.GetFontMetric();
+ double fRet = (rMetric.GetAscent() - rMetric.GetIntLeading()) / 3.0;
+ return fRet;
+ }
+
+ double TextLayouterDevice::getOverlineHeight() const
+ {
+ const ::FontMetric& rMetric = mrDevice.GetFontMetric();
+ double fRet = rMetric.GetIntLeading() / 2.5;
+ return fRet;
+ }
+
+ double TextLayouterDevice::getUnderlineHeight() const
+ {
+ const ::FontMetric& rMetric = mrDevice.GetFontMetric();
+ double fRet = rMetric.GetDescent() / 4.0;
+ return fRet;
+ }
+
+ double TextLayouterDevice::getTextHeight() const
+ {
+ return mrDevice.GetTextHeight();
+ }
+
+ double TextLayouterDevice::getTextWidth(
+ const String& rText,
+ sal_uInt32 nIndex,
+ sal_uInt32 nLength) const
+ {
+ return mrDevice.GetTextWidth(rText, nIndex, nLength);
+ }
+
+ bool TextLayouterDevice::getTextOutlines(
+ basegfx::B2DPolyPolygonVector& rB2DPolyPolyVector,
+ const String& rText,
+ sal_uInt32 nIndex,
+ sal_uInt32 nLength,
+ const ::std::vector< double >& rDXArray) const
+ {
+ const sal_uInt32 nDXArrayCount(rDXArray.size());
+ sal_uInt32 nTextLength(nLength);
+ const sal_uInt32 nStringLength(rText.Len());
+
+ if(nTextLength + nIndex > nStringLength)
+ {
+ nTextLength = nStringLength - nIndex;
+ }
+
+ if(nDXArrayCount)
+ {
+ OSL_ENSURE(nDXArrayCount == nTextLength, "DXArray size does not correspond to text portion size (!)");
+ std::vector< sal_Int32 > aIntegerDXArray(nDXArrayCount);
+
+ for(sal_uInt32 a(0); a < nDXArrayCount; a++)
+ {
+ aIntegerDXArray[a] = basegfx::fround(rDXArray[a]);
+ }
+
+ return mrDevice.GetTextOutlines(
+ rB2DPolyPolyVector,
+ rText,
+ nIndex,
+ nIndex,
+ nLength,
+ true,
+ 0,
+ &(aIntegerDXArray[0]));
+ }
+ else
+ {
+ return mrDevice.GetTextOutlines(
+ rB2DPolyPolyVector,
+ rText,
+ nIndex,
+ nIndex,
+ nLength,
+ true,
+ 0,
+ 0);
+ }
+ }
+
+ basegfx::B2DRange TextLayouterDevice::getTextBoundRect(
+ const String& rText,
+ sal_uInt32 nIndex,
+ sal_uInt32 nLength) const
+ {
+ sal_uInt32 nTextLength(nLength);
+ const sal_uInt32 nStringLength(rText.Len());
+
+ if(nTextLength + nIndex > nStringLength)
+ {
+ nTextLength = nStringLength - nIndex;
+ }
+
+ if(nTextLength)
+ {
+ Rectangle aRect;
+
+ mrDevice.GetTextBoundRect(
+ aRect,
+ rText,
+ nIndex,
+ nIndex,
+ nLength);
+
+ // #i104432#, #i102556# take empty results into account
+ if(!aRect.IsEmpty())
+ {
+ return basegfx::B2DRange(
+ aRect.Left(), aRect.Top(),
+ aRect.Right(), aRect.Bottom());
+ }
+ }
+
+ return basegfx::B2DRange();
+ }
+
+ double TextLayouterDevice::getFontAscent() const
+ {
+ const ::FontMetric& rMetric = mrDevice.GetFontMetric();
+ return rMetric.GetAscent();
+ }
+
+ double TextLayouterDevice::getFontDescent() const
+ {
+ const ::FontMetric& rMetric = mrDevice.GetFontMetric();
+ return rMetric.GetDescent();
+ }
+
+ void TextLayouterDevice::addTextRectActions(
+ const Rectangle& rRectangle,
+ const String& rText,
+ sal_uInt16 nStyle,
+ GDIMetaFile& rGDIMetaFile) const
+ {
+ mrDevice.AddTextRectActions(
+ rRectangle, rText, nStyle, rGDIMetaFile);
+ }
+
+ ::std::vector< double > TextLayouterDevice::getTextArray(
+ const String& rText,
+ sal_uInt32 nIndex,
+ sal_uInt32 nLength) const
+ {
+ ::std::vector< double > aRetval;
+ sal_uInt32 nTextLength(nLength);
+ const sal_uInt32 nStringLength(rText.Len());
+
+ if(nTextLength + nIndex > nStringLength)
+ {
+ nTextLength = nStringLength - nIndex;
+ }
+
+ if(nTextLength)
+ {
+ aRetval.reserve(nTextLength);
+ sal_Int32* pArray = new sal_Int32[nTextLength];
+ mrDevice.GetTextArray(rText, pArray, nIndex, nLength);
+
+ for(sal_uInt32 a(0); a < nTextLength; a++)
+ {
+ aRetval.push_back(pArray[a]);
+ }
+ }
+
+ return aRetval;
+ }
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// helper methods for vcl font handling
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Font getVclFontFromFontAttribute(
+ const attribute::FontAttribute& rFontAttribute,
+ double fFontScaleX,
+ double fFontScaleY,
+ double fFontRotation,
+ const ::com::sun::star::lang::Locale& rLocale)
+ {
+ // detect FontScaling
+ const sal_uInt32 nHeight(basegfx::fround(fabs(fFontScaleY)));
+ const sal_uInt32 nWidth(basegfx::fround(fabs(fFontScaleX)));
+ const bool bFontIsScaled(nHeight != nWidth);
+
+#ifdef WIN32
+ // for WIN32 systems, start with creating an unscaled font. If FontScaling
+ // is wanted, that width needs to be adapted using FontMetric again to get a
+ // width of the unscaled font
+ Font aRetval(
+ rFontAttribute.getFamilyName(),
+ rFontAttribute.getStyleName(),
+ Size(0, nHeight));
+#else
+ // for non-WIN32 systems things are easier since these accept a Font creation
+ // with initially nWidth != nHeight for FontScaling. Despite that, use zero for
+ // FontWidth when no scaling is used to explicitely have that zero when e.g. the
+ // Font would be recorded in a MetaFile (The MetaFile FontAction WILL record a
+ // set FontWidth; import that in a WIN32 system, and trouble is there)
+ Font aRetval(
+ rFontAttribute.getFamilyName(),
+ rFontAttribute.getStyleName(),
+ Size(bFontIsScaled ? nWidth : 0, nHeight));
+#endif
+ // define various other FontAttribute
+ aRetval.SetAlign(ALIGN_BASELINE);
+ aRetval.SetCharSet(rFontAttribute.getSymbol() ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE);
+ aRetval.SetVertical(rFontAttribute.getVertical() ? TRUE : FALSE);
+ aRetval.SetWeight(static_cast<FontWeight>(rFontAttribute.getWeight()));
+ aRetval.SetItalic(rFontAttribute.getItalic() ? ITALIC_NORMAL : ITALIC_NONE);
+ aRetval.SetOutline(rFontAttribute.getOutline());
+ aRetval.SetPitch(rFontAttribute.getMonospaced() ? PITCH_FIXED : PITCH_VARIABLE);
+ aRetval.SetLanguage(MsLangId::convertLocaleToLanguage(rLocale));
+
+#ifdef WIN32
+ // for WIN32 systems, correct the FontWidth if FontScaling is used
+ if(bFontIsScaled && nHeight > 0)
+ {
+ const FontMetric aUnscaledFontMetric(Application::GetDefaultDevice()->GetFontMetric(aRetval));
+
+ if(aUnscaledFontMetric.GetWidth() > 0)
+ {
+ const double fScaleFactor((double)nWidth / (double)nHeight);
+ const sal_uInt32 nScaledWidth(basegfx::fround((double)aUnscaledFontMetric.GetWidth() * fScaleFactor));
+ aRetval.SetWidth(nScaledWidth);
+ }
+ }
+#endif
+ // handle FontRotation (if defined)
+ if(!basegfx::fTools::equalZero(fFontRotation))
+ {
+ sal_Int16 aRotate10th((sal_Int16)(fFontRotation * (-1800.0/F_PI)));
+ aRetval.SetOrientation(aRotate10th % 3600);
+ }
+
+ return aRetval;
+ }
+
+ attribute::FontAttribute getFontAttributeFromVclFont(
+ basegfx::B2DVector& o_rSize,
+ const Font& rFont,
+ bool bRTL,
+ bool bBiDiStrong)
+ {
+ const attribute::FontAttribute aRetval(
+ rFont.GetName(),
+ rFont.GetStyleName(),
+ static_cast<sal_uInt16>(rFont.GetWeight()),
+ RTL_TEXTENCODING_SYMBOL == rFont.GetCharSet(),
+ rFont.IsVertical(),
+ ITALIC_NONE != rFont.GetItalic(),
+ PITCH_FIXED == rFont.GetPitch(),
+ rFont.IsOutline(),
+ bRTL,
+ bBiDiStrong);
+ // TODO: eKerning
+
+ // set FontHeight and init to no FontScaling
+ o_rSize.setY(rFont.GetSize().getHeight() > 0 ? rFont.GetSize().getHeight() : 0);
+ o_rSize.setX(o_rSize.getY());
+
+#ifdef WIN32
+ // for WIN32 systems, the FontScaling at the Font is detected by
+ // checking that FontWidth != 0. When FontScaling is used, WIN32
+ // needs to do extra stuff to detect the correct width (since it's
+ // zero and not equal the font height) and it's relationship to
+ // the height
+ if(rFont.GetSize().getWidth() > 0)
+ {
+ Font aUnscaledFont(rFont);
+ aUnscaledFont.SetWidth(0);
+ const FontMetric aUnscaledFontMetric(Application::GetDefaultDevice()->GetFontMetric(aUnscaledFont));
+
+ if(aUnscaledFontMetric.GetWidth() > 0)
+ {
+ const double fScaleFactor((double)rFont.GetSize().getWidth() / (double)aUnscaledFontMetric.GetWidth());
+ o_rSize.setX(fScaleFactor * o_rSize.getY());
+ }
+ }
+#else
+ // For non-WIN32 systems the detection is the same, but the value
+ // is easier achieved since width == height is interpreted as no
+ // scaling. Ergo, Width == 0 means width == height, and width != 0
+ // means the scaling is in the direct relation of width to height
+ if(rFont.GetSize().getWidth() > 0)
+ {
+ o_rSize.setX((double)rFont.GetSize().getWidth());
+ }
+#endif
+ return aRetval;
+ }
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/textlineprimitive2d.cxx b/drawinglayer/source/primitive2d/textlineprimitive2d.cxx
new file mode 100644
index 000000000000..f04021c77f7f
--- /dev/null
+++ b/drawinglayer/source/primitive2d/textlineprimitive2d.cxx
@@ -0,0 +1,312 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/textlineprimitive2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+#include <drawinglayer/attribute/strokeattribute.hxx>
+#include <drawinglayer/attribute/lineattribute.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence TextLinePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ Primitive2DSequence xRetval;
+
+ if(TEXT_LINE_NONE != getTextLine())
+ {
+ bool bDoubleLine(false);
+ bool bWaveLine(false);
+ bool bBoldLine(false);
+ const int* pDotDashArray(0);
+ basegfx::B2DLineJoin eLineJoin(basegfx::B2DLINEJOIN_NONE);
+ double fOffset(getOffset());
+ double fHeight(getHeight());
+
+ static const int aDottedArray[] = { 1, 1, 0}; // DOTTED LINE
+ static const int aDotDashArray[] = { 1, 1, 4, 1, 0}; // DASHDOT
+ static const int aDashDotDotArray[] = { 1, 1, 1, 1, 4, 1, 0}; // DASHDOTDOT
+ static const int aDashedArray[] = { 5, 2, 0}; // DASHED LINE
+ static const int aLongDashArray[] = { 7, 2, 0}; // LONGDASH
+
+ // get decomposition
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ getObjectTransformation().decompose(aScale, aTranslate, fRotate, fShearX);
+
+ switch(getTextLine())
+ {
+ default: // case TEXT_LINE_SINGLE:
+ {
+ break;
+ }
+ case TEXT_LINE_DOUBLE:
+ {
+ bDoubleLine = true;
+ break;
+ }
+ case TEXT_LINE_DOTTED:
+ {
+ pDotDashArray = aDottedArray;
+ break;
+ }
+ case TEXT_LINE_DASH:
+ {
+ pDotDashArray = aDashedArray;
+ break;
+ }
+ case TEXT_LINE_LONGDASH:
+ {
+ pDotDashArray = aLongDashArray;
+ break;
+ }
+ case TEXT_LINE_DASHDOT:
+ {
+ pDotDashArray = aDotDashArray;
+ break;
+ }
+ case TEXT_LINE_DASHDOTDOT:
+ {
+ pDotDashArray = aDashDotDotArray;
+ break;
+ }
+ case TEXT_LINE_SMALLWAVE:
+ {
+ bWaveLine = true;
+ break;
+ }
+ case TEXT_LINE_WAVE:
+ {
+ bWaveLine = true;
+ break;
+ }
+ case TEXT_LINE_DOUBLEWAVE:
+ {
+ bDoubleLine = true;
+ bWaveLine = true;
+ break;
+ }
+ case TEXT_LINE_BOLD:
+ {
+ bBoldLine = true;
+ break;
+ }
+ case TEXT_LINE_BOLDDOTTED:
+ {
+ bBoldLine = true;
+ pDotDashArray = aDottedArray;
+ break;
+ }
+ case TEXT_LINE_BOLDDASH:
+ {
+ bBoldLine = true;
+ pDotDashArray = aDashedArray;
+ break;
+ }
+ case TEXT_LINE_BOLDLONGDASH:
+ {
+ bBoldLine = true;
+ pDotDashArray = aLongDashArray;
+ break;
+ }
+ case TEXT_LINE_BOLDDASHDOT:
+ {
+ bBoldLine = true;
+ pDotDashArray = aDotDashArray;
+ break;
+ }
+ case TEXT_LINE_BOLDDASHDOTDOT:
+ {
+ bBoldLine = true;
+ pDotDashArray = aDashDotDotArray;
+ break;
+ }
+ case TEXT_LINE_BOLDWAVE:
+ {
+ bWaveLine = true;
+ bBoldLine = true;
+ break;
+ }
+ }
+
+ if(bBoldLine)
+ {
+ fHeight *= 2.0;
+ }
+
+ if(bDoubleLine)
+ {
+ fOffset -= 0.50 * fHeight;
+ fHeight *= 0.64;
+ }
+
+ if(bWaveLine)
+ {
+ eLineJoin = basegfx::B2DLINEJOIN_ROUND;
+ fHeight *= 0.25;
+ }
+
+ // prepare Line and Stroke Attributes
+ const attribute::LineAttribute aLineAttribute(getLineColor(), fHeight, eLineJoin);
+ attribute::StrokeAttribute aStrokeAttribute;
+
+ if(pDotDashArray)
+ {
+ ::std::vector< double > aDoubleArray;
+
+ for(const int* p = pDotDashArray; *p; ++p)
+ {
+ aDoubleArray.push_back((double)(*p) * fHeight);
+ }
+
+ aStrokeAttribute = attribute::StrokeAttribute(aDoubleArray);
+ }
+
+ // create base polygon and new primitive
+ basegfx::B2DPolygon aLine;
+ Primitive2DReference aNewPrimitive;
+
+ aLine.append(basegfx::B2DPoint(0.0, fOffset));
+ aLine.append(basegfx::B2DPoint(getWidth(), fOffset));
+
+ const basegfx::B2DHomMatrix aUnscaledTransform(
+ basegfx::tools::createShearXRotateTranslateB2DHomMatrix(
+ fShearX, fRotate, aTranslate));
+
+ aLine.transform(aUnscaledTransform);
+
+ if(bWaveLine)
+ {
+ double fWaveWidth(10.6 * fHeight);
+
+ if(TEXT_LINE_SMALLWAVE == getTextLine())
+ {
+ fWaveWidth *= 0.7;
+ }
+ else if(TEXT_LINE_WAVE == getTextLine())
+ {
+ // extra multiply to get the same WaveWidth as with the bold version
+ fWaveWidth *= 2.0;
+ }
+
+ aNewPrimitive = Primitive2DReference(new PolygonWavePrimitive2D(aLine, aLineAttribute, aStrokeAttribute, fWaveWidth, fWaveWidth * 0.5));
+ }
+ else
+ {
+ aNewPrimitive = Primitive2DReference(new PolygonStrokePrimitive2D(aLine, aLineAttribute, aStrokeAttribute));
+ }
+
+ // add primitive
+ appendPrimitive2DReferenceToPrimitive2DSequence(xRetval, aNewPrimitive);
+
+ if(bDoubleLine)
+ {
+ // double line, create 2nd primitive with offset using TransformPrimitive based on
+ // already created NewPrimitive
+ double fLineDist(2.3 * fHeight);
+
+ if(bWaveLine)
+ {
+ fLineDist = 6.3 * fHeight;
+ }
+
+ // move base point of text to 0.0 and de-rotate
+ basegfx::B2DHomMatrix aTransform(basegfx::tools::createTranslateB2DHomMatrix(
+ -aTranslate.getX(), -aTranslate.getY()));
+ aTransform.rotate(-fRotate);
+
+ // translate in Y by offset
+ aTransform.translate(0.0, fLineDist);
+
+ // move back and rotate
+ aTransform.rotate(fRotate);
+ aTransform.translate(aTranslate.getX(), aTranslate.getY());
+
+ // add transform primitive
+ const Primitive2DSequence aContent(&aNewPrimitive, 1);
+ appendPrimitive2DReferenceToPrimitive2DSequence(xRetval,
+ Primitive2DReference(new TransformPrimitive2D(aTransform, aContent)));
+ }
+ }
+
+ return xRetval;
+ }
+
+ TextLinePrimitive2D::TextLinePrimitive2D(
+ const basegfx::B2DHomMatrix& rObjectTransformation,
+ double fWidth,
+ double fOffset,
+ double fHeight,
+ TextLine eTextLine,
+ const basegfx::BColor& rLineColor)
+ : BufferedDecompositionPrimitive2D(),
+ maObjectTransformation(rObjectTransformation),
+ mfWidth(fWidth),
+ mfOffset(fOffset),
+ mfHeight(fHeight),
+ meTextLine(eTextLine),
+ maLineColor(rLineColor)
+ {
+ }
+
+ bool TextLinePrimitive2D::operator==( const BasePrimitive2D& rPrimitive ) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const TextLinePrimitive2D& rCompare = (TextLinePrimitive2D&)rPrimitive;
+
+ return (getObjectTransformation() == rCompare.getObjectTransformation()
+ && getWidth() == rCompare.getWidth()
+ && getOffset() == rCompare.getOffset()
+ && getHeight() == rCompare.getHeight()
+ && getTextLine() == rCompare.getTextLine()
+ && getLineColor() == rCompare.getLineColor());
+ }
+
+ return false;
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(TextLinePrimitive2D, PRIMITIVE2D_ID_TEXTLINEPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/textprimitive2d.cxx b/drawinglayer/source/primitive2d/textprimitive2d.cxx
new file mode 100644
index 000000000000..131249c6272f
--- /dev/null
+++ b/drawinglayer/source/primitive2d/textprimitive2d.cxx
@@ -0,0 +1,348 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/textprimitive2d.hxx>
+#include <drawinglayer/primitive2d/textlayoutdevice.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+#include <drawinglayer/primitive2d/texteffectprimitive2d.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace
+{
+ // adapts fontScale for usage with TextLayouter. Input is rScale which is the extracted
+ // scale from a text transformation. A copy is modified so that it contains only positive
+ // scalings and XY-equal scalings to allow to get a non-X-scaled Vcl-Font for TextLayouter.
+ // rScale is adapted accordingly to contain the corrected scale which would need to be
+ // applied to e.g. outlines received from TextLayouter under usage of fontScale. This
+ // includes Y-Scale, X-Scale-correction and mirrorings.
+ basegfx::B2DVector getCorrectedScaleAndFontScale(basegfx::B2DVector& rScale)
+ {
+ // copy input value
+ basegfx::B2DVector aFontScale(rScale);
+
+ // correct FontHeight settings
+ if(basegfx::fTools::equalZero(aFontScale.getY()))
+ {
+ // no font height; choose one and adapt scale to get back to original scaling
+ static double fDefaultFontScale(100.0);
+ rScale.setY(1.0 / fDefaultFontScale);
+ aFontScale.setY(fDefaultFontScale);
+ }
+ else if(basegfx::fTools::less(aFontScale.getY(), 0.0))
+ {
+ // negative font height; invert and adapt scale to get back to original scaling
+ aFontScale.setY(-aFontScale.getY());
+ rScale.setY(-1.0);
+ }
+ else
+ {
+ // positive font height; adapt scale; scaling will be part of the polygons
+ rScale.setY(1.0);
+ }
+
+ // correct FontWidth settings
+ if(basegfx::fTools::equal(aFontScale.getX(), aFontScale.getY()))
+ {
+ // no FontScale, adapt scale
+ rScale.setX(1.0);
+ }
+ else
+ {
+ // If FontScale is used, force to no FontScale to get a non-scaled VCL font.
+ // Adapt scaling in X accordingly.
+ rScale.setX(aFontScale.getX() / aFontScale.getY());
+ aFontScale.setX(aFontScale.getY());
+ }
+
+ return aFontScale;
+ }
+} // end of anonymous namespace
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ void TextSimplePortionPrimitive2D::getTextOutlinesAndTransformation(basegfx::B2DPolyPolygonVector& rTarget, basegfx::B2DHomMatrix& rTransformation) const
+ {
+ if(getTextLength())
+ {
+ // decompose object transformation to single values
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+
+ // if decomposition returns false, create no geometry since e.g. scaling may
+ // be zero
+ if(getTextTransform().decompose(aScale, aTranslate, fRotate, fShearX))
+ {
+ // handle special case: If scale is negative in (x,y) (3rd quadrant), it can
+ // be expressed as rotation by PI
+ if(basegfx::fTools::less(aScale.getX(), 0.0) && basegfx::fTools::less(aScale.getY(), 0.0))
+ {
+ aScale = basegfx::absolute(aScale);
+ fRotate += F_PI;
+ }
+
+ // for the TextLayouterDevice, it is necessary to have a scaling representing
+ // the font size. Since we want to extract polygons here, it is okay to
+ // work just with scaling and to ignore shear, rotation and translation,
+ // all that can be applied to the polygons later
+ const basegfx::B2DVector aFontScale(getCorrectedScaleAndFontScale(aScale));
+
+ // prepare textlayoutdevice
+ TextLayouterDevice aTextLayouter;
+ aTextLayouter.setFontAttribute(
+ getFontAttribute(),
+ aFontScale.getX(),
+ aFontScale.getY(),
+ getLocale());
+
+ // When getting outlines from stretched text (aScale.getX() != 1.0) it
+ // is necessary to inverse-scale the DXArray (if used) to not get the
+ // outlines already aligned to given, but wrong DXArray
+ if(getDXArray().size() && !basegfx::fTools::equal(aScale.getX(), 1.0))
+ {
+ ::std::vector< double > aScaledDXArray = getDXArray();
+ const double fDXArrayScale(1.0 / aScale.getX());
+
+ for(sal_uInt32 a(0); a < aScaledDXArray.size(); a++)
+ {
+ aScaledDXArray[a] *= fDXArrayScale;
+ }
+
+ // get the text outlines
+ aTextLayouter.getTextOutlines(
+ rTarget,
+ getText(),
+ getTextPosition(),
+ getTextLength(),
+ aScaledDXArray);
+ }
+ else
+ {
+ // get the text outlines
+ aTextLayouter.getTextOutlines(
+ rTarget,
+ getText(),
+ getTextPosition(),
+ getTextLength(),
+ getDXArray());
+ }
+
+ // create primitives for the outlines
+ const sal_uInt32 nCount(rTarget.size());
+
+ if(nCount)
+ {
+ // prepare object transformation for polygons
+ rTransformation = basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
+ aScale, fShearX, fRotate, aTranslate);
+ }
+ }
+ }
+ }
+
+ Primitive2DSequence TextSimplePortionPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ Primitive2DSequence aRetval;
+
+ if(getTextLength())
+ {
+ basegfx::B2DPolyPolygonVector aB2DPolyPolyVector;
+ basegfx::B2DHomMatrix aPolygonTransform;
+
+ // get text outlines and their object transformation
+ getTextOutlinesAndTransformation(aB2DPolyPolyVector, aPolygonTransform);
+
+ // create primitives for the outlines
+ const sal_uInt32 nCount(aB2DPolyPolyVector.size());
+
+ if(nCount)
+ {
+ // alloc space for the primitives
+ aRetval.realloc(nCount);
+
+ // color-filled polypolygons
+ for(sal_uInt32 a(0L); a < nCount; a++)
+ {
+ // prepare polypolygon
+ basegfx::B2DPolyPolygon& rPolyPolygon = aB2DPolyPolyVector[a];
+ rPolyPolygon.transform(aPolygonTransform);
+ aRetval[a] = new PolyPolygonColorPrimitive2D(rPolyPolygon, getFontColor());
+ }
+
+ if(getFontAttribute().getOutline())
+ {
+ // decompose polygon transformation to single values
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ aPolygonTransform.decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // create outline text effect with current content and replace
+ Primitive2DReference aNewTextEffect(new TextEffectPrimitive2D(
+ aRetval,
+ aTranslate,
+ fRotate,
+ TEXTEFFECTSTYLE2D_OUTLINE));
+
+ aRetval = Primitive2DSequence(&aNewTextEffect, 1);
+ }
+ }
+ }
+
+ return aRetval;
+ }
+
+ TextSimplePortionPrimitive2D::TextSimplePortionPrimitive2D(
+ const basegfx::B2DHomMatrix& rNewTransform,
+ const String& rText,
+ xub_StrLen aTextPosition,
+ xub_StrLen aTextLength,
+ const ::std::vector< double >& rDXArray,
+ const attribute::FontAttribute& rFontAttribute,
+ const ::com::sun::star::lang::Locale& rLocale,
+ const basegfx::BColor& rFontColor,
+ bool bFilled,
+ long nWidthToFill)
+ : BufferedDecompositionPrimitive2D(),
+ maTextTransform(rNewTransform),
+ maText(rText),
+ maTextPosition(aTextPosition),
+ maTextLength(aTextLength),
+ maDXArray(rDXArray),
+ maFontAttribute(rFontAttribute),
+ maLocale(rLocale),
+ maFontColor(rFontColor),
+ maB2DRange(),
+ mbFilled(bFilled),
+ mnWidthToFill(nWidthToFill)
+ {
+#ifdef DBG_UTIL
+ const xub_StrLen aStringLength(getText().Len());
+ OSL_ENSURE(aStringLength >= getTextPosition() && aStringLength >= getTextPosition() + getTextLength(),
+ "TextSimplePortionPrimitive2D with text out of range (!)");
+#endif
+ }
+
+ bool LocalesAreEqual(const ::com::sun::star::lang::Locale& rA, const ::com::sun::star::lang::Locale& rB)
+ {
+ return (rA.Language == rB.Language
+ && rA.Country == rB.Country
+ && rA.Variant == rB.Variant);
+ }
+
+ bool TextSimplePortionPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const TextSimplePortionPrimitive2D& rCompare = (TextSimplePortionPrimitive2D&)rPrimitive;
+
+ return (getTextTransform() == rCompare.getTextTransform()
+ && getText() == rCompare.getText()
+ && getTextPosition() == rCompare.getTextPosition()
+ && getTextLength() == rCompare.getTextLength()
+ && getDXArray() == rCompare.getDXArray()
+ && getFontAttribute() == rCompare.getFontAttribute()
+ && LocalesAreEqual(getLocale(), rCompare.getLocale())
+ && getFontColor() == rCompare.getFontColor()
+ && mbFilled == rCompare.mbFilled
+ && mnWidthToFill == rCompare.mnWidthToFill);
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange TextSimplePortionPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ if(maB2DRange.isEmpty() && getTextLength())
+ {
+ // get TextBoundRect as base size
+ // decompose object transformation to single values
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+
+ if(getTextTransform().decompose(aScale, aTranslate, fRotate, fShearX))
+ {
+ // for the TextLayouterDevice, it is necessary to have a scaling representing
+ // the font size. Since we want to extract polygons here, it is okay to
+ // work just with scaling and to ignore shear, rotation and translation,
+ // all that can be applied to the polygons later
+ const basegfx::B2DVector aFontScale(getCorrectedScaleAndFontScale(aScale));
+
+ // prepare textlayoutdevice
+ TextLayouterDevice aTextLayouter;
+ aTextLayouter.setFontAttribute(
+ getFontAttribute(),
+ aFontScale.getX(),
+ aFontScale.getY(),
+ getLocale());
+
+ // get basic text range
+ basegfx::B2DRange aNewRange(aTextLayouter.getTextBoundRect(getText(), getTextPosition(), getTextLength()));
+
+ // #i104432#, #i102556# take empty results into account
+ if(!aNewRange.isEmpty())
+ {
+ // prepare object transformation for range
+ const basegfx::B2DHomMatrix aRangeTransformation(basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
+ aScale, fShearX, fRotate, aTranslate));
+
+ // apply range transformation to it
+ aNewRange.transform(aRangeTransformation);
+
+ // assign to buffered value
+ const_cast< TextSimplePortionPrimitive2D* >(this)->maB2DRange = aNewRange;
+ }
+ }
+ }
+
+ return maB2DRange;
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(TextSimplePortionPrimitive2D, PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/textstrikeoutprimitive2d.cxx b/drawinglayer/source/primitive2d/textstrikeoutprimitive2d.cxx
new file mode 100644
index 000000000000..c278ba74949b
--- /dev/null
+++ b/drawinglayer/source/primitive2d/textstrikeoutprimitive2d.cxx
@@ -0,0 +1,289 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/textstrikeoutprimitive2d.hxx>
+#include <drawinglayer/primitive2d/textlayoutdevice.hxx>
+#include <drawinglayer/primitive2d/textprimitive2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <drawinglayer/attribute/lineattribute.hxx>
+#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ BaseTextStrikeoutPrimitive2D::BaseTextStrikeoutPrimitive2D(
+ const basegfx::B2DHomMatrix& rObjectTransformation,
+ double fWidth,
+ const basegfx::BColor& rFontColor)
+ : BufferedDecompositionPrimitive2D(),
+ maObjectTransformation(rObjectTransformation),
+ mfWidth(fWidth),
+ maFontColor(rFontColor)
+ {
+ }
+
+ bool BaseTextStrikeoutPrimitive2D::operator==( const BasePrimitive2D& rPrimitive ) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const BaseTextStrikeoutPrimitive2D& rCompare = (BaseTextStrikeoutPrimitive2D&)rPrimitive;
+
+ return (getObjectTransformation() == rCompare.getObjectTransformation()
+ && getWidth() == rCompare.getWidth()
+ && getFontColor() == rCompare.getFontColor());
+ }
+
+ return false;
+ }
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence TextCharacterStrikeoutPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ // strikeout with character
+ const String aSingleCharString(getStrikeoutChar());
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+
+ // get decomposition
+ getObjectTransformation().decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // prepare TextLayouter
+ TextLayouterDevice aTextLayouter;
+
+ aTextLayouter.setFontAttribute(
+ getFontAttribute(),
+ aScale.getX(),
+ aScale.getY(),
+ getLocale());
+
+ const double fStrikeCharWidth(aTextLayouter.getTextWidth(aSingleCharString, 0, 1));
+ const double fStrikeCharCount(fabs(getWidth()/fStrikeCharWidth));
+ const sal_uInt32 nStrikeCharCount(static_cast< sal_uInt32 >(fStrikeCharCount + 0.5));
+ std::vector<double> aDXArray(nStrikeCharCount);
+ String aStrikeoutString;
+
+ for(sal_uInt32 a(0); a < nStrikeCharCount; a++)
+ {
+ aStrikeoutString += aSingleCharString;
+ aDXArray[a] = (a + 1) * fStrikeCharWidth;
+ }
+
+ Primitive2DReference xReference(
+ new TextSimplePortionPrimitive2D(
+ getObjectTransformation(),
+ aStrikeoutString,
+ 0,
+ aStrikeoutString.Len(),
+ aDXArray,
+ getFontAttribute(),
+ getLocale(),
+ getFontColor()));
+
+ return Primitive2DSequence(&xReference, 1);
+ }
+
+ TextCharacterStrikeoutPrimitive2D::TextCharacterStrikeoutPrimitive2D(
+ const basegfx::B2DHomMatrix& rObjectTransformation,
+ double fWidth,
+ const basegfx::BColor& rFontColor,
+ sal_Unicode aStrikeoutChar,
+ const attribute::FontAttribute& rFontAttribute,
+ const ::com::sun::star::lang::Locale& rLocale)
+ : BaseTextStrikeoutPrimitive2D(rObjectTransformation, fWidth, rFontColor),
+ maStrikeoutChar(aStrikeoutChar),
+ maFontAttribute(rFontAttribute),
+ maLocale(rLocale)
+ {
+ }
+
+ bool TextCharacterStrikeoutPrimitive2D::operator==( const BasePrimitive2D& rPrimitive ) const
+ {
+ if(BaseTextStrikeoutPrimitive2D::operator==(rPrimitive))
+ {
+ const TextCharacterStrikeoutPrimitive2D& rCompare = (TextCharacterStrikeoutPrimitive2D&)rPrimitive;
+
+ return (getStrikeoutChar() == rCompare.getStrikeoutChar()
+ && getFontAttribute() == rCompare.getFontAttribute()
+ && LocalesAreEqual(getLocale(), rCompare.getLocale()));
+ }
+
+ return false;
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(TextCharacterStrikeoutPrimitive2D, PRIMITIVE2D_ID_TEXTCHARACTERSTRIKEOUTPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence TextGeometryStrikeoutPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ OSL_ENSURE(TEXT_STRIKEOUT_SLASH != getTextStrikeout() && TEXT_STRIKEOUT_X != getTextStrikeout(),
+ "Wrong TEXT_STRIKEOUT type; a TextCharacterStrikeoutPrimitive2D should be used (!)");
+
+ // strikeout with geometry
+ double fStrikeoutHeight(getHeight());
+ double fStrikeoutOffset(getOffset());
+ bool bDoubleLine(false);
+
+ // get decomposition
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ getObjectTransformation().decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // set line attribute
+ switch(getTextStrikeout())
+ {
+ default : // case primitive2d::TEXT_STRIKEOUT_SINGLE:
+ {
+ break;
+ }
+ case primitive2d::TEXT_STRIKEOUT_DOUBLE:
+ {
+ bDoubleLine = true;
+ break;
+ }
+ case primitive2d::TEXT_STRIKEOUT_BOLD:
+ {
+ fStrikeoutHeight *= 2.0;
+ break;
+ }
+ }
+
+ if(bDoubleLine)
+ {
+ fStrikeoutOffset -= 0.50 * fStrikeoutHeight;
+ fStrikeoutHeight *= 0.64;
+ }
+
+ // create base polygon and new primitive
+ basegfx::B2DPolygon aStrikeoutLine;
+
+ aStrikeoutLine.append(basegfx::B2DPoint(0.0, -fStrikeoutOffset));
+ aStrikeoutLine.append(basegfx::B2DPoint(getWidth(), -fStrikeoutOffset));
+
+ const basegfx::B2DHomMatrix aUnscaledTransform(
+ basegfx::tools::createShearXRotateTranslateB2DHomMatrix(
+ fShearX, fRotate, aTranslate));
+
+ aStrikeoutLine.transform(aUnscaledTransform);
+
+ // add primitive
+ const attribute::LineAttribute aLineAttribute(getFontColor(), fStrikeoutHeight, basegfx::B2DLINEJOIN_NONE);
+ Primitive2DSequence xRetval(1);
+ xRetval[0] = Primitive2DReference(new PolygonStrokePrimitive2D(aStrikeoutLine, aLineAttribute));
+
+ if(bDoubleLine)
+ {
+ // double line, create 2nd primitive with offset using TransformPrimitive based on
+ // already created NewPrimitive
+ const double fLineDist(2.0 * fStrikeoutHeight);
+
+ // move base point of text to 0.0 and de-rotate
+ basegfx::B2DHomMatrix aTransform(basegfx::tools::createTranslateB2DHomMatrix(
+ -aTranslate.getX(), -aTranslate.getY()));
+ aTransform.rotate(-fRotate);
+
+ // translate in Y by offset
+ aTransform.translate(0.0, -fLineDist);
+
+ // move back and rotate
+ aTransform.rotate(fRotate);
+ aTransform.translate(aTranslate.getX(), aTranslate.getY());
+
+ // add transform primitive
+ appendPrimitive2DReferenceToPrimitive2DSequence(xRetval,
+ Primitive2DReference(
+ new TransformPrimitive2D(
+ aTransform,
+ xRetval)));
+ }
+
+ return xRetval;
+ }
+
+ TextGeometryStrikeoutPrimitive2D::TextGeometryStrikeoutPrimitive2D(
+ const basegfx::B2DHomMatrix& rObjectTransformation,
+ double fWidth,
+ const basegfx::BColor& rFontColor,
+ double fHeight,
+ double fOffset,
+ TextStrikeout eTextStrikeout)
+ : BaseTextStrikeoutPrimitive2D(rObjectTransformation, fWidth, rFontColor),
+ mfHeight(fHeight),
+ mfOffset(fOffset),
+ meTextStrikeout(eTextStrikeout)
+ {
+ }
+
+ bool TextGeometryStrikeoutPrimitive2D::operator==( const BasePrimitive2D& rPrimitive ) const
+ {
+ if(BaseTextStrikeoutPrimitive2D::operator==(rPrimitive))
+ {
+ const TextGeometryStrikeoutPrimitive2D& rCompare = (TextGeometryStrikeoutPrimitive2D&)rPrimitive;
+
+ return (getHeight() == rCompare.getHeight()
+ && getOffset() == rCompare.getOffset()
+ && getTextStrikeout() == rCompare.getTextStrikeout());
+ }
+
+ return false;
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(TextGeometryStrikeoutPrimitive2D, PRIMITIVE2D_ID_TEXTGEOMETRYSTRIKEOUTPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/transformprimitive2d.cxx b/drawinglayer/source/primitive2d/transformprimitive2d.cxx
new file mode 100644
index 000000000000..f8ad7e2e3608
--- /dev/null
+++ b/drawinglayer/source/primitive2d/transformprimitive2d.cxx
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <basegfx/tools/canvastools.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ TransformPrimitive2D::TransformPrimitive2D(
+ const basegfx::B2DHomMatrix& rTransformation,
+ const Primitive2DSequence& rChildren)
+ : GroupPrimitive2D(rChildren),
+ maTransformation(rTransformation)
+ {
+ }
+
+ bool TransformPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(GroupPrimitive2D::operator==(rPrimitive))
+ {
+ const TransformPrimitive2D& rCompare = static_cast< const TransformPrimitive2D& >(rPrimitive);
+
+ return (getTransformation() == rCompare.getTransformation());
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange TransformPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ basegfx::B2DRange aRetval(getB2DRangeFromPrimitive2DSequence(getChildren(), rViewInformation));
+ aRetval.transform(getTransformation());
+ return aRetval;
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(TransformPrimitive2D, PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/transparenceprimitive2d.cxx b/drawinglayer/source/primitive2d/transparenceprimitive2d.cxx
new file mode 100644
index 000000000000..ab2f8c469cee
--- /dev/null
+++ b/drawinglayer/source/primitive2d/transparenceprimitive2d.cxx
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: alphaprimitive2d.cxx,v $
+ *
+ * $Revision: 1.5 $
+ *
+ * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library 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 for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/transparenceprimitive2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ TransparencePrimitive2D::TransparencePrimitive2D(
+ const Primitive2DSequence& rChildren,
+ const Primitive2DSequence& rTransparence)
+ : GroupPrimitive2D(rChildren),
+ maTransparence(rTransparence)
+ {
+ }
+
+ bool TransparencePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(GroupPrimitive2D::operator==(rPrimitive))
+ {
+ const TransparencePrimitive2D& rCompare = (TransparencePrimitive2D&)rPrimitive;
+
+ return (getTransparence() == rCompare.getTransparence());
+ }
+
+ return false;
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(TransparencePrimitive2D, PRIMITIVE2D_ID_TRANSPARENCEPRIMITIVE2D)
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/unifiedtransparenceprimitive2d.cxx b/drawinglayer/source/primitive2d/unifiedtransparenceprimitive2d.cxx
new file mode 100644
index 000000000000..cd6384b41074
--- /dev/null
+++ b/drawinglayer/source/primitive2d/unifiedtransparenceprimitive2d.cxx
@@ -0,0 +1,139 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: UnifiedTransparencePrimitive2D.cxx,v $
+ *
+ * $Revision: 1.5 $
+ *
+ * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library 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 for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/color/bcolor.hxx>
+#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/transparenceprimitive2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ UnifiedTransparencePrimitive2D::UnifiedTransparencePrimitive2D(
+ const Primitive2DSequence& rChildren,
+ double fTransparence)
+ : GroupPrimitive2D(rChildren),
+ mfTransparence(fTransparence)
+ {
+ }
+
+ bool UnifiedTransparencePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(GroupPrimitive2D::operator==(rPrimitive))
+ {
+ const UnifiedTransparencePrimitive2D& rCompare = (UnifiedTransparencePrimitive2D&)rPrimitive;
+
+ return (getTransparence() == rCompare.getTransparence());
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange UnifiedTransparencePrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ // do not use the fallback to decomposition here since for a correct BoundRect we also
+ // need invisible (1.0 == getTransparence()) geometry; these would be deleted in the decomposition
+ return getB2DRangeFromPrimitive2DSequence(getChildren(), rViewInformation);
+ }
+
+ Primitive2DSequence UnifiedTransparencePrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
+ {
+ if(0.0 == getTransparence())
+ {
+ // no transparence used, so just use the content
+ return getChildren();
+ }
+ else if(getTransparence() > 0.0 && getTransparence() < 1.0)
+ {
+ // The idea is to create a TransparencePrimitive2D with transparent content using a fill color
+ // corresponding to the transparence value. Problem is that in most systems, the right
+ // and bottom pixel array is not filled when filling polygons, thus this would not
+ // always produce a complete transparent bitmap. There are some solutions:
+ //
+ // - Grow the used polygon range by one discrete unit in X and Y. This
+ // will make the decomposition view-dependent.
+ //
+ // - For all filled polygon renderings, dra wthe polygon outline extra. This
+ // would lead to unwanted side effects when using concatenated polygons.
+ //
+ // - At this decomposition, add a filled polygon and a hairline polygon. This
+ // solution stays view-independent.
+ //
+ // I will take the last one here. The small overhead of two primitives will only be
+ // used when UnifiedTransparencePrimitive2D is not handled directly.
+ const basegfx::B2DRange aPolygonRange(getB2DRangeFromPrimitive2DSequence(getChildren(), rViewInformation));
+ const basegfx::B2DPolygon aPolygon(basegfx::tools::createPolygonFromRect(aPolygonRange));
+ const basegfx::BColor aGray(getTransparence(), getTransparence(), getTransparence());
+ Primitive2DSequence aTransparenceContent(2);
+
+ aTransparenceContent[0] = Primitive2DReference(new PolyPolygonColorPrimitive2D(basegfx::B2DPolyPolygon(aPolygon), aGray));
+ aTransparenceContent[1] = Primitive2DReference(new PolygonHairlinePrimitive2D(aPolygon, aGray));
+
+ // create sub-transparence group with a gray-colored rectangular fill polygon
+ const Primitive2DReference xRefB(new TransparencePrimitive2D(getChildren(), aTransparenceContent));
+ return Primitive2DSequence(&xRefB, 1L);
+ }
+ else
+ {
+ // completely transparent or invalid definition, add nothing
+ return Primitive2DSequence();
+ }
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(UnifiedTransparencePrimitive2D, PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/wallpaperprimitive2d.cxx b/drawinglayer/source/primitive2d/wallpaperprimitive2d.cxx
new file mode 100644
index 000000000000..625cd5db13b9
--- /dev/null
+++ b/drawinglayer/source/primitive2d/wallpaperprimitive2d.cxx
@@ -0,0 +1,272 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/wallpaperprimitive2d.hxx>
+#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+#include <drawinglayer/primitive2d/fillbitmapprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence WallpaperBitmapPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ Primitive2DSequence aRetval;
+
+ if(!getLocalObjectRange().isEmpty() && !getBitmapEx().IsEmpty())
+ {
+ // get bitmap PIXEL size
+ const Size& rPixelSize = getBitmapEx().GetSizePixel();
+
+ if(rPixelSize.Width() > 0 && rPixelSize.Height() > 0)
+ {
+ if(WALLPAPER_SCALE == getWallpaperStyle())
+ {
+ // shortcut for scale; use simple BitmapPrimitive2D
+ basegfx::B2DHomMatrix aObjectTransform;
+
+ aObjectTransform.set(0, 0, getLocalObjectRange().getWidth());
+ aObjectTransform.set(1, 1, getLocalObjectRange().getHeight());
+ aObjectTransform.set(0, 2, getLocalObjectRange().getMinX());
+ aObjectTransform.set(1, 2, getLocalObjectRange().getMinY());
+
+ Primitive2DReference xReference(
+ new BitmapPrimitive2D(
+ getBitmapEx(),
+ aObjectTransform));
+
+ aRetval = Primitive2DSequence(&xReference, 1);
+ }
+ else
+ {
+ // transform to logic size
+ basegfx::B2DHomMatrix aInverseViewTransformation(getViewTransformation());
+ aInverseViewTransformation.invert();
+ basegfx::B2DVector aLogicSize(rPixelSize.Width(), rPixelSize.Height());
+ aLogicSize = aInverseViewTransformation * aLogicSize;
+
+ // apply laout
+ basegfx::B2DPoint aTargetTopLeft(getLocalObjectRange().getMinimum());
+ bool bUseTargetTopLeft(true);
+ bool bNeedsClipping(false);
+
+ switch(getWallpaperStyle())
+ {
+ default: //case WALLPAPER_TILE :, also WALLPAPER_NULL and WALLPAPER_APPLICATIONGRADIENT
+ {
+ bUseTargetTopLeft = false;
+ break;
+ }
+ case WALLPAPER_SCALE :
+ {
+ // handled by shortcut above
+ break;
+ }
+ case WALLPAPER_TOPLEFT :
+ {
+ // nothing to do
+ break;
+ }
+ case WALLPAPER_TOP :
+ {
+ const basegfx::B2DPoint aCenter(getLocalObjectRange().getCenter());
+ aTargetTopLeft.setX(aCenter.getX() - (aLogicSize.getX() * 0.5));
+ break;
+ }
+ case WALLPAPER_TOPRIGHT :
+ {
+ aTargetTopLeft.setX(getLocalObjectRange().getMaxX() - aLogicSize.getX());
+ break;
+ }
+ case WALLPAPER_LEFT :
+ {
+ const basegfx::B2DPoint aCenter(getLocalObjectRange().getCenter());
+ aTargetTopLeft.setY(aCenter.getY() - (aLogicSize.getY() * 0.5));
+ break;
+ }
+ case WALLPAPER_CENTER :
+ {
+ const basegfx::B2DPoint aCenter(getLocalObjectRange().getCenter());
+ aTargetTopLeft = aCenter - (aLogicSize * 0.5);
+ break;
+ }
+ case WALLPAPER_RIGHT :
+ {
+ const basegfx::B2DPoint aCenter(getLocalObjectRange().getCenter());
+ aTargetTopLeft.setX(getLocalObjectRange().getMaxX() - aLogicSize.getX());
+ aTargetTopLeft.setY(aCenter.getY() - (aLogicSize.getY() * 0.5));
+ break;
+ }
+ case WALLPAPER_BOTTOMLEFT :
+ {
+ aTargetTopLeft.setY(getLocalObjectRange().getMaxY() - aLogicSize.getY());
+ break;
+ }
+ case WALLPAPER_BOTTOM :
+ {
+ const basegfx::B2DPoint aCenter(getLocalObjectRange().getCenter());
+ aTargetTopLeft.setX(aCenter.getX() - (aLogicSize.getX() * 0.5));
+ aTargetTopLeft.setY(getLocalObjectRange().getMaxY() - aLogicSize.getY());
+ break;
+ }
+ case WALLPAPER_BOTTOMRIGHT :
+ {
+ aTargetTopLeft = getLocalObjectRange().getMaximum() - aLogicSize;
+ break;
+ }
+ }
+
+ if(bUseTargetTopLeft)
+ {
+ // fill target range
+ const basegfx::B2DRange aTargetRange(aTargetTopLeft, aTargetTopLeft + aLogicSize);
+
+ // create aligned, single BitmapPrimitive2D
+ basegfx::B2DHomMatrix aObjectTransform;
+
+ aObjectTransform.set(0, 0, aTargetRange.getWidth());
+ aObjectTransform.set(1, 1, aTargetRange.getHeight());
+ aObjectTransform.set(0, 2, aTargetRange.getMinX());
+ aObjectTransform.set(1, 2, aTargetRange.getMinY());
+
+ Primitive2DReference xReference(
+ new BitmapPrimitive2D(
+ getBitmapEx(),
+ aObjectTransform));
+ aRetval = Primitive2DSequence(&xReference, 1);
+
+ // clip when not completely inside object range
+ bNeedsClipping = !getLocalObjectRange().isInside(aTargetRange);
+ }
+ else
+ {
+ // WALLPAPER_TILE, WALLPAPER_NULL, WALLPAPER_APPLICATIONGRADIENT
+ // convert to relative positions
+ const basegfx::B2DVector aRelativeSize(
+ aLogicSize.getX() / (getLocalObjectRange().getWidth() ? getLocalObjectRange().getWidth() : 1.0),
+ aLogicSize.getY() / (getLocalObjectRange().getHeight() ? getLocalObjectRange().getHeight() : 1.0));
+ basegfx::B2DPoint aRelativeTopLeft(0.0, 0.0);
+
+ if(WALLPAPER_TILE != getWallpaperStyle())
+ {
+ aRelativeTopLeft.setX(0.5 - aRelativeSize.getX());
+ aRelativeTopLeft.setY(0.5 - aRelativeSize.getY());
+ }
+
+ // prepare FillBitmapAttribute
+ const attribute::FillBitmapAttribute aFillBitmapAttribute(
+ getBitmapEx(),
+ aRelativeTopLeft,
+ aRelativeSize,
+ true);
+
+ // create ObjectTransform
+ basegfx::B2DHomMatrix aObjectTransform;
+
+ aObjectTransform.set(0, 0, getLocalObjectRange().getWidth());
+ aObjectTransform.set(1, 1, getLocalObjectRange().getHeight());
+ aObjectTransform.set(0, 2, getLocalObjectRange().getMinX());
+ aObjectTransform.set(1, 2, getLocalObjectRange().getMinY());
+
+ // create FillBitmapPrimitive
+ const drawinglayer::primitive2d::Primitive2DReference xFillBitmap(
+ new drawinglayer::primitive2d::FillBitmapPrimitive2D(
+ aObjectTransform,
+ aFillBitmapAttribute));
+ aRetval = Primitive2DSequence(&xFillBitmap, 1);
+
+ // always embed tiled fill to clipping
+ bNeedsClipping = true;
+ }
+
+ if(bNeedsClipping)
+ {
+ // embed to clipping; this is necessary for tiled fills
+ const basegfx::B2DPolyPolygon aPolyPolygon(
+ basegfx::tools::createPolygonFromRect(getLocalObjectRange()));
+ const drawinglayer::primitive2d::Primitive2DReference xClippedFill(
+ new drawinglayer::primitive2d::MaskPrimitive2D(
+ aPolyPolygon,
+ aRetval));
+ aRetval = Primitive2DSequence(&xClippedFill, 1);
+ }
+ }
+ }
+ }
+
+ return aRetval;
+ }
+
+ WallpaperBitmapPrimitive2D::WallpaperBitmapPrimitive2D(
+ const basegfx::B2DRange& rObjectRange,
+ const BitmapEx& rBitmapEx,
+ WallpaperStyle eWallpaperStyle)
+ : ViewTransformationDependentPrimitive2D(),
+ maObjectRange(rObjectRange),
+ maBitmapEx(rBitmapEx),
+ meWallpaperStyle(eWallpaperStyle)
+ {
+ }
+
+ bool WallpaperBitmapPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(ViewTransformationDependentPrimitive2D::operator==(rPrimitive))
+ {
+ const WallpaperBitmapPrimitive2D& rCompare = (WallpaperBitmapPrimitive2D&)rPrimitive;
+
+ return (getLocalObjectRange() == rCompare.getLocalObjectRange()
+ && getBitmapEx() == rCompare.getBitmapEx()
+ && getWallpaperStyle() == rCompare.getWallpaperStyle());
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange WallpaperBitmapPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ return getLocalObjectRange();
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(WallpaperBitmapPrimitive2D, PRIMITIVE2D_ID_WALLPAPERBITMAPPRIMITIVE2D)
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/wrongspellprimitive2d.cxx b/drawinglayer/source/primitive2d/wrongspellprimitive2d.cxx
new file mode 100644
index 000000000000..2e38ed8bed31
--- /dev/null
+++ b/drawinglayer/source/primitive2d/wrongspellprimitive2d.cxx
@@ -0,0 +1,125 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/primitive2d/wrongspellprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace primitive2d
+ {
+ Primitive2DSequence WrongSpellPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ // ATM this decompose is view-independent, what the original VCL-Display is not. To mimic
+ // the old behaviour here if wanted it is necessary to add get2DDecomposition and implement
+ // it similar to the usage in e.g. HelplinePrimitive2D. Remembering the ViewTransformation
+ // should be enough then.
+ // The view-independent wavelines work well (if You ask me). Maybe the old VCL-Behaviour is only
+ // in place because it was not possible/too expensive at that time to scale the wavelines with the
+ // view...
+ // With the VCL-PixelRenderer this will not even be used since it implements WrongSpellPrimitive2D
+ // directly and mimics the old VCL-Display there. If You implemented a new renderer without
+ // direct WrongSpellPrimitive2D support, You may want to do the described change here.
+
+ // get the font height (part of scale), so decompose the matrix
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ getTransformation().decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // calculate distances based on a static default (to allow testing in debugger)
+ static double fDefaultDistance(0.03);
+ const double fFontHeight(aScale.getY());
+ const double fUnderlineDistance(fFontHeight * fDefaultDistance);
+ const double fWaveWidth(2.0 * fUnderlineDistance);
+
+ // the Y-distance needs to be relativated to FontHeight since the points get
+ // transformed with the transformation containing that scale already.
+ const double fRelativeUnderlineDistance(basegfx::fTools::equalZero(aScale.getY()) ? 0.0 : fUnderlineDistance / aScale.getY());
+ basegfx::B2DPoint aStart(getStart(), fRelativeUnderlineDistance);
+ basegfx::B2DPoint aStop(getStop(), fRelativeUnderlineDistance);
+ basegfx::B2DPolygon aPolygon;
+
+ aPolygon.append(getTransformation() * aStart);
+ aPolygon.append(getTransformation() * aStop);
+
+ // prepare line attribute
+ const attribute::LineAttribute aLineAttribute(getColor());
+
+ // create the waveline primitive
+ Primitive2DReference xPrimitive(new PolygonWavePrimitive2D(aPolygon, aLineAttribute, fWaveWidth, 0.5 * fWaveWidth));
+ Primitive2DSequence xRetval(&xPrimitive, 1);
+
+ return xRetval;
+ }
+
+ WrongSpellPrimitive2D::WrongSpellPrimitive2D(
+ const basegfx::B2DHomMatrix& rTransformation,
+ double fStart,
+ double fStop,
+ const basegfx::BColor& rColor)
+ : BufferedDecompositionPrimitive2D(),
+ maTransformation(rTransformation),
+ mfStart(fStart),
+ mfStop(fStop),
+ maColor(rColor)
+ {
+ }
+
+ bool WrongSpellPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const WrongSpellPrimitive2D& rCompare = (WrongSpellPrimitive2D&)rPrimitive;
+
+ return (getTransformation() == rCompare.getTransformation()
+ && getStart() == rCompare.getStart()
+ && getStop() == rCompare.getStop()
+ && getColor() == rCompare.getColor());
+ }
+
+ return false;
+ }
+
+ // provide unique ID
+ ImplPrimitrive2DIDBlock(WrongSpellPrimitive2D, PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D)
+
+ } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */