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 .
20 #include "headless/svpgdi.hxx"
21 #include "headless/svpbmp.hxx"
23 #include "headless/svptextrender.hxx"
25 #include "saldatabasic.hxx"
27 #include <vcl/sysdata.hxx>
28 #include <basegfx/range/b2drange.hxx>
29 #include <basegfx/range/b2ibox.hxx>
30 #include <basegfx/polygon/b2dpolypolygon.hxx>
31 #include <basegfx/polygon/b2dpolypolygontools.hxx>
32 #include <basegfx/polygon/b2dpolygon.hxx>
33 #include <basegfx/polygon/b2dpolygontools.hxx>
34 #include <basebmp/scanlineformats.hxx>
36 #if ENABLE_CAIRO_CANVAS
40 #if OSL_DEBUG_LEVEL > 2
41 #include <basebmp/debug.hxx>
43 #include <rtl/strbuf.hxx>
49 inline void dbgOut( const basebmp::BitmapDeviceSharedPtr
&
50 #if OSL_DEBUG_LEVEL > 2
55 #if OSL_DEBUG_LEVEL > 2
56 static int dbgStreamNum
= 0;
57 OStringBuffer
aBuf( 256 );
58 aBuf
.append( "debug" );
59 mkdir( aBuf
.getStr(), 0777 );
61 aBuf
.append( sal_Int64(reinterpret_cast<sal_IntPtr
>(rDevice
.get())), 16 );
62 mkdir( aBuf
.getStr(), 0777 );
63 aBuf
.append( "/bmp" );
64 aBuf
.append( sal_Int32(dbgStreamNum
++) );
65 std::fstream
bmpstream( aBuf
.getStr(), std::ios::out
);
66 debugDump( rDevice
, bmpstream
);
72 bool SvpSalGraphics::blendBitmap( const SalTwoRect
&, const SalBitmap
& /*rBitmap*/ )
77 bool SvpSalGraphics::blendAlphaBitmap( const SalTwoRect
&, const SalBitmap
&, const SalBitmap
&, const SalBitmap
& )
82 bool SvpSalGraphics::drawAlphaBitmap( const SalTwoRect
&, const SalBitmap
& /*rSourceBitmap*/, const SalBitmap
& /*rAlphaBitmap*/ )
84 // TODO(P3) implement alpha blending
88 bool SvpSalGraphics::drawTransformedBitmap(
89 const basegfx::B2DPoint
& rNull
,
90 const basegfx::B2DPoint
& rX
,
91 const basegfx::B2DPoint
& rY
,
92 const SalBitmap
& rSourceBitmap
,
93 const SalBitmap
* pAlphaBitmap
)
95 // here direct support for transformed bitmaps can be implemented
96 (void)rNull
; (void)rX
; (void)rY
; (void)rSourceBitmap
; (void)pAlphaBitmap
;
100 #if ENABLE_CAIRO_CANVAS
104 bool isCairoCompatible(const basebmp::BitmapDeviceSharedPtr
&rBuffer
)
109 if (rBuffer
->getScanlineFormat() != basebmp::FORMAT_THIRTYTWO_BIT_TC_MASK_BGRX
)
112 #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 10, 0)
113 basegfx::B2IVector size
= rBuffer
->getSize();
114 sal_Int32 nStride
= rBuffer
->getScanlineStride();
115 return (cairo_format_stride_for_width(CAIRO_FORMAT_RGB24
, size
.getX()) == nStride
);
122 void SvpSalGraphics::clipRegion(cairo_t
* cr
)
124 RectangleVector aRectangles
;
125 if (!m_aClipRegion
.IsEmpty())
127 m_aClipRegion
.GetRegionRectangles(aRectangles
);
129 if (!aRectangles
.empty())
131 for (RectangleVector::const_iterator
aRectIter(aRectangles
.begin()); aRectIter
!= aRectangles
.end(); ++aRectIter
)
133 cairo_rectangle(cr
, aRectIter
->Left(), aRectIter
->Top(), aRectIter
->GetWidth(), aRectIter
->GetHeight());
138 #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 10, 0)
141 cairo_rectangle_int_t
getFillDamage(cairo_t
* cr
)
143 cairo_rectangle_int_t extents
;
144 double x1
, y1
, x2
, y2
;
146 cairo_clip_extents(cr
, &x1
, &y1
, &x2
, &y2
);
147 extents
.x
= x1
, extents
.y
= x2
, extents
.width
= x2
-x1
, extents
.height
= y2
-y1
;
148 cairo_region_t
*region
= cairo_region_create_rectangle(&extents
);
150 cairo_fill_extents(cr
, &x1
, &y1
, &x2
, &y2
);
151 extents
.x
= x1
, extents
.y
= x2
, extents
.width
= x2
-x1
, extents
.height
= y2
-y1
;
152 cairo_region_intersect_rectangle(region
, &extents
);
154 cairo_region_get_extents(region
, &extents
);
155 cairo_region_destroy(region
);
164 bool SvpSalGraphics::drawAlphaRect(long nX
, long nY
, long nWidth
, long nHeight
, sal_uInt8 nTransparency
)
167 (void)nX
; (void)nY
; (void)nWidth
; (void)nHeight
; (void)nTransparency
;
168 #if ENABLE_CAIRO_CANVAS
169 #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 10, 0)
170 if (m_bUseLineColor
|| !m_bUseFillColor
)
172 SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawAlphaRect case");
176 cairo_t
* cr
= createCairoContext(m_aDevice
);
180 if (!m_aDevice
->isTopDown())
182 cairo_scale(cr
, 1, -1.0);
183 cairo_translate(cr
, 0.0, -m_aDevice
->getSize().getY());
188 const double fTransparency
= (100 - nTransparency
) * (1.0/100);
189 cairo_set_source_rgba(cr
, m_aFillColor
.getRed()/255.0,
190 m_aFillColor
.getGreen()/255.0,
191 m_aFillColor
.getBlue()/255.0,
193 cairo_rectangle(cr
, nX
, nY
, nWidth
, nHeight
);
195 cairo_rectangle_int_t extents
;
196 basebmp::IBitmapDeviceDamageTrackerSharedPtr
xDamageTracker(m_aDevice
->getDamageTracker());
198 extents
= getFillDamage(cr
);
202 cairo_surface_flush(cairo_get_target(cr
));
203 cairo_destroy(cr
); // unref
207 xDamageTracker
->damaged(basegfx::B2IBox(extents
.x
, extents
.y
, extents
.x
+ extents
.width
,
208 extents
.y
+ extents
.height
));
216 SvpSalGraphics::SvpSalGraphics() :
217 m_bUseLineColor( true ),
218 m_aLineColor( COL_BLACK
),
219 m_bUseFillColor( false ),
220 m_aFillColor( COL_WHITE
),
221 m_aDrawMode( basebmp::DrawMode_PAINT
),
222 m_bClipSetup( false )
224 m_xTextRenderImpl
.reset(new SvpTextRender(*this));
227 SvpSalGraphics::~SvpSalGraphics()
231 void SvpSalGraphics::setDevice( basebmp::BitmapDeviceSharedPtr
& rDevice
)
233 m_aOrigDevice
= rDevice
;
235 m_xTextRenderImpl
->setDevice(rDevice
);
240 void SvpSalGraphics::GetResolution( sal_Int32
& rDPIX
, sal_Int32
& rDPIY
)
247 sal_uInt16
SvpSalGraphics::GetBitCount() const
249 return SvpSalBitmap::getBitCountFromScanlineFormat( m_aDevice
->getScanlineFormat() );
252 long SvpSalGraphics::GetGraphicsWidth() const
254 if( m_aDevice
.get() )
256 basegfx::B2IVector aSize
= m_aOrigDevice
->getSize();
262 void SvpSalGraphics::ResetClipRegion()
264 m_aDevice
= m_aOrigDevice
;
267 m_aClipRegion
.SetNull();
270 // verify clip for the whole area is setup
271 void SvpSalGraphics::ensureClip()
276 m_aDevice
= m_aOrigDevice
;
277 basegfx::B2IVector aSize
= m_aDevice
->getSize();
278 m_aClipMap
= basebmp::createClipDevice( aSize
);
280 RectangleVector aRectangles
;
281 m_aClipRegion
.GetRegionRectangles(aRectangles
);
283 for(RectangleVector::const_iterator
aRectIter(aRectangles
.begin()); aRectIter
!= aRectangles
.end(); ++aRectIter
)
285 const long nW(aRectIter
->GetWidth());
288 const long nH(aRectIter
->GetHeight());
292 basegfx::B2DPolyPolygon aFull
;
295 basegfx::tools::createPolygonFromRect(
296 basegfx::B2DRectangle(
299 aRectIter
->Left() + nW
,
300 aRectIter
->Top() + nH
)));
301 m_aClipMap
->fillPolyPolygon(aFull
, basebmp::Color(0), basebmp::DrawMode_PAINT
);
308 SvpSalGraphics::ClipUndoHandle::~ClipUndoHandle()
310 if( m_aDevice
.get() )
311 m_rGfx
.m_aDevice
= m_aDevice
;
314 // setup a clip rectangle -only- iff we have to; if aRange
315 // is entirely contained inside an existing clip frame, we
316 // will avoid setting up the clip bitmap. Similarly if the
317 // range doesn't appear at all we return true to avoid
319 bool SvpSalGraphics::isClippedSetup( const basegfx::B2IBox
&aRange
, SvpSalGraphics::ClipUndoHandle
&rUndo
)
324 if( m_aClipRegion
.IsEmpty() ) // no clipping
327 // fprintf( stderr, "ensureClipFor: %d, %d %dx%d\n",
328 // aRange.getMinX(), aRange.getMinY(),
329 // (int)aRange.getWidth(), (int)aRange.getHeight() );
331 // first see if aRange is purely internal to one of the clip regions
332 Rectangle
aRect( Point( aRange
.getMinX(), aRange
.getMinY() ),
333 Size( aRange
.getWidth(), aRange
.getHeight() ) );
335 // then see if we are overlapping with just one
338 RectangleVector aRectangles
;
339 m_aClipRegion
.GetRegionRectangles(aRectangles
);
340 for(RectangleVector::const_iterator
aRectIter(aRectangles
.begin()); aRectIter
!= aRectangles
.end(); ++aRectIter
)
342 if( aRectIter
->IsOver( aRect
) )
344 aHitRect
= *aRectIter
;
349 if( nHit
== 0 ) // rendering outside any clipping region
351 SAL_INFO("vcl.headless", "SvpSalGraphics::isClippedSetup: degenerate case detected ...");
354 else if( nHit
== 1 ) // common path: rendering against just one clipping region
356 if( aHitRect
.IsInside( aRect
) )
358 //The region to be painted (aRect) is equal to or inside the
359 //current clipping region
360 SAL_INFO("vcl.headless", "SvpSalGraphics::isClippedSetup: is inside ! avoid deeper clip ...");
363 SAL_INFO("vcl.headless", "SvpSalGraphics::isClippedSetup: operation only overlaps with a single clip zone");
364 rUndo
.m_aDevice
= m_aDevice
;
365 m_aDevice
= basebmp::subsetBitmapDevice( m_aOrigDevice
,
366 basegfx::B2IBox (aHitRect
.Left(),
368 aHitRect
.Right() + 1,
369 aHitRect
.Bottom() + 1) );
372 // fprintf (stderr, "URK: complex & slow clipping case\n" );
373 // horribly slow & complicated case ...
379 // Clipping by creating unconditional mask bitmaps is horribly
380 // slow so defer it, as much as possible. It is common to get
381 // 3 rectangles pushed, and have to create a vast off-screen
382 // mask only to destroy it shortly afterwards. That is
383 // particularly galling if we render only to a small,
384 // well defined rectangular area inside one of these clip
387 // ensureClipFor() or ensureClip() need to be called before
388 // real rendering. FIXME: we should prolly push this down to
389 // bitmapdevice instead.
390 bool SvpSalGraphics::setClipRegion( const vcl::Region
& i_rClip
)
392 m_aClipRegion
= i_rClip
;
394 if( i_rClip
.IsEmpty() )
396 m_aDevice
= m_aOrigDevice
;
401 RectangleVector aRectangles
;
402 i_rClip
.GetRegionRectangles(aRectangles
);
404 if (1 == aRectangles
.size())
406 //simplest case, subset the device to clip bounds
409 const Rectangle
& aBoundRect
= aRectangles
[0];
410 m_aDevice
= basebmp::subsetBitmapDevice(
412 basegfx::B2IBox(aBoundRect
.Left(),aBoundRect
.Top(),aBoundRect
.Right() + 1,aBoundRect
.Bottom() + 1) );
418 //more complex, either setup and tear down temporary
419 //subsets of the original device around render calls
420 //or generate m_aClipMap and pass that to basebmp
422 m_aDevice
= m_aOrigDevice
;
423 m_bClipSetup
= false;
429 void SvpSalGraphics::SetLineColor()
431 m_bUseLineColor
= false;
434 void SvpSalGraphics::SetLineColor( SalColor nSalColor
)
436 m_bUseLineColor
= true;
437 m_aLineColor
= basebmp::Color( nSalColor
);
440 void SvpSalGraphics::SetFillColor()
442 m_bUseFillColor
= false;
445 void SvpSalGraphics::SetFillColor( SalColor nSalColor
)
447 m_bUseFillColor
= true;
448 m_aFillColor
= basebmp::Color( nSalColor
);
451 void SvpSalGraphics::SetXORMode( bool bSet
, bool )
453 m_aDrawMode
= bSet
? basebmp::DrawMode_XOR
: basebmp::DrawMode_PAINT
;
456 void SvpSalGraphics::SetROPLineColor( SalROPColor nROPColor
)
458 m_bUseLineColor
= true;
462 m_aLineColor
= basebmp::Color( 0 );
465 m_aLineColor
= basebmp::Color( 0xffffff );
468 m_aLineColor
= basebmp::Color( 0xffffff );
473 void SvpSalGraphics::SetROPFillColor( SalROPColor nROPColor
)
475 m_bUseFillColor
= true;
479 m_aFillColor
= basebmp::Color( 0 );
482 m_aFillColor
= basebmp::Color( 0xffffff );
485 m_aFillColor
= basebmp::Color( 0xffffff );
490 void SvpSalGraphics::drawPixel( long nX
, long nY
)
492 if( m_bUseLineColor
)
495 m_aDevice
->setPixel( basegfx::B2IPoint( nX
, nY
),
504 void SvpSalGraphics::drawPixel( long nX
, long nY
, SalColor nSalColor
)
506 basebmp::Color
aColor( nSalColor
);
508 m_aDevice
->setPixel( basegfx::B2IPoint( nX
, nY
),
516 void SvpSalGraphics::drawLine( long nX1
, long nY1
, long nX2
, long nY2
)
518 if( m_bUseLineColor
)
520 ensureClip(); // FIXME: for ...
521 m_aDevice
->drawLine( basegfx::B2IPoint( nX1
, nY1
),
522 basegfx::B2IPoint( nX2
, nY2
),
530 void SvpSalGraphics::drawRect( long nX
, long nY
, long nWidth
, long nHeight
)
532 if ((m_bUseLineColor
|| m_bUseFillColor
) && m_aDevice
)
534 ensureClip(); // FIXME: for ...
535 if( m_bUseFillColor
)
537 basegfx::B2DPolygon aRect
= basegfx::tools::createPolygonFromRect( basegfx::B2DRectangle( nX
, nY
, nX
+nWidth
, nY
+nHeight
) );
538 basegfx::B2DPolyPolygon
aPolyPoly( aRect
);
539 m_aDevice
->fillPolyPolygon( aPolyPoly
, m_aFillColor
, m_aDrawMode
, m_aClipMap
);
541 if( m_bUseLineColor
)
543 // need same -1 hack as X11SalGraphicsImpl::drawRect
544 basegfx::B2DPolygon aRect
= basegfx::tools::createPolygonFromRect( basegfx::B2DRectangle( nX
, nY
, nX
+nWidth
-1, nY
+nHeight
-1 ) );
545 m_aDevice
->drawPolygon( aRect
, m_aLineColor
, m_aDrawMode
, m_aClipMap
);
551 void SvpSalGraphics::drawPolyLine( sal_uInt32 nPoints
, const SalPoint
* pPtAry
)
553 if (m_bUseLineColor
&& nPoints
&& m_aDevice
)
555 basegfx::B2DPolygon aPoly
;
556 aPoly
.append( basegfx::B2DPoint( pPtAry
->mnX
, pPtAry
->mnY
), nPoints
);
557 for( sal_uLong i
= 1; i
< nPoints
; i
++ )
558 aPoly
.setB2DPoint( i
, basegfx::B2DPoint( pPtAry
[i
].mnX
, pPtAry
[i
].mnY
) );
559 aPoly
.setClosed( false );
560 ensureClip(); // FIXME: for ...
561 m_aDevice
->drawPolygon( aPoly
, m_aLineColor
, m_aDrawMode
, m_aClipMap
);
566 void SvpSalGraphics::drawPolygon( sal_uInt32 nPoints
, const SalPoint
* pPtAry
)
568 if ((m_bUseLineColor
|| m_bUseFillColor
) && nPoints
&& m_aDevice
)
570 basegfx::B2DPolygon aPoly
;
571 aPoly
.append( basegfx::B2DPoint( pPtAry
->mnX
, pPtAry
->mnY
), nPoints
);
572 for( sal_uLong i
= 1; i
< nPoints
; i
++ )
573 aPoly
.setB2DPoint( i
, basegfx::B2DPoint( pPtAry
[i
].mnX
, pPtAry
[i
].mnY
) );
574 ensureClip(); // FIXME: for ...
575 if( m_bUseFillColor
)
577 aPoly
.setClosed( true );
578 m_aDevice
->fillPolyPolygon( basegfx::B2DPolyPolygon(aPoly
), m_aFillColor
, m_aDrawMode
, m_aClipMap
);
580 if( m_bUseLineColor
)
582 aPoly
.setClosed( false );
583 m_aDevice
->drawPolygon( aPoly
, m_aLineColor
, m_aDrawMode
, m_aClipMap
);
589 void SvpSalGraphics::drawPolyPolygon( sal_uInt32 nPoly
,
590 const sal_uInt32
* pPointCounts
,
591 PCONSTSALPOINT
* pPtAry
)
593 if ((m_bUseLineColor
|| m_bUseFillColor
) && nPoly
&& m_aDevice
)
595 basegfx::B2DPolyPolygon aPolyPoly
;
596 for( sal_uInt32 nPolygon
= 0; nPolygon
< nPoly
; nPolygon
++ )
598 sal_uInt32 nPoints
= pPointCounts
[nPolygon
];
601 PCONSTSALPOINT pPoints
= pPtAry
[nPolygon
];
602 basegfx::B2DPolygon aPoly
;
603 aPoly
.append( basegfx::B2DPoint( pPoints
->mnX
, pPoints
->mnY
), nPoints
);
604 for( sal_uInt32 i
= 1; i
< nPoints
; i
++ )
605 aPoly
.setB2DPoint( i
, basegfx::B2DPoint( pPoints
[i
].mnX
, pPoints
[i
].mnY
) );
607 aPolyPoly
.append( aPoly
);
610 ensureClip(); // FIXME: for ...
611 if( m_bUseFillColor
)
613 aPolyPoly
.setClosed( true );
614 m_aDevice
->fillPolyPolygon( aPolyPoly
, m_aFillColor
, m_aDrawMode
, m_aClipMap
);
616 if( m_bUseLineColor
)
618 aPolyPoly
.setClosed( false );
619 nPoly
= aPolyPoly
.count();
620 for( sal_uInt32 i
= 0; i
< nPoly
; i
++ )
621 m_aDevice
->drawPolygon( aPolyPoly
.getB2DPolygon(i
), m_aLineColor
, m_aDrawMode
, m_aClipMap
);
627 bool SvpSalGraphics::drawPolyLine(
628 const ::basegfx::B2DPolygon
&,
629 double /*fTransparency*/,
630 const ::basegfx::B2DVector
& /*rLineWidths*/,
631 basegfx::B2DLineJoin
/*eJoin*/,
632 com::sun::star::drawing::LineCap
/*eLineCap*/)
634 // TODO: implement and advertise OutDevSupport_B2DDraw support
638 bool SvpSalGraphics::drawPolyLineBezier( sal_uInt32
,
645 bool SvpSalGraphics::drawPolygonBezier( sal_uInt32
,
652 bool SvpSalGraphics::drawPolyPolygonBezier( sal_uInt32
,
654 const SalPoint
* const*,
655 const sal_uInt8
* const* )
660 #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 10, 0)
661 static void AddPolygonToPath(cairo_t
* cr
, const basegfx::B2DPolygon
& rPolygon
, bool bClosePath
)
663 // short circuit if there is nothing to do
664 const int nPointCount
= rPolygon
.count();
665 if( nPointCount
<= 0 )
670 const bool bHasCurves
= rPolygon
.areControlPointsUsed();
671 for( int nPointIdx
= 0, nPrevIdx
= 0;; nPrevIdx
= nPointIdx
++ )
673 int nClosedIdx
= nPointIdx
;
674 if( nPointIdx
>= nPointCount
)
676 // prepare to close last curve segment if needed
677 if( bClosePath
&& (nPointIdx
== nPointCount
) )
687 basegfx::B2DPoint aPoint
= rPolygon
.getB2DPoint( nClosedIdx
);
691 // first point => just move there
692 cairo_move_to(cr
, aPoint
.getX(), aPoint
.getY());
696 bool bPendingCurve
= false;
699 bPendingCurve
= rPolygon
.isNextControlPointUsed( nPrevIdx
);
700 bPendingCurve
|= rPolygon
.isPrevControlPointUsed( nClosedIdx
);
703 if( !bPendingCurve
) // line segment
705 cairo_line_to(cr
, aPoint
.getX(), aPoint
.getY());
707 else // cubic bezier segment
709 basegfx::B2DPoint aCP1
= rPolygon
.getNextControlPoint( nPrevIdx
);
710 basegfx::B2DPoint aCP2
= rPolygon
.getPrevControlPoint( nClosedIdx
);
711 cairo_curve_to(cr
, aCP1
.getX(), aCP1
.getY(), aCP2
.getX(), aCP2
.getY(),
712 aPoint
.getX(), aPoint
.getY());
718 cairo_close_path(cr
);
723 bool SvpSalGraphics::drawPolyPolygon(const basegfx::B2DPolyPolygon
& rPolyPoly
, double fTransparency
)
726 (void)rPolyPoly
; (void)fTransparency
;
727 #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 10, 0)
728 if (m_bUseLineColor
|| !m_bUseFillColor
)
730 SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawPolyPolygon case");
734 cairo_t
* cr
= createCairoContext(m_aDevice
);
738 if (!m_aDevice
->isTopDown())
740 cairo_scale(cr
, 1, -1.0);
741 cairo_translate(cr
, 0.0, -m_aDevice
->getSize().getY());
746 cairo_set_source_rgba(cr
, m_aFillColor
.getRed()/255.0,
747 m_aFillColor
.getGreen()/255.0,
748 m_aFillColor
.getBlue()/255.0,
751 for (const basegfx::B2DPolygon
* pPoly
= rPolyPoly
.begin(); pPoly
!= rPolyPoly
.end(); ++pPoly
)
752 AddPolygonToPath(cr
, *pPoly
, true);
754 cairo_rectangle_int_t extents
;
755 basebmp::IBitmapDeviceDamageTrackerSharedPtr
xDamageTracker(m_aDevice
->getDamageTracker());
757 extents
= getFillDamage(cr
);
761 cairo_surface_flush(cairo_get_target(cr
));
762 cairo_destroy(cr
); // unref
766 xDamageTracker
->damaged(basegfx::B2IBox(extents
.x
, extents
.y
, extents
.x
+ extents
.width
,
767 extents
.y
+ extents
.height
));
774 void SvpSalGraphics::copyArea( long nDestX
,
780 sal_uInt16
/*nFlags*/ )
782 basegfx::B2IBox
aSrcRect( nSrcX
, nSrcY
, nSrcX
+nSrcWidth
, nSrcY
+nSrcHeight
);
783 basegfx::B2IBox
aDestRect( nDestX
, nDestY
, nDestX
+nSrcWidth
, nDestY
+nSrcHeight
);
784 // fprintf( stderr, "copyArea %ld pixels - clip region %d\n",
785 // (long)(nSrcWidth * nSrcHeight), m_aClipMap.get() != NULL );
786 SvpSalGraphics::ClipUndoHandle
aUndo( this );
787 if( !isClippedSetup( aDestRect
, aUndo
) )
788 m_aDevice
->drawBitmap( m_aOrigDevice
, aSrcRect
, aDestRect
, basebmp::DrawMode_PAINT
, m_aClipMap
);
792 void SvpSalGraphics::copyBits( const SalTwoRect
& rPosAry
,
793 SalGraphics
* pSrcGraphics
)
795 if( !m_aDevice
.get() )
798 SvpSalGraphics
* pSrc
= pSrcGraphics
?
799 static_cast<SvpSalGraphics
*>(pSrcGraphics
) : this;
800 basegfx::B2IBox
aSrcRect( rPosAry
.mnSrcX
, rPosAry
.mnSrcY
,
801 rPosAry
.mnSrcX
+rPosAry
.mnSrcWidth
,
802 rPosAry
.mnSrcY
+rPosAry
.mnSrcHeight
);
803 basegfx::B2IBox
aDestRect( rPosAry
.mnDestX
, rPosAry
.mnDestY
,
804 rPosAry
.mnDestX
+rPosAry
.mnDestWidth
,
805 rPosAry
.mnDestY
+rPosAry
.mnDestHeight
);
807 SvpSalGraphics::ClipUndoHandle
aUndo( this );
808 if( !isClippedSetup( aDestRect
, aUndo
) )
809 m_aDevice
->drawBitmap( pSrc
->m_aOrigDevice
, aSrcRect
, aDestRect
, basebmp::DrawMode_PAINT
, m_aClipMap
);
813 void SvpSalGraphics::drawBitmap( const SalTwoRect
& rPosAry
,
814 const SalBitmap
& rSalBitmap
)
816 if( !m_aDevice
.get() )
819 const SvpSalBitmap
& rSrc
= static_cast<const SvpSalBitmap
&>(rSalBitmap
);
820 basegfx::B2IBox
aSrcRect( rPosAry
.mnSrcX
, rPosAry
.mnSrcY
,
821 rPosAry
.mnSrcX
+rPosAry
.mnSrcWidth
,
822 rPosAry
.mnSrcY
+rPosAry
.mnSrcHeight
);
823 basegfx::B2IBox
aDestRect( rPosAry
.mnDestX
, rPosAry
.mnDestY
,
824 rPosAry
.mnDestX
+rPosAry
.mnDestWidth
,
825 rPosAry
.mnDestY
+rPosAry
.mnDestHeight
);
827 SvpSalGraphics::ClipUndoHandle
aUndo( this );
828 if( !isClippedSetup( aDestRect
, aUndo
) )
829 m_aDevice
->drawBitmap( rSrc
.getBitmap(), aSrcRect
, aDestRect
, basebmp::DrawMode_PAINT
, m_aClipMap
);
833 void SvpSalGraphics::drawBitmap( const SalTwoRect
&,
837 // SNI, as in X11 plugin
840 void SvpSalGraphics::drawBitmap( const SalTwoRect
& rPosAry
,
841 const SalBitmap
& rSalBitmap
,
842 const SalBitmap
& rTransparentBitmap
)
844 const SvpSalBitmap
& rSrc
= static_cast<const SvpSalBitmap
&>(rSalBitmap
);
845 const SvpSalBitmap
& rSrcTrans
= static_cast<const SvpSalBitmap
&>(rTransparentBitmap
);
846 basegfx::B2IBox
aSrcRect( rPosAry
.mnSrcX
, rPosAry
.mnSrcY
,
847 rPosAry
.mnSrcX
+rPosAry
.mnSrcWidth
,
848 rPosAry
.mnSrcY
+rPosAry
.mnSrcHeight
);
849 basegfx::B2IBox
aDestRect( rPosAry
.mnDestX
, rPosAry
.mnDestY
,
850 rPosAry
.mnDestX
+rPosAry
.mnDestWidth
,
851 rPosAry
.mnDestY
+rPosAry
.mnDestHeight
);
852 SvpSalGraphics::ClipUndoHandle
aUndo( this );
853 if (!isClippedSetup(aDestRect
, aUndo
) && m_aDevice
)
854 m_aDevice
->drawMaskedBitmap( rSrc
.getBitmap(), rSrcTrans
.getBitmap(),
855 aSrcRect
, aDestRect
, basebmp::DrawMode_PAINT
, m_aClipMap
);
859 void SvpSalGraphics::drawMask( const SalTwoRect
& rPosAry
,
860 const SalBitmap
& rSalBitmap
,
861 SalColor nMaskColor
)
863 const SvpSalBitmap
& rSrc
= static_cast<const SvpSalBitmap
&>(rSalBitmap
);
864 basegfx::B2IBox
aSrcRect( rPosAry
.mnSrcX
, rPosAry
.mnSrcY
,
865 rPosAry
.mnSrcX
+rPosAry
.mnSrcWidth
,
866 rPosAry
.mnSrcY
+rPosAry
.mnSrcHeight
);
867 basegfx::B2IPoint
aDestPoint( rPosAry
.mnDestX
, rPosAry
.mnDestY
);
869 // BitmapDevice::drawMaskedColor works with 0==transparent,
870 // 255==opaque. drawMask() semantic is the other way
871 // around. Therefore, invert mask.
872 basebmp::BitmapDeviceSharedPtr aCopy
=
873 cloneBitmapDevice( basegfx::B2IVector( rPosAry
.mnSrcWidth
, rPosAry
.mnSrcHeight
),
875 basebmp::Color
aBgColor( COL_WHITE
);
876 aCopy
->clear(aBgColor
);
877 basebmp::Color
aFgColor( COL_BLACK
);
878 aCopy
->drawMaskedColor( aFgColor
, rSrc
.getBitmap(), aSrcRect
, basegfx::B2IPoint() );
880 basebmp::Color
aColor( nMaskColor
);
881 basegfx::B2IBox
aSrcRect2( 0, 0, rPosAry
.mnSrcWidth
, rPosAry
.mnSrcHeight
);
882 const basegfx::B2IBox
aClipRect( aDestPoint
, basegfx::B2ITuple( aSrcRect
.getWidth(), aSrcRect
.getHeight() ) );
884 SvpSalGraphics::ClipUndoHandle
aUndo( this );
885 if( !isClippedSetup( aClipRect
, aUndo
) )
886 m_aDevice
->drawMaskedColor( aColor
, aCopy
, aSrcRect
, aDestPoint
, m_aClipMap
);
890 SalBitmap
* SvpSalGraphics::getBitmap( long nX
, long nY
, long nWidth
, long nHeight
)
892 SvpSalBitmap
* pBitmap
= new SvpSalBitmap();
896 basebmp::BitmapDeviceSharedPtr aCopy
;
897 aCopy
= cloneBitmapDevice(basegfx::B2IVector(nWidth
, nHeight
),
899 basegfx::B2IBox
aSrcRect( nX
, nY
, nX
+nWidth
, nY
+nHeight
);
900 basegfx::B2IBox
aDestRect( 0, 0, nWidth
, nHeight
);
902 aCopy
->drawBitmap( m_aOrigDevice
, aSrcRect
, aDestRect
, basebmp::DrawMode_PAINT
);
904 pBitmap
->setBitmap( aCopy
);
910 SalColor
SvpSalGraphics::getPixel( long nX
, long nY
)
912 basebmp::Color
aColor( m_aOrigDevice
->getPixel( basegfx::B2IPoint( nX
, nY
) ) );
913 return aColor
.toInt32();
916 void SvpSalGraphics::invert( long nX
, long nY
, long nWidth
, long nHeight
, SalInvert
/*nFlags*/ )
918 // FIXME: handle SAL_INVERT_50 and SAL_INVERT_TRACKFRAME
919 basegfx::B2DPolygon aRect
= basegfx::tools::createPolygonFromRect( basegfx::B2DRectangle( nX
, nY
, nX
+nWidth
, nY
+nHeight
) );
920 basegfx::B2DPolyPolygon
aPolyPoly( aRect
);
921 basegfx::B2IBox
aDestRange( nX
, nY
, nX
+ nWidth
, nY
+ nHeight
);
923 SvpSalGraphics::ClipUndoHandle
aUndo( this );
924 if( !isClippedSetup( aDestRange
, aUndo
) )
925 m_aDevice
->fillPolyPolygon( aPolyPoly
, basebmp::Color( 0xffffff ), basebmp::DrawMode_XOR
, m_aClipMap
);
929 void SvpSalGraphics::invert( sal_uInt32 nPoints
, const SalPoint
* pPtAry
, SalInvert
/*nFlags*/ )
931 // FIXME: handle SAL_INVERT_50 and SAL_INVERT_TRACKFRAME
932 basegfx::B2DPolygon aPoly
;
933 aPoly
.append( basegfx::B2DPoint( pPtAry
->mnX
, pPtAry
->mnY
), nPoints
);
934 for( sal_uLong i
= 1; i
< nPoints
; i
++ )
935 aPoly
.setB2DPoint( i
, basegfx::B2DPoint( pPtAry
[i
].mnX
, pPtAry
[i
].mnY
) );
936 aPoly
.setClosed( true );
937 ensureClip(); // FIXME for ...
938 m_aDevice
->fillPolyPolygon( basegfx::B2DPolyPolygon(aPoly
), basebmp::Color( 0xffffff ), basebmp::DrawMode_XOR
, m_aClipMap
);
944 bool SvpSalGraphics::drawEPS( long, long, long, long, void*, sal_uLong
)
949 #if ENABLE_CAIRO_CANVAS
951 cairo_t
* SvpSalGraphics::createCairoContext(const basebmp::BitmapDeviceSharedPtr
&rBuffer
)
953 if (!isCairoCompatible(rBuffer
))
956 basegfx::B2IVector size
= rBuffer
->getSize();
957 sal_Int32 nStride
= rBuffer
->getScanlineStride();
959 basebmp::RawMemorySharedArray data
= rBuffer
->getBuffer();
960 cairo_surface_t
*target
=
961 cairo_image_surface_create_for_data(data
.get(),
963 size
.getX(), size
.getY(),
965 cairo_t
* cr
= cairo_create(target
);
966 cairo_surface_destroy(target
);
972 bool SvpSalGraphics::SupportsCairo() const
977 cairo::SurfaceSharedPtr
SvpSalGraphics::CreateSurface(const cairo::CairoSurfaceSharedPtr
& /*rSurface*/) const
979 return cairo::SurfaceSharedPtr();
982 cairo::SurfaceSharedPtr
SvpSalGraphics::CreateSurface(const OutputDevice
& /*rRefDevice*/, int /*x*/, int /*y*/, int /*width*/, int /*height*/) const
984 return cairo::SurfaceSharedPtr();
987 cairo::SurfaceSharedPtr
SvpSalGraphics::CreateBitmapSurface(const OutputDevice
& /*rRefDevice*/, const BitmapSystemData
& /*rData*/, const Size
& /*rSize*/) const
989 return cairo::SurfaceSharedPtr();
992 css::uno::Any
SvpSalGraphics::GetNativeSurfaceHandle(cairo::SurfaceSharedPtr
& /*rSurface*/, const basegfx::B2ISize
& /*rSize*/) const
994 return css::uno::Any();
999 SystemGraphicsData
SvpSalGraphics::GetGraphicsData() const
1001 return SystemGraphicsData();
1004 bool SvpSalGraphics::supportsOperation(OutDevSupportType eType
) const
1006 #if ENABLE_CAIRO_CANVAS
1007 if (m_aDrawMode
== basebmp::DrawMode_XOR
)
1009 if (!isCairoCompatible(m_aDevice
))
1013 case OutDevSupport_TransparentRect
:
1014 case OutDevSupport_B2DDraw
:
1016 case OutDevSupport_B2DClip
: //what's this one ?
1028 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */