1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
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
43 using namespace ::com::sun::star
;
53 struct DXColorBuffer
: public canvas::IColorBuffer
56 DXColorBuffer( const COMReference
<surface_type
>& rSurface
,
57 const ::basegfx::B2IVector
& rSize
) :
64 // implementation of the 'IColorBuffer' interface
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;
76 ::basegfx::B2IVector maSize
;
77 mutable D3DLOCKED_RECT maLockedRect
;
78 mutable COMReference
<surface_type
> mpSurface
;
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
);
89 void DXColorBuffer::unlock() const
91 mpSurface
->UnlockRect();
94 sal_uInt32
DXColorBuffer::getWidth() const
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
;
118 struct GDIColorBuffer
: public canvas::IColorBuffer
122 GDIColorBuffer( const BitmapSharedPtr
& rSurface
,
123 const ::basegfx::B2IVector
& rSize
) :
124 mpGDIPlusBitmap(rSurface
),
130 // implementation of the 'IColorBuffer' interface
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;
142 ::basegfx::B2IVector maSize
;
143 mutable Gdiplus::BitmapData aBmpData
;
144 BitmapSharedPtr mpGDIPlusBitmap
;
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
,
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
,
201 mpGdiPlusUser( GDIPlusUser::createInstance() ),
203 mpRenderModule(rRenderModule
),
204 mpSurfaceManager(rMgr
),
210 mbIsSurfaceDirty(true),
217 // DXSurfaceBitmap::getSize
220 ::basegfx::B2IVector
DXSurfaceBitmap::getSize() const
226 // DXSurfaceBitmap::init
229 void DXSurfaceBitmap::init()
231 // create container for pixel data
234 mpGDIPlusBitmap
.reset(
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
));
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
)
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
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
309 mbIsSurfaceDirty
= true;
314 return createSurfaceGraphics(mpSurface
);
318 // DXSurfaceBitmap::getBitmap
321 BitmapSharedPtr
DXSurfaceBitmap::getBitmap() const
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(),
339 (BYTE
*)aLockedRect
.pBits
));
341 mpSurface
->UnlockRect();
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(),
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
)) )
432 imdebug("bgra w=%d h=%d %p", maSize
.getX(),
433 maSize
.getY(), aLockedRect
.pBits
);
434 mpSurface
->UnlockRect();
440 // DXSurfaceBitmap::getData
443 uno::Sequence
< sal_Int8
> DXSurfaceBitmap::getData( rendering::IntegerBitmapLayout
& rBitmapLayout
,
444 const geometry::IntegerRectangle2D
& rect
)
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
470 // failed to lock, bail out
471 return uno::Sequence
< sal_Int8
>();
474 mpGDIPlusBitmap
->UnlockBits( &aBmpData
);
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];
518 pDst
+= nSegmentSizeInBytes
;
522 mpSurface
->UnlockRect();
528 // DXSurfaceBitmap::setData
531 void DXSurfaceBitmap::setData( const uno::Sequence
< sal_Int8
>& data
,
532 const rendering::IntegerBitmapLayout
& /*bitmapLayout*/,
533 const geometry::IntegerRectangle2D
& rect
)
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
556 throw uno::RuntimeException();
559 // commit data to bitmap
560 mpGDIPlusBitmap
->UnlockBits( &aBmpData
);
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
)
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();
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
)
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());
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: */