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 "pdfiprocessor.hxx"
31 : : #include "xmlemitter.hxx"
32 : : #include "pdfihelper.hxx"
33 : : #include "imagecontainer.hxx"
34 : : #include "style.hxx"
35 : : #include "drawtreevisiting.hxx"
36 : : #include "genericelements.hxx"
37 : :
38 : : #include "basegfx/polygon/b2dpolypolygontools.hxx"
39 : : #include "basegfx/range/b2drange.hxx"
40 : :
41 : : #include "com/sun/star/i18n/XBreakIterator.hpp"
42 : : #include "com/sun/star/lang/XMultiServiceFactory.hpp"
43 : : #include "comphelper/processfactory.hxx"
44 : : #include "com/sun/star/i18n/ScriptType.hpp"
45 : : #include "com/sun/star/i18n/DirectionProperty.hpp"
46 : :
47 : : #include <string.h>
48 : :
49 : : using namespace ::com::sun::star;
50 : : using namespace ::com::sun::star;
51 : : using namespace ::com::sun::star::lang;
52 : : using namespace ::com::sun::star::i18n;
53 : : using namespace ::com::sun::star::uno;
54 : :
55 : : namespace pdfi
56 : : {
57 : :
58 : 4509 : const ::com::sun::star::uno::Reference< ::com::sun::star::i18n::XBreakIterator >& DrawXmlOptimizer::GetBreakIterator()
59 : : {
60 [ + + ]: 4509 : if ( !mxBreakIter.is() )
61 : : {
62 [ + - ]: 3 : Reference< XComponentContext > xContext( this->m_rProcessor.m_xContext, uno::UNO_SET_THROW );
63 [ + - ][ + - ]: 3 : Reference< XMultiComponentFactory > xMSF( xContext->getServiceManager(), uno::UNO_SET_THROW );
[ + - ]
64 [ + - ][ + - ]: 3 : Reference < XInterface > xInterface = xMSF->createInstanceWithContext(::rtl::OUString("com.sun.star.i18n.BreakIterator"), xContext);
65 : :
66 [ + - ][ + - ]: 3 : mxBreakIter = uno::Reference< i18n::XBreakIterator >( xInterface, uno::UNO_QUERY );
67 : : }
68 : 4509 : return mxBreakIter;
69 : : }
70 : :
71 : 33 : const ::com::sun::star::uno::Reference< ::com::sun::star::i18n::XCharacterClassification >& DrawXmlEmitter::GetCharacterClassification()
72 : : {
73 [ + + ]: 33 : if ( !mxCharClass.is() )
74 : : {
75 [ + - ]: 3 : Reference< XComponentContext > xContext( m_rEmitContext.m_xContext, uno::UNO_SET_THROW );
76 [ + - ][ + - ]: 3 : Reference< XMultiComponentFactory > xMSF( xContext->getServiceManager(), uno::UNO_SET_THROW );
[ + - ]
77 [ + - ][ + - ]: 3 : Reference < XInterface > xInterface = xMSF->createInstanceWithContext(::rtl::OUString("com.sun.star.i18n.CharacterClassification"), xContext);
78 [ + - ][ + - ]: 3 : mxCharClass = uno::Reference< i18n::XCharacterClassification >( xInterface, uno::UNO_QUERY );
79 : : }
80 : 33 : return mxCharClass;
81 : : }
82 : :
83 : 0 : void DrawXmlEmitter::visit( HyperlinkElement& elem, const std::list< Element* >::const_iterator& )
84 : : {
85 [ # # ]: 0 : if( elem.Children.empty() )
86 : 0 : return;
87 : :
88 [ # # ][ # # ]: 0 : const char* pType = dynamic_cast<DrawElement*>(elem.Children.front()) ? "draw:a" : "text:a";
[ # # ]
89 : :
90 [ # # ]: 0 : PropertyMap aProps;
91 [ # # ][ # # ]: 0 : aProps[ USTR( "xlink:type" ) ] = USTR( "simple" );
[ # # ]
92 [ # # ][ # # ]: 0 : aProps[ USTR( "xlink:href" ) ] = elem.URI;
93 [ # # ][ # # ]: 0 : aProps[ USTR( "office:target-frame-name" ) ] = USTR( "_blank" );
[ # # ]
94 [ # # ][ # # ]: 0 : aProps[ USTR( "xlink:show" ) ] = USTR( "new" );
[ # # ]
95 : :
96 [ # # ]: 0 : m_rEmitContext.rEmitter.beginTag( pType, aProps );
97 : 0 : std::list< Element* >::iterator this_it = elem.Children.begin();
98 [ # # ][ # # ]: 0 : while( this_it !=elem.Children.end() && *this_it != &elem )
[ # # ][ # # ]
99 : : {
100 [ # # ]: 0 : (*this_it)->visitedBy( *this, this_it );
101 : 0 : ++this_it;
102 : : }
103 [ # # ][ # # ]: 0 : m_rEmitContext.rEmitter.endTag( pType );
104 : : }
105 : :
106 : 33 : void DrawXmlEmitter::visit( TextElement& elem, const std::list< Element* >::const_iterator& )
107 : : {
108 [ + - ]: 33 : if( ! elem.Text.getLength() )
109 : 33 : return;
110 : :
111 : 33 : rtl::OUString strSpace(32);
112 : 33 : rtl::OUString strNbSpace(160);
113 : 33 : rtl::OUString tabSpace(0x09);
114 [ + - ]: 33 : PropertyMap aProps;
115 [ + - ]: 33 : if( elem.StyleId != -1 )
116 : : {
117 [ + - ]: 66 : aProps[ rtl::OUString( "text:style-name" ) ] =
118 [ + - ]: 99 : m_rEmitContext.rStyles.getStyleName( elem.StyleId );
119 : : }
120 : :
121 : 33 : rtl::OUString str(elem.Text.getStr());
122 : :
123 : : // Check for RTL
124 : 33 : bool isRTL = false;
125 [ + - ]: 33 : Reference< i18n::XCharacterClassification > xCC( GetCharacterClassification() );
126 [ + - ]: 33 : if( xCC.is() )
127 : : {
128 [ + + ]: 312 : for(int i=1; i< elem.Text.getLength(); i++)
129 : : {
130 [ + - ][ + - ]: 279 : sal_Int16 nType = xCC->getCharacterDirection( str, i );
131 [ + - ][ + - ]: 279 : if ( nType == ::com::sun::star::i18n::DirectionProperty_RIGHT_TO_LEFT ||
[ + - ][ - + ]
132 : : nType == ::com::sun::star::i18n::DirectionProperty_RIGHT_TO_LEFT_ARABIC ||
133 : : nType == ::com::sun::star::i18n::DirectionProperty_RIGHT_TO_LEFT_EMBEDDING ||
134 : : nType == ::com::sun::star::i18n::DirectionProperty_RIGHT_TO_LEFT_OVERRIDE
135 : : )
136 : 0 : isRTL = true;
137 : : }
138 : : }
139 : :
140 [ - + ]: 33 : if (isRTL) // If so, reverse string
141 [ # # ]: 0 : str = m_rProcessor.mirrorString( str );
142 : :
143 [ + - ]: 33 : m_rEmitContext.rEmitter.beginTag( "text:span", aProps );
144 : :
145 [ + + ]: 345 : for(int i=0; i< elem.Text.getLength(); i++)
146 : : {
147 : 312 : rtl::OUString strToken= str.copy(i,1) ;
148 [ - + ][ + + ]: 312 : if( strSpace.equals(strToken) || strNbSpace.equals(strToken))
[ + + ]
149 : : {
150 [ + - ][ + - ]: 42 : aProps[ USTR( "text:c" ) ] = USTR( "1" );
[ + - ]
151 [ + - ]: 42 : m_rEmitContext.rEmitter.beginTag( "text:s", aProps );
152 [ + - ]: 42 : m_rEmitContext.rEmitter.endTag( "text:s");
153 : : }
154 : : else
155 : : {
156 [ - + ]: 270 : if( tabSpace.equals(strToken) )
157 : : {
158 [ # # ]: 0 : m_rEmitContext.rEmitter.beginTag( "text:tab", aProps );
159 [ # # ]: 0 : m_rEmitContext.rEmitter.endTag( "text:tab");
160 : : }
161 : : else
162 : : {
163 [ + - ]: 270 : m_rEmitContext.rEmitter.write( strToken );
164 : : }
165 : : }
166 : 312 : }
167 : :
168 : 33 : std::list< Element* >::iterator this_it = elem.Children.begin();
169 [ - + ][ # # ]: 33 : while( this_it !=elem.Children.end() && *this_it != &elem )
[ + - ][ - + ]
170 : : {
171 [ # # ]: 0 : (*this_it)->visitedBy( *this, this_it );
172 : 0 : ++this_it;
173 : : }
174 : :
175 [ + - ][ + - ]: 33 : m_rEmitContext.rEmitter.endTag( "text:span" );
176 : : }
177 : :
178 : 33 : void DrawXmlEmitter::visit( ParagraphElement& elem, const std::list< Element* >::const_iterator& )
179 : : {
180 [ + - ]: 33 : PropertyMap aProps;
181 [ + - ]: 33 : if( elem.StyleId != -1 )
182 : : {
183 [ + - ][ + - ]: 33 : aProps[ USTR( "text:style-name" ) ] = m_rEmitContext.rStyles.getStyleName( elem.StyleId );
[ + - ]
184 : : }
185 : 33 : const char* pTagType = "text:p";
186 [ - + ]: 33 : if( elem.Type == elem.Headline )
187 : 0 : pTagType = "text:h";
188 [ + - ]: 33 : m_rEmitContext.rEmitter.beginTag( pTagType, aProps );
189 : :
190 : 33 : std::list< Element* >::iterator this_it = elem.Children.begin();
191 [ + + ][ + - ]: 66 : while( this_it !=elem.Children.end() && *this_it != &elem )
[ + - ][ + + ]
192 : : {
193 [ + - ]: 33 : (*this_it)->visitedBy( *this, this_it );
194 : 33 : ++this_it;
195 : : }
196 : :
197 [ + - ][ + - ]: 33 : m_rEmitContext.rEmitter.endTag( pTagType );
198 : 33 : }
199 : :
200 : 42 : void DrawXmlEmitter::fillFrameProps( DrawElement& rElem,
201 : : PropertyMap& rProps,
202 : : const EmitContext& rEmitContext,
203 : : bool bWasTransformed
204 : : )
205 : : {
206 : 42 : double rel_x = rElem.x, rel_y = rElem.y;
207 : :
208 [ + - ][ + - ]: 42 : rProps[ USTR( "draw:z-index" ) ] = rtl::OUString::valueOf( rElem.ZOrder );
209 [ + - ][ + - ]: 42 : rProps[ USTR( "draw:style-name" )] = rEmitContext.rStyles.getStyleName( rElem.StyleId );
210 [ + - ][ + - ]: 42 : rProps[ USTR( "svg:width" ) ] = convertPixelToUnitString( rElem.w );
211 [ + - ][ + - ]: 42 : rProps[ USTR( "svg:height" ) ] = convertPixelToUnitString( rElem.h );
212 : :
213 : : const GraphicsContext& rGC =
214 : 42 : rEmitContext.rProcessor.getGraphicsContext( rElem.GCId );
215 [ + + ][ + + ]: 42 : if( rGC.Transformation.isIdentity() || bWasTransformed )
[ + - ]
216 : : {
217 [ + - ][ + - ]: 9 : rProps[ USTR( "svg:x" ) ] = convertPixelToUnitString( rel_x );
218 [ + - ][ + - ]: 9 : rProps[ USTR( "svg:y" ) ] = convertPixelToUnitString( rel_y );
219 : : }
220 : : else
221 : : {
222 : 33 : basegfx::B2DTuple aScale, aTranslation;
223 : : double fRotate, fShearX;
224 : :
225 [ + - ]: 33 : rGC.Transformation.decompose( aScale, aTranslation, fRotate, fShearX );
226 : :
227 : 33 : rtl::OUStringBuffer aBuf( 256 );
228 : :
229 : : // TODO(F2): general transformation case missing; if implemented, note
230 : : // that ODF rotation is oriented the other way
231 : :
232 : : // vertical mirroring is done by horizontally mirroring and rotaing 180 degree
233 : : // quaint !
234 [ - + ]: 33 : if( rElem.MirrorVertical )
235 : 0 : fRotate += M_PI;
236 : :
237 : : // build transformation string
238 [ - + ]: 33 : if( fShearX != 0.0 )
239 : : {
240 [ # # ]: 0 : aBuf.appendAscii( "skewX( " );
241 [ # # ]: 0 : aBuf.append( fShearX );
242 [ # # ]: 0 : aBuf.appendAscii( " )" );
243 : : }
244 [ - + ]: 33 : if( fRotate != 0.0 )
245 : : {
246 [ # # ]: 0 : if( aBuf.getLength() > 0 )
247 [ # # ]: 0 : aBuf.append( sal_Unicode(' ') );
248 [ # # ]: 0 : aBuf.appendAscii( "rotate( " );
249 [ # # ]: 0 : aBuf.append( -fRotate );
250 [ # # ]: 0 : aBuf.appendAscii( " )" );
251 : :
252 : : }
253 [ - + ]: 33 : if( aBuf.getLength() > 0 )
254 [ # # ]: 0 : aBuf.append( sal_Unicode(' ') );
255 [ + - ]: 33 : aBuf.appendAscii( "translate( " );
256 [ + - ][ + - ]: 33 : aBuf.append( convertPixelToUnitString( rel_x ) );
257 [ + - ]: 33 : aBuf.append( sal_Unicode(' ') );
258 [ + - ][ + - ]: 33 : aBuf.append( convertPixelToUnitString( rel_y ) );
259 [ + - ]: 33 : aBuf.appendAscii( " )" );
260 : :
261 [ + - ][ + - ]: 33 : rProps[ USTR( "draw:transform" ) ] = aBuf.makeStringAndClear();
[ + - ]
262 : : }
263 : 42 : }
264 : :
265 : 33 : void DrawXmlEmitter::visit( FrameElement& elem, const std::list< Element* >::const_iterator& )
266 : : {
267 [ + - ]: 33 : if( elem.Children.empty() )
268 : 33 : return;
269 : :
270 [ + - ][ + - ]: 33 : bool bTextBox = (dynamic_cast<ParagraphElement*>(elem.Children.front()) != NULL);
[ + - ]
271 [ + - ]: 33 : PropertyMap aFrameProps;
272 [ + - ]: 33 : fillFrameProps( elem, aFrameProps, m_rEmitContext );
273 [ + - ]: 33 : m_rEmitContext.rEmitter.beginTag( "draw:frame", aFrameProps );
274 [ + - ]: 33 : if( bTextBox )
275 [ + - ][ + - ]: 33 : m_rEmitContext.rEmitter.beginTag( "draw:text-box", PropertyMap() );
[ + - ]
276 : :
277 : 33 : std::list< Element* >::iterator this_it = elem.Children.begin();
278 [ + + ][ + - ]: 66 : while( this_it !=elem.Children.end() && *this_it != &elem )
[ + - ][ + + ]
279 : : {
280 [ + - ]: 33 : (*this_it)->visitedBy( *this, this_it );
281 : 33 : ++this_it;
282 : : }
283 : :
284 [ + - ]: 33 : if( bTextBox )
285 [ + - ]: 33 : m_rEmitContext.rEmitter.endTag( "draw:text-box" );
286 [ + - ][ + - ]: 33 : m_rEmitContext.rEmitter.endTag( "draw:frame" );
287 : : }
288 : :
289 : 9 : void DrawXmlEmitter::visit( PolyPolyElement& elem, const std::list< Element* >::const_iterator& )
290 : : {
291 [ + - ]: 9 : elem.updateGeometry();
292 : : /* note:
293 : : * aw recommends using 100dth of mm in all respects since the xml import
294 : : * (a) is buggy (see issue 37213)
295 : : * (b) is optimized for 100dth of mm and does not scale itself then,
296 : : * this does not gain us speed but makes for smaller rounding errors since
297 : : * the xml importer coordinates are integer based
298 : : */
299 [ + - ][ + + ]: 18 : for (sal_uInt32 i = 0; i< elem.PolyPoly.count(); i++)
300 : : {
301 [ + - ]: 9 : basegfx::B2DPolygon b2dPolygon;
302 [ + - ][ + - ]: 9 : b2dPolygon = elem.PolyPoly.getB2DPolygon( i );
[ + - ]
303 : :
304 [ + - ][ + + ]: 36 : for ( sal_uInt32 j = 0; j< b2dPolygon.count(); j++ )
305 : : {
306 : 27 : basegfx::B2DPoint point;
307 : 27 : basegfx::B2DPoint nextPoint;
308 [ + - ]: 27 : point = b2dPolygon.getB2DPoint( j );
309 : :
310 : 27 : basegfx::B2DPoint prevPoint;
311 [ + - ]: 27 : prevPoint = b2dPolygon.getPrevControlPoint( j ) ;
312 : :
313 : 27 : point.setX( convPx2mmPrec2( point.getX() )*100.0 );
314 : 27 : point.setY( convPx2mmPrec2( point.getY() )*100.0 );
315 : :
316 [ + + ][ + - ]: 27 : if ( b2dPolygon.isPrevControlPointUsed( j ) )
317 : : {
318 : 12 : prevPoint.setX( convPx2mmPrec2( prevPoint.getX() )*100.0 );
319 : 12 : prevPoint.setY( convPx2mmPrec2( prevPoint.getY() )*100.0 );
320 : : }
321 : :
322 [ + - ][ + + ]: 27 : if ( b2dPolygon.isNextControlPointUsed( j ) )
323 : : {
324 [ + - ]: 12 : nextPoint = b2dPolygon.getNextControlPoint( j ) ;
325 : 12 : nextPoint.setX( convPx2mmPrec2( nextPoint.getX() )*100.0 );
326 : 12 : nextPoint.setY( convPx2mmPrec2( nextPoint.getY() )*100.0 );
327 : : }
328 : :
329 [ + - ]: 27 : b2dPolygon.setB2DPoint( j, point );
330 : :
331 [ + - ][ + + ]: 27 : if ( b2dPolygon.isPrevControlPointUsed( j ) )
332 [ + - ]: 12 : b2dPolygon.setPrevControlPoint( j , prevPoint ) ;
333 : :
334 [ + - ][ + + ]: 27 : if ( b2dPolygon.isNextControlPointUsed( j ) )
335 [ + - ]: 12 : b2dPolygon.setNextControlPoint( j , nextPoint ) ;
336 : 27 : }
337 : :
338 [ + - ]: 9 : elem.PolyPoly.setB2DPolygon( i, b2dPolygon );
339 [ + - ]: 9 : }
340 : :
341 [ + - ]: 9 : PropertyMap aProps;
342 : : // PDFIProcessor transforms geometrical objects, not images and text
343 : : // so we need to tell fillFrameProps here that the transformation for
344 : : // a PolyPolyElement was already applied (aside form translation)
345 [ + - ]: 9 : fillFrameProps( elem, aProps, m_rEmitContext, true );
346 : 9 : rtl::OUStringBuffer aBuf( 64 );
347 [ + - ]: 9 : aBuf.appendAscii( "0 0 " );
348 [ + - ]: 9 : aBuf.append( convPx2mmPrec2(elem.w)*100.0 );
349 [ + - ]: 9 : aBuf.append( sal_Unicode(' ') );
350 [ + - ]: 9 : aBuf.append( convPx2mmPrec2(elem.h)*100.0 );
351 [ + - ][ + - ]: 9 : aProps[ USTR( "svg:viewBox" ) ] = aBuf.makeStringAndClear();
[ + - ]
352 [ + - ][ + - ]: 9 : aProps[ USTR( "svg:d" ) ] = basegfx::tools::exportToSvgD( elem.PolyPoly );
[ + - ]
353 : :
354 [ + - ]: 9 : m_rEmitContext.rEmitter.beginTag( "draw:path", aProps );
355 [ + - ][ + - ]: 9 : m_rEmitContext.rEmitter.endTag( "draw:path" );
356 : 9 : }
357 : :
358 : 0 : void DrawXmlEmitter::visit( ImageElement& elem, const std::list< Element* >::const_iterator& )
359 : : {
360 [ # # ]: 0 : PropertyMap aImageProps;
361 [ # # ]: 0 : m_rEmitContext.rEmitter.beginTag( "draw:image", aImageProps );
362 [ # # ][ # # ]: 0 : m_rEmitContext.rEmitter.beginTag( "office:binary-data", PropertyMap() );
[ # # ]
363 [ # # ]: 0 : m_rEmitContext.rImages.writeBase64EncodedStream( elem.Image, m_rEmitContext);
364 [ # # ]: 0 : m_rEmitContext.rEmitter.endTag( "office:binary-data" );
365 [ # # ][ # # ]: 0 : m_rEmitContext.rEmitter.endTag( "draw:image" );
366 : 0 : }
367 : :
368 : 3 : void DrawXmlEmitter::visit( PageElement& elem, const std::list< Element* >::const_iterator& )
369 : : {
370 [ + - ]: 3 : PropertyMap aPageProps;
371 [ + - ][ + - ]: 3 : aPageProps[ USTR( "draw:master-page-name" ) ] = m_rEmitContext.rStyles.getStyleName( elem.StyleId );
[ + - ]
372 : :
373 [ + - ]: 3 : m_rEmitContext.rEmitter.beginTag("draw:page", aPageProps);
374 : :
375 [ - + ]: 3 : if( m_rEmitContext.xStatusIndicator.is() )
376 [ # # ][ # # ]: 0 : m_rEmitContext.xStatusIndicator->setValue( elem.PageNumber );
377 : :
378 : 3 : std::list< Element* >::iterator this_it = elem.Children.begin();
379 [ + + ][ + - ]: 45 : while( this_it !=elem.Children.end() && *this_it != &elem )
[ + - ][ + + ]
380 : : {
381 [ + - ]: 42 : (*this_it)->visitedBy( *this, this_it );
382 : 42 : ++this_it;
383 : : }
384 : :
385 [ + - ][ + - ]: 3 : m_rEmitContext.rEmitter.endTag("draw:page");
386 : 3 : }
387 : :
388 : 3 : void DrawXmlEmitter::visit( DocumentElement& elem, const std::list< Element* >::const_iterator&)
389 : : {
390 [ + - ][ + - ]: 3 : m_rEmitContext.rEmitter.beginTag( "office:body", PropertyMap() );
[ + - ]
391 : : m_rEmitContext.rEmitter.beginTag( m_bWriteDrawDocument ? "office:drawing" : "office:presentation",
392 [ + - ][ + - ]: 3 : PropertyMap() );
[ + - ][ + - ]
393 : :
394 : 3 : std::list< Element* >::iterator this_it = elem.Children.begin();
395 [ + + ][ + - ]: 6 : while( this_it !=elem.Children.end() && *this_it != &elem )
[ + - ][ + + ]
396 : : {
397 [ + - ]: 3 : (*this_it)->visitedBy( *this, this_it );
398 : 3 : ++this_it;
399 : : }
400 : :
401 [ + - ][ + - ]: 3 : m_rEmitContext.rEmitter.endTag( m_bWriteDrawDocument ? "office:drawing" : "office:presentation" );
402 [ + - ]: 3 : m_rEmitContext.rEmitter.endTag( "office:body" );
403 : 3 : }
404 : :
405 : : /////////////////////////////////////////////////////////////////
406 : :
407 : 0 : void DrawXmlOptimizer::visit( HyperlinkElement&, const std::list< Element* >::const_iterator& )
408 : : {
409 : 0 : }
410 : :
411 : 33 : void DrawXmlOptimizer::visit( TextElement&, const std::list< Element* >::const_iterator&)
412 : : {
413 : 33 : }
414 : :
415 : 33 : void DrawXmlOptimizer::visit( FrameElement& elem, const std::list< Element* >::const_iterator& )
416 : : {
417 : 33 : elem.applyToChildren(*this);
418 : 33 : }
419 : :
420 : 0 : void DrawXmlOptimizer::visit( ImageElement&, const std::list< Element* >::const_iterator& )
421 : : {
422 : 0 : }
423 : :
424 : 9 : void DrawXmlOptimizer::visit( PolyPolyElement& elem, const std::list< Element* >::const_iterator& )
425 : : {
426 : : /* note: optimize two consecutive PolyPolyElements that
427 : : * have the same path but one of which is a stroke while
428 : : * the other is a fill
429 : : */
430 [ + - ]: 9 : if( elem.Parent )
431 : : {
432 : : // find following PolyPolyElement in parent's children list
433 : 9 : std::list< Element* >::iterator this_it = elem.Parent->Children.begin();
434 [ + - ][ + + ]: 54 : while( this_it != elem.Parent->Children.end() && *this_it != &elem )
[ + - ][ + + ]
435 : 45 : ++this_it;
436 : :
437 [ + - ]: 9 : if( this_it != elem.Parent->Children.end() )
438 : : {
439 : 9 : std::list< Element* >::iterator next_it = this_it;
440 [ + - ]: 9 : if( ++next_it != elem.Parent->Children.end() )
441 : : {
442 [ - + ]: 9 : PolyPolyElement* pNext = dynamic_cast<PolyPolyElement*>(*next_it);
443 : :
444 : : // TODO(F2): this comparison fails for OOo-generated polygons with beziers.
445 [ + + ][ + - ]: 9 : if( pNext && pNext->PolyPoly == elem.PolyPoly )
[ - + ][ - + ]
446 : : {
447 : : const GraphicsContext& rNextGC =
448 [ # # ]: 0 : m_rProcessor.getGraphicsContext( pNext->GCId );
449 : : const GraphicsContext& rThisGC =
450 [ # # ]: 0 : m_rProcessor.getGraphicsContext( elem.GCId );
451 : :
452 [ # # ][ # # ]: 0 : if( rThisGC.BlendMode == rNextGC.BlendMode &&
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
453 : : rThisGC.Flatness == rNextGC.Flatness &&
454 [ # # ]: 0 : rThisGC.Transformation == rNextGC.Transformation &&
455 [ # # ]: 0 : rThisGC.Clip == rNextGC.Clip &&
456 : : rThisGC.FillColor.Red == rNextGC.FillColor.Red &&
457 : : rThisGC.FillColor.Green== rNextGC.FillColor.Green &&
458 : : rThisGC.FillColor.Blue == rNextGC.FillColor.Blue &&
459 : : rThisGC.FillColor.Alpha== rNextGC.FillColor.Alpha &&
460 : : pNext->Action == PATH_STROKE &&
461 : : (elem.Action == PATH_FILL || elem.Action == PATH_EOFILL) )
462 : : {
463 [ # # ]: 0 : GraphicsContext aGC = rThisGC;
464 : 0 : aGC.LineJoin = rNextGC.LineJoin;
465 : 0 : aGC.LineCap = rNextGC.LineCap;
466 : 0 : aGC.LineWidth = rNextGC.LineWidth;
467 : 0 : aGC.MiterLimit= rNextGC.MiterLimit;
468 [ # # ]: 0 : aGC.DashArray = rNextGC.DashArray;
469 : 0 : aGC.LineColor = rNextGC.LineColor;
470 [ # # ]: 0 : elem.GCId = m_rProcessor.getGCId( aGC );
471 : :
472 : 0 : elem.Action |= pNext->Action;
473 : :
474 [ # # ]: 0 : elem.Children.splice( elem.Children.end(), pNext->Children );
475 [ # # ]: 0 : elem.Parent->Children.erase( next_it );
476 [ # # ][ # # ]: 9 : delete pNext;
[ # # ]
477 : : }
478 : : }
479 : : }
480 : : }
481 : : }
482 : 9 : }
483 : :
484 : 33 : void DrawXmlOptimizer::visit( ParagraphElement& elem, const std::list< Element* >::const_iterator& )
485 : : {
486 : 33 : optimizeTextElements( elem );
487 : :
488 : 33 : elem.applyToChildren(*this);
489 : 33 : }
490 : :
491 : 3 : void DrawXmlOptimizer::visit( PageElement& elem, const std::list< Element* >::const_iterator& )
492 : : {
493 [ - + ]: 3 : if( m_rProcessor.getStatusIndicator().is() )
494 [ # # ][ # # ]: 0 : m_rProcessor.getStatusIndicator()->setValue( elem.PageNumber );
495 : :
496 : : // resolve hyperlinks
497 [ + - ]: 3 : elem.resolveHyperlinks();
498 : :
499 [ + - ]: 3 : elem.resolveFontStyles( m_rProcessor ); // underlines and such
500 : :
501 : : // FIXME: until hyperlinks and font effects are adjusted for
502 : : // geometrical search handle them before sorting
503 [ + - ]: 3 : m_rProcessor.sortElements( &elem );
504 : :
505 : : // find paragraphs in text
506 : 3 : ParagraphElement* pCurPara = NULL;
507 : 3 : std::list< Element* >::iterator page_element, next_page_element;
508 : 3 : next_page_element = elem.Children.begin();
509 : 3 : double fCurLineHeight = 0.0; // average height of text items in current para
510 : 3 : int nCurLineElements = 0; // number of line contributing elements in current para
511 : 3 : double line_left = elem.w, line_right = 0.0;
512 : 3 : double column_width = elem.w*0.75; // estimate text width
513 : : // TODO: guess columns
514 [ + + ]: 45 : while( next_page_element != elem.Children.end() )
515 : : {
516 : 42 : page_element = next_page_element++;
517 [ - + ]: 42 : ParagraphElement* pPagePara = dynamic_cast<ParagraphElement*>(*page_element);
518 [ - + ]: 42 : if( pPagePara )
519 : : {
520 : 0 : pCurPara = pPagePara;
521 : : // adjust line height and text items
522 : 0 : fCurLineHeight = 0.0;
523 : 0 : nCurLineElements = 0;
524 [ # # ]: 0 : for( std::list< Element* >::iterator it = pCurPara->Children.begin();
525 : 0 : it != pCurPara->Children.end(); ++it )
526 : : {
527 [ # # ]: 0 : TextElement* pTestText = dynamic_cast<TextElement*>(*it);
528 [ # # ]: 0 : if( pTestText )
529 : : {
530 : 0 : fCurLineHeight = (fCurLineHeight*double(nCurLineElements) + pTestText->h)/double(nCurLineElements+1);
531 : 0 : nCurLineElements++;
532 : : }
533 : : }
534 : 0 : continue;
535 : : }
536 : :
537 [ - + ]: 42 : HyperlinkElement* pLink = dynamic_cast<HyperlinkElement*>(*page_element);
538 [ - + ]: 42 : DrawElement* pDraw = dynamic_cast<DrawElement*>(*page_element);
539 [ - + ][ # # ]: 42 : if( ! pDraw && pLink && ! pLink->Children.empty() )
[ # # ][ - + ]
540 [ # # ][ # # ]: 0 : pDraw = dynamic_cast<DrawElement*>(pLink->Children.front() );
541 [ + - ]: 42 : if( pDraw )
542 : : {
543 : : // insert small drawing objects as character, else leave them page bound
544 : :
545 : 42 : bool bInsertToParagraph = false;
546 : : // first check if this is either inside the paragraph
547 [ - + ][ # # ]: 42 : if( pCurPara && pDraw->y < pCurPara->y + pCurPara->h )
548 : : {
549 [ # # ]: 0 : if( pDraw->h < fCurLineHeight * 1.5 )
550 : : {
551 : 0 : bInsertToParagraph = true;
552 : 0 : fCurLineHeight = (fCurLineHeight*double(nCurLineElements) + pDraw->h)/double(nCurLineElements+1);
553 : 0 : nCurLineElements++;
554 : : // mark draw element as character
555 : 0 : pDraw->isCharacter = true;
556 : : }
557 : : }
558 : : // or perhaps the draw element begins a new paragraph
559 [ + + ]: 42 : else if( next_page_element != elem.Children.end() )
560 : : {
561 [ - + ]: 39 : TextElement* pText = dynamic_cast<TextElement*>(*next_page_element);
562 [ + - ]: 39 : if( ! pText )
563 : : {
564 [ - + ]: 39 : ParagraphElement* pPara = dynamic_cast<ParagraphElement*>(*next_page_element);
565 [ - + ][ # # ]: 39 : if( pPara && ! pPara->Children.empty() )
[ - + ]
566 [ # # ][ # # ]: 0 : pText = dynamic_cast<TextElement*>(pPara->Children.front());
567 : : }
568 [ - + ][ # # ]: 39 : if( pText && // check there is a text
[ # # ][ # # ]
[ # # ][ # # ]
569 : : pDraw->h < pText->h*1.5 && // and it is approx the same height
570 : : // and either upper or lower edge of pDraw is inside text's vertical range
571 : : ( ( pDraw->y >= pText->y && pDraw->y <= pText->y+pText->h ) ||
572 : : ( pDraw->y+pDraw->h >= pText->y && pDraw->y+pDraw->h <= pText->y+pText->h )
573 : : )
574 : : )
575 : : {
576 : 0 : bInsertToParagraph = true;
577 : 0 : fCurLineHeight = pDraw->h;
578 : 0 : nCurLineElements = 1;
579 : 0 : line_left = pDraw->x;
580 : 0 : line_right = pDraw->x + pDraw->w;
581 : : // begin a new paragraph
582 : 0 : pCurPara = NULL;
583 : : // mark draw element as character
584 : 0 : pDraw->isCharacter = true;
585 : : }
586 : : }
587 : :
588 [ + - ]: 42 : if( ! bInsertToParagraph )
589 : : {
590 : 42 : pCurPara = NULL;
591 : 42 : continue;
592 : : }
593 : : }
594 : :
595 [ # # ]: 0 : TextElement* pText = dynamic_cast<TextElement*>(*page_element);
596 [ # # ][ # # ]: 0 : if( ! pText && pLink && ! pLink->Children.empty() )
[ # # ][ # # ]
597 [ # # ][ # # ]: 0 : pText = dynamic_cast<TextElement*>(pLink->Children.front());
598 [ # # ]: 0 : if( pText )
599 : : {
600 : : Element* pGeo = pLink ? static_cast<Element*>(pLink) :
601 [ # # ]: 0 : static_cast<Element*>(pText);
602 [ # # ]: 0 : if( pCurPara )
603 : : {
604 : : // there was already a text element, check for a new paragraph
605 [ # # ]: 0 : if( nCurLineElements > 0 )
606 : : {
607 : : // if the new text is significantly distant from the paragraph
608 : : // begin a new paragraph
609 [ # # ]: 0 : if( pGeo->y > pCurPara->y + pCurPara->h + fCurLineHeight*0.5 )
610 : 0 : pCurPara = NULL; // insert new paragraph
611 [ # # ]: 0 : else if( pGeo->y > (pCurPara->y+pCurPara->h - fCurLineHeight*0.05) )
612 : : {
613 : : // new paragraph if either the last line of the paragraph
614 : : // was significantly shorter than the paragraph as a whole
615 [ # # ]: 0 : if( (line_right - line_left) < pCurPara->w*0.75 )
616 : 0 : pCurPara = NULL;
617 : : // or the last line was significantly smaller than the column width
618 [ # # ]: 0 : else if( (line_right - line_left) < column_width*0.75 )
619 : 0 : pCurPara = NULL;
620 : : }
621 : : }
622 : :
623 : :
624 : : }
625 : :
626 : :
627 : : // update line height/width
628 [ # # ]: 0 : if( pCurPara )
629 : : {
630 : 0 : fCurLineHeight = (fCurLineHeight*double(nCurLineElements) + pGeo->h)/double(nCurLineElements+1);
631 : 0 : nCurLineElements++;
632 [ # # ]: 0 : if( pGeo->x < line_left )
633 : 0 : line_left = pGeo->x;
634 [ # # ]: 0 : if( pGeo->x+pGeo->w > line_right )
635 : 0 : line_right = pGeo->x+pGeo->w;
636 : : }
637 : : else
638 : : {
639 : 0 : fCurLineHeight = pGeo->h;
640 : 0 : nCurLineElements = 1;
641 : 0 : line_left = pGeo->x;
642 : 0 : line_right = pGeo->x + pGeo->w;
643 : : }
644 : : }
645 : :
646 : :
647 : : // move element to current paragraph
648 [ # # ]: 0 : if (! pCurPara ) // new paragraph, insert one
649 : : {
650 [ # # ][ # # ]: 0 : pCurPara = m_rProcessor.getElementFactory()->createParagraphElement( NULL );
[ # # ]
651 : : // set parent
652 : 0 : pCurPara->Parent = &elem;
653 : : //insert new paragraph before current element
654 [ # # ]: 0 : page_element = elem.Children.insert( page_element, pCurPara );
655 : : // forward iterator to current element again
656 : 0 : ++ page_element;
657 : : // update next_element which is now invalid
658 : 0 : next_page_element = page_element;
659 : 0 : ++ next_page_element;
660 : : }
661 : 0 : Element* pCurEle = *page_element;
662 [ # # ]: 0 : pCurEle->setParent( page_element, pCurPara );
663 : : OSL_ENSURE( !pText || pCurEle == pText || pCurEle == pLink, "paragraph child list in disorder" );
664 [ # # ][ # # ]: 0 : if( pText || pDraw )
665 [ # # ]: 0 : pCurPara->updateGeometryWith( pCurEle );
666 : : }
667 : :
668 : : // process children
669 [ + - ]: 3 : elem.applyToChildren(*this);
670 : 3 : }
671 : :
672 : 0 : bool isSpaces(TextElement* pTextElem)
673 : : {
674 [ # # ]: 0 : for (sal_Int32 i = 0; i != pTextElem->Text.getLength(); ++i) {
675 [ # # ]: 0 : if (pTextElem->Text[i] != ' ') {
676 : 0 : return false;
677 : : }
678 : : }
679 : 0 : return true;
680 : : }
681 : :
682 : 0 : bool notTransformed(GraphicsContext GC)
683 : : {
684 : : return (
685 : 0 : GC.Transformation.get(0,0) == 100.00 &&
686 : 0 : GC.Transformation.get(1,0) == 0.00 &&
687 : 0 : GC.Transformation.get(0,1) == 0.00 &&
688 : 0 : GC.Transformation.get(1,1) == -100.00
689 [ # # # # : 0 : );
# # # # ]
690 : : }
691 : :
692 : 33 : void DrawXmlOptimizer::optimizeTextElements(Element& rParent)
693 : : {
694 [ + - ]: 33 : if( rParent.Children.empty() ) // this should not happen
695 : : {
696 : : OSL_FAIL( "empty paragraph optimized" );
697 : 33 : return;
698 : : }
699 : :
700 : : // concatenate child elements with same font id
701 : 33 : std::list< Element* >::iterator next = rParent.Children.begin();
702 : 33 : std::list< Element* >::iterator it = next++;
703 : :
704 [ + + ]: 312 : while( next != rParent.Children.end() )
705 : : {
706 : 279 : bool bConcat = false;
707 [ - + ]: 279 : TextElement* pCur = dynamic_cast<TextElement*>(*it);
708 : :
709 [ + - ]: 279 : if( pCur )
710 : : {
711 [ - + ]: 279 : TextElement* pNext = dynamic_cast<TextElement*>(*next);
712 : 279 : bool isComplex = false;
713 : 279 : rtl::OUString str(pCur->Text.getStr());
714 [ + + ]: 2394 : for(int i=0; i< str.getLength(); i++)
715 : : {
716 [ + - ][ + - ]: 2115 : sal_Int16 nType = GetBreakIterator()->getScriptType( str, i );
[ + - ]
717 [ - + ]: 2115 : if (nType == ::com::sun::star::i18n::ScriptType::COMPLEX)
718 : 0 : isComplex = true;
719 : : }
720 : 279 : bool bPara = strspn("ParagraphElement", typeid(rParent).name());
721 [ - + ]: 279 : ParagraphElement* pPara = dynamic_cast<ParagraphElement*>(&rParent);
722 [ + - ][ - + ]: 279 : if (bPara && isComplex)
723 : 0 : pPara->bRtl = true;
724 [ + - ]: 279 : if( pNext )
725 : : {
726 [ + - ]: 279 : const GraphicsContext& rCurGC = m_rProcessor.getGraphicsContext( pCur->GCId );
727 [ + - ]: 279 : const GraphicsContext& rNextGC = m_rProcessor.getGraphicsContext( pNext->GCId );
728 : :
729 : : // line and space optimization; works only in strictly horizontal mode
730 : :
731 : : // concatenate consecutive text elements unless there is a
732 : : // font or text color or matrix change, leave a new span in that case
733 [ - + ][ # # ]: 837 : if( (pCur->FontId == pNext->FontId || isSpaces(pNext)) &&
[ + - ][ + - ]
[ + - ][ + - ]
[ - + ][ # # ]
[ + - ]
734 : : rCurGC.FillColor.Red == rNextGC.FillColor.Red &&
735 : : rCurGC.FillColor.Green == rNextGC.FillColor.Green &&
736 : : rCurGC.FillColor.Blue == rNextGC.FillColor.Blue &&
737 : : rCurGC.FillColor.Alpha == rNextGC.FillColor.Alpha &&
738 [ + - ][ # # ]: 558 : (rCurGC.Transformation == rNextGC.Transformation || notTransformed(rNextGC))
[ # # ][ - + ]
[ # # ][ # # ]
739 : : )
740 : : {
741 [ + - ]: 279 : pCur->updateGeometryWith( pNext );
742 : : // append text to current element
743 [ + - ]: 279 : pCur->Text.append( pNext->Text.getStr(), pNext->Text.getLength() );
744 : :
745 : 279 : str = pCur->Text.getStr();
746 [ + + ]: 2673 : for(int i=0; i< str.getLength(); i++)
747 : : {
748 [ + - ][ + - ]: 2394 : sal_Int16 nType = GetBreakIterator()->getScriptType( str, i );
[ + - ]
749 [ - + ]: 2394 : if (nType == ::com::sun::star::i18n::ScriptType::COMPLEX)
750 : 0 : isComplex = true;
751 : : }
752 [ + - ][ - + ]: 279 : if (bPara && isComplex)
753 : 0 : pPara->bRtl = true;
754 : : // append eventual children to current element
755 : : // and clear children (else the children just
756 : : // appended to pCur would be destroyed)
757 [ + - ]: 279 : pCur->Children.splice( pCur->Children.end(), pNext->Children );
758 : : // get rid of the now useless element
759 [ + - ]: 279 : rParent.Children.erase( next );
760 [ + - ][ + - ]: 279 : delete pNext;
761 : 279 : bConcat = true;
762 : : }
763 : 279 : }
764 : : }
765 [ # # ][ # # ]: 0 : else if( dynamic_cast<HyperlinkElement*>(*it) )
[ # # ]
766 [ # # ]: 0 : optimizeTextElements( **it );
767 [ + - ]: 279 : if ( bConcat )
768 : 279 : next = it;
769 : : else
770 : 0 : ++it;
771 : 279 : ++next;
772 : : }
773 : : }
774 : :
775 : 3 : void DrawXmlOptimizer::visit( DocumentElement& elem, const std::list< Element* >::const_iterator&)
776 : : {
777 : 3 : elem.applyToChildren(*this);
778 : 3 : }
779 : :
780 : : //////////////////////////////////////////////////////////////////////////////////
781 : :
782 : :
783 : 9 : void DrawXmlFinalizer::visit( PolyPolyElement& elem, const std::list< Element* >::const_iterator& )
784 : : {
785 : : // xxx TODO copied from DrawElement
786 [ + - ]: 9 : const GraphicsContext& rGC = m_rProcessor.getGraphicsContext(elem.GCId );
787 [ + - ]: 9 : PropertyMap aProps;
788 [ + - ][ + - ]: 9 : aProps[ USTR( "style:family" ) ] = USTR( "graphic" );
[ + - ]
789 [ + - ][ + - ]: 9 : aProps[ USTR( "style:parent-style-name") ] = USTR( "standard" );
[ + - ]
790 : : // generate standard graphic style if necessary
791 [ + - ]: 9 : m_rStyleContainer.getStandardStyleId( "graphic" );
792 : :
793 [ + - ]: 9 : PropertyMap aGCProps;
794 : :
795 : : // TODO(F3): proper dash emulation
796 [ + + ]: 9 : if( elem.Action & PATH_STROKE )
797 : : {
798 [ + + ][ + - ]: 6 : aGCProps[ USTR("draw:stroke") ] = rGC.DashArray.empty() ? USTR("solid") : USTR("dash");
[ + - ][ + - ]
[ + - ]
799 [ + - ][ + - ]: 6 : aGCProps[ USTR("svg:stroke-color") ] = getColorString( rGC.LineColor );
[ + - ]
800 [ + + ]: 6 : if( rGC.LineWidth != 0.0 )
801 : : {
802 : 3 : ::basegfx::B2DVector aVec(rGC.LineWidth,0);
803 [ + - ]: 3 : aVec *= rGC.Transformation;
804 : :
805 : 3 : aVec.setX ( convPx2mmPrec2( aVec.getX() )*100.0 );
806 : 3 : aVec.setY ( convPx2mmPrec2( aVec.getY() )*100.0 );
807 : :
808 [ + - ][ + - ]: 3 : aGCProps[ USTR("svg:stroke-width") ] = rtl::OUString::valueOf( aVec.getLength() );
[ + - ]
809 : : }
810 : : }
811 : : else
812 : : {
813 [ + - ][ + - ]: 3 : aGCProps[ USTR("draw:stroke") ] = USTR("none");
[ + - ]
814 : : }
815 : :
816 : : // TODO(F1): check whether stuff could be emulated by gradient/bitmap/hatch
817 [ + + ]: 9 : if( elem.Action & (PATH_FILL | PATH_EOFILL) )
818 : : {
819 [ + - ][ + - ]: 3 : aGCProps[ USTR("draw:fill") ] = USTR("solid");
[ + - ]
820 [ + - ][ + - ]: 3 : aGCProps[ USTR("draw:fill-color") ] = getColorString( rGC.FillColor );
[ + - ]
821 : : }
822 : : else
823 : : {
824 [ + - ][ + - ]: 6 : aGCProps[ USTR("draw:fill") ] = USTR("none");
[ + - ]
825 : : }
826 : :
827 [ + - ]: 9 : StyleContainer::Style aStyle( "style:style", aProps );
828 [ + - ]: 9 : StyleContainer::Style aSubStyle( "style:graphic-properties", aGCProps );
829 [ + - ]: 9 : aStyle.SubStyles.push_back( &aSubStyle );
830 : :
831 [ + - ][ + - ]: 9 : elem.StyleId = m_rStyleContainer.getStyleId( aStyle );
[ + - ][ + - ]
[ + - ]
832 : 9 : }
833 : :
834 : 0 : void DrawXmlFinalizer::visit( HyperlinkElement&, const std::list< Element* >::const_iterator& )
835 : : {
836 : 0 : }
837 : :
838 : 33 : void DrawXmlFinalizer::visit( TextElement& elem, const std::list< Element* >::const_iterator& )
839 : : {
840 [ + - ]: 33 : const FontAttributes& rFont = m_rProcessor.getFont( elem.FontId );
841 [ + - ]: 33 : PropertyMap aProps;
842 [ + - ][ + - ]: 33 : aProps[ USTR( "style:family" ) ] = USTR( "text" );
[ + - ]
843 : :
844 [ + - ]: 33 : PropertyMap aFontProps;
845 : :
846 : : // family name
847 [ + - ][ + - ]: 33 : aFontProps[ USTR( "fo:font-family" ) ] = rFont.familyName;
848 [ + - ][ + - ]: 33 : aFontProps[ USTR( "style:font-family-complex" ) ] = rFont.familyName;
849 : :
850 : : // bold
851 [ - + ]: 33 : if( rFont.isBold )
852 : : {
853 [ # # ][ # # ]: 0 : aFontProps[ USTR( "fo:font-weight" ) ] = USTR( "bold" );
[ # # ]
854 [ # # ][ # # ]: 0 : aFontProps[ USTR( "fo:font-weight-asian" ) ] = USTR( "bold" );
[ # # ]
855 [ # # ][ # # ]: 0 : aFontProps[ USTR( "style:font-weight-complex" ) ] = USTR( "bold" );
[ # # ]
856 : : }
857 : : // italic
858 [ - + ]: 33 : if( rFont.isItalic )
859 : : {
860 [ # # ][ # # ]: 0 : aFontProps[ USTR( "fo:font-style" ) ] = USTR( "italic" );
[ # # ]
861 [ # # ][ # # ]: 0 : aFontProps[ USTR( "fo:font-style-asian" ) ] = USTR( "italic" );
[ # # ]
862 [ # # ][ # # ]: 0 : aFontProps[ USTR( "style:font-style-complex" ) ] = USTR( "italic" );
[ # # ]
863 : : }
864 : : // underline
865 [ - + ]: 33 : if( rFont.isUnderline )
866 : : {
867 [ # # ][ # # ]: 0 : aFontProps[ USTR( "style:text-underline-style" ) ] = USTR( "solid" );
[ # # ]
868 [ # # ][ # # ]: 0 : aFontProps[ USTR( "style:text-underline-width" ) ] = USTR( "auto" );
[ # # ]
869 [ # # ][ # # ]: 0 : aFontProps[ USTR( "style:text-underline-color" ) ] = USTR( "font-color" );
[ # # ]
870 : : }
871 : : // outline
872 [ - + ]: 33 : if( rFont.isOutline )
873 : : {
874 [ # # ][ # # ]: 0 : aFontProps[ USTR( "style:text-outline" ) ] = USTR( "true" );
[ # # ]
875 : : }
876 : : // size
877 : 33 : rtl::OUStringBuffer aBuf( 32 );
878 [ + - ]: 33 : aBuf.append( rFont.size*72/PDFI_OUTDEV_RESOLUTION );
879 [ + - ]: 33 : aBuf.appendAscii( "pt" );
880 [ + - ]: 33 : rtl::OUString aFSize = aBuf.makeStringAndClear();
881 [ + - ][ + - ]: 33 : aFontProps[ USTR( "fo:font-size" ) ] = aFSize;
882 [ + - ][ + - ]: 33 : aFontProps[ USTR( "style:font-size-asian" ) ] = aFSize;
883 [ + - ][ + - ]: 33 : aFontProps[ USTR( "style:font-size-complex" ) ] = aFSize;
884 : : // color
885 [ + - ]: 33 : const GraphicsContext& rGC = m_rProcessor.getGraphicsContext( elem.GCId );
886 [ - + ][ + - ]: 33 : aFontProps[ USTR( "fo:color" ) ] = getColorString( rFont.isOutline ? rGC.LineColor : rGC.FillColor );
[ + - ][ + - ]
887 : :
888 [ + - ]: 33 : StyleContainer::Style aStyle( "style:style", aProps );
889 [ + - ]: 33 : StyleContainer::Style aSubStyle( "style:text-properties", aFontProps );
890 [ + - ]: 33 : aStyle.SubStyles.push_back( &aSubStyle );
891 [ + - ][ + - ]: 33 : elem.StyleId = m_rStyleContainer.getStyleId( aStyle );
[ + - ][ + - ]
[ + - ]
892 : 33 : }
893 : :
894 : 33 : void DrawXmlFinalizer::visit( ParagraphElement& elem, const std::list< Element* >::const_iterator& )
895 : : {
896 : :
897 [ + - ]: 33 : PropertyMap aProps;
898 [ + - ][ + - ]: 33 : aProps[ USTR( "style:family" ) ] = USTR( "paragraph" );
[ + - ]
899 : : // generate standard paragraph style if necessary
900 [ + - ]: 33 : m_rStyleContainer.getStandardStyleId( "paragraph" );
901 : :
902 [ + - ]: 33 : PropertyMap aParProps;
903 : :
904 [ + - ][ + - ]: 33 : aParProps[ USTR("fo:text-align")] = USTR("start");
[ + - ]
905 [ - + ]: 33 : if (elem.bRtl)
906 [ # # ][ # # ]: 0 : aParProps[ USTR("style:writing-mode")] = USTR("rl-tb");
[ # # ]
907 : : else
908 [ + - ][ + - ]: 33 : aParProps[ USTR("style:writing-mode")] = USTR("lr-tb");
[ + - ]
909 : :
910 [ + - ]: 33 : StyleContainer::Style aStyle( "style:style", aProps );
911 [ + - ]: 33 : StyleContainer::Style aSubStyle( "style:paragraph-properties", aParProps );
912 [ + - ]: 33 : aStyle.SubStyles.push_back( &aSubStyle );
913 : :
914 [ + - ]: 33 : elem.StyleId = m_rStyleContainer.getStyleId( aStyle );
915 : :
916 [ + - ][ + - ]: 33 : elem.applyToChildren(*this);
[ + - ][ + - ]
[ + - ]
917 : 33 : }
918 : :
919 : 33 : void DrawXmlFinalizer::visit( FrameElement& elem, const std::list< Element* >::const_iterator&)
920 : : {
921 [ + - ]: 33 : PropertyMap aProps;
922 [ + - ][ + - ]: 33 : aProps[ USTR( "style:family" ) ] = USTR( "graphic" );
[ + - ]
923 [ + - ][ + - ]: 33 : aProps[ USTR( "style:parent-style-name") ] = USTR( "standard" );
[ + - ]
924 : : // generate standard graphic style if necessary
925 [ + - ]: 33 : m_rStyleContainer.getStandardStyleId( "graphic" );
926 : :
927 [ + - ]: 33 : PropertyMap aGCProps;
928 : :
929 [ + - ][ + - ]: 33 : aGCProps[ USTR("draw:stroke") ] = USTR("none");
[ + - ]
930 [ + - ][ + - ]: 33 : aGCProps[ USTR("draw:fill") ] = USTR("none");
[ + - ]
931 [ + - ][ + - ]: 33 : aGCProps[ USTR("draw:auto-grow-height") ] = USTR("true");
[ + - ]
932 [ + - ][ + - ]: 33 : aGCProps[ USTR("draw:auto-grow-width") ] = USTR("true");
[ + - ]
933 [ + - ][ + - ]: 33 : aGCProps[ USTR("draw:textarea-horizontal-align") ] = USTR("left");
[ + - ]
934 [ + - ][ + - ]: 33 : aGCProps[ USTR("draw:textarea-vertical-align") ] = USTR("top");
[ + - ]
935 [ + - ][ + - ]: 33 : aGCProps[ USTR("fo:min-height")] = USTR("0cm");
[ + - ]
936 [ + - ][ + - ]: 33 : aGCProps[ USTR("fo:min-width")] = USTR("0cm");
[ + - ]
937 [ + - ][ + - ]: 33 : aGCProps[ USTR("fo:padding-top") ] = USTR("0cm");
[ + - ]
938 [ + - ][ + - ]: 33 : aGCProps[ USTR("fo:padding-left") ] = USTR("0cm");
[ + - ]
939 [ + - ][ + - ]: 33 : aGCProps[ USTR("fo:padding-right") ] = USTR("0cm");
[ + - ]
940 [ + - ][ + - ]: 33 : aGCProps[ USTR("fo:padding-bottom") ] = USTR("0cm");
[ + - ]
941 : :
942 : : // remark: vertical mirroring is done in current OOO by
943 : : // mirroring horzontally and rotating 180 degrees
944 : : // this is quaint, but unfortunately it seems
945 : : // mirror=vertical is defined but not implemented in current code
946 [ - + ]: 33 : if( elem.MirrorVertical )
947 [ # # ][ # # ]: 0 : aGCProps[ USTR("style:mirror") ] = USTR("horizontal");
[ # # ]
948 : :
949 [ + - ]: 33 : StyleContainer::Style aStyle( "style:style", aProps );
950 [ + - ]: 33 : StyleContainer::Style aSubStyle( "style:graphic-properties", aGCProps );
951 [ + - ]: 33 : aStyle.SubStyles.push_back( &aSubStyle );
952 : :
953 [ + - ]: 33 : elem.StyleId = m_rStyleContainer.getStyleId( aStyle );
954 [ + - ][ + - ]: 33 : elem.applyToChildren(*this);
[ + - ][ + - ]
[ + - ]
955 : 33 : }
956 : :
957 : 0 : void DrawXmlFinalizer::visit( ImageElement&, const std::list< Element* >::const_iterator& )
958 : : {
959 : 0 : }
960 : :
961 : 3 : void DrawXmlFinalizer::visit( PageElement& elem, const std::list< Element* >::const_iterator& )
962 : : {
963 [ - + ]: 3 : if( m_rProcessor.getStatusIndicator().is() )
964 [ # # ][ # # ]: 0 : m_rProcessor.getStatusIndicator()->setValue( elem.PageNumber );
965 : :
966 : : // transform from pixel to mm
967 : 3 : double page_width = convPx2mm( elem.w ), page_height = convPx2mm( elem.h );
968 : :
969 : : // calculate page margins out of the relevant children (paragraphs)
970 : 3 : elem.TopMargin = elem.h, elem.BottomMargin = 0, elem.LeftMargin = elem.w, elem.RightMargin = 0;
971 : :
972 [ + + ]: 45 : for( std::list< Element* >::const_iterator it = elem.Children.begin(); it != elem.Children.end(); ++it )
973 : : {
974 [ + + ]: 42 : if( (*it)->x < elem.LeftMargin )
975 : 3 : elem.LeftMargin = (*it)->x;
976 [ + + ]: 42 : if( (*it)->y < elem.TopMargin )
977 : 6 : elem.TopMargin = (*it)->y;
978 [ + + ]: 42 : if( (*it)->x + (*it)->w > elem.RightMargin )
979 : 12 : elem.RightMargin = ((*it)->x + (*it)->w);
980 [ + + ]: 42 : if( (*it)->y + (*it)->h > elem.BottomMargin )
981 : 24 : elem.BottomMargin = ((*it)->y + (*it)->h);
982 : : }
983 : :
984 : : // transform margins to mm
985 : 3 : double left_margin = convPx2mm( elem.LeftMargin );
986 : 3 : double right_margin = convPx2mm( elem.RightMargin );
987 : 3 : double top_margin = convPx2mm( elem.TopMargin );
988 : 3 : double bottom_margin = convPx2mm( elem.BottomMargin );
989 : :
990 : : // round left/top margin to nearest mm
991 : 3 : left_margin = rtl_math_round( left_margin, 0, rtl_math_RoundingMode_Floor );
992 : 3 : top_margin = rtl_math_round( top_margin, 0, rtl_math_RoundingMode_Floor );
993 : : // round (fuzzy) right/bottom margin to nearest cm
994 [ + - ]: 3 : right_margin = rtl_math_round( right_margin, right_margin >= 10 ? -1 : 0, rtl_math_RoundingMode_Floor );
995 [ + - ]: 3 : bottom_margin = rtl_math_round( bottom_margin, bottom_margin >= 10 ? -1 : 0, rtl_math_RoundingMode_Floor );
996 : :
997 : : // set reasonable default in case of way too large margins
998 : : // e.g. no paragraph case
999 [ - + ]: 3 : if( left_margin > page_width/2.0 - 10 )
1000 : 0 : left_margin = 10;
1001 [ + - ]: 3 : if( right_margin > page_width/2.0 - 10 )
1002 : 3 : right_margin = 10;
1003 [ - + ]: 3 : if( top_margin > page_height/2.0 - 10 )
1004 : 0 : top_margin = 10;
1005 [ + - ]: 3 : if( bottom_margin > page_height/2.0 - 10 )
1006 : 3 : bottom_margin = 10;
1007 : :
1008 : : // catch the weird cases
1009 [ - + ]: 3 : if( left_margin < 0 )
1010 : 0 : left_margin = 0;
1011 [ - + ]: 3 : if( right_margin < 0 )
1012 : 0 : right_margin = 0;
1013 [ - + ]: 3 : if( top_margin < 0 )
1014 : 0 : top_margin = 0;
1015 [ - + ]: 3 : if( bottom_margin < 0 )
1016 : 0 : bottom_margin = 0;
1017 : :
1018 : : // widely differing margins are unlikely to be correct
1019 [ - + ]: 3 : if( right_margin > left_margin*1.5 )
1020 : 0 : right_margin = left_margin;
1021 : :
1022 : 3 : elem.LeftMargin = convmm2Px( left_margin );
1023 : 3 : elem.RightMargin = convmm2Px( right_margin );
1024 : 3 : elem.TopMargin = convmm2Px( top_margin );
1025 : 3 : elem.BottomMargin = convmm2Px( bottom_margin );
1026 : :
1027 : : // get styles for paragraphs
1028 [ + - ]: 3 : PropertyMap aPageProps;
1029 [ + - ]: 3 : PropertyMap aPageLayoutProps;
1030 : 3 : rtl::OUStringBuffer aBuf( 64 );
1031 [ + - ][ + - ]: 3 : aPageLayoutProps[ USTR( "fo:margin-top" ) ] = unitMMString( top_margin );
[ + - ]
1032 [ + - ][ + - ]: 3 : aPageLayoutProps[ USTR( "fo:margin-bottom" ) ] = unitMMString( bottom_margin );
[ + - ]
1033 [ + - ][ + - ]: 3 : aPageLayoutProps[ USTR( "fo:margin-left" ) ] = unitMMString( left_margin );
[ + - ]
1034 [ + - ][ + - ]: 3 : aPageLayoutProps[ USTR( "fo:margin-right" ) ] = unitMMString( right_margin );
[ + - ]
1035 [ + - ][ + - ]: 3 : aPageLayoutProps[ USTR( "fo:page-width" ) ] = unitMMString( page_width );
[ + - ]
1036 [ + - ][ + - ]: 3 : aPageLayoutProps[ USTR( "fo:page-height" ) ] = unitMMString( page_height );
[ + - ]
1037 [ # # ][ + - ]: 3 : aPageLayoutProps[ USTR( "style:print-orientation" ) ]= elem.w < elem.h ? USTR( "portrait" ) : USTR( "landscape" );
[ + - ][ + - ]
[ - + ]
1038 [ + - ][ + - ]: 3 : aPageLayoutProps[ USTR( "style:writing-mode" ) ]= USTR( "lr-tb" );
[ + - ]
1039 : :
1040 [ + - ]: 3 : StyleContainer::Style aStyle( "style:page-layout", aPageProps);
1041 [ + - ]: 3 : StyleContainer::Style aSubStyle( "style:page-layout-properties", aPageLayoutProps);
1042 [ + - ]: 3 : aStyle.SubStyles.push_back(&aSubStyle);
1043 [ + - ]: 3 : sal_Int32 nPageStyle = m_rStyleContainer.impl_getStyleId( aStyle, false );
1044 : :
1045 : : // create master page
1046 [ + - ]: 3 : rtl::OUString aMasterPageLayoutName = m_rStyleContainer.getStyleName( nPageStyle );
1047 [ + - ][ + - ]: 3 : aPageProps[ USTR( "style:page-layout-name" ) ] = aMasterPageLayoutName;
1048 : :
1049 [ + - ]: 3 : StyleContainer::Style aMPStyle( "style:master-page", aPageProps);
1050 : :
1051 [ + - ][ + - ]: 3 : StyleContainer::Style aHeaderStyle( "style:header", PropertyMap() );
[ + - ]
1052 [ + - ][ + - ]: 3 : StyleContainer::Style aFooterStyle( "style:footer", PropertyMap() );
[ + - ]
1053 : :
1054 [ + - ]: 3 : elem.StyleId = m_rStyleContainer.impl_getStyleId( aMPStyle,false );
1055 : :
1056 : :
1057 [ + - ]: 3 : rtl::OUString aMasterPageName = m_rStyleContainer.getStyleName( elem.StyleId );
1058 : :
1059 : : // create styles for children
1060 [ + - ][ + - ]: 3 : elem.applyToChildren(*this);
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
1061 : 3 : }
1062 : :
1063 : 3 : void DrawXmlFinalizer::visit( DocumentElement& elem, const std::list< Element* >::const_iterator& )
1064 : : {
1065 : 3 : elem.applyToChildren(*this);
1066 : 3 : }
1067 : :
1068 : : }
1069 : :
1070 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|