svx/source/sdr/primitive2d/sdrdecompositiontools.cxx | 239 +++++++------------ 1 file changed, 93 insertions(+), 146 deletions(-)
New commits: commit b72d264aa2dfa4fba5ccd9f50a97dbc7e8d6cf6e Author: Armin Le Grand (allotropia) <armin.le.grand.ext...@allotropia.de> AuthorDate: Mon Jun 27 12:46:56 2022 +0200 Commit: Armin Le Grand <armin.le.gr...@me.com> CommitDate: Mon Jun 27 17:22:47 2022 +0200 tdf#149651 Correct the MasterPageBackgroundFill mode Had to massively adapt to what others do in this issue, moving from ViewContact(s) as main data source to FillStyle directly Change-Id: If48666212e2f0afac4fbfab9af4908a5d2b4c047 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136487 Tested-by: Jenkins Reviewed-by: Armin Le Grand <armin.le.gr...@me.com> diff --git a/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx b/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx index fba547f92cbb..4c7316b53be0 100644 --- a/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx +++ b/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx @@ -55,12 +55,8 @@ #include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx> #include <svx/unoapi.hxx> #include <svx/svdpage.hxx> -#include <svx/sdr/contact/viewcontact.hxx> -#include <svx/sdr/contact/objectcontact.hxx> -#include <svx/sdr/contact/viewobjectcontact.hxx> -#include <svx/sdr/contact/displayinfo.hxx> -#include <basegfx/polygon/b2dpolygonclipper.hxx> -#include <set> +#include <sdr/primitive2d/sdrattributecreator.hxx> +#include <sdr/contact/viewcontactofmasterpagedescriptor.hxx> using namespace com::sun::star; @@ -133,30 +129,61 @@ basegfx::B2DRange getTextAnchorRange(const attribute::SdrTextAttribute& rText, return aAnchorRange; } -sdr::contact::ViewContact* getMasterPageViewContact( +drawinglayer::attribute::SdrFillAttribute getMasterPageFillAttribute( const geometry::ViewInformation2D& rViewInformation, basegfx::B2DVector& rPageSize) { + drawinglayer::attribute::SdrFillAttribute aRetval; + // get SdrPage const SdrPage* pVisualizedPage(GetSdrPageFromXDrawPage(rViewInformation.getVisualizedPage())); - if(nullptr == pVisualizedPage) - return nullptr; - // do not use in MasterPage mode, so initial SdrPage shall *not* be a - // MasterPage - if(pVisualizedPage->IsMasterPage()) - return nullptr; + if(nullptr != pVisualizedPage) + { + // copy needed values for further processing + rPageSize.setX(pVisualizedPage->GetWidth()); + rPageSize.setY(pVisualizedPage->GetHeight()); - // we need that SdrPage to have a MasterPage - if(!pVisualizedPage->TRG_HasMasterPage()) - return nullptr; + if(pVisualizedPage->IsMasterPage()) + { + // the page is a MasterPage, so we are in MasterPage view + // still need #i110846#, see ViewContactOfMasterPage + if(pVisualizedPage->getSdrPageProperties().GetStyleSheet()) + { + // create page fill attributes with correct properties + aRetval = drawinglayer::primitive2d::createNewSdrFillAttribute( + pVisualizedPage->getSdrPageProperties().GetItemSet()); + } + } + else + { + // the page is *no* MasterPage, we are in normal Page view, get the MasterPage + if(pVisualizedPage->TRG_HasMasterPage()) + { + sdr::contact::ViewContact& rVC(pVisualizedPage->TRG_GetMasterPageDescriptorViewContact()); + sdr::contact::ViewContactOfMasterPageDescriptor* pVCOMPD( + dynamic_cast<sdr::contact::ViewContactOfMasterPageDescriptor*>(&rVC)); - // copy needed values for processing - rPageSize.setX(pVisualizedPage->GetWidth()); - rPageSize.setY(pVisualizedPage->GetHeight()); + if(nullptr != pVCOMPD) + { + // in this case the still needed #i110846# is part of + // getCorrectSdrPageProperties, that's the main reason to re-use + // that call/functionality here + const SdrPageProperties* pCorrectProperties( + pVCOMPD->GetMasterPageDescriptor().getCorrectSdrPageProperties()); + + if(pCorrectProperties) + { + // create page fill attributes when correct properties were identified + aRetval = drawinglayer::primitive2d::createNewSdrFillAttribute( + pCorrectProperties->GetItemSet()); + } + } + } + } + } - // return it's ViewContact - return &pVisualizedPage->TRG_GetMasterPageDescriptorViewContact(); + return aRetval; } // provide a Primitive2D for the SlideBackgroundFill-mode. It is capable @@ -164,18 +191,15 @@ sdr::contact::ViewContact* getMasterPageViewContact( // needed preparation of the geometry in an isolated and controllable // space and way. // It is currently simple buffered (due to being derived from -// BufferedDecompositionPrimitive2D) and detects if MasterPage changes +// BufferedDecompositionPrimitive2D) and detects if FillStyle changes class SlideBackgroundFillPrimitive2D final : public BufferedDecompositionPrimitive2D { private: /// the basegfx::B2DPolyPolygon geometry basegfx::B2DPolyPolygon maPolyPolygon; - /// the polygon fill color - to allow simple fallback if needed - basegfx::BColor maBColor; - - /// the last VC the geometry was created for - sdr::contact::ViewContact* mpLastVC; + /// the last SdrFillAttribute the geometry was created for + drawinglayer::attribute::SdrFillAttribute maLastFill; protected: // create decomposition data @@ -186,8 +210,7 @@ protected: public: /// constructor SlideBackgroundFillPrimitive2D( - const basegfx::B2DPolyPolygon& rPolyPolygon, - const basegfx::BColor& rBColor); + const basegfx::B2DPolyPolygon& rPolyPolygon); /// check existing decomposition data, call parent virtual void get2DDecomposition( @@ -196,7 +219,6 @@ public: /// data read access const basegfx::B2DPolyPolygon& getB2DPolyPolygon() const { return maPolyPolygon; } - const basegfx::BColor& getBColor() const { return maBColor; } /// compare operator virtual bool operator==(const BasePrimitive2D& rPrimitive) const override; @@ -209,12 +231,10 @@ public: }; SlideBackgroundFillPrimitive2D::SlideBackgroundFillPrimitive2D( - const basegfx::B2DPolyPolygon& rPolyPolygon, - const basegfx::BColor& rBColor) + const basegfx::B2DPolyPolygon& rPolyPolygon) : BufferedDecompositionPrimitive2D() , maPolyPolygon(rPolyPolygon) -, maBColor(rBColor) -, mpLastVC(nullptr) +, maLastFill() { } @@ -223,90 +243,44 @@ void SlideBackgroundFillPrimitive2D::create2DDecomposition( const geometry::ViewInformation2D& rViewInformation) const { basegfx::B2DVector aPageSize; - sdr::contact::ViewContact* pViewContact(getMasterPageViewContact(rViewInformation, aPageSize)); - - // Check that we have a referenced SdrPage that is no MasterPage itself and has a MasterPage, - // we got it's ViewContact in pViewContact - if(nullptr != pViewContact) - { - // Get PolygonRange of own local geometry - const basegfx::B2DRange aPolygonRange(getB2DPolyPolygon().getB2DRange()); - - // if local geometry is empty, nothing will be shown, we are done - if(aPolygonRange.isEmpty()) - return; - - // Get PageRange - const basegfx::B2DRange aPageRange(0.0, 0.0, aPageSize.getX(), aPageSize.getY()); - - // if local geometry does not overlap with PageRange, nothing will be shown, we are done - if(!aPageRange.overlaps(aPolygonRange)) - return; - // Get the geometry + // get fill from target Page, this will check for all needed things + // like MasterPage/relationships, etc. (see getMasterPageFillAttribute impl above) + drawinglayer::attribute::SdrFillAttribute aFill( + getMasterPageFillAttribute(rViewInformation, aPageSize)); - // Add the MasterPage BG fill (if used, e.g. Picture/gradient, ...) - pViewContact->getViewIndependentPrimitive2DContainer(rContainer); - - // To create the MasterPage's ObjectHierarchy we need an ObjectContact (AKA View-side of things). - // We do not have one, but can use a temporary one anytime for temporary work. That whole VC/VOC/OC - // is designed to work with on-demand temporary objects if needed - sdr::contact::ObjectContact aObjectContact; - - // get the VOC from it (gets created) - sdr::contact::ViewObjectContact& rViewObjectContact(pViewContact->GetViewObjectContact(aObjectContact)); - sdr::contact::DisplayInfo aDisplayInfo; - - // we need this DisplayInfo-flag here - exceptionally - to get the same output as - // if the MasterPage is used as sub-content when creating geometry content for - // the non-MasterPage-view - aDisplayInfo.SetSubContentActive(true); + // if fill is on default (empty), nothing will be shown, we are done + if(aFill.isDefault()) + return; - // get the full MasterPage ObjectHierarchy - rViewObjectContact.getPrimitive2DSequenceSubHierarchy(aDisplayInfo, rContainer); + // Get PolygonRange of own local geometry + const basegfx::B2DRange aPolygonRange(getB2DPolyPolygon().getB2DRange()); - if(!rContainer.empty()) - { - // We got the geometry, but it may overlap the PageBounds of the - // Page/MasterPage, thus showing more beyond the PageBorders than - // the regular PageView does and is intended. - // This is independent from the geometry we collected in rContainer - // since the defining geometry is the getB2DPolyPolygon() one. - // We have already checked above that it's no empty and overlaps - // somehow. - // It also might be completely inside the PageRange. If not, we - // additionally would need to mask the content against PageBounds, - // so using potentially two different MaskPrimitive2D's. - // Since in this case we have a PolyPolygon and a B2DRange it is cheaper - // to geometrically clip that PolyPolygon geometry and use it - basegfx::B2DPolyPolygon aPolyPolygon(getB2DPolyPolygon()); - - if(!aPageRange.isInside(aPolygonRange)) - { - // we need to clip local geometry against PageBounds - aPolyPolygon = basegfx::utils::clipPolyPolygonOnRange( - aPolyPolygon, - aPageRange, - true /* bInside, use inside geometry */, - false /* bStroke, handle as filled PolyPolygon */); - } + // if local geometry is empty, nothing will be shown, we are done + if(aPolygonRange.isEmpty()) + return; - // create MaskPrimitive2D to limit display to PolygonGeometry - const Primitive2DReference aMasked( - new MaskPrimitive2D( - std::move(aPolyPolygon), - std::move(rContainer))); + // Get PageRange + const basegfx::B2DRange aPageRange(0.0, 0.0, aPageSize.getX(), aPageSize.getY()); - rContainer = Primitive2DContainer { aMasked }; - return; - } - } + // if local geometry does not overlap with PageRange, nothing will be shown, we are done + if(!aPageRange.overlaps(aPolygonRange)) + return; - // fallback: create as if drawing::FillStyle_SOLID was used - rContainer.push_back( - new PolyPolygonColorPrimitive2D( - getB2DPolyPolygon(), - getBColor())); + // create FillPrimitive2D with the geometry (the PolyPolygon) and + // the page's definitonRange to: + // - on one hand limit to geometry + // - on the other hand allow continutation of fill outside of + // MasterPage's range + const attribute::FillGradientAttribute aEmptyFillTransparenceGradient; + const Primitive2DReference aCreatedFill( + createPolyPolygonFillPrimitive( + getB2DPolyPolygon(), // geometry + aPageRange, // definition range + aFill, + aEmptyFillTransparenceGradient)); + + rContainer = Primitive2DContainer { aCreatedFill }; } void SlideBackgroundFillPrimitive2D::get2DDecomposition( @@ -314,11 +288,13 @@ void SlideBackgroundFillPrimitive2D::get2DDecomposition( const geometry::ViewInformation2D& rViewInformation) const { basegfx::B2DVector aPageSize; - sdr::contact::ViewContact* pViewContact(getMasterPageViewContact(rViewInformation, aPageSize)); + drawinglayer::attribute::SdrFillAttribute aFill; if(!getBuffered2DDecomposition().empty()) { - if(nullptr != pViewContact && pViewContact != mpLastVC) + aFill = getMasterPageFillAttribute(rViewInformation, aPageSize); + + if(!(aFill == maLastFill)) { // conditions of last local decomposition have changed, delete const_cast< SlideBackgroundFillPrimitive2D* >(this)->setBuffered2DDecomposition(Primitive2DContainer()); @@ -327,39 +303,12 @@ void SlideBackgroundFillPrimitive2D::get2DDecomposition( if(getBuffered2DDecomposition().empty()) { - // remember last MasterPageViewContact - const_cast< SlideBackgroundFillPrimitive2D* >(this)->mpLastVC = pViewContact; - } - - // tdf#149650 allow remember/detect of potential recursion for content creation. - // use a std::set association - instead of a single bool or address - due to the - // possibility of multiple SlideBackgroundFillPrimitive2D's being used at the same - // refresh. Also possible would be a local member (bool), but that just makes the - // class more complicated. Working with the address is not a problem here since below - // it reliably gets added/removed while being incarnated only. - static std::set<const SlideBackgroundFillPrimitive2D*> potentiallyActiveRecursion; - - if(potentiallyActiveRecursion.end() != potentiallyActiveRecursion.find(this)) - { - // The method getPrimitive2DSequenceSubHierarchy used in create2DDecomposition - // above has the potential to create a recursion, e.g. when the content of a page - // contains a SdrPageObj that again displays the page content (and potentially so - // on). - // This is valid, but works like a fractal, showing page content - // smaller and smaller inside a page. This needs to be controlled here to avoid - // the recursion. In this case just allow one single step since - // we are mainly interested in the page's BG fill anyways - return; + // remember last Fill + const_cast< SlideBackgroundFillPrimitive2D* >(this)->maLastFill = aFill; } - // remember that we enter a potential recursion - potentiallyActiveRecursion.insert(this); - // use parent implementation BufferedDecompositionPrimitive2D::get2DDecomposition(rVisitor, rViewInformation); - - // forget about potential recursion - potentiallyActiveRecursion.extract(this); } bool SlideBackgroundFillPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const @@ -369,8 +318,7 @@ bool SlideBackgroundFillPrimitive2D::operator==(const BasePrimitive2D& rPrimitiv const SlideBackgroundFillPrimitive2D& rCompare = static_cast<const SlideBackgroundFillPrimitive2D&>(rPrimitive); - return (getB2DPolyPolygon() == rCompare.getB2DPolyPolygon() - && getBColor() == rCompare.getBColor()); + return getB2DPolyPolygon() == rCompare.getB2DPolyPolygon(); } return false; @@ -450,8 +398,7 @@ sal_uInt32 SlideBackgroundFillPrimitive2D::getPrimitive2DID() const // create needed Primitive2D representation for // SlideBackgroundFill-mode pNewFillPrimitive = new SlideBackgroundFillPrimitive2D( - rPolyPolygon, - rFill.getColor()); + rPolyPolygon); } else {