33#include <osl/diagnose.h>
34#include <com/sun/star/i18n/CharacterClassification.hpp>
35#include <com/sun/star/i18n/DirectionProperty.hpp>
60 mxCharClass = CharacterClassification::create(xContext);
70 const char* pType =
dynamic_cast<DrawElement*
>(elem.
Children.front().get()) ?
"draw:a" :
"text:a";
73 aProps[
"xlink:type" ] =
"simple";
74 aProps[
"xlink:href" ] = elem.
URI;
75 aProps[
"office:target-frame-name" ] =
"_blank";
76 aProps[
"xlink:show" ] =
"new";
79 auto this_it = elem.
Children.begin();
80 while( this_it != elem.
Children.end() && this_it->get() != &elem )
82 (*this_it)->visitedBy( *
this, this_it );
90 if( elem.
Text.isEmpty() )
100 aProps[ OUString(
"text:style-name" ) ] =
104 OUString str(elem.
Text.toString());
111 for(
int i=1;
i< elem.
Text.getLength();
i++)
113 i18n::DirectionProperty
nType =
static_cast<i18n::DirectionProperty
>(xCC->getCharacterDirection( str,
i ));
114 if (
nType == i18n::DirectionProperty_RIGHT_TO_LEFT ||
115 nType == i18n::DirectionProperty_RIGHT_TO_LEFT_ARABIC ||
116 nType == i18n::DirectionProperty_RIGHT_TO_LEFT_EMBEDDING ||
117 nType == i18n::DirectionProperty_RIGHT_TO_LEFT_OVERRIDE
128 str = ::comphelper::string::reverseCodePoints(str);
134 for (
int i = 0;
i < elem.
Text.getLength();
i++)
137 if (strToken == strSpace || strToken == strNbSpace)
139 aProps[
"text:c"] =
"1";
143 else if (strToken == tabSpace)
152 auto this_it = elem.
Children.begin();
153 while( this_it != elem.
Children.end() && this_it->get() != &elem )
155 (*this_it)->visitedBy( *
this, this_it );
169 const char* pTagType =
"text:p";
174 auto this_it = elem.
Children.begin();
175 while( this_it != elem.
Children.end() && this_it->get() != &elem )
177 (*this_it)->visitedBy( *
this, this_it );
188 double rel_x = rElem.
x, rel_y = rElem.
y;
194 while ((pAnchor = pAnchor->
Parent))
206 ? std::u16string_view(
u"character") : std::u16string_view(
u"paragraph");
211 rProps[
"text:anchor-type" ] =
"page";
212 rProps[
"text:anchor-page-number" ] = OUString::number(pPage->
PageNumber);
218 rProps[
"draw:z-index" ] = OUString::number( rElem.
ZOrder );
236 double fRotate, fShearX;
240 OUStringBuffer
aBuf( 256 );
250 rel_y -= std::abs(rElem.
h);
253 aBuf.append(
"scale( 1.0 -1.0 )");
257 aBuf.append(
"skewX( " + OUString::number(fShearX) +
" )" );
261 if( !
aBuf.isEmpty() )
263 aBuf.append(
"rotate( " + OUString::number(-fRotate) +
" )" );
268 if( !
aBuf.isEmpty() )
270 aBuf.append(
"translate( "
277 rProps[
"draw:transform" ] =
aBuf.makeStringAndClear();
293 auto this_it = elem.
Children.begin();
294 while( this_it != elem.
Children.end() && this_it->get() != &elem )
296 (*this_it)->visitedBy( *
this, this_it );
319 for ( sal_uInt32 j = 0; j< b2dPolygon.
count(); j++ )
357 aProps[
"svg:viewBox" ] =
383 auto this_it = elem.
Children.begin();
384 while( this_it != elem.
Children.end() && this_it->get() != &elem )
386 (*this_it)->visitedBy( *
this, this_it );
396 for(
const auto& rxChild : elem.
Children )
403 for(
auto child_it = pPage->
Children.begin(); child_it != pPage->
Children.end(); ++child_it )
405 if(
dynamic_cast<DrawElement*
>(child_it->get()) != nullptr )
406 (*child_it)->
visitedBy( *
this, child_it );
416 if(
dynamic_cast<DrawElement*
>(it->get()) != nullptr )
417 (*it)->visitedBy( *
this, it );
453 auto next_it = elemIt;
500 auto prev = rParentIt;
519 if( pPrevPara->
y + pPrevPara->
h + 2*head_line_height > elem.
y )
532 if( pPrevText && pThisText )
572 std::list< std::unique_ptr<Element> >::iterator page_element, next_page_element;
573 next_page_element = elem.
Children.begin();
574 double fCurLineHeight = 0.0;
575 int nCurLineElements = 0;
576 double line_left = elem.
w, line_right = 0.0;
577 double column_width = elem.
w*0.75;
579 while( next_page_element != elem.
Children.end() )
581 page_element = next_page_element++;
585 pCurPara = pPagePara;
587 fCurLineHeight = 0.0;
588 nCurLineElements = 0;
589 for(
const auto& rxChild : pCurPara->
Children )
594 fCurLineHeight = (fCurLineHeight*double(nCurLineElements) + pTestText->
h)/
double(nCurLineElements+1);
603 if( ! pDraw &&
pLink && !
pLink->Children.empty() )
609 bool bInsertToParagraph =
false;
611 if( pCurPara && pDraw->
y < pCurPara->
y + pCurPara->
h )
613 if( pDraw->
h < fCurLineHeight * 1.5 )
615 bInsertToParagraph =
true;
616 fCurLineHeight = (fCurLineHeight*double(nCurLineElements) + pDraw->
h)/
double(nCurLineElements+1);
623 else if( next_page_element != elem.
Children.end() )
629 if( pPara && ! pPara->
Children.empty() )
630 pText = pPara->
Children.front()->dynCastAsTextElement();
633 pDraw->
h < pText->
h*1.5 &&
635 ( ( pDraw->
y >= pText->
y && pDraw->
y <= pText->
y+pText->
h ) ||
636 ( pDraw->
y+pDraw->
h >= pText->
y && pDraw->
y+pDraw->
h <= pText->
y+pText->
h )
640 bInsertToParagraph =
true;
641 fCurLineHeight = pDraw->
h;
642 nCurLineElements = 1;
643 line_left = pDraw->
x;
644 line_right = pDraw->
x + pDraw->
w;
652 if( ! bInsertToParagraph )
660 if( ! pText &&
pLink && !
pLink->Children.empty() )
661 pText =
pLink->Children.front()->dynCastAsTextElement();
669 if( nCurLineElements > 0 )
673 if( pGeo->
y > pCurPara->
y+pCurPara->
h + fCurLineHeight*0.5 )
675 else if( pGeo->
y > (pCurPara->
y+pCurPara->
h - fCurLineHeight*0.05) )
679 if( (line_right - line_left) < pCurPara->
w*0.75 )
682 else if( (line_right - line_left) < column_width*0.75 )
690 fCurLineHeight = (fCurLineHeight*double(nCurLineElements) + pGeo->
h)/
double(nCurLineElements+1);
692 if( pGeo->
x < line_left )
694 if( pGeo->
x+pGeo->
w > line_right )
695 line_right = pGeo->
x+pGeo->
w;
699 fCurLineHeight = pGeo->
h;
700 nCurLineElements = 1;
702 line_right = pGeo->
x + pGeo->
w;
713 page_element = elem.
Children.insert( page_element, std::unique_ptr<Element>(pCurPara) );
717 next_page_element = page_element;
718 ++ next_page_element;
720 Element* pCurEle = page_element->get();
722 OSL_ENSURE( !pText || pCurEle == pText || pCurEle ==
pLink,
"paragraph child list in disorder" );
745 auto isParagraphElement = [](std::unique_ptr<Element>& rxChild) ->
bool {
752 auto it = std::find_if(rElem.
Children.begin(), rElem.
Children.end(), isParagraphElement);
760 while( ++next_it != rElem.
Children.end() && pNextPara ==
nullptr )
764 if( pNextPara && pNextPara->
y > rPara.
y+rPara.
h*2 )
774 auto rit = std::find_if(rElem.
Children.rbegin(), rElem.
Children.rend(), isParagraphElement);
782 std::list< std::unique_ptr<Element> >::reverse_iterator next_it = rit;
784 while( ++next_it != rElem.
Children.rend() && pNextPara ==
nullptr )
788 if( pNextPara && pNextPara->
y < rPara.
y-rPara.
h*2 )
800 OSL_FAIL(
"empty paragraph optimized" );
805 auto next = rParent.
Children.begin();
808 bool bRotatedFrame =
false;
813 bRotatedFrame =
true;
815 while( next != rParent.
Children.end() )
817 bool bConcat =
false;
823 bool bPara = strspn(
"ParagraphElement",
typeid(rParent).
name());
837 && ! pNext->
Text.isEmpty()
838 && pNext->
Text[0] !=
' '
839 && ! pCur->
Text.isEmpty()
840 && pCur->
Text[pCur->
Text.getLength() - 1] !=
' '
844 if( pNext->
y > pCur->
y+pCur->
h )
850 || aLastCode == 0x2010
851 || (aLastCode >= 0x2012 && aLastCode <= 0x2015)
852 || aLastCode == 0xff0d
856 pCur->
Text.setLength( pCur->
Text.getLength()-1 );
859 else if( aLastCode != 0x2011 )
861 pCur->
Text.append(
' ' );
868 if( pCur->
x + pCur->
w + pNext->
h*0.15 < pNext->
x )
870 pCur->
Text.append(
' ' );
884 if (pPara && pPara->
bRtl)
889 bool bNeedReverse=
false;
890 str = pNext->
Text.toString();
891 for (sal_Int32
i=0;
i < str.getLength();
i++)
896 pCur->
Text.append(OUStringChar(str[
i]));
900 tempStr = ::comphelper::string::reverseCodePoints(tempStr);
901 pCur->
Text.append(tempStr);
904 bNeedReverse =
false;
908 tempStr += OUStringChar(str[
i]);
915 tempStr = ::comphelper::string::reverseCodePoints(tempStr);
916 pCur->
Text.append(tempStr);
920 pCur->
Text.append(tempStr);
966 aProps[
"style:family" ] =
"graphic";
974 aGCProps[
"draw:stroke" ] =
"solid";
982 aGCProps[
"draw:stroke" ] =
"dash";
983 aGCProps[
"draw:stroke-dash" ] =
995 aGCProps[
"draw:stroke" ] =
"none";
1001 aGCProps[
"draw:fill" ] =
"solid";
1006 aGCProps[
"draw:fill" ] =
"none";
1011 aStyle.
SubStyles.push_back( &aSubStyle );
1024 aProps[
"style:family" ] =
"text";
1031 aFontProps[
"fo:font-family" ] = rFont.
familyName;
1032 aFontProps[
"style:font-family-asian" ] = rFont.
familyName;
1033 aFontProps[
"style:font-family-complex" ] = rFont.
familyName;
1036 aFontProps[
"fo:font-weight" ] = rFont.
fontWeight;
1037 aFontProps[
"style:font-weight-asian" ] = rFont.
fontWeight;
1038 aFontProps[
"style:font-weight-complex" ] = rFont.
fontWeight;
1043 aFontProps[
"fo:font-style" ] =
"italic";
1044 aFontProps[
"style:font-style-asian" ] =
"italic";
1045 aFontProps[
"style:font-style-complex" ] =
"italic";
1051 aFontProps[
"style:text-underline-style" ] =
"solid";
1052 aFontProps[
"style:text-underline-width" ] =
"auto";
1053 aFontProps[
"style:text-underline-color" ] =
"font-color";
1058 aFontProps[
"style:text-outline" ] =
"true";
1062 aFontProps[
"fo:font-size" ] = aFSize;
1063 aFontProps[
"style:font-size-asian" ] = aFSize;
1064 aFontProps[
"style:font-size-complex" ] = aFSize;
1072 aStyle.
SubStyles.push_back( &aSubStyle );
1093 bool bIsCenter =
false;
1094 if( elem.
w < ( p_w/2) )
1096 double delta = elem.
w/4;
1099 if( elem.
w < p_w/8 )
1101 if( fabs( elem.
x+elem.
w/2 - ( p_x+ p_w/2) ) < delta ||
1102 (pPage && fabs( elem.
x+elem.
w/2 - (pPage->
x + pPage->
w/2) ) < delta) )
1105 aParaProps[
"fo:text-align" ] =
"center";
1108 if( ! bIsCenter && elem.
x > p_x + p_w/10 )
1111 aParaProps[
"fo:margin-left" ] = OUString::number(
convPx2mm( elem.
x - p_x )) +
"mm";
1116 auto it = rParentIt;
1124 aParaProps[
"fo:margin-bottom" ] =
1125 OUString::number(
convPx2mm( pNextPara->
y - (elem.
y+elem.
h) ) ) +
"mm";
1130 if( ! aParaProps.empty() )
1133 aProps[
"style:family" ] =
"paragraph";
1136 aStyle.
SubStyles.push_back( &aSubStyle );
1146 aProps[
"style:family" ] =
"graphic";
1150 aGCProps[
"draw:stroke" ] =
"none";
1151 aGCProps[
"draw:fill" ] =
"none";
1152 aGCProps[
"draw:auto-grow-height" ] =
"true";
1153 aGCProps[
"draw:auto-grow-width" ] =
"true";
1154 aGCProps[
"draw:textarea-horizontal-align" ] =
"left";
1155 aGCProps[
"draw:textarea-vertical-align" ] =
"top";
1156 aGCProps[
"fo:min-height"] =
"0cm";
1157 aGCProps[
"fo:min-width"] =
"0cm";
1158 aGCProps[
"fo:padding-top" ] =
"0cm";
1159 aGCProps[
"fo:padding-left" ] =
"0cm";
1160 aGCProps[
"fo:padding-right" ] =
"0cm";
1161 aGCProps[
"fo:padding-bottom" ] =
"0cm";
1165 aStyle.
SubStyles.push_back( &aSubStyle );
1177 const OUString& rMasterPageName )
1187 aProps[
"style:family" ] =
"paragraph";
1188 aProps[
"style:master-page-name" ] = rMasterPageName;
1214 for(
const auto& rxChild : elem.
Children )
1222 if( rxChild->x + rxChild->w > elem.
w - elem.
RightMargin )
1250 left_margin = rtl_math_round( left_margin, 0, rtl_math_RoundingMode_Floor );
1251 top_margin = rtl_math_round( top_margin, 0, rtl_math_RoundingMode_Floor );
1253 right_margin = rtl_math_round( right_margin, right_margin >= 10 ? -1 : 0, rtl_math_RoundingMode_Floor );
1254 bottom_margin = rtl_math_round( bottom_margin, bottom_margin >= 10 ? -1 : 0, rtl_math_RoundingMode_Floor );
1258 if( left_margin > page_width/2.0 - 10 )
1260 if( right_margin > page_width/2.0 - 10 )
1262 if( top_margin > page_height/2.0 - 10 )
1264 if( bottom_margin > page_height/2.0 - 10 )
1268 if( left_margin < 0 )
1270 if( right_margin < 0 )
1272 if( top_margin < 0 )
1274 if( bottom_margin < 0 )
1278 if( right_margin > left_margin*1.5 )
1279 right_margin = left_margin;
1289 aPageLayoutProps[
"fo:page-width" ] =
unitMMString( page_width );
1290 aPageLayoutProps[
"fo:page-height" ] =
unitMMString( page_height );
1291 aPageLayoutProps[
"style:print-orientation" ]
1292 = elem.
w < elem.
h ? std::u16string_view(
u"portrait") : std::u16string_view(
u"landscape");
1293 aPageLayoutProps[
"fo:margin-top" ] =
unitMMString( top_margin );
1294 aPageLayoutProps[
"fo:margin-bottom" ] =
unitMMString( bottom_margin );
1295 aPageLayoutProps[
"fo:margin-left" ] =
unitMMString( left_margin );
1296 aPageLayoutProps[
"fo:margin-right" ] =
unitMMString( right_margin );
1297 aPageLayoutProps[
"style:writing-mode" ]=
"lr-tb";
1306 aPageProps[
"style:page-layout-name" ] = aMasterPageLayoutName;
1312 elem.
HeaderElement->visitedBy( *
this, std::list<std::unique_ptr<Element>>::iterator() );
1314 aMPStyle.
SubStyles.push_back( &aHeaderStyle );
1318 elem.
FooterElement->visitedBy( *
this, std::list<std::unique_ptr<Element>>::iterator() );
1320 aMPStyle.
SubStyles.push_back( &aFooterStyle );
1334 pFirstPara->
Parent = &elem;
1335 elem.
Children.push_front( std::unique_ptr<Element>(pFirstPara) );
bool decompose(B2DTuple &rScale, B2DTuple &rTranslate, double &rRotate, double &rShearX) const
B2DPolygon const & getB2DPolygon(sal_uInt32 nIndex) const
void setB2DPolygon(sal_uInt32 nIndex, const B2DPolygon &rPolygon)
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
basegfx::B2DPoint getNextControlPoint(sal_uInt32 nIndex) const
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)
sal_Int32 setProperties(sal_Int32 nStyleId, PropertyMap &&rNewProps)
OUString getStyleName(sal_Int32 nStyle) const
sal_Int32 impl_getStyleId(const Style &rStyle, bool bSubStyle)
const PropertyMap * getProperties(sal_Int32 nStyleId) const
sal_Int32 getStyleId(const Style &rStyle)
static void fillFrameProps(DrawElement &rElem, PropertyMap &rProps, const EmitContext &rEmitContext)
virtual void visit(HyperlinkElement &, const std::list< std::unique_ptr< Element > >::const_iterator &) override
const css::uno::Reference< css::i18n::XCharacterClassification > & GetCharacterClassification()
EmitContext & m_rEmitContext
css::uno::Reference< css::i18n::XCharacterClassification > mxCharClass
PDFIProcessor & m_rProcessor
static void setFirstOnPage(ParagraphElement &rElem, StyleContainer &rStyles, const OUString &rMasterPageName)
virtual void visit(HyperlinkElement &, const std::list< std::unique_ptr< Element > >::const_iterator &) override
StyleContainer & m_rStyleContainer
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
void checkHeaderAndFooter(PageElement &rElem)
css::uno::Reference< css::i18n::XBreakIterator > mxBreakIter
PDFIProcessor & m_rProcessor
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.
#define SAL_INFO(area, stream)
OUString exportToSvgD(const B2DPolyPolygon &rPolyPoly, bool bUseRelativeCoordinates, bool bDetectQuadraticBeziers, bool bHandleRelativeNextPointCompatible, bool bOOXMLMotionPath=false)
OUString convertPixelToUnitString(double fPix)
OUString getColorString(const css::rendering::ARGBColor &)
Convert color to "#FEFEFE" color notation.
double convmm2Px(double fMM)
double convPx2mm(double fPix)
double GetAverageTransformationScale(const basegfx::B2DHomMatrix &matrix)
OUString unitMMString(double fMM)
std::unordered_map< OUString, OUString > PropertyMap
double convPx2mmPrec2(double fPix)
round to 2 decimal places
bool isComplex(const css::uno::Reference< css::i18n::XBreakIterator > &rBreakIterator, TextElement *const pTextElem)
void FillDashStyleProps(PropertyMap &props, const std::vector< double > &dashArray, double scale)
#define PDFI_OUTDEV_RESOLUTION
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.
css::uno::Reference< css::uno::XComponentContext > m_xContext
PDFIProcessor & rProcessor
css::uno::Reference< css::task::XStatusIndicator > xStatusIndicator
css::rendering::ARGBColor FillColor
css::rendering::ARGBColor LineColor
bool isRotatedOrSkewed() const
basegfx::B2DHomMatrix Transformation
OUString GetLineCapString() const
OUString GetLineJoinString() const
std::vector< double > DashArray
basegfx::B2DPolyPolygon Clip
std::unique_ptr< Element > FooterElement
std::unique_ptr< Element > HeaderElement
virtual void visitedBy(ElementTreeVisitor &, const std::list< std::unique_ptr< Element > >::const_iterator &rParentIt) override
To be implemented by every tree node that needs to be visitable.
void resolveFontStyles(PDFIProcessor const &rProc)
TextElement * getFirstTextChild() const
double getLineHeight(PDFIProcessor &rProc) const
bool isSingleLined(PDFIProcessor const &rProc) const
basegfx::B2DPolyPolygon PolyPoly
std::vector< Style * > SubStyles
Element * ContainedElement
virtual const TextElement * dynCastAsTextElement() const override
To avoid some dynamic_cast cost.