Files
odfstudio/vcl/unx/generic/gdi/salgdi.cxx
T
Caolán McNamara e510a208b0 move cairo helpers to vcl and make per-plug
Change-Id: I4de4d5c3a191784598e93a8cf70e45a3f59ae857
Reviewed-on: https://gerrit.libreoffice.org/14907
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
Tested-by: Caolán McNamara <caolanm@redhat.com>
2015-03-23 11:42:28 +00:00

568 lines
16 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 <config_graphite.h>
#include <vector>
#include <queue>
#include <set>
#include <prex.h>
#include <X11/Xproto.h>
#include <postx.h>
#include "tools/debug.hxx"
#include "basegfx/polygon/b2dpolygon.hxx"
#include "basegfx/polygon/b2dpolypolygon.hxx"
#include "basegfx/polygon/b2dpolypolygontools.hxx"
#include "basegfx/polygon/b2dpolygontools.hxx"
#include "basegfx/polygon/b2dpolygonclipper.hxx"
#include "basegfx/polygon/b2dlinegeometry.hxx"
#include "basegfx/matrix/b2dhommatrix.hxx"
#include "basegfx/matrix/b2dhommatrixtools.hxx"
#include "basegfx/polygon/b2dpolypolygoncutter.hxx"
#include "basegfx/polygon/b2dtrapezoid.hxx"
#include <vcl/jobdata.hxx>
#include <vcl/virdev.hxx>
#include "unx/salunx.h"
#include "unx/saldata.hxx"
#include "unx/saldisp.hxx"
#include "unx/salgdi.h"
#include "unx/salframe.h"
#include "unx/salvd.h"
#include "unx/x11/x11gdiimpl.h"
#include <unx/x11/xlimits.hxx>
#include "salgdiimpl.hxx"
#include "unx/x11windowprovider.hxx"
#include "textrender.hxx"
#include "gdiimpl.hxx"
#include "opengl/x11/gdiimpl.hxx"
#include "x11cairotextrender.hxx"
#include "openglx11cairotextrender.hxx"
#include "generic/printergfx.hxx"
#include "xrender_peer.hxx"
#include "cairo_cairo.hxx"
#include "cairo_xlib_cairo.hxx"
#include <vcl/opengl/OpenGLHelper.hxx>
X11SalGraphics::X11SalGraphics():
m_pFrame(NULL),
m_pVDev(NULL),
m_pColormap(NULL),
m_pDeleteColormap(NULL),
hDrawable_(None),
m_nXScreen( 0 ),
m_pXRenderFormat(NULL),
m_aXRenderPicture(0),
pPaintRegion_(NULL),
mpClipRegion(NULL),
pFontGC_(NULL),
nTextPixel_(0),
hBrush_(None),
bWindow_(false),
bPrinter_(false),
bVirDev_(false),
bFontGC_(false)
{
if (OpenGLHelper::isVCLOpenGLEnabled())
{
mxImpl.reset(new X11OpenGLSalGraphicsImpl(*this));
mxTextRenderImpl.reset((new OpenGLX11CairoTextRender(*this)));
}
else
{
mxTextRenderImpl.reset((new X11CairoTextRender(*this)));
mxImpl.reset(new X11SalGraphicsImpl(*this));
}
}
X11SalGraphics::~X11SalGraphics()
{
ReleaseFonts();
freeResources();
}
void X11SalGraphics::freeResources()
{
Display *pDisplay = GetXDisplay();
DBG_ASSERT( !pPaintRegion_, "pPaintRegion_" );
if( mpClipRegion ) XDestroyRegion( mpClipRegion ), mpClipRegion = None;
mxImpl->freeResources();
if( hBrush_ ) XFreePixmap( pDisplay, hBrush_ ), hBrush_ = None;
if( pFontGC_ ) XFreeGC( pDisplay, pFontGC_ ), pFontGC_ = None;
if( m_pDeleteColormap )
delete m_pDeleteColormap, m_pColormap = m_pDeleteColormap = NULL;
if( m_aXRenderPicture )
XRenderPeer::GetInstance().FreePicture( m_aXRenderPicture ), m_aXRenderPicture = 0;
bFontGC_ = false;
}
SalGraphicsImpl* X11SalGraphics::GetImpl() const
{
return mxImpl.get();
}
void X11SalGraphics::SetDrawable( Drawable aDrawable, SalX11Screen nXScreen )
{
// shortcut if nothing changed
if( hDrawable_ == aDrawable )
return;
// free screen specific resources if needed
if( nXScreen != m_nXScreen )
{
freeResources();
m_pColormap = &vcl_sal::getSalDisplay(GetGenericData())->GetColormap( nXScreen );
m_nXScreen = nXScreen;
}
hDrawable_ = aDrawable;
SetXRenderFormat( NULL );
if( m_aXRenderPicture )
{
XRenderPeer::GetInstance().FreePicture( m_aXRenderPicture );
m_aXRenderPicture = 0;
}
// TODO: moggi: FIXME nTextPixel_ = GetPixel( nTextColor_ );
}
void X11SalGraphics::Init( SalFrame *pFrame, Drawable aTarget,
SalX11Screen nXScreen )
{
m_pColormap = &vcl_sal::getSalDisplay(GetGenericData())->GetColormap(nXScreen);
m_nXScreen = nXScreen;
m_pFrame = pFrame;
m_pVDev = NULL;
bWindow_ = true;
bVirDev_ = false;
SetDrawable( aTarget, nXScreen );
mxImpl->Init();
}
void X11SalGraphics::DeInit()
{
SetDrawable( None, m_nXScreen );
}
void X11SalGraphics::SetClipRegion( GC pGC, Region pXReg ) const
{
Display *pDisplay = GetXDisplay();
int n = 0;
Region Regions[3];
if( mpClipRegion )
Regions[n++] = mpClipRegion;
if( pXReg && !XEmptyRegion( pXReg ) )
Regions[n++] = pXReg;
if( 0 == n )
XSetClipMask( pDisplay, pGC, None );
else if( 1 == n )
XSetRegion( pDisplay, pGC, Regions[0] );
else
{
Region pTmpRegion = XCreateRegion();
XIntersectRegion( Regions[0], Regions[1], pTmpRegion );
XSetRegion( pDisplay, pGC, pTmpRegion );
XDestroyRegion( pTmpRegion );
}
}
// Calculate a dither-pixmap and make a brush of it
#define P_DELTA 51
#define DMAP( v, m ) ((v % P_DELTA) > m ? (v / P_DELTA) + 1 : (v / P_DELTA))
bool X11SalGraphics::GetDitherPixmap( SalColor nSalColor )
{
static const short nOrdDither8Bit[ 8 ][ 8 ] =
{
{ 0, 38, 9, 48, 2, 40, 12, 50},
{25, 12, 35, 22, 28, 15, 37, 24},
{ 6, 44, 3, 41, 8, 47, 5, 44},
{32, 19, 28, 16, 34, 21, 31, 18},
{ 1, 40, 11, 49, 0, 39, 10, 48},
{27, 14, 36, 24, 26, 13, 36, 23},
{ 8, 46, 4, 43, 7, 45, 4, 42},
{33, 20, 30, 17, 32, 20, 29, 16}
};
// test for correct depth (8bit)
if( GetColormap().GetVisual().GetDepth() != 8 )
return false;
char pBits[64];
char *pBitsPtr = pBits;
// Set the pallette-entries for the dithering tile
sal_uInt8 nSalColorRed = SALCOLOR_RED ( nSalColor );
sal_uInt8 nSalColorGreen = SALCOLOR_GREEN ( nSalColor );
sal_uInt8 nSalColorBlue = SALCOLOR_BLUE ( nSalColor );
for( int nY = 0; nY < 8; nY++ )
{
for( int nX = 0; nX < 8; nX++ )
{
short nMagic = nOrdDither8Bit[nY][nX];
sal_uInt8 nR = P_DELTA * DMAP( nSalColorRed, nMagic );
sal_uInt8 nG = P_DELTA * DMAP( nSalColorGreen, nMagic );
sal_uInt8 nB = P_DELTA * DMAP( nSalColorBlue, nMagic );
*pBitsPtr++ = GetColormap().GetPixel( MAKE_SALCOLOR( nR, nG, nB ) );
}
}
// create the tile as ximage and an according pixmap -> caching
XImage *pImage = XCreateImage( GetXDisplay(),
GetColormap().GetXVisual(),
8,
ZPixmap,
0, // offset
pBits, // data
8, 8, // width & height
8, // bitmap_pad
0 ); // (default) bytes_per_line
if( !hBrush_ )
hBrush_ = limitXCreatePixmap( GetXDisplay(), GetDrawable(), 8, 8, 8 );
// put the ximage to the pixmap
XPutImage( GetXDisplay(),
hBrush_,
GetDisplay()->GetCopyGC( m_nXScreen ),
pImage,
0, 0, // Source
0, 0, // Destination
8, 8 ); // width & height
// destroy image-frame but not palette-data
pImage->data = NULL;
XDestroyImage( pImage );
return true;
}
void X11SalGraphics::GetResolution( sal_Int32 &rDPIX, sal_Int32 &rDPIY ) // const
{
const SalDisplay *pDisplay = GetDisplay();
if (!pDisplay)
{
OSL_TRACE("Null display");
rDPIX = rDPIY = 96;
return;
}
Pair dpi = pDisplay->GetResolution();
rDPIX = dpi.A();
rDPIY = dpi.B();
if ( rDPIY > 200 )
{
rDPIX = Divide( rDPIX * 200, rDPIY );
rDPIY = 200;
}
// #i12705# equalize x- and y-resolution if they are close enough
if( rDPIX != rDPIY )
{
// different x- and y- resolutions are usually artifacts of
// a wrongly calculated screen size.
#ifdef DEBUG
printf("Forcing Resolution from %" SAL_PRIdINT32 "x%" SAL_PRIdINT32 " to %" SAL_PRIdINT32 "x%" SAL_PRIdINT32 "\n",
rDPIX,rDPIY,rDPIY,rDPIY);
#endif
rDPIX = rDPIY; // y-resolution is more trustworthy
}
}
sal_uInt16 X11SalGraphics::GetBitCount() const
{
return mxImpl->GetBitCount();
}
long X11SalGraphics::GetGraphicsWidth() const
{
return mxImpl->GetGraphicsWidth();
}
void X11SalGraphics::ResetClipRegion()
{
mxImpl->ResetClipRegion();
}
bool X11SalGraphics::setClipRegion( const vcl::Region& i_rClip )
{
return mxImpl->setClipRegion( i_rClip );
}
void X11SalGraphics::SetLineColor()
{
mxImpl->SetLineColor();
}
void X11SalGraphics::SetLineColor( SalColor nSalColor )
{
mxImpl->SetLineColor( nSalColor );
}
void X11SalGraphics::SetFillColor()
{
mxImpl->SetFillColor();
}
void X11SalGraphics::SetFillColor( SalColor nSalColor )
{
mxImpl->SetFillColor( nSalColor );
}
void X11SalGraphics::SetROPLineColor( SalROPColor nROPColor )
{
mxImpl->SetROPLineColor( nROPColor );
}
void X11SalGraphics::SetROPFillColor( SalROPColor nROPColor )
{
mxImpl->SetROPFillColor( nROPColor );
}
void X11SalGraphics::SetXORMode( bool bSet, bool bInvertOnly )
{
mxImpl->SetXORMode( bSet, bInvertOnly );
}
void X11SalGraphics::drawPixel( long nX, long nY )
{
mxImpl->drawPixel( nX, nY );
}
void X11SalGraphics::drawPixel( long nX, long nY, SalColor nSalColor )
{
mxImpl->drawPixel( nX, nY, nSalColor );
}
void X11SalGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 )
{
mxImpl->drawLine( nX1, nY1, nX2, nY2 );
}
void X11SalGraphics::drawRect( long nX, long nY, long nDX, long nDY )
{
mxImpl->drawRect( nX, nY, nDX, nDY );
}
void X11SalGraphics::drawPolyLine( sal_uInt32 nPoints, const SalPoint *pPtAry )
{
mxImpl->drawPolyLine( nPoints, pPtAry );
}
void X11SalGraphics::drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry )
{
mxImpl->drawPolygon( nPoints, pPtAry );
}
void X11SalGraphics::drawPolyPolygon( sal_uInt32 nPoly,
const sal_uInt32 *pPoints,
PCONSTSALPOINT *pPtAry )
{
mxImpl->drawPolyPolygon( nPoly, pPoints, pPtAry );
}
bool X11SalGraphics::drawPolyLineBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const sal_uInt8* pFlgAry )
{
return mxImpl->drawPolyLineBezier( nPoints, pPtAry, pFlgAry );
}
bool X11SalGraphics::drawPolygonBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const sal_uInt8* pFlgAry )
{
return mxImpl->drawPolygonBezier( nPoints, pPtAry, pFlgAry );
}
bool X11SalGraphics::drawPolyPolygonBezier( sal_uInt32 nPoints, const sal_uInt32* pPoints,
const SalPoint* const* pPtAry, const sal_uInt8* const* pFlgAry)
{
return mxImpl->drawPolyPolygonBezier( nPoints, pPoints, pPtAry, pFlgAry );
}
void X11SalGraphics::invert( sal_uInt32 nPoints,
const SalPoint* pPtAry,
SalInvert nFlags )
{
mxImpl->invert( nPoints, pPtAry, nFlags );
}
bool X11SalGraphics::drawEPS( long nX, long nY, long nWidth,
long nHeight, void* pPtr, sal_uLong nSize )
{
return mxImpl->drawEPS( nX, nY, nWidth, nHeight, pPtr, nSize );
}
XRenderPictFormat* X11SalGraphics::GetXRenderFormat() const
{
if( m_pXRenderFormat == NULL )
m_pXRenderFormat = XRenderPeer::GetInstance().FindVisualFormat( GetVisual().visual );
return m_pXRenderFormat;
}
SystemGraphicsData X11SalGraphics::GetGraphicsData() const
{
SystemGraphicsData aRes;
aRes.nSize = sizeof(aRes);
aRes.pDisplay = GetXDisplay();
aRes.hDrawable = hDrawable_;
aRes.pVisual = GetVisual().visual;
aRes.nScreen = m_nXScreen.getXScreen();
aRes.nDepth = GetBitCount();
aRes.aColormap = GetColormap().GetXColormap();
aRes.pXRenderFormat = m_pXRenderFormat;
return aRes;
}
bool X11SalGraphics::SupportsCairo() const
{
Display *pDisplay = GetXDisplay();
int nDummy;
return XQueryExtension(pDisplay, "RENDER", &nDummy, &nDummy, &nDummy);
}
cairo::SurfaceSharedPtr X11SalGraphics::CreateSurface(const cairo::CairoSurfaceSharedPtr& rSurface) const
{
return cairo::SurfaceSharedPtr(new cairo::X11Surface(rSurface));
}
namespace
{
static cairo::X11SysData getSysData( const vcl::Window& rWindow )
{
const SystemEnvData* pSysData = cairo::GetSysData(&rWindow);
if( !pSysData )
return cairo::X11SysData();
else
return cairo::X11SysData(*pSysData);
}
static cairo::X11SysData getSysData( const VirtualDevice& rVirDev )
{
return cairo::X11SysData( rVirDev.GetSystemGfxData() );
}
}
cairo::SurfaceSharedPtr X11SalGraphics::CreateSurface( const OutputDevice& rRefDevice,
int x, int y, int width, int height ) const
{
if( rRefDevice.GetOutDevType() == OUTDEV_WINDOW )
return cairo::SurfaceSharedPtr(new cairo::X11Surface(getSysData(static_cast<const vcl::Window&>(rRefDevice)),
x,y,width,height));
if( rRefDevice.GetOutDevType() == OUTDEV_VIRDEV )
return cairo::SurfaceSharedPtr(new cairo::X11Surface(getSysData(static_cast<const VirtualDevice&>(rRefDevice)),
x,y,width,height));
return cairo::SurfaceSharedPtr();
}
cairo::SurfaceSharedPtr X11SalGraphics::CreateBitmapSurface( const OutputDevice& rRefDevice,
const BitmapSystemData& rData,
const Size& rSize ) const
{
SAL_INFO(
"canvas.cairo",
"requested size: " << rSize.Width() << " x " << rSize.Height()
<< " available size: " << rData.mnWidth << " x "
<< rData.mnHeight);
if ( rData.mnWidth == rSize.Width() && rData.mnHeight == rSize.Height() )
{
if( rRefDevice.GetOutDevType() == OUTDEV_WINDOW )
return cairo::SurfaceSharedPtr(new cairo::X11Surface(getSysData(static_cast<const vcl::Window&>(rRefDevice)), rData ));
else if( rRefDevice.GetOutDevType() == OUTDEV_VIRDEV )
return cairo::SurfaceSharedPtr(new cairo::X11Surface(getSysData(static_cast<const VirtualDevice&>(rRefDevice)), rData ));
}
return cairo::SurfaceSharedPtr();
}
css::uno::Any X11SalGraphics::GetNativeSurfaceHandle(cairo::SurfaceSharedPtr& rSurface, const ::basegfx::B2ISize& /*rSize*/) const
{
cairo::X11Surface& rXlibSurface=dynamic_cast<cairo::X11Surface&>(*rSurface.get());
css::uno::Sequence< css::uno::Any > args( 3 );
args[0] = css::uno::Any( false ); // do not call XFreePixmap on it
args[1] = css::uno::Any( rXlibSurface.getPixmap()->mhDrawable );
args[2] = css::uno::Any( sal_Int32( rXlibSurface.getDepth() ) );
return css::uno::Any(args);
}
// draw a poly-polygon
bool X11SalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rOrigPolyPoly, double fTransparency )
{
return mxImpl->drawPolyPolygon( rOrigPolyPoly, fTransparency );
}
bool X11SalGraphics::drawPolyLine(
const ::basegfx::B2DPolygon& rPolygon,
double fTransparency,
const ::basegfx::B2DVector& rLineWidth,
basegfx::B2DLineJoin eLineJoin,
com::sun::star::drawing::LineCap eLineCap)
{
return mxImpl->drawPolyLine( rPolygon, fTransparency, rLineWidth,
eLineJoin, eLineCap );
}
bool X11SalGraphics::drawGradient(const tools::PolyPolygon& rPoly, const Gradient& rGradient)
{
return mxImpl->drawGradient(rPoly, rGradient);
}
void X11SalGraphics::BeginPaint()
{
return mxImpl->beginPaint();
}
void X11SalGraphics::EndPaint()
{
return mxImpl->endPaint();
}
SalGeometryProvider *X11SalGraphics::GetGeometryProvider() const
{
if (m_pFrame)
return static_cast< SalGeometryProvider * >(m_pFrame);
else
return static_cast< SalGeometryProvider * >(m_pVDev);
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */