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