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