diff options
Diffstat (limited to 'drawinglayer/source')
108 files changed, 29660 insertions, 0 deletions
diff --git a/drawinglayer/source/animation/animationtiming.cxx b/drawinglayer/source/animation/animationtiming.cxx new file mode 100644 index 000000000000..ab73d07591b1 --- /dev/null +++ b/drawinglayer/source/animation/animationtiming.cxx @@ -0,0 +1,378 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: animationtiming.cxx,v $ + * + * $Revision: 1.6 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:19 $ + * + * 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/animation/animationtiming.hxx> +#include <basegfx/numeric/ftools.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace animation + { + ////////////////////////////////////////////////////////////////////////////// + + AnimationEntry::AnimationEntry() + { + } + + AnimationEntry::~AnimationEntry() + { + } + + ////////////////////////////////////////////////////////////////////////////// + + AnimationEntryFixed::AnimationEntryFixed(double fDuration, double fState) + : mfDuration(fDuration), + mfState(fState) + { + } + + AnimationEntryFixed::~AnimationEntryFixed() + { + } + + AnimationEntry* AnimationEntryFixed::clone() const + { + return new AnimationEntryFixed(mfDuration, mfState); + } + + bool AnimationEntryFixed::operator==(const AnimationEntry& rCandidate) const + { + const AnimationEntryFixed* pCompare = dynamic_cast< const AnimationEntryFixed* >(&rCandidate); + + return (pCompare + && basegfx::fTools::equal(mfDuration, pCompare->mfDuration) + && basegfx::fTools::equal(mfState, pCompare->mfState)); + } + + double AnimationEntryFixed::getDuration() const + { + return mfDuration; + } + + double AnimationEntryFixed::getStateAtTime(double /*fTime*/) const + { + return mfState; + } + + double AnimationEntryFixed::getNextEventTime(double fTime) const + { + if(basegfx::fTools::less(fTime, mfDuration)) + { + return mfDuration; + } + else + { + return 0.0; + } + } + + ////////////////////////////////////////////////////////////////////////////// + + AnimationEntryLinear::AnimationEntryLinear(double fDuration, double fFrequency, double fStart, double fStop) + : mfDuration(fDuration), + mfFrequency(fFrequency), + mfStart(fStart), + mfStop(fStop) + { + } + + AnimationEntryLinear::~AnimationEntryLinear() + { + } + + AnimationEntry* AnimationEntryLinear::clone() const + { + return new AnimationEntryLinear(mfDuration, mfFrequency, mfStart, mfStop); + } + + bool AnimationEntryLinear::operator==(const AnimationEntry& rCandidate) const + { + const AnimationEntryLinear* pCompare = dynamic_cast< const AnimationEntryLinear* >(&rCandidate); + + return (pCompare + && basegfx::fTools::equal(mfDuration, pCompare->mfDuration) + && basegfx::fTools::equal(mfStart, pCompare->mfStart) + && basegfx::fTools::equal(mfStop, pCompare->mfStop)); + } + + double AnimationEntryLinear::getDuration() const + { + return mfDuration; + } + + double AnimationEntryLinear::getStateAtTime(double fTime) const + { + if(basegfx::fTools::more(mfDuration, 0.0)) + { + const double fFactor(fTime / mfDuration); + + if(fFactor > 1.0) + { + return mfStop; + } + else + { + return mfStart + ((mfStop - mfStart) * fFactor); + } + } + else + { + return mfStart; + } + } + + double AnimationEntryLinear::getNextEventTime(double fTime) const + { + if(basegfx::fTools::less(fTime, mfDuration)) + { + // use the simple solution: just add the frequency. More correct (but also more + // complicated) would be to calculate the slice of time we are in and when this + // slice will end. For the animations, this makes no quality difference. + fTime += mfFrequency; + + if(basegfx::fTools::more(fTime, mfDuration)) + { + fTime = mfDuration; + } + + return fTime; + } + else + { + return 0.0; + } + } + + ////////////////////////////////////////////////////////////////////////////// + + sal_uInt32 AnimationEntryList::impGetIndexAtTime(double fTime, double &rfAddedTime) const + { + sal_uInt32 nIndex(0L); + + while(nIndex < maEntries.size() && basegfx::fTools::lessOrEqual(rfAddedTime + maEntries[nIndex]->getDuration(), fTime)) + { + rfAddedTime += maEntries[nIndex++]->getDuration(); + } + + return nIndex; + } + + AnimationEntryList::AnimationEntryList() + : mfDuration(0.0) + { + } + + AnimationEntryList::~AnimationEntryList() + { + for(sal_uInt32 a(0L); a < maEntries.size(); a++) + { + delete maEntries[a]; + } + } + + AnimationEntry* AnimationEntryList::clone() const + { + AnimationEntryList* pNew = new AnimationEntryList(); + + for(sal_uInt32 a(0L); a < maEntries.size(); a++) + { + pNew->append(*maEntries[a]); + } + + return pNew; + } + + bool AnimationEntryList::operator==(const AnimationEntry& rCandidate) const + { + const AnimationEntryList* pCompare = dynamic_cast< const AnimationEntryList* >(&rCandidate); + + if(pCompare && mfDuration == pCompare->mfDuration) + { + for(sal_uInt32 a(0L); a < maEntries.size(); a++) + { + if(!(*maEntries[a] == *pCompare->maEntries[a])) + { + return false; + } + } + + return true; + } + + return false; + } + + void AnimationEntryList::append(const AnimationEntry& rCandidate) + { + const double fDuration(rCandidate.getDuration()); + + if(!basegfx::fTools::equalZero(fDuration)) + { + maEntries.push_back(rCandidate.clone()); + mfDuration += fDuration; + } + } + + double AnimationEntryList::getDuration() const + { + return mfDuration; + } + + double AnimationEntryList::getStateAtTime(double fTime) const + { + if(!basegfx::fTools::equalZero(mfDuration)) + { + double fAddedTime(0.0); + const sal_uInt32 nIndex(impGetIndexAtTime(fTime, fAddedTime)); + + if(nIndex < maEntries.size()) + { + return maEntries[nIndex]->getStateAtTime(fTime - fAddedTime); + } + } + + return 0.0; + } + + double AnimationEntryList::getNextEventTime(double fTime) const + { + double fNewTime(0.0); + + if(!basegfx::fTools::equalZero(mfDuration)) + { + double fAddedTime(0.0); + const sal_uInt32 nIndex(impGetIndexAtTime(fTime, fAddedTime)); + + if(nIndex < maEntries.size()) + { + fNewTime = maEntries[nIndex]->getNextEventTime(fTime - fAddedTime) + fAddedTime; + } + } + + return fNewTime; + } + + ////////////////////////////////////////////////////////////////////////////// + + AnimationEntryLoop::AnimationEntryLoop(sal_uInt32 nRepeat) + : AnimationEntryList(), + mnRepeat(nRepeat) + { + } + + AnimationEntryLoop::~AnimationEntryLoop() + { + } + + AnimationEntry* AnimationEntryLoop::clone() const + { + AnimationEntryLoop* pNew = new AnimationEntryLoop(mnRepeat); + + for(sal_uInt32 a(0L); a < maEntries.size(); a++) + { + pNew->append(*maEntries[a]); + } + + return pNew; + } + + bool AnimationEntryLoop::operator==(const AnimationEntry& rCandidate) const + { + const AnimationEntryLoop* pCompare = dynamic_cast< const AnimationEntryLoop* >(&rCandidate); + + return (pCompare + && mnRepeat == pCompare->mnRepeat + && AnimationEntryList::operator==(rCandidate)); + } + + double AnimationEntryLoop::getDuration() const + { + return (mfDuration * (double)mnRepeat); + } + + double AnimationEntryLoop::getStateAtTime(double fTime) const + { + if(mnRepeat && !basegfx::fTools::equalZero(mfDuration)) + { + const sal_uInt32 nCurrentLoop((sal_uInt32)(fTime / mfDuration)); + + if(nCurrentLoop > mnRepeat) + { + return 1.0; + } + else + { + const double fTimeAtLoopStart((double)nCurrentLoop * mfDuration); + const double fRelativeTime(fTime - fTimeAtLoopStart); + return AnimationEntryList::getStateAtTime(fRelativeTime); + } + } + + return 0.0; + } + + double AnimationEntryLoop::getNextEventTime(double fTime) const + { + double fNewTime(0.0); + + if(mnRepeat && !basegfx::fTools::equalZero(mfDuration)) + { + const sal_uInt32 nCurrentLoop((sal_uInt32)(fTime / mfDuration)); + + if(nCurrentLoop <= mnRepeat) + { + const double fTimeAtLoopStart((double)nCurrentLoop * mfDuration); + const double fRelativeTime(fTime - fTimeAtLoopStart); + const double fNextEventAtLoop(AnimationEntryList::getNextEventTime(fRelativeTime)); + + if(!basegfx::fTools::equalZero(fNextEventAtLoop)) + { + fNewTime = fNextEventAtLoop + fTimeAtLoopStart; + } + } + } + + return fNewTime; + } + } // end of namespace animation +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/animation/makefile.mk b/drawinglayer/source/animation/makefile.mk new file mode 100644 index 000000000000..a72bf10711f4 --- /dev/null +++ b/drawinglayer/source/animation/makefile.mk @@ -0,0 +1,52 @@ +#************************************************************************* +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.3 $ +# +# last change: $Author: aw $ $Date: 2006-12-13 16:57:07 $ +# +# 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 +# +#************************************************************************* + +PRJ=..$/.. +PRJNAME=drawinglayer +TARGET=animation +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ---------------------------------- + +.INCLUDE : settings.mk + +# --- Files ------------------------------------- + +SLOFILES= \ + $(SLO)$/animationtiming.obj + +# --- Targets ---------------------------------- + +.INCLUDE : target.mk diff --git a/drawinglayer/source/attribute/fillattribute.cxx b/drawinglayer/source/attribute/fillattribute.cxx new file mode 100644 index 000000000000..12741e40c5c3 --- /dev/null +++ b/drawinglayer/source/attribute/fillattribute.cxx @@ -0,0 +1,102 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: fillattribute.cxx,v $ + * + * $Revision: 1.4 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:19 $ + * + * 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/attribute/fillattribute.hxx> +#include <basegfx/numeric/ftools.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace attribute + { + FillGradientAttribute::FillGradientAttribute(GradientStyle eStyle, double fBorder, double fOffsetX, double fOffsetY, double fAngle, + const basegfx::BColor& rStartColor, const basegfx::BColor& rEndColor, sal_uInt16 nSteps) + : maStartColor(rStartColor), + maEndColor(rEndColor), + mfBorder(fBorder), + mfOffsetX(fOffsetX), + mfOffsetY(fOffsetY), + mfAngle(fAngle), + meStyle(eStyle), + mnSteps(nSteps) + { + } + + bool FillGradientAttribute::operator==(const FillGradientAttribute& rCandidate) const + { + return (meStyle == rCandidate.meStyle + && maStartColor == rCandidate.maStartColor + && maEndColor == rCandidate.maEndColor + && mfBorder == rCandidate.mfBorder + && mfOffsetX == rCandidate.mfOffsetX + && mfOffsetY == rCandidate.mfOffsetY + && mfAngle == rCandidate.mfAngle + && mnSteps == rCandidate.mnSteps); + } + } // end of namespace attribute +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace attribute + { + FillHatchAttribute::FillHatchAttribute(HatchStyle eStyle, double fDistance, double fAngle, const basegfx::BColor& rColor, bool bFillBackground) + : mfDistance(fDistance), + mfAngle(fAngle), + maColor(rColor), + meStyle(eStyle), + mbFillBackground(bFillBackground) + { + } + + bool FillHatchAttribute::operator==(const FillHatchAttribute& rCandidate) const + { + return (meStyle == rCandidate.meStyle + && mfDistance == rCandidate.mfDistance + && mfAngle == rCandidate.mfAngle + && maColor == rCandidate.maColor + && mbFillBackground == rCandidate.mbFillBackground); + } + } // end of namespace attribute +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/attribute/fillbitmapattribute.cxx b/drawinglayer/source/attribute/fillbitmapattribute.cxx new file mode 100644 index 000000000000..539e85ab2733 --- /dev/null +++ b/drawinglayer/source/attribute/fillbitmapattribute.cxx @@ -0,0 +1,66 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: fillbitmapattribute.cxx,v $ + * + * $Revision: 1.4 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:19 $ + * + * 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/attribute/fillbitmapattribute.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace attribute + { + FillBitmapAttribute::FillBitmapAttribute(const Bitmap& rBitmap, const basegfx::B2DPoint& rTopLeft, const basegfx::B2DVector& rSize, bool bTiling) + : maBitmap(rBitmap), + maTopLeft(rTopLeft), + maSize(rSize), + mbTiling(bTiling) + { + } + + bool FillBitmapAttribute::operator==(const FillBitmapAttribute& rCandidate) const + { + return (maBitmap == rCandidate.maBitmap + && maTopLeft == rCandidate.maTopLeft + && maSize == rCandidate.maSize + && mbTiling == rCandidate.mbTiling); + } + } // end of namespace attribute +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/attribute/lineattribute.cxx b/drawinglayer/source/attribute/lineattribute.cxx new file mode 100644 index 000000000000..5ab44b73db82 --- /dev/null +++ b/drawinglayer/source/attribute/lineattribute.cxx @@ -0,0 +1,51 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: lineattribute.cxx,v $ + * + * $Revision: 1.3 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:19 $ + * + * 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/attribute/lineattribute.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace attribute + { + } // end of namespace attribute +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/attribute/linestartendattribute.cxx b/drawinglayer/source/attribute/linestartendattribute.cxx new file mode 100644 index 000000000000..785819870114 --- /dev/null +++ b/drawinglayer/source/attribute/linestartendattribute.cxx @@ -0,0 +1,58 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: linestartendattribute.cxx,v $ + * + * $Revision: 1.3 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:19 $ + * + * 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/attribute/linestartendattribute.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace attribute + { + bool LineStartEndAttribute::isActive() const + { + return (0.0 != getWidth() + && 0.0 != getB2DPolyPolygon().count() + && 0.0 != getB2DPolyPolygon().getB2DPolygon(0L).count()); + } + } // end of namespace attribute +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/attribute/makefile.mk b/drawinglayer/source/attribute/makefile.mk new file mode 100644 index 000000000000..fa91224e64b6 --- /dev/null +++ b/drawinglayer/source/attribute/makefile.mk @@ -0,0 +1,61 @@ +#************************************************************************* +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.3 $ +# +# last change: $Author: aw $ $Date: 2007-11-07 14:27:26 $ +# +# 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 +# +#************************************************************************* + +PRJ=..$/.. +PRJNAME=drawinglayer +TARGET=attribute +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ---------------------------------- + +.INCLUDE : settings.mk + +# --- Files ------------------------------------- + +SLOFILES= \ + $(SLO)$/fillattribute.obj \ + $(SLO)$/fillbitmapattribute.obj \ + $(SLO)$/materialattribute3d.obj \ + $(SLO)$/sdrallattribute3d.obj \ + $(SLO)$/sdrattribute.obj \ + $(SLO)$/sdrattribute3d.obj \ + $(SLO)$/sdrfillbitmapattribute.obj \ + $(SLO)$/lineattribute.obj \ + $(SLO)$/linestartendattribute.obj \ + $(SLO)$/strokeattribute.obj + +# --- Targets ---------------------------------- + +.INCLUDE : target.mk diff --git a/drawinglayer/source/attribute/materialattribute3d.cxx b/drawinglayer/source/attribute/materialattribute3d.cxx new file mode 100644 index 000000000000..bc3e8f3b317b --- /dev/null +++ b/drawinglayer/source/attribute/materialattribute3d.cxx @@ -0,0 +1,192 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: materialattribute3d.cxx,v $ + * + * $Revision: 1.4 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:19 $ + * + * 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/attribute/materialattribute3d.hxx> +#include <basegfx/color/bcolor.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace attribute + { + class ImpMaterialAttribute3D + { + public: + // materialAttribute3D definitions + basegfx::BColor maColor; // object color + basegfx::BColor maSpecular; // material specular color + basegfx::BColor maEmission; // material emissive color + sal_uInt16 mnSpecularIntensity; // material specular intensity [0..128] + + // refcounter + sal_uInt32 mnRefCount; + + ImpMaterialAttribute3D(const basegfx::BColor& rColor, const basegfx::BColor& rSpecular, const basegfx::BColor& rEmission, sal_uInt16 nSpecularIntensity) + : maColor(rColor), + maSpecular(rSpecular), + maEmission(rEmission), + mnSpecularIntensity(nSpecularIntensity), + mnRefCount(0L) + { + } + + ImpMaterialAttribute3D(const basegfx::BColor& rColor) + : maColor(rColor), + maSpecular(1.0, 1.0, 1.0), + maEmission(), + mnSpecularIntensity(15), + mnRefCount(0L) + { + } + + ImpMaterialAttribute3D() + : mnSpecularIntensity(0), + mnRefCount(0L) + { + } + + bool operator==(const ImpMaterialAttribute3D& rCandidate) const + { + return (maColor == rCandidate.maColor + && maSpecular == rCandidate.maSpecular + && maEmission == rCandidate.maEmission + && mnSpecularIntensity == rCandidate.mnSpecularIntensity); + } + + const basegfx::BColor& getColor() const { return maColor; } + const basegfx::BColor& getSpecular() const { return maSpecular; } + const basegfx::BColor& getEmission() const { return maEmission; } + sal_uInt16 getSpecularIntensity() const { return mnSpecularIntensity; } + }; + } // end of anonymous namespace +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace attribute + { + MaterialAttribute3D::MaterialAttribute3D(const basegfx::BColor& rColor, const basegfx::BColor& rSpecular, const basegfx::BColor& rEmission, sal_uInt16 nSpecularIntensity) + : mpMaterialAttribute3D(new ImpMaterialAttribute3D(rColor, rSpecular, rEmission, nSpecularIntensity)) + { + } + + MaterialAttribute3D::MaterialAttribute3D(const basegfx::BColor& rColor) + : mpMaterialAttribute3D(new ImpMaterialAttribute3D(rColor)) + { + } + + MaterialAttribute3D::MaterialAttribute3D() + : mpMaterialAttribute3D(new ImpMaterialAttribute3D()) + { + } + + MaterialAttribute3D::MaterialAttribute3D(const MaterialAttribute3D& rCandidate) + : mpMaterialAttribute3D(rCandidate.mpMaterialAttribute3D) + { + mpMaterialAttribute3D->mnRefCount++; + } + + MaterialAttribute3D::~MaterialAttribute3D() + { + if(mpMaterialAttribute3D->mnRefCount) + { + mpMaterialAttribute3D->mnRefCount--; + } + else + { + delete mpMaterialAttribute3D; + } + } + + MaterialAttribute3D& MaterialAttribute3D::operator=(const MaterialAttribute3D& rCandidate) + { + if(rCandidate.mpMaterialAttribute3D != mpMaterialAttribute3D) + { + if(mpMaterialAttribute3D->mnRefCount) + { + mpMaterialAttribute3D->mnRefCount--; + } + else + { + delete mpMaterialAttribute3D; + } + + mpMaterialAttribute3D = rCandidate.mpMaterialAttribute3D; + mpMaterialAttribute3D->mnRefCount++; + } + + return *this; + } + + bool MaterialAttribute3D::operator==(const MaterialAttribute3D& rCandidate) const + { + if(rCandidate.mpMaterialAttribute3D == mpMaterialAttribute3D) + { + return true; + } + + return (*rCandidate.mpMaterialAttribute3D == *mpMaterialAttribute3D); + } + + const basegfx::BColor& MaterialAttribute3D::getColor() const + { + return mpMaterialAttribute3D->getColor(); + } + + const basegfx::BColor& MaterialAttribute3D::getSpecular() const + { + return mpMaterialAttribute3D->getSpecular(); + } + + const basegfx::BColor& MaterialAttribute3D::getEmission() const + { + return mpMaterialAttribute3D->getEmission(); + } + + sal_uInt16 MaterialAttribute3D::getSpecularIntensity() const + { + return mpMaterialAttribute3D->getSpecularIntensity(); + } + } // end of namespace attribute +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/attribute/sdrallattribute3d.cxx b/drawinglayer/source/attribute/sdrallattribute3d.cxx new file mode 100644 index 000000000000..264d8d0432d1 --- /dev/null +++ b/drawinglayer/source/attribute/sdrallattribute3d.cxx @@ -0,0 +1,200 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: sdrallattribute3d.cxx,v $ + * + * $Revision: 1.4 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:19 $ + * + * 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/attribute/sdrallattribute3d.hxx> +#include <drawinglayer/attribute/sdrattribute.hxx> +#include <drawinglayer/attribute/fillattribute.hxx> + +////////////////////////////////////////////////////////////////////////////// +// pointer compare define +#define pointerOrContentEqual(p, q) ((p == q) || (p && q && *p == *q)) + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace attribute + { + SdrLineFillShadowAttribute::SdrLineFillShadowAttribute( + SdrLineAttribute* pLine, + SdrFillAttribute* pFill, + SdrLineStartEndAttribute* pLineStartEnd, + SdrShadowAttribute* pShadow, + FillGradientAttribute* pFillFloatTransGradient) + : mpShadow(pShadow), + mpLine(pLine), + mpLineStartEnd(pLineStartEnd), + mpFill(pFill), + mpFillFloatTransGradient(pFillFloatTransGradient) + { + } + + SdrLineFillShadowAttribute::SdrLineFillShadowAttribute( + const SdrLineFillShadowAttribute& rCandidate) + : mpShadow(0), + mpLine(0), + mpLineStartEnd(0), + mpFill(0), + mpFillFloatTransGradient(0) + { + *this = rCandidate; + } + + SdrLineFillShadowAttribute::~SdrLineFillShadowAttribute() + { + delete mpShadow; + delete mpLine; + delete mpLineStartEnd; + delete mpFill; + delete mpFillFloatTransGradient; + } + + SdrLineFillShadowAttribute& SdrLineFillShadowAttribute::operator=(const SdrLineFillShadowAttribute& rCandidate) + { + // handle mpShadow + { + // delete local mpShadow if necessary + if(mpShadow) + { + delete mpShadow; + mpShadow = 0; + } + + // copy mpShadow if necessary + if(rCandidate.mpShadow) + { + mpShadow = new SdrShadowAttribute(*rCandidate.mpShadow); + } + } + + // handle mpLine + { + // delete local mpLine if necessary + if(mpLine) + { + delete mpLine; + mpLine = 0; + } + + // copy mpLine if necessary + if(rCandidate.mpLine) + { + mpLine = new SdrLineAttribute(*rCandidate.mpLine); + } + } + + // handle mpLineStartEnd + { + // delete local mpLineStartEnd if necessary + if(mpLineStartEnd) + { + delete mpLineStartEnd; + mpLineStartEnd = 0; + } + + // copy mpLineStartEnd if necessary + if(rCandidate.mpLineStartEnd) + { + mpLineStartEnd = new SdrLineStartEndAttribute(*rCandidate.mpLineStartEnd); + } + } + + // handle mpFill + { + // delete local mpFill if necessary + if(mpFill) + { + delete mpFill; + mpFill = 0; + } + + // copy mpFill if necessary + if(rCandidate.mpFill) + { + mpFill = new SdrFillAttribute(*rCandidate.mpFill); + } + } + + // handle mpFillFloatTransGradient + { + // delete local mpFillFloatTransGradient if necessary + if(mpFillFloatTransGradient) + { + delete mpFillFloatTransGradient; + mpFillFloatTransGradient = 0; + } + + // copy mpFillFloatTransGradient if necessary + if(rCandidate.mpFillFloatTransGradient) + { + mpFillFloatTransGradient = new FillGradientAttribute(*rCandidate.mpFillFloatTransGradient); + } + } + + return *this; + } + + bool SdrLineFillShadowAttribute::operator==(const SdrLineFillShadowAttribute& rCandidate) const + { + // handle mpShadow + if(!pointerOrContentEqual(mpShadow, rCandidate.mpShadow)) + return false; + + // handle mpLine + if(!pointerOrContentEqual(mpLine, rCandidate.mpLine)) + return false; + + // handle mpLineStartEnd + if(!pointerOrContentEqual(mpLineStartEnd, rCandidate.mpLineStartEnd)) + return false; + + // handle mpFill + if(!pointerOrContentEqual(mpFill, rCandidate.mpFill)) + return false; + + // handle mpFillFloatTransGradient + if(!pointerOrContentEqual(mpFillFloatTransGradient, rCandidate.mpFillFloatTransGradient)) + return false; + + return true; + } + } // end of namespace attribute +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/attribute/sdrattribute.cxx b/drawinglayer/source/attribute/sdrattribute.cxx new file mode 100644 index 000000000000..8e55afa6751e --- /dev/null +++ b/drawinglayer/source/attribute/sdrattribute.cxx @@ -0,0 +1,293 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: sdrattribute.cxx,v $ + * + * $Revision: 1.5 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:19 $ + * + * 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/attribute/sdrattribute.hxx> +#include <drawinglayer/attribute/fillattribute.hxx> +#include <drawinglayer/attribute/sdrfillbitmapattribute.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace attribute + { + SdrLineAttribute::SdrLineAttribute( + basegfx::B2DLineJoin eJoin, double fWidth, double fTransparence, const basegfx::BColor& rColor, + const ::std::vector< double >& rDotDashArray, double fFullDotDashLen) + : meJoin(eJoin), + mfWidth(fWidth), + mfTransparence(fTransparence), + maColor(rColor), + maDotDashArray(rDotDashArray), + mfFullDotDashLen(fFullDotDashLen) + { + } + + SdrLineAttribute::SdrLineAttribute(const basegfx::BColor& rColor) + : meJoin(basegfx::B2DLINEJOIN_NONE), + mfWidth(0.0), + mfTransparence(0.0), + maColor(rColor), + maDotDashArray(), + mfFullDotDashLen(0.0) + { + } + + SdrLineAttribute::~SdrLineAttribute() + { + } + + bool SdrLineAttribute::operator==(const SdrLineAttribute& rCandidate) const + { + return (meJoin == rCandidate.meJoin + && mfWidth == rCandidate.mfWidth + && mfTransparence == rCandidate.mfTransparence + && maColor == rCandidate.maColor + && maDotDashArray == rCandidate.maDotDashArray); + } + } // end of namespace attribute +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace attribute + { + SdrLineStartEndAttribute::SdrLineStartEndAttribute( + const basegfx::B2DPolyPolygon& rStartPolyPolygon, const basegfx::B2DPolyPolygon& rEndPolyPolygon, + double fStartWidth, double fEndWidth, bool bStartActive, bool bEndActive, bool bStartCentered, bool bEndCentered) + : maStartPolyPolygon(rStartPolyPolygon), + maEndPolyPolygon(rEndPolyPolygon), + mfStartWidth(fStartWidth), + mfEndWidth(fEndWidth), + mbStartActive(bStartActive), + mbEndActive(bEndActive), + mbStartCentered(bStartCentered), + mbEndCentered(bEndCentered) + { + } + + SdrLineStartEndAttribute::~SdrLineStartEndAttribute() + { + } + + bool SdrLineStartEndAttribute::operator==(const SdrLineStartEndAttribute& rCandidate) const + { + return (mbStartActive == rCandidate.mbStartActive + && mbEndActive == rCandidate.mbEndActive + && mbStartCentered == rCandidate.mbStartCentered + && mbEndCentered == rCandidate.mbEndCentered + && mfStartWidth == rCandidate.mfStartWidth + && mfEndWidth == rCandidate.mfEndWidth + && maStartPolyPolygon == rCandidate.maStartPolyPolygon + && maEndPolyPolygon == rCandidate.maEndPolyPolygon); + } + } // end of namespace attribute +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace attribute + { + SdrShadowAttribute::SdrShadowAttribute(const basegfx::B2DVector& rOffset, double fTransparence, const basegfx::BColor& rColor) + : maOffset(rOffset), + mfTransparence(fTransparence), + maColor(rColor) + { + } + + SdrShadowAttribute::~SdrShadowAttribute() + { + } + + bool SdrShadowAttribute::operator==(const SdrShadowAttribute& rCandidate) const + { + return (mfTransparence == rCandidate.mfTransparence + && maColor == rCandidate.maColor + && maOffset == rCandidate.maOffset); + } + } // end of namespace attribute +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace attribute + { + SdrFillAttribute::SdrFillAttribute( + double fTransparence, + const basegfx::BColor& rColor, + FillGradientAttribute* pGradient, + FillHatchAttribute* pHatch, + SdrFillBitmapAttribute* pBitmap) + : mfTransparence(fTransparence), + maColor(rColor), + mpGradient(pGradient), + mpHatch(pHatch), + mpBitmap(pBitmap) + { + } + + SdrFillAttribute::SdrFillAttribute(const SdrFillAttribute& rCandidate) + : mfTransparence(1.0), + mpGradient(0L), + mpHatch(0L), + mpBitmap(0L) + { + if(!(*this == rCandidate)) + { + *this = rCandidate; + } + } + + SdrFillAttribute::~SdrFillAttribute() + { + delete mpGradient; + delete mpHatch; + delete mpBitmap; + } + + SdrFillAttribute& SdrFillAttribute::operator=(const SdrFillAttribute& rCandidate) + { + // copy data + mfTransparence = rCandidate.mfTransparence; + maColor = rCandidate.maColor; + + // handle mpGradient + { + // delete local mpGradient if necessary + if(mpGradient && ((!rCandidate.mpGradient) || (!(*mpGradient == *rCandidate.mpGradient)))) + { + delete mpGradient; + mpGradient = 0L; + } + + // copy mpGradient if necessary + if(!mpGradient && rCandidate.mpGradient) + { + mpGradient = new FillGradientAttribute(*rCandidate.mpGradient); + } + } + + // handle mpHatch + { + // delete local mpHatch if necessary + if(mpHatch && ((!rCandidate.mpHatch) || (!(*mpHatch == *rCandidate.mpHatch)))) + { + delete mpHatch; + mpHatch = 0L; + } + + // copy mpHatch if necessary + if(!mpHatch && rCandidate.mpHatch) + { + mpHatch = new FillHatchAttribute(*rCandidate.mpHatch); + } + } + + // handle mpBitmap + { + // delete local mpBitmap if necessary + if(mpBitmap && ((!rCandidate.mpBitmap) || (!(*mpBitmap == *rCandidate.mpBitmap)))) + { + delete mpBitmap; + mpBitmap = 0L; + } + + // copy mpBitmap if necessary + if(!mpBitmap && rCandidate.mpBitmap) + { + mpBitmap = new SdrFillBitmapAttribute(*rCandidate.mpBitmap); + } + } + + return *this; + } + + bool SdrFillAttribute::operator==(const SdrFillAttribute& rCandidate) const + { + if(mfTransparence != rCandidate.mfTransparence) + return false; + + if(mpGradient) + { + if(!rCandidate.mpGradient) + return false; + + if(!(*mpGradient == *rCandidate.mpGradient)) + return false; + } + else if(mpHatch) + { + if(!rCandidate.mpHatch) + return false; + + if(!(*mpHatch == *rCandidate.mpHatch)) + return false; + + if(mpHatch->isFillBackground() && !(maColor == rCandidate.maColor)) + return false; + } + else if(mpBitmap) + { + if(!rCandidate.mpBitmap) + return false; + + if(!(*mpBitmap == *rCandidate.mpBitmap)) + return false; + } + else + { + if(!rCandidate.isColor()) + return false; + + if(!(maColor == rCandidate.maColor)) + return false; + } + + return true; + } + } // end of namespace attribute +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/attribute/sdrattribute3d.cxx b/drawinglayer/source/attribute/sdrattribute3d.cxx new file mode 100644 index 000000000000..c130675b9c97 --- /dev/null +++ b/drawinglayer/source/attribute/sdrattribute3d.cxx @@ -0,0 +1,219 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: sdrattribute3d.cxx,v $ + * + * $Revision: 1.5 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:19 $ + * + * 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/attribute/sdrattribute3d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace attribute + { + Sdr3DObjectAttribute::Sdr3DObjectAttribute( + ::com::sun::star::drawing::NormalsKind aNormalsKind, + ::com::sun::star::drawing::TextureProjectionMode aTextureProjectionX, + ::com::sun::star::drawing::TextureProjectionMode aTextureProjectionY, + ::com::sun::star::drawing::TextureKind2 aTextureKind, + ::com::sun::star::drawing::TextureMode aTextureMode, + const MaterialAttribute3D& rMaterial, + bool bNormalsInvert, + bool bDoubleSided, + bool bShadow3D, + bool bTextureFilter, + bool bReducedLineGeometry) + : maNormalsKind(aNormalsKind), + maTextureProjectionX(aTextureProjectionX), + maTextureProjectionY(aTextureProjectionY), + maTextureKind(aTextureKind), + maTextureMode(aTextureMode), + maMaterial(rMaterial), + mbNormalsInvert(bNormalsInvert), + mbDoubleSided(bDoubleSided), + mbShadow3D(bShadow3D), + mbTextureFilter(bTextureFilter), + mbReducedLineGeometry(bReducedLineGeometry) + { + } + + bool Sdr3DObjectAttribute::operator==(const Sdr3DObjectAttribute& rCandidate) const + { + return (maNormalsKind == rCandidate.maNormalsKind + && maTextureProjectionX == rCandidate.maTextureProjectionX + && maTextureProjectionY == rCandidate.maTextureProjectionY + && maTextureKind == rCandidate.maTextureKind + && maTextureMode == rCandidate.maTextureMode + && maMaterial == rCandidate.maMaterial + && mbNormalsInvert == rCandidate.mbNormalsInvert + && mbDoubleSided == rCandidate.mbDoubleSided + && mbShadow3D == rCandidate.mbShadow3D + && mbTextureFilter == rCandidate.mbTextureFilter + && mbReducedLineGeometry == rCandidate.mbReducedLineGeometry); + } + } // end of namespace attribute +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace attribute + { + Sdr3DLightAttribute::Sdr3DLightAttribute(const basegfx::BColor& rColor, const basegfx::B3DVector& rDirection, bool bSpecular) + : maColor(rColor), + maDirection(rDirection), + mbSpecular(bSpecular) + { + } + + bool Sdr3DLightAttribute::operator==(const Sdr3DLightAttribute& rCandidate) const + { + return (maColor == rCandidate.maColor + && maDirection == rCandidate.maDirection + && mbSpecular == rCandidate.mbSpecular); + } + } // end of namespace attribute +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace attribute + { + SdrLightingAttribute::SdrLightingAttribute( + const basegfx::BColor& rAmbientLight, + const ::std::vector< Sdr3DLightAttribute >& rLightVector) + : maAmbientLight(rAmbientLight), + maLightVector(rLightVector) + { + } + + bool SdrLightingAttribute::operator==(const SdrLightingAttribute& rCandidate) const + { + return (maAmbientLight == rCandidate.maAmbientLight + && maLightVector == rCandidate.maLightVector); + } + + // color model solver + basegfx::BColor SdrLightingAttribute::solveColorModel( + const basegfx::B3DVector& rNormalInEyeCoordinates, + const basegfx::BColor& rColor, const basegfx::BColor& rSpecular, + const basegfx::BColor& rEmission, sal_uInt16 nSpecularIntensity) const + { + // initialize with emissive color + basegfx::BColor aRetval(rEmission); + + // take care of global ambient light + aRetval += getAmbientLight() * rColor; + + // prepare light access. Is there a light? + const sal_uInt32 nLightCount(maLightVector.size()); + + if(nLightCount && !rNormalInEyeCoordinates.equalZero()) + { + // prepare normal + basegfx::B3DVector aEyeNormal(rNormalInEyeCoordinates); + aEyeNormal.normalize(); + + for(sal_uInt32 a(0L); a < nLightCount; a++) + { + const Sdr3DLightAttribute& rLight(maLightVector[a]); + const double fCosFac(rLight.getDirection().scalar(aEyeNormal)); + + if(basegfx::fTools::more(fCosFac, 0.0)) + { + aRetval += ((rLight.getColor() * rColor) * fCosFac); + + if(rLight.getSpecular()) + { + // expand by (0.0, 0.0, 1.0) in Z + basegfx::B3DVector aSpecularNormal(rLight.getDirection().getX(), rLight.getDirection().getY(), rLight.getDirection().getZ() + 1.0); + aSpecularNormal.normalize(); + double fCosFac2(aSpecularNormal.scalar(aEyeNormal)); + + if(basegfx::fTools::more(fCosFac2, 0.0)) + { + fCosFac2 = pow(fCosFac2, (double)nSpecularIntensity); + aRetval += (rSpecular * fCosFac2); + } + } + } + } + } + + // clamp to color space before usage + aRetval.clamp(); + + return aRetval; + } + } // end of namespace attribute +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace attribute + { + SdrSceneAttribute::SdrSceneAttribute( + double fDistance, + double fShadowSlant, + ::com::sun::star::drawing::ProjectionMode aProjectionMode, + ::com::sun::star::drawing::ShadeMode aShadeMode, + bool bTwoSidedLighting) + : mfDistance(fDistance), + mfShadowSlant(fShadowSlant), + maProjectionMode(aProjectionMode), + maShadeMode(aShadeMode), + mbTwoSidedLighting(bTwoSidedLighting) + { + } + + bool SdrSceneAttribute::operator==(const SdrSceneAttribute& rCandidate) const + { + return (mfDistance == rCandidate.mfDistance + && mfShadowSlant == rCandidate.mfShadowSlant + && maProjectionMode == rCandidate.maProjectionMode + && maShadeMode == rCandidate.maShadeMode + && mbTwoSidedLighting == rCandidate.mbTwoSidedLighting); + } + } // end of namespace attribute +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/attribute/sdrfillbitmapattribute.cxx b/drawinglayer/source/attribute/sdrfillbitmapattribute.cxx new file mode 100644 index 000000000000..c35d0ba5c15f --- /dev/null +++ b/drawinglayer/source/attribute/sdrfillbitmapattribute.cxx @@ -0,0 +1,237 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: sdrfillbitmapattribute.cxx,v $ + * + * $Revision: 1.4 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:19 $ + * + * 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/attribute/sdrfillbitmapattribute.hxx> +#include <drawinglayer/attribute/fillbitmapattribute.hxx> +#include <basegfx/numeric/ftools.hxx> +#include <basegfx/range/b2drange.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace attribute + { + SdrFillBitmapAttribute::SdrFillBitmapAttribute( + const Bitmap& rBitmap, const basegfx::B2DVector& rSize, const basegfx::B2DVector& rOffset, + const basegfx::B2DVector& rOffsetPosition, const basegfx::B2DVector& rRectPoint, + bool bTiling, bool bStretch, bool bLogSize) + : maBitmap(rBitmap), + maSize(rSize), + maOffset(rOffset), + maOffsetPosition(rOffsetPosition), + maRectPoint(rRectPoint), + mbTiling(bTiling), + mbStretch(bStretch), + mbLogSize(bLogSize) + { + } + + bool SdrFillBitmapAttribute::operator==(const SdrFillBitmapAttribute& rCandidate) const + { + return (maBitmap == rCandidate.maBitmap + && maSize == rCandidate.maSize + && maOffset == rCandidate.maOffset + && maOffsetPosition == rCandidate.maOffsetPosition + && maRectPoint == rCandidate.maRectPoint + && mbTiling == rCandidate.mbTiling + && mbStretch == rCandidate.mbStretch + && mbLogSize == rCandidate.mbLogSize); + } + + FillBitmapAttribute SdrFillBitmapAttribute::getFillBitmapAttribute(const basegfx::B2DRange& rRange) const + { + // get logical size of bitmap (before expanding eventually) + Bitmap aBitmap(maBitmap); + const basegfx::B2DVector aLogicalSize(aBitmap.GetPrefSize().getWidth(), aBitmap.GetPrefSize().getHeight()); + + // get hor/ver shiftings and apply them eventually to the bitmap, but only + // when tiling is on + bool bExpandWidth(false); + bool bExpandHeight(false); + + if(mbTiling) + { + if(0.0 != maOffset.getX() || 0.0 != maOffset.getY()) + { + const sal_uInt32 nWidth(aBitmap.GetSizePixel().getWidth()); + const sal_uInt32 nHeight(aBitmap.GetSizePixel().getHeight()); + + if(0.0 != maOffset.getX()) + { + bExpandHeight = true; + const sal_uInt32 nOffset(basegfx::fround(((double)nWidth * maOffset.getX()) / 100.0)); + aBitmap.Expand(0L, nHeight); + + const Size aSizeA(nOffset, nHeight); + const Rectangle aDstA(Point(0L, nHeight), aSizeA); + const Rectangle aSrcA(Point(nWidth - nOffset, 0L), aSizeA); + aBitmap.CopyPixel(aDstA, aSrcA); + + const Size aSizeB(nWidth - nOffset, nHeight); + const Rectangle aDstB(Point(nOffset, nHeight), aSizeB); + const Rectangle aSrcB(Point(0L, 0L), aSizeB); + aBitmap.CopyPixel(aDstB, aSrcB); + } + else + { + bExpandWidth = true; + const sal_uInt32 nOffset(basegfx::fround(((double)nHeight * maOffset.getY()) / 100.0)); + aBitmap.Expand(nWidth, 0L); + + const Size aSize(nWidth, nHeight); + const Rectangle aDst(Point(nWidth, 0L), aSize); + const Rectangle aSrc(Point(0L, 0L), aSize); + aBitmap.CopyPixel(aDst, aSrc); + + const Size aSizeA(nWidth, nOffset); + const Rectangle aDstA(Point(0L, 0L), aSizeA); + const Rectangle aSrcA(Point(nWidth, nHeight - nOffset), aSizeA); + aBitmap.CopyPixel(aDstA, aSrcA); + + const Size aSizeB(nWidth, nHeight - nOffset); + const Rectangle aDstB(Point(0L, nOffset), aSizeB); + const Rectangle aSrcB(Point(nWidth, 0L), aSizeB); + aBitmap.CopyPixel(aDstB, aSrcB); + } + } + } + + // init values with defaults + basegfx::B2DPoint aBitmapSize(1.0, 1.0); + basegfx::B2DVector aBitmapTopLeft(0.0, 0.0); + + // are canges needed? + if(mbTiling || !mbStretch) + { + // init values with range sizes + const double fRangeWidth(0.0 != rRange.getWidth() ? rRange.getWidth() : 1.0); + const double fRangeHeight(0.0 != rRange.getHeight() ? rRange.getHeight() : 1.0); + aBitmapSize = basegfx::B2DPoint(fRangeWidth, fRangeHeight); + + // size changes + if(0.0 != maSize.getX()) + { + if(maSize.getX() < 0.0) + { + aBitmapSize.setX(aBitmapSize.getX() * (maSize.getX() * -0.01)); + } + else + { + aBitmapSize.setX(maSize.getX()); + } + } + else + { + aBitmapSize.setX(aLogicalSize.getX()); + } + + if(0.0 != maSize.getY()) + { + if(maSize.getY() < 0.0) + { + aBitmapSize.setY(aBitmapSize.getY() * (maSize.getY() * -0.01)); + } + else + { + aBitmapSize.setY(maSize.getY()); + } + } + else + { + aBitmapSize.setY(aLogicalSize.getY()); + } + + // get values, force to centered if necessary + const basegfx::B2DVector aRectPoint(mbTiling ? maRectPoint : basegfx::B2DVector(0.0, 0.0)); + + // position changes X + if(0.0 == aRectPoint.getX()) + { + aBitmapTopLeft.setX((fRangeWidth - aBitmapSize.getX()) * 0.5); + } + else if(1.0 == aRectPoint.getX()) + { + aBitmapTopLeft.setX(fRangeWidth - aBitmapSize.getX()); + } + + if(mbTiling && 0.0 != maOffsetPosition.getX()) + { + aBitmapTopLeft.setX(aBitmapTopLeft.getX() + (aBitmapSize.getX() * (maOffsetPosition.getX() * 0.01))); + } + + // position changes Y + if(0.0 == aRectPoint.getY()) + { + aBitmapTopLeft.setY((fRangeHeight - aBitmapSize.getY()) * 0.5); + } + else if(1.0 == aRectPoint.getY()) + { + aBitmapTopLeft.setY(fRangeHeight - aBitmapSize.getY()); + } + + if(mbTiling && 0.0 != maOffsetPosition.getY()) + { + aBitmapTopLeft.setY(aBitmapTopLeft.getY() + (aBitmapSize.getY() * (maOffsetPosition.getY() * 0.01))); + } + + // apply expand + if(bExpandWidth) + { + aBitmapSize.setX(aBitmapSize.getX() * 2.0); + } + + if(bExpandHeight) + { + aBitmapSize.setY(aBitmapSize.getY() * 2.0); + } + + // apply bitmap size scaling to unit rectangle + aBitmapTopLeft.setX(aBitmapTopLeft.getX() / fRangeWidth); + aBitmapTopLeft.setY(aBitmapTopLeft.getY() / fRangeHeight); + aBitmapSize.setX(aBitmapSize.getX() / fRangeWidth); + aBitmapSize.setY(aBitmapSize.getY() / fRangeHeight); + } + + return FillBitmapAttribute(aBitmap, aBitmapTopLeft, aBitmapSize, mbTiling); + } + } // end of namespace attribute +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/attribute/strokeattribute.cxx b/drawinglayer/source/attribute/strokeattribute.cxx new file mode 100644 index 000000000000..f3eb4797b832 --- /dev/null +++ b/drawinglayer/source/attribute/strokeattribute.cxx @@ -0,0 +1,63 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: strokeattribute.cxx,v $ + * + * $Revision: 1.3 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:19 $ + * + * 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/attribute/strokeattribute.hxx> +#include <numeric> + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace attribute + { + double StrokeAttribute::getFullDotDashLen() const + { + if(0.0 == mfFullDotDashLen && maDotDashArray.size()) + { + // calculate length on demand + const double fAccumulated(::std::accumulate(maDotDashArray.begin(), maDotDashArray.end(), 0.0)); + const_cast< StrokeAttribute* >(this)->mfFullDotDashLen = fAccumulated; + } + + return mfFullDotDashLen; + } + } // end of namespace attribute +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/geometry/makefile.mk b/drawinglayer/source/geometry/makefile.mk new file mode 100644 index 000000000000..38ceeb55a886 --- /dev/null +++ b/drawinglayer/source/geometry/makefile.mk @@ -0,0 +1,52 @@ +#************************************************************************* +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.3 $ +# +# last change: $Author: aw $ $Date: 2008-06-10 09:29:32 $ +# +# 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 +# +#************************************************************************* + +PRJ=..$/.. +PRJNAME=drawinglayer +TARGET=geometry + +# --- Settings ---------------------------------- + +.INCLUDE : settings.mk + +# --- Files ------------------------------------- + +SLOFILES= \ + $(SLO)$/viewinformation2d.obj \ + $(SLO)$/viewinformation3d.obj + +# --- Targets ---------------------------------- + +.INCLUDE : target.mk diff --git a/drawinglayer/source/geometry/viewinformation2d.cxx b/drawinglayer/source/geometry/viewinformation2d.cxx new file mode 100644 index 000000000000..706684c5f7d8 --- /dev/null +++ b/drawinglayer/source/geometry/viewinformation2d.cxx @@ -0,0 +1,553 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: viewinformation2d.cxx,v $ + * + * $Revision: 1.7 $ + * + * last change: $Author: aw $ $Date: 2008-06-24 15:31:07 $ + * + * 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/geometry/viewinformation2d.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/range/b2drange.hxx> +#include <osl/mutex.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <com/sun/star/geometry/AffineMatrix2D.hpp> +#include <com/sun/star/geometry/RealRectangle2D.hpp> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace geometry + { + class ImpViewInformation2D + { + private: + // ViewInformation2D implementation can change refcount, so we have only + // two memory regions for pairs of ViewInformation2D/ImpViewInformation2D + friend class ::drawinglayer::geometry::ViewInformation2D; + + // the refcounter. 0 means exclusively used + sal_uInt32 mnRefCount; + + protected: + // the object transformation + basegfx::B2DHomMatrix maObjectTransformation; + + // the view transformation + basegfx::B2DHomMatrix maViewTransformation; + + // the ObjectToView and it's inverse, both on demand from ObjectTransformation + // and ViewTransformation + basegfx::B2DHomMatrix maObjectToViewTransformation; + basegfx::B2DHomMatrix maInverseObjectToViewTransformation; + + // the visible range and the on-demand one in ViewCoordinates + basegfx::B2DRange maViewport; + basegfx::B2DRange maDiscreteViewport; + + // the DrawPage which is target of visualisation. This is needed e.g. for + // the view-dependent decomposition of PageNumber TextFields. + // This parameter is buffered here, but mainly resides in mxExtendedInformation, + // so it will be interpreted, but held there. It will also not be added + // to mxExtendedInformation in impFillViewInformationFromContent (it's there already) + uno::Reference< drawing::XDrawPage > mxVisualizedPage; + + // the point in time + double mfViewTime; + + // bitfield + bool mbReducedDisplayQuality : 1; + + // the complete PropertyValue representation (if already created) + uno::Sequence< beans::PropertyValue > mxViewInformation; + + // the extra PropertyValues; not represented by ViewTransformation, + // Viewport, VisualizedPage or ViewTime + uno::Sequence< beans::PropertyValue > mxExtendedInformation; + + // the local UNO API strings + const ::rtl::OUString& getNamePropertyObjectTransformation() + { + static ::rtl::OUString s_sNameProperty(RTL_CONSTASCII_USTRINGPARAM("ObjectTransformation")); + return s_sNameProperty; + } + + const ::rtl::OUString& getNamePropertyViewTransformation() + { + static ::rtl::OUString s_sNameProperty(RTL_CONSTASCII_USTRINGPARAM("ViewTransformation")); + return s_sNameProperty; + } + + const ::rtl::OUString& getNamePropertyViewport() + { + static ::rtl::OUString s_sNameProperty(RTL_CONSTASCII_USTRINGPARAM("Viewport")); + return s_sNameProperty; + } + + const ::rtl::OUString& getNamePropertyTime() + { + static ::rtl::OUString s_sNameProperty(RTL_CONSTASCII_USTRINGPARAM("Time")); + return s_sNameProperty; + } + + const ::rtl::OUString& getNamePropertyVisualizedPage() + { + static ::rtl::OUString s_sNameProperty(RTL_CONSTASCII_USTRINGPARAM("VisualizedPage")); + return s_sNameProperty; + } + + const ::rtl::OUString& getNamePropertyReducedDisplayQuality() + { + static ::rtl::OUString s_sNameProperty(RTL_CONSTASCII_USTRINGPARAM("ReducedDisplayQuality")); + return s_sNameProperty; + } + + void impInterpretPropertyValues(const uno::Sequence< beans::PropertyValue >& rViewParameters) + { + if(rViewParameters.hasElements()) + { + const sal_Int32 nCount(rViewParameters.getLength()); + sal_Int32 nExtendedInsert(0); + + // prepare extended information for filtering. Maximum size is nCount + mxExtendedInformation.realloc(nCount); + + for(sal_Int32 a(0); a < nCount; a++) + { + const beans::PropertyValue& rProp = rViewParameters[a]; + + if(rProp.Name == getNamePropertyReducedDisplayQuality()) + { + // extra information; add to filtered information + mxExtendedInformation[nExtendedInsert++] = rProp; + + // for performance reasons, also cache content locally + sal_Bool bSalBool = sal_True; + rProp.Value >>= bSalBool; + mbReducedDisplayQuality = bSalBool; + } + else if(rProp.Name == getNamePropertyObjectTransformation()) + { + com::sun::star::geometry::AffineMatrix2D aAffineMatrix2D; + rProp.Value >>= aAffineMatrix2D; + basegfx::unotools::homMatrixFromAffineMatrix(maObjectTransformation, aAffineMatrix2D); + } + else if(rProp.Name == getNamePropertyViewTransformation()) + { + com::sun::star::geometry::AffineMatrix2D aAffineMatrix2D; + rProp.Value >>= aAffineMatrix2D; + basegfx::unotools::homMatrixFromAffineMatrix(maViewTransformation, aAffineMatrix2D); + } + else if(rProp.Name == getNamePropertyViewport()) + { + com::sun::star::geometry::RealRectangle2D aViewport; + rProp.Value >>= aViewport; + maViewport = basegfx::unotools::b2DRectangleFromRealRectangle2D(aViewport); + } + else if(rProp.Name == getNamePropertyTime()) + { + rProp.Value >>= mfViewTime; + } + else if(rProp.Name == getNamePropertyVisualizedPage()) + { + rProp.Value >>= mxVisualizedPage; + } + else + { + // extra information; add to filtered information + mxExtendedInformation[nExtendedInsert++] = rProp; + } + } + + // extra information size is now known; realloc to final size + mxExtendedInformation.realloc(nExtendedInsert); + } + } + + void impFillViewInformationFromContent() + { + uno::Sequence< beans::PropertyValue > xRetval; + const bool bObjectTransformationUsed(!maObjectTransformation.isIdentity()); + const bool bViewTransformationUsed(!maViewTransformation.isIdentity()); + const bool bViewportUsed(!maViewport.isEmpty()); + const bool bTimeUsed(0.0 < mfViewTime); + const bool bVisualizedPageUsed(mxVisualizedPage.is()); + const bool bReducedDisplayQualityUsed(true == mbReducedDisplayQuality); + const bool bExtraInformation(mxExtendedInformation.hasElements()); + sal_uInt32 nIndex(0); + const sal_uInt32 nCount( + (bObjectTransformationUsed ? 1 : 0) + + (bViewTransformationUsed ? 1 : 0) + + (bViewportUsed ? 1 : 0) + + (bTimeUsed ? 1 : 0) + + (bVisualizedPageUsed ? 1 : 0) + + (bReducedDisplayQualityUsed ? 1 : 0) + + (bExtraInformation ? mxExtendedInformation.getLength() : 0)); + + mxViewInformation.realloc(nCount); + + if(bObjectTransformationUsed) + { + com::sun::star::geometry::AffineMatrix2D aAffineMatrix2D; + basegfx::unotools::affineMatrixFromHomMatrix(aAffineMatrix2D, maObjectTransformation); + mxViewInformation[nIndex].Name = getNamePropertyObjectTransformation(); + mxViewInformation[nIndex].Value <<= aAffineMatrix2D; + nIndex++; + } + + if(bViewTransformationUsed) + { + com::sun::star::geometry::AffineMatrix2D aAffineMatrix2D; + basegfx::unotools::affineMatrixFromHomMatrix(aAffineMatrix2D, maViewTransformation); + mxViewInformation[nIndex].Name = getNamePropertyViewTransformation(); + mxViewInformation[nIndex].Value <<= aAffineMatrix2D; + nIndex++; + } + + if(bViewportUsed) + { + const com::sun::star::geometry::RealRectangle2D aViewport(basegfx::unotools::rectangle2DFromB2DRectangle(maViewport)); + mxViewInformation[nIndex].Name = getNamePropertyViewport(); + mxViewInformation[nIndex].Value <<= aViewport; + nIndex++; + } + + if(bTimeUsed) + { + mxViewInformation[nIndex].Name = getNamePropertyTime(); + mxViewInformation[nIndex].Value <<= mfViewTime; + nIndex++; + } + + if(bVisualizedPageUsed) + { + mxViewInformation[nIndex].Name = getNamePropertyVisualizedPage(); + mxViewInformation[nIndex].Value <<= mxVisualizedPage; + nIndex++; + } + + if(bExtraInformation) + { + const sal_Int32 nExtra(mxExtendedInformation.getLength()); + + for(sal_Int32 a(0); a < nExtra; a++) + { + mxViewInformation[nIndex++] = mxExtendedInformation[a]; + } + } + } + + public: + ImpViewInformation2D( + const basegfx::B2DHomMatrix& rObjectTransformation, + const basegfx::B2DHomMatrix& rViewTransformation, + const basegfx::B2DRange& rViewport, + const uno::Reference< drawing::XDrawPage >& rxDrawPage, + double fViewTime, + const uno::Sequence< beans::PropertyValue >& rExtendedParameters) + : mnRefCount(0), + maObjectTransformation(rObjectTransformation), + maViewTransformation(rViewTransformation), + maObjectToViewTransformation(), + maInverseObjectToViewTransformation(), + maViewport(rViewport), + maDiscreteViewport(), + mxVisualizedPage(rxDrawPage), + mfViewTime(fViewTime), + mbReducedDisplayQuality(false), + mxViewInformation(), + mxExtendedInformation() + { + impInterpretPropertyValues(rExtendedParameters); + } + + ImpViewInformation2D(const uno::Sequence< beans::PropertyValue >& rViewParameters) + : mnRefCount(0), + maObjectTransformation(), + maViewTransformation(), + maObjectToViewTransformation(), + maInverseObjectToViewTransformation(), + maViewport(), + maDiscreteViewport(), + mxVisualizedPage(), + mfViewTime(), + mbReducedDisplayQuality(false), + mxViewInformation(rViewParameters), + mxExtendedInformation() + { + impInterpretPropertyValues(rViewParameters); + } + + const basegfx::B2DHomMatrix& getObjectTransformation() const + { + return maObjectTransformation; + } + + const basegfx::B2DHomMatrix& getViewTransformation() const + { + return maViewTransformation; + } + + const basegfx::B2DRange& getViewport() const + { + return maViewport; + } + + const basegfx::B2DRange& getDiscreteViewport() const + { + ::osl::Mutex m_mutex; + + if(maDiscreteViewport.isEmpty() && !maViewport.isEmpty()) + { + basegfx::B2DRange aDiscreteViewport(maViewport); + aDiscreteViewport.transform(getViewTransformation()); + const_cast< ImpViewInformation2D* >(this)->maDiscreteViewport = aDiscreteViewport; + } + + return maDiscreteViewport; + } + + const basegfx::B2DHomMatrix& getObjectToViewTransformation() const + { + ::osl::Mutex m_mutex; + + if(maObjectToViewTransformation.isIdentity() && + (!maObjectTransformation.isIdentity() || !maViewTransformation.isIdentity())) + { + basegfx::B2DHomMatrix aObjectToView(maViewTransformation * maObjectTransformation); + const_cast< ImpViewInformation2D* >(this)->maObjectToViewTransformation = aObjectToView; + } + + return maObjectToViewTransformation; + } + + const basegfx::B2DHomMatrix& getInverseObjectToViewTransformation() const + { + ::osl::Mutex m_mutex; + + if(maInverseObjectToViewTransformation.isIdentity() && + (!maObjectTransformation.isIdentity() || !maViewTransformation.isIdentity())) + { + basegfx::B2DHomMatrix aInverseObjectToView(maViewTransformation * maObjectTransformation); + aInverseObjectToView.invert(); + const_cast< ImpViewInformation2D* >(this)->maInverseObjectToViewTransformation = aInverseObjectToView; + } + + return maInverseObjectToViewTransformation; + } + + double getViewTime() const + { + return mfViewTime; + } + + const uno::Reference< drawing::XDrawPage >& getVisualizedPage() const + { + return mxVisualizedPage; + } + + bool getReducedDisplayQuality() const + { + return mbReducedDisplayQuality; + } + + const uno::Sequence< beans::PropertyValue >& getViewInformationSequence() const + { + if(!mxViewInformation.hasElements()) + { + const_cast< ImpViewInformation2D* >(this)->impFillViewInformationFromContent(); + } + + return mxViewInformation; + } + + const uno::Sequence< beans::PropertyValue >& getExtendedInformationSequence() const + { + return mxExtendedInformation; + } + + bool operator==(const ImpViewInformation2D& rCandidate) const + { + return (maObjectTransformation == rCandidate.maObjectTransformation + && maViewTransformation == rCandidate.maViewTransformation + && maViewport == rCandidate.maViewport + && mxVisualizedPage == rCandidate.mxVisualizedPage + && mfViewTime == rCandidate.mfViewTime + && mxExtendedInformation == rCandidate.mxExtendedInformation); + } + }; + } // end of anonymous namespace +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace geometry + { + ViewInformation2D::ViewInformation2D( + const basegfx::B2DHomMatrix& rObjectTransformation, + const basegfx::B2DHomMatrix& rViewTransformation, + const basegfx::B2DRange& rViewport, + const uno::Reference< drawing::XDrawPage >& rxDrawPage, + double fViewTime, + const uno::Sequence< beans::PropertyValue >& rExtendedParameters) + : mpViewInformation2D(new ImpViewInformation2D( + rObjectTransformation, + rViewTransformation, + rViewport, + rxDrawPage, + fViewTime, + rExtendedParameters)) + { + } + + ViewInformation2D::ViewInformation2D(const uno::Sequence< beans::PropertyValue >& rViewParameters) + : mpViewInformation2D(new ImpViewInformation2D(rViewParameters)) + { + } + + ViewInformation2D::ViewInformation2D(const ViewInformation2D& rCandidate) + : mpViewInformation2D(rCandidate.mpViewInformation2D) + { + ::osl::Mutex m_mutex; + mpViewInformation2D->mnRefCount++; + } + + ViewInformation2D::~ViewInformation2D() + { + ::osl::Mutex m_mutex; + + if(mpViewInformation2D->mnRefCount) + { + mpViewInformation2D->mnRefCount--; + } + else + { + delete mpViewInformation2D; + } + } + + ViewInformation2D& ViewInformation2D::operator=(const ViewInformation2D& rCandidate) + { + ::osl::Mutex m_mutex; + + if(mpViewInformation2D->mnRefCount) + { + mpViewInformation2D->mnRefCount--; + } + else + { + delete mpViewInformation2D; + } + + mpViewInformation2D = rCandidate.mpViewInformation2D; + mpViewInformation2D->mnRefCount++; + + return *this; + } + + bool ViewInformation2D::operator==(const ViewInformation2D& rCandidate) const + { + if(rCandidate.mpViewInformation2D == mpViewInformation2D) + { + return true; + } + + return (*rCandidate.mpViewInformation2D == *mpViewInformation2D); + } + + const basegfx::B2DHomMatrix& ViewInformation2D::getObjectTransformation() const + { + return mpViewInformation2D->getObjectTransformation(); + } + + const basegfx::B2DHomMatrix& ViewInformation2D::getViewTransformation() const + { + return mpViewInformation2D->getViewTransformation(); + } + + const basegfx::B2DRange& ViewInformation2D::getViewport() const + { + return mpViewInformation2D->getViewport(); + } + + double ViewInformation2D::getViewTime() const + { + return mpViewInformation2D->getViewTime(); + } + + const uno::Reference< drawing::XDrawPage >& ViewInformation2D::getVisualizedPage() const + { + return mpViewInformation2D->getVisualizedPage(); + } + + const basegfx::B2DHomMatrix& ViewInformation2D::getObjectToViewTransformation() const + { + return mpViewInformation2D->getObjectToViewTransformation(); + } + + const basegfx::B2DHomMatrix& ViewInformation2D::getInverseObjectToViewTransformation() const + { + return mpViewInformation2D->getInverseObjectToViewTransformation(); + } + + const basegfx::B2DRange& ViewInformation2D::getDiscreteViewport() const + { + return mpViewInformation2D->getDiscreteViewport(); + } + + bool ViewInformation2D::getReducedDisplayQuality() const + { + return mpViewInformation2D->getReducedDisplayQuality(); + } + + const uno::Sequence< beans::PropertyValue >& ViewInformation2D::getViewInformationSequence() const + { + return mpViewInformation2D->getViewInformationSequence(); + } + + const uno::Sequence< beans::PropertyValue >& ViewInformation2D::getExtendedInformationSequence() const + { + return mpViewInformation2D->getExtendedInformationSequence(); + } + } // end of namespace geometry +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/geometry/viewinformation3d.cxx b/drawinglayer/source/geometry/viewinformation3d.cxx new file mode 100644 index 000000000000..a47384485ee7 --- /dev/null +++ b/drawinglayer/source/geometry/viewinformation3d.cxx @@ -0,0 +1,562 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: viewinformation3d.cxx,v $ + * + * $Revision: 1.2 $ + * + * last change: $Author: aw $ $Date: 2008-06-24 15:31:07 $ + * + * 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/geometry/viewinformation3d.hxx> +#include <basegfx/range/b3drange.hxx> +#include <basegfx/matrix/b3dhommatrix.hxx> +#include <com/sun/star/geometry/AffineMatrix3D.hpp> +#include <com/sun/star/geometry/RealRectangle3D.hpp> +#include <basegfx/tools/canvastools.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace geometry + { + /** Implementation class for ViewInformation3D + */ + class ImpViewInformation3D + { + private: + // ViewInformation3D implementation can change refcount, so we have only + // two memory regions for pairs of ViewInformation3D/ImpViewInformation3D + friend class ::drawinglayer::geometry::ViewInformation3D; + + // the refcounter. 0 means exclusively used + sal_uInt32 mnRefCount; + + // the 3D transformations + // Object to World. This may change and being adapted when entering 3D transformation + // groups + basegfx::B3DHomMatrix maObjectTransformation; + + // World to Camera. This includes VRP, VPN and VUV camera coordinate system + basegfx::B3DHomMatrix maOrientation; + + // Camera to Device with X,Y and Z [-1.0 .. 1.0]. This is the + // 3D to 2D projection which may be parallell or perspective. When it is perspective, + // the last line of the homogen matrix will NOT be unused + basegfx::B3DHomMatrix maProjection; + + // Device to View with X,Y and Z [0.0 .. 1.0]. This converts from -1 to 1 coordinates + // in camera coordinate system to 0 to 1 in unit 2D coordinates. This way it stays + // view-independent. To get discrete coordinates, the 2D transformation of a scene + // as 2D object needs to be involved + basegfx::B3DHomMatrix maDeviceToView; + + // Object to View is the linear combination of all four transformations. It's + // buffered to avoid too much matrix multiplying and created on demand + basegfx::B3DHomMatrix maObjectToView; + + // the point in time + double mfViewTime; + + // the complete PropertyValue representation (if already created) + uno::Sequence< beans::PropertyValue > mxViewInformation; + + // the extra PropertyValues; does not contain the transformations + uno::Sequence< beans::PropertyValue > mxExtendedInformation; + + // the local UNO API strings + const ::rtl::OUString& getNamePropertyObjectTransformation() + { + static ::rtl::OUString s_sNameProperty(RTL_CONSTASCII_USTRINGPARAM("ObjectTransformation")); + return s_sNameProperty; + } + + const ::rtl::OUString& getNamePropertyOrientation() + { + static ::rtl::OUString s_sNameProperty(RTL_CONSTASCII_USTRINGPARAM("Orientation")); + return s_sNameProperty; + } + + const ::rtl::OUString& getNamePropertyProjection() + { + static ::rtl::OUString s_sNameProperty(RTL_CONSTASCII_USTRINGPARAM("Projection")); + return s_sNameProperty; + } + + const ::rtl::OUString& getNamePropertyProjection_30() + { + static ::rtl::OUString s_sNameProperty(RTL_CONSTASCII_USTRINGPARAM("Projection30")); + return s_sNameProperty; + } + + const ::rtl::OUString& getNamePropertyProjection_31() + { + static ::rtl::OUString s_sNameProperty(RTL_CONSTASCII_USTRINGPARAM("Projection31")); + return s_sNameProperty; + } + + const ::rtl::OUString& getNamePropertyProjection_32() + { + static ::rtl::OUString s_sNameProperty(RTL_CONSTASCII_USTRINGPARAM("Projection32")); + return s_sNameProperty; + } + + const ::rtl::OUString& getNamePropertyProjection_33() + { + static ::rtl::OUString s_sNameProperty(RTL_CONSTASCII_USTRINGPARAM("Projection33")); + return s_sNameProperty; + } + + const ::rtl::OUString& getNamePropertyDeviceToView() + { + static ::rtl::OUString s_sNameProperty(RTL_CONSTASCII_USTRINGPARAM("DeviceToView")); + return s_sNameProperty; + } + + const ::rtl::OUString& getNamePropertyTime() + { + static ::rtl::OUString s_sNamePropertyTime(RTL_CONSTASCII_USTRINGPARAM("Time")); + return s_sNamePropertyTime; + } + + // a central PropertyValue parsing method to allow transportatin of + // all ViewParameters using UNO API + void impInterpretPropertyValues(const uno::Sequence< beans::PropertyValue >& rViewParameters) + { + if(rViewParameters.hasElements()) + { + const sal_Int32 nCount(rViewParameters.getLength()); + sal_Int32 nExtendedInsert(0); + + // prepare extended information for filtering. Maximum size is nCount + mxExtendedInformation.realloc(nCount); + + for(sal_Int32 a(0); a < nCount; a++) + { + const beans::PropertyValue& rProp = rViewParameters[a]; + + if(rProp.Name == getNamePropertyObjectTransformation()) + { + com::sun::star::geometry::AffineMatrix3D aAffineMatrix3D; + rProp.Value >>= aAffineMatrix3D; + maObjectTransformation = basegfx::unotools::homMatrixFromAffineMatrix3D(aAffineMatrix3D); + } + else if(rProp.Name == getNamePropertyOrientation()) + { + com::sun::star::geometry::AffineMatrix3D aAffineMatrix3D; + rProp.Value >>= aAffineMatrix3D; + maOrientation = basegfx::unotools::homMatrixFromAffineMatrix3D(aAffineMatrix3D); + } + else if(rProp.Name == getNamePropertyProjection()) + { + // projection may be defined using a frustum in which case the last line of + // the 4x4 matrix is not (0,0,0,1). Since AffineMatrix3D does not support that, + // these four values need to be treated extra + const double f_30(maProjection.get(3, 0)); + const double f_31(maProjection.get(3, 1)); + const double f_32(maProjection.get(3, 2)); + const double f_33(maProjection.get(3, 3)); + + com::sun::star::geometry::AffineMatrix3D aAffineMatrix3D; + rProp.Value >>= aAffineMatrix3D; + maProjection = basegfx::unotools::homMatrixFromAffineMatrix3D(aAffineMatrix3D); + + maProjection.set(3, 0, f_30); + maProjection.set(3, 1, f_31); + maProjection.set(3, 2, f_32); + maProjection.set(3, 3, f_33); + } + else if(rProp.Name == getNamePropertyProjection_30()) + { + double f_30(0.0); + rProp.Value >>= f_30; + maProjection.set(3, 0, f_30); + } + else if(rProp.Name == getNamePropertyProjection_31()) + { + double f_31(0.0); + rProp.Value >>= f_31; + maProjection.set(3, 1, f_31); + } + else if(rProp.Name == getNamePropertyProjection_32()) + { + double f_32(0.0); + rProp.Value >>= f_32; + maProjection.set(3, 2, f_32); + } + else if(rProp.Name == getNamePropertyProjection_33()) + { + double f_33(1.0); + rProp.Value >>= f_33; + maProjection.set(3, 3, f_33); + } + else if(rProp.Name == getNamePropertyDeviceToView()) + { + com::sun::star::geometry::AffineMatrix3D aAffineMatrix3D; + rProp.Value >>= aAffineMatrix3D; + maDeviceToView = basegfx::unotools::homMatrixFromAffineMatrix3D(aAffineMatrix3D); + } + else if(rProp.Name == getNamePropertyTime()) + { + rProp.Value >>= mfViewTime; + } + else + { + // extra information; add to filtered information + mxExtendedInformation[nExtendedInsert++] = rProp; + } + } + + // extra information size is now known; realloc to final size + mxExtendedInformation.realloc(nExtendedInsert); + } + } + + // central method to create a Sequence of PropertyValues containing he complete + // data set + void impFillViewInformationFromContent() + { + uno::Sequence< beans::PropertyValue > xRetval; + const bool bObjectTransformationUsed(!maObjectTransformation.isIdentity()); + const bool bOrientationUsed(!maOrientation.isIdentity()); + const bool bProjectionUsed(!maProjection.isIdentity()); + const bool bDeviceToViewUsed(!maDeviceToView.isIdentity()); + const bool bTimeUsed(0.0 < mfViewTime); + const bool bExtraInformation(mxExtendedInformation.hasElements()); + + // projection may be defined using a frustum in which case the last line of + // the 4x4 matrix is not (0,0,0,1). Since AffineMatrix3D does not support that, + // these four values need to be treated extra + const bool bProjectionUsed_30(bProjectionUsed && !basegfx::fTools::equalZero(maProjection.get(3, 0))); + const bool bProjectionUsed_31(bProjectionUsed && !basegfx::fTools::equalZero(maProjection.get(3, 1))); + const bool bProjectionUsed_32(bProjectionUsed && !basegfx::fTools::equalZero(maProjection.get(3, 2))); + const bool bProjectionUsed_33(bProjectionUsed && !basegfx::fTools::equal(maProjection.get(3, 3), 1.0)); + + sal_uInt32 nIndex(0); + const sal_uInt32 nCount( + (bObjectTransformationUsed ? 1 : 0) + + (bOrientationUsed ? 1 : 0) + + (bProjectionUsed ? 1 : 0) + + (bProjectionUsed_30 ? 1 : 0) + + (bProjectionUsed_31 ? 1 : 0) + + (bProjectionUsed_32 ? 1 : 0) + + (bProjectionUsed_33 ? 1 : 0) + + (bDeviceToViewUsed ? 1 : 0) + + (bTimeUsed ? 1 : 0) + + (bExtraInformation ? mxExtendedInformation.getLength() : 0)); + + mxViewInformation.realloc(nCount); + + if(bObjectTransformationUsed) + { + com::sun::star::geometry::AffineMatrix3D aAffineMatrix3D; + basegfx::unotools::affineMatrixFromHomMatrix3D(aAffineMatrix3D, maObjectTransformation); + mxViewInformation[nIndex].Name = getNamePropertyObjectTransformation(); + mxViewInformation[nIndex].Value <<= aAffineMatrix3D; + nIndex++; + } + + if(bOrientationUsed) + { + com::sun::star::geometry::AffineMatrix3D aAffineMatrix3D; + basegfx::unotools::affineMatrixFromHomMatrix3D(aAffineMatrix3D, maOrientation); + mxViewInformation[nIndex].Name = getNamePropertyOrientation(); + mxViewInformation[nIndex].Value <<= aAffineMatrix3D; + nIndex++; + } + + if(bProjectionUsed) + { + com::sun::star::geometry::AffineMatrix3D aAffineMatrix3D; + basegfx::unotools::affineMatrixFromHomMatrix3D(aAffineMatrix3D, maProjection); + mxViewInformation[nIndex].Name = getNamePropertyProjection(); + mxViewInformation[nIndex].Value <<= aAffineMatrix3D; + nIndex++; + } + + if(bProjectionUsed_30) + { + mxViewInformation[nIndex].Name = getNamePropertyProjection_30(); + mxViewInformation[nIndex].Value <<= maProjection.get(3, 0); + nIndex++; + } + + if(bProjectionUsed_31) + { + mxViewInformation[nIndex].Name = getNamePropertyProjection_31(); + mxViewInformation[nIndex].Value <<= maProjection.get(3, 1); + nIndex++; + } + + if(bProjectionUsed_32) + { + mxViewInformation[nIndex].Name = getNamePropertyProjection_32(); + mxViewInformation[nIndex].Value <<= maProjection.get(3, 2); + nIndex++; + } + + if(bProjectionUsed_33) + { + mxViewInformation[nIndex].Name = getNamePropertyProjection_33(); + mxViewInformation[nIndex].Value <<= maProjection.get(3, 3); + nIndex++; + } + + if(bDeviceToViewUsed) + { + com::sun::star::geometry::AffineMatrix3D aAffineMatrix3D; + basegfx::unotools::affineMatrixFromHomMatrix3D(aAffineMatrix3D, maDeviceToView); + mxViewInformation[nIndex].Name = getNamePropertyDeviceToView(); + mxViewInformation[nIndex].Value <<= aAffineMatrix3D; + nIndex++; + } + + if(bTimeUsed) + { + mxViewInformation[nIndex].Name = getNamePropertyTime(); + mxViewInformation[nIndex].Value <<= mfViewTime; + nIndex++; + } + + if(bExtraInformation) + { + const sal_Int32 nExtra(mxExtendedInformation.getLength()); + + for(sal_Int32 a(0); a < nExtra; a++) + { + mxViewInformation[nIndex++] = mxExtendedInformation[a]; + } + } + } + + public: + ImpViewInformation3D( + const basegfx::B3DHomMatrix& rObjectTransformation, + const basegfx::B3DHomMatrix& rOrientation, + const basegfx::B3DHomMatrix& rProjection, + const basegfx::B3DHomMatrix& rDeviceToView, + double fViewTime, + const uno::Sequence< beans::PropertyValue >& rExtendedParameters) + : mnRefCount(0), + maObjectTransformation(rObjectTransformation), + maOrientation(rOrientation), + maProjection(rProjection), + maDeviceToView(rDeviceToView), + mfViewTime(fViewTime), + mxViewInformation(), + mxExtendedInformation() + { + impInterpretPropertyValues(rExtendedParameters); + } + + ImpViewInformation3D(const uno::Sequence< beans::PropertyValue >& rViewParameters) + : mnRefCount(0), + maObjectTransformation(), + maOrientation(), + maProjection(), + maDeviceToView(), + mfViewTime(), + mxViewInformation(rViewParameters), + mxExtendedInformation() + { + impInterpretPropertyValues(rViewParameters); + } + + const basegfx::B3DHomMatrix& getObjectTransformation() const { return maObjectTransformation; } + const basegfx::B3DHomMatrix& getOrientation() const { return maOrientation; } + const basegfx::B3DHomMatrix& getProjection() const { return maProjection; } + const basegfx::B3DHomMatrix& getDeviceToView() const { return maDeviceToView; } + double getViewTime() const { return mfViewTime; } + + const basegfx::B3DHomMatrix& getObjectToView() const + { + // on demand WorldToView creation + ::osl::Mutex m_mutex; + + if(maObjectToView.isIdentity()) + { + const_cast< ImpViewInformation3D* >(this)->maObjectToView = maDeviceToView * maProjection * maOrientation * maObjectTransformation; + } + + return maObjectToView; + } + + const uno::Sequence< beans::PropertyValue >& getViewInformationSequence() const + { + ::osl::Mutex m_mutex; + + if(!mxViewInformation.hasElements()) + { + const_cast< ImpViewInformation3D* >(this)->impFillViewInformationFromContent(); + } + + return mxViewInformation; + } + + const uno::Sequence< beans::PropertyValue >& getExtendedInformationSequence() const + { + return mxExtendedInformation; + } + + bool operator==(const ImpViewInformation3D& rCandidate) const + { + return (maObjectTransformation == rCandidate.maObjectTransformation + && maOrientation == rCandidate.maOrientation + && maProjection == rCandidate.maProjection + && maDeviceToView == rCandidate.maDeviceToView + && mfViewTime == rCandidate.mfViewTime + && mxExtendedInformation == rCandidate.mxExtendedInformation); + } + }; + } // end of anonymous namespace +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace geometry + { + ViewInformation3D::ViewInformation3D( + const basegfx::B3DHomMatrix& rObjectObjectTransformation, + const basegfx::B3DHomMatrix& rOrientation, + const basegfx::B3DHomMatrix& rProjection, + const basegfx::B3DHomMatrix& rDeviceToView, + double fViewTime, + const uno::Sequence< beans::PropertyValue >& rExtendedParameters) + : mpViewInformation3D(new ImpViewInformation3D(rObjectObjectTransformation, rOrientation, rProjection, rDeviceToView, fViewTime, rExtendedParameters)) + { + } + + ViewInformation3D::ViewInformation3D(const uno::Sequence< beans::PropertyValue >& rViewParameters) + : mpViewInformation3D(new ImpViewInformation3D(rViewParameters)) + { + } + + ViewInformation3D::ViewInformation3D(const ViewInformation3D& rCandidate) + : mpViewInformation3D(rCandidate.mpViewInformation3D) + { + ::osl::Mutex m_mutex; + mpViewInformation3D->mnRefCount++; + } + + ViewInformation3D::~ViewInformation3D() + { + ::osl::Mutex m_mutex; + + if(mpViewInformation3D->mnRefCount) + { + mpViewInformation3D->mnRefCount--; + } + else + { + delete mpViewInformation3D; + } + } + + ViewInformation3D& ViewInformation3D::operator=(const ViewInformation3D& rCandidate) + { + ::osl::Mutex m_mutex; + + if(mpViewInformation3D->mnRefCount) + { + mpViewInformation3D->mnRefCount--; + } + else + { + delete mpViewInformation3D; + } + + mpViewInformation3D = rCandidate.mpViewInformation3D; + mpViewInformation3D->mnRefCount++; + + return *this; + } + + bool ViewInformation3D::operator==(const ViewInformation3D& rCandidate) const + { + if(rCandidate.mpViewInformation3D == mpViewInformation3D) + { + return true; + } + + return (*rCandidate.mpViewInformation3D == *mpViewInformation3D); + } + + const basegfx::B3DHomMatrix& ViewInformation3D::getObjectTransformation() const + { + return mpViewInformation3D->getObjectTransformation(); + } + + const basegfx::B3DHomMatrix& ViewInformation3D::getOrientation() const + { + return mpViewInformation3D->getOrientation(); + } + + const basegfx::B3DHomMatrix& ViewInformation3D::getProjection() const + { + return mpViewInformation3D->getProjection(); + } + + const basegfx::B3DHomMatrix& ViewInformation3D::getDeviceToView() const + { + return mpViewInformation3D->getDeviceToView(); + } + + const basegfx::B3DHomMatrix& ViewInformation3D::getObjectToView() const + { + return mpViewInformation3D->getObjectToView(); + } + + double ViewInformation3D::getViewTime() const + { + return mpViewInformation3D->getViewTime(); + } + + const uno::Sequence< beans::PropertyValue >& ViewInformation3D::getViewInformationSequence() const + { + return mpViewInformation3D->getViewInformationSequence(); + } + + const uno::Sequence< beans::PropertyValue >& ViewInformation3D::getExtendedInformationSequence() const + { + return mpViewInformation3D->getExtendedInformationSequence(); + } + } // end of namespace geometry +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive2d/alphaprimitive2d.cxx b/drawinglayer/source/primitive2d/alphaprimitive2d.cxx new file mode 100644 index 000000000000..a503c2979c41 --- /dev/null +++ b/drawinglayer/source/primitive2d/alphaprimitive2d.cxx @@ -0,0 +1,78 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: alphaprimitive2d.cxx,v $ + * + * $Revision: 1.5 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive2d/alphaprimitive2d.hxx> +#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive2d + { + AlphaPrimitive2D::AlphaPrimitive2D( + const Primitive2DSequence& rChildren, + const Primitive2DSequence& rAlpha) + : GroupPrimitive2D(rChildren), + maAlpha(rAlpha) + { + } + + bool AlphaPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + { + if(GroupPrimitive2D::operator==(rPrimitive)) + { + const AlphaPrimitive2D& rCompare = (AlphaPrimitive2D&)rPrimitive; + + return (getAlpha() == rCompare.getAlpha()); + } + + return false; + } + + // provide unique ID + ImplPrimitrive2DIDBlock(AlphaPrimitive2D, PRIMITIVE2D_ID_ALPHAPRIMITIVE2D) + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive2d/animatedprimitive2d.cxx b/drawinglayer/source/primitive2d/animatedprimitive2d.cxx new file mode 100644 index 000000000000..13f1f699f1ab --- /dev/null +++ b/drawinglayer/source/primitive2d/animatedprimitive2d.cxx @@ -0,0 +1,293 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: animatedprimitive2d.cxx,v $ + * + * $Revision: 1.5 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive2d/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 + { + Primitive2DSequence AnimatedSwitchPrimitive2D::createLocalDecomposition(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(); + } + + AnimatedSwitchPrimitive2D::AnimatedSwitchPrimitive2D( + const animation::AnimationEntry& rAnimationEntry, + const Primitive2DSequence& rChildren, + bool bIsTextAnimation) + : GroupPrimitive2D(rChildren), + mpAnimationEntry(0), + mfDecomposeViewTime(0.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 + { + ::osl::MutexGuard aGuard( m_aMutex ); + + if(getLocalDecomposition().hasElements() && mfDecomposeViewTime != rViewInformation.getViewTime()) + { + // conditions of last local decomposition have changed, delete + const_cast< AnimatedSwitchPrimitive2D* >(this)->setLocalDecomposition(Primitive2DSequence()); + } + + if(!getLocalDecomposition().hasElements()) + { + // remember time + const_cast< AnimatedSwitchPrimitive2D* >(this)->mfDecomposeViewTime = rViewInformation.getViewTime(); + } + + // use parent implementation + return GroupPrimitive2D::get2DDecomposition(rViewInformation); + } + + basegfx::B2DRange AnimatedSwitchPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const + { + // to get range from decomposition and not from group content, call implementation from + // BasePrimitive2D here + return BasePrimitive2D::getB2DRange(rViewInformation); + } + + // provide unique ID + ImplPrimitrive2DIDBlock(AnimatedSwitchPrimitive2D, PRIMITIVE2D_ID_ANIMATEDSWITCHPRIMITIVE2D) + + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive2d + { + Primitive2DSequence AnimatedBlinkPrimitive2D::createLocalDecomposition(const geometry::ViewInformation2D& rViewInformation) const + { + if(getChildren().hasElements()) + { + const double fState(getAnimationEntry().getStateAtTime(rViewInformation.getViewTime())); + + if(fState < 0.5) + { + return getChildren(); + } + } + + return Primitive2DSequence(); + } + + AnimatedBlinkPrimitive2D::AnimatedBlinkPrimitive2D( + const animation::AnimationEntry& rAnimationEntry, + const Primitive2DSequence& rChildren, + bool bIsTextAnimation) + : AnimatedSwitchPrimitive2D(rAnimationEntry, rChildren, bIsTextAnimation) + { + } + + // provide unique ID + ImplPrimitrive2DIDBlock(AnimatedBlinkPrimitive2D, PRIMITIVE2D_ID_ANIMATEDBLINKPRIMITIVE2D) + + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// helper class for AnimatedInterpolatePrimitive2D + +namespace drawinglayer +{ + namespace primitive2d + { + BufferedMatrixDecompose::BufferedMatrixDecompose(const basegfx::B2DHomMatrix& rMatrix) + : maB2DHomMatrix(rMatrix), + maScale(0.0, 0.0), + maTranslate(0.0, 0.0), + mfRotate(0.0), + mfShearX(0.0), + mbDecomposed(false) + { + } + + void BufferedMatrixDecompose::ensureDecompose() const + { + if(!mbDecomposed) + { + BufferedMatrixDecompose* pThis = const_cast< BufferedMatrixDecompose* >(this); + maB2DHomMatrix.decompose(pThis->maScale, pThis->maTranslate, pThis->mfRotate, pThis->mfShearX); + pThis->mbDecomposed = true; + } + } + } // end of anonymous namespace +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive2d + { + Primitive2DSequence AnimatedInterpolatePrimitive2D::createLocalDecomposition(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; + + if(basegfx::fTools::equalZero(fOffset)) + { + // use matrix from nIndA directly + aTargetTransform = maMatrixStack[nIndA].getB2DHomMatrix(); + } + else + { + // interpolate. Get involved matrices and ensure they are decomposed + const sal_uInt32 nIndB((nIndA + 1L) % nSize); + std::vector< BufferedMatrixDecompose >::const_iterator aMatA(maMatrixStack.begin() + nIndA); + std::vector< BufferedMatrixDecompose >::const_iterator aMatB(maMatrixStack.begin() + nIndB); + + aMatA->ensureDecompose(); + aMatB->ensureDecompose(); + + // 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.scale(aScale.getX(), aScale.getY()); + aTargetTransform.shearX(fShearX); + aTargetTransform.rotate(fRotate); + aTargetTransform.translate(aTranslate.getX(), aTranslate.getY()); + } + + // create new transform primitive reference, return new sequence + const Primitive2DReference xRef(new TransformPrimitive2D(aTargetTransform, getChildren())); + return Primitive2DSequence(&xRef, 1L); + } + else + { + return getChildren(); + } + } + + AnimatedInterpolatePrimitive2D::AnimatedInterpolatePrimitive2D( + const std::vector< basegfx::B2DHomMatrix >& rmMatrixStack, + const animation::AnimationEntry& rAnimationEntry, + const Primitive2DSequence& rChildren, + bool bIsTextAnimation) + : AnimatedSwitchPrimitive2D(rAnimationEntry, rChildren, bIsTextAnimation), + maMatrixStack() + { + // copy matrices + const sal_uInt32 nCount(rmMatrixStack.size()); + + for(sal_uInt32 a(0L); a < nCount; a++) + { + maMatrixStack.push_back(BufferedMatrixDecompose(rmMatrixStack[a])); + } + } + + // provide unique ID + ImplPrimitrive2DIDBlock(AnimatedInterpolatePrimitive2D, PRIMITIVE2D_ID_ANIMATEDINTERPOLATEPRIMITIVE2D) + + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive2d/backgroundcolorprimitive2d.cxx b/drawinglayer/source/primitive2d/backgroundcolorprimitive2d.cxx new file mode 100644 index 000000000000..cff797451954 --- /dev/null +++ b/drawinglayer/source/primitive2d/backgroundcolorprimitive2d.cxx @@ -0,0 +1,124 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: backgroundcolorprimitive2d.cxx,v $ + * + * $Revision: 1.5 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive2d/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::createLocalDecomposition(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) + : BasePrimitive2D(), + maBColor(rBColor), + maLastViewport() + { + } + + bool BackgroundColorPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + { + if(BasePrimitive2D::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(getLocalDecomposition().hasElements() && (maLastViewport != rViewInformation.getViewport())) + { + // conditions of last local decomposition have changed, delete + const_cast< BackgroundColorPrimitive2D* >(this)->setLocalDecomposition(Primitive2DSequence()); + } + + if(!getLocalDecomposition().hasElements()) + { + // remember ViewRange + const_cast< BackgroundColorPrimitive2D* >(this)->maLastViewport = rViewInformation.getViewport(); + } + + // use parent implementation + return BasePrimitive2D::get2DDecomposition(rViewInformation); + } + + // provide unique ID + ImplPrimitrive2DIDBlock(BackgroundColorPrimitive2D, PRIMITIVE2D_ID_BACKGROUNDCOLORPRIMITIVE2D) + + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive2d/baseprimitive2d.cxx b/drawinglayer/source/primitive2d/baseprimitive2d.cxx new file mode 100644 index 000000000000..63941512bfb0 --- /dev/null +++ b/drawinglayer/source/primitive2d/baseprimitive2d.cxx @@ -0,0 +1,264 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: baseprimitive2d.cxx,v $ + * + * $Revision: 1.6 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive2d/baseprimitive2d.hxx> +#include <drawinglayer/geometry/viewinformation2d.hxx> +#include <basegfx/tools/canvastools.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive2d + { + Primitive2DSequence BasePrimitive2D::createLocalDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const + { + return Primitive2DSequence(); + } + + BasePrimitive2D::BasePrimitive2D() + : BasePrimitive2DImplBase(m_aMutex), + maLocalDecomposition() + { + } + + bool BasePrimitive2D::operator==( const BasePrimitive2D& rPrimitive ) const + { + return (getPrimitiveID() == rPrimitive.getPrimitiveID()); + } + + basegfx::B2DRange BasePrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const + { + return getB2DRangeFromPrimitive2DSequence(get2DDecomposition(rViewInformation), rViewInformation); + } + + Primitive2DSequence BasePrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const + { + ::osl::MutexGuard aGuard( m_aMutex ); + + if(!getLocalDecomposition().hasElements()) + { + const Primitive2DSequence aNewSequence(createLocalDecomposition(rViewInformation)); + const_cast< BasePrimitive2D* >(this)->setLocalDecomposition(aNewSequence); + } + + return getLocalDecomposition(); + } + + 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 + +////////////////////////////////////////////////////////////////////////////// +// 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 diff --git a/drawinglayer/source/primitive2d/bitmapprimitive2d.cxx b/drawinglayer/source/primitive2d/bitmapprimitive2d.cxx new file mode 100644 index 000000000000..5900900bcf06 --- /dev/null +++ b/drawinglayer/source/primitive2d/bitmapprimitive2d.cxx @@ -0,0 +1,89 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: bitmapprimitive2d.cxx,v $ + * + * $Revision: 1.5 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive2d/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 (maBitmapEx == rCompare.maBitmapEx + && maTransform == rCompare.maTransform); + } + + 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 diff --git a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx new file mode 100644 index 000000000000..ba73f920cb08 --- /dev/null +++ b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx @@ -0,0 +1,243 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: borderlineprimitive2d.cxx,v $ + * + * $Revision: 1.5 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive2d/borderlineprimitive2d.hxx> +#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <drawinglayer/primitive2d/polygonprimitive2d.hxx> +#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> +#include <numeric> + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive2d + { + Primitive2DSequence BorderLinePrimitive2D::createLocalDecomposition(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 + aLineWidthOffset); + aPolygon.append(aTmpEnd + aLineWidthOffset); + aPolygon.append(aTmpEnd - aLineWidthOffset); + aPolygon.append(aTmpStart - aLineWidthOffset); + aPolygon.setClosed(true); + + xRetval[0] = Primitive2DReference(new PolyPolygonColorPrimitive2D( + basegfx::B2DPolyPolygon(aPolygon), 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) + : BasePrimitive2D(), + maStart(rStart), + maEnd(rEnd), + mfLeftWidth(fLeftWidth), + mfDistance(fDistance), + mfRightWidth(fRightWidth), + mfExtendInnerStart(fExtendInnerStart), + mfExtendInnerEnd(fExtendInnerEnd), + mfExtendOuterStart(fExtendOuterStart), + mfExtendOuterEnd(fExtendOuterEnd), + maRGBColor(rRGBColor), + mbCreateInside(bCreateInside), + mbCreateOutside(bCreateOutside) + { + } + + bool BorderLinePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + { + if(BasePrimitive2D::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()); + } + + return false; + } + + // provide unique ID + ImplPrimitrive2DIDBlock(BorderLinePrimitive2D, PRIMITIVE2D_ID_BORDERLINEPRIMITIVE2D) + + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive2d/chartprimitive2d.cxx b/drawinglayer/source/primitive2d/chartprimitive2d.cxx new file mode 100644 index 000000000000..3df6464f8aeb --- /dev/null +++ b/drawinglayer/source/primitive2d/chartprimitive2d.cxx @@ -0,0 +1,90 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: chartprimitive2d.cxx,v $ + * + * $Revision: 1.3 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive2d/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 diff --git a/drawinglayer/source/primitive2d/controlprimitive2d.cxx b/drawinglayer/source/primitive2d/controlprimitive2d.cxx new file mode 100644 index 000000000000..6241eeb2fa73 --- /dev/null +++ b/drawinglayer/source/primitive2d/controlprimitive2d.cxx @@ -0,0 +1,394 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: controlprimitive2d.cxx,v $ + * + * $Revision: 1.6 $ + * + * last change: $Author: aw $ $Date: 2008-06-24 15:31:08 $ + * + * 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/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> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive2d + { + void ControlPrimitive2D::createXControl() + { + if(!mxXControl.is() && getControlModel().is()) + { + uno::Reference< beans::XPropertySet > xSet(getControlModel(), uno::UNO_QUERY); + + if(xSet.is()) + { + uno::Any aValue(xSet->getPropertyValue(rtl::OUString::createFromAscii("DefaultControl"))); + rtl::OUString aUnoControlTypeName; + + if(aValue >>= aUnoControlTypeName) + { + if(aUnoControlTypeName.getLength()) + { + uno::Reference< lang::XMultiServiceFactory > xFactory( comphelper::getProcessServiceFactory() ); + + if(xFactory.is()) + { + uno::Reference< awt::XControl > xXControl(xFactory->createInstance(aUnoControlTypeName), uno::UNO_QUERY); + + if(xXControl.is()) + { + xXControl->setModel(getControlModel()); + + // remember XControl + mxXControl = xXControl; + } + } + } + } + } + } + } + + Primitive2DReference ControlPrimitive2D::createBitmapDecomposition(const geometry::ViewInformation2D& rViewInformation) const + { + Primitive2DReference xRetval; + const uno::Reference< awt::XControl >& rXControl(getXControl()); + + if(rXControl.is()) + { + uno::Reference< awt::XWindow > xControlWindow(rXControl, uno::UNO_QUERY); + + if(xControlWindow.is()) + { + // get decomposition to get size + basegfx::B2DVector aScale, aTranslate; + double fRotate, fShearX; + getTransform().decompose(aScale, aTranslate, fRotate, fShearX); + + // get absolute discrete size (no mirror or rotate here) + aScale = basegfx::absolute(aScale); + basegfx::B2DVector aDiscreteSize(rViewInformation.getObjectToViewTransformation() * aScale); + + // limit to a maximum square size, e.g. 300x150 pixels (45000) + const SvtOptionsDrawinglayer aDrawinglayerOpt; + const double fDiscreteMax(aDrawinglayerOpt.GetQuadraticFormControlRenderLimit()); + const double fDiscreteQuadratic(aDiscreteSize.getX() * aDiscreteSize.getY()); + const bool bScaleUsed(fDiscreteQuadratic > fDiscreteMax); + double fFactor(1.0); + + if(bScaleUsed) + { + // get factor and adapt to scaled size + fFactor = sqrt(fDiscreteMax / fDiscreteQuadratic); + aDiscreteSize *= fFactor; + } + + // go to integer + const sal_Int32 nSizeX(basegfx::fround(aDiscreteSize.getX())); + const sal_Int32 nSizeY(basegfx::fround(aDiscreteSize.getY())); + + if(nSizeX > 0 && nSizeY > 0) + { + // prepare VirtualDevice + VirtualDevice aVirtualDevice(*Application::GetDefaultDevice()); + const Size aSizePixel(nSizeX, nSizeY); + aVirtualDevice.SetOutputSizePixel(aSizePixel); + + // set size at control + xControlWindow->setPosSize(0, 0, nSizeX, nSizeY, awt::PosSize::POSSIZE); + + // get graphics and view + uno::Reference< awt::XGraphics > xGraphics(aVirtualDevice.CreateUnoGraphics()); + uno::Reference< awt::XView > xControlView(rXControl, uno::UNO_QUERY); + + if(xGraphics.is() && xControlView.is()) + { + // link graphics and view + xControlView->setGraphics(xGraphics); + + { // #i93162# For painting the control setting a Zoom (using setZoom() at the xControlView) + // is needed to define the font size. Normally this is done in + // ViewObjectContactOfUnoControl::createPrimitive2DSequence by using positionControlForPaint(). + // For some reason the difference between MAP_TWIPS and MAP_100TH_MM still plays + // a role there so that for Draw/Impress/Calc (the MAP_100TH_MM users) i need to set a zoom + // here, too. The factor includes the needed scale, but is calculated by pure comparisons. It + // is somehow related to the twips/100thmm relationship. + bool bUserIs100thmm(false); + const uno::Reference< awt::XControl > xControl(xControlView, uno::UNO_QUERY); + + if(xControl.is()) + { + uno::Reference< awt::XWindowPeer > xWindowPeer(xControl->getPeer()); + + if(xWindowPeer.is()) + { + VCLXWindow* pVCLXWindow = VCLXWindow::GetImplementation(xWindowPeer); + + if(pVCLXWindow) + { + Window* pWindow = pVCLXWindow->GetWindow(); + + if(pWindow) + { + pWindow = pWindow->GetParent(); + + if(pWindow) + { + if(MAP_100TH_MM == pWindow->GetMapMode().GetMapUnit()) + { + bUserIs100thmm = true; + } + } + } + } + } + } + + if(bUserIs100thmm) + { + // calc screen zoom for text display. fFactor is already added indirectly in aDiscreteSize + basegfx::B2DVector aScreenZoom( + basegfx::fTools::equalZero(aScale.getX()) ? 1.0 : aDiscreteSize.getX() / aScale.getX(), + basegfx::fTools::equalZero(aScale.getY()) ? 1.0 : aDiscreteSize.getY() / aScale.getY()); + static double fZoomScale(28.0); // do not ask for this constant factor, but it gets the zoom right + aScreenZoom *= fZoomScale; + + // set zoom at control view for text scaling + xControlView->setZoom((float)aScreenZoom.getX(), (float)aScreenZoom.getY()); + } + } + + try + { + // try to paint it to VirtualDevice + xControlView->draw(0, 0); + + // get bitmap + const Bitmap aContent(aVirtualDevice.GetBitmap(Point(), aSizePixel)); + + // to avoid scaling, use the Bitmap pixel size as primitive size + const Size aBitmapSize(aContent.GetSizePixel()); + basegfx::B2DVector aBitmapSizeLogic( + rViewInformation.getInverseObjectToViewTransformation() * + basegfx::B2DVector(aBitmapSize.getWidth() - 1, aBitmapSize.getHeight() - 1)); + + if(bScaleUsed) + { + // if scaled adapt to scaled size + aBitmapSizeLogic /= fFactor; + } + + // short form for scale and translate transformation + basegfx::B2DHomMatrix aBitmapTransform; + + aBitmapTransform.set(0L, 0L, aBitmapSizeLogic.getX()); + aBitmapTransform.set(1L, 1L, aBitmapSizeLogic.getY()); + aBitmapTransform.set(0L, 2L, aTranslate.getX()); + aBitmapTransform.set(1L, 2L, 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::createLocalDecomposition(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) + : BasePrimitive2D(), + maTransform(rTransform), + mxControlModel(rxControlModel), + mxXControl(), + maLastViewScaling() + { + } + + ControlPrimitive2D::ControlPrimitive2D( + const basegfx::B2DHomMatrix& rTransform, + const uno::Reference< awt::XControlModel >& rxControlModel, + const uno::Reference< awt::XControl >& rxXControl) + : BasePrimitive2D(), + 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(BasePrimitive2D::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(getLocalDecomposition().hasElements()) + { + if(!maLastViewScaling.equal(aNewScaling)) + { + // conditions of last local decomposition have changed, delete + const_cast< ControlPrimitive2D* >(this)->setLocalDecomposition(Primitive2DSequence()); + } + } + + if(!getLocalDecomposition().hasElements()) + { + // remember ViewTransformation + const_cast< ControlPrimitive2D* >(this)->maLastViewScaling = aNewScaling; + } + + // use parent implementation + return BasePrimitive2D::get2DDecomposition(rViewInformation); + } + + // provide unique ID + ImplPrimitrive2DIDBlock(ControlPrimitive2D, PRIMITIVE2D_ID_CONTROLPRIMITIVE2D) + + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive2d/embedded3dprimitive2d.cxx b/drawinglayer/source/primitive2d/embedded3dprimitive2d.cxx new file mode 100644 index 000000000000..5805c02a61ed --- /dev/null +++ b/drawinglayer/source/primitive2d/embedded3dprimitive2d.cxx @@ -0,0 +1,176 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: embedded3dprimitive2d.cxx,v $ + * + * $Revision: 1.8 $ + * + * last change: $Author: aw $ $Date: 2008-06-24 15:31:08 $ + * + * 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/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::createLocalDecomposition(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) + : BasePrimitive2D(), + 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(BasePrimitive2D::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 diff --git a/drawinglayer/source/primitive2d/fillbitmapprimitive2d.cxx b/drawinglayer/source/primitive2d/fillbitmapprimitive2d.cxx new file mode 100644 index 000000000000..125c2cb42193 --- /dev/null +++ b/drawinglayer/source/primitive2d/fillbitmapprimitive2d.cxx @@ -0,0 +1,142 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: fillbitmapprimitive2d.cxx,v $ + * + * $Revision: 1.5 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive2d/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::createLocalDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const + { + const Size aTileSizePixel(getFillBitmap().getBitmap().GetSizePixel()); + Primitive2DSequence aRetval; + + // 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(BitmapEx(getFillBitmap().getBitmap()), 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(BitmapEx(getFillBitmap().getBitmap()), aObjectTransform)); + aRetval = Primitive2DSequence(&xRef, 1L); + } + } + + return aRetval; + } + + FillBitmapPrimitive2D::FillBitmapPrimitive2D( + const basegfx::B2DHomMatrix& rTransformation, + const attribute::FillBitmapAttribute& rFillBitmap) + : BasePrimitive2D(), + maTransformation(rTransformation), + maFillBitmap(rFillBitmap) + { + } + + bool FillBitmapPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + { + if(BasePrimitive2D::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::createPolygonFromRect(basegfx::B2DRange(0.0, 0.0, 1.0, 1.0))); + aPolygon.transform(getTransformation()); + return basegfx::tools::getRange(aPolygon); + } + + // provide unique ID + ImplPrimitrive2DIDBlock(FillBitmapPrimitive2D, PRIMITIVE2D_ID_FILLBITMAPPRIMITIVE2D) + + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx b/drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx new file mode 100644 index 000000000000..ff0c031b38a1 --- /dev/null +++ b/drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx @@ -0,0 +1,202 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: fillgradientprimitive2d.cxx,v $ + * + * $Revision: 1.6 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive2d/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 + { + Primitive2DSequence FillGradientPrimitive2D::createLocalDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const + { + const attribute::GradientStyle aGradientStyle(maFillGradient.getStyle()); + ::std::vector< basegfx::B2DHomMatrix > aMatrices; + ::std::vector< basegfx::BColor > aColors; + basegfx::B2DPolygon aUnitPolygon; + sal_uInt32 nSteps(maFillGradient.getSteps()); + + if(attribute::GRADIENTSTYLE_RADIAL == aGradientStyle || attribute::GRADIENTSTYLE_ELLIPTICAL == aGradientStyle) + { + const basegfx::B2DPoint aCircleCenter(0.5, 0.5); + aUnitPolygon = basegfx::tools::createPolygonFromEllipse(aCircleCenter, 0.5, 0.5); + } + else + { + aUnitPolygon = basegfx::tools::createPolygonFromRect(basegfx::B2DRange(0.0, 0.0, 1.0, 1.0)); + } + + // make sure steps is not too high/low + const basegfx::BColor aStart(maFillGradient.getStartColor()); + const basegfx::BColor aEnd(maFillGradient.getEndColor()); + const sal_uInt32 nMaxSteps(sal_uInt32((aStart.getMaximumDistance(aEnd) * 127.5) + 0.5)); + + if(nSteps == 0L) + { + nSteps = nMaxSteps; + } + + if(nSteps < 2L) + { + nSteps = 2L; + } + + if(nSteps > nMaxSteps) + { + nSteps = nMaxSteps; + } + + switch(aGradientStyle) + { + case attribute::GRADIENTSTYLE_LINEAR: + { + texture::GeoTexSvxGradientLinear aGradient(getObjectRange(), aStart, aEnd, nSteps, maFillGradient.getBorder(), -maFillGradient.getAngle()); + aGradient.appendTransformations(aMatrices); + aGradient.appendColors(aColors); + break; + } + case attribute::GRADIENTSTYLE_AXIAL: + { + texture::GeoTexSvxGradientAxial aGradient(getObjectRange(), aStart, aEnd, nSteps, maFillGradient.getBorder(), -maFillGradient.getAngle()); + aGradient.appendTransformations(aMatrices); + aGradient.appendColors(aColors); + break; + } + case attribute::GRADIENTSTYLE_RADIAL: + { + texture::GeoTexSvxGradientRadial aGradient(getObjectRange(), aStart, aEnd, nSteps, maFillGradient.getBorder(), maFillGradient.getOffsetX(), maFillGradient.getOffsetY()); + aGradient.appendTransformations(aMatrices); + aGradient.appendColors(aColors); + break; + } + case attribute::GRADIENTSTYLE_ELLIPTICAL: + { + texture::GeoTexSvxGradientElliptical aGradient(getObjectRange(), aStart, aEnd, nSteps, maFillGradient.getBorder(), maFillGradient.getOffsetX(), maFillGradient.getOffsetY(), -maFillGradient.getAngle()); + aGradient.appendTransformations(aMatrices); + aGradient.appendColors(aColors); + break; + } + case attribute::GRADIENTSTYLE_SQUARE: + { + texture::GeoTexSvxGradientSquare aGradient(getObjectRange(), aStart, aEnd, nSteps, maFillGradient.getBorder(), maFillGradient.getOffsetX(), maFillGradient.getOffsetY(), -maFillGradient.getAngle()); + aGradient.appendTransformations(aMatrices); + aGradient.appendColors(aColors); + break; + } + case attribute::GRADIENTSTYLE_RECT: + { + texture::GeoTexSvxGradientRect aGradient(getObjectRange(), aStart, aEnd, nSteps, maFillGradient.getBorder(), maFillGradient.getOffsetX(), maFillGradient.getOffsetY(), -maFillGradient.getAngle()); + aGradient.appendTransformations(aMatrices); + aGradient.appendColors(aColors); + break; + } + } + + // prepare return value + Primitive2DSequence aRetval(aColors.size() ? aMatrices.size() + 1L : aMatrices.size()); + + // create solid fill with start color + if(aColors.size()) + { + // create primitive + const Primitive2DReference xRef(new PolyPolygonColorPrimitive2D(basegfx::B2DPolyPolygon(basegfx::tools::createPolygonFromRect(getObjectRange())), aColors[0L])); + aRetval[0L] = xRef; + } + + // create solid fill steps + for(sal_uInt32 a(0L); a < aMatrices.size(); a++) + { + // create part polygon + basegfx::B2DPolygon aNewPoly(aUnitPolygon); + aNewPoly.transform(aMatrices[a]); + + // create solid fill + const Primitive2DReference xRef(new PolyPolygonColorPrimitive2D(basegfx::B2DPolyPolygon(aNewPoly), aColors[a + 1L])); + aRetval[a + 1L] = xRef; + } + + return aRetval; + } + + FillGradientPrimitive2D::FillGradientPrimitive2D( + const basegfx::B2DRange& rObjectRange, + const attribute::FillGradientAttribute& rFillGradient) + : BasePrimitive2D(), + maObjectRange(rObjectRange), + maFillGradient(rFillGradient) + { + } + + bool FillGradientPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + { + if(BasePrimitive2D::operator==(rPrimitive)) + { + const FillGradientPrimitive2D& rCompare = (FillGradientPrimitive2D&)rPrimitive; + + return (getObjectRange() == rCompare.getObjectRange() + && maFillGradient == rCompare.maFillGradient); + } + + 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 diff --git a/drawinglayer/source/primitive2d/fillhatchprimitive2d.cxx b/drawinglayer/source/primitive2d/fillhatchprimitive2d.cxx new file mode 100644 index 000000000000..06d04111686d --- /dev/null +++ b/drawinglayer/source/primitive2d/fillhatchprimitive2d.cxx @@ -0,0 +1,162 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: fillhatchprimitive2d.cxx,v $ + * + * $Revision: 1.6 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive2d/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::createLocalDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const + { + // create hatch + const basegfx::BColor aHatchColor(maFillHatch.getColor()); + const double fAngle(-maFillHatch.getAngle()); + ::std::vector< basegfx::B2DHomMatrix > aMatrices; + + // get hatch transformations + switch(maFillHatch.getStyle()) + { + case attribute::HATCHSTYLE_TRIPLE: + { + // rotated 45 degrees + texture::GeoTexSvxHatch aHatch(getObjectRange(), maFillHatch.getDistance(), fAngle + F_PI4); + aHatch.appendTransformations(aMatrices); + + // fall-through by purpose + } + case attribute::HATCHSTYLE_DOUBLE: + { + // rotated 90 degrees + texture::GeoTexSvxHatch aHatch(getObjectRange(), maFillHatch.getDistance(), fAngle + F_PI2); + aHatch.appendTransformations(aMatrices); + + // fall-through by purpose + } + case attribute::HATCHSTYLE_SINGLE: + { + // angle as given + texture::GeoTexSvxHatch aHatch(getObjectRange(), maFillHatch.getDistance(), fAngle); + aHatch.appendTransformations(aMatrices); + } + } + + // prepare return value + const bool bFillBackground(maFillHatch.isFillBackground()); + Primitive2DSequence aRetval(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())), maBColor)); + aRetval[0L] = 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 + 1L) : a] = xRef; + } + + return aRetval; + } + + FillHatchPrimitive2D::FillHatchPrimitive2D( + const basegfx::B2DRange& rObjectRange, + const basegfx::BColor& rBColor, + const attribute::FillHatchAttribute& rFillHatch) + : BasePrimitive2D(), + maObjectRange(rObjectRange), + maFillHatch(rFillHatch), + maBColor(rBColor) + { + } + + bool FillHatchPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + { + if(BasePrimitive2D::operator==(rPrimitive)) + { + const FillHatchPrimitive2D& rCompare = (FillHatchPrimitive2D&)rPrimitive; + + return (getObjectRange() == rCompare.getObjectRange() + && maFillHatch == rCompare.maFillHatch + && maBColor == rCompare.maBColor); + } + + 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 diff --git a/drawinglayer/source/primitive2d/graphicprimitive2d.cxx b/drawinglayer/source/primitive2d/graphicprimitive2d.cxx new file mode 100644 index 000000000000..1ed826dab562 --- /dev/null +++ b/drawinglayer/source/primitive2d/graphicprimitive2d.cxx @@ -0,0 +1,458 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: graphicprimitive2d.cxx,v $ + * + * $Revision: 1.3 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive2d/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> + +////////////////////////////////////////////////////////////////////////////// + +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::createLocalDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const + { + Primitive2DSequence aRetval; + + if(255L != getGraphicAttr().GetTransparency()) + { + // 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) + GraphicAttr aSuppressGraphicAttr(getGraphicAttr()); + aSuppressGraphicAttr.SetCrop(0L, 0L, 0L, 0L); + aSuppressGraphicAttr.SetRotation(0); + Graphic aTransformedGraphic(getGraphicObject().GetTransformedGraphic(&aSuppressGraphicAttr)); + Primitive2DReference xPrimitive; + + 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), getTransform())); + 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(), getTransform())); + } + + break; + } + + case GRAPHIC_GDIMETAFILE : + { + // create MetafilePrimitive2D + const GDIMetaFile& rMetafile = aTransformedGraphic.GetGDIMetaFile(); + + xPrimitive = Primitive2DReference( + new MetafilePrimitive2D( + getTransform(), + 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::createPolygonFromRect( + basegfx::B2DRange(0.0, 0.0, 1.0, 1.0))); + aMaskPolygon.transform(getTransform()); + + 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.scale(aCropped.getWidth(), aCropped.getHeight()); + aNewObjectTransform.translate(aCropped.getMinX() - aCurrent.getMinX(), aCropped.getMinY() - aCurrent.getMinY()); + aNewObjectTransform.shearX(fShearX); + aNewObjectTransform.rotate(fRotate); + aNewObjectTransform.translate(aTranslate.getX(), aTranslate.getY()); + + // 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::createPolygonFromRect(basegfx::B2DRange(0.0, 0.0, 1.0, 1.0))); + 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) + : BasePrimitive2D(), + maTransform(rTransform), + maGraphicObject(rGraphicObject), + maGraphicAttr(rGraphicAttr) + { + } + + GraphicPrimitive2D::GraphicPrimitive2D( + const basegfx::B2DHomMatrix& rTransform, + const GraphicObject& rGraphicObject) + : BasePrimitive2D(), + maTransform(rTransform), + maGraphicObject(rGraphicObject), + maGraphicAttr() + { + } + + bool GraphicPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + { + if(BasePrimitive2D::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 diff --git a/drawinglayer/source/primitive2d/gridprimitive2d.cxx b/drawinglayer/source/primitive2d/gridprimitive2d.cxx new file mode 100644 index 000000000000..df4171309389 --- /dev/null +++ b/drawinglayer/source/primitive2d/gridprimitive2d.cxx @@ -0,0 +1,329 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: gridprimitive2d.cxx,v $ + * + * $Revision: 1.10 $ + * + * last change: $Author: aw $ $Date: 2008-06-24 15:31:08 $ + * + * 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/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> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive2d + { + Primitive2DSequence GridPrimitive2D::createLocalDecomposition(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; + aRST.shearX(fShearX); + aRST.rotate(fRotate); + aRST.translate(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) + : BasePrimitive2D(), + 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(BasePrimitive2D::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(getLocalDecomposition().hasElements()) + { + if(maLastViewport != rViewInformation.getViewport() || maLastObjectToViewTransformation != rViewInformation.getObjectToViewTransformation()) + { + // conditions of last local decomposition have changed, delete + const_cast< GridPrimitive2D* >(this)->setLocalDecomposition(Primitive2DSequence()); + } + } + + if(!getLocalDecomposition().hasElements()) + { + // remember ViewRange and ViewTransformation + const_cast< GridPrimitive2D* >(this)->maLastObjectToViewTransformation = rViewInformation.getObjectToViewTransformation(); + const_cast< GridPrimitive2D* >(this)->maLastViewport = rViewInformation.getViewport(); + } + + // use parent implementation + return BasePrimitive2D::get2DDecomposition(rViewInformation); + } + + // provide unique ID + ImplPrimitrive2DIDBlock(GridPrimitive2D, PRIMITIVE2D_ID_GRIDPRIMITIVE2D) + + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive2d/groupprimitive2d.cxx b/drawinglayer/source/primitive2d/groupprimitive2d.cxx new file mode 100644 index 000000000000..ae899af6e84d --- /dev/null +++ b/drawinglayer/source/primitive2d/groupprimitive2d.cxx @@ -0,0 +1,87 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: groupprimitive2d.cxx,v $ + * + * $Revision: 1.7 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive2d/groupprimitive2d.hxx> +#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive2d + { + /// default: just return children, so all renderers not supporting group will use it's content + Primitive2DSequence GroupPrimitive2D::createLocalDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const + { + return getChildren(); + } + + 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; + } + + // provide unique ID + ImplPrimitrive2DIDBlock(GroupPrimitive2D, PRIMITIVE2D_ID_GROUPPRIMITIVE2D) + + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive2d/helplineprimitive2d.cxx b/drawinglayer/source/primitive2d/helplineprimitive2d.cxx new file mode 100644 index 000000000000..3232e635b561 --- /dev/null +++ b/drawinglayer/source/primitive2d/helplineprimitive2d.cxx @@ -0,0 +1,230 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: helplineprimitive2d.cxx,v $ + * + * $Revision: 1.7 $ + * + * last change: $Author: aw $ $Date: 2008-06-24 15:31:08 $ + * + * 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/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::createLocalDecomposition(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) + : BasePrimitive2D(), + maPosition(rPosition), + maDirection(rDirection), + meStyle(eStyle), + maRGBColA(rRGBColA), + maRGBColB(rRGBColB), + mfDiscreteDashLength(fDiscreteDashLength), + maLastObjectToViewTransformation(), + maLastViewport() + { + } + + bool HelplinePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + { + if(BasePrimitive2D::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(getLocalDecomposition().hasElements()) + { + if(maLastViewport != rViewInformation.getViewport() || maLastObjectToViewTransformation != rViewInformation.getObjectToViewTransformation()) + { + // conditions of last local decomposition have changed, delete + const_cast< HelplinePrimitive2D* >(this)->setLocalDecomposition(Primitive2DSequence()); + } + } + + if(!getLocalDecomposition().hasElements()) + { + // remember ViewRange and ViewTransformation + const_cast< HelplinePrimitive2D* >(this)->maLastObjectToViewTransformation = rViewInformation.getObjectToViewTransformation(); + const_cast< HelplinePrimitive2D* >(this)->maLastViewport = rViewInformation.getViewport(); + } + + // use parent implementation + return BasePrimitive2D::get2DDecomposition(rViewInformation); + } + + // provide unique ID + ImplPrimitrive2DIDBlock(HelplinePrimitive2D, PRIMITIVE2D_ID_HELPLINEPRIMITIVE2D) + + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive2d/hittestprimitive2d.cxx b/drawinglayer/source/primitive2d/hittestprimitive2d.cxx new file mode 100644 index 000000000000..daf65abd81d4 --- /dev/null +++ b/drawinglayer/source/primitive2d/hittestprimitive2d.cxx @@ -0,0 +1,76 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: hittestprimitive3d.cxx,v $ + * + * $Revision: 1.1.2.1 $ + * + * last change: $Author: aw $ $Date: 2008/09/25 17:12:14 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive2d/hittestprimitive2d.hxx> +#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive2d + { + Primitive2DSequence HitTestPrimitive2D::createLocalDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const + { + // return empty sequence + return Primitive2DSequence(); + } + + HitTestPrimitive2D::HitTestPrimitive2D( + const Primitive2DSequence& rChildren) + : GroupPrimitive2D(rChildren) + { + } + + basegfx::B2DRange HitTestPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const + { + return getB2DRangeFromPrimitive2DSequence(getChildren(), rViewInformation); + } + + // provide unique ID + ImplPrimitrive2DIDBlock(HitTestPrimitive2D, PRIMITIVE2D_ID_HITTESTPRIMITIVE2D) + + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive2d/invertprimitive2d.cxx b/drawinglayer/source/primitive2d/invertprimitive2d.cxx new file mode 100644 index 000000000000..374ec578113d --- /dev/null +++ b/drawinglayer/source/primitive2d/invertprimitive2d.cxx @@ -0,0 +1,65 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: unifiedalphaprimitive2d.cxx,v $ + * + * $Revision: 1.5 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive2d/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 diff --git a/drawinglayer/source/primitive2d/makefile.mk b/drawinglayer/source/primitive2d/makefile.mk new file mode 100644 index 000000000000..e10d1ddbcc71 --- /dev/null +++ b/drawinglayer/source/primitive2d/makefile.mk @@ -0,0 +1,90 @@ +#************************************************************************* +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.13 $ +# +# last change: $Author: aw $ $Date: 2008-04-04 06:00:23 $ +# +# 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 +# +#************************************************************************* + +PRJ=..$/.. +PRJNAME=drawinglayer +TARGET=primitive2d +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ---------------------------------- + +.INCLUDE : settings.mk + +# --- Files ------------------------------------- + +SLOFILES= \ + $(SLO)$/alphaprimitive2d.obj \ + $(SLO)$/animatedprimitive2d.obj \ + $(SLO)$/baseprimitive2d.obj \ + $(SLO)$/backgroundcolorprimitive2d.obj \ + $(SLO)$/bitmapprimitive2d.obj \ + $(SLO)$/borderlineprimitive2d.obj \ + $(SLO)$/chartprimitive2d.obj \ + $(SLO)$/controlprimitive2d.obj \ + $(SLO)$/embedded3dprimitive2d.obj \ + $(SLO)$/fillbitmapprimitive2d.obj \ + $(SLO)$/fillgradientprimitive2d.obj \ + $(SLO)$/fillhatchprimitive2d.obj \ + $(SLO)$/graphicprimitive2d.obj \ + $(SLO)$/gridprimitive2d.obj \ + $(SLO)$/groupprimitive2d.obj \ + $(SLO)$/helplineprimitive2d.obj \ + $(SLO)$/hittestprimitive2d.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)$/shadowprimitive2d.obj \ + $(SLO)$/structuretagprimitive2d.obj \ + $(SLO)$/texteffectprimitive2d.obj \ + $(SLO)$/textlayoutdevice.obj \ + $(SLO)$/textprimitive2d.obj \ + $(SLO)$/textdecoratedprimitive2d.obj \ + $(SLO)$/texthierarchyprimitive2d.obj \ + $(SLO)$/transformprimitive2d.obj \ + $(SLO)$/unifiedalphaprimitive2d.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..5737b9ef6cec --- /dev/null +++ b/drawinglayer/source/primitive2d/markerarrayprimitive2d.cxx @@ -0,0 +1,165 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: markerarrayprimitive2d.cxx,v $ + * + * $Revision: 1.7 $ + * + * last change: $Author: aw $ $Date: 2008-07-21 17:41:18 $ + * + * 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/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::createLocalDecomposition(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) + : BasePrimitive2D(), + maPositions(rPositions), + maMarker(rMarker) + { + } + + bool MarkerArrayPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + { + if(BasePrimitive2D::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 diff --git a/drawinglayer/source/primitive2d/maskprimitive2d.cxx b/drawinglayer/source/primitive2d/maskprimitive2d.cxx new file mode 100644 index 000000000000..20a4c98db67d --- /dev/null +++ b/drawinglayer/source/primitive2d/maskprimitive2d.cxx @@ -0,0 +1,79 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: maskprimitive2d.cxx,v $ + * + * $Revision: 1.5 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive2d/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; + } + + // provide unique ID + ImplPrimitrive2DIDBlock(MaskPrimitive2D, PRIMITIVE2D_ID_MASKPRIMITIVE2D) + + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive2d/mediaprimitive2d.cxx b/drawinglayer/source/primitive2d/mediaprimitive2d.cxx new file mode 100644 index 000000000000..7799b8e66d0e --- /dev/null +++ b/drawinglayer/source/primitive2d/mediaprimitive2d.cxx @@ -0,0 +1,164 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: mediaprimitive2d.cxx,v $ + * + * $Revision: 1.4 $ + * + * last change: $Author: aw $ $Date: 2008-06-24 15:31:08 $ + * + * 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/mediaprimitive2d.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> +#include <avmedia/mediawindow.hxx> +#include <goodies/grfmgr.hxx> +#include <drawinglayer/primitive2d/graphicprimitive2d.hxx> +#include <drawinglayer/geometry/viewinformation2d.hxx> +#include <drawinglayer/primitive2d/transformprimitive2d.hxx> +#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive2d + { + Primitive2DSequence MediaPrimitive2D::createLocalDecomposition(const geometry::ViewInformation2D& rViewInformation) const + { + Primitive2DSequence xRetval(1); + + // create background object + basegfx::B2DPolygon aBackgroundPolygon(basegfx::tools::createPolygonFromRect(basegfx::B2DRange(0.0, 0.0, 1.0, 1.0))); + 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, nothing to return + xRetval = Primitive2DSequence(); + } + 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) + : BasePrimitive2D(), + maTransform(rTransform), + maURL(rURL), + maBackgroundColor(rBackgroundColor), + mnDiscreteBorder(nDiscreteBorder) + { + } + + bool MediaPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + { + if(BasePrimitive2D::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 diff --git a/drawinglayer/source/primitive2d/metafileprimitive2d.cxx b/drawinglayer/source/primitive2d/metafileprimitive2d.cxx new file mode 100644 index 000000000000..2d1c0428a6a3 --- /dev/null +++ b/drawinglayer/source/primitive2d/metafileprimitive2d.cxx @@ -0,0 +1,89 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: metafileprimitive2d.cxx,v $ + * + * $Revision: 1.6 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive2d/metafileprimitive2d.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive2d + { + MetafilePrimitive2D::MetafilePrimitive2D( + const basegfx::B2DHomMatrix& rMetaFileTransform, + const GDIMetaFile& rMetaFile) + : BasePrimitive2D(), + maMetaFileTransform(rMetaFileTransform), + maMetaFile(rMetaFile) + { + } + + bool MetafilePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + { + if(BasePrimitive2D::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 + { + 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 diff --git a/drawinglayer/source/primitive2d/modifiedcolorprimitive2d.cxx b/drawinglayer/source/primitive2d/modifiedcolorprimitive2d.cxx new file mode 100644 index 000000000000..184cf2535911 --- /dev/null +++ b/drawinglayer/source/primitive2d/modifiedcolorprimitive2d.cxx @@ -0,0 +1,79 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: modifiedcolorprimitive2d.cxx,v $ + * + * $Revision: 1.5 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive2d/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 diff --git a/drawinglayer/source/primitive2d/pagepreviewprimitive2d.cxx b/drawinglayer/source/primitive2d/pagepreviewprimitive2d.cxx new file mode 100644 index 000000000000..01a82299682d --- /dev/null +++ b/drawinglayer/source/primitive2d/pagepreviewprimitive2d.cxx @@ -0,0 +1,185 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: pagepreviewprimitive2d.cxx,v $ + * + * $Revision: 1.3 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive2d/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> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive2d + { + Primitive2DSequence PagePreviewPrimitive2D::createLocalDecomposition(const geometry::ViewInformation2D& rViewInformation) const + { + Primitive2DSequence xRetval; + Primitive2DSequence aContent(getChildren()); + + 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 + aPageTrans.shearX(fShearX); + aPageTrans.rotate(fRotate); + aPageTrans.translate(aTranslate.getX(), aTranslate.getY()); + } + 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& rChildren, + bool bKeepAspectRatio) + : GroupPrimitive2D(rChildren), + mxDrawPage(rxDrawPage), + maTransform(rTransform), + mfContentWidth(fContentWidth), + mfContentHeight(fContentHeight), + mbKeepAspectRatio(bKeepAspectRatio) + { + } + + bool PagePreviewPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + { + if(GroupPrimitive2D::operator==(rPrimitive)) + { + const PagePreviewPrimitive2D& rCompare = static_cast< const PagePreviewPrimitive2D& >(rPrimitive); + + return (getXDrawPage() == rCompare.getXDrawPage() + && 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 diff --git a/drawinglayer/source/primitive2d/pointarrayprimitive2d.cxx b/drawinglayer/source/primitive2d/pointarrayprimitive2d.cxx new file mode 100644 index 000000000000..d144fd7030e6 --- /dev/null +++ b/drawinglayer/source/primitive2d/pointarrayprimitive2d.cxx @@ -0,0 +1,101 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: pointarrayprimitive2d.cxx,v $ + * + * $Revision: 1.3 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive2d/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 diff --git a/drawinglayer/source/primitive2d/polygonprimitive2d.cxx b/drawinglayer/source/primitive2d/polygonprimitive2d.cxx new file mode 100644 index 000000000000..b5212da54688 --- /dev/null +++ b/drawinglayer/source/primitive2d/polygonprimitive2d.cxx @@ -0,0 +1,633 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: polygonprimitive2d.cxx,v $ + * + * $Revision: 1.12 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive2d/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> + +////////////////////////////////////////////////////////////////////////////// + +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::createLocalDecomposition(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) + : BasePrimitive2D(), + maPolygon(rPolygon), + maRGBColorA(rRGBColorA), + maRGBColorB(rRGBColorB), + mfDiscreteDashLength(fDiscreteDashLength), + maLastInverseObjectToViewTransformation() + { + } + + bool PolygonMarkerPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + { + if(BasePrimitive2D::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(getLocalDecomposition().hasElements()) + { + if(rViewInformation.getInverseObjectToViewTransformation() != maLastInverseObjectToViewTransformation) + { + bNeedNewDecomposition = true; + } + } + + if(bNeedNewDecomposition) + { + // conditions of last local decomposition have changed, delete + const_cast< PolygonMarkerPrimitive2D* >(this)->setLocalDecomposition(Primitive2DSequence()); + } + + if(!getLocalDecomposition().hasElements()) + { + // remember last used InverseObjectToViewTransformation + PolygonMarkerPrimitive2D* pThat = const_cast< PolygonMarkerPrimitive2D* >(this); + pThat->maLastInverseObjectToViewTransformation = rViewInformation.getInverseObjectToViewTransformation(); + } + + // use parent implementation + return BasePrimitive2D::get2DDecomposition(rViewInformation); + } + + // provide unique ID + ImplPrimitrive2DIDBlock(PolygonMarkerPrimitive2D, PRIMITIVE2D_ID_POLYGONMARKERPRIMITIVE2D) + + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive2d + { + Primitive2DSequence PolygonStrokePrimitive2D::createLocalDecomposition(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(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().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) + : BasePrimitive2D(), + maPolygon(rPolygon), + maLineAttribute(rLineAttribute), + maStrokeAttribute(rStrokeAttribute) + { + } + + PolygonStrokePrimitive2D::PolygonStrokePrimitive2D( + const basegfx::B2DPolygon& rPolygon, + const attribute::LineAttribute& rLineAttribute) + : BasePrimitive2D(), + maPolygon(rPolygon), + maLineAttribute(rLineAttribute), + maStrokeAttribute() + { + } + + bool PolygonStrokePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + { + if(BasePrimitive2D::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 = BasePrimitive2D::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::createLocalDecomposition(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::createLocalDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const + { + // copy local polygon, it may be changed + basegfx::B2DPolygon aLocalPolygon(getB2DPolygon()); + basegfx::B2DPolyPolygon aArrowA; + basegfx::B2DPolyPolygon aArrowB; + + if(!aLocalPolygon.isClosed()) + { + // apply arrows + const double fPolyLength(basegfx::tools::getLength(aLocalPolygon)); + double fStart(0.0); + double fEnd(0.0); + + if(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().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 BasePrimitive2D::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 diff --git a/drawinglayer/source/primitive2d/polypolygonprimitive2d.cxx b/drawinglayer/source/primitive2d/polypolygonprimitive2d.cxx new file mode 100644 index 000000000000..9dd14aeb11e3 --- /dev/null +++ b/drawinglayer/source/primitive2d/polypolygonprimitive2d.cxx @@ -0,0 +1,548 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: polypolygonprimitive2d.cxx,v $ + * + * $Revision: 1.8 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive2d/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::createLocalDecomposition(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) + : BasePrimitive2D(), + maPolyPolygon(rPolyPolygon), + maBColor(rBColor) + { + } + + bool PolyPolygonHairlinePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + { + if(BasePrimitive2D::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::createLocalDecomposition(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) + : BasePrimitive2D(), + maPolyPolygon(rPolyPolygon), + maRGBColorA(rRGBColorA), + maRGBColorB(rRGBColorB), + mfDiscreteDashLength(fDiscreteDashLength) + { + } + + bool PolyPolygonMarkerPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + { + if(BasePrimitive2D::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::createLocalDecomposition(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) + : BasePrimitive2D(), + maPolyPolygon(rPolyPolygon), + maLineAttribute(rLineAttribute), + maStrokeAttribute(rStrokeAttribute) + { + } + + PolyPolygonStrokePrimitive2D::PolyPolygonStrokePrimitive2D( + const basegfx::B2DPolyPolygon& rPolyPolygon, + const attribute::LineAttribute& rLineAttribute) + : BasePrimitive2D(), + maPolyPolygon(rPolyPolygon), + maLineAttribute(rLineAttribute), + maStrokeAttribute() + { + } + + bool PolyPolygonStrokePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + { + if(BasePrimitive2D::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::createLocalDecomposition(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 BasePrimitive2D::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::createLocalDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const + { + // 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, 1L); + } + + PolyPolygonGradientPrimitive2D::PolyPolygonGradientPrimitive2D( + const basegfx::B2DPolyPolygon& rPolyPolygon, + const basegfx::BColor& rBColor, + const attribute::FillGradientAttribute& rFillGradient) + : PolyPolygonColorPrimitive2D(rPolyPolygon, rBColor), + maFillGradient(rFillGradient) + { + } + + bool PolyPolygonGradientPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + { + if(PolyPolygonColorPrimitive2D::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::createLocalDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const + { + // create SubSequence with FillHatchPrimitive2D + const basegfx::B2DRange aPolyPolygonRange(getB2DPolyPolygon().getB2DRange()); + FillHatchPrimitive2D* pNewHatch = new FillHatchPrimitive2D(aPolyPolygonRange, getBColor(), 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, 1L); + } + + PolyPolygonHatchPrimitive2D::PolyPolygonHatchPrimitive2D( + const basegfx::B2DPolyPolygon& rPolyPolygon, + const basegfx::BColor& rBColor, + const attribute::FillHatchAttribute& rFillHatch) + : PolyPolygonColorPrimitive2D(rPolyPolygon, rBColor), + maFillHatch(rFillHatch) + { + } + + bool PolyPolygonHatchPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + { + if(PolyPolygonColorPrimitive2D::operator==(rPrimitive)) + { + const PolyPolygonHatchPrimitive2D& rCompare = (PolyPolygonHatchPrimitive2D&)rPrimitive; + + return (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::createLocalDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const + { + // 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, 1L); + } + + PolyPolygonBitmapPrimitive2D::PolyPolygonBitmapPrimitive2D( + const basegfx::B2DPolyPolygon& rPolyPolygon, + const basegfx::BColor& rBColor, + const attribute::FillBitmapAttribute& rFillBitmap) + : PolyPolygonColorPrimitive2D(rPolyPolygon, rBColor), + maFillBitmap(rFillBitmap) + { + } + + bool PolyPolygonBitmapPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + { + if(PolyPolygonColorPrimitive2D::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 diff --git a/drawinglayer/source/primitive2d/primitivetools2d.cxx b/drawinglayer/source/primitive2d/primitivetools2d.cxx new file mode 100644 index 000000000000..d288a697d729 --- /dev/null +++ b/drawinglayer/source/primitive2d/primitivetools2d.cxx @@ -0,0 +1,106 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: baseprimitive2d.cxx,v $ + * + * $Revision: 1.6 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive2d/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(getLocalDecomposition().hasElements() && !basegfx::fTools::equal(fDiscreteUnit, getDiscreteUnit())) + { + // conditions of last local decomposition have changed, delete + const_cast< DiscreteMetricDependentPrimitive2D* >(this)->setLocalDecomposition(Primitive2DSequence()); + } + + if(!getLocalDecomposition().hasElements()) + { + // remember new valid DiscreteUnit + const_cast< DiscreteMetricDependentPrimitive2D* >(this)->mfDiscreteUnit = fDiscreteUnit; + } + + // call base implementation + return BasePrimitive2D::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(getLocalDecomposition().hasElements() && !rViewport.equal(getViewport())) + { + // conditions of last local decomposition have changed, delete + const_cast< ViewportDependentPrimitive2D* >(this)->setLocalDecomposition(Primitive2DSequence()); + } + + if(!getLocalDecomposition().hasElements()) + { + // remember new valid DiscreteUnit + const_cast< ViewportDependentPrimitive2D* >(this)->maViewport = rViewport; + } + + // call base implementation + return BasePrimitive2D::get2DDecomposition(rViewInformation); + } + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive2d/sceneprimitive2d.cxx b/drawinglayer/source/primitive2d/sceneprimitive2d.cxx new file mode 100644 index 000000000000..ad36a40ea996 --- /dev/null +++ b/drawinglayer/source/primitive2d/sceneprimitive2d.cxx @@ -0,0 +1,484 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: sceneprimitive2d.cxx,v $ + * + * $Revision: 1.16 $ + * + * last change: $Author: aw $ $Date: 2008-06-24 15:31:08 $ + * + * 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/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::createLocalDecomposition(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.processNonTransparent(getChildren3D()); + aZBufferProcessor3D.processTransparent(getChildren3D()); + 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::createPolygonFromRect(basegfx::B2DRange(0.0, 0.0, 1.0, 1.0))); + 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) + : BasePrimitive2D(), + 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(BasePrimitive2D::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(getLocalDecomposition().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)->setLocalDecomposition(Primitive2DSequence()); + } + + if(!getLocalDecomposition().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 BasePrimitive2D::get2DDecomposition(rViewInformation); + } + + // provide unique ID + ImplPrimitrive2DIDBlock(ScenePrimitive2D, PRIMITIVE2D_ID_SCENEPRIMITIVE2D) + + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive2d/shadowprimitive2d.cxx b/drawinglayer/source/primitive2d/shadowprimitive2d.cxx new file mode 100644 index 000000000000..5681f7f98d7e --- /dev/null +++ b/drawinglayer/source/primitive2d/shadowprimitive2d.cxx @@ -0,0 +1,114 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: shadowprimitive2d.cxx,v $ + * + * $Revision: 1.5 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive2d/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/alphaprimitive2d.hxx> +#include <drawinglayer/primitive2d/unifiedalphaprimitive2d.hxx> +#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive2d + { + Primitive2DSequence ShadowPrimitive2D::createLocalDecomposition(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; + } + + 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(GroupPrimitive2D::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; + } + + // provide unique ID + ImplPrimitrive2DIDBlock(ShadowPrimitive2D, PRIMITIVE2D_ID_SHADOWPRIMITIVE2D) + + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive2d/structuretagprimitive2d.cxx b/drawinglayer/source/primitive2d/structuretagprimitive2d.cxx new file mode 100644 index 000000000000..191b24dfcbf9 --- /dev/null +++ b/drawinglayer/source/primitive2d/structuretagprimitive2d.cxx @@ -0,0 +1,67 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: structuretagprimitive2d.cxx,v $ + * + * $Revision: 1.2 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive2d/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_STRUCTURETAGRIMITIVE2D) + + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive2d/textdecoratedprimitive2d.cxx b/drawinglayer/source/primitive2d/textdecoratedprimitive2d.cxx new file mode 100644 index 000000000000..d337950c6c6b --- /dev/null +++ b/drawinglayer/source/primitive2d/textdecoratedprimitive2d.cxx @@ -0,0 +1,888 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: textdecoratedprimitive2d.cxx,v $ + * + * $Revision: 1.12 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive2d/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> + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive2d + { + void TextDecoratedPortionPrimitive2D::impCreateTextLine( + std::vector< Primitive2DReference >& rTarget, + basegfx::DecomposedB2DHomMatrixContainer& rDecTrans, + const basegfx::B2DHomMatrix &rUnscaledTransform, + FontUnderline eLineStyle, + double fLineOffset, + double fLineHeight, + double fLineWidth, + const basegfx::BColor& rLineColor) const + { + bool bDoubleLine(false); + bool bWaveLine(false); + bool bBoldLine(false); + const int* pDotDashArray(0); + basegfx::B2DLineJoin eLineJoin(basegfx::B2DLINEJOIN_NONE); + + 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 + + switch(eLineStyle) + { + default: // case FONT_UNDERLINE_SINGLE: + { + break; + } + case FONT_UNDERLINE_DOUBLE: + { + bDoubleLine = true; + break; + } + case FONT_UNDERLINE_DOTTED: + { + pDotDashArray = aDottedArray; + break; + } + case FONT_UNDERLINE_DASH: + { + pDotDashArray = aDashedArray; + break; + } + case FONT_UNDERLINE_LONGDASH: + { + pDotDashArray = aLongDashArray; + break; + } + case FONT_UNDERLINE_DASHDOT: + { + pDotDashArray = aDotDashArray; + break; + } + case FONT_UNDERLINE_DASHDOTDOT: + { + pDotDashArray = aDashDotDotArray; + break; + } + case FONT_UNDERLINE_SMALLWAVE: + { + bWaveLine = true; + break; + } + case FONT_UNDERLINE_WAVE: + { + bWaveLine = true; + break; + } + case FONT_UNDERLINE_DOUBLEWAVE: + { + bDoubleLine = true; + bWaveLine = true; + break; + } + case FONT_UNDERLINE_BOLD: + { + bBoldLine = true; + break; + } + case FONT_UNDERLINE_BOLDDOTTED: + { + bBoldLine = true; + pDotDashArray = aDottedArray; + break; + } + case FONT_UNDERLINE_BOLDDASH: + { + bBoldLine = true; + pDotDashArray = aDashedArray; + break; + } + case FONT_UNDERLINE_BOLDLONGDASH: + { + bBoldLine = true; + pDotDashArray = aLongDashArray; + break; + } + case FONT_UNDERLINE_BOLDDASHDOT: + { + bBoldLine = true; + pDotDashArray = aDotDashArray; + break; + } + case FONT_UNDERLINE_BOLDDASHDOTDOT: + { + bBoldLine = true; + pDotDashArray = aDashDotDotArray; + break; + } + case FONT_UNDERLINE_BOLDWAVE: + { + bWaveLine = true; + bBoldLine = true; + break; + } + } + + if(bBoldLine) + { + fLineHeight *= 2.0; + } + + if(bDoubleLine) + { + fLineOffset -= 0.50 * fLineHeight; + fLineHeight *= 0.64; + } + + if(bWaveLine) + { + eLineJoin = basegfx::B2DLINEJOIN_ROUND; + fLineHeight *= 0.25; + } + + // prepare Line and Stroke Attributes + const attribute::LineAttribute aLineAttribute(rLineColor, fLineHeight, eLineJoin); + attribute::StrokeAttribute aStrokeAttribute; + + if(pDotDashArray) + { + ::std::vector< double > aDoubleArray; + + for(const int* p = pDotDashArray; *p; ++p) + { + aDoubleArray.push_back((double)(*p) * fLineHeight); + } + + aStrokeAttribute = attribute::StrokeAttribute(aDoubleArray); + } + + // create base polygon and new primitive + basegfx::B2DPolygon aLine; + Primitive2DReference aNewPrimitive; + + aLine.append(basegfx::B2DPoint(0.0, fLineOffset)); + aLine.append(basegfx::B2DPoint(fLineWidth, fLineOffset)); + aLine.transform(rUnscaledTransform); + + if(bWaveLine) + { + double fWaveWidth(10.6 * fLineHeight); + + if(FONT_UNDERLINE_SMALLWAVE == eLineStyle) + { + fWaveWidth *= 0.7; + } + else if(FONT_UNDERLINE_WAVE == eLineStyle) + { + // 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 + rTarget.push_back(aNewPrimitive); + + if(bDoubleLine) + { + // double line, create 2nd primitive with offset using TransformPrimitive based on + // already created NewPrimitive + double fLineDist(2.3 * fLineHeight); + + if(bWaveLine) + { + fLineDist = 6.3 * fLineHeight; + } + + basegfx::B2DHomMatrix aTransform; + + // move base point of text to 0.0 and de-rotate + aTransform.translate(-rDecTrans.getTranslate().getX(), -rDecTrans.getTranslate().getY()); + aTransform.rotate(-rDecTrans.getRotate()); + + // translate in Y by offset + aTransform.translate(0.0, fLineDist); + + // move back and rotate + aTransform.rotate(rDecTrans.getRotate()); + aTransform.translate(rDecTrans.getTranslate().getX(), rDecTrans.getTranslate().getY()); + + // add transform primitive + const Primitive2DSequence aContent(&aNewPrimitive, 1); + rTarget.push_back(Primitive2DReference(new TransformPrimitive2D(aTransform, aContent))); + } + } + + void TextDecoratedPortionPrimitive2D::impCreateGeometryContent( + std::vector< Primitive2DReference >& rTarget, + basegfx::DecomposedB2DHomMatrixContainer& rDecTrans, + const String& rText, + xub_StrLen aTextPosition, + xub_StrLen aTextLength, + const ::std::vector< double >& rDXArray, + const FontAttributes& rFontAttributes) const + { + // create the SimpleTextPrimitive needed in any case + rTarget.push_back(Primitive2DReference( + new TextSimplePortionPrimitive2D( + rDecTrans.getB2DHomMatrix(), + rText, + aTextPosition, + aTextLength, + rDXArray, + rFontAttributes, + getLocale(), + getFontColor()))); + + // see if something else needs to be done + const bool bOverlineUsed(FONT_UNDERLINE_NONE != getFontOverline()); + const bool bUnderlineUsed(FONT_UNDERLINE_NONE != getFontUnderline()); + const bool bStrikeoutUsed(FONT_STRIKEOUT_NONE != getFontStrikeout()); + + if(bUnderlineUsed || bStrikeoutUsed || bOverlineUsed) + { + // common preparations + basegfx::B2DHomMatrix aUnscaledTransform; + TextLayouterDevice aTextLayouter; + + // unscaled is needed since scale contains already the font size + aUnscaledTransform.shearX(rDecTrans.getShearX()); + aUnscaledTransform.rotate(rDecTrans.getRotate()); + aUnscaledTransform.translate(rDecTrans.getTranslate().getX(), rDecTrans.getTranslate().getY()); + + // TextLayouterDevice is needed to get metrics for text decorations like + // underline/strikeout/emphasis marks from it. For setup, the font size is needed + aTextLayouter.setFontAttributes( + getFontAttributes(), + 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 + impCreateTextLine(rTarget, rDecTrans, aUnscaledTransform, getFontOverline(), aTextLayouter.getOverlineOffset(), + aTextLayouter.getOverlineHeight(), fTextWidth, getOverlineColor()); + } + + if(bUnderlineUsed) + { + // create primitive geometry for underline + impCreateTextLine(rTarget, rDecTrans, aUnscaledTransform, getFontUnderline(), aTextLayouter.getUnderlineOffset(), + aTextLayouter.getUnderlineHeight(), fTextWidth, getTextlineColor()); + } + + if(bStrikeoutUsed) + { + // create primitive geometry for strikeout + if(FONT_STRIKEOUT_SLASH == getFontStrikeout() || FONT_STRIKEOUT_X == getFontStrikeout()) + { + // strikeout with character + const sal_Unicode aStrikeoutChar(FONT_STRIKEOUT_SLASH == getFontStrikeout() ? '/' : 'X'); + const String aSingleCharString(aStrikeoutChar); + const double fStrikeCharWidth(aTextLayouter.getTextWidth(aSingleCharString, 0, 1)); + const double fStrikeCharCount(fabs(fTextWidth/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; + } + + rTarget.push_back(Primitive2DReference( + new TextSimplePortionPrimitive2D( + rDecTrans.getB2DHomMatrix(), + aStrikeoutString, + 0, + aStrikeoutString.Len(), + aDXArray, + rFontAttributes, + getLocale(), + getFontColor()))); + } + else + { + // strikeout with geometry + double fStrikeoutHeight(aTextLayouter.getUnderlineHeight()); + double fStrikeoutOffset(aTextLayouter.getStrikeoutOffset()); + bool bDoubleLine(false); + + // set line attribute + switch(getFontStrikeout()) + { + default : // case primitive2d::FONT_STRIKEOUT_SINGLE: + { + break; + } + case primitive2d::FONT_STRIKEOUT_DOUBLE: + { + bDoubleLine = true; + break; + } + case primitive2d::FONT_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(fTextWidth, -fStrikeoutOffset)); + aStrikeoutLine.transform(aUnscaledTransform); + + const attribute::LineAttribute aLineAttribute(getFontColor(), fStrikeoutHeight, basegfx::B2DLINEJOIN_NONE); + Primitive2DReference aNewPrimitive(new PolygonStrokePrimitive2D(aStrikeoutLine, aLineAttribute)); + + // add primitive + rTarget.push_back(aNewPrimitive); + + if(bDoubleLine) + { + // double line, create 2nd primitive with offset using TransformPrimitive based on + // already created NewPrimitive + const double fLineDist(2.0 * fStrikeoutHeight); + basegfx::B2DHomMatrix aTransform; + + // move base point of text to 0.0 and de-rotate + aTransform.translate(-rDecTrans.getTranslate().getX(), -rDecTrans.getTranslate().getY()); + aTransform.rotate(-rDecTrans.getRotate()); + + // translate in Y by offset + aTransform.translate(0.0, -fLineDist); + + // move back and rotate + aTransform.rotate(rDecTrans.getRotate()); + aTransform.translate(rDecTrans.getTranslate().getX(), rDecTrans.getTranslate().getY()); + + // add transform primitive + const Primitive2DSequence aContent(&aNewPrimitive, 1); + rTarget.push_back(Primitive2DReference(new TransformPrimitive2D(aTransform, aContent))); + } + } + } + } + + // 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::DecomposedB2DHomMatrixContainer& rDecTrans) const + { + // break iterator support + // made static so it only needs to be fetched once, even with many single + // constructed VclMetafileProcessor2D. It's still incarnated on demand, + // but exists for OOo runtime now by purpose. + static ::com::sun::star::uno::Reference< ::com::sun::star::i18n::XBreakIterator > xLocalBreakIterator; + + if(!xLocalBreakIterator.is()) + { + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xMSF(::comphelper::getProcessServiceFactory()); + xLocalBreakIterator.set(xMSF->createInstance(rtl::OUString::createFromAscii("com.sun.star.i18n.BreakIterator")), ::com::sun::star::uno::UNO_QUERY); + } + + if(xLocalBreakIterator.is() && getTextLength()) + { + // init word iterator, get first word and truncate to possibilities + ::com::sun::star::i18n::Boundary aNextWordBoundary(xLocalBreakIterator->getWordBoundary( + getText(), getTextPosition(), getLocale(), ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True)); + + if(aNextWordBoundary.endPos == getTextPosition()) + { + // backward hit, force next word + aNextWordBoundary = xLocalBreakIterator->getWordBoundary( + getText(), getTextPosition() + 1, getLocale(), ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True); + } + + impCorrectTextBoundary(aNextWordBoundary); + + // prepare new font attributes WITHOUT outline + const FontAttributes aNewFontAttributes( + getFontAttributes().getFamilyName(), + getFontAttributes().getStyleName(), + getFontAttributes().getWeight(), + getFontAttributes().getSymbol(), + getFontAttributes().getVertical(), + getFontAttributes().getItalic(), + false, // no outline anymore, handled locally + getFontAttributes().getRTL(), + getFontAttributes().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(), aNewFontAttributes); + } + else + { + // prepare TextLayouter + const bool bNoDXArray(getDXArray().empty()); + TextLayouterDevice aTextLayouter; + + if(bNoDXArray) + { + // ..but only completely when no DXArray + aTextLayouter.setFontAttributes( + getFontAttributes(), + 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::DecomposedB2DHomMatrixContainer aDecTrans(aNewTransform); + + impCreateGeometryContent(rTarget, aDecTrans, getText(), nNewTextStart, + nNewTextEnd - nNewTextStart, aNewDXArray, aNewFontAttributes); + + 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::createLocalDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const + { + std::vector< Primitive2DReference > aNewPrimitives; + basegfx::DecomposedB2DHomMatrixContainer 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 FontAttributes aNewFontAttributes( + getFontAttributes().getFamilyName(), + getFontAttributes().getStyleName(), + getFontAttributes().getWeight(), + getFontAttributes().getSymbol(), + getFontAttributes().getVertical(), + getFontAttributes().getItalic(), + false, // no outline anymore, handled locally + getFontAttributes().getRTL(), + getFontAttributes().getBiDiStrong()); + + // handle as one word + impCreateGeometryContent(aNewPrimitives, aDecTrans, getText(), getTextPosition(), getTextLength(), getDXArray(), aNewFontAttributes); + } + + // 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 FontRelief + if(aRetval.hasElements()) + { + // outline AND shadow depend on NO FontRelief (see dialog) + const bool bHasFontRelief(FONT_RELIEF_NONE != getFontRelief()); + const bool bHasShadow(!bHasFontRelief && getShadow()); + const bool bHasOutline(!bHasFontRelief && getFontAttributes().getOutline()); + + if(bHasShadow || bHasFontRelief || 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 + basegfx::B2DHomMatrix aShadowTransform; + aShadowTransform.translate(fTextShadowOffset, fTextShadowOffset); + + // create shadow primitive + aShadow = Primitive2DReference(new ShadowPrimitive2D( + aShadowTransform, + aShadowColor, + aRetval)); + } + + if(bHasFontRelief) + { + // 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(FONT_RELIEF_ENGRAVED == getFontRelief()) + { + aTextEffectStyle2D = TEXTEFFECTSTYLE2D_RELIEF_ENGRAVED_DEFAULT; + } + else + { + aTextEffectStyle2D = TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED_DEFAULT; + } + } + else + { + if(FONT_RELIEF_ENGRAVED == getFontRelief()) + { + 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 FontAttributes& rFontAttributes, + const ::com::sun::star::lang::Locale& rLocale, + const basegfx::BColor& rFontColor, + + // local parameters + const basegfx::BColor& rOverlineColor, + const basegfx::BColor& rTextlineColor, + FontUnderline eFontOverline, + FontUnderline eFontUnderline, + bool bUnderlineAbove, + FontStrikeout eFontStrikeout, + bool bWordLineMode, + FontEmphasisMark eFontEmphasisMark, + bool bEmphasisMarkAbove, + bool bEmphasisMarkBelow, + FontRelief eFontRelief, + bool bShadow) + : TextSimplePortionPrimitive2D(rNewTransform, rText, aTextPosition, aTextLength, rDXArray, rFontAttributes, rLocale, rFontColor), + maOverlineColor(rOverlineColor), + maTextlineColor(rTextlineColor), + meFontOverline(eFontOverline), + meFontUnderline(eFontUnderline), + meFontStrikeout(eFontStrikeout), + meFontEmphasisMark(eFontEmphasisMark), + meFontRelief(eFontRelief), + 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() + && getFontStrikeout() == rCompare.getFontStrikeout() + && getFontEmphasisMark() == rCompare.getFontEmphasisMark() + && getFontRelief() == rCompare.getFontRelief() + && 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( + FONT_UNDERLINE_NONE != getFontOverline() + || FONT_UNDERLINE_NONE != getFontUnderline() + || FONT_STRIKEOUT_NONE != getFontStrikeout() + || FONT_EMPHASISMARK_NONE != getFontEmphasisMark() + || FONT_RELIEF_NONE != getFontRelief() + || getShadow()); + + if(bDecoratedIsNeeded) + { + // decoration is used, fallback to BasePrimitive2D::getB2DRange which uses + // the own local decomposition for computation and thus creates all necessary + // geometric objects + return BasePrimitive2D::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 diff --git a/drawinglayer/source/primitive2d/texteffectprimitive2d.cxx b/drawinglayer/source/primitive2d/texteffectprimitive2d.cxx new file mode 100644 index 000000000000..c1963f4ba2a4 --- /dev/null +++ b/drawinglayer/source/primitive2d/texteffectprimitive2d.cxx @@ -0,0 +1,245 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: texteffectprimitive2d.cxx,v $ + * + * $Revision: 1.4 $ + * + * last change: $Author: aw $ $Date: 2008-06-24 15:31:08 $ + * + * 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/texteffectprimitive2d.hxx> +#include <drawinglayer/geometry/viewinformation2d.hxx> +#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx> +#include <drawinglayer/primitive2d/transformprimitive2d.hxx> +#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive2d + { + static double fDiscreteSize(1.1); + + Primitive2DSequence TextEffectPrimitive2D::createLocalDecomposition(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; + aBackTransform.translate(-getRotationCenter().getX(), -getRotationCenter().getY()); + aBackTransform.rotate(-getDirection()); + + // prepare transform of sub-group back to it's position and rotation + basegfx::B2DHomMatrix aForwardTransform; + aForwardTransform.rotate(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(getChildren(), 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(getChildren(), aBColorModifierToWhite)); + } + else + { + // emboss/engrave in gray, keep original's color + const basegfx::BColorModifier aBColorModifierToGray(basegfx::BColor(0.75)); // 192 + const Primitive2DReference xModifiedColor(new ModifiedColorPrimitive2D(getChildren(), aBColorModifierToGray)); + aRetval[0] = Primitive2DReference(new TransformPrimitive2D(aTransform, Primitive2DSequence(&xModifiedColor, 1))); + + // add original, too + aRetval[1] = Primitive2DReference(new GroupPrimitive2D(getChildren())); + } + + 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, getChildren())); + + aTransform.set(0, 2, aDiagonalDistance.getX()); + aTransform.set(1, 2, aDiagonalDistance.getY()); + aRetval[1] = Primitive2DReference(new TransformPrimitive2D(aTransform, getChildren())); + + aTransform.set(0, 2, 0.0); + aTransform.set(1, 2, aDistance.getY()); + aRetval[2] = Primitive2DReference(new TransformPrimitive2D(aTransform, getChildren())); + + aTransform.set(0, 2, -aDiagonalDistance.getX()); + aTransform.set(1, 2, aDiagonalDistance.getY()); + aRetval[3] = Primitive2DReference(new TransformPrimitive2D(aTransform, getChildren())); + + aTransform.set(0, 2, -aDistance.getX()); + aTransform.set(1, 2, 0.0); + aRetval[4] = Primitive2DReference(new TransformPrimitive2D(aTransform, getChildren())); + + aTransform.set(0, 2, -aDiagonalDistance.getX()); + aTransform.set(1, 2, -aDiagonalDistance.getY()); + aRetval[5] = Primitive2DReference(new TransformPrimitive2D(aTransform, getChildren())); + + aTransform.set(0, 2, 0.0); + aTransform.set(1, 2, -aDistance.getY()); + aRetval[6] = Primitive2DReference(new TransformPrimitive2D(aTransform, getChildren())); + + aTransform.set(0, 2, aDiagonalDistance.getX()); + aTransform.set(1, 2, -aDiagonalDistance.getY()); + aRetval[7] = Primitive2DReference(new TransformPrimitive2D(aTransform, getChildren())); + + // 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(getChildren(), aBColorModifierToWhite)); + + break; + } + } + + return aRetval; + } + + TextEffectPrimitive2D::TextEffectPrimitive2D( + const Primitive2DSequence& rChildren, + const basegfx::B2DPoint& rRotationCenter, + double fDirection, + TextEffectStyle2D eTextEffectStyle2D) + : GroupPrimitive2D(rChildren), + maRotationCenter(rRotationCenter), + mfDirection(fDirection), + meTextEffectStyle2D(eTextEffectStyle2D) + { + } + + bool TextEffectPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + { + if(GroupPrimitive2D::operator==(rPrimitive)) + { + const TextEffectPrimitive2D& rCompare = (TextEffectPrimitive2D&)rPrimitive; + + return (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(getChildren(), rViewInformation)); + aRetval.grow(fDiscreteSize); + + return aRetval; + } + + Primitive2DSequence TextEffectPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const + { + ::osl::MutexGuard aGuard( m_aMutex ); + + if(getLocalDecomposition().hasElements()) + { + if(maLastObjectToViewTransformation != rViewInformation.getObjectToViewTransformation()) + { + // conditions of last local decomposition have changed, delete + const_cast< TextEffectPrimitive2D* >(this)->setLocalDecomposition(Primitive2DSequence()); + } + } + + if(!getLocalDecomposition().hasElements()) + { + // remember ViewRange and ViewTransformation + const_cast< TextEffectPrimitive2D* >(this)->maLastObjectToViewTransformation = rViewInformation.getObjectToViewTransformation(); + } + + // use parent implementation + return BasePrimitive2D::get2DDecomposition(rViewInformation); + } + + // provide unique ID + ImplPrimitrive2DIDBlock(TextEffectPrimitive2D, PRIMITIVE2D_ID_TEXTEFFECTPRIMITIVE2D) + + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive2d/texthierarchyprimitive2d.cxx b/drawinglayer/source/primitive2d/texthierarchyprimitive2d.cxx new file mode 100644 index 000000000000..72249e673c1b --- /dev/null +++ b/drawinglayer/source/primitive2d/texthierarchyprimitive2d.cxx @@ -0,0 +1,166 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: texthierarchyprimitive2d.cxx,v $ + * + * $Revision: 1.5 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive2d/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 diff --git a/drawinglayer/source/primitive2d/textlayoutdevice.cxx b/drawinglayer/source/primitive2d/textlayoutdevice.cxx new file mode 100644 index 000000000000..e321783c8406 --- /dev/null +++ b/drawinglayer/source/primitive2d/textlayoutdevice.cxx @@ -0,0 +1,430 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: textlayoutdevice.cxx,v $ + * + * $Revision: 1.10 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive2d/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::setFontAttributes( + const FontAttributes& rFontAttributes, + double fFontScaleX, + double fFontScaleY, + const ::com::sun::star::lang::Locale& rLocale) + { + setFont(getVclFontFromFontAttributes( + rFontAttributes, + 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, + xub_StrLen nIndex, + xub_StrLen nLength) const + { + return mrDevice.GetTextWidth(rText, nIndex, nLength); + } + + bool TextLayouterDevice::getTextOutlines( + basegfx::B2DPolyPolygonVector& rB2DPolyPolyVector, + const String& rText, + xub_StrLen nIndex, + xub_StrLen nLength, + const ::std::vector< double >& rDXArray) + { + const sal_uInt32 nDXArrayCount(rDXArray.size()); + + if(nDXArrayCount) + { + OSL_ENSURE(nDXArrayCount == nLength, "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, + xub_StrLen nIndex, + xub_StrLen nLength) const + { + if(nLength) + { + 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(); + } + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// helper methods for vcl font handling + +namespace drawinglayer +{ + namespace primitive2d + { + Font getVclFontFromFontAttributes( + const FontAttributes& rFontAttributes, + 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( + rFontAttributes.getFamilyName(), + rFontAttributes.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( + rFontAttributes.getFamilyName(), + rFontAttributes.getStyleName(), + Size(bFontIsScaled ? nWidth : 0, nHeight)); +#endif + // define various other FontAttributes + aRetval.SetAlign(ALIGN_BASELINE); + aRetval.SetCharSet(rFontAttributes.getSymbol() ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE); + aRetval.SetVertical(rFontAttributes.getVertical() ? TRUE : FALSE); + aRetval.SetWeight(static_cast<FontWeight>(rFontAttributes.getWeight())); + aRetval.SetItalic(rFontAttributes.getItalic() ? ITALIC_NORMAL : ITALIC_NONE); + aRetval.SetOutline(rFontAttributes.getOutline()); + 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; + } + + FontAttributes getFontAttributesFromVclFont( + basegfx::B2DVector& o_rSize, + const Font& rFont, + bool bRTL, + bool bBiDiStrong) + { + const FontAttributes aRetval( + rFont.GetName(), + rFont.GetStyleName(), + static_cast<sal_uInt16>(rFont.GetWeight()), + RTL_TEXTENCODING_SYMBOL == rFont.GetCharSet(), + rFont.IsVertical(), + ITALIC_NONE != rFont.GetItalic(), + 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 diff --git a/drawinglayer/source/primitive2d/textprimitive2d.cxx b/drawinglayer/source/primitive2d/textprimitive2d.cxx new file mode 100644 index 000000000000..f8e413da0e8c --- /dev/null +++ b/drawinglayer/source/primitive2d/textprimitive2d.cxx @@ -0,0 +1,374 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: textprimitive2d.cxx,v $ + * + * $Revision: 1.22 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive2d/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> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive2d + { + bool FontAttributes::operator==(const FontAttributes& rCompare) const + { + return (getFamilyName() == rCompare.getFamilyName() + && getStyleName() == rCompare.getStyleName() + && getWeight() == rCompare.getWeight() + && getSymbol() == rCompare.getSymbol() + && getVertical() == rCompare.getVertical() + && getItalic() == rCompare.getItalic() + && getOutline() == rCompare.getOutline() + && getRTL() == rCompare.getRTL() + && getBiDiStrong() == rCompare.getBiDiStrong()); + } + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +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.setFontAttributes( + getFontAttributes(), + 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.identity(); + rTransformation.scale(aScale.getX(), aScale.getY()); + rTransformation.shearX(fShearX); + rTransformation.rotate(fRotate); + rTransformation.translate(aTranslate.getX(), aTranslate.getY()); + } + } + } + } + + Primitive2DSequence TextSimplePortionPrimitive2D::createLocalDecomposition(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(getFontAttributes().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 FontAttributes& rFontAttributes, + const ::com::sun::star::lang::Locale& rLocale, + const basegfx::BColor& rFontColor) + : BasePrimitive2D(), + maTextTransform(rNewTransform), + maText(rText), + maTextPosition(aTextPosition), + maTextLength(aTextLength), + maDXArray(rDXArray), + maFontAttributes(rFontAttributes), + maLocale(rLocale), + maFontColor(rFontColor), + maB2DRange() + { +#ifdef DBG_UTIL + const xub_StrLen aStringLength(getText().Len()); + OSL_ENSURE(aStringLength >= getTextPosition() && aStringLength >= getTextPosition() + getTextLength(), + "TextSimplePortionPrimitive2D with text out of range (!)"); +#endif + } + + bool impLocalesAreEqual(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(BasePrimitive2D::operator==(rPrimitive)) + { + const TextSimplePortionPrimitive2D& rCompare = (TextSimplePortionPrimitive2D&)rPrimitive; + + return (getTextTransform() == rCompare.getTextTransform() + && getText() == rCompare.getText() + && getTextPosition() == rCompare.getTextPosition() + && getTextLength() == rCompare.getTextLength() + && getDXArray() == rCompare.getDXArray() + && getFontAttributes() == rCompare.getFontAttributes() + && impLocalesAreEqual(getLocale(), rCompare.getLocale()) + && getFontColor() == rCompare.getFontColor()); + } + + 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.setFontAttributes( + getFontAttributes(), + 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 + basegfx::B2DHomMatrix aRangeTransformation; + + aRangeTransformation.scale(aScale.getX(), aScale.getY()); + aRangeTransformation.shearX(fShearX); + aRangeTransformation.rotate(fRotate); + aRangeTransformation.translate(aTranslate.getX(), aTranslate.getY()); + + // 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 diff --git a/drawinglayer/source/primitive2d/transformprimitive2d.cxx b/drawinglayer/source/primitive2d/transformprimitive2d.cxx new file mode 100644 index 000000000000..7fe8293df854 --- /dev/null +++ b/drawinglayer/source/primitive2d/transformprimitive2d.cxx @@ -0,0 +1,87 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: transformprimitive2d.cxx,v $ + * + * $Revision: 1.5 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive2d/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 diff --git a/drawinglayer/source/primitive2d/unifiedalphaprimitive2d.cxx b/drawinglayer/source/primitive2d/unifiedalphaprimitive2d.cxx new file mode 100644 index 000000000000..49039e1a6e5c --- /dev/null +++ b/drawinglayer/source/primitive2d/unifiedalphaprimitive2d.cxx @@ -0,0 +1,129 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: unifiedalphaprimitive2d.cxx,v $ + * + * $Revision: 1.5 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive2d/unifiedalphaprimitive2d.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/color/bcolor.hxx> +#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> +#include <drawinglayer/primitive2d/alphaprimitive2d.hxx> +#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> +#include <drawinglayer/primitive2d/polygonprimitive2d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive2d + { + Primitive2DSequence UnifiedAlphaPrimitive2D::createLocalDecomposition(const geometry::ViewInformation2D& rViewInformation) const + { + if(0.0 == getAlpha()) + { + // no transparence used, so just use the content + return getChildren(); + } + else if(getAlpha() > 0.0 && getAlpha() < 1.0) + { + // The idea is to create a AlphaPrimitive2D with alpha content using a fill color + // corresponding to the alpha 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 alpha 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 UnifiedAlphaPrimitive2D is not handled directly. + const basegfx::B2DRange aPolygonRange(getB2DRangeFromPrimitive2DSequence(getChildren(), rViewInformation)); + const basegfx::B2DPolygon aPolygon(basegfx::tools::createPolygonFromRect(aPolygonRange)); + const basegfx::BColor aGray(getAlpha(), getAlpha(), getAlpha()); + Primitive2DSequence aAlphaContent(2); + + aAlphaContent[0] = Primitive2DReference(new PolyPolygonColorPrimitive2D(basegfx::B2DPolyPolygon(aPolygon), aGray)); + aAlphaContent[1] = Primitive2DReference(new PolygonHairlinePrimitive2D(aPolygon, aGray)); + + // create sub-transparence group with a gray-colored rectangular fill polygon + const Primitive2DReference xRefB(new AlphaPrimitive2D(getChildren(), aAlphaContent)); + return Primitive2DSequence(&xRefB, 1L); + } + else + { + // completely transparent or invalid definition, add nothing + return Primitive2DSequence(); + } + } + + UnifiedAlphaPrimitive2D::UnifiedAlphaPrimitive2D( + const Primitive2DSequence& rChildren, + double fAlpha) + : GroupPrimitive2D(rChildren), + mfAlpha(fAlpha) + { + } + + bool UnifiedAlphaPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + { + if(GroupPrimitive2D::operator==(rPrimitive)) + { + const UnifiedAlphaPrimitive2D& rCompare = (UnifiedAlphaPrimitive2D&)rPrimitive; + + return (getAlpha() == rCompare.getAlpha()); + } + + return false; + } + + // provide unique ID + ImplPrimitrive2DIDBlock(UnifiedAlphaPrimitive2D, PRIMITIVE2D_ID_UNIFIEDALPHAPRIMITIVE2D) + + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive2d/wrongspellprimitive2d.cxx b/drawinglayer/source/primitive2d/wrongspellprimitive2d.cxx new file mode 100644 index 000000000000..93a51d5379b3 --- /dev/null +++ b/drawinglayer/source/primitive2d/wrongspellprimitive2d.cxx @@ -0,0 +1,130 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: wrongspellprimitive2d.cxx,v $ + * + * $Revision: 1.5 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:20 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive2d/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::createLocalDecomposition(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) + : BasePrimitive2D(), + maTransformation(rTransformation), + mfStart(fStart), + mfStop(fStop), + maColor(rColor) + { + } + + bool WrongSpellPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + { + if(BasePrimitive2D::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 diff --git a/drawinglayer/source/primitive3d/baseprimitive3d.cxx b/drawinglayer/source/primitive3d/baseprimitive3d.cxx new file mode 100644 index 000000000000..032ae068003b --- /dev/null +++ b/drawinglayer/source/primitive3d/baseprimitive3d.cxx @@ -0,0 +1,264 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: baseprimitive3d.cxx,v $ + * + * $Revision: 1.5 $ + * + * last change: $Author: aw $ $Date: 2008-06-10 09:29:33 $ + * + * 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/primitive3d/baseprimitive3d.hxx> +#include <drawinglayer/geometry/viewinformation3d.hxx> +#include <basegfx/tools/canvastools.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + Primitive3DSequence BasePrimitive3D::createLocalDecomposition(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + return Primitive3DSequence(); + } + + BasePrimitive3D::BasePrimitive3D() + : BasePrimitive3DImplBase(m_aMutex), + maLocalDecomposition() + { + } + + bool BasePrimitive3D::operator==( const BasePrimitive3D& rPrimitive ) const + { + return (getPrimitiveID() == rPrimitive.getPrimitiveID()); + } + + basegfx::B3DRange BasePrimitive3D::getB3DRange(const geometry::ViewInformation3D& rViewInformation) const + { + return getB3DRangeFromPrimitive3DSequence(get3DDecomposition(rViewInformation), rViewInformation); + } + + Primitive3DSequence BasePrimitive3D::get3DDecomposition(const geometry::ViewInformation3D& rViewInformation) const + { + ::osl::MutexGuard aGuard( m_aMutex ); + + if(!getLocalDecomposition().hasElements()) + { + const Primitive3DSequence aNewSequence(createLocalDecomposition(rViewInformation)); + const_cast< BasePrimitive3D* >(this)->setLocalDecomposition(aNewSequence); + } + + return getLocalDecomposition(); + } + + Primitive3DSequence SAL_CALL BasePrimitive3D::getDecomposition( const uno::Sequence< beans::PropertyValue >& rViewParameters ) throw ( uno::RuntimeException ) + { + const geometry::ViewInformation3D aViewInformation(rViewParameters); + return get3DDecomposition(rViewParameters); + } + + com::sun::star::geometry::RealRectangle3D SAL_CALL BasePrimitive3D::getRange( const uno::Sequence< beans::PropertyValue >& rViewParameters ) throw ( uno::RuntimeException ) + { + const geometry::ViewInformation3D aViewInformation(rViewParameters); + return basegfx::unotools::rectangle3DFromB3DRectangle(getB3DRange(aViewInformation)); + } + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// tooling + +namespace drawinglayer +{ + namespace primitive3d + { + // get range3D from a given Primitive3DReference + basegfx::B3DRange getB3DRangeFromPrimitive3DReference(const Primitive3DReference& rCandidate, const geometry::ViewInformation3D& aViewInformation) + { + basegfx::B3DRange aRetval; + + if(rCandidate.is()) + { + // try to get C++ implementation base + const BasePrimitive3D* pCandidate(dynamic_cast< BasePrimitive3D* >(rCandidate.get())); + + if(pCandidate) + { + // use it if possible + aRetval.expand(pCandidate->getB3DRange(aViewInformation)); + } + else + { + // use UNO API call instead + const uno::Sequence< beans::PropertyValue >& rViewParameters(aViewInformation.getViewInformationSequence()); + aRetval.expand(basegfx::unotools::b3DRectangleFromRealRectangle3D(rCandidate->getRange(rViewParameters))); + } + } + + return aRetval; + } + + // get range3D from a given Primitive3DSequence + basegfx::B3DRange getB3DRangeFromPrimitive3DSequence(const Primitive3DSequence& rCandidate, const geometry::ViewInformation3D& aViewInformation) + { + basegfx::B3DRange aRetval; + + if(rCandidate.hasElements()) + { + const sal_Int32 nCount(rCandidate.getLength()); + + for(sal_Int32 a(0L); a < nCount; a++) + { + aRetval.expand(getB3DRangeFromPrimitive3DReference(rCandidate[a], aViewInformation)); + } + } + + return aRetval; + } + + bool arePrimitive3DReferencesEqual(const Primitive3DReference& rxA, const Primitive3DReference& rxB) + { + const sal_Bool bAIs(rxA.is()); + + if(bAIs != rxB.is()) + { + return false; + } + + if(!bAIs) + { + return true; + } + + const BasePrimitive3D* pA(dynamic_cast< const BasePrimitive3D* >(rxA.get())); + const BasePrimitive3D* pB(dynamic_cast< const BasePrimitive3D* >(rxB.get())); + const bool bAEqualZero(pA == 0L); + + if(bAEqualZero != (pB == 0L)) + { + return false; + } + + if(bAEqualZero) + { + return false; + } + + return (pA->operator==(*pB)); + } + + bool arePrimitive3DSequencesEqual(const Primitive3DSequence& rA, const Primitive3DSequence& 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(!arePrimitive3DReferencesEqual(rA[a], rB[a])) + { + return false; + } + } + + return true; + } + + // concatenate sequence + void appendPrimitive3DSequenceToPrimitive3DSequence(Primitive3DSequence& rDest, const Primitive3DSequence& 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 Primitive3D + void appendPrimitive3DReferenceToPrimitive3DSequence(Primitive3DSequence& rDest, const Primitive3DReference& rSource) + { + if(rSource.is()) + { + const sal_Int32 nDestCount(rDest.getLength()); + rDest.realloc(nDestCount + 1L); + rDest[nDestCount] = rSource; + } + } + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/groupprimitive3d.cxx b/drawinglayer/source/primitive3d/groupprimitive3d.cxx new file mode 100644 index 000000000000..b8ed86ee952a --- /dev/null +++ b/drawinglayer/source/primitive3d/groupprimitive3d.cxx @@ -0,0 +1,87 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: groupprimitive3d.cxx,v $ + * + * $Revision: 1.6 $ + * + * last change: $Author: aw $ $Date: 2008-06-10 09:29:33 $ + * + * 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/primitive3d/groupprimitive3d.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + /// default: just return children, so all renderers not supporting group will use it's content + Primitive3DSequence GroupPrimitive3D::createLocalDecomposition(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + return getChildren(); + } + + GroupPrimitive3D::GroupPrimitive3D( const Primitive3DSequence& rChildren ) + : BasePrimitive3D(), + 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 GroupPrimitive3D::operator==( const BasePrimitive3D& rPrimitive ) const + { + if(BasePrimitive3D::operator==(rPrimitive)) + { + const GroupPrimitive3D& rCompare = static_cast< const GroupPrimitive3D& >(rPrimitive); + + return (arePrimitive3DSequencesEqual(getChildren(), rCompare.getChildren())); + } + + return false; + } + + // provide unique ID + ImplPrimitrive3DIDBlock(GroupPrimitive3D, PRIMITIVE3D_ID_GROUPPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/hatchtextureprimitive3d.cxx b/drawinglayer/source/primitive3d/hatchtextureprimitive3d.cxx new file mode 100644 index 000000000000..dd49f99b751c --- /dev/null +++ b/drawinglayer/source/primitive3d/hatchtextureprimitive3d.cxx @@ -0,0 +1,313 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: hatchtextureprimitive3d.cxx,v $ + * + * $Revision: 1.11 $ + * + * last change: $Author: aw $ $Date: 2008-06-10 09:29:33 $ + * + * 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/primitive3d/hatchtextureprimitive3d.hxx> +#include <drawinglayer/primitive3d/polypolygonprimitive3d.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/polygon/b3dpolygon.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/range/b2drange.hxx> +#include <drawinglayer/texture/texture.hxx> +#include <basegfx/polygon/b2dpolygonclipper.hxx> +#include <basegfx/matrix/b3dhommatrix.hxx> +#include <drawinglayer/primitive3d/polygonprimitive3d.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + Primitive3DSequence HatchTexturePrimitive3D::createLocalDecomposition(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + Primitive3DSequence aRetval; + + if(getChildren().hasElements()) + { + const Primitive3DSequence aSource(getChildren()); + const sal_uInt32 nSourceCount(aSource.getLength()); + std::vector< Primitive3DReference > aDestination; + + for(sal_uInt32 a(0); a < nSourceCount; a++) + { + // get reference + const Primitive3DReference xReference(aSource[a]); + + if(xReference.is()) + { + // try to cast to BasePrimitive2D implementation + const BasePrimitive3D* pBasePrimitive = dynamic_cast< const BasePrimitive3D* >(xReference.get()); + + if(pBasePrimitive) + { + // it is a BasePrimitive3D implementation, use getPrimitiveID() call for switch + // not all content is needed, remove transparencies and ModifiedColorPrimitives + switch(pBasePrimitive->getPrimitiveID()) + { + case PRIMITIVE3D_ID_POLYPOLYGONMATERIALPRIMITIVE3D : + { + // polyPolygonMaterialPrimitive3D, check texturing and hatching + const PolyPolygonMaterialPrimitive3D& rPrimitive = static_cast< const PolyPolygonMaterialPrimitive3D& >(*pBasePrimitive); + const basegfx::B3DPolyPolygon aFillPolyPolygon(rPrimitive.getB3DPolyPolygon()); + + if(maHatch.isFillBackground()) + { + // add original primitive for background + aDestination.push_back(xReference); + } + + if(aFillPolyPolygon.areTextureCoordinatesUsed()) + { + const sal_uInt32 nPolyCount(aFillPolyPolygon.count()); + basegfx::B2DPolyPolygon aTexPolyPolygon; + basegfx::B2DPoint a2N; + basegfx::B2DVector a2X, a2Y; + basegfx::B3DPoint a3N; + basegfx::B3DVector a3X, a3Y; + bool b2N(false), b2X(false), b2Y(false); + + for(sal_uInt32 b(0); b < nPolyCount; b++) + { + const basegfx::B3DPolygon aPartPoly(aFillPolyPolygon.getB3DPolygon(b)); + const sal_uInt32 nPointCount(aPartPoly.count()); + basegfx::B2DPolygon aTexPolygon; + + for(sal_uInt32 c(0); c < nPointCount; c++) + { + const basegfx::B2DPoint a2Candidate(aPartPoly.getTextureCoordinate(c)); + + if(!b2N) + { + a2N = a2Candidate; + a3N = aPartPoly.getB3DPoint(c); + b2N = true; + } + else if(!b2X && !a2N.equal(a2Candidate)) + { + a2X = a2Candidate - a2N; + a3X = aPartPoly.getB3DPoint(c) - a3N; + b2X = true; + } + else if(!b2Y && !a2N.equal(a2Candidate) && !a2X.equal(a2Candidate)) + { + a2Y = a2Candidate - a2N; + + const double fCross(a2X.cross(a2Y)); + + if(!basegfx::fTools::equalZero(fCross)) + { + a3Y = aPartPoly.getB3DPoint(c) - a3N; + b2Y = true; + } + } + + aTexPolygon.append(a2Candidate); + } + + aTexPolygon.setClosed(true); + aTexPolyPolygon.append(aTexPolygon); + } + + if(b2N && b2X && b2Y) + { + // found two linearly independent 2D vectors + // get 2d range of texture coordinates + const basegfx::B2DRange aOutlineRange(basegfx::tools::getRange(aTexPolyPolygon)); + const basegfx::BColor aHatchColor(getHatch().getColor()); + const double fAngle(-getHatch().getAngle()); + ::std::vector< basegfx::B2DHomMatrix > aMatrices; + + // get hatch transformations + switch(getHatch().getStyle()) + { + case attribute::HATCHSTYLE_TRIPLE: + { + // rotated 45 degrees + texture::GeoTexSvxHatch aHatch(aOutlineRange, getHatch().getDistance(), fAngle + F_PI4); + aHatch.appendTransformations(aMatrices); + } + case attribute::HATCHSTYLE_DOUBLE: + { + // rotated 90 degrees + texture::GeoTexSvxHatch aHatch(aOutlineRange, getHatch().getDistance(), fAngle + F_PI2); + aHatch.appendTransformations(aMatrices); + } + case attribute::HATCHSTYLE_SINGLE: + { + // angle as given + texture::GeoTexSvxHatch aHatch(aOutlineRange, getHatch().getDistance(), fAngle); + aHatch.appendTransformations(aMatrices); + } + } + + // create geometry from unit line + basegfx::B2DPolyPolygon a2DHatchLines; + basegfx::B2DPolygon a2DUnitLine; + a2DUnitLine.append(basegfx::B2DPoint(0.0, 0.0)); + a2DUnitLine.append(basegfx::B2DPoint(1.0, 0.0)); + + for(sal_uInt32 c(0); c < aMatrices.size(); c++) + { + const basegfx::B2DHomMatrix& rMatrix = aMatrices[c]; + basegfx::B2DPolygon aNewLine(a2DUnitLine); + aNewLine.transform(rMatrix); + a2DHatchLines.append(aNewLine); + } + + if(a2DHatchLines.count()) + { + // clip against texture polygon + a2DHatchLines = basegfx::tools::clipPolyPolygonOnPolyPolygon(a2DHatchLines, aTexPolyPolygon, true, true); + } + + if(a2DHatchLines.count()) + { + // create 2d matrix with 2d vectors as column vectors and 2d point as offset, this represents + // a coordinate system transformation from unit coordinates to the new coordinate system + basegfx::B2DHomMatrix a2D; + a2D.set(0, 0, a2X.getX()); + a2D.set(1, 0, a2X.getY()); + a2D.set(0, 1, a2Y.getX()); + a2D.set(1, 1, a2Y.getY()); + a2D.set(0, 2, a2N.getX()); + a2D.set(1, 2, a2N.getY()); + + // invert that transformation, so we have a back-transformation from texture coordinates + // to unit coordinates + a2D.invert(); + a2DHatchLines.transform(a2D); + + // expand back-transformated geometry tpo 3D + basegfx::B3DPolyPolygon a3DHatchLines(basegfx::tools::createB3DPolyPolygonFromB2DPolyPolygon(a2DHatchLines, 0.0)); + + // create 3d matrix with 3d vectors as column vectors (0,0,1 as Z) and 3d point as offset, this represents + // a coordinate system transformation from unit coordinates to the object's 3d coordinate system + basegfx::B3DHomMatrix a3D; + a3D.set(0, 0, a3X.getX()); + a3D.set(1, 0, a3X.getY()); + a3D.set(2, 0, a3X.getZ()); + a3D.set(0, 1, a3Y.getX()); + a3D.set(1, 1, a3Y.getY()); + a3D.set(2, 1, a3Y.getZ()); + a3D.set(0, 3, a3N.getX()); + a3D.set(1, 3, a3N.getY()); + a3D.set(2, 3, a3N.getZ()); + + // transform hatch lines to 3D object coordinates + a3DHatchLines.transform(a3D); + + // build primitives from this geometry + const sal_uInt32 nHatchLines(a3DHatchLines.count()); + + for(sal_uInt32 d(0); d < nHatchLines; d++) + { + const Primitive3DReference xRef(new PolygonHairlinePrimitive3D(a3DHatchLines.getB3DPolygon(d), aHatchColor)); + aDestination.push_back(xRef); + } + } + } + } + + break; + } + default : + { + // add reference to result + aDestination.push_back(xReference); + break; + } + } + } + else + { + // unknown implementation, add to result + aDestination.push_back(xReference); + } + } + } + + // prepare return value + const sal_uInt32 nDestSize(aDestination.size()); + aRetval.realloc(nDestSize); + + for(sal_uInt32 b(0); b < nDestSize; b++) + { + aRetval[b] = aDestination[b]; + } + } + + return aRetval; + } + + HatchTexturePrimitive3D::HatchTexturePrimitive3D( + const attribute::FillHatchAttribute& rHatch, + const Primitive3DSequence& rChildren, + const basegfx::B2DVector& rTextureSize, + bool bModulate, + bool bFilter) + : TexturePrimitive3D(rChildren, rTextureSize, bModulate, bFilter), + maHatch(rHatch) + { + } + + bool HatchTexturePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(TexturePrimitive3D::operator==(rPrimitive)) + { + const HatchTexturePrimitive3D& rCompare = (HatchTexturePrimitive3D&)rPrimitive; + + return (getHatch() == rCompare.getHatch()); + } + + return false; + } + + // provide unique ID + ImplPrimitrive3DIDBlock(HatchTexturePrimitive3D, PRIMITIVE3D_ID_HATCHTEXTUREPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/hittestprimitive3d.cxx b/drawinglayer/source/primitive3d/hittestprimitive3d.cxx new file mode 100644 index 000000000000..50616ab1548b --- /dev/null +++ b/drawinglayer/source/primitive3d/hittestprimitive3d.cxx @@ -0,0 +1,76 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: hittestprimitive3d.cxx,v $ + * + * $Revision: 1.1.2.1 $ + * + * last change: $Author: aw $ $Date: 2008/09/25 17:12:14 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive3d/hittestprimitive3d.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + Primitive3DSequence HitTestPrimitive3D::createLocalDecomposition(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + // return empty sequence + return Primitive3DSequence(); + } + + HitTestPrimitive3D::HitTestPrimitive3D( + const Primitive3DSequence& rChildren) + : GroupPrimitive3D(rChildren) + { + } + + basegfx::B3DRange HitTestPrimitive3D::getB3DRange(const geometry::ViewInformation3D& rViewInformation) const + { + return getB3DRangeFromPrimitive3DSequence(getChildren(), rViewInformation); + } + + // provide unique ID + ImplPrimitrive3DIDBlock(HitTestPrimitive3D, PRIMITIVE3D_ID_HITTESTPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/makefile.mk b/drawinglayer/source/primitive3d/makefile.mk new file mode 100644 index 000000000000..fb160fb9bfa7 --- /dev/null +++ b/drawinglayer/source/primitive3d/makefile.mk @@ -0,0 +1,70 @@ +#************************************************************************* +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.5 $ +# +# last change: $Author: aw $ $Date: 2008-06-24 15:31:08 $ +# +# 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 +# +#************************************************************************* + +PRJ=..$/.. +PRJNAME=drawinglayer +TARGET=primitive3d +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ---------------------------------- + +.INCLUDE : settings.mk + +# --- Files ------------------------------------- + +SLOFILES= \ + $(SLO)$/baseprimitive3d.obj \ + $(SLO)$/groupprimitive3d.obj \ + $(SLO)$/hatchtextureprimitive3d.obj \ + $(SLO)$/hittestprimitive3d.obj \ + $(SLO)$/modifiedcolorprimitive3d.obj \ + $(SLO)$/polypolygonprimitive3d.obj \ + $(SLO)$/polygonprimitive3d.obj \ + $(SLO)$/polygontubeprimitive3d.obj \ + $(SLO)$/sdrcubeprimitive3d.obj \ + $(SLO)$/sdrdecompositiontools3d.obj \ + $(SLO)$/sdrextrudelathetools3d.obj \ + $(SLO)$/sdrextrudeprimitive3d.obj \ + $(SLO)$/sdrlatheprimitive3d.obj \ + $(SLO)$/sdrpolypolygonprimitive3d.obj \ + $(SLO)$/sdrprimitive3d.obj \ + $(SLO)$/sdrsphereprimitive3d.obj \ + $(SLO)$/shadowprimitive3d.obj \ + $(SLO)$/textureprimitive3d.obj \ + $(SLO)$/transformprimitive3d.obj + +# --- Targets ---------------------------------- + +.INCLUDE : target.mk diff --git a/drawinglayer/source/primitive3d/modifiedcolorprimitive3d.cxx b/drawinglayer/source/primitive3d/modifiedcolorprimitive3d.cxx new file mode 100644 index 000000000000..b683cef9defa --- /dev/null +++ b/drawinglayer/source/primitive3d/modifiedcolorprimitive3d.cxx @@ -0,0 +1,79 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: modifiedcolorprimitive3d.cxx,v $ + * + * $Revision: 1.6 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:21 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive3d/modifiedcolorprimitive3d.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + ModifiedColorPrimitive3D::ModifiedColorPrimitive3D( + const Primitive3DSequence& rChildren, + const basegfx::BColorModifier& rColorModifier) + : GroupPrimitive3D(rChildren), + maColorModifier(rColorModifier) + { + } + + bool ModifiedColorPrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(GroupPrimitive3D::operator==(rPrimitive)) + { + const ModifiedColorPrimitive3D& rCompare = (ModifiedColorPrimitive3D&)rPrimitive; + + return (maColorModifier == rCompare.maColorModifier); + } + + return false; + } + + // provide unique ID + ImplPrimitrive3DIDBlock(ModifiedColorPrimitive3D, PRIMITIVE3D_ID_MODIFIEDCOLORPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/polygonprimitive3d.cxx b/drawinglayer/source/primitive3d/polygonprimitive3d.cxx new file mode 100644 index 000000000000..b89499091dd0 --- /dev/null +++ b/drawinglayer/source/primitive3d/polygonprimitive3d.cxx @@ -0,0 +1,186 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: polygonprimitive3d.cxx,v $ + * + * $Revision: 1.10 $ + * + * last change: $Author: aw $ $Date: 2008-06-10 09:29:33 $ + * + * 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/primitive3d/polygonprimitive3d.hxx> +#include <basegfx/polygon/b3dpolygontools.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/polygon/b3dpolypolygontools.hxx> +#include <drawinglayer/primitive3d/polygontubeprimitive3d.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + PolygonHairlinePrimitive3D::PolygonHairlinePrimitive3D( + const basegfx::B3DPolygon& rPolygon, + const basegfx::BColor& rBColor) + : BasePrimitive3D(), + maPolygon(rPolygon), + maBColor(rBColor) + { + } + + bool PolygonHairlinePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(BasePrimitive3D::operator==(rPrimitive)) + { + const PolygonHairlinePrimitive3D& rCompare = (PolygonHairlinePrimitive3D&)rPrimitive; + + return (getB3DPolygon() == rCompare.getB3DPolygon() + && getBColor() == rCompare.getBColor()); + } + + return false; + } + + basegfx::B3DRange PolygonHairlinePrimitive3D::getB3DRange(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + return basegfx::tools::getRange(getB3DPolygon()); + } + + // provide unique ID + ImplPrimitrive3DIDBlock(PolygonHairlinePrimitive3D, PRIMITIVE3D_ID_POLYGONHAIRLINEPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + Primitive3DSequence PolygonStrokePrimitive3D::createLocalDecomposition(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + Primitive3DSequence aRetval; + + if(getB3DPolygon().count()) + { + basegfx::B3DPolyPolygon aHairLinePolyPolygon; + + if(0.0 == getStrokeAttribute().getFullDotDashLen()) + { + aHairLinePolyPolygon = basegfx::B3DPolyPolygon(getB3DPolygon()); + } + else + { + // apply LineStyle + basegfx::tools::applyLineDashing(getB3DPolygon(), getStrokeAttribute().getDotDashArray(), &aHairLinePolyPolygon, 0, getStrokeAttribute().getFullDotDashLen()); + } + + // prepare result + aRetval.realloc(aHairLinePolyPolygon.count()); + + if(getLineAttribute().getWidth()) + { + // create fat line data + const double fRadius(getLineAttribute().getWidth() / 2.0); + const basegfx::B2DLineJoin aLineJoin(getLineAttribute().getLineJoin()); + + for(sal_uInt32 a(0L); a < aHairLinePolyPolygon.count(); a++) + { + // create tube primitives + const Primitive3DReference xRef(new PolygonTubePrimitive3D(aHairLinePolyPolygon.getB3DPolygon(a), getLineAttribute().getColor(), fRadius, aLineJoin)); + aRetval[a] = xRef; + } + } + else + { + // create hair line data for all sub polygons + for(sal_uInt32 a(0L); a < aHairLinePolyPolygon.count(); a++) + { + const basegfx::B3DPolygon aCandidate = aHairLinePolyPolygon.getB3DPolygon(a); + const Primitive3DReference xRef(new PolygonHairlinePrimitive3D(aCandidate, getLineAttribute().getColor())); + aRetval[a] = xRef; + } + } + } + + return aRetval; + } + + PolygonStrokePrimitive3D::PolygonStrokePrimitive3D( + const basegfx::B3DPolygon& rPolygon, + const attribute::LineAttribute& rLineAttribute, + const attribute::StrokeAttribute& rStrokeAttribute) + : BasePrimitive3D(), + maPolygon(rPolygon), + maLineAttribute(rLineAttribute), + maStrokeAttribute(rStrokeAttribute) + { + } + + PolygonStrokePrimitive3D::PolygonStrokePrimitive3D( + const basegfx::B3DPolygon& rPolygon, + const attribute::LineAttribute& rLineAttribute) + : BasePrimitive3D(), + maPolygon(rPolygon), + maLineAttribute(rLineAttribute), + maStrokeAttribute() + { + } + + bool PolygonStrokePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(BasePrimitive3D::operator==(rPrimitive)) + { + const PolygonStrokePrimitive3D& rCompare = (PolygonStrokePrimitive3D&)rPrimitive; + + return (getB3DPolygon() == rCompare.getB3DPolygon() + && getLineAttribute() == rCompare.getLineAttribute() + && getStrokeAttribute() == rCompare.getStrokeAttribute()); + } + + return false; + } + + // provide unique ID + ImplPrimitrive3DIDBlock(PolygonStrokePrimitive3D, PRIMITIVE3D_ID_POLYGONSTROKEPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/polygontubeprimitive3d.cxx b/drawinglayer/source/primitive3d/polygontubeprimitive3d.cxx new file mode 100644 index 000000000000..09c4acdcaed5 --- /dev/null +++ b/drawinglayer/source/primitive3d/polygontubeprimitive3d.cxx @@ -0,0 +1,573 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: polygontubeprimitive3d.cxx,v $ + * + * $Revision: 1.12 $ + * + * last change: $Author: aw $ $Date: 2008-06-10 09:29:33 $ + * + * 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/primitive3d/polygontubeprimitive3d.hxx> +#include <drawinglayer/attribute/materialattribute3d.hxx> +#include <basegfx/matrix/b3dhommatrix.hxx> +#include <basegfx/polygon/b3dpolypolygon.hxx> +#include <drawinglayer/primitive3d/polypolygonprimitive3d.hxx> +#include <basegfx/polygon/b3dpolypolygontools.hxx> +#include <drawinglayer/primitive3d/transformprimitive3d.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + namespace // anonymous namespace + { + Primitive3DSequence getLineTubeSegments( + sal_uInt32 nSegments, + const attribute::MaterialAttribute3D& rMaterial) + { + // static data for buffered tube primitives + static Primitive3DSequence aLineTubeList; + static sal_uInt32 nLineTubeSegments(0L); + static attribute::MaterialAttribute3D aLineMaterial; + + // may exclusively change static data, use mutex + ::osl::Mutex m_mutex; + + if(nSegments != nLineTubeSegments || rMaterial != aLineMaterial) + { + nLineTubeSegments = nSegments; + aLineMaterial = rMaterial; + aLineTubeList = Primitive3DSequence(); + } + + if(!aLineTubeList.hasElements() && 0L != nLineTubeSegments) + { + const basegfx::B3DPoint aLeft(0.0, 0.0, 0.0); + const basegfx::B3DPoint aRight(1.0, 0.0, 0.0); + basegfx::B3DPoint aLastLeft(0.0, 1.0, 0.0); + basegfx::B3DPoint aLastRight(1.0, 1.0, 0.0); + basegfx::B3DHomMatrix aRot; + aRot.rotate(F_2PI / (double)nLineTubeSegments, 0.0, 0.0); + aLineTubeList.realloc(nLineTubeSegments); + + for(sal_uInt32 a(0L); a < nLineTubeSegments; a++) + { + const basegfx::B3DPoint aNextLeft(aRot * aLastLeft); + const basegfx::B3DPoint aNextRight(aRot * aLastRight); + basegfx::B3DPolygon aNewPolygon; + + aNewPolygon.append(aNextLeft); + aNewPolygon.setNormal(0L, basegfx::B3DVector(aNextLeft - aLeft)); + + aNewPolygon.append(aLastLeft); + aNewPolygon.setNormal(1L, basegfx::B3DVector(aLastLeft - aLeft)); + + aNewPolygon.append(aLastRight); + aNewPolygon.setNormal(2L, basegfx::B3DVector(aLastRight - aRight)); + + aNewPolygon.append(aNextRight); + aNewPolygon.setNormal(3L, basegfx::B3DVector(aNextRight - aRight)); + + aNewPolygon.setClosed(true); + + const basegfx::B3DPolyPolygon aNewPolyPolygon(aNewPolygon); + const Primitive3DReference xRef(new PolyPolygonMaterialPrimitive3D(aNewPolyPolygon, aLineMaterial, false)); + aLineTubeList[a] = xRef; + + aLastLeft = aNextLeft; + aLastRight = aNextRight; + } + } + + return aLineTubeList; + } + + Primitive3DSequence getLineCapSegments( + sal_uInt32 nSegments, + const attribute::MaterialAttribute3D& rMaterial) + { + // static data for buffered tube primitives + static Primitive3DSequence aLineCapList; + static sal_uInt32 nLineCapSegments(0L); + static attribute::MaterialAttribute3D aLineMaterial; + + // may exclusively change static data, use mutex + ::osl::Mutex m_mutex; + + if(nSegments != nLineCapSegments || rMaterial != aLineMaterial) + { + nLineCapSegments = nSegments; + aLineMaterial = rMaterial; + aLineCapList = Primitive3DSequence(); + } + + if(!aLineCapList.hasElements() && 0L != nLineCapSegments) + { + const basegfx::B3DPoint aNull(0.0, 0.0, 0.0); + basegfx::B3DPoint aLast(0.0, 1.0, 0.0); + basegfx::B3DHomMatrix aRot; + aRot.rotate(F_2PI / (double)nLineCapSegments, 0.0, 0.0); + aLineCapList.realloc(nLineCapSegments); + + for(sal_uInt32 a(0L); a < nLineCapSegments; a++) + { + const basegfx::B3DPoint aNext(aRot * aLast); + basegfx::B3DPolygon aNewPolygon; + + aNewPolygon.append(aLast); + aNewPolygon.setNormal(0L, basegfx::B3DVector(aLast - aNull)); + + aNewPolygon.append(aNext); + aNewPolygon.setNormal(1L, basegfx::B3DVector(aNext - aNull)); + + aNewPolygon.append(aNull); + aNewPolygon.setNormal(2L, basegfx::B3DVector(-1.0, 0.0, 0.0)); + + aNewPolygon.setClosed(true); + + const basegfx::B3DPolyPolygon aNewPolyPolygon(aNewPolygon); + const Primitive3DReference xRef(new PolyPolygonMaterialPrimitive3D(aNewPolyPolygon, aLineMaterial, false)); + aLineCapList[a] = xRef; + + aLast = aNext; + } + } + + return aLineCapList; + } + + Primitive3DSequence getLineJoinSegments( + sal_uInt32 nSegments, + const attribute::MaterialAttribute3D& rMaterial, + double fAngle, + double /*fDegreeStepWidth*/, + double fMiterMinimumAngle, + basegfx::B2DLineJoin aLineJoin) + { + // nSegments is for whole circle, adapt to half circle + const sal_uInt32 nVerSeg(nSegments >> 1L); + std::vector< BasePrimitive3D* > aResultVector; + + if(nVerSeg) + { + if(basegfx::B2DLINEJOIN_ROUND == aLineJoin) + { + // calculate new horizontal segments + const sal_uInt32 nHorSeg((sal_uInt32)((fAngle / F_2PI) * (double)nSegments)); + + if(nHorSeg) + { + // create half-sphere + const basegfx::B3DPolyPolygon aSphere(basegfx::tools::createUnitSphereFillPolyPolygon(nHorSeg, nVerSeg, true, F_PI2, -F_PI2, 0.0, fAngle)); + + for(sal_uInt32 a(0L); a < aSphere.count(); a++) + { + const basegfx::B3DPolygon aPartPolygon(aSphere.getB3DPolygon(a)); + const basegfx::B3DPolyPolygon aPartPolyPolygon(aPartPolygon); + BasePrimitive3D* pNew = new PolyPolygonMaterialPrimitive3D(aPartPolyPolygon, rMaterial, false); + aResultVector.push_back(pNew); + } + } + else + { + // fallback to bevel when there is not at least one segment hor and ver + aLineJoin = basegfx::B2DLINEJOIN_BEVEL; + } + } + + if(basegfx::B2DLINEJOIN_MIDDLE == aLineJoin + || basegfx::B2DLINEJOIN_BEVEL == aLineJoin + || basegfx::B2DLINEJOIN_MITER == aLineJoin) + { + if(basegfx::B2DLINEJOIN_MITER == aLineJoin) + { + const double fMiterAngle(fAngle/2.0); + + if(fMiterAngle < fMiterMinimumAngle) + { + // fallback to bevel when miter's angle is too small + aLineJoin = basegfx::B2DLINEJOIN_BEVEL; + } + } + + const double fInc(F_PI / (double)nVerSeg); + const double fSin(sin(-fAngle)); + const double fCos(cos(-fAngle)); + const bool bMiter(basegfx::B2DLINEJOIN_MITER == aLineJoin); + const double fMiterSin(bMiter ? sin(-(fAngle/2.0)) : 0.0); + const double fMiterCos(bMiter ? cos(-(fAngle/2.0)) : 0.0); + double fPos(-F_PI2); + basegfx::B3DPoint aPointOnXY, aPointRotY, aNextPointOnXY, aNextPointRotY; + basegfx::B3DPoint aCurrMiter, aNextMiter; + basegfx::B3DPolygon aNewPolygon, aMiterPolygon; + + // close polygon + aNewPolygon.setClosed(true); + aMiterPolygon.setClosed(true); + + for(sal_uInt32 a(0L); a < nVerSeg; a++) + { + const bool bFirst(0L == a); + const bool bLast(a + 1L == nVerSeg); + + if(bFirst || !bLast) + { + fPos += fInc; + + aNextPointOnXY = basegfx::B3DPoint( + cos(fPos), + sin(fPos), + 0.0); + + aNextPointRotY = basegfx::B3DPoint( + aNextPointOnXY.getX() * fCos, + aNextPointOnXY.getY(), + aNextPointOnXY.getX() * fSin); + + if(bMiter) + { + aNextMiter = basegfx::B3DPoint( + aNextPointOnXY.getX(), + aNextPointOnXY.getY(), + fMiterSin * (aNextPointOnXY.getX() / fMiterCos)); + } + } + + if(bFirst) + { + aNewPolygon.clear(); + + if(bMiter) + { + aNewPolygon.append(basegfx::B3DPoint(0.0, -1.0, 0.0)); + aNewPolygon.append(aNextPointOnXY); + aNewPolygon.append(aNextMiter); + + aMiterPolygon.clear(); + aMiterPolygon.append(basegfx::B3DPoint(0.0, -1.0, 0.0)); + aMiterPolygon.append(aNextMiter); + aMiterPolygon.append(aNextPointRotY); + } + else + { + aNewPolygon.append(basegfx::B3DPoint(0.0, -1.0, 0.0)); + aNewPolygon.append(aNextPointOnXY); + aNewPolygon.append(aNextPointRotY); + } + } + else if(bLast) + { + aNewPolygon.clear(); + + if(bMiter) + { + aNewPolygon.append(basegfx::B3DPoint(0.0, 1.0, 0.0)); + aNewPolygon.append(aCurrMiter); + aNewPolygon.append(aPointOnXY); + + aMiterPolygon.clear(); + aMiterPolygon.append(basegfx::B3DPoint(0.0, 1.0, 0.0)); + aMiterPolygon.append(aPointRotY); + aMiterPolygon.append(aCurrMiter); + } + else + { + aNewPolygon.append(basegfx::B3DPoint(0.0, 1.0, 0.0)); + aNewPolygon.append(aPointRotY); + aNewPolygon.append(aPointOnXY); + } + } + else + { + aNewPolygon.clear(); + + if(bMiter) + { + aNewPolygon.append(aPointOnXY); + aNewPolygon.append(aNextPointOnXY); + aNewPolygon.append(aNextMiter); + aNewPolygon.append(aCurrMiter); + + aMiterPolygon.clear(); + aMiterPolygon.append(aCurrMiter); + aMiterPolygon.append(aNextMiter); + aMiterPolygon.append(aNextPointRotY); + aMiterPolygon.append(aPointRotY); + } + else + { + aNewPolygon.append(aPointRotY); + aNewPolygon.append(aPointOnXY); + aNewPolygon.append(aNextPointOnXY); + aNewPolygon.append(aNextPointRotY); + } + } + + // set normals + for(sal_uInt32 b(0L); b < aNewPolygon.count(); b++) + { + aNewPolygon.setNormal(b, basegfx::B3DVector(aNewPolygon.getB3DPoint(b))); + } + + // create primitive + if(aNewPolygon.count()) + { + const basegfx::B3DPolyPolygon aNewPolyPolygon(aNewPolygon); + BasePrimitive3D* pNew = new PolyPolygonMaterialPrimitive3D(aNewPolyPolygon, rMaterial, false); + aResultVector.push_back(pNew); + } + + if(bMiter && aMiterPolygon.count()) + { + // set normals + for(sal_uInt32 c(0L); c < aMiterPolygon.count(); c++) + { + aMiterPolygon.setNormal(c, basegfx::B3DVector(aMiterPolygon.getB3DPoint(c))); + } + + // create primitive + const basegfx::B3DPolyPolygon aMiterPolyPolygon(aMiterPolygon); + BasePrimitive3D* pNew = new PolyPolygonMaterialPrimitive3D(aMiterPolyPolygon, rMaterial, false); + aResultVector.push_back(pNew); + } + + // prepare next step + if(bFirst || !bLast) + { + aPointOnXY = aNextPointOnXY; + aPointRotY = aNextPointRotY; + + if(bMiter) + { + aCurrMiter = aNextMiter; + } + } + } + } + } + + Primitive3DSequence aRetval(aResultVector.size()); + + for(sal_uInt32 a(0L); a < aResultVector.size(); a++) + { + aRetval[a] = Primitive3DReference(aResultVector[a]); + } + + return aRetval; + } + + basegfx::B3DHomMatrix getRotationFromVector(const basegfx::B3DVector& rVector) + { + // build transformation from unit vector to vector + basegfx::B3DHomMatrix aRetval; + + // get applied rotations from angles in XY and in XZ (cartesian) + const double fRotInXY(atan2(rVector.getY(), rVector.getXZLength())); + const double fRotInXZ(atan2(-rVector.getZ(), rVector.getX())); + + // apply rotations. Rot around Z needs to be done first, so apply in two steps + aRetval.rotate(0.0, 0.0, fRotInXY); + aRetval.rotate(0.0, fRotInXZ, 0.0); + + return aRetval; + } + } // end of anonymous namespace + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + Primitive3DSequence PolygonTubePrimitive3D::createLocalDecomposition(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + const sal_uInt32 nPointCount(getB3DPolygon().count()); + std::vector< BasePrimitive3D* > aResultVector; + + if(0L != nPointCount) + { + if(basegfx::fTools::more(getRadius(), 0.0)) + { + const attribute::MaterialAttribute3D aMaterial(getBColor()); + static sal_uInt32 nSegments(8L); // default for 3d line segments, for more quality just raise this value (in even steps) + const bool bClosed(getB3DPolygon().isClosed()); + const bool bNoLineJoin(basegfx::B2DLINEJOIN_NONE == getLineJoin()); + const sal_uInt32 nLoopCount(bClosed ? nPointCount : nPointCount - 1L); + basegfx::B3DPoint aLast(getB3DPolygon().getB3DPoint(nPointCount - 1L)); + basegfx::B3DPoint aCurr(getB3DPolygon().getB3DPoint(0L)); + + for(sal_uInt32 a(0L); a < nLoopCount; a++) + { + // get next data + const basegfx::B3DPoint aNext(getB3DPolygon().getB3DPoint((a + 1L) % nPointCount)); + const basegfx::B3DVector aForw(aNext - aCurr); + const double fForwLen(aForw.getLength()); + + if(basegfx::fTools::more(fForwLen, 0.0)) + { + // get rotation from vector, this describes rotation from (1, 0, 0) to aForw + basegfx::B3DHomMatrix aRotVector(getRotationFromVector(aForw)); + + // create default transformation with scale and rotate + basegfx::B3DHomMatrix aVectorTrans; + aVectorTrans.scale(fForwLen, getRadius(), getRadius()); + aVectorTrans *= aRotVector; + aVectorTrans.translate(aCurr.getX(), aCurr.getY(), aCurr.getZ()); + + if(bNoLineJoin || (!bClosed && !a)) + { + // line start edge, build transformed primitiveVector3D + TransformPrimitive3D* pNewTransformedA = new TransformPrimitive3D(aVectorTrans, getLineCapSegments(nSegments, aMaterial)); + aResultVector.push_back(pNewTransformedA); + } + else + { + const basegfx::B3DVector aBack(aCurr - aLast); + const double fCross(basegfx::cross(aBack, aForw).getLength()); + + if(!basegfx::fTools::equalZero(fCross)) + { + // line connect non-parallel, aBack, aForw, use getLineJoin() + const double fAngle(acos(aBack.scalar(aForw) / (fForwLen * aBack.getLength()))); // 0.0 .. F_PI2 + Primitive3DSequence aNewList(getLineJoinSegments(nSegments, aMaterial, fAngle, getDegreeStepWidth(), getMiterMinimumAngle(), getLineJoin())); + + // calculate transformation. First, get angle in YZ between nForw projected on (1, 0, 0) and nBack + basegfx::B3DHomMatrix aInvRotVector(aRotVector); + aInvRotVector.invert(); + basegfx::B3DVector aTransBack(aInvRotVector * aBack); + const double fRotInYZ(atan2(aTransBack.getY(), aTransBack.getZ())); + + // create trans by rotating unit sphere with angle 90 degrees around Y, then 180-fRot in X. + // Also apply usual scaling and translation + basegfx::B3DHomMatrix aSphereTrans; + aSphereTrans.rotate(0.0, F_PI2, 0.0); + aSphereTrans.rotate(F_PI - fRotInYZ, 0.0, 0.0); + aSphereTrans *= aRotVector; + aSphereTrans.scale(getRadius(), getRadius(), getRadius()); + aSphereTrans.translate(aCurr.getX(), aCurr.getY(), aCurr.getZ()); + + // line start edge, build transformed primitiveVector3D + TransformPrimitive3D* pNewTransformedB = new TransformPrimitive3D(aSphereTrans, aNewList); + aResultVector.push_back(pNewTransformedB); + } + } + + // create line segments, build transformed primitiveVector3D + TransformPrimitive3D* pNewTransformedC = new TransformPrimitive3D(aVectorTrans, getLineTubeSegments(nSegments, aMaterial)); + aResultVector.push_back(pNewTransformedC); + + if(bNoLineJoin || (!bClosed && ((a + 1L) == nLoopCount))) + { + // line end edge, first rotate (mirror) and translate, then use use aRotVector + basegfx::B3DHomMatrix aBackTrans; + aBackTrans.rotate(0.0, F_PI, 0.0); + aBackTrans.translate(1.0, 0.0, 0.0); + aBackTrans.scale(fForwLen, getRadius(), getRadius()); + aBackTrans *= aRotVector; + aBackTrans.translate(aCurr.getX(), aCurr.getY(), aCurr.getZ()); + + // line end edge, build transformed primitiveVector3D + TransformPrimitive3D* pNewTransformedD = new TransformPrimitive3D(aBackTrans, getLineCapSegments(nSegments, aMaterial)); + aResultVector.push_back(pNewTransformedD); + } + } + + // prepare next loop step + aLast = aCurr; + aCurr = aNext; + } + } + else + { + // create hairline + PolygonHairlinePrimitive3D* pNew = new PolygonHairlinePrimitive3D(getB3DPolygon(), getBColor()); + aResultVector.push_back(pNew); + } + } + + // prepare return value + Primitive3DSequence aRetval(aResultVector.size()); + + for(sal_uInt32 a(0L); a < aResultVector.size(); a++) + { + aRetval[a] = Primitive3DReference(aResultVector[a]); + } + + return aRetval; + } + + PolygonTubePrimitive3D::PolygonTubePrimitive3D( + const basegfx::B3DPolygon& rPolygon, + const basegfx::BColor& rBColor, + double fRadius, basegfx::B2DLineJoin aLineJoin, + double fDegreeStepWidth, + double fMiterMinimumAngle) + : PolygonHairlinePrimitive3D(rPolygon, rBColor), + mfRadius(fRadius), + mfDegreeStepWidth(fDegreeStepWidth), + mfMiterMinimumAngle(fMiterMinimumAngle), + maLineJoin(aLineJoin) + { + } + + bool PolygonTubePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(PolygonHairlinePrimitive3D::operator==(rPrimitive)) + { + const PolygonTubePrimitive3D& rCompare = (PolygonTubePrimitive3D&)rPrimitive; + + return (getRadius() == rCompare.getRadius() + && getDegreeStepWidth() == rCompare.getDegreeStepWidth() + && getMiterMinimumAngle() == rCompare.getMiterMinimumAngle() + && getLineJoin() == rCompare.getLineJoin()); + } + + return false; + } + + // provide unique ID + ImplPrimitrive3DIDBlock(PolygonTubePrimitive3D, PRIMITIVE3D_ID_POLYGONTUBEPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/polypolygonprimitive3d.cxx b/drawinglayer/source/primitive3d/polypolygonprimitive3d.cxx new file mode 100644 index 000000000000..f05a85869cbf --- /dev/null +++ b/drawinglayer/source/primitive3d/polypolygonprimitive3d.cxx @@ -0,0 +1,91 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: polypolygonprimitive3d.cxx,v $ + * + * $Revision: 1.9 $ + * + * last change: $Author: aw $ $Date: 2008-06-10 09:29:33 $ + * + * 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/primitive3d/polypolygonprimitive3d.hxx> +#include <basegfx/polygon/b3dpolypolygontools.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + PolyPolygonMaterialPrimitive3D::PolyPolygonMaterialPrimitive3D( + const basegfx::B3DPolyPolygon& rPolyPolygon, + const attribute::MaterialAttribute3D& rMaterial, + bool bDoubleSided) + : BasePrimitive3D(), + maPolyPolygon(rPolyPolygon), + maMaterial(rMaterial), + mbDoubleSided(bDoubleSided) + { + } + + bool PolyPolygonMaterialPrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(BasePrimitive3D::operator==(rPrimitive)) + { + const PolyPolygonMaterialPrimitive3D& rCompare = (PolyPolygonMaterialPrimitive3D&)rPrimitive; + + return (getB3DPolyPolygon() == rCompare.getB3DPolyPolygon() + && getMaterial() == rCompare.getMaterial() + && getDoubleSided() == rCompare.getDoubleSided()); + } + + return false; + } + + basegfx::B3DRange PolyPolygonMaterialPrimitive3D::getB3DRange(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + return basegfx::tools::getRange(getB3DPolyPolygon()); + } + + // provide unique ID + ImplPrimitrive3DIDBlock(PolyPolygonMaterialPrimitive3D, PRIMITIVE3D_ID_POLYPOLYGONMATERIALPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/sdrcubeprimitive3d.cxx b/drawinglayer/source/primitive3d/sdrcubeprimitive3d.cxx new file mode 100644 index 000000000000..341d2907a53d --- /dev/null +++ b/drawinglayer/source/primitive3d/sdrcubeprimitive3d.cxx @@ -0,0 +1,235 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: sdrcubeprimitive3d.cxx,v $ + * + * $Revision: 1.11 $ + * + * last change: $Author: aw $ $Date: 2008-06-10 09:29:33 $ + * + * 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/primitive3d/sdrcubeprimitive3d.hxx> +#include <basegfx/polygon/b3dpolypolygontools.hxx> +#include <basegfx/polygon/b3dpolygon.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <drawinglayer/primitive3d/sdrdecompositiontools3d.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> +#include <drawinglayer/primitive3d/hittestprimitive3d.hxx> +#include <drawinglayer/attribute/sdrattribute.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + Primitive3DSequence SdrCubePrimitive3D::createLocalDecomposition(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + const basegfx::B3DRange aUnitRange(0.0, 0.0, 0.0, 1.0, 1.0, 1.0); + Primitive3DSequence aRetval; + basegfx::B3DPolyPolygon aFill(basegfx::tools::createCubeFillPolyPolygonFromB3DRange(aUnitRange)); + + // normal creation + if(getSdrLFSAttribute().getFill()) + { + if(::com::sun::star::drawing::NormalsKind_SPECIFIC == getSdr3DObjectAttribute().getNormalsKind() + || ::com::sun::star::drawing::NormalsKind_SPHERE == getSdr3DObjectAttribute().getNormalsKind()) + { + // create sphere normals + const basegfx::B3DPoint aCenter(basegfx::tools::getRange(aFill).getCenter()); + aFill = basegfx::tools::applyDefaultNormalsSphere(aFill, aCenter); + } + + if(getSdr3DObjectAttribute().getNormalsInvert()) + { + // invert normals + aFill = basegfx::tools::invertNormals(aFill); + } + } + + // texture coordinates + if(getSdrLFSAttribute().getFill()) + { + // handle texture coordinates X + const bool bParallelX(::com::sun::star::drawing::TextureProjectionMode_PARALLEL == getSdr3DObjectAttribute().getTextureProjectionX()); + const bool bObjectSpecificX(::com::sun::star::drawing::TextureProjectionMode_OBJECTSPECIFIC == getSdr3DObjectAttribute().getTextureProjectionX()); + const bool bSphereX(!bParallelX && (::com::sun::star::drawing::TextureProjectionMode_SPHERE == getSdr3DObjectAttribute().getTextureProjectionX())); + + // handle texture coordinates Y + const bool bParallelY(::com::sun::star::drawing::TextureProjectionMode_PARALLEL == getSdr3DObjectAttribute().getTextureProjectionY()); + const bool bObjectSpecificY(::com::sun::star::drawing::TextureProjectionMode_OBJECTSPECIFIC == getSdr3DObjectAttribute().getTextureProjectionY()); + const bool bSphereY(!bParallelY && (::com::sun::star::drawing::TextureProjectionMode_SPHERE == getSdr3DObjectAttribute().getTextureProjectionY())); + + if(bParallelX || bParallelY) + { + // apply parallel texture coordinates in X and/or Y + const basegfx::B3DRange aRange(basegfx::tools::getRange(aFill)); + aFill = basegfx::tools::applyDefaultTextureCoordinatesParallel(aFill, aRange, bParallelX, bParallelY); + } + + if(bSphereX || bSphereY) + { + // apply spherical texture coordinates in X and/or Y + const basegfx::B3DRange aRange(basegfx::tools::getRange(aFill)); + const basegfx::B3DPoint aCenter(aRange.getCenter()); + aFill = basegfx::tools::applyDefaultTextureCoordinatesSphere(aFill, aCenter, bSphereX, bSphereY); + } + + if(bObjectSpecificX || bObjectSpecificY) + { + // object-specific + for(sal_uInt32 a(0L); a < aFill.count(); a++) + { + basegfx::B3DPolygon aTmpPoly(aFill.getB3DPolygon(a)); + + if(aTmpPoly.count() >= 4L) + { + for(sal_uInt32 b(0L); b < 4L; b++) + { + basegfx::B2DPoint aPoint(aTmpPoly.getTextureCoordinate(b)); + + if(bObjectSpecificX) + { + aPoint.setX((1L == b || 2L == b) ? 1.0 : 0.0); + } + + if(bObjectSpecificY) + { + aPoint.setY((2L == b || 3L == b) ? 1.0 : 0.0); + } + + aTmpPoly.setTextureCoordinate(b, aPoint); + } + + aFill.setB3DPolygon(a, aTmpPoly); + } + } + } + + // transform texture coordinates to texture size + basegfx::B2DHomMatrix aTexMatrix; + aTexMatrix.scale(getTextureSize().getX(), getTextureSize().getY()); + aFill.transformTextureCoordiantes(aTexMatrix); + } + + // build vector of PolyPolygons + ::std::vector< basegfx::B3DPolyPolygon > a3DPolyPolygonVector; + + for(sal_uInt32 a(0L); a < aFill.count(); a++) + { + a3DPolyPolygonVector.push_back(basegfx::B3DPolyPolygon(aFill.getB3DPolygon(a))); + } + + if(getSdrLFSAttribute().getFill()) + { + // add fill + aRetval = create3DPolyPolygonFillPrimitives( + a3DPolyPolygonVector, + getTransform(), + getTextureSize(), + getSdr3DObjectAttribute(), + *getSdrLFSAttribute().getFill(), + getSdrLFSAttribute().getFillFloatTransGradient()); + } + else + { + // create simplified 3d hit test geometry + const attribute::SdrFillAttribute aSimplifiedFillAttribute(0.0, basegfx::BColor(), 0, 0, 0); + + aRetval = create3DPolyPolygonFillPrimitives( + a3DPolyPolygonVector, + getTransform(), + getTextureSize(), + getSdr3DObjectAttribute(), + aSimplifiedFillAttribute, + 0); + + // encapsulate in HitTestPrimitive3D and add + const Primitive3DReference xRef(new HitTestPrimitive3D(aRetval)); + aRetval = Primitive3DSequence(&xRef, 1L); + } + + // add line + if(getSdrLFSAttribute().getLine()) + { + basegfx::B3DPolyPolygon aLine(basegfx::tools::createCubePolyPolygonFromB3DRange(aUnitRange)); + const Primitive3DSequence aLines(create3DPolyPolygonLinePrimitives(aLine, getTransform(), *getSdrLFSAttribute().getLine())); + appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aLines); + } + + // add shadow + if(getSdrLFSAttribute().getShadow() && aRetval.hasElements()) + { + const Primitive3DSequence aShadow(createShadowPrimitive3D(aRetval, *getSdrLFSAttribute().getShadow(), getSdr3DObjectAttribute().getShadow3D())); + appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aShadow); + } + + return aRetval; + } + + SdrCubePrimitive3D::SdrCubePrimitive3D( + const basegfx::B3DHomMatrix& rTransform, + const basegfx::B2DVector& rTextureSize, + const attribute::SdrLineFillShadowAttribute& rSdrLFSAttribute, + const attribute::Sdr3DObjectAttribute& rSdr3DObjectAttribute) + : SdrPrimitive3D(rTransform, rTextureSize, rSdrLFSAttribute, rSdr3DObjectAttribute) + { + } + + bool SdrCubePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + return SdrPrimitive3D::operator==(rPrimitive); + } + + basegfx::B3DRange SdrCubePrimitive3D::getB3DRange(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + // use defaut from sdrPrimitive3D which uses transformation expanded by line width/2. + // The parent implementation which uses the ranges of the decomposition would be more + // corrcet, but for historical reasons it is necessary to do the old method: To get + // the range of the non-transformed geometry and transform it then. This leads to different + // ranges where the new method is more correct, but the need to keep the old behaviour + // has priority here. + return getStandard3DRange(); + } + + // provide unique ID + ImplPrimitrive3DIDBlock(SdrCubePrimitive3D, PRIMITIVE3D_ID_SDRCUBEPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/sdrdecompositiontools3d.cxx b/drawinglayer/source/primitive3d/sdrdecompositiontools3d.cxx new file mode 100644 index 000000000000..df682ab04e6f --- /dev/null +++ b/drawinglayer/source/primitive3d/sdrdecompositiontools3d.cxx @@ -0,0 +1,299 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: sdrdecompositiontools3d.cxx,v $ + * + * $Revision: 1.7 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:21 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive3d/sdrdecompositiontools3d.hxx> +#include <basegfx/polygon/b3dpolygon.hxx> +#include <drawinglayer/attribute/strokeattribute.hxx> +#include <drawinglayer/attribute/sdrattribute.hxx> +#include <drawinglayer/primitive3d/baseprimitive3d.hxx> +#include <drawinglayer/primitive3d/polygonprimitive3d.hxx> +#include <basegfx/polygon/b3dpolypolygon.hxx> +#include <drawinglayer/primitive3d/polypolygonprimitive3d.hxx> +#include <drawinglayer/attribute/sdrattribute.hxx> +#include <vcl/vclenum.hxx> +#include <drawinglayer/attribute/fillattribute.hxx> +#include <drawinglayer/attribute/fillbitmapattribute.hxx> +#include <drawinglayer/attribute/sdrfillbitmapattribute.hxx> +#include <vcl/bmpacc.hxx> +#include <basegfx/polygon/b3dpolypolygontools.hxx> +#include <drawinglayer/primitive3d/textureprimitive3d.hxx> +#include <drawinglayer/primitive3d/modifiedcolorprimitive3d.hxx> +#include <drawinglayer/primitive3d/hatchtextureprimitive3d.hxx> +#include <drawinglayer/primitive3d/shadowprimitive3d.hxx> +#include <drawinglayer/attribute/sdrattribute3d.hxx> +#include <basegfx/range/b2drange.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + basegfx::B3DRange getRangeFrom3DGeometry(::std::vector< basegfx::B3DPolyPolygon >& rFill) + { + basegfx::B3DRange aRetval; + + for(sal_uInt32 a(0); a < rFill.size(); a++) + { + aRetval.expand(basegfx::tools::getRange(rFill[a])); + } + + return aRetval; + } + + void applyNormalsKindSphereTo3DGeometry(::std::vector< basegfx::B3DPolyPolygon >& rFill, const basegfx::B3DRange& rRange) + { + // create sphere normals + const basegfx::B3DPoint aCenter(rRange.getCenter()); + + for(sal_uInt32 a(0); a < rFill.size(); a++) + { + rFill[a] = basegfx::tools::applyDefaultNormalsSphere(rFill[a], aCenter); + } + } + + void applyNormalsKindFlatTo3DGeometry(::std::vector< basegfx::B3DPolyPolygon >& rFill) + { + for(sal_uInt32 a(0); a < rFill.size(); a++) + { + rFill[a].clearNormals(); + } + } + + void applyNormalsInvertTo3DGeometry(::std::vector< basegfx::B3DPolyPolygon >& rFill) + { + // invert normals + for(sal_uInt32 a(0); a < rFill.size(); a++) + { + rFill[a] = basegfx::tools::invertNormals(rFill[a]); + } + } + + void applyTextureTo3DGeometry( + ::com::sun::star::drawing::TextureProjectionMode eModeX, + ::com::sun::star::drawing::TextureProjectionMode eModeY, + ::std::vector< basegfx::B3DPolyPolygon >& rFill, + const basegfx::B3DRange& rRange, + const basegfx::B2DVector& rTextureSize) + { + sal_uInt32 a; + + // handle texture coordinates X + const bool bParallelX(::com::sun::star::drawing::TextureProjectionMode_PARALLEL == eModeX); + const bool bSphereX(!bParallelX && (::com::sun::star::drawing::TextureProjectionMode_SPHERE == eModeX)); + + // handle texture coordinates Y + const bool bParallelY(::com::sun::star::drawing::TextureProjectionMode_PARALLEL == eModeY); + const bool bSphereY(!bParallelY && (::com::sun::star::drawing::TextureProjectionMode_SPHERE == eModeY)); + + if(bParallelX || bParallelY) + { + // apply parallel texture coordinates in X and/or Y + for(a = 0; a < rFill.size(); a++) + { + rFill[a] = basegfx::tools::applyDefaultTextureCoordinatesParallel(rFill[a], rRange, bParallelX, bParallelY); + } + } + + if(bSphereX || bSphereY) + { + // apply spherical texture coordinates in X and/or Y + const basegfx::B3DPoint aCenter(rRange.getCenter()); + + for(a = 0; a < rFill.size(); a++) + { + rFill[a] = basegfx::tools::applyDefaultTextureCoordinatesSphere(rFill[a], aCenter, bSphereX, bSphereY); + } + } + + // transform texture coordinates to texture size + basegfx::B2DHomMatrix aTexMatrix; + aTexMatrix.scale(rTextureSize.getX(), rTextureSize.getY()); + + for(a = 0; a < rFill.size(); a++) + { + rFill[a].transformTextureCoordiantes(aTexMatrix); + } + } + + Primitive3DSequence create3DPolyPolygonLinePrimitives( + const basegfx::B3DPolyPolygon& rUnitPolyPolygon, + const basegfx::B3DHomMatrix& rObjectTransform, + const attribute::SdrLineAttribute& rLine) + { + // prepare fully scaled polyPolygon + basegfx::B3DPolyPolygon aScaledPolyPolygon(rUnitPolyPolygon); + aScaledPolyPolygon.transform(rObjectTransform); + + // create line and stroke attribute + const attribute::LineAttribute aLineAttribute(rLine.getColor(), rLine.getWidth(), rLine.getJoin()); + const attribute::StrokeAttribute aStrokeAttribute(rLine.getDotDashArray(), rLine.getFullDotDashLen()); + + // create primitives + Primitive3DSequence aRetval(aScaledPolyPolygon.count()); + + for(sal_uInt32 a(0L); a < aScaledPolyPolygon.count(); a++) + { + const Primitive3DReference xRef(new PolygonStrokePrimitive3D(aScaledPolyPolygon.getB3DPolygon(a), aLineAttribute, aStrokeAttribute)); + aRetval[a] = xRef; + } + + if(0.0 != rLine.getTransparence()) + { + // create UnifiedAlphaTexturePrimitive3D, add created primitives and exchange + const Primitive3DReference xRef(new UnifiedAlphaTexturePrimitive3D(rLine.getTransparence(), aRetval)); + aRetval = Primitive3DSequence(&xRef, 1L); + } + + return aRetval; + } + + Primitive3DSequence create3DPolyPolygonFillPrimitives( + const ::std::vector< basegfx::B3DPolyPolygon >& r3DPolyPolygonVector, + const basegfx::B3DHomMatrix& rObjectTransform, + const basegfx::B2DVector& rTextureSize, + const attribute::Sdr3DObjectAttribute& aSdr3DObjectAttribute, + const attribute::SdrFillAttribute& rFill, + const attribute::FillGradientAttribute* pFillGradient) + { + Primitive3DSequence aRetval; + + if(r3DPolyPolygonVector.size()) + { + // create list of simple fill primitives + aRetval.realloc(r3DPolyPolygonVector.size()); + + for(sal_uInt32 a(0L); a < r3DPolyPolygonVector.size(); a++) + { + // get scaled PolyPolygon + basegfx::B3DPolyPolygon aScaledPolyPolygon(r3DPolyPolygonVector[a]); + aScaledPolyPolygon.transform(rObjectTransform); + + if(aScaledPolyPolygon.areNormalsUsed()) + { + aScaledPolyPolygon.transformNormals(rObjectTransform); + } + + const Primitive3DReference xRef(new PolyPolygonMaterialPrimitive3D( + aScaledPolyPolygon, + aSdr3DObjectAttribute.getMaterial(), + aSdr3DObjectAttribute.getDoubleSided())); + aRetval[a] = xRef; + } + + // look for and evtl. build texture sub-group primitive + if(rFill.isGradient() || rFill.isHatch() || rFill.isBitmap()) + { + bool bModulate(::com::sun::star::drawing::TextureMode_MODULATE == aSdr3DObjectAttribute.getTextureMode()); + bool bFilter(aSdr3DObjectAttribute.getTextureFilter()); + BasePrimitive3D* pNewTexturePrimitive3D = 0L; + + if(rFill.isGradient()) + { + // create gradientTexture3D with sublist, add to local aRetval + pNewTexturePrimitive3D = new GradientTexturePrimitive3D(*rFill.getGradient(), aRetval, rTextureSize, bModulate, bFilter); + } + else if(rFill.isHatch()) + { + // create hatchTexture3D with sublist, add to local aRetval + pNewTexturePrimitive3D = new HatchTexturePrimitive3D(*rFill.getHatch(), aRetval, rTextureSize, bModulate, bFilter); + } + else // if(rFill.isBitmap()) + { + // create bitmapTexture3D with sublist, add to local aRetval + basegfx::B2DRange aTexRange(0.0, 0.0, rTextureSize.getX(), rTextureSize.getY()); + pNewTexturePrimitive3D = new BitmapTexturePrimitive3D(rFill.getBitmap()->getFillBitmapAttribute(aTexRange), aRetval, rTextureSize, bModulate, bFilter); + } + + // exchange aRetval content with texture group + const Primitive3DReference xRef(pNewTexturePrimitive3D); + aRetval = Primitive3DSequence(&xRef, 1L); + + if(::com::sun::star::drawing::TextureKind2_LUMINANCE == aSdr3DObjectAttribute.getTextureKind()) + { + // use modified color primitive to force textures to gray + const basegfx::BColorModifier aBColorModifier(basegfx::BColor(), 0.0, basegfx::BCOLORMODIFYMODE_GRAY); + const Primitive3DReference xRef2(new ModifiedColorPrimitive3D(aRetval, aBColorModifier)); + aRetval = Primitive3DSequence(&xRef2, 1L); + } + } + + if(0.0 != rFill.getTransparence()) + { + // create UnifiedAlphaTexturePrimitive3D with sublist and exchange + const Primitive3DReference xRef(new UnifiedAlphaTexturePrimitive3D(rFill.getTransparence(), aRetval)); + aRetval = Primitive3DSequence(&xRef, 1L); + } + else if(pFillGradient) + { + // create AlphaTexturePrimitive3D with sublist and exchange + const Primitive3DReference xRef(new AlphaTexturePrimitive3D(*pFillGradient, aRetval, rTextureSize)); + aRetval = Primitive3DSequence(&xRef, 1L); + } + } + + return aRetval; + } + + Primitive3DSequence createShadowPrimitive3D( + const Primitive3DSequence& rSource, + const attribute::SdrShadowAttribute& rShadow, + bool bShadow3D) + { + // create Shadow primitives. Uses already created primitives + if(rSource.hasElements() && !basegfx::fTools::moreOrEqual(rShadow.getTransparence(), 1.0)) + { + // prepare new list for shadow geometry + basegfx::B2DHomMatrix aShadowOffset; + aShadowOffset.set(0, 2, rShadow.getOffset().getX()); + aShadowOffset.set(1, 2, rShadow.getOffset().getY()); + + // create shadow primitive and add primitives + const Primitive3DReference xRef(new ShadowPrimitive3D(aShadowOffset, rShadow.getColor(), rShadow.getTransparence(), bShadow3D, rSource)); + return Primitive3DSequence(&xRef, 1L); + } + else + { + return Primitive3DSequence(); + } + } + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/sdrextrudelathetools3d.cxx b/drawinglayer/source/primitive3d/sdrextrudelathetools3d.cxx new file mode 100644 index 000000000000..973a82c8eca4 --- /dev/null +++ b/drawinglayer/source/primitive3d/sdrextrudelathetools3d.cxx @@ -0,0 +1,999 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: sdrextrudelathetools3d.cxx,v $ + * + * $Revision: 1.11 $ + * + * last change: $Author: aw $ $Date: 2008-06-24 15:31:08 $ + * + * 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/primitive3d/sdrextrudelathetools3d.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/range/b2drange.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/point/b3dpoint.hxx> +#include <basegfx/polygon/b3dpolygon.hxx> +#include <basegfx/polygon/b3dpolygontools.hxx> +#include <basegfx/polygon/b3dpolypolygontools.hxx> +#include <basegfx/range/b3drange.hxx> +#include <basegfx/matrix/b3dhommatrix.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <drawinglayer/geometry/viewinformation3d.hxx> +#include <numeric> + +////////////////////////////////////////////////////////////////////////////// +// decompositon helpers for extrude/lathe (rotation) objects + +namespace +{ + ////////////////////////////////////////////////////////////////////////////// + // common helpers + + basegfx::B2DPolyPolygon impScalePolyPolygonOnCenter( + const basegfx::B2DPolyPolygon& rSource, + double fScale) + { + basegfx::B2DPolyPolygon aRetval(rSource); + + if(!basegfx::fTools::equalZero(fScale)) + { + const basegfx::B2DRange aRange(basegfx::tools::getRange(rSource)); + const basegfx::B2DPoint aCenter(aRange.getCenter()); + basegfx::B2DHomMatrix aTrans; + + aTrans.translate(-aCenter.getX(), -aCenter.getY()); + aTrans.scale(fScale, fScale); + aTrans.translate(aCenter.getX(), aCenter.getY()); + aRetval.transform(aTrans); + } + + return aRetval; + } + + void impGetOuterPolyPolygon( + basegfx::B2DPolyPolygon& rPolygon, + basegfx::B2DPolyPolygon& rOuterPolyPolygon, + double fOffset, + bool bCharacterMode) + { + rOuterPolyPolygon = rPolygon; + + if(basegfx::fTools::more(fOffset, 0.0)) + { + if(bCharacterMode) + { + // grow the outside polygon and scale all polygons to original size. This is done + // to avoid a shrink which potentially would lead to self-intersections, but changes + // the original polygon -> not a precision step, so e.g. not usable for charts + const basegfx::B2DRange aRange(basegfx::tools::getRange(rPolygon)); + rPolygon = basegfx::tools::growInNormalDirection(rPolygon, fOffset); + const basegfx::B2DRange aGrownRange(basegfx::tools::getRange(rPolygon)); + const double fScaleX(basegfx::fTools::equalZero(aGrownRange.getWidth()) ? 1.0 : aRange.getWidth() / aGrownRange.getWidth()); + const double fScaleY(basegfx::fTools::equalZero(aGrownRange.getHeight())? 1.0 : aRange.getHeight() / aGrownRange.getHeight()); + basegfx::B2DHomMatrix aScaleTrans; + + aScaleTrans.translate(-aGrownRange.getMinX(), -aGrownRange.getMinY()); + aScaleTrans.scale(fScaleX, fScaleY); + aScaleTrans.translate(aRange.getMinX(), aRange.getMinY()); + rPolygon.transform(aScaleTrans); + rOuterPolyPolygon.transform(aScaleTrans); + } + else + { + // use more precision, shrink the outer polygons. Since this may lead to self-intersections, + // some kind of correction should be applied here after that step + rOuterPolyPolygon = basegfx::tools::growInNormalDirection(rPolygon, -fOffset); + basegfx::tools::correctGrowShrinkPolygonPair(rPolygon, rOuterPolyPolygon); + } + } + } + + void impAddInBetweenFill( + basegfx::B3DPolyPolygon& rTarget, + const basegfx::B3DPolyPolygon& rPolA, + const basegfx::B3DPolyPolygon& rPolB, + double fTexVerStart, + double fTexVerStop, + bool bCreateNormals, + bool bCreateTextureCoordinates) + { + OSL_ENSURE(rPolA.count() == rPolB.count(), "impAddInBetweenFill: unequally sized polygons (!)"); + const sal_uInt32 nPolygonCount(rPolA.count()); + + for(sal_uInt32 a(0L); a < nPolygonCount; a++) + { + const basegfx::B3DPolygon aSubA(rPolA.getB3DPolygon(a)); + const basegfx::B3DPolygon aSubB(rPolB.getB3DPolygon(a)); + OSL_ENSURE(aSubA.count() == aSubB.count(), "impAddInBetweenFill: unequally sized polygons (!)"); + const sal_uInt32 nPointCount(aSubA.count()); + + if(nPointCount) + { + const sal_uInt32 nEdgeCount(aSubA.isClosed() ? nPointCount : nPointCount - 1L); + double fTexHorMultiplicatorA(0.0), fTexHorMultiplicatorB(0.0); + double fPolygonPosA(0.0), fPolygonPosB(0.0); + + if(bCreateTextureCoordinates) + { + const double fPolygonLengthA(basegfx::tools::getLength(aSubA)); + fTexHorMultiplicatorA = basegfx::fTools::equalZero(fPolygonLengthA) ? 1.0 : 1.0 / fPolygonLengthA; + + const double fPolygonLengthB(basegfx::tools::getLength(aSubB)); + fTexHorMultiplicatorB = basegfx::fTools::equalZero(fPolygonLengthB) ? 1.0 : 1.0 / fPolygonLengthB; + } + + for(sal_uInt32 b(0L); b < nEdgeCount; b++) + { + const sal_uInt32 nIndexA(b); + const sal_uInt32 nIndexB((b + 1L) % nPointCount); + + const basegfx::B3DPoint aStartA(aSubA.getB3DPoint(nIndexA)); + const basegfx::B3DPoint aEndA(aSubA.getB3DPoint(nIndexB)); + const basegfx::B3DPoint aStartB(aSubB.getB3DPoint(nIndexA)); + const basegfx::B3DPoint aEndB(aSubB.getB3DPoint(nIndexB)); + + basegfx::B3DPolygon aNew; + aNew.setClosed(true); + + aNew.append(aStartA); + aNew.append(aStartB); + aNew.append(aEndB); + aNew.append(aEndA); + + if(bCreateNormals) + { + aNew.setNormal(0L, aSubA.getNormal(nIndexA)); + aNew.setNormal(1L, aSubB.getNormal(nIndexA)); + aNew.setNormal(2L, aSubB.getNormal(nIndexB)); + aNew.setNormal(3L, aSubA.getNormal(nIndexB)); + } + + if(bCreateTextureCoordinates) + { + const double fRelTexAL(fPolygonPosA * fTexHorMultiplicatorA); + const double fEdgeLengthA(basegfx::B3DVector(aEndA - aStartA).getLength()); + fPolygonPosA += fEdgeLengthA; + const double fRelTexAR(fPolygonPosA * fTexHorMultiplicatorA); + + const double fRelTexBL(fPolygonPosB * fTexHorMultiplicatorB); + const double fEdgeLengthB(basegfx::B3DVector(aEndB - aStartB).getLength()); + fPolygonPosB += fEdgeLengthB; + const double fRelTexBR(fPolygonPosB * fTexHorMultiplicatorB); + + aNew.setTextureCoordinate(0L, basegfx::B2DPoint(fRelTexAL, fTexVerStart)); + aNew.setTextureCoordinate(1L, basegfx::B2DPoint(fRelTexBL, fTexVerStop)); + aNew.setTextureCoordinate(2L, basegfx::B2DPoint(fRelTexBR, fTexVerStop)); + aNew.setTextureCoordinate(3L, basegfx::B2DPoint(fRelTexAR, fTexVerStart)); + } + + rTarget.append(aNew); + } + } + } + } + + void impSetNormal( + basegfx::B3DPolyPolygon& rCandidate, + const basegfx::B3DVector& rNormal) + { + for(sal_uInt32 a(0L); a < rCandidate.count(); a++) + { + basegfx::B3DPolygon aSub(rCandidate.getB3DPolygon(a)); + + for(sal_uInt32 b(0L); b < aSub.count(); b++) + { + aSub.setNormal(b, rNormal); + } + + rCandidate.setB3DPolygon(a, aSub); + } + } + + void impCreateInBetweenNormals( + basegfx::B3DPolyPolygon& rPolA, + basegfx::B3DPolyPolygon& rPolB, + bool bSmoothHorizontalNormals) + { + OSL_ENSURE(rPolA.count() == rPolB.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)"); + + for(sal_uInt32 a(0L); a < rPolA.count(); a++) + { + basegfx::B3DPolygon aSubA(rPolA.getB3DPolygon(a)); + basegfx::B3DPolygon aSubB(rPolB.getB3DPolygon(a)); + OSL_ENSURE(aSubA.count() == aSubB.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)"); + const sal_uInt32 nPointCount(aSubA.count()); + + if(nPointCount) + { + basegfx::B3DPoint aPrevA(aSubA.getB3DPoint(nPointCount - 1L)); + basegfx::B3DPoint aCurrA(aSubA.getB3DPoint(0L)); + const bool bClosed(aSubA.isClosed()); + + for(sal_uInt32 b(0L); b < nPointCount; b++) + { + const sal_uInt32 nIndNext((b + 1L) % nPointCount); + const basegfx::B3DPoint aNextA(aSubA.getB3DPoint(nIndNext)); + const basegfx::B3DPoint aCurrB(aSubB.getB3DPoint(b)); + + // vector to back + basegfx::B3DVector aDepth(aCurrB - aCurrA); + aDepth.normalize(); + + if(aDepth.equalZero()) + { + // no difference, try to get depth from next point + const basegfx::B3DPoint aNextB(aSubB.getB3DPoint(nIndNext)); + aDepth = aNextB - aNextA; + aDepth.normalize(); + } + + // vector to left (correct for non-closed lines) + const bool bFirstAndNotClosed(!bClosed && 0L == b); + basegfx::B3DVector aLeft(bFirstAndNotClosed ? aCurrA - aNextA : aPrevA - aCurrA); + aLeft.normalize(); + + // create left normal + const basegfx::B3DVector aNormalLeft(aDepth.getPerpendicular(aLeft)); + + if(bSmoothHorizontalNormals) + { + // vector to right (correct for non-closed lines) + const bool bLastAndNotClosed(!bClosed && b + 1L == nPointCount); + basegfx::B3DVector aRight(bLastAndNotClosed ? aCurrA - aPrevA : aNextA - aCurrA); + aRight.normalize(); + + // create right normal + const basegfx::B3DVector aNormalRight(aRight.getPerpendicular(aDepth)); + + // create smoothed in-between normal + basegfx::B3DVector aNewNormal(aNormalLeft + aNormalRight); + aNewNormal.normalize(); + + // set as new normal at polygons + aSubA.setNormal(b, aNewNormal); + aSubB.setNormal(b, aNewNormal); + } + else + { + // set aNormalLeft as new normal at polygons + aSubA.setNormal(b, aNormalLeft); + aSubB.setNormal(b, aNormalLeft); + } + + // prepare next step + aPrevA = aCurrA; + aCurrA = aNextA; + } + + rPolA.setB3DPolygon(a, aSubA); + rPolB.setB3DPolygon(a, aSubB); + } + } + } + + void impMixNormals( + basegfx::B3DPolyPolygon& rPolA, + const basegfx::B3DPolyPolygon& rPolB, + double fWeightA) + { + const double fWeightB(1.0 - fWeightA); + OSL_ENSURE(rPolA.count() == rPolB.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)"); + + for(sal_uInt32 a(0L); a < rPolA.count(); a++) + { + basegfx::B3DPolygon aSubA(rPolA.getB3DPolygon(a)); + const basegfx::B3DPolygon aSubB(rPolB.getB3DPolygon(a)); + OSL_ENSURE(aSubA.count() == aSubB.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)"); + const sal_uInt32 nPointCount(aSubA.count()); + + for(sal_uInt32 b(0L); b < nPointCount; b++) + { + const basegfx::B3DVector aVA(aSubA.getNormal(b) * fWeightA); + const basegfx::B3DVector aVB(aSubB.getNormal(b) * fWeightB); + basegfx::B3DVector aVNew(aVA + aVB); + aVNew.normalize(); + aSubA.setNormal(b, aVNew); + } + + rPolA.setB3DPolygon(a, aSubA); + } + } + + bool impHasCutWith(const basegfx::B2DPolygon& rPoly, const basegfx::B2DPoint& rStart, const basegfx::B2DPoint& rEnd) + { + // polygon is closed, one of the points is a member + const sal_uInt32 nPointCount(rPoly.count()); + + if(nPointCount) + { + basegfx::B2DPoint aCurrent(rPoly.getB2DPoint(0)); + const basegfx::B2DVector aVector(rEnd - rStart); + + for(sal_uInt32 a(0); a < nPointCount; a++) + { + const sal_uInt32 nNextIndex((a + 1) % nPointCount); + const basegfx::B2DPoint aNext(rPoly.getB2DPoint(nNextIndex)); + const basegfx::B2DVector aEdgeVector(aNext - aCurrent); + + if(basegfx::tools::findCut( + rStart, aVector, + aCurrent, aEdgeVector)) + { + return true; + } + + aCurrent = aNext; + } + } + + return false; + } +} // end of anonymous namespace + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + void createLatheSlices( + Slice3DVector& rSliceVector, + const basegfx::B2DPolyPolygon& rSource, + double fBackScale, + double fDiagonal, + double fRotation, + sal_uInt32 nSteps, + bool bCharacterMode, + bool bCloseFront, + bool bCloseBack) + { + if(basegfx::fTools::equalZero(fRotation) || 0L == nSteps) + { + // no rotation or no steps, just one plane + rSliceVector.push_back(Slice3D(rSource, basegfx::B3DHomMatrix())); + } + else + { + const bool bBackScale(!basegfx::fTools::equal(fBackScale, 1.0)); + const bool bClosedRotation(!bBackScale && basegfx::fTools::equal(fRotation, F_2PI)); + basegfx::B2DPolyPolygon aFront(rSource); + basegfx::B2DPolyPolygon aBack(rSource); + basegfx::B3DHomMatrix aTransformBack; + basegfx::B2DPolyPolygon aOuterBack; + + if(bClosedRotation) + { + bCloseFront = bCloseBack = false; + } + + if(bBackScale) + { + // avoid null zoom + if(basegfx::fTools::equalZero(fBackScale)) + { + fBackScale = 0.000001; + } + + // back is scaled compared to front, create scaled version + aBack = impScalePolyPolygonOnCenter(aBack, fBackScale); + } + + if(bCloseFront || bCloseBack) + { + const basegfx::B2DRange aBaseRange(basegfx::tools::getRange(aFront)); + const double fOuterLength(aBaseRange.getMaxX() * fRotation); + const double fInnerLength(aBaseRange.getMinX() * fRotation); + const double fAverageLength((fOuterLength + fInnerLength) * 0.5); + + if(bCloseFront) + { + const double fOffsetLen((fAverageLength / 12.0) * fDiagonal); + basegfx::B2DPolyPolygon aOuterFront; + impGetOuterPolyPolygon(aFront, aOuterFront, fOffsetLen, bCharacterMode); + basegfx::B3DHomMatrix aTransform; + aTransform.translate(0.0, 0.0, fOffsetLen); + rSliceVector.push_back(Slice3D(aOuterFront, aTransform, SLICETYPE3D_FRONTCAP)); + } + + if(bCloseBack) + { + const double fOffsetLen((fAverageLength / 12.0) * fDiagonal); + impGetOuterPolyPolygon(aBack, aOuterBack, fOffsetLen, bCharacterMode); + aTransformBack.translate(0.0, 0.0, -fOffsetLen); + aTransformBack.rotate(0.0, fRotation, 0.0); + } + } + + // add start polygon (a = 0L) + if(!bClosedRotation) + { + rSliceVector.push_back(Slice3D(aFront, basegfx::B3DHomMatrix())); + } + + // create segments (a + 1 .. nSteps) + const double fStepSize(1.0 / (double)nSteps); + + for(sal_uInt32 a(0L); a < nSteps; a++) + { + const double fStep((double)(a + 1L) * fStepSize); + basegfx::B2DPolyPolygon aNewPoly(bBackScale ? basegfx::tools::interpolate(aFront, aBack, fStep) : aFront); + basegfx::B3DHomMatrix aNewMat; + aNewMat.rotate(0.0, fRotation * fStep, 0.0); + rSliceVector.push_back(Slice3D(aNewPoly, aNewMat)); + } + + if(bCloseBack) + { + rSliceVector.push_back(Slice3D(aOuterBack, aTransformBack, SLICETYPE3D_BACKCAP)); + } + } + } + + void createExtrudeSlices( + Slice3DVector& rSliceVector, + const basegfx::B2DPolyPolygon& rSource, + double fBackScale, + double fDiagonal, + double fDepth, + bool bCharacterMode, + bool bCloseFront, + bool bCloseBack) + { + if(basegfx::fTools::equalZero(fDepth)) + { + // no depth, just one plane + rSliceVector.push_back(Slice3D(rSource, basegfx::B3DHomMatrix())); + } + else + { + // there is depth, create Polygons for front,back and their default depth positions + basegfx::B2DPolyPolygon aFront(rSource); + basegfx::B2DPolyPolygon aBack(rSource); + const bool bBackScale(!basegfx::fTools::equal(fBackScale, 1.0)); + double fZFront(fDepth); // default depth for aFront + double fZBack(0.0); // default depth for aBack + basegfx::B2DPolyPolygon aOuterBack; + + if(bBackScale) + { + // avoid null zoom + if(basegfx::fTools::equalZero(fBackScale)) + { + fBackScale = 0.000001; + } + + // aFront is scaled compared to aBack, create scaled version + aFront = impScalePolyPolygonOnCenter(aFront, fBackScale); + } + + if(bCloseFront) + { + const double fOffset(fDepth * fDiagonal * 0.5); + fZFront = fDepth - fOffset; + basegfx::B2DPolyPolygon aOuterFront; + impGetOuterPolyPolygon(aFront, aOuterFront, fOffset, bCharacterMode); + basegfx::B3DHomMatrix aTransformFront; + aTransformFront.translate(0.0, 0.0, fDepth); + rSliceVector.push_back(Slice3D(aOuterFront, aTransformFront, SLICETYPE3D_FRONTCAP)); + } + + if(bCloseBack) + { + const double fOffset(fDepth * fDiagonal * 0.5); + fZBack = fOffset; + impGetOuterPolyPolygon(aBack, aOuterBack, fOffset, bCharacterMode); + } + + // add front and back polygons at evtl. changed depths + { + basegfx::B3DHomMatrix aTransformA, aTransformB; + + aTransformA.translate(0.0, 0.0, fZFront); + rSliceVector.push_back(Slice3D(aFront, aTransformA)); + + aTransformB.translate(0.0, 0.0, fZBack); + rSliceVector.push_back(Slice3D(aBack, aTransformB)); + } + + if(bCloseBack) + { + rSliceVector.push_back(Slice3D(aOuterBack, basegfx::B3DHomMatrix(), SLICETYPE3D_BACKCAP)); + } + } + } + + basegfx::B3DPolyPolygon extractHorizontalLinesFromSlice(const Slice3DVector& rSliceVector, bool bCloseHorLines) + { + basegfx::B3DPolyPolygon aRetval; + const sal_uInt32 nNumSlices(rSliceVector.size()); + + if(nNumSlices) + { + const sal_uInt32 nSlideSubPolygonCount(rSliceVector[0].getB3DPolyPolygon().count()); + + for(sal_uInt32 b(0); b < nSlideSubPolygonCount; b++) + { + const sal_uInt32 nSubPolygonPointCount(rSliceVector[0].getB3DPolyPolygon().getB3DPolygon(b).count()); + + for(sal_uInt32 c(0); c < nSubPolygonPointCount; c++) + { + basegfx::B3DPolygon aNew; + + for(sal_uInt32 d(0); d < nNumSlices; d++) + { + OSL_ENSURE(nSlideSubPolygonCount == rSliceVector[d].getB3DPolyPolygon().count(), + "Slice PolyPolygon with different Polygon count (!)"); + OSL_ENSURE(nSubPolygonPointCount == rSliceVector[d].getB3DPolyPolygon().getB3DPolygon(b).count(), + "Slice Polygon with different point count (!)"); + aNew.append(rSliceVector[d].getB3DPolyPolygon().getB3DPolygon(b).getB3DPoint(c)); + } + + aNew.setClosed(bCloseHorLines); + aRetval.append(aNew); + } + } + } + + return aRetval; + } + + basegfx::B3DPolyPolygon extractVerticalLinesFromSlice(const Slice3DVector& rSliceVector) + { + basegfx::B3DPolyPolygon aRetval; + const sal_uInt32 nNumSlices(rSliceVector.size()); + + for(sal_uInt32 a(0L); a < nNumSlices; a++) + { + aRetval.append(rSliceVector[a].getB3DPolyPolygon()); + } + + return aRetval; + } + + void extractPlanesFromSlice( + ::std::vector< basegfx::B3DPolyPolygon >& rFill, + const Slice3DVector& rSliceVector, + bool bCreateNormals, + bool bSmoothHorizontalNormals, + bool bSmoothNormals, + bool bSmoothLids, + bool bClosed, + double fSmoothNormalsMix, + double fSmoothLidsMix, + bool bCreateTextureCoordinates, + const basegfx::B2DHomMatrix& rTexTransform) + { + const sal_uInt32 nNumSlices(rSliceVector.size()); + + if(nNumSlices) + { + // common parameters + const sal_uInt32 nLoopCount(bClosed ? nNumSlices : nNumSlices - 1L); + basegfx::B3DPolyPolygon aEdgeRounding; + sal_uInt32 a; + + // tetxture parameters + double fInvTexHeight(1.0); + double fTexHeightPos(0.0); + double fTexStart(0.0); + double fTexStop(1.0); + ::std::vector<double> aTexHeightArray; + basegfx::B3DRange aTexRangeFront; + basegfx::B3DRange aTexRangeBack; + + if(bCreateTextureCoordinates) + { + aTexRangeFront = basegfx::tools::getRange(rSliceVector[0L].getB3DPolyPolygon()); + aTexRangeBack = basegfx::tools::getRange(rSliceVector[nNumSlices - 1L].getB3DPolyPolygon()); + + if(aTexRangeBack.getDepth() > aTexRangeBack.getWidth()) + { + // last polygon is rotated so that depth is bigger than width, exchange X and Z + // for making applyDefaultTextureCoordinatesParallel use Z instead of X for + // horizontal texture coordinate + aTexRangeBack = basegfx::B3DRange( + aTexRangeBack.getMinZ(), aTexRangeBack.getMinY(), aTexRangeBack.getMinX(), + aTexRangeBack.getMaxZ(), aTexRangeBack.getMaxY(), aTexRangeBack.getMaxX()); + } + + basegfx::B3DPoint aCenter(basegfx::tools::getRange(rSliceVector[0L].getB3DPolyPolygon()).getCenter()); + + for(a = 0L; a < nLoopCount; a++) + { + const basegfx::B3DPoint aNextCenter(basegfx::tools::getRange(rSliceVector[(a + 1L) % nNumSlices].getB3DPolyPolygon()).getCenter()); + const double fLength(basegfx::B3DVector(aNextCenter - aCenter).getLength()); + aTexHeightArray.push_back(fLength); + aCenter = aNextCenter; + } + + const double fTexHeight(::std::accumulate(aTexHeightArray.begin(), aTexHeightArray.end(), 0.0)); + + if(!basegfx::fTools::equalZero(fTexHeight)) + { + fInvTexHeight = 1.0 / fTexHeight; + } + } + + if(nLoopCount) + { + for(a = 0L; a < nLoopCount; a++) + { + const Slice3D& rSliceA(rSliceVector[a]); + const Slice3D& rSliceB(rSliceVector[(a + 1L) % nNumSlices]); + const bool bAcceptPair(SLICETYPE3D_REGULAR == rSliceA.getSliceType() && SLICETYPE3D_REGULAR == rSliceB.getSliceType()); + basegfx::B3DPolyPolygon aPolA(rSliceA.getB3DPolyPolygon()); + basegfx::B3DPolyPolygon aPolB(rSliceB.getB3DPolyPolygon()); + + if(bAcceptPair) + { + if(bCreateNormals) + { + impCreateInBetweenNormals(aPolB, aPolA, bSmoothHorizontalNormals); + } + + { + const sal_uInt32 nIndPrev((a + nNumSlices - 1L) % nNumSlices); + const Slice3D& rSlicePrev(rSliceVector[nIndPrev]); + basegfx::B3DPolyPolygon aPrev(rSlicePrev.getB3DPolyPolygon()); + basegfx::B3DPolyPolygon aPolAA(rSliceA.getB3DPolyPolygon()); + + if(SLICETYPE3D_FRONTCAP == rSlicePrev.getSliceType()) + { + basegfx::B3DPolyPolygon aFront(rSlicePrev.getB3DPolyPolygon()); + const bool bHasSlant(aPolAA != aPrev); + + if(bCreateTextureCoordinates) + { + aFront = basegfx::tools::applyDefaultTextureCoordinatesParallel(aFront, aTexRangeFront); + } + + if(bCreateNormals) + { + basegfx::B3DVector aNormal(0.0, 0.0, -1.0); + + if(aFront.count()) + { + aNormal = -aFront.getB3DPolygon(0L).getNormal(); + } + + impSetNormal(aFront, aNormal); + + if(bHasSlant) + { + impCreateInBetweenNormals(aPolAA, aPrev, bSmoothHorizontalNormals); + + if(bSmoothNormals) + { + // smooth and copy + impMixNormals(aPolA, aPolAA, fSmoothNormalsMix); + aPolAA = aPolA; + } + else + { + // take over from surface + aPolAA = aPolA; + } + + if(bSmoothLids) + { + // smooth and copy + impMixNormals(aFront, aPrev, fSmoothLidsMix); + aPrev = aFront; + } + else + { + // take over from front + aPrev = aFront; + } + } + else + { + if(bSmoothNormals) + { + // smooth + impMixNormals(aPolA, aFront, fSmoothNormalsMix); + } + + if(bSmoothLids) + { + // smooth and copy + impMixNormals(aFront, aPolA, fSmoothLidsMix); + aPolA = aFront; + } + } + } + + if(bHasSlant) + { + if(bCreateTextureCoordinates) + { + fTexStart = fTexHeightPos * fInvTexHeight; + fTexStop = (fTexHeightPos - aTexHeightArray[(a + nLoopCount - 1L) % nLoopCount]) * fInvTexHeight; + } + + impAddInBetweenFill(aEdgeRounding, aPolAA, aPrev, fTexStart, fTexStop, bCreateNormals, bCreateTextureCoordinates); + } + + aFront.flip(); + rFill.push_back(aFront); + } + else + { + if(bCreateNormals && bSmoothNormals && (nIndPrev != a + 1L)) + { + impCreateInBetweenNormals(aPolAA, aPrev, bSmoothHorizontalNormals); + impMixNormals(aPolA, aPolAA, 0.5); + } + } + } + + { + const sal_uInt32 nIndNext((a + 2L) % nNumSlices); + const Slice3D& rSliceNext(rSliceVector[nIndNext]); + basegfx::B3DPolyPolygon aNext(rSliceNext.getB3DPolyPolygon()); + basegfx::B3DPolyPolygon aPolBB(rSliceB.getB3DPolyPolygon()); + + if(SLICETYPE3D_BACKCAP == rSliceNext.getSliceType()) + { + basegfx::B3DPolyPolygon aBack(rSliceNext.getB3DPolyPolygon()); + const bool bHasSlant(aPolBB != aNext); + + if(bCreateTextureCoordinates) + { + aBack = basegfx::tools::applyDefaultTextureCoordinatesParallel(aBack, aTexRangeBack); + } + + if(bCreateNormals) + { + const basegfx::B3DVector aNormal(aBack.count() ? aBack.getB3DPolygon(0L).getNormal() : basegfx::B3DVector(0.0, 0.0, 1.0)); + impSetNormal(aBack, aNormal); + + if(bHasSlant) + { + impCreateInBetweenNormals(aNext, aPolBB, bSmoothHorizontalNormals); + + if(bSmoothNormals) + { + // smooth and copy + impMixNormals(aPolB, aPolBB, fSmoothNormalsMix); + aPolBB = aPolB; + } + else + { + // take over from surface + aPolBB = aPolB; + } + + if(bSmoothLids) + { + // smooth and copy + impMixNormals(aBack, aNext, fSmoothLidsMix); + aNext = aBack; + } + else + { + // take over from back + aNext = aBack; + } + } + else + { + if(bSmoothNormals) + { + // smooth + impMixNormals(aPolB, aBack, fSmoothNormalsMix); + } + + if(bSmoothLids) + { + // smooth and copy + impMixNormals(aBack, aPolB, fSmoothLidsMix); + aPolB = aBack; + } + } + } + + if(bHasSlant) + { + if(bCreateTextureCoordinates) + { + fTexStart = (fTexHeightPos + aTexHeightArray[a] + aTexHeightArray[(a + 1L) % nLoopCount]) * fInvTexHeight; + fTexStop = (fTexHeightPos + aTexHeightArray[a]) * fInvTexHeight; + } + + impAddInBetweenFill(aEdgeRounding, aNext, aPolBB, fTexStart, fTexStop, bCreateNormals, bCreateTextureCoordinates); + } + + rFill.push_back(aBack); + } + else + { + if(bCreateNormals && bSmoothNormals && (nIndNext != a)) + { + impCreateInBetweenNormals(aNext, aPolBB, bSmoothHorizontalNormals); + impMixNormals(aPolB, aPolBB, 0.5); + } + } + } + + if(bCreateTextureCoordinates) + { + fTexStart = (fTexHeightPos + aTexHeightArray[a]) * fInvTexHeight; + fTexStop = fTexHeightPos * fInvTexHeight; + } + + impAddInBetweenFill(aEdgeRounding, aPolB, aPolA, fTexStart, fTexStop, bCreateNormals, bCreateTextureCoordinates); + } + + if(bCreateTextureCoordinates) + { + fTexHeightPos += aTexHeightArray[a]; + } + } + } + else + { + // no loop, but a single slice (1 == nNumSlices), create a filling from the single + // front plane + const Slice3D& rSlice(rSliceVector[0]); + basegfx::B3DPolyPolygon aFront(rSlice.getB3DPolyPolygon()); + + if(bCreateTextureCoordinates) + { + aFront = basegfx::tools::applyDefaultTextureCoordinatesParallel(aFront, aTexRangeFront); + } + + if(bCreateNormals) + { + basegfx::B3DVector aNormal(0.0, 0.0, -1.0); + + if(aFront.count()) + { + aNormal = -aFront.getB3DPolygon(0L).getNormal(); + } + + impSetNormal(aFront, aNormal); + } + + aFront.flip(); + rFill.push_back(aFront); + } + + if(bCreateTextureCoordinates) + { + aEdgeRounding.transformTextureCoordiantes(rTexTransform); + } + + for(a = 0L; a < aEdgeRounding.count(); a++) + { + rFill.push_back(basegfx::B3DPolyPolygon(aEdgeRounding.getB3DPolygon(a))); + } + } + } + + void createReducedOutlines( + const geometry::ViewInformation3D& rViewInformation, + const basegfx::B3DHomMatrix& rObjectTransform, + const basegfx::B3DPolygon& rLoopA, + const basegfx::B3DPolygon& rLoopB, + basegfx::B3DPolyPolygon& rTarget) + { + const sal_uInt32 nPointCount(rLoopA.count()); + + // with idetic polygons there are no outlines + if(rLoopA != rLoopB) + { + if(nPointCount && nPointCount == rLoopB.count()) + { + const basegfx::B3DHomMatrix aObjectTransform(rViewInformation.getObjectToView() * rObjectTransform); + const basegfx::B2DPolygon a2DLoopA(basegfx::tools::createB2DPolygonFromB3DPolygon(rLoopA, aObjectTransform)); + const basegfx::B2DPolygon a2DLoopB(basegfx::tools::createB2DPolygonFromB3DPolygon(rLoopB, aObjectTransform)); + const basegfx::B2DPoint a2DCenterA(a2DLoopA.getB2DRange().getCenter()); + const basegfx::B2DPoint a2DCenterB(a2DLoopB.getB2DRange().getCenter()); + + // without detectable Y-Axis there are no outlines + if(!a2DCenterA.equal(a2DCenterB)) + { + // search for outmost left and right inter-loop-edges which do not cut the loops + const basegfx::B2DPoint aCommonCenter(basegfx::average(a2DCenterA, a2DCenterB)); + const basegfx::B2DVector aAxisVector(a2DCenterA - a2DCenterB); + double fMaxLeft(0.0); + double fMaxRight(0.0); + sal_uInt32 nIndexLeft(0); + sal_uInt32 nIndexRight(0); + + for(sal_uInt32 a(0); a < nPointCount; a++) + { + const basegfx::B2DPoint aStart(a2DLoopA.getB2DPoint(a)); + const basegfx::B2DPoint aEnd(a2DLoopB.getB2DPoint(a)); + const basegfx::B2DPoint aMiddle(basegfx::average(aStart, aEnd)); + + if(!basegfx::tools::isInside(a2DLoopA, aMiddle)) + { + if(!basegfx::tools::isInside(a2DLoopB, aMiddle)) + { + if(!impHasCutWith(a2DLoopA, aStart, aEnd)) + { + if(!impHasCutWith(a2DLoopB, aStart, aEnd)) + { + const basegfx::B2DVector aCandidateVector(aMiddle - aCommonCenter); + const double fCross(aCandidateVector.cross(aAxisVector)); + const double fDistance(aCandidateVector.getLength()); + + if(fCross > 0.0) + { + if(fDistance > fMaxLeft) + { + fMaxLeft = fDistance; + nIndexLeft = a; + } + } + else if(fCross < 0.0) + { + if(fDistance > fMaxRight) + { + fMaxRight = fDistance; + nIndexRight = a; + } + } + } + } + } + } + } + + if(fMaxLeft != 0.0) + { + basegfx::B3DPolygon aToBeAdded; + aToBeAdded.append(rLoopA.getB3DPoint(nIndexLeft)); + aToBeAdded.append(rLoopB.getB3DPoint(nIndexLeft)); + rTarget.append(aToBeAdded); + } + + if(fMaxRight != 0.0) + { + basegfx::B3DPolygon aToBeAdded; + aToBeAdded.append(rLoopA.getB3DPoint(nIndexRight)); + aToBeAdded.append(rLoopB.getB3DPoint(nIndexRight)); + rTarget.append(aToBeAdded); + } + } + } + } + } + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/sdrextrudeprimitive3d.cxx b/drawinglayer/source/primitive3d/sdrextrudeprimitive3d.cxx new file mode 100644 index 000000000000..e9ef154c95f3 --- /dev/null +++ b/drawinglayer/source/primitive3d/sdrextrudeprimitive3d.cxx @@ -0,0 +1,537 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: sdrextrudeprimitive3d.cxx,v $ + * + * $Revision: 1.15 $ + * + * last change: $Author: aw $ $Date: 2008-06-26 16:21:48 $ + * + * 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/primitive3d/sdrextrudeprimitive3d.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b3dpolypolygontools.hxx> +#include <drawinglayer/primitive3d/sdrdecompositiontools3d.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> +#include <drawinglayer/geometry/viewinformation3d.hxx> +#include <drawinglayer/primitive3d/hittestprimitive3d.hxx> +#include <drawinglayer/attribute/sdrattribute.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + Primitive3DSequence SdrExtrudePrimitive3D::createLocalDecomposition(const geometry::ViewInformation3D& rViewInformation) const + { + Primitive3DSequence aRetval; + + // get slices + const Slice3DVector& rSliceVector = getSlices(); + + if(rSliceVector.size()) + { + sal_uInt32 a; + + // decide what to create + const ::com::sun::star::drawing::NormalsKind eNormalsKind(getSdr3DObjectAttribute().getNormalsKind()); + const bool bCreateNormals(::com::sun::star::drawing::NormalsKind_SPECIFIC == eNormalsKind); + const bool bCreateTextureCoordiantesX(::com::sun::star::drawing::TextureProjectionMode_OBJECTSPECIFIC == getSdr3DObjectAttribute().getTextureProjectionX()); + const bool bCreateTextureCoordiantesY(::com::sun::star::drawing::TextureProjectionMode_OBJECTSPECIFIC == getSdr3DObjectAttribute().getTextureProjectionY()); + double fRelativeTextureWidth(1.0); + basegfx::B2DHomMatrix aTexTransform; + + if(getSdrLFSAttribute().getFill() && (bCreateTextureCoordiantesX || bCreateTextureCoordiantesY)) + { + const basegfx::B2DPolygon aFirstPolygon(maCorrectedPolyPolygon.getB2DPolygon(0L)); + const double fFrontLength(basegfx::tools::getLength(aFirstPolygon)); + const double fFrontArea(basegfx::tools::getArea(aFirstPolygon)); + const double fSqrtFrontArea(sqrt(fFrontArea)); + fRelativeTextureWidth = basegfx::fTools::equalZero(fSqrtFrontArea) ? 1.0 : fFrontLength / fSqrtFrontArea; + fRelativeTextureWidth = (double)((sal_uInt32)(fRelativeTextureWidth - 0.5)); + + if(fRelativeTextureWidth < 1.0) + { + fRelativeTextureWidth = 1.0; + } + + aTexTransform.translate(-0.5, -0.5); + aTexTransform.scale(-1.0, -1.0); + aTexTransform.translate(0.5, 0.5); + aTexTransform.scale(fRelativeTextureWidth, 1.0); + } + + // create geometry + ::std::vector< basegfx::B3DPolyPolygon > aFill; + extractPlanesFromSlice(aFill, rSliceVector, + bCreateNormals, getSmoothHorizontalNormals(), getSmoothNormals(), getSmoothLids(), false, + 0.5, 0.6, bCreateTextureCoordiantesX || bCreateTextureCoordiantesY, aTexTransform); + + // get full range + const basegfx::B3DRange aRange(getRangeFrom3DGeometry(aFill)); + + // normal creation + if(getSdrLFSAttribute().getFill()) + { + if(::com::sun::star::drawing::NormalsKind_SPHERE == eNormalsKind) + { + applyNormalsKindSphereTo3DGeometry(aFill, aRange); + } + else if(::com::sun::star::drawing::NormalsKind_FLAT == eNormalsKind) + { + applyNormalsKindFlatTo3DGeometry(aFill); + } + + if(getSdr3DObjectAttribute().getNormalsInvert()) + { + applyNormalsInvertTo3DGeometry(aFill); + } + } + + // texture coordinates + if(getSdrLFSAttribute().getFill()) + { + applyTextureTo3DGeometry( + getSdr3DObjectAttribute().getTextureProjectionX(), + getSdr3DObjectAttribute().getTextureProjectionY(), + aFill, + aRange, + getTextureSize()); + } + + if(getSdrLFSAttribute().getFill()) + { + // add fill + aRetval = create3DPolyPolygonFillPrimitives( + aFill, + getTransform(), + getTextureSize(), + getSdr3DObjectAttribute(), + *getSdrLFSAttribute().getFill(), + getSdrLFSAttribute().getFillFloatTransGradient()); + } + else + { + // create simplified 3d hit test geometry + const attribute::SdrFillAttribute aSimplifiedFillAttribute(0.0, basegfx::BColor(), 0, 0, 0); + + aRetval = create3DPolyPolygonFillPrimitives( + aFill, + getTransform(), + getTextureSize(), + getSdr3DObjectAttribute(), + aSimplifiedFillAttribute, + 0); + + // encapsulate in HitTestPrimitive3D and add + const Primitive3DReference xRef(new HitTestPrimitive3D(aRetval)); + aRetval = Primitive3DSequence(&xRef, 1L); + } + + // add line + if(getSdrLFSAttribute().getLine()) + { + if(getSdr3DObjectAttribute().getReducedLineGeometry()) + { + // create geometric outlines with reduced line geometry for chart. + const basegfx::B3DPolyPolygon aVerLine(extractVerticalLinesFromSlice(rSliceVector)); + const sal_uInt32 nCount(aVerLine.count()); + basegfx::B3DPolyPolygon aReducedLoops; + basegfx::B3DPolyPolygon aNewLineGeometry; + + // sort out doubles (front and back planes when no edge rounding is done). Since + // this is a line geometry merged from PolyPolygons, loop over all Polygons + for(a = 0; a < nCount; a++) + { + const sal_uInt32 nReducedCount(aReducedLoops.count()); + const basegfx::B3DPolygon aCandidate(aVerLine.getB3DPolygon(a)); + bool bAdd(true); + + if(nReducedCount) + { + for(sal_uInt32 b(0); bAdd && b < nReducedCount; b++) + { + if(aCandidate == aReducedLoops.getB3DPolygon(b)) + { + bAdd = false; + } + } + } + + if(bAdd) + { + aReducedLoops.append(aCandidate); + } + } + + // from here work with reduced loops and reduced count without changing them + const sal_uInt32 nReducedCount(aReducedLoops.count()); + + if(nReducedCount > 1) + { + for(sal_uInt32 b(1); b < nReducedCount; b++) + { + // get loop pair + const basegfx::B3DPolygon aCandA(aReducedLoops.getB3DPolygon(b - 1)); + const basegfx::B3DPolygon aCandB(aReducedLoops.getB3DPolygon(b)); + + // for each loop pair create the connection edges + createReducedOutlines( + rViewInformation, + getTransform(), + aCandA, + aCandB, + aNewLineGeometry); + } + } + + // add reduced loops themselves + aNewLineGeometry.append(aReducedLoops); + + // to create vertical edges at non-C1/C2 steady loops, use maCorrectedPolyPolygon + // directly since the 3D Polygons do not suport this. + // + // Unfortunately there is no bezier polygon provided by the chart module; one reason is + // that the API for extrude wants a 3D polygon geometry (for historical reasons, i guess) + // and those have no beziers. Another reason is that he chart module uses self-created + // stuff to create the 2D geometry (in ShapeFactory::createPieSegment), but this geometry + // does not contain bezier infos, either. The only way which is possible for now is to 'detect' + // candidates for vertical edges of pie segments by looking for the angles in the polygon. + // + // This is all not very well designed ATM. Ideally, the ReducedLineGeometry is responsible + // for creating the outer geometry edges (createReducedOutlines), but for special edges + // like the vertical ones for pie center and both start/end, the incarnation with the + // knowledge about that it needs to create those and IS a pie segment -> in this case, + // the chart itself. + const sal_uInt32 nPolyCount(maCorrectedPolyPolygon.count()); + + for(sal_uInt32 c(0); c < nPolyCount; c++) + { + const basegfx::B2DPolygon aCandidate(maCorrectedPolyPolygon.getB2DPolygon(c)); + const sal_uInt32 nPointCount(aCandidate.count()); + + if(nPointCount > 2) + { + sal_uInt32 nIndexA(nPointCount); + sal_uInt32 nIndexB(nPointCount); + sal_uInt32 nIndexC(nPointCount); + + for(sal_uInt32 d(0); d < nPointCount; d++) + { + const sal_uInt32 nPrevInd((d + nPointCount - 1) % nPointCount); + const sal_uInt32 nNextInd((d + 1) % nPointCount); + const basegfx::B2DPoint aPoint(aCandidate.getB2DPoint(d)); + const basegfx::B2DVector aPrev(aCandidate.getB2DPoint(nPrevInd) - aPoint); + const basegfx::B2DVector aNext(aCandidate.getB2DPoint(nNextInd) - aPoint); + const double fAngle(aPrev.angle(aNext)); + + // take each angle which deviates more than 10% from going straight as + // special edge. This will detect the two outer edges of pie segments, + // but not always the center one (think about a near 180 degree pie) + if(F_PI - fabs(fAngle) > F_PI * 0.1) + { + if(nPointCount == nIndexA) + { + nIndexA = d; + } + else if(nPointCount == nIndexB) + { + nIndexB = d; + } + else if(nPointCount == nIndexC) + { + nIndexC = d; + d = nPointCount; + } + } + } + + const bool bIndexAUsed(nIndexA != nPointCount); + const bool bIndexBUsed(nIndexB != nPointCount); + bool bIndexCUsed(nIndexC != nPointCount); + + if(bIndexCUsed) + { + // already three special edges found, so the center one was already detected + // and does not need to be searched + } + else if(bIndexAUsed && bIndexBUsed) + { + // outer edges detected (they are approx. 90 degrees), but center one not. + // Look with the knowledge that it's in-between the two found ones + if(((nIndexA + 2) % nPointCount) == nIndexB) + { + nIndexC = (nIndexA + 1) % nPointCount; + } + else if(((nIndexA + nPointCount - 2) % nPointCount) == nIndexB) + { + nIndexC = (nIndexA + nPointCount - 1) % nPointCount; + } + + bIndexCUsed = (nIndexC != nPointCount); + } + + if(bIndexAUsed) + { + const basegfx::B2DPoint aPoint(aCandidate.getB2DPoint(nIndexA)); + const basegfx::B3DPoint aStart(aPoint.getX(), aPoint.getY(), 0.0); + const basegfx::B3DPoint aEnd(aPoint.getX(), aPoint.getY(), getDepth()); + basegfx::B3DPolygon aToBeAdded; + + aToBeAdded.append(aStart); + aToBeAdded.append(aEnd); + aNewLineGeometry.append(aToBeAdded); + } + + if(bIndexBUsed) + { + const basegfx::B2DPoint aPoint(aCandidate.getB2DPoint(nIndexB)); + const basegfx::B3DPoint aStart(aPoint.getX(), aPoint.getY(), 0.0); + const basegfx::B3DPoint aEnd(aPoint.getX(), aPoint.getY(), getDepth()); + basegfx::B3DPolygon aToBeAdded; + + aToBeAdded.append(aStart); + aToBeAdded.append(aEnd); + aNewLineGeometry.append(aToBeAdded); + } + + if(bIndexCUsed) + { + const basegfx::B2DPoint aPoint(aCandidate.getB2DPoint(nIndexC)); + const basegfx::B3DPoint aStart(aPoint.getX(), aPoint.getY(), 0.0); + const basegfx::B3DPoint aEnd(aPoint.getX(), aPoint.getY(), getDepth()); + basegfx::B3DPolygon aToBeAdded; + + aToBeAdded.append(aStart); + aToBeAdded.append(aEnd); + aNewLineGeometry.append(aToBeAdded); + } + } + } + + // append loops themselves + aNewLineGeometry.append(aReducedLoops); + + if(aNewLineGeometry.count()) + { + const Primitive3DSequence aLines(create3DPolyPolygonLinePrimitives(aNewLineGeometry, getTransform(), *getSdrLFSAttribute().getLine())); + appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aLines); + } + } + else + { + // extract line geometry from slices + const basegfx::B3DPolyPolygon aHorLine(extractHorizontalLinesFromSlice(rSliceVector, false)); + const basegfx::B3DPolyPolygon aVerLine(extractVerticalLinesFromSlice(rSliceVector)); + + // add horizontal lines + const Primitive3DSequence aHorLines(create3DPolyPolygonLinePrimitives(aHorLine, getTransform(), *getSdrLFSAttribute().getLine())); + appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aHorLines); + + // add vertical lines + const Primitive3DSequence aVerLines(create3DPolyPolygonLinePrimitives(aVerLine, getTransform(), *getSdrLFSAttribute().getLine())); + appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aVerLines); + } + } + + // add shadow + if(getSdrLFSAttribute().getShadow() && aRetval.hasElements()) + { + const Primitive3DSequence aShadow(createShadowPrimitive3D(aRetval, *getSdrLFSAttribute().getShadow(), getSdr3DObjectAttribute().getShadow3D())); + appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aShadow); + } + } + + return aRetval; + } + + void SdrExtrudePrimitive3D::impCreateSlices() + { + // prepare the polygon. No double points, correct orientations and a correct + // outmost polygon are needed + maCorrectedPolyPolygon = getPolyPolygon(); + maCorrectedPolyPolygon.removeDoublePoints(); + maCorrectedPolyPolygon = basegfx::tools::correctOrientations(maCorrectedPolyPolygon); + maCorrectedPolyPolygon = basegfx::tools::correctOutmostPolygon(maCorrectedPolyPolygon); + + // prepare slices as geometry + createExtrudeSlices(maSlices, maCorrectedPolyPolygon, getBackScale(), getDiagonal(), getDepth(), getCharacterMode(), getCloseFront(), getCloseBack()); + } + + const Slice3DVector& SdrExtrudePrimitive3D::getSlices() const + { + // This can be made dependent of getSdrLFSAttribute().getFill() and getSdrLFSAttribute().getLine() + // again when no longer geometry is needed for non-visible 3D objects as it is now for chart + if(getPolyPolygon().count() && !maSlices.size()) + { + ::osl::Mutex m_mutex; + const_cast< SdrExtrudePrimitive3D& >(*this).impCreateSlices(); + } + + return maSlices; + } + + SdrExtrudePrimitive3D::SdrExtrudePrimitive3D( + const basegfx::B3DHomMatrix& rTransform, + const basegfx::B2DVector& rTextureSize, + const attribute::SdrLineFillShadowAttribute& rSdrLFSAttribute, + const attribute::Sdr3DObjectAttribute& rSdr3DObjectAttribute, + const basegfx::B2DPolyPolygon& rPolyPolygon, + double fDepth, + double fDiagonal, + double fBackScale, + bool bSmoothNormals, + bool bSmoothHorizontalNormals, + bool bSmoothLids, + bool bCharacterMode, + bool bCloseFront, + bool bCloseBack) + : SdrPrimitive3D(rTransform, rTextureSize, rSdrLFSAttribute, rSdr3DObjectAttribute), + maCorrectedPolyPolygon(), + maSlices(), + maPolyPolygon(rPolyPolygon), + mfDepth(fDepth), + mfDiagonal(fDiagonal), + mfBackScale(fBackScale), + mpLastRLGViewInformation(0), + mbSmoothNormals(bSmoothNormals), + mbSmoothHorizontalNormals(bSmoothHorizontalNormals), + mbSmoothLids(bSmoothLids), + mbCharacterMode(bCharacterMode), + mbCloseFront(bCloseFront), + mbCloseBack(bCloseBack) + { + // make sure depth is positive + if(basegfx::fTools::lessOrEqual(getDepth(), 0.0)) + { + mfDepth = 0.0; + } + + // make sure the percentage value getDiagonal() is between 0.0 and 1.0 + if(basegfx::fTools::lessOrEqual(getDiagonal(), 0.0)) + { + mfDiagonal = 0.0; + } + else if(basegfx::fTools::moreOrEqual(getDiagonal(), 1.0)) + { + mfDiagonal = 1.0; + } + + // no close front/back when polygon is not closed + if(getPolyPolygon().count() && !getPolyPolygon().getB2DPolygon(0L).isClosed()) + { + mbCloseFront = mbCloseBack = false; + } + + // no edge rounding when not closing + if(!getCloseFront() && !getCloseBack()) + { + mfDiagonal = 0.0; + } + } + + SdrExtrudePrimitive3D::~SdrExtrudePrimitive3D() + { + if(mpLastRLGViewInformation) + { + delete mpLastRLGViewInformation; + } + } + + bool SdrExtrudePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(SdrPrimitive3D::operator==(rPrimitive)) + { + const SdrExtrudePrimitive3D& rCompare = static_cast< const SdrExtrudePrimitive3D& >(rPrimitive); + + return (getPolyPolygon() == rCompare.getPolyPolygon() + && getDepth() == rCompare.getDepth() + && getDiagonal() == rCompare.getDiagonal() + && getBackScale() == rCompare.getBackScale() + && getSmoothNormals() == rCompare.getSmoothNormals() + && getSmoothHorizontalNormals() == rCompare.getSmoothHorizontalNormals() + && getSmoothLids() == rCompare.getSmoothLids() + && getCharacterMode() == rCompare.getCharacterMode() + && getCloseFront() == rCompare.getCloseFront() + && getCloseBack() == rCompare.getCloseBack()); + } + + return false; + } + + basegfx::B3DRange SdrExtrudePrimitive3D::getB3DRange(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + // use defaut from sdrPrimitive3D which uses transformation expanded by line width/2 + // The parent implementation which uses the ranges of the decomposition would be more + // corrcet, but for historical reasons it is necessary to do the old method: To get + // the range of the non-transformed geometry and transform it then. This leads to different + // ranges where the new method is more correct, but the need to keep the old behaviour + // has priority here. + return get3DRangeFromSlices(getSlices()); + } + + Primitive3DSequence SdrExtrudePrimitive3D::get3DDecomposition(const geometry::ViewInformation3D& rViewInformation) const + { + if(getSdr3DObjectAttribute().getReducedLineGeometry()) + { + if(!mpLastRLGViewInformation || + (getLocalDecomposition().hasElements() + && *mpLastRLGViewInformation != rViewInformation)) + { + // conditions of last local decomposition with reduced lines have changed. Remember + // new one and clear current decompositiopn + ::osl::Mutex m_mutex; + SdrExtrudePrimitive3D* pThat = const_cast< SdrExtrudePrimitive3D* >(this); + pThat->setLocalDecomposition(Primitive3DSequence()); + delete pThat->mpLastRLGViewInformation; + pThat->mpLastRLGViewInformation = new geometry::ViewInformation3D(rViewInformation); + } + } + + // no test for buffering needed, call parent + return SdrPrimitive3D::get3DDecomposition(rViewInformation); + } + + // provide unique ID + ImplPrimitrive3DIDBlock(SdrExtrudePrimitive3D, PRIMITIVE3D_ID_SDREXTRUDEPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/sdrlatheprimitive3d.cxx b/drawinglayer/source/primitive3d/sdrlatheprimitive3d.cxx new file mode 100644 index 000000000000..33008e762c0a --- /dev/null +++ b/drawinglayer/source/primitive3d/sdrlatheprimitive3d.cxx @@ -0,0 +1,396 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: sdrlatheprimitive3d.cxx,v $ + * + * $Revision: 1.15 $ + * + * last change: $Author: aw $ $Date: 2008-06-24 15:31:08 $ + * + * 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/primitive3d/sdrlatheprimitive3d.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b3dpolypolygontools.hxx> +#include <drawinglayer/primitive3d/sdrdecompositiontools3d.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> +#include <drawinglayer/geometry/viewinformation3d.hxx> +#include <drawinglayer/primitive3d/hittestprimitive3d.hxx> +#include <drawinglayer/attribute/sdrattribute.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + Primitive3DSequence SdrLathePrimitive3D::createLocalDecomposition(const geometry::ViewInformation3D& rViewInformation) const + { + Primitive3DSequence aRetval; + + // get slices + const Slice3DVector& rSliceVector = getSlices(); + + if(rSliceVector.size()) + { + const bool bBackScale(!basegfx::fTools::equal(getBackScale(), 1.0)); + const bool bClosedRotation(!bBackScale && getHorizontalSegments() && basegfx::fTools::equal(getRotation(), F_2PI)); + sal_uInt32 a; + + // decide what to create + const ::com::sun::star::drawing::NormalsKind eNormalsKind(getSdr3DObjectAttribute().getNormalsKind()); + const bool bCreateNormals(::com::sun::star::drawing::NormalsKind_SPECIFIC == eNormalsKind); + const bool bCreateTextureCoordiantesX(::com::sun::star::drawing::TextureProjectionMode_OBJECTSPECIFIC == getSdr3DObjectAttribute().getTextureProjectionX()); + const bool bCreateTextureCoordiantesY(::com::sun::star::drawing::TextureProjectionMode_OBJECTSPECIFIC == getSdr3DObjectAttribute().getTextureProjectionY()); + basegfx::B2DHomMatrix aTexTransform; + + if(getSdrLFSAttribute().getFill() && (bCreateTextureCoordiantesX || bCreateTextureCoordiantesY)) + { + aTexTransform.set(0, 0, 0.0); + aTexTransform.set(0, 1, 1.0); + aTexTransform.set(1, 0, 1.0); + aTexTransform.set(1, 1, 0.0); + + aTexTransform.translate(0.0, -0.5); + aTexTransform.scale(1.0, -1.0); + aTexTransform.translate(0.0, 0.5); + } + + // create geometry + ::std::vector< basegfx::B3DPolyPolygon > aFill; + extractPlanesFromSlice(aFill, rSliceVector, + bCreateNormals, getSmoothHorizontalNormals(), getSmoothNormals(), getSmoothLids(), bClosedRotation, + 0.85, 0.6, bCreateTextureCoordiantesX || bCreateTextureCoordiantesY, aTexTransform); + + // get full range + const basegfx::B3DRange aRange(getRangeFrom3DGeometry(aFill)); + + // normal creation + if(getSdrLFSAttribute().getFill()) + { + if(::com::sun::star::drawing::NormalsKind_SPHERE == eNormalsKind) + { + applyNormalsKindSphereTo3DGeometry(aFill, aRange); + } + else if(::com::sun::star::drawing::NormalsKind_FLAT == eNormalsKind) + { + applyNormalsKindFlatTo3DGeometry(aFill); + } + + if(getSdr3DObjectAttribute().getNormalsInvert()) + { + applyNormalsInvertTo3DGeometry(aFill); + } + } + + // texture coordinates + if(getSdrLFSAttribute().getFill()) + { + applyTextureTo3DGeometry( + getSdr3DObjectAttribute().getTextureProjectionX(), + getSdr3DObjectAttribute().getTextureProjectionY(), + aFill, + aRange, + getTextureSize()); + } + + if(getSdrLFSAttribute().getFill()) + { + // add fill + aRetval = create3DPolyPolygonFillPrimitives( + aFill, + getTransform(), + getTextureSize(), + getSdr3DObjectAttribute(), + *getSdrLFSAttribute().getFill(), + getSdrLFSAttribute().getFillFloatTransGradient()); + } + else + { + // create simplified 3d hit test geometry + const attribute::SdrFillAttribute aSimplifiedFillAttribute(0.0, basegfx::BColor(), 0, 0, 0); + + aRetval = create3DPolyPolygonFillPrimitives( + aFill, + getTransform(), + getTextureSize(), + getSdr3DObjectAttribute(), + aSimplifiedFillAttribute, + 0); + + // encapsulate in HitTestPrimitive3D and add + const Primitive3DReference xRef(new HitTestPrimitive3D(aRetval)); + aRetval = Primitive3DSequence(&xRef, 1L); + } + + // add line + if(getSdrLFSAttribute().getLine()) + { + if(getSdr3DObjectAttribute().getReducedLineGeometry()) + { + // create geometric outlines with reduced line geometry for chart + const basegfx::B3DPolyPolygon aHorLine(extractHorizontalLinesFromSlice(rSliceVector, bClosedRotation)); + const sal_uInt32 nCount(aHorLine.count()); + basegfx::B3DPolyPolygon aNewLineGeometry; + + for(a = 1; a < nCount; a++) + { + // for each loop pair create the connection edges + createReducedOutlines( + rViewInformation, + getTransform(), + aHorLine.getB3DPolygon(a - 1), + aHorLine.getB3DPolygon(a), + aNewLineGeometry); + } + + for(a = 0; a < nCount; a++) + { + // filter hor lines for empty loops (those who have their defining point on the Y-Axis) + basegfx::B3DPolygon aCandidate(aHorLine.getB3DPolygon(a)); + aCandidate.removeDoublePoints(); + + if(aCandidate.count()) + { + aNewLineGeometry.append(aCandidate); + } + } + + if(aNewLineGeometry.count()) + { + const Primitive3DSequence aLines(create3DPolyPolygonLinePrimitives(aNewLineGeometry, getTransform(), *getSdrLFSAttribute().getLine())); + appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aLines); + } + } + else + { + // extract line geometry from slices + const basegfx::B3DPolyPolygon aHorLine(extractHorizontalLinesFromSlice(rSliceVector, bClosedRotation)); + const basegfx::B3DPolyPolygon aVerLine(extractVerticalLinesFromSlice(rSliceVector)); + + // add horizontal lines + const Primitive3DSequence aHorLines(create3DPolyPolygonLinePrimitives(aHorLine, getTransform(), *getSdrLFSAttribute().getLine())); + appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aHorLines); + + // add vertical lines + const Primitive3DSequence aVerLines(create3DPolyPolygonLinePrimitives(aVerLine, getTransform(), *getSdrLFSAttribute().getLine())); + appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aVerLines); + } + } + + // add shadow + if(getSdrLFSAttribute().getShadow() && aRetval.hasElements()) + { + const Primitive3DSequence aShadow(createShadowPrimitive3D(aRetval, *getSdrLFSAttribute().getShadow(), getSdr3DObjectAttribute().getShadow3D())); + appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aShadow); + } + } + + return aRetval; + } + + void SdrLathePrimitive3D::impCreateSlices() + { + // prepare the polygon. No double points, correct orientations and a correct + // outmost polygon are needed + maCorrectedPolyPolygon = basegfx::tools::adaptiveSubdivideByAngle(getPolyPolygon()); + maCorrectedPolyPolygon.removeDoublePoints(); + maCorrectedPolyPolygon = basegfx::tools::correctOrientations(maCorrectedPolyPolygon); + maCorrectedPolyPolygon = basegfx::tools::correctOutmostPolygon(maCorrectedPolyPolygon); + + // check edge count of first sub-polygon. If different, reSegment polyPolygon. This ensures + // that for polyPolygons, the subPolys 1..n only get reSegmented when polygon 0L is different + // at all (and not always) + const basegfx::B2DPolygon aSubCandidate(maCorrectedPolyPolygon.getB2DPolygon(0)); + const sal_uInt32 nSubEdgeCount(aSubCandidate.isClosed() ? aSubCandidate.count() : (aSubCandidate.count() ? aSubCandidate.count() - 1L : 0L)); + + if(nSubEdgeCount != getVerticalSegments()) + { + maCorrectedPolyPolygon = basegfx::tools::reSegmentPolyPolygon(maCorrectedPolyPolygon, getVerticalSegments()); + } + + // prepare slices as geometry + createLatheSlices(maSlices, maCorrectedPolyPolygon, getBackScale(), getDiagonal(), getRotation(), getHorizontalSegments(), getCharacterMode(), getCloseFront(), getCloseBack()); + } + + const Slice3DVector& SdrLathePrimitive3D::getSlices() const + { + // This can be made dependent of getSdrLFSAttribute().getFill() and getSdrLFSAttribute().getLine() + // again when no longer geometry is needed for non-visible 3D objects as it is now for chart + if(getPolyPolygon().count() && !maSlices.size()) + { + ::osl::Mutex m_mutex; + const_cast< SdrLathePrimitive3D& >(*this).impCreateSlices(); + } + + return maSlices; + } + + SdrLathePrimitive3D::SdrLathePrimitive3D( + const basegfx::B3DHomMatrix& rTransform, + const basegfx::B2DVector& rTextureSize, + const attribute::SdrLineFillShadowAttribute& rSdrLFSAttribute, + const attribute::Sdr3DObjectAttribute& rSdr3DObjectAttribute, + const basegfx::B2DPolyPolygon& rPolyPolygon, + sal_uInt32 nHorizontalSegments, + sal_uInt32 nVerticalSegments, + double fDiagonal, + double fBackScale, + double fRotation, + bool bSmoothNormals, + bool bSmoothHorizontalNormals, + bool bSmoothLids, + bool bCharacterMode, + bool bCloseFront, + bool bCloseBack) + : SdrPrimitive3D(rTransform, rTextureSize, rSdrLFSAttribute, rSdr3DObjectAttribute), + maCorrectedPolyPolygon(), + maSlices(), + maPolyPolygon(rPolyPolygon), + mnHorizontalSegments(nHorizontalSegments), + mnVerticalSegments(nVerticalSegments), + mfDiagonal(fDiagonal), + mfBackScale(fBackScale), + mfRotation(fRotation), + mpLastRLGViewInformation(0), + mbSmoothNormals(bSmoothNormals), + mbSmoothHorizontalNormals(bSmoothHorizontalNormals), + mbSmoothLids(bSmoothLids), + mbCharacterMode(bCharacterMode), + mbCloseFront(bCloseFront), + mbCloseBack(bCloseBack) + { + // make sure Rotation is positive + if(basegfx::fTools::lessOrEqual(getRotation(), 0.0)) + { + mfRotation = 0.0; + } + + // make sure the percentage value getDiagonal() is between 0.0 and 1.0 + if(basegfx::fTools::lessOrEqual(getDiagonal(), 0.0)) + { + mfDiagonal = 0.0; + } + else if(basegfx::fTools::moreOrEqual(getDiagonal(), 1.0)) + { + mfDiagonal = 1.0; + } + + // no close front/back when polygon is not closed + if(getPolyPolygon().count() && !getPolyPolygon().getB2DPolygon(0L).isClosed()) + { + mbCloseFront = mbCloseBack = false; + } + + // no edge rounding when not closing + if(!getCloseFront() && !getCloseBack()) + { + mfDiagonal = 0.0; + } + } + + SdrLathePrimitive3D::~SdrLathePrimitive3D() + { + if(mpLastRLGViewInformation) + { + delete mpLastRLGViewInformation; + } + } + + bool SdrLathePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(SdrPrimitive3D::operator==(rPrimitive)) + { + const SdrLathePrimitive3D& rCompare = static_cast< const SdrLathePrimitive3D& >(rPrimitive); + + return (getPolyPolygon() == rCompare.getPolyPolygon() + && getHorizontalSegments() == rCompare.getHorizontalSegments() + && getVerticalSegments() == rCompare.getVerticalSegments() + && getDiagonal() == rCompare.getDiagonal() + && getBackScale() == rCompare.getBackScale() + && getRotation() == rCompare.getRotation() + && getSmoothNormals() == rCompare.getSmoothNormals() + && getSmoothHorizontalNormals() == rCompare.getSmoothHorizontalNormals() + && getSmoothLids() == rCompare.getSmoothLids() + && getCharacterMode() == rCompare.getCharacterMode() + && getCloseFront() == rCompare.getCloseFront() + && getCloseBack() == rCompare.getCloseBack()); + } + + return false; + } + + basegfx::B3DRange SdrLathePrimitive3D::getB3DRange(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + // use defaut from sdrPrimitive3D which uses transformation expanded by line width/2 + // The parent implementation which uses the ranges of the decomposition would be more + // corrcet, but for historical reasons it is necessary to do the old method: To get + // the range of the non-transformed geometry and transform it then. This leads to different + // ranges where the new method is more correct, but the need to keep the old behaviour + // has priority here. + return get3DRangeFromSlices(getSlices()); + } + + Primitive3DSequence SdrLathePrimitive3D::get3DDecomposition(const geometry::ViewInformation3D& rViewInformation) const + { + if(getSdr3DObjectAttribute().getReducedLineGeometry()) + { + if(!mpLastRLGViewInformation || + (getLocalDecomposition().hasElements() + && *mpLastRLGViewInformation != rViewInformation)) + { + // conditions of last local decomposition with reduced lines have changed. Remember + // new one and clear current decompositiopn + ::osl::Mutex m_mutex; + SdrLathePrimitive3D* pThat = const_cast< SdrLathePrimitive3D* >(this); + pThat->setLocalDecomposition(Primitive3DSequence()); + delete pThat->mpLastRLGViewInformation; + pThat->mpLastRLGViewInformation = new geometry::ViewInformation3D(rViewInformation); + } + } + + // no test for buffering needed, call parent + return SdrPrimitive3D::get3DDecomposition(rViewInformation); + } + + // provide unique ID + ImplPrimitrive3DIDBlock(SdrLathePrimitive3D, PRIMITIVE3D_ID_SDRLATHEPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/sdrpolypolygonprimitive3d.cxx b/drawinglayer/source/primitive3d/sdrpolypolygonprimitive3d.cxx new file mode 100644 index 000000000000..a0813d3202a8 --- /dev/null +++ b/drawinglayer/source/primitive3d/sdrpolypolygonprimitive3d.cxx @@ -0,0 +1,206 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: sdrpolypolygonprimitive3d.cxx,v $ + * + * $Revision: 1.7 $ + * + * last change: $Author: aw $ $Date: 2008-06-10 09:29:33 $ + * + * 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/primitive3d/sdrpolypolygonprimitive3d.hxx> +#include <drawinglayer/primitive3d/sdrdecompositiontools3d.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> +#include <basegfx/polygon/b3dpolypolygontools.hxx> +#include <drawinglayer/attribute/sdrattribute.hxx> +#include <drawinglayer/primitive3d/hittestprimitive3d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + Primitive3DSequence SdrPolyPolygonPrimitive3D::createLocalDecomposition(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + Primitive3DSequence aRetval; + + if(getPolyPolygon3D().count()) + { + ::std::vector< basegfx::B3DPolyPolygon > aFill; + aFill.push_back(getPolyPolygon3D()); + + // get full range + const basegfx::B3DRange aRange(getRangeFrom3DGeometry(aFill)); + + // #i98295# normal creation + if(getSdrLFSAttribute().getFill()) + { + if(::com::sun::star::drawing::NormalsKind_SPHERE == getSdr3DObjectAttribute().getNormalsKind()) + { + applyNormalsKindSphereTo3DGeometry(aFill, aRange); + } + else if(::com::sun::star::drawing::NormalsKind_FLAT == getSdr3DObjectAttribute().getNormalsKind()) + { + applyNormalsKindFlatTo3DGeometry(aFill); + } + + if(getSdr3DObjectAttribute().getNormalsInvert()) + { + applyNormalsInvertTo3DGeometry(aFill); + } + } + + // #i98314# texture coordinates + if(getSdrLFSAttribute().getFill()) + { + applyTextureTo3DGeometry( + getSdr3DObjectAttribute().getTextureProjectionX(), + getSdr3DObjectAttribute().getTextureProjectionY(), + aFill, + aRange, + getTextureSize()); + } + + if(getSdrLFSAttribute().getFill()) + { + // add fill + aRetval = create3DPolyPolygonFillPrimitives( + aFill, + getTransform(), + getTextureSize(), + getSdr3DObjectAttribute(), + *getSdrLFSAttribute().getFill(), + getSdrLFSAttribute().getFillFloatTransGradient()); + } + else + { + // create simplified 3d hit test geometry + const attribute::SdrFillAttribute aSimplifiedFillAttribute(0.0, basegfx::BColor(), 0, 0, 0); + + aRetval = create3DPolyPolygonFillPrimitives( + aFill, + getTransform(), + getTextureSize(), + getSdr3DObjectAttribute(), + aSimplifiedFillAttribute, + 0); + + // encapsulate in HitTestPrimitive3D and add + const Primitive3DReference xRef(new HitTestPrimitive3D(aRetval)); + aRetval = Primitive3DSequence(&xRef, 1L); + } + + // add line + if(getSdrLFSAttribute().getLine()) + { + basegfx::B3DPolyPolygon aLine(getPolyPolygon3D()); + aLine.clearNormals(); + aLine.clearTextureCoordinates(); + const Primitive3DSequence aLines(create3DPolyPolygonLinePrimitives(aLine, getTransform(), *getSdrLFSAttribute().getLine())); + appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aLines); + } + + // add shadow + if(getSdrLFSAttribute().getShadow() && aRetval.hasElements()) + { + const Primitive3DSequence aShadow(createShadowPrimitive3D(aRetval, *getSdrLFSAttribute().getShadow(), getSdr3DObjectAttribute().getShadow3D())); + appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aShadow); + } + } + + return aRetval; + } + + SdrPolyPolygonPrimitive3D::SdrPolyPolygonPrimitive3D( + const basegfx::B3DPolyPolygon& rPolyPolygon3D, + const basegfx::B3DHomMatrix& rTransform, + const basegfx::B2DVector& rTextureSize, + const attribute::SdrLineFillShadowAttribute& rSdrLFSAttribute, + const attribute::Sdr3DObjectAttribute& rSdr3DObjectAttribute) + : SdrPrimitive3D(rTransform, rTextureSize, rSdrLFSAttribute, rSdr3DObjectAttribute), + maPolyPolygon3D(rPolyPolygon3D) + { + } + + bool SdrPolyPolygonPrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(SdrPrimitive3D::operator==(rPrimitive)) + { + const SdrPolyPolygonPrimitive3D& rCompare = static_cast< const SdrPolyPolygonPrimitive3D& >(rPrimitive); + + return (getPolyPolygon3D() == rCompare.getPolyPolygon3D()); + } + + return false; + } + + basegfx::B3DRange SdrPolyPolygonPrimitive3D::getB3DRange(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + // added this implementation to make sure that non-visible objects of this + // kind will deliver their expansion. If not implemented, it would never deliver + // the used space for non-visible objects since the decomposition for that + // case will be empty (what is correct). To support chart ATM which relies on + // non-visible objects occupying space in 3D, this method was added + basegfx::B3DRange aRetval; + + if(getPolyPolygon3D().count()) + { + aRetval = basegfx::tools::getRange(getPolyPolygon3D()); + aRetval.transform(getTransform()); + + if(getSdrLFSAttribute().getLine()) + { + const attribute::SdrLineAttribute& rLine = *getSdrLFSAttribute().getLine(); + + if(rLine.isVisible() && !basegfx::fTools::equalZero(rLine.getWidth())) + { + // expand by half LineWidth as tube radius + aRetval.grow(rLine.getWidth() / 2.0); + } + } + } + + return aRetval; + } + + // provide unique ID + ImplPrimitrive3DIDBlock(SdrPolyPolygonPrimitive3D, PRIMITIVE3D_ID_SDRPOLYPOLYGONPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/sdrprimitive3d.cxx b/drawinglayer/source/primitive3d/sdrprimitive3d.cxx new file mode 100644 index 000000000000..dc93d0c0f339 --- /dev/null +++ b/drawinglayer/source/primitive3d/sdrprimitive3d.cxx @@ -0,0 +1,133 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: sdrprimitive3d.cxx,v $ + * + * $Revision: 1.10 $ + * + * last change: $Author: aw $ $Date: 2008-06-24 15:31:08 $ + * + * 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/primitive3d/sdrprimitive3d.hxx> +#include <drawinglayer/attribute/sdrattribute.hxx> +#include <basegfx/polygon/b3dpolypolygontools.hxx> +#include <drawinglayer/primitive3d/sdrdecompositiontools3d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + basegfx::B3DRange SdrPrimitive3D::getStandard3DRange() const + { + basegfx::B3DRange aUnitRange(0.0, 0.0, 0.0, 1.0, 1.0, 1.0); + aUnitRange.transform(getTransform()); + + if(getSdrLFSAttribute().getLine()) + { + const attribute::SdrLineAttribute& rLine = *getSdrLFSAttribute().getLine(); + + if(rLine.isVisible() && !basegfx::fTools::equalZero(rLine.getWidth())) + { + // expand by hald LineWidth as tube radius + aUnitRange.grow(rLine.getWidth() / 2.0); + } + } + + return aUnitRange; + } + + basegfx::B3DRange SdrPrimitive3D::get3DRangeFromSlices(const Slice3DVector& rSlices) const + { + basegfx::B3DRange aRetval; + + if(rSlices.size()) + { + for(sal_uInt32 a(0L); a < rSlices.size(); a++) + { + aRetval.expand(basegfx::tools::getRange(rSlices[a].getB3DPolyPolygon())); + } + + aRetval.transform(getTransform()); + + if(getSdrLFSAttribute().getLine()) + { + const attribute::SdrLineAttribute& rLine = *getSdrLFSAttribute().getLine(); + + if(rLine.isVisible() && !basegfx::fTools::equalZero(rLine.getWidth())) + { + // expand by half LineWidth as tube radius + aRetval.grow(rLine.getWidth() / 2.0); + } + } + } + + return aRetval; + } + + SdrPrimitive3D::SdrPrimitive3D( + const basegfx::B3DHomMatrix& rTransform, + const basegfx::B2DVector& rTextureSize, + const attribute::SdrLineFillShadowAttribute& rSdrLFSAttribute, + const attribute::Sdr3DObjectAttribute& rSdr3DObjectAttribute) + : BasePrimitive3D(), + maTransform(rTransform), + maTextureSize(rTextureSize), + maSdrLFSAttribute(rSdrLFSAttribute), + maSdr3DObjectAttribute(rSdr3DObjectAttribute) + { + } + + bool SdrPrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(BasePrimitive3D::operator==(rPrimitive)) + { + const SdrPrimitive3D& rCompare = static_cast< const SdrPrimitive3D& >(rPrimitive); + + return (getTransform() == rCompare.getTransform() + && getTextureSize() == rCompare.getTextureSize() + && getSdrLFSAttribute() == rCompare.getSdrLFSAttribute() + && getSdr3DObjectAttribute() == rCompare.getSdr3DObjectAttribute()); + } + + return false; + } + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/sdrsphereprimitive3d.cxx b/drawinglayer/source/primitive3d/sdrsphereprimitive3d.cxx new file mode 100644 index 000000000000..e7149c611dd9 --- /dev/null +++ b/drawinglayer/source/primitive3d/sdrsphereprimitive3d.cxx @@ -0,0 +1,236 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: sdrsphereprimitive3d.cxx,v $ + * + * $Revision: 1.12 $ + * + * last change: $Author: aw $ $Date: 2008-06-10 09:29:33 $ + * + * 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/primitive3d/sdrsphereprimitive3d.hxx> +#include <basegfx/polygon/b3dpolypolygontools.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/polygon/b3dpolygon.hxx> +#include <drawinglayer/primitive3d/sdrdecompositiontools3d.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> +#include <drawinglayer/primitive3d/hittestprimitive3d.hxx> +#include <drawinglayer/attribute/sdrattribute.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + Primitive3DSequence SdrSpherePrimitive3D::createLocalDecomposition(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + Primitive3DSequence aRetval; + const basegfx::B3DRange aUnitRange(0.0, 0.0, 0.0, 1.0, 1.0, 1.0); + const bool bCreateNormals(::com::sun::star::drawing::NormalsKind_SPECIFIC == getSdr3DObjectAttribute().getNormalsKind() + || ::com::sun::star::drawing::NormalsKind_SPHERE == getSdr3DObjectAttribute().getNormalsKind()); + + // create unit geometry + basegfx::B3DPolyPolygon aFill(basegfx::tools::createSphereFillPolyPolygonFromB3DRange(aUnitRange, + getHorizontalSegments(), getVerticalSegments(), bCreateNormals)); + + // normal inversion + if(getSdrLFSAttribute().getFill() + && bCreateNormals + && getSdr3DObjectAttribute().getNormalsInvert() + && aFill.areNormalsUsed()) + { + // invert normals + aFill = basegfx::tools::invertNormals(aFill); + } + + // texture coordinates + if(getSdrLFSAttribute().getFill()) + { + // handle texture coordinates X + const bool bParallelX(::com::sun::star::drawing::TextureProjectionMode_PARALLEL == getSdr3DObjectAttribute().getTextureProjectionX()); + const bool bObjectSpecificX(::com::sun::star::drawing::TextureProjectionMode_OBJECTSPECIFIC == getSdr3DObjectAttribute().getTextureProjectionX()); + const bool bSphereX(::com::sun::star::drawing::TextureProjectionMode_SPHERE == getSdr3DObjectAttribute().getTextureProjectionX()); + + // handle texture coordinates Y + const bool bParallelY(::com::sun::star::drawing::TextureProjectionMode_PARALLEL == getSdr3DObjectAttribute().getTextureProjectionY()); + const bool bObjectSpecificY(::com::sun::star::drawing::TextureProjectionMode_OBJECTSPECIFIC == getSdr3DObjectAttribute().getTextureProjectionY()); + const bool bSphereY(::com::sun::star::drawing::TextureProjectionMode_SPHERE == getSdr3DObjectAttribute().getTextureProjectionY()); + + if(bParallelX || bParallelY) + { + // apply parallel texture coordinates in X and/or Y + const basegfx::B3DRange aRange(basegfx::tools::getRange(aFill)); + aFill = basegfx::tools::applyDefaultTextureCoordinatesParallel(aFill, aRange, bParallelX, bParallelY); + } + + if(bSphereX || bObjectSpecificX || bSphereY || bObjectSpecificY) + { + double fRelativeAngle(0.0); + + if(bObjectSpecificX) + { + // Since the texture coordinates are (for historical reasons) + // different from forced to sphere texture coordinates, + // create a old version from it by rotating to old state before applying + // the texture coordinates to emulate old behaviour + fRelativeAngle = F_2PI * ((double)((getHorizontalSegments() >> 1L) - 1L) / (double)getHorizontalSegments()); + basegfx::B3DHomMatrix aRot; + aRot.rotate(0.0, fRelativeAngle, 0.0); + aFill.transform(aRot); + } + + // apply spherical texture coordinates in X and/or Y + const basegfx::B3DRange aRange(basegfx::tools::getRange(aFill)); + const basegfx::B3DPoint aCenter(aRange.getCenter()); + aFill = basegfx::tools::applyDefaultTextureCoordinatesSphere(aFill, aCenter, + bSphereX || bObjectSpecificX, bSphereY || bObjectSpecificY); + + if(bObjectSpecificX) + { + // rotate back again + basegfx::B3DHomMatrix aRot; + aRot.rotate(0.0, -fRelativeAngle, 0.0); + aFill.transform(aRot); + } + } + + // transform texture coordinates to texture size + basegfx::B2DHomMatrix aTexMatrix; + aTexMatrix.scale(getTextureSize().getX(), getTextureSize().getY()); + aFill.transformTextureCoordiantes(aTexMatrix); + } + + // build vector of PolyPolygons + ::std::vector< basegfx::B3DPolyPolygon > a3DPolyPolygonVector; + + for(sal_uInt32 a(0L); a < aFill.count(); a++) + { + a3DPolyPolygonVector.push_back(basegfx::B3DPolyPolygon(aFill.getB3DPolygon(a))); + } + + if(getSdrLFSAttribute().getFill()) + { + // add fill + aRetval = create3DPolyPolygonFillPrimitives( + a3DPolyPolygonVector, + getTransform(), + getTextureSize(), + getSdr3DObjectAttribute(), + *getSdrLFSAttribute().getFill(), + getSdrLFSAttribute().getFillFloatTransGradient()); + } + else + { + // create simplified 3d hit test geometry + const attribute::SdrFillAttribute aSimplifiedFillAttribute(0.0, basegfx::BColor(), 0, 0, 0); + + aRetval = create3DPolyPolygonFillPrimitives( + a3DPolyPolygonVector, + getTransform(), + getTextureSize(), + getSdr3DObjectAttribute(), + aSimplifiedFillAttribute, + 0); + + // encapsulate in HitTestPrimitive3D and add + const Primitive3DReference xRef(new HitTestPrimitive3D(aRetval)); + aRetval = Primitive3DSequence(&xRef, 1L); + } + + // add line + if(getSdrLFSAttribute().getLine()) + { + basegfx::B3DPolyPolygon aSphere(basegfx::tools::createSpherePolyPolygonFromB3DRange(aUnitRange, getHorizontalSegments(), getVerticalSegments())); + const Primitive3DSequence aLines(create3DPolyPolygonLinePrimitives(aSphere, getTransform(), *getSdrLFSAttribute().getLine())); + appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aLines); + } + + // add shadow + if(getSdrLFSAttribute().getShadow() && aRetval.hasElements()) + { + const Primitive3DSequence aShadow(createShadowPrimitive3D(aRetval, *getSdrLFSAttribute().getShadow(), getSdr3DObjectAttribute().getShadow3D())); + appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aShadow); + } + + return aRetval; + } + + SdrSpherePrimitive3D::SdrSpherePrimitive3D( + const basegfx::B3DHomMatrix& rTransform, + const basegfx::B2DVector& rTextureSize, + const attribute::SdrLineFillShadowAttribute& rSdrLFSAttribute, + const attribute::Sdr3DObjectAttribute& rSdr3DObjectAttribute, + sal_uInt32 nHorizontalSegments, + sal_uInt32 nVerticalSegments) + : SdrPrimitive3D(rTransform, rTextureSize, rSdrLFSAttribute, rSdr3DObjectAttribute), + mnHorizontalSegments(nHorizontalSegments), + mnVerticalSegments(nVerticalSegments) + { + } + + bool SdrSpherePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(SdrPrimitive3D::operator==(rPrimitive)) + { + const SdrSpherePrimitive3D& rCompare = static_cast< const SdrSpherePrimitive3D& >(rPrimitive); + + return (getHorizontalSegments() == rCompare.getHorizontalSegments() + && getVerticalSegments() == rCompare.getVerticalSegments()); + } + + return false; + } + + basegfx::B3DRange SdrSpherePrimitive3D::getB3DRange(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + // use defaut from sdrPrimitive3D which uses transformation expanded by line width/2 + // The parent implementation which uses the ranges of the decomposition would be more + // corrcet, but for historical reasons it is necessary to do the old method: To get + // the range of the non-transformed geometry and transform it then. This leads to different + // ranges where the new method is more correct, but the need to keep the old behaviour + // has priority here. + return getStandard3DRange(); + } + + // provide unique ID + ImplPrimitrive3DIDBlock(SdrSpherePrimitive3D, PRIMITIVE3D_ID_SDRSPHEREPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/shadowprimitive3d.cxx b/drawinglayer/source/primitive3d/shadowprimitive3d.cxx new file mode 100644 index 000000000000..712bee65c7c3 --- /dev/null +++ b/drawinglayer/source/primitive3d/shadowprimitive3d.cxx @@ -0,0 +1,88 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: shadowprimitive3d.cxx,v $ + * + * $Revision: 1.8 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:21 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <drawinglayer/primitive3d/shadowprimitive3d.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + ShadowPrimitive3D::ShadowPrimitive3D( + const basegfx::B2DHomMatrix& rShadowTransform, + const basegfx::BColor& rShadowColor, + double fShadowTransparence, + bool bShadow3D, + const Primitive3DSequence& rChildren) + : GroupPrimitive3D(rChildren), + maShadowTransform(rShadowTransform), + maShadowColor(rShadowColor), + mfShadowTransparence(fShadowTransparence), + mbShadow3D(bShadow3D) + { + } + + bool ShadowPrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(GroupPrimitive3D::operator==(rPrimitive)) + { + const ShadowPrimitive3D& rCompare = (ShadowPrimitive3D&)rPrimitive; + + return (getShadowTransform() == rCompare.getShadowTransform() + && getShadowColor() == rCompare.getShadowColor() + && getShadowTransparence() == rCompare.getShadowTransparence() + && getShadow3D() == rCompare.getShadow3D()); + } + + return false; + } + + // provide unique ID + ImplPrimitrive3DIDBlock(ShadowPrimitive3D, PRIMITIVE3D_ID_SHADOWPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/textureprimitive3d.cxx b/drawinglayer/source/primitive3d/textureprimitive3d.cxx new file mode 100644 index 000000000000..3393346d0b2d --- /dev/null +++ b/drawinglayer/source/primitive3d/textureprimitive3d.cxx @@ -0,0 +1,237 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: textureprimitive3d.cxx,v $ + * + * $Revision: 1.9 $ + * + * last change: $Author: aw $ $Date: 2008-06-10 09:29:33 $ + * + * 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/primitive3d/textureprimitive3d.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + TexturePrimitive3D::TexturePrimitive3D( + const Primitive3DSequence& rChildren, + const basegfx::B2DVector& rTextureSize, + bool bModulate, bool bFilter) + : GroupPrimitive3D(rChildren), + maTextureSize(rTextureSize), + mbModulate(bModulate), + mbFilter(bFilter) + { + } + + bool TexturePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(GroupPrimitive3D::operator==(rPrimitive)) + { + const TexturePrimitive3D& rCompare = (TexturePrimitive3D&)rPrimitive; + + return (getModulate() == rCompare.getModulate() + && getFilter() == rCompare.getFilter()); + } + + return false; + } + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + Primitive3DSequence UnifiedAlphaTexturePrimitive3D::createLocalDecomposition(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + if(0.0 == getTransparence()) + { + // no transparence used, so just use content + return getChildren(); + } + else if(getTransparence() > 0.0 && getTransparence() < 1.0) + { + // create AlphaTexturePrimitive3D with fixed transparence as replacement + const basegfx::BColor aGray(getTransparence(), getTransparence(), getTransparence()); + const attribute::FillGradientAttribute aFillGradient(attribute::GRADIENTSTYLE_LINEAR, 0.0, 0.0, 0.0, 0.0, aGray, aGray, 1); + const Primitive3DReference xRef(new AlphaTexturePrimitive3D(aFillGradient, getChildren(), getTextureSize())); + return Primitive3DSequence(&xRef, 1L); + } + else + { + // completely transparent or invalid definition, add nothing + return Primitive3DSequence(); + } + } + + UnifiedAlphaTexturePrimitive3D::UnifiedAlphaTexturePrimitive3D( + double fTransparence, + const Primitive3DSequence& rChildren) + : TexturePrimitive3D(rChildren, basegfx::B2DVector(), false, false), + mfTransparence(fTransparence) + { + } + + bool UnifiedAlphaTexturePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(TexturePrimitive3D::operator==(rPrimitive)) + { + const UnifiedAlphaTexturePrimitive3D& rCompare = (UnifiedAlphaTexturePrimitive3D&)rPrimitive; + + return (getTransparence() == rCompare.getTransparence()); + } + + return false; + } + + // provide unique ID + ImplPrimitrive3DIDBlock(UnifiedAlphaTexturePrimitive3D, PRIMITIVE3D_ID_UNIFIEDALPHATEXTUREPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + Primitive3DSequence GradientTexturePrimitive3D::createLocalDecomposition(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + return getChildren(); + } + + GradientTexturePrimitive3D::GradientTexturePrimitive3D( + const attribute::FillGradientAttribute& rGradient, + const Primitive3DSequence& rChildren, + const basegfx::B2DVector& rTextureSize, + bool bModulate, + bool bFilter) + : TexturePrimitive3D(rChildren, rTextureSize, bModulate, bFilter), + maGradient(rGradient) + { + } + + bool GradientTexturePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(TexturePrimitive3D::operator==(rPrimitive)) + { + const GradientTexturePrimitive3D& rCompare = (GradientTexturePrimitive3D&)rPrimitive; + + return (getGradient() == rCompare.getGradient()); + } + + return false; + } + + // provide unique ID + ImplPrimitrive3DIDBlock(GradientTexturePrimitive3D, PRIMITIVE3D_ID_GRADIENTTEXTUREPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + Primitive3DSequence BitmapTexturePrimitive3D::createLocalDecomposition(const geometry::ViewInformation3D& /*rViewInformation*/) const + { + return getChildren(); + } + + BitmapTexturePrimitive3D::BitmapTexturePrimitive3D( + const attribute::FillBitmapAttribute& rBitmap, + const Primitive3DSequence& rChildren, + const basegfx::B2DVector& rTextureSize, + bool bModulate, bool bFilter) + : TexturePrimitive3D(rChildren, rTextureSize, bModulate, bFilter), + maBitmap(rBitmap) + { + } + + bool BitmapTexturePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(TexturePrimitive3D::operator==(rPrimitive)) + { + const BitmapTexturePrimitive3D& rCompare = (BitmapTexturePrimitive3D&)rPrimitive; + + return (getBitmap() == rCompare.getBitmap()); + } + + return false; + } + + // provide unique ID + ImplPrimitrive3DIDBlock(BitmapTexturePrimitive3D, PRIMITIVE3D_ID_BITMAPTEXTUREPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + AlphaTexturePrimitive3D::AlphaTexturePrimitive3D( + const attribute::FillGradientAttribute& rGradient, + const Primitive3DSequence& rChildren, + const basegfx::B2DVector& rTextureSize) + : GradientTexturePrimitive3D(rGradient, rChildren, rTextureSize, false, false) + { + } + + bool AlphaTexturePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + return (GradientTexturePrimitive3D::operator==(rPrimitive)); + } + + // provide unique ID + ImplPrimitrive3DIDBlock(AlphaTexturePrimitive3D, PRIMITIVE3D_ID_ALPHATEXTUREPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/primitive3d/transformprimitive3d.cxx b/drawinglayer/source/primitive3d/transformprimitive3d.cxx new file mode 100644 index 000000000000..cc96a9ecbc8d --- /dev/null +++ b/drawinglayer/source/primitive3d/transformprimitive3d.cxx @@ -0,0 +1,87 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: transformprimitive3d.cxx,v $ + * + * $Revision: 1.8 $ + * + * last change: $Author: aw $ $Date: 2008-06-10 09:29:33 $ + * + * 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/primitive3d/transformprimitive3d.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive3d + { + TransformPrimitive3D::TransformPrimitive3D( + const basegfx::B3DHomMatrix& rTransformation, + const Primitive3DSequence& rChildren) + : GroupPrimitive3D(rChildren), + maTransformation(rTransformation) + { + } + + bool TransformPrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const + { + if(GroupPrimitive3D::operator==(rPrimitive)) + { + const TransformPrimitive3D& rCompare = static_cast< const TransformPrimitive3D& >(rPrimitive); + + return (getTransformation() == rCompare.getTransformation()); + } + + return false; + } + + basegfx::B3DRange TransformPrimitive3D::getB3DRange(const geometry::ViewInformation3D& rViewInformation) const + { + basegfx::B3DRange aRetval(getB3DRangeFromPrimitive3DSequence(getChildren(), rViewInformation)); + aRetval.transform(getTransformation()); + return aRetval; + } + + // provide unique ID + ImplPrimitrive3DIDBlock(TransformPrimitive3D, PRIMITIVE3D_ID_TRANSFORMPRIMITIVE3D) + + } // end of namespace primitive3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/processor2d/baseprocessor2d.cxx b/drawinglayer/source/processor2d/baseprocessor2d.cxx new file mode 100644 index 000000000000..76f66b85c9fa --- /dev/null +++ b/drawinglayer/source/processor2d/baseprocessor2d.cxx @@ -0,0 +1,99 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: baseprocessor2d.cxx,v $ + * + * $Revision: 1.5 $ + * + * last change: $Author: aw $ $Date: 2008-06-24 15:31:08 $ + * + * 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/processor2d/baseprocessor2d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace processor2d + { + void BaseProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& /*rCandidate*/) + { + } + + BaseProcessor2D::BaseProcessor2D(const geometry::ViewInformation2D& rViewInformation) + : maViewInformation2D(rViewInformation) + { + } + + BaseProcessor2D::~BaseProcessor2D() + { + } + + void BaseProcessor2D::process(const primitive2d::Primitive2DSequence& rSource) + { + if(rSource.hasElements()) + { + const sal_Int32 nCount(rSource.getLength()); + + for(sal_Int32 a(0L); a < nCount; a++) + { + // get reference + const primitive2d::Primitive2DReference xReference(rSource[a]); + + if(xReference.is()) + { + // try to cast to BasePrimitive2D implementation + const primitive2d::BasePrimitive2D* pBasePrimitive = dynamic_cast< const primitive2d::BasePrimitive2D* >(xReference.get()); + + if(pBasePrimitive) + { + // it is a BasePrimitive2D implementation, use local processor + processBasePrimitive2D(*pBasePrimitive); + } + else + { + // unknown implementation, use UNO API call instead and process recursively + const uno::Sequence< beans::PropertyValue >& rViewParameters(getViewInformation2D().getViewInformationSequence()); + process(xReference->getDecomposition(rViewParameters)); + } + } + } + } + } + } // end of namespace processor2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/processor2d/canvasprocessor.cxx b/drawinglayer/source/processor2d/canvasprocessor.cxx new file mode 100644 index 000000000000..a60162de6ee0 --- /dev/null +++ b/drawinglayer/source/processor2d/canvasprocessor.cxx @@ -0,0 +1,2226 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: canvasprocessor.cxx,v $ + * + * $Revision: 1.8 $ + * + * last change: $Author: aw $ $Date: 2008-07-21 17:41:18 $ + * + * 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/processor2d/canvasprocessor.hxx> +#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> +#include <drawinglayer/primitive2d/polygonprimitive2d.hxx> +#include <com/sun/star/rendering/XCanvas.hpp> +#include <vcl/canvastools.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> +#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx> +#include <drawinglayer/primitive2d/transformprimitive2d.hxx> +#include <canvas/canvastools.hxx> +#include <svtools/ctloptions.hxx> +#include <vcl/svapp.hxx> +#include <drawinglayer/primitive2d/maskprimitive2d.hxx> +#include <basegfx/polygon/b2dpolygonclipper.hxx> +#include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx> +#include <drawinglayer/primitive2d/metafileprimitive2d.hxx> +#include <cppcanvas/basegfxfactory.hxx> +#include <com/sun/star/rendering/XBitmapCanvas.hpp> +#include <cppcanvas/vclfactory.hxx> +#include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx> +#include <drawinglayer/primitive2d/textprimitive2d.hxx> +#include <com/sun/star/rendering/TextDirection.hpp> +#include <vclhelperbitmaptransform.hxx> +#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <drawinglayer/primitive2d/alphaprimitive2d.hxx> +#include <basegfx/tuple/b2i64tuple.hxx> +#include <basegfx/range/b2irange.hxx> +#include <com/sun/star/rendering/XIntegerReadOnlyBitmap.hpp> +#include <com/sun/star/rendering/CompositeOperation.hpp> +#include <com/sun/star/rendering/StrokeAttributes.hpp> +#include <com/sun/star/rendering/PathJoinType.hpp> +#include <drawinglayer/primitive2d/fillbitmapprimitive2d.hxx> +#include <com/sun/star/rendering/TexturingMode.hpp> +#include <drawinglayer/primitive2d/unifiedalphaprimitive2d.hxx> +#include <vclhelperbufferdevice.hxx> +#include <drawinglayer/primitive2d/chartprimitive2d.hxx> +#include <helperchartrenderer.hxx> +#include <drawinglayer/primitive2d/wrongspellprimitive2d.hxx> +#include <helperwrongspellrenderer.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// +// AW: Adding the canvas example from THB here to extract stuff later +/* + // TODO(Q3): share impCreateEmptyBitmapWithPattern() and other + // helper methods with vclprocessor.cxx + Bitmap impCreateEmptyBitmapWithPattern(Bitmap aSource, const Size& aTargetSizePixel) + { + Bitmap aRetval; + BitmapReadAccess* pReadAccess = aSource.AcquireReadAccess(); + + if(pReadAccess) + { + if(aSource.GetBitCount() <= 8) + { + BitmapPalette aPalette(pReadAccess->GetPalette()); + aRetval = Bitmap(aTargetSizePixel, aSource.GetBitCount(), &aPalette); + } + else + { + aRetval = Bitmap(aTargetSizePixel, aSource.GetBitCount()); + } + + delete pReadAccess; + } + + return aRetval; + } + + Bitmap impModifyBitmap(const basegfx::BColorModifier& rModifier, const Bitmap& rSource) + { + Bitmap aRetval(rSource); + + switch(rModifier.getMode()) + { + case basegfx::BCOLORMODIFYMODE_REPLACE : + { + aRetval = impCreateEmptyBitmapWithPattern(aRetval, Size(1L, 1L)); + aRetval.Erase(Color(rModifier.getBColor())); + break; + } + + default : // BCOLORMODIFYMODE_INTERPOLATE, BCOLORMODIFYMODE_GRAY, BCOLORMODIFYMODE_BLACKANDWHITE + { + BitmapWriteAccess* pContent = aRetval.AcquireWriteAccess(); + + if(pContent) + { + for(sal_uInt32 y(0L); y < (sal_uInt32)pContent->Height(); y++) + { + for(sal_uInt32 x(0L); x < (sal_uInt32)pContent->Width(); x++) + { + const Color aColor = pContent->GetPixel(y, x); + const basegfx::BColor aBColor(rModifier.getModifiedColor(aColor.getBColor())); + pContent->SetPixel(y, x, BitmapColor(Color(aBColor))); + } + } + + delete pContent; + } + + break; + } + } + + return aRetval; + } + + Bitmap impModifyBitmap(const basegfx::BColorModifierStack& rBColorModifierStack, const Bitmap& rSource) + { + Bitmap aRetval(rSource); + + for(sal_uInt32 a(rBColorModifierStack.count()); a; ) + { + const basegfx::BColorModifier& rModifier = rBColorModifierStack.getBColorModifier(--a); + aRetval = impModifyBitmap(rModifier, aRetval); + } + + return aRetval; + } + + sal_uInt32 impCalcGradientSteps(sal_uInt32 nSteps, const basegfx::B2DRange& rRange, sal_uInt32 nMaxDist) + { + if(nSteps == 0L) + nSteps = (sal_uInt32)(rRange.getWidth() + rRange.getHeight()) / 8; + + if(nSteps < 2L) + { + nSteps = 2L; + } + + if(nSteps > nMaxDist) + { + nSteps = nMaxDist; + } + + return nSteps; + } + + void canvasProcessor::impDrawGradientSimple( + const basegfx::B2DPolyPolygon& rTargetForm, + const ::std::vector< basegfx::B2DHomMatrix >& rMatrices, + const ::std::vector< basegfx::BColor >& rColors, + const basegfx::B2DPolygon& rUnitPolygon) + { + uno::Reference< rendering::XPolyPolygon2D > xPoly( + basegfx::unotools::xPolyPolygonFromB2DPolygon( + mxCanvas->getDevice(), + rUnitPolygon)); + uno::Reference< rendering::XPolyPolygon2D > xTargetPoly( + basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + mxCanvas->getDevice(), + rTargetForm)); + + for(sal_uInt32 a(0L); a < rColors.size(); a++) + { + // set correct color + const basegfx::BColor aFillColor(rColors[a]); + + maRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence( + mxCanvas->getDevice(), + aFillColor); + + if(a) + { + if(a - 1L < rMatrices.size()) + { + canvas::tools::setRenderStateTransform( maRenderState, + rMatrices[a - 1L] ); + mxCanvas->fillPolyPolygon(xPoly,maViewState,maRenderState); + } + } + else + { + canvas::tools::setRenderStateTransform( maRenderState, + basegfx::B2DHomMatrix() ); + mxCanvas->fillPolyPolygon(xTargetPoly,maViewState,maRenderState); + } + } + } + + void canvasProcessor::impDrawGradientComplex( + const basegfx::B2DPolyPolygon& rTargetForm, + const ::std::vector< basegfx::B2DHomMatrix >& rMatrices, + const ::std::vector< basegfx::BColor >& rColors, + const basegfx::B2DPolygon& rUnitPolygon) + { + uno::Reference< rendering::XPolyPolygon2D > xPoly( + basegfx::unotools::xPolyPolygonFromB2DPolygon( + mxCanvas->getDevice(), + rUnitPolygon)); + uno::Reference< rendering::XPolyPolygon2D > xTargetPoly( + basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + mxCanvas->getDevice(), + rTargetForm)); + + maRenderState.Clip = xTargetPoly; + + // draw gradient PolyPolygons + for(std::size_t a = 0L; a < rMatrices.size(); a++) + { + // set correct color + if(rColors.size() > a) + { + const basegfx::BColor aFillColor(rColors[a]); + + maRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence( + mxCanvas->getDevice(), + aFillColor); + } + + canvas::tools::setRenderStateTransform( maRenderState, + rMatrices[a] ); + + if(a) + mxCanvas->fillPolyPolygon(xPoly,maViewState,maRenderState); + else + mxCanvas->fillPolyPolygon(xTargetPoly,maViewState,maRenderState); + } + + maRenderState.Clip.clear(); + } + + void canvasProcessor::impDrawGradient( + const basegfx::B2DPolyPolygon& rTargetForm, + ::drawinglayer::primitive::GradientStyle eGradientStyle, + sal_uInt32 nSteps, + const basegfx::BColor& rStart, + const basegfx::BColor& rEnd, + double fBorder, double fAngle, double fOffsetX, double fOffsetY, bool bSimple) + { + fprintf(stderr,"impDrawGradient\n"); + + basegfx::B2DPolyPolygon aTmp(rTargetForm); + aTmp.transform( maWorldToView ); + const basegfx::B2DRange aOutlineRangePixel(basegfx::tools::getRange(aTmp)); + const basegfx::B2DRange aOutlineRange(basegfx::tools::getRange(rTargetForm)); + + fprintf(stderr,"impDrawGradient: #%d\n",nSteps); + + if( // step count is infinite, can use native canvas + // gradients here + nSteps == 0 || + // step count is sufficiently high, such that no + // discernible difference should be visible. + nSteps > 64 ) + { + uno::Reference< rendering::XParametricPolyPolygon2DFactory > xFactory( + mxCanvas->getDevice()->getParametricPolyPolygonFactory() ); + + if( xFactory.is() ) + { + fprintf(stderr,"native gradient #1\n"); + + basegfx::B2DHomMatrix aTextureTransformation; + rendering::Texture aTexture; + + aTexture.RepeatModeX = rendering::TexturingMode::CLAMP; + aTexture.RepeatModeY = rendering::TexturingMode::CLAMP; + aTexture.Alpha = 1.0; + + + // setup start/end color values + // ---------------------------- + + const uno::Sequence< double > aStartColor( + basegfx::unotools::colorToDoubleSequence( mxCanvas->getDevice(), + rStart )); + const uno::Sequence< double > aEndColor( + basegfx::unotools::colorToDoubleSequence( mxCanvas->getDevice(), + rEnd )); + + // Setup texture transformation + // ---------------------------- + + const basegfx::B2DRange& rBounds( + basegfx::tools::getRange( rTargetForm )); + + // setup rotation angle. VCL rotates + // counter-clockwise, while canvas transformation + // rotates clockwise + //fAngle = -fAngle; + + switch(eGradientStyle) + { + case ::drawinglayer::primitive::GRADIENTSTYLE_LINEAR: + // FALLTHROUGH intended + case ::drawinglayer::primitive::GRADIENTSTYLE_AXIAL: + { + // standard orientation for VCL linear + // gradient is vertical, thus, rotate 90 + // degrees + fAngle += M_PI/2.0; + + // shrink texture, to account for border + // (only in x direction, linear gradient + // is constant in y direction, anyway) + aTextureTransformation.scale( + basegfx::pruneScaleValue(1.0 - fBorder), + 1.0 ); + + double fBorderX(0.0); + + // determine type of gradient (and necessary + // transformation matrix, should it be emulated by a + // generic gradient) + switch(eGradientStyle) + { + case ::drawinglayer::primitive::GRADIENTSTYLE_LINEAR: + // linear gradients don't respect + // offsets (they are implicitely + // assumed to be 50%). linear + // gradients don't have border on + // both sides, only on the + // startColor side. Gradient is + // invariant in y direction: leave + // y offset alone. + fBorderX = fBorder; + aTexture.Gradient = xFactory->createLinearHorizontalGradient( aStartColor, + aEndColor ); + break; + + case ::drawinglayer::primitive::GRADIENTSTYLE_AXIAL: + // axial gradients have border on + // both sides. Gradient is + // invariant in y direction: leave + // y offset alone. + fBorderX = fBorder * .5; + aTexture.Gradient = xFactory->createAxialHorizontalGradient( aStartColor, + aEndColor ); + break; + } + + // apply border offset values + aTextureTransformation.translate( fBorderX, + 0.0 ); + + // rotate texture according to gradient rotation + aTextureTransformation.translate( -0.5, -0.5 ); + aTextureTransformation.rotate( fAngle ); + + // to let the first strip of a rotated + // gradient start at the _edge_ of the + // bound rect (and not, due to rotation, + // slightly inside), slightly enlarge the + // gradient: + // + // y/2 sin(alpha) + x/2 cos(alpha) + // + // (values to change are not actual + // gradient scales, but original bound + // rect dimensions. Since we still want + // the border setting to apply after that, + // we multiply with that as above for + // nScaleX) + const double nScale( + basegfx::pruneScaleValue( + fabs( rBounds.getHeight()*sin(fAngle) ) + + fabs( rBounds.getWidth()*cos(fAngle) ))); + + aTextureTransformation.scale( nScale, nScale ); + + // translate back origin to center of + // primitive + aTextureTransformation.translate( 0.5*rBounds.getWidth(), + 0.5*rBounds.getHeight() ); + break; + } + + case ::drawinglayer::primitive::GRADIENTSTYLE_RADIAL: + // FALLTHROUGH intended + case ::drawinglayer::primitive::GRADIENTSTYLE_ELLIPTICAL: + // FALLTHROUGH intended + case ::drawinglayer::primitive::GRADIENTSTYLE_SQUARE: + // FALLTHROUGH intended + case ::drawinglayer::primitive::GRADIENTSTYLE_RECT: + { + fprintf(stderr,"native gradient #2\n"); + + // determine scale factors for the gradient (must + // be scaled up from [0,1]x[0,1] rect to object + // bounds). Will potentially changed in switch + // statement below. + // Respect border value, while doing so, the VCL + // gradient's border will effectively shrink the + // resulting gradient. + double nScaleX( rBounds.getWidth() * (1.0 - fBorder) ); + double nScaleY( rBounds.getHeight()* (1.0 - fBorder) ); + + // determine offset values. Since the + // border is divided half-by-half to both + // sides of the gradient, divide + // translation offset by an additional + // factor of 2. Also respect offset here, + // but since VCL gradients have their + // center at [0,0] for zero offset, but + // canvas gradients have their top, left + // edge aligned with the primitive, and + // offset of 50% effectively must yield + // zero shift. Both values will + // potentially be adapted in switch + // statement below. + double nOffsetX( rBounds.getWidth() * + (2.0 * fOffsetX - 1.0 + fBorder)*.5 ); + double nOffsetY( rBounds.getHeight() * + (2.0 * fOffsetY - 1.0 + fBorder)*.5 ); + + // determine type of gradient (and necessary + // transformation matrix, should it be emulated by a + // generic gradient) + switch(eGradientStyle) + { + case ::drawinglayer::primitive::GRADIENTSTYLE_RADIAL: + { + // create isotrophic scaling + if( nScaleX > nScaleY ) + { + nOffsetY -= (nScaleX - nScaleY) * 0.5; + nScaleY = nScaleX; + } + else + { + nOffsetX -= (nScaleY - nScaleX) * 0.5; + nScaleX = nScaleY; + } + + // enlarge gradient to match bound rect diagonal + aTextureTransformation.translate( -0.5, -0.5 ); + const double nScale( hypot(rBounds.getWidth(), + rBounds.getHeight()) / nScaleX ); + aTextureTransformation.scale( nScale, nScale ); + aTextureTransformation.translate( 0.5, 0.5 ); + + aTexture.Gradient = xFactory->createEllipticalGradient( + aEndColor, + aStartColor, + cssgeom::RealRectangle2D(0.0,0.0, + 1.0,1.0) ); + } + break; + + case ::drawinglayer::primitive::GRADIENTSTYLE_ELLIPTICAL: + { + // enlarge gradient slightly + aTextureTransformation.translate( -0.5, -0.5 ); + const double nSqrt2( sqrt(2.0) ); + aTextureTransformation.scale( nSqrt2,nSqrt2 ); + aTextureTransformation.translate( 0.5, 0.5 ); + + aTexture.Gradient = xFactory->createEllipticalGradient( + aEndColor, + aStartColor, + cssgeom::RealRectangle2D( rBounds.getMinX(), + rBounds.getMinY(), + rBounds.getMaxX(), + rBounds.getMaxY() )); + } + break; + + case ::drawinglayer::primitive::GRADIENTSTYLE_SQUARE: + { + // create isotrophic scaling + if( nScaleX > nScaleY ) + { + nOffsetY -= (nScaleX - nScaleY) * 0.5; + nScaleY = nScaleX; + } + else + { + nOffsetX -= (nScaleY - nScaleX) * 0.5; + nScaleX = nScaleY; + } + + aTexture.Gradient = xFactory->createRectangularGradient( + aEndColor, + aStartColor, + cssgeom::RealRectangle2D(0.0,0.0, + 1.0,1.0)); + } + break; + + case ::drawinglayer::primitive::GRADIENTSTYLE_RECT: + { + aTexture.Gradient = xFactory->createRectangularGradient( + aEndColor, + aStartColor, + cssgeom::RealRectangle2D( rBounds.getMinX(), + rBounds.getMinY(), + rBounds.getMaxX(), + rBounds.getMaxY() )); + } + break; + } + + nScaleX = basegfx::pruneScaleValue( nScaleX ); + nScaleY = basegfx::pruneScaleValue( nScaleY ); + + aTextureTransformation.scale( nScaleX, nScaleY ); + + // rotate texture according to gradient rotation + aTextureTransformation.translate( -0.5*nScaleX, -0.5*nScaleY ); + aTextureTransformation.rotate( fAngle ); + aTextureTransformation.translate( 0.5*nScaleX, 0.5*nScaleY ); + + aTextureTransformation.translate( nOffsetX, nOffsetY ); + } + break; + + default: + OSL_ENSURE( false, + "canvasProcessor::impDrawGradient(): Unexpected gradient type" ); + break; + } + + // As the texture coordinate space is relative to + // the polygon coordinate space (NOT to the + // polygon itself), move gradient to the start of + // the actual polygon. If we skip this, the + // gradient will always display at the origin, and + // not within the polygon bound (which might be + // miles away from the origin). + aTextureTransformation.translate( rBounds.getMinX(), + rBounds.getMinY() ); + + basegfx::unotools::affineMatrixFromHomMatrix( aTexture.AffineTransform, + aTextureTransformation ); + uno::Sequence< rendering::Texture > aSeq(1); + aSeq[0] = aTexture; + + mxCanvas->fillTexturedPolyPolygon( + basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + mxCanvas->getDevice(), + rTargetForm), + maViewState, + maRenderState, + aSeq ); + + // done, using native gradients + return; + } + } + else + { + // make sure steps is not too high/low + nSteps = impCalcGradientSteps(nSteps, + aOutlineRangePixel, + sal_uInt32((rStart.getMaximumDistance(rEnd) * 127.5) + 0.5)); + + + ::std::vector< basegfx::B2DHomMatrix > aMatrices; + ::std::vector< basegfx::BColor > aColors; + basegfx::B2DPolygon aUnitPolygon; + + if( drawinglayer::primitive::GRADIENTSTYLE_RADIAL == eGradientStyle || + drawinglayer::primitive::GRADIENTSTYLE_ELLIPTICAL == eGradientStyle) + { + const basegfx::B2DPoint aCircleCenter(0.5, 0.5); + aUnitPolygon = basegfx::tools::createPolygonFromEllipse(aCircleCenter, 0.5, 0.5); + aUnitPolygon = basegfx::tools::adaptiveSubdivideByAngle(aUnitPolygon); + } + else + { + aUnitPolygon = basegfx::tools::createPolygonFromRect( + basegfx::B2DRange(0.0, 0.0, 1.0, 1.0)); + } + + // create geometries + switch(eGradientStyle) + { + case ::drawinglayer::primitive::GRADIENTSTYLE_LINEAR: + { + ::drawinglayer::primitive::geoTexSvxGradientLinear aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fAngle); + aGradient.appendTransformations(aMatrices); + aGradient.appendColors(aColors); + break; + } + case ::drawinglayer::primitive::GRADIENTSTYLE_AXIAL: + { + ::drawinglayer::primitive::geoTexSvxGradientAxial aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fAngle); + aGradient.appendTransformations(aMatrices); + aGradient.appendColors(aColors); + break; + } + case ::drawinglayer::primitive::GRADIENTSTYLE_RADIAL: + { + ::drawinglayer::primitive::geoTexSvxGradientRadial aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fOffsetX, fOffsetY); + aGradient.appendTransformations(aMatrices); + aGradient.appendColors(aColors); + break; + } + case ::drawinglayer::primitive::GRADIENTSTYLE_ELLIPTICAL: + { + ::drawinglayer::primitive::geoTexSvxGradientElliptical aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fOffsetX, fOffsetX, fAngle); + aGradient.appendTransformations(aMatrices); + aGradient.appendColors(aColors); + break; + } + case ::drawinglayer::primitive::GRADIENTSTYLE_SQUARE: + { + ::drawinglayer::primitive::geoTexSvxGradientSquare aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fOffsetX, fOffsetX, fAngle); + aGradient.appendTransformations(aMatrices); + aGradient.appendColors(aColors); + break; + } + case ::drawinglayer::primitive::GRADIENTSTYLE_RECT: + { + ::drawinglayer::primitive::geoTexSvxGradientRect aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fOffsetX, fOffsetX, fAngle); + aGradient.appendTransformations(aMatrices); + aGradient.appendColors(aColors); + break; + } + } + + // paint them with mask using the XOR method + if(aMatrices.size()) + { + if(bSimple) + { + impDrawGradientSimple(rTargetForm, aMatrices, aColors, aUnitPolygon); + } + else + { + impDrawGradientComplex(rTargetForm, aMatrices, aColors, aUnitPolygon); + } + } + } + } + + + ////////////////////////////////////////////////////////////////////////////// + // rendering support + + // directdraw of text simple portion + void canvasProcessor::impRender_STXP(const textSimplePortionPrimitive& rTextCandidate) + { + const fontAttributes& rFontAttrs( rTextCandidate.getFontAttributes() ); + rendering::FontRequest aFontRequest; + + aFontRequest.FontDescription.FamilyName = rFontAttrs.maFamilyName; + aFontRequest.FontDescription.StyleName = rFontAttrs.maStyleName; + aFontRequest.FontDescription.IsSymbolFont = rFontAttrs.mbSymbol ? util::TriState_YES : util::TriState_NO; + aFontRequest.FontDescription.IsVertical = rFontAttrs.mbVertical ? util::TriState_YES : util::TriState_NO; + + // TODO(F2): improve vclenum->panose conversion + aFontRequest.FontDescription.FontDescription.Weight = + rFontAttrs.mnWeight; + aFontRequest.FontDescription.FontDescription.Letterform = + rFontAttrs.mbItalic ? 9 : 0; + + // font matrix should only be used for glyph rotations etc. + css::geometry::Matrix2D aFontMatrix; + canvas::tools::setIdentityMatrix2D( aFontMatrix ); + + uno::Reference<rendering::XCanvasFont> xFont( + mxCanvas->createFont( aFontRequest, + uno::Sequence< beans::PropertyValue >(), + aFontMatrix )); + + if( !xFont.is() ) + return; + + uno::Reference<rendering::XTextLayout> xLayout( + xFont->createTextLayout( + rendering::StringContext( rTextCandidate.getText(), + 0, + rTextCandidate.getText().Len() ), + // TODO(F3): Is this sufficient? + rendering::TextDirection::WEAK_LEFT_TO_RIGHT, + 0 )); + if( !xLayout.is() ) + return; + + xLayout->applyLogicalAdvancements( + uno::Sequence<double>(&rTextCandidate.getDXArray()[0], + rTextCandidate.getDXArray().size() )); + + const basegfx::BColor aRGBColor( + maBColorModifierStack.getModifiedColor( + rTextCandidate.getFontColor())); + + maRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence( + mxCanvas->getDevice(), + aRGBColor); + + // get render parameters and paint + mxCanvas->drawTextLayout( xLayout, + maViewState, + maRenderState ); + } + + // direct draw of hairline + void canvasProcessor::impRender_POHL(const polygonHairlinePrimitive& rPolygonCandidate) + { + const basegfx::BColor aRGBColor( + maBColorModifierStack.getModifiedColor( + rPolygonCandidate.getBColor())); + + maRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence( + mxCanvas->getDevice(), + aRGBColor); + + mxCanvas->drawPolyPolygon( basegfx::unotools::xPolyPolygonFromB2DPolygon( + mxCanvas->getDevice(), + rPolygonCandidate.getB2DPolygon()), + maViewState, + maRenderState ); + } + + // direct draw of transformed BitmapEx primitive + void canvasProcessor::impRender_BMPR(const bitmapPrimitive& rBitmapCandidate) + { + BitmapEx aBitmapEx(rBitmapCandidate.getBitmapEx()); + + if(maBColorModifierStack.count()) + { + // TODO(Q3): Share common bmp modification code with + // vclprocessor.cxx + Bitmap aChangedBitmap(impModifyBitmap(maBColorModifierStack, aBitmapEx.GetBitmap())); + + if(aBitmapEx.IsTransparent()) + { + if(aBitmapEx.IsAlpha()) + aBitmapEx = BitmapEx(aChangedBitmap, aBitmapEx.GetAlpha()); + else + aBitmapEx = BitmapEx(aChangedBitmap, aBitmapEx.GetMask()); + } + else + aBitmapEx = BitmapEx(aChangedBitmap); + } + + mxCanvas->drawBitmap( + vcl::unotools::xBitmapFromBitmapEx( mxCanvas->getDevice(), + aBitmapEx ), + maViewState, + maRenderState); + } + + void canvasProcessor::impRender_PPLB(const polyPolygonBitmapPrimitive& rPolyBitmapCandidate ) + { + const fillBitmapAttribute& rFillBmpAttr( rPolyBitmapCandidate.getFillBitmap() ); + const basegfx::B2DPolyPolygon& rPoly( rPolyBitmapCandidate.getB2DPolyPolygon() ); + + // TODO(Q3): Share common bmp modification code with + // vclprocessor.cxx + Bitmap aChangedBitmap( + impModifyBitmap(maBColorModifierStack, + rFillBmpAttr.getBitmap())); + + rendering::Texture aTexture; + const basegfx::B2DVector aBmpSize( rFillBmpAttr.getSize() ); + + const basegfx::B2DRange& rBounds( + basegfx::tools::getRange( rPoly )); + + basegfx::B2DHomMatrix aScale; + aScale.scale( aBmpSize.getX() * rBounds.getWidth(), + aBmpSize.getY() * rBounds.getHeight() ); + + basegfx::unotools::affineMatrixFromHomMatrix( + aTexture.AffineTransform, + aScale ); + + aTexture.Alpha = 1.0; + aTexture.Bitmap = + ::vcl::unotools::xBitmapFromBitmapEx( + mxCanvas->getDevice(), + aChangedBitmap ); + aTexture.RepeatModeX = rendering::TexturingMode::REPEAT; + aTexture.RepeatModeY = rendering::TexturingMode::REPEAT; + + uno::Sequence< rendering::Texture > aSeq(1); + aSeq[0] = aTexture; + + mxCanvas->fillTexturedPolyPolygon( + basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + mxCanvas->getDevice(), + rPoly), + maViewState, + maRenderState, + aSeq ); + } + + // direct draw of gradient + void canvasProcessor::impRender_PPLG(const polyPolygonGradientPrimitive& rPolygonCandidate) + { + const fillGradientAttribute& rGradient(rPolygonCandidate.getFillGradient()); + basegfx::BColor aStartColor(maBColorModifierStack.getModifiedColor(rGradient.getStartColor())); + basegfx::BColor aEndColor(maBColorModifierStack.getModifiedColor(rGradient.getEndColor())); + basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon()); + + if(aStartColor == aEndColor) + { + // no gradient at all, draw as polygon + + maRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence( + mxCanvas->getDevice(), + aStartColor); + + mxCanvas->drawPolyPolygon( basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + mxCanvas->getDevice(), + aLocalPolyPolygon), + maViewState, + maRenderState ); + } + else + { + // TODO(F3): if rGradient.getSteps() > 0, render + // gradient manually! + impDrawGradient( + aLocalPolyPolygon, rGradient.getStyle(), rGradient.getSteps(), + aStartColor, aEndColor, rGradient.getBorder(), + -rGradient.getAngle(), rGradient.getOffsetX(), rGradient.getOffsetY(), false); + } + } + + // direct draw of PolyPolygon with color + void canvasProcessor::impRender_PPLC(const polyPolygonColorPrimitive& rPolygonCandidate) + { + const basegfx::BColor aRGBColor( + maBColorModifierStack.getModifiedColor( + rPolygonCandidate.getBColor())); + + maRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence( + mxCanvas->getDevice(), + aRGBColor); + + mxCanvas->fillPolyPolygon( basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + mxCanvas->getDevice(), + rPolygonCandidate.getB2DPolyPolygon()), + maViewState, + maRenderState ); + } + + // direct draw of MetaFile + void canvasProcessor::impRender_META(const metafilePrimitive& rMetaCandidate) + { + // get metafile (copy it) + GDIMetaFile aMetaFile; + + // TODO(Q3): Share common metafile modification code with + // vclprocessor.cxx + if(maBColorModifierStack.count()) + { + const basegfx::BColor aRGBBaseColor(0, 0, 0); + const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(aRGBBaseColor)); + aMetaFile = rMetaCandidate.getMetaFile().GetMonochromeMtf(Color(aRGBColor)); + } + else + { + aMetaFile = rMetaCandidate.getMetaFile(); + } + + cppcanvas::BitmapCanvasSharedPtr pCanvas( + cppcanvas::VCLFactory::getInstance().createCanvas( + uno::Reference<rendering::XBitmapCanvas>( + mxCanvas, + uno::UNO_QUERY_THROW) )); + cppcanvas::RendererSharedPtr pMtfRenderer( + cppcanvas::VCLFactory::getInstance().createRenderer( + pCanvas, + aMetaFile, + cppcanvas::Renderer::Parameters() )); + if( pMtfRenderer ) + { + pCanvas->setTransformation(maWorldToView); + pMtfRenderer->setTransformation(rMetaCandidate.getTransform()); + pMtfRenderer->draw(); + } + } + + // mask group. Set mask polygon as clip + void canvasProcessor::impRender_MASK(const maskPrimitive& rMaskCandidate) + { + const primitiveVector& rSubList = rMaskCandidate.getPrimitiveVector(); + + if(!rSubList.empty()) + { + // TODO(F3): cannot use state-global renderstate, when recursing! + maRenderState.Clip = + basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + mxCanvas->getDevice(), + rMaskCandidate.getMask()); + + // paint to it + process(rSubList); + + maRenderState.Clip.clear(); + } + } + + // modified color group. Force output to unified color. + void canvasProcessor::impRender_MCOL(const modifiedColorPrimitive& rModifiedCandidate) + { + const primitiveVector& rSubList = rModifiedCandidate.getPrimitiveVector(); + + if(!rSubList.empty()) + { + maBColorModifierStack.push(rModifiedCandidate.getColorModifier()); + process(rModifiedCandidate.getPrimitiveVector()); + maBColorModifierStack.pop(); + } + } + + // sub-transparence group. Draw to bitmap device first. + void canvasProcessor::impRender_TRPR(const transparencePrimitive& rTransCandidate) + { + const primitiveVector& rSubList = rTransCandidate.getPrimitiveVector(); + + if(!rSubList.empty()) + { + basegfx::B2DRange aRange( + get2DRangeFromVector(rSubList, + getViewInformation())); + aRange.transform(maWorldToView); + const basegfx::B2I64Tuple& rSize( + canvas::tools::spritePixelAreaFromB2DRange(aRange).getRange()); + uno::Reference< rendering::XCanvas > xBitmap( + mxCanvas->getDevice()->createCompatibleAlphaBitmap( + css::geometry::IntegerSize2D(rSize.getX(), + rSize.getY())), + uno::UNO_QUERY_THROW); + + // remember last worldToView and add pixel offset + basegfx::B2DHomMatrix aLastWorldToView(maWorldToView); + basegfx::B2DHomMatrix aPixelOffset; + aPixelOffset.translate(aRange.getMinX(), + aRange.getMinY()); + setWorldToView(aPixelOffset * maWorldToView); + + // remember last canvas, set bitmap as target + uno::Reference< rendering::XCanvas > xLastCanvas( mxCanvas ); + mxCanvas = xBitmap; + + // paint content to it + process(rSubList); + + // TODO(F3): render transparent list to alpha + // channel. Note that the OutDev implementation has a + // shortcoming, in that nested transparency groups + // don't work - alpha is not combined properly. + + // process(rTransCandidate.getTransparenceList()); + + // back to old OutDev and worldToView + mxCanvas = xLastCanvas; + setWorldToView(aLastWorldToView); + + // DUMMY: add alpha modulation value to DeviceColor + // TODO(F3): color management + canvas::tools::setDeviceColor( maRenderState, + 1.0, 1.0, 1.0, 0.5 ); + // finally, draw bitmap + mxCanvas->drawBitmapModulated( + uno::Reference< rendering::XBitmap >( + xBitmap, + uno::UNO_QUERY_THROW), + maViewState, + maRenderState ); + } + } + + // transform group. + void canvasProcessor::impRender_TRN2(const transformPrimitive& rTransformCandidate) + { + // remember current transformation + basegfx::B2DHomMatrix aLastWorldToView(maWorldToView); + + // create new transformations + setWorldToView(maWorldToView * rTransformCandidate.getTransformation()); + + // let break down + process(rTransformCandidate.getPrimitiveVector()); + + // restore transformations + setWorldToView(aLastWorldToView); + } + + // marker + void canvasProcessor::impRender_MARK(const markerPrimitive& rMarkCandidate) + { + const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(rMarkCandidate.getRGBColor())); + + canvas::tools::initRenderState(maMarkerRenderState); + maMarkerRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence( + mxCanvas->getDevice(), + aRGBColor); + + // Markers are special objects - their position is + // determined by the view transformation, but their size + // is always the same + const basegfx::B2DPoint aViewPos(maWorldToView * rMarkCandidate.getPosition()); + + uno::Reference< rendering::XPolyPolygon2D > xMarkerPoly; + uno::Reference< rendering::XPolyPolygon2D > xHighlightMarkerPoly; + switch(rMarkCandidate.getStyle()) + { + default: + case MARKERSTYLE_POINT: + mxCanvas->drawPoint( basegfx::unotools::point2DFromB2DPoint(aViewPos), + maMarkerViewState, + maMarkerRenderState ); + return; + + case MARKERSTYLE_CROSS: + if( !mxCrossMarkerPoly.is() ) + { + basegfx::B2DPolyPolygon aPoly; + basegfx::tools::importFromSvgD( + aPoly, + rtl::OUString::createFromAscii( + "m-1 0 h2 m0 -1 v2" )); + mxCrossMarkerPoly = + basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + mxCanvas->getDevice(), + aPoly ); + } + xMarkerPoly = mxCrossMarkerPoly; + break; + + case MARKERSTYLE_GLUEPOINT : + if( !mxGluePointPoly.is() ) + { + basegfx::B2DPolyPolygon aPoly; + basegfx::tools::importFromSvgD( + aPoly, + rtl::OUString::createFromAscii( + "m-2 -3 l5 5 m-3 -2 l5 5 m-3 2 l5 -5 m-2 3 l5 -5" )); + mxGluePointPoly = + basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + mxCanvas->getDevice(), + aPoly ); + } + if( !mxGluePointHighlightPoly.is() ) + { + basegfx::B2DPolyPolygon aPoly; + basegfx::tools::importFromSvgD( + aPoly, + rtl::OUString::createFromAscii( + "m-2 -2 l4 4 m-2 2 l4 -4" )); + mxGluePointHighlightPoly = + basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + mxCanvas->getDevice(), + aPoly ); + } + xMarkerPoly = mxGluePointPoly; + xHighlightMarkerPoly = mxGluePointHighlightPoly; + break; + } + + basegfx::B2DRange aRange; + rMarkCandidate.getRealtiveViewRange(aRange); + const basegfx::B2DPoint aCenter(aRange.getCenter()); + + basegfx::B2DHomMatrix aTranslate; + aTranslate.translate(aViewPos.getX()+aCenter.getX(), + aViewPos.getY()+aCenter.getY()); + + canvas::tools::setRenderStateTransform( maMarkerRenderState, + aTranslate ); + + + mxCanvas->drawPolyPolygon( xMarkerPoly, + maMarkerViewState, + maMarkerRenderState ); + if( xHighlightMarkerPoly.is() ) + { + // TODO(F3): color management + canvas::tools::setDeviceColor(maMarkerRenderState, + 0.0, 0.0, 1.0, 1.0); + mxCanvas->drawPolyPolygon( xMarkerPoly, + maMarkerViewState, + maMarkerRenderState ); + } + } + + void canvasProcessor::setWorldToView(const basegfx::B2DHomMatrix& rMat) + { + maWorldToView = rMat; + canvas::tools::setViewStateTransform(maViewState, + maWorldToView); + } + + ////////////////////////////////////////////////////////////////////////////// + // internal processing support + + void canvasProcessor::process(const primitiveVector& rSource) + { + primitiveVector::const_iterator aCurr = rSource.begin(); + const primitiveVector::const_iterator aEnd = rSource.end(); + while( aCurr != aEnd ) + { + const referencedPrimitive& rCandidate = *aCurr; + + switch(rCandidate.getID()) + { + case CreatePrimitiveID('S', 'T', 'X', 'P'): + { + // directdraw of text simple portion + impRender_STXP(static_cast< const textSimplePortionPrimitive& >(rCandidate.getBasePrimitive())); + break; + } + + case CreatePrimitiveID('P', 'O', 'H', 'L'): + { + // direct draw of hairline + impRender_POHL(static_cast< const polygonHairlinePrimitive& >(rCandidate.getBasePrimitive())); + break; + } + + case CreatePrimitiveID('B', 'M', 'P', 'R'): + { + // direct draw of transformed BitmapEx primitive + impRender_BMPR(static_cast< const bitmapPrimitive& >(rCandidate.getBasePrimitive())); + break; + } + + case CreatePrimitiveID('F', 'B', 'M', 'P'): + { + OSL_ENSURE(false,"fillBitmapPrimitive not yet implemented"); + break; + } + + case CreatePrimitiveID('P', 'P', 'L', 'B'): + { + // direct draw of polygon with bitmap fill + impRender_PPLB(static_cast< const polyPolygonBitmapPrimitive& >(rCandidate.getBasePrimitive())); + break; + } + + case CreatePrimitiveID('P', 'P', 'L', 'G'): + { + // direct draw of gradient + impRender_PPLG(static_cast< const polyPolygonGradientPrimitive& >(rCandidate.getBasePrimitive())); + break; + } + + case CreatePrimitiveID('P', 'P', 'L', 'C'): + { + // direct draw of PolyPolygon with color + impRender_PPLC(static_cast< const polyPolygonColorPrimitive& >(rCandidate.getBasePrimitive())); + break; + } + + case CreatePrimitiveID('M', 'E', 'T', 'A'): + { + // direct draw of MetaFile + impRender_META(static_cast< const metafilePrimitive& >(rCandidate.getBasePrimitive())); + break; + } + + case CreatePrimitiveID('M', 'A', 'S', 'K'): + { + // mask group. Force output to VDev and create mask from given mask + impRender_MASK(static_cast< const maskPrimitive& >(rCandidate.getBasePrimitive())); + break; + } + + case CreatePrimitiveID('M', 'C', 'O', 'L'): + { + // modified color group. Force output to unified color. + impRender_MCOL(static_cast< const modifiedColorPrimitive& >(rCandidate.getBasePrimitive())); + break; + } + + case CreatePrimitiveID('T', 'R', 'P', 'R'): + { + // sub-transparence group. Draw to VDev first. + impRender_TRPR(static_cast< const transparencePrimitive& >(rCandidate.getBasePrimitive())); + break; + } + + case CreatePrimitiveID('T', 'R', 'N', '2'): + { + // transform group. + impRender_TRN2(static_cast< const transformPrimitive& >(rCandidate.getBasePrimitive())); + break; + } + + case CreatePrimitiveID('M', 'A', 'R', 'K'): + { + // marker + impRender_MARK(static_cast< const markerPrimitive& >(rCandidate.getBasePrimitive())); + break; + } + + case CreatePrimitiveID('A', 'N', 'S', 'W'): + case CreatePrimitiveID('A', 'N', 'B', 'L'): + case CreatePrimitiveID('A', 'N', 'I', 'N'): + { + // check timing, but do not accept + const animatedSwitchPrimitive& rAnimatedCandidate(static_cast< const animatedSwitchPrimitive& >(rCandidate.getBasePrimitive())); + const ::drawinglayer::animation::animationEntryList& rAnimationList = rAnimatedCandidate.getAnimationList(); + const double fNewTime(rAnimationList.getNextEventTime(getViewInformation().getViewTime())); + + // let break down + process(rAnimatedCandidate.getDecomposition(getViewInformation())); + + break; + } + + default: + { + // let break down + process(rCandidate.getBasePrimitive().getDecomposition(getViewInformation())); + } + } + + ++aCurr; + } + } + + canvasProcessor::canvasProcessor( const ::drawinglayer::geometry::viewInformation& rViewInformation, + const uno::Reference<rendering::XCanvas>& rCanvas ) : + processor(rViewInformation), + mxCanvas( rCanvas ), + mxCrossMarkerPoly(), + mxGluePointPoly(), + mxGluePointHighlightPoly(), + maBColorModifierStack(), + maWorldToView(), + maViewState(), + maRenderState(), + maMarkerViewState(), + maMarkerRenderState() + { + canvas::tools::initViewState(maViewState); + canvas::tools::initRenderState(maRenderState); + canvas::tools::initViewState(maMarkerViewState); + canvas::tools::initRenderState(maMarkerRenderState); + + maWorldToView = maViewInformation.getViewTransformation(); + + canvas::tools::setViewStateTransform(maViewState, + maWorldToView); + } + + canvasProcessor::~canvasProcessor() + {} +*/ +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace processor2d + { + ////////////////////////////////////////////////////////////////////////////// + // single primitive renderers + + void canvasProcessor2D::impRenderMaskPrimitive2D(const primitive2d::MaskPrimitive2D& rMaskCandidate) + { + const primitive2d::Primitive2DSequence& rChildren = rMaskCandidate.getChildren(); + static bool bUseMaskBitmapMethod(true); + + if(rChildren.hasElements()) + { + basegfx::B2DPolyPolygon aMask(rMaskCandidate.getMask()); + + if(!aMask.count()) + { + // no mask, no clipping. recursively paint content + process(rChildren); + } + else + { + // there are principally two methods for implementing the mask primitive. One + // is to set a clip polygon at the canvas, the other is to create and use a + // alpha-using XBitmap for content and draw the mask as alpha. Both have their + // advantages and disadvantages, so here are both with a bool allowing simple + // change + if(bUseMaskBitmapMethod) + { + // get logic range of transparent part, clip with ViewRange + basegfx::B2DRange aLogicRange(aMask.getB2DRange()); + + if(!getViewInformation2D().getViewport().isEmpty()) + { + aLogicRange.intersect(getViewInformation2D().getViewport()); + } + + if(!aLogicRange.isEmpty()) + { + // get discrete range of transparent part + basegfx::B2DRange aDiscreteRange(aLogicRange); + aDiscreteRange.transform(getViewInformation2D().getObjectToViewTransformation()); + + // expand to next covering discrete values (pixel bounds) + aDiscreteRange.expand(basegfx::B2DTuple(floor(aDiscreteRange.getMinX()), floor(aDiscreteRange.getMinY()))); + aDiscreteRange.expand(basegfx::B2DTuple(ceil(aDiscreteRange.getMaxX()), ceil(aDiscreteRange.getMaxY()))); + + // use VCL-based buffer device + impBufferDevice aBufferDevice(*mpOutputDevice, aDiscreteRange, false); + + if(aBufferDevice.isVisible()) + { + // remember current OutDev, Canvas and ViewInformation + OutputDevice* pLastOutputDevice = mpOutputDevice; + uno::Reference< rendering::XCanvas > xLastCanvas(mxCanvas); + const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D()); + + // prepare discrete offset for XBitmap, do not forget that the buffer bitmap + // may be truncated to discrete visible pixels + basegfx::B2DHomMatrix aDiscreteOffset; + aDiscreteOffset.translate( + aDiscreteRange.getMinX() > 0.0 ? -aDiscreteRange.getMinX() : 0.0, + aDiscreteRange.getMinY() > 0.0 ? -aDiscreteRange.getMinY() : 0.0); + + // create new local ViewInformation2D with new transformation + const geometry::ViewInformation2D aViewInformation2D( + getViewInformation2D().getObjectTransformation(), + aDiscreteOffset * getViewInformation2D().getViewTransformation(), + getViewInformation2D().getViewport(), + getViewInformation2D().getVisualizedPage(), + getViewInformation2D().getViewTime(), + getViewInformation2D().getExtendedInformationSequence()); + updateViewInformation(aViewInformation2D); + + // set OutDev and Canvas to content target + mpOutputDevice = &aBufferDevice.getContent(); + mxCanvas = mpOutputDevice->GetCanvas(); + canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation()); + + // if ViewState transform is changed, the clipping polygon needs to be adapted, too + const basegfx::B2DPolyPolygon aOldClipPolyPolygon(maClipPolyPolygon); + + if(maClipPolyPolygon.count()) + { + maClipPolyPolygon.transform(aDiscreteOffset); + maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon); + } + + // paint content + process(rChildren); + + // draw mask + const basegfx::BColor aBlack(0.0, 0.0, 0.0); + maRenderState.DeviceColor = aBlack.colorToDoubleSequence(mxCanvas->getDevice()); + + if(getOptionsDrawinglayer().IsAntiAliasing()) + { + // with AA, use 8bit AlphaMask to get nice borders + VirtualDevice& rAlpha = aBufferDevice.getAlpha(); + rAlpha.GetCanvas()->fillPolyPolygon( + basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), aMask), + maViewState, maRenderState); + } + else + { + // No AA, use 1bit mask + VirtualDevice& rMask = aBufferDevice.getMask(); + rMask.GetCanvas()->fillPolyPolygon( + basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), aMask), + maViewState, maRenderState); + } + + // back to old color stack, OutDev, Canvas and ViewTransform + mpOutputDevice = pLastOutputDevice; + mxCanvas = xLastCanvas; + updateViewInformation(aLastViewInformation2D); + canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation()); + + // restore clipping polygon + maClipPolyPolygon = aOldClipPolyPolygon; + + if(maClipPolyPolygon.count()) + { + maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon); + } + + // dump buffer to outdev + aBufferDevice.paint(); + } + } + } + else + { + // transform new mask polygon to view coordinates for processing. All masks + // are processed in view coordinates and clipped against each other evtl. to + // create multi-clips + aMask.transform(getViewInformation2D().getObjectTransformation()); + + // remember last current clip polygon + const basegfx::B2DPolyPolygon aLastClipPolyPolygon(maClipPolyPolygon); + + if(maClipPolyPolygon.count()) + { + // there is already a clip polygon set; build clipped union of + // current mask polygon and new one + maClipPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon(aMask, maClipPolyPolygon, false, false); + } + else + { + // use mask directly + maClipPolyPolygon = aMask; + } + + // set at ViewState + if(maClipPolyPolygon.count()) + { + // set new as clip polygon + maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon); + } + else + { + // empty, reset + maViewState.Clip.clear(); + } + + // paint content + process(rChildren); + + // restore local current to rescued clip polygon + maClipPolyPolygon = aLastClipPolyPolygon; + + // set at ViewState + if(maClipPolyPolygon.count()) + { + // set new as clip polygon + maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon); + } + else + { + // empty, reset + maViewState.Clip.clear(); + } + } + } + } + } + + void canvasProcessor2D::impRenderMetafilePrimitive2D(const primitive2d::MetafilePrimitive2D& rMetaCandidate) + { + GDIMetaFile aMetaFile; + + if(maBColorModifierStack.count()) + { + const basegfx::BColor aRGBBaseColor(0, 0, 0); + const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(aRGBBaseColor)); + aMetaFile = rMetaCandidate.getMetaFile().GetMonochromeMtf(Color(aRGBColor)); + } + else + { + aMetaFile = rMetaCandidate.getMetaFile(); + } + + cppcanvas::BitmapCanvasSharedPtr pCanvas(cppcanvas::VCLFactory::getInstance().createCanvas( + uno::Reference<rendering::XBitmapCanvas>(mxCanvas, uno::UNO_QUERY_THROW))); + cppcanvas::RendererSharedPtr pMtfRenderer(cppcanvas::VCLFactory::getInstance().createRenderer( + pCanvas, aMetaFile, cppcanvas::Renderer::Parameters())); + + if(pMtfRenderer) + { + pCanvas->setTransformation(getViewInformation2D().getObjectToViewTransformation()); + pMtfRenderer->setTransformation(rMetaCandidate.getTransform()); + pMtfRenderer->draw(); + } + } + + void canvasProcessor2D::impRenderTextSimplePortionPrimitive2D(const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate) + { + if(rTextCandidate.getTextLength()) + { + double fShearX(0.0); + { + const basegfx::B2DHomMatrix aLocalTransform(getViewInformation2D().getObjectToViewTransformation() * rTextCandidate.getTextTransform()); + basegfx::B2DVector aScale, aTranslate; + double fRotate; + aLocalTransform.decompose(aScale, aTranslate, fRotate, fShearX); + } + + if(!basegfx::fTools::equalZero(fShearX)) + { + // text is sheared. As long as the canvas renderers do not support this, + // use the decomposed primitive + process(rTextCandidate.get2DDecomposition(getViewInformation2D())); + } + else + { + const primitive2d::FontAttributes& rFontAttrs(rTextCandidate.getFontAttributes()); + rendering::FontRequest aFontRequest; + + aFontRequest.FontDescription.FamilyName = rFontAttrs.getFamilyName(); + aFontRequest.FontDescription.StyleName = rFontAttrs.getStyleName(); + aFontRequest.FontDescription.IsSymbolFont = rFontAttrs.getSymbol() ? util::TriState_YES : util::TriState_NO; + aFontRequest.FontDescription.IsVertical = rFontAttrs.getVertical() ? util::TriState_YES : util::TriState_NO; + // TODO(F2): improve vclenum->panose conversion + aFontRequest.FontDescription.FontDescription.Weight = static_cast< sal_uInt8 >(rFontAttrs.getWeight()); + aFontRequest.FontDescription.FontDescription.Letterform = rFontAttrs.getItalic() ? 9 : 0; + + // init CellSize to 1.0, else a default font height will be used + aFontRequest.CellSize = 1.0; + aFontRequest.Locale = rTextCandidate.getLocale(); + + // font matrix should only be used for glyph rotations etc. + com::sun::star::geometry::Matrix2D aFontMatrix; + canvas::tools::setIdentityMatrix2D(aFontMatrix); + + uno::Reference<rendering::XCanvasFont> xFont(mxCanvas->createFont( + aFontRequest, uno::Sequence< beans::PropertyValue >(), aFontMatrix)); + + if(xFont.is()) + { + // got a font, now try to get a TextLayout + const rendering::StringContext aStringContext( + rTextCandidate.getText(), rTextCandidate.getTextPosition(), rTextCandidate.getTextLength()); + uno::Reference<rendering::XTextLayout> xLayout(xFont->createTextLayout( + aStringContext, com::sun::star::rendering::TextDirection::WEAK_LEFT_TO_RIGHT, 0)); + + if(xLayout.is()) + { + // got a text layout, apply DXArray if given + const ::std::vector< double >& rDXArray = rTextCandidate.getDXArray(); + const sal_uInt32 nDXCount(rDXArray.size()); + + if(nDXCount) + { + // DXArray does not need to be adapted to getTextPosition/getTextLength, + // it is already provided correctly + const uno::Sequence< double > aDXSequence(&rDXArray[0], nDXCount); + xLayout->applyLogicalAdvancements(aDXSequence); + } + + // set text color + const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(rTextCandidate.getFontColor())); + maRenderState.DeviceColor = aRGBColor.colorToDoubleSequence(mxCanvas->getDevice()); + + // set text transformation + canvas::tools::setRenderStateTransform(maRenderState, + getViewInformation2D().getObjectTransformation() * rTextCandidate.getTextTransform()); + + // paint + mxCanvas->drawTextLayout(xLayout, maViewState, maRenderState); + } + } + } + } + } + + void canvasProcessor2D::impRenderBitmapPrimitive2D(const primitive2d::BitmapPrimitive2D& rBitmapCandidate) + { + // apply possible color modification to BitmapEx + BitmapEx aModifiedBitmapEx(impModifyBitmapEx(maBColorModifierStack, rBitmapCandidate.getBitmapEx())); + + if(aModifiedBitmapEx.IsEmpty()) + { + // replace with color filled polygon + const basegfx::BColor aModifiedColor(maBColorModifierStack.getModifiedColor(basegfx::BColor())); + const basegfx::B2DPolygon aPolygon(basegfx::tools::createPolygonFromRect(basegfx::B2DRange(0.0, 0.0, 1.0, 1.0))); + + maRenderState.DeviceColor = aModifiedColor.colorToDoubleSequence(mxCanvas->getDevice()); + canvas::tools::setRenderStateTransform(maRenderState, + getViewInformation2D().getObjectTransformation() * rBitmapCandidate.getTransform()); + + mxCanvas->fillPolyPolygon(basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + mxCanvas->getDevice(), basegfx::B2DPolyPolygon(aPolygon)), maViewState, maRenderState); + } + else + { + // adapt object's transformation to the correct scale + basegfx::B2DVector aScale, aTranslate; + double fRotate, fShearX; + basegfx::B2DHomMatrix aNewMatrix; + const Size aSizePixel(aModifiedBitmapEx.GetSizePixel()); + + if(0 != aSizePixel.Width() && 0 != aSizePixel.Height()) + { + rBitmapCandidate.getTransform().decompose(aScale, aTranslate, fRotate, fShearX); + aNewMatrix.scale(aScale.getX() / aSizePixel.Width(), aScale.getY() / aSizePixel.Height()); + aNewMatrix.shearX(fShearX); + aNewMatrix.rotate(fRotate); + aNewMatrix.translate(aTranslate.getX(), aTranslate.getY()); + + canvas::tools::setRenderStateTransform(maRenderState, + getViewInformation2D().getObjectTransformation() * aNewMatrix); + + mxCanvas->drawBitmap( + vcl::unotools::xBitmapFromBitmapEx(mxCanvas->getDevice(), aModifiedBitmapEx), + maViewState, maRenderState); + } + } + } + + void canvasProcessor2D::impRenderAlphaPrimitive2D(const primitive2d::AlphaPrimitive2D& rAlphaCandidate) + { + const primitive2d::Primitive2DSequence& rChildren = rAlphaCandidate.getChildren(); + const primitive2d::Primitive2DSequence& rAlpha = rAlphaCandidate.getAlpha(); + + if(rChildren.hasElements() && rAlpha.hasElements()) + { + // get logic range of transparent part and clip with ViewRange + basegfx::B2DRange aLogicRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rChildren, getViewInformation2D())); + + if(!getViewInformation2D().getViewport().isEmpty()) + { + aLogicRange.intersect(getViewInformation2D().getViewport()); + } + + if(!aLogicRange.isEmpty()) + { + // get discrete range of transparent part + basegfx::B2DRange aDiscreteRange(aLogicRange); + aDiscreteRange.transform(getViewInformation2D().getObjectToViewTransformation()); + + // expand to next covering discrete values (pixel bounds) + aDiscreteRange.expand(basegfx::B2DTuple(floor(aDiscreteRange.getMinX()), floor(aDiscreteRange.getMinY()))); + aDiscreteRange.expand(basegfx::B2DTuple(ceil(aDiscreteRange.getMaxX()), ceil(aDiscreteRange.getMaxY()))); + + // use VCL-based buffer device + impBufferDevice aBufferDevice(*mpOutputDevice, aDiscreteRange, false); + + if(aBufferDevice.isVisible()) + { + // remember current OutDev, Canvas and ViewInformation + OutputDevice* pLastOutputDevice = mpOutputDevice; + uno::Reference< rendering::XCanvas > xLastCanvas(mxCanvas); + const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D()); + + // prepare discrete offset for XBitmap, do not forget that the buffer bitmap + // may be truncated to discrete visible pixels + basegfx::B2DHomMatrix aDiscreteOffset; + aDiscreteOffset.translate( + aDiscreteRange.getMinX() > 0.0 ? -aDiscreteRange.getMinX() : 0.0, + aDiscreteRange.getMinY() > 0.0 ? -aDiscreteRange.getMinY() : 0.0); + + // create new local ViewInformation2D with new transformation + const geometry::ViewInformation2D aViewInformation2D( + getViewInformation2D().getObjectTransformation(), + aDiscreteOffset * getViewInformation2D().getViewTransformation(), + getViewInformation2D().getViewport(), + getViewInformation2D().getVisualizedPage(), + getViewInformation2D().getViewTime(), + getViewInformation2D().getExtendedInformationSequence()); + updateViewInformation(aViewInformation2D); + + // set OutDev and Canvas to content target + mpOutputDevice = &aBufferDevice.getContent(); + mxCanvas = mpOutputDevice->GetCanvas(); + canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation()); + + // if ViewState transform is changed, the clipping polygon needs to be adapted, too + const basegfx::B2DPolyPolygon aOldClipPolyPolygon(maClipPolyPolygon); + + if(maClipPolyPolygon.count()) + { + maClipPolyPolygon.transform(aDiscreteOffset); + maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon); + } + + // paint content + process(rChildren); + + // set to mask + mpOutputDevice = &aBufferDevice.getAlpha(); + mxCanvas = mpOutputDevice->GetCanvas(); + canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation()); + + // when painting alpha masks, reset the color stack + basegfx::BColorModifierStack aLastBColorModifierStack(maBColorModifierStack); + maBColorModifierStack = basegfx::BColorModifierStack(); + + // paint mask to it (always with alpha intensities, evtl. with AA) + process(rAlpha); + + // back to old color stack, OutDev, Canvas and ViewTransform + maBColorModifierStack = aLastBColorModifierStack; + mpOutputDevice = pLastOutputDevice; + mxCanvas = xLastCanvas; + updateViewInformation(aLastViewInformation2D); + canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation()); + + // restore clipping polygon + maClipPolyPolygon = aOldClipPolyPolygon; + + if(maClipPolyPolygon.count()) + { + maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon); + } + + // dump buffer to outdev + aBufferDevice.paint(); + } + } + } + } + + void canvasProcessor2D::impRenderPolygonStrokePrimitive2D(const primitive2d::PolygonStrokePrimitive2D& rPolygonStrokePrimitive) + { + // support direct fat line geometry. This moves the decomposition to the canvas. + // As long as our canvases are used (which also use basegfx tooling) this makes + // no difference, but potentially canvases may better support this + static bool bSupportFatLineDirectly(true); + bool bOutputDone(false); + + if(bSupportFatLineDirectly) + { + const attribute::LineAttribute& rLineAttribute = rPolygonStrokePrimitive.getLineAttribute(); + const attribute::StrokeAttribute& rStrokeAttribute = rPolygonStrokePrimitive.getStrokeAttribute(); + + if(0.0 < rLineAttribute.getWidth() || 0 != rStrokeAttribute.getDotDashArray().size()) + { + rendering::StrokeAttributes aStrokeAttribute; + + aStrokeAttribute.StrokeWidth = rLineAttribute.getWidth(); + aStrokeAttribute.MiterLimit = 15.0; // degrees; maybe here (15.0 * F_PI180) is needed, not clear in the documentation + const ::std::vector< double >& rDotDashArray = rStrokeAttribute.getDotDashArray(); + + if(rDotDashArray.size()) + { + aStrokeAttribute.DashArray = uno::Sequence< double >(&rDotDashArray[0], rDotDashArray.size()); + } + + switch(rLineAttribute.getLineJoin()) + { + default: // B2DLINEJOIN_NONE, B2DLINEJOIN_MIDDLE + aStrokeAttribute.JoinType = rendering::PathJoinType::NONE; + break; + case basegfx::B2DLINEJOIN_BEVEL: + aStrokeAttribute.JoinType = rendering::PathJoinType::BEVEL; + break; + case basegfx::B2DLINEJOIN_MITER: + aStrokeAttribute.JoinType = rendering::PathJoinType::MITER; + break; + case basegfx::B2DLINEJOIN_ROUND: + aStrokeAttribute.JoinType = rendering::PathJoinType::ROUND; + break; + } + + const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rLineAttribute.getColor())); + maRenderState.DeviceColor = aHairlineColor.colorToDoubleSequence(mxCanvas->getDevice()); + canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation()); + + mxCanvas->strokePolyPolygon( + basegfx::unotools::xPolyPolygonFromB2DPolygon(mxCanvas->getDevice(), rPolygonStrokePrimitive.getB2DPolygon()), + maViewState, maRenderState, aStrokeAttribute); + + bOutputDone = true; + } + } + + if(!bOutputDone) + { + // process decomposition + process(rPolygonStrokePrimitive.get2DDecomposition(getViewInformation2D())); + } + } + + void canvasProcessor2D::impRenderFillBitmapPrimitive2D(const primitive2d::FillBitmapPrimitive2D& rFillBitmapPrimitive2D) + { + // support tiled fills directly when tiling is on + static bool bSupportFillBitmapDirectly(true); + bool bOutputDone(false); + + if(bSupportFillBitmapDirectly) + { + const attribute::FillBitmapAttribute& rFillBitmapAttribute = rFillBitmapPrimitive2D.getFillBitmap(); + + if(rFillBitmapAttribute.getTiling()) + { + // apply possible color modification to Bitmap + const BitmapEx aChangedBitmapEx(impModifyBitmapEx(maBColorModifierStack, BitmapEx(rFillBitmapAttribute.getBitmap()))); + + if(aChangedBitmapEx.IsEmpty()) + { + // replace with color filled polygon + const basegfx::BColor aModifiedColor(maBColorModifierStack.getModifiedColor(basegfx::BColor())); + const basegfx::B2DPolygon aPolygon(basegfx::tools::createPolygonFromRect(basegfx::B2DRange(0.0, 0.0, 1.0, 1.0))); + + maRenderState.DeviceColor = aModifiedColor.colorToDoubleSequence(mxCanvas->getDevice()); + canvas::tools::setRenderStateTransform(maRenderState, + getViewInformation2D().getObjectTransformation() * rFillBitmapPrimitive2D.getTransformation()); + + mxCanvas->fillPolyPolygon(basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + mxCanvas->getDevice(), basegfx::B2DPolyPolygon(aPolygon)), maViewState, maRenderState); + } + else + { + const Size aSizePixel(aChangedBitmapEx.GetSizePixel()); + + if(0 != aSizePixel.Width() && 0 != aSizePixel.Height()) + { + // create texture matrix from texture to object (where object is unit square here), + // so use values directly + basegfx::B2DHomMatrix aTextureMatrix; + aTextureMatrix.scale( + rFillBitmapAttribute.getSize().getX(), + rFillBitmapAttribute.getSize().getY()); + aTextureMatrix.translate( + rFillBitmapAttribute.getTopLeft().getX(), + rFillBitmapAttribute.getTopLeft().getY()); + + // create and fill texture + rendering::Texture aTexture; + + basegfx::unotools::affineMatrixFromHomMatrix(aTexture.AffineTransform, aTextureMatrix); + aTexture.Alpha = 1.0; + aTexture.Bitmap = vcl::unotools::xBitmapFromBitmapEx(mxCanvas->getDevice(), aChangedBitmapEx); + aTexture.RepeatModeX = rendering::TexturingMode::REPEAT; + aTexture.RepeatModeY = rendering::TexturingMode::REPEAT; + + // canvas needs a polygon to fill, create unit rectangle polygon + const basegfx::B2DPolygon aOutlineRectangle(basegfx::tools::createPolygonFromRect(basegfx::B2DRange(0.0, 0.0, 1.0, 1.0))); + + // set primitive's transformation as render state transform + canvas::tools::setRenderStateTransform(maRenderState, + getViewInformation2D().getObjectTransformation() * rFillBitmapPrimitive2D.getTransformation()); + + // put texture into a uno sequence for handover + uno::Sequence< rendering::Texture > aSeq(1); + aSeq[0] = aTexture; + + // draw textured rectangle + mxCanvas->fillTexturedPolyPolygon( + basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), basegfx::B2DPolyPolygon(aOutlineRectangle)), + maViewState, maRenderState, aSeq); + } + } + + bOutputDone = true; + } + } + + if(!bOutputDone) + { + // process decomposition + process(rFillBitmapPrimitive2D.get2DDecomposition(getViewInformation2D())); + } + } + + void canvasProcessor2D::impRenderUnifiedAlphaPrimitive2D(const primitive2d::UnifiedAlphaPrimitive2D& rUniAlphaCandidate) + { + const primitive2d::Primitive2DSequence rChildren = rUniAlphaCandidate.getChildren(); + + if(rChildren.hasElements()) + { + bool bOutputDone(false); + + // Detect if a single PolyPolygonColorPrimitive2D is contained; in that case, + // use the fillPolyPolygon method with correctly set alpha. This is a often used + // case, so detectiong it is valuable + if(1 == rChildren.getLength()) + { + const primitive2d::Primitive2DReference xReference(rChildren[0]); + const primitive2d::PolyPolygonColorPrimitive2D* pPoPoColor = dynamic_cast< const primitive2d::PolyPolygonColorPrimitive2D* >(xReference.get()); + + if(pPoPoColor && PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D == pPoPoColor->getPrimitiveID()) + { + // direct draw of PolyPolygon with color and transparence + const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(pPoPoColor->getBColor())); + + // add alpha modulation value to DeviceColor + uno::Sequence< double > aColor(4); + + aColor[0] = aPolygonColor.getRed(); + aColor[1] = aPolygonColor.getGreen(); + aColor[2] = aPolygonColor.getBlue(); + aColor[3] = 1.0 - rUniAlphaCandidate.getAlpha(); + maRenderState.DeviceColor = aColor; + + canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation()); + mxCanvas->fillPolyPolygon( + basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), pPoPoColor->getB2DPolyPolygon()), + maViewState, maRenderState); + bOutputDone = true; + } + } + + if(!bOutputDone) + { + // process decomposition. This will be decomposed to an AlphaPrimitive2D + // with the same child context and a single polygon for alpha context. This could be + // directly handled here with known VCL-buffer technology, but would only + // make a small difference compared to directly rendering the AlphaPrimitive2D + // using impRenderAlphaPrimitive2D above. + process(rUniAlphaCandidate.get2DDecomposition(getViewInformation2D())); + } + } + } + + ////////////////////////////////////////////////////////////////////////////// + // internal processing support + + void canvasProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate) + { + switch(rCandidate.getPrimitiveID()) + { + case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D : + { + // direct draw of hairline + const primitive2d::PolygonHairlinePrimitive2D& rPolygonCandidate = static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate); + const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor())); + + maRenderState.DeviceColor = aHairlineColor.colorToDoubleSequence(mxCanvas->getDevice()); + canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation()); + mxCanvas->drawPolyPolygon( + basegfx::unotools::xPolyPolygonFromB2DPolygon(mxCanvas->getDevice(), rPolygonCandidate.getB2DPolygon()), + maViewState, maRenderState); + + break; + } + case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D : + { + // direct draw of PolyPolygon with color + const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate = static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate); + const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor())); + + maRenderState.DeviceColor = aPolygonColor.colorToDoubleSequence(mxCanvas->getDevice()); + canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation()); + mxCanvas->fillPolyPolygon( + basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), rPolygonCandidate.getB2DPolyPolygon()), + maViewState, maRenderState); + + break; + } + case PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D : + { + // modified color group. Force output to unified color. + const primitive2d::ModifiedColorPrimitive2D& rModifiedCandidate = static_cast< const primitive2d::ModifiedColorPrimitive2D& >(rCandidate); + + if(rModifiedCandidate.getChildren().hasElements()) + { + maBColorModifierStack.push(rModifiedCandidate.getColorModifier()); + process(rModifiedCandidate.getChildren()); + maBColorModifierStack.pop(); + } + + break; + } + case PRIMITIVE2D_ID_MASKPRIMITIVE2D : + { + // mask group + impRenderMaskPrimitive2D(static_cast< const primitive2d::MaskPrimitive2D& >(rCandidate)); + + break; + } + case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D : + { + // transform group. Remember current ViewInformation2D + const primitive2d::TransformPrimitive2D& rTransformCandidate = static_cast< const primitive2d::TransformPrimitive2D& >(rCandidate); + const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D()); + + // create new local ViewInformation2D with new transformation + const geometry::ViewInformation2D aViewInformation2D( + getViewInformation2D().getObjectTransformation() * rTransformCandidate.getTransformation(), + getViewInformation2D().getViewTransformation(), + getViewInformation2D().getViewport(), + getViewInformation2D().getVisualizedPage(), + getViewInformation2D().getViewTime(), + getViewInformation2D().getExtendedInformationSequence()); + updateViewInformation(aViewInformation2D); + + // set at canvas + canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation()); + + // proccess content + process(rTransformCandidate.getChildren()); + + // restore transformations + updateViewInformation(aLastViewInformation2D); + + // restore at canvas + canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation()); + + break; + } + case PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D : + { + // new XDrawPage for ViewInformation2D + const primitive2d::PagePreviewPrimitive2D& rPagePreviewCandidate = static_cast< const primitive2d::PagePreviewPrimitive2D& >(rCandidate); + + // remember current transformation and ViewInformation + const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D()); + + // create new local ViewInformation2D + const geometry::ViewInformation2D aViewInformation2D( + getViewInformation2D().getObjectTransformation(), + getViewInformation2D().getViewTransformation(), + getViewInformation2D().getViewport(), + rPagePreviewCandidate.getXDrawPage(), + getViewInformation2D().getViewTime(), + getViewInformation2D().getExtendedInformationSequence()); + updateViewInformation(aViewInformation2D); + + // proccess decomposed content + process(rPagePreviewCandidate.get2DDecomposition(getViewInformation2D())); + + // restore transformations + updateViewInformation(aLastViewInformation2D); + break; + } + case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D : + { + // MetaFile primitive + impRenderMetafilePrimitive2D(static_cast< const primitive2d::MetafilePrimitive2D& >(rCandidate)); + + break; + } + case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D : + { + // PointArray primitive + const primitive2d::PointArrayPrimitive2D& rPointArrayCandidate = static_cast< const primitive2d::PointArrayPrimitive2D& >(rCandidate); + + // set point color + const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(rPointArrayCandidate.getRGBColor())); + maRenderState.DeviceColor = aRGBColor.colorToDoubleSequence(mxCanvas->getDevice()); + canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation()); + + const std::vector< basegfx::B2DPoint >& rPointVector = rPointArrayCandidate.getPositions(); + const sal_uInt32 nPointCount(rPointVector.size()); + + for(sal_uInt32 a(0); a < nPointCount; a++) + { + const basegfx::B2DPoint& rPoint = rPointVector[a]; + mxCanvas->drawPoint(basegfx::unotools::point2DFromB2DPoint(rPoint), maViewState, maRenderState); + } + + break; + } + case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D : + { + // TextSimplePortion primitive + impRenderTextSimplePortionPrimitive2D(static_cast< const primitive2d::TextSimplePortionPrimitive2D& >(rCandidate)); + + break; + } + case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D : + { + // Bitmap primitive + impRenderBitmapPrimitive2D(static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate)); + + break; + } + case PRIMITIVE2D_ID_ALPHAPRIMITIVE2D : + { + // Alpha primitive + impRenderAlphaPrimitive2D(static_cast< const primitive2d::AlphaPrimitive2D& >(rCandidate)); + + break; + } + case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D: + { + // PolygonStrokePrimitive + impRenderPolygonStrokePrimitive2D(static_cast< const primitive2d::PolygonStrokePrimitive2D& >(rCandidate)); + + break; + } + case PRIMITIVE2D_ID_FILLBITMAPPRIMITIVE2D : + { + // FillBitmapPrimitive2D + impRenderFillBitmapPrimitive2D(static_cast< const primitive2d::FillBitmapPrimitive2D& >(rCandidate)); + + break; + } + case PRIMITIVE2D_ID_UNIFIEDALPHAPRIMITIVE2D : + { + // UnifiedAlphaPrimitive2D + impRenderUnifiedAlphaPrimitive2D(static_cast< const primitive2d::UnifiedAlphaPrimitive2D& >(rCandidate)); + + break; + } + case PRIMITIVE2D_ID_CHARTPRIMITIVE2D : + { + // chart primitive in canvas renderer; restore original DrawMode during call + // since the evtl. used ChartPrettyPainter will use the MapMode + const primitive2d::ChartPrimitive2D& rChartPrimitive = static_cast< const primitive2d::ChartPrimitive2D& >(rCandidate); + mpOutputDevice->Push(PUSH_MAPMODE); + mpOutputDevice->SetMapMode(maOriginalMapMode); + + if(!renderChartPrimitive2D( + rChartPrimitive, + *mpOutputDevice, + getViewInformation2D())) + { + // fallback to decomposition (MetaFile) + process(rChartPrimitive.get2DDecomposition(getViewInformation2D())); + } + + mpOutputDevice->Pop(); + break; + } + case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D : + { + // wrong spell primitive. Handled directly here using VCL since VCL has a nice and + // very direct waveline painting which is needed for this. If VCL is to be avoided, + // this can be removed anytime and the decomposition may be used + const primitive2d::WrongSpellPrimitive2D& rWrongSpellPrimitive = static_cast< const primitive2d::WrongSpellPrimitive2D& >(rCandidate); + + if(!renderWrongSpellPrimitive2D( + rWrongSpellPrimitive, + *mpOutputDevice, + getViewInformation2D().getObjectToViewTransformation(), + maBColorModifierStack)) + { + // fallback to decomposition (MetaFile) + process(rWrongSpellPrimitive.get2DDecomposition(getViewInformation2D())); + } + + break; + } + + // nice to have: + // + // case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D : + // - support FormControls more direct eventually, not sure if this is needed + // with the canvas renderer. The decomposition provides a bitmap representation + // of the control which will work + // + + default : + { + // process recursively + process(rCandidate.get2DDecomposition(getViewInformation2D())); + + break; + } + } + } + + ////////////////////////////////////////////////////////////////////////////// + // process support + + canvasProcessor2D::canvasProcessor2D( + const geometry::ViewInformation2D& rViewInformation, + OutputDevice& rOutDev) + : BaseProcessor2D(rViewInformation), + maOriginalMapMode(rOutDev.GetMapMode()), + mpOutputDevice(&rOutDev), + mxCanvas(rOutDev.GetCanvas()), + maViewState(), + maRenderState(), + maBColorModifierStack(), + maDrawinglayerOpt(), + maClipPolyPolygon(), + meLang(LANGUAGE_SYSTEM) + { + const SvtCTLOptions aSvtCTLOptions; + + canvas::tools::initViewState(maViewState); + canvas::tools::initRenderState(maRenderState); + canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation()); + + // set digit language, derived from SvtCTLOptions to have the correct + // number display for arabic/hindi numerals + if(SvtCTLOptions::NUMERALS_HINDI == aSvtCTLOptions.GetCTLTextNumerals()) + { + meLang = LANGUAGE_ARABIC_SAUDI_ARABIA; + } + else if(SvtCTLOptions::NUMERALS_ARABIC == aSvtCTLOptions.GetCTLTextNumerals()) + { + meLang = LANGUAGE_ENGLISH; + } + else + { + meLang = (LanguageType)Application::GetSettings().GetLanguage(); + } + + rOutDev.SetDigitLanguage(meLang); + + // prepare output directly to pixels + mpOutputDevice->Push(PUSH_MAPMODE); + mpOutputDevice->SetMapMode(); + + // react on AntiAliasing settings + if(getOptionsDrawinglayer().IsAntiAliasing()) + { + mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() | ANTIALIASING_ENABLE_B2DDRAW); + } + else + { + mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() & ~ANTIALIASING_ENABLE_B2DDRAW); + } + } + + canvasProcessor2D::~canvasProcessor2D() + { + // restore MapMode + mpOutputDevice->Pop(); + + // restore AntiAliasing + mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() & ~ANTIALIASING_ENABLE_B2DDRAW); + } + } // end of namespace processor2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/processor2d/contourextractor2d.cxx b/drawinglayer/source/processor2d/contourextractor2d.cxx new file mode 100644 index 000000000000..1f629cb25c9c --- /dev/null +++ b/drawinglayer/source/processor2d/contourextractor2d.cxx @@ -0,0 +1,211 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: contourextractor2d.cxx,v $ + * + * $Revision: 1.6 $ + * + * last change: $Author: aw $ $Date: 2008-06-24 15:31:08 $ + * + * 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/processor2d/contourextractor2d.hxx> +#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> +#include <drawinglayer/primitive2d/polygonprimitive2d.hxx> +#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> +#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <drawinglayer/primitive2d/metafileprimitive2d.hxx> +#include <drawinglayer/primitive2d/alphaprimitive2d.hxx> +#include <drawinglayer/primitive2d/maskprimitive2d.hxx> +#include <drawinglayer/primitive2d/transformprimitive2d.hxx> +#include <drawinglayer/primitive2d/sceneprimitive2d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace processor2d + { + ContourExtractor2D::ContourExtractor2D(const geometry::ViewInformation2D& rViewInformation) + : BaseProcessor2D(rViewInformation), + maExtractedContour() + { + } + + ContourExtractor2D::~ContourExtractor2D() + { + } + + void ContourExtractor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate) + { + switch(rCandidate.getPrimitiveID()) + { + case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D : + { + // extract hairline in world coordinates + const primitive2d::PolygonHairlinePrimitive2D& rPolygonCandidate(static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate)); + basegfx::B2DPolygon aLocalPolygon(rPolygonCandidate.getB2DPolygon()); + aLocalPolygon.transform(getViewInformation2D().getObjectTransformation()); + + if(aLocalPolygon.isClosed()) + { + // line polygons need to be represented as open polygons to differentiate them + // from filled polygons + basegfx::tools::openWithGeometryChange(aLocalPolygon); + } + + maExtractedContour.push_back(basegfx::B2DPolyPolygon(aLocalPolygon)); + break; + } + case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D : + { + // extract fill in world coordinates + const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate(static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate)); + basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon()); + aLocalPolyPolygon.transform(getViewInformation2D().getObjectTransformation()); + maExtractedContour.push_back(aLocalPolyPolygon); + break; + } + case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D : + { + // extract BoundRect from bitmaps in world coordinates + const primitive2d::BitmapPrimitive2D& rBitmapCandidate(static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate)); + basegfx::B2DHomMatrix aLocalTransform(getViewInformation2D().getObjectTransformation() * rBitmapCandidate.getTransform()); + basegfx::B2DPolygon aPolygon(basegfx::tools::createPolygonFromRect(basegfx::B2DRange(0.0, 0.0, 1.0, 1.0))); + aPolygon.transform(aLocalTransform); + maExtractedContour.push_back(basegfx::B2DPolyPolygon(aPolygon)); + break; + } + case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D : + { + // extract BoundRect from MetaFiles in world coordinates + const primitive2d::MetafilePrimitive2D& rMetaCandidate(static_cast< const primitive2d::MetafilePrimitive2D& >(rCandidate)); + basegfx::B2DHomMatrix aLocalTransform(getViewInformation2D().getObjectTransformation() * rMetaCandidate.getTransform()); + basegfx::B2DPolygon aPolygon(basegfx::tools::createPolygonFromRect(basegfx::B2DRange(0.0, 0.0, 1.0, 1.0))); + aPolygon.transform(aLocalTransform); + maExtractedContour.push_back(basegfx::B2DPolyPolygon(aPolygon)); + break; + } + case PRIMITIVE2D_ID_ALPHAPRIMITIVE2D : + { + // sub-transparence group. Look at children + const primitive2d::AlphaPrimitive2D& rTransCandidate(static_cast< const primitive2d::AlphaPrimitive2D& >(rCandidate)); + process(rTransCandidate.getChildren()); + break; + } + case PRIMITIVE2D_ID_MASKPRIMITIVE2D : + { + // extract mask in world coordinates, ignore content + const primitive2d::MaskPrimitive2D& rMaskCandidate(static_cast< const primitive2d::MaskPrimitive2D& >(rCandidate)); + basegfx::B2DPolyPolygon aMask(rMaskCandidate.getMask()); + aMask.transform(getViewInformation2D().getObjectTransformation()); + maExtractedContour.push_back(basegfx::B2DPolyPolygon(aMask)); + break; + } + case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D : + { + // remember current ViewInformation2D + const primitive2d::TransformPrimitive2D& rTransformCandidate(static_cast< const primitive2d::TransformPrimitive2D& >(rCandidate)); + const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D()); + + // create new local ViewInformation2D + const geometry::ViewInformation2D aViewInformation2D( + getViewInformation2D().getObjectTransformation() * rTransformCandidate.getTransformation(), + getViewInformation2D().getViewTransformation(), + getViewInformation2D().getViewport(), + getViewInformation2D().getVisualizedPage(), + getViewInformation2D().getViewTime(), + getViewInformation2D().getExtendedInformationSequence()); + updateViewInformation(aViewInformation2D); + + // proccess content + process(rTransformCandidate.getChildren()); + + // restore transformations + updateViewInformation(aLastViewInformation2D); + + break; + } + case PRIMITIVE2D_ID_SCENEPRIMITIVE2D : + { + // 2D Scene primitive containing 3D stuff; extract 2D contour in world coordinates + const primitive2d::ScenePrimitive2D& rScenePrimitive2DCandidate(static_cast< const primitive2d::ScenePrimitive2D& >(rCandidate)); + const primitive2d::Primitive2DSequence xExtracted2DSceneGeometry(rScenePrimitive2DCandidate.getGeometry2D()); + const primitive2d::Primitive2DSequence xExtracted2DSceneShadow(rScenePrimitive2DCandidate.getShadow2D(getViewInformation2D())); + + // proccess content + if(xExtracted2DSceneGeometry.hasElements()) + { + process(xExtracted2DSceneGeometry); + } + + // proccess content + if(xExtracted2DSceneShadow.hasElements()) + { + process(xExtracted2DSceneShadow); + } + + break; + } + case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D : + case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D : + case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D : + { + // ignorable primitives + break; + } + case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D : + case PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D : + { + // primitives who's BoundRect will be added in world coordinates + basegfx::B2DRange aRange(rCandidate.getB2DRange(getViewInformation2D())); + aRange.transform(getViewInformation2D().getObjectTransformation()); + maExtractedContour.push_back(basegfx::B2DPolyPolygon(basegfx::tools::createPolygonFromRect(aRange))); + break; + } + default : + { + // process recursively + process(rCandidate.get2DDecomposition(getViewInformation2D())); + break; + } + } + } + + } // end of namespace processor2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/processor2d/helperchartrenderer.cxx b/drawinglayer/source/processor2d/helperchartrenderer.cxx new file mode 100644 index 000000000000..ffa8917ddec8 --- /dev/null +++ b/drawinglayer/source/processor2d/helperchartrenderer.cxx @@ -0,0 +1,163 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: helperchartrenderer.cxx,v $ + * + * $Revision: 1.1.2.1 $ + * + * last change: $Author: aw $ $Date: 2008/09/24 14:28:34 $ + * + * 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 <helperchartrenderer.hxx> +#include <drawinglayer/primitive2d/chartprimitive2d.hxx> +#include <svtools/chartprettypainter.hxx> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <drawinglayer/geometry/viewinformation2d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + bool renderChartPrimitive2D( + const primitive2d::ChartPrimitive2D& rChartCandidate, + OutputDevice& rOutputDevice, + const geometry::ViewInformation2D& rViewInformation2D) + { + bool bChartRendered(false); + + // code from chart PrettyPrinter + try + { + uno::Reference< lang::XMultiServiceFactory > xFact( rChartCandidate.getChartModel(), uno::UNO_QUERY ); + OSL_ENSURE( xFact.is(), "Chart cannot be painted pretty!\n" ); + + if( xFact.is() ) + { + uno::Reference< lang::XUnoTunnel > xChartRenderer( xFact->createInstance( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.chart2.ChartRenderer" ) ) ), uno::UNO_QUERY ); + OSL_ENSURE( xChartRenderer.is(), "Chart cannot be painted pretty!\n" ); + + if( xChartRenderer.is() ) + { + ChartPrettyPainter* pPrettyPainter = reinterpret_cast<ChartPrettyPainter*>( + xChartRenderer->getSomething( ChartPrettyPainter::getUnoTunnelId() )); + + if( pPrettyPainter ) + { + // create logic object range; do NOT use ObjectTransformation for this + // (rViewInformation2D.getObjectTransformation()), only the logic object + // size is wanted + basegfx::B2DRange aObjectRange(0.0, 0.0, 1.0, 1.0); + aObjectRange.transform(rChartCandidate.getTransformation()); + const Rectangle aRectangle( + (sal_Int32)aObjectRange.getMinX(), (sal_Int32)aObjectRange.getMinY(), + (sal_Int32)aObjectRange.getMaxX(), (sal_Int32)aObjectRange.getMaxY()); + + // #i101811# + if(rViewInformation2D.getObjectTransformation().isIdentity()) + { + // no embedding in another transfromation, just paint with existing + // MapMode. This is just a shortcut; using the below code will also + // work; it has just a neutral ObjectTransformation + bChartRendered = pPrettyPainter->DoPaint(&rOutputDevice, aRectangle); + } + else + { + // rViewInformation2D.getObjectTransformation() is used and + // needs to be expressed in the MapMode for the PrettyPainter; + // else it would call ChartModelHelper::setPageSize(...) with the + // changed size what really will change the chart model and leads + // to re-layouts and re-formattings + const MapMode aOldMapMode(rOutputDevice.GetMapMode()); + basegfx::B2DVector aVTScale, aScale, aTranslate; + double fRotate, fShearX; + + // get basic scaling with current MapMode (aVTScale), containing + // mapping for set MapUnit (e.g. for 100th mm, the basic scale is + // not 1.0, 1.0). This is needed since this scale is included in + // the ObjectToView Transformation and needs to be removed (see + // correction below) to re-create a MapMode + rOutputDevice.SetMapMode(aOldMapMode.GetMapUnit()); + rOutputDevice.GetViewTransformation().decompose(aVTScale, aTranslate, fRotate, fShearX); + + // get complete ObjectToView Transformation scale and translate from current + // transformation chain (combined view and object transform) + rViewInformation2D.getObjectToViewTransformation().decompose(aScale, aTranslate, fRotate, fShearX); + + // assert when shear and/or rotation is used + OSL_ENSURE(basegfx::fTools::equalZero(fRotate), "Chart PrettyPrinting with unsupportable rotation (!)"); + OSL_ENSURE(basegfx::fTools::equalZero(fShearX), "Chart PrettyPrinting with unsupportable shear (!)"); + + // clean scale and translate from basic scaling (DPI, etc...) + // since this will implicitely be part of the to-be-created MapMode + const basegfx::B2DTuple aBasicCleaner( + basegfx::fTools::equalZero(aVTScale.getX()) ? 1.0 : 1.0 / aVTScale.getX(), + basegfx::fTools::equalZero(aVTScale.getY()) ? 1.0 : 1.0 / aVTScale.getY()); + aScale *= aBasicCleaner; + aTranslate *= aBasicCleaner; + + // for MapMode, take scale out of translation + const basegfx::B2DTuple aScaleRemover( + basegfx::fTools::equalZero(aScale.getX()) ? 1.0 : 1.0 / aScale.getX(), + basegfx::fTools::equalZero(aScale.getY()) ? 1.0 : 1.0 / aScale.getY()); + aTranslate *= aScaleRemover; + + // build new MapMode + const MapMode aNewMapMode(aOldMapMode.GetMapUnit(), + Point(basegfx::fround(aTranslate.getX()), basegfx::fround(aTranslate.getY())), + Fraction(aScale.getX()), Fraction(aScale.getY())); + + // use, paint, restore + rOutputDevice.SetMapMode(aNewMapMode); + bChartRendered = pPrettyPainter->DoPaint(&rOutputDevice, aRectangle); + rOutputDevice.SetMapMode(aOldMapMode); + } + } + } + } + } + catch( uno::Exception& e ) + { + (void)e; + DBG_ERROR( "Chart cannot be painted pretty!" ); + } + + return bChartRendered; + } +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/processor2d/helperchartrenderer.hxx b/drawinglayer/source/processor2d/helperchartrenderer.hxx new file mode 100644 index 000000000000..4677698129c2 --- /dev/null +++ b/drawinglayer/source/processor2d/helperchartrenderer.hxx @@ -0,0 +1,68 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: helperchartrenderer.hxx,v $ + * + * $Revision: 1.1.2.1 $ + * + * last change: $Author: aw $ $Date: 2008/09/24 14:28:43 $ + * + * 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 + * + ************************************************************************/ + +#ifndef INCLUDED_DRAWINGLAYER_PROCESSOR2D_HELPERCHARTRENDER_HXX +#define INCLUDED_DRAWINGLAYER_PROCESSOR2D_HELPERCHARTRENDER_HXX + +#include <sal/types.h> + +////////////////////////////////////////////////////////////////////////////// +// predefines + +class OutputDevice; + +namespace drawinglayer { namespace primitive2d { class ChartPrimitive2D; }} +namespace drawinglayer { namespace geometry { class ViewInformation2D; }} + +////////////////////////////////////////////////////////////////////////////// +// support chart PrettyPrinter usage from primitives + +namespace drawinglayer +{ + // #i101811# + // Added current ViewInformation2D to take evtl. changed + // ObjectTransformation into account + bool renderChartPrimitive2D( + const primitive2d::ChartPrimitive2D& rChartCandidate, + OutputDevice& rOutputDevice, + const geometry::ViewInformation2D& rViewInformation2D); + +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +#endif // INCLUDED_DRAWINGLAYER_PROCESSOR2D_HELPERCHARTRENDER_HXX + +// eof diff --git a/drawinglayer/source/processor2d/helperwrongspellrenderer.cxx b/drawinglayer/source/processor2d/helperwrongspellrenderer.cxx new file mode 100644 index 000000000000..44524f9c3fef --- /dev/null +++ b/drawinglayer/source/processor2d/helperwrongspellrenderer.cxx @@ -0,0 +1,104 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: helperwrongspellrenderer.cxx,v $ + * + * $Revision: 1.1.2.1 $ + * + * last change: $Author: aw $ $Date: 2008/09/24 14:28:52 $ + * + * 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 <helperwrongspellrenderer.hxx> +#include <drawinglayer/primitive2d/wrongspellprimitive2d.hxx> +#include <tools/gen.hxx> +#include <vcl/outdev.hxx> +#include <basegfx/color/bcolormodifier.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + bool renderWrongSpellPrimitive2D( + const primitive2d::WrongSpellPrimitive2D& rWrongSpellCandidate, + OutputDevice& rOutputDevice, + const basegfx::B2DHomMatrix& rObjectToViewTransformation, + const basegfx::BColorModifierStack& rBColorModifierStack) + { + const basegfx::B2DHomMatrix aLocalTransform(rObjectToViewTransformation * rWrongSpellCandidate.getTransformation()); + const basegfx::B2DVector aFontVectorPixel(aLocalTransform * basegfx::B2DVector(0.0, 1.0)); + const sal_uInt32 nFontPixelHeight(basegfx::fround(aFontVectorPixel.getLength())); + + static const sal_uInt32 nMinimumFontHeight(5); // #define WRONG_SHOW_MIN 5 + static const sal_uInt32 nSmallFontHeight(11); // #define WRONG_SHOW_SMALL 11 + static const sal_uInt32 nMediumFontHeight(15); // #define WRONG_SHOW_MEDIUM 15 + + if(nFontPixelHeight > nMinimumFontHeight) + { + const basegfx::B2DPoint aStart(aLocalTransform * basegfx::B2DPoint(rWrongSpellCandidate.getStart(), 0.0)); + const basegfx::B2DPoint aStop(aLocalTransform * basegfx::B2DPoint(rWrongSpellCandidate.getStop(), 0.0)); + const Point aVclStart(basegfx::fround(aStart.getX()), basegfx::fround(aStart.getY())); + const Point aVclStop(basegfx::fround(aStop.getX()), basegfx::fround(aStop.getY())); + sal_uInt16 nWaveStyle(WAVE_FLAT); + + if(nFontPixelHeight > nMediumFontHeight) + { + nWaveStyle = WAVE_NORMAL; + } + else if(nFontPixelHeight > nSmallFontHeight) + { + nWaveStyle = WAVE_SMALL; + } + + // #i101075# draw it. Do not forget to use the evtl. offsetted origin of the target device, + // e.g. when used with mask/transparence buffer device + const Point aOrigin(rOutputDevice.GetMapMode().GetOrigin()); + + const basegfx::BColor aProcessedColor(rBColorModifierStack.getModifiedColor(rWrongSpellCandidate.getColor())); + const bool bMapModeEnabledState(rOutputDevice.IsMapModeEnabled()); + + rOutputDevice.EnableMapMode(false); + rOutputDevice.SetLineColor(Color(aProcessedColor)); + rOutputDevice.SetFillColor(); + rOutputDevice.DrawWaveLine(aOrigin + aVclStart, aOrigin + aVclStop, nWaveStyle); + rOutputDevice.EnableMapMode(bMapModeEnabledState); + } + + // cannot really go wrong + return true; + } +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/processor2d/helperwrongspellrenderer.hxx b/drawinglayer/source/processor2d/helperwrongspellrenderer.hxx new file mode 100644 index 000000000000..6d9938a72f4e --- /dev/null +++ b/drawinglayer/source/processor2d/helperwrongspellrenderer.hxx @@ -0,0 +1,73 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: helperwrongspellrenderer.hxx,v $ + * + * $Revision: 1.1.2.1 $ + * + * last change: $Author: aw $ $Date: 2008/09/24 14:29:02 $ + * + * 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 + * + ************************************************************************/ + +#ifndef INCLUDED_DRAWINGLAYER_PROCESSOR2D_HELPERWRONGSPELLRENDER_HXX +#define INCLUDED_DRAWINGLAYER_PROCESSOR2D_HELPERWRONGSPELLRENDER_HXX + +#include <sal/types.h> + +////////////////////////////////////////////////////////////////////////////// +// predefines + +class OutputDevice; + +namespace drawinglayer { namespace primitive2d { + class WrongSpellPrimitive2D; +}} + +namespace basegfx { + class B2DHomMatrix; + class BColorModifierStack; +} + +////////////////////////////////////////////////////////////////////////////// +// support WrongSpell rendreing using VCL from primitives due to VCLs nice +// and fast solution with wavelines + +namespace drawinglayer +{ + bool renderWrongSpellPrimitive2D( + const primitive2d::WrongSpellPrimitive2D& rWrongSpellCandidate, + OutputDevice& rOutputDevice, + const basegfx::B2DHomMatrix& rObjectToViewTransformation, + const basegfx::BColorModifierStack& rBColorModifierStack); + +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +#endif // INCLUDED_DRAWINGLAYER_PROCESSOR2D_HELPERWRONGSPELLRENDER_HXX + +// eof diff --git a/drawinglayer/source/processor2d/hittestprocessor2d.cxx b/drawinglayer/source/processor2d/hittestprocessor2d.cxx new file mode 100644 index 000000000000..4ffef7515389 --- /dev/null +++ b/drawinglayer/source/processor2d/hittestprocessor2d.cxx @@ -0,0 +1,563 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: contourextractor2d.cxx,v $ + * + * $Revision: 1.6 $ + * + * last change: $Author: aw $ $Date: 2008-06-24 15:31:08 $ + * + * 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/processor2d/hittestprocessor2d.hxx> +#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> +#include <drawinglayer/primitive2d/transformprimitive2d.hxx> +#include <drawinglayer/primitive2d/polygonprimitive2d.hxx> +#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <drawinglayer/primitive2d/alphaprimitive2d.hxx> +#include <drawinglayer/primitive2d/maskprimitive2d.hxx> +#include <drawinglayer/primitive2d/sceneprimitive2d.hxx> +#include <drawinglayer/primitive2d/hittestprimitive2d.hxx> +#include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx> +#include <basegfx/matrix/b3dhommatrix.hxx> +#include <drawinglayer/processor3d/cutfindprocessor3d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace processor2d + { + HitTestProcessor2D::HitTestProcessor2D(const geometry::ViewInformation2D& rViewInformation, + const basegfx::B2DPoint& rLogicHitPosition, + double fLogicHitTolerance, + bool bHitTextOnly) + : BaseProcessor2D(rViewInformation), + maDiscreteHitPosition(), + mfDiscreteHitTolerance(0.0), + mbHit(false), + mbHitToleranceUsed(false), + mbUseHitTestPrimitiveContent(true), + mbHitTextOnly(bHitTextOnly) + { + // init hit tolerance + mfDiscreteHitTolerance = fLogicHitTolerance; + + if(basegfx::fTools::less(mfDiscreteHitTolerance, 0.0)) + { + // ensure input parameter for hit tolerance is >= 0.0 + mfDiscreteHitTolerance = 0.0; + } + else if(basegfx::fTools::more(mfDiscreteHitTolerance, 0.0)) + { + // generate discrete hit tolerance + mfDiscreteHitTolerance = (getViewInformation2D().getObjectToViewTransformation() + * basegfx::B2DVector(mfDiscreteHitTolerance, 0.0)).getLength(); + } + + // gererate discrete hit position + maDiscreteHitPosition = getViewInformation2D().getObjectToViewTransformation() * rLogicHitPosition; + + // check if HitTolerance is used + mbHitToleranceUsed = basegfx::fTools::more(getDiscreteHitTolerance(), 0.0); + } + + HitTestProcessor2D::~HitTestProcessor2D() + { + } + + bool HitTestProcessor2D::checkHairlineHitWithTolerance( + const basegfx::B2DPolygon& rPolygon, + double fDiscreteHitTolerance) + { + basegfx::B2DPolygon aLocalPolygon(rPolygon); + aLocalPolygon.transform(getViewInformation2D().getObjectToViewTransformation()); + + // get discrete range + basegfx::B2DRange aPolygonRange(aLocalPolygon.getB2DRange()); + + if(basegfx::fTools::more(fDiscreteHitTolerance, 0.0)) + { + aPolygonRange.grow(fDiscreteHitTolerance); + } + + // do rough range test first + if(aPolygonRange.isInside(getDiscreteHitPosition())) + { + // check if a polygon edge is hit + return basegfx::tools::isInEpsilonRange( + aLocalPolygon, + getDiscreteHitPosition(), + fDiscreteHitTolerance); + } + + return false; + } + + bool HitTestProcessor2D::checkFillHitWithTolerance( + const basegfx::B2DPolyPolygon& rPolyPolygon, + double fDiscreteHitTolerance) + { + bool bRetval(false); + basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolyPolygon); + aLocalPolyPolygon.transform(getViewInformation2D().getObjectToViewTransformation()); + + // get discrete range + basegfx::B2DRange aPolygonRange(aLocalPolyPolygon.getB2DRange()); + const bool bDiscreteHitToleranceUsed(basegfx::fTools::more(fDiscreteHitTolerance, 0.0)); + + if(bDiscreteHitToleranceUsed) + { + aPolygonRange.grow(fDiscreteHitTolerance); + } + + // do rough range test first + if(aPolygonRange.isInside(getDiscreteHitPosition())) + { + // if a HitTolerance is given, check for polygon edge hit in epsilon first + if(bDiscreteHitToleranceUsed && + basegfx::tools::isInEpsilonRange( + aLocalPolyPolygon, + getDiscreteHitPosition(), + fDiscreteHitTolerance)) + { + bRetval = true; + } + + // check for hit in filled polyPolygon + if(!bRetval && basegfx::tools::isInside( + aLocalPolyPolygon, + getDiscreteHitPosition(), + true)) + { + bRetval = true; + } + } + + return bRetval; + } + + void HitTestProcessor2D::check3DHit(const primitive2d::ScenePrimitive2D& rCandidate) + { + // calculate relative point in unified 2D scene + const basegfx::B2DPoint aLogicHitPosition(getViewInformation2D().getInverseObjectToViewTransformation() * getDiscreteHitPosition()); + + // use bitmap check in ScenePrimitive2D + bool bTryFastResult(false); + + if(rCandidate.tryToCheckLastVisualisationDirectHit(aLogicHitPosition, bTryFastResult)) + { + mbHit = bTryFastResult; + } + else + { + basegfx::B2DHomMatrix aInverseSceneTransform(rCandidate.getObjectTransformation()); + aInverseSceneTransform.invert(); + const basegfx::B2DPoint aRelativePoint(aInverseSceneTransform * aLogicHitPosition); + + // check if test point is inside scene's unified area at all + if(aRelativePoint.getX() >= 0.0 && aRelativePoint.getX() <= 1.0 + && aRelativePoint.getY() >= 0.0 && aRelativePoint.getY() <= 1.0) + { + // get 3D view information + const geometry::ViewInformation3D& rObjectViewInformation3D = rCandidate.getViewInformation3D(); + + // create HitPoint Front and Back, transform to object coordinates + basegfx::B3DHomMatrix aViewToObject(rObjectViewInformation3D.getObjectToView()); + aViewToObject.invert(); + const basegfx::B3DPoint aFront(aViewToObject * basegfx::B3DPoint(aRelativePoint.getX(), aRelativePoint.getY(), 0.0)); + const basegfx::B3DPoint aBack(aViewToObject * basegfx::B3DPoint(aRelativePoint.getX(), aRelativePoint.getY(), 1.0)); + + if(!aFront.equal(aBack)) + { + const primitive3d::Primitive3DSequence& rPrimitives = rCandidate.getChildren3D(); + + if(rPrimitives.hasElements()) + { + // make BoundVolume empty and overlapping test for speedup + const basegfx::B3DRange aObjectRange( + drawinglayer::primitive3d::getB3DRangeFromPrimitive3DSequence( + rPrimitives, rObjectViewInformation3D)); + + if(!aObjectRange.isEmpty()) + { + const basegfx::B3DRange aFrontBackRange(aFront, aBack); + + if(aObjectRange.overlaps(aFrontBackRange)) + { + // bound volumes hit, geometric cut tests needed + drawinglayer::processor3d::CutFindProcessor aCutFindProcessor( + rObjectViewInformation3D, + aFront, + aBack, + true); + aCutFindProcessor.process(rPrimitives); + + mbHit = (0 != aCutFindProcessor.getCutPoints().size()); + } + } + } + } + } + + // This is needed to check hit with 3D shadows, too. HitTest is without shadow + // to keep compatible with previous versions. Keeping here as reference + // + // if(!getHit()) + // { + // // if scene has shadow, check hit with shadow, too + // const primitive2d::Primitive2DSequence xExtracted2DSceneShadow(rCandidate.getShadow2D(getViewInformation2D())); + // + // if(xExtracted2DSceneShadow.hasElements()) + // { + // // proccess extracted 2D content + // process(xExtracted2DSceneShadow); + // } + // } + + if(!getHit()) + { + // empty 3D scene; Check for border hit + basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(basegfx::B2DRange(0.0, 0.0, 1.0, 1.0))); + aOutline.transform(rCandidate.getObjectTransformation()); + + mbHit = checkHairlineHitWithTolerance(aOutline, getDiscreteHitTolerance()); + } + + // This is what the previous version did. Keeping it here for reference + // + // // 2D Scene primitive containing 3D stuff; extract 2D contour in world coordinates + // // This may be refined later to an own 3D HitTest renderer which processes the 3D + // // geometry directly + // const primitive2d::ScenePrimitive2D& rScenePrimitive2DCandidate(static_cast< const primitive2d::ScenePrimitive2D& >(rCandidate)); + // const primitive2d::Primitive2DSequence xExtracted2DSceneGeometry(rScenePrimitive2DCandidate.getGeometry2D()); + // const primitive2d::Primitive2DSequence xExtracted2DSceneShadow(rScenePrimitive2DCandidate.getShadow2D(getViewInformation2D())); + // + // if(xExtracted2DSceneGeometry.hasElements() || xExtracted2DSceneShadow.hasElements()) + // { + // // proccess extracted 2D content + // process(xExtracted2DSceneGeometry); + // process(xExtracted2DSceneShadow); + // } + // else + // { + // // empty 3D scene; Check for border hit + // const basegfx::B2DRange aRange(rCandidate.getB2DRange(getViewInformation2D())); + // if(!aRange.isEmpty()) + // { + // const basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(aRange)); + // mbHit = checkHairlineHitWithTolerance(aOutline, getDiscreteHitTolerance()); + // } + // } + } + } + + void HitTestProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate) + { + if(getHit()) + { + // stop processing as soon as a hit was recognized + return; + } + + switch(rCandidate.getPrimitiveID()) + { + case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D : + { + // remember current ViewInformation2D + const primitive2d::TransformPrimitive2D& rTransformCandidate(static_cast< const primitive2d::TransformPrimitive2D& >(rCandidate)); + const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D()); + + // create new local ViewInformation2D containing transformation + const geometry::ViewInformation2D aViewInformation2D( + getViewInformation2D().getObjectTransformation() * rTransformCandidate.getTransformation(), + getViewInformation2D().getViewTransformation(), + getViewInformation2D().getViewport(), + getViewInformation2D().getVisualizedPage(), + getViewInformation2D().getViewTime(), + getViewInformation2D().getExtendedInformationSequence()); + updateViewInformation(aViewInformation2D); + + // proccess child content recursively + process(rTransformCandidate.getChildren()); + + // restore transformations + updateViewInformation(aLastViewInformation2D); + + break; + } + case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D : + { + if(!getHitTextOnly()) + { + // create hairline in discrete coordinates + const primitive2d::PolygonHairlinePrimitive2D& rPolygonCandidate(static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate)); + + // use hairline test + mbHit = checkHairlineHitWithTolerance(rPolygonCandidate.getB2DPolygon(), getDiscreteHitTolerance()); + } + + break; + } + case PRIMITIVE2D_ID_POLYGONMARKERPRIMITIVE2D : + { + if(!getHitTextOnly()) + { + // handle marker like hairline; no need to decompose in dashes + const primitive2d::PolygonMarkerPrimitive2D& rPolygonCandidate(static_cast< const primitive2d::PolygonMarkerPrimitive2D& >(rCandidate)); + + // use hairline test + mbHit = checkHairlineHitWithTolerance(rPolygonCandidate.getB2DPolygon(), getDiscreteHitTolerance()); + } + + break; + } + case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D : + { + if(!getHitTextOnly()) + { + // handle stroke evtl. directly; no need to decompose to filled polygon outlines + const primitive2d::PolygonStrokePrimitive2D& rPolygonCandidate(static_cast< const primitive2d::PolygonStrokePrimitive2D& >(rCandidate)); + const attribute::LineAttribute& rLineAttribute = rPolygonCandidate.getLineAttribute(); + + if(basegfx::fTools::more(rLineAttribute.getWidth(), 0.0)) + { + if(basegfx::B2DLINEJOIN_MITER == rLineAttribute.getLineJoin()) + { + // if line is mitered, use decomposition since mitered line + // geometry may use more space than the geometry grown by half line width + process(rCandidate.get2DDecomposition(getViewInformation2D())); + } + else + { + // for all other B2DLINEJOIN_* do a hairline HitTest with expanded tolerance + const basegfx::B2DVector aDiscreteHalfLineVector(getViewInformation2D().getObjectToViewTransformation() + * basegfx::B2DVector(rLineAttribute.getWidth() * 0.5, 0.0)); + mbHit = checkHairlineHitWithTolerance( + rPolygonCandidate.getB2DPolygon(), + getDiscreteHitTolerance() + aDiscreteHalfLineVector.getLength()); + } + } + else + { + // hairline; fallback to hairline test. Do not decompose + // since this may decompose the hairline to dashes + mbHit = checkHairlineHitWithTolerance(rPolygonCandidate.getB2DPolygon(), getDiscreteHitTolerance()); + } + } + + break; + } + case PRIMITIVE2D_ID_POLYGONWAVEPRIMITIVE2D : + { + if(!getHitTextOnly()) + { + // do not use decompose; just handle like a line with width + const primitive2d::PolygonWavePrimitive2D& rPolygonCandidate(static_cast< const primitive2d::PolygonWavePrimitive2D& >(rCandidate)); + double fLogicHitTolerance(0.0); + + // if WaveHeight, grow by it + if(basegfx::fTools::more(rPolygonCandidate.getWaveHeight(), 0.0)) + { + fLogicHitTolerance += rPolygonCandidate.getWaveHeight(); + } + + // if line width, grow by it + if(basegfx::fTools::more(rPolygonCandidate.getLineAttribute().getWidth(), 0.0)) + { + fLogicHitTolerance += rPolygonCandidate.getLineAttribute().getWidth() * 0.5; + } + + const basegfx::B2DVector aDiscreteHalfLineVector(getViewInformation2D().getObjectToViewTransformation() + * basegfx::B2DVector(fLogicHitTolerance, 0.0)); + + mbHit = checkHairlineHitWithTolerance( + rPolygonCandidate.getB2DPolygon(), + getDiscreteHitTolerance() + aDiscreteHalfLineVector.getLength()); + } + + break; + } + case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D : + { + if(!getHitTextOnly()) + { + // create filled polyPolygon in discrete coordinates + const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate(static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate)); + + // use fill hit test + mbHit = checkFillHitWithTolerance(rPolygonCandidate.getB2DPolyPolygon(), getDiscreteHitTolerance()); + } + + break; + } + case PRIMITIVE2D_ID_ALPHAPRIMITIVE2D : + { + // sub-transparence group + const primitive2d::AlphaPrimitive2D& rTransCandidate(static_cast< const primitive2d::AlphaPrimitive2D& >(rCandidate)); + + // Currently the transparence content is not taken into account; only + // the children are recursively checked for hit. This may be refined for + // parts where the content is completely transparent if needed. + process(rTransCandidate.getChildren()); + + break; + } + case PRIMITIVE2D_ID_MASKPRIMITIVE2D : + { + // create mask in discrete coordinates; only recursively continue + // with content when HitTest position is inside the mask + const primitive2d::MaskPrimitive2D& rMaskCandidate(static_cast< const primitive2d::MaskPrimitive2D& >(rCandidate)); + + // use fill hit test + if(checkFillHitWithTolerance(rMaskCandidate.getMask(), getDiscreteHitTolerance())) + { + // recursively HitTest children + process(rMaskCandidate.getChildren()); + } + + break; + } + case PRIMITIVE2D_ID_SCENEPRIMITIVE2D : + { + if(!getHitTextOnly()) + { + const primitive2d::ScenePrimitive2D& rSceneCandidate(static_cast< const primitive2d::ScenePrimitive2D& >(rCandidate)); + check3DHit(rSceneCandidate); + } + + break; + } + case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D : + case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D : + case PRIMITIVE2D_ID_GRIDPRIMITIVE2D : + case PRIMITIVE2D_ID_HELPLINEPRIMITIVE2D : + { + // ignorable primitives + break; + } + case PRIMITIVE2D_ID_SHADOWPRIMITIVE2D : + { + // Ignore shadows; we do not want to have shadows hittable. + // Remove this one to make shadows hittable on demand. + break; + } + case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D : + case PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D : + { + // for text use the BoundRect of the primitive itself + const basegfx::B2DRange aRange(rCandidate.getB2DRange(getViewInformation2D())); + + if(!aRange.isEmpty()) + { + const basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(aRange)); + mbHit = checkFillHitWithTolerance(basegfx::B2DPolyPolygon(aOutline), getDiscreteHitTolerance()); + } + + break; + } + case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D : + case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D : + case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D : + case PRIMITIVE2D_ID_FILLGRADIENTPRIMITIVE2D : + case PRIMITIVE2D_ID_FILLHATCHPRIMITIVE2D : + case PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D : + { + if(!getHitTextOnly()) + { + // Class of primitives for which just the BoundRect of the primitive itself + // will be used for HitTest currently. + // + // This may be refined in the future, e.g: + // - For Bitamps, the mask and/or alpha information may be used + // - For MetaFiles, the MetaFile content may be used + const basegfx::B2DRange aRange(rCandidate.getB2DRange(getViewInformation2D())); + + if(!aRange.isEmpty()) + { + const basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(aRange)); + mbHit = checkFillHitWithTolerance(basegfx::B2DPolyPolygon(aOutline), getDiscreteHitTolerance()); + } + } + + break; + } + case PRIMITIVE2D_ID_HITTESTPRIMITIVE2D : + { + // HitTest primitive; the default decomposition would return an empty seqence, + // so force this primitive to process it's children directly if the switch is set + // (which is the default). Else, ignore invisible content + if(getUseHitTestPrimitiveContent()) + { + const primitive2d::HitTestPrimitive2D& rHitTestCandidate(static_cast< const primitive2d::HitTestPrimitive2D& >(rCandidate)); + process(rHitTestCandidate.getChildren()); + } + + break; + } + case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D : + { + if(!getHitTextOnly()) + { + const primitive2d::PointArrayPrimitive2D& rPointArrayCandidate(static_cast< const primitive2d::PointArrayPrimitive2D& >(rCandidate)); + const std::vector< basegfx::B2DPoint >& rPositions = rPointArrayCandidate.getPositions(); + const sal_uInt32 nCount(rPositions.size()); + + for(sal_uInt32 a(0); !getHit() && a < nCount; a++) + { + const basegfx::B2DPoint aPosition(getViewInformation2D().getObjectToViewTransformation() * rPositions[a]); + const basegfx::B2DVector aDistance(aPosition - getDiscreteHitPosition()); + + if(aDistance.getLength() <= getDiscreteHitTolerance()) + { + mbHit = true; + } + } + } + + break; + } + default : + { + // process recursively + process(rCandidate.get2DDecomposition(getViewInformation2D())); + + break; + } + } + } + + } // end of namespace processor2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/processor2d/linegeometryextractor2d.cxx b/drawinglayer/source/processor2d/linegeometryextractor2d.cxx new file mode 100644 index 000000000000..5f0ab63ee1b3 --- /dev/null +++ b/drawinglayer/source/processor2d/linegeometryextractor2d.cxx @@ -0,0 +1,152 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: linegeometryextractor2d.cxx,v $ + * + * $Revision: 1.1 $ + * + * last change: $Author: aw $ $Date: 2008-06-24 15:44:27 $ + * + * 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/processor2d/linegeometryextractor2d.hxx> +#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> +#include <drawinglayer/primitive2d/polygonprimitive2d.hxx> +#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> +#include <drawinglayer/primitive2d/transformprimitive2d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace processor2d + { + LineGeometryExtractor2D::LineGeometryExtractor2D(const geometry::ViewInformation2D& rViewInformation) + : BaseProcessor2D(rViewInformation), + maExtractedHairlines(), + maExtractedLineFills(), + mbInLineGeometry(false) + { + } + + LineGeometryExtractor2D::~LineGeometryExtractor2D() + { + } + + void LineGeometryExtractor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate) + { + switch(rCandidate.getPrimitiveID()) + { + case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D : + case PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D : + { + // enter a line geometry group (with or without LineEnds) + bool bOldState(mbInLineGeometry); + mbInLineGeometry = true; + process(rCandidate.get2DDecomposition(getViewInformation2D())); + mbInLineGeometry = bOldState; + break; + } + case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D : + { + if(mbInLineGeometry) + { + // extract hairline line geometry in world coordinates + const primitive2d::PolygonHairlinePrimitive2D& rPolygonCandidate(static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate)); + basegfx::B2DPolygon aLocalPolygon(rPolygonCandidate.getB2DPolygon()); + aLocalPolygon.transform(getViewInformation2D().getObjectTransformation()); + maExtractedHairlines.push_back(aLocalPolygon); + } + break; + } + case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D : + { + if(mbInLineGeometry) + { + // extract filled line geometry (line with width) + const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate(static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate)); + basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon()); + aLocalPolyPolygon.transform(getViewInformation2D().getObjectTransformation()); + maExtractedLineFills.push_back(aLocalPolyPolygon); + } + break; + } + case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D : + { + // remember current transformation and ViewInformation + const primitive2d::TransformPrimitive2D& rTransformCandidate(static_cast< const primitive2d::TransformPrimitive2D& >(rCandidate)); + const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D()); + + // create new transformations for CurrentTransformation and for local ViewInformation2D + const geometry::ViewInformation2D aViewInformation2D( + getViewInformation2D().getObjectTransformation() * rTransformCandidate.getTransformation(), + getViewInformation2D().getViewTransformation(), + getViewInformation2D().getViewport(), + getViewInformation2D().getVisualizedPage(), + getViewInformation2D().getViewTime(), + getViewInformation2D().getExtendedInformationSequence()); + updateViewInformation(aViewInformation2D); + + // proccess content + process(rTransformCandidate.getChildren()); + + // restore transformations + updateViewInformation(aLastViewInformation2D); + + break; + } + case PRIMITIVE2D_ID_SCENEPRIMITIVE2D : + case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D : + case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D : + case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D : + case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D : + case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D : + case PRIMITIVE2D_ID_MASKPRIMITIVE2D : + { + // ignorable primitives + break; + } + default : + { + // process recursively + process(rCandidate.get2DDecomposition(getViewInformation2D())); + break; + } + } + } + } // end of namespace processor2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/processor2d/makefile.mk b/drawinglayer/source/processor2d/makefile.mk new file mode 100644 index 000000000000..fcbf2413b61f --- /dev/null +++ b/drawinglayer/source/processor2d/makefile.mk @@ -0,0 +1,66 @@ +#************************************************************************* +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.8 $ +# +# last change: $Author: aw $ $Date: 2008-06-24 15:31:08 $ +# +# 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 +# +#************************************************************************* + +PRJ=..$/.. +PRJNAME=drawinglayer +TARGET=processor2d +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ---------------------------------- + +.INCLUDE : settings.mk + +# --- Files ------------------------------------- + +SLOFILES= \ + $(SLO)$/baseprocessor2d.obj \ + $(SLO)$/vclhelpergradient.obj \ + $(SLO)$/vclhelperbitmaptransform.obj \ + $(SLO)$/vclhelperbitmaprender.obj \ + $(SLO)$/vclhelperbufferdevice.obj \ + $(SLO)$/vclprocessor2d.obj \ + $(SLO)$/helperchartrenderer.obj \ + $(SLO)$/helperwrongspellrenderer.obj \ + $(SLO)$/vclpixelprocessor2d.obj \ + $(SLO)$/vclmetafileprocessor2d.obj \ + $(SLO)$/contourextractor2d.obj \ + $(SLO)$/linegeometryextractor2d.obj \ + $(SLO)$/canvasprocessor.obj \ + $(SLO)$/hittestprocessor2d.obj \ + $(SLO)$/textaspolygonextractor2d.obj + +# --- Targets ---------------------------------- + +.INCLUDE : target.mk diff --git a/drawinglayer/source/processor2d/textaspolygonextractor2d.cxx b/drawinglayer/source/processor2d/textaspolygonextractor2d.cxx new file mode 100644 index 000000000000..9358c7f39c57 --- /dev/null +++ b/drawinglayer/source/processor2d/textaspolygonextractor2d.cxx @@ -0,0 +1,255 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: contourextractor2d.cxx,v $ + * + * $Revision: 1.6 $ + * + * last change: $Author: aw $ $Date: 2008-06-24 15:31:08 $ + * + * 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/processor2d/textaspolygonextractor2d.hxx> +#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> +#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> +#include <drawinglayer/primitive2d/polygonprimitive2d.hxx> +#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx> +#include <drawinglayer/primitive2d/transformprimitive2d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace processor2d + { + void TextAsPolygonExtractor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate) + { + switch(rCandidate.getPrimitiveID()) + { + case PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D : + { + // TextDecoratedPortionPrimitive2D can produce the following primitives + // when being decomposed: + // + // - TextSimplePortionPrimitive2D + // - PolygonWavePrimitive2D + // - PolygonStrokePrimitive2D + // - PolygonStrokePrimitive2D + // - PolyPolygonColorPrimitive2D + // - PolyPolygonHairlinePrimitive2D + // - PolygonHairlinePrimitive2D + // - ShadowPrimitive2D + // - ModifiedColorPrimitive2D + // - TransformPrimitive2D + // - TextEffectPrimitive2D + // - ModifiedColorPrimitive2D + // - TransformPrimitive2D + // - GroupPrimitive2D + + // encapsulate with flag and use decomposition + mnInText++; + process(rCandidate.get2DDecomposition(getViewInformation2D())); + mnInText--; + + break; + } + case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D : + { + // TextSimplePortionPrimitive2D can produce the following primitives + // when being decomposed: + // + // - PolyPolygonColorPrimitive2D + // - TextEffectPrimitive2D + // - ModifiedColorPrimitive2D + // - TransformPrimitive2D + // - GroupPrimitive2D + + // encapsulate with flag and use decomposition + mnInText++; + process(rCandidate.get2DDecomposition(getViewInformation2D())); + mnInText--; + + break; + } + + // as can be seen from the TextSimplePortionPrimitive2D and the + // TextDecoratedPortionPrimitive2D, inside of the mnInText marks + // the following primitives can occurr containing geometry data + // from text decomposition: + // + // - PolyPolygonColorPrimitive2D + // - PolygonHairlinePrimitive2D + // - PolyPolygonHairlinePrimitive2D (for convenience) + // + case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D : + { + if(mnInText) + { + const primitive2d::PolyPolygonColorPrimitive2D& rPoPoCoCandidate(static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate)); + basegfx::B2DPolyPolygon aPolyPolygon(rPoPoCoCandidate.getB2DPolyPolygon()); + + if(aPolyPolygon.count()) + { + // transform the PolyPolygon + aPolyPolygon.transform(getViewInformation2D().getObjectToViewTransformation()); + + // get evtl. corrected color + const basegfx::BColor aColor(maBColorModifierStack.getModifiedColor(rPoPoCoCandidate.getBColor())); + + // add to result vector + maTarget.push_back(TextAsPolygonDataNode(aPolyPolygon, aColor, true)); + } + } + + break; + } + case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D : + { + if(mnInText) + { + const primitive2d::PolygonHairlinePrimitive2D& rPoHaCandidate(static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate)); + basegfx::B2DPolygon aPolygon(rPoHaCandidate.getB2DPolygon()); + + if(aPolygon.count()) + { + // transform the Polygon + aPolygon.transform(getViewInformation2D().getObjectToViewTransformation()); + + // get evtl. corrected color + const basegfx::BColor aColor(maBColorModifierStack.getModifiedColor(rPoHaCandidate.getBColor())); + + // add to result vector + maTarget.push_back(TextAsPolygonDataNode(basegfx::B2DPolyPolygon(aPolygon), aColor, false)); + } + } + + break; + } + case PRIMITIVE2D_ID_POLYPOLYGONHAIRLINEPRIMITIVE2D : + { + if(mnInText) + { + const primitive2d::PolyPolygonHairlinePrimitive2D& rPoPoHaCandidate(static_cast< const primitive2d::PolyPolygonHairlinePrimitive2D& >(rCandidate)); + basegfx::B2DPolyPolygon aPolyPolygon(rPoPoHaCandidate.getB2DPolyPolygon()); + + if(aPolyPolygon.count()) + { + // transform the Polygon + aPolyPolygon.transform(getViewInformation2D().getObjectToViewTransformation()); + + // get evtl. corrected color + const basegfx::BColor aColor(maBColorModifierStack.getModifiedColor(rPoPoHaCandidate.getBColor())); + + // add to result vector + maTarget.push_back(TextAsPolygonDataNode(aPolyPolygon, aColor, false)); + } + } + + break; + } + + // usage of color modification stack is needed + case PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D : + { + const primitive2d::ModifiedColorPrimitive2D& rModifiedColorCandidate(static_cast< const primitive2d::ModifiedColorPrimitive2D& >(rCandidate)); + + if(rModifiedColorCandidate.getChildren().hasElements()) + { + maBColorModifierStack.push(rModifiedColorCandidate.getColorModifier()); + process(rModifiedColorCandidate.getChildren()); + maBColorModifierStack.pop(); + } + + break; + } + + // usage of transformation stack is needed + case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D : + { + // remember current transformation and ViewInformation + const primitive2d::TransformPrimitive2D& rTransformCandidate(static_cast< const primitive2d::TransformPrimitive2D& >(rCandidate)); + const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D()); + + // create new transformations for CurrentTransformation and for local ViewInformation2D + const geometry::ViewInformation2D aViewInformation2D( + getViewInformation2D().getObjectTransformation() * rTransformCandidate.getTransformation(), + getViewInformation2D().getViewTransformation(), + getViewInformation2D().getViewport(), + getViewInformation2D().getVisualizedPage(), + getViewInformation2D().getViewTime(), + getViewInformation2D().getExtendedInformationSequence()); + updateViewInformation(aViewInformation2D); + + // proccess content + process(rTransformCandidate.getChildren()); + + // restore transformations + updateViewInformation(aLastViewInformation2D); + + break; + } + + // ignorable primitives + case PRIMITIVE2D_ID_SCENEPRIMITIVE2D : + case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D : + case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D : + case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D : + case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D : + case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D : + case PRIMITIVE2D_ID_MASKPRIMITIVE2D : + { + break; + } + + default : + { + // process recursively + process(rCandidate.get2DDecomposition(getViewInformation2D())); + break; + } + } + } + + TextAsPolygonExtractor2D::TextAsPolygonExtractor2D(const geometry::ViewInformation2D& rViewInformation) + : BaseProcessor2D(rViewInformation), + maTarget(), + maBColorModifierStack(), + mnInText(0) + { + } + + TextAsPolygonExtractor2D::~TextAsPolygonExtractor2D() + { + } + } // end of namespace processor2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/processor2d/vclhelperbitmaprender.cxx b/drawinglayer/source/processor2d/vclhelperbitmaprender.cxx new file mode 100644 index 000000000000..1488cd4fd054 --- /dev/null +++ b/drawinglayer/source/processor2d/vclhelperbitmaprender.cxx @@ -0,0 +1,278 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: vclhelperbitmaprender.cxx,v $ + * + * $Revision: 1.3 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:21 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <vclhelperbitmaprender.hxx> +#include <goodies/grfmgr.hxx> +#include <basegfx/vector/b2dvector.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/range/b2drange.hxx> +#include <vcl/outdev.hxx> +#include <vclhelperbitmaptransform.hxx> + +////////////////////////////////////////////////////////////////////////////// +// support for different kinds of bitmap rendering using vcl + +namespace drawinglayer +{ + void RenderBitmapPrimitive2D_GraphicManager( + OutputDevice& rOutDev, + const BitmapEx& rBitmapEx, + const basegfx::B2DHomMatrix& rTransform) + { + // prepare attributes + GraphicAttr aAttributes; + + // decompose matrix to check for shear, rotate and mirroring + basegfx::B2DVector aScale, aTranslate; + double fRotate, fShearX; + rTransform.decompose(aScale, aTranslate, fRotate, fShearX); + + // mirror flags + aAttributes.SetMirrorFlags( + (basegfx::fTools::less(aScale.getX(), 0.0) ? BMP_MIRROR_HORZ : 0)| + (basegfx::fTools::less(aScale.getY(), 0.0) ? BMP_MIRROR_VERT : 0)); + + // rotation + if(!basegfx::fTools::equalZero(fRotate)) + { + double fRotation(fmod(3600.0 - (fRotate * (10.0 / F_PI180)), 3600.0)); + aAttributes.SetRotation((sal_uInt16)(fRotation)); + } + + // prepare Bitmap + basegfx::B2DRange aOutlineRange(0.0, 0.0, 1.0, 1.0); + + if(basegfx::fTools::equalZero(fRotate)) + { + aOutlineRange.transform(rTransform); + } + else + { + // if rotated, create the unrotated output rectangle for the GraphicManager paint + basegfx::B2DHomMatrix aSimpleObjectMatrix; + + aSimpleObjectMatrix.scale(fabs(aScale.getX()), fabs(aScale.getY())); + aSimpleObjectMatrix.translate(aTranslate.getX(), aTranslate.getY()); + + aOutlineRange.transform(aSimpleObjectMatrix); + } + + // prepare dest coor + const Rectangle aDestRectPixel( + basegfx::fround(aOutlineRange.getMinX()), basegfx::fround(aOutlineRange.getMinY()), + basegfx::fround(aOutlineRange.getMaxX()), basegfx::fround(aOutlineRange.getMaxY())); + + // paint it using GraphicManager + Graphic aGraphic(rBitmapEx); + GraphicObject aGraphicObject(aGraphic); + aGraphicObject.Draw(&rOutDev, aDestRectPixel.TopLeft(), aDestRectPixel.GetSize(), &aAttributes); + } + + void RenderBitmapPrimitive2D_BitmapEx( + OutputDevice& rOutDev, + const BitmapEx& rBitmapEx, + const basegfx::B2DHomMatrix& rTransform) + { + // only translate and scale, use vcl's DrawBitmapEx(). + BitmapEx aContent(rBitmapEx); + + // prepare dest coor. Necessary to expand since vcl's DrawBitmapEx draws one pix less + basegfx::B2DRange aOutlineRange(0.0, 0.0, 1.0, 1.0); + aOutlineRange.transform(rTransform); + const Rectangle aDestRectPixel( + basegfx::fround(aOutlineRange.getMinX()), basegfx::fround(aOutlineRange.getMinY()), + basegfx::fround(aOutlineRange.getMaxX()), basegfx::fround(aOutlineRange.getMaxY())); + + // decompose matrix to check for shear, rotate and mirroring + basegfx::B2DVector aScale, aTranslate; + double fRotate, fShearX; + rTransform.decompose(aScale, aTranslate, fRotate, fShearX); + + // Check mirroring. + sal_uInt32 nMirrorFlags(BMP_MIRROR_NONE); + + if(basegfx::fTools::less(aScale.getX(), 0.0)) + { + nMirrorFlags |= BMP_MIRROR_HORZ; + } + + if(basegfx::fTools::less(aScale.getY(), 0.0)) + { + nMirrorFlags |= BMP_MIRROR_VERT; + } + + if(BMP_MIRROR_NONE != nMirrorFlags) + { + aContent.Mirror(nMirrorFlags); + } + + // draw bitmap + rOutDev.DrawBitmapEx(aDestRectPixel.TopLeft(), aDestRectPixel.GetSize(), aContent); + } + + void RenderBitmapPrimitive2D_self( + OutputDevice& rOutDev, + const BitmapEx& rBitmapEx, + const basegfx::B2DHomMatrix& rTransform) + { + // process self with free transformation (containing shear and rotate). Get dest rect in pixels. + basegfx::B2DRange aOutlineRange(0.0, 0.0, 1.0, 1.0); + aOutlineRange.transform(rTransform); + const Rectangle aDestRectLogic( + basegfx::fround(aOutlineRange.getMinX()), basegfx::fround(aOutlineRange.getMinY()), + basegfx::fround(aOutlineRange.getMaxX()), basegfx::fround(aOutlineRange.getMaxY())); + const Rectangle aDestRectPixel(rOutDev.LogicToPixel(aDestRectLogic)); + + // #i96708# check if Metafile is recorded + const GDIMetaFile* pMetaFile = rOutDev.GetConnectMetaFile(); + const bool bRecordToMetaFile(pMetaFile && pMetaFile->IsRecord() && !pMetaFile->IsPause()); + + // intersect with output pixel size, but only + // when not recording to metafile + const Rectangle aOutputRectPixel(Point(), rOutDev.GetOutputSizePixel()); + Rectangle aCroppedRectPixel(bRecordToMetaFile ? aDestRectPixel : aDestRectPixel.GetIntersection(aOutputRectPixel)); + + if(!aCroppedRectPixel.IsEmpty()) + { + // as maximum for destination, orientate at SourceSizePixel, but + // take a rotation of 45 degrees (sqrt(2)) as maximum expansion into account + const Size aSourceSizePixel(rBitmapEx.GetSizePixel()); + const double fMaximumArea( + (double)aSourceSizePixel.getWidth() * + (double)aSourceSizePixel.getHeight() * + 1.4142136); // 1.4142136 taken as sqrt(2.0) + + // test if discrete view size (pixel) maybe too big and limit it + const double fArea(aCroppedRectPixel.getWidth() * aCroppedRectPixel.getHeight()); + const bool bNeedToReduce(fArea > fMaximumArea); + double fReduceFactor(1.0); + + if(bNeedToReduce) + { + fReduceFactor = sqrt(fMaximumArea / fArea); + aCroppedRectPixel.setWidth(basegfx::fround(aCroppedRectPixel.getWidth() * fReduceFactor)); + aCroppedRectPixel.setHeight(basegfx::fround(aCroppedRectPixel.getHeight() * fReduceFactor)); + } + + // build transform from pixel in aDestination to pixel in rBitmapEx + basegfx::B2DHomMatrix aTransform; + + // from relative in aCroppedRectPixel to relative in aDestRectPixel + // No need to take bNeedToReduce into account, TopLeft is unchanged + aTransform.translate(aCroppedRectPixel.Left() - aDestRectPixel.Left(), aCroppedRectPixel.Top() - aDestRectPixel.Top()); + + // from relative in aDestRectPixel to absolute Logic. Here it + // is essential to adapt to reduce factor (if used) + double fAdaptedDRPWidth((double)aDestRectPixel.getWidth()); + double fAdaptedDRPHeight((double)aDestRectPixel.getHeight()); + + if(bNeedToReduce) + { + fAdaptedDRPWidth *= fReduceFactor; + fAdaptedDRPHeight *= fReduceFactor; + } + + aTransform.scale(aDestRectLogic.getWidth() / fAdaptedDRPWidth, aDestRectLogic.getHeight() / fAdaptedDRPHeight); + aTransform.translate(aDestRectLogic.Left(), aDestRectLogic.Top()); + + // from absolute in Logic to unified object coordinates (0.0 .. 1.0 in x and y) + basegfx::B2DHomMatrix aInvBitmapTransform(rTransform); + aInvBitmapTransform.invert(); + aTransform = aInvBitmapTransform * aTransform; + + // from unit object coordinates to rBitmapEx pixel coordintes + aTransform.scale(aSourceSizePixel.getWidth() - 1L, aSourceSizePixel.getHeight() - 1L); + + // create bitmap using source, destination and linear back-transformation + BitmapEx aDestination = impTransformBitmapEx(rBitmapEx, aCroppedRectPixel, aTransform); + + // paint + if(bNeedToReduce) + { + // paint in target size + const double fFactor(1.0 / fReduceFactor); + const Size aDestSizePixel( + basegfx::fround(aCroppedRectPixel.getWidth() * fFactor), + basegfx::fround(aCroppedRectPixel.getHeight() * fFactor)); + + if(bRecordToMetaFile) + { + rOutDev.DrawBitmapEx( + rOutDev.PixelToLogic(aCroppedRectPixel.TopLeft()), + rOutDev.PixelToLogic(aDestSizePixel), + aDestination); + } + else + { + const bool bWasEnabled(rOutDev.IsMapModeEnabled()); + rOutDev.EnableMapMode(false); + + rOutDev.DrawBitmapEx( + aCroppedRectPixel.TopLeft(), + aDestSizePixel, + aDestination); + + rOutDev.EnableMapMode(bWasEnabled); + } + } + else + { + if(bRecordToMetaFile) + { + rOutDev.DrawBitmapEx( + rOutDev.PixelToLogic(aCroppedRectPixel.TopLeft()), + aDestination); + } + else + { + const bool bWasEnabled(rOutDev.IsMapModeEnabled()); + rOutDev.EnableMapMode(false); + + rOutDev.DrawBitmapEx( + aCroppedRectPixel.TopLeft(), + aDestination); + + rOutDev.EnableMapMode(bWasEnabled); + } + } + } + } +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/processor2d/vclhelperbitmaprender.hxx b/drawinglayer/source/processor2d/vclhelperbitmaprender.hxx new file mode 100644 index 000000000000..6dccdd72a813 --- /dev/null +++ b/drawinglayer/source/processor2d/vclhelperbitmaprender.hxx @@ -0,0 +1,74 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: vclhelperbitmaprender.hxx,v $ + * + * $Revision: 1.2 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:21 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +#ifndef INCLUDED_DRAWINGLAYER_PROCESSOR2D_VCLHELPERBITMAPRENDER_HXX +#define INCLUDED_DRAWINGLAYER_PROCESSOR2D_VCLHELPERBITMAPRENDER_HXX + +#include <sal/types.h> + +////////////////////////////////////////////////////////////////////////////// +// predefines + +class OutputDevice; +class BitmapEx; +namespace basegfx { class B2DHomMatrix; } + +////////////////////////////////////////////////////////////////////////////// +// support methods for vcl direct gradient renderering + +namespace drawinglayer +{ + void RenderBitmapPrimitive2D_GraphicManager( + OutputDevice& rOutDev, + const BitmapEx& rBitmapEx, + const basegfx::B2DHomMatrix& rTransform); + + void RenderBitmapPrimitive2D_BitmapEx( + OutputDevice& rOutDev, + const BitmapEx& rBitmapEx, + const basegfx::B2DHomMatrix& rTransform); + + void RenderBitmapPrimitive2D_self( + OutputDevice& rOutDev, + const BitmapEx& rBitmapEx, + const basegfx::B2DHomMatrix& rTransform); + +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +#endif // INCLUDED_DRAWINGLAYER_PROCESSOR2D_VCLHELPERBITMAPRENDER_HXX + +// eof diff --git a/drawinglayer/source/processor2d/vclhelperbitmaptransform.cxx b/drawinglayer/source/processor2d/vclhelperbitmaptransform.cxx new file mode 100644 index 000000000000..15be4047c35a --- /dev/null +++ b/drawinglayer/source/processor2d/vclhelperbitmaptransform.cxx @@ -0,0 +1,439 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: vclhelperbitmaptransform.cxx,v $ + * + * $Revision: 1.4 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:21 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <vclhelperbitmaptransform.hxx> +#include <vcl/bmpacc.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/color/bcolormodifier.hxx> + +////////////////////////////////////////////////////////////////////////////// +// support for rendering Bitmap and BitmapEx contents + +namespace drawinglayer +{ + namespace + { + void impSmoothPoint(BitmapColor& rValue, const basegfx::B2DPoint& rSource, sal_Int32 nIntX, sal_Int32 nIntY, BitmapReadAccess& rRead) + { + double fDeltaX(rSource.getX() - nIntX); + double fDeltaY(rSource.getY() - nIntY); + sal_Int32 nIndX(0L); + sal_Int32 nIndY(0L); + + if(fDeltaX > 0.0 && nIntX + 1L < rRead.Width()) + { + nIndX++; + } + else if(fDeltaX < 0.0 && nIntX >= 1L) + { + fDeltaX = -fDeltaX; + nIndX--; + } + + if(fDeltaY > 0.0 && nIntY + 1L < rRead.Height()) + { + nIndY++; + } + else if(fDeltaY < 0.0 && nIntY >= 1L) + { + fDeltaY = -fDeltaY; + nIndY--; + } + + if(nIndX || nIndY) + { + const double fColorToReal(1.0 / 255.0); + double fR(rValue.GetRed() * fColorToReal); + double fG(rValue.GetGreen() * fColorToReal); + double fB(rValue.GetBlue() * fColorToReal); + double fRBottom(0.0), fGBottom(0.0), fBBottom(0.0); + + if(nIndX) + { + const double fMulA(fDeltaX * fColorToReal); + double fMulB(1.0 - fDeltaX); + const BitmapColor aTopPartner(rRead.GetColor(nIntY, nIntX + nIndX)); + + fR = (fR * fMulB) + (aTopPartner.GetRed() * fMulA); + fG = (fG * fMulB) + (aTopPartner.GetGreen() * fMulA); + fB = (fB * fMulB) + (aTopPartner.GetBlue() * fMulA); + + if(nIndY) + { + fMulB *= fColorToReal; + const BitmapColor aBottom(rRead.GetColor(nIntY + nIndY, nIntX)); + const BitmapColor aBottomPartner(rRead.GetColor(nIntY + nIndY, nIntX + nIndX)); + + fRBottom = (aBottom.GetRed() * fMulB) + (aBottomPartner.GetRed() * fMulA); + fGBottom = (aBottom.GetGreen() * fMulB) + (aBottomPartner.GetGreen() * fMulA); + fBBottom = (aBottom.GetBlue() * fMulB) + (aBottomPartner.GetBlue() * fMulA); + } + } + + if(nIndY) + { + if(!nIndX) + { + const BitmapColor aBottom(rRead.GetColor(nIntY + nIndY, nIntX)); + + fRBottom = aBottom.GetRed() * fColorToReal; + fGBottom = aBottom.GetGreen() * fColorToReal; + fBBottom = aBottom.GetBlue() * fColorToReal; + } + + const double fMulB(1.0 - fDeltaY); + + fR = (fR * fMulB) + (fRBottom * fDeltaY); + fG = (fG * fMulB) + (fGBottom * fDeltaY); + fB = (fB * fMulB) + (fBBottom * fDeltaY); + } + + rValue.SetRed((sal_uInt8)(fR * 255.0)); + rValue.SetGreen((sal_uInt8)(fG * 255.0)); + rValue.SetBlue((sal_uInt8)(fB * 255.0)); + } + } + + void impSmoothIndex(BitmapColor& rValue, const basegfx::B2DPoint& rSource, sal_Int32 nIntX, sal_Int32 nIntY, BitmapReadAccess& rRead) + { + double fDeltaX(rSource.getX() - nIntX); + double fDeltaY(rSource.getY() - nIntY); + sal_Int32 nIndX(0L); + sal_Int32 nIndY(0L); + + if(fDeltaX > 0.0 && nIntX + 1L < rRead.Width()) + { + nIndX++; + } + else if(fDeltaX < 0.0 && nIntX >= 1L) + { + fDeltaX = -fDeltaX; + nIndX--; + } + + if(fDeltaY > 0.0 && nIntY + 1L < rRead.Height()) + { + nIndY++; + } + else if(fDeltaY < 0.0 && nIntY >= 1L) + { + fDeltaY = -fDeltaY; + nIndY--; + } + + if(nIndX || nIndY) + { + const double fColorToReal(1.0 / 255.0); + double fVal(rValue.GetIndex() * fColorToReal); + double fValBottom(0.0); + + if(nIndX) + { + const double fMulA(fDeltaX * fColorToReal); + double fMulB(1.0 - fDeltaX); + const BitmapColor aTopPartner(rRead.GetPixel(nIntY, nIntX + nIndX)); + + fVal = (fVal * fMulB) + (aTopPartner.GetIndex() * fMulA); + + if(nIndY) + { + fMulB *= fColorToReal; + const BitmapColor aBottom(rRead.GetPixel(nIntY + nIndY, nIntX)); + const BitmapColor aBottomPartner(rRead.GetPixel(nIntY + nIndY, nIntX + nIndX)); + + fValBottom = (aBottom.GetIndex() * fMulB) + (aBottomPartner.GetIndex() * fMulA); + } + } + + if(nIndY) + { + if(!nIndX) + { + const BitmapColor aBottom(rRead.GetPixel(nIntY + nIndY, nIntX)); + + fValBottom = aBottom.GetIndex() * fColorToReal; + } + + const double fMulB(1.0 - fDeltaY); + + fVal = (fVal * fMulB) + (fValBottom * fDeltaY); + } + + rValue.SetIndex((sal_uInt8)(fVal * 255.0)); + } + } + + void impTransformBitmap(const Bitmap& rSource, Bitmap& rDestination, const basegfx::B2DHomMatrix& rTransform, bool bSmooth) + { + BitmapWriteAccess* pWrite = rDestination.AcquireWriteAccess(); + + if(pWrite) + { + const Size aContentSizePixel(rSource.GetSizePixel()); + BitmapReadAccess* pRead = (const_cast< Bitmap& >(rSource)).AcquireReadAccess(); + + if(pRead) + { + const Size aDestinationSizePixel(rDestination.GetSizePixel()); + bool bWorkWithIndex(rDestination.GetBitCount() <= 8); + BitmapColor aOutside(pRead->GetBestMatchingColor(BitmapColor(0xff, 0xff, 0xff))); + + for(sal_Int32 y(0L); y < aDestinationSizePixel.getHeight(); y++) + { + for(sal_Int32 x(0L); x < aDestinationSizePixel.getWidth(); x++) + { + const basegfx::B2DPoint aSourceCoor(rTransform * basegfx::B2DPoint(x, y)); + const sal_Int32 nIntX(basegfx::fround(aSourceCoor.getX())); + + if(nIntX >= 0L && nIntX < aContentSizePixel.getWidth()) + { + const sal_Int32 nIntY(basegfx::fround(aSourceCoor.getY())); + + if(nIntY >= 0L && nIntY < aContentSizePixel.getHeight()) + { + if(bWorkWithIndex) + { + BitmapColor aValue(pRead->GetPixel(nIntY, nIntX)); + + if(bSmooth) + { + impSmoothIndex(aValue, aSourceCoor, nIntX, nIntY, *pRead); + } + + pWrite->SetPixel(y, x, aValue); + } + else + { + BitmapColor aValue(pRead->GetColor(nIntY, nIntX)); + + if(bSmooth) + { + impSmoothPoint(aValue, aSourceCoor, nIntX, nIntY, *pRead); + } + + pWrite->SetPixel(y, x, aValue.IsIndex() ? aValue : pWrite->GetBestMatchingColor(aValue)); + } + + continue; + } + } + + // here are outside pixels. Complete mask + if(bWorkWithIndex) + { + pWrite->SetPixel(y, x, aOutside); + } + } + } + + delete pRead; + } + + delete pWrite; + } + } + + Bitmap impCreateEmptyBitmapWithPattern(const Bitmap& rSource, const Size& aTargetSizePixel) + { + Bitmap aRetval; + BitmapReadAccess* pReadAccess = (const_cast< Bitmap& >(rSource)).AcquireReadAccess(); + + if(pReadAccess) + { + if(rSource.GetBitCount() <= 8) + { + BitmapPalette aPalette(pReadAccess->GetPalette()); + aRetval = Bitmap(aTargetSizePixel, rSource.GetBitCount(), &aPalette); + } + else + { + aRetval = Bitmap(aTargetSizePixel, rSource.GetBitCount()); + } + + delete pReadAccess; + } + + return aRetval; + } + } // end of anonymous namespace +} // end of namespace drawinglayer + +namespace drawinglayer +{ + BitmapEx impTransformBitmapEx( + const BitmapEx& rSource, + const Rectangle& rCroppedRectPixel, + const basegfx::B2DHomMatrix& rTransform) + { + // force destination to 24 bit, we want to smooth output + const Size aDestinationSize(rCroppedRectPixel.GetSize()); + Bitmap aDestination(impCreateEmptyBitmapWithPattern(rSource.GetBitmap(), aDestinationSize)); + static bool bDoSmoothAtAll(true); + impTransformBitmap(rSource.GetBitmap(), aDestination, rTransform, bDoSmoothAtAll); + + // create mask + if(rSource.IsTransparent()) + { + if(rSource.IsAlpha()) + { + Bitmap aAlpha(impCreateEmptyBitmapWithPattern(rSource.GetAlpha().GetBitmap(), aDestinationSize)); + impTransformBitmap(rSource.GetAlpha().GetBitmap(), aAlpha, rTransform, bDoSmoothAtAll); + return BitmapEx(aDestination, AlphaMask(aAlpha)); + } + else + { + Bitmap aMask(impCreateEmptyBitmapWithPattern(rSource.GetMask(), aDestinationSize)); + impTransformBitmap(rSource.GetMask(), aMask, rTransform, false); + return BitmapEx(aDestination, aMask); + } + } + + return BitmapEx(aDestination); + } + + BitmapEx impModifyBitmapEx( + const basegfx::BColorModifierStack& rBColorModifierStack, + const BitmapEx& rSource) + { + Bitmap aChangedBitmap(rSource.GetBitmap()); + bool bDone(false); + + for(sal_uInt32 a(rBColorModifierStack.count()); a && !bDone; ) + { + const basegfx::BColorModifier& rModifier = rBColorModifierStack.getBColorModifier(--a); + + switch(rModifier.getMode()) + { + case basegfx::BCOLORMODIFYMODE_REPLACE : + { + // complete replace + if(rSource.IsTransparent()) + { + // clear bitmap with dest color + if(aChangedBitmap.GetBitCount() <= 8) + { + // do NOT use erase; for e.g. 8bit Bitmaps, the nearest color to the given + // erase color is determined and used -> this may be different from what is + // wanted here. Better create a new bitmap with the needed color explicitely + BitmapReadAccess* pReadAccess = aChangedBitmap.AcquireReadAccess(); + OSL_ENSURE(pReadAccess, "Got no Bitmap ReadAccess ?!?"); + + if(pReadAccess) + { + BitmapPalette aNewPalette(pReadAccess->GetPalette()); + aNewPalette[0] = BitmapColor(Color(rModifier.getBColor())); + aChangedBitmap = Bitmap( + aChangedBitmap.GetSizePixel(), + aChangedBitmap.GetBitCount(), + &aNewPalette); + delete pReadAccess; + } + } + else + { + aChangedBitmap.Erase(Color(rModifier.getBColor())); + } + } + else + { + // erase bitmap, caller will know to paint direct + aChangedBitmap.SetEmpty(); + } + + bDone = true; + break; + } + + default : // BCOLORMODIFYMODE_INTERPOLATE, BCOLORMODIFYMODE_GRAY, BCOLORMODIFYMODE_BLACKANDWHITE + { + BitmapWriteAccess* pContent = aChangedBitmap.AcquireWriteAccess(); + + if(pContent) + { + const double fConvertColor(1.0 / 255.0); + + for(sal_uInt32 y(0L); y < (sal_uInt32)pContent->Height(); y++) + { + for(sal_uInt32 x(0L); x < (sal_uInt32)pContent->Width(); x++) + { + const BitmapColor aBMCol(pContent->GetColor(y, x)); + const basegfx::BColor aBSource( + (double)aBMCol.GetRed() * fConvertColor, + (double)aBMCol.GetGreen() * fConvertColor, + (double)aBMCol.GetBlue() * fConvertColor); + const basegfx::BColor aBDest(rModifier.getModifiedColor(aBSource)); + + pContent->SetPixel(y, x, BitmapColor(Color(aBDest))); + } + } + + delete pContent; + } + + break; + } + } + } + + if(aChangedBitmap.IsEmpty()) + { + return BitmapEx(); + } + else + { + if(rSource.IsTransparent()) + { + if(rSource.IsAlpha()) + { + return BitmapEx(aChangedBitmap, rSource.GetAlpha()); + } + else + { + return BitmapEx(aChangedBitmap, rSource.GetMask()); + } + } + else + { + return BitmapEx(aChangedBitmap); + } + } + } +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/processor2d/vclhelperbitmaptransform.hxx b/drawinglayer/source/processor2d/vclhelperbitmaptransform.hxx new file mode 100644 index 000000000000..5fa0e66eea2f --- /dev/null +++ b/drawinglayer/source/processor2d/vclhelperbitmaptransform.hxx @@ -0,0 +1,68 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: vclhelperbitmaptransform.hxx,v $ + * + * $Revision: 1.2 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:22 $ + * + * 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 + * + ************************************************************************/ + +#ifndef INCLUDED_DRAWINGLAYER_PROCESSOR2D_VCLHELPERBITMAPTRANSFORM_HXX +#define INCLUDED_DRAWINGLAYER_PROCESSOR2D_VCLHELPERBITMAPTRANSFORM_HXX + +#include <vcl/bitmapex.hxx> + +////////////////////////////////////////////////////////////////////////////// +// predefines + +namespace basegfx { + class B2DHomMatrix; + class BColorModifierStack; +} + +////////////////////////////////////////////////////////////////////////////// +// support methods for vcl direct gradient renderering + +namespace drawinglayer +{ + BitmapEx impTransformBitmapEx( + const BitmapEx& rSource, + const Rectangle& rCroppedRectPixel, + const basegfx::B2DHomMatrix& rTransform); + + BitmapEx impModifyBitmapEx( + const basegfx::BColorModifierStack& rBColorModifierStack, + const BitmapEx& rSource); +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +#endif // INCLUDED_DRAWINGLAYER_PROCESSOR2D_VCLHELPERBITMAPTRANSFORM_HXX + +// eof diff --git a/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx b/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx new file mode 100644 index 000000000000..9d63bd5c7df6 --- /dev/null +++ b/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx @@ -0,0 +1,190 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: vclhelperbufferdevice.cxx,v $ + * + * $Revision: 1.6 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:22 $ + * + * 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 <vclhelperbufferdevice.hxx> +#include <basegfx/range/b2drange.hxx> +#include <vcl/bitmapex.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <tools/stream.hxx> + +////////////////////////////////////////////////////////////////////////////// +// support for rendering Bitmap and BitmapEx contents + +namespace drawinglayer +{ + impBufferDevice::impBufferDevice( + OutputDevice& rOutDev, + const basegfx::B2DRange& rRange, + bool bAddOffsetToMapping) + : mrOutDev(rOutDev), + maContent(rOutDev), + mpMask(0L), + mpAlpha(0L) + { + basegfx::B2DRange aRangePixel(rRange); + aRangePixel.transform(rOutDev.GetViewTransformation()); + const Rectangle aRectPixel( + (sal_Int32)floor(aRangePixel.getMinX()), (sal_Int32)floor(aRangePixel.getMinY()), + (sal_Int32)ceil(aRangePixel.getMaxX()), (sal_Int32)ceil(aRangePixel.getMaxY())); + const Point aEmptyPoint; + maDestPixel = Rectangle(aEmptyPoint, rOutDev.GetOutputSizePixel()); + maDestPixel.Intersection(aRectPixel); + + if(isVisible()) + { + maContent.SetOutputSizePixel(maDestPixel.GetSize(), false); + + // #i93485# assert when copying from window to VDev is used + OSL_ENSURE(rOutDev.GetOutDevType() != OUTDEV_WINDOW, + "impBufferDevice render helper: Copying from Window to VDev, this should be avoided (!)"); + + const bool bWasEnabledSrc(rOutDev.IsMapModeEnabled()); + rOutDev.EnableMapMode(false); + maContent.DrawOutDev(aEmptyPoint, maDestPixel.GetSize(), maDestPixel.TopLeft(), maDestPixel.GetSize(), rOutDev); + rOutDev.EnableMapMode(bWasEnabledSrc); + + MapMode aNewMapMode(rOutDev.GetMapMode()); + + if(bAddOffsetToMapping) + { + const Point aLogicTopLeft(rOutDev.PixelToLogic(maDestPixel.TopLeft())); + aNewMapMode.SetOrigin(Point(-aLogicTopLeft.X(), -aLogicTopLeft.Y())); + } + + maContent.SetMapMode(aNewMapMode); + + // copy AA flag for new target + maContent.SetAntialiasing(mrOutDev.GetAntialiasing()); + } + } + + impBufferDevice::~impBufferDevice() + { + delete mpMask; + delete mpAlpha; + } + + void impBufferDevice::paint(double fTrans) + { + const Point aEmptyPoint; + const Size aSizePixel(maContent.GetOutputSizePixel()); + const bool bWasEnabledDst(mrOutDev.IsMapModeEnabled()); + static bool bDoSaveForVisualControl(false); + + mrOutDev.EnableMapMode(false); + maContent.EnableMapMode(false); + Bitmap aContent(maContent.GetBitmap(aEmptyPoint, aSizePixel)); + + if(bDoSaveForVisualControl) + { + SvFileStream aNew((const String&)String(ByteString( "c:\\content.bmp" ), RTL_TEXTENCODING_UTF8), STREAM_WRITE|STREAM_TRUNC); + aNew << aContent; + } + + if(mpAlpha) + { + mpAlpha->EnableMapMode(false); + const AlphaMask aAlphaMask(mpAlpha->GetBitmap(aEmptyPoint, aSizePixel)); + + if(bDoSaveForVisualControl) + { + SvFileStream aNew((const String&)String(ByteString( "c:\\alpha.bmp" ), RTL_TEXTENCODING_UTF8), STREAM_WRITE|STREAM_TRUNC); + aNew << aAlphaMask.GetBitmap(); + } + + mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aAlphaMask)); + } + else if(mpMask) + { + mpMask->EnableMapMode(false); + const Bitmap aMask(mpMask->GetBitmap(aEmptyPoint, aSizePixel)); + + if(bDoSaveForVisualControl) + { + SvFileStream aNew((const String&)String(ByteString( "c:\\mask.bmp" ), RTL_TEXTENCODING_UTF8), STREAM_WRITE|STREAM_TRUNC); + aNew << aMask; + } + + mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aMask)); + } + else if(0.0 != fTrans) + { + sal_uInt8 nMaskValue((sal_uInt8)basegfx::fround(fTrans * 255.0)); + const AlphaMask aAlphaMask(aSizePixel, &nMaskValue); + mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aAlphaMask)); + } + else + { + mrOutDev.DrawBitmap(maDestPixel.TopLeft(), aContent); + } + + mrOutDev.EnableMapMode(bWasEnabledDst); + } + + VirtualDevice& impBufferDevice::getMask() + { + if(!mpMask) + { + mpMask = new VirtualDevice(mrOutDev, 1); + mpMask->SetOutputSizePixel(maDestPixel.GetSize(), true); + mpMask->SetMapMode(maContent.GetMapMode()); + + // do NOT copy AA flag for mask! + } + + return *mpMask; + } + + VirtualDevice& impBufferDevice::getAlpha() + { + if(!mpAlpha) + { + mpAlpha = new VirtualDevice(); + mpAlpha->SetOutputSizePixel(maDestPixel.GetSize(), true); + mpAlpha->SetMapMode(maContent.GetMapMode()); + + // copy AA flag for new target; masking needs to be smooth + mpAlpha->SetAntialiasing(maContent.GetAntialiasing()); + } + + return *mpAlpha; + } +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/processor2d/vclhelperbufferdevice.hxx b/drawinglayer/source/processor2d/vclhelperbufferdevice.hxx new file mode 100644 index 000000000000..f987585249ad --- /dev/null +++ b/drawinglayer/source/processor2d/vclhelperbufferdevice.hxx @@ -0,0 +1,78 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: vclhelperbufferdevice.hxx,v $ + * + * $Revision: 1.2 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:22 $ + * + * 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 + * + ************************************************************************/ + +#ifndef INCLUDED_DRAWINGLAYER_PROCESSOR2D_VCLHELPERBUFFERDEVICE_HXX +#define INCLUDED_DRAWINGLAYER_PROCESSOR2D_VCLHELPERBUFFERDEVICE_HXX + +#include <vcl/virdev.hxx> + +////////////////////////////////////////////////////////////////////////////// +// predefines + +namespace basegfx { class B2DRange; } + +////////////////////////////////////////////////////////////////////////////// +// support methods for vcl direct gradient renderering + +namespace drawinglayer +{ + class impBufferDevice + { + OutputDevice& mrOutDev; + VirtualDevice maContent; + VirtualDevice* mpMask; + VirtualDevice* mpAlpha; + Rectangle maDestPixel; + + public: + impBufferDevice( + OutputDevice& rOutDev, + const basegfx::B2DRange& rRange, + bool bAddOffsetToMapping); + ~impBufferDevice(); + + void paint(double fTrans = 0.0); + bool isVisible() const { return !maDestPixel.IsEmpty(); } + VirtualDevice& getContent() { return maContent; } + VirtualDevice& getMask(); + VirtualDevice& getAlpha(); + }; +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +#endif // INCLUDED_DRAWINGLAYER_PROCESSOR2D_VCLHELPERBUFFERDEVICE_HXX + +// eof diff --git a/drawinglayer/source/processor2d/vclhelpergradient.cxx b/drawinglayer/source/processor2d/vclhelpergradient.cxx new file mode 100644 index 000000000000..25d7513006fa --- /dev/null +++ b/drawinglayer/source/processor2d/vclhelpergradient.cxx @@ -0,0 +1,297 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: vclhelpergradient.cxx,v $ + * + * $Revision: 1.5 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:22 $ + * + * 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 <vclhelpergradient.hxx> +#include <basegfx/range/b2drange.hxx> +#include <vcl/outdev.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <drawinglayer/texture/texture.hxx> + +////////////////////////////////////////////////////////////////////////////// +// support methods for vcl direct gradient renderering + +namespace drawinglayer +{ + namespace + { + sal_uInt32 impCalcGradientSteps(OutputDevice& rOutDev, sal_uInt32 nSteps, const basegfx::B2DRange& rRange, sal_uInt32 nMaxDist) + { + if(nSteps == 0L) + { + const Size aSize(rOutDev.LogicToPixel(Size(basegfx::fround(rRange.getWidth()), basegfx::fround(rRange.getHeight())))); + nSteps = (aSize.getWidth() + aSize.getHeight()) >> 3L; + } + + if(nSteps < 2L) + { + nSteps = 2L; + } + + if(nSteps > nMaxDist) + { + nSteps = nMaxDist; + } + + return nSteps; + } + + void impDrawGradientToOutDevSimple( + OutputDevice& rOutDev, + const basegfx::B2DPolyPolygon& rTargetForm, + const ::std::vector< basegfx::B2DHomMatrix >& rMatrices, + const ::std::vector< basegfx::BColor >& rColors, + const basegfx::B2DPolygon& rUnitPolygon) + { + rOutDev.SetLineColor(); + + for(sal_uInt32 a(0L); a < rColors.size(); a++) + { + // set correct color + const basegfx::BColor aFillColor(rColors[a]); + rOutDev.SetFillColor(Color(aFillColor)); + + if(a) + { + if(a - 1L < static_cast< sal_uInt32 >(rMatrices.size())) + { + basegfx::B2DPolygon aNewPoly(rUnitPolygon); + aNewPoly.transform(rMatrices[a - 1L]); + rOutDev.DrawPolygon(aNewPoly); + } + } + else + { + rOutDev.DrawPolyPolygon(rTargetForm); + } + } + } + + void impDrawGradientToOutDevComplex( + OutputDevice& rOutDev, + const basegfx::B2DPolyPolygon& rTargetForm, + const ::std::vector< basegfx::B2DHomMatrix >& rMatrices, + const ::std::vector< basegfx::BColor >& rColors, + const basegfx::B2DPolygon& rUnitPolygon) + { + PolyPolygon aVclTargetForm(rTargetForm); + ::std::vector< Polygon > aVclPolygons; + sal_uInt32 a; + + // remember and set to XOR + rOutDev.SetLineColor(); + rOutDev.Push(PUSH_RASTEROP); + rOutDev.SetRasterOp(ROP_XOR); + + // draw gradient PolyPolygons + for(a = 0L; a < rMatrices.size(); a++) + { + // create polygon and remember + basegfx::B2DPolygon aNewPoly(rUnitPolygon); + aNewPoly.transform(rMatrices[a]); + aVclPolygons.push_back(Polygon(aNewPoly)); + + // set correct color + if(rColors.size() > a) + { + const basegfx::BColor aFillColor(rColors[a]); + rOutDev.SetFillColor(Color(aFillColor)); + } + + // create vcl PolyPolygon and draw it + if(a) + { + PolyPolygon aVclPolyPoly(aVclPolygons[a - 1L]); + aVclPolyPoly.Insert(aVclPolygons[a]); + rOutDev.DrawPolyPolygon(aVclPolyPoly); + } + else + { + PolyPolygon aVclPolyPoly(aVclTargetForm); + aVclPolyPoly.Insert(aVclPolygons[0L]); + rOutDev.DrawPolyPolygon(aVclPolyPoly); + } + } + + // draw last poly in last color + if(rColors.size()) + { + const basegfx::BColor aFillColor(rColors[rColors.size() - 1L]); + rOutDev.SetFillColor(Color(aFillColor)); + rOutDev.DrawPolygon(aVclPolygons[aVclPolygons.size() - 1L]); + } + + // draw object form in black and go back to XOR + rOutDev.SetFillColor(COL_BLACK); + rOutDev.SetRasterOp(ROP_0); + rOutDev.DrawPolyPolygon(aVclTargetForm); + rOutDev.SetRasterOp(ROP_XOR); + + // draw gradient PolyPolygons again + for(a = 0L; a < rMatrices.size(); a++) + { + // set correct color + if(rColors.size() > a) + { + const basegfx::BColor aFillColor(rColors[a]); + rOutDev.SetFillColor(Color(aFillColor)); + } + + // create vcl PolyPolygon and draw it + if(a) + { + PolyPolygon aVclPolyPoly(aVclPolygons[a - 1L]); + aVclPolyPoly.Insert(aVclPolygons[a]); + rOutDev.DrawPolyPolygon(aVclPolyPoly); + } + else + { + PolyPolygon aVclPolyPoly(aVclTargetForm); + aVclPolyPoly.Insert(aVclPolygons[0L]); + rOutDev.DrawPolyPolygon(aVclPolyPoly); + } + } + + // draw last poly in last color + if(rColors.size()) + { + const basegfx::BColor aFillColor(rColors[rColors.size() - 1L]); + rOutDev.SetFillColor(Color(aFillColor)); + rOutDev.DrawPolygon(aVclPolygons[aVclPolygons.size() - 1L]); + } + + // reset drawmode + rOutDev.Pop(); + } + } // end of anonymous namespace +} // end of namespace drawinglayer + +namespace drawinglayer +{ + void impDrawGradientToOutDev( + OutputDevice& rOutDev, + const basegfx::B2DPolyPolygon& rTargetForm, + attribute::GradientStyle eGradientStyle, + sal_uInt32 nSteps, + const basegfx::BColor& rStart, + const basegfx::BColor& rEnd, + double fBorder, double fAngle, double fOffsetX, double fOffsetY, bool bSimple) + { + const basegfx::B2DRange aOutlineRange(basegfx::tools::getRange(rTargetForm)); + ::std::vector< basegfx::B2DHomMatrix > aMatrices; + ::std::vector< basegfx::BColor > aColors; + basegfx::B2DPolygon aUnitPolygon; + + if(attribute::GRADIENTSTYLE_RADIAL == eGradientStyle || attribute::GRADIENTSTYLE_ELLIPTICAL == eGradientStyle) + { + const basegfx::B2DPoint aCircleCenter(0.5, 0.5); + aUnitPolygon = basegfx::tools::createPolygonFromEllipse(aCircleCenter, 0.5, 0.5); + } + else + { + aUnitPolygon = basegfx::tools::createPolygonFromRect(basegfx::B2DRange(0.0, 0.0, 1.0, 1.0)); + } + + // make sure steps is not too high/low + nSteps = impCalcGradientSteps(rOutDev, nSteps, aOutlineRange, sal_uInt32((rStart.getMaximumDistance(rEnd) * 127.5) + 0.5)); + + // create geometries + switch(eGradientStyle) + { + case attribute::GRADIENTSTYLE_LINEAR: + { + texture::GeoTexSvxGradientLinear aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fAngle); + aGradient.appendTransformations(aMatrices); + aGradient.appendColors(aColors); + break; + } + case attribute::GRADIENTSTYLE_AXIAL: + { + texture::GeoTexSvxGradientAxial aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fAngle); + aGradient.appendTransformations(aMatrices); + aGradient.appendColors(aColors); + break; + } + case attribute::GRADIENTSTYLE_RADIAL: + { + texture::GeoTexSvxGradientRadial aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fOffsetX, fOffsetY); + aGradient.appendTransformations(aMatrices); + aGradient.appendColors(aColors); + break; + } + case attribute::GRADIENTSTYLE_ELLIPTICAL: + { + texture::GeoTexSvxGradientElliptical aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fOffsetX, fOffsetX, fAngle); + aGradient.appendTransformations(aMatrices); + aGradient.appendColors(aColors); + break; + } + case attribute::GRADIENTSTYLE_SQUARE: + { + texture::GeoTexSvxGradientSquare aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fOffsetX, fOffsetX, fAngle); + aGradient.appendTransformations(aMatrices); + aGradient.appendColors(aColors); + break; + } + case attribute::GRADIENTSTYLE_RECT: + { + texture::GeoTexSvxGradientRect aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fOffsetX, fOffsetX, fAngle); + aGradient.appendTransformations(aMatrices); + aGradient.appendColors(aColors); + break; + } + } + + // paint them with mask using the XOR method + if(aMatrices.size()) + { + if(bSimple) + { + impDrawGradientToOutDevSimple(rOutDev, rTargetForm, aMatrices, aColors, aUnitPolygon); + } + else + { + impDrawGradientToOutDevComplex(rOutDev, rTargetForm, aMatrices, aColors, aUnitPolygon); + } + } + } +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/processor2d/vclhelpergradient.hxx b/drawinglayer/source/processor2d/vclhelpergradient.hxx new file mode 100644 index 000000000000..e1671dbb87b2 --- /dev/null +++ b/drawinglayer/source/processor2d/vclhelpergradient.hxx @@ -0,0 +1,69 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: vclhelpergradient.hxx,v $ + * + * $Revision: 1.2 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:22 $ + * + * 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 + * + ************************************************************************/ + +#ifndef INCLUDED_DRAWINGLAYER_PROCESSOR2D_VCLHELPERGRADIENT_HXX +#define INCLUDED_DRAWINGLAYER_PROCESSOR2D_VCLHELPERGRADIENT_HXX + +#include <drawinglayer/attribute/fillattribute.hxx> + +////////////////////////////////////////////////////////////////////////////// +// predefines + +class OutputDevice; +namespace basegfx { + class B2DPolyPolygon; + class BColor; +} + +////////////////////////////////////////////////////////////////////////////// +// support methods for vcl direct gradient renderering + +namespace drawinglayer +{ + void impDrawGradientToOutDev( + OutputDevice& rOutDev, + const basegfx::B2DPolyPolygon& rTargetForm, + attribute::GradientStyle eGradientStyle, + sal_uInt32 nSteps, + const basegfx::BColor& rStart, + const basegfx::BColor& rEnd, + double fBorder, double fAngle, double fOffsetX, double fOffsetY, bool bSimple); +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +#endif // INCLUDED_DRAWINGLAYER_PROCESSOR2D_VCLHELPERGRADIENT_HXX + +// eof diff --git a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx new file mode 100644 index 000000000000..d1190c2d9179 --- /dev/null +++ b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx @@ -0,0 +1,1769 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: vclmetafileprocessor2d.cxx,v $ + * + * $Revision: 1.25 $ + * + * last change: $Author: aw $ $Date: 2008-07-21 17:41:18 $ + * + * 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/processor2d/vclmetafileprocessor2d.hxx> +#include <tools/gen.hxx> +#include <vcl/virdev.hxx> +#include <vcl/gdimtf.hxx> +#include <vcl/gradient.hxx> +#include <drawinglayer/attribute/fillattribute.hxx> +#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> +#include <drawinglayer/primitive2d/textprimitive2d.hxx> +#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> +#include <drawinglayer/primitive2d/polygonprimitive2d.hxx> +#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> +#include <drawinglayer/primitive2d/metafileprimitive2d.hxx> +#include <drawinglayer/primitive2d/maskprimitive2d.hxx> +#include <basegfx/polygon/b2dpolygonclipper.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx> +#include <drawinglayer/primitive2d/unifiedalphaprimitive2d.hxx> +#include <drawinglayer/primitive2d/alphaprimitive2d.hxx> +#include <drawinglayer/primitive2d/fillgradientprimitive2d.hxx> +#include <drawinglayer/processor2d/vclpixelprocessor2d.hxx> +#include <tools/stream.hxx> +#include <drawinglayer/primitive2d/transformprimitive2d.hxx> +#include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx> +#include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx> +#include <vcl/graphictools.hxx> +#include <vcl/metaact.hxx> +#include <drawinglayer/primitive2d/texthierarchyprimitive2d.hxx> +#include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx> +#include <comphelper/processfactory.hxx> +#include <rtl/ustring.hxx> +#include <com/sun/star/i18n/CharacterIteratorMode.hdl> +#include <com/sun/star/i18n/WordType.hpp> +#include <drawinglayer/primitive2d/controlprimitive2d.hxx> +#include <drawinglayer/primitive2d/graphicprimitive2d.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx> +#include <helperchartrenderer.hxx> +#include <drawinglayer/primitive2d/hittestprimitive2d.hxx> + +////////////////////////////////////////////////////////////////////////////// +// for PDFExtOutDevData Graphic support + +#include <vcl/graph.hxx> +#include <vcl/svapp.hxx> +#include <toolkit/helper/formpdfexport.hxx> + +////////////////////////////////////////////////////////////////////////////// +// for Control printing + +#include <com/sun/star/beans/XPropertySet.hpp> + +////////////////////////////////////////////////////////////////////////////// +// for current chart PrettyPrinting support + +#include <drawinglayer/primitive2d/chartprimitive2d.hxx> + +////////////////////////////////////////////////////////////////////////////// +// for StructureTagPrimitive support in sd's unomodel.cxx + +#include <drawinglayer/primitive2d/structuretagprimitive2d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace processor2d + { + Rectangle VclMetafileProcessor2D::impDumpToMetaFile( + const primitive2d::Primitive2DSequence& rContent, + GDIMetaFile& o_rContentMetafile) + { + // Prepare VDev, MetaFile and connections + OutputDevice* pLastOutputDevice = mpOutputDevice; + GDIMetaFile* pLastMetafile = mpMetaFile; + basegfx::B2DRange aPrimitiveRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rContent, getViewInformation2D())); + + // transform primitive range with current transformation (e.g shadow offset) + aPrimitiveRange.transform(maCurrentTransformation); + + const Rectangle aPrimitiveRectangle( + basegfx::fround(aPrimitiveRange.getMinX()), basegfx::fround(aPrimitiveRange.getMinY()), + basegfx::fround(aPrimitiveRange.getMaxX()), basegfx::fround(aPrimitiveRange.getMaxY())); + VirtualDevice aContentVDev; + MapMode aNewMapMode(pLastOutputDevice->GetMapMode()); + + mpOutputDevice = &aContentVDev; + mpMetaFile = &o_rContentMetafile; + aContentVDev.EnableOutput(false); + aContentVDev.SetMapMode(pLastOutputDevice->GetMapMode()); + o_rContentMetafile.Record(&aContentVDev); + aContentVDev.SetLineColor(pLastOutputDevice->GetLineColor()); + aContentVDev.SetFillColor(pLastOutputDevice->GetFillColor()); + aContentVDev.SetFont(pLastOutputDevice->GetFont()); + aContentVDev.SetDrawMode(pLastOutputDevice->GetDrawMode()); + aContentVDev.SetSettings(pLastOutputDevice->GetSettings()); + aContentVDev.SetRefPoint(pLastOutputDevice->GetRefPoint()); + + // dump to MetaFile + process(rContent); + + // cleanups + o_rContentMetafile.Stop(); + o_rContentMetafile.WindStart(); + aNewMapMode.SetOrigin(aPrimitiveRectangle.TopLeft()); + o_rContentMetafile.SetPrefMapMode(aNewMapMode); + o_rContentMetafile.SetPrefSize(aPrimitiveRectangle.GetSize()); + mpOutputDevice = pLastOutputDevice; + mpMetaFile = pLastMetafile; + + return aPrimitiveRectangle; + } + + void VclMetafileProcessor2D::impConvertFillGradientAttributeToVCLGradient( + Gradient& o_rVCLGradient, + const attribute::FillGradientAttribute& rFiGrAtt, + bool bIsTransparenceGradient) + { + if(bIsTransparenceGradient) + { + // it's about alpha channel intensities (black/white), do not use color modifier + o_rVCLGradient.SetStartColor(Color(rFiGrAtt.getStartColor())); + o_rVCLGradient.SetEndColor(Color(rFiGrAtt.getEndColor())); + } + else + { + // use color modifier to influence start/end color of gradient + o_rVCLGradient.SetStartColor(Color(maBColorModifierStack.getModifiedColor(rFiGrAtt.getStartColor()))); + o_rVCLGradient.SetEndColor(Color(maBColorModifierStack.getModifiedColor(rFiGrAtt.getEndColor()))); + } + + o_rVCLGradient.SetAngle(static_cast< sal_uInt16 >(rFiGrAtt.getAngle() * (1.0 / F_PI1800))); + o_rVCLGradient.SetBorder(static_cast< sal_uInt16 >(rFiGrAtt.getBorder() * 100.0)); + o_rVCLGradient.SetOfsX(static_cast< sal_uInt16 >(rFiGrAtt.getOffsetX() * 100.0)); + o_rVCLGradient.SetOfsY(static_cast< sal_uInt16 >(rFiGrAtt.getOffsetY() * 100.0)); + o_rVCLGradient.SetSteps(rFiGrAtt.getSteps()); + + // defaults for intensity; those were computed into the start/end colors already + o_rVCLGradient.SetStartIntensity(100); + o_rVCLGradient.SetEndIntensity(100); + + switch(rFiGrAtt.getStyle()) + { + default : // attribute::GRADIENTSTYLE_LINEAR : + { + o_rVCLGradient.SetStyle(GRADIENT_LINEAR); + break; + } + case attribute::GRADIENTSTYLE_AXIAL : + { + o_rVCLGradient.SetStyle(GRADIENT_AXIAL); + break; + } + case attribute::GRADIENTSTYLE_RADIAL : + { + o_rVCLGradient.SetStyle(GRADIENT_RADIAL); + break; + } + case attribute::GRADIENTSTYLE_ELLIPTICAL : + { + o_rVCLGradient.SetStyle(GRADIENT_ELLIPTICAL); + break; + } + case attribute::GRADIENTSTYLE_SQUARE : + { + o_rVCLGradient.SetStyle(GRADIENT_SQUARE); + break; + } + case attribute::GRADIENTSTYLE_RECT : + { + o_rVCLGradient.SetStyle(GRADIENT_RECT); + break; + } + } + } + + void VclMetafileProcessor2D::impStartSvtGraphicFill(SvtGraphicFill* pSvtGraphicFill) + { + if(pSvtGraphicFill && !mnSvtGraphicFillCount) + { + SvMemoryStream aMemStm; + + aMemStm << *pSvtGraphicFill; + mpMetaFile->AddAction(new MetaCommentAction("XPATHFILL_SEQ_BEGIN", 0, static_cast< const BYTE* >(aMemStm.GetData()), aMemStm.Seek(STREAM_SEEK_TO_END))); + mnSvtGraphicFillCount++; + } + } + + void VclMetafileProcessor2D::impEndSvtGraphicFill(SvtGraphicFill* pSvtGraphicFill) + { + if(pSvtGraphicFill && mnSvtGraphicFillCount) + { + mnSvtGraphicFillCount--; + mpMetaFile->AddAction(new MetaCommentAction("XPATHFILL_SEQ_END")); + delete pSvtGraphicFill; + } + } + + SvtGraphicStroke* VclMetafileProcessor2D::impTryToCreateSvtGraphicStroke( + const basegfx::B2DPolygon& rB2DPolygon, + const basegfx::BColor* pColor, + const attribute::LineAttribute* pLineAttribute, + const attribute::StrokeAttribute* pStrokeAttribute, + const attribute::LineStartEndAttribute* pStart, + const attribute::LineStartEndAttribute* pEnd) + { + SvtGraphicStroke* pRetval = 0; + + if(rB2DPolygon.count() && !mnSvtGraphicStrokeCount) + { + basegfx::BColor aStrokeColor; + basegfx::B2DPolyPolygon aStartArrow; + basegfx::B2DPolyPolygon aEndArrow; + + if(pColor) + { + aStrokeColor = *pColor; + } + else if(pLineAttribute) + { + aStrokeColor = maBColorModifierStack.getModifiedColor(pLineAttribute->getColor()); + } + + // It IS needed to record the stroke color at all in the metafile, + // SvtGraphicStroke has NO entry for stroke color(!) + mpOutputDevice->SetLineColor(Color(aStrokeColor)); + + if(!rB2DPolygon.isClosed()) + { + double fPolyLength(0.0); + + if(pStart && pStart->isActive()) + { + fPolyLength = basegfx::tools::getLength(rB2DPolygon); + + aStartArrow = basegfx::tools::createAreaGeometryForLineStartEnd( + rB2DPolygon, pStart->getB2DPolyPolygon(), true, pStart->getWidth(), + fPolyLength, pStart->isCentered() ? 0.5 : 0.0, 0); + } + + if(pEnd && pEnd->isActive()) + { + if(basegfx::fTools::equalZero(fPolyLength)) + { + fPolyLength = basegfx::tools::getLength(rB2DPolygon); + } + + aEndArrow = basegfx::tools::createAreaGeometryForLineStartEnd( + rB2DPolygon, pEnd->getB2DPolyPolygon(), false, pEnd->getWidth(), + fPolyLength, pEnd->isCentered() ? 0.5 : 0.0, 0); + } + } + + SvtGraphicStroke::JoinType eJoin(SvtGraphicStroke::joinNone); + double fLineWidth(0.0); + double fMiterLength(0.0); + SvtGraphicStroke::DashArray aDashArray; + + if(pLineAttribute) + { + // pre-fill fLineWidth + fLineWidth = pLineAttribute->getWidth(); + + // pre-fill fMiterLength + fMiterLength = fLineWidth; + + // get Join + switch(pLineAttribute->getLineJoin()) + { + default : // basegfx::B2DLINEJOIN_NONE : + { + eJoin = SvtGraphicStroke::joinNone; + break; + } + case basegfx::B2DLINEJOIN_BEVEL : + { + eJoin = SvtGraphicStroke::joinBevel; + break; + } + case basegfx::B2DLINEJOIN_MIDDLE : + case basegfx::B2DLINEJOIN_MITER : + { + eJoin = SvtGraphicStroke::joinMiter; + // ATM 15 degrees is assumed + fMiterLength /= rtl::math::sin(M_PI * (15.0 / 360.0)); + break; + } + case basegfx::B2DLINEJOIN_ROUND : + { + eJoin = SvtGraphicStroke::joinRound; + break; + } + } + } + + if(pStrokeAttribute) + { + // copy dash array + aDashArray = pStrokeAttribute->getDotDashArray(); + } + + // #i101734# apply current object transformation to created geometry. + // This is a partial fix. When a object transformation is used which + // e.g. contains a scaleX != scaleY, an unproportional scaling would + // have to be applied to the evtl. existing fat line. The current + // concept of PDF export and SvtGraphicStroke usage does simply not + // allow handling such definitions. The only clean way would be to + // add the transformation to SvtGraphicStroke and to handle it there + basegfx::B2DPolygon aB2DPolygon(rB2DPolygon); + + aB2DPolygon.transform(maCurrentTransformation); + aStartArrow.transform(maCurrentTransformation); + aEndArrow.transform(maCurrentTransformation); + + pRetval = new SvtGraphicStroke( + Polygon(aB2DPolygon), + PolyPolygon(aStartArrow), + PolyPolygon(aEndArrow), + mfCurrentUnifiedTransparence, + fLineWidth, + SvtGraphicStroke::capButt, + eJoin, + fMiterLength, + aDashArray); + } + + return pRetval; + } + + void VclMetafileProcessor2D::impStartSvtGraphicStroke(SvtGraphicStroke* pSvtGraphicStroke) + { + if(pSvtGraphicStroke && !mnSvtGraphicStrokeCount) + { + SvMemoryStream aMemStm; + + aMemStm << *pSvtGraphicStroke; + mpMetaFile->AddAction(new MetaCommentAction("XPATHSTROKE_SEQ_BEGIN", 0, static_cast< const BYTE* >(aMemStm.GetData()), aMemStm.Seek(STREAM_SEEK_TO_END))); + mnSvtGraphicStrokeCount++; + } + } + + void VclMetafileProcessor2D::impEndSvtGraphicStroke(SvtGraphicStroke* pSvtGraphicStroke) + { + if(pSvtGraphicStroke && mnSvtGraphicStrokeCount) + { + mnSvtGraphicStrokeCount--; + mpMetaFile->AddAction(new MetaCommentAction("XPATHSTROKE_SEQ_END")); + delete pSvtGraphicStroke; + } + } + + // init static break iterator + uno::Reference< ::com::sun::star::i18n::XBreakIterator > VclMetafileProcessor2D::mxBreakIterator; + + VclMetafileProcessor2D::VclMetafileProcessor2D(const geometry::ViewInformation2D& rViewInformation, OutputDevice& rOutDev) + : VclProcessor2D(rViewInformation, rOutDev), + mpMetaFile(rOutDev.GetConnectMetaFile()), + mnSvtGraphicFillCount(0), + mnSvtGraphicStrokeCount(0), + mfCurrentUnifiedTransparence(0.0), + mpPDFExtOutDevData(dynamic_cast< vcl::PDFExtOutDevData* >(rOutDev.GetExtOutDevData())) + { + OSL_ENSURE(rOutDev.GetConnectMetaFile(), "VclMetafileProcessor2D: Used on OutDev which has no MetaFile Target (!)"); + // draw to logic coordinates, do not initialize maCurrentTransformation to viewTransformation + // but only to ObjectTransformation. Do not change MapMode of destination. + maCurrentTransformation = rViewInformation.getObjectTransformation(); + } + + VclMetafileProcessor2D::~VclMetafileProcessor2D() + { + // MapMode was not changed, no restore necessary + } + + /*********************************************************************************************** + + Support of MetaCommentActions in the VclMetafileProcessor2D + Found MetaCommentActions and how they are supported: + + XGRAD_SEQ_BEGIN, XGRAD_SEQ_END: + + Used inside OutputDevice::DrawGradient to mark the start and end of a MetaGradientEx action. + It is used in various exporters/importers to have direct access to the gradient before it + is rendered by VCL (and thus fragmented to polygon color actions and others). On that base, e.g. + the Metafile to SdrObject import creates it's gradient objects. + Best (and safest) way to support it here is to use PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D, + map it back to the corresponding tools PolyPolygon and the Gradient and just call + OutputDevice::DrawGradient which creates the necessary compatible actions. + + XPATHFILL_SEQ_BEGIN, XPATHFILL_SEQ_END: + + Two producers, one is vcl/source/gdi/gdimtf.cxx, line 1273. There, it is transformed + inside GDIMetaFile::Rotate, nothing to take care of here. + The second producer is in graphics/svx/source/svdraw/impgrfll.cxx, line 374. This is used + with each incarnation of Imp_GraphicFill when a metafile is recorded, fillstyle is not + XFILL_NONE and not completely transparent. It creates a SvtGraphicFill and streams it + to the comment action. A closing end token is created in the destructor. + Usages of Imp_GraphicFill are in Do_Paint_Object-methods of SdrCircObj, SdrPathObj and + SdrRectObj. + The token users pick various actions from SvtGraphicFill, so it may need to be added for all kind + of filled objects, even simple colored polygons. It is added as extra information; the + Metafile actions between the two tokens are interpreted as output generated from those + fills. Thus, users have the choice to use the SvtGraphicFill info or the created output + actions. + Even for XFillTransparenceItem it is used, thus it may need to be supported in + UnifiedAlphaPrimitive2D, too, when interpreted as normally filled PolyPolygon. + Implemented for: + PRIMITIVE2D_ID_POLYPOLYGONBITMAPPRIMITIVE2D, + PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D, + PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D, + PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D, + and for PRIMITIVE2D_ID_UNIFIEDALPHAPRIMITIVE2D when detected unified alpha + + XPATHSTROKE_SEQ_BEGIN, XPATHSTROKE_SEQ_END: + + Similar to pathfill, but using SvtGraphicStroke instead. It also has two producers where one + is also the GDIMetaFile::Rotate. Another user is MetaCommentAction::Move which modifies the + contained path accordingly. + The other one is SdrObject::Imp_DrawLineGeometry. It's done when MetaFile is set at OutDev and + only when geometry is a single polygon (!). I see no reason for that; in the PS exporter this + would hinder to make use of PolyPolygon strokes. I will need to add support at: + PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D + PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D + PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D + This can be done hierarchical, too. + Okay, base implementation done based on those three primitives. + + FIELD_SEQ_BEGIN, FIELD_SEQ_END + + Used from slideshow for URLs, created from diverse SvxField implementations inside + createBeginComment()/createEndComment(). createBeginComment() is used from editeng\impedit3.cxx + inside ImpEditEngine::Paint. + Created TextHierarchyFieldPrimitive2D and added needed infos there; it is an group primitive and wraps + text primitives (but is not limited to that). It contains the field type if special actions for the + support of FIELD_SEQ_BEGIN/END are needed; this is the case for Page and URL fields. If more is + needed, it may be supported there. + FIELD_SEQ_BEGIN;PageField + FIELD_SEQ_END + Okay, these are now completely supported by TextHierarchyFieldPrimitive2D. URL works, too. + + XTEXT + + XTEXT_EOC(i) end of character + XTEXT_EOW(i) end of word + XTEXT_EOS(i) end of sentence + + this three are with index and are created with the help of a i18n::XBreakIterator in + ImplDrawWithComments. Simplifying, moving out text painting, reworking to create some + data structure for holding those TEXT infos. + Supported directly by TextSimplePortionPrimitive2D with adding a Locale to the basic text + primitive. In the MetaFileRenderer, the creation is now done (see below). This has the advantage + that this creations do not need to be done for all paints all the time. This would be + expensive since the BreakIterator and it's usage is expensive and for each paint also the + whole character stops would need to be created. + Created only for TextDecoratedPortionPrimitive2D due to XTEXT_EOL and XTEXT_EOP (see below) + + XTEXT_EOL() end of line + XTEXT_EOP() end of paragraph + + First try with boolean marks at TextDecoratedPortionPrimitive2D did not work too well, + i decided to solve it with structure. I added the TextHierarchyPrimitives for this, + namely: + - TextHierarchyLinePrimitive2D: Encapsulates single line + - TextHierarchyParagraphPrimitive2D: Encapsulates single paragraph + - TextHierarchyBlockPrimitive2D: encapsulates object texts (only one ATM) + Those are now supported in hierarchy. This means the MetaFile renderer will support them + by using them, reculrively using their content and adding MetaFile comments as needed. + This also means that when another text layouter will be used it will be necessary to + create/support the same HierarchyPrimitives to support users. + To transport the information using this hierarchy is best suited to all future needs; + the slideshow will be able to profit from it directly when using primitives; all other + renderers not interested in the text structure will just ignore the encapsulations. + + XTEXT_PAINTSHAPE_BEGIN, XTEXT_PAINTSHAPE_END + Supported now by the TextHierarchyBlockPrimitive2D. + + EPSReplacementGraphic: + Only used in goodies\source\filter.vcl\ieps\ieps.cxx and svx\source\xml\xmlgrhlp.cxx to + hold the original EPS which was imported in the same MetaFile as first 2 entries. Only + used to export the original again (if exists). + Not necessary to support with MetaFuleRenderer. + + XTEXT_SCROLLRECT, XTEXT_PAINTRECT + Currently used to get extra MetaFile infos using GraphicExporter which again uses + SdrTextObj::GetTextScrollMetaFileAndRectangle(). ATM works with primitives since + the rectangle data is added directly by the GraphicsExporter as comment. Does not need + to be adapted at once. + When adapting later, the only user - the diashow - should directly use the provided + Anination infos in the appropriate primitives (e.g. AnimatedSwitchPrimitive2D) + + PRNSPOOL_TRANSPARENTBITMAP_BEGIN, PRNSPOOL_TRANSPARENTBITMAP_END + VCL usage when printing PL -> THB. Okay, THB confirms that it is only used as + a fix (hack) while VCL printing. It is needed to not downscale a bitmap which + was explicitely created for the printer already again to some default maximum + bitmap sizes. + Nothing to do here for the primitive renderer. + + Support for vcl::PDFExtOutDevData: + PL knows that SJ did that stuff, it's used to hold a pointer to PDFExtOutDevData at + the OutDev. When set, some extra data is written there. Trying simple PDF export and + watching if i get those infos. + Well, a PDF export does not use e.g. ImpEditEngine::Paint since the PdfFilter uses + the SdXImpressDocument::render and thus uses the VclMetafileProcessor2D. I will check + if i get a PDFExtOutDevData at the target output device. + Indeed, i get one. Checking what all may be done when that extra-device-info is there. + + All in all i have to talk to SJ. I will need to emulate some of those actions, but + i need to discuss which ones. + In the future, all those infos would be taken from the primitive sequence anyways, + thus these extensions would potentially be temporary, too. + Discussed with SJ, added the necessary support and tested it. Details follow. + + - In ImpEditEngine::Paint, paragraph infos and URL stuff is added. + Added in primitive MetaFile renderer. + Checking URL: Indeed, current version exports it, but it is missing in primitive + CWS version. Adding support. + Okay, URLs work. Checked, Done. + + - UnoControlPDFExportContact is only created when PDFExtOutDevData is used at the + target and uno control data is created in UnoControlPDFExportContact::do_PaintObject. + This may be added in primitive MetaFile renderer. + Adding support... + OOps, the necessary helper stuff is in svx/source/form/formpdxexport.cxx in namespace + svxform. Have to talk to FS if this has to be like that. Especially since + ::vcl::PDFWriter::AnyWidget is filled out, which is already part of vcl. + Wrote an eMail to FS, he is on vacation currently. I see no reason why not to move + that stuff to somewhere else, maybe tools or svtools ?!? We will see... + Moved to toolkit, so i have to link against it. I tried VCL first, but it did + not work since VCLUnoHelper::CreateFont is unresolved in VCL (!). Other then the name + may imply, it is defined in toolkit (!). Since toolkit is linked against VCL itself, + the lowest move,ment plave is toolkit. + Checked form control export, it works well. Done. + + - In goodies, in GraphicObject::Draw, when the used Graphic is linked, infos are + generated. I will need to check what happens here with primitives. + To support, use of GraphicPrimitive2D (PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D) may be needed. + Added support, but feature is broken in main version, so i cannot test at all. + Writing a bug to CL (or SJ) and seeing what happens (#i80380#). + SJ took a look and we got it working. Tested VCL MetaFile Renderer based export, + as intended, the original file is exported. Works, Done. + + + + + To be done: + + - Maybe there are more places to take care of for vcl::PDFExtOutDevData! + + + + ****************************************************************************************************/ + + void VclMetafileProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate) + { + switch(rCandidate.getPrimitiveID()) + { + case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D : + { + // directdraw of wrong spell primitive + // Ignore for VclMetafileProcessor2D, this is for printing and MetaFile recording only + break; + } + case PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D : + { + const primitive2d::GraphicPrimitive2D& rGraphicPrimitive = static_cast< const primitive2d::GraphicPrimitive2D& >(rCandidate); + bool bUsingPDFExtOutDevData(false); + basegfx::B2DVector aTranslate, aScale; + static bool bSuppressPDFExtOutDevDataSupport(false); + + if(mpPDFExtOutDevData && !bSuppressPDFExtOutDevDataSupport) + { + // emulate data handling from UnoControlPDFExportContact, original see + // goodies/source/graphic/grfmgr.cxx + const Graphic& rGraphic = rGraphicPrimitive.getGraphicObject().GetGraphic(); + + if(rGraphic.IsLink()) + { + const GraphicAttr& rAttr = rGraphicPrimitive.getGraphicAttr(); + + if(!rAttr.IsSpecialDrawMode() && !rAttr.IsAdjusted()) + { + const basegfx::B2DHomMatrix& rTransform = rGraphicPrimitive.getTransform(); + double fRotate, fShearX; + rTransform.decompose(aScale, aTranslate, fRotate, fShearX); + + if( basegfx::fTools::equalZero( fRotate ) && ( aScale.getX() > 0.0 ) && ( aScale.getY() > 0.0 ) ) + { + bUsingPDFExtOutDevData = true; + mpPDFExtOutDevData->BeginGroup(); + } + } + } + } + + // process recursively and add MetaFile comment + process(rGraphicPrimitive.get2DDecomposition(getViewInformation2D())); + + if(bUsingPDFExtOutDevData) + { + // emulate data handling from UnoControlPDFExportContact, original see + // goodies/source/graphic/grfmgr.cxx + const basegfx::B2DRange aCurrentRange( + aTranslate.getX(), aTranslate.getY(), + aTranslate.getX() + aScale.getX(), aTranslate.getY() + aScale.getY()); + const Rectangle aCurrentRect( + sal_Int32(floor(aCurrentRange.getMinX())), sal_Int32(floor(aCurrentRange.getMinY())), + sal_Int32(ceil(aCurrentRange.getMaxX())), sal_Int32(ceil(aCurrentRange.getMaxY()))); + const GraphicAttr& rAttr = rGraphicPrimitive.getGraphicAttr(); + Rectangle aCropRect; + + if(rAttr.IsCropped()) + { + // calculate scalings between real image size and logic object size. This + // is necessary since the crop values are relative to original bitmap size + double fFactorX(1.0); + double fFactorY(1.0); + + { + const MapMode aMapMode100thmm(MAP_100TH_MM); + const Size aBitmapSize(Application::GetDefaultDevice()->LogicToLogic( + rGraphicPrimitive.getGraphicObject().GetPrefSize(), + rGraphicPrimitive.getGraphicObject().GetPrefMapMode(), aMapMode100thmm)); + const double fDivX(aBitmapSize.Width() - rAttr.GetLeftCrop() - rAttr.GetRightCrop()); + const double fDivY(aBitmapSize.Height() - rAttr.GetTopCrop() - rAttr.GetBottomCrop()); + + if(!basegfx::fTools::equalZero(fDivX)) + { + fFactorX = aScale.getX() / fDivX; + } + + if(!basegfx::fTools::equalZero(fDivY)) + { + fFactorY = aScale.getY() / fDivY; + } + } + + // calculate crop range and rect + basegfx::B2DRange aCropRange; + aCropRange.expand(aCurrentRange.getMinimum() - basegfx::B2DPoint(rAttr.GetLeftCrop() * fFactorX, rAttr.GetTopCrop() * fFactorY)); + aCropRange.expand(aCurrentRange.getMaximum() + basegfx::B2DPoint(rAttr.GetRightCrop() * fFactorX, rAttr.GetBottomCrop() * fFactorY)); + + aCropRect = Rectangle( + sal_Int32(floor(aCropRange.getMinX())), sal_Int32(floor(aCropRange.getMinY())), + sal_Int32(ceil(aCropRange.getMaxX())), sal_Int32(ceil(aCropRange.getMaxY()))); + } + + mpPDFExtOutDevData->EndGroup(rGraphicPrimitive.getGraphicObject().GetGraphic(), + rAttr.GetTransparency(), + aCurrentRect, + aCropRect); + } + + break; + } + case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D : + { + const primitive2d::ControlPrimitive2D& rControlPrimitive = static_cast< const primitive2d::ControlPrimitive2D& >(rCandidate); + const uno::Reference< awt::XControl >& rXControl(rControlPrimitive.getXControl()); + bool bIsPrintableControl(false); + + // find out if control is printable + if(rXControl.is()) + { + try + { + uno::Reference< beans::XPropertySet > xModelProperties(rXControl->getModel(), uno::UNO_QUERY); + uno::Reference< beans::XPropertySetInfo > xPropertyInfo(xModelProperties.is() + ? xModelProperties->getPropertySetInfo() + : uno::Reference< beans::XPropertySetInfo >()); + const ::rtl::OUString sPrintablePropertyName(RTL_CONSTASCII_USTRINGPARAM("Printable")); + + if(xPropertyInfo.is() && xPropertyInfo->hasPropertyByName(sPrintablePropertyName)) + { + OSL_VERIFY(xModelProperties->getPropertyValue(sPrintablePropertyName) >>= bIsPrintableControl); + } + } + catch(const uno::Exception&) + { + OSL_ENSURE(false, "VclMetafileProcessor2D: No access to printable flag of Control, caught an exception!"); + } + } + + // PDF export and printing only for printable controls + if(bIsPrintableControl) + { + const bool bPDFExport(mpPDFExtOutDevData && mpPDFExtOutDevData->GetIsExportFormFields()); + bool bDoProcessRecursively(true); + + if(bPDFExport) + { + // PDF export. Emulate data handling from UnoControlPDFExportContact + // I have now moved describePDFControl to toolkit, thus i can implement the PDF + // form control support now as follows + ::std::auto_ptr< ::vcl::PDFWriter::AnyWidget > pPDFControl; + ::toolkitform::describePDFControl(rXControl, pPDFControl); + + if(pPDFControl.get()) + { + // still need to fill in the location (is a class Rectangle) + const basegfx::B2DRange aRangeLogic(rControlPrimitive.getB2DRange(getViewInformation2D())); + const Rectangle aRectLogic( + (sal_Int32)floor(aRangeLogic.getMinX()), (sal_Int32)floor(aRangeLogic.getMinY()), + (sal_Int32)ceil(aRangeLogic.getMaxX()), (sal_Int32)ceil(aRangeLogic.getMaxY())); + pPDFControl->Location = aRectLogic; + + Size aFontSize(pPDFControl->TextFont.GetSize()); + aFontSize = mpOutputDevice->LogicToLogic(aFontSize, MapMode(MAP_POINT), mpOutputDevice->GetMapMode()); + pPDFControl->TextFont.SetSize(aFontSize); + + mpPDFExtOutDevData->BeginStructureElement(vcl::PDFWriter::Form); + mpPDFExtOutDevData->CreateControl(*pPDFControl.get()); + mpPDFExtOutDevData->EndStructureElement(); + + // no normal paint needed (see original UnoControlPDFExportContact::do_PaintObject); + // do not process recursively + bDoProcessRecursively = false; + } + else + { + // PDF export did not work, try simple output. + // Fallback to printer output by not setting bDoProcessRecursively + // to false. + } + } + + // #i93169# used flag the wrong way; true means that nothing was done yet + if(bDoProcessRecursively) + { + // printer output + try + { + // remember old graphics and create new + uno::Reference< awt::XView > xControlView(rXControl, uno::UNO_QUERY_THROW); + const uno::Reference< awt::XGraphics > xOriginalGraphics(xControlView->getGraphics()); + const uno::Reference< awt::XGraphics > xNewGraphics(mpOutputDevice->CreateUnoGraphics()); + + if(xNewGraphics.is()) + { + // link graphics and view + xControlView->setGraphics(xNewGraphics); + + // get position + const basegfx::B2DHomMatrix aObjectToDiscrete(getViewInformation2D().getObjectToViewTransformation() * rControlPrimitive.getTransform()); + const basegfx::B2DPoint aTopLeftDiscrete(aObjectToDiscrete * basegfx::B2DPoint(0.0, 0.0)); + + // draw it + xControlView->draw(basegfx::fround(aTopLeftDiscrete.getX()), basegfx::fround(aTopLeftDiscrete.getY())); + bDoProcessRecursively = false; + + // restore original graphics + xControlView->setGraphics(xOriginalGraphics); + } + } + catch( const uno::Exception& ) + { + OSL_ENSURE(false, "VclMetafileProcessor2D: Printing of Control failed, caught an exception!"); + } + } + + // process recursively if not done yet to export as decomposition (bitmap) + if(bDoProcessRecursively) + { + process(rControlPrimitive.get2DDecomposition(getViewInformation2D())); + } + } + + break; + } + case PRIMITIVE2D_ID_TEXTHIERARCHYFIELDPRIMITIVE2D : + { + // support for FIELD_SEQ_BEGIN, FIELD_SEQ_END and URL. It wraps text primitives (but is not limited to) + // thus do the MetafileAction embedding stuff but just handle recursively. + const primitive2d::TextHierarchyFieldPrimitive2D& rFieldPrimitive = static_cast< const primitive2d::TextHierarchyFieldPrimitive2D& >(rCandidate); + static const ByteString aCommentStringCommon("FIELD_SEQ_BEGIN"); + static const ByteString aCommentStringPage("FIELD_SEQ_BEGIN;PageField"); + static const ByteString aCommentStringEnd("FIELD_SEQ_END"); + + switch(rFieldPrimitive.getType()) + { + default : // case drawinglayer::primitive2d::FIELD_TYPE_COMMON : + { + mpMetaFile->AddAction(new MetaCommentAction(aCommentStringCommon)); + break; + } + case drawinglayer::primitive2d::FIELD_TYPE_PAGE : + { + mpMetaFile->AddAction(new MetaCommentAction(aCommentStringPage)); + break; + } + case drawinglayer::primitive2d::FIELD_TYPE_URL : + { + const rtl::OUString& rURL = rFieldPrimitive.getString(); + const String aOldString(rURL); + mpMetaFile->AddAction(new MetaCommentAction(aCommentStringCommon, 0, reinterpret_cast< const BYTE* >(aOldString.GetBuffer()), 2 * aOldString.Len())); + break; + } + } + + // process recursively + const primitive2d::Primitive2DSequence rContent = rFieldPrimitive.get2DDecomposition(getViewInformation2D()); + process(rContent); + + // for the end comment the type is not relevant yet, they are all the same. Just add. + mpMetaFile->AddAction(new MetaCommentAction(aCommentStringEnd)); + + if(mpPDFExtOutDevData && drawinglayer::primitive2d::FIELD_TYPE_URL == rFieldPrimitive.getType()) + { + // emulate data handling from ImpEditEngine::Paint + const basegfx::B2DRange aViewRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rContent, getViewInformation2D())); + const Rectangle aRectLogic( + (sal_Int32)floor(aViewRange.getMinX()), (sal_Int32)floor(aViewRange.getMinY()), + (sal_Int32)ceil(aViewRange.getMaxX()), (sal_Int32)ceil(aViewRange.getMaxY())); + vcl::PDFExtOutDevBookmarkEntry aBookmark; + aBookmark.nLinkId = mpPDFExtOutDevData->CreateLink(aRectLogic); + aBookmark.aBookmark = rFieldPrimitive.getString(); + std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = mpPDFExtOutDevData->GetBookmarks(); + rBookmarks.push_back( aBookmark ); + } + + break; + } + case PRIMITIVE2D_ID_TEXTHIERARCHYLINEPRIMITIVE2D : + { + const primitive2d::TextHierarchyLinePrimitive2D& rLinePrimitive = static_cast< const primitive2d::TextHierarchyLinePrimitive2D& >(rCandidate); + static const ByteString aCommentString("XTEXT_EOL"); + + // process recursively and add MetaFile comment + process(rLinePrimitive.get2DDecomposition(getViewInformation2D())); + mpMetaFile->AddAction(new MetaCommentAction(aCommentString)); + + break; + } + case PRIMITIVE2D_ID_TEXTHIERARCHYBULLETPRIMITIVE2D : + { + // in Outliner::PaintBullet(), a MetafileComment for bullets is added, too. The + // "XTEXT_EOC" is used, use here, too. + const primitive2d::TextHierarchyBulletPrimitive2D& rBulletPrimitive = static_cast< const primitive2d::TextHierarchyBulletPrimitive2D& >(rCandidate); + static const ByteString aCommentString("XTEXT_EOC"); + + // process recursively and add MetaFile comment + process(rBulletPrimitive.get2DDecomposition(getViewInformation2D())); + mpMetaFile->AddAction(new MetaCommentAction(aCommentString)); + + break; + } + case PRIMITIVE2D_ID_TEXTHIERARCHYPARAGRAPHPRIMITIVE2D : + { + const primitive2d::TextHierarchyParagraphPrimitive2D& rParagraphPrimitive = static_cast< const primitive2d::TextHierarchyParagraphPrimitive2D& >(rCandidate); + static const ByteString aCommentString("XTEXT_EOP"); + + if(mpPDFExtOutDevData) + { + // emulate data handling from ImpEditEngine::Paint + mpPDFExtOutDevData->BeginStructureElement( vcl::PDFWriter::Paragraph ); + } + + // process recursively and add MetaFile comment + process(rParagraphPrimitive.get2DDecomposition(getViewInformation2D())); + mpMetaFile->AddAction(new MetaCommentAction(aCommentString)); + + if(mpPDFExtOutDevData) + { + // emulate data handling from ImpEditEngine::Paint + mpPDFExtOutDevData->EndStructureElement(); + } + + break; + } + case PRIMITIVE2D_ID_TEXTHIERARCHYBLOCKPRIMITIVE2D : + { + const primitive2d::TextHierarchyBlockPrimitive2D& rBlockPrimitive = static_cast< const primitive2d::TextHierarchyBlockPrimitive2D& >(rCandidate); + static const ByteString aCommentStringA("XTEXT_PAINTSHAPE_BEGIN"); + static const ByteString aCommentStringB("XTEXT_PAINTSHAPE_END"); + + // add MetaFile comment, process recursively and add MetaFile comment + mpMetaFile->AddAction(new MetaCommentAction(aCommentStringA)); + process(rBlockPrimitive.get2DDecomposition(getViewInformation2D())); + mpMetaFile->AddAction(new MetaCommentAction(aCommentStringB)); + + break; + } + case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D : + case PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D : + { + // for supporting TEXT_ MetaFile actions there is more to do here; get the candidate + const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate = static_cast< const primitive2d::TextSimplePortionPrimitive2D& >(rCandidate); + // const primitive2d::TextDecoratedPortionPrimitive2D* pTextDecoratedCandidate = dynamic_cast< const primitive2d::TextDecoratedPortionPrimitive2D* >(&rCandidate); + + // Adapt evtl. used special DrawMode + const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode()); + adaptTextToFillDrawMode(); + + // directdraw of text simple portion; use default processing + RenderTextSimpleOrDecoratedPortionPrimitive2D(rTextCandidate); + + // restore DrawMode + mpOutputDevice->SetDrawMode(nOriginalDrawMode); + + // #i101169# if(pTextDecoratedCandidate) + { + // support for TEXT_ MetaFile actions only for decorated texts + if(!mxBreakIterator.is()) + { + uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xMSF(::comphelper::getProcessServiceFactory()); + mxBreakIterator.set(xMSF->createInstance(rtl::OUString::createFromAscii("com.sun.star.i18n.BreakIterator")), uno::UNO_QUERY); + } + + if(mxBreakIterator.is()) + { + const rtl::OUString& rTxt = rTextCandidate.getText(); + const sal_Int32 nTextLength(rTextCandidate.getTextLength()); // rTxt.getLength()); + + if(nTextLength) + { + const ::com::sun::star::lang::Locale& rLocale = rTextCandidate.getLocale(); + const sal_Int32 nTextPosition(rTextCandidate.getTextPosition()); + + sal_Int32 nDone; + sal_Int32 nNextCellBreak(mxBreakIterator->nextCharacters(rTxt, nTextPosition, rLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, 0, nDone)); + ::com::sun::star::i18n::Boundary nNextWordBoundary(mxBreakIterator->getWordBoundary(rTxt, nTextPosition, rLocale, ::com::sun::star::i18n::WordType::ANY_WORD, sal_True)); + sal_Int32 nNextSentenceBreak(mxBreakIterator->endOfSentence(rTxt, nTextPosition, rLocale)); + static const ByteString aCommentStringA("XTEXT_EOC"); + static const ByteString aCommentStringB("XTEXT_EOW"); + static const ByteString aCommentStringC("XTEXT_EOS"); + + for(sal_Int32 i(nTextPosition); i < nTextPosition + nTextLength; i++) + { + // create the entries for the respective break positions + if(i == nNextCellBreak) + { + mpMetaFile->AddAction(new MetaCommentAction(aCommentStringA, i - nTextPosition)); + nNextCellBreak = mxBreakIterator->nextCharacters(rTxt, i, rLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, 1, nDone); + } + if(i == nNextWordBoundary.endPos) + { + mpMetaFile->AddAction(new MetaCommentAction(aCommentStringB, i - nTextPosition)); + nNextWordBoundary = mxBreakIterator->getWordBoundary(rTxt, i + 1, rLocale, ::com::sun::star::i18n::WordType::ANY_WORD, sal_True); + } + if(i == nNextSentenceBreak) + { + mpMetaFile->AddAction(new MetaCommentAction(aCommentStringC, i - nTextPosition)); + nNextSentenceBreak = mxBreakIterator->endOfSentence(rTxt, i + 1, rLocale); + } + } + } + } + } + + break; + } + case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D : + { + // direct draw of hairline; use default processing + // also support SvtGraphicStroke MetaCommentAction + const primitive2d::PolygonHairlinePrimitive2D& rHairlinePrimitive = static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate); + const basegfx::BColor aLineColor(maBColorModifierStack.getModifiedColor(rHairlinePrimitive.getBColor())); + SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(rHairlinePrimitive.getB2DPolygon(), &aLineColor, 0, 0, 0, 0); + + impStartSvtGraphicStroke(pSvtGraphicStroke); + RenderPolygonHairlinePrimitive2D(static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate), false); + impEndSvtGraphicStroke(pSvtGraphicStroke); + break; + } + case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D : + { + // support SvtGraphicStroke MetaCommentAction + const primitive2d::PolygonStrokePrimitive2D& rStrokePrimitive = static_cast< const primitive2d::PolygonStrokePrimitive2D& >(rCandidate); + SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(rStrokePrimitive.getB2DPolygon(), 0, &rStrokePrimitive.getLineAttribute(), + &rStrokePrimitive.getStrokeAttribute(), 0, 0); + + // Adapt OutDev's DrawMode if special ones were used + const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode()); + adaptLineToFillDrawMode(); + + impStartSvtGraphicStroke(pSvtGraphicStroke); + + // #i101491# + // Change default of fat line generation for MetaFiles: Create MetaPolyLineAction + // instead of decomposing all geometries when the polygon has more than given amount of + // points; else the decomposition will get too expensive quiclky. OTOH + // the decomposition provides the better quality e.g. taking edge roundings + // into account which will NOT be taken into account with LineInfo-based actions + const sal_uInt32 nSubPolygonCount(rStrokePrimitive.getB2DPolygon().count()); + bool bDone(0 == nSubPolygonCount); + + if(!bDone && nSubPolygonCount > 1000) + { + // create MetaPolyLineActions, but without LINE_DASH + const attribute::LineAttribute& rLine = rStrokePrimitive.getLineAttribute(); + + if(basegfx::fTools::more(rLine.getWidth(), 0.0)) + { + const attribute::StrokeAttribute& rStroke = rStrokePrimitive.getStrokeAttribute(); + basegfx::B2DPolyPolygon aHairLinePolyPolygon; + + if(0.0 == rStroke.getFullDotDashLen()) + { + aHairLinePolyPolygon.append(rStrokePrimitive.getB2DPolygon()); + } + else + { + basegfx::tools::applyLineDashing( + rStrokePrimitive.getB2DPolygon(), rStroke.getDotDashArray(), + &aHairLinePolyPolygon, 0, rStroke.getFullDotDashLen()); + } + + const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rLine.getColor())); + mpOutputDevice->SetLineColor(Color(aHairlineColor)); + mpOutputDevice->SetFillColor(); + + aHairLinePolyPolygon.transform(maCurrentTransformation); + + const LineInfo aLineInfo(LINE_SOLID, basegfx::fround(rLine.getWidth())); + + for(sal_uInt32 a(0); a < aHairLinePolyPolygon.count(); a++) + { + const basegfx::B2DPolygon aCandidate(aHairLinePolyPolygon.getB2DPolygon(a)); + + if(aCandidate.count() > 1) + { + const Polygon aToolsPolygon(aCandidate); + + mpMetaFile->AddAction(new MetaPolyLineAction(aToolsPolygon, aLineInfo)); + } + } + + bDone = true; + } + } + + if(!bDone) + { + // use decomposition (creates line geometry as filled polygon + // geometry) + process(rCandidate.get2DDecomposition(getViewInformation2D())); + } + + impEndSvtGraphicStroke(pSvtGraphicStroke); + + // restore DrawMode + mpOutputDevice->SetDrawMode(nOriginalDrawMode); + + break; + } + case PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D : + { + // support SvtGraphicStroke MetaCommentAction + const primitive2d::PolygonStrokeArrowPrimitive2D& rStrokeArrowPrimitive = static_cast< const primitive2d::PolygonStrokeArrowPrimitive2D& >(rCandidate); + SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(rStrokeArrowPrimitive.getB2DPolygon(), 0, &rStrokeArrowPrimitive.getLineAttribute(), + &rStrokeArrowPrimitive.getStrokeAttribute(), &rStrokeArrowPrimitive.getStart(), &rStrokeArrowPrimitive.getEnd()); + + impStartSvtGraphicStroke(pSvtGraphicStroke); + process(rCandidate.get2DDecomposition(getViewInformation2D())); + impEndSvtGraphicStroke(pSvtGraphicStroke); + break; + } + case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D : + { + // direct draw of transformed BitmapEx primitive; use default processing + RenderBitmapPrimitive2D(static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_POLYPOLYGONBITMAPPRIMITIVE2D : + { + // need to handle PolyPolygonBitmapPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END + SvtGraphicFill* pSvtGraphicFill = 0; + + if(!mnSvtGraphicFillCount) + { + const primitive2d::PolyPolygonBitmapPrimitive2D& rBitmapCandidate = static_cast< const primitive2d::PolyPolygonBitmapPrimitive2D& >(rCandidate); + basegfx::B2DPolyPolygon aLocalPolyPolygon(rBitmapCandidate.getB2DPolyPolygon()); + aLocalPolyPolygon.transform(maCurrentTransformation); + + if(aLocalPolyPolygon.count()) + { + // calculate transformation. Get real object size, all values in FillBitmapAttribute + // are relative to the unified object + const attribute::FillBitmapAttribute& rFillBitmapAttribute = rBitmapCandidate .getFillBitmap(); + const basegfx::B2DRange aOutlineRange(basegfx::tools::getRange(aLocalPolyPolygon)); + const basegfx::B2DVector aOutlineSize(aOutlineRange.getRange()); + + // get absolute values + const basegfx::B2DVector aFillBitmapSize(rFillBitmapAttribute.getSize() * aOutlineSize); + const basegfx::B2DPoint aFillBitmapTopLeft(rFillBitmapAttribute.getTopLeft() * aOutlineSize); + + // the scaling needs scale from pixel to logic coordinate system + const Bitmap& rBitmap = rFillBitmapAttribute.getBitmap(); + Size aBmpSizePixel(rBitmap.GetSizePixel()); + + if(!aBmpSizePixel.Width()) + { + aBmpSizePixel.Width() = 1; + } + + if(!aBmpSizePixel.Height()) + { + aBmpSizePixel.Height() = 1; + } + + // setup transformation like in impgrfll + SvtGraphicFill::Transform aTransform; + + // scale values are divided by bitmap pixel sizes + aTransform.matrix[0] = aFillBitmapSize.getX() / aBmpSizePixel.Width(); + aTransform.matrix[4] = aFillBitmapSize.getY() / aBmpSizePixel.Height(); + + // translates are absolute + aTransform.matrix[2] = aFillBitmapTopLeft.getX(); + aTransform.matrix[5] = aFillBitmapTopLeft.getY(); + + // setup fill graphic like in impgrfll + Graphic aFillGraphic = Graphic(rBitmap); + aFillGraphic.SetPrefMapMode(MapMode(MAP_PIXEL)); + aFillGraphic.SetPrefSize(aBmpSizePixel); + + pSvtGraphicFill = new SvtGraphicFill( + PolyPolygon(aLocalPolyPolygon), + Color(), + 0.0, + SvtGraphicFill::fillEvenOdd, + SvtGraphicFill::fillTexture, + aTransform, + rFillBitmapAttribute.getTiling(), + SvtGraphicFill::hatchSingle, + Color(), + SvtGraphicFill::gradientLinear, + Color(), + Color(), + 0, + aFillGraphic); + } + } + + // Do use decomposition; encapsulate with SvtGraphicFill + impStartSvtGraphicFill(pSvtGraphicFill); + process(rCandidate.get2DDecomposition(getViewInformation2D())); + impEndSvtGraphicFill(pSvtGraphicFill); + + break; + } + case PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D : + { + // need to handle PolyPolygonHatchPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END + SvtGraphicFill* pSvtGraphicFill = 0; + + if(!mnSvtGraphicFillCount) + { + const primitive2d::PolyPolygonHatchPrimitive2D& rHatchCandidate = static_cast< const primitive2d::PolyPolygonHatchPrimitive2D& >(rCandidate); + basegfx::B2DPolyPolygon aLocalPolyPolygon(rHatchCandidate.getB2DPolyPolygon()); + aLocalPolyPolygon.transform(maCurrentTransformation); + + if(aLocalPolyPolygon.count()) + { + // re-create a VCL hatch as base data + const attribute::FillHatchAttribute& rFillHatchAttribute = rHatchCandidate.getFillHatch(); + SvtGraphicFill::HatchType eHatch(SvtGraphicFill::hatchSingle); + + switch(rFillHatchAttribute.getStyle()) + { + default: // attribute::HATCHSTYLE_SINGLE : + { + eHatch = SvtGraphicFill::hatchSingle; + break; + } + case attribute::HATCHSTYLE_DOUBLE : + { + eHatch = SvtGraphicFill::hatchDouble; + break; + } + case attribute::HATCHSTYLE_TRIPLE : + { + eHatch = SvtGraphicFill::hatchTriple; + break; + } + } + + SvtGraphicFill::Transform aTransform; + + // scale + aTransform.matrix[0] *= rFillHatchAttribute.getDistance(); + aTransform.matrix[4] *= rFillHatchAttribute.getDistance(); + + // rotate (was never correct in impgrfll anyways, use correct angle now) + aTransform.matrix[0] *= cos(rFillHatchAttribute.getAngle()); + aTransform.matrix[1] *= -sin(rFillHatchAttribute.getAngle()); + aTransform.matrix[3] *= sin(rFillHatchAttribute.getAngle()); + aTransform.matrix[4] *= cos(rFillHatchAttribute.getAngle()); + + pSvtGraphicFill = new SvtGraphicFill( + PolyPolygon(aLocalPolyPolygon), + Color(), + 0.0, + SvtGraphicFill::fillEvenOdd, + SvtGraphicFill::fillHatch, + aTransform, + false, + eHatch, + Color(rFillHatchAttribute.getColor()), + SvtGraphicFill::gradientLinear, + Color(), + Color(), + 0, + Graphic()); + } + } + + // Do use decomposition; encapsulate with SvtGraphicFill + impStartSvtGraphicFill(pSvtGraphicFill); + process(rCandidate.get2DDecomposition(getViewInformation2D())); + impEndSvtGraphicFill(pSvtGraphicFill); + + break; + } + case PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D : + { + const primitive2d::PolyPolygonGradientPrimitive2D& rGradientCandidate = static_cast< const primitive2d::PolyPolygonGradientPrimitive2D& >(rCandidate); + + // for support of MetaCommentActions of the form XGRAD_SEQ_BEGIN, XGRAD_SEQ_END + // it is safest to use the VCL OutputDevice::DrawGradient method which creates those. + // re-create a VCL-gradient from FillGradientPrimitive2D and the needed tools PolyPolygon + Gradient aVCLGradient; + impConvertFillGradientAttributeToVCLGradient(aVCLGradient, rGradientCandidate.getFillGradient(), false); + basegfx::B2DPolyPolygon aLocalPolyPolygon(rGradientCandidate.getB2DPolyPolygon()); + aLocalPolyPolygon.transform(maCurrentTransformation); + + // #i82145# ATM VCL printing of gradients using curved shapes does not work, + // i submitted the bug with the given ID to THB. When that task is fixed it is + // necessary to again remove this subdivision since it decreases possible + // printing quality (not even resolution-dependent for now). THB will tell + // me when that task is fixed in the master + const PolyPolygon aToolsPolyPolygon(basegfx::tools::adaptiveSubdivideByAngle(aLocalPolyPolygon)); + + // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support + SvtGraphicFill* pSvtGraphicFill = 0; + + if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count()) + { + // setup gradient stuff like in like in impgrfll + SvtGraphicFill::GradientType eGrad(SvtGraphicFill::gradientLinear); + + switch(aVCLGradient.GetStyle()) + { + default : // GRADIENT_LINEAR: + case GRADIENT_AXIAL: + eGrad = SvtGraphicFill::gradientLinear; + break; + case GRADIENT_RADIAL: + case GRADIENT_ELLIPTICAL: + eGrad = SvtGraphicFill::gradientRadial; + break; + case GRADIENT_SQUARE: + case GRADIENT_RECT: + eGrad = SvtGraphicFill::gradientRectangular; + break; + } + + pSvtGraphicFill = new SvtGraphicFill( + aToolsPolyPolygon, + Color(), + 0.0, + SvtGraphicFill::fillEvenOdd, + SvtGraphicFill::fillGradient, + SvtGraphicFill::Transform(), + false, + SvtGraphicFill::hatchSingle, + Color(), + eGrad, + aVCLGradient.GetStartColor(), + aVCLGradient.GetEndColor(), + aVCLGradient.GetSteps(), + Graphic()); + } + + // call VCL directly; encapsulate with SvtGraphicFill + impStartSvtGraphicFill(pSvtGraphicFill); + mpOutputDevice->DrawGradient(aToolsPolyPolygon, aVCLGradient); + impEndSvtGraphicFill(pSvtGraphicFill); + + // NO usage of common own gradient randerer, not used ATM for VCL MetaFile, see text above + // RenderPolyPolygonGradientPrimitive2D(static_cast< const primitive2d::PolyPolygonGradientPrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D : + { + const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate(static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate)); + const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor())); + basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon()); + aLocalPolyPolygon.transform(maCurrentTransformation); + + // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support + SvtGraphicFill* pSvtGraphicFill = 0; + + if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count()) + { + // setup simple color fill stuff like in impgrfll + pSvtGraphicFill = new SvtGraphicFill( + PolyPolygon(aLocalPolyPolygon), + Color(aPolygonColor), + 0.0, + SvtGraphicFill::fillEvenOdd, + SvtGraphicFill::fillSolid, + SvtGraphicFill::Transform(), + false, + SvtGraphicFill::hatchSingle, + Color(), + SvtGraphicFill::gradientLinear, + Color(), + Color(), + 0, + Graphic()); + } + + // set line and fill color + mpOutputDevice->SetFillColor(Color(aPolygonColor)); + mpOutputDevice->SetLineColor(); + + // call VCL directly; encapsulate with SvtGraphicFill + impStartSvtGraphicFill(pSvtGraphicFill); + mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon); + impEndSvtGraphicFill(pSvtGraphicFill); + + break; + } + case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D : + { + // direct draw of MetaFile, use default pocessing + RenderMetafilePrimitive2D(static_cast< const primitive2d::MetafilePrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_MASKPRIMITIVE2D : + { + // mask group. Special handling for MetaFiles. + const primitive2d::MaskPrimitive2D& rMaskCandidate = static_cast< const primitive2d::MaskPrimitive2D& >(rCandidate); + + if(rMaskCandidate.getChildren().hasElements()) + { + basegfx::B2DPolyPolygon aMask(rMaskCandidate.getMask()); + + if(aMask.count()) + { + // prepare new mask polygon and rescue current one + aMask.transform(maCurrentTransformation); + const basegfx::B2DPolyPolygon aLastClipPolyPolygon(maClipPolyPolygon); + + if(maClipPolyPolygon.count()) + { + // there is already a clip polygon set; build clipped union of + // current mask polygon and new one + maClipPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon(aMask, maClipPolyPolygon, false, false); + } + else + { + // use mask directly + maClipPolyPolygon = aMask; + } + + if(maClipPolyPolygon.count()) + { + // set VCL clip region; subdivide before conversion to tools polygon. Subdivision necessary (!) + // Removed subdivision and fixed in Region::ImplPolyPolyRegionToBandRegionFunc() in VCL where + // the ClipRegion is built from the Polygon. A AdaptiveSubdivide on the source polygon was missing there + mpOutputDevice->Push(PUSH_CLIPREGION); + //mpOutputDevice->SetClipRegion(Region(PolyPolygon(basegfx::tools::adaptiveSubdivideByAngle(maClipPolyPolygon)))); + mpOutputDevice->SetClipRegion(Region(PolyPolygon(maClipPolyPolygon))); + } + + // recursively paint content + process(rMaskCandidate.getChildren()); + + if(maClipPolyPolygon.count()) + { + // restore VCL clip region + mpOutputDevice->Pop(); + } + + // restore to rescued clip polygon + maClipPolyPolygon = aLastClipPolyPolygon; + } + else + { + // no mask, no clipping. recursively paint content + process(rMaskCandidate.getChildren()); + } + } + + break; + } + case PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D : + { + // modified color group. Force output to unified color. Use default pocessing. + RenderModifiedColorPrimitive2D(static_cast< const primitive2d::ModifiedColorPrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_UNIFIEDALPHAPRIMITIVE2D : + { + // for metafile: Need to examine what the pure vcl version is doing here actually + // - uses DrawTransparent with metafile for content and a gradient + // - uses DrawTransparent for single PolyPoylgons directly. Can be detected by + // checking the content for single PolyPolygonColorPrimitive2D + const primitive2d::UnifiedAlphaPrimitive2D& rUniAlphaCandidate = static_cast< const primitive2d::UnifiedAlphaPrimitive2D& >(rCandidate); + const primitive2d::Primitive2DSequence rContent = rUniAlphaCandidate.getChildren(); + + if(rContent.hasElements()) + { + // try to identify a single PolyPolygonColorPrimitive2D in the + // content part of the alpha primitive + const primitive2d::PolyPolygonColorPrimitive2D* pPoPoColor = 0; + static bool bForceToMetafile(false); + + if(!bForceToMetafile && 1 == rContent.getLength()) + { + const primitive2d::Primitive2DReference xReference(rContent[0]); + pPoPoColor = dynamic_cast< const primitive2d::PolyPolygonColorPrimitive2D* >(xReference.get()); + } + + // PolyPolygonGradientPrimitive2D, PolyPolygonHatchPrimitive2D and + // PolyPolygonBitmapPrimitive2D are derived from PolyPolygonColorPrimitive2D. + // Check also for correct ID to exclude derived implementations + if(pPoPoColor && PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D == pPoPoColor->getPrimitiveID()) + { + // single transparent PolyPolygon identified, use directly + const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(pPoPoColor->getBColor())); + basegfx::B2DPolyPolygon aLocalPolyPolygon(pPoPoColor->getB2DPolyPolygon()); + aLocalPolyPolygon.transform(maCurrentTransformation); + + // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support + SvtGraphicFill* pSvtGraphicFill = 0; + + if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count()) + { + // setup simple color with transparence fill stuff like in impgrfll + pSvtGraphicFill = new SvtGraphicFill( + PolyPolygon(aLocalPolyPolygon), + Color(aPolygonColor), + rUniAlphaCandidate.getAlpha(), + SvtGraphicFill::fillEvenOdd, + SvtGraphicFill::fillSolid, + SvtGraphicFill::Transform(), + false, + SvtGraphicFill::hatchSingle, + Color(), + SvtGraphicFill::gradientLinear, + Color(), + Color(), + 0, + Graphic()); + } + + // set line and fill color + const sal_uInt16 nTransPercentVcl((sal_uInt16)basegfx::fround(rUniAlphaCandidate.getAlpha() * 100.0)); + mpOutputDevice->SetFillColor(Color(aPolygonColor)); + mpOutputDevice->SetLineColor(); + + // call VCL directly; encapsulate with SvtGraphicFill + impStartSvtGraphicFill(pSvtGraphicFill); + mpOutputDevice->DrawTransparent( + PolyPolygon(aLocalPolyPolygon), + nTransPercentVcl); + impEndSvtGraphicFill(pSvtGraphicFill); + } + else + { + // svae old mfCurrentUnifiedTransparence and set new one + // so that contained SvtGraphicStroke may use the current one + const double fLastCurrentUnifiedTransparence(mfCurrentUnifiedTransparence); + // #i105377# paint the content metafile opaque as the transparency gets + // split of into the gradient below + // mfCurrentUnifiedTransparence = rUniAlphaCandidate.getAlpha(); + mfCurrentUnifiedTransparence = 0; + + // various content, create content-metafile + GDIMetaFile aContentMetafile; + const Rectangle aPrimitiveRectangle(impDumpToMetaFile(rContent, aContentMetafile)); + + // restore mfCurrentUnifiedTransparence; it may have been used + // while processing the sub-content in impDumpToMetaFile + mfCurrentUnifiedTransparence = fLastCurrentUnifiedTransparence; + + // create uniform VCL gradient for uniform transparency + Gradient aVCLGradient; + const sal_uInt8 nTransPercentVcl((sal_uInt8)basegfx::fround(rUniAlphaCandidate.getAlpha() * 255.0)); + const Color aTransColor(nTransPercentVcl, nTransPercentVcl, nTransPercentVcl); + + aVCLGradient.SetStyle(GRADIENT_LINEAR); + aVCLGradient.SetStartColor(aTransColor); + aVCLGradient.SetEndColor(aTransColor); + aVCLGradient.SetAngle(0); + aVCLGradient.SetBorder(0); + aVCLGradient.SetOfsX(0); + aVCLGradient.SetOfsY(0); + aVCLGradient.SetStartIntensity(100); + aVCLGradient.SetEndIntensity(100); + aVCLGradient.SetSteps(2); + + // render it to VCL + mpOutputDevice->DrawTransparent( + aContentMetafile, aPrimitiveRectangle.TopLeft(), + aPrimitiveRectangle.GetSize(), aVCLGradient); + } + } + + break; + } + case PRIMITIVE2D_ID_ALPHAPRIMITIVE2D : + { + // for metafile: Need to examine what the pure vcl version is doing here actually + // - uses DrawTransparent with metafile for content and a gradient + // i can detect this here with checking the gradient part for a single + // FillGradientPrimitive2D and reconstruct the gradient. + // If that detection goes wrong, i have to create an alpha-blended bitmap. Eventually + // do that in stripes, else RenderAlphaPrimitive2D may just be used + const primitive2d::AlphaPrimitive2D& rAlphaCandidate = static_cast< const primitive2d::AlphaPrimitive2D& >(rCandidate); + const primitive2d::Primitive2DSequence rContent = rAlphaCandidate.getChildren(); + const primitive2d::Primitive2DSequence rAlpha = rAlphaCandidate.getAlpha(); + + if(rContent.hasElements() && rAlpha.hasElements()) + { + // try to identify a single FillGradientPrimitive2D in the + // alpha part of the primitive + const primitive2d::FillGradientPrimitive2D* pFiGradient = 0; + static bool bForceToBigTransparentVDev(false); + + if(!bForceToBigTransparentVDev && 1 == rAlpha.getLength()) + { + const primitive2d::Primitive2DReference xReference(rAlpha[0]); + pFiGradient = dynamic_cast< const primitive2d::FillGradientPrimitive2D* >(xReference.get()); + } + + // Check also for correct ID to exclude derived implementations + if(pFiGradient && PRIMITIVE2D_ID_FILLGRADIENTPRIMITIVE2D == pFiGradient->getPrimitiveID()) + { + // various content, create content-metafile + GDIMetaFile aContentMetafile; + const Rectangle aPrimitiveRectangle(impDumpToMetaFile(rContent, aContentMetafile)); + + // re-create a VCL-gradient from FillGradientPrimitive2D + Gradient aVCLGradient; + impConvertFillGradientAttributeToVCLGradient(aVCLGradient, pFiGradient->getFillGradient(), true); + + // render it to VCL + mpOutputDevice->DrawTransparent( + aContentMetafile, aPrimitiveRectangle.TopLeft(), + aPrimitiveRectangle.GetSize(), aVCLGradient); + } + else + { + // sub-transparence group. Draw to VDev first. + // this may get refined to tiling when resolution is too big here + + // need to avoid switching off MapMode stuff here; maybe need another + // tooling class, cannot just do the same as with the pixel renderer. + // Need to experiment... + + // Okay, basic implementation finished and tested. The DPI stuff was hard + // and not easy to find out that it's needed. + // Since this will not yet happen normally (as long as noone constructs + // alpha primitives with non-trivial alpha content) i will for now not + // refine to tiling here. + + basegfx::B2DRange aViewRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rContent, getViewInformation2D())); + aViewRange.transform(maCurrentTransformation); + const Rectangle aRectLogic( + (sal_Int32)floor(aViewRange.getMinX()), (sal_Int32)floor(aViewRange.getMinY()), + (sal_Int32)ceil(aViewRange.getMaxX()), (sal_Int32)ceil(aViewRange.getMaxY())); + const Rectangle aRectPixel(mpOutputDevice->LogicToPixel(aRectLogic)); + const Size aSizePixel(aRectPixel.GetSize()); + const Point aEmptyPoint; + VirtualDevice aBufferDevice; + + if(aBufferDevice.SetOutputSizePixel(aSizePixel)) + { + // create and set MapModes for target devices + MapMode aNewMapMode(mpOutputDevice->GetMapMode()); + aNewMapMode.SetOrigin(Point(-aRectLogic.Left(), -aRectLogic.Top())); + aBufferDevice.SetMapMode(aNewMapMode); + + // prepare view transformation for target renderers + // ATTENTION! Need to apply another scaling because of the potential DPI differences + // between Printer and VDev (mpOutputDevice and aBufferDevice here). + // To get the DPI, LogicToPixel from (1,1) from MAP_INCH needs to be used. + basegfx::B2DHomMatrix aViewTransform(aBufferDevice.GetViewTransformation()); + const Size aDPIOld(mpOutputDevice->LogicToPixel(Size(1, 1), MAP_INCH)); + const Size aDPINew(aBufferDevice.LogicToPixel(Size(1, 1), MAP_INCH)); + const double fDPIXChange((double)aDPIOld.getWidth() / (double)aDPINew.getWidth()); + const double fDPIYChange((double)aDPIOld.getHeight() / (double)aDPINew.getHeight()); + + if(!basegfx::fTools::equal(fDPIXChange, 1.0) || !basegfx::fTools::equal(fDPIYChange, 1.0)) + { + aViewTransform.scale(fDPIXChange, fDPIYChange); + } + + // create view information and pixel renderer. Reuse known ViewInformation + // except new transformation and range + const geometry::ViewInformation2D aViewInfo( + getViewInformation2D().getObjectTransformation(), + aViewTransform, + aViewRange, + getViewInformation2D().getVisualizedPage(), + getViewInformation2D().getViewTime(), + getViewInformation2D().getExtendedInformationSequence()); + + VclPixelProcessor2D aBufferProcessor(aViewInfo, aBufferDevice); + + // draw content using pixel renderer + aBufferProcessor.process(rContent); + const Bitmap aBmContent(aBufferDevice.GetBitmap(aEmptyPoint, aSizePixel)); + + // draw alpha using pixel renderer + aBufferDevice.Erase(); + aBufferProcessor.process(rAlpha); + const AlphaMask aBmAlpha(aBufferDevice.GetBitmap(aEmptyPoint, aSizePixel)); + +#ifdef DBG_UTIL + static bool bDoSaveForVisualControl(false); + if(bDoSaveForVisualControl) + { + SvFileStream aNew(String(ByteString( "c:\\test.bmp" ), RTL_TEXTENCODING_UTF8), STREAM_WRITE|STREAM_TRUNC); + aNew << aBmContent; + } +#endif + + // paint + mpOutputDevice->DrawBitmapEx( + aRectLogic.TopLeft(), + aRectLogic.GetSize(), + BitmapEx(aBmContent, aBmAlpha)); + } + } + } + + break; + } + case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D : + { + // use default transform group pocessing + RenderTransformPrimitive2D(static_cast< const primitive2d::TransformPrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D : + { + // new XDrawPage for ViewInformation2D + RenderPagePreviewPrimitive2D(static_cast< const primitive2d::PagePreviewPrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D : + { + // use default marker array pocessing + RenderMarkerArrayPrimitive2D(static_cast< const primitive2d::MarkerArrayPrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D : + { + // use default point array pocessing + RenderPointArrayPrimitive2D(static_cast< const primitive2d::PointArrayPrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_CHARTPRIMITIVE2D : + { + // ChartPrimitive2D + const primitive2d::ChartPrimitive2D& rChartPrimitive = static_cast< const primitive2d::ChartPrimitive2D& >(rCandidate); + + if(!renderChartPrimitive2D( + rChartPrimitive, + *mpOutputDevice, + getViewInformation2D())) + { + // fallback to decomposition (MetaFile) + process(rChartPrimitive.get2DDecomposition(getViewInformation2D())); + } + break; + } + case PRIMITIVE2D_ID_STRUCTURETAGRIMITIVE2D : + { + // structured tag primitive + const primitive2d::StructureTagPrimitive2D& rStructureTagCandidate = static_cast< const primitive2d::StructureTagPrimitive2D& >(rCandidate); + const vcl::PDFWriter::StructElement& rTagElement(rStructureTagCandidate.getStructureElement()); + const bool bTagUsed(vcl::PDFWriter::NonStructElement != rTagElement); + + if(mpPDFExtOutDevData && bTagUsed) + { + // write start tag + mpPDFExtOutDevData->BeginStructureElement(rTagElement); + } + + // proccess childs normally + process(rStructureTagCandidate.getChildren()); + + if(mpPDFExtOutDevData && bTagUsed) + { + // write end tag + mpPDFExtOutDevData->EndStructureElement(); + } + + break; + } + case PRIMITIVE2D_ID_HITTESTPRIMITIVE2D : + { + // #i99123# + // invisible primitive; to rebuilt the old MetaFile creation, it is necessary to + // not ignore them (as it was thought), but to add a MetaFile entry for them. + basegfx::B2DRange aInvisibleRange(rCandidate.getB2DRange(getViewInformation2D())); + + if(!aInvisibleRange.isEmpty()) + { + aInvisibleRange.transform(maCurrentTransformation); + const Rectangle aRectLogic( + (sal_Int32)floor(aInvisibleRange.getMinX()), (sal_Int32)floor(aInvisibleRange.getMinY()), + (sal_Int32)ceil(aInvisibleRange.getMaxX()), (sal_Int32)ceil(aInvisibleRange.getMaxY())); + + mpOutputDevice->SetFillColor(); + mpOutputDevice->SetLineColor(); + mpOutputDevice->DrawRect(aRectLogic); + } + + break; + } + default : + { + // process recursively + process(rCandidate.get2DDecomposition(getViewInformation2D())); + break; + } + } + } + } // end of namespace processor2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx new file mode 100644 index 000000000000..ef351002a1ea --- /dev/null +++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx @@ -0,0 +1,579 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: vclpixelprocessor2d.cxx,v $ + * + * $Revision: 1.16 $ + * + * last change: $Author: aw $ $Date: 2008-06-26 16:21:48 $ + * + * 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/processor2d/vclpixelprocessor2d.hxx> +#include <vcl/outdev.hxx> +#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> +#include <drawinglayer/primitive2d/textprimitive2d.hxx> +#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> +#include <drawinglayer/primitive2d/polygonprimitive2d.hxx> +#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> +#include <drawinglayer/primitive2d/fillbitmapprimitive2d.hxx> +#include <drawinglayer/primitive2d/metafileprimitive2d.hxx> +#include <drawinglayer/primitive2d/maskprimitive2d.hxx> +#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx> +#include <drawinglayer/primitive2d/alphaprimitive2d.hxx> +#include <drawinglayer/primitive2d/transformprimitive2d.hxx> +#include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx> +#include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx> +#include <drawinglayer/primitive2d/wrongspellprimitive2d.hxx> +#include <drawinglayer/primitive2d/controlprimitive2d.hxx> +#include <com/sun/star/awt/XWindow2.hpp> +#include <drawinglayer/primitive2d/unifiedalphaprimitive2d.hxx> +#include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx> +#include <drawinglayer/primitive2d/chartprimitive2d.hxx> +#include <helperchartrenderer.hxx> +#include <helperwrongspellrenderer.hxx> +#include <drawinglayer/primitive2d/fillhatchprimitive2d.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <vcl/hatch.hxx> +#include <tools/diagnose_ex.h> +#include <com/sun/star/awt/PosSize.hpp> +#include <drawinglayer/primitive2d/invertprimitive2d.hxx> +#include <cstdio> +#include <drawinglayer/primitive2d/backgroundcolorprimitive2d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace processor2d + { + VclPixelProcessor2D::VclPixelProcessor2D(const geometry::ViewInformation2D& rViewInformation, OutputDevice& rOutDev) + : VclProcessor2D(rViewInformation, rOutDev), + maOriginalMapMode(rOutDev.GetMapMode()) + { + // prepare maCurrentTransformation matrix with viewTransformation to target directly to pixels + maCurrentTransformation = rViewInformation.getObjectToViewTransformation(); + + // prepare output directly to pixels + mpOutputDevice->Push(PUSH_MAPMODE); + mpOutputDevice->SetMapMode(); + + // react on AntiAliasing settings + if(getOptionsDrawinglayer().IsAntiAliasing()) + { + mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() | ANTIALIASING_ENABLE_B2DDRAW); + } + else + { + mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() & ~ANTIALIASING_ENABLE_B2DDRAW); + } + } + + VclPixelProcessor2D::~VclPixelProcessor2D() + { + // restore MapMode + mpOutputDevice->Pop(); + + // restore AntiAliasing + mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() & ~ANTIALIASING_ENABLE_B2DDRAW); + } + + void VclPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate) + { + switch(rCandidate.getPrimitiveID()) + { + case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D : + { + // directdraw of wrong spell primitive; added test possibility to check wrong spell decompose + static bool bHandleWrongSpellDirectly(true); + + if(bHandleWrongSpellDirectly) + { + const primitive2d::WrongSpellPrimitive2D& rWrongSpellPrimitive = static_cast< const primitive2d::WrongSpellPrimitive2D& >(rCandidate); + + if(!renderWrongSpellPrimitive2D( + rWrongSpellPrimitive, + *mpOutputDevice, + maCurrentTransformation, + maBColorModifierStack)) + { + // fallback to decomposition (MetaFile) + process(rWrongSpellPrimitive.get2DDecomposition(getViewInformation2D())); + } + } + else + { + process(rCandidate.get2DDecomposition(getViewInformation2D())); + } + break; + } + case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D : + { + // directdraw of text simple portion; added test possibility to check text decompose + static bool bForceSimpleTextDecomposition(false); + + // Adapt evtl. used special DrawMode + const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode()); + adaptTextToFillDrawMode(); + + if(!bForceSimpleTextDecomposition && getOptionsDrawinglayer().IsRenderSimpleTextDirect()) + { + RenderTextSimpleOrDecoratedPortionPrimitive2D(static_cast< const primitive2d::TextSimplePortionPrimitive2D& >(rCandidate)); + } + else + { + process(rCandidate.get2DDecomposition(getViewInformation2D())); + } + + // restore DrawMode + mpOutputDevice->SetDrawMode(nOriginalDrawMode); + + break; + } + case PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D : + { + // directdraw of text simple portion; added test possibility to check text decompose + static bool bForceComplexTextDecomposition(false); + + // Adapt evtl. used special DrawMode + const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode()); + adaptTextToFillDrawMode(); + + if(!bForceComplexTextDecomposition && getOptionsDrawinglayer().IsRenderDecoratedTextDirect()) + { + RenderTextSimpleOrDecoratedPortionPrimitive2D(static_cast< const primitive2d::TextSimplePortionPrimitive2D& >(rCandidate)); + } + else + { + process(rCandidate.get2DDecomposition(getViewInformation2D())); + } + + // restore DrawMode + mpOutputDevice->SetDrawMode(nOriginalDrawMode); + + break; + } + case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D : + { + // direct draw of hairline + RenderPolygonHairlinePrimitive2D(static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate), true); + break; + } + case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D : + { + // direct draw of transformed BitmapEx primitive + RenderBitmapPrimitive2D(static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_FILLBITMAPPRIMITIVE2D : + { + // direct draw of fillBitmapPrimitive + RenderFillBitmapPrimitive2D(static_cast< const primitive2d::FillBitmapPrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D : + { + if(getOptionsDrawinglayer().IsAntiAliasing()) + { + // For AA, direct render has to be avoided since it uses XOR maskings which will not + // work with AA. Instead, the decompose which uses MaskPrimitive2D with fillings is + // used + process(rCandidate.get2DDecomposition(getViewInformation2D())); + } + else + { + // direct draw of gradient + RenderPolyPolygonGradientPrimitive2D(static_cast< const primitive2d::PolyPolygonGradientPrimitive2D& >(rCandidate)); + } + break; + } + case PRIMITIVE2D_ID_POLYPOLYGONBITMAPPRIMITIVE2D : + { + // direct draw of bitmap + RenderPolyPolygonBitmapPrimitive2D(static_cast< const primitive2d::PolyPolygonBitmapPrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D : + { + // direct draw of PolyPolygon with color + RenderPolyPolygonColorPrimitive2D(static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D : + { + // #i98289# + const bool bForceLineSnap(getOptionsDrawinglayer().IsAntiAliasing() && getOptionsDrawinglayer().IsSnapHorVerLinesToDiscrete()); + const sal_uInt16 nOldAntiAliase(mpOutputDevice->GetAntialiasing()); + + if(bForceLineSnap) + { + mpOutputDevice->SetAntialiasing(nOldAntiAliase | ANTIALIASING_PIXELSNAPHAIRLINE); + } + + // direct draw of MetaFile + RenderMetafilePrimitive2D(static_cast< const primitive2d::MetafilePrimitive2D& >(rCandidate)); + + if(bForceLineSnap) + { + mpOutputDevice->SetAntialiasing(nOldAntiAliase); + } + + break; + } + case PRIMITIVE2D_ID_MASKPRIMITIVE2D : + { + // mask group. + RenderMaskPrimitive2DPixel(static_cast< const primitive2d::MaskPrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D : + { + // modified color group. Force output to unified color. + RenderModifiedColorPrimitive2D(static_cast< const primitive2d::ModifiedColorPrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_UNIFIEDALPHAPRIMITIVE2D : + { + // Detect if a single PolyPolygonColorPrimitive2D is contained; in that case, + // use the faster OutputDevice::DrawTransparent method + const primitive2d::UnifiedAlphaPrimitive2D& rUniAlphaCandidate = static_cast< const primitive2d::UnifiedAlphaPrimitive2D& >(rCandidate); + const primitive2d::Primitive2DSequence rContent = rUniAlphaCandidate.getChildren(); + bool bDrawTransparentUsed(false); + + // since DEV300 m33 DrawTransparent is supported in VCL (for some targets + // natively), so i am now enabling this shortcut + static bool bAllowUsingDrawTransparent(true); + + if(bAllowUsingDrawTransparent && rContent.hasElements() && 1 == rContent.getLength()) + { + const primitive2d::Primitive2DReference xReference(rContent[0]); + const primitive2d::PolyPolygonColorPrimitive2D* pPoPoColor = dynamic_cast< const primitive2d::PolyPolygonColorPrimitive2D* >(xReference.get()); + + if(pPoPoColor && PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D == pPoPoColor->getPrimitiveID()) + { + // single transparent PolyPolygon identified, use directly + const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(pPoPoColor->getBColor())); + mpOutputDevice->SetFillColor(Color(aPolygonColor)); + mpOutputDevice->SetLineColor(); + + basegfx::B2DPolyPolygon aLocalPolyPolygon(pPoPoColor->getB2DPolyPolygon()); + aLocalPolyPolygon.transform(maCurrentTransformation); + + mpOutputDevice->DrawTransparent(aLocalPolyPolygon, rUniAlphaCandidate.getAlpha()); + bDrawTransparentUsed = true; + } + } + + if(!bDrawTransparentUsed) + { + // unified sub-transparence. Draw to VDev first. + RenderUnifiedAlphaPrimitive2D(rUniAlphaCandidate); + } + + break; + } + case PRIMITIVE2D_ID_ALPHAPRIMITIVE2D : + { + // sub-transparence group. Draw to VDev first. + RenderAlphaPrimitive2D(static_cast< const primitive2d::AlphaPrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D : + { + // transform group. + RenderTransformPrimitive2D(static_cast< const primitive2d::TransformPrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D : + { + // new XDrawPage for ViewInformation2D + RenderPagePreviewPrimitive2D(static_cast< const primitive2d::PagePreviewPrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D : + { + // marker array + RenderMarkerArrayPrimitive2D(static_cast< const primitive2d::MarkerArrayPrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D : + { + // point array + RenderPointArrayPrimitive2D(static_cast< const primitive2d::PointArrayPrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D : + { + // control primitive + const primitive2d::ControlPrimitive2D& rControlPrimitive = static_cast< const primitive2d::ControlPrimitive2D& >(rCandidate); + const uno::Reference< awt::XControl >& rXControl(rControlPrimitive.getXControl()); + + try + { + // remember old graphics and create new + uno::Reference< awt::XView > xControlView(rXControl, uno::UNO_QUERY_THROW); + const uno::Reference< awt::XGraphics > xOriginalGraphics(xControlView->getGraphics()); + const uno::Reference< awt::XGraphics > xNewGraphics(mpOutputDevice->CreateUnoGraphics()); + + if(xNewGraphics.is()) + { + // link graphics and view + xControlView->setGraphics(xNewGraphics); + + // get position + const basegfx::B2DHomMatrix aObjectToPixel(maCurrentTransformation * rControlPrimitive.getTransform()); + const basegfx::B2DPoint aTopLeftPixel(aObjectToPixel * basegfx::B2DPoint(0.0, 0.0)); + + // find out if the control is already visualized as a VCL-ChildWindow. If yes, + // it does not need to be painted at all. + uno::Reference< awt::XWindow2 > xControlWindow(rXControl, uno::UNO_QUERY_THROW); + const bool bControlIsVisibleAsChildWindow(rXControl->getPeer().is() && xControlWindow->isVisible()); + + if(!bControlIsVisibleAsChildWindow) + { + // draw it. Do not forget to use the evtl. offsetted origin of the target device, + // e.g. when used with mask/transparence buffer device + const Point aOrigin(mpOutputDevice->GetMapMode().GetOrigin()); + xControlView->draw( + aOrigin.X() + basegfx::fround(aTopLeftPixel.getX()), + aOrigin.Y() + basegfx::fround(aTopLeftPixel.getY())); + } + + // restore original graphics + xControlView->setGraphics(xOriginalGraphics); + } + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION(); + + // process recursively and use the decomposition as Bitmap + process(rCandidate.get2DDecomposition(getViewInformation2D())); + } + + break; + } + case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D: + { + // the stroke primitive may be decomposed to filled polygons. To keep + // evtl. set DrawModes aka DRAWMODE_BLACKLINE, DRAWMODE_GRAYLINE, + // DRAWMODE_GHOSTEDLINE, DRAWMODE_WHITELINE or DRAWMODE_SETTINGSLINE + // working, these need to be copied to the corresponding fill modes + const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode()); + adaptLineToFillDrawMode(); + + // polygon stroke primitive + static bool bSuppressFatToHairlineCorrection(false); + + if(bSuppressFatToHairlineCorrection) + { + // remeber that we enter a PolygonStrokePrimitive2D decomposition, + // used for AA thick line drawing + mnPolygonStrokePrimitive2D++; + + // with AA there is no need to handle thin lines special + process(rCandidate.get2DDecomposition(getViewInformation2D())); + + // leave PolygonStrokePrimitive2D + mnPolygonStrokePrimitive2D--; + } + else + { + // Lines with 1 and 2 pixel width without AA need special treatment since their vsiualisation + // as filled polygons is geometrically corret but looks wrong since polygon filling avoids + // the right and bottom pixels. The used method evaluates that and takes the correct action, + // including calling recursively with decomposition if line is wide enough + const primitive2d::PolygonStrokePrimitive2D& rPolygonStrokePrimitive = static_cast< const primitive2d::PolygonStrokePrimitive2D& >(rCandidate); + + RenderPolygonStrokePrimitive2D(rPolygonStrokePrimitive); + } + + // restore DrawMode + mpOutputDevice->SetDrawMode(nOriginalDrawMode); + + break; + } + case PRIMITIVE2D_ID_CHARTPRIMITIVE2D : + { + // chart primitive in pixel renderer; restore original DrawMode during call + // since the evtl. used ChartPrettyPainter will use the MapMode + const primitive2d::ChartPrimitive2D& rChartPrimitive = static_cast< const primitive2d::ChartPrimitive2D& >(rCandidate); + mpOutputDevice->Push(PUSH_MAPMODE); + mpOutputDevice->SetMapMode(maOriginalMapMode); + + if(!renderChartPrimitive2D( + rChartPrimitive, + *mpOutputDevice, + getViewInformation2D())) + { + // fallback to decomposition (MetaFile) + process(rChartPrimitive.get2DDecomposition(getViewInformation2D())); + } + + mpOutputDevice->Pop(); + break; + } + case PRIMITIVE2D_ID_FILLHATCHPRIMITIVE2D : + { + static bool bForceIgnoreHatchSmoothing(false); + + if(bForceIgnoreHatchSmoothing || getOptionsDrawinglayer().IsAntiAliasing()) + { + // if AA is used (or ignore smoothing is on), there is no need to smooth + // hatch painting, use decomposition + process(rCandidate.get2DDecomposition(getViewInformation2D())); + } + else + { + // without AA, use VCL to draw the hatch. It snaps hatch distances to the next pixel + // and forces hatch distance to be >= 3 pixels to make the hatch display look smoother. + // This is wrong in principle, but looks nicer. This could also be done here directly + // without VCL usage if needed + const primitive2d::FillHatchPrimitive2D& rFillHatchPrimitive = static_cast< const primitive2d::FillHatchPrimitive2D& >(rCandidate); + + // create hatch polygon in range size and discrete coordinates + basegfx::B2DRange aHatchRange(rFillHatchPrimitive.getObjectRange()); + aHatchRange.transform(maCurrentTransformation); + const basegfx::B2DPolygon aHatchPolygon(basegfx::tools::createPolygonFromRect(aHatchRange)); + + // set hatch line color + const basegfx::BColor aHatchColor(maBColorModifierStack.getModifiedColor(rFillHatchPrimitive.getBColor())); + mpOutputDevice->SetFillColor(); + mpOutputDevice->SetLineColor(Color(aHatchColor)); + + // get hatch style + const attribute::FillHatchAttribute& rFillHatchAttributes = rFillHatchPrimitive.getFillHatch(); + HatchStyle eHatchStyle(HATCH_SINGLE); + + switch(rFillHatchAttributes.getStyle()) + { + default : // HATCHSTYLE_SINGLE + { + break; + } + case attribute::HATCHSTYLE_DOUBLE : + { + eHatchStyle = HATCH_DOUBLE; + break; + } + case attribute::HATCHSTYLE_TRIPLE : + { + eHatchStyle = HATCH_TRIPLE; + break; + } + } + + // create hatch + const basegfx::B2DVector aDiscreteDistance(maCurrentTransformation * basegfx::B2DVector(rFillHatchAttributes.getDistance(), 0.0)); + const sal_uInt32 nDistance(basegfx::fround(aDiscreteDistance.getLength())); + const sal_uInt16 nAngle10((sal_uInt16)basegfx::fround(rFillHatchAttributes.getAngle() / F_PI1800)); + ::Hatch aVCLHatch(eHatchStyle, Color(rFillHatchAttributes.getColor()), nDistance, nAngle10); + + // draw hatch using VCL + mpOutputDevice->DrawHatch(PolyPolygon(Polygon(aHatchPolygon)), aVCLHatch); + } + break; + } + case PRIMITIVE2D_ID_BACKGROUNDCOLORPRIMITIVE2D : + { + // #i98404# Handle directly, especially when AA is active + const primitive2d::BackgroundColorPrimitive2D& rPrimitive = static_cast< const primitive2d::BackgroundColorPrimitive2D& >(rCandidate); + const sal_uInt16 nOriginalAA(mpOutputDevice->GetAntialiasing()); + + // switch AA off in all cases + mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() & ~ANTIALIASING_ENABLE_B2DDRAW); + + // create color for fill + const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPrimitive.getBColor())); + mpOutputDevice->SetFillColor(Color(aPolygonColor)); + mpOutputDevice->SetLineColor(); + + // create rectangle for fill + const basegfx::B2DRange& aViewport(getViewInformation2D().getDiscreteViewport()); + const Rectangle aRectangle( + (sal_Int32)floor(aViewport.getMinX()), (sal_Int32)floor(aViewport.getMinY()), + (sal_Int32)ceil(aViewport.getMaxX()), (sal_Int32)ceil(aViewport.getMaxY())); + mpOutputDevice->DrawRect(aRectangle); + + // restore AA setting + mpOutputDevice->SetAntialiasing(nOriginalAA); + + break; + } + case PRIMITIVE2D_ID_TEXTHIERARCHYEDITPRIMITIVE2D : + { + // #i97628# + // This primitive means that the content is derived from an active text edit, + // not from model data itself. Some renderers need to suppress this content, e.g. + // the pixel renderer used for displaying the edit view (like this one). It's + // not to be suppressed by the MetaFile renderers, so that the edited text is + // part of the MetaFile, e.g. needed for presentation previews. + // Action: Ignore here, do nothing. + break; + } + case PRIMITIVE2D_ID_INVERTPRIMITIVE2D : + { + // invert primitive (currently only used for HighContrast fallback for selection in SW and SC). + // Set OutDev to XOR + mpOutputDevice->Push(); + mpOutputDevice->SetRasterOp( ROP_XOR ); + + // force paint color to white by using ColorModifierStack + const basegfx::BColor aColWhite(1.0, 1.0, 1.0); + const basegfx::BColorModifier aColorModifier(aColWhite, 0.0, basegfx::BCOLORMODIFYMODE_REPLACE); + maBColorModifierStack.push(aColorModifier); + + // process content recursively + process(rCandidate.get2DDecomposition(getViewInformation2D())); + + // restore ColorModifierStack + maBColorModifierStack.pop(); + + // restore OutDev + mpOutputDevice->Pop(); + break; + } + default : + { + // process recursively + process(rCandidate.get2DDecomposition(getViewInformation2D())); + break; + } + } + } + } // end of namespace processor2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/processor2d/vclprocessor2d.cxx b/drawinglayer/source/processor2d/vclprocessor2d.cxx new file mode 100644 index 000000000000..ede5aee730cf --- /dev/null +++ b/drawinglayer/source/processor2d/vclprocessor2d.cxx @@ -0,0 +1,1413 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: vclprocessor2d.cxx,v $ + * + * 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/processor2d/vclprocessor2d.hxx> +#include <drawinglayer/primitive2d/textprimitive2d.hxx> +#include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx> +#include <tools/debug.hxx> +#include <vcl/outdev.hxx> +#include <drawinglayer/primitive2d/polygonprimitive2d.hxx> +#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> +#include <vclhelperbitmaptransform.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <vclhelperbitmaprender.hxx> +#include <drawinglayer/attribute/sdrfillbitmapattribute.hxx> +#include <drawinglayer/primitive2d/fillbitmapprimitive2d.hxx> +#include <drawinglayer/attribute/fillattribute.hxx> +#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> +#include <vclhelpergradient.hxx> +#include <drawinglayer/primitive2d/metafileprimitive2d.hxx> +#include <drawinglayer/primitive2d/maskprimitive2d.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <vclhelperbufferdevice.hxx> +#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx> +#include <drawinglayer/primitive2d/unifiedalphaprimitive2d.hxx> +#include <drawinglayer/primitive2d/alphaprimitive2d.hxx> +#include <drawinglayer/primitive2d/transformprimitive2d.hxx> +#include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx> +#include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx> +#include <drawinglayer/primitive2d/wrongspellprimitive2d.hxx> +#include <svtools/ctloptions.hxx> +#include <vcl/svapp.hxx> +#include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx> +#include <tools/diagnose_ex.h> +#include <vcl/metric.hxx> + +////////////////////////////////////////////////////////////////////////////// +// control support + +#include <com/sun/star/awt/XWindow2.hpp> +#include <com/sun/star/awt/PosSize.hpp> +#include <com/sun/star/awt/XView.hpp> +#include <drawinglayer/primitive2d/controlprimitive2d.hxx> +#include <drawinglayer/primitive2d/textlayoutdevice.hxx> + +////////////////////////////////////////////////////////////////////////////// +// for test, can be removed again + +#include <basegfx/polygon/b2dpolygonclipper.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace processor2d + { + ////////////////////////////////////////////////////////////////////////////// + // UNO class usages + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::awt::XView; + using ::com::sun::star::awt::XGraphics; + using ::com::sun::star::awt::XWindow; + using ::com::sun::star::awt::PosSize::POSSIZE; + + static FontUnderline mapTextLineStyle(primitive2d::FontUnderline eLineStyle) + { + switch(eLineStyle) + { + default: + DBG_WARNING1( "DrawingLayer: Unknown text line style attribute (%d)!", eLineStyle ); + // fall through + case primitive2d::FONT_UNDERLINE_NONE: return UNDERLINE_NONE; + case primitive2d::FONT_UNDERLINE_SINGLE: return UNDERLINE_SINGLE; + case primitive2d::FONT_UNDERLINE_DOUBLE: return UNDERLINE_DOUBLE; + case primitive2d::FONT_UNDERLINE_DOTTED: return UNDERLINE_DOTTED; + case primitive2d::FONT_UNDERLINE_DASH: return UNDERLINE_DASH; + case primitive2d::FONT_UNDERLINE_LONGDASH: return UNDERLINE_LONGDASH; + case primitive2d::FONT_UNDERLINE_DASHDOT: return UNDERLINE_DASHDOT; + case primitive2d::FONT_UNDERLINE_DASHDOTDOT: return UNDERLINE_DASHDOTDOT; + case primitive2d::FONT_UNDERLINE_SMALLWAVE: return UNDERLINE_SMALLWAVE; + case primitive2d::FONT_UNDERLINE_WAVE: return UNDERLINE_WAVE; + case primitive2d::FONT_UNDERLINE_DOUBLEWAVE: return UNDERLINE_DOUBLEWAVE; + case primitive2d::FONT_UNDERLINE_BOLD: return UNDERLINE_BOLD; + case primitive2d::FONT_UNDERLINE_BOLDDOTTED: return UNDERLINE_BOLDDOTTED; + case primitive2d::FONT_UNDERLINE_BOLDDASH: return UNDERLINE_BOLDDASH; + case primitive2d::FONT_UNDERLINE_BOLDLONGDASH: return UNDERLINE_LONGDASH; + case primitive2d::FONT_UNDERLINE_BOLDDASHDOT: return UNDERLINE_BOLDDASHDOT; + case primitive2d::FONT_UNDERLINE_BOLDDASHDOTDOT:return UNDERLINE_BOLDDASHDOT; + case primitive2d::FONT_UNDERLINE_BOLDWAVE: return UNDERLINE_BOLDWAVE; + } + } + + ////////////////////////////////////////////////////////////////////////////// + // rendering support + + // directdraw of text simple portion or decorated portion primitive. When decorated, all the extra + // information is translated to VCL parameters and set at the font. + // Acceptance is restricted to no shearing and positive scaling in X and Y (no font mirroring + // for VCL) + void VclProcessor2D::RenderTextSimpleOrDecoratedPortionPrimitive2D(const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate) + { + // decompose matrix to have position and size of text + basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation * rTextCandidate.getTextTransform()); + basegfx::B2DVector aFontScaling, aTranslate; + double fRotate, fShearX; + aLocalTransform.decompose(aFontScaling, aTranslate, fRotate, fShearX); + bool bPrimitiveAccepted(false); + + if(basegfx::fTools::equalZero(fShearX)) + { + if(basegfx::fTools::less(aFontScaling.getX(), 0.0) && basegfx::fTools::less(aFontScaling.getY(), 0.0)) + { + // handle special case: If scale is negative in (x,y) (3rd quadrant), it can + // be expressed as rotation by PI. Use this since the Font rendering will not + // apply the negative scales in any form + aFontScaling = basegfx::absolute(aFontScaling); + fRotate += F_PI; + } + + if(basegfx::fTools::more(aFontScaling.getX(), 0.0) && basegfx::fTools::more(aFontScaling.getY(), 0.0)) + { + // Get the VCL font (use FontHeight as FontWidth) + Font aFont(primitive2d::getVclFontFromFontAttributes( + rTextCandidate.getFontAttributes(), + aFontScaling.getX(), + aFontScaling.getY(), + fRotate, + rTextCandidate.getLocale())); + + // handle additional font attributes + const primitive2d::TextDecoratedPortionPrimitive2D* pTCPP = + dynamic_cast<const primitive2d::TextDecoratedPortionPrimitive2D*>( &rTextCandidate ); + + if( pTCPP != NULL ) + { + + // set the color of text decorations + const basegfx::BColor aTextlineColor = maBColorModifierStack.getModifiedColor(pTCPP->getTextlineColor()); + mpOutputDevice->SetTextLineColor( Color(aTextlineColor) ); + + // set Overline attribute + FontUnderline eFontOverline = mapTextLineStyle( pTCPP->getFontOverline() ); + if( eFontOverline != UNDERLINE_NONE ) + { + aFont.SetOverline( eFontOverline ); + const basegfx::BColor aOverlineColor = maBColorModifierStack.getModifiedColor(pTCPP->getOverlineColor()); + mpOutputDevice->SetOverlineColor( Color(aOverlineColor) ); + if( pTCPP->getWordLineMode() ) + aFont.SetWordLineMode( true ); + } + + // set Underline attribute + FontUnderline eFontUnderline = mapTextLineStyle( pTCPP->getFontUnderline() ); + if( eFontUnderline != UNDERLINE_NONE ) + { + aFont.SetUnderline( eFontUnderline ); + if( pTCPP->getWordLineMode() ) + aFont.SetWordLineMode( true ); +//TODO: ??? if( pTCPP->getUnderlineAbove() ) +// aFont.SetUnderlineAbove( true ); + } + + // set Strikeout attribute + FontStrikeout eFontStrikeout = STRIKEOUT_NONE; + switch( pTCPP->getFontStrikeout() ) + { + default: + DBG_WARNING1( "DrawingLayer: Unknown strikeout attribute (%d)!", pTCPP->getFontStrikeout() ); + // fall through + case primitive2d::FONT_STRIKEOUT_NONE: eFontStrikeout = STRIKEOUT_NONE; break; + case primitive2d::FONT_STRIKEOUT_SINGLE: eFontStrikeout = STRIKEOUT_SINGLE; break; + case primitive2d::FONT_STRIKEOUT_DOUBLE: eFontStrikeout = STRIKEOUT_DOUBLE; break; + case primitive2d::FONT_STRIKEOUT_BOLD: eFontStrikeout = STRIKEOUT_BOLD; break; + case primitive2d::FONT_STRIKEOUT_SLASH: eFontStrikeout = STRIKEOUT_SLASH; break; + case primitive2d::FONT_STRIKEOUT_X: eFontStrikeout = STRIKEOUT_X; break; + } + + if( eFontStrikeout != STRIKEOUT_NONE ) + aFont.SetStrikeout( eFontStrikeout ); + + // set EmphasisMark attribute + FontEmphasisMark eFontEmphasisMark = EMPHASISMARK_NONE; + switch( pTCPP->getFontEmphasisMark() ) + { + default: + DBG_WARNING1( "DrawingLayer: Unknown EmphasisMark style (%d)!", pTCPP->getFontEmphasisMark() ); + // fall through + case primitive2d::FONT_EMPHASISMARK_NONE: eFontEmphasisMark = EMPHASISMARK_NONE; break; + case primitive2d::FONT_EMPHASISMARK_DOT: eFontEmphasisMark = EMPHASISMARK_DOT; break; + case primitive2d::FONT_EMPHASISMARK_CIRCLE: eFontEmphasisMark = EMPHASISMARK_CIRCLE; break; + case primitive2d::FONT_EMPHASISMARK_DISC: eFontEmphasisMark = EMPHASISMARK_DISC; break; + case primitive2d::FONT_EMPHASISMARK_ACCENT: eFontEmphasisMark = EMPHASISMARK_ACCENT; break; + } + + if( eFontEmphasisMark != EMPHASISMARK_NONE ) + { + DBG_ASSERT( (pTCPP->getEmphasisMarkAbove() != pTCPP->getEmphasisMarkBelow()), + "DrawingLayer: Bad EmphasisMark position!" ); + if( pTCPP->getEmphasisMarkAbove() ) + eFontEmphasisMark |= EMPHASISMARK_POS_ABOVE; + else + eFontEmphasisMark |= EMPHASISMARK_POS_BELOW; + aFont.SetEmphasisMark( eFontEmphasisMark ); + } + + // set Relief attribute + FontRelief eFontRelief = RELIEF_NONE; + switch( pTCPP->getFontRelief() ) + { + default: + DBG_WARNING1( "DrawingLayer: Unknown Relief style (%d)!", pTCPP->getFontRelief() ); + // fall through + case primitive2d::FONT_RELIEF_NONE: eFontRelief = RELIEF_NONE; break; + case primitive2d::FONT_RELIEF_EMBOSSED: eFontRelief = RELIEF_EMBOSSED; break; + case primitive2d::FONT_RELIEF_ENGRAVED: eFontRelief = RELIEF_ENGRAVED; break; + } + + if( eFontRelief != RELIEF_NONE ) + aFont.SetRelief( eFontRelief ); + + // set Shadow attribute + if( pTCPP->getShadow() ) + aFont.SetShadow( true ); + } + + // create transformed integer DXArray in view coordinate system + ::std::vector< sal_Int32 > aTransformedDXArray; + + if(rTextCandidate.getDXArray().size()) + { + aTransformedDXArray.reserve(rTextCandidate.getDXArray().size()); + const basegfx::B2DVector aPixelVector(maCurrentTransformation * basegfx::B2DVector(1.0, 0.0)); + const double fPixelVectorFactor(aPixelVector.getLength()); + + for(::std::vector< double >::const_iterator aStart(rTextCandidate.getDXArray().begin()); + aStart != rTextCandidate.getDXArray().end(); aStart++) + { + aTransformedDXArray.push_back(basegfx::fround((*aStart) * fPixelVectorFactor)); + } + } + + // set parameters and paint text snippet + const basegfx::BColor aRGBFontColor(maBColorModifierStack.getModifiedColor(rTextCandidate.getFontColor())); + const basegfx::B2DPoint aPoint(aLocalTransform * basegfx::B2DPoint(0.0, 0.0)); + const Point aStartPoint(basegfx::fround(aPoint.getX()), basegfx::fround(aPoint.getY())); + const sal_uInt32 nOldLayoutMode(mpOutputDevice->GetLayoutMode()); + + if(rTextCandidate.getFontAttributes().getRTL()) + { + sal_uInt32 nRTLLayoutMode(nOldLayoutMode & ~(TEXT_LAYOUT_COMPLEX_DISABLED|TEXT_LAYOUT_BIDI_STRONG)); + nRTLLayoutMode |= TEXT_LAYOUT_BIDI_RTL|TEXT_LAYOUT_TEXTORIGIN_LEFT; + mpOutputDevice->SetLayoutMode(nRTLLayoutMode); + } + + mpOutputDevice->SetFont(aFont); + mpOutputDevice->SetTextColor(Color(aRGBFontColor)); + + if(aTransformedDXArray.size()) + { + mpOutputDevice->DrawTextArray( + aStartPoint, + rTextCandidate.getText(), + &(aTransformedDXArray[0]), + rTextCandidate.getTextPosition(), + rTextCandidate.getTextLength()); + } + else + { + mpOutputDevice->DrawText( + aStartPoint, + rTextCandidate.getText(), + rTextCandidate.getTextPosition(), + rTextCandidate.getTextLength()); + } + + if(rTextCandidate.getFontAttributes().getRTL()) + { + mpOutputDevice->SetLayoutMode(nOldLayoutMode); + } + + bPrimitiveAccepted = true; + } + } + + if(!bPrimitiveAccepted) + { + // let break down + process(rTextCandidate.get2DDecomposition(getViewInformation2D())); + } + } + + // direct draw of hairline + void VclProcessor2D::RenderPolygonHairlinePrimitive2D(const primitive2d::PolygonHairlinePrimitive2D& rPolygonCandidate, bool bPixelBased) + { + const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor())); + mpOutputDevice->SetLineColor(Color(aHairlineColor)); + mpOutputDevice->SetFillColor(); + + basegfx::B2DPolygon aLocalPolygon(rPolygonCandidate.getB2DPolygon()); + aLocalPolygon.transform(maCurrentTransformation); + + if(bPixelBased && getOptionsDrawinglayer().IsAntiAliasing() && getOptionsDrawinglayer().IsSnapHorVerLinesToDiscrete()) + { + // #i98289# + // when a Hairline is painted and AntiAliasing is on the option SnapHorVerLinesToDiscrete + // allows to suppress AntiAliasing for pure horizontal or vertical lines. This is done since + // not-AntiAliased such lines look more pleasing to the eye (e.g. 2D chart content). This + // NEEDS to be done in discrete coordinates, so only useful for pixel based rendering. + aLocalPolygon = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aLocalPolygon); + } + + mpOutputDevice->DrawPolyLine(aLocalPolygon, 0.0); + } + + // direct draw of transformed BitmapEx primitive + void VclProcessor2D::RenderBitmapPrimitive2D(const primitive2d::BitmapPrimitive2D& rBitmapCandidate) + { + // create local transform + basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation * rBitmapCandidate.getTransform()); + BitmapEx aBitmapEx(rBitmapCandidate.getBitmapEx()); + bool bPainted(false); + + if(maBColorModifierStack.count()) + { + aBitmapEx = impModifyBitmapEx(maBColorModifierStack, aBitmapEx); + + if(aBitmapEx.IsEmpty()) + { + // color gets completely replaced, get it + const basegfx::BColor aModifiedColor(maBColorModifierStack.getModifiedColor(basegfx::BColor())); + basegfx::B2DPolygon aPolygon(basegfx::tools::createPolygonFromRect(basegfx::B2DRange(0.0, 0.0, 1.0, 1.0))); + aPolygon.transform(aLocalTransform); + + mpOutputDevice->SetFillColor(Color(aModifiedColor)); + mpOutputDevice->SetLineColor(); + mpOutputDevice->DrawPolygon(aPolygon); + + bPainted = true; + } + } + + if(!bPainted) + { + static bool bForceUseOfOwnTransformer(false); + static bool bUseGraphicManager(true); + + // decompose matrix to check for shear, rotate and mirroring + basegfx::B2DVector aScale, aTranslate; + double fRotate, fShearX; + aLocalTransform.decompose(aScale, aTranslate, fRotate, fShearX); + + if(!bForceUseOfOwnTransformer && basegfx::fTools::equalZero(fShearX)) + { + if(!bUseGraphicManager && basegfx::fTools::equalZero(fRotate)) + { + RenderBitmapPrimitive2D_BitmapEx(*mpOutputDevice, aBitmapEx, aLocalTransform); + } + else + { + RenderBitmapPrimitive2D_GraphicManager(*mpOutputDevice, aBitmapEx, aLocalTransform); + } + } + else + { + if(!aBitmapEx.IsTransparent() && (!basegfx::fTools::equalZero(fShearX) || !basegfx::fTools::equalZero(fRotate))) + { + // parts will be uncovered, extend aBitmapEx with a mask bitmap + const Bitmap aContent(aBitmapEx.GetBitmap()); + aBitmapEx = BitmapEx(aContent, Bitmap(aContent.GetSizePixel(), 1)); + } + + RenderBitmapPrimitive2D_self(*mpOutputDevice, aBitmapEx, aLocalTransform); + } + } + } + + void VclProcessor2D::RenderFillBitmapPrimitive2D(const primitive2d::FillBitmapPrimitive2D& rFillBitmapCandidate) + { + const attribute::FillBitmapAttribute& rFillBitmapAttribute(rFillBitmapCandidate.getFillBitmap()); + bool bPrimitiveAccepted(false); + + if(rFillBitmapAttribute.getTiling()) + { + // decompose matrix to check for shear, rotate and mirroring + basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation * rFillBitmapCandidate.getTransformation()); + basegfx::B2DVector aScale, aTranslate; + double fRotate, fShearX; + aLocalTransform.decompose(aScale, aTranslate, fRotate, fShearX); + + if(basegfx::fTools::equalZero(fRotate) && basegfx::fTools::equalZero(fShearX)) + { + // no shear or rotate, draw direct in pixel coordinates + bPrimitiveAccepted = true; + BitmapEx aBitmapEx(rFillBitmapAttribute.getBitmap()); + bool bPainted(false); + + if(maBColorModifierStack.count()) + { + aBitmapEx = impModifyBitmapEx(maBColorModifierStack, aBitmapEx); + + if(aBitmapEx.IsEmpty()) + { + // color gets completely replaced, get it + const basegfx::BColor aModifiedColor(maBColorModifierStack.getModifiedColor(basegfx::BColor())); + basegfx::B2DPolygon aPolygon(basegfx::tools::createPolygonFromRect(basegfx::B2DRange(0.0, 0.0, 1.0, 1.0))); + aPolygon.transform(aLocalTransform); + + mpOutputDevice->SetFillColor(Color(aModifiedColor)); + mpOutputDevice->SetLineColor(); + mpOutputDevice->DrawPolygon(aPolygon); + + bPainted = true; + } + } + + if(!bPainted) + { + const basegfx::B2DPoint aObjTopLeft(aTranslate.getX(), aTranslate.getY()); + const basegfx::B2DPoint aObjBottomRight(aTranslate.getX() + aScale.getX(), aTranslate.getY() + aScale.getY()); + const Point aObjTL(mpOutputDevice->LogicToPixel(Point((sal_Int32)aObjTopLeft.getX(), (sal_Int32)aObjTopLeft.getY()))); + const Point aObjBR(mpOutputDevice->LogicToPixel(Point((sal_Int32)aObjBottomRight.getX(), (sal_Int32)aObjBottomRight.getY()))); + + const basegfx::B2DPoint aBmpTopLeft(aLocalTransform * rFillBitmapAttribute.getTopLeft()); + const basegfx::B2DPoint aBmpBottomRight(aLocalTransform * basegfx::B2DPoint(rFillBitmapAttribute.getTopLeft() + rFillBitmapAttribute.getSize())); + const Point aBmpTL(mpOutputDevice->LogicToPixel(Point((sal_Int32)aBmpTopLeft.getX(), (sal_Int32)aBmpTopLeft.getY()))); + const Point aBmpBR(mpOutputDevice->LogicToPixel(Point((sal_Int32)aBmpBottomRight.getX(), (sal_Int32)aBmpBottomRight.getY()))); + + sal_Int32 nOWidth(aObjBR.X() - aObjTL.X()); + sal_Int32 nOHeight(aObjBR.Y() - aObjTL.Y()); + + // only do something when object has a size in discrete units + if(nOWidth > 0 && nOHeight > 0) + { + sal_Int32 nBWidth(aBmpBR.X() - aBmpTL.X()); + sal_Int32 nBHeight(aBmpBR.Y() - aBmpTL.Y()); + + // only do something when bitmap fill has a size in discrete units + if(nBWidth > 0 && nBHeight > 0) + { + sal_Int32 nBLeft(aBmpTL.X()); + sal_Int32 nBTop(aBmpTL.Y()); + + if(nBLeft > aObjTL.X()) + { + nBLeft -= ((nBLeft / nBWidth) + 1L) * nBWidth; + } + + if(nBLeft + nBWidth <= aObjTL.X()) + { + nBLeft -= (nBLeft / nBWidth) * nBWidth; + } + + if(nBTop > aObjTL.Y()) + { + nBTop -= ((nBTop / nBHeight) + 1L) * nBHeight; + } + + if(nBTop + nBHeight <= aObjTL.Y()) + { + nBTop -= (nBTop / nBHeight) * nBHeight; + } + + // nBWidth, nBHeight is the pixel size of the neede bitmap. To not need to scale it + // in vcl many times, create a size-optimized version + const Size aNeededBitmapSizePixel(nBWidth, nBHeight); + + if(aNeededBitmapSizePixel != aBitmapEx.GetSizePixel()) + { + aBitmapEx.Scale(aNeededBitmapSizePixel); + } + + // prepare OutDev + const Point aEmptyPoint(0, 0); + const Rectangle aVisiblePixel(aEmptyPoint, mpOutputDevice->GetOutputSizePixel()); + const bool bWasEnabled(mpOutputDevice->IsMapModeEnabled()); + mpOutputDevice->EnableMapMode(false); + + for(sal_Int32 nXPos(nBLeft); nXPos < aObjTL.X() + nOWidth; nXPos += nBWidth) + { + for(sal_Int32 nYPos(nBTop); nYPos < aObjTL.Y() + nOHeight; nYPos += nBHeight) + { + const Rectangle aOutRectPixel(Point(nXPos, nYPos), aNeededBitmapSizePixel); + + if(aOutRectPixel.IsOver(aVisiblePixel)) + { + mpOutputDevice->DrawBitmapEx(aOutRectPixel.TopLeft(), aBitmapEx); + } + } + } + + // restore OutDev + mpOutputDevice->EnableMapMode(bWasEnabled); + } + } + } + } + } + + if(!bPrimitiveAccepted) + { + // do not accept, use decomposition + process(rFillBitmapCandidate.get2DDecomposition(getViewInformation2D())); + } + } + + // direct draw of gradient + void VclProcessor2D::RenderPolyPolygonGradientPrimitive2D(const primitive2d::PolyPolygonGradientPrimitive2D& rPolygonCandidate) + { + const attribute::FillGradientAttribute& rGradient(rPolygonCandidate.getFillGradient()); + basegfx::BColor aStartColor(maBColorModifierStack.getModifiedColor(rGradient.getStartColor())); + basegfx::BColor aEndColor(maBColorModifierStack.getModifiedColor(rGradient.getEndColor())); + basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon()); + aLocalPolyPolygon.transform(maCurrentTransformation); + + if(aStartColor == aEndColor) + { + // no gradient at all, draw as polygon + mpOutputDevice->SetLineColor(); + mpOutputDevice->SetFillColor(Color(aStartColor)); + mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon); + } + else + { + impDrawGradientToOutDev( + *mpOutputDevice, aLocalPolyPolygon, rGradient.getStyle(), rGradient.getSteps(), + aStartColor, aEndColor, rGradient.getBorder(), + -rGradient.getAngle(), rGradient.getOffsetX(), rGradient.getOffsetY(), false); + } + } + + // direct draw of bitmap + void VclProcessor2D::RenderPolyPolygonBitmapPrimitive2D(const primitive2d::PolyPolygonBitmapPrimitive2D& rPolygonCandidate) + { + bool bDone(false); + const basegfx::B2DPolyPolygon& rPolyPolygon = rPolygonCandidate.getB2DPolyPolygon(); + + if(rPolyPolygon.count()) + { + const attribute::FillBitmapAttribute& rFillBitmapAttribute = rPolygonCandidate.getFillBitmap(); + const Bitmap& rBitmap = rFillBitmapAttribute.getBitmap(); + + if(rBitmap.IsEmpty()) + { + // empty bitmap, done + bDone = true; + } + else + { + // try to catch cases where the bitmap will be color-modified to a single + // color (e.g. shadow). This would NOT be optimizable with an alpha channel + // at the Bitmap which we do not have here. When this should change, this + // optimization has to be reworked accordingly. + const sal_uInt32 nBColorModifierStackCount(maBColorModifierStack.count()); + + if(nBColorModifierStackCount) + { + const basegfx::BColorModifier& rTopmostModifier = maBColorModifierStack.getBColorModifier(nBColorModifierStackCount - 1); + + if(basegfx::BCOLORMODIFYMODE_REPLACE == rTopmostModifier.getMode()) + { + // the bitmap fill is in unified color, so we can replace it with + // a single polygon fill. The form of the fill depends on tiling + if(rFillBitmapAttribute.getTiling()) + { + // with tiling, fill the whole PolyPolygon with the modifier color + basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolyPolygon); + + aLocalPolyPolygon.transform(maCurrentTransformation); + mpOutputDevice->SetLineColor(); + mpOutputDevice->SetFillColor(Color(rTopmostModifier.getBColor())); + mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon); + } + else + { + // without tiling, only the area common to the bitmap tile and the + // PolyPolygon is filled. Create the bitmap tile area in object + // coordinates. For this, the object transformation needs to be created + // from the already scaled PolyPolygon. The tile area in object + // coordinates wil always be non-rotated, so it's not necessary to + // work with a polygon here + basegfx::B2DRange aTileRange(rFillBitmapAttribute.getTopLeft(), + rFillBitmapAttribute.getTopLeft() + rFillBitmapAttribute.getSize()); + const basegfx::B2DRange aPolyPolygonRange(rPolyPolygon.getB2DRange()); + basegfx::B2DHomMatrix aNewObjectTransform; + + aNewObjectTransform.set(0, 0, aPolyPolygonRange.getWidth()); + aNewObjectTransform.set(1, 1, aPolyPolygonRange.getHeight()); + aNewObjectTransform.set(0, 2, aPolyPolygonRange.getMinX()); + aNewObjectTransform.set(1, 2, aPolyPolygonRange.getMinY()); + aTileRange.transform(aNewObjectTransform); + + // now clip the object polyPolygon against the tile range + // to get the common area (OR) + basegfx::B2DPolyPolygon aTarget = basegfx::tools::clipPolyPolygonOnRange(rPolyPolygon, aTileRange, true, false); + + if(aTarget.count()) + { + aTarget.transform(maCurrentTransformation); + mpOutputDevice->SetLineColor(); + mpOutputDevice->SetFillColor(Color(rTopmostModifier.getBColor())); + mpOutputDevice->DrawPolyPolygon(aTarget); + } + } + + bDone = true; + } + } + } + } + else + { + // empty polyPolygon, done + bDone = true; + } + + if(!bDone) + { + // use default decomposition + process(rPolygonCandidate.get2DDecomposition(getViewInformation2D())); + } + } + + // direct draw of PolyPolygon with color + void VclProcessor2D::RenderPolyPolygonColorPrimitive2D(const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate) + { + const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor())); + mpOutputDevice->SetFillColor(Color(aPolygonColor)); + mpOutputDevice->SetLineColor(); + + basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon()); + aLocalPolyPolygon.transform(maCurrentTransformation); + mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon); + + if(mnPolygonStrokePrimitive2D && getOptionsDrawinglayer().IsAntiAliasing()) + { + // when AA is on and this filled polygons are the result of stroked line geometry, + // draw the geometry once extra as lines to avoid AA 'gaps' between partial polygons + mpOutputDevice->SetFillColor(); + mpOutputDevice->SetLineColor(Color(aPolygonColor)); + const sal_uInt32 nCount(aLocalPolyPolygon.count()); + + for(sal_uInt32 a(0); a < nCount; a++) + { + mpOutputDevice->DrawPolyLine(aLocalPolyPolygon.getB2DPolygon(a), 0.0); + } + } + + static bool bTestPolygonClipping(false); + if(bTestPolygonClipping) + { + static bool bInside(true); + static bool bFilled(false); + static bool bLine(false); + + basegfx::B2DRange aRange(aLocalPolyPolygon.getB2DRange()); + aRange.grow(aRange.getWidth() * -0.1); + + if(bFilled) + { + basegfx::B2DPolyPolygon aFilledClipped(basegfx::tools::clipPolyPolygonOnRange(aLocalPolyPolygon, aRange, bInside, false)); + basegfx::BColor aRand(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0); + mpOutputDevice->SetFillColor(Color(aRand)); + mpOutputDevice->SetLineColor(); + mpOutputDevice->DrawPolyPolygon(aFilledClipped); + } + + if(bLine) + { + basegfx::B2DPolyPolygon aLineClipped(basegfx::tools::clipPolyPolygonOnRange(aLocalPolyPolygon, aRange, bInside, true)); + basegfx::BColor aRand(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0); + mpOutputDevice->SetFillColor(); + mpOutputDevice->SetLineColor(Color(aRand)); + + for(sal_uInt32 a(0); a < aLineClipped.count(); a++) + { + mpOutputDevice->DrawPolyLine(aLineClipped.getB2DPolygon(a), 0.0); + } + } + } + } + + // direct draw of MetaFile + void VclProcessor2D::RenderMetafilePrimitive2D(const primitive2d::MetafilePrimitive2D& rMetaCandidate) + { + // decompose matrix to check for shear, rotate and mirroring + basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation * rMetaCandidate.getTransform()); + basegfx::B2DVector aScale, aTranslate; + double fRotate, fShearX; + aLocalTransform.decompose(aScale, aTranslate, fRotate, fShearX); + + if(basegfx::fTools::less(aScale.getX(), 0.0) && basegfx::fTools::less(aScale.getY(), 0.0)) + { + // #i102175# handle special case: If scale is negative in (x,y) (3rd quadrant), it can + // be expressed as rotation by PI. This needs to be done for Metafiles since + // these can be rotated, but not really mirrored + aScale = basegfx::absolute(aScale); + fRotate += F_PI; + } + + // get BoundRect + basegfx::B2DRange aOutlineRange(rMetaCandidate.getB2DRange(getViewInformation2D())); + aOutlineRange.transform(maCurrentTransformation); + + // Due to the integer MapModes used from VCL aind inside MetaFiles errors of up to three + // pixels in size may happen. As long as there is no better way (e.g. convert the MetaFile + // to primitives) it is necessary to reduce maximum pixel size by 1 in X and Y and to use + // the inner pixel bounds accordingly (ceil resp. floor). This will also be done for logic + // units e.g. when creating a new MetaFile, but since much huger value ranges are used + // there typically will be okay for this compromize. + Rectangle aDestRectView( + // !!CAUTION!! Here, ceil and floor are exchanged BY PURPOSE, do NOT copy when + // looking for a standard conversion to rectangle (!) + (sal_Int32)ceil(aOutlineRange.getMinX()), (sal_Int32)ceil(aOutlineRange.getMinY()), + (sal_Int32)floor(aOutlineRange.getMaxX()), (sal_Int32)floor(aOutlineRange.getMaxY())); + + // get metafile (copy it) + GDIMetaFile aMetaFile; + + if(maBColorModifierStack.count()) + { + const basegfx::BColor aRGBBaseColor(0, 0, 0); + const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(aRGBBaseColor)); + aMetaFile = rMetaCandidate.getMetaFile().GetMonochromeMtf(Color(aRGBColor)); + } + else + { + aMetaFile = rMetaCandidate.getMetaFile(); + } + + // rotation + if(!basegfx::fTools::equalZero(fRotate)) + { + // #i103530# + // MetaFile::Rotate has no input parameter check, so the parameter needs to be + // well-aligned to the old range [0..3600] 10th degrees with inverse orientation + sal_Int16 nRotation((sal_Int16)((fRotate / F_PI180) * -10.0)); + + while(nRotation < 0) + nRotation += 3600; + + while(nRotation >= 3600) + nRotation -= 3600; + + aMetaFile.Rotate(nRotation); + } + + // Prepare target output size + Size aDestSize(aDestRectView.GetSize()); + + if(aDestSize.getWidth() && aDestSize.getHeight()) + { + // Get preferred Metafile output size. When it's very equal to the output size, it's probably + // a rounding error somewhere, so correct it to get a 1:1 output without single pixel scalings + // of the Metafile (esp. for contaned Bitmaps, e.g 3D charts) + const Size aPrefSize(mpOutputDevice->LogicToPixel(aMetaFile.GetPrefSize(), aMetaFile.GetPrefMapMode())); + + if(aPrefSize.getWidth() && (aPrefSize.getWidth() - 1 == aDestSize.getWidth() || aPrefSize.getWidth() + 1 == aDestSize.getWidth())) + { + aDestSize.setWidth(aPrefSize.getWidth()); + } + + if(aPrefSize.getHeight() && (aPrefSize.getHeight() - 1 == aDestSize.getHeight() || aPrefSize.getHeight() + 1 == aDestSize.getHeight())) + { + aDestSize.setHeight(aPrefSize.getHeight()); + } + + // paint it + aMetaFile.WindStart(); + aMetaFile.Play(mpOutputDevice, aDestRectView.TopLeft(), aDestSize); + } + } + + // mask group. Force output to VDev and create mask from given mask + void VclProcessor2D::RenderMaskPrimitive2DPixel(const primitive2d::MaskPrimitive2D& rMaskCandidate) + { + if(rMaskCandidate.getChildren().hasElements()) + { + basegfx::B2DPolyPolygon aMask(rMaskCandidate.getMask()); + + if(aMask.count()) + { + aMask.transform(maCurrentTransformation); + const basegfx::B2DRange aRange(basegfx::tools::getRange(aMask)); + impBufferDevice aBufferDevice(*mpOutputDevice, aRange, true); + + if(aBufferDevice.isVisible()) + { + // remember last OutDev and set to content + OutputDevice* pLastOutputDevice = mpOutputDevice; + mpOutputDevice = &aBufferDevice.getContent(); + + // paint to it + process(rMaskCandidate.getChildren()); + + // back to old OutDev + mpOutputDevice = pLastOutputDevice; + + // draw mask + if(getOptionsDrawinglayer().IsAntiAliasing()) + { + // with AA, use 8bit AlphaMask to get nice borders + VirtualDevice& rAlpha = aBufferDevice.getAlpha(); + rAlpha.SetLineColor(); + rAlpha.SetFillColor(COL_BLACK); + rAlpha.DrawPolyPolygon(aMask); + + // dump buffer to outdev + aBufferDevice.paint(); + } + else + { + // No AA, use 1bit mask + VirtualDevice& rMask = aBufferDevice.getMask(); + rMask.SetLineColor(); + rMask.SetFillColor(COL_BLACK); + rMask.DrawPolyPolygon(aMask); + + // dump buffer to outdev + aBufferDevice.paint(); + } + } + } + } + } + + // modified color group. Force output to unified color. + void VclProcessor2D::RenderModifiedColorPrimitive2D(const primitive2d::ModifiedColorPrimitive2D& rModifiedCandidate) + { + if(rModifiedCandidate.getChildren().hasElements()) + { + maBColorModifierStack.push(rModifiedCandidate.getColorModifier()); + process(rModifiedCandidate.getChildren()); + maBColorModifierStack.pop(); + } + } + + // unified sub-transparence. Draw to VDev first. + void VclProcessor2D::RenderUnifiedAlphaPrimitive2D(const primitive2d::UnifiedAlphaPrimitive2D& rTransCandidate) + { + static bool bForceToDecomposition(false); + + if(rTransCandidate.getChildren().hasElements()) + { + if(bForceToDecomposition) + { + // use decomposition + process(rTransCandidate.get2DDecomposition(getViewInformation2D())); + } + else + { + if(0.0 == rTransCandidate.getAlpha()) + { + // no transparence used, so just use the content + process(rTransCandidate.getChildren()); + } + else if(rTransCandidate.getAlpha() > 0.0 && rTransCandidate.getAlpha() < 1.0) + { + // alpha is in visible range + basegfx::B2DRange aRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rTransCandidate.getChildren(), getViewInformation2D())); + aRange.transform(maCurrentTransformation); + impBufferDevice aBufferDevice(*mpOutputDevice, aRange, true); + + if(aBufferDevice.isVisible()) + { + // remember last OutDev and set to content + OutputDevice* pLastOutputDevice = mpOutputDevice; + mpOutputDevice = &aBufferDevice.getContent(); + + // paint content to it + process(rTransCandidate.getChildren()); + + // back to old OutDev + mpOutputDevice = pLastOutputDevice; + + // dump buffer to outdev using given alpha + aBufferDevice.paint(rTransCandidate.getAlpha()); + } + } + } + } + } + + // sub-transparence group. Draw to VDev first. + void VclProcessor2D::RenderAlphaPrimitive2D(const primitive2d::AlphaPrimitive2D& rTransCandidate) + { + if(rTransCandidate.getChildren().hasElements()) + { + basegfx::B2DRange aRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rTransCandidate.getChildren(), getViewInformation2D())); + aRange.transform(maCurrentTransformation); + impBufferDevice aBufferDevice(*mpOutputDevice, aRange, true); + + if(aBufferDevice.isVisible()) + { + // remember last OutDev and set to content + OutputDevice* pLastOutputDevice = mpOutputDevice; + mpOutputDevice = &aBufferDevice.getContent(); + + // paint content to it + process(rTransCandidate.getChildren()); + + // set to mask + mpOutputDevice = &aBufferDevice.getAlpha(); + + // when painting alpha masks, reset the color stack + basegfx::BColorModifierStack aLastBColorModifierStack(maBColorModifierStack); + maBColorModifierStack = basegfx::BColorModifierStack(); + + // paint mask to it (always with alpha intensities, evtl. with AA) + process(rTransCandidate.getAlpha()); + + // back to old color stack + maBColorModifierStack = aLastBColorModifierStack; + + // back to old OutDev + mpOutputDevice = pLastOutputDevice; + + // dump buffer to outdev + aBufferDevice.paint(); + } + } + } + + // transform group. + void VclProcessor2D::RenderTransformPrimitive2D(const primitive2d::TransformPrimitive2D& rTransformCandidate) + { + // remember current transformation and ViewInformation + const basegfx::B2DHomMatrix aLastCurrentTransformation(maCurrentTransformation); + const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D()); + + // create new transformations for CurrentTransformation + // and for local ViewInformation2D + maCurrentTransformation = maCurrentTransformation * rTransformCandidate.getTransformation(); + const geometry::ViewInformation2D aViewInformation2D( + getViewInformation2D().getObjectTransformation() * rTransformCandidate.getTransformation(), + getViewInformation2D().getViewTransformation(), + getViewInformation2D().getViewport(), + getViewInformation2D().getVisualizedPage(), + getViewInformation2D().getViewTime(), + getViewInformation2D().getExtendedInformationSequence()); + updateViewInformation(aViewInformation2D); + + // proccess content + process(rTransformCandidate.getChildren()); + + // restore transformations + maCurrentTransformation = aLastCurrentTransformation; + updateViewInformation(aLastViewInformation2D); + } + + // new XDrawPage for ViewInformation2D + void VclProcessor2D::RenderPagePreviewPrimitive2D(const primitive2d::PagePreviewPrimitive2D& rPagePreviewCandidate) + { + // remember current transformation and ViewInformation + const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D()); + + // create new local ViewInformation2D + const geometry::ViewInformation2D aViewInformation2D( + getViewInformation2D().getObjectTransformation(), + getViewInformation2D().getViewTransformation(), + getViewInformation2D().getViewport(), + rPagePreviewCandidate.getXDrawPage(), + getViewInformation2D().getViewTime(), + getViewInformation2D().getExtendedInformationSequence()); + updateViewInformation(aViewInformation2D); + + // proccess decomposed content + process(rPagePreviewCandidate.get2DDecomposition(getViewInformation2D())); + + // restore transformations + updateViewInformation(aLastViewInformation2D); + } + + // marker + void VclProcessor2D::RenderMarkerArrayPrimitive2D(const primitive2d::MarkerArrayPrimitive2D& rMarkArrayCandidate) + { + static bool bCheckCompleteMarkerDecompose(false); + if(bCheckCompleteMarkerDecompose) + { + process(rMarkArrayCandidate.get2DDecomposition(getViewInformation2D())); + return; + } + + // get data + const std::vector< basegfx::B2DPoint >& rPositions = rMarkArrayCandidate.getPositions(); + const sal_uInt32 nCount(rPositions.size()); + + if(nCount && !rMarkArrayCandidate.getMarker().IsEmpty()) + { + // get pixel size + const BitmapEx& rMarker(rMarkArrayCandidate.getMarker()); + const Size aBitmapSize(rMarker.GetSizePixel()); + + if(aBitmapSize.Width() && aBitmapSize.Height()) + { + // get discrete half size + const basegfx::B2DVector aDiscreteHalfSize( + (aBitmapSize.getWidth() - 1.0) * 0.5, + (aBitmapSize.getHeight() - 1.0) * 0.5); + const bool bWasEnabled(mpOutputDevice->IsMapModeEnabled()); + + // do not forget evtl. moved origin in target device MapMode when + // switching it off; it would be missing and lead to wrong positions. + // All his could be done using logic sizes and coordinates, too, but + // we want a 1:1 bitmap rendering here, so it's more safe and faster + // to work with switching off MapMode usage completely. + const Point aOrigin(mpOutputDevice->GetMapMode().GetOrigin()); + + mpOutputDevice->EnableMapMode(false); + + for(std::vector< basegfx::B2DPoint >::const_iterator aIter(rPositions.begin()); aIter != rPositions.end(); aIter++) + { + const basegfx::B2DPoint aDiscreteTopLeft((maCurrentTransformation * (*aIter)) - aDiscreteHalfSize); + const Point aDiscretePoint(basegfx::fround(aDiscreteTopLeft.getX()), basegfx::fround(aDiscreteTopLeft.getY())); + + mpOutputDevice->DrawBitmapEx(aDiscretePoint + aOrigin, rMarker); + } + + mpOutputDevice->EnableMapMode(bWasEnabled); + } + } + } + + // point + void VclProcessor2D::RenderPointArrayPrimitive2D(const primitive2d::PointArrayPrimitive2D& rPointArrayCandidate) + { + const std::vector< basegfx::B2DPoint >& rPositions = rPointArrayCandidate.getPositions(); + const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(rPointArrayCandidate.getRGBColor())); + const Color aVCLColor(aRGBColor); + + for(std::vector< basegfx::B2DPoint >::const_iterator aIter(rPositions.begin()); aIter != rPositions.end(); aIter++) + { + const basegfx::B2DPoint aViewPosition(maCurrentTransformation * (*aIter)); + const Point aPos(basegfx::fround(aViewPosition.getX()), basegfx::fround(aViewPosition.getY())); + + mpOutputDevice->DrawPixel(aPos, aVCLColor); + } + } + + void VclProcessor2D::RenderPolygonStrokePrimitive2D(const primitive2d::PolygonStrokePrimitive2D& rPolygonStrokeCandidate) + { + // #i101491# method restructured to clearly use the DrawPolyLine + // calls starting from a deined line width + const attribute::LineAttribute& rLineAttribute = rPolygonStrokeCandidate.getLineAttribute(); + const double fLineWidth(rLineAttribute.getWidth()); + bool bDone(false); + + if(basegfx::fTools::more(fLineWidth, 0.0)) + { + const basegfx::B2DVector aDiscreteUnit(maCurrentTransformation * basegfx::B2DVector(fLineWidth, 0.0)); + const double fDiscreteLineWidth(aDiscreteUnit.getLength()); + const attribute::StrokeAttribute& rStrokeAttribute = rPolygonStrokeCandidate.getStrokeAttribute(); + const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rLineAttribute.getColor())); + basegfx::B2DPolyPolygon aHairlinePolyPolygon; + + mpOutputDevice->SetLineColor(Color(aHairlineColor)); + mpOutputDevice->SetFillColor(); + + if(0.0 == rStrokeAttribute.getFullDotDashLen()) + { + // no line dashing, just copy + aHairlinePolyPolygon.append(rPolygonStrokeCandidate.getB2DPolygon()); + } + else + { + // else apply LineStyle + basegfx::tools::applyLineDashing(rPolygonStrokeCandidate.getB2DPolygon(), + rStrokeAttribute.getDotDashArray(), + &aHairlinePolyPolygon, 0, rStrokeAttribute.getFullDotDashLen()); + } + + const sal_uInt32 nCount(aHairlinePolyPolygon.count()); + + if(nCount) + { + const bool bAntiAliased(getOptionsDrawinglayer().IsAntiAliasing()); + aHairlinePolyPolygon.transform(maCurrentTransformation); + + for(sal_uInt32 a(0); a < nCount; a++) + { + basegfx::B2DPolygon aCandidate(aHairlinePolyPolygon.getB2DPolygon(a)); + + if(bAntiAliased) + { + if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth, 1.0)) + { + // line in range ]0.0 .. 1.0[ + // paint as simple hairline + mpOutputDevice->DrawPolyLine(aCandidate, 0.0); + bDone = true; + } + else if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth, 2.0)) + { + // line in range [1.0 .. 2.0[ + // paint as 2x2 with dynamic line distance + basegfx::B2DHomMatrix aMat; + const double fDistance(fDiscreteLineWidth - 1.0); + const double fHalfDistance(fDistance * 0.5); + + aMat.set(0, 2, -fHalfDistance); + aMat.set(1, 2, -fHalfDistance); + aCandidate.transform(aMat); + mpOutputDevice->DrawPolyLine(aCandidate, 0.0); + + aMat.set(0, 2, fDistance); + aMat.set(1, 2, 0.0); + aCandidate.transform(aMat); + mpOutputDevice->DrawPolyLine(aCandidate, 0.0); + + aMat.set(0, 2, 0.0); + aMat.set(1, 2, fDistance); + aCandidate.transform(aMat); + mpOutputDevice->DrawPolyLine(aCandidate, 0.0); + + aMat.set(0, 2, -fDistance); + aMat.set(1, 2, 0.0); + aCandidate.transform(aMat); + mpOutputDevice->DrawPolyLine(aCandidate, 0.0); + bDone = true; + } + else if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth, 3.0)) + { + // line in range [2.0 .. 3.0] + // paint as cross in a 3x3 with dynamic line distance + basegfx::B2DHomMatrix aMat; + const double fDistance((fDiscreteLineWidth - 1.0) * 0.5); + + mpOutputDevice->DrawPolyLine(aCandidate, 0.0); + + aMat.set(0, 2, -fDistance); + aMat.set(1, 2, 0.0); + aCandidate.transform(aMat); + mpOutputDevice->DrawPolyLine(aCandidate, 0.0); + + aMat.set(0, 2, fDistance); + aMat.set(1, 2, -fDistance); + aCandidate.transform(aMat); + mpOutputDevice->DrawPolyLine(aCandidate, 0.0); + + aMat.set(0, 2, fDistance); + aMat.set(1, 2, fDistance); + aCandidate.transform(aMat); + mpOutputDevice->DrawPolyLine(aCandidate, 0.0); + + aMat.set(0, 2, -fDistance); + aMat.set(1, 2, fDistance); + aCandidate.transform(aMat); + mpOutputDevice->DrawPolyLine(aCandidate, 0.0); + bDone = true; + } + else + { + // #i101491# line width above 3.0 + } + } + else + { + if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth, 1.5)) + { + // line width below 1.5, draw the basic hairline polygon + mpOutputDevice->DrawPolyLine(aCandidate, 0.0); + bDone = true; + } + else if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth, 2.5)) + { + // line width is in range ]1.5 .. 2.5], use four hairlines + // drawn in a square + basegfx::B2DHomMatrix aMat; + mpOutputDevice->DrawPolyLine(aCandidate, 0.0); + + aMat.set(0, 2, 1.0); + aMat.set(1, 2, 0.0); + aCandidate.transform(aMat); + + mpOutputDevice->DrawPolyLine(aCandidate, 0.0); + + aMat.set(0, 2, 0.0); + aMat.set(1, 2, 1.0); + aCandidate.transform(aMat); + + mpOutputDevice->DrawPolyLine(aCandidate, 0.0); + + aMat.set(0, 2, -1.0); + aMat.set(1, 2, 0.0); + aCandidate.transform(aMat); + + mpOutputDevice->DrawPolyLine(aCandidate, 0.0); + bDone = true; + } + else + { + // #i101491# line width is above 2.5 + } + } + + if(!bDone && rPolygonStrokeCandidate.getB2DPolygon().count() > 1000) + { + // #i101491# If the polygon complexity uses more than a given amount, do + // use OuputDevice::DrawPolyLine directly; this will avoid buffering all + // decompositions in primtives (memory) and fallback to old line painting + // for very complex polygons, too + mpOutputDevice->DrawPolyLine(aCandidate, fDiscreteLineWidth, rLineAttribute.getLineJoin()); + bDone = true; + } + } + } + } + + if(!bDone) + { + // remeber that we enter a PolygonStrokePrimitive2D decomposition, + // used for AA thick line drawing + mnPolygonStrokePrimitive2D++; + + // line width is big enough for standard filled polygon visualisation or zero + process(rPolygonStrokeCandidate.get2DDecomposition(getViewInformation2D())); + + // leave PolygonStrokePrimitive2D + mnPolygonStrokePrimitive2D--; + } + } + + void VclProcessor2D::adaptLineToFillDrawMode() const + { + const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode()); + + if(nOriginalDrawMode & (DRAWMODE_BLACKLINE|DRAWMODE_GRAYLINE|DRAWMODE_GHOSTEDLINE|DRAWMODE_WHITELINE|DRAWMODE_SETTINGSLINE)) + { + sal_uInt32 nAdaptedDrawMode(nOriginalDrawMode); + + if(nOriginalDrawMode & DRAWMODE_BLACKLINE) + { + nAdaptedDrawMode |= DRAWMODE_BLACKFILL; + } + else + { + nAdaptedDrawMode &= ~DRAWMODE_BLACKFILL; + } + + if(nOriginalDrawMode & DRAWMODE_GRAYLINE) + { + nAdaptedDrawMode |= DRAWMODE_GRAYFILL; + } + else + { + nAdaptedDrawMode &= ~DRAWMODE_GRAYFILL; + } + + if(nOriginalDrawMode & DRAWMODE_GHOSTEDLINE) + { + nAdaptedDrawMode |= DRAWMODE_GHOSTEDFILL; + } + else + { + nAdaptedDrawMode &= ~DRAWMODE_GHOSTEDFILL; + } + + if(nOriginalDrawMode & DRAWMODE_WHITELINE) + { + nAdaptedDrawMode |= DRAWMODE_WHITEFILL; + } + else + { + nAdaptedDrawMode &= ~DRAWMODE_WHITEFILL; + } + + if(nOriginalDrawMode & DRAWMODE_SETTINGSLINE) + { + nAdaptedDrawMode |= DRAWMODE_SETTINGSFILL; + } + else + { + nAdaptedDrawMode &= ~DRAWMODE_SETTINGSFILL; + } + + mpOutputDevice->SetDrawMode(nAdaptedDrawMode); + } + } + + void VclProcessor2D::adaptTextToFillDrawMode() const + { + const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode()); + if(nOriginalDrawMode & (DRAWMODE_BLACKTEXT|DRAWMODE_GRAYTEXT|DRAWMODE_GHOSTEDTEXT|DRAWMODE_WHITETEXT|DRAWMODE_SETTINGSTEXT)) + { + sal_uInt32 nAdaptedDrawMode(nOriginalDrawMode); + + if(nOriginalDrawMode & DRAWMODE_BLACKTEXT) + { + nAdaptedDrawMode |= DRAWMODE_BLACKFILL; + } + else + { + nAdaptedDrawMode &= ~DRAWMODE_BLACKFILL; + } + + if(nOriginalDrawMode & DRAWMODE_GRAYTEXT) + { + nAdaptedDrawMode |= DRAWMODE_GRAYFILL; + } + else + { + nAdaptedDrawMode &= ~DRAWMODE_GRAYFILL; + } + + if(nOriginalDrawMode & DRAWMODE_GHOSTEDTEXT) + { + nAdaptedDrawMode |= DRAWMODE_GHOSTEDFILL; + } + else + { + nAdaptedDrawMode &= ~DRAWMODE_GHOSTEDFILL; + } + + if(nOriginalDrawMode & DRAWMODE_WHITETEXT) + { + nAdaptedDrawMode |= DRAWMODE_WHITEFILL; + } + else + { + nAdaptedDrawMode &= ~DRAWMODE_WHITEFILL; + } + + if(nOriginalDrawMode & DRAWMODE_SETTINGSTEXT) + { + nAdaptedDrawMode |= DRAWMODE_SETTINGSFILL; + } + else + { + nAdaptedDrawMode &= ~DRAWMODE_SETTINGSFILL; + } + + mpOutputDevice->SetDrawMode(nAdaptedDrawMode); + } + } + + ////////////////////////////////////////////////////////////////////////////// + // process support + + VclProcessor2D::VclProcessor2D( + const geometry::ViewInformation2D& rViewInformation, + OutputDevice& rOutDev) + : BaseProcessor2D(rViewInformation), + mpOutputDevice(&rOutDev), + maBColorModifierStack(), + maCurrentTransformation(), + maDrawinglayerOpt(), + mnPolygonStrokePrimitive2D(0) + { + // set digit language, derived from SvtCTLOptions to have the correct + // number display for arabic/hindi numerals + const SvtCTLOptions aSvtCTLOptions; + LanguageType eLang(LANGUAGE_SYSTEM); + + if(SvtCTLOptions::NUMERALS_HINDI == aSvtCTLOptions.GetCTLTextNumerals()) + { + eLang = LANGUAGE_ARABIC_SAUDI_ARABIA; + } + else if(SvtCTLOptions::NUMERALS_ARABIC == aSvtCTLOptions.GetCTLTextNumerals()) + { + eLang = LANGUAGE_ENGLISH; + } + else + { + eLang = (LanguageType)Application::GetSettings().GetLanguage(); + } + + rOutDev.SetDigitLanguage(eLang); + } + + VclProcessor2D::~VclProcessor2D() + { + } + } // end of namespace processor2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/processor3d/baseprocessor3d.cxx b/drawinglayer/source/processor3d/baseprocessor3d.cxx new file mode 100644 index 000000000000..7d630f2522be --- /dev/null +++ b/drawinglayer/source/processor3d/baseprocessor3d.cxx @@ -0,0 +1,122 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: baseprocessor3d.cxx,v $ + * + * $Revision: 1.7 $ + * + * last change: $Author: aw $ $Date: 2008-06-24 15:31:09 $ + * + * 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/processor3d/baseprocessor3d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace processor3d + { + void BaseProcessor3D::processBasePrimitive3D(const primitive3d::BasePrimitive3D& /*rCandidate*/) + { + } + + BaseProcessor3D::BaseProcessor3D(const geometry::ViewInformation3D& rViewInformation) + : maViewInformation3D(rViewInformation) + { + } + + BaseProcessor3D::~BaseProcessor3D() + { + } + + void BaseProcessor3D::process(const primitive3d::Primitive3DSequence& rSource) + { + if(rSource.hasElements()) + { + const sal_Int32 nCount(rSource.getLength()); + + for(sal_Int32 a(0L); a < nCount; a++) + { + // get reference + const primitive3d::Primitive3DReference xReference(rSource[a]); + + if(xReference.is()) + { + // try to cast to BasePrimitive3D implementation + const primitive3d::BasePrimitive3D* pBasePrimitive = dynamic_cast< const primitive3d::BasePrimitive3D* >(xReference.get()); + + if(pBasePrimitive) + { + processBasePrimitive3D(*pBasePrimitive); + } + else + { + // unknown implementation, use UNO API call instead and process recursively + const uno::Sequence< beans::PropertyValue >& rViewParameters(getViewInformation3D().getViewInformationSequence()); + process(xReference->getDecomposition(rViewParameters)); + } + } + } + } + } + } // end of namespace processor3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace processor3d + { + CollectingProcessor3D::CollectingProcessor3D(const geometry::ViewInformation3D& rViewInformation) + : BaseProcessor3D(rViewInformation), + maPrimitive3DSequence() + { + } + + CollectingProcessor3D::~CollectingProcessor3D() + { + } + + void CollectingProcessor3D::process(const primitive3d::Primitive3DSequence& rSource) + { + // accept everything + primitive3d::appendPrimitive3DSequenceToPrimitive3DSequence(maPrimitive3DSequence, rSource); + } + } // end of namespace processor3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/processor3d/cutfindprocessor3d.cxx b/drawinglayer/source/processor3d/cutfindprocessor3d.cxx new file mode 100644 index 000000000000..99f5801c60e3 --- /dev/null +++ b/drawinglayer/source/processor3d/cutfindprocessor3d.cxx @@ -0,0 +1,199 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: zbufferprocessor3d.cxx,v $ + * + * $Revision: 1.5 $ + * + * last change: $Author: aw $ $Date: 2008-06-24 15:31:09 $ + * + * 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/processor3d/cutfindprocessor3d.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> +#include <drawinglayer/primitive3d/transformprimitive3d.hxx> +#include <drawinglayer/primitive3d/hatchtextureprimitive3d.hxx> +#include <drawinglayer/primitive3d/hittestprimitive3d.hxx> +#include <drawinglayer/primitive3d/polypolygonprimitive3d.hxx> +#include <basegfx/polygon/b3dpolygon.hxx> +#include <basegfx/polygon/b3dpolygontools.hxx> +#include <basegfx/polygon/b3dpolypolygontools.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace processor3d + { + CutFindProcessor::CutFindProcessor(const geometry::ViewInformation3D& rViewInformation, + const basegfx::B3DPoint& rFront, + const basegfx::B3DPoint& rBack, + bool bAnyHit) + : BaseProcessor3D(rViewInformation), + maFront(rFront), + maBack(rBack), + maResult(), + maCombinedTransform(), + mbAnyHit(bAnyHit) + { + } + + void CutFindProcessor::processBasePrimitive3D(const primitive3d::BasePrimitive3D& rCandidate) + { + if(getAnyHit() && maResult.size()) + { + // stop processing as soon as a hit was recognized + return; + } + + // it is a BasePrimitive3D implementation, use getPrimitiveID() call for switch + switch(rCandidate.getPrimitiveID()) + { + case PRIMITIVE3D_ID_TRANSFORMPRIMITIVE3D : + { + // transform group. + const primitive3d::TransformPrimitive3D& rPrimitive = static_cast< const primitive3d::TransformPrimitive3D& >(rCandidate); + + // remember old and transform front, back to object coordinates + const basegfx::B3DPoint aLastFront(maFront); + const basegfx::B3DPoint aLastBack(maBack); + basegfx::B3DHomMatrix aInverseTrans(rPrimitive.getTransformation()); + aInverseTrans.invert(); + maFront *= aInverseTrans; + maBack *= aInverseTrans; + + // remember current and create new transformation; add new object transform from right side + const geometry::ViewInformation3D aLastViewInformation3D(getViewInformation3D()); + const geometry::ViewInformation3D aNewViewInformation3D( + aLastViewInformation3D.getObjectTransformation() * rPrimitive.getTransformation(), + aLastViewInformation3D.getOrientation(), + aLastViewInformation3D.getProjection(), + aLastViewInformation3D.getDeviceToView(), + aLastViewInformation3D.getViewTime(), + aLastViewInformation3D.getExtendedInformationSequence()); + updateViewInformation(aNewViewInformation3D); + + // #i102956# remember needed back-transform for found cuts (combine from right side) + const basegfx::B3DHomMatrix aLastCombinedTransform(maCombinedTransform); + maCombinedTransform = maCombinedTransform * rPrimitive.getTransformation(); + + // let break down + process(rPrimitive.getChildren()); + + // restore transformations and front, back + maCombinedTransform = aLastCombinedTransform; + updateViewInformation(aLastViewInformation3D); + maFront = aLastFront; + maBack = aLastBack; + break; + } + case PRIMITIVE3D_ID_POLYGONHAIRLINEPRIMITIVE3D : + { + // PolygonHairlinePrimitive3D, not used for hit test with planes, ignore. This + // means that also thick line expansion will not be hit-tested as + // PolyPolygonMaterialPrimitive3D + break; + } + case PRIMITIVE3D_ID_HATCHTEXTUREPRIMITIVE3D : + { + // #i97321# + // For HatchTexturePrimitive3D, do not use the decomposition since it will produce + // clipped hatch lines in 3D. It can be used when the hatch also has a filling, but for + // simplicity, just use the children which are the PolyPolygonMaterialPrimitive3D + // which define the hatched areas anyways; for HitTest this is more than adequate + const primitive3d::HatchTexturePrimitive3D& rPrimitive = static_cast< const primitive3d::HatchTexturePrimitive3D& >(rCandidate); + process(rPrimitive.getChildren()); + break; + } + case PRIMITIVE3D_ID_HITTESTPRIMITIVE3D : + { + // HitTestPrimitive3D, force usage due to we are doing a hit test and this + // primitive only gets generated on 3d objects without fill, exactly for this + // purpose + const primitive3d::HitTestPrimitive3D& rPrimitive = static_cast< const primitive3d::HitTestPrimitive3D& >(rCandidate); + process(rPrimitive.getChildren()); + break; + } + case PRIMITIVE3D_ID_POLYPOLYGONMATERIALPRIMITIVE3D : + { + // PolyPolygonMaterialPrimitive3D + const primitive3d::PolyPolygonMaterialPrimitive3D& rPrimitive = static_cast< const primitive3d::PolyPolygonMaterialPrimitive3D& >(rCandidate); + + if(!maFront.equal(maBack)) + { + const basegfx::B3DPolyPolygon& rPolyPolygon = rPrimitive.getB3DPolyPolygon(); + const sal_uInt32 nPolyCount(rPolyPolygon.count()); + + if(nPolyCount) + { + const basegfx::B3DPolygon aPolygon(rPolyPolygon.getB3DPolygon(0)); + const sal_uInt32 nPointCount(aPolygon.count()); + + if(nPointCount > 2) + { + const basegfx::B3DVector aPlaneNormal(aPolygon.getNormal()); + + if(!aPlaneNormal.equalZero()) + { + const basegfx::B3DPoint aPointOnPlane(aPolygon.getB3DPoint(0)); + double fCut(0.0); + + if(basegfx::tools::getCutBetweenLineAndPlane(aPlaneNormal, aPointOnPlane, maFront, maBack, fCut)) + { + const basegfx::B3DPoint aCutPoint(basegfx::interpolate(maFront, maBack, fCut)); + + if(basegfx::tools::isInside(rPolyPolygon, aCutPoint, false)) + { + // #i102956# add result. Do not forget to do this in the coordinate + // system the processor get started with, so use the collected + // combined transformation from processed TransformPrimitive3D's + maResult.push_back(maCombinedTransform * aCutPoint); + } + } + } + } + } + } + + break; + } + default : + { + // process recursively + process(rCandidate.get3DDecomposition(getViewInformation3D())); + break; + } + } + } + } // end of namespace processor3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/processor3d/defaultprocessor3d.cxx b/drawinglayer/source/processor3d/defaultprocessor3d.cxx new file mode 100644 index 000000000000..d9194ca4b5eb --- /dev/null +++ b/drawinglayer/source/processor3d/defaultprocessor3d.cxx @@ -0,0 +1,578 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: defaultprocessor3d.cxx,v $ + * + * $Revision: 1.13 $ + * + * last change: $Author: aw $ $Date: 2008-06-24 15:31:09 $ + * + * 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/processor3d/defaultprocessor3d.hxx> +#include <drawinglayer/primitive3d/textureprimitive3d.hxx> +#include <drawinglayer/texture/texture.hxx> +#include <drawinglayer/texture/texture3d.hxx> +#include <drawinglayer/primitive3d/hatchtextureprimitive3d.hxx> +#include <drawinglayer/primitive3d/modifiedcolorprimitive3d.hxx> +#include <drawinglayer/primitive3d/polygonprimitive3d.hxx> +#include <basegfx/polygon/b3dpolygontools.hxx> +#include <drawinglayer/attribute/materialattribute3d.hxx> +#include <drawinglayer/primitive3d/polypolygonprimitive3d.hxx> +#include <basegfx/polygon/b3dpolypolygontools.hxx> +#include <com/sun/star/drawing/ShadeMode.hpp> +#include <drawinglayer/attribute/sdrattribute3d.hxx> +#include <drawinglayer/primitive3d/transformprimitive3d.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace processor3d + { + void DefaultProcessor3D::impRenderGradientTexturePrimitive3D(const primitive3d::GradientTexturePrimitive3D& rPrimitive, bool bTransparence) + { + const primitive3d::Primitive3DSequence& rSubSequence = rPrimitive.getChildren(); + + if(rSubSequence.hasElements()) + { + // rescue values + const bool bOldModulate(getModulate()); mbModulate = rPrimitive.getModulate(); + const bool bOldFilter(getFilter()); mbFilter = rPrimitive.getFilter(); + const bool bOldSimpleTextureActive(mbSimpleTextureActive); + texture::GeoTexSvx* pOldTex = (bTransparence) ? mpTransparenceGeoTexSvx : mpGeoTexSvx; + + // create texture + const attribute::FillGradientAttribute& rFillGradient = rPrimitive.getGradient(); + const basegfx::B2DRange aOutlineRange(0.0, 0.0, rPrimitive.getTextureSize().getX(), rPrimitive.getTextureSize().getY()); + const attribute::GradientStyle aGradientStyle(rFillGradient.getStyle()); + sal_uInt32 nSteps(rFillGradient.getSteps()); + const basegfx::BColor aStart(rFillGradient.getStartColor()); + const basegfx::BColor aEnd(rFillGradient.getEndColor()); + const sal_uInt32 nMaxSteps(sal_uInt32((aStart.getMaximumDistance(aEnd) * 127.5) + 0.5)); + texture::GeoTexSvx* pNewTex = 0L; + + if(nMaxSteps) + { + // there IS a color distance + if(nSteps == 0L) + { + nSteps = nMaxSteps; + } + + if(nSteps < 2L) + { + nSteps = 2L; + } + + if(nSteps > nMaxSteps) + { + nSteps = nMaxSteps; + } + + switch(aGradientStyle) + { + case attribute::GRADIENTSTYLE_LINEAR: + { + pNewTex = new texture::GeoTexSvxGradientLinear(aOutlineRange, aStart, aEnd, nSteps, rFillGradient.getBorder(), -rFillGradient.getAngle()); + break; + } + case attribute::GRADIENTSTYLE_AXIAL: + { + pNewTex = new texture::GeoTexSvxGradientAxial(aOutlineRange, aStart, aEnd, nSteps, rFillGradient.getBorder(), -rFillGradient.getAngle()); + break; + } + case attribute::GRADIENTSTYLE_RADIAL: + { + pNewTex = new texture::GeoTexSvxGradientRadial(aOutlineRange, aStart, aEnd, nSteps, rFillGradient.getBorder(), rFillGradient.getOffsetX(), rFillGradient.getOffsetY()); + break; + } + case attribute::GRADIENTSTYLE_ELLIPTICAL: + { + pNewTex = new texture::GeoTexSvxGradientElliptical(aOutlineRange, aStart, aEnd, nSteps, rFillGradient.getBorder(), rFillGradient.getOffsetX(), rFillGradient.getOffsetY(), -rFillGradient.getAngle()); + break; + } + case attribute::GRADIENTSTYLE_SQUARE: + { + pNewTex = new texture::GeoTexSvxGradientSquare(aOutlineRange, aStart, aEnd, nSteps, rFillGradient.getBorder(), rFillGradient.getOffsetX(), rFillGradient.getOffsetY(), -rFillGradient.getAngle()); + break; + } + case attribute::GRADIENTSTYLE_RECT: + { + pNewTex = new texture::GeoTexSvxGradientRect(aOutlineRange, aStart, aEnd, nSteps, rFillGradient.getBorder(), rFillGradient.getOffsetX(), rFillGradient.getOffsetY(), -rFillGradient.getAngle()); + break; + } + } + + mbSimpleTextureActive = false; + } + else + { + // no color distance -> same color, use simple texture + pNewTex = new texture::GeoTexSvxMono(aStart, 1.0 - aStart.luminance()); + mbSimpleTextureActive = true; + } + + // set created texture + if(bTransparence) + { + mpTransparenceGeoTexSvx = pNewTex; + } + else + { + mpGeoTexSvx = pNewTex; + } + + // process sub-list + process(rSubSequence); + + // delete texture + delete pNewTex; + + // restore values + mbModulate = bOldModulate; + mbFilter = bOldFilter; + mbSimpleTextureActive = bOldSimpleTextureActive; + + if(bTransparence) + { + mpTransparenceGeoTexSvx = pOldTex; + } + else + { + mpGeoTexSvx = pOldTex; + } + } + } + + void DefaultProcessor3D::impRenderHatchTexturePrimitive3D(const primitive3d::HatchTexturePrimitive3D& rPrimitive) + { + const primitive3d::Primitive3DSequence& rSubSequence = rPrimitive.getChildren(); + + if(rSubSequence.hasElements()) + { + // rescue values + const bool bOldModulate(getModulate()); mbModulate = rPrimitive.getModulate(); + const bool bOldFilter(getFilter()); mbFilter = rPrimitive.getFilter(); + texture::GeoTexSvx* pOldTex = mpGeoTexSvx; + + // calculate logic pixel size in object coordinates. Create transformation view + // to object by inverting ObjectToView + basegfx::B3DHomMatrix aInvObjectToView(getViewInformation3D().getObjectToView()); + aInvObjectToView.invert(); + + // back-project discrete coordinates to object coordinates and extract + // maximum distance + const basegfx::B3DPoint aZero(aInvObjectToView * basegfx::B3DPoint(0.0, 0.0, 0.0)); + const basegfx::B3DPoint aOne(aInvObjectToView * basegfx::B3DPoint(1.0, 1.0, 1.0)); + const basegfx::B3DVector aLogicPixel(aOne - aZero); + double fLogicPixelSizeWorld(::std::max(::std::max(fabs(aLogicPixel.getX()), fabs(aLogicPixel.getY())), fabs(aLogicPixel.getZ()))); + + // calculate logic pixel size in texture coordinates + const double fLogicTexSizeX(fLogicPixelSizeWorld / rPrimitive.getTextureSize().getX()); + const double fLogicTexSizeY(fLogicPixelSizeWorld / rPrimitive.getTextureSize().getY()); + const double fLogicTexSize(fLogicTexSizeX > fLogicTexSizeY ? fLogicTexSizeX : fLogicTexSizeY); + + // create texture and set + texture::GeoTexSvxMultiHatch* pNewTex = new texture::GeoTexSvxMultiHatch(rPrimitive, fLogicTexSize); + mpGeoTexSvx = pNewTex; + + // process sub-list + process(rSubSequence); + + // delete texture + delete mpGeoTexSvx; + + // restore values + mbModulate = bOldModulate; + mbFilter = bOldFilter; + mpGeoTexSvx = pOldTex; + } + } + + void DefaultProcessor3D::impRenderBitmapTexturePrimitive3D(const primitive3d::BitmapTexturePrimitive3D& rPrimitive) + { + const primitive3d::Primitive3DSequence& rSubSequence = rPrimitive.getChildren(); + + if(rSubSequence.hasElements()) + { + // rescue values + const bool bOldModulate(getModulate()); mbModulate = rPrimitive.getModulate(); + const bool bOldFilter(getFilter()); mbFilter = rPrimitive.getFilter(); + texture::GeoTexSvx* pOldTex = mpGeoTexSvx; + + // create texture + const attribute::FillBitmapAttribute& rFillBitmapAttribute = rPrimitive.getBitmap(); + + if(rFillBitmapAttribute.getTiling()) + { + mpGeoTexSvx = new texture::GeoTexSvxBitmapTiled( + rFillBitmapAttribute.getBitmap(), + rFillBitmapAttribute.getTopLeft() * rPrimitive.getTextureSize(), + rFillBitmapAttribute.getSize() * rPrimitive.getTextureSize()); + } + else + { + mpGeoTexSvx = new texture::GeoTexSvxBitmap( + rFillBitmapAttribute.getBitmap(), + rFillBitmapAttribute.getTopLeft() * rPrimitive.getTextureSize(), + rFillBitmapAttribute.getSize() * rPrimitive.getTextureSize()); + } + + // process sub-list + process(rSubSequence); + + // delete texture + delete mpGeoTexSvx; + + // restore values + mbModulate = bOldModulate; + mbFilter = bOldFilter; + mpGeoTexSvx = pOldTex; + } + } + + void DefaultProcessor3D::impRenderModifiedColorPrimitive3D(const primitive3d::ModifiedColorPrimitive3D& rModifiedCandidate) + { + const primitive3d::Primitive3DSequence& rSubSequence = rModifiedCandidate.getChildren(); + + if(rSubSequence.hasElements()) + { + // put modifier on stack + maBColorModifierStack.push(rModifiedCandidate.getColorModifier()); + + // process sub-list + process(rModifiedCandidate.getChildren()); + + // remove modifier from stack + maBColorModifierStack.pop(); + } + } + + void DefaultProcessor3D::impRenderPolygonHairlinePrimitive3D(const primitive3d::PolygonHairlinePrimitive3D& rPrimitive) + { + basegfx::B3DPolygon aHairline(rPrimitive.getB3DPolygon()); + + if(aHairline.count()) + { + // hairlines need no extra data, clear it + aHairline.clearTextureCoordinates(); + aHairline.clearNormals(); + aHairline.clearBColors(); + + // transform to device coordinates (-1.0 .. 1.0) and check for visibility + aHairline.transform(getViewInformation3D().getObjectToView()); + const basegfx::B3DRange a3DRange(basegfx::tools::getRange(aHairline)); + const basegfx::B2DRange a2DRange(a3DRange.getMinX(), a3DRange.getMinY(), a3DRange.getMaxX(), a3DRange.getMaxY()); + + if(a2DRange.overlaps(maRasterRange)) + { + const attribute::MaterialAttribute3D aMaterial(maBColorModifierStack.getModifiedColor(rPrimitive.getBColor())); + + rasterconvertB3DPolygon(aMaterial, aHairline); + } + } + } + + void DefaultProcessor3D::impRenderPolyPolygonMaterialPrimitive3D(const primitive3d::PolyPolygonMaterialPrimitive3D& rPrimitive) + { + basegfx::B3DPolyPolygon aFill(rPrimitive.getB3DPolyPolygon()); + basegfx::BColor aObjectColor(rPrimitive.getMaterial().getColor()); + bool bPaintIt(aFill.count()); + + // #i98295# get ShadeMode. Correct early when only flat is possible due to missing normals + const ::com::sun::star::drawing::ShadeMode aShadeMode( + aFill.areNormalsUsed() ? + getSdrSceneAttribute().getShadeMode() : ::com::sun::star::drawing::ShadeMode_FLAT); + + if(bPaintIt) + { + // get rid of texture coordinates if there is no texture + if(aFill.areTextureCoordinatesUsed() && !getGeoTexSvx() && !getTransparenceGeoTexSvx()) + { + aFill.clearTextureCoordinates(); + } + + // #i98295# get rid of normals and color early when not needed + if(::com::sun::star::drawing::ShadeMode_FLAT == aShadeMode) + { + aFill.clearNormals(); + aFill.clearBColors(); + } + + // transform to device coordinates (-1.0 .. 1.0) and check for visibility + aFill.transform(getViewInformation3D().getObjectToView()); + const basegfx::B3DRange a3DRange(basegfx::tools::getRange(aFill)); + const basegfx::B2DRange a2DRange(a3DRange.getMinX(), a3DRange.getMinY(), a3DRange.getMaxX(), a3DRange.getMaxY()); + + bPaintIt = a2DRange.overlaps(maRasterRange); + } + + // check if it shall be painted regarding hiding of normals (backface culling) + if(bPaintIt && !rPrimitive.getDoubleSided()) + { + // get plane normal of polygon in view coordinates (with ZBuffer values), + // left-handed coordinate system + const basegfx::B3DVector aPlaneNormal(aFill.getB3DPolygon(0L).getNormal()); + + if(aPlaneNormal.getZ() > 0.0) + { + bPaintIt = false; + } + } + + if(bPaintIt) + { + // prepare ObjectToEye in NormalTransform + basegfx::B3DHomMatrix aNormalTransform(getViewInformation3D().getOrientation() * getViewInformation3D().getObjectTransformation()); + + if(getSdrSceneAttribute().getTwoSidedLighting()) + { + // get plane normal of polygon in view coordinates (with ZBuffer values), + // left-handed coordinate system + const basegfx::B3DVector aPlaneNormal(aFill.getB3DPolygon(0L).getNormal()); + + if(aPlaneNormal.getZ() > 0.0) + { + // mirror normals + aNormalTransform.scale(-1.0, -1.0, -1.0); + } + } + + switch(aShadeMode) + { + case ::com::sun::star::drawing::ShadeMode_PHONG: + { + // phong shading. Transform normals to eye coor + aFill.transformNormals(aNormalTransform); + break; + } + case ::com::sun::star::drawing::ShadeMode_SMOOTH: + { + // gouraud shading. Transform normals to eye coor + aFill.transformNormals(aNormalTransform); + + // prepare color model parameters, evtl. use blend color + const basegfx::BColor aColor(getModulate() ? basegfx::BColor(1.0, 1.0, 1.0) : rPrimitive.getMaterial().getColor()); + const basegfx::BColor& rSpecular(rPrimitive.getMaterial().getSpecular()); + const basegfx::BColor& rEmission(rPrimitive.getMaterial().getEmission()); + const sal_uInt16 nSpecularIntensity(rPrimitive.getMaterial().getSpecularIntensity()); + + // solve color model for each normal vector, set colors at points. Clear normals. + for(sal_uInt32 a(0L); a < aFill.count(); a++) + { + basegfx::B3DPolygon aPartFill(aFill.getB3DPolygon(a)); + + for(sal_uInt32 b(0L); b < aPartFill.count(); b++) + { + // solve color model. Transform normal to eye coor + const basegfx::B3DVector aNormal(aPartFill.getNormal(b)); + const basegfx::BColor aSolvedColor(getSdrLightingAttribute().solveColorModel(aNormal, aColor, rSpecular, rEmission, nSpecularIntensity)); + aPartFill.setBColor(b, aSolvedColor); + } + + // clear normals on this part polygon and write it back + aPartFill.clearNormals(); + aFill.setB3DPolygon(a, aPartFill); + } + break; + } + case ::com::sun::star::drawing::ShadeMode_FLAT: + { + // flat shading. Get plane vector in eye coordinates + const basegfx::B3DVector aPlaneEyeNormal(aNormalTransform * rPrimitive.getB3DPolyPolygon().getB3DPolygon(0L).getNormal()); + + // prepare color model parameters, evtl. use blend color + const basegfx::BColor aColor(getModulate() ? basegfx::BColor(1.0, 1.0, 1.0) : rPrimitive.getMaterial().getColor()); + const basegfx::BColor& rSpecular(rPrimitive.getMaterial().getSpecular()); + const basegfx::BColor& rEmission(rPrimitive.getMaterial().getEmission()); + const sal_uInt16 nSpecularIntensity(rPrimitive.getMaterial().getSpecularIntensity()); + + // solve color model for plane vector and use that color for whole plane + aObjectColor = getSdrLightingAttribute().solveColorModel(aPlaneEyeNormal, aColor, rSpecular, rEmission, nSpecularIntensity); + break; + } + default: // case ::com::sun::star::drawing::ShadeMode_DRAFT: + { + // draft, just use object color which is already set. Delete all other infos + aFill.clearNormals(); + aFill.clearBColors(); + break; + } + } + + // draw it to ZBuffer + const attribute::MaterialAttribute3D aMaterial( + maBColorModifierStack.getModifiedColor(aObjectColor), + rPrimitive.getMaterial().getSpecular(), + rPrimitive.getMaterial().getEmission(), + rPrimitive.getMaterial().getSpecularIntensity()); + + rasterconvertB3DPolyPolygon(aMaterial, aFill); + } + } + + void DefaultProcessor3D::impRenderTransformPrimitive3D(const primitive3d::TransformPrimitive3D& rTransformCandidate) + { + // transform group. Remember current transformations + const geometry::ViewInformation3D aLastViewInformation3D(getViewInformation3D()); + + // create new transformation; add new object transform from right side + const geometry::ViewInformation3D aNewViewInformation3D( + aLastViewInformation3D.getObjectTransformation() * rTransformCandidate.getTransformation(), + aLastViewInformation3D.getOrientation(), + aLastViewInformation3D.getProjection(), + aLastViewInformation3D.getDeviceToView(), + aLastViewInformation3D.getViewTime(), + aLastViewInformation3D.getExtendedInformationSequence()); + updateViewInformation(aNewViewInformation3D); + + // let break down recursively + process(rTransformCandidate.getChildren()); + + // restore transformations + updateViewInformation(aLastViewInformation3D); + } + + void DefaultProcessor3D::processBasePrimitive3D(const primitive3d::BasePrimitive3D& rBasePrimitive) + { + // it is a BasePrimitive3D implementation, use getPrimitiveID() call for switch + switch(rBasePrimitive.getPrimitiveID()) + { + case PRIMITIVE3D_ID_GRADIENTTEXTUREPRIMITIVE3D : + { + // GradientTexturePrimitive3D + const primitive3d::GradientTexturePrimitive3D& rPrimitive = static_cast< const primitive3d::GradientTexturePrimitive3D& >(rBasePrimitive); + impRenderGradientTexturePrimitive3D(rPrimitive, false); + break; + } + case PRIMITIVE3D_ID_HATCHTEXTUREPRIMITIVE3D : + { + // HatchTexturePrimitive3D + static bool bDoHatchDecomposition(false); + + if(bDoHatchDecomposition) + { + // let break down + process(rBasePrimitive.get3DDecomposition(getViewInformation3D())); + } + else + { + // hatchTexturePrimitive3D + const primitive3d::HatchTexturePrimitive3D& rPrimitive = static_cast< const primitive3d::HatchTexturePrimitive3D& >(rBasePrimitive); + impRenderHatchTexturePrimitive3D(rPrimitive); + } + break; + } + case PRIMITIVE3D_ID_BITMAPTEXTUREPRIMITIVE3D : + { + // BitmapTexturePrimitive3D + const primitive3d::BitmapTexturePrimitive3D& rPrimitive = static_cast< const primitive3d::BitmapTexturePrimitive3D& >(rBasePrimitive); + impRenderBitmapTexturePrimitive3D(rPrimitive); + break; + } + case PRIMITIVE3D_ID_ALPHATEXTUREPRIMITIVE3D : + { + // AlphaTexturePrimitive3D + const primitive3d::AlphaTexturePrimitive3D& rPrimitive = static_cast< const primitive3d::AlphaTexturePrimitive3D& >(rBasePrimitive); + impRenderGradientTexturePrimitive3D(rPrimitive, true); + break; + } + case PRIMITIVE3D_ID_MODIFIEDCOLORPRIMITIVE3D : + { + // ModifiedColorPrimitive3D + // Force output to unified color. + const primitive3d::ModifiedColorPrimitive3D& rPrimitive = static_cast< const primitive3d::ModifiedColorPrimitive3D& >(rBasePrimitive); + impRenderModifiedColorPrimitive3D(rPrimitive); + break; + } + case PRIMITIVE3D_ID_POLYGONHAIRLINEPRIMITIVE3D : + { + // directdraw of PolygonHairlinePrimitive3D + const primitive3d::PolygonHairlinePrimitive3D& rPrimitive = static_cast< const primitive3d::PolygonHairlinePrimitive3D& >(rBasePrimitive); + impRenderPolygonHairlinePrimitive3D(rPrimitive); + break; + } + case PRIMITIVE3D_ID_POLYPOLYGONMATERIALPRIMITIVE3D : + { + // directdraw of PolyPolygonMaterialPrimitive3D + const primitive3d::PolyPolygonMaterialPrimitive3D& rPrimitive = static_cast< const primitive3d::PolyPolygonMaterialPrimitive3D& >(rBasePrimitive); + impRenderPolyPolygonMaterialPrimitive3D(rPrimitive); + break; + } + case PRIMITIVE3D_ID_TRANSFORMPRIMITIVE3D : + { + // transform group (TransformPrimitive3D) + impRenderTransformPrimitive3D(static_cast< const primitive3d::TransformPrimitive3D& >(rBasePrimitive)); + break; + } + default: + { + // process recursively + process(rBasePrimitive.get3DDecomposition(getViewInformation3D())); + break; + } + } + } + + DefaultProcessor3D::DefaultProcessor3D( + const geometry::ViewInformation3D& rViewInformation, + const attribute::SdrSceneAttribute& rSdrSceneAttribute, + const attribute::SdrLightingAttribute& rSdrLightingAttribute) + : BaseProcessor3D(rViewInformation), + mrSdrSceneAttribute(rSdrSceneAttribute), + mrSdrLightingAttribute(rSdrLightingAttribute), + maRasterRange(), + maBColorModifierStack(), + mpGeoTexSvx(0), + mpTransparenceGeoTexSvx(0), + mbModulate(false), + mbFilter(false), + mbSimpleTextureActive(false) + { + // a derivation has to set maRasterRange which is used in the basic render methods. + // Setting to default here ([0.0 .. 1.0] in X,Y) to avoid problems + maRasterRange.expand(basegfx::B2DTuple(0.0, 0.0)); + maRasterRange.expand(basegfx::B2DTuple(1.0, 1.0)); + } + + DefaultProcessor3D::~DefaultProcessor3D() + { + } + } // end of namespace processor3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/processor3d/geometry2dextractor.cxx b/drawinglayer/source/processor3d/geometry2dextractor.cxx new file mode 100644 index 000000000000..8c19a4a2e3b8 --- /dev/null +++ b/drawinglayer/source/processor3d/geometry2dextractor.cxx @@ -0,0 +1,178 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: geometry2dextractor.cxx,v $ + * + * $Revision: 1.6 $ + * + * last change: $Author: aw $ $Date: 2008-06-24 15:31:09 $ + * + * 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/processor3d/geometry2dextractor.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> +#include <drawinglayer/primitive3d/transformprimitive3d.hxx> +#include <drawinglayer/primitive3d/modifiedcolorprimitive3d.hxx> +#include <drawinglayer/primitive3d/polygonprimitive3d.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <drawinglayer/primitive2d/polygonprimitive2d.hxx> +#include <drawinglayer/primitive3d/polypolygonprimitive3d.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> +#include <drawinglayer/primitive3d/textureprimitive3d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace processor3d + { + // as tooling, the process() implementation takes over API handling and calls this + // virtual render method when the primitive implementation is BasePrimitive3D-based. + void Geometry2DExtractingProcessor::processBasePrimitive3D(const primitive3d::BasePrimitive3D& rCandidate) + { + // it is a BasePrimitive3D implementation, use getPrimitiveID() call for switch + switch(rCandidate.getPrimitiveID()) + { + case PRIMITIVE3D_ID_TRANSFORMPRIMITIVE3D : + { + // transform group. Remember current transformations + const primitive3d::TransformPrimitive3D& rPrimitive = static_cast< const primitive3d::TransformPrimitive3D& >(rCandidate); + const geometry::ViewInformation3D aLastViewInformation3D(getViewInformation3D()); + + // create new transformation; add new object transform from right side + const geometry::ViewInformation3D aNewViewInformation3D( + aLastViewInformation3D.getObjectTransformation() * rPrimitive.getTransformation(), + aLastViewInformation3D.getOrientation(), + aLastViewInformation3D.getProjection(), + aLastViewInformation3D.getDeviceToView(), + aLastViewInformation3D.getViewTime(), + aLastViewInformation3D.getExtendedInformationSequence()); + updateViewInformation(aNewViewInformation3D); + + // let break down recursively + process(rPrimitive.getChildren()); + + // restore transformations + updateViewInformation(aLastViewInformation3D); + break; + } + case PRIMITIVE3D_ID_MODIFIEDCOLORPRIMITIVE3D : + { + // ModifiedColorPrimitive3D; push, process and pop + const primitive3d::ModifiedColorPrimitive3D& rModifiedCandidate = static_cast< const primitive3d::ModifiedColorPrimitive3D& >(rCandidate); + const primitive3d::Primitive3DSequence& rSubSequence = rModifiedCandidate.getChildren(); + + if(rSubSequence.hasElements()) + { + maBColorModifierStack.push(rModifiedCandidate.getColorModifier()); + process(rModifiedCandidate.getChildren()); + maBColorModifierStack.pop(); + } + break; + } + case PRIMITIVE3D_ID_POLYGONHAIRLINEPRIMITIVE3D : + { + // PolygonHairlinePrimitive3D + const primitive3d::PolygonHairlinePrimitive3D& rPrimitive = static_cast< const primitive3d::PolygonHairlinePrimitive3D& >(rCandidate); + basegfx::B2DPolygon a2DHairline(basegfx::tools::createB2DPolygonFromB3DPolygon(rPrimitive.getB3DPolygon(), getViewInformation3D().getObjectToView())); + + if(a2DHairline.count()) + { + a2DHairline.transform(getObjectTransformation()); + const basegfx::BColor aModifiedColor(maBColorModifierStack.getModifiedColor(rPrimitive.getBColor())); + const primitive2d::Primitive2DReference xRef(new primitive2d::PolygonHairlinePrimitive2D(a2DHairline, aModifiedColor)); + primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(maPrimitive2DSequence, xRef); + } + break; + } + case PRIMITIVE3D_ID_POLYPOLYGONMATERIALPRIMITIVE3D : + { + // PolyPolygonMaterialPrimitive3D + const primitive3d::PolyPolygonMaterialPrimitive3D& rPrimitive = static_cast< const primitive3d::PolyPolygonMaterialPrimitive3D& >(rCandidate); + basegfx::B2DPolyPolygon a2DFill(basegfx::tools::createB2DPolyPolygonFromB3DPolyPolygon(rPrimitive.getB3DPolyPolygon(), getViewInformation3D().getObjectToView())); + + if(a2DFill.count()) + { + a2DFill.transform(getObjectTransformation()); + const basegfx::BColor aModifiedColor(maBColorModifierStack.getModifiedColor(rPrimitive.getMaterial().getColor())); + const primitive2d::Primitive2DReference xRef(new primitive2d::PolyPolygonColorPrimitive2D(a2DFill, aModifiedColor)); + primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(maPrimitive2DSequence, xRef); + } + break; + } + case PRIMITIVE3D_ID_GRADIENTTEXTUREPRIMITIVE3D : + case PRIMITIVE3D_ID_HATCHTEXTUREPRIMITIVE3D : + case PRIMITIVE3D_ID_BITMAPTEXTUREPRIMITIVE3D : + case PRIMITIVE3D_ID_ALPHATEXTUREPRIMITIVE3D : + case PRIMITIVE3D_ID_UNIFIEDALPHATEXTUREPRIMITIVE3D : + { + // TexturePrimitive3D: Process children, do not try to decompose + const primitive3d::TexturePrimitive3D& rTexturePrimitive = static_cast< const primitive3d::TexturePrimitive3D& >(rCandidate); + const primitive3d::Primitive3DSequence aChildren(rTexturePrimitive.getChildren()); + + if(aChildren.hasElements()) + { + process(aChildren); + } + break; + } + case PRIMITIVE3D_ID_SHADOWPRIMITIVE3D : + { + // accept but ignore labels and shadow; these should be extracted seperately + break; + } + default : + { + // process recursively + process(rCandidate.get3DDecomposition(getViewInformation3D())); + break; + } + } + } + + Geometry2DExtractingProcessor::Geometry2DExtractingProcessor( + const geometry::ViewInformation3D& rViewInformation, + const basegfx::B2DHomMatrix& rObjectTransformation) + : BaseProcessor3D(rViewInformation), + maPrimitive2DSequence(), + maObjectTransformation(rObjectTransformation), + maBColorModifierStack() + { + } + } // end of namespace processor3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/processor3d/makefile.mk b/drawinglayer/source/processor3d/makefile.mk new file mode 100644 index 000000000000..2ae2ae52f2f2 --- /dev/null +++ b/drawinglayer/source/processor3d/makefile.mk @@ -0,0 +1,58 @@ +#************************************************************************* +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.5 $ +# +# last change: $Author: aw $ $Date: 2008-06-24 15:31:09 $ +# +# 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 +# +#************************************************************************* + +PRJ=..$/.. +PRJNAME=drawinglayer +TARGET=processor3d +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ---------------------------------- + +.INCLUDE : settings.mk + +# --- Files ------------------------------------- + +SLOFILES= \ + $(SLO)$/baseprocessor3d.obj \ + $(SLO)$/cutfindprocessor3d.obj \ + $(SLO)$/defaultprocessor3d.obj \ + $(SLO)$/shadow3dextractor.obj \ + $(SLO)$/geometry2dextractor.obj \ + $(SLO)$/zbufferprocessor3d.obj + + +# --- Targets ---------------------------------- + +.INCLUDE : target.mk diff --git a/drawinglayer/source/processor3d/shadow3dextractor.cxx b/drawinglayer/source/processor3d/shadow3dextractor.cxx new file mode 100644 index 000000000000..66d3c073854f --- /dev/null +++ b/drawinglayer/source/processor3d/shadow3dextractor.cxx @@ -0,0 +1,306 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: shadow3dextractor.cxx,v $ + * + * $Revision: 1.9 $ + * + * last change: $Author: aw $ $Date: 2008-06-24 15:31:09 $ + * + * 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/processor3d/shadow3dextractor.hxx> +#include <drawinglayer/primitive3d/shadowprimitive3d.hxx> +#include <drawinglayer/primitive2d/shadowprimitive2d.hxx> +#include <drawinglayer/primitive2d/unifiedalphaprimitive2d.hxx> +#include <drawinglayer/primitive3d/transformprimitive3d.hxx> +#include <drawinglayer/primitive3d/polygonprimitive3d.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <drawinglayer/primitive2d/polygonprimitive2d.hxx> +#include <drawinglayer/primitive3d/polypolygonprimitive3d.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace processor3d + { + // as tooling, the process() implementation takes over API handling and calls this + // virtual render method when the primitive implementation is BasePrimitive3D-based. + void Shadow3DExtractingProcessor::processBasePrimitive3D(const primitive3d::BasePrimitive3D& rCandidate) + { + // it is a BasePrimitive3D implementation, use getPrimitiveID() call for switch + switch(rCandidate.getPrimitiveID()) + { + case PRIMITIVE3D_ID_SHADOWPRIMITIVE3D : + { + // shadow3d object. Call recursive with content and start conversion + const primitive3d::ShadowPrimitive3D& rPrimitive = static_cast< const primitive3d::ShadowPrimitive3D& >(rCandidate); + + // set new target + primitive2d::Primitive2DSequence aNewSubList; + primitive2d::Primitive2DSequence* pLastTargetSequence = mpPrimitive2DSequence; + mpPrimitive2DSequence = &aNewSubList; + + // activate convert + const bool bLastConvert(mbConvert); + mbConvert = true; + + // set projection flag + const bool bLastUseProjection(mbUseProjection); + mbUseProjection = rPrimitive.getShadow3D(); + + // process content + process(rPrimitive.getChildren()); + + // restore values + mbUseProjection = bLastUseProjection; + mbConvert = bLastConvert; + mpPrimitive2DSequence = pLastTargetSequence; + + // create 2d shadow primitive with result + const primitive2d::Primitive2DReference xRef(new primitive2d::ShadowPrimitive2D(rPrimitive.getShadowTransform(), rPrimitive.getShadowColor(), aNewSubList)); + + if(basegfx::fTools::more(rPrimitive.getShadowTransparence(), 0.0)) + { + // create simpleTransparencePrimitive, add created primitives + const primitive2d::Primitive2DSequence aNewTransPrimitiveVector(&xRef, 1L); + const primitive2d::Primitive2DReference xRef2(new primitive2d::UnifiedAlphaPrimitive2D(aNewTransPrimitiveVector, rPrimitive.getShadowTransparence())); + primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(*mpPrimitive2DSequence, xRef2); + } + else + { + // add directly + primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(*mpPrimitive2DSequence, xRef); + } + break; + } + case PRIMITIVE3D_ID_TRANSFORMPRIMITIVE3D : + { + // transform group. Remember current transformations + const primitive3d::TransformPrimitive3D& rPrimitive = static_cast< const primitive3d::TransformPrimitive3D& >(rCandidate); + const geometry::ViewInformation3D aLastViewInformation3D(getViewInformation3D()); + + // create new transformation; add new object transform from right side + const geometry::ViewInformation3D aNewViewInformation3D( + aLastViewInformation3D.getObjectTransformation() * rPrimitive.getTransformation(), + aLastViewInformation3D.getOrientation(), + aLastViewInformation3D.getProjection(), + aLastViewInformation3D.getDeviceToView(), + aLastViewInformation3D.getViewTime(), + aLastViewInformation3D.getExtendedInformationSequence()); + updateViewInformation(aNewViewInformation3D); + + if(mbShadowProjectionIsValid) + { + // update buffered WorldToEye and EyeToView + maWorldToEye = getViewInformation3D().getOrientation() * getViewInformation3D().getObjectTransformation(); + maEyeToView = getViewInformation3D().getDeviceToView() * getViewInformation3D().getProjection(); + } + + // let break down + process(rPrimitive.getChildren()); + + // restore transformations + updateViewInformation(aLastViewInformation3D); + + if(mbShadowProjectionIsValid) + { + // update buffered WorldToEye and EyeToView + maWorldToEye = getViewInformation3D().getOrientation() * getViewInformation3D().getObjectTransformation(); + maEyeToView = getViewInformation3D().getDeviceToView() * getViewInformation3D().getProjection(); + } + break; + } + case PRIMITIVE3D_ID_POLYGONHAIRLINEPRIMITIVE3D : + { + // PolygonHairlinePrimitive3D + if(mbConvert) + { + const primitive3d::PolygonHairlinePrimitive3D& rPrimitive = static_cast< const primitive3d::PolygonHairlinePrimitive3D& >(rCandidate); + basegfx::B2DPolygon a2DHairline; + + if(mbUseProjection) + { + if(mbShadowProjectionIsValid) + { + a2DHairline = impDoShadowProjection(rPrimitive.getB3DPolygon()); + } + } + else + { + a2DHairline = basegfx::tools::createB2DPolygonFromB3DPolygon(rPrimitive.getB3DPolygon(), getViewInformation3D().getObjectToView()); + } + + if(a2DHairline.count()) + { + a2DHairline.transform(getObjectTransformation()); + const primitive2d::Primitive2DReference xRef(new primitive2d::PolygonHairlinePrimitive2D(a2DHairline, maPrimitiveColor)); + primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(*mpPrimitive2DSequence, xRef); + } + } + break; + } + case PRIMITIVE3D_ID_POLYPOLYGONMATERIALPRIMITIVE3D : + { + // PolyPolygonMaterialPrimitive3D + if(mbConvert) + { + const primitive3d::PolyPolygonMaterialPrimitive3D& rPrimitive = static_cast< const primitive3d::PolyPolygonMaterialPrimitive3D& >(rCandidate); + basegfx::B2DPolyPolygon a2DFill; + + if(mbUseProjection) + { + if(mbShadowProjectionIsValid) + { + a2DFill = impDoShadowProjection(rPrimitive.getB3DPolyPolygon()); + } + } + else + { + a2DFill = basegfx::tools::createB2DPolyPolygonFromB3DPolyPolygon(rPrimitive.getB3DPolyPolygon(), getViewInformation3D().getObjectToView()); + } + + if(a2DFill.count()) + { + a2DFill.transform(getObjectTransformation()); + const primitive2d::Primitive2DReference xRef(new primitive2d::PolyPolygonColorPrimitive2D(a2DFill, maPrimitiveColor)); + primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(*mpPrimitive2DSequence, xRef); + } + } + break; + } + default : + { + // process recursively + process(rCandidate.get3DDecomposition(getViewInformation3D())); + break; + } + } + } + + Shadow3DExtractingProcessor::Shadow3DExtractingProcessor( + const geometry::ViewInformation3D& rViewInformation, + const basegfx::B2DHomMatrix& rObjectTransformation, + const basegfx::B3DVector& rLightNormal, + double fShadowSlant, + const basegfx::B3DRange& rContained3DRange) + : BaseProcessor3D(rViewInformation), + maPrimitive2DSequence(), + mpPrimitive2DSequence(&maPrimitive2DSequence), + maObjectTransformation(rObjectTransformation), + maWorldToEye(), + maEyeToView(), + maLightNormal(rLightNormal), + maShadowPlaneNormal(), + maPlanePoint(), + mfLightPlaneScalar(0.0), + maPrimitiveColor(), + mbShadowProjectionIsValid(false), + mbConvert(false), + mbUseProjection(false) + { + // normalize light normal, get and normalize shadow plane normal and calculate scalar from it + maLightNormal.normalize(); + maShadowPlaneNormal = basegfx::B3DVector(0.0, sin(fShadowSlant), cos(fShadowSlant)); + maShadowPlaneNormal.normalize(); + mfLightPlaneScalar = maLightNormal.scalar(maShadowPlaneNormal); + + // use only when scalar is > 0.0, so the light is in front of the object + if(basegfx::fTools::more(mfLightPlaneScalar, 0.0)) + { + // prepare buffered WorldToEye and EyeToView + maWorldToEye = getViewInformation3D().getOrientation() * getViewInformation3D().getObjectTransformation(); + maEyeToView = getViewInformation3D().getDeviceToView() * getViewInformation3D().getProjection(); + + // calculate range to get front edge around which to rotate the shadow's projection + basegfx::B3DRange aContained3DRange(rContained3DRange); + aContained3DRange.transform(getWorldToEye()); + maPlanePoint.setX(maShadowPlaneNormal.getX() < 0.0 ? aContained3DRange.getMinX() : aContained3DRange.getMaxX()); + maPlanePoint.setY(maShadowPlaneNormal.getY() > 0.0 ? aContained3DRange.getMinY() : aContained3DRange.getMaxY()); + maPlanePoint.setZ(aContained3DRange.getMinZ() - (aContained3DRange.getDepth() / 8.0)); + + // set flag that shadow projection is prepared and allowed + mbShadowProjectionIsValid = true; + } + } + + basegfx::B2DPolygon Shadow3DExtractingProcessor::impDoShadowProjection(const basegfx::B3DPolygon& rSource) + { + basegfx::B2DPolygon aRetval; + + for(sal_uInt32 a(0L); a < rSource.count(); a++) + { + // get point, transform to eye coordinate system + basegfx::B3DPoint aCandidate(rSource.getB3DPoint(a)); + aCandidate *= getWorldToEye(); + + // we are in eye coordinates + // ray is (aCandidate + fCut * maLightNormal) + // plane is (maPlanePoint, maShadowPlaneNormal) + // maLightNormal.scalar(maShadowPlaneNormal) is already in mfLightPlaneScalar and > 0.0 + // get cut point of ray with shadow plane + const double fCut(basegfx::B3DVector(maPlanePoint - aCandidate).scalar(maShadowPlaneNormal) / mfLightPlaneScalar); + aCandidate += maLightNormal * fCut; + + // transform to view, use 2d coordinates + aCandidate *= getEyeToView(); + aRetval.append(basegfx::B2DPoint(aCandidate.getX(), aCandidate.getY())); + } + + // copy closed flag + aRetval.setClosed(rSource.isClosed()); + + return aRetval; + } + + basegfx::B2DPolyPolygon Shadow3DExtractingProcessor::impDoShadowProjection(const basegfx::B3DPolyPolygon& rSource) + { + basegfx::B2DPolyPolygon aRetval; + + for(sal_uInt32 a(0L); a < rSource.count(); a++) + { + aRetval.append(impDoShadowProjection(rSource.getB3DPolygon(a))); + } + + return aRetval; + } + } // end of namespace processor3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/processor3d/zbufferprocessor3d.cxx b/drawinglayer/source/processor3d/zbufferprocessor3d.cxx new file mode 100644 index 000000000000..b5a59e10a119 --- /dev/null +++ b/drawinglayer/source/processor3d/zbufferprocessor3d.cxx @@ -0,0 +1,747 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: zbufferprocessor3d.cxx,v $ + * + * $Revision: 1.5 $ + * + * last change: $Author: aw $ $Date: 2008-06-24 15:31:09 $ + * + * 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/processor3d/zbufferprocessor3d.hxx> +#include <basegfx/raster/bpixelraster.hxx> +#include <vcl/bmpacc.hxx> +#include <basegfx/raster/rasterconvert3d.hxx> +#include <basegfx/raster/bzpixelraster.hxx> +#include <drawinglayer/attribute/materialattribute3d.hxx> +#include <drawinglayer/texture/texture.hxx> +#include <drawinglayer/attribute/sdrattribute3d.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> +#include <drawinglayer/primitive3d/textureprimitive3d.hxx> +#include <drawinglayer/primitive3d/polygonprimitive3d.hxx> +#include <drawinglayer/primitive3d/polypolygonprimitive3d.hxx> +#include <drawinglayer/geometry/viewinformation2d.hxx> +#include <basegfx/polygon/b3dpolygontools.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace +{ + BitmapEx BPixelRasterToBitmapEx(const basegfx::BPixelRaster& rRaster, sal_uInt16 mnAntiAlialize) + { + BitmapEx aRetval; + const sal_uInt32 nWidth(mnAntiAlialize ? rRaster.getWidth()/mnAntiAlialize : rRaster.getWidth()); + const sal_uInt32 nHeight(mnAntiAlialize ? rRaster.getHeight()/mnAntiAlialize : rRaster.getHeight()); + + if(nWidth && nHeight) + { + const Size aDestSize(nWidth, nHeight); + sal_uInt8 nInitAlpha(255); + Bitmap aContent(aDestSize, 24); + AlphaMask aAlpha(aDestSize, &nInitAlpha); + BitmapWriteAccess* pContent = aContent.AcquireWriteAccess(); + BitmapWriteAccess* pAlpha = aAlpha.AcquireWriteAccess(); + + if(pContent && pAlpha) + { + if(mnAntiAlialize) + { + const sal_uInt16 nDivisor(mnAntiAlialize * mnAntiAlialize); + + for(sal_uInt32 y(0L); y < nHeight; y++) + { + for(sal_uInt32 x(0L); x < nWidth; x++) + { + sal_uInt16 nRed(0); + sal_uInt16 nGreen(0); + sal_uInt16 nBlue(0); + sal_uInt16 nOpacity(0); + sal_uInt32 nIndex(rRaster.getIndexFromXY(x * mnAntiAlialize, y * mnAntiAlialize)); + + for(sal_uInt32 c(0); c < mnAntiAlialize; c++) + { + for(sal_uInt32 d(0); d < mnAntiAlialize; d++) + { + const basegfx::BPixel& rPixel(rRaster.getBPixel(nIndex++)); + nRed = nRed + rPixel.getRed(); + nGreen = nGreen + rPixel.getGreen(); + nBlue = nBlue + rPixel.getBlue(); + nOpacity = nOpacity + rPixel.getOpacity(); + } + + nIndex += rRaster.getWidth() - mnAntiAlialize; + } + + nOpacity = nOpacity / nDivisor; + + if(nOpacity) + { + pContent->SetPixel(y, x, BitmapColor( + (sal_uInt8)(nRed / nDivisor), + (sal_uInt8)(nGreen / nDivisor), + (sal_uInt8)(nBlue / nDivisor))); + pAlpha->SetPixel(y, x, BitmapColor(255 - (sal_uInt8)nOpacity)); + } + } + } + } + else + { + sal_uInt32 nIndex(0L); + + for(sal_uInt32 y(0L); y < nHeight; y++) + { + for(sal_uInt32 x(0L); x < nWidth; x++) + { + const basegfx::BPixel& rPixel(rRaster.getBPixel(nIndex++)); + + if(rPixel.getOpacity()) + { + pContent->SetPixel(y, x, BitmapColor(rPixel.getRed(), rPixel.getGreen(), rPixel.getBlue())); + pAlpha->SetPixel(y, x, BitmapColor(255 - rPixel.getOpacity())); + } + } + } + } + + delete pContent; + delete pAlpha; + } + + aRetval = BitmapEx(aContent, aAlpha); + + // #i101811# set PrefMapMode and PrefSize at newly created Bitmap + aRetval.SetPrefMapMode(MAP_100TH_MM); + aRetval.SetPrefSize(Size(nWidth, nHeight)); + } + + return aRetval; + } +} // end of anonymous namespace + +////////////////////////////////////////////////////////////////////////////// + +class ZBufferRasterConverter3D : public basegfx::RasterConverter3D +{ +private: + const drawinglayer::processor3d::DefaultProcessor3D& mrProcessor; + basegfx::BZPixelRaster& mrBuffer; + + // interpolators for a single line span + basegfx::ip_single maIntZ; + basegfx::ip_triple maIntColor; + basegfx::ip_triple maIntNormal; + basegfx::ip_double maIntTexture; + basegfx::ip_triple maIntInvTexture; + + // current material to use for ratsreconversion + const drawinglayer::attribute::MaterialAttribute3D* mpCurrentMaterial; + + // bitfield + // some boolean flags for line span interpolator usages + unsigned mbModifyColor : 1; + unsigned mbUseTex : 1; + unsigned mbHasTexCoor : 1; + unsigned mbHasInvTexCoor : 1; + unsigned mbUseNrm : 1; + unsigned mbUseCol : 1; + + void getTextureCoor(basegfx::B2DPoint& rTarget) const + { + if(mbHasTexCoor) + { + rTarget.setX(maIntTexture.getX().getVal()); + rTarget.setY(maIntTexture.getY().getVal()); + } + else if(mbHasInvTexCoor) + { + const double fZFactor(maIntInvTexture.getZ().getVal()); + const double fInvZFactor(basegfx::fTools::equalZero(fZFactor) ? 1.0 : 1.0 / fZFactor); + rTarget.setX(maIntInvTexture.getX().getVal() * fInvZFactor); + rTarget.setY(maIntInvTexture.getY().getVal() * fInvZFactor); + } + } + + void incrementLineSpanInterpolators(double fStep) + { + maIntZ.increment(fStep); + + if(mbUseTex) + { + if(mbHasTexCoor) + { + maIntTexture.increment(fStep); + } + else if(mbHasInvTexCoor) + { + maIntInvTexture.increment(fStep); + } + } + + if(mbUseNrm) + { + maIntNormal.increment(fStep); + } + + if(mbUseCol) + { + maIntColor.increment(fStep); + } + } + + double decideColorAndOpacity(basegfx::BColor& rColor) + { + // init values with full opacity and material color + OSL_ENSURE(0 != mpCurrentMaterial, "CurrentMaterial not set (!)"); + double fOpacity(1.0); + rColor = mpCurrentMaterial->getColor(); + + if(mbUseTex) + { + basegfx::B2DPoint aTexCoor(0.0, 0.0); + getTextureCoor(aTexCoor); + + if(mrProcessor.getGeoTexSvx()) + { + // calc color in spot. This may also set to invisible already when + // e.g. bitmap textures have transparent parts + mrProcessor.getGeoTexSvx()->modifyBColor(aTexCoor, rColor, fOpacity); + } + + if(basegfx::fTools::more(fOpacity, 0.0) && mrProcessor.getTransparenceGeoTexSvx()) + { + // calc opacity. Object has a 2nd texture, a transparence texture + mrProcessor.getTransparenceGeoTexSvx()->modifyOpacity(aTexCoor, fOpacity); + } + } + + if(basegfx::fTools::more(fOpacity, 0.0)) + { + if(mrProcessor.getGeoTexSvx()) + { + if(mbUseNrm) + { + // blend texture with phong + rColor = mrProcessor.getSdrLightingAttribute().solveColorModel( + basegfx::B3DVector(maIntNormal.getX().getVal(), maIntNormal.getY().getVal(), maIntNormal.getZ().getVal()), + rColor, + mpCurrentMaterial->getSpecular(), + mpCurrentMaterial->getEmission(), + mpCurrentMaterial->getSpecularIntensity()); + } + else if(mbUseCol) + { + // blend texture with gouraud + basegfx::BColor aBlendColor(maIntColor.getX().getVal(), maIntColor.getY().getVal(), maIntColor.getZ().getVal()); + rColor *= aBlendColor; + } + else if(mrProcessor.getModulate()) + { + // blend texture with single material color + rColor *= mpCurrentMaterial->getColor(); + } + } + else + { + if(mbUseNrm) + { + // modify color with phong + rColor = mrProcessor.getSdrLightingAttribute().solveColorModel( + basegfx::B3DVector(maIntNormal.getX().getVal(), maIntNormal.getY().getVal(), maIntNormal.getZ().getVal()), + rColor, + mpCurrentMaterial->getSpecular(), + mpCurrentMaterial->getEmission(), + mpCurrentMaterial->getSpecularIntensity()); + } + else if(mbUseCol) + { + // modify color with gouraud + rColor.setRed(maIntColor.getX().getVal()); + rColor.setGreen(maIntColor.getY().getVal()); + rColor.setBlue(maIntColor.getZ().getVal()); + } + } + + if(mbModifyColor) + { + rColor = mrProcessor.getBColorModifierStack().getModifiedColor(rColor); + } + } + + return fOpacity; + } + + void setupLineSpanInterpolators(const basegfx::RasterConversionLineEntry3D& rA, const basegfx::RasterConversionLineEntry3D& rB) + { + // get inverse XDelta + const double xInvDelta(1.0 / (rB.getX().getVal() - rA.getX().getVal())); + + // prepare Z-interpolator + const double fZA(rA.getZ().getVal()); + const double fZB(rB.getZ().getVal()); + maIntZ = basegfx::ip_single(fZA, (fZB - fZA) * xInvDelta); + + // get bools and init other interpolators on demand accordingly + mbModifyColor = mrProcessor.getBColorModifierStack().count(); + mbHasTexCoor = SCANLINE_EMPTY_INDEX != rA.getTextureIndex() && SCANLINE_EMPTY_INDEX != rB.getTextureIndex(); + mbHasInvTexCoor = SCANLINE_EMPTY_INDEX != rA.getInverseTextureIndex() && SCANLINE_EMPTY_INDEX != rB.getInverseTextureIndex(); + const bool bTextureActive(mrProcessor.getGeoTexSvx() || mrProcessor.getTransparenceGeoTexSvx()); + mbUseTex = bTextureActive && (mbHasTexCoor || mbHasInvTexCoor || mrProcessor.getSimpleTextureActive()); + const bool bUseColorTex(mbUseTex && mrProcessor.getGeoTexSvx()); + const bool bNeedNrmOrCol(!bUseColorTex || (bUseColorTex && mrProcessor.getModulate())); + mbUseNrm = bNeedNrmOrCol && SCANLINE_EMPTY_INDEX != rA.getNormalIndex() && SCANLINE_EMPTY_INDEX != rB.getNormalIndex(); + mbUseCol = !mbUseNrm && bNeedNrmOrCol && SCANLINE_EMPTY_INDEX != rA.getColorIndex() && SCANLINE_EMPTY_INDEX != rB.getColorIndex(); + + if(mbUseTex) + { + if(mbHasTexCoor) + { + const basegfx::ip_double& rTA(getTextureInterpolators()[rA.getTextureIndex()]); + const basegfx::ip_double& rTB(getTextureInterpolators()[rB.getTextureIndex()]); + maIntTexture = basegfx::ip_double( + rTA.getX().getVal(), (rTB.getX().getVal() - rTA.getX().getVal()) * xInvDelta, + rTA.getY().getVal(), (rTB.getY().getVal() - rTA.getY().getVal()) * xInvDelta); + } + else if(mbHasInvTexCoor) + { + const basegfx::ip_triple& rITA(getInverseTextureInterpolators()[rA.getInverseTextureIndex()]); + const basegfx::ip_triple& rITB(getInverseTextureInterpolators()[rB.getInverseTextureIndex()]); + maIntInvTexture = basegfx::ip_triple( + rITA.getX().getVal(), (rITB.getX().getVal() - rITA.getX().getVal()) * xInvDelta, + rITA.getY().getVal(), (rITB.getY().getVal() - rITA.getY().getVal()) * xInvDelta, + rITA.getZ().getVal(), (rITB.getZ().getVal() - rITA.getZ().getVal()) * xInvDelta); + } + } + + if(mbUseNrm) + { + const basegfx::ip_triple& rNA(getNormalInterpolators()[rA.getNormalIndex()]); + const basegfx::ip_triple& rNB(getNormalInterpolators()[rB.getNormalIndex()]); + maIntNormal = basegfx::ip_triple( + rNA.getX().getVal(), (rNB.getX().getVal() - rNA.getX().getVal()) * xInvDelta, + rNA.getY().getVal(), (rNB.getY().getVal() - rNA.getY().getVal()) * xInvDelta, + rNA.getZ().getVal(), (rNB.getZ().getVal() - rNA.getZ().getVal()) * xInvDelta); + } + + if(mbUseCol) + { + const basegfx::ip_triple& rCA(getColorInterpolators()[rA.getColorIndex()]); + const basegfx::ip_triple& rCB(getColorInterpolators()[rB.getColorIndex()]); + maIntColor = basegfx::ip_triple( + rCA.getX().getVal(), (rCB.getX().getVal() - rCA.getX().getVal()) * xInvDelta, + rCA.getY().getVal(), (rCB.getY().getVal() - rCA.getY().getVal()) * xInvDelta, + rCA.getZ().getVal(), (rCB.getZ().getVal() - rCA.getZ().getVal()) * xInvDelta); + } + } + + virtual void processLineSpan(const basegfx::RasterConversionLineEntry3D& rA, const basegfx::RasterConversionLineEntry3D& rB, sal_Int32 nLine, sal_uInt32 nSpanCount); + +public: + ZBufferRasterConverter3D(basegfx::BZPixelRaster& rBuffer, const drawinglayer::processor3d::ZBufferProcessor3D& rProcessor) + : basegfx::RasterConverter3D(), + mrProcessor(rProcessor), + mrBuffer(rBuffer), + maIntZ(), + maIntColor(), + maIntNormal(), + maIntTexture(), + maIntInvTexture(), + mpCurrentMaterial(0), + mbModifyColor(false), + mbUseTex(false), + mbHasTexCoor(false), + mbUseNrm(false), + mbUseCol(false) + {} + + void setCurrentMaterial(const drawinglayer::attribute::MaterialAttribute3D& rMaterial) + { + mpCurrentMaterial = &rMaterial; + } +}; + +void ZBufferRasterConverter3D::processLineSpan(const basegfx::RasterConversionLineEntry3D& rA, const basegfx::RasterConversionLineEntry3D& rB, sal_Int32 nLine, sal_uInt32 nSpanCount) +{ + if(!(nSpanCount & 0x0001)) + { + if(nLine >= 0 && nLine < (sal_Int32)mrBuffer.getHeight()) + { + sal_uInt32 nXA(::std::min(mrBuffer.getWidth(), (sal_uInt32)::std::max((sal_Int32)0, basegfx::fround(rA.getX().getVal())))); + const sal_uInt32 nXB(::std::min(mrBuffer.getWidth(), (sal_uInt32)::std::max((sal_Int32)0, basegfx::fround(rB.getX().getVal())))); + + if(nXA < nXB) + { + // prepare the span interpolators + setupLineSpanInterpolators(rA, rB); + + // bring span interpolators to start condition by incrementing with the possible difference of + // clamped and non-clamped XStart. Interpolators are setup relying on double precision + // X-values, so that difference is the correct value to compensate for possible clampings + incrementLineSpanInterpolators(static_cast<double>(nXA) - rA.getX().getVal()); + + // prepare scanline index + sal_uInt32 nScanlineIndex(mrBuffer.getIndexFromXY(nXA, static_cast<sal_uInt32>(nLine))); + basegfx::BColor aNewColor; + + while(nXA < nXB) + { + // early-test Z values if we need to do anything at all + const double fNewZ(::std::max(0.0, ::std::min((double)0xffff, maIntZ.getVal()))); + const sal_uInt16 nNewZ(static_cast< sal_uInt16 >(fNewZ)); + sal_uInt16& rOldZ(mrBuffer.getZ(nScanlineIndex)); + + if(nNewZ > rOldZ) + { + // detect color and opacity for this pixel + const sal_uInt16 nOpacity(::std::max((sal_Int16)0, static_cast< sal_Int16 >(decideColorAndOpacity(aNewColor) * 255.0))); + + if(nOpacity > 0) + { + // avoid color overrun + aNewColor.clamp(); + + if(nOpacity >= 0x00ff) + { + // full opacity, set z and color + rOldZ = nNewZ; + mrBuffer.getBPixel(nScanlineIndex) = basegfx::BPixel(aNewColor, 0xff); + } + else + { + basegfx::BPixel& rDest = mrBuffer.getBPixel(nScanlineIndex); + + if(rDest.getOpacity()) + { + // both transparent, mix color based on front pixel's opacity + // (the new one) + const sal_uInt16 nTransparence(0x0100 - nOpacity); + rDest.setRed((sal_uInt8)(((rDest.getRed() * nTransparence) + ((sal_uInt16)(255.0 * aNewColor.getRed()) * nOpacity)) >> 8)); + rDest.setGreen((sal_uInt8)(((rDest.getGreen() * nTransparence) + ((sal_uInt16)(255.0 * aNewColor.getGreen()) * nOpacity)) >> 8)); + rDest.setBlue((sal_uInt8)(((rDest.getBlue() * nTransparence) + ((sal_uInt16)(255.0 * aNewColor.getBlue()) * nOpacity)) >> 8)); + + if(0xff != rDest.getOpacity()) + { + // destination is also transparent, mix opacities by weighting + // old opacity with new pixel's transparence and adding new opacity + rDest.setOpacity((sal_uInt8)(((rDest.getOpacity() * nTransparence) >> 8) + nOpacity)); + } + } + else + { + // dest is not visible. Set color. + rDest = basegfx::BPixel(aNewColor, (sal_uInt8)nOpacity); + } + } + } + } + + // increments + nScanlineIndex++; + nXA++; + incrementLineSpanInterpolators(1.0); + } + } + } + } +} + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace processor3d + { + // the processing method for a single, known primitive + void ZBufferProcessor3D::processBasePrimitive3D(const primitive3d::BasePrimitive3D& rBasePrimitive) + { + // it is a BasePrimitive3D implementation, use getPrimitiveID() call for switch + switch(rBasePrimitive.getPrimitiveID()) + { + case PRIMITIVE3D_ID_ALPHATEXTUREPRIMITIVE3D : + { + // AlphaTexturePrimitive3D + const primitive3d::AlphaTexturePrimitive3D& rPrimitive = static_cast< const primitive3d::AlphaTexturePrimitive3D& >(rBasePrimitive); + + if(mbProcessTransparent) + { + impRenderGradientTexturePrimitive3D(rPrimitive, true); + } + else + { + mbContainsTransparent = true; + } + break; + } + case PRIMITIVE3D_ID_POLYGONHAIRLINEPRIMITIVE3D : + { + // directdraw of PolygonHairlinePrimitive3D + const primitive3d::PolygonHairlinePrimitive3D& rPrimitive = static_cast< const primitive3d::PolygonHairlinePrimitive3D& >(rBasePrimitive); + + // do something when either not transparent and no transMap, or transparent and a TransMap + if((bool)mbProcessTransparent == (0 != getTransparenceGeoTexSvx())) + { + impRenderPolygonHairlinePrimitive3D(rPrimitive); + } + break; + } + case PRIMITIVE3D_ID_POLYPOLYGONMATERIALPRIMITIVE3D : + { + // directdraw of PolyPolygonMaterialPrimitive3D + const primitive3d::PolyPolygonMaterialPrimitive3D& rPrimitive = static_cast< const primitive3d::PolyPolygonMaterialPrimitive3D& >(rBasePrimitive); + + // do something when either not transparent and no transMap, or transparent and a TransMap + if((bool)mbProcessTransparent == (0 != getTransparenceGeoTexSvx())) + { + impRenderPolyPolygonMaterialPrimitive3D(rPrimitive); + } + break; + } + default: + { + // use the DefaultProcessor3D::processBasePrimitive3D() + DefaultProcessor3D::processBasePrimitive3D(rBasePrimitive); + break; + } + } + } + + void ZBufferProcessor3D::processNonTransparent(const primitive3d::Primitive3DSequence& rSource) + { + if(mpBZPixelRaster) + { + mbProcessTransparent = false; + mbContainsTransparent = false; + process(rSource); + } + } + + void ZBufferProcessor3D::processTransparent(const primitive3d::Primitive3DSequence& rSource) + { + if(mpBZPixelRaster && mbContainsTransparent) + { + mbProcessTransparent = true; + process(rSource); + } + } + + void ZBufferProcessor3D::rasterconvertB3DPolygon(const attribute::MaterialAttribute3D& rMaterial, const basegfx::B3DPolygon& rHairline) const + { + if(mpBZPixelRaster) + { + mpZBufferRasterConverter3D->setCurrentMaterial(rMaterial); + + if(mnAntiAlialize > 1) + { + const bool bForceLineSnap(getOptionsDrawinglayer().IsAntiAliasing() && getOptionsDrawinglayer().IsSnapHorVerLinesToDiscrete()); + + if(bForceLineSnap) + { + basegfx::B3DHomMatrix aTransform; + basegfx::B3DPolygon aSnappedHairline(rHairline); + const double fScaleDown(1.0 / mnAntiAlialize); + const double fScaleUp(mnAntiAlialize); + + // take oversampling out + aTransform.scale(fScaleDown, fScaleDown, 1.0); + aSnappedHairline.transform(aTransform); + + // snap to integer + aSnappedHairline = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aSnappedHairline); + + // add oversampling again + aTransform.identity(); + aTransform.scale(fScaleUp, fScaleUp, 1.0); + + if(false) + { + // when really want to go to single pixel lines, move to center. + // Without this translation, all hor/ver hairlines will be centered exactly + // between two pixel lines (which looks best) + const double fTranslateToCenter(mnAntiAlialize * 0.5); + aTransform.translate(fTranslateToCenter, fTranslateToCenter, 0.0); + } + + aSnappedHairline.transform(aTransform); + + mpZBufferRasterConverter3D->rasterconvertB3DPolygon(aSnappedHairline, 0, mpBZPixelRaster->getHeight(), mnAntiAlialize); + } + else + { + mpZBufferRasterConverter3D->rasterconvertB3DPolygon(rHairline, 0, mpBZPixelRaster->getHeight(), mnAntiAlialize); + } + } + else + { + mpZBufferRasterConverter3D->rasterconvertB3DPolygon(rHairline, 0, mpBZPixelRaster->getHeight(), 1); + } + } + } + + void ZBufferProcessor3D::rasterconvertB3DPolyPolygon(const attribute::MaterialAttribute3D& rMaterial, const basegfx::B3DPolyPolygon& rFill) const + { + if(mpBZPixelRaster) + { + mpZBufferRasterConverter3D->setCurrentMaterial(rMaterial); + mpZBufferRasterConverter3D->rasterconvertB3DPolyPolygon(rFill, &maInvEyeToView, 0, mpBZPixelRaster->getHeight()); + } + } + + ZBufferProcessor3D::ZBufferProcessor3D( + const geometry::ViewInformation3D& rViewInformation3D, + const geometry::ViewInformation2D& rViewInformation2D, + const attribute::SdrSceneAttribute& rSdrSceneAttribute, + const attribute::SdrLightingAttribute& rSdrLightingAttribute, + double fSizeX, + double fSizeY, + const basegfx::B2DRange& rVisiblePart, + sal_uInt16 nAntiAlialize) + : DefaultProcessor3D(rViewInformation3D, rSdrSceneAttribute, rSdrLightingAttribute), + mpBZPixelRaster(0), + maInvEyeToView(), + mpZBufferRasterConverter3D(0), + mnAntiAlialize(nAntiAlialize), + mbProcessTransparent(false), + mbContainsTransparent(false) + { + // generate ViewSizes + const double fFullViewSizeX((rViewInformation2D.getObjectToViewTransformation() * basegfx::B2DVector(fSizeX, 0.0)).getLength()); + const double fFullViewSizeY((rViewInformation2D.getObjectToViewTransformation() * basegfx::B2DVector(0.0, fSizeY)).getLength()); + const double fViewSizeX(fFullViewSizeX * rVisiblePart.getWidth()); + const double fViewSizeY(fFullViewSizeY * rVisiblePart.getHeight()); + + // generate RasterWidth and RasterHeight + const sal_uInt32 nRasterWidth((sal_uInt32)basegfx::fround(fViewSizeX) + 1); + const sal_uInt32 nRasterHeight((sal_uInt32)basegfx::fround(fViewSizeY) + 1); + + if(nRasterWidth && nRasterHeight) + { + // create view unit buffer + mpBZPixelRaster = new basegfx::BZPixelRaster( + mnAntiAlialize ? nRasterWidth * mnAntiAlialize : nRasterWidth, + mnAntiAlialize ? nRasterHeight * mnAntiAlialize : nRasterHeight); + OSL_ENSURE(mpBZPixelRaster, "ZBufferProcessor3D: Could not allocate basegfx::BZPixelRaster (!)"); + + // create DeviceToView for Z-Buffer renderer since Z is handled + // different from standard 3D transformations (Z is mirrored). Also + // the transformation includes the step from unit device coordinates + // to discrete units ([-1.0 .. 1.0] -> [minDiscrete .. maxDiscrete] + + basegfx::B3DHomMatrix aDeviceToView; + + { + // step one: + // + // bring from [-1.0 .. 1.0] in X,Y and Z to [0.0 .. 1.0]. Also + // necessary to + // - flip Y due to screen orientation + // - flip Z due to Z-Buffer orientation from back to front + + aDeviceToView.scale(0.5, -0.5, -0.5); + aDeviceToView.translate(0.5, 0.5, 0.5); + } + + { + // step two: + // + // bring from [0.0 .. 1.0] in X,Y and Z to view cordinates + // + // #i102611# + // also: scale Z to [1.5 .. 65534.5]. Normally, a range of [0.0 .. 65535.0] + // could be used, but a 'unused' value is needed, so '0' is used what reduces + // the range to [1.0 .. 65535.0]. It has also shown that small numerical errors + // (smaller as basegfx::fTools::mfSmallValue, which is 0.000000001) happen. + // Instead of checking those by basegfx::fTools methods which would cost + // runtime, just add another 0.5 tolerance to the start and end of the Z-Buffer + // range, thus resulting in [1.5 .. 65534.5] + const double fMaxZDepth(65533.0); + aDeviceToView.translate(-rVisiblePart.getMinX(), -rVisiblePart.getMinY(), 0.0); + + if(mnAntiAlialize) + aDeviceToView.scale(fFullViewSizeX * mnAntiAlialize, fFullViewSizeY * mnAntiAlialize, fMaxZDepth); + else + aDeviceToView.scale(fFullViewSizeX, fFullViewSizeY, fMaxZDepth); + + aDeviceToView.translate(0.0, 0.0, 1.5); + } + + // update local ViewInformation3D with own DeviceToView + const geometry::ViewInformation3D aNewViewInformation3D( + getViewInformation3D().getObjectTransformation(), + getViewInformation3D().getOrientation(), + getViewInformation3D().getProjection(), + aDeviceToView, + getViewInformation3D().getViewTime(), + getViewInformation3D().getExtendedInformationSequence()); + updateViewInformation(aNewViewInformation3D); + + // prepare inverse EyeToView transformation. This can be done in constructor + // since changes in object transformations when processing TransformPrimitive3Ds + // do not influence this prepared partial transformation + maInvEyeToView = getViewInformation3D().getDeviceToView() * getViewInformation3D().getProjection(); + maInvEyeToView.invert(); + + // prepare maRasterRange + maRasterRange.reset(); + maRasterRange.expand(basegfx::B2DPoint(0.0, 0.0)); + maRasterRange.expand(basegfx::B2DPoint(mpBZPixelRaster->getWidth(), mpBZPixelRaster->getHeight())); + + // create the raster converter + mpZBufferRasterConverter3D = new ZBufferRasterConverter3D(*mpBZPixelRaster, *this); + } + } + + ZBufferProcessor3D::~ZBufferProcessor3D() + { + if(mpBZPixelRaster) + { + delete mpZBufferRasterConverter3D; + delete mpBZPixelRaster; + } + } + + BitmapEx ZBufferProcessor3D::getBitmapEx() const + { + if(mpBZPixelRaster) + { + return BPixelRasterToBitmapEx(*mpBZPixelRaster, mnAntiAlialize); + } + + return BitmapEx(); + } + } // end of namespace processor3d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/texture/makefile.mk b/drawinglayer/source/texture/makefile.mk new file mode 100644 index 000000000000..abbb303cea0f --- /dev/null +++ b/drawinglayer/source/texture/makefile.mk @@ -0,0 +1,53 @@ +#************************************************************************* +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.3 $ +# +# last change: $Author: aw $ $Date: 2008-04-16 04:59:59 $ +# +# 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 +# +#************************************************************************* + +PRJ=..$/.. +PRJNAME=drawinglayer +TARGET=texture +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ---------------------------------- + +.INCLUDE : settings.mk + +# --- Files ------------------------------------- + +SLOFILES= \ + $(SLO)$/texture.obj \ + $(SLO)$/texture3d.obj + +# --- Targets ---------------------------------- + +.INCLUDE : target.mk diff --git a/drawinglayer/source/texture/texture.cxx b/drawinglayer/source/texture/texture.cxx new file mode 100644 index 000000000000..4f784c71897f --- /dev/null +++ b/drawinglayer/source/texture/texture.cxx @@ -0,0 +1,728 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: texture.cxx,v $ + * + * $Revision: 1.6 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:34 $ + * + * 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/texture/texture.hxx> +#include <basegfx/numeric/ftools.hxx> +#include <basegfx/tools/gradienttools.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace texture + { + GeoTexSvx::GeoTexSvx() + { + } + + GeoTexSvx::~GeoTexSvx() + { + } + + bool GeoTexSvx::operator==(const GeoTexSvx& /*rGeoTexSvx*/) const + { + // default implementation says yes (no data -> no difference) + return true; + } + + void GeoTexSvx::appendTransformations(::std::vector< basegfx::B2DHomMatrix >& /*rMatrices*/) + { + // default implementation does nothing + } + + void GeoTexSvx::modifyBColor(const basegfx::B2DPoint& /*rUV*/, basegfx::BColor& rBColor, double& /*rfOpacity*/) const + { + // base implementation creates random color (for testing only, may also be pure virtual) + rBColor.setRed((rand() & 0x7fff) / 32767.0); + rBColor.setGreen((rand() & 0x7fff) / 32767.0); + rBColor.setBlue((rand() & 0x7fff) / 32767.0); + } + + void GeoTexSvx::modifyOpacity(const basegfx::B2DPoint& rUV, double& rfOpacity) const + { + // base implementation uses inverse of luminance of solved color (for testing only, may also be pure virtual) + basegfx::BColor aBaseColor; + modifyBColor(rUV, aBaseColor, rfOpacity); + rfOpacity = 1.0 - aBaseColor.luminance(); + } + } // end of namespace texture +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace texture + { + void GeoTexSvxGradient::impAppendMatrix(::std::vector< basegfx::B2DHomMatrix >& rMatrices, const basegfx::B2DRange& rRange) + { + basegfx::B2DHomMatrix aNew; + aNew.set(0, 0, rRange.getWidth()); + aNew.set(1, 1, rRange.getHeight()); + aNew.set(0, 2, rRange.getMinX()); + aNew.set(1, 2, rRange.getMinY()); + rMatrices.push_back(maGradientInfo.maTextureTransform * aNew); + } + + void GeoTexSvxGradient::impAppendColorsRadial(::std::vector< basegfx::BColor >& rColors) + { + if(maGradientInfo.mnSteps) + { + rColors.push_back(maStart); + + for(sal_uInt32 a(1L); a < maGradientInfo.mnSteps - 1L; a++) + { + rColors.push_back(interpolate(maStart, maEnd, (double)a / (double)maGradientInfo.mnSteps)); + } + + rColors.push_back(maEnd); + } + } + + GeoTexSvxGradient::GeoTexSvxGradient(const basegfx::B2DRange& rTargetRange, const basegfx::BColor& rStart, const basegfx::BColor& rEnd, sal_uInt32 nSteps, double fBorder) + : maTargetRange(rTargetRange), + maStart(rStart), + maEnd(rEnd), + mfBorder(fBorder) + { + maGradientInfo.mnSteps = nSteps; + maGradientInfo.mfAspectRatio = 1.0; + } + + GeoTexSvxGradient::~GeoTexSvxGradient() + { + } + + bool GeoTexSvxGradient::operator==(const GeoTexSvx& rGeoTexSvx) const + { + const GeoTexSvxGradient* pCompare = dynamic_cast< const GeoTexSvxGradient* >(&rGeoTexSvx); + return (pCompare + && maGradientInfo.maTextureTransform == pCompare->maGradientInfo.maTextureTransform + && maTargetRange == pCompare->maTargetRange + && maGradientInfo.mnSteps == pCompare->maGradientInfo.mnSteps + && maGradientInfo.mfAspectRatio == pCompare->maGradientInfo.mfAspectRatio + && mfBorder == pCompare->mfBorder); + } + } // end of namespace texture +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace texture + { + GeoTexSvxGradientLinear::GeoTexSvxGradientLinear(const basegfx::B2DRange& rTargetRange, const basegfx::BColor& rStart, const basegfx::BColor& rEnd, sal_uInt32 nSteps, double fBorder, double fAngle) + : GeoTexSvxGradient(rTargetRange, rStart, rEnd, nSteps, fBorder) + { + basegfx::tools::createLinearODFGradientInfo(maGradientInfo, + rTargetRange, + nSteps, + fBorder, + fAngle); + } + + GeoTexSvxGradientLinear::~GeoTexSvxGradientLinear() + { + } + + void GeoTexSvxGradientLinear::appendTransformations(::std::vector< basegfx::B2DHomMatrix >& rMatrices) + { + if(maGradientInfo.mnSteps) + { + const double fTop(mfBorder); + const double fStripeWidth((1.0 - fTop) / maGradientInfo.mnSteps); + + for(sal_uInt32 a(1L); a < maGradientInfo.mnSteps; a++) + { + const double fOffsetUpper(fStripeWidth * (double)a); + + // create matrix + const basegfx::B2DRange aRect(0.0, fTop + fOffsetUpper, 1.0, 1.0); + impAppendMatrix(rMatrices, aRect); + } + } + } + + void GeoTexSvxGradientLinear::appendColors(::std::vector< basegfx::BColor >& rColors) + { + if(maGradientInfo.mnSteps) + { + rColors.push_back(maStart); + + for(sal_uInt32 a(1L); a < maGradientInfo.mnSteps; a++) + { + rColors.push_back(interpolate(maStart, maEnd, (double)a / (double)(maGradientInfo.mnSteps + 1L))); + } + } + } + + void GeoTexSvxGradientLinear::modifyBColor(const basegfx::B2DPoint& rUV, basegfx::BColor& rBColor, double& /*rfOpacity*/) const + { + const double fScaler(basegfx::tools::getLinearGradientAlpha(rUV, maGradientInfo)); + + rBColor = (maStart * (1.0 - fScaler)) + (maEnd * fScaler); + } + } // end of namespace texture +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace texture + { + GeoTexSvxGradientAxial::GeoTexSvxGradientAxial(const basegfx::B2DRange& rTargetRange, const basegfx::BColor& rStart, const basegfx::BColor& rEnd, sal_uInt32 nSteps, double fBorder, double fAngle) + : GeoTexSvxGradient(rTargetRange, rStart, rEnd, nSteps, fBorder) + { + basegfx::tools::createAxialODFGradientInfo(maGradientInfo, + rTargetRange, + nSteps, + fBorder, + fAngle); + } + + GeoTexSvxGradientAxial::~GeoTexSvxGradientAxial() + { + } + + void GeoTexSvxGradientAxial::appendTransformations(::std::vector< basegfx::B2DHomMatrix >& rMatrices) + { + if(maGradientInfo.mnSteps) + { + const double fHalfBorder(mfBorder * 0.5); + double fTop(fHalfBorder); + double fBottom(1.0 - fHalfBorder); + const double fStripeWidth((fBottom - fTop) / ((maGradientInfo.mnSteps * 2L) - 1L)); + + for(sal_uInt32 a(1L); a < maGradientInfo.mnSteps; a++) + { + const double fOffset(fStripeWidth * (double)a); + + // create matrix + const basegfx::B2DRange aRect(0.0, fTop + fOffset, 1.0, fBottom - fOffset); + impAppendMatrix(rMatrices, aRect); + } + } + } + + void GeoTexSvxGradientAxial::appendColors(::std::vector< basegfx::BColor >& rColors) + { + if(maGradientInfo.mnSteps) + { + rColors.push_back(maEnd); + + for(sal_uInt32 a(1L); a < maGradientInfo.mnSteps; a++) + { + rColors.push_back(interpolate(maEnd, maStart, (double)a / (double)maGradientInfo.mnSteps)); + } + } + } + + void GeoTexSvxGradientAxial::modifyBColor(const basegfx::B2DPoint& rUV, basegfx::BColor& rBColor, double& /*rfOpacity*/) const + { + const double fScaler(basegfx::tools::getAxialGradientAlpha(rUV, maGradientInfo)); + + rBColor = (maStart * (1.0 - fScaler)) + (maEnd * fScaler); + } + } // end of namespace texture +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace texture + { + GeoTexSvxGradientRadial::GeoTexSvxGradientRadial(const basegfx::B2DRange& rTargetRange, const basegfx::BColor& rStart, const basegfx::BColor& rEnd, sal_uInt32 nSteps, double fBorder, double fOffsetX, double fOffsetY) + : GeoTexSvxGradient(rTargetRange, rStart, rEnd, nSteps, fBorder) + { + basegfx::tools::createRadialODFGradientInfo(maGradientInfo, + rTargetRange, + basegfx::B2DVector(fOffsetX,fOffsetY), + nSteps, + fBorder); + } + + GeoTexSvxGradientRadial::~GeoTexSvxGradientRadial() + { + } + + void GeoTexSvxGradientRadial::appendTransformations(::std::vector< basegfx::B2DHomMatrix >& rMatrices) + { + if(maGradientInfo.mnSteps) + { + const double fHalfBorder((1.0 - mfBorder) * 0.5); + double fLeft(0.5 - fHalfBorder); + double fTop(0.5 - fHalfBorder); + double fRight(0.5 + fHalfBorder); + double fBottom(0.5 + fHalfBorder); + double fIncrementX, fIncrementY; + + if(maGradientInfo.mfAspectRatio > 1.0) + { + fIncrementY = (fBottom - fTop) / (double)(maGradientInfo.mnSteps * 2L); + fIncrementX = fIncrementY / maGradientInfo.mfAspectRatio; + } + else + { + fIncrementX = (fRight - fLeft) / (double)(maGradientInfo.mnSteps * 2L); + fIncrementY = fIncrementX * maGradientInfo.mfAspectRatio; + } + + for(sal_uInt32 a(1L); a < maGradientInfo.mnSteps; a++) + { + // next step + fLeft += fIncrementX; + fRight -= fIncrementX; + fTop += fIncrementY; + fBottom -= fIncrementY; + + // create matrix + const basegfx::B2DRange aRect(fLeft, fTop, fRight, fBottom); + impAppendMatrix(rMatrices, aRect); + } + } + } + + void GeoTexSvxGradientRadial::appendColors(::std::vector< basegfx::BColor >& rColors) + { + impAppendColorsRadial(rColors); + } + + void GeoTexSvxGradientRadial::modifyBColor(const basegfx::B2DPoint& rUV, basegfx::BColor& rBColor, double& /*rfOpacity*/) const + { + const double fScaler(basegfx::tools::getRadialGradientAlpha(rUV, maGradientInfo)); + + rBColor = (maStart * (1.0 - fScaler)) + (maEnd * fScaler); + } + } // end of namespace texture +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace texture + { + GeoTexSvxGradientElliptical::GeoTexSvxGradientElliptical(const basegfx::B2DRange& rTargetRange, const basegfx::BColor& rStart, const basegfx::BColor& rEnd, sal_uInt32 nSteps, double fBorder, double fOffsetX, double fOffsetY, double fAngle) + : GeoTexSvxGradient(rTargetRange, rStart, rEnd, nSteps, fBorder) + { + basegfx::tools::createEllipticalODFGradientInfo(maGradientInfo, + rTargetRange, + basegfx::B2DVector(fOffsetX,fOffsetY), + nSteps, + fBorder, + fAngle); + } + + GeoTexSvxGradientElliptical::~GeoTexSvxGradientElliptical() + { + } + + void GeoTexSvxGradientElliptical::appendTransformations(::std::vector< basegfx::B2DHomMatrix >& rMatrices) + { + if(maGradientInfo.mnSteps) + { + const double fHalfBorder((1.0 - mfBorder) * 0.5); + double fLeft(0.5 - fHalfBorder); + double fTop(0.5 - fHalfBorder); + double fRight(0.5 + fHalfBorder); + double fBottom(0.5 + fHalfBorder); + double fIncrementX, fIncrementY; + + if(maGradientInfo.mfAspectRatio > 1.0) + { + fIncrementY = (fBottom - fTop) / (double)(maGradientInfo.mnSteps * 2L); + fIncrementX = fIncrementY / maGradientInfo.mfAspectRatio; + } + else + { + fIncrementX = (fRight - fLeft) / (double)(maGradientInfo.mnSteps * 2L); + fIncrementY = fIncrementX * maGradientInfo.mfAspectRatio; + } + + for(sal_uInt32 a(1L); a < maGradientInfo.mnSteps; a++) + { + // next step + fLeft += fIncrementX; + fRight -= fIncrementX; + fTop += fIncrementY; + fBottom -= fIncrementY; + + // create matrix + const basegfx::B2DRange aRect(fLeft, fTop, fRight, fBottom); + impAppendMatrix(rMatrices, aRect); + } + } + } + + void GeoTexSvxGradientElliptical::appendColors(::std::vector< basegfx::BColor >& rColors) + { + impAppendColorsRadial(rColors); + } + + void GeoTexSvxGradientElliptical::modifyBColor(const basegfx::B2DPoint& rUV, basegfx::BColor& rBColor, double& /*rfOpacity*/) const + { + const double fScaler(basegfx::tools::getEllipticalGradientAlpha(rUV, maGradientInfo)); + + rBColor = (maStart * (1.0 - fScaler)) + (maEnd * fScaler); + } + } // end of namespace texture +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace texture + { + GeoTexSvxGradientSquare::GeoTexSvxGradientSquare(const basegfx::B2DRange& rTargetRange, const basegfx::BColor& rStart, const basegfx::BColor& rEnd, sal_uInt32 nSteps, double fBorder, double fOffsetX, double fOffsetY, double fAngle) + : GeoTexSvxGradient(rTargetRange, rStart, rEnd, nSteps, fBorder) + { + basegfx::tools::createSquareODFGradientInfo(maGradientInfo, + rTargetRange, + basegfx::B2DVector(fOffsetX,fOffsetY), + nSteps, + fBorder, + fAngle); + } + + GeoTexSvxGradientSquare::~GeoTexSvxGradientSquare() + { + } + + void GeoTexSvxGradientSquare::appendTransformations(::std::vector< basegfx::B2DHomMatrix >& rMatrices) + { + if(maGradientInfo.mnSteps) + { + const double fHalfBorder((1.0 - mfBorder) * 0.5); + double fLeft(0.5 - fHalfBorder); + double fTop(0.5 - fHalfBorder); + double fRight(0.5 + fHalfBorder); + double fBottom(0.5 + fHalfBorder); + double fIncrementX, fIncrementY; + + if(maGradientInfo.mfAspectRatio > 1.0) + { + const double fWidth(fRight - fLeft); + const double fHalfAspectExpansion(((maGradientInfo.mfAspectRatio - 1.0) * 0.5) * fWidth); + fTop -= fHalfAspectExpansion; + fBottom += fHalfAspectExpansion; + fIncrementX = fWidth / (double)(maGradientInfo.mnSteps * 2L); + fIncrementY = fIncrementX * maGradientInfo.mfAspectRatio; + } + else + { + const double fHeight(fBottom - fTop); + const double fHalfAspectExpansion((((1.0 / maGradientInfo.mfAspectRatio) - 1.0) * 0.5) * fHeight); + fLeft -= fHalfAspectExpansion; + fRight += fHalfAspectExpansion; + fIncrementY = fHeight / (double)(maGradientInfo.mnSteps * 2L); + fIncrementX = fIncrementY / maGradientInfo.mfAspectRatio; + } + + for(sal_uInt32 a(1L); a < maGradientInfo.mnSteps; a++) + { + // next step + fLeft += fIncrementX; + fRight -= fIncrementX; + fTop += fIncrementY; + fBottom -= fIncrementY; + + // create matrix + const basegfx::B2DRange aRect(fLeft, fTop, fRight, fBottom); + impAppendMatrix(rMatrices, aRect); + } + } + } + + void GeoTexSvxGradientSquare::appendColors(::std::vector< basegfx::BColor >& rColors) + { + impAppendColorsRadial(rColors); + } + + void GeoTexSvxGradientSquare::modifyBColor(const basegfx::B2DPoint& rUV, basegfx::BColor& rBColor, double& /*rfOpacity*/) const + { + const double fScaler(basegfx::tools::getSquareGradientAlpha(rUV, maGradientInfo)); + + rBColor = (maStart * (1.0 - fScaler)) + (maEnd * fScaler); + } + } // end of namespace texture +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace texture + { + GeoTexSvxGradientRect::GeoTexSvxGradientRect(const basegfx::B2DRange& rTargetRange, const basegfx::BColor& rStart, const basegfx::BColor& rEnd, sal_uInt32 nSteps, double fBorder, double fOffsetX, double fOffsetY, double fAngle) + : GeoTexSvxGradient(rTargetRange, rStart, rEnd, nSteps, fBorder) + { + basegfx::tools::createRectangularODFGradientInfo(maGradientInfo, + rTargetRange, + basegfx::B2DVector(fOffsetX,fOffsetY), + nSteps, + fBorder, + fAngle); + } + + GeoTexSvxGradientRect::~GeoTexSvxGradientRect() + { + } + + void GeoTexSvxGradientRect::appendTransformations(::std::vector< basegfx::B2DHomMatrix >& rMatrices) + { + if(maGradientInfo.mnSteps) + { + const double fHalfBorder((1.0 - mfBorder) * 0.5); + double fLeft(0.5 - fHalfBorder); + double fTop(0.5 - fHalfBorder); + double fRight(0.5 + fHalfBorder); + double fBottom(0.5 + fHalfBorder); + double fIncrementX, fIncrementY; + + if(maGradientInfo.mfAspectRatio > 1.0) + { + fIncrementY = (fBottom - fTop) / (double)(maGradientInfo.mnSteps * 2L); + fIncrementX = fIncrementY / maGradientInfo.mfAspectRatio; + } + else + { + fIncrementX = (fRight - fLeft) / (double)(maGradientInfo.mnSteps * 2L); + fIncrementY = fIncrementX * maGradientInfo.mfAspectRatio; + } + + for(sal_uInt32 a(1L); a < maGradientInfo.mnSteps; a++) + { + // next step + fLeft += fIncrementX; + fRight -= fIncrementX; + fTop += fIncrementY; + fBottom -= fIncrementY; + + // create matrix + const basegfx::B2DRange aRect(fLeft, fTop, fRight, fBottom); + impAppendMatrix(rMatrices, aRect); + } + } + } + + void GeoTexSvxGradientRect::appendColors(::std::vector< basegfx::BColor >& rColors) + { + impAppendColorsRadial(rColors); + } + + void GeoTexSvxGradientRect::modifyBColor(const basegfx::B2DPoint& rUV, basegfx::BColor& rBColor, double& /*rfOpacity*/) const + { + const double fScaler(basegfx::tools::getRectangularGradientAlpha(rUV, maGradientInfo)); + + rBColor = (maStart * (1.0 - fScaler)) + (maEnd * fScaler); + } + } // end of namespace texture +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace texture + { + GeoTexSvxHatch::GeoTexSvxHatch(const basegfx::B2DRange& rTargetRange, double fDistance, double fAngle) + : mfDistance(0.1), + mfAngle(fAngle), + mnSteps(10L) + { + double fTargetSizeX(rTargetRange.getWidth()); + double fTargetSizeY(rTargetRange.getHeight()); + double fTargetOffsetX(rTargetRange.getMinX()); + double fTargetOffsetY(rTargetRange.getMinY()); + + // add object expansion + if(0.0 != fAngle) + { + const double fAbsCos(fabs(cos(fAngle))); + const double fAbsSin(fabs(sin(fAngle))); + const double fNewX(fTargetSizeX * fAbsCos + fTargetSizeY * fAbsSin); + const double fNewY(fTargetSizeY * fAbsCos + fTargetSizeX * fAbsSin); + fTargetOffsetX -= (fNewX - fTargetSizeX) / 2.0; + fTargetOffsetY -= (fNewY - fTargetSizeY) / 2.0; + fTargetSizeX = fNewX; + fTargetSizeY = fNewY; + } + + // add object scale before rotate + maTextureTransform.scale(fTargetSizeX, fTargetSizeY); + + // add texture rotate after scale to keep perpendicular angles + if(0.0 != fAngle) + { + basegfx::B2DPoint aCenter(0.5, 0.5); + aCenter *= maTextureTransform; + + maTextureTransform.translate(-aCenter.getX(), -aCenter.getY()); + maTextureTransform.rotate(fAngle); + maTextureTransform.translate(aCenter.getX(), aCenter.getY()); + } + + // add object translate + maTextureTransform.translate(fTargetOffsetX, fTargetOffsetY); + + // prepare height for texture + const double fSteps((0.0 != fDistance) ? fTargetSizeY / fDistance : 10.0); + mnSteps = basegfx::fround(fSteps + 0.5); + mfDistance = 1.0 / fSteps; + + // build transform from u,v to [0.0 .. 1.0]. As base, use inverse texture transform + maBackTextureTransform = maTextureTransform; + maBackTextureTransform.invert(); + } + + GeoTexSvxHatch::~GeoTexSvxHatch() + { + } + + bool GeoTexSvxHatch::operator==(const GeoTexSvx& rGeoTexSvx) const + { + const GeoTexSvxHatch* pCompare = dynamic_cast< const GeoTexSvxHatch* >(&rGeoTexSvx); + return (pCompare + && maTextureTransform == pCompare->maTextureTransform + && mfDistance == pCompare->mfDistance + && mfAngle == pCompare->mfAngle + && mnSteps == pCompare->mnSteps); + } + + void GeoTexSvxHatch::appendTransformations(::std::vector< basegfx::B2DHomMatrix >& rMatrices) + { + for(sal_uInt32 a(1L); a < mnSteps; a++) + { + // create matrix + const double fOffset(mfDistance * (double)a); + basegfx::B2DHomMatrix aNew; + aNew.set(1, 2, fOffset); + rMatrices.push_back(maTextureTransform * aNew); + } + } + + double GeoTexSvxHatch::getDistanceToHatch(const basegfx::B2DPoint& rUV) const + { + const basegfx::B2DPoint aCoor(maBackTextureTransform * rUV); + return fmod(aCoor.getY(), mfDistance); + } + } // end of namespace texture +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace texture + { + GeoTexSvxTiled::GeoTexSvxTiled(const basegfx::B2DPoint& rTopLeft, const basegfx::B2DVector& rSize) + : maTopLeft(rTopLeft), + maSize(rSize) + { + if(basegfx::fTools::lessOrEqual(maSize.getX(), 0.0)) + { + maSize.setX(1.0); + } + + if(basegfx::fTools::lessOrEqual(maSize.getY(), 0.0)) + { + maSize.setY(1.0); + } + } + + GeoTexSvxTiled::~GeoTexSvxTiled() + { + } + + bool GeoTexSvxTiled::operator==(const GeoTexSvx& rGeoTexSvx) const + { + const GeoTexSvxTiled* pCompare = dynamic_cast< const GeoTexSvxTiled* >(&rGeoTexSvx); + return (pCompare + && maTopLeft == pCompare->maTopLeft + && maSize == pCompare->maSize); + } + + void GeoTexSvxTiled::appendTransformations(::std::vector< basegfx::B2DHomMatrix >& rMatrices) + { + double fStartX(maTopLeft.getX()); + double fStartY(maTopLeft.getY()); + + if(basegfx::fTools::more(fStartX, 0.0)) + { + fStartX -= (floor(fStartX / maSize.getX()) + 1.0) * maSize.getX(); + } + + if(basegfx::fTools::less(fStartX + maSize.getX(), 0.0)) + { + fStartX += floor(-fStartX / maSize.getX()) * maSize.getX(); + } + + if(basegfx::fTools::more(fStartY, 0.0)) + { + fStartY -= (floor(fStartY / maSize.getY()) + 1.0) * maSize.getY(); + } + + if(basegfx::fTools::less(fStartY + maSize.getY(), 0.0)) + { + fStartY += floor(-fStartY / maSize.getY()) * maSize.getY(); + } + + for(double fPosY(fStartY); basegfx::fTools::less(fPosY, 1.0); fPosY += maSize.getY()) + { + for(double fPosX(fStartX); basegfx::fTools::less(fPosX, 1.0); fPosX += maSize.getX()) + { + basegfx::B2DHomMatrix aNew; + + aNew.set(0, 0, maSize.getX()); + aNew.set(1, 1, maSize.getY()); + aNew.set(0, 2, fPosX); + aNew.set(1, 2, fPosY); + + rMatrices.push_back(aNew); + } + } + } + } // end of namespace texture +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/drawinglayer/source/texture/texture3d.cxx b/drawinglayer/source/texture/texture3d.cxx new file mode 100644 index 000000000000..0e103ad385c9 --- /dev/null +++ b/drawinglayer/source/texture/texture3d.cxx @@ -0,0 +1,271 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: texture3d.cxx,v $ + * + * $Revision: 1.2 $ + * + * last change: $Author: aw $ $Date: 2008-05-27 14:11:34 $ + * + * 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/texture/texture3d.hxx> +#include <vcl/bmpacc.hxx> +#include <drawinglayer/attribute/fillattribute.hxx> +#include <drawinglayer/primitive3d/hatchtextureprimitive3d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace texture + { + GeoTexSvxMono::GeoTexSvxMono(const basegfx::BColor& rSingleColor, double fOpacity) + : maSingleColor(rSingleColor), + mfOpacity(fOpacity) + { + } + + bool GeoTexSvxMono::operator==(const GeoTexSvx& rGeoTexSvx) const + { + const GeoTexSvxMono* pCompare = dynamic_cast< const GeoTexSvxMono* >(&rGeoTexSvx); + return (pCompare + && maSingleColor == pCompare->maSingleColor + && mfOpacity == pCompare->mfOpacity); + } + + void GeoTexSvxMono::modifyBColor(const basegfx::B2DPoint& /*rUV*/, basegfx::BColor& rBColor, double& /*rfOpacity*/) const + { + rBColor = maSingleColor; + } + + void GeoTexSvxMono::modifyOpacity(const basegfx::B2DPoint& /*rUV*/, double& rfOpacity) const + { + rfOpacity = mfOpacity; + } + } // end of namespace texture +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace texture + { + GeoTexSvxBitmap::GeoTexSvxBitmap(const Bitmap& rBitmap, const basegfx::B2DPoint& rTopLeft, const basegfx::B2DVector& rSize) + : maBitmap(rBitmap), + mpRead(0L), + maTopLeft(rTopLeft), + maSize(rSize), + mfMulX(0.0), + mfMulY(0.0) + { + mpRead = maBitmap.AcquireReadAccess(); + OSL_ENSURE(mpRead, "GeoTexSvxBitmap: Got no read access to Bitmap (!)"); + mfMulX = (double)mpRead->Width() / maSize.getX(); + mfMulY = (double)mpRead->Height() / maSize.getY(); + } + + GeoTexSvxBitmap::~GeoTexSvxBitmap() + { + delete mpRead; + } + + bool GeoTexSvxBitmap::impIsValid(const basegfx::B2DPoint& rUV, sal_Int32& rX, sal_Int32& rY) const + { + if(mpRead) + { + rX = (sal_Int32)((rUV.getX() - maTopLeft.getX()) * mfMulX); + + if(rX >= 0L && rX < mpRead->Width()) + { + rY = (sal_Int32)((rUV.getY() - maTopLeft.getY()) * mfMulY); + + return (rY >= 0L && rY < mpRead->Height()); + } + } + + return false; + } + + void GeoTexSvxBitmap::modifyBColor(const basegfx::B2DPoint& rUV, basegfx::BColor& rBColor, double& rfOpacity) const + { + sal_Int32 nX, nY; + + if(impIsValid(rUV, nX, nY)) + { + const double fConvertColor(1.0 / 255.0); + const BitmapColor aBMCol(mpRead->GetColor(nY, nX)); + const basegfx::BColor aBSource( + (double)aBMCol.GetRed() * fConvertColor, + (double)aBMCol.GetGreen() * fConvertColor, + (double)aBMCol.GetBlue() * fConvertColor); + + rBColor = aBSource; + } + else + { + rfOpacity = 0.0; + } + } + + void GeoTexSvxBitmap::modifyOpacity(const basegfx::B2DPoint& rUV, double& rfOpacity) const + { + sal_Int32 nX, nY; + + if(impIsValid(rUV, nX, nY)) + { + const BitmapColor aBMCol(mpRead->GetColor(nY, nX)); + const Color aColor(aBMCol.GetRed(), aBMCol.GetGreen(), aBMCol.GetBlue()); + + rfOpacity = ((double)(0xff - aColor.GetLuminance()) * (1.0 / 255.0)); + } + else + { + rfOpacity = 0.0; + } + } + } // end of namespace texture +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace texture + { + GeoTexSvxBitmapTiled::GeoTexSvxBitmapTiled(const Bitmap& rBitmap, const basegfx::B2DPoint& rTopLeft, const basegfx::B2DVector& rSize) + : GeoTexSvxBitmap(rBitmap, rTopLeft, rSize) + { + } + + void GeoTexSvxBitmapTiled::modifyBColor(const basegfx::B2DPoint& rUV, basegfx::BColor& rBColor, double& rfOpacity) const + { + if(mpRead) + { + GeoTexSvxBitmap::modifyBColor(impGetCorrected(rUV), rBColor, rfOpacity); + } + } + + void GeoTexSvxBitmapTiled::modifyOpacity(const basegfx::B2DPoint& rUV, double& rfOpacity) const + { + if(mpRead) + { + GeoTexSvxBitmap::modifyOpacity(impGetCorrected(rUV), rfOpacity); + } + } + } // end of namespace texture +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace texture + { + GeoTexSvxMultiHatch::GeoTexSvxMultiHatch(const primitive3d::HatchTexturePrimitive3D& rPrimitive, double fLogicPixelSize) + : mfLogicPixelSize(fLogicPixelSize), + mp0(0L), + mp1(0L), + mp2(0L) + { + const attribute::FillHatchAttribute& rHatch(rPrimitive.getHatch()); + const basegfx::B2DRange aOutlineRange(0.0, 0.0, rPrimitive.getTextureSize().getX(), rPrimitive.getTextureSize().getY()); + const double fAngleA(-rHatch.getAngle()); + maColor = rHatch.getColor(); + mbFillBackground = rHatch.isFillBackground(); + mp0 = new GeoTexSvxHatch(aOutlineRange, rHatch.getDistance(), fAngleA); + + if(attribute::HATCHSTYLE_DOUBLE == rHatch.getStyle() || attribute::HATCHSTYLE_TRIPLE == rHatch.getStyle()) + { + mp1 = new GeoTexSvxHatch(aOutlineRange, rHatch.getDistance(), fAngleA + F_PI2); + } + + if(attribute::HATCHSTYLE_TRIPLE == rHatch.getStyle()) + { + mp2 = new GeoTexSvxHatch(aOutlineRange, rHatch.getDistance(), fAngleA + F_PI4); + } + } + + GeoTexSvxMultiHatch::~GeoTexSvxMultiHatch() + { + delete mp0; + delete mp1; + delete mp2; + } + + bool GeoTexSvxMultiHatch::impIsOnHatch(const basegfx::B2DPoint& rUV) const + { + if(mp0->getDistanceToHatch(rUV) < mfLogicPixelSize) + { + return true; + } + + if(mp1 && mp1->getDistanceToHatch(rUV) < mfLogicPixelSize) + { + return true; + } + + if(mp2 && mp2->getDistanceToHatch(rUV) < mfLogicPixelSize) + { + return true; + } + + return false; + } + + void GeoTexSvxMultiHatch::modifyBColor(const basegfx::B2DPoint& rUV, basegfx::BColor& rBColor, double& rfOpacity) const + { + if(impIsOnHatch(rUV)) + { + rBColor = maColor; + } + else if(!mbFillBackground) + { + rfOpacity = 0.0; + } + } + + void GeoTexSvxMultiHatch::modifyOpacity(const basegfx::B2DPoint& rUV, double& rfOpacity) const + { + if(mbFillBackground || impIsOnHatch(rUV)) + { + rfOpacity = 1.0; + } + else + { + rfOpacity = 0.0; + } + } + } // end of namespace texture +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof |