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 <com/sun/star/rendering/XSimpleCanvas.hpp>
32 #include <com/sun/star/rendering/CompositeOperation.hpp>
33 #include <com/sun/star/rendering/PanoseLetterForm.hpp>
34 #include <com/sun/star/rendering/PanoseWeight.hpp>
35 #include <com/sun/star/lang/XServiceName.hpp>
36 
37 #include <o3tl/lazy_update.hxx>
38 #include <cppuhelper/factory.hxx>
39 #include <cppuhelper/implementationentry.hxx>
40 #include <cppuhelper/compbase2.hxx>
41 #include <cppuhelper/basemutex.hxx>
42 
43 #include <comphelper/servicedecl.hxx>
44 
45 #include <basegfx/matrix/b2dhommatrix.hxx>
46 #include <basegfx/matrix/b2dhommatrixtools.hxx>
47 
48 #include "canvas/canvastools.hxx"
49 
50 #include <boost/bind.hpp>
51 
52 #define SERVICE_NAME "com.sun.star.rendering.SimpleCanvas"
53 
54 using namespace ::com::sun::star;
55 using namespace canvas;
56 
57 namespace
58 {
59     inline uno::Sequence< double > color2Sequence( sal_Int32 const& nColor  	)
60     {
61         // TODO(F3): Color management
62         uno::Sequence< double > aRes( 4 );
63 
64         aRes[0] = static_cast<sal_uInt8>( (nColor&0xFF000000U) >> 24U ) / 255.0;
65         aRes[1] = static_cast<sal_uInt8>( (nColor&0x00FF0000U) >> 16U ) / 255.0;
66         aRes[2] = static_cast<sal_uInt8>( (nColor&0x0000FF00U) >>  8U ) / 255.0;
67         aRes[3] = static_cast<sal_uInt8>( (nColor&0x000000FFU) )        / 255.0;
68 
69         return aRes;
70     }
71 
72     inline uno::Reference< rendering::XPolyPolygon2D > rect2Poly( uno::Reference<rendering::XGraphicDevice> const& xDevice,
73                                                                   geometry::RealRectangle2D const&                 rRect )
74     {
75         uno::Sequence< geometry::RealPoint2D > rectSequence( 4 );
76         geometry::RealPoint2D* pOutput = rectSequence.getArray();
77         pOutput[0] = geometry::RealPoint2D( rRect.X1, rRect.Y1 );
78         pOutput[1] = geometry::RealPoint2D( rRect.X2, rRect.Y1 );
79         pOutput[2] = geometry::RealPoint2D( rRect.X2, rRect.Y2 );
80         pOutput[3] = geometry::RealPoint2D( rRect.X1, rRect.Y2 );
81 
82         uno::Sequence< uno::Sequence< geometry::RealPoint2D > > sequenceSequence( 1 );
83         sequenceSequence[0] = rectSequence;
84 
85         uno::Reference< rendering::XPolyPolygon2D > xRes(
86             xDevice->createCompatibleLinePolyPolygon( sequenceSequence ),
87             uno::UNO_QUERY );
88         if( xRes.is() )
89             xRes->setClosed( 0, sal_True );
90         return xRes;
91     }
92 
93     struct SimpleRenderState
94     {
95         o3tl::LazyUpdate<sal_Int32,
96                          uno::Sequence<double>,
97                          o3tl::LAZYUPDATE_FUNCTION_TAG >              m_aPenColor;
98         o3tl::LazyUpdate<sal_Int32,
99                          uno::Sequence<double>,
100                          o3tl::LAZYUPDATE_FUNCTION_TAG >              m_aFillColor;
101         o3tl::LazyUpdate<geometry::RealRectangle2D,
102                          uno::Reference< rendering::XPolyPolygon2D >,
103                          o3tl::LAZYUPDATE_FUNCTOR_TAG >               m_aRectClip;
104         geometry::AffineMatrix2D                                      m_aTransformation;
105 
106         explicit SimpleRenderState( uno::Reference<rendering::XGraphicDevice> const& xDevice ) :
107             m_aPenColor( &color2Sequence),
108             m_aFillColor( &color2Sequence ),
109             m_aRectClip( boost::bind( &rect2Poly,
110                                       xDevice,
111                                       _1 )),
112             m_aTransformation()
113         {
114             tools::setIdentityAffineMatrix2D( m_aTransformation );
115         }
116     };
117 
118 
119     typedef ::cppu::WeakComponentImplHelper2< ::com::sun::star::rendering::XSimpleCanvas,
120                                               ::com::sun::star::lang::XServiceName >	SimpleCanvasBase;
121 
122     class SimpleCanvasImpl : private cppu::BaseMutex,
123                              public SimpleCanvasBase
124     {
125     private:
126         bool isStrokingEnabled() const
127         {
128             return maRenderState.m_aPenColor.getInValue() && sal_Int32(0xFF) != 0;
129         }
130 
131         rendering::RenderState createStrokingRenderState() const
132         {
133             return rendering::RenderState(maRenderState.m_aTransformation,
134                                           *maRenderState.m_aRectClip,
135                                           *maRenderState.m_aPenColor,
136                                           rendering::CompositeOperation::OVER);
137         }
138 
139         bool isFillingEnabled() const
140         {
141             return maRenderState.m_aFillColor.getInValue() && sal_Int32(0xFF) != 0;
142         }
143 
144         rendering::RenderState createFillingRenderState() const
145         {
146             return rendering::RenderState(maRenderState.m_aTransformation,
147                                           *maRenderState.m_aRectClip,
148                                           *maRenderState.m_aFillColor,
149                                           rendering::CompositeOperation::OVER);
150         }
151 
152         static uno::Reference<rendering::XCanvas> grabCanvas( uno::Sequence<uno::Any> const& rArgs )
153         {
154             uno::Reference<rendering::XCanvas> xRet;
155 
156             // can't do much without an XCanvas, can't we?
157             if( rArgs.getLength() < 1 )
158                 throw lang::IllegalArgumentException();
159 
160             xRet.set( rArgs[0], uno::UNO_QUERY );
161 
162             // can't do much without an XCanvas, can't we?
163             if( !xRet.is() )
164                 throw lang::IllegalArgumentException();
165 
166             return xRet;
167         }
168 
169     public:
170         SimpleCanvasImpl( const uno::Sequence< uno::Any >&                aArguments,
171                           const uno::Reference< uno::XComponentContext >&  ) :
172             SimpleCanvasBase( m_aMutex ),
173             mxCanvas( grabCanvas(aArguments) ),
174             maFont(boost::bind( &rendering::XCanvas::createFont,
175                                 boost::cref(mxCanvas),
176                                 _1,
177                                 uno::Sequence< beans::PropertyValue >(),
178                                 geometry::Matrix2D() )),
179             maViewState(),
180             maRenderState( mxCanvas->getDevice() )
181         {
182             tools::initViewState(maViewState);
183         }
184 
185         ///////////////////////////////////////////////////////////////////////////////////////////////
186 
187     private:
188         // Ifc XServiceName
189         virtual ::rtl::OUString SAL_CALL getServiceName(  ) throw (uno::RuntimeException)
190         {
191             return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SERVICE_NAME ) );
192         }
193 
194         // Ifc XSimpleCanvas
195         virtual void SAL_CALL selectFont( const ::rtl::OUString& sFontName,
196                                           double                 size,
197                                           ::sal_Bool             bold,
198                                           ::sal_Bool             italic ) throw (uno::RuntimeException)
199         {
200             ::osl::MutexGuard aGuard( m_aMutex );
201 
202             maFont->FontDescription.FamilyName = sFontName;
203             maFont->CellSize = size;
204             maFont->FontDescription.FontDescription.Weight =
205                 bold ? rendering::PanoseWeight::BOLD : rendering::PanoseWeight::MEDIUM;
206             maFont->FontDescription.FontDescription.Letterform =
207                 italic ? rendering::PanoseLetterForm::OBLIQUE_CONTACT : rendering::PanoseLetterForm::ANYTHING;
208         }
209 
210         virtual void SAL_CALL setPenColor( ::sal_Int32 nsRgbaColor ) throw (uno::RuntimeException)
211         {
212             ::osl::MutexGuard aGuard( m_aMutex );
213             *(maRenderState.m_aPenColor) = nsRgbaColor;
214         }
215 
216         virtual void SAL_CALL setFillColor( ::sal_Int32 nsRgbaColor ) throw (uno::RuntimeException)
217         {
218             ::osl::MutexGuard aGuard( m_aMutex );
219             *(maRenderState.m_aFillColor) = nsRgbaColor;
220         }
221 
222         virtual void SAL_CALL setRectClip( const geometry::RealRectangle2D& aRect ) throw (uno::RuntimeException)
223         {
224             ::osl::MutexGuard aGuard( m_aMutex );
225             *(maRenderState.m_aRectClip) = aRect;
226         }
227 
228         virtual void SAL_CALL setTransformation( const geometry::AffineMatrix2D& aTransform ) throw (uno::RuntimeException)
229         {
230             ::osl::MutexGuard aGuard( m_aMutex );
231             maRenderState.m_aTransformation = aTransform;
232         }
233 
234         virtual void SAL_CALL drawPixel( const geometry::RealPoint2D& aPoint ) throw (uno::RuntimeException)
235         {
236             ::osl::MutexGuard aGuard( m_aMutex );
237             mxCanvas->drawPoint(aPoint,
238                                 maViewState,
239                                 createFillingRenderState());
240         }
241 
242         virtual void SAL_CALL drawLine( const geometry::RealPoint2D& aStartPoint,
243                                         const geometry::RealPoint2D& aEndPoint ) throw (uno::RuntimeException)
244         {
245             ::osl::MutexGuard aGuard( m_aMutex );
246             mxCanvas->drawLine(aStartPoint,
247                                aEndPoint,
248                                maViewState,
249                                createStrokingRenderState());
250         }
251 
252         virtual void SAL_CALL drawRect( const geometry::RealRectangle2D& aRect ) throw (uno::RuntimeException)
253         {
254             ::osl::MutexGuard aGuard( m_aMutex );
255             uno::Reference< rendering::XPolyPolygon2D > xPoly(
256                 rect2Poly( mxCanvas->getDevice(),
257                            aRect));
258 
259             if( isFillingEnabled() )
260                 mxCanvas->drawPolyPolygon(xPoly,
261                                           maViewState,
262                                           createFillingRenderState());
263             if( isStrokingEnabled() )
264                 mxCanvas->drawPolyPolygon(xPoly,
265                                           maViewState,
266                                           createStrokingRenderState());
267         }
268 
269         virtual void SAL_CALL drawPolyPolygon( const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon ) throw (uno::RuntimeException)
270         {
271             ::osl::MutexGuard aGuard( m_aMutex );
272 
273             if( isFillingEnabled() )
274                 mxCanvas->drawPolyPolygon(xPolyPolygon,
275                                           maViewState,
276                                           createFillingRenderState());
277             if( isStrokingEnabled() )
278                 mxCanvas->drawPolyPolygon(xPolyPolygon,
279                                           maViewState,
280                                           createStrokingRenderState());
281         }
282 
283         virtual void SAL_CALL drawText( const rendering::StringContext& aText,
284                                         const geometry::RealPoint2D&    aOutPos,
285                                         ::sal_Int8                      nTextDirection ) throw (uno::RuntimeException)
286         {
287             ::osl::MutexGuard aGuard( m_aMutex );
288             const basegfx::B2DHomMatrix offsetTransform(basegfx::tools::createTranslateB2DHomMatrix(aOutPos.X,aOutPos.Y));
289             rendering::RenderState aRenderState( createStrokingRenderState() );
290             tools::appendToRenderState(aRenderState, offsetTransform);
291 
292             mxCanvas->drawText(aText,
293                                maFont.getOutValue(),
294                                maViewState,
295                                aRenderState,
296                                nTextDirection);
297         }
298 
299         virtual void SAL_CALL drawBitmap( const uno::Reference< rendering::XBitmap >& xBitmap,
300                                           const geometry::RealPoint2D&                aLeftTop ) throw (uno::RuntimeException)
301         {
302             ::osl::MutexGuard aGuard( m_aMutex );
303             const basegfx::B2DHomMatrix offsetTransform(basegfx::tools::createTranslateB2DHomMatrix(aLeftTop.X,aLeftTop.Y));
304             rendering::RenderState aRenderState( createStrokingRenderState() );
305             tools::appendToRenderState(aRenderState, offsetTransform);
306 
307             mxCanvas->drawBitmap(xBitmap,maViewState,aRenderState);
308         }
309 
310         virtual uno::Reference< rendering::XGraphicDevice > SAL_CALL getDevice(  ) throw (uno::RuntimeException)
311         {
312             ::osl::MutexGuard aGuard( m_aMutex );
313             return mxCanvas->getDevice();
314         }
315 
316         virtual uno::Reference< rendering::XCanvas > SAL_CALL getCanvas(  ) throw (uno::RuntimeException)
317         {
318             ::osl::MutexGuard aGuard( m_aMutex );
319             return mxCanvas;
320         }
321 
322         virtual rendering::FontMetrics SAL_CALL getFontMetrics(  ) throw (uno::RuntimeException)
323         {
324             ::osl::MutexGuard aGuard( m_aMutex );
325             return maFont.getOutValue()->getFontMetrics();
326         }
327 
328         virtual uno::Reference< rendering::XCanvasFont > SAL_CALL getCurrentFont(  ) throw (uno::RuntimeException)
329         {
330             ::osl::MutexGuard aGuard( m_aMutex );
331             return maFont.getOutValue();
332         }
333 
334         virtual ::sal_Int32 SAL_CALL getCurrentPenColor(  ) throw (uno::RuntimeException)
335         {
336             ::osl::MutexGuard aGuard( m_aMutex );
337             return maRenderState.m_aPenColor.getInValue();
338         }
339 
340         virtual ::sal_Int32 SAL_CALL getCurrentFillColor(  ) throw (uno::RuntimeException)
341         {
342             ::osl::MutexGuard aGuard( m_aMutex );
343             return maRenderState.m_aFillColor.getInValue();
344         }
345 
346         virtual geometry::RealRectangle2D SAL_CALL getCurrentClipRect(  ) throw (uno::RuntimeException)
347         {
348             ::osl::MutexGuard aGuard( m_aMutex );
349             return maRenderState.m_aRectClip.getInValue();
350         }
351 
352         virtual geometry::AffineMatrix2D SAL_CALL getCurrentTransformation(  ) throw (uno::RuntimeException)
353         {
354             ::osl::MutexGuard aGuard( m_aMutex );
355             return maRenderState.m_aTransformation;
356         }
357 
358         virtual rendering::ViewState SAL_CALL getCurrentViewState(  ) throw (uno::RuntimeException)
359         {
360             ::osl::MutexGuard aGuard( m_aMutex );
361             return maViewState;
362         }
363 
364         virtual rendering::RenderState SAL_CALL getCurrentRenderState( sal_Bool bUseFillColor ) throw (uno::RuntimeException)
365         {
366             ::osl::MutexGuard aGuard( m_aMutex );
367             if( bUseFillColor )
368                 return createFillingRenderState();
369             else
370                 return createStrokingRenderState();
371         }
372 
373         ///////////////////////////////////////////////////////////////////////////////////////////////
374 
375         typedef o3tl::LazyUpdate<
376             rendering::FontRequest,
377             uno::Reference< rendering::XCanvasFont >,
378             o3tl::LAZYUPDATE_FUNCTOR_TAG > SimpleFont;
379 
380         uno::Reference<rendering::XCanvas> mxCanvas;
381         SimpleFont                         maFont;
382         rendering::ViewState               maViewState;
383         SimpleRenderState                  maRenderState;
384     };
385 
386     namespace sdecl = comphelper::service_decl;
387 #if defined (__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ <= 3)
388     sdecl::class_<SimpleCanvasImpl, sdecl::with_args<true> > serviceImpl;
389     const sdecl::ServiceDecl simpleCanvasDecl(
390         serviceImpl,
391 #else
392     const sdecl::ServiceDecl simpleCanvasDecl(
393         sdecl::class_<SimpleCanvasImpl, sdecl::with_args<true> >(),
394 #endif
395         "com.sun.star.comp.rendering.SimpleCanvas",
396         SERVICE_NAME );
397 }
398 
399 // The C shared lib entry points
400 COMPHELPER_SERVICEDECL_EXPORTS1(simpleCanvasDecl)
401