Branch libreoffice-5-0-4
[LibreOffice.git] / canvas / source / directx / dx_surfacebitmap.cxx
blob529c37c016f5141fb64f5c05c6dd394985985d89
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <string.h>
22 #include <com/sun/star/rendering/ColorComponentTag.hpp>
24 #include "dx_surfacebitmap.hxx"
25 #include "dx_impltools.hxx"
26 #include "dx_surfacegraphics.hxx"
27 #include "dx_graphicsprovider.hxx"
29 #include <canvas/debug.hxx>
30 #include <tools/diagnose_ex.h>
32 #include <basegfx/matrix/b2dhommatrix.hxx>
33 #include <basegfx/range/b2irange.hxx>
35 #if defined(DX_DEBUG_IMAGES)
36 # if OSL_DEBUG_LEVEL > 0
37 # include <imdebug.h>
38 # undef min
39 # undef max
40 # endif
41 #endif
43 using namespace ::com::sun::star;
45 namespace dxcanvas
47 namespace
50 // DXColorBuffer
53 struct DXColorBuffer : public canvas::IColorBuffer
55 public:
56 DXColorBuffer( const COMReference<surface_type>& rSurface,
57 const ::basegfx::B2IVector& rSize ) :
58 mpSurface(rSurface),
59 maSize(rSize),
60 mbAlpha(false)
64 // implementation of the 'IColorBuffer' interface
65 public:
67 virtual sal_uInt8* lock() const;
68 virtual void unlock() const;
69 virtual sal_uInt32 getWidth() const;
70 virtual sal_uInt32 getHeight() const;
71 virtual sal_uInt32 getStride() const;
72 virtual Format getFormat() const;
74 private:
76 ::basegfx::B2IVector maSize;
77 mutable D3DLOCKED_RECT maLockedRect;
78 mutable COMReference<surface_type> mpSurface;
79 bool mbAlpha;
82 sal_uInt8* DXColorBuffer::lock() const
84 if(SUCCEEDED(mpSurface->LockRect(&maLockedRect,NULL,D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY)))
85 return static_cast<sal_uInt8 *>(maLockedRect.pBits);
86 return NULL;
89 void DXColorBuffer::unlock() const
91 mpSurface->UnlockRect();
94 sal_uInt32 DXColorBuffer::getWidth() const
96 return maSize.getX();
99 sal_uInt32 DXColorBuffer::getHeight() const
101 return maSize.getY();
104 sal_uInt32 DXColorBuffer::getStride() const
106 return maLockedRect.Pitch;
109 canvas::IColorBuffer::Format DXColorBuffer::getFormat() const
111 return canvas::IColorBuffer::FMT_X8R8G8B8;
115 // GDIColorBuffer
118 struct GDIColorBuffer : public canvas::IColorBuffer
120 public:
122 GDIColorBuffer( const BitmapSharedPtr& rSurface,
123 const ::basegfx::B2IVector& rSize ) :
124 mpGDIPlusBitmap(rSurface),
125 maSize(rSize),
126 mbAlpha(true)
130 // implementation of the 'IColorBuffer' interface
131 public:
133 virtual sal_uInt8* lock() const;
134 virtual void unlock() const;
135 virtual sal_uInt32 getWidth() const;
136 virtual sal_uInt32 getHeight() const;
137 virtual sal_uInt32 getStride() const;
138 virtual Format getFormat() const;
140 private:
142 ::basegfx::B2IVector maSize;
143 mutable Gdiplus::BitmapData aBmpData;
144 BitmapSharedPtr mpGDIPlusBitmap;
145 bool mbAlpha;
148 sal_uInt8* GDIColorBuffer::lock() const
150 aBmpData.Width = maSize.getX();
151 aBmpData.Height = maSize.getY();
152 aBmpData.Stride = 4*aBmpData.Width;
153 aBmpData.PixelFormat = PixelFormat32bppARGB;
154 aBmpData.Scan0 = NULL;
155 const Gdiplus::Rect aRect( 0,0,aBmpData.Width,aBmpData.Height );
156 if( Gdiplus::Ok != mpGDIPlusBitmap->LockBits( &aRect,
157 Gdiplus::ImageLockModeRead,
158 PixelFormat32bppARGB,
159 &aBmpData ) )
161 return NULL;
164 return static_cast<sal_uInt8*>(aBmpData.Scan0);
167 void GDIColorBuffer::unlock() const
169 mpGDIPlusBitmap->UnlockBits( &aBmpData );
172 sal_uInt32 GDIColorBuffer::getWidth() const
174 return maSize.getX();
177 sal_uInt32 GDIColorBuffer::getHeight() const
179 return maSize.getY();
182 sal_uInt32 GDIColorBuffer::getStride() const
184 return aBmpData.Stride;
187 canvas::IColorBuffer::Format GDIColorBuffer::getFormat() const
189 return canvas::IColorBuffer::FMT_A8R8G8B8;
194 // DXSurfaceBitmap::DXSurfaceBitmap
197 DXSurfaceBitmap::DXSurfaceBitmap( const ::basegfx::B2IVector& rSize,
198 const canvas::ISurfaceProxyManagerSharedPtr& rMgr,
199 const IDXRenderModuleSharedPtr& rRenderModule,
200 bool bWithAlpha ) :
201 mpGdiPlusUser( GDIPlusUser::createInstance() ),
202 maSize(rSize),
203 mpRenderModule(rRenderModule),
204 mpSurfaceManager(rMgr),
205 mpSurfaceProxy(),
206 mpSurface(),
207 mpGDIPlusBitmap(),
208 mpGraphics(),
209 mpColorBuffer(),
210 mbIsSurfaceDirty(true),
211 mbAlpha(bWithAlpha)
213 init();
217 // DXSurfaceBitmap::getSize
220 ::basegfx::B2IVector DXSurfaceBitmap::getSize() const
222 return maSize;
226 // DXSurfaceBitmap::init
229 void DXSurfaceBitmap::init()
231 // create container for pixel data
232 if(mbAlpha)
234 mpGDIPlusBitmap.reset(
235 new Gdiplus::Bitmap(
236 maSize.getX(),
237 maSize.getY(),
238 PixelFormat32bppARGB
240 mpGraphics.reset( tools::createGraphicsFromBitmap(mpGDIPlusBitmap) );
242 // create the colorbuffer object, which is basically a simple
243 // wrapper around the directx surface. the colorbuffer is the
244 // interface which is used by the surfaceproxy to support any
245 // kind of underlying structure for the pixel data container.
246 mpColorBuffer.reset(new GDIColorBuffer(mpGDIPlusBitmap,maSize));
248 else
250 mpSurface = mpRenderModule->createSystemMemorySurface(maSize);
252 // create the colorbuffer object, which is basically a simple
253 // wrapper around the directx surface. the colorbuffer is the
254 // interface which is used by the surfaceproxy to support any
255 // kind of underlying structure for the pixel data container.
256 mpColorBuffer.reset(new DXColorBuffer(mpSurface,maSize));
259 // create a (possibly hardware accelerated) mirror surface.
260 mpSurfaceProxy = mpSurfaceManager->createSurfaceProxy(mpColorBuffer);
264 // DXSurfaceBitmap::resize
267 bool DXSurfaceBitmap::resize( const ::basegfx::B2IVector& rSize )
269 if(maSize != rSize)
271 maSize = rSize;
272 init();
275 return true;
279 // DXSurfaceBitmap::clear
282 void DXSurfaceBitmap::clear()
284 GraphicsSharedPtr pGraphics(getGraphics());
285 Gdiplus::Color transColor(255,0,0,0);
286 pGraphics->SetCompositingMode( Gdiplus::CompositingModeSourceCopy );
287 pGraphics->Clear( transColor );
291 // DXSurfaceBitmap::hasAlpha
294 bool DXSurfaceBitmap::hasAlpha() const
296 return mbAlpha;
300 // DXSurfaceBitmap::getGraphics
303 GraphicsSharedPtr DXSurfaceBitmap::getGraphics()
305 // since clients will most probably draw directly
306 // to the GDI+ bitmap, we need to mark it as dirty
307 // to ensure that the corrosponding dxsurface will
308 // be updated.
309 mbIsSurfaceDirty = true;
311 if(hasAlpha())
312 return mpGraphics;
313 else
314 return createSurfaceGraphics(mpSurface);
318 // DXSurfaceBitmap::getBitmap
321 BitmapSharedPtr DXSurfaceBitmap::getBitmap() const
323 if(hasAlpha())
324 return mpGDIPlusBitmap;
326 BitmapSharedPtr pResult;
328 D3DLOCKED_RECT aLockedRect;
329 if(SUCCEEDED(mpSurface->LockRect(&aLockedRect,NULL,D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY)))
331 // decide about the format we pass the gdi+, the directx surface is always
332 // 32bit, either with or without alpha component.
333 Gdiplus::PixelFormat nFormat = hasAlpha() ? PixelFormat32bppARGB : PixelFormat32bppRGB;
335 // construct a gdi+ bitmap from the raw pixel data.
336 pResult.reset(new Gdiplus::Bitmap( maSize.getX(),maSize.getY(),
337 aLockedRect.Pitch,
338 nFormat,
339 (BYTE *)aLockedRect.pBits ));
341 mpSurface->UnlockRect();
344 return pResult;
348 // DXSurfaceBitmap::draw
351 bool DXSurfaceBitmap::draw( double fAlpha,
352 const ::basegfx::B2DPoint& rPos,
353 const ::basegfx::B2DPolyPolygon& rClipPoly,
354 const ::basegfx::B2DHomMatrix& rTransform )
356 if( mbIsSurfaceDirty )
358 mpSurfaceProxy->setColorBufferDirty();
359 mbIsSurfaceDirty = false;
362 return mpSurfaceProxy->draw( fAlpha, rPos, rClipPoly, rTransform );
366 // DXSurfaceBitmap::draw
369 bool DXSurfaceBitmap::draw( double fAlpha,
370 const ::basegfx::B2DPoint& rPos,
371 const ::basegfx::B2DRange& rArea,
372 const ::basegfx::B2DHomMatrix& rTransform )
374 if( mbIsSurfaceDirty )
376 mpSurfaceProxy->setColorBufferDirty();
377 mbIsSurfaceDirty = false;
380 return mpSurfaceProxy->draw( fAlpha, rPos, rArea, rTransform );
384 // DXSurfaceBitmap::draw
387 bool DXSurfaceBitmap::draw( double fAlpha,
388 const ::basegfx::B2DPoint& rPos,
389 const ::basegfx::B2DHomMatrix& rTransform )
391 if( mbIsSurfaceDirty )
393 mpSurfaceProxy->setColorBufferDirty();
394 mbIsSurfaceDirty = false;
397 return mpSurfaceProxy->draw( fAlpha, rPos, rTransform );
401 // DXSurfaceBitmap::draw
404 bool DXSurfaceBitmap::draw( const ::basegfx::B2IRange& rArea )
406 if( mbIsSurfaceDirty )
408 mpSurfaceProxy->setColorBufferDirty();
409 mbIsSurfaceDirty = false;
412 const double fAlpha(1.0);
413 const ::basegfx::B2DHomMatrix aTransform;
414 const ::basegfx::B2DRange aIEEEArea( rArea );
415 return mpSurfaceProxy->draw(fAlpha,
416 ::basegfx::B2DPoint(),
417 aIEEEArea,
418 aTransform);
422 // DXSurfaceBitmap::imageDebugger
424 #if defined(DX_DEBUG_IMAGES)
425 # if OSL_DEBUG_LEVEL > 0
426 void DXSurfaceBitmap::imageDebugger()
428 D3DLOCKED_RECT aLockedRect;
429 if( FAILED(mpSurface->LockRect(&aLockedRect,NULL,D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY)) )
430 return;
432 imdebug("bgra w=%d h=%d %p", maSize.getX(),
433 maSize.getY(), aLockedRect.pBits);
434 mpSurface->UnlockRect();
436 # endif
437 #endif
440 // DXSurfaceBitmap::getData
443 uno::Sequence< sal_Int8 > DXSurfaceBitmap::getData( rendering::IntegerBitmapLayout& rBitmapLayout,
444 const geometry::IntegerRectangle2D& rect )
446 if(hasAlpha())
448 uno::Sequence< sal_Int8 > aRes( (rect.X2-rect.X1)*(rect.Y2-rect.Y1)*4 ); // TODO(F1): Be format-agnostic here
450 const Gdiplus::Rect aRect( tools::gdiPlusRectFromIntegerRectangle2D( rect ) );
452 Gdiplus::BitmapData aBmpData;
453 aBmpData.Width = rect.X2-rect.X1;
454 aBmpData.Height = rect.Y2-rect.Y1;
455 aBmpData.Stride = 4*aBmpData.Width;
456 aBmpData.PixelFormat = PixelFormat32bppARGB;
457 aBmpData.Scan0 = aRes.getArray();
459 // TODO(F1): Support more pixel formats natively
461 // read data from bitmap
462 if( Gdiplus::Ok != mpGDIPlusBitmap->LockBits( &aRect,
463 Gdiplus::ImageLockModeRead | Gdiplus::ImageLockModeUserInputBuf,
464 PixelFormat32bppARGB, // TODO(F1): Adapt to
465 // Graphics native
466 // format/change
467 // getMemoryLayout
468 &aBmpData ) )
470 // failed to lock, bail out
471 return uno::Sequence< sal_Int8 >();
474 mpGDIPlusBitmap->UnlockBits( &aBmpData );
476 return aRes;
478 else
480 sal_uInt32 nWidth = rect.X2-rect.X1;
481 sal_uInt32 nHeight = rect.Y2-rect.Y1;
483 uno::Sequence< sal_Int8 > aRes(nWidth*nHeight*4);
485 D3DLOCKED_RECT aLockedRect;
486 if(FAILED(mpSurface->LockRect(&aLockedRect,NULL,D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY)))
487 return uno::Sequence< sal_Int8 >();
488 D3DSURFACE_DESC aDesc;
489 if(FAILED(mpSurface->GetDesc(&aDesc)))
490 return uno::Sequence< sal_Int8 >();
492 assert(aDesc.Format == D3DFMT_A8R8G8B8 || aDesc.Format == D3DFMT_X8R8G8B8);
494 sal_uInt8 *pSrc = (sal_uInt8 *)((((BYTE *)aLockedRect.pBits)+(rect.Y1*aLockedRect.Pitch))+rect.X1);
495 sal_uInt8 *pDst = (sal_uInt8 *)aRes.getArray();
496 sal_uInt32 nSegmentSizeInBytes = nWidth*4;
497 for(sal_uInt32 y=0; y<nHeight; ++y)
499 memcpy(pDst,pSrc,nSegmentSizeInBytes);
500 pDst += nSegmentSizeInBytes;
501 pSrc += aLockedRect.Pitch;
504 if(rBitmapLayout.ColorSpace->getComponentTags().getArray()[0] == rendering::ColorComponentTag::RGB_RED &&
505 rBitmapLayout.ColorSpace->getComponentTags().getArray()[2] == rendering::ColorComponentTag::RGB_BLUE)
507 pDst = (sal_uInt8 *)aRes.getArray();
508 for(sal_uInt32 y=0; y<nHeight; ++y)
510 sal_uInt8* pPixel = pDst;
511 for(sal_uInt32 n = 0; n<nWidth; n++)
513 sal_uInt8 nB = pPixel[0];
514 pPixel[0] = pPixel[2];
515 pPixel[2] = nB;
516 pPixel += 4;
518 pDst += nSegmentSizeInBytes;
522 mpSurface->UnlockRect();
523 return aRes;
528 // DXSurfaceBitmap::setData
531 void DXSurfaceBitmap::setData( const uno::Sequence< sal_Int8 >& data,
532 const rendering::IntegerBitmapLayout& /*bitmapLayout*/,
533 const geometry::IntegerRectangle2D& rect )
535 if(hasAlpha())
537 const Gdiplus::Rect aRect( tools::gdiPlusRectFromIntegerRectangle2D( rect ) );
539 Gdiplus::BitmapData aBmpData;
540 aBmpData.Width = rect.X2-rect.X1;
541 aBmpData.Height = rect.Y2-rect.Y1;
542 aBmpData.Stride = 4*aBmpData.Width;
543 aBmpData.PixelFormat = PixelFormat32bppARGB;
544 aBmpData.Scan0 = (void*)data.getConstArray();
546 // TODO(F1): Support more pixel formats natively
548 if( Gdiplus::Ok != mpGDIPlusBitmap->LockBits( &aRect,
549 Gdiplus::ImageLockModeWrite | Gdiplus::ImageLockModeUserInputBuf,
550 PixelFormat32bppARGB, // TODO: Adapt to
551 // Graphics native
552 // format/change
553 // getMemoryLayout
554 &aBmpData ) )
556 throw uno::RuntimeException();
559 // commit data to bitmap
560 mpGDIPlusBitmap->UnlockBits( &aBmpData );
562 else
564 sal_uInt32 nWidth = rect.X2-rect.X1;
565 sal_uInt32 nHeight = rect.Y2-rect.Y1;
567 // lock the directx surface to receive the pointer to the surface memory.
568 D3DLOCKED_RECT aLockedRect;
569 if(FAILED(mpSurface->LockRect(&aLockedRect,NULL,D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY)))
570 throw uno::RuntimeException();
572 sal_uInt8 *pSrc = (sal_uInt8 *)data.getConstArray();
573 sal_uInt8 *pDst = (sal_uInt8 *)((((BYTE *)aLockedRect.pBits)+(rect.Y1*aLockedRect.Pitch))+rect.X1);
574 sal_uInt32 nSegmentSizeInBytes = nWidth<<4;
575 for(sal_uInt32 y=0; y<nHeight; ++y)
577 memcpy(pDst,pSrc,nSegmentSizeInBytes);
578 pSrc += nSegmentSizeInBytes;
579 pDst += aLockedRect.Pitch;
582 mpSurface->UnlockRect();
585 mbIsSurfaceDirty = true;
589 // DXSurfaceBitmap::setPixel
592 void DXSurfaceBitmap::setPixel( const uno::Sequence< sal_Int8 >& color,
593 const rendering::IntegerBitmapLayout& /*bitmapLayout*/,
594 const geometry::IntegerPoint2D& pos )
596 if(hasAlpha())
598 const geometry::IntegerSize2D aSize( maSize.getX(),maSize.getY() );
600 ENSURE_ARG_OR_THROW( pos.X >= 0 && pos.X < aSize.Width,
601 "CanvasHelper::setPixel: X coordinate out of bounds" );
602 ENSURE_ARG_OR_THROW( pos.Y >= 0 && pos.Y < aSize.Height,
603 "CanvasHelper::setPixel: Y coordinate out of bounds" );
604 ENSURE_ARG_OR_THROW( color.getLength() > 3,
605 "CanvasHelper::setPixel: not enough color components" );
607 if( Gdiplus::Ok != mpGDIPlusBitmap->SetPixel( pos.X, pos.Y,
608 Gdiplus::Color( tools::sequenceToArgb( color ))))
610 throw uno::RuntimeException();
613 else
615 ENSURE_ARG_OR_THROW( pos.X >= 0 && pos.X < maSize.getX(),
616 "CanvasHelper::setPixel: X coordinate out of bounds" );
617 ENSURE_ARG_OR_THROW( pos.Y >= 0 && pos.Y < maSize.getY(),
618 "CanvasHelper::setPixel: Y coordinate out of bounds" );
619 ENSURE_ARG_OR_THROW( color.getLength() > 3,
620 "CanvasHelper::setPixel: not enough color components" );
622 Gdiplus::Color aColor(tools::sequenceToArgb(color));
624 // lock the directx surface to receive the pointer to the surface memory.
625 D3DLOCKED_RECT aLockedRect;
626 if(FAILED(mpSurface->LockRect(&aLockedRect,NULL,D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY)))
627 throw uno::RuntimeException();
629 sal_uInt32 *pDst = (sal_uInt32 *)((((BYTE *)aLockedRect.pBits)+(pos.Y*aLockedRect.Pitch))+pos.X);
630 *pDst = aColor.GetValue();
631 mpSurface->UnlockRect();
634 mbIsSurfaceDirty = true;
638 // DXSurfaceBitmap::getPixel
641 uno::Sequence< sal_Int8 > DXSurfaceBitmap::getPixel( rendering::IntegerBitmapLayout& /*bitmapLayout*/,
642 const geometry::IntegerPoint2D& pos )
644 if(hasAlpha())
646 const geometry::IntegerSize2D aSize( maSize.getX(),maSize.getY() );
648 ENSURE_ARG_OR_THROW( pos.X >= 0 && pos.X < aSize.Width,
649 "CanvasHelper::getPixel: X coordinate out of bounds" );
650 ENSURE_ARG_OR_THROW( pos.Y >= 0 && pos.Y < aSize.Height,
651 "CanvasHelper::getPixel: Y coordinate out of bounds" );
653 Gdiplus::Color aColor;
655 if( Gdiplus::Ok != mpGDIPlusBitmap->GetPixel( pos.X, pos.Y, &aColor ) )
656 return uno::Sequence< sal_Int8 >();
658 return tools::argbToIntSequence(aColor.GetValue());
660 else
662 ENSURE_ARG_OR_THROW( pos.X >= 0 && pos.X < maSize.getX(),
663 "CanvasHelper::getPixel: X coordinate out of bounds" );
664 ENSURE_ARG_OR_THROW( pos.Y >= 0 && pos.Y < maSize.getY(),
665 "CanvasHelper::getPixel: Y coordinate out of bounds" );
667 // lock the directx surface to receive the pointer to the surface memory.
668 D3DLOCKED_RECT aLockedRect;
669 if(FAILED(mpSurface->LockRect(&aLockedRect,NULL,D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY)))
670 throw uno::RuntimeException();
672 sal_uInt32 *pDst = (sal_uInt32 *)((((BYTE *)aLockedRect.pBits)+(pos.Y*aLockedRect.Pitch))+pos.X);
673 Gdiplus::Color aColor(*pDst);
674 mpSurface->UnlockRect();
676 return tools::argbToIntSequence(aColor.GetValue());
681 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */