include/svx/framelink.hxx | 109 - include/svx/framelinkarray.hxx | 5 include/svx/sdr/primitive2d/sdrframeborderprimitive2d.hxx | 119 ++ include/svx/sdr/primitive2d/svx_primitivetypes2d.hxx | 1 svx/Library_svxcore.mk | 1 svx/source/dialog/framelink.cxx | 467 -------- svx/source/dialog/framelinkarray.cxx | 260 +--- svx/source/sdr/primitive2d/sdrframeborderprimitive2d.cxx | 768 ++++++++++++++ sw/source/core/layout/paintfrm.cxx | 194 +-- 9 files changed, 1078 insertions(+), 846 deletions(-)
New commits: commit 1b9bc3c3f6f3fb31802be37592fcf4153d3d420d Author: Armin Le Grand <[email protected]> AuthorDate: Mon Oct 22 10:33:03 2018 +0200 Commit: Thorsten Behrens <[email protected]> CommitDate: Wed Oct 24 20:57:51 2018 +0200 Reorganize FrameBorderPrimitive creation Step1: Basic concept, move stuff to svx and new SdrFrameBorderPrimitive2D Step2: Adapt all creators/usages to use SdrFrameBorderData/SdrFrameBorderPrimitive2D, check functionality Step3: Re-implement mergre of BorderLinePrimitive2D during decomposition of SdrFrameBorderPrimitive2D to keep the number of primitives low from the start, make merge optional (not urgently needed) Step4: Migrate and isolate all helper methods and classes involved in geometry creation of border lines to the implementation (.cxx) of the new primitive Change-Id: I840b6765439bd995f2c57ef36315427b1f0f3e21 Reviewed-on: https://gerrit.libreoffice.org/62247 Tested-by: Jenkins Reviewed-by: Armin Le Grand <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/62309 Reviewed-by: Thorsten Behrens <[email protected]> Tested-by: Thorsten Behrens <[email protected]> diff --git a/include/svx/framelink.hxx b/include/svx/framelink.hxx index 65f1920fd093..5861b9eb58f2 100644 --- a/include/svx/framelink.hxx +++ b/include/svx/framelink.hxx @@ -201,115 +201,6 @@ public: inline bool operator>( const Style& rL, const Style& rR ) { return rR.operator<(rL); } -// Drawing functions -class SAL_WARN_UNUSED SVX_DLLPUBLIC StyleVectorCombination -{ -private: - struct OffsetAndHalfWidthAndColor - { - double mfOffset; - double mfHalfWidth; - Color maColor; - - OffsetAndHalfWidthAndColor(double offset, double halfWidth, Color color) : - mfOffset(offset), - mfHalfWidth(halfWidth), - maColor(color) - {} - }; - - double mfRefModeOffset; - basegfx::B2DVector maB2DVector; - double mfAngle; - std::vector< OffsetAndHalfWidthAndColor > maOffsets; - -public: - StyleVectorCombination( - const Style& rStyle, - const basegfx::B2DVector& rB2DVector, - const double fAngle, - bool bMirrored, - const Color* pForceColor = nullptr); - - double getRefModeOffset() const { return mfRefModeOffset; } - const basegfx::B2DVector& getB2DVector() const { return maB2DVector; } - double getAngle() const { return mfAngle; } - bool empty() const { return maOffsets.empty(); } - size_t size() const { return maOffsets.size(); } - bool operator<( const StyleVectorCombination& rOther) const { return mfAngle < rOther.mfAngle; } - - void getColorAndOffsetAndHalfWidth(size_t nIndex, Color& rColor, double& rfOffset, double& rfHalfWidth) const; -}; - -class SAL_WARN_UNUSED SVX_DLLPUBLIC StyleVectorTable -{ -private: - std::vector< StyleVectorCombination > maEntries; - -public: - StyleVectorTable() - : maEntries() - { - } - - void add( - const Style& rStyle, - const basegfx::B2DVector& rMyVector, - const basegfx::B2DVector& rOtherVector, - bool bMirrored); - - void sort(); - - bool empty() const { return maEntries.empty(); } - size_t size() const { return maEntries.size(); } - const std::vector< StyleVectorCombination >& getEntries() const{ return maEntries; } -}; - -/** - * Helper method to create the correct drawinglayer::primitive2d::BorderLinePrimitive2D - * for the given data, especially the correct drawinglayer::primitive2d::BorderLine entries - * including the correctly solved/created LineStartEnd extends - * - * rTarget : Here the evtl. created BorderLinePrimitive2D will be appended - * rOrigin : StartPoint of the Borderline - * rX : Vector of the Borderline - * rBorder : svx::frame::Style of the of the Borderline - * rStartStyleVectorTable : All other Borderlines which have to be taken into account because - * they have the same StartPoint as the current Borderline. These will be used to calculate - * the correct LineStartEnd extends tor the BorderLinePrimitive2D. The definition should be - * built up using svx::frame::StyleVectorTable and StyleVectorTable::add and includes: - * rStyle : the svx::frame::Style of one other BorderLine - * rMyVector : the Vector of the *new* to-be-defined BorderLine, identical to rX - * rOtherVector: the Vector of one other BorderLine (may be, but does not need to be normalized), - * always *pointing away* from the common StartPoint rOrigin - * bMirrored : define if rStyle of one other BorderLine shall be mirrored (e.g. bottom-right edges) - * With multiple BorderLines the definitions have to be CounterClockWise. This will be - * ensured by StyleVectorTable sorting the entries, but knowing this may allow more efficcient - * data creation. - * rEndStyleVectorTable: All other BorderLines that have the same EndPoint. There are differences to - * the Start definitions: - * - do not forget to consequently use -rX for rMyVector - * - definitions have to be ClockWise for the EndBorderLines, will be ensured by sorting - * - * If you take all this into account, you will gett correctly extended BorderLinePrimitive2D - * reprsentations for the new to be defined BorderLine. That extensions will overlap nicely - * with the corresponding BordreLines and take all multiple line definitions in the ::Style into - * account. - * The internal solver is *not limitied* to ::Style(s) with three parts (Left/Gap/Right), this is - * just due to svx::frame::Style's definitions. A new solver based on this one can be created - * anytime using more mulötiple borders based on the more flexible - * std::vector< drawinglayer::primitive2d::BorderLine > if needed. - */ -SVX_DLLPUBLIC void CreateBorderPrimitives( - drawinglayer::primitive2d::Primitive2DContainer& rTarget, /// target for created primitives - const basegfx::B2DPoint& rOrigin, /// start point of borderline - const basegfx::B2DVector& rX, /// X-Axis of borderline with length - const Style& rBorder, /// Style of borderline - const StyleVectorTable& rStartStyleVectorTable, /// Styles and vectors (pointing away) at borderline start, ccw - const StyleVectorTable& rEndStyleVectorTable, /// Styles and vectors (pointing away) at borderline end, cw - const Color* pForceColor /// If specified, overrides frame border color. -); - } } diff --git a/include/svx/framelinkarray.hxx b/include/svx/framelinkarray.hxx index c2c207cec5a8..7a4d8e9df640 100644 --- a/include/svx/framelinkarray.hxx +++ b/include/svx/framelinkarray.hxx @@ -323,11 +323,6 @@ private: ArrayImplPtr mxImpl; }; -// helper to merge B2DPrimitive(s) in rSource and add to rTarget -void SVX_DLLPUBLIC HelperMergeInB2DPrimitiveArray( - const drawinglayer::primitive2d::Primitive2DContainer& rSource, - drawinglayer::primitive2d::Primitive2DContainer& rTarget); - } } diff --git a/include/svx/sdr/primitive2d/sdrframeborderprimitive2d.hxx b/include/svx/sdr/primitive2d/sdrframeborderprimitive2d.hxx new file mode 100755 index 000000000000..611ec6b20285 --- /dev/null +++ b/include/svx/sdr/primitive2d/sdrframeborderprimitive2d.hxx @@ -0,0 +1,119 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDRFRAMEBORDERPRIMITIVE2D_HXX +#define INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDRFRAMEBORDERPRIMITIVE2D_HXX + +#include <drawinglayer/primitive2d/baseprimitive2d.hxx> +#include <svx/framelink.hxx> + +// predefines + +namespace drawinglayer +{ + namespace primitive2d + { + class SVX_DLLPUBLIC SdrFrameBorderData + { + private: + basegfx::B2DPoint maOrigin; /// start point of borderline + basegfx::B2DVector maX; /// X-Axis of borderline with length + svx::frame::Style maStyle; /// Style of borderline + Color maColor; + bool mbForceColor; + + class SdrConnectStyleData + { + private: + svx::frame::Style maStyle; + basegfx::B2DVector maNormalizedPerpendicular; + bool mbStyleMirrored; + + public: + SdrConnectStyleData( + const svx::frame::Style& rStyle, + const basegfx::B2DVector& rNormalizedPerpendicular, + bool bStyleMirrored); + + const svx::frame::Style& getStyle() const { return maStyle; } + const basegfx::B2DVector& getNormalizedPerpendicular() const { return maNormalizedPerpendicular; } + bool getStyleMirrored() const { return mbStyleMirrored; } + }; + + std::vector<SdrConnectStyleData> maStart; + std::vector<SdrConnectStyleData> maEnd; + + public: + SdrFrameBorderData( + const basegfx::B2DPoint& rOrigin, + const basegfx::B2DVector& rX, + const svx::frame::Style& rStyle, + const Color* pForceColor); + + void addSdrConnectStyleData( + bool bStart, + const svx::frame::Style& rStyle, + const basegfx::B2DVector& rNormalizedPerpendicular, + bool bStyleMirrored); + + void create2DDecomposition(Primitive2DContainer& rContainer) const; + }; + + typedef std::vector<SdrFrameBorderData> SdrFrameBorderDataVector; + + } // end of namespace primitive2d +} // end of namespace drawinglayer + +namespace drawinglayer +{ + namespace primitive2d + { + class SVX_DLLPUBLIC SdrFrameBorderPrimitive2D : public BufferedDecompositionPrimitive2D + { + private: + std::shared_ptr<SdrFrameBorderDataVector> maFrameBorders; + bool mbMergeResult; + + protected: + // local decomposition. + virtual Primitive2DContainer create2DDecomposition( + const geometry::ViewInformation2D& aViewInformation) const override; + + public: + SdrFrameBorderPrimitive2D( + std::shared_ptr<SdrFrameBorderDataVector>& rFrameBorders, + bool bMergeResult); + + // compare operator + virtual bool operator==(const BasePrimitive2D& rPrimitive) const override; + + // data access + const SdrFrameBorderDataVector& getFrameBorders() const { return *maFrameBorders.get(); } + bool getMergeResult() const { return mbMergeResult; } + + // provide unique ID + DeclPrimitive2DIDBlock() + }; + } // end of namespace primitive2d +} // end of namespace drawinglayer + + +#endif // INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDRFRAMEBORDERPRIMITIVE2D_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/svx/sdr/primitive2d/svx_primitivetypes2d.hxx b/include/svx/sdr/primitive2d/svx_primitivetypes2d.hxx index d2a16623dd02..d6cb948a6bf6 100644 --- a/include/svx/sdr/primitive2d/svx_primitivetypes2d.hxx +++ b/include/svx/sdr/primitive2d/svx_primitivetypes2d.hxx @@ -47,6 +47,7 @@ #define PRIMITIVE2D_ID_SDROLECONTENTPRIMITIVE2D (PRIMITIVE2D_ID_RANGE_SVX| 21) #define PRIMITIVE2D_ID_SDRAUTOFITTEXTPRIMITIVE2D (PRIMITIVE2D_ID_RANGE_SVX| 22) #define PRIMITIVE2D_ID_SDRCHAINEDTEXTPRIMITIVE2D (PRIMITIVE2D_ID_RANGE_SVX| 23) +#define PRIMITIVE2D_ID_SDRFRAMEBORDERTPRIMITIVE2D (PRIMITIVE2D_ID_RANGE_SVX| 24) #endif // INCLUDED_SVX_SDR_PRIMITIVE2D_SVX_PRIMITIVETYPES2D_HXX diff --git a/svx/Library_svxcore.mk b/svx/Library_svxcore.mk index 4bb7dcab835f..8c58029d5949 100644 --- a/svx/Library_svxcore.mk +++ b/svx/Library_svxcore.mk @@ -247,6 +247,7 @@ $(eval $(call gb_Library_add_exception_objects,svxcore,\ svx/source/sdr/primitive2d/sdrcaptionprimitive2d \ svx/source/sdr/primitive2d/sdrconnectorprimitive2d \ svx/source/sdr/primitive2d/sdrmeasureprimitive2d \ + svx/source/sdr/primitive2d/sdrframeborderprimitive2d \ svx/source/sdr/primitive2d/sdrattributecreator \ svx/source/sdr/primitive2d/sdrdecompositiontools \ svx/source/sdr/primitive3d/sdrattributecreator3d \ diff --git a/svx/source/dialog/framelink.cxx b/svx/source/dialog/framelink.cxx index 4474602c78c6..80dd02450576 100644 --- a/svx/source/dialog/framelink.cxx +++ b/svx/source/dialog/framelink.cxx @@ -28,10 +28,6 @@ #include <tools/gen.hxx> #include <editeng/borderline.hxx> #include <svtools/borderhelper.hxx> - -#include <basegfx/polygon/b2dpolygon.hxx> -#include <basegfx/polygon/b2dpolygontools.hxx> - #include <drawinglayer/primitive2d/borderlineprimitive2d.hxx> @@ -334,469 +330,6 @@ bool Style::operator<( const Style& rOther) const // seem to be equal return false; } - -// Drawing functions -struct CutSet -{ - double mfOLML; - double mfORML; - double mfOLMR; - double mfORMR; - - CutSet() : mfOLML(0.0), mfORML(0.0), mfOLMR(0.0), mfORMR(0.0) - { - } - - bool operator<( const CutSet& rOther) const - { - const double fA(mfOLML + mfORML + mfOLMR + mfORMR); - const double fB(rOther.mfOLML + rOther.mfORML + rOther.mfOLMR + rOther.mfORMR); - - return fA < fB; - } - - double getSum() const { return mfOLML + mfORML + mfOLMR + mfORMR; } - } ; - -struct ExtendSet -{ - double mfExtLeft; - double mfExtRight; - - ExtendSet() : mfExtLeft(0.0), mfExtRight(0.0) {} -}; - -void getCutSet( - CutSet& rCutSet, - const basegfx::B2DPoint& rLeft, - const basegfx::B2DPoint& rRight, - const basegfx::B2DVector& rX, - const basegfx::B2DPoint& rOtherLeft, - const basegfx::B2DPoint& rOtherRight, - const basegfx::B2DVector& rOtherX) -{ - basegfx::tools::findCut( - rLeft, - rX, - rOtherLeft, - rOtherX, - CutFlagValue::LINE, - &rCutSet.mfOLML); - - basegfx::tools::findCut( - rRight, - rX, - rOtherLeft, - rOtherX, - CutFlagValue::LINE, - &rCutSet.mfOLMR); - - basegfx::tools::findCut( - rLeft, - rX, - rOtherRight, - rOtherX, - CutFlagValue::LINE, - &rCutSet.mfORML); - - basegfx::tools::findCut( - rRight, - rX, - rOtherRight, - rOtherX, - CutFlagValue::LINE, - &rCutSet.mfORMR); -} - -void getExtends( - std::vector<ExtendSet>& rExtendSet, // target Left/Right values to fill - const basegfx::B2DPoint& rOrigin, // own vector start - const StyleVectorCombination& rCombination, // own vector and offstets for lines - const basegfx::B2DVector& rPerpendX, // normalized perpendicular to own vector - const std::vector< StyleVectorCombination >& rStyleVector) // other vectors emerging in this point -{ - if(!rCombination.empty() && !rStyleVector.empty() && rCombination.size() == rExtendSet.size()) - { - const size_t nOffsetA(rCombination.size()); - - if(1 == nOffsetA) - { - Color aMyColor; double fMyOffset(0.0); double fMyHalfWidth(0.0); - rCombination.getColorAndOffsetAndHalfWidth(0, aMyColor, fMyOffset, fMyHalfWidth); - - if(0xff != aMyColor.GetTransparency()) - { - const basegfx::B2DPoint aLeft(rOrigin + (rPerpendX * (fMyOffset - fMyHalfWidth))); - const basegfx::B2DPoint aRight(rOrigin + (rPerpendX * (fMyOffset + fMyHalfWidth))); - std::vector< CutSet > aCutSets; - - for(const auto& rStyleCandidate : rStyleVector) - { - const basegfx::B2DVector aOtherPerpend(basegfx::getNormalizedPerpendicular(rStyleCandidate.getB2DVector())); - const size_t nOffsetB(rStyleCandidate.size()); - - for(size_t other(0); other < nOffsetB; other++) - { - Color aOtherColor; double fOtherOffset(0.0); double fOtherHalfWidth(0.0); - rStyleCandidate.getColorAndOffsetAndHalfWidth(other, aOtherColor, fOtherOffset, fOtherHalfWidth); - - if(0xff != aOtherColor.GetTransparency()) - { - const basegfx::B2DPoint aOtherLeft(rOrigin + (aOtherPerpend * (fOtherOffset - fOtherHalfWidth))); - const basegfx::B2DPoint aOtherRight(rOrigin + (aOtherPerpend * (fOtherOffset + fOtherHalfWidth))); - - CutSet aNewCutSet; - getCutSet(aNewCutSet, aLeft, aRight, rCombination.getB2DVector(), aOtherLeft, aOtherRight, rStyleCandidate.getB2DVector()); - aCutSets.push_back(aNewCutSet); - } - } - } - - if(!aCutSets.empty()) - { - CutSet aCutSet(aCutSets[0]); - const size_t nNumCutSets(aCutSets.size()); - - if(1 != nNumCutSets) - { - double fCutSet(aCutSet.getSum()); - - for(size_t a(1); a < nNumCutSets; a++) - { - const CutSet& rCandidate(aCutSets[a]); - const double fCandidate(rCandidate.getSum()); - - if(basegfx::fTools::equalZero(fCandidate - fCutSet)) - { - // both have equal center point, use medium cut - const double fNewOLML(std::max(std::min(rCandidate.mfOLML, rCandidate.mfORML), std::min(aCutSet.mfOLML, aCutSet.mfORML))); - const double fNewORML(std::min(std::max(rCandidate.mfOLML, rCandidate.mfORML), std::max(aCutSet.mfOLML, aCutSet.mfORML))); - const double fNewOLMR(std::max(std::min(rCandidate.mfOLMR, rCandidate.mfORMR), std::min(aCutSet.mfOLMR, aCutSet.mfORMR))); - const double fNewORMR(std::min(std::max(rCandidate.mfOLMR, rCandidate.mfORMR), std::max(aCutSet.mfOLMR, aCutSet.mfORMR))); - aCutSet.mfOLML = fNewOLML; - aCutSet.mfORML = fNewORML; - aCutSet.mfOLMR = fNewOLMR; - aCutSet.mfORMR = fNewORMR; - fCutSet = aCutSet.getSum(); - } - else if(fCandidate < fCutSet) - { - // get minimum - fCutSet = fCandidate; - aCutSet = rCandidate; - } - } - } - - ExtendSet& rExt(rExtendSet[0]); - - rExt.mfExtLeft = std::min(aCutSet.mfOLML, aCutSet.mfORML); - rExt.mfExtRight = std::min(aCutSet.mfOLMR, aCutSet.mfORMR); - } - } - } - else - { - size_t nVisEdgeUp(0); - size_t nVisEdgeDn(0); - - for(size_t my(0); my < nOffsetA; my++) - { - Color aMyColor; double fMyOffset(0.0); double fMyHalfWidth(0.0); - rCombination.getColorAndOffsetAndHalfWidth(my, aMyColor, fMyOffset, fMyHalfWidth); - - if(0xff != aMyColor.GetTransparency()) - { - const basegfx::B2DPoint aLeft(rOrigin + (rPerpendX * (fMyOffset - fMyHalfWidth))); - const basegfx::B2DPoint aRight(rOrigin + (rPerpendX * (fMyOffset + fMyHalfWidth))); - const bool bUpper(my <= (nOffsetA >> 1)); - const StyleVectorCombination& rStyleCandidate(bUpper ? rStyleVector.front() : rStyleVector.back()); - const basegfx::B2DVector aOtherPerpend(basegfx::getNormalizedPerpendicular(rStyleCandidate.getB2DVector())); - const size_t nOffsetB(rStyleCandidate.size()); - std::vector< CutSet > aCutSets; - - for(size_t other(0); other < nOffsetB; other++) - { - Color aOtherColor; double fOtherOffset(0.0); double fOtherHalfWidth(0.0); - rStyleCandidate.getColorAndOffsetAndHalfWidth(other, aOtherColor, fOtherOffset, fOtherHalfWidth); - - if(0xff != aOtherColor.GetTransparency()) - { - const basegfx::B2DPoint aOtherLeft(rOrigin + (aOtherPerpend * (fOtherOffset - fOtherHalfWidth))); - const basegfx::B2DPoint aOtherRight(rOrigin + (aOtherPerpend * (fOtherOffset + fOtherHalfWidth))); - CutSet aCutSet; - getCutSet(aCutSet, aLeft, aRight, rCombination.getB2DVector(), aOtherLeft, aOtherRight, rStyleCandidate.getB2DVector()); - aCutSets.push_back(aCutSet); - } - } - - if(!aCutSets.empty()) - { - // sort: min to start, max to end - std::sort(aCutSets.begin(), aCutSets.end()); - const bool bOtherUpper(rStyleCandidate.getAngle() > F_PI); - - // check if we need min or max - // bUpper bOtherUpper MinMax - // t t max - // t f min - // f f max - // f t min - const bool bMax(bUpper == bOtherUpper); - size_t nBaseIndex(0); - const size_t nNumCutSets(aCutSets.size()); - - if(bMax) - { - // access at end - nBaseIndex = nNumCutSets - 1 - (bUpper ? nVisEdgeUp : nVisEdgeDn); - } - else - { - // access at start - nBaseIndex = bUpper ? nVisEdgeUp : nVisEdgeDn; - } - - const size_t nSecuredIndex(std::min(nNumCutSets - 1, std::max(nBaseIndex, static_cast< size_t >(0)))); - const CutSet& rCutSet(aCutSets[nSecuredIndex]); - ExtendSet& rExt(rExtendSet[my]); - - rExt.mfExtLeft = std::min(rCutSet.mfOLML, rCutSet.mfORML); - rExt.mfExtRight = std::min(rCutSet.mfOLMR, rCutSet.mfORMR); - } - - if(bUpper) - { - nVisEdgeUp++; - } - else - { - nVisEdgeDn++; - } - } - } - } - } -} - -StyleVectorCombination::StyleVectorCombination( - const Style& rStyle, - const basegfx::B2DVector& rB2DVector, - double fAngle, - bool bMirrored, - const Color* pForceColor) -: mfRefModeOffset(0.0), - maB2DVector(rB2DVector), - mfAngle(fAngle), - maOffsets() -{ - if (rStyle.IsUsed()) - { - RefMode aRefMode(rStyle.GetRefMode()); - Color aPrim(rStyle.GetColorPrim()); - Color aSecn(rStyle.GetColorSecn()); - double fPrim(rStyle.Prim()); - double fSecn(rStyle.Secn()); - const bool bSecnUsed(0.0 != fSecn); - - if(bMirrored) - { - switch(aRefMode) - { - case RefMode::REFMODE_BEGIN: aRefMode = RefMode::REFMODE_END; break; - case RefMode::REFMODE_END: aRefMode = RefMode::REFMODE_BEGIN; break; - default: break; - } - - if(bSecnUsed) - { - std::swap(aPrim, aSecn); - std::swap(fPrim, fSecn); - } - } - - if (RefMode::REFMODE_CENTERED != aRefMode) - { - const double fHalfWidth(rStyle.GetWidth() * 0.5); - - if (RefMode::REFMODE_BEGIN == aRefMode) - { - // move aligned below vector - mfRefModeOffset = fHalfWidth; - } - else if (RefMode::REFMODE_END == aRefMode) - { - // move aligned above vector - mfRefModeOffset = -fHalfWidth; - } - } - - if (bSecnUsed) - { - // both or all three lines used - const bool bPrimTransparent(0xff == rStyle.GetColorPrim().GetTransparency()); - const bool bDistTransparent(!rStyle.UseGapColor() || 0xff == rStyle.GetColorGap().GetTransparency()); - const bool bSecnTransparent(0xff == aSecn.GetTransparency()); - - if(!bPrimTransparent || !bDistTransparent || !bSecnTransparent) - { - const double a(mfRefModeOffset - (rStyle.GetWidth() * 0.5)); - const double b(a + fPrim); - const double c(b + rStyle.Dist()); - const double d(c + fSecn); - - maOffsets.push_back( - OffsetAndHalfWidthAndColor( - (a + b) * 0.5, - fPrim * 0.5, - nullptr != pForceColor ? *pForceColor : aPrim)); - - maOffsets.push_back( - OffsetAndHalfWidthAndColor( - (b + c) * 0.5, - rStyle.Dist() * 0.5, - rStyle.UseGapColor() - ? (nullptr != pForceColor ? *pForceColor : rStyle.GetColorGap()) - : Color(COL_TRANSPARENT))); - - maOffsets.push_back( - OffsetAndHalfWidthAndColor( - (c + d) * 0.5, - fSecn * 0.5, - nullptr != pForceColor ? *pForceColor : aSecn)); - } - } - else - { - // one line used, push two values, from outer to inner - if(0xff != rStyle.GetColorPrim().GetTransparency()) - { - maOffsets.push_back( - OffsetAndHalfWidthAndColor( - mfRefModeOffset, - fPrim * 0.5, - nullptr != pForceColor ? *pForceColor : aPrim)); - } - } - } -} - -void StyleVectorCombination::getColorAndOffsetAndHalfWidth(size_t nIndex, Color& rColor, double& rfOffset, double& rfHalfWidth) const -{ - if(nIndex >= maOffsets.size()) - return; - const OffsetAndHalfWidthAndColor& rCandidate(maOffsets[nIndex]); - rfOffset = rCandidate.mfOffset; - rfHalfWidth = rCandidate.mfHalfWidth; - rColor = rCandidate.maColor; -} - -void StyleVectorTable::add( - const Style& rStyle, - const basegfx::B2DVector& rMyVector, - const basegfx::B2DVector& rOtherVector, - bool bMirrored) -{ - if(rStyle.IsUsed() && !basegfx::areParallel(rMyVector, rOtherVector)) - { - // create angle between both. angle() needs vectors pointing away from the same point, - // so take the mirrored one. Add F_PI to get from -pi..+pi to [0..F_PI2] for sorting - const double fAngle(basegfx::B2DVector(-rMyVector.getX(), -rMyVector.getY()).angle(rOtherVector) + F_PI); - maEntries.emplace_back(rStyle, rOtherVector, fAngle, bMirrored); - } -} - -void StyleVectorTable::sort() -{ - // sort inverse fom highest to lowest - std::sort(maEntries.begin(), maEntries.end(), [](const StyleVectorCombination& a, const StyleVectorCombination& b) { return a.getAngle() > b.getAngle(); }); -} - -void CreateBorderPrimitives( - drawinglayer::primitive2d::Primitive2DContainer& rTarget, - const basegfx::B2DPoint& rOrigin, - const basegfx::B2DVector& rX, - const Style& rBorder, - const StyleVectorTable& rStartStyleVectorTable, - const StyleVectorTable& rEndStyleVectorTable, - const Color* pForceColor) -{ - // get offset color pairs for style, one per visible line - const StyleVectorCombination aCombination(rBorder, rX, 0.0, false, pForceColor); - - if(!aCombination.empty()) - { - const basegfx::B2DVector aPerpendX(basegfx::getNormalizedPerpendicular(rX)); - const bool bHasStartStyles(!rStartStyleVectorTable.empty()); - const bool bHasEndStyles(!rEndStyleVectorTable.empty()); - const size_t nOffsets(aCombination.size()); - std::vector<ExtendSet> aExtendSetStart(nOffsets); - std::vector<ExtendSet> aExtendSetEnd(nOffsets); - - if(bHasStartStyles) - { - // create extends for line starts, use given point/vector and offsets - getExtends(aExtendSetStart, rOrigin, aCombination, aPerpendX, rStartStyleVectorTable.getEntries()); - } - - if(bHasEndStyles) - { - // Create extends for line ends, create inverse point/vector and inverse offsets. - const StyleVectorCombination aMirroredCombination(rBorder, -rX, 0.0, true, pForceColor); - - getExtends(aExtendSetEnd, rOrigin + rX, aMirroredCombination, -aPerpendX, rEndStyleVectorTable.getEntries()); - - // also need to inverse the result to apply to the correct lines - std::reverse(aExtendSetEnd.begin(), aExtendSetEnd.end()); - } - - std::vector< drawinglayer::primitive2d::BorderLine > aBorderlines; - const double fNegLength(-rX.getLength()); - - for(size_t a(0); a < nOffsets; a++) - { - Color aMyColor; - double fMyOffset(0.0); - double fMyHalfWidth(0.0); - aCombination.getColorAndOffsetAndHalfWidth(a, aMyColor, fMyOffset, fMyHalfWidth); - const ExtendSet& rExtStart(aExtendSetStart[a]); - const ExtendSet& rExtEnd(aExtendSetEnd[a]); - - if(0xff == aMyColor.GetTransparency()) - { - aBorderlines.push_back( - drawinglayer::primitive2d::BorderLine( - fMyHalfWidth * 2.0)); - } - else - { - aBorderlines.push_back( - drawinglayer::primitive2d::BorderLine( - drawinglayer::attribute::LineAttribute( - aMyColor.getBColor(), - fMyHalfWidth * 2.0), - fNegLength * rExtStart.mfExtLeft, - fNegLength * rExtStart.mfExtRight, - fNegLength * rExtEnd.mfExtRight, - fNegLength * rExtEnd.mfExtLeft)); - } - } - - static double fPatScFact(10.0); // 10.0 multiply, see old code - const std::vector<double> aDashing(svtools::GetLineDashing(rBorder.Type(), rBorder.PatternScale() * fPatScFact)); - const drawinglayer::attribute::StrokeAttribute aStrokeAttribute(aDashing); - const basegfx::B2DPoint aStart(rOrigin + (aPerpendX * aCombination.getRefModeOffset())); - - rTarget.push_back( - drawinglayer::primitive2d::Primitive2DReference( - new drawinglayer::primitive2d::BorderLinePrimitive2D( - aStart, - aStart + rX, - aBorderlines, - aStrokeAttribute))); - } -} - } } diff --git a/svx/source/dialog/framelinkarray.cxx b/svx/source/dialog/framelinkarray.cxx index a2aca66a37fd..147017da01f3 100644 --- a/svx/source/dialog/framelinkarray.cxx +++ b/svx/source/dialog/framelinkarray.cxx @@ -25,6 +25,7 @@ #include <algorithm> #include <vcl/outdev.hxx> #include <drawinglayer/primitive2d/borderlineprimitive2d.hxx> +#include <svx/sdr/primitive2d/sdrframeborderprimitive2d.hxx> #include <basegfx/matrix/b2dhommatrixtools.hxx> namespace svx { @@ -929,26 +930,38 @@ void Array::MirrorSelfX() } // drawing -void HelperCreateHorizontalEntry( - const Array& rArray, const Style& rStyle, size_t col, size_t row, - const basegfx::B2DPoint& rOrigin, const basegfx::B2DVector& rX, const basegfx::B2DVector& rY, - drawinglayer::primitive2d::Primitive2DContainer& rSequence, - bool bUpper, const Color* pForceColor) -{ +static void HelperCreateHorizontalEntry( + const Array& rArray, + const Style& rStyle, + size_t col, + size_t row, + const basegfx::B2DPoint& rOrigin, + const basegfx::B2DVector& rX, + const basegfx::B2DVector& rY, + drawinglayer::primitive2d::SdrFrameBorderDataVector& rData, + bool bUpper, + const Color* pForceColor) +{ + // prepare SdrFrameBorderData + rData.emplace_back( + bUpper ? rOrigin : basegfx::B2DPoint(rOrigin + rY), + rX, + rStyle, + pForceColor); + drawinglayer::primitive2d::SdrFrameBorderData& rInstance(rData.back()); + // get involved styles at start const Style& rStartFromTR(rArray.GetCellStyleBL( col, row - 1 )); const Style& rStartLFromT(rArray.GetCellStyleLeft( col, row - 1 )); const Style& rStartLFromL(rArray.GetCellStyleTop( col - 1, row )); const Style& rStartLFromB(rArray.GetCellStyleLeft( col, row )); const Style& rStartFromBR(rArray.GetCellStyleTL( col, row )); - StyleVectorTable aStart; - aStart.add(rStartFromTR, rX, rX - rY, false); - aStart.add(rStartLFromT, rX, -rY, true); - aStart.add(rStartLFromL, rX, -rX, true); - aStart.add(rStartLFromB, rX, rY, false); - aStart.add(rStartFromBR, rX, rX + rY, false); - aStart.sort(); + rInstance.addSdrConnectStyleData(true, rStartFromTR, rX - rY, false); + rInstance.addSdrConnectStyleData(true, rStartLFromT, -rY, true); + rInstance.addSdrConnectStyleData(true, rStartLFromL, -rX, true); + rInstance.addSdrConnectStyleData(true, rStartLFromB, rY, false); + rInstance.addSdrConnectStyleData(true, rStartFromBR, rX + rY, false); // get involved styles at end const Style& rEndFromTL(rArray.GetCellStyleBR( col, row - 1 )); @@ -956,47 +969,46 @@ void HelperCreateHorizontalEntry( const Style& rEndRFromR(rArray.GetCellStyleTop( col + 1, row )); const Style& rEndRFromB(rArray.GetCellStyleRight( col, row )); const Style& rEndFromBL(rArray.GetCellStyleTR( col, row )); - StyleVectorTable aEnd; - const basegfx::B2DVector aAxis(-rX); - - aEnd.add(rEndFromTL, aAxis, aAxis - rY, true); - aEnd.add(rEndRFromT, aAxis, -rY, true); - aEnd.add(rEndRFromR, aAxis, rX, false); - aEnd.add(rEndRFromB, aAxis, rY, false); - aEnd.add(rEndFromBL, aAxis, rY - rX, true); - aEnd.sort(); - - CreateBorderPrimitives( - rSequence, - bUpper ? rOrigin : basegfx::B2DPoint(rOrigin + rY), - rX, + + rInstance.addSdrConnectStyleData(false, rEndFromTL, -rX - rY, true); + rInstance.addSdrConnectStyleData(false, rEndRFromT, -rY, true); + rInstance.addSdrConnectStyleData(false, rEndRFromR, rX, false); + rInstance.addSdrConnectStyleData(false, rEndRFromB, rY, false); + rInstance.addSdrConnectStyleData(false, rEndFromBL, rY - rX, true); +} + +static void HelperCreateVerticalEntry( + const Array& rArray, + const Style& rStyle, + size_t col, + size_t row, + const basegfx::B2DPoint& rOrigin, + const basegfx::B2DVector& rX, + const basegfx::B2DVector& rY, + drawinglayer::primitive2d::SdrFrameBorderDataVector& rData, + bool bLeft, + const Color* pForceColor) +{ + // prepare SdrFrameBorderData + rData.emplace_back( + bLeft ? rOrigin : basegfx::B2DPoint(rOrigin + rX), + rY, rStyle, - aStart, - aEnd, - pForceColor - ); -} + pForceColor); + drawinglayer::primitive2d::SdrFrameBorderData& rInstance(rData.back()); -void HelperCreateVerticalEntry( - const Array& rArray, const Style& rStyle, size_t col, size_t row, - const basegfx::B2DPoint& rOrigin, const basegfx::B2DVector& rX, const basegfx::B2DVector& rY, - drawinglayer::primitive2d::Primitive2DContainer& rSequence, - bool bLeft, const Color* pForceColor) -{ // get involved styles at start const Style& rStartFromBL(rArray.GetCellStyleTR( col - 1, row )); const Style& rStartTFromL(rArray.GetCellStyleTop( col - 1, row )); const Style& rStartTFromT(rArray.GetCellStyleLeft( col, row - 1 )); const Style& rStartTFromR(rArray.GetCellStyleTop( col, row )); const Style& rStartFromBR(rArray.GetCellStyleTL( col, row )); - StyleVectorTable aStart; - aStart.add(rStartFromBR, rY, rX + rY, false); - aStart.add(rStartTFromR, rY, rX, false); - aStart.add(rStartTFromT, rY, -rY, true); - aStart.add(rStartTFromL, rY, -rX, true); - aStart.add(rStartFromBL, rY, rY - rX, true); - aStart.sort(); + rInstance.addSdrConnectStyleData(true, rStartFromBR, rX + rY, false); + rInstance.addSdrConnectStyleData(true, rStartTFromR, rX, false); + rInstance.addSdrConnectStyleData(true, rStartTFromT, -rY, true); + rInstance.addSdrConnectStyleData(true, rStartTFromL, -rX, true); + rInstance.addSdrConnectStyleData(true, rStartFromBL, rY - rX, true); // get involved styles at end const Style& rEndFromTL(rArray.GetCellStyleBR( col - 1, row )); @@ -1004,67 +1016,12 @@ void HelperCreateVerticalEntry( const Style& rEndBFromB(rArray.GetCellStyleLeft( col, row + 1 )); const Style& rEndBFromR(rArray.GetCellStyleBottom( col, row )); const Style& rEndFromTR(rArray.GetCellStyleBL( col, row )); - StyleVectorTable aEnd; - const basegfx::B2DVector aAxis(-rY); - - aEnd.add(rEndFromTR, aAxis, rX - rY, false); - aEnd.add(rEndBFromR, aAxis, rX, false); - aEnd.add(rEndBFromB, aAxis, rY, false); - aEnd.add(rEndBFromL, aAxis, -rX, true); - aEnd.add(rEndFromTL, aAxis, aAxis - rX, true); - aEnd.sort(); - - CreateBorderPrimitives( - rSequence, - bLeft ? rOrigin : basegfx::B2DPoint(rOrigin + rX), - rY, - rStyle, - aStart, - aEnd, - pForceColor - ); -} -void HelperMergeInB2DPrimitiveArray( - const drawinglayer::primitive2d::Primitive2DContainer& rSource, - drawinglayer::primitive2d::Primitive2DContainer& rTarget) -{ - if(rSource.size() > 1) - { - drawinglayer::primitive2d::Primitive2DReference aCandidate; - - for(const auto& a : rSource) - { - if(aCandidate.is()) - { - const drawinglayer::primitive2d::Primitive2DReference aMerge( - drawinglayer::primitive2d::tryMergeBorderLinePrimitive2D(aCandidate, a)); - - if(aMerge.is()) - { - aCandidate = aMerge; - } - else - { - rTarget.push_back(aCandidate); - aCandidate = a; - } - } - else - { - aCandidate = a; - } - } - - if(aCandidate.is()) - { - rTarget.push_back(aCandidate); - } - } - else - { - rTarget.append(rSource); - } + rInstance.addSdrConnectStyleData(false, rEndFromTR, rX - rY, false); + rInstance.addSdrConnectStyleData(false, rEndBFromR, rX, false); + rInstance.addSdrConnectStyleData(false, rEndBFromB, rY, false); + rInstance.addSdrConnectStyleData(false, rEndBFromL, -rX, true); + rInstance.addSdrConnectStyleData(false, rEndFromTL, -rY - rX, true); } drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( @@ -1095,10 +1052,9 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( const size_t nStartCol(nFirstCol > 0 ? nFirstCol - 1 : nFirstCol); const size_t nEndCol(nLastCol < GetColCount() - 1 ? nLastCol + 1 : nLastCol); - // various primitive sequences to collect the different border types - drawinglayer::primitive2d::Primitive2DContainer aHorizontalSequence; - std::vector< drawinglayer::primitive2d::Primitive2DContainer > aVerticalSequences(nEndCol - nStartCol + 1); - drawinglayer::primitive2d::Primitive2DContainer aCrossSequence; + // prepare SdrFrameBorderDataVector + std::shared_ptr<drawinglayer::primitive2d::SdrFrameBorderDataVector> aData( + std::make_shared<drawinglayer::primitive2d::SdrFrameBorderDataVector>()); // remember for which merged cells crossed lines were already created. To // do so, hold the size_t cell index in a set for fast check @@ -1148,7 +1104,7 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( if(rTop.IsUsed()) { - HelperCreateHorizontalEntry(*this, rTop, nCol, nRow, aOrigin, aX, aY, aHorizontalSequence, true, pForceColor); + HelperCreateHorizontalEntry(*this, rTop, nCol, nRow, aOrigin, aX, aY, *aData.get(), true, pForceColor); } } @@ -1160,7 +1116,7 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( if(rBottom.IsUsed()) { - HelperCreateHorizontalEntry(*this, rBottom, nCol, nRow + 1, aOrigin, aX, aY, aHorizontalSequence, false, pForceColor); + HelperCreateHorizontalEntry(*this, rBottom, nCol, nRow + 1, aOrigin, aX, aY, *aData.get(), false, pForceColor); } } @@ -1173,7 +1129,7 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( if(rLeft.IsUsed()) { - HelperCreateVerticalEntry(*this, rLeft, nCol, nRow, aOrigin, aX, aY, aVerticalSequences[nCol - nStartCol], true, pForceColor); + HelperCreateVerticalEntry(*this, rLeft, nCol, nRow, aOrigin, aX, aY, *aData.get(), true, pForceColor); } } @@ -1185,7 +1141,7 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( if(rRight.IsUsed()) { - HelperCreateVerticalEntry(*this, rRight, nCol + 1, nRow, aOrigin, aX, aY, aVerticalSequences[nCol - nStartCol], false, pForceColor); + HelperCreateVerticalEntry(*this, rRight, nCol + 1, nRow, aOrigin, aX, aY, *aData.get(), false, pForceColor); } } @@ -1226,69 +1182,51 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( if(rTLBR.IsUsed()) { /// top-left and bottom-right Style Tables + aData->emplace_back( + aOrigin, + aX + aY, + rTLBR, + pForceColor); + drawinglayer::primitive2d::SdrFrameBorderData& rInstance(aData->back()); + /// Fill top-left Style Table const Style& rTLFromRight(GetCellStyleTop(nCol, nRow)); const Style& rTLFromBottom(GetCellStyleLeft(nCol, nRow)); - StyleVectorTable aStart; - const basegfx::B2DVector aAxisA(aX + aY); - aStart.add(rTLFromRight, aAxisA, aX, false); - aStart.add(rTLFromBottom, aAxisA, aY, false); - aStart.sort(); + rInstance.addSdrConnectStyleData(true, rTLFromRight, aX, false); + rInstance.addSdrConnectStyleData(true, rTLFromBottom, aY, false); /// Fill bottom-right Style Table const Style& rBRFromBottom(GetCellStyleRight(nCol, nRow)); const Style& rBRFromLeft(GetCellStyleBottom(nCol, nRow)); - StyleVectorTable aEnd; - const basegfx::B2DVector aAxisB(-aX -aY); - - aEnd.add(rBRFromBottom, aAxisB, -aY, true); - aEnd.add(rBRFromLeft, aAxisB, -aX, true); - aEnd.sort(); - CreateBorderPrimitives( - aCrossSequence, - aOrigin, - aX + aY, - rTLBR, - aStart, - aEnd, - pForceColor - ); + rInstance.addSdrConnectStyleData(false, rBRFromBottom, -aY, true); + rInstance.addSdrConnectStyleData(false, rBRFromLeft, -aX, true); } if(rBLTR.IsUsed()) { /// bottom-left and top-right Style Tables + aData->emplace_back( + aOrigin + aY, + aX - aY, + rBLTR, + pForceColor); + drawinglayer::primitive2d::SdrFrameBorderData& rInstance(aData->back()); + /// Fill bottom-left Style Table const Style& rBLFromTop(GetCellStyleLeft(nCol, nRow)); const Style& rBLFromBottom(GetCellStyleBottom(nCol, nRow)); - StyleVectorTable aStart; - const basegfx::B2DVector aAxisA(aX - aY); - aStart.add(rBLFromTop, aAxisA, -aY, true); - aStart.add(rBLFromBottom, aAxisA, aX, false); - aStart.sort(); + rInstance.addSdrConnectStyleData(true, rBLFromTop, -aY, true); + rInstance.addSdrConnectStyleData(true, rBLFromBottom, aX, false); /// Fill top-right Style Table const Style& rTRFromLeft(GetCellStyleTop(nCol, nRow)); const Style& rTRFromBottom(GetCellStyleRight(nCol, nRow)); - StyleVectorTable aEnd; - const basegfx::B2DVector aAxisB(aY - aX); - - aEnd.add(rTRFromLeft, aAxisB, -aX, true); - aEnd.add(rTRFromBottom, aAxisB, aY, false); - aEnd.sort(); - CreateBorderPrimitives( - aCrossSequence, - aOrigin + aY, - aX - aY, - rBLTR, - aStart, - aEnd, - pForceColor - ); + rInstance.addSdrConnectStyleData(false, rTRFromLeft, -aX, true); + rInstance.addSdrConnectStyleData(false, rTRFromBottom, aY, false); } } } @@ -1296,16 +1234,20 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( } } - // to stay compatible, create order as it was formally. Also try to - // merge primitives as far as possible - HelperMergeInB2DPrimitiveArray(aHorizontalSequence, aCrossSequence); + // create instance of SdrFrameBorderPrimitive2D if + // SdrFrameBorderDataVector is used + drawinglayer::primitive2d::Primitive2DContainer aSequence; - for(const auto& aVert : aVerticalSequences) + if(!aData->empty()) { - HelperMergeInB2DPrimitiveArray(aVert, aCrossSequence); + aSequence.push_back( + drawinglayer::primitive2d::Primitive2DReference( + new drawinglayer::primitive2d::SdrFrameBorderPrimitive2D( + aData, + true))); } - return aCrossSequence; + return aSequence; } drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveArray() const diff --git a/svx/source/sdr/primitive2d/sdrframeborderprimitive2d.cxx b/svx/source/sdr/primitive2d/sdrframeborderprimitive2d.cxx new file mode 100755 index 000000000000..641968762d32 --- /dev/null +++ b/svx/source/sdr/primitive2d/sdrframeborderprimitive2d.cxx @@ -0,0 +1,768 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svx/sdr/primitive2d/sdrframeborderprimitive2d.hxx> +#include <drawinglayer/primitive2d/borderlineprimitive2d.hxx> +#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <svtools/borderhelper.hxx> + +namespace +{ + class StyleVectorCombination + { + private: + struct OffsetAndHalfWidthAndColor + { + double mfOffset; + double mfHalfWidth; + Color maColor; + + OffsetAndHalfWidthAndColor(double offset, double halfWidth, Color color) : + mfOffset(offset), + mfHalfWidth(halfWidth), + maColor(color) + {} + }; + + double mfRefModeOffset; + basegfx::B2DVector maB2DVector; + double mfAngle; + std::vector< OffsetAndHalfWidthAndColor > maOffsets; + + public: + StyleVectorCombination( + const svx::frame::Style& rStyle, + const basegfx::B2DVector& rB2DVector, + double fAngle, + bool bMirrored, + const Color* pForceColor) + : mfRefModeOffset(0.0), + maB2DVector(rB2DVector), + mfAngle(fAngle), + maOffsets() + { + if (rStyle.IsUsed()) + { + svx::frame::RefMode aRefMode(rStyle.GetRefMode()); + Color aPrim(rStyle.GetColorPrim()); + Color aSecn(rStyle.GetColorSecn()); + double fPrim(rStyle.Prim()); + double fSecn(rStyle.Secn()); + const bool bSecnUsed(0.0 != fSecn); + + if(bMirrored) + { + switch(aRefMode) + { + case svx::frame::RefMode::REFMODE_BEGIN: aRefMode = svx::frame::RefMode::REFMODE_END; break; + case svx::frame::RefMode::REFMODE_END: aRefMode = svx::frame::RefMode::REFMODE_BEGIN; break; + default: break; + } + + if(bSecnUsed) + { + std::swap(aPrim, aSecn); + std::swap(fPrim, fSecn); + } + } + + if (svx::frame::RefMode::REFMODE_CENTERED != aRefMode) + { + const double fHalfWidth(rStyle.GetWidth() * 0.5); + + if (svx::frame::RefMode::REFMODE_BEGIN == aRefMode) + { + // move aligned below vector + mfRefModeOffset = fHalfWidth; + } + else if (svx::frame::RefMode::REFMODE_END == aRefMode) + { + // move aligned above vector + mfRefModeOffset = -fHalfWidth; + } + } + + if (bSecnUsed) + { + // both or all three lines used + const bool bPrimTransparent(0xff == rStyle.GetColorPrim().GetTransparency()); + const bool bDistTransparent(!rStyle.UseGapColor() || 0xff == rStyle.GetColorGap().GetTransparency()); + const bool bSecnTransparent(0xff == aSecn.GetTransparency()); + + if(!bPrimTransparent || !bDistTransparent || !bSecnTransparent) + { + const double a(mfRefModeOffset - (rStyle.GetWidth() * 0.5)); + const double b(a + fPrim); + const double c(b + rStyle.Dist()); + const double d(c + fSecn); + + maOffsets.push_back( + OffsetAndHalfWidthAndColor( + (a + b) * 0.5, + fPrim * 0.5, + nullptr != pForceColor ? *pForceColor : aPrim)); + + maOffsets.push_back( + OffsetAndHalfWidthAndColor( + (b + c) * 0.5, + rStyle.Dist() * 0.5, + rStyle.UseGapColor() + ? (nullptr != pForceColor ? *pForceColor : rStyle.GetColorGap()) + : COL_TRANSPARENT)); + + maOffsets.push_back( + OffsetAndHalfWidthAndColor( + (c + d) * 0.5, + fSecn * 0.5, + nullptr != pForceColor ? *pForceColor : aSecn)); + } + } + else + { + // one line used, push two values, from outer to inner + if(0xff != rStyle.GetColorPrim().GetTransparency()) + { + maOffsets.push_back( + OffsetAndHalfWidthAndColor( + mfRefModeOffset, + fPrim * 0.5, + nullptr != pForceColor ? *pForceColor : aPrim)); + } + } + } + } + + double getRefModeOffset() const { return mfRefModeOffset; } + const basegfx::B2DVector& getB2DVector() const { return maB2DVector; } + double getAngle() const { return mfAngle; } + bool empty() const { return maOffsets.empty(); } + size_t size() const { return maOffsets.size(); } + + void getColorAndOffsetAndHalfWidth(size_t nIndex, Color& rColor, double& rfOffset, double& rfHalfWidth) const + { + if(nIndex >= maOffsets.size()) + return; + const OffsetAndHalfWidthAndColor& rCandidate(maOffsets[nIndex]); + rfOffset = rCandidate.mfOffset; + rfHalfWidth = rCandidate.mfHalfWidth; + rColor = rCandidate.maColor; + } + }; + + class StyleVectorTable + { + private: + std::vector< StyleVectorCombination > maEntries; + + public: + StyleVectorTable() + : maEntries() + { + } + + void add( + const svx::frame::Style& rStyle, + const basegfx::B2DVector& rMyVector, + const basegfx::B2DVector& rOtherVector, + bool bMirrored) + { + if(rStyle.IsUsed() && !basegfx::areParallel(rMyVector, rOtherVector)) + { + // create angle between both. angle() needs vectors pointing away from the same point, + // so take the mirrored one. Add F_PI to get from -pi..+pi to [0..F_PI2] for sorting + const double fAngle(basegfx::B2DVector(-rMyVector.getX(), -rMyVector.getY()).angle(rOtherVector) + F_PI); + maEntries.emplace_back(rStyle, rOtherVector, fAngle, bMirrored, nullptr); + } + } + + void sort() + { + // sort inverse fom highest to lowest + std::sort( + maEntries.begin(), + maEntries.end(), + [](const StyleVectorCombination& a, const StyleVectorCombination& b) + { return a.getAngle() > b.getAngle(); }); + } + + bool empty() const { return maEntries.empty(); } + const std::vector< StyleVectorCombination >& getEntries() const{ return maEntries; } + }; + + struct CutSet + { + double mfOLML; + double mfORML; + double mfOLMR; + double mfORMR; + + CutSet() : mfOLML(0.0), mfORML(0.0), mfOLMR(0.0), mfORMR(0.0) + { + } + + bool operator<( const CutSet& rOther) const + { + const double fA(mfOLML + mfORML + mfOLMR + mfORMR); + const double fB(rOther.mfOLML + rOther.mfORML + rOther.mfOLMR + rOther.mfORMR); + + return fA < fB; + } + + double getSum() const { return mfOLML + mfORML + mfOLMR + mfORMR; } + }; + + void getCutSet( + CutSet& rCutSet, + const basegfx::B2DPoint& rLeft, + const basegfx::B2DPoint& rRight, + const basegfx::B2DVector& rX, + const basegfx::B2DPoint& rOtherLeft, + const basegfx::B2DPoint& rOtherRight, + const basegfx::B2DVector& rOtherX) + { + basegfx::tools::findCut( + rLeft, + rX, + rOtherLeft, + rOtherX, + CutFlagValue::LINE, + &rCutSet.mfOLML); + + basegfx::tools::findCut( + rRight, + rX, + rOtherLeft, + rOtherX, + CutFlagValue::LINE, + &rCutSet.mfOLMR); + + basegfx::tools::findCut( + rLeft, + rX, + rOtherRight, + rOtherX, + CutFlagValue::LINE, + &rCutSet.mfORML); + + basegfx::tools::findCut( + rRight, + rX, + rOtherRight, + rOtherX, + CutFlagValue::LINE, + &rCutSet.mfORMR); + } + + struct ExtendSet + { + double mfExtLeft; + double mfExtRight; + + ExtendSet() : mfExtLeft(0.0), mfExtRight(0.0) {} + }; + + void getExtends( + std::vector<ExtendSet>& rExtendSet, // target Left/Right values to fill + const basegfx::B2DPoint& rOrigin, // own vector start + const StyleVectorCombination& rCombination, // own vector and offsets for lines + const basegfx::B2DVector& rPerpendX, // normalized perpendicular to own vector + const std::vector< StyleVectorCombination >& rStyleVector) // other vectors emerging in this point + { + if(!rCombination.empty() && !rStyleVector.empty() && rCombination.size() == rExtendSet.size()) + { + const size_t nOffsetA(rCombination.size()); + + if(1 == nOffsetA) + { + Color aMyColor; double fMyOffset(0.0); double fMyHalfWidth(0.0); + rCombination.getColorAndOffsetAndHalfWidth(0, aMyColor, fMyOffset, fMyHalfWidth); + + if(0xff != aMyColor.GetTransparency()) + { + const basegfx::B2DPoint aLeft(rOrigin + (rPerpendX * (fMyOffset - fMyHalfWidth))); + const basegfx::B2DPoint aRight(rOrigin + (rPerpendX * (fMyOffset + fMyHalfWidth))); + std::vector< CutSet > aCutSets; + + for(const auto& rStyleCandidate : rStyleVector) + { + const basegfx::B2DVector aOtherPerpend(basegfx::getNormalizedPerpendicular(rStyleCandidate.getB2DVector())); + const size_t nOffsetB(rStyleCandidate.size()); + + for(size_t other(0); other < nOffsetB; other++) + { + Color aOtherColor; double fOtherOffset(0.0); double fOtherHalfWidth(0.0); + rStyleCandidate.getColorAndOffsetAndHalfWidth(other, aOtherColor, fOtherOffset, fOtherHalfWidth); + + if(0xff != aOtherColor.GetTransparency()) + { + const basegfx::B2DPoint aOtherLeft(rOrigin + (aOtherPerpend * (fOtherOffset - fOtherHalfWidth))); + const basegfx::B2DPoint aOtherRight(rOrigin + (aOtherPerpend * (fOtherOffset + fOtherHalfWidth))); + + CutSet aNewCutSet; + getCutSet(aNewCutSet, aLeft, aRight, rCombination.getB2DVector(), aOtherLeft, aOtherRight, rStyleCandidate.getB2DVector()); + aCutSets.push_back(aNewCutSet); + } + } + } + + if(!aCutSets.empty()) + { + CutSet aCutSet(aCutSets[0]); + const size_t nNumCutSets(aCutSets.size()); + + if(1 != nNumCutSets) + { + double fCutSet(aCutSet.getSum()); + + for(size_t a(1); a < nNumCutSets; a++) + { + const CutSet& rCandidate(aCutSets[a]); + const double fCandidate(rCandidate.getSum()); + + if(basegfx::fTools::equalZero(fCandidate - fCutSet)) + { + // both have equal center point, use medium cut + const double fNewOLML(std::max(std::min(rCandidate.mfOLML, rCandidate.mfORML), std::min(aCutSet.mfOLML, aCutSet.mfORML))); + const double fNewORML(std::min(std::max(rCandidate.mfOLML, rCandidate.mfORML), std::max(aCutSet.mfOLML, aCutSet.mfORML))); + const double fNewOLMR(std::max(std::min(rCandidate.mfOLMR, rCandidate.mfORMR), std::min(aCutSet.mfOLMR, aCutSet.mfORMR))); + const double fNewORMR(std::min(std::max(rCandidate.mfOLMR, rCandidate.mfORMR), std::max(aCutSet.mfOLMR, aCutSet.mfORMR))); + aCutSet.mfOLML = fNewOLML; + aCutSet.mfORML = fNewORML; + aCutSet.mfOLMR = fNewOLMR; + aCutSet.mfORMR = fNewORMR; + fCutSet = aCutSet.getSum(); + } + else if(fCandidate < fCutSet) + { + // get minimum + fCutSet = fCandidate; + aCutSet = rCandidate; + } + } + } + + ExtendSet& rExt(rExtendSet[0]); + + rExt.mfExtLeft = std::min(aCutSet.mfOLML, aCutSet.mfORML); + rExt.mfExtRight = std::min(aCutSet.mfOLMR, aCutSet.mfORMR); + } + } + } + else + { + size_t nVisEdgeUp(0); + size_t nVisEdgeDn(0); + + for(size_t my(0); my < nOffsetA; my++) + { + Color aMyColor; double fMyOffset(0.0); double fMyHalfWidth(0.0); + rCombination.getColorAndOffsetAndHalfWidth(my, aMyColor, fMyOffset, fMyHalfWidth); + + if(0xff != aMyColor.GetTransparency()) + { + const basegfx::B2DPoint aLeft(rOrigin + (rPerpendX * (fMyOffset - fMyHalfWidth))); + const basegfx::B2DPoint aRight(rOrigin + (rPerpendX * (fMyOffset + fMyHalfWidth))); + const bool bUpper(my <= (nOffsetA >> 1)); + const StyleVectorCombination& rStyleCandidate(bUpper ? rStyleVector.front() : rStyleVector.back()); + const basegfx::B2DVector aOtherPerpend(basegfx::getNormalizedPerpendicular(rStyleCandidate.getB2DVector())); + const size_t nOffsetB(rStyleCandidate.size()); + std::vector< CutSet > aCutSets; + + for(size_t other(0); other < nOffsetB; other++) + { + Color aOtherColor; double fOtherOffset(0.0); double fOtherHalfWidth(0.0); + rStyleCandidate.getColorAndOffsetAndHalfWidth(other, aOtherColor, fOtherOffset, fOtherHalfWidth); + + if(0xff != aOtherColor.GetTransparency()) + { + const basegfx::B2DPoint aOtherLeft(rOrigin + (aOtherPerpend * (fOtherOffset - fOtherHalfWidth))); + const basegfx::B2DPoint aOtherRight(rOrigin + (aOtherPerpend * (fOtherOffset + fOtherHalfWidth))); + CutSet aCutSet; + getCutSet(aCutSet, aLeft, aRight, rCombination.getB2DVector(), aOtherLeft, aOtherRight, rStyleCandidate.getB2DVector()); + aCutSets.push_back(aCutSet); + } + } + + if(!aCutSets.empty()) + { + // sort: min to start, max to end + std::sort(aCutSets.begin(), aCutSets.end()); + const bool bOtherUpper(rStyleCandidate.getAngle() > F_PI); + + // check if we need min or max + // bUpper bOtherUpper MinMax + // t t max + // t f min + // f f max + // f t min + const bool bMax(bUpper == bOtherUpper); + size_t nBaseIndex(0); + const size_t nNumCutSets(aCutSets.size()); + + if(bMax) + { + // access at end + nBaseIndex = nNumCutSets - 1 - (bUpper ? nVisEdgeUp : nVisEdgeDn); + } + else + { + // access at start + nBaseIndex = bUpper ? nVisEdgeUp : nVisEdgeDn; + } + + const size_t nSecuredIndex(std::min(nNumCutSets - 1, std::max(nBaseIndex, static_cast< size_t >(0)))); + const CutSet& rCutSet(aCutSets[nSecuredIndex]); + ExtendSet& rExt(rExtendSet[my]); + + rExt.mfExtLeft = std::min(rCutSet.mfOLML, rCutSet.mfORML); + rExt.mfExtRight = std::min(rCutSet.mfOLMR, rCutSet.mfORMR); + } + + if(bUpper) + { + nVisEdgeUp++; + } + else + { + nVisEdgeDn++; + } + } + } + } + } + } + + /** + * Helper method to create the correct drawinglayer::primitive2d::BorderLinePrimitive2D + * for the given data, especially the correct drawinglayer::primitive2d::BorderLine entries + * including the correctly solved/created LineStartEnd extends + * + * rTarget : Here the evtl. created BorderLinePrimitive2D will be appended + * rOrigin : StartPoint of the Borderline + * rX : Vector of the Borderline + * rBorder : svx::frame::Style of the of the Borderline + * rStartStyleVectorTable : All other Borderlines which have to be taken into account because + * they have the same StartPoint as the current Borderline. These will be used to calculate + * the correct LineStartEnd extends tor the BorderLinePrimitive2D. The definition should be + * built up using svx::frame::StyleVectorTable and StyleVectorTable::add and includes: + * rStyle : the svx::frame::Style of one other BorderLine + * rMyVector : the Vector of the *new* to-be-defined BorderLine, identical to rX + * rOtherVector: the Vector of one other BorderLine (may be, but does not need to be normalized), + * always *pointing away* from the common StartPoint rOrigin + * bMirrored : define if rStyle of one other BorderLine shall be mirrored (e.g. bottom-right edges) + * With multiple BorderLines the definitions have to be CounterClockWise. This will be + * ensured by StyleVectorTable sorting the entries, but knowing this may allow more efficient + * data creation. + * rEndStyleVectorTable: All other BorderLines that have the same EndPoint. There are differences to + * the Start definitions: + * - do not forget to consequently use -rX for rMyVector + * - definitions have to be ClockWise for the EndBorderLines, will be ensured by sorting + * + * If you take all this into account, you will gett correctly extended BorderLinePrimitive2D + * representations for the new to be defined BorderLine. That extensions will overlap nicely + * with the corresponding BorderLines and take all multiple line definitions in the ::Style into + * account. + * The internal solver is *not limited* to ::Style(s) with three parts (Left/Gap/Right), this is + * just due to svx::frame::Style's definitions. A new solver based on this one can be created + * anytime using more mulötiple borders based on the more flexible + * std::vector< drawinglayer::primitive2d::BorderLine > if needed. + */ + void CreateBorderPrimitives( + drawinglayer::primitive2d::Primitive2DContainer& rTarget, /// target for created primitives + const basegfx::B2DPoint& rOrigin, /// start point of borderline + const basegfx::B2DVector& rX, /// X-Axis of borderline with length + const svx::frame::Style& rBorder, /// Style of borderline + const StyleVectorTable& rStartStyleVectorTable, /// Styles and vectors (pointing away) at borderline start, ccw + const StyleVectorTable& rEndStyleVectorTable, /// Styles and vectors (pointing away) at borderline end, cw + const Color* pForceColor) /// If specified, overrides frame border color. + { + // get offset color pairs for style, one per visible line + const StyleVectorCombination aCombination(rBorder, rX, 0.0, false, pForceColor); + + if(aCombination.empty()) + return; + + const basegfx::B2DVector aPerpendX(basegfx::getNormalizedPerpendicular(rX)); + const bool bHasStartStyles(!rStartStyleVectorTable.empty()); + const bool bHasEndStyles(!rEndStyleVectorTable.empty()); + const size_t nOffsets(aCombination.size()); + std::vector<ExtendSet> aExtendSetStart(nOffsets); + std::vector<ExtendSet> aExtendSetEnd(nOffsets); + + if(bHasStartStyles) + { + // create extends for line starts, use given point/vector and offsets + getExtends(aExtendSetStart, rOrigin, aCombination, aPerpendX, rStartStyleVectorTable.getEntries()); + } + + if(bHasEndStyles) + { + // Create extends for line ends, create inverse point/vector and inverse offsets. + const StyleVectorCombination aMirroredCombination(rBorder, -rX, 0.0, true, pForceColor); + + getExtends(aExtendSetEnd, rOrigin + rX, aMirroredCombination, -aPerpendX, rEndStyleVectorTable.getEntries()); + + // also need to inverse the result to apply to the correct lines + std::reverse(aExtendSetEnd.begin(), aExtendSetEnd.end()); + } + + std::vector< drawinglayer::primitive2d::BorderLine > aBorderlines; + const double fNegLength(-rX.getLength()); + + for(size_t a(0); a < nOffsets; a++) + { + Color aMyColor; + double fMyOffset(0.0); + double fMyHalfWidth(0.0); + aCombination.getColorAndOffsetAndHalfWidth(a, aMyColor, fMyOffset, fMyHalfWidth); + const ExtendSet& rExtStart(aExtendSetStart[a]); + const ExtendSet& rExtEnd(aExtendSetEnd[a]); + + if(0xff == aMyColor.GetTransparency()) + { + aBorderlines.push_back( + drawinglayer::primitive2d::BorderLine( + fMyHalfWidth * 2.0)); + } + else + { + aBorderlines.push_back( + drawinglayer::primitive2d::BorderLine( + drawinglayer::attribute::LineAttribute( + aMyColor.getBColor(), + fMyHalfWidth * 2.0), + fNegLength * rExtStart.mfExtLeft, + fNegLength * rExtStart.mfExtRight, + fNegLength * rExtEnd.mfExtRight, + fNegLength * rExtEnd.mfExtLeft)); + } + } + + static double fPatScFact(10.0); // 10.0 multiply, see old code + const std::vector<double> aDashing(svtools::GetLineDashing(rBorder.Type(), rBorder.PatternScale() * fPatScFact)); + const drawinglayer::attribute::StrokeAttribute aStrokeAttribute(aDashing); + const basegfx::B2DPoint aStart(rOrigin + (aPerpendX * aCombination.getRefModeOffset())); + + rTarget.push_back( + drawinglayer::primitive2d::Primitive2DReference( + new drawinglayer::primitive2d::BorderLinePrimitive2D( + aStart, + aStart + rX, + aBorderlines, + aStrokeAttribute))); + } +} + +namespace drawinglayer +{ + namespace primitive2d + { + SdrFrameBorderData::SdrConnectStyleData::SdrConnectStyleData( + const svx::frame::Style& rStyle, + const basegfx::B2DVector& rNormalizedPerpendicular, + bool bStyleMirrored) + : maStyle(rStyle), + maNormalizedPerpendicular(rNormalizedPerpendicular), + mbStyleMirrored(bStyleMirrored) + { + } + + SdrFrameBorderData::SdrFrameBorderData( + const basegfx::B2DPoint& rOrigin, + const basegfx::B2DVector& rX, + const svx::frame::Style& rStyle, + const Color* pForceColor) + : maOrigin(rOrigin), + maX(rX), + maStyle(rStyle), + maColor(nullptr != pForceColor ? *pForceColor : Color()), + mbForceColor(nullptr != pForceColor), + maStart(), + maEnd() + { + } + + void SdrFrameBorderData::addSdrConnectStyleData( + bool bStart, + const svx::frame::Style& rStyle, + const basegfx::B2DVector& rNormalizedPerpendicular, + bool bStyleMirrored) + { + if(rStyle.IsUsed()) + { + if(bStart) + { + maStart.emplace_back(rStyle, rNormalizedPerpendicular, bStyleMirrored); + } + else + { + maEnd.emplace_back(rStyle, rNormalizedPerpendicular, bStyleMirrored); + } + } + } + + void SdrFrameBorderData::create2DDecomposition(Primitive2DContainer& rContainer) const + { + StyleVectorTable aStartVector; + StyleVectorTable aEndVector; + const basegfx::B2DVector aAxis(-maX); + + for(const auto& rStart : maStart) + { + aStartVector.add( + rStart.getStyle(), + maX, + rStart.getNormalizedPerpendicular(), + rStart.getStyleMirrored()); + } + + for(const auto& rEnd : maEnd) + { + aEndVector.add( + rEnd.getStyle(), + aAxis, + rEnd.getNormalizedPerpendicular(), + rEnd.getStyleMirrored()); + } + + aStartVector.sort(); + aEndVector.sort(); + + CreateBorderPrimitives( + rContainer, + maOrigin, + maX, + maStyle, + aStartVector, + aEndVector, + mbForceColor ? &maColor : nullptr); + } + } // end of namespace primitive2d +} // end of namespace drawinglayer + +namespace drawinglayer +{ + namespace primitive2d + { + Primitive2DContainer SdrFrameBorderPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*aViewInformation*/) const + { + Primitive2DContainer aRetval; + + if(getMergeResult()) + { + // decompose all buffered SdrFrameBorderData entries and try to merge them + // to reduce existing number of BorderLinePrimitive2D(s) + for(const auto& rCandidate : getFrameBorders()) + { + // get decomposition on one SdrFrameBorderData entry + Primitive2DContainer aPartial; + rCandidate.create2DDecomposition(aPartial); + + for(const auto& aCandidatePartial : aPartial) + { + if(aRetval.empty()) + { + // no local data yet, just add as 1st entry, done + aRetval.push_back(aCandidatePartial); + } + else + { + bool bDidMerge(false); + + for(auto& aCandidateRetval : aRetval) + { + // try to merge by appending new data to existing data + const drawinglayer::primitive2d::Primitive2DReference aMergeRetvalPartial( + drawinglayer::primitive2d::tryMergeBorderLinePrimitive2D( + aCandidateRetval, + aCandidatePartial)); + + if(aMergeRetvalPartial.is()) + { + // could append, replace existing data with merged data, done + aCandidateRetval = aMergeRetvalPartial; + bDidMerge = true; + break; + } + + // try to merge by appending existing data to new data + const drawinglayer::primitive2d::Primitive2DReference aMergePartialRetval( + drawinglayer::primitive2d::tryMergeBorderLinePrimitive2D( + aCandidatePartial, + aCandidateRetval)); + + if(aMergePartialRetval.is()) + { + // could append, replace existing data with merged data, done + aCandidateRetval = aMergePartialRetval; + bDidMerge = true; + break; + } + } + + if(!bDidMerge) + { + // no merge aftzer checking all existing data, append as new segment + aRetval.push_back(aCandidatePartial); + } + } + } + } + } + else + { + // just decompose all buffered SdrFrameBorderData entries, do not try to merge + for(const auto& rCandidate : getFrameBorders()) + { + rCandidate.create2DDecomposition(aRetval); + } + } + + return aRetval; + } + + SdrFrameBorderPrimitive2D::SdrFrameBorderPrimitive2D( + std::shared_ptr<SdrFrameBorderDataVector>& rFrameBorders, + bool bMergeResult) + : BufferedDecompositionPrimitive2D(), + maFrameBorders(std::move(rFrameBorders)), + mbMergeResult(bMergeResult) + { + } + + bool SdrFrameBorderPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + { + if(BufferedDecompositionPrimitive2D::operator==(rPrimitive)) + { + const SdrFrameBorderPrimitive2D& rCompare = static_cast<const SdrFrameBorderPrimitive2D&>(rPrimitive); + + return maFrameBorders == rCompare.maFrameBorders; + } + + return false; + } + + // provide unique ID + ImplPrimitive2DIDBlock(SdrFrameBorderPrimitive2D, PRIMITIVE2D_ID_SDRFRAMEBORDERTPRIMITIVE2D) + + } // end of namespace primitive2d +} // end of namespace drawinglayer + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/paintfrm.cxx b/sw/source/core/layout/paintfrm.cxx index 77a675329219..c8fcefe1a162 100644 --- a/sw/source/core/layout/paintfrm.cxx +++ b/sw/source/core/layout/paintfrm.cxx @@ -64,6 +64,7 @@ #include <colfrm.hxx> #include <sw_primitivetypes2d.hxx> +#include <svx/sdr/primitive2d/sdrframeborderprimitive2d.hxx> #include <svx/sdr/contact/viewobjectcontactredirector.hxx> #include <svx/sdr/contact/viewobjectcontact.hxx> #include <svx/sdr/contact/viewcontact.hxx> @@ -2380,8 +2381,10 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons aUpper.Pos() += pUpper->Frame().Pos(); SwRect aUpperAligned( aUpper ); ::SwAlignRect( aUpperAligned, gProp.pSGlobalShell, &rDev ); - drawinglayer::primitive2d::Primitive2DContainer aHorizontalSequence; - drawinglayer::primitive2d::Primitive2DContainer aVerticalSequence; + + // prepare SdrFrameBorderDataVector + std::shared_ptr<drawinglayer::primitive2d::SdrFrameBorderDataVector> aData( + std::make_shared<drawinglayer::primitive2d::SdrFrameBorderDataVector>()); while ( true ) { @@ -2519,30 +2522,20 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons if(!aX.equalZero()) { const basegfx::B2DVector aY(basegfx::getNormalizedPerpendicular(aX)); - svx::frame::StyleVectorTable aStartVector; - - aStartVector.add(aStyles[ 1 ], aX, -aY, true); // aLFromT - aStartVector.add(aStyles[ 2 ], aX, -aX, true); // aLFromL - aStartVector.add(aStyles[ 3 ], aX, aY, false); // aLFromB - aStartVector.sort(); - - svx::frame::StyleVectorTable aEndVector; - const basegfx::B2DVector aAxis(-aX); - - aEndVector.add(aStyles[ 4 ], aAxis, -aY, true); // aRFromT - aEndVector.add(aStyles[ 5 ], aAxis, aX, false); // aRFromR - aEndVector.add(aStyles[ 6 ], aAxis, aY, false); // aRFromB - aEndVector.sort(); - - CreateBorderPrimitives( - aHorizontalSequence, + aData->emplace_back( aOrigin, aX, - aStyles[ 0 ], - aStartVector, - aEndVector, - pTmpColor - ); + aStyles[0], + pTmpColor); + drawinglayer::primitive2d::SdrFrameBorderData& rInstance(aData->back()); + + rInstance.addSdrConnectStyleData(true, aStyles[1], -aY, true); // aLFromT + rInstance.addSdrConnectStyleData(true, aStyles[2], -aX, true); // aLFromL + rInstance.addSdrConnectStyleData(true, aStyles[3], aY, false); // aLFromB + + rInstance.addSdrConnectStyleData(false, aStyles[4], -aY, true); // aRFromT + rInstance.addSdrConnectStyleData(false, aStyles[5], aX, false); // aRFromR + rInstance.addSdrConnectStyleData(false, aStyles[6], aY, false); // aRFromB } } else // vertical @@ -2553,30 +2546,20 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons if(!aX.equalZero()) { const basegfx::B2DVector aY(basegfx::getNormalizedPerpendicular(aX)); - svx::frame::StyleVectorTable aStartVector; - - aStartVector.add(aStyles[ 3 ], aX, -aY, false); // aTFromR - aStartVector.add(aStyles[ 2 ], aX, -aX, true); // aTFromT - aStartVector.add(aStyles[ 1 ], aX, aY, true); // aTFromL - aStartVector.sort(); - - svx::frame::StyleVectorTable aEndVector; - const basegfx::B2DVector aAxis(-aX); - - aEndVector.add(aStyles[ 6 ], aAxis, -aY, false); // aBFromR - aEndVector.add(aStyles[ 5 ], aAxis, aX, false); // aBFromB - aEndVector.add(aStyles[ 4 ], aAxis, aY, true); // aBFromL - aEndVector.sort(); - - CreateBorderPrimitives( - aVerticalSequence, + aData->emplace_back( aOrigin, aX, - aStyles[ 0 ], - aStartVector, - aEndVector, - pTmpColor - ); + aStyles[0], + pTmpColor); + drawinglayer::primitive2d::SdrFrameBorderData& rInstance(aData->back()); + + rInstance.addSdrConnectStyleData(true, aStyles[3], -aY, false); // aTFromR + rInstance.addSdrConnectStyleData(true, aStyles[2], -aX, true); // aTFromT + rInstance.addSdrConnectStyleData(true, aStyles[1], aY, true); // aTFromL + + rInstance.addSdrConnectStyleData(false, aStyles[6], -aY, false); // aBFromR + rInstance.addSdrConnectStyleData(false, aStyles[5], aX, false); // aBFromB + rInstance.addSdrConnectStyleData(false, aStyles[4], aY, true); // aBFromL } } } @@ -2584,15 +2567,19 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons ++aIter; } - // to stay compatible, create order as it was formally. Also try to - // merge primitives as far as possible - drawinglayer::primitive2d::Primitive2DContainer aSequence; - - svx::frame::HelperMergeInB2DPrimitiveArray(aHorizontalSequence, aSequence); - svx::frame::HelperMergeInB2DPrimitiveArray(aVerticalSequence, aSequence); - - // paint - mrTabFrame.ProcessPrimitives(aSequence); + // create instance of SdrFrameBorderPrimitive2D if + // SdrFrameBorderDataVector is used + if(!aData->empty()) + { + drawinglayer::primitive2d::Primitive2DContainer aSequence; + aSequence.push_back( + drawinglayer::primitive2d::Primitive2DReference( + new drawinglayer::primitive2d::SdrFrameBorderPrimitive2D( + aData, + true))); + // paint + mrTabFrame.ProcessPrimitives(aSequence); + } // restore output device: rDev.SetDrawMode( nOldDrawMode ); @@ -4508,6 +4495,10 @@ namespace drawinglayer basegfx::B2DPoint aBottomLeft(getB2DHomMatrix() * basegfx::B2DPoint(0.0, 1.0)); basegfx::B2DPoint aBottomRight(getB2DHomMatrix() * basegfx::B2DPoint(1.0, 1.0)); + // prepare SdrFrameBorderDataVector + std::shared_ptr<drawinglayer::primitive2d::SdrFrameBorderDataVector> aData( + std::make_shared<drawinglayer::primitive2d::SdrFrameBorderDataVector>()); + if(getStyleTop().IsUsed()) { // move top left/right inwards half border width @@ -4550,108 +4541,99 @@ namespace drawinglayer { // create BorderPrimitive(s) for top border const basegfx::B2DVector aVector(aTopRight - aTopLeft); - svx::frame::StyleVectorTable aStartStyleVectorTable; - svx::frame::StyleVectorTable aEndStyleVectorTable; + aData->emplace_back( + aTopLeft, + aVector, + getStyleTop(), + nullptr); + drawinglayer::primitive2d::SdrFrameBorderData& rInstance(aData->back()); if(getStyleLeft().IsUsed()) { - aStartStyleVectorTable.add(getStyleLeft(), aVector, basegfx::B2DVector(aBottomLeft - aTopLeft), false); + rInstance.addSdrConnectStyleData(true, getStyleLeft(), basegfx::B2DVector(aBottomLeft - aTopLeft), false); } if(getStyleRight().IsUsed()) { - aEndStyleVectorTable.add(getStyleRight(), -aVector, basegfx::B2DVector(aBottomRight - aTopRight), false); + rInstance.addSdrConnectStyleData(false, getStyleRight(), basegfx::B2DVector(aBottomRight - aTopRight), false); } - - CreateBorderPrimitives( - aRetval, - aTopLeft, - aVector, - getStyleTop(), - aStartStyleVectorTable, - aEndStyleVectorTable, - nullptr); } if(getStyleRight().IsUsed()) { // create BorderPrimitive(s) for right border const basegfx::B2DVector aVector(aBottomRight - aTopRight); - svx::frame::StyleVectorTable aStartStyleVectorTable; - svx::frame::StyleVectorTable aEndStyleVectorTable; + aData->emplace_back( + aTopRight, + aVector, + getStyleRight(), + nullptr); + drawinglayer::primitive2d::SdrFrameBorderData& rInstance(aData->back()); if(getStyleTop().IsUsed()) { - aStartStyleVectorTable.add(getStyleTop(), aVector, basegfx::B2DVector(aTopLeft - aTopRight), false); + rInstance.addSdrConnectStyleData(true, getStyleTop(), basegfx::B2DVector(aTopLeft - aTopRight), false); } if(getStyleBottom().IsUsed()) { - aEndStyleVectorTable.add(getStyleBottom(), -aVector, basegfx::B2DVector(aBottomLeft - aBottomRight), false); + rInstance.addSdrConnectStyleData(false, getStyleBottom(), basegfx::B2DVector(aBottomLeft - aBottomRight), false); } - - CreateBorderPrimitives( - aRetval, - aTopRight, - aVector, - getStyleRight(), - aStartStyleVectorTable, - aEndStyleVectorTable, - nullptr); } if(getStyleBottom().IsUsed()) { // create BorderPrimitive(s) for bottom border const basegfx::B2DVector aVector(aBottomLeft - aBottomRight); - svx::frame::StyleVectorTable aStartStyleVectorTable; - svx::frame::StyleVectorTable aEndStyleVectorTable; + aData->emplace_back( + aBottomRight, + aVector, + getStyleBottom(), + nullptr); + drawinglayer::primitive2d::SdrFrameBorderData& rInstance(aData->back()); if(getStyleRight().IsUsed()) { - aStartStyleVectorTable.add(getStyleRight(), aVector, basegfx::B2DVector(aTopRight - aBottomRight), false); + rInstance.addSdrConnectStyleData(true, getStyleRight(), basegfx::B2DVector(aTopRight - aBottomRight), false); } if(getStyleLeft().IsUsed()) { - aEndStyleVectorTable.add(getStyleLeft(), -aVector, basegfx::B2DVector(aTopLeft - aBottomLeft), false); + rInstance.addSdrConnectStyleData(false, getStyleLeft(), basegfx::B2DVector(aTopLeft - aBottomLeft), false); } - - CreateBorderPrimitives( - aRetval, - aBottomRight, - aVector, - getStyleBottom(), - aStartStyleVectorTable, - aEndStyleVectorTable, - nullptr); } if(getStyleLeft().IsUsed()) { // create BorderPrimitive(s) for left border const basegfx::B2DVector aVector(aTopLeft - aBottomLeft); - svx::frame::StyleVectorTable aStartStyleVectorTable; - svx::frame::StyleVectorTable aEndStyleVectorTable; + aData->emplace_back( + aBottomLeft, + aVector, + getStyleLeft(), + nullptr); + drawinglayer::primitive2d::SdrFrameBorderData& rInstance(aData->back()); if(getStyleBottom().IsUsed()) { - aStartStyleVectorTable.add(getStyleBottom(), aVector, basegfx::B2DVector(aBottomRight - aBottomLeft), false); + rInstance.addSdrConnectStyleData(true, getStyleBottom(), basegfx::B2DVector(aBottomRight - aBottomLeft), false); } if(getStyleTop().IsUsed()) { - aEndStyleVectorTable.add(getStyleTop(), -aVector, basegfx::B2DVector(aTopRight - aTopLeft), false); + rInstance.addSdrConnectStyleData(false, getStyleTop(), basegfx::B2DVector(aTopRight - aTopLeft), false); } + } - CreateBorderPrimitives( - aRetval, - aBottomLeft, - aVector, - getStyleLeft(), - aStartStyleVectorTable, - aEndStyleVectorTable, - nullptr); + // create instance of SdrFrameBorderPrimitive2D if + // SdrFrameBorderDataVector is used + if(!aData->empty()) + { + aRetval.push_back( + drawinglayer::primitive2d::Primitive2DReference( + new drawinglayer::primitive2d::SdrFrameBorderPrimitive2D( + aData, + true))); } return aRetval; _______________________________________________ Libreoffice-commits mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
