drawinglayer/qa/unit/border.cxx                            |   13 
 drawinglayer/source/primitive2d/borderlineprimitive2d.cxx  |   84 -----
 drawinglayer/source/processor2d/vclpixelprocessor2d.cxx    |   25 +
 include/drawinglayer/primitive2d/borderlineprimitive2d.hxx |   20 -
 include/svx/sdr/primitive2d/sdrframeborderprimitive2d.hxx  |   22 +
 svx/source/dialog/framelinkarray.cxx                       |    3 
 svx/source/sdr/primitive2d/sdrframeborderprimitive2d.cxx   |  215 +++++++++++--
 sw/source/core/layout/paintfrm.cxx                         |    6 
 8 files changed, 253 insertions(+), 135 deletions(-)

New commits:
commit 313392119522c21a6ecd14403d6f92c948149df7
Author:     Armin Le Grand <armin.le.gr...@cib.de>
AuthorDate: Thu Oct 25 10:06:05 2018 +0200
Commit:     Armin Le Grand <armin.le.gr...@cib.de>
CommitDate: Thu Oct 25 12:43:55 2018 +0200

    Reorganize FrameBorderPrimitive creation (II)
    
    Step5: Move the view-dependent decomposition from
    BorderLinePrimitive2D to SdrFrameBorderPrimitive2D.
    
    It is now possible to use discrete sizes before the
    line and edge matching is done what will look much
    better. When it was done at BorderLinePrimitive2D
    and the matching was already done, that match was
    'displaced' with the adapted forced scale to discrete
    units.
    
    The space and size used when zooming out for a single
    discrete unit (pixel) can heavily vary - it just covers
    a much larger logical area than the 'real' line/poly
    would do. All this needs to be handled (also for bound
    ranges) and can only be in a good way using primitives.
    
    Adapted to no longer do view-dependent changes in
    BorderLinePrimitive2D. Adapted to do these now at
    SdrFrameBorderPrimitive2D. Currently used to force
    the existing border partial lines (up to three) to
    not get taller than one logical unit.
    
    Adapted to no longer switch off AntiAliased rendering
    in VclPixelProcessor2D for processBorderLinePrimitive2D,
    this is problematic with various renderers on various
    systems (e.g. vcl still falls back to render multiple
    one-pixel-lines when taller than 3.5 pixels which looks
    horrible combined with other parts like filled polygons)
    
    All this needs fine balancing on
    - all systems
    - all renderers
    - all apps (which all have their own table implementation)
    - all render targets (pixel/PDF/print/slideshow/...)
    
    Done as thorough as possible, but may need additional
    finetuning. May also be a motivation to move away from
    vcl and implement these urgetly needed system-dependent
    primitive renderers...
    
    Adapted UnitTest testDoublePixelProcessing with the needed
    comments.
    
    Change-Id: Ie88bb76c2474b6ab3764d45a9cd1669264492acd
    Reviewed-on: https://gerrit.libreoffice.org/62344
    Tested-by: Jenkins
    Reviewed-by: Armin Le Grand <armin.le.gr...@cib.de>

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)
             }
         }
 
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to