diff options
Diffstat (limited to 'drawinglayer/source/primitive2d')
47 files changed, 13245 insertions, 0 deletions
diff --git a/drawinglayer/source/primitive2d/animatedprimitive2d.cxx b/drawinglayer/source/primitive2d/animatedprimitive2d.cxx new file mode 100644 index 000000000000..35cdc7e95bf8 --- /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..44f8a138d5f5 --- /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..00dc22cd89a3 --- /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..8e780ce2d38a --- /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..8a7d8b297a90 --- /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..87fdd094b8e9 --- /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..96ca10484549 --- /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(RTL_CONSTASCII_USTRINGPARAM("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..167497181de3 --- /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..7e6964db7f55 --- /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..8d8d757491ca --- /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..dc5a228be2ba --- /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..fb19bebc87e7 --- /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..91e68f04e003 --- /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..2ea9018460f6 --- /dev/null +++ b/drawinglayer/source/primitive2d/graphicprimitive2d.cxx @@ -0,0 +1,489 @@ +/* -*- 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 + +////////////////////////////////////////////////////////////////////////////// + +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& + ) 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 : + { + // 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)); + } + + 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..0439aa2436cf --- /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..25908a5b4c98 --- /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..e5d861806721 --- /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..c7bb66f60fdf --- /dev/null +++ b/drawinglayer/source/primitive2d/hiddengeometryprimitive2d.cxx @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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..7bd3be3cc596 --- /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..3bc4f8a4bafe --- /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..a864cd7cd89e --- /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..70b09b504118 --- /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..d205981205aa --- /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..2d7e22ffd542 --- /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..dd4bc359adb7 --- /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..94b3f9cb7a9a --- /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..6a656445db40 --- /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..e1102f8eeb35 --- /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..af73fcf278a8 --- /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..7d83868fa784 --- /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..42c5d545f092 --- /dev/null +++ b/drawinglayer/source/primitive2d/sdrdecompositiontools2d.cxx @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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..1247ba2785b6 --- /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..e6a0a1ce8dc9 --- /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..6c60b3f22281 --- /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(RTL_CONSTASCII_USTRINGPARAM("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..41e51c6e9e2f --- /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..b9ad03531206 --- /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..4653a0437a3b --- /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..e6ce69866cc8 --- /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..b76056b5a219 --- /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..e928f8326126 --- /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..98d7a64e2dfc --- /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..b3f1e2e1b0a3 --- /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..d5aec4d7434e --- /dev/null +++ b/drawinglayer/source/primitive2d/transparenceprimitive2d.cxx @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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..b96c8967bdaf --- /dev/null +++ b/drawinglayer/source/primitive2d/unifiedtransparenceprimitive2d.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 + * + * 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..0213ba90a6c6 --- /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..825251036d7a --- /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: */ |