diff options
author | Armin Le Grand <Armin.Le.Grand@cib.de> | 2017-07-04 16:28:58 +0200 |
---|---|---|
committer | Armin Le Grand <Armin.Le.Grand@cib.de> | 2017-07-12 21:01:20 +0200 |
commit | f65cbae8947c0462b35c8d3c3d5124e431b100b6 (patch) | |
tree | e8248f034f7a97e1716f9477937b55ae31038a76 /drawinglayer/source/primitive2d | |
parent | fc55711f01af172eb3a034454405fa941454c781 (diff) |
borderline: correct problems with border display
Borderline display with direct paint and with primitive direct
paint has quite some errors in the current state. Started to
unify usages, check deeper with creation/usage.
borderline: deep changes to BorderLine
Found basic error in determining the offset values
for BorderLinePrimitive creation, these were not
centered on the lines. Corrected that. This makes
it possible to remove the formally used clipping
which seems to have been used to correct that. Also
allows to go back to a 'normal' decomposition that
creates line primitives as expected. That again can
then be painted quite normally.
Also added view-dependent case to the decomposition
to guarantee a gap of one discrete unit (pixel).
Removed the direct painter, too. Checked and corrected
stroking.
borderline: Adapted previews to primitives
Added code to use the primitive representation in
all dialogs and apps using tables. The edit views
use these mostly, so the preview should do that,
too. Currently missing is a good visualization of
diagonals, but this is also true for edit views.
Checked all apps and table usages to not get worse
borderline: correct line dash visualization
When a dashed line is used, a factor of 10.0 was applied in the
original coded, added that. Also the orientation of vertical
borders was inverted since it was simpler to exchange Start/End,
but this also mirrors the line dash visualisation, corrected that
Change-Id: I4c1b380a76cb37389fab1259a53fb7cc9da982d1
e95e246d5563360617a2a2213e4d5ec7d0e736b9
62369b4de58fb0264aeb710ec6983ceddca5701d
77418cc6c84ebb0632f8c3448976e82ce612d6b6
b4eb28dc86ce05eb89b26517167305b994158ef8
borderline: adapt cppunittest and clang
Diffstat (limited to 'drawinglayer/source/primitive2d')
-rw-r--r-- | drawinglayer/source/primitive2d/borderlineprimitive2d.cxx | 389 | ||||
-rw-r--r-- | drawinglayer/source/primitive2d/clippedborderlineprimitive2d.cxx | 64 |
2 files changed, 141 insertions, 312 deletions
diff --git a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx index c6ea4a5c41f7..9735cc1aa44d 100644 --- a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx @@ -42,282 +42,138 @@ T round(T x) } #endif -namespace drawinglayer { - -namespace { - -void moveLine(basegfx::B2DPolygon& rPoly, double fGap, const basegfx::B2DVector& rVector) -{ - if (basegfx::fTools::equalZero(rVector.getX())) - { - basegfx::B2DHomMatrix aMat(1, 0, fGap, 0, 1, 0); - rPoly.transform(aMat); - } - else if (basegfx::fTools::equalZero(rVector.getY())) - { - basegfx::B2DHomMatrix aMat(1, 0, 0, 0, 1, fGap); - rPoly.transform(aMat); - } -} - -primitive2d::Primitive2DReference makeHairLinePrimitive( - const basegfx::B2DPoint& rStart, const basegfx::B2DPoint& rEnd, const basegfx::B2DVector& rVector, - const basegfx::BColor& rColor, double fGap) -{ - basegfx::B2DPolygon aPolygon; - aPolygon.append(rStart); - aPolygon.append(rEnd); - moveLine(aPolygon, fGap, rVector); - - return primitive2d::Primitive2DReference(new primitive2d::PolygonHairlinePrimitive2D(aPolygon, rColor)); -} - -primitive2d::Primitive2DReference makeSolidLinePrimitive( - const basegfx::B2DPolyPolygon& rClipRegion, const basegfx::B2DPoint& rStart, const basegfx::B2DPoint& rEnd, - const basegfx::B2DVector& rVector, const basegfx::BColor& rColor, double fLineWidth, double fGap) +namespace drawinglayer { - const basegfx::B2DVector aPerpendicular = basegfx::getPerpendicular(rVector); - const basegfx::B2DVector aLineWidthOffset = (fLineWidth * 0.5) * aPerpendicular; - - basegfx::B2DPolygon aPolygon; - aPolygon.append(rStart + aLineWidthOffset); - aPolygon.append(rEnd + aLineWidthOffset); - aPolygon.append(rEnd - aLineWidthOffset); - aPolygon.append(rStart - aLineWidthOffset); - aPolygon.setClosed(true); - - moveLine(aPolygon, fGap, rVector); - - basegfx::B2DPolyPolygon aClipped = - basegfx::tools::clipPolygonOnPolyPolygon(aPolygon, rClipRegion, true, false); - - if (aClipped.count()) - aPolygon = aClipped.getB2DPolygon(0); - - return primitive2d::Primitive2DReference( - new primitive2d::PolyPolygonColorPrimitive2D(basegfx::B2DPolyPolygon(aPolygon), rColor)); -} - -} - - // fdo#49438: heuristic pseudo hack - static bool lcl_UseHairline(double const fW, - basegfx::B2DPoint const& rStart, basegfx::B2DPoint const& rEnd, - geometry::ViewInformation2D const& rViewInformation) - { - basegfx::B2DTuple scale; - basegfx::B2DTuple translation; - double fRotation; - double fShear; - rViewInformation.getObjectToViewTransformation().decompose( - scale, translation, fRotation, fShear); - double const fScale( - (rEnd.getX() - rStart.getX() > rEnd.getY() - rStart.getY()) - ? scale.getY() : scale.getX()); - return (fW * fScale < 0.51); - } - - static double lcl_GetCorrectedWidth(double const fW, - basegfx::B2DPoint const& rStart, basegfx::B2DPoint const& rEnd, - geometry::ViewInformation2D const& rViewInformation) - { - return (lcl_UseHairline(fW, rStart, rEnd, rViewInformation)) ? 0.0 : fW; - } - namespace primitive2d { - double BorderLinePrimitive2D::getWidth( - geometry::ViewInformation2D const& rViewInformation) const - { - return lcl_GetCorrectedWidth(mfLeftWidth, getStart(), getEnd(), - rViewInformation) - + lcl_GetCorrectedWidth(mfDistance, getStart(), getEnd(), - rViewInformation) - + lcl_GetCorrectedWidth(mfRightWidth, getStart(), getEnd(), - rViewInformation); - } - - basegfx::B2DPolyPolygon BorderLinePrimitive2D::getClipPolygon( - geometry::ViewInformation2D const& rViewInformation) const + // helper to add a centered, maybe stroked line primitive to rContainer + void addPolygonStrokePrimitive2D( + Primitive2DContainer& rContainer, + const basegfx::B2DPoint& rStart, + const basegfx::B2DPoint& rEnd, + const basegfx::BColor& rColor, + double fWidth, + SvxBorderLineStyle aStyle, + double fPatternScale) { - basegfx::B2DPolygon clipPolygon; - - // Get the vectors - basegfx::B2DVector aVector( getEnd() - getStart() ); - aVector.normalize(); - const basegfx::B2DVector aPerpendicular(basegfx::getPerpendicular(aVector)); - - // Get the points - const double fWidth(getWidth(rViewInformation)); - const basegfx::B2DVector aLeftOff( - aPerpendicular * (-0.5 * std::max(fWidth, 1.0))); - const basegfx::B2DVector aRightOff( - aPerpendicular * (0.5 * std::max(fWidth, 1.0))); + basegfx::B2DPolygon aPolygon; - const basegfx::B2DVector aSLVector( aLeftOff - ( getExtendLeftStart() * aVector ) ); - clipPolygon.append( basegfx::B2DPoint( getStart() + aSLVector * 2.0 ) ); + aPolygon.append(rStart); + aPolygon.append(rEnd); - clipPolygon.append( getStart( ) ); + const attribute::LineAttribute aLineAttribute(rColor, fWidth); + static double fPatScFact(10.0); // 10.0 multiply, see old code + const std::vector<double> aDashing(svtools::GetLineDashing(aStyle, fPatternScale * fPatScFact)); - const basegfx::B2DVector aSRVector( aRightOff - ( getExtendRightStart() * aVector ) ); - clipPolygon.append( basegfx::B2DPoint( getStart() + aSRVector * 2.0 ) ); - - const basegfx::B2DVector aERVector( aRightOff + ( getExtendRightEnd() * aVector ) ); - clipPolygon.append( basegfx::B2DPoint( getEnd() + aERVector * 2.0 ) ); - - clipPolygon.append( getEnd( ) ); - - const basegfx::B2DVector aELVector( aLeftOff + ( getExtendLeftEnd() * aVector ) ); - clipPolygon.append( basegfx::B2DPoint( getEnd() + aELVector * 2.0 ) ); - - clipPolygon.setClosed( true ); - - return basegfx::B2DPolyPolygon( clipPolygon ); - } + if (aDashing.empty()) + { + rContainer.push_back( + new PolygonStrokePrimitive2D( + aPolygon, + aLineAttribute)); + } + else + { + const attribute::StrokeAttribute aStrokeAttribute(aDashing); - void BorderLinePrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& rViewInformation) const - { - createDecomposition(rContainer, rViewInformation, false); + rContainer.push_back( + new PolygonStrokePrimitive2D( + aPolygon, + aLineAttribute, + aStrokeAttribute)); + } } - void BorderLinePrimitive2D::createDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& rViewInformation, bool bPixelCorrection) const + void BorderLinePrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*rViewInformation*/) const { - if(!getStart().equal(getEnd()) && ( isInsideUsed() || isOutsideUsed() ) ) + if (!getStart().equal(getEnd()) && (isInsideUsed() || isOutsideUsed())) { // get data and vectors basegfx::B2DVector aVector(getEnd() - getStart()); aVector.normalize(); const basegfx::B2DVector aPerpendicular(basegfx::getPerpendicular(aVector)); - const basegfx::B2DPolyPolygon& aClipRegion = - getClipPolygon(rViewInformation); - - if(isOutsideUsed() && isInsideUsed()) + if (isOutsideUsed() && isInsideUsed()) { - const double fExt = getWidth(rViewInformation); // Extend a lot: it'll be clipped later. - const basegfx::B2DPoint aTmpStart(getStart() - (fExt * aVector)); - const basegfx::B2DPoint aTmpEnd(getEnd() + (fExt * aVector)); - - double fLeftWidth = getLeftWidth(); - bool bLeftHairline = lcl_UseHairline(fLeftWidth, getStart(), getEnd(), rViewInformation); - if (bLeftHairline) - fLeftWidth = 0.0; - - double fRightWidth = getRightWidth(); - bool bRightHairline = lcl_UseHairline(fRightWidth, getStart(), getEnd(), rViewInformation); - if (bRightHairline) - fRightWidth = 0.0; - - // "inside" line - - if (bLeftHairline) - rContainer.push_back(makeHairLinePrimitive( - getStart(), getEnd(), aVector, getRGBColorLeft(), 0.0)); - else + // double line with gap. Use mfDiscreteDistance (see get2DDecomposition) as distance. + // That value is prepared to be at least one pixel (discrete unit) so that the + // decomposition is view-dependent in this cases + if (isInsideUsed()) { - double fWidth = bPixelCorrection ? std::round(fLeftWidth) : fLeftWidth; - rContainer.push_back(makeSolidLinePrimitive( - aClipRegion, aTmpStart, aTmpEnd, aVector, getRGBColorLeft(), fWidth, -fLeftWidth/2.0)); + // inside line (left). Create stroke primitive centered on line width + const double fDeltaY((mfDiscreteDistance + getLeftWidth()) * 0.5); + const basegfx::B2DVector aDeltaY(aPerpendicular * fDeltaY); + const basegfx::B2DPoint aStart(getStart() - (aVector * getExtendLeftStart()) - aDeltaY); + const basegfx::B2DPoint aEnd(getEnd() + (aVector * getExtendLeftEnd()) - aDeltaY); + + addPolygonStrokePrimitive2D( + rContainer, + aStart, + aEnd, + getRGBColorLeft(), + getLeftWidth(), + getStyle(), + getPatternScale()); } - // "outside" line - - if (bRightHairline) - rContainer.push_back(makeHairLinePrimitive( - getStart(), getEnd(), aVector, getRGBColorRight(), fLeftWidth+mfDistance)); - else + if (hasGapColor() && isDistanceUsed()) { - double fWidth = bPixelCorrection ? std::round(fRightWidth) : fRightWidth; - rContainer.push_back(makeSolidLinePrimitive( - aClipRegion, aTmpStart, aTmpEnd, aVector, getRGBColorRight(), fWidth, mfDistance+fRightWidth/2.0)); + // gap (if visible, found no practicval usage). + // Create stroke primitive on vector with given color + addPolygonStrokePrimitive2D( + rContainer, + getStart(), + getEnd(), + getRGBColorGap(), + mfDiscreteDistance, + getStyle(), + getPatternScale()); } - } - else - { - // single line, create geometry - basegfx::B2DPolygon aPolygon; - const double fExt = getWidth(rViewInformation); // Extend a lot: it'll be clipped after - const basegfx::B2DPoint aTmpStart(getStart() - (fExt * aVector)); - const basegfx::B2DPoint aTmpEnd(getEnd() + (fExt * aVector)); - // Get which is the line to show - bool bIsSolidline = mnStyle == SvxBorderLineStyle::SOLID; - double nWidth = getLeftWidth(); - basegfx::BColor aColor = getRGBColorLeft(); - if ( basegfx::fTools::equal( 0.0, mfLeftWidth ) ) + if (isOutsideUsed()) { - nWidth = getRightWidth(); - aColor = getRGBColorRight(); + // outside line (right). Create stroke primitive centered on line width + const double fDeltaY((mfDiscreteDistance + getRightWidth()) * 0.5); + const basegfx::B2DVector aDeltaY(aPerpendicular * fDeltaY); + const basegfx::B2DPoint aStart(getStart() - (aVector * getExtendRightStart()) + aDeltaY); + const basegfx::B2DPoint aEnd(getEnd() + (aVector * getExtendRightEnd()) + aDeltaY); + + addPolygonStrokePrimitive2D( + rContainer, + aStart, + aEnd, + getRGBColorRight(), + getRightWidth(), + getStyle(), + getPatternScale()); } - bool const bIsHairline = lcl_UseHairline( - nWidth, getStart(), getEnd(), rViewInformation); - nWidth = lcl_GetCorrectedWidth(nWidth, - getStart(), getEnd(), rViewInformation); - - if(bIsHairline && bIsSolidline) - { - // create hairline primitive - aPolygon.append( getStart() ); - aPolygon.append( getEnd() ); - - rContainer.push_back(new PolygonHairlinePrimitive2D( - aPolygon, - aColor)); - } - else - { - // create filled polygon primitive - const basegfx::B2DVector aLineWidthOffset(((nWidth + 1) * 0.5) * aPerpendicular); - - aPolygon.append( aTmpStart ); - aPolygon.append( aTmpEnd ); - - basegfx::B2DPolyPolygon aDashed = - svtools::ApplyLineDashing(aPolygon, getStyle(), mfPatternScale*10.0); - - for (sal_uInt32 i = 0; i < aDashed.count(); i++ ) - { - basegfx::B2DPolygon aDash = aDashed.getB2DPolygon( i ); - basegfx::B2DPoint aDashStart = aDash.getB2DPoint( 0 ); - basegfx::B2DPoint aDashEnd = aDash.getB2DPoint( aDash.count() - 1 ); - - basegfx::B2DPolygon aDashPolygon; - aDashPolygon.append( aDashStart + aLineWidthOffset ); - aDashPolygon.append( aDashEnd + aLineWidthOffset ); - aDashPolygon.append( aDashEnd - aLineWidthOffset ); - aDashPolygon.append( aDashStart - aLineWidthOffset ); - aDashPolygon.setClosed( true ); - - basegfx::B2DPolyPolygon aClipped = basegfx::tools::clipPolygonOnPolyPolygon( - aDashPolygon, aClipRegion, true, false ); + } + else if(isInsideUsed()) + { + // single line, only inside values used, no vertical offsets + addPolygonStrokePrimitive2D( + rContainer, + getStart(), + getEnd(), + getRGBColorLeft(), + getLeftWidth(), + getStyle(), + getPatternScale()); + } + } + } - if ( aClipped.count() ) - aDashed.setB2DPolygon( i, aClipped.getB2DPolygon( 0 ) ); - } + bool BorderLinePrimitive2D::isHorizontalOrVertical(const geometry::ViewInformation2D& rViewInformation) const + { + if (!getStart().equal(getEnd())) + { + const basegfx::B2DHomMatrix& rOTVT = rViewInformation.getObjectToViewTransformation(); + const basegfx::B2DVector aVector(rOTVT * getEnd() - rOTVT * getStart()); - sal_uInt32 n = aDashed.count(); - for (sal_uInt32 i = 0; i < n; ++i) - { - basegfx::B2DPolygon aDash = aDashed.getB2DPolygon(i); - if (bIsHairline) - { - // Convert a rectangular polygon into a line. - basegfx::B2DPolygon aDash2; - basegfx::B2DRange aRange = aDash.getB2DRange(); - aDash2.append(basegfx::B2DPoint(aRange.getMinX(), aRange.getMinY())); - aDash2.append(basegfx::B2DPoint(aRange.getMaxX(), aRange.getMinY())); - rContainer.push_back( - new PolygonHairlinePrimitive2D(aDash2, aColor)); - } - else - { - rContainer.push_back( - new PolyPolygonColorPrimitive2D(basegfx::B2DPolyPolygon(aDash), aColor)); - } - } - } - } + return basegfx::fTools::equalZero(aVector.getX()) || basegfx::fTools::equalZero(aVector.getY()); } + + return false; } BorderLinePrimitive2D::BorderLinePrimitive2D( @@ -351,7 +207,8 @@ primitive2d::Primitive2DReference makeSolidLinePrimitive( maRGBColorGap(rRGBColorGap), mbHasGapColor(bHasGapColor), mnStyle(nStyle), - mfPatternScale(fPatternScale) + mfPatternScale(fPatternScale), + mfDiscreteDistance(0.0) { } @@ -381,6 +238,42 @@ primitive2d::Primitive2DReference makeSolidLinePrimitive( return false; } + void BorderLinePrimitive2D::get2DDecomposition(Primitive2DDecompositionVisitor& rVisitor, const geometry::ViewInformation2D& rViewInformation) const + { + ::osl::MutexGuard aGuard(m_aMutex); + + if (!getStart().equal(getEnd()) && isOutsideUsed() && isInsideUsed()) + { + // Double line with gap. In this case, we want to be view-dependent. + // 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, getDistance())); + + if (!rtl::math::approxEqual(fNewDiscreteDistance, mfDiscreteDistance)) + { + 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)->mfDiscreteDistance = fNewDiscreteDistance; + } + } + + // call base implementation + BufferedDecompositionPrimitive2D::get2DDecomposition(rVisitor, rViewInformation); + } + // provide unique ID ImplPrimitive2DIDBlock(BorderLinePrimitive2D, PRIMITIVE2D_ID_BORDERLINEPRIMITIVE2D) diff --git a/drawinglayer/source/primitive2d/clippedborderlineprimitive2d.cxx b/drawinglayer/source/primitive2d/clippedborderlineprimitive2d.cxx deleted file mode 100644 index ca44a2838909..000000000000 --- a/drawinglayer/source/primitive2d/clippedborderlineprimitive2d.cxx +++ /dev/null @@ -1,64 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -#include <drawinglayer/primitive2d/clippedborderlineprimitive2d.hxx> -#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> - -namespace drawinglayer -{ - namespace primitive2d - { - basegfx::B2DPolyPolygon ClippedBorderLinePrimitive2D::getClipPolygon( - SAL_UNUSED_PARAMETER geometry::ViewInformation2D const&) const - { - basegfx::B2DPolyPolygon aPolyPolygon; - aPolyPolygon.append( maIntersection ); - return aPolyPolygon; - } - - ClippedBorderLinePrimitive2D::ClippedBorderLinePrimitive2D( - const basegfx::B2DPoint& rStart, - const basegfx::B2DPoint& rEnd, - double fLeftWidth, - double fDistance, - double fRightWidth, - const basegfx::B2DPolygon& rIntersection, - const basegfx::BColor& rRGBColorRight, - const basegfx::BColor& rRGBColorLeft, - const basegfx::BColor& rRGBColorGap, - bool bHasGapColor, - SvxBorderLineStyle nStyle, - double fPatternScale) - : BorderLinePrimitive2D( rStart, rEnd, fLeftWidth,fDistance, fRightWidth, - 0.0, 0.0, 0.0, 0.0, rRGBColorRight, rRGBColorLeft, - rRGBColorGap, bHasGapColor, nStyle, fPatternScale), - maIntersection( rIntersection ) - { - } - - bool ClippedBorderLinePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const - { - if(BorderLinePrimitive2D::operator==(rPrimitive)) - { - const ClippedBorderLinePrimitive2D& rCompare = static_cast<const ClippedBorderLinePrimitive2D&>(rPrimitive); - - return maIntersection == rCompare.maIntersection; - } - - return false; - } - - // provide unique ID - ImplPrimitive2DIDBlock(ClippedBorderLinePrimitive2D, PRIMITIVE2D_ID_CLIPPEDBORDERLINEPRIMITIVE2D) - - - } // namespace primitive2d -} // namespace drawinglayer - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |