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 9421ed8..5fc3b57 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 992347c..b6634f6 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 9ebb4c8..1b130ef 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 ca66b28..c7a6377 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 (RefMode::Centered != rStyle.GetRefMode())
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 != 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 6052c23..2d81cae 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 d696569..52d6ce4 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 ac2d3ba..4ba2fc1 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)
void BorderLines::AddBorderLine(const drawinglayer::primitive2d::Primitive2DReference& rLine)
{
double const fMergeGap(properties.nSPixelSzW + properties.nSHalfPixelSzW); // NOT static!
// A is above/before B
if( mergeA.second <= mergeB.first &&
mergeA.second + fMergeGap >= mergeB.first )
for (drawinglayer::primitive2d::Primitive2DContainer::reverse_iterator it = m_Lines.rbegin(); it != m_Lines.rend(); ++it)
{
return 1;
}
// B is above/before A
else if( mergeB.second <= mergeA.first &&
mergeB.second + fMergeGap >= mergeA.first )
{
return 2;
}
return 0;
}
const drawinglayer::primitive2d::Primitive2DReference aMerged(drawinglayer::primitive2d::tryMergeBorderLinePrimitive2D(*it, rLine));
/**
* 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())
if (aMerged.is())
{
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)
{
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)
{
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);
}
}
// 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)
{
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);
}
/**