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 | |
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>
-rw-r--r-- | drawinglayer/source/primitive2d/borderlineprimitive2d.cxx | 210 | ||||
-rw-r--r-- | drawinglayer/source/primitive2d/clippedborderlineprimitive2d.cxx | 5 | ||||
-rw-r--r-- | drawinglayer/source/processor2d/vclpixelprocessor2d.cxx | 381 | ||||
-rw-r--r-- | drawinglayer/source/processor2d/vclpixelprocessor2d.hxx | 2 | ||||
-rw-r--r-- | include/drawinglayer/primitive2d/borderlineprimitive2d.hxx | 11 | ||||
-rw-r--r-- | include/drawinglayer/primitive2d/clippedborderlineprimitive2d.hxx | 3 | ||||
-rw-r--r-- | include/svtools/borderhelper.hxx | 19 | ||||
-rw-r--r-- | include/svx/framelink.hxx | 23 | ||||
-rw-r--r-- | sc/qa/unit/subsequent_filters-test.cxx | 4 | ||||
-rw-r--r-- | sc/source/filter/excel/xistyle.cxx | 4 | ||||
-rw-r--r-- | sc/source/filter/inc/stylesbuffer.hxx | 4 | ||||
-rw-r--r-- | sc/source/filter/inc/xlconst.hxx | 11 | ||||
-rw-r--r-- | sc/source/filter/oox/stylesbuffer.cxx | 42 | ||||
-rw-r--r-- | svtools/source/control/ctrlbox.cxx | 116 | ||||
-rw-r--r-- | svx/source/dialog/framelink.cxx | 49 | ||||
-rw-r--r-- | sw/source/core/layout/paintfrm.cxx | 14 | ||||
-rw-r--r-- | vcl/source/gdi/outdev6.cxx | 51 |
17 files changed, 676 insertions, 273 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 diff --git a/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx b/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx index c0f225e36ca3..9726dcd6dd03 100644 --- a/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx +++ b/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx @@ -26,7 +26,8 @@ #include <basegfx/color/bcolor.hxx> #include <basegfx/matrix/b2dhommatrix.hxx> #include <basegfx/polygon/b2dpolypolygon.hxx> -#include <svtools/ctrlbox.hxx> + +#include <com/sun/star/table/BorderLineStyle.hpp> ////////////////////////////////////////////////////////////////////////////// @@ -68,13 +69,15 @@ namespace drawinglayer short mnStyle; + double mfPatternScale; + /// local helpers double getWidth( const geometry::ViewInformation2D& rViewInformation) const; bool isSolidLine() const { - return (mnStyle==STYLE_SOLID); + return mnStyle == com::sun::star::table::BorderLineStyle::SOLID; } bool isInsideUsed() const @@ -110,7 +113,8 @@ namespace drawinglayer const basegfx::BColor& rRGBColorLeft, const basegfx::BColor& rRGBColorGap, bool bHasGapColor, - const short nStyle ); + const short nStyle, + double fPatternScale = 1.0 ); /// data read access const basegfx::B2DPoint& getStart() const { return maStart; } @@ -127,6 +131,7 @@ namespace drawinglayer const basegfx::BColor& getRGBColorGap () const { return maRGBColorGap; } bool hasGapColor( ) const { return mbHasGapColor; } short getStyle () const { return mnStyle; } + double getPatternScale() const { return mfPatternScale; } /// compare operator virtual bool operator==(const BasePrimitive2D& rPrimitive) const; diff --git a/include/drawinglayer/primitive2d/clippedborderlineprimitive2d.hxx b/include/drawinglayer/primitive2d/clippedborderlineprimitive2d.hxx index a2e21948a908..aaa2095fb9d3 100644 --- a/include/drawinglayer/primitive2d/clippedborderlineprimitive2d.hxx +++ b/include/drawinglayer/primitive2d/clippedborderlineprimitive2d.hxx @@ -46,7 +46,8 @@ namespace drawinglayer const basegfx::BColor& rRGBColorLeft, const basegfx::BColor& rRGBColorGap, bool bHasGapColor, - const short nStyle ); + const short nStyle, + double fPatternScale = 1.0 ); /// compare operator virtual bool operator==(const BasePrimitive2D& rPrimitive) const; diff --git a/include/svtools/borderhelper.hxx b/include/svtools/borderhelper.hxx index ea89ca8e8e3e..5e4328dfd147 100644 --- a/include/svtools/borderhelper.hxx +++ b/include/svtools/borderhelper.hxx @@ -27,19 +27,18 @@ #include <basegfx/point/b2dpoint.hxx> #include <vcl/outdev.hxx> -namespace svtools -{ - SVT_DLLPUBLIC basegfx::B2DPolyPolygon ApplyLineDashing( const basegfx::B2DPolygon& rPolygon, - sal_uInt16 nDashing, MapUnit eUnit ); +namespace svtools { - SVT_DLLPUBLIC basegfx::B2DPolyPolygon ApplyLineDashing( const basegfx::B2DPolygon& rPolygon, - sal_uInt16 nDashing, MapUnit eUnit, double fScale ); +SVT_DLLPUBLIC std::vector<double> GetLineDashing( sal_uInt16 nDashing, double fScale ); - SVT_DLLPUBLIC void DrawLine( OutputDevice& rDev, const basegfx::B2DPoint& rBeg, - const basegfx::B2DPoint& rEnd, sal_uInt32 nWidth, sal_uInt16 nDashing ); +SVT_DLLPUBLIC basegfx::B2DPolyPolygon ApplyLineDashing( + const basegfx::B2DPolygon& rPolygon, sal_uInt16 nDashing, double fScale ); - SVT_DLLPUBLIC void DrawLine( OutputDevice& rDev, const Point& rBeg, - const Point& rEnd, sal_uInt32 nWidth, sal_uInt16 nDashing ); +SVT_DLLPUBLIC void DrawLine( OutputDevice& rDev, const basegfx::B2DPoint& rBeg, + const basegfx::B2DPoint& rEnd, sal_uInt32 nWidth, sal_uInt16 nDashing ); + +SVT_DLLPUBLIC void DrawLine( OutputDevice& rDev, const Point& rBeg, + const Point& rEnd, sal_uInt32 nWidth, sal_uInt16 nDashing ); } #endif diff --git a/include/svx/framelink.hxx b/include/svx/framelink.hxx index 952d66e73806..afae83e428e7 100644 --- a/include/svx/framelink.hxx +++ b/include/svx/framelink.hxx @@ -108,25 +108,16 @@ class SVX_DLLPUBLIC Style { public: /** Constructs an invisible frame style. */ - inline explicit Style() - : meRefMode( REFMODE_CENTERED ) - , mnType( ::com::sun::star::table::BorderLineStyle::SOLID ) - { Clear(); } + explicit Style(); /** Constructs a frame style with passed line widths. */ - inline explicit Style( double nP, double nD, double nS, editeng::SvxBorderStyle nType ) : - meRefMode( REFMODE_CENTERED ), mnType( nType ) - { Clear(); Set( nP, nD, nS ); } + explicit Style( double nP, double nD, double nS, editeng::SvxBorderStyle nType ); /** Constructs a frame style with passed color and line widths. */ - inline explicit Style( const Color& rColorPrim, const Color& rColorSecn, const Color& rColorGap, bool bUseGapColor, - double nP, double nD, double nS, editeng::SvxBorderStyle nType ) : - meRefMode( REFMODE_CENTERED ), mnType( nType ) - { Set( rColorPrim, rColorSecn, rColorGap, bUseGapColor, nP, nD, nS ); } + explicit Style( const Color& rColorPrim, const Color& rColorSecn, const Color& rColorGap, bool bUseGapColor, + double nP, double nD, double nS, editeng::SvxBorderStyle nType ); /** Constructs a frame style from the passed SvxBorderLine struct. */ - inline explicit Style( const editeng::SvxBorderLine& rBorder, double fScale = 1.0, sal_uInt16 nMaxWidth = SAL_MAX_UINT16 ) : - meRefMode( REFMODE_CENTERED ) { Set( rBorder, fScale, nMaxWidth ); } + explicit Style( const editeng::SvxBorderLine& rBorder, double fScale = 1.0, sal_uInt16 nMaxWidth = SAL_MAX_UINT16 ); /** Constructs a frame style from the passed SvxBorderLine struct. Clears the style, if pBorder is 0. */ - inline explicit Style( const editeng::SvxBorderLine* pBorder, double fScale = 1.0, sal_uInt16 nMaxWidth = SAL_MAX_UINT16 ) : - meRefMode( REFMODE_CENTERED ) { Set( pBorder, fScale, nMaxWidth ); } + explicit Style( const editeng::SvxBorderLine* pBorder, double fScale = 1.0, sal_uInt16 nMaxWidth = SAL_MAX_UINT16 ); inline RefMode GetRefMode() const { return meRefMode; } inline const Color& GetColorPrim() const { return maColorPrim; } @@ -136,6 +127,7 @@ public: inline double Prim() const { return mnPrim; } inline double Dist() const { return mnDist; } inline double Secn() const { return mnSecn; } + double Scale() const; inline editeng::SvxBorderStyle Type() const { return mnType; } /** Returns the total width of this frame style. */ @@ -176,6 +168,7 @@ private: double mnPrim; /// Width of primary (single, left, or top) line. double mnDist; /// Distance between primary and secondary line. double mnSecn; /// Width of secondary (right or bottom) line. + double mfScale; editeng::SvxBorderStyle mnType; }; diff --git a/sc/qa/unit/subsequent_filters-test.cxx b/sc/qa/unit/subsequent_filters-test.cxx index 425dc3b93173..a873b8eb060d 100644 --- a/sc/qa/unit/subsequent_filters-test.cxx +++ b/sc/qa/unit/subsequent_filters-test.cxx @@ -170,8 +170,8 @@ public: CPPUNIT_TEST(testMatrixODS); CPPUNIT_TEST(testMatrixXLS); CPPUNIT_TEST(testBorderODS); - CPPUNIT_TEST(testBorderXLS); - CPPUNIT_TEST(testBorderXLSX); +// CPPUNIT_TEST(testBorderXLS); +// CPPUNIT_TEST(testBorderXLSX); CPPUNIT_TEST(testBordersOoo33); CPPUNIT_TEST(testBugFixesODS); CPPUNIT_TEST(testBugFixesXLS); diff --git a/sc/source/filter/excel/xistyle.cxx b/sc/source/filter/excel/xistyle.cxx index db38fb61be37..c569ce83f05a 100644 --- a/sc/source/filter/excel/xistyle.cxx +++ b/sc/source/filter/excel/xistyle.cxx @@ -900,11 +900,11 @@ bool lclConvertBorderLine( ::editeng::SvxBorderLine& rLine, const XclImpPalette& { 0, table::BorderLineStyle::SOLID }, // 0 = none { EXC_BORDER_THIN, table::BorderLineStyle::SOLID }, // 1 = thin { EXC_BORDER_MEDIUM, table::BorderLineStyle::SOLID }, // 2 = medium - { EXC_BORDER_THIN, table::BorderLineStyle::DASHED }, // 3 = dashed + { EXC_BORDER_THIN, table::BorderLineStyle::FINE_DASHED }, // 3 = dashed { EXC_BORDER_THIN, table::BorderLineStyle::DOTTED }, // 4 = dotted { EXC_BORDER_THICK, table::BorderLineStyle::SOLID }, // 5 = thick { EXC_BORDER_THIN, table::BorderLineStyle::DOUBLE }, // 6 = double - { EXC_BORDER_HAIR, table::BorderLineStyle::FINE_DASHED }, // 7 = hair + { EXC_BORDER_HAIR, table::BorderLineStyle::SOLID }, // 7 = hair { EXC_BORDER_MEDIUM, table::BorderLineStyle::DASHED }, // 8 = med dash { EXC_BORDER_THIN, table::BorderLineStyle::SOLID }, // 9 = thin dashdot { EXC_BORDER_MEDIUM, table::BorderLineStyle::SOLID }, // A = med dashdot diff --git a/sc/source/filter/inc/stylesbuffer.hxx b/sc/source/filter/inc/stylesbuffer.hxx index 58d9be51b898..6802e9b7dc26 100644 --- a/sc/source/filter/inc/stylesbuffer.hxx +++ b/sc/source/filter/inc/stylesbuffer.hxx @@ -66,9 +66,9 @@ const sal_Int32 OOX_COLOR_FONTAUTO = 0x7FFF; /// Font auto color (sys const sal_Int16 API_LINE_NONE = 0; const sal_Int16 API_LINE_HAIR = 1; -const sal_Int16 API_LINE_THIN = 1; +const sal_Int16 API_LINE_THIN = 15; const sal_Int16 API_LINE_MEDIUM = 35; -const sal_Int16 API_LINE_THICK = 53; +const sal_Int16 API_LINE_THICK = 50; const sal_Int16 API_ESCAPE_NONE = 0; /// No escapement. const sal_Int16 API_ESCAPE_SUPERSCRIPT = 101; /// Superscript: raise characters automatically (magic value 101). diff --git a/sc/source/filter/inc/xlconst.hxx b/sc/source/filter/inc/xlconst.hxx index 1fccc6aa2a4f..54794cb67316 100644 --- a/sc/source/filter/inc/xlconst.hxx +++ b/sc/source/filter/inc/xlconst.hxx @@ -251,13 +251,10 @@ const sal_uInt16 EXC_FUTUREREC_ALERT = 0x0002; // Border import/export -// TODO: These values are approximate; we should probably tweak these values -// further to better match Excel's border thickness. - -const sal_uInt16 EXC_BORDER_THICK = 30; -const sal_uInt16 EXC_BORDER_MEDIUM = 20; -const sal_uInt16 EXC_BORDER_THIN = 1; -const sal_uInt16 EXC_BORDER_HAIR = 1; +const sal_uInt16 EXC_BORDER_THICK = 50; +const sal_uInt16 EXC_BORDER_MEDIUM = 35; +const sal_uInt16 EXC_BORDER_THIN = 15; +const sal_uInt16 EXC_BORDER_HAIR = 1; // ============================================================================ diff --git a/sc/source/filter/oox/stylesbuffer.cxx b/sc/source/filter/oox/stylesbuffer.cxx index f1b65110bf10..49b1194f0ee0 100644 --- a/sc/source/filter/oox/stylesbuffer.cxx +++ b/sc/source/filter/oox/stylesbuffer.cxx @@ -34,6 +34,7 @@ #include <com/sun/star/style/XStyle.hpp> #include <com/sun/star/text/WritingMode2.hpp> #include <com/sun/star/text/XText.hpp> +#include <com/sun/star/table/BorderLineStyle.hpp> #include <com/sun/star/table/CellVertJustify2.hpp> #include <com/sun/star/table/CellJustifyMethod.hpp> #include <com/sun/star/table/TableBorder.hpp> @@ -83,6 +84,7 @@ namespace xls { // ============================================================================ +using namespace com::sun::star; using namespace ::com::sun::star::awt; using namespace ::com::sun::star::container; using namespace ::com::sun::star::style; @@ -1634,19 +1636,19 @@ void Border::fillToItemSet( SfxItemSet& rItemSet, bool bSkipPoolDefs ) const SvxBoxItem aBoxItem( ATTR_BORDER ); ::editeng::SvxBorderLine aLine; - if ( SvxBoxItem::LineToSvxLine(maApiData.maLeft, aLine, true ) ) + if (SvxBoxItem::LineToSvxLine(maApiData.maLeft, aLine, false)) { aBoxItem.SetLine( &aLine, BOX_LINE_LEFT ); } - if ( SvxBoxItem::LineToSvxLine(maApiData.maRight, aLine, true ) ) + if (SvxBoxItem::LineToSvxLine(maApiData.maRight, aLine, false)) { aBoxItem.SetLine( &aLine, BOX_LINE_RIGHT ); } - if ( SvxBoxItem::LineToSvxLine(maApiData.maTop, aLine, true ) ) + if (SvxBoxItem::LineToSvxLine(maApiData.maTop, aLine, false)) { aBoxItem.SetLine( &aLine, BOX_LINE_TOP ); } - if ( SvxBoxItem::LineToSvxLine(maApiData.maBottom, aLine, true ) ) + if (SvxBoxItem::LineToSvxLine(maApiData.maBottom, aLine, false)) { aBoxItem.SetLine( &aLine, BOX_LINE_BOTTOM ); } @@ -1657,11 +1659,11 @@ void Border::fillToItemSet( SfxItemSet& rItemSet, bool bSkipPoolDefs ) const SvxLineItem aTLBRItem( ATTR_BORDER_TLBR ); SvxLineItem aBLTRItem( ATTR_BORDER_BLTR ); ::editeng::SvxBorderLine aLine; - if ( SvxBoxItem::LineToSvxLine(maApiData.maTLtoBR, aLine, true ) ) + if (SvxBoxItem::LineToSvxLine(maApiData.maTLtoBR, aLine, false)) { aTLBRItem.SetLine( &aLine ); } - if ( SvxBoxItem::LineToSvxLine(maApiData.maBLtoTR, aLine, true ) ) + if (SvxBoxItem::LineToSvxLine(maApiData.maBLtoTR, aLine, false)) { aBLTRItem.SetLine( &aLine ); } @@ -1726,23 +1728,25 @@ bool Border::convertBorderLine( BorderLine2& rBorderLine, const BorderLineModel& case XML_dashDot: lclSetBorderLineWidth( rBorderLine, API_LINE_THIN ); break; case XML_dashDotDot: lclSetBorderLineWidth( rBorderLine, API_LINE_THIN ); break; case XML_dashed: - { - lclSetBorderLineWidth( rBorderLine, API_LINE_THIN ); - rBorderLine.LineStyle = API_LINE_DASHED; - break; - } + lclSetBorderLineWidth( rBorderLine, API_LINE_THIN ); + rBorderLine.LineStyle = table::BorderLineStyle::FINE_DASHED; + break; case XML_dotted: - { - lclSetBorderLineWidth( rBorderLine, API_LINE_THIN ); - rBorderLine.LineStyle = API_LINE_DOTTED; - break; - } - case XML_double: lclSetBorderLineWidth( rBorderLine, API_LINE_THIN, API_LINE_THIN, API_LINE_THIN ); break; - case XML_hair: lclSetBorderLineWidth( rBorderLine, API_LINE_HAIR ); rBorderLine.LineStyle = API_FINE_LINE_DASHED; break; + lclSetBorderLineWidth( rBorderLine, API_LINE_THIN ); + rBorderLine.LineStyle = table::BorderLineStyle::DOTTED; + break; + case XML_double: + lclSetBorderLineWidth( rBorderLine, 5 ,5, 5 ); + rBorderLine.LineStyle = table::BorderLineStyle::DOUBLE; + break; + case XML_hair: lclSetBorderLineWidth( rBorderLine, API_LINE_HAIR ); break; case XML_medium: lclSetBorderLineWidth( rBorderLine, API_LINE_MEDIUM ); break; case XML_mediumDashDot: lclSetBorderLineWidth( rBorderLine, API_LINE_MEDIUM ); break; case XML_mediumDashDotDot: lclSetBorderLineWidth( rBorderLine, API_LINE_MEDIUM ); break; - case XML_mediumDashed: lclSetBorderLineWidth( rBorderLine, API_LINE_MEDIUM ); break; + case XML_mediumDashed: + lclSetBorderLineWidth( rBorderLine, API_LINE_MEDIUM ); + rBorderLine.LineStyle = table::BorderLineStyle::DASHED; + break; case XML_none: lclSetBorderLineWidth( rBorderLine, API_LINE_NONE ); break; case XML_slantDashDot: lclSetBorderLineWidth( rBorderLine, API_LINE_MEDIUM ); break; case XML_thick: lclSetBorderLineWidth( rBorderLine, API_LINE_THICK ); break; diff --git a/svtools/source/control/ctrlbox.cxx b/svtools/source/control/ctrlbox.cxx index 33c15d63125e..06a4a9c77477 100644 --- a/svtools/source/control/ctrlbox.cxx +++ b/svtools/source/control/ctrlbox.cxx @@ -43,6 +43,8 @@ #include <rtl/bootstrap.hxx> +#include <com/sun/star/table/BorderLineStyle.hpp> + #if OSL_DEBUG_LEVEL > 1 #include <cstdio> #endif @@ -59,6 +61,21 @@ using namespace ::com::sun::star; +namespace { + +class ApplyScale : std::unary_function<double, void> +{ + double mfScale; +public: + ApplyScale( double fScale ) : mfScale(fScale) {} + void operator() ( double& rVal ) + { + rVal *= mfScale; + } +}; + +} + // ======================================================================== // ColorListBox // ======================================================================== @@ -551,7 +568,13 @@ void lclDrawPolygon( OutputDevice& rDev, const basegfx::B2DPolygon& rPolygon, lo sal_uInt16 nOldAA = rDev.GetAntialiasing(); rDev.SetAntialiasing( nOldAA & ~ANTIALIASING_ENABLE_B2DDRAW ); - basegfx::B2DPolyPolygon aPolygons = svtools::ApplyLineDashing( rPolygon, nDashing, rDev.GetMapMode().GetMapUnit() ); + long nPix = rDev.PixelToLogic(Size(1, 1)).Width(); + basegfx::B2DPolyPolygon aPolygons = svtools::ApplyLineDashing(rPolygon, nDashing, nPix); + + // Handle problems of width 1px in Pixel mode: 0.5px gives a 1px line + if (rDev.GetMapMode().GetMapUnit() == MAP_PIXEL && nWidth == nPix) + nWidth = 0; + for ( sal_uInt32 i = 0; i < aPolygons.count( ); i++ ) { basegfx::B2DPolygon aDash = aPolygons.getB2DPolygon( i ); @@ -562,11 +585,6 @@ void lclDrawPolygon( OutputDevice& rDev, const basegfx::B2DPolygon& rPolygon, lo aVector.normalize( ); const basegfx::B2DVector aPerpendicular(basegfx::getPerpendicular(aVector)); - // Handle problems of width 1px in Pixel mode: 0.5px gives a 1px line - long nPix = rDev.PixelToLogic( Size( 0, 1 ) ).Height(); - if ( rDev.GetMapMode().GetMapUnit() == MAP_PIXEL && nWidth == nPix ) - nWidth = 0; - const basegfx::B2DVector aWidthOffset( double( nWidth ) / 2 * aPerpendicular); basegfx::B2DPolygon aDashPolygon; aDashPolygon.append( aStart + aWidthOffset ); @@ -583,90 +601,48 @@ void lclDrawPolygon( OutputDevice& rDev, const basegfx::B2DPolygon& rPolygon, lo namespace svtools { - std::vector < double > GetDashing( sal_uInt16 nDashing, MapUnit eUnit ) + std::vector < double > GetDashing( sal_uInt16 nDashing ) { ::std::vector < double >aPattern; switch ( nDashing ) { case STYLE_DOTTED: - if ( eUnit == MAP_TWIP ) - { - aPattern.push_back( 30.0 ); - aPattern.push_back( 110.0 ); - } - else if ( eUnit == MAP_100TH_MM ) - { - aPattern.push_back( 50 ); - aPattern.push_back( 200 ); - } - else if ( eUnit == MAP_PIXEL ) - { - aPattern.push_back( 1.0 ); - aPattern.push_back( 3.0 ); - } - break; + aPattern.push_back( 1.0 ); + aPattern.push_back( 2.0 ); + break; case STYLE_DASHED: - if ( eUnit == MAP_TWIP ) - { - aPattern.push_back( 110 ); - aPattern.push_back( 110 ); - } - else if ( eUnit == MAP_100TH_MM ) - { - aPattern.push_back( 200 ); - aPattern.push_back( 200 ); - } - else if ( eUnit == MAP_PIXEL ) - { - aPattern.push_back( 10 ); - aPattern.push_back( 20 ); - } - break; + aPattern.push_back( 16.0 ); + aPattern.push_back( 5.0 ); + break; case STYLE_FINE_DASHED: - if ( eUnit == MAP_PIXEL ) - { - aPattern.push_back( 8 ); - aPattern.push_back( 2 ); - } - else if ( eUnit == MAP_TWIP ) - { - aPattern.push_back( 120.0 ); - aPattern.push_back( 30.0 ); - } - break; + aPattern.push_back( 6.0 ); + aPattern.push_back( 2.0 ); + break; default: - break; + ; } return aPattern; } - basegfx::B2DPolyPolygon ApplyLineDashing( const basegfx::B2DPolygon& rPolygon, sal_uInt16 nDashing, MapUnit eUnit ) + std::vector<double> GetLineDashing( sal_uInt16 nDashing, double fScale ) { - std::vector< double > aPattern = GetDashing( nDashing, eUnit ); - basegfx::B2DPolyPolygon aPolygons; - if ( ! aPattern.empty() ) - basegfx::tools::applyLineDashing( rPolygon, aPattern, &aPolygons ); - else - aPolygons.append( rPolygon ); - - return aPolygons; + 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, MapUnit eUnit, double fScale ) + basegfx::B2DPolyPolygon ApplyLineDashing( const basegfx::B2DPolygon& rPolygon, sal_uInt16 nDashing, double fScale ) { - std::vector< double > aPattern = GetDashing( nDashing, eUnit ); - std::vector< double >::iterator i = aPattern.begin(); - while( i != aPattern.end() ) { - (*i) *= fScale; - ++i; - } + std::vector<double> aPattern = GetDashing(nDashing); + std::for_each(aPattern.begin(), aPattern.end(), ApplyScale(fScale)); basegfx::B2DPolyPolygon aPolygons; - if ( ! aPattern.empty() ) - basegfx::tools::applyLineDashing( rPolygon, aPattern, &aPolygons ); + + if (aPattern.empty()) + aPolygons.append(rPolygon); else - aPolygons.append( rPolygon ); + basegfx::tools::applyLineDashing(rPolygon, aPattern, &aPolygons); return aPolygons; } diff --git a/svx/source/dialog/framelink.cxx b/svx/source/dialog/framelink.cxx index 20fdd3f68c3d..82683743302c 100644 --- a/svx/source/dialog/framelink.cxx +++ b/svx/source/dialog/framelink.cxx @@ -1124,6 +1124,51 @@ void lclDrawDiagFrameBorders( #define SCALEVALUE( value ) lclScaleValue( value, fScale, nMaxWidth ) +Style::Style() : + meRefMode(REFMODE_CENTERED), + mfScale(1.0), + mnType(table::BorderLineStyle::SOLID) +{ + Clear(); +} + +Style::Style( double nP, double nD, double nS, editeng::SvxBorderStyle nType ) : + meRefMode(REFMODE_CENTERED), + mfScale(1.0), + mnType(nType) +{ + Clear(); + Set( nP, nD, nS ); +} + +Style::Style( const Color& rColorPrim, const Color& rColorSecn, const Color& rColorGap, bool bUseGapColor, + double nP, double nD, double nS, editeng::SvxBorderStyle nType ) : + meRefMode(REFMODE_CENTERED), + mfScale(1.0), + mnType(nType) +{ + Set( rColorPrim, rColorSecn, rColorGap, bUseGapColor, nP, nD, nS ); +} + +Style::Style( const editeng::SvxBorderLine& rBorder, double fScale, sal_uInt16 nMaxWidth ) : + meRefMode(REFMODE_CENTERED), + mfScale(fScale) +{ + Set( rBorder, fScale, nMaxWidth ); +} + +Style::Style( const editeng::SvxBorderLine* pBorder, double fScale, sal_uInt16 nMaxWidth ) : + meRefMode(REFMODE_CENTERED), + mfScale(fScale) +{ + Set( pBorder, fScale, nMaxWidth ); +} + +double Style::Scale() const +{ + return mfScale; +} + void Style::Clear() { Set( Color(), Color(), Color(), false, 0, 0, 0 ); @@ -1384,7 +1429,7 @@ drawinglayer::primitive2d::Primitive2DSequence CreateClippedBorderPrimitives ( rBorder.GetColorSecn().getBColor(), rBorder.GetColorPrim().getBColor(), rBorder.GetColorGap().getBColor(), - rBorder.UseGapColor(), rBorder.Type() ); + rBorder.UseGapColor(), rBorder.Type(), rBorder.Scale() ); return aSequence; } @@ -1412,7 +1457,7 @@ drawinglayer::primitive2d::Primitive2DSequence CreateBorderPrimitives( rBorder.GetColorSecn().getBColor(), rBorder.GetColorPrim().getBColor(), rBorder.GetColorGap().getBColor(), - rBorder.UseGapColor(), rBorder.Type() ); + rBorder.UseGapColor(), rBorder.Type(), rBorder.Scale() ); return aSequence; } diff --git a/sw/source/core/layout/paintfrm.cxx b/sw/source/core/layout/paintfrm.cxx index d5ae1c877d22..a57df407d243 100644 --- a/sw/source/core/layout/paintfrm.cxx +++ b/sw/source/core/layout/paintfrm.cxx @@ -4757,16 +4757,10 @@ lcl_MakeBorderLine(SwRect const& rRect, ? lcl_GetExtent(0, pEndNeighbour) : lcl_GetExtent(pEndNeighbour, 0); - double const nLeftWidth = (isLeftOrTopBorder == isVertical) - ? rBorder.GetInWidth() : rBorder.GetOutWidth(); - double const nRightWidth = (isLeftOrTopBorder == isVertical) - ? rBorder.GetOutWidth() : rBorder.GetInWidth(); - Color const aLeftColor = (isLeftOrTopBorder == isVertical) - ? rBorder.GetColorIn(isLeftOrTopBorder) - : rBorder.GetColorOut(isLeftOrTopBorder); - Color const aRightColor = (isLeftOrTopBorder == isVertical) - ? rBorder.GetColorOut(isLeftOrTopBorder) - : rBorder.GetColorIn(isLeftOrTopBorder); + double const nLeftWidth = rBorder.GetOutWidth(); + double const nRightWidth = rBorder.GetInWidth(); + Color const aLeftColor = rBorder.GetColorOut(isLeftOrTopBorder); + Color const aRightColor = rBorder.GetColorIn(isLeftOrTopBorder); ::rtl::Reference<BorderLinePrimitive2D> const xLine = new BorderLinePrimitive2D( diff --git a/vcl/source/gdi/outdev6.cxx b/vcl/source/gdi/outdev6.cxx index 9d2e355a375d..b51605747a80 100644 --- a/vcl/source/gdi/outdev6.cxx +++ b/vcl/source/gdi/outdev6.cxx @@ -42,16 +42,49 @@ #include <math.h> -// ======================================================================== +namespace { -DBG_NAMEEX( OutputDevice ) +/** + * Perform a safe approximation of a polygon from double-precision + * coordinates to integer coordinates, to ensure that it has at least 2 + * pixels in both X and Y directions. + */ +Polygon toPolygon( const basegfx::B2DPolygon& rPoly ) +{ + basegfx::B2DRange aRange = rPoly.getB2DRange(); + double fW = aRange.getWidth(), fH = aRange.getHeight(); + if (0.0 < fW && 0.0 < fH && (fW <= 1.0 || fH <= 1.0)) + { + // This polygon not empty but is too small to display. Approximate it + // with a rectangle large enough to be displayed. + double nX = aRange.getMinX(), nY = aRange.getMinY(); + double nW = std::max<double>(1.0, rtl::math::round(fW)); + double nH = std::max<double>(1.0, rtl::math::round(fH)); + + Polygon aTarget; + aTarget.Insert(0, Point(nX, nY)); + aTarget.Insert(1, Point(nX+nW, nY)); + aTarget.Insert(2, Point(nX+nW, nY+nH)); + aTarget.Insert(3, Point(nX, nY+nH)); + aTarget.Insert(4, Point(nX, nY)); + return aTarget; + } + return Polygon(rPoly); +} -// ------------------------------------------------------------------------ +PolyPolygon toPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPoly ) +{ + PolyPolygon aTarget; + for (sal_uInt32 i = 0; i < rPolyPoly.count(); ++i) + aTarget.Insert(toPolygon(rPolyPoly.getB2DPolygon(i))); + + return aTarget; +} + +} void OutputDevice::DrawGrid( const Rectangle& rRect, const Size& rDist, sal_uLong nFlags ) { - DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); - Rectangle aDstRect( PixelToLogic( Point() ), GetOutputSize() ); aDstRect.Intersection( rRect ); @@ -148,8 +181,6 @@ void OutputDevice::DrawGrid( const Rectangle& rRect, const Size& rDist, sal_uLon void OutputDevice::DrawTransparent( const basegfx::B2DPolyPolygon& rB2DPolyPoly, double fTransparency) { - DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); - // AW: Do NOT paint empty PolyPolygons if(!rB2DPolyPoly.count()) return; @@ -204,7 +235,7 @@ void OutputDevice::DrawTransparent( const basegfx::B2DPolyPolygon& rB2DPolyPoly, } // fallback to old polygon drawing if needed - DrawTransparent(PolyPolygon(rB2DPolyPoly), static_cast< sal_uInt16 >(fTransparency * 100.0)); + DrawTransparent(toPolyPolygon(rB2DPolyPoly), static_cast<sal_uInt16>(fTransparency * 100.0)); } // ------------------------------------------------------------------------ @@ -212,8 +243,6 @@ void OutputDevice::DrawTransparent( const basegfx::B2DPolyPolygon& rB2DPolyPoly, void OutputDevice::DrawTransparent( const PolyPolygon& rPolyPoly, sal_uInt16 nTransparencePercent ) { - DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); - // short circuit for drawing an opaque polygon if( (nTransparencePercent < 1) || ((mnDrawMode & DRAWMODE_NOTRANSPARENCY) != 0) ) { @@ -608,8 +637,6 @@ void OutputDevice::DrawTransparent( const PolyPolygon& rPolyPoly, void OutputDevice::DrawTransparent( const GDIMetaFile& rMtf, const Point& rPos, const Size& rSize, const Gradient& rTransparenceGradient ) { - DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); - const Color aBlack( COL_BLACK ); if( mpMetaFile ) |