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 : :
30 : : #include <com/sun/star/i18n/ScriptType.hpp>
31 : : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
32 : : #include <comphelper/processfactory.hxx>
33 : : #include "swfwriter.hxx"
34 : : #include <vcl/metaact.hxx>
35 : : #include <vcl/gdimtf.hxx>
36 : : #include <vcl/bmpacc.hxx>
37 : : #include <vcl/virdev.hxx>
38 : : #include <vcl/metric.hxx>
39 : : #include <basegfx/matrix/b2dhommatrixtools.hxx>
40 : : #include <svtools/filter.hxx>
41 : : #include <vcl/graphictools.hxx>
42 : : #include <vcl/rendergraphicrasterizer.hxx>
43 : :
44 : : #ifndef _ZLIB_H
45 : : #ifdef SYSTEM_ZLIB
46 : : #include <zlib.h>
47 : : #else
48 : : #include <external/zlib/zlib.h>
49 : : #endif
50 : : #endif
51 : :
52 : : #include <vcl/salbtype.hxx>
53 : : #include <basegfx/polygon/b2dpolygon.hxx>
54 : : #include <basegfx/polygon/b2dpolypolygon.hxx>
55 : :
56 : : using namespace ::swf;
57 : : using namespace ::std;
58 : : using namespace ::rtl;
59 : : using namespace ::com::sun::star::i18n;
60 : : using namespace ::com::sun::star::uno;
61 : : using namespace ::com::sun::star::lang;
62 : : using namespace ::com::sun::star::io;
63 : : using namespace ::com::sun::star::beans;
64 : :
65 : : extern sal_uInt16 getMaxBitsUnsigned( sal_uInt32 nValue );
66 : : extern sal_uInt16 getMaxBitsSigned( sal_Int32 nValue );
67 : :
68 : 0 : static MapMode aTWIPSMode( MAP_TWIP );
69 : 0 : static MapMode a100thmmMode( MAP_100TH_MM );
70 : :
71 : : // -----------------------------------------------------------------------------
72 : :
73 : 0 : Point Writer::map( const Point& rPoint ) const
74 : : {
75 : 0 : const MapMode& aSourceMapMode = mpVDev->GetMapMode();
76 : :
77 : 0 : Point retPoint = mpVDev->LogicToLogic( rPoint, &aSourceMapMode, &aTWIPSMode );
78 : :
79 : : // AS: Produces a 'possible loss of data' warning that we can't fix without
80 : : // hurting code readability.
81 : 0 : retPoint.X() = (long)( retPoint.X() * mnDocXScale );
82 : 0 : retPoint.Y() = (long)( retPoint.Y() * mnDocYScale );
83 : :
84 : 0 : return retPoint;
85 : : }
86 : :
87 : : // -----------------------------------------------------------------------------
88 : :
89 : 0 : Size Writer::map( const Size& rSize ) const
90 : : {
91 : 0 : const MapMode& aSourceMapMode = mpVDev->GetMapMode();
92 : :
93 : 0 : Size retSize = mpVDev->LogicToLogic( rSize, &aSourceMapMode, &aTWIPSMode );
94 : :
95 : : // AS: Produces a 'possible loss of data' warning that we can't fix without
96 : : // hurting code readability.
97 : 0 : retSize.Width() = (long)( retSize.Width() * mnDocXScale );
98 : 0 : retSize.Height() = (long)( retSize.Height() * mnDocYScale );
99 : :
100 : 0 : return retSize;
101 : : }
102 : :
103 : : // -----------------------------------------------------------------------------
104 : :
105 : 0 : void Writer::map( PolyPolygon& rPolyPolygon ) const
106 : : {
107 : 0 : const sal_uInt16 nPolyCount = rPolyPolygon.Count();
108 : 0 : if( nPolyCount )
109 : : {
110 : : sal_uInt16 nPoly, nPoint, nPointCount;
111 : 0 : for( nPoly = 0; nPoly < nPolyCount; nPoly++ )
112 : : {
113 : 0 : Polygon& rPoly = rPolyPolygon[nPoly];
114 : 0 : nPointCount = rPoly.GetSize();
115 : :
116 : 0 : for( nPoint = 0; nPoint < nPointCount; nPoint++ )
117 : : {
118 : 0 : rPoly[nPoint] = map( rPoly[nPoint] );
119 : : }
120 : : }
121 : : }
122 : 0 : }
123 : :
124 : : // -----------------------------------------------------------------------------
125 : :
126 : 0 : sal_Int32 Writer::mapRelative( sal_Int32 n100thMM ) const
127 : : {
128 : 0 : MapMode aSourceMapMode( mpVDev->GetMapMode() );
129 : 0 : aSourceMapMode.SetOrigin( Point() );
130 : :
131 : 0 : sal_Int32 nTwips = mpVDev->LogicToLogic( Point( n100thMM, n100thMM ), &aSourceMapMode, &aTWIPSMode ).X();
132 : 0 : return nTwips;
133 : : }
134 : :
135 : : // -----------------------------------------------------------------------------
136 : :
137 : : /**
138 : : */
139 : 0 : void Writer::Impl_addPolygon( BitStream& rBits, const Polygon& rPoly, sal_Bool bFilled )
140 : : {
141 : 0 : Point aLastPoint( rPoly[0] );
142 : :
143 : 0 : Impl_addShapeRecordChange( rBits, _Int16(aLastPoint.X()),_Int16(aLastPoint.Y()), bFilled );
144 : :
145 : 0 : sal_uInt16 i = 0, nSize = rPoly.GetSize();
146 : :
147 : 0 : double d = 16.0f;
148 : :
149 : : // points
150 : 0 : while( ( i + 1 ) < nSize )
151 : : {
152 : 0 : if( ( i + 3 ) < nSize )
153 : : {
154 : 0 : PolyFlags P1( rPoly.GetFlags( i ) );
155 : 0 : PolyFlags P4( rPoly.GetFlags( i + 3 ) );
156 : :
157 : 0 : if( ( POLY_NORMAL == P1 || POLY_SMOOTH == P1 || POLY_SYMMTR == P1 ) &&
158 : 0 : ( POLY_CONTROL == rPoly.GetFlags( i + 1 ) ) &&
159 : 0 : ( POLY_CONTROL == rPoly.GetFlags( i + 2 ) ) &&
160 : : ( POLY_NORMAL == P4 || POLY_SMOOTH == P4 || POLY_SYMMTR == P4 ) )
161 : : {
162 : : Impl_quadBezierApprox( rBits, aLastPoint, d*d,
163 : 0 : rPoly.GetPoint( i ).X(), rPoly.GetPoint( i ).Y(),
164 : 0 : rPoly.GetPoint( i+1 ).X(), rPoly.GetPoint( i+1 ).Y(),
165 : 0 : rPoly.GetPoint( i+2 ).X(), rPoly.GetPoint( i+2 ).Y(),
166 : 0 : rPoly.GetPoint( i+3 ).X(), rPoly.GetPoint( i+3 ).Y() );
167 : 0 : i += 3;
168 : 0 : continue;
169 : : }
170 : : }
171 : :
172 : 0 : ++i;
173 : :
174 : 0 : const Point aPolyPoint( rPoly[ i ] );
175 : 0 : if( aPolyPoint != aLastPoint )
176 : : {
177 : 0 : Impl_addStraightEdgeRecord( rBits, _Int16(aPolyPoint.X() - aLastPoint.X()),_Int16(aPolyPoint.Y() - aLastPoint.Y()));
178 : 0 : aLastPoint = aPolyPoint;
179 : : }
180 : : }
181 : :
182 : 0 : if( bFilled && (rPoly[0] != rPoly[nSize-1]))
183 : : {
184 : 0 : const Point aPolyPoint( rPoly[ 0 ] );
185 : 0 : if( aPolyPoint != aLastPoint )
186 : : {
187 : 0 : Impl_addStraightEdgeRecord( rBits, _Int16(aPolyPoint.X() - aLastPoint.X()),_Int16(aPolyPoint.Y() - aLastPoint.Y()));
188 : : }
189 : : }
190 : 0 : }
191 : :
192 : : // -----------------------------------------------------------------------------
193 : :
194 : : /** exports a style change record with a move to (x,y) and depending on bFilled a line style 1 or fill style 1
195 : : */
196 : 0 : void Writer::Impl_addShapeRecordChange( BitStream& rBits, sal_Int16 dx, sal_Int16 dy, sal_Bool bFilled )
197 : : {
198 : 0 : rBits.writeUB( 0, 1 ); // TypeFlag
199 : 0 : rBits.writeUB( 0, 1 ); // StateNewStyles
200 : 0 : rBits.writeUB( !bFilled, 1 ); // StateLineStyle
201 : 0 : rBits.writeUB( 0, 1 ); // StateFillStyle0
202 : 0 : rBits.writeUB( bFilled, 1 ); // StateFillStyle1
203 : 0 : rBits.writeUB( 1, 1 ); // StateMoveTo
204 : :
205 : 0 : sal_uInt16 nMoveBits = max( getMaxBitsSigned( dx ), getMaxBitsSigned( dy ) );
206 : :
207 : 0 : rBits.writeUB( nMoveBits, 5 ); // Number of bits per value
208 : : // TODO: Optimize horizontal and vertical lines
209 : 0 : rBits.writeSB( dx, nMoveBits ); // DeltaX
210 : 0 : rBits.writeSB( dy, nMoveBits ); // DeltaY
211 : :
212 : 0 : rBits.writeUB( 1, 1 ); // set FillStyle1 or LineStyle to 1
213 : 0 : }
214 : :
215 : : // -----------------------------------------------------------------------------
216 : :
217 : : /** exports a straight edge record
218 : : */
219 : 0 : void Writer::Impl_addStraightEdgeRecord( BitStream& rBits, sal_Int16 dx, sal_Int16 dy )
220 : : {
221 : 0 : rBits.writeUB( 1, 1 ); // TypeFlag
222 : 0 : rBits.writeUB( 1, 1 ); // StraightFlag
223 : :
224 : 0 : sal_uInt16 nBits = max( getMaxBitsSigned( dx ), getMaxBitsSigned( dy ) );
225 : :
226 : 0 : rBits.writeUB( nBits - 2, 4 ); // Number of bits per value
227 : :
228 : 0 : if( (dx != 0) && (dy != 0) )
229 : : {
230 : 0 : rBits.writeUB( 1, 1 ); // GeneralLineFlag
231 : 0 : rBits.writeSB( dx, nBits ); // DeltaX
232 : 0 : rBits.writeSB( dy, nBits ); // DeltaY
233 : : }
234 : : else
235 : : {
236 : 0 : rBits.writeUB( 0, 1 );
237 : 0 : rBits.writeUB( ( dx == 0 ), 1 );
238 : 0 : if( dx == 0 )
239 : : {
240 : 0 : rBits.writeSB( dy, nBits ); // DeltaY
241 : : }
242 : : else
243 : : {
244 : 0 : rBits.writeSB( dx, nBits ); // DeltaX
245 : : }
246 : : }
247 : 0 : }
248 : :
249 : : // -----------------------------------------------------------------------------
250 : :
251 : : /** exports a curved edge record
252 : : */
253 : 0 : void Writer::Impl_addCurvedEdgeRecord( BitStream& rBits, sal_Int16 control_dx, sal_Int16 control_dy, sal_Int16 anchor_dx, sal_Int16 anchor_dy )
254 : : {
255 : 0 : rBits.writeUB( 1, 1 ); // TypeFlag
256 : 0 : rBits.writeUB( 0, 1 ); // CurvedFlag
257 : :
258 : : sal_uInt8 nBits = static_cast<sal_uInt8>(
259 : 0 : max( getMaxBitsSigned( control_dx ),
260 : 0 : max( getMaxBitsSigned( control_dy ),
261 : 0 : max( getMaxBitsSigned( anchor_dx ),
262 : 0 : max( getMaxBitsSigned( anchor_dy ), (sal_uInt16)3 ) ) ) ) );
263 : :
264 : 0 : rBits.writeUB( nBits - 2, 4 ); // Number of bits per value
265 : :
266 : 0 : rBits.writeSB( control_dx, nBits ); // DeltaX
267 : 0 : rBits.writeSB( control_dy, nBits ); // DeltaY
268 : 0 : rBits.writeSB( anchor_dx, nBits ); // DeltaX
269 : 0 : rBits.writeSB( anchor_dy, nBits ); // DeltaY
270 : 0 : }
271 : :
272 : : // -----------------------------------------------------------------------------
273 : :
274 : : /** exports a end shape record
275 : : */
276 : 0 : void Writer::Impl_addEndShapeRecord( BitStream& rBits )
277 : : {
278 : 0 : rBits.writeUB( 0, 6 );
279 : 0 : }
280 : :
281 : : // -----------------------------------------------------------------------------
282 : :
283 : 0 : void Writer::Impl_writePolygon( const Polygon& rPoly, sal_Bool bFilled )
284 : : {
285 : 0 : PolyPolygon aPolyPoly( rPoly );
286 : 0 : Impl_writePolyPolygon( aPolyPoly, bFilled );
287 : 0 : }
288 : :
289 : : // -----------------------------------------------------------------------------
290 : :
291 : 0 : void Writer::Impl_writePolygon( const Polygon& rPoly, sal_Bool bFilled, const Color& rFillColor, const Color& rLineColor )
292 : : {
293 : 0 : PolyPolygon aPolyPoly( rPoly );
294 : 0 : Impl_writePolyPolygon( aPolyPoly, bFilled, rFillColor, rLineColor );
295 : 0 : }
296 : :
297 : : // -----------------------------------------------------------------------------
298 : :
299 : 0 : void Writer::Impl_writePolyPolygon( const PolyPolygon& rPolyPoly, sal_Bool bFilled, sal_uInt8 nTransparence /* = 0 */ )
300 : : {
301 : 0 : Color aLineColor( mpVDev->GetLineColor() );
302 : 0 : if( 0 == aLineColor.GetTransparency() )
303 : 0 : aLineColor.SetTransparency( nTransparence );
304 : 0 : Color aFillColor( mpVDev->GetFillColor() );
305 : 0 : if( 0 == aFillColor.GetTransparency() )
306 : 0 : aFillColor.SetTransparency( nTransparence );
307 : 0 : Impl_writePolyPolygon(rPolyPoly, bFilled, aFillColor, aLineColor );
308 : 0 : }
309 : :
310 : : // -----------------------------------------------------------------------------
311 : :
312 : 0 : void Writer::Impl_writePolyPolygon( const PolyPolygon& rPolyPoly, sal_Bool bFilled, const Color& rFillColor, const Color& rLineColor )
313 : : {
314 : 0 : PolyPolygon aPolyPoly( rPolyPoly );
315 : :
316 : 0 : if( aPolyPoly.Count() )
317 : : {
318 : 0 : map( aPolyPoly );
319 : :
320 : 0 : if( mpClipPolyPolygon )
321 : 0 : rPolyPoly.GetIntersection( *mpClipPolyPolygon, aPolyPoly );
322 : :
323 : : sal_uInt16 nID;
324 : 0 : if( bFilled )
325 : : {
326 : 0 : Color aFillColor( rFillColor );
327 : 0 : if( 0 != mnGlobalTransparency )
328 : 0 : aFillColor.SetTransparency( mnGlobalTransparency );
329 : :
330 : 0 : FillStyle aStyle( aFillColor );
331 : 0 : nID = defineShape( aPolyPoly, aStyle );
332 : : }
333 : : else
334 : : {
335 : 0 : Color aLineColor( rLineColor );
336 : 0 : if( 0 != mnGlobalTransparency )
337 : 0 : aLineColor.SetTransparency( mnGlobalTransparency );
338 : :
339 : 0 : nID = defineShape( aPolyPoly, 1, aLineColor );
340 : : }
341 : 0 : maShapeIds.push_back( nID );
342 : 0 : }
343 : 0 : }
344 : :
345 : : // -----------------------------------------------------------------------------
346 : :
347 : : /** a gradient is a transition from one color to another, rendered inside a given polypolygon */
348 : 0 : void Writer::Impl_writeGradientEx( const PolyPolygon& rPolyPoly, const Gradient& rGradient )
349 : : {
350 : 0 : if( rPolyPoly.Count() )
351 : : {
352 : 0 : PolyPolygon aPolyPolygon( rPolyPoly );
353 : 0 : map( aPolyPolygon );
354 : :
355 : 0 : if( (rGradient.GetStyle() == GradientStyle_LINEAR && rGradient.GetAngle() == 900) || (rGradient.GetStyle() == GradientStyle_RADIAL) )
356 : : {
357 : 0 : const Rectangle aBoundRect( aPolyPolygon.GetBoundRect() );
358 : :
359 : 0 : FillStyle aFillStyle( aBoundRect, rGradient );
360 : :
361 : 0 : sal_uInt16 nShapeId = defineShape( aPolyPolygon, aFillStyle );
362 : 0 : maShapeIds.push_back( nShapeId );
363 : : }
364 : : else
365 : : {
366 : 0 : setClipping( &aPolyPolygon );
367 : :
368 : : // render the gradient filling to simple polygons
369 : : {
370 : 0 : GDIMetaFile aTmpMtf;
371 : 0 : mpVDev->AddGradientActions( aPolyPolygon.GetBoundRect(), rGradient, aTmpMtf );
372 : 0 : Impl_writeActions( aTmpMtf );
373 : : }
374 : :
375 : 0 : setClipping( NULL );
376 : 0 : }
377 : : }
378 : 0 : }
379 : :
380 : : // -----------------------------------------------------------------------------
381 : :
382 : 0 : void Writer::setClipping( const PolyPolygon* pClipPolyPolygon )
383 : : {
384 : 0 : mpClipPolyPolygon = pClipPolyPolygon;
385 : 0 : }
386 : :
387 : : // -----------------------------------------------------------------------------
388 : :
389 : : // AS: Just comparing fonts straight up is too literal. There are some
390 : : // differences in font that actually require different glyphs to be defined,
391 : : // and some that don't. This function is meant to capture all the differences
392 : : // that we care about.
393 : 0 : bool compare_fonts_for_me(const Font& rFont1, const Font& rFont2)
394 : : {
395 : 0 : return rFont1.GetName() == rFont2.GetName() &&
396 : 0 : rFont1.GetWeight() == rFont2.GetWeight() &&
397 : 0 : rFont1.GetItalic() == rFont2.GetItalic() &&
398 : 0 : rFont1.IsOutline() == rFont2.IsOutline() &&
399 : 0 : rFont1.IsShadow() == rFont2.IsShadow() &&
400 : 0 : rFont1.GetRelief() == rFont2.GetRelief();
401 : : }
402 : :
403 : : // -----------------------------------------------------------------------------
404 : :
405 : 0 : FlashFont& Writer::Impl_getFont( const Font& rFont )
406 : : {
407 : 0 : FontMap::iterator aIter( maFonts.begin() );
408 : 0 : const FontMap::iterator aEnd( maFonts.end() );
409 : :
410 : 0 : for(; aIter != aEnd; ++aIter)
411 : : {
412 : 0 : const Font tempFont = (*aIter)->getFont();
413 : 0 : if( compare_fonts_for_me(tempFont, rFont) )
414 : : {
415 : 0 : return **aIter;
416 : : }
417 : 0 : }
418 : :
419 : 0 : FlashFont* pFont = new FlashFont( rFont, createID() );
420 : 0 : maFonts.push_back( pFont );
421 : 0 : return *pFont;
422 : : }
423 : :
424 : : // -----------------------------------------------------------------------------
425 : :
426 : 0 : void Writer::Impl_writeText( const Point& rPos, const String& rText, const sal_Int32* pDXArray, long nWidth )
427 : : {
428 : 0 : const FontMetric aMetric( mpVDev->GetFontMetric() );
429 : :
430 : 0 : bool bTextSpecial = aMetric.IsShadow() || aMetric.IsOutline() || (aMetric.GetRelief() != RELIEF_NONE);
431 : :
432 : 0 : if( !bTextSpecial )
433 : : {
434 : 0 : Impl_writeText( rPos, rText, pDXArray, nWidth, mpVDev->GetTextColor() );
435 : : }
436 : : else
437 : : {
438 : 0 : if( aMetric.GetRelief() != RELIEF_NONE )
439 : : {
440 : 0 : Color aReliefColor( COL_LIGHTGRAY );
441 : 0 : Color aTextColor( mpVDev->GetTextColor() );
442 : :
443 : 0 : if ( aTextColor.GetColor() == COL_BLACK )
444 : 0 : aTextColor = Color( COL_WHITE );
445 : :
446 : 0 : if ( aTextColor.GetColor() == COL_WHITE )
447 : 0 : aReliefColor = Color( COL_BLACK );
448 : :
449 : :
450 : 0 : Point aPos( rPos );
451 : 0 : Point aOffset( 6,6 );
452 : :
453 : 0 : if ( aMetric.GetRelief() == RELIEF_ENGRAVED )
454 : : {
455 : 0 : aPos -= aOffset;
456 : : }
457 : : else
458 : : {
459 : 0 : aPos += aOffset;
460 : : }
461 : :
462 : 0 : Impl_writeText( aPos, rText, pDXArray, nWidth, aReliefColor );
463 : 0 : Impl_writeText( rPos, rText, pDXArray, nWidth, aTextColor );
464 : : }
465 : : else
466 : : {
467 : 0 : if( aMetric.IsShadow() )
468 : : {
469 : 0 : long nOff = 1 + ((aMetric.GetLineHeight()-24)/24);
470 : 0 : if ( aMetric.IsOutline() )
471 : 0 : nOff += 6;
472 : :
473 : 0 : Color aTextColor( mpVDev->GetTextColor() );
474 : 0 : Color aShadowColor = Color( COL_BLACK );
475 : :
476 : 0 : if ( (aTextColor.GetColor() == COL_BLACK) || (aTextColor.GetLuminance() < 8) )
477 : 0 : aShadowColor = Color( COL_LIGHTGRAY );
478 : :
479 : 0 : Point aPos( rPos );
480 : 0 : aPos += Point( nOff, nOff );
481 : 0 : Impl_writeText( aPos, rText, pDXArray, nWidth, aShadowColor );
482 : :
483 : 0 : if( !aMetric.IsOutline() )
484 : : {
485 : 0 : Impl_writeText( rPos, rText, pDXArray, nWidth, aTextColor );
486 : : }
487 : : }
488 : :
489 : 0 : if( aMetric.IsOutline() )
490 : : {
491 : 0 : Point aPos = rPos + Point( -6, -6 );
492 : 0 : Impl_writeText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor() );
493 : 0 : aPos = rPos + Point(+6,+6);
494 : 0 : Impl_writeText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor() );
495 : 0 : aPos = rPos + Point(-6,+0);
496 : 0 : Impl_writeText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor() );
497 : 0 : aPos = rPos + Point(-6,+6);
498 : 0 : Impl_writeText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor() );
499 : 0 : aPos = rPos + Point(+0,+6);
500 : 0 : Impl_writeText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor() );
501 : 0 : aPos = rPos + Point(+0,-6);
502 : 0 : Impl_writeText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor() );
503 : 0 : aPos = rPos + Point(+6,-1);
504 : 0 : Impl_writeText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor() );
505 : 0 : aPos = rPos + Point(+6,+0);
506 : 0 : Impl_writeText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor() );
507 : :
508 : 0 : Impl_writeText( rPos, rText, pDXArray, nWidth, Color( COL_WHITE ) );
509 : : }
510 : : }
511 : 0 : }
512 : 0 : }
513 : :
514 : 0 : void Writer::Impl_writeText( const Point& rPos, const String& rText, const sal_Int32* pDXArray, long nWidth, Color aTextColor )
515 : : {
516 : 0 : sal_uInt32 nLen = rText.Len();
517 : :
518 : 0 : if( !nLen )
519 : 0 : return;
520 : :
521 : 0 : const bool bRTL = (mpVDev->GetLayoutMode() & TEXT_LAYOUT_BIDI_RTL) != 0;
522 : :
523 : 0 : sal_Int16 nScriptType = ScriptType::LATIN;
524 : 0 : Reference < XBreakIterator > xBI( Impl_GetBreakIterator() );
525 : 0 : if( xBI.is() )
526 : : {
527 : 0 : const OUString oText( rText );
528 : 0 : nScriptType = xBI->getScriptType( oText, 0 );
529 : : }
530 : :
531 : : // if the text is either right to left or complex or asian, we
532 : : // ask the output device for a polygon representation.
533 : : // On complex and asian text, each unicode character can have
534 : : // different glyph representation, based on context. Also positioning
535 : : // is not trivial so we let the output device do it for us.
536 : 0 : if( bRTL || (nScriptType != ScriptType::LATIN) )
537 : : {
538 : : // todo: optimize me as this will generate a huge amount of duplicate polygons
539 : 0 : PolyPolygon aPolyPoygon;
540 : 0 : mpVDev->GetTextOutline( aPolyPoygon, rText, 0, 0, (sal_uInt16)nLen, sal_True, nWidth, pDXArray );
541 : 0 : aPolyPoygon.Translate( rPos );
542 : 0 : Impl_writePolyPolygon( aPolyPoygon, sal_True, aTextColor, aTextColor );
543 : : }
544 : : else
545 : : {
546 : 0 : Size aNormSize;
547 : : sal_Int32* pOwnArray;
548 : : sal_Int32* pDX;
549 : :
550 : : // get text sizes
551 : 0 : if( pDXArray )
552 : : {
553 : 0 : pOwnArray = NULL;
554 : 0 : aNormSize = Size( mpVDev->GetTextWidth( rText ), 0 );
555 : 0 : pDX = (sal_Int32*) pDXArray;
556 : : }
557 : : else
558 : : {
559 : 0 : pOwnArray = new sal_Int32[ nLen ];
560 : 0 : aNormSize = Size( mpVDev->GetTextArray( rText, pOwnArray ), 0 );
561 : 0 : pDX = pOwnArray;
562 : : }
563 : :
564 : 0 : if( nLen > 1 )
565 : : {
566 : 0 : aNormSize.Width() = pDX[ nLen - 2 ] + mpVDev->GetTextWidth( rtl::OUString(rText.GetChar((sal_uInt16) nLen - 1)) );
567 : :
568 : 0 : if( nWidth && aNormSize.Width() && ( nWidth != aNormSize.Width() ) )
569 : : {
570 : 0 : const double fFactor = (double) nWidth / aNormSize.Width();
571 : :
572 : : sal_uInt32 i;
573 : 0 : for( i = 0; i < ( nLen - 1 ); i++ )
574 : 0 : pDX[ i ] = FRound( pDX[ i ] * fFactor );
575 : : }
576 : : }
577 : :
578 : 0 : Font aOldFont( mpVDev->GetFont() );
579 : 0 : Point aBaseLinePos( rPos );
580 : :
581 : 0 : Font aFont(aOldFont);
582 : 0 : short nOrientation = aFont.GetOrientation();
583 : 0 : aFont.SetOrientation( 0 );
584 : 0 : aFont.SetUnderline(UNDERLINE_NONE);
585 : 0 : aFont.SetStrikeout(STRIKEOUT_NONE);
586 : 0 : mpVDev->SetFont( aFont );
587 : :
588 : 0 : const FontMetric aMetric( mpVDev->GetFontMetric() );
589 : :
590 : 0 : FlashFont& rFlashFont = Impl_getFont( aFont );
591 : :
592 : : // always adjust text position to match baseline alignment
593 : 0 : switch( aOldFont.GetAlign() )
594 : : {
595 : : case( ALIGN_TOP ):
596 : 0 : aBaseLinePos.Y() += aMetric.GetAscent();
597 : 0 : break;
598 : :
599 : : case( ALIGN_BOTTOM ):
600 : 0 : aBaseLinePos.Y() -= aMetric.GetDescent();
601 : 0 : break;
602 : :
603 : : default:
604 : 0 : break;
605 : : }
606 : :
607 : : // get mapped text position
608 : 0 : const Point aPt( map( aBaseLinePos ) );
609 : :
610 : : // write text element
611 : :
612 : : #if 0 // makes the calculated bound rect visible for debuging
613 : : {
614 : : Polygon aTmpPoly( aPoly );
615 : : sal_uInt16 nID = FlashGeometryExporter::writePolygonShape( aMovieStream, aTmpPoly, false, Color(COL_MAGENTA), Color(COL_MAGENTA), mpClipPolyPolygon );
616 : : ImplPlaceObject( nID );
617 : : }
618 : : #endif
619 : :
620 : : // CL: This is still a hack until we figure out how to calculate a correct bound rect
621 : : // for rotatet text
622 : 0 : Rectangle textBounds( 0, 0, static_cast<long>(mnDocWidth*mnDocXScale), static_cast<long>(mnDocHeight*mnDocYScale) );
623 : 0 : double scale = 1.0;
624 : :
625 : : // scale width if we have a stretched text
626 : 0 : if( 0 != aFont.GetSize().Width() )
627 : : {
628 : 0 : Font aTmpFont( aFont );
629 : 0 : aTmpFont.SetWidth(0);
630 : 0 : mpVDev->SetFont( aTmpFont );
631 : :
632 : 0 : const FontMetric aMetric2( mpVDev->GetFontMetric() );
633 : 0 : mpVDev->SetFont( aFont );
634 : :
635 : 0 : const long n1 = aFont.GetSize().Width();
636 : 0 : const long n2 = aMetric2.GetSize().Width();
637 : 0 : scale = (double)n1 / (double)n2;
638 : : }
639 : :
640 : 0 : basegfx::B2DHomMatrix m(basegfx::tools::createRotateB2DHomMatrix(static_cast<double>(nOrientation) * F_PI1800));
641 : 0 : m.translate( double(aPt.X() / scale), double(aPt.Y()) );
642 : 0 : m.scale( scale, scale );
643 : :
644 : 0 : sal_Int16 nHeight = _Int16( map( Size( 0, aFont.GetHeight() ) ).Height() );
645 : :
646 : 0 : startTag( TAG_DEFINETEXT );
647 : :
648 : 0 : sal_uInt16 nTextId = createID();
649 : :
650 : 0 : mpTag->addUI16( nTextId );
651 : 0 : mpTag->addRect( textBounds );
652 : 0 : mpTag->addMatrix( m );
653 : :
654 : 0 : sal_uInt8 nGlyphBits = 16;
655 : 0 : sal_uInt8 nAdvanceBits = 16;
656 : :
657 : 0 : mpTag->addUI8( nGlyphBits );
658 : 0 : mpTag->addUI8( nAdvanceBits );
659 : :
660 : : // text style change record
661 : 0 : mpTag->addUI8( 0x8c );
662 : 0 : mpTag->addUI16( rFlashFont.getID() );
663 : 0 : mpTag->addRGB( aTextColor );
664 : 0 : mpTag->addUI16( _uInt16( nHeight ) );
665 : :
666 : : DBG_ASSERT( nLen <= 127, "TODO: handle text with more than 127 characters" );
667 : :
668 : : // Glyph record
669 : 0 : mpTag->addUI8( (sal_uInt8) nLen );
670 : :
671 : 0 : BitStream aBits;
672 : :
673 : 0 : sal_Int32 nLastDX = 0;
674 : : sal_Int32 nAdvance;
675 : : sal_uInt32 i;
676 : 0 : for( i = 0; i < nLen; i++ )
677 : : {
678 : 0 : if( i < (nLen-1) )
679 : : {
680 : 0 : nAdvance = pDX[i] - nLastDX;
681 : 0 : nLastDX = pDX[i];
682 : : }
683 : : else
684 : : {
685 : 0 : nAdvance = 0;
686 : : }
687 : :
688 : 0 : aBits.writeUB( rFlashFont.getGlyph(rText.GetChar(_uInt16(i)),mpVDev), nGlyphBits );
689 : 0 : aBits.writeSB( _Int16(map( Size( (long)( nAdvance / scale ), 0 ) ).Width() ), nAdvanceBits );
690 : : }
691 : :
692 : 0 : mpTag->addBits( aBits );
693 : 0 : mpTag->addUI8( 0 );
694 : :
695 : 0 : endTag();
696 : :
697 : 0 : maShapeIds.push_back( nTextId );
698 : :
699 : : // AS: Write strikeout and underline, if neccessary. This code was originally taken from the SVG
700 : : // export facility, although the positioning had to be tweaked a little. I can't explain the
701 : : // numbers, but the flash lines up very well with the original OOo document. All of this should
702 : : // probably be converted to polygons as part of the meta file, though, as we don't handle any
703 : : // fancy lines (like dashes).
704 : 0 : if( ( aOldFont.GetStrikeout() != STRIKEOUT_NONE ) || ( aOldFont.GetUnderline() != UNDERLINE_NONE ) )
705 : : {
706 : 0 : Polygon aPoly( 4 );
707 : 0 : const long nLineHeight = Max( (long) FRound( aMetric.GetLineHeight() * 0.05 ), (long) 1 );
708 : :
709 : 0 : if( aOldFont.GetStrikeout() != STRIKEOUT_NONE )
710 : : {
711 : 0 : aPoly[ 0 ].X() = aBaseLinePos.X();
712 : 0 : aPoly[ 0 ].Y() = aBaseLinePos.Y() - FRound( aMetric.GetAscent() * 0.26 ) - nLineHeight;
713 : 0 : aPoly[ 1 ].X() = aPoly[ 0 ].X() + aNormSize.Width() - 1;
714 : 0 : aPoly[ 1 ].Y() = aPoly[ 0 ].Y();
715 : 0 : aPoly[ 2 ].X() = aPoly[ 1 ].X();
716 : 0 : aPoly[ 2 ].Y() = aPoly[ 1 ].Y() + nLineHeight - 1;
717 : 0 : aPoly[ 3 ].X() = aPoly[ 0 ].X();
718 : 0 : aPoly[ 3 ].Y() = aPoly[ 2 ].Y();
719 : :
720 : 0 : Impl_writePolygon( aPoly, sal_True, aTextColor, aTextColor );
721 : : }
722 : :
723 : : // AS: The factor of 1.5 on the nLineHeight is a magic number. I'm not sure why it works,
724 : : // but it looks good to me.
725 : 0 : if( aOldFont.GetUnderline() != UNDERLINE_NONE )
726 : : {
727 : 0 : aPoly[ 0 ].X() = aBaseLinePos.X();
728 : 0 : aPoly[ 0 ].Y() = static_cast<long>(aBaseLinePos.Y() + 1.5*nLineHeight);
729 : 0 : aPoly[ 1 ].X() = aPoly[ 0 ].X() + aNormSize.Width() - 1;
730 : 0 : aPoly[ 1 ].Y() = aPoly[ 0 ].Y();
731 : 0 : aPoly[ 2 ].X() = aPoly[ 1 ].X();
732 : 0 : aPoly[ 2 ].Y() = aPoly[ 1 ].Y() + nLineHeight - 1;
733 : 0 : aPoly[ 3 ].X() = aPoly[ 0 ].X();
734 : 0 : aPoly[ 3 ].Y() = aPoly[ 2 ].Y();
735 : :
736 : 0 : Impl_writePolygon( aPoly, sal_True, aTextColor, aTextColor );
737 : 0 : }
738 : : }
739 : :
740 : 0 : mpVDev->SetFont( aOldFont );
741 : 0 : delete[] pOwnArray;
742 : 0 : }
743 : : }
744 : :
745 : : // -----------------------------------------------------------------------------
746 : : // AS: Because JPEGs require the alpha channel provided seperately (JPEG does not
747 : : // natively support alpha channel, but SWF lets you provide it seperately), we
748 : : // extract the alpha channel into a seperate array here.
749 : 0 : void getBitmapData( const BitmapEx& aBmpEx, sal_uInt8*& tgadata, sal_uInt8*& tgaAlphadata, sal_uInt32& nWidth, sal_uInt32& nHeight )
750 : : {
751 : 0 : if( !aBmpEx.IsEmpty() )
752 : : {
753 : 0 : Bitmap aBmp( aBmpEx.GetBitmap() );
754 : 0 : BitmapReadAccess* pRAcc = aBmp.AcquireReadAccess();
755 : :
756 : 0 : if( pRAcc )
757 : : {
758 : 0 : AlphaMask aAlpha;
759 : 0 : nWidth = pRAcc->Width();
760 : 0 : nHeight = pRAcc->Height();
761 : 0 : tgadata = new sal_uInt8[nWidth*nHeight*4];
762 : 0 : tgaAlphadata = new sal_uInt8[nWidth*nHeight];
763 : 0 : sal_uInt8* p = tgadata, *pAlpha = tgaAlphadata;
764 : :
765 : :
766 : 0 : if( aBmpEx.IsAlpha() )
767 : 0 : aAlpha = aBmpEx.GetAlpha();
768 : 0 : else if( aBmpEx.IsTransparent() )
769 : 0 : aAlpha = aBmpEx.GetMask();
770 : : else
771 : : {
772 : 0 : sal_uInt8 cAlphaVal = 0;
773 : 0 : aAlpha = AlphaMask( aBmp.GetSizePixel(), &cAlphaVal );
774 : : }
775 : :
776 : 0 : BitmapReadAccess* pAAcc = aAlpha.AcquireReadAccess();
777 : :
778 : 0 : if( pAAcc )
779 : : {
780 : 0 : for( sal_uInt32 nY = 0; nY < nHeight; nY++ )
781 : : {
782 : 0 : for( sal_uInt32 nX = 0; nX < nWidth; nX++ )
783 : : {
784 : 0 : const sal_uInt8 nAlpha = pAAcc->GetPixel( nY, nX ).GetIndex();
785 : 0 : const BitmapColor aPixelColor( pRAcc->GetColor( nY, nX ) );
786 : :
787 : 0 : if( nAlpha == 0xff )
788 : : {
789 : 0 : *p++ = 0;
790 : 0 : *p++ = 0;
791 : 0 : *p++ = 0;
792 : 0 : *p++ = 0;
793 : : }
794 : : else
795 : : {
796 : 0 : *p++ = 0xff-nAlpha;
797 : 0 : *p++ = aPixelColor.GetRed();
798 : 0 : *p++ = aPixelColor.GetGreen();
799 : 0 : *p++ = aPixelColor.GetBlue();
800 : : }
801 : 0 : *pAlpha++ = 0xff - nAlpha;
802 : 0 : }
803 : : }
804 : :
805 : 0 : aAlpha.ReleaseAccess( pAAcc );
806 : : }
807 : :
808 : 0 : aBmp.ReleaseAccess( pRAcc );
809 : 0 : }
810 : : }
811 : 0 : }
812 : :
813 : : // -----------------------------------------------------------------------------
814 : 0 : sal_uInt16 Writer::defineBitmap( const BitmapEx &bmpSource, sal_Int32 nJPEGQualityLevel )
815 : : {
816 : 0 : sal_uLong bmpChecksum = bmpSource.GetChecksum();
817 : :
818 : 0 : ChecksumCache::iterator it = mBitmapCache.find(bmpChecksum);
819 : :
820 : : // AS: We already exported this bitmap, so just return its ID.
821 : 0 : if (mBitmapCache.end() != it)
822 : 0 : return it->second;
823 : :
824 : 0 : sal_uInt16 nBitmapId = createID();
825 : 0 : mBitmapCache[bmpChecksum] = nBitmapId;
826 : :
827 : : // AS: OK, we have a good image, so now we decide whether or not to JPEG it or
828 : : // or Lossless compress it.
829 : :
830 : : //Figure out lossless size
831 : : sal_uInt8 *pImageData, *pAlphaData;
832 : : sal_uInt32 width, height;
833 : :
834 : 0 : getBitmapData( bmpSource, pImageData, pAlphaData, width, height );
835 : 0 : sal_uInt32 raw_size = width * height * 4;
836 : 0 : uLongf compressed_size = raw_size + (sal_uInt32)(raw_size/100) + 12;
837 : 0 : sal_uInt8 *pCompressed = new sal_uInt8[ compressed_size ];
838 : :
839 : : #ifdef DBG_UTIL
840 : : if(compress2(pCompressed, &compressed_size, pImageData, raw_size, Z_BEST_COMPRESSION) != Z_OK)
841 : : {
842 : : DBG_ASSERT( false, "compress2 failed!" ); ((void)0);
843 : : }
844 : : #else
845 : 0 : compress2(pCompressed, &compressed_size, pImageData, raw_size, Z_BEST_COMPRESSION);
846 : : #endif
847 : :
848 : : // AS: SWF files let you provide an Alpha mask for JPEG images, but we have
849 : : // to ZLIB compress the alpha channel seperately.
850 : 0 : uLong alpha_compressed_size = 0;
851 : 0 : sal_uInt8 *pAlphaCompressed = NULL;
852 : 0 : if (bmpSource.IsAlpha() || bmpSource.IsTransparent())
853 : : {
854 : 0 : alpha_compressed_size = uLongf(width * height + (sal_uInt32)(raw_size/100) + 12);
855 : 0 : pAlphaCompressed = new sal_uInt8[ compressed_size ];
856 : :
857 : : #ifdef DBG_UTIL
858 : : if(compress2(pAlphaCompressed, &alpha_compressed_size, pAlphaData, width * height, Z_BEST_COMPRESSION) != Z_OK)
859 : : {
860 : : DBG_ASSERT( false, "compress2 failed!" ); ((void)0);
861 : : }
862 : : #else
863 : 0 : compress2(pAlphaCompressed, &alpha_compressed_size, pAlphaData, width * height, Z_BEST_COMPRESSION);
864 : : #endif
865 : : }
866 : :
867 : : //Figure out JPEG size
868 : 0 : const sal_uInt8* pJpgData = NULL;;
869 : 0 : sal_uInt32 nJpgDataLength = 0xffffffff;
870 : :
871 : 0 : Graphic aGraphic( bmpSource );
872 : 0 : SvMemoryStream aDstStm( 65535, 65535 );
873 : :
874 : 0 : GraphicFilter aFilter;
875 : :
876 : 0 : Sequence< PropertyValue > aFilterData(nJPEGQualityLevel != -1);
877 : 0 : if( nJPEGQualityLevel != -1 )
878 : : {
879 : 0 : aFilterData[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM("Quality"));
880 : 0 : aFilterData[0].Value <<= nJPEGQualityLevel;
881 : : }
882 : :
883 : 0 : if( aFilter.ExportGraphic( aGraphic, String(), aDstStm,
884 : 0 : aFilter.GetExportFormatNumberForShortName( OUString( RTL_CONSTASCII_USTRINGPARAM( JPG_SHORTNAME ) ) ), &aFilterData ) == ERRCODE_NONE )
885 : : {
886 : 0 : pJpgData = reinterpret_cast<const sal_uInt8*>(aDstStm.GetData());
887 : 0 : nJpgDataLength = aDstStm.Seek( STREAM_SEEK_TO_END );
888 : : }
889 : :
890 : : // AS: Ok, now go ahead and use whichever is smaller. If JPEG is smaller, then
891 : : // we have to export as TAG_DEFINEBITSJPEG3 in the case that there is alpha
892 : : // channel data.
893 : 0 : if ( pJpgData && ( nJpgDataLength + alpha_compressed_size < compressed_size) )
894 : 0 : Impl_writeJPEG(nBitmapId, pJpgData, nJpgDataLength, pAlphaCompressed, alpha_compressed_size );
895 : : else
896 : 0 : Impl_writeBmp( nBitmapId, width, height, pCompressed, compressed_size );
897 : :
898 : 0 : delete[] pCompressed;
899 : 0 : delete[] pAlphaCompressed;
900 : 0 : delete[] pImageData;
901 : 0 : delete[] pAlphaData;
902 : :
903 : 0 : return nBitmapId;
904 : : }
905 : :
906 : : // -----------------------------------------------------------------------------
907 : :
908 : 0 : void Writer::Impl_writeImage( const BitmapEx& rBmpEx, const Point& rPt, const Size& rSz, const Point& /* rSrcPt */, const Size& /* rSrcSz */, const Rectangle& rClipRect, bool bNeedToMapClipRect )
909 : : {
910 : 0 : if( !!rBmpEx )
911 : : {
912 : 0 : BitmapEx bmpSource( rBmpEx );
913 : :
914 : 0 : Rectangle originalPixelRect = Rectangle(Point(), bmpSource.GetSizePixel());
915 : :
916 : 0 : Point srcPt( map(rPt) );
917 : 0 : Size srcSize( map(rSz) );
918 : 0 : Rectangle destRect( srcPt, srcSize );
919 : :
920 : : // AS: Christian, my scaling factors are different than yours, and work better for me.
921 : : // However, I can't explain why exactly. I got some of this by trial and error.
922 : 0 : double XScale = static_cast<double>(originalPixelRect.GetWidth())/destRect.GetWidth();
923 : 0 : double YScale = static_cast<double>(originalPixelRect.GetHeight())/destRect.GetHeight();
924 : :
925 : : // AS: If rClipRect has a value set, then we need to crop the bmp appropriately.
926 : : // If a map event already occurred in the metafile, then we do not need to map
927 : : // the clip rect as it's already been done.
928 : 0 : if (!rClipRect.IsEmpty())
929 : : {
930 : : // AS: Christian, I also don't understand why bNeedToMapClipRect is necessary, but it
931 : : // works like a charm. Usually, the map event in the meta file does not cause the
932 : : // clipping rectangle to get mapped. However, sometimes there are multiple layers
933 : : // of mapping which eventually do cause the clipping rect to be mapped.
934 : 0 : Size clipSize( bNeedToMapClipRect ? map(rClipRect.GetSize()) : rClipRect.GetSize() );
935 : 0 : Rectangle clipRect = Rectangle(Point(), clipSize);
936 : 0 : destRect.Intersection( clipRect );
937 : :
938 : 0 : Rectangle cropRect(destRect);
939 : :
940 : : // AS: The bmp origion is always 0,0 so we have to adjust before we crop.
941 : 0 : cropRect.Move(-srcPt.X(), -srcPt.Y());
942 : : // AS: Rectangle has no scale function (?!) so I do it manually...
943 : 0 : Rectangle cropPixelRect(static_cast<long>(cropRect.Left()*XScale),
944 : 0 : static_cast<long>(cropRect.Top()*YScale),
945 : 0 : static_cast<long>(cropRect.Right()*XScale),
946 : 0 : static_cast<long>(cropRect.Bottom()*YScale));
947 : :
948 : 0 : bmpSource.Crop(cropPixelRect);
949 : : }
950 : :
951 : 0 : if( !!bmpSource )
952 : : {
953 : : // #105949# fix images that are under 16 pixels width or height by
954 : : // expanding them. Some swf players can't display such small
955 : : // bitmaps
956 : 0 : const Size& rSizePixel = bmpSource.GetSizePixel();
957 : 0 : if( (rSizePixel.Width() < 16) || (rSizePixel.Height() < 16) )
958 : : {
959 : 0 : const sal_uInt32 nDX = rSizePixel.Width() < 16 ? 16 - rSizePixel.Width() : 0;
960 : 0 : const sal_uInt32 nDY = rSizePixel.Height() < 16 ? 16 - rSizePixel.Height() : 0;
961 : 0 : bmpSource.Expand( nDX, nDY );
962 : : }
963 : :
964 : 0 : sal_Int32 nJPEGQuality = mnJPEGCompressMode;
965 : :
966 : 0 : Size szDestPixel = mpVDev->LogicToPixel(srcSize, aTWIPSMode);
967 : :
968 : 0 : double pixXScale = static_cast<double>(szDestPixel.Width()) / originalPixelRect.GetWidth();
969 : 0 : double pixYScale = static_cast<double>(szDestPixel.Height()) / originalPixelRect.GetHeight();
970 : :
971 : : // AS: If the image has been scaled down, then scale down the quality
972 : : // that we use for JPEG compression.
973 : 0 : if (pixXScale < 1.0 && pixYScale < 1.0)
974 : : {
975 : :
976 : 0 : double qualityScale = (pixXScale + pixYScale)/2;
977 : :
978 : 0 : nJPEGQuality = (sal_Int32)( nJPEGQuality * qualityScale );
979 : :
980 : 0 : if (nJPEGQuality < 10)
981 : 0 : nJPEGQuality += 3;
982 : : }
983 : :
984 : 0 : sal_uInt16 nBitmapId = defineBitmap(bmpSource, nJPEGQuality);
985 : :
986 : 0 : Polygon aPoly( destRect );
987 : :
988 : : // AS: Since images are being cropped now, no translation is normally necessary.
989 : : // However, some things like graphical bullet points are still get translated.
990 : 0 : ::basegfx::B2DHomMatrix m; // #i73264#
991 : 0 : m.scale(1.0/XScale, 1.0/YScale );
992 : 0 : if (destRect.Left() || destRect.Top())
993 : 0 : m.translate(destRect.Left(), destRect.Top());
994 : :
995 : 0 : FillStyle aFillStyle( nBitmapId, true, m );
996 : :
997 : 0 : sal_uInt16 nShapeId = defineShape( aPoly, aFillStyle );
998 : :
999 : 0 : maShapeIds.push_back( nShapeId );
1000 : 0 : }
1001 : : }
1002 : 0 : }
1003 : : // -----------------------------------------------------------------------------
1004 : :
1005 : 0 : void Writer::Impl_writeBmp( sal_uInt16 nBitmapId, sal_uInt32 width, sal_uInt32 height, sal_uInt8 *pCompressed, sal_uInt32 compressed_size )
1006 : : {
1007 : 0 : startTag( TAG_DEFINEBITSLOSSLESS2 );
1008 : :
1009 : 0 : mpTag->addUI16( nBitmapId );
1010 : 0 : mpTag->addUI8( 5 );
1011 : 0 : mpTag->addUI16( _uInt16(width) );
1012 : 0 : mpTag->addUI16( _uInt16(height) );
1013 : :
1014 : 0 : mpTag->Write( pCompressed, compressed_size );
1015 : :
1016 : 0 : endTag();
1017 : 0 : }
1018 : :
1019 : : // -----------------------------------------------------------------------------
1020 : :
1021 : 0 : void Writer::Impl_writeJPEG(sal_uInt16 nBitmapId, const sal_uInt8* pJpgData, sal_uInt32 nJpgDataLength, sal_uInt8 *pAlphaCompressed, sal_uInt32 alpha_compressed_size )
1022 : : {
1023 : : // AS: Go through the actuall JPEG bits, seperating out the
1024 : : // header fields from the actual image fields. Fields are
1025 : : // identifed by 0xFFXX where XX is the field type. Both
1026 : : // the header and the image need start and stop (D8 and D9),
1027 : : // so that's why you see those written to both. I don't
1028 : : // really know what the rest of these are, I got it to work
1029 : : // kind of by trial and error and by comparing with known
1030 : : // good SWF files.
1031 : 0 : sal_uInt8 cType = 0x01;
1032 : 0 : const sal_uInt8* pJpgSearch = pJpgData;
1033 : :
1034 : 0 : int nLength = 0;
1035 : :
1036 : 0 : SvMemoryStream EncodingTableStream;
1037 : 0 : SvMemoryStream ImageBitsStream;
1038 : 0 : for (;pJpgSearch < pJpgData + nJpgDataLength; pJpgSearch += nLength)
1039 : : {
1040 : :
1041 : : #ifdef DBG_UTIL
1042 : : if (0xFF != *pJpgSearch)
1043 : : {
1044 : : OSL_FAIL( "Expected JPEG marker." ); ((void)0);
1045 : : }
1046 : : #endif
1047 : :
1048 : 0 : cType = *(pJpgSearch + 1);
1049 : :
1050 : 0 : if (0xD8 == cType || 0xD9 == cType)
1051 : : {
1052 : 0 : nLength = 2;
1053 : : }
1054 : 0 : else if (0xDA == cType)
1055 : : {
1056 : : //AS: This is the actual image data, and runs to the
1057 : : // end of the file (as best I know), minus 2 bytes
1058 : : // for the closing 0xFFD9.
1059 : 0 : nLength = nJpgDataLength - (pJpgSearch - pJpgData) - 2;
1060 : : }
1061 : : else
1062 : : {
1063 : : // AS: Lengths are big endian.
1064 : :
1065 : : // Beware. pJpgSearch is not necessarily word-aligned,
1066 : : // so we access it byte-wise.
1067 : :
1068 : : // AS: Add 2 to the length to include the 0xFFXX itself.
1069 : 0 : nLength = 2 + (pJpgSearch[2]<<8) + pJpgSearch[3];
1070 : : }
1071 : :
1072 : : // AS: I'm refering to libjpeg for a list of what these
1073 : : // markers are. See jdmarker.c for a list.
1074 : : // AS: I'm ignoring application specific markers 0xE1...0xEF
1075 : : // and comments 0xFE. I don't know what
1076 : : // 0xF0 or 0xFD are for, and they don't come up.
1077 : : // Additionally, 0xDE and 0xDF aren't clear to me.
1078 : 0 : switch(cType)
1079 : : {
1080 : : case 0xD8:
1081 : : case 0xD9:
1082 : 0 : EncodingTableStream.Write( pJpgSearch, nLength );
1083 : 0 : ImageBitsStream.Write( pJpgSearch, nLength );
1084 : 0 : break;
1085 : :
1086 : : case 0x01:
1087 : : case 0xDB:
1088 : : case 0xDC:
1089 : : case 0xDD:
1090 : : case 0xC4:
1091 : 0 : EncodingTableStream.Write( pJpgSearch, nLength );
1092 : 0 : break;
1093 : :
1094 : : case 0xC0:
1095 : : case 0xC1:
1096 : : case 0xC2:
1097 : : case 0xC3:
1098 : : case 0xC5:
1099 : : case 0xC6:
1100 : : case 0xC7:
1101 : : // case 0xC8: Apparently reserved for JPEG extensions?
1102 : : case 0xC9:
1103 : : case 0xCA:
1104 : : case 0xCB:
1105 : : case 0xCD:
1106 : : case 0xCE:
1107 : : case 0xCF:
1108 : : case 0xDA:
1109 : : case 0xE0:
1110 : 0 : ImageBitsStream.Write( pJpgSearch, nLength );
1111 : 0 : break;
1112 : :
1113 : : default:
1114 : : OSL_FAIL( "JPEG marker I didn't handle!" );
1115 : :
1116 : : }
1117 : : }
1118 : :
1119 : 0 : EncodingTableStream.Seek( STREAM_SEEK_TO_END );
1120 : 0 : sal_uInt32 nEncodingTableSize = EncodingTableStream.Tell();
1121 : 0 : EncodingTableStream.Seek( STREAM_SEEK_TO_BEGIN );
1122 : :
1123 : 0 : ImageBitsStream.Seek( STREAM_SEEK_TO_END );
1124 : 0 : sal_uInt32 nImageBitsSize = ImageBitsStream.Tell();
1125 : 0 : ImageBitsStream.Seek( STREAM_SEEK_TO_BEGIN );
1126 : :
1127 : : // AS: If we need alpha support, use TAG_DEFINEBITSJPEG3.
1128 : 0 : if (alpha_compressed_size > 0)
1129 : : {
1130 : 0 : startTag( TAG_DEFINEBITSJPEG3 );
1131 : :
1132 : 0 : mpTag->addUI16( nBitmapId );
1133 : :
1134 : 0 : mpTag->addUI32( nEncodingTableSize + nImageBitsSize );
1135 : :
1136 : 0 : mpTag->Write(EncodingTableStream.GetData(), nEncodingTableSize);
1137 : 0 : mpTag->Write(ImageBitsStream.GetData(), nImageBitsSize);
1138 : :
1139 : 0 : mpTag->Write( pAlphaCompressed, alpha_compressed_size );
1140 : :
1141 : 0 : endTag();
1142 : : }
1143 : : else
1144 : : {
1145 : 0 : startTag( TAG_DEFINEBITSJPEG2 );
1146 : :
1147 : 0 : mpTag->addUI16( nBitmapId );
1148 : :
1149 : 0 : mpTag->Write(EncodingTableStream.GetData(), nEncodingTableSize);
1150 : 0 : mpTag->Write(ImageBitsStream.GetData(), nImageBitsSize);
1151 : :
1152 : 0 : endTag();
1153 : 0 : }
1154 : 0 : }
1155 : :
1156 : : // -----------------------------------------------------------------------------
1157 : :
1158 : 0 : void Writer::Impl_writeLine( const Point& rPt1, const Point& rPt2, const Color* pLineColor )
1159 : : {
1160 : 0 : Color aOldColor( mpVDev->GetLineColor() );
1161 : 0 : if( pLineColor )
1162 : 0 : mpVDev->SetLineColor( *pLineColor );
1163 : :
1164 : 0 : const Point aPtAry[2] = { rPt1, rPt2 };
1165 : 0 : Polygon aPoly( 2, aPtAry );
1166 : 0 : Impl_writePolyPolygon( aPoly, false );
1167 : :
1168 : 0 : mpVDev->SetLineColor( aOldColor );
1169 : 0 : }
1170 : :
1171 : : // -----------------------------------------------------------------------------
1172 : :
1173 : 0 : void Writer::Impl_writeRect( const Rectangle& rRect, long nRadX, long nRadY )
1174 : : {
1175 : 0 : if( (rRect.nTop == rRect.nBottom) || (rRect.nLeft == rRect.nRight) )
1176 : : {
1177 : 0 : Color aColor( mpVDev->GetFillColor() );
1178 : 0 : Impl_writeLine( rRect.TopLeft(), rRect.BottomRight(), &aColor );
1179 : : }
1180 : : else
1181 : : {
1182 : 0 : Polygon aPoly( rRect, nRadX, nRadY );
1183 : 0 : Impl_writePolyPolygon( aPoly, true );
1184 : : }
1185 : 0 : }
1186 : :
1187 : : // -----------------------------------------------------------------------------
1188 : :
1189 : 0 : void Writer::Impl_writeEllipse( const Point& rCenter, long nRadX, long nRadY )
1190 : : {
1191 : 0 : Polygon aPoly( rCenter, nRadX, nRadY );
1192 : 0 : Impl_writePolyPolygon( aPoly, false );
1193 : 0 : }
1194 : :
1195 : :
1196 : : /** writes the stroke defined by SvtGraphicStroke and returns true or it returns
1197 : : false if it can't handle this stroke.
1198 : : */
1199 : 0 : bool Writer::Impl_writeStroke( SvtGraphicStroke& rStroke )
1200 : : {
1201 : 0 : Polygon aPolygon;
1202 : 0 : rStroke.getPath( aPolygon );
1203 : 0 : PolyPolygon aPolyPolygon( aPolygon );
1204 : :
1205 : 0 : map( aPolyPolygon );
1206 : :
1207 : : // as log as not LINESTYLE2 and DefineShape4 is used (which
1208 : : // added support for LineJoin), only round LineJoins are
1209 : : // supported. Fallback to META_POLYLINE_ACTION and META_LINE_ACTION
1210 : 0 : if(SvtGraphicStroke::joinRound != rStroke.getJoinType())
1211 : 0 : return false;
1212 : :
1213 : 0 : PolyPolygon aStartArrow;
1214 : 0 : rStroke.getStartArrow( aStartArrow );
1215 : 0 : if( 0 != aStartArrow.Count() )
1216 : 0 : return false; // todo: Implement line ends
1217 : :
1218 : 0 : PolyPolygon aEndArrow;
1219 : 0 : rStroke.getEndArrow( aEndArrow );
1220 : 0 : if( 0 != aEndArrow.Count() )
1221 : 0 : return false; // todo: Implement line ends
1222 : :
1223 : 0 : SvtGraphicStroke::DashArray aDashArray;
1224 : 0 : rStroke.getDashArray( aDashArray );
1225 : 0 : if( 0 != aDashArray.size() )
1226 : 0 : return false; // todo: implement dashes
1227 : :
1228 : 0 : Color aColor( mpVDev->GetLineColor() );
1229 : :
1230 : 0 : if( 0.0 != rStroke.getTransparency() )
1231 : 0 : aColor.SetTransparency( sal::static_int_cast<sal_uInt8>( MinMax( (long int)( rStroke.getTransparency() * 0xff ), 0, 0xff ) ) );
1232 : :
1233 : 0 : sal_uInt16 nShapeId = defineShape( aPolyPolygon, sal::static_int_cast<sal_uInt16>( mapRelative( (sal_Int32)( rStroke.getStrokeWidth() ) ) ), aColor );
1234 : 0 : maShapeIds.push_back( nShapeId );
1235 : 0 : return true;
1236 : : }
1237 : :
1238 : : // -----------------------------------------------------------------------------
1239 : :
1240 : : /** writes the filling defined by SvtGraphicFill and returns true or it returns
1241 : : false if it can't handle this filling.
1242 : : */
1243 : 0 : bool Writer::Impl_writeFilling( SvtGraphicFill& rFilling )
1244 : : {
1245 : 0 : PolyPolygon aPolyPolygon;
1246 : 0 : rFilling.getPath( aPolyPolygon );
1247 : :
1248 : 0 : Rectangle aOldRect( aPolyPolygon.GetBoundRect() );
1249 : :
1250 : 0 : map( aPolyPolygon );
1251 : :
1252 : 0 : Rectangle aNewRect( aPolyPolygon.GetBoundRect() );
1253 : :
1254 : 0 : switch( rFilling.getFillType() )
1255 : : {
1256 : : case SvtGraphicFill::fillSolid:
1257 : : {
1258 : 0 : Color aColor( rFilling.getFillColor() );
1259 : :
1260 : 0 : if( 0.0 != rFilling.getTransparency() )
1261 : 0 : aColor.SetTransparency( sal::static_int_cast<sal_uInt8>( MinMax( (long int)( rFilling.getTransparency() * 0xff ) , 0, 0xff ) ) );
1262 : :
1263 : 0 : FillStyle aFillStyle( aColor );
1264 : :
1265 : 0 : sal_uInt16 nShapeId = defineShape( aPolyPolygon, aFillStyle );
1266 : 0 : maShapeIds.push_back( nShapeId );
1267 : : }
1268 : 0 : break;
1269 : : case SvtGraphicFill::fillGradient:
1270 : 0 : return false;
1271 : : case SvtGraphicFill::fillHatch:
1272 : 0 : return false;
1273 : : case SvtGraphicFill::fillTexture:
1274 : : {
1275 : 0 : Graphic aGraphic;
1276 : 0 : rFilling.getGraphic( aGraphic );
1277 : :
1278 : : // CL->AS: Should we also scale down the quality here depending on image scale?
1279 : 0 : sal_uInt16 nBitmapId = defineBitmap( aGraphic.GetBitmapEx(), mnJPEGCompressMode );
1280 : :
1281 : 0 : ::basegfx::B2DHomMatrix aMatrix; // #i73264#
1282 : :
1283 : 0 : SvtGraphicFill::Transform aTransform;
1284 : :
1285 : 0 : rFilling.getTransform( aTransform );
1286 : :
1287 : : sal_uInt16 a,b;
1288 : 0 : for( a = 0; a < 2; a++ )
1289 : : {
1290 : 0 : for( b = 0; b < 3; b++ )
1291 : : {
1292 : 0 : aMatrix.set(a, b, aTransform.matrix[a*3+b]);
1293 : : }
1294 : : }
1295 : 0 : aMatrix.set(2, 0, 0.0);
1296 : 0 : aMatrix.set(2, 1, 0.0);
1297 : 0 : aMatrix.set(2, 2, 1.0);
1298 : :
1299 : : // scale bitmap
1300 : 0 : double XScale = (double)aNewRect.GetWidth()/aOldRect.GetWidth();
1301 : 0 : double YScale = (double)aNewRect.GetHeight()/aOldRect.GetHeight();
1302 : :
1303 : 0 : aMatrix.scale( XScale, YScale );
1304 : :
1305 : 0 : FillStyle aFillStyle( nBitmapId, !rFilling.IsTiling(), aMatrix );
1306 : :
1307 : 0 : sal_uInt16 nShapeId = defineShape( aPolyPolygon, aFillStyle );
1308 : 0 : maShapeIds.push_back( nShapeId );
1309 : : }
1310 : 0 : break;
1311 : : }
1312 : 0 : return true;
1313 : : }
1314 : :
1315 : : // -----------------------------------------------------------------------------
1316 : :
1317 : : /* CL: The idea was to export page fields as text fields that get theire
1318 : : string from a variable set with actionscript by each page. This didn't
1319 : : work out since the formating is always wrong when text follows the
1320 : : page number field since pages greater one may require more space than
1321 : : page 1
1322 : : */
1323 : : #if 0
1324 : : bool Writer::Impl_writePageField( Rectangle& rTextBounds )
1325 : : {
1326 : : startTag( TAG_DEFINEEDITTEXT );
1327 : :
1328 : : sal_uInt16 nTextId = createID();
1329 : :
1330 : : mpTag->addUI16( nTextId );
1331 : : mpTag->addRect( rTextBounds );
1332 : :
1333 : : BitStream aBits;
1334 : : aBits.writeUB( 1, 1 ); // HasText
1335 : : aBits.writeUB( 0, 1 ); // WordWrap
1336 : : aBits.writeUB( 0, 1 ); // MultiLine
1337 : : aBits.writeUB( 0, 1 ); // Password
1338 : : aBits.writeUB( 1, 1 ); // HasTextColor
1339 : : aBits.writeUB( 0, 1 ); // HasMaxLength
1340 : : aBits.writeUB( 0, 1 ); // HasFont
1341 : : aBits.writeUB( 0, 1 ); // Reserved
1342 : : aBits.writeUB( 0, 1 ); // AutoSize
1343 : : aBits.writeUB( 0, 1 ); // HasLayout
1344 : : aBits.writeUB( 1, 1 ); // NoSelect
1345 : : aBits.writeUB( 1, 1 ); // Border
1346 : : aBits.writeUB( 0, 1 ); // Reserved
1347 : : aBits.writeUB( 0, 1 ); // HTML
1348 : : aBits.writeUB( 0, 1 ); // UseOutlines
1349 : : mpTag->addBits( aBits );
1350 : :
1351 : : Color aColor( COL_BLACK );
1352 : : mpTag->addRGB( aColor );
1353 : : mpTag->addString( "PageNumber" );
1354 : : mpTag->addString( "XXX" );
1355 : :
1356 : : endTag();
1357 : :
1358 : : maShapeIds.push_back( nTextId );
1359 : :
1360 : : return true;
1361 : : }
1362 : : #endif
1363 : :
1364 : : // -----------------------------------------------------------------------------
1365 : :
1366 : 0 : void Writer::Impl_handleLineInfoPolyPolygons(const LineInfo& rInfo, const basegfx::B2DPolygon& rLinePolygon)
1367 : : {
1368 : 0 : if(rLinePolygon.count())
1369 : : {
1370 : 0 : basegfx::B2DPolyPolygon aLinePolyPolygon(rLinePolygon);
1371 : 0 : basegfx::B2DPolyPolygon aFillPolyPolygon;
1372 : :
1373 : 0 : rInfo.applyToB2DPolyPolygon(aLinePolyPolygon, aFillPolyPolygon);
1374 : :
1375 : 0 : if(aLinePolyPolygon.count())
1376 : : {
1377 : 0 : for(sal_uInt32 a(0); a < aLinePolyPolygon.count(); a++)
1378 : : {
1379 : 0 : const basegfx::B2DPolygon aCandidate(aLinePolyPolygon.getB2DPolygon(a));
1380 : 0 : Impl_writePolygon(Polygon(aCandidate), sal_False );
1381 : 0 : }
1382 : : }
1383 : :
1384 : 0 : if(aFillPolyPolygon.count())
1385 : : {
1386 : 0 : const Color aOldLineColor(mpVDev->GetLineColor());
1387 : 0 : const Color aOldFillColor(mpVDev->GetFillColor());
1388 : :
1389 : 0 : mpVDev->SetLineColor();
1390 : 0 : mpVDev->SetFillColor(aOldLineColor);
1391 : :
1392 : 0 : for(sal_uInt32 a(0); a < aFillPolyPolygon.count(); a++)
1393 : : {
1394 : 0 : const Polygon aPolygon(aFillPolyPolygon.getB2DPolygon(a));
1395 : 0 : Impl_writePolyPolygon(PolyPolygon(Polygon(aPolygon)), sal_True );
1396 : 0 : }
1397 : :
1398 : 0 : mpVDev->SetLineColor(aOldLineColor);
1399 : 0 : mpVDev->SetFillColor(aOldFillColor);
1400 : 0 : }
1401 : : }
1402 : 0 : }
1403 : :
1404 : : // -----------------------------------------------------------------------------
1405 : :
1406 : 0 : void Writer::Impl_writeActions( const GDIMetaFile& rMtf )
1407 : : {
1408 : 0 : Rectangle clipRect;
1409 : 0 : int bMap = 0;
1410 : 0 : for( size_t i = 0, nCount = rMtf.GetActionSize(); i < nCount; i++ )
1411 : : {
1412 : 0 : const MetaAction* pAction = rMtf.GetAction( i );
1413 : 0 : const sal_uInt16 nType = pAction->GetType();
1414 : :
1415 : 0 : switch( nType )
1416 : : {
1417 : : case( META_PIXEL_ACTION ):
1418 : : {
1419 : 0 : const MetaPixelAction* pA = (const MetaPixelAction*) pAction;
1420 : :
1421 : 0 : Impl_writeLine( pA->GetPoint(), pA->GetPoint(), &pA->GetColor() );
1422 : : }
1423 : 0 : break;
1424 : :
1425 : : case( META_POINT_ACTION ):
1426 : : {
1427 : 0 : const MetaPointAction* pA = (const MetaPointAction*) pAction;
1428 : :
1429 : 0 : Impl_writeLine( pA->GetPoint(), pA->GetPoint() );
1430 : : }
1431 : 0 : break;
1432 : :
1433 : : case( META_LINE_ACTION ):
1434 : : {
1435 : 0 : const MetaLineAction* pA = (const MetaLineAction*) pAction;
1436 : :
1437 : 0 : if(pA->GetLineInfo().IsDefault())
1438 : : {
1439 : 0 : Impl_writeLine( pA->GetStartPoint(), pA->GetEndPoint() );
1440 : : }
1441 : : else
1442 : : {
1443 : : // LineInfo used; handle Dash/Dot and fat lines
1444 : 0 : basegfx::B2DPolygon aPolygon;
1445 : 0 : aPolygon.append(basegfx::B2DPoint(pA->GetStartPoint().X(), pA->GetStartPoint().Y()));
1446 : 0 : aPolygon.append(basegfx::B2DPoint(pA->GetEndPoint().X(), pA->GetEndPoint().Y()));
1447 : 0 : Impl_handleLineInfoPolyPolygons(pA->GetLineInfo(), aPolygon);
1448 : : }
1449 : : }
1450 : 0 : break;
1451 : :
1452 : : case( META_RECT_ACTION ):
1453 : : {
1454 : 0 : Impl_writeRect( ( (const MetaRectAction*) pAction )->GetRect(), 0, 0 );
1455 : : }
1456 : 0 : break;
1457 : :
1458 : : case( META_ROUNDRECT_ACTION ):
1459 : : {
1460 : 0 : const MetaRoundRectAction* pA = (const MetaRoundRectAction*) pAction;
1461 : :
1462 : 0 : Impl_writeRect( pA->GetRect(), pA->GetHorzRound(), pA->GetVertRound() );
1463 : : }
1464 : 0 : break;
1465 : :
1466 : : case( META_ELLIPSE_ACTION ):
1467 : : {
1468 : 0 : const MetaEllipseAction* pA = (const MetaEllipseAction*) pAction;
1469 : 0 : const Rectangle& rRect = pA->GetRect();
1470 : :
1471 : 0 : Impl_writeEllipse( rRect.Center(), rRect.GetWidth() >> 1, rRect.GetHeight() >> 1 );
1472 : : }
1473 : 0 : break;
1474 : :
1475 : : case( META_ARC_ACTION ):
1476 : : case( META_PIE_ACTION ):
1477 : : case( META_CHORD_ACTION ):
1478 : : case( META_POLYGON_ACTION ):
1479 : : {
1480 : 0 : Polygon aPoly;
1481 : :
1482 : 0 : switch( nType )
1483 : : {
1484 : : case( META_ARC_ACTION ):
1485 : : {
1486 : 0 : const MetaArcAction* pA = (const MetaArcAction*) pAction;
1487 : 0 : aPoly = Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_ARC );
1488 : : }
1489 : 0 : break;
1490 : :
1491 : : case( META_PIE_ACTION ):
1492 : : {
1493 : 0 : const MetaPieAction* pA = (const MetaPieAction*) pAction;
1494 : 0 : aPoly = Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_PIE );
1495 : : }
1496 : 0 : break;
1497 : :
1498 : : case( META_CHORD_ACTION ):
1499 : : {
1500 : 0 : const MetaChordAction* pA = (const MetaChordAction*) pAction;
1501 : 0 : aPoly = Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_CHORD );
1502 : : }
1503 : 0 : break;
1504 : :
1505 : : case( META_POLYGON_ACTION ):
1506 : 0 : aPoly = ( (const MetaPolygonAction*) pAction )->GetPolygon();
1507 : 0 : break;
1508 : : }
1509 : :
1510 : 0 : if( aPoly.GetSize() )
1511 : : {
1512 : 0 : Impl_writePolygon( aPoly, sal_True );
1513 : 0 : }
1514 : : }
1515 : 0 : break;
1516 : :
1517 : : case( META_POLYLINE_ACTION ):
1518 : : {
1519 : 0 : const MetaPolyLineAction* pA = (const MetaPolyLineAction*) pAction;
1520 : 0 : const Polygon& rPoly = pA->GetPolygon();
1521 : :
1522 : 0 : if( rPoly.GetSize() )
1523 : : {
1524 : 0 : if(pA->GetLineInfo().IsDefault())
1525 : : {
1526 : 0 : Impl_writePolygon( rPoly, sal_False );
1527 : : }
1528 : : else
1529 : : {
1530 : : // LineInfo used; handle Dash/Dot and fat lines
1531 : 0 : Impl_handleLineInfoPolyPolygons(pA->GetLineInfo(), rPoly.getB2DPolygon());
1532 : : }
1533 : : }
1534 : : }
1535 : 0 : break;
1536 : :
1537 : : case( META_POLYPOLYGON_ACTION ):
1538 : : {
1539 : 0 : const MetaPolyPolygonAction* pA = (const MetaPolyPolygonAction*) pAction;
1540 : 0 : const PolyPolygon& rPolyPoly = pA->GetPolyPolygon();
1541 : :
1542 : 0 : if( rPolyPoly.Count() )
1543 : 0 : Impl_writePolyPolygon( rPolyPoly, sal_True );
1544 : : }
1545 : 0 : break;
1546 : :
1547 : : case( META_GRADIENT_ACTION ):
1548 : : {
1549 : 0 : const MetaGradientAction* pA = (const MetaGradientAction*) pAction;
1550 : :
1551 : 0 : Polygon aPoly( pA->GetRect() );
1552 : 0 : Impl_writeGradientEx( aPoly, pA->GetGradient() );
1553 : : }
1554 : 0 : break;
1555 : :
1556 : : case( META_GRADIENTEX_ACTION ):
1557 : : {
1558 : 0 : const MetaGradientExAction* pA = (const MetaGradientExAction*) pAction;
1559 : 0 : Impl_writeGradientEx( pA->GetPolyPolygon(), pA->GetGradient() );
1560 : : }
1561 : 0 : break;
1562 : :
1563 : : case META_HATCH_ACTION:
1564 : : {
1565 : 0 : const MetaHatchAction* pA = (const MetaHatchAction*) pAction;
1566 : 0 : GDIMetaFile aTmpMtf;
1567 : :
1568 : 0 : mpVDev->AddHatchActions( pA->GetPolyPolygon(), pA->GetHatch(), aTmpMtf );
1569 : 0 : Impl_writeActions( aTmpMtf );
1570 : : }
1571 : 0 : break;
1572 : :
1573 : : case( META_TRANSPARENT_ACTION ):
1574 : : {
1575 : 0 : const MetaTransparentAction* pA = (const MetaTransparentAction*) pAction;
1576 : 0 : const PolyPolygon& rPolyPoly = pA->GetPolyPolygon();
1577 : :
1578 : 0 : if( rPolyPoly.Count() )
1579 : : {
1580 : : // convert transparence from percent into 0x00 - 0xff
1581 : 0 : sal_uInt8 nTransparence = (sal_uInt8) MinMax( FRound( pA->GetTransparence() * 2.55 ), 0, 255 );
1582 : 0 : Impl_writePolyPolygon( rPolyPoly, sal_True, nTransparence );
1583 : : }
1584 : : }
1585 : 0 : break;
1586 : :
1587 : : case( META_FLOATTRANSPARENT_ACTION ):
1588 : : {
1589 : 0 : const MetaFloatTransparentAction* pA = (const MetaFloatTransparentAction*) pAction;
1590 : 0 : GDIMetaFile aTmpMtf( pA->GetGDIMetaFile() );
1591 : 0 : Point aSrcPt( aTmpMtf.GetPrefMapMode().GetOrigin() );
1592 : 0 : const Size aSrcSize( aTmpMtf.GetPrefSize() );
1593 : 0 : const Point aDestPt( pA->GetPoint() );
1594 : 0 : const Size aDestSize( pA->GetSize() );
1595 : 0 : const double fScaleX = aSrcSize.Width() ? (double) aDestSize.Width() / aSrcSize.Width() : 1.0;
1596 : 0 : const double fScaleY = aSrcSize.Height() ? (double) aDestSize.Height() / aSrcSize.Height() : 1.0;
1597 : : long nMoveX, nMoveY;
1598 : :
1599 : 0 : if( fScaleX != 1.0 || fScaleY != 1.0 )
1600 : : {
1601 : 0 : aTmpMtf.Scale( fScaleX, fScaleY );
1602 : 0 : aSrcPt.X() = FRound( aSrcPt.X() * fScaleX );
1603 : 0 : aSrcPt.Y() = FRound( aSrcPt.Y() * fScaleY );
1604 : : }
1605 : :
1606 : 0 : nMoveX = aDestPt.X() - aSrcPt.X(), nMoveY = aDestPt.Y() - aSrcPt.Y();
1607 : :
1608 : 0 : if( nMoveX || nMoveY )
1609 : 0 : aTmpMtf.Move( nMoveX, nMoveY );
1610 : :
1611 : 0 : const Gradient& rGradient = pA->GetGradient();
1612 : 0 : sal_uInt32 nLuminance = ((sal_Int32)rGradient.GetStartColor().GetLuminance() + (sal_Int32)rGradient.GetEndColor().GetLuminance() ) >> 1;
1613 : :
1614 : 0 : sal_uInt8 nOldGlobalTransparency = mnGlobalTransparency;
1615 : 0 : mnGlobalTransparency = (sal_uInt8)MinMax( nLuminance, 0, 0xff );
1616 : :
1617 : 0 : mpVDev->Push();
1618 : 0 : Impl_writeActions( aTmpMtf );
1619 : 0 : mpVDev->Pop();
1620 : :
1621 : 0 : mnGlobalTransparency = nOldGlobalTransparency;
1622 : : }
1623 : 0 : break;
1624 : :
1625 : : case( META_EPS_ACTION ):
1626 : : {
1627 : 0 : const MetaEPSAction* pA = (const MetaEPSAction*) pAction;
1628 : 0 : const GDIMetaFile aGDIMetaFile( pA->GetSubstitute() );
1629 : 0 : sal_Bool bFound = sal_False;
1630 : :
1631 : 0 : for( size_t j = 0, nC = aGDIMetaFile.GetActionSize(); ( j < nC ) && !bFound; j++ )
1632 : : {
1633 : 0 : const MetaAction* pSubstAct = aGDIMetaFile.GetAction( j );
1634 : :
1635 : 0 : if( pSubstAct->GetType() == META_BMPSCALE_ACTION )
1636 : : {
1637 : 0 : bFound = sal_True;
1638 : 0 : const MetaBmpScaleAction* pBmpScaleAction = (const MetaBmpScaleAction*) pSubstAct;
1639 : 0 : Impl_writeImage( pBmpScaleAction->GetBitmap(),
1640 : 0 : pA->GetPoint(), pA->GetSize(),
1641 : 0 : Point(), pBmpScaleAction->GetBitmap().GetSizePixel(), clipRect, 1 == bMap );
1642 : : }
1643 : 0 : }
1644 : : }
1645 : 0 : break;
1646 : :
1647 : : case( META_COMMENT_ACTION ):
1648 : : {
1649 : 0 : const MetaCommentAction* pA = (const MetaCommentAction*) pAction;
1650 : 0 : const sal_uInt8* pData = pA->GetData();
1651 : 0 : String aSkipComment;
1652 : :
1653 : 0 : if( pA->GetComment().equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XGRAD_SEQ_BEGIN")) )
1654 : : {
1655 : 0 : const MetaGradientExAction* pGradAction = NULL;
1656 : 0 : sal_Bool bDone = sal_False;
1657 : :
1658 : 0 : while( !bDone && ( ++i < nCount ) )
1659 : : {
1660 : 0 : pAction = rMtf.GetAction( i );
1661 : :
1662 : 0 : if( pAction->GetType() == META_GRADIENTEX_ACTION )
1663 : 0 : pGradAction = (const MetaGradientExAction*) pAction;
1664 : 0 : else if( ( pAction->GetType() == META_COMMENT_ACTION ) &&
1665 : 0 : ( ( (const MetaCommentAction*) pAction )->GetComment().equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XGRAD_SEQ_END")) ) )
1666 : : {
1667 : 0 : bDone = sal_True;
1668 : : }
1669 : : }
1670 : :
1671 : 0 : if( pGradAction )
1672 : 0 : Impl_writeGradientEx( pGradAction->GetPolyPolygon(), pGradAction->GetGradient());
1673 : : }
1674 : 0 : else if( pA->GetComment().equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XPATHFILL_SEQ_BEGIN")) &&
1675 : : pData )
1676 : : {
1677 : :
1678 : : // this comment encapsulates all high level information for a filling that caused
1679 : : // the meta actions between the "XPATHFILL_SEQ_BEGIN" and "XPATHFILL_SEQ_END" comment.
1680 : :
1681 : 0 : SvtGraphicFill aFilling;
1682 : 0 : SvMemoryStream aMemStm( (void*)pData, pA->GetDataSize(), STREAM_READ );
1683 : :
1684 : : // read the fill info
1685 : 0 : aMemStm >> aFilling;
1686 : :
1687 : : // if impl_writeFilling can handle this high level filling, it returns true and we
1688 : : // skip all meta actions until "XPATHFILL_SEQ_END"
1689 : 0 : if( Impl_writeFilling( aFilling ) )
1690 : : {
1691 : 0 : bool bDone = sal_False;
1692 : :
1693 : 0 : while( !bDone && ( ++i < nCount ) )
1694 : : {
1695 : 0 : pAction = rMtf.GetAction( i );
1696 : :
1697 : 0 : if( ( pAction->GetType() == META_COMMENT_ACTION ) &&
1698 : 0 : ( ( (const MetaCommentAction*) pAction )->GetComment().equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XPATHFILL_SEQ_END")) ) )
1699 : : {
1700 : 0 : bDone = sal_True;
1701 : : }
1702 : : }
1703 : 0 : }
1704 : : }
1705 : 0 : else if( pA->GetComment().equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XPATHSTROKE_SEQ_BEGIN")) &&
1706 : : pData )
1707 : : {
1708 : :
1709 : : // this comment encapsulates all high level information for a filling that caused
1710 : : // the meta actions between the "XPATHFILL_SEQ_BEGIN" and "XPATHFILL_SEQ_END" comment.
1711 : :
1712 : 0 : SvtGraphicStroke aStroke;
1713 : 0 : SvMemoryStream aMemStm( (void*)pData, pA->GetDataSize(), STREAM_READ );
1714 : :
1715 : : // read the fill info
1716 : 0 : aMemStm >> aStroke;
1717 : :
1718 : : // if impl_writeStroke can handle this high level stroke, it returns true and we
1719 : : // skip all meta actions until "XPATHSTROKE_SEQ_END"
1720 : 0 : if( Impl_writeStroke( aStroke ) )
1721 : : {
1722 : 0 : bool bDone = sal_False;
1723 : :
1724 : 0 : while( !bDone && ( ++i < nCount ) )
1725 : : {
1726 : 0 : pAction = rMtf.GetAction( i );
1727 : :
1728 : 0 : if( ( pAction->GetType() == META_COMMENT_ACTION ) &&
1729 : 0 : ( ( (const MetaCommentAction*) pAction )->GetComment().equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XPATHSTROKE_SEQ_END")) ) )
1730 : : {
1731 : 0 : bDone = sal_True;
1732 : : }
1733 : : }
1734 : 0 : }
1735 : 0 : }
1736 : : }
1737 : 0 : break;
1738 : :
1739 : : case( META_BMPSCALE_ACTION ):
1740 : : {
1741 : 0 : const MetaBmpScaleAction* pA = (const MetaBmpScaleAction*) pAction;
1742 : :
1743 : 0 : Impl_writeImage( pA->GetBitmap(),
1744 : 0 : pA->GetPoint(), pA->GetSize(),
1745 : 0 : Point(), pA->GetBitmap().GetSizePixel(), clipRect, 1 == bMap );
1746 : : }
1747 : 0 : break;
1748 : :
1749 : : case( META_BMP_ACTION ):
1750 : : {
1751 : 0 : const MetaBmpAction* pA = (const MetaBmpAction*) pAction;
1752 : 0 : Impl_writeImage( pA->GetBitmap(),
1753 : 0 : pA->GetPoint(), mpVDev->PixelToLogic( pA->GetBitmap().GetSizePixel()),
1754 : 0 : Point(), pA->GetBitmap().GetSizePixel(), clipRect, 1 ==bMap );
1755 : : }
1756 : 0 : break;
1757 : :
1758 : : case( META_BMPSCALEPART_ACTION ):
1759 : : {
1760 : 0 : const MetaBmpScalePartAction* pA = (const MetaBmpScalePartAction*) pAction;
1761 : 0 : Impl_writeImage( pA->GetBitmap(),
1762 : 0 : pA->GetDestPoint(), pA->GetDestSize(),
1763 : 0 : pA->GetSrcPoint(), pA->GetSrcSize(), clipRect, 1 == bMap );
1764 : : }
1765 : 0 : break;
1766 : :
1767 : : case( META_BMPEX_ACTION ):
1768 : : {
1769 : 0 : const MetaBmpExAction* pA = (const MetaBmpExAction*) pAction;
1770 : 0 : Impl_writeImage( pA->GetBitmapEx(),
1771 : 0 : pA->GetPoint(), mpVDev->PixelToLogic( pA->GetBitmapEx().GetSizePixel() ),
1772 : 0 : Point(), pA->GetBitmapEx().GetSizePixel(), clipRect, 1 == bMap );
1773 : : }
1774 : 0 : break;
1775 : :
1776 : : case( META_BMPEXSCALE_ACTION ):
1777 : : {
1778 : 0 : const MetaBmpExScaleAction* pA = (const MetaBmpExScaleAction*) pAction;
1779 : 0 : Impl_writeImage( pA->GetBitmapEx(),
1780 : 0 : pA->GetPoint(), pA->GetSize(),
1781 : 0 : Point(), pA->GetBitmapEx().GetSizePixel(), clipRect, 1 == bMap );
1782 : : }
1783 : 0 : break;
1784 : :
1785 : : case( META_BMPEXSCALEPART_ACTION ):
1786 : : {
1787 : 0 : const MetaBmpExScalePartAction* pA = (const MetaBmpExScalePartAction*) pAction;
1788 : 0 : Impl_writeImage( pA->GetBitmapEx(),
1789 : 0 : pA->GetDestPoint(), pA->GetDestSize(),
1790 : 0 : pA->GetSrcPoint(), pA->GetSrcSize(), clipRect, 1 == bMap );
1791 : : }
1792 : 0 : break;
1793 : :
1794 : : case( META_TEXT_ACTION ):
1795 : : {
1796 : 0 : const MetaTextAction* pA = (const MetaTextAction*) pAction;
1797 : 0 : Impl_writeText( pA->GetPoint(), String( pA->GetText(), pA->GetIndex(), pA->GetLen() ), NULL, 0);
1798 : : }
1799 : 0 : break;
1800 : :
1801 : : case( META_TEXTRECT_ACTION ):
1802 : : {
1803 : 0 : const MetaTextRectAction* pA = (const MetaTextRectAction*) pAction;
1804 : 0 : Impl_writeText( pA->GetRect().TopLeft(), pA->GetText(), NULL, 0 );
1805 : : }
1806 : 0 : break;
1807 : :
1808 : : case( META_TEXTARRAY_ACTION ):
1809 : : {
1810 : 0 : const MetaTextArrayAction* pA = (const MetaTextArrayAction*) pAction;
1811 : 0 : Impl_writeText( pA->GetPoint(), String( pA->GetText(), pA->GetIndex(), pA->GetLen() ), pA->GetDXArray(), 0 );
1812 : : }
1813 : 0 : break;
1814 : :
1815 : : case( META_STRETCHTEXT_ACTION ):
1816 : : {
1817 : 0 : const MetaStretchTextAction* pA = (const MetaStretchTextAction*) pAction;
1818 : 0 : Impl_writeText( pA->GetPoint(), String( pA->GetText(), pA->GetIndex(), pA->GetLen() ), NULL, pA->GetWidth() );
1819 : : }
1820 : 0 : break;
1821 : :
1822 : : case( META_ISECTRECTCLIPREGION_ACTION ):
1823 : : {
1824 : 0 : const MetaISectRectClipRegionAction* pA = (const MetaISectRectClipRegionAction*) pAction;
1825 : 0 : clipRect = pA->GetRect();
1826 : : }
1827 : : case( META_CLIPREGION_ACTION ):
1828 : : case( META_ISECTREGIONCLIPREGION_ACTION ):
1829 : : case( META_MOVECLIPREGION_ACTION ):
1830 : : {
1831 : 0 : ( (MetaAction*) pAction )->Execute( mpVDev );
1832 : : }
1833 : 0 : break;
1834 : :
1835 : : case( META_RENDERGRAPHIC_ACTION ):
1836 : : {
1837 : 0 : const MetaRenderGraphicAction* pA = (const MetaRenderGraphicAction*) pAction;
1838 : 0 : const ::vcl::RenderGraphicRasterizer aRasterizer( pA->GetRenderGraphic() );
1839 : 0 : const Point aPointPixel;
1840 : 0 : const Size aSizePixel( mpVDev->LogicToPixel( pA->GetSize() ) );
1841 : 0 : const BitmapEx aBmpEx( aRasterizer.Rasterize( aSizePixel ) );
1842 : :
1843 : 0 : Impl_writeImage( aBmpEx, pA->GetPoint(), pA->GetSize(),
1844 : 0 : aPointPixel, aBmpEx.GetSizePixel(), clipRect, 1 == bMap );
1845 : : }
1846 : 0 : break;
1847 : :
1848 : : case( META_MAPMODE_ACTION ):
1849 : : {
1850 : 0 : bMap++;
1851 : : }
1852 : : case( META_REFPOINT_ACTION ):
1853 : : case( META_LINECOLOR_ACTION ):
1854 : : case( META_FILLCOLOR_ACTION ):
1855 : : case( META_TEXTLINECOLOR_ACTION ):
1856 : : case( META_TEXTFILLCOLOR_ACTION ):
1857 : : case( META_TEXTCOLOR_ACTION ):
1858 : : case( META_TEXTALIGN_ACTION ):
1859 : : case( META_FONT_ACTION ):
1860 : : case( META_PUSH_ACTION ):
1861 : : case( META_POP_ACTION ):
1862 : : case( META_LAYOUTMODE_ACTION ):
1863 : : {
1864 : 0 : ( (MetaAction*) pAction )->Execute( mpVDev );
1865 : : }
1866 : 0 : break;
1867 : :
1868 : : case( META_RASTEROP_ACTION ):
1869 : : case( META_MASK_ACTION ):
1870 : : case( META_MASKSCALE_ACTION ):
1871 : : case( META_MASKSCALEPART_ACTION ):
1872 : : case( META_WALLPAPER_ACTION ):
1873 : : case( META_TEXTLINE_ACTION ):
1874 : : {
1875 : : // !!! >>> we don't want to support these actions
1876 : : }
1877 : 0 : break;
1878 : :
1879 : : default:
1880 : 0 : break;
1881 : : }
1882 : : }
1883 : 0 : }
1884 : :
1885 : :
1886 : : /////////////////////////////////////////////////////////////////////////
1887 : :
1888 : :
1889 : 0 : void Writer::Impl_addStraightLine( BitStream& rBits, Point& rLastPoint,
1890 : : const double P2x, const double P2y )
1891 : : {
1892 : 0 : Point aPoint( FRound(P2x), FRound(P2y) );
1893 : :
1894 : 0 : Impl_addStraightEdgeRecord( rBits, _Int16(aPoint.X() - rLastPoint.X()),_Int16(aPoint.Y() - rLastPoint.Y()));
1895 : 0 : rLastPoint = aPoint;
1896 : :
1897 : 0 : }
1898 : :
1899 : : // -----------------------------------------------------------------------------
1900 : :
1901 : 0 : void Writer::Impl_addQuadBezier( BitStream& rBits, Point& rLastPoint,
1902 : : const double P2x, const double P2y,
1903 : : const double P3x, const double P3y )
1904 : : {
1905 : :
1906 : 0 : Point aControlPoint( FRound(P2x), FRound(P2y) );
1907 : 0 : Point aAnchorPoint( FRound(P3x), FRound(P3y) );
1908 : :
1909 : : Impl_addCurvedEdgeRecord( rBits,
1910 : 0 : _Int16(aControlPoint.X() - rLastPoint.X()),_Int16(aControlPoint.Y() - rLastPoint.Y()),
1911 : 0 : _Int16(aAnchorPoint.X() - aControlPoint.X()),_Int16(aAnchorPoint.Y() - aControlPoint.Y()) );
1912 : 0 : rLastPoint = aAnchorPoint;
1913 : 0 : }
1914 : :
1915 : : // -----------------------------------------------------------------------------
1916 : :
1917 : : /* Approximate given cubic bezier curve by quadratic bezier segments */
1918 : 0 : void Writer::Impl_quadBezierApprox( BitStream& rBits,
1919 : : Point& rLastPoint,
1920 : : const double d2,
1921 : : const double P1x, const double P1y,
1922 : : const double P2x, const double P2y,
1923 : : const double P3x, const double P3y,
1924 : : const double P4x, const double P4y )
1925 : : {
1926 : : // Check for degenerate case, where the given cubic bezier curve
1927 : : // is already quadratic: P4 == 3P3 - 3P2 + P1
1928 : 0 : if( P4x == 3.0*P3x - 3.0*P2x + P1x &&
1929 : : P4y == 3.0*P3y - 3.0*P2y + P1y )
1930 : : {
1931 : : Impl_addQuadBezier( rBits, rLastPoint,
1932 : : 3.0/2.0*P2x - 1.0/2.0*P1x, 3.0/2.0*P2y - 1.0/2.0*P1y,
1933 : 0 : P4x, P4y);
1934 : : }
1935 : : else
1936 : : {
1937 : : // Create quadratic segment for given cubic:
1938 : : // Start and end point must coincide, determine quadratic control
1939 : : // point in such a way that it lies on the intersection of the
1940 : : // tangents at start and end point, resp. Thus, both cubic and
1941 : : // quadratic curve segments will match in 0th and 1st derivative
1942 : : // at the start and end points
1943 : :
1944 : : // Intersection of P2P1 and P4P3
1945 : : // (P2y-P4y)(P3x-P4x)-(P2x-P4x)(P3y-P4y)
1946 : : // lambda = -------------------------------------
1947 : : // (P1x-P2x)(P3y-P4y)-(P1y-P2y)(P3x-P4x)
1948 : : //
1949 : : // Intersection point IP is now
1950 : : // IP = P2 + lambda(P1-P2)
1951 : : //
1952 : 0 : const double nominator( (P2y-P4y)*(P3x-P4x) - (P2x-P4x)*(P3y-P4y) );
1953 : 0 : const double denominator( (P1x-P2x)*(P3y-P4y) - (P1y-P2y)*(P3x-P4x) );
1954 : 0 : const double lambda( nominator / denominator );
1955 : :
1956 : 0 : const double IPx( P2x + lambda*( P1x - P2x) );
1957 : 0 : const double IPy( P2y + lambda*( P1y - P2y) );
1958 : :
1959 : : // Introduce some alias names: quadratic start point is P1, end
1960 : : // point is P4, control point is IP
1961 : 0 : const double QP1x( P1x );
1962 : 0 : const double QP1y( P1y );
1963 : 0 : const double QP2x( IPx );
1964 : 0 : const double QP2y( IPy );
1965 : 0 : const double QP3x( P4x );
1966 : 0 : const double QP3y( P4y );
1967 : :
1968 : : // Adapted bezier flatness test (lecture notes from R. Schaback,
1969 : : // Mathematics of Computer-Aided Design, Uni Goettingen, 2000)
1970 : : //
1971 : : // ||C(t) - Q(t)|| <= max ||c_j - q_j||
1972 : : // 0<=j<=n
1973 : : //
1974 : : // In this case, we don't need the distance from the cubic bezier
1975 : : // to a straight line, but to a quadratic bezier. The c_j's are
1976 : : // the cubic bezier's bernstein coefficients, the q_j's the
1977 : : // quadratic bezier's. We have the c_j's given, the q_j's can be
1978 : : // calculated from QPi like this (sorry, mixed index notation, we
1979 : : // use [1,n], formulas use [0,n-1]):
1980 : : //
1981 : : // q_0 = QP1 = P1
1982 : : // q_1 = 1/3 QP1 + 2/3 QP2
1983 : : // q_2 = 2/3 QP2 + 1/3 QP3
1984 : : // q_3 = QP3 = P4
1985 : : //
1986 : : // We can drop case 0 and 3, since there the curves coincide
1987 : : // (distance is zero)
1988 : :
1989 : : // calculate argument of max for j=1 and j=2
1990 : 0 : const double fJ1x( P2x - 1.0/3.0*QP1x - 2.0/3.0*QP2x );
1991 : 0 : const double fJ1y( P2y - 1.0/3.0*QP1y - 2.0/3.0*QP2y );
1992 : 0 : const double fJ2x( P3x - 2.0/3.0*QP2x - 1.0/3.0*QP3x );
1993 : 0 : const double fJ2y( P3y - 2.0/3.0*QP2y - 1.0/3.0*QP3y );
1994 : :
1995 : : // stop if distance from cubic curve is guaranteed to be bounded by d
1996 : : // Should denominator be 0: then P1P2 and P3P4 are parallel (P1P2^T R[90,P3P4] = 0.0),
1997 : : // meaning that either we have a straight line or an inflexion point (see else block below)
1998 : 0 : if( 0.0 != denominator &&
1999 : : ::std::max( fJ1x*fJ1x + fJ1y*fJ1y,
2000 : 0 : fJ2x*fJ2x + fJ2y*fJ2y) < d2 )
2001 : : {
2002 : : // requested resolution reached.
2003 : : // Add end points to output file.
2004 : : // order is preserved, since this is so to say depth first traversal.
2005 : : Impl_addQuadBezier( rBits, rLastPoint,
2006 : : QP2x, QP2y,
2007 : 0 : QP3x, QP3y);
2008 : : }
2009 : : else
2010 : : {
2011 : : // Maybe subdivide further
2012 : :
2013 : : // This is for robustness reasons, since the line intersection
2014 : : // method below gets instable if the curve gets closer to a
2015 : : // straight line. If the given cubic bezier does not deviate by
2016 : : // more than d/4 from a straight line, either:
2017 : : // - take the line (that's what we do here)
2018 : : // - express the line by a quadratic bezier
2019 : :
2020 : : // Perform bezier flatness test (lecture notes from R. Schaback,
2021 : : // Mathematics of Computer-Aided Design, Uni Goettingen, 2000)
2022 : : //
2023 : : // ||P(t) - L(t)|| <= max ||b_j - b_0 - j/n(b_n - b_0)||
2024 : : // 0<=j<=n
2025 : : //
2026 : : // What is calculated here is an upper bound to the distance from
2027 : : // a line through b_0 and b_3 (P1 and P4 in our notation) and the
2028 : : // curve. We can drop 0 and n from the running indices, since the
2029 : : // argument of max becomes zero for those cases.
2030 : 0 : const double fJ1x2( P2x - P1x - 1.0/3.0*(P4x - P1x) );
2031 : 0 : const double fJ1y2( P2y - P1y - 1.0/3.0*(P4y - P1y) );
2032 : 0 : const double fJ2x2( P3x - P1x - 2.0/3.0*(P4x - P1x) );
2033 : 0 : const double fJ2y2( P3y - P1y - 2.0/3.0*(P4y - P1y) );
2034 : :
2035 : : // stop if distance from line is guaranteed to be bounded by d/4
2036 : 0 : if( ::std::max( fJ1x2*fJ1x2 + fJ1y2*fJ1y2,
2037 : 0 : fJ2x2*fJ2x2 + fJ2y2*fJ2y2) < d2/16.0 )
2038 : : {
2039 : : // do not subdivide further, add straight line instead
2040 : 0 : Impl_addStraightLine( rBits, rLastPoint, P4x, P4y);
2041 : : }
2042 : : else
2043 : : {
2044 : : // deCasteljau bezier arc, split at t=0.5
2045 : : // Foley/vanDam, p. 508
2046 : 0 : const double L1x( P1x ), L1y( P1y );
2047 : 0 : const double L2x( (P1x + P2x)*0.5 ), L2y( (P1y + P2y)*0.5 );
2048 : 0 : const double Hx ( (P2x + P3x)*0.5 ), Hy ( (P2y + P3y)*0.5 );
2049 : 0 : const double L3x( (L2x + Hx)*0.5 ), L3y( (L2y + Hy)*0.5 );
2050 : 0 : const double R4x( P4x ), R4y( P4y );
2051 : 0 : const double R3x( (P3x + P4x)*0.5 ), R3y( (P3y + P4y)*0.5 );
2052 : 0 : const double R2x( (Hx + R3x)*0.5 ), R2y( (Hy + R3y)*0.5 );
2053 : 0 : const double R1x( (L3x + R2x)*0.5 ), R1y( (L3y + R2y)*0.5 );
2054 : 0 : const double L4x( R1x ), L4y( R1y );
2055 : :
2056 : : // subdivide further
2057 : 0 : Impl_quadBezierApprox(rBits, rLastPoint, d2, L1x, L1y, L2x, L2y, L3x, L3y, L4x, L4y);
2058 : 0 : Impl_quadBezierApprox(rBits, rLastPoint, d2, R1x, R1y, R2x, R2y, R3x, R3y, R4x, R4y);
2059 : : }
2060 : : }
2061 : : }
2062 : 0 : }
2063 : :
2064 : 0 : Reference < XBreakIterator > Writer::Impl_GetBreakIterator()
2065 : : {
2066 : 0 : if ( !mxBreakIterator.is() )
2067 : : {
2068 : 0 : Reference< XMultiServiceFactory > xMSF( ::comphelper::getProcessServiceFactory() );
2069 : 0 : mxBreakIterator.set( xMSF->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.i18n.BreakIterator" )) ), UNO_QUERY );
2070 : : }
2071 : 0 : return mxBreakIterator;
2072 : 0 : }
2073 : :
2074 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|