merge the formfield patch from ooo-build
[ooovba.git] / canvas / source / tools / image.cxx
blobded6dc9fc3c32f3886f48fea7c97b8855821c8ab
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: image.cxx,v $
10 * $Revision: 1.16 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_canvas.hxx"
34 #include <canvas/debug.hxx>
35 #include <tools/diagnose_ex.h>
37 #include <canvas/canvastools.hxx>
38 #include <canvas/parametricpolypolygon.hxx>
40 #include <com/sun/star/rendering/RepaintResult.hpp>
41 #include <com/sun/star/rendering/XIntegerReadOnlyBitmap.hpp>
43 #include <vcl/canvastools.hxx>
44 #include <vcl/bitmapex.hxx>
45 #include <vcl/bmpacc.hxx>
47 #include <basegfx/range/b2drange.hxx>
48 #include <basegfx/point/b2dpoint.hxx>
49 #include <basegfx/matrix/b2dhommatrix.hxx>
50 #include <basegfx/polygon/b2dpolygon.hxx>
51 #include <basegfx/polygon/b2dpolypolygon.hxx>
52 #include <basegfx/polygon/b2dpolygoncutandtouch.hxx>
53 #include <basegfx/polygon/b2dpolygontriangulator.hxx>
54 #include <basegfx/polygon/b2dpolypolygontools.hxx>
55 #include <basegfx/polygon/b2dpolygontools.hxx>
56 #include <basegfx/polygon/b2dpolygonclipper.hxx>
57 #include <basegfx/tools/canvastools.hxx>
58 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
59 #include <basegfx/polygon/b2dpolygonclipper.hxx>
61 #include "image.hxx"
63 #define CANVAS_IMAGE_CXX
64 #include "image_sysprereq.h"
66 //////////////////////////////////////////////////////////////////////////////////
67 // platform-dependend includes [wrapped into their own namepsaces]
68 //////////////////////////////////////////////////////////////////////////////////
70 #if defined(WNT)
71 # if defined _MSC_VER
72 # pragma warning(push,1)
73 # endif
75 namespace win32
77 #undef DECLARE_HANDLE
78 #undef WB_LEFT
79 #undef WB_RIGHT
80 #undef APIENTRY
81 #define WIN32_LEAN_AND_MEAN
82 #define NOMINMAX
83 #include <windows.h>
86 # if defined _MSC_VER
87 # pragma warning(pop)
88 # endif
89 #elif defined(OS2)
90 namespace os2
92 #include <svpm.h>
94 #else
95 #if !defined(QUARTZ)
96 namespace unx
98 #include <X11/Xlib.h>
100 #endif
101 #endif
103 #include <algorithm>
105 using namespace ::com::sun::star;
107 namespace canvas { namespace
109 //////////////////////////////////////////////////////////////////////////////////
110 // TransAffineFromAffineMatrix
111 //////////////////////////////////////////////////////////////////////////////////
113 ::agg::trans_affine transAffineFromAffineMatrix( const geometry::AffineMatrix2D& m )
115 return agg::trans_affine(m.m00,
116 m.m10,
117 m.m01,
118 m.m11,
119 m.m02,
120 m.m12);
123 //////////////////////////////////////////////////////////////////////////////////
124 // TransAffineFromB2DHomMatrix
125 //////////////////////////////////////////////////////////////////////////////////
127 ::agg::trans_affine transAffineFromB2DHomMatrix( const ::basegfx::B2DHomMatrix& m )
129 return agg::trans_affine(m.get(0,0),
130 m.get(1,0),
131 m.get(0,1),
132 m.get(1,1),
133 m.get(0,2),
134 m.get(1,2));
137 //////////////////////////////////////////////////////////////////////////////////
138 // ARGB
139 //////////////////////////////////////////////////////////////////////////////////
141 struct ARGBColor
143 sal_uInt8 a;
144 sal_uInt8 r;
145 sal_uInt8 g;
146 sal_uInt8 b;
149 /// ARGB color
150 union ARGB
152 ARGBColor Color;
153 sal_uInt32 color;
155 ARGB() :
156 color(0)
160 explicit ARGB( sal_uInt32 _color ) :
161 color(_color)
165 ARGB( sal_uInt8 _a,
166 sal_uInt8 _r,
167 sal_uInt8 _g,
168 sal_uInt8 _b )
170 Color.a = _a;
171 Color.r = _r;
172 Color.g = _g;
173 Color.b = _b;
176 ARGB( sal_uInt32 default_color,
177 const ::com::sun::star::uno::Sequence< double >& sequence ) :
178 color(default_color)
180 if(sequence.getLength() > 2)
182 Color.r = static_cast<sal_uInt8>(255.0f*sequence[0]);
183 Color.g = static_cast<sal_uInt8>(255.0f*sequence[1]);
184 Color.b = static_cast<sal_uInt8>(255.0f*sequence[2]);
185 if(sequence.getLength() > 3)
186 Color.a = static_cast<sal_uInt8>(255.0f*sequence[3]);
190 ARGB( const ARGB& rhs ) :
191 color( rhs.color )
195 ARGB &operator=( const ARGB &rhs )
197 color=rhs.color;
198 return *this;
202 //////////////////////////////////////////////////////////////////////////////////
203 // setupState
204 //////////////////////////////////////////////////////////////////////////////////
206 /// Calc common output state from XCanvas parameters
207 void setupState( ::basegfx::B2DHomMatrix& o_rViewTransform,
208 ::basegfx::B2DHomMatrix& o_rRenderTransform,
209 ::std::auto_ptr< ::basegfx::B2DPolyPolygon >& o_rViewClip,
210 ::std::auto_ptr< ::basegfx::B2DPolyPolygon >& o_rRenderClip,
211 ARGB& o_rRenderColor,
212 const rendering::ViewState& viewState,
213 const rendering::RenderState& renderState )
215 ::basegfx::unotools::homMatrixFromAffineMatrix(o_rRenderTransform,
216 renderState.AffineTransform);
217 ::basegfx::unotools::homMatrixFromAffineMatrix(o_rViewTransform,
218 viewState.AffineTransform);
220 o_rRenderColor = ARGB(0xFFFFFFFF,
221 renderState.DeviceColor);
223 // TODO(F3): handle compositing modes
225 if( viewState.Clip.is() )
227 ::basegfx::B2DPolyPolygon aViewClip(
228 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( viewState.Clip ));
230 if(aViewClip.areControlPointsUsed())
231 aViewClip = ::basegfx::tools::adaptiveSubdivideByAngle(aViewClip);
233 o_rViewClip.reset( new ::basegfx::B2DPolyPolygon( aViewClip ) );
236 if( renderState.Clip.is() )
238 ::basegfx::B2DPolyPolygon aRenderClip(
239 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( viewState.Clip ) );
241 if(aRenderClip.areControlPointsUsed())
242 aRenderClip = ::basegfx::tools::adaptiveSubdivideByAngle(aRenderClip);
244 o_rRenderClip.reset( new ::basegfx::B2DPolyPolygon( aRenderClip ) );
248 //////////////////////////////////////////////////////////////////////////////////
249 // clipAndTransformPolygon
250 //////////////////////////////////////////////////////////////////////////////////
252 /** Clip and transform given polygon
254 @param io_rClippee
255 Polygon to clip
257 @param bIsFilledPolyPolygon
258 When true, the polygon is clipped as if it was to be rendered
259 with fill, when false, the polygon is clipped as if it was to
260 be rendered with stroking.
262 void clipAndTransformPolygon( ::basegfx::B2DPolyPolygon& io_rClippee,
263 bool bIsFilledPolyPolygon,
264 const ::basegfx::B2DHomMatrix& rViewTransform,
265 const ::basegfx::B2DHomMatrix& rRenderTransform,
266 const ::basegfx::B2DPolyPolygon* pViewClip,
267 const ::basegfx::B2DPolyPolygon* pRenderClip )
269 ::basegfx::B2DPolyPolygon aPolyPolygon(io_rClippee);
270 io_rClippee.clear();
272 // clip contour against renderclip
273 if( pRenderClip )
275 // AW: Simplified
276 aPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon(
277 aPolyPolygon, *pRenderClip, true, !bIsFilledPolyPolygon);
280 if( !aPolyPolygon.count() )
281 return;
283 // transform result into view space
284 aPolyPolygon.transform(rRenderTransform);
286 // clip contour against viewclip
287 if( pViewClip )
289 // AW: Simplified
290 aPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon(
291 aPolyPolygon, *pViewClip, true, !bIsFilledPolyPolygon);
294 if(!(aPolyPolygon.count()))
295 return;
297 // transform result into device space
298 aPolyPolygon.transform(rViewTransform);
300 io_rClippee = aPolyPolygon;
303 //////////////////////////////////////////////////////////////////////////////////
304 // setupPolyPolygon
305 //////////////////////////////////////////////////////////////////////////////////
307 void setupPolyPolygon( ::basegfx::B2DPolyPolygon& io_rClippee,
308 bool bIsFilledPolyPolygon,
309 ARGB& o_rRenderColor,
310 const rendering::ViewState& viewState,
311 const rendering::RenderState& renderState )
313 ::basegfx::B2DHomMatrix aViewTransform;
314 ::basegfx::B2DHomMatrix aRenderTransform;
315 ::std::auto_ptr< ::basegfx::B2DPolyPolygon > pViewClip;
316 ::std::auto_ptr< ::basegfx::B2DPolyPolygon > pRenderClip;
318 setupState( aViewTransform,
319 aRenderTransform,
320 pViewClip,
321 pRenderClip,
322 o_rRenderColor,
323 viewState,
324 renderState );
326 clipAndTransformPolygon( io_rClippee,
327 bIsFilledPolyPolygon,
328 aViewTransform,
329 aRenderTransform,
330 pViewClip.get(),
331 pRenderClip.get() );
334 //////////////////////////////////////////////////////////////////////////////////
335 // RawABGRBitmap
336 //////////////////////////////////////////////////////////////////////////////////
338 // Raw ABGR [AABBGGRR] 32bit continous
339 struct RawABGRBitmap
341 sal_Int32 mnWidth;
342 sal_Int32 mnHeight;
343 sal_uInt8* mpBitmapData;
346 //////////////////////////////////////////////////////////////////////////////////
347 // vclBitmapEx2Raw
348 //////////////////////////////////////////////////////////////////////////////////
350 void vclBitmapEx2Raw( const ::BitmapEx& rBmpEx, RawABGRBitmap& rBmpData )
352 Bitmap aBitmap( rBmpEx.GetBitmap() );
354 ScopedBitmapReadAccess pReadAccess( aBitmap.AcquireReadAccess(),
355 aBitmap );
357 const sal_Int32 nWidth( rBmpData.mnWidth );
358 const sal_Int32 nHeight( rBmpData.mnHeight );
360 ENSURE_OR_THROW( pReadAccess.get() != NULL,
361 "vclBitmapEx2Raw(): "
362 "Unable to acquire read acces to bitmap" );
364 if( rBmpEx.IsTransparent())
366 if( rBmpEx.IsAlpha() )
368 // 8bit alpha mask
369 Bitmap aAlpha( rBmpEx.GetAlpha().GetBitmap() );
371 ScopedBitmapReadAccess pAlphaReadAccess( aAlpha.AcquireReadAccess(),
372 aAlpha );
374 // By convention, the access buffer always has
375 // one of the following formats:
377 // BMP_FORMAT_1BIT_MSB_PAL
378 // BMP_FORMAT_4BIT_MSN_PAL
379 // BMP_FORMAT_8BIT_PAL
380 // BMP_FORMAT_16BIT_TC_LSB_MASK
381 // BMP_FORMAT_24BIT_TC_BGR
382 // BMP_FORMAT_32BIT_TC_MASK
384 // and is always BMP_FORMAT_BOTTOM_UP
386 // This is the way
387 // WinSalBitmap::AcquireBuffer() sets up the
388 // buffer
390 ENSURE_OR_THROW( pAlphaReadAccess.get() != NULL,
391 "vclBitmapEx2Raw(): "
392 "Unable to acquire read acces to alpha" );
394 ENSURE_OR_THROW( pAlphaReadAccess->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ||
395 pAlphaReadAccess->GetScanlineFormat() == BMP_FORMAT_8BIT_TC_MASK,
396 "vclBitmapEx2Raw(): "
397 "Unsupported alpha scanline format" );
399 BitmapColor aCol;
400 sal_uInt8* pCurrOutput( rBmpData.mpBitmapData );
401 int x, y;
403 for( y=0; y<nHeight; ++y )
405 switch( pReadAccess->GetScanlineFormat() )
407 case BMP_FORMAT_8BIT_PAL:
409 Scanline pScan = pReadAccess->GetScanline( y );
410 Scanline pAScan = pAlphaReadAccess->GetScanline( y );
412 for( x=0; x<nWidth; ++x )
414 aCol = pReadAccess->GetPaletteColor( *pScan++ );
416 *pCurrOutput++ = aCol.GetBlue();
417 *pCurrOutput++ = aCol.GetGreen();
418 *pCurrOutput++ = aCol.GetRed();
420 // out notion of alpha is
421 // different from the rest
422 // of the world's
423 *pCurrOutput++ = 255 - (BYTE)*pAScan++;
426 break;
428 case BMP_FORMAT_24BIT_TC_BGR:
430 Scanline pScan = pReadAccess->GetScanline( y );
431 Scanline pAScan = pAlphaReadAccess->GetScanline( y );
433 for( x=0; x<nWidth; ++x )
435 // store as RGBA
436 *pCurrOutput++ = *pScan++;
437 *pCurrOutput++ = *pScan++;
438 *pCurrOutput++ = *pScan++;
440 // out notion of alpha is
441 // different from the rest
442 // of the world's
443 *pCurrOutput++ = 255 - (BYTE)*pAScan++;
446 break;
448 // TODO(P2): Might be advantageous
449 // to hand-formulate the following
450 // formats, too.
451 case BMP_FORMAT_1BIT_MSB_PAL:
452 // FALLTHROUGH intended
453 case BMP_FORMAT_4BIT_MSN_PAL:
454 // FALLTHROUGH intended
455 case BMP_FORMAT_16BIT_TC_LSB_MASK:
456 // FALLTHROUGH intended
457 case BMP_FORMAT_32BIT_TC_MASK:
459 Scanline pAScan = pAlphaReadAccess->GetScanline( y );
461 // using fallback for those
462 // seldom formats
463 for( x=0; x<nWidth; ++x )
465 // yes. x and y are swapped on Get/SetPixel
466 aCol = pReadAccess->GetColor(y,x);
468 *pCurrOutput++ = aCol.GetBlue();
469 *pCurrOutput++ = aCol.GetGreen();
470 *pCurrOutput++ = aCol.GetRed();
472 // out notion of alpha is
473 // different from the rest
474 // of the world's
475 *pCurrOutput++ = 255 - (BYTE)*pAScan++;
478 break;
480 case BMP_FORMAT_1BIT_LSB_PAL:
481 // FALLTHROUGH intended
482 case BMP_FORMAT_4BIT_LSN_PAL:
483 // FALLTHROUGH intended
484 case BMP_FORMAT_8BIT_TC_MASK:
485 // FALLTHROUGH intended
486 case BMP_FORMAT_24BIT_TC_RGB:
487 // FALLTHROUGH intended
488 case BMP_FORMAT_24BIT_TC_MASK:
489 // FALLTHROUGH intended
490 case BMP_FORMAT_16BIT_TC_MSB_MASK:
491 // FALLTHROUGH intended
492 case BMP_FORMAT_32BIT_TC_ABGR:
493 // FALLTHROUGH intended
494 case BMP_FORMAT_32BIT_TC_ARGB:
495 // FALLTHROUGH intended
496 case BMP_FORMAT_32BIT_TC_BGRA:
497 // FALLTHROUGH intended
498 case BMP_FORMAT_32BIT_TC_RGBA:
499 // FALLTHROUGH intended
500 default:
501 ENSURE_OR_THROW( false,
502 "vclBitmapEx2Raw(): "
503 "Unexpected scanline format - has "
504 "WinSalBitmap::AcquireBuffer() changed?" );
508 else
510 // 1bit alpha mask
511 Bitmap aMask( rBmpEx.GetMask() );
513 ScopedBitmapReadAccess pMaskReadAccess( aMask.AcquireReadAccess(),
514 aMask );
516 // By convention, the access buffer always has
517 // one of the following formats:
519 // BMP_FORMAT_1BIT_MSB_PAL
520 // BMP_FORMAT_4BIT_MSN_PAL
521 // BMP_FORMAT_8BIT_PAL
522 // BMP_FORMAT_16BIT_TC_LSB_MASK
523 // BMP_FORMAT_24BIT_TC_BGR
524 // BMP_FORMAT_32BIT_TC_MASK
526 // and is always BMP_FORMAT_BOTTOM_UP
528 // This is the way
529 // WinSalBitmap::AcquireBuffer() sets up the
530 // buffer
532 ENSURE_OR_THROW( pMaskReadAccess.get() != NULL,
533 "vclBitmapEx2Raw(): "
534 "Unable to acquire read acces to mask" );
536 ENSURE_OR_THROW( pMaskReadAccess->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL,
537 "vclBitmapEx2Raw(): "
538 "Unsupported mask scanline format" );
540 BitmapColor aCol;
541 int nCurrBit;
542 const int nMask( 1L );
543 const int nInitialBit(7);
544 sal_uInt32 *pBuffer = reinterpret_cast<sal_uInt32 *>(rBmpData.mpBitmapData);
545 int x, y;
547 // mapping table, to get from mask index color to
548 // alpha value (which depends on the mask's palette)
549 sal_uInt8 aColorMap[2];
551 const BitmapColor& rCol0( pMaskReadAccess->GetPaletteColor( 0 ) );
552 const BitmapColor& rCol1( pMaskReadAccess->GetPaletteColor( 1 ) );
554 // shortcut for true luminance calculation
555 // (assumes that palette is grey-level). Note the
556 // swapped the indices here, to account for the
557 // fact that VCL's notion of alpha is inverted to
558 // the rest of the world's.
559 aColorMap[0] = rCol1.GetRed();
560 aColorMap[1] = rCol0.GetRed();
562 for( y=0; y<nHeight; ++y )
564 switch( pReadAccess->GetScanlineFormat() )
566 case BMP_FORMAT_8BIT_PAL:
568 Scanline pScan = pReadAccess->GetScanline( y );
569 Scanline pMScan = pMaskReadAccess->GetScanline( y );
571 for( x=0, nCurrBit=nInitialBit; x<nWidth; ++x )
573 aCol = pReadAccess->GetPaletteColor( *pScan++ );
575 // RGB -> ABGR
576 unsigned int color = aCol.GetRed();
577 color |= aCol.GetGreen()<<8;
578 color |= aCol.GetBlue()<<16;
579 color |= aColorMap[ (pMScan[ (x & ~7L) >> 3L ] >> nCurrBit ) & nMask ]<<24;
580 *pBuffer++ = color;
581 nCurrBit = ((nCurrBit - 1) % 8L) & 7L;
584 break;
586 case BMP_FORMAT_24BIT_TC_BGR:
588 Scanline pScan = pReadAccess->GetScanline( y );
589 Scanline pMScan = pMaskReadAccess->GetScanline( y );
591 for( x=0, nCurrBit=nInitialBit; x<nWidth; ++x )
593 // BGR -> ABGR
594 unsigned int color = (*pScan++)<<16;
595 color |= (*pScan++)<<8;
596 color |= (*pScan++);
597 color |= (aColorMap[ (pMScan[ (x & ~7L) >> 3L ] >> nCurrBit ) & nMask ])<<24;
598 *pBuffer++ = color;
599 nCurrBit = ((nCurrBit - 1) % 8L) & 7L;
602 break;
604 // TODO(P2): Might be advantageous
605 // to hand-formulate the following
606 // formats, too.
607 case BMP_FORMAT_1BIT_MSB_PAL:
608 // FALLTHROUGH intended
609 case BMP_FORMAT_4BIT_MSN_PAL:
610 // FALLTHROUGH intended
611 case BMP_FORMAT_16BIT_TC_LSB_MASK:
612 // FALLTHROUGH intended
613 case BMP_FORMAT_32BIT_TC_MASK:
615 Scanline pMScan = pMaskReadAccess->GetScanline( y );
617 // using fallback for those
618 // seldom formats
619 for( x=0, nCurrBit=nInitialBit; x<nWidth; ++x )
621 // yes. x and y are swapped on Get/SetPixel
622 aCol = pReadAccess->GetColor(y,x);
624 // -> ABGR
625 unsigned int color = aCol.GetBlue()<<16;
626 color |= aCol.GetGreen()<<8;
627 color |= aCol.GetRed();
628 color |= (aColorMap[ (pMScan[ (x & ~7L) >> 3L ] >> nCurrBit ) & nMask ])<<24;
629 *pBuffer++ = color;
630 nCurrBit = ((nCurrBit - 1) % 8L) & 7L;
633 break;
635 case BMP_FORMAT_1BIT_LSB_PAL:
636 // FALLTHROUGH intended
637 case BMP_FORMAT_4BIT_LSN_PAL:
638 // FALLTHROUGH intended
639 case BMP_FORMAT_8BIT_TC_MASK:
640 // FALLTHROUGH intended
641 case BMP_FORMAT_24BIT_TC_RGB:
642 // FALLTHROUGH intended
643 case BMP_FORMAT_24BIT_TC_MASK:
644 // FALLTHROUGH intended
645 case BMP_FORMAT_16BIT_TC_MSB_MASK:
646 // FALLTHROUGH intended
647 case BMP_FORMAT_32BIT_TC_ABGR:
648 // FALLTHROUGH intended
649 case BMP_FORMAT_32BIT_TC_ARGB:
650 // FALLTHROUGH intended
651 case BMP_FORMAT_32BIT_TC_BGRA:
652 // FALLTHROUGH intended
653 case BMP_FORMAT_32BIT_TC_RGBA:
654 // FALLTHROUGH intended
655 default:
656 ENSURE_OR_THROW( false,
657 "vclBitmapEx2Raw(): "
658 "Unexpected scanline format - has "
659 "WinSalBitmap::AcquireBuffer() changed?" );
664 else
666 // *no* alpha mask
667 ULONG nFormat = pReadAccess->GetScanlineFormat();
668 BYTE *pBuffer = reinterpret_cast<BYTE *>(rBmpData.mpBitmapData);
670 switch(nFormat)
672 case BMP_FORMAT_24BIT_TC_BGR:
675 sal_Int32 height = pReadAccess->Height();
676 for(sal_Int32 y=0; y<height; ++y)
678 BYTE *pScanline=pReadAccess->GetScanline(y);
679 sal_Int32 width = pReadAccess->Width();
680 for(sal_Int32 x=0; x<width; ++x)
682 // BGR -> RGB
683 BYTE b(*pScanline++);
684 BYTE g(*pScanline++);
685 BYTE r(*pScanline++);
686 *pBuffer++ = r;
687 *pBuffer++ = g;
688 *pBuffer++ = b;
692 break;
694 case BMP_FORMAT_24BIT_TC_RGB:
697 sal_Int32 height = pReadAccess->Height();
698 for(sal_Int32 y=0; y<height; ++y)
700 BYTE *pScanline=pReadAccess->GetScanline(y);
701 sal_Int32 width = pReadAccess->Width();
702 for(sal_Int32 x=0; x<width; ++x)
704 // RGB -> RGB
705 BYTE r(*pScanline++);
706 BYTE g(*pScanline++);
707 BYTE b(*pScanline++);
708 *pBuffer++ = r;
709 *pBuffer++ = g;
710 *pBuffer++ = b;
714 break;
716 case BMP_FORMAT_1BIT_MSB_PAL:
717 case BMP_FORMAT_1BIT_LSB_PAL:
718 case BMP_FORMAT_4BIT_MSN_PAL:
719 case BMP_FORMAT_4BIT_LSN_PAL:
720 case BMP_FORMAT_8BIT_PAL:
723 sal_Int32 height = pReadAccess->Height();
724 for(sal_Int32 y=0; y<height; ++y)
726 BYTE *pScanline=pReadAccess->GetScanline(y);
727 sal_Int32 width = pReadAccess->Width();
728 for(sal_Int32 x=0; x<width; ++x)
730 BitmapColor aCol(pReadAccess->GetPaletteColor(*pScanline++));
732 *pBuffer++ = aCol.GetRed();
733 *pBuffer++ = aCol.GetGreen();
734 *pBuffer++ = aCol.GetBlue();
738 break;
743 //////////////////////////////////////////////////////////////////////////////////
744 // color_generator_linear
745 //////////////////////////////////////////////////////////////////////////////////
747 template<typename T> struct color_generator_linear
749 typedef typename T::value_type value_type;
751 color_generator_linear( const T &c1,
752 const T &c2,
753 unsigned int aSteps ) : maSteps(aSteps),
754 maColor1(c1),
755 maColor2(c2)
759 unsigned size() const { return maSteps; }
760 const T operator [] (unsigned v) const
762 const double w = double(v)/maSteps;
763 return T( static_cast<value_type>(maColor1.r+(maColor2.r-maColor1.r)*w),
764 static_cast<value_type>(maColor1.g+(maColor2.g-maColor1.g)*w),
765 static_cast<value_type>(maColor1.b+(maColor2.b-maColor1.b)*w),
766 static_cast<value_type>(maColor1.a+(maColor2.a-maColor1.a)*w));
769 unsigned int maSteps;
770 const T maColor1;
771 const T maColor2;
774 //////////////////////////////////////////////////////////////////////////////////
775 // color_generator_axial
776 //////////////////////////////////////////////////////////////////////////////////
778 template<typename T> struct color_generator_axial
780 typedef typename T::value_type value_type;
782 color_generator_axial( const T &c1,
783 const T &c2,
784 unsigned int aSteps ) : maSteps(aSteps),
785 maColor1(c1),
786 maColor2(c2)
790 unsigned size() const { return maSteps; }
791 const T operator [] (unsigned v) const
793 const double aHalfSteps = maSteps/2.0;
794 const double w = (v >= aHalfSteps) ?
795 1.0-((double(v)-aHalfSteps)/aHalfSteps) :
796 (double(v)*2.0)/maSteps;
797 return T( static_cast<value_type>(maColor1.r+(maColor2.r-maColor1.r)*w),
798 static_cast<value_type>(maColor1.g+(maColor2.g-maColor1.g)*w),
799 static_cast<value_type>(maColor1.b+(maColor2.b-maColor1.b)*w),
800 static_cast<value_type>(maColor1.a+(maColor2.a-maColor1.a)*w));
803 unsigned int maSteps;
804 const T maColor1;
805 const T maColor2;
808 //////////////////////////////////////////////////////////////////////////////////
809 // color_generator_adaptor
810 //////////////////////////////////////////////////////////////////////////////////
812 template<typename T> struct color_generator_adaptor
814 color_generator_adaptor( const T &c1,
815 const T &c2,
816 unsigned int aSteps ) : linear_generator(c1,c2,aSteps),
817 axial_generator(c1,c2,aSteps),
818 mbLinear(true) {}
819 void set_linear( bool bLinear ) { mbLinear=bLinear; }
820 unsigned size() const { return mbLinear ? linear_generator.size() : axial_generator.size(); }
821 const T operator [] (unsigned v) const
823 return mbLinear ?
824 linear_generator.operator [] (v) :
825 axial_generator.operator [] (v);
828 color_generator_linear<T> linear_generator;
829 color_generator_axial<T> axial_generator;
830 bool mbLinear;
833 //////////////////////////////////////////////////////////////////////////////////
834 // gradient_polymorphic_wrapper_base
835 //////////////////////////////////////////////////////////////////////////////////
837 struct gradient_polymorphic_wrapper_base
839 virtual int calculate(int x, int y, int) const = 0;
842 //////////////////////////////////////////////////////////////////////////////////
843 // gradient_polymorphic_wrapper
844 //////////////////////////////////////////////////////////////////////////////////
846 template<class GradientF> struct gradient_polymorphic_wrapper :
847 public gradient_polymorphic_wrapper_base
849 virtual int calculate(int x, int y, int d) const
851 return m_gradient.calculate(x, y, d);
853 GradientF m_gradient;
856 //////////////////////////////////////////////////////////////////////////////////
857 // gradient_rect
858 //////////////////////////////////////////////////////////////////////////////////
860 class gradient_rect
862 public:
864 int width;
865 int height;
867 inline int calculate(int x, int y, int d) const
869 int ax = abs(x);
870 int ay = abs(y);
871 int clamp_x = height>width ? 0 : (width-height);
872 int clamp_y = height>width ? (height-width) : 0;
873 int value_x = (ax-clamp_x)*d/(width-clamp_x);
874 int value_y = (ay-clamp_y)*d/(height-clamp_y);
875 if(ax < (clamp_x))
876 value_x = 0;
877 if(ay < (clamp_y))
878 value_y = 0;
879 return value_x > value_y ? value_x : value_y;
883 sal_uInt32 getBytesPerPixel( IColorBuffer::Format eFormat )
885 switch(eFormat)
887 default:
888 OSL_ENSURE(false, "Unexpected pixel format");
889 // FALLTHROUGH intended
890 case IColorBuffer::FMT_R8G8B8:
891 return 3L;
892 case IColorBuffer::FMT_A8R8G8B8:
893 return 4L;
898 //////////////////////////////////////////////////////////////////////////////////
899 // Image::drawLinePolyPolygon
900 //////////////////////////////////////////////////////////////////////////////////
902 template<class pixel_format>
903 void Image::drawLinePolyPolygonImpl( const ::basegfx::B2DPolyPolygon& rPolyPolygon,
904 double fStrokeWidth,
905 const rendering::ViewState& viewState,
906 const rendering::RenderState& renderState )
908 ::basegfx::B2DPolyPolygon aPolyPolygon( rPolyPolygon );
909 ARGB aRenderColor;
911 setupPolyPolygon( aPolyPolygon, false, aRenderColor, viewState, renderState );
913 if( !aPolyPolygon.count() )
914 return;
916 // Class template pixel_formats_rgb24 has full knowledge about this
917 // particular pixel format in memory. The only template parameter
918 // can be order_rgb24 or order_bgr24 that determines the order of color channels.
919 //typedef agg::pixfmt_rgba32 pixel_format;
920 pixel_format pixf(maRenderingBuffer);
922 // There are two basic renderers with almost the same functionality:
923 // renderer_base and renderer_mclip. The first one is used most often
924 // and it performs low level clipping.
925 // This simply adds clipping to the graphics buffer, the clip rect
926 // will be initialized to the area of the framebuffer.
927 typedef agg::renderer_base<pixel_format> renderer_base;
928 agg::renderer_base<pixel_format> renb(pixf);
930 // To draw Anti-Aliased primitives one shoud *rasterize* them first.
931 // The primary rasterization technique in AGG is scanline based.
932 // That is, a polygon is converted into a number of horizontal
933 // scanlines and then the scanlines are being rendered one by one.
934 // To transfer information from a rasterizer to the scanline renderer
935 // there scanline containers are used. A scanline consists of a
936 // number of horizontal, non-intersecting spans. All spans must be ordered by X.
937 // --> *packed* scanline container
938 agg::scanline_p8 sl;
940 typedef agg::renderer_outline_aa<renderer_base> renderer_type;
941 typedef agg::rasterizer_outline_aa<renderer_type> rasterizer_type;
942 agg::line_profile_aa profile;
943 profile.width(fStrokeWidth);
944 renderer_type ren(renb, profile);
945 rasterizer_type ras(ren);
947 const agg::rgba8 fillcolor(aRenderColor.Color.r,
948 aRenderColor.Color.g,
949 aRenderColor.Color.b,
950 aRenderColor.Color.a);
951 ren.color(fillcolor);
953 agg::path_storage path;
954 agg::conv_curve<agg::path_storage> curve(path);
956 for(sal_uInt32 nPolygon=0; nPolygon<aPolyPolygon.count(); ++nPolygon)
958 const basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(nPolygon));
959 const sal_uInt32 nPointCount(aPolygon.count());
961 if(nPointCount)
963 if(aPolygon.areControlPointsUsed())
965 // prepare edge-based loop
966 basegfx::B2DPoint aCurrentPoint(aPolygon.getB2DPoint(0));
967 const sal_uInt32 nEdgeCount(aPolygon.isClosed() ? nPointCount - 1 : nPointCount);
969 // first vertex
970 path.move_to(aCurrentPoint.getX(), aCurrentPoint.getY());
972 for(sal_uInt32 a(0); a < nEdgeCount; a++)
974 // access next point
975 const sal_uInt32 nNextIndex((a + 1) % nPointCount);
976 const basegfx::B2DPoint aNextPoint(aPolygon.getB2DPoint(nNextIndex));
978 // get control points
979 const basegfx::B2DPoint aControlNext(aPolygon.getNextControlPoint(a));
980 const basegfx::B2DPoint aControlPrev(aPolygon.getPrevControlPoint(nNextIndex));
982 // specify first cp, second cp, next vertex
983 path.curve4(
984 aControlNext.getX(), aControlNext.getY(),
985 aControlPrev.getX(), aControlPrev.getY(),
986 aNextPoint.getX(), aNextPoint.getY());
988 // prepare next step
989 aCurrentPoint = aNextPoint;
992 else
994 const basegfx::B2DPoint aStartPoint(aPolygon.getB2DPoint(0));
995 ras.move_to_d(aStartPoint.getX(), aStartPoint.getY());
997 for(sal_uInt32 a(1); a < nPointCount; a++)
999 const basegfx::B2DPoint aVertexPoint(aPolygon.getB2DPoint(a));
1000 ras.line_to_d(aVertexPoint.getX(), aVertexPoint.getY());
1003 ras.render(aPolygon.isClosed());
1008 ras.add_path(curve);
1009 ras.render(false);
1012 //////////////////////////////////////////////////////////////////////////////////
1013 // Image::drawLinePolyPolygon
1014 //////////////////////////////////////////////////////////////////////////////////
1016 void Image::drawLinePolyPolygon( const ::basegfx::B2DPolyPolygon& rPoly,
1017 double fStrokeWidth,
1018 const rendering::ViewState& viewState,
1019 const rendering::RenderState& renderState )
1021 switch(maDesc.eFormat)
1023 case FMT_R8G8B8:
1024 drawLinePolyPolygonImpl<agg::pixfmt_rgb24>(rPoly,fStrokeWidth,viewState,renderState);
1025 break;
1026 case FMT_A8R8G8B8:
1027 drawLinePolyPolygonImpl<agg::pixfmt_rgba32>(rPoly,fStrokeWidth,viewState,renderState);
1028 break;
1029 default:
1030 OSL_ENSURE(false, "Unexpected pixel format");
1031 break;
1035 //////////////////////////////////////////////////////////////////////////////////
1036 // Image::implDrawBitmap
1037 //////////////////////////////////////////////////////////////////////////////////
1039 /** internal utility function to draw one image into another one.
1040 the source image will be drawn with respect to the given
1041 transform and clip settings.
1043 ImageCachedPrimitiveSharedPtr Image::implDrawBitmap(
1044 const Image& rBitmap,
1045 const rendering::ViewState& viewState,
1046 const rendering::RenderState& renderState )
1048 ::basegfx::B2DPolyPolygon aPoly(
1049 ::basegfx::tools::createPolygonFromRect(
1050 ::basegfx::B2DRange(0.0, 0.0,
1051 rBitmap.maDesc.nWidth,
1052 rBitmap.maDesc.nHeight ) ) );
1053 ARGB aFillColor;
1055 setupPolyPolygon( aPoly, true, aFillColor, viewState, renderState );
1057 if( !aPoly.count() )
1058 return ImageCachedPrimitiveSharedPtr();
1060 ::basegfx::B2DHomMatrix aViewTransform;
1061 ::basegfx::B2DHomMatrix aRenderTransform;
1062 ::basegfx::B2DHomMatrix aTextureTransform;
1064 ::basegfx::unotools::homMatrixFromAffineMatrix(aRenderTransform,
1065 renderState.AffineTransform);
1066 ::basegfx::unotools::homMatrixFromAffineMatrix(aViewTransform,
1067 viewState.AffineTransform);
1068 aTextureTransform *= aRenderTransform;
1070 // TODO(F2): Fill in texture
1071 rendering::Texture aTexture;
1073 return fillTexturedPolyPolygon( rBitmap,
1074 aPoly,
1075 aTextureTransform,
1076 aViewTransform,
1077 aTexture );
1080 //////////////////////////////////////////////////////////////////////////////////
1081 // cachedPrimitiveFTPP [cachedPrimitive for [F]ill[T]extured[P]oly[P]olygon]
1082 //////////////////////////////////////////////////////////////////////////////////
1084 #if AGG_VERSION >= 2400
1085 template<class pixel_format_dst,class span_gen_type>
1086 #else
1087 template<class pixel_format,class span_gen_type>
1088 #endif
1089 class cachedPrimitiveFTPP : public ImageCachedPrimitive
1091 public:
1093 cachedPrimitiveFTPP( const ::basegfx::B2DHomMatrix &rTransform,
1094 const ::basegfx::B2DHomMatrix &rViewTransform,
1095 agg::rendering_buffer &dst,
1096 const agg::rendering_buffer& src ) :
1097 aTransform(rTransform),
1098 inter(tm),
1099 filter(filter_kernel),
1100 #if AGG_VERSION >= 2400
1101 pixs(const_cast<agg::rendering_buffer&>(src)),
1102 source(pixs),
1103 sg(source,inter,filter),
1104 pixd(dst),
1105 rb(pixd),
1106 ren(rb,sa,sg)
1107 #else
1108 sg(sa,src,inter,filter),
1109 pixf(dst),
1110 rb(pixf),
1111 ren(rb,sg)
1112 #endif
1114 ::basegfx::B2DHomMatrix aFinalTransform(aTransform);
1115 aFinalTransform *= rViewTransform;
1116 tm = transAffineFromB2DHomMatrix(aFinalTransform);
1117 tm.invert();
1120 virtual void setImage( const ::boost::shared_ptr< class Image >& rTargetImage )
1122 pImage=rTargetImage;
1125 virtual sal_Int8 redraw( const ::com::sun::star::rendering::ViewState& aState ) const
1127 ::basegfx::B2DHomMatrix aViewTransform;
1128 ::basegfx::unotools::homMatrixFromAffineMatrix(aViewTransform,aState.AffineTransform);
1129 ::basegfx::B2DHomMatrix aFinalTransform(aTransform);
1130 aFinalTransform *= aViewTransform;
1131 tm = transAffineFromB2DHomMatrix(aFinalTransform);
1132 tm.invert();
1133 redraw();
1134 return ::com::sun::star::rendering::RepaintResult::REDRAWN;
1137 inline void redraw() const { agg::render_scanlines(ras, sl, ren); }
1139 mutable agg::rasterizer_scanline_aa<> ras;
1141 private:
1143 typedef agg::span_interpolator_linear<> interpolator_type;
1144 #if AGG_VERSION >= 2400
1145 typedef agg::renderer_base<pixel_format_dst> renderer_base;
1146 typedef agg::span_allocator< typename span_gen_type::color_type > span_alloc_type;
1147 typedef agg::renderer_scanline_aa<renderer_base, span_alloc_type, span_gen_type> renderer_type;
1148 typedef typename span_gen_type::source_type source_type;
1149 typedef typename span_gen_type::source_type::pixfmt_type pixel_format_src;
1150 #else
1151 typedef agg::renderer_base<pixel_format> renderer_base;
1152 typedef agg::renderer_scanline_aa<renderer_base, span_gen_type> renderer_type;
1153 #endif
1155 ::basegfx::B2DHomMatrix aTransform;
1156 interpolator_type inter;
1157 agg::image_filter_bilinear filter_kernel;
1158 agg::image_filter_lut filter;
1159 #if AGG_VERSION >= 2400
1160 span_alloc_type sa;
1161 pixel_format_src pixs;
1162 source_type source;
1163 #else
1164 agg::span_allocator< typename span_gen_type::color_type > sa;
1165 #endif
1166 span_gen_type sg;
1167 #if AGG_VERSION >= 2400
1168 pixel_format_dst pixd;
1169 #else
1170 pixel_format pixf;
1171 #endif
1172 renderer_base rb;
1173 mutable renderer_type ren;
1174 mutable agg::scanline_p8 sl;
1175 mutable agg::trans_affine tm;
1176 ImageSharedPtr pImage;
1179 //////////////////////////////////////////////////////////////////////////////////
1180 // Image::fillTexturedPolyPolygon
1181 //////////////////////////////////////////////////////////////////////////////////
1183 template<class pixel_format,class span_gen_type>
1184 ImageCachedPrimitiveSharedPtr Image::fillTexturedPolyPolygonImpl(
1185 const Image& rTexture,
1186 const ::basegfx::B2DPolyPolygon& rPolyPolygon,
1187 const ::basegfx::B2DHomMatrix& rOverallTransform,
1188 const ::basegfx::B2DHomMatrix& rViewTransform,
1189 const rendering::Texture& )
1191 // calculate final overall transform.
1192 ::basegfx::B2DHomMatrix aOverallTransform(rOverallTransform);
1193 aOverallTransform *= rViewTransform;
1195 // instead of always using the full-blown solution we
1196 // first check to see if this is a simple rectangular
1197 // 1-to-1 copy from source to destination image.
1198 ::basegfx::B2DTuple aTranslate(aOverallTransform.get(0,2),aOverallTransform.get(1,2));
1199 ::basegfx::B2DTuple aSize(rTexture.maDesc.nWidth,rTexture.maDesc.nHeight);
1200 ::basegfx::B2DRange aRange(aTranslate,aTranslate+aSize);
1201 ::basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon);
1202 aPolyPolygon.transform(aOverallTransform);
1203 if(::basegfx::tools::isPolyPolygonEqualRectangle(aPolyPolygon,aRange))
1205 // yes, we can take the shortcut.
1206 // but we need to clip the destination rectangle
1207 // against the boundary of the destination image.
1208 sal_Int32 dwSrcX(0);
1209 sal_Int32 dwSrcY(0);
1210 sal_Int32 dwDstX(static_cast<sal_Int32>(aTranslate.getX()));
1211 sal_Int32 dwDstY(static_cast<sal_Int32>(aTranslate.getY()));
1212 sal_Int32 dwWidth(rTexture.maDesc.nWidth);
1213 sal_Int32 dwHeight(rTexture.maDesc.nHeight);
1215 // prevent fast copy if destination position is not an
1216 // integer coordinate. otherwise we would most probably
1217 // introduce visual glitches while combining this with
1218 // high-accuracy rendering stuff.
1219 if( ::basegfx::fTools::equalZero(aTranslate.getX()-dwDstX) &&
1220 ::basegfx::fTools::equalZero(aTranslate.getY()-dwDstY))
1222 // clip against destination boundary. shrink size if
1223 // necessary, modify destination position if we need to.
1224 if(dwDstX < 0) { dwWidth-=dwDstX; dwSrcX=-dwDstX; dwDstX=0; }
1225 if(dwDstY < 0) { dwHeight-=dwDstY; dwSrcY=-dwDstY; dwDstY=0; }
1226 const sal_Int32 dwRight(dwDstX+dwWidth);
1227 const sal_Int32 dwBottom(dwDstY+dwHeight);
1228 if(dwRight > dwWidth)
1229 dwWidth -= dwRight-dwWidth;
1230 if(dwBottom > dwHeight)
1231 dwHeight -= dwBottom-dwHeight;
1233 // calculate source buffer
1234 const Description &srcDesc = rTexture.maDesc;
1235 const sal_uInt32 dwSrcBytesPerPixel(getBytesPerPixel(srcDesc.eFormat));
1236 const sal_uInt32 dwSrcPitch(srcDesc.nWidth*dwSrcBytesPerPixel+srcDesc.nStride);
1237 sal_uInt8 *pSrcBuffer = rTexture.maDesc.pBuffer+(dwSrcPitch*dwSrcX)+(dwSrcBytesPerPixel*dwSrcY);
1239 // calculate destination buffer
1240 const Description &dstDesc = maDesc;
1241 const sal_uInt32 dwDstBytesPerPixel(getBytesPerPixel(dstDesc.eFormat));
1242 const sal_uInt32 dwDstPitch(dstDesc.nWidth*dwDstBytesPerPixel+dstDesc.nStride);
1243 sal_uInt8 *pDstBuffer = maDesc.pBuffer+(dwDstPitch*dwDstY)+(dwDstBytesPerPixel*dwDstX);
1245 // if source and destination format match, we can simply
1246 // copy whole scanlines.
1247 if(srcDesc.eFormat == dstDesc.eFormat)
1249 const sal_Size dwNumBytesPerScanline(dwSrcBytesPerPixel*dwWidth);
1250 for(sal_Int32 y=0; y<dwHeight; ++y)
1252 rtl_copyMemory(pDstBuffer,pSrcBuffer,dwNumBytesPerScanline);
1253 pSrcBuffer += dwSrcPitch;
1254 pDstBuffer += dwDstPitch;
1257 else
1259 // otherwise [formats do not match], we need to copy
1260 // each pixel one by one and convert from source to destination format.
1261 if(srcDesc.eFormat == FMT_A8R8G8B8 && dstDesc.eFormat == FMT_R8G8B8)
1263 for(sal_Int32 y=0; y<dwHeight; ++y)
1265 sal_uInt8 *pSrc=pSrcBuffer;
1266 sal_uInt8 *pDst=pDstBuffer;
1267 for(sal_Int32 x=0; x<dwWidth; ++x)
1269 BYTE r(*pSrc++);
1270 BYTE g(*pSrc++);
1271 BYTE b(*pSrc++);
1272 BYTE Alpha(*pSrc++);
1273 BYTE OneMinusAlpha(0xFF-Alpha);
1274 *pDst=(((r*Alpha)+((*pDst)*OneMinusAlpha))/0xFF);
1275 ++pDst;
1276 *pDst=(((g*Alpha)+((*pDst)*OneMinusAlpha))/0xFF);
1277 ++pDst;
1278 *pDst=(((b*Alpha)+((*pDst)*OneMinusAlpha))/0xFF);
1279 ++pDst;
1281 pSrcBuffer += dwSrcPitch;
1282 pDstBuffer += dwDstPitch;
1285 else if(srcDesc.eFormat == FMT_R8G8B8 && dstDesc.eFormat == FMT_A8R8G8B8)
1287 for(sal_Int32 y=0; y<dwHeight; ++y)
1289 sal_uInt8 *pSrc=pSrcBuffer;
1290 sal_uInt8 *pDst=pDstBuffer;
1291 for(sal_Int32 x=0; x<dwWidth; ++x)
1293 BYTE r(*pSrc++);
1294 BYTE g(*pSrc++);
1295 BYTE b(*pSrc++);
1296 *pDst++=r;
1297 *pDst++=g;
1298 *pDst++=b;
1299 *pDst++=0xFF;
1301 pSrcBuffer += dwSrcPitch;
1302 pDstBuffer += dwDstPitch;
1307 return ImageCachedPrimitiveSharedPtr();
1311 typedef cachedPrimitiveFTPP<pixel_format,span_gen_type> cachedPrimitive_t;
1312 cachedPrimitive_t *pPrimitive = new cachedPrimitive_t( rOverallTransform,
1313 rViewTransform,
1314 maRenderingBuffer,
1315 rTexture.maRenderingBuffer);
1317 agg::path_storage path;
1318 agg::conv_curve<agg::path_storage> curve(path);
1320 for(sal_uInt32 nPolygon(0); nPolygon < rPolyPolygon.count(); nPolygon++)
1322 const basegfx::B2DPolygon aPolygon(rPolyPolygon.getB2DPolygon(nPolygon));
1323 const sal_uInt32 nPointCount(aPolygon.count());
1325 if(nPointCount)
1327 if(aPolygon.areControlPointsUsed())
1329 // prepare edge-based loop
1330 basegfx::B2DPoint aCurrentPoint(aPolygon.getB2DPoint(0));
1331 const sal_uInt32 nEdgeCount(aPolygon.isClosed() ? nPointCount - 1 : nPointCount);
1333 // first vertex
1334 path.move_to(aCurrentPoint.getX(), aCurrentPoint.getY());
1336 for(sal_uInt32 a(0); a < nEdgeCount; a++)
1338 // access next point
1339 const sal_uInt32 nNextIndex((a + 1) % nPointCount);
1340 const basegfx::B2DPoint aNextPoint(aPolygon.getB2DPoint(nNextIndex));
1342 // get control points
1343 const basegfx::B2DPoint aControlNext(aPolygon.getNextControlPoint(a));
1344 const basegfx::B2DPoint aControlPrev(aPolygon.getPrevControlPoint(nNextIndex));
1346 // specify first cp, second cp, next vertex
1347 path.curve4(
1348 aControlNext.getX(), aControlNext.getY(),
1349 aControlPrev.getX(), aControlPrev.getY(),
1350 aNextPoint.getX(), aNextPoint.getY());
1352 // prepare next step
1353 aCurrentPoint = aNextPoint;
1356 else
1358 const basegfx::B2DPoint aPoint(aPolygon.getB2DPoint(0));
1359 pPrimitive->ras.move_to_d(aPoint.getX(), aPoint.getY());
1361 for(sal_uInt32 a(1); a < nPointCount; a++)
1363 const basegfx::B2DPoint aVertexPoint(aPolygon.getB2DPoint(a));
1364 pPrimitive->ras.line_to_d(aVertexPoint.getX(), aVertexPoint.getY());
1367 if(aPolygon.isClosed())
1369 pPrimitive->ras.close_polygon();
1375 pPrimitive->ras.add_path(curve);
1376 pPrimitive->redraw();
1378 return ImageCachedPrimitiveSharedPtr(pPrimitive);
1381 //////////////////////////////////////////////////////////////////////////////////
1382 // Image::fillTexturedPolyPolygon
1383 //////////////////////////////////////////////////////////////////////////////////
1385 ImageCachedPrimitiveSharedPtr Image::fillTexturedPolyPolygon(
1386 const Image& rTexture,
1387 const ::basegfx::B2DPolyPolygon& rPolyPolygon,
1388 const ::basegfx::B2DHomMatrix& rOverallTransform,
1389 const ::basegfx::B2DHomMatrix& rViewTransform,
1390 const rendering::Texture& texture )
1392 typedef agg::wrap_mode_repeat wrap_x_type;
1393 typedef agg::wrap_mode_repeat wrap_y_type;
1394 typedef agg::pixfmt_rgb24 pixfmt_rgb24;
1395 typedef agg::pixfmt_rgba32 pixfmt_rgba32;
1396 #if AGG_VERSION >= 2400
1397 typedef agg::image_accessor_wrap< pixfmt_rgba32, wrap_x_type, wrap_y_type > img_source_type_rgba;
1398 typedef agg::image_accessor_wrap< pixfmt_rgb24, wrap_x_type, wrap_y_type > img_source_type_rgb;
1400 typedef agg::span_image_resample_rgba_affine< img_source_type_rgba > span_gen_type_rgba;
1401 typedef agg::span_image_resample_rgb_affine< img_source_type_rgb > span_gen_type_rgb;
1402 #else
1403 typedef agg::span_pattern_resample_rgba_affine< pixfmt_rgba32::color_type,
1404 pixfmt_rgba32::order_type,
1405 wrap_x_type,
1406 wrap_y_type> span_gen_type_rgba;
1407 typedef agg::span_pattern_resample_rgb_affine< pixfmt_rgb24::color_type,
1408 pixfmt_rgb24::order_type,
1409 wrap_x_type,
1410 wrap_y_type> span_gen_type_rgb;
1411 #endif
1413 const Format nDest = maDesc.eFormat;
1414 const Format nSource = rTexture.maDesc.eFormat;
1416 if(nDest == FMT_R8G8B8 && nSource == FMT_R8G8B8)
1418 return fillTexturedPolyPolygonImpl< agg::pixfmt_rgb24,
1419 span_gen_type_rgb >(
1420 rTexture,
1421 rPolyPolygon,
1422 rOverallTransform,
1423 rViewTransform,
1424 texture );
1426 else if(nDest == FMT_R8G8B8 && nSource == FMT_A8R8G8B8)
1428 return fillTexturedPolyPolygonImpl< agg::pixfmt_rgb24,
1429 span_gen_type_rgba >(
1430 rTexture,
1431 rPolyPolygon,
1432 rOverallTransform,
1433 rViewTransform,
1434 texture );
1436 else if(nDest == FMT_A8R8G8B8 && nSource == FMT_R8G8B8)
1438 return fillTexturedPolyPolygonImpl< agg::pixfmt_rgba32,
1439 span_gen_type_rgb >(
1440 rTexture,
1441 rPolyPolygon,
1442 rOverallTransform,
1443 rViewTransform,
1444 texture );
1446 else if(nDest == FMT_A8R8G8B8 && nSource == FMT_A8R8G8B8)
1448 return fillTexturedPolyPolygonImpl< agg::pixfmt_rgba32,
1449 span_gen_type_rgba >(
1450 rTexture,
1451 rPolyPolygon,
1452 rOverallTransform,
1453 rViewTransform,
1454 texture );
1456 else
1458 OSL_ENSURE(false, "Unexpected pixel format");
1461 return ImageCachedPrimitiveSharedPtr();
1464 //////////////////////////////////////////////////////////////////////////////////
1465 // Image::fillGradient
1466 //////////////////////////////////////////////////////////////////////////////////
1468 template<class pixel_format>
1469 void Image::fillGradientImpl( const ParametricPolyPolygon::Values& rValues,
1470 const uno::Sequence< double >& rUnoColor1,
1471 const uno::Sequence< double >& rUnoColor2,
1472 const ::basegfx::B2DPolyPolygon& rPolyPolygon,
1473 const ::basegfx::B2DHomMatrix& rOverallTransform,
1474 const rendering::Texture& )
1476 const ARGB aColor1(0xFFFFFFFF,
1477 rUnoColor1);
1478 const ARGB aColor2(0xFFFFFFFF,
1479 rUnoColor2);
1481 // first of all we need to provide the framebuffer we want to render to.
1482 // the properties of the framebuffer are
1483 // 1) memory & layout [width, height, stride]
1484 // 2) pixelformat
1485 // 3) clipping
1487 // Class template pixel_formats_rgb24 has full knowledge about this
1488 // particular pixel format in memory. The only template parameter
1489 // can be order_rgb24 or order_bgr24 that determines the order of color channels.
1490 pixel_format pixf(maRenderingBuffer);
1492 // There are two basic renderers with almost the same functionality:
1493 // renderer_base and renderer_mclip. The first one is used most often
1494 // and it performs low level clipping.
1495 // This simply adds clipping to the graphics buffer, the clip rect
1496 // will be initialized to the area of the framebuffer.
1497 typedef agg::renderer_base<pixel_format> renderer_base;
1498 renderer_base rb(pixf);
1500 // bounding rectangle of untransformed polypolygon
1501 const ::basegfx::B2DRange& rBounds(::basegfx::tools::getRange(rPolyPolygon));
1503 // the color generator produces a specific color from
1504 // some given interpolation value.
1505 // number of steps for color interpolation
1506 typedef typename pixel_format::color_type color_type;
1507 color_type color1(agg::rgba8(aColor1.Color.r,
1508 aColor1.Color.g,
1509 aColor1.Color.b,
1510 255));
1511 color_type color2(agg::rgba8(aColor2.Color.r,
1512 aColor2.Color.g,
1513 aColor2.Color.b,
1514 255));
1515 typedef color_generator_adaptor<color_type> color_generator_type;
1516 unsigned int dwNumSteps = static_cast<unsigned int>(rBounds.getWidth());
1517 color_generator_type colors(color1,color2,dwNumSteps);
1518 colors.set_linear(rValues.meType != ParametricPolyPolygon::GRADIENT_AXIAL);
1520 // color = f(x,y)
1521 gradient_polymorphic_wrapper<agg::gradient_x> gf_x;
1522 gradient_polymorphic_wrapper<agg::gradient_radial> gf_radial;
1523 gradient_polymorphic_wrapper<gradient_rect> gf_rectangular;
1524 gf_rectangular.m_gradient.width = static_cast<int>(rBounds.getWidth())<<4;
1525 gf_rectangular.m_gradient.height = static_cast<int>(rBounds.getHeight())<<4;
1526 const gradient_polymorphic_wrapper_base *gf[] = { &gf_x, // GRADIENT_LINEAR
1527 &gf_x, // GRADIENT_AXIAL
1528 &gf_radial, // GRADIENT_ELLIPTICAL
1529 &gf_rectangular // GRADIENT_RECTANGULAR
1532 // how do texture coordinates change when the pixel coordinate change?
1533 typedef agg::span_interpolator_linear<> interpolator_type;
1534 agg::trans_affine tm;
1535 tm *= agg::trans_affine_scaling(1.0f/rBounds.getWidth(),
1536 1.0f/rBounds.getHeight());
1537 if(rValues.meType == ParametricPolyPolygon::GRADIENT_ELLIPTICAL ||
1538 rValues.meType == ParametricPolyPolygon::GRADIENT_RECTANGULAR)
1540 //tm *= trans_affine_scaling(mnAspectRatio,+1.0f);
1541 //const double fAspect = aBounds.getWidth()/aBounds.getHeight();
1542 //tm *= trans_affine_scaling(+0.5f,+0.5f*(1.0f/fAspect));
1543 //tm *= trans_affine_translation(+0.5f,+0.5f);
1544 tm *= agg::trans_affine_scaling(+0.5f,+0.5f);
1545 tm *= agg::trans_affine_translation(+0.5f,+0.5f);
1547 tm *= transAffineFromB2DHomMatrix(rOverallTransform);
1548 tm.invert();
1549 interpolator_type inter(tm);
1551 // spanline allocators reserve memory for the color values
1552 // filled up by the spanline generators.
1553 typedef agg::span_allocator<color_type> gradient_span_alloc;
1554 gradient_span_alloc span_alloc;
1556 // scanline generators create the actual color values for
1557 // some specific coordinate range of a scanline.
1558 typedef agg::span_gradient<color_type,
1559 interpolator_type,
1560 gradient_polymorphic_wrapper_base,
1561 color_generator_type > gradient_span_gen;
1562 #if AGG_VERSION >= 2400
1563 gradient_span_gen span_gen(inter,
1564 *gf[rValues.meType],
1565 colors,
1567 dwNumSteps);
1568 #else
1569 gradient_span_gen span_gen(span_alloc,
1570 inter,
1571 *gf[rValues.meType],
1572 colors,
1574 dwNumSteps);
1575 #endif
1577 // To draw Anti-Aliased primitives one shoud *rasterize* them first.
1578 // The primary rasterization technique in AGG is scanline based.
1579 // That is, a polygon is converted into a number of horizontal
1580 // scanlines and then the scanlines are being rendered one by one.
1581 // To transfer information from a rasterizer to the scanline renderer
1582 // there scanline containers are used. A scanline consists of a
1583 // number of horizontal, non-intersecting spans. All spans must be ordered by X.
1584 // --> packed scanline container
1585 agg::scanline_p8 sl;
1587 // antialiased scanline renderer with pattern filling capability
1588 // [in contrast to solid renderers, that is]
1589 // the instance of this particular renderer combines the
1590 // renderbuffer [i.e. destination] and the spanline generator [i.e. source]
1591 #if AGG_VERSION >= 2400
1592 typedef agg::renderer_scanline_aa<renderer_base, gradient_span_alloc, gradient_span_gen> renderer_gradient;
1593 renderer_gradient r1(rb, span_alloc, span_gen);
1594 #else
1595 typedef agg::renderer_scanline_aa<renderer_base, gradient_span_gen> renderer_gradient;
1596 renderer_gradient r1(rb, span_gen);
1597 #endif
1599 // instantiate the rasterizer and feed the incoming polypolygon.
1600 agg::rasterizer_scanline_aa<> ras;
1601 agg::path_storage path;
1602 agg::conv_curve<agg::path_storage> curve(path);
1604 for(sal_uInt32 nPolygon(0); nPolygon < rPolyPolygon.count(); nPolygon++)
1606 const basegfx::B2DPolygon aPolygon(rPolyPolygon.getB2DPolygon(nPolygon));
1607 const sal_uInt32 nPointCount(aPolygon.count());
1609 if(nPointCount)
1611 if(aPolygon.areControlPointsUsed())
1613 // prepare edge-based loop
1614 basegfx::B2DPoint aCurrentPoint(aPolygon.getB2DPoint(0));
1615 const sal_uInt32 nEdgeCount(aPolygon.isClosed() ? nPointCount - 1 : nPointCount);
1617 // first vertex
1618 path.move_to(aCurrentPoint.getX(), aCurrentPoint.getY());
1620 for(sal_uInt32 a(0); a < nEdgeCount; a++)
1622 // access next point
1623 const sal_uInt32 nNextIndex((a + 1) % nPointCount);
1624 const basegfx::B2DPoint aNextPoint(aPolygon.getB2DPoint(nNextIndex));
1626 // get control points
1627 const basegfx::B2DPoint aControlNext(aPolygon.getNextControlPoint(a));
1628 const basegfx::B2DPoint aControlPrev(aPolygon.getPrevControlPoint(nNextIndex));
1630 // specify first cp, second cp, next vertex
1631 path.curve4(
1632 aControlNext.getX(), aControlNext.getY(),
1633 aControlPrev.getX(), aControlPrev.getY(),
1634 aNextPoint.getX(), aNextPoint.getY());
1636 // prepare next step
1637 aCurrentPoint = aNextPoint;
1640 else
1642 const basegfx::B2DPoint aPoint(aPolygon.getB2DPoint(0));
1643 ras.move_to_d(aPoint.getX(), aPoint.getY());
1645 for(sal_uInt32 a(1); a < nPointCount; a++)
1647 const basegfx::B2DPoint aVertexPoint(aPolygon.getB2DPoint(a));
1648 ras.line_to_d(aVertexPoint.getX(), aVertexPoint.getY());
1651 if(aPolygon.isClosed())
1653 ras.close_polygon();
1659 // everything is up and running, go...
1660 ras.add_path(curve);
1661 render_scanlines(ras,sl,r1);
1664 //////////////////////////////////////////////////////////////////////////////////
1665 // Image::fillGradient
1666 //////////////////////////////////////////////////////////////////////////////////
1668 void Image::fillGradient( const ParametricPolyPolygon::Values& rValues,
1669 const uno::Sequence< double >& rUnoColor1,
1670 const uno::Sequence< double >& rUnoColor2,
1671 const ::basegfx::B2DPolyPolygon& rPolyPolygon,
1672 const ::basegfx::B2DHomMatrix& rOverallTransform,
1673 const rendering::Texture& texture )
1675 switch(maDesc.eFormat)
1677 case FMT_R8G8B8:
1678 fillGradientImpl<agg::pixfmt_rgb24>(rValues,rUnoColor1,rUnoColor2,rPolyPolygon,rOverallTransform,texture);
1679 break;
1680 case FMT_A8R8G8B8:
1681 fillGradientImpl<agg::pixfmt_rgba32>(rValues,rUnoColor1,rUnoColor2,rPolyPolygon,rOverallTransform,texture);
1682 break;
1683 default:
1684 OSL_ENSURE(false, "Unexpected pixel format");
1685 break;
1689 //////////////////////////////////////////////////////////////////////////////////
1690 // Image::fromVCLBitmap
1691 //////////////////////////////////////////////////////////////////////////////////
1693 bool Image::fromVCLBitmap( ::BitmapEx& rBmpEx )
1695 const ::Size aBmpSize( rBmpEx.GetSizePixel() );
1696 Image::Description desc;
1697 desc.eFormat = rBmpEx.IsTransparent() ? FMT_A8R8G8B8 : FMT_R8G8B8;
1698 desc.nWidth = aBmpSize.Width();
1699 desc.nHeight = aBmpSize.Height();
1700 desc.nStride = 0;
1701 const sal_uInt32 nPitch(desc.nWidth*getBytesPerPixel(desc.eFormat)+desc.nStride);
1702 desc.pBuffer = new sal_uInt8 [nPitch*desc.nHeight];
1703 maDesc = desc;
1704 mbBufferHasUserOwnership = false;
1705 maRenderingBuffer.attach(static_cast<agg::int8u *>(desc.pBuffer),
1706 desc.nWidth,
1707 desc.nHeight,
1708 nPitch);
1709 RawABGRBitmap aBmpData;
1710 aBmpData.mnWidth = aBmpSize.Width();
1711 aBmpData.mnHeight = aBmpSize.Height();
1712 aBmpData.mpBitmapData = static_cast<sal_uInt8 *>(desc.pBuffer);
1713 vclBitmapEx2Raw(rBmpEx,aBmpData);
1715 return true;
1718 //////////////////////////////////////////////////////////////////////////////////
1719 // Image::Image
1720 //////////////////////////////////////////////////////////////////////////////////
1722 Image::Image( const Description& rDesc ) :
1723 maDesc( rDesc ),
1724 maRenderingBuffer(),
1725 mbBufferHasUserOwnership( rDesc.pBuffer != NULL )
1727 #if defined(PROFILER)
1728 for(int i=0; i<TIMER_MAX; ++i)
1729 maElapsedTime[i]=0.0;
1730 #endif
1732 // allocate own buffer memory, if not provided
1733 sal_uInt8* pBuffer = maDesc.pBuffer;
1734 const sal_uInt32 nWidth(maDesc.nWidth);
1735 const sal_uInt32 nHeight(maDesc.nHeight);
1736 const sal_uInt32 nStride(maDesc.nStride);
1737 const sal_uInt32 nPitch(nWidth*getBytesPerPixel(maDesc.eFormat)
1738 + nStride);
1740 if( !pBuffer )
1741 pBuffer = new sal_uInt8 [nPitch*nHeight];
1743 maDesc.pBuffer = pBuffer;
1745 // attach graphics buffer
1746 maRenderingBuffer.attach(
1747 static_cast<agg::int8u *>(pBuffer),
1748 nWidth,
1749 nHeight,
1750 nPitch );
1753 //////////////////////////////////////////////////////////////////////////////////
1754 // Image::Image
1755 //////////////////////////////////////////////////////////////////////////////////
1757 Image::Image( const uno::Reference< rendering::XBitmap >& xBitmap ) :
1758 maDesc(),
1759 maRenderingBuffer(),
1760 mbBufferHasUserOwnership( false )
1762 #if defined(PROFILER)
1763 for(int i=0; i<TIMER_MAX; ++i)
1764 maElapsedTime[i]=0.0;
1765 #endif
1767 // TODO(F1): Add support for floating point bitmap formats
1768 uno::Reference<rendering::XIntegerReadOnlyBitmap> xIntBmp(xBitmap,
1769 uno::UNO_QUERY_THROW);
1770 ::BitmapEx aBmpEx = ::vcl::unotools::bitmapExFromXBitmap(xIntBmp);
1771 if( !!aBmpEx )
1772 fromVCLBitmap(aBmpEx);
1774 // TODO(F2): Fallback to XIntegerBitmap interface for import
1775 OSL_ENSURE(false,
1776 "Image::Image(): Cannot retrieve bitmap data!" );
1779 //////////////////////////////////////////////////////////////////////////////////
1780 // Image::~Image
1781 //////////////////////////////////////////////////////////////////////////////////
1783 Image::~Image()
1785 #if defined(PROFILER)
1787 double aAccumulatedTime(0.0);
1788 for(int i=0; i<TIMER_MAX; ++i)
1789 aAccumulatedTime += maElapsedTime[i];
1791 OSL_TRACE("Image %d - %d %d %d %d %d\n",(int)(aAccumulatedTime*1000.0),
1792 (int)(maElapsedTime[TIMER_FILLTEXTUREDPOLYPOLYGON]*1000.0),
1793 (int)(maElapsedTime[TIMER_FILLB2DPOLYPOLYGON]*1000.0),
1794 (int)(maElapsedTime[TIMER_DRAWPOLYPOLYGON]*1000.0),
1795 (int)(maElapsedTime[TIMER_FILLPOLYPOLYGON]*1000.0),
1796 (int)(maElapsedTime[TIMER_DRAWBITMAP]*1000.0));
1798 #endif
1800 if( !mbBufferHasUserOwnership )
1801 delete [] maDesc.pBuffer;
1804 //////////////////////////////////////////////////////////////////////////////////
1805 // Image::clear
1806 //////////////////////////////////////////////////////////////////////////////////
1808 template<class pixel_format>
1809 void Image::clearImpl( sal_uInt8 a,
1810 sal_uInt8 r,
1811 sal_uInt8 g,
1812 sal_uInt8 b )
1814 pixel_format pixf(maRenderingBuffer);
1815 agg::renderer_base<pixel_format> renb(pixf);
1817 renb.clear(agg::rgba8(r,g,b,a));
1820 //////////////////////////////////////////////////////////////////////////////////
1821 // Image::clear
1822 //////////////////////////////////////////////////////////////////////////////////
1824 void Image::clear( sal_uInt8 a,
1825 sal_uInt8 r,
1826 sal_uInt8 g,
1827 sal_uInt8 b )
1829 switch(maDesc.eFormat)
1831 case FMT_R8G8B8:
1832 return clearImpl<agg::pixfmt_rgb24>(a,r,g,b);
1833 case FMT_A8R8G8B8:
1834 return clearImpl<agg::pixfmt_rgba32>(a,r,g,b);
1835 default:
1836 OSL_ENSURE(false, "Unexpected pixel format");
1837 break;
1841 //////////////////////////////////////////////////////////////////////////////////
1842 // Image::fillB2DPolyPolygon
1843 //////////////////////////////////////////////////////////////////////////////////
1845 void Image::fillB2DPolyPolygon(
1846 const ::basegfx::B2DPolyPolygon& rPolyPolygon,
1847 const rendering::ViewState& viewState,
1848 const rendering::RenderState& renderState )
1850 #if defined(PROFILER)
1851 ScopeTimer aTimer(TIMER_FILLB2DPOLYPOLYGON,this);
1852 #endif
1854 switch(maDesc.eFormat)
1856 case FMT_R8G8B8:
1857 fillPolyPolygonImpl<agg::pixfmt_rgb24>(rPolyPolygon,viewState,renderState);
1858 break;
1859 case FMT_A8R8G8B8:
1860 fillPolyPolygonImpl<agg::pixfmt_rgba32>(rPolyPolygon,viewState,renderState);
1861 break;
1862 default:
1863 OSL_ENSURE(false, "Unexpected pixel format");
1864 break;
1868 //////////////////////////////////////////////////////////////////////////////////
1869 // Image::lock
1870 //////////////////////////////////////////////////////////////////////////////////
1872 sal_uInt8* Image::lock() const
1874 return maDesc.pBuffer;
1877 //////////////////////////////////////////////////////////////////////////////////
1878 // Image::unlock
1879 //////////////////////////////////////////////////////////////////////////////////
1881 void Image::unlock() const
1885 //////////////////////////////////////////////////////////////////////////////////
1886 // Image::getWidth
1887 //////////////////////////////////////////////////////////////////////////////////
1889 sal_uInt32 Image::getWidth() const
1891 return maDesc.nWidth;
1894 //////////////////////////////////////////////////////////////////////////////////
1895 // Image::getHeight
1896 //////////////////////////////////////////////////////////////////////////////////
1898 sal_uInt32 Image::getHeight() const
1900 return maDesc.nHeight;
1903 //////////////////////////////////////////////////////////////////////////////////
1904 // Image::getStride
1905 //////////////////////////////////////////////////////////////////////////////////
1907 sal_uInt32 Image::getStride() const
1909 return maDesc.nWidth*getBytesPerPixel(maDesc.eFormat)+maDesc.nStride;
1912 //////////////////////////////////////////////////////////////////////////////////
1913 // Image::getFormat
1914 //////////////////////////////////////////////////////////////////////////////////
1916 IColorBuffer::Format Image::getFormat() const
1918 return maDesc.eFormat;
1921 //////////////////////////////////////////////////////////////////////////////////
1922 // Image::drawPoint
1923 //////////////////////////////////////////////////////////////////////////////////
1925 void Image::drawPoint( const geometry::RealPoint2D& /*aPoint*/,
1926 const rendering::ViewState& /*viewState*/,
1927 const rendering::RenderState& /*renderState*/ )
1929 OSL_ENSURE(false,
1930 "Image::drawPoint(): NYI" );
1933 //////////////////////////////////////////////////////////////////////////////////
1934 // Image::drawLine
1935 //////////////////////////////////////////////////////////////////////////////////
1937 void Image::drawLine( const geometry::RealPoint2D& aStartPoint,
1938 const geometry::RealPoint2D& aEndPoint,
1939 const rendering::ViewState& viewState,
1940 const rendering::RenderState& renderState )
1942 ::basegfx::B2DPolygon aLinePoly;
1943 aLinePoly.append(
1944 ::basegfx::unotools::b2DPointFromRealPoint2D( aStartPoint ) );
1945 aLinePoly.append(
1946 ::basegfx::unotools::b2DPointFromRealPoint2D( aEndPoint ) );
1948 drawLinePolyPolygon( ::basegfx::B2DPolyPolygon( aLinePoly ),
1949 1.0,
1950 viewState,
1951 renderState );
1954 //////////////////////////////////////////////////////////////////////////////////
1955 // Image::drawBezier
1956 //////////////////////////////////////////////////////////////////////////////////
1958 void Image::drawBezier( const geometry::RealBezierSegment2D& aBezierSegment,
1959 const geometry::RealPoint2D& aEndPoint,
1960 const rendering::ViewState& viewState,
1961 const rendering::RenderState& renderState )
1963 basegfx::B2DPolygon aBezierPoly;
1965 aBezierPoly.append(basegfx::B2DPoint(aBezierSegment.Px, aBezierSegment.Py));
1966 aBezierPoly.appendBezierSegment(
1967 basegfx::B2DPoint(aBezierSegment.C1x, aBezierSegment.C1y),
1968 basegfx::B2DPoint(aBezierSegment.C2x, aBezierSegment.C2y),
1969 basegfx::unotools::b2DPointFromRealPoint2D(aEndPoint));
1971 drawLinePolyPolygon( ::basegfx::B2DPolyPolygon( aBezierPoly ),
1972 1.0,
1973 viewState,
1974 renderState );
1977 //////////////////////////////////////////////////////////////////////////////////
1978 // Image::drawPolyPolygon
1979 //////////////////////////////////////////////////////////////////////////////////
1981 ImageCachedPrimitiveSharedPtr Image::drawPolyPolygon(
1982 const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
1983 const rendering::ViewState& viewState,
1984 const rendering::RenderState& renderState )
1986 #if defined(PROFILER)
1987 ScopeTimer aTimer(TIMER_DRAWPOLYPOLYGON,this);
1988 #endif
1990 if( !xPolyPolygon.is() )
1991 return ImageCachedPrimitiveSharedPtr();
1993 drawLinePolyPolygon( ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( xPolyPolygon ),
1994 1.0,
1995 viewState,
1996 renderState );
1998 // TODO(F2): Implement sensible ImageCachedPrimitive
1999 return ImageCachedPrimitiveSharedPtr();
2002 //////////////////////////////////////////////////////////////////////////////////
2003 // Image::strokePolyPolygon
2004 //////////////////////////////////////////////////////////////////////////////////
2006 ImageCachedPrimitiveSharedPtr Image::strokePolyPolygon(
2007 const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
2008 const rendering::ViewState& viewState,
2009 const rendering::RenderState& renderState,
2010 const rendering::StrokeAttributes& strokeAttributes )
2012 if( !xPolyPolygon.is() )
2013 return ImageCachedPrimitiveSharedPtr();
2015 drawLinePolyPolygon( ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( xPolyPolygon ),
2016 strokeAttributes.StrokeWidth,
2017 viewState,
2018 renderState );
2020 // TODO(F2): Implement sensible ImageCachedPrimitive
2021 return ImageCachedPrimitiveSharedPtr();
2024 //////////////////////////////////////////////////////////////////////////////////
2025 // Image::strokeTexturedPolyPolygon
2026 //////////////////////////////////////////////////////////////////////////////////
2028 ImageCachedPrimitiveSharedPtr Image::strokeTexturedPolyPolygon(
2029 const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/,
2030 const rendering::ViewState& /*viewState*/,
2031 const rendering::RenderState& /*renderState*/,
2032 const uno::Sequence< rendering::Texture >& /*textures*/,
2033 const ::std::vector< ::boost::shared_ptr<Image> >& /*textureAnnotations*/,
2034 const rendering::StrokeAttributes& /*strokeAttributes*/ )
2036 OSL_ENSURE(false,
2037 "Image::strokeTexturedPolyPolygon(): NYI" );
2039 // TODO(F2): Implement sensible ImageCachedPrimitive
2040 return ImageCachedPrimitiveSharedPtr();
2043 //////////////////////////////////////////////////////////////////////////////////
2044 // Image::strokeTextureMappedPolyPolygon
2045 //////////////////////////////////////////////////////////////////////////////////
2047 ImageCachedPrimitiveSharedPtr Image::strokeTextureMappedPolyPolygon(
2048 const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/,
2049 const rendering::ViewState& /*viewState*/,
2050 const rendering::RenderState& /*renderState*/,
2051 const uno::Sequence< rendering::Texture >& /*textures*/,
2052 const ::std::vector< ::boost::shared_ptr<Image> >& /*textureAnnotations*/,
2053 const uno::Reference< geometry::XMapping2D >& /*xMapping*/,
2054 const rendering::StrokeAttributes& /*strokeAttributes*/ )
2056 OSL_ENSURE(false,
2057 "Image::strokeTextureMappedPolyPolygon(): NYI" );
2059 // TODO(F2): Implement sensible ImageCachedPrimitive
2060 return ImageCachedPrimitiveSharedPtr();
2063 //////////////////////////////////////////////////////////////////////////////////
2064 // Image::fillPolyPolygon
2065 //////////////////////////////////////////////////////////////////////////////////
2067 template<class pixel_format>
2068 ImageCachedPrimitiveSharedPtr Image::fillPolyPolygonImpl(
2069 const ::basegfx::B2DPolyPolygon& rPolyPolygon,
2070 const rendering::ViewState& viewState,
2071 const rendering::RenderState& renderState )
2073 #if defined(PROFILER)
2074 ScopeTimer aTimer(TIMER_FILLPOLYPOLYGON,this);
2075 #endif
2077 ARGB aFillColor;
2079 ::basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon);
2080 setupPolyPolygon( aPolyPolygon, true, aFillColor, viewState, renderState );
2082 if( !aPolyPolygon.count() )
2083 return ImageCachedPrimitiveSharedPtr();
2085 pixel_format pixf(maRenderingBuffer);
2086 agg::renderer_base<pixel_format> renb(pixf);
2088 // Scanline renderer for solid filling.
2089 agg::renderer_scanline_aa_solid<agg::renderer_base<pixel_format> > ren(renb);
2091 // Rasterizer & scanline
2092 agg::rasterizer_scanline_aa<> ras;
2093 agg::scanline_p8 sl;
2095 agg::path_storage path;
2096 agg::conv_curve<agg::path_storage> curve(path);
2098 for(sal_uInt32 nPolygon(0); nPolygon < aPolyPolygon.count(); nPolygon++)
2100 const basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(nPolygon));
2101 const sal_uInt32 nPointCount(aPolygon.count());
2103 if(nPointCount)
2105 if(aPolygon.areControlPointsUsed())
2107 // prepare edge-based loop
2108 basegfx::B2DPoint aCurrentPoint(aPolygon.getB2DPoint(0));
2109 const sal_uInt32 nEdgeCount(aPolygon.isClosed() ? nPointCount - 1 : nPointCount);
2111 // first vertex
2112 path.move_to(aCurrentPoint.getX(), aCurrentPoint.getY());
2114 for(sal_uInt32 a(0); a < nEdgeCount; a++)
2116 // access next point
2117 const sal_uInt32 nNextIndex((a + 1) % nPointCount);
2118 const basegfx::B2DPoint aNextPoint(aPolygon.getB2DPoint(nNextIndex));
2120 // get control points
2121 const basegfx::B2DPoint aControlNext(aPolygon.getNextControlPoint(a));
2122 const basegfx::B2DPoint aControlPrev(aPolygon.getPrevControlPoint(nNextIndex));
2124 // specify first cp, second cp, next vertex
2125 path.curve4(
2126 aControlNext.getX(), aControlNext.getY(),
2127 aControlPrev.getX(), aControlPrev.getY(),
2128 aNextPoint.getX(), aNextPoint.getY());
2130 // prepare next step
2131 aCurrentPoint = aNextPoint;
2134 else
2136 const basegfx::B2DPoint aPoint(aPolygon.getB2DPoint(0));
2137 ras.move_to_d(aPoint.getX(), aPoint.getY());
2139 for(sal_uInt32 a(1); a < nPointCount; a++)
2141 const basegfx::B2DPoint aVertexPoint(aPolygon.getB2DPoint(a));
2142 ras.line_to_d(aVertexPoint.getX(), aVertexPoint.getY());
2145 if(aPolygon.isClosed())
2147 ras.close_polygon();
2153 ras.add_path(curve);
2154 agg::rgba8 fillcolor(aFillColor.Color.r,aFillColor.Color.g,aFillColor.Color.b,aFillColor.Color.a);
2155 ren.color(fillcolor);
2156 agg::render_scanlines(ras, sl, ren);
2158 // TODO(F2): Implement sensible ImageCachedPrimitive
2159 return ImageCachedPrimitiveSharedPtr();
2162 //////////////////////////////////////////////////////////////////////////////////
2163 // Image::fillPolyPolygon
2164 //////////////////////////////////////////////////////////////////////////////////
2166 ImageCachedPrimitiveSharedPtr Image::fillPolyPolygon(
2167 const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
2168 const rendering::ViewState& viewState,
2169 const rendering::RenderState& renderState )
2171 if( !xPolyPolygon.is() )
2172 return ImageCachedPrimitiveSharedPtr();
2174 ::basegfx::B2DPolyPolygon aPoly(
2175 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( xPolyPolygon ) );
2177 switch(maDesc.eFormat)
2179 case FMT_R8G8B8:
2180 return fillPolyPolygonImpl<agg::pixfmt_rgb24>(aPoly,viewState,renderState);
2181 case FMT_A8R8G8B8:
2182 return fillPolyPolygonImpl<agg::pixfmt_rgba32>(aPoly,viewState,renderState);
2183 default:
2184 OSL_ENSURE(false, "Unexpected pixel format");
2185 break;
2188 return ImageCachedPrimitiveSharedPtr();
2191 //////////////////////////////////////////////////////////////////////////////////
2192 // Image::fillTexturedPolyPolygon
2193 //////////////////////////////////////////////////////////////////////////////////
2195 ImageCachedPrimitiveSharedPtr Image::fillTexturedPolyPolygon(
2196 const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
2197 const rendering::ViewState& viewState,
2198 const rendering::RenderState& renderState,
2199 const uno::Sequence< rendering::Texture >& textures,
2200 const ::std::vector< ::boost::shared_ptr<Image> >& textureAnnotations )
2202 #if defined(PROFILER)
2203 ScopeTimer aTimer(TIMER_FILLTEXTUREDPOLYPOLYGON,this);
2204 #endif
2206 if( !xPolyPolygon.is() )
2207 return ImageCachedPrimitiveSharedPtr();
2209 ::basegfx::B2DPolyPolygon aPoly(
2210 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( xPolyPolygon ) );
2211 ARGB aFillColor;
2213 setupPolyPolygon( aPoly, true, aFillColor, viewState, renderState );
2215 if( !aPoly.count() )
2216 return ImageCachedPrimitiveSharedPtr();
2218 ::basegfx::B2DHomMatrix aViewTransform;
2219 ::basegfx::B2DHomMatrix aRenderTransform;
2220 ::basegfx::B2DHomMatrix aTextureTransform;
2222 ::basegfx::unotools::homMatrixFromAffineMatrix(aTextureTransform,
2223 textures[0].AffineTransform);
2224 ::basegfx::unotools::homMatrixFromAffineMatrix(aRenderTransform,
2225 renderState.AffineTransform);
2226 ::basegfx::unotools::homMatrixFromAffineMatrix(aViewTransform,
2227 viewState.AffineTransform);
2228 aTextureTransform *= aRenderTransform;
2230 // TODO(F1): Multi-texturing
2231 if( textures[0].Gradient.is() )
2233 aTextureTransform *= aViewTransform;
2235 // try to cast XParametricPolyPolygon2D reference to
2236 // our implementation class.
2237 ::canvas::ParametricPolyPolygon* pGradient =
2238 dynamic_cast< ::canvas::ParametricPolyPolygon* >( textures[0].Gradient.get() );
2240 if( pGradient )
2242 const ParametricPolyPolygon::Values& rValues(
2243 pGradient->getValues() );
2245 // TODO: use all the colors and place them on given positions/stops
2246 // TODO(E1): Return value
2247 // TODO(F1): FillRule
2248 fillGradient( rValues,
2249 rValues.maColors [0],
2250 rValues.maColors [rValues.maColors.getLength () - 1],
2251 aPoly,
2252 aTextureTransform,
2253 textures[0] );
2256 else if( textures[0].Bitmap.is() )
2258 ImageSharedPtr pTexture;
2260 if( textureAnnotations[0].get() != NULL )
2261 pTexture = textureAnnotations[0];
2262 else
2263 pTexture.reset( new Image( textures[0].Bitmap ) );
2265 const sal_uInt32 nWidth(pTexture->maDesc.nWidth);
2266 const sal_uInt32 nHeight(pTexture->maDesc.nHeight);
2268 // scale texture into one-by-one unit rect.
2269 aTextureTransform.scale(1.0f/nWidth,
2270 1.0f/nHeight);
2272 // TODO(E1): Return value
2273 // TODO(F1): FillRule
2274 return fillTexturedPolyPolygon( *pTexture,
2275 aPoly,
2276 aTextureTransform,
2277 aViewTransform,
2278 textures[0] );
2281 // TODO(F2): Implement sensible ImageCachedPrimitive
2282 return ImageCachedPrimitiveSharedPtr();
2285 //////////////////////////////////////////////////////////////////////////////////
2286 // Image::fillTextureMappedPolyPolygon
2287 //////////////////////////////////////////////////////////////////////////////////
2289 ImageCachedPrimitiveSharedPtr Image::fillTextureMappedPolyPolygon(
2290 const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/,
2291 const rendering::ViewState& /*viewState*/,
2292 const rendering::RenderState& /*renderState*/,
2293 const uno::Sequence< rendering::Texture >& /*textures*/,
2294 const ::std::vector< ::boost::shared_ptr<Image> >& /*textureAnnotations*/,
2295 const uno::Reference< geometry::XMapping2D >& /*xMapping*/ )
2297 OSL_ENSURE(false,
2298 "Image::fillTextureMappedPolyPolygon(): NYI" );
2300 // TODO(F2): Implement sensible ImageCachedPrimitive
2301 return ImageCachedPrimitiveSharedPtr();
2304 //////////////////////////////////////////////////////////////////////////////////
2305 // Image::drawBitmap
2306 //////////////////////////////////////////////////////////////////////////////////
2308 ImageCachedPrimitiveSharedPtr Image::drawBitmap(
2309 const uno::Reference< rendering::XBitmap >& xBitmap,
2310 const rendering::ViewState& viewState,
2311 const rendering::RenderState& renderState )
2313 #if defined(PROFILER)
2314 ScopeTimer aTimer(TIMER_DRAWBITMAP,this);
2315 #endif
2317 // TODO(P3): Implement bitmap caching
2318 if( !xBitmap.is() )
2319 return ImageCachedPrimitiveSharedPtr();
2321 XBitmapAccessor accessor( xBitmap );
2322 if(accessor.isValid())
2324 Image aImage( accessor.getDesc() );
2326 implDrawBitmap( aImage,
2327 viewState,
2328 renderState );
2330 // TODO(F2): Implement sensible ImageCachedPrimitive
2331 return ImageCachedPrimitiveSharedPtr();
2334 Image aImage( xBitmap );
2336 return implDrawBitmap( aImage,viewState,renderState );
2339 //////////////////////////////////////////////////////////////////////////////////
2340 // Image::drawBitmap
2341 //////////////////////////////////////////////////////////////////////////////////
2343 ImageCachedPrimitiveSharedPtr Image::drawBitmap(
2344 const ImageSharedPtr& rImage,
2345 const rendering::ViewState& viewState,
2346 const rendering::RenderState& renderState )
2348 #if defined(PROFILER)
2349 ScopeTimer aTimer(TIMER_DRAWBITMAP,this);
2350 #endif
2352 // TODO(P3): Implement bitmap caching
2353 if( !rImage )
2354 return ImageCachedPrimitiveSharedPtr();
2356 return implDrawBitmap( *rImage,
2357 viewState,
2358 renderState );
2361 //////////////////////////////////////////////////////////////////////////////////
2362 // Image::drawBitmapModulated
2363 //////////////////////////////////////////////////////////////////////////////////
2365 ImageCachedPrimitiveSharedPtr Image::drawBitmapModulated(
2366 const uno::Reference< rendering::XBitmap >& xBitmap,
2367 const rendering::ViewState& viewState,
2368 const rendering::RenderState& renderState )
2370 // TODO(P3): Implement bitmap caching
2371 if( !xBitmap.is() )
2372 return ImageCachedPrimitiveSharedPtr();
2374 Image aImage( xBitmap );
2376 // TODO(F2): Distinguish modulated and unmodulated bitmap output
2377 return implDrawBitmap( aImage,viewState,renderState );
2380 //////////////////////////////////////////////////////////////////////////////////
2381 // Image::drawBitmapModulated
2382 //////////////////////////////////////////////////////////////////////////////////
2384 ImageCachedPrimitiveSharedPtr Image::drawBitmapModulated(
2385 const ImageSharedPtr& rImage,
2386 const rendering::ViewState& viewState,
2387 const rendering::RenderState& renderState )
2389 // TODO(P3): Implement bitmap caching
2390 if( !rImage )
2391 return ImageCachedPrimitiveSharedPtr();
2393 // TODO(F2): Distinguish modulated and unmodulated bitmap output
2394 return implDrawBitmap( *rImage,viewState,renderState );