vcl/ios/salios.cxx          |  147 ++++++++++++++++++++++++++++++++++++++++++
 vcl/osx/salmacos.cxx        |  152 ++++++++++++++++++++++++++++++++++++++++++++
 vcl/quartz/salgdicommon.cxx |  147 ------------------------------------------
 3 files changed, 299 insertions(+), 147 deletions(-)

New commits:
commit a396dde0907ad87ac928c9a1b9f7640a73910b17
Author:     Thorsten Wagner <thorsten.wagne...@gmail.com>
AuthorDate: Mon Jun 28 22:36:56 2021 +0200
Commit:     Adolfo Jayme Barrientos <fit...@ubuntu.com>
CommitDate: Tue Jun 29 10:29:16 2021 +0200

    tdf#142061 Consider window scaling for XOR drawing on macOS
    
    Change-Id: I4261334b6d2d2f34fe3452cc870aba6f88c4069e
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/118036
    Reviewed-by: Adolfo Jayme Barrientos <fit...@ubuntu.com>
    Tested-by: Adolfo Jayme Barrientos <fit...@ubuntu.com>

diff --git a/vcl/ios/salios.cxx b/vcl/ios/salios.cxx
index d1552b8b0bbb..4c8c99b4c4a4 100644
--- a/vcl/ios/salios.cxx
+++ b/vcl/ios/salios.cxx
@@ -331,6 +331,153 @@ void AquaSalGraphics::SetVirDevGraphics(CGLayerHolder 
const & rLayer, CGContextR
     SetState();
 }
 
+void XorEmulation::SetTarget( int nWidth, int nHeight, int nTargetDepth,
+                              CGContextRef xTargetContext, CGLayerRef 
xTargetLayer )
+{
+    SAL_INFO( "vcl.quartz", "XorEmulation::SetTarget() this=" << this <<
+              " (" << nWidth << "x" << nHeight << ") depth=" << nTargetDepth <<
+              " context=" << xTargetContext << " layer=" << xTargetLayer );
+
+    // prepare to replace old mask+temp context
+    if( m_xMaskContext )
+    {
+        // cleanup the mask context
+        CGContextRelease( m_xMaskContext );
+        delete[] m_pMaskBuffer;
+        m_xMaskContext = nullptr;
+        m_pMaskBuffer = nullptr;
+
+        // cleanup the temp context if needed
+        if( m_xTempContext )
+        {
+            CGContextRelease( m_xTempContext );
+            delete[] m_pTempBuffer;
+            m_xTempContext = nullptr;
+            m_pTempBuffer = nullptr;
+        }
+    }
+
+    // return early if there is nothing more to do
+    if( !xTargetContext )
+    {
+        return;
+    }
+    // retarget drawing operations to the XOR mask
+    m_xTargetLayer = xTargetLayer;
+    m_xTargetContext = xTargetContext;
+
+    // prepare creation of matching CGBitmaps
+    CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace;
+    CGBitmapInfo aCGBmpInfo = kCGImageAlphaNoneSkipFirst;
+    int nBitDepth = nTargetDepth;
+    if( !nBitDepth )
+    {
+        nBitDepth = 32;
+    }
+    int nBytesPerRow = 4;
+    const size_t nBitsPerComponent = (nBitDepth == 16) ? 5 : 8;
+    if( nBitDepth <= 8 )
+    {
+        aCGColorSpace = GetSalData()->mxGraySpace;
+        aCGBmpInfo = kCGImageAlphaNone;
+        nBytesPerRow = 1;
+    }
+    nBytesPerRow *= nWidth;
+    m_nBufferLongs = (nHeight * nBytesPerRow + sizeof(sal_uLong)-1) / 
sizeof(sal_uLong);
+
+    // create a XorMask context
+    m_pMaskBuffer = new sal_uLong[ m_nBufferLongs ];
+    m_xMaskContext = CGBitmapContextCreate( m_pMaskBuffer,
+                                            nWidth, nHeight,
+                                            nBitsPerComponent, nBytesPerRow,
+                                            aCGColorSpace, aCGBmpInfo );
+    SAL_WARN_IF( !m_xMaskContext, "vcl.quartz", "mask context creation failed" 
);
+
+    // reset the XOR mask to black
+    memset( m_pMaskBuffer, 0, m_nBufferLongs * sizeof(sal_uLong) );
+
+    // a bitmap context will be needed for manual XORing
+    // create one unless the target context is a bitmap context
+    if( nTargetDepth )
+    {
+        m_pTempBuffer = static_cast<sal_uLong*>(CGBitmapContextGetData( 
m_xTargetContext ));
+    }
+    if( !m_pTempBuffer )
+    {
+        // create a bitmap context matching to the target context
+        m_pTempBuffer = new sal_uLong[ m_nBufferLongs ];
+        m_xTempContext = CGBitmapContextCreate( m_pTempBuffer,
+                                                nWidth, nHeight,
+                                                nBitsPerComponent, 
nBytesPerRow,
+                                                aCGColorSpace, aCGBmpInfo );
+        SAL_WARN_IF( !m_xTempContext, "vcl.quartz", "temp context creation 
failed" );
+    }
+
+    // initialize XOR mask context for drawing
+    CGContextSetFillColorSpace( m_xMaskContext, aCGColorSpace );
+    CGContextSetStrokeColorSpace( m_xMaskContext, aCGColorSpace );
+    CGContextSetShouldAntialias( m_xMaskContext, false );
+
+    // improve the XorMask's XOR emulation a little
+    // NOTE: currently only enabled for monochrome contexts
+    if( aCGColorSpace == GetSalData()->mxGraySpace )
+    {
+        CGContextSetBlendMode( m_xMaskContext, kCGBlendModeDifference );
+    }
+    // initialize the transformation matrix to the drawing target
+    const CGAffineTransform aCTM = CGContextGetCTM( xTargetContext );
+    CGContextConcatCTM( m_xMaskContext, aCTM );
+    if( m_xTempContext )
+    {
+        CGContextConcatCTM( m_xTempContext, aCTM );
+    }
+    // initialize the default XorMask graphics state
+    CGContextSaveGState( m_xMaskContext );
+}
+
+bool XorEmulation::UpdateTarget()
+{
+    SAL_INFO( "vcl.quartz", "XorEmulation::UpdateTarget() this=" << this );
+
+    if( !IsEnabled() )
+    {
+        return false;
+    }
+    // update the temp bitmap buffer if needed
+    if( m_xTempContext )
+    {
+        SAL_WARN_IF( m_xTargetContext == nullptr, "vcl.quartz", "Target layer 
is NULL");
+        CGContextDrawLayerAtPoint( m_xTempContext, CGPointZero, m_xTargetLayer 
);
+    }
+    // do a manual XOR with the XorMask
+    // this approach suffices for simple color manipulations
+    // and also the complex-clipping-XOR-trick used in metafiles
+    const sal_uLong* pSrc = m_pMaskBuffer;
+    sal_uLong* pDst = m_pTempBuffer;
+    for( int i = m_nBufferLongs; --i >= 0;)
+    {
+        *(pDst++) ^= *(pSrc++);
+    }
+    // write back the XOR results to the target context
+    if( m_xTempContext )
+    {
+        CGImageRef xXorImage = CGBitmapContextCreateImage( m_xTempContext );
+        const int nWidth  = static_cast<int>(CGImageGetWidth( xXorImage ));
+        const int nHeight = static_cast<int>(CGImageGetHeight( xXorImage ));
+        // TODO: update minimal changerect
+        const CGRect aFullRect = CGRectMake(0, 0, nWidth, nHeight);
+        CGContextDrawImage( m_xTargetContext, aFullRect, xXorImage );
+        CGImageRelease( xXorImage );
+    }
+
+    // reset the XorMask to black again
+    // TODO: not needed for last update
+    memset( m_pMaskBuffer, 0, m_nBufferLongs * sizeof(sal_uLong) );
+
+    // TODO: return FALSE if target was not changed
+    return true;
+}
+
 /// From salvd.cxx
 
 void AquaSalVirtualDevice::Destroy()
diff --git a/vcl/osx/salmacos.cxx b/vcl/osx/salmacos.cxx
index 24a4b5b5a4d6..e6573e101b61 100644
--- a/vcl/osx/salmacos.cxx
+++ b/vcl/osx/salmacos.cxx
@@ -285,6 +285,158 @@ void AquaSalGraphics::SetVirDevGraphics(CGLayerHolder 
const &rLayer, CGContextRe
              " (" << mnWidth << "x" << mnHeight << ") fScale=" << fScale << " 
mnBitmapDepth=" << mnBitmapDepth);
 }
 
+void XorEmulation::SetTarget(int nWidth, int nHeight, int nTargetDepth, 
CGContextRef xTargetContext, CGLayerRef xTargetLayer)
+{
+    SAL_INFO("vcl.quartz", "XorEmulation::SetTarget() this=" << this <<
+             " (" << nWidth << "x" << nHeight << ") depth=" << nTargetDepth <<
+             " context=" << xTargetContext << " layer=" << xTargetLayer);
+
+    // Prepare to replace old mask and temporary context
+
+    if (m_xMaskContext)
+    {
+        CGContextRelease(m_xMaskContext);
+        delete[] m_pMaskBuffer;
+        m_xMaskContext = nullptr;
+        m_pMaskBuffer = nullptr;
+        if (m_xTempContext)
+        {
+            CGContextRelease(m_xTempContext);
+            delete[] m_pTempBuffer;
+            m_xTempContext = nullptr;
+            m_pTempBuffer = nullptr;
+        }
+    }
+
+    // Return early if there is nothing more to do
+
+    if (!xTargetContext)
+        return;
+
+    // Retarget drawing operations to the XOR mask
+
+    m_xTargetLayer = xTargetLayer;
+    m_xTargetContext = xTargetContext;
+
+    // Prepare creation of matching bitmaps
+
+    CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace;
+    CGBitmapInfo aCGBmpInfo = kCGImageAlphaNoneSkipFirst;
+    int nBitDepth = nTargetDepth;
+    if (!nBitDepth)
+        nBitDepth = 32;
+    int nBytesPerRow = 4;
+    const size_t nBitsPerComponent = (nBitDepth == 16) ? 5 : 8;
+    if (nBitDepth <= 8)
+    {
+        aCGColorSpace = GetSalData()->mxGraySpace;
+        aCGBmpInfo = kCGImageAlphaNone;
+        nBytesPerRow = 1;
+    }
+    float fScale = AquaSalGraphics::GetWindowScaling();
+    size_t nScaledWidth = nWidth * fScale;
+    size_t nScaledHeight = nHeight * fScale;
+    nBytesPerRow *= nScaledWidth;
+    m_nBufferLongs = (nScaledHeight * nBytesPerRow + sizeof(sal_uLong) - 1) / 
sizeof(sal_uLong);
+
+    // Create XOR mask context
+
+    m_pMaskBuffer = new sal_uLong[m_nBufferLongs];
+    m_xMaskContext = CGBitmapContextCreate(m_pMaskBuffer, nScaledWidth, 
nScaledHeight,
+                                           nBitsPerComponent, nBytesPerRow, 
aCGColorSpace, aCGBmpInfo);
+    SAL_WARN_IF(!m_xMaskContext, "vcl.quartz", "mask context creation failed");
+
+    // Reset XOR mask to black
+
+    memset(m_pMaskBuffer, 0, m_nBufferLongs * sizeof(sal_uLong));
+
+    // Create bitmap context for manual XOR unless target context is a bitmap 
context
+
+    if (nTargetDepth)
+        m_pTempBuffer = 
static_cast<sal_uLong*>(CGBitmapContextGetData(m_xTargetContext));
+    if (!m_pTempBuffer)
+    {
+        m_pTempBuffer = new sal_uLong[m_nBufferLongs];
+        m_xTempContext = CGBitmapContextCreate(m_pTempBuffer, nScaledWidth, 
nScaledHeight,
+                                               nBitsPerComponent, 
nBytesPerRow, aCGColorSpace, aCGBmpInfo);
+        SAL_WARN_IF(!m_xTempContext, "vcl.quartz", "temp context creation 
failed");
+    }
+
+    // Initialize XOR mask context for drawing
+
+    CGContextSetFillColorSpace(m_xMaskContext, aCGColorSpace);
+    CGContextSetStrokeColorSpace(m_xMaskContext, aCGColorSpace);
+    CGContextSetShouldAntialias(m_xMaskContext, false);
+
+    // Improve XOR emulation for monochrome contexts
+
+    if (aCGColorSpace == GetSalData()->mxGraySpace)
+        CGContextSetBlendMode(m_xMaskContext, kCGBlendModeDifference);
+
+    // Initialize XOR mask transformation matrix and apply scale matrix to 
consider layer scaling
+
+    const CGAffineTransform aCTM = CGContextGetCTM(xTargetContext);
+    CGContextConcatCTM(m_xMaskContext, aCTM);
+    if (m_xTempContext)
+    {
+        CGContextConcatCTM( m_xTempContext, aCTM );
+        CGContextScaleCTM(m_xTempContext, 1 / fScale, 1 / fScale);
+    }
+    CGContextSaveGState(m_xMaskContext);
+}
+
+bool XorEmulation::UpdateTarget()
+{
+    SAL_INFO("vcl.quartz", "XorEmulation::UpdateTarget() this=" << this);
+
+    if (!IsEnabled())
+        return false;
+
+    // Update temporary bitmap buffer
+
+    if (m_xTempContext)
+    {
+        SAL_WARN_IF(m_xTargetContext == nullptr, "vcl.quartz", "Target layer 
is NULL");
+        CGContextDrawLayerAtPoint(m_xTempContext, CGPointZero, m_xTargetLayer);
+    }
+
+    // XOR using XOR mask (sufficient for simple color manipulations as well 
as for complex XOR clipping used in metafiles)
+
+    const sal_uLong *pSrc = m_pMaskBuffer;
+    sal_uLong *pDst = m_pTempBuffer;
+    for (int i = m_nBufferLongs; --i >= 0;)
+        *(pDst++) ^= *(pSrc++);
+
+    // Write back XOR results to target context
+
+    if (m_xTempContext)
+    {
+        CGImageRef xXorImage = CGBitmapContextCreateImage(m_xTempContext);
+        size_t nWidth = CGImageGetWidth(xXorImage);
+        size_t nHeight = CGImageGetHeight(xXorImage);
+
+        // Set scale matrix of target context to consider layer scaling and 
update target context
+        // TODO: Update minimal change rectangle
+
+        const CGRect aFullRect = CGRectMake(0, 0, nWidth, nHeight);
+        CGContextSaveGState(m_xTargetContext);
+        float fScale = AquaSalGraphics::GetWindowScaling();
+        CGContextScaleCTM(m_xTargetContext, 1 / fScale, 1 / fScale);
+        CGContextDrawImage(m_xTargetContext, aFullRect, xXorImage);
+        CGContextRestoreGState(m_xTargetContext);
+        CGImageRelease(xXorImage);
+    }
+
+    // Reset XOR mask to black again
+    // TODO: Not needed for last update
+
+    memset(m_pMaskBuffer, 0, m_nBufferLongs * sizeof(sal_uLong));
+
+    // TODO: Return FALSE if target was not changed
+
+    return true;
+}
+
 // From salvd.cxx
 
 void AquaSalVirtualDevice::Destroy()
diff --git a/vcl/quartz/salgdicommon.cxx b/vcl/quartz/salgdicommon.cxx
index bbfe185b73d2..e393659658d6 100644
--- a/vcl/quartz/salgdicommon.cxx
+++ b/vcl/quartz/salgdicommon.cxx
@@ -1544,151 +1544,4 @@ XorEmulation::~XorEmulation()
     SetTarget( 0, 0, 0, nullptr, nullptr );
 }
 
-void XorEmulation::SetTarget( int nWidth, int nHeight, int nTargetDepth,
-                              CGContextRef xTargetContext, CGLayerRef 
xTargetLayer )
-{
-    SAL_INFO( "vcl.quartz", "XorEmulation::SetTarget() this=" << this <<
-              " (" << nWidth << "x" << nHeight << ") depth=" << nTargetDepth <<
-              " context=" << xTargetContext << " layer=" << xTargetLayer );
-
-    // prepare to replace old mask+temp context
-    if( m_xMaskContext )
-    {
-        // cleanup the mask context
-        CGContextRelease( m_xMaskContext );
-        delete[] m_pMaskBuffer;
-        m_xMaskContext = nullptr;
-        m_pMaskBuffer = nullptr;
-
-        // cleanup the temp context if needed
-        if( m_xTempContext )
-        {
-            CGContextRelease( m_xTempContext );
-            delete[] m_pTempBuffer;
-            m_xTempContext = nullptr;
-            m_pTempBuffer = nullptr;
-        }
-    }
-
-    // return early if there is nothing more to do
-    if( !xTargetContext )
-    {
-        return;
-    }
-    // retarget drawing operations to the XOR mask
-    m_xTargetLayer = xTargetLayer;
-    m_xTargetContext = xTargetContext;
-
-    // prepare creation of matching CGBitmaps
-    CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace;
-    CGBitmapInfo aCGBmpInfo = kCGImageAlphaNoneSkipFirst;
-    int nBitDepth = nTargetDepth;
-    if( !nBitDepth )
-    {
-        nBitDepth = 32;
-    }
-    int nBytesPerRow = 4;
-    const size_t nBitsPerComponent = (nBitDepth == 16) ? 5 : 8;
-    if( nBitDepth <= 8 )
-    {
-        aCGColorSpace = GetSalData()->mxGraySpace;
-        aCGBmpInfo = kCGImageAlphaNone;
-        nBytesPerRow = 1;
-    }
-    nBytesPerRow *= nWidth;
-    m_nBufferLongs = (nHeight * nBytesPerRow + sizeof(sal_uLong)-1) / 
sizeof(sal_uLong);
-
-    // create a XorMask context
-    m_pMaskBuffer = new sal_uLong[ m_nBufferLongs ];
-    m_xMaskContext = CGBitmapContextCreate( m_pMaskBuffer,
-                                            nWidth, nHeight,
-                                            nBitsPerComponent, nBytesPerRow,
-                                            aCGColorSpace, aCGBmpInfo );
-    SAL_WARN_IF( !m_xMaskContext, "vcl.quartz", "mask context creation failed" 
);
-
-    // reset the XOR mask to black
-    memset( m_pMaskBuffer, 0, m_nBufferLongs * sizeof(sal_uLong) );
-
-    // a bitmap context will be needed for manual XORing
-    // create one unless the target context is a bitmap context
-    if( nTargetDepth )
-    {
-        m_pTempBuffer = static_cast<sal_uLong*>(CGBitmapContextGetData( 
m_xTargetContext ));
-    }
-    if( !m_pTempBuffer )
-    {
-        // create a bitmap context matching to the target context
-        m_pTempBuffer = new sal_uLong[ m_nBufferLongs ];
-        m_xTempContext = CGBitmapContextCreate( m_pTempBuffer,
-                                                nWidth, nHeight,
-                                                nBitsPerComponent, 
nBytesPerRow,
-                                                aCGColorSpace, aCGBmpInfo );
-        SAL_WARN_IF( !m_xTempContext, "vcl.quartz", "temp context creation 
failed" );
-    }
-
-    // initialize XOR mask context for drawing
-    CGContextSetFillColorSpace( m_xMaskContext, aCGColorSpace );
-    CGContextSetStrokeColorSpace( m_xMaskContext, aCGColorSpace );
-    CGContextSetShouldAntialias( m_xMaskContext, false );
-
-    // improve the XorMask's XOR emulation a little
-    // NOTE: currently only enabled for monochrome contexts
-    if( aCGColorSpace == GetSalData()->mxGraySpace )
-    {
-        CGContextSetBlendMode( m_xMaskContext, kCGBlendModeDifference );
-    }
-    // initialize the transformation matrix to the drawing target
-    const CGAffineTransform aCTM = CGContextGetCTM( xTargetContext );
-    CGContextConcatCTM( m_xMaskContext, aCTM );
-    if( m_xTempContext )
-    {
-        CGContextConcatCTM( m_xTempContext, aCTM );
-    }
-    // initialize the default XorMask graphics state
-    CGContextSaveGState( m_xMaskContext );
-}
-
-bool XorEmulation::UpdateTarget()
-{
-    SAL_INFO( "vcl.quartz", "XorEmulation::UpdateTarget() this=" << this );
-
-    if( !IsEnabled() )
-    {
-        return false;
-    }
-    // update the temp bitmap buffer if needed
-    if( m_xTempContext )
-    {
-        SAL_WARN_IF( m_xTargetContext == nullptr, "vcl.quartz", "Target layer 
is NULL");
-        CGContextDrawLayerAtPoint( m_xTempContext, CGPointZero, m_xTargetLayer 
);
-    }
-    // do a manual XOR with the XorMask
-    // this approach suffices for simple color manipulations
-    // and also the complex-clipping-XOR-trick used in metafiles
-    const sal_uLong* pSrc = m_pMaskBuffer;
-    sal_uLong* pDst = m_pTempBuffer;
-    for( int i = m_nBufferLongs; --i >= 0;)
-    {
-        *(pDst++) ^= *(pSrc++);
-    }
-    // write back the XOR results to the target context
-    if( m_xTempContext )
-    {
-        CGImageRef xXorImage = CGBitmapContextCreateImage( m_xTempContext );
-        const int nWidth  = static_cast<int>(CGImageGetWidth( xXorImage ));
-        const int nHeight = static_cast<int>(CGImageGetHeight( xXorImage ));
-        // TODO: update minimal changerect
-        const CGRect aFullRect = CGRectMake(0, 0, nWidth, nHeight);
-        CGContextDrawImage( m_xTargetContext, aFullRect, xXorImage );
-        CGImageRelease( xXorImage );
-    }
-
-    // reset the XorMask to black again
-    // TODO: not needed for last update
-    memset( m_pMaskBuffer, 0, m_nBufferLongs * sizeof(sal_uLong) );
-
-    // TODO: return FALSE if target was not changed
-    return true;
-}
-
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to