diff options
author | Armin Le Grand <Armin.Le.Grand@Sun.COM> | 2010-06-17 18:02:36 +0200 |
---|---|---|
committer | Armin Le Grand <Armin.Le.Grand@Sun.COM> | 2010-06-17 18:02:36 +0200 |
commit | 12f9037a5313240ce598b17369bf002f0f7fd9f2 (patch) | |
tree | 7828ae6c6f8bebf3a9a1f82cca8e13e6a6ec68b5 | |
parent | f288b50cef4d2a13cfb100af3a71f14b171d066a (diff) | |
parent | bf8660708144ccb693063a20954f64a66a1c979d (diff) |
aw083: added aw082 due to possible conflicts in vclmetafileprocessor2d.cxx
22 files changed, 878 insertions, 431 deletions
diff --git a/drawinglayer/inc/drawinglayer/primitive2d/textprimitive2d.hxx b/drawinglayer/inc/drawinglayer/primitive2d/textprimitive2d.hxx index 0f426c6ad2ba..6c67bded2b17 100644 --- a/drawinglayer/inc/drawinglayer/primitive2d/textprimitive2d.hxx +++ b/drawinglayer/inc/drawinglayer/primitive2d/textprimitive2d.hxx @@ -62,11 +62,48 @@ namespace drawinglayer To get better text quality, it is suggested to handle tis primitive directly in a renderer. In that case, e.g. hintings on the system can be supported. + + @param maTextTransform + The text transformation contains the text start position (always baselined) + as translation, the FontSize as scale (where width relative to height defines + font scaling and width == height means no font scaling) and the font rotation + and shear. + When shear is used and a renderer does not support it, it may be better to use + the decomposition which will do everything correctly. Same is true for mirroring + which would be expressed as negative scalings. + + @param rText + The text to be used. Only a part may be used, but a bigger part of the string + may be necessary for correct layouting (e.g. international) + + @param aTextPosition + The index to the first character to use from rText + + @param aTextLength + The number of characters to use from rText + + @param rDXArray + The distances between the characters. This parameter may be empty, in that case + the renderer is responsible to do something useful. If it is given, it has to be of + the size aTextLength. Its values are in logical coordinates and describe the + distance for each character to use. This is independent from the font width which + is given with maTextTransform. The first value is the offset to use from the start + point in FontCoordinateSystem X-Direction (given by maTextTransform) to the start + point of the second character + + @param rFontAttribute + The font definition + + @param rLocale + The locale to use + + @param rFontColor + The font color to use */ class TextSimplePortionPrimitive2D : public BufferedDecompositionPrimitive2D { private: - /// text range transformation from unit range ([0.0 .. 1.0]) to text range + /// text transformation (FontCoordinateSystem) basegfx::B2DHomMatrix maTextTransform; /// The text, used from maTextPosition up to maTextPosition + maTextLength @@ -78,10 +115,10 @@ namespace drawinglayer /// The length for maText usage, starting from maTextPosition xub_StrLen maTextLength; - /// The DX array scale-independent in unit coordinates + /// The DX array in logic units ::std::vector< double > maDXArray; - /// The font to use + /// The font definition attribute::FontAttribute maFontAttribute; /// The Locale for the text @@ -90,7 +127,7 @@ namespace drawinglayer /// font color basegfx::BColor maFontColor; - /// #i96669# add simple range buffering for this primitive + /// #i96669# internal: add simple range buffering for this primitive basegfx::B2DRange maB2DRange; protected: diff --git a/drawinglayer/inc/drawinglayer/processor3d/shadow3dextractor.hxx b/drawinglayer/inc/drawinglayer/processor3d/shadow3dextractor.hxx index 23d8e7edd913..93ebfeab48e7 100644 --- a/drawinglayer/inc/drawinglayer/processor3d/shadow3dextractor.hxx +++ b/drawinglayer/inc/drawinglayer/processor3d/shadow3dextractor.hxx @@ -54,9 +54,12 @@ namespace drawinglayer class Shadow3DExtractingProcessor : public BaseProcessor3D { private: + /// typedef for data handling + typedef std::vector< primitive2d::BasePrimitive2D* > BasePrimitive2DVector; + /// result holding vector (2D) and target vector for stacking (inited to &maPrimitive2DSequence) - primitive2d::Primitive2DSequence maPrimitive2DSequence; - primitive2d::Primitive2DSequence* mpPrimitive2DSequence; + BasePrimitive2DVector maPrimitive2DSequence; + BasePrimitive2DVector* mpPrimitive2DSequence; /// object transformation for scene for 2d definition basegfx::B2DHomMatrix maObjectTransformation; @@ -93,6 +96,10 @@ namespace drawinglayer */ virtual void processBasePrimitive3D(const primitive3d::BasePrimitive3D& rCandidate); + /// helper to convert from BasePrimitive2DVector to primitive2d::Primitive2DSequence + const primitive2d::Primitive2DSequence getPrimitive2DSequenceFromBasePrimitive2DVector( + const BasePrimitive2DVector& rVector) const; + public: Shadow3DExtractingProcessor( const geometry::ViewInformation3D& rViewInformation, @@ -100,9 +107,10 @@ namespace drawinglayer const basegfx::B3DVector& rLightNormal, double fShadowSlant, const basegfx::B3DRange& rContained3DRange); + virtual ~Shadow3DExtractingProcessor(); /// data read access - const primitive2d::Primitive2DSequence& getPrimitive2DSequence() const { return maPrimitive2DSequence; } + const primitive2d::Primitive2DSequence getPrimitive2DSequence() const; const basegfx::B2DHomMatrix& getObjectTransformation() const { return maObjectTransformation; } const basegfx::B3DHomMatrix& getWorldToEye() const { return maWorldToEye; } const basegfx::B3DHomMatrix& getEyeToView() const { return maEyeToView; } diff --git a/drawinglayer/source/primitive2d/metafileprimitive2d.cxx b/drawinglayer/source/primitive2d/metafileprimitive2d.cxx index 480fa99e07fe..0d57e566ef8a 100644 --- a/drawinglayer/source/primitive2d/metafileprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/metafileprimitive2d.cxx @@ -94,8 +94,10 @@ namespace basegfx::BColor maTextLineColor; basegfx::BColor maOverlineColor; - /// clipping, font, etc. - Region maRegion; + /// clipping + basegfx::B2DPolyPolygon maClipPolyPoygon; + + /// font, etc. Font maFont; RasterOp maRasterOp; sal_uInt32 mnLayoutMode; @@ -110,7 +112,7 @@ namespace bool mbTextFillColor : 1; bool mbTextLineColor : 1; bool mbOverlineColor : 1; - bool mbRegion : 1; + bool mbClipPolyPolygonActive : 1; public: PropertyHolder() @@ -122,7 +124,7 @@ namespace maTextFillColor(), maTextLineColor(), maOverlineColor(), - maRegion(), + maClipPolyPoygon(), maFont(), maRasterOp(ROP_OVERPAINT), mnLayoutMode(0), @@ -134,7 +136,7 @@ namespace mbTextFillColor(false), mbTextLineColor(false), mbOverlineColor(false), - mbRegion(false) + mbClipPolyPolygonActive(false) { } @@ -179,10 +181,10 @@ namespace bool getOverlineColorActive() const { return mbOverlineColor; } void setOverlineColorActive(bool bNew) { if(bNew != mbOverlineColor) mbOverlineColor = bNew; } - const Region& getRegion() const { return maRegion; } - void setRegion(const Region& rRegion) { if(rRegion != maRegion) maRegion = rRegion; } - bool getRegionActive() const { return mbRegion; } - void setRegionActive(bool bNew) { if(bNew != mbRegion) mbRegion = bNew; } + const basegfx::B2DPolyPolygon& getClipPolyPolygon() const { return maClipPolyPoygon; } + void setClipPolyPolygon(const basegfx::B2DPolyPolygon& rNew) { if(rNew != maClipPolyPoygon) maClipPolyPoygon = rNew; } + bool getClipPolyPolygonActive() const { return mbClipPolyPolygonActive; } + void setClipPolyPolygonActive(bool bNew) { if(bNew != mbClipPolyPolygonActive) mbClipPolyPolygonActive = bNew; } const Font& getFont() const { return maFont; } void setFont(const Font& rFont) { if(rFont != maFont) maFont = rFont; } @@ -235,6 +237,12 @@ namespace return maPropertyHolders.size(); } + void PushDefault() + { + PropertyHolder* pNew = new PropertyHolder(); + maPropertyHolders.push_back(pNew); + } + void Push(sal_uInt16 nPushFlags) { if(nPushFlags) @@ -291,8 +299,8 @@ namespace } if(!(nPushFlags & PUSH_CLIPREGION )) { - pLast->setRegion(pTip->getRegion()); - pLast->setRegionActive(pTip->getRegionActive()); + pLast->setClipPolyPolygon(pTip->getClipPolyPolygon()); + pLast->setClipPolyPolygonActive(pTip->getClipPolyPolygonActive()); } if(!(nPushFlags & PUSH_RASTEROP )) { @@ -336,11 +344,11 @@ namespace } } } - - // execute the pop - delete maPropertyHolders.back(); - maPropertyHolders.pop_back(); } + + // execute the pop + delete maPropertyHolders.back(); + maPropertyHolders.pop_back(); } } @@ -465,25 +473,18 @@ namespace // the buffer to not delete them in the destructor. aTargets.clear(); - if(xRetval.hasElements() && rPropertyHolder.getRegionActive()) + if(xRetval.hasElements() && rPropertyHolder.getClipPolyPolygonActive()) { - const Region& rRegion = rPropertyHolder.getRegion(); + const basegfx::B2DPolyPolygon& rClipPolyPolygon = rPropertyHolder.getClipPolyPolygon(); - if(!rRegion.IsEmpty()) + if(rClipPolyPolygon.count()) { - basegfx::B2DPolyPolygon aClipPolyPolygon(getB2DPolyPolygonFromRegion(rRegion)); + const drawinglayer::primitive2d::Primitive2DReference xMask( + new drawinglayer::primitive2d::MaskPrimitive2D( + rClipPolyPolygon, + xRetval)); - if(aClipPolyPolygon.count()) - { - aClipPolyPolygon.transform(rPropertyHolder.getTransformation()); - - const drawinglayer::primitive2d::Primitive2DReference xMask( - new drawinglayer::primitive2d::MaskPrimitive2D( - aClipPolyPolygon, - xRetval)); - - xRetval = drawinglayer::primitive2d::Primitive2DSequence(&xMask, 1); - } + xRetval = drawinglayer::primitive2d::Primitive2DSequence(&xMask, 1); } } @@ -943,14 +944,17 @@ namespace default : // case HATCH_SINGLE : { aHatchStyle = drawinglayer::attribute::HATCHSTYLE_SINGLE; + break; } case HATCH_DOUBLE : { aHatchStyle = drawinglayer::attribute::HATCHSTYLE_DOUBLE; + break; } case HATCH_TRIPLE : { aHatchStyle = drawinglayer::attribute::HATCHSTYLE_TRIPLE; + break; } } @@ -969,53 +973,56 @@ namespace a new target for embracing new geometry to the current region */ void HandleNewClipRegion( - const Region* pRegion, + const basegfx::B2DPolyPolygon& rClipPolyPolygon, TargetHolders& rTargetHolders, PropertyHolders& rPropertyHolders) { - const bool bNewActive(pRegion && !pRegion->IsEmpty()); + const bool bNewActive(rClipPolyPolygon.count()); - // #i108636# The handlig of new ClipRegions was not done as good as possible - // in the first version of this interpreter; e.g. when a ClipRegion was set + // #i108636# The handlig of new ClipPolyPolygons was not done as good as possible + // in the first version of this interpreter; e.g. when a ClipPolyPolygon was set // initially and then using a lot of push/pop actions, the pop always leads - // to setting a 'new' ClipRegion which indeed is the return to the ClipRegion + // to setting a 'new' ClipPolyPolygon which indeed is the return to the ClipPolyPolygon // of the properties next on the stack. - // This ClipRegion is identical to the current one, so there is no need to + // + // This ClipPolyPolygon is identical to the current one, so there is no need to // create a MaskPrimitive2D containing the up-to-now created primitives, but // this was done before. While this does not lead to wrong primitive // representations of the metafile data, it creates unneccesarily expensive - // representations. Just detecting when no really 'new' ClipRegion gets set + // representations. Just detecting when no really 'new' ClipPolyPolygon gets set // solves the problem. - if(!rPropertyHolders.Current().getRegionActive() && !bNewActive) + if(!rPropertyHolders.Current().getClipPolyPolygonActive() && !bNewActive) { - // no active region exchanged by no new one, done + // no active ClipPolyPolygon exchanged by no new one, done return; } - if(rPropertyHolders.Current().getRegionActive() && bNewActive) + if(rPropertyHolders.Current().getClipPolyPolygonActive() && bNewActive) { - // active region and new active region - if(rPropertyHolders.Current().getRegion() == *pRegion) + // active ClipPolyPolygon and new active ClipPolyPolygon + if(rPropertyHolders.Current().getClipPolyPolygon() == rClipPolyPolygon) { - // new region is the same as the old region, done + // new is the same as old, done return; } } - // Here the old region and the new one are definitively different, maybe + // Here the old and the new are definitively different, maybe // old one and/or new one is not active. - // Handle deletion of old region.The process evtl. created primitives which - // belong to this active region. These need to be embedded to a + // Handle deletion of old ClipPolyPolygon. The process evtl. created primitives which + // belong to this active ClipPolyPolygon. These need to be embedded to a // MaskPrimitive2D accordingly. - if(rPropertyHolders.Current().getRegionActive() && rTargetHolders.size() > 1) + if(rPropertyHolders.Current().getClipPolyPolygonActive() && rTargetHolders.size() > 1) { drawinglayer::primitive2d::Primitive2DSequence aSubContent; - if(!rPropertyHolders.Current().getRegion().IsEmpty() && rTargetHolders.Current().size()) + if(rPropertyHolders.Current().getClipPolyPolygon().count() + && rTargetHolders.Current().size()) { - aSubContent = rTargetHolders.Current().getPrimitive2DSequence(rPropertyHolders.Current()); + aSubContent = rTargetHolders.Current().getPrimitive2DSequence( + rPropertyHolders.Current()); } rTargetHolders.Pop(); @@ -1030,11 +1037,11 @@ namespace // apply new settings to current properties by setting // the new region now - rPropertyHolders.Current().setRegionActive(bNewActive); + rPropertyHolders.Current().setClipPolyPolygonActive(bNewActive); if(bNewActive) { - rPropertyHolders.Current().setRegion(*pRegion); + rPropertyHolders.Current().setClipPolyPolygon(rClipPolyPolygon); // prepare new content holder for new active region rTargetHolders.Push(); @@ -2134,8 +2141,11 @@ namespace drawinglayer::primitive2d::Primitive2DSequence xSubContent; { rTargetHolders.Push(); + // #i# for sub-Mteafile contents, do start with new, default render state + rPropertyHolders.PushDefault(); interpretMetafile(aGDIMetaFile, rTargetHolders, rPropertyHolders, rViewInformation); xSubContent = rTargetHolders.Current().getPrimitive2DSequence(rPropertyHolders.Current()); + rPropertyHolders.Pop(); rTargetHolders.Pop(); } @@ -2424,13 +2434,18 @@ namespace if(pA->IsClipping()) { - // new clipping - HandleNewClipRegion(&pA->GetRegion(), rTargetHolders, rPropertyHolders); + // new clipping. Get PolyPolygon and transform with current transformation + basegfx::B2DPolyPolygon aNewClipPolyPolygon(getB2DPolyPolygonFromRegion(pA->GetRegion())); + + aNewClipPolyPolygon.transform(rPropertyHolders.Current().getTransformation()); + HandleNewClipRegion(aNewClipPolyPolygon, rTargetHolders, rPropertyHolders); } else { // end clipping - HandleNewClipRegion(0, rTargetHolders, rPropertyHolders); + const basegfx::B2DPolyPolygon aEmptyPolyPolygon; + + HandleNewClipRegion(aEmptyPolyPolygon, rTargetHolders, rPropertyHolders); } break; @@ -2444,49 +2459,60 @@ namespace if(rRectangle.IsEmpty()) { // intersect with empty rectangle will always give empty - // region; start new clipping with empty region - const Region aNewRegion; - HandleNewClipRegion(&aNewRegion, rTargetHolders, rPropertyHolders); + // ClipPolyPolygon; start new clipping with empty PolyPolygon + const basegfx::B2DPolyPolygon aEmptyPolyPolygon; + + HandleNewClipRegion(aEmptyPolyPolygon, rTargetHolders, rPropertyHolders); } else { - if(rPropertyHolders.Current().getRegionActive()) + // create transformed ClipRange + basegfx::B2DRange aClipRange( + rRectangle.Left(), rRectangle.Top(), + rRectangle.Right(), rRectangle.Bottom()); + + aClipRange.transform(rPropertyHolders.Current().getTransformation()); + + if(rPropertyHolders.Current().getClipPolyPolygonActive()) { - if(rPropertyHolders.Current().getRegion().IsEmpty()) + if(0 == rPropertyHolders.Current().getClipPolyPolygon().count()) { - // nothing to do, empty active clip region will stay + // nothing to do, empty active clipPolyPolygon will stay // empty when intersecting } else { - // AND existing region and new rectangle + // AND existing region and new ClipRange const basegfx::B2DPolyPolygon aOriginalPolyPolygon( - getB2DPolyPolygonFromRegion(rPropertyHolders.Current().getRegion())); + rPropertyHolders.Current().getClipPolyPolygon()); basegfx::B2DPolyPolygon aClippedPolyPolygon; if(aOriginalPolyPolygon.count()) { - const basegfx::B2DRange aIntersectRange( - rRectangle.Left(), rRectangle.Top(), - rRectangle.Right(), rRectangle.Bottom()); - aClippedPolyPolygon = basegfx::tools::clipPolyPolygonOnRange( - aOriginalPolyPolygon, aIntersectRange, true, false); + aOriginalPolyPolygon, + aClipRange, + true, + false); } if(aClippedPolyPolygon != aOriginalPolyPolygon) { // start new clipping with intersected region - const Region aNewRegion(aClippedPolyPolygon); - HandleNewClipRegion(&aNewRegion, rTargetHolders, rPropertyHolders); + HandleNewClipRegion( + aClippedPolyPolygon, + rTargetHolders, + rPropertyHolders); } } } else { - // start new clipping with rectangle - const Region aNewRegion(rRectangle); - HandleNewClipRegion(&aNewRegion, rTargetHolders, rPropertyHolders); + // start new clipping with ClipRange + const basegfx::B2DPolyPolygon aNewClipPolyPolygon( + basegfx::tools::createPolygonFromRect(aClipRange)); + + HandleNewClipRegion(aNewClipPolyPolygon, rTargetHolders, rPropertyHolders); } } @@ -2501,50 +2527,48 @@ namespace if(rNewRegion.IsEmpty()) { // intersect with empty region will always give empty - // region; start new clipping with empty region - const Region aNewRegion; - HandleNewClipRegion(&aNewRegion, rTargetHolders, rPropertyHolders); + // region; start new clipping with empty PolyPolygon + const basegfx::B2DPolyPolygon aEmptyPolyPolygon; + + HandleNewClipRegion(aEmptyPolyPolygon, rTargetHolders, rPropertyHolders); } else { - if(rPropertyHolders.Current().getRegionActive()) + // get new ClipPolyPolygon, transform it with current transformation + basegfx::B2DPolyPolygon aNewClipPolyPolygon(getB2DPolyPolygonFromRegion(rNewRegion)); + aNewClipPolyPolygon.transform(rPropertyHolders.Current().getTransformation()); + + if(rPropertyHolders.Current().getClipPolyPolygonActive()) { - if(rPropertyHolders.Current().getRegion().IsEmpty()) + if(0 == rPropertyHolders.Current().getClipPolyPolygon().count()) { - // nothing to do, empty active clip region will stay empty + // nothing to do, empty active clipPolyPolygon will stay empty // when intersecting with any region } else { // AND existing and new region const basegfx::B2DPolyPolygon aOriginalPolyPolygon( - getB2DPolyPolygonFromRegion(rPropertyHolders.Current().getRegion())); + rPropertyHolders.Current().getClipPolyPolygon()); basegfx::B2DPolyPolygon aClippedPolyPolygon; if(aOriginalPolyPolygon.count()) { - const basegfx::B2DPolyPolygon aClipPolyPolygon( - getB2DPolyPolygonFromRegion(rNewRegion)); - - if(aClipPolyPolygon.count()) - { - aClippedPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon( - aOriginalPolyPolygon, aClipPolyPolygon, true, false); - } + aClippedPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon( + aOriginalPolyPolygon, aNewClipPolyPolygon, true, false); } if(aClippedPolyPolygon != aOriginalPolyPolygon) { - // start new clipping with intersected region - const Region aNewRegion(aClippedPolyPolygon); - HandleNewClipRegion(&aNewRegion, rTargetHolders, rPropertyHolders); + // start new clipping with intersected ClipPolyPolygon + HandleNewClipRegion(aClippedPolyPolygon, rTargetHolders, rPropertyHolders); } } } else { - // start new clipping with new region - HandleNewClipRegion(&rNewRegion, rTargetHolders, rPropertyHolders); + // start new clipping with new ClipPolyPolygon + HandleNewClipRegion(aNewClipPolyPolygon, rTargetHolders, rPropertyHolders); } } @@ -2555,24 +2579,31 @@ namespace /** CHECKED, WORKS WELL */ const MetaMoveClipRegionAction* pA = (const MetaMoveClipRegionAction*)pAction; - if(rPropertyHolders.Current().getRegionActive()) + if(rPropertyHolders.Current().getClipPolyPolygonActive()) { - if(rPropertyHolders.Current().getRegion().IsEmpty()) + if(0 == rPropertyHolders.Current().getClipPolyPolygon().count()) { // nothing to do } else { - // move using old interface - Region aRegion(rPropertyHolders.Current().getRegion()); - const sal_Int32 nHor(pA->GetHorzMove()); const sal_Int32 nVer(pA->GetVertMove()); if(0 != nHor || 0 != nVer) { - aRegion.Move(nHor, nVer); - HandleNewClipRegion(&aRegion, rTargetHolders, rPropertyHolders); + // prepare translation, add current transformation + basegfx::B2DVector aVector(pA->GetHorzMove(), pA->GetVertMove()); + aVector *= rPropertyHolders.Current().getTransformation(); + basegfx::B2DHomMatrix aTransform( + basegfx::tools::createTranslateB2DHomMatrix(aVector)); + + // transform existing region + basegfx::B2DPolyPolygon aClipPolyPolygon( + rPropertyHolders.Current().getClipPolyPolygon()); + + aClipPolyPolygon.transform(aTransform); + HandleNewClipRegion(aClipPolyPolygon, rTargetHolders, rPropertyHolders); } } } @@ -2777,10 +2808,12 @@ namespace const bool bRegionMayChange(rPropertyHolders.Current().getPushFlags() & PUSH_CLIPREGION); const bool bRasterOpMayChange(rPropertyHolders.Current().getPushFlags() & PUSH_RASTEROP); - if(bRegionMayChange && rPropertyHolders.Current().getRegionActive()) + if(bRegionMayChange && rPropertyHolders.Current().getClipPolyPolygonActive()) { // end evtl. clipping - HandleNewClipRegion(0, rTargetHolders, rPropertyHolders); + const basegfx::B2DPolyPolygon aEmptyPolyPolygon; + + HandleNewClipRegion(aEmptyPolyPolygon, rTargetHolders, rPropertyHolders); } if(bRasterOpMayChange && rPropertyHolders.Current().isRasterOpActive()) @@ -2797,10 +2830,11 @@ namespace HandleNewRasterOp(rPropertyHolders.Current().getRasterOp(), rTargetHolders, rPropertyHolders); } - if(bRegionMayChange && rPropertyHolders.Current().getRegionActive()) + if(bRegionMayChange && rPropertyHolders.Current().getClipPolyPolygonActive()) { // start evtl. clipping - HandleNewClipRegion(&rPropertyHolders.Current().getRegion(), rTargetHolders, rPropertyHolders); + HandleNewClipRegion( + rPropertyHolders.Current().getClipPolyPolygon(), rTargetHolders, rPropertyHolders); } break; @@ -2948,8 +2982,11 @@ namespace drawinglayer::primitive2d::Primitive2DSequence xSubContent; { rTargetHolders.Push(); + // #i# for sub-Mteafile contents, do start with new, default render state + rPropertyHolders.PushDefault(); interpretMetafile(rContent, rTargetHolders, rPropertyHolders, rViewInformation); xSubContent = rTargetHolders.Current().getPrimitive2DSequence(rPropertyHolders.Current()); + rPropertyHolders.Pop(); rTargetHolders.Pop(); } diff --git a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx index 68ca424cca78..dc954de7bb2a 100644 --- a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx @@ -94,6 +94,147 @@ using namespace com::sun::star; ////////////////////////////////////////////////////////////////////////////// +// #112245# definition for maximum allowed point count due to Metafile target. +// To be on the safe side with the old tools polygon, use slightly less then +// the theoretical maximum (bad experiences with tools polygon) + +#define MAX_POLYGON_POINT_COUNT_METAFILE (0x0000fff0) + +////////////////////////////////////////////////////////////////////////////// + +namespace +{ + // #112245# helper to split line polygon in half + void splitLinePolygon( + const basegfx::B2DPolygon& rBasePolygon, + basegfx::B2DPolygon& o_aLeft, + basegfx::B2DPolygon& o_aRight) + { + const sal_uInt32 nCount(rBasePolygon.count()); + + if(nCount) + { + const sal_uInt32 nHalfCount((nCount - 1) >> 1); + + o_aLeft = basegfx::B2DPolygon(rBasePolygon, 0, nHalfCount + 1); + o_aLeft.setClosed(false); + + o_aRight = basegfx::B2DPolygon(rBasePolygon, nHalfCount, nCount - nHalfCount); + o_aRight.setClosed(false); + + if(rBasePolygon.isClosed()) + { + o_aRight.append(rBasePolygon.getB2DPoint(0)); + + if(rBasePolygon.areControlPointsUsed()) + { + o_aRight.setControlPoints( + o_aRight.count() - 1, + rBasePolygon.getPrevControlPoint(0), + rBasePolygon.getNextControlPoint(0)); + } + } + } + else + { + o_aLeft.clear(); + o_aRight.clear(); + } + } + + // #112245# helper to evtl. split filled polygons to maximum metafile point count + bool fillPolyPolygonNeededToBeSplit(basegfx::B2DPolyPolygon& rPolyPolygon) + { + bool bRetval(false); + const sal_uInt32 nPolyCount(rPolyPolygon.count()); + + if(nPolyCount) + { + basegfx::B2DPolyPolygon aSplitted; + + for(sal_uInt32 a(0); a < nPolyCount; a++) + { + const basegfx::B2DPolygon aCandidate(rPolyPolygon.getB2DPolygon(a)); + const sal_uInt32 nPointCount(aCandidate.count()); + bool bNeedToSplit(false); + + if(aCandidate.areControlPointsUsed()) + { + // compare with the maximum for bezier curved polygons + bNeedToSplit = nPointCount > ((MAX_POLYGON_POINT_COUNT_METAFILE / 3L) - 1L); + } + else + { + // compare with the maximum for simple point polygons + bNeedToSplit = nPointCount > (MAX_POLYGON_POINT_COUNT_METAFILE - 1); + } + + if(bNeedToSplit) + { + // need to split the partial polygon + const basegfx::B2DRange aRange(aCandidate.getB2DRange()); + const basegfx::B2DPoint aCenter(aRange.getCenter()); + + if(aRange.getWidth() > aRange.getHeight()) + { + // clip in left and right + const basegfx::B2DPolyPolygon aLeft( + basegfx::tools::clipPolygonOnParallelAxis( + aCandidate, + false, + true, + aCenter.getX(), + false)); + const basegfx::B2DPolyPolygon aRight( + basegfx::tools::clipPolygonOnParallelAxis( + aCandidate, + false, + false, + aCenter.getX(), + false)); + + aSplitted.append(aLeft); + aSplitted.append(aRight); + } + else + { + // clip in top and bottom + const basegfx::B2DPolyPolygon aTop( + basegfx::tools::clipPolygonOnParallelAxis( + aCandidate, + true, + true, + aCenter.getY(), + false)); + const basegfx::B2DPolyPolygon aBottom( + basegfx::tools::clipPolygonOnParallelAxis( + aCandidate, + true, + false, + aCenter.getY(), + false)); + + aSplitted.append(aTop); + aSplitted.append(aBottom); + } + } + else + { + aSplitted.append(aCandidate); + } + } + + if(aSplitted.count() != nPolyCount) + { + rPolyPolygon = aSplitted; + } + } + + return bRetval; + } +} // end of anonymous namespace + +////////////////////////////////////////////////////////////////////////////// namespace drawinglayer { @@ -985,14 +1126,12 @@ namespace drawinglayer const primitive2d::PolygonHairlinePrimitive2D& rHairlinePrimitive = static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate); const basegfx::B2DPolygon& rBasePolygon = rHairlinePrimitive.getB2DPolygon(); - if(rBasePolygon.count() > (0x0000ffff - 1)) + if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1)) { // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points // per polygon. If there are more, split the polygon in half and call recursively - const sal_uInt32 nCount(rBasePolygon.count()); - const sal_uInt32 nHalfCount((nCount - 1) >> 1); - const basegfx::B2DPolygon aLeft(rBasePolygon, 0, nHalfCount + 1); - const basegfx::B2DPolygon aRight(rBasePolygon, nHalfCount, nCount - nHalfCount); + basegfx::B2DPolygon aLeft, aRight; + splitLinePolygon(rBasePolygon, aLeft, aRight); const primitive2d::PolygonHairlinePrimitive2D aPLeft(aLeft, rHairlinePrimitive.getBColor()); const primitive2d::PolygonHairlinePrimitive2D aPRight(aRight, rHairlinePrimitive.getBColor()); @@ -1020,14 +1159,12 @@ namespace drawinglayer const primitive2d::PolygonStrokePrimitive2D& rStrokePrimitive = static_cast< const primitive2d::PolygonStrokePrimitive2D& >(rCandidate); const basegfx::B2DPolygon& rBasePolygon = rStrokePrimitive.getB2DPolygon(); - if(rBasePolygon.count() > (0x0000ffff - 1)) + if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1)) { // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points // per polygon. If there are more, split the polygon in half and call recursively - const sal_uInt32 nCount(rBasePolygon.count()); - const sal_uInt32 nHalfCount((nCount - 1) >> 1); - const basegfx::B2DPolygon aLeft(rBasePolygon, 0, nHalfCount + 1); - const basegfx::B2DPolygon aRight(rBasePolygon, nHalfCount, nCount - nHalfCount); + basegfx::B2DPolygon aLeft, aRight; + splitLinePolygon(rBasePolygon, aLeft, aRight); const primitive2d::PolygonStrokePrimitive2D aPLeft( aLeft, rStrokePrimitive.getLineAttribute(), rStrokePrimitive.getStrokeAttribute()); const primitive2d::PolygonStrokePrimitive2D aPRight( @@ -1099,14 +1236,12 @@ namespace drawinglayer const primitive2d::PolygonStrokeArrowPrimitive2D& rStrokeArrowPrimitive = static_cast< const primitive2d::PolygonStrokeArrowPrimitive2D& >(rCandidate); const basegfx::B2DPolygon& rBasePolygon = rStrokeArrowPrimitive.getB2DPolygon(); - if(rBasePolygon.count() > (0x0000ffff - 1)) + if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1)) { // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points // per polygon. If there are more, split the polygon in half and call recursively - const sal_uInt32 nCount(rBasePolygon.count()); - const sal_uInt32 nHalfCount((nCount - 1) >> 1); - const basegfx::B2DPolygon aLeft(rBasePolygon, 0, nHalfCount + 1); - const basegfx::B2DPolygon aRight(rBasePolygon, nHalfCount, nCount - nHalfCount); + basegfx::B2DPolygon aLeft, aRight; + splitLinePolygon(rBasePolygon, aLeft, aRight); const attribute::LineStartEndAttribute aEmpty; const primitive2d::PolygonStrokeArrowPrimitive2D aPLeft( aLeft, @@ -1150,16 +1285,26 @@ namespace drawinglayer case PRIMITIVE2D_ID_POLYPOLYGONBITMAPPRIMITIVE2D : { // need to handle PolyPolygonBitmapPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END - SvtGraphicFill* pSvtGraphicFill = 0; + const primitive2d::PolyPolygonBitmapPrimitive2D& rBitmapCandidate = static_cast< const primitive2d::PolyPolygonBitmapPrimitive2D& >(rCandidate); + basegfx::B2DPolyPolygon aLocalPolyPolygon(rBitmapCandidate.getB2DPolyPolygon()); - if(!mnSvtGraphicFillCount) + if(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon)) { - const primitive2d::PolyPolygonBitmapPrimitive2D& rBitmapCandidate = static_cast< const primitive2d::PolyPolygonBitmapPrimitive2D& >(rCandidate); - basegfx::B2DPolyPolygon aLocalPolyPolygon(rBitmapCandidate.getB2DPolyPolygon()); - aLocalPolyPolygon.transform(maCurrentTransformation); + // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points + // per polygon. If there are more use the splitted polygon and call recursively + const primitive2d::PolyPolygonBitmapPrimitive2D aSplitted( + aLocalPolyPolygon, + rBitmapCandidate.getFillBitmap()); - if(aLocalPolyPolygon.count()) + processBasePrimitive2D(aSplitted); + } + else + { + SvtGraphicFill* pSvtGraphicFill = 0; + + if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count()) { + aLocalPolyPolygon.transform(maCurrentTransformation); // calculate transformation. Get real object size, all values in FillBitmapAttribute // are relative to the unified object const attribute::FillBitmapAttribute& rFillBitmapAttribute = rBitmapCandidate .getFillBitmap(); @@ -1216,84 +1361,100 @@ namespace drawinglayer 0, aFillGraphic); } - } - // Do use decomposition; encapsulate with SvtGraphicFill - impStartSvtGraphicFill(pSvtGraphicFill); - process(rCandidate.get2DDecomposition(getViewInformation2D())); - impEndSvtGraphicFill(pSvtGraphicFill); + // Do use decomposition; encapsulate with SvtGraphicFill + impStartSvtGraphicFill(pSvtGraphicFill); + process(rCandidate.get2DDecomposition(getViewInformation2D())); + impEndSvtGraphicFill(pSvtGraphicFill); + } break; } case PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D : { // need to handle PolyPolygonHatchPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END + const primitive2d::PolyPolygonHatchPrimitive2D& rHatchCandidate = static_cast< const primitive2d::PolyPolygonHatchPrimitive2D& >(rCandidate); + basegfx::B2DPolyPolygon aLocalPolyPolygon(rHatchCandidate.getB2DPolyPolygon()); + + // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points + // per polygon. Split polygon until there are less than that + while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon)) + ; + SvtGraphicFill* pSvtGraphicFill = 0; + const attribute::FillHatchAttribute& rFillHatchAttribute = rHatchCandidate.getFillHatch(); + aLocalPolyPolygon.transform(maCurrentTransformation); - if(!mnSvtGraphicFillCount) + if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count()) { - const primitive2d::PolyPolygonHatchPrimitive2D& rHatchCandidate = static_cast< const primitive2d::PolyPolygonHatchPrimitive2D& >(rCandidate); - basegfx::B2DPolyPolygon aLocalPolyPolygon(rHatchCandidate.getB2DPolyPolygon()); - aLocalPolyPolygon.transform(maCurrentTransformation); + // re-create a VCL hatch as base data + SvtGraphicFill::HatchType eHatch(SvtGraphicFill::hatchSingle); - if(aLocalPolyPolygon.count()) + switch(rFillHatchAttribute.getStyle()) { - // re-create a VCL hatch as base data - const attribute::FillHatchAttribute& rFillHatchAttribute = rHatchCandidate.getFillHatch(); - SvtGraphicFill::HatchType eHatch(SvtGraphicFill::hatchSingle); - - switch(rFillHatchAttribute.getStyle()) + default: // attribute::HATCHSTYLE_SINGLE : { - default: // attribute::HATCHSTYLE_SINGLE : - { - eHatch = SvtGraphicFill::hatchSingle; - break; - } - case attribute::HATCHSTYLE_DOUBLE : - { - eHatch = SvtGraphicFill::hatchDouble; - break; - } - case attribute::HATCHSTYLE_TRIPLE : - { - eHatch = SvtGraphicFill::hatchTriple; - break; - } + eHatch = SvtGraphicFill::hatchSingle; + break; + } + case attribute::HATCHSTYLE_DOUBLE : + { + eHatch = SvtGraphicFill::hatchDouble; + break; } + case attribute::HATCHSTYLE_TRIPLE : + { + eHatch = SvtGraphicFill::hatchTriple; + break; + } + } - SvtGraphicFill::Transform aTransform; + SvtGraphicFill::Transform aTransform; - // scale - aTransform.matrix[0] *= rFillHatchAttribute.getDistance(); - aTransform.matrix[4] *= rFillHatchAttribute.getDistance(); + // scale + aTransform.matrix[0] *= rFillHatchAttribute.getDistance(); + aTransform.matrix[4] *= rFillHatchAttribute.getDistance(); - // rotate (was never correct in impgrfll anyways, use correct angle now) - aTransform.matrix[0] *= cos(rFillHatchAttribute.getAngle()); - aTransform.matrix[1] *= -sin(rFillHatchAttribute.getAngle()); - aTransform.matrix[3] *= sin(rFillHatchAttribute.getAngle()); - aTransform.matrix[4] *= cos(rFillHatchAttribute.getAngle()); + // rotate (was never correct in impgrfll anyways, use correct angle now) + aTransform.matrix[0] *= cos(rFillHatchAttribute.getAngle()); + aTransform.matrix[1] *= -sin(rFillHatchAttribute.getAngle()); + aTransform.matrix[3] *= sin(rFillHatchAttribute.getAngle()); + aTransform.matrix[4] *= cos(rFillHatchAttribute.getAngle()); - pSvtGraphicFill = new SvtGraphicFill( - PolyPolygon(aLocalPolyPolygon), - Color(), - 0.0, - SvtGraphicFill::fillEvenOdd, - SvtGraphicFill::fillHatch, - aTransform, - false, - eHatch, - Color(rFillHatchAttribute.getColor()), - SvtGraphicFill::gradientLinear, - Color(), - Color(), - 0, - Graphic()); - } + pSvtGraphicFill = new SvtGraphicFill( + PolyPolygon(aLocalPolyPolygon), + Color(), + 0.0, + SvtGraphicFill::fillEvenOdd, + SvtGraphicFill::fillHatch, + aTransform, + false, + eHatch, + Color(rFillHatchAttribute.getColor()), + SvtGraphicFill::gradientLinear, + Color(), + Color(), + 0, + Graphic()); } // Do use decomposition; encapsulate with SvtGraphicFill impStartSvtGraphicFill(pSvtGraphicFill); - process(rCandidate.get2DDecomposition(getViewInformation2D())); + + // #i111954# do NOT use decomposition, but use direct VCL-command + // process(rCandidate.get2DDecomposition(getViewInformation2D())); + const PolyPolygon aToolsPolyPolygon(aLocalPolyPolygon); + const HatchStyle aHatchStyle( + attribute::HATCHSTYLE_SINGLE == rFillHatchAttribute.getStyle() ? HATCH_SINGLE : + attribute::HATCHSTYLE_DOUBLE == rFillHatchAttribute.getStyle() ? HATCH_DOUBLE : + HATCH_TRIPLE); + + mpOutputDevice->DrawHatch(aToolsPolyPolygon, + Hatch(aHatchStyle, + Color(rFillHatchAttribute.getColor()), + basegfx::fround(rFillHatchAttribute.getDistance()), + basegfx::fround(rFillHatchAttribute.getAngle() / F_PI1800))); + impEndSvtGraphicFill(pSvtGraphicFill); break; @@ -1301,13 +1462,18 @@ namespace drawinglayer case PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D : { const primitive2d::PolyPolygonGradientPrimitive2D& rGradientCandidate = static_cast< const primitive2d::PolyPolygonGradientPrimitive2D& >(rCandidate); + basegfx::B2DPolyPolygon aLocalPolyPolygon(rGradientCandidate.getB2DPolyPolygon()); + + // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points + // per polygon. Split polygon until there are less than that + while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon)) + ; // for support of MetaCommentActions of the form XGRAD_SEQ_BEGIN, XGRAD_SEQ_END // it is safest to use the VCL OutputDevice::DrawGradient method which creates those. // re-create a VCL-gradient from FillGradientPrimitive2D and the needed tools PolyPolygon Gradient aVCLGradient; impConvertFillGradientAttributeToVCLGradient(aVCLGradient, rGradientCandidate.getFillGradient(), false); - basegfx::B2DPolyPolygon aLocalPolyPolygon(rGradientCandidate.getB2DPolyPolygon()); aLocalPolyPolygon.transform(maCurrentTransformation); // #i82145# ATM VCL printing of gradients using curved shapes does not work, @@ -1365,13 +1531,20 @@ namespace drawinglayer // NO usage of common own gradient randerer, not used ATM for VCL MetaFile, see text above // RenderPolyPolygonGradientPrimitive2D(static_cast< const primitive2d::PolyPolygonGradientPrimitive2D& >(rCandidate)); + break; } case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D : { const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate(static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate)); - const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor())); basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon()); + + // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points + // per polygon. Split polygon until there are less than that + while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon)) + ; + + const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor())); aLocalPolyPolygon.transform(maCurrentTransformation); // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support @@ -1433,7 +1606,11 @@ namespace drawinglayer { // there is already a clip polygon set; build clipped union of // current mask polygon and new one - maClipPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon(aMask, maClipPolyPolygon, false, false); + maClipPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon( + aMask, + maClipPolyPolygon, + true, // #i106516# we want the inside of aMask, not the outside + false); } else { @@ -1535,6 +1712,13 @@ namespace drawinglayer // single transparent PolyPolygon identified, use directly const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(pPoPoColor->getBColor())); basegfx::B2DPolyPolygon aLocalPolyPolygon(pPoPoColor->getB2DPolyPolygon()); + + // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points + // per polygon. Split polygon until there are less than that + while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon)) + ; + + // now transform aLocalPolyPolygon.transform(maCurrentTransformation); // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx index a1b1393a2fac..6a280fcad95e 100644 --- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx @@ -284,20 +284,37 @@ namespace drawinglayer if(bAllowUsingDrawTransparent && 1 == rContent.getLength()) { const primitive2d::Primitive2DReference xReference(rContent[0]); - const primitive2d::PolyPolygonColorPrimitive2D* pPoPoColor = dynamic_cast< const primitive2d::PolyPolygonColorPrimitive2D* >(xReference.get()); + const primitive2d::BasePrimitive2D* pBasePrimitive = dynamic_cast< const primitive2d::BasePrimitive2D* >(xReference.get()); - if(pPoPoColor && PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D == pPoPoColor->getPrimitive2DID()) + if(pBasePrimitive) { - // single transparent PolyPolygon identified, use directly - const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(pPoPoColor->getBColor())); - mpOutputDevice->SetFillColor(Color(aPolygonColor)); - mpOutputDevice->SetLineColor(); - - basegfx::B2DPolyPolygon aLocalPolyPolygon(pPoPoColor->getB2DPolyPolygon()); - aLocalPolyPolygon.transform(maCurrentTransformation); - - mpOutputDevice->DrawTransparent(aLocalPolyPolygon, rUniTransparenceCandidate.getTransparence()); - bDrawTransparentUsed = true; + switch(pBasePrimitive->getPrimitive2DID()) + { + case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D: + { + // single transparent PolyPolygon identified, use directly + const primitive2d::PolyPolygonColorPrimitive2D* pPoPoColor = static_cast< const primitive2d::PolyPolygonColorPrimitive2D* >(pBasePrimitive); + OSL_ENSURE(pPoPoColor, "OOps, PrimitiveID and PrimitiveType do not match (!)"); + const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(pPoPoColor->getBColor())); + mpOutputDevice->SetFillColor(Color(aPolygonColor)); + mpOutputDevice->SetLineColor(); + + basegfx::B2DPolyPolygon aLocalPolyPolygon(pPoPoColor->getB2DPolyPolygon()); + aLocalPolyPolygon.transform(maCurrentTransformation); + + mpOutputDevice->DrawTransparent(aLocalPolyPolygon, rUniTransparenceCandidate.getTransparence()); + bDrawTransparentUsed = true; + break; + } + // #i# need to wait for #i101378# which is in CWS vcl112 to directly paint transparent hairlines + //case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D: + //{ + // // single transparent PolygonHairlinePrimitive2D identified, use directly + // const primitive2d::PolygonHairlinePrimitive2D* pPoHair = static_cast< const primitive2d::PolygonHairlinePrimitive2D* >(pBasePrimitive); + // OSL_ENSURE(pPoHair, "OOps, PrimitiveID and PrimitiveType do not match (!)"); + // break; + //} + } } } @@ -469,19 +486,29 @@ namespace drawinglayer // This is wrong in principle, but looks nicer. This could also be done here directly // without VCL usage if needed const primitive2d::FillHatchPrimitive2D& rFillHatchPrimitive = static_cast< const primitive2d::FillHatchPrimitive2D& >(rCandidate); + const attribute::FillHatchAttribute& rFillHatchAttributes = rFillHatchPrimitive.getFillHatch(); // create hatch polygon in range size and discrete coordinates basegfx::B2DRange aHatchRange(rFillHatchPrimitive.getObjectRange()); aHatchRange.transform(maCurrentTransformation); const basegfx::B2DPolygon aHatchPolygon(basegfx::tools::createPolygonFromRect(aHatchRange)); + if(rFillHatchAttributes.isFillBackground()) + { + // #i111846# background fill is active; draw fill polygon + const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rFillHatchPrimitive.getBColor())); + + mpOutputDevice->SetFillColor(Color(aPolygonColor)); + mpOutputDevice->SetLineColor(); + mpOutputDevice->DrawPolygon(aHatchPolygon); + } + // set hatch line color const basegfx::BColor aHatchColor(maBColorModifierStack.getModifiedColor(rFillHatchPrimitive.getBColor())); mpOutputDevice->SetFillColor(); mpOutputDevice->SetLineColor(Color(aHatchColor)); // get hatch style - const attribute::FillHatchAttribute& rFillHatchAttributes = rFillHatchPrimitive.getFillHatch(); HatchStyle eHatchStyle(HATCH_SINGLE); switch(rFillHatchAttributes.getStyle()) diff --git a/drawinglayer/source/processor3d/shadow3dextractor.cxx b/drawinglayer/source/processor3d/shadow3dextractor.cxx index 2abbcaa9f83f..9e0c0674ea66 100644 --- a/drawinglayer/source/processor3d/shadow3dextractor.cxx +++ b/drawinglayer/source/processor3d/shadow3dextractor.cxx @@ -51,6 +51,25 @@ namespace drawinglayer { namespace processor3d { + /// helper to convert from BasePrimitive2DVector to primitive2d::Primitive2DSequence + const primitive2d::Primitive2DSequence Shadow3DExtractingProcessor::getPrimitive2DSequenceFromBasePrimitive2DVector( + const BasePrimitive2DVector& rVector) const + { + const sal_uInt32 nCount(rVector.size()); + primitive2d::Primitive2DSequence aRetval(nCount); + + for(sal_uInt32 a(0); a < nCount; a++) + { + aRetval[a] = rVector[a]; + } + + // all entries taken over; no need to delete entries, just reset to + // mark as empty + const_cast< BasePrimitive2DVector& >(rVector).clear(); + + return aRetval; + } + // as tooling, the process() implementation takes over API handling and calls this // virtual render method when the primitive implementation is BasePrimitive3D-based. void Shadow3DExtractingProcessor::processBasePrimitive3D(const primitive3d::BasePrimitive3D& rCandidate) @@ -64,8 +83,8 @@ namespace drawinglayer const primitive3d::ShadowPrimitive3D& rPrimitive = static_cast< const primitive3d::ShadowPrimitive3D& >(rCandidate); // set new target - primitive2d::Primitive2DSequence aNewSubList; - primitive2d::Primitive2DSequence* pLastTargetSequence = mpPrimitive2DSequence; + BasePrimitive2DVector aNewSubList; + BasePrimitive2DVector* pLastTargetSequence = mpPrimitive2DSequence; mpPrimitive2DSequence = &aNewSubList; // activate convert @@ -84,21 +103,26 @@ namespace drawinglayer mbConvert = bLastConvert; mpPrimitive2DSequence = pLastTargetSequence; - // create 2d shadow primitive with result - const primitive2d::Primitive2DReference xRef(new primitive2d::ShadowPrimitive2D(rPrimitive.getShadowTransform(), rPrimitive.getShadowColor(), aNewSubList)); + // create 2d shadow primitive with result. This also fetches all entries + // from aNewSubList, so there is no need to delete them + primitive2d::BasePrimitive2D* pNew = new primitive2d::ShadowPrimitive2D( + rPrimitive.getShadowTransform(), + rPrimitive.getShadowColor(), + getPrimitive2DSequenceFromBasePrimitive2DVector(aNewSubList)); if(basegfx::fTools::more(rPrimitive.getShadowTransparence(), 0.0)) { // create simpleTransparencePrimitive, add created primitives - const primitive2d::Primitive2DSequence aNewTransPrimitiveVector(&xRef, 1L); - const primitive2d::Primitive2DReference xRef2(new primitive2d::UnifiedTransparencePrimitive2D(aNewTransPrimitiveVector, rPrimitive.getShadowTransparence())); - primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(*mpPrimitive2DSequence, xRef2); - } - else - { - // add directly - primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(*mpPrimitive2DSequence, xRef); + const primitive2d::Primitive2DReference xRef(pNew); + const primitive2d::Primitive2DSequence aNewTransPrimitiveVector(&xRef, 1); + + pNew = new primitive2d::UnifiedTransparencePrimitive2D( + aNewTransPrimitiveVector, + rPrimitive.getShadowTransparence()); } + + mpPrimitive2DSequence->push_back(pNew); + break; } case PRIMITIVE3D_ID_TRANSFORMPRIMITIVE3D : @@ -161,8 +185,10 @@ namespace drawinglayer if(a2DHairline.count()) { a2DHairline.transform(getObjectTransformation()); - const primitive2d::Primitive2DReference xRef(new primitive2d::PolygonHairlinePrimitive2D(a2DHairline, maPrimitiveColor)); - primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(*mpPrimitive2DSequence, xRef); + mpPrimitive2DSequence->push_back( + new primitive2d::PolygonHairlinePrimitive2D( + a2DHairline, + maPrimitiveColor)); } } break; @@ -190,8 +216,10 @@ namespace drawinglayer if(a2DFill.count()) { a2DFill.transform(getObjectTransformation()); - const primitive2d::Primitive2DReference xRef(new primitive2d::PolyPolygonColorPrimitive2D(a2DFill, maPrimitiveColor)); - primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(*mpPrimitive2DSequence, xRef); + mpPrimitive2DSequence->push_back( + new primitive2d::PolyPolygonColorPrimitive2D( + a2DFill, + maPrimitiveColor)); } } break; @@ -251,6 +279,16 @@ namespace drawinglayer } } + Shadow3DExtractingProcessor::~Shadow3DExtractingProcessor() + { + OSL_ENSURE(0 == maPrimitive2DSequence.size(), + "OOps, someone used Shadow3DExtractingProcessor, but did not fetch the results (!)"); + for(sal_uInt32 a(0); a < maPrimitive2DSequence.size(); a++) + { + delete maPrimitive2DSequence[a]; + } + } + basegfx::B2DPolygon Shadow3DExtractingProcessor::impDoShadowProjection(const basegfx::B3DPolygon& rSource) { basegfx::B2DPolygon aRetval; @@ -291,6 +329,12 @@ namespace drawinglayer return aRetval; } + + const primitive2d::Primitive2DSequence Shadow3DExtractingProcessor::getPrimitive2DSequence() const + { + return getPrimitive2DSequenceFromBasePrimitive2DVector(maPrimitive2DSequence); + } + } // end of namespace processor3d } // end of namespace drawinglayer diff --git a/drawinglayer/source/processor3d/zbufferprocessor3d.cxx b/drawinglayer/source/processor3d/zbufferprocessor3d.cxx index 326b9d392999..b06718d01ccb 100644 --- a/drawinglayer/source/processor3d/zbufferprocessor3d.cxx +++ b/drawinglayer/source/processor3d/zbufferprocessor3d.cxx @@ -487,7 +487,7 @@ private: boost::shared_ptr< drawinglayer::texture::GeoTexSvx > mpTransparenceGeoTexSvx; drawinglayer::attribute::MaterialAttribute3D maMaterial; basegfx::B3DPolyPolygon maPolyPolygon; - sal_uInt32 mfCenterZ; + double mfCenterZ; // bitfield bool mbModulate : 1; diff --git a/svx/inc/svx/sdrmasterpagedescriptor.hxx b/svx/inc/svx/sdrmasterpagedescriptor.hxx index 8325d2a57fa1..612f2ab927ec 100644 --- a/svx/inc/svx/sdrmasterpagedescriptor.hxx +++ b/svx/inc/svx/sdrmasterpagedescriptor.hxx @@ -89,8 +89,6 @@ namespace sdr // operators sal_Bool operator==(const MasterPageDescriptor& rCandidate) const; sal_Bool operator!=(const MasterPageDescriptor& rCandidate) const; - - const SfxItemSet& getCorrectFillAttributes() const; }; } // end of namespace sdr diff --git a/svx/inc/svx/svdpage.hxx b/svx/inc/svx/svdpage.hxx index 29cf17ec9180..c601fddef181 100644 --- a/svx/inc/svx/svdpage.hxx +++ b/svx/inc/svx/svdpage.hxx @@ -376,7 +376,6 @@ private: public: // construct/destruct SdrPageProperties(SdrPage& rSdrPage); - SdrPageProperties(const SdrPageProperties& rCandidate); virtual ~SdrPageProperties(); // Notify(...) from baseclass SfxListener diff --git a/svx/source/engine3d/scene3d.cxx b/svx/source/engine3d/scene3d.cxx index d799aec38eb7..036f700e6e96 100644 --- a/svx/source/engine3d/scene3d.cxx +++ b/svx/source/engine3d/scene3d.cxx @@ -336,8 +336,18 @@ UINT16 E3dScene::GetObjIdentifier() const void E3dScene::SetBoundRectDirty() { - // avoid resetting aOutRect which in case of this object is model data, - // not re-creatable view data + E3dScene* pScene = GetScene(); + + if(pScene == this) + { + // avoid resetting aOutRect which in case of a 3D scene used as 2d object + // is model data,not re-creatable view data + } + else + { + // if not the outmost scene it is used as group in 3d, call parent + E3dObject::SetBoundRectDirty(); + } } /************************************************************************* diff --git a/svx/source/engine3d/view3d.cxx b/svx/source/engine3d/view3d.cxx index 97fee2250658..047faef2cb41 100644 --- a/svx/source/engine3d/view3d.cxx +++ b/svx/source/engine3d/view3d.cxx @@ -75,6 +75,7 @@ #include <svx/sdr/overlay/overlayprimitive2dsequenceobject.hxx> #include <drawinglayer/primitive2d/transformprimitive2d.hxx> #include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <basegfx/polygon/b2dpolypolygoncutter.hxx> #define ITEMVALUE(ItemSet,Id,Cast) ((const Cast&)(ItemSet).Get(Id)).GetValue() @@ -1066,77 +1067,39 @@ void E3dView::ConvertMarkedObjTo3D(BOOL bExtrude, basegfx::B2DPoint aPnt1, baseg struct E3dDepthNeighbour { - E3dDepthNeighbour* pNext; - E3dExtrudeObj* pObj; - - E3dDepthNeighbour() { pNext = NULL; pObj = NULL; } + E3dDepthNeighbour* mpNext; + E3dExtrudeObj* mpObj; + basegfx::B2DPolyPolygon maPreparedPolyPolygon; + + E3dDepthNeighbour() + : mpNext(0), + mpObj(0), + maPreparedPolyPolygon() + { + } }; struct E3dDepthLayer { - E3dDepthLayer* pDown; - E3dDepthNeighbour* pNext; - - E3dDepthLayer() { pDown = NULL; pNext = NULL; } - ~E3dDepthLayer() { while(pNext) { E3dDepthNeighbour* pSucc = pNext->pNext; delete pNext; pNext = pSucc; }} -}; - -bool ImpDoesOverlap(const basegfx::B2DPolygon& rPolygonA, const basegfx::B2DPolygon& rPolygonB) -{ - bool bRetval(false); - const basegfx::B2DRange aRangeA(basegfx::tools::getRange(rPolygonA)); - const basegfx::B2DRange aRangeB(basegfx::tools::getRange(rPolygonB)); + E3dDepthLayer* mpDown; + E3dDepthNeighbour* mpNext; - if(aRangeA.overlaps(aRangeB)) + E3dDepthLayer() + : mpDown(0), + mpNext(0) { - // A in B ? - if(basegfx::tools::isInside(rPolygonA, rPolygonB)) - return true; - - // B in A ? - if(basegfx::tools::isInside(rPolygonB, rPolygonA)) - return true; - - // A and B the same ? - if(basegfx::tools::isInside(rPolygonB, rPolygonA, true)) - return true; } - return bRetval; -} - -bool ImpDoesOverlap(const basegfx::B2DPolyPolygon& rPolyPolygonA, const basegfx::B2DPolyPolygon& rPolyPolygonB) -{ - bool bRetval(false); - const basegfx::B2DRange aRangeA(basegfx::tools::getRange(rPolyPolygonA)); - const basegfx::B2DRange aRangeB(basegfx::tools::getRange(rPolyPolygonB)); - - if(aRangeA.overlaps(aRangeB)) + ~E3dDepthLayer() { - const sal_uInt32 nCntA(rPolyPolygonA.count()); - const sal_uInt32 nCntB(rPolyPolygonB.count()); - - for(sal_uInt32 a(0L); !bRetval && a < nCntA; a++) + while(mpNext) { - const basegfx::B2DPolygon aPolygonA(rPolyPolygonA.getB2DPolygon(a)); - - if(aPolygonA.isClosed()) - { - for(sal_uInt32 b(0L); !bRetval && b < nCntB; b++) - { - const basegfx::B2DPolygon aPolygonB(rPolyPolygonB.getB2DPolygon(b)); - - if(aPolygonB.isClosed()) - { - bRetval = ImpDoesOverlap(aPolygonA, aPolygonB); - } - } - } + E3dDepthNeighbour* pSucc = mpNext->mpNext; + delete mpNext; + mpNext = pSucc; } } - - return bRetval; -} +}; void E3dView::DoDepthArrange(E3dScene* pScene, double fDepth) { @@ -1147,39 +1110,41 @@ void E3dView::DoDepthArrange(E3dScene* pScene, double fDepth) E3dDepthLayer* pBaseLayer = NULL; E3dDepthLayer* pLayer = NULL; INT32 nNumLayers = 0; - //SfxItemPool& rPool = pMod->GetItemPool(); while(aIter.IsMore()) { - E3dObject* pSubObj = (E3dObject*)aIter.Next(); + E3dExtrudeObj* pExtrudeObj = dynamic_cast< E3dExtrudeObj* >(aIter.Next()); - if(pSubObj && pSubObj->ISA(E3dExtrudeObj)) + if(pExtrudeObj) { - E3dExtrudeObj* pExtrudeObj = (E3dExtrudeObj*)pSubObj; - const basegfx::B2DPolyPolygon aExtrudePoly(pExtrudeObj->GetExtrudePolygon()); - + const basegfx::B2DPolyPolygon aExtrudePoly( + basegfx::tools::prepareForPolygonOperation(pExtrudeObj->GetExtrudePolygon())); const SfxItemSet& rLocalSet = pExtrudeObj->GetMergedItemSet(); - XFillStyle eLocalFillStyle = ITEMVALUE(rLocalSet, XATTR_FILLSTYLE, XFillStyleItem); - Color aLocalColor = ((const XFillColorItem&)(rLocalSet.Get(XATTR_FILLCOLOR))).GetColorValue(); + const XFillStyle eLocalFillStyle = ITEMVALUE(rLocalSet, XATTR_FILLSTYLE, XFillStyleItem); + const Color aLocalColor = ((const XFillColorItem&)(rLocalSet.Get(XATTR_FILLCOLOR))).GetColorValue(); - // ExtrudeObj einordnen + // sort in ExtrudeObj if(pLayer) { - // Gibt es eine Ueberschneidung mit einem Objekt dieses - // Layers? - BOOL bOverlap(FALSE); - E3dDepthNeighbour* pAct = pLayer->pNext; + // do we have overlap with an object of this layer? + bool bOverlap(false); + E3dDepthNeighbour* pAct = pLayer->mpNext; while(!bOverlap && pAct) { - // ueberlappen sich pAct->pObj und pExtrudeObj ? - const basegfx::B2DPolyPolygon aActPoly(pAct->pObj->GetExtrudePolygon()); - bOverlap = ImpDoesOverlap(aExtrudePoly, aActPoly); + // do pAct->mpObj and pExtrudeObj overlap? Check by + // using logical AND clipping + const basegfx::B2DPolyPolygon aAndPolyPolygon( + basegfx::tools::solvePolygonOperationAnd( + aExtrudePoly, + pAct->maPreparedPolyPolygon)); + + bOverlap = (0 != aAndPolyPolygon.count()); if(bOverlap) { // second ciriteria: is another fillstyle or color used? - const SfxItemSet& rCompareSet = pAct->pObj->GetMergedItemSet(); + const SfxItemSet& rCompareSet = pAct->mpObj->GetMergedItemSet(); XFillStyle eCompareFillStyle = ITEMVALUE(rCompareSet, XATTR_FILLSTYLE, XFillStyleItem); @@ -1201,71 +1166,74 @@ void E3dView::DoDepthArrange(E3dScene* pScene, double fDepth) } } - pAct = pAct->pNext; + pAct = pAct->mpNext; } if(bOverlap) { - // ja, beginne einen neuen Layer - pLayer->pDown = new E3dDepthLayer; - pLayer = pLayer->pDown; + // yes, start a new layer + pLayer->mpDown = new E3dDepthLayer; + pLayer = pLayer->mpDown; nNumLayers++; - pLayer->pNext = new E3dDepthNeighbour; - pLayer->pNext->pObj = pExtrudeObj; + pLayer->mpNext = new E3dDepthNeighbour; + pLayer->mpNext->mpObj = pExtrudeObj; + pLayer->mpNext->maPreparedPolyPolygon = aExtrudePoly; } else { - // nein, Objekt kann in aktuellen Layer + // no, add to current layer E3dDepthNeighbour* pNewNext = new E3dDepthNeighbour; - pNewNext->pObj = pExtrudeObj; - pNewNext->pNext = pLayer->pNext; - pLayer->pNext = pNewNext; + pNewNext->mpObj = pExtrudeObj; + pNewNext->maPreparedPolyPolygon = aExtrudePoly; + pNewNext->mpNext = pLayer->mpNext; + pLayer->mpNext = pNewNext; } } else { - // erster Layer ueberhaupt + // first layer ever pBaseLayer = new E3dDepthLayer; pLayer = pBaseLayer; nNumLayers++; - pLayer->pNext = new E3dDepthNeighbour; - pLayer->pNext->pObj = pExtrudeObj; + pLayer->mpNext = new E3dDepthNeighbour; + pLayer->mpNext->mpObj = pExtrudeObj; + pLayer->mpNext->maPreparedPolyPolygon = aExtrudePoly; } } } - // Anzahl Layer steht fest + // number of layers is done if(nNumLayers > 1) { - // Arrangement ist notwendig + // need to be arranged double fMinDepth = fDepth * 0.8; double fStep = (fDepth - fMinDepth) / (double)nNumLayers; pLayer = pBaseLayer; while(pLayer) { - // an pLayer entlangspazieren - E3dDepthNeighbour* pAct = pLayer->pNext; + // move along layer + E3dDepthNeighbour* pAct = pLayer->mpNext; while(pAct) { - // Anpassen - pAct->pObj->SetMergedItem(SfxUInt32Item(SDRATTR_3DOBJ_DEPTH, sal_uInt32(fMinDepth + 0.5))); + // adapt extrude value + pAct->mpObj->SetMergedItem(SfxUInt32Item(SDRATTR_3DOBJ_DEPTH, sal_uInt32(fMinDepth + 0.5))); - // Naechster Eintrag - pAct = pAct->pNext; + // next + pAct = pAct->mpNext; } - // naechster Layer - pLayer = pLayer->pDown; + // next layer + pLayer = pLayer->mpDown; fMinDepth += fStep; } } - // angelegte Strukturen aufraeumen + // cleanup while(pBaseLayer) { - pLayer = pBaseLayer->pDown; + pLayer = pBaseLayer->mpDown; delete pBaseLayer; pBaseLayer = pLayer; } diff --git a/svx/source/sdr/contact/viewcontactofmasterpagedescriptor.cxx b/svx/source/sdr/contact/viewcontactofmasterpagedescriptor.cxx index ba260e79bba9..cbe9c4a9c615 100644 --- a/svx/source/sdr/contact/viewcontactofmasterpagedescriptor.cxx +++ b/svx/source/sdr/contact/viewcontactofmasterpagedescriptor.cxx @@ -61,11 +61,30 @@ namespace sdr drawinglayer::primitive2d::Primitive2DSequence ViewContactOfMasterPageDescriptor::createViewIndependentPrimitive2DSequence() const { drawinglayer::primitive2d::Primitive2DSequence xRetval; + drawinglayer::attribute::SdrFillAttribute aFill; + const SdrPage* pCorrectPage = &GetMasterPageDescriptor().GetOwnerPage(); + const SdrPageProperties* pCorrectProperties = &pCorrectPage->getSdrPageProperties(); - // build primitive from page fill attributes - const SfxItemSet& rPageFillAttributes = GetMasterPageDescriptor().getCorrectFillAttributes(); - const drawinglayer::attribute::SdrFillAttribute aFill( - drawinglayer::primitive2d::createNewSdrFillAttribute(rPageFillAttributes)); + if(XFILL_NONE == ((const XFillStyleItem&)pCorrectProperties->GetItemSet().Get(XATTR_FILLSTYLE)).GetValue()) + { + pCorrectPage = &GetMasterPageDescriptor().GetUsedPage(); + pCorrectProperties = &pCorrectPage->getSdrPageProperties(); + } + + if(pCorrectPage->IsMasterPage() && !pCorrectProperties->GetStyleSheet()) + { + // #i110846# Suppress SdrPage FillStyle for MasterPages without StyleSheets, + // else the PoolDefault (XFILL_COLOR and Blue8) will be used. Normally, all + // MasterPages should have a StyleSheet excactly for this reason, but historically + // e.g. the Notes MasterPage has no StyleSheet set (and there maybe others). + pCorrectProperties = 0; + } + + if(pCorrectProperties) + { + // create page fill attributes when correct properties were identified + aFill = drawinglayer::primitive2d::createNewSdrFillAttribute(pCorrectProperties->GetItemSet()); + } if(!aFill.isDefault()) { diff --git a/svx/source/sdr/contact/viewcontactofsdrpage.cxx b/svx/source/sdr/contact/viewcontactofsdrpage.cxx index e486f978fafb..b80b6fcbba88 100644 --- a/svx/source/sdr/contact/viewcontactofsdrpage.cxx +++ b/svx/source/sdr/contact/viewcontactofsdrpage.cxx @@ -203,10 +203,18 @@ namespace sdr } else { - // build primitive from pObject's attributes - const SfxItemSet& rFillAttributes = rPage.getSdrPageProperties().GetItemSet(); - const drawinglayer::attribute::SdrFillAttribute aFill( - drawinglayer::primitive2d::createNewSdrFillAttribute(rFillAttributes)); + drawinglayer::attribute::SdrFillAttribute aFill; + + // #i110846# Suppress SdrPage FillStyle for MasterPages without StyleSheets, + // else the PoolDefault (XFILL_COLOR and Blue8) will be used. Normally, all + // MasterPages should have a StyleSheet excactly for this reason, but historically + // e.g. the Notes MasterPage has no StyleSheet set (and there maybe others). + if(rPage.getSdrPageProperties().GetStyleSheet()) + { + // create page fill attributes with correct properties + aFill = drawinglayer::primitive2d::createNewSdrFillAttribute( + rPage.getSdrPageProperties().GetItemSet()); + } if(!aFill.isDefault()) { diff --git a/svx/source/sdr/primitive2d/sdrpathprimitive2d.cxx b/svx/source/sdr/primitive2d/sdrpathprimitive2d.cxx index ac9b6307dd05..2ceea2c69b7d 100644 --- a/svx/source/sdr/primitive2d/sdrpathprimitive2d.cxx +++ b/svx/source/sdr/primitive2d/sdrpathprimitive2d.cxx @@ -51,13 +51,11 @@ namespace drawinglayer if(!getSdrLFSTAttribute().getFill().isDefault() && getUnitPolyPolygon().isClosed()) { - // take care for orientations - const basegfx::B2DPolyPolygon aOrientedUnitPolyPolygon( - basegfx::tools::correctOrientations(getUnitPolyPolygon())); - + // #i108255# no need to use correctOrientations here; target is + // straight visualisation appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, createPolyPolygonFillPrimitive( - aOrientedUnitPolyPolygon, + getUnitPolyPolygon(), getTransform(), getSdrLFSTAttribute().getFill(), getSdrLFSTAttribute().getFillFloatTransGradient())); diff --git a/svx/source/svdraw/sdrmasterpagedescriptor.cxx b/svx/source/svdraw/sdrmasterpagedescriptor.cxx index 6bcdd8f55856..67b2de8b693c 100644 --- a/svx/source/svdraw/sdrmasterpagedescriptor.cxx +++ b/svx/source/svdraw/sdrmasterpagedescriptor.cxx @@ -113,18 +113,6 @@ namespace sdr || &maUsedPage != &rCandidate.maUsedPage || maVisibleLayers != rCandidate.maVisibleLayers); } - - const SfxItemSet& MasterPageDescriptor::getCorrectFillAttributes() const - { - const SfxItemSet& rOwnerPageAtributes = GetOwnerPage().getSdrPageProperties().GetItemSet(); - - if(XFILL_NONE != ((const XFillStyleItem&)rOwnerPageAtributes.Get(XATTR_FILLSTYLE)).GetValue()) - { - return rOwnerPageAtributes; - } - - return GetUsedPage().getSdrPageProperties().GetItemSet(); - } } // end of namespace sdr ////////////////////////////////////////////////////////////////////////////// diff --git a/svx/source/svdraw/svdedtv.cxx b/svx/source/svdraw/svdedtv.cxx index 3b878ce93138..5eae04dbbc87 100644 --- a/svx/source/svdraw/svdedtv.cxx +++ b/svx/source/svdraw/svdedtv.cxx @@ -805,6 +805,12 @@ void SdrEditView::DeleteMarkedList(const SdrMarkList& rMark) void SdrEditView::DeleteMarkedObj() { + // #i110981# return when nothing is to be done at all + if(!GetMarkedObjectCount()) + { + return; + } + // moved breaking action and undo start outside loop BrkAction(); BegUndo(ImpGetResStr(STR_EditDelete),GetDescriptionOfMarkedObjects(),SDRREPFUNC_OBJ_DELETE); diff --git a/svx/source/svdraw/svdedtv2.cxx b/svx/source/svdraw/svdedtv2.cxx index e31ea11be7d6..8cf83c0429cc 100644 --- a/svx/source/svdraw/svdedtv2.cxx +++ b/svx/source/svdraw/svdedtv2.cxx @@ -1090,7 +1090,16 @@ void SdrEditView::MergeMarkedObjects(SdrMergeMode eMode) if(!bFirstObjectComplete) { - aMergePolyPolygonA = aTmpPoly; + // #i111987# Also need to collect ORed source shape when more than + // a single polygon is involved + if(aMergePolyPolygonA.count()) + { + aMergePolyPolygonA = basegfx::tools::solvePolygonOperationOr(aMergePolyPolygonA, aTmpPoly); + } + else + { + aMergePolyPolygonA = aTmpPoly; + } } else { diff --git a/svx/source/svdraw/svdfmtf.cxx b/svx/source/svdraw/svdfmtf.cxx index 445fe60c0670..34a77fcd9e62 100644 --- a/svx/source/svdraw/svdfmtf.cxx +++ b/svx/source/svdraw/svdfmtf.cxx @@ -85,6 +85,11 @@ ImpSdrGDIMetaFileImport::ImpSdrGDIMetaFileImport(SdrModel& rModel): bLastObjWasPolyWithoutLine(FALSE),bNoLine(FALSE),bNoFill(FALSE),bLastObjWasLine(FALSE) { aVD.EnableOutput(FALSE); + + // #i111954# init to no fill and no line initially + aVD.SetLineColor(); + aVD.SetFillColor(); + aOldLineColor.SetRed( aVD.GetLineColor().GetRed() + 1 ); // invalidate old line color pLineAttr=new SfxItemSet(rModel.GetItemPool(),XATTR_LINE_FIRST,XATTR_LINE_LAST); pFillAttr=new SfxItemSet(rModel.GetItemPool(),XATTR_FILL_FIRST,XATTR_FILL_LAST); @@ -380,17 +385,61 @@ void ImpSdrGDIMetaFileImport::InsertObj( SdrObject* pObj, sal_Bool bScale ) pObj->NbcMove( Size( aOfs.X(), aOfs.Y() ) ); } - aTmpList.InsertObject( pObj ); - if ( HAS_BASE( SdrPathObj, pObj ) ) + // #i111954# check object for visibility + // used are SdrPathObj, SdrRectObj, SdrCircObj, SdrGrafObj + bool bVisible(false); + + if(pObj->HasLineStyle()) + { + bVisible = true; + } + + if(!bVisible && pObj->HasFillStyle()) + { + bVisible = true; + } + + if(!bVisible) + { + SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >(pObj); + + if(pTextObj && pTextObj->HasText()) + { + bVisible = true; + } + } + + if(!bVisible) { - FASTBOOL bClosed=pObj->IsClosedObj(); - bLastObjWasPolyWithoutLine=bNoLine && bClosed; - bLastObjWasLine=!bClosed; + SdrGrafObj* pGrafObj = dynamic_cast< SdrGrafObj* >(pObj); + + if(pGrafObj) + { + // this may be refined to check if the graphic really is visible. It + // is here to ensure that graphic objects without fill, line and text + // get created + bVisible = true; + } + } + + if(!bVisible) + { + SdrObject::Free(pObj); } else { - bLastObjWasPolyWithoutLine = FALSE; - bLastObjWasLine = FALSE; + aTmpList.InsertObject( pObj ); + if ( HAS_BASE( SdrPathObj, pObj ) ) + { + FASTBOOL bClosed=pObj->IsClosedObj(); + bLastObjWasPolyWithoutLine=bNoLine && bClosed; + bLastObjWasLine=!bClosed; + } + else + { + bLastObjWasPolyWithoutLine = FALSE; + bLastObjWasLine = FALSE; + } } } diff --git a/svx/source/svdraw/svdocirc.cxx b/svx/source/svdraw/svdocirc.cxx index 12cdeac9ef85..4c600cba821f 100644 --- a/svx/source/svdraw/svdocirc.cxx +++ b/svx/source/svdraw/svdocirc.cxx @@ -239,8 +239,9 @@ basegfx::B2DPolygon SdrCircObj::ImpCalcXPolyCirc(const SdrObjKind eCicrleKind, c else { // mirror start, end for geometry creation since model coordinate system is mirrored in Y - const double fStart(((36000 - nEnd) % 36000) * F_PI18000); - const double fEnd(((36000 - nStart) % 36000) * F_PI18000); + // #i111715# increase numerical correctness by first dividing and not using F_PI1800 + const double fStart((((36000 - nEnd) % 36000) / 18000.0) * F_PI); + const double fEnd((((36000 - nStart) % 36000) / 18000.0) * F_PI); // create circle segment. This is not closed by default aCircPolygon = basegfx::tools::createPolygonFromEllipseSegment( diff --git a/svx/source/svdraw/svdoedge.cxx b/svx/source/svdraw/svdoedge.cxx index dc76855f05cc..6482c28befb9 100644 --- a/svx/source/svdraw/svdoedge.cxx +++ b/svx/source/svdraw/svdoedge.cxx @@ -1674,6 +1674,11 @@ void SdrEdgeObj::SetEdgeTrackPath( const basegfx::B2DPolyPolygon& rPoly ) *pEdgeTrack = XPolygon( rPoly.getB2DPolygon( 0 ) ); bEdgeTrackDirty = sal_False; bEdgeTrackUserDefined = sal_True; + + // #i110629# also set aRect and maSnapeRect dependent from pEdgeTrack + const Rectangle aPolygonBounds(pEdgeTrack->GetBoundRect()); + aRect = aPolygonBounds; + maSnapRect = aPolygonBounds; } } @@ -2206,17 +2211,31 @@ FASTBOOL SdrEdgeObj::ImpFindConnector(const Point& rPt, const SdrPageView& rPV, void SdrEdgeObj::NbcSetSnapRect(const Rectangle& rRect) { - Rectangle aOld(GetSnapRect()); - long nMulX = rRect.Right() - rRect.Left(); - long nDivX = aOld.Right() - aOld.Left(); - long nMulY = rRect.Bottom() - rRect.Top(); - long nDivY = aOld.Bottom() - aOld.Top(); - if ( nDivX == 0 ) { nMulX = 1; nDivX = 1; } - if ( nDivY == 0 ) { nMulY = 1; nDivY = 1; } - Fraction aX(nMulX, nDivX); - Fraction aY(nMulY, nDivY); - NbcResize(aOld.TopLeft(), aX, aY); - NbcMove(Size(rRect.Left() - aOld.Left(), rRect.Top() - aOld.Top())); + const Rectangle aOld(GetSnapRect()); + + if(aOld != rRect) + { + if(aRect.IsEmpty() && 0 == pEdgeTrack->GetPointCount()) + { + // #i110629# When initializing, do not scale on empty Rectangle; this + // will mirror the underlying text object (!) + aRect = rRect; + maSnapRect = rRect; + } + else + { + long nMulX = rRect.Right() - rRect.Left(); + long nDivX = aOld.Right() - aOld.Left(); + long nMulY = rRect.Bottom() - rRect.Top(); + long nDivY = aOld.Bottom() - aOld.Top(); + if ( nDivX == 0 ) { nMulX = 1; nDivX = 1; } + if ( nDivY == 0 ) { nMulY = 1; nDivY = 1; } + Fraction aX(nMulX, nDivX); + Fraction aY(nMulY, nDivY); + NbcResize(aOld.TopLeft(), aX, aY); + NbcMove(Size(rRect.Left() - aOld.Left(), rRect.Top() - aOld.Top())); + } + } } void SdrEdgeObj::NbcMove(const Size& rSiz) diff --git a/svx/source/svdraw/svdotextpathdecomposition.cxx b/svx/source/svdraw/svdotextpathdecomposition.cxx index f6780bd7c90d..031e8e9dd45b 100644 --- a/svx/source/svdraw/svdotextpathdecomposition.cxx +++ b/svx/source/svdraw/svdotextpathdecomposition.cxx @@ -107,15 +107,13 @@ namespace maLocale(rInfo.mpLocale ? *rInfo.mpLocale : ::com::sun::star::lang::Locale()), mbRTL(rInfo.mrFont.IsVertical() ? false : rInfo.IsRTL()) { - if(mnTextLength) + if(mnTextLength && rInfo.mpDXArray) { maDblDXArray.reserve(mnTextLength); - const sal_Int32 nFontWidth(0L == maFont.GetWidth() ? maFont.GetHeight() : maFont.GetWidth()); - const double fScaleFactor(0L != nFontWidth ? 1.0 / (double)nFontWidth : 1.0); for(xub_StrLen a(0); a < mnTextLength; a++) { - maDblDXArray.push_back((double)rInfo.mpDXArray[a] * fScaleFactor); + maDblDXArray.push_back((double)rInfo.mpDXArray[a]); } } } @@ -291,7 +289,8 @@ namespace const double fPolyLength(basegfx::tools::getLength(aPolygonCandidate)); double fPolyEnd(fPolyLength); double fPolyStart(0.0); - double fScaleFactor(1.0); + double fAutosizeScaleFactor(1.0); + bool bAutosizeScale(false); if(maSdrFormTextAttribute.getFormTextMirror()) { @@ -352,7 +351,8 @@ namespace // if scale, prepare scale factor between curve length and text length if(0.0 != fParagraphTextLength) { - fScaleFactor = (fPolyEnd - fPolyStart) / fParagraphTextLength; + fAutosizeScaleFactor = (fPolyEnd - fPolyStart) / fParagraphTextLength; + bAutosizeScale = true; } } } @@ -382,10 +382,10 @@ namespace // prepare portion length. Takes RTL sections into account. double fPortionLength(pCandidate->getDisplayLength(nUsedTextLength, nNextGlyphLen)); - if(XFT_AUTOSIZE == maSdrFormTextAttribute.getFormTextAdjust()) + if(bAutosizeScale) { - // when scaling, expand portion length - fPortionLength *= fScaleFactor; + // when autosize scaling, expand portion length + fPortionLength *= fAutosizeScaleFactor; } // create transformation @@ -397,10 +397,10 @@ namespace aNewTransformA.scale(aFontScaling.getX(), aFontScaling.getY()); // prepare scaling of text primitive - if(XFT_AUTOSIZE == maSdrFormTextAttribute.getFormTextAdjust()) + if(bAutosizeScale) { - // when scaling, expand text primitive scaling - aNewTransformA.scale(fScaleFactor, fScaleFactor); + // when autosize scaling, expand text primitive scaling to it + aNewTransformA.scale(fAutosizeScaleFactor, fAutosizeScaleFactor); } // eventually create shadow primitives from aDecomposition and add to rDecomposition @@ -497,17 +497,42 @@ namespace aNewTransformB.translate(aPerpendicular.getX(), aPerpendicular.getY()); } - // shadow primitive creation - if(bShadow) + if(pCandidate->getText().Len() && nNextGlyphLen) { - if(pCandidate->getText().Len() && nNextGlyphLen) + const xub_StrLen nPortionIndex(pCandidate->getPortionIndex(nUsedTextLength, nNextGlyphLen)); + ::std::vector< double > aNewDXArray; + + if(nNextGlyphLen > 1 && pCandidate->getDoubleDXArray().size()) { + // copy DXArray for portion + aNewDXArray.insert( + aNewDXArray.begin(), + pCandidate->getDoubleDXArray().begin() + nPortionIndex, + pCandidate->getDoubleDXArray().begin() + (nPortionIndex + nNextGlyphLen)); + + if(nPortionIndex > 0) + { + // adapt to portion start + double fDXOffset= *(pCandidate->getDoubleDXArray().begin() + (nPortionIndex - 1)); + ::std::transform( + aNewDXArray.begin(), aNewDXArray.end(), + aNewDXArray.begin(), ::std::bind2nd(::std::minus<double>(), fDXOffset)); + } + + if(bAutosizeScale) + { + // when autosize scaling, adapt to DXArray, too + ::std::transform( + aNewDXArray.begin(), aNewDXArray.end(), + aNewDXArray.begin(), ::std::bind2nd(::std::multiplies<double>(), fAutosizeScaleFactor)); + } + } + + if(bShadow) + { + // shadow primitive creation const Color aShadowColor(maSdrFormTextAttribute.getFormTextShdwColor()); const basegfx::BColor aRGBShadowColor(aShadowColor.getBColor()); - const xub_StrLen nPortionIndex(pCandidate->getPortionIndex(nUsedTextLength, nNextGlyphLen)); - const ::std::vector< double > aNewDXArray( - pCandidate->getDoubleDXArray().begin() + nPortionIndex, - pCandidate->getDoubleDXArray().begin() + nPortionIndex + nNextGlyphLen); drawinglayer::primitive2d::TextSimplePortionPrimitive2D* pNew = new drawinglayer::primitive2d::TextSimplePortionPrimitive2D( @@ -522,30 +547,25 @@ namespace mrShadowDecomposition.push_back(pNew); } - } - // primitive creation - if(pCandidate->getText().Len() && nNextGlyphLen) - { - const Color aColor(pCandidate->getFont().GetColor()); - const basegfx::BColor aRGBColor(aColor.getBColor()); - const xub_StrLen nPortionIndex(pCandidate->getPortionIndex(nUsedTextLength, nNextGlyphLen)); - const ::std::vector< double > aNewDXArray( - pCandidate->getDoubleDXArray().begin() + nPortionIndex, - pCandidate->getDoubleDXArray().begin() + nPortionIndex + nNextGlyphLen); - - drawinglayer::primitive2d::TextSimplePortionPrimitive2D* pNew = - new drawinglayer::primitive2d::TextSimplePortionPrimitive2D( - aNewTransformB * aNewTransformA, - pCandidate->getText(), - nPortionIndex, - nNextGlyphLen, - aNewDXArray, - aCandidateFontAttribute, - pCandidate->getLocale(), - aRGBColor); - - mrDecomposition.push_back(pNew); + { + // primitive creation + const Color aColor(pCandidate->getFont().GetColor()); + const basegfx::BColor aRGBColor(aColor.getBColor()); + + drawinglayer::primitive2d::TextSimplePortionPrimitive2D* pNew = + new drawinglayer::primitive2d::TextSimplePortionPrimitive2D( + aNewTransformB * aNewTransformA, + pCandidate->getText(), + nPortionIndex, + nNextGlyphLen, + aNewDXArray, + aCandidateFontAttribute, + pCandidate->getLocale(), + aRGBColor); + + mrDecomposition.push_back(pNew); + } } // consume from portion // no += here, xub_StrLen is USHORT and the compiler will gererate a warning here diff --git a/svx/source/svdraw/svdpage.cxx b/svx/source/svdraw/svdpage.cxx index 6dd816d429da..8da0b248f38b 100644 --- a/svx/source/svdraw/svdpage.cxx +++ b/svx/source/svdraw/svdpage.cxx @@ -1221,18 +1221,6 @@ SdrPageProperties::SdrPageProperties(SdrPage& rSdrPage) } } -SdrPageProperties::SdrPageProperties(const SdrPageProperties& rCandidate) -: SfxListener(), - mpSdrPage(rCandidate.mpSdrPage), - mpStyleSheet(0), - mpProperties(new SfxItemSet(*rCandidate.mpProperties)) -{ - if(rCandidate.GetStyleSheet()) - { - ImpAddStyleSheet(*rCandidate.GetStyleSheet()); - } -} - SdrPageProperties::~SdrPageProperties() { ImpRemoveStyleSheet(); @@ -1365,6 +1353,8 @@ SdrPage::SdrPage(const SdrPage& rSrcPage) // Warning: this leads to slicing (see issue 93186) and has to be // removed as soon as possible. *this = rSrcPage; + OSL_ENSURE(mpSdrPageProperties, + "SdrPage::SdrPage: operator= did not create needed SdrPageProperties (!)"); // be careful and correct eListKind, a member of SdrObjList which // will be changed by the SdrOIbjList::operator= before... @@ -1382,8 +1372,6 @@ SdrPage::SdrPage(const SdrPage& rSrcPage) mxUnoPage = NULL; xComponent->dispose(); } - - mpSdrPageProperties = new SdrPageProperties(rSrcPage.getSdrPageProperties()); } SdrPage::~SdrPage() @@ -1478,8 +1466,28 @@ void SdrPage::operator=(const SdrPage& rSrcPage) mbObjectsNotPersistent = rSrcPage.mbObjectsNotPersistent; { - delete mpSdrPageProperties; - mpSdrPageProperties = new SdrPageProperties(rSrcPage.getSdrPageProperties()); + // #i111122# delete SdrPageProperties when model is different + if(mpSdrPageProperties && GetModel() != rSrcPage.GetModel()) + { + delete mpSdrPageProperties; + mpSdrPageProperties = 0; + } + + if(!mpSdrPageProperties) + { + mpSdrPageProperties = new SdrPageProperties(*this); + } + else + { + mpSdrPageProperties->ClearItem(0); + } + + if(!IsMasterPage()) + { + mpSdrPageProperties->PutItemSet(rSrcPage.getSdrPageProperties().GetItemSet()); + } + + mpSdrPageProperties->SetStyleSheet(rSrcPage.getSdrPageProperties().GetStyleSheet()); } // Now copy the contained obejcts (by cloning them) @@ -1659,7 +1667,17 @@ void SdrPage::SetModel(SdrModel* pNewModel) } pLayerAdmin->SetModel(pNewModel); - SdrPageProperties *pNew = new SdrPageProperties(getSdrPageProperties()); + // create new SdrPageProperties with new model (due to SfxItemSet there) + // and copy ItemSet and StyleSheet + SdrPageProperties *pNew = new SdrPageProperties(*this); + + if(!IsMasterPage()) + { + pNew->PutItemSet(getSdrPageProperties().GetItemSet()); + } + + pNew->SetStyleSheet(getSdrPageProperties().GetStyleSheet()); + delete mpSdrPageProperties; mpSdrPageProperties = pNew; } |