initial Experimental System-Dependent PrimitiveRenderer for Cairo
just some partial pieces export TEST_SYSTEM_PRIMITIVE_RENDERER=1 and the simple drawing shapes work Change-Id: I3e01501a1cb21ec86d6fe8f5637a23e7358ffc86 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/144632 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caolanm@redhat.com>
This commit is contained in:
parent
179f50f810
commit
ff46c8bf59
11 changed files with 891 additions and 40 deletions
|
@ -26,6 +26,7 @@ Settings about which desktops have support enabled.
|
|||
/**
|
||||
* Additional settings for the plugins
|
||||
*/
|
||||
#define USE_HEADLESS_CODE 0
|
||||
#define ENABLE_GSTREAMER_1_0 0
|
||||
#define QT5_HAVE_GOBJECT 0
|
||||
#define QT5_USING_X11 0
|
||||
|
|
|
@ -1231,6 +1231,7 @@ disable_x11_tests()
|
|||
test "$using_x11" = yes && USING_X11=TRUE
|
||||
|
||||
if test "$using_freetype_fontconfig" = yes; then
|
||||
AC_DEFINE(USE_HEADLESS_CODE)
|
||||
USE_HEADLESS_CODE=TRUE
|
||||
if test "$using_headless_plugin" = yes; then
|
||||
AC_DEFINE(ENABLE_HEADLESS)
|
||||
|
|
|
@ -27,6 +27,7 @@ $(eval $(call gb_Library_use_sdk_api,drawinglayer))
|
|||
$(eval $(call gb_Library_use_externals,drawinglayer,\
|
||||
boost_headers \
|
||||
libxml2 \
|
||||
$(if $(USE_HEADLESS_CODE), cairo) \
|
||||
))
|
||||
|
||||
ifneq ($(ENABLE_WASM_STRIP_CANVAS),TRUE)
|
||||
|
@ -68,6 +69,12 @@ $(eval $(call gb_Library_add_exception_objects,drawinglayer,\
|
|||
))
|
||||
endif
|
||||
|
||||
ifeq ($(USE_HEADLESS_CODE),TRUE)
|
||||
$(eval $(call gb_Library_add_exception_objects,drawinglayer,\
|
||||
drawinglayer/source/processor2d/cairopixelprocessor2d \
|
||||
))
|
||||
endif
|
||||
|
||||
$(eval $(call gb_Library_add_exception_objects,drawinglayer,\
|
||||
drawinglayer/source/animation/animationtiming \
|
||||
drawinglayer/source/attribute/fillgraphicattribute \
|
||||
|
|
724
drawinglayer/source/processor2d/cairopixelprocessor2d.cxx
Normal file
724
drawinglayer/source/processor2d/cairopixelprocessor2d.cxx
Normal file
|
@ -0,0 +1,724 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
|
||||
/*
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
#include <sal/config.h>
|
||||
|
||||
#include <drawinglayer/processor2d/cairopixelprocessor2d.hxx>
|
||||
#include <sal/log.hxx>
|
||||
#include <vcl/cairo.hxx>
|
||||
#include <vcl/outdev.hxx>
|
||||
#include <vcl/svapp.hxx>
|
||||
#include <basegfx/polygon/b2dpolygontools.hxx>
|
||||
#include <basegfx/polygon/b2dpolypolygontools.hxx>
|
||||
#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
|
||||
#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
|
||||
#include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
|
||||
#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
|
||||
#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
|
||||
#include <drawinglayer/primitive2d/backgroundcolorprimitive2d.hxx>
|
||||
#include <drawinglayer/primitive2d/baseprimitive2d.hxx>
|
||||
#include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx>
|
||||
#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
|
||||
#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
|
||||
#include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx>
|
||||
#include <drawinglayer/primitive2d/PolygonStrokePrimitive2D.hxx>
|
||||
#include <drawinglayer/primitive2d/Tools.hxx>
|
||||
#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
|
||||
#include <drawinglayer/primitive2d/transparenceprimitive2d.hxx>
|
||||
#include <drawinglayer/converters.hxx>
|
||||
#include <basegfx/curve/b2dcubicbezier.hxx>
|
||||
#include <basegfx/matrix/b2dhommatrixtools.hxx>
|
||||
#include <basegfx/utils/systemdependentdata.hxx>
|
||||
#include <vcl/BitmapReadAccess.hxx>
|
||||
|
||||
using namespace com::sun::star;
|
||||
|
||||
namespace
|
||||
{
|
||||
basegfx::B2DPoint impPixelSnap(const basegfx::B2DPolygon& rPolygon,
|
||||
const drawinglayer::geometry::ViewInformation2D& rViewInformation,
|
||||
sal_uInt32 nIndex)
|
||||
{
|
||||
const sal_uInt32 nCount(rPolygon.count());
|
||||
|
||||
// get the data
|
||||
const basegfx::B2ITuple aPrevTuple(
|
||||
basegfx::fround(rViewInformation.getObjectToViewTransformation()
|
||||
* rPolygon.getB2DPoint((nIndex + nCount - 1) % nCount)));
|
||||
const basegfx::B2DPoint aCurrPoint(rViewInformation.getObjectToViewTransformation()
|
||||
* rPolygon.getB2DPoint(nIndex));
|
||||
const basegfx::B2ITuple aCurrTuple(basegfx::fround(aCurrPoint));
|
||||
const basegfx::B2ITuple aNextTuple(
|
||||
basegfx::fround(rViewInformation.getObjectToViewTransformation()
|
||||
* rPolygon.getB2DPoint((nIndex + 1) % nCount)));
|
||||
|
||||
// get the states
|
||||
const bool bPrevVertical(aPrevTuple.getX() == aCurrTuple.getX());
|
||||
const bool bNextVertical(aNextTuple.getX() == aCurrTuple.getX());
|
||||
const bool bPrevHorizontal(aPrevTuple.getY() == aCurrTuple.getY());
|
||||
const bool bNextHorizontal(aNextTuple.getY() == aCurrTuple.getY());
|
||||
const bool bSnapX(bPrevVertical || bNextVertical);
|
||||
const bool bSnapY(bPrevHorizontal || bNextHorizontal);
|
||||
|
||||
if (bSnapX || bSnapY)
|
||||
{
|
||||
basegfx::B2DPoint aSnappedPoint(bSnapX ? aCurrTuple.getX() : aCurrPoint.getX(),
|
||||
bSnapY ? aCurrTuple.getY() : aCurrPoint.getY());
|
||||
|
||||
aSnappedPoint *= rViewInformation.getInverseObjectToViewTransformation();
|
||||
|
||||
return aSnappedPoint;
|
||||
}
|
||||
|
||||
return rPolygon.getB2DPoint(nIndex);
|
||||
}
|
||||
|
||||
void addB2DPolygonToPathGeometry(cairo_t* cr, const basegfx::B2DPolygon& rPolygon,
|
||||
const drawinglayer::geometry::ViewInformation2D* pViewInformation)
|
||||
{
|
||||
// short circuit if there is nothing to do
|
||||
const sal_uInt32 nPointCount(rPolygon.count());
|
||||
|
||||
const bool bHasCurves(rPolygon.areControlPointsUsed());
|
||||
const bool bClosePath(rPolygon.isClosed());
|
||||
basegfx::B2DPoint aLast;
|
||||
|
||||
for (sal_uInt32 nPointIdx = 0, nPrevIdx = 0;; nPrevIdx = nPointIdx++)
|
||||
{
|
||||
int nClosedIdx = nPointIdx;
|
||||
if (nPointIdx >= nPointCount)
|
||||
{
|
||||
// prepare to close last curve segment if needed
|
||||
if (bClosePath && (nPointIdx == nPointCount))
|
||||
{
|
||||
nClosedIdx = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const basegfx::B2DPoint aPoint(nullptr == pViewInformation
|
||||
? rPolygon.getB2DPoint(nClosedIdx)
|
||||
: impPixelSnap(rPolygon, *pViewInformation, nClosedIdx));
|
||||
|
||||
if (!nPointIdx)
|
||||
{
|
||||
// first point => just move there
|
||||
cairo_move_to(cr, aPoint.getX(), aPoint.getY());
|
||||
aLast = aPoint;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool bPendingCurve(false);
|
||||
|
||||
if (bHasCurves)
|
||||
{
|
||||
bPendingCurve = rPolygon.isNextControlPointUsed(nPrevIdx);
|
||||
bPendingCurve |= rPolygon.isPrevControlPointUsed(nClosedIdx);
|
||||
}
|
||||
|
||||
if (!bPendingCurve) // line segment
|
||||
{
|
||||
cairo_line_to(cr, aPoint.getX(), aPoint.getY());
|
||||
}
|
||||
else // cubic bezier segment
|
||||
{
|
||||
basegfx::B2DPoint aCP1 = rPolygon.getNextControlPoint(nPrevIdx);
|
||||
basegfx::B2DPoint aCP2 = rPolygon.getPrevControlPoint(nClosedIdx);
|
||||
|
||||
// tdf#99165 if the control points are 'empty', create the mathematical
|
||||
// correct replacement ones to avoid problems with the graphical sub-system
|
||||
// tdf#101026 The 1st attempt to create a mathematically correct replacement control
|
||||
// vector was wrong. Best alternative is one as close as possible which means short.
|
||||
if (aCP1.equal(aLast))
|
||||
{
|
||||
aCP1 = aLast + ((aCP2 - aLast) * 0.0005);
|
||||
}
|
||||
|
||||
if (aCP2.equal(aPoint))
|
||||
{
|
||||
aCP2 = aPoint + ((aCP1 - aPoint) * 0.0005);
|
||||
}
|
||||
|
||||
cairo_curve_to(cr, aCP1.getX(), aCP1.getY(), aCP2.getX(), aCP2.getY(), aPoint.getX(),
|
||||
aPoint.getY());
|
||||
}
|
||||
|
||||
aLast = aPoint;
|
||||
}
|
||||
|
||||
if (bClosePath)
|
||||
{
|
||||
cairo_close_path(cr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace drawinglayer::processor2d
|
||||
{
|
||||
CairoPixelProcessor2D::CairoPixelProcessor2D(const geometry::ViewInformation2D& rViewInformation)
|
||||
: BaseProcessor2D(rViewInformation)
|
||||
, maBColorModifierStack()
|
||||
, mpRT(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
CairoPixelProcessor2D::CairoPixelProcessor2D(const geometry::ViewInformation2D& rViewInformation,
|
||||
cairo_surface_t* pTarget)
|
||||
: BaseProcessor2D(rViewInformation)
|
||||
, maBColorModifierStack()
|
||||
, mpRT(nullptr)
|
||||
{
|
||||
if (pTarget)
|
||||
{
|
||||
cairo_t* pRT = cairo_create(pTarget);
|
||||
cairo_set_antialias(pRT, rViewInformation.getUseAntiAliasing() ? CAIRO_ANTIALIAS_DEFAULT
|
||||
: CAIRO_ANTIALIAS_NONE);
|
||||
setRenderTarget(pRT);
|
||||
}
|
||||
}
|
||||
|
||||
CairoPixelProcessor2D::~CairoPixelProcessor2D()
|
||||
{
|
||||
if (mpRT)
|
||||
cairo_destroy(mpRT);
|
||||
}
|
||||
|
||||
void CairoPixelProcessor2D::processPolygonHairlinePrimitive2D(
|
||||
const primitive2d::PolygonHairlinePrimitive2D& rPolygonHairlinePrimitive2D)
|
||||
{
|
||||
const basegfx::B2DPolygon& rPolygon(rPolygonHairlinePrimitive2D.getB2DPolygon());
|
||||
|
||||
if (!rPolygon.count())
|
||||
return;
|
||||
|
||||
cairo_save(mpRT);
|
||||
|
||||
cairo_matrix_t aMatrix;
|
||||
const double fAAOffset(getViewInformation2D().getUseAntiAliasing() ? 0.5 : 0.0);
|
||||
const basegfx::B2DHomMatrix& rObjectToView(
|
||||
getViewInformation2D().getObjectToViewTransformation());
|
||||
cairo_matrix_init(&aMatrix, rObjectToView.a(), rObjectToView.b(), rObjectToView.c(),
|
||||
rObjectToView.d(), rObjectToView.e() + fAAOffset,
|
||||
rObjectToView.f() + fAAOffset);
|
||||
|
||||
// set linear transformation
|
||||
cairo_set_matrix(mpRT, &aMatrix);
|
||||
|
||||
const basegfx::BColor aHairlineColor(
|
||||
maBColorModifierStack.getModifiedColor(rPolygonHairlinePrimitive2D.getBColor()));
|
||||
cairo_set_source_rgb(mpRT, aHairlineColor.getRed(), aHairlineColor.getGreen(),
|
||||
aHairlineColor.getBlue());
|
||||
|
||||
// TODO: Unfortunately Direct2D paint of one pixel wide lines does not
|
||||
// correctly and completely blend 100% over the background. Experimenting
|
||||
// shows that a value around/slightly below 2.0 is needed which hints that
|
||||
// alpha bleding the half-shifted lines (see fAAOffset above) is involved.
|
||||
// To get correct blending I try to use just wider hairlines for now. This
|
||||
// may need to be improved - or balanced (trying sqrt(2) now...)
|
||||
cairo_set_line_width(mpRT, 1.44f);
|
||||
|
||||
addB2DPolygonToPathGeometry(mpRT, rPolygon, &getViewInformation2D());
|
||||
|
||||
cairo_stroke(mpRT);
|
||||
|
||||
cairo_restore(mpRT);
|
||||
}
|
||||
|
||||
void CairoPixelProcessor2D::processPolyPolygonColorPrimitive2D(
|
||||
const primitive2d::PolyPolygonColorPrimitive2D& rPolyPolygonColorPrimitive2D)
|
||||
{
|
||||
const basegfx::B2DPolyPolygon& rPolyPolygon(rPolyPolygonColorPrimitive2D.getB2DPolyPolygon());
|
||||
const sal_uInt32 nCount(rPolyPolygon.count());
|
||||
|
||||
if (!nCount)
|
||||
return;
|
||||
|
||||
cairo_save(mpRT);
|
||||
|
||||
cairo_matrix_t aMatrix;
|
||||
const double fAAOffset(getViewInformation2D().getUseAntiAliasing() ? 0.5 : 0.0);
|
||||
const basegfx::B2DHomMatrix& rObjectToView(
|
||||
getViewInformation2D().getObjectToViewTransformation());
|
||||
cairo_matrix_init(&aMatrix, rObjectToView.a(), rObjectToView.b(), rObjectToView.c(),
|
||||
rObjectToView.d(), rObjectToView.e() + fAAOffset,
|
||||
rObjectToView.f() + fAAOffset);
|
||||
|
||||
// set linear transformation
|
||||
cairo_set_matrix(mpRT, &aMatrix);
|
||||
|
||||
const basegfx::BColor aFillColor(
|
||||
maBColorModifierStack.getModifiedColor(rPolyPolygonColorPrimitive2D.getBColor()));
|
||||
cairo_set_source_rgb(mpRT, aFillColor.getRed(), aFillColor.getGreen(), aFillColor.getBlue());
|
||||
|
||||
for (const auto& rPolygon : rPolyPolygon)
|
||||
addB2DPolygonToPathGeometry(mpRT, rPolygon, &getViewInformation2D());
|
||||
|
||||
cairo_fill(mpRT);
|
||||
|
||||
cairo_restore(mpRT);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
void CairoPixelProcessor2D::processBitmapPrimitive2D(
|
||||
const primitive2d::BitmapPrimitive2D& rBitmapCandidate)
|
||||
{
|
||||
// TODO: All the smarts to get/make a cairo_surface_t from a BitmapEx is internal to vcl at the moment
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
// This bit-tweaking looping is unpleasant and unfortunate
|
||||
void LuminanceToAlpha(cairo_surface_t* pMask)
|
||||
{
|
||||
cairo_surface_flush(pMask);
|
||||
|
||||
int nWidth = cairo_image_surface_get_width(pMask);
|
||||
int nHeight = cairo_image_surface_get_height(pMask);
|
||||
int nStride = cairo_image_surface_get_stride(pMask);
|
||||
unsigned char* mask_surface_data = cairo_image_surface_get_data(pMask);
|
||||
|
||||
// include/basegfx/color/bcolormodifier.hxx
|
||||
const double nRedMul = 0.2125 / 255.0;
|
||||
const double nGreenMul = 0.7154 / 255.0;
|
||||
const double nBlueMul = 0.0721 / 255.0;
|
||||
for (int y = 0; y < nHeight; ++y)
|
||||
{
|
||||
unsigned char* pMaskPixelData = mask_surface_data + (nStride * y);
|
||||
for (int x = 0; x < nWidth; ++x)
|
||||
{
|
||||
double fLuminance = pMaskPixelData[SVP_CAIRO_RED] * nRedMul
|
||||
+ pMaskPixelData[SVP_CAIRO_GREEN] * nGreenMul
|
||||
+ pMaskPixelData[SVP_CAIRO_BLUE] * nBlueMul;
|
||||
// Only this alpha channel is taken into account by cairo_mask_surface
|
||||
// so reuse this surface for the alpha result
|
||||
pMaskPixelData[SVP_CAIRO_ALPHA] = 255.0 * fLuminance;
|
||||
pMaskPixelData += 4;
|
||||
}
|
||||
}
|
||||
|
||||
cairo_surface_mark_dirty(pMask);
|
||||
}
|
||||
}
|
||||
|
||||
void CairoPixelProcessor2D::processTransparencePrimitive2D(
|
||||
const primitive2d::TransparencePrimitive2D& rTransCandidate)
|
||||
{
|
||||
if (rTransCandidate.getChildren().empty())
|
||||
return;
|
||||
|
||||
if (rTransCandidate.getTransparence().empty())
|
||||
return;
|
||||
|
||||
cairo_surface_t* pTarget = cairo_get_target(mpRT);
|
||||
|
||||
double clip_x1, clip_x2, clip_y1, clip_y2;
|
||||
cairo_clip_extents(mpRT, &clip_x1, &clip_y1, &clip_x2, &clip_y2);
|
||||
|
||||
// calculate visible range, create only for that range
|
||||
basegfx::B2DRange aDiscreteRange(
|
||||
rTransCandidate.getChildren().getB2DRange(getViewInformation2D()));
|
||||
aDiscreteRange.transform(getViewInformation2D().getObjectToViewTransformation());
|
||||
const basegfx::B2DRange aViewRange(basegfx::B2DPoint(clip_x1, clip_y1),
|
||||
basegfx::B2DPoint(clip_x2, clip_y2));
|
||||
basegfx::B2DRange aVisibleRange(aDiscreteRange);
|
||||
aVisibleRange.intersect(aViewRange);
|
||||
|
||||
if (aVisibleRange.isEmpty())
|
||||
{
|
||||
// not visible, done
|
||||
return;
|
||||
}
|
||||
|
||||
const basegfx::B2DHomMatrix aEmbedTransform(basegfx::utils::createTranslateB2DHomMatrix(
|
||||
-aVisibleRange.getMinX(), -aVisibleRange.getMinY()));
|
||||
geometry::ViewInformation2D aViewInformation2D(getViewInformation2D());
|
||||
aViewInformation2D.setViewTransformation(aEmbedTransform
|
||||
* getViewInformation2D().getViewTransformation());
|
||||
// draw mask to temporary surface
|
||||
cairo_surface_t* pMask = cairo_surface_create_similar_image(pTarget, CAIRO_FORMAT_ARGB32,
|
||||
ceil(aVisibleRange.getWidth()),
|
||||
ceil(aVisibleRange.getHeight()));
|
||||
CairoPixelProcessor2D aMaskRenderer(aViewInformation2D, pMask);
|
||||
aMaskRenderer.process(rTransCandidate.getTransparence());
|
||||
|
||||
// convert mask to something cairo can use
|
||||
LuminanceToAlpha(pMask);
|
||||
|
||||
// draw content to temporary surface
|
||||
cairo_surface_t* pContent = cairo_surface_create_similar(
|
||||
pTarget, cairo_surface_get_content(pTarget), ceil(aVisibleRange.getWidth()),
|
||||
ceil(aVisibleRange.getHeight()));
|
||||
CairoPixelProcessor2D aContent(aViewInformation2D, pContent);
|
||||
aContent.process(rTransCandidate.getChildren());
|
||||
|
||||
// munge the temporary surfaces to our target surface
|
||||
cairo_set_source_surface(mpRT, pContent, aVisibleRange.getMinX(), aVisibleRange.getMinY());
|
||||
cairo_mask_surface(mpRT, pMask, aVisibleRange.getMinX(), aVisibleRange.getMinY());
|
||||
|
||||
cairo_surface_destroy(pContent);
|
||||
cairo_surface_destroy(pMask);
|
||||
}
|
||||
|
||||
void CairoPixelProcessor2D::processMaskPrimitive2DPixel(
|
||||
const primitive2d::MaskPrimitive2D& rMaskCandidate)
|
||||
{
|
||||
if (rMaskCandidate.getChildren().empty())
|
||||
return;
|
||||
|
||||
basegfx::B2DPolyPolygon aMask(rMaskCandidate.getMask());
|
||||
|
||||
if (!aMask.count())
|
||||
return;
|
||||
|
||||
double clip_x1, clip_x2, clip_y1, clip_y2;
|
||||
cairo_clip_extents(mpRT, &clip_x1, &clip_y1, &clip_x2, &clip_y2);
|
||||
|
||||
basegfx::B2DRange aMaskRange(aMask.getB2DRange());
|
||||
aMaskRange.transform(getViewInformation2D().getObjectToViewTransformation());
|
||||
const basegfx::B2DRange aViewRange(basegfx::B2DPoint(clip_x1, clip_y1),
|
||||
basegfx::B2DPoint(clip_x2, clip_y2));
|
||||
|
||||
if (!aViewRange.overlaps(aMaskRange))
|
||||
return;
|
||||
|
||||
cairo_save(mpRT);
|
||||
|
||||
cairo_matrix_t aMatrix;
|
||||
const basegfx::B2DHomMatrix& rObjectToView(
|
||||
getViewInformation2D().getObjectToViewTransformation());
|
||||
cairo_matrix_init(&aMatrix, rObjectToView.a(), rObjectToView.b(), rObjectToView.c(),
|
||||
rObjectToView.d(), rObjectToView.e(), rObjectToView.f());
|
||||
|
||||
// set linear transformation
|
||||
cairo_set_matrix(mpRT, &aMatrix);
|
||||
|
||||
// put mask as path
|
||||
for (const auto& rPolygon : aMask)
|
||||
addB2DPolygonToPathGeometry(mpRT, rPolygon, &getViewInformation2D());
|
||||
|
||||
// clip to this mask
|
||||
cairo_clip(mpRT);
|
||||
|
||||
process(rMaskCandidate.getChildren());
|
||||
|
||||
cairo_restore(mpRT);
|
||||
}
|
||||
|
||||
void CairoPixelProcessor2D::processPointArrayPrimitive2D(
|
||||
const primitive2d::PointArrayPrimitive2D& rPointArrayCandidate)
|
||||
{
|
||||
const std::vector<basegfx::B2DPoint>& rPositions(rPointArrayCandidate.getPositions());
|
||||
if (rPositions.empty())
|
||||
return;
|
||||
|
||||
const basegfx::BColor aPointColor(
|
||||
maBColorModifierStack.getModifiedColor(rPointArrayCandidate.getRGBColor()));
|
||||
cairo_set_source_rgb(mpRT, aPointColor.getRed(), aPointColor.getGreen(), aPointColor.getBlue());
|
||||
|
||||
// To really paint a single pixel I found nothing better than
|
||||
// switch off AA and draw a pixel-aligned rectangle
|
||||
const cairo_antialias_t eOldAAMode(cairo_get_antialias(mpRT));
|
||||
cairo_set_antialias(mpRT, CAIRO_ANTIALIAS_NONE);
|
||||
|
||||
for (auto const& pos : rPositions)
|
||||
{
|
||||
const basegfx::B2DPoint aDiscretePos(getViewInformation2D().getObjectToViewTransformation()
|
||||
* pos);
|
||||
const double fX(ceil(aDiscretePos.getX()));
|
||||
const double fY(ceil(aDiscretePos.getY()));
|
||||
|
||||
cairo_rectangle(mpRT, fX, fY, 1, 1);
|
||||
cairo_fill(mpRT);
|
||||
}
|
||||
|
||||
cairo_set_antialias(mpRT, eOldAAMode);
|
||||
}
|
||||
|
||||
void CairoPixelProcessor2D::processModifiedColorPrimitive2D(
|
||||
const primitive2d::ModifiedColorPrimitive2D& rModifiedCandidate)
|
||||
{
|
||||
if (!rModifiedCandidate.getChildren().empty())
|
||||
{
|
||||
maBColorModifierStack.push(rModifiedCandidate.getColorModifier());
|
||||
process(rModifiedCandidate.getChildren());
|
||||
maBColorModifierStack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
void CairoPixelProcessor2D::processTransformPrimitive2D(
|
||||
const primitive2d::TransformPrimitive2D& rTransformCandidate)
|
||||
{
|
||||
// remember current transformation and ViewInformation
|
||||
const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D());
|
||||
|
||||
// create new transformations for local ViewInformation2D
|
||||
geometry::ViewInformation2D aViewInformation2D(getViewInformation2D());
|
||||
aViewInformation2D.setObjectTransformation(getViewInformation2D().getObjectTransformation()
|
||||
* rTransformCandidate.getTransformation());
|
||||
updateViewInformation(aViewInformation2D);
|
||||
|
||||
// process content
|
||||
process(rTransformCandidate.getChildren());
|
||||
|
||||
// restore transformations
|
||||
updateViewInformation(aLastViewInformation2D);
|
||||
}
|
||||
|
||||
void CairoPixelProcessor2D::processPolygonStrokePrimitive2D(
|
||||
const primitive2d::PolygonStrokePrimitive2D& rPolygonStrokeCandidate)
|
||||
{
|
||||
const basegfx::B2DPolygon& rPolygon(rPolygonStrokeCandidate.getB2DPolygon());
|
||||
const attribute::LineAttribute& rLineAttribute(rPolygonStrokeCandidate.getLineAttribute());
|
||||
|
||||
if (!rPolygon.count() || rLineAttribute.getWidth() < 0.0)
|
||||
{
|
||||
// no geometry, done
|
||||
return;
|
||||
}
|
||||
|
||||
// get some values early that might be used for decisions
|
||||
const bool bHairline(0.0 == rLineAttribute.getWidth());
|
||||
const basegfx::B2DHomMatrix& rObjectToView(
|
||||
getViewInformation2D().getObjectToViewTransformation());
|
||||
const double fDiscreteLineWidth(
|
||||
bHairline ? 1.0
|
||||
: ceil((rObjectToView * basegfx::B2DVector(rLineAttribute.getWidth(), 0.0))
|
||||
.getLength()));
|
||||
|
||||
// Here for every combination which the system-specific implementation is not
|
||||
// capable of visualizing, use the (for decomposable Primitives always possible)
|
||||
// fallback to the decomposition.
|
||||
if (basegfx::B2DLineJoin::NONE == rLineAttribute.getLineJoin() && fDiscreteLineWidth > 1.5)
|
||||
{
|
||||
// basegfx::B2DLineJoin::NONE is special for our office, no other GraphicSystem
|
||||
// knows that (so far), so fallback to decomposition. This is only needed if
|
||||
// LineJoin will be used, so also check for discrete LineWidth before falling back
|
||||
process(rPolygonStrokeCandidate);
|
||||
return;
|
||||
}
|
||||
|
||||
// This is a method every system-specific implementation of a decomposable Primitive
|
||||
// can use to allow simple optical control of paint implementation:
|
||||
// Create a copy, e.g. change color to 'red' as here and paint before the system
|
||||
// paints it using the decomposition. That way you can - if active - directly
|
||||
// optically compare if the system-specific solution is geometrically identical to
|
||||
// the decomposition (which defines our interpretation that we need to visualize).
|
||||
// Look below in the impl for bRenderDecomposeForCompareInRed to see that in that case
|
||||
// we create a half-transparent paint to better support visual control
|
||||
static bool bRenderDecomposeForCompareInRed(false);
|
||||
|
||||
if (bRenderDecomposeForCompareInRed)
|
||||
{
|
||||
const attribute::LineAttribute aRed(
|
||||
basegfx::BColor(1.0, 0.0, 0.0), rLineAttribute.getWidth(), rLineAttribute.getLineJoin(),
|
||||
rLineAttribute.getLineCap(), rLineAttribute.getMiterMinimumAngle());
|
||||
rtl::Reference<primitive2d::PolygonStrokePrimitive2D> xCopy(
|
||||
new primitive2d::PolygonStrokePrimitive2D(
|
||||
rPolygonStrokeCandidate.getB2DPolygon(), aRed,
|
||||
rPolygonStrokeCandidate.getStrokeAttribute()));
|
||||
process(*xCopy);
|
||||
}
|
||||
|
||||
cairo_save(mpRT);
|
||||
|
||||
cairo_matrix_t aMatrix;
|
||||
const double fAAOffset(getViewInformation2D().getUseAntiAliasing() ? 0.5 : 0.0);
|
||||
cairo_matrix_init(&aMatrix, rObjectToView.a(), rObjectToView.b(), rObjectToView.c(),
|
||||
rObjectToView.d(), rObjectToView.e() + fAAOffset,
|
||||
rObjectToView.f() + fAAOffset);
|
||||
|
||||
// set linear transformation
|
||||
cairo_set_matrix(mpRT, &aMatrix);
|
||||
|
||||
// setup line attributes
|
||||
cairo_line_join_t eCairoLineJoin = CAIRO_LINE_JOIN_MITER;
|
||||
switch (rLineAttribute.getLineJoin())
|
||||
{
|
||||
case basegfx::B2DLineJoin::Bevel:
|
||||
eCairoLineJoin = CAIRO_LINE_JOIN_BEVEL;
|
||||
break;
|
||||
case basegfx::B2DLineJoin::Round:
|
||||
eCairoLineJoin = CAIRO_LINE_JOIN_ROUND;
|
||||
break;
|
||||
case basegfx::B2DLineJoin::NONE:
|
||||
case basegfx::B2DLineJoin::Miter:
|
||||
eCairoLineJoin = CAIRO_LINE_JOIN_MITER;
|
||||
break;
|
||||
}
|
||||
|
||||
// convert miter minimum angle to miter limit
|
||||
double fMiterLimit
|
||||
= 1.0 / sin(std::max(rLineAttribute.getMiterMinimumAngle(), 0.01 * M_PI) / 2.0);
|
||||
|
||||
// setup cap attribute
|
||||
cairo_line_cap_t eCairoLineCap(CAIRO_LINE_CAP_BUTT);
|
||||
|
||||
switch (rLineAttribute.getLineCap())
|
||||
{
|
||||
default: // css::drawing::LineCap_BUTT:
|
||||
{
|
||||
eCairoLineCap = CAIRO_LINE_CAP_BUTT;
|
||||
break;
|
||||
}
|
||||
case css::drawing::LineCap_ROUND:
|
||||
{
|
||||
eCairoLineCap = CAIRO_LINE_CAP_ROUND;
|
||||
break;
|
||||
}
|
||||
case css::drawing::LineCap_SQUARE:
|
||||
{
|
||||
eCairoLineCap = CAIRO_LINE_CAP_SQUARE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
basegfx::BColor aLineColor(maBColorModifierStack.getModifiedColor(rLineAttribute.getColor()));
|
||||
if (bRenderDecomposeForCompareInRed)
|
||||
aLineColor.setRed(0.5);
|
||||
|
||||
cairo_set_source_rgb(mpRT, aLineColor.getRed(), aLineColor.getGreen(), aLineColor.getBlue());
|
||||
|
||||
cairo_set_line_join(mpRT, eCairoLineJoin);
|
||||
cairo_set_line_cap(mpRT, eCairoLineCap);
|
||||
|
||||
// TODO: Hairline LineWidth, see comment at processPolygonHairlinePrimitive2D
|
||||
cairo_set_line_width(mpRT, bHairline ? 1.44 : fDiscreteLineWidth);
|
||||
cairo_set_miter_limit(mpRT, fMiterLimit);
|
||||
|
||||
const attribute::StrokeAttribute& rStrokeAttribute(
|
||||
rPolygonStrokeCandidate.getStrokeAttribute());
|
||||
const bool bDashUsed(!rStrokeAttribute.isDefault()
|
||||
&& !rStrokeAttribute.getDotDashArray().empty()
|
||||
&& 0.0 < rStrokeAttribute.getFullDotDashLen());
|
||||
if (bDashUsed)
|
||||
{
|
||||
const std::vector<double>& rStroke = rStrokeAttribute.getDotDashArray();
|
||||
cairo_set_dash(mpRT, rStroke.data(), rStroke.size(), 0.0);
|
||||
}
|
||||
|
||||
addB2DPolygonToPathGeometry(mpRT, rPolygon, &getViewInformation2D());
|
||||
|
||||
cairo_stroke(mpRT);
|
||||
|
||||
cairo_restore(mpRT);
|
||||
}
|
||||
|
||||
void CairoPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate)
|
||||
{
|
||||
switch (rCandidate.getPrimitive2DID())
|
||||
{
|
||||
#if 0
|
||||
// geometry that *has* to be processed
|
||||
case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D:
|
||||
{
|
||||
processBitmapPrimitive2D(
|
||||
static_cast<const primitive2d::BitmapPrimitive2D&>(rCandidate));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D:
|
||||
{
|
||||
processPointArrayPrimitive2D(
|
||||
static_cast<const primitive2d::PointArrayPrimitive2D&>(rCandidate));
|
||||
break;
|
||||
}
|
||||
case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D:
|
||||
{
|
||||
processPolygonHairlinePrimitive2D(
|
||||
static_cast<const primitive2d::PolygonHairlinePrimitive2D&>(rCandidate));
|
||||
break;
|
||||
}
|
||||
case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D:
|
||||
{
|
||||
processPolyPolygonColorPrimitive2D(
|
||||
static_cast<const primitive2d::PolyPolygonColorPrimitive2D&>(rCandidate));
|
||||
break;
|
||||
}
|
||||
// embedding/groups that *have* to be processed
|
||||
case PRIMITIVE2D_ID_TRANSPARENCEPRIMITIVE2D:
|
||||
{
|
||||
processTransparencePrimitive2D(
|
||||
static_cast<const primitive2d::TransparencePrimitive2D&>(rCandidate));
|
||||
break;
|
||||
}
|
||||
case PRIMITIVE2D_ID_INVERTPRIMITIVE2D:
|
||||
{
|
||||
// TODO: fallback is at VclPixelProcessor2D::processInvertPrimitive2D, so
|
||||
// not in reach. Ignore for now.
|
||||
// processInvertPrimitive2D(rCandidate);
|
||||
break;
|
||||
}
|
||||
case PRIMITIVE2D_ID_MASKPRIMITIVE2D:
|
||||
{
|
||||
processMaskPrimitive2DPixel(
|
||||
static_cast<const primitive2d::MaskPrimitive2D&>(rCandidate));
|
||||
break;
|
||||
}
|
||||
case PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D:
|
||||
{
|
||||
processModifiedColorPrimitive2D(
|
||||
static_cast<const primitive2d::ModifiedColorPrimitive2D&>(rCandidate));
|
||||
break;
|
||||
}
|
||||
case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D:
|
||||
{
|
||||
processTransformPrimitive2D(
|
||||
static_cast<const primitive2d::TransformPrimitive2D&>(rCandidate));
|
||||
break;
|
||||
}
|
||||
#if 0
|
||||
// geometry that *may* be processed due to being able to do it better
|
||||
// then using the decomposition
|
||||
case PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D:
|
||||
{
|
||||
processUnifiedTransparencePrimitive2D(
|
||||
static_cast<const primitive2d::UnifiedTransparencePrimitive2D&>(rCandidate));
|
||||
break;
|
||||
}
|
||||
case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D:
|
||||
{
|
||||
processMarkerArrayPrimitive2D(
|
||||
static_cast<const primitive2d::MarkerArrayPrimitive2D&>(rCandidate));
|
||||
break;
|
||||
}
|
||||
case PRIMITIVE2D_ID_BACKGROUNDCOLORPRIMITIVE2D:
|
||||
{
|
||||
processBackgroundColorPrimitive2D(
|
||||
static_cast<const primitive2d::BackgroundColorPrimitive2D&>(rCandidate));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D:
|
||||
{
|
||||
processPolygonStrokePrimitive2D(
|
||||
static_cast<const primitive2d::PolygonStrokePrimitive2D&>(rCandidate));
|
||||
break;
|
||||
}
|
||||
|
||||
// continue with decompose
|
||||
default:
|
||||
{
|
||||
SAL_INFO("drawinglayer", "default case for " << drawinglayer::primitive2d::idToString(
|
||||
rCandidate.getPrimitive2DID()));
|
||||
// process recursively
|
||||
process(rCandidate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // end of namespace
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
|
|
@ -18,12 +18,15 @@
|
|||
*/
|
||||
#include <drawinglayer/processor2d/processor2dtools.hxx>
|
||||
#include <vcl/gdimtf.hxx>
|
||||
#include <vcl/sysdata.hxx>
|
||||
#include "vclpixelprocessor2d.hxx"
|
||||
#include "vclmetafileprocessor2d.hxx"
|
||||
#include <config_vclplug.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <drawinglayer/processor2d/d2dpixelprocessor2d.hxx>
|
||||
#include <vcl/sysdata.hxx>
|
||||
#elif USE_HEADLESS_CODE
|
||||
#include <drawinglayer/processor2d/cairopixelprocessor2d.hxx>
|
||||
#endif
|
||||
|
||||
using namespace com::sun::star;
|
||||
|
@ -34,11 +37,9 @@ std::unique_ptr<BaseProcessor2D> createPixelProcessor2DFromOutputDevice(
|
|||
OutputDevice& rTargetOutDev,
|
||||
const drawinglayer::geometry::ViewInformation2D& rViewInformation2D)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
static const bool bTestSystemPrimitiveRenderer(nullptr != std::getenv("TEST_SYSTEM_PRIMITIVE_RENDERER"));
|
||||
if(bTestSystemPrimitiveRenderer)
|
||||
{
|
||||
SystemGraphicsData aData(rTargetOutDev.GetSystemGfxData());
|
||||
drawinglayer::geometry::ViewInformation2D aViewInformation2D(rViewInformation2D);
|
||||
// if mnOutOffX/mnOutOffY is set (a 'hack' to get a cheap additional offset), apply it additionally
|
||||
if(0 != rTargetOutDev.GetOutOffXPixel() || 0 != rTargetOutDev.GetOutOffYPixel())
|
||||
|
@ -47,12 +48,20 @@ std::unique_ptr<BaseProcessor2D> createPixelProcessor2DFromOutputDevice(
|
|||
aTransform.translate(rTargetOutDev.GetOutOffXPixel(), rTargetOutDev.GetOutOffYPixel());
|
||||
aViewInformation2D.setViewTransformation(aTransform);
|
||||
}
|
||||
#if defined(_WIN32)
|
||||
SystemGraphicsData aData(rTargetOutDev.GetSystemGfxData());
|
||||
std::unique_ptr<D2DPixelProcessor2D> aRetval(
|
||||
std::make_unique<D2DPixelProcessor2D>(aViewInformation2D, aData.hDC));
|
||||
if (aRetval->valid())
|
||||
return aRetval;
|
||||
}
|
||||
#elif USE_HEADLESS_CODE
|
||||
SystemGraphicsData aData(rTargetOutDev.GetSystemGfxData());
|
||||
std::unique_ptr<CairoPixelProcessor2D> aRetval(
|
||||
std::make_unique<CairoPixelProcessor2D>(aViewInformation2D, static_cast<cairo_surface_t*>(aData.pSurface)));
|
||||
if (aRetval->valid())
|
||||
return aRetval;
|
||||
#endif
|
||||
}
|
||||
|
||||
// create Pixel Vcl-Processor
|
||||
return std::make_unique<VclPixelProcessor2D>(rViewInformation2D, rTargetOutDev);
|
||||
|
|
104
include/drawinglayer/processor2d/cairopixelprocessor2d.hxx
Normal file
104
include/drawinglayer/processor2d/cairopixelprocessor2d.hxx
Normal file
|
@ -0,0 +1,104 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
|
||||
/*
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <drawinglayer/processor2d/baseprocessor2d.hxx>
|
||||
#include <basegfx/color/bcolormodifier.hxx>
|
||||
#include <sal/config.h>
|
||||
|
||||
// cairo-specific
|
||||
#include <cairo.h>
|
||||
|
||||
namespace drawinglayer::primitive2d
|
||||
{
|
||||
class PolyPolygonColorPrimitive2D;
|
||||
class PolygonHairlinePrimitive2D;
|
||||
class BitmapPrimitive2D;
|
||||
class UnifiedTransparencePrimitive2D;
|
||||
class BackgroundColorPrimitive2D;
|
||||
class TransparencePrimitive2D;
|
||||
class MaskPrimitive2D;
|
||||
class ModifiedColorPrimitive2D;
|
||||
class TransformPrimitive2D;
|
||||
class PointArrayPrimitive2D;
|
||||
class MarkerArrayPrimitive2D;
|
||||
class PolygonStrokePrimitive2D;
|
||||
}
|
||||
|
||||
namespace drawinglayer::processor2d
|
||||
{
|
||||
class DRAWINGLAYER_DLLPUBLIC CairoPixelProcessor2D : public BaseProcessor2D
|
||||
{
|
||||
// the modifiedColorPrimitive stack
|
||||
basegfx::BColorModifierStack maBColorModifierStack;
|
||||
|
||||
// cairo specific data
|
||||
cairo_t* mpRT;
|
||||
|
||||
// helpers for direct paints
|
||||
void processPolygonHairlinePrimitive2D(
|
||||
const primitive2d::PolygonHairlinePrimitive2D& rPolygonHairlinePrimitive2D);
|
||||
void processPolyPolygonColorPrimitive2D(
|
||||
const primitive2d::PolyPolygonColorPrimitive2D& rPolyPolygonColorPrimitive2D);
|
||||
#if 0
|
||||
void processBitmapPrimitive2D(const primitive2d::BitmapPrimitive2D& rBitmapCandidate);
|
||||
#endif
|
||||
void
|
||||
processTransparencePrimitive2D(const primitive2d::TransparencePrimitive2D& rTransCandidate);
|
||||
#if 0
|
||||
void processUnifiedTransparencePrimitive2D(
|
||||
const primitive2d::UnifiedTransparencePrimitive2D& rTransCandidate);
|
||||
#endif
|
||||
void processMaskPrimitive2DPixel(const primitive2d::MaskPrimitive2D& rMaskCandidate);
|
||||
void processModifiedColorPrimitive2D(
|
||||
const primitive2d::ModifiedColorPrimitive2D& rModifiedCandidate);
|
||||
void processTransformPrimitive2D(const primitive2d::TransformPrimitive2D& rTransformCandidate);
|
||||
void
|
||||
processPointArrayPrimitive2D(const primitive2d::PointArrayPrimitive2D& rPointArrayCandidate);
|
||||
#if 0
|
||||
void
|
||||
processMarkerArrayPrimitive2D(const primitive2d::MarkerArrayPrimitive2D& rMarkerArrayCandidate);
|
||||
void processBackgroundColorPrimitive2D(
|
||||
const primitive2d::BackgroundColorPrimitive2D& rBackgroundColorCandidate);
|
||||
#endif
|
||||
void processPolygonStrokePrimitive2D(
|
||||
const primitive2d::PolygonStrokePrimitive2D& rPolygonStrokeCandidate);
|
||||
#if 0
|
||||
// common helpers
|
||||
ID2D1Bitmap* implCreateAlpha_Direct(const primitive2d::TransparencePrimitive2D& rTransCandidate,
|
||||
const basegfx::B2DRange& rVisibleRange);
|
||||
ID2D1Bitmap*
|
||||
implCreateAlpha_B2DBitmap(const primitive2d::TransparencePrimitive2D& rTransCandidate,
|
||||
const basegfx::B2DRange& rVisibleRange,
|
||||
D2D1_MATRIX_3X2_F& rMaskScale);
|
||||
#endif
|
||||
|
||||
/* the local processor for BasePrimitive2D-Implementation based primitives,
|
||||
called from the common process()-implementation
|
||||
*/
|
||||
virtual void processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate) override;
|
||||
|
||||
protected:
|
||||
// local protected minimal constructor for usage in derivates, e.g. helpers
|
||||
CairoPixelProcessor2D(const geometry::ViewInformation2D& rViewInformation);
|
||||
|
||||
bool hasError() const { return cairo_status(mpRT) != CAIRO_STATUS_SUCCESS; }
|
||||
void setRenderTarget(cairo_t* mpNewRT) { mpRT = mpNewRT; }
|
||||
bool hasRenderTarget() const { return nullptr != mpRT; }
|
||||
|
||||
public:
|
||||
bool valid() const { return hasRenderTarget() && !hasError(); }
|
||||
CairoPixelProcessor2D(const geometry::ViewInformation2D& rViewInformation,
|
||||
cairo_surface_t* pTarget);
|
||||
virtual ~CairoPixelProcessor2D() override;
|
||||
};
|
||||
}
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
|
|
@ -17,13 +17,43 @@
|
|||
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_VCL_CAIRO_HXX
|
||||
#define INCLUDED_VCL_CAIRO_HXX
|
||||
#pragma once
|
||||
|
||||
#include <sal/config.h>
|
||||
#include <osl/endian.h>
|
||||
#include <vcl/Scanline.hxx>
|
||||
#include <vcl/vclptr.hxx>
|
||||
#include <config_features.h>
|
||||
#include <memory>
|
||||
|
||||
//Using formats that match cairo's formats. For android we patch cairo,
|
||||
//which is internal in that case, to swap the rgb components so that
|
||||
//cairo then matches the OpenGL GL_RGBA format so we can use it there
|
||||
//where we don't have GL_BGRA support.
|
||||
// SVP_24BIT_FORMAT is used to store 24-bit images in 3-byte pixels to conserve memory.
|
||||
#if defined(ANDROID) && !HAVE_FEATURE_ANDROID_LOK
|
||||
#define SVP_24BIT_FORMAT (ScanlineFormat::N24BitTcRgb | ScanlineFormat::TopDown)
|
||||
#define SVP_CAIRO_FORMAT (ScanlineFormat::N32BitTcRgba | ScanlineFormat::TopDown)
|
||||
#define SVP_CAIRO_BLUE 1
|
||||
#define SVP_CAIRO_GREEN 2
|
||||
#define SVP_CAIRO_RED 0
|
||||
#define SVP_CAIRO_ALPHA 3
|
||||
#elif defined OSL_BIGENDIAN
|
||||
#define SVP_24BIT_FORMAT (ScanlineFormat::N24BitTcRgb | ScanlineFormat::TopDown)
|
||||
#define SVP_CAIRO_FORMAT (ScanlineFormat::N32BitTcArgb | ScanlineFormat::TopDown)
|
||||
#define SVP_CAIRO_BLUE 3
|
||||
#define SVP_CAIRO_GREEN 2
|
||||
#define SVP_CAIRO_RED 1
|
||||
#define SVP_CAIRO_ALPHA 0
|
||||
#else
|
||||
#define SVP_24BIT_FORMAT (ScanlineFormat::N24BitTcBgr | ScanlineFormat::TopDown)
|
||||
#define SVP_CAIRO_FORMAT (ScanlineFormat::N32BitTcBgra | ScanlineFormat::TopDown)
|
||||
#define SVP_CAIRO_BLUE 0
|
||||
#define SVP_CAIRO_GREEN 1
|
||||
#define SVP_CAIRO_RED 2
|
||||
#define SVP_CAIRO_ALPHA 3
|
||||
#endif
|
||||
|
||||
typedef struct _cairo_surface cairo_surface_t;
|
||||
typedef struct _cairo cairo_t;
|
||||
|
||||
|
@ -64,6 +94,4 @@ namespace cairo {
|
|||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include <sal/types.h>
|
||||
#include <vcl/dllapi.h>
|
||||
#include <config_vclplug.h>
|
||||
|
||||
class SalFrame;
|
||||
|
||||
|
@ -156,7 +157,9 @@ struct SystemGraphicsData
|
|||
void* pVisual; // the visual in use
|
||||
int nScreen; // the current screen of the drawable
|
||||
void* pXRenderFormat; // render format for drawable
|
||||
void* pSurface; // the cairo surface when using svp-based backends
|
||||
#endif
|
||||
#if USE_HEADLESS_CODE
|
||||
void* pSurface; // the cairo surface when using svp-based backends, which includes gtk[3|4]
|
||||
#endif
|
||||
SystemGraphicsData()
|
||||
: nSize( sizeof( SystemGraphicsData ) )
|
||||
|
@ -175,6 +178,8 @@ struct SystemGraphicsData
|
|||
, pVisual( nullptr )
|
||||
, nScreen( 0 )
|
||||
, pXRenderFormat( nullptr )
|
||||
#endif
|
||||
#if USE_HEADLESS_CODE
|
||||
, pSurface( nullptr )
|
||||
#endif
|
||||
{ }
|
||||
|
|
|
@ -90,7 +90,9 @@ css::uno::Any SvpSalGraphics::GetNativeSurfaceHandle(cairo::SurfaceSharedPtr& /*
|
|||
|
||||
SystemGraphicsData SvpSalGraphics::GetGraphicsData() const
|
||||
{
|
||||
return SystemGraphicsData();
|
||||
SystemGraphicsData aGraphicsData;
|
||||
aGraphicsData.pSurface = m_aCairoCommon.m_pSurface;
|
||||
return aGraphicsData;
|
||||
}
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
||||
|
|
|
@ -40,34 +40,6 @@
|
|||
|
||||
#include <unordered_map>
|
||||
|
||||
//Using formats that match cairo's formats. For android we patch cairo,
|
||||
//which is internal in that case, to swap the rgb components so that
|
||||
//cairo then matches the OpenGL GL_RGBA format so we can use it there
|
||||
//where we don't have GL_BGRA support.
|
||||
// SVP_24BIT_FORMAT is used to store 24-bit images in 3-byte pixels to conserve memory.
|
||||
#if defined(ANDROID) && !HAVE_FEATURE_ANDROID_LOK
|
||||
#define SVP_24BIT_FORMAT (ScanlineFormat::N24BitTcRgb | ScanlineFormat::TopDown)
|
||||
#define SVP_CAIRO_FORMAT (ScanlineFormat::N32BitTcRgba | ScanlineFormat::TopDown)
|
||||
#define SVP_CAIRO_BLUE 1
|
||||
#define SVP_CAIRO_GREEN 2
|
||||
#define SVP_CAIRO_RED 0
|
||||
#define SVP_CAIRO_ALPHA 3
|
||||
#elif defined OSL_BIGENDIAN
|
||||
#define SVP_24BIT_FORMAT (ScanlineFormat::N24BitTcRgb | ScanlineFormat::TopDown)
|
||||
#define SVP_CAIRO_FORMAT (ScanlineFormat::N32BitTcArgb | ScanlineFormat::TopDown)
|
||||
#define SVP_CAIRO_BLUE 3
|
||||
#define SVP_CAIRO_GREEN 2
|
||||
#define SVP_CAIRO_RED 1
|
||||
#define SVP_CAIRO_ALPHA 0
|
||||
#else
|
||||
#define SVP_24BIT_FORMAT (ScanlineFormat::N24BitTcBgr | ScanlineFormat::TopDown)
|
||||
#define SVP_CAIRO_FORMAT (ScanlineFormat::N32BitTcBgra | ScanlineFormat::TopDown)
|
||||
#define SVP_CAIRO_BLUE 0
|
||||
#define SVP_CAIRO_GREEN 1
|
||||
#define SVP_CAIRO_RED 2
|
||||
#define SVP_CAIRO_ALPHA 3
|
||||
#endif
|
||||
|
||||
typedef struct _cairo cairo_t;
|
||||
typedef struct _cairo_surface cairo_surface_t;
|
||||
typedef struct _cairo_user_data_key cairo_user_data_key_t;
|
||||
|
|
|
@ -286,14 +286,12 @@ bool isVCLSkiaEnabled()
|
|||
static bool bEnable = false;
|
||||
static bool bForceSkia = false;
|
||||
|
||||
#if defined(_WIN32)
|
||||
// allow global disable when testing SystemPrimitiveRenderer since current Skia on Win does not
|
||||
// harmonize with using Direct2D and D2DPixelProcessor2D
|
||||
static const bool bTestSystemPrimitiveRenderer(
|
||||
nullptr != std::getenv("TEST_SYSTEM_PRIMITIVE_RENDERER"));
|
||||
if (bTestSystemPrimitiveRenderer)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
// No hardware rendering, so no Skia
|
||||
// TODO SKIA
|
||||
|
|
Loading…
Reference in a new issue