drawinglayer/source/processor2d/cairopixelprocessor2d.cxx | 151 +++++++++----- 1 file changed, 98 insertions(+), 53 deletions(-)
New commits: commit a3081afb197dfd55055657eb89c6305a24e9e530 Author: Armin Le Grand (Collabora) <armin.le.gr...@me.com> AuthorDate: Sat Jul 20 19:33:01 2024 +0200 Commit: Armin Le Grand <armin.le.gr...@me.com> CommitDate: Mon Jul 22 12:16:02 2024 +0200 CairoSDPR: Better support for XOR Change-Id: Ib6a8489e655640e7a12eaec943977867e94d2793 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170799 Tested-by: Jenkins Reviewed-by: Armin Le Grand <armin.le.gr...@me.com> diff --git a/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx b/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx index 492f50446f61..24695b0b0a8a 100644 --- a/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx +++ b/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx @@ -1212,74 +1212,119 @@ void CairoPixelProcessor2D::processInvertPrimitive2D( aContent.process(rInvertCandidate.getChildren()); cairo_surface_flush(pContent); - // get read access to target - XOR unfortunately needs that - cairo_surface_t* pRenderTarget(pTarget); + // decide if to use builtin or create XOR yourself + // NOTE: not using and doing self is closer to what the + // current default does, so keep it + static bool bUseBuiltinXOR(false); - if (CAIRO_SURFACE_TYPE_IMAGE != cairo_surface_get_type(pRenderTarget)) + if (!bUseBuiltinXOR) { - pRenderTarget = cairo_surface_map_to_image(pRenderTarget, nullptr); - } + // get read access to target - XOR unfortunately needs that + cairo_surface_t* pRenderTarget(pTarget); - // iterate over pre-rendered pContent, call Dst due to being changed - const sal_uInt32 nDstWidth(cairo_image_surface_get_width(pContent)); - const sal_uInt32 nDstHeight(cairo_image_surface_get_height(pContent)); - const sal_uInt32 nDstStride(cairo_image_surface_get_stride(pContent)); - unsigned char* pDstDataRoot(cairo_image_surface_get_data(pContent)); + if (CAIRO_SURFACE_TYPE_IMAGE != cairo_surface_get_type(pRenderTarget)) + { + pRenderTarget = cairo_surface_map_to_image(pRenderTarget, nullptr); + } - // in parallel, iterate over Src data - const sal_uInt32 nSrcOffX(floor(aVisibleRange.getMinX())); - const sal_uInt32 nSrcOffY(floor(aVisibleRange.getMinY())); - const sal_uInt32 nSrcStride(cairo_image_surface_get_stride(pRenderTarget)); - unsigned char* pSrcDataRoot(cairo_image_surface_get_data(pRenderTarget)); + // iterate over pre-rendered pContent (call it Front) + const sal_uInt32 nFrontWidth(cairo_image_surface_get_width(pContent)); + const sal_uInt32 nFrontHeight(cairo_image_surface_get_height(pContent)); + const sal_uInt32 nFrontStride(cairo_image_surface_get_stride(pContent)); + unsigned char* pFrontDataRoot(cairo_image_surface_get_data(pContent)); - if (nullptr != pDstDataRoot && nullptr != pSrcDataRoot) - { - for (sal_uInt32 y(0); y < nDstHeight; ++y) - { - // get mem locations - unsigned char* pDstData(pDstDataRoot + (nDstStride * y)); - unsigned char* pSrcData(pSrcDataRoot + (nSrcStride * (y + nSrcOffY)) + (nSrcOffX * 4)); + // in parallel, iterate over original data (call it Back) + const sal_uInt32 nBackOffX(floor(aVisibleRange.getMinX())); + const sal_uInt32 nBackOffY(floor(aVisibleRange.getMinY())); + const sal_uInt32 nBackStride(cairo_image_surface_get_stride(pRenderTarget)); + unsigned char* pBackDataRoot(cairo_image_surface_get_data(pRenderTarget)); - for (sal_uInt32 x(0); x < nDstWidth; ++x) + if (nullptr != pFrontDataRoot && nullptr != pBackDataRoot) + { + for (sal_uInt32 y(0); y < nFrontHeight; ++y) { - // do not forget pre-multiply -> need to get both alphas - sal_uInt8 nSrcAlpha(pSrcData[SVP_CAIRO_ALPHA]); - sal_uInt8 nDstAlpha(pDstData[SVP_CAIRO_ALPHA]); - - // create XOR r,g,b - const sal_uInt8 b( - vcl::bitmap::unpremultiply(nDstAlpha, pDstData[SVP_CAIRO_BLUE]) - ^ vcl::bitmap::unpremultiply(nSrcAlpha, pSrcData[SVP_CAIRO_BLUE])); - const sal_uInt8 g( - vcl::bitmap::unpremultiply(nDstAlpha, pDstData[SVP_CAIRO_GREEN]) - ^ vcl::bitmap::unpremultiply(nSrcAlpha, pSrcData[SVP_CAIRO_GREEN])); - const sal_uInt8 r(vcl::bitmap::unpremultiply(nDstAlpha, pDstData[SVP_CAIRO_RED]) - ^ vcl::bitmap::unpremultiply(nSrcAlpha, pSrcData[SVP_CAIRO_RED])); - - // write back - pDstData[SVP_CAIRO_BLUE] = vcl::bitmap::premultiply(nDstAlpha, b); - pDstData[SVP_CAIRO_GREEN] = vcl::bitmap::premultiply(nDstAlpha, g); - pDstData[SVP_CAIRO_RED] = vcl::bitmap::premultiply(nDstAlpha, r); - - // advance memory - pSrcData += 4; - pDstData += 4; + // get mem locations + unsigned char* pFrontData(pFrontDataRoot + (nFrontStride * y)); + unsigned char* pBackData(pBackDataRoot + (nBackStride * (y + nBackOffY)) + + (nBackOffX * 4)); + + for (sal_uInt32 x(0); x < nFrontWidth; ++x) + { + // do not forget pre-multiply -> need to get both alphas + const sal_uInt8 nBackAlpha(pBackData[SVP_CAIRO_ALPHA]); + const sal_uInt8 nFrontAlpha(pFrontData[SVP_CAIRO_ALPHA]); + + // only something to do if not fully transparent + if (0 != nFrontAlpha) + { + sal_uInt8 nFrontB(pFrontData[SVP_CAIRO_BLUE]); + sal_uInt8 nFrontG(pFrontData[SVP_CAIRO_GREEN]); + sal_uInt8 nFrontR(pFrontData[SVP_CAIRO_RED]); + + if (255 != nFrontAlpha) + { + nFrontB = vcl::bitmap::unpremultiply(nFrontAlpha, nFrontB); + nFrontG = vcl::bitmap::unpremultiply(nFrontAlpha, nFrontG); + nFrontR = vcl::bitmap::unpremultiply(nFrontAlpha, nFrontR); + } + + sal_uInt8 nBackB(pBackData[SVP_CAIRO_BLUE]); + sal_uInt8 nBackG(pBackData[SVP_CAIRO_GREEN]); + sal_uInt8 nBackR(pBackData[SVP_CAIRO_RED]); + + if (255 != nBackAlpha) + { + nBackB = vcl::bitmap::unpremultiply(nBackAlpha, nBackB); + nBackG = vcl::bitmap::unpremultiply(nBackAlpha, nBackG); + nBackR = vcl::bitmap::unpremultiply(nBackAlpha, nBackR); + } + + // create XOR r,g,b + const sal_uInt8 b(nFrontB ^ nBackB); + const sal_uInt8 g(nFrontG ^ nBackG); + const sal_uInt8 r(nFrontR ^ nBackR); + + // write back + if (255 == nFrontAlpha) + { + pFrontData[SVP_CAIRO_BLUE] = b; + pFrontData[SVP_CAIRO_GREEN] = g; + pFrontData[SVP_CAIRO_RED] = r; + } + else + { + pFrontData[SVP_CAIRO_BLUE] = vcl::bitmap::premultiply(nFrontAlpha, b); + pFrontData[SVP_CAIRO_GREEN] = vcl::bitmap::premultiply(nFrontAlpha, g); + pFrontData[SVP_CAIRO_RED] = vcl::bitmap::premultiply(nFrontAlpha, r); + } + } + + // advance memory + pBackData += 4; + pFrontData += 4; + } } - } - cairo_surface_mark_dirty(pContent); - } + cairo_surface_mark_dirty(pContent); + } - if (pRenderTarget != pTarget) - { - // cleanup mapping for read access to target - cairo_surface_unmap_image(pTarget, pRenderTarget); + if (pRenderTarget != pTarget) + { + // cleanup mapping for read access to target + cairo_surface_unmap_image(pTarget, pRenderTarget); + } } - // draw created XOR to target + // draw XOR to target cairo_set_source_surface(mpRT, pContent, aVisibleRange.getMinX(), aVisibleRange.getMinY()); cairo_rectangle(mpRT, aVisibleRange.getMinX(), aVisibleRange.getMinY(), aVisibleRange.getWidth(), aVisibleRange.getHeight()); + + if (bUseBuiltinXOR) + { + cairo_set_operator(mpRT, CAIRO_OPERATOR_XOR); + } + cairo_fill(mpRT); // cleanup temporary surface