basegfx/source/matrix/b2dhommatrixtools.cxx | 14 drawinglayer/CppunitTest_drawinglayer_border.mk | 1 drawinglayer/qa/unit/border.cxx | 81 drawinglayer/source/primitive2d/baseprimitive2d.cxx | 1 drawinglayer/source/primitive2d/borderlineprimitive2d.cxx | 493 +++- drawinglayer/source/processor2d/vclpixelprocessor2d.hxx | 1 include/basegfx/matrix/b2dhommatrixtools.hxx | 9 include/drawinglayer/primitive2d/borderlineprimitive2d.hxx | 99 include/drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx | 1 include/svx/framelink.hxx | 369 --- include/svx/framelinkarray.hxx | 44 include/svx/sdr/primitive2d/svx_primitivetypes2d.hxx | 19 sc/source/ui/miscdlgs/autofmt.cxx | 21 sc/source/ui/view/output.cxx | 9 svx/source/dialog/framelink.cxx | 1126 +++++----- svx/source/dialog/framelinkarray.cxx | 872 +++---- svx/source/dialog/frmsel.cxx | 37 svx/source/inc/frmselimpl.hxx | 1 svx/source/table/viewcontactoftableobj.cxx | 513 ---- sw/source/core/layout/paintfrm.cxx | 404 +-- sw/source/ui/table/tautofmt.cxx | 13 21 files changed, 1895 insertions(+), 2233 deletions(-)
New commits: commit ab65fe804cf3a97bd172b5551b553b9bcde6d756 Author: Armin Le Grand <[email protected]> Date: Thu Sep 14 16:45:56 2017 +0200 borderline: Extended decompose Decompose of BorderLinePrimitive2D extended to take care of non-perpendicular line endings for matching. Improved matching, one error in calc fixed Change-Id: I869a75385711b58e6725daba0f22be8a98158ad9 diff --git a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx index 6295d4673c36..0b6dda423adf 100644 --- a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx @@ -149,15 +149,118 @@ namespace drawinglayer if(!candidate.isGap()) { const basegfx::B2DVector aDeltaY(aPerpendicular * (fOffset + (fWidth * 0.5))); - const basegfx::B2DPoint aStart(getStart() - (aVector * candidate.getStartAverage()) + aDeltaY); - const basegfx::B2DPoint aEnd(getEnd() + (aVector * candidate.getEndAverage()) + aDeltaY); - - addPolygonStrokePrimitive2D( - rContainer, - aStart, - aEnd, - candidate.getLineAttribute(), - getStrokeAttribute()); + const basegfx::B2DPoint aStart(getStart() + aDeltaY); + const basegfx::B2DPoint aEnd(getEnd() + aDeltaY); + const bool bStartPerpendicular(rtl::math::approxEqual(candidate.getStartLeft(), candidate.getStartRight())); + const bool bEndPerpendicular(rtl::math::approxEqual(candidate.getEndLeft(), candidate.getEndRight())); + + if(bStartPerpendicular && bEndPerpendicular) + { + // start and end extends lead to an edge perpendicular to the line, so we can just use + // a PolygonStrokePrimitive2D for representation + addPolygonStrokePrimitive2D( + rContainer, + aStart - (aVector * candidate.getStartLeft()), + aEnd + (aVector * candidate.getEndLeft()), + candidate.getLineAttribute(), + getStrokeAttribute()); + } + else + { + // start and/or end extensions lead to a lineStart/End that is *not* + // perpendicular to the line itself + if(getStrokeAttribute().isDefault() || 0.0 == getStrokeAttribute().getFullDotDashLen()) + { + // without stroke, we can simply represent that using a filled polygon + const basegfx::B2DVector aHalfLineOffset(aPerpendicular * (candidate.getLineAttribute().getWidth() * 0.5)); + basegfx::B2DPolygon aPolygon; + + aPolygon.append(aStart - aHalfLineOffset - (aVector * candidate.getStartLeft())); + aPolygon.append(aEnd - aHalfLineOffset + (aVector * candidate.getEndLeft())); + aPolygon.append(aEnd + aHalfLineOffset + (aVector * candidate.getEndRight())); + aPolygon.append(aStart + aHalfLineOffset - (aVector * candidate.getStartRight())); + + rContainer.push_back( + new PolyPolygonColorPrimitive2D( + basegfx::B2DPolyPolygon(aPolygon), + candidate.getLineAttribute().getColor())); + } + else + { + // with stroke, we have a problem - a filled polygon would lose the + // stroke. Let's represent the start and/or end as triangles, the main + // line still as PolygonStrokePrimitive2D. + // Fill default line Start/End for stroke, so we need no adaptions in else pathes + basegfx::B2DPoint aStrokeStart(aStart - (aVector * candidate.getStartLeft())); + basegfx::B2DPoint aStrokeEnd(aEnd + (aVector * candidate.getEndLeft())); + const basegfx::B2DVector aHalfLineOffset(aPerpendicular * (candidate.getLineAttribute().getWidth() * 0.5)); + + if(!bStartPerpendicular) + { + const double fMin(std::min(candidate.getStartLeft(), candidate.getStartRight())); + const double fMax(std::max(candidate.getStartLeft(), candidate.getStartRight())); + basegfx::B2DPolygon aPolygon; + + // create a triangle with min/max values for LineStart and add + if(rtl::math::approxEqual(candidate.getStartLeft(), fMax)) + { + aPolygon.append(aStart - aHalfLineOffset - (aVector * candidate.getStartLeft())); + } + + aPolygon.append(aStart - aHalfLineOffset - (aVector * fMin)); + aPolygon.append(aStart + aHalfLineOffset - (aVector * fMin)); + + if(rtl::math::approxEqual(candidate.getStartRight(), fMax)) + { + aPolygon.append(aStart + aHalfLineOffset - (aVector * candidate.getStartRight())); + } + + rContainer.push_back( + new PolyPolygonColorPrimitive2D( + basegfx::B2DPolyPolygon(aPolygon), + candidate.getLineAttribute().getColor())); + + // Adapt StrokeStart accordingly + aStrokeStart = aStart - (aVector * fMin); + } + + if(!bEndPerpendicular) + { + const double fMin(std::min(candidate.getEndLeft(), candidate.getEndRight())); + const double fMax(std::max(candidate.getEndLeft(), candidate.getEndRight())); + basegfx::B2DPolygon aPolygon; + + // create a triangle with min/max values for LineEnd and add + if(rtl::math::approxEqual(candidate.getEndLeft(), fMax)) + { + aPolygon.append(aEnd - aHalfLineOffset + (aVector * candidate.getEndLeft())); + } + + if(rtl::math::approxEqual(candidate.getEndRight(), fMax)) + { + aPolygon.append(aEnd + aHalfLineOffset + (aVector * candidate.getEndRight())); + } + + aPolygon.append(aEnd + aHalfLineOffset + (aVector * fMin)); + aPolygon.append(aEnd - aHalfLineOffset + (aVector * fMin)); + + rContainer.push_back( + new PolyPolygonColorPrimitive2D( + basegfx::B2DPolyPolygon(aPolygon), + candidate.getLineAttribute().getColor())); + + // Adapt StrokeEnd accordingly + aStrokeEnd = aEnd + (aVector * fMin); + } + + addPolygonStrokePrimitive2D( + rContainer, + aStrokeStart, + aStrokeEnd, + candidate.getLineAttribute(), + getStrokeAttribute()); + } + } } fOffset += fWidth; diff --git a/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx b/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx index b6634f6ce64e..cb57e40fbe8a 100644 --- a/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx +++ b/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx @@ -79,10 +79,6 @@ namespace drawinglayer /// helper to get adapted width (maximum) double getAdaptedWidth(double fMinWidth) const; - /// helper to get average values Start/End - double getStartAverage() const { return 0.5 * (mfStartLeft + mfStartRight); } - double getEndAverage() const { return 0.5 * (mfEndLeft + mfEndRight); } - /// compare operator bool operator==(const BorderLine& rBorderLine) const; }; diff --git a/sc/source/ui/view/output.cxx b/sc/source/ui/view/output.cxx index da4c342d44d6..858ea99ef83f 100644 --- a/sc/source/ui/view/output.cxx +++ b/sc/source/ui/view/output.cxx @@ -660,7 +660,7 @@ void ScOutputData::SetCellRotations() const double fOrient((bLayoutRTL ? -1.0 : 1.0) * nAttrRotate * F_PI18000); // 1/100th degrees -> [0..2PI] svx::frame::Array& rArray = mrTabInfo.maArray; - rArray.SetCellRotation(nY+1, nX+1, eRotMode, fOrient); + rArray.SetCellRotation(nX+1, nY+1, eRotMode, fOrient); } } } diff --git a/svx/source/dialog/framelink.cxx b/svx/source/dialog/framelink.cxx index ea5b33315cfc..e205560df33c 100644 --- a/svx/source/dialog/framelink.cxx +++ b/svx/source/dialog/framelink.cxx @@ -550,12 +550,15 @@ void getAllCutSets( for(const auto& rOtherOffset : otherOffsets) { - const basegfx::B2DPoint aOtherLeft(rOrigin + (aOtherPerpend * (rOtherOffset.mfOffset - rOtherOffset.mfHalfWidth))); - const basegfx::B2DPoint aOtherRight(rOrigin + (aOtherPerpend * (rOtherOffset.mfOffset + rOtherOffset.mfHalfWidth))); - CutSet aCutSet; + if(0xff != rOtherOffset.maColor.GetTransparency()) + { + const basegfx::B2DPoint aOtherLeft(rOrigin + (aOtherPerpend * (rOtherOffset.mfOffset - rOtherOffset.mfHalfWidth))); + const basegfx::B2DPoint aOtherRight(rOrigin + (aOtherPerpend * (rOtherOffset.mfOffset + rOtherOffset.mfHalfWidth))); + CutSet aCutSet; - getCutSet(aCutSet, rLeft, rRight, rX, aOtherLeft, aOtherRight, rStyleVectorCombination.getB2DVector()); - rCutSets.push_back(aCutSet); + getCutSet(aCutSet, rLeft, rRight, rX, aOtherLeft, aOtherRight, rStyleVectorCombination.getB2DVector()); + rCutSets.push_back(aCutSet); + } } } } @@ -586,22 +589,42 @@ CutSet getMinMaxCutSet( { const CutSet& rCandidate(rCutSets[a]); const double fCandidate(rCandidate.mfOLML + rCandidate.mfORML + rCandidate.mfOLMR + rCandidate.mfORMR); + bool bCopy(false); - if(bMin) + if(basegfx::fTools::equalZero(fCandidate - fRetval)) { - if(fCandidate < fRetval) + // both are equal (use basegfx::fTools::equalZero and *not* rtl::math::approxEqual here, that is too precise) + const bool bPerpendR(rtl::math::approxEqual(aRetval.mfOLML, aRetval.mfOLMR) || rtl::math::approxEqual(aRetval.mfORML, aRetval.mfORMR)); + const bool bPerpendC(rtl::math::approxEqual(rCandidate.mfOLML, rCandidate.mfOLMR) || rtl::math::approxEqual(rCandidate.mfORML, rCandidate.mfORMR)); + + if(!bPerpendR && !bPerpendC) + { + // when both are not perpend, create medium cut + const double fNewOLML(std::max(std::min(rCandidate.mfOLML, rCandidate.mfORML), std::min(aRetval.mfOLML, aRetval.mfORML))); + const double fNewORML(std::min(std::max(rCandidate.mfOLML, rCandidate.mfORML), std::max(aRetval.mfOLML, aRetval.mfORML))); + const double fNewOLMR(std::max(std::min(rCandidate.mfOLMR, rCandidate.mfORMR), std::min(aRetval.mfOLMR, aRetval.mfORMR))); + const double fNewORMR(std::min(std::max(rCandidate.mfOLMR, rCandidate.mfORMR), std::max(aRetval.mfOLMR, aRetval.mfORMR))); + aRetval.mfOLML = fNewOLML; + aRetval.mfORML = fNewORML; + aRetval.mfOLMR = fNewOLMR; + aRetval.mfORMR = fNewORMR; + fRetval = aRetval.mfOLML + aRetval.mfORML + aRetval.mfOLMR + aRetval.mfORMR; + } + else { - fRetval = fCandidate; - aRetval = rCandidate; + // if equal and perpend differs, perpend one is assumed smaller + bCopy = ((bMin && bPerpendC && !bPerpendR) || (!bMin && !bPerpendC && bPerpendR)); } } else { - if(fCandidate > fRetval) - { - fRetval = fCandidate; - aRetval = rCandidate; - } + bCopy = ((bMin && fCandidate < fRetval) || (!bMin && fCandidate > fRetval)); + } + + if(bCopy) + { + fRetval = fCandidate; + aRetval = rCandidate; } } commit 2f16219741aba016677103e4b22738d055c39a91 Author: Armin Le Grand <[email protected]> Date: Thu Sep 14 11:44:23 2017 +0200 borderline: Fixed PatternScale The applied PatternScale factor was not consequently used in svx::frame::Style so that the Previews in the Dialogs look weird. Fixed that and stumbled over Writer applying it's own scale which then was leading to double scaling, ceaned that up. Change-Id: I89f41bfd7884e5e743080301e219491e215054c3 diff --git a/include/svx/framelink.hxx b/include/svx/framelink.hxx index 1b130efa7f2f..414f23aaaca7 100644 --- a/include/svx/framelink.hxx +++ b/include/svx/framelink.hxx @@ -159,11 +159,11 @@ public: /** Constructs an invisible frame style. */ explicit Style(); /** Constructs a frame style with passed line widths. */ - explicit Style( double nP, double nD, double nS, SvxBorderLineStyle nType ); + explicit Style( double nP, double nD, double nS, SvxBorderLineStyle nType, double fScale ); /** Constructs a frame style with passed color and line widths. */ - explicit Style( const Color& rColorPrim, const Color& rColorSecn, const Color& rColorGap, bool bUseGapColor, double nP, double nD, double nS, SvxBorderLineStyle nType ); + explicit Style( const Color& rColorPrim, const Color& rColorSecn, const Color& rColorGap, bool bUseGapColor, double nP, double nD, double nS, SvxBorderLineStyle nType, double fScale ); /** Constructs a frame style from the passed SvxBorderLine struct. */ - explicit Style( const editeng::SvxBorderLine* pBorder, double fScale = 1.0 ); + explicit Style( const editeng::SvxBorderLine* pBorder, double fScale ); RefMode GetRefMode() const { if(!maImplStyle) return RefMode::Centered; return maImplStyle->meRefMode; } const Color GetColorPrim() const { if(!maImplStyle) return Color(); return maImplStyle->maColorPrim; } diff --git a/svx/source/dialog/framelink.cxx b/svx/source/dialog/framelink.cxx index b7554436bf48..ea5b33315cfc 100644 --- a/svx/source/dialog/framelink.cxx +++ b/svx/source/dialog/framelink.cxx @@ -56,19 +56,21 @@ Style::Style() : { } -Style::Style( double nP, double nD, double nS, SvxBorderLineStyle nType ) : +Style::Style( double nP, double nD, double nS, SvxBorderLineStyle nType, double fScale ) : maImplStyle(new implStyle()), mpUsingCell(nullptr) { maImplStyle->mnType = nType; + maImplStyle->mfPatternScale = fScale; Set( nP, nD, nS ); } -Style::Style( const Color& rColorPrim, const Color& rColorSecn, const Color& rColorGap, bool bUseGapColor, double nP, double nD, double nS, SvxBorderLineStyle nType ) : +Style::Style( const Color& rColorPrim, const Color& rColorSecn, const Color& rColorGap, bool bUseGapColor, double nP, double nD, double nS, SvxBorderLineStyle nType, double fScale ) : maImplStyle(new implStyle()), mpUsingCell(nullptr) { maImplStyle->mnType = nType; + maImplStyle->mfPatternScale = fScale; Set( rColorPrim, rColorSecn, rColorGap, bUseGapColor, nP, nD, nS ); } @@ -154,6 +156,7 @@ void Style::Set( const SvxBorderLine* pBorder, double fScale, sal_uInt16 nMaxWid const sal_uInt16 nSecn(pBorder->GetInWidth()); pTarget->mnType = pBorder->GetBorderLineStyle(); + pTarget->mfPatternScale = fScale; if( !nSecn ) // no or single frame border { diff --git a/svx/source/dialog/frmsel.cxx b/svx/source/dialog/frmsel.cxx index 9678339fbca6..291d47903361 100644 --- a/svx/source/dialog/frmsel.cxx +++ b/svx/source/dialog/frmsel.cxx @@ -132,7 +132,7 @@ void FrameBorder::SetCoreStyle( const SvxBorderLine* pStyle ) maCoreStyle = SvxBorderLine(); // from twips to points - maUIStyle.Set( &maCoreStyle, 0.05, FRAMESEL_GEOM_WIDTH ); + maUIStyle.Set( &maCoreStyle, FrameBorder::GetDefaultPatternScale(), FRAMESEL_GEOM_WIDTH ); meState = maUIStyle.IsUsed() ? FrameBorderState::Show : FrameBorderState::Hide; } @@ -150,7 +150,7 @@ void FrameBorder::SetState( FrameBorderState eState ) break; case FrameBorderState::DontCare: maCoreStyle = SvxBorderLine(); - maUIStyle = frame::Style(3, 0, 0, SvxBorderLineStyle::SOLID); //OBJ_FRAMESTYLE_DONTCARE + maUIStyle = frame::Style(3, 0, 0, SvxBorderLineStyle::SOLID, FrameBorder::GetDefaultPatternScale()); //OBJ_FRAMESTYLE_DONTCARE break; } } @@ -643,7 +643,7 @@ void FrameSelectorImpl::DrawAllFrameBorders() rRightStyle.GetColorSecn(), rRightStyle.GetColorGap(), rRightStyle.UseGapColor(), rRightStyle.Secn(), rRightStyle.Dist(), rRightStyle.Prim( ), - rRightStyle.Type( ) ); + rRightStyle.Type( ), rRightStyle.PatternScale() ); maArray.SetColumnStyleRight( mbVer ? 1 : 0, rInvertedRight ); maArray.SetRowStyleTop( 0, maTop.GetUIStyle() ); @@ -655,7 +655,7 @@ void FrameSelectorImpl::DrawAllFrameBorders() rHorStyle.GetColorSecn(), rHorStyle.GetColorGap(), rHorStyle.UseGapColor(), rHorStyle.Secn(), rHorStyle.Dist(), rHorStyle.Prim( ), - rHorStyle.Type() ); + rHorStyle.Type(), rHorStyle.PatternScale() ); maArray.SetRowStyleTop( 1, rInvertedHor ); } @@ -665,7 +665,7 @@ void FrameSelectorImpl::DrawAllFrameBorders() rBottomStyle.GetColorSecn(), rBottomStyle.GetColorGap(), rBottomStyle.UseGapColor(), rBottomStyle.Secn(), rBottomStyle.Dist(), rBottomStyle.Prim( ), - rBottomStyle.Type() ); + rBottomStyle.Type(), rBottomStyle.PatternScale() ); maArray.SetRowStyleBottom( mbHor ? 1 : 0, rInvertedBottom ); for( size_t nCol = 0; nCol < maArray.GetColCount(); ++nCol ) diff --git a/svx/source/inc/frmselimpl.hxx b/svx/source/inc/frmselimpl.hxx index 7e2e73b8238a..62a0d7f3a9d7 100644 --- a/svx/source/inc/frmselimpl.hxx +++ b/svx/source/inc/frmselimpl.hxx @@ -36,6 +36,7 @@ class FrameBorder { public: explicit FrameBorder(FrameBorderType eType); + static double GetDefaultPatternScale() { return 0.05; } FrameBorderType GetType() const { diff --git a/sw/source/core/layout/paintfrm.cxx b/sw/source/core/layout/paintfrm.cxx index 89c4351957a8..4098b2add8f4 100644 --- a/sw/source/core/layout/paintfrm.cxx +++ b/sw/source/core/layout/paintfrm.cxx @@ -2758,20 +2758,11 @@ void SwTabFramePainter::Insert( const SwFrame& rFrame, const SvxBoxItem& rBoxIte bool const bVert = mrTabFrame.IsVertical(); bool const bR2L = mrTabFrame.IsRightToLeft(); - SwViewShell* pViewShell = mrTabFrame.getRootFrame()->GetCurrShell(); - OutputDevice* pOutDev = pViewShell->GetOut(); - const MapMode& rMapMode = pOutDev->GetMapMode(); - const Fraction& rFracX = rMapMode.GetScaleX(); - const Fraction& rFracY = rMapMode.GetScaleY(); - - svx::frame::Style aL(rBoxItem.GetLeft(), rFracY); -// aL.SetPatternScale(rFracY); - svx::frame::Style aR(rBoxItem.GetRight(), rFracY); -// aR.SetPatternScale(rFracY); - svx::frame::Style aT(rBoxItem.GetTop(), rFracX); -// aT.SetPatternScale(rFracX); - svx::frame::Style aB(rBoxItem.GetBottom(), rFracX); -// aB.SetPatternScale(rFracX); + // no scaling needed, it's all in the primitives and the target device + svx::frame::Style aL(rBoxItem.GetLeft(), 1.0); + svx::frame::Style aR(rBoxItem.GetRight(), 1.0); + svx::frame::Style aT(rBoxItem.GetTop(), 1.0); + svx::frame::Style aB(rBoxItem.GetBottom(), 1.0); aR.MirrorSelf(); aB.MirrorSelf(); commit 16fd7af90a9be159ebc7eab09083f1ef7eb64645 Author: Armin Le Grand <[email protected]> Date: Wed Sep 13 18:37:02 2017 +0200 borderline: extended the expand logic Extended and checked the expand logic for creating the line extends. Now creating quite the right lines, will need to check some speccial cases. Also some cleanups. Change-Id: I3a3bd4d23c7017ecd873147df2d93af61de39fa6 diff --git a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx index eba1f7f0d996..6295d4673c36 100644 --- a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx @@ -165,89 +165,6 @@ namespace drawinglayer } } - - - - // static double fPatScFact(10.0); // 10.0 multiply, see old code - // const std::vector<double> aDashing(svtools::GetLineDashing(getStyle(), getPatternScale() * fPatScFact)); - // const attribute::StrokeAttribute aStrokeAttribute(aDashing); - - // if (3 == getBorderLines().size()) - // { - // // double line with gap. Use mfSmallestAllowedDiscreteGapDistance (see get2DDecomposition) as distance. - // // That value is prepared to be at least one pixel (discrete unit) so that the - // // decomposition is view-dependent in this cases - // const BorderLine& rLeft(getBorderLines()[0]); - // const BorderLine& rGap(getBorderLines()[1]); - // const BorderLine& rRight(getBorderLines()[2]); - // const double fFullWidth(rLeft.getWidth() + mfSmallestAllowedDiscreteGapDistance + rRight.getWidth()); - - // { - // // inside line (left of vector). Create stroke primitive centered on left line width - // const double fDeltaY((rLeft.getWidth() - fFullWidth) * 0.5); - // const basegfx::B2DVector aDeltaY(aPerpendicular * fDeltaY); - // const basegfx::B2DPoint aStart(getStart() - (aVector * rLeft.getBorderLineExtend().getStartAverage()) + aDeltaY); - // const basegfx::B2DPoint aEnd(getEnd() + (aVector * rLeft.getBorderLineExtend().getEndAverage()) + aDeltaY); - // const attribute::LineAttribute aLineAttribute(rLeft.getRGBColor(), rLeft.getWidth()); - - // addPolygonStrokePrimitive2D( - // rContainer, - // aStart, - // aEnd, - // aLineAttribute, - // aStrokeAttribute); - // } - - // if (hasGapColor()) - // { - // // gap (if visible, found practical usage in Writer MultiColorBorderLines). - // // Create stroke primitive on vector with given color centered on gap position - // const double fDeltaY(((fFullWidth - mfSmallestAllowedDiscreteGapDistance) * 0.5) - rRight.getWidth()); - // const basegfx::B2DVector aDeltaY(aPerpendicular * fDeltaY); - // const basegfx::B2DPoint aStart(getStart() - (aVector * rGap.getBorderLineExtend().getStartAverage()) + aDeltaY); - // const basegfx::B2DPoint aEnd(getEnd() + (aVector * rGap.getBorderLineExtend().getEndAverage()) + aDeltaY); - // const attribute::LineAttribute aLineAttribute(rGap.getRGBColor(), mfSmallestAllowedDiscreteGapDistance); - - // addPolygonStrokePrimitive2D( - // rContainer, - // aStart, - // aEnd, - // aLineAttribute, - // aStrokeAttribute); - // } - - // { - // // outside line (right of vector). Create stroke primitive centered on right line width - // const double fDeltaY((fFullWidth - rRight.getWidth()) * 0.5); - // const basegfx::B2DVector aDeltaY(aPerpendicular * fDeltaY); - // const basegfx::B2DPoint aStart(getStart() - (aVector * rRight.getBorderLineExtend().getStartAverage()) + aDeltaY); - // const basegfx::B2DPoint aEnd(getEnd() + (aVector * rRight.getBorderLineExtend().getEndAverage()) + aDeltaY); - // const attribute::LineAttribute aLineAttribute(rRight.getRGBColor(), rRight.getWidth()); - - // addPolygonStrokePrimitive2D( - // rContainer, - // aStart, - // aEnd, - // aLineAttribute, - // aStrokeAttribute); - // } - // } - // else - // { - // // single line, only inside values used, no vertical offsets - // const BorderLine& rBorderLine(getBorderLines()[0]); - // const attribute::LineAttribute aLineAttribute(rBorderLine.getRGBColor(), rBorderLine.getWidth()); - - // addPolygonStrokePrimitive2D( - // rContainer, - // getStart() - (aVector * rBorderLine.getBorderLineExtend().getStartAverage()), - // getEnd() + (aVector * rBorderLine.getBorderLineExtend().getEndAverage()), - // aLineAttribute, - // aStrokeAttribute); - // } - // } - // } - bool BorderLinePrimitive2D::isHorizontalOrVertical(const geometry::ViewInformation2D& rViewInformation) const { if (!getStart().equal(getEnd())) diff --git a/svx/source/dialog/framelink.cxx b/svx/source/dialog/framelink.cxx index c7a6377ab3e8..b7554436bf48 100644 --- a/svx/source/dialog/framelink.cxx +++ b/svx/source/dialog/framelink.cxx @@ -380,6 +380,7 @@ double getOffsetAndHalfWidthAndColorFromStyle( Color aSecn(rStyle.GetColorSecn()); double fPrim(rStyle.Prim()); double fSecn(rStyle.Secn()); + const bool bSecnUsed(0.0 != fSecn); if(bMirrored) { @@ -389,8 +390,12 @@ double getOffsetAndHalfWidthAndColorFromStyle( case RefMode::End: aRefMode = RefMode::Begin; break; default: break; } - std::swap(aPrim, aSecn); - std::swap(fPrim, fSecn); + + if(bSecnUsed) + { + std::swap(aPrim, aSecn); + std::swap(fPrim, fSecn); + } } if (RefMode::Centered != aRefMode) @@ -409,7 +414,7 @@ double getOffsetAndHalfWidthAndColorFromStyle( } } - if (rStyle.Dist() && fSecn) + if (bSecnUsed) { // both or all three lines used const bool bPrimTransparent(0xff == rStyle.GetColorPrim().GetTransparency()); @@ -503,6 +508,103 @@ void getCutSet( &rCutSet.mfORMR); } +void getAllCutSets( + std::vector< CutSet >& rCutSets, + const basegfx::B2DPoint& rOrigin, + const basegfx::B2DPoint& rLeft, + const basegfx::B2DPoint& rRight, + const basegfx::B2DVector& rX, + const StyleVectorTable& rStyleVectorTable, + bool bUpper, + bool bLower) +{ + for(const auto& rStyleVectorCombination : rStyleVectorTable) + { + if(bUpper || bLower) + { + // use only upper or lower vectors compared to rX + const double fCross(rX.cross(rStyleVectorCombination.getB2DVector())); + + if(bUpper && fCross > 0.0) + { + // upper vectors wanted, but is lower + continue; + } + + if(bLower && fCross < 0.0) + { + // lower vectors wanted, but is upper + continue; + } + } + + std::vector< OffsetAndHalfWidthAndColor > otherOffsets; + getOffsetAndHalfWidthAndColorFromStyle(rStyleVectorCombination.getStyle(), nullptr, rStyleVectorCombination.isMirrored(), otherOffsets); + + if(!otherOffsets.empty()) + { + const basegfx::B2DVector aOtherPerpend(basegfx::getNormalizedPerpendicular(rStyleVectorCombination.getB2DVector())); + + for(const auto& rOtherOffset : otherOffsets) + { + const basegfx::B2DPoint aOtherLeft(rOrigin + (aOtherPerpend * (rOtherOffset.mfOffset - rOtherOffset.mfHalfWidth))); + const basegfx::B2DPoint aOtherRight(rOrigin + (aOtherPerpend * (rOtherOffset.mfOffset + rOtherOffset.mfHalfWidth))); + CutSet aCutSet; + + getCutSet(aCutSet, rLeft, rRight, rX, aOtherLeft, aOtherRight, rStyleVectorCombination.getB2DVector()); + rCutSets.push_back(aCutSet); + } + } + } +} + +CutSet getMinMaxCutSet( + bool bMin, + const std::vector< CutSet >& rCutSets) +{ + if(rCutSets.empty()) + { + CutSet aRetval; + aRetval.mfOLML = aRetval.mfORML = aRetval.mfOLMR = aRetval.mfORMR = 0.0; + return aRetval; + } + + const size_t aSize(rCutSets.size()); + + if(1 == aSize) + { + return rCutSets[0]; + } + + CutSet aRetval(rCutSets[0]); + double fRetval(aRetval.mfOLML + aRetval.mfORML + aRetval.mfOLMR + aRetval.mfORMR); + + for(size_t a(1); a < aSize; a++) + { + const CutSet& rCandidate(rCutSets[a]); + const double fCandidate(rCandidate.mfOLML + rCandidate.mfORML + rCandidate.mfOLMR + rCandidate.mfORMR); + + if(bMin) + { + if(fCandidate < fRetval) + { + fRetval = fCandidate; + aRetval = rCandidate; + } + } + else + { + if(fCandidate > fRetval) + { + fRetval = fCandidate; + aRetval = rCandidate; + } + } + } + + return aRetval; +} + void getExtends( std::vector<ExtendSet>& rExtendSet, // target Left/Right values to fill const basegfx::B2DPoint& rOrigin, // own vector start @@ -518,41 +620,99 @@ void getExtends( for(size_t a(0); a < nOffsets; a++) { const OffsetAndHalfWidthAndColor& rOffset(rOffsets[a]); - ExtendSet& rExt(rExtendSet[a]); - bool bExtSet(false); - const basegfx::B2DPoint aLeft(rOrigin + (rPerpendX * (rOffset.mfOffset - rOffset.mfHalfWidth))); - const basegfx::B2DPoint aRight(rOrigin + (rPerpendX * (rOffset.mfOffset + rOffset.mfHalfWidth))); - for(const auto& rStyleVectorCombination : rStyleVectorTable) + if(0xff != rOffset.maColor.GetTransparency()) { - std::vector< OffsetAndHalfWidthAndColor > otherOffsets; - getOffsetAndHalfWidthAndColorFromStyle(rStyleVectorCombination.getStyle(), nullptr, rStyleVectorCombination.isMirrored(), otherOffsets); + const basegfx::B2DPoint aLeft(rOrigin + (rPerpendX * (rOffset.mfOffset - rOffset.mfHalfWidth))); + const basegfx::B2DPoint aRight(rOrigin + (rPerpendX * (rOffset.mfOffset + rOffset.mfHalfWidth))); + std::vector< CutSet > aCutSets; + CutSet aResult; + bool bResultSet(false); + + if(1 == nOffsets) + { + // single line: + // - get all CutSets + // - get minimum values as extension (biggest possible overlap) + getAllCutSets(aCutSets, rOrigin, aLeft, aRight, rX, rStyleVectorTable, false, false); - if(!otherOffsets.empty()) + if(!aCutSets.empty()) + { + aResult = getMinMaxCutSet(true, aCutSets); + bResultSet = true; + } + } + else { - const basegfx::B2DVector aOtherPerpend(basegfx::getNormalizedPerpendicular(rStyleVectorCombination.getB2DVector())); + // multiple lines + const bool bUpper(a < (nOffsets >> 1)); + const bool bLower(a > (nOffsets >> 1)); - for(const auto& rOtherOffset : otherOffsets) + if(bUpper) { - const basegfx::B2DPoint aOtherLeft(rOrigin + (aOtherPerpend * (rOtherOffset.mfOffset - rOtherOffset.mfHalfWidth))); - const basegfx::B2DPoint aOtherRight(rOrigin + (aOtherPerpend * (rOtherOffset.mfOffset + rOtherOffset.mfHalfWidth))); - CutSet aCutSet; + getAllCutSets(aCutSets, rOrigin, aLeft, aRight, rX, rStyleVectorTable, true, false); + + if(!aCutSets.empty()) + { + aResult = getMinMaxCutSet(false, aCutSets); + bResultSet = true; + } + else + { + getAllCutSets(aCutSets, rOrigin, aLeft, aRight, rX, rStyleVectorTable, false, true); - getCutSet(aCutSet, aLeft, aRight, rX, aOtherLeft, aOtherRight, rStyleVectorCombination.getB2DVector()); + if(!aCutSets.empty()) + { + aResult = getMinMaxCutSet(true, aCutSets); + bResultSet = true; + } + } + } + else if(bLower) + { + getAllCutSets(aCutSets, rOrigin, aLeft, aRight, rX, rStyleVectorTable, false, true); - if(!bExtSet) + if(!aCutSets.empty()) { - rExt.mfExtLeft = std::min(aCutSet.mfOLML, aCutSet.mfORML); - rExt.mfExtRight = std::min(aCutSet.mfOLMR, aCutSet.mfORMR); - bExtSet = true; + aResult = getMinMaxCutSet(false, aCutSets); + bResultSet = true; } else { - rExt.mfExtLeft = std::min(rExt.mfExtLeft , std::min(aCutSet.mfOLML, aCutSet.mfORML)); - rExt.mfExtRight = std::min(rExt.mfExtRight , std::min(aCutSet.mfOLMR, aCutSet.mfORMR)); + getAllCutSets(aCutSets, rOrigin, aLeft, aRight, rX, rStyleVectorTable, true, false); + + if(!aCutSets.empty()) + { + aResult = getMinMaxCutSet(true, aCutSets); + bResultSet = true; + } + } + } + else // middle line + { + getAllCutSets(aCutSets, rOrigin, aLeft, aRight, rX, rStyleVectorTable, false, false); + + if(!aCutSets.empty()) + { + const CutSet aResultMin(getMinMaxCutSet(true, aCutSets)); + const CutSet aResultMax(getMinMaxCutSet(false, aCutSets)); + + aResult.mfOLML = (aResultMin.mfOLML + aResultMax.mfOLML) * 0.5; + aResult.mfORML = (aResultMin.mfORML + aResultMax.mfORML) * 0.5; + aResult.mfOLMR = (aResultMin.mfOLMR + aResultMax.mfOLMR) * 0.5; + aResult.mfORMR = (aResultMin.mfORMR + aResultMax.mfORMR) * 0.5; + bResultSet = true; } } } + + if(bResultSet) + { + ExtendSet& rExt(rExtendSet[a]); + + rExt.mfExtLeft = std::min(aResult.mfOLML, aResult.mfORML); + rExt.mfExtRight = std::min(aResult.mfOLMR, aResult.mfORMR); + } } } } @@ -588,9 +748,22 @@ void CreateBorderPrimitives( if(bHasEndStyles) { - // create extends for line ends, use inverse point/vector and inverse offsets - std::reverse(myOffsets.begin(), myOffsets.end()); - getExtends(aExtendSetEnd, rOrigin + rX, -rX, -aPerpendX, myOffsets, rEndStyleVectorTable); + // Create extends for line ends, use inverse point/vector and inverse offsets. + // Offsets need to be inverted for different width of lines. To invert, change + // order, but also sign of offset. Do this on a copy since myOffsets will be + // used below to create the primitives + std::vector< OffsetAndHalfWidthAndColor > myInverseOffsets(myOffsets); + std::reverse(myInverseOffsets.begin(), myInverseOffsets.end()); + + for(auto& offset : myInverseOffsets) + { + offset.mfOffset *= -1; + } + + getExtends(aExtendSetEnd, rOrigin + rX, -rX, -aPerpendX, myInverseOffsets, rEndStyleVectorTable); + + // also need to reverse the result to apply to the correct lines + std::reverse(aExtendSetEnd.begin(), aExtendSetEnd.end()); } std::vector< drawinglayer::primitive2d::BorderLine > aBorderlines; diff --git a/svx/source/dialog/framelinkarray.cxx b/svx/source/dialog/framelinkarray.cxx index db54294640c5..5a526145cd54 100644 --- a/svx/source/dialog/framelinkarray.cxx +++ b/svx/source/dialog/framelinkarray.cxx @@ -988,7 +988,7 @@ void HelperCreateVerticalEntry( if(rStartFromBR.IsUsed()) aStart.push_back(StyleVectorCombination(rStartFromBR, rX + rY, false)); if(rStartTFromR.IsUsed()) aStart.push_back(StyleVectorCombination(rStartTFromR, rX, false)); - if(rStartTFromT.IsUsed()) aStart.push_back(StyleVectorCombination(rStartTFromT, rY, true)); + if(rStartTFromT.IsUsed()) aStart.push_back(StyleVectorCombination(rStartTFromT, -rY, true)); if(rStartTFromL.IsUsed()) aStart.push_back(StyleVectorCombination(rStartTFromL, -rX, true)); if(rStartFromBL.IsUsed()) aStart.push_back(StyleVectorCombination(rStartFromBL, rY - rX, true)); @@ -1002,9 +1002,9 @@ void HelperCreateVerticalEntry( if(rEndFromTR.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndFromTR, rX - rY, false)); if(rEndBFromR.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndBFromR, rX, false)); - if(rEndBFromB.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndBFromB, -rY, false)); - if(rEndBFromL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndBFromL, rX, true)); - if(rEndFromTL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndFromTL, rX + rY, true)); + if(rEndBFromB.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndBFromB, rY, false)); + if(rEndBFromL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndBFromL, -rX, true)); + if(rEndFromTL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndFromTL, -rX - rY, true)); CreateBorderPrimitives( rSequence, commit 1f02af4dbd13d79647549e1269722e2c0b67fa90 Author: Armin Le Grand <[email protected]> Date: Wed Sep 13 10:29:29 2017 +0200 borderline: Added merge BorderLinePrimitive2D Added BorderLinePrimitive2D merges for Writer and fixes. diff --git a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx index 5fc3b57fbbda..eba1f7f0d996 100644 --- a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx @@ -439,7 +439,15 @@ namespace drawinglayer return Primitive2DReference(); } - if(!rBT.isGap()) + if(rBT.isGap()) + { + // when gap, width has to be equal + if(!rtl::math::approxEqual(rBT.getLineAttribute().getWidth(), rBC.getLineAttribute().getWidth())) + { + return Primitive2DReference(); + } + } + else { // when not gap, the line extends have at least reach to the center ( > 0.0), // else there is a extend usage. When > 0.0 they just overlap, no problem @@ -465,11 +473,18 @@ namespace drawinglayer const BorderLine& rBT(pCandidateA->getBorderLines()[a]); const BorderLine& rBC(pCandidateB->getBorderLines()[a]); - aMergedBorderLines.push_back( - BorderLine( - rBT.getLineAttribute(), - rBT.getStartLeft(), rBT.getStartRight(), - rBC.getEndLeft(), rBC.getEndRight())); + if(rBT.isGap()) + { + aMergedBorderLines.push_back(rBT); + } + else + { + aMergedBorderLines.push_back( + BorderLine( + rBT.getLineAttribute(), + rBT.getStartLeft(), rBT.getStartRight(), + rBC.getEndLeft(), rBC.getEndRight())); + } } return Primitive2DReference( diff --git a/include/svx/framelinkarray.hxx b/include/svx/framelinkarray.hxx index 83b6c28d2524..2b06d29a41b2 100644 --- a/include/svx/framelinkarray.hxx +++ b/include/svx/framelinkarray.hxx @@ -319,6 +319,11 @@ private: std::unique_ptr<ArrayImpl> 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/svx/source/dialog/framelinkarray.cxx b/svx/source/dialog/framelinkarray.cxx index 2d81caebd3a7..db54294640c5 100644 --- a/svx/source/dialog/framelinkarray.cxx +++ b/svx/source/dialog/framelinkarray.cxx @@ -249,9 +249,6 @@ struct ArrayImpl long GetColPosition( size_t nCol ) const; long GetRowPosition( size_t nRow ) const; - long GetColWidth( size_t nFirstCol, size_t nLastCol ) const; - long GetRowHeight( size_t nFirstRow, size_t nLastRow ) const; - bool HasCellRotation() const; }; @@ -375,16 +372,6 @@ long ArrayImpl::GetRowPosition( size_t nRow ) const return maYCoords[ nRow ]; } -long ArrayImpl::GetColWidth( size_t nFirstCol, size_t nLastCol ) const -{ - return GetColPosition( nLastCol + 1 ) - GetColPosition( nFirstCol ); -} - -long ArrayImpl::GetRowHeight( size_t nFirstRow, size_t nLastRow ) const -{ - return GetRowPosition( nLastRow + 1 ) - GetRowPosition( nFirstRow ); -} - bool ArrayImpl::HasCellRotation() const { // check cell array diff --git a/svx/source/table/viewcontactoftableobj.cxx b/svx/source/table/viewcontactoftableobj.cxx index 52d6ce42b943..90d143665140 100644 --- a/svx/source/table/viewcontactoftableobj.cxx +++ b/svx/source/table/viewcontactoftableobj.cxx @@ -208,14 +208,14 @@ namespace sdr const basegfx::B2DVector aY(basegfx::getNormalizedPerpendicular(rX)); /// Fill top-left Style Table - if(rLeftA.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftA, -aY, bHor ? true : false)); - if(rLeftB.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftB, -rX, bHor ? true : true)); - if(rLeftC.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftC, aY, bHor ? false : true)); + if(rLeftA.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftA, -aY, bHor)); // bHor ? true : false)); + if(rLeftB.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftB, -rX, true)); // bHor ? true : true)); + if(rLeftC.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftC, aY, !bHor)); // bHor ? false : true)); /// Fill bottom-right Style Table - if(rRightA.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightA, -aY, bHor ? true : false)); - if(rRightB.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightB, rX, bHor ? false : false)); - if(rRightC.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightC, aY, bHor ? false : true)); + if(rRightA.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightA, -aY, bHor)); // bHor ? true : false)); + if(rRightB.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightB, rX, false)); // bHor ? false : false)); + if(rRightC.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightC, aY, !bHor)); // bHor ? false : true)); CreateBorderPrimitives( rContainer, diff --git a/sw/source/core/layout/paintfrm.cxx b/sw/source/core/layout/paintfrm.cxx index 4ba2fc11ec57..89c4351957a8 100644 --- a/sw/source/core/layout/paintfrm.cxx +++ b/sw/source/core/layout/paintfrm.cxx @@ -88,6 +88,7 @@ #include <drawinglayer/primitive2d/textlayoutdevice.hxx> #include <drawinglayer/processor2d/processorfromoutputdevice.hxx> #include <svx/unoapi.hxx> +#include <svx/framelinkarray.hxx> #include <comphelper/sequence.hxx> #include <basegfx/matrix/b2dhommatrixtools.hxx> #include <basegfx/color/bcolortools.hxx> @@ -2431,7 +2432,8 @@ 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 aSequence; + drawinglayer::primitive2d::Primitive2DContainer aHorizontalSequence; + drawinglayer::primitive2d::Primitive2DContainer aVerticalSequence; while ( true ) { @@ -2559,7 +2561,7 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons if(aStyles[ 6 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 6 ], aY, false)); // aRFromB CreateBorderPrimitives( - aSequence, + aHorizontalSequence, aOrigin, aX, aStyles[ 0 ], @@ -2589,7 +2591,7 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons if(aStyles[ 4 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 4 ], aY, true)); // aBFromL CreateBorderPrimitives( - aSequence, + aVerticalSequence, aOrigin, aX, aStyles[ 0 ], @@ -2604,6 +2606,14 @@ 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); // restore output device: commit 53599a9a183878cdf435f80939f8d301a3909d78 Author: Armin Le Grand <[email protected]> Date: Tue Sep 12 17:28:54 2017 +0200 borderline: merge redefined, mirrored Styles Redefined merge of BorderlinePrimitives, removed old Writer stuff for it. Also added support for handling Styles mirrored for extension calculations. diff --git a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx index 9421ed8b249b..5fc3b57fbbda 100644 --- a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx @@ -144,7 +144,7 @@ namespace drawinglayer for(const auto& candidate : maBorderLines) { - const double fWidth(candidate.getAdaptedWidth(mfSmallestAllowedDiscreteGapDistance) * 0.5); + const double fWidth(candidate.getAdaptedWidth(mfSmallestAllowedDiscreteGapDistance)); if(!candidate.isGap()) { @@ -369,6 +369,116 @@ namespace drawinglayer // provide unique ID ImplPrimitive2DIDBlock(BorderLinePrimitive2D, PRIMITIVE2D_ID_BORDERLINEPRIMITIVE2D) + Primitive2DReference tryMergeBorderLinePrimitive2D( + const Primitive2DReference& rCandidateA, + const Primitive2DReference& rCandidateB) + { + // try to cast to BorderLinePrimitive2D + const primitive2d::BorderLinePrimitive2D* pCandidateA = dynamic_cast< const primitive2d::BorderLinePrimitive2D* >(rCandidateA.get()); + const primitive2d::BorderLinePrimitive2D* pCandidateB = dynamic_cast< const primitive2d::BorderLinePrimitive2D* >(rCandidateB.get()); + + // we need a comparable BorderLinePrimitive2D + if(nullptr == pCandidateA || nullptr == pCandidateB) + { + return Primitive2DReference(); + } + + // start of candidate has to match end of this + if(!pCandidateA->getEnd().equal(pCandidateB->getStart())) + { + return Primitive2DReference(); + } + + // candidate A needs a length + if(pCandidateA->getStart().equal(pCandidateA->getEnd())) + { + return Primitive2DReference(); + } + + // candidate B needs a length + if(pCandidateB->getStart().equal(pCandidateB->getEnd())) + { + return Primitive2DReference(); + } + + // StrokeAttribute has to be equal + if(!(pCandidateA->getStrokeAttribute() == pCandidateB->getStrokeAttribute())) + { + return Primitive2DReference(); + } + + // direction has to be equal -> cross product == 0.0 + const basegfx::B2DVector aVT(pCandidateA->getEnd() - pCandidateA->getStart()); + const basegfx::B2DVector aVC(pCandidateB->getEnd() - pCandidateB->getStart()); + if(!rtl::math::approxEqual(0.0, aVC.cross(aVT))) + { + return Primitive2DReference(); + } + + // number BorderLines has to be equal + const size_t count(pCandidateA->getBorderLines().size()); + if(count != pCandidateB->getBorderLines().size()) + { + return Primitive2DReference(); + } + + for(size_t a(0); a < count; a++) + { + const BorderLine& rBT(pCandidateA->getBorderLines()[a]); + const BorderLine& rBC(pCandidateB->getBorderLines()[a]); + + // LineAttribute has to be the same + if(!(rBC.getLineAttribute() == rBT.getLineAttribute())) + { + return Primitive2DReference(); + } + + // isGap has to be the same + if(rBC.isGap() != rBT.isGap()) + { + return Primitive2DReference(); + } + + if(!rBT.isGap()) + { + // when not gap, the line extends have at least reach to the center ( > 0.0), + // else there is a extend usage. When > 0.0 they just overlap, no problem + if(rBT.getEndLeft() >= 0.0 + && rBT.getEndRight() >= 0.0 + && rBC.getStartLeft() >= 0.0 + && rBC.getStartRight() >= 0.0) + { + // okay + } + else + { + return Primitive2DReference(); + } + } + } + + // all conditions met, create merged primitive + std::vector< BorderLine > aMergedBorderLines; + + for(size_t a(0); a < count; a++) + { + const BorderLine& rBT(pCandidateA->getBorderLines()[a]); + const BorderLine& rBC(pCandidateB->getBorderLines()[a]); + + aMergedBorderLines.push_back( + BorderLine( + rBT.getLineAttribute(), + rBT.getStartLeft(), rBT.getStartRight(), + rBC.getEndLeft(), rBC.getEndRight())); + } + + return Primitive2DReference( + new BorderLinePrimitive2D( + pCandidateA->getStart(), + pCandidateB->getEnd(), + aMergedBorderLines, + pCandidateA->getStrokeAttribute())); + } } // end of namespace primitive2d } // end of namespace drawinglayer diff --git a/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx b/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx index 992347c7dc9b..b6634f6ce64e 100644 --- a/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx +++ b/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx @@ -87,6 +87,13 @@ namespace drawinglayer bool operator==(const BorderLine& rBorderLine) const; }; + /// helper to try to merge two instances of BorderLinePrimitive2D. If it was possible, + /// a merged version is in the returned Primitive2DReference. Lots of preconditions + /// have to be met to allow that, see implementation (and maybe even expand) + Primitive2DReference DRAWINGLAYER_DLLPUBLIC tryMergeBorderLinePrimitive2D( + const Primitive2DReference& rCandidateA, + const Primitive2DReference& rCandidateB); + /** BorderLinePrimitive2D class This is the basic primitive to build frames around objects, e.g. tables. diff --git a/include/svx/framelink.hxx b/include/svx/framelink.hxx index 9ebb4c85e5aa..1b130efa7f2f 100644 --- a/include/svx/framelink.hxx +++ b/include/svx/framelink.hxx @@ -213,66 +213,27 @@ public: inline bool operator>( const Style& rL, const Style& rR ) { return rR.operator<(rL); } -// Various helper functions - -/** Checks whether two horizontal frame borders are "connectable". - - Two borders are "connectable" in terms of this function, if both can be - drawn with only one call of a border drawing function. This means, the two - frame borders must have equal style and color, and none of the other - vertical and diagonal frame borders break the lines of the two borders in - any way (i.e. two vertical double frame borders would break the horizonal - frame borders). Of course this function can be used for vertical frame - borders as well. - - The following picture shows the meaning of all passed parameters: - - \ rTFromT / - \ | / - rTFromTL | rTFromTR - \ | / - \ | / - ======== rLBorder ========= ========== rRBorder ======= - / | \ - / | \ - rBFromBL | rBFromBR - / | \ - / rBFromB \ - - @return - True, if rLBorder and rRBorder can be drawn in one step without - interruption at their connection point. - */ -SVX_DLLPUBLIC bool CheckFrameBorderConnectable( - const Style& rLBorder, /// Style of the left frame border to connect. - const Style& rRBorder, /// Style of the right frame border to connect. - - const Style& rTFromTL, /// Diagonal frame border from top-left to connection point. - const Style& rTFromT, /// Vertical frame border from top to connection point. - const Style& rTFromTR, /// Horizontal frame border from top-right to connection point. - - const Style& rBFromBL, /// Diagonal frame border from bottom-left to connection point. - const Style& rBFromB, /// Vertical frame border from bottom to connection point. - const Style& rBFromBR /// Horizontal frame border from bottom-right to connection point. -); - - // Drawing functions class SAL_WARN_UNUSED SVX_DLLPUBLIC StyleVectorCombination { private: const Style& mrStyle; - const basegfx::B2DVector& mrB2DVector; + const basegfx::B2DVector maB2DVector; + const bool mbMirrored; + public: - StyleVectorCombination(const Style& rStyle, const basegfx::B2DVector& rB2DVector) : + StyleVectorCombination(const Style& rStyle, const basegfx::B2DVector& rB2DVector, bool bMirrored) : mrStyle(rStyle), - mrB2DVector(rB2DVector) - {} + maB2DVector(rB2DVector), + mbMirrored(bMirrored) + { + } const Style& getStyle() const { return mrStyle; } - const basegfx::B2DVector& getB2DVector() const { return mrB2DVector; } + const basegfx::B2DVector& getB2DVector() const { return maB2DVector; } + bool isMirrored() const { return mbMirrored; } }; typedef std::vector< StyleVectorCombination > StyleVectorTable; diff --git a/svx/source/dialog/framelink.cxx b/svx/source/dialog/framelink.cxx index ca66b285f8d4..c7a6377ab3e8 100644 --- a/svx/source/dialog/framelink.cxx +++ b/svx/source/dialog/framelink.cxx @@ -88,7 +88,7 @@ void Style::SetPatternScale( double fScale ) { if(!maImplStyle) { - if(1.0 == fScale) + if(rtl::math::approxEqual(1.0, fScale)) { return; } @@ -334,29 +334,6 @@ bool Style::operator<( const Style& rOther) const return false; } -bool CheckFrameBorderConnectable( const Style& rLBorder, const Style& rRBorder, - const Style& rTFromTL, const Style& rTFromT, const Style& rTFromTR, - const Style& rBFromBL, const Style& rBFromB, const Style& rBFromBR ) -{ - return // returns 1 AND (2a OR 2b) - // 1) only, if both frame borders are equal - (rLBorder == rRBorder) - && - ( - ( - // 2a) if the borders are not double, at least one of the vertical must not be double - !rLBorder.Secn() && (!rTFromT.Secn() || !rBFromB.Secn()) - ) - || - ( - // 2b) if the borders are double, all other borders must not be double - rLBorder.Secn() && - !rTFromTL.Secn() && !rTFromT.Secn() && !rTFromTR.Secn() && - !rBFromBL.Secn() && !rBFromB.Secn() && !rBFromBR.Secn() - ) - ); -} - // Drawing functions struct OffsetAndHalfWidthAndColor { @@ -387,48 +364,70 @@ struct ExtendSet ExtendSet() : mfExtLeft(0.0), mfExtRight(0.0) {} }; -void getOffsetAndHalfWidthAndColorFromStyle(const Style& rStyle, const Color* pForceColor, std::vector< OffsetAndHalfWidthAndColor >& offsets) +double getOffsetAndHalfWidthAndColorFromStyle( + const Style& rStyle, + const Color* pForceColor, + bool bMirrored, + std::vector< OffsetAndHalfWidthAndColor >& offsets) { + // do not forget RefMode offset, primitive is free of it + double fRefModeOffset(0.0); + if (rStyle.IsUsed()) { - // do not forget RefMode offset, primitive is free of it - double fRefModeOffset(0.0); + RefMode aRefMode(rStyle.GetRefMode()); + Color aPrim(rStyle.GetColorPrim()); + Color aSecn(rStyle.GetColorSecn()); + double fPrim(rStyle.Prim()); + double fSecn(rStyle.Secn()); + + if(bMirrored) + { + switch(aRefMode) + { + case RefMode::Begin: aRefMode = RefMode::End; break; + case RefMode::End: aRefMode = RefMode::Begin; break; + default: break; + } + std::swap(aPrim, aSecn); + std::swap(fPrim, fSecn); + } - if (RefMode::Centered != rStyle.GetRefMode()) + if (RefMode::Centered != aRefMode) { const double fHalfWidth(rStyle.GetWidth() * 0.5); - if (RefMode::Begin == rStyle.GetRefMode()) + if (RefMode::Begin == aRefMode) { // move aligned below vector fRefModeOffset = fHalfWidth; } - else if (RefMode::End == rStyle.GetRefMode()) + else if (RefMode::End == aRefMode) { // move aligned above vector fRefModeOffset = -fHalfWidth; } } - if (rStyle.Dist() && rStyle.Secn()) + if (rStyle.Dist() && fSecn) { // 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 == rStyle.GetColorSecn().GetTransparency()); + const bool bSecnTransparent(0xff == aSecn.GetTransparency()); if(!bPrimTransparent || !bDistTransparent || !bSecnTransparent) { const double a(fRefModeOffset - (rStyle.GetWidth() * 0.5)); - const double b(a + rStyle.Prim()); + const double b(a + fPrim); const double c(b + rStyle.Dist()); - const double d(c + rStyle.Secn()); + const double d(c + fSecn); offsets.push_back( OffsetAndHalfWidthAndColor( (a + b) * 0.5, - rStyle.Prim() * 0.5, - nullptr != pForceColor ? *pForceColor : rStyle.GetColorPrim())); + fPrim * 0.5, + nullptr != pForceColor ? *pForceColor : aPrim)); offsets.push_back( OffsetAndHalfWidthAndColor( @@ -441,8 +440,8 @@ void getOffsetAndHalfWidthAndColorFromStyle(const Style& rStyle, const Color* pF offsets.push_back( OffsetAndHalfWidthAndColor( (c + d) * 0.5, - rStyle.Secn() * 0.5, - nullptr != pForceColor ? *pForceColor : rStyle.GetColorSecn())); + fSecn * 0.5, + nullptr != pForceColor ? *pForceColor : aSecn)); } } else @@ -453,11 +452,13 @@ void getOffsetAndHalfWidthAndColorFromStyle(const Style& rStyle, const Color* pF offsets.push_back( OffsetAndHalfWidthAndColor( fRefModeOffset, - rStyle.Prim() * 0.5, - nullptr != pForceColor ? *pForceColor : rStyle.GetColorPrim())); + fPrim * 0.5, + nullptr != pForceColor ? *pForceColor : aPrim)); } } } + + return fRefModeOffset; } void getCutSet( @@ -525,7 +526,7 @@ void getExtends( for(const auto& rStyleVectorCombination : rStyleVectorTable) { std::vector< OffsetAndHalfWidthAndColor > otherOffsets; - getOffsetAndHalfWidthAndColorFromStyle(rStyleVectorCombination.getStyle(), nullptr, otherOffsets); + getOffsetAndHalfWidthAndColorFromStyle(rStyleVectorCombination.getStyle(), nullptr, rStyleVectorCombination.isMirrored(), otherOffsets); if(!otherOffsets.empty()) { @@ -568,7 +569,7 @@ void CreateBorderPrimitives( { // get offset color pairs for style, one per visible line std::vector< OffsetAndHalfWidthAndColor > myOffsets; - getOffsetAndHalfWidthAndColorFromStyle(rBorder, pForceColor, myOffsets); + const double fRefModeOffset(getOffsetAndHalfWidthAndColorFromStyle(rBorder, pForceColor, false, myOffsets)); const size_t nOffsets(myOffsets.size()); if(nOffsets) @@ -624,12 +625,13 @@ void CreateBorderPrimitives( 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 * fRefModeOffset)); rTarget.append( drawinglayer::primitive2d::Primitive2DReference( new drawinglayer::primitive2d::BorderLinePrimitive2D( - rOrigin, - rOrigin + rX, + aStart, + aStart + rX, aBorderlines, aStrokeAttribute))); } diff --git a/svx/source/dialog/framelinkarray.cxx b/svx/source/dialog/framelinkarray.cxx index 6052c23f3e8a..2d81caebd3a7 100644 --- a/svx/source/dialog/framelinkarray.cxx +++ b/svx/source/dialog/framelinkarray.cxx @@ -954,11 +954,11 @@ void HelperCreateHorizontalEntry( const Style& rStartFromBR(rArray.GetCellStyleTL( col, row )); StyleVectorTable aStart; - if(rStartFromTR.IsUsed()) aStart.push_back(StyleVectorCombination(rStartFromTR, rX - rY)); - if(rStartLFromT.IsUsed()) aStart.push_back(StyleVectorCombination(rStartLFromT, -rY)); - if(rStartLFromL.IsUsed()) aStart.push_back(StyleVectorCombination(rStartLFromL, -rX)); - if(rStartLFromB.IsUsed()) aStart.push_back(StyleVectorCombination(rStartLFromB, rY)); - if(rStartFromBR.IsUsed()) aStart.push_back(StyleVectorCombination(rStartFromBR, rX + rY)); + if(rStartFromTR.IsUsed()) aStart.push_back(StyleVectorCombination(rStartFromTR, rX - rY, false)); + if(rStartLFromT.IsUsed()) aStart.push_back(StyleVectorCombination(rStartLFromT, -rY, true)); + if(rStartLFromL.IsUsed()) aStart.push_back(StyleVectorCombination(rStartLFromL, -rX, true)); + if(rStartLFromB.IsUsed()) aStart.push_back(StyleVectorCombination(rStartLFromB, rY, false)); + if(rStartFromBR.IsUsed()) aStart.push_back(StyleVectorCombination(rStartFromBR, rX + rY, false)); // get involved styles at end const Style& rEndFromTL(rArray.GetCellStyleBR( col, row - 1 )); @@ -968,11 +968,11 @@ void HelperCreateHorizontalEntry( const Style& rEndFromBL(rArray.GetCellStyleTR( col, row )); StyleVectorTable aEnd; - if(rEndFromTL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndFromTL, -rX -rY)); - if(rEndRFromT.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndRFromT, -rY)); - if(rEndRFromR.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndRFromR, rX)); - if(rEndRFromB.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndRFromB, rY)); - if(rEndFromBL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndFromBL, rY - rX)); + if(rEndFromTL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndFromTL, -rX -rY, true)); + if(rEndRFromT.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndRFromT, -rY, true)); + if(rEndRFromR.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndRFromR, rX, false)); + if(rEndRFromB.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndRFromB, rY, false)); + if(rEndFromBL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndFromBL, rY - rX, true)); CreateBorderPrimitives( rSequence, @@ -999,11 +999,11 @@ void HelperCreateVerticalEntry( const Style& rStartFromBR(rArray.GetCellStyleTL( col, row )); StyleVectorTable aStart; - if(rStartFromBR.IsUsed()) aStart.push_back(StyleVectorCombination(rStartFromBR, rX + rY)); - if(rStartTFromR.IsUsed()) aStart.push_back(StyleVectorCombination(rStartTFromR, rX)); - if(rStartTFromT.IsUsed()) aStart.push_back(StyleVectorCombination(rStartTFromT, rY)); - if(rStartTFromL.IsUsed()) aStart.push_back(StyleVectorCombination(rStartTFromL, -rX)); - if(rStartFromBL.IsUsed()) aStart.push_back(StyleVectorCombination(rStartFromBL, rY - rX)); + if(rStartFromBR.IsUsed()) aStart.push_back(StyleVectorCombination(rStartFromBR, rX + rY, false)); + if(rStartTFromR.IsUsed()) aStart.push_back(StyleVectorCombination(rStartTFromR, rX, false)); + if(rStartTFromT.IsUsed()) aStart.push_back(StyleVectorCombination(rStartTFromT, rY, true)); + if(rStartTFromL.IsUsed()) aStart.push_back(StyleVectorCombination(rStartTFromL, -rX, true)); + if(rStartFromBL.IsUsed()) aStart.push_back(StyleVectorCombination(rStartFromBL, rY - rX, true)); // get involved styles at end const Style& rEndFromTL(rArray.GetCellStyleBR( col - 1, row )); @@ -1013,11 +1013,11 @@ void HelperCreateVerticalEntry( const Style& rEndFromTR(rArray.GetCellStyleBL( col, row )); StyleVectorTable aEnd; - if(rEndFromTR.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndFromTR, rX - rY)); - if(rEndBFromR.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndBFromR, rX)); - if(rEndBFromB.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndBFromB, -rY)); - if(rEndBFromL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndBFromL, rX)); - if(rEndFromTL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndFromTL, rX + rY)); + if(rEndFromTR.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndFromTR, rX - rY, false)); + if(rEndBFromR.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndBFromR, rX, false)); + if(rEndBFromB.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndBFromB, -rY, false)); + if(rEndBFromL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndBFromL, rX, true)); + if(rEndFromTL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndFromTL, rX + rY, true)); CreateBorderPrimitives( rSequence, @@ -1069,6 +1069,48 @@ void HelperCreateEntry(const Array& rArray, const Style& rStyle, drawinglayer::p } } +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.append(aCandidate); + aCandidate = a; + } + } + else + { + aCandidate = a; + } + } + + if(aCandidate.is()) + { + rTarget.append(aCandidate); + } + } + else + { + rTarget.append(rSource); + } +} + drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( size_t nFirstCol, size_t nFirstRow, size_t nLastCol, size_t nLastRow, const Color* pForceColor ) const @@ -1078,7 +1120,7 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( // various primitive sequences to collect the different border types drawinglayer::primitive2d::Primitive2DContainer aHorizontalSequence; - drawinglayer::primitive2d::Primitive2DContainer aVerticalSequence; + std::vector< drawinglayer::primitive2d::Primitive2DContainer > aVerticalSequences(nLastCol - nFirstCol + 1); drawinglayer::primitive2d::Primitive2DContainer aCrossSequence; for (size_t nRow = nFirstRow; nRow <= nLastRow; ++nRow) @@ -1131,7 +1173,7 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( if(rLeft.IsUsed()) { - HelperCreateEntry(*this, rLeft, aVerticalSequence, pForceColor); + HelperCreateEntry(*this, rLeft, aVerticalSequences[nCol - nFirstCol], pForceColor); } } @@ -1141,7 +1183,7 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( if(rRight.IsUsed()) { - HelperCreateEntry(*this, rRight, aVerticalSequence, pForceColor); + HelperCreateEntry(*this, rRight, aVerticalSequences[nCol - nFirstCol], pForceColor); } } @@ -1156,15 +1198,15 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( /// Fill top-left Style Table const Style& rTLFromRight(GetCellStyleTop(_nFirstCol, _nFirstRow)); - if(rTLFromRight.IsUsed()) aStart.push_back(StyleVectorCombination(rTLFromRight, aX)); + if(rTLFromRight.IsUsed()) aStart.push_back(StyleVectorCombination(rTLFromRight, aX, false)); const Style& rTLFromBottom(GetCellStyleLeft(_nFirstCol, _nFirstRow)); - if(rTLFromBottom.IsUsed()) aStart.push_back(StyleVectorCombination(rTLFromBottom, aY)); + if(rTLFromBottom.IsUsed()) aStart.push_back(StyleVectorCombination(rTLFromBottom, aY, false)); /// Fill bottom-right Style Table const Style& rBRFromBottom(GetCellStyleRight(_nLastCol, _nLastRow)); - if(rBRFromBottom.IsUsed()) aEnd.push_back(StyleVectorCombination(rBRFromBottom, -aY)); + if(rBRFromBottom.IsUsed()) aEnd.push_back(StyleVectorCombination(rBRFromBottom, -aY, true)); const Style& rBRFromLeft(GetCellStyleBottom(_nLastCol, _nLastRow)); - if(rBRFromLeft.IsUsed()) aEnd.push_back(StyleVectorCombination(rBRFromLeft, -aX)); + if(rBRFromLeft.IsUsed()) aEnd.push_back(StyleVectorCombination(rBRFromLeft, -aX, true)); CreateBorderPrimitives( aCrossSequence, @@ -1186,15 +1228,15 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( /// Fill bottom-left Style Table const Style& rBLFromTop(GetCellStyleLeft(_nFirstCol, _nLastRow)); - if(rBLFromTop.IsUsed()) aStart.push_back(StyleVectorCombination(rBLFromTop, -aY)); + if(rBLFromTop.IsUsed()) aStart.push_back(StyleVectorCombination(rBLFromTop, -aY, true)); const Style& rBLFromBottom(GetCellStyleBottom(_nFirstCol, _nLastRow)); - if(rBLFromBottom.IsUsed()) aStart.push_back(StyleVectorCombination(rBLFromBottom, aX)); + if(rBLFromBottom.IsUsed()) aStart.push_back(StyleVectorCombination(rBLFromBottom, aX, false)); /// Fill top-right Style Table const Style& rTRFromBottom(GetCellStyleRight(_nLastCol, _nFirstRow)); - if(rTRFromBottom.IsUsed()) aEnd.push_back(StyleVectorCombination(rTRFromBottom, -aY)); + if(rTRFromBottom.IsUsed()) aEnd.push_back(StyleVectorCombination(rTRFromBottom, -aY, true)); const Style& rTRFromLeft(GetCellStyleTop(_nLastCol, _nFirstRow)); - if(rTRFromLeft.IsUsed()) aEnd.push_back(StyleVectorCombination(rTRFromLeft, -aX)); + if(rTRFromLeft.IsUsed()) aEnd.push_back(StyleVectorCombination(rTRFromLeft, -aX, false)); CreateBorderPrimitives( aCrossSequence, @@ -1211,9 +1253,13 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( } } - // to stay compatible, create order as it was formally - aCrossSequence.append(aHorizontalSequence); - aCrossSequence.append(aVerticalSequence); + // to stay compatible, create order as it was formally. Also try to + // merge primitives as far as possible + HelperMergeInB2DPrimitiveArray(aHorizontalSequence, aCrossSequence); + for(const auto& aVert : aVerticalSequences) + { + HelperMergeInB2DPrimitiveArray(aVert, aCrossSequence); + } return aCrossSequence; } diff --git a/svx/source/table/viewcontactoftableobj.cxx b/svx/source/table/viewcontactoftableobj.cxx index d696569dc329..52d6ce42b943 100644 --- a/svx/source/table/viewcontactoftableobj.cxx +++ b/svx/source/table/viewcontactoftableobj.cxx @@ -197,7 +197,7 @@ namespace sdr return svx::frame::Style(); } - void createForVector(drawinglayer::primitive2d::Primitive2DContainer& rContainer, const basegfx::B2DPoint& rOrigin, const basegfx::B2DVector& rX, + void createForVector(bool bHor, drawinglayer::primitive2d::Primitive2DContainer& rContainer, const basegfx::B2DPoint& rOrigin, const basegfx::B2DVector& rX, const svx::frame::Style& rLine, const svx::frame::Style& rLeftA, const svx::frame::Style& rLeftB, const svx::frame::Style& rLeftC, const svx::frame::Style& rRightA, const svx::frame::Style& rRightB, const svx::frame::Style& rRightC) @@ -206,17 +206,16 @@ namespace sdr svx::frame::StyleVectorTable aStart; svx::frame::StyleVectorTable aEnd; const basegfx::B2DVector aY(basegfx::getNormalizedPerpendicular(rX)); - const double fTwipsToMM(127.0 / 72.0); /// Fill top-left Style Table - if(rLeftA.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftA, -aY)); - if(rLeftB.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftB, -rX)); - if(rLeftC.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftC, aY)); + if(rLeftA.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftA, -aY, bHor ? true : false)); + if(rLeftB.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftB, -rX, bHor ? true : true)); + if(rLeftC.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftC, aY, bHor ? false : true)); /// Fill bottom-right Style Table - if(rRightA.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightA, -aY)); - if(rRightB.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightB, rX)); - if(rRightC.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightC, aY)); + if(rRightA.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightA, -aY, bHor ? true : false)); + if(rRightB.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightB, rX, bHor ? false : false)); + if(rRightC.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightC, aY, bHor ? false : true)); CreateBorderPrimitives( rContainer, @@ -350,32 +349,31 @@ namespace sdr const basegfx::B2DPoint aOrigin(aCellMatrix * basegfx::B2DPoint(0.0, 0.0)); const basegfx::B2DVector aX(aCellMatrix * basegfx::B2DVector(1.0, 0.0)); const basegfx::B2DVector aY(aCellMatrix * basegfx::B2DVector(0.0, 1.0)); - const double fTwipsToMM(127.0 / 72.0); if(aLeftLine.IsUsed()) { - createForVector(aBorderSequence, aOrigin, aY, aLeftLine, + createForVector(false, aBorderSequence, aOrigin, aY, aLeftLine, aTopLine, aLeftFromTLine, aTopFromLLine, aBottomLine, aLeftFromBLine, aBottomFromLLine); } if(aBottomLine.IsUsed()) { - createForVector(aBorderSequence, aOrigin + aY, aX, aBottomLine, + createForVector(true, aBorderSequence, aOrigin + aY, aX, aBottomLine, aLeftLine, aBottomFromLLine, aLeftFromBLine, aRightLine, aBottomFromRLine, aRightFromBLine); } if(aRightLine.IsUsed()) { - createForVector(aBorderSequence, aOrigin + aX, aY, aRightLine, + createForVector(false, aBorderSequence, aOrigin + aX, aY, aRightLine, aTopFromRLine, aRightFromTLine, aTopLine, aBottomFromRLine, aRightFromBLine, aBottomLine); } if(aTopLine.IsUsed()) { - createForVector(aBorderSequence, aOrigin, aX, aTopLine, + createForVector(true, aBorderSequence, aOrigin, aX, aTopLine, aLeftFromTLine, aTopFromLLine, aLeftLine, aRightFromTLine, aTopFromRLine, aRightLine); } diff --git a/sw/source/core/layout/paintfrm.cxx b/sw/source/core/layout/paintfrm.cxx index ac2d3ba9e21f..4ba2fc11ec57 100644 --- a/sw/source/core/layout/paintfrm.cxx +++ b/sw/source/core/layout/paintfrm.cxx @@ -221,7 +221,7 @@ class BorderLines { drawinglayer::primitive2d::Primitive2DContainer m_Lines; public: - void AddBorderLine(css::uno::Reference<BorderLinePrimitive2D> const& xLine, SwPaintProperties const & properties); + void AddBorderLine(const drawinglayer::primitive2d::Primitive2DReference& rLine); drawinglayer::primitive2d::Primitive2DContainer GetBorderLines_Clear() { drawinglayer::primitive2d::Primitive2DContainer lines; @@ -472,197 +472,20 @@ SwSavePaintStatics::~SwSavePaintStatics() gProp.aSScaleY = aSScaleY; } -/** - * Check whether the two primitive can be merged - * - * @param[in] mergeA A primitive start and end position - * @param[in] mergeB B primitive start and end position - * @return 1 if A and B can be merged to a primite staring with A, ending with B - * 2 if A and B can be merged to a primite staring with B, ending with A - * 0 if A and B can't be merged -**/ -static sal_uInt8 lcl_TryMergeLines( - pair<double, double> const& mergeA, - pair<double, double> const& mergeB, - SwPaintProperties const & properties) -{ - double const fMergeGap(properties.nSPixelSzW + properties.nSHalfPixelSzW); // NOT static! - // A is above/before B - if( mergeA.second <= mergeB.first && - mergeA.second + fMergeGap >= mergeB.first ) - { - return 1; - } - // B is above/before A - else if( mergeB.second <= mergeA.first && - mergeB.second + fMergeGap >= mergeA.first ) - { - return 2; - } - return 0; -} - -/** - * Make a new primitive from the two input borderline primitive - * - * @param[in] rLine starting primitive - * @param[in] rOther ending primitive - * @param[in] rStart starting point of merged primitive - * @param[in] rEnd ending point of merged primitive - * @return merged primitive -**/ -static rtl::Reference<BorderLinePrimitive2D> -lcl_MergeBorderLines( - BorderLinePrimitive2D const& rLine, - BorderLinePrimitive2D const& rOther, - basegfx::B2DPoint const& rStart, - basegfx::B2DPoint const& rEnd) -{ - const std::vector< BorderLine >& rLineLeft(rLine.getBorderLines()); - const std::vector< BorderLine >& rOtherLeft(rOther.getBorderLines()); - const size_t aSize(std::min(rLineLeft.size(), rOtherLeft.size())); - std::vector< BorderLine > aNew; - - for(size_t a(0); a < aSize; a++) - { - const BorderLine& la(rLineLeft[a]); - const BorderLine& lb(rOtherLeft[a]); - - if(la.isGap() || lb.isGap()) - { - aNew.push_back(la); - } - else - { - aNew.push_back( - BorderLine( - la.getLineAttribute(), - la.getStartLeft(), - la.getStartRight(), - lb.getEndLeft(), - lb.getEndRight())); - } - } - - return new BorderLinePrimitive2D( - rStart, - rEnd, - aNew, - rLine.getStrokeAttribute()); -} - -/** - * Merge the two borderline if possible. - * - * @param[in] rThis one borderline primitive - * @param[in] rOther other borderline primitive - * @return merged borderline including the two input primitive, if they can be merged - * 0, otherwise -**/ -static rtl::Reference<BorderLinePrimitive2D> -lcl_TryMergeBorderLine(BorderLinePrimitive2D const& rThis, - BorderLinePrimitive2D const& rOther, - SwPaintProperties const & properties) +void BorderLines::AddBorderLine(const drawinglayer::primitive2d::Primitive2DReference& rLine) { - assert(rThis.getEnd().getX() >= rThis.getStart().getX()); - assert(rThis.getEnd().getY() >= rThis.getStart().getY()); - assert(rOther.getEnd().getX() >= rOther.getStart().getX()); - assert(rOther.getEnd().getY() >= rOther.getStart().getY()); - const bool bSameEdgeNumber(rThis.getBorderLines().size() == rOther.getBorderLines().size()); - - if (!bSameEdgeNumber) - { - return nullptr; - } - - double thisHeight = rThis.getEnd().getY() - rThis.getStart().getY(); - double thisWidth = rThis.getEnd().getX() - rThis.getStart().getX(); - double otherHeight = rOther.getEnd().getY() - rOther.getStart().getY(); - double otherWidth = rOther.getEnd().getX() - rOther.getStart().getX(); - - // check for same orientation, same line width, same style and matching colors - bool bSameStuff( - ((thisHeight > thisWidth) == (otherHeight > otherWidth)) - && rThis.getStrokeAttribute() == rOther.getStrokeAttribute()); - - if(bSameStuff) + for (drawinglayer::primitive2d::Primitive2DContainer::reverse_iterator it = m_Lines.rbegin(); it != m_Lines.rend(); ++it) { - const std::vector< BorderLine >& rLineLeft(rThis.getBorderLines()); - const std::vector< BorderLine >& rOtherLeft(rOther.getBorderLines()); - const size_t aSize(std::min(rLineLeft.size(), rOtherLeft.size())); - - for(size_t a(0); bSameStuff && a < aSize; a++) - { - const BorderLine& la(rLineLeft[a]); - const BorderLine& lb(rOtherLeft[a]); - - bSameStuff = la == lb; - } - } - - if (bSameStuff) - { - int nRet = 0; - if (thisHeight > thisWidth) // vertical line - { - if (rtl::math::approxEqual(rThis.getStart().getX(), rOther.getStart().getX())) - { - assert(rtl::math::approxEqual(rThis.getEnd().getX(), rOther.getEnd().getX())); - nRet = lcl_TryMergeLines( - make_pair(rThis.getStart().getY(), rThis.getEnd().getY()), - make_pair(rOther.getStart().getY(),rOther.getEnd().getY()), - properties); - } - } - else // horizontal line - { - if (rtl::math::approxEqual(rThis.getStart().getY(), rOther.getStart().getY())) - { - assert(rtl::math::approxEqual(rThis.getEnd().getY(), rOther.getEnd().getY())); - nRet = lcl_TryMergeLines( - make_pair(rThis.getStart().getX(), rThis.getEnd().getX()), - make_pair(rOther.getStart().getX(),rOther.getEnd().getX()), - properties); - } - } + const drawinglayer::primitive2d::Primitive2DReference aMerged(drawinglayer::primitive2d::tryMergeBorderLinePrimitive2D(*it, rLine)); - // The merged primitive starts with rThis and ends with rOther - if (nRet == 1) - { - basegfx::B2DPoint const start( - rThis.getStart().getX(), rThis.getStart().getY()); - basegfx::B2DPoint const end( - rOther.getEnd().getX(), rOther.getEnd().getY()); - return lcl_MergeBorderLines(rThis, rOther, start, end).get(); - } - // The merged primitive starts with rOther and ends with rThis - else if(nRet == 2) + if (aMerged.is()) { - basegfx::B2DPoint const start( - rOther.getStart().getX(), rOther.getStart().getY()); - basegfx::B2DPoint const end( - rThis.getEnd().getX(), rThis.getEnd().getY()); - return lcl_MergeBorderLines(rOther, rThis, start, end).get(); - } - } - return nullptr; -} - -void BorderLines::AddBorderLine( - css::uno::Reference<BorderLinePrimitive2D> const& xLine, SwPaintProperties const & properties) -{ - for (drawinglayer::primitive2d::Primitive2DContainer::reverse_iterator it = m_Lines.rbegin(); it != m_Lines.rend(); - ++it) - { - rtl::Reference<BorderLinePrimitive2D> const xMerged( - lcl_TryMergeBorderLine(*static_cast<BorderLinePrimitive2D*>((*it).get()), *xLine.get(), properties).get()); - if (xMerged.is()) - { - *it = xMerged.get(); // replace existing line with merged + *it = aMerged; // replace existing line with merged // lcl_TryMergeBorderLine return; } } - m_Lines.push_back(xLine); + + m_Lines.append(rLine); } SwLineRect::SwLineRect( const SwRect &rRect, const Color *pCol, const SvxBorderLineStyle nStyl, @@ -2608,6 +2431,7 @@ 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 aSequence; while ( true ) { @@ -2715,8 +2539,6 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons if(aStyles[0].IsUsed()) { - drawinglayer::primitive2d::Primitive2DContainer aSequence; - if (bHori) { const basegfx::B2DPoint aOrigin(aPaintStart.X(), aPaintStart.Y()); @@ -2728,13 +2550,13 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons svx::frame::StyleVectorTable aStartTable; svx::frame::StyleVectorTable aEndTable; - if(aStyles[ 1 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 1 ], -aY)); // aLFromT - if(aStyles[ 2 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 2 ], -aX)); // aLFromL - if(aStyles[ 3 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 3 ], aY)); // aLFromB + if(aStyles[ 1 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 1 ], -aY, true)); // aLFromT + if(aStyles[ 2 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 2 ], -aX, true)); // aLFromL + if(aStyles[ 3 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 3 ], aY, false)); // aLFromB - if(aStyles[ 4 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 4 ], -aY)); // aRFromT - if(aStyles[ 5 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 5 ], aX)); // aRFromR - if(aStyles[ 6 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 6 ], aY)); // aRFromB + if(aStyles[ 4 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 4 ], -aY, true)); // aRFromT + if(aStyles[ 5 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 5 ], aX, false)); // aRFromR + if(aStyles[ 6 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 6 ], aY, false)); // aRFromB CreateBorderPrimitives( aSequence, @@ -2743,7 +2565,7 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons aStyles[ 0 ], aStartTable, aEndTable, - nullptr + pTmpColor ); } } @@ -2758,13 +2580,13 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons svx::frame::StyleVectorTable aStartTable; svx::frame::StyleVectorTable aEndTable; - if(aStyles[ 3 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 3 ], -aY)); // aTFromR - if(aStyles[ 2 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 2 ], -aX)); // aTFromT - if(aStyles[ 1 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 1 ], aY)); // aTFromL + if(aStyles[ 3 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 3 ], -aY, false)); // aTFromR + if(aStyles[ 2 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 2 ], -aX, true)); // aTFromT + if(aStyles[ 1 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 1 ], aY, true)); // aTFromL - if(aStyles[ 6 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 6 ], -aY)); // aBFromR - if(aStyles[ 5 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 5 ], aX)); // aBFromB - if(aStyles[ 4 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 4 ], aY)); // aBFromL + if(aStyles[ 6 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 6 ], -aY, false)); // aBFromR + if(aStyles[ 5 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 5 ], aX, false)); // aBFromB + if(aStyles[ 4 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 4 ], aY, true)); // aBFromL CreateBorderPrimitives( aSequence, @@ -2773,18 +2595,17 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons aStyles[ 0 ], aStartTable, aEndTable, - nullptr + pTmpColor ); } } - - mrTabFrame.ProcessPrimitives(aSequence); } } - ++aIter; } + mrTabFrame.ProcessPrimitives(aSequence); + // restore output device: rDev.SetDrawMode( nOldDrawMode ); } @@ -4839,7 +4660,7 @@ static void lcl_MakeBorderLine(SwRect const& rRect, // When rendering to very small (virtual) devices, like when producing // page thumbnails in a mobile device app, the line geometry can end up // bogus (negative width or height), so just ignore such border lines. - // Otherwise we will run into assertions later in lcl_TryMergeBorderLine() + // Otherwise we will run into assertions later in BorderLinePrimitive2D::tryMerge() // at least. if (aEnd.getX() < aStart.getX() || aEnd.getY() < aStart.getY()) @@ -4894,14 +4715,14 @@ static void lcl_MakeBorderLine(SwRect const& rRect, nExtentRightEnd)); } - rtl::Reference<BorderLinePrimitive2D> xLine( + drawinglayer::primitive2d::Primitive2DReference aLine( new BorderLinePrimitive2D( aStart, aEnd, aBorderlines, aStrokeAttribute)); - properties.pBLines->AddBorderLine(xLine.get(), properties); + properties.pBLines->AddBorderLine(aLine); } /** commit 98ceb50c0a65708729df8f2967e616f52db42261 Author: Armin Le Grand <[email protected]> Date: Fri Sep 8 13:39:29 2017 +0200 borderline: Adapted BorderLinePrimitive2D and usages ... etc. - the rest is truncated _______________________________________________ Libreoffice-commits mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
