Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include <vcl/rendergraphicrasterizer.hxx>
30 : : #include <vcl/svapp.hxx>
31 : : #include <vcl/wrkwin.hxx>
32 : : #include <vcl/virdev.hxx>
33 : : #include <vcl/unohelp.hxx>
34 : : #include <vcl/bmpacc.hxx>
35 : : #include <vcl/graph.hxx>
36 : : #include <tools/stream.hxx>
37 : : #include <comphelper/processfactory.hxx>
38 : : #include <unotools/streamwrap.hxx>
39 : :
40 : : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
41 : :
42 : : #include <boost/scoped_ptr.hpp>
43 : :
44 : : #define VCL_SERVICENAME_RASTERIZER_SVG "com.sun.star.graphic.GraphicRasterizer_RSVG"
45 : :
46 : : using namespace com::sun::star;
47 : :
48 : : namespace vcl
49 : : {
50 : : // ---------------------------------------------------------
51 : : // - maximum extent in pixel for graphics to be rasterized -
52 : : // ---------------------------------------------------------
53 : :
54 : : static const sal_uInt32 nRasterizerDefaultExtent = 4096;
55 : :
56 : : // ---------------------------
57 : : // - RenderGraphicRasterizer -
58 : : // ---------------------------
59 : :
60 : 0 : RenderGraphicRasterizer::RenderGraphicRasterizer( const RenderGraphic& rRenderGraphic ) :
61 : : maRenderGraphic( rRenderGraphic ),
62 : : mfRotateAngle( 0.0 ),
63 : : mfShearAngleX( 0.0 ),
64 [ # # ]: 0 : mfShearAngleY( 0.0 )
65 : : {
66 : 0 : }
67 : :
68 : : // -------------------------------------------------------------------------
69 : :
70 : 0 : RenderGraphicRasterizer::RenderGraphicRasterizer( const RenderGraphicRasterizer& rRenderGraphicRasterizer ) :
71 : : maRenderGraphic( rRenderGraphicRasterizer.maRenderGraphic ),
72 : : mxRasterizer( rRenderGraphicRasterizer.mxRasterizer ),
73 : : maBitmapEx( rRenderGraphicRasterizer.maBitmapEx ),
74 : : maDefaultSizePixel( rRenderGraphicRasterizer.maDefaultSizePixel ),
75 : : mfRotateAngle( rRenderGraphicRasterizer.mfRotateAngle ),
76 : : mfShearAngleX( rRenderGraphicRasterizer.mfShearAngleX ),
77 [ # # ]: 0 : mfShearAngleY( rRenderGraphicRasterizer.mfShearAngleY )
78 : : {
79 : 0 : }
80 : :
81 : : // -------------------------------------------------------------------------
82 : :
83 [ # # ]: 0 : RenderGraphicRasterizer::~RenderGraphicRasterizer()
84 : : {
85 [ # # ]: 0 : }
86 : :
87 : : // -------------------------------------------------------------------------
88 : :
89 : 0 : RenderGraphicRasterizer& RenderGraphicRasterizer::operator=(
90 : : const RenderGraphicRasterizer& rRenderGraphicRasterizer )
91 : : {
92 : 0 : maRenderGraphic = rRenderGraphicRasterizer.maRenderGraphic;
93 : 0 : maBitmapEx = rRenderGraphicRasterizer.maBitmapEx;
94 : 0 : maDefaultSizePixel = rRenderGraphicRasterizer.maDefaultSizePixel;
95 : 0 : mfRotateAngle = rRenderGraphicRasterizer.mfRotateAngle;
96 : 0 : mfShearAngleX = rRenderGraphicRasterizer.mfShearAngleX;
97 : 0 : mfShearAngleY = rRenderGraphicRasterizer.mfShearAngleY;
98 : 0 : mxRasterizer = rRenderGraphicRasterizer.mxRasterizer;
99 : :
100 : 0 : return( *this );
101 : : }
102 : :
103 : : // -------------------------------------------------------------------------
104 : :
105 : 0 : const Size& RenderGraphicRasterizer::GetDefaultSizePixel() const
106 : : {
107 : 0 : const_cast< RenderGraphicRasterizer* >( this )->InitializeRasterizer();
108 : :
109 : 0 : return( maDefaultSizePixel );
110 : : }
111 : :
112 : : // -------------------------------------------------------------------------
113 : :
114 : 0 : BitmapEx RenderGraphicRasterizer::GetReplacement() const
115 : : {
116 : 0 : BitmapEx aRet( Rasterize( GetDefaultSizePixel() ) );
117 : :
118 [ # # ]: 0 : aRet.SetPrefSize( GetPrefSize() );
119 [ # # ][ # # ]: 0 : aRet.SetPrefMapMode( GetPrefMapMode() );
[ # # ]
120 : :
121 : 0 : return( aRet );
122 : : }
123 : :
124 : : // -------------------------------------------------------------------------
125 : :
126 : 0 : Size RenderGraphicRasterizer::GetPrefSize() const
127 : : {
128 [ # # ]: 0 : const Size aSizePixel( GetDefaultSizePixel() );
129 : 0 : boost::scoped_ptr< VirtualDevice > xCompVDev;
130 : 0 : OutputDevice* pCompDev = NULL;
131 : :
132 : : #ifndef NO_GETAPPWINDOW
133 [ # # ]: 0 : pCompDev = Application::GetAppWindow();
134 : : #endif
135 : :
136 [ # # ]: 0 : if( !pCompDev )
137 : : {
138 [ # # ][ # # ]: 0 : xCompVDev.reset( new VirtualDevice );
[ # # ]
139 : 0 : pCompDev = xCompVDev.get();
140 : : }
141 : :
142 [ # # ][ # # ]: 0 : return( pCompDev->PixelToLogic( aSizePixel, GetPrefMapMode() ) );
[ # # ][ # # ]
143 : : }
144 : :
145 : : // -------------------------------------------------------------------------
146 : :
147 : 0 : MapMode RenderGraphicRasterizer::GetPrefMapMode() const
148 : : {
149 : 0 : return( MapMode( MAP_100TH_MM ) );
150 : : }
151 : :
152 : : // -------------------------------------------------------------------------
153 : :
154 : 0 : const BitmapEx& RenderGraphicRasterizer::Rasterize( const Size& rSizePixel,
155 : : double fRotateAngle,
156 : : double fShearAngleX,
157 : : double fShearAngleY,
158 : : sal_uInt32 nMaxExtent ) const
159 : : {
160 : 0 : const bool bRasterize = !maRenderGraphic.IsEmpty() &&
161 : 0 : rSizePixel.Width() && rSizePixel.Height() &&
162 : 0 : ( maBitmapEx.IsEmpty() ||
163 : 0 : ( rSizePixel != maBitmapEx.GetSizePixel() ) ||
164 : : ( fRotateAngle != mfRotateAngle ) ||
165 : : ( fShearAngleX != mfShearAngleX ) ||
166 [ # # ][ # # ]: 0 : ( fShearAngleY != mfShearAngleY ) );
[ # # ][ # #
# # # # #
# # # ]
167 : :
168 [ # # ]: 0 : if( bRasterize )
169 : : {
170 : 0 : const_cast< RenderGraphicRasterizer* >( this )->InitializeRasterizer();
171 : :
172 [ # # ]: 0 : if( mxRasterizer.is() )
173 : : {
174 : 0 : sal_uInt32 nWidth = labs( rSizePixel.Width() );
175 : 0 : sal_uInt32 nHeight = labs( rSizePixel.Height() );
176 : :
177 : : // limiting the extent of the rastered bitmap
178 [ # # ]: 0 : if( VCL_RASTERIZER_UNLIMITED_EXTENT != nMaxExtent )
179 : : {
180 [ # # ]: 0 : if( VCL_RASTERIZER_DEFAULT_EXTENT == nMaxExtent )
181 : : {
182 : 0 : nMaxExtent = nRasterizerDefaultExtent;
183 : : }
184 : :
185 [ # # ][ # # ]: 0 : if( ( nWidth > nMaxExtent ) || ( nHeight > nMaxExtent ) )
186 : : {
187 [ # # ]: 0 : const double fScale = static_cast< double >( nMaxExtent ) / ::std::max( nWidth, nHeight );
188 : :
189 : 0 : nWidth = FRound( nWidth * fScale );
190 : 0 : nHeight = FRound( nHeight * fScale );
191 : : }
192 : : }
193 : :
194 [ # # ]: 0 : if( !ImplRasterizeFromCache( const_cast< RenderGraphicRasterizer& >( *this ),
195 [ # # ]: 0 : Size( nWidth, nHeight ), fRotateAngle, fShearAngleX, fShearAngleY ) )
196 : : {
197 : : try
198 : : {
199 [ # # ]: 0 : const uno::Sequence< beans::PropertyValue > aPropertySeq;
200 [ # # ]: 0 : const Graphic aRasteredGraphic( mxRasterizer->rasterize( nWidth,
201 : : nHeight,
202 : : fRotateAngle,
203 : : fShearAngleX,
204 : : fShearAngleY,
205 [ # # ][ # # ]: 0 : aPropertySeq ) );
206 : :
207 [ # # ][ # # ]: 0 : maBitmapEx = aRasteredGraphic.GetBitmapEx();
[ # # ]
208 : 0 : mfRotateAngle = fRotateAngle;
209 : 0 : mfShearAngleX = fShearAngleX;
210 : 0 : mfShearAngleY = fShearAngleY;
211 : :
212 [ # # ][ # # ]: 0 : ImplUpdateCache( *this );
[ # # ]
213 : :
214 : : // OSL_TRACE( "Wanted: %d x %d / Got: %d x %d", rSizePixel.Width(), rSizePixel.Height(), maBitmapEx.GetSizePixel().Width(), maBitmapEx.GetSizePixel().Height() );
215 : : }
216 [ # # ]: 0 : catch( ... )
217 : : {
218 : : OSL_TRACE( "caught exception during rasterization" );
219 : : }
220 : : }
221 : : }
222 : : }
223 : :
224 : 0 : return( maBitmapEx );
225 : : }
226 : :
227 : : // -------------------------------------------------------------------------
228 : :
229 : 0 : void RenderGraphicRasterizer::InitializeRasterizer()
230 : : {
231 [ # # ][ # # ]: 0 : if( !mxRasterizer.is() && !ImplInitializeFromCache( *this ) )
[ # # ]
232 : : {
233 [ # # ]: 0 : uno::Reference< lang::XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory() );
234 : :
235 : 0 : maDefaultSizePixel.Width() = maDefaultSizePixel.Height() = 0;
236 : :
237 [ # # ][ # # ]: 0 : if( !maRenderGraphic.IsEmpty() )
238 : : {
239 : 0 : rtl::OUString aServiceName;
240 : :
241 [ # # ]: 0 : if( 0 == maRenderGraphic.GetGraphicDataMimeType().compareToAscii( "image/svg+xml" ) )
242 : : {
243 [ # # ]: 0 : aServiceName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( VCL_SERVICENAME_RASTERIZER_SVG ) );
244 : : }
245 : :
246 [ # # ]: 0 : if( !aServiceName.isEmpty() )
247 : : {
248 [ # # ][ # # ]: 0 : mxRasterizer.set( xFactory->createInstance( aServiceName ), uno::UNO_QUERY );
[ # # ]
249 : :
250 [ # # ]: 0 : if( mxRasterizer.is() )
251 : : {
252 : 0 : boost::scoped_ptr< VirtualDevice > xCompVDev;
253 : 0 : OutputDevice* pCompDev = NULL;
254 : :
255 : : #ifndef NO_GETAPPWINDOW
256 [ # # ]: 0 : pCompDev = Application::GetAppWindow();
257 : : #endif
258 : :
259 [ # # ]: 0 : if( !pCompDev )
260 : : {
261 [ # # ][ # # ]: 0 : xCompVDev.reset( new VirtualDevice );
[ # # ]
262 : 0 : pCompDev = xCompVDev.get();
263 : : }
264 : :
265 [ # # ][ # # ]: 0 : const Size aDPI( pCompDev->LogicToPixel( Size( 1, 1 ), MAP_INCH ) );
[ # # ]
266 : 0 : awt::Size aSizePixel;
267 : 0 : SvMemoryStream aMemStm( maRenderGraphic.GetGraphicData().get(),
268 : : maRenderGraphic.GetGraphicDataLength(),
269 [ # # ]: 0 : STREAM_READ );
270 : :
271 [ # # ][ # # ]: 0 : uno::Reference< io::XInputStream > xIStm( new utl::OSeekableInputStreamWrapper( aMemStm ) );
[ # # ]
272 : :
273 : : try
274 : : {
275 [ # # ][ # # ]: 0 : if( !xIStm.is() || !mxRasterizer->initializeData( xIStm, aDPI.Width(), aDPI.Height(), aSizePixel ) )
[ # # ][ # # ]
[ # # ]
276 : : {
277 : 0 : mxRasterizer.clear();
278 : : }
279 : : else
280 : : {
281 : 0 : maDefaultSizePixel.Width() = aSizePixel.Width;
282 : 0 : maDefaultSizePixel.Height() = aSizePixel.Height;
283 : : }
284 : : }
285 [ # # ]: 0 : catch( ... )
286 : : {
287 : : OSL_TRACE( "caught exception during initialization of SVG rasterizer component" );
288 : 0 : mxRasterizer.clear();
289 [ # # ][ # # ]: 0 : }
290 : : }
291 : 0 : }
292 : 0 : }
293 : : }
294 : 0 : }
295 : :
296 : : // ------------------------------------------------------------------------------
297 : :
298 : 0 : RenderGraphicRasterizer::RenderGraphicRasterizerCache& RenderGraphicRasterizer::ImplGetCache()
299 : : {
300 : : static RenderGraphicRasterizerCache* pCache = NULL;
301 : :
302 [ # # ]: 0 : if( !pCache )
303 : : {
304 [ # # ]: 0 : pCache = new RenderGraphicRasterizerCache;
305 : : }
306 : :
307 : 0 : return( *pCache );
308 : : }
309 : :
310 : : // ------------------------------------------------------------------------------
311 : :
312 : 0 : bool RenderGraphicRasterizer::ImplInitializeFromCache( RenderGraphicRasterizer& rRasterizer )
313 : : {
314 : 0 : RenderGraphicRasterizerCache& rCache = ImplGetCache();
315 : 0 : bool bRet = false;
316 : :
317 [ # # ]: 0 : for( sal_uInt32 i = 0; i < rCache.size(); ++i )
318 : : {
319 : 0 : const RenderGraphicRasterizer* pCheck = &rCache[ i ];
320 : :
321 [ # # ][ # # ]: 0 : if( pCheck && pCheck->mxRasterizer.is() && ( pCheck->maRenderGraphic == rRasterizer.maRenderGraphic ) )
[ # # ][ # # ]
322 : : {
323 : : // OSL_TRACE( "Hit RenderGraphicRasterizer cache for initialization" );
324 : :
325 [ # # ]: 0 : rRasterizer.mxRasterizer = pCheck->mxRasterizer;
326 : 0 : rRasterizer.maDefaultSizePixel = pCheck->maDefaultSizePixel;
327 : :
328 : : // put found Rasterizer at begin of deque
329 [ # # ][ # # ]: 0 : const RenderGraphicRasterizer aFound( rCache[ i ] );
330 : :
331 [ # # ][ # # ]: 0 : rCache.erase( rCache.begin() + i );
332 [ # # ]: 0 : rCache.push_front( aFound );
333 : :
334 : :
335 [ # # ]: 0 : bRet = true;
336 : : }
337 : : }
338 : :
339 : 0 : return( bRet );
340 : : }
341 : :
342 : : // ------------------------------------------------------------------------------
343 : :
344 : 0 : bool RenderGraphicRasterizer::ImplRasterizeFromCache( RenderGraphicRasterizer& rRasterizer,
345 : : const Size& rSizePixel,
346 : : double fRotateAngle,
347 : : double fShearAngleX,
348 : : double fShearAngleY )
349 : : {
350 : 0 : RenderGraphicRasterizerCache& rCache = ImplGetCache();
351 : 0 : bool bRet = false;
352 : :
353 [ # # ]: 0 : for( sal_uInt32 i = 0; i < rCache.size(); ++i )
354 : : {
355 : 0 : const RenderGraphicRasterizer& rCheck = rCache[ i ];
356 : :
357 [ # # # # : 0 : if( rCheck.mxRasterizer.is() && rRasterizer.mxRasterizer.is() &&
# # # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
358 : 0 : ( ( rCheck.mxRasterizer == rRasterizer.mxRasterizer ) ||
359 : 0 : ( rRasterizer.maRenderGraphic == rCheck.maRenderGraphic ) ) &&
360 : 0 : ( rCheck.maBitmapEx.GetSizePixel() == rSizePixel ) &&
361 : : ( rCheck.mfRotateAngle == fRotateAngle ) &&
362 : : ( rCheck.mfShearAngleX == fShearAngleX ) &&
363 : : ( rCheck.mfShearAngleY == fShearAngleY ) )
364 : : {
365 : : // OSL_TRACE( "Hit RenderGraphicRasterizer cache for rasterizing" );
366 : :
367 [ # # ]: 0 : rRasterizer.maBitmapEx = rCheck.maBitmapEx;
368 : 0 : rRasterizer.mfRotateAngle = fRotateAngle;
369 : 0 : rRasterizer.mfShearAngleX = fShearAngleX;
370 : 0 : rRasterizer.mfShearAngleY = fShearAngleY;
371 : :
372 : : // put found Rasterizer at begin of deque
373 [ # # ][ # # ]: 0 : const RenderGraphicRasterizer aFound( rCache[ i ] );
374 : :
375 [ # # ][ # # ]: 0 : rCache.erase( rCache.begin() + i );
376 [ # # ]: 0 : rCache.push_front( aFound );
377 : :
378 [ # # ]: 0 : bRet = true;
379 : : }
380 : : }
381 : :
382 : 0 : return( bRet );
383 : : }
384 : :
385 : : // ------------------------------------------------------------------------------
386 : :
387 : 0 : void RenderGraphicRasterizer::ImplUpdateCache( const RenderGraphicRasterizer& rRasterizer )
388 : : {
389 : 0 : RenderGraphicRasterizerCache& rCache = ImplGetCache();
390 : 0 : const sal_uInt32 nMaxCacheSize = 8;
391 : :
392 [ # # ]: 0 : if( rCache.size() < nMaxCacheSize )
393 : : {
394 : 0 : rCache.push_front( rRasterizer );
395 : : }
396 : : else
397 : : {
398 : 0 : rCache.pop_back();
399 : 0 : rCache.push_front( rRasterizer );
400 : : }
401 : 0 : }
402 : :
403 : : } // VCL
404 : :
405 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|