LibreOffice Module sdext (master) 1
pdfiprocessor.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
20
21#include <pdfiprocessor.hxx>
22#include <xmlemitter.hxx>
23#include <pdfihelper.hxx>
24#include <imagecontainer.hxx>
25#include <genericelements.hxx>
26#include "style.hxx"
27#include <treevisiting.hxx>
28
29#include <sal/log.hxx>
30
36#include <i18nutil/unicode.hxx>
37
38using namespace com::sun::star;
39
40
41namespace pdfi
42{
43
44 PDFIProcessor::PDFIProcessor( const uno::Reference< task::XStatusIndicator >& xStat ,
45 css::uno::Reference< css::uno::XComponentContext > const & xContext) :
46
47 m_xContext(xContext),
48 prevCharWidth(0),
49 m_pDocument( ElementFactory::createDocumentElement() ),
50 m_pCurPage(nullptr),
51 m_pCurElement(nullptr),
52 m_nNextFontId( 1 ),
53 m_nNextGCId( 1 ),
54 m_nPages(0),
55 m_nNextZOrder( 1 ),
56 m_xStatusIndicator( xStat )
57{
58 FontAttributes aDefFont;
59 aDefFont.familyName = "Helvetica";
60 aDefFont.fontWeight = u"normal";
61 aDefFont.isItalic = false;
62 aDefFont.size = 10*PDFI_OUTDEV_RESOLUTION/72;
63 m_aIdToFont.insert({0, aDefFont});
64 m_aFontToId.insert({aDefFont, 0});
65
66 GraphicsContext aDefGC;
67 m_aGCStack.push_back( aDefGC );
68 m_aGCToId.insert({aDefGC, 0});
69 m_aIdToGC.insert({0, aDefGC});
70}
71
72void PDFIProcessor::setPageNum( sal_Int32 nPages )
73{
74 m_nPages = nPages;
75}
76
77
79{
80 GraphicsContextStack::value_type const a(m_aGCStack.back());
81 m_aGCStack.push_back(a);
82}
83
85{
86 m_aGCStack.pop_back();
87}
88
89void PDFIProcessor::setFlatness( double value )
90{
92}
93
94void PDFIProcessor::setTransformation( const geometry::AffineMatrix2D& rMatrix )
95{
98 rMatrix );
99}
100
101void PDFIProcessor::setLineDash( const uno::Sequence<double>& dashes,
102 double /*start*/ )
103{
104 // TODO(F2): factor in start offset
105 GraphicsContext& rContext( getCurrentContext() );
107}
108
110{
111 getCurrentContext().LineJoin = nJoin;
112}
113
115{
116 getCurrentContext().LineCap = nCap;
117}
118
120{
121 SAL_WARN("sdext.pdfimport", "PDFIProcessor::setMiterLimit(): not supported by ODF");
122}
123
125{
126 getCurrentContext().LineWidth = nWidth;
127}
128
129void PDFIProcessor::setFillColor( const rendering::ARGBColor& rColor )
130{
131 getCurrentContext().FillColor = rColor;
132}
133
134void PDFIProcessor::setStrokeColor( const rendering::ARGBColor& rColor )
135{
136 getCurrentContext().LineColor = rColor;
137}
138
140{
141 FontAttributes aChangedFont( i_rFont );
143 // for text render modes, please see PDF reference manual
144 if (rGC.TextRenderMode == 1)
145 {
146 aChangedFont.isOutline = true;
147 }
148 else if (rGC.TextRenderMode == 2)
149 {
150 // tdf#81484: faux bold is represented as "stroke+fill" (while using the same color for both stroke and fill) in pdf.
151 // Convert to bold instead if the stroke color is the same as the fill color,
152 // otherwise it should be outline.
154 aChangedFont.fontWeight = u"bold";
155 else
156 aChangedFont.isOutline = true;
157 }
158 FontToIdMap::const_iterator it = m_aFontToId.find( aChangedFont );
159 if( it != m_aFontToId.end() )
160 rGC.FontId = it->second;
161 else
162 {
163 m_aFontToId[ aChangedFont ] = m_nNextFontId;
164 m_aIdToFont[ m_nNextFontId ] = aChangedFont;
165 rGC.FontId = m_nNextFontId;
167 }
168}
169
170void PDFIProcessor::setTextRenderMode( sal_Int32 i_nMode )
171{
173 rGC.TextRenderMode = i_nMode;
174 IdToFontMap::iterator it = m_aIdToFont.find( rGC.FontId );
175 if( it != m_aIdToFont.end() )
176 setFont( it->second );
177}
178
179sal_Int32 PDFIProcessor::getFontId( const FontAttributes& rAttr ) const
180{
181 const sal_Int32 nCurFont = getCurrentContext().FontId;
182 const_cast<PDFIProcessor*>(this)->setFont( rAttr );
183 const sal_Int32 nFont = getCurrentContext().FontId;
184 const_cast<PDFIProcessor*>(this)->getCurrentContext().FontId = nCurFont;
185
186 return nFont;
187}
188
189// line diagnose block - start
191{
192 if (m_GlyphsList.empty())
193 return;
194
195 double spaceDetectBoundary = 0.0;
196
197 // Try to find space glyph and its width
198 for (CharGlyph & i : m_GlyphsList)
199 {
200 OUString& glyph = i.getGlyph();
201
202 sal_Unicode ch = '\0';
203 if (!glyph.isEmpty())
204 ch = glyph[0];
205
206 if ((ch == 0x20) || (ch == 0xa0))
207 {
208 double spaceWidth = i.getWidth();
209 spaceDetectBoundary = spaceWidth * 0.5;
210 break;
211 }
212 }
213
214 // If space glyph is not found, use average glyph width instead
215 if (spaceDetectBoundary == 0.0)
216 {
217 double avgGlyphWidth = 0.0;
218 for (const CharGlyph & i : m_GlyphsList)
219 avgGlyphWidth += i.getWidth();
220 avgGlyphWidth /= m_GlyphsList.size();
221 spaceDetectBoundary = avgGlyphWidth * 0.2;
222 }
223
225 m_GlyphsList[0].getCurElement(),
226 getGCId(m_GlyphsList[0].getGC()));
227 frame->ZOrder = m_nNextZOrder++;
228 frame->IsForText = true;
229 frame->FontSize = getFont(m_GlyphsList[0].getGC().FontId).size;
231
232 for (size_t i = 0; i < m_GlyphsList.size(); i++)
233 {
234 bool prependSpace = false;
236 para,
237 getGCId(m_GlyphsList[i].getGC()),
238 m_GlyphsList[i].getGC().FontId);
239 if (i == 0)
240 {
241 text->x = m_GlyphsList[0].getGC().Transformation.get(0, 2);
242 text->y = m_GlyphsList[0].getGC().Transformation.get(1, 2);
243 text->w = 0;
244 text->h = 0;
246 frame->updateGeometryWith(para);
247 }
248 else
249 {
250 double spaceSize = m_GlyphsList[i].getPrevSpaceWidth();
251 prependSpace = spaceSize > spaceDetectBoundary;
252 }
253 if (prependSpace)
254 text->Text.append(" ");
255 text->Text.append(m_GlyphsList[i].getGlyph());
256 }
257
258 m_GlyphsList.clear();
259}
260
261void PDFIProcessor::drawGlyphs( const OUString& rGlyphs,
262 const geometry::RealRectangle2D& rRect,
263 const geometry::Matrix2D& rFontMatrix,
264 double fontSize)
265{
266 double ascent = getFont(getCurrentContext().FontId).ascent;
267
268 basegfx::B2DHomMatrix fontMatrix(
269 rFontMatrix.m00, rFontMatrix.m01, 0.0,
270 rFontMatrix.m10, rFontMatrix.m11, 0.0);
271 fontMatrix.scale(fontSize, fontSize);
272
273 basegfx::B2DHomMatrix totalTextMatrix1(fontMatrix);
274 basegfx::B2DHomMatrix totalTextMatrix2(fontMatrix);
275 totalTextMatrix1.translate(rRect.X1, rRect.Y1);
276 totalTextMatrix2.translate(rRect.X2, rRect.Y2);
277
278 basegfx::B2DHomMatrix corrMatrix;
279 corrMatrix.scale(1.0, -1.0);
280 corrMatrix.translate(0.0, ascent);
281 totalTextMatrix1 = totalTextMatrix1 * corrMatrix;
282 totalTextMatrix2 = totalTextMatrix2 * corrMatrix;
283
284 totalTextMatrix1 *= getCurrentContext().Transformation;
285 totalTextMatrix2 *= getCurrentContext().Transformation;
286
287 basegfx::B2DHomMatrix invMatrix(totalTextMatrix1);
289 invMatrix.invert();
290 invPrevMatrix.invert();
291 basegfx::B2DHomMatrix offsetMatrix1(totalTextMatrix1);
292 basegfx::B2DHomMatrix offsetMatrix2(totalTextMatrix2);
293 offsetMatrix1 *= invPrevMatrix;
294 offsetMatrix2 *= invMatrix;
295
296 double charWidth = offsetMatrix2.get(0, 2);
297 double prevSpaceWidth = offsetMatrix1.get(0, 2) - prevCharWidth;
298
299 if ((totalTextMatrix1.get(0, 0) != prevTextMatrix.get(0, 0)) ||
300 (totalTextMatrix1.get(0, 1) != prevTextMatrix.get(0, 1)) ||
301 (totalTextMatrix1.get(1, 0) != prevTextMatrix.get(1, 0)) ||
302 (totalTextMatrix1.get(1, 1) != prevTextMatrix.get(1, 1)) ||
303 (offsetMatrix1.get(0, 2) < 0.0) ||
304 (prevSpaceWidth > prevCharWidth * 1.3) ||
305 (!basegfx::fTools::equalZero(offsetMatrix1.get(1, 2), 0.0001)))
306 {
308 }
309
310 CharGlyph aGlyph(m_pCurElement, getCurrentContext(), charWidth, prevSpaceWidth, rGlyphs);
311 aGlyph.getGC().Transformation = totalTextMatrix1;
312 m_GlyphsList.push_back(aGlyph);
313
314 prevCharWidth = charWidth;
315 prevTextMatrix = totalTextMatrix1;
316}
317
319{
321 if( pText )
322 m_pCurElement = pText->Parent;
323}
324
326{
328
329 basegfx::B2DTuple aScale, aTranslation;
330 double fRotate, fShearX;
331 rGC.Transformation.decompose(aScale, aTranslation, fRotate, fShearX);
332
333 const sal_Int32 nGCId = getGCId(rGC);
335 ImageElement* pImageElement = ElementFactory::createImageElement( pFrame, nGCId, nImage );
336 pFrame->x = pImageElement->x = aTranslation.getX();
337 pFrame->y = pImageElement->y = aTranslation.getY();
338 pFrame->w = pImageElement->w = aScale.getX();
339 pFrame->h = pImageElement->h = aScale.getY();
340 pFrame->ZOrder = m_nNextZOrder++;
341
342 // Poppler wrapper takes into account that vertical axes of PDF and ODF are opposite,
343 // and it flips matrix vertically (see poppler's GfxState::GfxState()).
344 // But image internal vertical axis is independent of PDF vertical axis direction,
345 // so arriving matrix is extra-flipped relative to image.
346 // We force vertical flip here to compensate that.
347 pFrame->MirrorVertical = true;
348}
349
350void PDFIProcessor::drawMask(const uno::Sequence<beans::PropertyValue>& xBitmap,
351 bool /*bInvert*/ )
352{
353 // TODO(F3): Handle mask and inversion
354 setupImage( m_aImages.addImage(xBitmap) );
355}
356
357void PDFIProcessor::drawImage(const uno::Sequence<beans::PropertyValue>& xBitmap )
358{
359 setupImage( m_aImages.addImage(xBitmap) );
360}
361
362void PDFIProcessor::drawColorMaskedImage(const uno::Sequence<beans::PropertyValue>& xBitmap,
363 const uno::Sequence<uno::Any>& /*xMaskColors*/ )
364{
365 // TODO(F3): Handle mask colors
366 setupImage( m_aImages.addImage(xBitmap) );
367}
368
369void PDFIProcessor::drawMaskedImage(const uno::Sequence<beans::PropertyValue>& xBitmap,
370 const uno::Sequence<beans::PropertyValue>& /*xMask*/,
371 bool /*bInvertMask*/)
372{
373 // TODO(F3): Handle mask and inversion
374 setupImage( m_aImages.addImage(xBitmap) );
375}
376
377void PDFIProcessor::drawAlphaMaskedImage(const uno::Sequence<beans::PropertyValue>& xBitmap,
378 const uno::Sequence<beans::PropertyValue>& /*xMask*/)
379{
380 // TODO(F3): Handle mask
381
382 setupImage( m_aImages.addImage(xBitmap) );
383
384}
385
386void PDFIProcessor::strokePath( const uno::Reference< rendering::XPolyPolygon2D >& rPath )
387{
390
394 aPoly,
395 PATH_STROKE );
396 pPoly->updateGeometry();
397 pPoly->ZOrder = m_nNextZOrder++;
398}
399
400void PDFIProcessor::fillPath( const uno::Reference< rendering::XPolyPolygon2D >& rPath )
401{
404
408 aPoly,
409 PATH_FILL );
410 pPoly->updateGeometry();
411 pPoly->ZOrder = m_nNextZOrder++;
412}
413
414void PDFIProcessor::eoFillPath( const uno::Reference< rendering::XPolyPolygon2D >& rPath )
415{
418
422 aPoly,
423 PATH_EOFILL );
424 pPoly->updateGeometry();
425 pPoly->ZOrder = m_nNextZOrder++;
426}
427
428void PDFIProcessor::intersectClip(const uno::Reference< rendering::XPolyPolygon2D >& rPath)
429{
430 // TODO(F3): interpret fill mode
434
435 if( aCurClip.count() ) // #i92985# adapted API from (..., false, false) to (..., true, false)
436 aNewClip = basegfx::utils::clipPolyPolygonOnPolyPolygon( aCurClip, aNewClip, true, false );
437
438 getCurrentContext().Clip = aNewClip;
439}
440
441void PDFIProcessor::intersectEoClip(const uno::Reference< rendering::XPolyPolygon2D >& rPath)
442{
443 // TODO(F3): interpret fill mode
447
448 if( aCurClip.count() ) // #i92985# adapted API from (..., false, false) to (..., true, false)
449 aNewClip = basegfx::utils::clipPolyPolygonOnPolyPolygon( aCurClip, aNewClip, true, false );
450
451 getCurrentContext().Clip = aNewClip;
452}
453
454void PDFIProcessor::hyperLink( const geometry::RealRectangle2D& rBounds,
455 const OUString& rURI )
456{
457 if( !rURI.isEmpty() )
458 {
461 rURI );
462 pLink->x = rBounds.X1;
463 pLink->y = rBounds.Y1;
464 pLink->w = rBounds.X2-rBounds.X1;
465 pLink->h = rBounds.Y2-rBounds.Y1;
466 }
467}
468
469const FontAttributes& PDFIProcessor::getFont( sal_Int32 nFontId ) const
470{
471 IdToFontMap::const_iterator it = m_aIdToFont.find( nFontId );
472 if( it == m_aIdToFont.end() )
473 it = m_aIdToFont.find( 0 );
474 return it->second;
475}
476
478{
479 sal_Int32 nGCId = 0;
480 auto it = m_aGCToId.find( rGC );
481 if( it != m_aGCToId.end() )
482 nGCId = it->second;
483 else
484 {
485 m_aGCToId.insert({rGC, m_nNextGCId});
486 m_aIdToGC.insert({m_nNextGCId, rGC});
487 nGCId = m_nNextGCId;
488 m_nNextGCId++;
489 }
490
491 return nGCId;
492}
493
495{
496 auto it = m_aIdToGC.find( nGCId );
497 if( it == m_aIdToGC.end() )
498 it = m_aIdToGC.find( 0 );
499 return it->second;
500}
501
503{
504 processGlyphLine(); // draw last line
505 if( m_xStatusIndicator.is()
506 && m_pCurPage
508 )
509 m_xStatusIndicator->end();
510}
511
512void PDFIProcessor::startPage( const geometry::RealSize2D& rSize )
513{
514 // initial clip is to page bounds
517 basegfx::B2DRange( 0, 0, rSize.Width, rSize.Height )));
518
519 sal_Int32 nNextPageNr = m_pCurPage ? m_pCurPage->PageNumber+1 : 1;
520 if( m_xStatusIndicator.is() )
521 {
522 if( nNextPageNr == 1 )
523 startIndicator( " " );
524 m_xStatusIndicator->setValue( nNextPageNr );
525 }
528 m_pCurPage->w = rSize.Width;
529 m_pCurPage->h = rSize.Height;
530 m_nNextZOrder = 1;
531
532
533}
534
536 const TreeVisitorFactory& rVisitorFactory )
537{
538#if OSL_DEBUG_LEVEL > 0
539 m_pDocument->emitStructure( 0 );
540#endif
541
542 ElementTreeVisitorSharedPtr optimizingVisitor(
543 rVisitorFactory.createOptimizingVisitor(*this));
544 // FIXME: localization
545 startIndicator( " " );
546 m_pDocument->visitedBy( *optimizingVisitor, std::list<std::unique_ptr<Element>>::const_iterator());
547
548#if OSL_DEBUG_LEVEL > 0
549 m_pDocument->emitStructure( 0 );
550#endif
551
552 // get styles
553 StyleContainer aStyles;
554 ElementTreeVisitorSharedPtr finalizingVisitor(
555 rVisitorFactory.createStyleCollectingVisitor(aStyles,*this));
556 // FIXME: localization
557
558 m_pDocument->visitedBy( *finalizingVisitor, std::list<std::unique_ptr<Element>>::const_iterator() );
559
560 EmitContext aContext( rEmitter, aStyles, m_aImages, *this, m_xStatusIndicator, m_xContext );
561 ElementTreeVisitorSharedPtr aEmittingVisitor(
562 rVisitorFactory.createEmittingVisitor(aContext));
563
564 PropertyMap aProps;
565 // document prolog
566 #define OASIS_STR "urn:oasis:names:tc:opendocument:xmlns:"
567 aProps[ "xmlns:office" ] = OASIS_STR "office:1.0" ;
568 aProps[ "xmlns:style" ] = OASIS_STR "style:1.0" ;
569 aProps[ "xmlns:text" ] = OASIS_STR "text:1.0" ;
570 aProps[ "xmlns:svg" ] = OASIS_STR "svg-compatible:1.0" ;
571 aProps[ "xmlns:table" ] = OASIS_STR "table:1.0" ;
572 aProps[ "xmlns:draw" ] = OASIS_STR "drawing:1.0" ;
573 aProps[ "xmlns:fo" ] = OASIS_STR "xsl-fo-compatible:1.0" ;
574 aProps[ "xmlns:xlink"] = "http://www.w3.org/1999/xlink";
575 aProps[ "xmlns:dc"] = "http://purl.org/dc/elements/1.1/";
576 aProps[ "xmlns:number"] = OASIS_STR "datastyle:1.0" ;
577 aProps[ "xmlns:presentation"] = OASIS_STR "presentation:1.0" ;
578 aProps[ "xmlns:math"] = "http://www.w3.org/1998/Math/MathML";
579 aProps[ "xmlns:form"] = OASIS_STR "form:1.0" ;
580 aProps[ "xmlns:script"] = OASIS_STR "script:1.0" ;
581 aProps[ "xmlns:dom"] = "http://www.w3.org/2001/xml-events";
582 aProps[ "xmlns:xforms"] = "http://www.w3.org/2002/xforms";
583 aProps[ "xmlns:xsd"] = "http://www.w3.org/2001/XMLSchema";
584 aProps[ "xmlns:xsi"] = "http://www.w3.org/2001/XMLSchema-instance";
585 aProps[ "office:version" ] = "1.0";
586
587 aContext.rEmitter.beginTag( "office:document", aProps );
588
589 // emit style list
590 aStyles.emit( aContext, *aEmittingVisitor );
591
592 m_pDocument->visitedBy( *aEmittingVisitor, std::list<std::unique_ptr<Element>>::const_iterator() );
593 aContext.rEmitter.endTag( "office:document" );
594 endIndicator();
595}
596
597void PDFIProcessor::startIndicator( const OUString& rText )
598{
599 sal_Int32 nElements = m_nPages;
600 if( !m_xStatusIndicator.is() )
601 return;
602
603 sal_Int32 nLength = rText.getLength();
604 OUStringBuffer aStr( nLength*2 );
605 const sal_Unicode* pText = rText.getStr();
606 for( int i = 0; i < nLength; i++ )
607 {
608 if( nLength-i > 1&&
609 pText[i] == '%' &&
610 pText[i+1] == 'd'
611 )
612 {
613 aStr.append( nElements );
614 i++;
615 }
616 else
617 aStr.append( pText[i] );
618 }
619 m_xStatusIndicator->start( aStr.makeStringAndClear(), nElements );
620}
621
623{
624 if( m_xStatusIndicator.is() )
625 m_xStatusIndicator->end();
626}
627
628static bool lr_tb_sort( std::unique_ptr<Element> const & pLeft, std::unique_ptr<Element> const & pRight )
629{
630 // Ensure irreflexivity (which could be compromised if h or w is negative):
631 if (pLeft == pRight)
632 return false;
633
634 // first: top-bottom sorting
635
636 // Note: allow for 10% overlap on text lines since text lines are usually
637 // of the same order as font height whereas the real paint area
638 // of text is usually smaller
639 double fudge_factor_left = 0.0, fudge_factor_right = 0.0;
640 if( pLeft->dynCastAsTextElement() )
641 fudge_factor_left = 0.1;
642 if( pRight->dynCastAsTextElement() )
643 fudge_factor_right = 0.1;
644
645 // Allow negative height
646 double lower_boundary_left = pLeft->y + std::max(pLeft->h, 0.0) - fabs(pLeft->h) * fudge_factor_left;
647 double lower_boundary_right = pRight->y + std::max(pRight->h, 0.0) - fabs(pRight->h) * fudge_factor_right;
648 double upper_boundary_left = pLeft->y + std::min(pLeft->h, 0.0);
649 double upper_boundary_right = pRight->y + std::min(pRight->h, 0.0);
650 // if left's lower boundary is above right's upper boundary
651 // then left is smaller
652 if( lower_boundary_left < upper_boundary_right )
653 return true;
654 // if right's lower boundary is above left's upper boundary
655 // then left is definitely not smaller
656 if( lower_boundary_right < upper_boundary_left )
657 return false;
658
659 // Allow negative width
660 double left_boundary_left = pLeft->y + std::min(pLeft->w, 0.0);
661 double left_boundary_right = pRight->y + std::min(pRight->w, 0.0);
662 double right_boundary_left = pLeft->y + std::max(pLeft->w, 0.0);
663 double right_boundary_right = pRight->y + std::max(pRight->w, 0.0);
664 // by now we have established that left and right are inside
665 // a "line", that is they have vertical overlap
666 // second: left-right sorting
667 // if left's right boundary is left to right's left boundary
668 // then left is smaller
669 if( right_boundary_left < left_boundary_right )
670 return true;
671 // if right's right boundary is left to left's left boundary
672 // then left is definitely not smaller
673 if( right_boundary_right < left_boundary_left )
674 return false;
675
676 // here we have established vertical and horizontal overlap
677 // so sort left first, top second
678 if( pLeft->x < pRight->x )
679 return true;
680 if( pRight->x < pLeft->x )
681 return false;
682 if( pLeft->y < pRight->y )
683 return true;
684
685 return false;
686}
687
689{
690 if( pEle->Children.empty() )
691 return;
692
693 // sort method from std::list is equivalent to stable_sort
694 // See S Meyers, Effective STL
695 pEle->Children.sort(lr_tb_sort);
696}
697
698/* Produce mirrored-image for each code point which has the Bidi_Mirrored property, within a string.
699 This need to be done in forward order.
700*/
701OUString PDFIProcessor::SubstituteBidiMirrored(const OUString& rString)
702{
703 const sal_Int32 nLen = rString.getLength();
704 OUStringBuffer aMirror(nLen);
705
706 for (sal_Int32 i = 0; i < nLen;) {
707 const sal_uInt32 nCodePoint = rString.iterateCodePoints(&i);
708 aMirror.appendUtf32(unicode::GetMirroredChar(nCodePoint));
709 }
710 return aMirror.makeStringAndClear();
711}
712
713}
714
715/* 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)
void transform(const basegfx::B2DHomMatrix &rMatrix)
sal_uInt32 count() const
TYPE getX() const
TYPE getY() const
GraphicsContext & getGC()
static ParagraphElement * createParagraphElement(Element *pParent)
static FrameElement * createFrameElement(Element *pParent, sal_Int32 nGCId)
static PageElement * createPageElement(Element *pParent, sal_Int32 nPageNr)
static PolyPolyElement * createPolyPolyElement(Element *pParent, sal_Int32 nGCId, const basegfx::B2DPolyPolygon &rPolyPoly, sal_Int8 nAction)
static TextElement * createTextElement(Element *pParent, sal_Int32 nGCId, sal_Int32 nFontId)
static ImageElement * createImageElement(Element *pParent, sal_Int32 nGCId, ImageId nImage)
static HyperlinkElement * createHyperlinkElement(Element *pParent, const OUString &rURI)
ImageId addImage(const css::uno::Sequence< css::beans::PropertyValue > &xBitmap)
Main entry from the parser.
ImageContainer m_aImages
void startIndicator(const OUString &rText)
std::vector< CharGlyph > m_GlyphsList
virtual void setLineWidth(double) override
virtual void drawColorMaskedImage(const css::uno::Sequence< css::beans::PropertyValue > &xBitmap, const css::uno::Sequence< css::uno::Any > &xMaskColors) override
Given image must already be color-mapped and normalized to sRGB.
css::uno::Reference< css::uno::XComponentContext > m_xContext
virtual void setFlatness(double) override
virtual void setTransformation(const css::geometry::AffineMatrix2D &rMatrix) override
virtual void setMiterLimit(double) override
const GraphicsContext & getGraphicsContext(sal_Int32 nGCId) const
virtual void intersectClip(const css::uno::Reference< css::rendering::XPolyPolygon2D > &rPath) override
virtual void setLineDash(const css::uno::Sequence< double > &dashes, double start) override
virtual void popState() override
virtual void hyperLink(const css::geometry::RealRectangle2D &rBounds, const OUString &rURI) override
basegfx::B2DHomMatrix prevTextMatrix
const FontAttributes & getFont(sal_Int32 nFontId) const
virtual void setPageNum(sal_Int32 nNumPages) override
Total number of pages for upcoming document.
virtual void strokePath(const css::uno::Reference< css::rendering::XPolyPolygon2D > &rPath) override
sal_Int32 getFontId(const FontAttributes &rAttr) const
virtual void setLineCap(sal_Int8) override
virtual void pushState() override
void setupImage(ImageId nImage)
static void sortElements(Element *pElement)
PDFIProcessor(const css::uno::Reference< css::task::XStatusIndicator > &xStat, css::uno::Reference< css::uno::XComponentContext > const &xContext)
virtual void endPage() override
virtual void intersectEoClip(const css::uno::Reference< css::rendering::XPolyPolygon2D > &rPath) override
virtual void drawMask(const css::uno::Sequence< css::beans::PropertyValue > &xBitmap, bool bInvert) override
draws given bitmap as a mask (using current fill color)
virtual void setStrokeColor(const css::rendering::ARGBColor &rColor) override
PageElement * m_pCurPage
virtual void drawMaskedImage(const css::uno::Sequence< css::beans::PropertyValue > &xBitmap, const css::uno::Sequence< css::beans::PropertyValue > &xMask, bool bInvertMask) override
static OUString SubstituteBidiMirrored(const OUString &rString)
GraphicsContext & getCurrentContext()
virtual void setLineJoin(sal_Int8) override
virtual void setFillColor(const css::rendering::ARGBColor &rColor) override
GraphicsContextStack m_aGCStack
std::shared_ptr< DocumentElement > m_pDocument
virtual void setTextRenderMode(sal_Int32) override
virtual void eoFillPath(const css::uno::Reference< css::rendering::XPolyPolygon2D > &rPath) override
sal_Int32 getGCId(const GraphicsContext &rGC)
virtual void drawGlyphs(const OUString &rGlyphs, const css::geometry::RealRectangle2D &rRect, const css::geometry::Matrix2D &rFontMatrix, double fontSize) override
virtual void drawAlphaMaskedImage(const css::uno::Sequence< css::beans::PropertyValue > &xImage, const css::uno::Sequence< css::beans::PropertyValue > &xMask) override
css::uno::Reference< css::task::XStatusIndicator > m_xStatusIndicator
virtual void startPage(const css::geometry::RealSize2D &rSize) override
virtual void endText() override
issued when a sequence of associated glyphs is drawn
virtual void setFont(const FontAttributes &rFont) override
virtual void drawImage(const css::uno::Sequence< css::beans::PropertyValue > &xBitmap) override
Given image must already be color-mapped and normalized to sRGB.
virtual void fillPath(const css::uno::Reference< css::rendering::XPolyPolygon2D > &rPath) override
void emit(XmlEmitter &rEmitter, const TreeVisitorFactory &rVisitorFactory)
void emit(EmitContext &rContext, ElementTreeVisitor &rContainedElemVisitor)
Definition: style.cxx:209
Output interface to ODF.
Definition: xmlemitter.hxx:33
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.
static sal_uInt32 GetMirroredChar(sal_uInt32)
Any value
sal_Int32 nElements
float u
uno_Any a
SvBaseLink * pLink
#define SAL_WARN(area, stream)
aStr
def text(shape, orig_st)
bool equalZero(const T &rfVal)
::basegfx::B2DHomMatrix & homMatrixFromAffineMatrix(::basegfx::B2DHomMatrix &output, const geometry::AffineMatrix2D &input)
::basegfx::B2DPolyPolygon b2DPolyPolygonFromXPolyPolygon2D(const uno::Reference< rendering::XPolyPolygon2D > &xPoly)
B2DPolygon createPolygonFromRect(const B2DRectangle &rRect, double fRadiusX, double fRadiusY)
B2DPolyPolygon clipPolyPolygonOnPolyPolygon(const B2DPolyPolygon &rCandidate, const B2DPolyPolygon &rClip, bool bInside, bool bStroke, size_t *pPointLimit)
DstType sequenceToContainer(const css::uno::Sequence< SrcType > &i_Sequence)
int i
std::shared_ptr< ElementTreeVisitor > ElementTreeVisitorSharedPtr
std::unordered_map< OUString, OUString > PropertyMap
Definition: pdfihelper.hxx:44
static bool lr_tb_sort(std::unique_ptr< Element > const &pLeft, std::unique_ptr< Element > const &pRight)
@ PATH_EOFILL
Definition: pdfihelper.hxx:48
@ PATH_STROKE
Definition: pdfihelper.hxx:48
@ PATH_FILL
Definition: pdfihelper.hxx:48
sal_Int32 ImageId
Definition: pdfihelper.hxx:45
#define PDFI_OUTDEV_RESOLUTION
Definition: pdfihelper.hxx:38
#define OASIS_STR
virtual const TextElement * dynCastAsTextElement() const
To avoid some dynamic_cast cost.
std::list< std::unique_ptr< Element > > Children
void updateGeometryWith(const Element *pMergeFrom)
Union element geometry with given element.
XmlEmitter & rEmitter
css::rendering::ARGBColor FillColor
Definition: pdfihelper.hxx:100
css::rendering::ARGBColor LineColor
Definition: pdfihelper.hxx:99
basegfx::B2DHomMatrix Transformation
Definition: pdfihelper.hxx:110
std::vector< double > DashArray
Definition: pdfihelper.hxx:107
basegfx::B2DPolyPolygon Clip
Definition: pdfihelper.hxx:111
Tree manipulation factory.
virtual std::shared_ptr< ElementTreeVisitor > createOptimizingVisitor(PDFIProcessor &) const =0
Create visitor that combines tree nodes.
virtual std::shared_ptr< ElementTreeVisitor > createStyleCollectingVisitor(StyleContainer &, PDFIProcessor &) const =0
Create visitor that prepares style info.
virtual std::shared_ptr< ElementTreeVisitor > createEmittingVisitor(EmitContext &) const =0
Create visitor that emits tree to an output target.
sal_uInt16 sal_Unicode
signed char sal_Int8
const uno::Reference< uno::XComponentContext > m_xContext
Definition: wrapper.cxx:144
sal_Int32 nLength