diff --git a/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx b/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx index 28d34bd3b992..c7565fb8502c 100644 --- a/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx +++ b/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx @@ -431,10 +431,10 @@ nMinimalDiscreteSquareSizeToBuffer(nMinimalDiscreteSize* nMinimalDiscreteSize); class CairoSurfaceHelper { // the buffered CairoSurface (bitmap data) - cairo_surface_t* mpCairoSurface; + cairo::CairoSurfaceSharedPtr mpCairoSurface; // evtl. MipMapped data (pre-scale to reduce data processing load) - mutable std::unordered_map maDownscaled; + mutable std::unordered_map maDownscaled; // create 32bit RGBA data for given Bitmap void createRGBA(const Bitmap& rBitmap) @@ -442,15 +442,17 @@ class CairoSurfaceHelper BitmapScopedReadAccess pReadAccess(rBitmap); const tools::Long nHeight(pReadAccess->Height()); const tools::Long nWidth(pReadAccess->Width()); - mpCairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, nWidth, nHeight); - if (cairo_surface_status(mpCairoSurface) != CAIRO_STATUS_SUCCESS) + mpCairoSurface = cairo::CairoSurfaceSharedPtr( + cairo_image_surface_create(CAIRO_FORMAT_ARGB32, nWidth, nHeight), + &cairo_surface_destroy); + if (cairo_surface_status(mpCairoSurface.get()) != CAIRO_STATUS_SUCCESS) { SAL_WARN("drawinglayer", "cairo_image_surface_create failed for: " << nWidth << " x " << nHeight); return; } const sal_uInt32 nStride(cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, nWidth)); - unsigned char* surfaceData(cairo_image_surface_get_data(mpCairoSurface)); + unsigned char* surfaceData(cairo_image_surface_get_data(mpCairoSurface.get())); for (tools::Long y(0); y < nHeight; ++y) { @@ -469,7 +471,7 @@ class CairoSurfaceHelper } } - cairo_surface_mark_dirty(mpCairoSurface); + cairo_surface_mark_dirty(mpCairoSurface.get()); } // create 32bit RGB data for given Bitmap @@ -478,15 +480,17 @@ class CairoSurfaceHelper BitmapScopedReadAccess pReadAccess(rBitmap); const tools::Long nHeight(pReadAccess->Height()); const tools::Long nWidth(pReadAccess->Width()); - mpCairoSurface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, nWidth, nHeight); - if (cairo_surface_status(mpCairoSurface) != CAIRO_STATUS_SUCCESS) + mpCairoSurface = cairo::CairoSurfaceSharedPtr( + cairo_image_surface_create(CAIRO_FORMAT_RGB24, nWidth, nHeight), + &cairo_surface_destroy); + if (cairo_surface_status(mpCairoSurface.get()) != CAIRO_STATUS_SUCCESS) { SAL_WARN("drawinglayer", "cairo_image_surface_create failed for: " << nWidth << " x " << nHeight); return; } sal_uInt32 nStride(cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, nWidth)); - unsigned char* surfaceData(cairo_image_surface_get_data(mpCairoSurface)); + unsigned char* surfaceData(cairo_image_surface_get_data(mpCairoSurface.get())); for (tools::Long y(0); y < nHeight; ++y) { @@ -504,7 +508,7 @@ class CairoSurfaceHelper } } - cairo_surface_mark_dirty(mpCairoSurface); + cairo_surface_mark_dirty(mpCairoSurface.get()); } // #define TEST_RGB16 @@ -553,7 +557,7 @@ public: CairoSurfaceHelper(const Bitmap& rBitmap) // When using a cairo-backed Bitmap (i.e. SvpSalBitmap), we can avoid a lot of copying, // which is beneficial for documents with lots of large images. Try to access directly. - : mpCairoSurface(static_cast(rBitmap.tryToGetCairoSurface())) + : mpCairoSurface(rBitmap.tryToGetCairoSurface()) , maDownscaled() { if (nullptr != mpCairoSurface) @@ -569,18 +573,8 @@ public: #endif } - ~CairoSurfaceHelper() - { - // cleanup surface - cairo_surface_destroy(mpCairoSurface); - - // cleanup MipMap surfaces - for (auto& candidate : maDownscaled) - cairo_surface_destroy(candidate.second); - } - - cairo_surface_t* getCairoSurface(sal_uInt32 nTargetWidth = 0, - sal_uInt32 nTargetHeight = 0) const + cairo::CairoSurfaceSharedPtr getCairoSurface(sal_uInt32 nTargetWidth = 0, + sal_uInt32 nTargetHeight = 0) const { // in simple cases just return the single created surface if (bDisableDownScale || nullptr == mpCairoSurface || 0 == nTargetWidth @@ -588,8 +582,8 @@ public: return mpCairoSurface; // get width/height of original surface - const sal_uInt32 nSourceWidth(cairo_image_surface_get_width(mpCairoSurface)); - const sal_uInt32 nSourceHeight(cairo_image_surface_get_height(mpCairoSurface)); + const sal_uInt32 nSourceWidth(cairo_image_surface_get_width(mpCairoSurface.get())); + const sal_uInt32 nSourceHeight(cairo_image_surface_get_height(mpCairoSurface.get())); // zoomed in on both axes, need to stretch at paint, no pre-scale useful if (nTargetWidth >= nSourceWidth && nTargetHeight >= nSourceHeight) @@ -639,15 +633,17 @@ public: return isHit->second; // create new surface in the targeted size - cairo_surface_t* pSurfaceTarget(cairo_surface_create_similar( - mpCairoSurface, cairo_surface_get_content(mpCairoSurface), nW, nH)); + cairo::CairoSurfaceSharedPtr pSurfaceTarget( + cairo_surface_create_similar(mpCairoSurface.get(), + cairo_surface_get_content(mpCairoSurface.get()), nW, nH), + &cairo_surface_destroy); - cairo_t* cr = cairo_create(pSurfaceTarget); + cairo_t* cr = cairo_create(pSurfaceTarget.get()); const double fScaleX(static_cast(nW) / static_cast(nSourceWidth)); const double fScaleY(static_cast(nH) / static_cast(nSourceHeight)); cairo_scale(cr, fScaleX, fScaleY); - cairo_set_source_surface(cr, mpCairoSurface, 0.0, 0.0); + cairo_set_source_surface(cr, mpCairoSurface.get(), 0.0, 0.0); cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_GOOD); cairo_paint(cr); cairo_destroy(cr); @@ -667,8 +663,8 @@ public: if (nullptr == mpCairoSurface) return true; - const sal_uInt32 nSourceWidth(cairo_image_surface_get_width(mpCairoSurface)); - const sal_uInt32 nSourceHeight(cairo_image_surface_get_height(mpCairoSurface)); + const sal_uInt32 nSourceWidth(cairo_image_surface_get_width(mpCairoSurface.get())); + const sal_uInt32 nSourceHeight(cairo_image_surface_get_height(mpCairoSurface.get())); return nSourceWidth * nSourceHeight < nMinimalDiscreteSquareSizeToBuffer; } @@ -714,9 +710,9 @@ sal_uInt32 SystemDependentData_CairoSurface::calculateCombinedHoldCyclesInSecond // To detect 'big' graphics, compare to an assumed ScreenSize (may also // be fetched from real screen if needed). To react, create a buffer // residing time of one hour (increase if needed). - cairo_surface_t* pSurface(mpCairoSurfaceHelper->getCairoSurface()); - const tools::Long nStride(cairo_image_surface_get_stride(pSurface)); - const tools::Long nHeight(cairo_image_surface_get_height(pSurface)); + cairo::CairoSurfaceSharedPtr pSurface(mpCairoSurfaceHelper->getCairoSurface()); + const tools::Long nStride(cairo_image_surface_get_stride(pSurface.get())); + const tools::Long nHeight(cairo_image_surface_get_height(pSurface.get())); // use a common big screen and assume 1/2 size of a graphic as 'big' const sal_Int64 nBigGraphicPixels((2560 * 1440) / 2); @@ -739,9 +735,9 @@ sal_Int64 SystemDependentData_CairoSurface::estimateUsageInBytes() const if (mpCairoSurfaceHelper) { - cairo_surface_t* pSurface(mpCairoSurfaceHelper->getCairoSurface()); - const tools::Long nStride(cairo_image_surface_get_stride(pSurface)); - const tools::Long nHeight(cairo_image_surface_get_height(pSurface)); + cairo::CairoSurfaceSharedPtr pSurface(mpCairoSurfaceHelper->getCairoSurface()); + const tools::Long nStride(cairo_image_surface_get_stride(pSurface.get())); + const tools::Long nHeight(cairo_image_surface_get_height(pSurface.get())); // w * h * 4 bytesPerPixel nRetval = nStride * nHeight * 4; @@ -760,7 +756,7 @@ sal_Int64 SystemDependentData_CairoSurface::estimateUsageInBytes() const std::shared_ptr getOrCreateCairoSurfaceHelper(const Bitmap& rBitmap) { - cairo_surface_t* pSurface(static_cast(rBitmap.tryToGetCairoSurface())); + cairo::CairoSurfaceSharedPtr pSurface(rBitmap.tryToGetCairoSurface()); if (nullptr != pSurface) { // in this case we get a cairo_surface_t directly from the underlying @@ -780,7 +776,8 @@ std::shared_ptr getOrCreateCairoSurfaceHelper(const Bitmap& // for !isCairoCompatible cases. const tools::Long aSmallBitmapSquareSize(160 * 100); - if (cairo_image_surface_get_stride(pSurface) * cairo_image_surface_get_height(pSurface) + if (cairo_image_surface_get_stride(pSurface.get()) + * cairo_image_surface_get_height(pSurface.get()) <= aSmallBitmapSquareSize) { // take the shortcut: For this small directly accessible size @@ -1435,8 +1432,9 @@ void CairoPixelProcessor2D::paintBitmapAlpha(const Bitmap& rBitmap, return; } - cairo_surface_t* pTarget(aCairoSurfaceHelper->getCairoSurface(nDestWidth, nDestHeight)); - if (nullptr == pTarget) + cairo::CairoSurfaceSharedPtr pTarget( + aCairoSurfaceHelper->getCairoSurface(nDestWidth, nDestHeight)); + if (!pTarget) { SAL_WARN("drawinglayer", "SDPRCairo: No CairoSurface from Bitmap SurfaceHelper (!)"); return; @@ -1460,7 +1458,7 @@ void CairoPixelProcessor2D::paintBitmapAlpha(const Bitmap& rBitmap, cairo_stroke(mpRT); } - cairo_set_source_surface(mpRT, pTarget, 0, 0); + cairo_set_source_surface(mpRT, pTarget.get(), 0, 0); // get the pattern created by cairo_set_source_surface and // it's transformation @@ -1485,8 +1483,8 @@ void CairoPixelProcessor2D::paintBitmapAlpha(const Bitmap& rBitmap, // simple (we are in unit coordinates) cairo_rectangle(mpRT, 0, 0, 1, 1); cairo_clip(mpRT); - cairo_matrix_scale(&aMatrix, cairo_image_surface_get_width(pTarget), - cairo_image_surface_get_height(pTarget)); + cairo_matrix_scale(&aMatrix, cairo_image_surface_get_width(pTarget.get()), + cairo_image_surface_get_height(pTarget.get())); // The alternative wpuld be: resize/scale it SLIGHTLY to force // that half pixel overlap to be inside the unit range. @@ -2224,15 +2222,15 @@ void CairoPixelProcessor2D::processMarkerArrayPrimitive2D( } // do not use dimensions, these are usually small instances - cairo_surface_t* pTarget(aCairoSurfaceHelper->getCairoSurface()); - if (nullptr == pTarget) + cairo::CairoSurfaceSharedPtr pTarget(aCairoSurfaceHelper->getCairoSurface()); + if (!pTarget) { SAL_WARN("drawinglayer", "SDPRCairo: No CairoSurface from Bitmap SurfaceHelper (!)"); return; } - const sal_uInt32 nWidth(cairo_image_surface_get_width(pTarget)); - const sal_uInt32 nHeight(cairo_image_surface_get_height(pTarget)); + const sal_uInt32 nWidth(cairo_image_surface_get_width(pTarget.get())); + const sal_uInt32 nHeight(cairo_image_surface_get_height(pTarget.get())); const tools::Long nMiX((nWidth / 2) + 1); const tools::Long nMiY((nHeight / 2) + 1); @@ -2248,7 +2246,7 @@ void CairoPixelProcessor2D::processMarkerArrayPrimitive2D( const double fX(ceil(aDiscretePos.getX())); const double fY(ceil(aDiscretePos.getY())); - cairo_set_source_surface(mpRT, pTarget, fX - nMiX, fY - nMiY); + cairo_set_source_surface(mpRT, pTarget.get(), fX - nMiX, fY - nMiY); cairo_paint(mpRT); } @@ -2716,8 +2714,9 @@ void CairoPixelProcessor2D::processFillGraphicPrimitive2D( return; } - cairo_surface_t* pTarget(aCairoSurfaceHelper->getCairoSurface(nDestWidth, nDestHeight)); - if (nullptr == pTarget) + cairo::CairoSurfaceSharedPtr pTarget( + aCairoSurfaceHelper->getCairoSurface(nDestWidth, nDestHeight)); + if (!pTarget) { SAL_WARN("drawinglayer", "SDPRCairo: No CairoSurface from Bitmap SurfaceHelper (!)"); return; @@ -2731,10 +2730,10 @@ void CairoPixelProcessor2D::processFillGraphicPrimitive2D( aLocalTransform.d(), aLocalTransform.e(), aLocalTransform.f()); cairo_set_matrix(mpRT, &aMatrix); - const sal_uInt32 nWidth(cairo_image_surface_get_width(pTarget)); - const sal_uInt32 nHeight(cairo_image_surface_get_height(pTarget)); + const sal_uInt32 nWidth(cairo_image_surface_get_width(pTarget.get())); + const sal_uInt32 nHeight(cairo_image_surface_get_height(pTarget.get())); - cairo_set_source_surface(mpRT, pTarget, 0, 0); + cairo_set_source_surface(mpRT, pTarget.get(), 0, 0); // get the pattern created by cairo_set_source_surface and // it's transformation @@ -2742,7 +2741,7 @@ void CairoPixelProcessor2D::processFillGraphicPrimitive2D( cairo_pattern_get_matrix(sourcepattern, &aMatrix); // clip for RGBA (see other places) - if (CAIRO_FORMAT_ARGB32 == cairo_image_surface_get_format(pTarget)) + if (CAIRO_FORMAT_ARGB32 == cairo_image_surface_get_format(pTarget.get())) { cairo_rectangle(mpRT, 0, 0, 1, 1); cairo_clip(mpRT); diff --git a/include/vcl/bitmap.hxx b/include/vcl/bitmap.hxx index 27ad60b8faf2..0c5557f6b281 100644 --- a/include/vcl/bitmap.hxx +++ b/include/vcl/bitmap.hxx @@ -101,6 +101,13 @@ class SalBitmap; namespace basegfx { class SystemDependentDataHolder; } +#if USE_HEADLESS_CODE +typedef struct _cairo_surface cairo_surface_t; +namespace cairo { + typedef std::shared_ptr CairoSurfaceSharedPtr; +} +#endif + struct BitmapSystemData { #if defined(_WIN32) @@ -721,7 +728,7 @@ public: void DumpAsPng(const char* pFileName = nullptr) const; #if USE_HEADLESS_CODE - void* tryToGetCairoSurface() const; + cairo::CairoSurfaceSharedPtr tryToGetCairoSurface() const; #endif private: diff --git a/vcl/source/bitmap/bitmap.cxx b/vcl/source/bitmap/bitmap.cxx index b6f1d693070f..38ac109dcd33 100644 --- a/vcl/source/bitmap/bitmap.cxx +++ b/vcl/source/bitmap/bitmap.cxx @@ -388,7 +388,7 @@ Bitmap& Bitmap::operator=( const Bitmap& rBitmap ) } #if USE_HEADLESS_CODE -void* Bitmap::tryToGetCairoSurface() const +cairo::CairoSurfaceSharedPtr Bitmap::tryToGetCairoSurface() const { SvpSalBitmap* pSvpSalBitmap(dynamic_cast(ImplGetSalBitmap().get())); if (nullptr == pSvpSalBitmap) @@ -398,7 +398,9 @@ void* Bitmap::tryToGetCairoSurface() const if (nullptr == pBitmapBuffer) return nullptr; - return CairoCommon::createCairoSurface(pBitmapBuffer); + return cairo::CairoSurfaceSharedPtr( + CairoCommon::createCairoSurface(pBitmapBuffer), + &cairo_surface_destroy); } #endif