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 1503 : const Reference< XBreakIterator >& DrawXmlOptimizer::GetBreakIterator()
51 : {
52 1503 : if ( !mxBreakIter.is() )
53 : {
54 1 : Reference< XComponentContext > xContext( this->m_rProcessor.m_xContext, uno::UNO_SET_THROW );
55 1 : mxBreakIter = BreakIterator::create(xContext);
56 : }
57 1503 : return mxBreakIter;
58 : }
59 :
60 11 : const Reference< XCharacterClassification >& DrawXmlEmitter::GetCharacterClassification()
61 : {
62 11 : if ( !mxCharClass.is() )
63 : {
64 1 : Reference< XComponentContext > xContext( m_rEmitContext.m_xContext, uno::UNO_SET_THROW );
65 1 : mxCharClass = CharacterClassification::create(xContext);
66 : }
67 11 : 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 11 : void DrawXmlEmitter::visit( TextElement& elem, const std::list< Element* >::const_iterator& )
94 : {
95 11 : if( ! elem.Text.getLength() )
96 11 : return;
97 :
98 11 : rtl::OUString strSpace(32);
99 11 : rtl::OUString strNbSpace(160);
100 11 : rtl::OUString tabSpace(0x09);
101 11 : PropertyMap aProps;
102 11 : if( elem.StyleId != -1 )
103 : {
104 22 : aProps[ rtl::OUString( "text:style-name" ) ] =
105 33 : m_rEmitContext.rStyles.getStyleName( elem.StyleId );
106 : }
107 :
108 11 : rtl::OUString str(elem.Text.getStr());
109 :
110 : // Check for RTL
111 11 : bool isRTL = false;
112 11 : Reference< i18n::XCharacterClassification > xCC( GetCharacterClassification() );
113 11 : if( xCC.is() )
114 : {
115 104 : for(int i=1; i< elem.Text.getLength(); i++)
116 : {
117 93 : sal_Int16 nType = xCC->getCharacterDirection( str, i );
118 93 : 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 11 : if (isRTL) // If so, reverse string
128 0 : str = m_rProcessor.mirrorString( str );
129 :
130 11 : m_rEmitContext.rEmitter.beginTag( "text:span", aProps );
131 :
132 115 : for(int i=0; i< elem.Text.getLength(); i++)
133 : {
134 104 : rtl::OUString strToken= str.copy(i,1) ;
135 104 : if( strSpace.equals(strToken) || strNbSpace.equals(strToken))
136 : {
137 14 : aProps[ USTR( "text:c" ) ] = USTR( "1" );
138 14 : m_rEmitContext.rEmitter.beginTag( "text:s", aProps );
139 14 : m_rEmitContext.rEmitter.endTag( "text:s");
140 : }
141 : else
142 : {
143 90 : 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 90 : m_rEmitContext.rEmitter.write( strToken );
151 : }
152 : }
153 104 : }
154 :
155 11 : std::list< Element* >::iterator this_it = elem.Children.begin();
156 22 : 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 11 : m_rEmitContext.rEmitter.endTag( "text:span" );
163 : }
164 :
165 11 : void DrawXmlEmitter::visit( ParagraphElement& elem, const std::list< Element* >::const_iterator& )
166 : {
167 11 : PropertyMap aProps;
168 11 : if( elem.StyleId != -1 )
169 : {
170 11 : aProps[ USTR( "text:style-name" ) ] = m_rEmitContext.rStyles.getStyleName( elem.StyleId );
171 : }
172 11 : const char* pTagType = "text:p";
173 11 : if( elem.Type == elem.Headline )
174 0 : pTagType = "text:h";
175 11 : m_rEmitContext.rEmitter.beginTag( pTagType, aProps );
176 :
177 11 : std::list< Element* >::iterator this_it = elem.Children.begin();
178 33 : while( this_it !=elem.Children.end() && *this_it != &elem )
179 : {
180 11 : (*this_it)->visitedBy( *this, this_it );
181 11 : ++this_it;
182 : }
183 :
184 11 : m_rEmitContext.rEmitter.endTag( pTagType );
185 11 : }
186 :
187 14 : void DrawXmlEmitter::fillFrameProps( DrawElement& rElem,
188 : PropertyMap& rProps,
189 : const EmitContext& rEmitContext,
190 : bool bWasTransformed
191 : )
192 : {
193 14 : double rel_x = rElem.x, rel_y = rElem.y;
194 :
195 14 : rProps[ USTR( "draw:z-index" ) ] = rtl::OUString::valueOf( rElem.ZOrder );
196 14 : rProps[ USTR( "draw:style-name" )] = rEmitContext.rStyles.getStyleName( rElem.StyleId );
197 14 : rProps[ USTR( "svg:width" ) ] = convertPixelToUnitString( rElem.w );
198 14 : rProps[ USTR( "svg:height" ) ] = convertPixelToUnitString( rElem.h );
199 :
200 : const GraphicsContext& rGC =
201 14 : rEmitContext.rProcessor.getGraphicsContext( rElem.GCId );
202 14 : if( rGC.Transformation.isIdentity() || bWasTransformed )
203 : {
204 3 : rProps[ USTR( "svg:x" ) ] = convertPixelToUnitString( rel_x );
205 3 : rProps[ USTR( "svg:y" ) ] = convertPixelToUnitString( rel_y );
206 : }
207 : else
208 : {
209 11 : basegfx::B2DTuple aScale, aTranslation;
210 : double fRotate, fShearX;
211 :
212 11 : rGC.Transformation.decompose( aScale, aTranslation, fRotate, fShearX );
213 :
214 11 : 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 11 : if( rElem.MirrorVertical )
222 0 : fRotate += M_PI;
223 :
224 : // build transformation string
225 11 : if( fShearX != 0.0 )
226 : {
227 0 : aBuf.appendAscii( "skewX( " );
228 0 : aBuf.append( fShearX );
229 0 : aBuf.appendAscii( " )" );
230 : }
231 11 : 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 11 : if( aBuf.getLength() > 0 )
241 0 : aBuf.append( sal_Unicode(' ') );
242 11 : aBuf.appendAscii( "translate( " );
243 11 : aBuf.append( convertPixelToUnitString( rel_x ) );
244 11 : aBuf.append( sal_Unicode(' ') );
245 11 : aBuf.append( convertPixelToUnitString( rel_y ) );
246 11 : aBuf.appendAscii( " )" );
247 :
248 11 : rProps[ USTR( "draw:transform" ) ] = aBuf.makeStringAndClear();
249 : }
250 14 : }
251 :
252 11 : void DrawXmlEmitter::visit( FrameElement& elem, const std::list< Element* >::const_iterator& )
253 : {
254 11 : if( elem.Children.empty() )
255 11 : return;
256 :
257 11 : bool bTextBox = (dynamic_cast<ParagraphElement*>(elem.Children.front()) != NULL);
258 11 : PropertyMap aFrameProps;
259 11 : fillFrameProps( elem, aFrameProps, m_rEmitContext );
260 11 : m_rEmitContext.rEmitter.beginTag( "draw:frame", aFrameProps );
261 11 : if( bTextBox )
262 11 : m_rEmitContext.rEmitter.beginTag( "draw:text-box", PropertyMap() );
263 :
264 11 : std::list< Element* >::iterator this_it = elem.Children.begin();
265 33 : while( this_it !=elem.Children.end() && *this_it != &elem )
266 : {
267 11 : (*this_it)->visitedBy( *this, this_it );
268 11 : ++this_it;
269 : }
270 :
271 11 : if( bTextBox )
272 11 : m_rEmitContext.rEmitter.endTag( "draw:text-box" );
273 11 : m_rEmitContext.rEmitter.endTag( "draw:frame" );
274 : }
275 :
276 3 : void DrawXmlEmitter::visit( PolyPolyElement& elem, const std::list< Element* >::const_iterator& )
277 : {
278 3 : 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 6 : for (sal_uInt32 i = 0; i< elem.PolyPoly.count(); i++)
287 : {
288 3 : basegfx::B2DPolygon b2dPolygon;
289 3 : b2dPolygon = elem.PolyPoly.getB2DPolygon( i );
290 :
291 12 : for ( sal_uInt32 j = 0; j< b2dPolygon.count(); j++ )
292 : {
293 9 : basegfx::B2DPoint point;
294 9 : basegfx::B2DPoint nextPoint;
295 9 : point = b2dPolygon.getB2DPoint( j );
296 :
297 9 : basegfx::B2DPoint prevPoint;
298 9 : prevPoint = b2dPolygon.getPrevControlPoint( j ) ;
299 :
300 9 : point.setX( convPx2mmPrec2( point.getX() )*100.0 );
301 9 : point.setY( convPx2mmPrec2( point.getY() )*100.0 );
302 :
303 9 : if ( b2dPolygon.isPrevControlPointUsed( j ) )
304 : {
305 4 : prevPoint.setX( convPx2mmPrec2( prevPoint.getX() )*100.0 );
306 4 : prevPoint.setY( convPx2mmPrec2( prevPoint.getY() )*100.0 );
307 : }
308 :
309 9 : if ( b2dPolygon.isNextControlPointUsed( j ) )
310 : {
311 4 : nextPoint = b2dPolygon.getNextControlPoint( j ) ;
312 4 : nextPoint.setX( convPx2mmPrec2( nextPoint.getX() )*100.0 );
313 4 : nextPoint.setY( convPx2mmPrec2( nextPoint.getY() )*100.0 );
314 : }
315 :
316 9 : b2dPolygon.setB2DPoint( j, point );
317 :
318 9 : if ( b2dPolygon.isPrevControlPointUsed( j ) )
319 4 : b2dPolygon.setPrevControlPoint( j , prevPoint ) ;
320 :
321 9 : if ( b2dPolygon.isNextControlPointUsed( j ) )
322 4 : b2dPolygon.setNextControlPoint( j , nextPoint ) ;
323 9 : }
324 :
325 3 : elem.PolyPoly.setB2DPolygon( i, b2dPolygon );
326 3 : }
327 :
328 3 : 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 3 : fillFrameProps( elem, aProps, m_rEmitContext, true );
333 3 : rtl::OUStringBuffer aBuf( 64 );
334 3 : aBuf.appendAscii( "0 0 " );
335 3 : aBuf.append( convPx2mmPrec2(elem.w)*100.0 );
336 3 : aBuf.append( sal_Unicode(' ') );
337 3 : aBuf.append( convPx2mmPrec2(elem.h)*100.0 );
338 3 : aProps[ USTR( "svg:viewBox" ) ] = aBuf.makeStringAndClear();
339 3 : aProps[ USTR( "svg:d" ) ] = basegfx::tools::exportToSvgD( elem.PolyPoly );
340 :
341 3 : m_rEmitContext.rEmitter.beginTag( "draw:path", aProps );
342 3 : m_rEmitContext.rEmitter.endTag( "draw:path" );
343 3 : }
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 1 : void DrawXmlEmitter::visit( PageElement& elem, const std::list< Element* >::const_iterator& )
356 : {
357 1 : PropertyMap aPageProps;
358 1 : aPageProps[ USTR( "draw:master-page-name" ) ] = m_rEmitContext.rStyles.getStyleName( elem.StyleId );
359 :
360 1 : m_rEmitContext.rEmitter.beginTag("draw:page", aPageProps);
361 :
362 1 : if( m_rEmitContext.xStatusIndicator.is() )
363 0 : m_rEmitContext.xStatusIndicator->setValue( elem.PageNumber );
364 :
365 1 : std::list< Element* >::iterator this_it = elem.Children.begin();
366 16 : while( this_it !=elem.Children.end() && *this_it != &elem )
367 : {
368 14 : (*this_it)->visitedBy( *this, this_it );
369 14 : ++this_it;
370 : }
371 :
372 1 : m_rEmitContext.rEmitter.endTag("draw:page");
373 1 : }
374 :
375 1 : void DrawXmlEmitter::visit( DocumentElement& elem, const std::list< Element* >::const_iterator&)
376 : {
377 1 : m_rEmitContext.rEmitter.beginTag( "office:body", PropertyMap() );
378 : m_rEmitContext.rEmitter.beginTag( m_bWriteDrawDocument ? "office:drawing" : "office:presentation",
379 1 : PropertyMap() );
380 :
381 1 : std::list< Element* >::iterator this_it = elem.Children.begin();
382 3 : while( this_it !=elem.Children.end() && *this_it != &elem )
383 : {
384 1 : (*this_it)->visitedBy( *this, this_it );
385 1 : ++this_it;
386 : }
387 :
388 1 : m_rEmitContext.rEmitter.endTag( m_bWriteDrawDocument ? "office:drawing" : "office:presentation" );
389 1 : m_rEmitContext.rEmitter.endTag( "office:body" );
390 1 : }
391 :
392 : /////////////////////////////////////////////////////////////////
393 :
394 0 : void DrawXmlOptimizer::visit( HyperlinkElement&, const std::list< Element* >::const_iterator& )
395 : {
396 0 : }
397 :
398 11 : void DrawXmlOptimizer::visit( TextElement&, const std::list< Element* >::const_iterator&)
399 : {
400 11 : }
401 :
402 11 : void DrawXmlOptimizer::visit( FrameElement& elem, const std::list< Element* >::const_iterator& )
403 : {
404 11 : elem.applyToChildren(*this);
405 11 : }
406 :
407 0 : void DrawXmlOptimizer::visit( ImageElement&, const std::list< Element* >::const_iterator& )
408 : {
409 0 : }
410 :
411 3 : 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 3 : if( elem.Parent )
418 : {
419 : // find following PolyPolyElement in parent's children list
420 3 : std::list< Element* >::iterator this_it = elem.Parent->Children.begin();
421 21 : while( this_it != elem.Parent->Children.end() && *this_it != &elem )
422 15 : ++this_it;
423 :
424 3 : if( this_it != elem.Parent->Children.end() )
425 : {
426 3 : std::list< Element* >::iterator next_it = this_it;
427 3 : if( ++next_it != elem.Parent->Children.end() )
428 : {
429 3 : PolyPolyElement* pNext = dynamic_cast<PolyPolyElement*>(*next_it);
430 :
431 : // TODO(F2): this comparison fails for OOo-generated polygons with beziers.
432 3 : 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 3 : }
470 :
471 11 : void DrawXmlOptimizer::visit( ParagraphElement& elem, const std::list< Element* >::const_iterator& )
472 : {
473 11 : optimizeTextElements( elem );
474 :
475 11 : elem.applyToChildren(*this);
476 11 : }
477 :
478 1 : void DrawXmlOptimizer::visit( PageElement& elem, const std::list< Element* >::const_iterator& )
479 : {
480 1 : if( m_rProcessor.getStatusIndicator().is() )
481 0 : m_rProcessor.getStatusIndicator()->setValue( elem.PageNumber );
482 :
483 : // resolve hyperlinks
484 1 : elem.resolveHyperlinks();
485 :
486 1 : 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 1 : m_rProcessor.sortElements( &elem );
491 :
492 : // find paragraphs in text
493 1 : ParagraphElement* pCurPara = NULL;
494 1 : std::list< Element* >::iterator page_element, next_page_element;
495 1 : next_page_element = elem.Children.begin();
496 1 : double fCurLineHeight = 0.0; // average height of text items in current para
497 1 : int nCurLineElements = 0; // number of line contributing elements in current para
498 1 : double line_left = elem.w, line_right = 0.0;
499 1 : double column_width = elem.w*0.75; // estimate text width
500 : // TODO: guess columns
501 16 : while( next_page_element != elem.Children.end() )
502 : {
503 14 : page_element = next_page_element++;
504 14 : ParagraphElement* pPagePara = dynamic_cast<ParagraphElement*>(*page_element);
505 14 : 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 14 : HyperlinkElement* pLink = dynamic_cast<HyperlinkElement*>(*page_element);
525 14 : DrawElement* pDraw = dynamic_cast<DrawElement*>(*page_element);
526 14 : if( ! pDraw && pLink && ! pLink->Children.empty() )
527 0 : pDraw = dynamic_cast<DrawElement*>(pLink->Children.front() );
528 14 : if( pDraw )
529 : {
530 : // insert small drawing objects as character, else leave them page bound
531 :
532 14 : bool bInsertToParagraph = false;
533 : // first check if this is either inside the paragraph
534 14 : 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 14 : else if( next_page_element != elem.Children.end() )
547 : {
548 13 : TextElement* pText = dynamic_cast<TextElement*>(*next_page_element);
549 13 : if( ! pText )
550 : {
551 13 : ParagraphElement* pPara = dynamic_cast<ParagraphElement*>(*next_page_element);
552 13 : if( pPara && ! pPara->Children.empty() )
553 0 : pText = dynamic_cast<TextElement*>(pPara->Children.front());
554 : }
555 13 : 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 14 : if( ! bInsertToParagraph )
576 : {
577 14 : pCurPara = NULL;
578 14 : 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 1 : elem.applyToChildren(*this);
657 1 : }
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 11 : void DrawXmlOptimizer::optimizeTextElements(Element& rParent)
680 : {
681 11 : if( rParent.Children.empty() ) // this should not happen
682 : {
683 : OSL_FAIL( "empty paragraph optimized" );
684 11 : return;
685 : }
686 :
687 : // concatenate child elements with same font id
688 11 : std::list< Element* >::iterator next = rParent.Children.begin();
689 11 : std::list< Element* >::iterator it = next++;
690 :
691 115 : while( next != rParent.Children.end() )
692 : {
693 93 : bool bConcat = false;
694 93 : TextElement* pCur = dynamic_cast<TextElement*>(*it);
695 :
696 93 : if( pCur )
697 : {
698 93 : TextElement* pNext = dynamic_cast<TextElement*>(*next);
699 93 : bool isComplex = false;
700 93 : rtl::OUString str(pCur->Text.getStr());
701 798 : for(int i=0; i< str.getLength(); i++)
702 : {
703 705 : sal_Int16 nType = GetBreakIterator()->getScriptType( str, i );
704 705 : if (nType == ::com::sun::star::i18n::ScriptType::COMPLEX)
705 0 : isComplex = true;
706 : }
707 93 : bool bPara = strspn("ParagraphElement", typeid(rParent).name());
708 93 : ParagraphElement* pPara = dynamic_cast<ParagraphElement*>(&rParent);
709 93 : if (bPara && isComplex)
710 0 : pPara->bRtl = true;
711 93 : if( pNext )
712 : {
713 93 : const GraphicsContext& rCurGC = m_rProcessor.getGraphicsContext( pCur->GCId );
714 93 : 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 279 : 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 186 : (rCurGC.Transformation == rNextGC.Transformation || notTransformed(rNextGC))
726 : )
727 : {
728 93 : pCur->updateGeometryWith( pNext );
729 : // append text to current element
730 93 : pCur->Text.append( pNext->Text.getStr(), pNext->Text.getLength() );
731 :
732 93 : str = pCur->Text.getStr();
733 891 : for(int i=0; i< str.getLength(); i++)
734 : {
735 798 : sal_Int16 nType = GetBreakIterator()->getScriptType( str, i );
736 798 : if (nType == ::com::sun::star::i18n::ScriptType::COMPLEX)
737 0 : isComplex = true;
738 : }
739 93 : 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 93 : pCur->Children.splice( pCur->Children.end(), pNext->Children );
745 : // get rid of the now useless element
746 93 : rParent.Children.erase( next );
747 93 : delete pNext;
748 93 : bConcat = true;
749 : }
750 93 : }
751 : }
752 0 : else if( dynamic_cast<HyperlinkElement*>(*it) )
753 0 : optimizeTextElements( **it );
754 93 : if ( bConcat )
755 93 : next = it;
756 : else
757 0 : ++it;
758 93 : ++next;
759 : }
760 : }
761 :
762 1 : void DrawXmlOptimizer::visit( DocumentElement& elem, const std::list< Element* >::const_iterator&)
763 : {
764 1 : elem.applyToChildren(*this);
765 1 : }
766 :
767 : //////////////////////////////////////////////////////////////////////////////////
768 :
769 :
770 3 : void DrawXmlFinalizer::visit( PolyPolyElement& elem, const std::list< Element* >::const_iterator& )
771 : {
772 : // xxx TODO copied from DrawElement
773 3 : const GraphicsContext& rGC = m_rProcessor.getGraphicsContext(elem.GCId );
774 3 : PropertyMap aProps;
775 3 : aProps[ USTR( "style:family" ) ] = USTR( "graphic" );
776 3 : aProps[ USTR( "style:parent-style-name") ] = USTR( "standard" );
777 : // generate standard graphic style if necessary
778 3 : m_rStyleContainer.getStandardStyleId( "graphic" );
779 :
780 3 : PropertyMap aGCProps;
781 :
782 : // TODO(F3): proper dash emulation
783 3 : if( elem.Action & PATH_STROKE )
784 : {
785 2 : aGCProps[ USTR("draw:stroke") ] = rGC.DashArray.empty() ? USTR("solid") : USTR("dash");
786 2 : aGCProps[ USTR("svg:stroke-color") ] = getColorString( rGC.LineColor );
787 2 : if( rGC.LineWidth != 0.0 )
788 : {
789 1 : ::basegfx::B2DVector aVec(rGC.LineWidth,0);
790 1 : aVec *= rGC.Transformation;
791 :
792 1 : aVec.setX ( convPx2mmPrec2( aVec.getX() )*100.0 );
793 1 : aVec.setY ( convPx2mmPrec2( aVec.getY() )*100.0 );
794 :
795 1 : aGCProps[ USTR("svg:stroke-width") ] = rtl::OUString::valueOf( aVec.getLength() );
796 : }
797 : }
798 : else
799 : {
800 1 : aGCProps[ USTR("draw:stroke") ] = USTR("none");
801 : }
802 :
803 : // TODO(F1): check whether stuff could be emulated by gradient/bitmap/hatch
804 3 : if( elem.Action & (PATH_FILL | PATH_EOFILL) )
805 : {
806 1 : aGCProps[ USTR("draw:fill") ] = USTR("solid");
807 1 : aGCProps[ USTR("draw:fill-color") ] = getColorString( rGC.FillColor );
808 : }
809 : else
810 : {
811 2 : aGCProps[ USTR("draw:fill") ] = USTR("none");
812 : }
813 :
814 3 : StyleContainer::Style aStyle( "style:style", aProps );
815 3 : StyleContainer::Style aSubStyle( "style:graphic-properties", aGCProps );
816 3 : aStyle.SubStyles.push_back( &aSubStyle );
817 :
818 3 : elem.StyleId = m_rStyleContainer.getStyleId( aStyle );
819 3 : }
820 :
821 0 : void DrawXmlFinalizer::visit( HyperlinkElement&, const std::list< Element* >::const_iterator& )
822 : {
823 0 : }
824 :
825 11 : void DrawXmlFinalizer::visit( TextElement& elem, const std::list< Element* >::const_iterator& )
826 : {
827 11 : const FontAttributes& rFont = m_rProcessor.getFont( elem.FontId );
828 11 : PropertyMap aProps;
829 11 : aProps[ USTR( "style:family" ) ] = USTR( "text" );
830 :
831 11 : PropertyMap aFontProps;
832 :
833 : // family name
834 11 : aFontProps[ USTR( "fo:font-family" ) ] = rFont.familyName;
835 11 : aFontProps[ USTR( "style:font-family-complex" ) ] = rFont.familyName;
836 :
837 : // bold
838 11 : 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 11 : 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 11 : 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 11 : if( rFont.isOutline )
860 : {
861 0 : aFontProps[ USTR( "style:text-outline" ) ] = USTR( "true" );
862 : }
863 : // size
864 11 : rtl::OUStringBuffer aBuf( 32 );
865 11 : aBuf.append( rFont.size*72/PDFI_OUTDEV_RESOLUTION );
866 11 : aBuf.appendAscii( "pt" );
867 11 : rtl::OUString aFSize = aBuf.makeStringAndClear();
868 11 : aFontProps[ USTR( "fo:font-size" ) ] = aFSize;
869 11 : aFontProps[ USTR( "style:font-size-asian" ) ] = aFSize;
870 11 : aFontProps[ USTR( "style:font-size-complex" ) ] = aFSize;
871 : // color
872 11 : const GraphicsContext& rGC = m_rProcessor.getGraphicsContext( elem.GCId );
873 11 : aFontProps[ USTR( "fo:color" ) ] = getColorString( rFont.isOutline ? rGC.LineColor : rGC.FillColor );
874 :
875 11 : StyleContainer::Style aStyle( "style:style", aProps );
876 11 : StyleContainer::Style aSubStyle( "style:text-properties", aFontProps );
877 11 : aStyle.SubStyles.push_back( &aSubStyle );
878 11 : elem.StyleId = m_rStyleContainer.getStyleId( aStyle );
879 11 : }
880 :
881 11 : void DrawXmlFinalizer::visit( ParagraphElement& elem, const std::list< Element* >::const_iterator& )
882 : {
883 :
884 11 : PropertyMap aProps;
885 11 : aProps[ USTR( "style:family" ) ] = USTR( "paragraph" );
886 : // generate standard paragraph style if necessary
887 11 : m_rStyleContainer.getStandardStyleId( "paragraph" );
888 :
889 11 : PropertyMap aParProps;
890 :
891 11 : aParProps[ USTR("fo:text-align")] = USTR("start");
892 11 : if (elem.bRtl)
893 0 : aParProps[ USTR("style:writing-mode")] = USTR("rl-tb");
894 : else
895 11 : aParProps[ USTR("style:writing-mode")] = USTR("lr-tb");
896 :
897 11 : StyleContainer::Style aStyle( "style:style", aProps );
898 11 : StyleContainer::Style aSubStyle( "style:paragraph-properties", aParProps );
899 11 : aStyle.SubStyles.push_back( &aSubStyle );
900 :
901 11 : elem.StyleId = m_rStyleContainer.getStyleId( aStyle );
902 :
903 11 : elem.applyToChildren(*this);
904 11 : }
905 :
906 11 : void DrawXmlFinalizer::visit( FrameElement& elem, const std::list< Element* >::const_iterator&)
907 : {
908 11 : PropertyMap aProps;
909 11 : aProps[ USTR( "style:family" ) ] = USTR( "graphic" );
910 11 : aProps[ USTR( "style:parent-style-name") ] = USTR( "standard" );
911 : // generate standard graphic style if necessary
912 11 : m_rStyleContainer.getStandardStyleId( "graphic" );
913 :
914 11 : PropertyMap aGCProps;
915 :
916 11 : aGCProps[ USTR("draw:stroke") ] = USTR("none");
917 11 : aGCProps[ USTR("draw:fill") ] = USTR("none");
918 11 : aGCProps[ USTR("draw:auto-grow-height") ] = USTR("true");
919 11 : aGCProps[ USTR("draw:auto-grow-width") ] = USTR("true");
920 11 : aGCProps[ USTR("draw:textarea-horizontal-align") ] = USTR("left");
921 11 : aGCProps[ USTR("draw:textarea-vertical-align") ] = USTR("top");
922 11 : aGCProps[ USTR("fo:min-height")] = USTR("0cm");
923 11 : aGCProps[ USTR("fo:min-width")] = USTR("0cm");
924 11 : aGCProps[ USTR("fo:padding-top") ] = USTR("0cm");
925 11 : aGCProps[ USTR("fo:padding-left") ] = USTR("0cm");
926 11 : aGCProps[ USTR("fo:padding-right") ] = USTR("0cm");
927 11 : 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 11 : if( elem.MirrorVertical )
934 0 : aGCProps[ USTR("style:mirror") ] = USTR("horizontal");
935 :
936 11 : StyleContainer::Style aStyle( "style:style", aProps );
937 11 : StyleContainer::Style aSubStyle( "style:graphic-properties", aGCProps );
938 11 : aStyle.SubStyles.push_back( &aSubStyle );
939 :
940 11 : elem.StyleId = m_rStyleContainer.getStyleId( aStyle );
941 11 : elem.applyToChildren(*this);
942 11 : }
943 :
944 0 : void DrawXmlFinalizer::visit( ImageElement&, const std::list< Element* >::const_iterator& )
945 : {
946 0 : }
947 :
948 1 : void DrawXmlFinalizer::visit( PageElement& elem, const std::list< Element* >::const_iterator& )
949 : {
950 1 : if( m_rProcessor.getStatusIndicator().is() )
951 0 : m_rProcessor.getStatusIndicator()->setValue( elem.PageNumber );
952 :
953 : // transform from pixel to mm
954 1 : double page_width = convPx2mm( elem.w ), page_height = convPx2mm( elem.h );
955 :
956 : // calculate page margins out of the relevant children (paragraphs)
957 1 : elem.TopMargin = elem.h, elem.BottomMargin = 0, elem.LeftMargin = elem.w, elem.RightMargin = 0;
958 :
959 15 : for( std::list< Element* >::const_iterator it = elem.Children.begin(); it != elem.Children.end(); ++it )
960 : {
961 14 : if( (*it)->x < elem.LeftMargin )
962 1 : elem.LeftMargin = (*it)->x;
963 14 : if( (*it)->y < elem.TopMargin )
964 2 : elem.TopMargin = (*it)->y;
965 14 : if( (*it)->x + (*it)->w > elem.RightMargin )
966 4 : elem.RightMargin = ((*it)->x + (*it)->w);
967 14 : if( (*it)->y + (*it)->h > elem.BottomMargin )
968 8 : elem.BottomMargin = ((*it)->y + (*it)->h);
969 : }
970 :
971 : // transform margins to mm
972 1 : double left_margin = convPx2mm( elem.LeftMargin );
973 1 : double right_margin = convPx2mm( elem.RightMargin );
974 1 : double top_margin = convPx2mm( elem.TopMargin );
975 1 : double bottom_margin = convPx2mm( elem.BottomMargin );
976 :
977 : // round left/top margin to nearest mm
978 1 : left_margin = rtl_math_round( left_margin, 0, rtl_math_RoundingMode_Floor );
979 1 : top_margin = rtl_math_round( top_margin, 0, rtl_math_RoundingMode_Floor );
980 : // round (fuzzy) right/bottom margin to nearest cm
981 1 : right_margin = rtl_math_round( right_margin, right_margin >= 10 ? -1 : 0, rtl_math_RoundingMode_Floor );
982 1 : 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 1 : if( left_margin > page_width/2.0 - 10 )
987 0 : left_margin = 10;
988 1 : if( right_margin > page_width/2.0 - 10 )
989 1 : right_margin = 10;
990 1 : if( top_margin > page_height/2.0 - 10 )
991 0 : top_margin = 10;
992 1 : if( bottom_margin > page_height/2.0 - 10 )
993 1 : bottom_margin = 10;
994 :
995 : // catch the weird cases
996 1 : if( left_margin < 0 )
997 0 : left_margin = 0;
998 1 : if( right_margin < 0 )
999 0 : right_margin = 0;
1000 1 : if( top_margin < 0 )
1001 0 : top_margin = 0;
1002 1 : if( bottom_margin < 0 )
1003 0 : bottom_margin = 0;
1004 :
1005 : // widely differing margins are unlikely to be correct
1006 1 : if( right_margin > left_margin*1.5 )
1007 0 : right_margin = left_margin;
1008 :
1009 1 : elem.LeftMargin = convmm2Px( left_margin );
1010 1 : elem.RightMargin = convmm2Px( right_margin );
1011 1 : elem.TopMargin = convmm2Px( top_margin );
1012 1 : elem.BottomMargin = convmm2Px( bottom_margin );
1013 :
1014 : // get styles for paragraphs
1015 1 : PropertyMap aPageProps;
1016 1 : PropertyMap aPageLayoutProps;
1017 1 : rtl::OUStringBuffer aBuf( 64 );
1018 1 : aPageLayoutProps[ USTR( "fo:margin-top" ) ] = unitMMString( top_margin );
1019 1 : aPageLayoutProps[ USTR( "fo:margin-bottom" ) ] = unitMMString( bottom_margin );
1020 1 : aPageLayoutProps[ USTR( "fo:margin-left" ) ] = unitMMString( left_margin );
1021 1 : aPageLayoutProps[ USTR( "fo:margin-right" ) ] = unitMMString( right_margin );
1022 1 : aPageLayoutProps[ USTR( "fo:page-width" ) ] = unitMMString( page_width );
1023 1 : aPageLayoutProps[ USTR( "fo:page-height" ) ] = unitMMString( page_height );
1024 1 : aPageLayoutProps[ USTR( "style:print-orientation" ) ]= elem.w < elem.h ? USTR( "portrait" ) : USTR( "landscape" );
1025 1 : aPageLayoutProps[ USTR( "style:writing-mode" ) ]= USTR( "lr-tb" );
1026 :
1027 1 : StyleContainer::Style aStyle( "style:page-layout", aPageProps);
1028 1 : StyleContainer::Style aSubStyle( "style:page-layout-properties", aPageLayoutProps);
1029 1 : aStyle.SubStyles.push_back(&aSubStyle);
1030 1 : sal_Int32 nPageStyle = m_rStyleContainer.impl_getStyleId( aStyle, false );
1031 :
1032 : // create master page
1033 1 : rtl::OUString aMasterPageLayoutName = m_rStyleContainer.getStyleName( nPageStyle );
1034 1 : aPageProps[ USTR( "style:page-layout-name" ) ] = aMasterPageLayoutName;
1035 :
1036 1 : StyleContainer::Style aMPStyle( "style:master-page", aPageProps);
1037 :
1038 1 : StyleContainer::Style aHeaderStyle( "style:header", PropertyMap() );
1039 1 : StyleContainer::Style aFooterStyle( "style:footer", PropertyMap() );
1040 :
1041 1 : elem.StyleId = m_rStyleContainer.impl_getStyleId( aMPStyle,false );
1042 :
1043 :
1044 1 : rtl::OUString aMasterPageName = m_rStyleContainer.getStyleName( elem.StyleId );
1045 :
1046 : // create styles for children
1047 1 : elem.applyToChildren(*this);
1048 1 : }
1049 :
1050 1 : void DrawXmlFinalizer::visit( DocumentElement& elem, const std::list< Element* >::const_iterator& )
1051 : {
1052 1 : elem.applyToChildren(*this);
1053 1 : }
1054 :
1055 : }
1056 :
1057 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|