diff options
author | Vladimir Glazounov <vg@openoffice.org> | 2008-08-19 22:15:32 +0000 |
---|---|---|
committer | Vladimir Glazounov <vg@openoffice.org> | 2008-08-19 22:15:32 +0000 |
commit | 3561a2267478ed25de17778cc5b76d0a95279adc (patch) | |
tree | 01062cafb0fc41703f393cda95336af27ebbc7a7 /svx/source/sdr | |
parent | 75ab68565b598d1dd9bcc860b7fbf1b1718abd85 (diff) |
INTEGRATION: CWS aw033 (1.1.2); FILE ADDED
2008/08/19 16:46:29 cl 1.1.2.9: fixed license files
2008/05/27 14:49:59 aw 1.1.2.8: #i39532# changes DEV300 m12 resync corrections
2008/04/04 06:07:50 aw 1.1.2.7: #i39532# added primitive support for tables
2008/02/07 14:13:23 aw 1.1.2.6: stable version from working GIT repository for unxlngi6 build
2007/11/19 11:26:07 aw 1.1.2.5: #i39532# Lot of changes to make polygon stuff bezier-able
2007/11/07 14:34:33 aw 1.1.2.4: #i39532# committing to have a base for HDU
2007/08/13 15:34:33 aw 1.1.2.3: #i39532# changes after resync
2007/03/06 12:39:31 aw 1.1.2.2: #i39532#
2006/10/19 10:57:53 aw 1.1.2.1: #i39532# primitive
Diffstat (limited to 'svx/source/sdr')
-rw-r--r-- | svx/source/sdr/primitive2d/sdrdecompositiontools.cxx | 439 |
1 files changed, 439 insertions, 0 deletions
diff --git a/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx b/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx new file mode 100644 index 0000000000..d488f27f62 --- /dev/null +++ b/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx @@ -0,0 +1,439 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: sdrdecompositiontools.cxx,v $ + * + * $Revision: 1.2 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <svx/sdr/primitive2d/sdrdecompositiontools.hxx> +#include <svx/sdr/attribute/sdrallattribute.hxx> +#include <drawinglayer/primitive2d/baseprimitive2d.hxx> +#include <drawinglayer/attribute/sdrattribute.hxx> +#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> +#include <drawinglayer/primitive2d/unifiedalphaprimitive2d.hxx> +#include <drawinglayer/primitive2d/alphaprimitive2d.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <drawinglayer/primitive2d/fillgradientprimitive2d.hxx> +#include <drawinglayer/attribute/strokeattribute.hxx> +#include <drawinglayer/attribute/linestartendattribute.hxx> +#include <drawinglayer/primitive2d/polygonprimitive2d.hxx> +#include <drawinglayer/attribute/sdrfillbitmapattribute.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <drawinglayer/primitive2d/shadowprimitive2d.hxx> +#include <svx/sdr/attribute/sdrtextattribute.hxx> +#include <svx/sdr/primitive2d/sdrtextprimitive2d.hxx> +#include <svx/svdotext.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <drawinglayer/primitive2d/animatedprimitive2d.hxx> +#include <drawinglayer/animation/animationtiming.hxx> +#include <drawinglayer/primitive2d/maskprimitive2d.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <drawinglayer/geometry/viewinformation2d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive2d + { + Primitive2DReference createPolyPolygonFillPrimitive( + const ::basegfx::B2DPolyPolygon& rUnitPolyPolygon, + const ::basegfx::B2DHomMatrix& rObjectTransform, + const attribute::SdrFillAttribute& rFill, + const attribute::FillGradientAttribute* pFillGradient) + { + // prepare fully scaled polygon + ::basegfx::B2DPolyPolygon aScaledPolyPolygon(rUnitPolyPolygon); + aScaledPolyPolygon.transform(rObjectTransform); + BasePrimitive2D* pNewFillPrimitive = 0L; + + if(rFill.isGradient()) + { + pNewFillPrimitive = new PolyPolygonGradientPrimitive2D(aScaledPolyPolygon, rFill.getColor(), *rFill.getGradient()); + } + else if(rFill.isHatch()) + { + pNewFillPrimitive = new PolyPolygonHatchPrimitive2D(aScaledPolyPolygon, rFill.getColor(), *rFill.getHatch()); + } + else if(rFill.isBitmap()) + { + const ::basegfx::B2DRange aRange(::basegfx::tools::getRange(aScaledPolyPolygon)); + pNewFillPrimitive = new PolyPolygonBitmapPrimitive2D(aScaledPolyPolygon, rFill.getColor(), rFill.getBitmap()->getFillBitmapAttribute(aRange)); + } + else + { + pNewFillPrimitive = new PolyPolygonColorPrimitive2D(aScaledPolyPolygon, rFill.getColor()); + } + + if(0.0 != rFill.getTransparence()) + { + // create simpleTransparencePrimitive, add created fill primitive + const Primitive2DReference xRefA(pNewFillPrimitive); + const Primitive2DSequence aContent(&xRefA, 1L); + return Primitive2DReference(new UnifiedAlphaPrimitive2D(aContent, rFill.getTransparence())); + } + else if(pFillGradient) + { + // create sequence with created fill primitive + const Primitive2DReference xRefA(pNewFillPrimitive); + const Primitive2DSequence aContent(&xRefA, 1L); + + // create FillGradientPrimitive2D for transparence and add to new sequence + // fillGradientPrimitive is enough here (compared to PolyPolygonGradientPrimitive2D) since float transparence will be masked anyways + const ::basegfx::B2DRange aRange(::basegfx::tools::getRange(aScaledPolyPolygon)); + const Primitive2DReference xRefB(new FillGradientPrimitive2D(aRange, *pFillGradient)); + const Primitive2DSequence aAlpha(&xRefB, 1L); + + // create AlphaPrimitive2D using alpha and content + return Primitive2DReference(new AlphaPrimitive2D(aContent, aAlpha)); + } + else + { + // add to decomposition + return Primitive2DReference(pNewFillPrimitive); + } + } + + Primitive2DReference createPolygonLinePrimitive( + const ::basegfx::B2DPolygon& rUnitPolygon, + const ::basegfx::B2DHomMatrix& rObjectTransform, + const attribute::SdrLineAttribute& rLine, + const attribute::SdrLineStartEndAttribute* pStroke) + { + // prepare fully scaled polygon + ::basegfx::B2DPolygon aScaledPolygon(rUnitPolygon); + aScaledPolygon.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()); + BasePrimitive2D* pNewLinePrimitive = 0L; + + if(!rUnitPolygon.isClosed() && pStroke) + { + attribute::LineStartEndAttribute aStart(pStroke->getStartWidth(), pStroke->getStartPolyPolygon(), pStroke->isStartCentered()); + attribute::LineStartEndAttribute aEnd(pStroke->getEndWidth(), pStroke->getEndPolyPolygon(), pStroke->isEndCentered()); + + // create data + pNewLinePrimitive = new PolygonStrokeArrowPrimitive2D(aScaledPolygon, aLineAttribute, aStrokeAttribute, aStart, aEnd); + } + else + { + // create data + pNewLinePrimitive = new PolygonStrokePrimitive2D(aScaledPolygon, aLineAttribute, aStrokeAttribute); + } + + if(0.0 != rLine.getTransparence()) + { + // create simpleTransparencePrimitive, add created fill primitive + const Primitive2DReference xRefA(pNewLinePrimitive); + const Primitive2DSequence aContent(&xRefA, 1L); + return Primitive2DReference(new UnifiedAlphaPrimitive2D(aContent, rLine.getTransparence())); + } + else + { + // add to decomposition + return Primitive2DReference(pNewLinePrimitive); + } + } + + Primitive2DReference createTextPrimitive( + const ::basegfx::B2DPolyPolygon& rUnitPolyPolygon, + const ::basegfx::B2DHomMatrix& rObjectTransform, + const attribute::SdrTextAttribute& rText, + const attribute::SdrLineAttribute* pStroke, + bool bCellText) + { + ::basegfx::B2DHomMatrix aAnchorTransform(rObjectTransform); + SdrTextPrimitive2D* pNew = 0L; + + if(rText.isContour()) + { + // contour text + if(pStroke && 0.0 != pStroke->getWidth()) + { + // take line width into account and shrink contour polygon accordingly + // decompose to get scale + ::basegfx::B2DVector aScale, aTranslate; + double fRotate, fShearX; + rObjectTransform.decompose(aScale, aTranslate, fRotate, fShearX); + + // scale outline to object's size to allow growing with value relative to that size + // and also to keep aspect ratio + ::basegfx::B2DHomMatrix aScaleTransform; + aScaleTransform.set(0, 0, fabs(aScale.getX())); + aScaleTransform.set(1, 1, fabs(aScale.getY())); + ::basegfx::B2DPolyPolygon aScaledUnitPolyPolygon(rUnitPolyPolygon); + aScaledUnitPolyPolygon.transform(aScaleTransform); + + // grow the polygon. To shrink, use negative value (half width) + aScaledUnitPolyPolygon = ::basegfx::tools::growInNormalDirection(aScaledUnitPolyPolygon, -(pStroke->getWidth() * 0.5)); + + // scale back to unit polygon + aScaleTransform.set(0, 0, 0.0 != aScale.getX() ? 1.0 / aScale.getX() : 1.0); + aScaleTransform.set(1, 1, 0.0 != aScale.getY() ? 1.0 / aScale.getY() : 1.0); + aScaledUnitPolyPolygon.transform(aScaleTransform); + + // create with unit polygon + pNew = new SdrContourTextPrimitive2D(rText.getSdrText(), aScaledUnitPolyPolygon, rObjectTransform); + } + else + { + // create with unit polygon + pNew = new SdrContourTextPrimitive2D(rText.getSdrText(), rUnitPolyPolygon, rObjectTransform); + } + } + else if(rText.isFontwork() && !rText.isScroll()) + { + // text on path, use scaled polygon. Not allowed when text scrolling is used. + ::basegfx::B2DPolyPolygon aScaledPolyPolygon(rUnitPolyPolygon); + aScaledPolyPolygon.transform(rObjectTransform); + pNew = new SdrPathTextPrimitive2D(rText.getSdrText(), aScaledPolyPolygon); + } + else + { + // rObjectTransform is the whole SdrObject transformation from unit rectangle + // to it's size and position. Decompose to allow working with single values. + ::basegfx::B2DVector aScale, aTranslate; + double fRotate, fShearX; + rObjectTransform.decompose(aScale, aTranslate, fRotate, fShearX); + + // extract mirroring + const bool bMirrorX(::basegfx::fTools::less(aScale.getX(), 0.0)); + const bool bMirrorY(::basegfx::fTools::less(aScale.getY(), 0.0)); + aScale = basegfx::absolute(aScale); + + // Get the real size, since polygon ountline and scale + // from the object transformation may vary (e.g. ellipse segments) + ::basegfx::B2DHomMatrix aJustScaleTransform; + aJustScaleTransform.set(0, 0, aScale.getX()); + aJustScaleTransform.set(1, 1, aScale.getY()); + ::basegfx::B2DPolyPolygon aScaledUnitPolyPolygon(rUnitPolyPolygon); + aScaledUnitPolyPolygon.transform(aJustScaleTransform); + const ::basegfx::B2DRange aSnapRange(::basegfx::tools::getRange(aScaledUnitPolyPolygon)); + + // create a range describing the wanted text position and size (aTextAnchorRange). This + // means to use the text distance values here + const ::basegfx::B2DPoint aTopLeft(aSnapRange.getMinX() + rText.getTextLeftDistance(), aSnapRange.getMinY() + rText.getTextUpperDistance()); + const ::basegfx::B2DPoint aBottomRight(aSnapRange.getMaxX() - rText.getTextRightDistance(), aSnapRange.getMaxY() - rText.getTextLowerDistance()); + ::basegfx::B2DRange aTextAnchorRange; + aTextAnchorRange.expand(aTopLeft); + aTextAnchorRange.expand(aBottomRight); + + // now create a transformation from this basic range (aTextAnchorRange) + aAnchorTransform.identity(); + aAnchorTransform.scale(aTextAnchorRange.getWidth(), aTextAnchorRange.getHeight()); + aAnchorTransform.translate(aTextAnchorRange.getMinX(), aTextAnchorRange.getMinY()); + + // apply mirroring + aAnchorTransform.scale(bMirrorX ? -1.0 : 1.0, bMirrorY ? -1.0 : 1.0); + + // apply object's other transforms + aAnchorTransform.shearX(fShearX); + aAnchorTransform.rotate(fRotate); + aAnchorTransform.translate(aTranslate.getX(), aTranslate.getY()); + + if(rText.isFitToSize()) + { + // streched text in range + pNew = new SdrStretchTextPrimitive2D(rText.getSdrText(), aAnchorTransform); + } + else // text in range + { + // build new primitive + pNew = new SdrBlockTextPrimitive2D(rText.getSdrText(), aAnchorTransform, rText.isScroll(), bCellText); + } + } + + OSL_ENSURE(pNew != 0, "createTextPrimitive: no text primitive created (!)"); + + if(rText.isBlink()) + { + // prepare animation and primitive list + drawinglayer::animation::AnimationEntryList aAnimationList; + rText.getBlinkTextTiming(aAnimationList); + + if(0.0 != aAnimationList.getDuration()) + { + // create content sequence + const Primitive2DReference xRefA(pNew); + const Primitive2DSequence aContent(&xRefA, 1L); + + // create and add animated switch primitive + return Primitive2DReference(new AnimatedBlinkPrimitive2D(aAnimationList, aContent, true)); + } + else + { + // add to decomposition + return Primitive2DReference(pNew); + } + } + else if(rText.isScroll()) + { + // get scroll direction + const SdrTextAniDirection eDirection(rText.getSdrText().GetObject().GetTextAniDirection()); + const bool bHorizontal(SDRTEXTANI_LEFT == eDirection || SDRTEXTANI_RIGHT == eDirection); + + // decompose to get separated values for the scroll box + ::basegfx::B2DVector aScale, aTranslate; + double fRotate, fShearX; + aAnchorTransform.decompose(aScale, aTranslate, fRotate, fShearX); + + // build transform from scaled only to full AnchorTransform and inverse + ::basegfx::B2DHomMatrix aSRT; + aSRT.shearX(fShearX); + aSRT.rotate(fRotate); + aSRT.translate(aTranslate.getX(), aTranslate.getY()); + ::basegfx::B2DHomMatrix aISRT(aSRT); + aISRT.invert(); + + // bring the primitive back to scaled only and get scaled range, create new clone for this + SdrTextPrimitive2D* pNew2 = pNew->createTransformedClone(aISRT); + OSL_ENSURE(pNew2, "createTextPrimitive: Could not create transformed clone of text primitive (!)"); + delete pNew; + pNew = pNew2; + + // create neutral geometry::ViewInformation2D for local range and decompose calls. This is okay + // since the decompose is view-independent + const uno::Sequence< beans::PropertyValue > xViewParameters; + geometry::ViewInformation2D aViewInformation2D(xViewParameters); + + // get range + const ::basegfx::B2DRange aScaledRange(pNew->getB2DRange(aViewInformation2D)); + + // create left outside and right outside transformations. Also take care + // of the clip rectangle + ::basegfx::B2DHomMatrix aLeft, aRight; + ::basegfx::B2DPoint aClipTopLeft(0.0, 0.0); + ::basegfx::B2DPoint aClipBottomRight(aScale.getX(), aScale.getY()); + + if(bHorizontal) + { + aClipTopLeft.setY(aScaledRange.getMinY()); + aClipBottomRight.setY(aScaledRange.getMaxY()); + aLeft.translate(-aScaledRange.getMaxX(), 0.0); + aRight.translate(aScale.getX() - aScaledRange.getMinX(), 0.0); + } + else + { + aClipTopLeft.setX(aScaledRange.getMinX()); + aClipBottomRight.setX(aScaledRange.getMaxX()); + aLeft.translate(0.0, -aScaledRange.getMaxY()); + aRight.translate(0.0, aScale.getY() - aScaledRange.getMinY()); + } + + aLeft *= aSRT; + aRight *= aSRT; + + // prepare animation list + drawinglayer::animation::AnimationEntryList aAnimationList; + + if(bHorizontal) + { + rText.getScrollTextTiming(aAnimationList, aScale.getX(), aScaledRange.getWidth()); + } + else + { + rText.getScrollTextTiming(aAnimationList, aScale.getY(), aScaledRange.getHeight()); + } + + if(0.0 != aAnimationList.getDuration()) + { + // create a new Primitive2DSequence containing the animated text in it's scaled only state. + // use the decomposition to force to simple text primitives, those will no longer + // need the outliner for formatting (alternatively it is also possible to just add + // pNew to aNewPrimitiveSequence) + Primitive2DSequence aAnimSequence(pNew->get2DDecomposition(aViewInformation2D)); + delete pNew; + + // create a new animatedInterpolatePrimitive and add it + std::vector< basegfx::B2DHomMatrix > aMatrixStack; + aMatrixStack.push_back(aLeft); + aMatrixStack.push_back(aRight); + const Primitive2DReference xRefA(new AnimatedInterpolatePrimitive2D(aMatrixStack, aAnimationList, aAnimSequence, true)); + const Primitive2DSequence aContent(&xRefA, 1L); + + // scrolling needs an encapsulating clipping primitive + const ::basegfx::B2DRange aClipRange(aClipTopLeft, aClipBottomRight); + ::basegfx::B2DPolygon aClipPolygon(::basegfx::tools::createPolygonFromRect(aClipRange)); + aClipPolygon.transform(aSRT); + return Primitive2DReference(new MaskPrimitive2D(::basegfx::B2DPolyPolygon(aClipPolygon), aContent)); + } + else + { + // add to decomposition + return Primitive2DReference(pNew); + } + } + else + { + // add to decomposition + return Primitive2DReference(pNew); + } + } + + Primitive2DReference createShadowPrimitive( + const Primitive2DSequence& rSource, + const attribute::SdrShadowAttribute& rShadow) + { + // create Shadow primitives. Need to be added in front, should use already created primitives + if(rSource.hasElements()) + { + // prepare shadow offset + ::basegfx::B2DHomMatrix aShadowOffset; + aShadowOffset.set(0, 2, rShadow.getOffset().getX()); + aShadowOffset.set(1, 2, rShadow.getOffset().getY()); + + // create shadow primitive and add content + const Primitive2DReference xRefShadow(new ShadowPrimitive2D(aShadowOffset, rShadow.getColor(), rSource)); + + if(0.0 != rShadow.getTransparence()) + { + // create SimpleTransparencePrimitive2D + const Primitive2DSequence aContent(&xRefShadow, 1L); + return Primitive2DReference(new UnifiedAlphaPrimitive2D(aContent, rShadow.getTransparence())); + } + else + { + // return directly + return xRefShadow; + } + } + else + { + return Primitive2DReference(); + } + } + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof |