diff options
Diffstat (limited to 'canvas/source/directx')
53 files changed, 14116 insertions, 0 deletions
diff --git a/canvas/source/directx/dx_5rm.cxx b/canvas/source/directx/dx_5rm.cxx new file mode 100755 index 000000000000..4937934732cd --- /dev/null +++ b/canvas/source/directx/dx_5rm.cxx @@ -0,0 +1,2286 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_5rm.cxx,v $ + * $Revision: 1.5 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#if DIRECTX_VERSION < 0x0900 + +// Nvidia GeForce Go 6800 crashes with a bluescreen if we take the +// maximum texture size, which would be twice as large. this behaviors +// has only been observed on directx5. +// This value is simply the maximum size for textures we request from +// the system, it has absolutely nothing to do with the size of primitives +// we're able to render, both concepts are totally independent from each other. +#define MAX_TEXTURE_SIZE (2048) +#define MIN_TEXTURE_SIZE (32) +//#define FAKE_MAX_NUMBER_TEXTURES (2) +//#define FAKE_MAX_TEXTURE_SIZE (512) + +////////////////////////////////////////////////////////////////////////////////// +// includes +////////////////////////////////////////////////////////////////////////////////// +#include <vcl/syschild.hxx> +#include <vcl/window.hxx> +#include <canvas/debug.hxx> +#include <canvas/verbosetrace.hxx> +#include <canvas/elapsedtime.hxx> +#include <canvas/canvastools.hxx> +#include <canvas/rendering/icolorbuffer.hxx> +#include <canvas/rendering/isurface.hxx> +#include <canvas/rendering/irendermodule.hxx> +#include <tools/diagnose_ex.h> +#include <basegfx/numeric/ftools.hxx> +#include <basegfx/vector/b2dsize.hxx> +#include <basegfx/vector/b2isize.hxx> +#include <basegfx/point/b2ipoint.hxx> +#include <basegfx/range/b2irectangle.hxx> +#include <boost/scoped_ptr.hpp> +#include <com/sun/star/lang/NoSupportException.hpp> + +#define COMPILE_MULTIMON_STUBS + +#include "dx_rendermodule.hxx" +#include "dx_surfacegraphics.hxx" +#include <vcl/sysdata.hxx> + +#undef WB_LEFT +#undef WB_RIGHT + +#include "dx_impltools.hxx" +#include <malloc.h> + +#if defined(DX_DEBUG_IMAGES) +# if OSL_DEBUG_LEVEL > 0 +# include <imdebug.h> +# undef min +# undef max +# endif +#endif + +#undef COMPILE_MULTIMON_STUBS + +#include <stdio.h> + +#define MONITOR_DEFAULTTONULL 0x00000000 +#define MONITOR_DEFAULTTOPRIMARY 0x00000001 +#define MONITOR_DEFAULTTONEAREST 0x00000002 + +using namespace ::com::sun::star; + +////////////////////////////////////////////////////////////////////////////////// +// 'dxcanvas' namespace +////////////////////////////////////////////////////////////////////////////////// + +namespace dxcanvas +{ + namespace + { + bool doBlit( const ::basegfx::B2IPoint& rDestPos, + IDirectDrawSurface& rOutSurface, + const ::basegfx::B2IRange& rSourceArea, + IDirectDrawSurface& rSourceSurface, + DDBLTFX* pBltFx, + bool bForceSoftware ) + { + if( !bForceSoftware ) + { + // blit surface to backbuffer + RECT aOutRect = + { + rDestPos.getX(), + rDestPos.getY(), + rDestPos.getX() + static_cast<sal_Int32>(rSourceArea.getWidth()), + rDestPos.getY() + static_cast<sal_Int32>(rSourceArea.getHeight()), + }; + RECT aSourceRect = + { + rSourceArea.getMinX(), + rSourceArea.getMinY(), + rSourceArea.getMaxX(), + rSourceArea.getMaxY() + }; + + if( SUCCEEDED(rOutSurface.Blt( &aOutRect, + &rSourceSurface, + &aSourceRect, + DDBLT_WAIT, + pBltFx )) ) + { + return true; + } + } + + // failed, or forced to use SW copy. attempt manual copy. + bool bResult = false; + + // lock source surface + DDSURFACEDESC aDescSrc; + rtl_fillMemory(&aDescSrc,sizeof(DDSURFACEDESC),0); + aDescSrc.dwSize = sizeof(DDSURFACEDESC); + const DWORD dwSrcFlags = DDLOCK_NOSYSLOCK| + DDLOCK_SURFACEMEMORYPTR| + DDLOCK_WAIT| + DDLOCK_READONLY; + if(SUCCEEDED(rSourceSurface.Lock(NULL, + &aDescSrc, + dwSrcFlags, + NULL))) + { + // lock destination surface + DDSURFACEDESC aDescDst; + rtl_fillMemory(&aDescDst,sizeof(DDSURFACEDESC),0); + aDescDst.dwSize = sizeof(DDSURFACEDESC); + const DWORD dwDstFlags = DDLOCK_NOSYSLOCK| + DDLOCK_SURFACEMEMORYPTR| + DDLOCK_WAIT| + DDLOCK_WRITEONLY; + if(SUCCEEDED(rOutSurface.Lock(NULL, + &aDescDst, + dwDstFlags, + NULL))) + { + sal_uInt32 nSrcFormat; + nSrcFormat = ::canvas::tools::bitcount32(aDescSrc.ddpfPixelFormat.dwRGBAlphaBitMask)<<12; + nSrcFormat |= ::canvas::tools::bitcount32(aDescSrc.ddpfPixelFormat.dwRBitMask)<<8; + nSrcFormat |= ::canvas::tools::bitcount32(aDescSrc.ddpfPixelFormat.dwGBitMask)<<4; + nSrcFormat |= ::canvas::tools::bitcount32(aDescSrc.ddpfPixelFormat.dwBBitMask); + + sal_uInt32 nDstFormat; + nDstFormat = ::canvas::tools::bitcount32(aDescDst.ddpfPixelFormat.dwRGBAlphaBitMask)<<12; + nDstFormat |= ::canvas::tools::bitcount32(aDescDst.ddpfPixelFormat.dwRBitMask)<<8; + nDstFormat |= ::canvas::tools::bitcount32(aDescDst.ddpfPixelFormat.dwGBitMask)<<4; + nDstFormat |= ::canvas::tools::bitcount32(aDescDst.ddpfPixelFormat.dwBBitMask); + + // TODO(E1): Use numeric_cast to catch overflow here + const sal_uInt32 nWidth( static_cast<sal_uInt32>( + rSourceArea.getWidth() ) ); + const sal_uInt32 nHeight( static_cast<sal_uInt32>( + rSourceArea.getHeight() ) ); + + if((nSrcFormat == 0x8888) && (nDstFormat == 0x0565)) + { + // medium range 8888 to 0565 pixel format conversion. + bResult = true; + sal_uInt8 *pSrcSurface = (sal_uInt8 *)aDescSrc.lpSurface + + rSourceArea.getMinY()*aDescSrc.lPitch + + (rSourceArea.getMinX()<<2); + sal_uInt8 *pDstSurface = (sal_uInt8 *)aDescDst.lpSurface + + rDestPos.getY()*aDescDst.lPitch + + (rDestPos.getX()<<1); + for(sal_uInt32 y=0; y<nHeight; ++y) + { + sal_uInt32 *pSrcScanline = (sal_uInt32 *)pSrcSurface; + sal_uInt16 *pDstScanline = (sal_uInt16 *)pDstSurface; + for(sal_uInt32 x=0; x<nWidth; ++x) + { + sal_uInt32 srcPixel = *pSrcScanline++; + sal_uInt16 dstPixel; + dstPixel = (sal_uInt16)((srcPixel & 0x0000F8) >> 3); + dstPixel |= (srcPixel & 0x00FC00) >> 5; + dstPixel |= (srcPixel & 0xF80000) >> 8; + *pDstScanline++ = dstPixel; + } + pSrcSurface += aDescSrc.lPitch; + pDstSurface += aDescDst.lPitch; + } + } + else if((nSrcFormat == 0x8888) && (nDstFormat == 0x0888)) + { + // medium range 8888 to 0888 pixel format conversion. + bResult = true; + sal_uInt8 *pSrcSurface = (sal_uInt8 *)aDescSrc.lpSurface + + rSourceArea.getMinY()*aDescSrc.lPitch + + (rSourceArea.getMinX()<<2); + sal_uInt8 *pDstSurface = (sal_uInt8 *)aDescDst.lpSurface + + rDestPos.getY()*aDescDst.lPitch + + (rDestPos.getX()<<2); + for(sal_uInt32 y=0; y<nHeight; ++y) + { + sal_uInt32 *pSrcScanline = (sal_uInt32 *)pSrcSurface; + sal_uInt16 *pDstScanline = (sal_uInt16 *)pDstSurface; + for(sal_uInt32 x=0; x<nWidth; ++x) + { + *pDstScanline++ = (sal_uInt16)*pSrcScanline++; + } + pSrcSurface += aDescSrc.lPitch; + pDstSurface += aDescDst.lPitch; + } + } + else if((nSrcFormat == 0x8888) && (nDstFormat == 0x1555)) + { + // medium range 8888 to 1555 pixel format conversion. + bResult = true; + sal_uInt8 *pSrcSurface = (sal_uInt8 *)aDescSrc.lpSurface + + rSourceArea.getMinY()*aDescSrc.lPitch + + (rSourceArea.getMinX()<<2); + sal_uInt8 *pDstSurface = (sal_uInt8 *)aDescDst.lpSurface + + rDestPos.getY()*aDescDst.lPitch + + (rDestPos.getX()<<1); + for(sal_uInt32 y=0; y<nHeight; ++y) + { + sal_uInt32 *pSrcScanline = (sal_uInt32*)pSrcSurface; + sal_uInt16 *pDstScanline = (sal_uInt16 *)pDstSurface; + for(sal_uInt32 x=0; x<nWidth; ++x) + { + sal_uInt32 srcPixel = *pSrcScanline++; + sal_uInt16 dstPixel; + dstPixel = (sal_uInt16)((srcPixel & 0x000000F8) >> 3); + dstPixel |= (srcPixel & 0x0000F800) >> 6; + dstPixel |= (srcPixel & 0x00F80000) >> 9; + dstPixel |= (srcPixel & 0x80000000) >> 16; + *pDstScanline++ = dstPixel; + } + pSrcSurface += aDescSrc.lPitch; + pDstSurface += aDescDst.lPitch; + } + } + + // unlock destination surface + rOutSurface.Unlock(NULL); + } + + // unlock source surface + rSourceSurface.Unlock(NULL); + } + + return bResult; + } + + void dumpSurface( const COMReference<IDirectDrawSurface> &pSurface, const char *szFilename ) + { + if(!(pSurface.get())) + return; + + DDSURFACEDESC aSurfaceDesc; + rtl_fillMemory( &aSurfaceDesc,sizeof(DDSURFACEDESC),0 ); + aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC); + + if( FAILED(pSurface->Lock( NULL, + &aSurfaceDesc, + DDLOCK_NOSYSLOCK|DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT|DDLOCK_READONLY, + NULL)) ) + return; + + const std::size_t dwBitmapSize(aSurfaceDesc.dwWidth*aSurfaceDesc.dwHeight*4); + sal_uInt8 *pBuffer = static_cast<sal_uInt8 *>(_alloca(dwBitmapSize)); + if(pBuffer) + { + sal_uInt8 *pSource = reinterpret_cast<sal_uInt8 *>(aSurfaceDesc.lpSurface); + sal_uInt8 *pDest = reinterpret_cast<sal_uInt8 *>(pBuffer); + const std::size_t dwDestPitch(aSurfaceDesc.dwWidth<<2); + pDest += aSurfaceDesc.dwHeight*dwDestPitch; + for(sal_uInt32 y=0; y<aSurfaceDesc.dwHeight; ++y) + { + pDest -= dwDestPitch; + rtl_copyMemory( pDest, pSource, dwDestPitch ); + pSource += aSurfaceDesc.lPitch; + } + + if(FILE *fp = fopen(szFilename,"wb")) + { + BITMAPINFOHEADER bitmapInfo; + + bitmapInfo.biSize = sizeof(BITMAPINFOHEADER); + bitmapInfo.biWidth = aSurfaceDesc.dwWidth; + bitmapInfo.biHeight = aSurfaceDesc.dwHeight; + bitmapInfo.biPlanes = 1; + bitmapInfo.biBitCount = 32; + bitmapInfo.biCompression = BI_RGB; + bitmapInfo.biSizeImage = 0; + bitmapInfo.biXPelsPerMeter = 0; + bitmapInfo.biYPelsPerMeter = 0; + bitmapInfo.biClrUsed = 0; + bitmapInfo.biClrImportant = 0; + + const std::size_t dwFileSize(sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+dwBitmapSize); + + BITMAPFILEHEADER header; + header.bfType = 'MB'; + header.bfSize = dwFileSize; + header.bfReserved1 = 0; + header.bfReserved2 = 0; + header.bfOffBits = sizeof(BITMAPFILEHEADER) + bitmapInfo.biSize; + + fwrite(&header,1,sizeof(BITMAPFILEHEADER),fp); + fwrite(&bitmapInfo,1,sizeof(BITMAPINFOHEADER),fp); + fwrite(pBuffer,1,dwBitmapSize,fp); + + fclose(fp); + } + } + + pSurface->Unlock(NULL); + } + + void clearSurface( const COMReference<IDirectDrawSurface>& pSurface ) + { + if(!(pSurface.is())) + return; + + DDBLTFX aBltFx; + + rtl_fillMemory( &aBltFx, + sizeof(DDBLTFX), 0 ); + aBltFx.dwSize = sizeof(DDBLTFX); + aBltFx.dwFillColor = 0; + + pSurface->Blt( NULL, + NULL, + NULL, + DDBLT_COLORFILL | DDBLT_WAIT, + &aBltFx ); + } + + // Define struct for MonitorEntry + struct MonitorEntry + { + GUID mnGUID; + HMONITOR mhMonitor; + MONITORINFO maMonitorInfo; + }; + + // define type for MonitorList + typedef ::std::vector< MonitorEntry > MonitorList; + + // Win32 system callback for DirectDrawEnumerateExA call + BOOL WINAPI EnumerateExA_Callback( GUID FAR* lpGUID, + LPSTR /*lpDriverDescription*/, + LPSTR /*lpDriverName*/, + LPVOID lpContext, + HMONITOR hMonitor ) + { + if(lpGUID) + { + MonitorList* pMonitorList = (MonitorList*)lpContext; + MonitorEntry aEntry; + + aEntry.mnGUID = *lpGUID; + aEntry.mhMonitor = hMonitor; + aEntry.maMonitorInfo.cbSize = sizeof(MONITORINFO); + GetMonitorInfo( hMonitor, + &aEntry.maMonitorInfo ); + + pMonitorList->push_back(aEntry); + } + + return DDENUMRET_OK; + } + + void fillMonitorList( MonitorList& rMonitorList ) + { + // Try to fill MonitorList. If neither lib or call to + // DirectDrawEnumerateExA does not exist, it's an old + // DX version (< 5.0), or system does not support + // multiple monitors. + HINSTANCE hInstance = LoadLibrary("ddraw.dll"); + + if(hInstance) + { + LPDIRECTDRAWENUMERATEEX lpDDEnumEx = + (LPDIRECTDRAWENUMERATEEX)GetProcAddress(hInstance,"DirectDrawEnumerateExA"); + + if(lpDDEnumEx) + lpDDEnumEx( (LPDDENUMCALLBACKEXA) EnumerateExA_Callback, + &rMonitorList, + DDENUM_ATTACHEDSECONDARYDEVICES ); + + FreeLibrary(hInstance); + } + } + + IDirectDraw2* createDirectDraw( const MonitorList& rMonitorList, + MONITORINFO& rMonitorInfo, + HWND renderWindow ) + { + GUID* gpSelectedDriverGUID = NULL; + + // if we have multiple monitors, choose a gpSelectedDriverGUID from monitor list + HMONITOR hMonitor = MonitorFromWindow(renderWindow, + MONITOR_DEFAULTTONEAREST); + + MonitorList::const_iterator aCurr = rMonitorList.begin(); + const MonitorList::const_iterator aEnd = rMonitorList.end(); + while( !gpSelectedDriverGUID && aCurr != aEnd ) + { + if(hMonitor == aCurr->mhMonitor) + { + // This is the monitor we are running on + gpSelectedDriverGUID = const_cast<GUID*>(&aCurr->mnGUID); + rMonitorInfo = aCurr->maMonitorInfo; + } + + ++aCurr; + } + + IDirectDraw* pDirectDraw; + if( FAILED( DirectDrawCreate( gpSelectedDriverGUID, &pDirectDraw, NULL ))) + return NULL; + + IDirectDraw2* pDirectDraw2; + if( FAILED( pDirectDraw->QueryInterface( IID_IDirectDraw2, (LPVOID*)&pDirectDraw2 ))) + return NULL; + + // queryInterface bumped up the refcount, so release the + // reference to the original IDirectDraw interface. + pDirectDraw->Release(); + + return pDirectDraw2; + } + + HRESULT WINAPI EnumTextureFormatsCallback( LPDDSURFACEDESC pSurfaceDesc, + LPVOID pContext ) + { + // dirty cast of given context back to result ModeSelectContext + DDPIXELFORMAT* pResult = (DDPIXELFORMAT*)pContext; + + if( pResult == NULL || pSurfaceDesc == NULL ) + return DDENUMRET_CANCEL; + + VERBOSE_TRACE( "EnumTextureFormatsCallback: advertised texture format has dwRGBBitCount %d, dwRBitMask %x, " + "dwGBitMask %x, dwBBitMask %x and dwRGBAlphaBitMask %x. The format uses %s alpha.", + pSurfaceDesc->ddpfPixelFormat.dwRGBBitCount, + pSurfaceDesc->ddpfPixelFormat.dwRBitMask, + pSurfaceDesc->ddpfPixelFormat.dwGBitMask, + pSurfaceDesc->ddpfPixelFormat.dwBBitMask, + pSurfaceDesc->ddpfPixelFormat.dwRGBAlphaBitMask, + pSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_ALPHAPREMULT ? "premultiplied" : "non-premultiplied" ); + + // Only accept RGB surfaces with alpha channel + if( (DDPF_ALPHAPIXELS | DDPF_RGB) == + (pSurfaceDesc->ddpfPixelFormat.dwFlags & (DDPF_ALPHAPIXELS | DDPF_RGB)) ) + { + // ignore formats with the DDPF_ALPHAPREMULT flag + if(!(pSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_ALPHAPREMULT)) + { + // take widest alpha channel available + if( pSurfaceDesc->ddpfPixelFormat.dwAlphaBitDepth > pResult->dwAlphaBitDepth ) + { + // take new format + rtl_copyMemory( pResult, &pSurfaceDesc->ddpfPixelFormat, sizeof(DDPIXELFORMAT) ); + } + else if( pSurfaceDesc->ddpfPixelFormat.dwAlphaBitDepth == pResult->dwAlphaBitDepth ) + { + // tie-breaking: take highest bitcount + if( pSurfaceDesc->ddpfPixelFormat.dwRGBBitCount > pResult->dwRGBBitCount ) + { + // take new format + rtl_copyMemory( pResult, &pSurfaceDesc->ddpfPixelFormat, sizeof(DDPIXELFORMAT) ); + } + } + } + } + + return DDENUMRET_OK; + } + + class DXRenderModule; + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurface + ////////////////////////////////////////////////////////////////////////////////// + + /** ISurface implemenation. + + @attention holds the DXRenderModule via non-refcounted + reference! This is safe with current state of affairs, since + the canvas::PageManager holds surface and render module via + shared_ptr (and makes sure all surfaces are deleted before its + render module member goes out of scope). + */ + class DXSurface : public canvas::ISurface + { + public: + DXSurface( DXRenderModule& rRenderModule, + const ::basegfx::B2ISize& rSize ); + ~DXSurface(); + + virtual bool selectTexture(); + virtual bool isValid(); + virtual bool update( const ::basegfx::B2IPoint& rDestPos, + const ::basegfx::B2IRange& rSourceRect, + ::canvas::IColorBuffer& rSource ); + virtual ::basegfx::B2IVector getSize(); + + private: + /// Guard local methods against concurrent acces to RenderModule + class ImplRenderModuleGuard : private ::boost::noncopyable + { + public: + explicit inline ImplRenderModuleGuard( DXRenderModule& rRenderModule ); + inline ~ImplRenderModuleGuard(); + + private: + DXRenderModule& mrRenderModule; + }; + + DXRenderModule& mrRenderModule; + + COMReference<IDirectDrawSurface> mpSurface; + COMReference<IDirect3DTexture2> mpTexture; + + ::basegfx::B2IVector maSize; + }; + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule + ////////////////////////////////////////////////////////////////////////////////// + + /// Default implementation of IDXRenderModule + class DXRenderModule : public IDXRenderModule + { + public: + explicit DXRenderModule( const ::Window& rWindow ); + + virtual void lock() const { maMutex.acquire(); } + virtual void unlock() const { maMutex.release(); } + + virtual COMReference<IDirectDrawSurface> + createSystemMemorySurface( const ::basegfx::B2IVector& rSize ); + + virtual bool flip( const ::basegfx::B2IRectangle& rUpdateArea, + const ::basegfx::B2IRectangle& rCurrWindowArea ); + + virtual void resize( const ::basegfx::B2IRange& rect ); + virtual HWND getHWND() const { return mhWnd; } + virtual void disposing(); + virtual void screenShot(); + virtual ::basegfx::B2IVector getPageSize(); + virtual ::canvas::ISurfaceSharedPtr createSurface( const ::basegfx::B2IVector& surfaceSize ); + virtual void beginPrimitive( PrimitiveType eType ); + virtual void endPrimitive(); + virtual void pushVertex( const ::canvas::Vertex& vertex ); + virtual bool isError(); + + const D3DDEVICEDESC& getDeviceDesc() const { return maDeviceDesc; } + const DDPIXELFORMAT& getTextureFormat() const { return maTextureFormat; } + COMReference<IDirectDraw2> getDirectDraw() { return mpDirectDraw; } + COMReference< IDirect3DDevice2 > getDevice() { return mpDirect3DDevice; } + + void flushVertexCache(); + + struct ModeSelectContext + { + DDSURFACEDESC selectedDesc; + ::basegfx::B2ISize requestedSize; + }; + + /** Query actual size of the device + + This is especially interesting for fullscreen devices + */ + ::basegfx::B2ISize getFramebufferSize() const; + + /** Query the amount of memory available for new surfaces + + This might differ from getAvailableTextureMem() + @see getAvailableTextureMem() + + @param bWithAGPMema + When true, returned value includes non-local, + i.e. AGP-able memory, too. + + @return the amount of free surface mem + */ + std::size_t getAvailableSurfaceMem( bool bWithAGPMem=true ) const; + + /** Query the amount of memory available for new textures + + This might differ from getAvailableSurfaceMem() + @see getAvailableSurfaceMem() + + @param bWithAGPMema + When true, returned value includes non-local, + i.e. AGP-able memory, too. + + @return the amount of free texture mem + */ + std::size_t getAvailableTextureMem( bool bWithAGPMem=true ) const; + + private: + bool queryCaps(); + bool validateCaps(); + bool setup3DDevice(); + unsigned int getDisplayFormat() const; + + void convert2Screen( ::basegfx::B2IPoint& io_rDestPos, + ::basegfx::B2IRange& io_rDestArea ); + + void renderInfoText( const ::rtl::OUString& rStr, + const Gdiplus::PointF& rPos ) const; + void renderFPSCounter() const; + void renderMemAvailable() const; + + bool create( const ::Window& rWindow ); + bool validateMainSurfaces(); + + /** This object represents the DirectX state machine. In order + to serialize access to DirectX's global state, a global + mutex is required. + */ + static ::osl::Mutex maMutex; + + HWND mhWnd; + ::boost::scoped_ptr<SystemChildWindow> mpWindow; + ::basegfx::B2IVector maSize; + + ModeSelectContext maSelectedFullscreenMode; + DDPIXELFORMAT maTextureFormat; + + MONITORINFO maMonitorInfo; // monitor info for mpDirectDraw's monitor + COMReference<IDirectDraw2> mpDirectDraw; + COMReference<IDirectDrawSurface> mpPrimarySurface; + COMReference<IDirectDrawSurface> mpBackBufferSurface; + + COMReference< IDirect3D2 > mpDirect3D; + COMReference< IDirect3DDevice2 > mpDirect3DDevice; + + mutable ::canvas::tools::ElapsedTime maLastUpdate; // for the frame counter + + D3DDEVICEDESC maDeviceDesc; + + typedef std::vector<canvas::Vertex> vertexCache_t; + vertexCache_t maVertexCache; + std::size_t mnCount; + + int mnBeginSceneCount; + + const bool mbPageFlipping; + bool mbHasNoTearingBlt; + bool mbError; + PrimitiveType meType; + + ::canvas::ISurfaceSharedPtr mpTexture; + ::basegfx::B2IVector maPageSize; + }; + + ::osl::Mutex DXRenderModule::maMutex; + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurface::ImplRenderModuleGuard + ////////////////////////////////////////////////////////////////////////////////// + + inline DXSurface::ImplRenderModuleGuard::ImplRenderModuleGuard( + DXRenderModule& rRenderModule ) : + mrRenderModule( rRenderModule ) + { + mrRenderModule.lock(); + } + + inline DXSurface::ImplRenderModuleGuard::~ImplRenderModuleGuard() + { + mrRenderModule.unlock(); + } + +#ifdef FAKE_MAX_NUMBER_TEXTURES + static sal_uInt32 gNumSurfaces = 0; +#endif + + void fillRect( sal_uInt32 *pDest, + sal_uInt32 dwWidth, + sal_uInt32 dwHeight, + sal_uInt32 dwPitch, + sal_uInt32 dwColor ) + { + for(sal_uInt32 i=0; i<dwWidth; ++i) + { + pDest[i]=dwColor; + pDest[((dwHeight-1)*dwPitch)+i]=dwColor; + } + + for(sal_uInt32 j=0; j<dwHeight; ++j) + { + pDest[0]=dwColor; + pDest[dwWidth-1]=dwColor; + pDest += dwPitch; + } + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurface::DXSurface + ////////////////////////////////////////////////////////////////////////////////// + + DXSurface::DXSurface( DXRenderModule& rRenderModule, + const ::basegfx::B2ISize& rSize ) : + mrRenderModule(rRenderModule), + mpTexture(NULL), + mpSurface(NULL), + maSize() + { + ImplRenderModuleGuard aGuard( mrRenderModule ); + +#ifdef FAKE_MAX_NUMBER_TEXTURES + ++gNumSurfaces; + if(gNumSurfaces >= FAKE_MAX_NUMBER_TEXTURES) + return; +#endif + +#ifdef FAKE_MAX_TEXTURE_SIZE + if(rSize.getX() > FAKE_MAX_TEXTURE_SIZE) + return; + if(rSize.getY() > FAKE_MAX_TEXTURE_SIZE) + return; +#endif + + ENSURE_ARG_OR_THROW(rSize.getX() > 0 && rSize.getY() > 0, + "DXSurface::DXSurface(): request for zero-sized surface"); + + const D3DDEVICEDESC &deviceDesc = rRenderModule.getDeviceDesc(); + + DDSURFACEDESC aSurfaceDesc; + rtl_fillMemory( &aSurfaceDesc,sizeof(DDSURFACEDESC),0 ); + aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC); + aSurfaceDesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; + aSurfaceDesc.dwWidth = ::std::min(deviceDesc.dwMaxTextureWidth,::canvas::tools::nextPow2(rSize.getX())); + aSurfaceDesc.dwHeight = ::std::min(deviceDesc.dwMaxTextureHeight,::canvas::tools::nextPow2(rSize.getY())); + aSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE | + DDSCAPS_VIDEOMEMORY | + DDSCAPS_LOCALVIDMEM; + rtl_copyMemory(&aSurfaceDesc.ddpfPixelFormat,&rRenderModule.getTextureFormat(),sizeof(DDPIXELFORMAT)); + + IDirectDrawSurface *pSurface; + COMReference<IDirectDraw2> pDirectDraw(rRenderModule.getDirectDraw()); + HRESULT hr = pDirectDraw->CreateSurface(&aSurfaceDesc, &pSurface, NULL); + if(FAILED(hr)) + { + // if the call failed due to 'out of videomemory', + // retry with request for AGP memory. + if(DDERR_OUTOFVIDEOMEMORY == hr) + { + aSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE | + DDSCAPS_VIDEOMEMORY | + DDSCAPS_NONLOCALVIDMEM; + hr = pDirectDraw->CreateSurface(&aSurfaceDesc, &pSurface, NULL); + } + } + + if(SUCCEEDED(hr)) + { + IDirect3DTexture2* pTexture; + if( FAILED(pSurface->QueryInterface(IID_IDirect3DTexture2, (LPVOID *)&pTexture)) ) + { + pSurface->Release(); + return; + } + + maSize.setX(aSurfaceDesc.dwWidth); + maSize.setY(aSurfaceDesc.dwHeight); + + mpSurface=COMReference<IDirectDrawSurface>(pSurface); + mpTexture=COMReference<IDirect3DTexture2>(pTexture); + + // #122683# Clear texture, to avoid ugly artifacts at the + // border to invisible sprite areas (note that the textures + // are usually only partly utilized). + clearSurface( mpSurface ); + } + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurface::~DXSurface + ////////////////////////////////////////////////////////////////////////////////// + + DXSurface::~DXSurface() + { + ImplRenderModuleGuard aGuard( mrRenderModule ); + +#ifdef FAKE_MAX_NUMBER_TEXTURES + gNumSurfaces--; +#endif + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurface::selectTexture + ////////////////////////////////////////////////////////////////////////////////// + + bool DXSurface::selectTexture() + { + ImplRenderModuleGuard aGuard( mrRenderModule ); + + mrRenderModule.flushVertexCache(); + + D3DTEXTUREHANDLE aTextureHandle; + if(FAILED(mpTexture->GetHandle( + mrRenderModule.getDevice().get(), + &aTextureHandle))) + { + return false; + } + + // select texture for next primitive + if(FAILED(mrRenderModule.getDevice()->SetRenderState( + D3DRENDERSTATE_TEXTUREHANDLE,aTextureHandle))) + { + return false; + } + +#if defined(DX_DEBUG_IMAGES) +# if OSL_DEBUG_LEVEL > 0 + if( mpSurface.is() ) + { + DDSURFACEDESC aSurfaceDesc; + rtl_fillMemory( &aSurfaceDesc,sizeof(DDSURFACEDESC),0 ); + aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC); + + if( SUCCEEDED(mpSurface->Lock( NULL, + &aSurfaceDesc, + DDLOCK_NOSYSLOCK|DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT|DDLOCK_READONLY, + NULL)) ) + { + imdebug( "rgba w=%d h=%d %p", + aSurfaceDesc.dwWidth, + aSurfaceDesc.dwHeight, + aSurfaceDesc.lpSurface ); + + mpSurface->Unlock(NULL); + } + } +# endif +#endif + + return true; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurface::isValid + ////////////////////////////////////////////////////////////////////////////////// + + bool DXSurface::isValid() + { + ImplRenderModuleGuard aGuard( mrRenderModule ); + + if(!(mpSurface.is())) + return false; + + if(mpSurface->IsLost() == DDERR_SURFACELOST) + { + mpSurface->Restore(); + return false; + } + + return true; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurface::update + ////////////////////////////////////////////////////////////////////////////////// + + bool DXSurface::update( const ::basegfx::B2IPoint& rDestPos, + const ::basegfx::B2IRange& rSourceRect, + ::canvas::IColorBuffer& rSource ) + { + ImplRenderModuleGuard aGuard( mrRenderModule ); + + // can't update if surface is not valid, that means + // either not existent nor restored... + if(!(isValid())) + return false; + + DDSURFACEDESC aSurfaceDesc; + rtl_fillMemory( &aSurfaceDesc,sizeof(DDSURFACEDESC),0 ); + aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC); + + // TODO(P2): only lock the region we want to update + if( FAILED(mpSurface->Lock( NULL, + &aSurfaceDesc, + DDLOCK_NOSYSLOCK|DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT|DDLOCK_WRITEONLY, + NULL)) ) + return false; + + if(sal_uInt8* pImage = rSource.lock()) + { + switch( rSource.getFormat() ) + { + case ::canvas::IColorBuffer::FMT_A8R8G8B8: + { + const std::size_t nSourceBytesPerPixel(4); + const std::size_t nSourcePitchInBytes(rSource.getStride()); + pImage += rSourceRect.getMinY()*nSourcePitchInBytes; + pImage += rSourceRect.getMinX()*nSourceBytesPerPixel; + + // calculate the destination memory address + sal_uInt8 *pDst = ((sal_uInt8*)aSurfaceDesc.lpSurface+ + (rDestPos.getY()*aSurfaceDesc.lPitch) + + (4*rDestPos.getX())); + + const sal_uInt32 nNumBytesToCopy( + static_cast<sal_uInt32>( + rSourceRect.getWidth())* + nSourceBytesPerPixel); + const sal_uInt64 nNumLines(rSourceRect.getHeight()); + + for(sal_uInt32 i=0; i<nNumLines; ++i) + { + rtl_copyMemory(pDst,pImage,nNumBytesToCopy); + + pDst += aSurfaceDesc.lPitch; + pImage += nSourcePitchInBytes; + } + } + break; + + case ::canvas::IColorBuffer::FMT_R8G8B8: + { + const std::size_t nSourceBytesPerPixel(3); + const std::size_t nSourcePitchInBytes(rSource.getStride()); + pImage += rSourceRect.getMinY()*nSourcePitchInBytes; + pImage += rSourceRect.getMinX()*nSourceBytesPerPixel; + + // calculate the destination memory address + sal_uInt8 *pDst = ((sal_uInt8*)aSurfaceDesc.lpSurface+ + (rDestPos.getY()*aSurfaceDesc.lPitch) + + (4*rDestPos.getX())); + + const sal_uInt64 nNumColumns(rSourceRect.getWidth()); + const sal_uInt64 nNumLines(rSourceRect.getHeight()); + for(sal_uInt32 i=0; i<nNumLines; ++i) + { + sal_uInt32 *pDstScanline = reinterpret_cast<sal_uInt32 *>(pDst); + sal_uInt8 *pSrcScanline = reinterpret_cast<sal_uInt8 *>(pImage); + for(sal_uInt32 x=0; x<nNumColumns; ++x) + { + sal_uInt32 color(0xFF000000); + color |= pSrcScanline[2]<<16; + color |= pSrcScanline[1]<<8; + color |= pSrcScanline[0]; + pSrcScanline += 3; + *pDstScanline++ = color; + } + + pDst += aSurfaceDesc.lPitch; + pImage += nSourcePitchInBytes; + } + } + break; + + case ::canvas::IColorBuffer::FMT_X8R8G8B8: + { + const std::size_t nSourceBytesPerPixel(4); + const std::size_t nSourcePitchInBytes(rSource.getStride()); + pImage += rSourceRect.getMinY()*nSourcePitchInBytes; + pImage += rSourceRect.getMinX()*nSourceBytesPerPixel; + + // calculate the destination memory address + sal_uInt8 *pDst = ((sal_uInt8*)aSurfaceDesc.lpSurface+ + (rDestPos.getY()*aSurfaceDesc.lPitch) + + (4*rDestPos.getX())); + + const sal_uInt64 nNumLines(rSourceRect.getHeight()); + + for(sal_uInt32 i=0; i<nNumLines; ++i) + { + sal_uInt32 *pSrc32 = reinterpret_cast<sal_uInt32 *>(pImage); + sal_uInt32 *pDst32 = reinterpret_cast<sal_uInt32 *>(pDst); + for(sal_uInt32 j=0; j<rSourceRect.getWidth(); ++j) + pDst32[j] = 0xFF000000 | pSrc32[j]; + + pDst += aSurfaceDesc.lPitch; + pImage += nSourcePitchInBytes; + } + } + break; + + default: + ENSURE_OR_RETURN(false, + "DXSurface::update(): Unknown/unimplemented buffer format" ); + break; + } + + rSource.unlock(); + } + + return SUCCEEDED(mpSurface->Unlock(NULL)); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurface::getSize + ////////////////////////////////////////////////////////////////////////////////// + + ::basegfx::B2IVector DXSurface::getSize() + { + return maSize; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::DXRenderModule + ////////////////////////////////////////////////////////////////////////////////// + + DXRenderModule::DXRenderModule( const ::Window& rWindow ) : + mhWnd(0), + mpWindow(), + maSize(), + maSelectedFullscreenMode(), + maTextureFormat(), + maMonitorInfo(), + mpDirectDraw(), + mpPrimarySurface(), + mpBackBufferSurface(), + mpDirect3D(), + mpDirect3DDevice(), + maLastUpdate(), + maDeviceDesc(), + maVertexCache(), + mnCount(0), + mnBeginSceneCount(0), + mbPageFlipping( false ), + mbHasNoTearingBlt( false ), + mbError( false ), + meType( PRIMITIVE_TYPE_UNKNOWN ), + mpTexture(), + maPageSize() + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + if(!(create(rWindow))) + { + throw lang::NoSupportException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "Could not create DirectX device!") ),NULL); + } + + // allocate a single texture surface which can be used later. + // we also use this to calibrate the page size. + ::basegfx::B2IVector aPageSize( + ::std::min( + static_cast<sal_uInt32>(maDeviceDesc.dwMaxTextureWidth), + static_cast<sal_uInt32>(MAX_TEXTURE_SIZE)), + ::std::min( + static_cast<sal_uInt32>(maDeviceDesc.dwMaxTextureHeight), + static_cast<sal_uInt32>(MAX_TEXTURE_SIZE))); + while(true) + { + mpTexture = ::canvas::ISurfaceSharedPtr( + new DXSurface(*this,aPageSize)); + if(mpTexture->isValid()) + break; + + aPageSize.setX(aPageSize.getX()>>1); + aPageSize.setY(aPageSize.getY()>>1); + if((aPageSize.getX() < MIN_TEXTURE_SIZE) || + (aPageSize.getY() < MIN_TEXTURE_SIZE)) + { + throw lang::NoSupportException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "Could not create DirectX device!") ),NULL); + } + } + maPageSize=aPageSize; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::create + ////////////////////////////////////////////////////////////////////////////////// + + bool DXRenderModule::create( const ::Window& rWindow ) + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + maVertexCache.reserve(1024); + + mpWindow.reset( + new SystemChildWindow( + const_cast<Window *>(&rWindow), 0) ); + + // system child window must not receive mouse events + mpWindow->SetMouseTransparent( TRUE ); + + // parent should receive paint messages as well + // [PARENTCLIPMODE_NOCLIP], the argument is here + // passed as plain numeric value since the stupid + // define utilizes a USHORT cast. + mpWindow->SetParentClipMode(0x0002); + + // the system child window must not clear its background + mpWindow->EnableEraseBackground( FALSE ); + + mpWindow->SetControlForeground(); + mpWindow->SetControlBackground(); + mpWindow->EnablePaint(FALSE); + + const SystemEnvData *pData = mpWindow->GetSystemData(); + const HWND hwnd(reinterpret_cast<HWND>(pData->hWnd)); + mhWnd = const_cast<HWND>(hwnd); + + ENSURE_OR_THROW( IsWindow( reinterpret_cast<HWND>(mhWnd) ), + "DXRenderModuleDXRenderModuleWin32() No valid HWND given." ); + + // retrieve position and size of the parent window + const ::Size &rSizePixel(rWindow.GetSizePixel()); + + // remember the size of the parent window, since we + // need to use this for our child window. + maSize.setX(static_cast<sal_Int32>(rSizePixel.Width())); + maSize.setY(static_cast<sal_Int32>(rSizePixel.Height())); + + // let the child window cover the same size as the parent window. + mpWindow->SetPosSizePixel(0,0,maSize.getX(),maSize.getY()); + + MonitorList aMonitorList; + fillMonitorList( aMonitorList ); + + mpDirectDraw = COMReference<IDirectDraw2>( + createDirectDraw(aMonitorList, maMonitorInfo, mhWnd)); + + if(!mpDirectDraw.is()) + return false; + + if( !queryCaps() ) + { + // go defunct, and exit + VERBOSE_TRACE( "Device::Device(): GetCaps failed" ); + mpDirectDraw.reset(); + return false; + } + + if( !validateCaps() ) + { + // go defunct, and exit + VERBOSE_TRACE( "Device::Device(): Insufficient DirectX capabilities, failed" ); + mpDirectDraw.reset(); + return false; + } + + if( FAILED( mpDirectDraw->SetCooperativeLevel( mhWnd, + DDSCL_NORMAL|DDSCL_MULTITHREADED|DDSCL_FPUPRESERVE ) ) ) + { + // go defunct, and exit + VERBOSE_TRACE( "Device::Device(): SetCooperativeLevel failed" ); + mpDirectDraw.reset(); + return false; + } + + // setup query struct + rtl_fillMemory( &maSelectedFullscreenMode.selectedDesc, + sizeof(DDSURFACEDESC), 0 ); + maSelectedFullscreenMode.selectedDesc.dwSize = sizeof(DDSURFACEDESC); + + // read current display mode, e.g. for screen dimension + if( FAILED( mpDirectDraw->GetDisplayMode( &maSelectedFullscreenMode.selectedDesc )) ) + { + // go defunct, and exit + VERBOSE_TRACE( "Device::Device(): GetDisplayMode failed" ); + mpDirectDraw.reset(); + return false; + } + + // check for supported primary surface formats... + unsigned int nDisplayFormat = getDisplayFormat() & 0x00000FFF; + if(nDisplayFormat != 0x888 && nDisplayFormat != 0x565) + { + // go defunct, and exit + VERBOSE_TRACE( "Device::Device(): Unsupported DisplayFormat" ); + mpDirectDraw.reset(); + return false; + } + + // create primary surface reference + DDSURFACEDESC aSurfaceDesc; + IDirectDrawSurface* pPrimarySurface; + + rtl_fillMemory( &aSurfaceDesc, + sizeof(DDSURFACEDESC), 0 ); + aSurfaceDesc.dwSize = sizeof(aSurfaceDesc); + aSurfaceDesc.dwFlags = DDSD_CAPS; + aSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE; + + if( FAILED(mpDirectDraw->CreateSurface(&aSurfaceDesc, &pPrimarySurface, NULL)) ) + { + // go defunct, and exit + VERBOSE_TRACE( "Device::Device(): CreateSurface failed" ); + mpDirectDraw.reset(); + return false; + } + + mpPrimarySurface = COMReference< IDirectDrawSurface >(pPrimarySurface); + + // create a Clipper and associate it with the primary surface + // and the render window + LPDIRECTDRAWCLIPPER pClipper; + if( FAILED(mpDirectDraw->CreateClipper( 0, &pClipper, NULL )) ) + { + // go defunct, and exit + VERBOSE_TRACE( "Device::Device(): CreateClipper failed" ); + mpPrimarySurface.reset(); + mpDirectDraw.reset(); + return false; + } + if( FAILED(pClipper->SetHWnd(0, mhWnd)) ) + { + // go defunct, and exit + VERBOSE_TRACE( "Device::Device(): Clipper->SetHWnd failed" ); + pClipper->Release(); + mpPrimarySurface.reset(); + mpDirectDraw.reset(); + return false; + } + if( FAILED(mpPrimarySurface->SetClipper( pClipper )) ) + { + // go defunct, and exit + VERBOSE_TRACE( "Device::Device(): SetClipper failed" ); + pClipper->Release(); + mpPrimarySurface.reset(); + mpDirectDraw.reset(); + return false; + } + + // clipper is now owned by mpPrimarySurface, release our reference + pClipper->Release(); + + // TODO(F3): Check whether palette needs any setup here + + // get us a backbuffer for simulated flipping + IDirectDrawSurface* pSurface; + + // Strictly speaking, we don't need a full screen worth of + // backbuffer here. We could also scale dynamically with + // the current window size, but this will make it + // necessary to temporarily have two buffers while copying + // from the old to the new one. What's more, at the time + // we need a larger buffer, DX might not have sufficient + // resources available, and we're then left with too small + // a back buffer, and no way of falling back to a + // different canvas implementation. + const ::basegfx::B2ISize aSize( getFramebufferSize() ); + + rtl_fillMemory( &aSurfaceDesc, + sizeof(DDSURFACEDESC), 0 ); + aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC); + aSurfaceDesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; + aSurfaceDesc.dwHeight= aSize.getY(); + aSurfaceDesc.dwWidth = aSize.getX(); + + aSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM; + + HRESULT nRes = mpDirectDraw->CreateSurface(&aSurfaceDesc, &pSurface, NULL); + + if( FAILED( nRes ) ) + { + if( nRes == DDERR_OUTOFVIDEOMEMORY ) + { + // local vid mem failed. Maybe AGP mem works? + aSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY | DDSCAPS_NONLOCALVIDMEM; + if( FAILED(mpDirectDraw->CreateSurface(&aSurfaceDesc, &pSurface, NULL)) ) + { + // no chance, go defunct, and exit + VERBOSE_TRACE( "Device::Device(): CreateSurface for backbuffer failed" ); + mpPrimarySurface.reset(); + mpDirectDraw.reset(); + return false; + } + + VERBOSE_TRACE( "Device::Device(): CreateSurface for backbuffer reverted to non-local video mem" ); + } + else + { + // no chance, go defunct, and exit + VERBOSE_TRACE( "Device::Device(): CreateSurface for backbuffer failed" ); + mpPrimarySurface.reset(); + mpDirectDraw.reset(); + return false; + } + } + + VERBOSE_TRACE( "Device::Device(): created backbuffer of size %d times %d pixel", + aSurfaceDesc.dwWidth, + aSurfaceDesc.dwHeight ); + + mpBackBufferSurface = COMReference< IDirectDrawSurface >(pSurface); + clearSurface(mpBackBufferSurface); + + if( !setup3DDevice() ) + { + // go defunct, and exit + VERBOSE_TRACE( "Device::Device(): setup3DDevice failed" ); + mpBackBufferSurface.reset(); + mpPrimarySurface.reset(); + mpDirectDraw.reset(); + return false; + } + + mpWindow->Show(); + + return true; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::getSize + ////////////////////////////////////////////////////////////////////////////////// + + ::basegfx::B2ISize DXRenderModule::getFramebufferSize() const + { + return mpDirectDraw.is() ? + ::basegfx::B2ISize( maSelectedFullscreenMode.selectedDesc.dwWidth, + maSelectedFullscreenMode.selectedDesc.dwHeight ) : + ::basegfx::B2ISize(); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::setup3DDevice + ////////////////////////////////////////////////////////////////////////////////// + + bool DXRenderModule::setup3DDevice() + { + // create and setup 3D device + // ========================== + LPDIRECT3D2 pDirect3D; + if( FAILED( mpDirectDraw->QueryInterface( IID_IDirect3D2, (LPVOID*)&pDirect3D ) ) ) + { + // go defunct, and exit + VERBOSE_TRACE( "Device::setup3DDevice(): QueryInterface() for Direct3D failed" ); + return false; + } + + mpDirect3D = COMReference< IDirect3D2 >(pDirect3D); + + LPDIRECT3DDEVICE2 pDirect3DDevice; + // try HW-accelerated device first + if( FAILED(mpDirect3D->CreateDevice( IID_IDirect3DHALDevice, + mpBackBufferSurface.get(), + &pDirect3DDevice )) ) + { + // no HW 3D support - go defunct, and exit + VERBOSE_TRACE( "Device::setup3DDevice(): CreateDevice() for HW Direct3D rendering failed" ); + mpDirect3D.reset(); + return false; + } + + D3DDEVICEDESC aHELDeviceDesc; + rtl_fillMemory(&maDeviceDesc,sizeof(maDeviceDesc),0); + rtl_fillMemory(&aHELDeviceDesc,sizeof(aHELDeviceDesc),0); + maDeviceDesc.dwSize = sizeof(maDeviceDesc); + aHELDeviceDesc.dwSize = sizeof(aHELDeviceDesc); + if(FAILED(pDirect3DDevice->GetCaps(&maDeviceDesc,&aHELDeviceDesc))) + { + // go defunct, and exit + VERBOSE_TRACE( "Device::setup3DDevice(): GetCaps() for Direct3DDevice failed" ); + mpDirect3D.reset(); + return false; + } + + mpDirect3DDevice = COMReference< IDirect3DDevice2 >(pDirect3DDevice); + + // select appropriate texture format (_need_ alpha channel here) + rtl_fillMemory( &maTextureFormat, + sizeof(DDPIXELFORMAT), 0 ); + maTextureFormat.dwSize = sizeof(DDPIXELFORMAT); + if( SUCCEEDED(mpDirect3DDevice->EnumTextureFormats( EnumTextureFormatsCallback, &maTextureFormat )) ) + { + bool bSupportedFormat = true; + if((maTextureFormat.dwFlags & (DDPF_ALPHAPIXELS | DDPF_RGB)) != (DDPF_ALPHAPIXELS | DDPF_RGB)) + bSupportedFormat = false; + else if(maTextureFormat.dwRGBAlphaBitMask != 0xFF000000) + bSupportedFormat = false; + else if(maTextureFormat.dwRBitMask != 0x00FF0000) + bSupportedFormat = false; + else if(maTextureFormat.dwGBitMask != 0x0000FF00) + bSupportedFormat = false; + else if(maTextureFormat.dwBBitMask != 0x000000FF) + bSupportedFormat = false; + + if(bSupportedFormat) + { + VERBOSE_TRACE( "Device::setup3DDevice(): chose texture format dwRGBBitCount %d, dwRBitMask %x, " + "dwGBitMask %x, dwBBitMask %x and dwRGBAlphaBitMask %x. The texture uses %s alpha.", + maTextureFormat.dwRGBBitCount, + maTextureFormat.dwRBitMask, + maTextureFormat.dwGBitMask, + maTextureFormat.dwBBitMask, + maTextureFormat.dwRGBAlphaBitMask, + maTextureFormat.dwFlags & DDPF_ALPHAPREMULT ? "premultiplied" : "non-premultiplied" ); + + // setup the device (with as much as we can possibly do here) + // ========================================================== + + LPDIRECT3DVIEWPORT2 pViewport; + + if( SUCCEEDED(mpDirect3D->CreateViewport( &pViewport, NULL )) ) + { + if( SUCCEEDED(mpDirect3DDevice->AddViewport( pViewport )) ) + { + // setup viewport (to whole backbuffer) + D3DVIEWPORT2 aViewport; + + aViewport.dwSize = sizeof(D3DVIEWPORT2); + aViewport.dwX = 0; + aViewport.dwY = 0; + aViewport.dwWidth = maSelectedFullscreenMode.selectedDesc.dwWidth; + aViewport.dwHeight = maSelectedFullscreenMode.selectedDesc.dwHeight; + aViewport.dvClipX = -1.0; + aViewport.dvClipY = -1.0; + aViewport.dvClipWidth = 2.0; + aViewport.dvClipHeight = 2.0; + aViewport.dvMinZ = 0.0; + aViewport.dvMaxZ = 1.0; + + if( SUCCEEDED(pViewport->SetViewport2( &aViewport )) ) + { + if( SUCCEEDED(mpDirect3DDevice->SetCurrentViewport( pViewport )) ) + { + // Viewport was handed over to 3DDevice, thus we can release now + pViewport->Release(); + + // currently, no need for any + // matrix or light source + // setup, since we only render + // transformed&lighted + // vertices + + // done; successfully + return true; + } + else + { + VERBOSE_TRACE( "Device::setup3DDevice(): SetCurrentViewport failed" ); + } + } + else + { + VERBOSE_TRACE( "Device::setup3DDevice(): SetViewport2 failed" ); + } + } + else + { + VERBOSE_TRACE( "Device::setup3DDevice(): AddViewport failed" ); + } + + pViewport->Release(); + } + else + { + VERBOSE_TRACE( "Device::setup3DDevice(): CreateViewport failed" ); + } + } + else + { + VERBOSE_TRACE( "Device::setup3DDevice(): No supported pixelformat" ); + } + } + else + { + VERBOSE_TRACE( "Device::setup3DDevice(): EnumTextureFormats failed" ); + } + + // go defunct, and exit + mpDirect3DDevice.reset(); + mpDirect3D.reset(); + + return false; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::queryCaps + ////////////////////////////////////////////////////////////////////////////////// + + bool DXRenderModule::queryCaps() + { + DDCAPS aHWCaps; + DDCAPS aHELCaps; + + rtl_fillMemory( &aHWCaps, + sizeof(aHWCaps), 0 ); + rtl_fillMemory( &aHELCaps, + sizeof(aHELCaps), 0 ); + aHWCaps.dwSize = sizeof( aHWCaps ); + aHELCaps.dwSize = sizeof( aHELCaps ); + + if( FAILED( mpDirectDraw->GetCaps( &aHWCaps, + &aHELCaps ) ) ) + { + return false; + } + + mbHasNoTearingBlt = aHWCaps.dwFXCaps & DDBLTFX_NOTEARING; + + VERBOSE_TRACE( "dxcanvas initialization: %d bytes VRAM free for surfaces (%d with AGP mem), " + "%d bytes VRAM free for textures (%d with AGP mem)", + getAvailableSurfaceMem( false ), + getAvailableSurfaceMem( true ), + getAvailableTextureMem( false ), + getAvailableTextureMem( true ) ); + + return true; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::validateCaps + ////////////////////////////////////////////////////////////////////////////////// + + bool DXRenderModule::validateCaps() + { + // TODO(E3): Validate HW capabilities. Depending on primary + // surface size, reject HW e.g. on the grounds of insufficient + // VRAM. + + // setup query struct + DDSURFACEDESC desc; + rtl_fillMemory(&desc,sizeof(DDSURFACEDESC),0); + desc.dwSize = sizeof(DDSURFACEDESC); + + // read current display mode, e.g. for screen dimension + if(FAILED( mpDirectDraw->GetDisplayMode(&desc))) + return false; + + // simple heuristic: we need at least 3 times the desktop + // resolution based on ARGB color values... + std::size_t nMinimumVRAMSize = ((desc.dwWidth*desc.dwHeight)<<2)*3; + if(getAvailableSurfaceMem() < nMinimumVRAMSize) + return false; + + return true; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::getDisplayFormat + ////////////////////////////////////////////////////////////////////////////////// + + unsigned int DXRenderModule::getDisplayFormat() const + { + unsigned int nFormat; + nFormat = ::canvas::tools::bitcount32(maSelectedFullscreenMode.selectedDesc.ddpfPixelFormat.dwRGBAlphaBitMask)<<12; + nFormat |= ::canvas::tools::bitcount32(maSelectedFullscreenMode.selectedDesc.ddpfPixelFormat.dwRBitMask)<<8; + nFormat |= ::canvas::tools::bitcount32(maSelectedFullscreenMode.selectedDesc.ddpfPixelFormat.dwGBitMask)<<4; + nFormat |= ::canvas::tools::bitcount32(maSelectedFullscreenMode.selectedDesc.ddpfPixelFormat.dwBBitMask); + return nFormat; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::getAvailableSurfaceMem + ////////////////////////////////////////////////////////////////////////////////// + + std::size_t DXRenderModule::getAvailableSurfaceMem( bool bWithAGPMem ) const + { + if( !mpDirectDraw.is() ) + return 0; + + std::size_t nRes( 0 ); + + DDSCAPS aSurfaceCaps; + DWORD nTotal, nFree; + + // real VRAM (const_cast, since GetAvailableVidMem is non-const) + aSurfaceCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM; + if( FAILED(const_cast<IDirectDraw2&>(*mpDirectDraw).GetAvailableVidMem( &aSurfaceCaps, &nTotal, &nFree )) ) + return 0; + + nRes += nFree; + + if( bWithAGPMem ) + { + // AGP RAM (const_cast, since GetAvailableVidMem is non-const) + aSurfaceCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY | DDSCAPS_NONLOCALVIDMEM; + if( FAILED(const_cast<IDirectDraw2&>(*mpDirectDraw).GetAvailableVidMem( &aSurfaceCaps, &nTotal, &nFree )) ) + return 0; + + nRes += nFree; + } + + return nRes; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::getAvailableTextureMem + ////////////////////////////////////////////////////////////////////////////////// + + std::size_t DXRenderModule::getAvailableTextureMem( bool bWithAGPMem ) const + { + if( !mpDirectDraw.is() ) + return 0; + + std::size_t nRes( 0 ); + + DDSCAPS aSurfaceCaps; + DWORD nTotal, nFree; + + // TODO(F1): Check if flags are applicable + + // real VRAM (const_cast, since GetAvailableVidMem is non-const) + aSurfaceCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM; + if( FAILED(const_cast<IDirectDraw2&>(*mpDirectDraw).GetAvailableVidMem( &aSurfaceCaps, &nTotal, &nFree )) ) + return 0; + + nRes += nFree; + + if( bWithAGPMem ) + { + // AGP RAM (const_cast, since GetAvailableVidMem is non-const) + aSurfaceCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY | DDSCAPS_NONLOCALVIDMEM; + if( FAILED(const_cast<IDirectDraw2&>(*mpDirectDraw).GetAvailableVidMem( &aSurfaceCaps, &nTotal, &nFree )) ) + return 0; + + nRes += nFree; + } + + // TODO(F1): Add pool mem + + return nRes; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::convert2Screen + ////////////////////////////////////////////////////////////////////////////////// + + void DXRenderModule::convert2Screen( ::basegfx::B2IPoint& io_rDestPos, + ::basegfx::B2IRange& io_rDestArea ) + { + POINT aPoint = { 0, 0 }; + ClientToScreen( mhWnd, &aPoint ); + + // i52230 make sure given screen coordinate is relative to + // this monitor's area (the device rendering is always + // contained to a single monitor) + aPoint.x -= maMonitorInfo.rcMonitor.left; + aPoint.y -= maMonitorInfo.rcMonitor.top; + + io_rDestPos.setX( io_rDestPos.getX() + aPoint.x ); + io_rDestPos.setY( io_rDestPos.getY() + aPoint.y ); + + const ::basegfx::B2ISize& rSize( getFramebufferSize() ); + + // calc output bounds (clip against framebuffer bounds) + io_rDestArea = ::basegfx::B2IRange( + ::std::max( sal_Int32(0), + ::std::min( sal_Int32(rSize.getX()), + sal_Int32(io_rDestArea.getMinX() + aPoint.x) ) ), + ::std::max( sal_Int32(0), + ::std::min( sal_Int32(rSize.getY()), + sal_Int32(io_rDestArea.getMinY() + aPoint.y) ) ), + ::std::max( sal_Int32(0), + ::std::min( sal_Int32(rSize.getX()), + sal_Int32(io_rDestArea.getMaxX() + aPoint.x) ) ), + ::std::max( sal_Int32(0), + ::std::min( sal_Int32(rSize.getY()), + sal_Int32(io_rDestArea.getMaxY() + aPoint.y) ) ) ); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::createSystemMemorySurface + ////////////////////////////////////////////////////////////////////////////////// + + COMReference<IDirectDrawSurface> DXRenderModule::createSystemMemorySurface( const ::basegfx::B2IVector& rSize ) + { + DDSURFACEDESC aSurfaceDesc; + IDirectDrawSurface* pSurface; + + aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC); + aSurfaceDesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;; + aSurfaceDesc.dwWidth = rSize.getX(); + aSurfaceDesc.dwHeight= rSize.getY(); + + rtl_copyMemory( &aSurfaceDesc.ddpfPixelFormat, &maTextureFormat, sizeof(DDPIXELFORMAT) ); + + aSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; + + HRESULT nRes = mpDirectDraw->CreateSurface(&aSurfaceDesc, &pSurface, NULL); + if(FAILED(nRes)) + return COMReference<IDirectDrawSurface>(NULL); + + return COMReference<IDirectDrawSurface>(pSurface); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::flip + ////////////////////////////////////////////////////////////////////////////////// + + bool DXRenderModule::flip( const ::basegfx::B2IRectangle& rUpdateArea, + const ::basegfx::B2IRectangle& rCurrWindowArea ) + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + // see if the main surfaces got lost. if so, try to + // restore them. bail out if this operation fails. + if(!(validateMainSurfaces())) + return false; + + flushVertexCache(); + + ENSURE_OR_THROW( !mnBeginSceneCount, + "Device::flip(): within 3D scene" ); + + // TODO(E3): handle DX errors more thoroughly. For fullscreen + // exclusive mode, actually even our primary surface can get + // lost and needs restore! + + if( mpDirectDraw.is() && + mpPrimarySurface.is() && + mpBackBufferSurface.is() ) + { + // ignore area and offset for page flipping device + if( mbPageFlipping ) + { +#if defined(VERBOSE) && defined(DBG_UTIL) + renderFPSCounter(); + renderMemAvailable(); +#endif + VERBOSE_TRACE( "Device::flip(): Using true page flipping" ); + + // use true page flipping. Hopefully, the 3D hardware + // is flushed on this flip call (rumours have it that + // way), otherwise, perform the Lock hack as for the + // Blt below. + if( SUCCEEDED(mpPrimarySurface->Flip( NULL, DDFLIP_WAIT )) ) + return true; + } + else + { + VERBOSE_TRACE( "Device::flip(): Using blt for page flipping" ); + + // determine actual window position + ::basegfx::B2IPoint aDestPoint( rUpdateArea.getMinimum() ); + ::basegfx::B2IRange aSourceArea( rUpdateArea ); + ::basegfx::B2IRange aDestArea( 0,0, + static_cast<sal_Int32>(rCurrWindowArea.getWidth()), + static_cast<sal_Int32>(rCurrWindowArea.getHeight()) ); + convert2Screen( aDestPoint, aDestArea ); + + // perform clipping + if( !::canvas::tools::clipBlit( aSourceArea, + aDestPoint, + rUpdateArea, + aDestArea ) ) + return true; // fully clipped, but still, in a way, + // successful. + + // TODO(P1): Rumours have it that the 3D hardware + // _might_ still be rendering with flaky drivers, + // which don't flush properly on Blt(). It was said, + // that 'usually', it works to lock the 3D render + // target (the backbuffer in this case). OTOH, I've + // found that this tends to degrade performance + // significantly on complying cards... + + // TODO(P1): Up until rev. 1.3, this method contained + // code to make sure the blit will start _immediately_ + // after the Blt call. If this is not warranted, wait + // for the next vsync. As this case was found to be + // extremely seldom, kicked out (what's more, there's + // simply no guarantee that the blitter will be + // available at any point in the code - Windows still + // is a preemptive multi-processing environment. And + // _if_ we're competing with someone over the blitter, + // we will do so the next VBLANK interval, and the + // following...) + + // screen update seems to be smoother when waiting + // for vblank in every case - even when blitter + // supports the DDBLTFX_NOTEARING flag. + if( FAILED(mpDirectDraw->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, + NULL)) ) + return false; + + DDBLTFX aBltFx; + DDBLTFX* pBltFX = NULL; + if( mbHasNoTearingBlt ) + { + // Blt can internally schedule for no-tearing + // =========================================== + + rtl_fillMemory( &aBltFx, + sizeof(aBltFx), 0 ); + aBltFx.dwSize = sizeof(aBltFx); + aBltFx.dwDDFX = DDBLTFX_NOTEARING; + + pBltFX = &aBltFx; + } + + if( doBlit( aDestPoint, + *mpPrimarySurface, + aSourceArea, + *mpBackBufferSurface, + pBltFX,false ) ) + { +#if defined(VERBOSE) && defined(DBG_UTIL) + renderFPSCounter(); + renderMemAvailable(); +#endif + return true; + } + } + } + return false; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::disposing + ////////////////////////////////////////////////////////////////////////////////// + + void DXRenderModule::disposing() + { + if(!(mhWnd)) + return; + + mpTexture.reset(); + mpWindow.reset(); + mhWnd=NULL; + + // refrain from releasing the DX5 objects - deleting the + // DX5 device seems to kill the whole engine, including + // all objects we might still hold references to + // (surfaces, e.g.) + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::screenshot + ////////////////////////////////////////////////////////////////////////////////// + + void DXRenderModule::screenShot() + { + if(!(mpBackBufferSurface.get())) + return; + char filename[256]; + static sal_uInt32 counter = 0; + sprintf(filename,"c:\\shot%d.bmp",counter++); + dumpSurface(mpBackBufferSurface,filename); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::validateMainSurfaces + ////////////////////////////////////////////////////////////////////////////////// + + bool DXRenderModule::validateMainSurfaces() + { + if(mpPrimarySurface.get()) { + if(mpPrimarySurface->IsLost() == DDERR_SURFACELOST) { + if(FAILED(mpPrimarySurface->Restore())) + return false; + } + } + + if(mpBackBufferSurface.get()) { + if(mpBackBufferSurface->IsLost() == DDERR_SURFACELOST) + { + // TODO(F1): simply restoring the backbuffer does not + // work as expected, we need to re-create everything + // from scratch. find out why... + //if(SUCCEEDED(mpBackBufferSurface->Restore())) + // return setup3DDevice(); + + mpBackBufferSurface.reset(); + + // get us a backbuffer for simulated flipping + IDirectDrawSurface* pSurface; + + // TODO(P2): Strictly speaking, we don't need a full screen worth of + // backbuffer here. We could also scale dynamically with the current + // window size, but this will make it necessary to temporarily have two + // buffers while copying from the old to the new one. YMMV. + const ::basegfx::B2ISize aSize( getFramebufferSize() ); + + DDSURFACEDESC aSurfaceDesc; + rtl_fillMemory( &aSurfaceDesc, sizeof(DDSURFACEDESC), 0 ); + aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC); + aSurfaceDesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; + aSurfaceDesc.dwHeight= aSize.getY(); + aSurfaceDesc.dwWidth = aSize.getX(); + + aSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM; + + HRESULT nRes = mpDirectDraw->CreateSurface(&aSurfaceDesc, &pSurface, NULL); + + if( FAILED( nRes ) ) + { + if( nRes == DDERR_OUTOFVIDEOMEMORY ) + { + // local vid mem failed. Maybe AGP mem works? + aSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY | DDSCAPS_NONLOCALVIDMEM; + if( FAILED(mpDirectDraw->CreateSurface(&aSurfaceDesc, &pSurface, NULL)) ) + { + // no chance + return false; + } + + VERBOSE_TRACE( "Device::Device(): CreateSurface for backbuffer reverted to non-local video mem" ); + } + else + { + // no chance + VERBOSE_TRACE( "Device::Device(): CreateSurface for backbuffer failed" ); + return false; + } + } + + VERBOSE_TRACE( "Device::Device(): created backbuffer of size %d times %d pixel", + aSurfaceDesc.dwWidth, + aSurfaceDesc.dwHeight ); + + mpBackBufferSurface = COMReference< IDirectDrawSurface >(pSurface); + + return setup3DDevice(); + } + } + + return true; + } + + void DXRenderModule::renderInfoText( const ::rtl::OUString& rStr, + const Gdiplus::PointF& rPos ) const + { + ENSURE_OR_THROW( !mnBeginSceneCount, + "Device::renderInfoText(): within 3D scene" ); + + // render text directly to primary surface + GraphicsSharedPtr pGraphics; + + if( mbPageFlipping ) + { + // render on top of backbuffer. We have + // page flipping, anyway, thus this will + // cost us nothing. + pGraphics = createSurfaceGraphics( mpBackBufferSurface ); + } + else + { + // render FPS directly to front buffer. + // That saves us another explicit blit, + // and for me, the FPS counter can blink, + // if it likes to... + pGraphics = createSurfaceGraphics( mpPrimarySurface ); + } + + if( !mbPageFlipping ) + { + // clear background. We might be doing optimized redraws, + // and the background under the FPS count will then not be + // cleared. + Gdiplus::SolidBrush aBrush( + Gdiplus::Color( 255, 255, 255 ) ); + + pGraphics->FillRectangle( &aBrush, + rPos.X, rPos.Y, 80.0, 20.0 ); + } + + Gdiplus::SolidBrush aBrush( + Gdiplus::Color( 255, 0, 255 ) ); + Gdiplus::Font aFont( NULL, + 16, + Gdiplus::FontStyleRegular, + Gdiplus::UnitWorld, + NULL ); + pGraphics->DrawString( reinterpret_cast<LPCWSTR>(rStr.getStr()), + rStr.getLength(), + &aFont, + rPos, + &aBrush ); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::renderMemAvailable + ////////////////////////////////////////////////////////////////////////////////// + + void DXRenderModule::renderMemAvailable() const + { + ENSURE_OR_THROW( !mnBeginSceneCount, + "DXRenderModule::renderMemAvailable(): within 3D scene" ); + + const double nSurfaceMem( getAvailableSurfaceMem()/1024 ); + + ::rtl::OUString text( ::rtl::math::doubleToUString( nSurfaceMem, + rtl_math_StringFormat_F, + 2,'.',NULL,' ') ); + + // pad with leading space + while( text.getLength() < 6 ) + text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM (" ")) + text; + + text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("S: ")) + text; + + renderInfoText( text, + Gdiplus::PointF( 0.0, 20) ); + + + const double nTexMem( getAvailableTextureMem()/1024 ); + + text = ::rtl::math::doubleToUString( nTexMem, + rtl_math_StringFormat_F, + 2,'.',NULL,' '); + // pad with leading space + while( text.getLength() < 6 ) + text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM (" ")) + text; + + text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("T: ")) + text; + + renderInfoText( text, + Gdiplus::PointF( 0.0, 40) ); + + VERBOSE_TRACE( "dxcanvas: %f free surface mem, %f free texture mem", + nSurfaceMem, nTexMem ); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::renderFPSCounter + ////////////////////////////////////////////////////////////////////////////////// + + void DXRenderModule::renderFPSCounter() const + { + ENSURE_OR_THROW( !mnBeginSceneCount, + "DXRenderModule::ren derFPSCounter(): within 3D scene" ); + + const double denominator( maLastUpdate.getElapsedTime() ); + maLastUpdate.reset(); + + ::rtl::OUString text( ::rtl::math::doubleToUString( denominator == 0.0 ? 100.0 : 1.0/denominator, + rtl_math_StringFormat_F, + 2,'.',NULL,' ') ); + + // pad with leading space + while( text.getLength() < 6 ) + text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM (" ")) + text; + + text += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM (" fps")); + + renderInfoText( text, + Gdiplus::PointF() ); + + VERBOSE_TRACE( "dxcanvas: %f FPS", + denominator == 0.0 ? 100.0 : 1.0/denominator ); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::resize + ////////////////////////////////////////////////////////////////////////////////// + + void DXRenderModule::resize( const ::basegfx::B2IRange& rect ) + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + if( mhWnd==0 ) + return; + + // don't do anything if the size didn't change. + if(maSize.getX() == static_cast<sal_Int32>(rect.getWidth()) && + maSize.getY() == static_cast<sal_Int32>(rect.getHeight())) + return; + + // TODO(Q2): use numeric cast to prevent overflow + maSize.setX(static_cast<sal_Int32>(rect.getWidth())); + maSize.setY(static_cast<sal_Int32>(rect.getHeight())); + + mpWindow->SetPosSizePixel(0,0,maSize.getX(),maSize.getY()); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::getPageSize + ////////////////////////////////////////////////////////////////////////////////// + + ::basegfx::B2IVector DXRenderModule::getPageSize() + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + return maPageSize; + } + + ::canvas::ISurfaceSharedPtr DXRenderModule::createSurface( const ::basegfx::B2IVector& surfaceSize ) + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + const ::basegfx::B2IVector& rPageSize( getPageSize() ); + ::basegfx::B2ISize aSize(surfaceSize); + if(!(aSize.getX())) + aSize.setX(rPageSize.getX()); + if(!(aSize.getY())) + aSize.setY(rPageSize.getY()); + + if(mpTexture.use_count() == 1) + return mpTexture; + + return ::canvas::ISurfaceSharedPtr( + new DXSurface(*this, + aSize) ); + } + + void DXRenderModule::beginPrimitive( PrimitiveType eType ) + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + ENSURE_OR_THROW( !mnBeginSceneCount, + "DXRenderModule::beginPrimitive(): nested call" ); + + ++mnBeginSceneCount; + meType=eType; + mnCount=0; + } + + void DXRenderModule::endPrimitive() + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + --mnBeginSceneCount; + meType=PRIMITIVE_TYPE_UNKNOWN; + mnCount=0; + } + + void DXRenderModule::pushVertex( const ::canvas::Vertex& vertex ) + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + switch(meType) + { + case PRIMITIVE_TYPE_TRIANGLE: + { + maVertexCache.push_back(vertex); + ++mnCount; + mnCount &= 3; + break; + } + + case PRIMITIVE_TYPE_QUAD: + { + if(mnCount == 3) + { + const std::size_t size(maVertexCache.size()); + ::canvas::Vertex v0(maVertexCache[size-1]); + ::canvas::Vertex v2(maVertexCache[size-3]); + maVertexCache.push_back(v0); + maVertexCache.push_back(vertex); + maVertexCache.push_back(v2); + mnCount=0; + } + else + { + maVertexCache.push_back(vertex); + ++mnCount; + } + break; + } + + default: + OSL_ENSURE( false, + "DXRenderModule::pushVertex(): unexpected primitive types" ); + break; + } + } + + bool DXRenderModule::isError() + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + return mbError; + } + + void DXRenderModule::flushVertexCache() + { + if(!(maVertexCache.size())) + return; + + mbError=true; + + if( FAILED(mpDirect3DDevice->BeginScene()) ) + return; + + // enable texture alpha blending + if( FAILED(mpDirect3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE))) + return; + + // enable texture alpha modulation, for honoring fAlpha + if( FAILED(mpDirect3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREMAPBLEND, + D3DTBLEND_MODULATEALPHA)) ) + return; + + // enable texture magnification filtering (don't care if this + // fails, it's just visually more pleasant) + mpDirect3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREMAG, + D3DFILTER_LINEAR); + + // enable texture minification filtering (don't care if this + // fails, it's just visually more pleasant) + mpDirect3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREMIN, + D3DFILTER_LINEAR); + + // enable subpixel texture output (don't care if this + // fails, it's just visually more pleasant) + mpDirect3DDevice->SetRenderState(D3DRENDERSTATE_SUBPIXEL, + TRUE); + + // normal combination of object... + if( FAILED(mpDirect3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, + D3DBLEND_SRCALPHA)) ) + return; + + // ..and background color + if( FAILED(mpDirect3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, + D3DBLEND_INVSRCALPHA)) ) + return; + + // disable backface culling; this enables us to mirror sprites + // by simply reverting the triangles, which, with enabled + // culling, would be invisible otherwise + if( FAILED(mpDirect3DDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, + D3DCULL_NONE)) ) + return; + + mbError=false; + + const float nHalfPixelSizeX(0.5f/maPageSize.getX()); + const float nHalfPixelSizeY(0.5f/maPageSize.getY()); + sal_uInt32 nIndex(0); + const std::size_t size(maVertexCache.size()); + D3DTLVERTEX *vertices = static_cast<D3DTLVERTEX *>(_alloca(sizeof(D3DTLVERTEX)*size)); + vertexCache_t::const_iterator it(maVertexCache.begin()); + while(it != maVertexCache.end()) + { + vertices[nIndex++] = D3DTLVERTEX( + D3DVECTOR(static_cast<D3DVALUE>(it->x), + static_cast<D3DVALUE>(it->y), + static_cast<D3DVALUE>(it->z)), + 1, + D3DRGBA(1,1,1,it->a), + D3DRGBA(0,0,0,0), + static_cast<float>(it->u + nHalfPixelSizeX), + static_cast<float>(it->v + nHalfPixelSizeY)); + ++it; + } + + maVertexCache.clear(); + + mbError |= FAILED(mpDirect3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST, + D3DVT_TLVERTEX, + (LPVOID)vertices, + size, + 0)); + + mbError |= FAILED(mpDirect3DDevice->EndScene()); + } + } + + IDXRenderModuleSharedPtr createRenderModule( const ::Window& rParent ) + { + return IDXRenderModuleSharedPtr( new DXRenderModule(rParent) ); + } +} + +#endif diff --git a/canvas/source/directx/dx_9rm.cxx b/canvas/source/directx/dx_9rm.cxx new file mode 100755 index 000000000000..acef323ddc1b --- /dev/null +++ b/canvas/source/directx/dx_9rm.cxx @@ -0,0 +1,1366 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_9rm.cxx,v $ + * $Revision: 1.5 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#if DIRECTX_VERSION == 0x0900 + +#define MAX_TEXTURE_SIZE (2048) +#define MIN_TEXTURE_SIZE (32) +//#define FAKE_MAX_NUMBER_TEXTURES (2) +//#define FAKE_MAX_TEXTURE_SIZE (4096) + +#define VERTEX_BUFFER_SIZE (341*3) // 1023, the size of the internal + // vertex buffer (must be divisable + // by 3, as each triangle primitive + // has 3 vertices) + + +////////////////////////////////////////////////////////////////////////////////// +// includes +////////////////////////////////////////////////////////////////////////////////// +#include <vcl/syschild.hxx> +#include <vcl/window.hxx> + +#include <canvas/debug.hxx> +#include <canvas/verbosetrace.hxx> +#include <tools/diagnose_ex.h> + +#include <canvas/elapsedtime.hxx> +#include <canvas/canvastools.hxx> +#include <canvas/rendering/icolorbuffer.hxx> +#include <canvas/rendering/isurface.hxx> +#include <canvas/rendering/irendermodule.hxx> +#include <basegfx/numeric/ftools.hxx> +#include <basegfx/vector/b2dsize.hxx> +#include <basegfx/vector/b2isize.hxx> +#include <basegfx/point/b2ipoint.hxx> +#include <basegfx/range/b2irectangle.hxx> +#include <boost/scoped_ptr.hpp> +#include <com/sun/star/lang/NoSupportException.hpp> + +#include "dx_rendermodule.hxx" +#include "dx_config.hxx" + +#undef WB_LEFT +#undef WB_RIGHT + +#include "dx_impltools.hxx" +#include <vcl/sysdata.hxx> + +#if defined(DX_DEBUG_IMAGES) +# if OSL_DEBUG_LEVEL > 0 +# include <imdebug.h> +# undef min +# undef max +# endif +#endif + +using namespace ::com::sun::star; + +////////////////////////////////////////////////////////////////////////////////// +// 'dxcanvas' namespace +////////////////////////////////////////////////////////////////////////////////// + +namespace dxcanvas +{ + namespace + { + ////////////////////////////////////////////////////////////////////////////////// + // monitorSupport + ////////////////////////////////////////////////////////////////////////////////// + + class monitorSupport + { + public: + + monitorSupport() : + mhLibrary(LoadLibrary("user32.dll")), + mpMonitorFromWindow(NULL) + { + if(mhLibrary) + mpMonitorFromWindow = reinterpret_cast<fMonitorFromWindow>( + GetProcAddress( + mhLibrary,"MonitorFromWindow")); + } + + ~monitorSupport() + { + if(mhLibrary) + FreeLibrary(mhLibrary); + mhLibrary=0; + } + + HMONITOR MonitorFromWindow( HWND hwnd ) + { + // return adapter_default in case something went wrong... + if(!(mpMonitorFromWindow)) + return HMONITOR(0); + // MONITOR_DEFAULTTONEAREST + const DWORD dwFlags(0x00000002); + return mpMonitorFromWindow(hwnd,dwFlags); + } + private: + + HINSTANCE mhLibrary; + typedef HMONITOR (WINAPI *fMonitorFromWindow )( HWND hwnd, DWORD dwFlags ); + fMonitorFromWindow mpMonitorFromWindow; + }; + + monitorSupport aMonitorSupport; + + + class DXRenderModule; + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurface + ////////////////////////////////////////////////////////////////////////////////// + + /** ISurface implemenation. + + @attention holds the DXRenderModule via non-refcounted + reference! This is safe with current state of affairs, since + the canvas::PageManager holds surface and render module via + shared_ptr (and makes sure all surfaces are deleted before its + render module member goes out of scope). + */ + class DXSurface : public canvas::ISurface + { + public: + DXSurface( DXRenderModule& rRenderModule, + const ::basegfx::B2ISize& rSize ); + ~DXSurface(); + + virtual bool selectTexture(); + virtual bool isValid(); + virtual bool update( const ::basegfx::B2IPoint& rDestPos, + const ::basegfx::B2IRange& rSourceRect, + ::canvas::IColorBuffer& rSource ); + virtual ::basegfx::B2IVector getSize(); + COMReference<IDirect3DTexture9> getTexture() const; + + private: + /// Guard local methods against concurrent acces to RenderModule + class ImplRenderModuleGuard : private ::boost::noncopyable + { + public: + explicit inline ImplRenderModuleGuard( DXRenderModule& rRenderModule ); + inline ~ImplRenderModuleGuard(); + + private: + DXRenderModule& mrRenderModule; + }; + + DXRenderModule& mrRenderModule; + COMReference<IDirect3DTexture9> mpTexture; + + ::basegfx::B2IVector maSize; + }; + + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule + ////////////////////////////////////////////////////////////////////////////////// + + /// Default implementation of IDXRenderModule + class DXRenderModule : public IDXRenderModule + { + public: + explicit DXRenderModule( const ::Window& rWindow ); + ~DXRenderModule(); + + virtual void lock() const { maMutex.acquire(); } + virtual void unlock() const { maMutex.release(); } + + virtual COMReference<IDirect3DSurface9> + createSystemMemorySurface( const ::basegfx::B2IVector& rSize ); + virtual void disposing(); + virtual HWND getHWND() const { return mhWnd; } + virtual void screenShot(); + + virtual bool flip( const ::basegfx::B2IRectangle& rUpdateArea, + const ::basegfx::B2IRectangle& rCurrWindowArea ); + + virtual void resize( const ::basegfx::B2IRange& rect ); + virtual ::basegfx::B2IVector getPageSize(); + virtual ::canvas::ISurfaceSharedPtr createSurface( const ::basegfx::B2IVector& surfaceSize ); + virtual void beginPrimitive( PrimitiveType eType ); + virtual void endPrimitive(); + virtual void pushVertex( const ::canvas::Vertex& vertex ); + virtual bool isError(); + + COMReference<IDirect3DDevice9> getDevice() { return mpDevice; } + + void flushVertexCache(); + void commitVertexCache(); + + private: + + bool create( const ::Window& rWindow ); + bool createDevice(); + bool verifyDevice( const UINT nAdapter ); + UINT getAdapterFromWindow(); + + /** This object represents the DirectX state machine. In order + to serialize access to DirectX's global state, a global + mutex is required. + */ + static ::osl::Mutex maMutex; + + HWND mhWnd; + COMReference<IDirect3DDevice9> mpDevice; + COMReference<IDirect3D9> mpDirect3D9; + COMReference<IDirect3DSwapChain9> mpSwapChain; + COMReference<IDirect3DVertexBuffer9> mpVertexBuffer; + ::canvas::ISurfaceSharedPtr mpTexture; + ::boost::scoped_ptr<SystemChildWindow> mpWindow; + ::basegfx::B2IVector maSize; + typedef std::vector<canvas::Vertex> vertexCache_t; + vertexCache_t maVertexCache; + std::size_t mnCount; + int mnBeginSceneCount; + bool mbCanUseDynamicTextures; + bool mbError; + PrimitiveType meType; + ::basegfx::B2IVector maPageSize; + D3DPRESENT_PARAMETERS mad3dpp; + + inline bool isDisposed() const { return (mhWnd==NULL); } + + struct dxvertex + { + float x,y,z,rhw; + DWORD diffuse; + float u,v; + }; + + std::size_t maNumVertices; + std::size_t maWriteIndex; + std::size_t maReadIndex; + }; + + ::osl::Mutex DXRenderModule::maMutex; + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurface::ImplRenderModuleGuard + ////////////////////////////////////////////////////////////////////////////////// + + inline DXSurface::ImplRenderModuleGuard::ImplRenderModuleGuard( + DXRenderModule& rRenderModule ) : + mrRenderModule( rRenderModule ) + { + mrRenderModule.lock(); + } + + inline DXSurface::ImplRenderModuleGuard::~ImplRenderModuleGuard() + { + mrRenderModule.unlock(); + } + +#ifdef FAKE_MAX_NUMBER_TEXTURES + static sal_uInt32 gNumSurfaces = 0; +#endif + + void fillRect( sal_uInt32 *pDest, + sal_uInt32 dwWidth, + sal_uInt32 dwHeight, + sal_uInt32 dwPitch, + sal_uInt32 dwColor ) + { + for(sal_uInt32 i=0; i<dwWidth; ++i) + { + pDest[i]=dwColor; + pDest[((dwHeight-1)*dwPitch)+i]=dwColor; + } + + for(sal_uInt32 j=0; j<dwHeight; ++j) + { + pDest[0]=dwColor; + pDest[dwWidth-1]=dwColor; + pDest += dwPitch; + } + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurface::DXSurface + ////////////////////////////////////////////////////////////////////////////////// + + DXSurface::DXSurface( DXRenderModule& rRenderModule, + const ::basegfx::B2ISize& rSize ) : + mrRenderModule(rRenderModule), + mpTexture(NULL), + maSize() + { + ImplRenderModuleGuard aGuard( mrRenderModule ); + +#ifdef FAKE_MAX_NUMBER_TEXTURES + ++gNumSurfaces; + if(gNumSurfaces >= FAKE_MAX_NUMBER_TEXTURES) + return; +#endif + +#ifdef FAKE_MAX_TEXTURE_SIZE + if(rSize.getX() > FAKE_MAX_TEXTURE_SIZE) + return; + if(rSize.getY() > FAKE_MAX_TEXTURE_SIZE) + return; +#endif + + ENSURE_ARG_OR_THROW(rSize.getX() > 0 && rSize.getY() > 0, + "DXSurface::DXSurface(): request for zero-sized surface"); + + COMReference<IDirect3DDevice9> pDevice(rRenderModule.getDevice()); + + IDirect3DTexture9 *pTexture(NULL); + if(FAILED(pDevice->CreateTexture( + rSize.getX(), + rSize.getY(), + 1,0,D3DFMT_A8R8G8B8, + D3DPOOL_MANAGED, + &pTexture,NULL))) + return; + + mpTexture=COMReference<IDirect3DTexture9>(pTexture); + maSize = rSize; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurface::~DXSurface + ////////////////////////////////////////////////////////////////////////////////// + + DXSurface::~DXSurface() + { + ImplRenderModuleGuard aGuard( mrRenderModule ); + +#ifdef FAKE_MAX_NUMBER_TEXTURES + gNumSurfaces--; +#endif + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurface::selectTexture + ////////////////////////////////////////////////////////////////////////////////// + + bool DXSurface::selectTexture() + { + ImplRenderModuleGuard aGuard( mrRenderModule ); + mrRenderModule.flushVertexCache(); + COMReference<IDirect3DDevice9> pDevice(mrRenderModule.getDevice()); + + if( FAILED(pDevice->SetTexture(0,mpTexture.get())) ) + return false; + + return true; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurface::isValid + ////////////////////////////////////////////////////////////////////////////////// + + bool DXSurface::isValid() + { + ImplRenderModuleGuard aGuard( mrRenderModule ); + + if(!(mpTexture.is())) + return false; + return true; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurface::update + ////////////////////////////////////////////////////////////////////////////////// + + bool DXSurface::update( const ::basegfx::B2IPoint& rDestPos, + const ::basegfx::B2IRange& rSourceRect, + ::canvas::IColorBuffer& rSource ) + { + ImplRenderModuleGuard aGuard( mrRenderModule ); + + // can't update if surface is not valid, that means + // either not existent nor restored... + if(!(isValid())) + return false; + + D3DLOCKED_RECT aLockedRect; + RECT rect; + rect.left = std::max(sal_Int32(0),rDestPos.getX()); + rect.top = std::max(sal_Int32(0),rDestPos.getY()); + // to avoid interpolation artifacts from other textures, + // the surface manager allocates one pixel gap between + // them. Clear that to transparent. + rect.right = std::min(maSize.getX(), + rect.left + sal_Int32(rSourceRect.getWidth()+1)); + rect.bottom = std::min(maSize.getY(), + rect.top + sal_Int32(rSourceRect.getHeight()+1)); + const bool bClearRightColumn( rect.right < maSize.getX() ); + const bool bClearBottomRow( rect.bottom < maSize.getY() ); + + if(SUCCEEDED(mpTexture->LockRect(0,&aLockedRect,&rect,D3DLOCK_NOSYSLOCK))) + { + if(sal_uInt8* pImage = rSource.lock()) + { + switch( rSource.getFormat() ) + { + case ::canvas::IColorBuffer::FMT_A8R8G8B8: + { + const std::size_t nSourceBytesPerPixel(4); + const std::size_t nSourcePitchInBytes(rSource.getStride()); + pImage += rSourceRect.getMinY()*nSourcePitchInBytes; + pImage += rSourceRect.getMinX()*nSourceBytesPerPixel; + + // calculate the destination memory address + sal_uInt8 *pDst = (sal_uInt8*)aLockedRect.pBits; + + const sal_uInt32 nNumBytesToCopy( + static_cast<sal_uInt32>( + rSourceRect.getWidth())* + nSourceBytesPerPixel); + const sal_uInt64 nNumLines(rSourceRect.getHeight()); + + for(sal_uInt32 i=0; i<nNumLines; ++i) + { + rtl_copyMemory(pDst,pImage,nNumBytesToCopy); + + if( bClearRightColumn ) + { + // to avoid interpolation artifacts + // from other textures, the surface + // manager allocates one pixel gap + // between them. Clear that to + // transparent. + pDst[nNumBytesToCopy] = + pDst[nNumBytesToCopy+1] = + pDst[nNumBytesToCopy+2] = + pDst[nNumBytesToCopy+3] = 0x00; + } + pDst += aLockedRect.Pitch; + pImage += nSourcePitchInBytes; + } + + if( bClearBottomRow ) + rtl_zeroMemory(pDst,nNumBytesToCopy+4); + } + break; + + case ::canvas::IColorBuffer::FMT_R8G8B8: + { + const std::size_t nSourceBytesPerPixel(3); + const std::size_t nSourcePitchInBytes(rSource.getStride()); + pImage += rSourceRect.getMinY()*nSourcePitchInBytes; + pImage += rSourceRect.getMinX()*nSourceBytesPerPixel; + + // calculate the destination memory address + sal_uInt8 *pDst = (sal_uInt8*)aLockedRect.pBits; + + const sal_Int32 nNumColumns( + sal::static_int_cast<sal_Int32>(rSourceRect.getWidth())); + const sal_Int32 nNumLines( + sal::static_int_cast<sal_Int32>(rSourceRect.getHeight())); + for(sal_Int32 i=0; i<nNumLines; ++i) + { + sal_uInt32 *pDstScanline = reinterpret_cast<sal_uInt32 *>(pDst); + sal_uInt8 *pSrcScanline = reinterpret_cast<sal_uInt8 *>(pImage); + + for(sal_Int32 x=0; x<nNumColumns; ++x) + { + sal_uInt32 color(0xFF000000); + color |= pSrcScanline[2]<<16; + color |= pSrcScanline[1]<<8; + color |= pSrcScanline[0]; + pSrcScanline += 3; + *pDstScanline++ = color; + } + if( bClearRightColumn ) + *pDstScanline++ = 0xFF000000; + + pDst += aLockedRect.Pitch; + pImage += nSourcePitchInBytes; + } + + if( bClearBottomRow ) + rtl_zeroMemory(pDst,4*(nNumColumns+1)); + } + break; + + case ::canvas::IColorBuffer::FMT_X8R8G8B8: + { + const std::size_t nSourceBytesPerPixel(4); + const std::size_t nSourcePitchInBytes(rSource.getStride()); + pImage += rSourceRect.getMinY()*nSourcePitchInBytes; + pImage += rSourceRect.getMinX()*nSourceBytesPerPixel; + + // calculate the destination memory address + sal_uInt8 *pDst = (sal_uInt8*)aLockedRect.pBits; + + const sal_Int32 nNumLines( + sal::static_int_cast<sal_Int32>(rSourceRect.getHeight())); + const sal_Int32 nNumColumns( + sal::static_int_cast<sal_Int32>(rSourceRect.getWidth())); + for(sal_Int32 i=0; i<nNumLines; ++i) + { + sal_uInt32 *pSrc32 = reinterpret_cast<sal_uInt32 *>(pImage); + sal_uInt32 *pDst32 = reinterpret_cast<sal_uInt32 *>(pDst); + for(sal_Int32 j=0; j<nNumColumns; ++j) + pDst32[j] = 0xFF000000 | pSrc32[j]; + + if( bClearRightColumn ) + pDst32[nNumColumns] = 0xFF000000; + + pDst += aLockedRect.Pitch; + pImage += nSourcePitchInBytes; + } + + if( bClearBottomRow ) + rtl_zeroMemory(pDst,4*(nNumColumns+1)); + } + break; + + default: + ENSURE_OR_RETURN(false, + "DXSurface::update(): Unknown/unimplemented buffer format" ); + break; + } + + rSource.unlock(); + } + + return SUCCEEDED(mpTexture->UnlockRect(0)); + } + + return true; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurface::getSize + ////////////////////////////////////////////////////////////////////////////////// + + ::basegfx::B2IVector DXSurface::getSize() + { + return maSize; + } + + COMReference<IDirect3DTexture9> DXSurface::getTexture() const + { + return mpTexture; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::DXRenderModule + ////////////////////////////////////////////////////////////////////////////////// + + DXRenderModule::DXRenderModule( const ::Window& rWindow ) : + mhWnd(0), + mpDevice(), + mpDirect3D9(), + mpSwapChain(), + mpVertexBuffer(), + mpTexture(), + maSize(), + maVertexCache(), + mnCount(0), + mnBeginSceneCount(0), + mbCanUseDynamicTextures(false), + mbError( false ), + meType( PRIMITIVE_TYPE_UNKNOWN ), + maPageSize(), + mad3dpp(), + maNumVertices( VERTEX_BUFFER_SIZE ), + maWriteIndex(0), + maReadIndex(0) + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + if(!(create(rWindow))) + { + throw lang::NoSupportException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "Could not create DirectX device!") ),NULL); + } + + // allocate a single texture surface which can be used later. + // we also use this to calibrate the page size. + ::basegfx::B2IVector aPageSize(maPageSize); + while(true) + { + mpTexture = ::canvas::ISurfaceSharedPtr( + new DXSurface(*this,aPageSize)); + if(mpTexture->isValid()) + break; + + aPageSize.setX(aPageSize.getX()>>1); + aPageSize.setY(aPageSize.getY()>>1); + if((aPageSize.getX() < MIN_TEXTURE_SIZE) || + (aPageSize.getY() < MIN_TEXTURE_SIZE)) + { + throw lang::NoSupportException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "Could not create DirectX device - " + "insufficient texture space!") ),NULL); + } + } + maPageSize=aPageSize; + + IDirect3DVertexBuffer9 *pVB(NULL); + DWORD aFVF(D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1); + if( FAILED(mpDevice->CreateVertexBuffer(sizeof(dxvertex)*maNumVertices, + D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY, + aFVF, + D3DPOOL_DEFAULT, + &pVB, + NULL)) ) + { + throw lang::NoSupportException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "Could not create DirectX device - out of memory!")),NULL); + } + + mpVertexBuffer=COMReference<IDirect3DVertexBuffer9>(pVB); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::~DXRenderModule + ////////////////////////////////////////////////////////////////////////////////// + + DXRenderModule::~DXRenderModule() + { + disposing(); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::disposing + ////////////////////////////////////////////////////////////////////////////////// + + void DXRenderModule::disposing() + { + if(!(mhWnd)) + return; + + mpTexture.reset(); + mpWindow.reset(); + mhWnd=NULL; + + // refrain from releasing the DX9 objects. We're the only + // ones holding references to them, and it might be + // dangerous to destroy the DX9 device, before all other + // objects are dead. + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::create + ////////////////////////////////////////////////////////////////////////////////// + + bool DXRenderModule::create( const ::Window& rWindow ) + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + maVertexCache.reserve(1024); + + mpWindow.reset( + new SystemChildWindow( + const_cast<Window *>(&rWindow), 0) ); + + // system child window must not receive mouse events + mpWindow->SetMouseTransparent( TRUE ); + + // parent should receive paint messages as well + // [PARENTCLIPMODE_NOCLIP], the argument is here + // passed as plain numeric value since the stupid + // define utilizes a USHORT cast. + mpWindow->SetParentClipMode(0x0002); + + // the system child window must not clear its background + mpWindow->EnableEraseBackground( FALSE ); + + mpWindow->SetControlForeground(); + mpWindow->SetControlBackground(); + mpWindow->EnablePaint(FALSE); + + const SystemEnvData *pData = mpWindow->GetSystemData(); + const HWND hwnd(reinterpret_cast<HWND>(pData->hWnd)); + mhWnd = const_cast<HWND>(hwnd); + + ENSURE_OR_THROW( IsWindow( reinterpret_cast<HWND>(mhWnd) ), + "DXRenderModule::create() No valid HWND given." ); + + // retrieve position and size of the parent window + const ::Size &rSizePixel(rWindow.GetSizePixel()); + + // remember the size of the parent window, since we + // need to use this for our child window. + maSize.setX(static_cast<sal_Int32>(rSizePixel.Width())); + maSize.setY(static_cast<sal_Int32>(rSizePixel.Height())); + + // let the child window cover the same size as the parent window. + mpWindow->SetPosSizePixel(0,0,maSize.getX(),maSize.getY()); + + // TODO(F2): since we would like to share precious hardware + // resources, the direct3d9 object should be global. each new + // request for a canvas should only create a new swapchain. + mpDirect3D9 = COMReference<IDirect3D9>( + Direct3DCreate9(D3D_SDK_VERSION)); + if(!mpDirect3D9.is()) + return false; + + // create a device from the direct3d9 object. + if(!(createDevice())) + return false; + + mpWindow->Show(); + + return true; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::verifyDevice + ////////////////////////////////////////////////////////////////////////////////// + + bool DXRenderModule::verifyDevice( const UINT nAdapter ) + { + ENSURE_OR_THROW( mpDirect3D9.is(), + "DXRenderModule::verifyDevice() No valid device." ); + + // ask direct3d9 about the capabilities of hardware devices on a specific adapter. + // here we decide if the underlying hardware of the machine 'is good enough'. + // since we only need a tiny little fraction of what could be used, this + // is basically a no-op. + D3DCAPS9 aCaps; + if(FAILED(mpDirect3D9->GetDeviceCaps(nAdapter,D3DDEVTYPE_HAL,&aCaps))) + return false; + if(!(aCaps.MaxTextureWidth)) + return false; + if(!(aCaps.MaxTextureHeight)) + return false; + maPageSize = ::basegfx::B2IVector(aCaps.MaxTextureWidth,aCaps.MaxTextureHeight); + + // check device against white & blacklist entries + D3DADAPTER_IDENTIFIER9 aIdent; + if(FAILED(mpDirect3D9->GetAdapterIdentifier(nAdapter,0,&aIdent))) + return false; + + DXCanvasItem aConfigItem; + DXCanvasItem::DeviceInfo aInfo; + aInfo.nVendorId = aIdent.VendorId; + aInfo.nDeviceId = aIdent.DeviceId; + aInfo.nDeviceSubSysId = aIdent.SubSysId; + aInfo.nDeviceRevision = aIdent.Revision; + + aInfo.nDriverId = HIWORD(aIdent.DriverVersion.HighPart); + aInfo.nDriverVersion = LOWORD(aIdent.DriverVersion.HighPart); + aInfo.nDriverSubVersion = HIWORD(aIdent.DriverVersion.LowPart); + aInfo.nDriverBuildId = LOWORD(aIdent.DriverVersion.LowPart); + + if( !aConfigItem.isDeviceUsable(aInfo) ) + return false; + + if( aConfigItem.isBlacklistCurrentDevice() ) + { + aConfigItem.blacklistDevice(aInfo); + return false; + } + + aConfigItem.adaptMaxTextureSize(maPageSize); + + mbCanUseDynamicTextures = (aCaps.Caps2 & D3DCAPS2_DYNAMICTEXTURES) != 0; + + return true; + } + + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::createDevice + ////////////////////////////////////////////////////////////////////////////////// + + bool DXRenderModule::createDevice() + { + // we expect that the caller provides us with a valid HWND + ENSURE_OR_THROW( IsWindow(mhWnd), + "DXRenderModule::createDevice() No valid HWND given." ); + + // we expect that the caller already created the direct3d9 object. + ENSURE_OR_THROW( mpDirect3D9.is(), + "DXRenderModule::createDevice() no direct3d?." ); + + // find the adapter identifier from the window. + const UINT aAdapter(getAdapterFromWindow()); + if(aAdapter == static_cast<UINT>(-1)) + return false; + + // verify that device possibly works + if( !verifyDevice(aAdapter) ) + return false; + + // query the display mode from the selected adapter. + // we'll later request the backbuffer format to be same + // same as the display format. + D3DDISPLAYMODE d3ddm; + mpDirect3D9->GetAdapterDisplayMode(aAdapter,&d3ddm); + + // we need to use D3DSWAPEFFECT_COPY here since the canvas-api has + // basically nothing to do with efficient resource handling. it tries + // to avoid drawing whenevery possible, which is simply not the most + // efficient way we could leverage the hardware in this case. it would + // be far better to redraw the backbuffer each time we would like to + // display the content of the backbuffer, but we need to face reality + // here and follow how the canvas was designed. + + // Strictly speaking, we don't need a full screen worth of + // backbuffer here. We could also scale dynamically with + // the current window size, but this will make it + // necessary to temporarily have two buffers while copying + // from the old to the new one. What's more, at the time + // we need a larger buffer, DX might not have sufficient + // resources available, and we're then left with too small + // a back buffer, and no way of falling back to a + // different canvas implementation. + ZeroMemory( &mad3dpp, sizeof(mad3dpp) ); + mad3dpp.BackBufferWidth = std::max(sal_Int32(maSize.getX()), + sal_Int32(d3ddm.Width)); + mad3dpp.BackBufferHeight = std::max(sal_Int32(maSize.getY()), + sal_Int32(d3ddm.Height)); + mad3dpp.BackBufferCount = 1; + mad3dpp.Windowed = TRUE; + mad3dpp.SwapEffect = D3DSWAPEFFECT_COPY; + mad3dpp.BackBufferFormat = d3ddm.Format; + mad3dpp.EnableAutoDepthStencil = FALSE; + mad3dpp.hDeviceWindow = mhWnd; + mad3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; + + // now create the device, first try hardware vertex processing, + // then software vertex processing. if both queries fail, we give up + // and indicate failure. + IDirect3DDevice9 *pDevice(NULL); + if(FAILED(mpDirect3D9->CreateDevice(aAdapter, + D3DDEVTYPE_HAL, + mhWnd, + D3DCREATE_HARDWARE_VERTEXPROCESSING| + D3DCREATE_MULTITHREADED|D3DCREATE_FPU_PRESERVE, + &mad3dpp, + &pDevice))) + if(FAILED(mpDirect3D9->CreateDevice(aAdapter, + D3DDEVTYPE_HAL, + mhWnd, + D3DCREATE_SOFTWARE_VERTEXPROCESSING| + D3DCREATE_MULTITHREADED|D3DCREATE_FPU_PRESERVE, + &mad3dpp, + &pDevice))) + return false; + + // got it, store it in a safe place... + mpDevice=COMReference<IDirect3DDevice9>(pDevice); + + // After CreateDevice, the first swap chain already exists, so just get it... + IDirect3DSwapChain9 *pSwapChain(NULL); + pDevice->GetSwapChain(0,&pSwapChain); + mpSwapChain=COMReference<IDirect3DSwapChain9>(pSwapChain); + if( !mpSwapChain.is() ) + return false; + + // clear the render target [which is the backbuffer in this case]. + // we are forced to do this once, and furthermore right now. + // please note that this is only possible since we created the + // backbuffer with copy semantics [the content is preserved after + // calls to Present()], which is an unnecessarily expensive operation. + LPDIRECT3DSURFACE9 pBackBuffer = NULL; + mpSwapChain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&pBackBuffer); + mpDevice->SetRenderTarget( 0, pBackBuffer ); + mpDevice->Clear(0,NULL,D3DCLEAR_TARGET,0,1.0f,0L); + pBackBuffer->Release(); + + return true; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::createSystemMemorySurface + ////////////////////////////////////////////////////////////////////////////////// + + COMReference<IDirect3DSurface9> DXRenderModule::createSystemMemorySurface( const ::basegfx::B2IVector& rSize ) + { + if(isDisposed()) + return COMReference<IDirect3DSurface9>(NULL); + + // please note that D3DFMT_X8R8G8B8 is the only format we're + // able to choose here, since GetDC() doesn't support any + // other 32bit-format. + IDirect3DSurface9 *pSurface(NULL); + if( FAILED(mpDevice->CreateOffscreenPlainSurface( + rSize.getX(), + rSize.getY(), + D3DFMT_X8R8G8B8, + D3DPOOL_SYSTEMMEM, + &pSurface, + NULL)) ) + { + throw lang::NoSupportException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "Could not create offscreen surface - out of mem!") ),NULL); + } + + return COMReference<IDirect3DSurface9>(pSurface); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::flip + ////////////////////////////////////////////////////////////////////////////////// + + bool DXRenderModule::flip( const ::basegfx::B2IRectangle& rUpdateArea, + const ::basegfx::B2IRectangle& /*rCurrWindowArea*/ ) + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + if(isDisposed() || !mpSwapChain.is()) + return false; + + flushVertexCache(); + + // TODO(P2): Might be faster to actually pass update area here + RECT aRect = + { + rUpdateArea.getMinX(), + rUpdateArea.getMinY(), + rUpdateArea.getMaxX(), + rUpdateArea.getMaxY() + }; + HRESULT hr(mpSwapChain->Present(&aRect,&aRect,NULL,NULL,0)); + if(FAILED(hr)) + { + if(hr != D3DERR_DEVICELOST) + return false; + + // interestingly enough, sometimes the Reset() below + // *still* causes DeviceLost errors. So, cycle until + // DX was kind enough to really reset the device... + do + { + mpVertexBuffer.reset(); + hr = mpDevice->Reset(&mad3dpp); + if(SUCCEEDED(hr)) + { + IDirect3DVertexBuffer9 *pVB(NULL); + DWORD aFVF(D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1); + if( FAILED(mpDevice->CreateVertexBuffer(sizeof(dxvertex)*maNumVertices, + D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY, + aFVF, + D3DPOOL_DEFAULT, + &pVB, + NULL)) ) + { + throw lang::NoSupportException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "Could not create DirectX device - out of memory!")),NULL); + } + mpVertexBuffer=COMReference<IDirect3DVertexBuffer9>(pVB); + + // retry after the restore + if(SUCCEEDED(mpSwapChain->Present(&aRect,&aRect,NULL,NULL,0))) + return true; + } + + TimeValue aTimeout; + aTimeout.Seconds=1; + aTimeout.Nanosec=0; + osl_waitThread(&aTimeout); + } + while(hr == D3DERR_DEVICELOST); + + return false; + } + + return true; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::screenShot + ////////////////////////////////////////////////////////////////////////////////// + + void DXRenderModule::screenShot() + { + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::resize + ////////////////////////////////////////////////////////////////////////////////// + + void DXRenderModule::resize( const ::basegfx::B2IRange& rect ) + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + if(isDisposed()) + return; + + // don't do anything if the size didn't change. + if(maSize.getX() == static_cast<sal_Int32>(rect.getWidth()) && + maSize.getY() == static_cast<sal_Int32>(rect.getHeight())) + return; + + // TODO(Q2): use numeric cast to prevent overflow + maSize.setX(static_cast<sal_Int32>(rect.getWidth())); + maSize.setY(static_cast<sal_Int32>(rect.getHeight())); + + mpWindow->SetPosSizePixel(0,0,maSize.getX(),maSize.getY()); + + // resize back buffer, if necessary + // ------------------------------------------------------------- + + // don't attempt to create anything if the + // requested size is NULL. + if(!(maSize.getX())) + return; + if(!(maSize.getY())) + return; + + // backbuffer too small (might happen, if window is + // maximized across multiple monitors) + if( sal_Int32(mad3dpp.BackBufferWidth) < maSize.getX() || + sal_Int32(mad3dpp.BackBufferHeight) < maSize.getY() ) + { + mad3dpp.BackBufferWidth = maSize.getX(); + mad3dpp.BackBufferHeight = maSize.getY(); + + // clear before, save resources + mpSwapChain.reset(); + + IDirect3DSwapChain9 *pSwapChain(NULL); + if(FAILED(mpDevice->CreateAdditionalSwapChain(&mad3dpp,&pSwapChain))) + return; + mpSwapChain=COMReference<IDirect3DSwapChain9>(pSwapChain); + + // clear the render target [which is the backbuffer in this case]. + // we are forced to do this once, and furthermore right now. + // please note that this is only possible since we created the + // backbuffer with copy semantics [the content is preserved after + // calls to Present()], which is an unnecessarily expensive operation. + LPDIRECT3DSURFACE9 pBackBuffer = NULL; + mpSwapChain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&pBackBuffer); + mpDevice->SetRenderTarget( 0, pBackBuffer ); + mpDevice->Clear(0,NULL,D3DCLEAR_TARGET,0,1.0f,0L); + pBackBuffer->Release(); + } + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::getPageSize + ////////////////////////////////////////////////////////////////////////////////// + + ::basegfx::B2IVector DXRenderModule::getPageSize() + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + return maPageSize; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::createSurface + ////////////////////////////////////////////////////////////////////////////////// + + ::canvas::ISurfaceSharedPtr DXRenderModule::createSurface( const ::basegfx::B2IVector& surfaceSize ) + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + if(isDisposed()) + return ::canvas::ISurfaceSharedPtr(); + + const ::basegfx::B2IVector& rPageSize( getPageSize() ); + ::basegfx::B2ISize aSize(surfaceSize); + if(!(aSize.getX())) + aSize.setX(rPageSize.getX()); + if(!(aSize.getY())) + aSize.setY(rPageSize.getY()); + + if(mpTexture.use_count() == 1) + return mpTexture; + + return ::canvas::ISurfaceSharedPtr( new DXSurface(*this,aSize) ); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::beginPrimitive + ////////////////////////////////////////////////////////////////////////////////// + + void DXRenderModule::beginPrimitive( PrimitiveType eType ) + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + if(isDisposed()) + return; + + ENSURE_OR_THROW( !mnBeginSceneCount, + "DXRenderModule::beginPrimitive(): nested call" ); + + ++mnBeginSceneCount; + meType=eType; + mnCount=0; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::endPrimitive + ////////////////////////////////////////////////////////////////////////////////// + + void DXRenderModule::endPrimitive() + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + if(isDisposed()) + return; + + --mnBeginSceneCount; + meType=PRIMITIVE_TYPE_UNKNOWN; + mnCount=0; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::pushVertex + ////////////////////////////////////////////////////////////////////////////////// + + void DXRenderModule::pushVertex( const ::canvas::Vertex& vertex ) + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + if(isDisposed()) + return; + + switch(meType) + { + case PRIMITIVE_TYPE_TRIANGLE: + { + maVertexCache.push_back(vertex); + ++mnCount; + mnCount &= 3; + break; + } + + case PRIMITIVE_TYPE_QUAD: + { + if(mnCount == 3) + { + const std::size_t size(maVertexCache.size()); + ::canvas::Vertex v0(maVertexCache[size-1]); + ::canvas::Vertex v2(maVertexCache[size-3]); + maVertexCache.push_back(v0); + maVertexCache.push_back(vertex); + maVertexCache.push_back(v2); + mnCount=0; + } + else + { + maVertexCache.push_back(vertex); + ++mnCount; + } + break; + } + + default: + OSL_ENSURE(false, + "DXRenderModule::pushVertex(): unexpected primitive type"); + break; + } + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::isError + ////////////////////////////////////////////////////////////////////////////////// + + bool DXRenderModule::isError() + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + return mbError; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::getAdapterFromWindow + ////////////////////////////////////////////////////////////////////////////////// + + UINT DXRenderModule::getAdapterFromWindow() + { + HMONITOR hMonitor(aMonitorSupport.MonitorFromWindow(mhWnd)); + UINT aAdapterCount(mpDirect3D9->GetAdapterCount()); + for(UINT i=0; i<aAdapterCount; ++i) + if(hMonitor == mpDirect3D9->GetAdapterMonitor(i)) + return i; + return static_cast<UINT>(-1); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::commitVertexCache + ////////////////////////////////////////////////////////////////////////////////// + + void DXRenderModule::commitVertexCache() + { + if(maReadIndex != maWriteIndex) + { + const std::size_t nVertexStride = sizeof(dxvertex); + const unsigned int nNumVertices = maWriteIndex-maReadIndex; + const unsigned int nNumPrimitives = nNumVertices / 3; + + if(FAILED(mpDevice->SetStreamSource(0,mpVertexBuffer.get(),0,nVertexStride))) + return; + + if(FAILED(mpDevice->SetFVF(D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1))) + return; + + if(FAILED(mpDevice->BeginScene())) + return; + + mbError |= FAILED(mpDevice->DrawPrimitive(D3DPT_TRIANGLELIST,maReadIndex,nNumPrimitives)); + mbError |= FAILED(mpDevice->EndScene()); + + maReadIndex += nNumVertices; + } + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::flushVertexCache + ////////////////////////////////////////////////////////////////////////////////// + + void DXRenderModule::flushVertexCache() + { + if(!(maVertexCache.size())) + return; + + mbError=true; + + if( FAILED(mpDevice->SetRenderState(D3DRS_LIGHTING,FALSE))) + return; + + // enable texture alpha blending + if( FAILED(mpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE))) + return; + + mpDevice->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_LINEAR); + mpDevice->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_LINEAR); + mpDevice->SetSamplerState(0,D3DSAMP_ADDRESSU ,D3DTADDRESS_CLAMP ); + mpDevice->SetSamplerState(0,D3DSAMP_ADDRESSV ,D3DTADDRESS_CLAMP ); + + // configure the fixed-function pipeline. + // the only 'feature' we need here is to modulate the alpha-channels + // from the texture and the interpolated diffuse color. the result + // will then be blended with the backbuffer. + // fragment color = texture color * diffuse.alpha. + mpDevice->SetTextureStageState(0,D3DTSS_ALPHAOP,D3DTOP_MODULATE); + mpDevice->SetTextureStageState(0,D3DTSS_ALPHAARG1,D3DTA_TEXTURE); + mpDevice->SetTextureStageState(0,D3DTSS_ALPHAARG2,D3DTA_DIFFUSE); + + // normal combination of object... + if( FAILED(mpDevice->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA)) ) + return; + + // ..and background color + if( FAILED(mpDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA)) ) + return; + + // disable backface culling; this enables us to mirror sprites + // by simply reverting the triangles, which, with enabled + // culling, would be invisible otherwise + if( FAILED(mpDevice->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE)) ) + return; + + mbError=false; + + std::size_t nSize(maVertexCache.size()); + const std::size_t nVertexStride = sizeof(dxvertex); + + const ::basegfx::B2IVector aPageSize(getPageSize()); + const float nHalfPixelSizeX(0.5f/aPageSize.getX()); + const float nHalfPixelSizeY(0.5f/aPageSize.getY()); + vertexCache_t::const_iterator it(maVertexCache.begin()); + + while( nSize ) + { + DWORD dwLockFlags(D3DLOCK_NOOVERWRITE); + + // Check to see if there's space for the current set of + // vertices in the buffer. + if( maNumVertices - maWriteIndex < nSize ) + { + commitVertexCache(); + dwLockFlags = D3DLOCK_DISCARD; + maWriteIndex = 0; + maReadIndex = 0; + } + + dxvertex *vertices(NULL); + const std::size_t nNumVertices( + std::min(maNumVertices - maWriteIndex, + nSize)); + if(FAILED(mpVertexBuffer->Lock(maWriteIndex*nVertexStride, + nNumVertices*nVertexStride, + (void **)&vertices, + dwLockFlags))) + return; + + std::size_t nIndex(0); + while( nIndex < nNumVertices ) + { + dxvertex &dest = vertices[nIndex++]; + dest.x=it->x; + dest.y=it->y; + dest.z=it->z; + dest.rhw=1; + const sal_uInt32 alpha(static_cast<sal_uInt32>(it->a*255.0f)); + dest.diffuse=D3DCOLOR_ARGB(alpha,255,255,255); + dest.u=static_cast<float>(it->u + nHalfPixelSizeX); + dest.v=static_cast<float>(it->v + nHalfPixelSizeY); + ++it; + } + + mpVertexBuffer->Unlock(); + + // Advance to the next position in the vertex buffer. + maWriteIndex += nNumVertices; + nSize -= nNumVertices; + + commitVertexCache(); + } + + maVertexCache.clear(); + } + } + + ////////////////////////////////////////////////////////////////////////////////// + // createRenderModule + ////////////////////////////////////////////////////////////////////////////////// + + IDXRenderModuleSharedPtr createRenderModule( const ::Window& rParent ) + { + return IDXRenderModuleSharedPtr( new DXRenderModule(rParent) ); + } +} + +#endif diff --git a/canvas/source/directx/dx_bitmap.cxx b/canvas/source/directx/dx_bitmap.cxx new file mode 100755 index 000000000000..7f2af1020bca --- /dev/null +++ b/canvas/source/directx/dx_bitmap.cxx @@ -0,0 +1,222 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_bitmap.cxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include "dx_bitmap.hxx" +#include "dx_graphicsprovider.hxx" +#include "dx_impltools.hxx" + +#include <canvas/debug.hxx> +#include <tools/diagnose_ex.h> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/range/b2irange.hxx> + +#if defined(DX_DEBUG_IMAGES) +# if OSL_DEBUG_LEVEL > 0 +# include <imdebug.h> +# undef min +# undef max +# endif +#endif + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + ////////////////////////////////////////////////////////////////////////////////// + // DXBitmap::DXBitmap + ////////////////////////////////////////////////////////////////////////////////// + + DXBitmap::DXBitmap( const BitmapSharedPtr& rBitmap, + bool bWithAlpha ) : + mpGdiPlusUser( GDIPlusUser::createInstance() ), + maSize(rBitmap->GetWidth(),rBitmap->GetHeight()), + mpBitmap(rBitmap), + mpGraphics(tools::createGraphicsFromBitmap(mpBitmap)), + mbAlpha(bWithAlpha) + { + } + + DXBitmap::DXBitmap( const ::basegfx::B2IVector& rSize, + bool bWithAlpha ) : + mpGdiPlusUser( GDIPlusUser::createInstance() ), + maSize(rSize), + mpBitmap(), + mpGraphics(), + mbAlpha(bWithAlpha) + { + // create container for pixel data + if(mbAlpha) + { + mpBitmap.reset( + new Gdiplus::Bitmap( + maSize.getX(), + maSize.getY(), + PixelFormat32bppARGB)); + } + else + { + mpBitmap.reset( + new Gdiplus::Bitmap( + maSize.getX(), + maSize.getY(), + PixelFormat24bppRGB)); + } + + mpGraphics.reset( tools::createGraphicsFromBitmap(mpBitmap) ); + } + + BitmapSharedPtr DXBitmap::getBitmap() const + { + return mpBitmap; + } + + GraphicsSharedPtr DXBitmap::getGraphics() + { + return mpGraphics; + } + + ::basegfx::B2IVector DXBitmap::getSize() const + { + return maSize; + } + + bool DXBitmap::hasAlpha() const + { + return mbAlpha; + } + + uno::Sequence< sal_Int8 > DXBitmap::getData( rendering::IntegerBitmapLayout& /*bitmapLayout*/, + const geometry::IntegerRectangle2D& rect ) + { + uno::Sequence< sal_Int8 > aRes( (rect.X2-rect.X1)*(rect.Y2-rect.Y1)*4 ); // TODO(F1): Be format-agnostic here + + const Gdiplus::Rect aRect( tools::gdiPlusRectFromIntegerRectangle2D( rect ) ); + + Gdiplus::BitmapData aBmpData; + aBmpData.Width = rect.X2-rect.X1; + aBmpData.Height = rect.Y2-rect.Y1; + aBmpData.Stride = 4*aBmpData.Width; + aBmpData.PixelFormat = PixelFormat32bppARGB; + aBmpData.Scan0 = aRes.getArray(); + + // TODO(F1): Support more pixel formats natively + + // read data from bitmap + if( Gdiplus::Ok != mpBitmap->LockBits( &aRect, + Gdiplus::ImageLockModeRead | Gdiplus::ImageLockModeUserInputBuf, + PixelFormat32bppARGB, // TODO(F1): Adapt to + // Graphics native + // format/change + // getMemoryLayout + &aBmpData ) ) + { + // failed to lock, bail out + return uno::Sequence< sal_Int8 >(); + } + + mpBitmap->UnlockBits( &aBmpData ); + + return aRes; + } + + void DXBitmap::setData( const uno::Sequence< sal_Int8 >& data, + const rendering::IntegerBitmapLayout& /*bitmapLayout*/, + const geometry::IntegerRectangle2D& rect ) + { + const Gdiplus::Rect aRect( tools::gdiPlusRectFromIntegerRectangle2D( rect ) ); + + Gdiplus::BitmapData aBmpData; + aBmpData.Width = rect.X2-rect.X1; + aBmpData.Height = rect.Y2-rect.Y1; + aBmpData.Stride = 4*aBmpData.Width; + aBmpData.PixelFormat = PixelFormat32bppARGB; + aBmpData.Scan0 = (void*)data.getConstArray(); + + // TODO(F1): Support more pixel formats natively + + if( Gdiplus::Ok != mpBitmap->LockBits( &aRect, + Gdiplus::ImageLockModeWrite | Gdiplus::ImageLockModeUserInputBuf, + PixelFormat32bppARGB, // TODO: Adapt to + // Graphics native + // format/change + // getMemoryLayout + &aBmpData ) ) + { + throw uno::RuntimeException(); + } + + // commit data to bitmap + mpBitmap->UnlockBits( &aBmpData ); + } + + void DXBitmap::setPixel( const uno::Sequence< sal_Int8 >& color, + const rendering::IntegerBitmapLayout& /*bitmapLayout*/, + const geometry::IntegerPoint2D& pos ) + { + const geometry::IntegerSize2D aSize( maSize.getX(),maSize.getY() ); + + ENSURE_ARG_OR_THROW( pos.X >= 0 && pos.X < aSize.Width, + "CanvasHelper::setPixel: X coordinate out of bounds" ); + ENSURE_ARG_OR_THROW( pos.Y >= 0 && pos.Y < aSize.Height, + "CanvasHelper::setPixel: Y coordinate out of bounds" ); + ENSURE_ARG_OR_THROW( color.getLength() > 3, + "CanvasHelper::setPixel: not enough color components" ); + + if( Gdiplus::Ok != mpBitmap->SetPixel( pos.X, pos.Y, + Gdiplus::Color( tools::sequenceToArgb( color )))) + { + throw uno::RuntimeException(); + } + } + + uno::Sequence< sal_Int8 > DXBitmap::getPixel( rendering::IntegerBitmapLayout& /*bitmapLayout*/, + const geometry::IntegerPoint2D& pos ) + { + const geometry::IntegerSize2D aSize( maSize.getX(),maSize.getY() ); + + ENSURE_ARG_OR_THROW( pos.X >= 0 && pos.X < aSize.Width, + "CanvasHelper::getPixel: X coordinate out of bounds" ); + ENSURE_ARG_OR_THROW( pos.Y >= 0 && pos.Y < aSize.Height, + "CanvasHelper::getPixel: Y coordinate out of bounds" ); + + Gdiplus::Color aColor; + + if( Gdiplus::Ok != mpBitmap->GetPixel( pos.X, pos.Y, &aColor ) ) + return uno::Sequence< sal_Int8 >(); + + return tools::argbToIntSequence(aColor.GetValue()); + } + +} + diff --git a/canvas/source/directx/dx_bitmap.hxx b/canvas/source/directx/dx_bitmap.hxx new file mode 100755 index 000000000000..1745e3d4f779 --- /dev/null +++ b/canvas/source/directx/dx_bitmap.hxx @@ -0,0 +1,96 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_bitmap.hxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _DXCANVAS_DXBITMAP_HXX +#define _DXCANVAS_DXBITMAP_HXX + +#include <com/sun/star/rendering/XCanvas.hpp> +#include <com/sun/star/rendering/XIntegerBitmap.hpp> +#include <boost/shared_ptr.hpp> +#include <basegfx/vector/b2ivector.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/range/b2drange.hxx> +#include "dx_winstuff.hxx" +#include "dx_ibitmap.hxx" +#include "dx_graphicsprovider.hxx" +#include "dx_gdiplususer.hxx" + +namespace dxcanvas +{ + class DXBitmap : public IBitmap + { + public: + DXBitmap( const BitmapSharedPtr& rBitmap, + bool bWithAlpha ); + DXBitmap( const ::basegfx::B2IVector& rSize, + bool bWithAlpha ); + + virtual GraphicsSharedPtr getGraphics(); + + virtual BitmapSharedPtr getBitmap() const; + virtual ::basegfx::B2IVector getSize() const; + virtual bool hasAlpha() const; + + ::com::sun::star::uno::Sequence< sal_Int8 > getData( + ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout, + const ::com::sun::star::geometry::IntegerRectangle2D& rect ); + + void setData( + const ::com::sun::star::uno::Sequence< sal_Int8 >& data, + const ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout, + const ::com::sun::star::geometry::IntegerRectangle2D& rect ); + + void setPixel( + const ::com::sun::star::uno::Sequence< sal_Int8 >& color, + const ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout, + const ::com::sun::star::geometry::IntegerPoint2D& pos ); + + ::com::sun::star::uno::Sequence< sal_Int8 > getPixel( + ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout, + const ::com::sun::star::geometry::IntegerPoint2D& pos ); + + private: + // Refcounted global GDI+ state container + GDIPlusUserSharedPtr mpGdiPlusUser; + + // size of this image in pixels [integral unit] + ::basegfx::B2IVector maSize; + + BitmapSharedPtr mpBitmap; + GraphicsSharedPtr mpGraphics; + + // true if the bitmap contains an alpha channel + bool mbAlpha; + }; + + typedef ::boost::shared_ptr< DXBitmap > DXBitmapSharedPtr; +} + +#endif diff --git a/canvas/source/directx/dx_bitmapcanvashelper.cxx b/canvas/source/directx/dx_bitmapcanvashelper.cxx new file mode 100755 index 000000000000..467b91dec1d7 --- /dev/null +++ b/canvas/source/directx/dx_bitmapcanvashelper.cxx @@ -0,0 +1,249 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_bitmapcanvashelper.cxx,v $ + * $Revision: 1.2 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <canvas/debug.hxx> +#include <tools/diagnose_ex.h> + +#include <rtl/logfile.hxx> +#include <rtl/math.hxx> + +#include <com/sun/star/rendering/TexturingMode.hpp> +#include <com/sun/star/rendering/CompositeOperation.hpp> +#include <com/sun/star/rendering/RepaintResult.hpp> +#include <com/sun/star/rendering/PathCapType.hpp> +#include <com/sun/star/rendering/PathJoinType.hpp> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/tools/canvastools.hxx> + +#include <comphelper/sequence.hxx> +#include <canvas/canvastools.hxx> + +#include "dx_spritecanvas.hxx" +#include "dx_impltools.hxx" +#include "dx_canvasfont.hxx" +#include "dx_textlayout.hxx" +#include "dx_bitmapcanvashelper.hxx" + +#include <algorithm> + + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + BitmapCanvasHelper::BitmapCanvasHelper() : + mpTarget() + {} + + void BitmapCanvasHelper::disposing() + { + mpTarget.reset(); + CanvasHelper::disposing(); + } + + void BitmapCanvasHelper::setTarget( const IBitmapSharedPtr& rTarget ) + { + ENSURE_OR_THROW( rTarget, + "BitmapCanvasHelper::setTarget(): Invalid target" ); + ENSURE_OR_THROW( !mpTarget.get(), + "BitmapCanvasHelper::setTarget(): target set, old target would be overwritten" ); + + mpTarget = rTarget; + CanvasHelper::setTarget(rTarget); + } + + void BitmapCanvasHelper::setTarget( const IBitmapSharedPtr& rTarget, + const ::basegfx::B2ISize& rOutputOffset ) + { + ENSURE_OR_THROW( rTarget, + "BitmapCanvasHelper::setTarget(): invalid target" ); + ENSURE_OR_THROW( !mpTarget.get(), + "BitmapCanvasHelper::setTarget(): target set, old target would be overwritten" ); + + mpTarget = rTarget; + CanvasHelper::setTarget(rTarget,rOutputOffset); + } + + void BitmapCanvasHelper::clear() + { + if( needOutput() ) + { + GraphicsSharedPtr pGraphics( mpTarget->getGraphics() ); + + Gdiplus::Color aClearColor = hasAlpha() ? + Gdiplus::Color( 0,255,255,255 ) : Gdiplus::Color((Gdiplus::ARGB)Gdiplus::Color::White); + + ENSURE_OR_THROW( + Gdiplus::Ok == pGraphics->SetCompositingMode( + Gdiplus::CompositingModeSourceCopy ), // force set, don't blend + "BitmapCanvasHelper::clear(): GDI+ SetCompositingMode call failed" ); + ENSURE_OR_THROW( + Gdiplus::Ok == pGraphics->Clear( aClearColor ), + "BitmapCanvasHelper::clear(): GDI+ Clear call failed" ); + } + } + + uno::Reference< rendering::XCachedPrimitive > BitmapCanvasHelper::drawTextLayout( const rendering::XCanvas* /*pCanvas*/, + const uno::Reference< rendering::XTextLayout >& xLayoutetText, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + ENSURE_OR_THROW( xLayoutetText.is(), + "BitmapCanvasHelper::drawTextLayout: layout is NULL"); + + if( needOutput() ) + { + TextLayout* pTextLayout = + dynamic_cast< TextLayout* >( xLayoutetText.get() ); + + ENSURE_OR_THROW( pTextLayout, + "BitmapCanvasHelper::drawTextLayout(): TextLayout not compatible with this canvas" ); + + pTextLayout->draw( mpTarget->getGraphics(), + viewState, + renderState, + maOutputOffset, + mpDevice, + mpTarget->hasAlpha() ); + } + + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + void BitmapCanvasHelper::copyRect( const rendering::XCanvas* /*pCanvas*/, + const uno::Reference< rendering::XBitmapCanvas >& /*sourceCanvas*/, + const geometry::RealRectangle2D& /*sourceRect*/, + const rendering::ViewState& /*sourceViewState*/, + const rendering::RenderState& /*sourceRenderState*/, + const geometry::RealRectangle2D& /*destRect*/, + const rendering::ViewState& /*destViewState*/, + const rendering::RenderState& /*destRenderState*/ ) + { + // TODO(F2): copyRect NYI + } + + geometry::IntegerSize2D BitmapCanvasHelper::getSize() + { + if( !mpTarget ) + return geometry::IntegerSize2D(1, 1); + + return basegfx::unotools::integerSize2DFromB2ISize(mpTarget->getSize()); + } + + uno::Reference< rendering::XBitmap > BitmapCanvasHelper::getScaledBitmap( const geometry::RealSize2D& /*newSize*/, + sal_Bool /*beFast*/ ) + { + // TODO(F1): + return uno::Reference< rendering::XBitmap >(); + } + + uno::Sequence< sal_Int8 > BitmapCanvasHelper::getData( rendering::IntegerBitmapLayout& bitmapLayout, + const geometry::IntegerRectangle2D& rect ) + { + RTL_LOGFILE_CONTEXT( aLog, "::dxcanvas::BitmapCanvasHelper::getData()" ); + + ENSURE_OR_THROW( mpTarget, + "::dxcanvas::BitmapCanvasHelper::getData(): disposed" ); + + if( !mpTarget ) + return uno::Sequence< sal_Int8 >(); + + bitmapLayout = getMemoryLayout(); + return mpTarget->getData(bitmapLayout,rect); + } + + void BitmapCanvasHelper::setData( const uno::Sequence< sal_Int8 >& data, + const rendering::IntegerBitmapLayout& bitmapLayout, + const geometry::IntegerRectangle2D& rect ) + { + RTL_LOGFILE_CONTEXT( aLog, "::dxcanvas::BitmapCanvasHelper::setData()" ); + + ENSURE_OR_THROW( mpTarget, + "::dxcanvas::BitmapCanvasHelper::setData(): disposed" ); + + if( !mpTarget ) + return; + + mpTarget->setData(data,bitmapLayout,rect); + } + + void BitmapCanvasHelper::setPixel( const uno::Sequence< sal_Int8 >& color, + const rendering::IntegerBitmapLayout& bitmapLayout, + const geometry::IntegerPoint2D& pos ) + { + RTL_LOGFILE_CONTEXT( aLog, "::dxcanvas::BitmapCanvasHelper::setPixel()" ); + + ENSURE_OR_THROW( mpTarget, + "::dxcanvas::BitmapCanvasHelper::setPixel(): disposed" ); + + if( !mpTarget ) + return; + + mpTarget->setPixel(color,bitmapLayout,pos); + } + + uno::Sequence< sal_Int8 > BitmapCanvasHelper::getPixel( rendering::IntegerBitmapLayout& bitmapLayout, + const geometry::IntegerPoint2D& pos ) + { + RTL_LOGFILE_CONTEXT( aLog, "::dxcanvas::BitmapCanvasHelper::getPixel()" ); + + ENSURE_OR_THROW( mpTarget, + "::dxcanvas::BitmapCanvasHelper::getPixel(): disposed" ); + + if( !mpTarget ) + return uno::Sequence< sal_Int8 >(); + + bitmapLayout = getMemoryLayout(); + return mpTarget->getPixel(bitmapLayout,pos); + } + + uno::Reference< rendering::XBitmapPalette > BitmapCanvasHelper::getPalette() + { + // TODO(F1): Palette bitmaps NYI + return uno::Reference< rendering::XBitmapPalette >(); + } + + rendering::IntegerBitmapLayout BitmapCanvasHelper::getMemoryLayout() + { + if( !mpTarget ) + return rendering::IntegerBitmapLayout(); // we're disposed + + return ::canvas::tools::getStdMemoryLayout(getSize()); + } + bool BitmapCanvasHelper::hasAlpha() const + { + return mpTarget ? mpTarget->hasAlpha() : false; + } +} diff --git a/canvas/source/directx/dx_bitmapcanvashelper.hxx b/canvas/source/directx/dx_bitmapcanvashelper.hxx new file mode 100755 index 000000000000..6291adefc707 --- /dev/null +++ b/canvas/source/directx/dx_bitmapcanvashelper.hxx @@ -0,0 +1,139 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_bitmapcanvashelper.hxx,v $ + * $Revision: 1.2 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _DXCANVAS_BITMAPCANVASHELPER_HXX_ +#define _DXCANVAS_BITMAPCANVASHELPER_HXX_ + +#include <com/sun/star/rendering/XCanvas.hpp> + +#include <basegfx/vector/b2isize.hxx> +#include <basegfx/vector/b2dsize.hxx> + +#include "dx_graphicsprovider.hxx" +#include "dx_ibitmap.hxx" +#include "dx_gdiplususer.hxx" +#include "dx_impltools.hxx" +#include "dx_canvashelper.hxx" + +#include <boost/utility.hpp> + + +namespace dxcanvas +{ + /** Helper class for basic canvas functionality. Also offers + optional backbuffer painting, when providing it with a second + HDC to render into. + */ + class BitmapCanvasHelper : public CanvasHelper + { + public: + BitmapCanvasHelper(); + + /// Release all references + void disposing(); + + /** Set the target for rendering operations + + @param rTarget + Render target + */ + void setTarget( const IBitmapSharedPtr& rTarget ); + + /** Set the target for rendering operations + + @param rTarget + Render target + + @param rOutputOffset + Output offset in pixel + */ + void setTarget( const IBitmapSharedPtr& rTarget, + const ::basegfx::B2ISize& rOutputOffset ); + + + // CanvasHelper functionality is implementation-inherited. yuck. + // ============================================================= + void clear(); + + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive > + drawTextLayout( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XTextLayout >& layoutetText, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + + // BitmapCanvasHelper functionality + // ================================ + + void copyRect( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XBitmapCanvas >& sourceCanvas, + const ::com::sun::star::geometry::RealRectangle2D& sourceRect, + const ::com::sun::star::rendering::ViewState& sourceViewState, + const ::com::sun::star::rendering::RenderState& sourceRenderState, + const ::com::sun::star::geometry::RealRectangle2D& destRect, + const ::com::sun::star::rendering::ViewState& destViewState, + const ::com::sun::star::rendering::RenderState& destRenderState ); + + ::com::sun::star::geometry::IntegerSize2D getSize(); + + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmap > + getScaledBitmap( const ::com::sun::star::geometry::RealSize2D& newSize, + sal_Bool beFast ); + + ::com::sun::star::uno::Sequence< sal_Int8 > + getData( ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout, + const ::com::sun::star::geometry::IntegerRectangle2D& rect ); + + void setData( const ::com::sun::star::uno::Sequence< sal_Int8 >& data, + const ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout, + const ::com::sun::star::geometry::IntegerRectangle2D& rect ); + + void setPixel( const ::com::sun::star::uno::Sequence< sal_Int8 >& color, + const ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout, + const ::com::sun::star::geometry::IntegerPoint2D& pos ); + + ::com::sun::star::uno::Sequence< sal_Int8 > + getPixel( ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout, + const ::com::sun::star::geometry::IntegerPoint2D& pos ); + + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmapPalette > getPalette(); + + ::com::sun::star::rendering::IntegerBitmapLayout getMemoryLayout(); + + bool hasAlpha() const; + + protected: + /// Render target + IBitmapSharedPtr mpTarget; + }; +} + +#endif /* _DXCANVAS_BITMAPCANVASHELPER_HXX_ */ diff --git a/canvas/source/directx/dx_bitmapprovider.hxx b/canvas/source/directx/dx_bitmapprovider.hxx new file mode 100644 index 000000000000..09147eebcf8d --- /dev/null +++ b/canvas/source/directx/dx_bitmapprovider.hxx @@ -0,0 +1,48 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_bitmapprovider.hxx,v $ + * $Revision: 1.2 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _DXCANVAS_BITMAPPROVIDER_HXX_ +#define _DXCANVAS_BITMAPPROVIDER_HXX_ + +#include "dx_ibitmap.hxx" +#include <boost/shared_ptr.hpp> + +namespace dxcanvas +{ + struct BitmapProvider + { + virtual ~BitmapProvider() {} + virtual IBitmapSharedPtr getBitmap() const = 0; + }; + + typedef boost::shared_ptr<BitmapProvider> BitmapProviderSharedPtr; +} + +#endif diff --git a/canvas/source/directx/dx_canvas.cxx b/canvas/source/directx/dx_canvas.cxx new file mode 100644 index 000000000000..26dd88b0b538 --- /dev/null +++ b/canvas/source/directx/dx_canvas.cxx @@ -0,0 +1,258 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_canvas.cxx,v $ + * $Revision: 1.3 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <ctype.h> // don't ask. msdev breaks otherwise... +#include <canvas/debug.hxx> +#include <canvas/verbosetrace.hxx> +#include <canvas/canvastools.hxx> +#include <tools/diagnose_ex.h> + +#include <osl/mutex.hxx> + +#include <com/sun/star/awt/XWindow.hpp> +#include <com/sun/star/awt/XSystemDependentWindowPeer.hpp> +#include <com/sun/star/registry/XRegistryKey.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/lang/NoSupportException.hpp> + +#include <toolkit/helper/vclunohelper.hxx> +#include <cppuhelper/factory.hxx> +#include <cppuhelper/implementationentry.hxx> +#include <comphelper/servicedecl.hxx> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/numeric/ftools.hxx> + +#include "dx_graphicsprovider.hxx" +#include "dx_winstuff.hxx" +#include "dx_canvas.hxx" + +#include <vcl/sysdata.hxx> + +#define CANVAS_TECH "GDI+" +#define CANVAS_SERVICE_NAME "com.sun.star.rendering.Canvas." CANVAS_TECH +#define CANVAS_IMPLEMENTATION_NAME "com.sun.star.comp.rendering.Canvas." CANVAS_TECH +#define BITMAPCANVAS_SERVICE_NAME "com.sun.star.rendering.BitmapCanvas." CANVAS_TECH +#define BITMAPCANVAS_IMPLEMENTATION_NAME "com.sun.star.comp.rendering.BitmapCanvas." CANVAS_TECH + + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + /// Actual canonical implementation of the GraphicsProvider interface + class GraphicsProviderImpl : public GraphicsProvider + { + GraphicsSharedPtr mpGraphics; + public: + explicit GraphicsProviderImpl( Gdiplus::Graphics* pGraphics ) : mpGraphics( pGraphics ) {} + virtual GraphicsSharedPtr getGraphics() { return mpGraphics; } + }; + + Canvas::Canvas( const uno::Sequence< uno::Any >& aArguments, + const uno::Reference< uno::XComponentContext >& rxContext ) : + maArguments(aArguments), + mxComponentContext( rxContext ) + { + } + + void Canvas::initialize() + { + // #i64742# Only perform initialization when not in probe mode + if( maArguments.getLength() == 0 ) + return; + + VERBOSE_TRACE( "Canvas::initialize called" ); + + // At index 1, we expect a HWND handle here, containing a + // pointer to a valid window, on which to output + // At index 2, we expect the current window bound rect + ENSURE_ARG_OR_THROW( maArguments.getLength() >= 6 && + maArguments[5].getValueTypeClass() == uno::TypeClass_SEQUENCE, + "SpriteCanvas::initialize: wrong number of arguments, or wrong types" ); + + uno::Sequence<sal_Int8> aSeq; + maArguments[5] >>= aSeq; + + const SystemGraphicsData* pSysData=reinterpret_cast<const SystemGraphicsData*>(aSeq.getConstArray()); + if( !pSysData || !pSysData->hDC ) + throw lang::NoSupportException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "Passed SystemGraphicsData or HDC invalid!")), + NULL); + + // setup helper + maDeviceHelper.init( pSysData->hDC, + *this ); + maCanvasHelper.setDevice( *this ); + maCanvasHelper.setTarget( + GraphicsProviderSharedPtr( + new GraphicsProviderImpl( + Gdiplus::Graphics::FromHDC(pSysData->hDC)))); + + maArguments.realloc(0); + } + + void SAL_CALL Canvas::disposing() + { + ::osl::MutexGuard aGuard( m_aMutex ); + + mxComponentContext.clear(); + + // forward to parent + CanvasBaseT::disposing(); + } + + ::rtl::OUString SAL_CALL Canvas::getServiceName( ) throw (uno::RuntimeException) + { + return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( CANVAS_SERVICE_NAME ) ); + } + + BitmapCanvas::BitmapCanvas( const uno::Sequence< uno::Any >& aArguments, + const uno::Reference< uno::XComponentContext >& rxContext ) : + maArguments(aArguments), + mxComponentContext( rxContext ), + mpTarget() + { + } + + void BitmapCanvas::initialize() + { + // #i64742# Only perform initialization when not in probe mode + if( maArguments.getLength() == 0 ) + return; + + VERBOSE_TRACE( "BitmapCanvas::initialize called" ); + + // At index 1, we expect a HWND handle here, containing a + // pointer to a valid window, on which to output + // At index 2, we expect the current window bound rect + ENSURE_ARG_OR_THROW( maArguments.getLength() >= 6 && + maArguments[5].getValueTypeClass() == uno::TypeClass_SEQUENCE, + "SpriteCanvas::initialize: wrong number of arguments, or wrong types" ); + + uno::Sequence<sal_Int8> aSeq; + maArguments[5] >>= aSeq; + + const SystemGraphicsData* pSysData=reinterpret_cast<const SystemGraphicsData*>(aSeq.getConstArray()); + if( !pSysData || !pSysData->hDC ) + throw lang::NoSupportException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "Passed SystemGraphicsData or HDC invalid!")), + NULL); + + // setup helper + maDeviceHelper.init( pSysData->hDC, + *this ); + maCanvasHelper.setDevice( *this ); + + // check whether we can actually provide a BitmapCanvas + // here. for this, check whether the HDC has a bitmap + // selected. + HBITMAP hBmp; + hBmp=(HBITMAP)GetCurrentObject(pSysData->hDC, OBJ_BITMAP); + if( !hBmp || GetObjectType(pSysData->hDC) != OBJ_MEMDC ) + { + throw lang::NoSupportException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "Passed HDC is no mem DC/has no bitmap selected!")), + NULL); + } + + mpTarget.reset( new DXBitmap( + BitmapSharedPtr( + Gdiplus::Bitmap::FromHBITMAP( + hBmp, 0) ), + false )); + + maCanvasHelper.setTarget( mpTarget ); + + maArguments.realloc(0); + } + + void SAL_CALL BitmapCanvas::disposing() + { + ::osl::MutexGuard aGuard( m_aMutex ); + + mpTarget.reset(); + mxComponentContext.clear(); + + // forward to parent + BitmapCanvasBaseT::disposing(); + } + + ::rtl::OUString SAL_CALL BitmapCanvas::getServiceName( ) throw (uno::RuntimeException) + { + return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( BITMAPCANVAS_SERVICE_NAME ) ); + } + + IBitmapSharedPtr BitmapCanvas::getBitmap() const + { + return mpTarget; + } + + static uno::Reference<uno::XInterface> initCanvas( Canvas* pCanvas ) + { + uno::Reference<uno::XInterface> xRet(static_cast<cppu::OWeakObject*>(pCanvas)); + pCanvas->initialize(); + return xRet; + } + + namespace sdecl = comphelper::service_decl; + sdecl::class_<Canvas, sdecl::with_args<true> > serviceImpl1(&initCanvas); + const sdecl::ServiceDecl dxCanvasDecl( + serviceImpl1, + CANVAS_IMPLEMENTATION_NAME, + CANVAS_SERVICE_NAME ); + + static uno::Reference<uno::XInterface> initBitmapCanvas( BitmapCanvas* pCanvas ) + { + uno::Reference<uno::XInterface> xRet(static_cast<cppu::OWeakObject*>(pCanvas)); + pCanvas->initialize(); + return xRet; + } + + namespace sdecl = comphelper::service_decl; + sdecl::class_<BitmapCanvas, sdecl::with_args<true> > serviceImpl2(&initBitmapCanvas); + const sdecl::ServiceDecl dxBitmapCanvasDecl( + serviceImpl2, + BITMAPCANVAS_IMPLEMENTATION_NAME, + BITMAPCANVAS_SERVICE_NAME ); +} + +// The C shared lib entry points +COMPHELPER_SERVICEDECL_EXPORTS2(dxcanvas::dxCanvasDecl, + dxcanvas::dxBitmapCanvasDecl); diff --git a/canvas/source/directx/dx_canvas.hxx b/canvas/source/directx/dx_canvas.hxx new file mode 100644 index 000000000000..ab2aa398757d --- /dev/null +++ b/canvas/source/directx/dx_canvas.hxx @@ -0,0 +1,179 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_canvas.hxx,v $ + * $Revision: 1.2 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _DXCANVAS_CANVAS_HXX_ +#define _DXCANVAS_CANVAS_HXX_ + +#include <rtl/ref.hxx> + +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/lang/XServiceName.hpp> +#include <com/sun/star/util/XUpdatable.hpp> +#include <com/sun/star/rendering/XBitmapCanvas.hpp> +#include <com/sun/star/rendering/XIntegerBitmap.hpp> +#include <com/sun/star/rendering/XGraphicDevice.hpp> +#include <com/sun/star/rendering/XBufferController.hpp> +#include <com/sun/star/rendering/XParametricPolyPolygon2DFactory.hpp> + +#include <cppuhelper/compbase7.hxx> +#include <cppuhelper/compbase6.hxx> +#include <comphelper/uno3.hxx> + +#include <canvas/base/integerbitmapbase.hxx> +#include <canvas/base/basemutexhelper.hxx> +#include <canvas/base/graphicdevicebase.hxx> + +#include "dx_bitmapprovider.hxx" +#include "dx_canvashelper.hxx" +#include "dx_bitmapcanvashelper.hxx" +#include "dx_impltools.hxx" +#include "dx_devicehelper.hxx" + + +namespace dxcanvas +{ + typedef ::cppu::WeakComponentImplHelper6< ::com::sun::star::rendering::XCanvas, + ::com::sun::star::rendering::XGraphicDevice, + ::com::sun::star::rendering::XParametricPolyPolygon2DFactory, + ::com::sun::star::util::XUpdatable, + ::com::sun::star::beans::XPropertySet, + ::com::sun::star::lang::XServiceName > GraphicDeviceBase1_Base; + typedef ::canvas::GraphicDeviceBase< ::canvas::BaseMutexHelper< GraphicDeviceBase1_Base >, + DeviceHelper, + ::osl::MutexGuard, + ::cppu::OWeakObject > CanvasBase1_Base; + typedef ::canvas::CanvasBase< CanvasBase1_Base, + CanvasHelper, + ::osl::MutexGuard, + ::cppu::OWeakObject > CanvasBaseT; + + /** Product of this component's factory. + + The Canvas object combines the actual Window canvas with + the XGraphicDevice interface. This is because there's a + one-to-one relation between them, anyway, since each window + can have exactly one canvas and one associated + XGraphicDevice. And to avoid messing around with circular + references, this is implemented as one single object. + */ + class Canvas : public CanvasBaseT + { + public: + Canvas( const ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Any >& aArguments, + const ::com::sun::star::uno::Reference< + ::com::sun::star::uno::XComponentContext >& rxContext ); + + void initialize(); + + /// Dispose all internal references + virtual void SAL_CALL disposing(); + + // Forwarding the XComponent implementation to the + // cppu::ImplHelper templated base + // Classname Base doing refcounting Base implementing the XComponent interface + // | | | + // V V V + DECLARE_UNO3_XCOMPONENT_AGG_DEFAULTS( Canvas, GraphicDeviceBase1_Base, ::cppu::WeakComponentImplHelperBase ); + + // XServiceName + virtual ::rtl::OUString SAL_CALL getServiceName( ) throw (::com::sun::star::uno::RuntimeException); + + private: + ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > maArguments; + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > mxComponentContext; + }; + + typedef ::rtl::Reference< Canvas > CanvasRef; + + ////////////////////////////////////////////////////////////////////////////////////////////////////// + + typedef ::cppu::WeakComponentImplHelper7< ::com::sun::star::rendering::XBitmapCanvas, + ::com::sun::star::rendering::XIntegerBitmap, + ::com::sun::star::rendering::XGraphicDevice, + ::com::sun::star::rendering::XParametricPolyPolygon2DFactory, + ::com::sun::star::util::XUpdatable, + ::com::sun::star::beans::XPropertySet, + ::com::sun::star::lang::XServiceName > GraphicDeviceBase2_Base; + typedef ::canvas::GraphicDeviceBase< ::canvas::BaseMutexHelper< GraphicDeviceBase2_Base >, + DeviceHelper, + ::osl::MutexGuard, + ::cppu::OWeakObject > CanvasBase2_Base; + typedef ::canvas::IntegerBitmapBase< CanvasBase2_Base, + BitmapCanvasHelper, + ::osl::MutexGuard, + ::cppu::OWeakObject > BitmapCanvasBaseT; + + /** Product of this component's factory. + + The Canvas object combines the actual Window canvas with + the XGraphicDevice interface. This is because there's a + one-to-one relation between them, anyway, since each window + can have exactly one canvas and one associated + XGraphicDevice. And to avoid messing around with circular + references, this is implemented as one single object. + */ + class BitmapCanvas : public BitmapCanvasBaseT, public BitmapProvider + { + public: + BitmapCanvas( const ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Any >& aArguments, + const ::com::sun::star::uno::Reference< + ::com::sun::star::uno::XComponentContext >& rxContext ); + + void initialize(); + + /// Dispose all internal references + virtual void SAL_CALL disposing(); + + // Forwarding the XComponent implementation to the + // cppu::ImplHelper templated base + // Classname Base doing refcounting Base implementing the XComponent interface + // | | | + // V V V + DECLARE_UNO3_XCOMPONENT_AGG_DEFAULTS( BitmapCanvas, GraphicDeviceBase2_Base, ::cppu::WeakComponentImplHelperBase ); + + // XServiceName + virtual ::rtl::OUString SAL_CALL getServiceName( ) throw (::com::sun::star::uno::RuntimeException); + + // BitmapProvider + virtual IBitmapSharedPtr getBitmap() const; + + private: + ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > maArguments; + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > mxComponentContext; + IBitmapSharedPtr mpTarget; + }; + + typedef ::rtl::Reference< BitmapCanvas > BitmapCanvasRef; +} + +#endif diff --git a/canvas/source/directx/dx_canvasbitmap.cxx b/canvas/source/directx/dx_canvasbitmap.cxx new file mode 100755 index 000000000000..5e4b61e6d104 --- /dev/null +++ b/canvas/source/directx/dx_canvasbitmap.cxx @@ -0,0 +1,280 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_canvasbitmap.cxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <ctype.h> // don't ask. msdev breaks otherwise... +#include <canvas/debug.hxx> +#include <canvas/canvastools.hxx> +#include <tools/diagnose_ex.h> + +#include <vcl/bitmapex.hxx> + +#include <boost/preprocessor/repetition.hpp> +#include <boost/preprocessor/iteration/local.hpp> +#include <boost/scoped_array.hpp> + +#include "dx_canvasbitmap.hxx" +#include "dx_impltools.hxx" + + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + CanvasBitmap::CanvasBitmap( const IBitmapSharedPtr& rBitmap, + const DeviceRef& rDevice ) : + mpDevice( rDevice ), + mpBitmap( rBitmap ) + { + ENSURE_OR_THROW( mpDevice.is() && mpBitmap, + "CanvasBitmap::CanvasBitmap(): Invalid surface or device" ); + + maCanvasHelper.setDevice( *mpDevice.get() ); + maCanvasHelper.setTarget( mpBitmap ); + } + + void SAL_CALL CanvasBitmap::disposing() + { + mpBitmap.reset(); + mpDevice.clear(); + + // forward to parent + CanvasBitmap_Base::disposing(); + } + + struct AlphaDIB + { + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[256]; + }; + + uno::Any SAL_CALL CanvasBitmap::getFastPropertyValue( sal_Int32 nHandle ) throw (uno::RuntimeException) + { + uno::Any aRes; + // 0 ... get BitmapEx + // 1 ... get Pixbuf with bitmap RGB content + // 2 ... get Pixbuf with bitmap alpha mask + switch( nHandle ) + { + // sorry, no BitmapEx here... + case 0: + aRes = ::com::sun::star::uno::Any( reinterpret_cast<sal_Int64>( (BitmapEx*) NULL ) ); + break; + + case 1: + { + if(!mpBitmap->hasAlpha()) + { + HBITMAP aHBmp; + mpBitmap->getBitmap()->GetHBITMAP(Gdiplus::Color(), &aHBmp ); + + uno::Sequence< uno::Any > args(1); + args[0] = uno::Any( sal_Int64(aHBmp) ); + + aRes <<= args; + } + else + { + // need to copy&convert the bitmap, since dx + // canvas uses inline alpha channel + HDC hScreenDC=GetDC(NULL); + const basegfx::B2IVector aSize(mpBitmap->getSize()); + HBITMAP hBmpBitmap = CreateCompatibleBitmap( hScreenDC, + aSize.getX(), + aSize.getY() ); + if( !hBmpBitmap ) + return aRes; + + BITMAPINFOHEADER aBIH; + + aBIH.biSize = sizeof( BITMAPINFOHEADER ); + aBIH.biWidth = aSize.getX(); + aBIH.biHeight = -aSize.getY(); + aBIH.biPlanes = 1; + aBIH.biBitCount = 32; + aBIH.biCompression = BI_RGB; // expects pixel in + // bbggrrxx format + // (little endian) + aBIH.biSizeImage = 0; + aBIH.biXPelsPerMeter = 0; + aBIH.biYPelsPerMeter = 0; + aBIH.biClrUsed = 0; + aBIH.biClrImportant = 0; + + Gdiplus::BitmapData aBmpData; + aBmpData.Width = aSize.getX(); + aBmpData.Height = aSize.getY(); + aBmpData.Stride = 4*aBmpData.Width; + aBmpData.PixelFormat = PixelFormat32bppARGB; + aBmpData.Scan0 = NULL; + const Gdiplus::Rect aRect( 0,0,aSize.getX(),aSize.getY() ); + BitmapSharedPtr pGDIPlusBitmap=mpBitmap->getBitmap(); + if( Gdiplus::Ok != pGDIPlusBitmap->LockBits( &aRect, + Gdiplus::ImageLockModeRead, + PixelFormat32bppARGB, // outputs ARGB (big endian) + &aBmpData ) ) + { + // failed to lock, bail out + return aRes; + } + + // now aBmpData.Scan0 contains our bits - push + // them into HBITMAP, ignoring alpha + SetDIBits( hScreenDC, hBmpBitmap, 0, aSize.getY(), aBmpData.Scan0, (PBITMAPINFO)&aBIH, DIB_RGB_COLORS ); + + pGDIPlusBitmap->UnlockBits( &aBmpData ); + + uno::Sequence< uno::Any > args(1); + args[0] = uno::Any( sal_Int64(hBmpBitmap) ); + + aRes <<= args; + } + } + break; + + case 2: + { + if(!mpBitmap->hasAlpha()) + { + return aRes; + } + else + { + static AlphaDIB aDIB= + { + {0,0,0,1,8,BI_RGB,0,0,0,0,0}, + { + // this here fills palette with grey + // level colors, starting from 0,0,0 + // up to 255,255,255 +#define BOOST_PP_LOCAL_MACRO(n_) \ + BOOST_PP_COMMA_IF(n_) \ + {n_,n_,n_,n_} +#define BOOST_PP_LOCAL_LIMITS (0, 255) +#include BOOST_PP_LOCAL_ITERATE() + } + }; + + // need to copy&convert the bitmap, since dx + // canvas uses inline alpha channel + HDC hScreenDC=GetDC(NULL); + const basegfx::B2IVector aSize(mpBitmap->getSize()); + HBITMAP hBmpBitmap = CreateCompatibleBitmap( hScreenDC, aSize.getX(), aSize.getY() ); + if( !hBmpBitmap ) + return aRes; + + aDIB.bmiHeader.biSize = sizeof( BITMAPINFOHEADER ); + aDIB.bmiHeader.biWidth = aSize.getX(); + aDIB.bmiHeader.biHeight = -aSize.getY(); + aDIB.bmiHeader.biPlanes = 1; + aDIB.bmiHeader.biBitCount = 8; + aDIB.bmiHeader.biCompression = BI_RGB; + aDIB.bmiHeader.biSizeImage = 0; + aDIB.bmiHeader.biXPelsPerMeter = 0; + aDIB.bmiHeader.biYPelsPerMeter = 0; + aDIB.bmiHeader.biClrUsed = 0; + aDIB.bmiHeader.biClrImportant = 0; + + Gdiplus::BitmapData aBmpData; + aBmpData.Width = aSize.getX(); + aBmpData.Height = aSize.getY(); + aBmpData.Stride = 4*aBmpData.Width; + aBmpData.PixelFormat = PixelFormat32bppARGB; + aBmpData.Scan0 = NULL; + const Gdiplus::Rect aRect( 0,0,aSize.getX(),aSize.getY() ); + BitmapSharedPtr pGDIPlusBitmap=mpBitmap->getBitmap(); + if( Gdiplus::Ok != pGDIPlusBitmap->LockBits( &aRect, + Gdiplus::ImageLockModeRead, + PixelFormat32bppARGB, // outputs ARGB (big endian) + &aBmpData ) ) + { + // failed to lock, bail out + return aRes; + } + + // copy only alpha channel to pAlphaBits + const sal_Int32 nScanWidth((aSize.getX() + 3) & ~3); + boost::scoped_array<sal_uInt8> pAlphaBits( new sal_uInt8[nScanWidth*aSize.getY()] ); + const sal_uInt8* pInBits=(sal_uInt8*)aBmpData.Scan0; + pInBits+=3; + sal_uInt8* pOutBits; + for( sal_Int32 y=0; y<aSize.getY(); ++y ) + { + pOutBits=pAlphaBits.get()+y*nScanWidth; + for( sal_Int32 x=0; x<aSize.getX(); ++x ) + { + *pOutBits++ = 255-*pInBits; + pInBits += 4; + } + } + + pGDIPlusBitmap->UnlockBits( &aBmpData ); + + // set bits to newly create HBITMAP + SetDIBits( hScreenDC, hBmpBitmap, 0, + aSize.getY(), pAlphaBits.get(), + (PBITMAPINFO)&aDIB, DIB_RGB_COLORS ); + + uno::Sequence< uno::Any > args(1); + args[0] = uno::Any( sal_Int64(hBmpBitmap) ); + + aRes <<= args; + } + } + break; + } + + return aRes; + } + +#define IMPLEMENTATION_NAME "DXCanvas.CanvasBitmap" +#define SERVICE_NAME "com.sun.star.rendering.CanvasBitmap" + + ::rtl::OUString SAL_CALL CanvasBitmap::getImplementationName( ) throw (uno::RuntimeException) + { + return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( IMPLEMENTATION_NAME ) ); + } + + sal_Bool SAL_CALL CanvasBitmap::supportsService( const ::rtl::OUString& ServiceName ) throw (uno::RuntimeException) + { + return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( SERVICE_NAME ) ); + } + + uno::Sequence< ::rtl::OUString > SAL_CALL CanvasBitmap::getSupportedServiceNames( ) throw (uno::RuntimeException) + { + uno::Sequence< ::rtl::OUString > aRet(1); + aRet[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME ) ); + + return aRet; + } + +} diff --git a/canvas/source/directx/dx_canvasbitmap.hxx b/canvas/source/directx/dx_canvasbitmap.hxx new file mode 100755 index 000000000000..1d3b223f5827 --- /dev/null +++ b/canvas/source/directx/dx_canvasbitmap.hxx @@ -0,0 +1,107 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_canvasbitmap.hxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _DXCANVAS_CANVASBITMAP_HXX +#define _DXCANVAS_CANVASBITMAP_HXX + +#include <cppuhelper/compbase4.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/rendering/XBitmapCanvas.hpp> +#include <com/sun/star/rendering/XIntegerBitmap.hpp> +#include <com/sun/star/beans/XFastPropertySet.hpp> + +#include <basegfx/vector/b2isize.hxx> + +#include <boost/shared_ptr.hpp> + +#include <cppuhelper/compbase3.hxx> +#include <comphelper/uno3.hxx> +#include <canvas/base/basemutexhelper.hxx> +#include <canvas/base/integerbitmapbase.hxx> + +#include "dx_bitmapprovider.hxx" +#include "dx_bitmapcanvashelper.hxx" +#include "dx_devicehelper.hxx" +#include "dx_impltools.hxx" +#include "dx_ibitmap.hxx" + + +/* Definition of CanvasBitmap class */ + +namespace dxcanvas +{ + typedef ::cppu::WeakComponentImplHelper4< ::com::sun::star::rendering::XBitmapCanvas, + ::com::sun::star::rendering::XIntegerBitmap, + ::com::sun::star::lang::XServiceInfo, + ::com::sun::star::beans::XFastPropertySet > CanvasBitmapBase_Base; + typedef ::canvas::IntegerBitmapBase< ::canvas::BaseMutexHelper< CanvasBitmapBase_Base >, + BitmapCanvasHelper, + ::osl::MutexGuard, + ::cppu::OWeakObject > CanvasBitmap_Base; + + class CanvasBitmap : public CanvasBitmap_Base, public BitmapProvider + { + public: + /** Create a canvas bitmap for the given surface + + @param rSurface + Surface to create API object for. + + @param rDevice + Reference device, with which bitmap should be compatible + */ + CanvasBitmap( const IBitmapSharedPtr& rSurface, + const DeviceRef& rDevice ); + + /// Dispose all internal references + virtual void SAL_CALL disposing(); + + // XServiceInfo + virtual ::rtl::OUString SAL_CALL getImplementationName( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames( ) throw (::com::sun::star::uno::RuntimeException); + + // BitmapProvider + virtual IBitmapSharedPtr getBitmap() const { return mpBitmap; } + + virtual ::com::sun::star::uno::Any SAL_CALL getFastPropertyValue(sal_Int32 nHandle) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setFastPropertyValue(sal_Int32, const ::com::sun::star::uno::Any&) throw (::com::sun::star::uno::RuntimeException) {} + + private: + /** MUST hold here, too, since CanvasHelper only contains a + raw pointer (without refcounting) + */ + DeviceRef mpDevice; + IBitmapSharedPtr mpBitmap; + }; +} + +#endif /* _DXCANVAS_CANVASBITMAP_HXX */ diff --git a/canvas/source/directx/dx_canvascustomsprite.cxx b/canvas/source/directx/dx_canvascustomsprite.cxx new file mode 100755 index 000000000000..a63f7cb74011 --- /dev/null +++ b/canvas/source/directx/dx_canvascustomsprite.cxx @@ -0,0 +1,126 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_canvascustomsprite.cxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <ctype.h> // don't ask. msdev breaks otherwise... +#include <canvas/debug.hxx> +#include <canvas/verbosetrace.hxx> +#include <tools/diagnose_ex.h> + +#include <rtl/logfile.hxx> +#include <rtl/math.hxx> + +#include <canvas/canvastools.hxx> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/point/b2dpoint.hxx> + +#include "dx_canvascustomsprite.hxx" +#include "dx_spritecanvas.hxx" +#include "dx_impltools.hxx" + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + CanvasCustomSprite::CanvasCustomSprite( const ::com::sun::star::geometry::RealSize2D& rSpriteSize, + const SpriteCanvasRef& rRefDevice, + const IDXRenderModuleSharedPtr& rRenderModule, + const ::canvas::ISurfaceProxyManagerSharedPtr& rSurfaceProxy, + bool bShowSpriteBounds ) : + mpSpriteCanvas( rRefDevice ), + mpSurface() + { + ENSURE_OR_THROW( rRefDevice.get(), + "CanvasCustomSprite::CanvasCustomSprite(): Invalid sprite canvas" ); + + mpSurface.reset( + new DXSurfaceBitmap( + ::basegfx::B2IVector( + ::canvas::tools::roundUp( rSpriteSize.Width ), + ::canvas::tools::roundUp( rSpriteSize.Height )), + rSurfaceProxy, + rRenderModule, + true)); + + maCanvasHelper.setDevice( *rRefDevice.get() ); + maCanvasHelper.setTarget( mpSurface ); + + maSpriteHelper.init( rSpriteSize, + rRefDevice, + rRenderModule, + mpSurface, + bShowSpriteBounds ); + + // clear sprite to 100% transparent + maCanvasHelper.clear(); + } + + void SAL_CALL CanvasCustomSprite::disposing() + { + ::osl::MutexGuard aGuard( m_aMutex ); + + mpSurface.reset(); + mpSpriteCanvas.clear(); + + // forward to parent + CanvasCustomSpriteBaseT::disposing(); + } + +#define IMPLEMENTATION_NAME "DXCanvas.CanvasCustomSprite" +#define SERVICE_NAME "com.sun.star.rendering.CanvasCustomSprite" + + ::rtl::OUString SAL_CALL CanvasCustomSprite::getImplementationName() throw( uno::RuntimeException ) + { + return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( IMPLEMENTATION_NAME ) ); + } + + sal_Bool SAL_CALL CanvasCustomSprite::supportsService( const ::rtl::OUString& ServiceName ) throw( uno::RuntimeException ) + { + return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( SERVICE_NAME ) ); + } + + uno::Sequence< ::rtl::OUString > SAL_CALL CanvasCustomSprite::getSupportedServiceNames() throw( uno::RuntimeException ) + { + uno::Sequence< ::rtl::OUString > aRet(1); + aRet[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME ) ); + + return aRet; + } + + void CanvasCustomSprite::redraw() const + { + ::osl::MutexGuard aGuard( m_aMutex ); + + maSpriteHelper.redraw( mbSurfaceDirty ); + } +} diff --git a/canvas/source/directx/dx_canvascustomsprite.hxx b/canvas/source/directx/dx_canvascustomsprite.hxx new file mode 100755 index 000000000000..73a4b88b19f6 --- /dev/null +++ b/canvas/source/directx/dx_canvascustomsprite.hxx @@ -0,0 +1,142 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_canvascustomsprite.hxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _DXCANVAS_CANVASCUSTOMSPRITE_HXX +#define _DXCANVAS_CANVASCUSTOMSPRITE_HXX + +#include <cppuhelper/compbase4.hxx> +#include <comphelper/uno3.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/rendering/XCustomSprite.hpp> +#include <com/sun/star/rendering/XIntegerBitmap.hpp> +#include <com/sun/star/rendering/XPolyPolygon2D.hpp> + +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/vector/b2isize.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> + +#include <canvas/base/basemutexhelper.hxx> +#include <canvas/base/canvascustomspritebase.hxx> + +#include "dx_sprite.hxx" +#include "dx_surfacebitmap.hxx" +#include "dx_bitmapcanvashelper.hxx" +#include "dx_spritehelper.hxx" +#include "dx_spritecanvas.hxx" + + +namespace dxcanvas +{ + typedef ::cppu::WeakComponentImplHelper4< ::com::sun::star::rendering::XCustomSprite, + ::com::sun::star::rendering::XBitmapCanvas, + ::com::sun::star::rendering::XIntegerBitmap, + ::com::sun::star::lang::XServiceInfo > CanvasCustomSpriteBase_Base; + /** Mixin Sprite + + Have to mixin the Sprite interface before deriving from + ::canvas::CanvasCustomSpriteBase, as this template should + already implement some of those interface methods. + + The reason why this appears kinda convoluted is the fact that + we cannot specify non-IDL types as WeakComponentImplHelperN + template args, and furthermore, don't want to derive + ::canvas::CanvasCustomSpriteBase directly from + ::canvas::Sprite (because derivees of + ::canvas::CanvasCustomSpriteBase have to explicitely forward + the XInterface methods (e.g. via DECLARE_UNO3_AGG_DEFAULTS) + anyway). Basically, ::canvas::CanvasCustomSpriteBase should + remain a base class that provides implementation, not to + enforce any specific interface on its derivees. + */ + class CanvasCustomSpriteSpriteBase_Base : public ::canvas::BaseMutexHelper< CanvasCustomSpriteBase_Base >, + public Sprite + { + }; + + typedef ::canvas::CanvasCustomSpriteBase< CanvasCustomSpriteSpriteBase_Base, + SpriteHelper, + BitmapCanvasHelper, + ::osl::MutexGuard, + ::cppu::OWeakObject > CanvasCustomSpriteBaseT; + + /* Definition of CanvasCustomSprite class */ + + class CanvasCustomSprite : public CanvasCustomSpriteBaseT + { + public: + /** Create a custom sprite + + @param rSpriteSize + Size of the sprite in pixel + + @param rRefDevice + Associated output device + + @param rSpriteCanvas + Target canvas + + @param rDevice + Target DX device + */ + CanvasCustomSprite( const ::com::sun::star::geometry::RealSize2D& rSpriteSize, + const SpriteCanvasRef& rRefDevice, + const IDXRenderModuleSharedPtr& rRenderModule, + const ::canvas::ISurfaceProxyManagerSharedPtr& rSurfaceProxy, + bool bShowSpriteBounds ); + + virtual void SAL_CALL disposing(); + + // Forwarding the XComponent implementation to the + // cppu::ImplHelper templated base + // Classname Base doing refcount Base implementing the XComponent interface + // | | | + // V V V + DECLARE_UNO3_XCOMPONENT_AGG_DEFAULTS( CanvasCustomSprite, CanvasCustomSpriteBase_Base, ::cppu::WeakComponentImplHelperBase ); + + // XServiceInfo + virtual ::rtl::OUString SAL_CALL getImplementationName() throw( ::com::sun::star::uno::RuntimeException ); + virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw( ::com::sun::star::uno::RuntimeException ); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames() throw( ::com::sun::star::uno::RuntimeException ); + + // Sprite + virtual void redraw() const; + + private: + /** MUST hold here, too, since BitmapCanvasHelper only contains a + raw pointer (without refcounting) + */ + SpriteCanvasRef mpSpriteCanvas; + DXSurfaceBitmapSharedPtr mpSurface; + }; +} + +#endif /* _DXCANVAS_CANVASCUSTOMSPRITE_HXX */ diff --git a/canvas/source/directx/dx_canvasfont.cxx b/canvas/source/directx/dx_canvasfont.cxx new file mode 100755 index 000000000000..f041642e51aa --- /dev/null +++ b/canvas/source/directx/dx_canvasfont.cxx @@ -0,0 +1,183 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_canvasfont.cxx,v $ + * $Revision: 1.5 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <ctype.h> // don't ask. msdev breaks otherwise... +#include "dx_winstuff.hxx" +#include "dx_spritecanvas.hxx" +#include "dx_canvasfont.hxx" +#include "dx_textlayout.hxx" + +#include <com/sun/star/rendering/XSpriteCanvas.hpp> +#include <com/sun/star/rendering/PanoseWeight.hpp> + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + namespace + { + INT calcFontStyle( const rendering::FontRequest& rFontRequest ) + { + INT nFontStyle( Gdiplus::FontStyleRegular ); + + if( rFontRequest.FontDescription.FontDescription.Weight > rendering::PanoseWeight::BOOK ) + nFontStyle = Gdiplus::FontStyleBold; + + return nFontStyle; + } + } + + CanvasFont::CanvasFont( const rendering::FontRequest& rFontRequest, + const uno::Sequence< beans::PropertyValue >& /*extraFontProperties*/, + const geometry::Matrix2D& fontMatrix ) : + CanvasFont_Base( m_aMutex ), + mpGdiPlusUser( GDIPlusUser::createInstance() ), + // TODO(F1): extraFontProperties, fontMatrix + mpFontFamily(), + mpFont(), + maFontRequest( rFontRequest ), + maFontMatrix( fontMatrix ) + { + const sal_Int32 nLen(rFontRequest.FontDescription.FamilyName.getLength()); + const sal_Unicode* pStr(rFontRequest.FontDescription.FamilyName.getStr()); + std::vector< sal_Unicode > pStrBuf(nLen+1,0); + std::copy(pStr,pStr+nLen,&pStrBuf[0]); + + mpFontFamily.reset( new Gdiplus::FontFamily(reinterpret_cast<LPCWSTR>(&pStrBuf[0]),NULL) ); + if( !mpFontFamily->IsAvailable() ) + mpFontFamily.reset( new Gdiplus::FontFamily(L"Arial",NULL) ); + + mpFont.reset( new Gdiplus::Font( mpFontFamily.get(), + static_cast<Gdiplus::REAL>(rFontRequest.CellSize), + calcFontStyle( rFontRequest ), + Gdiplus::UnitWorld )); + } + + void SAL_CALL CanvasFont::disposing() + { + ::osl::MutexGuard aGuard( m_aMutex ); + + mpFont.reset(); + mpFontFamily.reset(); + mpGdiPlusUser.reset(); + } + + uno::Reference< rendering::XTextLayout > SAL_CALL CanvasFont::createTextLayout( const rendering::StringContext& aText, + sal_Int8 nDirection, + sal_Int64 nRandomSeed ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + return new TextLayout( aText, nDirection, nRandomSeed, ImplRef( this ) ); + } + + uno::Sequence< double > SAL_CALL CanvasFont::getAvailableSizes( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO + return uno::Sequence< double >(); + } + + uno::Sequence< beans::PropertyValue > SAL_CALL CanvasFont::getExtraFontProperties( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO + return uno::Sequence< beans::PropertyValue >(); + } + + rendering::FontRequest SAL_CALL CanvasFont::getFontRequest( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + return maFontRequest; + } + + rendering::FontMetrics SAL_CALL CanvasFont::getFontMetrics( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO + return rendering::FontMetrics(); + } + +#define SERVICE_NAME "com.sun.star.rendering.CanvasFont" +#define IMPLEMENTATION_NAME "DXCanvas::CanvasFont" + + ::rtl::OUString SAL_CALL CanvasFont::getImplementationName() throw( uno::RuntimeException ) + { + return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( IMPLEMENTATION_NAME ) ); + } + + sal_Bool SAL_CALL CanvasFont::supportsService( const ::rtl::OUString& ServiceName ) throw( uno::RuntimeException ) + { + return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( SERVICE_NAME ) ); + } + + uno::Sequence< ::rtl::OUString > SAL_CALL CanvasFont::getSupportedServiceNames() throw( uno::RuntimeException ) + { + uno::Sequence< ::rtl::OUString > aRet(1); + aRet[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME ) ); + + return aRet; + } + + double CanvasFont::getCellAscent() const + { + ::osl::MutexGuard aGuard( m_aMutex ); + + return mpFontFamily->GetCellAscent(0); // TODO(F1): rFontRequest.styleName + } + + double CanvasFont::getEmHeight() const + { + ::osl::MutexGuard aGuard( m_aMutex ); + + return mpFontFamily->GetEmHeight(0); // TODO(F1): rFontRequest.styleName + } + + FontSharedPtr CanvasFont::getFont() const + { + ::osl::MutexGuard aGuard( m_aMutex ); + + return mpFont; + } + + const ::com::sun::star::geometry::Matrix2D& CanvasFont::getFontMatrix() const + { + ::osl::MutexGuard aGuard( m_aMutex ); + + return maFontMatrix; + } +} diff --git a/canvas/source/directx/dx_canvasfont.hxx b/canvas/source/directx/dx_canvasfont.hxx new file mode 100755 index 000000000000..cbd7c273192d --- /dev/null +++ b/canvas/source/directx/dx_canvasfont.hxx @@ -0,0 +1,107 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_canvasfont.hxx,v $ + * $Revision: 1.3 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _DXCANVAS_CANVASFONT_HXX +#define _DXCANVAS_CANVASFONT_HXX + +#include <comphelper/implementationreference.hxx> + +#include <cppuhelper/compbase2.hxx> +#include <comphelper/broadcasthelper.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/rendering/XCanvas.hpp> +#include <com/sun/star/rendering/XCanvasFont.hpp> + +#include <rtl/ref.hxx> + +#include <boost/shared_ptr.hpp> +#include <boost/utility.hpp> + +#include "dx_winstuff.hxx" +#include "dx_gdiplususer.hxx" + + +/* Definition of CanvasFont class */ + +namespace dxcanvas +{ + class SpriteCanvas; + + typedef ::boost::shared_ptr< Gdiplus::Font > FontSharedPtr; + typedef ::boost::shared_ptr< Gdiplus::FontFamily > FontFamilySharedPtr; + + typedef ::cppu::WeakComponentImplHelper2< ::com::sun::star::rendering::XCanvasFont, + ::com::sun::star::lang::XServiceInfo > CanvasFont_Base; + + class CanvasFont : public ::comphelper::OBaseMutex, + public CanvasFont_Base, + private ::boost::noncopyable + { + public: + typedef ::comphelper::ImplementationReference< + CanvasFont, + ::com::sun::star::rendering::XCanvasFont > ImplRef; + + CanvasFont( const ::com::sun::star::rendering::FontRequest& fontRequest, + const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& extraFontProperties, + const ::com::sun::star::geometry::Matrix2D& fontMatrix ); + + /// Dispose all internal references + virtual void SAL_CALL disposing(); + + // XCanvasFont + virtual ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XTextLayout > SAL_CALL createTextLayout( const ::com::sun::star::rendering::StringContext& aText, sal_Int8 nDirection, sal_Int64 nRandomSeed ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::rendering::FontRequest SAL_CALL getFontRequest( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::rendering::FontMetrics SAL_CALL getFontMetrics( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< double > SAL_CALL getAvailableSizes( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > SAL_CALL getExtraFontProperties( ) throw (::com::sun::star::uno::RuntimeException); + + // XServiceInfo + virtual ::rtl::OUString SAL_CALL getImplementationName() throw( ::com::sun::star::uno::RuntimeException ); + virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw( ::com::sun::star::uno::RuntimeException ); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames() throw( ::com::sun::star::uno::RuntimeException ); + + double getCellAscent() const; + double getEmHeight() const; + FontSharedPtr getFont() const; + const ::com::sun::star::geometry::Matrix2D& getFontMatrix() const; + + private: + GDIPlusUserSharedPtr mpGdiPlusUser; + FontFamilySharedPtr mpFontFamily; + FontSharedPtr mpFont; + ::com::sun::star::rendering::FontRequest maFontRequest; + ::com::sun::star::geometry::Matrix2D maFontMatrix; + }; + +} + +#endif /* _DXCANVAS_CANVASFONT_HXX */ diff --git a/canvas/source/directx/dx_canvashelper.cxx b/canvas/source/directx/dx_canvashelper.cxx new file mode 100755 index 000000000000..0642b6c50efb --- /dev/null +++ b/canvas/source/directx/dx_canvashelper.cxx @@ -0,0 +1,815 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_canvashelper.cxx,v $ + * $Revision: 1.5 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <canvas/debug.hxx> +#include <tools/diagnose_ex.h> + +#include <rtl/logfile.hxx> +#include <rtl/math.hxx> + +#include <com/sun/star/rendering/TexturingMode.hpp> +#include <com/sun/star/rendering/CompositeOperation.hpp> +#include <com/sun/star/rendering/RepaintResult.hpp> +#include <com/sun/star/rendering/PathCapType.hpp> +#include <com/sun/star/rendering/PathJoinType.hpp> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/tools/canvastools.hxx> + +#include <comphelper/sequence.hxx> +#include <canvas/canvastools.hxx> + +#include "dx_spritecanvas.hxx" +#include "dx_impltools.hxx" +#include "dx_vcltools.hxx" +#include "dx_canvasfont.hxx" +#include "dx_textlayout.hxx" +#include "dx_canvashelper.hxx" + +#include <algorithm> + + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + namespace + { + Gdiplus::LineCap gdiCapFromCap( sal_Int8 nCapType ) + { + switch( nCapType ) + { + case rendering::PathCapType::BUTT: + return Gdiplus::LineCapFlat; + + case rendering::PathCapType::ROUND: + return Gdiplus::LineCapRound; + + case rendering::PathCapType::SQUARE: + return Gdiplus::LineCapSquare; + + default: + ENSURE_OR_THROW( false, + "gdiCapFromCap(): Unexpected cap type" ); + } + + return Gdiplus::LineCapFlat; + } + + Gdiplus::LineJoin gdiJoinFromJoin( sal_Int8 nJoinType ) + { + switch( nJoinType ) + { + case rendering::PathJoinType::NONE: + OSL_ENSURE( false, + "gdiJoinFromJoin(): Join NONE not possible, mapping to MITER" ); + // FALLTHROUGH intended + case rendering::PathJoinType::MITER: + return Gdiplus::LineJoinMiter; + + case rendering::PathJoinType::ROUND: + return Gdiplus::LineJoinRound; + + case rendering::PathJoinType::BEVEL: + return Gdiplus::LineJoinBevel; + + default: + ENSURE_OR_THROW( false, + "gdiJoinFromJoin(): Unexpected join type" ); + } + + return Gdiplus::LineJoinMiter; + } + } + + CanvasHelper::CanvasHelper() : + mpGdiPlusUser( GDIPlusUser::createInstance() ), + mpDevice( NULL ), + mpGraphicsProvider(), + maOutputOffset() + { + } + + void CanvasHelper::disposing() + { + mpGraphicsProvider.reset(); + mpDevice = NULL; + mpGdiPlusUser.reset(); + } + + void CanvasHelper::setDevice( rendering::XGraphicDevice& rDevice ) + { + mpDevice = &rDevice; + } + + void CanvasHelper::setTarget( const GraphicsProviderSharedPtr& rTarget ) + { + ENSURE_OR_THROW( rTarget, + "CanvasHelper::setTarget(): Invalid target" ); + ENSURE_OR_THROW( !mpGraphicsProvider.get(), + "CanvasHelper::setTarget(): target set, old target would be overwritten" ); + + mpGraphicsProvider = rTarget; + } + + void CanvasHelper::setTarget( const GraphicsProviderSharedPtr& rTarget, + const ::basegfx::B2ISize& rOutputOffset ) + { + ENSURE_OR_THROW( rTarget, + "CanvasHelper::setTarget(): invalid target" ); + ENSURE_OR_THROW( !mpGraphicsProvider.get(), + "CanvasHelper::setTarget(): target set, old target would be overwritten" ); + + mpGraphicsProvider = rTarget; + maOutputOffset = rOutputOffset; + } + + void CanvasHelper::clear() + { + if( needOutput() ) + { + GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() ); + Gdiplus::Color aClearColor = Gdiplus::Color((Gdiplus::ARGB)Gdiplus::Color::White); + + ENSURE_OR_THROW( + Gdiplus::Ok == pGraphics->SetCompositingMode( + Gdiplus::CompositingModeSourceCopy ), // force set, don't blend + "CanvasHelper::clear(): GDI+ SetCompositingMode call failed" ); + ENSURE_OR_THROW( + Gdiplus::Ok == pGraphics->Clear( aClearColor ), + "CanvasHelper::clear(): GDI+ Clear call failed" ); + } + } + + void CanvasHelper::drawPoint( const rendering::XCanvas* /*pCanvas*/, + const geometry::RealPoint2D& aPoint, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + if( needOutput() ) + { + GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() ); + + setupGraphicsState( pGraphics, viewState, renderState ); + + Gdiplus::SolidBrush aBrush( + Gdiplus::Color( + tools::sequenceToArgb(renderState.DeviceColor)) ); + + // determine size of one-by-one device pixel ellipse + Gdiplus::Matrix aMatrix; + pGraphics->GetTransform(&aMatrix); + aMatrix.Invert(); + Gdiplus::PointF vector(1, 1); + aMatrix.TransformVectors(&vector); + + // paint a one-by-one circle, with the given point + // in the middle (rounded to float) + ENSURE_OR_THROW( + Gdiplus::Ok == pGraphics->FillEllipse( &aBrush, + // disambiguate call + Gdiplus::REAL(aPoint.X), + Gdiplus::REAL(aPoint.Y), + Gdiplus::REAL(vector.X), + Gdiplus::REAL(vector.Y) ), + "CanvasHelper::drawPoint(): GDI+ call failed" ); + } + } + + void CanvasHelper::drawLine( const rendering::XCanvas* /*pCanvas*/, + const geometry::RealPoint2D& aStartPoint, + const geometry::RealPoint2D& aEndPoint, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + if( needOutput() ) + { + GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() ); + + setupGraphicsState( pGraphics, viewState, renderState ); + + Gdiplus::Pen aPen( + Gdiplus::Color( + tools::sequenceToArgb(renderState.DeviceColor)), + Gdiplus::REAL(0.0) ); + + // #122683# Switched precedence of pixel offset + // mode. Seemingly, polygon stroking needs + // PixelOffsetModeNone to achieve visually pleasing + // results, whereas all other operations (e.g. polygon + // fills, bitmaps) look better with PixelOffsetModeHalf. + const Gdiplus::PixelOffsetMode aOldMode( + pGraphics->GetPixelOffsetMode() ); + pGraphics->SetPixelOffsetMode( Gdiplus::PixelOffsetModeNone ); + + Gdiplus::Status hr = pGraphics->DrawLine( &aPen, + Gdiplus::REAL(aStartPoint.X), // disambiguate call + Gdiplus::REAL(aStartPoint.Y), + Gdiplus::REAL(aEndPoint.X), + Gdiplus::REAL(aEndPoint.Y) ); + pGraphics->SetPixelOffsetMode( aOldMode ); + + ENSURE_OR_THROW( + Gdiplus::Ok == hr, + "CanvasHelper::drawLine(): GDI+ call failed" ); + } + } + + void CanvasHelper::drawBezier( const rendering::XCanvas* /*pCanvas*/, + const geometry::RealBezierSegment2D& aBezierSegment, + const geometry::RealPoint2D& aEndPoint, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + if( needOutput() ) + { + GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() ); + + setupGraphicsState( pGraphics, viewState, renderState ); + + Gdiplus::Pen aPen( + Gdiplus::Color( + tools::sequenceToArgb(renderState.DeviceColor)), + Gdiplus::REAL(0.0) ); + + // #122683# Switched precedence of pixel offset + // mode. Seemingly, polygon stroking needs + // PixelOffsetModeNone to achieve visually pleasing + // results, whereas all other operations (e.g. polygon + // fills, bitmaps) look better with PixelOffsetModeHalf. + const Gdiplus::PixelOffsetMode aOldMode( + pGraphics->GetPixelOffsetMode() ); + pGraphics->SetPixelOffsetMode( Gdiplus::PixelOffsetModeNone ); + + Gdiplus::Status hr = pGraphics->DrawBezier( &aPen, + Gdiplus::REAL(aBezierSegment.Px), // disambiguate call + Gdiplus::REAL(aBezierSegment.Py), + Gdiplus::REAL(aBezierSegment.C1x), + Gdiplus::REAL(aBezierSegment.C1y), + Gdiplus::REAL(aEndPoint.X), + Gdiplus::REAL(aEndPoint.Y), + Gdiplus::REAL(aBezierSegment.C2x), + Gdiplus::REAL(aBezierSegment.C2y) ); + + pGraphics->SetPixelOffsetMode( aOldMode ); + + ENSURE_OR_THROW( + Gdiplus::Ok == hr, + "CanvasHelper::drawBezier(): GDI+ call failed" ); + } + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawPolyPolygon( const rendering::XCanvas* /*pCanvas*/, + const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + ENSURE_OR_THROW( xPolyPolygon.is(), + "CanvasHelper::drawPolyPolygon: polygon is NULL"); + + if( needOutput() ) + { + GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() ); + + setupGraphicsState( pGraphics, viewState, renderState ); + + Gdiplus::Pen aPen( + Gdiplus::Color( + tools::sequenceToArgb(renderState.DeviceColor)), + Gdiplus::REAL(0.0) ); + + // #122683# Switched precedence of pixel offset + // mode. Seemingly, polygon stroking needs + // PixelOffsetModeNone to achieve visually pleasing + // results, whereas all other operations (e.g. polygon + // fills, bitmaps) look better with PixelOffsetModeHalf. + const Gdiplus::PixelOffsetMode aOldMode( + pGraphics->GetPixelOffsetMode() ); + pGraphics->SetPixelOffsetMode( Gdiplus::PixelOffsetModeNone ); + + GraphicsPathSharedPtr pPath( tools::graphicsPathFromXPolyPolygon2D( xPolyPolygon ) ); + + // TODO(E1): Return value + Gdiplus::Status hr = pGraphics->DrawPath( &aPen, pPath.get() ); + + pGraphics->SetPixelOffsetMode( aOldMode ); + + ENSURE_OR_THROW( + Gdiplus::Ok == hr, + "CanvasHelper::drawPolyPolygon(): GDI+ call failed" ); + } + + // TODO(P1): Provide caching here. + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::strokePolyPolygon( const rendering::XCanvas* /*pCanvas*/, + const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + const rendering::StrokeAttributes& strokeAttributes ) + { + ENSURE_OR_THROW( xPolyPolygon.is(), + "CanvasHelper::drawPolyPolygon: polygon is NULL"); + + if( needOutput() ) + { + GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() ); + + setupGraphicsState( pGraphics, viewState, renderState ); + + + // Setup stroke pen + // ---------------- + + Gdiplus::Pen aPen( + Gdiplus::Color( + tools::sequenceToArgb(renderState.DeviceColor)), + static_cast< Gdiplus::REAL >(strokeAttributes.StrokeWidth) ); + + // #122683# Switched precedence of pixel offset + // mode. Seemingly, polygon stroking needs + // PixelOffsetModeNone to achieve visually pleasing + // results, whereas all other operations (e.g. polygon + // fills, bitmaps) look better with PixelOffsetModeHalf. + const Gdiplus::PixelOffsetMode aOldMode( + pGraphics->GetPixelOffsetMode() ); + pGraphics->SetPixelOffsetMode( Gdiplus::PixelOffsetModeNone ); + + aPen.SetMiterLimit( static_cast< Gdiplus::REAL >(strokeAttributes.MiterLimit) ); + + const ::std::vector< Gdiplus::REAL >& rDashArray( + ::comphelper::sequenceToContainer< ::std::vector< Gdiplus::REAL > >( + strokeAttributes.DashArray ) ); + if( !rDashArray.empty() ) + { + aPen.SetDashPattern( &rDashArray[0], + rDashArray.size() ); + } + aPen.SetLineCap( gdiCapFromCap(strokeAttributes.StartCapType), + gdiCapFromCap(strokeAttributes.EndCapType), + Gdiplus::DashCapFlat ); + aPen.SetLineJoin( gdiJoinFromJoin(strokeAttributes.JoinType) ); + + GraphicsPathSharedPtr pPath( tools::graphicsPathFromXPolyPolygon2D( xPolyPolygon ) ); + + // TODO(E1): Return value + Gdiplus::Status hr = pGraphics->DrawPath( &aPen, pPath.get() ); + + pGraphics->SetPixelOffsetMode( aOldMode ); + + ENSURE_OR_THROW( + Gdiplus::Ok == hr, + "CanvasHelper::strokePolyPolygon(): GDI+ call failed" ); + } + + // TODO(P1): Provide caching here. + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::strokeTexturedPolyPolygon( const rendering::XCanvas* /*pCanvas*/, + const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/, + const rendering::ViewState& /*viewState*/, + const rendering::RenderState& /*renderState*/, + const uno::Sequence< rendering::Texture >& /*textures*/, + const rendering::StrokeAttributes& /*strokeAttributes*/ ) + { + // TODO + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::strokeTextureMappedPolyPolygon( const rendering::XCanvas* /*pCanvas*/, + const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/, + const rendering::ViewState& /*viewState*/, + const rendering::RenderState& /*renderState*/, + const uno::Sequence< rendering::Texture >& /*textures*/, + const uno::Reference< geometry::XMapping2D >& /*xMapping*/, + const rendering::StrokeAttributes& /*strokeAttributes*/ ) + { + // TODO + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + uno::Reference< rendering::XPolyPolygon2D > CanvasHelper::queryStrokeShapes( const rendering::XCanvas* /*pCanvas*/, + const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/, + const rendering::ViewState& /*viewState*/, + const rendering::RenderState& /*renderState*/, + const rendering::StrokeAttributes& /*strokeAttributes*/ ) + { + // TODO + return uno::Reference< rendering::XPolyPolygon2D >(NULL); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::fillPolyPolygon( const rendering::XCanvas* /*pCanvas*/, + const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + ENSURE_OR_THROW( xPolyPolygon.is(), + "CanvasHelper::fillPolyPolygon: polygon is NULL"); + + if( needOutput() ) + { + GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() ); + + setupGraphicsState( pGraphics, viewState, renderState ); + + Gdiplus::SolidBrush aBrush( + tools::sequenceToArgb(renderState.DeviceColor)); + + GraphicsPathSharedPtr pPath( tools::graphicsPathFromXPolyPolygon2D( xPolyPolygon ) ); + + // TODO(F1): FillRule + ENSURE_OR_THROW( Gdiplus::Ok == pGraphics->FillPath( &aBrush, pPath.get() ), + "CanvasHelper::fillPolyPolygon(): GDI+ call failed " ); + } + + // TODO(P1): Provide caching here. + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::fillTextureMappedPolyPolygon( const rendering::XCanvas* /*pCanvas*/, + const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/, + const rendering::ViewState& /*viewState*/, + const rendering::RenderState& /*renderState*/, + const uno::Sequence< rendering::Texture >& /*textures*/, + const uno::Reference< geometry::XMapping2D >& /*xMapping*/ ) + { + // TODO + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + uno::Reference< rendering::XCanvasFont > CanvasHelper::createFont( const rendering::XCanvas* /*pCanvas*/, + const rendering::FontRequest& fontRequest, + const uno::Sequence< beans::PropertyValue >& extraFontProperties, + const geometry::Matrix2D& fontMatrix ) + { + if( needOutput() ) + { + return uno::Reference< rendering::XCanvasFont >( + new CanvasFont(fontRequest, extraFontProperties, fontMatrix ) ); + } + + return uno::Reference< rendering::XCanvasFont >(); + } + + uno::Sequence< rendering::FontInfo > CanvasHelper::queryAvailableFonts( const rendering::XCanvas* /*pCanvas*/, + const rendering::FontInfo& /*aFilter*/, + const uno::Sequence< beans::PropertyValue >& /*aFontProperties*/ ) + { + // TODO + return uno::Sequence< rendering::FontInfo >(); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawText( const rendering::XCanvas* /*pCanvas*/, + const rendering::StringContext& text, + const uno::Reference< rendering::XCanvasFont >& xFont, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + sal_Int8 /*textDirection*/ ) + { + ENSURE_OR_THROW( xFont.is(), + "CanvasHelper::drawText: font is NULL"); + + if( needOutput() ) + { + GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() ); + + setupGraphicsState( pGraphics, viewState, renderState ); + + Gdiplus::SolidBrush aBrush( + Gdiplus::Color( + tools::sequenceToArgb(renderState.DeviceColor))); + + CanvasFont::ImplRef pFont( + tools::canvasFontFromXFont(xFont) ); + + // Move glyphs up, such that output happens at the font + // baseline. + Gdiplus::PointF aPoint( 0.0, + static_cast<Gdiplus::REAL>(-(pFont->getFont()->GetSize()* + pFont->getCellAscent() / + pFont->getEmHeight())) ); + + // TODO(F1): According to + // http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q307208, + // we might have to revert to GDI and ExTextOut here, + // since GDI+ takes the scalability a little bit too + // far... + + // TODO(F2): Proper layout (BiDi, CTL)! IMHO must use + // DrawDriverString here, and perform layouting myself... + ENSURE_OR_THROW( + Gdiplus::Ok == pGraphics->DrawString( reinterpret_cast<LPCWSTR>( + text.Text.copy( text.StartPosition, + text.Length ).getStr()), + text.Length, + pFont->getFont().get(), + aPoint, + &aBrush ), + "CanvasHelper::drawText(): GDI+ call failed" ); + } + + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawTextLayout( const rendering::XCanvas* /*pCanvas*/, + const uno::Reference< rendering::XTextLayout >& xLayoutetText, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + ENSURE_OR_THROW( xLayoutetText.is(), + "CanvasHelper::drawTextLayout: layout is NULL"); + + if( needOutput() ) + { + TextLayout* pTextLayout = + dynamic_cast< TextLayout* >( xLayoutetText.get() ); + + ENSURE_OR_THROW( pTextLayout, + "CanvasHelper::drawTextLayout(): TextLayout not compatible with this canvas" ); + + pTextLayout->draw( mpGraphicsProvider->getGraphics(), + viewState, + renderState, + maOutputOffset, + mpDevice, + false ); + } + + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawBitmap( const rendering::XCanvas* /*pCanvas*/, + const uno::Reference< rendering::XBitmap >& xBitmap, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + ENSURE_OR_THROW( xBitmap.is(), + "CanvasHelper::drawBitmap: bitmap is NULL"); + + if( needOutput() ) + { + // check whether one of our own objects - need to retrieve + // bitmap _before_ calling + // GraphicsProvider::getGraphics(), to avoid locking our + // own surface. + BitmapSharedPtr pGdiBitmap; + BitmapProvider* pBitmap = dynamic_cast< BitmapProvider* >(xBitmap.get()); + if( pBitmap ) + { + IBitmapSharedPtr pDXBitmap( pBitmap->getBitmap() ); + if( pDXBitmap ) + pGdiBitmap = pDXBitmap->getBitmap(); + } + + GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() ); + setupGraphicsState( pGraphics, viewState, renderState ); + + if( pGdiBitmap ) + tools::drawGdiPlusBitmap(pGraphics,pGdiBitmap); + else + tools::drawVCLBitmapFromXBitmap(pGraphics, + xBitmap); + } + + // TODO(P1): Provide caching here. + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawBitmapModulated( const rendering::XCanvas* pCanvas, + const uno::Reference< rendering::XBitmap >& xBitmap, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + ENSURE_OR_THROW( xBitmap.is(), + "CanvasHelper::drawBitmap: bitmap is NULL"); + + // no color set -> this is equivalent to a plain drawBitmap(), then + if( renderState.DeviceColor.getLength() < 3 ) + return drawBitmap( pCanvas, xBitmap, viewState, renderState ); + + if( needOutput() ) + { + GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() ); + + setupGraphicsState( pGraphics, viewState, renderState ); + + BitmapSharedPtr pBitmap( tools::bitmapFromXBitmap( xBitmap ) ); + Gdiplus::Rect aRect( 0, 0, + pBitmap->GetWidth(), + pBitmap->GetHeight() ); + + // Setup an ImageAttributes with an alpha-modulating + // color matrix. + const rendering::ARGBColor& rARGBColor( + mpDevice->getDeviceColorSpace()->convertToARGB(renderState.DeviceColor)[0]); + + Gdiplus::ImageAttributes aImgAttr; + tools::setModulateImageAttributes( aImgAttr, + rARGBColor.Red, + rARGBColor.Green, + rARGBColor.Blue, + rARGBColor.Alpha ); + + ENSURE_OR_THROW( + Gdiplus::Ok == pGraphics->DrawImage( pBitmap.get(), + aRect, + 0, 0, + pBitmap->GetWidth(), + pBitmap->GetHeight(), + Gdiplus::UnitPixel, + &aImgAttr, + NULL, + NULL ), + "CanvasHelper::drawBitmapModulated(): GDI+ call failed" ); + } + + // TODO(P1): Provide caching here. + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + uno::Reference< rendering::XGraphicDevice > CanvasHelper::getDevice() + { + return uno::Reference< rendering::XGraphicDevice >(mpDevice); + } + + // private helper + // -------------------------------------------------- + + Gdiplus::CompositingMode CanvasHelper::calcCompositingMode( sal_Int8 nMode ) + { + Gdiplus::CompositingMode aRet( Gdiplus::CompositingModeSourceOver ); + + switch( nMode ) + { + case rendering::CompositeOperation::OVER: + // FALLTHROUGH intended + case rendering::CompositeOperation::CLEAR: + aRet = Gdiplus::CompositingModeSourceOver; + break; + + case rendering::CompositeOperation::SOURCE: + aRet = Gdiplus::CompositingModeSourceCopy; + break; + + case rendering::CompositeOperation::DESTINATION: + // FALLTHROUGH intended + case rendering::CompositeOperation::UNDER: + // FALLTHROUGH intended + case rendering::CompositeOperation::INSIDE: + // FALLTHROUGH intended + case rendering::CompositeOperation::INSIDE_REVERSE: + // FALLTHROUGH intended + case rendering::CompositeOperation::OUTSIDE: + // FALLTHROUGH intended + case rendering::CompositeOperation::OUTSIDE_REVERSE: + // FALLTHROUGH intended + case rendering::CompositeOperation::ATOP: + // FALLTHROUGH intended + case rendering::CompositeOperation::ATOP_REVERSE: + // FALLTHROUGH intended + case rendering::CompositeOperation::XOR: + // FALLTHROUGH intended + case rendering::CompositeOperation::ADD: + // FALLTHROUGH intended + case rendering::CompositeOperation::SATURATE: + // TODO(F2): Problem, because GDI+ only knows about two compositing modes + aRet = Gdiplus::CompositingModeSourceOver; + break; + + default: + ENSURE_OR_THROW( false, "CanvasHelper::calcCompositingMode: unexpected mode" ); + break; + } + + return aRet; + } + + void CanvasHelper::setupGraphicsState( GraphicsSharedPtr& rGraphics, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + ENSURE_OR_THROW( needOutput(), + "CanvasHelper::setupGraphicsState: primary graphics invalid" ); + ENSURE_OR_THROW( mpDevice, + "CanvasHelper::setupGraphicsState: reference device invalid" ); + + // setup view transform first. Clipping e.g. depends on it + ::basegfx::B2DHomMatrix aTransform; + ::canvas::tools::getViewStateTransform(aTransform, viewState); + + // add output offset + if( !maOutputOffset.equalZero() ) + { + ::basegfx::B2DHomMatrix aOutputOffset; + aOutputOffset.translate( maOutputOffset.getX(), + maOutputOffset.getY() ); + + aTransform = aOutputOffset * aTransform; + } + + Gdiplus::Matrix aMatrix; + tools::gdiPlusMatrixFromB2DHomMatrix( aMatrix, aTransform ); + + ENSURE_OR_THROW( + Gdiplus::Ok == rGraphics->SetTransform( &aMatrix ), + "CanvasHelper::setupGraphicsState(): Failed to set GDI+ transformation" ); + + // setup view and render state clipping + ENSURE_OR_THROW( + Gdiplus::Ok == rGraphics->ResetClip(), + "CanvasHelper::setupGraphicsState(): Failed to reset GDI+ clip" ); + + if( viewState.Clip.is() ) + { + GraphicsPathSharedPtr aClipPath( tools::graphicsPathFromXPolyPolygon2D( viewState.Clip ) ); + + // TODO(P3): Cache clip. SetClip( GraphicsPath ) performs abyssmally on GDI+. + // Try SetClip( Rect ) or similar for simple clip paths (need some support in + // LinePolyPolygon, then) + ENSURE_OR_THROW( + Gdiplus::Ok == rGraphics->SetClip( aClipPath.get(), + Gdiplus::CombineModeIntersect ), + "CanvasHelper::setupGraphicsState(): Cannot set GDI+ clip" ); + } + + // setup overall transform only now. View clip above was relative to + // view transform + ::canvas::tools::mergeViewAndRenderTransform(aTransform, + viewState, + renderState); + + // add output offset + if( !maOutputOffset.equalZero() ) + { + ::basegfx::B2DHomMatrix aOutputOffset; + aOutputOffset.translate( maOutputOffset.getX(), + maOutputOffset.getY() ); + + aTransform = aOutputOffset * aTransform; + } + + tools::gdiPlusMatrixFromB2DHomMatrix( aMatrix, aTransform ); + + ENSURE_OR_THROW( + Gdiplus::Ok == rGraphics->SetTransform( &aMatrix ), + "CanvasHelper::setupGraphicsState(): Cannot set GDI+ transformation" ); + + if( renderState.Clip.is() ) + { + GraphicsPathSharedPtr aClipPath( tools::graphicsPathFromXPolyPolygon2D( renderState.Clip ) ); + + // TODO(P3): Cache clip. SetClip( GraphicsPath ) performs abyssmally on GDI+. + // Try SetClip( Rect ) or similar for simple clip paths (need some support in + // LinePolyPolygon, then) + ENSURE_OR_THROW( + Gdiplus::Ok == rGraphics->SetClip( aClipPath.get(), + Gdiplus::CombineModeIntersect ), + "CanvasHelper::setupGraphicsState(): Cannot set GDI+ clip" ); + } + + // setup compositing + const Gdiplus::CompositingMode eCompositing( calcCompositingMode( renderState.CompositeOperation ) ); + ENSURE_OR_THROW( + Gdiplus::Ok == rGraphics->SetCompositingMode( eCompositing ), + "CanvasHelper::setupGraphicsState(): Cannot set GDI* compositing mode)" ); + } + + void CanvasHelper::flush() const + { + if( needOutput() ) + mpGraphicsProvider->getGraphics()->Flush( Gdiplus::FlushIntentionSync ); + } +} diff --git a/canvas/source/directx/dx_canvashelper.hxx b/canvas/source/directx/dx_canvashelper.hxx new file mode 100755 index 000000000000..57de9b3d28f0 --- /dev/null +++ b/canvas/source/directx/dx_canvashelper.hxx @@ -0,0 +1,260 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_canvashelper.hxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _DXCANVAS_CANVASHELPER_HXX_ +#define _DXCANVAS_CANVASHELPER_HXX_ + +#include <com/sun/star/rendering/XCanvas.hpp> + +#include <basegfx/vector/b2isize.hxx> +#include <basegfx/vector/b2dsize.hxx> + +#include "dx_graphicsprovider.hxx" +#include "dx_gdiplususer.hxx" +#include "dx_impltools.hxx" + +#include <boost/utility.hpp> + + +namespace dxcanvas +{ + /** Helper class for basic canvas functionality. Also offers + optional backbuffer painting, when providing it with a second + HDC to render into. + */ + class CanvasHelper : private ::boost::noncopyable + { + public: + CanvasHelper(); + + /// Release all references + void disposing(); + + /** Initialize canvas helper + + This method late-initializes the canvas helper, providing + it with the necessary device and output objects. Note that + the CanvasHelper does <em>not</em> take ownership of the + passed rDevice reference, nor does it perform any + reference counting. Thus, to prevent the reference counted + SpriteCanvas object from deletion, the user of this class + is responsible for holding ref-counted references itself! + + @param rDevice + Reference device this canvas is associated with + + */ + void setDevice( com::sun::star::rendering::XGraphicDevice& rDevice ); + + /** Set the target for rendering operations + + @param rTarget + Render target + */ + void setTarget( const GraphicsProviderSharedPtr& rTarget ); + + /** Set the target for rendering operations + + @param rTarget + Render target + + @param rOutputOffset + Output offset in pixel + */ + void setTarget( const GraphicsProviderSharedPtr& rTarget, + const ::basegfx::B2ISize& rOutputOffset ); + + + // CanvasHelper functionality + // ========================== + + // XCanvas (only providing, not implementing the + // interface. Also note subtle method parameter differences) + void clear(); + void drawPoint( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::geometry::RealPoint2D& aPoint, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + void drawLine( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::geometry::RealPoint2D& aStartPoint, + const ::com::sun::star::geometry::RealPoint2D& aEndPoint, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + void drawBezier( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::geometry::RealBezierSegment2D& aBezierSegment, + const ::com::sun::star::geometry::RealPoint2D& aEndPoint, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive > + drawPolyPolygon( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XPolyPolygon2D >& xPolyPolygon, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive > + strokePolyPolygon( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XPolyPolygon2D >& xPolyPolygon, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState, + const ::com::sun::star::rendering::StrokeAttributes& strokeAttributes ); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive > + strokeTexturedPolyPolygon( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XPolyPolygon2D >& xPolyPolygon, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState, + const ::com::sun::star::uno::Sequence< + ::com::sun::star::rendering::Texture >& textures, + const ::com::sun::star::rendering::StrokeAttributes& strokeAttributes ); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive > + strokeTextureMappedPolyPolygon( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XPolyPolygon2D >& xPolyPolygon, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState, + const ::com::sun::star::uno::Sequence< + ::com::sun::star::rendering::Texture >& textures, + const ::com::sun::star::uno::Reference< + ::com::sun::star::geometry::XMapping2D >& xMapping, + const ::com::sun::star::rendering::StrokeAttributes& strokeAttributes ); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XPolyPolygon2D > + queryStrokeShapes( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XPolyPolygon2D >& xPolyPolygon, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState, + const ::com::sun::star::rendering::StrokeAttributes& strokeAttributes ); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive > + fillPolyPolygon( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XPolyPolygon2D >& xPolyPolygon, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive > + fillTexturedPolyPolygon( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XPolyPolygon2D >& xPolyPolygon, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState, + const ::com::sun::star::uno::Sequence< + ::com::sun::star::rendering::Texture >& textures ); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive > + fillTextureMappedPolyPolygon( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XPolyPolygon2D >& xPolyPolygon, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState, + const ::com::sun::star::uno::Sequence< + ::com::sun::star::rendering::Texture >& textures, + const ::com::sun::star::uno::Reference< + ::com::sun::star::geometry::XMapping2D >& xMapping ); + + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCanvasFont > SAL_CALL + createFont( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::rendering::FontRequest& fontRequest, + const ::com::sun::star::uno::Sequence< + ::com::sun::star::beans::PropertyValue >& extraFontProperties, + const ::com::sun::star::geometry::Matrix2D& fontMatrix ); + + ::com::sun::star::uno::Sequence< ::com::sun::star::rendering::FontInfo > + queryAvailableFonts( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::rendering::FontInfo& aFilter, + const ::com::sun::star::uno::Sequence< + ::com::sun::star::beans::PropertyValue >& aFontProperties ); + + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive > + drawText( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::rendering::StringContext& text, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XCanvasFont >& xFont, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState, + sal_Int8 textDirection ); + + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive > + drawTextLayout( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XTextLayout >& layoutetText, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive > + drawBitmap( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XBitmap >& xBitmap, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive > + drawBitmapModulated( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XBitmap >& xBitmap, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice > + getDevice(); + + // Flush drawing queue to screen + void flush() const; + + /** Called from XCanvas base classes, to notify that content + is _about_ to change + */ + void modifying() {} + + protected: + /// Refcounted global GDI+ state container + GDIPlusUserSharedPtr mpGdiPlusUser; + + /** Phyical output device + + Deliberately not a refcounted reference, because of + potential circular references for spritecanvas. + */ + com::sun::star::rendering::XGraphicDevice* mpDevice; + + /// Provides the Gdiplus::Graphics to render into + GraphicsProviderSharedPtr mpGraphicsProvider; + + bool needOutput() const { return mpGraphicsProvider.get() != NULL; }; + + // returns transparency of color + void setupGraphicsState( GraphicsSharedPtr& rGraphics, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + + Gdiplus::CompositingMode calcCompositingMode( sal_Int8 nMode ); + + /// Current (transformation-independent) output buffer offset + ::basegfx::B2ISize maOutputOffset; + }; +} + +#endif /* _DXCANVAS_CANVASHELPER_HXX_ */ diff --git a/canvas/source/directx/dx_canvashelper_texturefill.cxx b/canvas/source/directx/dx_canvashelper_texturefill.cxx new file mode 100755 index 000000000000..f291d197c4de --- /dev/null +++ b/canvas/source/directx/dx_canvashelper_texturefill.cxx @@ -0,0 +1,740 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_canvashelper_texturefill.cxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <canvas/debug.hxx> +#include <tools/diagnose_ex.h> +#include <rtl/math.hxx> + +#include <com/sun/star/rendering/TexturingMode.hpp> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/numeric/ftools.hxx> +#include <basegfx/tools/tools.hxx> +#include <basegfx/tools/canvastools.hxx> + +#include <canvas/parametricpolypolygon.hxx> + +#include "dx_spritecanvas.hxx" +#include "dx_canvashelper.hxx" +#include "dx_impltools.hxx" + +#include <boost/scoped_ptr.hpp> + + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + namespace + { + typedef ::boost::shared_ptr< Gdiplus::PathGradientBrush > PathGradientBrushSharedPtr; + + bool fillLinearGradient( GraphicsSharedPtr& rGraphics, + const Gdiplus::Color& rColor1, + const Gdiplus::Color& rColor2, + const GraphicsPathSharedPtr& rFillPath, + const rendering::Texture& texture ) + { + // setup a linear gradient with two colors + // --------------------------------------- + + Gdiplus::LinearGradientBrush aBrush( + Gdiplus::PointF(0.0f, + 0.5f), + Gdiplus::PointF(1.0f, + 0.5f), + rColor1, + rColor2 ); + + // render background color, as LinearGradientBrush does not + // properly support the WrapModeClamp repeat mode + Gdiplus::SolidBrush aBackgroundBrush( rColor1 ); + rGraphics->FillPath( &aBackgroundBrush, rFillPath.get() ); + + // TODO(F2): This does not yet support other repeat modes + // except clamp, and probably also no multi-texturing + + // calculate parallelogram of gradient in object space, extend + // top and bottom of it such that they cover the whole fill + // path bound area + ::basegfx::B2DHomMatrix aTextureTransform; + ::basegfx::unotools::homMatrixFromAffineMatrix( aTextureTransform, + texture.AffineTransform ); + + ::basegfx::B2DPoint aLeftTop( 0.0, 0.0 ); + ::basegfx::B2DPoint aLeftBottom( 0.0, 1.0 ); + ::basegfx::B2DPoint aRightTop( 1.0, 0.0 ); + ::basegfx::B2DPoint aRightBottom( 1.0, 1.0 ); + + aLeftTop *= aTextureTransform; + aLeftBottom *= aTextureTransform; + aRightTop *= aTextureTransform; + aRightBottom*= aTextureTransform; + + Gdiplus::RectF aBounds; + rFillPath->GetBounds( &aBounds, NULL, NULL ); + + // now, we potentially have to enlarge our gradient area + // atop and below the transformed [0,1]x[0,1] unit rect, + // for the gradient to fill the complete bound rect. + ::basegfx::tools::infiniteLineFromParallelogram( aLeftTop, + aLeftBottom, + aRightTop, + aRightBottom, + tools::b2dRangeFromGdiPlusRectF( aBounds ) ); + + // calc length of bound rect diagonal + const double nDiagonalLength( + hypot( aBounds.Width, + aBounds.Height ) ); + + // generate a path which covers the 'right' side of the + // gradient, extending two times the bound rect diagonal to + // the right (and thus covering the whole half plane 'right' + // of the gradient). Take the middle of the gradient as the + // 'left' side of the polygon, to not fall victim to rounding + // errors at the edge. + ::basegfx::B2DVector aDirection( aLeftTop - aLeftBottom ); + aDirection = ::basegfx::getNormalizedPerpendicular( aDirection ); + aDirection *= nDiagonalLength; + + const ::basegfx::B2DPoint aHalfPlaneLeftTop( (aLeftTop + aRightTop) * 0.5 ); + const ::basegfx::B2DPoint aHalfPlaneLeftBottom( (aLeftBottom + aRightBottom) * 0.5 ); + const ::basegfx::B2DPoint aHalfPlaneRightTop( aRightTop + aDirection ); + const ::basegfx::B2DPoint aHalfPlaneRightBottom( aRightBottom + aDirection ); + + Gdiplus::GraphicsPath aSolidFillPath; + aSolidFillPath.AddLine( static_cast<Gdiplus::REAL>(aHalfPlaneLeftTop.getX()), + static_cast<Gdiplus::REAL>(aHalfPlaneLeftTop.getY()), + static_cast<Gdiplus::REAL>(aHalfPlaneRightTop.getX()), + static_cast<Gdiplus::REAL>(aHalfPlaneRightTop.getY()) ); + aSolidFillPath.AddLine( static_cast<Gdiplus::REAL>(aHalfPlaneRightBottom.getX()), + static_cast<Gdiplus::REAL>(aHalfPlaneRightBottom.getY()), + static_cast<Gdiplus::REAL>(aHalfPlaneLeftBottom.getX()), + static_cast<Gdiplus::REAL>(aHalfPlaneLeftBottom.getY()) ); + aSolidFillPath.CloseFigure(); + + // limit output to fill path, we've just generated a path that + // might be substantially larger + if( Gdiplus::Ok != rGraphics->SetClip( rFillPath.get(), + Gdiplus::CombineModeIntersect ) ) + { + return false; + } + + Gdiplus::SolidBrush aBackgroundBrush2( rColor2 ); + rGraphics->FillPath( &aBackgroundBrush2, &aSolidFillPath ); + + // generate clip polygon from the extended parallelogram + // (exploit the feature that distinct lines in a figure are + // automatically closed by a straight line) + Gdiplus::GraphicsPath aClipPath; + aClipPath.AddLine( static_cast<Gdiplus::REAL>(aLeftTop.getX()), + static_cast<Gdiplus::REAL>(aLeftTop.getY()), + static_cast<Gdiplus::REAL>(aRightTop.getX()), + static_cast<Gdiplus::REAL>(aRightTop.getY()) ); + aClipPath.AddLine( static_cast<Gdiplus::REAL>(aRightBottom.getX()), + static_cast<Gdiplus::REAL>(aRightBottom.getY()), + static_cast<Gdiplus::REAL>(aLeftBottom.getX()), + static_cast<Gdiplus::REAL>(aLeftBottom.getY()) ); + aClipPath.CloseFigure(); + + // limit output to a _single_ strip of the gradient (have to + // clip here, since GDI+ wrapmode clamp does not work here) + if( Gdiplus::Ok != rGraphics->SetClip( &aClipPath, + Gdiplus::CombineModeIntersect ) ) + { + return false; + } + + // now, finally, output the gradient + Gdiplus::Matrix aMatrix; + tools::gdiPlusMatrixFromAffineMatrix2D( aMatrix, + texture.AffineTransform ); + aBrush.SetTransform( &aMatrix ); + + rGraphics->FillRectangle( &aBrush, aBounds ); + + return true; + } + + bool fillAxialGradient( GraphicsSharedPtr& rGraphics, + const Gdiplus::Color& rColor1, + const Gdiplus::Color& rColor2, + const GraphicsPathSharedPtr& rFillPath, + const rendering::Texture& texture ) + { + // setup a linear gradient with three colors + // ----------------------------------------- + + Gdiplus::LinearGradientBrush aBrush( + Gdiplus::PointF(0.0f, + 0.5f), + Gdiplus::PointF(1.0f, + 0.5f), + rColor1, + rColor1 ); + + Gdiplus::Color aColors[] = + { + rColor1, // at 0.0 + rColor2, // at 0.5 + rColor1 // at 1.0 + }; + + Gdiplus::REAL aPositions[] = + { + 0.0, + 0.5, + 1.0 + }; + + if( Gdiplus::Ok != aBrush.SetInterpolationColors( aColors, + aPositions, + sizeof( aPositions ) / sizeof(Gdiplus::REAL) ) ) + { + return false; + } + + // render background color, as LinearGradientBrush does not + // properly support the WrapModeClamp repeat mode + Gdiplus::SolidBrush aBackgroundBrush( rColor1 ); + rGraphics->FillPath( &aBackgroundBrush, rFillPath.get() ); + + // TODO(F2): This does not yet support other repeat modes + // except clamp, and probably also no multi-texturing + + // calculate parallelogram of gradient in object space, extend + // top and bottom of it such that they cover the whole fill + // path bound area + ::basegfx::B2DHomMatrix aTextureTransform; + ::basegfx::unotools::homMatrixFromAffineMatrix( aTextureTransform, + texture.AffineTransform ); + + ::basegfx::B2DPoint aLeftTop( 0.0, 0.0 ); + ::basegfx::B2DPoint aLeftBottom( 0.0, 1.0 ); + ::basegfx::B2DPoint aRightTop( 1.0, 0.0 ); + ::basegfx::B2DPoint aRightBottom( 1.0, 1.0 ); + + aLeftTop *= aTextureTransform; + aLeftBottom *= aTextureTransform; + aRightTop *= aTextureTransform; + aRightBottom*= aTextureTransform; + + Gdiplus::RectF aBounds; + rFillPath->GetBounds( &aBounds, NULL, NULL ); + + // now, we potentially have to enlarge our gradient area + // atop and below the transformed [0,1]x[0,1] unit rect, + // for the gradient to fill the complete bound rect. + ::basegfx::tools::infiniteLineFromParallelogram( aLeftTop, + aLeftBottom, + aRightTop, + aRightBottom, + tools::b2dRangeFromGdiPlusRectF( aBounds ) ); + + // generate clip polygon from the extended parallelogram + // (exploit the feature that distinct lines in a figure are + // automatically closed by a straight line) + Gdiplus::GraphicsPath aClipPath; + aClipPath.AddLine( static_cast<Gdiplus::REAL>(aLeftTop.getX()), + static_cast<Gdiplus::REAL>(aLeftTop.getY()), + static_cast<Gdiplus::REAL>(aRightTop.getX()), + static_cast<Gdiplus::REAL>(aRightTop.getY()) ); + aClipPath.AddLine( static_cast<Gdiplus::REAL>(aRightBottom.getX()), + static_cast<Gdiplus::REAL>(aRightBottom.getY()), + static_cast<Gdiplus::REAL>(aLeftBottom.getX()), + static_cast<Gdiplus::REAL>(aLeftBottom.getY()) ); + aClipPath.CloseFigure(); + + // limit output to a _single_ strip of the gradient (have to + // clip here, since GDI+ wrapmode clamp does not work here) + if( Gdiplus::Ok != rGraphics->SetClip( rFillPath.get(), + Gdiplus::CombineModeIntersect ) ) + { + return false; + } + if( Gdiplus::Ok != rGraphics->SetClip( &aClipPath, + Gdiplus::CombineModeIntersect ) ) + { + return false; + } + + // now, finally, output the gradient + Gdiplus::Matrix aMatrix; + tools::gdiPlusMatrixFromAffineMatrix2D( aMatrix, + texture.AffineTransform ); + aBrush.SetTransform( &aMatrix ); + + rGraphics->FillRectangle( &aBrush, aBounds ); + + return true; + } + + PathGradientBrushSharedPtr createPathGradientBrush( const GraphicsPathSharedPtr& rGradientPath, + const Gdiplus::Color& rColor1, + const Gdiplus::Color& rColor2 ) + { + PathGradientBrushSharedPtr pGradientBrush( + new Gdiplus::PathGradientBrush( rGradientPath.get() ) ); + + Gdiplus::Color aColors[] = + { + rColor1 + }; + + INT nCount(1); + + pGradientBrush->SetSurroundColors( aColors, + &nCount ); + pGradientBrush->SetCenterColor( rColor2 ); + + return pGradientBrush; + } + + bool fillPolygonalGradient( const ::canvas::ParametricPolyPolygon::Values& rValues, + GraphicsSharedPtr& rGraphics, + const Gdiplus::Color& rColor1, + const Gdiplus::Color& rColor2, + const GraphicsPathSharedPtr& rPath, + const rendering::Texture& texture ) + { + Gdiplus::Matrix aMatrix; + tools::gdiPlusMatrixFromAffineMatrix2D( aMatrix, + texture.AffineTransform ); + + // copy original fill path object, might have to change it + // below + GraphicsPathSharedPtr pFillPath( rPath ); + + // clone original gradient path object, we need to change it + // below + GraphicsPathSharedPtr pGradientPath( + tools::graphicsPathFromB2DPolygon( rValues.maGradientPoly ) ); + + ENSURE_OR_RETURN( pGradientPath.get(), + "ParametricPolyPolygon::fillPolygonalGradient(): Could not clone path" ); + + PathGradientBrushSharedPtr pGradientBrush; + + // fill background uniformly with end color + Gdiplus::SolidBrush aBackgroundBrush( rColor1 ); + rGraphics->FillPath( &aBackgroundBrush, pFillPath.get() ); + + // scale focus according to aspect ratio: for wider-than-tall + // bounds (nAspectRatio > 1.0), the focus must have non-zero + // width. Specifically, a bound rect twice as wide as tall has + // a focus of half it's width. + if( !::rtl::math::approxEqual(rValues.mnAspectRatio, + 1.0) ) + { + // KLUDGE 1: + // + // And here comes the greatest shortcoming of the GDI+ + // gradients ever: SetFocusScales completely ignores + // transformations, both when set at the PathGradientBrush + // and for the world coordinate system. Thus, to correctly + // display anisotrophic path gradients, we have to render + // them by hand. WTF. + + // TODO(F2): This does not yet support other repeat modes + // except clamp, and probably also no multi-texturing + + // limit output to to-be-filled polygon + if( Gdiplus::Ok != rGraphics->SetClip( pFillPath.get(), + Gdiplus::CombineModeIntersect ) ) + { + return false; + } + + rGraphics->MultiplyTransform( &aMatrix ); + + // disable anti-aliasing, if any + const Gdiplus::SmoothingMode eOldAAMode( rGraphics->GetSmoothingMode() ); + rGraphics->SetSmoothingMode( Gdiplus::SmoothingModeHighSpeed ); + + + // determine number of steps to use + // -------------------------------- + + // TODO(Q2): Unify step calculations with VCL canvas + const int nColorSteps( + ::std::max( + labs( rColor1.GetRed() - rColor2.GetRed() ), + ::std::max( + labs( rColor1.GetGreen() - rColor2.GetGreen() ), + labs( rColor1.GetBlue() - rColor2.GetBlue() ) ) ) ); + + Gdiplus::Matrix aWorldTransformMatrix; + rGraphics->GetTransform( &aWorldTransformMatrix ); + + Gdiplus::RectF aBounds; + pGradientPath->GetBounds( &aBounds, &aWorldTransformMatrix, NULL ); + + // longest line in gradient bound rect + const int nGradientSize( + static_cast<int>( hypot( aBounds.Width, aBounds.Height ) + 1.0 ) ); + + // typical number for pixel of the same color (strip size) + const int nStripSize( 2 ); + + // use at least three steps, and at utmost the number of + // color steps. + const int nStepCount( + ::std::max( + 3, + ::std::min( + nGradientSize / nStripSize, + nColorSteps ) ) + 1 ); + + + Gdiplus::SolidBrush aFillBrush( rColor1 ); + Gdiplus::Matrix aGDIScaleMatrix; + ::basegfx::B2DHomMatrix aScaleMatrix; + + // calc relative size for anisotrophic polygon scaling: + // when the aspect ratio is e.g. 2.0, that denotes a + // gradient which is twice as wide as high. Then, to + // generate a symmetric gradient, the x direction is only + // scaled to 0.5 times the gradient width. Similarly, when + // the aspect ratio is 4.0, the focus has 3/4 the width of + // the overall gradient. + const double nRelativeFocusSize( rValues.mnAspectRatio > 1.0 ? + 1.0 - 1.0/rValues.mnAspectRatio : + 1.0 - rValues.mnAspectRatio ); + + for( int i=1; i<nStepCount; ++i ) + { + // lerp color. Funnily, the straight-forward integer + // lerp ((nStepCount - i)*val + i*val)/nStepCount gets + // fully botched by MSVC, at least for anything that + // really inlines inlines (i.e. every compile without + // debug=t) + const double nFrac( (double)i/nStepCount ); + + const Gdiplus::Color aFillColor( + static_cast<BYTE>( (1.0 - nFrac)*rColor1.GetRed() + nFrac*rColor2.GetRed() ), + static_cast<BYTE>( (1.0 - nFrac)*rColor1.GetGreen() + nFrac*rColor2.GetGreen() ), + static_cast<BYTE>( (1.0 - nFrac)*rColor1.GetBlue() + nFrac*rColor2.GetBlue() ) ); + + aFillBrush.SetColor( aFillColor ); + + const double nCurrScale( (nStepCount-i)/(double)nStepCount ); + aScaleMatrix.identity(); + aScaleMatrix.translate( -0.5, -0.5 ); + + // handle anisotrophic polygon scaling + if( rValues.mnAspectRatio < 1.0 ) + { + // height > width case + aScaleMatrix.scale( nCurrScale, + // lerp with nCurrScale + // between 1.0 and + // relative focus height + nCurrScale + (1.0-nCurrScale)*nRelativeFocusSize ); + } + else if( rValues.mnAspectRatio > 1.0 ) + { + // width > height case + aScaleMatrix.scale( nCurrScale + (1.0-nCurrScale)*nRelativeFocusSize, + // lerp with nCurrScale + // between 1.0 and + // relative focus width + nCurrScale ); + } + else + { + aScaleMatrix.scale( nCurrScale, + nCurrScale ); + } + + aScaleMatrix.translate( 0.5, 0.5 ); + + tools::gdiPlusMatrixFromB2DHomMatrix( aGDIScaleMatrix, + aScaleMatrix ); + + GraphicsPathSharedPtr pScaledGradientPath( + tools::graphicsPathFromB2DPolygon( rValues.maGradientPoly ) ); + pScaledGradientPath->Transform( &aGDIScaleMatrix ); + + rGraphics->FillPath( &aFillBrush, pScaledGradientPath.get() ); + } + + // reset to old anti-alias mode + rGraphics->SetSmoothingMode( eOldAAMode ); + } + else + { + // KLUDGE 2: + // + // We're generating a PathGradientBrush from scratch here, + // and put in a transformed GraphicsPath (transformed with + // the texture transform). This is because the + // straight-forward approach to store a Brush pointer at + // this class and set a texture transform via + // PathGradientBrush::SetTransform() is spoiled by MS: it + // seems that _either_ the texture transform, _or_ the + // transform at the Graphics can be set, but not both. If + // one sets both, only the translational components of the + // texture is respected. + + pGradientPath->Transform( &aMatrix ); + + pGradientBrush = createPathGradientBrush( + pGradientPath, + rColor1, + rColor2 ); + + // explicitely setup center point. Since the center of GDI+ + // gradients are by default the _centroid_ of the path + // (i.e. the weighted sum of edge points), it will not + // necessarily coincide with our notion of center. + Gdiplus::PointF aCenterPoint(0.5, 0.5); + aMatrix.TransformPoints( &aCenterPoint ); + pGradientBrush->SetCenterPoint( aCenterPoint ); + + const bool bTileX( texture.RepeatModeX != rendering::TexturingMode::CLAMP ); + const bool bTileY( texture.RepeatModeY != rendering::TexturingMode::CLAMP ); + + if( bTileX && bTileY ) + pGradientBrush->SetWrapMode( Gdiplus::WrapModeTile ); + else + { + OSL_ENSURE( bTileY == bTileX, + "ParametricPolyPolygon::fillPolygonalGradient(): Cannot have repeat x and repeat y differ!" ); + + pGradientBrush->SetWrapMode( Gdiplus::WrapModeClamp ); + } + + // render actual gradient + rGraphics->FillPath( pGradientBrush.get(), pFillPath.get() ); + } + +#if defined(VERBOSE) && defined(DBG_UTIL) + rGraphics->MultiplyTransform( &aMatrix ); + + Gdiplus::Pen aPen( Gdiplus::Color( 255, 255, 0, 0 ), + 0.0001f ); + + rGraphics->DrawRectangle( &aPen, + Gdiplus::RectF( 0.0f, 0.0f, + 1.0f, 1.0f ) ); +#endif + + return true; + } + + bool fillGradient( const ::canvas::ParametricPolyPolygon::Values& rValues, + const Gdiplus::Color& rColor1, + const Gdiplus::Color& rColor2, + GraphicsSharedPtr& rGraphics, + const GraphicsPathSharedPtr& rPath, + const rendering::Texture& texture ) + { + switch( rValues.meType ) + { + case ::canvas::ParametricPolyPolygon::GRADIENT_LINEAR: + fillLinearGradient( rGraphics, + rColor1, + rColor2, + rPath, + texture ); + break; + + case ::canvas::ParametricPolyPolygon::GRADIENT_AXIAL: + fillAxialGradient( rGraphics, + rColor1, + rColor2, + rPath, + texture ); + break; + + case ::canvas::ParametricPolyPolygon::GRADIENT_ELLIPTICAL: + // FALLTHROUGH intended + case ::canvas::ParametricPolyPolygon::GRADIENT_RECTANGULAR: + fillPolygonalGradient( rValues, + rGraphics, + rColor1, + rColor2, + rPath, + texture ); + break; + + default: + ENSURE_OR_THROW( false, + "CanvasHelper::fillGradient(): Unexpected case" ); + } + + return true; + } + + void fillBitmap( const uno::Reference< rendering::XBitmap >& xBitmap, + GraphicsSharedPtr& rGraphics, + const GraphicsPathSharedPtr& rPath, + const rendering::Texture& rTexture ) + { + OSL_ENSURE( rTexture.RepeatModeX == + rTexture.RepeatModeY, + "CanvasHelper::fillBitmap(): GDI+ cannot handle differing X/Y repeat mode." ); + + const bool bClamp( rTexture.RepeatModeX == rendering::TexturingMode::CLAMP && + rTexture.RepeatModeY == rendering::TexturingMode::CLAMP ); + + const geometry::IntegerSize2D aBmpSize( xBitmap->getSize() ); + ENSURE_ARG_OR_THROW( aBmpSize.Width != 0 && + aBmpSize.Height != 0, + "CanvasHelper::fillBitmap(): zero-sized texture bitmap" ); + + // TODO(P3): Detect case that path is rectangle and + // bitmap is just scaled into that. Then, we can + // render directly, without generating a temporary + // GDI+ bitmap (this is significant, because drawing + // layer presents background object bitmap in that + // way!) + BitmapSharedPtr pBitmap( + tools::bitmapFromXBitmap( xBitmap ) ); + + TextureBrushSharedPtr pBrush; + + if( ::rtl::math::approxEqual( rTexture.Alpha, + 1.0 ) ) + { + pBrush.reset( + new Gdiplus::TextureBrush( + pBitmap.get(), + bClamp ? Gdiplus::WrapModeClamp : Gdiplus::WrapModeTile ) ); + } + else + { + Gdiplus::ImageAttributes aImgAttr; + + tools::setModulateImageAttributes( aImgAttr, + 1.0, + 1.0, + 1.0, + rTexture.Alpha ); + + Gdiplus::Rect aRect(0,0, + aBmpSize.Width, + aBmpSize.Height); + pBrush.reset( + new Gdiplus::TextureBrush( + pBitmap.get(), + aRect, + &aImgAttr ) ); + + pBrush->SetWrapMode( + bClamp ? Gdiplus::WrapModeClamp : Gdiplus::WrapModeTile ); + } + + Gdiplus::Matrix aTextureTransform; + tools::gdiPlusMatrixFromAffineMatrix2D( aTextureTransform, + rTexture.AffineTransform ); + + // scale down bitmap to [0,1]x[0,1] rect, as required + // from the XCanvas interface. + pBrush->ScaleTransform( static_cast< Gdiplus::REAL >(1.0/aBmpSize.Width), + static_cast< Gdiplus::REAL >(1.0/aBmpSize.Height) ); + pBrush->MultiplyTransform( &aTextureTransform ); + + // TODO(F1): FillRule + ENSURE_OR_THROW( + Gdiplus::Ok == rGraphics->FillPath( pBrush.get(), + rPath.get() ), + "CanvasHelper::fillTexturedPolyPolygon(): GDI+ call failed" ); + } + } + + // ------------------------------------------------------------- + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::fillTexturedPolyPolygon( const rendering::XCanvas* /*pCanvas*/, + const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + const uno::Sequence< rendering::Texture >& textures ) + { + ENSURE_OR_THROW( xPolyPolygon.is(), + "CanvasHelper::fillTexturedPolyPolygon: polygon is NULL"); + ENSURE_OR_THROW( textures.getLength(), + "CanvasHelper::fillTexturedPolyPolygon: empty texture sequence"); + + if( needOutput() ) + { + GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() ); + + setupGraphicsState( pGraphics, viewState, renderState ); + + // TODO(F1): Multi-texturing + if( textures[0].Gradient.is() ) + { + // try to cast XParametricPolyPolygon2D reference to + // our implementation class. + ::canvas::ParametricPolyPolygon* pGradient = + dynamic_cast< ::canvas::ParametricPolyPolygon* >( textures[0].Gradient.get() ); + + if( pGradient ) + { + const ::canvas::ParametricPolyPolygon::Values& rValues( + pGradient->getValues() ); + + // TODO: use all the colors and place them on given positions/stops + const Gdiplus::Color aColor1(tools::sequenceToArgb(rValues.maColors[0])); + const Gdiplus::Color aColor2(tools::sequenceToArgb(rValues.maColors[rValues.maColors.getLength () - 1] )); + + // TODO(E1): Return value + // TODO(F1): FillRule + fillGradient( rValues, + aColor1, + aColor2, + pGraphics, + tools::graphicsPathFromXPolyPolygon2D( xPolyPolygon ), + textures[0] ); + } + } + else if( textures[0].Bitmap.is() ) + { + // TODO(E1): Return value + // TODO(F1): FillRule + fillBitmap( textures[0].Bitmap, + pGraphics, + tools::graphicsPathFromXPolyPolygon2D( xPolyPolygon ), + textures[0] ); + } + } + + // TODO(P1): Provide caching here. + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } +} diff --git a/canvas/source/directx/dx_config.cxx b/canvas/source/directx/dx_config.cxx new file mode 100755 index 000000000000..48f44e3ba816 --- /dev/null +++ b/canvas/source/directx/dx_config.cxx @@ -0,0 +1,176 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_config.cxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include "dx_config.hxx" + +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <comphelper/anytostring.hxx> +#include <basegfx/vector/b2ivector.hxx> +#include <cppuhelper/exc_hlp.hxx> + +using namespace com::sun::star; + +namespace dxcanvas +{ + DXCanvasItem::DXCanvasItem() : + ConfigItem( + ::rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( "Office.Canvas/DXCanvas" )), + CONFIG_MODE_IMMEDIATE_UPDATE ), + maValues(), + maMaxTextureSize(), + mbBlacklistCurrentDevice(false), + mbValuesDirty(false) + { + try + { + uno::Sequence< ::rtl::OUString > aName(1); + aName[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DeviceBlacklist" )); + + uno::Sequence< uno::Any > aProps( GetProperties( aName )); + uno::Sequence< sal_Int32 > aValues; + + if( aProps.getLength() > 0 && + (aProps[0] >>= aValues) ) + { + const sal_Int32* pValues = aValues.getConstArray(); + const sal_Int32 nNumEntries( aValues.getLength()*sizeof(sal_Int32)/sizeof(DeviceInfo) ); + for( sal_Int32 i=0; i<nNumEntries; ++i ) + { + DeviceInfo aInfo; + aInfo.nVendorId = *pValues++; + aInfo.nDeviceId = *pValues++; + aInfo.nDeviceSubSysId = *pValues++; + aInfo.nDeviceRevision = *pValues++; + aInfo.nDriverId = *pValues++; + aInfo.nDriverVersion = *pValues++; + aInfo.nDriverSubVersion = *pValues++; + aInfo.nDriverBuildId = *pValues++; + maValues.insert(aInfo); + } + } + + aName[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "BlacklistCurrentDevice" )); + aProps = GetProperties( aName ); + if( aProps.getLength() > 0 ) + aProps[0] >>= mbBlacklistCurrentDevice; + + aName[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MaxTextureSize" )); + aProps = GetProperties( aName ); + if( aProps.getLength() > 0 ) + maMaxTextureSize.reset( aProps[0].get<sal_Int32>() ); + else + maMaxTextureSize.reset(); + } + catch( uno::Exception& ) + { + OSL_ENSURE( false, + rtl::OUStringToOString( + comphelper::anyToString( cppu::getCaughtException() ), + RTL_TEXTENCODING_UTF8 ).getStr() ); + } + } + + DXCanvasItem::~DXCanvasItem() + { + if( !mbValuesDirty ) + return; + + try + { + uno::Sequence< ::rtl::OUString > aName(1); + aName[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DeviceBlacklist" )); + + uno::Sequence< sal_Int32 > aValues( sizeof(DeviceInfo)/sizeof(sal_Int32)*maValues.size() ); + + sal_Int32* pValues = aValues.getArray(); + ValueSet::const_iterator aIter( maValues.begin() ); + const ValueSet::const_iterator aEnd( maValues.end() ); + while( aIter != aEnd ) + { + const DeviceInfo& rInfo( *aIter ); + *pValues++ = rInfo.nVendorId; + *pValues++ = rInfo.nDeviceId; + *pValues++ = rInfo.nDeviceSubSysId; + *pValues++ = rInfo.nDeviceRevision; + *pValues++ = rInfo.nDriverId; + *pValues++ = rInfo.nDriverVersion; + *pValues++ = rInfo.nDriverSubVersion; + *pValues++ = rInfo.nDriverBuildId; + ++aIter; + } + + uno::Sequence< uno::Any > aValue(1); + aValue[0] <<= aValues; + PutProperties( aName, aValue ); + } + catch( uno::Exception& ) + { + OSL_ENSURE( false, + rtl::OUStringToOString( + comphelper::anyToString( cppu::getCaughtException() ), + RTL_TEXTENCODING_UTF8 ).getStr() ); + } + } + + bool DXCanvasItem::isDeviceUsable( const DeviceInfo& rDeviceInfo ) const + { + return maValues.find(rDeviceInfo) == maValues.end(); + } + + bool DXCanvasItem::isBlacklistCurrentDevice() const + { + return mbBlacklistCurrentDevice; + } + + void DXCanvasItem::blacklistDevice( const DeviceInfo& rDeviceInfo ) + { + mbValuesDirty = true; + maValues.insert(rDeviceInfo); + } + + void DXCanvasItem::adaptMaxTextureSize( basegfx::B2IVector& io_maxTextureSize ) const + { + if( maMaxTextureSize ) + { + io_maxTextureSize.setX( + std::min( *maMaxTextureSize, + io_maxTextureSize.getX() )); + io_maxTextureSize.setY( + std::min( *maMaxTextureSize, + io_maxTextureSize.getY() )); + } + } + +} diff --git a/canvas/source/directx/dx_config.hxx b/canvas/source/directx/dx_config.hxx new file mode 100644 index 000000000000..34deddb509a7 --- /dev/null +++ b/canvas/source/directx/dx_config.hxx @@ -0,0 +1,90 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_config.hxx,v $ + * $Revision: 1.3 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _DXCANVAS_DXCONFIG_HXX +#define _DXCANVAS_DXCONFIG_HXX + +#include <unotools/configitem.hxx> +#include <boost/optional.hpp> +#include <set> + +namespace basegfx { class B2IVector; } + +namespace dxcanvas +{ + /** Provide DX canvas config data + */ + class DXCanvasItem : public ::utl::ConfigItem + { + public: + DXCanvasItem(); + + struct DeviceInfo + { + sal_Int32 nVendorId; + sal_Int32 nDeviceId; + sal_Int32 nDeviceSubSysId; + sal_Int32 nDeviceRevision; + + sal_Int32 nDriverId; + sal_Int32 nDriverVersion; + sal_Int32 nDriverSubVersion; + sal_Int32 nDriverBuildId; + + bool operator<( const DeviceInfo& rRHS ) const + { + return nVendorId != rRHS.nVendorId ? nVendorId < rRHS.nVendorId : + (nDeviceId != rRHS.nDeviceId ? nDeviceId < rRHS.nDeviceId : + (nDeviceSubSysId != rRHS.nDeviceSubSysId ? nDeviceSubSysId < rRHS.nDeviceSubSysId : + (nDeviceRevision != rRHS.nDeviceRevision ? nDeviceRevision < rRHS.nDeviceRevision : + (nDriverId != rRHS.nDriverId ? nDriverId < rRHS.nDriverId : + (nDriverVersion != rRHS.nDriverVersion ? nDriverVersion < rRHS.nDriverVersion : + (nDriverSubVersion != rRHS.nDriverSubVersion ? nDriverSubVersion < rRHS.nDriverSubVersion : + (nDriverBuildId != rRHS.nDriverBuildId ? nDriverBuildId < rRHS.nDriverBuildId : false))))))); + } + }; + + ~DXCanvasItem(); + + bool isDeviceUsable( const DeviceInfo& rDeviceInfo ) const; + bool isBlacklistCurrentDevice() const; + void blacklistDevice( const DeviceInfo& rDeviceInfo ); + void adaptMaxTextureSize( basegfx::B2IVector& io_maxTextureSize ) const; + + private: + typedef std::set< DeviceInfo > ValueSet; + ValueSet maValues; + boost::optional<sal_Int32> maMaxTextureSize; + bool mbBlacklistCurrentDevice; + bool mbValuesDirty; + }; +} + +#endif /* #ifndef _DXCANVAS_DXCONFIG_HXX */ diff --git a/canvas/source/directx/dx_devicehelper.cxx b/canvas/source/directx/dx_devicehelper.cxx new file mode 100755 index 000000000000..f08609a3b1f9 --- /dev/null +++ b/canvas/source/directx/dx_devicehelper.cxx @@ -0,0 +1,239 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_devicehelper.cxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <ctype.h> // don't ask. msdev breaks otherwise... +#include <vcl/window.hxx> +#include <vcl/canvastools.hxx> +#include <canvas/debug.hxx> +#include <canvas/verbosetrace.hxx> +#include <canvas/canvastools.hxx> +#include <tools/diagnose_ex.h> + +#include <osl/mutex.hxx> +#include <cppuhelper/compbase1.hxx> + +#include <com/sun/star/lang/NoSupportException.hpp> +#include <toolkit/helper/vclunohelper.hxx> +#include <basegfx/tools/canvastools.hxx> +#include "dx_linepolypolygon.hxx" +#include "dx_spritecanvas.hxx" +#include "dx_canvasbitmap.hxx" +#include "dx_devicehelper.hxx" + + +#undef WB_LEFT +#undef WB_RIGHT +#include "dx_winstuff.hxx" + + +#include <vcl/sysdata.hxx> + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + DeviceHelper::DeviceHelper() : + mpDevice( NULL ), + mnHDC(0) + { + } + + void DeviceHelper::init( HDC hdc, + rendering::XGraphicDevice& rDevice ) + { + mnHDC = hdc; + mpDevice = &rDevice; + } + + void DeviceHelper::disposing() + { + // release all references + mnHDC = 0; + mpDevice = NULL; + } + + geometry::RealSize2D DeviceHelper::getPhysicalResolution() + { + if( !mpDevice ) + return ::canvas::tools::createInfiniteSize2D(); // we're disposed + + HDC hDC = getHDC(); + ENSURE_OR_THROW( hDC, + "DeviceHelper::getPhysicalResolution(): cannot retrieve HDC from window" ); + + const int nHorzRes( GetDeviceCaps( hDC, + LOGPIXELSX ) ); + const int nVertRes( GetDeviceCaps( hDC, + LOGPIXELSY ) ); + + return geometry::RealSize2D( nHorzRes*25.4, + nVertRes*25.4 ); + } + + geometry::RealSize2D DeviceHelper::getPhysicalSize() + { + if( !mpDevice ) + return ::canvas::tools::createInfiniteSize2D(); // we're disposed + + HDC hDC=getHDC(); + ENSURE_OR_THROW( hDC, + "DeviceHelper::getPhysicalSize(): cannot retrieve HDC from window" ); + + const int nHorzSize( GetDeviceCaps( hDC, + HORZSIZE ) ); + const int nVertSize( GetDeviceCaps( hDC, + VERTSIZE ) ); + + return geometry::RealSize2D( nHorzSize, + nVertSize ); + } + + uno::Reference< rendering::XLinePolyPolygon2D > DeviceHelper::createCompatibleLinePolyPolygon( + const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/, + const uno::Sequence< uno::Sequence< geometry::RealPoint2D > >& points ) + { + if( !mpDevice ) + return uno::Reference< rendering::XLinePolyPolygon2D >(); // we're disposed + + return uno::Reference< rendering::XLinePolyPolygon2D >( + new LinePolyPolygon( + ::basegfx::unotools::polyPolygonFromPoint2DSequenceSequence( points ) ) ); + } + + uno::Reference< rendering::XBezierPolyPolygon2D > DeviceHelper::createCompatibleBezierPolyPolygon( + const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/, + const uno::Sequence< uno::Sequence< geometry::RealBezierSegment2D > >& points ) + { + if( !mpDevice ) + return uno::Reference< rendering::XBezierPolyPolygon2D >(); // we're disposed + + return uno::Reference< rendering::XBezierPolyPolygon2D >( + new LinePolyPolygon( + ::basegfx::unotools::polyPolygonFromBezier2DSequenceSequence( points ) ) ); + } + + uno::Reference< rendering::XBitmap > DeviceHelper::createCompatibleBitmap( + const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/, + const geometry::IntegerSize2D& size ) + { + if( !mpDevice ) + return uno::Reference< rendering::XBitmap >(); // we're disposed + + DXBitmapSharedPtr pBitmap( + new DXBitmap( + ::basegfx::unotools::b2ISizeFromIntegerSize2D(size), + false)); + + // create a 24bit RGB system memory surface + return uno::Reference< rendering::XBitmap >(new CanvasBitmap(pBitmap,mpDevice)); + } + + uno::Reference< rendering::XVolatileBitmap > DeviceHelper::createVolatileBitmap( + const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/, + const geometry::IntegerSize2D& /*size*/ ) + { + return uno::Reference< rendering::XVolatileBitmap >(); + } + + uno::Reference< rendering::XBitmap > DeviceHelper::createCompatibleAlphaBitmap( + const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/, + const geometry::IntegerSize2D& size ) + { + if( !mpDevice ) + return uno::Reference< rendering::XBitmap >(); // we're disposed + + DXBitmapSharedPtr pBitmap( + new DXBitmap( + ::basegfx::unotools::b2ISizeFromIntegerSize2D(size), + true)); + + // create a 32bit ARGB system memory surface + return uno::Reference< rendering::XBitmap >(new CanvasBitmap(pBitmap,mpDevice)); + } + + uno::Reference< rendering::XVolatileBitmap > DeviceHelper::createVolatileAlphaBitmap( + const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/, + const geometry::IntegerSize2D& /*size*/ ) + { + return uno::Reference< rendering::XVolatileBitmap >(); + } + + sal_Bool DeviceHelper::hasFullScreenMode() + { + return false; + } + + sal_Bool DeviceHelper::enterFullScreenMode( sal_Bool /*bEnter*/ ) + { + return false; + } + + uno::Any DeviceHelper::isAccelerated() const + { + return ::com::sun::star::uno::makeAny(false); + } + + uno::Any DeviceHelper::getDeviceHandle() const + { + HDC hdc( getHDC() ); + if( hdc ) + return uno::makeAny( reinterpret_cast< sal_Int64 >(hdc) ); + else + return uno::Any(); + } + + uno::Any DeviceHelper::getSurfaceHandle() const + { + // TODO(F1): expose DirectDraw object + //return mpBackBuffer->getBitmap().get(); + return uno::Any(); + } + + namespace + { + struct DeviceColorSpace: public rtl::StaticWithInit<uno::Reference<rendering::XColorSpace>, + DeviceColorSpace> + { + uno::Reference<rendering::XColorSpace> operator()() + { + return vcl::unotools::createStandardColorSpace(); + } + }; + } + + uno::Reference<rendering::XColorSpace> DeviceHelper::getColorSpace() const + { + // always the same + return DeviceColorSpace::get(); + } +} diff --git a/canvas/source/directx/dx_devicehelper.hxx b/canvas/source/directx/dx_devicehelper.hxx new file mode 100755 index 000000000000..79ffee0562b0 --- /dev/null +++ b/canvas/source/directx/dx_devicehelper.hxx @@ -0,0 +1,124 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_devicehelper.hxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _DXCANVAS_DEVICEHELPER_HXX +#define _DXCANVAS_DEVICEHELPER_HXX + +#include <com/sun/star/awt/Rectangle.hpp> +#include <com/sun/star/rendering/XGraphicDevice.hpp> +#include <com/sun/star/rendering/XBufferController.hpp> + +#include "dx_rendermodule.hxx" +#include "dx_bitmap.hxx" + +#include <canvas/rendering/isurfaceproxymanager.hxx> + +#include <boost/utility.hpp> + + +/* Definition of DeviceHelper class */ + +namespace dxcanvas +{ + class DeviceHelper : private ::boost::noncopyable + { + public: + DeviceHelper(); + + /** Init the device helper + + @param hdc + private or class dc of the output device. is only stored, + not release + + @param rDevice + Ref back to owning UNO device + */ + void init( HDC hdc, + com::sun::star::rendering::XGraphicDevice& rDevice ); + + /// Dispose all internal references + void disposing(); + + // XWindowGraphicDevice + ::com::sun::star::geometry::RealSize2D getPhysicalResolution(); + ::com::sun::star::geometry::RealSize2D getPhysicalSize(); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XLinePolyPolygon2D > createCompatibleLinePolyPolygon( + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice >& rDevice, + const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::geometry::RealPoint2D > >& points ); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBezierPolyPolygon2D > createCompatibleBezierPolyPolygon( + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice >& rDevice, + const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::geometry::RealBezierSegment2D > >& points ); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmap > createCompatibleBitmap( + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice >& rDevice, + const ::com::sun::star::geometry::IntegerSize2D& size ); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XVolatileBitmap > createVolatileBitmap( + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice >& rDevice, + const ::com::sun::star::geometry::IntegerSize2D& size ); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmap > createCompatibleAlphaBitmap( + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice >& rDevice, + const ::com::sun::star::geometry::IntegerSize2D& size ); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XVolatileBitmap > createVolatileAlphaBitmap( + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice >& rDevice, + const ::com::sun::star::geometry::IntegerSize2D& size ); + + sal_Bool hasFullScreenMode(); + sal_Bool enterFullScreenMode( sal_Bool bEnter ); + + ::com::sun::star::uno::Any isAccelerated() const; + ::com::sun::star::uno::Any getDeviceHandle() const; + ::com::sun::star::uno::Any getSurfaceHandle() const; + ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XColorSpace > getColorSpace() const; + + /** called when DumpScreenContent property is enabled on + XGraphicDevice, and writes out bitmaps of current screen. + */ + void dumpScreenContent() const {} + + protected: + HDC getHDC() const { return mnHDC; } + com::sun::star::rendering::XGraphicDevice* getDevice() const { return mpDevice; } + + private: + /** Phyical output device + + Deliberately not a refcounted reference, because of + potential circular references for canvas. Needed to + create bitmaps + */ + com::sun::star::rendering::XGraphicDevice* mpDevice; + HDC mnHDC; + }; + + typedef ::rtl::Reference< com::sun::star::rendering::XGraphicDevice > DeviceRef; +} + +#endif /* _DXCANVAS_DEVICEHELPER_HXX */ diff --git a/canvas/source/directx/dx_gdiplususer.cxx b/canvas/source/directx/dx_gdiplususer.cxx new file mode 100755 index 000000000000..0a070e5e67df --- /dev/null +++ b/canvas/source/directx/dx_gdiplususer.cxx @@ -0,0 +1,84 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_gdiplususer.cxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <osl/mutex.hxx> + +#include "dx_winstuff.hxx" +#include "dx_gdiplususer.hxx" + + +namespace dxcanvas +{ + namespace + { + ::osl::Mutex* p_gdiPlusUsageCountMutex( osl::Mutex::getGlobalMutex() ); + int n_gdiPlusUsageCount( 0 ); + + ULONG_PTR a_GdiPlusToken; // GDI+ handle. Owned by this object + } + + GDIPlusUserSharedPtr GDIPlusUser::createInstance() + { + return GDIPlusUserSharedPtr( new GDIPlusUser() ); + } + + GDIPlusUser::~GDIPlusUser() + { + ::osl::MutexGuard aGuard( *p_gdiPlusUsageCountMutex ); + + --n_gdiPlusUsageCount; + + if( n_gdiPlusUsageCount == 0 ) + Gdiplus::GdiplusShutdown( a_GdiPlusToken ); + } + + GDIPlusUser::GDIPlusUser() + { + ::osl::MutexGuard aGuard( *p_gdiPlusUsageCountMutex ); + + if( n_gdiPlusUsageCount == 0 ) + { + // Setup GDI+ + + // No extras here, simply taking GdiplusStartupInput's + // default constructor + Gdiplus::GdiplusStartupInput gdiPlusStartupInput; + + Gdiplus::GdiplusStartup( &a_GdiPlusToken, + &gdiPlusStartupInput, + NULL ); + } + + ++n_gdiPlusUsageCount; + } +} diff --git a/canvas/source/directx/dx_gdiplususer.hxx b/canvas/source/directx/dx_gdiplususer.hxx new file mode 100755 index 000000000000..c80a9f1aedc0 --- /dev/null +++ b/canvas/source/directx/dx_gdiplususer.hxx @@ -0,0 +1,58 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_gdiplususer.hxx,v $ + * $Revision: 1.3 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _DXCANVAS_GDIPLUSUSER_HXX +#define _DXCANVAS_GDIPLUSUSER_HXX + +#include <sal/config.h> + +#include <boost/shared_ptr.hpp> + +/* Definition of GDIPlusUser class */ + +namespace dxcanvas +{ + class GDIPlusUser + { + public: + typedef ::boost::shared_ptr< GDIPlusUser > GDIPlusUserSharedPtr; + + static GDIPlusUserSharedPtr createInstance(); + ~GDIPlusUser(); + + private: + GDIPlusUser(); // create us via factory method + }; + + typedef GDIPlusUser::GDIPlusUserSharedPtr GDIPlusUserSharedPtr; + +} + +#endif /* _DXCANVAS_GDIPLUSUSER_HXX */ diff --git a/canvas/source/directx/dx_graphicsprovider.hxx b/canvas/source/directx/dx_graphicsprovider.hxx new file mode 100644 index 000000000000..977795e7583f --- /dev/null +++ b/canvas/source/directx/dx_graphicsprovider.hxx @@ -0,0 +1,56 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_graphicsprovider.hxx,v $ + * $Revision: 1.2 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _DXCANVAS_GRAPHICSPROVIDER_HXX +#define _DXCANVAS_GRAPHICSPROVIDER_HXX + +#include "dx_winstuff.hxx" + +#include <boost/shared_ptr.hpp> +#include <boost/utility.hpp> + +namespace Gdiplus{ class Graphics; } + +namespace dxcanvas +{ + /** Provider of a Gdiplus::Graphics. Interface + */ + class GraphicsProvider : private ::boost::noncopyable + { + public: + virtual ~GraphicsProvider() {} + + virtual GraphicsSharedPtr getGraphics() = 0; + }; + + typedef ::boost::shared_ptr< GraphicsProvider > GraphicsProviderSharedPtr; +} + +#endif /* _DXCANVAS_GRAPHICSPROVIDER_HXX */ diff --git a/canvas/source/directx/dx_ibitmap.hxx b/canvas/source/directx/dx_ibitmap.hxx new file mode 100644 index 000000000000..9d78562765e4 --- /dev/null +++ b/canvas/source/directx/dx_ibitmap.hxx @@ -0,0 +1,73 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_ibitmap.hxx,v $ + * $Revision: 1.2 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _DXCANVAS_DXIBITMAP_HXX +#define _DXCANVAS_DXIBITMAP_HXX + +#include <com/sun/star/rendering/XCanvas.hpp> +#include <com/sun/star/rendering/XIntegerBitmap.hpp> +#include <boost/shared_ptr.hpp> +#include <basegfx/vector/b2ivector.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/range/b2drange.hxx> +#include "dx_graphicsprovider.hxx" + +namespace dxcanvas +{ + /// Interface for internal canvas bitmap objects + struct IBitmap : public GraphicsProvider + { + virtual BitmapSharedPtr getBitmap() const = 0; + virtual ::basegfx::B2IVector getSize() const = 0; + virtual bool hasAlpha() const = 0; + + virtual ::com::sun::star::uno::Sequence< sal_Int8 > getData( + ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout, + const ::com::sun::star::geometry::IntegerRectangle2D& rect ) = 0; + + virtual void setData( + const ::com::sun::star::uno::Sequence< sal_Int8 >& data, + const ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout, + const ::com::sun::star::geometry::IntegerRectangle2D& rect ) = 0; + + virtual void setPixel( + const ::com::sun::star::uno::Sequence< sal_Int8 >& color, + const ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout, + const ::com::sun::star::geometry::IntegerPoint2D& pos ) = 0; + + virtual ::com::sun::star::uno::Sequence< sal_Int8 > getPixel( + ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout, + const ::com::sun::star::geometry::IntegerPoint2D& pos ) = 0; + }; + + typedef boost::shared_ptr<IBitmap> IBitmapSharedPtr; +} + +#endif diff --git a/canvas/source/directx/dx_impltools.cxx b/canvas/source/directx/dx_impltools.cxx new file mode 100755 index 000000000000..40164c9a1d87 --- /dev/null +++ b/canvas/source/directx/dx_impltools.cxx @@ -0,0 +1,628 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_impltools.cxx,v $ + * $Revision: 1.5 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <ctype.h> // don't ask. msdev breaks otherwise... +#include <basegfx/numeric/ftools.hxx> + +#include <canvas/debug.hxx> +#include <canvas/verbosetrace.hxx> +#include <tools/diagnose_ex.h> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/geometry/RealPoint2D.hpp> +#include <com/sun/star/geometry/IntegerRectangle2D.hpp> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/range/b2irectangle.hxx> +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/tools/canvastools.hxx> + +#include <canvas/canvastools.hxx> +#include <canvas/verifyinput.hxx> + +#include "dx_impltools.hxx" +#include "dx_vcltools.hxx" +#include "dx_linepolypolygon.hxx" +#include "dx_canvasbitmap.hxx" +#include "dx_canvasfont.hxx" +#include "dx_canvas.hxx" +#include "dx_spritecanvas.hxx" + +#include <boost/scoped_array.hpp> + +#include <vector> +#include <algorithm> + + +using namespace ::com::sun::star; + + +namespace dxcanvas +{ + namespace tools + { + ::basegfx::B2DPolyPolygon polyPolygonFromXPolyPolygon2D( const uno::Reference< rendering::XPolyPolygon2D >& xPoly ) + { + LinePolyPolygon* pPolyImpl = dynamic_cast< LinePolyPolygon* >( xPoly.get() ); + + if( pPolyImpl ) + { + return pPolyImpl->getPolyPolygon(); + } + else + { + const sal_Int32 nPolys( xPoly->getNumberOfPolygons() ); + + // not a known implementation object - try data source + // interfaces + uno::Reference< rendering::XBezierPolyPolygon2D > xBezierPoly( + xPoly, + uno::UNO_QUERY ); + + if( xBezierPoly.is() ) + { + return ::basegfx::unotools::polyPolygonFromBezier2DSequenceSequence( + xBezierPoly->getBezierSegments( 0, + nPolys, + 0, + -1 ) ); + } + else + { + uno::Reference< rendering::XLinePolyPolygon2D > xLinePoly( + xPoly, + uno::UNO_QUERY ); + + // no implementation class and no data provider + // found - contract violation. + ENSURE_ARG_OR_THROW( xLinePoly.is(), + "VCLCanvas::polyPolygonFromXPolyPolygon2D(): Invalid input " + "poly-polygon, cannot retrieve vertex data" ); + + return ::basegfx::unotools::polyPolygonFromPoint2DSequenceSequence( + xLinePoly->getPoints( 0, + nPolys, + 0, + -1 ) ); + } + } + } + + void setupGraphics( Gdiplus::Graphics& rGraphics ) + { + // setup graphics with (somewhat arbitrary) defaults + //rGraphics.SetCompositingQuality( Gdiplus::CompositingQualityHighQuality ); + rGraphics.SetCompositingQuality( Gdiplus::CompositingQualityHighSpeed ); + //rGraphics.SetInterpolationMode( Gdiplus::InterpolationModeHighQualityBilinear ); // with prefiltering for shrinks + rGraphics.SetInterpolationMode( Gdiplus::InterpolationModeBilinear ); + + // #122683# Switched precedence of pixel offset + // mode. Seemingly, polygon stroking needs + // PixelOffsetModeNone to achieve visually pleasing + // results, whereas all other operations (e.g. polygon + // fills, bitmaps) look better with PixelOffsetModeHalf. + rGraphics.SetPixelOffsetMode( Gdiplus::PixelOffsetModeHalf ); // Pixel center at (0.5, 0.5) etc. + //rGraphics.SetPixelOffsetMode( Gdiplus::PixelOffsetModeNone ); + + //rGraphics.SetSmoothingMode( Gdiplus::SmoothingModeHighSpeed ); // no line/curve antialiasing + //rGraphics.SetSmoothingMode( Gdiplus::SmoothingModeHighQuality ); + rGraphics.SetSmoothingMode( Gdiplus::SmoothingModeAntiAlias ); + //rGraphics.SetTextRenderingHint( Gdiplus::TextRenderingHintAntiAlias ); + rGraphics.SetTextRenderingHint( Gdiplus::TextRenderingHintSystemDefault ); + rGraphics.SetPageUnit(Gdiplus::UnitPixel); + } + + Gdiplus::Graphics* createGraphicsFromHDC(HDC aHDC) + { + Gdiplus::Graphics* pRet = new Gdiplus::Graphics(aHDC); + if( pRet ) + setupGraphics( *pRet ); + return pRet; + } + + Gdiplus::Graphics* createGraphicsFromBitmap(const BitmapSharedPtr& rBitmap) + { + Gdiplus::Graphics* pRet = Gdiplus::Graphics::FromImage(rBitmap.get()); + if( pRet ) + setupGraphics( *pRet ); + return pRet; + } + + void gdiPlusMatrixFromB2DHomMatrix( Gdiplus::Matrix& rGdiplusMatrix, const ::basegfx::B2DHomMatrix& rMatrix ) + { + rGdiplusMatrix.SetElements( static_cast<Gdiplus::REAL>(rMatrix.get(0,0)), + static_cast<Gdiplus::REAL>(rMatrix.get(1,0)), + static_cast<Gdiplus::REAL>(rMatrix.get(0,1)), + static_cast<Gdiplus::REAL>(rMatrix.get(1,1)), + static_cast<Gdiplus::REAL>(rMatrix.get(0,2)), + static_cast<Gdiplus::REAL>(rMatrix.get(1,2)) ); + } + + void gdiPlusMatrixFromAffineMatrix2D( Gdiplus::Matrix& rGdiplusMatrix, + const geometry::AffineMatrix2D& rMatrix ) + { + rGdiplusMatrix.SetElements( static_cast<Gdiplus::REAL>(rMatrix.m00), + static_cast<Gdiplus::REAL>(rMatrix.m10), + static_cast<Gdiplus::REAL>(rMatrix.m01), + static_cast<Gdiplus::REAL>(rMatrix.m11), + static_cast<Gdiplus::REAL>(rMatrix.m02), + static_cast<Gdiplus::REAL>(rMatrix.m12) ); + } + + namespace + { + // TODO(P2): Check whether this gets inlined. If not, make functor + // out of it + inline Gdiplus::PointF implGdiPlusPointFromRealPoint2D( const ::com::sun::star::geometry::RealPoint2D& rPoint ) + { + return Gdiplus::PointF( static_cast<Gdiplus::REAL>(rPoint.X), + static_cast<Gdiplus::REAL>(rPoint.Y) ); + } + + void graphicsPathFromB2DPolygon( GraphicsPathSharedPtr& rOutput, + ::std::vector< Gdiplus::PointF >& rPoints, + const ::basegfx::B2DPolygon& rPoly ) + { + const sal_uInt32 nPoints( rPoly.count() ); + + if( !nPoints ) + return; + + rOutput->StartFigure(); + + const bool bClosedPolygon( rPoly.isClosed() ); + + if( rPoly.areControlPointsUsed() ) + { + // control points used -> for now, add all + // segments as curves to GraphicsPath + + // If the polygon is closed, we need to add the + // first point, thus, one more (can't simply + // GraphicsPath::CloseFigure() it, since the last + // point cannot have any control points for GDI+) + rPoints.resize( 3*nPoints + bClosedPolygon ); + + sal_uInt32 nCurrOutput=0; + for( sal_uInt32 nCurrPoint=0; nCurrPoint<nPoints; ++nCurrPoint ) + { + const ::basegfx::B2DPoint& rPoint( rPoly.getB2DPoint( nCurrPoint ) ); + rPoints[nCurrOutput++] = Gdiplus::PointF( static_cast<Gdiplus::REAL>(rPoint.getX()), + static_cast<Gdiplus::REAL>(rPoint.getY()) ); + + const ::basegfx::B2DPoint& rControlPointA( rPoly.getNextControlPoint( nCurrPoint ) ); + rPoints[nCurrOutput++] = Gdiplus::PointF( static_cast<Gdiplus::REAL>(rControlPointA.getX()), + static_cast<Gdiplus::REAL>(rControlPointA.getY()) ); + + const ::basegfx::B2DPoint& rControlPointB( rPoly.getPrevControlPoint( (nCurrPoint + 1) % nPoints) ); + rPoints[nCurrOutput++] = Gdiplus::PointF( static_cast<Gdiplus::REAL>(rControlPointB.getX()), + static_cast<Gdiplus::REAL>(rControlPointB.getY()) ); + } + + if( bClosedPolygon ) + { + // add first point again (to be able to pass + // control points for the last point, see + // above) + const ::basegfx::B2DPoint& rPoint( rPoly.getB2DPoint(0) ); + rPoints[nCurrOutput++] = Gdiplus::PointF( static_cast<Gdiplus::REAL>(rPoint.getX()), + static_cast<Gdiplus::REAL>(rPoint.getY()) ); + + rOutput->AddBeziers( &rPoints[0], nCurrOutput ); + } + else + { + // GraphicsPath expects 3(n-1)+1 points (i.e. the + // last point must not have any trailing control + // points after it). + // Therefore, simply don't pass the last two + // points here. + if( nCurrOutput > 3 ) + rOutput->AddBeziers( &rPoints[0], nCurrOutput-2 ); + } + } + else + { + // no control points -> no curves, simply add + // straigt lines to GraphicsPath + rPoints.resize( nPoints ); + + for( sal_uInt32 nCurrPoint=0; nCurrPoint<nPoints; ++nCurrPoint ) + { + const ::basegfx::B2DPoint& rPoint( rPoly.getB2DPoint( nCurrPoint ) ); + rPoints[nCurrPoint] = Gdiplus::PointF( static_cast<Gdiplus::REAL>(rPoint.getX()), + static_cast<Gdiplus::REAL>(rPoint.getY()) ); + } + + rOutput->AddLines( &rPoints[0], nPoints ); + } + + if( bClosedPolygon ) + rOutput->CloseFigure(); + } + } + + Gdiplus::PointF gdiPlusPointFromRealPoint2D( const ::com::sun::star::geometry::RealPoint2D& rPoint ) + { + return implGdiPlusPointFromRealPoint2D( rPoint ); + } + + Gdiplus::Rect gdiPlusRectFromIntegerRectangle2D( const geometry::IntegerRectangle2D& rRect ) + { + return Gdiplus::Rect( rRect.X1, + rRect.Y1, + rRect.X2 - rRect.X1, + rRect.Y2 - rRect.Y1 ); + } + + Gdiplus::RectF gdiPlusRectFFromRectangle2D( const geometry::RealRectangle2D& rRect ) + { + return Gdiplus::RectF( static_cast<Gdiplus::REAL>(rRect.X1), + static_cast<Gdiplus::REAL>(rRect.Y1), + static_cast<Gdiplus::REAL>(rRect.X2 - rRect.X1), + static_cast<Gdiplus::REAL>(rRect.Y2 - rRect.Y1) ); + } + + RECT gdiRectFromB2IRect( const ::basegfx::B2IRange& rRect ) + { + RECT aRect = {rRect.getMinX(), + rRect.getMinY(), + rRect.getMaxX(), + rRect.getMaxY()}; + + return aRect; + } + + geometry::RealPoint2D realPoint2DFromGdiPlusPointF( const Gdiplus::PointF& rPoint ) + { + return geometry::RealPoint2D( rPoint.X, rPoint.Y ); + } + + geometry::RealRectangle2D realRectangle2DFromGdiPlusRectF( const Gdiplus::RectF& rRect ) + { + return geometry::RealRectangle2D( rRect.X, rRect.Y, + rRect.X + rRect.Width, + rRect.Y + rRect.Height ); + } + + ::basegfx::B2DPoint b2dPointFromGdiPlusPointF( const Gdiplus::PointF& rPoint ) + { + return ::basegfx::B2DPoint( rPoint.X, rPoint.Y ); + } + + ::basegfx::B2DRange b2dRangeFromGdiPlusRectF( const Gdiplus::RectF& rRect ) + { + return ::basegfx::B2DRange( rRect.X, rRect.Y, + rRect.X + rRect.Width, + rRect.Y + rRect.Height ); + } + + uno::Sequence< double > argbToDoubleSequence( const Gdiplus::ARGB& rColor ) + { + // TODO(F1): handle color space conversions, when defined on canvas/graphicDevice + uno::Sequence< double > aRet(4); + + aRet[0] = ((rColor >> 16) & 0xFF) / 255.0; // red + aRet[1] = ((rColor >> 8) & 0xFF) / 255.0; // green + aRet[2] = (rColor & 0xFF) / 255.0; // blue + aRet[3] = ((rColor >> 24) & 0xFF) / 255.0; // alpha + + return aRet; + } + + uno::Sequence< sal_Int8 > argbToIntSequence( const Gdiplus::ARGB& rColor ) + { + // TODO(F1): handle color space conversions, when defined on canvas/graphicDevice + uno::Sequence< sal_Int8 > aRet(4); + + aRet[0] = static_cast<sal_Int8>((rColor >> 16) & 0xFF); // red + aRet[1] = static_cast<sal_Int8>((rColor >> 8) & 0xFF); // green + aRet[2] = static_cast<sal_Int8>(rColor & 0xFF); // blue + aRet[3] = static_cast<sal_Int8>((rColor >> 24) & 0xFF); // alpha + + return aRet; + } + + Gdiplus::ARGB sequenceToArgb( const uno::Sequence< sal_Int8 >& rColor ) + { + ENSURE_OR_THROW( rColor.getLength() > 2, + "sequenceToArgb: need at least three channels" ); + + // TODO(F1): handle color space conversions, when defined on canvas/graphicDevice + Gdiplus::ARGB aColor; + + aColor = (static_cast<sal_uInt8>(rColor[0]) << 16) | (static_cast<sal_uInt8>(rColor[1]) << 8) | static_cast<sal_uInt8>(rColor[2]); + + if( rColor.getLength() > 3 ) + aColor |= static_cast<sal_uInt8>(rColor[3]) << 24; + + return aColor; + } + + Gdiplus::ARGB sequenceToArgb( const uno::Sequence< double >& rColor ) + { + ENSURE_OR_THROW( rColor.getLength() > 2, + "sequenceToColor: need at least three channels" ); + + // TODO(F1): handle color space conversions, when defined on canvas/graphicDevice + Gdiplus::ARGB aColor; + + ::canvas::tools::verifyRange(rColor[0],0.0,1.0); + ::canvas::tools::verifyRange(rColor[1],0.0,1.0); + ::canvas::tools::verifyRange(rColor[2],0.0,1.0); + + aColor = + (static_cast<sal_uInt8>( ::basegfx::fround( 255*rColor[0] ) ) << 16) | + (static_cast<sal_uInt8>( ::basegfx::fround( 255*rColor[1] ) ) << 8) | + static_cast<sal_uInt8>( ::basegfx::fround( 255*rColor[2] ) ); + + if( rColor.getLength() > 3 ) + { + ::canvas::tools::verifyRange(rColor[3],0.0,1.0); + aColor |= static_cast<sal_uInt8>( ::basegfx::fround( 255*rColor[3] ) ) << 24; + } + + return aColor; + } + + GraphicsPathSharedPtr graphicsPathFromRealPoint2DSequence( const uno::Sequence< uno::Sequence< geometry::RealPoint2D > >& points ) + { + GraphicsPathSharedPtr pRes( new Gdiplus::GraphicsPath() ); + ::std::vector< Gdiplus::PointF > aPoints; + + sal_Int32 nCurrPoly; + for( nCurrPoly=0; nCurrPoly<points.getLength(); ++nCurrPoly ) + { + const sal_Int32 nCurrSize( points[nCurrPoly].getLength() ); + if( nCurrSize ) + { + aPoints.resize( nCurrSize ); + + // TODO(F1): Closed/open polygons + + // convert from RealPoint2D array to Gdiplus::PointF array + ::std::transform( const_cast< uno::Sequence< geometry::RealPoint2D >& >(points[nCurrPoly]).getArray(), + const_cast< uno::Sequence< geometry::RealPoint2D >& >(points[nCurrPoly]).getArray()+nCurrSize, + aPoints.begin(), + implGdiPlusPointFromRealPoint2D ); + + pRes->AddLines( &aPoints[0], nCurrSize ); + } + } + + return pRes; + } + + GraphicsPathSharedPtr graphicsPathFromB2DPolygon( const ::basegfx::B2DPolygon& rPoly ) + { + GraphicsPathSharedPtr pRes( new Gdiplus::GraphicsPath() ); + ::std::vector< Gdiplus::PointF > aPoints; + + graphicsPathFromB2DPolygon( pRes, aPoints, rPoly ); + + return pRes; + } + + GraphicsPathSharedPtr graphicsPathFromB2DPolyPolygon( const ::basegfx::B2DPolyPolygon& rPoly ) + { + GraphicsPathSharedPtr pRes( new Gdiplus::GraphicsPath() ); + ::std::vector< Gdiplus::PointF > aPoints; + + const sal_uInt32 nPolies( rPoly.count() ); + for( sal_uInt32 nCurrPoly=0; nCurrPoly<nPolies; ++nCurrPoly ) + { + graphicsPathFromB2DPolygon( pRes, + aPoints, + rPoly.getB2DPolygon( nCurrPoly ) ); + } + + return pRes; + } + + GraphicsPathSharedPtr graphicsPathFromXPolyPolygon2D( const uno::Reference< rendering::XPolyPolygon2D >& xPoly ) + { + LinePolyPolygon* pPolyImpl = dynamic_cast< LinePolyPolygon* >( xPoly.get() ); + + if( pPolyImpl ) + { + return pPolyImpl->getGraphicsPath(); + } + else + { + return tools::graphicsPathFromB2DPolyPolygon( + polyPolygonFromXPolyPolygon2D( xPoly ) ); + } + } + + bool drawGdiPlusBitmap( const GraphicsSharedPtr& rGraphics, + const BitmapSharedPtr& rBitmap ) + { + Gdiplus::PointF aPoint; + return (Gdiplus::Ok == rGraphics->DrawImage( rBitmap.get(), + aPoint ) ); + } + + bool drawDIBits( const GraphicsSharedPtr& rGraphics, + const BITMAPINFO& rBI, + const void* pBits ) + { + BitmapSharedPtr pBitmap( + Gdiplus::Bitmap::FromBITMAPINFO( &rBI, + (void*)pBits ) ); + + return drawGdiPlusBitmap( rGraphics, + pBitmap ); + } + + bool drawRGBABits( const GraphicsSharedPtr& rGraphics, + const RawRGBABitmap& rRawRGBAData ) + { + BitmapSharedPtr pBitmap( new Gdiplus::Bitmap( rRawRGBAData.mnWidth, + rRawRGBAData.mnHeight, + PixelFormat32bppARGB ) ); + + Gdiplus::BitmapData aBmpData; + aBmpData.Width = rRawRGBAData.mnWidth; + aBmpData.Height = rRawRGBAData.mnHeight; + aBmpData.Stride = 4*aBmpData.Width; // bottom-up format + aBmpData.PixelFormat = PixelFormat32bppARGB; + aBmpData.Scan0 = rRawRGBAData.mpBitmapData.get(); + + const Gdiplus::Rect aRect( 0,0,aBmpData.Width,aBmpData.Height ); + if( Gdiplus::Ok != pBitmap->LockBits( &aRect, + Gdiplus::ImageLockModeWrite | Gdiplus::ImageLockModeUserInputBuf, + PixelFormat32bppARGB, + &aBmpData ) ) + { + return false; + } + + // commit data to bitmap + pBitmap->UnlockBits( &aBmpData ); + + return drawGdiPlusBitmap( rGraphics, + pBitmap ); + } + + BitmapSharedPtr bitmapFromXBitmap( const uno::Reference< rendering::XBitmap >& xBitmap ) + { + BitmapProvider* pBitmapProvider = dynamic_cast< BitmapProvider* >(xBitmap.get()); + + if( pBitmapProvider ) + { + IBitmapSharedPtr pBitmap( pBitmapProvider->getBitmap() ); + return pBitmap->getBitmap(); + } + else + { + // not a native CanvasBitmap, extract VCL bitmap and + // render into GDI+ bitmap of similar size + // ================================================= + + const geometry::IntegerSize2D aBmpSize( xBitmap->getSize() ); + BitmapSharedPtr pBitmap; + + if( xBitmap->hasAlpha() ) + { + // TODO(P2): At least for the alpha bitmap case, it + // would be possible to generate the corresponding + // bitmap directly + pBitmap.reset( new Gdiplus::Bitmap( aBmpSize.Width, + aBmpSize.Height, + PixelFormat32bppARGB ) ); + } + else + { + // TODO(F2): Might be wise to create bitmap compatible + // to the VCL bitmap. Also, check whether the VCL + // bitmap's system handles can be used to create the + // GDI+ bitmap (currently, it does not seem so). + pBitmap.reset( new Gdiplus::Bitmap( aBmpSize.Width, + aBmpSize.Height, + PixelFormat24bppRGB ) ); + } + + GraphicsSharedPtr pGraphics(createGraphicsFromBitmap(pBitmap)); + tools::setupGraphics(*pGraphics); + if( !drawVCLBitmapFromXBitmap( + pGraphics, + xBitmap) ) + { + pBitmap.reset(); + } + + return pBitmap; + } + } + + CanvasFont::ImplRef canvasFontFromXFont( const uno::Reference< rendering::XCanvasFont >& xFont ) + { + CanvasFont* pCanvasFont = dynamic_cast< CanvasFont* >(xFont.get()); + + ENSURE_ARG_OR_THROW( pCanvasFont, + "canvasFontFromXFont(): Invalid XFont (or incompatible font for this XCanvas)" ); + + return CanvasFont::ImplRef( pCanvasFont ); + } + + void setModulateImageAttributes( Gdiplus::ImageAttributes& o_rAttr, + double nRedModulation, + double nGreenModulation, + double nBlueModulation, + double nAlphaModulation ) + { + // This gets rather verbose, but we have to setup a color + // transformation matrix, in order to incorporate the global + // alpha value mfAlpha into the bitmap rendering. + Gdiplus::ColorMatrix aColorMatrix; + + aColorMatrix.m[0][0] = static_cast<Gdiplus::REAL>(nRedModulation); + aColorMatrix.m[0][1] = 0.0; + aColorMatrix.m[0][2] = 0.0; + aColorMatrix.m[0][3] = 0.0; + aColorMatrix.m[0][4] = 0.0; + + aColorMatrix.m[1][0] = 0.0; + aColorMatrix.m[1][1] = static_cast<Gdiplus::REAL>(nGreenModulation); + aColorMatrix.m[1][2] = 0.0; + aColorMatrix.m[1][3] = 0.0; + aColorMatrix.m[1][4] = 0.0; + + aColorMatrix.m[2][0] = 0.0; + aColorMatrix.m[2][1] = 0.0; + aColorMatrix.m[2][2] = static_cast<Gdiplus::REAL>(nBlueModulation); + aColorMatrix.m[2][3] = 0.0; + aColorMatrix.m[2][4] = 0.0; + + aColorMatrix.m[3][0] = 0.0; + aColorMatrix.m[3][1] = 0.0; + aColorMatrix.m[3][2] = 0.0; + aColorMatrix.m[3][3] = static_cast<Gdiplus::REAL>(nAlphaModulation); + aColorMatrix.m[3][4] = 0.0; + + aColorMatrix.m[4][0] = 0.0; + aColorMatrix.m[4][1] = 0.0; + aColorMatrix.m[4][2] = 0.0; + aColorMatrix.m[4][3] = 0.0; + aColorMatrix.m[4][4] = 1.0; + + o_rAttr.SetColorMatrix( &aColorMatrix, + Gdiplus::ColorMatrixFlagsDefault, + Gdiplus::ColorAdjustTypeDefault ); + } + + } // namespace tools +} // namespace dxcanvas diff --git a/canvas/source/directx/dx_impltools.hxx b/canvas/source/directx/dx_impltools.hxx new file mode 100755 index 000000000000..072d1063235d --- /dev/null +++ b/canvas/source/directx/dx_impltools.hxx @@ -0,0 +1,138 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_impltools.hxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _DXCANVAS_IMPLTOOLS_HXX +#define _DXCANVAS_IMPLTOOLS_HXX + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/util/TriState.hpp> + +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/numeric/ftools.hxx> + +#include <boost/shared_ptr.hpp> +#include "dx_canvasfont.hxx" + +namespace basegfx +{ + class B2DPoint; + class B2DRange; + class B2DHomMatrix; + class B2IPoint; + class B2IRange; + class B2DPolyPolygon; +}; + +namespace com { namespace sun { namespace star { namespace geometry +{ + struct IntegerRectangle2D; + struct RealPoint2D; +} } } } + +namespace com { namespace sun { namespace star { namespace rendering +{ + class XCanvas; + class XGraphicDevice; + class XBitmap; + class XPolyPolygon2D; + class XCanvasFont; +} } } } + + +namespace dxcanvas +{ + namespace tools + { + struct RawRGBABitmap; + + ::basegfx::B2DPolyPolygon + polyPolygonFromXPolyPolygon2D( const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XPolyPolygon2D >& ); + + Gdiplus::Graphics* createGraphicsFromHDC(HDC); + Gdiplus::Graphics* createGraphicsFromBitmap(const BitmapSharedPtr&); + + void setupGraphics( Gdiplus::Graphics& rGraphics ); + + void gdiPlusMatrixFromB2DHomMatrix( Gdiplus::Matrix& rGdiplusMatrix, + const ::basegfx::B2DHomMatrix& rMatrix ); + void gdiPlusMatrixFromAffineMatrix2D( Gdiplus::Matrix& rGdiplusMatrix, + const ::com::sun::star::geometry::AffineMatrix2D& rMatrix ); + + Gdiplus::PointF gdiPlusPointFFromRealPoint2D( const ::com::sun::star::geometry::RealPoint2D& ); + Gdiplus::RectF gdiPlusRectFFromRectangle2D( const ::com::sun::star::geometry::RealRectangle2D& ); + Gdiplus::Rect gdiPlusRectFromIntegerRectangle2D( const ::com::sun::star::geometry::IntegerRectangle2D& ); + RECT gdiRectFromB2IRect( const ::basegfx::B2IRange& ); + + ::com::sun::star::geometry::RealPoint2D realPoint2DFromGdiPlusPointF( const Gdiplus::PointF& ); + ::com::sun::star::geometry::RealRectangle2D realRectangle2DFromGdiPlusRectF( const Gdiplus::RectF& ); + + ::basegfx::B2DPoint b2dPointFromGdiPlusPointF( const Gdiplus::PointF& ); + ::basegfx::B2DRange b2dRangeFromGdiPlusRectF( const Gdiplus::RectF& ); + + ::com::sun::star::uno::Sequence< double > argbToDoubleSequence( const Gdiplus::ARGB& rColor ); + ::com::sun::star::uno::Sequence< sal_Int8 > argbToIntSequence( const Gdiplus::ARGB& rColor ); + Gdiplus::ARGB sequenceToArgb( const ::com::sun::star::uno::Sequence< sal_Int8 >& rColor ); + Gdiplus::ARGB sequenceToArgb( const ::com::sun::star::uno::Sequence< double >& rColor ); + + GraphicsPathSharedPtr graphicsPathFromRealPoint2DSequence( const ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Sequence< ::com::sun::star::geometry::RealPoint2D > >& ); + + GraphicsPathSharedPtr graphicsPathFromB2DPolygon( const ::basegfx::B2DPolygon& rPoly ); + GraphicsPathSharedPtr graphicsPathFromB2DPolyPolygon( const ::basegfx::B2DPolyPolygon& rPoly ); + + GraphicsPathSharedPtr graphicsPathFromXPolyPolygon2D( const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XPolyPolygon2D >& ); + bool drawGdiPlusBitmap( const GraphicsSharedPtr& rGraphics, + const BitmapSharedPtr& rBitmap ); + bool drawDIBits( const ::boost::shared_ptr< Gdiplus::Graphics >& rGraphics, + const BITMAPINFO& rBI, + const void* pBits ); + + bool drawRGBABits( const ::boost::shared_ptr< Gdiplus::Graphics >& rGraphics, + const RawRGBABitmap& rRawRGBAData ); + + BitmapSharedPtr bitmapFromXBitmap( const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XBitmap >& xBitmap ); + + CanvasFont::ImplRef canvasFontFromXFont( const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XCanvasFont >& xFont ); + + void setModulateImageAttributes( Gdiplus::ImageAttributes& o_rAttr, + double nRedModulation, + double nGreenModulation, + double nBlueModulation, + double nAlphaModulation ); + } +} + +#endif /* _DXCANVAS_IMPLTOOLS_HXX */ diff --git a/canvas/source/directx/dx_linepolypolygon.cxx b/canvas/source/directx/dx_linepolypolygon.cxx new file mode 100755 index 000000000000..e63adc3dc613 --- /dev/null +++ b/canvas/source/directx/dx_linepolypolygon.cxx @@ -0,0 +1,68 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_linepolypolygon.cxx,v $ + * $Revision: 1.5 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <basegfx/tools/canvastools.hxx> +#include "dx_linepolypolygon.hxx" + + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + LinePolyPolygon::LinePolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPoly ) : + ::basegfx::unotools::UnoPolyPolygon( rPolyPoly ), + mpGdiPlusUser( GDIPlusUser::createInstance() ), + mpPath() + { + } + + GraphicsPathSharedPtr LinePolyPolygon::getGraphicsPath() const + { + // generate GraphicsPath only on demand (gets deleted as soon + // as any of the modifying methods above touches the + // B2DPolyPolygon). + if( !mpPath ) + { + mpPath = tools::graphicsPathFromB2DPolyPolygon( getPolyPolygonUnsafe() ); + mpPath->SetFillMode( const_cast<LinePolyPolygon*>(this)->getFillRule() == rendering::FillRule_EVEN_ODD ? + Gdiplus::FillModeAlternate : Gdiplus::FillModeWinding ); + } + + return mpPath; + } + + void LinePolyPolygon::modifying() const + { + mpPath.reset(); + } +} diff --git a/canvas/source/directx/dx_linepolypolygon.hxx b/canvas/source/directx/dx_linepolypolygon.hxx new file mode 100755 index 000000000000..431cd1b87b4f --- /dev/null +++ b/canvas/source/directx/dx_linepolypolygon.hxx @@ -0,0 +1,59 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_linepolypolygon.hxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _DXCANVAS_LINEPOLYPOLYGON_HXX_ +#define _DXCANVAS_LINEPOLYPOLYGON_HXX_ + +#include <canvas/canvastools.hxx> +#include <basegfx/tools/unopolypolygon.hxx> + +#include "dx_gdiplususer.hxx" +#include "dx_impltools.hxx" + + +namespace dxcanvas +{ + class LinePolyPolygon : public ::basegfx::unotools::UnoPolyPolygon + { + public: + explicit LinePolyPolygon( const ::basegfx::B2DPolyPolygon& ); + + GraphicsPathSharedPtr getGraphicsPath() const; + + private: + // overridden, to clear mpPath + virtual void modifying() const; + + GDIPlusUserSharedPtr mpGdiPlusUser; + mutable GraphicsPathSharedPtr mpPath; + }; +} + +#endif /* _DXCANVAS_LINEPOLYPOLYGON_HXX_ */ diff --git a/canvas/source/directx/dx_rendermodule.hxx b/canvas/source/directx/dx_rendermodule.hxx new file mode 100755 index 000000000000..11f8cf6e4261 --- /dev/null +++ b/canvas/source/directx/dx_rendermodule.hxx @@ -0,0 +1,93 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_rendermodule.hxx,v $ + * $Revision: 1.3 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _DXCANVAS_RENDERMODULE_HXX +#define _DXCANVAS_RENDERMODULE_HXX + +#include <basegfx/vector/b2ivector.hxx> +#include <basegfx/range/b2irectangle.hxx> +#include <canvas/rendering/irendermodule.hxx> +#include <boost/shared_ptr.hpp> +#include "dx_winstuff.hxx" + +class Window; +namespace basegfx +{ + class B2IRange; + class B2DVector; +} + +namespace dxcanvas +{ + /// Specialization of IRenderModule for DirectX + struct IDXRenderModule : public canvas::IRenderModule + { + /** Flip front- and backbuffer, update only given area + + Note: Both update area and offset are ignored for + fullscreen canvas, that uses page flipping (cannot, by + definition, do anything else there except displaying the + full backbuffer instead of the front buffer) + + @param rUpdateArea + Area to copy from backbuffer to front + + @param rCurrWindowArea + Current area of VCL window (coordinates relative to VCL + HWND) + */ + virtual bool flip( const ::basegfx::B2IRectangle& rUpdateArea, + const ::basegfx::B2IRectangle& rCurrWindowArea ) = 0; + + /** Resize backbuffer area for this render module + */ + virtual void resize( const ::basegfx::B2IRange& rect ) = 0; + + /// Write a snapshot of the screen to disk + virtual void screenShot() = 0; + + virtual COMReference<surface_type> + createSystemMemorySurface( + const ::basegfx::B2IVector& rSize ) = 0; + + virtual void disposing() = 0; + virtual HWND getHWND() const = 0; + }; + + typedef ::boost::shared_ptr< IDXRenderModule > IDXRenderModuleSharedPtr; + + + /** Factory method, to create an IRenderModule instance for the + given VCL window instance + */ + IDXRenderModuleSharedPtr createRenderModule( const ::Window& rParent ); +} + +#endif diff --git a/canvas/source/directx/dx_sprite.hxx b/canvas/source/directx/dx_sprite.hxx new file mode 100755 index 000000000000..6ff6af1bc701 --- /dev/null +++ b/canvas/source/directx/dx_sprite.hxx @@ -0,0 +1,54 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_sprite.hxx,v $ + * $Revision: 1.3 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_DXCANVAS_SPRITE_HXX +#define INCLUDED_DXCANVAS_SPRITE_HXX + +#include <canvas/base/sprite.hxx> + +namespace dxcanvas +{ + /** Specialization of ::canvas::Sprite interface, to also provide + redraw methods. + */ + class Sprite : public ::canvas::Sprite + { + public: + + /** Redraw sprite using the hardware + + This method will silently fail, if the previous + restoreTextures() call failed. + */ + virtual void redraw() const = 0; + }; +} + +#endif /* INCLUDED_DXCANVAS_SPRITE_HXX */ diff --git a/canvas/source/directx/dx_spritecanvas.cxx b/canvas/source/directx/dx_spritecanvas.cxx new file mode 100755 index 000000000000..8ffeae3715ab --- /dev/null +++ b/canvas/source/directx/dx_spritecanvas.cxx @@ -0,0 +1,214 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_spritecanvas.cxx,v $ + * $Revision: 1.5 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <ctype.h> // don't ask. msdev breaks otherwise... +#include <canvas/debug.hxx> +#include <canvas/verbosetrace.hxx> +#include <tools/diagnose_ex.h> + +#include <canvas/canvastools.hxx> + +#include <osl/mutex.hxx> + +#include <com/sun/star/registry/XRegistryKey.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/lang/NoSupportException.hpp> + +#include <toolkit/helper/vclunohelper.hxx> +#include <cppuhelper/factory.hxx> +#include <cppuhelper/implementationentry.hxx> +#include <comphelper/servicedecl.hxx> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/numeric/ftools.hxx> + +#include "dx_winstuff.hxx" +#include "dx_spritecanvas.hxx" + +#if DIRECTX_VERSION < 0x0900 +# define CANVAS_TECH "DX5" +#else +# define CANVAS_TECH "DX9" +#endif + +#define SPRITECANVAS_SERVICE_NAME "com.sun.star.rendering.SpriteCanvas." CANVAS_TECH +#define SPRITECANVAS_IMPLEMENTATION_NAME "com.sun.star.comp.rendering.SpriteCanvas." CANVAS_TECH + + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + SpriteCanvas::SpriteCanvas( const uno::Sequence< uno::Any >& aArguments, + const uno::Reference< uno::XComponentContext >& rxContext ) : + maArguments(aArguments), + mxComponentContext( rxContext ) + { + } + + void SpriteCanvas::initialize() + { + // #i64742# Only call initialize when not in probe mode + if( maArguments.getLength() == 0 ) + return; + + VERBOSE_TRACE( "SpriteCanvas::initialize called" ); + + /* aArguments: + 0: ptr to creating instance (Window or VirtualDevice) + 1: SystemEnvData as a streamed Any (or empty for VirtualDevice) + 2: current bounds of creating instance + 3: bool, denoting always on top state for Window (always false for VirtualDevice) + 4: XWindow for creating Window (or empty for VirtualDevice) + 5: SystemGraphicsData as a streamed Any + */ + ENSURE_ARG_OR_THROW( maArguments.getLength() >= 5 && + maArguments[4].getValueTypeClass() == uno::TypeClass_INTERFACE, + "VCLSpriteCanvas::initialize: wrong number of arguments, or wrong types" ); + + uno::Reference< awt::XWindow > xParentWindow; + maArguments[4] >>= xParentWindow; + Window* pParentWindow = VCLUnoHelper::GetWindow(xParentWindow); + if( !pParentWindow ) + throw lang::NoSupportException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "Parent window not VCL window, or canvas out-of-process!")), + NULL); + + awt::Rectangle aRect; + maArguments[2] >>= aRect; + + sal_Bool bIsFullscreen( sal_False ); + maArguments[3] >>= bIsFullscreen; + + // setup helper + maDeviceHelper.init( *pParentWindow, + *this, + aRect, + bIsFullscreen ); + maCanvasHelper.init( *this, + maRedrawManager, + maDeviceHelper.getRenderModule(), + maDeviceHelper.getSurfaceProxy(), + maDeviceHelper.getBackBuffer(), + ::basegfx::B2ISize() ); + maArguments.realloc(0); + } + + void SAL_CALL SpriteCanvas::disposing() + { + ::osl::MutexGuard aGuard( m_aMutex ); + + mxComponentContext.clear(); + + // forward to parent + SpriteCanvasBaseT::disposing(); + } + + ::sal_Bool SAL_CALL SpriteCanvas::showBuffer( ::sal_Bool bUpdateAll ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // avoid repaints on hidden window (hidden: not mapped to + // screen). Return failure, since the screen really has _not_ + // been updated (caller should try again later) + return !mbIsVisible ? false : SpriteCanvasBaseT::showBuffer( bUpdateAll ); + } + + ::sal_Bool SAL_CALL SpriteCanvas::switchBuffer( ::sal_Bool bUpdateAll ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // avoid repaints on hidden window (hidden: not mapped to + // screen). Return failure, since the screen really has _not_ + // been updated (caller should try again later) + return !mbIsVisible ? false : SpriteCanvasBaseT::switchBuffer( bUpdateAll ); + } + + sal_Bool SAL_CALL SpriteCanvas::updateScreen( sal_Bool bUpdateAll ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // avoid repaints on hidden window (hidden: not mapped to + // screen). Return failure, since the screen really has _not_ + // been updated (caller should try again later) + return !mbIsVisible ? false : maCanvasHelper.updateScreen( + ::basegfx::unotools::b2IRectangleFromAwtRectangle(maBounds), + bUpdateAll, + mbSurfaceDirty ); + } + + ::rtl::OUString SAL_CALL SpriteCanvas::getServiceName( ) throw (uno::RuntimeException) + { + return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SPRITECANVAS_SERVICE_NAME ) ); + } + + const IDXRenderModuleSharedPtr& SpriteCanvas::getRenderModule() const + { + ::osl::MutexGuard aGuard( m_aMutex ); + + return maDeviceHelper.getRenderModule(); + } + + const DXSurfaceBitmapSharedPtr& SpriteCanvas::getBackBuffer() const + { + ::osl::MutexGuard aGuard( m_aMutex ); + + return maDeviceHelper.getBackBuffer(); + } + + IBitmapSharedPtr SpriteCanvas::getBitmap() const + { + return maDeviceHelper.getBackBuffer(); + } + + static uno::Reference<uno::XInterface> initCanvas( SpriteCanvas* pCanvas ) + { + uno::Reference<uno::XInterface> xRet(static_cast<cppu::OWeakObject*>(pCanvas)); + pCanvas->initialize(); + return xRet; + } + + namespace sdecl = comphelper::service_decl; + sdecl::class_<SpriteCanvas, sdecl::with_args<true> > serviceImpl(&initCanvas); + const sdecl::ServiceDecl dxSpriteCanvasDecl( + serviceImpl, + SPRITECANVAS_IMPLEMENTATION_NAME, + SPRITECANVAS_SERVICE_NAME ); +} + +// The C shared lib entry points +COMPHELPER_SERVICEDECL_EXPORTS1(dxcanvas::dxSpriteCanvasDecl); diff --git a/canvas/source/directx/dx_spritecanvas.hxx b/canvas/source/directx/dx_spritecanvas.hxx new file mode 100755 index 000000000000..555316d14b9f --- /dev/null +++ b/canvas/source/directx/dx_spritecanvas.hxx @@ -0,0 +1,159 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_spritecanvas.hxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _DXCANVAS_SPRITECANVAS_HXX_ +#define _DXCANVAS_SPRITECANVAS_HXX_ + +#include <rtl/ref.hxx> + +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/lang/XServiceName.hpp> +#include <com/sun/star/awt/XWindowListener.hpp> +#include <com/sun/star/util/XUpdatable.hpp> +#include <com/sun/star/rendering/XSpriteCanvas.hpp> +#include <com/sun/star/rendering/XIntegerBitmap.hpp> +#include <com/sun/star/rendering/XGraphicDevice.hpp> +#include <com/sun/star/rendering/XBufferController.hpp> +#include <com/sun/star/rendering/XParametricPolyPolygon2DFactory.hpp> + +#include <cppuhelper/compbase9.hxx> +#include <comphelper/uno3.hxx> + +#include <canvas/base/spritecanvasbase.hxx> +#include <canvas/base/basemutexhelper.hxx> +#include <canvas/base/bufferedgraphicdevicebase.hxx> + +#include "dx_bitmapprovider.hxx" +#include "dx_spritecanvashelper.hxx" +#include "dx_surfacebitmap.hxx" +#include "dx_impltools.hxx" +#include "dx_spritedevicehelper.hxx" + + +namespace dxcanvas +{ + typedef ::cppu::WeakComponentImplHelper9< ::com::sun::star::rendering::XSpriteCanvas, + ::com::sun::star::rendering::XIntegerBitmap, + ::com::sun::star::rendering::XGraphicDevice, + ::com::sun::star::rendering::XParametricPolyPolygon2DFactory, + ::com::sun::star::rendering::XBufferController, + ::com::sun::star::awt::XWindowListener, + ::com::sun::star::util::XUpdatable, + ::com::sun::star::beans::XPropertySet, + ::com::sun::star::lang::XServiceName > WindowGraphicDeviceBase_Base; + typedef ::canvas::BufferedGraphicDeviceBase< ::canvas::BaseMutexHelper< WindowGraphicDeviceBase_Base >, + SpriteDeviceHelper, + ::osl::MutexGuard, + ::cppu::OWeakObject > SpriteCanvasBase_Base; + /** Mixin SpriteSurface + + Have to mixin the SpriteSurface before deriving from + ::canvas::SpriteCanvasBase, as this template should already + implement some of those interface methods. + + The reason why this appears kinda convoluted is the fact that + we cannot specify non-IDL types as WeakComponentImplHelperN + template args, and furthermore, don't want to derive + ::canvas::SpriteCanvasBase directly from + ::canvas::SpriteSurface (because derivees of + ::canvas::SpriteCanvasBase have to explicitely forward the + XInterface methods (e.g. via DECLARE_UNO3_AGG_DEFAULTS) + anyway). Basically, ::canvas::CanvasCustomSpriteBase should + remain a base class that provides implementation, not to + enforce any specific interface on its derivees. + */ + class SpriteCanvasBaseSpriteSurface_Base : public SpriteCanvasBase_Base, + public ::canvas::SpriteSurface + { + }; + + typedef ::canvas::SpriteCanvasBase< SpriteCanvasBaseSpriteSurface_Base, + SpriteCanvasHelper, + ::osl::MutexGuard, + ::cppu::OWeakObject > SpriteCanvasBaseT; + + /** Product of this component's factory. + + The SpriteCanvas object combines the actual Window canvas with + the XGraphicDevice interface. This is because there's a + one-to-one relation between them, anyway, since each window + can have exactly one canvas and one associated + XGraphicDevice. And to avoid messing around with circular + references, this is implemented as one single object. + */ + class SpriteCanvas : public SpriteCanvasBaseT, public BitmapProvider + { + public: + SpriteCanvas( const ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Any >& aArguments, + const ::com::sun::star::uno::Reference< + ::com::sun::star::uno::XComponentContext >& rxContext ); + + void initialize(); + + /// Dispose all internal references + virtual void SAL_CALL disposing(); + + // Forwarding the XComponent implementation to the + // cppu::ImplHelper templated base + // Classname Base doing refcounting Base implementing the XComponent interface + // | | | + // V V V + DECLARE_UNO3_XCOMPONENT_AGG_DEFAULTS( SpriteCanvas, WindowGraphicDeviceBase_Base, ::cppu::WeakComponentImplHelperBase ); + + // XBufferController (partial) + virtual ::sal_Bool SAL_CALL showBuffer( ::sal_Bool bUpdateAll ) throw (::com::sun::star::uno::RuntimeException); + virtual ::sal_Bool SAL_CALL switchBuffer( ::sal_Bool bUpdateAll ) throw (::com::sun::star::uno::RuntimeException); + + // XSpriteCanvas (partial) + virtual sal_Bool SAL_CALL updateScreen( sal_Bool bUpdateAll ) throw (::com::sun::star::uno::RuntimeException); + + // XServiceName + virtual ::rtl::OUString SAL_CALL getServiceName( ) throw (::com::sun::star::uno::RuntimeException); + + /// Retrieve rendermodule object for this Canvas + const IDXRenderModuleSharedPtr& getRenderModule() const; + + /// Get backbuffer for this canvas + const DXSurfaceBitmapSharedPtr& getBackBuffer() const; + + // BitmapProvider + virtual IBitmapSharedPtr getBitmap() const; + + private: + ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > maArguments; + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > mxComponentContext; + }; + + typedef ::rtl::Reference< SpriteCanvas > SpriteCanvasRef; +} + +#endif diff --git a/canvas/source/directx/dx_spritecanvashelper.cxx b/canvas/source/directx/dx_spritecanvashelper.cxx new file mode 100755 index 000000000000..3217089a3543 --- /dev/null +++ b/canvas/source/directx/dx_spritecanvashelper.cxx @@ -0,0 +1,385 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_spritecanvashelper.cxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <canvas/debug.hxx> +#include <canvas/verbosetrace.hxx> +#include <canvas/canvastools.hxx> +#include <tools/diagnose_ex.h> + +#include <comphelper/scopeguard.hxx> + +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/tools/canvastools.hxx> + +#include <boost/cast.hpp> + +#include "dx_spritecanvashelper.hxx" +#include "dx_canvascustomsprite.hxx" + +#if defined(DX_DEBUG_IMAGES) +# if OSL_DEBUG_LEVEL > 0 +# include <imdebug.h> +# undef min +# undef max +# endif +#endif + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + namespace + { + void repaintBackground( const ::basegfx::B2DRange& rUpdateArea, + const ::basegfx::B2IRange& rOutputArea, + const DXSurfaceBitmapSharedPtr& rBackBuffer ) + { + // TODO(E1): Use numeric_cast to catch overflow here + ::basegfx::B2IRange aActualArea( 0, 0, + static_cast<sal_Int32>(rOutputArea.getWidth()), + static_cast<sal_Int32>(rOutputArea.getHeight()) ); + aActualArea.intersect( fround( rUpdateArea ) ); + + // repaint the given area of the screen with background content + rBackBuffer->draw(aActualArea); + } + + void spriteRedraw( const ::canvas::Sprite::Reference& rSprite ) + { + // downcast to derived dxcanvas::Sprite interface, which + // provides the actual redraw methods. + ::boost::polymorphic_downcast< Sprite* >( + rSprite.get() )->redraw(); + } + + void spriteRedrawStub( const ::canvas::Sprite::Reference& rSprite ) + { + if( rSprite.is() ) + { + // downcast to derived dxcanvas::Sprite interface, which + // provides the actual redraw methods. + ::boost::polymorphic_downcast< Sprite* >( + rSprite.get() )->redraw(); + } + } + + void spriteRedrawStub2( const ::canvas::SpriteRedrawManager::AreaComponent& rComponent ) + { + if( rComponent.second.getSprite().is() ) + { + // downcast to derived dxcanvas::Sprite interface, which + // provides the actual redraw methods. + ::boost::polymorphic_downcast< Sprite* >( + rComponent.second.getSprite().get() )->redraw(); + } + } + } + + SpriteCanvasHelper::SpriteCanvasHelper() : + mpSpriteSurface( NULL ), + mpRedrawManager( NULL ), + mpRenderModule(), + mpSurfaceProxy(), + mpBackBuffer(), + maUpdateRect(), + maScrapRect(), + mbShowSpriteBounds( false ) + { +#if defined(VERBOSE) && defined(DBG_UTIL) + // inverse default for verbose debug mode + mbShowSpriteBounds = true; +#endif + } + + void SpriteCanvasHelper::init( SpriteCanvas& rParent, + ::canvas::SpriteRedrawManager& rManager, + const IDXRenderModuleSharedPtr& rRenderModule, + const ::canvas::ISurfaceProxyManagerSharedPtr& rSurfaceProxy, + const DXSurfaceBitmapSharedPtr& rBackBuffer, + const ::basegfx::B2ISize& rOutputOffset ) + { + // init base + setDevice( rParent ); + setTarget( rBackBuffer, rOutputOffset ); + + mpSpriteSurface = &rParent; + mpRedrawManager = &rManager; + mpRenderModule = rRenderModule; + mpSurfaceProxy = rSurfaceProxy; + mpBackBuffer = rBackBuffer; + } + + void SpriteCanvasHelper::disposing() + { + if(mpRenderModule) + mpRenderModule->disposing(); + + mpBackBuffer.reset(); + mpRenderModule.reset(); + mpRedrawManager = NULL; + mpSpriteSurface = NULL; + + // forward to base + CanvasHelper::disposing(); + } + + uno::Reference< rendering::XAnimatedSprite > SpriteCanvasHelper::createSpriteFromAnimation( + const uno::Reference< rendering::XAnimation >& /*animation*/ ) + { + return uno::Reference< rendering::XAnimatedSprite >(); + } + + uno::Reference< rendering::XAnimatedSprite > SpriteCanvasHelper::createSpriteFromBitmaps( + const uno::Sequence< uno::Reference< rendering::XBitmap > >& /*animationBitmaps*/, + sal_Int8 /*interpolationMode*/ ) + { + return uno::Reference< rendering::XAnimatedSprite >(); + } + + uno::Reference< rendering::XCustomSprite > SpriteCanvasHelper::createCustomSprite( const geometry::RealSize2D& spriteSize ) + { + if( !mpRedrawManager ) + return uno::Reference< rendering::XCustomSprite >(); // we're disposed + + return uno::Reference< rendering::XCustomSprite >( + new CanvasCustomSprite( spriteSize, + mpSpriteSurface, + mpRenderModule, + mpSurfaceProxy, + mbShowSpriteBounds ) ); + } + + uno::Reference< rendering::XSprite > SpriteCanvasHelper::createClonedSprite( const uno::Reference< rendering::XSprite >& /*original*/ ) + { + return uno::Reference< rendering::XSprite >(); + } + + sal_Bool SpriteCanvasHelper::updateScreen( const ::basegfx::B2IRectangle& rCurrArea, + sal_Bool bUpdateAll, + bool& io_bSurfaceDirty ) + { + if( !mpRedrawManager || + !mpRenderModule || + !mpBackBuffer ) + { + return sal_False; // disposed, or otherwise dysfunctional + } + +#if defined(DX_DEBUG_IMAGES) +# if OSL_DEBUG_LEVEL > 0 + mpBackBuffer->imageDebugger(); +# endif +#endif + + // store current output area (need to tunnel that to the + // background, scroll, opaque and general sprite repaint + // routines) + maScrapRect = rCurrArea; + + // clear area that needs to be blitted to screen beforehand + maUpdateRect.reset(); + + // TODO(P1): Might be worthwile to track areas of background + // changes, too. + + // TODO(P2): Might be worthwhile to use page-flipping only if + // a certain percentage of screen area has changed - and + // compose directly to the front buffer otherwise. + if( !bUpdateAll && !io_bSurfaceDirty ) + { + // background has not changed, so we're free to optimize + // repaint to areas where a sprite has changed + + // process each independent area of overlapping sprites + // separately. + mpRedrawManager->forEachSpriteArea( *this ); + + // flip primary surface to screen + // ============================== + + // perform buffer flipping + mpRenderModule->flip( maUpdateRect, + rCurrArea ); + } + else + { + // limit update to parent window area (ignored for fullscreen) + // TODO(E1): Use numeric_cast to catch overflow here + const ::basegfx::B2IRectangle aUpdateArea( 0,0, + static_cast<sal_Int32>(rCurrArea.getWidth()), + static_cast<sal_Int32>(rCurrArea.getHeight()) ); + + // background has changed, or called requested full + // update, or we're performing double buffering via page + // flipping, so we currently have no choice but repaint + // everything + + // repaint the whole screen with background content + mpBackBuffer->draw(aUpdateArea); + + // redraw sprites + mpRedrawManager->forEachSprite(::std::ptr_fun( &spriteRedraw ) ); + + // flip primary surface to screen + // ============================== + + // perform buffer flipping + mpRenderModule->flip( aUpdateArea, + rCurrArea ); + } + + // change record vector must be cleared, for the next turn of + // rendering and sprite changing + mpRedrawManager->clearChangeRecords(); + + io_bSurfaceDirty = false; + + return sal_True; + } + + void SpriteCanvasHelper::backgroundPaint( const ::basegfx::B2DRange& rUpdateRect ) + { + ENSURE_OR_THROW( mpRenderModule && + mpBackBuffer, + "SpriteCanvasHelper::backgroundPaint(): NULL device pointer " ); + + repaintBackground( rUpdateRect, + maScrapRect, + mpBackBuffer ); + } + + void SpriteCanvasHelper::scrollUpdate( const ::basegfx::B2DRange& /*rMoveStart*/, + const ::basegfx::B2DRange& rMoveEnd, + const ::canvas::SpriteRedrawManager::UpdateArea& rUpdateArea ) + { + ENSURE_OR_THROW( mpRenderModule && + mpBackBuffer, + "SpriteCanvasHelper::scrollUpdate(): NULL device pointer " ); + + // round rectangles to integer pixel. Note: have to be + // extremely careful here, to avoid off-by-one errors for + // the destination area: otherwise, the next scroll update + // would copy pixel that are not supposed to be part of + // the sprite. + const ::basegfx::B2IRange& rDestRect( + ::canvas::tools::spritePixelAreaFromB2DRange( rMoveEnd ) ); + + // not much sense in really implementing scrollUpdate here, + // since outputting a sprite only partially would result in + // expensive clipping. Furthermore, we cannot currently render + // 3D directly to the front buffer, thus, would have to blit + // the full sprite area, anyway. But at least optimized in the + // sense that unnecessary background paints behind the sprites + // are avoided. + ::std::for_each( rUpdateArea.maComponentList.begin(), + rUpdateArea.maComponentList.end(), + ::std::ptr_fun( &spriteRedrawStub2 ) ); + + // repaint uncovered areas from backbuffer - take the + // _rounded_ rectangles from above, to have the update + // consistent with the scroll above. + ::std::vector< ::basegfx::B2DRange > aUncoveredAreas; + ::basegfx::computeSetDifference( aUncoveredAreas, + rUpdateArea.maTotalBounds, + ::basegfx::B2DRange( rDestRect ) ); + ::std::for_each( aUncoveredAreas.begin(), + aUncoveredAreas.end(), + ::boost::bind( &repaintBackground, + _1, + ::boost::cref(maScrapRect), + ::boost::cref(mpBackBuffer) ) ); + + // TODO(E1): Use numeric_cast to catch overflow here + ::basegfx::B2IRange aActualArea( 0, 0, + static_cast<sal_Int32>(maScrapRect.getWidth()), + static_cast<sal_Int32>(maScrapRect.getHeight()) ); + aActualArea.intersect( fround( rUpdateArea.maTotalBounds ) ); + + // add given update area to the 'blit to foreground' rect + maUpdateRect.expand( aActualArea ); + } + + void SpriteCanvasHelper::opaqueUpdate( const ::basegfx::B2DRange& rTotalArea, + const ::std::vector< ::canvas::Sprite::Reference >& rSortedUpdateSprites ) + { + ENSURE_OR_THROW( mpRenderModule && + mpBackBuffer, + "SpriteCanvasHelper::opaqueUpdate(): NULL device pointer " ); + + // TODO(P2): optimize this by truly rendering to the front + // buffer. Currently, we've the 3D device only for the back + // buffer. + ::std::for_each( rSortedUpdateSprites.begin(), + rSortedUpdateSprites.end(), + ::std::ptr_fun( &spriteRedrawStub ) ); + + // TODO(E1): Use numeric_cast to catch overflow here + ::basegfx::B2IRange aActualArea( 0, 0, + static_cast<sal_Int32>(maScrapRect.getWidth()), + static_cast<sal_Int32>(maScrapRect.getHeight()) ); + aActualArea.intersect( fround( rTotalArea ) ); + + // add given update area to the 'blit to foreground' rect + maUpdateRect.expand( aActualArea ); + } + + void SpriteCanvasHelper::genericUpdate( const ::basegfx::B2DRange& rTotalArea, + const ::std::vector< ::canvas::Sprite::Reference >& rSortedUpdateSprites ) + { + ENSURE_OR_THROW( mpRenderModule && + mpBackBuffer, + "SpriteCanvasHelper::genericUpdate(): NULL device pointer " ); + + // paint background + // ================ + + // TODO(E1): Use numeric_cast to catch overflow here + ::basegfx::B2IRange aActualArea( 0, 0, + static_cast<sal_Int32>(maScrapRect.getWidth()), + static_cast<sal_Int32>(maScrapRect.getHeight()) ); + aActualArea.intersect( fround( rTotalArea ) ); + + // repaint the given area of the screen with background content + mpBackBuffer->draw(aActualArea); + + // paint sprite + // ============ + + ::std::for_each( rSortedUpdateSprites.begin(), + rSortedUpdateSprites.end(), + ::std::ptr_fun( &spriteRedrawStub ) ); + + // add given update area to the 'blit to foreground' rect + maUpdateRect.expand( aActualArea ); + } +} diff --git a/canvas/source/directx/dx_spritecanvashelper.hxx b/canvas/source/directx/dx_spritecanvashelper.hxx new file mode 100755 index 000000000000..d1825670cafc --- /dev/null +++ b/canvas/source/directx/dx_spritecanvashelper.hxx @@ -0,0 +1,164 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_spritecanvashelper.hxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _DXCANVAS_SPRITECANVASHELPER_HXX_ +#define _DXCANVAS_SPRITECANVASHELPER_HXX_ + +#include <com/sun/star/rendering/XSpriteCanvas.hpp> +#include <com/sun/star/rendering/XIntegerBitmap.hpp> + +#include <canvas/spriteredrawmanager.hxx> +#include <canvas/rendering/isurfaceproxy.hxx> +#include <canvas/rendering/isurfaceproxymanager.hxx> + +#include "dx_bitmapcanvashelper.hxx" +#include "dx_impltools.hxx" +#include "dx_rendermodule.hxx" +#include "dx_surfacebitmap.hxx" + +#include <basegfx/range/b2irectangle.hxx> + +namespace dxcanvas +{ + class SpriteCanvas; + + class SpriteCanvasHelper : public BitmapCanvasHelper + { + public: + SpriteCanvasHelper(); + + void init( SpriteCanvas& rParent, + ::canvas::SpriteRedrawManager& rManager, + const IDXRenderModuleSharedPtr& rRenderModule, + const ::canvas::ISurfaceProxyManagerSharedPtr& rSurfaceProxy, + const DXSurfaceBitmapSharedPtr& rBackBuffer, + const ::basegfx::B2ISize& rOutputOffset ); + + /// Dispose all internal references + void disposing(); + + // XSpriteCanvas + ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XAnimatedSprite > createSpriteFromAnimation( + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XAnimation >& animation ); + + ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XAnimatedSprite > createSpriteFromBitmaps( + const ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XBitmap > >& animationBitmaps, + sal_Int8 interpolationMode ); + + ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XCustomSprite > createCustomSprite( + const ::com::sun::star::geometry::RealSize2D& spriteSize ); + + ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XSprite > createClonedSprite( + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XSprite >& original ); + + /** Actually perform the screen update + + @param rCurrArea + Current window area in absolute screen coordinates + + @param bUpdateAll + sal_True, if everything must be updated, not only changed + sprites + + @param io_bSurfaceDirty + In/out parameter, whether backbuffer surface is dirty (if + yes, we're performing a full update, anyway) + */ + sal_Bool updateScreen( const ::basegfx::B2IRectangle& rCurrArea, + sal_Bool bUpdateAll, + bool& io_bSurfaceDirty ); + + + // SpriteRedrawManager functor calls + // ------------------------------------------------- + + /** Gets called for simple background repaints + */ + void backgroundPaint( const ::basegfx::B2DRange& rUpdateRect ); + + /** Gets called when area can be handled by scrolling. + + Called method must copy screen content from rMoveStart to + rMoveEnd, and restore the background in the uncovered + areas. + + @param rMoveStart + Source rect of the scroll + + @param rMoveEnd + Dest rect of the scroll + + @param rUpdateArea + All info necessary, should rMoveStart be partially or + fully outside the outdev + */ + void scrollUpdate( const ::basegfx::B2DRange& rMoveStart, + const ::basegfx::B2DRange& rMoveEnd, + const ::canvas::SpriteRedrawManager::UpdateArea& rUpdateArea ); + + void opaqueUpdate( const ::basegfx::B2DRange& rTotalArea, + const ::std::vector< ::canvas::Sprite::Reference >& rSortedUpdateSprites ); + + void genericUpdate( const ::basegfx::B2DRange& rTotalArea, + const ::std::vector< ::canvas::Sprite::Reference >& rSortedUpdateSprites ); + + private: + /// For generating sprites + SpriteCanvas* mpSpriteSurface; + + /// Set from the SpriteCanvas: instance coordinating sprite redraw + ::canvas::SpriteRedrawManager* mpRedrawManager; + + /// DX device, handling all low-level rendering + IDXRenderModuleSharedPtr mpRenderModule; + + ::canvas::ISurfaceProxyManagerSharedPtr mpSurfaceProxy; + + /// Backbuffer, contains the static canvas render output + DXSurfaceBitmapSharedPtr mpBackBuffer; + + /// Completely temporary rect storage (used by sprite repaint) + mutable ::basegfx::B2IRange maUpdateRect; + + /// Completely temporary rect storage (used by sprite repaint) + mutable ::basegfx::B2IRange maScrapRect; + + /// When true, show small bound rects around each sprite + bool mbShowSpriteBounds; + }; +} + +#endif /* _DXCANVAS_SPRITECANVASHELPER_HXX_ */ diff --git a/canvas/source/directx/dx_spritedevicehelper.cxx b/canvas/source/directx/dx_spritedevicehelper.cxx new file mode 100644 index 000000000000..ba997f18f8b6 --- /dev/null +++ b/canvas/source/directx/dx_spritedevicehelper.cxx @@ -0,0 +1,262 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_spritedevicehelper.cxx,v $ + * $Revision: 1.2 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <ctype.h> // don't ask. msdev breaks otherwise... +#include <vcl/window.hxx> +#include <canvas/debug.hxx> +#include <canvas/verbosetrace.hxx> +#include <canvas/canvastools.hxx> +#include <tools/diagnose_ex.h> + +#include <osl/mutex.hxx> +#include <cppuhelper/compbase1.hxx> + +#include <com/sun/star/lang/NoSupportException.hpp> +#include <toolkit/helper/vclunohelper.hxx> +#include <basegfx/tools/canvastools.hxx> +#include "dx_linepolypolygon.hxx" +#include "dx_spritecanvas.hxx" +#include "dx_canvasbitmap.hxx" +#include "dx_spritedevicehelper.hxx" + + +#undef WB_LEFT +#undef WB_RIGHT +#include "dx_winstuff.hxx" + + +#include <vcl/sysdata.hxx> + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + SpriteDeviceHelper::SpriteDeviceHelper() : + DeviceHelper(), + mpSpriteCanvas( NULL ), + mpSurfaceProxyManager(), + mpRenderModule(), + mpBackBuffer() + { + } + + void SpriteDeviceHelper::init( Window& rWindow, + SpriteCanvas& rSpriteCanvas, + const awt::Rectangle& rRect, + bool /*bFullscreen*/ ) + { + // #i60490# ensure backbuffer has sensible minimal size + const sal_Int32 w( ::std::max(sal_Int32(1),sal_Int32(rRect.Width))); + const sal_Int32 h( ::std::max(sal_Int32(1),sal_Int32(rRect.Height))); + + rSpriteCanvas.setWindow( + uno::Reference<awt::XWindow2>( + VCLUnoHelper::GetInterface(&rWindow), + uno::UNO_QUERY_THROW) ); + + const SystemEnvData *pData = rWindow.GetSystemData(); + const HWND hWnd = reinterpret_cast<HWND>(pData->hWnd); + if( !IsWindow( hWnd ) ) + throw lang::NoSupportException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "Passed window has invalid system window, or canvas out-of-process!")), + NULL); + + mpSpriteCanvas = &rSpriteCanvas; + + try + { + // setup directx rendermodule + mpRenderModule = createRenderModule( rWindow ); + } + catch (...) { + + throw lang::NoSupportException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "Could not create DirectX device!") ), + static_cast< ::cppu::OWeakObject* >(&rSpriteCanvas) ); + } + + // create the surfaceproxy manager + mpSurfaceProxyManager = ::canvas::createSurfaceProxyManager( mpRenderModule ); + + // #i60490# ensure backbuffer has sensible minimal size + mpBackBuffer.reset(new DXSurfaceBitmap( + ::basegfx::B2ISize(w,h), + mpSurfaceProxyManager, + mpRenderModule, + false)); + + // Assumes: SystemChildWindow() has CS_OWNDC + DeviceHelper::init(GetDC(mpRenderModule->getHWND()), + rSpriteCanvas); + } + + void SpriteDeviceHelper::disposing() + { + // release all references + mpBackBuffer.reset(); + mpSurfaceProxyManager.reset(); + mpRenderModule.reset(); + mpSpriteCanvas = NULL; + + DeviceHelper::disposing(); + } + + uno::Reference< rendering::XBitmap > SpriteDeviceHelper::createCompatibleBitmap( + const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/, + const geometry::IntegerSize2D& size ) + { + if( !getDevice() ) + return uno::Reference< rendering::XBitmap >(); // we're disposed + + DXSurfaceBitmapSharedPtr pBitmap( + new DXSurfaceBitmap( + ::basegfx::unotools::b2ISizeFromIntegerSize2D(size), + mpSurfaceProxyManager, + mpRenderModule, + false)); + + // create a 24bit RGB system memory surface + return uno::Reference< rendering::XBitmap >(new CanvasBitmap(pBitmap,getDevice())); + } + + uno::Reference< rendering::XVolatileBitmap > SpriteDeviceHelper::createVolatileBitmap( + const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/, + const geometry::IntegerSize2D& /*size*/ ) + { + return uno::Reference< rendering::XVolatileBitmap >(); + } + + uno::Reference< rendering::XBitmap > SpriteDeviceHelper::createCompatibleAlphaBitmap( + const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/, + const geometry::IntegerSize2D& size ) + { + if( !getDevice() ) + return uno::Reference< rendering::XBitmap >(); // we're disposed + + DXSurfaceBitmapSharedPtr pBitmap( + new DXSurfaceBitmap( + ::basegfx::unotools::b2ISizeFromIntegerSize2D(size), + mpSurfaceProxyManager, + mpRenderModule, + true)); + + // create a 32bit ARGB system memory surface + return uno::Reference< rendering::XBitmap >(new CanvasBitmap(pBitmap,getDevice())); + } + + uno::Reference< rendering::XVolatileBitmap > SpriteDeviceHelper::createVolatileAlphaBitmap( + const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/, + const geometry::IntegerSize2D& /*size*/ ) + { + return uno::Reference< rendering::XVolatileBitmap >(); + } + + sal_Bool SpriteDeviceHelper::hasFullScreenMode() + { + // TODO(F3): offer fullscreen mode the XCanvas way + return false; + } + + sal_Bool SpriteDeviceHelper::enterFullScreenMode( sal_Bool /*bEnter*/ ) + { + // TODO(F3): offer fullscreen mode the XCanvas way + return false; + } + + ::sal_Int32 SpriteDeviceHelper::createBuffers( ::sal_Int32 /*nBuffers*/ ) + { + // TODO(F3): implement XBufferStrategy interface. For now, we + // _always_ will have exactly one backbuffer + return 1; + } + + void SpriteDeviceHelper::destroyBuffers() + { + // TODO(F3): implement XBufferStrategy interface. For now, we + // _always_ will have exactly one backbuffer + } + + ::sal_Bool SpriteDeviceHelper::showBuffer( bool, ::sal_Bool ) + { + OSL_ENSURE(false,"Not supposed to be called, handled by SpriteCanvas"); + return sal_False; + } + + ::sal_Bool SpriteDeviceHelper::switchBuffer( bool, ::sal_Bool ) + { + OSL_ENSURE(false,"Not supposed to be called, handled by SpriteCanvas"); + return sal_False; + } + + uno::Any SpriteDeviceHelper::isAccelerated() const + { + return ::com::sun::star::uno::makeAny(true); + } + + void SpriteDeviceHelper::notifySizeUpdate( const awt::Rectangle& rBounds ) + { + // #i60490# ensure backbuffer has sensible minimal size + const sal_Int32 x(rBounds.X); + const sal_Int32 y(rBounds.Y); + const sal_Int32 w(::std::max(sal_Int32(1),sal_Int32(rBounds.Width))); + const sal_Int32 h(::std::max(sal_Int32(1),sal_Int32(rBounds.Height))); + + if( mpRenderModule ) + mpRenderModule->resize(::basegfx::B2IRange(x,y,x+w,y+h)); + + resizeBackBuffer(::basegfx::B2ISize(w,h)); + } + + void SpriteDeviceHelper::resizeBackBuffer( const ::basegfx::B2ISize& rNewSize ) + { + // disposed? + if(!(mpBackBuffer)) + return; + + mpBackBuffer->resize(rNewSize); + mpBackBuffer->clear(); + } + + HWND SpriteDeviceHelper::getHwnd() const + { + if( mpRenderModule ) + return mpRenderModule->getHWND(); + else + return 0; + } + + void SpriteDeviceHelper::dumpScreenContent() const + { + if( mpRenderModule ) + mpRenderModule->screenShot(); + } +} diff --git a/canvas/source/directx/dx_spritedevicehelper.hxx b/canvas/source/directx/dx_spritedevicehelper.hxx new file mode 100644 index 000000000000..9e3f4727cfce --- /dev/null +++ b/canvas/source/directx/dx_spritedevicehelper.hxx @@ -0,0 +1,117 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_spritedevicehelper.hxx,v $ + * $Revision: 1.2 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _DXCANVAS_SPRITEDEVICEHELPER_HXX +#define _DXCANVAS_SPRITEDEVICEHELPER_HXX + +#include <com/sun/star/awt/Rectangle.hpp> +#include <com/sun/star/rendering/XGraphicDevice.hpp> +#include <com/sun/star/rendering/XBufferController.hpp> + +#include "dx_rendermodule.hxx" +#include "dx_surfacebitmap.hxx" +#include "dx_devicehelper.hxx" + +#include <canvas/rendering/isurfaceproxymanager.hxx> + +#include <boost/utility.hpp> + + +namespace dxcanvas +{ + class SpriteCanvas; + class SpriteCanvasHelper; + + class SpriteDeviceHelper : public DeviceHelper + { + public: + SpriteDeviceHelper(); + + void init( Window& rWindow, + SpriteCanvas& rSpriteCanvas, + const ::com::sun::star::awt::Rectangle& rRect, + bool bFullscreen ); + + /// Dispose all internal references + void disposing(); + + // partial override XWindowGraphicDevice + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmap > createCompatibleBitmap( + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice >& rDevice, + const ::com::sun::star::geometry::IntegerSize2D& size ); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XVolatileBitmap > createVolatileBitmap( + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice >& rDevice, + const ::com::sun::star::geometry::IntegerSize2D& size ); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmap > createCompatibleAlphaBitmap( + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice >& rDevice, + const ::com::sun::star::geometry::IntegerSize2D& size ); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XVolatileBitmap > createVolatileAlphaBitmap( + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice >& rDevice, + const ::com::sun::star::geometry::IntegerSize2D& size ); + + sal_Bool hasFullScreenMode( ); + sal_Bool enterFullScreenMode( sal_Bool bEnter ); + + ::sal_Int32 createBuffers( ::sal_Int32 nBuffers ); + void destroyBuffers( ); + ::sal_Bool showBuffer( bool bIsVisible, ::sal_Bool bUpdateAll ); + ::sal_Bool switchBuffer( bool bIsVisible, ::sal_Bool bUpdateAll ); + + const IDXRenderModuleSharedPtr& getRenderModule() const { return mpRenderModule; } + const DXSurfaceBitmapSharedPtr& getBackBuffer() const { return mpBackBuffer; } + const ::canvas::ISurfaceProxyManagerSharedPtr &getSurfaceProxy() const { return mpSurfaceProxyManager; } + + ::com::sun::star::uno::Any isAccelerated() const; + + void notifySizeUpdate( const ::com::sun::star::awt::Rectangle& rBounds ); + + /** called when DumpScreenContent property is enabled on + XGraphicDevice, and writes out bitmaps of current screen. + */ + void dumpScreenContent() const; + + private: + void resizeBackBuffer( const ::basegfx::B2ISize& rNewSize ); + HWND getHwnd() const; + + /// Pointer to sprite canvas (owner of this helper), needed to create bitmaps + SpriteCanvas* mpSpriteCanvas; + + DXSurfaceBitmapSharedPtr mpBackBuffer; + + /// Instance passing out HW textures + ::canvas::ISurfaceProxyManagerSharedPtr mpSurfaceProxyManager; + + /// Our encapsulation interface to DirectX + IDXRenderModuleSharedPtr mpRenderModule; + }; +} + +#endif /* _DXCANVAS_SPRITEDEVICEHELPER_HXX */ diff --git a/canvas/source/directx/dx_spritehelper.cxx b/canvas/source/directx/dx_spritehelper.cxx new file mode 100755 index 000000000000..f68c703b9e12 --- /dev/null +++ b/canvas/source/directx/dx_spritehelper.cxx @@ -0,0 +1,219 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_spritehelper.cxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <ctype.h> // don't ask. msdev breaks otherwise... +#include <canvas/debug.hxx> +#include <canvas/verbosetrace.hxx> +#include <tools/diagnose_ex.h> + +#include <rtl/logfile.hxx> +#include <rtl/math.hxx> + +#include <canvas/canvastools.hxx> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/numeric/ftools.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolypolygonrasterconverter.hxx> +#include <basegfx/polygon/b2dpolygontriangulator.hxx> +#include <basegfx/polygon/b2dpolygoncutandtouch.hxx> + +#include "dx_canvascustomsprite.hxx" +#include "dx_spritehelper.hxx" +#include "dx_impltools.hxx" + +#include <memory> + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + SpriteHelper::SpriteHelper() : + mpSpriteCanvas(), + mpBitmap(), + mbTextureDirty( true ), + mbShowSpriteBounds( false ) + { + } + + void SpriteHelper::init( const geometry::RealSize2D& rSpriteSize, + const SpriteCanvasRef& rSpriteCanvas, + const IDXRenderModuleSharedPtr& rRenderModule, + const DXSurfaceBitmapSharedPtr rBitmap, + bool bShowSpriteBounds ) + { + ENSURE_OR_THROW( rSpriteCanvas.get() && + rRenderModule && + rBitmap, + "SpriteHelper::init(): Invalid device, sprite canvas or surface" ); + + mpSpriteCanvas = rSpriteCanvas; + mpBitmap = rBitmap; + mbTextureDirty = true; + mbShowSpriteBounds = bShowSpriteBounds; + + // also init base class + CanvasCustomSpriteHelper::init( rSpriteSize, + rSpriteCanvas.get() ); + } + + void SpriteHelper::disposing() + { + mpBitmap.reset(); + mpSpriteCanvas.clear(); + + // forward to parent + CanvasCustomSpriteHelper::disposing(); + } + + ::basegfx::B2DPolyPolygon SpriteHelper::polyPolygonFromXPolyPolygon2D( uno::Reference< rendering::XPolyPolygon2D >& xPoly ) const + { + return tools::polyPolygonFromXPolyPolygon2D( xPoly ); + } + + bool SpriteHelper::needRedraw() const + { + if( !mpBitmap || + !mpSpriteCanvas.get() ) + { + return false; // we're disposed, no redraw necessary + } + + if( !isActive() || + ::basegfx::fTools::equalZero( getAlpha() ) ) + { + return false; // sprite is invisible + } + + return true; + } + + void SpriteHelper::redraw( bool& io_bSurfaceDirty ) const + { + if( !mpBitmap || + !mpSpriteCanvas.get() ) + { + return; // we're disposed + } + + const ::basegfx::B2DPoint& rPos( getPosPixel() ); + const double fAlpha( getAlpha() ); + + if( isActive() && + !::basegfx::fTools::equalZero( fAlpha ) ) + { + + // TODO(Q2): For the time being, Device does not take a target + // surface, but always unconditionally renders to the + // background buffer. + + // log output pos in device pixel + VERBOSE_TRACE( "SpriteHelper::redraw(): output pos is (%f, %f)", + rPos.getX(), + rPos.getY() ); + + const double fAlpha( getAlpha() ); + const ::basegfx::B2DVector& rSize( getSizePixel() ); + const ::basegfx::B2DHomMatrix& rTransform( getTransformation() ); + const uno::Reference< rendering::XPolyPolygon2D >& xClip( getClip() ); + + mbTextureDirty = false; + io_bSurfaceDirty = false; // state taken, and processed. + + ::basegfx::B2DPolyPolygon aClipPath; // empty for no clip + bool bIsClipRectangular( false ); // false, if no + // clip, or clip + // is complex + + // setup and apply clip (if any) + // ================================= + + if( xClip.is() ) + { + aClipPath = tools::polyPolygonFromXPolyPolygon2D( xClip ); + + const sal_Int32 nNumClipPolygons( aClipPath.count() ); + if( nNumClipPolygons ) + { + // TODO(P2): hold rectangle attribute directly + // at the XPolyPolygon2D + + // check whether the clip is rectangular + if( nNumClipPolygons == 1 ) + if( ::basegfx::tools::isRectangle( aClipPath.getB2DPolygon( 0 ) ) ) + bIsClipRectangular = true; + } + } + + const ::basegfx::B2DRectangle aSourceRect( 0.0, + 0.0, + rSize.getX(), + rSize.getY() ); + + // draw simple rectangular area if no clip is set. + if( !aClipPath.count() ) + { + mpBitmap->draw(fAlpha,rPos,rTransform); + } + else if( bIsClipRectangular ) + { + // apply a simple rect clip + // ======================== + + ::basegfx::B2DRectangle aClipBounds( + ::basegfx::tools::getRange( aClipPath ) ); + aClipBounds.intersect( aSourceRect ); + + mpBitmap->draw(fAlpha,rPos,aClipBounds,rTransform); + } + else + { + // apply clip the hard way + // ======================= + + mpBitmap->draw(fAlpha,rPos,aClipPath,rTransform); + } + + if( mbShowSpriteBounds ) + { + if( aClipPath.count() ) + { + // TODO(F2): Re-enable debug output + } + } + } + } +} diff --git a/canvas/source/directx/dx_spritehelper.hxx b/canvas/source/directx/dx_spritehelper.hxx new file mode 100755 index 000000000000..c246467b8eb8 --- /dev/null +++ b/canvas/source/directx/dx_spritehelper.hxx @@ -0,0 +1,114 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_spritehelper.hxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _DXCANVAS_SPRITEHELPER_HXX +#define _DXCANVAS_SPRITEHELPER_HXX + +#include <com/sun/star/rendering/XCustomSprite.hpp> + +#include <canvas/base/canvascustomspritehelper.hxx> + +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/vector/b2isize.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> + +#include "dx_spritecanvas.hxx" +#include "dx_surfacebitmap.hxx" + +namespace dxcanvas +{ + /* Definition of SpriteHelper class */ + + /** Helper class for canvas sprites. + + This class implements all sprite-related functionality, like + that available on the XSprite interface. + */ + class SpriteHelper : public ::canvas::CanvasCustomSpriteHelper + { + public: + /** Create sprite helper + */ + SpriteHelper(); + + /** Late-init the sprite helper + + @param rSpriteSize + Size of the sprite + + @param rSpriteCanvas + Sprite canvas this sprite is part of. Object stores + ref-counted reference to it, thus, don't forget to pass on + disposing()! + + @param rRenderModule + rendermodule to use + + @param rSpriteSurface + The surface of the sprite (not the DX texture, but the + persistent target of content rendering) + + @param bShowSpriteBounds + When true, little debug bound rects for sprites are shown + */ + void init( const ::com::sun::star::geometry::RealSize2D& rSpriteSize, + const SpriteCanvasRef& rSpriteCanvas, + const IDXRenderModuleSharedPtr& rRenderModule, + const DXSurfaceBitmapSharedPtr rBitmap, + bool bShowSpriteBounds ); + + void disposing(); + + /** Repaint sprite content via hardware to associated sprite + canvas + + @param io_bSurfaceDirty + Input/output parameter, whether the sprite content is + dirty or not. If texture was updated, set to false + + */ + void redraw( bool& io_bSurfaceDirty ) const; + + private: + virtual ::basegfx::B2DPolyPolygon polyPolygonFromXPolyPolygon2D( + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XPolyPolygon2D >& xPoly ) const; + + /// Returns true, if the sprite _really_ needs redraw + bool needRedraw() const; + + SpriteCanvasRef mpSpriteCanvas; + + DXSurfaceBitmapSharedPtr mpBitmap; + mutable bool mbTextureDirty; // when true, texture needs update + bool mbShowSpriteBounds; // when true, debug bound rect for sprites is shown + }; +} + +#endif /* _DXCANVAS_SPRITEHELPER_HXX */ diff --git a/canvas/source/directx/dx_surfacebitmap.cxx b/canvas/source/directx/dx_surfacebitmap.cxx new file mode 100644 index 000000000000..e82f814d3b23 --- /dev/null +++ b/canvas/source/directx/dx_surfacebitmap.cxx @@ -0,0 +1,807 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_surfacebitmap.cxx,v $ + * $Revision: 1.2 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include "dx_surfacebitmap.hxx" +#include "dx_impltools.hxx" +#include "dx_surfacegraphics.hxx" +#include "dx_graphicsprovider.hxx" + +#include <canvas/debug.hxx> +#include <tools/diagnose_ex.h> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/range/b2irange.hxx> + +#if defined(DX_DEBUG_IMAGES) +# if OSL_DEBUG_LEVEL > 0 +# include <imdebug.h> +# undef min +# undef max +# endif +#endif + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + namespace + { + ////////////////////////////////////////////////////////////////////////////////// + // DXColorBuffer + ////////////////////////////////////////////////////////////////////////////////// + + struct DXColorBuffer : public canvas::IColorBuffer + { + public: + DXColorBuffer( const COMReference<surface_type>& rSurface, + const ::basegfx::B2IVector& rSize ) : + mpSurface(rSurface), + maSize(rSize), + mbAlpha(false) + { + } + + // implementation of the 'IColorBuffer' interface + public: + + virtual sal_uInt8* lock() const; + virtual void unlock() const; + virtual sal_uInt32 getWidth() const; + virtual sal_uInt32 getHeight() const; + virtual sal_uInt32 getStride() const; + virtual Format getFormat() const; + + private: + + ::basegfx::B2IVector maSize; +#if DIRECTX_VERSION < 0x0900 + mutable DDSURFACEDESC aSurfaceDesc; +#else + mutable D3DLOCKED_RECT maLockedRect; +#endif + mutable COMReference<surface_type> mpSurface; + bool mbAlpha; + }; + + sal_uInt8* DXColorBuffer::lock() const + { +#if DIRECTX_VERSION < 0x0900 + rtl_fillMemory((void *)&aSurfaceDesc,sizeof(DDSURFACEDESC),0); + aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC); + const DWORD dwFlags = DDLOCK_NOSYSLOCK|DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT|DDLOCK_READONLY; + if(SUCCEEDED(mpSurface->Lock(NULL,&aSurfaceDesc,dwFlags,NULL))) + return static_cast<sal_uInt8 *>(aSurfaceDesc.lpSurface); +#else + if(SUCCEEDED(mpSurface->LockRect(&maLockedRect,NULL,D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY))) + return static_cast<sal_uInt8 *>(maLockedRect.pBits); +#endif + return NULL; + } + + void DXColorBuffer::unlock() const + { +#if DIRECTX_VERSION < 0x0900 + mpSurface->Unlock(NULL); +#else + mpSurface->UnlockRect(); +#endif + } + + sal_uInt32 DXColorBuffer::getWidth() const + { + return maSize.getX(); + } + + sal_uInt32 DXColorBuffer::getHeight() const + { + return maSize.getY(); + } + + sal_uInt32 DXColorBuffer::getStride() const + { +#if DIRECTX_VERSION < 0x0900 + return aSurfaceDesc.lPitch; +#else + return maLockedRect.Pitch; +#endif + } + + canvas::IColorBuffer::Format DXColorBuffer::getFormat() const + { + return canvas::IColorBuffer::FMT_X8R8G8B8; + } + + ////////////////////////////////////////////////////////////////////////////////// + // GDIColorBuffer + ////////////////////////////////////////////////////////////////////////////////// + + struct GDIColorBuffer : public canvas::IColorBuffer + { + public: + + GDIColorBuffer( const BitmapSharedPtr& rSurface, + const ::basegfx::B2IVector& rSize ) : + mpGDIPlusBitmap(rSurface), + maSize(rSize), + mbAlpha(true) + { + } + + // implementation of the 'IColorBuffer' interface + public: + + virtual sal_uInt8* lock() const; + virtual void unlock() const; + virtual sal_uInt32 getWidth() const; + virtual sal_uInt32 getHeight() const; + virtual sal_uInt32 getStride() const; + virtual Format getFormat() const; + + private: + + ::basegfx::B2IVector maSize; + mutable Gdiplus::BitmapData aBmpData; + BitmapSharedPtr mpGDIPlusBitmap; + bool mbAlpha; + }; + + sal_uInt8* GDIColorBuffer::lock() const + { + aBmpData.Width = maSize.getX(); + aBmpData.Height = maSize.getY(); + aBmpData.Stride = 4*aBmpData.Width; + aBmpData.PixelFormat = PixelFormat32bppARGB; + aBmpData.Scan0 = NULL; + const Gdiplus::Rect aRect( 0,0,aBmpData.Width,aBmpData.Height ); + if( Gdiplus::Ok != mpGDIPlusBitmap->LockBits( &aRect, + Gdiplus::ImageLockModeRead, + PixelFormat32bppARGB, + &aBmpData ) ) + { + return NULL; + } + + return static_cast<sal_uInt8*>(aBmpData.Scan0); + } + + void GDIColorBuffer::unlock() const + { + mpGDIPlusBitmap->UnlockBits( &aBmpData ); + } + + sal_uInt32 GDIColorBuffer::getWidth() const + { + return maSize.getX(); + } + + sal_uInt32 GDIColorBuffer::getHeight() const + { + return maSize.getY(); + } + + sal_uInt32 GDIColorBuffer::getStride() const + { + return aBmpData.Stride; + } + + canvas::IColorBuffer::Format GDIColorBuffer::getFormat() const + { + return canvas::IColorBuffer::FMT_A8R8G8B8; + } + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::DXSurfaceBitmap + ////////////////////////////////////////////////////////////////////////////////// + + DXSurfaceBitmap::DXSurfaceBitmap( const ::basegfx::B2IVector& rSize, + const canvas::ISurfaceProxyManagerSharedPtr& rMgr, + const IDXRenderModuleSharedPtr& rRenderModule, + bool bWithAlpha ) : + mpGdiPlusUser( GDIPlusUser::createInstance() ), + maSize(rSize), + mpRenderModule(rRenderModule), + mpSurfaceManager(rMgr), + mpSurfaceProxy(), + mpSurface(), + mpGDIPlusBitmap(), + mpGraphics(), + mpColorBuffer(), + mbIsSurfaceDirty(true), + mbAlpha(bWithAlpha) + { + init(); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::getSize + ////////////////////////////////////////////////////////////////////////////////// + + ::basegfx::B2IVector DXSurfaceBitmap::getSize() const + { + return maSize; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::init + ////////////////////////////////////////////////////////////////////////////////// + + void DXSurfaceBitmap::init() + { + // create container for pixel data + if(mbAlpha) + { + mpGDIPlusBitmap.reset( + new Gdiplus::Bitmap( + maSize.getX(), + maSize.getY(), + PixelFormat32bppARGB + )); + mpGraphics.reset( tools::createGraphicsFromBitmap(mpGDIPlusBitmap) ); + + // create the colorbuffer object, which is basically a simple + // wrapper around the directx surface. the colorbuffer is the + // interface which is used by the surfaceproxy to support any + // kind of underlying structure for the pixel data container. + mpColorBuffer.reset(new GDIColorBuffer(mpGDIPlusBitmap,maSize)); + } + else + { + mpSurface = mpRenderModule->createSystemMemorySurface(maSize); + + // create the colorbuffer object, which is basically a simple + // wrapper around the directx surface. the colorbuffer is the + // interface which is used by the surfaceproxy to support any + // kind of underlying structure for the pixel data container. + mpColorBuffer.reset(new DXColorBuffer(mpSurface,maSize)); + } + + // create a (possibly hardware accelerated) mirror surface. + mpSurfaceProxy = mpSurfaceManager->createSurfaceProxy(mpColorBuffer); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::resize + ////////////////////////////////////////////////////////////////////////////////// + + bool DXSurfaceBitmap::resize( const ::basegfx::B2IVector& rSize ) + { + if(maSize != rSize) + { + maSize = rSize; + init(); + } + + return true; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::clear + ////////////////////////////////////////////////////////////////////////////////// + + void DXSurfaceBitmap::clear() + { + GraphicsSharedPtr pGraphics(getGraphics()); + Gdiplus::Color transColor(255,0,0,0); + pGraphics->SetCompositingMode( Gdiplus::CompositingModeSourceCopy ); + pGraphics->Clear( transColor ); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::hasAlpha + ////////////////////////////////////////////////////////////////////////////////// + + bool DXSurfaceBitmap::hasAlpha() const + { + return mbAlpha; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::getGraphics + ////////////////////////////////////////////////////////////////////////////////// + + GraphicsSharedPtr DXSurfaceBitmap::getGraphics() + { + // since clients will most probably draw directly + // to the GDI+ bitmap, we need to mark it as dirty + // to ensure that the corrosponding dxsurface will + // be updated. + mbIsSurfaceDirty = true; + + if(hasAlpha()) + return mpGraphics; + else + return createSurfaceGraphics(mpSurface); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::getBitmap + ////////////////////////////////////////////////////////////////////////////////// + + BitmapSharedPtr DXSurfaceBitmap::getBitmap() const + { + if(hasAlpha()) + return mpGDIPlusBitmap; + + BitmapSharedPtr pResult; + +#if DIRECTX_VERSION < 0x0900 + DDSURFACEDESC aSurfaceDesc; + rtl_fillMemory(&aSurfaceDesc,sizeof(DDSURFACEDESC),0); + aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC); + const DWORD dwFlags = DDLOCK_NOSYSLOCK|DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT|DDLOCK_READONLY; + + // lock the directx surface to receive the pointer to the surface memory. + if(SUCCEEDED(mpSurface->Lock(NULL,&aSurfaceDesc,dwFlags,NULL))) + { + // decide about the format we pass the gdi+, the directx surface is always + // 32bit, either with or without alpha component. + Gdiplus::PixelFormat nFormat = hasAlpha() ? PixelFormat32bppARGB : PixelFormat32bppRGB; + + // construct a gdi+ bitmap from the raw pixel data. + pResult.reset(new Gdiplus::Bitmap( maSize.getX(),maSize.getY(), + aSurfaceDesc.lPitch, + nFormat, + (BYTE *)aSurfaceDesc.lpSurface )); + + // unlock the directx surface + mpSurface->Unlock(NULL); + } +#else + D3DLOCKED_RECT aLockedRect; + if(SUCCEEDED(mpSurface->LockRect(&aLockedRect,NULL,D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY))) + { + // decide about the format we pass the gdi+, the directx surface is always + // 32bit, either with or without alpha component. + Gdiplus::PixelFormat nFormat = hasAlpha() ? PixelFormat32bppARGB : PixelFormat32bppRGB; + + // construct a gdi+ bitmap from the raw pixel data. + pResult.reset(new Gdiplus::Bitmap( maSize.getX(),maSize.getY(), + aLockedRect.Pitch, + nFormat, + (BYTE *)aLockedRect.pBits )); + + mpSurface->UnlockRect(); + } +#endif + + return pResult; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::draw + ////////////////////////////////////////////////////////////////////////////////// + + bool DXSurfaceBitmap::draw( double fAlpha, + const ::basegfx::B2DPoint& rPos, + const ::basegfx::B2DPolyPolygon& rClipPoly, + const ::basegfx::B2DHomMatrix& rTransform ) + { + if( mbIsSurfaceDirty ) + { + mpSurfaceProxy->setColorBufferDirty(); + mbIsSurfaceDirty = false; + } + + return mpSurfaceProxy->draw( fAlpha, rPos, rClipPoly, rTransform ); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::draw + ////////////////////////////////////////////////////////////////////////////////// + + bool DXSurfaceBitmap::draw( double fAlpha, + const ::basegfx::B2DPoint& rPos, + const ::basegfx::B2DRange& rArea, + const ::basegfx::B2DHomMatrix& rTransform ) + { + if( mbIsSurfaceDirty ) + { + mpSurfaceProxy->setColorBufferDirty(); + mbIsSurfaceDirty = false; + } + + return mpSurfaceProxy->draw( fAlpha, rPos, rArea, rTransform ); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::draw + ////////////////////////////////////////////////////////////////////////////////// + + bool DXSurfaceBitmap::draw( double fAlpha, + const ::basegfx::B2DPoint& rPos, + const ::basegfx::B2DHomMatrix& rTransform ) + { + if( mbIsSurfaceDirty ) + { + mpSurfaceProxy->setColorBufferDirty(); + mbIsSurfaceDirty = false; + } + + return mpSurfaceProxy->draw( fAlpha, rPos, rTransform ); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::draw + ////////////////////////////////////////////////////////////////////////////////// + + bool DXSurfaceBitmap::draw( const ::basegfx::B2IRange& rArea ) + { + if( mbIsSurfaceDirty ) + { + mpSurfaceProxy->setColorBufferDirty(); + mbIsSurfaceDirty = false; + } + + const double fAlpha(1.0); + const ::basegfx::B2DHomMatrix aTransform; + const ::basegfx::B2DRange aIEEEArea( rArea ); + return mpSurfaceProxy->draw(fAlpha, + ::basegfx::B2DPoint(), + aIEEEArea, + aTransform); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::imageDebugger + ////////////////////////////////////////////////////////////////////////////////// +#if defined(DX_DEBUG_IMAGES) +# if OSL_DEBUG_LEVEL > 0 + void DXSurfaceBitmap::imageDebugger() + { +#if DIRECTX_VERSION < 0x0900 + DDSURFACEDESC aSurfaceDesc; + rtl_fillMemory( &aSurfaceDesc,sizeof(DDSURFACEDESC),0 ); + aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC); + + if( FAILED(mpSurface->Lock( NULL, + &aSurfaceDesc, + DDLOCK_NOSYSLOCK|DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT|DDLOCK_READONLY, + NULL)) ) + return; + + imdebug("bgra w=%d h=%d %p", aSurfaceDesc.dwWidth, aSurfaceDesc.dwHeight, aSurfaceDesc.lpSurface); + + mpSurface->Unlock(NULL); +#else + D3DLOCKED_RECT aLockedRect; + if( FAILED(mpSurface->LockRect(&aLockedRect,NULL,D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY)) ) + return; + + imdebug("bgra w=%d h=%d %p", maSize.getX(), + maSize.getY(), aLockedRect.pBits); + mpSurface->UnlockRect(); +#endif + } +# endif +#endif + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::getData + ////////////////////////////////////////////////////////////////////////////////// + + uno::Sequence< sal_Int8 > DXSurfaceBitmap::getData( rendering::IntegerBitmapLayout& /*bitmapLayout*/, + const geometry::IntegerRectangle2D& rect ) + { + if(hasAlpha()) + { + uno::Sequence< sal_Int8 > aRes( (rect.X2-rect.X1)*(rect.Y2-rect.Y1)*4 ); // TODO(F1): Be format-agnostic here + + const Gdiplus::Rect aRect( tools::gdiPlusRectFromIntegerRectangle2D( rect ) ); + + Gdiplus::BitmapData aBmpData; + aBmpData.Width = rect.X2-rect.X1; + aBmpData.Height = rect.Y2-rect.Y1; + aBmpData.Stride = 4*aBmpData.Width; + aBmpData.PixelFormat = PixelFormat32bppARGB; + aBmpData.Scan0 = aRes.getArray(); + + // TODO(F1): Support more pixel formats natively + + // read data from bitmap + if( Gdiplus::Ok != mpGDIPlusBitmap->LockBits( &aRect, + Gdiplus::ImageLockModeRead | Gdiplus::ImageLockModeUserInputBuf, + PixelFormat32bppARGB, // TODO(F1): Adapt to + // Graphics native + // format/change + // getMemoryLayout + &aBmpData ) ) + { + // failed to lock, bail out + return uno::Sequence< sal_Int8 >(); + } + + mpGDIPlusBitmap->UnlockBits( &aBmpData ); + + return aRes; + } + else + { + sal_uInt32 nWidth = rect.X2-rect.X1; + sal_uInt32 nHeight = rect.Y2-rect.Y1; + + uno::Sequence< sal_Int8 > aRes(nWidth*nHeight*4); + +#if DIRECTX_VERSION < 0x0900 + DDSURFACEDESC aSurfaceDesc; + rtl_fillMemory(&aSurfaceDesc,sizeof(DDSURFACEDESC),0); + aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC); + const DWORD dwFlags = DDLOCK_NOSYSLOCK|DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT|DDLOCK_READONLY; + + // lock the directx surface to receive the pointer to the surface memory. + if(FAILED(mpSurface->Lock(NULL,&aSurfaceDesc,dwFlags,NULL))) + return uno::Sequence< sal_Int8 >(); + + sal_uInt8 *pSrc = (sal_uInt8 *)((((BYTE *)aSurfaceDesc.lpSurface)+(rect.Y1*aSurfaceDesc.lPitch))+rect.X1); + sal_uInt8 *pDst = (sal_uInt8 *)aRes.getArray(); + sal_uInt32 nSegmentSizeInBytes = nWidth<<4; + for(sal_uInt32 y=0; y<nHeight; ++y) + { + rtl_copyMemory(pDst,pSrc,nSegmentSizeInBytes); + pDst += nSegmentSizeInBytes; + pSrc += aSurfaceDesc.lPitch; + } + + mpSurface->Unlock(NULL); +#else + D3DLOCKED_RECT aLockedRect; + if(FAILED(mpSurface->LockRect(&aLockedRect,NULL,D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY))) + return uno::Sequence< sal_Int8 >(); + + sal_uInt8 *pSrc = (sal_uInt8 *)((((BYTE *)aLockedRect.pBits)+(rect.Y1*aLockedRect.Pitch))+rect.X1); + sal_uInt8 *pDst = (sal_uInt8 *)aRes.getArray(); + sal_uInt32 nSegmentSizeInBytes = nWidth<<4; + for(sal_uInt32 y=0; y<nHeight; ++y) + { + rtl_copyMemory(pDst,pSrc,nSegmentSizeInBytes); + pDst += nSegmentSizeInBytes; + pSrc += aLockedRect.Pitch; + } + + mpSurface->UnlockRect(); +#endif + return aRes; + } + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::setData + ////////////////////////////////////////////////////////////////////////////////// + + void DXSurfaceBitmap::setData( const uno::Sequence< sal_Int8 >& data, + const rendering::IntegerBitmapLayout& /*bitmapLayout*/, + const geometry::IntegerRectangle2D& rect ) + { + if(hasAlpha()) + { + const Gdiplus::Rect aRect( tools::gdiPlusRectFromIntegerRectangle2D( rect ) ); + + Gdiplus::BitmapData aBmpData; + aBmpData.Width = rect.X2-rect.X1; + aBmpData.Height = rect.Y2-rect.Y1; + aBmpData.Stride = 4*aBmpData.Width; + aBmpData.PixelFormat = PixelFormat32bppARGB; + aBmpData.Scan0 = (void*)data.getConstArray(); + + // TODO(F1): Support more pixel formats natively + + if( Gdiplus::Ok != mpGDIPlusBitmap->LockBits( &aRect, + Gdiplus::ImageLockModeWrite | Gdiplus::ImageLockModeUserInputBuf, + PixelFormat32bppARGB, // TODO: Adapt to + // Graphics native + // format/change + // getMemoryLayout + &aBmpData ) ) + { + throw uno::RuntimeException(); + } + + // commit data to bitmap + mpGDIPlusBitmap->UnlockBits( &aBmpData ); + } + else + { + sal_uInt32 nWidth = rect.X2-rect.X1; + sal_uInt32 nHeight = rect.Y2-rect.Y1; + +#if DIRECTX_VERSION < 0x0900 + DDSURFACEDESC aSurfaceDesc; + rtl_fillMemory(&aSurfaceDesc,sizeof(DDSURFACEDESC),0); + aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC); + const DWORD dwFlags = DDLOCK_NOSYSLOCK|DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT|DDLOCK_WRITEONLY; + + // lock the directx surface to receive the pointer to the surface memory. + if(FAILED(mpSurface->Lock(NULL,&aSurfaceDesc,dwFlags,NULL))) + throw uno::RuntimeException(); + + sal_uInt8 *pSrc = (sal_uInt8 *)data.getConstArray(); + sal_uInt8 *pDst = (sal_uInt8 *)((((BYTE *)aSurfaceDesc.lpSurface)+(rect.Y1*aSurfaceDesc.lPitch))+rect.X1); + sal_uInt32 nSegmentSizeInBytes = nWidth<<4; + for(sal_uInt32 y=0; y<nHeight; ++y) + { + rtl_copyMemory(pDst,pSrc,nSegmentSizeInBytes); + pSrc += nSegmentSizeInBytes; + pDst += aSurfaceDesc.lPitch; + } + + mpSurface->Unlock(NULL); +#else + // lock the directx surface to receive the pointer to the surface memory. + D3DLOCKED_RECT aLockedRect; + if(FAILED(mpSurface->LockRect(&aLockedRect,NULL,D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY))) + throw uno::RuntimeException(); + + sal_uInt8 *pSrc = (sal_uInt8 *)data.getConstArray(); + sal_uInt8 *pDst = (sal_uInt8 *)((((BYTE *)aLockedRect.pBits)+(rect.Y1*aLockedRect.Pitch))+rect.X1); + sal_uInt32 nSegmentSizeInBytes = nWidth<<4; + for(sal_uInt32 y=0; y<nHeight; ++y) + { + rtl_copyMemory(pDst,pSrc,nSegmentSizeInBytes); + pSrc += nSegmentSizeInBytes; + pDst += aLockedRect.Pitch; + } + + mpSurface->UnlockRect(); +#endif + } + + mbIsSurfaceDirty = true; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::setPixel + ////////////////////////////////////////////////////////////////////////////////// + + void DXSurfaceBitmap::setPixel( const uno::Sequence< sal_Int8 >& color, + const rendering::IntegerBitmapLayout& /*bitmapLayout*/, + const geometry::IntegerPoint2D& pos ) + { + if(hasAlpha()) + { + const geometry::IntegerSize2D aSize( maSize.getX(),maSize.getY() ); + + ENSURE_ARG_OR_THROW( pos.X >= 0 && pos.X < aSize.Width, + "CanvasHelper::setPixel: X coordinate out of bounds" ); + ENSURE_ARG_OR_THROW( pos.Y >= 0 && pos.Y < aSize.Height, + "CanvasHelper::setPixel: Y coordinate out of bounds" ); + ENSURE_ARG_OR_THROW( color.getLength() > 3, + "CanvasHelper::setPixel: not enough color components" ); + + if( Gdiplus::Ok != mpGDIPlusBitmap->SetPixel( pos.X, pos.Y, + Gdiplus::Color( tools::sequenceToArgb( color )))) + { + throw uno::RuntimeException(); + } + } + else + { + ENSURE_ARG_OR_THROW( pos.X >= 0 && pos.X < maSize.getX(), + "CanvasHelper::setPixel: X coordinate out of bounds" ); + ENSURE_ARG_OR_THROW( pos.Y >= 0 && pos.Y < maSize.getY(), + "CanvasHelper::setPixel: Y coordinate out of bounds" ); + ENSURE_ARG_OR_THROW( color.getLength() > 3, + "CanvasHelper::setPixel: not enough color components" ); + + Gdiplus::Color aColor(tools::sequenceToArgb(color)); + +#if DIRECTX_VERSION < 0x0900 + DDSURFACEDESC aSurfaceDesc; + rtl_fillMemory(&aSurfaceDesc,sizeof(DDSURFACEDESC),0); + aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC); + const DWORD dwFlags = DDLOCK_NOSYSLOCK|DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT|DDLOCK_WRITEONLY; + + // lock the directx surface to receive the pointer to the surface memory. + if(FAILED(mpSurface->Lock(NULL,&aSurfaceDesc,dwFlags,NULL))) + throw uno::RuntimeException(); + + sal_uInt32 *pDst = (sal_uInt32 *)((((BYTE *)aSurfaceDesc.lpSurface)+(pos.Y*aSurfaceDesc.lPitch))+pos.X); + *pDst = aColor.GetValue(); + mpSurface->Unlock(NULL); +#else + // lock the directx surface to receive the pointer to the surface memory. + D3DLOCKED_RECT aLockedRect; + if(FAILED(mpSurface->LockRect(&aLockedRect,NULL,D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY))) + throw uno::RuntimeException(); + + sal_uInt32 *pDst = (sal_uInt32 *)((((BYTE *)aLockedRect.pBits)+(pos.Y*aLockedRect.Pitch))+pos.X); + *pDst = aColor.GetValue(); + mpSurface->UnlockRect(); +#endif + } + + mbIsSurfaceDirty = true; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::getPixel + ////////////////////////////////////////////////////////////////////////////////// + + uno::Sequence< sal_Int8 > DXSurfaceBitmap::getPixel( rendering::IntegerBitmapLayout& /*bitmapLayout*/, + const geometry::IntegerPoint2D& pos ) + { + if(hasAlpha()) + { + const geometry::IntegerSize2D aSize( maSize.getX(),maSize.getY() ); + + ENSURE_ARG_OR_THROW( pos.X >= 0 && pos.X < aSize.Width, + "CanvasHelper::getPixel: X coordinate out of bounds" ); + ENSURE_ARG_OR_THROW( pos.Y >= 0 && pos.Y < aSize.Height, + "CanvasHelper::getPixel: Y coordinate out of bounds" ); + + Gdiplus::Color aColor; + + if( Gdiplus::Ok != mpGDIPlusBitmap->GetPixel( pos.X, pos.Y, &aColor ) ) + return uno::Sequence< sal_Int8 >(); + + return tools::argbToIntSequence(aColor.GetValue()); + } + else + { + ENSURE_ARG_OR_THROW( pos.X >= 0 && pos.X < maSize.getX(), + "CanvasHelper::getPixel: X coordinate out of bounds" ); + ENSURE_ARG_OR_THROW( pos.Y >= 0 && pos.Y < maSize.getY(), + "CanvasHelper::getPixel: Y coordinate out of bounds" ); + +#if DIRECTX_VERSION < 0x0900 + DDSURFACEDESC aSurfaceDesc; + rtl_fillMemory(&aSurfaceDesc,sizeof(DDSURFACEDESC),0); + aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC); + const DWORD dwFlags = DDLOCK_NOSYSLOCK|DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT|DDLOCK_READONLY; + + // lock the directx surface to receive the pointer to the surface memory. + if(FAILED(mpSurface->Lock(NULL,&aSurfaceDesc,dwFlags,NULL))) + throw uno::RuntimeException(); + + sal_uInt32 *pDst = (sal_uInt32 *)((((BYTE *)aSurfaceDesc.lpSurface)+(pos.Y*aSurfaceDesc.lPitch))+pos.X); + Gdiplus::Color aColor(*pDst); + mpSurface->Unlock(NULL); +#else + // lock the directx surface to receive the pointer to the surface memory. + D3DLOCKED_RECT aLockedRect; + if(FAILED(mpSurface->LockRect(&aLockedRect,NULL,D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY))) + throw uno::RuntimeException(); + + sal_uInt32 *pDst = (sal_uInt32 *)((((BYTE *)aLockedRect.pBits)+(pos.Y*aLockedRect.Pitch))+pos.X); + Gdiplus::Color aColor(*pDst); + mpSurface->UnlockRect(); +#endif + + return tools::argbToIntSequence(aColor.GetValue()); + } + } + + ////////////////////////////////////////////////////////////////////////////////// + // End of file + ////////////////////////////////////////////////////////////////////////////////// +} + diff --git a/canvas/source/directx/dx_surfacebitmap.hxx b/canvas/source/directx/dx_surfacebitmap.hxx new file mode 100644 index 000000000000..7519635d5ccc --- /dev/null +++ b/canvas/source/directx/dx_surfacebitmap.hxx @@ -0,0 +1,150 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_surfacebitmap.hxx,v $ + * $Revision: 1.2 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _DXCANVAS_DXSURFACEBITMAP_HXX +#define _DXCANVAS_DXSURFACEBITMAP_HXX + +#include <canvas/rendering/isurfaceproxy.hxx> +#include <canvas/rendering/isurfaceproxymanager.hxx> +#include "dx_ibitmap.hxx" +#include "dx_canvasfont.hxx" //winstuff +#include "dx_gdiplususer.hxx" +#include "dx_rendermodule.hxx" + +namespace dxcanvas +{ + class DXSurfaceBitmap : public IBitmap + { + public: + DXSurfaceBitmap( const ::basegfx::B2IVector& rSize, + const canvas::ISurfaceProxyManagerSharedPtr& rMgr, + const IDXRenderModuleSharedPtr& rRenderModule, + bool bWithAlpha ); + + bool resize( const ::basegfx::B2IVector& rSize ); + void clear(); + + virtual GraphicsSharedPtr getGraphics(); + + virtual BitmapSharedPtr getBitmap() const; + virtual ::basegfx::B2IVector getSize() const; + virtual bool hasAlpha() const; + + COMReference<surface_type> getSurface() const { return mpSurface; } + + bool draw( double fAlpha, + const ::basegfx::B2DPoint& rPos, + const ::basegfx::B2DHomMatrix& rTransform ); + + bool draw( const ::basegfx::B2IRange& rArea ); + + bool draw( double fAlpha, + const ::basegfx::B2DPoint& rPos, + const ::basegfx::B2DRange& rArea, + const ::basegfx::B2DHomMatrix& rTransform ); + + bool draw( double fAlpha, + const ::basegfx::B2DPoint& rPos, + const ::basegfx::B2DPolyPolygon& rClipPoly, + const ::basegfx::B2DHomMatrix& rTransform ); + + virtual ::com::sun::star::uno::Sequence< sal_Int8 > getData( + ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout, + const ::com::sun::star::geometry::IntegerRectangle2D& rect ); + + virtual void setData( + const ::com::sun::star::uno::Sequence< sal_Int8 >& data, + const ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout, + const ::com::sun::star::geometry::IntegerRectangle2D& rect ); + + virtual void setPixel( + const ::com::sun::star::uno::Sequence< sal_Int8 >& color, + const ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout, + const ::com::sun::star::geometry::IntegerPoint2D& pos ); + + virtual ::com::sun::star::uno::Sequence< sal_Int8 > getPixel( + ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout, + const ::com::sun::star::geometry::IntegerPoint2D& pos ); + +#ifdef DX_DEBUG_IMAGES + void imageDebugger(); +#endif + private: + void init(); + + // Refcounted global GDI+ state container + GDIPlusUserSharedPtr mpGdiPlusUser; + + // size of this image in pixels [integral unit] + ::basegfx::B2IVector maSize; + + // pointer to the rendermodule, needed to create surfaces + // which are used as container for the actual pixel data. + // generally we could use any kind of storage, but GDI+ + // is not willing to render antialiased fonts unless we + // use this special kind of container, don't ask me why... + IDXRenderModuleSharedPtr mpRenderModule; + + // pointer to the surface manager, needed in case clients + // want to resize the bitmap. + canvas::ISurfaceProxyManagerSharedPtr mpSurfaceManager; + + // access point to the surface proxy which handles + // the hardware-dependent rendering stuff. + canvas::ISurfaceProxySharedPtr mpSurfaceProxy; + + // container for pixel data, we need to use a directx + // surface since GDI+ sucks... + COMReference<surface_type> mpSurface; + + // since GDI+ does not work correctly in case we + // run on a 16bit display [don't ask me why] we need + // to occasionally render to a native GDI+ bitmap. + BitmapSharedPtr mpGDIPlusBitmap; + // Graphics for the mpGDIPlusBitmap + GraphicsSharedPtr mpGraphics; + + // internal implementation of the iColorBuffer interface + canvas::IColorBufferSharedPtr mpColorBuffer; + + // indicates wether the associated surface needs + // to refresh its contents or not. in other words, + // this flag is set iff both representations are + // out of sync. + mutable bool mbIsSurfaceDirty; + + // true if the bitmap contains an alpha channel + bool mbAlpha; + }; + + typedef ::boost::shared_ptr< DXSurfaceBitmap > DXSurfaceBitmapSharedPtr; +} + +#endif diff --git a/canvas/source/directx/dx_surfacegraphics.cxx b/canvas/source/directx/dx_surfacegraphics.cxx new file mode 100755 index 000000000000..8b9af6be6827 --- /dev/null +++ b/canvas/source/directx/dx_surfacegraphics.cxx @@ -0,0 +1,88 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_surfacegraphics.cxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include "dx_surfacegraphics.hxx" +#include "dx_impltools.hxx" + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + namespace + { + struct GraphicsDeleter + { + COMReference<surface_type> mpSurface; + HDC maHDC; + + GraphicsDeleter(const COMReference<surface_type>& rSurface, HDC hdc) : + mpSurface(rSurface), + maHDC(hdc) + {} + + void operator()( Gdiplus::Graphics* pGraphics ) + { + if(!pGraphics) + return; + + pGraphics->Flush(Gdiplus::FlushIntentionSync); + delete pGraphics; + + if(mpSurface.is()) + mpSurface->ReleaseDC( maHDC ); + } + }; + } + + GraphicsSharedPtr createSurfaceGraphics(const COMReference<surface_type>& rSurface ) + { + Gdiplus::Graphics* pGraphics; + GraphicsSharedPtr pRet; + HDC aHDC; + if( SUCCEEDED(rSurface->GetDC( &aHDC )) ) + { + pGraphics = Gdiplus::Graphics::FromHDC( aHDC ); + if(pGraphics) + { + tools::setupGraphics( *pGraphics ); + pRet.reset(pGraphics, + GraphicsDeleter(rSurface, aHDC)); + return pRet; + } + else + rSurface->ReleaseDC( aHDC ); + } + + throw uno::RuntimeException(); + } +} diff --git a/canvas/source/directx/dx_surfacegraphics.hxx b/canvas/source/directx/dx_surfacegraphics.hxx new file mode 100755 index 000000000000..696f2de338d3 --- /dev/null +++ b/canvas/source/directx/dx_surfacegraphics.hxx @@ -0,0 +1,48 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_surfacegraphics.hxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _DXCANVAS_SURFACEGRAPHICS_HXX +#define _DXCANVAS_SURFACEGRAPHICS_HXX + +#include "dx_graphicsprovider.hxx" + +namespace dxcanvas +{ + /** Container providing a Gdiplus::Graphics for a Surface + + This wrapper class transparently handles allocation and + release of surface resources the RAII way (the + GraphicsSharedPtr returned has a deleter that does all the + necessary DX cleanup work). + */ + GraphicsSharedPtr createSurfaceGraphics(const COMReference<surface_type>& rSurface ); +} + +#endif /* _DXCANVAS_SURFACEGRAPHICS_HXX */ diff --git a/canvas/source/directx/dx_textlayout.cxx b/canvas/source/directx/dx_textlayout.cxx new file mode 100755 index 000000000000..e1fd917ed772 --- /dev/null +++ b/canvas/source/directx/dx_textlayout.cxx @@ -0,0 +1,283 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_textlayout.cxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <ctype.h> // don't ask. msdev breaks otherwise... +#include <canvas/debug.hxx> +#include <canvas/verbosetrace.hxx> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/numeric/ftools.hxx> +#include "dx_bitmap.hxx" +#include "dx_textlayout.hxx" +#include "dx_spritecanvas.hxx" +#include "dx_textlayout_drawhelper.hxx" + + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + TextLayout::TextLayout( const rendering::StringContext& aText, + sal_Int8 nDirection, + sal_Int64 /*nRandomSeed*/, + const CanvasFont::ImplRef& rFont ) : + TextLayout_Base( m_aMutex ), + maText( aText ), + maLogicalAdvancements(), + mpFont( rFont ), + mnTextDirection( nDirection ) + { + } + + TextLayout::~TextLayout() + { + } + + void SAL_CALL TextLayout::disposing() + { + mpFont.reset(); + } + + // XTextLayout + uno::Sequence< uno::Reference< rendering::XPolyPolygon2D > > SAL_CALL TextLayout::queryTextShapes( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO + return uno::Sequence< uno::Reference< rendering::XPolyPolygon2D > >(); + } + + uno::Sequence< geometry::RealRectangle2D > SAL_CALL TextLayout::queryInkMeasures( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO + return uno::Sequence< geometry::RealRectangle2D >(); + } + + uno::Sequence< geometry::RealRectangle2D > SAL_CALL TextLayout::queryMeasures( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO + return uno::Sequence< geometry::RealRectangle2D >(); + } + + uno::Sequence< double > SAL_CALL TextLayout::queryLogicalAdvancements( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + return maLogicalAdvancements; + } + + void SAL_CALL TextLayout::applyLogicalAdvancements( const uno::Sequence< double >& aAdvancements ) throw (lang::IllegalArgumentException, uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + if( aAdvancements.getLength() != maText.Length ) + { + OSL_TRACE( "TextLayout::applyLogicalAdvancements(): mismatching number of advancements" ); + throw lang::IllegalArgumentException(); + } + + maLogicalAdvancements = aAdvancements; + } + + geometry::RealRectangle2D SAL_CALL TextLayout::queryTextBounds( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + uno::Reference< rendering::XGraphicDevice > xGraphicDevice; + ::dxcanvas::TextLayoutDrawHelper aDrawHelper(xGraphicDevice); + + // render text + const geometry::RealRectangle2D aBounds( + aDrawHelper.queryTextBounds( + maText, + maLogicalAdvancements, + mpFont.getRef(), + mpFont->getFontMatrix())); + + return aBounds; + } + + double SAL_CALL TextLayout::justify( double /*nSize*/ ) throw (lang::IllegalArgumentException, uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO + return 0.0; + } + + double SAL_CALL TextLayout::combinedJustify( const uno::Sequence< uno::Reference< rendering::XTextLayout > >& /*aNextLayouts*/, + double /*nSize*/ ) throw (lang::IllegalArgumentException, uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO + return 0.0; + } + + rendering::TextHit SAL_CALL TextLayout::getTextHit( const geometry::RealPoint2D& /*aHitPoint*/ ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO + return rendering::TextHit(); + } + + rendering::Caret SAL_CALL TextLayout::getCaret( sal_Int32 /*nInsertionIndex*/, + sal_Bool /*bExcludeLigatures*/ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO + return rendering::Caret(); + } + + sal_Int32 SAL_CALL TextLayout::getNextInsertionIndex( sal_Int32 /*nStartIndex*/, + sal_Int32 /*nCaretAdvancement*/, + sal_Bool /*bExcludeLigatures*/ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO + return 0; + } + + uno::Reference< rendering::XPolyPolygon2D > SAL_CALL TextLayout::queryVisualHighlighting( sal_Int32 /*nStartIndex*/, + sal_Int32 /*nEndIndex*/ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO + return uno::Reference< rendering::XPolyPolygon2D >(); + } + + uno::Reference< rendering::XPolyPolygon2D > SAL_CALL TextLayout::queryLogicalHighlighting( sal_Int32 /*nStartIndex*/, + sal_Int32 /*nEndIndex*/ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO + return uno::Reference< rendering::XPolyPolygon2D >(); + } + + double SAL_CALL TextLayout::getBaselineOffset( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO + return 0.0; + } + + sal_Int8 SAL_CALL TextLayout::getMainTextDirection( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + return mnTextDirection; + } + + uno::Reference< rendering::XCanvasFont > SAL_CALL TextLayout::getFont( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + return mpFont.getRef(); + } + + rendering::StringContext SAL_CALL TextLayout::getText( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + return maText; + } + + namespace + { + // TODO(P2): Check whether this gets inlined. If not, make functor + // out of it + inline Gdiplus::PointF gdiPlusPointFromDx( const double& dx ) + { + return Gdiplus::PointF( static_cast<Gdiplus::REAL>(dx), + 0.0f ); + } + } + + bool TextLayout::draw( const GraphicsSharedPtr& rGraphics, + const rendering::ViewState& rViewState, + const rendering::RenderState& rRenderState, + const ::basegfx::B2ISize& rOutputOffset, + const uno::Reference< rendering::XGraphicDevice >& xGraphicDevice, + bool bAlphaSurface ) const + { + ::osl::MutexGuard aGuard( m_aMutex ); + + ::dxcanvas::TextLayoutDrawHelper aDrawHelper(xGraphicDevice); + + // render text + aDrawHelper.drawText( + rGraphics, + rViewState, + rRenderState, + rOutputOffset, + maText, + maLogicalAdvancements, + mpFont.getRef(), + mpFont->getFontMatrix(), + bAlphaSurface); + + return true; + } + + +#define SERVICE_NAME "com.sun.star.rendering.TextLayout" +#define IMPLEMENTATION_NAME "DXCanvas::TextLayout" + + ::rtl::OUString SAL_CALL TextLayout::getImplementationName() throw( uno::RuntimeException ) + { + return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( IMPLEMENTATION_NAME ) ); + } + + sal_Bool SAL_CALL TextLayout::supportsService( const ::rtl::OUString& ServiceName ) throw( uno::RuntimeException ) + { + return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( SERVICE_NAME ) ); + } + + uno::Sequence< ::rtl::OUString > SAL_CALL TextLayout::getSupportedServiceNames() throw( uno::RuntimeException ) + { + uno::Sequence< ::rtl::OUString > aRet(1); + aRet[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME ) ); + + return aRet; + } +} diff --git a/canvas/source/directx/dx_textlayout.hxx b/canvas/source/directx/dx_textlayout.hxx new file mode 100755 index 000000000000..a8562ed34f7a --- /dev/null +++ b/canvas/source/directx/dx_textlayout.hxx @@ -0,0 +1,118 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_textlayout.hxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _DXCANVAS_TEXTLAYOUT_HXX +#define _DXCANVAS_TEXTLAYOUT_HXX + +#include <cppuhelper/compbase2.hxx> +#include <comphelper/broadcasthelper.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> + +#include <com/sun/star/rendering/XTextLayout.hpp> + +#include <basegfx/vector/b2isize.hxx> + +#include <boost/utility.hpp> + +#include "dx_canvasfont.hxx" +#include "dx_ibitmap.hxx" +#include "dx_winstuff.hxx" +#include "dx_gdiplususer.hxx" + + +/* Definition of TextLayout class */ +class DXBitmapSharedPtr; + +namespace dxcanvas +{ + typedef ::cppu::WeakComponentImplHelper2< ::com::sun::star::rendering::XTextLayout, + ::com::sun::star::lang::XServiceInfo > TextLayout_Base; + + class TextLayout : public ::comphelper::OBaseMutex, + public TextLayout_Base, + private ::boost::noncopyable + { + public: + TextLayout( const ::com::sun::star::rendering::StringContext& aText, + sal_Int8 nDirection, + sal_Int64 nRandomSeed, + const CanvasFont::ImplRef& rFont ); + + /// Dispose all internal references + virtual void SAL_CALL disposing(); + + // XTextLayout + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XPolyPolygon2D > > SAL_CALL queryTextShapes( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::geometry::RealRectangle2D > SAL_CALL queryInkMeasures( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::geometry::RealRectangle2D > SAL_CALL queryMeasures( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< double > SAL_CALL queryLogicalAdvancements( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL applyLogicalAdvancements( const ::com::sun::star::uno::Sequence< double >& aAdvancements ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::geometry::RealRectangle2D SAL_CALL queryTextBounds( ) throw (::com::sun::star::uno::RuntimeException); + virtual double SAL_CALL justify( double nSize ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException); + virtual double SAL_CALL combinedJustify( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XTextLayout > >& aNextLayouts, double nSize ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::rendering::TextHit SAL_CALL getTextHit( const ::com::sun::star::geometry::RealPoint2D& aHitPoint ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::rendering::Caret SAL_CALL getCaret( sal_Int32 nInsertionIndex, sal_Bool bExcludeLigatures ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getNextInsertionIndex( sal_Int32 nStartIndex, sal_Int32 nCaretAdvancement, sal_Bool bExcludeLigatures ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XPolyPolygon2D > SAL_CALL queryVisualHighlighting( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XPolyPolygon2D > SAL_CALL queryLogicalHighlighting( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual double SAL_CALL getBaselineOffset( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int8 SAL_CALL getMainTextDirection( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCanvasFont > SAL_CALL getFont( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::rendering::StringContext SAL_CALL getText( ) throw (::com::sun::star::uno::RuntimeException); + + // XServiceInfo + virtual ::rtl::OUString SAL_CALL getImplementationName() throw( ::com::sun::star::uno::RuntimeException ); + virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw( ::com::sun::star::uno::RuntimeException ); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames() throw( ::com::sun::star::uno::RuntimeException ); + + bool draw( const GraphicsSharedPtr& rGraphics, + const ::com::sun::star::rendering::ViewState& rViewState, + const ::com::sun::star::rendering::RenderState& rRenderState, + const ::basegfx::B2ISize& rOutputOffset, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XGraphicDevice >& xGraphicDevice, + bool bAlphaSurface ) const; + + protected: + ~TextLayout(); // we're a ref-counted UNO class. _We_ destroy ourselves. + + private: + // NOTE: no need for GDIPlusUserSharedPtr, mpFont implicitely has one already + + ::com::sun::star::rendering::StringContext maText; + ::com::sun::star::uno::Sequence< double > maLogicalAdvancements; + CanvasFont::ImplRef mpFont; + sal_Int8 mnTextDirection; + }; + +} + +#endif /* _DXCANVAS_TEXTLAYOUT_HXX */ diff --git a/canvas/source/directx/dx_textlayout_drawhelper.cxx b/canvas/source/directx/dx_textlayout_drawhelper.cxx new file mode 100755 index 000000000000..358bd1e9d74f --- /dev/null +++ b/canvas/source/directx/dx_textlayout_drawhelper.cxx @@ -0,0 +1,315 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_textlayout_drawhelper.cxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <tools/poly.hxx> + +#include <vcl/metric.hxx> +#include <vcl/virdev.hxx> +#include <vcl/metric.hxx> +#include <vcl/canvastools.hxx> +#include <tools/diagnose_ex.h> + +#include <boost/scoped_array.hpp> +#include <boost/bind.hpp> +#include <com/sun/star/rendering/FontRequest.hpp> +#include <com/sun/star/rendering/XCanvasFont.hpp> +#include <comphelper/sequence.hxx> +#include <comphelper/scopeguard.hxx> +#include <tools/color.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <canvas/canvastools.hxx> +#include <canvas/debug.hxx> +#include "dx_impltools.hxx" +#include <vcl/sysdata.hxx> +#include <i18npool/mslangid.hxx> +#include "dx_textlayout_drawhelper.hxx" +#include "dx_bitmap.hxx" +#include "dx_canvasfont.hxx" + +class ::com::sun::star::rendering::XCanvasFont; + +using namespace ::com::sun::star; + + +////////////////////////////////////////////////////////////////////////////// + +namespace dxcanvas +{ + class DXBitmap; + TextLayoutDrawHelper::TextLayoutDrawHelper( + const uno::Reference< rendering::XGraphicDevice >& xGraphicDevice ) : + mxGraphicDevice(xGraphicDevice) + { + } + + TextLayoutDrawHelper::~TextLayoutDrawHelper() + { + } + + void TextLayoutDrawHelper::drawText( + const GraphicsSharedPtr& rGraphics, + const ::com::sun::star::rendering::ViewState& rViewState, + const ::com::sun::star::rendering::RenderState& rRenderState, + const ::basegfx::B2ISize& rOutputOffset, + const ::com::sun::star::rendering::StringContext& rText, + const ::com::sun::star::uno::Sequence< double >& rLogicalAdvancements, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XCanvasFont >& rCanvasFont, + const ::com::sun::star::geometry::Matrix2D& rFontMatrix, + bool bAlphaSurface ) + { + HDC hdc = rGraphics->GetHDC(); + + // issue an ReleaseHDC() when leaving the scope + const ::comphelper::ScopeGuard aGuard( + boost::bind( &Gdiplus::Graphics::ReleaseHDC, + rGraphics.get(), + hdc )); + + SystemGraphicsData aSystemGraphicsData; + aSystemGraphicsData.nSize = sizeof(SystemGraphicsData); + aSystemGraphicsData.hDC = reinterpret_cast< ::HDC >(hdc); + VirtualDevice aVirtualDevice(&aSystemGraphicsData, 0); + + // disable font antialiasing - GDI does not handle alpha + // surfaces properly. + if( bAlphaSurface ) + aVirtualDevice.SetAntialiasing(ANTIALIASING_DISABLE_TEXT); + + if(rText.Length) + { + sal_Bool test = mxGraphicDevice.is(); + ENSURE_OR_THROW( test, + "TextLayoutDrawHelper::drawText(): Invalid GraphicDevice" ); + + // set text color. Make sure to remove transparence part first. + Color aColor( COL_WHITE ); + + if( rRenderState.DeviceColor.getLength() > 2 ) + aColor = ::vcl::unotools::doubleSequenceToColor( + rRenderState.DeviceColor, + mxGraphicDevice->getDeviceColorSpace()); + aColor.SetTransparency(0); + aVirtualDevice.SetTextColor(aColor); + + // create the font + const ::com::sun::star::rendering::FontRequest& rFontRequest = rCanvasFont->getFontRequest(); + Font aFont( + rFontRequest.FontDescription.FamilyName, + rFontRequest.FontDescription.StyleName, + Size( 0, ::basegfx::fround(rFontRequest.CellSize))); + + aFont.SetAlign( ALIGN_BASELINE ); + aFont.SetCharSet( (rFontRequest.FontDescription.IsSymbolFont==com::sun::star::util::TriState_YES) ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE ); + aFont.SetVertical( (rFontRequest.FontDescription.IsVertical==com::sun::star::util::TriState_YES) ? TRUE : FALSE ); + aFont.SetWeight( static_cast<FontWeight>(rFontRequest.FontDescription.FontDescription.Weight) ); + aFont.SetItalic( (rFontRequest.FontDescription.FontDescription.Letterform<=8) ? ITALIC_NONE : ITALIC_NORMAL ); + + aFont.SetLanguage(MsLangId::convertLocaleToLanguage(rFontRequest.Locale)); + + // setup font color + aFont.SetColor( aColor ); + aFont.SetFillColor( aColor ); + + // adjust to stretched font + if(!::rtl::math::approxEqual(rFontMatrix.m00, rFontMatrix.m11)) + { + const Size aSize = aVirtualDevice.GetFontMetric( aFont ).GetSize(); + const double fDividend( rFontMatrix.m10 + rFontMatrix.m11 ); + double fStretch = (rFontMatrix.m00 + rFontMatrix.m01); + + if( !::basegfx::fTools::equalZero( fDividend) ) + fStretch /= fDividend; + + const sal_Int32 nNewWidth = ::basegfx::fround( aSize.Width() * fStretch ); + + aFont.SetWidth( nNewWidth ); + } + + // set font + aVirtualDevice.SetFont(aFont); + + // create world transformation matrix + ::basegfx::B2DHomMatrix aWorldTransform; + ::canvas::tools::mergeViewAndRenderTransform(aWorldTransform, rViewState, rRenderState); + + if(!rOutputOffset.equalZero()) + { + aWorldTransform.translate(rOutputOffset.getX(), rOutputOffset.getY()); + } + + // set ViewState clipping + if(rViewState.Clip.is()) + { + ::basegfx::B2DPolyPolygon aClipPoly(dxcanvas::tools::polyPolygonFromXPolyPolygon2D(rViewState.Clip)); + ::basegfx::B2DHomMatrix aMatrix; + ::basegfx::unotools::homMatrixFromAffineMatrix(aMatrix, rViewState.AffineTransform ); + + if(!rOutputOffset.equalZero()) + { + aMatrix.translate(rOutputOffset.getX(), rOutputOffset.getY()); + } + + aClipPoly.transform(aMatrix); + const Region& rClipRegion = Region(PolyPolygon(aClipPoly)); + aVirtualDevice.IntersectClipRegion(rClipRegion); + } + + if(rRenderState.Clip.is()) + { + ::basegfx::B2DPolyPolygon aClipPoly(dxcanvas::tools::polyPolygonFromXPolyPolygon2D(rRenderState.Clip)); + aClipPoly.transform(aWorldTransform); + const Region& rClipRegion = Region(PolyPolygon(aClipPoly)); + aVirtualDevice.IntersectClipRegion(rClipRegion); + } + + // set world transform + XFORM aXForm; + aXForm.eM11 = (FLOAT)aWorldTransform.get(0, 0); + aXForm.eM12 = (FLOAT)aWorldTransform.get(1, 0); + aXForm.eM21 = (FLOAT)aWorldTransform.get(0, 1); + aXForm.eM22 = (FLOAT)aWorldTransform.get(1, 1); + aXForm.eDx = (FLOAT)aWorldTransform.get(0, 2); + aXForm.eDy = (FLOAT)aWorldTransform.get(1, 2); + + // TODO(F3): This is NOT supported on 95/98/ME! + SetGraphicsMode(hdc, GM_ADVANCED); + SetTextAlign(hdc, TA_BASELINE); + SetWorldTransform(hdc, &aXForm); + + // use a empty StartPosition for text rendering + const Point aEmptyPoint(0, 0); + + // create the String + const String aText(rText.Text.getStr()); + + if( rLogicalAdvancements.getLength() ) + { + // create the DXArray + const sal_Int32 nLen( rLogicalAdvancements.getLength() ); + ::boost::scoped_array<sal_Int32> pDXArray( new sal_Int32[nLen] ); + for( sal_Int32 i=0; i<nLen; ++i ) + pDXArray[i] = basegfx::fround( rLogicalAdvancements[i] ); + + // draw the String + aVirtualDevice.DrawTextArray( aEmptyPoint, + aText, + pDXArray.get(), + (xub_StrLen)rText.StartPosition, + (xub_StrLen)rText.Length ); + } + else + { + // draw the String + aVirtualDevice.DrawText( aEmptyPoint, + aText, + (xub_StrLen)rText.StartPosition, + (xub_StrLen)rText.Length ); + } + } + } + + geometry::RealRectangle2D TextLayoutDrawHelper::queryTextBounds( const rendering::StringContext& rText, + const uno::Sequence< double >& rLogicalAdvancements, + const uno::Reference< rendering::XCanvasFont >& rCanvasFont, + const geometry::Matrix2D& rFontMatrix ) + { + if(!(rText.Length)) + return geometry::RealRectangle2D(); + + // TODO(F1): Fetching default screen DC here, will yield wrong + // metrics when e.g. formatting for a printer! + SystemGraphicsData aSystemGraphicsData; + aSystemGraphicsData.nSize = sizeof(SystemGraphicsData); + aSystemGraphicsData.hDC = reinterpret_cast< ::HDC >(GetDC( NULL )); + VirtualDevice aVirtualDevice(&aSystemGraphicsData, 0); + + // create the font + const ::com::sun::star::rendering::FontRequest& rFontRequest = rCanvasFont->getFontRequest(); + Font aFont( + rFontRequest.FontDescription.FamilyName, + rFontRequest.FontDescription.StyleName, + Size( 0, ::basegfx::fround(rFontRequest.CellSize))); + + aFont.SetAlign( ALIGN_BASELINE ); + aFont.SetCharSet( (rFontRequest.FontDescription.IsSymbolFont==com::sun::star::util::TriState_YES) ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE ); + aFont.SetVertical( (rFontRequest.FontDescription.IsVertical==com::sun::star::util::TriState_YES) ? TRUE : FALSE ); + aFont.SetWeight( static_cast<FontWeight>(rFontRequest.FontDescription.FontDescription.Weight) ); + aFont.SetItalic( (rFontRequest.FontDescription.FontDescription.Letterform<=8) ? ITALIC_NONE : ITALIC_NORMAL ); + + // adjust to stretched font + if(!::rtl::math::approxEqual(rFontMatrix.m00, rFontMatrix.m11)) + { + const Size aSize = aVirtualDevice.GetFontMetric( aFont ).GetSize(); + const double fDividend( rFontMatrix.m10 + rFontMatrix.m11 ); + double fStretch = (rFontMatrix.m00 + rFontMatrix.m01); + + if( !::basegfx::fTools::equalZero( fDividend) ) + fStretch /= fDividend; + + const sal_Int32 nNewWidth = ::basegfx::fround( aSize.Width() * fStretch ); + + aFont.SetWidth( nNewWidth ); + } + + // set font + aVirtualDevice.SetFont(aFont); + + // need metrics for Y offset, the XCanvas always renders + // relative to baseline + const ::FontMetric& aMetric( aVirtualDevice.GetFontMetric() ); + + const sal_Int32 nAboveBaseline( -aMetric.GetIntLeading() - aMetric.GetAscent() ); + const sal_Int32 nBelowBaseline( aMetric.GetDescent() ); + + if( rLogicalAdvancements.getLength() ) + { + return geometry::RealRectangle2D( 0, nAboveBaseline, + rLogicalAdvancements[ rLogicalAdvancements.getLength()-1 ], + nBelowBaseline ); + } + else + { + return geometry::RealRectangle2D( 0, nAboveBaseline, + aVirtualDevice.GetTextWidth( + rText.Text, + ::canvas::tools::numeric_cast<USHORT>(rText.StartPosition), + ::canvas::tools::numeric_cast<USHORT>(rText.Length) ), + nBelowBaseline ); + } + } +} + + +// eof diff --git a/canvas/source/directx/dx_textlayout_drawhelper.hxx b/canvas/source/directx/dx_textlayout_drawhelper.hxx new file mode 100755 index 000000000000..b6e4cd60a64f --- /dev/null +++ b/canvas/source/directx/dx_textlayout_drawhelper.hxx @@ -0,0 +1,89 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_textlayout_drawhelper.hxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _TEXTLAYOUT_DRAWHELPER_HXX +#define _TEXTLAYOUT_DRAWHELPER_HXX + +#include <boost/shared_ptr.hpp> + +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/rendering/StringContext.hpp> +#include <com/sun/star/rendering/XCanvasFont.hpp> +#include <com/sun/star/geometry/Matrix2D.hpp> +#include <com/sun/star/rendering/XGraphicDevice.hpp> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/vector/b2isize.hxx> + +class ::com::sun::star::rendering::XCanvasFont; + +namespace Gdiplus { class Graphics; } + +namespace dxcanvas +{ + struct Bitmap; + class TextLayoutDrawHelper + { + public: + TextLayoutDrawHelper( + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice >& xGraphicDevice); + ~TextLayoutDrawHelper(); + + // draw text + void drawText( const boost::shared_ptr<Gdiplus::Graphics>& rGraphics, + const ::com::sun::star::rendering::ViewState& rViewState, + const ::com::sun::star::rendering::RenderState& rRenderState, + const ::basegfx::B2ISize& rOutputOffset, + const ::com::sun::star::rendering::StringContext& rText, + const ::com::sun::star::uno::Sequence< double >& rLogicalAdvancements, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XCanvasFont >& rCanvasFont, + const ::com::sun::star::geometry::Matrix2D& rFontMatrix, + bool bAlphaSurface ); + + ::com::sun::star::geometry::RealRectangle2D queryTextBounds( + const ::com::sun::star::rendering::StringContext& rText, + const ::com::sun::star::uno::Sequence< double >& rLogicalAdvancements, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XCanvasFont >& rCanvasFont, + const ::com::sun::star::geometry::Matrix2D& rFontMatrix ); + +#ifdef DBG_UTIL + void test(); +#endif + + protected: + ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XGraphicDevice > mxGraphicDevice; + }; +} + +#endif /* _TEXTLAYOUT_DRAWHELPER_HXX */ +// eof diff --git a/canvas/source/directx/dx_vcltools.cxx b/canvas/source/directx/dx_vcltools.cxx new file mode 100755 index 000000000000..e4d8ac04d5ba --- /dev/null +++ b/canvas/source/directx/dx_vcltools.cxx @@ -0,0 +1,526 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_vcltools.cxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <vcl/canvastools.hxx> + +#include <vcl/bitmap.hxx> +#include <vcl/bitmapex.hxx> +#include <vcl/bmpacc.hxx> +#include <tools/diagnose_ex.h> + +#include "dx_impltools.hxx" +#include <basegfx/numeric/ftools.hxx> + +#include <canvas/debug.hxx> +#include <canvas/verbosetrace.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/rendering/XIntegerBitmap.hpp> + +#include <boost/scoped_array.hpp> + +#include "dx_vcltools.hxx" + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + namespace tools + { + namespace + { + /// Calc number of colors in given BitmapInfoHeader + sal_Int32 calcDIBColorCount( const BITMAPINFOHEADER& rBIH ) + { + if( rBIH.biSize != sizeof( BITMAPCOREHEADER ) ) + { + if( rBIH.biBitCount <= 8 ) + { + if( rBIH.biClrUsed ) + return rBIH.biClrUsed; + else + return 1L << rBIH.biBitCount; + } + } + else + { + BITMAPCOREHEADER* pCoreHeader = (BITMAPCOREHEADER*)&rBIH; + + if( pCoreHeader->bcBitCount <= 8 ) + return 1L << pCoreHeader->bcBitCount; + } + + return 0; // nothing known + } + + /// Draw DI bits to given Graphics + bool drawDIBits( const ::boost::shared_ptr< Gdiplus::Graphics >& rGraphics, + const void* hDIB ) + { + bool bRet( false ); + BitmapSharedPtr pBitmap; + + const BITMAPINFO* pBI = (BITMAPINFO*)GlobalLock( (HGLOBAL)hDIB ); + + if( pBI ) + { + const BITMAPINFOHEADER* pBIH = (BITMAPINFOHEADER*)pBI; + const BYTE* pBits = (BYTE*) pBI + *(DWORD*)pBI + + calcDIBColorCount( *pBIH ) * sizeof( RGBQUAD ); + + // forward to outsourced GDI+ rendering method + // (header clashes) + bRet = tools::drawDIBits( rGraphics, *pBI, (void*)pBits ); + + GlobalUnlock( (HGLOBAL)hDIB ); + } + + return bRet; + } + + /** Draw VCL bitmap to given Graphics + + @param rBmp + Reference to bitmap. Might get modified, in such a way + that it will hold a DIB after a successful function call. + */ + bool drawVCLBitmap( const ::boost::shared_ptr< Gdiplus::Graphics >& rGraphics, + ::Bitmap& rBmp ) + { + BitmapSystemData aBmpSysData; + + if( !rBmp.GetSystemData( aBmpSysData ) || + !aBmpSysData.pDIB ) + { + // first of all, ensure that Bitmap contains a DIB, by + // aquiring a read access + BitmapReadAccess* pReadAcc = rBmp.AcquireReadAccess(); + + // TODO(P2): Acquiring a read access can actually + // force a read from VRAM, thus, avoiding this + // step somehow will increase performance + // here. + if( pReadAcc ) + { + // try again: now, WinSalBitmap must have + // generated a DIB + if( rBmp.GetSystemData( aBmpSysData ) && + aBmpSysData.pDIB ) + { + return drawDIBits( rGraphics, + aBmpSysData.pDIB ); + } + + rBmp.ReleaseAccess( pReadAcc ); + } + } + else + { + return drawDIBits( rGraphics, + aBmpSysData.pDIB ); + } + + // failed to generate DIBits from vcl bitmap + return false; + } + + /** Create a chunk of raw RGBA data GDI+ Bitmap from VCL BbitmapEX + */ + RawRGBABitmap bitmapFromVCLBitmapEx( const ::BitmapEx& rBmpEx ) + { + // TODO(P2): Avoid temporary bitmap generation, maybe + // even ensure that created DIBs are copied back to + // BmpEx (currently, every AcquireReadAccess() will + // make the local bitmap copy unique, effectively + // duplicating the memory used) + + ENSURE_OR_THROW( rBmpEx.IsTransparent(), + "::dxcanvas::tools::bitmapFromVCLBitmapEx(): " + "BmpEx not transparent" ); + + // convert transparent bitmap to 32bit RGBA + // ======================================== + + const ::Size aBmpSize( rBmpEx.GetSizePixel() ); + + RawRGBABitmap aBmpData; + aBmpData.mnWidth = aBmpSize.Width(); + aBmpData.mnHeight = aBmpSize.Height(); + aBmpData.mpBitmapData.reset( new sal_uInt8[ 4*aBmpData.mnWidth*aBmpData.mnHeight ] ); + + Bitmap aBitmap( rBmpEx.GetBitmap() ); + + ScopedBitmapReadAccess pReadAccess( aBitmap.AcquireReadAccess(), + aBitmap ); + + const sal_Int32 nWidth( aBmpSize.Width() ); + const sal_Int32 nHeight( aBmpSize.Height() ); + + ENSURE_OR_THROW( pReadAccess.get() != NULL, + "::dxcanvas::tools::bitmapFromVCLBitmapEx(): " + "Unable to acquire read acces to bitmap" ); + + if( rBmpEx.IsAlpha() ) + { + Bitmap aAlpha( rBmpEx.GetAlpha().GetBitmap() ); + + ScopedBitmapReadAccess pAlphaReadAccess( aAlpha.AcquireReadAccess(), + aAlpha ); + + // By convention, the access buffer always has + // one of the following formats: + // + // BMP_FORMAT_1BIT_MSB_PAL + // BMP_FORMAT_4BIT_MSN_PAL + // BMP_FORMAT_8BIT_PAL + // BMP_FORMAT_16BIT_TC_LSB_MASK + // BMP_FORMAT_24BIT_TC_BGR + // BMP_FORMAT_32BIT_TC_MASK + // + // and is always BMP_FORMAT_BOTTOM_UP + // + // This is the way + // WinSalBitmap::AcquireBuffer() sets up the + // buffer + + ENSURE_OR_THROW( pAlphaReadAccess.get() != NULL, + "::dxcanvas::tools::bitmapFromVCLBitmapEx(): " + "Unable to acquire read acces to alpha" ); + + ENSURE_OR_THROW( pAlphaReadAccess->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL || + pAlphaReadAccess->GetScanlineFormat() == BMP_FORMAT_8BIT_TC_MASK, + "::dxcanvas::tools::bitmapFromVCLBitmapEx(): " + "Unsupported alpha scanline format" ); + + BitmapColor aCol; + const sal_Int32 nWidth( aBmpSize.Width() ); + const sal_Int32 nHeight( aBmpSize.Height() ); + sal_uInt8* pCurrOutput( aBmpData.mpBitmapData.get() ); + int x, y; + + for( y=0; y<nHeight; ++y ) + { + switch( pReadAccess->GetScanlineFormat() ) + { + case BMP_FORMAT_8BIT_PAL: + { + Scanline pScan = pReadAccess->GetScanline( y ); + Scanline pAScan = pAlphaReadAccess->GetScanline( y ); + + for( x=0; x<nWidth; ++x ) + { + aCol = pReadAccess->GetPaletteColor( *pScan++ ); + + *pCurrOutput++ = aCol.GetBlue(); + *pCurrOutput++ = aCol.GetGreen(); + *pCurrOutput++ = aCol.GetRed(); + + // out notion of alpha is + // different from the rest + // of the world's + *pCurrOutput++ = 255 - (BYTE)*pAScan++; + } + } + break; + + case BMP_FORMAT_24BIT_TC_BGR: + { + Scanline pScan = pReadAccess->GetScanline( y ); + Scanline pAScan = pAlphaReadAccess->GetScanline( y ); + + for( x=0; x<nWidth; ++x ) + { + // store as RGBA + *pCurrOutput++ = *pScan++; + *pCurrOutput++ = *pScan++; + *pCurrOutput++ = *pScan++; + + // out notion of alpha is + // different from the rest + // of the world's + *pCurrOutput++ = 255 - (BYTE)*pAScan++; + } + } + break; + + // TODO(P2): Might be advantageous + // to hand-formulate the following + // formats, too. + case BMP_FORMAT_1BIT_MSB_PAL: + // FALLTHROUGH intended + case BMP_FORMAT_4BIT_MSN_PAL: + // FALLTHROUGH intended + case BMP_FORMAT_16BIT_TC_LSB_MASK: + // FALLTHROUGH intended + case BMP_FORMAT_32BIT_TC_MASK: + { + Scanline pAScan = pAlphaReadAccess->GetScanline( y ); + + // using fallback for those + // seldom formats + for( x=0; x<nWidth; ++x ) + { + // yes. x and y are swapped on Get/SetPixel + aCol = pReadAccess->GetColor(y,x); + + *pCurrOutput++ = aCol.GetBlue(); + *pCurrOutput++ = aCol.GetGreen(); + *pCurrOutput++ = aCol.GetRed(); + + // out notion of alpha is + // different from the rest + // of the world's + *pCurrOutput++ = 255 - (BYTE)*pAScan++; + } + } + break; + + case BMP_FORMAT_1BIT_LSB_PAL: + // FALLTHROUGH intended + case BMP_FORMAT_4BIT_LSN_PAL: + // FALLTHROUGH intended + case BMP_FORMAT_8BIT_TC_MASK: + // FALLTHROUGH intended + case BMP_FORMAT_24BIT_TC_RGB: + // FALLTHROUGH intended + case BMP_FORMAT_24BIT_TC_MASK: + // FALLTHROUGH intended + case BMP_FORMAT_16BIT_TC_MSB_MASK: + // FALLTHROUGH intended + case BMP_FORMAT_32BIT_TC_ABGR: + // FALLTHROUGH intended + case BMP_FORMAT_32BIT_TC_ARGB: + // FALLTHROUGH intended + case BMP_FORMAT_32BIT_TC_BGRA: + // FALLTHROUGH intended + case BMP_FORMAT_32BIT_TC_RGBA: + // FALLTHROUGH intended + default: + ENSURE_OR_THROW( false, + "::dxcanvas::tools::bitmapFromVCLBitmapEx(): " + "Unexpected scanline format - has " + "WinSalBitmap::AcquireBuffer() changed?" ); + } + } + } + else + { + Bitmap aMask( rBmpEx.GetMask() ); + + ScopedBitmapReadAccess pMaskReadAccess( aMask.AcquireReadAccess(), + aMask ); + + // By convention, the access buffer always has + // one of the following formats: + // + // BMP_FORMAT_1BIT_MSB_PAL + // BMP_FORMAT_4BIT_MSN_PAL + // BMP_FORMAT_8BIT_PAL + // BMP_FORMAT_16BIT_TC_LSB_MASK + // BMP_FORMAT_24BIT_TC_BGR + // BMP_FORMAT_32BIT_TC_MASK + // + // and is always BMP_FORMAT_BOTTOM_UP + // + // This is the way + // WinSalBitmap::AcquireBuffer() sets up the + // buffer + + ENSURE_OR_THROW( pMaskReadAccess.get() != NULL, + "::dxcanvas::tools::bitmapFromVCLBitmapEx(): " + "Unable to acquire read acces to mask" ); + + ENSURE_OR_THROW( pMaskReadAccess->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL, + "::dxcanvas::tools::bitmapFromVCLBitmapEx(): " + "Unsupported mask scanline format" ); + + BitmapColor aCol; + int nCurrBit; + const int nMask( 1L ); + const int nInitialBit(7); + sal_uInt8* pCurrOutput( aBmpData.mpBitmapData.get() ); + int x, y; + + // mapping table, to get from mask index color to + // alpha value (which depends on the mask's palette) + sal_uInt8 aColorMap[2]; + + const BitmapColor& rCol0( pMaskReadAccess->GetPaletteColor( 0 ) ); + const BitmapColor& rCol1( pMaskReadAccess->GetPaletteColor( 1 ) ); + + // shortcut for true luminance calculation + // (assumes that palette is grey-level). Note the + // swapped the indices here, to account for the + // fact that VCL's notion of alpha is inverted to + // the rest of the world's. + aColorMap[0] = rCol1.GetRed(); + aColorMap[1] = rCol0.GetRed(); + + for( y=0; y<nHeight; ++y ) + { + switch( pReadAccess->GetScanlineFormat() ) + { + case BMP_FORMAT_8BIT_PAL: + { + Scanline pScan = pReadAccess->GetScanline( y ); + Scanline pMScan = pMaskReadAccess->GetScanline( y ); + + for( x=0, nCurrBit=nInitialBit; x<nWidth; ++x ) + { + aCol = pReadAccess->GetPaletteColor( *pScan++ ); + + *pCurrOutput++ = aCol.GetBlue(); + *pCurrOutput++ = aCol.GetGreen(); + *pCurrOutput++ = aCol.GetRed(); + + *pCurrOutput++ = aColorMap[ (pMScan[ (x & ~7L) >> 3L ] >> nCurrBit ) & nMask ]; + nCurrBit = ((nCurrBit - 1) % 8L) & 7L; + } + } + break; + + case BMP_FORMAT_24BIT_TC_BGR: + { + Scanline pScan = pReadAccess->GetScanline( y ); + Scanline pMScan = pMaskReadAccess->GetScanline( y ); + + for( x=0, nCurrBit=nInitialBit; x<nWidth; ++x ) + { + // store as RGBA + *pCurrOutput++ = *pScan++; + *pCurrOutput++ = *pScan++; + *pCurrOutput++ = *pScan++; + + *pCurrOutput++ = aColorMap[ (pMScan[ (x & ~7L) >> 3L ] >> nCurrBit ) & nMask ]; + nCurrBit = ((nCurrBit - 1) % 8L) & 7L; + } + } + break; + + // TODO(P2): Might be advantageous + // to hand-formulate the following + // formats, too. + case BMP_FORMAT_1BIT_MSB_PAL: + // FALLTHROUGH intended + case BMP_FORMAT_4BIT_MSN_PAL: + // FALLTHROUGH intended + case BMP_FORMAT_16BIT_TC_LSB_MASK: + // FALLTHROUGH intended + case BMP_FORMAT_32BIT_TC_MASK: + { + Scanline pMScan = pMaskReadAccess->GetScanline( y ); + + // using fallback for those + // seldom formats + for( x=0, nCurrBit=nInitialBit; x<nWidth; ++x ) + { + // yes. x and y are swapped on Get/SetPixel + aCol = pReadAccess->GetColor(y,x); + + // store as RGBA + *pCurrOutput++ = aCol.GetBlue(); + *pCurrOutput++ = aCol.GetGreen(); + *pCurrOutput++ = aCol.GetRed(); + + *pCurrOutput++ = aColorMap[ (pMScan[ (x & ~7L) >> 3L ] >> nCurrBit ) & nMask ]; + nCurrBit = ((nCurrBit - 1) % 8L) & 7L; + } + } + break; + + case BMP_FORMAT_1BIT_LSB_PAL: + // FALLTHROUGH intended + case BMP_FORMAT_4BIT_LSN_PAL: + // FALLTHROUGH intended + case BMP_FORMAT_8BIT_TC_MASK: + // FALLTHROUGH intended + case BMP_FORMAT_24BIT_TC_RGB: + // FALLTHROUGH intended + case BMP_FORMAT_24BIT_TC_MASK: + // FALLTHROUGH intended + case BMP_FORMAT_16BIT_TC_MSB_MASK: + // FALLTHROUGH intended + case BMP_FORMAT_32BIT_TC_ABGR: + // FALLTHROUGH intended + case BMP_FORMAT_32BIT_TC_ARGB: + // FALLTHROUGH intended + case BMP_FORMAT_32BIT_TC_BGRA: + // FALLTHROUGH intended + case BMP_FORMAT_32BIT_TC_RGBA: + // FALLTHROUGH intended + default: + ENSURE_OR_THROW( false, + "::dxcanvas::tools::bitmapFromVCLBitmapEx(): " + "Unexpected scanline format - has " + "WinSalBitmap::AcquireBuffer() changed?" ); + } + } + } + + return aBmpData; + } + + bool drawVCLBitmapEx( const ::boost::shared_ptr< Gdiplus::Graphics >& rGraphics, + const ::BitmapEx& rBmpEx ) + { + if( !rBmpEx.IsTransparent() ) + { + Bitmap aBmp( rBmpEx.GetBitmap() ); + return drawVCLBitmap( rGraphics, aBmp ); + } + else + { + return drawRGBABits( rGraphics, + bitmapFromVCLBitmapEx( rBmpEx ) ); + } + } + } + + bool drawVCLBitmapFromXBitmap( const ::boost::shared_ptr< Gdiplus::Graphics >& rGraphics, + const uno::Reference< rendering::XBitmap >& xBitmap ) + { + // TODO(F2): add support for floating point bitmap formats + uno::Reference< rendering::XIntegerReadOnlyBitmap > xIntBmp( + xBitmap, uno::UNO_QUERY ); + + if( !xIntBmp.is() ) + return false; + + ::BitmapEx aBmpEx = ::vcl::unotools::bitmapExFromXBitmap( xIntBmp ); + if( !aBmpEx ) + return false; + + return drawVCLBitmapEx( rGraphics, aBmpEx ); + } + } +} diff --git a/canvas/source/directx/dx_vcltools.hxx b/canvas/source/directx/dx_vcltools.hxx new file mode 100755 index 000000000000..c3566951d46a --- /dev/null +++ b/canvas/source/directx/dx_vcltools.hxx @@ -0,0 +1,67 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_vcltools.hxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _DXCANVAS_VCLTOOLS_HXX +#define _DXCANVAS_VCLTOOLS_HXX + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/util/TriState.hpp> + +#include <boost/shared_ptr.hpp> + + +namespace com { namespace sun { namespace star { namespace lang +{ + class XUnoTunnel; +} } } } + +namespace Gdiplus { class Graphics; } + +namespace dxcanvas +{ + namespace tools + { + /** Raw RGBA bitmap data, + contiguous in memory + */ + struct RawRGBABitmap + { + sal_Int32 mnWidth; + sal_Int32 mnHeight; + ::boost::shared_ptr< sal_uInt8 > mpBitmapData; + }; + + bool drawVCLBitmapFromXBitmap( const ::boost::shared_ptr< Gdiplus::Graphics >& rGraphics, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XBitmap >& xBitmap ); + } +} + +#endif /* _DXCANVAS_VCLTOOLS_HXX */ diff --git a/canvas/source/directx/dx_winstuff.hxx b/canvas/source/directx/dx_winstuff.hxx new file mode 100755 index 000000000000..1c64506c0f21 --- /dev/null +++ b/canvas/source/directx/dx_winstuff.hxx @@ -0,0 +1,222 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dx_winstuff.hxx,v $ + * $Revision: 1.3 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _DXCANVAS_WINSTUFF_HXX +#define _DXCANVAS_WINSTUFF_HXX + +#include <algorithm> + +#include <boost/shared_ptr.hpp> + +#include <basegfx/numeric/ftools.hxx> + +#ifdef _WINDOWS_ +#error someone else included <windows.h> +#endif + +// Enabling Direct3D Debug Information Further more, with registry key +// \\HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Direct3D\D3D9Debugging\\EnableCreationStack +// set to 1, sets a backtrace each time an object is created to the +// following global variable: LPCWSTR CreationCallStack +#if OSL_DEBUG_LEVEL > 0 +# define D3D_DEBUG_INFO +#endif + +#ifndef DIRECTX_VERSION +#error please define for which directx version we should compile +#endif + +#if defined _MSC_VER +#pragma warning(push,1) +#endif + + +#define BOOL win32BOOL +#define INT32 win32INT32 +#define UINT32 win32UINT32 +#define GradientStyle_RECT win32GradientStyle_RECT +#define Polygon win32Polygon +#define PolyPolygon win32PolyPolygon +#undef WB_LEFT +#undef WB_RIGHT + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> // TODO(Q1): extract minimal set of required headers for gdiplus + +#if DIRECTX_VERSION < 0x0900 + + #include <multimon.h> + + // Be compatible with directdraw 3.0. Lets see how far this takes us + #define DIRECTDRAW_VERSION 0x0300 + #include <ddraw.h> + + // Be compatible with direct3d 5.0. Lets see how far this takes us + #define DIRECT3D_VERSION 0x0500 + #define D3D_OVERLOADS + #include <d3d.h> + + typedef IDirectDrawSurface surface_type; + +#else + + #include <d3d9.h> + #include <d3dx9.h> + #include <dxerr9.h> + + typedef IDirect3DSurface9 surface_type; + +#endif + +#undef DrawText + +#ifdef __MINGW32__
+using ::std::max;
+using ::std::min;
+#endif
+
+#include <gdiplus.h> + +#ifdef min +# undef min +#endif +#ifdef max +# undef max +#endif + +namespace dxcanvas +{ + // some shared pointer typedefs to Gdiplus objects + typedef ::boost::shared_ptr< Gdiplus::Graphics > GraphicsSharedPtr; + typedef ::boost::shared_ptr< Gdiplus::GraphicsPath > GraphicsPathSharedPtr; + typedef ::boost::shared_ptr< Gdiplus::Bitmap > BitmapSharedPtr; + typedef ::boost::shared_ptr< Gdiplus::CachedBitmap > CachedBitmapSharedPtr; + typedef ::boost::shared_ptr< Gdiplus::Font > FontSharedPtr; + typedef ::boost::shared_ptr< Gdiplus::Brush > BrushSharedPtr; + typedef ::boost::shared_ptr< Gdiplus::TextureBrush > TextureBrushSharedPtr; + + /** COM object RAII wrapper + + This template wraps a Windows COM object, transparently + handling lifetime issues the C++ way (i.e. releasing the + reference when the object is destroyed) + */ + template< typename T > class COMReference + { + public: + typedef T Wrappee; + + COMReference() : + mp( NULL ) + { + } + + /** Create from raw pointer + + @attention This constructor assumes the interface is + already acquired (unless p is NULL), no additional AddRef + is called here. + + This caters e.g. for all DirectX factory methods, which + return the created interfaces pre-acquired, into a raw + pointer. Simply pass the pointer to this class, but don't + call Release manually on it! + + @example IDirectDrawSurface* pSurface; + pDD->CreateSurface(&aSurfaceDesc, &pSurface, NULL); + mpSurface = COMReference< IDirectDrawSurface >(pSurface); + + */ + explicit COMReference( T* p ) : + mp( p ) + { + } + + COMReference( const COMReference& rNew ) : + mp( NULL ) + { + if( rNew.mp == NULL ) + return; + + rNew.mp->AddRef(); // do that _before_ assigning the + // pointer. Just in case... + mp = rNew.mp; + } + + COMReference& operator=( const COMReference& rRHS ) + { + COMReference aTmp(rRHS); + ::std::swap( mp, aTmp.mp ); + + return *this; + } + + ~COMReference() + { + reset(); + } + + int reset() + { + int refcount = 0; + if( mp ) + refcount = mp->Release(); + + mp = NULL; + return refcount; + } + + bool is() const { return mp != NULL; } + T* get() const { return mp; } + T* operator->() const { return mp; } + T& operator*() const { return *mp; } + + private: + T* mp; + }; + + // get_pointer() enables boost::mem_fn to recognize COMReference + template<class T> inline T * get_pointer(COMReference<T> const& p) + { + return p.get(); + } +} + +#if defined _MSC_VER +#pragma warning(pop) +#endif + +#undef DELETE +#undef BOOL +#undef INT32 +#undef UINT32 +#undef PolyPolygon + +#endif /* _DXCANVAS_WINSTUFF_HXX */ diff --git a/canvas/source/directx/exports.dxp b/canvas/source/directx/exports.dxp new file mode 100644 index 000000000000..9630d7e06768 --- /dev/null +++ b/canvas/source/directx/exports.dxp @@ -0,0 +1,3 @@ +component_getImplementationEnvironment +component_writeInfo +component_getFactory diff --git a/canvas/source/directx/makefile.mk b/canvas/source/directx/makefile.mk new file mode 100644 index 000000000000..1a9db2ec51c0 --- /dev/null +++ b/canvas/source/directx/makefile.mk @@ -0,0 +1,223 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.9 $ +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=canvas +TARGET=directx9canvas +TARGET2=directx5canvas +TARGET3=gdipluscanvas +ENABLE_EXCEPTIONS=TRUE + + +# --- Settings ----------------------------------------------------------- + +.INCLUDE : settings.mk +DLLPRE = + +# --- Nothing to do if we're compiling with --disable-directx ----------- +.IF "$(ENABLE_DIRECTX)" == "" +@all: + @echo "Building without DirectX support..." +.ENDIF + + +# --- Common ---------------------------------------------------------- + +.IF "$(verbose)"!="" || "$(VERBOSE)"!="" +CDEFS+= -DVERBOSE +.ENDIF + +.IF "$(dx_debug_images)"!="" || "$(DX_DEBUG_IMAGES)"!="" +CDEFS+= -DDX_DEBUG_IMAGES +.ENDIF + +# --- This is Windows only! { ---------------------------------------------------------------- + +.IF "$(GUI)" == "WNT" + +SHARED_SLOFILES = \ + $(SLO)$/dx_bitmap.obj \ + $(SLO)$/dx_bitmapcanvashelper.obj \ + $(SLO)$/dx_canvasbitmap.obj \ + $(SLO)$/dx_canvasfont.obj \ + $(SLO)$/dx_canvashelper.obj \ + $(SLO)$/dx_canvashelper_texturefill.obj \ + $(SLO)$/dx_devicehelper.obj \ + $(SLO)$/dx_gdiplususer.obj \ + $(SLO)$/dx_impltools.obj \ + $(SLO)$/dx_linepolypolygon.obj \ + $(SLO)$/dx_textlayout.obj \ + $(SLO)$/dx_textlayout_drawhelper.obj \ + $(SLO)$/dx_vcltools.obj + +DX_SLOFILES = \ + $(SLO)$/dx_5rm.obj \ + $(SLO)$/dx_9rm.obj \ + $(SLO)$/dx_canvascustomsprite.obj \ + $(SLO)$/dx_config.obj \ + $(SLO)$/dx_spritecanvas.obj \ + $(SLO)$/dx_spritecanvashelper.obj \ + $(SLO)$/dx_spritedevicehelper.obj \ + $(SLO)$/dx_spritehelper.obj \ + $(SLO)$/dx_surfacebitmap.obj \ + $(SLO)$/dx_surfacegraphics.obj +DX_SLOFILES += $(SHARED_SLOFILES) + +GDIPLUS_SLOFILES = \ + $(SLO)$/dx_canvas.obj +GDIPLUS_SLOFILES += $(SHARED_SLOFILES) + +STDLIBS= $(CPPULIB) $(TKLIB) $(SALLIB) $(COMPHELPERLIB) $(CPPUHELPERLIB) $(BASEGFXLIB) $(CANVASTOOLSLIB) $(VCLLIB) $(TOOLSLIB) $(UNOTOOLSLIB) $(I18NISOLANGLIB) + + +######################################################## +# DX9 +######################################################## + +# Indicates the source obj files for the dx5 lib +LIB1TARGET= $(SLB)$/$(TARGET).lib +LIB1OBJFILES = $(DX_SLOFILES) + +# Indicates the filename of the shared library. +SHL1TARGET=$(TARGET).uno + +# Links import libraries. +SHL1STDLIBS= $(STDLIBS) + +# Specifies an import library to create. For Win32 only. +SHL1IMPLIB=i$(TARGET) + +# Specifies libraries from the same module to put into the shared library. +SHL1LIBS=$(SLB)$/$(TARGET).lib + +SHL1DEF=$(MISC)$/$(SHL1TARGET).def + +DEF1NAME=$(SHL1TARGET) +DEF1EXPORTFILE=exports.dxp + +CDEFS+=-DDIRECTX_VERSION=0x0900 + +SHL1STDLIBS += $(GDI32LIB) +.IF "$(COM)" == "GCC" +SHL1STDLIBS += $(DIRECTXSDK_LIB)/d3d9.lib +.ELSE +SHL1STDLIBS += d3d9.lib +.ENDIF +SHL1STDLIBS += $(GDIPLUSLIB) + +.IF "$(dx_debug_images)"!="" || "$(DX_DEBUG_IMAGES)"!="" +SHL1STDLIBS += imdebug.lib +.ENDIF + + +######################################################## +# DX5 +######################################################## + +.IF "$(USE_DIRECTX5)" != "" +SECOND_BUILD=DX5 +DX5_SLOFILES=$(DX_SLOFILES) +DX5CDEFS += -DDIRECTX_VERSION=0x0500 + +LIB2TARGET= $(SLB)$/$(TARGET2).lib +LIB2OBJFILES = $(REAL_DX5_SLOFILES) + +# Indicates the filename of the shared library. +SHL2TARGET=$(TARGET2).uno + +# Links import libraries. +SHL2STDLIBS= $(STDLIBS) + +# Specifies an import library to create. For Win32 only. +SHL2IMPLIB=i$(TARGET2).lib + +# Specifies libraries from the same module to put into the shared library. +SHL2LIBS=$(SLB)$/$(TARGET2).lib +SHL2DEF=$(MISC)$/$(SHL2TARGET).def + +DEF2NAME=$(SHL2TARGET) +DEF2EXPORTFILE=exports.dxp + +SHL2STDLIBS += $(GDI32LIB) +SHL2STDLIBS += $(DDRAWLIB) +SHL2STDLIBS += $(GDIPLUSLIB) + +.IF "$(COM)" == "GCC" +SHL2STDLIBS += $(DIRECTXSDK_LIB)/d3dx.lib +.ELSE +SHL2STDLIBS += d3dx.lib +.ENDIF + +.IF "$(dx_debug_images)"!="" || "$(DX_DEBUG_IMAGES)"!="" +SHL2STDLIBS += imdebug.lib +.ENDIF +.ENDIF # IF "$(USE_DIRECTX5)" != "" + + +######################################################## +# GDI+ +######################################################## + +LIB3TARGET= $(SLB)$/$(TARGET3).lib +LIB3OBJFILES = $(GDIPLUS_SLOFILES) + +# Indicates the filename of the shared library. +SHL3TARGET=$(TARGET3).uno + +# Links import libraries. +SHL3STDLIBS= $(CPPULIB) $(TKLIB) $(SALLIB) $(COMPHELPERLIB) $(CPPUHELPERLIB) $(BASEGFXLIB) $(CANVASTOOLSLIB) $(VCLLIB) $(TOOLSLIB) $(UNOTOOLSLIB) $(I18NISOLANGLIB) + +# Specifies an import library to create. For Win32 only. +SHL3IMPLIB=i$(TARGET3).lib + +# Specifies libraries from the same module to put into the shared library. +SHL3LIBS=$(SLB)$/$(TARGET3).lib +SHL3DEF=$(MISC)$/$(SHL3TARGET).def + +DEF3NAME=$(SHL3TARGET) +DEF3EXPORTFILE=exports.dxp + +SHL3STDLIBS += $(GDI32LIB) +SHL3STDLIBS += $(GDIPLUSLIB) + +.IF "$(dx_debug_images)"!="" || "$(DX_DEBUG_IMAGES)"!="" +SHL3STDLIBS += imdebug.lib +.ENDIF + +.ENDIF # IF "$(GUI)" == "WNT" + +# --- This is Windows only! } ---------------------------------------------------------------- + +# ========================================================================== + +.INCLUDE : target.mk + |