From 02da9f7a917ffc68dfe7a44c8d03b272cb5bfc18 Mon Sep 17 00:00:00 2001 From: Armin Le Grand Date: Fri, 10 May 2013 08:48:11 +0000 Subject: Resolves: #i110384# added better fat line rendering where possible (cherry picked from commit 144eb666b72516ef78c15424087800dff1be5cfd) Conflicts: drawinglayer/inc/drawinglayer/processor2d/vclpixelprocessor2d.hxx drawinglayer/inc/drawinglayer/processor2d/vclprocessor2d.hxx vcl/inc/vcl/outdev.hxx Change-Id: I89f378a4d7a8311b8922f10acff66b000a20a4b7 --- .../source/processor2d/vclpixelprocessor2d.cxx | 257 +++++++++++++++++++-- .../source/processor2d/vclpixelprocessor2d.hxx | 14 ++ drawinglayer/source/processor2d/vclprocessor2d.cxx | 80 ------- drawinglayer/source/processor2d/vclprocessor2d.hxx | 2 - 4 files changed, 248 insertions(+), 105 deletions(-) (limited to 'drawinglayer') diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx index a320d1a88c78..a486dd84b578 100644 --- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx @@ -92,6 +92,141 @@ namespace drawinglayer mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() & ~ANTIALIASING_ENABLE_B2DDRAW); } + 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; + } + + bool VclPixelProcessor2D::tryDrawPolygonHairlinePrimitive2DDirect(const drawinglayer::primitive2d::PolygonHairlinePrimitive2D& rSource, double fTransparency) + { + basegfx::B2DPolygon aLocalPolygon(rSource.getB2DPolygon()); + + if(!aLocalPolygon.count()) + { + // no geometry, done + return true; + } + + const basegfx::BColor aLineColor(maBColorModifierStack.getModifiedColor(rSource.getBColor())); + + mpOutputDevice->SetFillColor(); + mpOutputDevice->SetLineColor(Color(aLineColor)); + aLocalPolygon.transform(maCurrentTransformation); + + // try drawing; if it did not work, use standard fallback + if(mpOutputDevice->TryDrawPolyLineDirect( + aLocalPolygon, + 0.0, + fTransparency)) + { + return true; + } + + return false; + } + + bool VclPixelProcessor2D::tryDrawPolygonStrokePrimitive2DDirect(const drawinglayer::primitive2d::PolygonStrokePrimitive2D& rSource, double fTransparency) + { + basegfx::B2DPolygon aLocalPolygon(rSource.getB2DPolygon()); + + if(!aLocalPolygon.count()) + { + // no geometry, done + return true; + } + + aLocalPolygon = basegfx::tools::simplifyCurveSegments(aLocalPolygon); + basegfx::B2DPolyPolygon aHairLinePolyPolygon; + + if(rSource.getStrokeAttribute().isDefault() || 0.0 == rSource.getStrokeAttribute().getFullDotDashLen()) + { + // no line dashing, just copy + aHairLinePolyPolygon.append(aLocalPolygon); + } + else + { + // apply LineStyle + basegfx::tools::applyLineDashing( + aLocalPolygon, + rSource.getStrokeAttribute().getDotDashArray(), + &aHairLinePolyPolygon, + 0, + rSource.getStrokeAttribute().getFullDotDashLen()); + } + + if(!aHairLinePolyPolygon.count()) + { + // no geometry, done + return true; + } + + const basegfx::BColor aLineColor( + maBColorModifierStack.getModifiedColor( + rSource.getLineAttribute().getColor())); + + mpOutputDevice->SetFillColor(); + mpOutputDevice->SetLineColor(Color(aLineColor)); + aHairLinePolyPolygon.transform(maCurrentTransformation); + + double fLineWidth(rSource.getLineAttribute().getWidth()); + + if(basegfx::fTools::more(fLineWidth, 0.0)) + { + basegfx::B2DVector aLineWidth(fLineWidth, 0.0); + + aLineWidth = maCurrentTransformation * aLineWidth; + fLineWidth = aLineWidth.getLength(); + } + + bool bHasPoints(false); + bool bTryWorked(false); + + for(sal_uInt32 a(0); a < aHairLinePolyPolygon.count(); a++) + { + const basegfx::B2DPolygon aSingle(aHairLinePolyPolygon.getB2DPolygon(a)); + + if(aSingle.count()) + { + bHasPoints = true; + + if(mpOutputDevice->TryDrawPolyLineDirect( + aSingle, + fLineWidth, + fTransparency, + rSource.getLineAttribute().getLineJoin(), + rSource.getLineAttribute().getLineCap())) + { + bTryWorked = true; + } + } + } + + if(!bTryWorked && !bHasPoints) + { + // no geometry despite try + bTryWorked = true; + } + + return bTryWorked; + } + void VclPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate) { switch(rCandidate.getPrimitive2DID()) @@ -169,8 +304,17 @@ namespace drawinglayer } case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D : { + // try to use directly + const primitive2d::PolygonHairlinePrimitive2D& rPolygonHairlinePrimitive2D = static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate); + static bool bAllowed(true); + + if(bAllowed && tryDrawPolygonHairlinePrimitive2DDirect(rPolygonHairlinePrimitive2D, 0.0)) + { + break; + } + // direct draw of hairline - RenderPolygonHairlinePrimitive2D(static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate), true); + RenderPolygonHairlinePrimitive2D(rPolygonHairlinePrimitive2D, true); break; } case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D : @@ -240,8 +384,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 : @@ -313,25 +502,41 @@ namespace drawinglayer // single transparent PolyPolygon identified, use directly const primitive2d::PolyPolygonColorPrimitive2D* pPoPoColor = static_cast< const primitive2d::PolyPolygonColorPrimitive2D* >(pBasePrimitive); OSL_ENSURE(pPoPoColor, "OOps, PrimitiveID and PrimitiveType do not match (!)"); - const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(pPoPoColor->getBColor())); - mpOutputDevice->SetFillColor(Color(aPolygonColor)); - mpOutputDevice->SetLineColor(); - - basegfx::B2DPolyPolygon aLocalPolyPolygon(pPoPoColor->getB2DPolyPolygon()); - aLocalPolyPolygon.transform(maCurrentTransformation); - - mpOutputDevice->DrawTransparent(aLocalPolyPolygon, rUniTransparenceCandidate.getTransparence()); - bDrawTransparentUsed = true; + bDrawTransparentUsed = tryDrawPolyPolygonColorPrimitive2DDirect(*pPoPoColor, rUniTransparenceCandidate.getTransparence()); + break; + } + case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D: + { + // single transparent PolygonHairlinePrimitive2D identified, use directly + const primitive2d::PolygonHairlinePrimitive2D* pPoHair = static_cast< const primitive2d::PolygonHairlinePrimitive2D* >(pBasePrimitive); + OSL_ENSURE(pPoHair, "OOps, PrimitiveID and PrimitiveType do not match (!)"); + + // do no tallow by default - problem is that self-overlapping parts of this geometry will + // not be in a all-same transparency but will already alpha-cover themselves with blending. + // This is not what the UnifiedTransparencePrimitive2D defines: It requires all it's + // content to be uniformely transparent. + // For hairline the effect is pretty minimal, but still not correct. + static bool bAllowed(false); + + bDrawTransparentUsed = bAllowed && tryDrawPolygonHairlinePrimitive2DDirect(*pPoHair, rUniTransparenceCandidate.getTransparence()); + break; + } + case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D: + { + // single transparent PolygonStrokePrimitive2D identified, use directly + const primitive2d::PolygonStrokePrimitive2D* pPoStroke = static_cast< const primitive2d::PolygonStrokePrimitive2D* >(pBasePrimitive); + OSL_ENSURE(pPoStroke, "OOps, PrimitiveID and PrimitiveType do not match (!)"); + + // do no tallow by default - problem is that self-overlapping parts of this geometry will + // not be in a all-same transparency but will already alpha-cover themselves with blending. + // This is not what the UnifiedTransparencePrimitive2D defines: It requires all it's + // content to be uniformely transparent. + // To check, acitvate and draw a wide transparent self-crossing line/curve + static bool bAllowed(false); + + bDrawTransparentUsed = bAllowed && tryDrawPolygonStrokePrimitive2DDirect(*pPoStroke, rUniTransparenceCandidate.getTransparence()); break; } - // #i# need to wait for #i101378# which is in CWS vcl112 to directly paint transparent hairlines - //case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D: - //{ - // // single transparent PolygonHairlinePrimitive2D identified, use directly - // const primitive2d::PolygonHairlinePrimitive2D* pPoHair = static_cast< const primitive2d::PolygonHairlinePrimitive2D* >(pBasePrimitive); - // OSL_ENSURE(pPoHair, "OOps, PrimitiveID and PrimitiveType do not match (!)"); - // break; - //} } } } @@ -431,6 +636,14 @@ namespace drawinglayer } case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D: { + // try to use directly + const primitive2d::PolygonStrokePrimitive2D& rPolygonStrokePrimitive2D = static_cast< const primitive2d::PolygonStrokePrimitive2D& >(rCandidate); + + if(tryDrawPolygonStrokePrimitive2DDirect(rPolygonStrokePrimitive2D, 0.0)) + { + break; + } + // the stroke primitive may be decomposed to filled polygons. To keep // evtl. set DrawModes aka DRAWMODE_BLACKLINE, DRAWMODE_GRAYLINE, // DRAWMODE_GHOSTEDLINE, DRAWMODE_WHITELINE or DRAWMODE_SETTINGSLINE @@ -459,9 +672,7 @@ namespace drawinglayer // as filled polygons is geometrically corret but looks wrong since polygon filling avoids // the right and bottom pixels. The used method evaluates that and takes the correct action, // including calling recursively with decomposition if line is wide enough - const primitive2d::PolygonStrokePrimitive2D& rPolygonStrokePrimitive = static_cast< const primitive2d::PolygonStrokePrimitive2D& >(rCandidate); - - RenderPolygonStrokePrimitive2D(rPolygonStrokePrimitive); + RenderPolygonStrokePrimitive2D(rPolygonStrokePrimitive2D); } // restore DrawMode diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.hxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.hxx index 4ef981320555..2b4128925a91 100644 --- a/drawinglayer/source/processor2d/vclpixelprocessor2d.hxx +++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.hxx @@ -25,6 +25,15 @@ #include "vclprocessor2d.hxx" #include +////////////////////////////////////////////////////////////////////////////// +// predefines + +namespace drawinglayer { namespace primitive2d { + class PolyPolygonColorPrimitive2D; + class PolygonHairlinePrimitive2D; + class PolygonStrokePrimitive2D; +}} + ////////////////////////////////////////////////////////////////////////////// namespace drawinglayer @@ -46,6 +55,11 @@ namespace drawinglayer */ virtual void processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate); + // some helpers to try direct paints (shortcuts) + 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); + public: /// constructor/destructor VclPixelProcessor2D( diff --git a/drawinglayer/source/processor2d/vclprocessor2d.cxx b/drawinglayer/source/processor2d/vclprocessor2d.cxx index d0fc7b3f074a..d1b85ff9618f 100644 --- a/drawinglayer/source/processor2d/vclprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclprocessor2d.cxx @@ -782,86 +782,6 @@ namespace drawinglayer } } - // direct draw of PolyPolygon with color - void VclProcessor2D::RenderPolyPolygonColorPrimitive2D(const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate) - { - const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor())); - mpOutputDevice->SetFillColor(Color(aPolygonColor)); - mpOutputDevice->SetLineColor(); - - basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon()); - aLocalPolyPolygon.transform(maCurrentTransformation); - - static bool bCheckTrapezoidDecomposition(false); - static bool bShowOutlinesThere(false); - if(bCheckTrapezoidDecomposition) - { - // clip against discrete ViewPort - const basegfx::B2DRange& rDiscreteViewport = getViewInformation2D().getDiscreteViewport(); - aLocalPolyPolygon = basegfx::tools::clipPolyPolygonOnRange( - aLocalPolyPolygon, rDiscreteViewport, true, false); - - if(aLocalPolyPolygon.count()) - { - // subdivide - aLocalPolyPolygon = basegfx::tools::adaptiveSubdivideByDistance( - aLocalPolyPolygon, 0.5); - - // trapezoidize - basegfx::B2DTrapezoidVector aB2DTrapezoidVector; - basegfx::tools::trapezoidSubdivide(aB2DTrapezoidVector, aLocalPolyPolygon); - - const sal_uInt32 nCount(aB2DTrapezoidVector.size()); - - if(nCount) - { - basegfx::BColor aInvPolygonColor(aPolygonColor); - aInvPolygonColor.invert(); - - for(sal_uInt32 a(0); a < nCount; a++) - { - const basegfx::B2DPolygon aTempPolygon(aB2DTrapezoidVector[a].getB2DPolygon()); - - if(bShowOutlinesThere) - { - mpOutputDevice->SetFillColor(Color(aPolygonColor)); - mpOutputDevice->SetLineColor(); - } - - mpOutputDevice->DrawPolygon(aTempPolygon); - - if(bShowOutlinesThere) - { - mpOutputDevice->SetFillColor(); - mpOutputDevice->SetLineColor(Color(aInvPolygonColor)); - mpOutputDevice->DrawPolyLine(aTempPolygon, 0.0); - } - } - } - } - } - else - { - mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon); - - if(mnPolygonStrokePrimitive2D - && getOptionsDrawinglayer().IsAntiAliasing() - && (mpOutputDevice->GetAntialiasing() & ANTIALIASING_ENABLE_B2DDRAW)) - { - // 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 - mpOutputDevice->SetFillColor(); - mpOutputDevice->SetLineColor(Color(aPolygonColor)); - const sal_uInt32 nCount(aLocalPolyPolygon.count()); - - for(sal_uInt32 a(0); a < nCount; a++) - { - mpOutputDevice->DrawPolyLine(aLocalPolyPolygon.getB2DPolygon(a), 0.0); - } - } - } - } - // mask group. Force output to VDev and create mask from given mask void VclProcessor2D::RenderMaskPrimitive2DPixel(const primitive2d::MaskPrimitive2D& rMaskCandidate) { diff --git a/drawinglayer/source/processor2d/vclprocessor2d.hxx b/drawinglayer/source/processor2d/vclprocessor2d.hxx index b8d984ea9967..f1fccb368abd 100644 --- a/drawinglayer/source/processor2d/vclprocessor2d.hxx +++ b/drawinglayer/source/processor2d/vclprocessor2d.hxx @@ -38,7 +38,6 @@ namespace drawinglayer { namespace primitive2d { class FillGraphicPrimitive2D; class PolyPolygonGradientPrimitive2D; class PolyPolygonGraphicPrimitive2D; - class PolyPolygonColorPrimitive2D; class MetafilePrimitive2D; class MaskPrimitive2D; class UnifiedTransparencePrimitive2D; @@ -95,7 +94,6 @@ namespace drawinglayer void RenderBitmapPrimitive2D(const primitive2d::BitmapPrimitive2D& rBitmapCandidate); void RenderFillGraphicPrimitive2D(const primitive2d::FillGraphicPrimitive2D& rFillBitmapCandidate); void RenderPolyPolygonGraphicPrimitive2D(const primitive2d::PolyPolygonGraphicPrimitive2D& rPolygonCandidate); - void RenderPolyPolygonColorPrimitive2D(const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate); void RenderMaskPrimitive2DPixel(const primitive2d::MaskPrimitive2D& rMaskCandidate); void RenderModifiedColorPrimitive2D(const primitive2d::ModifiedColorPrimitive2D& rModifiedCandidate); void RenderUnifiedTransparencePrimitive2D(const primitive2d::UnifiedTransparencePrimitive2D& rTransCandidate); -- cgit