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 #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
46 #include <fmtanchr.hxx>
47 #include <fmtornt.hxx>
48 #include <fmturl.hxx>
49 #include <fmtfsize.hxx>
50 #include <fmtclds.hxx>
51 #include <fmtcntnt.hxx>
52 #include <fmtsrnd.hxx>
53 #include <fmtinfmt.hxx>
54 #include <txtinet.hxx>
55 #include <frmatr.hxx>
56 #include <grfatr.hxx>
57 #include <flypos.hxx>
58 #include <ndgrf.hxx>
59
60 #include <doc.hxx>
61 #include <ndtxt.hxx>
62 #include <pam.hxx>
63 #include <swerror.h>
64 #include <frmfmt.hxx>
65 #include "wrthtml.hxx"
66 #include "htmlatr.hxx"
67 #include "htmlfly.hxx"
68 #include "htmlreqifreader.hxx"
69
70 using namespace css;
71
72 const HtmlFrmOpts HTML_FRMOPTS_IMG_ALL =
73 HtmlFrmOpts::Alt |
74 HtmlFrmOpts::Size |
75 HtmlFrmOpts::AnySize |
76 HtmlFrmOpts::Border |
77 HtmlFrmOpts::Name;
78 const HtmlFrmOpts HTML_FRMOPTS_IMG_CNTNR =
79 HTML_FRMOPTS_IMG_ALL |
80 HtmlFrmOpts::AbsSize;
81 const HtmlFrmOpts HTML_FRMOPTS_IMG =
82 HTML_FRMOPTS_IMG_ALL |
83 HtmlFrmOpts::Align |
84 HtmlFrmOpts::Space |
85 HtmlFrmOpts::BrClear;
86 const HtmlFrmOpts HTML_FRMOPTS_IMG_CSS1 =
87 HtmlFrmOpts::SAlign |
88 HtmlFrmOpts::SSpace;
89
90 const HtmlFrmOpts HTML_FRMOPTS_DIV =
91 HtmlFrmOpts::Id |
92 HtmlFrmOpts::SAlign |
93 HtmlFrmOpts::SSize |
94 HtmlFrmOpts::AnySize |
95 HtmlFrmOpts::AbsSize |
96 HtmlFrmOpts::SSpace |
97 HtmlFrmOpts::SBorder |
98 HtmlFrmOpts::SBackground |
99 HtmlFrmOpts::BrClear |
100 HtmlFrmOpts::Dir;
101
102 const HtmlFrmOpts HTML_FRMOPTS_MULTICOL =
103 HtmlFrmOpts::Id |
104 HtmlFrmOpts::Width |
105 HtmlFrmOpts::AnySize |
106 HtmlFrmOpts::AbsSize |
107 HtmlFrmOpts::Dir;
108
109 const HtmlFrmOpts HTML_FRMOPTS_MULTICOL_CSS1 =
110 HtmlFrmOpts::SAlign |
111 HtmlFrmOpts::SSize |
112 HtmlFrmOpts::SSpace |
113 HtmlFrmOpts::SBorder|
114 HtmlFrmOpts::SBackground;
115
116 const HtmlFrmOpts HTML_FRMOPTS_SPACER =
117 HtmlFrmOpts::Align |
118 HtmlFrmOpts::Size |
119 HtmlFrmOpts::AnySize |
120 HtmlFrmOpts::BrClear |
121 HtmlFrmOpts::MarginSize |
122 HtmlFrmOpts::AbsSize;
123
124 const HtmlFrmOpts HTML_FRMOPTS_CNTNR =
125 HtmlFrmOpts::SAlign |
126 HtmlFrmOpts::SSpace |
127 HtmlFrmOpts::SWidth |
128 HtmlFrmOpts::AnySize |
129 HtmlFrmOpts::AbsSize |
130 HtmlFrmOpts::SPixSize;
131
132 static Writer& OutHTML_FrameFormatTableNode( Writer& rWrt, const SwFrameFormat& rFrameFormat );
133 static Writer& OutHTML_FrameFormatAsMulticol( Writer& rWrt, const SwFrameFormat& rFormat,
134 bool bInCntnr );
135 static Writer& OutHTML_FrameFormatAsSpacer( Writer& rWrt, const SwFrameFormat& rFormat );
136 static Writer& OutHTML_FrameFormatAsDivOrSpan( Writer& rWrt,
137 const SwFrameFormat& rFrameFormat, bool bSpan );
138 static Writer& OutHTML_FrameFormatAsImage( Writer& rWrt, const SwFrameFormat& rFormat, bool bPNGFallback );
139
140 static Writer& OutHTML_FrameFormatGrfNode( Writer& rWrt, const SwFrameFormat& rFormat,
141 bool bInCntnr, bool bPNGFallback );
142
143 static Writer& OutHTML_FrameFormatAsMarquee( Writer& rWrt, const SwFrameFormat& rFrameFormat,
144 const SdrObject& rSdrObj );
145
146 HTMLOutEvent const aImageEventTable[] =
147 {
148 { OOO_STRING_SVTOOLS_HTML_O_SDonload, OOO_STRING_SVTOOLS_HTML_O_onload, SvMacroItemId::OnImageLoadDone },
149 { OOO_STRING_SVTOOLS_HTML_O_SDonabort, OOO_STRING_SVTOOLS_HTML_O_onabort, SvMacroItemId::OnImageLoadCancel },
150 { OOO_STRING_SVTOOLS_HTML_O_SDonerror, OOO_STRING_SVTOOLS_HTML_O_onerror, SvMacroItemId::OnImageLoadError },
151 { nullptr, nullptr, SvMacroItemId::NONE }
152 };
153
154 HTMLOutEvent const aIMapEventTable[] =
155 {
156 { OOO_STRING_SVTOOLS_HTML_O_SDonmouseover, OOO_STRING_SVTOOLS_HTML_O_onmouseover, SvMacroItemId::OnMouseOver },
157 { OOO_STRING_SVTOOLS_HTML_O_SDonmouseout, OOO_STRING_SVTOOLS_HTML_O_onmouseout, SvMacroItemId::OnMouseOut },
158 { nullptr, nullptr, SvMacroItemId::NONE }
159 };
160
GuessFrameType(const SwFrameFormat & rFrameFormat,const SdrObject * & rpSdrObj)161 sal_uInt16 SwHTMLWriter::GuessFrameType( const SwFrameFormat& rFrameFormat,
162 const SdrObject*& rpSdrObj )
163 {
164 SwHTMLFrameType eType;
165
166 if( RES_DRAWFRMFMT == rFrameFormat.Which() )
167 {
168 // use an arbitrary draw object as the default value
169 eType = HTML_FRMTYPE_DRAW;
170
171 const SdrObject *pObj =
172 SwHTMLWriter::GetMarqueeTextObj( static_cast<const SwDrawFrameFormat &>(rFrameFormat) );
173 if( pObj )
174 {
175 // scrolling text
176 rpSdrObj = pObj;
177 eType = HTML_FRMTYPE_MARQUEE;
178 }
179 else
180 {
181 pObj = GetHTMLControl( static_cast<const SwDrawFrameFormat &>(rFrameFormat) );
182
183 if( pObj )
184 {
185 // Form control
186 rpSdrObj = pObj;
187 eType = HTML_FRMTYPE_CONTROL;
188 }
189 }
190 }
191 else
192 {
193 // use a text frame as the default value
194 eType = HTML_FRMTYPE_TEXT;
195
196 const SwFormatContent& rFlyContent = rFrameFormat.GetContent();
197 sal_uLong nStt = rFlyContent.GetContentIdx()->GetIndex()+1;
198 const SwNode* pNd = m_pDoc->GetNodes()[ nStt ];
199
200 if( pNd->IsGrfNode() )
201 {
202 // graphic node
203 eType = HTML_FRMTYPE_GRF;
204 }
205 else if( pNd->IsOLENode() )
206 {
207 // applet, plugin, floating frame
208 eType = static_cast<SwHTMLFrameType>(GuessOLENodeFrameType( *pNd ));
209 }
210 else
211 {
212 sal_uLong nEnd = m_pDoc->GetNodes()[nStt-1]->EndOfSectionIndex();
213
214 const SfxPoolItem* pItem;
215 const SfxItemSet& rItemSet = rFrameFormat.GetAttrSet();
216 if( SfxItemState::SET == rItemSet.GetItemState( RES_COL,
217 true, &pItem ) &&
218 static_cast<const SwFormatCol *>(pItem)->GetNumCols() > 1 )
219 {
220 // frame with columns
221 eType = HTML_FRMTYPE_MULTICOL;
222 }
223 else if( pNd->IsTableNode() )
224 {
225 const SwTableNode *pTableNd = pNd->GetTableNode();
226 sal_uLong nTableEnd = pTableNd->EndOfSectionIndex();
227
228 if( nTableEnd+1 == nEnd )
229 {
230 // table
231 eType = HTML_FRMTYPE_TABLE;
232 }
233 else if( nTableEnd+2 == nEnd )
234 {
235 // table with caption
236 eType = HTML_FRMTYPE_TABLE_CAP;
237 }
238 }
239 else if( pNd->IsTextNode() )
240 {
241 const SwTextNode *pTextNd = pNd->GetTextNode();
242
243 bool bEmpty = false;
244 if( nStt==nEnd-1 && !pTextNd->Len() )
245 {
246 // empty frame? Only if no frame is
247 // anchored to the text or start node.
248 bEmpty = true;
249 if( m_pHTMLPosFlyFrames )
250 {
251 for( auto & pHTMLPosFlyFrame : *m_pHTMLPosFlyFrames )
252 {
253 sal_uLong nIdx = pHTMLPosFlyFrame->GetNdIndex().GetIndex();
254 bEmpty = (nIdx != nStt) && (nIdx != nStt-1);
255 if( !bEmpty || nIdx > nStt )
256 break;
257 }
258 }
259 }
260 if( bEmpty )
261 {
262 std::unique_ptr<SvxBrushItem> aBrush = rFrameFormat.makeBackgroundBrushItem();
263 /// background is not empty, if it has a background graphic
264 /// or its background color is not "no fill"/"auto fill".
265 if( aBrush &&
266 (GPOS_NONE != aBrush->GetGraphicPos() ||
267 aBrush->GetColor() != COL_TRANSPARENT ))
268 {
269 bEmpty = false;
270 }
271 }
272 if( bEmpty )
273 {
274 // empty frame
275 eType = HTML_FRMTYPE_EMPTY;
276 }
277 else if( m_pDoc->GetNodes()[nStt+1]->IsTableNode() )
278 {
279 const SwTableNode *pTableNd =
280 m_pDoc->GetNodes()[nStt+1]->GetTableNode();
281 if( pTableNd->EndOfSectionIndex()+1 == nEnd )
282 {
283 // table with heading
284 eType = HTML_FRMTYPE_TABLE_CAP;
285 }
286 }
287 }
288 }
289 }
290
291 return static_cast< sal_uInt16 >(eType);
292 }
293
CollectFlyFrames()294 void SwHTMLWriter::CollectFlyFrames()
295 {
296 OSL_ENSURE( HTML_CFG_MAX+1 == MAX_BROWSERS,
297 "number of browser configurations has changed" );
298
299 SwPosFlyFrames aFlyPos(
300 m_pDoc->GetAllFlyFormats(m_bWriteAll ? nullptr : m_pCurrentPam.get(), true));
301
302 for(const auto& rpItem : aFlyPos)
303 {
304 const SwFrameFormat& rFrameFormat = rpItem->GetFormat();
305 const SdrObject *pSdrObj = nullptr;
306 const SwPosition *pAPos;
307 const SwContentNode *pACNd;
308 SwHTMLFrameType eType = static_cast<SwHTMLFrameType>(GuessFrameType( rFrameFormat, pSdrObj ));
309
310 AllHtmlFlags nMode;
311 const SwFormatAnchor& rAnchor = rFrameFormat.GetAnchor();
312 sal_Int16 eHoriRel = rFrameFormat.GetHoriOrient().GetRelationOrient();
313 switch( rAnchor.GetAnchorId() )
314 {
315 case RndStdIds::FLY_AT_PAGE:
316 case RndStdIds::FLY_AT_FLY:
317 nMode = aHTMLOutFramePageFlyTable[eType][m_nExportMode];
318 break;
319
320 case RndStdIds::FLY_AT_PARA:
321 // frames that are anchored to a paragraph are only placed
322 // before the paragraph, if the paragraph has a
323 // spacing.
324 if( text::RelOrientation::FRAME == eHoriRel &&
325 (pAPos = rAnchor.GetContentAnchor()) != nullptr &&
326 (pACNd = pAPos->nNode.GetNode().GetContentNode()) != nullptr )
327 {
328 const SvxLRSpaceItem& rLRItem =
329 static_cast<const SvxLRSpaceItem&>(pACNd->GetAttr(RES_LR_SPACE));
330 if( rLRItem.GetTextLeft() || rLRItem.GetRight() )
331 {
332 nMode = aHTMLOutFrameParaFrameTable[eType][m_nExportMode];
333 break;
334 }
335 }
336 nMode = aHTMLOutFrameParaPrtAreaTable[eType][m_nExportMode];
337 break;
338
339 case RndStdIds::FLY_AT_CHAR:
340 if( text::RelOrientation::FRAME == eHoriRel || text::RelOrientation::PRINT_AREA == eHoriRel )
341 nMode = aHTMLOutFrameParaPrtAreaTable[eType][m_nExportMode];
342 else
343 nMode = aHTMLOutFrameParaOtherTable[eType][m_nExportMode];
344 break;
345
346 default:
347 nMode = aHTMLOutFrameParaPrtAreaTable[eType][m_nExportMode];
348 break;
349 }
350
351 if( !m_pHTMLPosFlyFrames )
352 m_pHTMLPosFlyFrames.reset(new SwHTMLPosFlyFrames);
353
354 m_pHTMLPosFlyFrames->insert( std::make_unique<SwHTMLPosFlyFrame>(*rpItem, pSdrObj, nMode) );
355 }
356 }
357
OutFlyFrame(sal_uLong nNdIdx,sal_Int32 nContentIdx,HtmlPosition nPos,HTMLOutContext * pContext)358 bool SwHTMLWriter::OutFlyFrame( sal_uLong nNdIdx, sal_Int32 nContentIdx, HtmlPosition nPos,
359 HTMLOutContext *pContext )
360 {
361 bool bFlysLeft = false; // Are there still Flys left at the current node position?
362
363 // OutFlyFrame can be called recursively. Thus, sometimes it is
364 // necessary to start over after a Fly was returned.
365 bool bRestart = true;
366 while( m_pHTMLPosFlyFrames && bRestart )
367 {
368 bFlysLeft = bRestart = false;
369
370 // search for the beginning of the FlyFrames
371 size_t i {0};
372
373 for( ; i < m_pHTMLPosFlyFrames->size() &&
374 (*m_pHTMLPosFlyFrames)[i]->GetNdIndex().GetIndex() < nNdIdx; i++ )
375 ;
376 for( ; !bRestart && i < m_pHTMLPosFlyFrames->size() &&
377 (*m_pHTMLPosFlyFrames)[i]->GetNdIndex().GetIndex() == nNdIdx; i++ )
378 {
379 SwHTMLPosFlyFrame *pPosFly = (*m_pHTMLPosFlyFrames)[i].get();
380 if( ( HtmlPosition::Any == nPos ||
381 pPosFly->GetOutPos() == nPos ) &&
382 pPosFly->GetContentIndex() == nContentIdx )
383 {
384 // It is important to remove it first, because additional
385 // elements or the whole array could be deleted on
386 // deeper recursion levels.
387 std::unique_ptr<SwHTMLPosFlyFrame> flyHolder = m_pHTMLPosFlyFrames->erase_extract(i);
388 i--;
389 if( m_pHTMLPosFlyFrames->empty() )
390 {
391 m_pHTMLPosFlyFrames.reset();
392 bRestart = true; // not really, only exit the loop
393 }
394
395 if( pContext )
396 {
397 HTMLOutFuncs::FlushToAscii(Strm(), *pContext );
398 pContext = nullptr; // one time only
399 }
400
401 OutFrameFormat( pPosFly->GetOutMode(), pPosFly->GetFormat(),
402 pPosFly->GetSdrObject() );
403 switch( pPosFly->GetOutFn() )
404 {
405 case HtmlOut::Div:
406 case HtmlOut::Span:
407 case HtmlOut::MultiCol:
408 case HtmlOut::TableNode:
409 bRestart = true; // It could become recursive here
410 break;
411 default: break;
412 }
413 }
414 else
415 {
416 bFlysLeft = true;
417 }
418 }
419 }
420
421 return bFlysLeft;
422 }
423
OutFrameFormat(AllHtmlFlags nMode,const SwFrameFormat & rFrameFormat,const SdrObject * pSdrObject)424 void SwHTMLWriter::OutFrameFormat( AllHtmlFlags nMode, const SwFrameFormat& rFrameFormat,
425 const SdrObject *pSdrObject )
426 {
427 HtmlContainerFlags nCntnrMode = nMode.nContainer;
428 HtmlOut nOutMode = nMode.nOut;
429 OString aContainerStr;
430 if( HtmlContainerFlags::NONE != nCntnrMode )
431 {
432
433 if( m_bLFPossible && HtmlContainerFlags::Div == nCntnrMode )
434 OutNewLine();
435
436 OStringBuffer sOut;
437 aContainerStr = (HtmlContainerFlags::Div == nCntnrMode)
438 ? OOO_STRING_SVTOOLS_HTML_division
439 : OOO_STRING_SVTOOLS_HTML_span;
440 sOut.append("<" + GetNamespace() + aContainerStr + " "
441 OOO_STRING_SVTOOLS_HTML_O_class "=\""
442 "sd-abs-pos\"");
443 Strm().WriteOString( sOut.makeStringAndClear() );
444
445 // Output a width for non-draw objects
446 HtmlFrmOpts nFrameFlags = HTML_FRMOPTS_CNTNR;
447
448 // For frames with columns we can also output the background
449 if( HtmlOut::MultiCol == nOutMode )
450 nFrameFlags |= HtmlFrmOpts::SBackground|HtmlFrmOpts::SBorder;
451
452 if( IsHTMLMode( HTMLMODE_BORDER_NONE ) )
453 nFrameFlags |= HtmlFrmOpts::SNoBorder;
454 OutCSS1_FrameFormatOptions( rFrameFormat, nFrameFlags, pSdrObject );
455 Strm().WriteChar( '>' );
456
457 if( HtmlContainerFlags::Div == nCntnrMode )
458 {
459 IncIndentLevel();
460 m_bLFPossible = true;
461 }
462 }
463
464 switch( nOutMode )
465 {
466 case HtmlOut::TableNode: // OK
467 OSL_ENSURE( aContainerStr.isEmpty(), "Table: Container is not supposed to be here" );
468 OutHTML_FrameFormatTableNode( *this, rFrameFormat );
469 break;
470 case HtmlOut::GraphicNode: // OK
471 OutHTML_FrameFormatGrfNode( *this, rFrameFormat, !aContainerStr.isEmpty(), /*bPNGFallback=*/true );
472 break;
473 case HtmlOut::OleNode: // OK
474 OutHTML_FrameFormatOLENode( *this, rFrameFormat, !aContainerStr.isEmpty() );
475 break;
476 case HtmlOut::OleGraphic: // OK
477 OutHTML_FrameFormatOLENodeGrf( *this, rFrameFormat, !aContainerStr.isEmpty() );
478 break;
479 case HtmlOut::Div:
480 case HtmlOut::Span:
481 OSL_ENSURE( aContainerStr.isEmpty(), "Div: Container is not supposed to be here" );
482 OutHTML_FrameFormatAsDivOrSpan( *this, rFrameFormat, HtmlOut::Span==nOutMode );
483 break;
484 case HtmlOut::MultiCol: // OK
485 OutHTML_FrameFormatAsMulticol( *this, rFrameFormat, !aContainerStr.isEmpty() );
486 break;
487 case HtmlOut::Spacer: // OK
488 OSL_ENSURE( aContainerStr.isEmpty(), "Spacer: Container is not supposed to be here" );
489 OutHTML_FrameFormatAsSpacer( *this, rFrameFormat );
490 break;
491 case HtmlOut::Control: // OK
492 OutHTML_DrawFrameFormatAsControl( *this,
493 static_cast<const SwDrawFrameFormat &>(rFrameFormat), dynamic_cast<const SdrUnoObj&>(*pSdrObject),
494 !aContainerStr.isEmpty() );
495 break;
496 case HtmlOut::AMarquee:
497 OutHTML_FrameFormatAsMarquee( *this, rFrameFormat, *pSdrObject );
498 break;
499 case HtmlOut::Marquee:
500 OSL_ENSURE( aContainerStr.isEmpty(), "Marquee: Container is not supposed to be here" );
501 OutHTML_DrawFrameFormatAsMarquee( *this,
502 static_cast<const SwDrawFrameFormat &>(rFrameFormat), *pSdrObject );
503 break;
504 case HtmlOut::GraphicFrame:
505 OutHTML_FrameFormatAsImage( *this, rFrameFormat, /*bPNGFallback=*/true );
506 break;
507 }
508
509 if( HtmlContainerFlags::Div == nCntnrMode )
510 {
511 DecIndentLevel();
512 if( m_bLFPossible )
513 OutNewLine();
514 HTMLOutFuncs::Out_AsciiTag( Strm(), OString(GetNamespace() + OOO_STRING_SVTOOLS_HTML_division), false );
515 m_bLFPossible = true;
516 }
517 else if( HtmlContainerFlags::Span == nCntnrMode )
518 HTMLOutFuncs::Out_AsciiTag( Strm(), OString(GetNamespace() + OOO_STRING_SVTOOLS_HTML_span), false );
519 }
520
OutFrameFormatOptions(const SwFrameFormat & rFrameFormat,const OUString & rAlternateText,HtmlFrmOpts nFrameOpts)521 OString SwHTMLWriter::OutFrameFormatOptions( const SwFrameFormat &rFrameFormat,
522 const OUString& rAlternateText,
523 HtmlFrmOpts nFrameOpts )
524 {
525 OString sRetEndTags;
526 OStringBuffer sOut;
527 const SfxPoolItem* pItem;
528 const SfxItemSet& rItemSet = rFrameFormat.GetAttrSet();
529
530 // Name
531 if( (nFrameOpts & (HtmlFrmOpts::Id|HtmlFrmOpts::Name)) &&
532 !rFrameFormat.GetName().isEmpty() )
533 {
534 const char *pStr =
535 (nFrameOpts & HtmlFrmOpts::Id) ? OOO_STRING_SVTOOLS_HTML_O_id : OOO_STRING_SVTOOLS_HTML_O_name;
536 sOut.append(OString::Concat(" ") + pStr + "=\"");
537 Strm().WriteOString( sOut.makeStringAndClear() );
538 HTMLOutFuncs::Out_String( Strm(), rFrameFormat.GetName(), m_eDestEnc, &m_aNonConvertableCharacters );
539 sOut.append('\"');
540 }
541
542 // Name
543 if( nFrameOpts & HtmlFrmOpts::Dir )
544 {
545 SvxFrameDirection nDir = GetHTMLDirection( rItemSet );
546 Strm().WriteOString( sOut.makeStringAndClear() );
547 OutDirection( nDir );
548 }
549
550 // ALT
551 if( (nFrameOpts & HtmlFrmOpts::Alt) && !rAlternateText.isEmpty() )
552 {
553 sOut.append(" " OOO_STRING_SVTOOLS_HTML_O_alt "=\"");
554 Strm().WriteOString( sOut.makeStringAndClear() );
555 HTMLOutFuncs::Out_String( Strm(), rAlternateText, m_eDestEnc, &m_aNonConvertableCharacters );
556 sOut.append('\"');
557 }
558
559 // ALIGN
560 const char *pStr = nullptr;
561 RndStdIds eAnchorId = rFrameFormat.GetAnchor().GetAnchorId();
562 if( (nFrameOpts & HtmlFrmOpts::Align) &&
563 ((RndStdIds::FLY_AT_PARA == eAnchorId) || (RndStdIds::FLY_AT_CHAR == eAnchorId)) )
564 {
565 // MIB 12.3.98: Wouldn't it be more clever to left-align frames that
566 // are anchored to a paragraph if necessary, instead of inserting them
567 // as being anchored to characters?
568 const SwFormatHoriOrient& rHoriOri = rFrameFormat.GetHoriOrient();
569 if( !(nFrameOpts & HtmlFrmOpts::SAlign) ||
570 text::RelOrientation::FRAME == rHoriOri.GetRelationOrient() ||
571 text::RelOrientation::PRINT_AREA == rHoriOri.GetRelationOrient() )
572 {
573 pStr = text::HoriOrientation::RIGHT == rHoriOri.GetHoriOrient()
574 ? OOO_STRING_SVTOOLS_HTML_AL_right
575 : OOO_STRING_SVTOOLS_HTML_AL_left;
576 }
577 }
578 if( (nFrameOpts & HtmlFrmOpts::Align) && !pStr &&
579 ( !(nFrameOpts & HtmlFrmOpts::SAlign) ||
580 (RndStdIds::FLY_AS_CHAR == eAnchorId) ) &&
581 SfxItemState::SET == rItemSet.GetItemState( RES_VERT_ORIENT, true, &pItem ))
582 {
583 switch( static_cast<const SwFormatVertOrient*>(pItem)->GetVertOrient() )
584 {
585 case text::VertOrientation::LINE_TOP: pStr = OOO_STRING_SVTOOLS_HTML_VA_top; break;
586 case text::VertOrientation::CHAR_TOP:
587 case text::VertOrientation::BOTTOM: pStr = OOO_STRING_SVTOOLS_HTML_VA_texttop; break; // not possible
588 case text::VertOrientation::LINE_CENTER:
589 case text::VertOrientation::CHAR_CENTER: pStr = OOO_STRING_SVTOOLS_HTML_VA_absmiddle; break; // not possible
590 case text::VertOrientation::CENTER: pStr = OOO_STRING_SVTOOLS_HTML_VA_middle; break;
591 case text::VertOrientation::LINE_BOTTOM:
592 case text::VertOrientation::CHAR_BOTTOM: pStr = OOO_STRING_SVTOOLS_HTML_VA_absbottom; break; // not possible
593 case text::VertOrientation::TOP: pStr = OOO_STRING_SVTOOLS_HTML_VA_bottom; break;
594 case text::VertOrientation::NONE: break;
595 }
596 }
597 if( pStr )
598 {
599 sOut.append(OString::Concat(" " OOO_STRING_SVTOOLS_HTML_O_align "=\"") +
600 pStr + "\"");
601 }
602
603 // HSPACE and VSPACE
604 Size aTwipSpc( 0, 0 );
605 if( (nFrameOpts & (HtmlFrmOpts::Space|HtmlFrmOpts::MarginSize)) &&
606 SfxItemState::SET == rItemSet.GetItemState( RES_LR_SPACE, true, &pItem ))
607 {
608 aTwipSpc.setWidth(
609 ( static_cast<const SvxLRSpaceItem*>(pItem)->GetLeft() +
610 static_cast<const SvxLRSpaceItem*>(pItem)->GetRight() ) / 2 );
611 m_nDfltLeftMargin = m_nDfltRightMargin = aTwipSpc.Width();
612 }
613 if( (nFrameOpts & (HtmlFrmOpts::Space|HtmlFrmOpts::MarginSize)) &&
614 SfxItemState::SET == rItemSet.GetItemState( RES_UL_SPACE, true, &pItem ))
615 {
616 aTwipSpc.setHeight(
617 ( static_cast<const SvxULSpaceItem*>(pItem)->GetUpper() +
618 static_cast<const SvxULSpaceItem*>(pItem)->GetLower() ) / 2 );
619 m_nDfltTopMargin = m_nDfltBottomMargin = o3tl::narrowing<sal_uInt16>(aTwipSpc.Height());
620 }
621
622 if( (nFrameOpts & HtmlFrmOpts::Space) &&
623 (aTwipSpc.Width() || aTwipSpc.Height()) &&
624 Application::GetDefaultDevice() )
625 {
626 Size aPixelSpc =
627 Application::GetDefaultDevice()->LogicToPixel( aTwipSpc,
628 MapMode(MapUnit::MapTwip) );
629 if( !aPixelSpc.Width() && aTwipSpc.Width() )
630 aPixelSpc.setWidth( 1 );
631 if( !aPixelSpc.Height() && aTwipSpc.Height() )
632 aPixelSpc.setHeight( 1 );
633
634 if( aPixelSpc.Width() )
635 {
636 sOut.append(" " OOO_STRING_SVTOOLS_HTML_O_hspace
637 "=\"" + OString::number(aPixelSpc.Width()) + "\"");
638 }
639
640 if( aPixelSpc.Height() )
641 {
642 sOut.append(" " OOO_STRING_SVTOOLS_HTML_O_vspace
643 "=\"" + OString::number(aPixelSpc.Height()) + "\"");
644 }
645 }
646
647 // The spacing must be considered for the size, if the corresponding flag
648 // is set.
649 if( nFrameOpts & HtmlFrmOpts::MarginSize )
650 {
651 aTwipSpc.setWidth( aTwipSpc.Width() * -2 );
652 aTwipSpc.setHeight( aTwipSpc.Height() * -2 );
653 }
654 else
655 {
656 aTwipSpc.setWidth( 0 );
657 aTwipSpc.setHeight( 0 );
658 }
659
660 if( !(nFrameOpts & HtmlFrmOpts::AbsSize) &&
661 SfxItemState::SET == rItemSet.GetItemState( RES_BOX, true, &pItem ))
662 {
663 const SvxBoxItem* pBoxItem = static_cast<const SvxBoxItem*>(pItem);
664
665 aTwipSpc.AdjustWidth(pBoxItem->CalcLineSpace( SvxBoxItemLine::LEFT ) );
666 aTwipSpc.AdjustWidth(pBoxItem->CalcLineSpace( SvxBoxItemLine::RIGHT ) );
667 aTwipSpc.AdjustHeight(pBoxItem->CalcLineSpace( SvxBoxItemLine::TOP ) );
668 aTwipSpc.AdjustHeight(pBoxItem->CalcLineSpace( SvxBoxItemLine::BOTTOM ) );
669 }
670
671 // WIDTH and/or HEIGHT
672 // Output SwFrameSize::Variable/SwFrameSize::Minimum only, if ANYSIZE is set
673 if( (nFrameOpts & HtmlFrmOpts::Size) &&
674 SfxItemState::SET == rItemSet.GetItemState( RES_FRM_SIZE, true, &pItem ) &&
675 ( (nFrameOpts & HtmlFrmOpts::AnySize) ||
676 SwFrameSize::Fixed == static_cast<const SwFormatFrameSize *>(pItem)->GetHeightSizeType()) )
677 {
678 const SwFormatFrameSize *pFSItem = static_cast<const SwFormatFrameSize *>(pItem);
679 sal_uInt8 nPercentWidth = pFSItem->GetWidthPercent();
680 sal_uInt8 nPercentHeight = pFSItem->GetHeightPercent();
681
682 // Size of the object in Twips without margins
683 Size aTwipSz( (nPercentWidth ? 0
684 : pFSItem->GetWidth()-aTwipSpc.Width()),
685 (nPercentHeight ? 0
686 : pFSItem->GetHeight()-aTwipSpc.Height()) );
687
688 OSL_ENSURE( !aTwipSz.IsEmpty(), "Frame size minus spacing < 0!!!???" );
689 if( aTwipSz.Width() < 0 )
690 aTwipSz.setWidth( 0 );
691 if( aTwipSz.Height() < 0 )
692 aTwipSz.setHeight( 0 );
693
694 Size aPixelSz( 0, 0 );
695 if( (aTwipSz.Width() || aTwipSz.Height()) &&
696 Application::GetDefaultDevice() )
697 {
698 aPixelSz =
699 Application::GetDefaultDevice()->LogicToPixel( aTwipSz,
700 MapMode(MapUnit::MapTwip) );
701 if( !aPixelSz.Width() && aTwipSz.Width() )
702 aPixelSz.setWidth( 1 );
703 if( !aPixelSz.Height() && aTwipSz.Height() )
704 aPixelSz.setHeight( 1 );
705 }
706
707 if( (nFrameOpts & HtmlFrmOpts::Width) &&
708 ((nPercentWidth && nPercentWidth!=255) || aPixelSz.Width()) )
709 {
710 sOut.append(" " OOO_STRING_SVTOOLS_HTML_O_width "=\"");
711 if( nPercentWidth )
712 sOut.append(static_cast<sal_Int32>(nPercentWidth)).append('%');
713 else
714 sOut.append(static_cast<sal_Int32>(aPixelSz.Width()));
715 sOut.append("\"");
716 }
717
718 if( (nFrameOpts & HtmlFrmOpts::Height) &&
719 ((nPercentHeight && nPercentHeight!=255) || aPixelSz.Height()) )
720 {
721 sOut.append(" " OOO_STRING_SVTOOLS_HTML_O_height "=\"");
722 if( nPercentHeight )
723 sOut.append(static_cast<sal_Int32>(nPercentHeight)).append('%');
724 else
725 sOut.append(static_cast<sal_Int32>(aPixelSz.Height()));
726 sOut.append("\"");
727 }
728 }
729
730 if (!sOut.isEmpty())
731 Strm().WriteOString( sOut.makeStringAndClear() );
732
733 // Insert wrap for graphics that are anchored to a paragraph as
734 // <BR CLEAR=...> in the string
735 if( (nFrameOpts & HtmlFrmOpts::BrClear) &&
736 ((RndStdIds::FLY_AT_PARA == rFrameFormat.GetAnchor().GetAnchorId()) ||
737 (RndStdIds::FLY_AT_CHAR == rFrameFormat.GetAnchor().GetAnchorId())) &&
738 SfxItemState::SET == rItemSet.GetItemState( RES_SURROUND, true, &pItem ))
739 {
740 const SwFormatSurround* pSurround = static_cast<const SwFormatSurround*>(pItem);
741 sal_Int16 eHoriOri = rFrameFormat.GetHoriOrient().GetHoriOrient();
742 pStr = nullptr;
743 css::text::WrapTextMode eSurround = pSurround->GetSurround();
744 bool bAnchorOnly = pSurround->IsAnchorOnly();
745 switch( eHoriOri )
746 {
747 case text::HoriOrientation::RIGHT:
748 {
749 switch( eSurround )
750 {
751 case css::text::WrapTextMode_NONE:
752 case css::text::WrapTextMode_RIGHT:
753 pStr = OOO_STRING_SVTOOLS_HTML_AL_right;
754 break;
755 case css::text::WrapTextMode_LEFT:
756 case css::text::WrapTextMode_PARALLEL:
757 if( bAnchorOnly )
758 m_bClearRight = true;
759 break;
760 default:
761 ;
762 }
763 }
764 break;
765
766 default:
767 // If a frame is centered, it gets left aligned. This
768 // should be taken into account here, too.
769 {
770 switch( eSurround )
771 {
772 case css::text::WrapTextMode_NONE:
773 case css::text::WrapTextMode_LEFT:
774 pStr = OOO_STRING_SVTOOLS_HTML_AL_left;
775 break;
776 case css::text::WrapTextMode_RIGHT:
777 case css::text::WrapTextMode_PARALLEL:
778 if( bAnchorOnly )
779 m_bClearLeft = true;
780 break;
781 default:
782 ;
783 }
784 }
785 break;
786
787 }
788
789 if( pStr )
790 {
791 sOut.append("<" OOO_STRING_SVTOOLS_HTML_linebreak
792 " " OOO_STRING_SVTOOLS_HTML_O_clear
793 "=\"" + OString::Concat(pStr) + "\">");
794 sRetEndTags = sOut.makeStringAndClear();
795 }
796 }
797 return sRetEndTags;
798 }
799
writeFrameFormatOptions(HtmlWriter & aHtml,const SwFrameFormat & rFrameFormat,std::u16string_view rAlternateText,HtmlFrmOpts nFrameOptions)800 void SwHTMLWriter::writeFrameFormatOptions(HtmlWriter& aHtml, const SwFrameFormat& rFrameFormat, std::u16string_view rAlternateText, HtmlFrmOpts nFrameOptions)
801 {
802 bool bReplacement = (nFrameOptions & HtmlFrmOpts::Replacement) || mbReqIF;
803 const SfxPoolItem* pItem;
804 const SfxItemSet& rItemSet = rFrameFormat.GetAttrSet();
805
806 // Name
807 if( (nFrameOptions & (HtmlFrmOpts::Id|HtmlFrmOpts::Name)) &&
808 !rFrameFormat.GetName().isEmpty() && !bReplacement)
809 {
810 const char* pAttributeName = (nFrameOptions & HtmlFrmOpts::Id) ? OOO_STRING_SVTOOLS_HTML_O_id : OOO_STRING_SVTOOLS_HTML_O_name;
811 aHtml.attribute(pAttributeName, rFrameFormat.GetName());
812 }
813
814 // Name
815 if (nFrameOptions & HtmlFrmOpts::Dir)
816 {
817 SvxFrameDirection nCurrentDirection = GetHTMLDirection(rItemSet);
818 OString sDirection = convertDirection(nCurrentDirection);
819 aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_dir, sDirection);
820 }
821
822 // alt
823 if( (nFrameOptions & HtmlFrmOpts::Alt) && !rAlternateText.empty() && !bReplacement )
824 {
825 aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_alt, rAlternateText);
826 }
827
828 // align
829 const char* pAlignString = nullptr;
830 RndStdIds eAnchorId = rFrameFormat.GetAnchor().GetAnchorId();
831 if( (nFrameOptions & HtmlFrmOpts::Align) &&
832 ((RndStdIds::FLY_AT_PARA == eAnchorId) || (RndStdIds::FLY_AT_CHAR == eAnchorId)) && !bReplacement)
833 {
834 const SwFormatHoriOrient& rHoriOri = rFrameFormat.GetHoriOrient();
835 if( !(nFrameOptions & HtmlFrmOpts::SAlign) ||
836 text::RelOrientation::FRAME == rHoriOri.GetRelationOrient() ||
837 text::RelOrientation::PRINT_AREA == rHoriOri.GetRelationOrient() )
838 {
839 pAlignString = text::HoriOrientation::RIGHT == rHoriOri.GetHoriOrient()
840 ? OOO_STRING_SVTOOLS_HTML_AL_right
841 : OOO_STRING_SVTOOLS_HTML_AL_left;
842 }
843 }
844 if( (nFrameOptions & HtmlFrmOpts::Align) && !pAlignString &&
845 ( !(nFrameOptions & HtmlFrmOpts::SAlign) ||
846 (RndStdIds::FLY_AS_CHAR == eAnchorId) ) &&
847 SfxItemState::SET == rItemSet.GetItemState( RES_VERT_ORIENT, true, &pItem ))
848 {
849 switch( static_cast<const SwFormatVertOrient*>(pItem)->GetVertOrient() )
850 {
851 case text::VertOrientation::LINE_TOP: pAlignString = OOO_STRING_SVTOOLS_HTML_VA_top; break;
852 case text::VertOrientation::CHAR_TOP:
853 case text::VertOrientation::BOTTOM: pAlignString = OOO_STRING_SVTOOLS_HTML_VA_texttop; break;
854 case text::VertOrientation::LINE_CENTER:
855 case text::VertOrientation::CHAR_CENTER: pAlignString = OOO_STRING_SVTOOLS_HTML_VA_absmiddle; break;
856 case text::VertOrientation::CENTER: pAlignString = OOO_STRING_SVTOOLS_HTML_VA_middle; break;
857 case text::VertOrientation::LINE_BOTTOM:
858 case text::VertOrientation::CHAR_BOTTOM: pAlignString = OOO_STRING_SVTOOLS_HTML_VA_absbottom; break;
859 case text::VertOrientation::TOP: pAlignString = OOO_STRING_SVTOOLS_HTML_VA_bottom; break;
860 case text::VertOrientation::NONE: break;
861 }
862 }
863 if (pAlignString && !bReplacement)
864 {
865 aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_align, pAlignString);
866 }
867
868 // hspace and vspace
869 Size aTwipSpc( 0, 0 );
870 if( (nFrameOptions & (HtmlFrmOpts::Space | HtmlFrmOpts::MarginSize)) &&
871 SfxItemState::SET == rItemSet.GetItemState( RES_LR_SPACE, true, &pItem ))
872 {
873 aTwipSpc.setWidth(
874 ( static_cast<const SvxLRSpaceItem*>(pItem)->GetLeft() +
875 static_cast<const SvxLRSpaceItem*>(pItem)->GetRight() ) / 2 );
876 m_nDfltLeftMargin = m_nDfltRightMargin = aTwipSpc.Width();
877 }
878 if( (nFrameOptions & (HtmlFrmOpts::Space|HtmlFrmOpts::MarginSize)) &&
879 SfxItemState::SET == rItemSet.GetItemState( RES_UL_SPACE, true, &pItem ))
880 {
881 aTwipSpc.setHeight(
882 ( static_cast<const SvxULSpaceItem*>(pItem)->GetUpper() +
883 static_cast<const SvxULSpaceItem*>(pItem)->GetLower() ) / 2 );
884 m_nDfltTopMargin = m_nDfltBottomMargin = o3tl::narrowing<sal_uInt16>(aTwipSpc.Height());
885 }
886
887 if( (nFrameOptions & HtmlFrmOpts::Space) &&
888 (aTwipSpc.Width() || aTwipSpc.Height()) &&
889 Application::GetDefaultDevice() )
890 {
891 Size aPixelSpc =
892 Application::GetDefaultDevice()->LogicToPixel( aTwipSpc,
893 MapMode(MapUnit::MapTwip) );
894 if( !aPixelSpc.Width() && aTwipSpc.Width() )
895 aPixelSpc.setWidth( 1 );
896 if( !aPixelSpc.Height() && aTwipSpc.Height() )
897 aPixelSpc.setHeight( 1 );
898
899 if (aPixelSpc.Width())
900 {
901 aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_hspace, static_cast<sal_Int32>(aPixelSpc.Width()));
902 }
903
904 if (aPixelSpc.Height())
905 {
906 aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_vspace, static_cast<sal_Int32>(aPixelSpc.Height()));
907 }
908 }
909
910 // The spacing must be considered for the size, if the corresponding flag
911 // is set.
912 if( nFrameOptions & HtmlFrmOpts::MarginSize )
913 {
914 aTwipSpc.setWidth( aTwipSpc.Width() * -2 );
915 aTwipSpc.setHeight( aTwipSpc.Height() * -2 );
916 }
917 else
918 {
919 aTwipSpc.setWidth( 0 );
920 aTwipSpc.setHeight( 0 );
921 }
922
923 if( !(nFrameOptions & HtmlFrmOpts::AbsSize) &&
924 SfxItemState::SET == rItemSet.GetItemState( RES_BOX, true, &pItem ))
925 {
926 const SvxBoxItem* pBoxItem = static_cast<const SvxBoxItem*>(pItem);
927
928 aTwipSpc.AdjustWidth(pBoxItem->CalcLineSpace( SvxBoxItemLine::LEFT ) );
929 aTwipSpc.AdjustWidth(pBoxItem->CalcLineSpace( SvxBoxItemLine::RIGHT ) );
930 aTwipSpc.AdjustHeight(pBoxItem->CalcLineSpace( SvxBoxItemLine::TOP ) );
931 aTwipSpc.AdjustHeight(pBoxItem->CalcLineSpace( SvxBoxItemLine::BOTTOM ) );
932 }
933
934 // "width" and/or "height"
935 // Only output SwFrameSize::Variable/SwFrameSize::Minimum if ANYSIZE is set
936 const SwFormatFrameSize* pFSItem = nullptr;
937 std::optional<SwFormatFrameSize> aFrameSize;
938 if (SfxItemState::SET == rItemSet.GetItemState( RES_FRM_SIZE, true, &pItem ))
939 {
940 pFSItem = static_cast<const SwFormatFrameSize *>(pItem);
941 }
942 else if (const SdrObject* pObject = rFrameFormat.FindSdrObject())
943 {
944 // Write size for Draw shapes as well.
945 const tools::Rectangle& rSnapRect = pObject->GetSnapRect();
946 aFrameSize.emplace();
947 aFrameSize->SetWidthSizeType(SwFrameSize::Fixed);
948 aFrameSize->SetWidth(rSnapRect.getWidth());
949 aFrameSize->SetHeightSizeType(SwFrameSize::Fixed);
950 aFrameSize->SetHeight(rSnapRect.getHeight());
951 pFSItem = &*aFrameSize;
952 }
953 if( (nFrameOptions & HtmlFrmOpts::Size) &&
954 pFSItem &&
955 ( (nFrameOptions & HtmlFrmOpts::AnySize) ||
956 SwFrameSize::Fixed == pFSItem->GetHeightSizeType()) )
957 {
958 sal_uInt8 nPercentWidth = pFSItem->GetWidthPercent();
959 sal_uInt8 nPercentHeight = pFSItem->GetHeightPercent();
960
961 // Size of the object in Twips without margins
962 Size aTwipSz( (nPercentWidth ? 0
963 : pFSItem->GetWidth()-aTwipSpc.Width()),
964 (nPercentHeight ? 0
965 : pFSItem->GetHeight()-aTwipSpc.Height()) );
966
967 OSL_ENSURE( !aTwipSz.IsEmpty(), "Frame size minus spacing < 0!!!???" );
968 if( aTwipSz.Width() < 0 )
969 aTwipSz.setWidth( 0 );
970 if( aTwipSz.Height() < 0 )
971 aTwipSz.setHeight( 0 );
972
973 Size aPixelSz( 0, 0 );
974 if( (aTwipSz.Width() || aTwipSz.Height()) &&
975 Application::GetDefaultDevice() )
976 {
977 aPixelSz =
978 Application::GetDefaultDevice()->LogicToPixel( aTwipSz,
979 MapMode(MapUnit::MapTwip) );
980 if( !aPixelSz.Width() && aTwipSz.Width() )
981 aPixelSz.setWidth( 1 );
982 if( !aPixelSz.Height() && aTwipSz.Height() )
983 aPixelSz.setHeight( 1 );
984 }
985
986 if( (nFrameOptions & HtmlFrmOpts::Width) &&
987 ((nPercentWidth && nPercentWidth!=255) || aPixelSz.Width()) )
988 {
989 OString sWidth;
990 if (nPercentWidth)
991 sWidth = OString::number(static_cast<sal_Int32>(nPercentWidth)) + "%";
992 else
993 sWidth = OString::number(static_cast<sal_Int32>(aPixelSz.Width()));
994 aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_width, sWidth);
995 }
996
997 if( (nFrameOptions & HtmlFrmOpts::Height) &&
998 ((nPercentHeight && nPercentHeight!=255) || aPixelSz.Height()) )
999 {
1000 OString sHeight;
1001 if (nPercentHeight)
1002 sHeight = OString::number(static_cast<sal_Int32>(nPercentHeight)) + "%";
1003 else
1004 sHeight = OString::number(static_cast<sal_Int32>(aPixelSz.Height()));
1005 aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_height, sHeight);
1006 }
1007 }
1008
1009 // Insert wrap for graphics that are anchored to a paragraph as
1010 // <BR CLEAR=...> in the string
1011
1012 if( !((nFrameOptions & HtmlFrmOpts::BrClear) &&
1013 ((RndStdIds::FLY_AT_PARA == rFrameFormat.GetAnchor().GetAnchorId()) ||
1014 (RndStdIds::FLY_AT_CHAR == rFrameFormat.GetAnchor().GetAnchorId())) &&
1015 SfxItemState::SET == rItemSet.GetItemState( RES_SURROUND, true, &pItem )))
1016 return;
1017
1018 const char* pSurroundString = nullptr;
1019
1020 const SwFormatSurround* pSurround = static_cast<const SwFormatSurround*>(pItem);
1021 sal_Int16 eHoriOri = rFrameFormat.GetHoriOrient().GetHoriOrient();
1022 css::text::WrapTextMode eSurround = pSurround->GetSurround();
1023 bool bAnchorOnly = pSurround->IsAnchorOnly();
1024 switch( eHoriOri )
1025 {
1026 case text::HoriOrientation::RIGHT:
1027 {
1028 switch( eSurround )
1029 {
1030 case css::text::WrapTextMode_NONE:
1031 case css::text::WrapTextMode_RIGHT:
1032 pSurroundString = OOO_STRING_SVTOOLS_HTML_AL_right;
1033 break;
1034 case css::text::WrapTextMode_LEFT:
1035 case css::text::WrapTextMode_PARALLEL:
1036 if( bAnchorOnly )
1037 m_bClearRight = true;
1038 break;
1039 default:
1040 ;
1041 }
1042 }
1043 break;
1044
1045 default:
1046 // If a frame is centered, it gets left aligned. This
1047 // should be taken into account here, too.
1048 {
1049 switch( eSurround )
1050 {
1051 case css::text::WrapTextMode_NONE:
1052 case css::text::WrapTextMode_LEFT:
1053 pSurroundString = OOO_STRING_SVTOOLS_HTML_AL_left;
1054 break;
1055 case css::text::WrapTextMode_RIGHT:
1056 case css::text::WrapTextMode_PARALLEL:
1057 if( bAnchorOnly )
1058 m_bClearLeft = true;
1059 break;
1060 default:
1061 break;
1062 }
1063 }
1064 break;
1065 }
1066
1067 if (pSurroundString)
1068 {
1069 aHtml.start(OOO_STRING_SVTOOLS_HTML_linebreak);
1070 aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_clear, pSurroundString);
1071 aHtml.end();
1072 }
1073 }
1074
1075 namespace
1076 {
1077
lclWriteOutImap(SwHTMLWriter & rHTMLWrt,const SfxItemSet & rItemSet,const SwFrameFormat & rFrameFormat,const Size & rRealSize,const ImageMap * pAltImgMap,const SwFormatURL * & pURLItem)1078 OUString lclWriteOutImap(SwHTMLWriter& rHTMLWrt, const SfxItemSet& rItemSet, const SwFrameFormat& rFrameFormat,
1079 const Size& rRealSize, const ImageMap* pAltImgMap, const SwFormatURL*& pURLItem)
1080 {
1081 OUString aIMapName;
1082
1083 const SfxPoolItem* pItem;
1084
1085 // Only consider the URL attribute if no ImageMap was supplied
1086 if (!pAltImgMap && SfxItemState::SET == rItemSet.GetItemState( RES_URL, true, &pItem))
1087 {
1088 pURLItem = static_cast<const SwFormatURL*>( pItem);
1089 }
1090
1091 // write ImageMap
1092 const ImageMap* pIMap = pAltImgMap;
1093 if( !pIMap && pURLItem )
1094 {
1095 pIMap = pURLItem->GetMap();
1096 }
1097
1098 if (pIMap)
1099 {
1100 // make the name unique
1101 aIMapName = pIMap->GetName();
1102 OUString aNameBase;
1103 if (!aIMapName.isEmpty())
1104 aNameBase = aIMapName;
1105 else
1106 aNameBase = OOO_STRING_SVTOOLS_HTML_map;
1107
1108 if (aIMapName.isEmpty())
1109 aIMapName = aNameBase + OUString::number(rHTMLWrt.m_nImgMapCnt);
1110
1111 bool bFound;
1112 do
1113 {
1114 bFound = false;
1115 for (const OUString & rImgMapName : rHTMLWrt.m_aImgMapNames)
1116 {
1117 // TODO: Unicode: Comparison is case insensitive for ASCII
1118 // characters only now!
1119 if (aIMapName.equalsIgnoreAsciiCase(rImgMapName))
1120 {
1121 bFound = true;
1122 break;
1123 }
1124 }
1125 if (bFound)
1126 {
1127 rHTMLWrt.m_nImgMapCnt++;
1128 aIMapName = aNameBase + OUString::number( rHTMLWrt.m_nImgMapCnt );
1129 }
1130 } while (bFound);
1131
1132 bool bScale = false;
1133 Fraction aScaleX(1, 1);
1134 Fraction aScaleY(1, 1);
1135
1136 const SwFormatFrameSize& rFrameSize = rFrameFormat.GetFrameSize();
1137 const SvxBoxItem& rBox = rFrameFormat.GetBox();
1138
1139 if (!rFrameSize.GetWidthPercent() && rRealSize.Width())
1140 {
1141 SwTwips nWidth = rFrameSize.GetWidth();
1142 nWidth -= rBox.CalcLineSpace(SvxBoxItemLine::LEFT) + rBox.CalcLineSpace(SvxBoxItemLine::RIGHT);
1143
1144 OSL_ENSURE( nWidth > 0, "Are there any graphics that are 0 twip wide!?" );
1145 if (nWidth <= 0) // should not happen
1146 nWidth = 1;
1147
1148 if (rRealSize.Width() != nWidth)
1149 {
1150 aScaleX = Fraction(nWidth, rRealSize.Width());
1151 bScale = true;
1152 }
1153 }
1154
1155 if (!rFrameSize.GetHeightPercent() && rRealSize.Height())
1156 {
1157 SwTwips nHeight = rFrameSize.GetHeight();
1158
1159 nHeight -= rBox.CalcLineSpace(SvxBoxItemLine::TOP) + rBox.CalcLineSpace(SvxBoxItemLine::BOTTOM);
1160
1161 OSL_ENSURE( nHeight > 0, "Are there any graphics that are 0 twip high!?" );
1162 if (nHeight <= 0)
1163 nHeight = 1;
1164
1165 if (rRealSize.Height() != nHeight)
1166 {
1167 aScaleY = Fraction(nHeight, rRealSize.Height());
1168 bScale = true;
1169 }
1170 }
1171
1172 rHTMLWrt.m_aImgMapNames.push_back(aIMapName);
1173
1174 OString aIndMap, aIndArea;
1175 const char *pIndArea = nullptr, *pIndMap = nullptr;
1176
1177 if (rHTMLWrt.m_bLFPossible)
1178 {
1179 rHTMLWrt.OutNewLine( true );
1180 aIndMap = rHTMLWrt.GetIndentString();
1181 aIndArea = rHTMLWrt.GetIndentString(1);
1182 pIndArea = aIndArea.getStr();
1183 pIndMap = aIndMap.getStr();
1184 }
1185
1186 if (bScale)
1187 {
1188 ImageMap aScaledIMap(*pIMap);
1189 aScaledIMap.Scale(aScaleX, aScaleY);
1190 HTMLOutFuncs::Out_ImageMap( rHTMLWrt.Strm(), rHTMLWrt.GetBaseURL(), aScaledIMap, aIMapName,
1191 aIMapEventTable,
1192 rHTMLWrt.m_bCfgStarBasic,
1193 SAL_NEWLINE_STRING, pIndArea, pIndMap,
1194 rHTMLWrt.m_eDestEnc,
1195 &rHTMLWrt.m_aNonConvertableCharacters );
1196 }
1197 else
1198 {
1199 HTMLOutFuncs::Out_ImageMap( rHTMLWrt.Strm(), rHTMLWrt.GetBaseURL(), *pIMap, aIMapName,
1200 aIMapEventTable,
1201 rHTMLWrt.m_bCfgStarBasic,
1202 SAL_NEWLINE_STRING, pIndArea, pIndMap,
1203 rHTMLWrt.m_eDestEnc,
1204 &rHTMLWrt.m_aNonConvertableCharacters );
1205 }
1206 }
1207 return aIMapName;
1208 }
1209
1210 }
1211
OutHTML_ImageStart(HtmlWriter & rHtml,Writer & rWrt,const SwFrameFormat & rFrameFormat,const OUString & rGraphicURL,Graphic const & rGraphic,const OUString & rAlternateText,const Size & rRealSize,HtmlFrmOpts nFrameOpts,const char * pMarkType,const ImageMap * pAltImgMap,const OUString & rMimeType)1212 Writer& OutHTML_ImageStart( HtmlWriter& rHtml, Writer& rWrt, const SwFrameFormat &rFrameFormat,
1213 const OUString& rGraphicURL,
1214 Graphic const & rGraphic, const OUString& rAlternateText,
1215 const Size &rRealSize, HtmlFrmOpts nFrameOpts,
1216 const char *pMarkType,
1217 const ImageMap *pAltImgMap,
1218 const OUString& rMimeType )
1219 {
1220 SwHTMLWriter& rHTMLWrt = static_cast<SwHTMLWriter&>(rWrt);
1221 // <object data="..."> instead of <img src="...">
1222 bool bReplacement = (nFrameOpts & HtmlFrmOpts::Replacement) || rHTMLWrt.mbReqIF;
1223
1224 if (rHTMLWrt.mbSkipImages)
1225 return rHTMLWrt;
1226
1227 // if necessary, temporarily close an open attribute
1228 if( !rHTMLWrt.m_aINetFormats.empty() )
1229 {
1230 SwFormatINetFormat* pINetFormat = rHTMLWrt.m_aINetFormats.back();
1231 OutHTML_INetFormat( rWrt, *pINetFormat, false );
1232 }
1233
1234 OUString aGraphicURL( rGraphicURL );
1235 if( !rHTMLWrt.mbEmbedImages && !HTMLOutFuncs::PrivateURLToInternalImg(aGraphicURL) && !rHTMLWrt.mpTempBaseURL )
1236 aGraphicURL = URIHelper::simpleNormalizedMakeRelative( rWrt.GetBaseURL(), aGraphicURL);
1237
1238 const SfxPoolItem* pItem;
1239 const SfxItemSet& rItemSet = rFrameFormat.GetAttrSet();
1240
1241 const SwFormatURL* pURLItem = nullptr;
1242 OUString aIMapName = lclWriteOutImap(rHTMLWrt, rItemSet, rFrameFormat, rRealSize, pAltImgMap, pURLItem);
1243
1244 // put img into new line
1245 if( rHTMLWrt.m_bLFPossible )
1246 rHTMLWrt.OutNewLine( true );
1247
1248 // <a name=...></a>...<img ...>
1249 if( pMarkType && !rFrameFormat.GetName().isEmpty() )
1250 {
1251 rHTMLWrt.OutImplicitMark( rFrameFormat.GetName(), pMarkType );
1252 }
1253
1254 // URL -> <a>...<img ... >...</a>
1255 const SvxMacroItem *pMacItem = nullptr;
1256 if (SfxItemState::SET == rItemSet.GetItemState(RES_FRMMACRO, true, &pItem))
1257 {
1258 pMacItem = static_cast<const SvxMacroItem *>(pItem);
1259 }
1260
1261 if (pURLItem || pMacItem)
1262 {
1263 OUString aMapURL;
1264 OUString aName;
1265 OUString aTarget;
1266
1267 if(pURLItem)
1268 {
1269 aMapURL = pURLItem->GetURL();
1270 aName = pURLItem->GetName();
1271 aTarget = pURLItem->GetTargetFrameName();
1272 }
1273
1274 bool bEvents = pMacItem && !pMacItem->GetMacroTable().empty();
1275
1276 if( !aMapURL.isEmpty() || !aName.isEmpty() || !aTarget.isEmpty() || bEvents )
1277 {
1278 rHtml.start(OOO_STRING_SVTOOLS_HTML_anchor);
1279
1280 // Output "href" element if a link or macro exists
1281 if( !aMapURL.isEmpty() || bEvents )
1282 {
1283 rHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_href, OUStringToOString(rHTMLWrt.convertHyperlinkHRefValue(aMapURL), RTL_TEXTENCODING_UTF8));
1284 }
1285
1286 if( !aName.isEmpty() )
1287 {
1288 rHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_name, OUStringToOString(aName, RTL_TEXTENCODING_UTF8));
1289 }
1290
1291 if( !aTarget.isEmpty() )
1292 {
1293 rHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_target, OUStringToOString(aTarget, RTL_TEXTENCODING_UTF8));
1294 }
1295
1296 if( pMacItem )
1297 {
1298 const SvxMacroTableDtor& rMacTable = pMacItem->GetMacroTable();
1299 if (!rMacTable.empty())
1300 {
1301 HtmlWriterHelper::applyEvents(rHtml, rMacTable, aAnchorEventTable, rHTMLWrt.m_bCfgStarBasic);
1302 }
1303 }
1304 }
1305 }
1306
1307 // <font color = ...>...<img ... >...</font>
1308 sal_uInt16 nBorderWidth = 0;
1309 if( (nFrameOpts & HtmlFrmOpts::Border) &&
1310 SfxItemState::SET == rItemSet.GetItemState( RES_BOX, true, &pItem ))
1311 {
1312 Size aTwipBorder( 0, 0 );
1313 const SvxBoxItem* pBoxItem = static_cast<const SvxBoxItem*>(pItem);
1314
1315 const ::editeng::SvxBorderLine *pColBorderLine = nullptr;
1316 const ::editeng::SvxBorderLine *pBorderLine = pBoxItem->GetLeft();
1317 if( pBorderLine )
1318 {
1319 pColBorderLine = pBorderLine;
1320 aTwipBorder.AdjustWidth(pBorderLine->GetOutWidth() );
1321 }
1322
1323 pBorderLine = pBoxItem->GetRight();
1324 if( pBorderLine )
1325 {
1326 pColBorderLine = pBorderLine;
1327 aTwipBorder.AdjustWidth(pBorderLine->GetOutWidth() );
1328 }
1329
1330 pBorderLine = pBoxItem->GetTop();
1331 if( pBorderLine )
1332 {
1333 pColBorderLine = pBorderLine;
1334 aTwipBorder.AdjustHeight(pBorderLine->GetOutWidth() );
1335 }
1336
1337 pBorderLine = pBoxItem->GetBottom();
1338 if( pBorderLine )
1339 {
1340 pColBorderLine = pBorderLine;
1341 aTwipBorder.AdjustHeight(pBorderLine->GetOutWidth() );
1342 }
1343
1344 aTwipBorder.setWidth( aTwipBorder.Width() / 2 );
1345 aTwipBorder.setHeight( aTwipBorder.Height() / 2 );
1346
1347 if( (aTwipBorder.Width() || aTwipBorder.Height()) &&
1348 Application::GetDefaultDevice() )
1349 {
1350 Size aPixelBorder =
1351 Application::GetDefaultDevice()->LogicToPixel( aTwipBorder,
1352 MapMode(MapUnit::MapTwip) );
1353 if( !aPixelBorder.Width() && aTwipBorder.Width() )
1354 aPixelBorder.setWidth( 1 );
1355 if( !aPixelBorder.Height() && aTwipBorder.Height() )
1356 aPixelBorder.setHeight( 1 );
1357
1358 if( aPixelBorder.Width() )
1359 aPixelBorder.setHeight( 0 );
1360
1361 nBorderWidth =
1362 o3tl::narrowing<sal_uInt16>(aPixelBorder.Width() + aPixelBorder.Height());
1363 }
1364
1365 if( pColBorderLine )
1366 {
1367 rHtml.start(OOO_STRING_SVTOOLS_HTML_font);
1368 HtmlWriterHelper::applyColor(rHtml, OOO_STRING_SVTOOLS_HTML_O_color, pColBorderLine->GetColor());
1369 }
1370 }
1371
1372 OString aTag(OOO_STRING_SVTOOLS_HTML_image);
1373 if (bReplacement)
1374 // Write replacement graphic of OLE object as <object>.
1375 aTag = OOO_STRING_SVTOOLS_HTML_object;
1376 rHtml.start(aTag);
1377
1378 OStringBuffer sBuffer;
1379 if(rHTMLWrt.mbEmbedImages)
1380 {
1381 OUString aGraphicInBase64;
1382 if (XOutBitmap::GraphicToBase64(rGraphic, aGraphicInBase64))
1383 {
1384 sBuffer.append(OOO_STRING_SVTOOLS_HTML_O_data);
1385 sBuffer.append(":");
1386 sBuffer.append(OUStringToOString(aGraphicInBase64, RTL_TEXTENCODING_UTF8));
1387 rHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_src, sBuffer.makeStringAndClear().getStr());
1388 }
1389 else
1390 rHTMLWrt.m_nWarn = WARN_SWG_POOR_LOAD;
1391 }
1392 else
1393 {
1394 sBuffer.append(OUStringToOString(aGraphicURL, RTL_TEXTENCODING_UTF8));
1395 OString aAttribute(OOO_STRING_SVTOOLS_HTML_O_src);
1396 if (bReplacement)
1397 aAttribute = OOO_STRING_SVTOOLS_HTML_O_data;
1398 rHtml.attribute(aAttribute, sBuffer.makeStringAndClear().getStr());
1399 }
1400
1401 if (bReplacement)
1402 {
1403 // Handle XHTML type attribute for OLE replacement images.
1404 if (!rMimeType.isEmpty())
1405 rHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_type, rMimeType.toUtf8());
1406 }
1407
1408 // Events
1409 if (SfxItemState::SET == rItemSet.GetItemState(RES_FRMMACRO, true, &pItem))
1410 {
1411 const SvxMacroTableDtor& rMacTable = static_cast<const SvxMacroItem *>(pItem)->GetMacroTable();
1412 if (!rMacTable.empty())
1413 {
1414 HtmlWriterHelper::applyEvents(rHtml, rMacTable, aImageEventTable, rHTMLWrt.m_bCfgStarBasic);
1415 }
1416 }
1417
1418 // alt, align, width, height, hspace, vspace
1419 rHTMLWrt.writeFrameFormatOptions(rHtml, rFrameFormat, rAlternateText, nFrameOpts);
1420 if( rHTMLWrt.IsHTMLMode( HTMLMODE_ABS_POS_FLY ) )
1421 rHTMLWrt.OutCSS1_FrameFormatOptions( rFrameFormat, nFrameOpts );
1422
1423 if ((nFrameOpts & HtmlFrmOpts::Border) && !bReplacement)
1424 {
1425 rHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_border, nBorderWidth);
1426 }
1427
1428 if( pURLItem && pURLItem->IsServerMap() )
1429 {
1430 rHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_ismap);
1431 }
1432
1433 if( !aIMapName.isEmpty() )
1434 {
1435 rHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_usemap, OUString("#" + aIMapName));
1436 }
1437
1438 if (bReplacement)
1439 {
1440 // XHTML object replacement image's alternate text doesn't use the
1441 // "alt" attribute.
1442 if (rAlternateText.isEmpty())
1443 // Empty alternate text is not valid.
1444 rHtml.characters(" ");
1445 else
1446 rHtml.characters(rAlternateText.toUtf8());
1447 }
1448
1449 return rHTMLWrt;
1450 }
1451
OutHTML_ImageEnd(HtmlWriter & rHtml,Writer & rWrt)1452 Writer& OutHTML_ImageEnd( HtmlWriter& rHtml, Writer& rWrt )
1453 {
1454 SwHTMLWriter& rHTMLWrt = static_cast<SwHTMLWriter&>(rWrt);
1455 rHtml.flushStack();
1456
1457 if( !rHTMLWrt.m_aINetFormats.empty() )
1458 {
1459 // There is still an attribute on the stack that has to be reopened
1460 SwFormatINetFormat *pINetFormat = rHTMLWrt.m_aINetFormats.back();
1461 OutHTML_INetFormat( rWrt, *pINetFormat, true );
1462 }
1463
1464 return rHTMLWrt;
1465 }
1466
OutHTML_BulletImage(Writer & rWrt,const char * pTag,const SvxBrushItem * pBrush,const OUString & rGraphicURL)1467 Writer& OutHTML_BulletImage( Writer& rWrt,
1468 const char *pTag,
1469 const SvxBrushItem* pBrush,
1470 const OUString &rGraphicURL)
1471 {
1472 SwHTMLWriter & rHTMLWrt = static_cast<SwHTMLWriter&>(rWrt);
1473
1474 OUString aGraphicInBase64;
1475 OUString aLink;
1476 if( pBrush )
1477 {
1478 aLink = pBrush->GetGraphicLink();
1479 if(rHTMLWrt.mbEmbedImages || aLink.isEmpty())
1480 {
1481 const Graphic* pGrf = pBrush->GetGraphic();
1482 if( pGrf )
1483 {
1484 if( !XOutBitmap::GraphicToBase64(*pGrf, aGraphicInBase64) )
1485 {
1486 rHTMLWrt.m_nWarn = WARN_SWG_POOR_LOAD;
1487 }
1488 }
1489 }
1490 else if(!aLink.isEmpty())
1491 {
1492 if( rHTMLWrt.m_bCfgCpyLinkedGrfs )
1493 {
1494 rHTMLWrt.CopyLocalFileToINet( aLink );
1495 }
1496
1497 }
1498 }
1499 else if(!rHTMLWrt.mbEmbedImages)
1500 {
1501 aLink = rGraphicURL;
1502 }
1503 if(!aLink.isEmpty())
1504 {
1505 if( !HTMLOutFuncs::PrivateURLToInternalImg(aLink) )
1506 aLink = URIHelper::simpleNormalizedMakeRelative( rWrt.GetBaseURL(), aLink);
1507 }
1508
1509 OStringBuffer sOut;
1510 if( pTag )
1511 sOut.append('<').append(pTag);
1512
1513 sOut.append(' ');
1514 sOut.append(OOO_STRING_SVTOOLS_HTML_O_style "=\"");
1515 if(!aLink.isEmpty())
1516 {
1517 sOut.append(OOO_STRING_SVTOOLS_HTML_O_src "=\"");
1518 rWrt.Strm().WriteOString( sOut.makeStringAndClear() );
1519 HTMLOutFuncs::Out_String( rWrt.Strm(), aLink, rHTMLWrt.m_eDestEnc, &rHTMLWrt.m_aNonConvertableCharacters );
1520 }
1521 else
1522 {
1523 sOut.append("list-style-image: url("
1524 OOO_STRING_SVTOOLS_HTML_O_data ":");
1525 rWrt.Strm().WriteOString( sOut.makeStringAndClear() );
1526 HTMLOutFuncs::Out_String( rWrt.Strm(), aGraphicInBase64, rHTMLWrt.m_eDestEnc, &rHTMLWrt.m_aNonConvertableCharacters );
1527 sOut.append(");");
1528 }
1529 sOut.append('\"');
1530
1531 if (pTag)
1532 sOut.append('>');
1533 rWrt.Strm().WriteOString( sOut.makeStringAndClear() );
1534
1535 return rWrt;
1536 }
1537
OutHTML_FrameFormatTableNode(Writer & rWrt,const SwFrameFormat & rFrameFormat)1538 static Writer& OutHTML_FrameFormatTableNode( Writer& rWrt, const SwFrameFormat& rFrameFormat )
1539 {
1540 SwHTMLWriter & rHTMLWrt = static_cast<SwHTMLWriter&>(rWrt);
1541
1542 const SwFormatContent& rFlyContent = rFrameFormat.GetContent();
1543 sal_uLong nStt = rFlyContent.GetContentIdx()->GetIndex()+1;
1544 sal_uLong nEnd = rHTMLWrt.m_pDoc->GetNodes()[nStt-1]->EndOfSectionIndex();
1545
1546 OUString aCaption;
1547 bool bTopCaption = false;
1548
1549 // Not const, because GetTable won't be const sometime later
1550 SwNode *pNd = rHTMLWrt.m_pDoc->GetNodes()[ nStt ];
1551 SwTableNode *pTableNd = pNd->GetTableNode();
1552 const SwTextNode *pTextNd = pNd->GetTextNode();
1553 if( !pTableNd && pTextNd )
1554 {
1555 // Table with heading
1556 bTopCaption = true;
1557 pTableNd = rHTMLWrt.m_pDoc->GetNodes()[nStt+1]->GetTableNode();
1558 }
1559 OSL_ENSURE( pTableNd, "Frame does not contain a table" );
1560 if( pTableNd )
1561 {
1562 sal_uLong nTableEnd = pTableNd->EndOfSectionIndex();
1563 OSL_ENSURE( nTableEnd == nEnd - 1 ||
1564 (nTableEnd == nEnd - 2 && !bTopCaption),
1565 "Invalid frame content for a table" );
1566
1567 if( nTableEnd == nEnd - 2 )
1568 pTextNd = rHTMLWrt.m_pDoc->GetNodes()[nTableEnd+1]->GetTextNode();
1569 }
1570 if( pTextNd )
1571 aCaption = pTextNd->GetText();
1572
1573 if( pTableNd )
1574 {
1575 HTMLSaveData aSaveData( rHTMLWrt, pTableNd->GetIndex()+1,
1576 pTableNd->EndOfSectionIndex(),
1577 true, &rFrameFormat );
1578 rHTMLWrt.m_bOutFlyFrame = true;
1579 OutHTML_SwTableNode( rHTMLWrt, *pTableNd, &rFrameFormat, &aCaption,
1580 bTopCaption );
1581 }
1582
1583 return rWrt;
1584 }
1585
OutHTML_FrameFormatAsMulticol(Writer & rWrt,const SwFrameFormat & rFrameFormat,bool bInCntnr)1586 static Writer & OutHTML_FrameFormatAsMulticol( Writer& rWrt,
1587 const SwFrameFormat& rFrameFormat,
1588 bool bInCntnr )
1589 {
1590 SwHTMLWriter & rHTMLWrt = static_cast<SwHTMLWriter&>(rWrt);
1591
1592 rHTMLWrt.ChangeParaToken( HtmlTokenId::NONE );
1593
1594 // Close the current <DL>!
1595 rHTMLWrt.OutAndSetDefList( 0 );
1596
1597 // output as Multicol
1598 if( rHTMLWrt.m_bLFPossible )
1599 rHTMLWrt.OutNewLine();
1600
1601 OStringBuffer sOut;
1602 sOut.append('<').append(rHTMLWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_multicol);
1603
1604 const SwFormatCol& rFormatCol = rFrameFormat.GetCol();
1605
1606 // output the number of columns as COLS
1607 sal_uInt16 nCols = rFormatCol.GetNumCols();
1608 if( nCols )
1609 {
1610 sOut.append(" " OOO_STRING_SVTOOLS_HTML_O_cols
1611 "=\"" + OString::number(nCols) + "\"");
1612 }
1613
1614 // the Gutter width (minimum value) as GUTTER
1615 sal_uInt16 nGutter = rFormatCol.GetGutterWidth( true );
1616 if( nGutter!=USHRT_MAX )
1617 {
1618 if( nGutter && Application::GetDefaultDevice() )
1619 {
1620 nGutter = o3tl::narrowing<sal_uInt16>(Application::GetDefaultDevice()
1621 ->LogicToPixel( Size(nGutter,0),
1622 MapMode(MapUnit::MapTwip) ).Width());
1623 }
1624 sOut.append(" " OOO_STRING_SVTOOLS_HTML_O_gutter
1625 "=\"" + OString::number(nGutter) + "\"");
1626 }
1627
1628 rWrt.Strm().WriteOString( sOut.makeStringAndClear() );
1629
1630 // WIDTH
1631 HtmlFrmOpts nFrameFlags = HTML_FRMOPTS_MULTICOL;
1632 if( rHTMLWrt.IsHTMLMode( HTMLMODE_ABS_POS_FLY ) && !bInCntnr )
1633 nFrameFlags |= HTML_FRMOPTS_MULTICOL_CSS1;
1634 rHTMLWrt.OutFrameFormatOptions(rFrameFormat, OUString(), nFrameFlags);
1635 if( rHTMLWrt.IsHTMLMode( HTMLMODE_ABS_POS_FLY ) && !bInCntnr )
1636 rHTMLWrt.OutCSS1_FrameFormatOptions( rFrameFormat, nFrameFlags );
1637
1638 rWrt.Strm().WriteChar( '>' );
1639
1640 rHTMLWrt.m_bLFPossible = true;
1641 rHTMLWrt.IncIndentLevel(); // indent the content of Multicol
1642
1643 const SwFormatContent& rFlyContent = rFrameFormat.GetContent();
1644 sal_uLong nStt = rFlyContent.GetContentIdx()->GetIndex();
1645 const SwStartNode* pSttNd = rWrt.m_pDoc->GetNodes()[nStt]->GetStartNode();
1646 OSL_ENSURE( pSttNd, "Where is the start node" );
1647
1648 {
1649 // in a block, so that the old state can be restored in time
1650 // before the end
1651 HTMLSaveData aSaveData( rHTMLWrt, nStt+1,
1652 pSttNd->EndOfSectionIndex(),
1653 true, &rFrameFormat );
1654 rHTMLWrt.m_bOutFlyFrame = true;
1655 rHTMLWrt.Out_SwDoc( rWrt.m_pCurrentPam.get() );
1656 }
1657
1658 rHTMLWrt.DecIndentLevel(); // indent the content of Multicol;
1659 if( rHTMLWrt.m_bLFPossible )
1660 rHTMLWrt.OutNewLine();
1661 HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OString(rHTMLWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_multicol), false );
1662 rHTMLWrt.m_bLFPossible = true;
1663
1664 return rWrt;
1665 }
1666
OutHTML_FrameFormatAsSpacer(Writer & rWrt,const SwFrameFormat & rFrameFormat)1667 static Writer& OutHTML_FrameFormatAsSpacer( Writer& rWrt, const SwFrameFormat& rFrameFormat )
1668 {
1669 SwHTMLWriter & rHTMLWrt = static_cast<SwHTMLWriter&>(rWrt);
1670
1671 // if possible, output a line break before the graphic
1672 if( rHTMLWrt.m_bLFPossible )
1673 rHTMLWrt.OutNewLine( true );
1674
1675 OString sOut =
1676 "<" + rHTMLWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_spacer " "
1677 OOO_STRING_SVTOOLS_HTML_O_type "=\""
1678 OOO_STRING_SVTOOLS_HTML_SPTYPE_block "\"";
1679 rWrt.Strm().WriteOString( sOut );
1680
1681 // ALIGN, WIDTH, HEIGHT
1682 OString aEndTags = rHTMLWrt.OutFrameFormatOptions(rFrameFormat, OUString(), HTML_FRMOPTS_SPACER);
1683
1684 rWrt.Strm().WriteChar( '>' );
1685 if( !aEndTags.isEmpty() )
1686 rWrt.Strm().WriteOString( aEndTags );
1687
1688 return rWrt;
1689 }
1690
OutHTML_FrameFormatAsDivOrSpan(Writer & rWrt,const SwFrameFormat & rFrameFormat,bool bSpan)1691 static Writer& OutHTML_FrameFormatAsDivOrSpan( Writer& rWrt,
1692 const SwFrameFormat& rFrameFormat, bool bSpan)
1693 {
1694 SwHTMLWriter & rHTMLWrt = static_cast<SwHTMLWriter&>(rWrt);
1695
1696 OString aTag;
1697 if( !bSpan )
1698 {
1699 rHTMLWrt.ChangeParaToken( HtmlTokenId::NONE );
1700
1701 // Close the current <DL>!
1702 rHTMLWrt.OutAndSetDefList( 0 );
1703 aTag = OOO_STRING_SVTOOLS_HTML_division;
1704 }
1705 else
1706 aTag = OOO_STRING_SVTOOLS_HTML_span;
1707
1708 // output as DIV
1709 if( rHTMLWrt.m_bLFPossible )
1710 rHTMLWrt.OutNewLine();
1711
1712 OStringBuffer sOut;
1713 sOut.append('<').append(rHTMLWrt.GetNamespace() + aTag);
1714
1715 rWrt.Strm().WriteOString( sOut.makeStringAndClear() );
1716 HtmlFrmOpts nFrameFlags = HTML_FRMOPTS_DIV;
1717 if( rHTMLWrt.IsHTMLMode( HTMLMODE_BORDER_NONE ) )
1718 nFrameFlags |= HtmlFrmOpts::SNoBorder;
1719 OString aEndTags = rHTMLWrt.OutFrameFormatOptions(rFrameFormat, OUString(), nFrameFlags);
1720 rHTMLWrt.OutCSS1_FrameFormatOptions( rFrameFormat, nFrameFlags );
1721 rWrt.Strm().WriteChar( '>' );
1722
1723 rHTMLWrt.IncIndentLevel(); // indent the content
1724 rHTMLWrt.m_bLFPossible = true;
1725
1726 const SwFormatContent& rFlyContent = rFrameFormat.GetContent();
1727 sal_uLong nStt = rFlyContent.GetContentIdx()->GetIndex();
1728
1729 // Output frame-anchored frames that are anchored to the start node
1730 rHTMLWrt.OutFlyFrame( nStt, 0, HtmlPosition::Any );
1731
1732 const SwStartNode* pSttNd = rWrt.m_pDoc->GetNodes()[nStt]->GetStartNode();
1733 OSL_ENSURE( pSttNd, "Where is the start node" );
1734
1735 {
1736 // in a block, so that the old state can be restored in time
1737 // before the end
1738 HTMLSaveData aSaveData( rHTMLWrt, nStt+1,
1739 pSttNd->EndOfSectionIndex(),
1740 true, &rFrameFormat );
1741 rHTMLWrt.m_bOutFlyFrame = true;
1742 rHTMLWrt.Out_SwDoc( rWrt.m_pCurrentPam.get() );
1743 }
1744
1745 rHTMLWrt.DecIndentLevel(); // indent the content of Multicol;
1746 if( rHTMLWrt.m_bLFPossible )
1747 rHTMLWrt.OutNewLine();
1748 HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OString(rHTMLWrt.GetNamespace() + aTag), false );
1749
1750 if( !aEndTags.isEmpty() )
1751 rWrt.Strm().WriteOString( aEndTags );
1752
1753 return rWrt;
1754 }
1755
1756 /// Starts the OLE version of an image in the ReqIF + OLE case.
OutHTML_ImageOLEStart(SwHTMLWriter & rHTMLWrt,const Graphic & rGraphic,const SwFrameFormat & rFrameFormat)1757 static void OutHTML_ImageOLEStart(SwHTMLWriter& rHTMLWrt, const Graphic& rGraphic,
1758 const SwFrameFormat& rFrameFormat)
1759 {
1760 if (rHTMLWrt.mbReqIF && rHTMLWrt.m_bExportImagesAsOLE)
1761 {
1762 // Write the original image as an RTF fragment.
1763 OUString aFileName;
1764 if (rHTMLWrt.GetOrigFileName())
1765 aFileName = *rHTMLWrt.GetOrigFileName();
1766 INetURLObject aURL(aFileName);
1767 OUString aName = aURL.getBase() + "_" + aURL.getExtension() + "_"
1768 + OUString::number(rGraphic.GetChecksum(), 16);
1769 aURL.setBase(aName);
1770 aURL.setExtension(u"ole");
1771 aFileName = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE);
1772
1773 SvFileStream aOutStream(aFileName, StreamMode::WRITE);
1774 if (!SwReqIfReader::WrapGraphicInRtf(rGraphic, rFrameFormat, aOutStream))
1775 SAL_WARN("sw.html", "SwReqIfReader::WrapGraphicInRtf() failed");
1776
1777 // Refer to this data.
1778 aFileName = URIHelper::simpleNormalizedMakeRelative(rHTMLWrt.GetBaseURL(), aFileName);
1779 rHTMLWrt.Strm().WriteOString(
1780 OString("<" + rHTMLWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_object));
1781 rHTMLWrt.Strm().WriteOString(OString(" data=\"" + aFileName.toUtf8() + "\""));
1782 rHTMLWrt.Strm().WriteOString(" type=\"text/rtf\"");
1783 rHTMLWrt.Strm().WriteOString(">");
1784 rHTMLWrt.OutNewLine();
1785 }
1786 }
1787
1788 /// Ends the OLE version of an image in the ReqIF + OLE case.
OutHTML_ImageOLEEnd(SwHTMLWriter & rHTMLWrt)1789 static void OutHTML_ImageOLEEnd(SwHTMLWriter& rHTMLWrt)
1790 {
1791 if (rHTMLWrt.mbReqIF && rHTMLWrt.m_bExportImagesAsOLE)
1792 {
1793 rHTMLWrt.Strm().WriteOString(
1794 OString("</" + rHTMLWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_object ">"));
1795 }
1796 }
1797
OutHTML_FrameFormatAsImage(Writer & rWrt,const SwFrameFormat & rFrameFormat,bool bPNGFallback)1798 static Writer & OutHTML_FrameFormatAsImage( Writer& rWrt, const SwFrameFormat& rFrameFormat, bool bPNGFallback)
1799 {
1800 SwHTMLWriter& rHTMLWrt = static_cast<SwHTMLWriter&>(rWrt);
1801 bool bWritePNGFallback = rHTMLWrt.mbReqIF && !rHTMLWrt.m_bExportImagesAsOLE && bPNGFallback;
1802
1803 if (rHTMLWrt.mbSkipImages)
1804 return rWrt;
1805
1806 ImageMap aIMap;
1807 std::optional<Size> aDPI;
1808 if (rHTMLWrt.m_nShapeDPI.has_value())
1809 {
1810 aDPI.emplace(*rHTMLWrt.m_nShapeDPI, *rHTMLWrt.m_nShapeDPI);
1811 }
1812 Graphic aGraphic( const_cast<SwFrameFormat &>(rFrameFormat).MakeGraphic( &aIMap, /*nMaximumQuadraticPixels=*/2100000, aDPI ) );
1813
1814 if (rHTMLWrt.mbReqIF)
1815 {
1816 // ImageMap doesn't seem to be allowed in reqif.
1817 if (auto pGrafObj = dynamic_cast<const SdrGrafObj*>(rFrameFormat.FindSdrObject()))
1818 {
1819 aGraphic = pGrafObj->GetGraphic();
1820 }
1821 else
1822 {
1823 // We only have a bitmap, write that as PNG without any fallback.
1824 bWritePNGFallback = false;
1825 }
1826 }
1827
1828 Size aSz( 0, 0 );
1829 OUString GraphicURL;
1830 OUString aMimeType("image/jpeg");
1831 if(!rHTMLWrt.mbEmbedImages)
1832 {
1833 if( rHTMLWrt.GetOrigFileName() )
1834 GraphicURL = *rHTMLWrt.GetOrigFileName();
1835
1836 OUString aFilterName("JPG");
1837 XOutFlags nFlags = XOutFlags::UseGifIfPossible | XOutFlags::UseNativeIfPossible;
1838
1839 if (rHTMLWrt.mbReqIF && !bWritePNGFallback)
1840 {
1841 // Writing image without fallback PNG in ReqIF mode: force PNG output.
1842 aFilterName = "PNG";
1843 nFlags = XOutFlags::NONE;
1844 aMimeType = "image/png";
1845 }
1846 else if (rHTMLWrt.mbReqIF)
1847 {
1848 // Original format is wanted, don't force JPG.
1849 aFilterName.clear();
1850 aMimeType.clear();
1851 }
1852
1853 if( aGraphic.GetType() == GraphicType::NONE ||
1854 XOutBitmap::WriteGraphic( aGraphic, GraphicURL,
1855 aFilterName,
1856 nFlags ) != ERRCODE_NONE )
1857 {
1858 // empty or incorrect, because there is nothing to output
1859 rHTMLWrt.m_nWarn = WARN_SWG_POOR_LOAD;
1860 return rWrt;
1861 }
1862
1863 GraphicURL = URIHelper::SmartRel2Abs(
1864 INetURLObject(rWrt.GetBaseURL()), GraphicURL,
1865 URIHelper::GetMaybeFileHdl() );
1866
1867 }
1868 uno::Reference<beans::XPropertySet> xGraphic(aGraphic.GetXGraphic(), uno::UNO_QUERY);
1869 if (xGraphic.is() && aMimeType.isEmpty())
1870 xGraphic->getPropertyValue("MimeType") >>= aMimeType;
1871
1872 OutHTML_ImageOLEStart(rHTMLWrt, aGraphic, rFrameFormat);
1873
1874 HtmlWriter aHtml(rWrt.Strm(), rHTMLWrt.maNamespace);
1875 OutHTML_ImageStart( aHtml, rWrt, rFrameFormat, GraphicURL, aGraphic, rFrameFormat.GetName(), aSz,
1876 HtmlFrmOpts::GenImgMask, "frame",
1877 aIMap.GetIMapObjectCount() ? &aIMap : nullptr, aMimeType );
1878
1879 GfxLink aLink = aGraphic.GetGfxLink();
1880 if (bWritePNGFallback && aLink.GetType() != GfxLinkType::NativePng)
1881 {
1882 OutHTML_FrameFormatAsImage( rWrt, rFrameFormat, /*bPNGFallback=*/false);
1883 }
1884
1885 OutHTML_ImageEnd(aHtml, rWrt);
1886
1887 OutHTML_ImageOLEEnd(rHTMLWrt);
1888
1889 return rWrt;
1890 }
1891
OutHTML_FrameFormatGrfNode(Writer & rWrt,const SwFrameFormat & rFrameFormat,bool bInCntnr,bool bPNGFallback)1892 static Writer& OutHTML_FrameFormatGrfNode( Writer& rWrt, const SwFrameFormat& rFrameFormat,
1893 bool bInCntnr, bool bPNGFallback )
1894 {
1895 SwHTMLWriter& rHTMLWrt = static_cast<SwHTMLWriter&>(rWrt);
1896 bool bWritePNGFallback = rHTMLWrt.mbReqIF && !rHTMLWrt.m_bExportImagesAsOLE && bPNGFallback;
1897
1898 if (rHTMLWrt.mbSkipImages)
1899 return rWrt;
1900
1901 const SwFormatContent& rFlyContent = rFrameFormat.GetContent();
1902 sal_uLong nStt = rFlyContent.GetContentIdx()->GetIndex()+1;
1903 SwGrfNode *pGrfNd = rHTMLWrt.m_pDoc->GetNodes()[ nStt ]->GetGrfNode();
1904 OSL_ENSURE( pGrfNd, "Grf node expected" );
1905 if( !pGrfNd )
1906 return rWrt;
1907
1908 HtmlFrmOpts nFrameFlags = bInCntnr ? HTML_FRMOPTS_IMG_CNTNR : HTML_FRMOPTS_IMG;
1909 if( rHTMLWrt.IsHTMLMode( HTMLMODE_ABS_POS_FLY ) && !bInCntnr )
1910 nFrameFlags |= HTML_FRMOPTS_IMG_CSS1;
1911
1912 Graphic aGraphic = pGrfNd->GetGraphic();
1913 OUString aGraphicURL;
1914 OUString aMimeType;
1915 if(!rHTMLWrt.mbEmbedImages)
1916 {
1917 const SwMirrorGrf& rMirror = pGrfNd->GetSwAttrSet().GetMirrorGrf();
1918
1919 if( !pGrfNd->IsLinkedFile() || MirrorGraph::Dont != rMirror.GetValue() )
1920 {
1921 // create a (mirrored) jpeg file
1922 if( rHTMLWrt.GetOrigFileName() )
1923 aGraphicURL = *rHTMLWrt.GetOrigFileName();
1924 else
1925 aGraphicURL = rHTMLWrt.GetBaseURL();
1926 pGrfNd->GetGrf( true );
1927
1928 XOutFlags nFlags = XOutFlags::UseGifIfSensible |
1929 XOutFlags::UseNativeIfPossible;
1930 switch( rMirror.GetValue() )
1931 {
1932 case MirrorGraph::Vertical: nFlags = XOutFlags::MirrorHorz; break;
1933 case MirrorGraph::Horizontal: nFlags = XOutFlags::MirrorVert; break;
1934 case MirrorGraph::Both:
1935 nFlags = XOutFlags::MirrorVert | XOutFlags::MirrorHorz;
1936 break;
1937 default: break;
1938 }
1939
1940 Size aMM100Size;
1941 const SwFormatFrameSize& rSize = rFrameFormat.GetFrameSize();
1942 aMM100Size = OutputDevice::LogicToLogic( rSize.GetSize(),
1943 MapMode( MapUnit::MapTwip ), MapMode( MapUnit::Map100thMM ));
1944
1945 OUString aFilterName("");
1946
1947 if (rHTMLWrt.mbReqIF && !bWritePNGFallback)
1948 {
1949 // Writing image without fallback PNG in ReqIF mode: force PNG
1950 // output.
1951 // But don't force it when writing the original format and we'll write PNG inside
1952 // that.
1953 aFilterName = "PNG";
1954 nFlags &= ~XOutFlags::UseNativeIfPossible;
1955 nFlags &= ~XOutFlags::UseGifIfSensible;
1956 aMimeType = "image/png";
1957 }
1958
1959 const Graphic& rGraphic = pGrfNd->GetGrf();
1960
1961 // So that Graphic::IsTransparent() can report true.
1962 if (!rGraphic.isAvailable())
1963 const_cast<Graphic&>(rGraphic).makeAvailable();
1964
1965 ErrCode nErr = XOutBitmap::WriteGraphic( rGraphic, aGraphicURL,
1966 aFilterName, nFlags, &aMM100Size );
1967 if( nErr )
1968 {
1969 rHTMLWrt.m_nWarn = WARN_SWG_POOR_LOAD;
1970 return rWrt;
1971 }
1972 aGraphicURL = URIHelper::SmartRel2Abs(
1973 INetURLObject(rWrt.GetBaseURL()), aGraphicURL,
1974 URIHelper::GetMaybeFileHdl() );
1975 }
1976 else
1977 {
1978 pGrfNd->GetFileFilterNms( &aGraphicURL, nullptr );
1979 if( rHTMLWrt.m_bCfgCpyLinkedGrfs )
1980 rWrt.CopyLocalFileToINet( aGraphicURL );
1981 }
1982
1983 }
1984 uno::Reference<beans::XPropertySet> xGraphic(aGraphic.GetXGraphic(), uno::UNO_QUERY);
1985 if (xGraphic.is() && aMimeType.isEmpty())
1986 xGraphic->getPropertyValue("MimeType") >>= aMimeType;
1987
1988 OutHTML_ImageOLEStart(rHTMLWrt, aGraphic, rFrameFormat);
1989
1990 HtmlWriter aHtml(rWrt.Strm(), rHTMLWrt.maNamespace);
1991 OutHTML_ImageStart( aHtml, rWrt, rFrameFormat, aGraphicURL, aGraphic, pGrfNd->GetTitle(),
1992 pGrfNd->GetTwipSize(), nFrameFlags, "graphic", nullptr, aMimeType );
1993
1994 GfxLink aLink = aGraphic.GetGfxLink();
1995 if (bWritePNGFallback && aLink.GetType() != GfxLinkType::NativePng)
1996 {
1997 // Not OLE mode, outer format is not PNG: write inner PNG.
1998 OutHTML_FrameFormatGrfNode( rWrt, rFrameFormat,
1999 bInCntnr, /*bPNGFallback=*/false );
2000 }
2001
2002 OutHTML_ImageEnd(aHtml, rWrt);
2003
2004 OutHTML_ImageOLEEnd(rHTMLWrt);
2005
2006 return rWrt;
2007 }
2008
OutHTML_FrameFormatAsMarquee(Writer & rWrt,const SwFrameFormat & rFrameFormat,const SdrObject & rSdrObj)2009 static Writer& OutHTML_FrameFormatAsMarquee( Writer& rWrt, const SwFrameFormat& rFrameFormat,
2010 const SdrObject& rSdrObj )
2011 {
2012 SwHTMLWriter & rHTMLWrt = static_cast<SwHTMLWriter&>(rWrt);
2013
2014 // get the edit engine attributes of the object as SW attributes and
2015 // sort them as Hints
2016 const SfxItemSet& rFormatItemSet = rFrameFormat.GetAttrSet();
2017 SfxItemSet aItemSet( *rFormatItemSet.GetPool(), svl::Items<RES_CHRATR_BEGIN,
2018 RES_CHRATR_END>{} );
2019 SwHTMLWriter::GetEEAttrsFromDrwObj( aItemSet, &rSdrObj );
2020 bool bCfgOutStylesOld = rHTMLWrt.m_bCfgOutStyles;
2021 rHTMLWrt.m_bCfgOutStyles = false;
2022 rHTMLWrt.m_bTextAttr = true;
2023 rHTMLWrt.m_bTagOn = true;
2024 Out_SfxItemSet( aHTMLAttrFnTab, rWrt, aItemSet, false );
2025 rHTMLWrt.m_bTextAttr = false;
2026
2027 OutHTML_DrawFrameFormatAsMarquee( rHTMLWrt,
2028 static_cast<const SwDrawFrameFormat &>(rFrameFormat),
2029 rSdrObj );
2030 rHTMLWrt.m_bTextAttr = true;
2031 rHTMLWrt.m_bTagOn = false;
2032 Out_SfxItemSet( aHTMLAttrFnTab, rWrt, aItemSet, false );
2033 rHTMLWrt.m_bTextAttr = false;
2034 rHTMLWrt.m_bCfgOutStyles = bCfgOutStylesOld;
2035
2036 return rWrt;
2037 }
2038
OutHTML_HeaderFooter(Writer & rWrt,const SwFrameFormat & rFrameFormat,bool bHeader)2039 Writer& OutHTML_HeaderFooter( Writer& rWrt, const SwFrameFormat& rFrameFormat,
2040 bool bHeader )
2041 {
2042 SwHTMLWriter & rHTMLWrt = static_cast<SwHTMLWriter&>(rWrt);
2043
2044 // output as Multicol
2045 rHTMLWrt.OutNewLine();
2046 OStringBuffer sOut;
2047 sOut.append(OOO_STRING_SVTOOLS_HTML_division " "
2048 OOO_STRING_SVTOOLS_HTML_O_title "=\"")
2049 .append( bHeader ? "header" : "footer" ).append("\"");
2050 HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OString(rHTMLWrt.GetNamespace() + sOut) );
2051
2052 rHTMLWrt.IncIndentLevel(); // indent the content of Multicol;
2053
2054 // Piece a spacer for the spacing together. Because the
2055 // <DL> or </DL> always produces a space between paragraphs, it is
2056 // subtracted if necessary.
2057 const SvxULSpaceItem& rULSpace = rFrameFormat.GetULSpace();
2058 sal_uInt16 nSize = bHeader ? rULSpace.GetLower() : rULSpace.GetUpper();
2059 rHTMLWrt.m_nHeaderFooterSpace = nSize;
2060
2061 OString aSpacer;
2062 if( rHTMLWrt.IsHTMLMode(HTMLMODE_VERT_SPACER) &&
2063 nSize > HTML_PARSPACE && Application::GetDefaultDevice() )
2064 {
2065 nSize -= HTML_PARSPACE;
2066 nSize = static_cast<sal_Int16>(Application::GetDefaultDevice()
2067 ->LogicToPixel( Size(nSize,0), MapMode(MapUnit::MapTwip) ).Width());
2068
2069 aSpacer = OOO_STRING_SVTOOLS_HTML_spacer
2070 " " OOO_STRING_SVTOOLS_HTML_O_type
2071 "=\"" OOO_STRING_SVTOOLS_HTML_SPTYPE_vertical "\""
2072 " " OOO_STRING_SVTOOLS_HTML_O_size
2073 "=\"" + OString::number(nSize) + "\"";
2074 }
2075
2076 const SwFormatContent& rFlyContent = rFrameFormat.GetContent();
2077 sal_uLong nStt = rFlyContent.GetContentIdx()->GetIndex();
2078 const SwStartNode* pSttNd = rWrt.m_pDoc->GetNodes()[nStt]->GetStartNode();
2079 OSL_ENSURE( pSttNd, "Where is the start node" );
2080
2081 if( !bHeader && !aSpacer.isEmpty() )
2082 {
2083 rHTMLWrt.OutNewLine();
2084 HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OString(rHTMLWrt.GetNamespace() + aSpacer) );
2085 }
2086
2087 {
2088 // in a block, so that the old state can be restored in time
2089 // before the end. pFlyFormat doesn't need to be set here, because
2090 // PageDesc attributes cannot occur here
2091 HTMLSaveData aSaveData( rHTMLWrt, nStt+1,
2092 pSttNd->EndOfSectionIndex() );
2093
2094 if( bHeader )
2095 rHTMLWrt.m_bOutHeader = true;
2096 else
2097 rHTMLWrt.m_bOutFooter = true;
2098
2099 rHTMLWrt.Out_SwDoc( rWrt.m_pCurrentPam.get() );
2100 }
2101
2102 if( bHeader && !aSpacer.isEmpty() )
2103 {
2104 rHTMLWrt.OutNewLine();
2105 HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OString(rHTMLWrt.GetNamespace() + aSpacer) );
2106 }
2107
2108 rHTMLWrt.DecIndentLevel(); // indent the content of Multicol;
2109 rHTMLWrt.OutNewLine();
2110 HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OString(rHTMLWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_division), false );
2111
2112 rHTMLWrt.m_nHeaderFooterSpace = 0;
2113
2114 return rWrt;
2115 }
2116
AddLinkTarget(const OUString & rURL)2117 void SwHTMLWriter::AddLinkTarget( const OUString& rURL )
2118 {
2119 if( rURL.isEmpty() || rURL[0] != '#' )
2120 return;
2121
2122 // There might be a '|' as delimiter (if the link has been inserted
2123 // freshly) or a '%7c' or a '%7C' if the document has been saved and
2124 // loaded already.
2125 sal_Int32 nPos = rURL.getLength();
2126 bool bFound = false, bEncoded = false;
2127 while( !bFound && nPos > 0 )
2128 {
2129 sal_Unicode c = rURL[ --nPos ];
2130 switch( c )
2131 {
2132 case cMarkSeparator:
2133 bFound = true;
2134 break;
2135 case '%':
2136 bFound = (rURL.getLength() - nPos) >=3 && rURL[ nPos+1 ] == '7';
2137 if(bFound)
2138 {
2139 c = rURL[ nPos+2 ];
2140 bFound = (c == 'C' || c == 'c');
2141 }
2142 if( bFound )
2143 bEncoded = true;
2144 }
2145 }
2146 if( !bFound || nPos < 2 ) // at least "#a|..."
2147 return;
2148
2149 OUString aURL( rURL.copy( 1 ) );
2150
2151 // nPos-1+1/3 (-1 because of Erase)
2152 OUString sCmp = aURL.copy(bEncoded ? nPos+2 : nPos).replaceAll(" ","");
2153 if( sCmp.isEmpty() )
2154 return;
2155
2156 sCmp = sCmp.toAsciiLowerCase();
2157
2158 if( sCmp == "region" ||
2159 sCmp == "frame" ||
2160 sCmp == "graphic" ||
2161 sCmp == "ole" ||
2162 sCmp == "table" )
2163 {
2164 // Just remember it in a sorted array
2165 if( bEncoded )
2166 {
2167 aURL = aURL.replaceAt( nPos - 1, 3, OUString(cMarkSeparator) );
2168 }
2169 m_aImplicitMarks.insert( aURL );
2170 }
2171 else if( sCmp == "outline" )
2172 {
2173 // Here, we need position and name. That's why we sort a
2174 // sal_uInt16 and a string array ourselves.
2175 OUString aOutline( aURL.copy( 0, nPos-1 ) );
2176 SwPosition aPos( *m_pCurrentPam->GetPoint() );
2177 if( m_pDoc->GotoOutline( aPos, aOutline ) )
2178 {
2179 sal_uInt32 nIdx = aPos.nNode.GetIndex();
2180
2181 decltype(m_aOutlineMarkPoss)::size_type nIns=0;
2182 while( nIns < m_aOutlineMarkPoss.size() &&
2183 m_aOutlineMarkPoss[nIns] < nIdx )
2184 nIns++;
2185
2186 m_aOutlineMarkPoss.insert( m_aOutlineMarkPoss.begin()+nIns, nIdx );
2187 if( bEncoded )
2188 {
2189 aURL = aURL.replaceAt( nPos - 1, 3, OUString(cMarkSeparator) );
2190 }
2191 m_aOutlineMarks.insert( m_aOutlineMarks.begin()+nIns, aURL );
2192 }
2193 }
2194 }
2195
CollectLinkTargets()2196 void SwHTMLWriter::CollectLinkTargets()
2197 {
2198 const SwTextINetFormat* pTextAttr;
2199
2200 for (const SfxPoolItem* pItem : m_pDoc->GetAttrPool().GetItemSurrogates(RES_TXTATR_INETFMT))
2201 {
2202 auto pINetFormat = dynamic_cast<const SwFormatINetFormat*>(pItem);
2203 const SwTextNode* pTextNd;
2204
2205 if( pINetFormat &&
2206 nullptr != ( pTextAttr = pINetFormat->GetTextINetFormat()) &&
2207 nullptr != ( pTextNd = pTextAttr->GetpTextNode() ) &&
2208 pTextNd->GetNodes().IsDocNodes() )
2209 {
2210 AddLinkTarget( pINetFormat->GetValue() );
2211 }
2212 }
2213
2214 for (const SfxPoolItem* pItem : m_pDoc->GetAttrPool().GetItemSurrogates(RES_URL))
2215 {
2216 auto pURL = dynamic_cast<const SwFormatURL*>(pItem);
2217 if( pURL )
2218 {
2219 AddLinkTarget( pURL->GetURL() );
2220 const ImageMap *pIMap = pURL->GetMap();
2221 if( pIMap )
2222 {
2223 for( size_t i=0; i<pIMap->GetIMapObjectCount(); ++i )
2224 {
2225 const IMapObject* pObj = pIMap->GetIMapObject( i );
2226 if( pObj )
2227 {
2228 AddLinkTarget( pObj->GetURL() );
2229 }
2230 }
2231 }
2232 }
2233 }
2234 }
2235
2236 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2237