fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / vcl / headless / svpgdi.cxx
blob06030d99d6f83667ac2c9b6f52d1380207f34dfe
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 "headless/svpgdi.hxx"
21 #include "headless/svpbmp.hxx"
22 #ifndef IOS
23 #include "headless/svptextrender.hxx"
24 #endif
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
37 #include <cairo.h>
38 #endif
40 #if OSL_DEBUG_LEVEL > 2
41 #include <basebmp/debug.hxx>
42 #include <fstream>
43 #include <rtl/strbuf.hxx>
44 #include <sys/stat.h>
45 #endif
47 #include <stdio.h>
49 inline void dbgOut( const basebmp::BitmapDeviceSharedPtr&
50 #if OSL_DEBUG_LEVEL > 2
51 rDevice
52 #endif
55 #if OSL_DEBUG_LEVEL > 2
56 static int dbgStreamNum = 0;
57 OStringBuffer aBuf( 256 );
58 aBuf.append( "debug" );
59 mkdir( aBuf.getStr(), 0777 );
60 aBuf.append( "/" );
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 );
67 #endif
70 #ifndef IOS
72 bool SvpSalGraphics::blendBitmap( const SalTwoRect&, const SalBitmap& /*rBitmap*/ )
74 return false;
77 bool SvpSalGraphics::blendAlphaBitmap( const SalTwoRect&, const SalBitmap&, const SalBitmap&, const SalBitmap& )
79 return false;
82 bool SvpSalGraphics::drawAlphaBitmap( const SalTwoRect&, const SalBitmap& /*rSourceBitmap*/, const SalBitmap& /*rAlphaBitmap*/ )
84 // TODO(P3) implement alpha blending
85 return false;
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;
97 return false;
100 #if ENABLE_CAIRO_CANVAS
102 namespace
104 bool isCairoCompatible(const basebmp::BitmapDeviceSharedPtr &rBuffer)
106 if (!rBuffer)
107 return false;
109 if (rBuffer->getScanlineFormat() != basebmp::FORMAT_THIRTYTWO_BIT_TC_MASK_BGRX)
110 return false;
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);
116 #else
117 return false;
118 #endif
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());
135 cairo_clip(cr);
138 #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 10, 0)
139 namespace
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);
157 return extents;
160 #endif
162 #endif
164 bool SvpSalGraphics::drawAlphaRect(long nX, long nY, long nWidth, long nHeight, sal_uInt8 nTransparency)
166 bool bRet = false;
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");
173 return false;
176 cairo_t* cr = createCairoContext(m_aDevice);
177 if (!cr)
178 return bRet;
180 if (!m_aDevice->isTopDown())
182 cairo_scale(cr, 1, -1.0);
183 cairo_translate(cr, 0.0, -m_aDevice->getSize().getY());
186 clipRegion(cr);
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,
192 fTransparency);
193 cairo_rectangle(cr, nX, nY, nWidth, nHeight);
195 cairo_rectangle_int_t extents;
196 basebmp::IBitmapDeviceDamageTrackerSharedPtr xDamageTracker(m_aDevice->getDamageTracker());
197 if (xDamageTracker)
198 extents = getFillDamage(cr);
200 cairo_fill(cr);
202 cairo_surface_flush(cairo_get_target(cr));
203 cairo_destroy(cr); // unref
205 if (xDamageTracker)
207 xDamageTracker->damaged(basegfx::B2IBox(extents.x, extents.y, extents.x + extents.width,
208 extents.y + extents.height));
210 bRet = true;
211 #endif
212 #endif
213 return bRet;
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;
234 ResetClipRegion();
235 m_xTextRenderImpl->setDevice(rDevice);
238 #endif
240 void SvpSalGraphics::GetResolution( sal_Int32& rDPIX, sal_Int32& rDPIY )
242 rDPIX = rDPIY = 96;
245 #ifndef IOS
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();
257 return aSize.getX();
259 return 0;
262 void SvpSalGraphics::ResetClipRegion()
264 m_aDevice = m_aOrigDevice;
265 m_aClipMap.reset();
266 m_bClipSetup = true;
267 m_aClipRegion.SetNull();
270 // verify clip for the whole area is setup
271 void SvpSalGraphics::ensureClip()
273 if (m_bClipSetup)
274 return;
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());
286 if(nW)
288 const long nH(aRectIter->GetHeight());
290 if(nH)
292 basegfx::B2DPolyPolygon aFull;
294 aFull.append(
295 basegfx::tools::createPolygonFromRect(
296 basegfx::B2DRectangle(
297 aRectIter->Left(),
298 aRectIter->Top(),
299 aRectIter->Left() + nW,
300 aRectIter->Top() + nH)));
301 m_aClipMap->fillPolyPolygon(aFull, basebmp::Color(0), basebmp::DrawMode_PAINT);
305 m_bClipSetup = true;
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
318 // rendering
319 bool SvpSalGraphics::isClippedSetup( const basegfx::B2IBox &aRange, SvpSalGraphics::ClipUndoHandle &rUndo )
321 if( m_bClipSetup )
322 return false;
324 if( m_aClipRegion.IsEmpty() ) // no clipping
325 return false;
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
336 int nHit = 0;
337 Rectangle aHitRect;
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;
345 nHit++;
349 if( nHit == 0 ) // rendering outside any clipping region
351 SAL_INFO("vcl.headless", "SvpSalGraphics::isClippedSetup: degenerate case detected ...");
352 return true;
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 ...");
361 return false;
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(),
367 aHitRect.Top(),
368 aHitRect.Right() + 1,
369 aHitRect.Bottom() + 1) );
370 return false;
372 // fprintf (stderr, "URK: complex & slow clipping case\n" );
373 // horribly slow & complicated case ...
375 ensureClip();
376 return false;
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
385 // rectangles.
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;
393 m_aClipMap.reset();
394 if( i_rClip.IsEmpty() )
396 m_aDevice = m_aOrigDevice;
397 m_bClipSetup = true;
398 return true;
401 RectangleVector aRectangles;
402 i_rClip.GetRegionRectangles(aRectangles);
404 if (1 == aRectangles.size())
406 //simplest case, subset the device to clip bounds
407 m_aClipMap.reset();
409 const Rectangle& aBoundRect = aRectangles[0];
410 m_aDevice = basebmp::subsetBitmapDevice(
411 m_aOrigDevice,
412 basegfx::B2IBox(aBoundRect.Left(),aBoundRect.Top(),aBoundRect.Right() + 1,aBoundRect.Bottom() + 1) );
414 m_bClipSetup = true;
416 else
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
421 //calls
422 m_aDevice = m_aOrigDevice;
423 m_bClipSetup = false;
426 return true;
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;
459 switch( nROPColor )
461 case SAL_ROP_0:
462 m_aLineColor = basebmp::Color( 0 );
463 break;
464 case SAL_ROP_1:
465 m_aLineColor = basebmp::Color( 0xffffff );
466 break;
467 case SAL_ROP_INVERT:
468 m_aLineColor = basebmp::Color( 0xffffff );
469 break;
473 void SvpSalGraphics::SetROPFillColor( SalROPColor nROPColor )
475 m_bUseFillColor = true;
476 switch( nROPColor )
478 case SAL_ROP_0:
479 m_aFillColor = basebmp::Color( 0 );
480 break;
481 case SAL_ROP_1:
482 m_aFillColor = basebmp::Color( 0xffffff );
483 break;
484 case SAL_ROP_INVERT:
485 m_aFillColor = basebmp::Color( 0xffffff );
486 break;
490 void SvpSalGraphics::drawPixel( long nX, long nY )
492 if( m_bUseLineColor )
494 ensureClip();
495 m_aDevice->setPixel( basegfx::B2IPoint( nX, nY ),
496 m_aLineColor,
497 m_aDrawMode,
498 m_aClipMap
501 dbgOut( m_aDevice );
504 void SvpSalGraphics::drawPixel( long nX, long nY, SalColor nSalColor )
506 basebmp::Color aColor( nSalColor );
507 ensureClip();
508 m_aDevice->setPixel( basegfx::B2IPoint( nX, nY ),
509 aColor,
510 m_aDrawMode,
511 m_aClipMap
513 dbgOut( m_aDevice );
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 ),
523 m_aLineColor,
524 m_aDrawMode,
525 m_aClipMap );
527 dbgOut( m_aDevice );
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 );
548 dbgOut( m_aDevice );
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 );
563 dbgOut( m_aDevice );
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 );
586 dbgOut( m_aDevice );
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];
599 if( nPoints )
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 );
624 dbgOut( m_aDevice );
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
635 return false;
638 bool SvpSalGraphics::drawPolyLineBezier( sal_uInt32,
639 const SalPoint*,
640 const sal_uInt8* )
642 return false;
645 bool SvpSalGraphics::drawPolygonBezier( sal_uInt32,
646 const SalPoint*,
647 const sal_uInt8* )
649 return false;
652 bool SvpSalGraphics::drawPolyPolygonBezier( sal_uInt32,
653 const sal_uInt32*,
654 const SalPoint* const*,
655 const sal_uInt8* const* )
657 return false;
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 )
667 return;
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) )
679 nClosedIdx = 0;
681 else
683 break;
687 basegfx::B2DPoint aPoint = rPolygon.getB2DPoint( nClosedIdx );
689 if( !nPointIdx )
691 // first point => just move there
692 cairo_move_to(cr, aPoint.getX(), aPoint.getY());
693 continue;
696 bool bPendingCurve = false;
697 if( bHasCurves )
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());
716 if( bClosePath )
718 cairo_close_path(cr);
721 #endif
723 bool SvpSalGraphics::drawPolyPolygon(const basegfx::B2DPolyPolygon& rPolyPoly, double fTransparency)
725 bool bRet = false;
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");
731 return false;
734 cairo_t* cr = createCairoContext(m_aDevice);
735 if (!cr)
736 return false;
738 if (!m_aDevice->isTopDown())
740 cairo_scale(cr, 1, -1.0);
741 cairo_translate(cr, 0.0, -m_aDevice->getSize().getY());
744 clipRegion(cr);
746 cairo_set_source_rgba(cr, m_aFillColor.getRed()/255.0,
747 m_aFillColor.getGreen()/255.0,
748 m_aFillColor.getBlue()/255.0,
749 1.0-fTransparency);
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());
756 if (xDamageTracker)
757 extents = getFillDamage(cr);
759 cairo_fill(cr);
761 cairo_surface_flush(cairo_get_target(cr));
762 cairo_destroy(cr); // unref
764 if (xDamageTracker)
766 xDamageTracker->damaged(basegfx::B2IBox(extents.x, extents.y, extents.x + extents.width,
767 extents.y + extents.height));
769 bRet = true;
770 #endif
771 return bRet;
774 void SvpSalGraphics::copyArea( long nDestX,
775 long nDestY,
776 long nSrcX,
777 long nSrcY,
778 long nSrcWidth,
779 long nSrcHeight,
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 );
789 dbgOut( m_aDevice );
792 void SvpSalGraphics::copyBits( const SalTwoRect& rPosAry,
793 SalGraphics* pSrcGraphics )
795 if( !m_aDevice.get() )
796 return;
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 );
810 dbgOut( m_aDevice );
813 void SvpSalGraphics::drawBitmap( const SalTwoRect& rPosAry,
814 const SalBitmap& rSalBitmap )
816 if( !m_aDevice.get() )
817 return;
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 );
830 dbgOut( m_aDevice );
833 void SvpSalGraphics::drawBitmap( const SalTwoRect&,
834 const SalBitmap&,
835 SalColor )
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 );
856 dbgOut( m_aDevice );
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 ),
874 rSrc.getBitmap() );
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 );
887 dbgOut( m_aDevice );
890 SalBitmap* SvpSalGraphics::getBitmap( long nX, long nY, long nWidth, long nHeight )
892 SvpSalBitmap* pBitmap = new SvpSalBitmap();
894 if (m_aDevice)
896 basebmp::BitmapDeviceSharedPtr aCopy;
897 aCopy = cloneBitmapDevice(basegfx::B2IVector(nWidth, nHeight),
898 m_aDevice);
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 );
907 return pBitmap;
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 );
926 dbgOut( m_aDevice );
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 );
939 dbgOut( m_aDevice );
942 #endif
944 bool SvpSalGraphics::drawEPS( long, long, long, long, void*, sal_uLong )
946 return false;
949 #if ENABLE_CAIRO_CANVAS
951 cairo_t* SvpSalGraphics::createCairoContext(const basebmp::BitmapDeviceSharedPtr &rBuffer)
953 if (!isCairoCompatible(rBuffer))
954 return NULL;
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(),
962 CAIRO_FORMAT_RGB24,
963 size.getX(), size.getY(),
964 nStride);
965 cairo_t* cr = cairo_create(target);
966 cairo_surface_destroy(target);
967 return cr;
970 #endif
972 bool SvpSalGraphics::SupportsCairo() const
974 return false;
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();
997 #ifndef IOS
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)
1008 return false;
1009 if (!isCairoCompatible(m_aDevice))
1010 return false;
1011 switch (eType)
1013 case OutDevSupport_TransparentRect:
1014 case OutDevSupport_B2DDraw:
1015 return true;
1016 case OutDevSupport_B2DClip: //what's this one ?
1017 return false;
1019 return false;
1020 #else
1021 (void)eType;
1022 return false;
1023 #endif
1026 #endif
1028 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */