diff options
author | Kohei Yoshida <kohei.yoshida@collabora.com> | 2014-01-13 13:18:25 -0500 |
---|---|---|
committer | Andras Timar <andras.timar@collabora.com> | 2014-01-29 22:33:16 +0000 |
commit | 9a19e8d838753128504274e1885eb3ce8ec1dbb8 (patch) | |
tree | ba7783a8d2ddfa3a4f2fedd9fc4075e1b8a0990b /drawinglayer | |
parent | 33ada1f20a2cdd6d52e6cb6e81aa0477ec0df563 (diff) |
fdo#73487, fdo#73886: Overhaul cell borders to make them look sane.
Change-Id: Ie563f272b60ec8b6b8a4ff0df7256902997610c1
Reviewed-on: https://gerrit.libreoffice.org/7597
Reviewed-by: Andras Timar <andras.timar@collabora.com>
Tested-by: Andras Timar <andras.timar@collabora.com>
Diffstat (limited to 'drawinglayer')
4 files changed, 480 insertions, 118 deletions
diff --git a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx index c281d8e5f745..de1a02d108ed 100644 --- a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx @@ -28,7 +28,23 @@ #include <numeric> #include <algorithm> -////////////////////////////////////////////////////////////////////////////// +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); + } +} + +} namespace drawinglayer { @@ -114,7 +130,6 @@ namespace drawinglayer if(!getStart().equal(getEnd()) && ( isInsideUsed() || isOutsideUsed() ) ) { // get data and vectors - const double fWidth(getWidth(rViewInformation)); basegfx::B2DVector aVector(getEnd() - getStart()); aVector.normalize(); const basegfx::B2DVector aPerpendicular(basegfx::getPerpendicular(aVector)); @@ -124,124 +139,66 @@ namespace drawinglayer if(isOutsideUsed() && isInsideUsed()) { - const double fExt = getWidth(rViewInformation); // Extend a lot: it'll be clipped after - - // both used, double line definition. Create left and right offset - xRetval.realloc(2); - sal_uInt32 nInsert(0); + basegfx::B2DPolygon aPolygon; + 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)); - basegfx::B2DPolygon aGap; + // Get which is the line to show + double nWidth = getLeftWidth(); + basegfx::BColor aColor = getRGBColorLeft(); - { - // create geometry for left - const basegfx::B2DVector aLeftOff(aPerpendicular * (0.5 * (lcl_GetCorrectedWidth(mfLeftWidth, getStart(), getEnd(), rViewInformation) - fWidth + 1))); - const basegfx::B2DPoint aTmpStart(getStart() + aLeftOff - ( fExt * aVector)); - const basegfx::B2DPoint aTmpEnd(getEnd() + aLeftOff + ( fExt * aVector)); - basegfx::B2DPolygon aLeft; - - if (lcl_UseHairline(mfLeftWidth, getStart(), getEnd(), - rViewInformation)) - { - // create hairline primitive - aLeft.append(aTmpStart); - aLeft.append(aTmpEnd); + bool const bIsHairline = lcl_UseHairline( + nWidth, getStart(), getEnd(), rViewInformation); + nWidth = lcl_GetCorrectedWidth(nWidth, + getStart(), getEnd(), rViewInformation); - basegfx::B2DPolyPolygon const aClipped = - basegfx::tools::clipPolygonOnPolyPolygon( - aLeft, aClipRegion, true, true); + // distance is already scaled. + double fGap = mfDistance*8.0; - xRetval[nInsert++] = - new PolyPolygonHairlinePrimitive2D( - aClipped, - getRGBColorLeft()); + if (bIsHairline) + { + // create hairline primitive + aPolygon.append( getStart() ); + aPolygon.append( getEnd() ); - aGap.append( getStart() - getExtendLeftStart() * aVector ); - aGap.append( getEnd() + getExtendLeftEnd() * aVector ); - } - else - { - // create filled polygon primitive. Already tried to create thick lines - // with the correct LineWidth, but this leads to problems when no AA - // is available and fat line special case reductions between 0.5 < x < 2.5 line widths - // are executed due to the FilledPolygon-do-not-paint-their-bottom-and-right-lines. - const basegfx::B2DVector aLineWidthOffset((lcl_GetCorrectedWidth(mfLeftWidth, getStart(), getEnd(), rViewInformation) * 0.5) * aPerpendicular); - - aLeft.append(aTmpStart + aLineWidthOffset); - aLeft.append(aTmpEnd + aLineWidthOffset); - aLeft.append(aTmpEnd - aLineWidthOffset); - aLeft.append(aTmpStart - aLineWidthOffset); - aLeft.setClosed(true); + basegfx::B2DPolygon aPolygon2 = aPolygon; + moveLine(aPolygon2, fGap, aVector); - basegfx::B2DPolyPolygon aClipped = basegfx::tools::clipPolygonOnPolyPolygon( - aLeft, aClipRegion, true, false ); - - aGap.append( aTmpStart + aLineWidthOffset ); - aGap.append( aTmpEnd + aLineWidthOffset ); + xRetval.realloc(2); + xRetval[0] = Primitive2DReference(new PolygonHairlinePrimitive2D( + aPolygon, + aColor)); - xRetval[nInsert++] = Primitive2DReference(new PolyPolygonColorPrimitive2D( - aClipped, getRGBColorLeft())); - } + xRetval[1] = Primitive2DReference(new PolygonHairlinePrimitive2D( + aPolygon2, + aColor)); } - + else { - // create geometry for right - const basegfx::B2DVector aRightOff(aPerpendicular * (0.5 * (fWidth - lcl_GetCorrectedWidth(mfRightWidth, getStart(), getEnd(), rViewInformation) + 1))); - const basegfx::B2DPoint aTmpStart(getStart() + aRightOff - ( fExt * aVector)); - const basegfx::B2DPoint aTmpEnd(getEnd() + aRightOff + ( fExt * aVector)); - basegfx::B2DPolygon aRight; - - if (lcl_UseHairline(mfRightWidth, getStart(), getEnd(), - rViewInformation)) - { - // create hairline primitive - aRight.append(aTmpStart); - aRight.append(aTmpEnd); - - basegfx::B2DPolyPolygon const aClipped = - basegfx::tools::clipPolygonOnPolyPolygon( - aRight, aClipRegion, true, true); - - xRetval[nInsert++] = - new PolyPolygonHairlinePrimitive2D( - aClipped, - getRGBColorRight()); - - aGap.append( getStart() - getExtendRightStart() * aVector ); - aGap.append( getEnd() + getExtendRightEnd() * aVector ); - } - else - { - // create filled polygon primitive - const basegfx::B2DVector aLineWidthOffset((lcl_GetCorrectedWidth(mfRightWidth, getStart(), getEnd(), rViewInformation) * 0.5) * aPerpendicular); - - aRight.append(aTmpStart + aLineWidthOffset); - aRight.append(aTmpEnd + aLineWidthOffset); - aRight.append(aTmpEnd - aLineWidthOffset); - aRight.append(aTmpStart - aLineWidthOffset); - aRight.setClosed(true); - - basegfx::B2DPolyPolygon aClipped = basegfx::tools::clipPolygonOnPolyPolygon( - aRight, aClipRegion, true, false ); + // create filled polygon primitive + const basegfx::B2DVector aLineWidthOffset(((nWidth + 1) * 0.5) * aPerpendicular); - xRetval[nInsert++] = Primitive2DReference(new PolyPolygonColorPrimitive2D( - aClipped, getRGBColorRight())); + aPolygon.append( aTmpStart + aLineWidthOffset ); + aPolygon.append( aTmpEnd + aLineWidthOffset ); + aPolygon.append( aTmpEnd - aLineWidthOffset ); + aPolygon.append( aTmpStart - aLineWidthOffset ); + aPolygon.setClosed( true ); - aGap.append( aTmpEnd - aLineWidthOffset ); - aGap.append( aTmpStart - aLineWidthOffset ); - } - } + basegfx::B2DPolyPolygon aClipped = basegfx::tools::clipPolygonOnPolyPolygon( + aPolygon, aClipRegion, true, false ); - if (hasGapColor() && aGap.count() == 4) - { - xRetval.realloc( xRetval.getLength() + 1 ); - // create geometry for filled gap - aGap.setClosed( true ); + if ( aClipped.count() ) + aPolygon = aClipped.getB2DPolygon(0); - basegfx::B2DPolyPolygon aClipped = basegfx::tools::clipPolygonOnPolyPolygon( - aGap, aClipRegion, true, false ); + basegfx::B2DPolygon aPolygon2 = aPolygon; + moveLine(aPolygon2, fGap, aVector); - xRetval[nInsert++] = Primitive2DReference( new PolyPolygonColorPrimitive2D( - aClipped, getRGBColorGap() ) ); + xRetval.realloc(2); + xRetval[0] = Primitive2DReference( + new PolyPolygonColorPrimitive2D(basegfx::B2DPolyPolygon(aPolygon), aColor)); + xRetval[1] = Primitive2DReference( + new PolyPolygonColorPrimitive2D(basegfx::B2DPolyPolygon(aPolygon2), aColor)); } } else @@ -251,7 +208,6 @@ namespace drawinglayer 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)); - xRetval.realloc(1); // Get which is the line to show bool bIsSolidline = isSolidLine(); @@ -273,6 +229,7 @@ namespace drawinglayer aPolygon.append( getStart() ); aPolygon.append( getEnd() ); + xRetval.realloc(1); xRetval[0] = Primitive2DReference(new PolygonHairlinePrimitive2D( aPolygon, aColor)); @@ -281,13 +238,13 @@ namespace drawinglayer { // create filled polygon primitive const basegfx::B2DVector aLineWidthOffset(((nWidth + 1) * 0.5) * aPerpendicular); - basegfx::B2DVector aScale( rViewInformation.getInverseObjectToViewTransformation() * aVector ); aPolygon.append( aTmpStart ); aPolygon.append( aTmpEnd ); - basegfx::B2DPolyPolygon aDashed = svtools::ApplyLineDashing( - aPolygon, getStyle(), MAP_PIXEL, aScale.getLength() ); + 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 ); @@ -308,8 +265,28 @@ namespace drawinglayer aDashed.setB2DPolygon( i, aClipped.getB2DPolygon( 0 ) ); } - xRetval[0] = Primitive2DReference(new PolyPolygonColorPrimitive2D( - basegfx::B2DPolyPolygon( aDashed ), aColor)); + sal_uInt32 n = aDashed.count(); + xRetval.realloc(n); + for (sal_uInt32 i = 0; i < n; ++i) + { + basegfx::B2DPolygon aDash = aDashed.getB2DPolygon(i); + if (bIsHairline) + { + // Convert a rectanglar polygon into a line. + basegfx::B2DPolygon aDash2; + basegfx::B2DRange aRange = aDash.getB2DRange(); + basegfx::B2DPoint aPt(aRange.getMinX(), aRange.getMinY()); + aDash2.append(basegfx::B2DPoint(aRange.getMinX(), aRange.getMinY())); + aDash2.append(basegfx::B2DPoint(aRange.getMaxX(), aRange.getMinY())); + xRetval[i] = Primitive2DReference( + new PolygonHairlinePrimitive2D(aDash2, aColor)); + } + else + { + xRetval[i] = Primitive2DReference( + new PolyPolygonColorPrimitive2D(basegfx::B2DPolyPolygon(aDash), aColor)); + } + } } } } @@ -331,7 +308,8 @@ namespace drawinglayer const basegfx::BColor& rRGBColorLeft, const basegfx::BColor& rRGBColorGap, bool bHasGapColor, - const short nStyle) + const short nStyle, + double fPatternScale) : BufferedDecompositionPrimitive2D(), maStart(rStart), maEnd(rEnd), @@ -346,7 +324,8 @@ namespace drawinglayer maRGBColorLeft(rRGBColorLeft), maRGBColorGap(rRGBColorGap), mbHasGapColor(bHasGapColor), - mnStyle(nStyle) + mnStyle(nStyle), + mfPatternScale(fPatternScale) { } @@ -369,7 +348,8 @@ namespace drawinglayer && getRGBColorLeft() == rCompare.getRGBColorLeft() && getRGBColorGap() == rCompare.getRGBColorGap() && hasGapColor() == rCompare.hasGapColor() - && getStyle() == rCompare.getStyle()); + && getStyle() == rCompare.getStyle() + && getPatternScale() == rCompare.getPatternScale()); } return false; diff --git a/drawinglayer/source/primitive2d/clippedborderlineprimitive2d.cxx b/drawinglayer/source/primitive2d/clippedborderlineprimitive2d.cxx index 2bfcd8c121a8..895c06eafa52 100644 --- a/drawinglayer/source/primitive2d/clippedborderlineprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/clippedborderlineprimitive2d.cxx @@ -33,10 +33,11 @@ namespace drawinglayer const basegfx::BColor& rRGBColorLeft, const basegfx::BColor& rRGBColorGap, bool bHasGapColor, - const short nStyle) + const short nStyle, + double fPatternScale) : BorderLinePrimitive2D( rStart, rEnd, fLeftWidth,fDistance, fRightWidth, 0.0, 0.0, 0.0, 0.0, rRGBColorRight, rRGBColorLeft, - rRGBColorGap, bHasGapColor, nStyle), + rRGBColorGap, bHasGapColor, nStyle, fPatternScale), maIntersection( rIntersection ) { } diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx index a805bd2895ff..9552be3d4a14 100644 --- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx @@ -34,6 +34,7 @@ #include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx> #include <drawinglayer/primitive2d/wrongspellprimitive2d.hxx> #include <drawinglayer/primitive2d/controlprimitive2d.hxx> +#include <drawinglayer/primitive2d/borderlineprimitive2d.hxx> #include <com/sun/star/awt/XWindow2.hpp> #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx> #include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx> @@ -51,12 +52,41 @@ #include <drawinglayer/primitive2d/svggradientprimitive2d.hxx> #include <toolkit/helper/vclunohelper.hxx> #include <vcl/window.hxx> +#include <svtools/borderhelper.hxx> + +#include <com/sun/star/table/BorderLineStyle.hpp> ////////////////////////////////////////////////////////////////////////////// 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 { @@ -239,6 +269,338 @@ 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 table::BorderLineStyle::SOLID: + case table::BorderLineStyle::DOUBLE: + { + const basegfx::BColor aLineColor = + maBColorModifierStack.getModifiedColor(rSource.getRGBColorLeft()); + double nThick = rtl::math::round(rSource.getLeftWidth()); + + bool bDouble = rSource.getStyle() == table::BorderLineStyle::DOUBLE; + + 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 table::BorderLineStyle::DOTTED: + case table::BorderLineStyle::DASHED: + case table::BorderLineStyle::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()) @@ -843,6 +1205,23 @@ namespace drawinglayer RenderSvgRadialAtomPrimitive2D(static_cast< const primitive2d::SvgRadialAtomPrimitive2D& >(rCandidate)); break; } + 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. + sal_uInt16 nAntiAliasing = mpOutputDevice->GetAntialiasing(); + mpOutputDevice->SetAntialiasing(nAntiAliasing & ~ANTIALIASING_ENABLE_B2DDRAW); + + const drawinglayer::primitive2d::BorderLinePrimitive2D& rBorder = + static_cast<const drawinglayer::primitive2d::BorderLinePrimitive2D&>(rCandidate); + + if (!tryDrawBorderLinePrimitive2DDirect(rBorder)) + process(rCandidate.get2DDecomposition(getViewInformation2D())); + + mpOutputDevice->SetAntialiasing(nAntiAliasing); + break; + } default : { // process recursively diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.hxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.hxx index a55962deb5b6..c9c2d7422dc6 100644 --- a/drawinglayer/source/processor2d/vclpixelprocessor2d.hxx +++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.hxx @@ -34,6 +34,7 @@ namespace drawinglayer { namespace primitive2d { class PolyPolygonColorPrimitive2D; class PolygonHairlinePrimitive2D; class PolygonStrokePrimitive2D; + class BorderLinePrimitive2D; }} ////////////////////////////////////////////////////////////////////////////// @@ -64,6 +65,7 @@ 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 |