1*cdf0e10cSrcweir /************************************************************************* 2*cdf0e10cSrcweir * 3*cdf0e10cSrcweir * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4*cdf0e10cSrcweir * 5*cdf0e10cSrcweir * Copyright 2000, 2010 Oracle and/or its affiliates. 6*cdf0e10cSrcweir * 7*cdf0e10cSrcweir * OpenOffice.org - a multi-platform office productivity suite 8*cdf0e10cSrcweir * 9*cdf0e10cSrcweir * This file is part of OpenOffice.org. 10*cdf0e10cSrcweir * 11*cdf0e10cSrcweir * OpenOffice.org is free software: you can redistribute it and/or modify 12*cdf0e10cSrcweir * it under the terms of the GNU Lesser General Public License version 3 13*cdf0e10cSrcweir * only, as published by the Free Software Foundation. 14*cdf0e10cSrcweir * 15*cdf0e10cSrcweir * OpenOffice.org is distributed in the hope that it will be useful, 16*cdf0e10cSrcweir * but WITHOUT ANY WARRANTY; without even the implied warranty of 17*cdf0e10cSrcweir * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18*cdf0e10cSrcweir * GNU Lesser General Public License version 3 for more details 19*cdf0e10cSrcweir * (a copy is included in the LICENSE file that accompanied this code). 20*cdf0e10cSrcweir * 21*cdf0e10cSrcweir * You should have received a copy of the GNU Lesser General Public License 22*cdf0e10cSrcweir * version 3 along with OpenOffice.org. If not, see 23*cdf0e10cSrcweir * <http://www.openoffice.org/license.html> 24*cdf0e10cSrcweir * for a copy of the LGPLv3 License. 25*cdf0e10cSrcweir * 26*cdf0e10cSrcweir ************************************************************************/ 27*cdf0e10cSrcweir 28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 29*cdf0e10cSrcweir #include "precompiled_sdext.hxx" 30*cdf0e10cSrcweir 31*cdf0e10cSrcweir #include "pdfiprocessor.hxx" 32*cdf0e10cSrcweir #include "xmlemitter.hxx" 33*cdf0e10cSrcweir #include "pdfihelper.hxx" 34*cdf0e10cSrcweir #include "imagecontainer.hxx" 35*cdf0e10cSrcweir #include "style.hxx" 36*cdf0e10cSrcweir #include "writertreevisiting.hxx" 37*cdf0e10cSrcweir #include "genericelements.hxx" 38*cdf0e10cSrcweir 39*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygontools.hxx> 40*cdf0e10cSrcweir #include <basegfx/range/b2drange.hxx> 41*cdf0e10cSrcweir 42*cdf0e10cSrcweir 43*cdf0e10cSrcweir namespace pdfi 44*cdf0e10cSrcweir { 45*cdf0e10cSrcweir 46*cdf0e10cSrcweir void WriterXmlEmitter::visit( HyperlinkElement& elem, const std::list< Element* >::const_iterator& ) 47*cdf0e10cSrcweir { 48*cdf0e10cSrcweir if( elem.Children.empty() ) 49*cdf0e10cSrcweir return; 50*cdf0e10cSrcweir 51*cdf0e10cSrcweir const char* pType = dynamic_cast<DrawElement*>(elem.Children.front()) ? "draw:a" : "text:a"; 52*cdf0e10cSrcweir 53*cdf0e10cSrcweir PropertyMap aProps; 54*cdf0e10cSrcweir aProps[ USTR( "xlink:type" ) ] = USTR( "simple" ); 55*cdf0e10cSrcweir aProps[ USTR( "xlink:href" ) ] = elem.URI; 56*cdf0e10cSrcweir aProps[ USTR( "office:target-frame-name" ) ] = USTR( "_blank" ); 57*cdf0e10cSrcweir aProps[ USTR( "xlink:show" ) ] = USTR( "new" ); 58*cdf0e10cSrcweir 59*cdf0e10cSrcweir m_rEmitContext.rEmitter.beginTag( pType, aProps ); 60*cdf0e10cSrcweir std::list< Element* >::iterator this_it = elem.Children.begin(); 61*cdf0e10cSrcweir while( this_it !=elem.Children.end() && *this_it != &elem ) 62*cdf0e10cSrcweir { 63*cdf0e10cSrcweir (*this_it)->visitedBy( *this, this_it ); 64*cdf0e10cSrcweir this_it++; 65*cdf0e10cSrcweir } 66*cdf0e10cSrcweir m_rEmitContext.rEmitter.endTag( pType ); 67*cdf0e10cSrcweir } 68*cdf0e10cSrcweir 69*cdf0e10cSrcweir void WriterXmlEmitter::visit( TextElement& elem, const std::list< Element* >::const_iterator& ) 70*cdf0e10cSrcweir { 71*cdf0e10cSrcweir if( ! elem.Text.getLength() ) 72*cdf0e10cSrcweir return; 73*cdf0e10cSrcweir 74*cdf0e10cSrcweir PropertyMap aProps; 75*cdf0e10cSrcweir if( elem.StyleId != -1 ) 76*cdf0e10cSrcweir { 77*cdf0e10cSrcweir aProps[ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "text:style-name" ) ) ] = 78*cdf0e10cSrcweir m_rEmitContext.rStyles.getStyleName( elem.StyleId ); 79*cdf0e10cSrcweir } 80*cdf0e10cSrcweir 81*cdf0e10cSrcweir m_rEmitContext.rEmitter.beginTag( "text:span", aProps ); 82*cdf0e10cSrcweir m_rEmitContext.rEmitter.write( elem.Text.makeStringAndClear() ); 83*cdf0e10cSrcweir std::list< Element* >::iterator this_it = elem.Children.begin(); 84*cdf0e10cSrcweir while( this_it !=elem.Children.end() && *this_it != &elem ) 85*cdf0e10cSrcweir { 86*cdf0e10cSrcweir (*this_it)->visitedBy( *this, this_it ); 87*cdf0e10cSrcweir this_it++; 88*cdf0e10cSrcweir } 89*cdf0e10cSrcweir 90*cdf0e10cSrcweir m_rEmitContext.rEmitter.endTag( "text:span" ); 91*cdf0e10cSrcweir } 92*cdf0e10cSrcweir 93*cdf0e10cSrcweir void WriterXmlEmitter::visit( ParagraphElement& elem, const std::list< Element* >::const_iterator& ) 94*cdf0e10cSrcweir { 95*cdf0e10cSrcweir PropertyMap aProps; 96*cdf0e10cSrcweir if( elem.StyleId != -1 ) 97*cdf0e10cSrcweir { 98*cdf0e10cSrcweir aProps[ USTR( "text:style-name" ) ] = m_rEmitContext.rStyles.getStyleName( elem.StyleId ); 99*cdf0e10cSrcweir } 100*cdf0e10cSrcweir const char* pTagType = "text:p"; 101*cdf0e10cSrcweir if( elem.Type == elem.Headline ) 102*cdf0e10cSrcweir pTagType = "text:h"; 103*cdf0e10cSrcweir m_rEmitContext.rEmitter.beginTag( pTagType, aProps ); 104*cdf0e10cSrcweir 105*cdf0e10cSrcweir std::list< Element* >::iterator this_it = elem.Children.begin(); 106*cdf0e10cSrcweir while( this_it !=elem.Children.end() && *this_it != &elem ) 107*cdf0e10cSrcweir { 108*cdf0e10cSrcweir (*this_it)->visitedBy( *this, this_it ); 109*cdf0e10cSrcweir this_it++; 110*cdf0e10cSrcweir } 111*cdf0e10cSrcweir 112*cdf0e10cSrcweir m_rEmitContext.rEmitter.endTag( pTagType ); 113*cdf0e10cSrcweir } 114*cdf0e10cSrcweir 115*cdf0e10cSrcweir void WriterXmlEmitter::fillFrameProps( DrawElement& rElem, 116*cdf0e10cSrcweir PropertyMap& rProps, 117*cdf0e10cSrcweir const EmitContext& rEmitContext ) 118*cdf0e10cSrcweir { 119*cdf0e10cSrcweir double rel_x = rElem.x, rel_y = rElem.y; 120*cdf0e10cSrcweir 121*cdf0e10cSrcweir // find anchor type by recursing though parents 122*cdf0e10cSrcweir Element* pAnchor = rElem.Parent; 123*cdf0e10cSrcweir while( pAnchor && 124*cdf0e10cSrcweir ! dynamic_cast<ParagraphElement*>(pAnchor) && 125*cdf0e10cSrcweir ! dynamic_cast<PageElement*>(pAnchor) ) 126*cdf0e10cSrcweir { 127*cdf0e10cSrcweir pAnchor = pAnchor->Parent; 128*cdf0e10cSrcweir } 129*cdf0e10cSrcweir if( pAnchor ) 130*cdf0e10cSrcweir { 131*cdf0e10cSrcweir if( dynamic_cast<ParagraphElement*>(pAnchor) ) 132*cdf0e10cSrcweir { 133*cdf0e10cSrcweir rProps[ USTR( "text:anchor-type" ) ] = 134*cdf0e10cSrcweir rElem.isCharacter ? USTR( "character" ) : USTR( "paragraph" ); 135*cdf0e10cSrcweir } 136*cdf0e10cSrcweir else 137*cdf0e10cSrcweir { 138*cdf0e10cSrcweir PageElement* pPage = dynamic_cast<PageElement*>(pAnchor); 139*cdf0e10cSrcweir rProps[ USTR( "text:anchor-type" ) ] = USTR( "page" ); 140*cdf0e10cSrcweir rProps[ USTR( "text:anchor-page-number" ) ] = rtl::OUString::valueOf(pPage->PageNumber); 141*cdf0e10cSrcweir } 142*cdf0e10cSrcweir rel_x -= pAnchor->x; 143*cdf0e10cSrcweir rel_y -= pAnchor->y; 144*cdf0e10cSrcweir } 145*cdf0e10cSrcweir 146*cdf0e10cSrcweir rProps[ USTR( "draw:z-index" ) ] = rtl::OUString::valueOf( rElem.ZOrder ); 147*cdf0e10cSrcweir rProps[ USTR( "draw:style-name" )] = rEmitContext.rStyles.getStyleName( rElem.StyleId ); 148*cdf0e10cSrcweir rProps[ USTR( "svg:width" ) ] = convertPixelToUnitString( rElem.w ); 149*cdf0e10cSrcweir rProps[ USTR( "svg:height" ) ] = convertPixelToUnitString( rElem.h ); 150*cdf0e10cSrcweir 151*cdf0e10cSrcweir const GraphicsContext& rGC = 152*cdf0e10cSrcweir rEmitContext.rProcessor.getGraphicsContext( rElem.GCId ); 153*cdf0e10cSrcweir if( rGC.Transformation.isIdentity() ) 154*cdf0e10cSrcweir { 155*cdf0e10cSrcweir if( !rElem.isCharacter ) 156*cdf0e10cSrcweir { 157*cdf0e10cSrcweir rProps[ USTR( "svg:x" ) ] = convertPixelToUnitString( rel_x ); 158*cdf0e10cSrcweir rProps[ USTR( "svg:y" ) ] = convertPixelToUnitString( rel_y ); 159*cdf0e10cSrcweir } 160*cdf0e10cSrcweir } 161*cdf0e10cSrcweir else 162*cdf0e10cSrcweir { 163*cdf0e10cSrcweir basegfx::B2DTuple aScale, aTranslation; 164*cdf0e10cSrcweir double fRotate, fShearX; 165*cdf0e10cSrcweir 166*cdf0e10cSrcweir rGC.Transformation.decompose( aScale, aTranslation, fRotate, fShearX ); 167*cdf0e10cSrcweir 168*cdf0e10cSrcweir rtl::OUStringBuffer aBuf( 256 ); 169*cdf0e10cSrcweir 170*cdf0e10cSrcweir // TODO(F2): general transformation case missing; if implemented, note 171*cdf0e10cSrcweir // that ODF rotation is oriented the other way 172*cdf0e10cSrcweir 173*cdf0e10cSrcweir // build transformation string 174*cdf0e10cSrcweir if( fShearX != 0.0 ) 175*cdf0e10cSrcweir { 176*cdf0e10cSrcweir aBuf.appendAscii( "skewX( " ); 177*cdf0e10cSrcweir aBuf.append( fShearX ); 178*cdf0e10cSrcweir aBuf.appendAscii( " )" ); 179*cdf0e10cSrcweir } 180*cdf0e10cSrcweir if( fRotate != 0.0 ) 181*cdf0e10cSrcweir { 182*cdf0e10cSrcweir if( aBuf.getLength() > 0 ) 183*cdf0e10cSrcweir aBuf.append( sal_Unicode(' ') ); 184*cdf0e10cSrcweir aBuf.appendAscii( "rotate( " ); 185*cdf0e10cSrcweir aBuf.append( -fRotate ); 186*cdf0e10cSrcweir aBuf.appendAscii( " )" ); 187*cdf0e10cSrcweir 188*cdf0e10cSrcweir } 189*cdf0e10cSrcweir if( ! rElem.isCharacter ) 190*cdf0e10cSrcweir { 191*cdf0e10cSrcweir if( aBuf.getLength() > 0 ) 192*cdf0e10cSrcweir aBuf.append( sal_Unicode(' ') ); 193*cdf0e10cSrcweir aBuf.appendAscii( "translate( " ); 194*cdf0e10cSrcweir aBuf.append( convertPixelToUnitString( rel_x ) ); 195*cdf0e10cSrcweir aBuf.append( sal_Unicode(' ') ); 196*cdf0e10cSrcweir aBuf.append( convertPixelToUnitString( rel_y ) ); 197*cdf0e10cSrcweir aBuf.appendAscii( " )" ); 198*cdf0e10cSrcweir } 199*cdf0e10cSrcweir 200*cdf0e10cSrcweir rProps[ USTR( "draw:transform" ) ] = aBuf.makeStringAndClear(); 201*cdf0e10cSrcweir } 202*cdf0e10cSrcweir } 203*cdf0e10cSrcweir 204*cdf0e10cSrcweir void WriterXmlEmitter::visit( FrameElement& elem, const std::list< Element* >::const_iterator& ) 205*cdf0e10cSrcweir { 206*cdf0e10cSrcweir if( elem.Children.empty() ) 207*cdf0e10cSrcweir return; 208*cdf0e10cSrcweir 209*cdf0e10cSrcweir bool bTextBox = (dynamic_cast<ParagraphElement*>(elem.Children.front()) != NULL); 210*cdf0e10cSrcweir PropertyMap aFrameProps; 211*cdf0e10cSrcweir fillFrameProps( elem, aFrameProps, m_rEmitContext ); 212*cdf0e10cSrcweir m_rEmitContext.rEmitter.beginTag( "draw:frame", aFrameProps ); 213*cdf0e10cSrcweir if( bTextBox ) 214*cdf0e10cSrcweir m_rEmitContext.rEmitter.beginTag( "draw:text-box", PropertyMap() ); 215*cdf0e10cSrcweir 216*cdf0e10cSrcweir std::list< Element* >::iterator this_it = elem.Children.begin(); 217*cdf0e10cSrcweir while( this_it !=elem.Children.end() && *this_it != &elem ) 218*cdf0e10cSrcweir { 219*cdf0e10cSrcweir (*this_it)->visitedBy( *this, this_it ); 220*cdf0e10cSrcweir this_it++; 221*cdf0e10cSrcweir } 222*cdf0e10cSrcweir 223*cdf0e10cSrcweir if( bTextBox ) 224*cdf0e10cSrcweir m_rEmitContext.rEmitter.endTag( "draw:text-box" ); 225*cdf0e10cSrcweir m_rEmitContext.rEmitter.endTag( "draw:frame" ); 226*cdf0e10cSrcweir } 227*cdf0e10cSrcweir 228*cdf0e10cSrcweir void WriterXmlEmitter::visit( PolyPolyElement& elem, const std::list< Element* >::const_iterator& ) 229*cdf0e10cSrcweir { 230*cdf0e10cSrcweir elem.updateGeometry(); 231*cdf0e10cSrcweir /* note: 232*cdf0e10cSrcweir * aw recommends using 100dth of mm in all respects since the xml import 233*cdf0e10cSrcweir * (a) is buggy (see issue 37213) 234*cdf0e10cSrcweir * (b) is optimized for 100dth of mm and does not scale itself then, 235*cdf0e10cSrcweir * this does not gain us speed but makes for smaller rounding errors since 236*cdf0e10cSrcweir * the xml importer coordinates are integer based 237*cdf0e10cSrcweir */ 238*cdf0e10cSrcweir for (sal_uInt32 i = 0; i< elem.PolyPoly.count(); i++) 239*cdf0e10cSrcweir { 240*cdf0e10cSrcweir basegfx::B2DPolygon b2dPolygon; 241*cdf0e10cSrcweir b2dPolygon = elem.PolyPoly.getB2DPolygon( i ); 242*cdf0e10cSrcweir 243*cdf0e10cSrcweir for ( sal_uInt32 j = 0; j< b2dPolygon.count(); j++ ) 244*cdf0e10cSrcweir { 245*cdf0e10cSrcweir basegfx::B2DPoint point; 246*cdf0e10cSrcweir basegfx::B2DPoint nextPoint; 247*cdf0e10cSrcweir point = b2dPolygon.getB2DPoint( j ); 248*cdf0e10cSrcweir 249*cdf0e10cSrcweir basegfx::B2DPoint prevPoint; 250*cdf0e10cSrcweir prevPoint = b2dPolygon.getPrevControlPoint( j ) ; 251*cdf0e10cSrcweir 252*cdf0e10cSrcweir point.setX( convPx2mmPrec2( point.getX() )*100.0 ); 253*cdf0e10cSrcweir point.setY( convPx2mmPrec2( point.getY() )*100.0 ); 254*cdf0e10cSrcweir 255*cdf0e10cSrcweir if ( b2dPolygon.isPrevControlPointUsed( j ) ) 256*cdf0e10cSrcweir { 257*cdf0e10cSrcweir prevPoint.setX( convPx2mmPrec2( prevPoint.getX() )*100.0 ); 258*cdf0e10cSrcweir prevPoint.setY( convPx2mmPrec2( prevPoint.getY() )*100.0 ); 259*cdf0e10cSrcweir } 260*cdf0e10cSrcweir 261*cdf0e10cSrcweir if ( b2dPolygon.isNextControlPointUsed( j ) ) 262*cdf0e10cSrcweir { 263*cdf0e10cSrcweir nextPoint = b2dPolygon.getNextControlPoint( j ) ; 264*cdf0e10cSrcweir nextPoint.setX( convPx2mmPrec2( nextPoint.getX() )*100.0 ); 265*cdf0e10cSrcweir nextPoint.setY( convPx2mmPrec2( nextPoint.getY() )*100.0 ); 266*cdf0e10cSrcweir } 267*cdf0e10cSrcweir 268*cdf0e10cSrcweir b2dPolygon.setB2DPoint( j, point ); 269*cdf0e10cSrcweir 270*cdf0e10cSrcweir if ( b2dPolygon.isPrevControlPointUsed( j ) ) 271*cdf0e10cSrcweir b2dPolygon.setPrevControlPoint( j , prevPoint ) ; 272*cdf0e10cSrcweir 273*cdf0e10cSrcweir if ( b2dPolygon.isNextControlPointUsed( j ) ) 274*cdf0e10cSrcweir b2dPolygon.setNextControlPoint( j , nextPoint ) ; 275*cdf0e10cSrcweir } 276*cdf0e10cSrcweir 277*cdf0e10cSrcweir elem.PolyPoly.setB2DPolygon( i, b2dPolygon ); 278*cdf0e10cSrcweir } 279*cdf0e10cSrcweir 280*cdf0e10cSrcweir PropertyMap aProps; 281*cdf0e10cSrcweir fillFrameProps( elem, aProps, m_rEmitContext ); 282*cdf0e10cSrcweir rtl::OUStringBuffer aBuf( 64 ); 283*cdf0e10cSrcweir aBuf.appendAscii( "0 0 " ); 284*cdf0e10cSrcweir aBuf.append( convPx2mmPrec2(elem.w)*100.0 ); 285*cdf0e10cSrcweir aBuf.append( sal_Unicode(' ') ); 286*cdf0e10cSrcweir aBuf.append( convPx2mmPrec2(elem.h)*100.0 ); 287*cdf0e10cSrcweir aProps[ USTR( "svg:viewBox" ) ] = aBuf.makeStringAndClear(); 288*cdf0e10cSrcweir aProps[ USTR( "svg:d" ) ] = basegfx::tools::exportToSvgD( elem.PolyPoly ); 289*cdf0e10cSrcweir 290*cdf0e10cSrcweir m_rEmitContext.rEmitter.beginTag( "draw:path", aProps ); 291*cdf0e10cSrcweir m_rEmitContext.rEmitter.endTag( "draw:path" ); 292*cdf0e10cSrcweir } 293*cdf0e10cSrcweir 294*cdf0e10cSrcweir void WriterXmlEmitter::visit( ImageElement& elem, const std::list< Element* >::const_iterator& ) 295*cdf0e10cSrcweir { 296*cdf0e10cSrcweir PropertyMap aImageProps; 297*cdf0e10cSrcweir m_rEmitContext.rEmitter.beginTag( "draw:image", aImageProps ); 298*cdf0e10cSrcweir m_rEmitContext.rEmitter.beginTag( "office:binary-data", PropertyMap() ); 299*cdf0e10cSrcweir m_rEmitContext.rImages.writeBase64EncodedStream( elem.Image, m_rEmitContext); 300*cdf0e10cSrcweir m_rEmitContext.rEmitter.endTag( "office:binary-data" ); 301*cdf0e10cSrcweir m_rEmitContext.rEmitter.endTag( "draw:image" ); 302*cdf0e10cSrcweir } 303*cdf0e10cSrcweir 304*cdf0e10cSrcweir void WriterXmlEmitter::visit( PageElement& elem, const std::list< Element* >::const_iterator& ) 305*cdf0e10cSrcweir { 306*cdf0e10cSrcweir if( m_rEmitContext.xStatusIndicator.is() ) 307*cdf0e10cSrcweir m_rEmitContext.xStatusIndicator->setValue( elem.PageNumber ); 308*cdf0e10cSrcweir 309*cdf0e10cSrcweir std::list< Element* >::iterator this_it = elem.Children.begin(); 310*cdf0e10cSrcweir while( this_it !=elem.Children.end() && *this_it != &elem ) 311*cdf0e10cSrcweir { 312*cdf0e10cSrcweir (*this_it)->visitedBy( *this, this_it ); 313*cdf0e10cSrcweir this_it++; 314*cdf0e10cSrcweir } 315*cdf0e10cSrcweir } 316*cdf0e10cSrcweir 317*cdf0e10cSrcweir void WriterXmlEmitter::visit( DocumentElement& elem, const std::list< Element* >::const_iterator&) 318*cdf0e10cSrcweir { 319*cdf0e10cSrcweir m_rEmitContext.rEmitter.beginTag( "office:body", PropertyMap() ); 320*cdf0e10cSrcweir m_rEmitContext.rEmitter.beginTag( "office:text", PropertyMap() ); 321*cdf0e10cSrcweir 322*cdf0e10cSrcweir for( std::list< Element* >::iterator it = elem.Children.begin(); it != elem.Children.end(); ++it ) 323*cdf0e10cSrcweir { 324*cdf0e10cSrcweir PageElement* pPage = dynamic_cast<PageElement*>(*it); 325*cdf0e10cSrcweir if( pPage ) 326*cdf0e10cSrcweir { 327*cdf0e10cSrcweir // emit only page anchored objects 328*cdf0e10cSrcweir // currently these are only DrawElement types 329*cdf0e10cSrcweir for( std::list< Element* >::iterator child_it = pPage->Children.begin(); child_it != pPage->Children.end(); ++child_it ) 330*cdf0e10cSrcweir { 331*cdf0e10cSrcweir if( dynamic_cast<DrawElement*>(*child_it) != NULL ) 332*cdf0e10cSrcweir (*child_it)->visitedBy( *this, child_it ); 333*cdf0e10cSrcweir } 334*cdf0e10cSrcweir } 335*cdf0e10cSrcweir } 336*cdf0e10cSrcweir 337*cdf0e10cSrcweir // do not emit page anchored objects, they are emitted before 338*cdf0e10cSrcweir // (must precede all pages in writer document) currently these are 339*cdf0e10cSrcweir // only DrawElement types 340*cdf0e10cSrcweir for( std::list< Element* >::iterator it = elem.Children.begin(); it != elem.Children.end(); ++it ) 341*cdf0e10cSrcweir { 342*cdf0e10cSrcweir if( dynamic_cast<DrawElement*>(*it) == NULL ) 343*cdf0e10cSrcweir (*it)->visitedBy( *this, it ); 344*cdf0e10cSrcweir } 345*cdf0e10cSrcweir 346*cdf0e10cSrcweir m_rEmitContext.rEmitter.endTag( "office:text" ); 347*cdf0e10cSrcweir m_rEmitContext.rEmitter.endTag( "office:body" ); 348*cdf0e10cSrcweir } 349*cdf0e10cSrcweir 350*cdf0e10cSrcweir ///////////////////////////////////////////////////////////////// 351*cdf0e10cSrcweir 352*cdf0e10cSrcweir void WriterXmlOptimizer::visit( HyperlinkElement&, const std::list< Element* >::const_iterator& ) 353*cdf0e10cSrcweir { 354*cdf0e10cSrcweir } 355*cdf0e10cSrcweir 356*cdf0e10cSrcweir void WriterXmlOptimizer::visit( TextElement&, const std::list< Element* >::const_iterator&) 357*cdf0e10cSrcweir { 358*cdf0e10cSrcweir } 359*cdf0e10cSrcweir 360*cdf0e10cSrcweir void WriterXmlOptimizer::visit( FrameElement& elem, const std::list< Element* >::const_iterator& ) 361*cdf0e10cSrcweir { 362*cdf0e10cSrcweir elem.applyToChildren(*this); 363*cdf0e10cSrcweir } 364*cdf0e10cSrcweir 365*cdf0e10cSrcweir void WriterXmlOptimizer::visit( ImageElement&, const std::list< Element* >::const_iterator& ) 366*cdf0e10cSrcweir { 367*cdf0e10cSrcweir } 368*cdf0e10cSrcweir 369*cdf0e10cSrcweir void WriterXmlOptimizer::visit( PolyPolyElement& elem, const std::list< Element* >::const_iterator& ) 370*cdf0e10cSrcweir { 371*cdf0e10cSrcweir /* note: optimize two consecutive PolyPolyElements that 372*cdf0e10cSrcweir * have the same path but one of which is a stroke while 373*cdf0e10cSrcweir * the other is a fill 374*cdf0e10cSrcweir */ 375*cdf0e10cSrcweir if( elem.Parent ) 376*cdf0e10cSrcweir { 377*cdf0e10cSrcweir // find following PolyPolyElement in parent's children list 378*cdf0e10cSrcweir std::list< Element* >::iterator this_it = elem.Parent->Children.begin(); 379*cdf0e10cSrcweir while( this_it != elem.Parent->Children.end() && *this_it != &elem ) 380*cdf0e10cSrcweir ++this_it; 381*cdf0e10cSrcweir 382*cdf0e10cSrcweir if( this_it != elem.Parent->Children.end() ) 383*cdf0e10cSrcweir { 384*cdf0e10cSrcweir std::list< Element* >::iterator next_it = this_it; 385*cdf0e10cSrcweir if( ++next_it != elem.Parent->Children.end() ) 386*cdf0e10cSrcweir { 387*cdf0e10cSrcweir PolyPolyElement* pNext = dynamic_cast<PolyPolyElement*>(*next_it); 388*cdf0e10cSrcweir if( pNext && pNext->PolyPoly == elem.PolyPoly ) 389*cdf0e10cSrcweir { 390*cdf0e10cSrcweir const GraphicsContext& rNextGC = 391*cdf0e10cSrcweir m_rProcessor.getGraphicsContext( pNext->GCId ); 392*cdf0e10cSrcweir const GraphicsContext& rThisGC = 393*cdf0e10cSrcweir m_rProcessor.getGraphicsContext( elem.GCId ); 394*cdf0e10cSrcweir 395*cdf0e10cSrcweir if( rThisGC.BlendMode == rNextGC.BlendMode && 396*cdf0e10cSrcweir rThisGC.Flatness == rNextGC.Flatness && 397*cdf0e10cSrcweir rThisGC.Transformation == rNextGC.Transformation && 398*cdf0e10cSrcweir rThisGC.Clip == rNextGC.Clip && 399*cdf0e10cSrcweir pNext->Action == PATH_STROKE && 400*cdf0e10cSrcweir (elem.Action == PATH_FILL || elem.Action == PATH_EOFILL) ) 401*cdf0e10cSrcweir { 402*cdf0e10cSrcweir GraphicsContext aGC = rThisGC; 403*cdf0e10cSrcweir aGC.LineJoin = rNextGC.LineJoin; 404*cdf0e10cSrcweir aGC.LineCap = rNextGC.LineCap; 405*cdf0e10cSrcweir aGC.LineWidth = rNextGC.LineWidth; 406*cdf0e10cSrcweir aGC.MiterLimit= rNextGC.MiterLimit; 407*cdf0e10cSrcweir aGC.DashArray = rNextGC.DashArray; 408*cdf0e10cSrcweir aGC.LineColor = rNextGC.LineColor; 409*cdf0e10cSrcweir elem.GCId = m_rProcessor.getGCId( aGC ); 410*cdf0e10cSrcweir 411*cdf0e10cSrcweir elem.Action |= pNext->Action; 412*cdf0e10cSrcweir 413*cdf0e10cSrcweir elem.Children.splice( elem.Children.end(), pNext->Children ); 414*cdf0e10cSrcweir elem.Parent->Children.erase( next_it ); 415*cdf0e10cSrcweir delete pNext; 416*cdf0e10cSrcweir } 417*cdf0e10cSrcweir } 418*cdf0e10cSrcweir } 419*cdf0e10cSrcweir } 420*cdf0e10cSrcweir } 421*cdf0e10cSrcweir } 422*cdf0e10cSrcweir 423*cdf0e10cSrcweir void WriterXmlOptimizer::visit( ParagraphElement& elem, const std::list< Element* >::const_iterator& rParentIt) 424*cdf0e10cSrcweir { 425*cdf0e10cSrcweir optimizeTextElements( elem ); 426*cdf0e10cSrcweir 427*cdf0e10cSrcweir elem.applyToChildren(*this); 428*cdf0e10cSrcweir 429*cdf0e10cSrcweir if( elem.Parent && rParentIt != elem.Parent->Children.end() ) 430*cdf0e10cSrcweir { 431*cdf0e10cSrcweir // find if there is a previous paragraph that might be a heading for this one 432*cdf0e10cSrcweir std::list<Element*>::const_iterator prev = rParentIt; 433*cdf0e10cSrcweir ParagraphElement* pPrevPara = NULL; 434*cdf0e10cSrcweir while( prev != elem.Parent->Children.begin() ) 435*cdf0e10cSrcweir { 436*cdf0e10cSrcweir --prev; 437*cdf0e10cSrcweir pPrevPara = dynamic_cast< ParagraphElement* >(*prev); 438*cdf0e10cSrcweir if( pPrevPara ) 439*cdf0e10cSrcweir { 440*cdf0e10cSrcweir /* What constitutes a heading ? current hints are: 441*cdf0e10cSrcweir * - one line only 442*cdf0e10cSrcweir * - not too far away from this paragraph (two heading height max ?) 443*cdf0e10cSrcweir * - font larger or bold 444*cdf0e10cSrcweir * this is of course incomplete 445*cdf0e10cSrcweir * FIXME: improve hints for heading 446*cdf0e10cSrcweir */ 447*cdf0e10cSrcweir // check for single line 448*cdf0e10cSrcweir if( pPrevPara->isSingleLined( m_rProcessor ) ) 449*cdf0e10cSrcweir { 450*cdf0e10cSrcweir double head_line_height = pPrevPara->getLineHeight( m_rProcessor ); 451*cdf0e10cSrcweir if( pPrevPara->y + pPrevPara->h + 2*head_line_height > elem.y ) 452*cdf0e10cSrcweir { 453*cdf0e10cSrcweir // check for larger font 454*cdf0e10cSrcweir if( head_line_height > elem.getLineHeight( m_rProcessor ) ) 455*cdf0e10cSrcweir { 456*cdf0e10cSrcweir pPrevPara->Type = elem.Headline; 457*cdf0e10cSrcweir } 458*cdf0e10cSrcweir else 459*cdf0e10cSrcweir { 460*cdf0e10cSrcweir // check whether text of pPrevPara is bold (at least first text element) 461*cdf0e10cSrcweir // and this para is not bold (dito) 462*cdf0e10cSrcweir TextElement* pPrevText = pPrevPara->getFirstTextChild(); 463*cdf0e10cSrcweir TextElement* pThisText = elem.getFirstTextChild(); 464*cdf0e10cSrcweir if( pPrevText && pThisText ) 465*cdf0e10cSrcweir { 466*cdf0e10cSrcweir const FontAttributes& rPrevFont = m_rProcessor.getFont( pPrevText->FontId ); 467*cdf0e10cSrcweir const FontAttributes& rThisFont = m_rProcessor.getFont( pThisText->FontId ); 468*cdf0e10cSrcweir if( rPrevFont.isBold && ! rThisFont.isBold ) 469*cdf0e10cSrcweir pPrevPara->Type = elem.Headline; 470*cdf0e10cSrcweir } 471*cdf0e10cSrcweir } 472*cdf0e10cSrcweir } 473*cdf0e10cSrcweir } 474*cdf0e10cSrcweir break; 475*cdf0e10cSrcweir } 476*cdf0e10cSrcweir } 477*cdf0e10cSrcweir } 478*cdf0e10cSrcweir } 479*cdf0e10cSrcweir 480*cdf0e10cSrcweir void WriterXmlOptimizer::visit( PageElement& elem, const std::list< Element* >::const_iterator& ) 481*cdf0e10cSrcweir { 482*cdf0e10cSrcweir if( m_rProcessor.getStatusIndicator().is() ) 483*cdf0e10cSrcweir m_rProcessor.getStatusIndicator()->setValue( elem.PageNumber ); 484*cdf0e10cSrcweir 485*cdf0e10cSrcweir // resolve hyperlinks 486*cdf0e10cSrcweir elem.resolveHyperlinks(); 487*cdf0e10cSrcweir 488*cdf0e10cSrcweir elem.resolveFontStyles( m_rProcessor ); // underlines and such 489*cdf0e10cSrcweir 490*cdf0e10cSrcweir // FIXME: until hyperlinks and font effects are adjusted for 491*cdf0e10cSrcweir // geometrical search handle them before sorting 492*cdf0e10cSrcweir m_rProcessor.sortElements( &elem ); 493*cdf0e10cSrcweir 494*cdf0e10cSrcweir // find paragraphs in text 495*cdf0e10cSrcweir ParagraphElement* pCurPara = NULL; 496*cdf0e10cSrcweir std::list< Element* >::iterator page_element, next_page_element; 497*cdf0e10cSrcweir next_page_element = elem.Children.begin(); 498*cdf0e10cSrcweir double fCurLineHeight = 0.0; // average height of text items in current para 499*cdf0e10cSrcweir int nCurLineElements = 0; // number of line contributing elements in current para 500*cdf0e10cSrcweir double line_left = elem.w, line_right = 0.0; 501*cdf0e10cSrcweir double column_width = elem.w*0.75; // estimate text width 502*cdf0e10cSrcweir // TODO: guess columns 503*cdf0e10cSrcweir while( next_page_element != elem.Children.end() ) 504*cdf0e10cSrcweir { 505*cdf0e10cSrcweir page_element = next_page_element++; 506*cdf0e10cSrcweir ParagraphElement* pPagePara = dynamic_cast<ParagraphElement*>(*page_element); 507*cdf0e10cSrcweir if( pPagePara ) 508*cdf0e10cSrcweir { 509*cdf0e10cSrcweir pCurPara = pPagePara; 510*cdf0e10cSrcweir // adjust line height and text items 511*cdf0e10cSrcweir fCurLineHeight = 0.0; 512*cdf0e10cSrcweir nCurLineElements = 0; 513*cdf0e10cSrcweir for( std::list< Element* >::iterator it = pCurPara->Children.begin(); 514*cdf0e10cSrcweir it != pCurPara->Children.end(); ++it ) 515*cdf0e10cSrcweir { 516*cdf0e10cSrcweir TextElement* pTestText = dynamic_cast<TextElement*>(*it); 517*cdf0e10cSrcweir if( pTestText ) 518*cdf0e10cSrcweir { 519*cdf0e10cSrcweir fCurLineHeight = (fCurLineHeight*double(nCurLineElements) + pTestText->h)/double(nCurLineElements+1); 520*cdf0e10cSrcweir nCurLineElements++; 521*cdf0e10cSrcweir } 522*cdf0e10cSrcweir } 523*cdf0e10cSrcweir continue; 524*cdf0e10cSrcweir } 525*cdf0e10cSrcweir 526*cdf0e10cSrcweir HyperlinkElement* pLink = dynamic_cast<HyperlinkElement*>(*page_element); 527*cdf0e10cSrcweir DrawElement* pDraw = dynamic_cast<DrawElement*>(*page_element); 528*cdf0e10cSrcweir if( ! pDraw && pLink && ! pLink->Children.empty() ) 529*cdf0e10cSrcweir pDraw = dynamic_cast<DrawElement*>(pLink->Children.front() ); 530*cdf0e10cSrcweir if( pDraw ) 531*cdf0e10cSrcweir { 532*cdf0e10cSrcweir // insert small drawing objects as character, else leave them page bound 533*cdf0e10cSrcweir 534*cdf0e10cSrcweir bool bInsertToParagraph = false; 535*cdf0e10cSrcweir // first check if this is either inside the paragraph 536*cdf0e10cSrcweir if( pCurPara && pDraw->y < pCurPara->y + pCurPara->h ) 537*cdf0e10cSrcweir { 538*cdf0e10cSrcweir if( pDraw->h < fCurLineHeight * 1.5 ) 539*cdf0e10cSrcweir { 540*cdf0e10cSrcweir bInsertToParagraph = true; 541*cdf0e10cSrcweir fCurLineHeight = (fCurLineHeight*double(nCurLineElements) + pDraw->h)/double(nCurLineElements+1); 542*cdf0e10cSrcweir nCurLineElements++; 543*cdf0e10cSrcweir // mark draw element as character 544*cdf0e10cSrcweir pDraw->isCharacter = true; 545*cdf0e10cSrcweir } 546*cdf0e10cSrcweir } 547*cdf0e10cSrcweir // or perhaps the draw element begins a new paragraph 548*cdf0e10cSrcweir else if( next_page_element != elem.Children.end() ) 549*cdf0e10cSrcweir { 550*cdf0e10cSrcweir TextElement* pText = dynamic_cast<TextElement*>(*next_page_element); 551*cdf0e10cSrcweir if( ! pText ) 552*cdf0e10cSrcweir { 553*cdf0e10cSrcweir ParagraphElement* pPara = dynamic_cast<ParagraphElement*>(*next_page_element); 554*cdf0e10cSrcweir if( pPara && ! pPara->Children.empty() ) 555*cdf0e10cSrcweir pText = dynamic_cast<TextElement*>(pPara->Children.front()); 556*cdf0e10cSrcweir } 557*cdf0e10cSrcweir if( pText && // check there is a text 558*cdf0e10cSrcweir pDraw->h < pText->h*1.5 && // and it is approx the same height 559*cdf0e10cSrcweir // and either upper or lower edge of pDraw is inside text's vertical range 560*cdf0e10cSrcweir ( ( pDraw->y >= pText->y && pDraw->y <= pText->y+pText->h ) || 561*cdf0e10cSrcweir ( pDraw->y+pDraw->h >= pText->y && pDraw->y+pDraw->h <= pText->y+pText->h ) 562*cdf0e10cSrcweir ) 563*cdf0e10cSrcweir ) 564*cdf0e10cSrcweir { 565*cdf0e10cSrcweir bInsertToParagraph = true; 566*cdf0e10cSrcweir fCurLineHeight = pDraw->h; 567*cdf0e10cSrcweir nCurLineElements = 1; 568*cdf0e10cSrcweir line_left = pDraw->x; 569*cdf0e10cSrcweir line_right = pDraw->x + pDraw->w; 570*cdf0e10cSrcweir // begin a new paragraph 571*cdf0e10cSrcweir pCurPara = NULL; 572*cdf0e10cSrcweir // mark draw element as character 573*cdf0e10cSrcweir pDraw->isCharacter = true; 574*cdf0e10cSrcweir } 575*cdf0e10cSrcweir } 576*cdf0e10cSrcweir 577*cdf0e10cSrcweir if( ! bInsertToParagraph ) 578*cdf0e10cSrcweir { 579*cdf0e10cSrcweir pCurPara = NULL; 580*cdf0e10cSrcweir continue; 581*cdf0e10cSrcweir } 582*cdf0e10cSrcweir } 583*cdf0e10cSrcweir 584*cdf0e10cSrcweir TextElement* pText = dynamic_cast<TextElement*>(*page_element); 585*cdf0e10cSrcweir if( ! pText && pLink && ! pLink->Children.empty() ) 586*cdf0e10cSrcweir pText = dynamic_cast<TextElement*>(pLink->Children.front()); 587*cdf0e10cSrcweir if( pText ) 588*cdf0e10cSrcweir { 589*cdf0e10cSrcweir Element* pGeo = pLink ? static_cast<Element*>(pLink) : 590*cdf0e10cSrcweir static_cast<Element*>(pText); 591*cdf0e10cSrcweir if( pCurPara ) 592*cdf0e10cSrcweir { 593*cdf0e10cSrcweir // there was already a text element, check for a new paragraph 594*cdf0e10cSrcweir if( nCurLineElements > 0 ) 595*cdf0e10cSrcweir { 596*cdf0e10cSrcweir // if the new text is significantly distant from the paragraph 597*cdf0e10cSrcweir // begin a new paragraph 598*cdf0e10cSrcweir if( pGeo->y > pCurPara->y+pCurPara->h + fCurLineHeight*0.5 ) 599*cdf0e10cSrcweir pCurPara = NULL; // insert new paragraph 600*cdf0e10cSrcweir else if( pGeo->y > (pCurPara->y+pCurPara->h - fCurLineHeight*0.05) ) 601*cdf0e10cSrcweir { 602*cdf0e10cSrcweir // new paragraph if either the last line of the paragraph 603*cdf0e10cSrcweir // was significantly shorter than the paragraph as a whole 604*cdf0e10cSrcweir if( (line_right - line_left) < pCurPara->w*0.75 ) 605*cdf0e10cSrcweir pCurPara = NULL; 606*cdf0e10cSrcweir // or the last line was significantly smaller than the column width 607*cdf0e10cSrcweir else if( (line_right - line_left) < column_width*0.75 ) 608*cdf0e10cSrcweir pCurPara = NULL; 609*cdf0e10cSrcweir } 610*cdf0e10cSrcweir } 611*cdf0e10cSrcweir } 612*cdf0e10cSrcweir // update line height/width 613*cdf0e10cSrcweir if( pCurPara ) 614*cdf0e10cSrcweir { 615*cdf0e10cSrcweir fCurLineHeight = (fCurLineHeight*double(nCurLineElements) + pGeo->h)/double(nCurLineElements+1); 616*cdf0e10cSrcweir nCurLineElements++; 617*cdf0e10cSrcweir if( pGeo->x < line_left ) 618*cdf0e10cSrcweir line_left = pGeo->x; 619*cdf0e10cSrcweir if( pGeo->x+pGeo->w > line_right ) 620*cdf0e10cSrcweir line_right = pGeo->x+pGeo->w; 621*cdf0e10cSrcweir } 622*cdf0e10cSrcweir else 623*cdf0e10cSrcweir { 624*cdf0e10cSrcweir fCurLineHeight = pGeo->h; 625*cdf0e10cSrcweir nCurLineElements = 1; 626*cdf0e10cSrcweir line_left = pGeo->x; 627*cdf0e10cSrcweir line_right = pGeo->x + pGeo->w; 628*cdf0e10cSrcweir } 629*cdf0e10cSrcweir } 630*cdf0e10cSrcweir 631*cdf0e10cSrcweir // move element to current paragraph 632*cdf0e10cSrcweir if( ! pCurPara ) // new paragraph, insert one 633*cdf0e10cSrcweir { 634*cdf0e10cSrcweir pCurPara = m_rProcessor.getElementFactory()->createParagraphElement( NULL ); 635*cdf0e10cSrcweir // set parent 636*cdf0e10cSrcweir pCurPara->Parent = &elem; 637*cdf0e10cSrcweir //insert new paragraph before current element 638*cdf0e10cSrcweir page_element = elem.Children.insert( page_element, pCurPara ); 639*cdf0e10cSrcweir // forward iterator to current element again 640*cdf0e10cSrcweir ++ page_element; 641*cdf0e10cSrcweir // update next_element which is now invalid 642*cdf0e10cSrcweir next_page_element = page_element; 643*cdf0e10cSrcweir ++ next_page_element; 644*cdf0e10cSrcweir } 645*cdf0e10cSrcweir Element* pCurEle = *page_element; 646*cdf0e10cSrcweir pCurEle->setParent( page_element, pCurPara ); 647*cdf0e10cSrcweir OSL_ENSURE( !pText || pCurEle == pText || pCurEle == pLink, "paragraph child list in disorder" ); 648*cdf0e10cSrcweir if( pText || pDraw ) 649*cdf0e10cSrcweir pCurPara->updateGeometryWith( pCurEle ); 650*cdf0e10cSrcweir } 651*cdf0e10cSrcweir 652*cdf0e10cSrcweir // process children 653*cdf0e10cSrcweir elem.applyToChildren(*this); 654*cdf0e10cSrcweir 655*cdf0e10cSrcweir // find possible header and footer 656*cdf0e10cSrcweir checkHeaderAndFooter( elem ); 657*cdf0e10cSrcweir } 658*cdf0e10cSrcweir 659*cdf0e10cSrcweir void WriterXmlOptimizer::checkHeaderAndFooter( PageElement& rElem ) 660*cdf0e10cSrcweir { 661*cdf0e10cSrcweir /* indicators for a header: 662*cdf0e10cSrcweir * - single line paragrah at top of page ( inside 15% page height) 663*cdf0e10cSrcweir * - at least linheight above the next paragr aph 664*cdf0e10cSrcweir * 665*cdf0e10cSrcweir * indicators for a footer likewise: 666*cdf0e10cSrcweir * - single line paragraph at bottom of page (inside 15% page height) 667*cdf0e10cSrcweir * - at least lineheight below the previous paragraph 668*cdf0e10cSrcweir */ 669*cdf0e10cSrcweir 670*cdf0e10cSrcweir // detect header 671*cdf0e10cSrcweir // Note: the following assumes that the pages' chiuldren have been 672*cdf0e10cSrcweir // sorted geometrically 673*cdf0e10cSrcweir std::list< Element* >::iterator it = rElem.Children.begin(); 674*cdf0e10cSrcweir while( it != rElem.Children.end() ) 675*cdf0e10cSrcweir { 676*cdf0e10cSrcweir ParagraphElement* pPara = dynamic_cast<ParagraphElement*>(*it); 677*cdf0e10cSrcweir if( pPara ) 678*cdf0e10cSrcweir { 679*cdf0e10cSrcweir if( pPara->y+pPara->h < rElem.h*0.15 && pPara->isSingleLined( m_rProcessor ) ) 680*cdf0e10cSrcweir { 681*cdf0e10cSrcweir std::list< Element* >::iterator next_it = it; 682*cdf0e10cSrcweir ParagraphElement* pNextPara = NULL; 683*cdf0e10cSrcweir while( ++next_it != rElem.Children.end() && pNextPara == NULL ) 684*cdf0e10cSrcweir { 685*cdf0e10cSrcweir pNextPara = dynamic_cast<ParagraphElement*>(*next_it); 686*cdf0e10cSrcweir } 687*cdf0e10cSrcweir if( pNextPara && pNextPara->y > pPara->y+pPara->h*2 ) 688*cdf0e10cSrcweir { 689*cdf0e10cSrcweir rElem.HeaderElement = pPara; 690*cdf0e10cSrcweir pPara->Parent = NULL; 691*cdf0e10cSrcweir rElem.Children.remove( pPara ); 692*cdf0e10cSrcweir } 693*cdf0e10cSrcweir } 694*cdf0e10cSrcweir break; 695*cdf0e10cSrcweir } 696*cdf0e10cSrcweir ++it; 697*cdf0e10cSrcweir } 698*cdf0e10cSrcweir 699*cdf0e10cSrcweir // detect footer 700*cdf0e10cSrcweir std::list< Element* >::reverse_iterator rit = rElem.Children.rbegin(); 701*cdf0e10cSrcweir while( rit != rElem.Children.rend() ) 702*cdf0e10cSrcweir { 703*cdf0e10cSrcweir ParagraphElement* pPara = dynamic_cast<ParagraphElement*>(*rit); 704*cdf0e10cSrcweir if( pPara ) 705*cdf0e10cSrcweir { 706*cdf0e10cSrcweir if( pPara->y > rElem.h*0.85 && pPara->isSingleLined( m_rProcessor ) ) 707*cdf0e10cSrcweir { 708*cdf0e10cSrcweir std::list< Element* >::reverse_iterator next_it = rit; 709*cdf0e10cSrcweir ParagraphElement* pNextPara = NULL; 710*cdf0e10cSrcweir while( ++next_it != rElem.Children.rend() && pNextPara == NULL ) 711*cdf0e10cSrcweir { 712*cdf0e10cSrcweir pNextPara = dynamic_cast<ParagraphElement*>(*next_it); 713*cdf0e10cSrcweir } 714*cdf0e10cSrcweir if( pNextPara && pNextPara->y < pPara->y-pPara->h*2 ) 715*cdf0e10cSrcweir { 716*cdf0e10cSrcweir rElem.FooterElement = pPara; 717*cdf0e10cSrcweir pPara->Parent = NULL; 718*cdf0e10cSrcweir rElem.Children.remove( pPara ); 719*cdf0e10cSrcweir } 720*cdf0e10cSrcweir } 721*cdf0e10cSrcweir break; 722*cdf0e10cSrcweir } 723*cdf0e10cSrcweir ++rit; 724*cdf0e10cSrcweir } 725*cdf0e10cSrcweir } 726*cdf0e10cSrcweir 727*cdf0e10cSrcweir void WriterXmlOptimizer::optimizeTextElements(Element& rParent) 728*cdf0e10cSrcweir { 729*cdf0e10cSrcweir if( rParent.Children.empty() ) // this should not happen 730*cdf0e10cSrcweir { 731*cdf0e10cSrcweir OSL_ENSURE( 0, "empty paragraph optimized" ); 732*cdf0e10cSrcweir return; 733*cdf0e10cSrcweir } 734*cdf0e10cSrcweir 735*cdf0e10cSrcweir // concatenate child elements with same font id 736*cdf0e10cSrcweir std::list< Element* >::iterator next = rParent.Children.begin(); 737*cdf0e10cSrcweir std::list< Element* >::iterator it = next++; 738*cdf0e10cSrcweir FrameElement* pFrame = dynamic_cast<FrameElement*>(rParent.Parent); 739*cdf0e10cSrcweir bool bRotatedFrame = false; 740*cdf0e10cSrcweir if( pFrame ) 741*cdf0e10cSrcweir { 742*cdf0e10cSrcweir const GraphicsContext& rFrameGC = m_rProcessor.getGraphicsContext( pFrame->GCId ); 743*cdf0e10cSrcweir if( rFrameGC.isRotatedOrSkewed() ) 744*cdf0e10cSrcweir bRotatedFrame = true; 745*cdf0e10cSrcweir } 746*cdf0e10cSrcweir while( next != rParent.Children.end() ) 747*cdf0e10cSrcweir { 748*cdf0e10cSrcweir bool bConcat = false; 749*cdf0e10cSrcweir TextElement* pCur = dynamic_cast<TextElement*>(*it); 750*cdf0e10cSrcweir if( pCur ) 751*cdf0e10cSrcweir { 752*cdf0e10cSrcweir TextElement* pNext = dynamic_cast<TextElement*>(*next); 753*cdf0e10cSrcweir if( pNext ) 754*cdf0e10cSrcweir { 755*cdf0e10cSrcweir const GraphicsContext& rCurGC = m_rProcessor.getGraphicsContext( pCur->GCId ); 756*cdf0e10cSrcweir const GraphicsContext& rNextGC = m_rProcessor.getGraphicsContext( pNext->GCId ); 757*cdf0e10cSrcweir 758*cdf0e10cSrcweir // line and space optimization; works only in strictly horizontal mode 759*cdf0e10cSrcweir 760*cdf0e10cSrcweir if( !bRotatedFrame 761*cdf0e10cSrcweir && ! rCurGC.isRotatedOrSkewed() 762*cdf0e10cSrcweir && ! rNextGC.isRotatedOrSkewed() 763*cdf0e10cSrcweir && pNext->Text.charAt( 0 ) != sal_Unicode(' ') 764*cdf0e10cSrcweir && pCur->Text.getLength() > 0 765*cdf0e10cSrcweir && pCur->Text.charAt( pCur->Text.getLength()-1 ) != sal_Unicode(' ') 766*cdf0e10cSrcweir ) 767*cdf0e10cSrcweir { 768*cdf0e10cSrcweir // check for new line in paragraph 769*cdf0e10cSrcweir if( pNext->y > pCur->y+pCur->h ) 770*cdf0e10cSrcweir { 771*cdf0e10cSrcweir // new line begins 772*cdf0e10cSrcweir // check whether a space would should be inserted or a hyphen removed 773*cdf0e10cSrcweir sal_Unicode aLastCode = pCur->Text.charAt( pCur->Text.getLength()-1 ); 774*cdf0e10cSrcweir if( aLastCode == '-' 775*cdf0e10cSrcweir || aLastCode == 0x2010 776*cdf0e10cSrcweir || (aLastCode >= 0x2012 && aLastCode <= 0x2015) 777*cdf0e10cSrcweir || aLastCode == 0xff0d 778*cdf0e10cSrcweir ) 779*cdf0e10cSrcweir { 780*cdf0e10cSrcweir // cut a hyphen 781*cdf0e10cSrcweir pCur->Text.setLength( pCur->Text.getLength()-1 ); 782*cdf0e10cSrcweir } 783*cdf0e10cSrcweir // append a space unless there is a non breaking hyphen 784*cdf0e10cSrcweir else if( aLastCode != 0x2011 ) 785*cdf0e10cSrcweir { 786*cdf0e10cSrcweir pCur->Text.append( sal_Unicode( ' ' ) ); 787*cdf0e10cSrcweir } 788*cdf0e10cSrcweir } 789*cdf0e10cSrcweir else // we're continuing the same line 790*cdf0e10cSrcweir { 791*cdf0e10cSrcweir // check whether a space would should be inserted 792*cdf0e10cSrcweir // check for a small horizontal offset 793*cdf0e10cSrcweir if( pCur->x + pCur->w + pNext->h*0.15 < pNext->x ) 794*cdf0e10cSrcweir { 795*cdf0e10cSrcweir pCur->Text.append( sal_Unicode(' ') ); 796*cdf0e10cSrcweir } 797*cdf0e10cSrcweir } 798*cdf0e10cSrcweir } 799*cdf0e10cSrcweir // concatenate consecutive text elements unless there is a 800*cdf0e10cSrcweir // font or text color or matrix change, leave a new span in that case 801*cdf0e10cSrcweir if( pCur->FontId == pNext->FontId && 802*cdf0e10cSrcweir rCurGC.FillColor.Red == rNextGC.FillColor.Red && 803*cdf0e10cSrcweir rCurGC.FillColor.Green == rNextGC.FillColor.Green && 804*cdf0e10cSrcweir rCurGC.FillColor.Blue == rNextGC.FillColor.Blue && 805*cdf0e10cSrcweir rCurGC.FillColor.Alpha == rNextGC.FillColor.Alpha && 806*cdf0e10cSrcweir rCurGC.Transformation == rNextGC.Transformation 807*cdf0e10cSrcweir ) 808*cdf0e10cSrcweir { 809*cdf0e10cSrcweir pCur->updateGeometryWith( pNext ); 810*cdf0e10cSrcweir // append text to current element 811*cdf0e10cSrcweir pCur->Text.append( pNext->Text.getStr(), pNext->Text.getLength() ); 812*cdf0e10cSrcweir // append eventual children to current element 813*cdf0e10cSrcweir // and clear children (else the children just 814*cdf0e10cSrcweir // appended to pCur would be destroyed) 815*cdf0e10cSrcweir pCur->Children.splice( pCur->Children.end(), pNext->Children ); 816*cdf0e10cSrcweir // get rid of the now useless element 817*cdf0e10cSrcweir rParent.Children.erase( next ); 818*cdf0e10cSrcweir delete pNext; 819*cdf0e10cSrcweir bConcat = true; 820*cdf0e10cSrcweir } 821*cdf0e10cSrcweir } 822*cdf0e10cSrcweir } 823*cdf0e10cSrcweir else if( dynamic_cast<HyperlinkElement*>(*it) ) 824*cdf0e10cSrcweir optimizeTextElements( **it ); 825*cdf0e10cSrcweir if( bConcat ) 826*cdf0e10cSrcweir { 827*cdf0e10cSrcweir next = it; 828*cdf0e10cSrcweir ++next; 829*cdf0e10cSrcweir } 830*cdf0e10cSrcweir else 831*cdf0e10cSrcweir { 832*cdf0e10cSrcweir ++it; 833*cdf0e10cSrcweir ++next; 834*cdf0e10cSrcweir } 835*cdf0e10cSrcweir } 836*cdf0e10cSrcweir } 837*cdf0e10cSrcweir 838*cdf0e10cSrcweir void WriterXmlOptimizer::visit( DocumentElement& elem, const std::list< Element* >::const_iterator&) 839*cdf0e10cSrcweir { 840*cdf0e10cSrcweir elem.applyToChildren(*this); 841*cdf0e10cSrcweir } 842*cdf0e10cSrcweir 843*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////////// 844*cdf0e10cSrcweir 845*cdf0e10cSrcweir 846*cdf0e10cSrcweir void WriterXmlFinalizer::visit( PolyPolyElement& elem, const std::list< Element* >::const_iterator& ) 847*cdf0e10cSrcweir { 848*cdf0e10cSrcweir // xxx TODO copied from DrawElement 849*cdf0e10cSrcweir const GraphicsContext& rGC = m_rProcessor.getGraphicsContext(elem.GCId ); 850*cdf0e10cSrcweir PropertyMap aProps; 851*cdf0e10cSrcweir aProps[ USTR( "style:family" ) ] = USTR( "graphic" ); 852*cdf0e10cSrcweir 853*cdf0e10cSrcweir PropertyMap aGCProps; 854*cdf0e10cSrcweir 855*cdf0e10cSrcweir // TODO(F3): proper dash emulation 856*cdf0e10cSrcweir if( elem.Action & PATH_STROKE ) 857*cdf0e10cSrcweir { 858*cdf0e10cSrcweir aGCProps[ USTR("draw:stroke") ] = rGC.DashArray.empty() ? USTR("solid") : USTR("dash"); 859*cdf0e10cSrcweir aGCProps[ USTR("svg:stroke-color") ] = getColorString( rGC.LineColor ); 860*cdf0e10cSrcweir if( rGC.LineWidth != 0.0 ) 861*cdf0e10cSrcweir { 862*cdf0e10cSrcweir ::basegfx::B2DVector aVec(rGC.LineWidth,0); 863*cdf0e10cSrcweir aVec *= rGC.Transformation; 864*cdf0e10cSrcweir 865*cdf0e10cSrcweir aVec.setX ( convPx2mmPrec2( aVec.getX() )*100.0 ); 866*cdf0e10cSrcweir aVec.setY ( convPx2mmPrec2( aVec.getY() )*100.0 ); 867*cdf0e10cSrcweir 868*cdf0e10cSrcweir aGCProps[ USTR("svg:stroke-width") ] = rtl::OUString::valueOf( aVec.getLength() ); 869*cdf0e10cSrcweir } 870*cdf0e10cSrcweir } 871*cdf0e10cSrcweir else 872*cdf0e10cSrcweir { 873*cdf0e10cSrcweir aGCProps[ USTR("draw:stroke") ] = USTR("none"); 874*cdf0e10cSrcweir } 875*cdf0e10cSrcweir 876*cdf0e10cSrcweir // TODO(F1): check whether stuff could be emulated by gradient/bitmap/hatch 877*cdf0e10cSrcweir if( elem.Action & (PATH_FILL | PATH_EOFILL) ) 878*cdf0e10cSrcweir { 879*cdf0e10cSrcweir aGCProps[ USTR("draw:fill") ] = USTR("solid"); 880*cdf0e10cSrcweir aGCProps[ USTR("draw:fill-color") ] = getColorString( rGC.FillColor ); 881*cdf0e10cSrcweir } 882*cdf0e10cSrcweir else 883*cdf0e10cSrcweir { 884*cdf0e10cSrcweir aGCProps[ USTR("draw:fill") ] = USTR("none"); 885*cdf0e10cSrcweir } 886*cdf0e10cSrcweir 887*cdf0e10cSrcweir StyleContainer::Style aStyle( "style:style", aProps ); 888*cdf0e10cSrcweir StyleContainer::Style aSubStyle( "style:graphic-properties", aGCProps ); 889*cdf0e10cSrcweir aStyle.SubStyles.push_back( &aSubStyle ); 890*cdf0e10cSrcweir 891*cdf0e10cSrcweir elem.StyleId = m_rStyleContainer.getStyleId( aStyle ); 892*cdf0e10cSrcweir } 893*cdf0e10cSrcweir 894*cdf0e10cSrcweir void WriterXmlFinalizer::visit( HyperlinkElement&, const std::list< Element* >::const_iterator& ) 895*cdf0e10cSrcweir { 896*cdf0e10cSrcweir } 897*cdf0e10cSrcweir 898*cdf0e10cSrcweir void WriterXmlFinalizer::visit( TextElement& elem, const std::list< Element* >::const_iterator& ) 899*cdf0e10cSrcweir { 900*cdf0e10cSrcweir const FontAttributes& rFont = m_rProcessor.getFont( elem.FontId ); 901*cdf0e10cSrcweir PropertyMap aProps; 902*cdf0e10cSrcweir aProps[ USTR( "style:family" ) ] = USTR( "text" ); 903*cdf0e10cSrcweir 904*cdf0e10cSrcweir PropertyMap aFontProps; 905*cdf0e10cSrcweir 906*cdf0e10cSrcweir // family name 907*cdf0e10cSrcweir aFontProps[ USTR( "fo:font-family" ) ] = rFont.familyName; 908*cdf0e10cSrcweir // bold 909*cdf0e10cSrcweir if( rFont.isBold ) 910*cdf0e10cSrcweir { 911*cdf0e10cSrcweir aFontProps[ USTR( "fo:font-weight" ) ] = USTR( "bold" ); 912*cdf0e10cSrcweir aFontProps[ USTR( "fo:font-weight-asian" ) ] = USTR( "bold" ); 913*cdf0e10cSrcweir aFontProps[ USTR( "fo:font-weight-complex" ) ] = USTR( "bold" ); 914*cdf0e10cSrcweir } 915*cdf0e10cSrcweir // italic 916*cdf0e10cSrcweir if( rFont.isItalic ) 917*cdf0e10cSrcweir { 918*cdf0e10cSrcweir aFontProps[ USTR( "fo:font-style" ) ] = USTR( "italic" ); 919*cdf0e10cSrcweir aFontProps[ USTR( "fo:font-style-asian" ) ] = USTR( "italic" ); 920*cdf0e10cSrcweir aFontProps[ USTR( "fo:font-style-complex" ) ] = USTR( "italic" ); 921*cdf0e10cSrcweir } 922*cdf0e10cSrcweir // underline 923*cdf0e10cSrcweir if( rFont.isUnderline ) 924*cdf0e10cSrcweir { 925*cdf0e10cSrcweir aFontProps[ USTR( "style:text-underline-style" ) ] = USTR( "solid" ); 926*cdf0e10cSrcweir aFontProps[ USTR( "style:text-underline-width" ) ] = USTR( "auto" ); 927*cdf0e10cSrcweir aFontProps[ USTR( "style:text-underline-color" ) ] = USTR( "font-color" ); 928*cdf0e10cSrcweir } 929*cdf0e10cSrcweir // outline 930*cdf0e10cSrcweir if( rFont.isOutline ) 931*cdf0e10cSrcweir { 932*cdf0e10cSrcweir aFontProps[ USTR( "style:text-outline" ) ] = USTR( "true" ); 933*cdf0e10cSrcweir } 934*cdf0e10cSrcweir // size 935*cdf0e10cSrcweir rtl::OUStringBuffer aBuf( 32 ); 936*cdf0e10cSrcweir aBuf.append( rFont.size*72/PDFI_OUTDEV_RESOLUTION ); 937*cdf0e10cSrcweir aBuf.appendAscii( "pt" ); 938*cdf0e10cSrcweir rtl::OUString aFSize = aBuf.makeStringAndClear(); 939*cdf0e10cSrcweir aFontProps[ USTR( "fo:font-size" ) ] = aFSize; 940*cdf0e10cSrcweir aFontProps[ USTR( "style:font-size-asian" ) ] = aFSize; 941*cdf0e10cSrcweir aFontProps[ USTR( "style:font-size-complex" ) ] = aFSize; 942*cdf0e10cSrcweir // color 943*cdf0e10cSrcweir const GraphicsContext& rGC = m_rProcessor.getGraphicsContext( elem.GCId ); 944*cdf0e10cSrcweir aFontProps[ USTR( "fo:color" ) ] = getColorString( rFont.isOutline ? rGC.LineColor : rGC.FillColor ); 945*cdf0e10cSrcweir 946*cdf0e10cSrcweir StyleContainer::Style aStyle( "style:style", aProps ); 947*cdf0e10cSrcweir StyleContainer::Style aSubStyle( "style:text-properties", aFontProps ); 948*cdf0e10cSrcweir aStyle.SubStyles.push_back( &aSubStyle ); 949*cdf0e10cSrcweir elem.StyleId = m_rStyleContainer.getStyleId( aStyle ); 950*cdf0e10cSrcweir } 951*cdf0e10cSrcweir 952*cdf0e10cSrcweir void WriterXmlFinalizer::visit( ParagraphElement& elem, const std::list< Element* >::const_iterator& rParentIt ) 953*cdf0e10cSrcweir { 954*cdf0e10cSrcweir PropertyMap aParaProps; 955*cdf0e10cSrcweir 956*cdf0e10cSrcweir if( elem.Parent ) 957*cdf0e10cSrcweir { 958*cdf0e10cSrcweir // check for center alignement 959*cdf0e10cSrcweir // criterion: paragraph is small relative to parent and distributed around its center 960*cdf0e10cSrcweir double p_x = elem.Parent->x; 961*cdf0e10cSrcweir double p_y = elem.Parent->y; 962*cdf0e10cSrcweir double p_w = elem.Parent->w; 963*cdf0e10cSrcweir double p_h = elem.Parent->h; 964*cdf0e10cSrcweir 965*cdf0e10cSrcweir PageElement* pPage = dynamic_cast<PageElement*>(elem.Parent); 966*cdf0e10cSrcweir if( pPage ) 967*cdf0e10cSrcweir { 968*cdf0e10cSrcweir p_x += pPage->LeftMargin; 969*cdf0e10cSrcweir p_y += pPage->TopMargin; 970*cdf0e10cSrcweir p_w -= pPage->LeftMargin+pPage->RightMargin; 971*cdf0e10cSrcweir p_h -= pPage->TopMargin+pPage->BottomMargin; 972*cdf0e10cSrcweir } 973*cdf0e10cSrcweir bool bIsCenter = false; 974*cdf0e10cSrcweir if( elem.w < ( p_w/2) ) 975*cdf0e10cSrcweir { 976*cdf0e10cSrcweir double delta = elem.w/4; 977*cdf0e10cSrcweir // allow very small paragraphs to deviate a little more 978*cdf0e10cSrcweir // relative to parent's center 979*cdf0e10cSrcweir if( elem.w < p_w/8 ) 980*cdf0e10cSrcweir delta = elem.w; 981*cdf0e10cSrcweir if( fabs( elem.x+elem.w/2 - ( p_x+ p_w/2) ) < delta || 982*cdf0e10cSrcweir (pPage && fabs( elem.x+elem.w/2 - (pPage->x + pPage->w/2) ) < delta) ) 983*cdf0e10cSrcweir { 984*cdf0e10cSrcweir bIsCenter = true; 985*cdf0e10cSrcweir aParaProps[ USTR( "fo:text-align" ) ] = USTR( "center" ); 986*cdf0e10cSrcweir } 987*cdf0e10cSrcweir } 988*cdf0e10cSrcweir if( ! bIsCenter && elem.x > p_x + p_w/10 ) 989*cdf0e10cSrcweir { 990*cdf0e10cSrcweir // indent 991*cdf0e10cSrcweir rtl::OUStringBuffer aBuf( 32 ); 992*cdf0e10cSrcweir aBuf.append( convPx2mm( elem.x - p_x ) ); 993*cdf0e10cSrcweir aBuf.appendAscii( "mm" ); 994*cdf0e10cSrcweir aParaProps[ USTR( "fo:margin-left" ) ] = aBuf.makeStringAndClear(); 995*cdf0e10cSrcweir } 996*cdf0e10cSrcweir 997*cdf0e10cSrcweir // check whether to leave some space to next paragraph 998*cdf0e10cSrcweir // find wether there is a next paragraph 999*cdf0e10cSrcweir std::list< Element* >::const_iterator it = rParentIt; 1000*cdf0e10cSrcweir const ParagraphElement* pNextPara = NULL; 1001*cdf0e10cSrcweir while( ++it != elem.Parent->Children.end() && ! pNextPara ) 1002*cdf0e10cSrcweir pNextPara = dynamic_cast< const ParagraphElement* >(*it); 1003*cdf0e10cSrcweir if( pNextPara ) 1004*cdf0e10cSrcweir { 1005*cdf0e10cSrcweir if( pNextPara->y - (elem.y+elem.h) > convmm2Px( 10 ) ) 1006*cdf0e10cSrcweir { 1007*cdf0e10cSrcweir rtl::OUStringBuffer aBuf( 32 ); 1008*cdf0e10cSrcweir aBuf.append( convPx2mm( pNextPara->y - (elem.y+elem.h) ) ); 1009*cdf0e10cSrcweir aBuf.appendAscii( "mm" ); 1010*cdf0e10cSrcweir aParaProps[ USTR( "fo:margin-bottom" ) ] = aBuf.makeStringAndClear(); 1011*cdf0e10cSrcweir } 1012*cdf0e10cSrcweir } 1013*cdf0e10cSrcweir } 1014*cdf0e10cSrcweir 1015*cdf0e10cSrcweir if( ! aParaProps.empty() ) 1016*cdf0e10cSrcweir { 1017*cdf0e10cSrcweir PropertyMap aProps; 1018*cdf0e10cSrcweir aProps[ USTR( "style:family" ) ] = USTR( "paragraph" ); 1019*cdf0e10cSrcweir StyleContainer::Style aStyle( "style:style", aProps ); 1020*cdf0e10cSrcweir StyleContainer::Style aSubStyle( "style:paragraph-properties", aParaProps ); 1021*cdf0e10cSrcweir aStyle.SubStyles.push_back( &aSubStyle ); 1022*cdf0e10cSrcweir elem.StyleId = m_rStyleContainer.getStyleId( aStyle ); 1023*cdf0e10cSrcweir } 1024*cdf0e10cSrcweir 1025*cdf0e10cSrcweir elem.applyToChildren(*this); 1026*cdf0e10cSrcweir } 1027*cdf0e10cSrcweir 1028*cdf0e10cSrcweir void WriterXmlFinalizer::visit( FrameElement& elem, const std::list< Element* >::const_iterator&) 1029*cdf0e10cSrcweir { 1030*cdf0e10cSrcweir PropertyMap aProps; 1031*cdf0e10cSrcweir aProps[ USTR( "style:family" ) ] = USTR( "graphic" ); 1032*cdf0e10cSrcweir 1033*cdf0e10cSrcweir PropertyMap aGCProps; 1034*cdf0e10cSrcweir 1035*cdf0e10cSrcweir aGCProps[ USTR("draw:stroke") ] = USTR("none"); 1036*cdf0e10cSrcweir aGCProps[ USTR("draw:fill") ] = USTR("none"); 1037*cdf0e10cSrcweir 1038*cdf0e10cSrcweir StyleContainer::Style aStyle( "style:style", aProps ); 1039*cdf0e10cSrcweir StyleContainer::Style aSubStyle( "style:graphic-properties", aGCProps ); 1040*cdf0e10cSrcweir aStyle.SubStyles.push_back( &aSubStyle ); 1041*cdf0e10cSrcweir 1042*cdf0e10cSrcweir elem.StyleId = m_rStyleContainer.getStyleId( aStyle ); 1043*cdf0e10cSrcweir elem.applyToChildren(*this); 1044*cdf0e10cSrcweir } 1045*cdf0e10cSrcweir 1046*cdf0e10cSrcweir void WriterXmlFinalizer::visit( ImageElement&, const std::list< Element* >::const_iterator& ) 1047*cdf0e10cSrcweir { 1048*cdf0e10cSrcweir } 1049*cdf0e10cSrcweir 1050*cdf0e10cSrcweir void WriterXmlFinalizer::setFirstOnPage( ParagraphElement& rElem, 1051*cdf0e10cSrcweir StyleContainer& rStyles, 1052*cdf0e10cSrcweir const rtl::OUString& rMasterPageName ) 1053*cdf0e10cSrcweir { 1054*cdf0e10cSrcweir PropertyMap aProps; 1055*cdf0e10cSrcweir if( rElem.StyleId != -1 ) 1056*cdf0e10cSrcweir { 1057*cdf0e10cSrcweir const PropertyMap* pProps = rStyles.getProperties( rElem.StyleId ); 1058*cdf0e10cSrcweir if( pProps ) 1059*cdf0e10cSrcweir aProps = *pProps; 1060*cdf0e10cSrcweir } 1061*cdf0e10cSrcweir 1062*cdf0e10cSrcweir aProps[ USTR( "style:family" ) ] = USTR( "paragraph" ); 1063*cdf0e10cSrcweir aProps[ USTR( "style:master-page-name" ) ] = rMasterPageName; 1064*cdf0e10cSrcweir 1065*cdf0e10cSrcweir if( rElem.StyleId != -1 ) 1066*cdf0e10cSrcweir rElem.StyleId = rStyles.setProperties( rElem.StyleId, aProps ); 1067*cdf0e10cSrcweir else 1068*cdf0e10cSrcweir { 1069*cdf0e10cSrcweir StyleContainer::Style aStyle( "style:style", aProps ); 1070*cdf0e10cSrcweir rElem.StyleId = rStyles.getStyleId( aStyle ); 1071*cdf0e10cSrcweir } 1072*cdf0e10cSrcweir } 1073*cdf0e10cSrcweir 1074*cdf0e10cSrcweir void WriterXmlFinalizer::visit( PageElement& elem, const std::list< Element* >::const_iterator& ) 1075*cdf0e10cSrcweir { 1076*cdf0e10cSrcweir if( m_rProcessor.getStatusIndicator().is() ) 1077*cdf0e10cSrcweir m_rProcessor.getStatusIndicator()->setValue( elem.PageNumber ); 1078*cdf0e10cSrcweir 1079*cdf0e10cSrcweir // transform from pixel to mm 1080*cdf0e10cSrcweir double page_width = convPx2mm( elem.w ), page_height = convPx2mm( elem.h ); 1081*cdf0e10cSrcweir 1082*cdf0e10cSrcweir // calculate page margins out of the relevant children (paragraphs) 1083*cdf0e10cSrcweir elem.TopMargin = elem.h, elem.BottomMargin = 0, elem.LeftMargin = elem.w, elem.RightMargin = 0; 1084*cdf0e10cSrcweir // first element should be a paragraphy 1085*cdf0e10cSrcweir ParagraphElement* pFirstPara = NULL; 1086*cdf0e10cSrcweir for( std::list< Element* >::const_iterator it = elem.Children.begin(); it != elem.Children.end(); ++it ) 1087*cdf0e10cSrcweir { 1088*cdf0e10cSrcweir if( dynamic_cast<ParagraphElement*>( *it ) ) 1089*cdf0e10cSrcweir { 1090*cdf0e10cSrcweir if( (*it)->x < elem.LeftMargin ) 1091*cdf0e10cSrcweir elem.LeftMargin = (*it)->x; 1092*cdf0e10cSrcweir if( (*it)->y < elem.TopMargin ) 1093*cdf0e10cSrcweir elem.TopMargin = (*it)->y; 1094*cdf0e10cSrcweir if( (*it)->x + (*it)->w > elem.w - elem.RightMargin ) 1095*cdf0e10cSrcweir elem.RightMargin = elem.w - ((*it)->x + (*it)->w); 1096*cdf0e10cSrcweir if( (*it)->y + (*it)->h > elem.h - elem.BottomMargin ) 1097*cdf0e10cSrcweir elem.BottomMargin = elem.h - ((*it)->y + (*it)->h); 1098*cdf0e10cSrcweir if( ! pFirstPara ) 1099*cdf0e10cSrcweir pFirstPara = dynamic_cast<ParagraphElement*>( *it ); 1100*cdf0e10cSrcweir } 1101*cdf0e10cSrcweir } 1102*cdf0e10cSrcweir if( elem.HeaderElement && elem.HeaderElement->y < elem.TopMargin ) 1103*cdf0e10cSrcweir elem.TopMargin = elem.HeaderElement->y; 1104*cdf0e10cSrcweir if( elem.FooterElement && elem.FooterElement->y+elem.FooterElement->h > elem.h - elem.BottomMargin ) 1105*cdf0e10cSrcweir elem.BottomMargin = elem.h - (elem.FooterElement->y + elem.FooterElement->h); 1106*cdf0e10cSrcweir 1107*cdf0e10cSrcweir // transform margins to mm 1108*cdf0e10cSrcweir double left_margin = convPx2mm( elem.LeftMargin ); 1109*cdf0e10cSrcweir double right_margin = convPx2mm( elem.RightMargin ); 1110*cdf0e10cSrcweir double top_margin = convPx2mm( elem.TopMargin ); 1111*cdf0e10cSrcweir double bottom_margin = convPx2mm( elem.BottomMargin ); 1112*cdf0e10cSrcweir if( ! pFirstPara ) 1113*cdf0e10cSrcweir { 1114*cdf0e10cSrcweir // use default page margins 1115*cdf0e10cSrcweir left_margin = 10; 1116*cdf0e10cSrcweir right_margin = 10; 1117*cdf0e10cSrcweir top_margin = 10; 1118*cdf0e10cSrcweir bottom_margin = 10; 1119*cdf0e10cSrcweir } 1120*cdf0e10cSrcweir 1121*cdf0e10cSrcweir // round left/top margin to nearest mm 1122*cdf0e10cSrcweir left_margin = rtl_math_round( left_margin, 0, rtl_math_RoundingMode_Floor ); 1123*cdf0e10cSrcweir top_margin = rtl_math_round( top_margin, 0, rtl_math_RoundingMode_Floor ); 1124*cdf0e10cSrcweir // round (fuzzy) right/bottom margin to nearest cm 1125*cdf0e10cSrcweir right_margin = rtl_math_round( right_margin, right_margin >= 10 ? -1 : 0, rtl_math_RoundingMode_Floor ); 1126*cdf0e10cSrcweir bottom_margin = rtl_math_round( bottom_margin, bottom_margin >= 10 ? -1 : 0, rtl_math_RoundingMode_Floor ); 1127*cdf0e10cSrcweir 1128*cdf0e10cSrcweir // set reasonable default in case of way too large margins 1129*cdf0e10cSrcweir // e.g. no paragraph case 1130*cdf0e10cSrcweir if( left_margin > page_width/2.0 - 10 ) 1131*cdf0e10cSrcweir left_margin = 10; 1132*cdf0e10cSrcweir if( right_margin > page_width/2.0 - 10 ) 1133*cdf0e10cSrcweir right_margin = 10; 1134*cdf0e10cSrcweir if( top_margin > page_height/2.0 - 10 ) 1135*cdf0e10cSrcweir top_margin = 10; 1136*cdf0e10cSrcweir if( bottom_margin > page_height/2.0 - 10 ) 1137*cdf0e10cSrcweir bottom_margin = 10; 1138*cdf0e10cSrcweir 1139*cdf0e10cSrcweir // catch the weird cases 1140*cdf0e10cSrcweir if( left_margin < 0 ) 1141*cdf0e10cSrcweir left_margin = 0; 1142*cdf0e10cSrcweir if( right_margin < 0 ) 1143*cdf0e10cSrcweir right_margin = 0; 1144*cdf0e10cSrcweir if( top_margin < 0 ) 1145*cdf0e10cSrcweir top_margin = 0; 1146*cdf0e10cSrcweir if( bottom_margin < 0 ) 1147*cdf0e10cSrcweir bottom_margin = 0; 1148*cdf0e10cSrcweir 1149*cdf0e10cSrcweir // widely differing margins are unlikely to be correct 1150*cdf0e10cSrcweir if( right_margin > left_margin*1.5 ) 1151*cdf0e10cSrcweir right_margin = left_margin; 1152*cdf0e10cSrcweir 1153*cdf0e10cSrcweir elem.LeftMargin = convmm2Px( left_margin ); 1154*cdf0e10cSrcweir elem.RightMargin = convmm2Px( right_margin ); 1155*cdf0e10cSrcweir elem.TopMargin = convmm2Px( top_margin ); 1156*cdf0e10cSrcweir elem.BottomMargin = convmm2Px( bottom_margin ); 1157*cdf0e10cSrcweir 1158*cdf0e10cSrcweir // get styles for paragraphs 1159*cdf0e10cSrcweir PropertyMap aPageProps; 1160*cdf0e10cSrcweir PropertyMap aPageLayoutProps; 1161*cdf0e10cSrcweir rtl::OUStringBuffer aBuf( 64 ); 1162*cdf0e10cSrcweir aPageLayoutProps[ USTR( "fo:page-width" ) ] = unitMMString( page_width ); 1163*cdf0e10cSrcweir aPageLayoutProps[ USTR( "fo:page-height" ) ] = unitMMString( page_height ); 1164*cdf0e10cSrcweir aPageLayoutProps[ USTR( "style:print-orientation" ) ] 1165*cdf0e10cSrcweir = elem.w < elem.h ? USTR( "portrait" ) : USTR( "landscape" ); 1166*cdf0e10cSrcweir aPageLayoutProps[ USTR( "fo:margin-top" ) ] = unitMMString( top_margin ); 1167*cdf0e10cSrcweir aPageLayoutProps[ USTR( "fo:margin-bottom" ) ] = unitMMString( bottom_margin ); 1168*cdf0e10cSrcweir aPageLayoutProps[ USTR( "fo:margin-left" ) ] = unitMMString( left_margin ); 1169*cdf0e10cSrcweir aPageLayoutProps[ USTR( "fo:margin-right" ) ] = unitMMString( right_margin ); 1170*cdf0e10cSrcweir aPageLayoutProps[ USTR( "style:writing-mode" ) ]= USTR( "lr-tb" ); 1171*cdf0e10cSrcweir 1172*cdf0e10cSrcweir StyleContainer::Style aStyle( "style:page-layout", aPageProps); 1173*cdf0e10cSrcweir StyleContainer::Style aSubStyle( "style:page-layout-properties", aPageLayoutProps); 1174*cdf0e10cSrcweir aStyle.SubStyles.push_back(&aSubStyle); 1175*cdf0e10cSrcweir sal_Int32 nPageStyle = m_rStyleContainer.impl_getStyleId( aStyle, false ); 1176*cdf0e10cSrcweir 1177*cdf0e10cSrcweir // create master page 1178*cdf0e10cSrcweir rtl::OUString aMasterPageLayoutName = m_rStyleContainer.getStyleName( nPageStyle ); 1179*cdf0e10cSrcweir aPageProps[ USTR( "style:page-layout-name" ) ] = aMasterPageLayoutName; 1180*cdf0e10cSrcweir StyleContainer::Style aMPStyle( "style:master-page", aPageProps ); 1181*cdf0e10cSrcweir StyleContainer::Style aHeaderStyle( "style:header", PropertyMap() ); 1182*cdf0e10cSrcweir StyleContainer::Style aFooterStyle( "style:footer", PropertyMap() ); 1183*cdf0e10cSrcweir if( elem.HeaderElement ) 1184*cdf0e10cSrcweir { 1185*cdf0e10cSrcweir elem.HeaderElement->visitedBy( *this, std::list<Element*>::iterator() ); 1186*cdf0e10cSrcweir aHeaderStyle.ContainedElement = elem.HeaderElement; 1187*cdf0e10cSrcweir aMPStyle.SubStyles.push_back( &aHeaderStyle ); 1188*cdf0e10cSrcweir } 1189*cdf0e10cSrcweir if( elem.FooterElement ) 1190*cdf0e10cSrcweir { 1191*cdf0e10cSrcweir elem.FooterElement->visitedBy( *this, std::list<Element*>::iterator() ); 1192*cdf0e10cSrcweir aFooterStyle.ContainedElement = elem.FooterElement; 1193*cdf0e10cSrcweir aMPStyle.SubStyles.push_back( &aFooterStyle ); 1194*cdf0e10cSrcweir } 1195*cdf0e10cSrcweir elem.StyleId = m_rStyleContainer.impl_getStyleId( aMPStyle,false ); 1196*cdf0e10cSrcweir 1197*cdf0e10cSrcweir 1198*cdf0e10cSrcweir rtl::OUString aMasterPageName = m_rStyleContainer.getStyleName( elem.StyleId ); 1199*cdf0e10cSrcweir 1200*cdf0e10cSrcweir // create styles for children 1201*cdf0e10cSrcweir elem.applyToChildren(*this); 1202*cdf0e10cSrcweir 1203*cdf0e10cSrcweir // no paragraph or other elements before the first paragraph 1204*cdf0e10cSrcweir if( ! pFirstPara ) 1205*cdf0e10cSrcweir { 1206*cdf0e10cSrcweir pFirstPara = m_rProcessor.getElementFactory()->createParagraphElement( NULL ); 1207*cdf0e10cSrcweir pFirstPara->Parent = &elem; 1208*cdf0e10cSrcweir elem.Children.push_front( pFirstPara ); 1209*cdf0e10cSrcweir } 1210*cdf0e10cSrcweir setFirstOnPage(*pFirstPara, m_rStyleContainer, aMasterPageName); 1211*cdf0e10cSrcweir } 1212*cdf0e10cSrcweir 1213*cdf0e10cSrcweir void WriterXmlFinalizer::visit( DocumentElement& elem, const std::list< Element* >::const_iterator& ) 1214*cdf0e10cSrcweir { 1215*cdf0e10cSrcweir elem.applyToChildren(*this); 1216*cdf0e10cSrcweir } 1217*cdf0e10cSrcweir 1218*cdf0e10cSrcweir } 1219