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