diff options
author | Kohei Yoshida <kohei.yoshida@collabora.com> | 2014-01-13 13:18:25 -0500 |
---|---|---|
committer | Kohei Yoshida <kohei.yoshida@collabora.com> | 2014-01-17 11:30:50 -0500 |
commit | 98633cd8fc3fe7e2e5176c3329cf287c913471d7 (patch) | |
tree | 2adccf479c20a305bcff9e7efb37df22cf2ed081 /drawinglayer | |
parent | 6b07d7b52c96cf66f4db01b76f92c9d81cc71eba (diff) |
fdo#73487: Overhaul cell borders to make them look sane.
Change-Id: I207db352e017214f61baa947ef8f34662c724087
Diffstat (limited to 'drawinglayer')
3 files changed, 180 insertions, 119 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 a626d60a4d6e..85e17d9de855 100644 --- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx @@ -104,6 +104,28 @@ namespace drawinglayer mpOutputDevice->SetAntialiasing(m_pImpl->m_nOrigAntiAliasing); } + bool VclPixelProcessor2D::tryDrawPolyPolygonColorPrimitive2DDirect(const drawinglayer::primitive2d::PolyPolygonColorPrimitive2D& rSource, double fTransparency) + { + basegfx::B2DPolyPolygon aLocalPolyPolygon(rSource.getB2DPolyPolygon()); + + if(!aLocalPolyPolygon.count()) + { + // no geometry, done + return true; + } + + const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rSource.getBColor())); + + mpOutputDevice->SetFillColor(Color(aPolygonColor)); + mpOutputDevice->SetLineColor(); + aLocalPolyPolygon.transform(maCurrentTransformation); + mpOutputDevice->DrawTransparent( + aLocalPolyPolygon, + fTransparency); + + return true; + } + void VclPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate) { switch(rCandidate.getPrimitive2DID()) @@ -211,8 +233,53 @@ namespace drawinglayer } case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D : { - // direct draw of PolyPolygon with color - RenderPolyPolygonColorPrimitive2D(static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate)); + // try to use directly + const primitive2d::PolyPolygonColorPrimitive2D& rPolyPolygonColorPrimitive2D = static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate); + basegfx::B2DPolyPolygon aLocalPolyPolygon; + static bool bAllowed(true); + + if(bAllowed && tryDrawPolyPolygonColorPrimitive2DDirect(rPolyPolygonColorPrimitive2D, 0.0)) + { + // okay, done. In this case no gaps should have to be repaired, too + } + else + { + // direct draw of PolyPolygon with color + const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolyPolygonColorPrimitive2D.getBColor())); + + mpOutputDevice->SetFillColor(Color(aPolygonColor)); + mpOutputDevice->SetLineColor(); + aLocalPolyPolygon = rPolyPolygonColorPrimitive2D.getB2DPolyPolygon(); + aLocalPolyPolygon.transform(maCurrentTransformation); + mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon); + } + + // when AA is on and this filled polygons are the result of stroked line geometry, + // draw the geometry once extra as lines to avoid AA 'gaps' between partial polygons + // Caution: This is needed in both cases (!) + if(mnPolygonStrokePrimitive2D + && getOptionsDrawinglayer().IsAntiAliasing() + && (mpOutputDevice->GetAntialiasing() & ANTIALIASING_ENABLE_B2DDRAW)) + { + const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolyPolygonColorPrimitive2D.getBColor())); + sal_uInt32 nCount(aLocalPolyPolygon.count()); + + if(!nCount) + { + aLocalPolyPolygon = rPolyPolygonColorPrimitive2D.getB2DPolyPolygon(); + aLocalPolyPolygon.transform(maCurrentTransformation); + nCount = aLocalPolyPolygon.count(); + } + + mpOutputDevice->SetFillColor(); + mpOutputDevice->SetLineColor(Color(aPolygonColor)); + + for(sal_uInt32 a(0); a < nCount; a++) + { + mpOutputDevice->DrawPolyLine(aLocalPolyPolygon.getB2DPolygon(a), 0.0); + } + } + break; } case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D : @@ -590,6 +657,19 @@ 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); + + process(rCandidate.get2DDecomposition(getViewInformation2D())); + + mpOutputDevice->SetAntialiasing(nAntiAliasing); + break; + } default : { // process recursively |