diff options
Diffstat (limited to 'drawinglayer')
-rw-r--r-- | drawinglayer/Library_drawinglayer.mk | 1 | ||||
-rw-r--r-- | drawinglayer/qa/unit/border.cxx | 47 | ||||
-rw-r--r-- | drawinglayer/source/primitive2d/borderlineprimitive2d.cxx | 389 | ||||
-rw-r--r-- | drawinglayer/source/primitive2d/clippedborderlineprimitive2d.cxx | 64 | ||||
-rw-r--r-- | drawinglayer/source/processor2d/vclpixelprocessor2d.cxx | 395 | ||||
-rw-r--r-- | drawinglayer/source/processor2d/vclpixelprocessor2d.hxx | 1 |
6 files changed, 180 insertions, 717 deletions
diff --git a/drawinglayer/Library_drawinglayer.mk b/drawinglayer/Library_drawinglayer.mk index 8c431c8ec08f..32daccd9d43e 100644 --- a/drawinglayer/Library_drawinglayer.mk +++ b/drawinglayer/Library_drawinglayer.mk @@ -67,7 +67,6 @@ $(eval $(call gb_Library_add_exception_objects,drawinglayer,\ drawinglayer/source/primitive2d/baseprimitive2d \ drawinglayer/source/primitive2d/bitmapprimitive2d \ drawinglayer/source/primitive2d/borderlineprimitive2d \ - drawinglayer/source/primitive2d/clippedborderlineprimitive2d \ drawinglayer/source/primitive2d/controlprimitive2d \ drawinglayer/source/primitive2d/cropprimitive2d \ drawinglayer/source/primitive2d/discretebitmapprimitive2d \ diff --git a/drawinglayer/qa/unit/border.cxx b/drawinglayer/qa/unit/border.cxx index 25264c46ee51..ce99965b13f9 100644 --- a/drawinglayer/qa/unit/border.cxx +++ b/drawinglayer/qa/unit/border.cxx @@ -17,6 +17,7 @@ #include <drawinglayer/geometry/viewinformation2d.hxx> #include <drawinglayer/primitive2d/borderlineprimitive2d.hxx> #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> +#include <drawinglayer/primitive2d/polygonprimitive2d.hxx> #include <drawinglayer/processor2d/baseprocessor2d.hxx> #include <drawinglayer/processor2d/processorfromoutputdevice.hxx> #include <rtl/ref.hxx> @@ -70,17 +71,15 @@ void DrawinglayerBorderTest::testDoubleDecompositionSolid() // Make sure it results in two borders as it's a double one. CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), aContainer.size()); - // Get the inside line. - auto pInside = dynamic_cast<const drawinglayer::primitive2d::PolyPolygonColorPrimitive2D*>(aContainer[0].get()); + // Get the inside line, now a PolygonStrokePrimitive2D + auto pInside = dynamic_cast<const drawinglayer::primitive2d::PolygonStrokePrimitive2D*>(aContainer[0].get()); CPPUNIT_ASSERT(pInside); // Make sure the inside line's height is fLeftWidth. - const basegfx::B2DPolyPolygon& rPolyPolygon = pInside->getB2DPolyPolygon(); - CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(1), rPolyPolygon.count()); - const basegfx::B2DPolygon& rPolygon = rPolyPolygon.getB2DPolygon(0); - const basegfx::B2DRange& rRange = rPolygon.getB2DRange(); + const double fLineWidthFromDecompose = pInside->getLineAttribute().getWidth(); + // This was 2.47, i.e. the width of the inner line was 1 unit (in the bugdoc's case: 1 pixel) wider than expected. - CPPUNIT_ASSERT_DOUBLES_EQUAL(fLeftWidth, rRange.getHeight(), basegfx::fTools::getSmallValue()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(fLeftWidth, fLineWidthFromDecompose, basegfx::fTools::getSmallValue()); } void DrawinglayerBorderTest::testDoublePixelProcessing() @@ -100,7 +99,7 @@ void DrawinglayerBorderTest::testDoublePixelProcessing() basegfx::B2DPoint aEnd(100, 20); double const fLeftWidth = 1.47; double const fDistance = 1.47; - double fRightWidth = 1.47; + double const fRightWidth = 1.47; double const fExtendLeftStart = 0; double const fExtendLeftEnd = 0; double const fExtendRightStart = 0; @@ -117,31 +116,33 @@ void DrawinglayerBorderTest::testDoublePixelProcessing() // Process the primitives. pProcessor->process(aPrimitives); - // Now assert the height of the outer (second) border polygon. + // Double line now gets decomposed in Metafile to painting four lines + // with width == 0 in a cross pattern due to real line width being between + // 1.0 and 2.0. Count created lines aMetaFile.Stop(); aMetaFile.WindStart(); - bool bFirst = true; - sal_Int32 nHeight = 0; + sal_uInt32 nPolyLineActionCount = 0; + for (std::size_t nAction = 0; nAction < aMetaFile.GetActionSize(); ++nAction) { MetaAction* pAction = aMetaFile.GetAction(nAction); - if (pAction->GetType() == MetaActionType::POLYPOLYGON) + + if (MetaActionType::POLYLINE == pAction->GetType()) { - if (bFirst) + auto pMPLAction = static_cast<MetaPolyLineAction*>(pAction); + + if (0 == pMPLAction->GetLineInfo().GetWidth() && LineStyle::Solid == pMPLAction->GetLineInfo().GetStyle()) { - bFirst = false; - continue; + nPolyLineActionCount++; } - - auto pMPPAction = static_cast<MetaPolyPolygonAction*>(pAction); - const tools::PolyPolygon& rPolyPolygon = pMPPAction->GetPolyPolygon(); - nHeight = rPolyPolygon.GetBoundRect().getHeight(); } } - sal_Int32 nExpectedHeight = std::round(fRightWidth); - // This was 2, and should be 1: if the logical requested width is 1.47, - // then that must be 1 px on the screen, not 2. - CPPUNIT_ASSERT_EQUAL(nExpectedHeight, nHeight); + + // Check if all eight (2x four) simple lines with width == 0 and + // solid were created + const sal_uInt32 nExpectedNumPolyLineActions = 8; + + CPPUNIT_ASSERT_EQUAL(nExpectedNumPolyLineActions, nPolyLineActionCount); } CPPUNIT_TEST_SUITE_REGISTRATION(DrawinglayerBorderTest); 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: */ diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx index 4b5e45c7ef04..a93f85df4595 100644 --- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx @@ -70,34 +70,6 @@ T round(T x) using namespace com::sun::star; -namespace { - -basegfx::B2DPolygon makeRectPolygon( double fX, double fY, double fW, double fH ) -{ - basegfx::B2DPolygon aPoly; - aPoly.append(basegfx::B2DPoint(fX, fY)); - aPoly.append(basegfx::B2DPoint(fX+fW, fY)); - aPoly.append(basegfx::B2DPoint(fX+fW, fY+fH)); - aPoly.append(basegfx::B2DPoint(fX, fY+fH)); - aPoly.setClosed(true); - return aPoly; -} - -void drawHairLine( - OutputDevice* pOutDev, double fX1, double fY1, double fX2, double fY2, - const basegfx::BColor& rColor ) -{ - basegfx::B2DPolygon aTarget; - aTarget.append(basegfx::B2DPoint(fX1, fY1)); - aTarget.append(basegfx::B2DPoint(fX2, fY2)); - - pOutDev->SetFillColor(); - pOutDev->SetLineColor(Color(rColor)); - pOutDev->DrawPolyLine(aTarget); -} - -} - namespace drawinglayer { namespace processor2d @@ -306,341 +278,6 @@ namespace drawinglayer return bTryWorked; } - bool VclPixelProcessor2D::tryDrawBorderLinePrimitive2DDirect( - const drawinglayer::primitive2d::BorderLinePrimitive2D& rSource) - { - const basegfx::B2DPoint& rS = rSource.getStart(); - const basegfx::B2DPoint& rE = rSource.getEnd(); - - double fX1 = rS.getX(); - double fY1 = rS.getY(); - double fX2 = rE.getX(); - double fY2 = rE.getY(); - - bool bHorizontal = false; - if (fX1 == fX2) - { - // Vertical line. - } - else if (fY1 == fY2) - { - // Horizontal line. - bHorizontal = true; - } - else - // Neither. Bail out. - return false; - - switch (rSource.getStyle()) - { - case SvxBorderLineStyle::SOLID: - case SvxBorderLineStyle::DOUBLE_THIN: - { - const basegfx::BColor aLineColor = - maBColorModifierStack.getModifiedColor(rSource.getRGBColorLeft()); - double nThick = rtl::math::round(rSource.getLeftWidth()); - - bool bDouble = rSource.getStyle() == SvxBorderLineStyle::DOUBLE_THIN; - - basegfx::B2DPolygon aTarget; - - if (bHorizontal) - { - // Horizontal line. Draw it as a rectangle. - - aTarget = makeRectPolygon(fX1, fY1, fX2-fX1, nThick); - aTarget.transform(maCurrentTransformation); - - basegfx::B2DRange aRange = aTarget.getB2DRange(); - double fH = aRange.getHeight(); - - if (bDouble) - { - // Double line - drawHairLine( - mpOutputDevice, aRange.getMinX(), aRange.getMinY()-1.0, aRange.getMaxX(), aRange.getMinY()-1.0, - aLineColor); - - drawHairLine( - mpOutputDevice, aRange.getMinX(), aRange.getMinY()+1.0, aRange.getMaxX(), aRange.getMinY()+1.0, - aLineColor); - - return true; - } - - if (fH <= 1.0) - { - // Draw it as a line. - drawHairLine( - mpOutputDevice, aRange.getMinX(), aRange.getMinY(), aRange.getMaxX(), aRange.getMinY(), - aLineColor); - - return true; - } - - double fOffset = rtl::math::round(fH/2.0, 0, rtl_math_RoundingMode_Down); - if (fOffset != 0.0) - { - // Move it up a bit to align it vertically centered. - basegfx::B2DHomMatrix aMat; - aMat.set(1, 2, -fOffset); - aTarget.transform(aMat); - } - } - else - { - // Vertical line. Draw it as a rectangle. - - aTarget = makeRectPolygon(fX1, fY1, nThick, fY2-fY1); - aTarget.transform(maCurrentTransformation); - - basegfx::B2DRange aRange = aTarget.getB2DRange(); - double fW = aRange.getWidth(); - - if (bDouble) - { - // Draw it as a line. - drawHairLine( - mpOutputDevice, aRange.getMinX()-1.0, aRange.getMinY(), aRange.getMinX()-1.0, aRange.getMaxY(), - aLineColor); - - drawHairLine( - mpOutputDevice, aRange.getMinX()+1.0, aRange.getMinY(), aRange.getMinX()+1.0, aRange.getMaxY(), - aLineColor); - - return true; - } - - if (fW <= 1.0) - { - // Draw it as a line. - drawHairLine( - mpOutputDevice, aRange.getMinX(), aRange.getMinY(), aRange.getMinX(), aRange.getMaxY(), - aLineColor); - - return true; - } - - double fOffset = rtl::math::round(fW/2.0, 0, rtl_math_RoundingMode_Down); - if (fOffset != 0.0) - { - // Move it to the left a bit to center it horizontally. - basegfx::B2DHomMatrix aMat; - aMat.set(0, 2, -fOffset); - aTarget.transform(aMat); - } - } - - mpOutputDevice->SetFillColor(Color(aLineColor)); - mpOutputDevice->SetLineColor(); - mpOutputDevice->DrawPolygon(aTarget); - return true; - } - break; - case SvxBorderLineStyle::DOTTED: - case SvxBorderLineStyle::DASHED: - case SvxBorderLineStyle::DASH_DOT: - case SvxBorderLineStyle::DASH_DOT_DOT: - case SvxBorderLineStyle::FINE_DASHED: - { - std::vector<double> aPattern = - svtools::GetLineDashing(rSource.getStyle(), rSource.getPatternScale()*10.0); - - if (aPattern.empty()) - // Failed to get pattern values. - return false; - - double nThick = rtl::math::round(rSource.getLeftWidth()); - - const basegfx::BColor aLineColor = - maBColorModifierStack.getModifiedColor(rSource.getRGBColorLeft()); - - // Transform the current line range before using it for rendering. - basegfx::B2DRange aRange(fX1, fY1, fX2, fY2); - aRange.transform(maCurrentTransformation); - fX1 = aRange.getMinX(); - fX2 = aRange.getMaxX(); - fY1 = aRange.getMinY(); - fY2 = aRange.getMaxY(); - - basegfx::B2DPolyPolygon aTarget; - - if (bHorizontal) - { - // Horizontal line. - - if (basegfx::fTools::equalZero(nThick)) - { - // Dash line segment too small to draw. Substitute it with a solid line. - drawHairLine(mpOutputDevice, fX1, fY1, fX2, fY1, aLineColor); - return true; - } - - // Create a dash unit polygon set. - basegfx::B2DPolyPolygon aDashes; - std::vector<double>::const_iterator it = aPattern.begin(), itEnd = aPattern.end(); - for (; it != itEnd; ++it) - aDashes.append(makeRectPolygon(0, 0, *it, nThick)); - - aDashes.transform(maCurrentTransformation); - rtl::math::setNan(&nThick); - - // Pixelize the dash unit. We use the same height for - // all dash polygons. - basegfx::B2DPolyPolygon aDashesPix; - - for (sal_uInt32 i = 0, n = aDashes.count(); i < n; ++i) - { - basegfx::B2DPolygon aPoly = aDashes.getB2DPolygon(i); - aRange = aPoly.getB2DRange(); - double fW = rtl::math::round(aRange.getWidth()); - if (basegfx::fTools::equalZero(fW)) - { - // Dash line segment too small to draw. Substitute it with a solid line. - drawHairLine(mpOutputDevice, fX1, fY1, fX2, fY1, aLineColor); - return true; - } - - if (rtl::math::isNan(nThick)) - nThick = rtl::math::round(aRange.getHeight()); - - aDashesPix.append(makeRectPolygon(0, 0, fW, nThick)); - } - - // Make all dash polygons and render them. - double fX = fX1; - bool bLine = true; - sal_uInt32 i = 0, n = aDashesPix.count(); - while (fX <= fX2) - { - basegfx::B2DPolygon aPoly = aDashesPix.getB2DPolygon(i); - aRange = aPoly.getB2DRange(); - if (bLine) - { - double fBlockW = aRange.getWidth(); - if (fX + fBlockW > fX2) - // Clip the right end in case it spills over the range. - fBlockW = fX2 - fX + 1; - - double fH = aRange.getHeight(); - if (basegfx::fTools::equalZero(fH)) - fH = 1.0; - - aTarget.append(makeRectPolygon(fX, fY1, fBlockW, fH)); - } - - bLine = !bLine; // line and blank alternate. - fX += aRange.getWidth(); - - ++i; - if (i >= n) - i = 0; - } - - double fOffset = rtl::math::round(nThick/2.0, 0, rtl_math_RoundingMode_Down); - if (fOffset != 0.0) - { - // Move it up a bit to align it vertically centered. - basegfx::B2DHomMatrix aMat; - aMat.set(1, 2, -fOffset); - aTarget.transform(aMat); - } - } - else - { - // Vertical line. - - if (basegfx::fTools::equalZero(nThick)) - { - // Dash line segment too small to draw. Substitute it with a solid line. - drawHairLine(mpOutputDevice, fX1, fY1, fX1, fY2, aLineColor); - return true; - } - - // Create a dash unit polygon set. - basegfx::B2DPolyPolygon aDashes; - std::vector<double>::const_iterator it = aPattern.begin(), itEnd = aPattern.end(); - for (; it != itEnd; ++it) - aDashes.append(makeRectPolygon(0, 0, nThick, *it)); - - aDashes.transform(maCurrentTransformation); - rtl::math::setNan(&nThick); - - // Pixelize the dash unit. We use the same width for - // all dash polygons. - basegfx::B2DPolyPolygon aDashesPix; - - for (sal_uInt32 i = 0, n = aDashes.count(); i < n; ++i) - { - basegfx::B2DPolygon aPoly = aDashes.getB2DPolygon(i); - aRange = aPoly.getB2DRange(); - double fH = rtl::math::round(aRange.getHeight()); - if (basegfx::fTools::equalZero(fH)) - { - // Dash line segment too small to draw. Substitute it with a solid line. - drawHairLine(mpOutputDevice, fX1, fY1, fX1, fY2, aLineColor); - return true; - } - - if (rtl::math::isNan(nThick)) - nThick = rtl::math::round(aRange.getWidth()); - - aDashesPix.append(makeRectPolygon(0, 0, nThick, fH)); - } - - // Make all dash polygons and render them. - double fY = fY1; - bool bLine = true; - sal_uInt32 i = 0, n = aDashesPix.count(); - while (fY <= fY2) - { - basegfx::B2DPolygon aPoly = aDashesPix.getB2DPolygon(i); - aRange = aPoly.getB2DRange(); - if (bLine) - { - double fBlockH = aRange.getHeight(); - if (fY + fBlockH > fY2) - // Clip the bottom end in case it spills over the range. - fBlockH = fY2 - fY + 1; - - double fW = aRange.getWidth(); - if (basegfx::fTools::equalZero(fW)) - fW = 1.0; - - aTarget.append(makeRectPolygon(fX1, fY, fW, fBlockH)); - } - - bLine = !bLine; // line and blank alternate. - fY += aRange.getHeight(); - - ++i; - if (i >= n) - i = 0; - } - - double fOffset = rtl::math::round(nThick/2.0, 0, rtl_math_RoundingMode_Down); - if (fOffset != 0.0) - { - // Move it to the left a bit to center it horizontally. - basegfx::B2DHomMatrix aMat; - aMat.set(0, 2, -fOffset); - aTarget.transform(aMat); - } - } - - mpOutputDevice->SetFillColor(Color(aLineColor)); - mpOutputDevice->SetLineColor(); - mpOutputDevice->DrawPolyPolygon(aTarget); - - return true; - } - break; - default: - ; - } - return false; - } - void VclPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate) { switch(rCandidate.getPrimitive2DID()) @@ -1253,28 +890,26 @@ namespace drawinglayer } case PRIMITIVE2D_ID_BORDERLINEPRIMITIVE2D: { - // process recursively, but turn off anti-aliasing. Border - // lines are always rectangular, and look horrible when - // the anti-aliasing is enabled. - AntialiasingFlags nAntiAliasing = mpOutputDevice->GetAntialiasing(); - mpOutputDevice->SetAntialiasing(nAntiAliasing & ~AntialiasingFlags::EnableB2dDraw); - + // 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'. const drawinglayer::primitive2d::BorderLinePrimitive2D& rBorder = static_cast<const drawinglayer::primitive2d::BorderLinePrimitive2D&>(rCandidate); - if (!tryDrawBorderLinePrimitive2DDirect(rBorder)) + if (rBorder.isHorizontalOrVertical(getViewInformation2D())) { - if (rBorder.getStyle() == SvxBorderLineStyle::DOUBLE) - { - primitive2d::Primitive2DContainer aContainer; - rBorder.createDecomposition(aContainer, getViewInformation2D(), true); - process(aContainer); - } - else - process(rCandidate); - } + AntialiasingFlags nAntiAliasing = mpOutputDevice->GetAntialiasing(); + mpOutputDevice->SetAntialiasing(nAntiAliasing & ~AntialiasingFlags::EnableB2dDraw); - mpOutputDevice->SetAntialiasing(nAntiAliasing); + process(rCandidate); + mpOutputDevice->SetAntialiasing(nAntiAliasing); + } + else + { + process(rCandidate); + } break; } default : diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.hxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.hxx index 0a8e97d748b8..19c0282ffc5a 100644 --- a/drawinglayer/source/processor2d/vclpixelprocessor2d.hxx +++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.hxx @@ -64,7 +64,6 @@ namespace drawinglayer bool tryDrawPolyPolygonColorPrimitive2DDirect(const drawinglayer::primitive2d::PolyPolygonColorPrimitive2D& rSource, double fTransparency); bool tryDrawPolygonHairlinePrimitive2DDirect(const drawinglayer::primitive2d::PolygonHairlinePrimitive2D& rSource, double fTransparency); bool tryDrawPolygonStrokePrimitive2DDirect(const drawinglayer::primitive2d::PolygonStrokePrimitive2D& rSource, double fTransparency); - bool tryDrawBorderLinePrimitive2DDirect(const drawinglayer::primitive2d::BorderLinePrimitive2D& rSource); public: /// constructor/destructor |