summaryrefslogtreecommitdiff
path: root/drawinglayer
diff options
context:
space:
mode:
Diffstat (limited to 'drawinglayer')
-rw-r--r--drawinglayer/Library_drawinglayer.mk1
-rw-r--r--drawinglayer/qa/unit/border.cxx47
-rw-r--r--drawinglayer/source/primitive2d/borderlineprimitive2d.cxx389
-rw-r--r--drawinglayer/source/primitive2d/clippedborderlineprimitive2d.cxx64
-rw-r--r--drawinglayer/source/processor2d/vclpixelprocessor2d.cxx395
-rw-r--r--drawinglayer/source/processor2d/vclpixelprocessor2d.hxx1
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