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