summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drawinglayer/qa/unit/border.cxx13
-rw-r--r--drawinglayer/source/primitive2d/borderlineprimitive2d.cxx84
-rw-r--r--drawinglayer/source/processor2d/vclpixelprocessor2d.cxx25
-rw-r--r--include/drawinglayer/primitive2d/borderlineprimitive2d.hxx20
-rw-r--r--include/svx/sdr/primitive2d/sdrframeborderprimitive2d.hxx22
-rw-r--r--svx/source/dialog/framelinkarray.cxx3
-rw-r--r--svx/source/sdr/primitive2d/sdrframeborderprimitive2d.cxx215
-rw-r--r--sw/source/core/layout/paintfrm.cxx6
8 files changed, 253 insertions, 135 deletions
diff --git a/drawinglayer/qa/unit/border.cxx b/drawinglayer/qa/unit/border.cxx
index 365c90d1691f..30d278a91560 100644
--- a/drawinglayer/qa/unit/border.cxx
+++ b/drawinglayer/qa/unit/border.cxx
@@ -189,7 +189,7 @@ void DrawinglayerBorderTest::testDoublePixelProcessing()
{
auto pMPLAction = static_cast<MetaPolyLineAction*>(pAction);
- if (0 == pMPLAction->GetLineInfo().GetWidth() && LineStyle::Solid == pMPLAction->GetLineInfo().GetStyle())
+ if (0 != pMPLAction->GetLineInfo().GetWidth() && LineStyle::Solid == pMPLAction->GetLineInfo().GetStyle())
{
nPolyLineActionCount++;
}
@@ -198,7 +198,16 @@ void DrawinglayerBorderTest::testDoublePixelProcessing()
// Check if all eight (2x four) simple lines with width == 0 and
// solid were created
- const sal_uInt32 nExpectedNumPolyLineActions = 8;
+ //
+ // This has changed: Now, just the needed 'real' lines get created
+ // which have a width of 1. This are two lines. The former multiple
+ // lines were a combination of view-dependent force to a single-pixel
+ // line width (0 == lineWidth -> hairline) and vcl rendering this
+ // using a (insane) combination of single non-AAed lines. All the
+ // system-dependent part of the BorderLine stuff is now done in
+ // SdrFrameBorderPrimitive2D and svx.
+ // Adapted this test - still useful, breaking it may be a hint :-)
+ const sal_uInt32 nExpectedNumPolyLineActions = 2;
CPPUNIT_ASSERT_EQUAL(nExpectedNumPolyLineActions, nPolyLineActionCount);
}
diff --git a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
index 4c7bf9743628..e23a48921dc6 100644
--- a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
@@ -76,18 +76,6 @@ namespace drawinglayer
&& isGap() == rBorderLine.isGap();
}
- double BorderLine::getAdaptedWidth(double fMinWidth) const
- {
- if(isGap())
- {
- return std::max(getLineAttribute().getWidth(), fMinWidth);
- }
- else
- {
- return getLineAttribute().getWidth();
- }
- }
-
// helper to add a centered, maybe stroked line primitive to rContainer
static void addPolygonStrokePrimitive2D(
Primitive2DContainer& rContainer,
@@ -124,7 +112,7 @@ namespace drawinglayer
for(const auto& candidate : maBorderLines)
{
- fRetval += candidate.getAdaptedWidth(mfSmallestAllowedDiscreteGapDistance);
+ fRetval += candidate.getLineAttribute().getWidth();
}
return fRetval;
@@ -143,7 +131,7 @@ namespace drawinglayer
for(const auto& candidate : maBorderLines)
{
- const double fWidth(candidate.getAdaptedWidth(mfSmallestAllowedDiscreteGapDistance));
+ const double fWidth(candidate.getLineAttribute().getWidth());
if(!candidate.isGap())
{
@@ -289,8 +277,7 @@ namespace drawinglayer
maStart(rStart),
maEnd(rEnd),
maBorderLines(rBorderLines),
- maStrokeAttribute(rStrokeAttribute),
- mfSmallestAllowedDiscreteGapDistance(0.0)
+ maStrokeAttribute(rStrokeAttribute)
{
}
@@ -320,71 +307,6 @@ namespace drawinglayer
return false;
}
- bool BorderLinePrimitive2D::getSmallestGap(double& rfSmallestGap) const
- {
- bool bGapFound(false);
-
- for(const auto& candidate : maBorderLines)
- {
- if(candidate.isGap())
- {
- if(bGapFound)
- {
- rfSmallestGap = std::min(rfSmallestGap, candidate.getLineAttribute().getWidth());
- }
- else
- {
- bGapFound = true;
- rfSmallestGap = candidate.getLineAttribute().getWidth();
- }
- }
- }
-
- return bGapFound;
- }
-
- void BorderLinePrimitive2D::get2DDecomposition(Primitive2DDecompositionVisitor& rVisitor, const geometry::ViewInformation2D& rViewInformation) const
- {
- ::osl::MutexGuard aGuard(m_aMutex);
-
- if (!getStart().equal(getEnd()) && getBorderLines().size() > 1)
- {
- // Line with potential gap. In this case, we want to be view-dependent.
- // get the smallest gap
- double fSmallestGap(0.0);
-
- if(getSmallestGap(fSmallestGap))
- {
- // Get the current DiscreteUnit, look at X and Y and use the maximum
- const basegfx::B2DVector aDiscreteVector(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 1.0));
- const double fDiscreteUnit(std::min(fabs(aDiscreteVector.getX()), fabs(aDiscreteVector.getY())));
-
- // When discrete unit is bigger than distance (distance is less than one pixel),
- // force distance to one pixel. Or expressed different, do not let the distance
- // get smaller than one pixel. This is done for screen rendering and compatibility.
- // This can also be done using DiscreteMetricDependentPrimitive2D as base class
- // for this class, but specialization is better here for later buffering (only
- // do this when 'double line with gap')
- const double fNewDiscreteDistance(std::max(fDiscreteUnit, fSmallestGap));
-
- if (!rtl::math::approxEqual(fNewDiscreteDistance, mfSmallestAllowedDiscreteGapDistance))
- {
- if (!getBuffered2DDecomposition().empty())
- {
- // conditions of last local decomposition have changed, delete
- const_cast< BorderLinePrimitive2D* >(this)->setBuffered2DDecomposition(Primitive2DContainer());
- }
-
- // remember value for usage in create2DDecomposition
- const_cast< BorderLinePrimitive2D* >(this)->mfSmallestAllowedDiscreteGapDistance = fNewDiscreteDistance;
- }
- }
- }
-
- // call base implementation
- BufferedDecompositionPrimitive2D::get2DDecomposition(rVisitor, rViewInformation);
- }
-
// provide unique ID
ImplPrimitive2DIDBlock(BorderLinePrimitive2D, PRIMITIVE2D_ID_BORDERLINEPRIMITIVE2D)
diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
index 4a891166f295..ad70cec45135 100644
--- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
@@ -879,17 +879,36 @@ namespace drawinglayer
void VclPixelProcessor2D::processBorderLinePrimitive2D(const drawinglayer::primitive2d::BorderLinePrimitive2D& rBorder)
{
- // process recursively, but switch off AntiAliasing for
+ // Process recursively, but switch off AntiAliasing for
// horizontal/vertical lines (*not* diagonal lines).
// Checked using AntialiasingFlags::PixelSnapHairline instead,
// but with AntiAliasing on the display really is too 'ghosty' when
// using fine stroking. Correct, but 'ghosty'.
- if (rBorder.isHorizontalOrVertical(getViewInformation2D()))
+ // It has shown that there are quite some problems here:
+ // - vcl OutDev renderer methods stuill use fallbacks to paint
+ // multiple single lines between discrete sizes of < 3.5 what
+ // looks bad and does not matzch
+ // - mix of filled Polygons and Lines is bad when AA switched off
+ // - Alignment of AA with non-AA may be bad in diverse different
+ // renderers
+ //
+ // Due to these reasons I change the strategy: Always draw AAed, but
+ // allow fallback to test/check and if needed. The normal case
+ // where BorderLines will be system-depenently snapped to have at
+ // least a single discrete width per partial line (there may be up to
+ // three) works well nowadays due to most renderers moving the AA stuff
+ // by 0.5 pixels (discrete units) to match well with the non-AAed parts.
+ //
+ // Env-Switch for steering this, default is off.
+ // Enable by setting at all (and to something)
+ static const char* pSwitchOffAntiAliasingForHorVerBorderlines(getenv("SAL_SWITCH_OFF_ANTIALIASING_FOR_HOR_VER_BORTDERLINES"));
+ static bool bSwitchOffAntiAliasingForHorVerBorderlines(nullptr != pSwitchOffAntiAliasingForHorVerBorderlines);
+
+ if (bSwitchOffAntiAliasingForHorVerBorderlines && rBorder.isHorizontalOrVertical(getViewInformation2D()))
{
AntialiasingFlags nAntiAliasing = mpOutputDevice->GetAntialiasing();
mpOutputDevice->SetAntialiasing(nAntiAliasing & ~AntialiasingFlags::EnableB2dDraw);
-
process(rBorder);
mpOutputDevice->SetAntialiasing(nAntiAliasing);
}
diff --git a/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx b/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx
index cb57e40fbe8a..a3f41985061e 100644
--- a/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx
+++ b/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx
@@ -38,7 +38,9 @@ namespace drawinglayer
/** BorderLine class
Helper class holding the style definition for a single part of a full BorderLine definition.
Line extends are for start/end and for Left/Right, seen in vector direction. If
- Left != Right that means the line has a diagonal start/end
+ Left != Right that means the line has a diagonal start/end.
+ Think about it similar to a trapezoid, but not aligned to X-Axis and using the
+ perpendicular vector to the given one in a right-handed coordinate system.
*/
class DRAWINGLAYER_DLLPUBLIC BorderLine
{
@@ -76,9 +78,6 @@ namespace drawinglayer
double getEndRight() const { return mfEndRight; }
bool isGap() const { return mbIsGap; }
- /// helper to get adapted width (maximum)
- double getAdaptedWidth(double fMinWidth) const;
-
/// compare operator
bool operator==(const BorderLine& rBorderLine) const;
};
@@ -111,18 +110,10 @@ namespace drawinglayer
/// common style definitions
const drawinglayer::attribute::StrokeAttribute maStrokeAttribute;
- // for view dependent decomposition in the case with existing gaps,
- // remember the smallest allowed concrete gap distance, see get2DDecomposition
- // implementation
- double mfSmallestAllowedDiscreteGapDistance;
-
/// create local decomposition
virtual void create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& rViewInformation) const override;
- /// helper to find smallest defined gap in maBorderLines
- bool getSmallestGap(double& rfSmallestGap) const;
-
- /// helper to get the full width taking mfSmallestAllowedDiscreteGapDistance into account
+ /// helper to get the full width from maBorderLines
double getFullWidth() const;
public:
@@ -145,9 +136,6 @@ namespace drawinglayer
/// compare operator
virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
- /// Override standard getDecomposition to be view-dependent here
- virtual void get2DDecomposition(Primitive2DDecompositionVisitor& rVisitor, const geometry::ViewInformation2D& rViewInformation) const override;
-
/// provide unique ID
DeclPrimitive2DIDBlock()
};
diff --git a/include/svx/sdr/primitive2d/sdrframeborderprimitive2d.hxx b/include/svx/sdr/primitive2d/sdrframeborderprimitive2d.hxx
index 29afb3584538..58f3b94cfd01 100644
--- a/include/svx/sdr/primitive2d/sdrframeborderprimitive2d.hxx
+++ b/include/svx/sdr/primitive2d/sdrframeborderprimitive2d.hxx
@@ -72,7 +72,11 @@ namespace drawinglayer
const basegfx::B2DVector& rNormalizedPerpendicular,
bool bStyleMirrored);
- void create2DDecomposition(Primitive2DContainer& rContainer) const;
+ void create2DDecomposition(
+ Primitive2DContainer& rContainer,
+ double fMinDiscreteUnit) const;
+
+ double getMinimalNonZeroBorderWidth() const;
};
typedef std::vector<SdrFrameBorderData> SdrFrameBorderDataVector;
@@ -88,7 +92,10 @@ namespace drawinglayer
{
private:
std::shared_ptr<SdrFrameBorderDataVector> maFrameBorders;
+ double mfMinimalNonZeroBorderWidth;
+ double mfMinimalNonZeroBorderWidthUsedForDecompose;
bool mbMergeResult;
+ bool mbForceToSingleDiscreteUnit;
protected:
// local decomposition.
@@ -99,14 +106,21 @@ namespace drawinglayer
public:
SdrFrameBorderPrimitive2D(
std::shared_ptr<SdrFrameBorderDataVector>& rFrameBorders,
- bool bMergeResult);
+ bool bMergeResult,
+ bool bForceToSingleDiscreteUnit);
// compare operator
virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
+ // override to get view-dependent
+ virtual void get2DDecomposition(
+ Primitive2DDecompositionVisitor& rVisitor,
+ const geometry::ViewInformation2D& rViewInformation) const override;
+
// data access
- const SdrFrameBorderDataVector& getFrameBorders() const { return *maFrameBorders.get(); }
- bool getMergeResult() const { return mbMergeResult; }
+ const std::shared_ptr<SdrFrameBorderDataVector>& getFrameBorders() const { return maFrameBorders; }
+ bool doMergeResult() const { return mbMergeResult; }
+ bool doForceToSingleDiscreteUnit() const { return mbForceToSingleDiscreteUnit; }
// provide unique ID
DeclPrimitive2DIDBlock()
diff --git a/svx/source/dialog/framelinkarray.cxx b/svx/source/dialog/framelinkarray.cxx
index d369da07f34f..0281c0300bfd 100644
--- a/svx/source/dialog/framelinkarray.cxx
+++ b/svx/source/dialog/framelinkarray.cxx
@@ -1233,7 +1233,8 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange(
drawinglayer::primitive2d::Primitive2DReference(
new drawinglayer::primitive2d::SdrFrameBorderPrimitive2D(
aData,
- true)));
+ true, // try to merge results to have less primitivbes
+ true))); // force visualization to minimal one discrete unit (pixel)
}
return aSequence;
diff --git a/svx/source/sdr/primitive2d/sdrframeborderprimitive2d.cxx b/svx/source/sdr/primitive2d/sdrframeborderprimitive2d.cxx
index f67a24ac4137..072fec2498c3 100644
--- a/svx/source/sdr/primitive2d/sdrframeborderprimitive2d.cxx
+++ b/svx/source/sdr/primitive2d/sdrframeborderprimitive2d.cxx
@@ -19,12 +19,25 @@
#include <svx/sdr/primitive2d/sdrframeborderprimitive2d.hxx>
#include <drawinglayer/primitive2d/borderlineprimitive2d.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <svtools/borderhelper.hxx>
namespace
{
+ double snapToDiscreteUnit(
+ double fValue,
+ double fMinimalDiscreteUnit)
+ {
+ if(0.0 != fValue)
+ {
+ fValue = std::max(fValue, fMinimalDiscreteUnit);
+ }
+
+ return fValue;
+ }
+
class StyleVectorCombination
{
private:
@@ -52,7 +65,8 @@ namespace
const basegfx::B2DVector& rB2DVector,
double fAngle,
bool bMirrored,
- const Color* pForceColor)
+ const Color* pForceColor,
+ double fMinimalDiscreteUnit)
: mfRefModeOffset(0.0),
maB2DVector(rB2DVector),
mfAngle(fAngle),
@@ -63,9 +77,18 @@ namespace
svx::frame::RefMode aRefMode(rStyle.GetRefMode());
Color aPrim(rStyle.GetColorPrim());
Color aSecn(rStyle.GetColorSecn());
- double fPrim(rStyle.Prim());
- double fSecn(rStyle.Secn());
- const bool bSecnUsed(0.0 != fSecn);
+ const bool bSecnUsed(0.0 != rStyle.Secn());
+
+ // Get the single segment line widths. This is the point where the
+ // minimal discrete unit wil be used if given (fMinimalDiscreteUnit). If
+ // not given it's 0.0 and thus will have no influence.
+ double fPrim(snapToDiscreteUnit(rStyle.Prim(), fMinimalDiscreteUnit));
+ const double fDist(snapToDiscreteUnit(rStyle.Dist(), fMinimalDiscreteUnit));
+ double fSecn(snapToDiscreteUnit(rStyle.Secn(), fMinimalDiscreteUnit));
+
+ // Of course also do not use svx::frame::Style::GetWidth() for obvious
+ // reasons.
+ const double fStyleWidth(fPrim + fDist + fSecn);
if(bMirrored)
{
@@ -85,7 +108,7 @@ namespace
if (svx::frame::RefMode::Centered != aRefMode)
{
- const double fHalfWidth(rStyle.GetWidth() * 0.5);
+ const double fHalfWidth(fStyleWidth * 0.5);
if (svx::frame::RefMode::Begin == aRefMode)
{
@@ -108,9 +131,9 @@ namespace
if(!bPrimTransparent || !bDistTransparent || !bSecnTransparent)
{
- const double a(mfRefModeOffset - (rStyle.GetWidth() * 0.5));
+ const double a(mfRefModeOffset - (fStyleWidth * 0.5));
const double b(a + fPrim);
- const double c(b + rStyle.Dist());
+ const double c(b + fDist);
const double d(c + fSecn);
maOffsets.push_back(
@@ -122,7 +145,7 @@ namespace
maOffsets.push_back(
OffsetAndHalfWidthAndColor(
(b + c) * 0.5,
- rStyle.Dist() * 0.5,
+ fDist * 0.5,
rStyle.UseGapColor()
? (nullptr != pForceColor ? *pForceColor : rStyle.GetColorGap())
: COL_TRANSPARENT));
@@ -181,14 +204,21 @@ namespace
const svx::frame::Style& rStyle,
const basegfx::B2DVector& rMyVector,
const basegfx::B2DVector& rOtherVector,
- bool bMirrored)
+ bool bMirrored,
+ double fMinimalDiscreteUnit)
{
if(rStyle.IsUsed() && !basegfx::areParallel(rMyVector, rOtherVector))
{
// create angle between both. angle() needs vectors pointing away from the same point,
// so take the mirrored one. Add F_PI to get from -pi..+pi to [0..F_PI2] for sorting
const double fAngle(basegfx::B2DVector(-rMyVector.getX(), -rMyVector.getY()).angle(rOtherVector) + F_PI);
- maEntries.emplace_back(rStyle, rOtherVector, fAngle, bMirrored, nullptr);
+ maEntries.emplace_back(
+ rStyle,
+ rOtherVector,
+ fAngle,
+ bMirrored,
+ nullptr,
+ fMinimalDiscreteUnit);
}
}
@@ -491,10 +521,17 @@ namespace
const svx::frame::Style& rBorder, /// Style of borderline
const StyleVectorTable& rStartStyleVectorTable, /// Styles and vectors (pointing away) at borderline start, ccw
const StyleVectorTable& rEndStyleVectorTable, /// Styles and vectors (pointing away) at borderline end, cw
- const Color* pForceColor) /// If specified, overrides frame border color.
+ const Color* pForceColor, /// If specified, overrides frame border color.
+ double fMinimalDiscreteUnit) /// minimal discrete unit to use for svx::frame::Style width values
{
// get offset color pairs for style, one per visible line
- const StyleVectorCombination aCombination(rBorder, rX, 0.0, false, pForceColor);
+ const StyleVectorCombination aCombination(
+ rBorder,
+ rX,
+ 0.0,
+ false,
+ pForceColor,
+ fMinimalDiscreteUnit);
if(aCombination.empty())
return;
@@ -515,7 +552,13 @@ namespace
if(bHasEndStyles)
{
// Create extends for line ends, create inverse point/vector and inverse offsets.
- const StyleVectorCombination aMirroredCombination(rBorder, -rX, 0.0, true, pForceColor);
+ const StyleVectorCombination aMirroredCombination(
+ rBorder,
+ -rX,
+ 0.0,
+ true,
+ pForceColor,
+ fMinimalDiscreteUnit);
getExtends(aExtendSetEnd, rOrigin + rX, aMirroredCombination, -aPerpendX, rEndStyleVectorTable.getEntries());
@@ -568,6 +611,35 @@ namespace
aBorderlines,
aStrokeAttribute)));
}
+
+ double getMinimalNonZeroValue(double fCurrent, double fNew)
+ {
+ if(0.0 != fNew)
+ {
+ if(0.0 != fCurrent)
+ {
+ fCurrent = std::min(fNew, fCurrent);
+ }
+ else
+ {
+ fCurrent = fNew;
+ }
+ }
+
+ return fCurrent;
+ }
+
+ double getMinimalNonZeroBorderWidthFromStyle(double fCurrent, const svx::frame::Style& rStyle)
+ {
+ if(rStyle.IsUsed())
+ {
+ fCurrent = getMinimalNonZeroValue(fCurrent, rStyle.Prim());
+ fCurrent = getMinimalNonZeroValue(fCurrent, rStyle.Dist());
+ fCurrent = getMinimalNonZeroValue(fCurrent, rStyle.Secn());
+ }
+
+ return fCurrent;
+ }
}
namespace drawinglayer
@@ -618,7 +690,9 @@ namespace drawinglayer
}
}
- void SdrFrameBorderData::create2DDecomposition(Primitive2DContainer& rContainer) const
+ void SdrFrameBorderData::create2DDecomposition(
+ Primitive2DContainer& rContainer,
+ double fMinimalDiscreteUnit) const
{
StyleVectorTable aStartVector;
StyleVectorTable aEndVector;
@@ -630,7 +704,8 @@ namespace drawinglayer
rStart.getStyle(),
maX,
rStart.getNormalizedPerpendicular(),
- rStart.getStyleMirrored());
+ rStart.getStyleMirrored(),
+ fMinimalDiscreteUnit);
}
for(const auto& rEnd : maEnd)
@@ -639,7 +714,8 @@ namespace drawinglayer
rEnd.getStyle(),
aAxis,
rEnd.getNormalizedPerpendicular(),
- rEnd.getStyleMirrored());
+ rEnd.getStyleMirrored(),
+ fMinimalDiscreteUnit);
}
aStartVector.sort();
@@ -652,7 +728,25 @@ namespace drawinglayer
maStyle,
aStartVector,
aEndVector,
- mbForceColor ? &maColor : nullptr);
+ mbForceColor ? &maColor : nullptr,
+ fMinimalDiscreteUnit);
+ }
+
+ double SdrFrameBorderData::getMinimalNonZeroBorderWidth() const
+ {
+ double fRetval(getMinimalNonZeroBorderWidthFromStyle(0.0, maStyle));
+
+ for(const auto& rStart : maStart)
+ {
+ fRetval = getMinimalNonZeroBorderWidthFromStyle(fRetval, rStart.getStyle());
+ }
+
+ for(const auto& rEnd : maEnd)
+ {
+ fRetval = getMinimalNonZeroBorderWidthFromStyle(fRetval, rEnd.getStyle());
+ }
+
+ return fRetval;
}
} // end of namespace primitive2d
} // end of namespace drawinglayer
@@ -661,19 +755,34 @@ namespace drawinglayer
{
namespace primitive2d
{
- void SdrFrameBorderPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*aViewInformation*/) const
+ void SdrFrameBorderPrimitive2D::create2DDecomposition(
+ Primitive2DContainer& rContainer,
+ const geometry::ViewInformation2D& /*aViewInformation*/) const
{
+ if(!getFrameBorders())
+ {
+ return;
+ }
+
Primitive2DContainer aRetval;
- if(getMergeResult())
+ // Check and use the minimal non-zero BorderWidth for decompose
+ // if that is set and wanted
+ const double fMinimalDiscreteUnit(doForceToSingleDiscreteUnit()
+ ? mfMinimalNonZeroBorderWidthUsedForDecompose
+ : 0.0);
+
+ if(doMergeResult())
{
// decompose all buffered SdrFrameBorderData entries and try to merge them
// to reduce existing number of BorderLinePrimitive2D(s)
- for(const auto& rCandidate : getFrameBorders())
+ for(const auto& rCandidate : *getFrameBorders().get())
{
// get decomposition on one SdrFrameBorderData entry
Primitive2DContainer aPartial;
- rCandidate.create2DDecomposition(aPartial);
+ rCandidate.create2DDecomposition(
+ aPartial,
+ fMinimalDiscreteUnit);
for(const auto& aCandidatePartial : aPartial)
{
@@ -729,9 +838,11 @@ namespace drawinglayer
else
{
// just decompose all buffered SdrFrameBorderData entries, do not try to merge
- for(const auto& rCandidate : getFrameBorders())
+ for(const auto& rCandidate : *getFrameBorders().get())
{
- rCandidate.create2DDecomposition(aRetval);
+ rCandidate.create2DDecomposition(
+ aRetval,
+ fMinimalDiscreteUnit);
}
}
@@ -740,11 +851,25 @@ namespace drawinglayer
SdrFrameBorderPrimitive2D::SdrFrameBorderPrimitive2D(
std::shared_ptr<SdrFrameBorderDataVector>& rFrameBorders,
- bool bMergeResult)
+ bool bMergeResult,
+ bool bForceToSingleDiscreteUnit)
: BufferedDecompositionPrimitive2D(),
maFrameBorders(std::move(rFrameBorders)),
- mbMergeResult(bMergeResult)
+ mfMinimalNonZeroBorderWidth(0.0),
+ mfMinimalNonZeroBorderWidthUsedForDecompose(0.0),
+ mbMergeResult(bMergeResult),
+ mbForceToSingleDiscreteUnit(bForceToSingleDiscreteUnit)
{
+ if(getFrameBorders() && doForceToSingleDiscreteUnit())
+ {
+ // detect used minimal non-zero partial border width
+ for(const auto& rCandidate : *getFrameBorders().get())
+ {
+ mfMinimalNonZeroBorderWidth = getMinimalNonZeroValue(
+ mfMinimalNonZeroBorderWidth,
+ rCandidate.getMinimalNonZeroBorderWidth());
+ }
+ }
}
bool SdrFrameBorderPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
@@ -753,12 +878,50 @@ namespace drawinglayer
{
const SdrFrameBorderPrimitive2D& rCompare = static_cast<const SdrFrameBorderPrimitive2D&>(rPrimitive);
- return maFrameBorders == rCompare.maFrameBorders;
+ return getFrameBorders() == rCompare.getFrameBorders()
+ && doMergeResult() == rCompare.doMergeResult()
+ && doForceToSingleDiscreteUnit() == rCompare.doForceToSingleDiscreteUnit();
}
return false;
}
+ void SdrFrameBorderPrimitive2D::get2DDecomposition(
+ Primitive2DDecompositionVisitor& rVisitor,
+ const geometry::ViewInformation2D& rViewInformation) const
+ {
+ if(doForceToSingleDiscreteUnit())
+ {
+ // Get the current DiscreteUnit, look at X and Y and use the maximum
+ const basegfx::B2DVector aDiscreteVector(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 1.0));
+ double fDiscreteUnit(std::min(fabs(aDiscreteVector.getX()), fabs(aDiscreteVector.getY())));
+
+ if(fDiscreteUnit <= mfMinimalNonZeroBorderWidth)
+ {
+ // no need to use it, reset
+ fDiscreteUnit = 0.0;
+ }
+
+ if(fDiscreteUnit != mfMinimalNonZeroBorderWidthUsedForDecompose)
+ {
+ // conditions of last local decomposition have changed, delete
+ // possible content
+ if(!getBuffered2DDecomposition().empty())
+ {
+ const_cast< SdrFrameBorderPrimitive2D* >(this)->setBuffered2DDecomposition(Primitive2DContainer());
+ }
+
+ // remember new conditions
+ const_cast< SdrFrameBorderPrimitive2D* >(this)->mfMinimalNonZeroBorderWidthUsedForDecompose = fDiscreteUnit;
+ }
+ }
+
+ // call parent. This will call back ::create2DDecomposition above
+ // where mfMinimalNonZeroBorderWidthUsedForDecompose will be used
+ // when doForceToSingleDiscreteUnit() is true
+ BufferedDecompositionPrimitive2D::get2DDecomposition(rVisitor, rViewInformation);
+ }
+
// provide unique ID
ImplPrimitive2DIDBlock(SdrFrameBorderPrimitive2D, PRIMITIVE2D_ID_SDRFRAMEBORDERTPRIMITIVE2D)
diff --git a/sw/source/core/layout/paintfrm.cxx b/sw/source/core/layout/paintfrm.cxx
index 22122b663918..cd65f907d42f 100644
--- a/sw/source/core/layout/paintfrm.cxx
+++ b/sw/source/core/layout/paintfrm.cxx
@@ -2567,7 +2567,8 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons
drawinglayer::primitive2d::Primitive2DReference(
new drawinglayer::primitive2d::SdrFrameBorderPrimitive2D(
aData,
- true)));
+ true, // try to merge results to have less primitivbes
+ true))); // force visualization to minimal one discrete unit (pixel)
// paint
mrTabFrame.ProcessPrimitives(aSequence);
}
@@ -4630,7 +4631,8 @@ namespace drawinglayer
drawinglayer::primitive2d::Primitive2DReference(
new drawinglayer::primitive2d::SdrFrameBorderPrimitive2D(
aData,
- true)));
+ true, // try to merge results to have less primitivbes
+ true))); // force visualization to minimal one discrete unit (pixel)
}
}