[Libreoffice-commits] core.git: 6 commits - include/vcl sd/source vcl/inc vcl/opengl vcl/Package_opengl.mk vcl/source

Luboš Luňák l.lunak at collabora.com
Mon Jan 19 03:22:29 PST 2015


 include/vcl/bitmap.hxx                            |    9 +
 sd/source/ui/presenter/PresenterPreviewCache.cxx  |    4 
 sd/source/ui/slidesorter/view/SlideSorterView.cxx |    4 
 vcl/Package_opengl.mk                             |    2 
 vcl/inc/opengl/program.hxx                        |    2 
 vcl/inc/opengl/salbmp.hxx                         |    1 
 vcl/inc/openglgdiimpl.hxx                         |   10 -
 vcl/opengl/areaScaleFastFragmentShader.glsl       |   43 +++++
 vcl/opengl/areaScaleFragmentShader.glsl           |  131 +++++++++++++++
 vcl/opengl/gdiimpl.cxx                            |  181 +++++++++++++---------
 vcl/opengl/program.cxx                            |   12 +
 vcl/opengl/scale.cxx                              |   76 +++++++++
 vcl/source/gdi/bitmap3.cxx                        |    6 
 13 files changed, 409 insertions(+), 72 deletions(-)

New commits:
commit e437b13008f458bde2977e754214babdfd210558
Author: Luboš Luňák <l.lunak at collabora.com>
Date:   Sun Jan 18 22:49:22 2015 +0100

    try to handle properly fillcolor != linecolor in opengl polypolygons drawing
    
    Change-Id: I962416f48fdb348d8a3d95edf747cfe2f1c929c9

diff --git a/vcl/opengl/gdiimpl.cxx b/vcl/opengl/gdiimpl.cxx
index 50d9ec1..8a40f1a 100644
--- a/vcl/opengl/gdiimpl.cxx
+++ b/vcl/opengl/gdiimpl.cxx
@@ -1191,7 +1191,7 @@ void OpenGLSalGraphicsImpl::drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32*
         }
     }
 
-    if( UseSolidAA( mnLineColor ) )
+    if( mnLineColor != mnFillColor && UseSolidAA( mnLineColor ) )
     {
         // TODO Use glMultiDrawElements or primitive restart
         for( sal_uInt32 i = 0; i < nPoly; i++ )
@@ -1212,6 +1212,20 @@ bool OpenGLSalGraphicsImpl::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rP
     if( UseSolid( mnFillColor, fTransparency ) )
         DrawPolyPolygon( rPolyPolygon );
 
+    if( mnLineColor != mnFillColor && UseSolidAA( mnLineColor ) )
+    {
+        for( sal_uInt32 i = 0; i < rPolyPolygon.count(); i++ )
+        {
+            const basegfx::B2DPolygon& polygon = rPolyPolygon.getB2DPolygon( i );
+            for( sal_uInt32 j = 0; j < polygon.count(); ++j )
+            {
+                const basegfx::B2DPoint& rPt1 = polygon.getB2DPoint( j );
+                const basegfx::B2DPoint& rPt2 = polygon.getB2DPoint(( j + 1 ) % polygon.count());
+                DrawLineAA( rPt1.getX(), rPt1.getY(), rPt2.getX(), rPt2.getY());
+            }
+        }
+    }
+
     PostDraw();
 
     return true;
commit 90630adcc119dd5adda635146312910e6eb3c0df
Author: Luboš Luňák <l.lunak at collabora.com>
Date:   Sun Jan 18 22:42:06 2015 +0100

    draw polypolygons properly in opengl backend
    
    The polygons that make the polypolygon cannot be simply drawn one onto another,
    because if they overlap, it's actually xor (as used e.g. for drawing the border
    when editing a text box Impress, which without this fix just made it a full
    rectangle instead of a frame).
    
    Change-Id: I67c7f6448fb3ee0f9742a2299c612515abff68d8

diff --git a/vcl/inc/openglgdiimpl.hxx b/vcl/inc/openglgdiimpl.hxx
index ce49e96..7bb4532 100644
--- a/vcl/inc/openglgdiimpl.hxx
+++ b/vcl/inc/openglgdiimpl.hxx
@@ -89,7 +89,7 @@ public:
     void DrawEdgeAA( double nX1, double nY1, double nX2, double nY2 );
     void DrawConvexPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry, bool blockAA = false );
     void DrawConvexPolygon( const Polygon& rPolygon, bool blockAA = false );
-    void DrawTrapezoid( const basegfx::B2DTrapezoid& trapezoid );
+    void DrawTrapezoid( const basegfx::B2DTrapezoid& trapezoid, bool blockAA = false );
     void DrawRect( long nX, long nY, long nWidth, long nHeight );
     void DrawRect( const Rectangle& rRect );
     void DrawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry );
diff --git a/vcl/opengl/gdiimpl.cxx b/vcl/opengl/gdiimpl.cxx
index c9b7c0b..50d9ec1 100644
--- a/vcl/opengl/gdiimpl.cxx
+++ b/vcl/opengl/gdiimpl.cxx
@@ -718,7 +718,7 @@ void OpenGLSalGraphicsImpl::DrawConvexPolygon( const Polygon& rPolygon, bool blo
     }
 }
 
-void OpenGLSalGraphicsImpl::DrawTrapezoid( const basegfx::B2DTrapezoid& trapezoid )
+void OpenGLSalGraphicsImpl::DrawTrapezoid( const basegfx::B2DTrapezoid& trapezoid, bool blockAA )
 {
     const basegfx::B2DPolygon& rPolygon = trapezoid.getB2DPolygon();
     sal_uInt16 nPoints = rPolygon.count();
@@ -735,7 +735,7 @@ void OpenGLSalGraphicsImpl::DrawTrapezoid( const basegfx::B2DTrapezoid& trapezoi
     mpProgram->SetVertices( &aVertices[0] );
     glDrawArrays( GL_TRIANGLE_FAN, 0, nPoints );
 
-    if( mrParent.getAntiAliasB2DDraw())
+    if( !blockAA && mrParent.getAntiAliasB2DDraw())
     {
         // Make the edges antialiased by drawing the edge lines again with AA.
         // TODO: If transparent drawing is set up, drawing the lines themselves twice
@@ -805,56 +805,15 @@ void OpenGLSalGraphicsImpl::DrawPolygon( sal_uInt32 nPoints, const SalPoint* pPt
 
 void OpenGLSalGraphicsImpl::DrawPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPolygon, bool blockAA )
 {
-    ::std::vector< GLfloat > aVertices;
-    GLfloat nWidth = GetWidth();
-    GLfloat nHeight = GetHeight();
     const ::basegfx::B2DPolyPolygon& aSimplePolyPolygon = ::basegfx::tools::solveCrossovers( rPolyPolygon );
-
-    for( sal_uInt32 i = 0; i < aSimplePolyPolygon.count(); i++ )
+    basegfx::B2DTrapezoidVector aB2DTrapVector;
+    basegfx::tools::trapezoidSubdivide( aB2DTrapVector, aSimplePolyPolygon );
+    // draw tesselation result
+    if( aB2DTrapVector.size())
     {
-        const basegfx::B2DPolygon& rPolygon( aSimplePolyPolygon.getB2DPolygon( i ) );
-        const ::basegfx::B2DPolygon& aResult(
-            ::basegfx::triangulator::triangulate( rPolygon ) );
-
-        for( sal_uInt32 j = 0; j < aResult.count(); j++ )
-        {
-            const ::basegfx::B2DPoint& rPt( aResult.getB2DPoint( j ) );
-            aVertices.push_back( 2 * rPt.getX() / nWidth - 1.0f );
-            aVertices.push_back( 1.0f - 2 * rPt.getY() / nHeight );
-        }
+        for( size_t i = 0; i < aB2DTrapVector.size(); ++i )
+            DrawTrapezoid( aB2DTrapVector[ i ], blockAA );
     }
-
-    mpProgram->SetVertices( aVertices.data() );
-    glDrawArrays( GL_TRIANGLES, 0, aVertices.size() / 2 );
-
-    if( !blockAA && mrParent.getAntiAliasB2DDraw())
-    {
-        // Make the edges antialiased by drawing the edge lines again with AA.
-        // TODO: If transparent drawing is set up, drawing the lines themselves twice
-        // may be a problem, if that is a real problem, the polygon areas itself needs to be
-        // masked out for this or something.
-#ifdef DBG_UTIL
-        assert( mProgramIsSolidColor );
-#endif
-        SalColor lastSolidColor = mProgramSolidColor;
-        double lastSolidTransparency = mProgramSolidTransparency;
-        if( UseSolidAA( lastSolidColor, lastSolidTransparency ))
-        {
-            for( sal_uInt32 i = 0; i < aSimplePolyPolygon.count(); i++ )
-            {
-                const basegfx::B2DPolygon& rPolygon( aSimplePolyPolygon.getB2DPolygon( i ) );
-                for( sal_uInt32 j = 0; j < rPolygon.count(); j++ )
-                {
-                    const ::basegfx::B2DPoint& rPt1( rPolygon.getB2DPoint( j ) );
-                    const ::basegfx::B2DPoint& rPt2( rPolygon.getB2DPoint(( j + 1 ) % rPolygon.count()) );
-                    DrawEdgeAA( rPt1.getX(), rPt1.getY(), rPt2.getX(), rPt2.getY());
-                }
-            }
-            UseSolid( lastSolidColor, lastSolidTransparency );
-        }
-    }
-
-    CHECK_GL_ERROR();
 }
 
 void OpenGLSalGraphicsImpl::DrawRegionBand( const RegionBand& rRegion )
@@ -1212,8 +1171,24 @@ void OpenGLSalGraphicsImpl::drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32*
 
     if( UseSolid( mnFillColor ) )
     {
-        for( sal_uInt32 i = 0; i < nPoly; i++ )
-            DrawPolygon( pPoints[i], pPtAry[i] );
+        if( nPoly == 1 )
+        {
+            for( sal_uInt32 i = 0; i < nPoly; i++ )
+                DrawPolygon( pPoints[i], pPtAry[i] );
+        }
+        else
+        {
+            basegfx::B2DPolyPolygon polyPolygon;
+            for( sal_uInt32 i = 0; i < nPoly; ++i )
+            {
+                basegfx::B2DPolygon polygon;
+                for( sal_uInt32 j = 0; j < pPoints[ i ]; ++j )
+                    polygon.append( basegfx::B2DPoint( pPtAry[i][j].mnX, pPtAry[i][j].mnY ) );
+                polygon.setClosed( true );
+                polyPolygon.append( polygon );
+            }
+            DrawPolyPolygon( polyPolygon );
+        }
     }
 
     if( UseSolidAA( mnLineColor ) )
@@ -1235,13 +1210,7 @@ bool OpenGLSalGraphicsImpl::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rP
     PreDraw();
 
     if( UseSolid( mnFillColor, fTransparency ) )
-    {
-        for( sal_uInt32 i = 0; i < rPolyPolygon.count(); i++ )
-        {
-            const ::basegfx::B2DPolyPolygon aOnePoly( rPolyPolygon.getB2DPolygon( i ) );
-            DrawPolyPolygon( aOnePoly );
-        }
-    }
+        DrawPolyPolygon( rPolyPolygon );
 
     PostDraw();
 
commit b8b37e6ef29d7868e3e4a41df5a0a97b4297d77b
Author: Luboš Luňák <l.lunak at collabora.com>
Date:   Sun Jan 18 19:00:32 2015 +0100

    fix opengl hairline special casing
    
    Apparently polygons can consist of curves too.
    
    Change-Id: Ie35861e6d182e4bd4ac0523e78a90618c96f09a6

diff --git a/vcl/inc/openglgdiimpl.hxx b/vcl/inc/openglgdiimpl.hxx
index 4b50469..ce49e96 100644
--- a/vcl/inc/openglgdiimpl.hxx
+++ b/vcl/inc/openglgdiimpl.hxx
@@ -35,6 +35,11 @@
 class SalFrame;
 class SalVirtualDevice;
 
+namespace basegfx
+{
+class B2DTrapezoid;
+};
+
 class VCL_PLUGIN_PUBLIC OpenGLSalGraphicsImpl : public SalGraphicsImpl
 {
 protected:
@@ -84,6 +89,7 @@ public:
     void DrawEdgeAA( double nX1, double nY1, double nX2, double nY2 );
     void DrawConvexPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry, bool blockAA = false );
     void DrawConvexPolygon( const Polygon& rPolygon, bool blockAA = false );
+    void DrawTrapezoid( const basegfx::B2DTrapezoid& trapezoid );
     void DrawRect( long nX, long nY, long nWidth, long nHeight );
     void DrawRect( const Rectangle& rRect );
     void DrawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry );
diff --git a/vcl/opengl/gdiimpl.cxx b/vcl/opengl/gdiimpl.cxx
index bbbe5c9..c9b7c0b 100644
--- a/vcl/opengl/gdiimpl.cxx
+++ b/vcl/opengl/gdiimpl.cxx
@@ -718,6 +718,47 @@ void OpenGLSalGraphicsImpl::DrawConvexPolygon( const Polygon& rPolygon, bool blo
     }
 }
 
+void OpenGLSalGraphicsImpl::DrawTrapezoid( const basegfx::B2DTrapezoid& trapezoid )
+{
+    const basegfx::B2DPolygon& rPolygon = trapezoid.getB2DPolygon();
+    sal_uInt16 nPoints = rPolygon.count();
+    std::vector<GLfloat> aVertices(nPoints * 2);
+    sal_uInt32 i, j;
+
+    for( i = 0, j = 0; i < nPoints; i++, j += 2 )
+    {
+        const basegfx::B2DPoint& rPt = rPolygon.getB2DPoint( i );
+        aVertices[j] = (2 * rPt.getX()) / GetWidth() - 1.0;
+        aVertices[j+1] = 1.0 - (2 * rPt.getY() / GetHeight());
+    }
+
+    mpProgram->SetVertices( &aVertices[0] );
+    glDrawArrays( GL_TRIANGLE_FAN, 0, nPoints );
+
+    if( mrParent.getAntiAliasB2DDraw())
+    {
+        // Make the edges antialiased by drawing the edge lines again with AA.
+        // TODO: If transparent drawing is set up, drawing the lines themselves twice
+        // may be a problem, if that is a real problem, the polygon areas itself needs to be
+        // masked out for this or something.
+#ifdef DBG_UTIL
+        assert( mProgramIsSolidColor );
+#endif
+        SalColor lastSolidColor = mProgramSolidColor;
+        double lastSolidTransparency = mProgramSolidTransparency;
+        if( UseSolidAA( lastSolidColor, lastSolidTransparency ))
+        {
+            for( i = 0; i < nPoints; ++i )
+            {
+                const basegfx::B2DPoint& rPt1 = rPolygon.getB2DPoint( i );
+                const basegfx::B2DPoint& rPt2 = rPolygon.getB2DPoint(( i + 1 ) % nPoints );
+                DrawEdgeAA( rPt1.getX(), rPt1.getY(), rPt2.getX(), rPt2.getY());
+            }
+            UseSolid( lastSolidColor, lastSolidTransparency );
+        }
+    }
+}
+
 void OpenGLSalGraphicsImpl::DrawRect( long nX, long nY, long nWidth, long nHeight )
 {
     long nX1( nX );
@@ -1245,17 +1286,19 @@ bool OpenGLSalGraphicsImpl::drawPolyLine(
     if( bIsHairline )
     {
         // hairlines can be drawn in a simpler way (the linejoin and linecap styles can be ignored)
-        PreDraw();
-        if( UseSolidAA( mnLineColor, fTransparency ))
+        basegfx::B2DTrapezoidVector aB2DTrapVector;
+        basegfx::tools::createLineTrapezoidFromB2DPolygon( aB2DTrapVector, aPolygon, rLineWidth.getX() );
+        // draw tesselation result
+        if( aB2DTrapVector.size())
         {
-            for( sal_uInt32 j = 0; j < rPolygon.count() - 1; j++ )
+            PreDraw();
+            if( UseSolid( mnLineColor, fTransparency ))
             {
-                const ::basegfx::B2DPoint& rPt1( rPolygon.getB2DPoint( j ) );
-                const ::basegfx::B2DPoint& rPt2( rPolygon.getB2DPoint(( j + 1 )) );
-                DrawLineAA( rPt1.getX(), rPt1.getY(), rPt2.getX(), rPt2.getY());
+                for( size_t i = 0; i < aB2DTrapVector.size(); ++i )
+                    DrawTrapezoid( aB2DTrapVector[ i ] );
             }
+            PostDraw();
         }
-        PostDraw();
         return true;
     }
 
commit 1f978c136e803a0ab75fad427cde90661ed1afac
Author: Luboš Luňák <l.lunak at collabora.com>
Date:   Sun Jan 18 18:58:20 2015 +0100

    use AA for convex polygons when needed too
    
    Change-Id: I8e66d369956a9bcf9c63c6eccad47d4b7a7eb67d

diff --git a/vcl/inc/openglgdiimpl.hxx b/vcl/inc/openglgdiimpl.hxx
index 2b815ee..4b50469 100644
--- a/vcl/inc/openglgdiimpl.hxx
+++ b/vcl/inc/openglgdiimpl.hxx
@@ -82,8 +82,8 @@ public:
     void DrawLineAA( double nX1, double nY1, double nX2, double nY2 );
     void DrawLinesAA( sal_uInt32 nPoints, const SalPoint* pPtAry, bool bClose );
     void DrawEdgeAA( double nX1, double nY1, double nX2, double nY2 );
-    void DrawConvexPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry );
-    void DrawConvexPolygon( const Polygon& rPolygon );
+    void DrawConvexPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry, bool blockAA = false );
+    void DrawConvexPolygon( const Polygon& rPolygon, bool blockAA = false );
     void DrawRect( long nX, long nY, long nWidth, long nHeight );
     void DrawRect( const Rectangle& rRect );
     void DrawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry );
diff --git a/vcl/opengl/gdiimpl.cxx b/vcl/opengl/gdiimpl.cxx
index ebfc03a..bbbe5c9 100644
--- a/vcl/opengl/gdiimpl.cxx
+++ b/vcl/opengl/gdiimpl.cxx
@@ -640,7 +640,7 @@ void OpenGLSalGraphicsImpl::DrawEdgeAA( double nX1, double nY1, double nX2, doub
     ImplDrawLineAA( nX1, nY1, nX2, nY2, true );
 }
 
-void OpenGLSalGraphicsImpl::DrawConvexPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry )
+void OpenGLSalGraphicsImpl::DrawConvexPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry, bool blockAA )
 {
     std::vector<GLfloat> aVertices(nPoints * 2);
     sal_uInt32 i, j;
@@ -653,9 +653,32 @@ void OpenGLSalGraphicsImpl::DrawConvexPolygon( sal_uInt32 nPoints, const SalPoin
 
     mpProgram->SetVertices( &aVertices[0] );
     glDrawArrays( GL_TRIANGLE_FAN, 0, nPoints );
+
+    if( !blockAA && mrParent.getAntiAliasB2DDraw())
+    {
+        // Make the edges antialiased by drawing the edge lines again with AA.
+        // TODO: If transparent drawing is set up, drawing the lines themselves twice
+        // may be a problem, if that is a real problem, the polygon areas itself needs to be
+        // masked out for this or something.
+#ifdef DBG_UTIL
+        assert( mProgramIsSolidColor );
+#endif
+        SalColor lastSolidColor = mProgramSolidColor;
+        double lastSolidTransparency = mProgramSolidTransparency;
+        if( UseSolidAA( lastSolidColor, lastSolidTransparency ))
+        {
+            for( i = 0; i < nPoints; ++i )
+            {
+                const SalPoint& rPt1 = pPtAry[ i ];
+                const SalPoint& rPt2 = pPtAry[ ( i + 1 ) % nPoints ];
+                DrawEdgeAA( rPt1.mnX, rPt1.mnY, rPt2.mnX, rPt2.mnY );
+            }
+            UseSolid( lastSolidColor, lastSolidTransparency );
+        }
+    }
 }
 
-void OpenGLSalGraphicsImpl::DrawConvexPolygon( const Polygon& rPolygon )
+void OpenGLSalGraphicsImpl::DrawConvexPolygon( const Polygon& rPolygon, bool blockAA )
 {
     sal_uInt16 nPoints = rPolygon.GetSize() - 1;
     std::vector<GLfloat> aVertices(nPoints * 2);
@@ -671,7 +694,7 @@ void OpenGLSalGraphicsImpl::DrawConvexPolygon( const Polygon& rPolygon )
     mpProgram->SetVertices( &aVertices[0] );
     glDrawArrays( GL_TRIANGLE_FAN, 0, nPoints );
 
-    if( mrParent.getAntiAliasB2DDraw())
+    if( !blockAA && mrParent.getAntiAliasB2DDraw())
     {
         // Make the edges antialiased by drawing the edge lines again with AA.
         // TODO: If transparent drawing is set up, drawing the lines themselves twice
@@ -704,7 +727,7 @@ void OpenGLSalGraphicsImpl::DrawRect( long nX, long nY, long nWidth, long nHeigh
     const SalPoint aPoints[] = { { nX1, nY2 }, { nX1, nY1 },
                                  { nX2, nY1 }, { nX2, nY2 }};
 
-    DrawConvexPolygon( 4, aPoints );
+    DrawConvexPolygon( 4, aPoints, true );
 }
 
 void OpenGLSalGraphicsImpl::DrawRect( const Rectangle& rRect )
@@ -716,7 +739,7 @@ void OpenGLSalGraphicsImpl::DrawRect( const Rectangle& rRect )
     const SalPoint aPoints[] = { { nX1, nY2 }, { nX1, nY1 },
                                  { nX2, nY1 }, { nX2, nY2 }};
 
-    DrawConvexPolygon( 4, aPoints );
+    DrawConvexPolygon( 4, aPoints, true );
 }
 
 void OpenGLSalGraphicsImpl::DrawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry )
@@ -958,7 +981,7 @@ void OpenGLSalGraphicsImpl::DrawLinearGradient( const Gradient& rGradient, const
     GLfloat fMin = 1.0 - 100.0 / (100.0 - rGradient.GetBorder());
     aTexCoord[5] = aTexCoord[7] = fMin;
     mpProgram->SetTextureCoord( aTexCoord );
-    DrawConvexPolygon( aPoly );
+    DrawConvexPolygon( aPoly, true );
 }
 
 void OpenGLSalGraphicsImpl::DrawAxialGradient( const Gradient& rGradient, const Rectangle& rRect )
@@ -1008,7 +1031,7 @@ void OpenGLSalGraphicsImpl::DrawAxialGradient( const Gradient& rGradient, const
     GLfloat fMin = 1.0 - 100.0 / (100.0 - rGradient.GetBorder());
     aTexCoord[3] = aTexCoord[5] = aTexCoord[9] = aTexCoord[11] = fMin;
     mpProgram->SetTextureCoord( aTexCoord );
-    DrawConvexPolygon( aPoly );
+    DrawConvexPolygon( aPoly, true );
 }
 
 void OpenGLSalGraphicsImpl::DrawRadialGradient( const Gradient& rGradient, const Rectangle& rRect )
commit 0bdad2b3b6a2b4c252ff71c2b3995485fd34ed8d
Author: Luboš Luňák <l.lunak at collabora.com>
Date:   Sat Jan 17 20:46:55 2015 +0100

    use supersampling in Impress if fast opengl scaling is available
    
    So far it's been always disabled, with the exception of the slide preview
    extension.
    
    Change-Id: Iaee6fe2d5267c9dfdc31cbf4fb90a9ac0e08e781

diff --git a/include/vcl/bitmap.hxx b/include/vcl/bitmap.hxx
index 2dbfa81..0fe2afa 100644
--- a/include/vcl/bitmap.hxx
+++ b/include/vcl/bitmap.hxx
@@ -560,6 +560,15 @@ public:
      */
     bool                    Scale( const double& rScaleX, const double& rScaleY, sal_uInt32 nScaleFlag = BMP_SCALE_DEFAULT );
 
+    /**
+      Returns true if bitmap scaling is considered to be fast.
+
+      Currently this returns true if OpenGL is used for scaling, otherwise false (CPU scaling is slower).
+
+      @since 4.5
+    */
+    static bool HasFastScale();
+
     // Adapt the BitCount of rNew to BitCount of lolal, including grey or color paltette
     // Can be used to create alpha/mask bitmaps after their processing in 24bit
     void                    AdaptBitCount(Bitmap& rNew) const;
diff --git a/sd/source/ui/presenter/PresenterPreviewCache.cxx b/sd/source/ui/presenter/PresenterPreviewCache.cxx
index f88d2a5..da47d90 100644
--- a/sd/source/ui/presenter/PresenterPreviewCache.cxx
+++ b/sd/source/ui/presenter/PresenterPreviewCache.cxx
@@ -96,7 +96,7 @@ PresenterPreviewCache::PresenterPreviewCache (const Reference<XComponentContext>
     : PresenterPreviewCacheInterfaceBase(m_aMutex),
       maPreviewSize(Size(200,200)),
       mpCacheContext(new PresenterCacheContext()),
-      mpCache(new PageCache(maPreviewSize, false, mpCacheContext))
+      mpCache(new PageCache(maPreviewSize, Bitmap::HasFastScale(), mpCacheContext))
 {
     (void)rxContext;
 }
@@ -146,7 +146,7 @@ void SAL_CALL PresenterPreviewCache::setPreviewSize (
     OSL_ASSERT(mpCache.get()!=NULL);
 
     maPreviewSize = Size(rSize.Width, rSize.Height);
-    mpCache->ChangeSize(maPreviewSize, false);
+    mpCache->ChangeSize(maPreviewSize, Bitmap::HasFastScale());
 }
 
 Reference<rendering::XBitmap> SAL_CALL PresenterPreviewCache::getSlidePreview (
diff --git a/sd/source/ui/slidesorter/view/SlideSorterView.cxx b/sd/source/ui/slidesorter/view/SlideSorterView.cxx
index 705ca08..4d34b14 100644
--- a/sd/source/ui/slidesorter/view/SlideSorterView.cxx
+++ b/sd/source/ui/slidesorter/view/SlideSorterView.cxx
@@ -424,7 +424,7 @@ void SlideSorterView::Layout ()
             const Size aNewPreviewSize (mpLayouter->GetPageObjectLayouter()->GetPreviewSize(PageObjectLayouter::WindowCoordinateSystem));
             if (maPreviewSize != aNewPreviewSize && GetPreviewCache())
             {
-                mpPreviewCache->ChangeSize(aNewPreviewSize, false);
+                mpPreviewCache->ChangeSize(aNewPreviewSize, Bitmap::HasFastScale());
                 maPreviewSize = aNewPreviewSize;
             }
         }
@@ -706,7 +706,7 @@ void SlideSorterView::ConfigurationChanged (
         mpPreviewCache.reset(
             new cache::PageCache(
                 mpLayouter->GetPageObjectSize(),
-                false,
+                Bitmap::HasFastScale(),
                 cache::SharedCacheContext(new ViewCacheContext(mrSlideSorter))));
     }
 
diff --git a/vcl/source/gdi/bitmap3.cxx b/vcl/source/gdi/bitmap3.cxx
index 38816e4..2115160 100644
--- a/vcl/source/gdi/bitmap3.cxx
+++ b/vcl/source/gdi/bitmap3.cxx
@@ -24,6 +24,7 @@
 #include <vcl/bitmapex.hxx>
 #include <vcl/bitmap.hxx>
 #include <vcl/bitmapscalesuper.hxx>
+#include <vcl/opengl/OpenGLHelper.hxx>
 
 #include <boost/scoped_array.hpp>
 
@@ -993,6 +994,11 @@ bool Bitmap::Scale( const Size& rNewSize, sal_uInt32 nScaleFlag )
     return bRet;
 }
 
+bool Bitmap::HasFastScale()
+{
+    return OpenGLHelper::isVCLOpenGLEnabled();
+}
+
 void Bitmap::AdaptBitCount(Bitmap& rNew) const
 {
     ImplAdaptBitCount(rNew);
commit ab65925b40134ff7d8b88c61db5235549599385f
Author: Luboš Luňák <l.lunak at collabora.com>
Date:   Sat Jan 17 20:00:52 2015 +0100

    "area" scaling for opengl that has good results for downscaling
    
    Change-Id: I0e4ad776cbf31f9a130aedf0f9741927560b5ac1

diff --git a/vcl/Package_opengl.mk b/vcl/Package_opengl.mk
index 0aa324f..0a54ad6 100644
--- a/vcl/Package_opengl.mk
+++ b/vcl/Package_opengl.mk
@@ -10,6 +10,8 @@
 $(eval $(call gb_Package_Package,vcl_opengl_shader,$(SRCDIR)/vcl/opengl))
 
 $(eval $(call gb_Package_add_files,vcl_opengl_shader,$(LIBO_ETC_FOLDER)/opengl,\
+	areaScaleFastFragmentShader.glsl \
+	areaScaleFragmentShader.glsl \
 	blendedTextureFragmentShader.glsl \
 	blendedTextureVertexShader.glsl \
 	dumbVertexShader.glsl \
diff --git a/vcl/inc/opengl/program.hxx b/vcl/inc/opengl/program.hxx
index 6e21abf..8fc74d20 100644
--- a/vcl/inc/opengl/program.hxx
+++ b/vcl/inc/opengl/program.hxx
@@ -55,6 +55,8 @@ public:
     void SetUniform2f( const OString& rName, GLfloat v1, GLfloat v2 );
     void SetUniform1fv( const OString& rName, GLsizei nCount, GLfloat* aValues );
     void SetUniform2fv( const OString& rName, GLsizei nCount, GLfloat* aValues );
+    void SetUniform1i( const OString& rName, GLint v1 );
+    void SetUniform1iv( const OString& rName, GLsizei nCount, GLint* aValues );
     void SetColor( const OString& rName, const Color& rColor );
     void SetColor( const OString& rName, SalColor nColor, sal_uInt8 nTransparency );
     void SetColorf( const OString& rName, SalColor nColor, double fTransparency );
diff --git a/vcl/inc/opengl/salbmp.hxx b/vcl/inc/opengl/salbmp.hxx
index 200698f..84c64ed 100644
--- a/vcl/inc/opengl/salbmp.hxx
+++ b/vcl/inc/opengl/salbmp.hxx
@@ -104,6 +104,7 @@ private:
     bool ImplScaleFilter( const double& rScaleX, const double& rScaleY, GLenum nFilter );
     void ImplCreateKernel( const double& fScale, const Kernel& rKernel, GLfloat*& pWeights, sal_uInt32& aKernelSize );
     bool ImplScaleConvolution( const double& rScaleX, const double& rScaleY, const Kernel& aKernel );
+    bool ImplScaleArea( double rScaleX, double rScaleY );
 
 public:
 
diff --git a/vcl/opengl/areaScaleFastFragmentShader.glsl b/vcl/opengl/areaScaleFastFragmentShader.glsl
new file mode 100644
index 0000000..b8874d1
--- /dev/null
+++ b/vcl/opengl/areaScaleFastFragmentShader.glsl
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/* TODO Use textureOffset for newest version of GLSL */
+
+uniform sampler2D sampler;
+uniform int xscale;
+uniform int yscale;
+uniform float xstep;
+uniform float ystep;
+uniform float ratio; // = 1.0/(xscale*yscale)
+
+varying vec2 tex_coord;
+
+/*
+ Just make the resulting color the average of all the source pixels
+ (which is an area (xscale)x(yscale) ).
+*/
+void main(void)
+{
+    vec4 sum = vec4( 0.0, 0.0, 0.0, 0.0 );
+    vec2 offset = vec2( 0.0, 0.0 );
+    for( int y = 0; y < yscale; ++y )
+    {
+        for( int x = 0; x < xscale; ++x )
+        {
+            sum += texture2D( sampler, tex_coord.st + offset );
+            offset.x += xstep;
+        }
+        offset.y += ystep;
+        offset.x = 0.0;
+    }
+    sum *= ratio;
+    gl_FragColor = sum;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/opengl/areaScaleFragmentShader.glsl b/vcl/opengl/areaScaleFragmentShader.glsl
new file mode 100644
index 0000000..cae5eb6
--- /dev/null
+++ b/vcl/opengl/areaScaleFragmentShader.glsl
@@ -0,0 +1,131 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/* TODO Use textureOffset for newest version of GLSL */
+
+uniform sampler2D sampler;
+uniform int swidth;
+uniform int sheight;
+uniform float xscale;
+uniform float yscale;
+uniform float xsrcconvert;
+uniform float ysrcconvert;
+uniform float xdestconvert;
+uniform float ydestconvert;
+
+varying vec2 tex_coord;
+
+void main(void)
+{
+    // Convert to pixel coordinates again.
+    int dx = int( tex_coord.s * xdestconvert );
+    int dy = int( tex_coord.t * ydestconvert );
+
+    // Note: These values are always the same for the same X (or Y),
+    // so they could be precalculated in C++ and passed to the shader,
+    // but GLSL has limits on the size of uniforms passed to it,
+    // so it'd need something like texture buffer objects from newer
+    // GLSL versions, and it seems the hassle is not really worth it.
+
+    // How much each column/row will contribute to the resulting pixel.
+    // assert( xscale <= 100 ); assert( yscale <= 100 );
+    float xratio[ 100 + 2 ];
+    float yratio[ 100 + 2 ];
+    // For finding the first and last source pixel.
+    int xpixel[ 100 + 2 ];
+    int ypixel[ 100 + 2 ];
+
+    int xpos = 0;
+    int ypos = 0;
+
+    // Compute the range of source pixels which will make up this destination pixel.
+    float fsx1 = dx * xscale;
+    float fsx2 = fsx1 + xscale;
+    // To whole pixel coordinates.
+    int sx1 = ceil( fsx1 );
+    int sx2 = floor( fsx2 );
+    // Range checking.
+    sx2 = min( sx2, swidth - 1 );
+    sx1 = min( sx1, sx2 );
+
+    // How much one full column contributes to the resulting pixel.
+    float width = min( xscale, swidth - fsx1 );
+
+    if( sx1 - fsx1 > 0.001 )
+    {   // The first column contributes only partially.
+        xpixel[ xpos ] = sx1 - 1;
+        xratio[ xpos ] = ( sx1 - fsx1 ) / width;
+        ++xpos;
+    }
+    for( int sx = sx1; sx < sx2; ++sx )
+    {   // Columns that fully contribute to the resulting pixel.
+        xpixel[ xpos ] = sx;
+        xratio[ xpos ] = 1.0 / width;
+        ++xpos;
+    }
+    if( fsx2 - sx2 > 0.001 )
+    {   // The last column contributes only partially.
+        xpixel[ xpos ] = sx2;
+        xratio[ xpos ] = min( min( fsx2 - sx2, 1.0 ) / width, 1.0 );
+        ++xpos;
+    }
+
+    // The same for Y.
+    float fsy1 = dy * yscale;
+    float fsy2 = fsy1 + yscale;
+    int sy1 = ceil( fsy1 );
+    int sy2 = floor( fsy2 );
+    sy2 = min( sy2, sheight - 1 );
+    sy1 = min( sy1, sy2 );
+
+    float height = min( yscale, sheight - fsy1 );
+
+    if( sy1 - fsy1 > 0.001 )
+    {
+        ypixel[ ypos ] = sy1 - 1;
+        yratio[ ypos ] = ( sy1 - fsy1 ) / height;
+        ++ypos;
+    }
+    for( int sy = sy1; sy < sy2; ++sy )
+    {
+        ypixel[ ypos ] = sy;
+        yratio[ ypos ] = 1.0 / height;
+        ++ypos;
+    }
+    if( fsy2 - sy2 > 0.001 )
+    {
+        ypixel[ ypos ] = sy2;
+        yratio[ ypos ] = min( min( fsy2 - sy2, 1.0 ) / height, 1.0 );
+        ++ypos;
+    }
+
+    int xstart = xpixel[ 0 ];
+    int xend = xpixel[ xpos - 1 ];
+    int ystart = ypixel[ 0 ];
+    int yend = ypixel[ ypos - 1 ];
+
+    vec4 sum = vec4( 0.0, 0.0, 0.0, 0.0 );
+
+    ypos = 0;
+    for( int y = ystart; y <= yend; ++y, ++ypos )
+    {
+        vec4 tmp = vec4( 0.0, 0.0, 0.0, 0.0 );
+        xpos = 0;
+        for( int x = xstart; x <= xend; ++x, ++xpos )
+        {
+            vec2 offset = vec2( x * xsrcconvert, y * ysrcconvert );
+            tmp += texture2D( sampler, offset ) * xratio[ xpos ];
+        }
+        sum += tmp * yratio[ ypos ];
+    }
+
+    gl_FragColor = sum;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/opengl/program.cxx b/vcl/opengl/program.cxx
index 0fe4605..d3a192c 100644
--- a/vcl/opengl/program.cxx
+++ b/vcl/opengl/program.cxx
@@ -148,6 +148,18 @@ void OpenGLProgram::SetUniform2fv( const OString& rName, GLsizei nCount, GLfloat
     glUniform2fv( nUniform, nCount, aValues );
 }
 
+void OpenGLProgram::SetUniform1i( const OString& rName, GLint v1 )
+{
+    GLuint nUniform = GetUniformLocation( rName );
+    glUniform1i( nUniform, v1 );
+}
+
+void OpenGLProgram::SetUniform1iv( const OString& rName, GLsizei nCount, GLint* aValues )
+{
+    GLuint nUniform = GetUniformLocation( rName );
+    glUniform1iv( nUniform, nCount, aValues );
+}
+
 void OpenGLProgram::SetColor( const OString& rName, SalColor nColor, sal_uInt8 nTransparency )
 {
     GLuint nUniform = GetUniformLocation( rName );
diff --git a/vcl/opengl/scale.cxx b/vcl/opengl/scale.cxx
index a81c63b..84cf967 100644
--- a/vcl/opengl/scale.cxx
+++ b/vcl/opengl/scale.cxx
@@ -188,6 +188,78 @@ bool OpenGLSalBitmap::ImplScaleConvolution(
     return true;
 }
 
+/*
+ "Area" scaling algorithm, which seems to give better results for downscaling
+ than other algorithms. The principle (taken from opencv, see resize.cl)
+ is that each resulting pixel is the average of all the source pixel values
+ it represents. Which is trivial in the case of exact multiples for downscaling,
+ the generic case needs to also consider that some source pixels contribute
+ only partially to their resulting pixels (becauses of non-integer multiples).
+*/
+bool OpenGLSalBitmap::ImplScaleArea( double rScaleX, double rScaleY )
+{
+    int nNewWidth( mnWidth * rScaleX );
+    int nNewHeight( mnHeight * rScaleY );
+
+    if( nNewWidth == mnWidth && nNewHeight == mnHeight )
+        return true;
+
+    double ixscale = 1 / rScaleX;
+    double iyscale = 1 / rScaleY;
+    bool fast = ( ixscale == int( ixscale ) && iyscale == int( iyscale )
+        && int( nNewWidth * ixscale ) == mnWidth && int( nNewHeight * iyscale ) == mnHeight );
+
+    // The generic case has arrays only up to 100 ratio downscaling, which is hopefully enough
+    // in practice, but protect against buffer overflows in case such an extreme case happens
+    // (and in such case the precision of the generic algorithm probably doesn't matter anyway).
+    if( ixscale > 100 || iyscale > 100 )
+        fast = true;
+
+    // TODO Make sure the framebuffer is alright
+
+    OpenGLProgram* pProgram = mpContext->UseProgram( "textureVertexShader",
+        fast ? OUString( "areaScaleFastFragmentShader" ) : OUString( "areaScaleFragmentShader" ));
+    if( pProgram == 0 )
+        return false;
+
+    OpenGLTexture aScratchTex = OpenGLTexture( nNewWidth, nNewHeight );
+    OpenGLFramebuffer* pFramebuffer = mpContext->AcquireFramebuffer( aScratchTex );
+
+    if( fast )
+    {
+        pProgram->SetUniform1i( "xscale", ixscale );
+        pProgram->SetUniform1i( "yscale", iyscale );
+        pProgram->SetUniform1f( "xstep", 1.0 / mnWidth );
+        pProgram->SetUniform1f( "ystep", 1.0 / mnHeight );
+        pProgram->SetUniform1f( "ratio", 1.0 / ( ixscale * iyscale ));
+    }
+    else
+    {
+        pProgram->SetUniform1f( "xscale", ixscale );
+        pProgram->SetUniform1f( "yscale", iyscale );
+        pProgram->SetUniform1i( "swidth", mnWidth );
+        pProgram->SetUniform1i( "sheight", mnHeight );
+        // For converting between <0,mnWidth-1> and <0.0,1.0> coordinate systems.
+        pProgram->SetUniform1f( "xsrcconvert", 1.0 / ( mnWidth - 1 ));
+        pProgram->SetUniform1f( "ysrcconvert", 1.0 / ( mnHeight - 1 ));
+        pProgram->SetUniform1f( "xdestconvert", 1.0 * ( nNewWidth - 1 ));
+        pProgram->SetUniform1f( "ydestconvert", 1.0 * ( nNewHeight - 1 ));
+    }
+
+    pProgram->SetTexture( "sampler", maTexture );
+    pProgram->DrawTexture( maTexture );
+    pProgram->Clean();
+
+    maTexture = aScratchTex;
+    mpContext->ReleaseFramebuffer( pFramebuffer );
+
+    mnWidth = nNewWidth;
+    mnHeight = nNewHeight;
+
+    CHECK_GL_ERROR();
+    return true;
+}
+
 bool OpenGLSalBitmap::ImplScale( const double& rScaleX, const double& rScaleY, sal_uInt32 nScaleFlag )
 {
     SAL_INFO( "vcl.opengl", "::ImplScale" );
@@ -209,6 +281,10 @@ bool OpenGLSalBitmap::ImplScale( const double& rScaleX, const double& rScaleY, s
 
         return ImplScaleConvolution( rScaleX, rScaleY, aKernel );
     }
+    else if( nScaleFlag == BMP_SCALE_BESTQUALITY && rScaleX <= 1 && rScaleY <= 1 )
+    { // Use are scaling for best quality, but only if downscaling.
+        return ImplScaleArea( rScaleX, rScaleY );
+    }
     else if( nScaleFlag == BMP_SCALE_LANCZOS || nScaleFlag == BMP_SCALE_BESTQUALITY  )
     {
         const Lanczos3Kernel aKernel;


More information about the Libreoffice-commits mailing list