diff options
-rw-r--r-- | drawinglayer/qa/unit/border.cxx | 13 | ||||
-rw-r--r-- | drawinglayer/source/primitive2d/borderlineprimitive2d.cxx | 84 | ||||
-rw-r--r-- | drawinglayer/source/processor2d/vclpixelprocessor2d.cxx | 25 | ||||
-rw-r--r-- | include/drawinglayer/primitive2d/borderlineprimitive2d.hxx | 20 | ||||
-rw-r--r-- | include/svx/sdr/primitive2d/sdrframeborderprimitive2d.hxx | 22 | ||||
-rw-r--r-- | svx/source/dialog/framelinkarray.cxx | 3 | ||||
-rw-r--r-- | svx/source/sdr/primitive2d/sdrframeborderprimitive2d.cxx | 215 | ||||
-rw-r--r-- | sw/source/core/layout/paintfrm.cxx | 6 |
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) } } |