[Libreoffice-commits] core.git: Branch 'distro/collabora/cp-4.1' - drawinglayer/source include/drawinglayer include/svtools svtools/source

Kohei Yoshida kohei.yoshida at collabora.com
Mon Jan 20 11:13:56 PST 2014


 drawinglayer/source/processor2d/vclpixelprocessor2d.cxx  |  319 ++++++++++++++-
 include/drawinglayer/processor2d/vclpixelprocessor2d.hxx |    4 
 include/svtools/borderhelper.hxx                         |    2 
 svtools/source/control/ctrlbox.cxx                       |    7 
 4 files changed, 330 insertions(+), 2 deletions(-)

New commits:
commit ac40f13eebde508cce14b67d59dd36c2c18ccf7b
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Sat Jan 18 18:17:52 2014 -0500

    fdo#73487: Better pixelization of lines for on-screen rendering.
    
    Conflicts:
    	drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
    	drawinglayer/source/processor2d/vclpixelprocessor2d.hxx
    
    Change-Id: I95d087a1f4841bfb7f665bcfebecd4c22c817958

diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
index 85e17d9..bb21cf2 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
 {
@@ -126,6 +156,287 @@ namespace drawinglayer
             return true;
         }
 
+        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 (fH <= 1.0 || bDouble)
+                        {
+                            // Draw it as a line.
+                            drawHairLine(
+                                mpOutputDevice, aRange.getMinX(), aRange.getMinY(), aRange.getMaxX(), aRange.getMinY(),
+                                aLineColor);
+
+                            if (bDouble)
+                            {
+                                drawHairLine(
+                                    mpOutputDevice, aRange.getMinX(), aRange.getMinY()+2.0, aRange.getMaxX(), aRange.getMinY()+2.0,
+                                    aLineColor);
+                            }
+
+                            return true;
+                        }
+                    }
+                    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 (fW <= 1.0 || bDouble)
+                        {
+                            // Draw it as a line.
+                            drawHairLine(
+                                mpOutputDevice, aRange.getMinX(), aRange.getMinY(), aRange.getMinX(), aRange.getMaxY(),
+                                aLineColor);
+
+                            if (bDouble)
+                            {
+                                drawHairLine(
+                                    mpOutputDevice, aRange.getMinX()+2.0, aRange.getMinY(), aRange.getMinX()+2.0, aRange.getMaxY(),
+                                    aLineColor);
+                            }
+                            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:
+                {
+                    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;
+                        }
+                    }
+                    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;
+                        }
+                    }
+
+                    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())
@@ -665,7 +976,11 @@ namespace drawinglayer
                     sal_uInt16 nAntiAliasing = mpOutputDevice->GetAntialiasing();
                     mpOutputDevice->SetAntialiasing(nAntiAliasing & ~ANTIALIASING_ENABLE_B2DDRAW);
 
-                    process(rCandidate.get2DDecomposition(getViewInformation2D()));
+                    const drawinglayer::primitive2d::BorderLinePrimitive2D& rBorder =
+                        static_cast<const drawinglayer::primitive2d::BorderLinePrimitive2D&>(rCandidate);
+
+                    if (!tryDrawBorderLinePrimitive2DDirect(rBorder))
+                        process(rCandidate.get2DDecomposition(getViewInformation2D()));
 
                     mpOutputDevice->SetAntialiasing(nAntiAliasing);
                     break;
diff --git a/include/drawinglayer/processor2d/vclpixelprocessor2d.hxx b/include/drawinglayer/processor2d/vclpixelprocessor2d.hxx
index ecd91b6..7e10de4 100644
--- a/include/drawinglayer/processor2d/vclpixelprocessor2d.hxx
+++ b/include/drawinglayer/processor2d/vclpixelprocessor2d.hxx
@@ -31,8 +31,11 @@
 
 namespace drawinglayer
 {
+    namespace primitive2d { class BorderLinePrimitive2D; }
+
     namespace processor2d
     {
+
         /** VclPixelProcessor2D class
 
             This processor derived from VclProcessor2D is the base class for rendering
@@ -53,6 +56,7 @@ namespace drawinglayer
 
             // some helpers to try direct paints (shortcuts)
             bool tryDrawPolyPolygonColorPrimitive2DDirect(const drawinglayer::primitive2d::PolyPolygonColorPrimitive2D& rSource, double fTransparency);
+            bool tryDrawBorderLinePrimitive2DDirect(const drawinglayer::primitive2d::BorderLinePrimitive2D& rSource);
 
         public:
             /// constructor/destructor
diff --git a/include/svtools/borderhelper.hxx b/include/svtools/borderhelper.hxx
index dac540c..c405ba5 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 67336bd..ab78c4b 100644
--- a/svtools/source/control/ctrlbox.cxx
+++ b/svtools/source/control/ctrlbox.cxx
@@ -638,6 +638,13 @@ namespace svtools
         return aPattern;
     }
 
+    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);


More information about the Libreoffice-commits mailing list