diff options
-rw-r--r-- | drawinglayer/source/processor2d/vclpixelprocessor2d.cxx | 177 | ||||
-rw-r--r-- | include/svtools/borderhelper.hxx | 2 | ||||
-rw-r--r-- | svtools/source/control/ctrlbox.cxx | 10 |
3 files changed, 152 insertions, 37 deletions
diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx index 97a67910f7e7..f1429a1e4384 100644 --- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx @@ -52,6 +52,7 @@ #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> @@ -59,7 +60,20 @@ 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; +} + +} namespace drawinglayer { @@ -245,56 +259,145 @@ namespace drawinglayer bool VclPixelProcessor2D::tryDrawBorderLinePrimitive2DDirect( const drawinglayer::primitive2d::BorderLinePrimitive2D& rSource) { - if (rSource.getStyle() == table::BorderLineStyle::SOLID) - { - const basegfx::B2DPoint& rS = rSource.getStart(); - const basegfx::B2DPoint& rE = rSource.getEnd(); + const basegfx::B2DPoint& rS = rSource.getStart(); + const basegfx::B2DPoint& rE = rSource.getEnd(); - double nX1 = rS.getX(); - double nY1 = rS.getY(); - double nX2 = rE.getX(); - double nY2 = rE.getY(); + double fX1 = rS.getX(); + double fY1 = rS.getY(); + double fX2 = rE.getX(); + double fY2 = rE.getY(); - if (nY1 == nY2) + switch (rSource.getStyle()) + { + case table::BorderLineStyle::SOLID: { - // Horizontal line. Draw it as a rectangle. - basegfx::B2DPolygon aTarget; + if (fY1 == fY2) + { + // Horizontal line. Draw it as a rectangle. - const basegfx::BColor aLineColor = - maBColorModifierStack.getModifiedColor(rSource.getRGBColorLeft()); - double nThick = rtl::math::round(rSource.getLeftWidth()); + const basegfx::BColor aLineColor = + maBColorModifierStack.getModifiedColor(rSource.getRGBColorLeft()); + double nThick = rtl::math::round(rSource.getLeftWidth()); - aTarget.append(basegfx::B2DPoint(nX1, nY1)); - aTarget.append(basegfx::B2DPoint(nX2, nY1)); - aTarget.append(basegfx::B2DPoint(nX2, nY1+nThick)); - aTarget.append(basegfx::B2DPoint(nX1, nY1+nThick)); - aTarget.setClosed(true); - aTarget.transform(maCurrentTransformation); + basegfx::B2DPolygon aTarget = makeRectPolygon(fX1, fY1, fX2-fX1, nThick); + aTarget.transform(maCurrentTransformation); - basegfx::B2DRange aRange = aTarget.getB2DRange(); - double fH = aRange.getHeight(); + basegfx::B2DRange aRange = aTarget.getB2DRange(); + double fH = aRange.getHeight(); - if (fH <= 1.0) - { - // Draw it as a line. - aTarget.clear(); - aTarget.append(basegfx::B2DPoint(aRange.getMinX(), aRange.getMinY())); - aTarget.append(basegfx::B2DPoint(aRange.getMaxX(), aRange.getMinY())); + if (fH <= 1.0) + { + // Draw it as a line. + aTarget.clear(); + aTarget.append(basegfx::B2DPoint(aRange.getMinX(), aRange.getMinY())); + aTarget.append(basegfx::B2DPoint(aRange.getMaxX(), aRange.getMinY())); - mpOutputDevice->SetFillColor(); - mpOutputDevice->SetLineColor(Color(aLineColor)); + mpOutputDevice->SetFillColor(); + mpOutputDevice->SetLineColor(Color(aLineColor)); - mpOutputDevice->DrawPolyLine(aTarget); + mpOutputDevice->DrawPolyLine(aTarget); + return true; + } + + 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: + { + double fH = rtl::math::round(rSource.getLeftWidth()); - mpOutputDevice->SetFillColor(Color(aLineColor)); - mpOutputDevice->SetLineColor(); + if (fY1 == fY2) + { + // Horizontal line. - mpOutputDevice->DrawPolygon(aTarget); - return true; - } + basegfx::B2DPolyPolygon aDashes; + std::vector<double> aPattern = + svtools::GetLineDashing(rSource.getStyle(), rSource.getPatternScale()*10.0); + + if (aPattern.empty()) + // Failed to get pattern values. + return false; + + // Create a dash unit polygon set. + std::vector<double>::const_iterator it = aPattern.begin(), itEnd = aPattern.end(); + for (; it != itEnd; ++it) + { + double fW = *it; + aDashes.append(makeRectPolygon(0, 0, fW, fH)); + } + + aDashes.transform(maCurrentTransformation); + rtl::math::setNan(&fH); + + // 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); + basegfx::B2DRange aRange = aPoly.getB2DRange(); + double fW = rtl::math::round(aRange.getWidth()); + if (rtl::math::isNan(fH)) + fH = rtl::math::round(aRange.getHeight()); + aDashesPix.append(makeRectPolygon(0, 0, fW, fH)); + } + + // 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(); + + // Make all dash polygons and render them. + basegfx::B2DPolyPolygon aTarget; + 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; + aTarget.append(makeRectPolygon(fX, fY1, fBlockW, aRange.getHeight())); + } + + bLine = !bLine; // line and blank alternate. + fX += aRange.getWidth(); + + ++i; + if (i >= n) + i = 0; + } + + const basegfx::BColor aLineColor = + maBColorModifierStack.getModifiedColor(rSource.getRGBColorLeft()); + mpOutputDevice->SetFillColor(Color(aLineColor)); + mpOutputDevice->SetLineColor(); + + mpOutputDevice->DrawPolyPolygon(aTarget); + + return true; + } + } + break; + default: + ; } return false; } diff --git a/include/svtools/borderhelper.hxx b/include/svtools/borderhelper.hxx index a1eb77bdb08f..5e4328dfd147 100644 --- a/include/svtools/borderhelper.hxx +++ b/include/svtools/borderhelper.hxx @@ -29,6 +29,8 @@ namespace svtools { +SVT_DLLPUBLIC std::vector<double> GetLineDashing( sal_uInt16 nDashing, double fScale ); + SVT_DLLPUBLIC basegfx::B2DPolyPolygon ApplyLineDashing( const basegfx::B2DPolygon& rPolygon, sal_uInt16 nDashing, double fScale ); diff --git a/svtools/source/control/ctrlbox.cxx b/svtools/source/control/ctrlbox.cxx index b77b737037ea..47012cd7a79c 100644 --- a/svtools/source/control/ctrlbox.cxx +++ b/svtools/source/control/ctrlbox.cxx @@ -586,6 +586,9 @@ void lclDrawPolygon( OutputDevice& rDev, const basegfx::B2DPolygon& rPolygon, lo namespace svtools { +/** + * Dashing array must start with a line width and end with a blank width. + */ std::vector<double> GetDashing( sal_uInt16 nDashing ) { std::vector<double> aPattern; @@ -625,6 +628,13 @@ public: } +std::vector<double> GetLineDashing( sal_uInt16 nDashing, double fScale ) +{ + std::vector<double> aPattern = GetDashing(nDashing); + std::for_each(aPattern.begin(), aPattern.end(), ApplyScale(fScale)); + return aPattern; +} + basegfx::B2DPolyPolygon ApplyLineDashing( const basegfx::B2DPolygon& rPolygon, sal_uInt16 nDashing, double fScale ) { std::vector<double> aPattern = GetDashing(nDashing); |