diff options
Diffstat (limited to 'drawinglayer/source')
21 files changed, 1358 insertions, 215 deletions
diff --git a/drawinglayer/source/attribute/sdrallattribute3d.cxx b/drawinglayer/source/attribute/sdrallattribute3d.cxx index 44875dda2d19..264d8d0432d1 100644 --- a/drawinglayer/source/attribute/sdrallattribute3d.cxx +++ b/drawinglayer/source/attribute/sdrallattribute3d.cxx @@ -64,17 +64,15 @@ namespace drawinglayer { } - SdrLineFillShadowAttribute::SdrLineFillShadowAttribute(const SdrLineFillShadowAttribute& rCandidate) - : mpShadow(0L), - mpLine(0L), - mpLineStartEnd(0L), - mpFill(0L), - mpFillFloatTransGradient(0L) + SdrLineFillShadowAttribute::SdrLineFillShadowAttribute( + const SdrLineFillShadowAttribute& rCandidate) + : mpShadow(0), + mpLine(0), + mpLineStartEnd(0), + mpFill(0), + mpFillFloatTransGradient(0) { - if(!(*this == rCandidate)) - { - *this = rCandidate; - } + *this = rCandidate; } SdrLineFillShadowAttribute::~SdrLineFillShadowAttribute() @@ -91,14 +89,14 @@ namespace drawinglayer // handle mpShadow { // delete local mpShadow if necessary - if(mpShadow && ((!rCandidate.mpShadow) || (!(*mpShadow == *rCandidate.mpShadow)))) + if(mpShadow) { delete mpShadow; - mpShadow = 0L; + mpShadow = 0; } // copy mpShadow if necessary - if(!mpShadow && rCandidate.mpShadow) + if(rCandidate.mpShadow) { mpShadow = new SdrShadowAttribute(*rCandidate.mpShadow); } @@ -107,14 +105,14 @@ namespace drawinglayer // handle mpLine { // delete local mpLine if necessary - if(mpLine && ((!rCandidate.mpLine) || (!(*mpLine == *rCandidate.mpLine)))) + if(mpLine) { delete mpLine; - mpLine = 0L; + mpLine = 0; } // copy mpLine if necessary - if(!mpLine && rCandidate.mpLine) + if(rCandidate.mpLine) { mpLine = new SdrLineAttribute(*rCandidate.mpLine); } @@ -123,14 +121,14 @@ namespace drawinglayer // handle mpLineStartEnd { // delete local mpLineStartEnd if necessary - if(mpLineStartEnd && ((!rCandidate.mpLineStartEnd) || (!(*mpLineStartEnd == *rCandidate.mpLineStartEnd)))) + if(mpLineStartEnd) { delete mpLineStartEnd; - mpLineStartEnd = 0L; + mpLineStartEnd = 0; } // copy mpLineStartEnd if necessary - if(!mpLineStartEnd && rCandidate.mpLineStartEnd) + if(rCandidate.mpLineStartEnd) { mpLineStartEnd = new SdrLineStartEndAttribute(*rCandidate.mpLineStartEnd); } @@ -139,14 +137,14 @@ namespace drawinglayer // handle mpFill { // delete local mpFill if necessary - if(mpFill && ((!rCandidate.mpFill) || (!(*mpFill == *rCandidate.mpFill)))) + if(mpFill) { delete mpFill; - mpFill = 0L; + mpFill = 0; } // copy mpFill if necessary - if(!mpFill && rCandidate.mpFill) + if(rCandidate.mpFill) { mpFill = new SdrFillAttribute(*rCandidate.mpFill); } @@ -155,14 +153,14 @@ namespace drawinglayer // handle mpFillFloatTransGradient { // delete local mpFillFloatTransGradient if necessary - if(mpFillFloatTransGradient && ((!rCandidate.mpFillFloatTransGradient) || (!(*mpFillFloatTransGradient == *rCandidate.mpFillFloatTransGradient)))) + if(mpFillFloatTransGradient) { delete mpFillFloatTransGradient; - mpFillFloatTransGradient = 0L; + mpFillFloatTransGradient = 0; } // copy mpFillFloatTransGradient if necessary - if(!mpFillFloatTransGradient && rCandidate.mpFillFloatTransGradient) + if(rCandidate.mpFillFloatTransGradient) { mpFillFloatTransGradient = new FillGradientAttribute(*rCandidate.mpFillFloatTransGradient); } diff --git a/drawinglayer/source/primitive2d/chartprimitive2d.cxx b/drawinglayer/source/primitive2d/chartprimitive2d.cxx index 6086b54000a1..3df6464f8aeb 100644 --- a/drawinglayer/source/primitive2d/chartprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/chartprimitive2d.cxx @@ -76,6 +76,13 @@ namespace drawinglayer // 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 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 index b909d0fde9f5..e10d1ddbcc71 100644 --- a/drawinglayer/source/primitive2d/makefile.mk +++ b/drawinglayer/source/primitive2d/makefile.mk @@ -62,6 +62,7 @@ SLOFILES= \ $(SLO)$/groupprimitive2d.obj \ $(SLO)$/helplineprimitive2d.obj \ $(SLO)$/hittestprimitive2d.obj \ + $(SLO)$/invertprimitive2d.obj \ $(SLO)$/markerarrayprimitive2d.obj \ $(SLO)$/pointarrayprimitive2d.obj \ $(SLO)$/maskprimitive2d.obj \ @@ -71,6 +72,7 @@ SLOFILES= \ $(SLO)$/pagepreviewprimitive2d.obj \ $(SLO)$/polypolygonprimitive2d.obj \ $(SLO)$/polygonprimitive2d.obj \ + $(SLO)$/primitivetools2d.obj \ $(SLO)$/sceneprimitive2d.obj \ $(SLO)$/shadowprimitive2d.obj \ $(SLO)$/structuretagprimitive2d.obj \ diff --git a/drawinglayer/source/primitive2d/polygonprimitive2d.cxx b/drawinglayer/source/primitive2d/polygonprimitive2d.cxx index a795e84ed433..b5212da54688 100644 --- a/drawinglayer/source/primitive2d/polygonprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/polygonprimitive2d.cxx @@ -116,7 +116,7 @@ namespace drawinglayer const basegfx::B2DVector aDashVector(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(getDiscreteDashLength(), 0.0)); const double fLogicDashLength(aDashVector.getX()); - if(fLogicDashLength > 0.0) + if(fLogicDashLength > 0.0 && !getRGBColorA().equal(getRGBColorB())) { // apply dashing; get line and gap snippets ::std::vector< double > aDash; @@ -239,17 +239,19 @@ namespace drawinglayer { 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(getB2DPolygon()); + aHairLinePolyPolygon.append(aB2DPolygon); } else { // apply LineStyle - basegfx::tools::applyLineDashing(getB2DPolygon(), getStrokeAttribute().getDotDashArray(), &aHairLinePolyPolygon, 0, getStrokeAttribute().getFullDotDashLen()); + basegfx::tools::applyLineDashing(aB2DPolygon, getStrokeAttribute().getDotDashArray(), &aHairLinePolyPolygon, 0, getStrokeAttribute().getFullDotDashLen()); } const sal_uInt32 nCount(aHairLinePolyPolygon.count()); @@ -263,12 +265,9 @@ namespace drawinglayer for(sal_uInt32 a(0L); a < nCount; a++) { - // AW: New version of createAreaGeometry; now creates bezier polygons + // New version of createAreaGeometry; now creates bezier polygons aAreaPolyPolygon.append(basegfx::tools::createAreaGeometry( aHairLinePolyPolygon.getB2DPolygon(a), fHalfLineWidth, aLineJoin)); - //const basegfx::B2DPolyPolygon aNewPolyPolygon(basegfx::tools::createAreaGeometryForPolygon( - // aHairLinePolyPolygon.getB2DPolygon(a), fHalfLineWidth, aLineJoin, fMiterMinimumAngle)); - //aAreaPolyPolygon.append(aNewPolyPolygon); } // prepare return value 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 index 73d26a71fa4c..f52af2da6a6d 100644 --- a/drawinglayer/source/primitive2d/sceneprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/sceneprimitive2d.cxx @@ -363,11 +363,13 @@ namespace drawinglayer basegfx::B2DRange aDiscreteRange; basegfx::B2DRange aUnitVisibleRange; bool bNeedNewDecomposition(false); + bool bDiscreteSizesAreCalculated(false); if(getLocalDecomposition().hasElements()) { basegfx::B2DRange aVisibleDiscreteRange; calculateDsicreteSizes(rViewInformation, aDiscreteRange, aVisibleDiscreteRange, aUnitVisibleRange); + bDiscreteSizesAreCalculated = true; // display has changed and cannot be reused when resolution did change if(!basegfx::fTools::equal(aDiscreteRange.getWidth(), mfOldDiscreteSizeX) || @@ -395,6 +397,12 @@ namespace drawinglayer if(!getLocalDecomposition().hasElements()) { + if(!bDiscreteSizesAreCalculated) + { + basegfx::B2DRange aVisibleDiscreteRange; + calculateDsicreteSizes(rViewInformation, aDiscreteRange, aVisibleDiscreteRange, aUnitVisibleRange); + } + // remember last used NewDiscreteSize and NewUnitVisiblePart ScenePrimitive2D* pThat = const_cast< ScenePrimitive2D* >(this); pThat->mfOldDiscreteSizeX = aDiscreteRange.getWidth(); diff --git a/drawinglayer/source/primitive2d/textdecoratedprimitive2d.cxx b/drawinglayer/source/primitive2d/textdecoratedprimitive2d.cxx index 4faa85fe898c..94e92a149e50 100644 --- a/drawinglayer/source/primitive2d/textdecoratedprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/textdecoratedprimitive2d.cxx @@ -305,7 +305,7 @@ namespace drawinglayer // 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()); + aTextLayouter.setFontAttributes(getFontAttributes(), rDecTrans.getScale().getX(), rDecTrans.getScale().getY(), getLocale()); // get text width double fTextWidth(0.0); @@ -526,7 +526,7 @@ namespace drawinglayer if(bNoDXArray) { // ..but only completely when no DXArray - aTextLayouter.setFontAttributes(getFontAttributes(), rDecTrans.getScale().getX(), rDecTrans.getScale().getY()); + aTextLayouter.setFontAttributes(getFontAttributes(), rDecTrans.getScale().getX(), rDecTrans.getScale().getY(),getLocale()); } // do iterate over single words diff --git a/drawinglayer/source/primitive2d/textlayoutdevice.cxx b/drawinglayer/source/primitive2d/textlayoutdevice.cxx index b8f7d59e6f05..0055af3ea4bd 100644 --- a/drawinglayer/source/primitive2d/textlayoutdevice.cxx +++ b/drawinglayer/source/primitive2d/textlayoutdevice.cxx @@ -41,6 +41,7 @@ #include <vcl/virdev.hxx> #include <vcl/font.hxx> #include <vcl/metric.hxx> +#include <i18npool/mslangid.hxx> #include <drawinglayer/primitive2d/textprimitive2d.hxx> ////////////////////////////////////////////////////////////////////////////// @@ -165,14 +166,14 @@ namespace drawinglayer mrDevice.SetFont( rFont ); } - void TextLayouterDevice::setFontAttributes(const FontAttributes& rFontAttributes, const basegfx::B2DHomMatrix& rTransform) + void TextLayouterDevice::setFontAttributes(const FontAttributes& rFontAttributes, const basegfx::B2DHomMatrix& rTransform, const ::com::sun::star::lang::Locale & rLocale) { - setFont(getVclFontFromFontAttributes(rFontAttributes, rTransform, mrDevice)); + setFont(getVclFontFromFontAttributes(rFontAttributes, rTransform, rLocale, mrDevice)); } - void TextLayouterDevice::setFontAttributes(const FontAttributes& rFontAttributes, double fFontScaleX, double fFontScaleY) + void TextLayouterDevice::setFontAttributes(const FontAttributes& rFontAttributes, double fFontScaleX, double fFontScaleY, const ::com::sun::star::lang::Locale & rLocale) { - setFont(getVclFontFromFontAttributes(rFontAttributes, fFontScaleX, fFontScaleY, 0.0, mrDevice)); + setFont(getVclFontFromFontAttributes(rFontAttributes, fFontScaleX, fFontScaleY, 0.0, rLocale, mrDevice)); } double TextLayouterDevice::getOverlineOffset() const @@ -239,8 +240,25 @@ namespace drawinglayer basegfx::B2DPolyPolygonVector& rB2DPolyPolyVector, const String& rText, xub_StrLen nIndex, - xub_StrLen nLength) + xub_StrLen nLength, + // #i89784# added suppirt for DXArray for justified text + const ::std::vector< double >& rDXArray, + double fFontScaleWidth) { + std::vector< sal_Int32 > aTransformedDXArray; + const sal_uInt32 nDXArraySize(rDXArray.size()); + + if(nDXArraySize && basegfx::fTools::more(fFontScaleWidth, 0.0)) + { + OSL_ENSURE(nDXArraySize == nLength, "DXArray size does not correspond to text portion size (!)"); + aTransformedDXArray.reserve(nDXArraySize); + + for(std::vector< double >::const_iterator aStart(rDXArray.begin()); aStart != rDXArray.end(); aStart++) + { + aTransformedDXArray.push_back(basegfx::fround((*aStart) * fFontScaleWidth)); + } + } + return mrDevice.GetTextOutlines( rB2DPolyPolyVector, rText, @@ -249,7 +267,7 @@ namespace drawinglayer nLength, true, 0, - 0); + nDXArraySize ? &(aTransformedDXArray[0]) : 0); } basegfx::B2DRange TextLayouterDevice::getTextBoundRect( @@ -268,12 +286,14 @@ namespace drawinglayer nIndex, nLength); - return basegfx::B2DRange(aRect.Left(), aRect.Top(), aRect.Right(), aRect.Bottom()); - } - else - { - return basegfx::B2DRange(); + // #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 @@ -288,6 +308,7 @@ namespace drawinglayer Font getVclFontFromFontAttributes( const FontAttributes& rFontAttributes, const basegfx::B2DHomMatrix& rTransform, + const ::com::sun::star::lang::Locale & rLocale, const OutputDevice& rOutDev) { // decompose matrix to have position and size of text @@ -296,7 +317,7 @@ namespace drawinglayer rTransform.decompose(aScale, aTranslate, fRotate, fShearX); - return getVclFontFromFontAttributes(rFontAttributes, aScale.getX(), aScale.getY(), fRotate, rOutDev); + return getVclFontFromFontAttributes(rFontAttributes, aScale.getX(), aScale.getY(), fRotate, rLocale, rOutDev); } Font getVclFontFromFontAttributes( @@ -304,6 +325,7 @@ namespace drawinglayer double fFontScaleX, double fFontScaleY, double fFontRotation, + const ::com::sun::star::lang::Locale & rLocale, const OutputDevice& /*rOutDev*/) { sal_uInt32 nWidth(basegfx::fround(fabs(fFontScaleX))); @@ -323,6 +345,7 @@ namespace drawinglayer 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 // #100424# use higher precision diff --git a/drawinglayer/source/primitive2d/textprimitive2d.cxx b/drawinglayer/source/primitive2d/textprimitive2d.cxx index bf46f4ab21d0..7c62c235c21d 100644 --- a/drawinglayer/source/primitive2d/textprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/textprimitive2d.cxx @@ -145,17 +145,25 @@ namespace drawinglayer // prepare textlayoutdevice TextLayouterDevice aTextLayouter; - aTextLayouter.setFontAttributes(getFontAttributes(), aFontScale.getX(), aFontScale.getY()); + aTextLayouter.setFontAttributes(getFontAttributes(), aFontScale.getX(), aFontScale.getY(), getLocale()); #ifdef WIN32 // when under Windows and the font is unequally scaled, need to correct font X-Scaling factor if(bCorrectScale) { - aScale.setX(aScale.getX() * aTextLayouter.getCurrentFontRelation()); + const double fFontRelation(aTextLayouter.getCurrentFontRelation()); + aScale.setX(aScale.getX() * fFontRelation); + aFontScale.setX(aFontScale.getX() / fFontRelation); } #endif // get the text outlines. No DXArray is given (would contain integers equal to unit vector // transformed by object's transformation), let VCL do the job - aTextLayouter.getTextOutlines(rTarget, getText(), getTextPosition(), getTextLength()); + aTextLayouter.getTextOutlines( + rTarget, getText(), + getTextPosition(), + getTextLength(), + // #i89784# added support for DXArray for justified text + getDXArray(), + aFontScale.getX()); // create primitives for the outlines const sal_uInt32 nCount(rTarget.size()); @@ -300,30 +308,35 @@ namespace drawinglayer // prepare textlayoutdevice TextLayouterDevice aTextLayouter; - aTextLayouter.setFontAttributes(getFontAttributes(), aFontScale.getX(), aFontScale.getY()); + aTextLayouter.setFontAttributes(getFontAttributes(), aFontScale.getX(), aFontScale.getY(), getLocale()); // get basic text range basegfx::B2DRange aNewRange(aTextLayouter.getTextBoundRect(getText(), getTextPosition(), getTextLength())); -#ifdef WIN32 - // when under Windows and the font is unequally scaled, need to correct font X-Scaling factor - if(bCorrectScale) + + // #i102556# take empty results into account + if(!aNewRange.isEmpty()) { - aScale.setX(aScale.getX() * aTextLayouter.getCurrentFontRelation()); - } +#ifdef WIN32 + // when under Windows and the font is unequally scaled, need to correct font X-Scaling factor + if(bCorrectScale) + { + aScale.setX(aScale.getX() * aTextLayouter.getCurrentFontRelation()); + } #endif - // prepare object transformation for range - basegfx::B2DHomMatrix aRangeTransformation; + // 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()); + 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); + // apply range transformation to it + aNewRange.transform(aRangeTransformation); - // assign to buffered value - const_cast< TextSimplePortionPrimitive2D* >(this)->maB2DRange = aNewRange; + // assign to buffered value + const_cast< TextSimplePortionPrimitive2D* >(this)->maB2DRange = aNewRange; + } } } diff --git a/drawinglayer/source/processor2d/canvasprocessor.cxx b/drawinglayer/source/processor2d/canvasprocessor.cxx index f4a8a7b5282d..a60162de6ee0 100644 --- a/drawinglayer/source/processor2d/canvasprocessor.cxx +++ b/drawinglayer/source/processor2d/canvasprocessor.cxx @@ -2106,7 +2106,10 @@ namespace drawinglayer mpOutputDevice->Push(PUSH_MAPMODE); mpOutputDevice->SetMapMode(maOriginalMapMode); - if(!renderChartPrimitive2D(rChartPrimitive, *mpOutputDevice)) + if(!renderChartPrimitive2D( + rChartPrimitive, + *mpOutputDevice, + getViewInformation2D())) { // fallback to decomposition (MetaFile) process(rChartPrimitive.get2DDecomposition(getViewInformation2D())); diff --git a/drawinglayer/source/processor2d/helperchartrenderer.cxx b/drawinglayer/source/processor2d/helperchartrenderer.cxx index c2d99604469b..ffa8917ddec8 100644 --- a/drawinglayer/source/processor2d/helperchartrenderer.cxx +++ b/drawinglayer/source/processor2d/helperchartrenderer.cxx @@ -41,6 +41,7 @@ #include <svtools/chartprettypainter.hxx> #include <com/sun/star/lang/XUnoTunnel.hpp> #include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <drawinglayer/geometry/viewinformation2d.hxx> ////////////////////////////////////////////////////////////////////////////// @@ -50,7 +51,10 @@ using namespace com::sun::star; namespace drawinglayer { - bool renderChartPrimitive2D(const primitive2d::ChartPrimitive2D& rChartCandidate, OutputDevice& rOutputDevice) + bool renderChartPrimitive2D( + const primitive2d::ChartPrimitive2D& rChartCandidate, + OutputDevice& rOutputDevice, + const geometry::ViewInformation2D& rViewInformation2D) { bool bChartRendered(false); @@ -73,14 +77,74 @@ namespace drawinglayer if( pPrettyPainter ) { - // create logic object range + // 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()); - bChartRendered = pPrettyPainter->DoPaint(&rOutputDevice, aRectangle); + // #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); + } } } } diff --git a/drawinglayer/source/processor2d/helperchartrenderer.hxx b/drawinglayer/source/processor2d/helperchartrenderer.hxx index de13431c79c0..4677698129c2 100644 --- a/drawinglayer/source/processor2d/helperchartrenderer.hxx +++ b/drawinglayer/source/processor2d/helperchartrenderer.hxx @@ -43,16 +43,21 @@ class OutputDevice; -namespace drawinglayer { namespace primitive2d { - class ChartPrimitive2D; -}} +namespace drawinglayer { namespace primitive2d { class ChartPrimitive2D; }} +namespace drawinglayer { namespace geometry { class ViewInformation2D; }} ////////////////////////////////////////////////////////////////////////////// // support chart PrettyPrinter usage from primitives namespace drawinglayer { - bool renderChartPrimitive2D(const primitive2d::ChartPrimitive2D& rChartCandidate, OutputDevice& rOutputDevice); + // #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 diff --git a/drawinglayer/source/processor2d/hittestprocessor2d.cxx b/drawinglayer/source/processor2d/hittestprocessor2d.cxx new file mode 100644 index 000000000000..8a2d732cbb2f --- /dev/null +++ b/drawinglayer/source/processor2d/hittestprocessor2d.cxx @@ -0,0 +1,451 @@ +/************************************************************************* + * + * 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> + +////////////////////////////////////////////////////////////////////////////// + +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::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()) + { + // 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(getViewInformation2D())); + + if(xExtracted2DSceneGeometry.hasElements()) + { + // proccess extracted 2D content + process(xExtracted2DSceneGeometry); + } + else + { + // empty 3D scene; Check for border hit + const basegfx::B2DRange aRange(rCandidate.getB2DRange(getViewInformation2D())); + basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(aRange)); + + mbHit = checkHairlineHitWithTolerance(aOutline, getDiscreteHitTolerance()); + } + } + + break; + } + case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D : + case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D : + case PRIMITIVE2D_ID_GRIDPRIMITIVE2D : + case PRIMITIVE2D_ID_HELPLINEPRIMITIVE2D : + { + // ignorable primitives + 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())); + 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())); + 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 index 89e0999d361d..5f0ab63ee1b3 100644 --- a/drawinglayer/source/processor2d/linegeometryextractor2d.cxx +++ b/drawinglayer/source/processor2d/linegeometryextractor2d.cxx @@ -86,7 +86,7 @@ namespace drawinglayer const primitive2d::PolygonHairlinePrimitive2D& rPolygonCandidate(static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate)); basegfx::B2DPolygon aLocalPolygon(rPolygonCandidate.getB2DPolygon()); aLocalPolygon.transform(getViewInformation2D().getObjectTransformation()); - maExtractedHairlines.append(aLocalPolygon); + maExtractedHairlines.push_back(aLocalPolygon); } break; } @@ -98,7 +98,7 @@ namespace drawinglayer const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate(static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate)); basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon()); aLocalPolyPolygon.transform(getViewInformation2D().getObjectTransformation()); - maExtractedLineFills.append(aLocalPolyPolygon); + maExtractedLineFills.push_back(aLocalPolyPolygon); } break; } diff --git a/drawinglayer/source/processor2d/makefile.mk b/drawinglayer/source/processor2d/makefile.mk index 38dcb42cd4a0..fcbf2413b61f 100644 --- a/drawinglayer/source/processor2d/makefile.mk +++ b/drawinglayer/source/processor2d/makefile.mk @@ -57,7 +57,9 @@ SLOFILES= \ $(SLO)$/vclmetafileprocessor2d.obj \ $(SLO)$/contourextractor2d.obj \ $(SLO)$/linegeometryextractor2d.obj \ - $(SLO)$/canvasprocessor.obj + $(SLO)$/canvasprocessor.obj \ + $(SLO)$/hittestprocessor2d.obj \ + $(SLO)$/textaspolygonextractor2d.obj # --- Targets ---------------------------------- 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/vclmetafileprocessor2d.cxx b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx index 172413105b1c..24f54d3ddc58 100644 --- a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx @@ -247,8 +247,8 @@ namespace drawinglayer if(rB2DPolygon.count() && !mnSvtGraphicStrokeCount) { basegfx::BColor aStrokeColor; - PolyPolygon aStartPolyPolygon; - PolyPolygon aEndPolyPolygon; + basegfx::B2DPolyPolygon aStartArrow; + basegfx::B2DPolyPolygon aEndArrow; if(pColor) { @@ -271,11 +271,9 @@ namespace drawinglayer { fPolyLength = basegfx::tools::getLength(rB2DPolygon); - const basegfx::B2DPolyPolygon aStartArrow(basegfx::tools::createAreaGeometryForLineStartEnd( + aStartArrow = basegfx::tools::createAreaGeometryForLineStartEnd( rB2DPolygon, pStart->getB2DPolyPolygon(), true, pStart->getWidth(), - fPolyLength, pStart->isCentered() ? 0.5 : 0.0, 0)); - - aStartPolyPolygon = PolyPolygon(aStartArrow); + fPolyLength, pStart->isCentered() ? 0.5 : 0.0, 0); } if(pEnd && pEnd->isActive()) @@ -285,11 +283,9 @@ namespace drawinglayer fPolyLength = basegfx::tools::getLength(rB2DPolygon); } - const basegfx::B2DPolyPolygon aEndArrow(basegfx::tools::createAreaGeometryForLineStartEnd( + aEndArrow = basegfx::tools::createAreaGeometryForLineStartEnd( rB2DPolygon, pEnd->getB2DPolyPolygon(), false, pEnd->getWidth(), - fPolyLength, pEnd->isCentered() ? 0.5 : 0.0, 0)); - - aEndPolyPolygon = PolyPolygon(aEndArrow); + fPolyLength, pEnd->isCentered() ? 0.5 : 0.0, 0); } } @@ -341,10 +337,23 @@ namespace drawinglayer 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(rB2DPolygon), - aStartPolyPolygon, - aEndPolyPolygon, + Polygon(aB2DPolygon), + PolyPolygon(aStartArrow), + PolyPolygon(aEndArrow), mfCurrentUnifiedTransparence, fLineWidth, SvtGraphicStroke::capButt, @@ -1001,7 +1010,68 @@ namespace drawinglayer adaptLineToFillDrawMode(); impStartSvtGraphicStroke(pSvtGraphicStroke); - process(rCandidate.get2DDecomposition(getViewInformation2D())); + + // #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); + + mrMetaFile.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 @@ -1623,7 +1693,10 @@ namespace drawinglayer // ChartPrimitive2D const primitive2d::ChartPrimitive2D& rChartPrimitive = static_cast< const primitive2d::ChartPrimitive2D& >(rCandidate); - if(!renderChartPrimitive2D(rChartPrimitive, *mpOutputDevice)) + if(!renderChartPrimitive2D( + rChartPrimitive, + *mpOutputDevice, + getViewInformation2D())) { // fallback to decomposition (MetaFile) process(rChartPrimitive.get2DDecomposition(getViewInformation2D())); diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx index 559974682463..8e2f89bb82a6 100644 --- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx @@ -64,6 +64,7 @@ #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> @@ -425,7 +426,10 @@ namespace drawinglayer mpOutputDevice->Push(PUSH_MAPMODE); mpOutputDevice->SetMapMode(maOriginalMapMode); - if(!renderChartPrimitive2D(rChartPrimitive, *mpOutputDevice)) + if(!renderChartPrimitive2D( + rChartPrimitive, + *mpOutputDevice, + getViewInformation2D())) { // fallback to decomposition (MetaFile) process(rChartPrimitive.get2DDecomposition(getViewInformation2D())); @@ -532,6 +536,28 @@ namespace drawinglayer // 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 diff --git a/drawinglayer/source/processor2d/vclprocessor2d.cxx b/drawinglayer/source/processor2d/vclprocessor2d.cxx index 08dba659a6a0..adc33c4d676d 100644 --- a/drawinglayer/source/processor2d/vclprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclprocessor2d.cxx @@ -189,6 +189,7 @@ namespace drawinglayer aScale.getY(), fRotate, + rTextCandidate.getLocale(), *mpOutputDevice)); if(!basegfx::fTools::equal(aScale.getX(), aScale.getY())) @@ -210,6 +211,7 @@ namespace drawinglayer aScale.getX(), aScale.getY(), fRotate, + rTextCandidate.getLocale(), *mpOutputDevice); } } @@ -680,6 +682,15 @@ namespace drawinglayer 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); @@ -713,8 +724,18 @@ namespace drawinglayer // rotation if(!basegfx::fTools::equalZero(fRotate)) { - double fRotation((fRotate / F_PI180) * -10.0); - aMetaFile.Rotate((sal_uInt16)(fRotation)); + // #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 @@ -1011,6 +1032,8 @@ namespace drawinglayer 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); @@ -1019,154 +1042,160 @@ namespace drawinglayer { const basegfx::B2DVector aDiscreteUnit(maCurrentTransformation * basegfx::B2DVector(fLineWidth, 0.0)); const double fDiscreteLineWidth(aDiscreteUnit.getLength()); - const bool bAntiAliased(getOptionsDrawinglayer().IsAntiAliasing()); - const double fAllowedUpperBound(bAntiAliased ? 3.0 : 2.5); + const attribute::StrokeAttribute& rStrokeAttribute = rPolygonStrokeCandidate.getStrokeAttribute(); + const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rLineAttribute.getColor())); + basegfx::B2DPolyPolygon aHairlinePolyPolygon; - if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth, fAllowedUpperBound)) - { - // force to hairline - const attribute::StrokeAttribute& rStrokeAttribute = rPolygonStrokeCandidate.getStrokeAttribute(); - const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rLineAttribute.getColor())); - basegfx::B2DPolyPolygon aHairlinePolyPolygon; + mpOutputDevice->SetLineColor(Color(aHairlineColor)); + mpOutputDevice->SetFillColor(); - 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()); + } - 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()); - const sal_uInt32 nCount(aHairlinePolyPolygon.count()); + if(nCount) + { + const bool bAntiAliased(getOptionsDrawinglayer().IsAntiAliasing()); + aHairlinePolyPolygon.transform(maCurrentTransformation); - if(nCount) + for(sal_uInt32 a(0); a < nCount; a++) { - aHairlinePolyPolygon.transform(maCurrentTransformation); + basegfx::B2DPolygon aCandidate(aHairlinePolyPolygon.getB2DPolygon(a)); if(bAntiAliased) { - for(sal_uInt32 a(0); a < nCount; a++) + if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth, 1.0)) { - basegfx::B2DPolygon aCandidate(aHairlinePolyPolygon.getB2DPolygon(a)); - - if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth, 1.0)) - { - // line in range ]0.0 .. 1.0[ - // paint as simple hairline - mpOutputDevice->DrawPolyLine(aCandidate, 0.0); - } - 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); - } - else - { - // 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); - } + // 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::more(fDiscreteLineWidth, 1.5)) + 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); - for(sal_uInt32 a(0); a < nCount; a++) - { - basegfx::B2DPolygon aCandidate(aHairlinePolyPolygon.getB2DPolygon(a)); - mpOutputDevice->DrawPolyLine(aCandidate, 0.0); - - aMat.set(0, 2, 1.0); - aMat.set(1, 2, 0.0); - aCandidate.transform(aMat); + aMat.set(0, 2, 1.0); + aMat.set(1, 2, 0.0); + aCandidate.transform(aMat); - mpOutputDevice->DrawPolyLine(aCandidate, 0.0); + mpOutputDevice->DrawPolyLine(aCandidate, 0.0); - aMat.set(0, 2, 0.0); - aMat.set(1, 2, 1.0); - aCandidate.transform(aMat); + aMat.set(0, 2, 0.0); + aMat.set(1, 2, 1.0); + aCandidate.transform(aMat); - mpOutputDevice->DrawPolyLine(aCandidate, 0.0); + mpOutputDevice->DrawPolyLine(aCandidate, 0.0); - aMat.set(0, 2, -1.0); - aMat.set(1, 2, 0.0); - aCandidate.transform(aMat); + aMat.set(0, 2, -1.0); + aMat.set(1, 2, 0.0); + aCandidate.transform(aMat); - mpOutputDevice->DrawPolyLine(aCandidate, 0.0); - } + mpOutputDevice->DrawPolyLine(aCandidate, 0.0); + bDone = true; } else { - for(sal_uInt32 a(0); a < nCount; a++) - { - // draw the basic hairline polygon - const basegfx::B2DPolygon aCandidate(aHairlinePolyPolygon.getB2DPolygon(a)); - mpOutputDevice->DrawPolyLine(aCandidate, 0.0); - } + // #i101491# line width is above 2.5 } } - } - bDone = true; + 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; + } + } } } diff --git a/drawinglayer/source/processor3d/zbufferprocessor3d.cxx b/drawinglayer/source/processor3d/zbufferprocessor3d.cxx index 24015903de4c..b5a59e10a119 100644 --- a/drawinglayer/source/processor3d/zbufferprocessor3d.cxx +++ b/drawinglayer/source/processor3d/zbufferprocessor3d.cxx @@ -141,6 +141,10 @@ namespace } 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; @@ -671,15 +675,25 @@ namespace drawinglayer { // step two: // - // bring from [0.0 .. 1.0] in X,Y and Z to view cordinates. also: - // - scale Z to [0.0 .. fMaxZDepth] - const double fMaxZDepth(double(0x0000ff00)); + // 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 |