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 {
225
226 if (rElem.MirrorVertical)
227 {
229 mat2.translate(0, -0.5);
230 mat2.scale(1, -1);
231 mat2.translate(0, 0.5);
232 mat = mat * mat2;
233 }
234
235 double scale = convPx2mm(100);
236 mat.scale(scale, scale);
237
238 rProps[ sDrawTransform ] =
239 OUString::Concat("matrix(")
240 + OUString::number(mat.get(0, 0))
241 + " "
242 + OUString::number(mat.get(1, 0))
243 + " "
244 + OUString::number(mat.get(0, 1))
245 + " "
246 + OUString::number(mat.get(1, 1))
247 + " "
248 + OUString::number(mat.get(0, 2))
249 + " "
250 + OUString::number(mat.get(1, 2))
251 + ")";
252
253 }
254}
255
256void DrawXmlEmitter::visit( FrameElement& elem, const std::list< std::unique_ptr<Element> >::const_iterator& )
257{
258 if( elem.Children.empty() )
259 return;
260
261 bool bTextBox = (dynamic_cast<ParagraphElement*>(elem.Children.front().get()) != nullptr);
262 PropertyMap aFrameProps;
263 fillFrameProps( elem, aFrameProps, m_rEmitContext, false );
264 m_rEmitContext.rEmitter.beginTag( "draw:frame", aFrameProps );
265 if( bTextBox )
266 m_rEmitContext.rEmitter.beginTag( "draw:text-box", PropertyMap() );
267
268 auto this_it = elem.Children.begin();
269 while( this_it != elem.Children.end() && this_it->get() != &elem )
270 {
271 (*this_it)->visitedBy( *this, this_it );
272 ++this_it;
273 }
274
275 if( bTextBox )
276 m_rEmitContext.rEmitter.endTag( "draw:text-box" );
277 m_rEmitContext.rEmitter.endTag( "draw:frame" );
278}
279
280void DrawXmlEmitter::visit( PolyPolyElement& elem, const std::list< std::unique_ptr<Element> >::const_iterator& )
281{
282 elem.updateGeometry();
283 /* note:
284 * aw recommends using 100dth of mm in all respects since the xml import
285 * (a) is buggy (see issue 37213)
286 * (b) is optimized for 100dth of mm and does not scale itself then,
287 * this does not gain us speed but makes for smaller rounding errors since
288 * the xml importer coordinates are integer based
289 */
290 for (sal_uInt32 i = 0; i< elem.PolyPoly.count(); i++)
291 {
292 basegfx::B2DPolygon b2dPolygon = elem.PolyPoly.getB2DPolygon( i );
293
294 for ( sal_uInt32 j = 0; j< b2dPolygon.count(); j++ )
295 {
297 basegfx::B2DPoint nextPoint;
298 point = b2dPolygon.getB2DPoint( j );
299
300 basegfx::B2DPoint prevPoint = b2dPolygon.getPrevControlPoint( j ) ;
301
302 point.setX( convPx2mmPrec2( point.getX() )*100.0 );
303 point.setY( convPx2mmPrec2( point.getY() )*100.0 );
304
305 if ( b2dPolygon.isPrevControlPointUsed( j ) )
306 {
307 prevPoint.setX( convPx2mmPrec2( prevPoint.getX() )*100.0 );
308 prevPoint.setY( convPx2mmPrec2( prevPoint.getY() )*100.0 );
309 }
310
311 if ( b2dPolygon.isNextControlPointUsed( j ) )
312 {
313 nextPoint = b2dPolygon.getNextControlPoint( j ) ;
314 nextPoint.setX( convPx2mmPrec2( nextPoint.getX() )*100.0 );
315 nextPoint.setY( convPx2mmPrec2( nextPoint.getY() )*100.0 );
316 }
317
318 b2dPolygon.setB2DPoint( j, point );
319
320 if ( b2dPolygon.isPrevControlPointUsed( j ) )
321 b2dPolygon.setPrevControlPoint( j , prevPoint ) ;
322
323 if ( b2dPolygon.isNextControlPointUsed( j ) )
324 b2dPolygon.setNextControlPoint( j , nextPoint ) ;
325 }
326
327 elem.PolyPoly.setB2DPolygon( i, b2dPolygon );
328 }
329
330 PropertyMap aProps;
331 // PDFIProcessor transforms geometrical objects, not images and text
332 // so we need to tell fillFrameProps here that the transformation for
333 // a PolyPolyElement was already applied (aside from translation)
334 fillFrameProps( elem, aProps, m_rEmitContext, true );
335 aProps[ "svg:viewBox" ] =
336 "0 0 "
337 + OUString::number( convPx2mmPrec2(elem.w)*100.0 )
338 + " "
339 + OUString::number( convPx2mmPrec2(elem.h)*100.0 );
340 aProps[ "svg:d" ] = basegfx::utils::exportToSvgD( elem.PolyPoly, false, true, false );
341
342 m_rEmitContext.rEmitter.beginTag( "draw:path", aProps );
343 m_rEmitContext.rEmitter.endTag( "draw:path" );
344}
345
346void DrawXmlEmitter::visit( ImageElement& elem, const std::list< std::unique_ptr<Element> >::const_iterator& )
347{
348 PropertyMap aImageProps;
349 m_rEmitContext.rEmitter.beginTag( "draw:image", aImageProps );
350 m_rEmitContext.rEmitter.beginTag( "office:binary-data", PropertyMap() );
352 m_rEmitContext.rEmitter.endTag( "office:binary-data" );
353 m_rEmitContext.rEmitter.endTag( "draw:image" );
354}
355
356void DrawXmlEmitter::visit( PageElement& elem, const std::list< std::unique_ptr<Element> >::const_iterator& )
357{
358 PropertyMap aPageProps;
359 aPageProps[ "draw:master-page-name" ] = m_rEmitContext.rStyles.getStyleName( elem.StyleId );
360
361 m_rEmitContext.rEmitter.beginTag("draw:page", aPageProps);
362
365
366 auto this_it = elem.Children.begin();
367 while( this_it != elem.Children.end() && this_it->get() != &elem )
368 {
369 (*this_it)->visitedBy( *this, this_it );
370 ++this_it;
371 }
372
373 m_rEmitContext.rEmitter.endTag("draw:page");
374}
375
376void DrawXmlEmitter::visit( DocumentElement& elem, const std::list< std::unique_ptr<Element> >::const_iterator&)
377{
378 m_rEmitContext.rEmitter.beginTag( "office:body", PropertyMap() );
379 m_rEmitContext.rEmitter.beginTag( m_bWriteDrawDocument ? "office:drawing" : "office:presentation",
380 PropertyMap() );
381
382 auto this_it = elem.Children.begin();
383 while( this_it != elem.Children.end() && this_it->get() != &elem )
384 {
385 (*this_it)->visitedBy( *this, this_it );
386 ++this_it;
387 }
388
389 m_rEmitContext.rEmitter.endTag( m_bWriteDrawDocument ? "office:drawing" : "office:presentation" );
390 m_rEmitContext.rEmitter.endTag( "office:body" );
391}
392
393
394void DrawXmlOptimizer::visit( HyperlinkElement&, const std::list< std::unique_ptr<Element> >::const_iterator& )
395{
396}
397
398void DrawXmlOptimizer::visit( TextElement&, const std::list< std::unique_ptr<Element> >::const_iterator&)
399{
400}
401
402void DrawXmlOptimizer::visit( FrameElement& elem, const std::list< std::unique_ptr<Element> >::const_iterator& )
403{
404 elem.applyToChildren(*this);
405}
406
407void DrawXmlOptimizer::visit( ImageElement&, const std::list< std::unique_ptr<Element> >::const_iterator& )
408{
409}
410
411void DrawXmlOptimizer::visit( PolyPolyElement& elem, const std::list< std::unique_ptr<Element> >::const_iterator& elemIt )
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 if( !elem.Parent )
418 return;
419
420 // find following PolyPolyElement in parent's children list
421 if( elemIt == elem.Parent->Children.end() )
422 return;
423 auto next_it = elemIt;
424 ++next_it;
425 if( next_it == elem.Parent->Children.end() )
426 return;
427
428 PolyPolyElement* pNext = dynamic_cast<PolyPolyElement*>(next_it->get());
429 // TODO(F2): this comparison fails for OOo-generated polygons with beziers.
430 if( !pNext || pNext->PolyPoly != elem.PolyPoly )
431 return;
432
433 const GraphicsContext& rNextGC =
435 const GraphicsContext& rThisGC =
437
438 if( !(rThisGC.BlendMode == rNextGC.BlendMode &&
439 rThisGC.Flatness == rNextGC.Flatness &&
440 rThisGC.Transformation == rNextGC.Transformation &&
441 rThisGC.Clip == rNextGC.Clip &&
442 rThisGC.FillColor.Red == rNextGC.FillColor.Red &&
443 rThisGC.FillColor.Green== rNextGC.FillColor.Green &&
444 rThisGC.FillColor.Blue == rNextGC.FillColor.Blue &&
445 rThisGC.FillColor.Alpha== rNextGC.FillColor.Alpha &&
446 pNext->Action == PATH_STROKE &&
447 (elem.Action == PATH_FILL || elem.Action == PATH_EOFILL)) )
448 return;
449
450 GraphicsContext aGC = rThisGC;
451 aGC.LineJoin = rNextGC.LineJoin;
452 aGC.LineCap = rNextGC.LineCap;
453 aGC.LineWidth = rNextGC.LineWidth;
454 aGC.MiterLimit= rNextGC.MiterLimit;
455 aGC.DashArray = rNextGC.DashArray;
456 aGC.LineColor = rNextGC.LineColor;
457 elem.GCId = m_rProcessor.getGCId( aGC );
458
459 elem.Action |= pNext->Action;
460
461 elem.Children.splice( elem.Children.end(), pNext->Children );
462 elem.Parent->Children.erase(next_it);
463}
464
465void DrawXmlOptimizer::visit( ParagraphElement& elem, const std::list< std::unique_ptr<Element> >::const_iterator& )
466{
467 optimizeTextElements( elem );
468
469 elem.applyToChildren(*this);
470}
471
472void DrawXmlOptimizer::visit( PageElement& elem, const std::list< std::unique_ptr<Element> >::const_iterator& )
473{
475 m_rProcessor.getStatusIndicator()->setValue( elem.PageNumber );
476
477 // resolve hyperlinks
478 elem.resolveHyperlinks();
479
480 elem.resolveFontStyles( m_rProcessor ); // underlines and such
481
482 // FIXME: until hyperlinks and font effects are adjusted for
483 // geometrical search handle them before sorting
485
486 // find paragraphs in text
487 ParagraphElement* pCurPara = nullptr;
488 std::list< std::unique_ptr<Element> >::iterator page_element, next_page_element;
489 next_page_element = elem.Children.begin();
490 double fCurLineHeight = 0.0; // average height of text items in current para
491 int nCurLineElements = 0; // number of line contributing elements in current para
492 double line_left = elem.w, line_right = 0.0;
493 double column_width = elem.w*0.75; // estimate text width
494 // TODO: guess columns
495 while( next_page_element != elem.Children.end() )
496 {
497 page_element = next_page_element++;
498 ParagraphElement* pPagePara = dynamic_cast<ParagraphElement*>(page_element->get());
499 if( pPagePara )
500 {
501 pCurPara = pPagePara;
502 // adjust line height and text items
503 fCurLineHeight = 0.0;
504 nCurLineElements = 0;
505 for( const auto& rxChild : pCurPara->Children )
506 {
507 TextElement* pTestText = rxChild->dynCastAsTextElement();
508 if( pTestText )
509 {
510 fCurLineHeight = (fCurLineHeight*double(nCurLineElements) + pTestText->h)/double(nCurLineElements+1);
511 nCurLineElements++;
512 }
513 }
514 continue;
515 }
516
517 HyperlinkElement* pLink = dynamic_cast<HyperlinkElement*>(page_element->get());
518 DrawElement* pDraw = dynamic_cast<DrawElement*>(page_element->get());
519 if( ! pDraw && pLink && ! pLink->Children.empty() )
520 pDraw = dynamic_cast<DrawElement*>(pLink->Children.front().get() );
521 if( pDraw )
522 {
523 // insert small drawing objects as character, else leave them page bound
524
525 bool bInsertToParagraph = false;
526 // first check if this is either inside the paragraph
527 if( pCurPara && pDraw->y < pCurPara->y + pCurPara->h )
528 {
529 if( pDraw->h < fCurLineHeight * 1.5 )
530 {
531 bInsertToParagraph = true;
532 fCurLineHeight = (fCurLineHeight*double(nCurLineElements) + pDraw->h)/double(nCurLineElements+1);
533 nCurLineElements++;
534 // mark draw element as character
535 pDraw->isCharacter = true;
536 }
537 }
538 // or perhaps the draw element begins a new paragraph
539 else if( next_page_element != elem.Children.end() )
540 {
541 TextElement* pText = (*next_page_element)->dynCastAsTextElement();
542 if( ! pText )
543 {
544 ParagraphElement* pPara = dynamic_cast<ParagraphElement*>(next_page_element->get());
545 if( pPara && ! pPara->Children.empty() )
546 pText = pPara->Children.front()->dynCastAsTextElement();
547 }
548 if( pText && // check there is a text
549 pDraw->h < pText->h*1.5 && // and it is approx the same height
550 // and either upper or lower edge of pDraw is inside text's vertical range
551 ( ( pDraw->y >= pText->y && pDraw->y <= pText->y+pText->h ) ||
552 ( pDraw->y+pDraw->h >= pText->y && pDraw->y+pDraw->h <= pText->y+pText->h )
553 )
554 )
555 {
556 bInsertToParagraph = true;
557 fCurLineHeight = pDraw->h;
558 nCurLineElements = 1;
559 line_left = pDraw->x;
560 line_right = pDraw->x + pDraw->w;
561 // begin a new paragraph
562 pCurPara = nullptr;
563 // mark draw element as character
564 pDraw->isCharacter = true;
565 }
566 }
567
568 if( ! bInsertToParagraph )
569 {
570 pCurPara = nullptr;
571 continue;
572 }
573 }
574
575 TextElement* pText = (*page_element)->dynCastAsTextElement();
576 if( ! pText && pLink && ! pLink->Children.empty() )
577 pText = pLink->Children.front()->dynCastAsTextElement();
578 if( pText )
579 {
580 Element* pGeo = pLink ? static_cast<Element*>(pLink) :
581 static_cast<Element*>(pText);
582 if( pCurPara )
583 {
584 // there was already a text element, check for a new paragraph
585 if( nCurLineElements > 0 )
586 {
587 // if the new text is significantly distant from the paragraph
588 // begin a new paragraph
589 if( pGeo->y > pCurPara->y + pCurPara->h + fCurLineHeight*0.5 )
590 pCurPara = nullptr; // insert new paragraph
591 else if( pGeo->y > (pCurPara->y+pCurPara->h - fCurLineHeight*0.05) )
592 {
593 // new paragraph if either the last line of the paragraph
594 // was significantly shorter than the paragraph as a whole
595 if( (line_right - line_left) < pCurPara->w*0.75 )
596 pCurPara = nullptr;
597 // or the last line was significantly smaller than the column width
598 else if( (line_right - line_left) < column_width*0.75 )
599 pCurPara = nullptr;
600 }
601 }
602
603
604 }
605
606
607 // update line height/width
608 if( pCurPara )
609 {
610 fCurLineHeight = (fCurLineHeight*double(nCurLineElements) + pGeo->h)/double(nCurLineElements+1);
611 nCurLineElements++;
612 if( pGeo->x < line_left )
613 line_left = pGeo->x;
614 if( pGeo->x+pGeo->w > line_right )
615 line_right = pGeo->x+pGeo->w;
616 }
617 else
618 {
619 fCurLineHeight = pGeo->h;
620 nCurLineElements = 1;
621 line_left = pGeo->x;
622 line_right = pGeo->x + pGeo->w;
623 }
624 }
625
626
627 // move element to current paragraph
628 if (! pCurPara ) // new paragraph, insert one
629 {
630 pCurPara = ElementFactory::createParagraphElement( nullptr );
631 // set parent
632 pCurPara->Parent = &elem;
633 //insert new paragraph before current element
634 page_element = elem.Children.insert( page_element, std::unique_ptr<Element>(pCurPara) );
635 // forward iterator to current element again
636 ++ page_element;
637 // update next_element which is now invalid
638 next_page_element = page_element;
639 ++ next_page_element;
640 }
641 Element* pCurEle = page_element->get();
642 Element::setParent( page_element, pCurPara );
643 OSL_ENSURE( !pText || pCurEle == pText || pCurEle == pLink, "paragraph child list in disorder" );
644 if( pText || pDraw )
645 pCurPara->updateGeometryWith( pCurEle );
646 }
647
648 // process children
649 elem.applyToChildren(*this);
650}
651
652static bool isSpaces(TextElement* pTextElem)
653{
654 for (sal_Int32 i = 0; i != pTextElem->Text.getLength(); ++i) {
655 if (pTextElem->Text[i] != ' ') {
656 return false;
657 }
658 }
659 return true;
660}
661
663{
664 if( rParent.Children.empty() ) // this should not happen
665 {
666 OSL_FAIL( "empty paragraph optimized" );
667 return;
668 }
669
670 // concatenate child elements with same font id
671 auto next = rParent.Children.begin();
672 auto it = next++;
673
674 while( next != rParent.Children.end() )
675 {
676 bool bConcat = false;
677 TextElement* pCur = (*it)->dynCastAsTextElement();
678
679 if( pCur )
680 {
681 TextElement* pNext = (*next)->dynCastAsTextElement();
682 OUString str;
683 bool bPara = strspn("ParagraphElement", typeid(rParent).name());
684 ParagraphElement* pPara = dynamic_cast<ParagraphElement*>(&rParent);
685 if (bPara && pPara && isComplex(GetBreakIterator(), pCur))
686 pPara->bRtl = true;
687 if( pNext )
688 {
689 const GraphicsContext& rCurGC = m_rProcessor.getGraphicsContext( pCur->GCId );
690 const GraphicsContext& rNextGC = m_rProcessor.getGraphicsContext( pNext->GCId );
691
692 // line and space optimization; works only in strictly horizontal mode
693
694 // concatenate consecutive text elements unless there is a
695 // font or text color change, leave a new span in that case
696 if( (pCur->FontId == pNext->FontId || isSpaces(pNext)) &&
697 rCurGC.FillColor.Red == rNextGC.FillColor.Red &&
698 rCurGC.FillColor.Green == rNextGC.FillColor.Green &&
699 rCurGC.FillColor.Blue == rNextGC.FillColor.Blue &&
700 rCurGC.FillColor.Alpha == rNextGC.FillColor.Alpha
701 )
702 {
703 pCur->updateGeometryWith( pNext );
704 if (pPara && pPara->bRtl)
705 {
706 // Tdf#152083: If RTL, reverse the text in pNext so that its correct order is
707 // restored when the combined text is reversed in DrawXmlEmitter::visit.
708 OUString tempStr;
709 bool bNeedReverse=false;
710 str = pNext->Text.toString();
711 for (sal_Int32 i=0; i < str.getLength(); i++)
712 {
713 if (str[i] == u' ')
714 { // Space char (e.g. the space as in " م") needs special treatment.
715 // First, append the space char to pCur.
716 pCur->Text.append(OUStringChar(str[i]));
717 // Then, check whether the tmpStr needs reverse, if so then reverse and append.
718 if (bNeedReverse)
719 {
720 tempStr = ::comphelper::string::reverseCodePoints(tempStr);
721 pCur->Text.append(tempStr);
722 tempStr = u"";
723 }
724 bNeedReverse = false;
725 }
726 else
727 {
728 tempStr += OUStringChar(str[i]);
729 bNeedReverse = true;
730 }
731 }
732 // Do the last append
733 if (bNeedReverse)
734 {
735 tempStr = ::comphelper::string::reverseCodePoints(tempStr);
736 pCur->Text.append(tempStr);
737 }
738 else
739 {
740 pCur->Text.append(tempStr);
741 }
742 }
743 else
744 {
745 // append text to current element directly without reverse
746 pCur->Text.append( pNext->Text );
747 }
748
749 if (bPara && pPara && isComplex(GetBreakIterator(), pCur))
750 pPara->bRtl = true;
751 // append eventual children to current element
752 // and clear children (else the children just
753 // appended to pCur would be destroyed)
754 pCur->Children.splice( pCur->Children.end(), pNext->Children );
755 // get rid of the now useless element
756 rParent.Children.erase( next );
757 bConcat = true;
758 }
759 }
760 }
761 else if( dynamic_cast<HyperlinkElement*>(it->get()) )
762 optimizeTextElements( **it );
763 if ( bConcat )
764 next = it;
765 else
766 ++it;
767 ++next;
768 }
769}
770
771void DrawXmlOptimizer::visit( DocumentElement& elem, const std::list< std::unique_ptr<Element> >::const_iterator&)
772{
773 elem.applyToChildren(*this);
774}
775
776
777void DrawXmlFinalizer::visit( PolyPolyElement& elem, const std::list< std::unique_ptr<Element> >::const_iterator& )
778{
779 // xxx TODO copied from DrawElement
781
782 PropertyMap aProps;
783 aProps[ "style:family" ] = "graphic";
784 aProps[ "style:parent-style-name" ] = "standard";
785 // generate standard graphic style if necessary
787
788 PropertyMap aGCProps;
789 if (elem.Action & PATH_STROKE)
790 {
792 if (rGC.DashArray.size() < 2)
793 {
794 aGCProps[ "draw:stroke" ] = "solid";
795 }
796 else
797 {
800 StyleContainer::Style style("draw:stroke-dash", std::move(props));
801
802 aGCProps[ "draw:stroke" ] = "dash";
803 aGCProps[ "draw:stroke-dash" ] =
806 }
807
808 aGCProps[ "svg:stroke-color" ] = getColorString(rGC.LineColor);
809 if (rGC.LineColor.Alpha != 1.0)
810 aGCProps["svg:stroke-opacity"] = getPercentString(rGC.LineColor.Alpha * 100.0);
811 aGCProps[ "svg:stroke-width" ] = convertPixelToUnitString(rGC.LineWidth * scale);
812 aGCProps[ "draw:stroke-linejoin" ] = rGC.GetLineJoinString();
813 aGCProps[ "svg:stroke-linecap" ] = rGC.GetLineCapString();
814 }
815 else
816 {
817 aGCProps[ "draw:stroke" ] = "none";
818 }
819
820 // TODO(F1): check whether stuff could be emulated by gradient/bitmap/hatch
821 if( elem.Action & (PATH_FILL | PATH_EOFILL) )
822 {
823 aGCProps[ "draw:fill" ] = "solid";
824 aGCProps[ "draw:fill-color" ] = getColorString(rGC.FillColor);
825 if (rGC.FillColor.Alpha != 1.0)
826 aGCProps["draw:opacity"] = getPercentString(rGC.FillColor.Alpha * 100.0);
827 }
828 else
829 {
830 aGCProps[ "draw:fill" ] = "none";
831 }
832
833 StyleContainer::Style aStyle( "style:style", std::move(aProps) );
834 StyleContainer::Style aSubStyle( "style:graphic-properties", std::move(aGCProps) );
835 aStyle.SubStyles.push_back( &aSubStyle );
836
837 elem.StyleId = m_rStyleContainer.getStyleId( aStyle );
838}
839
840void DrawXmlFinalizer::visit( HyperlinkElement&, const std::list< std::unique_ptr<Element> >::const_iterator& )
841{
842}
843
844static void SetFontsizeProperties(PropertyMap& props, double fontSize)
845{
846 OUString aFSize = OUString::number(fontSize * 72 / PDFI_OUTDEV_RESOLUTION) + "pt";
847 props["fo:font-size"] = aFSize;
848 props["style:font-size-asian"] = aFSize;
849 props["style:font-size-complex"] = aFSize;
850}
851
852void DrawXmlFinalizer::visit( TextElement& elem, const std::list< std::unique_ptr<Element> >::const_iterator& )
853{
854 const FontAttributes& rFont = m_rProcessor.getFont( elem.FontId );
855 PropertyMap aProps;
856 aProps[ "style:family" ] = "text";
857
858 PropertyMap aFontProps;
859
860 // family name
861 // TODO: tdf#143095: use system font name rather than PSName
862 SAL_INFO("sdext.pdfimport", "The font used in xml is: " << rFont.familyName);
863 aFontProps[ "fo:font-family" ] = rFont.familyName;
864 aFontProps[ "style:font-family-asian" ] = rFont.familyName;
865 aFontProps[ "style:font-family-complex" ] = rFont.familyName;
866
867 // bold
868 aFontProps[ "fo:font-weight" ] = rFont.fontWeight;
869 aFontProps[ "style:font-weight-asian" ] = rFont.fontWeight;
870 aFontProps[ "style:font-weight-complex" ] = rFont.fontWeight;
871
872 // italic
873 if( rFont.isItalic )
874 {
875 aFontProps[ "fo:font-style" ] = "italic";
876 aFontProps[ "style:font-style-asian" ] = "italic";
877 aFontProps[ "style:font-style-complex" ] = "italic";
878 }
879
880 // underline
881 if( rFont.isUnderline )
882 {
883 aFontProps[ "style:text-underline-style" ] = "solid";
884 aFontProps[ "style:text-underline-width" ] = "auto";
885 aFontProps[ "style:text-underline-color" ] = "font-color";
886 }
887
888 // outline
889 if( rFont.isOutline )
890 aFontProps[ "style:text-outline" ] = "true";
891
892 // size
893 SetFontsizeProperties(aFontProps, rFont.size);
894
895 // color
897 aFontProps[ "fo:color" ] = getColorString( rFont.isOutline ? rGC.LineColor : rGC.FillColor );
898
899 // scale
900 double fRotate, fShearX;
901 basegfx::B2DTuple aScale, aTranslation;
902 rGC.Transformation.decompose(aScale, aTranslation, fRotate, fShearX);
903 double textScale = 100 * aScale.getX() / aScale.getY();
904 if (((textScale >= 1) && (textScale <= 99)) ||
905 ((textScale >= 101) && (textScale <= 999)))
906 {
907 aFontProps[ "style:text-scale" ] = getPercentString(textScale);
908 }
909
910 StyleContainer::Style aStyle( "style:style", std::move(aProps) );
911 StyleContainer::Style aSubStyle( "style:text-properties", std::move(aFontProps) );
912 aStyle.SubStyles.push_back( &aSubStyle );
913 elem.StyleId = m_rStyleContainer.getStyleId( aStyle );
914}
915
916void DrawXmlFinalizer::visit( ParagraphElement& elem, const std::list< std::unique_ptr<Element> >::const_iterator& )
917{
918
919 PropertyMap aProps;
920 aProps[ "style:family" ] = "paragraph";
921 // generate standard paragraph style if necessary
923
924 PropertyMap aParProps;
925
926 aParProps[ "fo:text-align"] = "start";
927 if (elem.bRtl)
928 aParProps[ "style:writing-mode"] = "rl-tb";
929 else
930 aParProps[ "style:writing-mode"] = "lr-tb";
931
932 StyleContainer::Style aStyle( "style:style", std::move(aProps) );
933 StyleContainer::Style aSubStyle( "style:paragraph-properties", std::move(aParProps) );
934 aStyle.SubStyles.push_back( &aSubStyle );
935
936 elem.StyleId = m_rStyleContainer.getStyleId( aStyle );
937
938 elem.applyToChildren(*this);
939}
940
941void DrawXmlFinalizer::visit( FrameElement& elem, const std::list< std::unique_ptr<Element> >::const_iterator&)
942{
943 PropertyMap props1;
944 props1[ "style:family" ] = "graphic";
945 props1[ "style:parent-style-name" ] = "standard";
946 // generate standard graphic style if necessary
948
949 PropertyMap aGCProps;
950
951 aGCProps[ "draw:stroke" ] = "none";
952 aGCProps[ "draw:fill" ] = "none";
953 aGCProps[ "draw:auto-grow-height" ] = "true";
954 aGCProps[ "draw:auto-grow-width" ] = "true";
955 aGCProps[ "draw:textarea-horizontal-align" ] = "left";
956 aGCProps[ "draw:textarea-vertical-align" ] = "top";
957 aGCProps[ "fo:min-height"] = "0cm";
958 aGCProps[ "fo:min-width"] = "0cm";
959 aGCProps[ "fo:padding-top" ] = "0cm";
960 aGCProps[ "fo:padding-left" ] = "0cm";
961 aGCProps[ "fo:padding-right" ] = "0cm";
962 aGCProps[ "fo:padding-bottom" ] = "0cm";
963
964 StyleContainer::Style style1( "style:style", std::move(props1) );
965 StyleContainer::Style subStyle1( "style:graphic-properties", std::move(aGCProps) );
966 style1.SubStyles.push_back(&subStyle1);
967
968 elem.StyleId = m_rStyleContainer.getStyleId(style1);
969
970 if (elem.IsForText)
971 {
972 PropertyMap props2;
973 props2["style:family"] = "paragraph";
974
975 PropertyMap textProps;
976 SetFontsizeProperties(textProps, elem.FontSize);
977
978 StyleContainer::Style style2("style:style", std::move(props2));
979 StyleContainer::Style subStyle2("style:text-properties", std::move(textProps));
980 style2.SubStyles.push_back(&subStyle2);
982 }
983
984 elem.applyToChildren(*this);
985}
986
987void DrawXmlFinalizer::visit( ImageElement&, const std::list< std::unique_ptr<Element> >::const_iterator& )
988{
989}
990
991void DrawXmlFinalizer::visit( PageElement& elem, const std::list< std::unique_ptr<Element> >::const_iterator& )
992{
994 m_rProcessor.getStatusIndicator()->setValue( elem.PageNumber );
995
996 // transform from pixel to mm
997 double page_width = convPx2mm( elem.w ), page_height = convPx2mm( elem.h );
998
999 // calculate page margins out of the relevant children (paragraphs)
1000 elem.TopMargin = elem.h;
1001 elem.BottomMargin = 0;
1002 elem.LeftMargin = elem.w;
1003 elem.RightMargin = 0;
1004
1005 for( const auto& rxChild : elem.Children )
1006 {
1007 if( rxChild->x < elem.LeftMargin )
1008 elem.LeftMargin = rxChild->x;
1009 if( rxChild->y < elem.TopMargin )
1010 elem.TopMargin = rxChild->y;
1011 if( rxChild->x + rxChild->w > elem.RightMargin )
1012 elem.RightMargin = (rxChild->x + rxChild->w);
1013 if( rxChild->y + rxChild->h > elem.BottomMargin )
1014 elem.BottomMargin = (rxChild->y + rxChild->h);
1015 }
1016
1017 // transform margins to mm
1018 double left_margin = convPx2mm( elem.LeftMargin );
1019 double right_margin = convPx2mm( elem.RightMargin );
1020 double top_margin = convPx2mm( elem.TopMargin );
1021 double bottom_margin = convPx2mm( elem.BottomMargin );
1022
1023 // round left/top margin to nearest mm
1024 left_margin = rtl_math_round( left_margin, 0, rtl_math_RoundingMode_Floor );
1025 top_margin = rtl_math_round( top_margin, 0, rtl_math_RoundingMode_Floor );
1026 // round (fuzzy) right/bottom margin to nearest cm
1027 right_margin = rtl_math_round( right_margin, right_margin >= 10 ? -1 : 0, rtl_math_RoundingMode_Floor );
1028 bottom_margin = rtl_math_round( bottom_margin, bottom_margin >= 10 ? -1 : 0, rtl_math_RoundingMode_Floor );
1029
1030 // set reasonable default in case of way too large margins
1031 // e.g. no paragraph case
1032 if( left_margin > page_width/2.0 - 10 )
1033 left_margin = 10;
1034 if( right_margin > page_width/2.0 - 10 )
1035 right_margin = 10;
1036 if( top_margin > page_height/2.0 - 10 )
1037 top_margin = 10;
1038 if( bottom_margin > page_height/2.0 - 10 )
1039 bottom_margin = 10;
1040
1041 // catch the weird cases
1042 if( left_margin < 0 )
1043 left_margin = 0;
1044 if( right_margin < 0 )
1045 right_margin = 0;
1046 if( top_margin < 0 )
1047 top_margin = 0;
1048 if( bottom_margin < 0 )
1049 bottom_margin = 0;
1050
1051 // widely differing margins are unlikely to be correct
1052 if( right_margin > left_margin*1.5 )
1053 right_margin = left_margin;
1054
1055 elem.LeftMargin = convmm2Px( left_margin );
1056 elem.RightMargin = convmm2Px( right_margin );
1057 elem.TopMargin = convmm2Px( top_margin );
1058 elem.BottomMargin = convmm2Px( bottom_margin );
1059
1060 // get styles for paragraphs
1061 PropertyMap aPageProps;
1062 PropertyMap aPageLayoutProps;
1063 aPageLayoutProps[ "fo:margin-top" ] = unitMMString( top_margin );
1064 aPageLayoutProps[ "fo:margin-bottom" ] = unitMMString( bottom_margin );
1065 aPageLayoutProps[ "fo:margin-left" ] = unitMMString( left_margin );
1066 aPageLayoutProps[ "fo:margin-right" ] = unitMMString( right_margin );
1067 aPageLayoutProps[ "fo:page-width" ] = unitMMString( page_width );
1068 aPageLayoutProps[ "fo:page-height" ] = unitMMString( page_height );
1069 aPageLayoutProps[ "style:print-orientation" ]= elem.w < elem.h ? std::u16string_view(u"portrait") : std::u16string_view(u"landscape");
1070 aPageLayoutProps[ "style:writing-mode" ]= "lr-tb";
1071
1072 StyleContainer::Style aStyle( "style:page-layout", std::move(aPageProps));
1073 StyleContainer::Style aSubStyle( "style:page-layout-properties", std::move(aPageLayoutProps));
1074 aStyle.SubStyles.push_back(&aSubStyle);
1075 sal_Int32 nPageStyle = m_rStyleContainer.impl_getStyleId( aStyle, false );
1076
1077 // create master page
1078 OUString aMasterPageLayoutName = m_rStyleContainer.getStyleName( nPageStyle );
1079 aPageProps[ "style:page-layout-name" ] = aMasterPageLayoutName;
1080
1081 StyleContainer::Style aMPStyle( "style:master-page", std::move(aPageProps));
1082
1083 elem.StyleId = m_rStyleContainer.impl_getStyleId( aMPStyle,false );
1084
1085 // create styles for children
1086 elem.applyToChildren(*this);
1087}
1088
1089void DrawXmlFinalizer::visit( DocumentElement& elem, const std::list< std::unique_ptr<Element> >::const_iterator& )
1090{
1091 elem.applyToChildren(*this);
1092}
1093
1094}
1095
1096/* 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)
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