1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
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.
14  *
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).
20  *
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.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_canvas.hxx"
30 
31 #include <canvas/debug.hxx>
32 #include <tools/diagnose_ex.h>
33 
34 #include <com/sun/star/geometry/AffineMatrix2D.hpp>
35 #include <com/sun/star/geometry/Matrix2D.hpp>
36 #include <com/sun/star/awt/Rectangle.hpp>
37 #include <com/sun/star/util/Endianness.hpp>
38 #include <com/sun/star/rendering/XIntegerBitmapColorSpace.hpp>
39 #include <com/sun/star/rendering/IntegerBitmapLayout.hpp>
40 #include <com/sun/star/rendering/ColorSpaceType.hpp>
41 #include <com/sun/star/rendering/ColorComponentTag.hpp>
42 #include <com/sun/star/rendering/RenderingIntent.hpp>
43 #include <com/sun/star/rendering/RenderState.hpp>
44 #include <com/sun/star/rendering/ViewState.hpp>
45 #include <com/sun/star/rendering/XCanvas.hpp>
46 #include <com/sun/star/rendering/XColorSpace.hpp>
47 #include <com/sun/star/rendering/CompositeOperation.hpp>
48 #include <com/sun/star/beans/XPropertySet.hpp>
49 #include <com/sun/star/lang/XServiceInfo.hpp>
50 
51 #include <basegfx/matrix/b2dhommatrix.hxx>
52 #include <basegfx/range/b2drange.hxx>
53 #include <basegfx/range/b2irange.hxx>
54 #include <basegfx/range/b2drectangle.hxx>
55 #include <basegfx/point/b2dpoint.hxx>
56 #include <basegfx/point/b2ipoint.hxx>
57 #include <basegfx/vector/b2ivector.hxx>
58 #include <basegfx/polygon/b2dpolygon.hxx>
59 #include <basegfx/polygon/b2dpolygontools.hxx>
60 #include <basegfx/polygon/b2dpolypolygontools.hxx>
61 #include <basegfx/tools/canvastools.hxx>
62 #include <basegfx/numeric/ftools.hxx>
63 #include <basegfx/matrix/b2dhommatrixtools.hxx>
64 
65 #include <cppuhelper/compbase1.hxx>
66 #include <rtl/instance.hxx>
67 #include <toolkit/helper/vclunohelper.hxx>
68 #include <vcl/window.hxx>
69 #include <vcl/canvastools.hxx>
70 
71 #include <canvas/canvastools.hxx>
72 
73 #include <limits>
74 
75 
76 using namespace ::com::sun::star;
77 
78 namespace com { namespace sun { namespace star { namespace rendering
79 {
80     bool operator==( const RenderState& renderState1,
81                      const RenderState& renderState2 )
82     {
83         if( renderState1.Clip != renderState2.Clip )
84             return false;
85 
86         if( renderState1.DeviceColor != renderState2.DeviceColor )
87             return false;
88 
89         if( renderState1.CompositeOperation != renderState2.CompositeOperation )
90             return false;
91 
92         ::basegfx::B2DHomMatrix mat1, mat2;
93         ::canvas::tools::getRenderStateTransform( mat1, renderState1 );
94         ::canvas::tools::getRenderStateTransform( mat2, renderState2 );
95         if( mat1 != mat2 )
96             return false;
97 
98         return true;
99     }
100 
101     bool operator==( const ViewState& viewState1,
102                      const ViewState& viewState2 )
103     {
104         if( viewState1.Clip != viewState2.Clip )
105             return false;
106 
107         ::basegfx::B2DHomMatrix mat1, mat2;
108         ::canvas::tools::getViewStateTransform( mat1, viewState1 );
109         ::canvas::tools::getViewStateTransform( mat2, viewState2 );
110         if( mat1 != mat2 )
111             return false;
112 
113         return true;
114     }
115 }}}}
116 
117 namespace canvas
118 {
119     namespace tools
120     {
121         geometry::RealSize2D createInfiniteSize2D()
122         {
123             return geometry::RealSize2D(
124                 ::std::numeric_limits<double>::infinity(),
125                 ::std::numeric_limits<double>::infinity() );
126         }
127 
128         rendering::RenderState& initRenderState( rendering::RenderState& renderState )
129         {
130             // setup identity transform
131             setIdentityAffineMatrix2D( renderState.AffineTransform );
132             renderState.Clip = uno::Reference< rendering::XPolyPolygon2D >();
133             renderState.DeviceColor = uno::Sequence< double >();
134             renderState.CompositeOperation = rendering::CompositeOperation::OVER;
135 
136             return renderState;
137         }
138 
139         rendering::ViewState& initViewState( rendering::ViewState& viewState )
140         {
141             // setup identity transform
142             setIdentityAffineMatrix2D( viewState.AffineTransform );
143             viewState.Clip = uno::Reference< rendering::XPolyPolygon2D >();
144 
145             return viewState;
146         }
147 
148         ::basegfx::B2DHomMatrix& getViewStateTransform( ::basegfx::B2DHomMatrix&	transform,
149                                                         const rendering::ViewState&	viewState )
150         {
151             return ::basegfx::unotools::homMatrixFromAffineMatrix( transform, viewState.AffineTransform );
152         }
153 
154         rendering::ViewState& setViewStateTransform( rendering::ViewState& 			viewState,
155                                                      const ::basegfx::B2DHomMatrix&	transform )
156         {
157             ::basegfx::unotools::affineMatrixFromHomMatrix( viewState.AffineTransform, transform );
158 
159             return viewState;
160         }
161 
162         ::basegfx::B2DHomMatrix& getRenderStateTransform( ::basegfx::B2DHomMatrix&		transform,
163                                                           const rendering::RenderState&	renderState )
164         {
165             return ::basegfx::unotools::homMatrixFromAffineMatrix( transform, renderState.AffineTransform );
166         }
167 
168         rendering::RenderState& setRenderStateTransform( rendering::RenderState& 		renderState,
169                                                          const ::basegfx::B2DHomMatrix&	transform )
170         {
171             ::basegfx::unotools::affineMatrixFromHomMatrix( renderState.AffineTransform, transform );
172 
173             return renderState;
174         }
175 
176         rendering::RenderState& appendToRenderState( rendering::RenderState&		renderState,
177                                                    const ::basegfx::B2DHomMatrix&	rTransform )
178         {
179             ::basegfx::B2DHomMatrix transform;
180 
181             getRenderStateTransform( transform, renderState );
182             return setRenderStateTransform( renderState, transform * rTransform );
183         }
184 
185         rendering::ViewState& appendToViewState( rendering::ViewState&			viewState,
186                                                  const ::basegfx::B2DHomMatrix&	rTransform )
187         {
188             ::basegfx::B2DHomMatrix transform;
189 
190             getViewStateTransform( transform, viewState );
191             return setViewStateTransform( viewState, transform * rTransform );
192         }
193 
194         rendering::RenderState& prependToRenderState( rendering::RenderState&			renderState,
195                                                       const ::basegfx::B2DHomMatrix&	rTransform )
196         {
197             ::basegfx::B2DHomMatrix transform;
198 
199             getRenderStateTransform( transform, renderState );
200             return setRenderStateTransform( renderState, rTransform * transform );
201         }
202 
203         rendering::ViewState& prependToViewState( rendering::ViewState&				viewState,
204                                                   const ::basegfx::B2DHomMatrix&		rTransform )
205         {
206             ::basegfx::B2DHomMatrix transform;
207 
208             getViewStateTransform( transform, viewState );
209             return setViewStateTransform( viewState, rTransform * transform );
210         }
211 
212         ::basegfx::B2DHomMatrix& mergeViewAndRenderTransform( ::basegfx::B2DHomMatrix&		combinedTransform,
213                                                               const rendering::ViewState&	viewState,
214                                                               const rendering::RenderState& renderState	)
215         {
216             ::basegfx::B2DHomMatrix viewTransform;
217 
218             ::basegfx::unotools::homMatrixFromAffineMatrix( combinedTransform, renderState.AffineTransform );
219             ::basegfx::unotools::homMatrixFromAffineMatrix( viewTransform, viewState.AffineTransform );
220 
221 			// this statement performs combinedTransform = viewTransform * combinedTransform
222             combinedTransform *= viewTransform;
223 
224             return combinedTransform;
225         }
226 
227         rendering::ViewState& mergeViewAndRenderState( rendering::ViewState&						resultViewState,
228                                                        const rendering::ViewState&					viewState,
229                                                        const rendering::RenderState&				renderState,
230                                                        const uno::Reference< rendering::XCanvas >& 	/*xCanvas*/ 	)
231         {
232             ::basegfx::B2DHomMatrix		aTmpMatrix;
233             geometry::AffineMatrix2D 	convertedMatrix;
234 
235             resultViewState.Clip = NULL; // TODO(F2): intersect clippings
236 
237             return setViewStateTransform(
238                 resultViewState,
239                 mergeViewAndRenderTransform( aTmpMatrix,
240                                              viewState,
241                                              renderState ) );
242         }
243 
244         geometry::AffineMatrix2D& setIdentityAffineMatrix2D( geometry::AffineMatrix2D& matrix )
245         {
246             matrix.m00 = 1.0;
247             matrix.m01 = 0.0;
248             matrix.m02 = 0.0;
249             matrix.m10 = 0.0;
250             matrix.m11 = 1.0;
251             matrix.m12 = 0.0;
252 
253             return matrix;
254         }
255 
256         geometry::Matrix2D& setIdentityMatrix2D( geometry::Matrix2D& matrix )
257         {
258             matrix.m00 = 1.0;
259             matrix.m01 = 0.0;
260             matrix.m10 = 0.0;
261             matrix.m11 = 1.0;
262 
263             return matrix;
264         }
265 
266         namespace
267         {
268             class StandardColorSpace : public cppu::WeakImplHelper1< com::sun::star::rendering::XIntegerBitmapColorSpace >
269             {
270             private:
271                 uno::Sequence< sal_Int8 >  maComponentTags;
272                 uno::Sequence< sal_Int32 > maBitCounts;
273 
274                 virtual ::sal_Int8 SAL_CALL getType(  ) throw (uno::RuntimeException)
275                 {
276                     return rendering::ColorSpaceType::RGB;
277                 }
278                 virtual uno::Sequence< ::sal_Int8 > SAL_CALL getComponentTags(  ) throw (uno::RuntimeException)
279                 {
280                     return maComponentTags;
281                 }
282                 virtual ::sal_Int8 SAL_CALL getRenderingIntent(  ) throw (uno::RuntimeException)
283                 {
284                     return rendering::RenderingIntent::PERCEPTUAL;
285                 }
286                 virtual uno::Sequence< beans::PropertyValue > SAL_CALL getProperties(  ) throw (uno::RuntimeException)
287                 {
288                     return uno::Sequence< beans::PropertyValue >();
289                 }
290                 virtual uno::Sequence< double > SAL_CALL convertColorSpace( const uno::Sequence< double >& deviceColor,
291                                                                             const uno::Reference< rendering::XColorSpace >& targetColorSpace ) throw (lang::IllegalArgumentException,
292                                                                                                                                                       uno::RuntimeException)
293                 {
294                     // TODO(P3): if we know anything about target
295                     // colorspace, this can be greatly sped up
296                     uno::Sequence<rendering::ARGBColor> aIntermediate(
297                         convertToARGB(deviceColor));
298                     return targetColorSpace->convertFromARGB(aIntermediate);
299                 }
300                 virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertToRGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
301                 {
302                     const double*  pIn( deviceColor.getConstArray() );
303                     const sal_Size nLen( deviceColor.getLength() );
304                     ENSURE_ARG_OR_THROW2(nLen%4==0,
305                                          "number of channels no multiple of 4",
306                                          static_cast<rendering::XColorSpace*>(this), 0);
307 
308                     uno::Sequence< rendering::RGBColor > aRes(nLen/4);
309                     rendering::RGBColor* pOut( aRes.getArray() );
310                     for( sal_Size i=0; i<nLen; i+=4 )
311                     {
312                         *pOut++ = rendering::RGBColor(pIn[0],pIn[1],pIn[2]);
313                         pIn += 4;
314                     }
315                     return aRes;
316                 }
317                 virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToARGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
318                 {
319                     const double*  pIn( deviceColor.getConstArray() );
320                     const sal_Size nLen( deviceColor.getLength() );
321                     ENSURE_ARG_OR_THROW2(nLen%4==0,
322                                          "number of channels no multiple of 4",
323                                          static_cast<rendering::XColorSpace*>(this), 0);
324 
325                     uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
326                     rendering::ARGBColor* pOut( aRes.getArray() );
327                     for( sal_Size i=0; i<nLen; i+=4 )
328                     {
329                         *pOut++ = rendering::ARGBColor(pIn[3],pIn[0],pIn[1],pIn[2]);
330                         pIn += 4;
331                     }
332                     return aRes;
333                 }
334                 virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToPARGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
335                 {
336                     const double*  pIn( deviceColor.getConstArray() );
337                     const sal_Size nLen( deviceColor.getLength() );
338                     ENSURE_ARG_OR_THROW2(nLen%4==0,
339                                          "number of channels no multiple of 4",
340                                          static_cast<rendering::XColorSpace*>(this), 0);
341 
342                     uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
343                     rendering::ARGBColor* pOut( aRes.getArray() );
344                     for( sal_Size i=0; i<nLen; i+=4 )
345                     {
346                         *pOut++ = rendering::ARGBColor(pIn[3],pIn[3]*pIn[0],pIn[3]*pIn[1],pIn[3]*pIn[2]);
347                         pIn += 4;
348                     }
349                     return aRes;
350                 }
351                 virtual uno::Sequence< double > SAL_CALL convertFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
352                 {
353                     const rendering::RGBColor* pIn( rgbColor.getConstArray() );
354                     const sal_Size             nLen( rgbColor.getLength() );
355 
356                     uno::Sequence< double > aRes(nLen*4);
357                     double* pColors=aRes.getArray();
358                     for( sal_Size i=0; i<nLen; ++i )
359                     {
360                         *pColors++ = pIn->Red;
361                         *pColors++ = pIn->Green;
362                         *pColors++ = pIn->Blue;
363                         *pColors++ = 1.0;
364                         ++pIn;
365                     }
366                     return aRes;
367                 }
368                 virtual uno::Sequence< double > SAL_CALL convertFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
369                 {
370                     const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
371                     const sal_Size              nLen( rgbColor.getLength() );
372 
373                     uno::Sequence< double > aRes(nLen*4);
374                     double* pColors=aRes.getArray();
375                     for( sal_Size i=0; i<nLen; ++i )
376                     {
377                         *pColors++ = pIn->Red;
378                         *pColors++ = pIn->Green;
379                         *pColors++ = pIn->Blue;
380                         *pColors++ = pIn->Alpha;
381                         ++pIn;
382                     }
383                     return aRes;
384                 }
385                 virtual uno::Sequence< double > SAL_CALL convertFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
386                 {
387                     const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
388                     const sal_Size              nLen( rgbColor.getLength() );
389 
390                     uno::Sequence< double > aRes(nLen*4);
391                     double* pColors=aRes.getArray();
392                     for( sal_Size i=0; i<nLen; ++i )
393                     {
394                         *pColors++ = pIn->Red/pIn->Alpha;
395                         *pColors++ = pIn->Green/pIn->Alpha;
396                         *pColors++ = pIn->Blue/pIn->Alpha;
397                         *pColors++ = pIn->Alpha;
398                         ++pIn;
399                     }
400                     return aRes;
401                 }
402 
403                 // XIntegerBitmapColorSpace
404                 virtual ::sal_Int32 SAL_CALL getBitsPerPixel(  ) throw (uno::RuntimeException)
405                 {
406                     return 32;
407                 }
408                 virtual uno::Sequence< ::sal_Int32 > SAL_CALL getComponentBitCounts(  ) throw (uno::RuntimeException)
409                 {
410                     return maBitCounts;
411                 }
412                 virtual ::sal_Int8 SAL_CALL getEndianness(  ) throw (uno::RuntimeException)
413                 {
414                     return util::Endianness::LITTLE;
415                 }
416                 virtual uno::Sequence<double> SAL_CALL convertFromIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor,
417                                                                                      const uno::Reference< rendering::XColorSpace >& targetColorSpace ) throw (lang::IllegalArgumentException,
418                                                                                                                                                                uno::RuntimeException)
419                 {
420                     if( dynamic_cast<StandardColorSpace*>(targetColorSpace.get()) )
421                     {
422                         const sal_Int8* pIn( deviceColor.getConstArray() );
423                         const sal_Size  nLen( deviceColor.getLength() );
424                         ENSURE_ARG_OR_THROW2(nLen%4==0,
425                                              "number of channels no multiple of 4",
426                                              static_cast<rendering::XColorSpace*>(this), 0);
427 
428                         uno::Sequence<double> aRes(nLen);
429                         double* pOut( aRes.getArray() );
430                         for( sal_Size i=0; i<nLen; i+=4 )
431                         {
432                             *pOut++ = vcl::unotools::toDoubleColor(*pIn++);
433                             *pOut++ = vcl::unotools::toDoubleColor(*pIn++);
434                             *pOut++ = vcl::unotools::toDoubleColor(*pIn++);
435                             *pOut++ = vcl::unotools::toDoubleColor(255-*pIn++);
436                         }
437                         return aRes;
438                     }
439                     else
440                     {
441                         // TODO(P3): if we know anything about target
442                         // colorspace, this can be greatly sped up
443                         uno::Sequence<rendering::ARGBColor> aIntermediate(
444                             convertIntegerToARGB(deviceColor));
445                         return targetColorSpace->convertFromARGB(aIntermediate);
446                     }
447                 }
448                 virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertToIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor,
449                                                                                          const uno::Reference< rendering::XIntegerBitmapColorSpace >& targetColorSpace ) throw (lang::IllegalArgumentException,
450                                                                                                                                                                               uno::RuntimeException)
451                 {
452                     if( dynamic_cast<StandardColorSpace*>(targetColorSpace.get()) )
453                     {
454                         // it's us, so simply pass-through the data
455                         return deviceColor;
456                     }
457                     else
458                     {
459                         // TODO(P3): if we know anything about target
460                         // colorspace, this can be greatly sped up
461                         uno::Sequence<rendering::ARGBColor> aIntermediate(
462                             convertIntegerToARGB(deviceColor));
463                         return targetColorSpace->convertIntegerFromARGB(aIntermediate);
464                     }
465                 }
466                 virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertIntegerToRGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
467                 {
468                     const sal_Int8* pIn( deviceColor.getConstArray() );
469                     const sal_Size  nLen( deviceColor.getLength() );
470                     ENSURE_ARG_OR_THROW2(nLen%4==0,
471                                          "number of channels no multiple of 4",
472                                          static_cast<rendering::XColorSpace*>(this), 0);
473 
474                     uno::Sequence< rendering::RGBColor > aRes(nLen/4);
475                     rendering::RGBColor* pOut( aRes.getArray() );
476                     for( sal_Size i=0; i<nLen; i+=4 )
477                     {
478                         *pOut++ = rendering::RGBColor(
479                             vcl::unotools::toDoubleColor(pIn[0]),
480                             vcl::unotools::toDoubleColor(pIn[1]),
481                             vcl::unotools::toDoubleColor(pIn[2]));
482                         pIn += 4;
483                     }
484                     return aRes;
485                 }
486 
487                 virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
488                 {
489                     const sal_Int8* pIn( deviceColor.getConstArray() );
490                     const sal_Size  nLen( deviceColor.getLength() );
491                     ENSURE_ARG_OR_THROW2(nLen%4==0,
492                                          "number of channels no multiple of 4",
493                                          static_cast<rendering::XColorSpace*>(this), 0);
494 
495                     uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
496                     rendering::ARGBColor* pOut( aRes.getArray() );
497                     for( sal_Size i=0; i<nLen; i+=4 )
498                     {
499                         *pOut++ = rendering::ARGBColor(
500                             vcl::unotools::toDoubleColor(255-pIn[3]),
501                             vcl::unotools::toDoubleColor(pIn[0]),
502                             vcl::unotools::toDoubleColor(pIn[1]),
503                             vcl::unotools::toDoubleColor(pIn[2]));
504                         pIn += 4;
505                     }
506                     return aRes;
507                 }
508 
509                 virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToPARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
510                 {
511                     const sal_Int8* pIn( deviceColor.getConstArray() );
512                     const sal_Size  nLen( deviceColor.getLength() );
513                     ENSURE_ARG_OR_THROW2(nLen%4==0,
514                                          "number of channels no multiple of 4",
515                                          static_cast<rendering::XColorSpace*>(this), 0);
516 
517                     uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
518                     rendering::ARGBColor* pOut( aRes.getArray() );
519                     for( sal_Size i=0; i<nLen; i+=4 )
520                     {
521                         const sal_Int8 nAlpha( 255-pIn[3] );
522                         *pOut++ = rendering::ARGBColor(
523                             vcl::unotools::toDoubleColor(nAlpha),
524                             vcl::unotools::toDoubleColor(nAlpha*pIn[0]),
525                             vcl::unotools::toDoubleColor(nAlpha*pIn[1]),
526                             vcl::unotools::toDoubleColor(nAlpha*pIn[2]));
527                         pIn += 4;
528                     }
529                     return aRes;
530                 }
531 
532                 virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
533                 {
534                     const rendering::RGBColor* pIn( rgbColor.getConstArray() );
535                     const sal_Size             nLen( rgbColor.getLength() );
536 
537                     uno::Sequence< sal_Int8 > aRes(nLen*4);
538                     sal_Int8* pColors=aRes.getArray();
539                     for( sal_Size i=0; i<nLen; ++i )
540                     {
541                         *pColors++ = vcl::unotools::toByteColor(pIn->Red);
542                         *pColors++ = vcl::unotools::toByteColor(pIn->Green);
543                         *pColors++ = vcl::unotools::toByteColor(pIn->Blue);
544                         *pColors++ = 0;
545                         ++pIn;
546                     }
547                     return aRes;
548                 }
549 
550                 virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
551                 {
552                     const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
553                     const sal_Size              nLen( rgbColor.getLength() );
554 
555                     uno::Sequence< sal_Int8 > aRes(nLen*4);
556                     sal_Int8* pColors=aRes.getArray();
557                     for( sal_Size i=0; i<nLen; ++i )
558                     {
559                         *pColors++ = vcl::unotools::toByteColor(pIn->Red);
560                         *pColors++ = vcl::unotools::toByteColor(pIn->Green);
561                         *pColors++ = vcl::unotools::toByteColor(pIn->Blue);
562                         *pColors++ = 255-vcl::unotools::toByteColor(pIn->Alpha);
563                         ++pIn;
564                     }
565                     return aRes;
566                 }
567 
568                 virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
569                 {
570                     const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
571                     const sal_Size              nLen( rgbColor.getLength() );
572 
573                     uno::Sequence< sal_Int8 > aRes(nLen*4);
574                     sal_Int8* pColors=aRes.getArray();
575                     for( sal_Size i=0; i<nLen; ++i )
576                     {
577                         *pColors++ = vcl::unotools::toByteColor(pIn->Red/pIn->Alpha);
578                         *pColors++ = vcl::unotools::toByteColor(pIn->Green/pIn->Alpha);
579                         *pColors++ = vcl::unotools::toByteColor(pIn->Blue/pIn->Alpha);
580                         *pColors++ = 255-vcl::unotools::toByteColor(pIn->Alpha);
581                         ++pIn;
582                     }
583                     return aRes;
584                 }
585 
586             public:
587                 StandardColorSpace() :
588                     maComponentTags(4),
589                     maBitCounts(4)
590                 {
591                     sal_Int8*  pTags = maComponentTags.getArray();
592                     sal_Int32* pBitCounts = maBitCounts.getArray();
593                     pTags[0] = rendering::ColorComponentTag::RGB_RED;
594                     pTags[1] = rendering::ColorComponentTag::RGB_GREEN;
595                     pTags[2] = rendering::ColorComponentTag::RGB_BLUE;
596                     pTags[3] = rendering::ColorComponentTag::ALPHA;
597 
598                     pBitCounts[0] =
599                     pBitCounts[1] =
600                     pBitCounts[2] =
601                     pBitCounts[3] = 8;
602                 }
603             };
604 
605             struct StandardColorSpaceHolder : public rtl::StaticWithInit<uno::Reference<rendering::XIntegerBitmapColorSpace>,
606                                                                          StandardColorSpaceHolder>
607             {
608                 uno::Reference<rendering::XIntegerBitmapColorSpace> operator()()
609                 {
610                     return new StandardColorSpace();
611                 }
612             };
613         }
614 
615         uno::Reference<rendering::XIntegerBitmapColorSpace> getStdColorSpace()
616         {
617             return StandardColorSpaceHolder::get();
618         }
619 
620         rendering::IntegerBitmapLayout getStdMemoryLayout( const geometry::IntegerSize2D& rBmpSize )
621         {
622             rendering::IntegerBitmapLayout aLayout;
623 
624             aLayout.ScanLines = rBmpSize.Height;
625             aLayout.ScanLineBytes = rBmpSize.Width*4;
626             aLayout.ScanLineStride = aLayout.ScanLineBytes;
627             aLayout.PlaneStride = 0;
628             aLayout.ColorSpace = getStdColorSpace();
629             aLayout.Palette.clear();
630             aLayout.IsMsbFirst = sal_False;
631 
632             return aLayout;
633         }
634 
635         ::Color stdIntSequenceToColor( const uno::Sequence<sal_Int8>& rColor )
636         {
637 #ifdef OSL_BIGENDIAN
638             const sal_Int8* pCols( rColor.getConstArray() );
639             return ::Color( pCols[3], pCols[0], pCols[1], pCols[2] );
640 #else
641             return ::Color( *reinterpret_cast< const ::ColorData* >(rColor.getConstArray()) );
642 #endif
643         }
644 
645         uno::Sequence<sal_Int8> colorToStdIntSequence( const ::Color& rColor )
646         {
647             uno::Sequence<sal_Int8> aRet(4);
648             sal_Int8* pCols( aRet.getArray() );
649 #ifdef OSL_BIGENDIAN
650             pCols[0] = rColor.GetRed();
651             pCols[1] = rColor.GetGreen();
652             pCols[2] = rColor.GetBlue();
653             pCols[3] = 255-rColor.GetTransparency();
654 #else
655             *reinterpret_cast<sal_Int32*>(pCols) = rColor.GetColor();
656 #endif
657             return aRet;
658         }
659 
660         // Create a corrected view transformation out of the give one,
661         // which ensures that the rectangle given by (0,0) and
662         // rSpriteSize is mapped with its left,top corner to (0,0)
663         // again. This is required to properly render sprite
664         // animations to buffer bitmaps.
665         ::basegfx::B2DHomMatrix& calcRectToOriginTransform( ::basegfx::B2DHomMatrix&			o_transform,
666                                                             const ::basegfx::B2DRange&			i_srcRect,
667                                                             const ::basegfx::B2DHomMatrix&		i_transformation )
668         {
669             if( i_srcRect.isEmpty() )
670                 return o_transform=i_transformation;
671 
672             // transform by given transformation
673             ::basegfx::B2DRectangle aTransformedRect;
674 
675             calcTransformedRectBounds( aTransformedRect,
676                                        i_srcRect,
677                                        i_transformation );
678 
679             // now move resulting left,top point of bounds to (0,0)
680             const basegfx::B2DHomMatrix aCorrectedTransform(basegfx::tools::createTranslateB2DHomMatrix(
681                 -aTransformedRect.getMinX(), -aTransformedRect.getMinY()));
682 
683             // prepend to original transformation
684             o_transform = aCorrectedTransform * i_transformation;
685 
686             return o_transform;
687         }
688 
689         ::basegfx::B2DRange& calcTransformedRectBounds( ::basegfx::B2DRange&			outRect,
690                                                         const ::basegfx::B2DRange&		inRect,
691                                                         const ::basegfx::B2DHomMatrix& 	transformation )
692         {
693             outRect.reset();
694 
695             if( inRect.isEmpty() )
696                 return outRect;
697 
698             // transform all four extremal points of the rectangle,
699             // take bounding rect of those.
700 
701             // transform left-top point
702             outRect.expand( transformation * inRect.getMinimum() );
703 
704             // transform bottom-right point
705             outRect.expand( transformation * inRect.getMaximum() );
706 
707             ::basegfx::B2DPoint aPoint;
708 
709             // transform top-right point
710             aPoint.setX( inRect.getMaxX() );
711             aPoint.setY( inRect.getMinY() );
712 
713             aPoint *= transformation;
714             outRect.expand( aPoint );
715 
716             // transform bottom-left point
717             aPoint.setX( inRect.getMinX() );
718             aPoint.setY( inRect.getMaxY() );
719 
720             aPoint *= transformation;
721             outRect.expand( aPoint );
722 
723             // over and out.
724             return outRect;
725         }
726 
727         ::basegfx::B2DHomMatrix& calcRectToRectTransform( ::basegfx::B2DHomMatrix&			o_transform,
728                                                           const ::basegfx::B2DRange&		destRect,
729                                                           const ::basegfx::B2DRange&		srcRect,
730                                                           const ::basegfx::B2DHomMatrix&	transformation )
731         {
732             if( srcRect.isEmpty() ||
733                 destRect.isEmpty() )
734             {
735                 return o_transform=transformation;
736             }
737 
738             // transform inputRect by transformation
739             ::basegfx::B2DRectangle aTransformedRect;
740             calcTransformedRectBounds( aTransformedRect,
741                                        srcRect,
742                                        transformation );
743 
744             // now move resulting left,top point of bounds to (0,0)
745             basegfx::B2DHomMatrix aCorrectedTransform(basegfx::tools::createTranslateB2DHomMatrix(
746                 -aTransformedRect.getMinX(), -aTransformedRect.getMinY()));
747 
748             // scale to match outRect
749             const double xDenom( aTransformedRect.getWidth() );
750             const double yDenom( aTransformedRect.getHeight() );
751             if( xDenom != 0.0 && yDenom != 0.0 )
752                 aCorrectedTransform.scale( destRect.getWidth() / xDenom,
753                                            destRect.getHeight() / yDenom );
754             // TODO(E2): error handling
755 
756             // translate to final position
757             aCorrectedTransform.translate( destRect.getMinX(),
758                                            destRect.getMinY() );
759 
760             ::basegfx::B2DHomMatrix transform( transformation );
761             o_transform = aCorrectedTransform * transform;
762 
763             return o_transform;
764         }
765 
766 		bool isInside( const ::basegfx::B2DRange& 		rContainedRect,
767                        const ::basegfx::B2DRange& 		rTransformRect,
768                        const ::basegfx::B2DHomMatrix&	rTransformation )
769         {
770             if( rContainedRect.isEmpty() || rTransformRect.isEmpty() )
771                 return false;
772 
773             ::basegfx::B2DPolygon aPoly(
774                 ::basegfx::tools::createPolygonFromRect( rTransformRect ) );
775             aPoly.transform( rTransformation );
776 
777             return ::basegfx::tools::isInside( aPoly,
778                                                ::basegfx::tools::createPolygonFromRect(
779                                                    rContainedRect ),
780                                                true );
781         }
782 
783         namespace
784         {
785             bool clipAreaImpl( ::basegfx::B2IRange*       o_pDestArea,
786                                ::basegfx::B2IRange&       io_rSourceArea,
787                                ::basegfx::B2IPoint&       io_rDestPoint,
788                                const ::basegfx::B2IRange& rSourceBounds,
789                                const ::basegfx::B2IRange& rDestBounds )
790             {
791                 const ::basegfx::B2IPoint aSourceTopLeft(
792                     io_rSourceArea.getMinimum() );
793 
794                 ::basegfx::B2IRange aLocalSourceArea( io_rSourceArea );
795 
796                 // clip source area (which must be inside rSourceBounds)
797                 aLocalSourceArea.intersect( rSourceBounds );
798 
799                 if( aLocalSourceArea.isEmpty() )
800                     return false;
801 
802                 // calc relative new source area points (relative to orig
803                 // source area)
804                 const ::basegfx::B2IVector aUpperLeftOffset(
805                     aLocalSourceArea.getMinimum()-aSourceTopLeft );
806                 const ::basegfx::B2IVector aLowerRightOffset(
807                     aLocalSourceArea.getMaximum()-aSourceTopLeft );
808 
809                 ::basegfx::B2IRange aLocalDestArea( io_rDestPoint + aUpperLeftOffset,
810                                                     io_rDestPoint + aLowerRightOffset );
811 
812                 // clip dest area (which must be inside rDestBounds)
813                 aLocalDestArea.intersect( rDestBounds );
814 
815                 if( aLocalDestArea.isEmpty() )
816                     return false;
817 
818                 // calc relative new dest area points (relative to orig
819                 // source area)
820                 const ::basegfx::B2IVector aDestUpperLeftOffset(
821                     aLocalDestArea.getMinimum()-io_rDestPoint );
822                 const ::basegfx::B2IVector aDestLowerRightOffset(
823                     aLocalDestArea.getMaximum()-io_rDestPoint );
824 
825                 io_rSourceArea = ::basegfx::B2IRange( aSourceTopLeft + aDestUpperLeftOffset,
826                                                       aSourceTopLeft + aDestLowerRightOffset );
827                 io_rDestPoint  = aLocalDestArea.getMinimum();
828 
829                 if( o_pDestArea )
830                     *o_pDestArea = aLocalDestArea;
831 
832                 return true;
833             }
834         }
835 
836         bool clipScrollArea( ::basegfx::B2IRange&                  io_rSourceArea,
837                              ::basegfx::B2IPoint&                  io_rDestPoint,
838                              ::std::vector< ::basegfx::B2IRange >& o_ClippedAreas,
839                              const ::basegfx::B2IRange&            rBounds )
840         {
841             ::basegfx::B2IRange aResultingDestArea;
842 
843             // compute full destination area (to determine uninitialized
844             // areas below)
845             const ::basegfx::B2I64Tuple& rRange( io_rSourceArea.getRange() );
846             ::basegfx::B2IRange aInputDestArea( io_rDestPoint.getX(),
847                                                 io_rDestPoint.getY(),
848                                                 (io_rDestPoint.getX()
849                                                  + static_cast<sal_Int32>(rRange.getX())),
850                                                 (io_rDestPoint.getY()
851                                                  + static_cast<sal_Int32>(rRange.getY())) );
852             // limit to output area (no point updating outside of it)
853             aInputDestArea.intersect( rBounds );
854 
855             // clip to rBounds
856             if( !clipAreaImpl( &aResultingDestArea,
857                                io_rSourceArea,
858                                io_rDestPoint,
859                                rBounds,
860                                rBounds ) )
861                 return false;
862 
863             // finally, compute all areas clipped off the total
864             // destination area.
865             ::basegfx::computeSetDifference( o_ClippedAreas,
866                                              aInputDestArea,
867                                              aResultingDestArea );
868 
869             return true;
870         }
871 
872         bool clipBlit( ::basegfx::B2IRange&       io_rSourceArea,
873                        ::basegfx::B2IPoint&       io_rDestPoint,
874                        const ::basegfx::B2IRange& rSourceBounds,
875                        const ::basegfx::B2IRange& rDestBounds )
876         {
877             return clipAreaImpl( NULL,
878                                  io_rSourceArea,
879                                  io_rDestPoint,
880                                  rSourceBounds,
881                                  rDestBounds );
882         }
883 
884         ::basegfx::B2IRange spritePixelAreaFromB2DRange( const ::basegfx::B2DRange& rRange )
885         {
886             if( rRange.isEmpty() )
887                 return ::basegfx::B2IRange();
888 
889             const ::basegfx::B2IPoint aTopLeft( ::basegfx::fround( rRange.getMinX() ),
890                                                 ::basegfx::fround( rRange.getMinY() ) );
891             return ::basegfx::B2IRange( aTopLeft,
892                                         aTopLeft + ::basegfx::B2IPoint(
893                                             ::basegfx::fround( rRange.getWidth() ),
894                                             ::basegfx::fround( rRange.getHeight() ) ) );
895         }
896 
897 		uno::Sequence< uno::Any >& getDeviceInfo( const uno::Reference< rendering::XCanvas >& i_rxCanvas,
898 												  uno::Sequence< uno::Any >& 				  o_rxParams )
899 		{
900 			o_rxParams.realloc( 0 );
901 
902 			if( i_rxCanvas.is() )
903 			{
904                 try
905                 {
906                     uno::Reference< rendering::XGraphicDevice > xDevice( i_rxCanvas->getDevice(),
907                                                                          uno::UNO_QUERY_THROW );
908 
909                     uno::Reference< lang::XServiceInfo >  xServiceInfo( xDevice,
910                                                                         uno::UNO_QUERY_THROW );
911                     uno::Reference< beans::XPropertySet > xPropSet( xDevice,
912                                                                     uno::UNO_QUERY_THROW );
913 
914                     o_rxParams.realloc( 2 );
915 
916                     o_rxParams[ 0 ] = uno::makeAny( xServiceInfo->getImplementationName() );
917                     o_rxParams[ 1 ] = uno::makeAny( xPropSet->getPropertyValue(
918                                                         ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("DeviceHandle") ) ) );
919                 }
920                 catch( uno::Exception& )
921                 {
922                     // ignore, but return empty sequence
923                 }
924 			}
925 
926 			return o_rxParams;
927 		}
928 
929         awt::Rectangle getAbsoluteWindowRect( const awt::Rectangle&                  rRect,
930                                               const uno::Reference< awt::XWindow2 >& xWin  )
931         {
932             awt::Rectangle aRetVal( rRect );
933 
934             ::Window* pWindow = VCLUnoHelper::GetWindow(xWin);
935             if( pWindow )
936             {
937                 ::Point aPoint( aRetVal.X,
938                                 aRetVal.Y );
939 
940                 aPoint = pWindow->OutputToScreenPixel( aPoint );
941 
942                 aRetVal.X = aPoint.X();
943                 aRetVal.Y = aPoint.Y();
944             }
945 
946             return aRetVal;
947         }
948 
949         ::basegfx::B2DPolyPolygon getBoundMarksPolyPolygon( const ::basegfx::B2DRange& rRange )
950         {
951             ::basegfx::B2DPolyPolygon aPolyPoly;
952             ::basegfx::B2DPolygon     aPoly;
953 
954             const double nX0( rRange.getMinX() );
955             const double nY0( rRange.getMinY() );
956             const double nX1( rRange.getMaxX() );
957             const double nY1( rRange.getMaxY() );
958 
959             aPoly.append( ::basegfx::B2DPoint( nX0+4,
960                                                nY0 ) );
961             aPoly.append( ::basegfx::B2DPoint( nX0,
962                                                nY0 ) );
963             aPoly.append( ::basegfx::B2DPoint( nX0,
964                                                nY0+4 ) );
965             aPolyPoly.append( aPoly ); aPoly.clear();
966 
967             aPoly.append( ::basegfx::B2DPoint( nX1-4,
968                                                nY0 ) );
969             aPoly.append( ::basegfx::B2DPoint( nX1,
970                                                nY0 ) );
971             aPoly.append( ::basegfx::B2DPoint( nX1,
972                                                nY0+4 ) );
973             aPolyPoly.append( aPoly ); aPoly.clear();
974 
975             aPoly.append( ::basegfx::B2DPoint( nX0+4,
976                                                nY1 ) );
977             aPoly.append( ::basegfx::B2DPoint( nX0,
978                                                nY1 ) );
979             aPoly.append( ::basegfx::B2DPoint( nX0,
980                                                nY1-4 ) );
981             aPolyPoly.append( aPoly ); aPoly.clear();
982 
983             aPoly.append( ::basegfx::B2DPoint( nX1-4,
984                                                nY1 ) );
985             aPoly.append( ::basegfx::B2DPoint( nX1,
986                                                nY1 ) );
987             aPoly.append( ::basegfx::B2DPoint( nX1,
988                                                nY1-4 ) );
989             aPolyPoly.append( aPoly );
990 
991             return aPolyPoly;
992         }
993 
994         int calcGradientStepCount( ::basegfx::B2DHomMatrix&      rTotalTransform,
995                                    const rendering::ViewState&   viewState,
996                                    const rendering::RenderState& renderState,
997                                    const rendering::Texture&     texture,
998                                    int                           nColorSteps )
999         {
1000             // calculate overall texture transformation (directly from
1001             // texture to device space).
1002             ::basegfx::B2DHomMatrix aMatrix;
1003 
1004             rTotalTransform.identity();
1005             ::basegfx::unotools::homMatrixFromAffineMatrix( rTotalTransform,
1006                                                             texture.AffineTransform );
1007             ::canvas::tools::mergeViewAndRenderTransform(aMatrix,
1008                                                          viewState,
1009                                                          renderState);
1010             rTotalTransform *= aMatrix; // prepend total view/render transformation
1011 
1012             // determine size of gradient in device coordinate system
1013             // (to e.g. determine sensible number of gradient steps)
1014             ::basegfx::B2DPoint aLeftTop( 0.0, 0.0 );
1015             ::basegfx::B2DPoint aLeftBottom( 0.0, 1.0 );
1016             ::basegfx::B2DPoint aRightTop( 1.0, 0.0 );
1017             ::basegfx::B2DPoint aRightBottom( 1.0, 1.0 );
1018 
1019             aLeftTop	*= rTotalTransform;
1020             aLeftBottom *= rTotalTransform;
1021             aRightTop 	*= rTotalTransform;
1022             aRightBottom*= rTotalTransform;
1023 
1024             // longest line in gradient bound rect
1025             const int nGradientSize(
1026                 static_cast<int>(
1027                     ::std::max(
1028                         ::basegfx::B2DVector(aRightBottom-aLeftTop).getLength(),
1029                         ::basegfx::B2DVector(aRightTop-aLeftBottom).getLength() ) + 1.0 ) );
1030 
1031             // typical number for pixel of the same color (strip size)
1032             const int nStripSize( nGradientSize < 50 ? 2 : 4 );
1033 
1034             // use at least three steps, and at utmost the number of color
1035             // steps
1036             return ::std::max( 3,
1037                                ::std::min(
1038                                    nGradientSize / nStripSize,
1039                                    nColorSteps ) );
1040         }
1041 
1042 	} // namespace tools
1043 
1044 } // namespace canvas
1045