1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <com/sun/star/text/HoriOrientation.hpp>
21 #include <com/sun/star/text/VertOrientation.hpp>
22 #include <com/sun/star/text/RelOrientation.hpp>
23 #include <com/sun/star/beans/XPropertySet.hpp>
24 #include <hintids.hxx>
25 #include <tools/fract.hxx>
26 #include <svl/urihelper.hxx>
27 #include <vcl/svapp.hxx>
28 #include <sfx2/event.hxx>
29 #include <svtools/htmlkywd.hxx>
30 #include <svtools/htmlout.hxx>
31 #include <svtools/htmltokn.h>
32 #include <vcl/imap.hxx>
33 #include <vcl/imapobj.hxx>
34 #include <svtools/htmlcfg.hxx>
35 #include <svtools/HtmlWriter.hxx>
36 #include <svx/svdouno.hxx>
37 #include <svx/xoutbmp.hxx>
38 #include <editeng/boxitem.hxx>
39 #include <editeng/lrspitem.hxx>
40 #include <editeng/ulspitem.hxx>
41 #include <editeng/brushitem.hxx>
42 #include <sal/log.hxx>
43 #include <osl/diagnose.h>
44 #include <svx/svdograf.hxx>
45 #include <comphelper/xmlencode.hxx>
47 #include <fmtanchr.hxx>
48 #include <fmtornt.hxx>
50 #include <fmtfsize.hxx>
51 #include <fmtclds.hxx>
52 #include <fmtcntnt.hxx>
53 #include <fmtsrnd.hxx>
54 #include <fmtinfmt.hxx>
55 #include <txtinet.hxx>
66 #include "wrthtml.hxx"
67 #include "htmlatr.hxx"
68 #include "htmlfly.hxx"
69 #include "htmlreqifreader.hxx"
73 const HtmlFrmOpts HTML_FRMOPTS_IMG_ALL
=
76 HtmlFrmOpts::AnySize
|
79 const HtmlFrmOpts HTML_FRMOPTS_IMG_CNTNR
=
80 HTML_FRMOPTS_IMG_ALL
|
82 const HtmlFrmOpts HTML_FRMOPTS_IMG
=
83 HTML_FRMOPTS_IMG_ALL
|
87 const HtmlFrmOpts HTML_FRMOPTS_IMG_CSS1
=
91 const HtmlFrmOpts HTML_FRMOPTS_DIV
=
95 HtmlFrmOpts::AnySize
|
96 HtmlFrmOpts::AbsSize
|
98 HtmlFrmOpts::SBorder
|
99 HtmlFrmOpts::SBackground
|
100 HtmlFrmOpts::BrClear
|
103 const HtmlFrmOpts HTML_FRMOPTS_MULTICOL
=
106 HtmlFrmOpts::AnySize
|
107 HtmlFrmOpts::AbsSize
|
110 const HtmlFrmOpts HTML_FRMOPTS_MULTICOL_CSS1
=
111 HtmlFrmOpts::SAlign
|
113 HtmlFrmOpts::SSpace
|
114 HtmlFrmOpts::SBorder
|
115 HtmlFrmOpts::SBackground
;
117 const HtmlFrmOpts HTML_FRMOPTS_SPACER
=
120 HtmlFrmOpts::AnySize
|
121 HtmlFrmOpts::BrClear
|
122 HtmlFrmOpts::MarginSize
|
123 HtmlFrmOpts::AbsSize
;
125 const HtmlFrmOpts HTML_FRMOPTS_CNTNR
=
126 HtmlFrmOpts::SAlign
|
127 HtmlFrmOpts::SSpace
|
128 HtmlFrmOpts::SWidth
|
129 HtmlFrmOpts::AnySize
|
130 HtmlFrmOpts::AbsSize
|
131 HtmlFrmOpts::SPixSize
;
133 static SwHTMLWriter
& OutHTML_FrameFormatTableNode( SwHTMLWriter
& rWrt
, const SwFrameFormat
& rFrameFormat
);
134 static SwHTMLWriter
& OutHTML_FrameFormatAsMulticol( SwHTMLWriter
& rWrt
, const SwFrameFormat
& rFormat
,
136 static SwHTMLWriter
& OutHTML_FrameFormatAsSpacer( SwHTMLWriter
& rWrt
, const SwFrameFormat
& rFormat
);
137 static SwHTMLWriter
& OutHTML_FrameFormatAsDivOrSpan( SwHTMLWriter
& rWrt
,
138 const SwFrameFormat
& rFrameFormat
, bool bSpan
);
139 static SwHTMLWriter
& OutHTML_FrameFormatAsImage( SwHTMLWriter
& rWrt
, const SwFrameFormat
& rFormat
, bool bPNGFallback
);
141 static SwHTMLWriter
& OutHTML_FrameFormatGrfNode( SwHTMLWriter
& rWrt
, const SwFrameFormat
& rFormat
,
142 bool bInCntnr
, bool bPNGFallback
);
144 static SwHTMLWriter
& OutHTML_FrameFormatAsMarquee( SwHTMLWriter
& rWrt
, const SwFrameFormat
& rFrameFormat
,
145 const SdrObject
& rSdrObj
);
147 HTMLOutEvent
const aImageEventTable
[] =
149 { OOO_STRING_SVTOOLS_HTML_O_SDonload
, OOO_STRING_SVTOOLS_HTML_O_onload
, SvMacroItemId::OnImageLoadDone
},
150 { OOO_STRING_SVTOOLS_HTML_O_SDonabort
, OOO_STRING_SVTOOLS_HTML_O_onabort
, SvMacroItemId::OnImageLoadCancel
},
151 { OOO_STRING_SVTOOLS_HTML_O_SDonerror
, OOO_STRING_SVTOOLS_HTML_O_onerror
, SvMacroItemId::OnImageLoadError
},
152 { nullptr, nullptr, SvMacroItemId::NONE
}
155 HTMLOutEvent
const aIMapEventTable
[] =
157 { OOO_STRING_SVTOOLS_HTML_O_SDonmouseover
, OOO_STRING_SVTOOLS_HTML_O_onmouseover
, SvMacroItemId::OnMouseOver
},
158 { OOO_STRING_SVTOOLS_HTML_O_SDonmouseout
, OOO_STRING_SVTOOLS_HTML_O_onmouseout
, SvMacroItemId::OnMouseOut
},
159 { nullptr, nullptr, SvMacroItemId::NONE
}
162 SwHTMLFrameType
SwHTMLWriter::GuessFrameType( const SwFrameFormat
& rFrameFormat
,
163 const SdrObject
*& rpSdrObj
)
165 SwHTMLFrameType eType
;
167 if( RES_DRAWFRMFMT
== rFrameFormat
.Which() )
169 // use an arbitrary draw object as the default value
170 eType
= HTML_FRMTYPE_DRAW
;
172 const SdrObject
*pObj
=
173 SwHTMLWriter::GetMarqueeTextObj( static_cast<const SwDrawFrameFormat
&>(rFrameFormat
) );
178 eType
= HTML_FRMTYPE_MARQUEE
;
182 pObj
= GetHTMLControl( static_cast<const SwDrawFrameFormat
&>(rFrameFormat
) );
188 eType
= HTML_FRMTYPE_CONTROL
;
194 // use a text frame as the default value
195 eType
= HTML_FRMTYPE_TEXT
;
197 const SwFormatContent
& rFlyContent
= rFrameFormat
.GetContent();
198 SwNodeOffset nStt
= rFlyContent
.GetContentIdx()->GetIndex()+1;
199 const SwNode
* pNd
= m_pDoc
->GetNodes()[ nStt
];
201 if( pNd
->IsGrfNode() )
204 eType
= HTML_FRMTYPE_GRF
;
206 else if( pNd
->IsOLENode() )
208 // applet, plugin, floating frame
209 eType
= GuessOLENodeFrameType( *pNd
);
213 SwNodeOffset nEnd
= m_pDoc
->GetNodes()[nStt
-1]->EndOfSectionIndex();
215 const SfxItemSet
& rItemSet
= rFrameFormat
.GetAttrSet();
216 const SwFormatCol
* pFormatCol
= rItemSet
.GetItemIfSet( RES_COL
);
217 if( pFormatCol
&& pFormatCol
->GetNumCols() > 1 )
219 // frame with columns
220 eType
= HTML_FRMTYPE_MULTICOL
;
222 else if( pNd
->IsTableNode() )
224 const SwTableNode
*pTableNd
= pNd
->GetTableNode();
225 SwNodeOffset nTableEnd
= pTableNd
->EndOfSectionIndex();
227 if( nTableEnd
+1 == nEnd
)
230 eType
= HTML_FRMTYPE_TABLE
;
232 else if( nTableEnd
+2 == nEnd
)
234 // table with caption
235 eType
= HTML_FRMTYPE_TABLE_CAP
;
238 else if( pNd
->IsTextNode() )
240 const SwTextNode
*pTextNd
= pNd
->GetTextNode();
243 if( nStt
==nEnd
-1 && !pTextNd
->Len() )
245 // empty frame? Only if no frame is
246 // anchored to the text or start node.
248 for( auto & pHTMLPosFlyFrame
: m_aHTMLPosFlyFrames
)
250 SwNodeOffset nIdx
= pHTMLPosFlyFrame
->GetNdIndex().GetIndex();
251 bEmpty
= (nIdx
!= nStt
) && (nIdx
!= nStt
-1);
252 if( !bEmpty
|| nIdx
> nStt
)
258 std::unique_ptr
<SvxBrushItem
> aBrush
= rFrameFormat
.makeBackgroundBrushItem();
259 /// background is not empty, if it has a background graphic
260 /// or its background color is not "no fill"/"auto fill".
261 if( GPOS_NONE
!= aBrush
->GetGraphicPos() ||
262 aBrush
->GetColor() != COL_TRANSPARENT
)
270 eType
= HTML_FRMTYPE_EMPTY
;
272 else if( m_pDoc
->GetNodes()[nStt
+1]->IsTableNode() )
274 const SwTableNode
*pTableNd
=
275 m_pDoc
->GetNodes()[nStt
+1]->GetTableNode();
276 if( pTableNd
->EndOfSectionIndex()+1 == nEnd
)
278 // table with heading
279 eType
= HTML_FRMTYPE_TABLE_CAP
;
289 void SwHTMLWriter::CollectFlyFrames()
291 OSL_ENSURE( HTML_CFG_MAX
+1 == MAX_BROWSERS
,
292 "number of browser configurations has changed" );
294 SwPosFlyFrames
aFlyPos(
295 m_pDoc
->GetAllFlyFormats(m_bWriteAll
? nullptr : m_pCurrentPam
.get(), true));
297 for(const SwPosFlyFrame
& rItem
: aFlyPos
)
299 const SwFrameFormat
& rFrameFormat
= rItem
.GetFormat();
300 const SdrObject
*pSdrObj
= nullptr;
301 const SwNode
*pAnchorNode
;
302 const SwContentNode
*pACNd
;
303 SwHTMLFrameType eType
= GuessFrameType( rFrameFormat
, pSdrObj
);
306 const SwFormatAnchor
& rAnchor
= rFrameFormat
.GetAnchor();
307 sal_Int16 eHoriRel
= rFrameFormat
.GetHoriOrient().GetRelationOrient();
308 switch( rAnchor
.GetAnchorId() )
310 case RndStdIds::FLY_AT_PAGE
:
311 case RndStdIds::FLY_AT_FLY
:
312 nMode
= aHTMLOutFramePageFlyTable
[eType
][m_nExportMode
];
315 case RndStdIds::FLY_AT_PARA
:
316 // frames that are anchored to a paragraph are only placed
317 // before the paragraph, if the paragraph has a
319 if( text::RelOrientation::FRAME
== eHoriRel
&&
320 (pAnchorNode
= rAnchor
.GetAnchorNode()) != nullptr &&
321 (pACNd
= pAnchorNode
->GetContentNode()) != nullptr )
323 const SvxTextLeftMarginItem
& rTextLeftMargin
=
324 pACNd
->GetAttr(RES_MARGIN_TEXTLEFT
);
325 const SvxRightMarginItem
& rRightMargin
=
326 pACNd
->GetAttr(RES_MARGIN_RIGHT
);
327 if (rTextLeftMargin
.GetTextLeft() || rRightMargin
.GetRight())
329 nMode
= aHTMLOutFrameParaFrameTable
[eType
][m_nExportMode
];
333 nMode
= aHTMLOutFrameParaPrtAreaTable
[eType
][m_nExportMode
];
336 case RndStdIds::FLY_AT_CHAR
:
337 if( text::RelOrientation::FRAME
== eHoriRel
|| text::RelOrientation::PRINT_AREA
== eHoriRel
)
338 nMode
= aHTMLOutFrameParaPrtAreaTable
[eType
][m_nExportMode
];
340 nMode
= aHTMLOutFrameParaOtherTable
[eType
][m_nExportMode
];
344 nMode
= aHTMLOutFrameParaPrtAreaTable
[eType
][m_nExportMode
];
348 m_aHTMLPosFlyFrames
.insert( std::make_unique
<SwHTMLPosFlyFrame
>(rItem
, pSdrObj
, nMode
) );
352 bool SwHTMLWriter::OutFlyFrame( SwNodeOffset nNdIdx
, sal_Int32 nContentIdx
, HtmlPosition nPos
)
354 bool bFlysLeft
= false; // Are there still Flys left at the current node position?
356 // OutFlyFrame can be called recursively. Thus, sometimes it is
357 // necessary to start over after a Fly was returned.
358 bool bRestart
= true;
359 while( !m_aHTMLPosFlyFrames
.empty() && bRestart
)
361 bFlysLeft
= bRestart
= false;
363 // search for the beginning of the FlyFrames
366 for( ; i
< m_aHTMLPosFlyFrames
.size() &&
367 m_aHTMLPosFlyFrames
[i
]->GetNdIndex().GetIndex() < nNdIdx
; i
++ )
369 for( ; !bRestart
&& i
< m_aHTMLPosFlyFrames
.size() &&
370 m_aHTMLPosFlyFrames
[i
]->GetNdIndex().GetIndex() == nNdIdx
; i
++ )
372 SwHTMLPosFlyFrame
*pPosFly
= m_aHTMLPosFlyFrames
[i
].get();
373 if( ( HtmlPosition::Any
== nPos
||
374 pPosFly
->GetOutPos() == nPos
) &&
375 pPosFly
->GetContentIndex() == nContentIdx
)
377 // It is important to remove it first, because additional
378 // elements or the whole array could be deleted on
379 // deeper recursion levels.
380 std::unique_ptr
<SwHTMLPosFlyFrame
> flyHolder
= m_aHTMLPosFlyFrames
.erase_extract(i
);
382 if( m_aHTMLPosFlyFrames
.empty() )
384 bRestart
= true; // not really, only exit the loop
387 HTMLOutFuncs::FlushToAscii(Strm()); // it was one time only; do we still need it?
389 OutFrameFormat( pPosFly
->GetOutMode(), pPosFly
->GetFormat(),
390 pPosFly
->GetSdrObject() );
391 switch( pPosFly
->GetOutFn() )
395 case HtmlOut::MultiCol
:
396 case HtmlOut::TableNode
:
397 bRestart
= true; // It could become recursive here
412 void SwHTMLWriter::OutFrameFormat( AllHtmlFlags nMode
, const SwFrameFormat
& rFrameFormat
,
413 const SdrObject
*pSdrObject
)
415 HtmlContainerFlags nCntnrMode
= nMode
.nContainer
;
416 HtmlOut nOutMode
= nMode
.nOut
;
417 OString aContainerStr
;
418 if( HtmlContainerFlags::NONE
!= nCntnrMode
)
421 if( m_bLFPossible
&& HtmlContainerFlags::Div
== nCntnrMode
)
425 aContainerStr
= (HtmlContainerFlags::Div
== nCntnrMode
)
426 ? OOO_STRING_SVTOOLS_HTML_division
427 : OOO_STRING_SVTOOLS_HTML_span
;
428 sOut
.append("<" + GetNamespace() + aContainerStr
+ " "
429 OOO_STRING_SVTOOLS_HTML_O_class
"=\""
431 Strm().WriteOString( sOut
);
434 // Output a width for non-draw objects
435 HtmlFrmOpts nFrameFlags
= HTML_FRMOPTS_CNTNR
;
437 // For frames with columns we can also output the background
438 if( HtmlOut::MultiCol
== nOutMode
)
439 nFrameFlags
|= HtmlFrmOpts::SBackground
|HtmlFrmOpts::SBorder
;
441 if( IsHTMLMode( HTMLMODE_BORDER_NONE
) )
442 nFrameFlags
|= HtmlFrmOpts::SNoBorder
;
443 OutCSS1_FrameFormatOptions( rFrameFormat
, nFrameFlags
, pSdrObject
);
444 Strm().WriteChar( '>' );
446 if( HtmlContainerFlags::Div
== nCntnrMode
)
449 m_bLFPossible
= true;
455 case HtmlOut::TableNode
: // OK
456 OSL_ENSURE( aContainerStr
.isEmpty(), "Table: Container is not supposed to be here" );
457 OutHTML_FrameFormatTableNode( *this, rFrameFormat
);
459 case HtmlOut::GraphicNode
: // OK
460 OutHTML_FrameFormatGrfNode( *this, rFrameFormat
, !aContainerStr
.isEmpty(), /*bPNGFallback=*/true );
462 case HtmlOut::OleNode
: // OK
463 OutHTML_FrameFormatOLENode( *this, rFrameFormat
, !aContainerStr
.isEmpty() );
465 case HtmlOut::OleGraphic
: // OK
466 OutHTML_FrameFormatOLENodeGrf( *this, rFrameFormat
, !aContainerStr
.isEmpty() );
470 OSL_ENSURE( aContainerStr
.isEmpty(), "Div: Container is not supposed to be here" );
471 OutHTML_FrameFormatAsDivOrSpan( *this, rFrameFormat
, HtmlOut::Span
==nOutMode
);
473 case HtmlOut::MultiCol
: // OK
474 OutHTML_FrameFormatAsMulticol( *this, rFrameFormat
, !aContainerStr
.isEmpty() );
476 case HtmlOut::Spacer
: // OK
477 OSL_ENSURE( aContainerStr
.isEmpty(), "Spacer: Container is not supposed to be here" );
478 OutHTML_FrameFormatAsSpacer( *this, rFrameFormat
);
480 case HtmlOut::Control
: // OK
481 OutHTML_DrawFrameFormatAsControl( *this,
482 static_cast<const SwDrawFrameFormat
&>(rFrameFormat
), dynamic_cast<const SdrUnoObj
&>(*pSdrObject
),
483 !aContainerStr
.isEmpty() );
485 case HtmlOut::AMarquee
:
486 OutHTML_FrameFormatAsMarquee( *this, rFrameFormat
, *pSdrObject
);
488 case HtmlOut::Marquee
:
489 OSL_ENSURE( aContainerStr
.isEmpty(), "Marquee: Container is not supposed to be here" );
490 OutHTML_DrawFrameFormatAsMarquee( *this,
491 static_cast<const SwDrawFrameFormat
&>(rFrameFormat
), *pSdrObject
);
493 case HtmlOut::GraphicFrame
:
494 OutHTML_FrameFormatAsImage( *this, rFrameFormat
, /*bPNGFallback=*/true );
498 if( HtmlContainerFlags::Div
== nCntnrMode
)
503 HTMLOutFuncs::Out_AsciiTag( Strm(), Concat2View(GetNamespace() + OOO_STRING_SVTOOLS_HTML_division
), false );
504 m_bLFPossible
= true;
506 else if( HtmlContainerFlags::Span
== nCntnrMode
)
507 HTMLOutFuncs::Out_AsciiTag( Strm(), Concat2View(GetNamespace() + OOO_STRING_SVTOOLS_HTML_span
), false );
510 OString
SwHTMLWriter::OutFrameFormatOptions( const SwFrameFormat
&rFrameFormat
,
511 const OUString
& rAlternateText
,
512 HtmlFrmOpts nFrameOpts
)
516 const SfxItemSet
& rItemSet
= rFrameFormat
.GetAttrSet();
519 if( (nFrameOpts
& (HtmlFrmOpts::Id
|HtmlFrmOpts::Name
)) &&
520 !rFrameFormat
.GetName().isEmpty() )
523 (nFrameOpts
& HtmlFrmOpts::Id
) ? OOO_STRING_SVTOOLS_HTML_O_id
: OOO_STRING_SVTOOLS_HTML_O_name
;
524 sOut
.append(OString::Concat(" ") + pStr
+ "=\"");
525 Strm().WriteOString( sOut
);
527 HTMLOutFuncs::Out_String( Strm(), rFrameFormat
.GetName() );
532 if( nFrameOpts
& HtmlFrmOpts::Dir
)
534 SvxFrameDirection nDir
= GetHTMLDirection( rItemSet
);
535 Strm().WriteOString( sOut
);
537 OutDirection( nDir
);
541 if( (nFrameOpts
& HtmlFrmOpts::Alt
) && !rAlternateText
.isEmpty() )
543 sOut
.append(" " OOO_STRING_SVTOOLS_HTML_O_alt
"=\"");
544 Strm().WriteOString( sOut
);
546 HTMLOutFuncs::Out_String( Strm(), rAlternateText
);
551 const char *pStr
= nullptr;
552 RndStdIds eAnchorId
= rFrameFormat
.GetAnchor().GetAnchorId();
553 if( (nFrameOpts
& HtmlFrmOpts::Align
) &&
554 ((RndStdIds::FLY_AT_PARA
== eAnchorId
) || (RndStdIds::FLY_AT_CHAR
== eAnchorId
)) )
556 // MIB 12.3.98: Wouldn't it be more clever to left-align frames that
557 // are anchored to a paragraph if necessary, instead of inserting them
558 // as being anchored to characters?
559 const SwFormatHoriOrient
& rHoriOri
= rFrameFormat
.GetHoriOrient();
560 if( !(nFrameOpts
& HtmlFrmOpts::SAlign
) ||
561 text::RelOrientation::FRAME
== rHoriOri
.GetRelationOrient() ||
562 text::RelOrientation::PRINT_AREA
== rHoriOri
.GetRelationOrient() )
564 pStr
= text::HoriOrientation::RIGHT
== rHoriOri
.GetHoriOrient()
565 ? OOO_STRING_SVTOOLS_HTML_AL_right
566 : OOO_STRING_SVTOOLS_HTML_AL_left
;
569 const SwFormatVertOrient
* pVertOrient
;
570 if( (nFrameOpts
& HtmlFrmOpts::Align
) && !pStr
&&
571 ( !(nFrameOpts
& HtmlFrmOpts::SAlign
) ||
572 (RndStdIds::FLY_AS_CHAR
== eAnchorId
) ) &&
573 (pVertOrient
= rItemSet
.GetItemIfSet( RES_VERT_ORIENT
)) )
575 switch( pVertOrient
->GetVertOrient() )
577 case text::VertOrientation::LINE_TOP
: pStr
= OOO_STRING_SVTOOLS_HTML_VA_top
; break;
578 case text::VertOrientation::CHAR_TOP
:
579 case text::VertOrientation::BOTTOM
: pStr
= OOO_STRING_SVTOOLS_HTML_VA_texttop
; break; // not possible
580 case text::VertOrientation::LINE_CENTER
:
581 case text::VertOrientation::CHAR_CENTER
: pStr
= OOO_STRING_SVTOOLS_HTML_VA_absmiddle
; break; // not possible
582 case text::VertOrientation::CENTER
: pStr
= OOO_STRING_SVTOOLS_HTML_VA_middle
; break;
583 case text::VertOrientation::LINE_BOTTOM
:
584 case text::VertOrientation::CHAR_BOTTOM
: pStr
= OOO_STRING_SVTOOLS_HTML_VA_absbottom
; break; // not possible
585 case text::VertOrientation::TOP
: pStr
= OOO_STRING_SVTOOLS_HTML_VA_bottom
; break;
586 case text::VertOrientation::NONE
: break;
591 sOut
.append(OString::Concat(" " OOO_STRING_SVTOOLS_HTML_O_align
"=\"") +
596 Size
aTwipSpc( 0, 0 );
597 const SvxLRSpaceItem
* pLRSpaceItem
;
598 if( (nFrameOpts
& (HtmlFrmOpts::Space
|HtmlFrmOpts::MarginSize
)) &&
599 (pLRSpaceItem
= rItemSet
.GetItemIfSet( RES_LR_SPACE
)) )
602 ( pLRSpaceItem
->GetLeft() + pLRSpaceItem
->GetRight() ) / 2 );
603 m_nDfltLeftMargin
= m_nDfltRightMargin
= aTwipSpc
.Width();
605 const SvxULSpaceItem
* pULSpaceItem
;
606 if( (nFrameOpts
& (HtmlFrmOpts::Space
|HtmlFrmOpts::MarginSize
)) &&
607 (pULSpaceItem
= rItemSet
.GetItemIfSet( RES_UL_SPACE
)) )
610 ( pULSpaceItem
->GetUpper() + pULSpaceItem
->GetLower() ) / 2 );
611 m_nDfltTopMargin
= m_nDfltBottomMargin
= o3tl::narrowing
<sal_uInt16
>(aTwipSpc
.Height());
614 if( (nFrameOpts
& HtmlFrmOpts::Space
) &&
615 (aTwipSpc
.Width() || aTwipSpc
.Height()) &&
618 Size aPixelSpc
= SwHTMLWriter::ToPixel(aTwipSpc
);
620 if( aPixelSpc
.Width() )
622 sOut
.append(" " OOO_STRING_SVTOOLS_HTML_O_hspace
623 "=\"" + OString::number(aPixelSpc
.Width()) + "\"");
626 if( aPixelSpc
.Height() )
628 sOut
.append(" " OOO_STRING_SVTOOLS_HTML_O_vspace
629 "=\"" + OString::number(aPixelSpc
.Height()) + "\"");
633 // The spacing must be considered for the size, if the corresponding flag
635 if( nFrameOpts
& HtmlFrmOpts::MarginSize
)
637 aTwipSpc
.setWidth( aTwipSpc
.Width() * -2 );
638 aTwipSpc
.setHeight( aTwipSpc
.Height() * -2 );
642 aTwipSpc
.setWidth( 0 );
643 aTwipSpc
.setHeight( 0 );
646 const SvxBoxItem
* pBoxItem
;
647 if( !(nFrameOpts
& HtmlFrmOpts::AbsSize
) &&
648 (pBoxItem
= rItemSet
.GetItemIfSet( RES_BOX
)) )
650 aTwipSpc
.AdjustWidth(pBoxItem
->CalcLineSpace( SvxBoxItemLine::LEFT
) );
651 aTwipSpc
.AdjustWidth(pBoxItem
->CalcLineSpace( SvxBoxItemLine::RIGHT
) );
652 aTwipSpc
.AdjustHeight(pBoxItem
->CalcLineSpace( SvxBoxItemLine::TOP
) );
653 aTwipSpc
.AdjustHeight(pBoxItem
->CalcLineSpace( SvxBoxItemLine::BOTTOM
) );
656 // WIDTH and/or HEIGHT
657 // Output SwFrameSize::Variable/SwFrameSize::Minimum only, if ANYSIZE is set
658 const SwFormatFrameSize
*pFSItem
;
659 if( (nFrameOpts
& HtmlFrmOpts::Size
) &&
660 (pFSItem
= rItemSet
.GetItemIfSet( RES_FRM_SIZE
)) &&
661 ( (nFrameOpts
& HtmlFrmOpts::AnySize
) ||
662 SwFrameSize::Fixed
== pFSItem
->GetHeightSizeType()) )
664 sal_uInt8 nPercentWidth
= pFSItem
->GetWidthPercent();
665 sal_uInt8 nPercentHeight
= pFSItem
->GetHeightPercent();
667 // Size of the object in Twips without margins
668 Size
aTwipSz( (nPercentWidth
? 0
669 : pFSItem
->GetWidth()-aTwipSpc
.Width()),
671 : pFSItem
->GetHeight()-aTwipSpc
.Height()) );
673 OSL_ENSURE( aTwipSz
.Width() >= 0 && aTwipSz
.Height() >= 0, "Frame size minus spacing < 0!!!???" );
674 if( aTwipSz
.Width() < 0 )
675 aTwipSz
.setWidth( 0 );
676 if( aTwipSz
.Height() < 0 )
677 aTwipSz
.setHeight( 0 );
679 Size
aPixelSz(SwHTMLWriter::ToPixel(aTwipSz
));
681 if( (nFrameOpts
& HtmlFrmOpts::Width
) &&
682 ((nPercentWidth
&& nPercentWidth
!=255) || aPixelSz
.Width()) )
684 sOut
.append(" " OOO_STRING_SVTOOLS_HTML_O_width
"=\"");
686 sOut
.append(OString::number(static_cast<sal_Int32
>(nPercentWidth
)) + "%");
688 sOut
.append(static_cast<sal_Int32
>(aPixelSz
.Width()));
692 if( (nFrameOpts
& HtmlFrmOpts::Height
) &&
693 ((nPercentHeight
&& nPercentHeight
!=255) || aPixelSz
.Height()) )
695 sOut
.append(" " OOO_STRING_SVTOOLS_HTML_O_height
"=\"");
697 sOut
.append(OString::number(static_cast<sal_Int32
>(nPercentHeight
)) + "%");
699 sOut
.append(static_cast<sal_Int32
>(aPixelSz
.Height()));
706 Strm().WriteOString( sOut
);
710 // Insert wrap for graphics that are anchored to a paragraph as
711 // <BR CLEAR=...> in the string
712 const SwFormatSurround
* pSurround
;
713 if( (nFrameOpts
& HtmlFrmOpts::BrClear
) &&
714 ((RndStdIds::FLY_AT_PARA
== rFrameFormat
.GetAnchor().GetAnchorId()) ||
715 (RndStdIds::FLY_AT_CHAR
== rFrameFormat
.GetAnchor().GetAnchorId())) &&
716 (pSurround
= rItemSet
.GetItemIfSet( RES_SURROUND
)) )
718 sal_Int16 eHoriOri
= rFrameFormat
.GetHoriOrient().GetHoriOrient();
720 css::text::WrapTextMode eSurround
= pSurround
->GetSurround();
721 bool bAnchorOnly
= pSurround
->IsAnchorOnly();
724 case text::HoriOrientation::RIGHT
:
728 case css::text::WrapTextMode_NONE
:
729 case css::text::WrapTextMode_RIGHT
:
730 pStr
= OOO_STRING_SVTOOLS_HTML_AL_right
;
732 case css::text::WrapTextMode_LEFT
:
733 case css::text::WrapTextMode_PARALLEL
:
735 m_bClearRight
= true;
744 // If a frame is centered, it gets left aligned. This
745 // should be taken into account here, too.
749 case css::text::WrapTextMode_NONE
:
750 case css::text::WrapTextMode_LEFT
:
751 pStr
= OOO_STRING_SVTOOLS_HTML_AL_left
;
753 case css::text::WrapTextMode_RIGHT
:
754 case css::text::WrapTextMode_PARALLEL
:
768 sOut
.append("<" OOO_STRING_SVTOOLS_HTML_linebreak
769 " " OOO_STRING_SVTOOLS_HTML_O_clear
770 "=\"" + OString::Concat(pStr
) + "\">");
771 sRetEndTags
= sOut
.makeStringAndClear();
777 void SwHTMLWriter::writeFrameFormatOptions(HtmlWriter
& aHtml
, const SwFrameFormat
& rFrameFormat
, std::u16string_view rAlternateText
, HtmlFrmOpts nFrameOptions
)
779 bool bReplacement
= (nFrameOptions
& HtmlFrmOpts::Replacement
) || mbReqIF
;
780 const SfxItemSet
& rItemSet
= rFrameFormat
.GetAttrSet();
783 if( (nFrameOptions
& (HtmlFrmOpts::Id
|HtmlFrmOpts::Name
)) &&
784 !rFrameFormat
.GetName().isEmpty() && !bReplacement
)
786 const char* pAttributeName
= (nFrameOptions
& HtmlFrmOpts::Id
) ? OOO_STRING_SVTOOLS_HTML_O_id
: OOO_STRING_SVTOOLS_HTML_O_name
;
787 aHtml
.attribute(pAttributeName
, rFrameFormat
.GetName());
791 if (nFrameOptions
& HtmlFrmOpts::Dir
)
793 SvxFrameDirection nCurrentDirection
= GetHTMLDirection(rItemSet
);
794 OString sDirection
= convertDirection(nCurrentDirection
);
795 aHtml
.attribute(OOO_STRING_SVTOOLS_HTML_O_dir
, sDirection
);
799 if( (nFrameOptions
& HtmlFrmOpts::Alt
) && !rAlternateText
.empty() && !bReplacement
)
801 aHtml
.attribute(OOO_STRING_SVTOOLS_HTML_O_alt
, rAlternateText
);
805 std::string_view pAlignString
;
806 RndStdIds eAnchorId
= rFrameFormat
.GetAnchor().GetAnchorId();
807 if( (nFrameOptions
& HtmlFrmOpts::Align
) &&
808 ((RndStdIds::FLY_AT_PARA
== eAnchorId
) || (RndStdIds::FLY_AT_CHAR
== eAnchorId
)) && !bReplacement
)
810 const SwFormatHoriOrient
& rHoriOri
= rFrameFormat
.GetHoriOrient();
811 if( !(nFrameOptions
& HtmlFrmOpts::SAlign
) ||
812 text::RelOrientation::FRAME
== rHoriOri
.GetRelationOrient() ||
813 text::RelOrientation::PRINT_AREA
== rHoriOri
.GetRelationOrient() )
815 pAlignString
= text::HoriOrientation::RIGHT
== rHoriOri
.GetHoriOrient()
816 ? std::string_view(OOO_STRING_SVTOOLS_HTML_AL_right
)
817 : std::string_view(OOO_STRING_SVTOOLS_HTML_AL_left
);
820 const SwFormatVertOrient
* pVertOrient
;
821 if( (nFrameOptions
& HtmlFrmOpts::Align
) && pAlignString
.empty() &&
822 ( !(nFrameOptions
& HtmlFrmOpts::SAlign
) ||
823 (RndStdIds::FLY_AS_CHAR
== eAnchorId
) ) &&
824 (pVertOrient
= rItemSet
.GetItemIfSet( RES_VERT_ORIENT
)) )
826 switch( pVertOrient
->GetVertOrient() )
828 case text::VertOrientation::LINE_TOP
: pAlignString
= OOO_STRING_SVTOOLS_HTML_VA_top
; break;
829 case text::VertOrientation::CHAR_TOP
:
830 case text::VertOrientation::BOTTOM
: pAlignString
= OOO_STRING_SVTOOLS_HTML_VA_texttop
; break;
831 case text::VertOrientation::LINE_CENTER
:
832 case text::VertOrientation::CHAR_CENTER
: pAlignString
= OOO_STRING_SVTOOLS_HTML_VA_absmiddle
; break;
833 case text::VertOrientation::CENTER
: pAlignString
= OOO_STRING_SVTOOLS_HTML_VA_middle
; break;
834 case text::VertOrientation::LINE_BOTTOM
:
835 case text::VertOrientation::CHAR_BOTTOM
: pAlignString
= OOO_STRING_SVTOOLS_HTML_VA_absbottom
; break;
836 case text::VertOrientation::TOP
: pAlignString
= OOO_STRING_SVTOOLS_HTML_VA_bottom
; break;
837 case text::VertOrientation::NONE
: break;
840 if (!pAlignString
.empty() && !bReplacement
)
842 aHtml
.attribute(OOO_STRING_SVTOOLS_HTML_O_align
, pAlignString
);
846 Size
aTwipSpc( 0, 0 );
847 const SvxLRSpaceItem
* pLRSpaceItem
;
848 if( (nFrameOptions
& (HtmlFrmOpts::Space
| HtmlFrmOpts::MarginSize
)) &&
849 (pLRSpaceItem
= rItemSet
.GetItemIfSet( RES_LR_SPACE
)) )
852 ( pLRSpaceItem
->GetLeft() + pLRSpaceItem
->GetRight() ) / 2 );
853 m_nDfltLeftMargin
= m_nDfltRightMargin
= aTwipSpc
.Width();
855 const SvxULSpaceItem
* pULSpaceItem
;
856 if( (nFrameOptions
& (HtmlFrmOpts::Space
|HtmlFrmOpts::MarginSize
)) &&
857 (pULSpaceItem
= rItemSet
.GetItemIfSet( RES_UL_SPACE
)) )
860 ( pULSpaceItem
->GetUpper() + pULSpaceItem
->GetLower() ) / 2 );
861 m_nDfltTopMargin
= m_nDfltBottomMargin
= o3tl::narrowing
<sal_uInt16
>(aTwipSpc
.Height());
864 if( (nFrameOptions
& HtmlFrmOpts::Space
) &&
865 (aTwipSpc
.Width() || aTwipSpc
.Height()) &&
868 Size aPixelSpc
= SwHTMLWriter::ToPixel(aTwipSpc
);
870 if (aPixelSpc
.Width())
872 aHtml
.attribute(OOO_STRING_SVTOOLS_HTML_O_hspace
, static_cast<sal_Int32
>(aPixelSpc
.Width()));
875 if (aPixelSpc
.Height())
877 aHtml
.attribute(OOO_STRING_SVTOOLS_HTML_O_vspace
, static_cast<sal_Int32
>(aPixelSpc
.Height()));
881 // The spacing must be considered for the size, if the corresponding flag
883 if( nFrameOptions
& HtmlFrmOpts::MarginSize
)
885 aTwipSpc
.setWidth( aTwipSpc
.Width() * -2 );
886 aTwipSpc
.setHeight( aTwipSpc
.Height() * -2 );
890 aTwipSpc
.setWidth( 0 );
891 aTwipSpc
.setHeight( 0 );
894 const SvxBoxItem
* pBoxItem
;
895 if( !(nFrameOptions
& HtmlFrmOpts::AbsSize
) &&
896 (pBoxItem
= rItemSet
.GetItemIfSet( RES_BOX
)) )
898 aTwipSpc
.AdjustWidth(pBoxItem
->CalcLineSpace( SvxBoxItemLine::LEFT
) );
899 aTwipSpc
.AdjustWidth(pBoxItem
->CalcLineSpace( SvxBoxItemLine::RIGHT
) );
900 aTwipSpc
.AdjustHeight(pBoxItem
->CalcLineSpace( SvxBoxItemLine::TOP
) );
901 aTwipSpc
.AdjustHeight(pBoxItem
->CalcLineSpace( SvxBoxItemLine::BOTTOM
) );
904 // "width" and/or "height"
905 // Only output SwFrameSize::Variable/SwFrameSize::Minimum if ANYSIZE is set
906 std::optional
<SwFormatFrameSize
> aFrameSize
;
907 const SwFormatFrameSize
* pFSItem
= rItemSet
.GetItemIfSet( RES_FRM_SIZE
);
908 const SdrObject
* pObject
;
909 if (!pFSItem
&& (pObject
= rFrameFormat
.FindSdrObject()))
911 // Write size for Draw shapes as well.
912 const tools::Rectangle
& rSnapRect
= pObject
->GetSnapRect();
913 aFrameSize
.emplace();
914 aFrameSize
->SetWidthSizeType(SwFrameSize::Fixed
);
915 aFrameSize
->SetWidth(rSnapRect
.getOpenWidth());
916 aFrameSize
->SetHeightSizeType(SwFrameSize::Fixed
);
917 aFrameSize
->SetHeight(rSnapRect
.getOpenHeight());
918 pFSItem
= &*aFrameSize
;
920 if( (nFrameOptions
& HtmlFrmOpts::Size
) &&
922 ( (nFrameOptions
& HtmlFrmOpts::AnySize
) ||
923 SwFrameSize::Fixed
== pFSItem
->GetHeightSizeType()) )
925 sal_uInt8 nPercentWidth
= pFSItem
->GetWidthPercent();
926 sal_uInt8 nPercentHeight
= pFSItem
->GetHeightPercent();
928 // Size of the object in Twips without margins
929 Size
aTwipSz( (nPercentWidth
&& nPercentWidth
!= 255 ? 0
930 : pFSItem
->GetWidth()-aTwipSpc
.Width()),
931 (nPercentHeight
&& nPercentHeight
!= 255 ? 0
932 : pFSItem
->GetHeight()-aTwipSpc
.Height()) );
934 OSL_ENSURE( aTwipSz
.Width() >= 0 && aTwipSz
.Height() >= 0, "Frame size minus spacing < 0!!!???" );
935 if( aTwipSz
.Width() < 0 )
936 aTwipSz
.setWidth( 0 );
937 if( aTwipSz
.Height() < 0 )
938 aTwipSz
.setHeight( 0 );
940 Size
aPixelSz(SwHTMLWriter::ToPixel(aTwipSz
));
942 if( (nFrameOptions
& HtmlFrmOpts::Width
) &&
943 ((nPercentWidth
&& nPercentWidth
!=255) || aPixelSz
.Width()) )
948 if (nPercentWidth
== 255)
956 sWidth
= OString::number(static_cast<sal_Int32
>(aPixelSz
.Width()));
961 sWidth
= OString::number(static_cast<sal_Int32
>(nPercentWidth
)) + "%";
965 sWidth
= OString::number(static_cast<sal_Int32
>(aPixelSz
.Width()));
966 if (!mbXHTML
|| sWidth
!= "auto")
968 aHtml
.attribute(OOO_STRING_SVTOOLS_HTML_O_width
, sWidth
);
972 if( (nFrameOptions
& HtmlFrmOpts::Height
) &&
973 ((nPercentHeight
&& nPercentHeight
!=255) || aPixelSz
.Height()) )
978 if (nPercentHeight
== 255)
986 sHeight
= OString::number(static_cast<sal_Int32
>(aPixelSz
.Height()));
991 sHeight
= OString::number(static_cast<sal_Int32
>(nPercentHeight
)) + "%";
995 sHeight
= OString::number(static_cast<sal_Int32
>(aPixelSz
.Height()));
996 if (!mbXHTML
|| sHeight
!= "auto")
998 aHtml
.attribute(OOO_STRING_SVTOOLS_HTML_O_height
, sHeight
);
1003 // Insert wrap for graphics that are anchored to a paragraph as
1004 // <BR CLEAR=...> in the string
1006 if( !(nFrameOptions
& HtmlFrmOpts::BrClear
) )
1008 RndStdIds nAnchorId
= rFrameFormat
.GetAnchor().GetAnchorId();
1009 if (RndStdIds::FLY_AT_PARA
!= nAnchorId
&& RndStdIds::FLY_AT_CHAR
!= nAnchorId
)
1011 const SwFormatSurround
* pSurround
= rItemSet
.GetItemIfSet( RES_SURROUND
);
1015 std::string_view pSurroundString
;
1017 sal_Int16 eHoriOri
= rFrameFormat
.GetHoriOrient().GetHoriOrient();
1018 css::text::WrapTextMode eSurround
= pSurround
->GetSurround();
1019 bool bAnchorOnly
= pSurround
->IsAnchorOnly();
1022 case text::HoriOrientation::RIGHT
:
1026 case css::text::WrapTextMode_NONE
:
1027 case css::text::WrapTextMode_RIGHT
:
1028 pSurroundString
= OOO_STRING_SVTOOLS_HTML_AL_right
;
1030 case css::text::WrapTextMode_LEFT
:
1031 case css::text::WrapTextMode_PARALLEL
:
1033 m_bClearRight
= true;
1042 // If a frame is centered, it gets left aligned. This
1043 // should be taken into account here, too.
1047 case css::text::WrapTextMode_NONE
:
1048 case css::text::WrapTextMode_LEFT
:
1049 pSurroundString
= OOO_STRING_SVTOOLS_HTML_AL_left
;
1051 case css::text::WrapTextMode_RIGHT
:
1052 case css::text::WrapTextMode_PARALLEL
:
1054 m_bClearLeft
= true;
1063 if (!pSurroundString
.empty())
1065 aHtml
.start(OOO_STRING_SVTOOLS_HTML_linebreak
);
1066 aHtml
.attribute(OOO_STRING_SVTOOLS_HTML_O_clear
, pSurroundString
);
1074 OUString
lclWriteOutImap(SwHTMLWriter
& rWrt
, const SfxItemSet
& rItemSet
, const SwFrameFormat
& rFrameFormat
,
1075 const Size
& rRealSize
, const ImageMap
* pAltImgMap
, const SwFormatURL
*& pURLItem
)
1079 // Only consider the URL attribute if no ImageMap was supplied
1081 pURLItem
= rItemSet
.GetItemIfSet( RES_URL
);
1084 const ImageMap
* pIMap
= pAltImgMap
;
1085 if( !pIMap
&& pURLItem
)
1087 pIMap
= pURLItem
->GetMap();
1092 // make the name unique
1093 aIMapName
= pIMap
->GetName();
1095 if (!aIMapName
.isEmpty())
1096 aNameBase
= aIMapName
;
1098 aNameBase
= OOO_STRING_SVTOOLS_HTML_map
;
1100 if (aIMapName
.isEmpty())
1101 aIMapName
= aNameBase
+ OUString::number(rWrt
.m_nImgMapCnt
);
1107 for (const OUString
& rImgMapName
: rWrt
.m_aImgMapNames
)
1109 // TODO: Unicode: Comparison is case insensitive for ASCII
1110 // characters only now!
1111 if (aIMapName
.equalsIgnoreAsciiCase(rImgMapName
))
1119 rWrt
.m_nImgMapCnt
++;
1120 aIMapName
= aNameBase
+ OUString::number( rWrt
.m_nImgMapCnt
);
1124 bool bScale
= false;
1125 Fraction
aScaleX(1, 1);
1126 Fraction
aScaleY(1, 1);
1128 const SwFormatFrameSize
& rFrameSize
= rFrameFormat
.GetFrameSize();
1129 const SvxBoxItem
& rBox
= rFrameFormat
.GetBox();
1131 if (!rFrameSize
.GetWidthPercent() && rRealSize
.Width())
1133 SwTwips nWidth
= rFrameSize
.GetWidth();
1134 nWidth
-= rBox
.CalcLineSpace(SvxBoxItemLine::LEFT
) + rBox
.CalcLineSpace(SvxBoxItemLine::RIGHT
);
1136 OSL_ENSURE( nWidth
> 0, "Are there any graphics that are 0 twip wide!?" );
1137 if (nWidth
<= 0) // should not happen
1140 if (rRealSize
.Width() != nWidth
)
1142 aScaleX
= Fraction(nWidth
, rRealSize
.Width());
1147 if (!rFrameSize
.GetHeightPercent() && rRealSize
.Height())
1149 SwTwips nHeight
= rFrameSize
.GetHeight();
1151 nHeight
-= rBox
.CalcLineSpace(SvxBoxItemLine::TOP
) + rBox
.CalcLineSpace(SvxBoxItemLine::BOTTOM
);
1153 OSL_ENSURE( nHeight
> 0, "Are there any graphics that are 0 twip high!?" );
1157 if (rRealSize
.Height() != nHeight
)
1159 aScaleY
= Fraction(nHeight
, rRealSize
.Height());
1164 rWrt
.m_aImgMapNames
.push_back(aIMapName
);
1166 OString aIndMap
, aIndArea
;
1167 const char *pIndArea
= nullptr, *pIndMap
= nullptr;
1169 if (rWrt
.m_bLFPossible
)
1171 rWrt
.OutNewLine( true );
1172 aIndMap
= rWrt
.GetIndentString();
1173 aIndArea
= rWrt
.GetIndentString(1);
1174 pIndArea
= aIndArea
.getStr();
1175 pIndMap
= aIndMap
.getStr();
1180 ImageMap
aScaledIMap(*pIMap
);
1181 aScaledIMap
.Scale(aScaleX
, aScaleY
);
1182 HTMLOutFuncs::Out_ImageMap( rWrt
.Strm(), rWrt
.GetBaseURL(), aScaledIMap
, aIMapName
,
1184 rWrt
.m_bCfgStarBasic
,
1185 SAL_NEWLINE_STRING
, pIndArea
, pIndMap
);
1189 HTMLOutFuncs::Out_ImageMap( rWrt
.Strm(), rWrt
.GetBaseURL(), *pIMap
, aIMapName
,
1191 rWrt
.m_bCfgStarBasic
,
1192 SAL_NEWLINE_STRING
, pIndArea
, pIndMap
);
1198 OUString
getFrameFormatText(const SwFrameFormat
& rFrameFormat
)
1200 const SwFormatContent
& rFlyContent
= rFrameFormat
.GetContent();
1201 const SwNodeIndex
* pSttIx
= rFlyContent
.GetContentIdx();
1205 const SwNodeOffset nStt
= pSttIx
->GetIndex();
1206 const auto& nodes
= rFrameFormat
.GetDoc()->GetNodes();
1207 const SwNodeOffset nEnd
= nodes
[nStt
]->EndOfSectionIndex();
1209 OUStringBuffer result
;
1210 for (SwNodeOffset i
= nStt
+ 1; i
< nEnd
; ++i
)
1212 if (const auto* pTextNd
= nodes
[i
]->GetTextNode())
1214 if (!result
.isEmpty())
1215 result
.append("\n");
1216 result
.append(comphelper::string::encodeForXml(pTextNd
->GetExpandText(
1217 nullptr, 0, -1, true, true, false,
1218 ExpandMode::ExpandFields
| ExpandMode::HideInvisible
| ExpandMode::HideDeletions
1219 | ExpandMode::HideFieldmarkCommands
)));
1223 return result
.makeStringAndClear();
1228 SwHTMLWriter
& OutHTML_ImageStart( HtmlWriter
& rHtml
, SwHTMLWriter
& rWrt
, const SwFrameFormat
&rFrameFormat
,
1229 const OUString
& rGraphicURL
,
1230 Graphic
const & rGraphic
, const OUString
& rAlternateText
,
1231 const Size
&rRealSize
, HtmlFrmOpts nFrameOpts
,
1232 const char *pMarkType
,
1233 const ImageMap
*pAltImgMap
,
1234 std::u16string_view rMimeType
)
1236 // <object data="..."> instead of <img src="...">
1237 bool bReplacement
= (nFrameOpts
& HtmlFrmOpts::Replacement
) || rWrt
.mbReqIF
;
1239 if (rWrt
.mbSkipImages
)
1242 // if necessary, temporarily close an open attribute
1243 if( !rWrt
.m_aINetFormats
.empty() )
1245 SwFormatINetFormat
* pINetFormat
= rWrt
.m_aINetFormats
.back();
1246 OutHTML_INetFormat( rWrt
, *pINetFormat
, false );
1249 OUString
aGraphicURL( rGraphicURL
);
1250 if( !rWrt
.mbEmbedImages
&& !HTMLOutFuncs::PrivateURLToInternalImg(aGraphicURL
) && !rWrt
.mpTempBaseURL
)
1251 aGraphicURL
= URIHelper::simpleNormalizedMakeRelative( rWrt
.GetBaseURL(), aGraphicURL
);
1253 const SfxItemSet
& rItemSet
= rFrameFormat
.GetAttrSet();
1255 const SwFormatURL
* pURLItem
= nullptr;
1256 OUString aIMapName
= lclWriteOutImap(rWrt
, rItemSet
, rFrameFormat
, rRealSize
, pAltImgMap
, pURLItem
);
1258 // put img into new line
1259 if( rWrt
.m_bLFPossible
)
1260 rWrt
.OutNewLine( true );
1262 // <a name=...></a>...<img ...>
1263 if( pMarkType
&& !rFrameFormat
.GetName().isEmpty() )
1265 rWrt
.OutImplicitMark( rFrameFormat
.GetName(), pMarkType
);
1268 // URL -> <a>...<img ... >...</a>
1269 const SvxMacroItem
*pMacItem
= rItemSet
.GetItemIfSet(RES_FRMMACRO
);
1271 if (pURLItem
|| pMacItem
)
1279 aMapURL
= pURLItem
->GetURL();
1280 aName
= pURLItem
->GetName();
1281 aTarget
= pURLItem
->GetTargetFrameName();
1284 bool bEvents
= pMacItem
&& !pMacItem
->GetMacroTable().empty();
1286 if( !aMapURL
.isEmpty() || !aName
.isEmpty() || !aTarget
.isEmpty() || bEvents
)
1288 rHtml
.start(OOO_STRING_SVTOOLS_HTML_anchor
);
1290 // Output "href" element if a link or macro exists
1291 if( !aMapURL
.isEmpty() || bEvents
)
1293 rHtml
.attribute(OOO_STRING_SVTOOLS_HTML_O_href
, rWrt
.convertHyperlinkHRefValue(aMapURL
));
1296 if( !aName
.isEmpty() )
1298 rHtml
.attribute(OOO_STRING_SVTOOLS_HTML_O_name
, aName
);
1301 if( !aTarget
.isEmpty() )
1303 rHtml
.attribute(OOO_STRING_SVTOOLS_HTML_O_target
, aTarget
);
1308 const SvxMacroTableDtor
& rMacTable
= pMacItem
->GetMacroTable();
1309 if (!rMacTable
.empty())
1311 HtmlWriterHelper::applyEvents(rHtml
, rMacTable
, aAnchorEventTable
, rWrt
.m_bCfgStarBasic
);
1317 // <font color = ...>...<img ... >...</font>
1318 sal_uInt16 nBorderWidth
= 0;
1319 const SvxBoxItem
* pBoxItem
;
1320 if( (nFrameOpts
& HtmlFrmOpts::Border
) &&
1321 (pBoxItem
= rItemSet
.GetItemIfSet( RES_BOX
)) )
1323 Size
aTwipBorder( 0, 0 );
1324 const ::editeng::SvxBorderLine
*pColBorderLine
= nullptr;
1325 const ::editeng::SvxBorderLine
*pBorderLine
= pBoxItem
->GetLeft();
1328 pColBorderLine
= pBorderLine
;
1329 aTwipBorder
.AdjustWidth(pBorderLine
->GetOutWidth() );
1332 pBorderLine
= pBoxItem
->GetRight();
1335 pColBorderLine
= pBorderLine
;
1336 aTwipBorder
.AdjustWidth(pBorderLine
->GetOutWidth() );
1339 pBorderLine
= pBoxItem
->GetTop();
1342 pColBorderLine
= pBorderLine
;
1343 aTwipBorder
.AdjustHeight(pBorderLine
->GetOutWidth() );
1346 pBorderLine
= pBoxItem
->GetBottom();
1349 pColBorderLine
= pBorderLine
;
1350 aTwipBorder
.AdjustHeight(pBorderLine
->GetOutWidth() );
1353 aTwipBorder
.setWidth( aTwipBorder
.Width() / 2 );
1354 aTwipBorder
.setHeight( aTwipBorder
.Height() / 2 );
1356 if( (aTwipBorder
.Width() || aTwipBorder
.Height()) &&
1357 Application::GetDefaultDevice() )
1359 Size aPixelBorder
= SwHTMLWriter::ToPixel(aTwipBorder
);
1361 if( aPixelBorder
.Width() )
1362 aPixelBorder
.setHeight( 0 );
1365 o3tl::narrowing
<sal_uInt16
>(aPixelBorder
.Width() + aPixelBorder
.Height());
1368 if( pColBorderLine
)
1370 rHtml
.start(OOO_STRING_SVTOOLS_HTML_font
);
1371 HtmlWriterHelper::applyColor(rHtml
, OOO_STRING_SVTOOLS_HTML_O_color
, pColBorderLine
->GetColor());
1375 OString
aTag(OOO_STRING_SVTOOLS_HTML_image
);
1377 // Write replacement graphic of OLE object as <object>.
1378 aTag
= OOO_STRING_SVTOOLS_HTML_object
;
1381 if(rWrt
.mbEmbedImages
)
1383 OUString aGraphicInBase64
;
1384 if (XOutBitmap::GraphicToBase64(rGraphic
, aGraphicInBase64
))
1386 OString
sBuffer(OString::Concat(OOO_STRING_SVTOOLS_HTML_O_data
)
1388 + OUStringToOString(aGraphicInBase64
, RTL_TEXTENCODING_UTF8
));
1389 rHtml
.attribute(OOO_STRING_SVTOOLS_HTML_O_src
, sBuffer
);
1392 rWrt
.m_nWarn
= WARN_SWG_POOR_LOAD
;
1396 OString
sBuffer(OUStringToOString(aGraphicURL
, RTL_TEXTENCODING_UTF8
));
1397 OString
aAttribute(OOO_STRING_SVTOOLS_HTML_O_src
);
1399 aAttribute
= OOO_STRING_SVTOOLS_HTML_O_data
;
1400 rHtml
.attribute(aAttribute
, sBuffer
);
1405 // Handle XHTML type attribute for OLE replacement images.
1406 if (!rMimeType
.empty())
1407 rHtml
.attribute(OOO_STRING_SVTOOLS_HTML_O_type
, rMimeType
);
1411 if (const SvxMacroItem
* pMacroItem
= rItemSet
.GetItemIfSet(RES_FRMMACRO
))
1413 const SvxMacroTableDtor
& rMacTable
= pMacroItem
->GetMacroTable();
1414 if (!rMacTable
.empty())
1416 HtmlWriterHelper::applyEvents(rHtml
, rMacTable
, aImageEventTable
, rWrt
.m_bCfgStarBasic
);
1420 // alt, align, width, height, hspace, vspace
1421 rWrt
.writeFrameFormatOptions(rHtml
, rFrameFormat
, rAlternateText
, nFrameOpts
);
1422 if( rWrt
.IsHTMLMode( HTMLMODE_ABS_POS_FLY
) )
1423 rWrt
.OutCSS1_FrameFormatOptions( rFrameFormat
, nFrameOpts
);
1425 if ((nFrameOpts
& HtmlFrmOpts::Border
) && !bReplacement
)
1427 rHtml
.attribute(OOO_STRING_SVTOOLS_HTML_O_border
, nBorderWidth
);
1430 if( pURLItem
&& pURLItem
->IsServerMap() )
1432 rHtml
.attribute(OOO_STRING_SVTOOLS_HTML_O_ismap
);
1435 if( !aIMapName
.isEmpty() )
1437 rHtml
.attribute(OOO_STRING_SVTOOLS_HTML_O_usemap
, Concat2View("#" + aIMapName
));
1442 OUString aAltText
= rAlternateText
;
1443 // In ReqIF mode, output text from the frame instead
1445 if (OUString aFrameText
= getFrameFormatText(rFrameFormat
); !aFrameText
.isEmpty())
1446 aAltText
= aFrameText
;
1448 // XHTML object replacement image's alternate text doesn't use the
1450 if (aAltText
.isEmpty())
1451 // Empty alternate text is not valid.
1452 rHtml
.characters(" ");
1454 rHtml
.characters(aAltText
.toUtf8());
1460 SwHTMLWriter
& OutHTML_ImageEnd( HtmlWriter
& rHtml
, SwHTMLWriter
& rWrt
)
1464 if( !rWrt
.m_aINetFormats
.empty() )
1466 // There is still an attribute on the stack that has to be reopened
1467 SwFormatINetFormat
*pINetFormat
= rWrt
.m_aINetFormats
.back();
1468 OutHTML_INetFormat( rWrt
, *pINetFormat
, true );
1474 SwHTMLWriter
& OutHTML_BulletImage( SwHTMLWriter
& rWrt
,
1476 const SvxBrushItem
* pBrush
,
1477 const OUString
&rGraphicURL
)
1479 OUString aGraphicInBase64
;
1483 aLink
= pBrush
->GetGraphicLink();
1484 if(rWrt
.mbEmbedImages
|| aLink
.isEmpty())
1486 const Graphic
* pGrf
= pBrush
->GetGraphic();
1489 if( !XOutBitmap::GraphicToBase64(*pGrf
, aGraphicInBase64
) )
1491 rWrt
.m_nWarn
= WARN_SWG_POOR_LOAD
;
1495 else if(!aLink
.isEmpty())
1497 if( rWrt
.m_bCfgCpyLinkedGrfs
)
1499 rWrt
.CopyLocalFileToINet( aLink
);
1504 else if(!rWrt
.mbEmbedImages
)
1506 aLink
= rGraphicURL
;
1508 if(!aLink
.isEmpty())
1510 if( !HTMLOutFuncs::PrivateURLToInternalImg(aLink
) )
1511 aLink
= URIHelper::simpleNormalizedMakeRelative( rWrt
.GetBaseURL(), aLink
);
1516 sOut
.append(OString::Concat("<") + pTag
);
1518 sOut
.append(" " OOO_STRING_SVTOOLS_HTML_O_style
"=\"");
1519 if(!aLink
.isEmpty())
1521 sOut
.append(OOO_STRING_SVTOOLS_HTML_O_src
"=\"");
1522 rWrt
.Strm().WriteOString( sOut
);
1524 HTMLOutFuncs::Out_String( rWrt
.Strm(), aLink
);
1528 sOut
.append("list-style-image: url("
1529 OOO_STRING_SVTOOLS_HTML_O_data
":");
1530 rWrt
.Strm().WriteOString( sOut
);
1532 HTMLOutFuncs::Out_String( rWrt
.Strm(), aGraphicInBase64
);
1539 rWrt
.Strm().WriteOString( sOut
);
1544 static SwHTMLWriter
& OutHTML_FrameFormatTableNode( SwHTMLWriter
& rWrt
, const SwFrameFormat
& rFrameFormat
)
1546 const SwFormatContent
& rFlyContent
= rFrameFormat
.GetContent();
1547 SwNodeOffset nStt
= rFlyContent
.GetContentIdx()->GetIndex()+1;
1548 SwNodeOffset nEnd
= rWrt
.m_pDoc
->GetNodes()[nStt
-1]->EndOfSectionIndex();
1551 bool bTopCaption
= false;
1553 // Not const, because GetTable won't be const sometime later
1554 SwNode
*pNd
= rWrt
.m_pDoc
->GetNodes()[ nStt
];
1555 SwTableNode
*pTableNd
= pNd
->GetTableNode();
1556 const SwTextNode
*pTextNd
= pNd
->GetTextNode();
1557 if( !pTableNd
&& pTextNd
)
1559 // Table with heading
1561 pTableNd
= rWrt
.m_pDoc
->GetNodes()[nStt
+1]->GetTableNode();
1563 OSL_ENSURE( pTableNd
, "Frame does not contain a table" );
1566 SwNodeOffset nTableEnd
= pTableNd
->EndOfSectionIndex();
1567 OSL_ENSURE( nTableEnd
== nEnd
- 1 ||
1568 (nTableEnd
== nEnd
- 2 && !bTopCaption
),
1569 "Invalid frame content for a table" );
1571 if( nTableEnd
== nEnd
- 2 )
1572 pTextNd
= rWrt
.m_pDoc
->GetNodes()[nTableEnd
+1]->GetTextNode();
1575 aCaption
= pTextNd
->GetText();
1579 HTMLSaveData
aSaveData( rWrt
, pTableNd
->GetIndex()+1,
1580 pTableNd
->EndOfSectionIndex(),
1581 true, &rFrameFormat
);
1582 rWrt
.m_bOutFlyFrame
= true;
1583 OutHTML_SwTableNode( rWrt
, *pTableNd
, &rFrameFormat
, &aCaption
,
1590 static SwHTMLWriter
& OutHTML_FrameFormatAsMulticol( SwHTMLWriter
& rWrt
,
1591 const SwFrameFormat
& rFrameFormat
,
1594 rWrt
.ChangeParaToken( HtmlTokenId::NONE
);
1596 // Close the current <DL>!
1597 rWrt
.OutAndSetDefList( 0 );
1599 // output as Multicol
1600 if( rWrt
.m_bLFPossible
)
1603 OStringBuffer
sOut("<" + rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_multicol
);
1605 const SwFormatCol
& rFormatCol
= rFrameFormat
.GetCol();
1607 // output the number of columns as COLS
1608 sal_uInt16 nCols
= rFormatCol
.GetNumCols();
1611 sOut
.append(" " OOO_STRING_SVTOOLS_HTML_O_cols
1612 "=\"" + OString::number(nCols
) + "\"");
1615 // the Gutter width (minimum value) as GUTTER
1616 sal_uInt16 nGutter
= rFormatCol
.GetGutterWidth( true );
1617 if( nGutter
!=USHRT_MAX
)
1619 nGutter
= SwHTMLWriter::ToPixel(nGutter
);
1620 sOut
.append(" " OOO_STRING_SVTOOLS_HTML_O_gutter
1621 "=\"" + OString::number(nGutter
) + "\"");
1624 rWrt
.Strm().WriteOString( sOut
);
1628 HtmlFrmOpts nFrameFlags
= HTML_FRMOPTS_MULTICOL
;
1629 if( rWrt
.IsHTMLMode( HTMLMODE_ABS_POS_FLY
) && !bInCntnr
)
1630 nFrameFlags
|= HTML_FRMOPTS_MULTICOL_CSS1
;
1631 rWrt
.OutFrameFormatOptions(rFrameFormat
, OUString(), nFrameFlags
);
1632 if( rWrt
.IsHTMLMode( HTMLMODE_ABS_POS_FLY
) && !bInCntnr
)
1633 rWrt
.OutCSS1_FrameFormatOptions( rFrameFormat
, nFrameFlags
);
1635 rWrt
.Strm().WriteChar( '>' );
1637 rWrt
.m_bLFPossible
= true;
1638 rWrt
.IncIndentLevel(); // indent the content of Multicol
1640 const SwFormatContent
& rFlyContent
= rFrameFormat
.GetContent();
1641 SwNodeOffset nStt
= rFlyContent
.GetContentIdx()->GetIndex();
1642 const SwStartNode
* pSttNd
= rWrt
.m_pDoc
->GetNodes()[nStt
]->GetStartNode();
1643 OSL_ENSURE( pSttNd
, "Where is the start node" );
1646 // in a block, so that the old state can be restored in time
1648 HTMLSaveData
aSaveData( rWrt
, nStt
+1,
1649 pSttNd
->EndOfSectionIndex(),
1650 true, &rFrameFormat
);
1651 rWrt
.m_bOutFlyFrame
= true;
1652 rWrt
.Out_SwDoc( rWrt
.m_pCurrentPam
.get() );
1655 rWrt
.DecIndentLevel(); // indent the content of Multicol;
1656 if( rWrt
.m_bLFPossible
)
1658 HTMLOutFuncs::Out_AsciiTag( rWrt
.Strm(), Concat2View(rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_multicol
), false );
1659 rWrt
.m_bLFPossible
= true;
1664 static SwHTMLWriter
& OutHTML_FrameFormatAsSpacer( SwHTMLWriter
& rWrt
, const SwFrameFormat
& rFrameFormat
)
1666 // if possible, output a line break before the graphic
1667 if( rWrt
.m_bLFPossible
)
1668 rWrt
.OutNewLine( true );
1671 "<" + rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_spacer
" "
1672 OOO_STRING_SVTOOLS_HTML_O_type
"=\""
1673 OOO_STRING_SVTOOLS_HTML_SPTYPE_block
"\"";
1674 rWrt
.Strm().WriteOString( sOut
);
1676 // ALIGN, WIDTH, HEIGHT
1677 OString aEndTags
= rWrt
.OutFrameFormatOptions(rFrameFormat
, OUString(), HTML_FRMOPTS_SPACER
);
1679 rWrt
.Strm().WriteChar( '>' );
1680 if( !aEndTags
.isEmpty() )
1681 rWrt
.Strm().WriteOString( aEndTags
);
1686 static SwHTMLWriter
& OutHTML_FrameFormatAsDivOrSpan( SwHTMLWriter
& rWrt
,
1687 const SwFrameFormat
& rFrameFormat
, bool bSpan
)
1692 rWrt
.ChangeParaToken( HtmlTokenId::NONE
);
1694 // Close the current <DL>!
1695 rWrt
.OutAndSetDefList( 0 );
1696 aTag
= OOO_STRING_SVTOOLS_HTML_division
;
1699 aTag
= OOO_STRING_SVTOOLS_HTML_span
;
1702 if( rWrt
.m_bLFPossible
)
1705 OStringBuffer
sOut("<" + rWrt
.GetNamespace() + aTag
);
1707 rWrt
.Strm().WriteOString( sOut
);
1709 HtmlFrmOpts nFrameFlags
= HTML_FRMOPTS_DIV
;
1710 if( rWrt
.IsHTMLMode( HTMLMODE_BORDER_NONE
) )
1711 nFrameFlags
|= HtmlFrmOpts::SNoBorder
;
1712 OString aEndTags
= rWrt
.OutFrameFormatOptions(rFrameFormat
, OUString(), nFrameFlags
);
1713 rWrt
.OutCSS1_FrameFormatOptions( rFrameFormat
, nFrameFlags
);
1714 rWrt
.Strm().WriteChar( '>' );
1716 rWrt
.IncIndentLevel(); // indent the content
1717 rWrt
.m_bLFPossible
= true;
1719 const SwFormatContent
& rFlyContent
= rFrameFormat
.GetContent();
1720 SwNodeOffset nStt
= rFlyContent
.GetContentIdx()->GetIndex();
1722 // Output frame-anchored frames that are anchored to the start node
1723 rWrt
.OutFlyFrame( nStt
, 0, HtmlPosition::Any
);
1725 const SwStartNode
* pSttNd
= rWrt
.m_pDoc
->GetNodes()[nStt
]->GetStartNode();
1726 OSL_ENSURE( pSttNd
, "Where is the start node" );
1729 // in a block, so that the old state can be restored in time
1731 HTMLSaveData
aSaveData( rWrt
, nStt
+1,
1732 pSttNd
->EndOfSectionIndex(),
1733 true, &rFrameFormat
);
1734 rWrt
.m_bOutFlyFrame
= true;
1735 rWrt
.Out_SwDoc( rWrt
.m_pCurrentPam
.get() );
1738 rWrt
.DecIndentLevel(); // indent the content of Multicol;
1739 if( rWrt
.m_bLFPossible
)
1741 HTMLOutFuncs::Out_AsciiTag( rWrt
.Strm(), Concat2View(rWrt
.GetNamespace() + aTag
), false );
1743 if( !aEndTags
.isEmpty() )
1744 rWrt
.Strm().WriteOString( aEndTags
);
1749 /// Starts the OLE version of an image in the ReqIF + OLE case.
1750 static void OutHTML_ImageOLEStart(SwHTMLWriter
& rWrt
, const Graphic
& rGraphic
,
1751 const SwFrameFormat
& rFrameFormat
)
1753 if (!rWrt
.mbReqIF
|| !rWrt
.m_bExportImagesAsOLE
)
1756 // Write the original image as an RTF fragment.
1758 if (rWrt
.GetOrigFileName())
1759 aFileName
= *rWrt
.GetOrigFileName();
1760 INetURLObject
aURL(aFileName
);
1761 OUString aName
= aURL
.getBase() + "_" + aURL
.getExtension() + "_"
1762 + OUString::number(rGraphic
.GetChecksum(), 16);
1763 aURL
.setBase(aName
);
1764 aURL
.setExtension(u
"ole");
1765 aFileName
= aURL
.GetMainURL(INetURLObject::DecodeMechanism::NONE
);
1767 SvFileStream
aOutStream(aFileName
, StreamMode::WRITE
);
1768 if (!SwReqIfReader::WrapGraphicInRtf(rGraphic
, rFrameFormat
, aOutStream
))
1769 SAL_WARN("sw.html", "SwReqIfReader::WrapGraphicInRtf() failed");
1771 // Refer to this data.
1772 aFileName
= URIHelper::simpleNormalizedMakeRelative(rWrt
.GetBaseURL(), aFileName
);
1773 rWrt
.Strm().WriteOString(
1774 Concat2View("<" + rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_object
));
1775 rWrt
.Strm().WriteOString(Concat2View(" data=\"" + aFileName
.toUtf8() + "\""));
1776 rWrt
.Strm().WriteOString(" type=\"text/rtf\"");
1777 rWrt
.Strm().WriteOString(">");
1781 /// Ends the OLE version of an image in the ReqIF + OLE case.
1782 static void OutHTML_ImageOLEEnd(SwHTMLWriter
& rWrt
)
1784 if (rWrt
.mbReqIF
&& rWrt
.m_bExportImagesAsOLE
)
1786 rWrt
.Strm().WriteOString(
1787 Concat2View("</" + rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_object
">"));
1791 static SwHTMLWriter
& OutHTML_FrameFormatAsImage( SwHTMLWriter
& rWrt
, const SwFrameFormat
& rFrameFormat
, bool bPNGFallback
)
1793 bool bWritePNGFallback
= rWrt
.mbReqIF
&& !rWrt
.m_bExportImagesAsOLE
&& bPNGFallback
;
1795 if (rWrt
.mbSkipImages
)
1799 std::optional
<Size
> aDPI
;
1800 if (rWrt
.m_nShapeDPI
.has_value())
1802 aDPI
.emplace(*rWrt
.m_nShapeDPI
, *rWrt
.m_nShapeDPI
);
1804 Graphic
aGraphic( const_cast<SwFrameFormat
&>(rFrameFormat
).MakeGraphic( &aIMap
, /*nMaximumQuadraticPixels=*/2100000, aDPI
) );
1808 // ImageMap doesn't seem to be allowed in reqif.
1809 if (auto pGrafObj
= dynamic_cast<const SdrGrafObj
*>(rFrameFormat
.FindSdrObject()))
1811 aGraphic
= pGrafObj
->GetGraphic();
1815 // We only have a bitmap, write that as PNG without any fallback.
1816 bWritePNGFallback
= false;
1821 OUString GraphicURL
;
1822 OUString
aMimeType("image/jpeg");
1823 if(!rWrt
.mbEmbedImages
)
1825 if( rWrt
.GetOrigFileName() )
1826 GraphicURL
= *rWrt
.GetOrigFileName();
1828 OUString
aFilterName("JPG");
1829 XOutFlags nFlags
= XOutFlags::UseGifIfPossible
| XOutFlags::UseNativeIfPossible
;
1831 if (rWrt
.mbReqIF
&& !bWritePNGFallback
)
1833 // Writing image without fallback PNG in ReqIF mode: force PNG output.
1834 aFilterName
= "PNG";
1835 nFlags
= XOutFlags::NONE
;
1836 aMimeType
= "image/png";
1838 else if (rWrt
.mbReqIF
)
1840 // Original format is wanted, don't force JPG.
1841 aFilterName
.clear();
1845 if( aGraphic
.GetType() == GraphicType::NONE
||
1846 XOutBitmap::WriteGraphic( aGraphic
, GraphicURL
,
1848 nFlags
) != ERRCODE_NONE
)
1850 // empty or incorrect, because there is nothing to output
1851 rWrt
.m_nWarn
= WARN_SWG_POOR_LOAD
;
1855 GraphicURL
= URIHelper::SmartRel2Abs(
1856 INetURLObject(rWrt
.GetBaseURL()), GraphicURL
,
1857 URIHelper::GetMaybeFileHdl() );
1860 uno::Reference
<beans::XPropertySet
> xGraphic(aGraphic
.GetXGraphic(), uno::UNO_QUERY
);
1861 if (xGraphic
.is() && aMimeType
.isEmpty())
1862 xGraphic
->getPropertyValue("MimeType") >>= aMimeType
;
1864 OutHTML_ImageOLEStart(rWrt
, aGraphic
, rFrameFormat
);
1866 HtmlWriter
aHtml(rWrt
.Strm(), rWrt
.maNamespace
);
1867 OutHTML_ImageStart( aHtml
, rWrt
, rFrameFormat
, GraphicURL
, aGraphic
, rFrameFormat
.GetName(), aSz
,
1868 HtmlFrmOpts::GenImgMask
, "frame",
1869 aIMap
.GetIMapObjectCount() ? &aIMap
: nullptr, aMimeType
);
1871 GfxLink aLink
= aGraphic
.GetGfxLink();
1872 if (bWritePNGFallback
&& aLink
.GetType() != GfxLinkType::NativePng
)
1874 OutHTML_FrameFormatAsImage( rWrt
, rFrameFormat
, /*bPNGFallback=*/false);
1877 OutHTML_ImageEnd(aHtml
, rWrt
);
1879 OutHTML_ImageOLEEnd(rWrt
);
1884 static SwHTMLWriter
& OutHTML_FrameFormatGrfNode( SwHTMLWriter
& rWrt
, const SwFrameFormat
& rFrameFormat
,
1885 bool bInCntnr
, bool bPNGFallback
)
1887 bool bWritePNGFallback
= rWrt
.mbReqIF
&& !rWrt
.m_bExportImagesAsOLE
&& bPNGFallback
;
1889 if (rWrt
.mbSkipImages
)
1892 const SwFormatContent
& rFlyContent
= rFrameFormat
.GetContent();
1893 SwNodeOffset nStt
= rFlyContent
.GetContentIdx()->GetIndex()+1;
1894 SwGrfNode
*pGrfNd
= rWrt
.m_pDoc
->GetNodes()[ nStt
]->GetGrfNode();
1895 OSL_ENSURE( pGrfNd
, "Grf node expected" );
1899 HtmlFrmOpts nFrameFlags
= bInCntnr
? HTML_FRMOPTS_IMG_CNTNR
: HTML_FRMOPTS_IMG
;
1900 if( rWrt
.IsHTMLMode( HTMLMODE_ABS_POS_FLY
) && !bInCntnr
)
1901 nFrameFlags
|= HTML_FRMOPTS_IMG_CSS1
;
1903 Graphic aGraphic
= pGrfNd
->GetGraphic();
1905 if (aGraphic
.GetType() == GraphicType::GdiMetafile
)
1907 // We only have a metafile, write that as PNG without any fallback.
1908 bWritePNGFallback
= false;
1911 OUString aGraphicURL
;
1913 if(!rWrt
.mbEmbedImages
)
1915 const SwMirrorGrf
& rMirror
= pGrfNd
->GetSwAttrSet().GetMirrorGrf();
1917 if( !pGrfNd
->IsLinkedFile() || MirrorGraph::Dont
!= rMirror
.GetValue() )
1919 // create a (mirrored) jpeg file
1920 if( rWrt
.GetOrigFileName() )
1921 aGraphicURL
= *rWrt
.GetOrigFileName();
1923 aGraphicURL
= rWrt
.GetBaseURL();
1924 pGrfNd
->GetGrf( true );
1926 XOutFlags nFlags
= XOutFlags::UseGifIfSensible
|
1927 XOutFlags::UseNativeIfPossible
;
1928 switch( rMirror
.GetValue() )
1930 case MirrorGraph::Vertical
: nFlags
= XOutFlags::MirrorHorz
; break;
1931 case MirrorGraph::Horizontal
: nFlags
= XOutFlags::MirrorVert
; break;
1932 case MirrorGraph::Both
:
1933 nFlags
= XOutFlags::MirrorVert
| XOutFlags::MirrorHorz
;
1938 const SwFormatFrameSize
& rSize
= rFrameFormat
.GetFrameSize();
1939 Size aMM100Size
= o3tl::convert( rSize
.GetSize(),
1940 o3tl::Length::twip
, o3tl::Length::mm100
);
1942 OUString aFilterName
;
1946 // In ReqIF mode, do not try to write GIF for other image types
1947 nFlags
&= ~XOutFlags::UseGifIfSensible
;
1948 if (!bWritePNGFallback
)
1950 // Writing image without fallback PNG in ReqIF mode: force PNG
1952 // But don't force it when writing the original format and we'll write PNG inside
1954 aFilterName
= "PNG";
1955 nFlags
&= ~XOutFlags::UseNativeIfPossible
;
1959 const Graphic
& rGraphic
= pGrfNd
->GetGrf();
1961 // So that Graphic::IsTransparent() can report true.
1962 if (!rGraphic
.isAvailable())
1963 const_cast<Graphic
&>(rGraphic
).makeAvailable();
1965 if (rWrt
.mbReqIF
&& bWritePNGFallback
)
1967 // ReqIF: force native data if possible.
1968 const std::shared_ptr
<VectorGraphicData
>& pVectorGraphicData
= rGraphic
.getVectorGraphicData();
1969 if (pVectorGraphicData
&& pVectorGraphicData
->getType() == VectorGraphicDataType::Svg
)
1971 aFilterName
= "svg";
1973 else if (rGraphic
.GetGfxLink().IsEMF())
1975 aFilterName
= "emf";
1977 else if (pVectorGraphicData
&& pVectorGraphicData
->getType() == VectorGraphicDataType::Wmf
)
1979 aFilterName
= "wmf";
1981 else if (rGraphic
.GetGfxLink().GetType() == GfxLinkType::NativeTif
)
1983 aFilterName
= "tif";
1987 ErrCode nErr
= XOutBitmap::WriteGraphic( rGraphic
, aGraphicURL
,
1988 aFilterName
, nFlags
, &aMM100Size
, nullptr, &aMimeType
);
1991 rWrt
.m_nWarn
= WARN_SWG_POOR_LOAD
;
1994 aGraphicURL
= URIHelper::SmartRel2Abs(
1995 INetURLObject(rWrt
.GetBaseURL()), aGraphicURL
,
1996 URIHelper::GetMaybeFileHdl() );
2000 pGrfNd
->GetFileFilterNms( &aGraphicURL
, nullptr );
2001 if( rWrt
.m_bCfgCpyLinkedGrfs
)
2002 rWrt
.CopyLocalFileToINet( aGraphicURL
);
2006 uno::Reference
<beans::XPropertySet
> xGraphic(aGraphic
.GetXGraphic(), uno::UNO_QUERY
);
2007 if (xGraphic
.is() && aMimeType
.isEmpty())
2008 xGraphic
->getPropertyValue("MimeType") >>= aMimeType
;
2010 OutHTML_ImageOLEStart(rWrt
, aGraphic
, rFrameFormat
);
2012 HtmlWriter
aHtml(rWrt
.Strm(), rWrt
.maNamespace
);
2013 OutHTML_ImageStart( aHtml
, rWrt
, rFrameFormat
, aGraphicURL
, aGraphic
, pGrfNd
->GetTitle(),
2014 pGrfNd
->GetTwipSize(), nFrameFlags
, "graphic", nullptr, aMimeType
);
2016 GfxLink aLink
= aGraphic
.GetGfxLink();
2017 if (bWritePNGFallback
&& aLink
.GetType() != GfxLinkType::NativePng
)
2019 // Not OLE mode, outer format is not PNG: write inner PNG.
2020 OutHTML_FrameFormatGrfNode( rWrt
, rFrameFormat
,
2021 bInCntnr
, /*bPNGFallback=*/false );
2024 OutHTML_ImageEnd(aHtml
, rWrt
);
2026 OutHTML_ImageOLEEnd(rWrt
);
2031 static SwHTMLWriter
& OutHTML_FrameFormatAsMarquee( SwHTMLWriter
& rWrt
, const SwFrameFormat
& rFrameFormat
,
2032 const SdrObject
& rSdrObj
)
2034 // get the edit engine attributes of the object as SW attributes and
2035 // sort them as Hints
2036 const SfxItemSet
& rFormatItemSet
= rFrameFormat
.GetAttrSet();
2037 SfxItemSetFixed
<RES_CHRATR_BEGIN
, RES_CHRATR_END
> aItemSet( *rFormatItemSet
.GetPool() );
2038 SwHTMLWriter::GetEEAttrsFromDrwObj( aItemSet
, &rSdrObj
);
2039 bool bCfgOutStylesOld
= rWrt
.m_bCfgOutStyles
;
2040 rWrt
.m_bCfgOutStyles
= false;
2041 rWrt
.m_bTextAttr
= true;
2042 rWrt
.m_bTagOn
= true;
2043 Out_SfxItemSet( aHTMLAttrFnTab
, rWrt
, aItemSet
, false );
2044 rWrt
.m_bTextAttr
= false;
2046 OutHTML_DrawFrameFormatAsMarquee( rWrt
,
2047 static_cast<const SwDrawFrameFormat
&>(rFrameFormat
),
2049 rWrt
.m_bTextAttr
= true;
2050 rWrt
.m_bTagOn
= false;
2051 Out_SfxItemSet( aHTMLAttrFnTab
, rWrt
, aItemSet
, false );
2052 rWrt
.m_bTextAttr
= false;
2053 rWrt
.m_bCfgOutStyles
= bCfgOutStylesOld
;
2058 SwHTMLWriter
& OutHTML_HeaderFooter( SwHTMLWriter
& rWrt
, const SwFrameFormat
& rFrameFormat
,
2061 // output as Multicol
2064 sOut
.append(OOO_STRING_SVTOOLS_HTML_division
" "
2065 OOO_STRING_SVTOOLS_HTML_O_title
"=\"")
2066 .append( bHeader
? "header" : "footer" ).append("\"");
2067 HTMLOutFuncs::Out_AsciiTag( rWrt
.Strm(), Concat2View(rWrt
.GetNamespace() + sOut
) );
2069 rWrt
.IncIndentLevel(); // indent the content of Multicol;
2071 // Piece a spacer for the spacing together. Because the
2072 // <DL> or </DL> always produces a space between paragraphs, it is
2073 // subtracted if necessary.
2074 const SvxULSpaceItem
& rULSpace
= rFrameFormat
.GetULSpace();
2075 sal_uInt16 nSize
= bHeader
? rULSpace
.GetLower() : rULSpace
.GetUpper();
2076 rWrt
.m_nHeaderFooterSpace
= nSize
;
2079 if( rWrt
.IsHTMLMode(HTMLMODE_VERT_SPACER
) &&
2080 nSize
> HTML_PARSPACE
)
2082 nSize
-= HTML_PARSPACE
;
2083 nSize
= SwHTMLWriter::ToPixel(nSize
);
2085 aSpacer
= OOO_STRING_SVTOOLS_HTML_spacer
2086 " " OOO_STRING_SVTOOLS_HTML_O_type
2087 "=\"" OOO_STRING_SVTOOLS_HTML_SPTYPE_vertical
"\""
2088 " " OOO_STRING_SVTOOLS_HTML_O_size
2089 "=\"" + OString::number(nSize
) + "\"";
2092 const SwFormatContent
& rFlyContent
= rFrameFormat
.GetContent();
2093 SwNodeOffset nStt
= rFlyContent
.GetContentIdx()->GetIndex();
2094 const SwStartNode
* pSttNd
= rWrt
.m_pDoc
->GetNodes()[nStt
]->GetStartNode();
2095 OSL_ENSURE( pSttNd
, "Where is the start node" );
2097 if( !bHeader
&& !aSpacer
.isEmpty() )
2100 HTMLOutFuncs::Out_AsciiTag( rWrt
.Strm(), Concat2View(rWrt
.GetNamespace() + aSpacer
) );
2104 // in a block, so that the old state can be restored in time
2105 // before the end. pFlyFormat doesn't need to be set here, because
2106 // PageDesc attributes cannot occur here
2107 HTMLSaveData
aSaveData( rWrt
, nStt
+1,
2108 pSttNd
->EndOfSectionIndex() );
2111 rWrt
.m_bOutHeader
= true;
2113 rWrt
.m_bOutFooter
= true;
2115 rWrt
.Out_SwDoc( rWrt
.m_pCurrentPam
.get() );
2118 if( bHeader
&& !aSpacer
.isEmpty() )
2121 HTMLOutFuncs::Out_AsciiTag( rWrt
.Strm(), Concat2View(rWrt
.GetNamespace() + aSpacer
) );
2124 rWrt
.DecIndentLevel(); // indent the content of Multicol;
2126 HTMLOutFuncs::Out_AsciiTag( rWrt
.Strm(), Concat2View(rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_division
), false );
2128 rWrt
.m_nHeaderFooterSpace
= 0;
2133 void SwHTMLWriter::AddLinkTarget( std::u16string_view aURL
)
2135 if( aURL
.empty() || aURL
[0] != '#' )
2138 // There might be a '|' as delimiter (if the link has been inserted
2139 // freshly) or a '%7c' or a '%7C' if the document has been saved and
2141 sal_Int32 nPos
= aURL
.size();
2142 bool bFound
= false, bEncoded
= false;
2143 while( !bFound
&& nPos
> 0 )
2145 sal_Unicode c
= aURL
[ --nPos
];
2148 case cMarkSeparator
:
2152 bFound
= (aURL
.size() - nPos
) >=3 && aURL
[ nPos
+1 ] == '7';
2156 bFound
= (c
== 'C' || c
== 'c');
2162 if( !bFound
|| nPos
< 2 ) // at least "#a|..."
2165 aURL
= aURL
.substr( 1 );
2167 // nPos-1+1/3 (-1 because of Erase)
2168 OUString sCmp
= OUString(aURL
.substr(bEncoded
? nPos
+2 : nPos
)).replaceAll(" ","");
2169 if( sCmp
.isEmpty() )
2172 sCmp
= sCmp
.toAsciiLowerCase();
2174 if( sCmp
== "region" ||
2176 sCmp
== "graphic" ||
2180 // Just remember it in a sorted array
2181 OUString
aURL2(aURL
);
2184 aURL2
= aURL2
.replaceAt( nPos
- 1, 3, rtl::OUStringChar(cMarkSeparator
) );
2186 m_aImplicitMarks
.insert( aURL2
);
2188 else if( sCmp
== "outline" )
2190 // Here, we need position and name. That's why we sort a
2191 // sal_uInt16 and a string array ourselves.
2192 OUString
aOutline( aURL
.substr( 0, nPos
-1 ) );
2193 SwPosition
aPos( *m_pCurrentPam
->GetPoint() );
2194 if( m_pDoc
->GotoOutline( aPos
, aOutline
) )
2196 SwNodeOffset nIdx
= aPos
.GetNodeIndex();
2198 decltype(m_aOutlineMarkPoss
)::size_type nIns
=0;
2199 while( nIns
< m_aOutlineMarkPoss
.size() &&
2200 m_aOutlineMarkPoss
[nIns
] < nIdx
)
2203 m_aOutlineMarkPoss
.insert( m_aOutlineMarkPoss
.begin()+nIns
, nIdx
);
2204 OUString
aURL2(aURL
);
2207 aURL2
= aURL2
.replaceAt( nPos
- 1, 3, rtl::OUStringChar(cMarkSeparator
) );
2209 m_aOutlineMarks
.insert( m_aOutlineMarks
.begin()+nIns
, aURL2
);
2214 void SwHTMLWriter::CollectLinkTargets()
2216 const SwTextINetFormat
* pTextAttr
;
2218 for (const SfxPoolItem
* pItem
: m_pDoc
->GetAttrPool().GetItemSurrogates(RES_TXTATR_INETFMT
))
2220 auto pINetFormat
= dynamic_cast<const SwFormatINetFormat
*>(pItem
);
2221 const SwTextNode
* pTextNd
;
2224 nullptr != ( pTextAttr
= pINetFormat
->GetTextINetFormat()) &&
2225 nullptr != ( pTextNd
= pTextAttr
->GetpTextNode() ) &&
2226 pTextNd
->GetNodes().IsDocNodes() )
2228 AddLinkTarget( pINetFormat
->GetValue() );
2232 for (const SfxPoolItem
* pItem
: m_pDoc
->GetAttrPool().GetItemSurrogates(RES_URL
))
2234 auto pURL
= dynamic_cast<const SwFormatURL
*>(pItem
);
2237 AddLinkTarget( pURL
->GetURL() );
2238 const ImageMap
*pIMap
= pURL
->GetMap();
2241 for( size_t i
=0; i
<pIMap
->GetIMapObjectCount(); ++i
)
2243 const IMapObject
* pObj
= pIMap
->GetIMapObject( i
);
2246 AddLinkTarget( pObj
->GetURL() );
2254 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */