cppcanvas/source/mtfrenderer/transparencygroupaction.cxx |   67 ++++++++++++---
 include/vcl/outdev.hxx                                   |    5 +
 vcl/source/outdev/transparent.cxx                        |   35 ++++++-
 3 files changed, 90 insertions(+), 17 deletions(-)

New commits:
commit e644d4da25e1b6cd211d51dbd2dc7de84648c708
Author:     Patrick Luby <[email protected]>
AuthorDate: Fri Aug 25 08:39:46 2023 -0400
Commit:     Mike Kaganski <[email protected]>
CommitDate: Mon Aug 28 13:30:48 2023 +0200

    tdf#150610 fix broken rendering of text meta actions
    
    Even when drawing to a VirtualDevice where antialiasing
    is disabled, text will still be drawn with some
    antialiased pixels on HiDPI displays. So, expand the
    size of the VirtualDevice slightly to capture any of
    the pixles drawn past the edges of the destination
    bounds.
    
    Change-Id: Ibcba8234708d8784c12f984289ec0a8fcad6694e
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/156098
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <[email protected]>
    Reviewed-by: Patrick Luby <[email protected]>
    (cherry picked from commit e7496f41562b75ea9732ca48f9aa0c07b69e424f)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/156135

diff --git a/cppcanvas/source/mtfrenderer/transparencygroupaction.cxx 
b/cppcanvas/source/mtfrenderer/transparencygroupaction.cxx
index b1dff7cb404f..1cd29135662e 100644
--- a/cppcanvas/source/mtfrenderer/transparencygroupaction.cxx
+++ b/cppcanvas/source/mtfrenderer/transparencygroupaction.cxx
@@ -205,6 +205,8 @@ namespace cppcanvas::internal
                     return false;
                 }
 
+                ::Point aMtfOffsetPoint;
+
                 // if there's no buffer bitmap, or as soon as the
                 // total transformation changes, we've got to
                 // re-render the bitmap
@@ -215,15 +217,59 @@ namespace cppcanvas::internal
                 {
                     DBG_TESTSOLARMUTEX();
 
+                    // tdf#150610 fix broken rendering of text meta actions
+                    // Even when drawing to a VirtualDevice where antialiasing
+                    // is disabled, text will still be drawn with some
+                    // antialiased pixels on HiDPI displays. So, expand the
+                    // size of the VirtualDevice slightly to capture any of
+                    // the pixles drawn past the edges of the destination
+                    // bounds.
+                    bool        bHasTextActions = false;
+                    MetaAction* pCurrAct;
+                    int         nCurrActionIndex;
+                    for( nCurrActionIndex=0, 
pCurrAct=mpGroupMtf->FirstAction();
+                         pCurrAct && !bHasTextActions;
+                         ++nCurrActionIndex, pCurrAct = 
mpGroupMtf->NextAction() )
+                    {
+                        switch( pCurrAct->GetType() )
+                        {
+                            case MetaActionType::TEXT:
+                            case MetaActionType::TEXTARRAY:
+                            case MetaActionType::STRETCHTEXT:
+                            case MetaActionType::TEXTRECT:
+                                if( ( rSubset.mnSubsetBegin == 0 && 
rSubset.mnSubsetEnd == -1 ) || ( rSubset.mnSubsetBegin <= nCurrActionIndex && 
rSubset.mnSubsetEnd > nCurrActionIndex ) )
+                                    bHasTextActions = true;
+                                break;
+                            default:
+                                break;
+                        }
+                    }
+
                     // output size of metafile
                     ::Size aOutputSizePixel( ::basegfx::fround( aScale.getX() 
* maDstSize.getWidth() ),
                                              ::basegfx::fround( aScale.getY() 
* maDstSize.getHeight() ) );
 
-                    // pixel size of cache bitmap: round up to nearest int
-                    ::Size aBitmapSizePixel( static_cast<sal_Int32>( 
aScale.getX() * maDstSize.getWidth() )+1,
-                                             static_cast<sal_Int32>( 
aScale.getY() * maDstSize.getHeight() )+1 );
+                    sal_Int32 nBitmapExtra;
+                    if ( bHasTextActions )
+                    {
+                        nBitmapExtra = 10;
+                        aMtfOffsetPoint = ::Point( nBitmapExtra / 2, 
nBitmapExtra / 2 );
+                    }
+                    else
+                    {
+                        // Related tdf#150610 assume antialiasing is enabled
+                        // Although antialiasing is normally disabled in the
+                        // VirtualDevice, lines in tdf#150610 will draw past
+                        // the edge of the VirtualDevice when running a
+                        // slideshow so always add an extra pixel on the
+                        // right and bottom edges.
+                        nBitmapExtra = 1;
+                    }
 
-                    ::Point aEmptyPoint;
+                    // pixel size of cache bitmap: round up to nearest int
+                    ::Point aBitmapPoint;
+                    ::Size aBitmapSizePixel( static_cast<sal_Int32>( 
aScale.getX() * maDstSize.getWidth() ) + nBitmapExtra,
+                                             static_cast<sal_Int32>( 
aScale.getY() * maDstSize.getHeight() ) + nBitmapExtra );
 
                     // render our content into an appropriately sized
                     // VirtualDevice with alpha channel
@@ -238,8 +284,6 @@ namespace cppcanvas::internal
                         // true subset - extract referenced
                         // metaactions from mpGroupMtf
                         GDIMetaFile aMtf;
-                        MetaAction* pCurrAct;
-                        int         nCurrActionIndex;
 
                         // extract subset actions
                         for( nCurrActionIndex=0,
@@ -320,7 +364,9 @@ namespace cppcanvas::internal
                         }
 
                         aVDev->DrawTransparent( aMtf,
-                                               aEmptyPoint,
+                                               aBitmapPoint,
+                                               aBitmapSizePixel,
+                                               aMtfOffsetPoint,
                                                aOutputSizePixel,
                                                *mpAlphaGradient );
                     }
@@ -328,7 +374,9 @@ namespace cppcanvas::internal
                     {
                         // no subsetting - render whole mtf
                         aVDev->DrawTransparent( *mpGroupMtf,
-                                               aEmptyPoint,
+                                               aBitmapPoint,
+                                               aBitmapSizePixel,
+                                               aMtfOffsetPoint,
                                                aOutputSizePixel,
                                                *mpAlphaGradient );
                     }
@@ -338,7 +386,7 @@ namespace cppcanvas::internal
                     BitmapSharedPtr aBmp( VCLFactory::createBitmap(
                                               mpCanvas,
                                               aVDev->GetBitmapEx(
-                                                  aEmptyPoint,
+                                                  aBitmapPoint,
                                                   aBitmapSizePixel ) ) );
                     mxBufferBitmap = aBmp->getUNOBitmap();
                     maLastTransformation = aTotalTransform;
@@ -362,6 +410,7 @@ namespace cppcanvas::internal
                 // the contained scaling, we've got to right-multiply with
                 // the inverse.
                 ::basegfx::B2DHomMatrix aScaleCorrection;
+                aScaleCorrection.translate( -aMtfOffsetPoint.X(), 
-aMtfOffsetPoint.Y() );
                 aScaleCorrection.scale( 1/aScale.getX(), 1/aScale.getY() );
                 aTransform = aTransform * aScaleCorrection;
 
diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx
index d550ecfce293..9625488b8f12 100644
--- a/include/vcl/outdev.hxx
+++ b/include/vcl/outdev.hxx
@@ -1499,6 +1499,11 @@ public:
                                         const GDIMetaFile& rMtf, const Point& 
rPos, const Size& rSize,
                                         const Gradient& rTransparenceGradient 
);
 
+    void                        DrawTransparent(
+                                        const GDIMetaFile& rMtf, const Point& 
rPos, const Size& rSize,
+                                        const Point& rMtfPos, const Size& 
rMtfSize,
+                                        const Gradient& rTransparenceGradient 
);
+
 protected:
 
     virtual void                EmulateDrawTransparent( const 
tools::PolyPolygon& rPolyPoly, sal_uInt16 nTransparencePercent );
diff --git a/vcl/source/outdev/transparent.cxx 
b/vcl/source/outdev/transparent.cxx
index 4a4b6b5a54bb..cc6cdf14823d 100644
--- a/vcl/source/outdev/transparent.cxx
+++ b/vcl/source/outdev/transparent.cxx
@@ -561,6 +561,13 @@ void OutputDevice::DrawTransparent( const 
tools::PolyPolygon& rPolyPoly,
 
 void OutputDevice::DrawTransparent( const GDIMetaFile& rMtf, const Point& rPos,
                                     const Size& rSize, const Gradient& 
rTransparenceGradient )
+{
+    DrawTransparent( rMtf, rPos, rSize, rPos, rSize, rTransparenceGradient );
+}
+
+void OutputDevice::DrawTransparent( const GDIMetaFile& rMtf, const Point& 
rPos, const Size& rSize,
+                                    const Point& rMtfPos, const Size& rMtfSize,
+                                    const Gradient& rTransparenceGradient )
 {
     assert(!is_double_buffered_window());
 
@@ -579,7 +586,7 @@ void OutputDevice::DrawTransparent( const GDIMetaFile& 
rMtf, const Point& rPos,
         ( mnDrawMode & DrawModeFlags::NoTransparency ) )
     {
         const_cast<GDIMetaFile&>(rMtf).WindStart();
-        const_cast<GDIMetaFile&>(rMtf).Play(*this, rPos, rSize);
+        const_cast<GDIMetaFile&>(rMtf).Play(*this, rMtfPos, rMtfSize);
         const_cast<GDIMetaFile&>(rMtf).WindStart();
     }
     else
@@ -604,7 +611,13 @@ void OutputDevice::DrawTransparent( const GDIMetaFile& 
rMtf, const Point& rPos,
 
             if( xVDev->SetOutputSizePixel( aDstRect.GetSize() ) )
             {
-                if(GetAntialiasing() != AntialiasingFlags::NONE)
+                // tdf#150610 fix broken rendering of text meta actions
+                // Even when drawing to a VirtualDevice that has antialiasing
+                // disabled, text will still be drawn with some antialiased
+                // pixels on HiDPI displays. So, use the antialiasing enabled
+                // code to render if there are any text meta actions in the
+                // metafile.
+                if(GetAntialiasing() != AntialiasingFlags::NONE || rPos != 
rMtfPos || rSize != rMtfSize)
                 {
                     // #i102109#
                     // For MetaFile replay (see task) it may now be necessary 
to take
@@ -635,27 +648,33 @@ void OutputDevice::DrawTransparent( const GDIMetaFile& 
rMtf, const Point& rPos,
                     // draw MetaFile to buffer
                     xVDev->EnableMapMode(bBufferMapModeEnabled);
                     const_cast<GDIMetaFile&>(rMtf).WindStart();
-                    const_cast<GDIMetaFile&>(rMtf).Play(*xVDev, rPos, rSize);
+                    const_cast<GDIMetaFile&>(rMtf).Play(*xVDev, rMtfPos, 
rMtfSize);
                     const_cast<GDIMetaFile&>(rMtf).WindStart();
 
                     // get content bitmap from buffer
                     xVDev->EnableMapMode(false);
 
-                    const Bitmap aPaint(xVDev->GetBitmap(aPoint, 
xVDev->GetOutputSizePixel()));
+                    const BitmapEx aPaint(xVDev->GetBitmapEx(aPoint, 
xVDev->GetOutputSizePixel()));
 
                     // create alpha mask from gradient and get as Bitmap
                     xVDev->EnableMapMode(bBufferMapModeEnabled);
                     xVDev->SetDrawMode(DrawModeFlags::GrayGradient);
+                    // Related tdf#150610 draw gradient to VirtualDevice bounds
+                    // If we are here and the metafile bounds differs from the
+                    // VirtualDevice bounds so that we apply the transparency
+                    // gradient to any pixels drawn outside of the metafile
+                    // bounds.
                     xVDev->DrawGradient(tools::Rectangle(rPos, rSize), 
rTransparenceGradient);
                     xVDev->SetDrawMode(DrawModeFlags::Default);
                     xVDev->EnableMapMode(false);
 
-                    const AlphaMask aAlpha(xVDev->GetBitmap(aPoint, 
xVDev->GetOutputSizePixel()));
+                    AlphaMask aAlpha(xVDev->GetBitmap(aPoint, 
xVDev->GetOutputSizePixel()));
+                    aAlpha.BlendWith(aPaint.GetAlphaMask());
 
                     xVDev.disposeAndClear();
 
                     // draw masked content to target and restore MapMode
-                    DrawBitmapEx(aDstRect.TopLeft(), BitmapEx(aPaint, aAlpha));
+                    DrawBitmapEx(aDstRect.TopLeft(), 
BitmapEx(aPaint.GetBitmap(), aAlpha));
                     EnableMapMode(bOrigMapModeEnabled);
                 }
                 else
@@ -670,7 +689,7 @@ void OutputDevice::DrawTransparent( const GDIMetaFile& 
rMtf, const Point& rPos,
 
                     // create paint bitmap
                     const_cast<GDIMetaFile&>(rMtf).WindStart();
-                    const_cast<GDIMetaFile&>(rMtf).Play(*xVDev, rPos, rSize);
+                    const_cast<GDIMetaFile&>(rMtf).Play(*xVDev, rMtfPos, 
rMtfSize);
                     const_cast<GDIMetaFile&>(rMtf).WindStart();
                     xVDev->EnableMapMode( false );
                     BitmapEx aPaint = xVDev->GetBitmapEx(Point(), 
xVDev->GetOutputSizePixel());
@@ -678,7 +697,7 @@ void OutputDevice::DrawTransparent( const GDIMetaFile& 
rMtf, const Point& rPos,
 
                     // create alpha mask from gradient
                     xVDev->SetDrawMode( DrawModeFlags::GrayGradient );
-                    xVDev->DrawGradient( tools::Rectangle( rPos, rSize ), 
rTransparenceGradient );
+                    xVDev->DrawGradient( tools::Rectangle( rMtfPos, rMtfSize 
), rTransparenceGradient );
                     xVDev->SetDrawMode( DrawModeFlags::Default );
                     xVDev->EnableMapMode( false );
 

Reply via email to