CWS-TOOLING: integrate CWS os146
[LibreOffice.git] / canvas / source / tools / image.cxx
blob4b8a2a3348731aa5bb7e5456db8defd853af6b8b
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_canvas.hxx"
31 #include <canvas/debug.hxx>
32 #include <tools/diagnose_ex.h>
34 #include <canvas/canvastools.hxx>
35 #include <canvas/parametricpolypolygon.hxx>
37 #include <com/sun/star/rendering/RepaintResult.hpp>
38 #include <com/sun/star/rendering/XIntegerReadOnlyBitmap.hpp>
40 #include <vcl/canvastools.hxx>
41 #include <vcl/bitmapex.hxx>
42 #include <vcl/bmpacc.hxx>
44 #include <basegfx/range/b2drange.hxx>
45 #include <basegfx/point/b2dpoint.hxx>
46 #include <basegfx/matrix/b2dhommatrix.hxx>
47 #include <basegfx/polygon/b2dpolygon.hxx>
48 #include <basegfx/polygon/b2dpolypolygon.hxx>
49 #include <basegfx/polygon/b2dpolygoncutandtouch.hxx>
50 #include <basegfx/polygon/b2dpolygontriangulator.hxx>
51 #include <basegfx/polygon/b2dpolypolygontools.hxx>
52 #include <basegfx/polygon/b2dpolygontools.hxx>
53 #include <basegfx/polygon/b2dpolygonclipper.hxx>
54 #include <basegfx/tools/canvastools.hxx>
55 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
56 #include <basegfx/polygon/b2dpolygonclipper.hxx>
58 #include "image.hxx"
60 #define CANVAS_IMAGE_CXX
61 #include "image_sysprereq.h"
63 //////////////////////////////////////////////////////////////////////////////////
64 // platform-dependend includes [wrapped into their own namepsaces]
65 //////////////////////////////////////////////////////////////////////////////////
67 #if defined(WNT)
68 # if defined _MSC_VER
69 # pragma warning(push,1)
70 # endif
72 namespace win32
74 #undef DECLARE_HANDLE
75 #undef WB_LEFT
76 #undef WB_RIGHT
77 #undef APIENTRY
78 #define WIN32_LEAN_AND_MEAN
79 #define NOMINMAX
80 #include <windows.h>
83 # if defined _MSC_VER
84 # pragma warning(pop)
85 # endif
86 #elif defined(OS2)
87 namespace os2
89 #include <svpm.h>
91 #else
92 #if !defined(QUARTZ)
93 namespace unx
95 #include <X11/Xlib.h>
97 #endif
98 #endif
100 #include <algorithm>
102 using namespace ::com::sun::star;
104 namespace canvas { namespace
106 //////////////////////////////////////////////////////////////////////////////////
107 // TransAffineFromAffineMatrix
108 //////////////////////////////////////////////////////////////////////////////////
110 ::agg::trans_affine transAffineFromAffineMatrix( const geometry::AffineMatrix2D& m )
112 return agg::trans_affine(m.m00,
113 m.m10,
114 m.m01,
115 m.m11,
116 m.m02,
117 m.m12);
120 //////////////////////////////////////////////////////////////////////////////////
121 // TransAffineFromB2DHomMatrix
122 //////////////////////////////////////////////////////////////////////////////////
124 ::agg::trans_affine transAffineFromB2DHomMatrix( const ::basegfx::B2DHomMatrix& m )
126 return agg::trans_affine(m.get(0,0),
127 m.get(1,0),
128 m.get(0,1),
129 m.get(1,1),
130 m.get(0,2),
131 m.get(1,2));
134 //////////////////////////////////////////////////////////////////////////////////
135 // ARGB
136 //////////////////////////////////////////////////////////////////////////////////
138 struct ARGBColor
140 sal_uInt8 a;
141 sal_uInt8 r;
142 sal_uInt8 g;
143 sal_uInt8 b;
146 /// ARGB color
147 union ARGB
149 ARGBColor Color;
150 sal_uInt32 color;
152 ARGB() :
153 color(0)
157 explicit ARGB( sal_uInt32 _color ) :
158 color(_color)
162 ARGB( sal_uInt8 _a,
163 sal_uInt8 _r,
164 sal_uInt8 _g,
165 sal_uInt8 _b )
167 Color.a = _a;
168 Color.r = _r;
169 Color.g = _g;
170 Color.b = _b;
173 ARGB( sal_uInt32 default_color,
174 const ::com::sun::star::uno::Sequence< double >& sequence ) :
175 color(default_color)
177 if(sequence.getLength() > 2)
179 Color.r = static_cast<sal_uInt8>(255.0f*sequence[0]);
180 Color.g = static_cast<sal_uInt8>(255.0f*sequence[1]);
181 Color.b = static_cast<sal_uInt8>(255.0f*sequence[2]);
182 if(sequence.getLength() > 3)
183 Color.a = static_cast<sal_uInt8>(255.0f*sequence[3]);
187 ARGB( const ARGB& rhs ) :
188 color( rhs.color )
192 ARGB &operator=( const ARGB &rhs )
194 color=rhs.color;
195 return *this;
199 //////////////////////////////////////////////////////////////////////////////////
200 // setupState
201 //////////////////////////////////////////////////////////////////////////////////
203 /// Calc common output state from XCanvas parameters
204 void setupState( ::basegfx::B2DHomMatrix& o_rViewTransform,
205 ::basegfx::B2DHomMatrix& o_rRenderTransform,
206 ::std::auto_ptr< ::basegfx::B2DPolyPolygon >& o_rViewClip,
207 ::std::auto_ptr< ::basegfx::B2DPolyPolygon >& o_rRenderClip,
208 ARGB& o_rRenderColor,
209 const rendering::ViewState& viewState,
210 const rendering::RenderState& renderState )
212 ::basegfx::unotools::homMatrixFromAffineMatrix(o_rRenderTransform,
213 renderState.AffineTransform);
214 ::basegfx::unotools::homMatrixFromAffineMatrix(o_rViewTransform,
215 viewState.AffineTransform);
217 o_rRenderColor = ARGB(0xFFFFFFFF,
218 renderState.DeviceColor);
220 // TODO(F3): handle compositing modes
222 if( viewState.Clip.is() )
224 ::basegfx::B2DPolyPolygon aViewClip(
225 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( viewState.Clip ));
227 if(aViewClip.areControlPointsUsed())
228 aViewClip = ::basegfx::tools::adaptiveSubdivideByAngle(aViewClip);
230 o_rViewClip.reset( new ::basegfx::B2DPolyPolygon( aViewClip ) );
233 if( renderState.Clip.is() )
235 ::basegfx::B2DPolyPolygon aRenderClip(
236 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( viewState.Clip ) );
238 if(aRenderClip.areControlPointsUsed())
239 aRenderClip = ::basegfx::tools::adaptiveSubdivideByAngle(aRenderClip);
241 o_rRenderClip.reset( new ::basegfx::B2DPolyPolygon( aRenderClip ) );
245 //////////////////////////////////////////////////////////////////////////////////
246 // clipAndTransformPolygon
247 //////////////////////////////////////////////////////////////////////////////////
249 /** Clip and transform given polygon
251 @param io_rClippee
252 Polygon to clip
254 @param bIsFilledPolyPolygon
255 When true, the polygon is clipped as if it was to be rendered
256 with fill, when false, the polygon is clipped as if it was to
257 be rendered with stroking.
259 void clipAndTransformPolygon( ::basegfx::B2DPolyPolygon& io_rClippee,
260 bool bIsFilledPolyPolygon,
261 const ::basegfx::B2DHomMatrix& rViewTransform,
262 const ::basegfx::B2DHomMatrix& rRenderTransform,
263 const ::basegfx::B2DPolyPolygon* pViewClip,
264 const ::basegfx::B2DPolyPolygon* pRenderClip )
266 ::basegfx::B2DPolyPolygon aPolyPolygon(io_rClippee);
267 io_rClippee.clear();
269 // clip contour against renderclip
270 if( pRenderClip )
272 // AW: Simplified
273 aPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon(
274 aPolyPolygon, *pRenderClip, true, !bIsFilledPolyPolygon);
277 if( !aPolyPolygon.count() )
278 return;
280 // transform result into view space
281 aPolyPolygon.transform(rRenderTransform);
283 // clip contour against viewclip
284 if( pViewClip )
286 // AW: Simplified
287 aPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon(
288 aPolyPolygon, *pViewClip, true, !bIsFilledPolyPolygon);
291 if(!(aPolyPolygon.count()))
292 return;
294 // transform result into device space
295 aPolyPolygon.transform(rViewTransform);
297 io_rClippee = aPolyPolygon;
300 //////////////////////////////////////////////////////////////////////////////////
301 // setupPolyPolygon
302 //////////////////////////////////////////////////////////////////////////////////
304 void setupPolyPolygon( ::basegfx::B2DPolyPolygon& io_rClippee,
305 bool bIsFilledPolyPolygon,
306 ARGB& o_rRenderColor,
307 const rendering::ViewState& viewState,
308 const rendering::RenderState& renderState )
310 ::basegfx::B2DHomMatrix aViewTransform;
311 ::basegfx::B2DHomMatrix aRenderTransform;
312 ::std::auto_ptr< ::basegfx::B2DPolyPolygon > pViewClip;
313 ::std::auto_ptr< ::basegfx::B2DPolyPolygon > pRenderClip;
315 setupState( aViewTransform,
316 aRenderTransform,
317 pViewClip,
318 pRenderClip,
319 o_rRenderColor,
320 viewState,
321 renderState );
323 clipAndTransformPolygon( io_rClippee,
324 bIsFilledPolyPolygon,
325 aViewTransform,
326 aRenderTransform,
327 pViewClip.get(),
328 pRenderClip.get() );
331 //////////////////////////////////////////////////////////////////////////////////
332 // RawABGRBitmap
333 //////////////////////////////////////////////////////////////////////////////////
335 // Raw ABGR [AABBGGRR] 32bit continous
336 struct RawABGRBitmap
338 sal_Int32 mnWidth;
339 sal_Int32 mnHeight;
340 sal_uInt8* mpBitmapData;
343 //////////////////////////////////////////////////////////////////////////////////
344 // vclBitmapEx2Raw
345 //////////////////////////////////////////////////////////////////////////////////
347 void vclBitmapEx2Raw( const ::BitmapEx& rBmpEx, RawABGRBitmap& rBmpData )
349 Bitmap aBitmap( rBmpEx.GetBitmap() );
351 ScopedBitmapReadAccess pReadAccess( aBitmap.AcquireReadAccess(),
352 aBitmap );
354 const sal_Int32 nWidth( rBmpData.mnWidth );
355 const sal_Int32 nHeight( rBmpData.mnHeight );
357 ENSURE_OR_THROW( pReadAccess.get() != NULL,
358 "vclBitmapEx2Raw(): "
359 "Unable to acquire read acces to bitmap" );
361 if( rBmpEx.IsTransparent())
363 if( rBmpEx.IsAlpha() )
365 // 8bit alpha mask
366 Bitmap aAlpha( rBmpEx.GetAlpha().GetBitmap() );
368 ScopedBitmapReadAccess pAlphaReadAccess( aAlpha.AcquireReadAccess(),
369 aAlpha );
371 // By convention, the access buffer always has
372 // one of the following formats:
374 // BMP_FORMAT_1BIT_MSB_PAL
375 // BMP_FORMAT_4BIT_MSN_PAL
376 // BMP_FORMAT_8BIT_PAL
377 // BMP_FORMAT_16BIT_TC_LSB_MASK
378 // BMP_FORMAT_24BIT_TC_BGR
379 // BMP_FORMAT_32BIT_TC_MASK
381 // and is always BMP_FORMAT_BOTTOM_UP
383 // This is the way
384 // WinSalBitmap::AcquireBuffer() sets up the
385 // buffer
387 ENSURE_OR_THROW( pAlphaReadAccess.get() != NULL,
388 "vclBitmapEx2Raw(): "
389 "Unable to acquire read acces to alpha" );
391 ENSURE_OR_THROW( pAlphaReadAccess->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ||
392 pAlphaReadAccess->GetScanlineFormat() == BMP_FORMAT_8BIT_TC_MASK,
393 "vclBitmapEx2Raw(): "
394 "Unsupported alpha scanline format" );
396 BitmapColor aCol;
397 sal_uInt8* pCurrOutput( rBmpData.mpBitmapData );
398 int x, y;
400 for( y=0; y<nHeight; ++y )
402 switch( pReadAccess->GetScanlineFormat() )
404 case BMP_FORMAT_8BIT_PAL:
406 Scanline pScan = pReadAccess->GetScanline( y );
407 Scanline pAScan = pAlphaReadAccess->GetScanline( y );
409 for( x=0; x<nWidth; ++x )
411 aCol = pReadAccess->GetPaletteColor( *pScan++ );
413 *pCurrOutput++ = aCol.GetBlue();
414 *pCurrOutput++ = aCol.GetGreen();
415 *pCurrOutput++ = aCol.GetRed();
417 // out notion of alpha is
418 // different from the rest
419 // of the world's
420 *pCurrOutput++ = 255 - (sal_uInt8)*pAScan++;
423 break;
425 case BMP_FORMAT_24BIT_TC_BGR:
427 Scanline pScan = pReadAccess->GetScanline( y );
428 Scanline pAScan = pAlphaReadAccess->GetScanline( y );
430 for( x=0; x<nWidth; ++x )
432 // store as RGBA
433 *pCurrOutput++ = *pScan++;
434 *pCurrOutput++ = *pScan++;
435 *pCurrOutput++ = *pScan++;
437 // out notion of alpha is
438 // different from the rest
439 // of the world's
440 *pCurrOutput++ = 255 - (sal_uInt8)*pAScan++;
443 break;
445 // TODO(P2): Might be advantageous
446 // to hand-formulate the following
447 // formats, too.
448 case BMP_FORMAT_1BIT_MSB_PAL:
449 // FALLTHROUGH intended
450 case BMP_FORMAT_4BIT_MSN_PAL:
451 // FALLTHROUGH intended
452 case BMP_FORMAT_16BIT_TC_LSB_MASK:
453 // FALLTHROUGH intended
454 case BMP_FORMAT_32BIT_TC_MASK:
456 Scanline pAScan = pAlphaReadAccess->GetScanline( y );
458 // using fallback for those
459 // seldom formats
460 for( x=0; x<nWidth; ++x )
462 // yes. x and y are swapped on Get/SetPixel
463 aCol = pReadAccess->GetColor(y,x);
465 *pCurrOutput++ = aCol.GetBlue();
466 *pCurrOutput++ = aCol.GetGreen();
467 *pCurrOutput++ = aCol.GetRed();
469 // out notion of alpha is
470 // different from the rest
471 // of the world's
472 *pCurrOutput++ = 255 - (sal_uInt8)*pAScan++;
475 break;
477 case BMP_FORMAT_1BIT_LSB_PAL:
478 // FALLTHROUGH intended
479 case BMP_FORMAT_4BIT_LSN_PAL:
480 // FALLTHROUGH intended
481 case BMP_FORMAT_8BIT_TC_MASK:
482 // FALLTHROUGH intended
483 case BMP_FORMAT_24BIT_TC_RGB:
484 // FALLTHROUGH intended
485 case BMP_FORMAT_24BIT_TC_MASK:
486 // FALLTHROUGH intended
487 case BMP_FORMAT_16BIT_TC_MSB_MASK:
488 // FALLTHROUGH intended
489 case BMP_FORMAT_32BIT_TC_ABGR:
490 // FALLTHROUGH intended
491 case BMP_FORMAT_32BIT_TC_ARGB:
492 // FALLTHROUGH intended
493 case BMP_FORMAT_32BIT_TC_BGRA:
494 // FALLTHROUGH intended
495 case BMP_FORMAT_32BIT_TC_RGBA:
496 // FALLTHROUGH intended
497 default:
498 ENSURE_OR_THROW( false,
499 "vclBitmapEx2Raw(): "
500 "Unexpected scanline format - has "
501 "WinSalBitmap::AcquireBuffer() changed?" );
505 else
507 // 1bit alpha mask
508 Bitmap aMask( rBmpEx.GetMask() );
510 ScopedBitmapReadAccess pMaskReadAccess( aMask.AcquireReadAccess(),
511 aMask );
513 // By convention, the access buffer always has
514 // one of the following formats:
516 // BMP_FORMAT_1BIT_MSB_PAL
517 // BMP_FORMAT_4BIT_MSN_PAL
518 // BMP_FORMAT_8BIT_PAL
519 // BMP_FORMAT_16BIT_TC_LSB_MASK
520 // BMP_FORMAT_24BIT_TC_BGR
521 // BMP_FORMAT_32BIT_TC_MASK
523 // and is always BMP_FORMAT_BOTTOM_UP
525 // This is the way
526 // WinSalBitmap::AcquireBuffer() sets up the
527 // buffer
529 ENSURE_OR_THROW( pMaskReadAccess.get() != NULL,
530 "vclBitmapEx2Raw(): "
531 "Unable to acquire read acces to mask" );
533 ENSURE_OR_THROW( pMaskReadAccess->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL,
534 "vclBitmapEx2Raw(): "
535 "Unsupported mask scanline format" );
537 BitmapColor aCol;
538 int nCurrBit;
539 const int nMask( 1L );
540 const int nInitialBit(7);
541 sal_uInt32 *pBuffer = reinterpret_cast<sal_uInt32 *>(rBmpData.mpBitmapData);
542 int x, y;
544 // mapping table, to get from mask index color to
545 // alpha value (which depends on the mask's palette)
546 sal_uInt8 aColorMap[2];
548 const BitmapColor& rCol0( pMaskReadAccess->GetPaletteColor( 0 ) );
549 const BitmapColor& rCol1( pMaskReadAccess->GetPaletteColor( 1 ) );
551 // shortcut for true luminance calculation
552 // (assumes that palette is grey-level). Note the
553 // swapped the indices here, to account for the
554 // fact that VCL's notion of alpha is inverted to
555 // the rest of the world's.
556 aColorMap[0] = rCol1.GetRed();
557 aColorMap[1] = rCol0.GetRed();
559 for( y=0; y<nHeight; ++y )
561 switch( pReadAccess->GetScanlineFormat() )
563 case BMP_FORMAT_8BIT_PAL:
565 Scanline pScan = pReadAccess->GetScanline( y );
566 Scanline pMScan = pMaskReadAccess->GetScanline( y );
568 for( x=0, nCurrBit=nInitialBit; x<nWidth; ++x )
570 aCol = pReadAccess->GetPaletteColor( *pScan++ );
572 // RGB -> ABGR
573 unsigned int color = aCol.GetRed();
574 color |= aCol.GetGreen()<<8;
575 color |= aCol.GetBlue()<<16;
576 color |= aColorMap[ (pMScan[ (x & ~7L) >> 3L ] >> nCurrBit ) & nMask ]<<24;
577 *pBuffer++ = color;
578 nCurrBit = ((nCurrBit - 1) % 8L) & 7L;
581 break;
583 case BMP_FORMAT_24BIT_TC_BGR:
585 Scanline pScan = pReadAccess->GetScanline( y );
586 Scanline pMScan = pMaskReadAccess->GetScanline( y );
588 for( x=0, nCurrBit=nInitialBit; x<nWidth; ++x )
590 // BGR -> ABGR
591 unsigned int color = (*pScan++)<<16;
592 color |= (*pScan++)<<8;
593 color |= (*pScan++);
594 color |= (aColorMap[ (pMScan[ (x & ~7L) >> 3L ] >> nCurrBit ) & nMask ])<<24;
595 *pBuffer++ = color;
596 nCurrBit = ((nCurrBit - 1) % 8L) & 7L;
599 break;
601 // TODO(P2): Might be advantageous
602 // to hand-formulate the following
603 // formats, too.
604 case BMP_FORMAT_1BIT_MSB_PAL:
605 // FALLTHROUGH intended
606 case BMP_FORMAT_4BIT_MSN_PAL:
607 // FALLTHROUGH intended
608 case BMP_FORMAT_16BIT_TC_LSB_MASK:
609 // FALLTHROUGH intended
610 case BMP_FORMAT_32BIT_TC_MASK:
612 Scanline pMScan = pMaskReadAccess->GetScanline( y );
614 // using fallback for those
615 // seldom formats
616 for( x=0, nCurrBit=nInitialBit; x<nWidth; ++x )
618 // yes. x and y are swapped on Get/SetPixel
619 aCol = pReadAccess->GetColor(y,x);
621 // -> ABGR
622 unsigned int color = aCol.GetBlue()<<16;
623 color |= aCol.GetGreen()<<8;
624 color |= aCol.GetRed();
625 color |= (aColorMap[ (pMScan[ (x & ~7L) >> 3L ] >> nCurrBit ) & nMask ])<<24;
626 *pBuffer++ = color;
627 nCurrBit = ((nCurrBit - 1) % 8L) & 7L;
630 break;
632 case BMP_FORMAT_1BIT_LSB_PAL:
633 // FALLTHROUGH intended
634 case BMP_FORMAT_4BIT_LSN_PAL:
635 // FALLTHROUGH intended
636 case BMP_FORMAT_8BIT_TC_MASK:
637 // FALLTHROUGH intended
638 case BMP_FORMAT_24BIT_TC_RGB:
639 // FALLTHROUGH intended
640 case BMP_FORMAT_24BIT_TC_MASK:
641 // FALLTHROUGH intended
642 case BMP_FORMAT_16BIT_TC_MSB_MASK:
643 // FALLTHROUGH intended
644 case BMP_FORMAT_32BIT_TC_ABGR:
645 // FALLTHROUGH intended
646 case BMP_FORMAT_32BIT_TC_ARGB:
647 // FALLTHROUGH intended
648 case BMP_FORMAT_32BIT_TC_BGRA:
649 // FALLTHROUGH intended
650 case BMP_FORMAT_32BIT_TC_RGBA:
651 // FALLTHROUGH intended
652 default:
653 ENSURE_OR_THROW( false,
654 "vclBitmapEx2Raw(): "
655 "Unexpected scanline format - has "
656 "WinSalBitmap::AcquireBuffer() changed?" );
661 else
663 // *no* alpha mask
664 sal_uIntPtr nFormat = pReadAccess->GetScanlineFormat();
665 sal_uInt8 *pBuffer = reinterpret_cast<sal_uInt8 *>(rBmpData.mpBitmapData);
667 switch(nFormat)
669 case BMP_FORMAT_24BIT_TC_BGR:
672 sal_Int32 height = pReadAccess->Height();
673 for(sal_Int32 y=0; y<height; ++y)
675 sal_uInt8 *pScanline=pReadAccess->GetScanline(y);
676 sal_Int32 width = pReadAccess->Width();
677 for(sal_Int32 x=0; x<width; ++x)
679 // BGR -> RGB
680 sal_uInt8 b(*pScanline++);
681 sal_uInt8 g(*pScanline++);
682 sal_uInt8 r(*pScanline++);
683 *pBuffer++ = r;
684 *pBuffer++ = g;
685 *pBuffer++ = b;
689 break;
691 case BMP_FORMAT_24BIT_TC_RGB:
694 sal_Int32 height = pReadAccess->Height();
695 for(sal_Int32 y=0; y<height; ++y)
697 sal_uInt8 *pScanline=pReadAccess->GetScanline(y);
698 sal_Int32 width = pReadAccess->Width();
699 for(sal_Int32 x=0; x<width; ++x)
701 // RGB -> RGB
702 sal_uInt8 r(*pScanline++);
703 sal_uInt8 g(*pScanline++);
704 sal_uInt8 b(*pScanline++);
705 *pBuffer++ = r;
706 *pBuffer++ = g;
707 *pBuffer++ = b;
711 break;
713 case BMP_FORMAT_1BIT_MSB_PAL:
714 case BMP_FORMAT_1BIT_LSB_PAL:
715 case BMP_FORMAT_4BIT_MSN_PAL:
716 case BMP_FORMAT_4BIT_LSN_PAL:
717 case BMP_FORMAT_8BIT_PAL:
720 sal_Int32 height = pReadAccess->Height();
721 for(sal_Int32 y=0; y<height; ++y)
723 sal_uInt8 *pScanline=pReadAccess->GetScanline(y);
724 sal_Int32 width = pReadAccess->Width();
725 for(sal_Int32 x=0; x<width; ++x)
727 BitmapColor aCol(pReadAccess->GetPaletteColor(*pScanline++));
729 *pBuffer++ = aCol.GetRed();
730 *pBuffer++ = aCol.GetGreen();
731 *pBuffer++ = aCol.GetBlue();
735 break;
740 //////////////////////////////////////////////////////////////////////////////////
741 // color_generator_linear
742 //////////////////////////////////////////////////////////////////////////////////
744 template<typename T> struct color_generator_linear
746 typedef typename T::value_type value_type;
748 color_generator_linear( const T &c1,
749 const T &c2,
750 unsigned int aSteps ) : maSteps(aSteps),
751 maColor1(c1),
752 maColor2(c2)
756 unsigned size() const { return maSteps; }
757 const T operator [] (unsigned v) const
759 const double w = double(v)/maSteps;
760 return T( static_cast<value_type>(maColor1.r+(maColor2.r-maColor1.r)*w),
761 static_cast<value_type>(maColor1.g+(maColor2.g-maColor1.g)*w),
762 static_cast<value_type>(maColor1.b+(maColor2.b-maColor1.b)*w),
763 static_cast<value_type>(maColor1.a+(maColor2.a-maColor1.a)*w));
766 unsigned int maSteps;
767 const T maColor1;
768 const T maColor2;
771 //////////////////////////////////////////////////////////////////////////////////
772 // color_generator_axial
773 //////////////////////////////////////////////////////////////////////////////////
775 template<typename T> struct color_generator_axial
777 typedef typename T::value_type value_type;
779 color_generator_axial( const T &c1,
780 const T &c2,
781 unsigned int aSteps ) : maSteps(aSteps),
782 maColor1(c1),
783 maColor2(c2)
787 unsigned size() const { return maSteps; }
788 const T operator [] (unsigned v) const
790 const double aHalfSteps = maSteps/2.0;
791 const double w = (v >= aHalfSteps) ?
792 1.0-((double(v)-aHalfSteps)/aHalfSteps) :
793 (double(v)*2.0)/maSteps;
794 return T( static_cast<value_type>(maColor1.r+(maColor2.r-maColor1.r)*w),
795 static_cast<value_type>(maColor1.g+(maColor2.g-maColor1.g)*w),
796 static_cast<value_type>(maColor1.b+(maColor2.b-maColor1.b)*w),
797 static_cast<value_type>(maColor1.a+(maColor2.a-maColor1.a)*w));
800 unsigned int maSteps;
801 const T maColor1;
802 const T maColor2;
805 //////////////////////////////////////////////////////////////////////////////////
806 // color_generator_adaptor
807 //////////////////////////////////////////////////////////////////////////////////
809 template<typename T> struct color_generator_adaptor
811 color_generator_adaptor( const T &c1,
812 const T &c2,
813 unsigned int aSteps ) : linear_generator(c1,c2,aSteps),
814 axial_generator(c1,c2,aSteps),
815 mbLinear(true) {}
816 void set_linear( bool bLinear ) { mbLinear=bLinear; }
817 unsigned size() const { return mbLinear ? linear_generator.size() : axial_generator.size(); }
818 const T operator [] (unsigned v) const
820 return mbLinear ?
821 linear_generator.operator [] (v) :
822 axial_generator.operator [] (v);
825 color_generator_linear<T> linear_generator;
826 color_generator_axial<T> axial_generator;
827 bool mbLinear;
830 //////////////////////////////////////////////////////////////////////////////////
831 // gradient_polymorphic_wrapper_base
832 //////////////////////////////////////////////////////////////////////////////////
834 struct gradient_polymorphic_wrapper_base
836 virtual int calculate(int x, int y, int) const = 0;
839 //////////////////////////////////////////////////////////////////////////////////
840 // gradient_polymorphic_wrapper
841 //////////////////////////////////////////////////////////////////////////////////
843 template<class GradientF> struct gradient_polymorphic_wrapper :
844 public gradient_polymorphic_wrapper_base
846 virtual int calculate(int x, int y, int d) const
848 return m_gradient.calculate(x, y, d);
850 GradientF m_gradient;
853 //////////////////////////////////////////////////////////////////////////////////
854 // gradient_rect
855 //////////////////////////////////////////////////////////////////////////////////
857 class gradient_rect
859 public:
861 int width;
862 int height;
864 inline int calculate(int x, int y, int d) const
866 int ax = abs(x);
867 int ay = abs(y);
868 int clamp_x = height>width ? 0 : (width-height);
869 int clamp_y = height>width ? (height-width) : 0;
870 int value_x = (ax-clamp_x)*d/(width-clamp_x);
871 int value_y = (ay-clamp_y)*d/(height-clamp_y);
872 if(ax < (clamp_x))
873 value_x = 0;
874 if(ay < (clamp_y))
875 value_y = 0;
876 return value_x > value_y ? value_x : value_y;
880 sal_uInt32 getBytesPerPixel( IColorBuffer::Format eFormat )
882 switch(eFormat)
884 default:
885 OSL_ENSURE(false, "Unexpected pixel format");
886 // FALLTHROUGH intended
887 case IColorBuffer::FMT_R8G8B8:
888 return 3L;
889 case IColorBuffer::FMT_A8R8G8B8:
890 return 4L;
895 //////////////////////////////////////////////////////////////////////////////////
896 // Image::drawLinePolyPolygon
897 //////////////////////////////////////////////////////////////////////////////////
899 template<class pixel_format>
900 void Image::drawLinePolyPolygonImpl( const ::basegfx::B2DPolyPolygon& rPolyPolygon,
901 double fStrokeWidth,
902 const rendering::ViewState& viewState,
903 const rendering::RenderState& renderState )
905 ::basegfx::B2DPolyPolygon aPolyPolygon( rPolyPolygon );
906 ARGB aRenderColor;
908 setupPolyPolygon( aPolyPolygon, false, aRenderColor, viewState, renderState );
910 if( !aPolyPolygon.count() )
911 return;
913 // Class template pixel_formats_rgb24 has full knowledge about this
914 // particular pixel format in memory. The only template parameter
915 // can be order_rgb24 or order_bgr24 that determines the order of color channels.
916 //typedef agg::pixfmt_rgba32 pixel_format;
917 pixel_format pixf(maRenderingBuffer);
919 // There are two basic renderers with almost the same functionality:
920 // renderer_base and renderer_mclip. The first one is used most often
921 // and it performs low level clipping.
922 // This simply adds clipping to the graphics buffer, the clip rect
923 // will be initialized to the area of the framebuffer.
924 typedef agg::renderer_base<pixel_format> renderer_base;
925 agg::renderer_base<pixel_format> renb(pixf);
927 // To draw Anti-Aliased primitives one shoud *rasterize* them first.
928 // The primary rasterization technique in AGG is scanline based.
929 // That is, a polygon is converted into a number of horizontal
930 // scanlines and then the scanlines are being rendered one by one.
931 // To transfer information from a rasterizer to the scanline renderer
932 // there scanline containers are used. A scanline consists of a
933 // number of horizontal, non-intersecting spans. All spans must be ordered by X.
934 // --> *packed* scanline container
935 agg::scanline_p8 sl;
937 typedef agg::renderer_outline_aa<renderer_base> renderer_type;
938 typedef agg::rasterizer_outline_aa<renderer_type> rasterizer_type;
939 agg::line_profile_aa profile;
940 profile.width(fStrokeWidth);
941 renderer_type ren(renb, profile);
942 rasterizer_type ras(ren);
944 const agg::rgba8 fillcolor(aRenderColor.Color.r,
945 aRenderColor.Color.g,
946 aRenderColor.Color.b,
947 aRenderColor.Color.a);
948 ren.color(fillcolor);
950 agg::path_storage path;
951 agg::conv_curve<agg::path_storage> curve(path);
953 for(sal_uInt32 nPolygon=0; nPolygon<aPolyPolygon.count(); ++nPolygon)
955 const basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(nPolygon));
956 const sal_uInt32 nPointCount(aPolygon.count());
958 if(nPointCount)
960 if(aPolygon.areControlPointsUsed())
962 // prepare edge-based loop
963 basegfx::B2DPoint aCurrentPoint(aPolygon.getB2DPoint(0));
964 const sal_uInt32 nEdgeCount(aPolygon.isClosed() ? nPointCount - 1 : nPointCount);
966 // first vertex
967 path.move_to(aCurrentPoint.getX(), aCurrentPoint.getY());
969 for(sal_uInt32 a(0); a < nEdgeCount; a++)
971 // access next point
972 const sal_uInt32 nNextIndex((a + 1) % nPointCount);
973 const basegfx::B2DPoint aNextPoint(aPolygon.getB2DPoint(nNextIndex));
975 // get control points
976 const basegfx::B2DPoint aControlNext(aPolygon.getNextControlPoint(a));
977 const basegfx::B2DPoint aControlPrev(aPolygon.getPrevControlPoint(nNextIndex));
979 // specify first cp, second cp, next vertex
980 path.curve4(
981 aControlNext.getX(), aControlNext.getY(),
982 aControlPrev.getX(), aControlPrev.getY(),
983 aNextPoint.getX(), aNextPoint.getY());
985 // prepare next step
986 aCurrentPoint = aNextPoint;
989 else
991 const basegfx::B2DPoint aStartPoint(aPolygon.getB2DPoint(0));
992 ras.move_to_d(aStartPoint.getX(), aStartPoint.getY());
994 for(sal_uInt32 a(1); a < nPointCount; a++)
996 const basegfx::B2DPoint aVertexPoint(aPolygon.getB2DPoint(a));
997 ras.line_to_d(aVertexPoint.getX(), aVertexPoint.getY());
1000 ras.render(aPolygon.isClosed());
1005 ras.add_path(curve);
1006 ras.render(false);
1009 //////////////////////////////////////////////////////////////////////////////////
1010 // Image::drawLinePolyPolygon
1011 //////////////////////////////////////////////////////////////////////////////////
1013 void Image::drawLinePolyPolygon( const ::basegfx::B2DPolyPolygon& rPoly,
1014 double fStrokeWidth,
1015 const rendering::ViewState& viewState,
1016 const rendering::RenderState& renderState )
1018 switch(maDesc.eFormat)
1020 case FMT_R8G8B8:
1021 drawLinePolyPolygonImpl<agg::pixfmt_rgb24>(rPoly,fStrokeWidth,viewState,renderState);
1022 break;
1023 case FMT_A8R8G8B8:
1024 drawLinePolyPolygonImpl<agg::pixfmt_rgba32>(rPoly,fStrokeWidth,viewState,renderState);
1025 break;
1026 default:
1027 OSL_ENSURE(false, "Unexpected pixel format");
1028 break;
1032 //////////////////////////////////////////////////////////////////////////////////
1033 // Image::implDrawBitmap
1034 //////////////////////////////////////////////////////////////////////////////////
1036 /** internal utility function to draw one image into another one.
1037 the source image will be drawn with respect to the given
1038 transform and clip settings.
1040 ImageCachedPrimitiveSharedPtr Image::implDrawBitmap(
1041 const Image& rBitmap,
1042 const rendering::ViewState& viewState,
1043 const rendering::RenderState& renderState )
1045 ::basegfx::B2DPolyPolygon aPoly(
1046 ::basegfx::tools::createPolygonFromRect(
1047 ::basegfx::B2DRange(0.0, 0.0,
1048 rBitmap.maDesc.nWidth,
1049 rBitmap.maDesc.nHeight ) ) );
1050 ARGB aFillColor;
1052 setupPolyPolygon( aPoly, true, aFillColor, viewState, renderState );
1054 if( !aPoly.count() )
1055 return ImageCachedPrimitiveSharedPtr();
1057 ::basegfx::B2DHomMatrix aViewTransform;
1058 ::basegfx::B2DHomMatrix aRenderTransform;
1059 ::basegfx::B2DHomMatrix aTextureTransform;
1061 ::basegfx::unotools::homMatrixFromAffineMatrix(aRenderTransform,
1062 renderState.AffineTransform);
1063 ::basegfx::unotools::homMatrixFromAffineMatrix(aViewTransform,
1064 viewState.AffineTransform);
1065 aTextureTransform *= aRenderTransform;
1067 // TODO(F2): Fill in texture
1068 rendering::Texture aTexture;
1070 return fillTexturedPolyPolygon( rBitmap,
1071 aPoly,
1072 aTextureTransform,
1073 aViewTransform,
1074 aTexture );
1077 //////////////////////////////////////////////////////////////////////////////////
1078 // cachedPrimitiveFTPP [cachedPrimitive for [F]ill[T]extured[P]oly[P]olygon]
1079 //////////////////////////////////////////////////////////////////////////////////
1081 #if AGG_VERSION >= 2400
1082 template<class pixel_format_dst,class span_gen_type>
1083 #else
1084 template<class pixel_format,class span_gen_type>
1085 #endif
1086 class cachedPrimitiveFTPP : public ImageCachedPrimitive
1088 public:
1090 cachedPrimitiveFTPP( const ::basegfx::B2DHomMatrix &rTransform,
1091 const ::basegfx::B2DHomMatrix &rViewTransform,
1092 agg::rendering_buffer &dst,
1093 const agg::rendering_buffer& src ) :
1094 aTransform(rTransform),
1095 inter(tm),
1096 filter(filter_kernel),
1097 #if AGG_VERSION >= 2400
1098 pixs(const_cast<agg::rendering_buffer&>(src)),
1099 source(pixs),
1100 sg(source,inter,filter),
1101 pixd(dst),
1102 rb(pixd),
1103 ren(rb,sa,sg)
1104 #else
1105 sg(sa,src,inter,filter),
1106 pixf(dst),
1107 rb(pixf),
1108 ren(rb,sg)
1109 #endif
1111 ::basegfx::B2DHomMatrix aFinalTransform(aTransform);
1112 aFinalTransform *= rViewTransform;
1113 tm = transAffineFromB2DHomMatrix(aFinalTransform);
1114 tm.invert();
1117 virtual void setImage( const ::boost::shared_ptr< class Image >& rTargetImage )
1119 pImage=rTargetImage;
1122 virtual sal_Int8 redraw( const ::com::sun::star::rendering::ViewState& aState ) const
1124 ::basegfx::B2DHomMatrix aViewTransform;
1125 ::basegfx::unotools::homMatrixFromAffineMatrix(aViewTransform,aState.AffineTransform);
1126 ::basegfx::B2DHomMatrix aFinalTransform(aTransform);
1127 aFinalTransform *= aViewTransform;
1128 tm = transAffineFromB2DHomMatrix(aFinalTransform);
1129 tm.invert();
1130 redraw();
1131 return ::com::sun::star::rendering::RepaintResult::REDRAWN;
1134 inline void redraw() const { agg::render_scanlines(ras, sl, ren); }
1136 mutable agg::rasterizer_scanline_aa<> ras;
1138 private:
1140 typedef agg::span_interpolator_linear<> interpolator_type;
1141 #if AGG_VERSION >= 2400
1142 typedef agg::renderer_base<pixel_format_dst> renderer_base;
1143 typedef agg::span_allocator< typename span_gen_type::color_type > span_alloc_type;
1144 typedef agg::renderer_scanline_aa<renderer_base, span_alloc_type, span_gen_type> renderer_type;
1145 typedef typename span_gen_type::source_type source_type;
1146 typedef typename span_gen_type::source_type::pixfmt_type pixel_format_src;
1147 #else
1148 typedef agg::renderer_base<pixel_format> renderer_base;
1149 typedef agg::renderer_scanline_aa<renderer_base, span_gen_type> renderer_type;
1150 #endif
1152 ::basegfx::B2DHomMatrix aTransform;
1153 interpolator_type inter;
1154 agg::image_filter_bilinear filter_kernel;
1155 agg::image_filter_lut filter;
1156 #if AGG_VERSION >= 2400
1157 span_alloc_type sa;
1158 pixel_format_src pixs;
1159 source_type source;
1160 #else
1161 agg::span_allocator< typename span_gen_type::color_type > sa;
1162 #endif
1163 span_gen_type sg;
1164 #if AGG_VERSION >= 2400
1165 pixel_format_dst pixd;
1166 #else
1167 pixel_format pixf;
1168 #endif
1169 renderer_base rb;
1170 mutable renderer_type ren;
1171 mutable agg::scanline_p8 sl;
1172 mutable agg::trans_affine tm;
1173 ImageSharedPtr pImage;
1176 //////////////////////////////////////////////////////////////////////////////////
1177 // Image::fillTexturedPolyPolygon
1178 //////////////////////////////////////////////////////////////////////////////////
1180 template<class pixel_format,class span_gen_type>
1181 ImageCachedPrimitiveSharedPtr Image::fillTexturedPolyPolygonImpl(
1182 const Image& rTexture,
1183 const ::basegfx::B2DPolyPolygon& rPolyPolygon,
1184 const ::basegfx::B2DHomMatrix& rOverallTransform,
1185 const ::basegfx::B2DHomMatrix& rViewTransform,
1186 const rendering::Texture& )
1188 // calculate final overall transform.
1189 ::basegfx::B2DHomMatrix aOverallTransform(rOverallTransform);
1190 aOverallTransform *= rViewTransform;
1192 // instead of always using the full-blown solution we
1193 // first check to see if this is a simple rectangular
1194 // 1-to-1 copy from source to destination image.
1195 ::basegfx::B2DTuple aTranslate(aOverallTransform.get(0,2),aOverallTransform.get(1,2));
1196 ::basegfx::B2DTuple aSize(rTexture.maDesc.nWidth,rTexture.maDesc.nHeight);
1197 ::basegfx::B2DRange aRange(aTranslate,aTranslate+aSize);
1198 ::basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon);
1199 aPolyPolygon.transform(aOverallTransform);
1200 if(::basegfx::tools::isPolyPolygonEqualRectangle(aPolyPolygon,aRange))
1202 // yes, we can take the shortcut.
1203 // but we need to clip the destination rectangle
1204 // against the boundary of the destination image.
1205 sal_Int32 dwSrcX(0);
1206 sal_Int32 dwSrcY(0);
1207 sal_Int32 dwDstX(static_cast<sal_Int32>(aTranslate.getX()));
1208 sal_Int32 dwDstY(static_cast<sal_Int32>(aTranslate.getY()));
1209 sal_Int32 dwWidth(rTexture.maDesc.nWidth);
1210 sal_Int32 dwHeight(rTexture.maDesc.nHeight);
1212 // prevent fast copy if destination position is not an
1213 // integer coordinate. otherwise we would most probably
1214 // introduce visual glitches while combining this with
1215 // high-accuracy rendering stuff.
1216 if( ::basegfx::fTools::equalZero(aTranslate.getX()-dwDstX) &&
1217 ::basegfx::fTools::equalZero(aTranslate.getY()-dwDstY))
1219 // clip against destination boundary. shrink size if
1220 // necessary, modify destination position if we need to.
1221 if(dwDstX < 0) { dwWidth-=dwDstX; dwSrcX=-dwDstX; dwDstX=0; }
1222 if(dwDstY < 0) { dwHeight-=dwDstY; dwSrcY=-dwDstY; dwDstY=0; }
1223 const sal_Int32 dwRight(dwDstX+dwWidth);
1224 const sal_Int32 dwBottom(dwDstY+dwHeight);
1225 if(dwRight > dwWidth)
1226 dwWidth -= dwRight-dwWidth;
1227 if(dwBottom > dwHeight)
1228 dwHeight -= dwBottom-dwHeight;
1230 // calculate source buffer
1231 const Description &srcDesc = rTexture.maDesc;
1232 const sal_uInt32 dwSrcBytesPerPixel(getBytesPerPixel(srcDesc.eFormat));
1233 const sal_uInt32 dwSrcPitch(srcDesc.nWidth*dwSrcBytesPerPixel+srcDesc.nStride);
1234 sal_uInt8 *pSrcBuffer = rTexture.maDesc.pBuffer+(dwSrcPitch*dwSrcX)+(dwSrcBytesPerPixel*dwSrcY);
1236 // calculate destination buffer
1237 const Description &dstDesc = maDesc;
1238 const sal_uInt32 dwDstBytesPerPixel(getBytesPerPixel(dstDesc.eFormat));
1239 const sal_uInt32 dwDstPitch(dstDesc.nWidth*dwDstBytesPerPixel+dstDesc.nStride);
1240 sal_uInt8 *pDstBuffer = maDesc.pBuffer+(dwDstPitch*dwDstY)+(dwDstBytesPerPixel*dwDstX);
1242 // if source and destination format match, we can simply
1243 // copy whole scanlines.
1244 if(srcDesc.eFormat == dstDesc.eFormat)
1246 const sal_Size dwNumBytesPerScanline(dwSrcBytesPerPixel*dwWidth);
1247 for(sal_Int32 y=0; y<dwHeight; ++y)
1249 rtl_copyMemory(pDstBuffer,pSrcBuffer,dwNumBytesPerScanline);
1250 pSrcBuffer += dwSrcPitch;
1251 pDstBuffer += dwDstPitch;
1254 else
1256 // otherwise [formats do not match], we need to copy
1257 // each pixel one by one and convert from source to destination format.
1258 if(srcDesc.eFormat == FMT_A8R8G8B8 && dstDesc.eFormat == FMT_R8G8B8)
1260 for(sal_Int32 y=0; y<dwHeight; ++y)
1262 sal_uInt8 *pSrc=pSrcBuffer;
1263 sal_uInt8 *pDst=pDstBuffer;
1264 for(sal_Int32 x=0; x<dwWidth; ++x)
1266 sal_uInt8 r(*pSrc++);
1267 sal_uInt8 g(*pSrc++);
1268 sal_uInt8 b(*pSrc++);
1269 sal_uInt8 Alpha(*pSrc++);
1270 sal_uInt8 OneMinusAlpha(0xFF-Alpha);
1271 *pDst=(((r*Alpha)+((*pDst)*OneMinusAlpha))/0xFF);
1272 ++pDst;
1273 *pDst=(((g*Alpha)+((*pDst)*OneMinusAlpha))/0xFF);
1274 ++pDst;
1275 *pDst=(((b*Alpha)+((*pDst)*OneMinusAlpha))/0xFF);
1276 ++pDst;
1278 pSrcBuffer += dwSrcPitch;
1279 pDstBuffer += dwDstPitch;
1282 else if(srcDesc.eFormat == FMT_R8G8B8 && dstDesc.eFormat == FMT_A8R8G8B8)
1284 for(sal_Int32 y=0; y<dwHeight; ++y)
1286 sal_uInt8 *pSrc=pSrcBuffer;
1287 sal_uInt8 *pDst=pDstBuffer;
1288 for(sal_Int32 x=0; x<dwWidth; ++x)
1290 sal_uInt8 r(*pSrc++);
1291 sal_uInt8 g(*pSrc++);
1292 sal_uInt8 b(*pSrc++);
1293 *pDst++=r;
1294 *pDst++=g;
1295 *pDst++=b;
1296 *pDst++=0xFF;
1298 pSrcBuffer += dwSrcPitch;
1299 pDstBuffer += dwDstPitch;
1304 return ImageCachedPrimitiveSharedPtr();
1308 typedef cachedPrimitiveFTPP<pixel_format,span_gen_type> cachedPrimitive_t;
1309 cachedPrimitive_t *pPrimitive = new cachedPrimitive_t( rOverallTransform,
1310 rViewTransform,
1311 maRenderingBuffer,
1312 rTexture.maRenderingBuffer);
1314 agg::path_storage path;
1315 agg::conv_curve<agg::path_storage> curve(path);
1317 for(sal_uInt32 nPolygon(0); nPolygon < rPolyPolygon.count(); nPolygon++)
1319 const basegfx::B2DPolygon aPolygon(rPolyPolygon.getB2DPolygon(nPolygon));
1320 const sal_uInt32 nPointCount(aPolygon.count());
1322 if(nPointCount)
1324 if(aPolygon.areControlPointsUsed())
1326 // prepare edge-based loop
1327 basegfx::B2DPoint aCurrentPoint(aPolygon.getB2DPoint(0));
1328 const sal_uInt32 nEdgeCount(aPolygon.isClosed() ? nPointCount - 1 : nPointCount);
1330 // first vertex
1331 path.move_to(aCurrentPoint.getX(), aCurrentPoint.getY());
1333 for(sal_uInt32 a(0); a < nEdgeCount; a++)
1335 // access next point
1336 const sal_uInt32 nNextIndex((a + 1) % nPointCount);
1337 const basegfx::B2DPoint aNextPoint(aPolygon.getB2DPoint(nNextIndex));
1339 // get control points
1340 const basegfx::B2DPoint aControlNext(aPolygon.getNextControlPoint(a));
1341 const basegfx::B2DPoint aControlPrev(aPolygon.getPrevControlPoint(nNextIndex));
1343 // specify first cp, second cp, next vertex
1344 path.curve4(
1345 aControlNext.getX(), aControlNext.getY(),
1346 aControlPrev.getX(), aControlPrev.getY(),
1347 aNextPoint.getX(), aNextPoint.getY());
1349 // prepare next step
1350 aCurrentPoint = aNextPoint;
1353 else
1355 const basegfx::B2DPoint aPoint(aPolygon.getB2DPoint(0));
1356 pPrimitive->ras.move_to_d(aPoint.getX(), aPoint.getY());
1358 for(sal_uInt32 a(1); a < nPointCount; a++)
1360 const basegfx::B2DPoint aVertexPoint(aPolygon.getB2DPoint(a));
1361 pPrimitive->ras.line_to_d(aVertexPoint.getX(), aVertexPoint.getY());
1364 if(aPolygon.isClosed())
1366 pPrimitive->ras.close_polygon();
1372 pPrimitive->ras.add_path(curve);
1373 pPrimitive->redraw();
1375 return ImageCachedPrimitiveSharedPtr(pPrimitive);
1378 //////////////////////////////////////////////////////////////////////////////////
1379 // Image::fillTexturedPolyPolygon
1380 //////////////////////////////////////////////////////////////////////////////////
1382 ImageCachedPrimitiveSharedPtr Image::fillTexturedPolyPolygon(
1383 const Image& rTexture,
1384 const ::basegfx::B2DPolyPolygon& rPolyPolygon,
1385 const ::basegfx::B2DHomMatrix& rOverallTransform,
1386 const ::basegfx::B2DHomMatrix& rViewTransform,
1387 const rendering::Texture& texture )
1389 typedef agg::wrap_mode_repeat wrap_x_type;
1390 typedef agg::wrap_mode_repeat wrap_y_type;
1391 typedef agg::pixfmt_rgb24 pixfmt_rgb24;
1392 typedef agg::pixfmt_rgba32 pixfmt_rgba32;
1393 #if AGG_VERSION >= 2400
1394 typedef agg::image_accessor_wrap< pixfmt_rgba32, wrap_x_type, wrap_y_type > img_source_type_rgba;
1395 typedef agg::image_accessor_wrap< pixfmt_rgb24, wrap_x_type, wrap_y_type > img_source_type_rgb;
1397 typedef agg::span_image_resample_rgba_affine< img_source_type_rgba > span_gen_type_rgba;
1398 typedef agg::span_image_resample_rgb_affine< img_source_type_rgb > span_gen_type_rgb;
1399 #else
1400 typedef agg::span_pattern_resample_rgba_affine< pixfmt_rgba32::color_type,
1401 pixfmt_rgba32::order_type,
1402 wrap_x_type,
1403 wrap_y_type> span_gen_type_rgba;
1404 typedef agg::span_pattern_resample_rgb_affine< pixfmt_rgb24::color_type,
1405 pixfmt_rgb24::order_type,
1406 wrap_x_type,
1407 wrap_y_type> span_gen_type_rgb;
1408 #endif
1410 const Format nDest = maDesc.eFormat;
1411 const Format nSource = rTexture.maDesc.eFormat;
1413 if(nDest == FMT_R8G8B8 && nSource == FMT_R8G8B8)
1415 return fillTexturedPolyPolygonImpl< agg::pixfmt_rgb24,
1416 span_gen_type_rgb >(
1417 rTexture,
1418 rPolyPolygon,
1419 rOverallTransform,
1420 rViewTransform,
1421 texture );
1423 else if(nDest == FMT_R8G8B8 && nSource == FMT_A8R8G8B8)
1425 return fillTexturedPolyPolygonImpl< agg::pixfmt_rgb24,
1426 span_gen_type_rgba >(
1427 rTexture,
1428 rPolyPolygon,
1429 rOverallTransform,
1430 rViewTransform,
1431 texture );
1433 else if(nDest == FMT_A8R8G8B8 && nSource == FMT_R8G8B8)
1435 return fillTexturedPolyPolygonImpl< agg::pixfmt_rgba32,
1436 span_gen_type_rgb >(
1437 rTexture,
1438 rPolyPolygon,
1439 rOverallTransform,
1440 rViewTransform,
1441 texture );
1443 else if(nDest == FMT_A8R8G8B8 && nSource == FMT_A8R8G8B8)
1445 return fillTexturedPolyPolygonImpl< agg::pixfmt_rgba32,
1446 span_gen_type_rgba >(
1447 rTexture,
1448 rPolyPolygon,
1449 rOverallTransform,
1450 rViewTransform,
1451 texture );
1453 else
1455 OSL_ENSURE(false, "Unexpected pixel format");
1458 return ImageCachedPrimitiveSharedPtr();
1461 //////////////////////////////////////////////////////////////////////////////////
1462 // Image::fillGradient
1463 //////////////////////////////////////////////////////////////////////////////////
1465 template<class pixel_format>
1466 void Image::fillGradientImpl( const ParametricPolyPolygon::Values& rValues,
1467 const uno::Sequence< double >& rUnoColor1,
1468 const uno::Sequence< double >& rUnoColor2,
1469 const ::basegfx::B2DPolyPolygon& rPolyPolygon,
1470 const ::basegfx::B2DHomMatrix& rOverallTransform,
1471 const rendering::Texture& )
1473 const ARGB aColor1(0xFFFFFFFF,
1474 rUnoColor1);
1475 const ARGB aColor2(0xFFFFFFFF,
1476 rUnoColor2);
1478 // first of all we need to provide the framebuffer we want to render to.
1479 // the properties of the framebuffer are
1480 // 1) memory & layout [width, height, stride]
1481 // 2) pixelformat
1482 // 3) clipping
1484 // Class template pixel_formats_rgb24 has full knowledge about this
1485 // particular pixel format in memory. The only template parameter
1486 // can be order_rgb24 or order_bgr24 that determines the order of color channels.
1487 pixel_format pixf(maRenderingBuffer);
1489 // There are two basic renderers with almost the same functionality:
1490 // renderer_base and renderer_mclip. The first one is used most often
1491 // and it performs low level clipping.
1492 // This simply adds clipping to the graphics buffer, the clip rect
1493 // will be initialized to the area of the framebuffer.
1494 typedef agg::renderer_base<pixel_format> renderer_base;
1495 renderer_base rb(pixf);
1497 // bounding rectangle of untransformed polypolygon
1498 const ::basegfx::B2DRange& rBounds(::basegfx::tools::getRange(rPolyPolygon));
1500 // the color generator produces a specific color from
1501 // some given interpolation value.
1502 // number of steps for color interpolation
1503 typedef typename pixel_format::color_type color_type;
1504 color_type color1(agg::rgba8(aColor1.Color.r,
1505 aColor1.Color.g,
1506 aColor1.Color.b,
1507 255));
1508 color_type color2(agg::rgba8(aColor2.Color.r,
1509 aColor2.Color.g,
1510 aColor2.Color.b,
1511 255));
1512 typedef color_generator_adaptor<color_type> color_generator_type;
1513 unsigned int dwNumSteps = static_cast<unsigned int>(rBounds.getWidth());
1514 color_generator_type colors(color1,color2,dwNumSteps);
1515 colors.set_linear(true);
1517 // color = f(x,y)
1518 gradient_polymorphic_wrapper<agg::gradient_x> gf_x;
1519 gradient_polymorphic_wrapper<agg::gradient_radial> gf_radial;
1520 gradient_polymorphic_wrapper<gradient_rect> gf_rectangular;
1521 gf_rectangular.m_gradient.width = static_cast<int>(rBounds.getWidth())<<4;
1522 gf_rectangular.m_gradient.height = static_cast<int>(rBounds.getHeight())<<4;
1523 const gradient_polymorphic_wrapper_base *gf[] = { &gf_x, // GRADIENT_LINEAR
1524 &gf_x, // GRADIENT_AXIAL
1525 &gf_radial, // GRADIENT_ELLIPTICAL
1526 &gf_rectangular // GRADIENT_RECTANGULAR
1529 // how do texture coordinates change when the pixel coordinate change?
1530 typedef agg::span_interpolator_linear<> interpolator_type;
1531 agg::trans_affine tm;
1532 tm *= agg::trans_affine_scaling(1.0f/rBounds.getWidth(),
1533 1.0f/rBounds.getHeight());
1534 if(rValues.meType == ParametricPolyPolygon::GRADIENT_ELLIPTICAL ||
1535 rValues.meType == ParametricPolyPolygon::GRADIENT_RECTANGULAR)
1537 //tm *= trans_affine_scaling(mnAspectRatio,+1.0f);
1538 //const double fAspect = aBounds.getWidth()/aBounds.getHeight();
1539 //tm *= trans_affine_scaling(+0.5f,+0.5f*(1.0f/fAspect));
1540 //tm *= trans_affine_translation(+0.5f,+0.5f);
1541 tm *= agg::trans_affine_scaling(+0.5f,+0.5f);
1542 tm *= agg::trans_affine_translation(+0.5f,+0.5f);
1544 tm *= transAffineFromB2DHomMatrix(rOverallTransform);
1545 tm.invert();
1546 interpolator_type inter(tm);
1548 // spanline allocators reserve memory for the color values
1549 // filled up by the spanline generators.
1550 typedef agg::span_allocator<color_type> gradient_span_alloc;
1551 gradient_span_alloc span_alloc;
1553 // scanline generators create the actual color values for
1554 // some specific coordinate range of a scanline.
1555 typedef agg::span_gradient<color_type,
1556 interpolator_type,
1557 gradient_polymorphic_wrapper_base,
1558 color_generator_type > gradient_span_gen;
1559 #if AGG_VERSION >= 2400
1560 gradient_span_gen span_gen(inter,
1561 *gf[rValues.meType],
1562 colors,
1564 dwNumSteps);
1565 #else
1566 gradient_span_gen span_gen(span_alloc,
1567 inter,
1568 *gf[rValues.meType],
1569 colors,
1571 dwNumSteps);
1572 #endif
1574 // To draw Anti-Aliased primitives one shoud *rasterize* them first.
1575 // The primary rasterization technique in AGG is scanline based.
1576 // That is, a polygon is converted into a number of horizontal
1577 // scanlines and then the scanlines are being rendered one by one.
1578 // To transfer information from a rasterizer to the scanline renderer
1579 // there scanline containers are used. A scanline consists of a
1580 // number of horizontal, non-intersecting spans. All spans must be ordered by X.
1581 // --> packed scanline container
1582 agg::scanline_p8 sl;
1584 // antialiased scanline renderer with pattern filling capability
1585 // [in contrast to solid renderers, that is]
1586 // the instance of this particular renderer combines the
1587 // renderbuffer [i.e. destination] and the spanline generator [i.e. source]
1588 #if AGG_VERSION >= 2400
1589 typedef agg::renderer_scanline_aa<renderer_base, gradient_span_alloc, gradient_span_gen> renderer_gradient;
1590 renderer_gradient r1(rb, span_alloc, span_gen);
1591 #else
1592 typedef agg::renderer_scanline_aa<renderer_base, gradient_span_gen> renderer_gradient;
1593 renderer_gradient r1(rb, span_gen);
1594 #endif
1596 // instantiate the rasterizer and feed the incoming polypolygon.
1597 agg::rasterizer_scanline_aa<> ras;
1598 agg::path_storage path;
1599 agg::conv_curve<agg::path_storage> curve(path);
1601 for(sal_uInt32 nPolygon(0); nPolygon < rPolyPolygon.count(); nPolygon++)
1603 const basegfx::B2DPolygon aPolygon(rPolyPolygon.getB2DPolygon(nPolygon));
1604 const sal_uInt32 nPointCount(aPolygon.count());
1606 if(nPointCount)
1608 if(aPolygon.areControlPointsUsed())
1610 // prepare edge-based loop
1611 basegfx::B2DPoint aCurrentPoint(aPolygon.getB2DPoint(0));
1612 const sal_uInt32 nEdgeCount(aPolygon.isClosed() ? nPointCount - 1 : nPointCount);
1614 // first vertex
1615 path.move_to(aCurrentPoint.getX(), aCurrentPoint.getY());
1617 for(sal_uInt32 a(0); a < nEdgeCount; a++)
1619 // access next point
1620 const sal_uInt32 nNextIndex((a + 1) % nPointCount);
1621 const basegfx::B2DPoint aNextPoint(aPolygon.getB2DPoint(nNextIndex));
1623 // get control points
1624 const basegfx::B2DPoint aControlNext(aPolygon.getNextControlPoint(a));
1625 const basegfx::B2DPoint aControlPrev(aPolygon.getPrevControlPoint(nNextIndex));
1627 // specify first cp, second cp, next vertex
1628 path.curve4(
1629 aControlNext.getX(), aControlNext.getY(),
1630 aControlPrev.getX(), aControlPrev.getY(),
1631 aNextPoint.getX(), aNextPoint.getY());
1633 // prepare next step
1634 aCurrentPoint = aNextPoint;
1637 else
1639 const basegfx::B2DPoint aPoint(aPolygon.getB2DPoint(0));
1640 ras.move_to_d(aPoint.getX(), aPoint.getY());
1642 for(sal_uInt32 a(1); a < nPointCount; a++)
1644 const basegfx::B2DPoint aVertexPoint(aPolygon.getB2DPoint(a));
1645 ras.line_to_d(aVertexPoint.getX(), aVertexPoint.getY());
1648 if(aPolygon.isClosed())
1650 ras.close_polygon();
1656 // everything is up and running, go...
1657 ras.add_path(curve);
1658 render_scanlines(ras,sl,r1);
1661 //////////////////////////////////////////////////////////////////////////////////
1662 // Image::fillGradient
1663 //////////////////////////////////////////////////////////////////////////////////
1665 void Image::fillGradient( const ParametricPolyPolygon::Values& rValues,
1666 const uno::Sequence< double >& rUnoColor1,
1667 const uno::Sequence< double >& rUnoColor2,
1668 const ::basegfx::B2DPolyPolygon& rPolyPolygon,
1669 const ::basegfx::B2DHomMatrix& rOverallTransform,
1670 const rendering::Texture& texture )
1672 switch(maDesc.eFormat)
1674 case FMT_R8G8B8:
1675 fillGradientImpl<agg::pixfmt_rgb24>(rValues,rUnoColor1,rUnoColor2,rPolyPolygon,rOverallTransform,texture);
1676 break;
1677 case FMT_A8R8G8B8:
1678 fillGradientImpl<agg::pixfmt_rgba32>(rValues,rUnoColor1,rUnoColor2,rPolyPolygon,rOverallTransform,texture);
1679 break;
1680 default:
1681 OSL_ENSURE(false, "Unexpected pixel format");
1682 break;
1686 //////////////////////////////////////////////////////////////////////////////////
1687 // Image::fromVCLBitmap
1688 //////////////////////////////////////////////////////////////////////////////////
1690 bool Image::fromVCLBitmap( ::BitmapEx& rBmpEx )
1692 const ::Size aBmpSize( rBmpEx.GetSizePixel() );
1693 Image::Description desc;
1694 desc.eFormat = rBmpEx.IsTransparent() ? FMT_A8R8G8B8 : FMT_R8G8B8;
1695 desc.nWidth = aBmpSize.Width();
1696 desc.nHeight = aBmpSize.Height();
1697 desc.nStride = 0;
1698 const sal_uInt32 nPitch(desc.nWidth*getBytesPerPixel(desc.eFormat)+desc.nStride);
1699 desc.pBuffer = new sal_uInt8 [nPitch*desc.nHeight];
1700 maDesc = desc;
1701 mbBufferHasUserOwnership = false;
1702 maRenderingBuffer.attach(static_cast<agg::int8u *>(desc.pBuffer),
1703 desc.nWidth,
1704 desc.nHeight,
1705 nPitch);
1706 RawABGRBitmap aBmpData;
1707 aBmpData.mnWidth = aBmpSize.Width();
1708 aBmpData.mnHeight = aBmpSize.Height();
1709 aBmpData.mpBitmapData = static_cast<sal_uInt8 *>(desc.pBuffer);
1710 vclBitmapEx2Raw(rBmpEx,aBmpData);
1712 return true;
1715 //////////////////////////////////////////////////////////////////////////////////
1716 // Image::Image
1717 //////////////////////////////////////////////////////////////////////////////////
1719 Image::Image( const Description& rDesc ) :
1720 maDesc( rDesc ),
1721 maRenderingBuffer(),
1722 mbBufferHasUserOwnership( rDesc.pBuffer != NULL )
1724 #if defined(PROFILER)
1725 for(int i=0; i<TIMER_MAX; ++i)
1726 maElapsedTime[i]=0.0;
1727 #endif
1729 // allocate own buffer memory, if not provided
1730 sal_uInt8* pBuffer = maDesc.pBuffer;
1731 const sal_uInt32 nWidth(maDesc.nWidth);
1732 const sal_uInt32 nHeight(maDesc.nHeight);
1733 const sal_uInt32 nStride(maDesc.nStride);
1734 const sal_uInt32 nPitch(nWidth*getBytesPerPixel(maDesc.eFormat)
1735 + nStride);
1737 if( !pBuffer )
1738 pBuffer = new sal_uInt8 [nPitch*nHeight];
1740 maDesc.pBuffer = pBuffer;
1742 // attach graphics buffer
1743 maRenderingBuffer.attach(
1744 static_cast<agg::int8u *>(pBuffer),
1745 nWidth,
1746 nHeight,
1747 nPitch );
1750 //////////////////////////////////////////////////////////////////////////////////
1751 // Image::Image
1752 //////////////////////////////////////////////////////////////////////////////////
1754 Image::Image( const uno::Reference< rendering::XBitmap >& xBitmap ) :
1755 maDesc(),
1756 maRenderingBuffer(),
1757 mbBufferHasUserOwnership( false )
1759 #if defined(PROFILER)
1760 for(int i=0; i<TIMER_MAX; ++i)
1761 maElapsedTime[i]=0.0;
1762 #endif
1764 // TODO(F1): Add support for floating point bitmap formats
1765 uno::Reference<rendering::XIntegerReadOnlyBitmap> xIntBmp(xBitmap,
1766 uno::UNO_QUERY_THROW);
1767 ::BitmapEx aBmpEx = ::vcl::unotools::bitmapExFromXBitmap(xIntBmp);
1768 if( !!aBmpEx )
1769 fromVCLBitmap(aBmpEx);
1771 // TODO(F2): Fallback to XIntegerBitmap interface for import
1772 OSL_ENSURE(false,
1773 "Image::Image(): Cannot retrieve bitmap data!" );
1776 //////////////////////////////////////////////////////////////////////////////////
1777 // Image::~Image
1778 //////////////////////////////////////////////////////////////////////////////////
1780 Image::~Image()
1782 #if defined(PROFILER)
1784 double aAccumulatedTime(0.0);
1785 for(int i=0; i<TIMER_MAX; ++i)
1786 aAccumulatedTime += maElapsedTime[i];
1788 OSL_TRACE("Image %d - %d %d %d %d %d\n",(int)(aAccumulatedTime*1000.0),
1789 (int)(maElapsedTime[TIMER_FILLTEXTUREDPOLYPOLYGON]*1000.0),
1790 (int)(maElapsedTime[TIMER_FILLB2DPOLYPOLYGON]*1000.0),
1791 (int)(maElapsedTime[TIMER_DRAWPOLYPOLYGON]*1000.0),
1792 (int)(maElapsedTime[TIMER_FILLPOLYPOLYGON]*1000.0),
1793 (int)(maElapsedTime[TIMER_DRAWBITMAP]*1000.0));
1795 #endif
1797 if( !mbBufferHasUserOwnership )
1798 delete [] maDesc.pBuffer;
1801 //////////////////////////////////////////////////////////////////////////////////
1802 // Image::clear
1803 //////////////////////////////////////////////////////////////////////////////////
1805 template<class pixel_format>
1806 void Image::clearImpl( sal_uInt8 a,
1807 sal_uInt8 r,
1808 sal_uInt8 g,
1809 sal_uInt8 b )
1811 pixel_format pixf(maRenderingBuffer);
1812 agg::renderer_base<pixel_format> renb(pixf);
1814 renb.clear(agg::rgba8(r,g,b,a));
1817 //////////////////////////////////////////////////////////////////////////////////
1818 // Image::clear
1819 //////////////////////////////////////////////////////////////////////////////////
1821 void Image::clear( sal_uInt8 a,
1822 sal_uInt8 r,
1823 sal_uInt8 g,
1824 sal_uInt8 b )
1826 switch(maDesc.eFormat)
1828 case FMT_R8G8B8:
1829 return clearImpl<agg::pixfmt_rgb24>(a,r,g,b);
1830 case FMT_A8R8G8B8:
1831 return clearImpl<agg::pixfmt_rgba32>(a,r,g,b);
1832 default:
1833 OSL_ENSURE(false, "Unexpected pixel format");
1834 break;
1838 //////////////////////////////////////////////////////////////////////////////////
1839 // Image::fillB2DPolyPolygon
1840 //////////////////////////////////////////////////////////////////////////////////
1842 void Image::fillB2DPolyPolygon(
1843 const ::basegfx::B2DPolyPolygon& rPolyPolygon,
1844 const rendering::ViewState& viewState,
1845 const rendering::RenderState& renderState )
1847 #if defined(PROFILER)
1848 ScopeTimer aTimer(TIMER_FILLB2DPOLYPOLYGON,this);
1849 #endif
1851 switch(maDesc.eFormat)
1853 case FMT_R8G8B8:
1854 fillPolyPolygonImpl<agg::pixfmt_rgb24>(rPolyPolygon,viewState,renderState);
1855 break;
1856 case FMT_A8R8G8B8:
1857 fillPolyPolygonImpl<agg::pixfmt_rgba32>(rPolyPolygon,viewState,renderState);
1858 break;
1859 default:
1860 OSL_ENSURE(false, "Unexpected pixel format");
1861 break;
1865 //////////////////////////////////////////////////////////////////////////////////
1866 // Image::lock
1867 //////////////////////////////////////////////////////////////////////////////////
1869 sal_uInt8* Image::lock() const
1871 return maDesc.pBuffer;
1874 //////////////////////////////////////////////////////////////////////////////////
1875 // Image::unlock
1876 //////////////////////////////////////////////////////////////////////////////////
1878 void Image::unlock() const
1882 //////////////////////////////////////////////////////////////////////////////////
1883 // Image::getWidth
1884 //////////////////////////////////////////////////////////////////////////////////
1886 sal_uInt32 Image::getWidth() const
1888 return maDesc.nWidth;
1891 //////////////////////////////////////////////////////////////////////////////////
1892 // Image::getHeight
1893 //////////////////////////////////////////////////////////////////////////////////
1895 sal_uInt32 Image::getHeight() const
1897 return maDesc.nHeight;
1900 //////////////////////////////////////////////////////////////////////////////////
1901 // Image::getStride
1902 //////////////////////////////////////////////////////////////////////////////////
1904 sal_uInt32 Image::getStride() const
1906 return maDesc.nWidth*getBytesPerPixel(maDesc.eFormat)+maDesc.nStride;
1909 //////////////////////////////////////////////////////////////////////////////////
1910 // Image::getFormat
1911 //////////////////////////////////////////////////////////////////////////////////
1913 IColorBuffer::Format Image::getFormat() const
1915 return maDesc.eFormat;
1918 //////////////////////////////////////////////////////////////////////////////////
1919 // Image::drawPoint
1920 //////////////////////////////////////////////////////////////////////////////////
1922 void Image::drawPoint( const geometry::RealPoint2D& /*aPoint*/,
1923 const rendering::ViewState& /*viewState*/,
1924 const rendering::RenderState& /*renderState*/ )
1926 OSL_ENSURE(false,
1927 "Image::drawPoint(): NYI" );
1930 //////////////////////////////////////////////////////////////////////////////////
1931 // Image::drawLine
1932 //////////////////////////////////////////////////////////////////////////////////
1934 void Image::drawLine( const geometry::RealPoint2D& aStartPoint,
1935 const geometry::RealPoint2D& aEndPoint,
1936 const rendering::ViewState& viewState,
1937 const rendering::RenderState& renderState )
1939 ::basegfx::B2DPolygon aLinePoly;
1940 aLinePoly.append(
1941 ::basegfx::unotools::b2DPointFromRealPoint2D( aStartPoint ) );
1942 aLinePoly.append(
1943 ::basegfx::unotools::b2DPointFromRealPoint2D( aEndPoint ) );
1945 drawLinePolyPolygon( ::basegfx::B2DPolyPolygon( aLinePoly ),
1946 1.0,
1947 viewState,
1948 renderState );
1951 //////////////////////////////////////////////////////////////////////////////////
1952 // Image::drawBezier
1953 //////////////////////////////////////////////////////////////////////////////////
1955 void Image::drawBezier( const geometry::RealBezierSegment2D& aBezierSegment,
1956 const geometry::RealPoint2D& aEndPoint,
1957 const rendering::ViewState& viewState,
1958 const rendering::RenderState& renderState )
1960 basegfx::B2DPolygon aBezierPoly;
1962 aBezierPoly.append(basegfx::B2DPoint(aBezierSegment.Px, aBezierSegment.Py));
1963 aBezierPoly.appendBezierSegment(
1964 basegfx::B2DPoint(aBezierSegment.C1x, aBezierSegment.C1y),
1965 basegfx::B2DPoint(aBezierSegment.C2x, aBezierSegment.C2y),
1966 basegfx::unotools::b2DPointFromRealPoint2D(aEndPoint));
1968 drawLinePolyPolygon( ::basegfx::B2DPolyPolygon( aBezierPoly ),
1969 1.0,
1970 viewState,
1971 renderState );
1974 //////////////////////////////////////////////////////////////////////////////////
1975 // Image::drawPolyPolygon
1976 //////////////////////////////////////////////////////////////////////////////////
1978 ImageCachedPrimitiveSharedPtr Image::drawPolyPolygon(
1979 const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
1980 const rendering::ViewState& viewState,
1981 const rendering::RenderState& renderState )
1983 #if defined(PROFILER)
1984 ScopeTimer aTimer(TIMER_DRAWPOLYPOLYGON,this);
1985 #endif
1987 if( !xPolyPolygon.is() )
1988 return ImageCachedPrimitiveSharedPtr();
1990 drawLinePolyPolygon( ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( xPolyPolygon ),
1991 1.0,
1992 viewState,
1993 renderState );
1995 // TODO(F2): Implement sensible ImageCachedPrimitive
1996 return ImageCachedPrimitiveSharedPtr();
1999 //////////////////////////////////////////////////////////////////////////////////
2000 // Image::strokePolyPolygon
2001 //////////////////////////////////////////////////////////////////////////////////
2003 ImageCachedPrimitiveSharedPtr Image::strokePolyPolygon(
2004 const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
2005 const rendering::ViewState& viewState,
2006 const rendering::RenderState& renderState,
2007 const rendering::StrokeAttributes& strokeAttributes )
2009 if( !xPolyPolygon.is() )
2010 return ImageCachedPrimitiveSharedPtr();
2012 drawLinePolyPolygon( ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( xPolyPolygon ),
2013 strokeAttributes.StrokeWidth,
2014 viewState,
2015 renderState );
2017 // TODO(F2): Implement sensible ImageCachedPrimitive
2018 return ImageCachedPrimitiveSharedPtr();
2021 //////////////////////////////////////////////////////////////////////////////////
2022 // Image::strokeTexturedPolyPolygon
2023 //////////////////////////////////////////////////////////////////////////////////
2025 ImageCachedPrimitiveSharedPtr Image::strokeTexturedPolyPolygon(
2026 const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/,
2027 const rendering::ViewState& /*viewState*/,
2028 const rendering::RenderState& /*renderState*/,
2029 const uno::Sequence< rendering::Texture >& /*textures*/,
2030 const ::std::vector< ::boost::shared_ptr<Image> >& /*textureAnnotations*/,
2031 const rendering::StrokeAttributes& /*strokeAttributes*/ )
2033 OSL_ENSURE(false,
2034 "Image::strokeTexturedPolyPolygon(): NYI" );
2036 // TODO(F2): Implement sensible ImageCachedPrimitive
2037 return ImageCachedPrimitiveSharedPtr();
2040 //////////////////////////////////////////////////////////////////////////////////
2041 // Image::strokeTextureMappedPolyPolygon
2042 //////////////////////////////////////////////////////////////////////////////////
2044 ImageCachedPrimitiveSharedPtr Image::strokeTextureMappedPolyPolygon(
2045 const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/,
2046 const rendering::ViewState& /*viewState*/,
2047 const rendering::RenderState& /*renderState*/,
2048 const uno::Sequence< rendering::Texture >& /*textures*/,
2049 const ::std::vector< ::boost::shared_ptr<Image> >& /*textureAnnotations*/,
2050 const uno::Reference< geometry::XMapping2D >& /*xMapping*/,
2051 const rendering::StrokeAttributes& /*strokeAttributes*/ )
2053 OSL_ENSURE(false,
2054 "Image::strokeTextureMappedPolyPolygon(): NYI" );
2056 // TODO(F2): Implement sensible ImageCachedPrimitive
2057 return ImageCachedPrimitiveSharedPtr();
2060 //////////////////////////////////////////////////////////////////////////////////
2061 // Image::fillPolyPolygon
2062 //////////////////////////////////////////////////////////////////////////////////
2064 template<class pixel_format>
2065 ImageCachedPrimitiveSharedPtr Image::fillPolyPolygonImpl(
2066 const ::basegfx::B2DPolyPolygon& rPolyPolygon,
2067 const rendering::ViewState& viewState,
2068 const rendering::RenderState& renderState )
2070 #if defined(PROFILER)
2071 ScopeTimer aTimer(TIMER_FILLPOLYPOLYGON,this);
2072 #endif
2074 ARGB aFillColor;
2076 ::basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon);
2077 setupPolyPolygon( aPolyPolygon, true, aFillColor, viewState, renderState );
2079 if( !aPolyPolygon.count() )
2080 return ImageCachedPrimitiveSharedPtr();
2082 pixel_format pixf(maRenderingBuffer);
2083 agg::renderer_base<pixel_format> renb(pixf);
2085 // Scanline renderer for solid filling.
2086 agg::renderer_scanline_aa_solid<agg::renderer_base<pixel_format> > ren(renb);
2088 // Rasterizer & scanline
2089 agg::rasterizer_scanline_aa<> ras;
2090 agg::scanline_p8 sl;
2092 agg::path_storage path;
2093 agg::conv_curve<agg::path_storage> curve(path);
2095 for(sal_uInt32 nPolygon(0); nPolygon < aPolyPolygon.count(); nPolygon++)
2097 const basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(nPolygon));
2098 const sal_uInt32 nPointCount(aPolygon.count());
2100 if(nPointCount)
2102 if(aPolygon.areControlPointsUsed())
2104 // prepare edge-based loop
2105 basegfx::B2DPoint aCurrentPoint(aPolygon.getB2DPoint(0));
2106 const sal_uInt32 nEdgeCount(aPolygon.isClosed() ? nPointCount - 1 : nPointCount);
2108 // first vertex
2109 path.move_to(aCurrentPoint.getX(), aCurrentPoint.getY());
2111 for(sal_uInt32 a(0); a < nEdgeCount; a++)
2113 // access next point
2114 const sal_uInt32 nNextIndex((a + 1) % nPointCount);
2115 const basegfx::B2DPoint aNextPoint(aPolygon.getB2DPoint(nNextIndex));
2117 // get control points
2118 const basegfx::B2DPoint aControlNext(aPolygon.getNextControlPoint(a));
2119 const basegfx::B2DPoint aControlPrev(aPolygon.getPrevControlPoint(nNextIndex));
2121 // specify first cp, second cp, next vertex
2122 path.curve4(
2123 aControlNext.getX(), aControlNext.getY(),
2124 aControlPrev.getX(), aControlPrev.getY(),
2125 aNextPoint.getX(), aNextPoint.getY());
2127 // prepare next step
2128 aCurrentPoint = aNextPoint;
2131 else
2133 const basegfx::B2DPoint aPoint(aPolygon.getB2DPoint(0));
2134 ras.move_to_d(aPoint.getX(), aPoint.getY());
2136 for(sal_uInt32 a(1); a < nPointCount; a++)
2138 const basegfx::B2DPoint aVertexPoint(aPolygon.getB2DPoint(a));
2139 ras.line_to_d(aVertexPoint.getX(), aVertexPoint.getY());
2142 if(aPolygon.isClosed())
2144 ras.close_polygon();
2150 ras.add_path(curve);
2151 agg::rgba8 fillcolor(aFillColor.Color.r,aFillColor.Color.g,aFillColor.Color.b,aFillColor.Color.a);
2152 ren.color(fillcolor);
2153 agg::render_scanlines(ras, sl, ren);
2155 // TODO(F2): Implement sensible ImageCachedPrimitive
2156 return ImageCachedPrimitiveSharedPtr();
2159 //////////////////////////////////////////////////////////////////////////////////
2160 // Image::fillPolyPolygon
2161 //////////////////////////////////////////////////////////////////////////////////
2163 ImageCachedPrimitiveSharedPtr Image::fillPolyPolygon(
2164 const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
2165 const rendering::ViewState& viewState,
2166 const rendering::RenderState& renderState )
2168 if( !xPolyPolygon.is() )
2169 return ImageCachedPrimitiveSharedPtr();
2171 ::basegfx::B2DPolyPolygon aPoly(
2172 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( xPolyPolygon ) );
2174 switch(maDesc.eFormat)
2176 case FMT_R8G8B8:
2177 return fillPolyPolygonImpl<agg::pixfmt_rgb24>(aPoly,viewState,renderState);
2178 case FMT_A8R8G8B8:
2179 return fillPolyPolygonImpl<agg::pixfmt_rgba32>(aPoly,viewState,renderState);
2180 default:
2181 OSL_ENSURE(false, "Unexpected pixel format");
2182 break;
2185 return ImageCachedPrimitiveSharedPtr();
2188 //////////////////////////////////////////////////////////////////////////////////
2189 // Image::fillTexturedPolyPolygon
2190 //////////////////////////////////////////////////////////////////////////////////
2192 ImageCachedPrimitiveSharedPtr Image::fillTexturedPolyPolygon(
2193 const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
2194 const rendering::ViewState& viewState,
2195 const rendering::RenderState& renderState,
2196 const uno::Sequence< rendering::Texture >& textures,
2197 const ::std::vector< ::boost::shared_ptr<Image> >& textureAnnotations )
2199 #if defined(PROFILER)
2200 ScopeTimer aTimer(TIMER_FILLTEXTUREDPOLYPOLYGON,this);
2201 #endif
2203 if( !xPolyPolygon.is() )
2204 return ImageCachedPrimitiveSharedPtr();
2206 ::basegfx::B2DPolyPolygon aPoly(
2207 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( xPolyPolygon ) );
2208 ARGB aFillColor;
2210 setupPolyPolygon( aPoly, true, aFillColor, viewState, renderState );
2212 if( !aPoly.count() )
2213 return ImageCachedPrimitiveSharedPtr();
2215 ::basegfx::B2DHomMatrix aViewTransform;
2216 ::basegfx::B2DHomMatrix aRenderTransform;
2217 ::basegfx::B2DHomMatrix aTextureTransform;
2219 ::basegfx::unotools::homMatrixFromAffineMatrix(aTextureTransform,
2220 textures[0].AffineTransform);
2221 ::basegfx::unotools::homMatrixFromAffineMatrix(aRenderTransform,
2222 renderState.AffineTransform);
2223 ::basegfx::unotools::homMatrixFromAffineMatrix(aViewTransform,
2224 viewState.AffineTransform);
2225 aTextureTransform *= aRenderTransform;
2227 // TODO(F1): Multi-texturing
2228 if( textures[0].Gradient.is() )
2230 aTextureTransform *= aViewTransform;
2232 // try to cast XParametricPolyPolygon2D reference to
2233 // our implementation class.
2234 ::canvas::ParametricPolyPolygon* pGradient =
2235 dynamic_cast< ::canvas::ParametricPolyPolygon* >( textures[0].Gradient.get() );
2237 if( pGradient )
2239 const ParametricPolyPolygon::Values& rValues(
2240 pGradient->getValues() );
2242 // TODO: use all the colors and place them on given positions/stops
2243 // TODO(E1): Return value
2244 // TODO(F1): FillRule
2245 fillGradient( rValues,
2246 rValues.maColors [0],
2247 rValues.maColors [rValues.maColors.getLength () - 1],
2248 aPoly,
2249 aTextureTransform,
2250 textures[0] );
2253 else if( textures[0].Bitmap.is() )
2255 ImageSharedPtr pTexture;
2257 if( textureAnnotations[0].get() != NULL )
2258 pTexture = textureAnnotations[0];
2259 else
2260 pTexture.reset( new Image( textures[0].Bitmap ) );
2262 const sal_uInt32 nWidth(pTexture->maDesc.nWidth);
2263 const sal_uInt32 nHeight(pTexture->maDesc.nHeight);
2265 // scale texture into one-by-one unit rect.
2266 aTextureTransform.scale(1.0f/nWidth,
2267 1.0f/nHeight);
2269 // TODO(E1): Return value
2270 // TODO(F1): FillRule
2271 return fillTexturedPolyPolygon( *pTexture,
2272 aPoly,
2273 aTextureTransform,
2274 aViewTransform,
2275 textures[0] );
2278 // TODO(F2): Implement sensible ImageCachedPrimitive
2279 return ImageCachedPrimitiveSharedPtr();
2282 //////////////////////////////////////////////////////////////////////////////////
2283 // Image::fillTextureMappedPolyPolygon
2284 //////////////////////////////////////////////////////////////////////////////////
2286 ImageCachedPrimitiveSharedPtr Image::fillTextureMappedPolyPolygon(
2287 const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/,
2288 const rendering::ViewState& /*viewState*/,
2289 const rendering::RenderState& /*renderState*/,
2290 const uno::Sequence< rendering::Texture >& /*textures*/,
2291 const ::std::vector< ::boost::shared_ptr<Image> >& /*textureAnnotations*/,
2292 const uno::Reference< geometry::XMapping2D >& /*xMapping*/ )
2294 OSL_ENSURE(false,
2295 "Image::fillTextureMappedPolyPolygon(): NYI" );
2297 // TODO(F2): Implement sensible ImageCachedPrimitive
2298 return ImageCachedPrimitiveSharedPtr();
2301 //////////////////////////////////////////////////////////////////////////////////
2302 // Image::drawBitmap
2303 //////////////////////////////////////////////////////////////////////////////////
2305 ImageCachedPrimitiveSharedPtr Image::drawBitmap(
2306 const uno::Reference< rendering::XBitmap >& xBitmap,
2307 const rendering::ViewState& viewState,
2308 const rendering::RenderState& renderState )
2310 #if defined(PROFILER)
2311 ScopeTimer aTimer(TIMER_DRAWBITMAP,this);
2312 #endif
2314 // TODO(P3): Implement bitmap caching
2315 if( !xBitmap.is() )
2316 return ImageCachedPrimitiveSharedPtr();
2318 XBitmapAccessor accessor( xBitmap );
2319 if(accessor.isValid())
2321 Image aImage( accessor.getDesc() );
2323 implDrawBitmap( aImage,
2324 viewState,
2325 renderState );
2327 // TODO(F2): Implement sensible ImageCachedPrimitive
2328 return ImageCachedPrimitiveSharedPtr();
2331 Image aImage( xBitmap );
2333 return implDrawBitmap( aImage,viewState,renderState );
2336 //////////////////////////////////////////////////////////////////////////////////
2337 // Image::drawBitmap
2338 //////////////////////////////////////////////////////////////////////////////////
2340 ImageCachedPrimitiveSharedPtr Image::drawBitmap(
2341 const ImageSharedPtr& rImage,
2342 const rendering::ViewState& viewState,
2343 const rendering::RenderState& renderState )
2345 #if defined(PROFILER)
2346 ScopeTimer aTimer(TIMER_DRAWBITMAP,this);
2347 #endif
2349 // TODO(P3): Implement bitmap caching
2350 if( !rImage )
2351 return ImageCachedPrimitiveSharedPtr();
2353 return implDrawBitmap( *rImage,
2354 viewState,
2355 renderState );
2358 //////////////////////////////////////////////////////////////////////////////////
2359 // Image::drawBitmapModulated
2360 //////////////////////////////////////////////////////////////////////////////////
2362 ImageCachedPrimitiveSharedPtr Image::drawBitmapModulated(
2363 const uno::Reference< rendering::XBitmap >& xBitmap,
2364 const rendering::ViewState& viewState,
2365 const rendering::RenderState& renderState )
2367 // TODO(P3): Implement bitmap caching
2368 if( !xBitmap.is() )
2369 return ImageCachedPrimitiveSharedPtr();
2371 Image aImage( xBitmap );
2373 // TODO(F2): Distinguish modulated and unmodulated bitmap output
2374 return implDrawBitmap( aImage,viewState,renderState );
2377 //////////////////////////////////////////////////////////////////////////////////
2378 // Image::drawBitmapModulated
2379 //////////////////////////////////////////////////////////////////////////////////
2381 ImageCachedPrimitiveSharedPtr Image::drawBitmapModulated(
2382 const ImageSharedPtr& rImage,
2383 const rendering::ViewState& viewState,
2384 const rendering::RenderState& renderState )
2386 // TODO(P3): Implement bitmap caching
2387 if( !rImage )
2388 return ImageCachedPrimitiveSharedPtr();
2390 // TODO(F2): Distinguish modulated and unmodulated bitmap output
2391 return implDrawBitmap( *rImage,viewState,renderState );