summaryrefslogtreecommitdiffstats
path: root/vcl/source/gdi/bmpacc.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
commit940b4d1848e8c70ab7642901a68594e8016caffc (patch)
treeeb72f344ee6c3d9b80a7ecc079ea79e9fba8676d /vcl/source/gdi/bmpacc.cxx
parentInitial commit. (diff)
downloadlibreoffice-upstream.tar.xz
libreoffice-upstream.zip
Adding upstream version 1:7.0.4.upstream/1%7.0.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vcl/source/gdi/bmpacc.cxx')
-rw-r--r--vcl/source/gdi/bmpacc.cxx464
1 files changed, 464 insertions, 0 deletions
diff --git a/vcl/source/gdi/bmpacc.cxx b/vcl/source/gdi/bmpacc.cxx
new file mode 100644
index 000000000..6910c6e3e
--- /dev/null
+++ b/vcl/source/gdi/bmpacc.cxx
@@ -0,0 +1,464 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/bitmap.hxx>
+#include <vcl/bitmapaccess.hxx>
+
+#include <bitmapwriteaccess.hxx>
+#include <salbmp.hxx>
+#include <svdata.hxx>
+#include <salinst.hxx>
+
+#include <string.h>
+#include <sal/log.hxx>
+#include <tools/debug.hxx>
+
+BitmapInfoAccess::BitmapInfoAccess( Bitmap& rBitmap, BitmapAccessMode nMode ) :
+ mpBuffer ( nullptr ),
+ mnAccessMode ( nMode )
+{
+ std::shared_ptr<SalBitmap> xImpBmp = rBitmap.ImplGetSalBitmap();
+
+ assert( xImpBmp && "Forbidden Access to empty bitmap!" );
+
+ if( !xImpBmp )
+ return;
+
+ if (mnAccessMode == BitmapAccessMode::Write)
+ {
+ xImpBmp->DropScaledCache();
+
+ if (xImpBmp.use_count() > 2)
+ {
+ xImpBmp.reset();
+ rBitmap.ImplMakeUnique();
+ xImpBmp = rBitmap.ImplGetSalBitmap();
+ }
+ }
+
+ mpBuffer = xImpBmp->AcquireBuffer( mnAccessMode );
+
+ if( !mpBuffer )
+ {
+ std::shared_ptr<SalBitmap> xNewImpBmp(ImplGetSVData()->mpDefInst->CreateSalBitmap());
+ if (xNewImpBmp->Create(*xImpBmp, rBitmap.GetBitCount()))
+ {
+ xImpBmp = xNewImpBmp;
+ rBitmap.ImplSetSalBitmap( xImpBmp );
+ mpBuffer = xImpBmp->AcquireBuffer( mnAccessMode );
+ }
+ }
+
+ maBitmap = rBitmap;
+}
+
+BitmapInfoAccess::~BitmapInfoAccess()
+{
+ std::shared_ptr<SalBitmap> xImpBmp = maBitmap.ImplGetSalBitmap();
+
+ if (mpBuffer && xImpBmp)
+ {
+ xImpBmp->ReleaseBuffer( mpBuffer, mnAccessMode );
+ }
+}
+
+sal_uInt16 BitmapInfoAccess::GetBestPaletteIndex( const BitmapColor& rBitmapColor ) const
+{
+ return( HasPalette() ? mpBuffer->maPalette.GetBestIndex( rBitmapColor ) : 0 );
+}
+
+BitmapReadAccess::BitmapReadAccess( Bitmap& rBitmap, BitmapAccessMode nMode ) :
+ BitmapInfoAccess( rBitmap, nMode ),
+ mFncGetPixel ( nullptr ),
+ mFncSetPixel ( nullptr )
+{
+ if (!mpBuffer)
+ return;
+
+ const std::shared_ptr<SalBitmap>& xImpBmp = rBitmap.ImplGetSalBitmap();
+ if (!xImpBmp)
+ return;
+
+ maColorMask = mpBuffer->maColorMask;
+
+ bool bOk = ImplSetAccessPointers(RemoveScanline(mpBuffer->mnFormat));
+
+ if (!bOk)
+ {
+ xImpBmp->ReleaseBuffer( mpBuffer, mnAccessMode );
+ mpBuffer = nullptr;
+ }
+}
+
+BitmapReadAccess::~BitmapReadAccess()
+{
+}
+
+namespace
+{
+ bool Bitmap32IsPreMultipled()
+ {
+ auto pBackendCapabilities = ImplGetSVData()->mpDefInst->GetBackendCapabilities();
+ return pBackendCapabilities->mbSupportsBitmap32;
+ }
+}
+
+bool BitmapReadAccess::ImplSetAccessPointers( ScanlineFormat nFormat )
+{
+ bool bRet = true;
+
+ switch( nFormat )
+ {
+ case ScanlineFormat::N1BitMsbPal:
+ {
+ mFncGetPixel = GetPixelForN1BitMsbPal;
+ mFncSetPixel = SetPixelForN1BitMsbPal;
+ }
+ break;
+ case ScanlineFormat::N1BitLsbPal:
+ {
+ mFncGetPixel = GetPixelForN1BitLsbPal;
+ mFncSetPixel = SetPixelForN1BitLsbPal;
+ }
+ break;
+ case ScanlineFormat::N4BitMsnPal:
+ {
+ mFncGetPixel = GetPixelForN4BitMsnPal;
+ mFncSetPixel = SetPixelForN4BitMsnPal;
+ }
+ break;
+ case ScanlineFormat::N4BitLsnPal:
+ {
+ mFncGetPixel = GetPixelForN4BitLsnPal;
+ mFncSetPixel = SetPixelForN4BitLsnPal;
+ }
+ break;
+ case ScanlineFormat::N8BitPal:
+ {
+ mFncGetPixel = GetPixelForN8BitPal;
+ mFncSetPixel = SetPixelForN8BitPal;
+ }
+ break;
+ case ScanlineFormat::N8BitTcMask:
+ {
+ mFncGetPixel = GetPixelForN8BitTcMask;
+ mFncSetPixel = SetPixelForN8BitTcMask;
+ }
+ break;
+ case ScanlineFormat::N24BitTcBgr:
+ {
+ mFncGetPixel = GetPixelForN24BitTcBgr;
+ mFncSetPixel = SetPixelForN24BitTcBgr;
+ }
+ break;
+ case ScanlineFormat::N24BitTcRgb:
+ {
+ mFncGetPixel = GetPixelForN24BitTcRgb;
+ mFncSetPixel = SetPixelForN24BitTcRgb;
+ }
+ break;
+ case ScanlineFormat::N32BitTcAbgr:
+ {
+ if (Bitmap32IsPreMultipled())
+ {
+ mFncGetPixel = GetPixelForN32BitTcAbgr;
+ mFncSetPixel = SetPixelForN32BitTcAbgr;
+ }
+ else
+ {
+ mFncGetPixel = GetPixelForN32BitTcXbgr;
+ mFncSetPixel = SetPixelForN32BitTcXbgr;
+ }
+ }
+ break;
+ case ScanlineFormat::N32BitTcArgb:
+ {
+ if (Bitmap32IsPreMultipled())
+ {
+ mFncGetPixel = GetPixelForN32BitTcArgb;
+ mFncSetPixel = SetPixelForN32BitTcArgb;
+ }
+ else
+ {
+ mFncGetPixel = GetPixelForN32BitTcXrgb;
+ mFncSetPixel = SetPixelForN32BitTcXrgb;
+ }
+ }
+ break;
+ case ScanlineFormat::N32BitTcBgra:
+ {
+ if (Bitmap32IsPreMultipled())
+ {
+ mFncGetPixel = GetPixelForN32BitTcBgra;
+ mFncSetPixel = SetPixelForN32BitTcBgra;
+ }
+ else
+ {
+ mFncGetPixel = GetPixelForN32BitTcBgrx;
+ mFncSetPixel = SetPixelForN32BitTcBgrx;
+ }
+ }
+ break;
+ case ScanlineFormat::N32BitTcRgba:
+ {
+ if (Bitmap32IsPreMultipled())
+ {
+ mFncGetPixel = GetPixelForN32BitTcRgba;
+ mFncSetPixel = SetPixelForN32BitTcRgba;
+ }
+ else
+ {
+ mFncGetPixel = GetPixelForN32BitTcRgbx;
+ mFncSetPixel = SetPixelForN32BitTcRgbx;
+ }
+ }
+ break;
+ case ScanlineFormat::N32BitTcMask:
+ {
+ mFncGetPixel = GetPixelForN32BitTcMask;
+ mFncSetPixel = SetPixelForN32BitTcMask;
+ }
+ break;
+
+ default:
+ bRet = false;
+ break;
+ }
+
+ return bRet;
+}
+
+BitmapColor BitmapReadAccess::GetInterpolatedColorWithFallback( double fY, double fX, const BitmapColor& rFallback ) const
+{
+ // ask directly doubles >= 0.0 here to avoid rounded values of 0 at small negative
+ // double values, e.g. static_cast< sal_Int32 >(-0.25) is 0, not -1, but *has* to be outside (!)
+ if(mpBuffer && fX >= 0.0 && fY >= 0.0)
+ {
+ const sal_Int64 nX(static_cast<sal_Int64>(fX));
+ const sal_Int64 nY(static_cast<sal_Int64>(fY));
+
+ if(nX < mpBuffer->mnWidth && nY < mpBuffer->mnHeight)
+ {
+ // get base-return value from inside pixel
+ BitmapColor aRetval(GetColor(nY, nX));
+
+ // calculate deltas and indices for neighbour accesses
+ sal_Int16 nDeltaX((fX - (nX + 0.5)) * 255.0); // [-255 .. 255]
+ sal_Int16 nDeltaY((fY - (nY + 0.5)) * 255.0); // [-255 .. 255]
+ sal_Int16 nIndX(0);
+ sal_Int16 nIndY(0);
+
+ if(nDeltaX > 0)
+ {
+ nIndX = nX + 1;
+ }
+ else
+ {
+ nIndX = nX - 1;
+ nDeltaX = -nDeltaX;
+ }
+
+ if(nDeltaY > 0)
+ {
+ nIndY = nY + 1;
+ }
+ else
+ {
+ nIndY = nY - 1;
+ nDeltaY = -nDeltaY;
+ }
+
+ // get right/left neighbour
+ BitmapColor aXCol(rFallback);
+
+ if(nDeltaX && nIndX >= 0 && nIndX < mpBuffer->mnWidth)
+ {
+ aXCol = GetColor(nY, nIndX);
+ }
+
+ // get top/bottom neighbour
+ BitmapColor aYCol(rFallback);
+
+ if(nDeltaY && nIndY >= 0 && nIndY < mpBuffer->mnHeight)
+ {
+ aYCol = GetColor(nIndY, nX);
+ }
+
+ // get one of four edge neighbours
+ BitmapColor aXYCol(rFallback);
+
+ if(nDeltaX && nDeltaY && nIndX >=0 && nIndY >= 0 && nIndX < mpBuffer->mnWidth && nIndY < mpBuffer->mnHeight)
+ {
+ aXYCol = GetColor(nIndY, nIndX);
+ }
+
+ // merge return value with right/left neighbour
+ if(aXCol != aRetval)
+ {
+ aRetval.Merge(aXCol, 255 - nDeltaX);
+ }
+
+ // merge top/bottom neighbour with edge
+ if(aYCol != aXYCol)
+ {
+ aYCol.Merge(aXYCol, 255 - nDeltaX);
+ }
+
+ // merge return value with already merged top/bottom neighbour
+ if(aRetval != aYCol)
+ {
+ aRetval.Merge(aYCol, 255 - nDeltaY);
+ }
+
+ return aRetval;
+ }
+ }
+
+ return rFallback;
+}
+
+BitmapColor BitmapReadAccess::GetColorWithFallback( double fY, double fX, const BitmapColor& rFallback ) const
+{
+ // ask directly doubles >= 0.0 here to avoid rounded values of 0 at small negative
+ // double values, e.g. static_cast< sal_Int32 >(-0.25) is 0, not -1, but *has* to be outside (!)
+ if(mpBuffer && fX >= 0.0 && fY >= 0.0)
+ {
+ const sal_Int32 nX(static_cast< sal_Int32 >(fX));
+ const sal_Int32 nY(static_cast< sal_Int32 >(fY));
+
+ if(nX < mpBuffer->mnWidth && nY < mpBuffer->mnHeight)
+ {
+ return GetColor(nY, nX);
+ }
+ }
+
+ return rFallback;
+}
+
+BitmapWriteAccess::BitmapWriteAccess(Bitmap& rBitmap)
+ : BitmapReadAccess(rBitmap, BitmapAccessMode::Write)
+{
+}
+
+BitmapWriteAccess::~BitmapWriteAccess()
+{
+}
+
+void BitmapWriteAccess::CopyScanline( long nY, const BitmapReadAccess& rReadAcc )
+{
+ assert(nY >= 0 && nY < mpBuffer->mnHeight && "y-coordinate in destination out of range!");
+ SAL_WARN_IF( nY >= rReadAcc.Height(), "vcl", "y-coordinate in source out of range!" );
+ SAL_WARN_IF( ( !HasPalette() || !rReadAcc.HasPalette() ) && ( HasPalette() || rReadAcc.HasPalette() ), "vcl", "No copying possible between palette bitmap and TC bitmap!" );
+
+ if( ( GetScanlineFormat() == rReadAcc.GetScanlineFormat() ) &&
+ ( GetScanlineSize() >= rReadAcc.GetScanlineSize() ) )
+ {
+ memcpy(GetScanline(nY), rReadAcc.GetScanline(nY), rReadAcc.GetScanlineSize());
+ }
+ else
+ {
+ // TODO: use fastbmp infrastructure
+ Scanline pScanline = GetScanline( nY );
+ Scanline pScanlineRead = rReadAcc.GetScanline(nY);
+ for( long nX = 0, nWidth = std::min( mpBuffer->mnWidth, rReadAcc.Width() ); nX < nWidth; nX++ )
+ SetPixelOnData( pScanline, nX, rReadAcc.GetPixelFromData( pScanlineRead, nX ) );
+ }
+}
+
+void BitmapWriteAccess::CopyScanline( long nY, ConstScanline aSrcScanline,
+ ScanlineFormat nSrcScanlineFormat, sal_uInt32 nSrcScanlineSize )
+{
+ const ScanlineFormat nFormat = RemoveScanline( nSrcScanlineFormat );
+
+ assert(nY >= 0 && nY < mpBuffer->mnHeight && "y-coordinate in destination out of range!");
+ DBG_ASSERT( ( HasPalette() && nFormat <= ScanlineFormat::N8BitPal ) ||
+ ( !HasPalette() && nFormat > ScanlineFormat::N8BitPal ),
+ "No copying possible between palette and non palette scanlines!" );
+
+ const sal_uLong nCount = std::min( GetScanlineSize(), nSrcScanlineSize );
+
+ if( nCount )
+ {
+ if( GetScanlineFormat() == RemoveScanline( nSrcScanlineFormat ) )
+ memcpy(GetScanline(nY), aSrcScanline, nCount);
+ else
+ {
+ DBG_ASSERT( nFormat != ScanlineFormat::N8BitTcMask &&
+ nFormat != ScanlineFormat::N32BitTcMask,
+ "No support for pixel formats with color masks yet!" );
+
+ // TODO: use fastbmp infrastructure
+ FncGetPixel pFncGetPixel;
+
+ switch( nFormat )
+ {
+ case ScanlineFormat::N1BitMsbPal: pFncGetPixel = GetPixelForN1BitMsbPal; break;
+ case ScanlineFormat::N1BitLsbPal: pFncGetPixel = GetPixelForN1BitLsbPal; break;
+ case ScanlineFormat::N4BitMsnPal: pFncGetPixel = GetPixelForN4BitMsnPal; break;
+ case ScanlineFormat::N4BitLsnPal: pFncGetPixel = GetPixelForN4BitLsnPal; break;
+ case ScanlineFormat::N8BitPal: pFncGetPixel = GetPixelForN8BitPal; break;
+ case ScanlineFormat::N8BitTcMask: pFncGetPixel = GetPixelForN8BitTcMask; break;
+ case ScanlineFormat::N24BitTcBgr: pFncGetPixel = GetPixelForN24BitTcBgr; break;
+ case ScanlineFormat::N24BitTcRgb: pFncGetPixel = GetPixelForN24BitTcRgb; break;
+ case ScanlineFormat::N32BitTcAbgr:
+ if (Bitmap32IsPreMultipled())
+ pFncGetPixel = GetPixelForN32BitTcAbgr;
+ else
+ pFncGetPixel = GetPixelForN32BitTcXbgr;
+ break;
+ case ScanlineFormat::N32BitTcArgb:
+ if (Bitmap32IsPreMultipled())
+ pFncGetPixel = GetPixelForN32BitTcArgb;
+ else
+ pFncGetPixel = GetPixelForN32BitTcXrgb;
+ break;
+ case ScanlineFormat::N32BitTcBgra:
+ if (Bitmap32IsPreMultipled())
+ pFncGetPixel = GetPixelForN32BitTcBgra;
+ else
+ pFncGetPixel = GetPixelForN32BitTcBgrx;
+ break;
+ case ScanlineFormat::N32BitTcRgba:
+ if (Bitmap32IsPreMultipled())
+ pFncGetPixel = GetPixelForN32BitTcRgba;
+ else
+ pFncGetPixel = GetPixelForN32BitTcRgbx;
+ break;
+ case ScanlineFormat::N32BitTcMask:
+ pFncGetPixel = GetPixelForN32BitTcMask;
+ break;
+
+ default:
+ assert(false);
+ pFncGetPixel = nullptr;
+ break;
+ }
+
+ if( pFncGetPixel )
+ {
+ const ColorMask aDummyMask;
+ Scanline pScanline = GetScanline(nY);
+ for (long nX = 0, nWidth = mpBuffer->mnWidth; nX < nWidth; ++nX)
+ SetPixelOnData(pScanline, nX, pFncGetPixel(aSrcScanline, nX, aDummyMask));
+ }
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */