LibreOffice Module sw (master) 1
swhtml.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <sal/config.h>
21
22#include <algorithm>
23#include <memory>
24#include <config_java.h>
25
26#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
27#include <com/sun/star/document/XDocumentProperties.hpp>
28#include <com/sun/star/i18n/ScriptType.hpp>
29#include <com/sun/star/i18n/XBreakIterator.hpp>
30#include <comphelper/string.hxx>
31#include <o3tl/safeint.hxx>
32#include <rtl/ustrbuf.hxx>
33#include <svx/svxids.hrc>
34#if OSL_DEBUG_LEVEL > 0
35#include <stdlib.h>
36#endif
37#include <hintids.hxx>
38
39#include <utility>
40#include <vcl/errinf.hxx>
41#include <svl/stritem.hxx>
42#include <vcl/imap.hxx>
43#include <svtools/htmltokn.h>
44#include <svtools/htmlkywd.hxx>
45#include <svtools/ctrltool.hxx>
48#include <vcl/svapp.hxx>
49#include <sfx2/event.hxx>
50#include <sfx2/docfile.hxx>
51
52#include <sfx2/linkmgr.hxx>
53#include <editeng/kernitem.hxx>
54#include <editeng/boxitem.hxx>
55#include <editeng/fhgtitem.hxx>
57#include <editeng/postitem.hxx>
58#include <editeng/wghtitem.hxx>
60#include <editeng/udlnitem.hxx>
62#include <editeng/blinkitem.hxx>
63#include <editeng/ulspitem.hxx>
64#include <editeng/colritem.hxx>
65#include <editeng/fontitem.hxx>
67#include <editeng/lrspitem.hxx>
68#include <editeng/protitem.hxx>
69#include <editeng/flstitem.hxx>
71
72#include <frmatr.hxx>
73#include <charatr.hxx>
74#include <fmtfld.hxx>
75#include <fmtpdsc.hxx>
76#include <fmtanchr.hxx>
77#include <fmtsrnd.hxx>
78#include <fmtfsize.hxx>
79#include <fmtclds.hxx>
80#include <fchrfmt.hxx>
81#include <fmtinfmt.hxx>
82#include <fmtfollowtextflow.hxx>
83#include <fmtornt.hxx>
84#include <doc.hxx>
85#include <IDocumentUndoRedo.hxx>
93#include <IDocumentState.hxx>
94#include <pam.hxx>
95#include <ndtxt.hxx>
96#include <mdiexp.hxx>
97#include <poolfmt.hxx>
98#include <pagedesc.hxx>
99#include <IMark.hxx>
100#include <docsh.hxx>
101#include <editsh.hxx>
102#include <docufld.hxx>
103#include "swcss1.hxx"
104#include <fltini.hxx>
105#include <htmltbl.hxx>
106#include "htmlnum.hxx"
107#include "swhtml.hxx"
108#include "wrthtml.hxx"
109#include <linkenum.hxx>
110#include <breakit.hxx>
111#include <SwAppletImpl.hxx>
112#include <swdll.hxx>
113#include <txatbase.hxx>
114
115#include <sfx2/viewfrm.hxx>
116#include <svx/svdobj.hxx>
117#include <officecfg/Office/Writer.hxx>
120#include <officecfg/Office/Common.hxx>
121
122#include <swerror.h>
123#include <ndole.hxx>
124#include <unoframe.hxx>
125#include "css1atr.hxx"
126#include <frameformats.hxx>
127
128#define FONTSIZE_MASK 7
129
130#define HTML_ESC_PROP 80
131#define HTML_ESC_SUPER DFLT_ESC_SUPER
132#define HTML_ESC_SUB DFLT_ESC_SUB
133
134#define HTML_SPTYPE_BLOCK 1
135#define HTML_SPTYPE_HORI 2
136#define HTML_SPTYPE_VERT 3
137
139using namespace ::com::sun::star;
140
141// <P ALIGN=xxx>, <Hn ALIGN=xxx>, <TD ALIGN=xxx> etc.
143{
144 { OOO_STRING_SVTOOLS_HTML_AL_left, SvxAdjust::Left },
145 { OOO_STRING_SVTOOLS_HTML_AL_center, SvxAdjust::Center },
146 { OOO_STRING_SVTOOLS_HTML_AL_middle, SvxAdjust::Center }, // Netscape
147 { OOO_STRING_SVTOOLS_HTML_AL_right, SvxAdjust::Right },
148 { OOO_STRING_SVTOOLS_HTML_AL_justify, SvxAdjust::Block },
149 { OOO_STRING_SVTOOLS_HTML_AL_char, SvxAdjust::Left },
150 { nullptr, SvxAdjust(0) }
151};
152
153// <SPACER TYPE=...>
155{
159 { nullptr, 0 }
160};
161
163{
165}
166
168{
170 // HTML import into Writer, avoid loading the Writer/Web template.
171 return OUString();
172
173 static const OUStringLiteral sTemplateWithoutExt(u"internal/html");
174 SvtPathOptions aPathOpt;
175
176 // first search for OpenDocument Writer/Web template
177 // OpenDocument Writer/Web template (extension .oth)
178 OUString sTemplate( sTemplateWithoutExt + ".oth" );
179 if (aPathOpt.SearchFile( sTemplate, SvtPathOptions::Paths::Template ))
180 return sTemplate;
181
182 // no OpenDocument Writer/Web template found.
183 // search for OpenOffice.org Writer/Web template
184 sTemplate = sTemplateWithoutExt + ".stw";
185 if (aPathOpt.SearchFile( sTemplate, SvtPathOptions::Paths::Template ))
186 return sTemplate;
187
188 OSL_ENSURE( false, "The default HTML template cannot be found in the defined template directories!");
189
190 return OUString();
191}
192
194{
195 OSL_ENSURE( m_pMedium, "Where is the medium??" );
196
197 if( m_pMedium->IsRemote() || !m_pMedium->IsStorage() )
198 {
200 return true;
201 }
202 return false;
203
204}
205
206// Call for the general Reader-Interface
207ErrCode HTMLReader::Read( SwDoc &rDoc, const OUString& rBaseURL, SwPaM &rPam, const OUString & rName )
208{
210
211 if( !m_pStream )
212 {
213 OSL_ENSURE( m_pStream, "HTML-Read without stream" );
214 return ERR_SWG_READ_ERROR;
215 }
216
217 if( !m_bInsertMode )
218 {
220
221 // Set the HTML page style, when it isn't a HTML document,
222 // otherwise it's already set.
224 {
227 }
228 }
229
230 // so nobody steals the document!
231 rtl::Reference<SwDoc> xHoldAlive(&rDoc);
232 ErrCode nRet = ERRCODE_NONE;
233 tools::SvRef<SwHTMLParser> xParser = new SwHTMLParser( &rDoc, rPam, *m_pStream,
234 rName, rBaseURL, !m_bInsertMode, m_pMedium,
235 IsReadUTF8(),
237
238 SvParserState eState = xParser->CallParser();
239
240 if( SvParserState::Pending == eState )
242 else if( SvParserState::Accepted != eState )
243 {
244 const OUString sErr(OUString::number(static_cast<sal_Int32>(xParser->GetLineNr()))
245 + "," + OUString::number(static_cast<sal_Int32>(xParser->GetLinePos())));
246
247 // use the stream as transport for error number
248 nRet = *new StringErrorInfo( ERR_FORMAT_ROWCOL, sErr,
249 DialogMask::ButtonsOk | DialogMask::MessageError );
250 }
251
252 return nRet;
253}
254
256 OUString aPath,
257 OUString aBaseURL,
258 bool bReadNewDoc,
259 SfxMedium* pMed, bool bReadUTF8,
260 bool bNoHTMLComments,
261 const OUString& rNamespace )
262 : SfxHTMLParser( rIn, bReadNewDoc, pMed ),
263 m_aPathToFile(std::move( aPath )),
264 m_sBaseURL(std::move( aBaseURL )),
265 m_xAttrTab(std::make_shared<HTMLAttrTable>()),
266 m_pNumRuleInfo( new SwHTMLNumRuleInfo ),
267 m_xDoc( pD ),
268 m_pActionViewShell( nullptr ),
269 m_pSttNdIdx( nullptr ),
270 m_pFormImpl( nullptr ),
271 m_pImageMap( nullptr ),
272 m_nBaseFontStMin( 0 ),
273 m_nFontStMin( 0 ),
274 m_nDefListDeep( 0 ),
275 m_nFontStHeadStart( 0 ),
276 m_nSBModuleCnt( 0 ),
277 m_nMissingImgMaps( 0 ),
278 m_nParaCnt( 5 ),
279 // #i83625#
280 m_nContextStMin( 0 ),
281 m_nContextStAttrMin( 0 ),
282 m_nSelectEntryCnt( 0 ),
283 m_nOpenParaToken( HtmlTokenId::NONE ),
284 m_eJumpTo( JumpToMarks::NONE ),
285#ifdef DBG_UTIL
286 m_nContinue( 0 ),
287#endif
288 m_eParaAdjust( SvxAdjust::End ),
289 m_bDocInitialized( false ),
290 m_bSetModEnabled( false ),
291 m_bInFloatingFrame( false ),
292 m_bInField( false ),
293 m_bKeepUnknown( false ),
294 m_bCallNextToken( false ),
295 m_bIgnoreRawData( false ),
296 m_bLBEntrySelected ( false ),
297 m_bTAIgnoreNewPara ( false ),
298 m_bFixMarqueeWidth ( false ),
299 m_bNoParSpace( false ),
300 m_bInNoEmbed( false ),
301 m_bInTitle( false ),
302 m_bUpdateDocStat( false ),
303 m_bFixSelectWidth( false ),
304 m_bTextArea( false ),
305 m_bSelect( false ),
306 m_bInFootEndNoteAnchor( false ),
307 m_bInFootEndNoteSymbol( false ),
308 m_bIgnoreHTMLComments( bNoHTMLComments ),
309 m_bRemoveHidden( false ),
310 m_bBodySeen( false ),
311 m_bReadingHeaderOrFooter( false ),
312 m_bNotifyMacroEventRead( false ),
313 m_bFuzzing(utl::ConfigManager::IsFuzzing()),
314 m_isInTableStructure(false),
315 m_nTableDepth( 0 ),
316 m_nFloatingFrames( 0 ),
317 m_nListItems( 0 ),
318 m_pTempViewFrame(nullptr)
319{
320 // If requested explicitly, then force ignoring of comments (don't create postits for them).
321 if (!m_bFuzzing)
322 {
326 }
327
328 m_nEventId = nullptr;
330
331 m_eScriptLang = HTMLScriptLanguage::Unknown;
332
333 rCursor.DeleteMark();
334 m_pPam = &rCursor; // re-use existing cursor: avoids spurious ~SwContentIndexReg assert
335 memset(m_xAttrTab.get(), 0, sizeof(HTMLAttrTable));
336
337 // Read the font sizes 1-7 from the INI file
338 if (!m_bFuzzing)
339 {
347 }
348 else
349 {
351 m_aFontHeights[4] = m_aFontHeights[5] = m_aFontHeights[6] = 12 * 20;
352 }
353
354 if(bReadNewDoc)
355 {
356 //CJK has different defaults, so a different object should be used for this
357 //RES_CHARTR_CJK_FONTSIZE is a valid value
359 m_xDoc->SetDefault( aFontHeight );
361 m_xDoc->SetDefault( aFontHeightCJK );
363 m_xDoc->SetDefault( aFontHeightCTL );
364
365 // #i18732# - adjust default of option 'FollowTextFlow'
366 // TODO: not sure what the appropriate default for HTML should be?
367 m_xDoc->SetDefault( SwFormatFollowTextFlow(true) );
368 }
369
370 // Change to HTML mode during the import, so that the right styles are created
371 m_bOldIsHTMLMode = m_xDoc->getIDocumentSettingAccess().get(DocumentSettingId::HTML_MODE);
372 m_xDoc->getIDocumentSettingAccess().set(DocumentSettingId::HTML_MODE, true);
373
374 m_pCSS1Parser.reset(new SwCSS1Parser(m_xDoc.get(), *this, m_aFontHeights, m_sBaseURL, IsNewDoc()));
375 if (!m_bFuzzing)
377
378 if( bReadUTF8 )
379 {
380 SetSrcEncoding( RTL_TEXTENCODING_UTF8 );
381 }
382 else
383 {
384 SwDocShell *pDocSh = m_xDoc->GetDocShell();
385 SvKeyValueIterator *pHeaderAttrs =
386 pDocSh->GetHeaderAttributes();
387 if( pHeaderAttrs )
388 SetEncodingByHTTPHeader( pHeaderAttrs );
389 }
390 m_pCSS1Parser->SetDfltEncoding( osl_getThreadTextEncoding() );
391
392 SwDocShell* pDocSh = m_xDoc->GetDocShell();
393 if( pDocSh )
394 {
395 m_bViewCreated = true; // not, load synchronous
396
397 // a jump mark is present
398
399 if( pMed )
400 {
401 m_sJmpMark = pMed->GetURLObject().GetMark();
402 if( !m_sJmpMark.isEmpty() )
403 {
405 sal_Int32 nLastPos = m_sJmpMark.lastIndexOf( cMarkSeparator );
406 sal_Int32 nPos = nLastPos != -1 ? nLastPos : 0;
407
408 OUString sCmp;
409 if (nPos)
410 {
411 sCmp = m_sJmpMark.copy(nPos + 1).replaceAll(" ", "");
412 }
413
414 if( !sCmp.isEmpty() )
415 {
416 sCmp = sCmp.toAsciiLowerCase();
417 if( sCmp == "region" )
419 else if( sCmp == "table" )
421 else if( sCmp == "graphic" )
423 else if( sCmp == "outline" ||
424 sCmp == "text" ||
425 sCmp == "frame" )
426 m_eJumpTo = JumpToMarks::NONE; // this is nothing valid!
427 else
428 // otherwise this is a normal (book)mark
429 nPos = -1;
430 }
431 else
432 nPos = -1;
433
434 if( nPos != -1 )
435 m_sJmpMark = m_sJmpMark.copy( 0, nPos );
436 if( m_sJmpMark.isEmpty() )
438 }
439 }
440 }
441
442 if (!rNamespace.isEmpty())
443 {
444 SetNamespace(rNamespace);
445 m_bXHTML = true;
446 if (rNamespace == "reqif-xhtml")
447 m_bReqIF = true;
448 }
449
450 // Extract load parameters which are specific to this filter.
451 if (!pMed)
452 {
453 return;
454 }
455
456 comphelper::SequenceAsHashMap aLoadMap(pMed->GetArgs());
457 auto it = aLoadMap.find("AllowedRTFOLEMimeTypes");
458 if (it == aLoadMap.end())
459 {
460 return;
461 }
462
463 uno::Sequence<OUString> aTypes;
464 it->second >>= aTypes;
465 m_aAllowedRTFOLEMimeTypes = comphelper::sequenceToContainer<std::set<OUString>>(aTypes);
466}
467
469{
470#ifdef DBG_UTIL
471 OSL_ENSURE( !m_nContinue, "DTOR in continue!" );
472#endif
473
474 OSL_ENSURE(m_aContexts.empty(), "There are still contexts on the stack");
475 OSL_ENSURE(!m_nContextStMin, "There are protected contexts");
476 m_nContextStMin = 0;
477 while (!m_aContexts.empty())
478 {
479 std::unique_ptr<HTMLAttrContext> xCntxt(PopContext());
480 ClearContext(xCntxt.get());
481 }
482
483 bool bAsync = m_xDoc->IsInLoadAsynchron();
484 m_xDoc->SetInLoadAsynchron( false );
485 m_xDoc->getIDocumentSettingAccess().set(DocumentSettingId::HTML_MODE, m_bOldIsHTMLMode);
486
487 if( m_xDoc->GetDocShell() && m_nEventId )
489
490 // the DocumentDetected maybe can delete the DocShells, therefore fetch again
491 if( m_xDoc->GetDocShell() )
492 {
493 // update linked sections
494 sal_uInt16 nLinkMode = m_xDoc->getIDocumentSettingAccess().getLinkUpdateMode( true );
495 if( nLinkMode != NEVER && bAsync &&
496 SfxObjectCreateMode::INTERNAL!=m_xDoc->GetDocShell()->GetCreateMode() )
497 m_xDoc->getIDocumentLinksAdministration().GetLinkManager().UpdateAllLinks( nLinkMode == MANUAL, false, nullptr );
498
499 if ( m_xDoc->GetDocShell()->IsLoading() )
500 {
501 // #i59688#
502 m_xDoc->GetDocShell()->LoadingFinished();
503 }
504 }
505
506 delete m_pSttNdIdx;
507
508 if( !m_aSetAttrTab.empty() )
509 {
510 OSL_ENSURE( m_aSetAttrTab.empty(),"There are still attributes on the stack" );
511 for ( const auto& rpAttr : m_aSetAttrTab )
512 delete rpAttr;
513 m_aSetAttrTab.clear();
514 }
515
516 m_pCSS1Parser.reset();
517 m_pNumRuleInfo.reset();
519 m_pFootEndNoteImpl.reset();
520
521 OSL_ENSURE(!m_xTable, "It exists still an open table");
522 m_pImageMaps.reset();
523
524 OSL_ENSURE( m_vPendingStack.empty(),
525 "SwHTMLParser::~SwHTMLParser: Here should not be Pending-Stack anymore" );
526 m_vPendingStack.clear();
527
528 m_xDoc.clear();
529
530 if ( m_pTempViewFrame )
531 {
533
534 // the temporary view frame is hidden, so the hidden flag might need to be removed
535 if ( m_bRemoveHidden && m_xDoc.is() && m_xDoc->GetDocShell() && m_xDoc->GetDocShell()->GetMedium() )
536 m_xDoc->GetDocShell()->GetMedium()->GetItemSet()->ClearItem( SID_HIDDEN );
537 }
538}
539
540IMPL_LINK_NOARG( SwHTMLParser, AsyncCallback, void*, void )
541{
542 m_nEventId=nullptr;
543
544 // #i47907# - If the document has already been destructed,
545 // the parser should be aware of this:
546 if( ( m_xDoc->GetDocShell() && m_xDoc->GetDocShell()->IsAbortingImport() )
547 || 1 == m_xDoc->getReferenceCount() )
548 {
549 // was the import aborted by SFX?
550 eState = SvParserState::Error;
551 }
552
553 GetAsynchCallLink().Call(nullptr);
554}
555
557{
558 // create temporary index on position 0, so it won't be moved!
559 m_pSttNdIdx = new SwNodeIndex( m_xDoc->GetNodes() );
560 if( !IsNewDoc() ) // insert into existing document ?
561 {
562 const SwPosition* pPos = m_pPam->GetPoint();
563
564 m_xDoc->getIDocumentContentOperations().SplitNode( *pPos, false );
565
566 *m_pSttNdIdx = pPos->GetNodeIndex()-1;
567 m_xDoc->getIDocumentContentOperations().SplitNode( *pPos, false );
568
569 SwPaM aInsertionRangePam( *pPos );
570
572
573 // split any redline over the insertion point
574 aInsertionRangePam.SetMark();
575 *aInsertionRangePam.GetPoint() = *m_pPam->GetPoint();
576 aInsertionRangePam.Move( fnMoveBackward );
577 m_xDoc->getIDocumentRedlineAccess().SplitRedline( aInsertionRangePam );
578
579 m_xDoc->SetTextFormatColl( *m_pPam,
580 m_pCSS1Parser->GetTextCollFromPool( RES_POOLCOLL_STANDARD ));
581 }
582
583 if( GetMedium() )
584 {
585 if( !m_bViewCreated )
586 {
587 m_nEventId = Application::PostUserEvent( LINK( this, SwHTMLParser, AsyncCallback ) );
588 }
589 else
590 {
591 m_bViewCreated = true;
592 m_nEventId = nullptr;
593 }
594 }
595 else // show progress bar
596 {
597 rInput.Seek(STREAM_SEEK_TO_END);
598 rInput.ResetError();
599
600 m_xProgress.reset(new ImportProgress(m_xDoc->GetDocShell(), 0, rInput.Tell()));
601
602 rInput.Seek(STREAM_SEEK_TO_BEGIN);
603 rInput.ResetError();
604 }
605
606 StartListening(m_xDoc->GetPageDesc( 0 ).GetNotifier());
607
609 return eRet;
610}
611
613{
614 const SwNode *pPrev = m_xDoc->GetNodes()[nNodeIdx - 1];
615 return pPrev->IsContentNode() || (pPrev->IsEndNode() && pPrev->StartOfSectionNode()->IsSectionNode());
616}
617
619{
620#ifdef DBG_UTIL
621 OSL_ENSURE(!m_nContinue, "Continue in Continue - not supposed to happen");
622 m_nContinue++;
623#endif
624
625 // When the import (of SFX) is aborted, an error will be set but
626 // we still continue, so that we clean up properly.
627 OSL_ENSURE( SvParserState::Error!=eState,
628 "SwHTMLParser::Continue: already set an error" );
629 if( m_xDoc->GetDocShell() && m_xDoc->GetDocShell()->IsAbortingImport() )
630 eState = SvParserState::Error;
631
632 // Fetch SwViewShell from document, save it and set as current.
633 SwViewShell *pInitVSh = CallStartAction();
634
635 if( SvParserState::Error != eState && GetMedium() && !m_bViewCreated )
636 {
637 // At first call first return, show document and wait for callback
638 // time.
639 // At this point in CallParser only one digit was read and
640 // a SaveState(0) was called.
641 eState = SvParserState::Pending;
642 m_bViewCreated = true;
643 m_xDoc->SetInLoadAsynchron( true );
644
645#ifdef DBG_UTIL
646 m_nContinue--;
647#endif
648
649 return;
650 }
651
652 m_bSetModEnabled = false;
653 if( m_xDoc->GetDocShell() )
654 {
655 m_bSetModEnabled = m_xDoc->GetDocShell()->IsEnableSetModified();
656 if( m_bSetModEnabled )
657 {
658 m_xDoc->GetDocShell()->EnableSetModified( false );
659 }
660 }
661
662 // during import don't call OLE-Modified
663 Link<bool,void> aOLELink( m_xDoc->GetOle2Link() );
664 m_xDoc->SetOle2Link( Link<bool,void>() );
665
666 bool bModified = m_xDoc->getIDocumentState().IsModified();
667 bool const bWasUndo = m_xDoc->GetIDocumentUndoRedo().DoesUndo();
668 m_xDoc->GetIDocumentUndoRedo().DoUndo(false);
669
670 // When the import will be aborted, don't call Continue anymore.
671 // If a Pending-Stack exists make sure the stack is ended with a call
672 // of NextToken.
673 if( SvParserState::Error == eState )
674 {
675 OSL_ENSURE( m_vPendingStack.empty() || m_vPendingStack.back().nToken != HtmlTokenId::NONE,
676 "SwHTMLParser::Continue: Pending-Stack without Token" );
677 if( !m_vPendingStack.empty() && m_vPendingStack.back().nToken != HtmlTokenId::NONE )
678 NextToken( m_vPendingStack.back().nToken );
679 OSL_ENSURE( m_vPendingStack.empty(),
680 "SwHTMLParser::Continue: There is again a Pending-Stack" );
681 }
682 else
683 {
684 HTMLParser::Continue( !m_vPendingStack.empty() ? m_vPendingStack.back().nToken : nToken );
685 }
686
687 // disable progress bar again
688 m_xProgress.reset();
689
690 bool bLFStripped = false;
691 if( SvParserState::Pending != GetStatus() )
692 {
693 // set the last attributes yet
694 {
695 if( !m_aScriptSource.isEmpty() )
696 {
697 SwScriptFieldType *pType =
698 static_cast<SwScriptFieldType*>(m_xDoc->getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::Script ));
699
701 false );
702 InsertAttr( SwFormatField( aField ), false );
703 }
704
705 if( m_pAppletImpl )
706 {
707 if( m_pAppletImpl->GetApplet().is() )
708 EndApplet();
709 else
710 EndObject();
711 }
712
713 // maybe remove an existing LF after the last paragraph
714 if( IsNewDoc() )
715 bLFStripped = StripTrailingLF() > 0;
716
717 // close still open numbering
718 while( GetNumInfo().GetNumRule() )
720
721 OSL_ENSURE( !m_nContextStMin, "There are protected contexts" );
722 // try this twice, first normally to let m_nContextStMin decrease
723 // naturally and get contexts popped in desired order, and if that
724 // fails force it
725 for (int i = 0; i < 2; ++i)
726 {
727 while (m_aContexts.size() > m_nContextStMin)
728 {
729 std::unique_ptr<HTMLAttrContext> xCntxt(PopContext());
730 if (xCntxt)
731 EndContext(xCntxt.get());
732 }
733 if (!m_nContextStMin)
734 break;
735 OSL_ENSURE(!m_nContextStMin, "There are still protected contexts");
736 m_nContextStMin = 0;
737 }
738
739 m_aParaAttrs.clear();
740
741 SetAttr( false );
742
743 // set the first delayed styles
744 m_pCSS1Parser->SetDelayedStyles();
745 }
746
747 // again correct the start
748 if( !IsNewDoc() && m_pSttNdIdx->GetIndex() )
749 {
750 SwTextNode* pTextNode = m_pSttNdIdx->GetNode().GetTextNode();
751 SwNodeIndex aNxtIdx( *m_pSttNdIdx );
752 if( pTextNode && pTextNode->CanJoinNext( &aNxtIdx ))
753 {
754 const sal_Int32 nStt = pTextNode->GetText().getLength();
755 // when the cursor is still in the node, then set him at the end
756 if( m_pPam->GetPoint()->GetNode() == aNxtIdx.GetNode() )
757 {
758 m_pPam->GetPoint()->Assign( *pTextNode, nStt );
759 }
760
761#if OSL_DEBUG_LEVEL > 0
762// !!! shouldn't be possible, or ??
763 OSL_ENSURE( m_pSttNdIdx->GetIndex()+1 != m_pPam->GetBound().GetNodeIndex(),
764 "Pam.Bound1 is still in the node" );
765 OSL_ENSURE( m_pSttNdIdx->GetIndex()+1 != m_pPam->GetBound( false ).GetNodeIndex(),
766 "Pam.Bound2 is still in the node" );
767
769 {
770 const sal_Int32 nCntPos = m_pPam->GetBound().GetContentIndex();
772 pTextNode->GetText().getLength() + nCntPos );
773 }
774 if( m_pSttNdIdx->GetIndex()+1 == m_pPam->GetBound( false ).GetNodeIndex() )
775 {
776 const sal_Int32 nCntPos = m_pPam->GetBound( false ).GetContentIndex();
777 m_pPam->GetBound( false ).SetContent(
778 pTextNode->GetText().getLength() + nCntPos );
779 }
780#endif
781 // Keep character attribute!
782 SwTextNode* pDelNd = aNxtIdx.GetNode().GetTextNode();
783 if (pTextNode->GetText().getLength())
784 pDelNd->FormatToTextAttr( pTextNode );
785 else
786 pTextNode->ChgFormatColl( pDelNd->GetTextColl() );
787 pTextNode->JoinNext();
788 }
789 }
790 }
791
792 if( SvParserState::Accepted == eState )
793 {
795 {
796 // Some Image-Map relations are still missing.
797 // Maybe now the Image-Maps are there?
799 }
800
801 // now remove the last useless paragraph
802 SwPosition* pPos = m_pPam->GetPoint();
803 if( !pPos->GetContentIndex() && !bLFStripped )
804 {
805 SwTextNode* pCurrentNd;
806 SwNodeOffset nNodeIdx = pPos->GetNodeIndex();
807
808 bool bHasFlysOrMarks =
810
811 if( IsNewDoc() )
812 {
813 if (!m_pPam->GetPoint()->GetContentIndex() && CanRemoveNode(nNodeIdx))
814 {
816 if( pCNd && pCNd->StartOfSectionIndex()+2 <
817 pCNd->EndOfSectionIndex() && !bHasFlysOrMarks )
818 {
820 SwCursorShell *pCursorSh = dynamic_cast<SwCursorShell *>( pVSh );
821 if( pCursorSh &&
822 pCursorSh->GetCursor()->GetPoint()
823 ->GetNodeIndex() == nNodeIdx )
824 {
825 pCursorSh->MovePara(GoPrevPara, fnParaEnd );
826 pCursorSh->SetMark();
827 pCursorSh->ClearMark();
828 }
829 SwNode& rDelNode = m_pPam->GetPoint()->GetNode();
830 // move so we don't have a dangling SwContentIndex to the deleted node
832 if (m_pPam->HasMark())
834 m_xDoc->GetNodes().Delete( rDelNode );
835 }
836 }
837 }
838 else if( nullptr != ( pCurrentNd = m_xDoc->GetNodes()[ nNodeIdx ]->GetTextNode()) && !bHasFlysOrMarks )
839 {
840 if( pCurrentNd->CanJoinNext( pPos ))
841 {
842 SwTextNode* pNextNd = pPos->GetNode().GetTextNode();
844 pNextNd->JoinPrev();
845 }
846 else if (pCurrentNd->GetText().isEmpty())
847 {
849 SwNode& rDelNode = pPos->GetNode();
850 // move so we don't have a dangling SwContentIndex to the deleted node
852 m_xDoc->GetNodes().Delete( rDelNode );
854 }
855 }
856 }
857
858 // annul the SplitNode from the beginning
859 else if( !IsNewDoc() )
860 {
861 if( pPos->GetContentIndex() ) // then there was no <p> at the end
862 m_pPam->Move( fnMoveForward, GoInNode ); // therefore to the next
863 SwTextNode* pTextNode = pPos->GetNode().GetTextNode();
864 SwNodeIndex aPrvIdx( pPos->GetNode() );
865 if( pTextNode && pTextNode->CanJoinPrev( &aPrvIdx ) &&
866 *m_pSttNdIdx <= aPrvIdx )
867 {
868 // Normally here should take place a JoinNext, but all cursors and
869 // so are registered in pTextNode, so that it MUST remain.
870
871 // Convert paragraph to character attribute, from Prev adopt
872 // the paragraph attribute and the template!
873 SwTextNode* pPrev = aPrvIdx.GetNode().GetTextNode();
874 pTextNode->ChgFormatColl( pPrev->GetTextColl() );
875 pTextNode->FormatToTextAttr( pPrev );
876 pTextNode->ResetAllAttr();
877
878 if( pPrev->HasSwAttrSet() )
879 pTextNode->SetAttr( *pPrev->GetpSwAttrSet() );
880
881 if( &m_pPam->GetBound().GetNode() == pPrev )
882 m_pPam->GetBound().nContent.Assign( pTextNode, 0 );
883 if( &m_pPam->GetBound(false).GetNode() == pPrev )
884 m_pPam->GetBound(false).nContent.Assign( pTextNode, 0 );
885
886 pTextNode->JoinPrev();
887 }
888 }
889
890 // adjust AutoLoad in DocumentProperties
891 if (!m_bFuzzing && IsNewDoc())
892 {
893 SwDocShell *pDocShell(m_xDoc->GetDocShell());
894 OSL_ENSURE(pDocShell, "no SwDocShell");
895 if (pDocShell) {
896 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
897 pDocShell->GetModel(), uno::UNO_QUERY_THROW);
898 uno::Reference<document::XDocumentProperties> xDocProps(
899 xDPS->getDocumentProperties());
900 OSL_ENSURE(xDocProps.is(), "DocumentProperties is null");
901 if ( xDocProps.is() && (xDocProps->getAutoloadSecs() > 0) &&
902 (xDocProps->getAutoloadURL().isEmpty()) )
903 {
904 xDocProps->setAutoloadURL(m_aPathToFile);
905 }
906 }
907 }
908
909 if( m_bUpdateDocStat )
910 {
911 m_xDoc->getIDocumentStatistics().UpdateDocStat( false, true );
912 }
913 }
914
915 if( SvParserState::Pending != GetStatus() )
916 {
917 delete m_pSttNdIdx;
918 m_pSttNdIdx = nullptr;
919 }
920
921 // should the parser be the last one who hold the document, then nothing
922 // has to be done anymore, document will be destroyed shortly!
923 if( 1 < m_xDoc->getReferenceCount() )
924 {
925 if( bWasUndo )
926 {
927 m_xDoc->GetIDocumentUndoRedo().DelAllUndoObj();
928 m_xDoc->GetIDocumentUndoRedo().DoUndo(true);
929 }
930 else if( !pInitVSh )
931 {
932 // When at the beginning of Continue no Shell was available,
933 // it's possible in the meantime one was created.
934 // In that case the bWasUndo flag is wrong and we must
935 // enable Undo.
937 if( pTmpVSh )
938 {
939 m_xDoc->GetIDocumentUndoRedo().DoUndo(true);
940 }
941 }
942
943 m_xDoc->SetOle2Link( aOLELink );
944 if( !bModified )
945 m_xDoc->getIDocumentState().ResetModified();
946 if( m_bSetModEnabled && m_xDoc->GetDocShell() )
947 {
948 m_xDoc->GetDocShell()->EnableSetModified();
949 m_bSetModEnabled = false; // this is unnecessary here
950 }
951 }
952
953 // When the Document-SwVievShell still exists and an Action is open
954 // (doesn't have to be by abort), end the Action, disconnect from Shell
955 // and finally reconstruct the old Shell.
956 CallEndAction( true );
957
958#ifdef DBG_UTIL
959 m_nContinue--;
960#endif
961}
962
964{
965 if(rHint.GetId() == SfxHintId::Dying)
966 {
968 ReleaseRef();
969 }
970}
971
973{
974 OSL_ENSURE( !m_bDocInitialized, "DocumentDetected called multiple times" );
975 m_bDocInitialized = true;
976 if( IsNewDoc() )
977 {
978 if( IsInHeader() )
979 FinishHeader();
980
981 CallEndAction( true );
982
983 m_xDoc->GetIDocumentUndoRedo().DoUndo(false);
984 // For DocumentDetected in general a SwViewShell is created.
985 // But it also can be created later, in case the UI is captured.
987 }
988}
989
990// is called for every token that is recognised in CallParser
992{
993 if( ( m_xDoc->GetDocShell() && m_xDoc->GetDocShell()->IsAbortingImport() )
994 || 1 == m_xDoc->getReferenceCount() )
995 {
996 // Was the import cancelled by SFX? If a pending stack
997 // exists, clean it.
998 eState = SvParserState::Error;
999 OSL_ENSURE( m_vPendingStack.empty() || m_vPendingStack.back().nToken != HtmlTokenId::NONE,
1000 "SwHTMLParser::NextToken: Pending-Stack without token" );
1001 if( 1 == m_xDoc->getReferenceCount() || m_vPendingStack.empty() )
1002 return ;
1003 }
1004
1005#if OSL_DEBUG_LEVEL > 0
1006 if( !m_vPendingStack.empty() )
1007 {
1008 switch( nToken )
1009 {
1010 // tables are read by recursive method calls
1011 case HtmlTokenId::TABLE_ON:
1012 // For CSS declarations we might have to wait
1013 // for a file download to finish
1014 case HtmlTokenId::LINK:
1015 // For controls we might have to set the size.
1016 case HtmlTokenId::INPUT:
1017 case HtmlTokenId::TEXTAREA_ON:
1018 case HtmlTokenId::SELECT_ON:
1019 case HtmlTokenId::SELECT_OFF:
1020 break;
1021 default:
1022 OSL_ENSURE( m_vPendingStack.empty(), "Unknown token for Pending-Stack" );
1023 break;
1024 }
1025 }
1026#endif
1027
1028 // The following special cases have to be treated before the
1029 // filter detection, because Netscape doesn't reference the content
1030 // of the title for filter detection either.
1031 if( m_vPendingStack.empty() )
1032 {
1033 if( m_bInTitle )
1034 {
1035 switch( nToken )
1036 {
1037 case HtmlTokenId::TITLE_OFF:
1038 {
1039 OUString sTitle = m_sTitle.makeStringAndClear();
1040 if( IsNewDoc() && !sTitle.isEmpty() )
1041 {
1042 if( m_xDoc->GetDocShell() ) {
1043 uno::Reference<document::XDocumentPropertiesSupplier>
1044 xDPS(m_xDoc->GetDocShell()->GetModel(),
1045 uno::UNO_QUERY_THROW);
1046 uno::Reference<document::XDocumentProperties> xDocProps(
1047 xDPS->getDocumentProperties());
1048 OSL_ENSURE(xDocProps.is(), "no DocumentProperties");
1049 if (xDocProps.is()) {
1050 xDocProps->setTitle(sTitle);
1051 }
1052
1053 m_xDoc->GetDocShell()->SetTitle(sTitle);
1054 }
1055 }
1056 m_bInTitle = false;
1057 break;
1058 }
1059
1060 case HtmlTokenId::NONBREAKSPACE:
1061 m_sTitle.append(" ");
1062 break;
1063
1064 case HtmlTokenId::SOFTHYPH:
1065 m_sTitle.append("-");
1066 break;
1067
1068 case HtmlTokenId::TEXTTOKEN:
1069 m_sTitle.append(aToken);
1070 break;
1071
1072 default:
1073 m_sTitle.append("<");
1074 if( (nToken >= HtmlTokenId::ONOFF_START) && isOffToken(nToken) )
1075 m_sTitle.append("/");
1076 m_sTitle.append(sSaveToken);
1077 if( !aToken.isEmpty() )
1078 {
1079 m_sTitle.append(" ");
1080 m_sTitle.append(aToken);
1081 }
1082 m_sTitle.append(">");
1083 break;
1084 }
1085
1086 return;
1087 }
1088 }
1089
1090 // Find out what type of document it is if we don't know already.
1091 // For Controls this has to be finished before the control is inserted
1092 // because for inserting a View is needed.
1093 if( !m_bDocInitialized )
1095
1096 bool bGetIDOption = false, bInsertUnknown = false;
1097 bool bUpperSpaceSave = m_bUpperSpace;
1098 m_bUpperSpace = false;
1099
1100 // The following special cases may or have to be treated after the
1101 // filter detection
1102 if( m_vPendingStack.empty() )
1103 {
1104 if( m_bInFloatingFrame )
1105 {
1106 // <SCRIPT> is ignored here (from us), because it is ignored in
1107 // Applets as well
1108 if( HtmlTokenId::IFRAME_OFF == nToken )
1109 {
1110 m_bCallNextToken = false;
1111 m_bInFloatingFrame = false;
1112 }
1113
1114 return;
1115 }
1116 else if( m_bInNoEmbed )
1117 {
1118 switch( nToken )
1119 {
1120 case HtmlTokenId::NOEMBED_OFF:
1123 m_aContents.clear();
1124 m_bCallNextToken = false;
1125 m_bInNoEmbed = false;
1126 break;
1127
1128 case HtmlTokenId::RAWDATA:
1130 break;
1131
1132 default:
1133 OSL_ENSURE( false, "SwHTMLParser::NextToken: invalid tag" );
1134 break;
1135 }
1136
1137 return;
1138 }
1139 else if( m_pAppletImpl )
1140 {
1141 // in an applet only <PARAM> tags and the </APPLET> tag
1142 // are of interest for us (for the moment)
1143 // <SCRIPT> is ignored here (from Netscape)!
1144
1145 switch( nToken )
1146 {
1147 case HtmlTokenId::APPLET_OFF:
1148 m_bCallNextToken = false;
1149 EndApplet();
1150 break;
1151 case HtmlTokenId::OBJECT_OFF:
1152 m_bCallNextToken = false;
1153 EndObject();
1154 break;
1155 case HtmlTokenId::PARAM:
1156 InsertParam();
1157 break;
1158 default: break;
1159 }
1160
1161 return;
1162 }
1163 else if( m_bTextArea )
1164 {
1165 // in a TextArea everything up to </TEXTAREA> is inserted as text.
1166 // <SCRIPT> is ignored here (from Netscape)!
1167
1168 switch( nToken )
1169 {
1170 case HtmlTokenId::TEXTAREA_OFF:
1171 m_bCallNextToken = false;
1172 EndTextArea();
1173 break;
1174
1175 default:
1177 break;
1178 }
1179
1180 return;
1181 }
1182 else if( m_bSelect )
1183 {
1184 // HAS to be treated after bNoScript!
1185 switch( nToken )
1186 {
1187 case HtmlTokenId::SELECT_OFF:
1188 m_bCallNextToken = false;
1189 EndSelect();
1190 return;
1191
1192 case HtmlTokenId::OPTION:
1194 return;
1195
1196 case HtmlTokenId::TEXTTOKEN:
1198 return;
1199
1200 case HtmlTokenId::INPUT:
1201 case HtmlTokenId::SCRIPT_ON:
1202 case HtmlTokenId::SCRIPT_OFF:
1203 case HtmlTokenId::NOSCRIPT_ON:
1204 case HtmlTokenId::NOSCRIPT_OFF:
1205 case HtmlTokenId::RAWDATA:
1206 // treat in normal switch
1207 break;
1208
1209 default:
1210 // ignore
1211 return;
1212 }
1213 }
1214 else if( m_pMarquee )
1215 {
1216 // in a TextArea everything up to </TEXTAREA> is inserted as text.
1217 // The <SCRIPT> tags are ignored from MS-IE, we ignore the whole
1218 // script.
1219 switch( nToken )
1220 {
1221 case HtmlTokenId::MARQUEE_OFF:
1222 m_bCallNextToken = false;
1223 EndMarquee();
1224 break;
1225
1226 case HtmlTokenId::TEXTTOKEN:
1228 break;
1229 default: break;
1230 }
1231
1232 return;
1233 }
1234 else if( m_bInField )
1235 {
1236 switch( nToken )
1237 {
1238 case HtmlTokenId::SDFIELD_OFF:
1239 m_bCallNextToken = false;
1240 EndField();
1241 break;
1242
1243 case HtmlTokenId::TEXTTOKEN:
1245 break;
1246 default: break;
1247 }
1248
1249 return;
1250 }
1252 {
1253 switch( nToken )
1254 {
1255 case HtmlTokenId::ANCHOR_OFF:
1256 EndAnchor();
1257 m_bCallNextToken = false;
1258 break;
1259
1260 case HtmlTokenId::TEXTTOKEN:
1262 break;
1263 default: break;
1264 }
1265 return;
1266 }
1267 else if( !m_aUnknownToken.isEmpty() )
1268 {
1269 // Paste content of unknown tags.
1270 // (but surely if we are not in the header section) fdo#36080 fdo#34666
1271 if (!aToken.isEmpty() && !IsInHeader() )
1272 {
1273 if( !m_bDocInitialized )
1275 m_xDoc->getIDocumentContentOperations().InsertString( *m_pPam, aToken.toString());
1276
1277 // if there are temporary paragraph attributes and the
1278 // paragraph isn't empty then the paragraph attributes
1279 // are final.
1280 m_aParaAttrs.clear();
1281
1282 SetAttr();
1283 }
1284
1285 // Unknown token in the header are only closed by a matching
1286 // end-token, </HEAD> or <BODY>. Text inside is ignored.
1287 switch( nToken )
1288 {
1289 case HtmlTokenId::UNKNOWNCONTROL_OFF:
1290 if( m_aUnknownToken != sSaveToken )
1291 return;
1292 [[fallthrough]];
1293 case HtmlTokenId::FRAMESET_ON:
1294 case HtmlTokenId::HEAD_OFF:
1295 case HtmlTokenId::BODY_ON:
1296 case HtmlTokenId::IMAGE: // Don't know why Netscape acts this way.
1297 m_aUnknownToken.clear();
1298 break;
1299 case HtmlTokenId::TEXTTOKEN:
1300 return;
1301 default:
1302 m_aUnknownToken.clear();
1303 break;
1304 }
1305 }
1306 }
1307
1308 switch( nToken )
1309 {
1310 case HtmlTokenId::BODY_ON:
1311 if (!m_bBodySeen)
1312 {
1313 m_bBodySeen = true;
1314 if( !m_aStyleSource.isEmpty() )
1315 {
1316 m_pCSS1Parser->ParseStyleSheet( m_aStyleSource );
1317 m_aStyleSource.clear();
1318 }
1319 if( IsNewDoc() )
1320 {
1322 // If there is a template for the first or the right page,
1323 // it is set here.
1324 const SwPageDesc *pPageDesc = nullptr;
1325 if( m_pCSS1Parser->IsSetFirstPageDesc() )
1326 pPageDesc = m_pCSS1Parser->GetFirstPageDesc();
1327 else if( m_pCSS1Parser->IsSetRightPageDesc() )
1328 pPageDesc = m_pCSS1Parser->GetRightPageDesc();
1329
1330 if( pPageDesc )
1331 {
1332 m_xDoc->getIDocumentContentOperations().InsertPoolItem( *m_pPam, SwFormatPageDesc( pPageDesc ) );
1333 }
1334 }
1335 }
1336 break;
1337
1338 case HtmlTokenId::LINK:
1339 InsertLink();
1340 break;
1341
1342 case HtmlTokenId::BASE:
1343 {
1344 const HTMLOptions& rHTMLOptions = GetOptions();
1345 for (size_t i = rHTMLOptions.size(); i; )
1346 {
1347 const HTMLOption& rOption = rHTMLOptions[--i];
1348 switch( rOption.GetToken() )
1349 {
1350 case HtmlOptionId::HREF:
1351 m_sBaseURL = rOption.GetString();
1352 break;
1353 case HtmlOptionId::TARGET:
1354 if( IsNewDoc() )
1355 {
1356 SwDocShell *pDocShell(m_xDoc->GetDocShell());
1357 OSL_ENSURE(pDocShell, "no SwDocShell");
1358 if (pDocShell) {
1359 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
1360 pDocShell->GetModel(), uno::UNO_QUERY_THROW);
1361 uno::Reference<document::XDocumentProperties>
1362 xDocProps(xDPS->getDocumentProperties());
1363 OSL_ENSURE(xDocProps.is(),"no DocumentProperties");
1364 if (xDocProps.is()) {
1365 xDocProps->setDefaultTarget(
1366 rOption.GetString());
1367 }
1368 }
1369 }
1370 break;
1371 default: break;
1372 }
1373 }
1374 }
1375 break;
1376
1377 case HtmlTokenId::META:
1378 {
1379 SvKeyValueIterator *pHTTPHeader = nullptr;
1380 if( IsNewDoc() )
1381 {
1382 SwDocShell *pDocSh = m_xDoc->GetDocShell();
1383 if( pDocSh )
1384 pHTTPHeader = pDocSh->GetHeaderAttributes();
1385 }
1386 SwDocShell *pDocShell(m_xDoc->GetDocShell());
1387 OSL_ENSURE(pDocShell, "no SwDocShell");
1388 if (pDocShell)
1389 {
1390 uno::Reference<document::XDocumentProperties> xDocProps;
1391 if (IsNewDoc())
1392 {
1393 const uno::Reference<document::XDocumentPropertiesSupplier>
1394 xDPS( pDocShell->GetModel(), uno::UNO_QUERY_THROW );
1395 xDocProps = xDPS->getDocumentProperties();
1396 OSL_ENSURE(xDocProps.is(), "DocumentProperties is null");
1397 }
1398 ParseMetaOptions( xDocProps, pHTTPHeader );
1399 }
1400 }
1401 break;
1402
1403 case HtmlTokenId::TITLE_ON:
1404 m_bInTitle = true;
1405 break;
1406
1407 case HtmlTokenId::SCRIPT_ON:
1408 NewScript();
1409 break;
1410
1411 case HtmlTokenId::SCRIPT_OFF:
1412 EndScript();
1413 break;
1414
1415 case HtmlTokenId::NOSCRIPT_ON:
1416 case HtmlTokenId::NOSCRIPT_OFF:
1417 bInsertUnknown = true;
1418 break;
1419
1420 case HtmlTokenId::STYLE_ON:
1421 NewStyle();
1422 break;
1423
1424 case HtmlTokenId::STYLE_OFF:
1425 EndStyle();
1426 break;
1427
1428 case HtmlTokenId::RAWDATA:
1429 if( !m_bIgnoreRawData )
1430 {
1431 if( IsReadScript() )
1432 {
1434 }
1435 else if( IsReadStyle() )
1436 {
1437 if( !m_aStyleSource.isEmpty() )
1438 m_aStyleSource += "\n";
1439 m_aStyleSource += aToken;
1440 }
1441 }
1442 break;
1443
1444 case HtmlTokenId::OBJECT_ON:
1445 if (m_bXHTML)
1446 {
1447 if (!InsertEmbed())
1448 InsertImage();
1449 break;
1450 }
1451#if HAVE_FEATURE_JAVA
1452 NewObject();
1454#endif
1455 break;
1456
1457 case HtmlTokenId::OBJECT_OFF:
1458 if (!m_aEmbeds.empty())
1459 m_aEmbeds.pop();
1460 break;
1461
1462 case HtmlTokenId::APPLET_ON:
1463#if HAVE_FEATURE_JAVA
1464 InsertApplet();
1466#endif
1467 break;
1468
1469 case HtmlTokenId::IFRAME_ON:
1470 if (m_bFuzzing && m_nFloatingFrames > 64)
1471 SAL_WARN("sw.html", "Not importing any more FloatingFrames for fuzzing performance");
1472 else
1473 {
1476 }
1477 break;
1478
1479 case HtmlTokenId::LINEBREAK:
1480 if( !IsReadPRE() )
1481 {
1483 break;
1484 }
1485 else
1486 bGetIDOption = true;
1487 // <BR>s in <PRE> resemble true LFs, hence no break
1488 [[fallthrough]];
1489
1490 case HtmlTokenId::NEWPARA:
1491 // CR in PRE/LISTING/XMP
1492 {
1493 if( HtmlTokenId::NEWPARA==nToken ||
1495 {
1496 AppendTextNode(); // there is no LF at this place
1497 // therefore it will cause no problems
1499 }
1500 // progress bar
1501 if (m_xProgress)
1502 m_xProgress->Update(rInput.Tell());
1503 }
1504 break;
1505
1506 case HtmlTokenId::NONBREAKSPACE:
1507 m_xDoc->getIDocumentContentOperations().InsertString( *m_pPam, OUString(CHAR_HARDBLANK) );
1508 break;
1509
1510 case HtmlTokenId::SOFTHYPH:
1511 m_xDoc->getIDocumentContentOperations().InsertString( *m_pPam, OUString(CHAR_SOFTHYPHEN) );
1512 break;
1513
1514 case HtmlTokenId::LINEFEEDCHAR:
1515 if( m_pPam->GetPoint()->GetContentIndex() )
1517 if (!m_xTable && !m_xDoc->IsInHeaderFooter(m_pPam->GetPoint()->GetNode()))
1518 {
1519 NewAttr(m_xAttrTab, &m_xAttrTab->pBreak, SvxFormatBreakItem(SvxBreak::PageBefore, RES_BREAK));
1520 EndAttr( m_xAttrTab->pBreak, false );
1521 }
1522 break;
1523
1524 case HtmlTokenId::TEXTTOKEN:
1525 case HtmlTokenId::CDATA:
1526 // insert string without spanning attributes at the end.
1527 if( !aToken.isEmpty() && ' '==aToken[0] && !IsReadPRE() )
1528 {
1529 sal_Int32 nPos = m_pPam->GetPoint()->GetContentIndex();
1530 const SwTextNode* pTextNode = nPos ? m_pPam->GetPoint()->GetNode().GetTextNode() : nullptr;
1531 if (pTextNode)
1532 {
1533 const OUString& rText = pTextNode->GetText();
1534 sal_Unicode cLast = rText[--nPos];
1535 if( ' ' == cLast || '\x0a' == cLast)
1536 aToken.remove(0, 1);
1537 }
1538 else
1539 aToken.remove(0, 1);
1540
1541 if( aToken.isEmpty() )
1542 {
1543 m_bUpperSpace = bUpperSpaceSave;
1544 break;
1545 }
1546 }
1547
1548 if( !aToken.isEmpty() )
1549 {
1550 if( !m_bDocInitialized )
1552
1553 if (!m_aEmbeds.empty())
1554 {
1555 // The text token is inside an OLE object, which means
1556 // alternate text.
1557 SwOLENode* pOLENode = m_aEmbeds.top();
1558 if (!pOLENode)
1559 {
1560 // <object> is mapped to an image -> ignore.
1561 break;
1562 }
1563
1564 if (SwFlyFrameFormat* pFormat
1565 = dynamic_cast<SwFlyFrameFormat*>(pOLENode->GetFlyFormat()))
1566 {
1568 {
1569 pObject->SetTitle(pObject->GetTitle() + aToken);
1570 break;
1571 }
1572 }
1573 }
1574
1575 m_xDoc->getIDocumentContentOperations().InsertString( *m_pPam, aToken.toString());
1576
1577 // if there are temporary paragraph attributes and the
1578 // paragraph isn't empty then the paragraph attributes
1579 // are final.
1580 m_aParaAttrs.clear();
1581
1582 SetAttr();
1583 }
1584 break;
1585
1586 case HtmlTokenId::HORZRULE:
1588 break;
1589
1590 case HtmlTokenId::IMAGE:
1591 InsertImage();
1592 // if only the parser references the doc, we can break and set
1593 // an error code
1594 if( 1 == m_xDoc->getReferenceCount() )
1595 {
1596 eState = SvParserState::Error;
1597 }
1598 break;
1599
1600 case HtmlTokenId::SPACER:
1601 InsertSpacer();
1602 break;
1603
1604 case HtmlTokenId::EMBED:
1605 InsertEmbed();
1606 break;
1607
1608 case HtmlTokenId::NOEMBED_ON:
1609 m_bInNoEmbed = true;
1610 m_bCallNextToken = bool(m_xTable);
1611 ReadRawData( OOO_STRING_SVTOOLS_HTML_noembed );
1612 break;
1613
1614 case HtmlTokenId::DEFLIST_ON:
1615 if( m_nOpenParaToken != HtmlTokenId::NONE )
1616 EndPara();
1617 NewDefList();
1618 break;
1619 case HtmlTokenId::DEFLIST_OFF:
1620 if( m_nOpenParaToken != HtmlTokenId::NONE )
1621 EndPara();
1622 EndDefListItem( HtmlTokenId::NONE );
1623 EndDefList();
1624 break;
1625
1626 case HtmlTokenId::DD_ON:
1627 case HtmlTokenId::DT_ON:
1628 if( m_nOpenParaToken != HtmlTokenId::NONE )
1629 EndPara();
1630 EndDefListItem();// close <DD>/<DT> and set no template
1632 break;
1633
1634 case HtmlTokenId::DD_OFF:
1635 case HtmlTokenId::DT_OFF:
1636 // c.f. HtmlTokenId::LI_OFF
1637 // Actually we should close a DD/DT now.
1638 // But neither Netscape nor Microsoft do this and so don't we.
1640 break;
1641
1642 // divisions
1643 case HtmlTokenId::DIVISION_ON:
1644 case HtmlTokenId::CENTER_ON:
1646 {
1647 if (m_nOpenParaToken != HtmlTokenId::NONE)
1648 {
1649 if (IsReadPRE())
1650 m_nOpenParaToken = HtmlTokenId::NONE;
1651 else
1652 EndPara();
1653 }
1655 }
1656 break;
1657
1658 case HtmlTokenId::DIVISION_OFF:
1659 case HtmlTokenId::CENTER_OFF:
1661 {
1662 if (m_nOpenParaToken != HtmlTokenId::NONE)
1663 {
1664 if (IsReadPRE())
1665 m_nOpenParaToken = HtmlTokenId::NONE;
1666 else
1667 EndPara();
1668 }
1669 EndDivision();
1670 }
1671 break;
1672
1673 case HtmlTokenId::MULTICOL_ON:
1674 if( m_nOpenParaToken != HtmlTokenId::NONE )
1675 EndPara();
1676 NewMultiCol();
1677 break;
1678
1679 case HtmlTokenId::MULTICOL_OFF:
1680 if( m_nOpenParaToken != HtmlTokenId::NONE )
1681 EndPara();
1682 EndTag( HtmlTokenId::MULTICOL_ON );
1683 break;
1684
1685 case HtmlTokenId::MARQUEE_ON:
1686 NewMarquee();
1687 m_bCallNextToken = m_pMarquee!=nullptr && m_xTable;
1688 break;
1689
1690 case HtmlTokenId::FORM_ON:
1691 NewForm();
1692 break;
1693 case HtmlTokenId::FORM_OFF:
1694 EndForm();
1695 break;
1696
1697 // templates
1698 case HtmlTokenId::PARABREAK_ON:
1699 if( m_nOpenParaToken != HtmlTokenId::NONE )
1700 EndPara( true );
1701 NewPara();
1702 break;
1703
1704 case HtmlTokenId::PARABREAK_OFF:
1705 EndPara( true );
1706 break;
1707
1708 case HtmlTokenId::ADDRESS_ON:
1709 if( m_nOpenParaToken != HtmlTokenId::NONE )
1710 EndPara();
1711 NewTextFormatColl(HtmlTokenId::ADDRESS_ON, RES_POOLCOLL_SEND_ADDRESS);
1712 break;
1713
1714 case HtmlTokenId::ADDRESS_OFF:
1715 if( m_nOpenParaToken != HtmlTokenId::NONE )
1716 EndPara();
1717 EndTextFormatColl( HtmlTokenId::ADDRESS_OFF );
1718 break;
1719
1720 case HtmlTokenId::BLOCKQUOTE_ON:
1721 case HtmlTokenId::BLOCKQUOTE30_ON:
1722 if( m_nOpenParaToken != HtmlTokenId::NONE )
1723 EndPara();
1724 NewTextFormatColl( HtmlTokenId::BLOCKQUOTE_ON, RES_POOLCOLL_HTML_BLOCKQUOTE );
1725 break;
1726
1727 case HtmlTokenId::BLOCKQUOTE_OFF:
1728 case HtmlTokenId::BLOCKQUOTE30_OFF:
1729 if( m_nOpenParaToken != HtmlTokenId::NONE )
1730 EndPara();
1731 EndTextFormatColl( HtmlTokenId::BLOCKQUOTE_ON );
1732 break;
1733
1734 case HtmlTokenId::PREFORMTXT_ON:
1735 case HtmlTokenId::LISTING_ON:
1736 case HtmlTokenId::XMP_ON:
1737 if( m_nOpenParaToken != HtmlTokenId::NONE )
1738 EndPara();
1740 break;
1741
1742 case HtmlTokenId::PREFORMTXT_OFF:
1743 m_bNoParSpace = true; // the last PRE-paragraph gets a spacing
1744 EndTextFormatColl( HtmlTokenId::PREFORMTXT_OFF );
1745 break;
1746
1747 case HtmlTokenId::LISTING_OFF:
1748 case HtmlTokenId::XMP_OFF:
1750 break;
1751
1752 case HtmlTokenId::HEAD1_ON:
1753 case HtmlTokenId::HEAD2_ON:
1754 case HtmlTokenId::HEAD3_ON:
1755 case HtmlTokenId::HEAD4_ON:
1756 case HtmlTokenId::HEAD5_ON:
1757 case HtmlTokenId::HEAD6_ON:
1758 if( m_nOpenParaToken != HtmlTokenId::NONE )
1759 {
1760 if( IsReadPRE() )
1761 m_nOpenParaToken = HtmlTokenId::NONE;
1762 else
1763 EndPara();
1764 }
1765 NewHeading( nToken );
1766 break;
1767
1768 case HtmlTokenId::HEAD1_OFF:
1769 case HtmlTokenId::HEAD2_OFF:
1770 case HtmlTokenId::HEAD3_OFF:
1771 case HtmlTokenId::HEAD4_OFF:
1772 case HtmlTokenId::HEAD5_OFF:
1773 case HtmlTokenId::HEAD6_OFF:
1774 EndHeading();
1775 break;
1776
1777 case HtmlTokenId::TABLE_ON:
1778 if( !m_vPendingStack.empty() )
1779 BuildTable( SvxAdjust::End );
1780 else
1781 {
1782 if( m_nOpenParaToken != HtmlTokenId::NONE )
1783 EndPara();
1784 OSL_ENSURE(!m_xTable, "table in table not allowed here");
1785 if( !m_xTable && (IsNewDoc() || !m_pPam->GetPointNode().FindTableNode()) &&
1787 m_xDoc->GetNodes().GetEndOfExtras().GetIndex() ||
1789 {
1790 if ( m_nParaCnt < 5 )
1791 Show(); // show what we have up to here
1792
1793 SvxAdjust eAdjust = m_xAttrTab->pAdjust
1794 ? static_cast<const SvxAdjustItem&>(m_xAttrTab->pAdjust->GetItem()).
1795 GetAdjust()
1796 : SvxAdjust::End;
1797 BuildTable( eAdjust );
1798 }
1799 else
1800 bInsertUnknown = m_bKeepUnknown;
1801 }
1802 break;
1803
1804 // lists
1805 case HtmlTokenId::DIRLIST_ON:
1806 case HtmlTokenId::MENULIST_ON:
1807 case HtmlTokenId::ORDERLIST_ON:
1808 case HtmlTokenId::UNORDERLIST_ON:
1809 if( m_nOpenParaToken != HtmlTokenId::NONE )
1810 EndPara();
1812 break;
1813
1814 case HtmlTokenId::DIRLIST_OFF:
1815 case HtmlTokenId::MENULIST_OFF:
1816 case HtmlTokenId::ORDERLIST_OFF:
1817 case HtmlTokenId::UNORDERLIST_OFF:
1818 if( m_nOpenParaToken != HtmlTokenId::NONE )
1819 EndPara();
1820 EndNumberBulletListItem( HtmlTokenId::NONE, true );
1822 break;
1823
1824 case HtmlTokenId::LI_ON:
1825 case HtmlTokenId::LISTHEADER_ON:
1826 if( m_nOpenParaToken != HtmlTokenId::NONE &&
1828 || HtmlTokenId::PARABREAK_ON==m_nOpenParaToken) )
1829 {
1830 // only finish paragraph for <P><LI>, not for <DD><LI>
1831 EndPara();
1832 }
1833
1834 if (m_bFuzzing && m_nListItems > 1024)
1835 {
1836 SAL_WARN("sw.html", "skipping remaining bullet import for performance during fuzzing");
1837 }
1838 else
1839 {
1840 EndNumberBulletListItem( HtmlTokenId::NONE, false );// close <LI>/<LH> and don't set a template
1842 }
1843
1844 ++m_nListItems;
1845
1846 break;
1847 case HtmlTokenId::LI_OFF:
1848 case HtmlTokenId::LISTHEADER_OFF:
1850 break;
1851
1852 // Attribute :
1853 case HtmlTokenId::ITALIC_ON:
1854 {
1858 NewStdAttr( HtmlTokenId::ITALIC_ON,
1859 &m_xAttrTab->pItalic, aPosture,
1860 &m_xAttrTab->pItalicCJK, &aPostureCJK,
1861 &m_xAttrTab->pItalicCTL, &aPostureCTL );
1862 }
1863 break;
1864
1865 case HtmlTokenId::BOLD_ON:
1866 {
1870 NewStdAttr( HtmlTokenId::BOLD_ON,
1871 &m_xAttrTab->pBold, aWeight,
1872 &m_xAttrTab->pBoldCJK, &aWeightCJK,
1873 &m_xAttrTab->pBoldCTL, &aWeightCTL );
1874 }
1875 break;
1876
1877 case HtmlTokenId::STRIKE_ON:
1878 case HtmlTokenId::STRIKETHROUGH_ON:
1879 {
1880 NewStdAttr( HtmlTokenId::STRIKE_ON, &m_xAttrTab->pStrike,
1882 }
1883 break;
1884
1885 case HtmlTokenId::UNDERLINE_ON:
1886 {
1887 NewStdAttr( HtmlTokenId::UNDERLINE_ON, &m_xAttrTab->pUnderline,
1889 }
1890 break;
1891
1892 case HtmlTokenId::SUPERSCRIPT_ON:
1893 {
1894 NewStdAttr( HtmlTokenId::SUPERSCRIPT_ON, &m_xAttrTab->pEscapement,
1896 }
1897 break;
1898
1899 case HtmlTokenId::SUBSCRIPT_ON:
1900 {
1901 NewStdAttr( HtmlTokenId::SUBSCRIPT_ON, &m_xAttrTab->pEscapement,
1903 }
1904 break;
1905
1906 case HtmlTokenId::BLINK_ON:
1907 {
1908 NewStdAttr( HtmlTokenId::BLINK_ON, &m_xAttrTab->pBlink,
1909 SvxBlinkItem( true, RES_CHRATR_BLINK ) );
1910 }
1911 break;
1912
1913 case HtmlTokenId::SPAN_ON:
1914 NewStdAttr( HtmlTokenId::SPAN_ON );
1915 break;
1916
1917 case HtmlTokenId::ITALIC_OFF:
1918 case HtmlTokenId::BOLD_OFF:
1919 case HtmlTokenId::STRIKE_OFF:
1920 case HtmlTokenId::UNDERLINE_OFF:
1921 case HtmlTokenId::SUPERSCRIPT_OFF:
1922 case HtmlTokenId::SUBSCRIPT_OFF:
1923 case HtmlTokenId::BLINK_OFF:
1924 case HtmlTokenId::SPAN_OFF:
1925 EndTag( nToken );
1926 break;
1927
1928 case HtmlTokenId::STRIKETHROUGH_OFF:
1929 EndTag( HtmlTokenId::STRIKE_OFF );
1930 break;
1931
1932 case HtmlTokenId::BASEFONT_ON:
1934 break;
1935 case HtmlTokenId::BASEFONT_OFF:
1937 break;
1938 case HtmlTokenId::FONT_ON:
1939 case HtmlTokenId::BIGPRINT_ON:
1940 case HtmlTokenId::SMALLPRINT_ON:
1942 break;
1943 case HtmlTokenId::FONT_OFF:
1944 case HtmlTokenId::BIGPRINT_OFF:
1945 case HtmlTokenId::SMALLPRINT_OFF:
1947 break;
1948
1949 case HtmlTokenId::EMPHASIS_ON:
1950 case HtmlTokenId::CITATION_ON:
1951 case HtmlTokenId::STRONG_ON:
1952 case HtmlTokenId::CODE_ON:
1953 case HtmlTokenId::SAMPLE_ON:
1954 case HtmlTokenId::KEYBOARD_ON:
1955 case HtmlTokenId::VARIABLE_ON:
1956 case HtmlTokenId::DEFINSTANCE_ON:
1957 case HtmlTokenId::SHORTQUOTE_ON:
1958 case HtmlTokenId::LANGUAGE_ON:
1959 case HtmlTokenId::AUTHOR_ON:
1960 case HtmlTokenId::PERSON_ON:
1961 case HtmlTokenId::ACRONYM_ON:
1962 case HtmlTokenId::ABBREVIATION_ON:
1963 case HtmlTokenId::INSERTEDTEXT_ON:
1964 case HtmlTokenId::DELETEDTEXT_ON:
1965
1966 case HtmlTokenId::TELETYPE_ON:
1968 break;
1969
1970 case HtmlTokenId::SDFIELD_ON:
1971 NewField();
1973 break;
1974
1975 case HtmlTokenId::EMPHASIS_OFF:
1976 case HtmlTokenId::CITATION_OFF:
1977 case HtmlTokenId::STRONG_OFF:
1978 case HtmlTokenId::CODE_OFF:
1979 case HtmlTokenId::SAMPLE_OFF:
1980 case HtmlTokenId::KEYBOARD_OFF:
1981 case HtmlTokenId::VARIABLE_OFF:
1982 case HtmlTokenId::DEFINSTANCE_OFF:
1983 case HtmlTokenId::SHORTQUOTE_OFF:
1984 case HtmlTokenId::LANGUAGE_OFF:
1985 case HtmlTokenId::AUTHOR_OFF:
1986 case HtmlTokenId::PERSON_OFF:
1987 case HtmlTokenId::ACRONYM_OFF:
1988 case HtmlTokenId::ABBREVIATION_OFF:
1989 case HtmlTokenId::INSERTEDTEXT_OFF:
1990 case HtmlTokenId::DELETEDTEXT_OFF:
1991
1992 case HtmlTokenId::TELETYPE_OFF:
1993 EndTag( nToken );
1994 break;
1995
1996 case HtmlTokenId::HEAD_OFF:
1997 if( !m_aStyleSource.isEmpty() )
1998 {
1999 m_pCSS1Parser->ParseStyleSheet( m_aStyleSource );
2000 m_aStyleSource.clear();
2001 }
2002 break;
2003
2004 case HtmlTokenId::DOCTYPE:
2005 case HtmlTokenId::BODY_OFF:
2006 case HtmlTokenId::HTML_OFF:
2007 case HtmlTokenId::HEAD_ON:
2008 case HtmlTokenId::TITLE_OFF:
2009 break; // don't evaluate further???
2010 case HtmlTokenId::HTML_ON:
2011 {
2012 const HTMLOptions& rHTMLOptions = GetOptions();
2013 for (size_t i = rHTMLOptions.size(); i; )
2014 {
2015 const HTMLOption& rOption = rHTMLOptions[--i];
2016 if( HtmlOptionId::DIR == rOption.GetToken() )
2017 {
2018 const OUString& rDir = rOption.GetString();
2019 SfxItemSet aItemSet( m_xDoc->GetAttrPool(),
2020 m_pCSS1Parser->GetWhichMap() );
2021 SvxCSS1PropertyInfo aPropInfo;
2022 OUString aDummy;
2023 ParseStyleOptions( aDummy, aDummy, aDummy, aItemSet,
2024 aPropInfo, nullptr, &rDir );
2025
2026 m_pCSS1Parser->SetPageDescAttrs( nullptr, &aItemSet );
2027 break;
2028 }
2029 }
2030 }
2031 break;
2032
2033 case HtmlTokenId::INPUT:
2034 InsertInput();
2035 break;
2036
2037 case HtmlTokenId::TEXTAREA_ON:
2038 NewTextArea();
2040 break;
2041
2042 case HtmlTokenId::SELECT_ON:
2043 NewSelect();
2045 break;
2046
2047 case HtmlTokenId::ANCHOR_ON:
2048 NewAnchor();
2049 break;
2050
2051 case HtmlTokenId::ANCHOR_OFF:
2052 EndAnchor();
2053 break;
2054
2055 case HtmlTokenId::COMMENT:
2056 if( ( aToken.getLength() > 5 ) && ( ! m_bIgnoreHTMLComments ) )
2057 {
2058 // insert as Post-It
2059 // If there are no space characters right behind
2060 // the <!-- and on front of the -->, leave the comment untouched.
2061 if( ' ' == aToken[ 3 ] &&
2062 ' ' == aToken[ aToken.getLength()-3 ] )
2063 {
2064 std::u16string_view aComment( aToken.subView( 3, aToken.getLength()-5 ) );
2065 InsertComment(OUString(comphelper::string::strip(aComment, ' ')));
2066 }
2067 else
2068 {
2069 OUString aComment = "<" + aToken + ">";
2070 InsertComment( aComment );
2071 }
2072 }
2073 break;
2074
2075 case HtmlTokenId::MAP_ON:
2076 // Image Maps are read asynchronously: At first only an image map is created
2077 // Areas are processed later. Nevertheless the
2078 // ImageMap is inserted into the IMap-Array, because it might be used
2079 // already.
2080 m_pImageMap = new ImageMap;
2082 {
2083 if (!m_pImageMaps)
2084 m_pImageMaps.reset( new ImageMaps );
2085 m_pImageMaps->push_back(std::unique_ptr<ImageMap>(m_pImageMap));
2086 }
2087 else
2088 {
2089 delete m_pImageMap;
2090 m_pImageMap = nullptr;
2091 }
2092 break;
2093
2094 case HtmlTokenId::MAP_OFF:
2095 // there is no ImageMap anymore (don't delete IMap, because it's
2096 // already contained in the array!)
2097 m_pImageMap = nullptr;
2098 break;
2099
2100 case HtmlTokenId::AREA:
2101 if( m_pImageMap )
2102 ParseAreaOptions( m_pImageMap, m_sBaseURL, SvMacroItemId::OnMouseOver,
2103 SvMacroItemId::OnMouseOut );
2104 break;
2105
2106 case HtmlTokenId::FRAMESET_ON:
2107 bInsertUnknown = m_bKeepUnknown;
2108 break;
2109
2110 case HtmlTokenId::NOFRAMES_ON:
2111 if( IsInHeader() )
2112 FinishHeader();
2113 bInsertUnknown = m_bKeepUnknown;
2114 break;
2115
2116 case HtmlTokenId::UNKNOWNCONTROL_ON:
2117 // Ignore content of unknown token in the header, if the token
2118 // does not start with a '!'.
2119 // (but judging from the code, also if does not start with a '%')
2120 // (and also if we're not somewhere we consider PRE)
2121 if( IsInHeader() && !IsReadPRE() && m_aUnknownToken.isEmpty() &&
2122 !sSaveToken.isEmpty() && '!' != sSaveToken[0] &&
2123 '%' != sSaveToken[0] )
2124 m_aUnknownToken = sSaveToken;
2125 [[fallthrough]];
2126
2127 default:
2128 bInsertUnknown = m_bKeepUnknown;
2129 break;
2130 }
2131
2132 if( bGetIDOption )
2134
2135 if( bInsertUnknown )
2136 {
2137 OUStringBuffer aComment("HTML: <");
2138 if( (nToken >= HtmlTokenId::ONOFF_START) && isOffToken(nToken) )
2139 aComment.append("/");
2140 aComment.append(sSaveToken);
2141 if( !aToken.isEmpty() )
2142 {
2143 UnescapeToken();
2144 aComment.append(" " + aToken);
2145 }
2146 aComment.append(">");
2147 InsertComment( aComment.makeStringAndClear() );
2148 }
2149
2150 // if there are temporary paragraph attributes and the
2151 // paragraph isn't empty then the paragraph attributes are final.
2152 if( !m_aParaAttrs.empty() && m_pPam->GetPoint()->GetContentIndex() )
2153 m_aParaAttrs.clear();
2154}
2155
2156static void lcl_swhtml_getItemInfo( const HTMLAttr& rAttr,
2157 bool& rScriptDependent,
2158 sal_uInt16& rScriptType )
2159{
2160 switch( rAttr.GetItem().Which() )
2161 {
2162 case RES_CHRATR_FONT:
2165 case RES_CHRATR_POSTURE:
2166 case RES_CHRATR_WEIGHT:
2167 rScriptType = i18n::ScriptType::LATIN;
2168 rScriptDependent = true;
2169 break;
2175 rScriptType = i18n::ScriptType::ASIAN;
2176 rScriptDependent = true;
2177 break;
2183 rScriptType = i18n::ScriptType::COMPLEX;
2184 rScriptDependent = true;
2185 break;
2186 default:
2187 rScriptDependent = false;
2188 break;
2189 }
2190}
2191
2193{
2194 // A hard line break at the end always must be removed.
2195 // A second one we replace with paragraph spacing.
2196 sal_Int32 nLFStripped = StripTrailingLF();
2197 if( (AM_NOSPACE==eMode || AM_SOFTNOSPACE==eMode) && nLFStripped > 1 )
2198 eMode = AM_SPACE;
2199
2200 // the hard attributes of this paragraph will never be invalid again
2201 m_aParaAttrs.clear();
2202
2203 SwTextNode *pTextNode = (AM_SPACE==eMode || AM_NOSPACE==eMode) ?
2204 m_pPam->GetPoint()->GetNode().GetTextNode() : nullptr;
2205
2206 if (pTextNode)
2207 {
2208 const SvxULSpaceItem& rULSpace =
2209 pTextNode->SwContentNode::GetAttr( RES_UL_SPACE );
2210
2211 bool bChange = AM_NOSPACE==eMode ? rULSpace.GetLower() > 0
2212 : rULSpace.GetLower() == 0;
2213
2214 if( bChange )
2215 {
2216 const SvxULSpaceItem& rCollULSpace =
2217 pTextNode->GetAnyFormatColl().GetULSpace();
2218
2219 bool bMayReset = AM_NOSPACE==eMode ? rCollULSpace.GetLower() == 0
2220 : rCollULSpace.GetLower() > 0;
2221
2222 if( bMayReset &&
2223 rCollULSpace.GetUpper() == rULSpace.GetUpper() )
2224 {
2225 pTextNode->ResetAttr( RES_UL_SPACE );
2226 }
2227 else
2228 {
2229 pTextNode->SetAttr(
2230 SvxULSpaceItem( rULSpace.GetUpper(),
2232 }
2233 }
2234 }
2236
2237 SwPosition aOldPos( *m_pPam->GetPoint() );
2238
2239 bool bRet = m_xDoc->getIDocumentContentOperations().AppendTextNode( *m_pPam->GetPoint() );
2240
2241 // split character attributes and maybe set none,
2242 // which are set for the whole paragraph
2243 const sal_Int32 nEndCnt = aOldPos.GetContentIndex();
2244 const SwPosition& rPos = *m_pPam->GetPoint();
2245
2246 HTMLAttr** pHTMLAttributes = reinterpret_cast<HTMLAttr**>(m_xAttrTab.get());
2247 for (auto nCnt = sizeof(HTMLAttrTable) / sizeof(HTMLAttr*); nCnt--; ++pHTMLAttributes)
2248 {
2249 HTMLAttr *pAttr = *pHTMLAttributes;
2250 if( pAttr && pAttr->GetItem().Which() < RES_PARATR_BEGIN )
2251 {
2252 bool bWholePara = false;
2253
2254 while( pAttr )
2255 {
2256 HTMLAttr *pNext = pAttr->GetNext();
2257 if( pAttr->GetStartParagraphIdx() < aOldPos.GetNodeIndex() ||
2258 (!bWholePara &&
2259 pAttr->GetStartParagraph() == aOldPos.GetNode() &&
2260 pAttr->GetStartContent() != nEndCnt) )
2261 {
2262 bWholePara =
2263 pAttr->GetStartParagraph() == aOldPos.GetNode() &&
2264 pAttr->GetStartContent() == 0;
2265
2266 sal_Int32 nStt = pAttr->m_nStartContent;
2267 bool bScript = false;
2268 sal_uInt16 nScriptItem;
2269 bool bInsert = true;
2270 lcl_swhtml_getItemInfo( *pAttr, bScript,
2271 nScriptItem );
2272 // set previous part
2273 if( bScript )
2274 {
2275 const SwTextNode *pTextNd =
2277 OSL_ENSURE( pTextNd, "No text node" );
2278 if( pTextNd )
2279 {
2280 const OUString& rText = pTextNd->GetText();
2281 sal_uInt16 nScriptText =
2282 g_pBreakIt->GetBreakIter()->getScriptType(
2283 rText, pAttr->GetStartContent() );
2284 sal_Int32 nScriptEnd = g_pBreakIt->GetBreakIter()
2285 ->endOfScript( rText, nStt, nScriptText );
2286 while (nScriptEnd < nEndCnt && nScriptEnd != -1)
2287 {
2288 if( nScriptItem == nScriptText )
2289 {
2290 HTMLAttr *pSetAttr =
2291 pAttr->Clone( aOldPos.GetNode(), nScriptEnd );
2292 pSetAttr->m_nStartContent = nStt;
2293 pSetAttr->ClearPrev();
2294 if( !pNext || bWholePara )
2295 {
2296 if (pSetAttr->m_bInsAtStart)
2297 m_aSetAttrTab.push_front( pSetAttr );
2298 else
2299 m_aSetAttrTab.push_back( pSetAttr );
2300 }
2301 else
2302 pNext->InsertPrev( pSetAttr );
2303 }
2304 nStt = nScriptEnd;
2305 nScriptText = g_pBreakIt->GetBreakIter()->getScriptType(
2306 rText, nStt );
2307 nScriptEnd = g_pBreakIt->GetBreakIter()
2308 ->endOfScript( rText, nStt, nScriptText );
2309 }
2310 bInsert = nScriptItem == nScriptText;
2311 }
2312 }
2313 if( bInsert )
2314 {
2315 HTMLAttr *pSetAttr =
2316 pAttr->Clone( aOldPos.GetNode(), nEndCnt );
2317 pSetAttr->m_nStartContent = nStt;
2318
2319 // When the attribute is for the whole paragraph, the outer
2320 // attributes aren't effective anymore. Hence it may not be inserted
2321 // in the Prev-List of an outer attribute, because that won't be
2322 // set. That leads to shifting when fields are used.
2323 if( !pNext || bWholePara )
2324 {
2325 if (pSetAttr->m_bInsAtStart)
2326 m_aSetAttrTab.push_front( pSetAttr );
2327 else
2328 m_aSetAttrTab.push_back( pSetAttr );
2329 }
2330 else
2331 pNext->InsertPrev( pSetAttr );
2332 }
2333 else
2334 {
2335 HTMLAttr *pPrev = pAttr->GetPrev();
2336 if( pPrev )
2337 {
2338 // the previous attributes must be set anyway
2339 if( !pNext || bWholePara )
2340 {
2341 if (pPrev->m_bInsAtStart)
2342 m_aSetAttrTab.push_front( pPrev );
2343 else
2344 m_aSetAttrTab.push_back( pPrev );
2345 }
2346 else
2347 pNext->InsertPrev( pPrev );
2348 }
2349 }
2350 pAttr->ClearPrev();
2351 }
2352
2353 pAttr->SetStart( rPos );
2354 pAttr = pNext;
2355 }
2356 }
2357 }
2358
2359 if( bUpdateNum )
2360 {
2361 if( GetNumInfo().GetDepth() )
2362 {
2363 sal_uInt8 nLvl = GetNumInfo().GetLevel();
2364 SetNodeNum( nLvl );
2365 }
2366 else
2368 }
2369
2370 // We must set the attribute of the paragraph before now (because of JavaScript)
2371 SetAttr();
2372
2373 // Now it is time to get rid of all script dependent hints that are
2374 // equal to the settings in the style
2375 SwTextNode *pTextNd = aOldPos.GetNode().GetTextNode();
2376 OSL_ENSURE( pTextNd, "There is the txt node" );
2377 size_t nCntAttr = (pTextNd && pTextNd->GetpSwpHints())
2378 ? pTextNd->GetSwpHints().Count() : 0;
2379 if( nCntAttr )
2380 {
2381 // These are the end position of all script dependent hints.
2382 // If we find a hint that starts before the current end position,
2383 // we have to set it. If we find a hint that start behind or at
2384 // that position, we have to take the hint value into account.
2385 // If it is equal to the style, or in fact the paragraph value
2386 // for that hint, the hint is removed. Otherwise its end position
2387 // is remembered.
2388 sal_Int32 aEndPos[15] =
2389 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
2390 SwpHints& rHints = pTextNd->GetSwpHints();
2391 for( size_t i=0; i < nCntAttr; i++ )
2392 {
2393 SwTextAttr *pHt = rHints.Get( i );
2394 sal_uInt16 nWhich = pHt->Which();
2395 sal_Int16 nIdx = 0;
2396 bool bFont = false;
2397 switch( nWhich )
2398 {
2399 case RES_CHRATR_FONT:
2400 nIdx = 0;
2401 bFont = true;
2402 break;
2404 nIdx = 1;
2405 break;
2407 nIdx = 2;
2408 break;
2409 case RES_CHRATR_POSTURE:
2410 nIdx = 3;
2411 break;
2412 case RES_CHRATR_WEIGHT:
2413 nIdx = 4;
2414 break;
2416 nIdx = 5;
2417 bFont = true;
2418 break;
2420 nIdx = 6;
2421 break;
2423 nIdx = 7;
2424 break;
2426 nIdx = 8;
2427 break;
2429 nIdx = 9;
2430 break;
2432 nIdx = 10;
2433 bFont = true;
2434 break;
2436 nIdx = 11;
2437 break;
2439 nIdx = 12;
2440 break;
2442 nIdx = 13;
2443 break;
2445 nIdx = 14;
2446 break;
2447 default:
2448 // Skip to next attribute
2449 continue;
2450 }
2451 const sal_Int32 nStt = pHt->GetStart();
2452 if( nStt >= aEndPos[nIdx] )
2453 {
2454 const SfxPoolItem& rItem =
2455 static_cast<const SwContentNode *>(pTextNd)->GetAttr( nWhich );
2456 if( bFont ? swhtml_css1atr_equalFontItems(rItem,pHt->GetAttr())
2457 : rItem == pHt->GetAttr() )
2458 {
2459 // The hint is the same as set in the paragraph and
2460 // therefore, it can be deleted
2461 // CAUTION!!! This WILL delete the hint and it MAY
2462 // also delete the SwpHints!!! To avoid any trouble
2463 // we leave the loop immediately if this is the last
2464 // hint.
2465 pTextNd->DeleteAttribute( pHt );
2466 if( 1 == nCntAttr )
2467 break;
2468 i--;
2469 nCntAttr--;
2470 }
2471 else
2472 {
2473 // The hint is different. Therefore all hints within that
2474 // hint have to be ignored.
2475 aEndPos[nIdx] = pHt->GetEnd() ? *pHt->GetEnd() : nStt;
2476 }
2477 }
2478 else
2479 {
2480 // The hint starts before another one ends.
2481 // The hint in this case is not deleted
2482 OSL_ENSURE( pHt->GetEnd() && *pHt->GetEnd() <= aEndPos[nIdx],
2483 "hints aren't nested properly!" );
2484 }
2485 }
2486 }
2487
2488 if (!m_xTable && !--m_nParaCnt)
2489 Show();
2490
2491 return bRet;
2492}
2493
2495{
2496 //If it already has ParSpace, return
2497 if( !m_bNoParSpace )
2498 return;
2499
2500 m_bNoParSpace = false;
2501
2502 SwNodeOffset nNdIdx = m_pPam->GetPoint()->GetNodeIndex() - 1;
2503
2504 SwTextNode *pTextNode = m_xDoc->GetNodes()[nNdIdx]->GetTextNode();
2505 if( !pTextNode )
2506 return;
2507
2508 SvxULSpaceItem rULSpace =
2509 pTextNode->SwContentNode::GetAttr( RES_UL_SPACE );
2510 if( rULSpace.GetLower() )
2511 return;
2512
2513 const SvxULSpaceItem& rCollULSpace =
2514 pTextNode->GetAnyFormatColl().GetULSpace();
2515 if( rCollULSpace.GetLower() &&
2516 rCollULSpace.GetUpper() == rULSpace.GetUpper() )
2517 {
2518 pTextNode->ResetAttr( RES_UL_SPACE );
2519 }
2520 else
2521 {
2522 //What I do here, is that I examine the attributes, and if
2523 //I find out, that it's CJK/CTL, then I set the paragraph space
2524 //to the value set in HTML_CJK_PARSPACE/HTML_CTL_PARSPACE.
2525
2526 bool bIsCJK = false;
2527 bool bIsCTL = false;
2528
2529 const size_t nCntAttr = pTextNode->GetpSwpHints()
2530 ? pTextNode->GetSwpHints().Count() : 0;
2531
2532 for(size_t i = 0; i < nCntAttr; ++i)
2533 {
2534 SwTextAttr *const pHt = pTextNode->GetSwpHints().Get(i);
2535 sal_uInt16 const nWhich = pHt->Which();
2536 if (RES_CHRATR_CJK_FONT == nWhich ||
2537 RES_CHRATR_CJK_FONTSIZE == nWhich ||
2538 RES_CHRATR_CJK_LANGUAGE == nWhich ||
2539 RES_CHRATR_CJK_POSTURE == nWhich ||
2540 RES_CHRATR_CJK_WEIGHT == nWhich)
2541 {
2542 bIsCJK = true;
2543 break;
2544 }
2545 if (RES_CHRATR_CTL_FONT == nWhich ||
2546 RES_CHRATR_CTL_FONTSIZE == nWhich ||
2547 RES_CHRATR_CTL_LANGUAGE == nWhich ||
2548 RES_CHRATR_CTL_POSTURE == nWhich ||
2549 RES_CHRATR_CTL_WEIGHT == nWhich)
2550 {
2551 bIsCTL = true;
2552 break;
2553 }
2554 }
2555
2556 if( bIsCTL )
2557 {
2558 pTextNode->SetAttr(
2560 }
2561 else if( bIsCJK )
2562 {
2563 pTextNode->SetAttr(
2565 } else {
2566 pTextNode->SetAttr(
2568 }
2569 }
2570}
2571
2573{
2574 // Here
2575 // - a EndAction is called, so the document is formatted
2576 // - a Reschedule is called,
2577 // - the own View-Shell is set again
2578 // - and a StartAction is called
2579
2580 OSL_ENSURE( SvParserState::Working==eState, "Show not in working state - That can go wrong" );
2581 SwViewShell *pOldVSh = CallEndAction();
2582
2584
2585 if( ( m_xDoc->GetDocShell() && m_xDoc->GetDocShell()->IsAbortingImport() )
2586 || 1 == m_xDoc->getReferenceCount() )
2587 {
2588 // was the import aborted by SFX?
2589 eState = SvParserState::Error;
2590 }
2591
2592 // Fetch the SwViewShell again, as it could be destroyed in Reschedule.
2593 SwViewShell *pVSh = CallStartAction( pOldVSh );
2594
2595 // is the current node not visible anymore, then we use a bigger increment
2596 if( pVSh )
2597 {
2599 ? 5 : 50;
2600 }
2601}
2602
2604{
2605 // Here
2606 // - a Reschedule is called, so it can be scrolled
2607 // - the own View-Shell is set again
2608 // - a StartAction/EndAction is called, when there was scrolling.
2609
2610 OSL_ENSURE( SvParserState::Working==eState, "ShowStatLine not in working state - That can go wrong" );
2611
2612 // scroll bar
2613 if (m_xProgress)
2614 {
2615 m_xProgress->Update(rInput.Tell());
2617 }
2618 else
2619 {
2621
2622 if( ( m_xDoc->GetDocShell() && m_xDoc->GetDocShell()->IsAbortingImport() )
2623 || 1 == m_xDoc->getReferenceCount() )
2624 // was the import aborted by SFX?
2625 eState = SvParserState::Error;
2626
2628 if( pVSh && pVSh->HasInvalidRect() )
2629 {
2630 CallEndAction( false, false );
2631 CallStartAction( pVSh, false );
2632 }
2633 }
2634}
2635
2637{
2638 OSL_ENSURE( !m_pActionViewShell, "CallStartAction: SwViewShell already set" );
2639
2640 if( !pVSh || bChkPtr )
2641 {
2642#if OSL_DEBUG_LEVEL > 0
2643 SwViewShell *pOldVSh = pVSh;
2644#endif
2645 pVSh = m_xDoc->getIDocumentLayoutAccess().GetCurrentViewShell();
2646#if OSL_DEBUG_LEVEL > 0
2647 OSL_ENSURE( !pVSh || !pOldVSh || pOldVSh == pVSh, "CallStartAction: Who swapped the SwViewShell?" );
2648 if( pOldVSh && !pVSh )
2649 pVSh = nullptr;
2650#endif
2651 }
2652 m_pActionViewShell = pVSh;
2653
2654 if( m_pActionViewShell )
2655 {
2656 if( auto pEditShell = dynamic_cast< SwEditShell *>( m_pActionViewShell ) )
2657 pEditShell->StartAction();
2658 else
2660 }
2661
2662 return m_pActionViewShell;
2663}
2664
2665SwViewShell *SwHTMLParser::CallEndAction( bool bChkAction, bool bChkPtr )
2666{
2667 if( bChkPtr )
2668 {
2669 SwViewShell *pVSh = m_xDoc->getIDocumentLayoutAccess().GetCurrentViewShell();
2670 OSL_ENSURE( !pVSh || m_pActionViewShell == pVSh,
2671 "CallEndAction: Who swapped the SwViewShell?" );
2672#if OSL_DEBUG_LEVEL > 0
2673 if( m_pActionViewShell && !pVSh )
2674 pVSh = nullptr;
2675#endif
2676 if( pVSh != m_pActionViewShell )
2677 m_pActionViewShell = nullptr;
2678 }
2679
2680 if( !m_pActionViewShell || (bChkAction && !m_pActionViewShell->ActionPend()) )
2681 return m_pActionViewShell;
2682
2683 if( dynamic_cast< const SwEditShell *>( m_pActionViewShell ) != nullptr )
2684 {
2685 // Already scrolled?, then make sure that the view doesn't move!
2686 const bool bOldLock = m_pActionViewShell->IsViewLocked();
2688 const bool bOldEndActionByVirDev = m_pActionViewShell->IsEndActionByVirDev();
2690 static_cast<SwEditShell*>(m_pActionViewShell)->EndAction();
2691 m_pActionViewShell->SetEndActionByVirDev( bOldEndActionByVirDev );
2692 m_pActionViewShell->LockView( bOldLock );
2693
2694 // bChkJumpMark is only set when the object was also found
2695 if( m_bChkJumpMark )
2696 {
2697 const Point aVisSttPos( DOCUMENTBORDER, DOCUMENTBORDER );
2698 if( GetMedium() && aVisSttPos == m_pActionViewShell->VisArea().Pos() )
2700 GetMedium()->GetURLObject().GetMark() );
2701 m_bChkJumpMark = false;
2702 }
2703 }
2704 else
2706
2707 // if the parser holds the last reference to the document, then we can
2708 // abort here and set an error.
2709 if( 1 == m_xDoc->getReferenceCount() )
2710 {
2711 eState = SvParserState::Error;
2712 }
2713
2715 m_pActionViewShell = nullptr;
2716
2717 return pVSh;
2718}
2719
2721{
2722 SwViewShell *pVSh = m_xDoc->getIDocumentLayoutAccess().GetCurrentViewShell();
2723 OSL_ENSURE( !pVSh || m_pActionViewShell == pVSh,
2724 "CheckActionViewShell: Who has swapped SwViewShell?" );
2725#if OSL_DEBUG_LEVEL > 0
2726 if( m_pActionViewShell && !pVSh )
2727 pVSh = nullptr;
2728#endif
2729 if( pVSh != m_pActionViewShell )
2730 m_pActionViewShell = nullptr;
2731
2732 return m_pActionViewShell;
2733}
2734
2736 : m_pFrameFormat(pFrameFormat)
2737{
2738 StartListening(m_pFrameFormat->GetNotifier());
2739}
2740
2742{
2743 if (rHint.GetId() == SfxHintId::Dying)
2744 m_pFrameFormat = nullptr;
2745}
2746
2747void SwHTMLParser::SetAttr_( bool bChkEnd, bool bBeforeTable,
2748 std::deque<std::unique_ptr<HTMLAttr>> *pPostIts )
2749{
2750 SwPaM aAttrPam( *m_pPam->GetPoint() );
2751 const SwPosition& rEndPos = *m_pPam->GetPoint();
2752 const sal_Int32 nEndCnt = m_pPam->GetPoint()->GetContentIndex();
2753 HTMLAttr* pAttr;
2754 SwContentNode* pCNd;
2755
2756 std::vector<std::unique_ptr<HTMLAttr>> aFields;
2757
2758 for( auto n = m_aSetAttrTab.size(); n; )
2759 {
2760 pAttr = m_aSetAttrTab[ --n ];
2761 sal_uInt16 nWhich = pAttr->m_pItem->Which();
2762
2763 SwNodeOffset nEndParaIdx = pAttr->GetEndParagraphIdx();
2764 bool bSetAttr;
2765 if( bChkEnd )
2766 {
2767 // Set character attribute with end early on, so set them still in
2768 // the current paragraph (because of JavaScript and various "chats"(?)).
2769 // This shouldn't be done for attributes which are used for
2770 // the whole paragraph, because they could be from a paragraph style
2771 // which can't be set. Because the attributes are inserted with
2772 // SETATTR_DONTREPLACE, they should be able to be set later.
2773 bSetAttr = ( nEndParaIdx < rEndPos.GetNodeIndex() &&
2774 (RES_LR_SPACE != nWhich || !GetNumInfo().GetNumRule()) ) ||
2775 ( !pAttr->IsLikePara() &&
2776 nEndParaIdx == rEndPos.GetNodeIndex() &&
2777 pAttr->GetEndContent() < nEndCnt &&
2778 (isCHRATR(nWhich) || isTXTATR_WITHEND(nWhich)) ) ||
2779 ( bBeforeTable &&
2780 nEndParaIdx == rEndPos.GetNodeIndex() &&
2781 !pAttr->GetEndContent() );
2782 }
2783 else
2784 {
2785 // Attributes in body nodes array section shouldn't be set if we are in a
2786 // special nodes array section, but vice versa it's possible.
2787 SwNodeOffset nEndOfIcons = m_xDoc->GetNodes().GetEndOfExtras().GetIndex();
2788 bSetAttr = nEndParaIdx < rEndPos.GetNodeIndex() ||
2789 rEndPos.GetNodeIndex() > nEndOfIcons ||
2790 nEndParaIdx <= nEndOfIcons;
2791 }
2792
2793 if( bSetAttr )
2794 {
2795 // The attribute shouldn't be in the list of temporary paragraph
2796 // attributes, because then it would be deleted.
2797 while( !m_aParaAttrs.empty() )
2798 {
2799 OSL_ENSURE( pAttr != m_aParaAttrs.back(),
2800 "SetAttr: Attribute must not yet be set" );
2801 m_aParaAttrs.pop_back();
2802 }
2803
2804 // then set it
2805 m_aSetAttrTab.erase( m_aSetAttrTab.begin() + n );
2806
2807 while( pAttr )
2808 {
2809 HTMLAttr *pPrev = pAttr->GetPrev();
2810 if( !pAttr->m_bValid )
2811 {
2812 // invalid attributes can be deleted
2813 delete pAttr;
2814 pAttr = pPrev;
2815 continue;
2816 }
2817
2818 pCNd = pAttr->m_nStartPara.GetNode().GetContentNode();
2819 if( !pCNd )
2820 {
2821 // because of the awful deleting of nodes an index can also
2822 // point to an end node :-(
2823 if ( (pAttr->GetStartParagraph() == pAttr->GetEndParagraph()) &&
2824 !isTXTATR_NOEND(nWhich) )
2825 {
2826 // when the end index also points to the node, we don't
2827 // need to set attributes anymore, except if it's a text attribute.
2828 delete pAttr;
2829 pAttr = pPrev;
2830 continue;
2831 }
2832 pCNd = m_xDoc->GetNodes().GoNext( &(pAttr->m_nStartPara) );
2833 if( pCNd )
2834 pAttr->m_nStartContent = 0;
2835 else
2836 {
2837 OSL_ENSURE( false, "SetAttr: GoNext() failed!" );
2838 delete pAttr;
2839 pAttr = pPrev;
2840 continue;
2841 }
2842 }
2843
2844 // because of the deleting of BRs the start index can also
2845 // point behind the end the text
2846 if( pAttr->m_nStartContent > pCNd->Len() )
2847 pAttr->m_nStartContent = pCNd->Len();
2848 aAttrPam.GetPoint()->Assign( *pCNd, pAttr->m_nStartContent );
2849
2850 aAttrPam.SetMark();
2851 if ( (pAttr->GetStartParagraph() != pAttr->GetEndParagraph()) &&
2852 !isTXTATR_NOEND(nWhich) )
2853 {
2854 pCNd = pAttr->m_nEndPara.GetNode().GetContentNode();
2855 if( !pCNd )
2856 {
2857 pCNd = SwNodes::GoPrevious( &(pAttr->m_nEndPara) );
2858 if( pCNd )
2859 pAttr->m_nEndContent = pCNd->Len();
2860 else
2861 {
2862 OSL_ENSURE( false, "SetAttr: GoPrevious() failed!" );
2863 aAttrPam.DeleteMark();
2864 delete pAttr;
2865 pAttr = pPrev;
2866 continue;
2867 }
2868 }
2869 }
2870 else if( pAttr->IsLikePara() )
2871 {
2872 pAttr->m_nEndContent = pCNd->Len();
2873 }
2874
2875 // because of the deleting of BRs the start index can also
2876 // point behind the end the text
2877 if( pAttr->m_nEndContent > pCNd->Len() )
2878 pAttr->m_nEndContent = pCNd->Len();
2879
2880 aAttrPam.GetPoint()->Assign( *pCNd, pAttr->m_nEndContent );
2881 if( bBeforeTable &&
2882 aAttrPam.GetPoint()->GetNodeIndex() ==
2883 rEndPos.GetNodeIndex() )
2884 {
2885 // If we're before inserting a table and the attribute ends
2886 // in the current node, then we must end it in the previous
2887 // node or discard it, if it starts in that node.
2888 if( nWhich != RES_BREAK && nWhich != RES_PAGEDESC &&
2889 !isTXTATR_NOEND(nWhich) )
2890 {
2891 if( aAttrPam.GetMark()->GetNodeIndex() !=
2892 rEndPos.GetNodeIndex() )
2893 {
2894 OSL_ENSURE( !aAttrPam.GetPoint()->GetContentIndex(),
2895 "Content-Position before table not 0???" );
2896 aAttrPam.Move( fnMoveBackward );
2897 }
2898 else
2899 {
2900 aAttrPam.DeleteMark();
2901 delete pAttr;
2902 pAttr = pPrev;
2903 continue;
2904 }
2905 }
2906 }
2907
2908 switch( nWhich )
2909 {
2910 case RES_FLTR_BOOKMARK: // insert bookmark
2911 {
2912 const OUString sName( static_cast<SfxStringItem*>(pAttr->m_pItem.get())->GetValue() );
2913 IDocumentMarkAccess* const pMarkAccess = m_xDoc->getIDocumentMarkAccess();
2914 IDocumentMarkAccess::const_iterator_t ppBkmk = pMarkAccess->findMark( sName );
2915 if( ppBkmk != pMarkAccess->getAllMarksEnd() &&
2916 (*ppBkmk)->GetMarkStart() == *aAttrPam.GetPoint() )
2917 break; // do not generate duplicates on this position
2918 aAttrPam.DeleteMark();
2919 const ::sw::mark::IMark* const pNewMark = pMarkAccess->makeMark(
2920 aAttrPam,
2921 sName,
2923 ::sw::mark::InsertMode::New);
2924
2925 // jump to bookmark
2926 if( JumpToMarks::Mark == m_eJumpTo && pNewMark->GetName() == m_sJmpMark )
2927 {
2928 m_bChkJumpMark = true;
2930 }
2931 }
2932 break;
2933 case RES_TXTATR_FIELD:
2936 {
2937 SwFieldIds nFieldWhich =
2938 pPostIts
2939 ? static_cast<const SwFormatField *>(pAttr->m_pItem.get())->GetField()->GetTyp()->Which()
2941 if( pPostIts && (SwFieldIds::Postit == nFieldWhich ||
2942 SwFieldIds::Script == nFieldWhich) )
2943 {
2944 pPostIts->emplace_front( pAttr );
2945 }
2946 else
2947 {
2948 aFields.emplace_back( pAttr);
2949 }
2950 }
2951 aAttrPam.DeleteMark();
2952 pAttr = pPrev;
2953 continue;
2954
2955 case RES_LR_SPACE:
2956 if( aAttrPam.GetPoint()->GetNodeIndex() ==
2957 aAttrPam.GetMark()->GetNodeIndex())
2958 {
2959 // because of numbering set this attribute directly at node
2960 pCNd->SetAttr( *pAttr->m_pItem );
2961 break;
2962 }
2963 OSL_ENSURE( false,
2964 "LRSpace set over multiple paragraphs!" );
2965 [[fallthrough]]; // (shouldn't reach this point anyway)
2966
2967 // tdf#94088 expand RES_BACKGROUND to the new fill attribute
2968 // definitions in the range [XATTR_FILL_FIRST .. XATTR_FILL_LAST].
2969 // This is the right place in the future if the adapted fill attributes
2970 // may be handled more directly in HTML import to handle them.
2971 case RES_BACKGROUND:
2972 {
2973 const SvxBrushItem& rBrush = static_cast< SvxBrushItem& >(*pAttr->m_pItem);
2975
2977 m_xDoc->getIDocumentContentOperations().InsertItemSet(aAttrPam, aNewSet, SetAttrMode::DONTREPLACE);
2978 break;
2979 }
2980 default:
2981
2982 // maybe jump to a bookmark
2983 if( RES_TXTATR_INETFMT == nWhich &&
2985 m_sJmpMark == static_cast<SwFormatINetFormat*>(pAttr->m_pItem.get())->GetName() )
2986 {
2987 m_bChkJumpMark = true;
2989 }
2990
2991 m_xDoc->getIDocumentContentOperations().InsertPoolItem( aAttrPam, *pAttr->m_pItem, SetAttrMode::DONTREPLACE );
2992 }
2993 aAttrPam.DeleteMark();
2994
2995 delete pAttr;
2996 pAttr = pPrev;
2997 }
2998 }
2999 }
3000
3001 for( auto n = m_aMoveFlyFrames.size(); n; )
3002 {
3003 SwFrameFormat *pFrameFormat = m_aMoveFlyFrames[--n]->GetFrameFormat();
3004 if (!pFrameFormat)
3005 {
3006 SAL_WARN("sw.html", "SwFrameFormat deleted during import");
3007 m_aMoveFlyFrames.erase( m_aMoveFlyFrames.begin() + n );
3008 m_aMoveFlyCnts.erase( m_aMoveFlyCnts.begin() + n );
3009 continue;
3010 }
3011
3012 const SwFormatAnchor& rAnchor = pFrameFormat->GetAnchor();
3013 OSL_ENSURE( RndStdIds::FLY_AT_PARA == rAnchor.GetAnchorId(),
3014 "Only At-Para flys need special handling" );
3015 SwNodeOffset nFlyParaIdx = rAnchor.GetAnchorNode()->GetIndex();
3016 bool bMoveFly;
3017 if( bChkEnd )
3018 {
3019 bMoveFly = nFlyParaIdx < rEndPos.GetNodeIndex() ||
3020 ( nFlyParaIdx == rEndPos.GetNodeIndex() &&
3021 m_aMoveFlyCnts[n] < nEndCnt );
3022 }
3023 else
3024 {
3025 SwNodeOffset nEndOfIcons = m_xDoc->GetNodes().GetEndOfExtras().GetIndex();
3026 bMoveFly = nFlyParaIdx < rEndPos.GetNodeIndex() ||
3027 rEndPos.GetNodeIndex() > nEndOfIcons ||
3028 nFlyParaIdx <= nEndOfIcons;
3029 }
3030 if( bMoveFly )
3031 {
3032 pFrameFormat->DelFrames();
3033 *aAttrPam.GetPoint() = *rAnchor.GetContentAnchor();
3034 aAttrPam.GetPoint()->SetContent( m_aMoveFlyCnts[n] );
3035 SwFormatAnchor aAnchor( rAnchor );
3036 aAnchor.SetType( RndStdIds::FLY_AT_CHAR );
3037 aAnchor.SetAnchor( aAttrPam.GetPoint() );
3038 pFrameFormat->SetFormatAttr( aAnchor );
3039
3040 const SwFormatHoriOrient& rHoriOri = pFrameFormat->GetHoriOrient();
3041 if( text::HoriOrientation::LEFT == rHoriOri.GetHoriOrient() )
3042 {
3043 SwFormatHoriOrient aHoriOri( rHoriOri );
3044 aHoriOri.SetRelationOrient( text::RelOrientation::CHAR );
3045 pFrameFormat->SetFormatAttr( aHoriOri );
3046 }
3047 const SwFormatVertOrient& rVertOri = pFrameFormat->GetVertOrient();
3048 if( text::VertOrientation::TOP == rVertOri.GetVertOrient() )
3049 {
3050 SwFormatVertOrient aVertOri( rVertOri );
3051 aVertOri.SetRelationOrient( text::RelOrientation::CHAR );
3052 pFrameFormat->SetFormatAttr( aVertOri );
3053 }
3054
3055 pFrameFormat->MakeFrames();
3056 m_aMoveFlyFrames.erase( m_aMoveFlyFrames.begin() + n );
3057 m_aMoveFlyCnts.erase( m_aMoveFlyCnts.begin() + n );
3058 }
3059 }
3060 for (auto & field : aFields)
3061 {
3062 pCNd = field->m_nStartPara.GetNode().GetContentNode();
3063 aAttrPam.GetPoint()->Assign( *pCNd, field->m_nStartContent );
3064
3065 if( bBeforeTable &&
3066 aAttrPam.GetPoint()->GetNodeIndex() == rEndPos.GetNodeIndex() )
3067 {
3068 OSL_ENSURE( !bBeforeTable, "Aha, the case does occur" );
3069 OSL_ENSURE( !aAttrPam.GetPoint()->GetContentIndex(),
3070 "Content-Position before table not 0???" );
3071 // !!!
3072 aAttrPam.Move( fnMoveBackward );
3073 }
3074
3075 m_xDoc->getIDocumentContentOperations().InsertPoolItem( aAttrPam, *field->m_pItem );
3076
3077 field.reset();
3078 }
3079 aFields.clear();
3080}
3081
3082void SwHTMLParser::NewAttr(const std::shared_ptr<HTMLAttrTable>& rAttrTable, HTMLAttr **ppAttr, const SfxPoolItem& rItem )
3083{
3084 // Font height and font colour as well as escape attributes may not be
3085 // combined. Therefore they're saved in a list and in it the last opened
3086 // attribute is at the beginning and count is always one. For all other
3087 // attributes count is just incremented.
3088 if( *ppAttr )
3089 {
3090 HTMLAttr *pAttr = new HTMLAttr(*m_pPam->GetPoint(), rItem, ppAttr, rAttrTable);
3091 pAttr->InsertNext( *ppAttr );
3092 (*ppAttr) = pAttr;
3093 }
3094 else
3095 (*ppAttr) = new HTMLAttr(*m_pPam->GetPoint(), rItem, ppAttr, rAttrTable);
3096}
3097
3098bool SwHTMLParser::EndAttr( HTMLAttr* pAttr, bool bChkEmpty )
3099{
3100 bool bRet = true;
3101
3102 // The list header is saved in the attribute.
3103 HTMLAttr **ppHead = pAttr->m_ppHead;
3104
3105 OSL_ENSURE( ppHead, "No list header attribute found!" );
3106
3107 // save the current position as end position
3108 const SwPosition* pEndPos = m_pPam->GetPoint();
3109 sal_Int32 nEndCnt = m_pPam->GetPoint()->GetContentIndex();
3110
3111 // Is the last started or an earlier started attribute being ended?
3112 HTMLAttr *pLast = nullptr;
3113 if( ppHead && pAttr != *ppHead )
3114 {
3115 // The last started attribute isn't being ended
3116
3117 // Then we look for attribute which was started immediately afterwards,
3118 // which has also not yet been ended (otherwise it would no longer be
3119 // in the list).
3120 pLast = *ppHead;
3121 while( pLast && pLast->GetNext() != pAttr )
3122 pLast = pLast->GetNext();
3123
3124 OSL_ENSURE( pLast, "Attribute not found in own list!" );
3125 }
3126
3127 bool bMoveBack = false;
3128 sal_uInt16 nWhich = pAttr->m_pItem->Which();
3129 if( !nEndCnt && RES_PARATR_BEGIN <= nWhich &&
3130 pEndPos->GetNodeIndex() != pAttr->GetStartParagraph().GetIndex() )
3131 {
3132 // Then move back one position in the content!
3133 bMoveBack = m_pPam->Move( fnMoveBackward );
3134 nEndCnt = m_pPam->GetPoint()->GetContentIndex();
3135 }
3136
3137 // now end the attribute
3138 HTMLAttr *pNext = pAttr->GetNext();
3139
3140 bool bInsert;
3141 sal_uInt16 nScriptItem = 0;
3142 bool bScript = false;
3143 // does it have a non-empty range?
3144 if( !bChkEmpty || (RES_PARATR_BEGIN <= nWhich && bMoveBack) ||
3145 RES_PAGEDESC == nWhich || RES_BREAK == nWhich ||
3146 pEndPos->GetNodeIndex() != pAttr->GetStartParagraph().GetIndex() ||
3147 nEndCnt != pAttr->GetStartContent() )
3148 {
3149 bInsert = true;
3150 // We do some optimization for script dependent attributes here.
3151 if( pEndPos->GetNodeIndex() == pAttr->GetStartParagraph().GetIndex() )
3152 {
3153 lcl_swhtml_getItemInfo( *pAttr, bScript, nScriptItem );
3154 }
3155 }
3156 else
3157 {
3158 bInsert = false;
3159 }
3160
3161 const SwTextNode *pTextNd = (bInsert && bScript) ?
3163 nullptr;
3164
3165 if (pTextNd)
3166 {
3167 const OUString& rText = pTextNd->GetText();
3168 sal_uInt16 nScriptText = g_pBreakIt->GetBreakIter()->getScriptType(
3169 rText, pAttr->GetStartContent() );
3170 sal_Int32 nScriptEnd = g_pBreakIt->GetBreakIter()
3171 ->endOfScript( rText, pAttr->GetStartContent(), nScriptText );
3172 while (nScriptEnd < nEndCnt && nScriptEnd != -1)
3173 {
3174 if( nScriptItem == nScriptText )
3175 {
3176 HTMLAttr *pSetAttr = pAttr->Clone( pEndPos->GetNode(), nScriptEnd );
3177 pSetAttr->ClearPrev();
3178 if( pNext )
3179 pNext->InsertPrev( pSetAttr );
3180 else
3181 {
3182 if (pSetAttr->m_bInsAtStart)
3183 m_aSetAttrTab.push_front( pSetAttr );
3184 else
3185 m_aSetAttrTab.push_back( pSetAttr );
3186 }
3187 }
3188 pAttr->m_nStartContent = nScriptEnd;
3189 nScriptText = g_pBreakIt->GetBreakIter()->getScriptType(
3190 rText, nScriptEnd );
3191 nScriptEnd = g_pBreakIt->GetBreakIter()
3192 ->endOfScript( rText, nScriptEnd, nScriptText );
3193 }
3194 bInsert = nScriptItem == nScriptText;
3195 }
3196 if( bInsert )
3197 {
3198 pAttr->m_nEndPara = pEndPos->GetNode();
3199 pAttr->m_nEndContent = nEndCnt;
3200 pAttr->m_bInsAtStart = RES_TXTATR_INETFMT != nWhich &&
3201 RES_TXTATR_CHARFMT != nWhich;
3202
3203 if( !pNext )
3204 {
3205 // No open attributes of that type exists any longer, so all
3206 // can be set. Except they depend on another attribute, then
3207 // they're appended there.
3208 if (pAttr->m_bInsAtStart)
3209 m_aSetAttrTab.push_front( pAttr );
3210 else
3211 m_aSetAttrTab.push_back( pAttr );
3212 }
3213 else
3214 {
3215 // There are other open attributes of that type,
3216 // therefore the setting must be postponed.
3217 // Hence the current attribute is added at the end
3218 // of the Prev-List of the successor.
3219 pNext->InsertPrev( pAttr );
3220 }
3221 }
3222 else
3223 {
3224 // Then don't insert, but delete. Because of the "faking" of styles
3225 // by hard attributing there can be also other empty attributes in the
3226 // Prev-List, which must be set anyway.
3227 HTMLAttr *pPrev = pAttr->GetPrev();
3228 bRet = false;
3229 delete pAttr;
3230
3231 if( pPrev )
3232 {
3233 // The previous attributes must be set anyway.
3234 if( pNext )
3235 pNext->InsertPrev( pPrev );
3236 else
3237 {
3238 if (pPrev->m_bInsAtStart)
3239 m_aSetAttrTab.push_front( pPrev );
3240 else
3241 m_aSetAttrTab.push_back( pPrev );
3242 }
3243 }
3244
3245 }
3246
3247 // If the first attribute of the list was set, then the list header
3248 // must be corrected as well.
3249 if( pLast )
3250 pLast->m_pNext = pNext;
3251 else if( ppHead )
3252 *ppHead = pNext;
3253
3254 if( bMoveBack )
3256
3257 return bRet;
3258}
3259
3261{
3262 // preliminary paragraph attributes are not allowed here, they could
3263 // be set here and then the pointers become invalid!
3264 OSL_ENSURE(m_aParaAttrs.empty(),
3265 "Danger: there are non-final paragraph attributes");
3266 m_aParaAttrs.clear();
3267
3268 // The list header is saved in the attribute
3269 HTMLAttr **ppHead = pAttr->m_ppHead;
3270
3271 OSL_ENSURE( ppHead, "no list header attribute found!" );
3272
3273 // Is the last started or an earlier started attribute being removed?
3274 HTMLAttr *pLast = nullptr;
3275 if( ppHead && pAttr != *ppHead )
3276 {
3277 // The last started attribute isn't being ended
3278
3279 // Then we look for attribute which was started immediately afterwards,
3280 // which has also not yet been ended (otherwise it would no longer be
3281 // in the list).
3282 pLast = *ppHead;
3283 while( pLast && pLast->GetNext() != pAttr )
3284 pLast = pLast->GetNext();
3285
3286 OSL_ENSURE( pLast, "Attribute not found in own list!" );
3287 }
3288
3289 // now delete the attribute
3290 HTMLAttr *pNext = pAttr->GetNext();
3291 HTMLAttr *pPrev = pAttr->GetPrev();
3292 //hold ref to xAttrTab until end of scope to ensure *ppHead validity
3293 std::shared_ptr<HTMLAttrTable> xKeepAlive(pAttr->m_xAttrTab);
3294 delete pAttr;
3295
3296 if( pPrev )
3297 {
3298 // The previous attributes must be set anyway.
3299 if( pNext )
3300 pNext->InsertPrev( pPrev );
3301 else
3302 {
3303 if (pPrev->m_bInsAtStart)
3304 m_aSetAttrTab.push_front( pPrev );
3305 else
3306 m_aSetAttrTab.push_back( pPrev );
3307 }
3308 }
3309
3310 // If the first attribute of the list was deleted, then the list header
3311 // must be corrected as well.
3312 if( pLast )
3313 pLast->m_pNext = pNext;
3314 else if( ppHead )
3315 *ppHead = pNext;
3316}
3317
3318void SwHTMLParser::SaveAttrTab(std::shared_ptr<HTMLAttrTable> const & rNewAttrTab)
3319{
3320 // preliminary paragraph attributes are not allowed here, they could
3321 // be set here and then the pointers become invalid!
3322 OSL_ENSURE(m_aParaAttrs.empty(),
3323 "Danger: there are non-final paragraph attributes");
3324 m_aParaAttrs.clear();
3325
3326 HTMLAttr** pHTMLAttributes = reinterpret_cast<HTMLAttr**>(m_xAttrTab.get());
3327 HTMLAttr** pSaveAttributes = reinterpret_cast<HTMLAttr**>(rNewAttrTab.get());
3328
3329 for (auto nCnt = sizeof(HTMLAttrTable) / sizeof(HTMLAttr*); nCnt--; ++pHTMLAttributes, ++pSaveAttributes)
3330 {
3331 *pSaveAttributes = *pHTMLAttributes;
3332
3333 HTMLAttr *pAttr = *pSaveAttributes;
3334 while (pAttr)
3335 {
3336 pAttr->SetHead(pSaveAttributes, rNewAttrTab);
3337 pAttr = pAttr->GetNext();
3338 }
3339
3340 *pHTMLAttributes = nullptr;
3341 }
3342}
3343
3344void SwHTMLParser::SplitAttrTab( std::shared_ptr<HTMLAttrTable> const & rNewAttrTab,
3345 bool bMoveEndBack )
3346{
3347 // preliminary paragraph attributes are not allowed here, they could
3348 // be set here and then the pointers become invalid!
3349 OSL_ENSURE(m_aParaAttrs.empty(),
3350 "Danger: there are non-final paragraph attributes");
3351 m_aParaAttrs.clear();
3352
3353 SwNodeIndex nEndIdx( m_pPam->GetPoint()->GetNode() );
3354
3355 // close all still open attributes and re-open them after the table
3356 HTMLAttr** pHTMLAttributes = reinterpret_cast<HTMLAttr**>(m_xAttrTab.get());
3357 HTMLAttr** pSaveAttributes = reinterpret_cast<HTMLAttr**>(rNewAttrTab.get());
3358 bool bSetAttr = true;
3359 const sal_Int32 nSttCnt = m_pPam->GetPoint()->GetContentIndex();
3360 sal_Int32 nEndCnt = nSttCnt;
3361
3362 if( bMoveEndBack )
3363 {
3364 SwNodeOffset nOldEnd = nEndIdx.GetIndex();
3365 SwNodeOffset nTmpIdx;
3366 if( ( nTmpIdx = m_xDoc->GetNodes().GetEndOfExtras().GetIndex()) >= nOldEnd ||
3367 ( nTmpIdx = m_xDoc->GetNodes().GetEndOfAutotext().GetIndex()) >= nOldEnd )
3368 {
3369 nTmpIdx = m_xDoc->GetNodes().GetEndOfInserts().GetIndex();
3370 }
3371 SwContentNode* pCNd = SwNodes::GoPrevious(&nEndIdx);
3372
3373 // Don't set attributes, when the PaM was moved outside of the content area.
3374 bSetAttr = pCNd && nTmpIdx < nEndIdx.GetIndex();
3375
3376 nEndCnt = (bSetAttr ? pCNd->Len() : 0);
3377 }
3378 for (auto nCnt = sizeof(HTMLAttrTable) / sizeof(HTMLAttr*); nCnt--; (++pHTMLAttributes, ++pSaveAttributes))
3379 {
3380 HTMLAttr *pAttr = *pHTMLAttributes;
3381 *pSaveAttributes = nullptr;
3382 while( pAttr )
3383 {
3384 HTMLAttr *pNext = pAttr->GetNext();
3385 HTMLAttr *pPrev = pAttr->GetPrev();
3386
3387 if( bSetAttr &&
3388 ( pAttr->GetStartParagraphIdx() < nEndIdx.GetIndex() ||
3389 (pAttr->GetStartParagraph() == nEndIdx &&
3390 pAttr->GetStartContent() != nEndCnt) ) )
3391 {
3392 // The attribute must be set before the list. We need the
3393 // original and therefore we clone it, because pointer to the
3394 // attribute exist in the other contexts. The Next-List is lost
3395 // in doing so, but the Previous-List is preserved.
3396 HTMLAttr *pSetAttr = pAttr->Clone( nEndIdx.GetNode(), nEndCnt );
3397
3398 if( pNext )
3399 pNext->InsertPrev( pSetAttr );
3400 else
3401 {
3402 if (pSetAttr->m_bInsAtStart)
3403 m_aSetAttrTab.push_front( pSetAttr );
3404 else
3405 m_aSetAttrTab.push_back( pSetAttr );
3406 }
3407 }
3408 else if( pPrev )
3409 {
3410 // If the attribute doesn't need to be set before the table, then
3411 // the previous attributes must still be set.
3412 if( pNext )
3413 pNext->InsertPrev( pPrev );
3414 else
3415 {
3416 if (pPrev->m_bInsAtStart)
3417 m_aSetAttrTab.push_front( pPrev );
3418 else
3419 m_aSetAttrTab.push_back( pPrev );
3420 }
3421 }
3422
3423 // set the start of the attribute anew and break link
3424 pAttr->Reset(m_pPam->GetPoint()->GetNode(), nSttCnt, pSaveAttributes, rNewAttrTab);
3425
3426 if (*pSaveAttributes)
3427 {
3428 HTMLAttr *pSAttr = *pSaveAttributes;
3429 while( pSAttr->GetNext() )
3430 pSAttr = pSAttr->GetNext();
3431 pSAttr->InsertNext( pAttr );
3432 }
3433 else
3434 *pSaveAttributes = pAttr;
3435
3436 pAttr = pNext;
3437 }
3438
3439 *pHTMLAttributes = nullptr;
3440 }
3441}
3442
3443void SwHTMLParser::RestoreAttrTab(std::shared_ptr<HTMLAttrTable> const & rNewAttrTab)
3444{
3445 // preliminary paragraph attributes are not allowed here, they could
3446 // be set here and then the pointers become invalid!
3447 OSL_ENSURE(m_aParaAttrs.empty(),
3448 "Danger: there are non-final paragraph attributes");
3449 m_aParaAttrs.clear();
3450
3451 HTMLAttr** pHTMLAttributes = reinterpret_cast<HTMLAttr**>(m_xAttrTab.get());
3452 HTMLAttr** pSaveAttributes = reinterpret_cast<HTMLAttr**>(rNewAttrTab.get());
3453
3454 for (auto nCnt = sizeof(HTMLAttrTable) / sizeof(HTMLAttr*); nCnt--; ++pHTMLAttributes, ++pSaveAttributes)
3455 {
3456 OSL_ENSURE(!*pHTMLAttributes, "The attribute table is not empty!");
3457
3458 *pHTMLAttributes = *pSaveAttributes;
3459
3460 HTMLAttr *pAttr = *pHTMLAttributes;
3461 while (pAttr)
3462 {
3463 OSL_ENSURE( !pAttr->GetPrev() || !pAttr->GetPrev()->m_ppHead,
3464 "Previous attribute has still a header" );
3465 pAttr->SetHead(pHTMLAttributes, m_xAttrTab);
3466 pAttr = pAttr->GetNext();
3467 }
3468
3469 *pSaveAttributes = nullptr;
3470 }
3471}
3472
3473void SwHTMLParser::InsertAttr( const SfxPoolItem& rItem, bool bInsAtStart )
3474{
3475 HTMLAttr* pTmp = new HTMLAttr(*m_pPam->GetPoint(), rItem, nullptr, std::shared_ptr<HTMLAttrTable>());
3476 if (bInsAtStart)
3477 m_aSetAttrTab.push_front( pTmp );
3478 else
3479 m_aSetAttrTab.push_back( pTmp );
3480}
3481
3482void SwHTMLParser::InsertAttrs( std::deque<std::unique_ptr<HTMLAttr>> rAttrs )
3483{
3484 while( !rAttrs.empty() )
3485 {
3486 std::unique_ptr<HTMLAttr> pAttr = std::move(rAttrs.front());
3487 InsertAttr( pAttr->GetItem(), false );
3488 rAttrs.pop_front();
3489 }
3490}
3491
3493{
3494 OUString aId, aStyle, aLang, aDir;
3495 OUString aClass;
3496
3497 const HTMLOptions& rHTMLOptions = GetOptions();
3498 for (size_t i = rHTMLOptions.size(); i; )
3499 {
3500 const HTMLOption& rOption = rHTMLOptions[--i];
3501 switch( rOption.GetToken() )
3502 {
3503 case HtmlOptionId::ID:
3504 aId = rOption.GetString();
3505 break;
3506 case HtmlOptionId::STYLE:
3507 aStyle = rOption.GetString();
3508 break;
3509 case HtmlOptionId::CLASS:
3510 aClass = rOption.GetString();
3511 break;
3512 case HtmlOptionId::LANG:
3513 aLang = rOption.GetString();
3514 break;
3515 case HtmlOptionId::DIR:
3516 aDir = rOption.GetString();
3517 break;
3518 default: break;
3519 }
3520 }
3521
3522 // create a new context
3523 std::unique_ptr<HTMLAttrContext> xCntxt(new HTMLAttrContext(nToken));
3524
3525 // parse styles
3526 if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) )
3527 {
3528 SfxItemSet aItemSet( m_xDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
3529 SvxCSS1PropertyInfo aPropInfo;
3530
3531 if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) )
3532 {
3533 if( HtmlTokenId::SPAN_ON != nToken || aClass.isEmpty() ||
3534 !CreateContainer( aClass, aItemSet, aPropInfo, xCntxt.get() ) )
3535 DoPositioning( aItemSet, aPropInfo, xCntxt.get() );
3536 InsertAttrs( aItemSet, aPropInfo, xCntxt.get(), true );
3537 }
3538 }
3539
3540 // save the context
3541 PushContext(xCntxt);
3542}
3543
3545 HTMLAttr **ppAttr, const SfxPoolItem & rItem,
3546 HTMLAttr **ppAttr2, const SfxPoolItem *pItem2,
3547 HTMLAttr **ppAttr3, const SfxPoolItem *pItem3 )
3548{
3549 OUString aId, aStyle, aClass, aLang, aDir;
3550
3551 const HTMLOptions& rHTMLOptions = GetOptions();
3552 for (size_t i = rHTMLOptions.size(); i; )
3553 {
3554 const HTMLOption& rOption = rHTMLOptions[--i];
3555 switch( rOption.GetToken() )
3556 {
3557 case HtmlOptionId::ID:
3558 aId = rOption.GetString();
3559 break;
3560 case HtmlOptionId::STYLE:
3561 aStyle = rOption.GetString();
3562 break;
3563 case HtmlOptionId::CLASS:
3564 aClass = rOption.GetString();
3565 break;
3566 case HtmlOptionId::LANG:
3567 aLang = rOption.GetString();
3568 break;
3569 case HtmlOptionId::DIR:
3570 aDir = rOption.GetString();
3571 break;
3572 default: break;
3573 }
3574 }
3575
3576 // create a new context
3577 std::unique_ptr<HTMLAttrContext> xCntxt(new HTMLAttrContext(nToken));
3578
3579 // parse styles
3580 if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) )
3581 {
3582 SfxItemSet aItemSet( m_xDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
3583 SvxCSS1PropertyInfo aPropInfo;
3584
3585 aItemSet.Put( rItem );
3586 if( pItem2 )
3587 aItemSet.Put( *pItem2 );
3588 if( pItem3 )
3589 aItemSet.Put( *pItem3 );
3590
3591 if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) )
3592 DoPositioning( aItemSet, aPropInfo, xCntxt.get() );
3593
3594 InsertAttrs( aItemSet, aPropInfo, xCntxt.get(), true );
3595 }
3596 else
3597 {
3598 InsertAttr( ppAttr ,rItem, xCntxt.get() );
3599 if( pItem2 )
3600 {
3601 OSL_ENSURE( ppAttr2, "missing table entry for item2" );
3602 InsertAttr( ppAttr2, *pItem2, xCntxt.get() );
3603 }
3604 if( pItem3 )
3605 {
3606 OSL_ENSURE( ppAttr3, "missing table entry for item3" );
3607 InsertAttr( ppAttr3, *pItem3, xCntxt.get() );
3608 }
3609 }
3610
3611 // save the context
3612 PushContext(xCntxt);
3613}
3614
3616{
3617 // fetch context
3618 std::unique_ptr<HTMLAttrContext> xCntxt(PopContext(getOnToken(nToken)));
3619 if (xCntxt)
3620 {
3621 // and maybe end the attributes
3622 EndContext(xCntxt.get());
3623 }
3624}
3625
3627{
3628 OUString aId, aStyle, aClass, aLang, aDir;
3629 sal_uInt16 nSize = 3;
3630
3631 const HTMLOptions& rHTMLOptions = GetOptions();
3632 for (size_t i = rHTMLOptions.size(); i; )
3633 {
3634 const HTMLOption& rOption = rHTMLOptions[--i];
3635 switch( rOption.GetToken() )
3636 {
3637 case HtmlOptionId::SIZE:
3638 nSize = o3tl::narrowing<sal_uInt16>(rOption.GetNumber());
3639 break;
3640 case HtmlOptionId::ID:
3641 aId = rOption.GetString();
3642 break;
3643 case HtmlOptionId::STYLE:
3644 aStyle = rOption.GetString();
3645 break;
3646 case HtmlOptionId::CLASS:
3647 aClass = rOption.GetString();
3648 break;
3649 case HtmlOptionId::LANG:
3650 aLang = rOption.GetString();
3651 break;
3652 case HtmlOptionId::DIR:
3653 aDir = rOption.GetString();
3654 break;
3655 default: break;
3656 }
3657 }
3658
3659 if( nSize < 1 )
3660 nSize = 1;
3661
3662 if( nSize > 7 )
3663 nSize = 7;
3664
3665 // create a new context
3666 std::unique_ptr<HTMLAttrContext> xCntxt(new HTMLAttrContext(HtmlTokenId::BASEFONT_ON));
3667
3668 // parse styles
3669 if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) )
3670 {
3671 SfxItemSet aItemSet( m_xDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
3672 SvxCSS1PropertyInfo aPropInfo;
3673
3674 //CJK has different defaults
3675 SvxFontHeightItem aFontHeight( m_aFontHeights[nSize-1], 100, RES_CHRATR_FONTSIZE );
3676 aItemSet.Put( aFontHeight );
3677 SvxFontHeightItem aFontHeightCJK( m_aFontHeights[nSize-1], 100, RES_CHRATR_CJK_FONTSIZE );
3678 aItemSet.Put( aFontHeightCJK );
3679 //Complex type can contain so many types of letters,
3680 //that it's not really worthy to bother, IMO.
3681 //Still, I have set a default.
3682 SvxFontHeightItem aFontHeightCTL( m_aFontHeights[nSize-1], 100, RES_CHRATR_CTL_FONTSIZE );
3683 aItemSet.Put( aFontHeightCTL );
3684
3685 if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) )
3686 DoPositioning( aItemSet, aPropInfo, xCntxt.get() );
3687
3688 InsertAttrs( aItemSet, aPropInfo, xCntxt.get(), true );
3689 }
3690 else
3691 {
3692 SvxFontHeightItem aFontHeight( m_aFontHeights[nSize-1], 100, RES_CHRATR_FONTSIZE );
3693 InsertAttr( &m_xAttrTab->pFontHeight, aFontHeight, xCntxt.get() );
3694 SvxFontHeightItem aFontHeightCJK( m_aFontHeights[nSize-1], 100, RES_CHRATR_CJK_FONTSIZE );
3695 InsertAttr( &m_xAttrTab->pFontHeightCJK, aFontHeightCJK, xCntxt.get() );
3696 SvxFontHeightItem aFontHeightCTL( m_aFontHeights[nSize-1], 100, RES_CHRATR_CTL_FONTSIZE );
3697 InsertAttr( &m_xAttrTab->pFontHeightCTL, aFontHeightCTL, xCntxt.get() );
3698 }
3699
3700 // save the context
3701 PushContext(xCntxt);
3702
3703 // save the font size
3704 m_aBaseFontStack.push_back( nSize );
3705}
3706
3708{
3709 EndTag( HtmlTokenId::BASEFONT_ON );
3710
3711 // avoid stack underflow in tables
3712 if( m_aBaseFontStack.size() > m_nBaseFontStMin )
3713 m_aBaseFontStack.erase( m_aBaseFontStack.begin() + m_aBaseFontStack.size() - 1 );
3714}
3715
3717{
3718 sal_uInt16 nBaseSize =
3721 : 3 );
3722 sal_uInt16 nFontSize =
3723 ( m_aFontStack.size() > m_nFontStMin
3725 : nBaseSize );
3726
3727 OUString aFace, aId, aStyle, aClass, aLang, aDir;
3728 Color aColor;
3729 sal_uLong nFontHeight = 0; // actual font height to set
3730 sal_uInt16 nSize = 0; // font height in Netscape notation (1-7)
3731 bool bColor = false;
3732
3733 const HTMLOptions& rHTMLOptions = GetOptions();
3734 for (size_t i = rHTMLOptions.size(); i; )
3735 {
3736 const HTMLOption& rOption = rHTMLOptions[--i];
3737 switch( rOption.GetToken() )
3738 {
3739 case HtmlOptionId::SIZE:
3740 if( HtmlTokenId::FONT_ON==nToken && !rOption.GetString().isEmpty() )
3741 {
3742 sal_Int32 nSSize;
3743 if( '+' == rOption.GetString()[0] ||
3744 '-' == rOption.GetString()[0] )
3745 nSSize = o3tl::saturating_add<sal_Int32>(nBaseSize, rOption.GetSNumber());
3746 else
3747 nSSize = static_cast<sal_Int32>(rOption.GetNumber());
3748
3749 if( nSSize < 1 )
3750 nSSize = 1;
3751 else if( nSSize > 7 )
3752 nSSize = 7;
3753
3754 nSize = o3tl::narrowing<sal_uInt16>(nSSize);
3755 nFontHeight = m_aFontHeights[nSize-1];
3756 }
3757 break;
3758 case HtmlOptionId::COLOR:
3759 if( HtmlTokenId::FONT_ON==nToken )
3760 {
3761 rOption.GetColor( aColor );
3762 bColor = true;
3763 }
3764 break;
3765 case HtmlOptionId::FACE:
3766 if( HtmlTokenId::FONT_ON==nToken )
3767 aFace = rOption.GetString();
3768 break;
3769 case HtmlOptionId::ID:
3770 aId = rOption.GetString();
3771 break;
3772 case HtmlOptionId::STYLE:
3773 aStyle = rOption.GetString();
3774 break;
3775 case HtmlOptionId::CLASS:
3776 aClass = rOption.GetString();
3777 break;
3778 case HtmlOptionId::LANG:
3779 aLang = rOption.GetString();
3780 break;
3781 case HtmlOptionId::DIR:
3782 aDir = rOption.GetString();
3783 break;
3784 default: break;
3785 }
3786 }
3787
3788 if( HtmlTokenId::FONT_ON != nToken )
3789 {
3790 // HTML_BIGPRINT_ON or HTML_SMALLPRINT_ON
3791
3792 // In headings the current heading sets the font height
3793 // and not BASEFONT.
3794 const SwFormatColl *pColl = GetCurrFormatColl();
3795 sal_uInt16 nPoolId = pColl ? pColl->GetPoolFormatId() : 0;
3796 if( nPoolId>=RES_POOLCOLL_HEADLINE1 &&
3797 nPoolId<=RES_POOLCOLL_HEADLINE6 )
3798 {
3799 // If the font height in the heading wasn't changed yet,
3800 // then take the one from the style.
3801 if( m_nFontStHeadStart==m_aFontStack.size() )
3802 nFontSize = static_cast< sal_uInt16 >(6 - (nPoolId - RES_POOLCOLL_HEADLINE1));
3803 }
3804 else
3805 nPoolId = 0;
3806
3807 if( HtmlTokenId::BIGPRINT_ON == nToken )
3808 nSize = ( nFontSize<7 ? nFontSize+1 : 7 );
3809 else
3810 nSize = ( nFontSize>1 ? nFontSize-1 : 1 );
3811
3812 // If possible in headlines we fetch the new font height
3813 // from the style.
3814 if( nPoolId && nSize>=1 && nSize <=6 )
3815 nFontHeight =
3816 m_pCSS1Parser->GetTextCollFromPool(
3817 RES_POOLCOLL_HEADLINE1+6-nSize )->GetSize().GetHeight();
3818 else
3819 nFontHeight = m_aFontHeights[nSize-1];
3820 }
3821
3822 OSL_ENSURE( !nSize == !nFontHeight, "HTML-Font-Size != Font-Height" );
3823
3824 OUString aFontName;
3825 const OUString aStyleName;
3826 FontFamily eFamily = FAMILY_DONTKNOW; // family and pitch,
3827 FontPitch ePitch = PITCH_DONTKNOW; // if not found
3828 rtl_TextEncoding eEnc = osl_getThreadTextEncoding();
3829
3830 if( !aFace.isEmpty() && !m_pCSS1Parser->IsIgnoreFontFamily() )
3831 {
3832 const FontList *pFList = nullptr;
3833 SwDocShell *pDocSh = m_xDoc->GetDocShell();
3834 if( pDocSh )
3835 {
3836 const SvxFontListItem *pFListItem =
3837 static_cast<const SvxFontListItem *>(pDocSh->GetItem(SID_ATTR_CHAR_FONTLIST));
3838 if( pFListItem )
3839 pFList = pFListItem->GetFontList();
3840 }
3841
3842 bool bFound = false;
3843 sal_Int32 nStrPos = 0;
3844 while( nStrPos!= -1 )
3845 {
3846 OUString aFName = aFace.getToken( 0, ',', nStrPos );
3847 aFName = comphelper::string::strip(aFName, ' ');
3848 if( !aFName.isEmpty() )
3849 {
3850 if( !bFound && pFList )
3851 {
3852 sal_Handle hFont = pFList->GetFirstFontMetric( aFName );
3853 if( nullptr != hFont )
3854 {
3855 const FontMetric& rFMetric = FontList::GetFontMetric( hFont );
3856 if( RTL_TEXTENCODING_DONTKNOW != rFMetric.GetCharSet() )
3857 {
3858 bFound = true;
3859 if( RTL_TEXTENCODING_SYMBOL == rFMetric.GetCharSet() )
3860 eEnc = RTL_TEXTENCODING_SYMBOL;
3861 }
3862 }
3863 }
3864 if( !aFontName.isEmpty() )
3865 aFontName += ";";
3866 aFontName += aFName;
3867 }
3868 }
3869 }
3870
3871 // create a new context
3872 std::unique_ptr<HTMLAttrContext> xCntxt(new HTMLAttrContext(nToken));
3873
3874 // parse styles
3875 if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) )
3876 {
3877 SfxItemSet aItemSet( m_xDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
3878 SvxCSS1PropertyInfo aPropInfo;
3879
3880 if( nFontHeight )
3881 {
3882 SvxFontHeightItem aFontHeight( nFontHeight, 100, RES_CHRATR_FONTSIZE );
3883 aItemSet.Put( aFontHeight );
3884 SvxFontHeightItem aFontHeightCJK( nFontHeight, 100, RES_CHRATR_CJK_FONTSIZE );
3885 aItemSet.Put( aFontHeightCJK );
3886 SvxFontHeightItem aFontHeightCTL( nFontHeight, 100, RES_CHRATR_CTL_FONTSIZE );
3887 aItemSet.Put( aFontHeightCTL );
3888 }
3889 if( bColor )
3890 aItemSet.Put( SvxColorItem(aColor, RES_CHRATR_COLOR) );
3891 if( !aFontName.isEmpty() )
3892 {
3893 SvxFontItem aFont( eFamily, aFontName, aStyleName, ePitch, eEnc, RES_CHRATR_FONT );
3894 aItemSet.Put( aFont );
3895 SvxFontItem aFontCJK( eFamily, aFontName, aStyleName, ePitch, eEnc, RES_CHRATR_CJK_FONT );
3896 aItemSet.Put( aFontCJK );
3897 SvxFontItem aFontCTL( eFamily, aFontName, aStyleName, ePitch, eEnc, RES_CHRATR_CTL_FONT );
3898 aItemSet.Put( aFontCTL );
3899 }
3900
3901 if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) )
3902 DoPositioning( aItemSet, aPropInfo, xCntxt.get() );
3903
3904 InsertAttrs( aItemSet, aPropInfo, xCntxt.get(), true );
3905 }
3906 else
3907 {
3908 if( nFontHeight )
3909 {
3910 SvxFontHeightItem aFontHeight( nFontHeight, 100, RES_CHRATR_FONTSIZE );
3911 InsertAttr( &m_xAttrTab->pFontHeight, aFontHeight, xCntxt.get() );
3912 SvxFontHeightItem aFontHeightCJK( nFontHeight, 100, RES_CHRATR_CJK_FONTSIZE );
3913 InsertAttr( &m_xAttrTab->pFontHeight, aFontHeightCJK, xCntxt.get() );
3914 SvxFontHeightItem aFontHeightCTL( nFontHeight, 100, RES_CHRATR_CTL_FONTSIZE );
3915 InsertAttr( &m_xAttrTab->pFontHeight, aFontHeightCTL, xCntxt.get() );
3916 }
3917 if( bColor )
3918 InsertAttr( &m_xAttrTab->pFontColor, SvxColorItem(aColor, RES_CHRATR_COLOR), xCntxt.get() );
3919 if( !aFontName.isEmpty() )
3920 {
3921 SvxFontItem aFont( eFamily, aFontName, aStyleName, ePitch, eEnc, RES_CHRATR_FONT );
3922 InsertAttr( &m_xAttrTab->pFont, aFont, xCntxt.get() );
3923 SvxFontItem aFontCJK( eFamily, aFontName, aStyleName, ePitch, eEnc, RES_CHRATR_CJK_FONT );
3924 InsertAttr( &m_xAttrTab->pFont, aFontCJK, xCntxt.get() );
3925 SvxFontItem aFontCTL( eFamily, aFontName, aStyleName, ePitch, eEnc, RES_CHRATR_CTL_FONT );
3926 InsertAttr( &m_xAttrTab->pFont, aFontCTL, xCntxt.get() );
3927 }
3928 }
3929
3930 // save the context
3931 PushContext(xCntxt);
3932
3933 m_aFontStack.push_back( nSize );
3934}
3935
3937{
3938 EndTag( nToken );
3939
3940 // avoid stack underflow in tables
3941 if( m_aFontStack.size() > m_nFontStMin )
3942 m_aFontStack.erase( m_aFontStack.begin() + m_aFontStack.size() - 1 );
3943}
3944
3946{
3947 if( m_pPam->GetPoint()->GetContentIndex() )
3949 else
3950 AddParSpace();
3951
3952 m_eParaAdjust = SvxAdjust::End;
3953 OUString aId, aStyle, aClass, aLang, aDir;
3954
3955 const HTMLOptions& rHTMLOptions = GetOptions();
3956 for (size_t i = rHTMLOptions.size(); i; )
3957 {
3958 const HTMLOption& rOption = rHTMLOptions[--i];
3959 switch( rOption.GetToken() )
3960 {
3961 case HtmlOptionId::ID:
3962 aId = rOption.GetString();
3963 break;
3964 case HtmlOptionId::ALIGN:
3966 break;
3967 case HtmlOptionId::STYLE:
3968 aStyle = rOption.GetString();
3969 break;
3970 case HtmlOptionId::CLASS:
3971 aClass = rOption.GetString();
3972 break;
3973 case HtmlOptionId::LANG:
3974 aLang = rOption.GetString();
3975 break;
3976 case HtmlOptionId::DIR:
3977 aDir = rOption.GetString();
3978 break;
3979 default: break;
3980 }
3981 }
3982
3983 // create a new context
3984 std::unique_ptr<HTMLAttrContext> xCntxt(
3985 !aClass.isEmpty() ? new HTMLAttrContext( HtmlTokenId::PARABREAK_ON,
3986 RES_POOLCOLL_TEXT, aClass )
3987 : new HTMLAttrContext( HtmlTokenId::PARABREAK_ON ));
3988
3989 // parse styles (Don't consider class. This is only possible as long as none of
3990 // the CSS1 properties of the class must be formatted hard!!!)
3991 if (HasStyleOptions(aStyle, aId, {}, &aLang, &aDir))
3992 {
3993 SfxItemSet aItemSet( m_xDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
3994 SvxCSS1PropertyInfo aPropInfo;
3995
3996 if (ParseStyleOptions(aStyle, aId, OUString(), aItemSet, aPropInfo, &aLang, &aDir))
3997 {
3998 OSL_ENSURE( aClass.isEmpty() || !m_pCSS1Parser->GetClass( aClass ),
3999 "Class is not considered" );
4000 DoPositioning( aItemSet, aPropInfo, xCntxt.get() );
4001 InsertAttrs( aItemSet, aPropInfo, xCntxt.get() );
4002 }
4003 }
4004
4005 if( SvxAdjust::End != m_eParaAdjust )
4007
4008 // and push on stack
4009 PushContext( xCntxt );
4010
4011 // set the current style or its attributes
4012 SetTextCollAttrs( !aClass.isEmpty() ? m_aContexts.back().get() : nullptr );
4013
4014 // progress bar
4015 ShowStatline();
4016
4017 OSL_ENSURE( m_nOpenParaToken == HtmlTokenId::NONE, "Now an open paragraph element will be lost." );
4018 m_nOpenParaToken = HtmlTokenId::PARABREAK_ON;
4019}
4020
4021void SwHTMLParser::EndPara( bool bReal )
4022{
4023 if (HtmlTokenId::LI_ON==m_nOpenParaToken && m_xTable)
4024 {
4025#if OSL_DEBUG_LEVEL > 0
4026 const SwNumRule *pNumRule = m_pPam->GetPointNode().GetTextNode()->GetNumRule();
4027 OSL_ENSURE( pNumRule, "Where is the NumRule" );
4028#endif
4029 }
4030
4031 // Netscape skips empty paragraphs, we do the same; unless in XHTML mode, which prefers mapping
4032 // the source document to the doc model 1:1 if possible.
4033 if( bReal )
4034 {
4037 else
4038 AddParSpace();
4039 }
4040
4041 // If a DD or DT was open, it's an implied definition list,
4042 // which must be closed now.
4043 if( (m_nOpenParaToken == HtmlTokenId::DT_ON || m_nOpenParaToken == HtmlTokenId::DD_ON) &&
4045 {
4047 }
4048
4049 // Pop the context of the stack. It can also be from an
4050 // implied opened definition list.
4051 std::unique_ptr<HTMLAttrContext> xCntxt(
4052 PopContext( m_nOpenParaToken != HtmlTokenId::NONE ? getOnToken(m_nOpenParaToken) : HtmlTokenId::PARABREAK_ON ));
4053
4054 // close attribute
4055 if (xCntxt)
4056 {
4057 EndContext(xCntxt.get());
4058 SetAttr(); // because of JavaScript set paragraph attributes as fast as possible
4059 xCntxt.reset();
4060 }
4061
4062 // reset the existing style
4063 if( bReal )
4065
4066 m_nOpenParaToken = HtmlTokenId::NONE;
4067}
4068
4070{
4071 m_eParaAdjust = SvxAdjust::End;
4072
4073 OUString aId, aStyle, aClass, aLang, aDir;
4074
4075 const HTMLOptions& rHTMLOptions = GetOptions();
4076 for (size_t i = rHTMLOptions.size(); i; )
4077 {
4078 const HTMLOption& rOption = rHTMLOptions[--i];
4079 switch( rOption.GetToken() )
4080 {
4081 case HtmlOptionId::ID:
4082 aId = rOption.GetString();
4083 break;
4084 case HtmlOptionId::ALIGN:
4086 break;
4087 case HtmlOptionId::STYLE:
4088 aStyle = rOption.GetString();
4089 break;
4090 case HtmlOptionId::CLASS:
4091 aClass = rOption.GetString();
4092 break;
4093 case HtmlOptionId::LANG:
4094 aLang = rOption.GetString();
4095 break;
4096 case HtmlOptionId::DIR:
4097 aDir = rOption.GetString();
4098 break;
4099 default: break;
4100 }
4101 }
4102
4103 // open a new paragraph
4104 if( m_pPam->GetPoint()->GetContentIndex() )
4106 else
4107 AddParSpace();
4108
4109 // search for the matching style
4110 sal_uInt16 nTextColl;
4111 switch( nToken )
4112 {
4113 case HtmlTokenId::HEAD1_ON: nTextColl = RES_POOLCOLL_HEADLINE1; break;
4114 case HtmlTokenId::HEAD2_ON: nTextColl = RES_POOLCOLL_HEADLINE2; break;
4115 case HtmlTokenId::HEAD3_ON: nTextColl = RES_POOLCOLL_HEADLINE3; break;
4116 case HtmlTokenId::HEAD4_ON: nTextColl = RES_POOLCOLL_HEADLINE4; break;
4117 case HtmlTokenId::HEAD5_ON: nTextColl = RES_POOLCOLL_HEADLINE5; break;
4118 case HtmlTokenId::HEAD6_ON: nTextColl = RES_POOLCOLL_HEADLINE6; break;
4119 default: nTextColl = RES_POOLCOLL_STANDARD; break;
4120 }
4121
4122 // create the context
4123 std::unique_ptr<HTMLAttrContext> xCntxt(new HTMLAttrContext(nToken, nTextColl, aClass));
4124
4125 // parse styles (regarding class see also NewPara)
4126 if (HasStyleOptions(aStyle, aId, {}, &aLang, &aDir))
4127 {
4128 SfxItemSet aItemSet( m_xDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
4129 SvxCSS1PropertyInfo aPropInfo;
4130
4131 if (ParseStyleOptions(aStyle, aId, OUString(), aItemSet, aPropInfo, &aLang, &aDir))
4132 {
4133 OSL_ENSURE( aClass.isEmpty() || !m_pCSS1Parser->GetClass( aClass ),
4134 "Class is not considered" );
4135 DoPositioning( aItemSet, aPropInfo, xCntxt.get() );
4136 InsertAttrs( aItemSet, aPropInfo, xCntxt.get() );
4137 }
4138 }
4139
4140 if( SvxAdjust::End != m_eParaAdjust )
4142
4143 // and push on stack
4144 PushContext(xCntxt);
4145
4146 // set the current style or its attributes
4147 SetTextCollAttrs(m_aContexts.back().get());
4148
4150
4151 // progress bar
4152 ShowStatline();
4153}
4154
4156{
4157 // open a new paragraph
4158 if( m_pPam->GetPoint()->GetContentIndex() )
4160 else
4161 AddParSpace();
4162
4163 // search context matching the token and fetch it from stack
4164 std::unique_ptr<HTMLAttrContext> xCntxt;
4165 auto nPos = m_aContexts.size();
4166 while( !xCntxt && nPos>m_nContextStMin )
4167 {
4168 switch( m_aContexts[--nPos]->GetToken() )
4169 {
4170 case HtmlTokenId::HEAD1_ON:
4171 case HtmlTokenId::HEAD2_ON:
4172 case HtmlTokenId::HEAD3_ON:
4173 case HtmlTokenId::HEAD4_ON:
4174 case HtmlTokenId::HEAD5_ON:
4175 case HtmlTokenId::HEAD6_ON:
4176 xCntxt = std::move(m_aContexts[nPos]);
4177 m_aContexts.erase( m_aContexts.begin() + nPos );
4178 break;
4179 default: break;
4180 }
4181 }
4182
4183 // and now end attributes
4184 if (xCntxt)
4185 {
4186 EndContext(xCntxt.get());
4187 SetAttr(); // because of JavaScript set paragraph attributes as fast as possible
4188 xCntxt.reset();
4189 }
4190
4191 // reset existing style
4193
4195}
4196
4197void SwHTMLParser::NewTextFormatColl( HtmlTokenId nToken, sal_uInt16 nColl )
4198{
4199 OUString aId, aStyle, aClass, aLang, aDir;
4200
4201 const HTMLOptions& rHTMLOptions = GetOptions();
4202 for (size_t i = rHTMLOptions.size(); i; )
4203 {
4204 const HTMLOption& rOption = rHTMLOptions[--i];
4205 switch( rOption.GetToken() )
4206 {
4207 case HtmlOptionId::ID:
4208 aId = rOption.GetString();
4209 break;
4210 case HtmlOptionId::STYLE:
4211 aStyle = rOption.GetString();
4212 break;
4213 case HtmlOptionId::CLASS:
4214 aClass = rOption.GetString();
4215 break;
4216 case HtmlOptionId::LANG:
4217 aLang = rOption.GetString();
4218 break;
4219 case HtmlOptionId::DIR:
4220 aDir = rOption.GetString();
4221 break;
4222 default: break;
4223 }
4224 }
4225
4226 // open a new paragraph
4228 switch( nToken )
4229 {
4230 case HtmlTokenId::LISTING_ON:
4231 case HtmlTokenId::XMP_ON:
4232 // These both tags will be mapped to the PRE style. For the case that a
4233 // a CLASS exists we will delete it so that we don't get the CLASS of
4234 // the PRE style.
4235 aClass.clear();
4236 [[fallthrough]];
4237 case HtmlTokenId::BLOCKQUOTE_ON:
4238 case HtmlTokenId::BLOCKQUOTE30_ON:
4239 case HtmlTokenId::PREFORMTXT_ON:
4240 eMode = AM_SPACE;
4241 break;
4242 case HtmlTokenId::ADDRESS_ON:
4243 eMode = AM_NOSPACE; // ADDRESS can follow on a <P> without </P>
4244 break;
4245 case HtmlTokenId::DT_ON:
4246 case HtmlTokenId::DD_ON:
4248 break;
4249 default:
4250 OSL_ENSURE( false, "unknown style" );
4251 break;
4252 }
4253 if( m_pPam->GetPoint()->GetContentIndex() )
4255 else if( AM_SPACE==eMode )
4256 AddParSpace();
4257
4258 // ... and save in a context
4259 std::unique_ptr<HTMLAttrContext> xCntxt(new HTMLAttrContext(nToken, nColl, aClass));
4260
4261 // parse styles (regarding class see also NewPara)
4262 if (HasStyleOptions(aStyle, aId, {}, &aLang, &aDir))
4263 {
4264 SfxItemSet aItemSet( m_xDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
4265 SvxCSS1PropertyInfo aPropInfo;
4266
4267 if (ParseStyleOptions(aStyle, aId, OUString(), aItemSet, aPropInfo, &aLang, &aDir))
4268 {
4269 OSL_ENSURE( aClass.isEmpty() || !m_pCSS1Parser->GetClass( aClass ),
4270 "Class is not considered" );
4271 DoPositioning( aItemSet, aPropInfo, xCntxt.get() );
4272 InsertAttrs( aItemSet, aPropInfo, xCntxt.get() );
4273 }
4274 }
4275
4276 PushContext(xCntxt);
4277
4278 // set the new style
4279 SetTextCollAttrs(m_aContexts.back().get());
4280
4281 // update progress bar
4282 ShowStatline();
4283}
4284
4286{
4288 switch( getOnToken(nToken) )
4289 {
4290 case HtmlTokenId::BLOCKQUOTE_ON:
4291 case HtmlTokenId::BLOCKQUOTE30_ON:
4292 case HtmlTokenId::PREFORMTXT_ON:
4293 case HtmlTokenId::LISTING_ON:
4294 case HtmlTokenId::XMP_ON:
4295 eMode = AM_SPACE;
4296 break;
4297 case HtmlTokenId::ADDRESS_ON:
4298 case HtmlTokenId::DT_ON:
4299 case HtmlTokenId::DD_ON:
4301 break;
4302 default:
4303 OSL_ENSURE( false, "unknown style" );
4304 break;
4305 }
4306 if( m_pPam->GetPoint()->GetContentIndex() )
4308 else if( AM_SPACE==eMode )
4309 AddParSpace();
4310
4311 // pop current context of stack
4312 std::unique_ptr<HTMLAttrContext> xCntxt(PopContext(getOnToken(nToken)));
4313
4314 // and now end attributes
4315 if (xCntxt)
4316 {
4317 EndContext(xCntxt.get());
4318 SetAttr(); // because of JavaScript set paragraph attributes as fast as possible
4319 xCntxt.reset();
4320 }
4321
4322 // reset existing style
4324}
4325
4327{
4328 OUString aId, aStyle, aClass, aLang, aDir;
4329
4330 const HTMLOptions& rHTMLOptions = GetOptions();
4331 for (size_t i = rHTMLOptions.size(); i; )
4332 {
4333 const HTMLOption& rOption = rHTMLOptions[--i];
4334 switch( rOption.GetToken() )
4335 {
4336 case HtmlOptionId::ID:
4337 aId = rOption.GetString();
4338 break;
4339 case HtmlOptionId::STYLE:
4340 aStyle = rOption.GetString();
4341 break;
4342 case HtmlOptionId::CLASS:
4343 aClass = rOption.GetString();
4344 break;
4345 case HtmlOptionId::LANG:
4346 aLang = rOption.GetString();
4347 break;
4348 case HtmlOptionId::DIR:
4349 aDir = rOption.GetString();
4350 break;
4351 default: break;
4352 }
4353 }
4354
4355 // open a new paragraph
4356 bool bSpace = (GetNumInfo().GetDepth() + m_nDefListDeep) == 0;
4357 if( m_pPam->GetPoint()->GetContentIndex() )
4359 else if( bSpace )
4360 AddParSpace();
4361
4362 // one level more
4364
4365 bool bInDD = false, bNotInDD = false;
4366 auto nPos = m_aContexts.size();
4367 while( !bInDD && !bNotInDD && nPos>m_nContextStMin )
4368 {
4369 HtmlTokenId nCntxtToken = m_aContexts[--nPos]->GetToken();
4370 switch( nCntxtToken )
4371 {
4372 case HtmlTokenId::DEFLIST_ON:
4373 case HtmlTokenId::DIRLIST_ON:
4374 case HtmlTokenId::MENULIST_ON:
4375 case HtmlTokenId::ORDERLIST_ON:
4376 case HtmlTokenId::UNORDERLIST_ON:
4377 bNotInDD = true;
4378 break;
4379 case HtmlTokenId::DD_ON:
4380 bInDD = true;
4381 break;
4382 default: break;
4383 }
4384 }
4385
4386 // ... and save in a context
4387 std::unique_ptr<HTMLAttrContext> xCntxt(new HTMLAttrContext(HtmlTokenId::DEFLIST_ON));
4388
4389 // in it save also the margins
4390 sal_uInt16 nLeft=0, nRight=0;
4391 short nIndent=0;
4392 GetMarginsFromContext( nLeft, nRight, nIndent );
4393
4394 // The indentation, which already results from a DL, correlates with a DT
4395 // on the current level and this correlates to a DD from the previous level.
4396 // For a level >=2 we must add DD distance.
4397 if( !bInDD && m_nDefListDeep > 1 )
4398 {
4399
4400 // and the one of the DT-style of the current level
4401 SvxLRSpaceItem rLRSpace =
4402 m_pCSS1Parser->GetTextFormatColl(RES_POOLCOLL_HTML_DD, OUString())
4403 ->GetLRSpace();
4404 nLeft = nLeft + static_cast< sal_uInt16 >(rLRSpace.GetTextLeft());
4405 }
4406
4407 xCntxt->SetMargins( nLeft, nRight, nIndent );
4408
4409 // parse styles
4410 if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) )
4411 {
4412 SfxItemSet aItemSet( m_xDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
4413 SvxCSS1PropertyInfo aPropInfo;
4414
4415 if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) )
4416 {
4417 DoPositioning( aItemSet, aPropInfo, xCntxt.get() );
4418 InsertAttrs( aItemSet, aPropInfo, xCntxt.get() );
4419 }
4420 }
4421
4422 PushContext(xCntxt);
4423
4424 // set the attributes of the new style
4425 if( m_nDefListDeep > 1 )
4426 SetTextCollAttrs(m_aContexts.back().get());
4427}
4428
4430{
4431 bool bSpace = (GetNumInfo().GetDepth() + m_nDefListDeep) == 1;
4432 if( m_pPam->GetPoint()->GetContentIndex() )
4434 else if( bSpace )
4435 AddParSpace();
4436
4437 // one level less
4438 if( m_nDefListDeep > 0 )
4440
4441 // pop current context of stack
4442 std::unique_ptr<HTMLAttrContext> xCntxt(PopContext(HtmlTokenId::DEFLIST_ON));
4443
4444 // and now end attributes
4445 if (xCntxt)
4446 {
4447 EndContext(xCntxt.get());
4448 SetAttr(); // because of JavaScript set paragraph attributes as fast as possible
4449 xCntxt.reset();
4450 }
4451
4452 // and set style
4454}
4455
4457{
4458 // determine if the DD/DT exist in a DL
4459 bool bInDefList = false, bNotInDefList = false;
4460 auto nPos = m_aContexts.size();
4461 while( !bInDefList && !bNotInDefList && nPos>m_nContextStMin )
4462 {
4463 HtmlTokenId nCntxtToken = m_aContexts[--nPos]->GetToken();
4464 switch( nCntxtToken )
4465 {
4466 case HtmlTokenId::DEFLIST_ON:
4467 bInDefList = true;
4468 break;
4469 case HtmlTokenId::DIRLIST_ON:
4470 case HtmlTokenId::MENULIST_ON:
4471 case HtmlTokenId::ORDERLIST_ON:
4472 case HtmlTokenId::UNORDERLIST_ON:
4473 bNotInDefList = true;
4474 break;
4475 default: break;
4476 }
4477 }
4478
4479 // if not, then implicitly open a new DL
4480 if( !bInDefList )
4481 {
4483 OSL_ENSURE( m_nOpenParaToken == HtmlTokenId::NONE,
4484 "Now an open paragraph element will be lost." );
4486 }
4487
4488 NewTextFormatColl( nToken, static_cast< sal_uInt16 >(nToken==HtmlTokenId::DD_ON ? RES_POOLCOLL_HTML_DD
4490}
4491
4493{
4494 // open a new paragraph
4495 if( nToken == HtmlTokenId::NONE && m_pPam->GetPoint()->GetContentIndex() )
4497
4498 // search context matching the token and fetch it from stack
4500 std::unique_ptr<HTMLAttrContext> xCntxt;
4501 auto nPos = m_aContexts.size();
4502 while( !xCntxt && nPos>m_nContextStMin )
4503 {
4504 HtmlTokenId nCntxtToken = m_aContexts[--nPos]->GetToken();
4505 switch( nCntxtToken )
4506 {
4507 case HtmlTokenId::DD_ON:
4508 case HtmlTokenId::DT_ON:
4509 if( nToken == HtmlTokenId::NONE || nToken == nCntxtToken )
4510 {
4511 xCntxt = std::move(m_aContexts[nPos]);
4512 m_aContexts.erase( m_aContexts.begin() + nPos );
4513 }
4514 break;
4515 case HtmlTokenId::DEFLIST_ON:
4516 // don't look at DD/DT outside the current DefList
4517 case HtmlTokenId::DIRLIST_ON:
4518 case HtmlTokenId::MENULIST_ON:
4519 case HtmlTokenId::ORDERLIST_ON:
4520 case HtmlTokenId::UNORDERLIST_ON:
4521 // and also not outside another list
4523 break;
4524 default: break;
4525 }
4526 }
4527
4528 // and now end attributes
4529 if (xCntxt)
4530 {
4531 EndContext(xCntxt.get());
4532 SetAttr(); // because of JavaScript set paragraph attributes as fast as possible
4533 }
4534}
4535
4545bool SwHTMLParser::HasCurrentParaFlys( bool bNoSurroundOnly,
4546 bool bSurroundOnly ) const
4547{
4548 SwNode& rNode = m_pPam->GetPoint()->GetNode();
4549
4550 const SwFrameFormats& rFrameFormatTable = *m_xDoc->GetSpzFrameFormats();
4551
4552 bool bFound = false;
4553 for ( size_t i=0; i<rFrameFormatTable.size(); i++ )
4554 {
4555 const SwFrameFormat *const pFormat = rFrameFormatTable[i];
4556 SwFormatAnchor const*const pAnchor = &pFormat->GetAnchor();
4557 // A frame was found, when
4558 // - it is paragraph-bound, and
4559 // - is anchored in current paragraph, and
4560 // - every paragraph-bound frame counts, or
4561 // - (only frames without wrapping count and) the frame doesn't have
4562 // a wrapping
4563 SwNode const*const pAnchorNode = pAnchor->GetAnchorNode();
4564 if (pAnchorNode &&
4565 ((RndStdIds::FLY_AT_PARA == pAnchor->GetAnchorId()) ||
4566 (RndStdIds::FLY_AT_CHAR == pAnchor->GetAnchorId())) &&
4567 *pAnchorNode == rNode )
4568 {
4569 if( !(bNoSurroundOnly || bSurroundOnly) )
4570 {
4571 bFound = true;
4572 break;
4573 }
4574 else
4575 {
4576 // When looking for frames with wrapping, also disregard
4577 // ones with wrap-through. In this case it's (still) HIDDEN-Controls,
4578 // and you don't want to evade those when positioning.
4579 css::text::WrapTextMode eSurround = pFormat->GetSurround().GetSurround();
4580 if( bNoSurroundOnly )
4581 {
4582 if( css::text::WrapTextMode_NONE==eSurround )
4583 {
4584 bFound = true;
4585 break;
4586 }
4587 }
4588 if( bSurroundOnly )
4589 {
4590 if( css::text::WrapTextMode_NONE==eSurround )
4591 {
4592 bFound = false;
4593 break;
4594 }
4595 else if( css::text::WrapTextMode_THROUGH!=eSurround )
4596 {
4597 bFound = true;
4598 // Continue searching: It's possible that some without
4599 // wrapping will follow...
4600 }
4601 }
4602 }
4603 }
4604 }
4605
4606 return bFound;
4607}
4608
4609// the special methods for inserting of objects
4610
4612{
4613 const SwContentNode* pCNd = m_pPam->GetPointContentNode();
4614 return pCNd ? &pCNd->GetAnyFormatColl() : nullptr;
4615}
4616
4618{
4619 SwTextFormatColl *pCollToSet = nullptr; // the style to set
4620 SfxItemSet *pItemSet = nullptr; // set of hard attributes
4621 sal_uInt16 nTopColl = pContext ? pContext->GetTextFormatColl() : 0;
4622 const OUString rTopClass = pContext ? pContext->GetClass() : OUString();
4623 sal_uInt16 nDfltColl = RES_POOLCOLL_TEXT;
4624
4625 bool bInPRE=false; // some context info
4626
4627 sal_uInt16 nLeftMargin = 0, nRightMargin = 0; // the margins and
4628 short nFirstLineIndent = 0; // indentations
4629
4630 auto nDepth = m_aContexts.size();
4631 if (m_bFuzzing && nDepth > 512)
4632 {
4633 SAL_WARN("sw.html", "Not applying any more text collection attributes to a deeply nested node for fuzzing performance");
4634 nDepth = 0;
4635 }
4636
4637 for (auto i = m_nContextStAttrMin; i < nDepth; ++i)
4638 {
4639 const HTMLAttrContext *pCntxt = m_aContexts[i].get();
4640
4641 sal_uInt16 nColl = pCntxt->GetTextFormatColl();
4642 if( nColl )
4643 {
4644 // There is a style to set. Then at first we must decide,
4645 // if the style can be set.
4646 bool bSetThis = true;
4647 switch( nColl )
4648 {
4650 bInPRE = true;
4651 break;
4652 case RES_POOLCOLL_TEXT:
4653 // <TD><P CLASS=xxx> must become TD.xxx
4654 if( nDfltColl==RES_POOLCOLL_TABLE ||
4655 nDfltColl==RES_POOLCOLL_TABLE_HDLN )
4656 nColl = nDfltColl;
4657 break;
4659 // also <HR> in <PRE> set as style, otherwise it can't
4660 // be exported anymore
4661 break;
4662 default:
4663 if( bInPRE )
4664 bSetThis = false;
4665 break;
4666 }
4667
4668 SwTextFormatColl *pNewColl =
4669 m_pCSS1Parser->GetTextFormatColl( nColl, pCntxt->GetClass() );
4670
4671 if( bSetThis )
4672 {
4673 // If now a different style should be set as previously, the
4674 // previous style must be replaced by hard attribution.
4675
4676 if( pCollToSet )
4677 {
4678 // insert the attributes hard, which previous style sets
4679 if( !pItemSet )
4680 pItemSet = new SfxItemSet( pCollToSet->GetAttrSet() );
4681 else
4682 {
4683 const SfxItemSet& rCollSet = pCollToSet->GetAttrSet();
4684 SfxItemSet aItemSet( *rCollSet.GetPool(),
4685 rCollSet.GetRanges() );
4686 aItemSet.Set( rCollSet );
4687 pItemSet->Put( aItemSet );
4688 }
4689 // but remove the attributes, which the current style sets,
4690 // because otherwise they will be overwritten later
4691 pItemSet->Differentiate( pNewColl->GetAttrSet() );
4692 }
4693
4694 pCollToSet = pNewColl;
4695 }
4696 else
4697 {
4698 // hard attribution
4699 if( !pItemSet )
4700 pItemSet = new SfxItemSet( pNewColl->GetAttrSet() );
4701 else
4702 {
4703 const SfxItemSet& rCollSet = pNewColl->GetAttrSet();
4704 SfxItemSet aItemSet( *rCollSet.GetPool(),
4705 rCollSet.GetRanges() );
4706 aItemSet.Set( rCollSet );
4707 pItemSet->Put( aItemSet );
4708 }
4709 }
4710 }
4711 else
4712 {
4713 // Maybe a default style exists?
4714 nColl = pCntxt->GetDefaultTextFormatColl();
4715 if( nColl )
4716 nDfltColl = nColl;
4717 }
4718
4719 // if applicable fetch new paragraph indents
4720 if( pCntxt->IsLRSpaceChanged() )
4721 {
4722 sal_uInt16 nLeft=0, nRight=0;
4723
4724 pCntxt->GetMargins( nLeft, nRight, nFirstLineIndent );
4725 nLeftMargin = nLeft;
4726 nRightMargin = nRight;
4727 }
4728 }
4729
4730 // If in current context a new style should be set,
4731 // its paragraph margins must be inserted in the context.
4732 if( pContext && nTopColl )
4733 {
4734 // <TD><P CLASS=xxx> must become TD.xxx
4735 if( nTopColl==RES_POOLCOLL_TEXT &&
4736 (nDfltColl==RES_POOLCOLL_TABLE ||
4737 nDfltColl==RES_POOLCOLL_TABLE_HDLN) )
4738 nTopColl = nDfltColl;
4739
4740 const SwTextFormatColl *pTopColl =
4741 m_pCSS1Parser->GetTextFormatColl( nTopColl, rTopClass );
4742 const SfxItemSet& rItemSet = pTopColl->GetAttrSet();
4743 if( const SvxLRSpaceItem *pLRItem = rItemSet.GetItemIfSet(RES_LR_SPACE) )
4744 {
4745 sal_Int32 nLeft = pLRItem->GetTextLeft();
4746 sal_Int32 nRight = pLRItem->GetRight();
4747 nFirstLineIndent = pLRItem->GetTextFirstLineOffset();
4748
4749 // In Definition lists the margins also contain the margins from the previous levels
4750 if( RES_POOLCOLL_HTML_DD == nTopColl )
4751 {
4752 const SvxLRSpaceItem& rDTLRSpace = m_pCSS1Parser
4753 ->GetTextFormatColl(RES_POOLCOLL_HTML_DT, OUString())
4754 ->GetLRSpace();
4755 nLeft -= rDTLRSpace.GetTextLeft();
4756 nRight -= rDTLRSpace.GetRight();
4757 }
4758 else if( RES_POOLCOLL_HTML_DT == nTopColl )
4759 {
4760 nLeft = 0;
4761 nRight = 0;
4762 }
4763
4764 // the paragraph margins add up
4765 nLeftMargin = nLeftMargin + static_cast< sal_uInt16 >(nLeft);
4766 nRightMargin = nRightMargin + static_cast< sal_uInt16 >(nRight);
4767
4769 nFirstLineIndent );
4770 }
4771 if( const SvxULSpaceItem* pULItem = rItemSet.GetItemIfSet(RES_UL_SPACE) )
4772 {
4773 pContext->SetULSpace( pULItem->GetUpper(), pULItem->GetLower() );
4774 }
4775 }
4776
4777 // If no style is set in the context use the text body.
4778 if( !pCollToSet )
4779 {
4780 pCollToSet = m_pCSS1Parser->GetTextCollFromPool( nDfltColl );
4781 const SvxLRSpaceItem& rLRItem = pCollToSet->GetLRSpace();
4782 if( !nLeftMargin )
4783 nLeftMargin = static_cast< sal_uInt16 >(rLRItem.GetTextLeft());
4784 if( !nRightMargin )
4785 nRightMargin = static_cast< sal_uInt16 >(rLRItem.GetRight());
4786 if( !nFirstLineIndent )
4787 nFirstLineIndent = rLRItem.GetTextFirstLineOffset();
4788 }
4789
4790 // remove previous hard attribution of paragraph
4791 for( auto pParaAttr : m_aParaAttrs )
4792 pParaAttr->Invalidate();
4793 m_aParaAttrs.clear();
4794
4795 // set the style
4796 m_xDoc->SetTextFormatColl( *m_pPam, pCollToSet );
4797
4798 // if applicable correct the paragraph indent
4799 const SvxLRSpaceItem& rLRItem = pCollToSet->GetLRSpace();
4800 bool bSetLRSpace = nLeftMargin != rLRItem.GetTextLeft() ||
4801 nFirstLineIndent != rLRItem.GetTextFirstLineOffset() ||
4802 nRightMargin != rLRItem.GetRight();
4803
4804 if( bSetLRSpace )
4805 {
4806 SvxLRSpaceItem aLRItem( rLRItem );
4807 aLRItem.SetTextLeft( nLeftMargin );
4808 aLRItem.SetRight( nRightMargin );
4809 aLRItem.SetTextFirstLineOffset( nFirstLineIndent );
4810 if( pItemSet )
4811 pItemSet->Put( aLRItem );
4812 else
4813 {
4814 NewAttr(m_xAttrTab, &m_xAttrTab->pLRSpace, aLRItem);
4815 m_xAttrTab->pLRSpace->SetLikePara();
4816 m_aParaAttrs.push_back( m_xAttrTab->pLRSpace );
4817 EndAttr( m_xAttrTab->pLRSpace, false );
4818 }
4819 }
4820
4821 // and now set the attributes
4822 if( pItemSet )
4823 {
4824 InsertParaAttrs( *pItemSet );
4825 delete pItemSet;
4826 }
4827}
4828
4830{
4831 OUString aId, aStyle, aLang, aDir;
4832 OUString aClass;
4833
4834 const HTMLOptions& rHTMLOptions = GetOptions();
4835 for (size_t i = rHTMLOptions.size(); i; )
4836 {
4837 const HTMLOption& rOption = rHTMLOptions[--i];
4838 switch( rOption.GetToken() )
4839 {
4840 case HtmlOptionId::ID:
4841 aId = rOption.GetString();
4842 break;
4843 case HtmlOptionId::STYLE:
4844 aStyle = rOption.GetString();
4845 break;
4846 case HtmlOptionId::CLASS:
4847 aClass = rOption.GetString();
4848 break;
4849 case HtmlOptionId::LANG:
4850 aLang = rOption.GetString();
4851 break;
4852 case HtmlOptionId::DIR:
4853 aDir = rOption.GetString();
4854 break;
4855 default: break;
4856 }
4857 }
4858
4859 // create a new context
4860 std::unique_ptr<HTMLAttrContext> xCntxt(new HTMLAttrContext(nToken));
4861
4862 // set the style and save it in the context
4863 SwCharFormat* pCFormat = m_pCSS1Parser->GetChrFormat( nToken, aClass );
4864 OSL_ENSURE( pCFormat, "No character format found for token" );
4865
4866 // parse styles (regarding class see also NewPara)
4867 if (HasStyleOptions(aStyle, aId, {}, &aLang, &aDir))
4868 {
4869 SfxItemSet aItemSet( m_xDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
4870 SvxCSS1PropertyInfo aPropInfo;
4871
4872 if (ParseStyleOptions(aStyle, aId, OUString(), aItemSet, aPropInfo, &aLang, &aDir))
4873 {
4874 OSL_ENSURE( aClass.isEmpty() || !m_pCSS1Parser->GetClass( aClass ),
4875 "Class is not considered" );
4876 DoPositioning( aItemSet, aPropInfo, xCntxt.get() );
4877 InsertAttrs( aItemSet, aPropInfo, xCntxt.get(), true );
4878 }
4879 }
4880
4881 // Character formats are stored in their own stack and can never be inserted
4882 // by styles. Therefore the attribute doesn't exist in CSS1-Which-Range.
4883 if( pCFormat )
4884 InsertAttr( &m_xAttrTab->pCharFormats, SwFormatCharFormat( pCFormat ), xCntxt.get() );
4885
4886 // save the context
4887 PushContext(xCntxt);
4888}
4889
4891{
4892 // and if applicable change it via the options
4893 sal_Int16 eVertOri = text::VertOrientation::TOP;
4894 sal_Int16 eHoriOri = text::HoriOrientation::NONE;
4895 Size aSize( 0, 0);
4896 tools::Long nSize = 0;
4897 bool bPercentWidth = false;
4898 bool bPercentHeight = false;
4899 sal_uInt16 nType = HTML_SPTYPE_HORI;
4900
4901 const HTMLOptions& rHTMLOptions = GetOptions();
4902 for (size_t i = rHTMLOptions.size(); i; )
4903 {
4904 const HTMLOption& rOption = rHTMLOptions[--i];
4905 switch( rOption.GetToken() )
4906 {
4907 case HtmlOptionId::TYPE:
4909 break;
4910 case HtmlOptionId::ALIGN:
4911 eVertOri =
4913 eVertOri );
4914 eHoriOri =
4916 eHoriOri );
4917 break;
4918 case HtmlOptionId::WIDTH:
4919 // First only save as pixel value!
4920 bPercentWidth = (rOption.GetString().indexOf('%') != -1);
4921 aSize.setWidth( static_cast<tools::Long>(rOption.GetNumber()) );
4922 break;
4923 case HtmlOptionId::HEIGHT:
4924 // First only save as pixel value!
4925 bPercentHeight = (rOption.GetString().indexOf('%') != -1);
4926 aSize.setHeight( static_cast<tools::Long>(rOption.GetNumber()) );
4927 break;
4928 case HtmlOptionId::SIZE:
4929 // First only save as pixel value!
4930 nSize = rOption.GetNumber();
4931 break;
4932 default: break;
4933 }
4934 }
4935
4936 switch( nType )
4937 {
4938 case HTML_SPTYPE_BLOCK:
4939 {
4940 // create an empty text frame
4941
4942 // fetch the ItemSet
4943 SfxItemSetFixed<RES_FRMATR_BEGIN, RES_FRMATR_END-1> aFrameSet( m_xDoc->GetAttrPool() );
4944 if( !IsNewDoc() )
4945 Reader::ResetFrameFormatAttrs( aFrameSet );
4946
4947 // set the anchor and the adjustment
4948 SetAnchorAndAdjustment( eVertOri, eHoriOri, aFrameSet );
4949
4950 // and the size of the frame
4951 Size aDfltSz( MINFLY, MINFLY );
4952 Size aSpace( 0, 0 );
4953 SfxItemSet aDummyItemSet( m_xDoc->GetAttrPool(),
4954 m_pCSS1Parser->GetWhichMap() );
4955 SvxCSS1PropertyInfo aDummyPropInfo;
4956
4957 SetFixSize( aSize, aDfltSz, bPercentWidth, bPercentHeight,
4958 aDummyPropInfo, aFrameSet );
4959 SetSpace( aSpace, aDummyItemSet, aDummyPropInfo, aFrameSet );
4960
4961 // protect the content
4962 SvxProtectItem aProtectItem( RES_PROTECT) ;
4963 aProtectItem.SetContentProtect( true );
4964 aFrameSet.Put( aProtectItem );
4965
4966 // create the frame
4967 RndStdIds eAnchorId =
4968 aFrameSet.Get(RES_ANCHOR).GetAnchorId();
4969 SwFrameFormat *pFlyFormat = m_xDoc->MakeFlySection( eAnchorId,
4970 m_pPam->GetPoint(), &aFrameSet );
4971 // Possibly create frames and register auto-bound frames.
4972 RegisterFlyFrame( pFlyFormat );
4973 }
4974 break;
4975 case HTML_SPTYPE_VERT:
4976 if( nSize > 0 )
4977 {
4979 {
4981 ->PixelToLogic( Size(0,nSize),
4982 MapMode(MapUnit::MapTwip) ).Height();
4983 }
4984
4985 // set a paragraph margin
4986 SwTextNode *pTextNode = nullptr;
4987 if( !m_pPam->GetPoint()->GetContentIndex() )
4988 {
4989 // if possible change the bottom paragraph margin
4990 // of previous node
4991
4992 SetAttr(); // set still open paragraph attributes
4993
4994 pTextNode = m_xDoc->GetNodes()[m_pPam->GetPoint()->GetNodeIndex()-1]
4995 ->GetTextNode();
4996
4997 // If the previous paragraph isn't a text node, then now an
4998 // empty paragraph is created, which already generates a single
4999 // line of spacing.
5000 if( !pTextNode )
5001 nSize = nSize>HTML_PARSPACE ? nSize-HTML_PARSPACE : 0;
5002 }
5003
5004 if( pTextNode )
5005 {
5006 SvxULSpaceItem aULSpace( pTextNode->SwContentNode::GetAttr( RES_UL_SPACE ) );
5007 aULSpace.SetLower( aULSpace.GetLower() + o3tl::narrowing<sal_uInt16>(nSize) );
5008 pTextNode->SetAttr( aULSpace );
5009 }
5010 else
5011 {
5012 NewAttr(m_xAttrTab, &m_xAttrTab->pULSpace, SvxULSpaceItem(0, o3tl::narrowing<sal_uInt16>(nSize), RES_UL_SPACE));
5013 EndAttr( m_xAttrTab->pULSpace, false );
5014
5015 AppendTextNode(); // Don't change spacing!
5016 }
5017 }
5018 break;
5019 case HTML_SPTYPE_HORI:
5020 if( nSize > 0 )
5021 {
5022 // If the paragraph is still empty, set first line
5023 // indentation, otherwise apply letter spacing over a space.
5024
5026 {
5028 ->PixelToLogic( Size(nSize,0),
5029 MapMode(MapUnit::MapTwip) ).Width();
5030 }
5031
5032 if( !m_pPam->GetPoint()->GetContentIndex() )
5033 {
5034 sal_uInt16 nLeft=0, nRight=0;
5035 short nIndent = 0;
5036
5037 GetMarginsFromContextWithNumberBullet( nLeft, nRight, nIndent );
5038 nIndent = nIndent + static_cast<short>(nSize);
5039
5040 SvxLRSpaceItem aLRItem( RES_LR_SPACE );
5041 aLRItem.SetTextLeft( nLeft );
5042 aLRItem.SetRight( nRight );
5043 aLRItem.SetTextFirstLineOffset( nIndent );
5044
5045 NewAttr(m_xAttrTab, &m_xAttrTab->pLRSpace, aLRItem);
5046 EndAttr( m_xAttrTab->pLRSpace, false );
5047 }
5048 else
5049 {
5050 NewAttr(m_xAttrTab, &m_xAttrTab->pKerning, SvxKerningItem( static_cast<short>(nSize), RES_CHRATR_KERNING ));
5051 m_xDoc->getIDocumentContentOperations().InsertString( *m_pPam, " " );
5052 EndAttr( m_xAttrTab->pKerning );
5053 }
5054 }
5055 }
5056}
5057
5058sal_uInt16 SwHTMLParser::ToTwips( sal_uInt16 nPixel )
5059{
5061 {
5063 Size( nPixel, nPixel ), MapMode( MapUnit::MapTwip ) ).Width();
5064 return o3tl::narrowing<sal_uInt16>(std::min(nTwips, SwTwips(SAL_MAX_UINT16)));
5065 }
5066 else
5067 return nPixel;
5068}
5069
5071{
5073 if( nWidth )
5074 return nWidth;
5075
5076 if( !m_aHTMLPageSize.Width() )
5077 {
5078 const SwFrameFormat& rPgFormat = m_pCSS1Parser->GetMasterPageDesc()->GetMaster();
5079
5080 const SwFormatFrameSize& rSz = rPgFormat.GetFrameSize();
5081 const SvxLRSpaceItem& rLR = rPgFormat.GetLRSpace();
5082 const SvxULSpaceItem& rUL = rPgFormat.GetULSpace();
5083 const SwFormatCol& rCol = rPgFormat.GetCol();
5084
5085 m_aHTMLPageSize.setWidth( rSz.GetWidth() - rLR.GetLeft() - rLR.GetRight() );
5086 m_aHTMLPageSize.setHeight( rSz.GetHeight() - rUL.GetUpper() - rUL.GetLower() );
5087
5088 if( 1 < rCol.GetNumCols() )
5090 }
5091
5092 return m_aHTMLPageSize.Width();
5093}
5094
5096{
5097 OUString aId;
5098 const HTMLOptions& rHTMLOptions = GetOptions();
5099 for (size_t i = rHTMLOptions.size(); i; )
5100 {
5101 const HTMLOption& rOption = rHTMLOptions[--i];
5102 if( HtmlOptionId::ID==rOption.GetToken() )
5103 {
5104 aId = rOption.GetString();
5105 break;
5106 }
5107 }
5108
5109 if( !aId.isEmpty() )
5110 InsertBookmark( aId );
5111}
5112
5114{
5115 OUString aId, aStyle, aClass; // the id of bookmark
5117
5118 // then we fetch the options
5119 const HTMLOptions& rHTMLOptions = GetOptions();
5120 for (size_t i = rHTMLOptions.size(); i; )
5121 {
5122 const HTMLOption& rOption = rHTMLOptions[--i];
5123 switch( rOption.GetToken() )
5124 {
5125 case HtmlOptionId::CLEAR:
5126 {
5127 const OUString &rClear = rOption.GetString();
5128 if( rClear.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_AL_all ) )
5129 {
5130 eClear = SwLineBreakClear::ALL;
5131 }
5132 else if( rClear.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_AL_left ) )
5133 {
5134 eClear = SwLineBreakClear::LEFT;
5135 }
5136 else if( rClear.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_AL_right ) )
5137 {
5138 eClear = SwLineBreakClear::LEFT;
5139 }
5140 }
5141 break;
5142 case HtmlOptionId::ID:
5143 aId = rOption.GetString();
5144 break;
5145 case HtmlOptionId::STYLE:
5146 aStyle = rOption.GetString();
5147 break;
5148 case HtmlOptionId::CLASS:
5149 aClass = rOption.GetString();
5150 break;
5151 default: break;
5152 }
5153 }
5154
5155 // parse styles
5156 std::shared_ptr<SvxFormatBreakItem> aBreakItem(std::make_shared<SvxFormatBreakItem>(SvxBreak::NONE, RES_BREAK));
5157 bool bBreakItem = false;
5158 if( HasStyleOptions( aStyle, aId, aClass ) )
5159 {
5160 SfxItemSet aItemSet( m_xDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
5161 SvxCSS1PropertyInfo aPropInfo;
5162
5163 if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo ) )
5164 {
5165 if( m_pCSS1Parser->SetFormatBreak( aItemSet, aPropInfo ) )
5166 {
5167 aBreakItem.reset(aItemSet.Get(RES_BREAK).Clone());
5168 bBreakItem = true;
5169 }
5170 if( !aPropInfo.m_aId.isEmpty() )
5171 InsertBookmark( aPropInfo.m_aId );
5172 }
5173 }
5174
5175 if( bBreakItem && SvxBreak::PageAfter == aBreakItem->GetBreak() )
5176 {
5177 NewAttr(m_xAttrTab, &m_xAttrTab->pBreak, *aBreakItem);
5178 EndAttr( m_xAttrTab->pBreak, false );
5179 }
5180
5181 if (!bBreakItem)
5182 {
5183 if (eClear == SwLineBreakClear::NONE)
5184 {
5185 // If no CLEAR could or should be executed, a line break will be inserted
5186 m_xDoc->getIDocumentContentOperations().InsertString(*m_pPam, "\x0A");
5187 }
5188 else
5189 {
5190 // <BR CLEAR=xxx> is mapped an SwFormatLineBreak.
5191 SwTextNode* pTextNode = m_pPam->GetPointNode().GetTextNode();
5192 if (pTextNode)
5193 {
5194 SwFormatLineBreak aLineBreak(eClear);
5195 sal_Int32 nPos = m_pPam->GetPoint()->GetContentIndex();
5196 pTextNode->InsertItem(aLineBreak, nPos, nPos);
5197 }
5198 }
5199 }
5200 else if( m_pPam->GetPoint()->GetContentIndex() )
5201 {
5202 // If a CLEAR is executed in a non-empty paragraph, then after it
5203 // a new paragraph has to be opened.
5204 // MIB 21.02.97: Here actually we should change the bottom paragraph
5205 // margin to zero. This will fail for something like this <BR ..><P>
5206 // (>Netscape). That's why we don't do it.
5208 }
5209 if( bBreakItem && SvxBreak::PageBefore == aBreakItem->GetBreak() )
5210 {
5211 NewAttr(m_xAttrTab, &m_xAttrTab->pBreak, *aBreakItem);
5212 EndAttr( m_xAttrTab->pBreak, false );
5213 }
5214}
5215
5217{
5218 sal_uInt16 nSize = 0;
5219 sal_uInt16 nWidth = 0;
5220
5221 SvxAdjust eAdjust = SvxAdjust::End;
5222
5223 bool bPercentWidth = false;
5224 bool bNoShade = false;
5225 bool bColor = false;
5226
5227 Color aColor;
5228 OUString aId;
5229
5230 // let's fetch the options
5231 const HTMLOptions& rHTMLOptions = GetOptions();
5232 for (size_t i = rHTMLOptions.size(); i; )
5233 {
5234 const HTMLOption& rOption = rHTMLOptions[--i];
5235 switch( rOption.GetToken() )
5236 {
5237 case HtmlOptionId::ID:
5238 aId = rOption.GetString();
5239 break;
5240 case HtmlOptionId::SIZE:
5241 nSize = o3tl::narrowing<sal_uInt16>(rOption.GetNumber());
5242 break;
5243 case HtmlOptionId::WIDTH:
5244 bPercentWidth = (rOption.GetString().indexOf('%') != -1);
5245 nWidth = o3tl::narrowing<sal_uInt16>(rOption.GetNumber());
5246 if( bPercentWidth && nWidth>=100 )
5247 {
5248 // the default case are 100% lines (no attributes necessary)
5249 nWidth = 0;
5250 bPercentWidth = false;
5251 }
5252 break;
5253 case HtmlOptionId::ALIGN:
5254 eAdjust = rOption.GetEnum( aHTMLPAlignTable, eAdjust );
5255 break;
5256 case HtmlOptionId::NOSHADE:
5257 bNoShade = true;
5258 break;
5259 case HtmlOptionId::COLOR:
5260 rOption.GetColor( aColor );
5261 bColor = true;
5262 break;
5263 default: break;
5264 }
5265 }
5266
5267 if( m_pPam->GetPoint()->GetContentIndex() )
5269 if( m_nOpenParaToken != HtmlTokenId::NONE )
5270 EndPara();
5273
5274 // ...and save in a context
5275 std::unique_ptr<HTMLAttrContext> xCntxt(
5276 new HTMLAttrContext(HtmlTokenId::HORZRULE, RES_POOLCOLL_HTML_HR, OUString()));
5277
5278 PushContext(xCntxt);
5279
5280 // set the new style
5281 SetTextCollAttrs(m_aContexts.back().get());
5282
5283 // the hard attributes of the current paragraph will never become invalid
5284 m_aParaAttrs.clear();
5285
5286 if( nSize>0 || bColor || bNoShade )
5287 {
5288 // set line colour and/or width
5289 if( !bColor )
5290 aColor = COL_GRAY;
5291
5292 SvxBorderLine aBorderLine( &aColor );
5293 if( nSize )
5294 {
5295 tools::Long nPWidth = 0;
5296 tools::Long nPHeight = static_cast<tools::Long>(nSize);
5297 SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight );
5298 if ( !bNoShade )
5299 {
5300 aBorderLine.SetBorderLineStyle(SvxBorderLineStyle::DOUBLE);
5301 }
5302 aBorderLine.SetWidth( nPHeight );
5303 }
5304 else if( bNoShade )
5305 {
5306 aBorderLine.SetWidth( SvxBorderLineWidth::Medium );
5307 }
5308 else
5309 {
5310 aBorderLine.SetBorderLineStyle(SvxBorderLineStyle::DOUBLE);
5312 }
5313
5314 SvxBoxItem aBoxItem(RES_BOX);
5315 aBoxItem.SetLine( &aBorderLine, SvxBoxItemLine::BOTTOM );
5316 HTMLAttr* pTmp = new HTMLAttr(*m_pPam->GetPoint(), aBoxItem, nullptr, std::shared_ptr<HTMLAttrTable>());
5317 m_aSetAttrTab.push_back( pTmp );
5318 }
5319 if( nWidth )
5320 {
5321 // If we aren't in a table, then the width value will be "faked" with
5322 // paragraph indents. That makes little sense in a table. In order to
5323 // avoid that the line is considered during the width calculation, it
5324 // still gets an appropriate LRSpace-Item.
5325 if (!m_xTable)
5326 {
5327 // fake length and alignment of line above paragraph indents
5328 tools::Long nBrowseWidth = GetCurrentBrowseWidth();
5329 nWidth = bPercentWidth ? o3tl::narrowing<sal_uInt16>((nWidth*nBrowseWidth) / 100)
5330 :