b3566864db
Change-Id: I1d9f1dc96788530eb6a226a53a67764918348100 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145139 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caolanm@redhat.com>
689 lines
24 KiB
C++
689 lines
24 KiB
C++
/* -*- 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 <headless/SvpGraphicsBackend.hxx>
|
|
|
|
#include <sal/log.hxx>
|
|
#include <basegfx/matrix/b2dhommatrixtools.hxx>
|
|
#include <basegfx/polygon/b2dpolygontools.hxx>
|
|
#include <vcl/BitmapTools.hxx>
|
|
#include <headless/BitmapHelper.hxx>
|
|
|
|
SvpGraphicsBackend::SvpGraphicsBackend(CairoCommon& rCairoCommon)
|
|
: m_rCairoCommon(rCairoCommon)
|
|
{
|
|
}
|
|
|
|
void SvpGraphicsBackend::Init() {}
|
|
|
|
void SvpGraphicsBackend::freeResources() {}
|
|
|
|
void SvpGraphicsBackend::setClipRegion(const vcl::Region& i_rClip)
|
|
{
|
|
m_rCairoCommon.m_aClipRegion = i_rClip;
|
|
}
|
|
|
|
void SvpGraphicsBackend::ResetClipRegion() { m_rCairoCommon.m_aClipRegion.SetNull(); }
|
|
|
|
sal_uInt16 SvpGraphicsBackend::GetBitCount() const
|
|
{
|
|
if (cairo_surface_get_content(m_rCairoCommon.m_pSurface) != CAIRO_CONTENT_COLOR_ALPHA)
|
|
return 1;
|
|
return 32;
|
|
}
|
|
|
|
tools::Long SvpGraphicsBackend::GetGraphicsWidth() const
|
|
{
|
|
return m_rCairoCommon.m_pSurface ? m_rCairoCommon.m_aFrameSize.getX() : 0;
|
|
}
|
|
|
|
void SvpGraphicsBackend::SetLineColor() { m_rCairoCommon.m_oLineColor = std::nullopt; }
|
|
|
|
void SvpGraphicsBackend::SetLineColor(Color nColor) { m_rCairoCommon.m_oLineColor = nColor; }
|
|
|
|
void SvpGraphicsBackend::SetFillColor() { m_rCairoCommon.m_oFillColor = std::nullopt; }
|
|
|
|
void SvpGraphicsBackend::SetFillColor(Color nColor) { m_rCairoCommon.m_oFillColor = nColor; }
|
|
|
|
void SvpGraphicsBackend::SetXORMode(bool bSet, bool /*bInvertOnly*/)
|
|
{
|
|
m_rCairoCommon.m_ePaintMode = bSet ? PaintMode::Xor : PaintMode::Over;
|
|
}
|
|
|
|
void SvpGraphicsBackend::SetROPLineColor(SalROPColor nROPColor)
|
|
{
|
|
switch (nROPColor)
|
|
{
|
|
case SalROPColor::N0:
|
|
m_rCairoCommon.m_oLineColor = Color(0, 0, 0);
|
|
break;
|
|
case SalROPColor::N1:
|
|
m_rCairoCommon.m_oLineColor = Color(0xff, 0xff, 0xff);
|
|
break;
|
|
case SalROPColor::Invert:
|
|
m_rCairoCommon.m_oLineColor = Color(0xff, 0xff, 0xff);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void SvpGraphicsBackend::SetROPFillColor(SalROPColor nROPColor)
|
|
{
|
|
switch (nROPColor)
|
|
{
|
|
case SalROPColor::N0:
|
|
m_rCairoCommon.m_oFillColor = Color(0, 0, 0);
|
|
break;
|
|
case SalROPColor::N1:
|
|
m_rCairoCommon.m_oFillColor = Color(0xff, 0xff, 0xff);
|
|
break;
|
|
case SalROPColor::Invert:
|
|
m_rCairoCommon.m_oFillColor = Color(0xff, 0xff, 0xff);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void SvpGraphicsBackend::drawPixel(tools::Long nX, tools::Long nY)
|
|
{
|
|
drawPixel(nX, nY, *m_rCairoCommon.m_oLineColor);
|
|
}
|
|
|
|
void SvpGraphicsBackend::drawPixel(tools::Long nX, tools::Long nY, Color aColor)
|
|
{
|
|
cairo_t* cr = m_rCairoCommon.getCairoContext(true, getAntiAlias());
|
|
basegfx::B2DRange extents;
|
|
m_rCairoCommon.clipRegion(cr);
|
|
|
|
CairoCommon::drawPixel(cr, &extents, aColor, nX, nY);
|
|
|
|
m_rCairoCommon.releaseCairoContext(cr, true, extents);
|
|
}
|
|
|
|
void SvpGraphicsBackend::drawLine(tools::Long nX1, tools::Long nY1, tools::Long nX2,
|
|
tools::Long nY2)
|
|
{
|
|
cairo_t* cr = m_rCairoCommon.getCairoContext(false, getAntiAlias());
|
|
basegfx::B2DRange extents;
|
|
m_rCairoCommon.clipRegion(cr);
|
|
|
|
CairoCommon::drawLine(cr, &extents, *m_rCairoCommon.m_oLineColor, getAntiAlias(), nX1, nY1, nX2,
|
|
nY2);
|
|
|
|
m_rCairoCommon.releaseCairoContext(cr, false, extents);
|
|
}
|
|
|
|
void SvpGraphicsBackend::drawRect(tools::Long nX, tools::Long nY, tools::Long nWidth,
|
|
tools::Long nHeight)
|
|
{
|
|
cairo_t* cr = m_rCairoCommon.getCairoContext(true, getAntiAlias());
|
|
basegfx::B2DRange extents;
|
|
m_rCairoCommon.clipRegion(cr);
|
|
|
|
CairoCommon::drawRect(cr, &extents, m_rCairoCommon.m_oLineColor, m_rCairoCommon.m_oFillColor,
|
|
getAntiAlias(), nX, nY, nWidth, nHeight);
|
|
|
|
m_rCairoCommon.releaseCairoContext(cr, true, extents);
|
|
}
|
|
|
|
void SvpGraphicsBackend::drawPolyLine(sal_uInt32 nPoints, const Point* pPtAry)
|
|
{
|
|
cairo_t* cr = m_rCairoCommon.getCairoContext(false, getAntiAlias());
|
|
basegfx::B2DRange aExtents;
|
|
m_rCairoCommon.clipRegion(cr);
|
|
|
|
CairoCommon::drawPolyLine(cr, &aExtents, *m_rCairoCommon.m_oLineColor, getAntiAlias(), nPoints,
|
|
pPtAry);
|
|
|
|
m_rCairoCommon.releaseCairoContext(cr, false, aExtents);
|
|
}
|
|
|
|
void SvpGraphicsBackend::drawPolygon(sal_uInt32 nPoints, const Point* pPtAry)
|
|
{
|
|
cairo_t* cr = m_rCairoCommon.getCairoContext(true, getAntiAlias());
|
|
basegfx::B2DRange extents;
|
|
m_rCairoCommon.clipRegion(cr);
|
|
|
|
CairoCommon::drawPolygon(cr, &extents, m_rCairoCommon.m_oLineColor, m_rCairoCommon.m_oFillColor,
|
|
getAntiAlias(), nPoints, pPtAry);
|
|
|
|
m_rCairoCommon.releaseCairoContext(cr, true, extents);
|
|
}
|
|
|
|
void SvpGraphicsBackend::drawPolyPolygon(sal_uInt32 nPoly, const sal_uInt32* pPointCounts,
|
|
const Point** pPtAry)
|
|
{
|
|
cairo_t* cr = m_rCairoCommon.getCairoContext(true, getAntiAlias());
|
|
basegfx::B2DRange extents;
|
|
m_rCairoCommon.clipRegion(cr);
|
|
|
|
CairoCommon::drawPolyPolygon(cr, &extents, m_rCairoCommon.m_oLineColor,
|
|
m_rCairoCommon.m_oFillColor, getAntiAlias(), nPoly, pPointCounts,
|
|
pPtAry);
|
|
|
|
m_rCairoCommon.releaseCairoContext(cr, true, extents);
|
|
}
|
|
|
|
bool SvpGraphicsBackend::drawPolyPolygon(const basegfx::B2DHomMatrix& rObjectToDevice,
|
|
const basegfx::B2DPolyPolygon& rPolyPolygon,
|
|
double fTransparency)
|
|
{
|
|
cairo_t* cr = m_rCairoCommon.getCairoContext(true, getAntiAlias());
|
|
basegfx::B2DRange extents;
|
|
m_rCairoCommon.clipRegion(cr);
|
|
|
|
bool bRetVal(CairoCommon::drawPolyPolygon(cr, &extents, m_rCairoCommon.m_oLineColor,
|
|
m_rCairoCommon.m_oFillColor, getAntiAlias(),
|
|
rObjectToDevice, rPolyPolygon, fTransparency));
|
|
|
|
m_rCairoCommon.releaseCairoContext(cr, true, extents);
|
|
|
|
return bRetVal;
|
|
}
|
|
|
|
bool SvpGraphicsBackend::drawPolyLine(const basegfx::B2DHomMatrix& rObjectToDevice,
|
|
const basegfx::B2DPolygon& rPolyLine, double fTransparency,
|
|
double fLineWidth, const std::vector<double>* pStroke,
|
|
basegfx::B2DLineJoin eLineJoin,
|
|
css::drawing::LineCap eLineCap, double fMiterMinimumAngle,
|
|
bool bPixelSnapHairline)
|
|
{
|
|
// short circuit if there is nothing to do
|
|
if (0 == rPolyLine.count() || fTransparency < 0.0 || fTransparency >= 1.0)
|
|
return true;
|
|
|
|
// Wrap call to static version of ::drawPolyLine by
|
|
// preparing/getting some local data and parameters
|
|
// due to usage in vcl/unx/generic/gdi/salgdi.cxx.
|
|
// This is mainly about extended handling of extents
|
|
// and the way destruction of CairoContext is handled
|
|
// due to current XOR stuff
|
|
cairo_t* cr = m_rCairoCommon.getCairoContext(false, getAntiAlias());
|
|
basegfx::B2DRange aExtents;
|
|
m_rCairoCommon.clipRegion(cr);
|
|
|
|
bool bRetval(CairoCommon::drawPolyLine(cr, &aExtents, *m_rCairoCommon.m_oLineColor,
|
|
getAntiAlias(), rObjectToDevice, rPolyLine,
|
|
fTransparency, fLineWidth, pStroke, eLineJoin, eLineCap,
|
|
fMiterMinimumAngle, bPixelSnapHairline));
|
|
|
|
m_rCairoCommon.releaseCairoContext(cr, false, aExtents);
|
|
|
|
return bRetval;
|
|
}
|
|
|
|
bool SvpGraphicsBackend::drawPolyLineBezier(sal_uInt32, const Point*, const PolyFlags*)
|
|
{
|
|
SAL_INFO("vcl.gdi", "unsupported SvpSalGraphics::drawPolyLineBezier case");
|
|
return false;
|
|
}
|
|
|
|
bool SvpGraphicsBackend::drawPolygonBezier(sal_uInt32, const Point*, const PolyFlags*)
|
|
{
|
|
SAL_INFO("vcl.gdi", "unsupported SvpSalGraphics::drawPolygonBezier case");
|
|
return false;
|
|
}
|
|
|
|
bool SvpGraphicsBackend::drawPolyPolygonBezier(sal_uInt32, const sal_uInt32*, const Point* const*,
|
|
const PolyFlags* const*)
|
|
{
|
|
SAL_INFO("vcl.gdi", "unsupported SvpSalGraphics::drawPolyPolygonBezier case");
|
|
return false;
|
|
}
|
|
|
|
void SvpGraphicsBackend::copyArea(tools::Long nDestX, tools::Long nDestY, tools::Long nSrcX,
|
|
tools::Long nSrcY, tools::Long nSrcWidth, tools::Long nSrcHeight,
|
|
bool /*bWindowInvalidate*/)
|
|
{
|
|
SalTwoRect aTR(nSrcX, nSrcY, nSrcWidth, nSrcHeight, nDestX, nDestY, nSrcWidth, nSrcHeight);
|
|
|
|
cairo_surface_t* source = m_rCairoCommon.m_pSurface;
|
|
m_rCairoCommon.copyBitsCairo(aTR, source, getAntiAlias());
|
|
}
|
|
|
|
void SvpGraphicsBackend::copyBits(const SalTwoRect& rTR, SalGraphics* pSrcGraphics)
|
|
{
|
|
cairo_surface_t* source = nullptr;
|
|
|
|
if (pSrcGraphics)
|
|
{
|
|
SvpGraphicsBackend* pSrc = static_cast<SvpGraphicsBackend*>(pSrcGraphics->GetImpl());
|
|
source = pSrc->m_rCairoCommon.m_pSurface;
|
|
}
|
|
else
|
|
{
|
|
source = m_rCairoCommon.m_pSurface;
|
|
}
|
|
|
|
m_rCairoCommon.copyBitsCairo(rTR, source, getAntiAlias());
|
|
}
|
|
|
|
void SvpGraphicsBackend::drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap)
|
|
{
|
|
// MM02 try to access buffered BitmapHelper
|
|
std::shared_ptr<BitmapHelper> aSurface;
|
|
tryToUseSourceBuffer(rSalBitmap, aSurface);
|
|
cairo_surface_t* source = aSurface->getSurface(rPosAry.mnDestWidth, rPosAry.mnDestHeight);
|
|
|
|
if (!source)
|
|
{
|
|
SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawAlphaBitmap case");
|
|
return;
|
|
}
|
|
|
|
#if 0 // LO code is not yet bitmap32-ready.
|
|
// if m_bSupportsBitmap32 becomes true for Svp revisit this
|
|
m_rCairoCommon.copyWithOperator(rPosAry, source, CAIRO_OPERATOR_OVER, getAntiAlias());
|
|
#else
|
|
m_rCairoCommon.copyWithOperator(rPosAry, source, CAIRO_OPERATOR_SOURCE, getAntiAlias());
|
|
#endif
|
|
}
|
|
|
|
void SvpGraphicsBackend::drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap,
|
|
const SalBitmap& rTransparentBitmap)
|
|
{
|
|
drawAlphaBitmap(rPosAry, rSalBitmap, rTransparentBitmap);
|
|
}
|
|
|
|
void SvpGraphicsBackend::drawMask(const SalTwoRect& rTR, const SalBitmap& rSalBitmap,
|
|
Color nMaskColor)
|
|
{
|
|
/** creates an image from the given rectangle, replacing all black pixels
|
|
* with nMaskColor and make all other full transparent */
|
|
// MM02 here decided *against* using buffered BitmapHelper
|
|
// because the data gets somehow 'unmuliplied'. This may also be
|
|
// done just once, but I am not sure if this is safe to do.
|
|
// So for now dispense re-using data here.
|
|
BitmapHelper aSurface(rSalBitmap, true); // The mask is argb32
|
|
if (!aSurface.getSurface())
|
|
{
|
|
SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawMask case");
|
|
return;
|
|
}
|
|
sal_Int32 nStride;
|
|
unsigned char* mask_data = aSurface.getBits(nStride);
|
|
#if !ENABLE_WASM_STRIP_PREMULTIPLY
|
|
vcl::bitmap::lookup_table const& unpremultiply_table = vcl::bitmap::get_unpremultiply_table();
|
|
#endif
|
|
for (tools::Long y = rTR.mnSrcY; y < rTR.mnSrcY + rTR.mnSrcHeight; ++y)
|
|
{
|
|
unsigned char* row = mask_data + (nStride * y);
|
|
unsigned char* data = row + (rTR.mnSrcX * 4);
|
|
for (tools::Long x = rTR.mnSrcX; x < rTR.mnSrcX + rTR.mnSrcWidth; ++x)
|
|
{
|
|
sal_uInt8 a = data[SVP_CAIRO_ALPHA];
|
|
#if ENABLE_WASM_STRIP_PREMULTIPLY
|
|
sal_uInt8 b = vcl::bitmap::unpremultiply(a, data[SVP_CAIRO_BLUE]);
|
|
sal_uInt8 g = vcl::bitmap::unpremultiply(a, data[SVP_CAIRO_GREEN]);
|
|
sal_uInt8 r = vcl::bitmap::unpremultiply(a, data[SVP_CAIRO_RED]);
|
|
#else
|
|
sal_uInt8 b = unpremultiply_table[a][data[SVP_CAIRO_BLUE]];
|
|
sal_uInt8 g = unpremultiply_table[a][data[SVP_CAIRO_GREEN]];
|
|
sal_uInt8 r = unpremultiply_table[a][data[SVP_CAIRO_RED]];
|
|
#endif
|
|
if (r == 0 && g == 0 && b == 0)
|
|
{
|
|
data[0] = nMaskColor.GetBlue();
|
|
data[1] = nMaskColor.GetGreen();
|
|
data[2] = nMaskColor.GetRed();
|
|
data[3] = 0xff;
|
|
}
|
|
else
|
|
{
|
|
data[0] = 0;
|
|
data[1] = 0;
|
|
data[2] = 0;
|
|
data[3] = 0;
|
|
}
|
|
data += 4;
|
|
}
|
|
}
|
|
aSurface.mark_dirty();
|
|
|
|
cairo_t* cr = m_rCairoCommon.getCairoContext(false, getAntiAlias());
|
|
m_rCairoCommon.clipRegion(cr);
|
|
|
|
cairo_rectangle(cr, rTR.mnDestX, rTR.mnDestY, rTR.mnDestWidth, rTR.mnDestHeight);
|
|
|
|
basegfx::B2DRange extents = getClippedFillDamage(cr);
|
|
|
|
cairo_clip(cr);
|
|
|
|
cairo_translate(cr, rTR.mnDestX, rTR.mnDestY);
|
|
double fXScale = static_cast<double>(rTR.mnDestWidth) / rTR.mnSrcWidth;
|
|
double fYScale = static_cast<double>(rTR.mnDestHeight) / rTR.mnSrcHeight;
|
|
cairo_scale(cr, fXScale, fYScale);
|
|
cairo_set_source_surface(cr, aSurface.getSurface(), -rTR.mnSrcX, -rTR.mnSrcY);
|
|
|
|
if (cairo_status(cr) == CAIRO_STATUS_SUCCESS)
|
|
{
|
|
//tdf#133716 borders of upscaled images should not be blurred
|
|
cairo_pattern_t* sourcepattern = cairo_get_source(cr);
|
|
cairo_pattern_set_extend(sourcepattern, CAIRO_EXTEND_PAD);
|
|
}
|
|
|
|
cairo_paint(cr);
|
|
|
|
m_rCairoCommon.releaseCairoContext(cr, false, extents);
|
|
}
|
|
|
|
std::shared_ptr<SalBitmap> SvpGraphicsBackend::getBitmap(tools::Long nX, tools::Long nY,
|
|
tools::Long nWidth, tools::Long nHeight)
|
|
{
|
|
std::shared_ptr<SvpSalBitmap> pBitmap = std::make_shared<SvpSalBitmap>();
|
|
BitmapPalette aPal;
|
|
vcl::PixelFormat ePixelFormat = vcl::PixelFormat::INVALID;
|
|
if (GetBitCount() == 1)
|
|
{
|
|
ePixelFormat = vcl::PixelFormat::N1_BPP;
|
|
aPal.SetEntryCount(2);
|
|
aPal[0] = COL_BLACK;
|
|
aPal[1] = COL_WHITE;
|
|
}
|
|
else
|
|
{
|
|
ePixelFormat = vcl::PixelFormat::N32_BPP;
|
|
}
|
|
|
|
if (!pBitmap->Create(Size(nWidth, nHeight), ePixelFormat, aPal))
|
|
{
|
|
SAL_WARN("vcl.gdi", "SvpSalGraphics::getBitmap, cannot create bitmap");
|
|
return nullptr;
|
|
}
|
|
|
|
cairo_surface_t* target = CairoCommon::createCairoSurface(pBitmap->GetBuffer());
|
|
if (!target)
|
|
{
|
|
SAL_WARN("vcl.gdi", "SvpSalGraphics::getBitmap, cannot create cairo surface");
|
|
return nullptr;
|
|
}
|
|
cairo_t* cr = cairo_create(target);
|
|
|
|
SalTwoRect aTR(nX, nY, nWidth, nHeight, 0, 0, nWidth, nHeight);
|
|
CairoCommon::renderSource(cr, aTR, m_rCairoCommon.m_pSurface);
|
|
|
|
cairo_destroy(cr);
|
|
cairo_surface_destroy(target);
|
|
|
|
Toggle1BitTransparency(*pBitmap->GetBuffer());
|
|
|
|
return pBitmap;
|
|
}
|
|
|
|
void SvpGraphicsBackend::drawBitmapBuffer(const SalTwoRect& rTR, const BitmapBuffer* pBuffer,
|
|
cairo_operator_t eOp)
|
|
{
|
|
cairo_surface_t* source = CairoCommon::createCairoSurface(pBuffer);
|
|
m_rCairoCommon.copyWithOperator(rTR, source, eOp, getAntiAlias());
|
|
cairo_surface_destroy(source);
|
|
}
|
|
|
|
Color SvpGraphicsBackend::getPixel(tools::Long nX, tools::Long nY)
|
|
{
|
|
return CairoCommon::getPixel(m_rCairoCommon.m_pSurface, nX, nY);
|
|
}
|
|
|
|
void SvpGraphicsBackend::invert(tools::Long nX, tools::Long nY, tools::Long nWidth,
|
|
tools::Long nHeight, SalInvert nFlags)
|
|
{
|
|
basegfx::B2DPolygon aRect = basegfx::utils::createPolygonFromRect(
|
|
basegfx::B2DRectangle(nX, nY, nX + nWidth, nY + nHeight));
|
|
|
|
m_rCairoCommon.invert(aRect, nFlags, getAntiAlias());
|
|
}
|
|
|
|
void SvpGraphicsBackend::invert(sal_uInt32 nPoints, const Point* pPtAry, SalInvert nFlags)
|
|
{
|
|
basegfx::B2DPolygon aPoly;
|
|
aPoly.append(basegfx::B2DPoint(pPtAry->getX(), pPtAry->getY()), nPoints);
|
|
for (sal_uInt32 i = 1; i < nPoints; ++i)
|
|
aPoly.setB2DPoint(i, basegfx::B2DPoint(pPtAry[i].getX(), pPtAry[i].getY()));
|
|
aPoly.setClosed(true);
|
|
|
|
m_rCairoCommon.invert(aPoly, nFlags, getAntiAlias());
|
|
}
|
|
|
|
bool SvpGraphicsBackend::drawEPS(tools::Long /*nX*/, tools::Long /*nY*/, tools::Long /*nWidth*/,
|
|
tools::Long /*nHeight*/, void* /*pPtr*/, sal_uInt32 /*nSize*/)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool SvpGraphicsBackend::blendBitmap(const SalTwoRect& /*rPosAry*/, const SalBitmap& /*rBitmap*/)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool SvpGraphicsBackend::blendAlphaBitmap(const SalTwoRect& /*rPosAry*/,
|
|
const SalBitmap& /*rSrcBitmap*/,
|
|
const SalBitmap& /*rMaskBitmap*/,
|
|
const SalBitmap& /*rAlphaBitmap*/)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool SvpGraphicsBackend::drawAlphaBitmap(const SalTwoRect& rTR, const SalBitmap& rSourceBitmap,
|
|
const SalBitmap& rAlphaBitmap)
|
|
{
|
|
if (rAlphaBitmap.GetBitCount() != 8 && rAlphaBitmap.GetBitCount() != 1)
|
|
{
|
|
SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawAlphaBitmap alpha depth case: "
|
|
<< rAlphaBitmap.GetBitCount());
|
|
return false;
|
|
}
|
|
|
|
if (!rTR.mnSrcWidth || !rTR.mnSrcHeight)
|
|
{
|
|
SAL_WARN("vcl.gdi", "not possible to stretch nothing");
|
|
return true;
|
|
}
|
|
|
|
// MM02 try to access buffered BitmapHelper
|
|
std::shared_ptr<BitmapHelper> aSurface;
|
|
tryToUseSourceBuffer(rSourceBitmap, aSurface);
|
|
cairo_surface_t* source = aSurface->getSurface(rTR.mnDestWidth, rTR.mnDestHeight);
|
|
|
|
if (!source)
|
|
{
|
|
SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawAlphaBitmap case");
|
|
return false;
|
|
}
|
|
|
|
// MM02 try to access buffered MaskHelper
|
|
std::shared_ptr<MaskHelper> aMask;
|
|
tryToUseMaskBuffer(rAlphaBitmap, aMask);
|
|
cairo_surface_t* mask = aMask->getSurface(rTR.mnDestWidth, rTR.mnDestHeight);
|
|
|
|
if (!mask)
|
|
{
|
|
SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawAlphaBitmap case");
|
|
return false;
|
|
}
|
|
|
|
cairo_t* cr = m_rCairoCommon.getCairoContext(false, getAntiAlias());
|
|
m_rCairoCommon.clipRegion(cr);
|
|
|
|
cairo_rectangle(cr, rTR.mnDestX, rTR.mnDestY, rTR.mnDestWidth, rTR.mnDestHeight);
|
|
|
|
basegfx::B2DRange extents = getClippedFillDamage(cr);
|
|
|
|
cairo_clip(cr);
|
|
|
|
cairo_pattern_t* maskpattern = cairo_pattern_create_for_surface(mask);
|
|
cairo_translate(cr, rTR.mnDestX, rTR.mnDestY);
|
|
double fXScale = static_cast<double>(rTR.mnDestWidth) / rTR.mnSrcWidth;
|
|
double fYScale = static_cast<double>(rTR.mnDestHeight) / rTR.mnSrcHeight;
|
|
cairo_scale(cr, fXScale, fYScale);
|
|
cairo_set_source_surface(cr, source, -rTR.mnSrcX, -rTR.mnSrcY);
|
|
|
|
cairo_pattern_t* sourcepattern = cairo_get_source(cr);
|
|
|
|
//tdf#133716 borders of upscaled images should not be blurred
|
|
//tdf#114117 when stretching a single or multi pixel width/height source to fit an area
|
|
//the image will be extended into that size.
|
|
cairo_pattern_set_extend(sourcepattern, CAIRO_EXTEND_PAD);
|
|
cairo_pattern_set_extend(maskpattern, CAIRO_EXTEND_PAD);
|
|
|
|
//this block is just "cairo_mask_surface", but we have to make it explicit
|
|
//because of the cairo_pattern_set_filter etc we may want applied
|
|
cairo_matrix_t matrix;
|
|
cairo_matrix_init_translate(&matrix, rTR.mnSrcX, rTR.mnSrcY);
|
|
cairo_pattern_set_matrix(maskpattern, &matrix);
|
|
cairo_mask(cr, maskpattern);
|
|
|
|
cairo_pattern_destroy(maskpattern);
|
|
|
|
m_rCairoCommon.releaseCairoContext(cr, false, extents);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SvpGraphicsBackend::drawTransformedBitmap(const basegfx::B2DPoint& rNull,
|
|
const basegfx::B2DPoint& rX,
|
|
const basegfx::B2DPoint& rY,
|
|
const SalBitmap& rSourceBitmap,
|
|
const SalBitmap* pAlphaBitmap, double fAlpha)
|
|
{
|
|
if (pAlphaBitmap && pAlphaBitmap->GetBitCount() != 8 && pAlphaBitmap->GetBitCount() != 1)
|
|
{
|
|
SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawTransformedBitmap alpha depth case: "
|
|
<< pAlphaBitmap->GetBitCount());
|
|
return false;
|
|
}
|
|
|
|
if (fAlpha != 1.0)
|
|
return false;
|
|
|
|
// MM02 try to access buffered BitmapHelper
|
|
std::shared_ptr<BitmapHelper> aSurface;
|
|
tryToUseSourceBuffer(rSourceBitmap, aSurface);
|
|
const tools::Long nDestWidth(basegfx::fround(basegfx::B2DVector(rX - rNull).getLength()));
|
|
const tools::Long nDestHeight(basegfx::fround(basegfx::B2DVector(rY - rNull).getLength()));
|
|
cairo_surface_t* source(aSurface->getSurface(nDestWidth, nDestHeight));
|
|
|
|
if (!source)
|
|
{
|
|
SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawTransformedBitmap case");
|
|
return false;
|
|
}
|
|
|
|
// MM02 try to access buffered MaskHelper
|
|
std::shared_ptr<MaskHelper> aMask;
|
|
if (nullptr != pAlphaBitmap)
|
|
{
|
|
tryToUseMaskBuffer(*pAlphaBitmap, aMask);
|
|
}
|
|
|
|
// access cairo_surface_t from MaskHelper
|
|
cairo_surface_t* mask(nullptr);
|
|
if (aMask)
|
|
{
|
|
mask = aMask->getSurface(nDestWidth, nDestHeight);
|
|
}
|
|
|
|
if (nullptr != pAlphaBitmap && nullptr == mask)
|
|
{
|
|
SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawTransformedBitmap case");
|
|
return false;
|
|
}
|
|
|
|
const Size aSize = rSourceBitmap.GetSize();
|
|
cairo_t* cr = m_rCairoCommon.getCairoContext(false, getAntiAlias());
|
|
m_rCairoCommon.clipRegion(cr);
|
|
|
|
// setup the image transformation
|
|
// using the rNull,rX,rY points as destinations for the (0,0),(0,Width),(Height,0) source points
|
|
const basegfx::B2DVector aXRel = rX - rNull;
|
|
const basegfx::B2DVector aYRel = rY - rNull;
|
|
cairo_matrix_t matrix;
|
|
cairo_matrix_init(&matrix, aXRel.getX() / aSize.Width(), aXRel.getY() / aSize.Width(),
|
|
aYRel.getX() / aSize.Height(), aYRel.getY() / aSize.Height(), rNull.getX(),
|
|
rNull.getY());
|
|
|
|
cairo_transform(cr, &matrix);
|
|
|
|
cairo_rectangle(cr, 0, 0, aSize.Width(), aSize.Height());
|
|
basegfx::B2DRange extents = getClippedFillDamage(cr);
|
|
cairo_clip(cr);
|
|
|
|
cairo_set_source_surface(cr, source, 0, 0);
|
|
if (mask)
|
|
cairo_mask_surface(cr, mask, 0, 0);
|
|
else
|
|
cairo_paint(cr);
|
|
|
|
m_rCairoCommon.releaseCairoContext(cr, false, extents);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SvpGraphicsBackend::hasFastDrawTransformedBitmap() const
|
|
{
|
|
return CairoCommon::hasFastDrawTransformedBitmap();
|
|
}
|
|
|
|
bool SvpGraphicsBackend::drawAlphaRect(tools::Long nX, tools::Long nY, tools::Long nWidth,
|
|
tools::Long nHeight, sal_uInt8 nTransparency)
|
|
{
|
|
cairo_t* cr = m_rCairoCommon.getCairoContext(false, getAntiAlias());
|
|
basegfx::B2DRange extents;
|
|
m_rCairoCommon.clipRegion(cr);
|
|
|
|
const bool bRetval(CairoCommon::drawAlphaRect(cr, &extents, *m_rCairoCommon.m_oLineColor,
|
|
*m_rCairoCommon.m_oFillColor, nX, nY, nWidth,
|
|
nHeight, nTransparency));
|
|
m_rCairoCommon.releaseCairoContext(cr, false, extents);
|
|
|
|
return bRetval;
|
|
}
|
|
|
|
bool SvpGraphicsBackend::drawGradient(const tools::PolyPolygon& rPolyPolygon,
|
|
const Gradient& rGradient)
|
|
{
|
|
cairo_t* cr = m_rCairoCommon.getCairoContext(true, getAntiAlias());
|
|
basegfx::B2DRange extents;
|
|
m_rCairoCommon.clipRegion(cr);
|
|
|
|
const bool bRetval(
|
|
CairoCommon::drawGradient(cr, &extents, getAntiAlias(), rPolyPolygon, rGradient));
|
|
|
|
m_rCairoCommon.releaseCairoContext(cr, true, extents);
|
|
|
|
return bRetval;
|
|
}
|
|
|
|
bool SvpGraphicsBackend::implDrawGradient(basegfx::B2DPolyPolygon const& rPolyPolygon,
|
|
SalGradient const& rGradient)
|
|
{
|
|
cairo_t* cr = m_rCairoCommon.getCairoContext(true, getAntiAlias());
|
|
basegfx::B2DRange extents;
|
|
m_rCairoCommon.clipRegion(cr);
|
|
|
|
bool bRetVal(
|
|
CairoCommon::implDrawGradient(cr, &extents, getAntiAlias(), rPolyPolygon, rGradient));
|
|
|
|
m_rCairoCommon.releaseCairoContext(cr, true, extents);
|
|
|
|
return bRetVal;
|
|
}
|
|
|
|
bool SvpGraphicsBackend::supportsOperation(OutDevSupportType eType) const
|
|
{
|
|
return CairoCommon::supportsOperation(eType);
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|