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