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