build fix
[LibreOffice.git] / sw / source / filter / html / swhtml.cxx
blob34f821037f4735465a381d65a443b0e70a94f404
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_features.h>
22 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
23 #include <com/sun/star/document/XDocumentProperties.hpp>
24 #include <com/sun/star/i18n/ScriptType.hpp>
25 #include <comphelper/string.hxx>
26 #include <rtl/ustrbuf.hxx>
27 #include <sfx2/sfx.hrc>
28 #include <svx/svxids.hrc>
29 #if OSL_DEBUG_LEVEL > 0
30 #include <stdlib.h>
31 #endif
32 #include <hintids.hxx>
34 #include <svl/stritem.hxx>
35 #include <svtools/imap.hxx>
36 #include <svtools/htmltokn.h>
37 #include <svtools/htmlkywd.hxx>
38 #include <svtools/ctrltool.hxx>
39 #include <unotools/pathoptions.hxx>
40 #include <vcl/svapp.hxx>
41 #include <vcl/wrkwin.hxx>
42 #include <sfx2/fcontnr.hxx>
43 #include <sfx2/docfile.hxx>
45 #include <svtools/htmlcfg.hxx>
46 #include <sfx2/linkmgr.hxx>
47 #include <editeng/kernitem.hxx>
48 #include <editeng/boxitem.hxx>
49 #include <editeng/fhgtitem.hxx>
50 #include <editeng/formatbreakitem.hxx>
51 #include <editeng/postitem.hxx>
52 #include <editeng/wghtitem.hxx>
53 #include <editeng/crossedoutitem.hxx>
54 #include <editeng/udlnitem.hxx>
55 #include <editeng/escapementitem.hxx>
56 #include <editeng/blinkitem.hxx>
57 #include <editeng/ulspitem.hxx>
58 #include <editeng/colritem.hxx>
59 #include <editeng/fontitem.hxx>
60 #include <editeng/adjustitem.hxx>
61 #include <editeng/lrspitem.hxx>
62 #include <editeng/protitem.hxx>
63 #include <editeng/flstitem.hxx>
64 #include <svx/unobrushitemhelper.hxx>
66 #include <frmatr.hxx>
67 #include <charatr.hxx>
68 #include <fmtfld.hxx>
69 #include <fmtpdsc.hxx>
70 #include <txtfld.hxx>
71 #include <fmtanchr.hxx>
72 #include <fmtsrnd.hxx>
73 #include <fmtfsize.hxx>
74 #include <fmtclds.hxx>
75 #include <fchrfmt.hxx>
76 #include <fmtinfmt.hxx>
77 #include <fmtfollowtextflow.hxx>
78 #include <docary.hxx>
79 #include <docstat.hxx>
80 #include <doc.hxx>
81 #include <IDocumentUndoRedo.hxx>
82 #include <IDocumentSettingAccess.hxx>
83 #include <IDocumentLayoutAccess.hxx>
84 #include <IDocumentLinksAdministration.hxx>
85 #include <IDocumentRedlineAccess.hxx>
86 #include <IDocumentFieldsAccess.hxx>
87 #include <IDocumentStylePoolAccess.hxx>
88 #include <IDocumentStatistics.hxx>
89 #include <IDocumentState.hxx>
90 #include <pam.hxx>
91 #include <ndtxt.hxx>
92 #include <mdiexp.hxx>
93 #include <expfld.hxx>
94 #include <poolfmt.hxx>
95 #include <pagedesc.hxx>
96 #include <IMark.hxx>
97 #include <docsh.hxx>
98 #include <editsh.hxx>
99 #include <docufld.hxx>
100 #include <swcss1.hxx>
101 #include <fltini.hxx>
102 #include <htmltbl.hxx>
103 #include <htmlnum.hxx>
104 #include <swhtml.hxx>
105 #include <linkenum.hxx>
106 #include <breakit.hxx>
107 #include <SwAppletImpl.hxx>
109 #include <sfx2/viewfrm.hxx>
111 #include <statstr.hrc>
112 #include <swerror.h>
113 #include <css1atr.hxx>
115 #define FONTSIZE_MASK 7
117 #define HTML_ESC_PROP 80
118 #define HTML_ESC_SUPER DFLT_ESC_SUPER
119 #define HTML_ESC_SUB DFLT_ESC_SUB
121 #define HTML_SPTYPE_BLOCK 1
122 #define HTML_SPTYPE_HORI 2
123 #define HTML_SPTYPE_VERT 3
125 using editeng::SvxBorderLine;
126 using namespace ::com::sun::star;
128 // <P ALIGN=xxx>, <Hn ALIGN=xxx>, <TD ALIGN=xxx> usw.
129 HTMLOptionEnum aHTMLPAlignTable[] =
131 { OOO_STRING_SVTOOLS_HTML_AL_left, SVX_ADJUST_LEFT },
132 { OOO_STRING_SVTOOLS_HTML_AL_center, SVX_ADJUST_CENTER },
133 { OOO_STRING_SVTOOLS_HTML_AL_middle, SVX_ADJUST_CENTER }, // Netscape
134 { OOO_STRING_SVTOOLS_HTML_AL_right, SVX_ADJUST_RIGHT },
135 { OOO_STRING_SVTOOLS_HTML_AL_justify, SVX_ADJUST_BLOCK },
136 { OOO_STRING_SVTOOLS_HTML_AL_char, SVX_ADJUST_LEFT },
137 { nullptr, 0 }
140 // <SPACER TYPE=...>
141 static HTMLOptionEnum aHTMLSpacerTypeTable[] =
143 { OOO_STRING_SVTOOLS_HTML_SPTYPE_block, HTML_SPTYPE_BLOCK },
144 { OOO_STRING_SVTOOLS_HTML_SPTYPE_horizontal, HTML_SPTYPE_HORI },
145 { OOO_STRING_SVTOOLS_HTML_SPTYPE_vertical, HTML_SPTYPE_VERT },
146 { nullptr, 0 }
149 HTMLReader::HTMLReader()
151 bTmplBrowseMode = true;
154 OUString HTMLReader::GetTemplateName() const
156 const OUString sTemplateWithoutExt("internal/html");
157 SvtPathOptions aPathOpt;
159 // first search for OpenDocument Writer/Web template
160 // OpenDocument Writer/Web template (extension .oth)
161 OUString sTemplate( sTemplateWithoutExt + ".oth" );
162 if (aPathOpt.SearchFile( sTemplate, SvtPathOptions::PATH_TEMPLATE ))
163 return sTemplate;
165 // no OpenDocument Writer/Web template found.
166 // search for OpenOffice.org Writer/Web template
167 sTemplate = sTemplateWithoutExt + ".stw";
168 if (aPathOpt.SearchFile( sTemplate, SvtPathOptions::PATH_TEMPLATE ))
169 return sTemplate;
171 OSL_ENSURE( false, "The default HTML template cannot be found in the defined template directories!");
173 return OUString();
176 bool HTMLReader::SetStrmStgPtr()
178 OSL_ENSURE( pMedium, "Wo ist das Medium??" );
180 if( pMedium->IsRemote() || !pMedium->IsStorage() )
182 pStrm = pMedium->GetInStream();
183 return true;
185 return false;
189 // Aufruf fuer die allg. Reader-Schnittstelle
190 sal_uLong HTMLReader::Read( SwDoc &rDoc, const OUString& rBaseURL, SwPaM &rPam, const OUString & rName )
192 if( !pStrm )
194 OSL_ENSURE( pStrm, "HTML-Read ohne Stream" );
195 return ERR_SWG_READ_ERROR;
198 if( !bInsertMode )
200 Reader::ResetFrameFormats( rDoc );
202 // Die HTML-Seitenvorlage setzen, wenn des kein HTML-Dokument ist,
203 // sonst ist sie schon gesetzt.
204 if( !rDoc.getIDocumentSettingAccess().get(DocumentSettingId::HTML_MODE) )
206 rDoc.getIDocumentContentOperations().InsertPoolItem( rPam, SwFormatPageDesc(
207 rDoc.getIDocumentStylePoolAccess().GetPageDescFromPool( RES_POOLPAGE_HTML, false )) );
211 // damit keiner das Doc klaut!
212 rDoc.acquire();
213 sal_uLong nRet = 0;
214 tools::SvRef<SvParser> xParser = new SwHTMLParser( &rDoc, rPam, *pStrm,
215 rName, rBaseURL, !bInsertMode, pMedium,
216 IsReadUTF8(),
217 bIgnoreHTMLComments );
219 SvParserState eState = xParser->CallParser();
221 if( SVPAR_PENDING == eState )
222 pStrm->ResetError();
223 else if( SVPAR_ACCEPTED != eState )
225 const OUString sErr(OUString::number((sal_Int32)xParser->GetLineNr())
226 + "," + OUString::number((sal_Int32)xParser->GetLinePos()));
228 // den Stream als Fehlernummer Transporter benutzen
229 nRet = *new StringErrorInfo( ERR_FORMAT_ROWCOL, sErr,
230 ERRCODE_BUTTON_OK | ERRCODE_MSG_ERROR );
233 return nRet;
236 SwHTMLParser::SwHTMLParser( SwDoc* pD, SwPaM& rCursor, SvStream& rIn,
237 const OUString& rPath,
238 const OUString& rBaseURL,
239 bool bReadNewDoc,
240 SfxMedium* pMed, bool bReadUTF8,
241 bool bNoHTMLComments )
242 : SfxHTMLParser( rIn, bReadNewDoc, pMed ),
243 SwClient( nullptr ),
244 m_aPathToFile( rPath ),
245 m_sBaseURL( rBaseURL ),
246 m_pAppletImpl( nullptr ),
247 m_pCSS1Parser( nullptr ),
248 m_pNumRuleInfo( new SwHTMLNumRuleInfo ),
249 m_pPendStack( nullptr ),
250 m_pDoc( pD ),
251 m_pActionViewShell( nullptr ),
252 m_pSttNdIdx( nullptr ),
253 m_pTable(nullptr),
254 m_pFormImpl( nullptr ),
255 m_pMarquee( nullptr ),
256 m_pField( nullptr ),
257 m_pImageMap( nullptr ),
258 m_pImageMaps(nullptr),
259 m_pFootEndNoteImpl( nullptr ),
260 m_nScriptStartLineNr( 0 ),
261 m_nBaseFontStMin( 0 ),
262 m_nFontStMin( 0 ),
263 m_nDefListDeep( 0 ),
264 m_nFontStHeadStart( 0 ),
265 m_nSBModuleCnt( 0 ),
266 m_nMissingImgMaps( 0 ),
267 m_nParaCnt( 5 ),
268 // #i83625#
269 m_nContextStMin( 0 ),
270 m_nContextStAttrMin( 0 ),
271 m_nSelectEntryCnt( 0 ),
272 m_nOpenParaToken( 0 ),
273 m_eJumpTo( JUMPTO_NONE ),
274 #ifdef DBG_UTIL
275 m_nContinue( 0 ),
276 #endif
277 m_eParaAdjust( SVX_ADJUST_END ),
278 m_bDocInitalized( false ),
279 m_bSetModEnabled( false ),
280 m_bInFloatingFrame( false ),
281 m_bInField( false ),
282 m_bCallNextToken( false ),
283 m_bIgnoreRawData( false ),
284 m_bLBEntrySelected ( false ),
285 m_bTAIgnoreNewPara ( false ),
286 m_bFixMarqueeWidth ( false ),
287 m_bNoParSpace( false ),
288 m_bInNoEmbed( false ),
289 m_bInTitle( false ),
290 m_bUpdateDocStat( false ),
291 m_bFixSelectWidth( false ),
292 m_bFixSelectHeight( false ),
293 m_bTextArea( false ),
294 m_bSelect( false ),
295 m_bInFootEndNoteAnchor( false ),
296 m_bInFootEndNoteSymbol( false ),
297 m_bIgnoreHTMLComments( bNoHTMLComments ),
298 m_bRemoveHidden( false ),
299 m_isInTableStructure(false),
300 m_pTempViewFrame(nullptr)
302 m_nEventId = nullptr;
303 m_bUpperSpace = m_bViewCreated = m_bChkJumpMark = false;
305 m_eScriptLang = HTML_SL_UNKNOWN;
307 rCursor.DeleteMark();
308 m_pPam = &rCursor; // re-use existing cursor: avoids spurious ~SwIndexReg assert
309 memset( &m_aAttrTab, 0, sizeof( HTMLAttrTable ));
311 // Die Font-Groessen 1-7 aus der INI-Datei lesen
312 SvxHtmlOptions& rHtmlOptions = SvxHtmlOptions::Get();
313 m_aFontHeights[0] = rHtmlOptions.GetFontSize( 0 ) * 20;
314 m_aFontHeights[1] = rHtmlOptions.GetFontSize( 1 ) * 20;
315 m_aFontHeights[2] = rHtmlOptions.GetFontSize( 2 ) * 20;
316 m_aFontHeights[3] = rHtmlOptions.GetFontSize( 3 ) * 20;
317 m_aFontHeights[4] = rHtmlOptions.GetFontSize( 4 ) * 20;
318 m_aFontHeights[5] = rHtmlOptions.GetFontSize( 5 ) * 20;
319 m_aFontHeights[6] = rHtmlOptions.GetFontSize( 6 ) * 20;
321 m_bKeepUnknown = rHtmlOptions.IsImportUnknown();
323 if(bReadNewDoc)
325 //CJK has different defaults, so a different object should be used for this
326 //RES_CHARTR_CJK_FONTSIZE is a valid value
327 SvxFontHeightItem aFontHeight(m_aFontHeights[2], 100, RES_CHRATR_FONTSIZE);
328 m_pDoc->SetDefault( aFontHeight );
329 SvxFontHeightItem aFontHeightCJK(m_aFontHeights[2], 100, RES_CHRATR_CJK_FONTSIZE);
330 m_pDoc->SetDefault( aFontHeightCJK );
331 SvxFontHeightItem aFontHeightCTL(m_aFontHeights[2], 100, RES_CHRATR_CTL_FONTSIZE);
332 m_pDoc->SetDefault( aFontHeightCTL );
334 // #i18732# - adjust default of option 'FollowTextFlow'
335 // TODO: not sure what the appropriate default for HTML should be?
336 m_pDoc->SetDefault( SwFormatFollowTextFlow(true) );
339 // Waehrend des Imports in den HTML-Modus schalten, damit die
340 // richrigen Vorlagen angelegt werden
341 m_bOldIsHTMLMode = m_pDoc->getIDocumentSettingAccess().get(DocumentSettingId::HTML_MODE);
342 m_pDoc->getIDocumentSettingAccess().set(DocumentSettingId::HTML_MODE, true);
344 m_pCSS1Parser = new SwCSS1Parser( m_pDoc, m_aFontHeights, m_sBaseURL, IsNewDoc() );
345 m_pCSS1Parser->SetIgnoreFontFamily( rHtmlOptions.IsIgnoreFontFamily() );
347 if( bReadUTF8 )
349 SetSrcEncoding( RTL_TEXTENCODING_UTF8 );
351 else
353 SwDocShell *pDocSh = m_pDoc->GetDocShell();
354 SvKeyValueIterator *pHeaderAttrs =
355 pDocSh->GetHeaderAttributes();
356 if( pHeaderAttrs )
357 SetEncodingByHTTPHeader( pHeaderAttrs );
359 m_pCSS1Parser->SetDfltEncoding( osl_getThreadTextEncoding() );
361 // Timer nur bei ganz normalen Dokumenten aufsetzen!
362 SwDocShell* pDocSh = m_pDoc->GetDocShell();
363 if( pDocSh )
365 m_bViewCreated = true; // nicht, synchron laden
367 // es ist ein Sprungziel vorgegeben.
369 if( pMed )
371 m_sJmpMark = pMed->GetURLObject().GetMark();
372 if( !m_sJmpMark.isEmpty() )
374 m_eJumpTo = JUMPTO_MARK;
375 sal_Int32 nLastPos = m_sJmpMark.lastIndexOf( cMarkSeparator );
376 sal_Int32 nPos = nLastPos != -1 ? nLastPos : 0;
378 OUString sCmp;
379 if (nPos)
381 sCmp = m_sJmpMark.copy(nPos + 1).replaceAll(" ", "");
384 if( !sCmp.isEmpty() )
386 sCmp = sCmp.toAsciiLowerCase();
387 if( sCmp == "region" )
388 m_eJumpTo = JUMPTO_REGION;
389 else if( sCmp == "table" )
390 m_eJumpTo = JUMPTO_TABLE;
391 else if( sCmp == "graphic" )
392 m_eJumpTo = JUMPTO_GRAPHIC;
393 else if( sCmp == "outline" ||
394 sCmp == "text" ||
395 sCmp == "frame" )
396 m_eJumpTo = JUMPTO_NONE; // das ist nichts gueltiges!
397 else
398 // ansonsten ist das ein normaler (Book)Mark
399 nPos = -1;
401 else
402 nPos = -1;
404 if( nPos != -1 )
405 m_sJmpMark = m_sJmpMark.copy( 0, nPos );
406 if( m_sJmpMark.isEmpty() )
407 m_eJumpTo = JUMPTO_NONE;
413 SwHTMLParser::~SwHTMLParser()
415 #ifdef DBG_UTIL
416 OSL_ENSURE( !m_nContinue, "DTOR im Continue!" );
417 #endif
418 bool bAsync = m_pDoc->IsInLoadAsynchron();
419 m_pDoc->SetInLoadAsynchron( false );
420 m_pDoc->getIDocumentSettingAccess().set(DocumentSettingId::HTML_MODE, m_bOldIsHTMLMode);
422 if( m_pDoc->GetDocShell() && m_nEventId )
423 Application::RemoveUserEvent( m_nEventId );
425 // das DocumentDetected kann ggfs. die DocShells loeschen, darum nochmals
426 // abfragen
427 if( m_pDoc->GetDocShell() )
429 // Gelinkte Bereiche updaten
430 sal_uInt16 nLinkMode = m_pDoc->getIDocumentSettingAccess().getLinkUpdateMode( true );
431 if( nLinkMode != NEVER && bAsync &&
432 SfxObjectCreateMode::INTERNAL!=m_pDoc->GetDocShell()->GetCreateMode() )
433 m_pDoc->getIDocumentLinksAdministration().GetLinkManager().UpdateAllLinks( nLinkMode == MANUAL );
435 if ( m_pDoc->GetDocShell()->IsLoading() )
437 // #i59688#
438 m_pDoc->GetDocShell()->LoadingFinished();
442 delete m_pSttNdIdx;
444 if( !m_aSetAttrTab.empty() )
446 OSL_ENSURE( m_aSetAttrTab.empty(),"Es stehen noch Attribute auf dem Stack" );
447 for ( HTMLAttrs::const_iterator it = m_aSetAttrTab.begin();
448 it != m_aSetAttrTab.end(); ++it )
449 delete *it;
450 m_aSetAttrTab.clear();
453 delete m_pCSS1Parser;
454 delete m_pNumRuleInfo;
455 DeleteFormImpl();
456 DeleteFootEndNoteImpl();
458 OSL_ENSURE( !m_pTable, "Es existiert noch eine offene Tabelle" );
459 delete m_pImageMaps;
461 OSL_ENSURE( !m_pPendStack,
462 "SwHTMLParser::~SwHTMLParser: Hier sollte es keinen Pending-Stack mehr geben" );
463 while( m_pPendStack )
465 SwPendingStack* pTmp = m_pPendStack;
466 m_pPendStack = m_pPendStack->pNext;
467 delete pTmp->pData;
468 delete pTmp;
471 if( !m_pDoc->release() )
473 // keiner will mehr das Doc haben, also weg damit
474 delete m_pDoc;
475 m_pDoc = nullptr;
478 if ( m_pTempViewFrame )
480 m_pTempViewFrame->DoClose();
482 // the temporary view frame is hidden, so the hidden flag might need to be removed
483 if ( m_bRemoveHidden && m_pDoc && m_pDoc->GetDocShell() && m_pDoc->GetDocShell()->GetMedium() )
484 m_pDoc->GetDocShell()->GetMedium()->GetItemSet()->ClearItem( SID_HIDDEN );
488 IMPL_LINK_NOARG( SwHTMLParser, AsyncCallback, void*, void )
490 m_nEventId=nullptr;
492 // #i47907# - If the document has already been destructed,
493 // the parser should be aware of this:
494 if( ( m_pDoc->GetDocShell() && m_pDoc->GetDocShell()->IsAbortingImport() )
495 || 1 == m_pDoc->getReferenceCount() )
497 // wurde der Import vom SFX abgebrochen?
498 eState = SVPAR_ERROR;
501 GetAsynchCallLink().Call(nullptr);
504 SvParserState SwHTMLParser::CallParser()
506 // einen temporaeren Index anlegen, auf Pos 0 so wird er nicht bewegt!
507 m_pSttNdIdx = new SwNodeIndex( m_pDoc->GetNodes() );
508 if( !IsNewDoc() ) // in ein Dokument einfuegen ?
510 const SwPosition* pPos = m_pPam->GetPoint();
512 m_pDoc->getIDocumentContentOperations().SplitNode( *pPos, false );
514 *m_pSttNdIdx = pPos->nNode.GetIndex()-1;
515 m_pDoc->getIDocumentContentOperations().SplitNode( *pPos, false );
517 SwPaM aInsertionRangePam( *pPos );
519 m_pPam->Move( fnMoveBackward );
521 // split any redline over the insertion point
522 aInsertionRangePam.SetMark();
523 *aInsertionRangePam.GetPoint() = *m_pPam->GetPoint();
524 aInsertionRangePam.Move( fnMoveBackward );
525 m_pDoc->getIDocumentRedlineAccess().SplitRedline( aInsertionRangePam );
527 m_pDoc->SetTextFormatColl( *m_pPam,
528 m_pCSS1Parser->GetTextCollFromPool( RES_POOLCOLL_STANDARD ));
531 if( GetMedium() )
533 if( !m_bViewCreated )
535 m_nEventId = Application::PostUserEvent( LINK( this, SwHTMLParser, AsyncCallback ) );
537 else
539 m_bViewCreated = true;
540 m_nEventId = nullptr;
544 // Laufbalken anzeigen
545 else if( !GetMedium() || !GetMedium()->IsRemote() )
547 rInput.Seek(STREAM_SEEK_TO_END);
548 rInput.ResetError();
549 ::StartProgress( STR_STATSTR_W4WREAD, 0, rInput.Tell(),
550 m_pDoc->GetDocShell() );
551 rInput.Seek(STREAM_SEEK_TO_BEGIN);
552 rInput.ResetError();
555 m_pDoc->GetPageDesc( 0 ).Add( this );
557 SvParserState eRet = HTMLParser::CallParser();
558 return eRet;
561 void SwHTMLParser::Continue( int nToken )
563 #ifdef DBG_UTIL
564 OSL_ENSURE(!m_nContinue, "Continue im Continue - not supposed to happen");
565 m_nContinue++;
566 #endif
568 // Wenn der Import (vom SFX) abgebrochen wurde, wird ein Fehler
569 // gesetzt aber trotzdem noch weiter gemacht, damit vernuenftig
570 // aufgeraeumt wird.
571 OSL_ENSURE( SVPAR_ERROR!=eState,
572 "SwHTMLParser::Continue: bereits ein Fehler gesetzt" );
573 if( m_pDoc->GetDocShell() && m_pDoc->GetDocShell()->IsAbortingImport() )
574 eState = SVPAR_ERROR;
576 // Die SwViewShell vom Dokument holen, merken und als aktuelle setzen.
577 SwViewShell *pInitVSh = CallStartAction();
579 if( SVPAR_ERROR != eState && GetMedium() && !m_bViewCreated )
581 // Beim ersten Aufruf erstmal returnen, Doc anzeigen
582 // und auf Timer Callback warten.
583 // An dieser Stelle wurde im CallParser gerade mal ein Zeichen
584 // gelesen und ein SaveState(0) gerufen.
585 eState = SVPAR_PENDING;
586 m_bViewCreated = true;
587 m_pDoc->SetInLoadAsynchron( true );
589 #ifdef DBG_UTIL
590 m_nContinue--;
591 #endif
593 return;
596 m_bSetModEnabled = false;
597 if( m_pDoc->GetDocShell() &&
598 (m_bSetModEnabled = m_pDoc->GetDocShell()->IsEnableSetModified()) )
600 m_pDoc->GetDocShell()->EnableSetModified( false );
603 // waehrend des einlesens kein OLE-Modified rufen
604 Link<bool,void> aOLELink( m_pDoc->GetOle2Link() );
605 m_pDoc->SetOle2Link( Link<bool,void>() );
607 bool bModified = m_pDoc->getIDocumentState().IsModified();
608 bool const bWasUndo = m_pDoc->GetIDocumentUndoRedo().DoesUndo();
609 m_pDoc->GetIDocumentUndoRedo().DoUndo(false);
611 // Wenn der Import abgebrochen wird, kein Continue mehr rufen.
612 // Falls ein Pending-Stack existiert aber durch einen Aufruf
613 // von NextToken dafuer sorgen, dass der Pending-Stack noch
614 // beendet wird.
615 if( SVPAR_ERROR == eState )
617 OSL_ENSURE( !m_pPendStack || m_pPendStack->nToken,
618 "SwHTMLParser::Continue: Pending-Stack ohne Token" );
619 if( m_pPendStack && m_pPendStack->nToken )
620 NextToken( m_pPendStack->nToken );
621 OSL_ENSURE( !m_pPendStack,
622 "SwHTMLParser::Continue: Es gibt wieder einen Pend-Stack" );
624 else
626 HTMLParser::Continue( m_pPendStack ? m_pPendStack->nToken : nToken );
629 // Laufbalken wieder abschalten
630 EndProgress( m_pDoc->GetDocShell() );
632 bool bLFStripped = false;
633 if( SVPAR_PENDING != GetStatus() )
635 // noch die letzten Attribute setzen
637 if( !m_aScriptSource.isEmpty() )
639 SwScriptFieldType *pType =
640 static_cast<SwScriptFieldType*>(m_pDoc->getIDocumentFieldsAccess().GetSysFieldType( RES_SCRIPTFLD ));
642 SwScriptField aField( pType, m_aScriptType, m_aScriptSource,
643 false );
644 InsertAttr( SwFormatField( aField ), false );
647 if( m_pAppletImpl )
649 if( m_pAppletImpl->GetApplet().is() )
650 EndApplet();
651 else
652 EndObject();
655 // ggf. ein noch vorhandes LF hinter dem letzen Absatz entfernen
656 if( IsNewDoc() )
657 bLFStripped = StripTrailingLF() > 0;
659 // noch offene Nummerierungen beenden.
660 while( GetNumInfo().GetNumRule() )
661 EndNumBulList();
663 OSL_ENSURE( !m_nContextStMin, "Es gibt geschuetzte Kontexte" );
664 m_nContextStMin = 0;
665 while( m_aContexts.size() )
667 HTMLAttrContext *pCntxt = PopContext();
668 if( pCntxt )
670 EndContext( pCntxt );
671 delete pCntxt;
675 if( !m_aParaAttrs.empty() )
676 m_aParaAttrs.clear();
678 SetAttr( false );
680 // Noch die erst verzoegert gesetzten Styles setzen
681 m_pCSS1Parser->SetDelayedStyles();
684 // den Start wieder korrigieren
685 if( !IsNewDoc() && m_pSttNdIdx->GetIndex() )
687 SwTextNode* pTextNode = m_pSttNdIdx->GetNode().GetTextNode();
688 SwNodeIndex aNxtIdx( *m_pSttNdIdx );
689 if( pTextNode && pTextNode->CanJoinNext( &aNxtIdx ))
691 const sal_Int32 nStt = pTextNode->GetText().getLength();
692 // wenn der Cursor noch in dem Node steht, dann setze in an das Ende
693 if( m_pPam->GetPoint()->nNode == aNxtIdx )
695 m_pPam->GetPoint()->nNode = *m_pSttNdIdx;
696 m_pPam->GetPoint()->nContent.Assign( pTextNode, nStt );
699 #if OSL_DEBUG_LEVEL > 0
700 // !!! sollte nicht moeglich sein, oder ??
701 OSL_ENSURE( m_pSttNdIdx->GetIndex()+1 != m_pPam->GetBound().nNode.GetIndex(),
702 "Pam.Bound1 steht noch im Node" );
703 OSL_ENSURE( m_pSttNdIdx->GetIndex()+1 != m_pPam->GetBound( false ).nNode.GetIndex(),
704 "Pam.Bound2 steht noch im Node" );
706 if( m_pSttNdIdx->GetIndex()+1 == m_pPam->GetBound().nNode.GetIndex() )
708 const sal_Int32 nCntPos = m_pPam->GetBound().nContent.GetIndex();
709 m_pPam->GetBound().nContent.Assign( pTextNode,
710 pTextNode->GetText().getLength() + nCntPos );
712 if( m_pSttNdIdx->GetIndex()+1 == m_pPam->GetBound( false ).nNode.GetIndex() )
714 const sal_Int32 nCntPos = m_pPam->GetBound( false ).nContent.GetIndex();
715 m_pPam->GetBound( false ).nContent.Assign( pTextNode,
716 pTextNode->GetText().getLength() + nCntPos );
718 #endif
719 // Zeichen Attribute beibehalten!
720 SwTextNode* pDelNd = aNxtIdx.GetNode().GetTextNode();
721 if (pTextNode->GetText().getLength())
722 pDelNd->FormatToTextAttr( pTextNode );
723 else
724 pTextNode->ChgFormatColl( pDelNd->GetTextColl() );
725 pTextNode->JoinNext();
730 if( SVPAR_ACCEPTED == eState )
732 if( m_nMissingImgMaps )
734 // es fehlen noch ein paar Image-Map zuordungen.
735 // vielleicht sind die Image-Maps ja jetzt da?
736 ConnectImageMaps();
739 // jetzt noch den letzten ueberfluessigen Absatz loeschen
740 SwPosition* pPos = m_pPam->GetPoint();
741 if( !pPos->nContent.GetIndex() && !bLFStripped )
743 SwTextNode* pAktNd;
744 sal_uLong nNodeIdx = pPos->nNode.GetIndex();
746 bool bHasFlysOrMarks =
747 HasCurrentParaFlys() || HasCurrentParaBookmarks( true );
749 if( IsNewDoc() )
751 const SwNode *pPrev = m_pDoc->GetNodes()[nNodeIdx -1];
752 if( !m_pPam->GetPoint()->nContent.GetIndex() &&
753 ( pPrev->IsContentNode() ||
754 (pPrev->IsEndNode() &&
755 pPrev->StartOfSectionNode()->IsSectionNode()) ) )
757 SwContentNode* pCNd = m_pPam->GetContentNode();
758 if( pCNd && pCNd->StartOfSectionIndex()+2 <
759 pCNd->EndOfSectionIndex() && !bHasFlysOrMarks )
761 SwViewShell *pVSh = CheckActionViewShell();
762 SwCursorShell *pCursorSh = pVSh && dynamic_cast< const SwCursorShell *>( pVSh ) != nullptr
763 ? static_cast < SwCursorShell * >( pVSh )
764 : nullptr;
765 if( pCursorSh &&
766 pCursorSh->GetCursor()->GetPoint()
767 ->nNode.GetIndex() == nNodeIdx )
769 pCursorSh->MovePara(GoPrevPara, fnParaEnd );
770 pCursorSh->SetMark();
771 pCursorSh->ClearMark();
773 m_pPam->GetBound().nContent.Assign( nullptr, 0 );
774 m_pPam->GetBound(false).nContent.Assign( nullptr, 0 );
775 m_pDoc->GetNodes().Delete( m_pPam->GetPoint()->nNode );
779 else if( nullptr != ( pAktNd = m_pDoc->GetNodes()[ nNodeIdx ]->GetTextNode()) && !bHasFlysOrMarks )
781 if( pAktNd->CanJoinNext( &pPos->nNode ))
783 SwTextNode* pNextNd = pPos->nNode.GetNode().GetTextNode();
784 pPos->nContent.Assign( pNextNd, 0 );
785 m_pPam->SetMark(); m_pPam->DeleteMark();
786 pNextNd->JoinPrev();
788 else if (pAktNd->GetText().isEmpty())
790 pPos->nContent.Assign( nullptr, 0 );
791 m_pPam->SetMark(); m_pPam->DeleteMark();
792 m_pDoc->GetNodes().Delete( pPos->nNode );
793 m_pPam->Move( fnMoveBackward );
798 // nun noch das SplitNode vom Anfang aufheben
799 else if( !IsNewDoc() )
801 if( pPos->nContent.GetIndex() ) // dann gabs am Ende kein <P>,
802 m_pPam->Move( fnMoveForward, GoInNode ); // als zum naechsten Node
803 SwTextNode* pTextNode = pPos->nNode.GetNode().GetTextNode();
804 SwNodeIndex aPrvIdx( pPos->nNode );
805 if( pTextNode && pTextNode->CanJoinPrev( &aPrvIdx ) &&
806 *m_pSttNdIdx <= aPrvIdx )
808 // eigentlich muss hier ein JoinNext erfolgen, aber alle Cursor
809 // usw. sind im pTextNode angemeldet, so dass der bestehen
810 // bleiben MUSS.
812 // Absatz in Zeichen-Attribute umwandeln, aus dem Prev die
813 // Absatzattribute und die Vorlage uebernehmen!
814 SwTextNode* pPrev = aPrvIdx.GetNode().GetTextNode();
815 pTextNode->ChgFormatColl( pPrev->GetTextColl() );
816 pTextNode->FormatToTextAttr( pPrev );
817 pTextNode->ResetAllAttr();
819 if( pPrev->HasSwAttrSet() )
820 pTextNode->SetAttr( *pPrev->GetpSwAttrSet() );
822 if( &m_pPam->GetBound().nNode.GetNode() == pPrev )
823 m_pPam->GetBound().nContent.Assign( pTextNode, 0 );
824 if( &m_pPam->GetBound(false).nNode.GetNode() == pPrev )
825 m_pPam->GetBound(false).nContent.Assign( pTextNode, 0 );
827 pTextNode->JoinPrev();
831 // adjust AutoLoad in DocumentProperties
832 if( IsNewDoc() )
834 SwDocShell *pDocShell(m_pDoc->GetDocShell());
835 OSL_ENSURE(pDocShell, "no SwDocShell");
836 if (pDocShell) {
837 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
838 pDocShell->GetModel(), uno::UNO_QUERY_THROW);
839 uno::Reference<document::XDocumentProperties> xDocProps(
840 xDPS->getDocumentProperties());
841 OSL_ENSURE(xDocProps.is(), "DocumentProperties is null");
842 if ( xDocProps.is() && (xDocProps->getAutoloadSecs() > 0) &&
843 (xDocProps->getAutoloadURL().isEmpty()) )
845 xDocProps->setAutoloadURL(m_aPathToFile);
850 if( m_bUpdateDocStat )
852 m_pDoc->getIDocumentStatistics().UpdateDocStat( false, true );
856 if( SVPAR_PENDING != GetStatus() )
858 delete m_pSttNdIdx;
859 m_pSttNdIdx = nullptr;
862 // sollte der Parser der Letzte sein, der das Doc haelt, dann braucht
863 // man hier auch nichts mehr tun, Doc wird gleich zerstoert!
864 if( 1 < m_pDoc->getReferenceCount() )
866 if( bWasUndo )
868 m_pDoc->GetIDocumentUndoRedo().DelAllUndoObj();
869 m_pDoc->GetIDocumentUndoRedo().DoUndo(true);
871 else if( !pInitVSh )
873 // Wenn zu Beginn des Continue keine Shell vorhanden war,
874 // kann trotzdem mitlerweile eine angelegt worden sein.
875 // In dieses Fall stimmt das bWasUndo-Flag nicht und
876 // wir muessen das Undo noch anschalten.
877 SwViewShell *pTmpVSh = CheckActionViewShell();
878 if( pTmpVSh )
880 m_pDoc->GetIDocumentUndoRedo().DoUndo(true);
884 m_pDoc->SetOle2Link( aOLELink );
885 if( !bModified )
886 m_pDoc->getIDocumentState().ResetModified();
887 if( m_bSetModEnabled && m_pDoc->GetDocShell() )
889 m_pDoc->GetDocShell()->EnableSetModified();
890 m_bSetModEnabled = false; // this is unnecessary here
894 // Wenn die Dokuemnt-SwViewShell noch existiert und eine Action
895 // offen ist (muss bei Abbruch nicht sein), die Action beenden,
896 // uns von der Shell abmelden und schliesslich die alte Shell
897 // wieder rekonstruieren.
898 CallEndAction( true );
900 #ifdef DBG_UTIL
901 m_nContinue--;
902 #endif
905 void SwHTMLParser::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew )
907 switch( pOld ? pOld->Which() : pNew ? pNew->Which() : 0 )
909 case RES_OBJECTDYING:
910 if (pOld && static_cast<const SwPtrMsgPoolItem *>(pOld)->pObject == GetRegisteredIn())
912 // dann uns selbst beenden
913 GetRegisteredInNonConst()->Remove( this );
914 ReleaseRef(); // ansonsten sind wir fertig!
916 break;
920 void SwHTMLParser::DocumentDetected()
922 OSL_ENSURE( !m_bDocInitalized, "DocumentDetected mehrfach aufgerufen" );
923 m_bDocInitalized = true;
924 if( IsNewDoc() )
926 if( IsInHeader() )
927 FinishHeader( true );
929 CallEndAction( true );
931 m_pDoc->GetIDocumentUndoRedo().DoUndo(false);
932 // Durch das DocumentDetected wurde im allgemeinen eine
933 // SwViewShell angelegt. Es kann aber auch sein, dass sie
934 // erst spaeter angelegt wird, naemlich dann, wenn die UI
935 // gecaptured ist.
936 CallStartAction();
940 // is called for every token that is recognised in CallParser
941 void SwHTMLParser::NextToken( int nToken )
943 if( ( m_pDoc->GetDocShell() && m_pDoc->GetDocShell()->IsAbortingImport() )
944 || 1 == m_pDoc->getReferenceCount() )
946 // Was the import cancelled by SFX? If a pending stack
947 // exists, clean it.
948 eState = SVPAR_ERROR;
949 OSL_ENSURE( !m_pPendStack || m_pPendStack->nToken,
950 "SwHTMLParser::NextToken: Pending-Stack without token" );
951 if( 1 == m_pDoc->getReferenceCount() || !m_pPendStack )
952 return ;
955 #if OSL_DEBUG_LEVEL > 0
956 if( m_pPendStack )
958 switch( nToken )
960 // tables are read by recursive method calls
961 case HTML_TABLE_ON:
962 // For CSS declarations we might have to wait
963 // for a file download to finish
964 case HTML_LINK:
965 // For controls we might have to set the size.
966 case HTML_INPUT:
967 case HTML_TEXTAREA_ON:
968 case HTML_SELECT_ON:
969 case HTML_SELECT_OFF:
970 break;
971 default:
972 OSL_ENSURE( !m_pPendStack, "Unbekanntes Token fuer Pending-Stack" );
973 break;
976 #endif
978 // The following special cases have to be treated before the
979 // filter detection, because Netscape doesn't reference the content
980 // of the title for filter detection either.
981 if( !m_pPendStack )
983 if( m_bInTitle )
985 switch( nToken )
987 case HTML_TITLE_OFF:
988 if( IsNewDoc() && !m_sTitle.isEmpty() )
990 if( m_pDoc->GetDocShell() ) {
991 uno::Reference<document::XDocumentPropertiesSupplier>
992 xDPS(m_pDoc->GetDocShell()->GetModel(),
993 uno::UNO_QUERY_THROW);
994 uno::Reference<document::XDocumentProperties> xDocProps(
995 xDPS->getDocumentProperties());
996 OSL_ENSURE(xDocProps.is(), "no DocumentProperties");
997 if (xDocProps.is()) {
998 xDocProps->setTitle(m_sTitle);
1001 m_pDoc->GetDocShell()->SetTitle( m_sTitle );
1004 m_bInTitle = false;
1005 m_sTitle.clear();
1006 break;
1008 case HTML_NONBREAKSPACE:
1009 m_sTitle += " ";
1010 break;
1012 case HTML_SOFTHYPH:
1013 m_sTitle += "-";
1014 break;
1016 case HTML_TEXTTOKEN:
1017 m_sTitle += aToken;
1018 break;
1020 default:
1021 m_sTitle += "<";
1022 if( (HTML_TOKEN_ONOFF & nToken) && (1 & nToken) )
1023 m_sTitle += "/";
1024 m_sTitle += sSaveToken;
1025 if( !aToken.isEmpty() )
1027 m_sTitle += " ";
1028 m_sTitle += aToken;
1030 m_sTitle += ">";
1031 break;
1034 return;
1038 // Find out what type of document it is if we don't know already.
1039 // For Controls this has to be finished before the control is inserted
1040 // because for inserting a View is needed.
1041 if( !m_bDocInitalized )
1042 DocumentDetected();
1044 bool bGetIDOption = false, bInsertUnknown = false;
1045 bool bUpperSpaceSave = m_bUpperSpace;
1046 m_bUpperSpace = false;
1048 // The following special cases may or have to be treated after the
1049 // filter detection
1050 if( !m_pPendStack )
1052 if( m_bInFloatingFrame )
1054 // <SCRIPT> is ignored here (from us), because it is ignored in
1055 // Applets as well
1056 if( HTML_IFRAME_OFF == nToken )
1058 m_bCallNextToken = false;
1059 m_bInFloatingFrame = false;
1062 return;
1064 else if( m_bInNoEmbed )
1066 switch( nToken )
1068 case HTML_NOEMBED_OFF:
1069 m_aContents = convertLineEnd(m_aContents, GetSystemLineEnd());
1070 InsertComment( m_aContents, OOO_STRING_SVTOOLS_HTML_noembed );
1071 m_aContents.clear();
1072 m_bCallNextToken = false;
1073 m_bInNoEmbed = false;
1074 break;
1076 case HTML_RAWDATA:
1077 InsertCommentText( OOO_STRING_SVTOOLS_HTML_noembed );
1078 break;
1080 default:
1081 OSL_ENSURE( false, "SwHTMLParser::NextToken: invalid tag" );
1082 break;
1085 return;
1087 else if( m_pAppletImpl )
1089 // in an applet only <PARAM> tags and the </APPLET> tag
1090 // are of interest for us (for the moment)
1091 // <SCRIPT> is ignored here (from Netscape)!
1093 switch( nToken )
1095 case HTML_APPLET_OFF:
1096 m_bCallNextToken = false;
1097 EndApplet();
1098 break;
1099 case HTML_OBJECT_OFF:
1100 m_bCallNextToken = false;
1101 EndObject();
1102 break;
1104 case HTML_PARAM:
1105 InsertParam();
1106 break;
1109 return;
1111 else if( m_bTextArea )
1113 // in a TextArea everything up to </TEXTAREA> is inserted as text.
1114 // <SCRIPT> is ignored here (from Netscape)!
1116 switch( nToken )
1118 case HTML_TEXTAREA_OFF:
1119 m_bCallNextToken = false;
1120 EndTextArea();
1121 break;
1123 default:
1124 InsertTextAreaText( static_cast< sal_uInt16 >(nToken) );
1125 break;
1128 return;
1130 else if( m_bSelect )
1132 // HAS to be treated after bNoScript!
1133 switch( nToken )
1135 case HTML_SELECT_OFF:
1136 m_bCallNextToken = false;
1137 EndSelect();
1138 return;
1140 case HTML_OPTION:
1141 InsertSelectOption();
1142 return;
1144 case HTML_TEXTTOKEN:
1145 InsertSelectText();
1146 return;
1148 case HTML_INPUT:
1149 case HTML_SCRIPT_ON:
1150 case HTML_SCRIPT_OFF:
1151 case HTML_NOSCRIPT_ON:
1152 case HTML_NOSCRIPT_OFF:
1153 case HTML_RAWDATA:
1154 // treat in normal switch
1155 break;
1157 default:
1158 // ignore
1159 return;
1162 else if( m_pMarquee )
1164 // in a TextArea everything up to </TEXTAREA> is inserted as text.
1165 // The <SCRIPT> tags are ignored from MS-IE, we ignore the whole
1166 // script.
1167 switch( nToken )
1169 case HTML_MARQUEE_OFF:
1170 m_bCallNextToken = false;
1171 EndMarquee();
1172 break;
1174 case HTML_TEXTTOKEN:
1175 InsertMarqueeText();
1176 break;
1179 return;
1181 else if( m_bInField )
1183 switch( nToken )
1185 case HTML_SDFIELD_OFF:
1186 m_bCallNextToken = false;
1187 EndField();
1188 break;
1190 case HTML_TEXTTOKEN:
1191 InsertFieldText();
1192 break;
1195 return;
1197 else if( m_bInFootEndNoteAnchor || m_bInFootEndNoteSymbol )
1199 switch( nToken )
1201 case HTML_ANCHOR_OFF:
1202 EndAnchor();
1203 m_bCallNextToken = false;
1204 break;
1206 case HTML_TEXTTOKEN:
1207 InsertFootEndNoteText();
1208 break;
1210 return;
1212 else if( !m_aUnknownToken.isEmpty() )
1214 // Paste content of unknown tags.
1215 // (but surely if we are not in the header section) fdo#36080 fdo#34666
1216 if (!aToken.isEmpty() && !IsInHeader() )
1218 if( !m_bDocInitalized )
1219 DocumentDetected();
1220 m_pDoc->getIDocumentContentOperations().InsertString( *m_pPam, aToken );
1222 // if there are temporary paragraph attributes and the
1223 // paragraph isn't empty then the paragraph attributes
1224 // are final.
1225 if( !m_aParaAttrs.empty() )
1226 m_aParaAttrs.clear();
1228 SetAttr();
1231 // Unknown token in the header are only closed by a matching
1232 // end-token, </HEAD> or <BODY>. Text inside is ignored.
1233 switch( nToken )
1235 case HTML_UNKNOWNCONTROL_OFF:
1236 if( m_aUnknownToken != sSaveToken )
1237 return;
1238 SAL_FALLTHROUGH;
1239 case HTML_FRAMESET_ON:
1240 case HTML_HEAD_OFF:
1241 case HTML_BODY_ON:
1242 case HTML_IMAGE: // Don't know why Netscape acts this way.
1243 m_aUnknownToken.clear();
1244 break;
1245 case HTML_TEXTTOKEN:
1246 return;
1247 default:
1248 m_aUnknownToken.clear();
1249 break;
1254 switch( nToken )
1256 case HTML_BODY_ON:
1257 if( !m_aStyleSource.isEmpty() )
1259 m_pCSS1Parser->ParseStyleSheet( m_aStyleSource );
1260 m_aStyleSource.clear();
1262 if( IsNewDoc() )
1264 InsertBodyOptions();
1265 // If there is a template for the first or the right page,
1266 // it is set here.
1267 const SwPageDesc *pPageDesc = nullptr;
1268 if( m_pCSS1Parser->IsSetFirstPageDesc() )
1269 pPageDesc = m_pCSS1Parser->GetFirstPageDesc();
1270 else if( m_pCSS1Parser->IsSetRightPageDesc() )
1271 pPageDesc = m_pCSS1Parser->GetRightPageDesc();
1273 if( pPageDesc )
1275 m_pDoc->getIDocumentContentOperations().InsertPoolItem( *m_pPam, SwFormatPageDesc( pPageDesc ) );
1278 break;
1280 case HTML_LINK:
1281 InsertLink();
1282 break;
1284 case HTML_BASE:
1286 const HTMLOptions& rHTMLOptions = GetOptions();
1287 for (size_t i = rHTMLOptions.size(); i; )
1289 const HTMLOption& rOption = rHTMLOptions[--i];
1290 switch( rOption.GetToken() )
1292 case HTML_O_HREF:
1293 m_sBaseURL = rOption.GetString();
1294 break;
1295 case HTML_O_TARGET:
1296 if( IsNewDoc() )
1298 SwDocShell *pDocShell(m_pDoc->GetDocShell());
1299 OSL_ENSURE(pDocShell, "no SwDocShell");
1300 if (pDocShell) {
1301 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
1302 pDocShell->GetModel(), uno::UNO_QUERY_THROW);
1303 uno::Reference<document::XDocumentProperties>
1304 xDocProps(xDPS->getDocumentProperties());
1305 OSL_ENSURE(xDocProps.is(),"no DocumentProperties");
1306 if (xDocProps.is()) {
1307 xDocProps->setDefaultTarget(
1308 rOption.GetString());
1312 break;
1316 break;
1318 case HTML_META:
1320 SvKeyValueIterator *pHTTPHeader = nullptr;
1321 if( IsNewDoc() )
1323 SwDocShell *pDocSh = m_pDoc->GetDocShell();
1324 if( pDocSh )
1325 pHTTPHeader = pDocSh->GetHeaderAttributes();
1327 SwDocShell *pDocShell(m_pDoc->GetDocShell());
1328 OSL_ENSURE(pDocShell, "no SwDocShell");
1329 if (pDocShell)
1331 uno::Reference<document::XDocumentProperties> xDocProps;
1332 if (IsNewDoc())
1334 const uno::Reference<document::XDocumentPropertiesSupplier>
1335 xDPS( pDocShell->GetModel(), uno::UNO_QUERY_THROW );
1336 xDocProps = xDPS->getDocumentProperties();
1337 OSL_ENSURE(xDocProps.is(), "DocumentProperties is null");
1339 ParseMetaOptions( xDocProps, pHTTPHeader );
1342 break;
1344 case HTML_TITLE_ON:
1345 m_bInTitle = true;
1346 break;
1348 case HTML_SCRIPT_ON:
1349 NewScript();
1350 break;
1352 case HTML_SCRIPT_OFF:
1353 EndScript();
1354 break;
1356 case HTML_NOSCRIPT_ON:
1357 case HTML_NOSCRIPT_OFF:
1358 bInsertUnknown = true;
1359 break;
1361 case HTML_STYLE_ON:
1362 NewStyle();
1363 break;
1365 case HTML_STYLE_OFF:
1366 EndStyle();
1367 break;
1369 case HTML_RAWDATA:
1370 if( !m_bIgnoreRawData )
1372 if( IsReadScript() )
1374 AddScriptSource();
1376 else if( IsReadStyle() )
1378 if( !m_aStyleSource.isEmpty() )
1379 m_aStyleSource += "\n";
1380 m_aStyleSource += aToken;
1383 break;
1385 case HTML_OBJECT_ON:
1386 #if HAVE_FEATURE_JAVA
1387 NewObject();
1388 m_bCallNextToken = m_pAppletImpl!=nullptr && m_pTable!=nullptr;
1389 #endif
1390 break;
1392 case HTML_APPLET_ON:
1393 #if HAVE_FEATURE_JAVA
1394 InsertApplet();
1395 m_bCallNextToken = m_pAppletImpl!=nullptr && m_pTable!=nullptr;
1396 #endif
1397 break;
1399 case HTML_IFRAME_ON:
1400 InsertFloatingFrame();
1401 m_bCallNextToken = m_bInFloatingFrame && m_pTable!=nullptr;
1402 break;
1404 case HTML_LINEBREAK:
1405 if( !IsReadPRE() )
1407 InsertLineBreak();
1408 break;
1410 else
1411 bGetIDOption = true;
1412 // <BR>s in <PRE> resemble true LFs, hence no break
1413 SAL_FALLTHROUGH;
1415 case HTML_NEWPARA:
1416 // CR in PRE/LISTING/XMP
1418 if( HTML_NEWPARA==nToken ||
1419 m_pPam->GetPoint()->nContent.GetIndex() )
1421 AppendTextNode(); // there is no LF at this place
1422 // therefore it will cause no problems
1423 SetTextCollAttrs();
1425 // progress bar
1426 if( !GetMedium() || !GetMedium()->IsRemote() )
1427 ::SetProgressState( rInput.Tell(), m_pDoc->GetDocShell() );
1429 break;
1431 case HTML_NONBREAKSPACE:
1432 m_pDoc->getIDocumentContentOperations().InsertString( *m_pPam, OUString(CHAR_HARDBLANK) );
1433 break;
1435 case HTML_SOFTHYPH:
1436 m_pDoc->getIDocumentContentOperations().InsertString( *m_pPam, OUString(CHAR_SOFTHYPHEN) );
1437 break;
1439 case HTML_LINEFEEDCHAR:
1440 if( m_pPam->GetPoint()->nContent.GetIndex() )
1441 AppendTextNode();
1442 if( !m_pTable && !m_pDoc->IsInHeaderFooter( m_pPam->GetPoint()->nNode ) )
1444 NewAttr( &m_aAttrTab.pBreak, SvxFormatBreakItem(SvxBreak::PageBefore, RES_BREAK) );
1445 EndAttr( m_aAttrTab.pBreak, false );
1447 break;
1449 case HTML_TEXTTOKEN:
1450 // insert string without spanning attributes at the end.
1451 if( !aToken.isEmpty() && ' '==aToken[0] && !IsReadPRE() )
1453 sal_Int32 nPos = m_pPam->GetPoint()->nContent.GetIndex();
1454 if( nPos )
1456 const OUString& rText =
1457 m_pPam->GetPoint()->nNode.GetNode().GetTextNode()->GetText();
1458 sal_Unicode cLast = rText[--nPos];
1459 if( ' ' == cLast || '\x0a' == cLast)
1460 aToken = aToken.copy(1);
1462 else
1463 aToken = aToken.copy(1);
1465 if( aToken.isEmpty() )
1467 m_bUpperSpace = bUpperSpaceSave;
1468 break;
1472 if( !aToken.isEmpty() )
1474 if( !m_bDocInitalized )
1475 DocumentDetected();
1476 m_pDoc->getIDocumentContentOperations().InsertString( *m_pPam, aToken );
1478 // if there are temporary paragraph attributes and the
1479 // paragraph isn't empty then the paragraph attributes
1480 // are final.
1481 if( !m_aParaAttrs.empty() )
1482 m_aParaAttrs.clear();
1484 SetAttr();
1486 break;
1488 case HTML_HORZRULE:
1489 InsertHorzRule();
1490 break;
1492 case HTML_IMAGE:
1493 InsertImage();
1494 // if only the parser references the doc, we can break and set
1495 // an error code
1496 if( 1 == m_pDoc->getReferenceCount() )
1498 eState = SVPAR_ERROR;
1500 break;
1502 case HTML_SPACER:
1503 InsertSpacer();
1504 break;
1506 case HTML_EMBED:
1507 InsertEmbed();
1508 break;
1510 case HTML_NOEMBED_ON:
1511 m_bInNoEmbed = true;
1512 m_bCallNextToken = m_pTable!=nullptr;
1513 ReadRawData( OOO_STRING_SVTOOLS_HTML_noembed );
1514 break;
1516 case HTML_DEFLIST_ON:
1517 if( m_nOpenParaToken )
1518 EndPara();
1519 NewDefList();
1520 break;
1521 case HTML_DEFLIST_OFF:
1522 if( m_nOpenParaToken )
1523 EndPara();
1524 EndDefListItem( 0, 1==m_nDefListDeep );
1525 EndDefList();
1526 break;
1528 case HTML_DD_ON:
1529 case HTML_DT_ON:
1530 if( m_nOpenParaToken )
1531 EndPara();
1532 EndDefListItem();// close <DD>/<DT> and set no template
1533 NewDefListItem( nToken );
1534 break;
1536 case HTML_DD_OFF:
1537 case HTML_DT_OFF:
1538 // c.f. HTML_LI_OFF
1539 // Actually we should close a DD/DT now.
1540 // But neither Netscape nor Microsoft do this and so don't we.
1541 EndDefListItem( nToken );
1542 break;
1544 // divisions
1545 case HTML_DIVISION_ON:
1546 case HTML_CENTER_ON:
1547 if (!m_isInTableStructure)
1549 if( m_nOpenParaToken )
1551 if( IsReadPRE() )
1552 m_nOpenParaToken = 0;
1553 else
1554 EndPara();
1556 NewDivision( nToken );
1558 break;
1560 case HTML_DIVISION_OFF:
1561 case HTML_CENTER_OFF:
1562 if (!m_isInTableStructure)
1564 if( m_nOpenParaToken )
1566 if( IsReadPRE() )
1567 m_nOpenParaToken = 0;
1568 else
1569 EndPara();
1571 EndDivision( nToken );
1573 break;
1575 case HTML_MULTICOL_ON:
1576 if( m_nOpenParaToken )
1577 EndPara();
1578 NewMultiCol();
1579 break;
1581 case HTML_MULTICOL_OFF:
1582 if( m_nOpenParaToken )
1583 EndPara();
1584 EndTag( HTML_MULTICOL_ON );
1585 break;
1587 case HTML_MARQUEE_ON:
1588 NewMarquee();
1589 m_bCallNextToken = m_pMarquee!=nullptr && m_pTable!=nullptr;
1590 break;
1592 case HTML_FORM_ON:
1593 NewForm();
1594 break;
1595 case HTML_FORM_OFF:
1596 EndForm();
1597 break;
1599 // templates
1600 case HTML_PARABREAK_ON:
1601 if( m_nOpenParaToken )
1602 EndPara( true );
1603 NewPara();
1604 break;
1606 case HTML_PARABREAK_OFF:
1607 EndPara( true );
1608 break;
1610 case HTML_ADDRESS_ON:
1611 if( m_nOpenParaToken )
1612 EndPara();
1613 NewTextFormatColl( HTML_ADDRESS_ON, RES_POOLCOLL_SENDADRESS );
1614 break;
1616 case HTML_ADDRESS_OFF:
1617 if( m_nOpenParaToken )
1618 EndPara();
1619 EndTextFormatColl( HTML_ADDRESS_OFF );
1620 break;
1622 case HTML_BLOCKQUOTE_ON:
1623 case HTML_BLOCKQUOTE30_ON:
1624 if( m_nOpenParaToken )
1625 EndPara();
1626 NewTextFormatColl( HTML_BLOCKQUOTE_ON, RES_POOLCOLL_HTML_BLOCKQUOTE );
1627 break;
1629 case HTML_BLOCKQUOTE_OFF:
1630 case HTML_BLOCKQUOTE30_OFF:
1631 if( m_nOpenParaToken )
1632 EndPara();
1633 EndTextFormatColl( HTML_BLOCKQUOTE_ON );
1634 break;
1636 case HTML_PREFORMTXT_ON:
1637 case HTML_LISTING_ON:
1638 case HTML_XMP_ON:
1639 if( m_nOpenParaToken )
1640 EndPara();
1641 NewTextFormatColl( nToken, RES_POOLCOLL_HTML_PRE );
1642 break;
1644 case HTML_PREFORMTXT_OFF:
1645 m_bNoParSpace = true; // the last PRE-paragraph gets a spacing
1646 EndTextFormatColl( HTML_PREFORMTXT_OFF );
1647 break;
1649 case HTML_LISTING_OFF:
1650 case HTML_XMP_OFF:
1651 EndTextFormatColl( nToken );
1652 break;
1654 case HTML_HEAD1_ON:
1655 case HTML_HEAD2_ON:
1656 case HTML_HEAD3_ON:
1657 case HTML_HEAD4_ON:
1658 case HTML_HEAD5_ON:
1659 case HTML_HEAD6_ON:
1660 if( m_nOpenParaToken )
1662 if( IsReadPRE() )
1663 m_nOpenParaToken = 0;
1664 else
1665 EndPara();
1667 NewHeading( nToken );
1668 break;
1670 case HTML_HEAD1_OFF:
1671 case HTML_HEAD2_OFF:
1672 case HTML_HEAD3_OFF:
1673 case HTML_HEAD4_OFF:
1674 case HTML_HEAD5_OFF:
1675 case HTML_HEAD6_OFF:
1676 EndHeading();
1677 break;
1679 case HTML_TABLE_ON:
1680 if( m_pPendStack )
1681 BuildTable( SVX_ADJUST_END );
1682 else
1684 if( m_nOpenParaToken )
1685 EndPara();
1686 OSL_ENSURE( !m_pTable, "table in table not allowed here" );
1687 if( !m_pTable && (IsNewDoc() || !m_pPam->GetNode().FindTableNode()) &&
1688 (m_pPam->GetPoint()->nNode.GetIndex() >
1689 m_pDoc->GetNodes().GetEndOfExtras().GetIndex() ||
1690 !m_pPam->GetNode().FindFootnoteStartNode() ) )
1692 if ( m_nParaCnt < 5 )
1693 Show(); // show what we have up to here
1695 SvxAdjust eAdjust = m_aAttrTab.pAdjust
1696 ? static_cast<const SvxAdjustItem&>(m_aAttrTab.pAdjust->GetItem()).
1697 GetAdjust()
1698 : SVX_ADJUST_END;
1699 BuildTable( eAdjust );
1701 else
1702 bInsertUnknown = m_bKeepUnknown;
1704 break;
1706 // lists
1707 case HTML_DIRLIST_ON:
1708 case HTML_MENULIST_ON:
1709 case HTML_ORDERLIST_ON:
1710 case HTML_UNORDERLIST_ON:
1711 if( m_nOpenParaToken )
1712 EndPara();
1713 NewNumBulList( nToken );
1714 break;
1716 case HTML_DIRLIST_OFF:
1717 case HTML_MENULIST_OFF:
1718 case HTML_ORDERLIST_OFF:
1719 case HTML_UNORDERLIST_OFF:
1720 if( m_nOpenParaToken )
1721 EndPara();
1722 EndNumBulListItem( 0, true, GetNumInfo().GetDepth()==1 );
1723 EndNumBulList( nToken );
1724 break;
1726 case HTML_LI_ON:
1727 case HTML_LISTHEADER_ON:
1728 if( m_nOpenParaToken &&
1729 (m_pPam->GetPoint()->nContent.GetIndex()
1730 || HTML_PARABREAK_ON==m_nOpenParaToken) )
1732 // only finish paragraph for <P><LI>, not for <DD><LI>
1733 EndPara();
1736 EndNumBulListItem( 0, false );// close <LI>/<LH> and don't set a template
1737 NewNumBulListItem( nToken );
1738 break;
1740 case HTML_LI_OFF:
1741 case HTML_LISTHEADER_OFF:
1742 EndNumBulListItem( nToken, false );
1743 break;
1745 // Attribute :
1746 case HTML_ITALIC_ON:
1748 SvxPostureItem aPosture( ITALIC_NORMAL, RES_CHRATR_POSTURE );
1749 SvxPostureItem aPostureCJK( ITALIC_NORMAL, RES_CHRATR_CJK_POSTURE );
1750 SvxPostureItem aPostureCTL( ITALIC_NORMAL, RES_CHRATR_CTL_POSTURE );
1751 NewStdAttr( HTML_ITALIC_ON,
1752 &m_aAttrTab.pItalic, aPosture,
1753 &m_aAttrTab.pItalicCJK, &aPostureCJK,
1754 &m_aAttrTab.pItalicCTL, &aPostureCTL );
1756 break;
1758 case HTML_BOLD_ON:
1760 SvxWeightItem aWeight( WEIGHT_BOLD, RES_CHRATR_WEIGHT );
1761 SvxWeightItem aWeightCJK( WEIGHT_BOLD, RES_CHRATR_CJK_WEIGHT );
1762 SvxWeightItem aWeightCTL( WEIGHT_BOLD, RES_CHRATR_CTL_WEIGHT );
1763 NewStdAttr( HTML_BOLD_ON,
1764 &m_aAttrTab.pBold, aWeight,
1765 &m_aAttrTab.pBoldCJK, &aWeightCJK,
1766 &m_aAttrTab.pBoldCTL, &aWeightCTL );
1768 break;
1770 case HTML_STRIKE_ON:
1771 case HTML_STRIKETHROUGH_ON:
1773 NewStdAttr( HTML_STRIKE_ON, &m_aAttrTab.pStrike,
1774 SvxCrossedOutItem(STRIKEOUT_SINGLE, RES_CHRATR_CROSSEDOUT) );
1776 break;
1778 case HTML_UNDERLINE_ON:
1780 NewStdAttr( HTML_UNDERLINE_ON, &m_aAttrTab.pUnderline,
1781 SvxUnderlineItem(LINESTYLE_SINGLE, RES_CHRATR_UNDERLINE) );
1783 break;
1785 case HTML_SUPERSCRIPT_ON:
1787 NewStdAttr( HTML_SUPERSCRIPT_ON, &m_aAttrTab.pEscapement,
1788 SvxEscapementItem(HTML_ESC_SUPER,HTML_ESC_PROP, RES_CHRATR_ESCAPEMENT) );
1790 break;
1792 case HTML_SUBSCRIPT_ON:
1794 NewStdAttr( HTML_SUBSCRIPT_ON, &m_aAttrTab.pEscapement,
1795 SvxEscapementItem(HTML_ESC_SUB,HTML_ESC_PROP, RES_CHRATR_ESCAPEMENT) );
1797 break;
1799 case HTML_BLINK_ON:
1801 NewStdAttr( HTML_BLINK_ON, &m_aAttrTab.pBlink,
1802 SvxBlinkItem( true, RES_CHRATR_BLINK ) );
1804 break;
1806 case HTML_SPAN_ON:
1807 NewStdAttr( HTML_SPAN_ON );
1808 break;
1810 case HTML_ITALIC_OFF:
1811 case HTML_BOLD_OFF:
1812 case HTML_STRIKE_OFF:
1813 case HTML_UNDERLINE_OFF:
1814 case HTML_SUPERSCRIPT_OFF:
1815 case HTML_SUBSCRIPT_OFF:
1816 case HTML_BLINK_OFF:
1817 case HTML_SPAN_OFF:
1818 EndTag( nToken );
1819 break;
1821 case HTML_STRIKETHROUGH_OFF:
1822 EndTag( HTML_STRIKE_OFF );
1823 break;
1825 case HTML_BASEFONT_ON:
1826 NewBasefontAttr();
1827 break;
1828 case HTML_BASEFONT_OFF:
1829 EndBasefontAttr();
1830 break;
1831 case HTML_FONT_ON:
1832 case HTML_BIGPRINT_ON:
1833 case HTML_SMALLPRINT_ON:
1834 NewFontAttr( nToken );
1835 break;
1836 case HTML_FONT_OFF:
1837 case HTML_BIGPRINT_OFF:
1838 case HTML_SMALLPRINT_OFF:
1839 EndFontAttr( nToken );
1840 break;
1842 case HTML_EMPHASIS_ON:
1843 case HTML_CITIATION_ON:
1844 case HTML_STRONG_ON:
1845 case HTML_CODE_ON:
1846 case HTML_SAMPLE_ON:
1847 case HTML_KEYBOARD_ON:
1848 case HTML_VARIABLE_ON:
1849 case HTML_DEFINSTANCE_ON:
1850 case HTML_SHORTQUOTE_ON:
1851 case HTML_LANGUAGE_ON:
1852 case HTML_AUTHOR_ON:
1853 case HTML_PERSON_ON:
1854 case HTML_ACRONYM_ON:
1855 case HTML_ABBREVIATION_ON:
1856 case HTML_INSERTEDTEXT_ON:
1857 case HTML_DELETEDTEXT_ON:
1859 case HTML_TELETYPE_ON:
1860 NewCharFormat( nToken );
1861 break;
1863 case HTML_SDFIELD_ON:
1864 NewField();
1865 m_bCallNextToken = m_bInField && m_pTable!=nullptr;
1866 break;
1868 case HTML_EMPHASIS_OFF:
1869 case HTML_CITIATION_OFF:
1870 case HTML_STRONG_OFF:
1871 case HTML_CODE_OFF:
1872 case HTML_SAMPLE_OFF:
1873 case HTML_KEYBOARD_OFF:
1874 case HTML_VARIABLE_OFF:
1875 case HTML_DEFINSTANCE_OFF:
1876 case HTML_SHORTQUOTE_OFF:
1877 case HTML_LANGUAGE_OFF:
1878 case HTML_AUTHOR_OFF:
1879 case HTML_PERSON_OFF:
1880 case HTML_ACRONYM_OFF:
1881 case HTML_ABBREVIATION_OFF:
1882 case HTML_INSERTEDTEXT_OFF:
1883 case HTML_DELETEDTEXT_OFF:
1885 case HTML_TELETYPE_OFF:
1886 EndTag( nToken );
1887 break;
1889 case HTML_HEAD_OFF:
1890 if( !m_aStyleSource.isEmpty() )
1892 m_pCSS1Parser->ParseStyleSheet( m_aStyleSource );
1893 m_aStyleSource.clear();
1895 break;
1897 case HTML_DOCTYPE:
1898 case HTML_BODY_OFF:
1899 case HTML_HTML_OFF:
1900 case HTML_HEAD_ON:
1901 case HTML_TITLE_OFF:
1902 break; // don't evaluate further???
1903 case HTML_HTML_ON:
1905 const HTMLOptions& rHTMLOptions = GetOptions();
1906 for (size_t i = rHTMLOptions.size(); i; )
1908 const HTMLOption& rOption = rHTMLOptions[--i];
1909 if( HTML_O_DIR == rOption.GetToken() )
1911 const OUString& rDir = rOption.GetString();
1912 SfxItemSet aItemSet( m_pDoc->GetAttrPool(),
1913 m_pCSS1Parser->GetWhichMap() );
1914 SvxCSS1PropertyInfo aPropInfo;
1915 OUString aDummy;
1916 ParseStyleOptions( aDummy, aDummy, aDummy, aItemSet,
1917 aPropInfo, nullptr, &rDir );
1919 m_pCSS1Parser->SetPageDescAttrs( nullptr, &aItemSet );
1920 break;
1924 break;
1926 case HTML_INPUT:
1927 InsertInput();
1928 break;
1930 case HTML_TEXTAREA_ON:
1931 NewTextArea();
1932 m_bCallNextToken = m_bTextArea && m_pTable!=nullptr;
1933 break;
1935 case HTML_SELECT_ON:
1936 NewSelect();
1937 m_bCallNextToken = m_bSelect && m_pTable!=nullptr;
1938 break;
1940 case HTML_ANCHOR_ON:
1941 NewAnchor();
1942 break;
1944 case HTML_ANCHOR_OFF:
1945 EndAnchor();
1946 break;
1948 case HTML_COMMENT:
1949 if( ( aToken.getLength() > 5 ) && ( ! m_bIgnoreHTMLComments ) )
1951 // insert as Post-It
1952 // If there are no space characters right behind
1953 // the <!-- and on front of the -->, leave the comment untouched.
1954 if( ' ' == aToken[ 3 ] &&
1955 ' ' == aToken[ aToken.getLength()-3 ] )
1957 OUString aComment( aToken.copy( 3, aToken.getLength()-5 ) );
1958 InsertComment(comphelper::string::strip(aComment, ' '));
1960 else
1962 OUStringBuffer aComment;
1963 aComment.append('<').append(aToken).append('>');
1964 InsertComment( aComment.makeStringAndClear() );
1967 break;
1969 case HTML_MAP_ON:
1970 // Image Maps are read asynchronously: At first only an image map is created
1971 // Areas are processed later. Nevertheless the
1972 // ImageMap is inserted into the IMap-Array, because it might be used
1973 // already.
1974 m_pImageMap = new ImageMap;
1975 if( ParseMapOptions( m_pImageMap) )
1977 if (!m_pImageMaps)
1978 m_pImageMaps = new ImageMaps;
1979 m_pImageMaps->push_back(std::unique_ptr<ImageMap>(m_pImageMap));
1981 else
1983 delete m_pImageMap;
1984 m_pImageMap = nullptr;
1986 break;
1988 case HTML_MAP_OFF:
1989 // there is no ImageMap anymore (don't delete IMap, because it's
1990 // already contained in the array!)
1991 m_pImageMap = nullptr;
1992 break;
1994 case HTML_AREA:
1995 if( m_pImageMap )
1996 ParseAreaOptions( m_pImageMap, m_sBaseURL, SFX_EVENT_MOUSEOVER_OBJECT,
1997 SFX_EVENT_MOUSEOUT_OBJECT );
1998 break;
2000 case HTML_FRAMESET_ON:
2001 bInsertUnknown = m_bKeepUnknown;
2002 break;
2004 case HTML_NOFRAMES_ON:
2005 if( IsInHeader() )
2006 FinishHeader( true );
2007 bInsertUnknown = m_bKeepUnknown;
2008 break;
2010 case HTML_UNKNOWNCONTROL_ON:
2011 // Ignore content of unknown token in the header, if the token
2012 // does not start with a '!'.
2013 // (but judging from the code, also if does not start with a '%')
2014 // (and also if we're not somewhere we consider PRE)
2015 if( IsInHeader() && !IsReadPRE() && m_aUnknownToken.isEmpty() &&
2016 !sSaveToken.isEmpty() && '!' != sSaveToken[0] &&
2017 '%' != sSaveToken[0] )
2018 m_aUnknownToken = sSaveToken;
2019 SAL_FALLTHROUGH;
2021 default:
2022 bInsertUnknown = m_bKeepUnknown;
2023 break;
2026 if( bGetIDOption )
2027 InsertIDOption();
2029 if( bInsertUnknown )
2031 OUString aComment("HTML: <");
2032 if( (HTML_TOKEN_ONOFF & nToken) != 0 && (1 & nToken) != 0 )
2033 aComment += "/";
2034 aComment += sSaveToken;
2035 if( !aToken.isEmpty() )
2037 UnescapeToken();
2038 (aComment += " ") += aToken;
2040 aComment += ">";
2041 InsertComment( aComment );
2044 // if there are temporary paragraph attributes and the
2045 // paragraph isn't empty then the paragraph attributes are final.
2046 if( !m_aParaAttrs.empty() && m_pPam->GetPoint()->nContent.GetIndex() )
2047 m_aParaAttrs.clear();
2050 static void lcl_swhtml_getItemInfo( const HTMLAttr& rAttr,
2051 bool& rScriptDependent, bool& rFont,
2052 sal_uInt16& rScriptType )
2054 switch( rAttr.GetItem().Which() )
2056 case RES_CHRATR_FONT:
2057 rFont = true;
2058 SAL_FALLTHROUGH;
2059 case RES_CHRATR_FONTSIZE:
2060 case RES_CHRATR_LANGUAGE:
2061 case RES_CHRATR_POSTURE:
2062 case RES_CHRATR_WEIGHT:
2063 rScriptType = i18n::ScriptType::LATIN;
2064 rScriptDependent = true;
2065 break;
2066 case RES_CHRATR_CJK_FONT:
2067 rFont = true;
2068 SAL_FALLTHROUGH;
2069 case RES_CHRATR_CJK_FONTSIZE:
2070 case RES_CHRATR_CJK_LANGUAGE:
2071 case RES_CHRATR_CJK_POSTURE:
2072 case RES_CHRATR_CJK_WEIGHT:
2073 rScriptType = i18n::ScriptType::ASIAN;
2074 rScriptDependent = true;
2075 break;
2076 case RES_CHRATR_CTL_FONT:
2077 rFont = true;
2078 SAL_FALLTHROUGH;
2079 case RES_CHRATR_CTL_FONTSIZE:
2080 case RES_CHRATR_CTL_LANGUAGE:
2081 case RES_CHRATR_CTL_POSTURE:
2082 case RES_CHRATR_CTL_WEIGHT:
2083 rScriptType = i18n::ScriptType::COMPLEX;
2084 rScriptDependent = true;
2085 break;
2086 default:
2087 rScriptDependent = false;
2088 rFont = false;
2089 break;
2093 bool SwHTMLParser::AppendTextNode( SwHTMLAppendMode eMode, bool bUpdateNum )
2095 // Ein harter Zeilen-Umbruch am Ende muss immer entfernt werden.
2096 // Einen zweiten ersetzen wir durch einen Absatz-Abstand.
2097 sal_Int32 nLFStripped = StripTrailingLF();
2098 if( (AM_NOSPACE==eMode || AM_SOFTNOSPACE==eMode) && nLFStripped > 1 )
2099 eMode = AM_SPACE;
2101 // die harten Attribute an diesem Absatz werden nie mehr ungueltig
2102 if( !m_aParaAttrs.empty() )
2103 m_aParaAttrs.clear();
2105 if( AM_SPACE==eMode || AM_NOSPACE==eMode )
2107 SwTextNode *pTextNode =
2108 m_pPam->GetPoint()->nNode.GetNode().GetTextNode();
2110 const SvxULSpaceItem& rULSpace =
2111 static_cast<const SvxULSpaceItem&>(pTextNode->SwContentNode::GetAttr( RES_UL_SPACE ));
2113 bool bChange = AM_NOSPACE==eMode ? rULSpace.GetLower() > 0
2114 : rULSpace.GetLower() == 0;
2116 if( bChange )
2118 const SvxULSpaceItem& rCollULSpace =
2119 pTextNode->GetAnyFormatColl().GetULSpace();
2121 bool bMayReset = AM_NOSPACE==eMode ? rCollULSpace.GetLower() == 0
2122 : rCollULSpace.GetLower() > 0;
2124 if( bMayReset &&
2125 rCollULSpace.GetUpper() == rULSpace.GetUpper() )
2127 pTextNode->ResetAttr( RES_UL_SPACE );
2129 else
2131 pTextNode->SetAttr(
2132 SvxULSpaceItem( rULSpace.GetUpper(),
2133 AM_NOSPACE==eMode ? 0 : HTML_PARSPACE, RES_UL_SPACE ) );
2137 m_bNoParSpace = AM_NOSPACE==eMode || AM_SOFTNOSPACE==eMode;
2139 SwPosition aOldPos( *m_pPam->GetPoint() );
2141 bool bRet = m_pDoc->getIDocumentContentOperations().AppendTextNode( *m_pPam->GetPoint() );
2143 // Zeichen-Attribute aufspalten und ggf keine setzen, die ueber den
2144 // ganzen Absatz gesetzt sind
2145 const SwNodeIndex& rEndIdx = aOldPos.nNode;
2146 const sal_Int32 nEndCnt = aOldPos.nContent.GetIndex();
2147 const SwPosition& rPos = *m_pPam->GetPoint();
2149 HTMLAttr** pHTMLAttributes = reinterpret_cast<HTMLAttr**>(&m_aAttrTab);
2150 for (auto nCnt = sizeof(HTMLAttrTable) / sizeof(HTMLAttr*); nCnt--; ++pHTMLAttributes)
2152 HTMLAttr *pAttr = *pHTMLAttributes;
2153 if( pAttr && pAttr->GetItem().Which() < RES_PARATR_BEGIN )
2155 bool bWholePara = false;
2157 while( pAttr )
2159 HTMLAttr *pNext = pAttr->GetNext();
2160 if( pAttr->GetSttParaIdx() < rEndIdx.GetIndex() ||
2161 (!bWholePara &&
2162 pAttr->GetSttPara() == rEndIdx &&
2163 pAttr->GetSttCnt() != nEndCnt) )
2165 bWholePara =
2166 pAttr->GetSttPara() == rEndIdx &&
2167 pAttr->GetSttCnt() == 0;
2169 sal_Int32 nStt = pAttr->nSttContent;
2170 bool bScript = false, bFont = false;
2171 sal_uInt16 nScriptItem;
2172 bool bInsert = true;
2173 lcl_swhtml_getItemInfo( *pAttr, bScript, bFont,
2174 nScriptItem );
2175 // den besehrigen Teil setzen
2176 if( bInsert && bScript )
2178 const SwTextNode *pTextNd =
2179 pAttr->GetSttPara().GetNode().GetTextNode();
2180 OSL_ENSURE( pTextNd, "No text node" );
2181 if( pTextNd )
2183 const OUString& rText = pTextNd->GetText();
2184 sal_uInt16 nScriptText =
2185 g_pBreakIt->GetBreakIter()->getScriptType(
2186 rText, pAttr->GetSttCnt() );
2187 sal_Int32 nScriptEnd = g_pBreakIt->GetBreakIter()
2188 ->endOfScript( rText, nStt, nScriptText );
2189 while (nScriptEnd < nEndCnt && nScriptEnd != -1)
2191 if( nScriptItem == nScriptText )
2193 HTMLAttr *pSetAttr =
2194 pAttr->Clone( rEndIdx, nScriptEnd );
2195 pSetAttr->nSttContent = nStt;
2196 pSetAttr->ClearPrev();
2197 if( !pNext || bWholePara )
2199 if (pSetAttr->bInsAtStart)
2200 m_aSetAttrTab.push_front( pSetAttr );
2201 else
2202 m_aSetAttrTab.push_back( pSetAttr );
2204 else
2205 pNext->InsertPrev( pSetAttr );
2207 nStt = nScriptEnd;
2208 nScriptText = g_pBreakIt->GetBreakIter()->getScriptType(
2209 rText, nStt );
2210 nScriptEnd = g_pBreakIt->GetBreakIter()
2211 ->endOfScript( rText, nStt, nScriptText );
2213 bInsert = nScriptItem == nScriptText;
2216 if( bInsert )
2218 HTMLAttr *pSetAttr =
2219 pAttr->Clone( rEndIdx, nEndCnt );
2220 pSetAttr->nSttContent = nStt;
2222 // Wenn das Attribut den gesamten Absatz umspannt, werden
2223 // alle auesseren Attribute nicht mehr beachtet. Deshalb
2224 // darf es auch nicht in die Prev-Liste eines ausseren
2225 // Attributs eingetragen werden, denn dieses wird ja
2226 // erstmal nicht gesetzt. Das fuehrt zu verschiebenungen,
2227 // wenn Felder ins Rennen kommen
2228 if( !pNext || bWholePara )
2230 if (pSetAttr->bInsAtStart)
2231 m_aSetAttrTab.push_front( pSetAttr );
2232 else
2233 m_aSetAttrTab.push_back( pSetAttr );
2235 else
2236 pNext->InsertPrev( pSetAttr );
2238 else
2240 HTMLAttr *pPrev = pAttr->GetPrev();
2241 if( pPrev )
2243 // Die Previous-Attribute muessen trotzdem gesetzt werden.
2244 if( !pNext || bWholePara )
2246 if (pPrev->bInsAtStart)
2247 m_aSetAttrTab.push_front( pPrev );
2248 else
2249 m_aSetAttrTab.push_back( pPrev );
2251 else
2252 pNext->InsertPrev( pPrev );
2255 pAttr->ClearPrev();
2258 pAttr->SetStart( rPos );
2259 pAttr = pNext;
2264 if( bUpdateNum )
2266 if( GetNumInfo().GetDepth() )
2268 sal_uInt8 nLvl = GetNumInfo().GetLevel();
2269 SetNodeNum( nLvl );
2271 else
2272 m_pPam->GetNode().GetTextNode()->ResetAttr( RES_PARATR_NUMRULE );
2275 // We must set the attribute of the paragraph before now (because of JavaScript)
2276 SetAttr();
2278 // Now it is time to get rid of all script dependent hints that are
2279 // equal to the settings in the style
2280 SwTextNode *pTextNd = rEndIdx.GetNode().GetTextNode();
2281 OSL_ENSURE( pTextNd, "There is the txt node" );
2282 size_t nCntAttr = (pTextNd && pTextNd->GetpSwpHints())
2283 ? pTextNd->GetSwpHints().Count() : 0;
2284 if( nCntAttr )
2286 // These are the end position of all script dependent hints.
2287 // If we find a hint that starts before the current end position,
2288 // we have to set it. If we find a hint that start behind or at
2289 // that position, we have to take the hint value into account.
2290 // If it is equal to the style, or in fact the paragarph value
2291 // for that hint, the hint is removed. Otherwise its end position
2292 // is remembered.
2293 sal_Int32 aEndPos[15] =
2294 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
2295 SwpHints& rHints = pTextNd->GetSwpHints();
2296 for( size_t i=0; i < nCntAttr; i++ )
2298 SwTextAttr *pHt = rHints.Get( i );
2299 sal_uInt16 nWhich = pHt->Which();
2300 sal_Int16 nIdx = 0;
2301 bool bFont = false;
2302 switch( nWhich )
2304 case RES_CHRATR_FONT:
2305 nIdx = 0;
2306 bFont = true;
2307 break;
2308 case RES_CHRATR_FONTSIZE:
2309 nIdx = 1;
2310 break;
2311 case RES_CHRATR_LANGUAGE:
2312 nIdx = 2;
2313 break;
2314 case RES_CHRATR_POSTURE:
2315 nIdx = 3;
2316 break;
2317 case RES_CHRATR_WEIGHT:
2318 nIdx = 4;
2319 break;
2320 case RES_CHRATR_CJK_FONT:
2321 nIdx = 5;
2322 bFont = true;
2323 break;
2324 case RES_CHRATR_CJK_FONTSIZE:
2325 nIdx = 6;
2326 break;
2327 case RES_CHRATR_CJK_LANGUAGE:
2328 nIdx = 7;
2329 break;
2330 case RES_CHRATR_CJK_POSTURE:
2331 nIdx = 8;
2332 break;
2333 case RES_CHRATR_CJK_WEIGHT:
2334 nIdx = 9;
2335 break;
2336 case RES_CHRATR_CTL_FONT:
2337 nIdx = 10;
2338 bFont = true;
2339 break;
2340 case RES_CHRATR_CTL_FONTSIZE:
2341 nIdx = 11;
2342 break;
2343 case RES_CHRATR_CTL_LANGUAGE:
2344 nIdx = 12;
2345 break;
2346 case RES_CHRATR_CTL_POSTURE:
2347 nIdx = 13;
2348 break;
2349 case RES_CHRATR_CTL_WEIGHT:
2350 nIdx = 14;
2351 break;
2352 default:
2353 // Skip to next attribute
2354 continue;
2356 const sal_Int32 nStt = pHt->GetStart();
2357 if( nStt >= aEndPos[nIdx] )
2359 const SfxPoolItem& rItem =
2360 static_cast<const SwContentNode *>(pTextNd)->GetAttr( nWhich );
2361 if( bFont ? swhtml_css1atr_equalFontItems(rItem,pHt->GetAttr())
2362 : rItem == pHt->GetAttr() )
2364 // The hint is the same as set in the paragraph and
2365 // therefore, it can be deleted
2366 // CAUTION!!! This WILL delete the hint and it MAY
2367 // also delete the SwpHints!!! To avoid any trouble
2368 // we leave the loop immediately if this is the last
2369 // hint.
2370 pTextNd->DeleteAttribute( pHt );
2371 if( 1 == nCntAttr )
2372 break;
2373 i--;
2374 nCntAttr--;
2376 else
2378 // The hint is different. Therefore all hints within that
2379 // hint have to be ignored.
2380 aEndPos[nIdx] = pHt->GetEnd() ? *pHt->GetEnd() : nStt;
2383 else
2385 // The hint starts before another one ends.
2386 // The hint in this case is not deleted
2387 OSL_ENSURE( pHt->GetEnd() && *pHt->GetEnd() <= aEndPos[nIdx],
2388 "hints aren't nested properly!" );
2393 if( !m_pTable && !--m_nParaCnt )
2394 Show();
2396 return bRet;
2399 void SwHTMLParser::AddParSpace()
2401 //If it already has ParSpace, return
2402 if( !m_bNoParSpace )
2403 return;
2405 m_bNoParSpace = false;
2407 sal_uLong nNdIdx = m_pPam->GetPoint()->nNode.GetIndex() - 1;
2409 SwTextNode *pTextNode = m_pDoc->GetNodes()[nNdIdx]->GetTextNode();
2410 if( !pTextNode )
2411 return;
2413 SvxULSpaceItem rULSpace =
2414 static_cast<const SvxULSpaceItem&>(pTextNode->SwContentNode::GetAttr( RES_UL_SPACE ));
2415 if( !rULSpace.GetLower() )
2417 const SvxULSpaceItem& rCollULSpace =
2418 pTextNode->GetAnyFormatColl().GetULSpace();
2419 if( rCollULSpace.GetLower() &&
2420 rCollULSpace.GetUpper() == rULSpace.GetUpper() )
2422 pTextNode->ResetAttr( RES_UL_SPACE );
2424 else
2426 //What I do here, is that I examine the attributes, and if
2427 //I find out, that it's CJK/CTL, then I set the paragraph space
2428 //to the value set in HTML_CJK_PARSPACE/HTML_CTL_PARSPACE.
2430 bool bIsCJK = false;
2431 bool bIsCTL = false;
2433 const size_t nCntAttr = (pTextNode && pTextNode->GetpSwpHints())
2434 ? pTextNode->GetSwpHints().Count() : 0;
2436 for(size_t i = 0; i < nCntAttr; ++i)
2438 SwTextAttr *const pHt = pTextNode->GetSwpHints().Get(i);
2439 sal_uInt16 const nWhich = pHt->Which();
2440 if (RES_CHRATR_CJK_FONT == nWhich ||
2441 RES_CHRATR_CJK_FONTSIZE == nWhich ||
2442 RES_CHRATR_CJK_LANGUAGE == nWhich ||
2443 RES_CHRATR_CJK_POSTURE == nWhich ||
2444 RES_CHRATR_CJK_WEIGHT == nWhich)
2446 bIsCJK = true;
2447 break;
2449 if (RES_CHRATR_CTL_FONT == nWhich ||
2450 RES_CHRATR_CTL_FONTSIZE == nWhich ||
2451 RES_CHRATR_CTL_LANGUAGE == nWhich ||
2452 RES_CHRATR_CTL_POSTURE == nWhich ||
2453 RES_CHRATR_CTL_WEIGHT == nWhich)
2455 bIsCTL = true;
2456 break;
2460 if( bIsCTL )
2462 pTextNode->SetAttr(
2463 SvxULSpaceItem( rULSpace.GetUpper(), HTML_CTL_PARSPACE, RES_UL_SPACE ) );
2465 else if( bIsCJK )
2467 pTextNode->SetAttr(
2468 SvxULSpaceItem( rULSpace.GetUpper(), HTML_CJK_PARSPACE, RES_UL_SPACE ) );
2469 } else {
2470 pTextNode->SetAttr(
2471 SvxULSpaceItem( rULSpace.GetUpper(), HTML_PARSPACE, RES_UL_SPACE ) );
2477 void SwHTMLParser::Show()
2479 // Hier wird
2480 // - ein EndAction gerufen, damit formatiert wird
2481 // - ein Reschedule gerufen,
2482 // - die eiegen View-Shell wieder gesetzt
2483 // - und Start-Action gerufen
2485 OSL_ENSURE( SVPAR_WORKING==eState, "Show nicht im Working-State - Das kann ins Auge gehen" );
2486 SwViewShell *pOldVSh = CallEndAction();
2488 Application::Reschedule();
2490 if( ( m_pDoc->GetDocShell() && m_pDoc->GetDocShell()->IsAbortingImport() )
2491 || 1 == m_pDoc->getReferenceCount() )
2493 // wurde der Import vom SFX abgebrochen?
2494 eState = SVPAR_ERROR;
2497 // Die SwViewShell nochmal holen, denn sie koennte im Reschedule
2498 // zerstoert wirden sein.
2499 SwViewShell *pVSh = CallStartAction( pOldVSh );
2501 // ist der aktuelle Node nicht mehr sichtbar, dann benutzen wir
2502 // eine groessere Schrittweite
2503 if( pVSh )
2505 m_nParaCnt = (m_pPam->GetPoint()->nNode.GetNode().IsInVisibleArea(pVSh))
2506 ? 5 : 50;
2510 void SwHTMLParser::ShowStatline()
2512 // Hier wird
2513 // - ein Reschedule gerufen, damit gescrollt werden kann
2514 // - die eiegen View-Shell wieder gesetzt
2515 // - ein Start/End-Action gerufen, wenn gescrollt wurde.
2517 OSL_ENSURE( SVPAR_WORKING==eState, "ShowStatLine nicht im Working-State - Das kann ins Auge gehen" );
2519 // Laufbalkenanzeige
2520 if( !GetMedium() || !GetMedium()->IsRemote() )
2522 ::SetProgressState( rInput.Tell(), m_pDoc->GetDocShell() );
2523 CheckActionViewShell();
2525 else
2527 Application::Reschedule();
2529 if( ( m_pDoc->GetDocShell() && m_pDoc->GetDocShell()->IsAbortingImport() )
2530 || 1 == m_pDoc->getReferenceCount() )
2531 // wurde der Import vom SFX abgebrochen?
2532 eState = SVPAR_ERROR;
2534 SwViewShell *pVSh = CheckActionViewShell();
2535 if( pVSh && pVSh->HasInvalidRect() )
2537 CallEndAction( false, false );
2538 CallStartAction( pVSh, false );
2543 SwViewShell *SwHTMLParser::CallStartAction( SwViewShell *pVSh, bool bChkPtr )
2545 OSL_ENSURE( !m_pActionViewShell, "CallStartAction: SwViewShell schon gesetzt" );
2547 if( !pVSh || bChkPtr )
2549 #if OSL_DEBUG_LEVEL > 0
2550 SwViewShell *pOldVSh = pVSh;
2551 #endif
2552 pVSh = m_pDoc->getIDocumentLayoutAccess().GetCurrentViewShell();
2553 #if OSL_DEBUG_LEVEL > 0
2554 OSL_ENSURE( !pVSh || !pOldVSh || pOldVSh == pVSh, "CallStartAction: Wer hat die SwViewShell ausgetauscht?" );
2555 if( pOldVSh && !pVSh )
2556 pVSh = nullptr;
2557 #endif
2559 m_pActionViewShell = pVSh;
2561 if( m_pActionViewShell )
2563 if( dynamic_cast< const SwEditShell *>( m_pActionViewShell ) != nullptr )
2564 static_cast<SwEditShell*>(m_pActionViewShell)->StartAction();
2565 else
2566 m_pActionViewShell->StartAction();
2569 return m_pActionViewShell;
2572 SwViewShell *SwHTMLParser::CallEndAction( bool bChkAction, bool bChkPtr )
2574 if( bChkPtr )
2576 SwViewShell *pVSh = m_pDoc->getIDocumentLayoutAccess().GetCurrentViewShell();
2577 OSL_ENSURE( !pVSh || m_pActionViewShell == pVSh,
2578 "CallEndAction: Wer hat die SwViewShell ausgetauscht?" );
2579 #if OSL_DEBUG_LEVEL > 0
2580 if( m_pActionViewShell && !pVSh )
2581 pVSh = nullptr;
2582 #endif
2583 if( pVSh != m_pActionViewShell )
2584 m_pActionViewShell = nullptr;
2587 if( !m_pActionViewShell || (bChkAction && !m_pActionViewShell->ActionPend()) )
2588 return m_pActionViewShell;
2590 if( dynamic_cast< const SwEditShell *>( m_pActionViewShell ) != nullptr )
2592 //Schon gescrollt?, dann dafuer sorgen, dass die View sich nicht bewegt!
2593 const bool bOldLock = m_pActionViewShell->IsViewLocked();
2594 m_pActionViewShell->LockView( true );
2595 const bool bOldEndActionByVirDev = m_pActionViewShell->IsEndActionByVirDev();
2596 m_pActionViewShell->SetEndActionByVirDev( true );
2597 static_cast<SwEditShell*>(m_pActionViewShell)->EndAction();
2598 m_pActionViewShell->SetEndActionByVirDev( bOldEndActionByVirDev );
2599 m_pActionViewShell->LockView( bOldLock );
2601 // bChkJumpMark ist nur gesetzt, wenn das Object auch gefunden wurde
2602 if( m_bChkJumpMark )
2604 const Point aVisSttPos( DOCUMENTBORDER, DOCUMENTBORDER );
2605 if( GetMedium() && aVisSttPos == m_pActionViewShell->VisArea().Pos() )
2606 ::JumpToSwMark( m_pActionViewShell,
2607 GetMedium()->GetURLObject().GetMark() );
2608 m_bChkJumpMark = false;
2611 else
2612 m_pActionViewShell->EndAction();
2614 // sollte der Parser der Letzte sein, der das Doc haelt, dann kann
2615 // man hier abbrechen und einen Fehler setzen.
2616 if( 1 == m_pDoc->getReferenceCount() )
2618 eState = SVPAR_ERROR;
2621 SwViewShell *pVSh = m_pActionViewShell;
2622 m_pActionViewShell = nullptr;
2624 return pVSh;
2627 SwViewShell *SwHTMLParser::CheckActionViewShell()
2629 SwViewShell *pVSh = m_pDoc->getIDocumentLayoutAccess().GetCurrentViewShell();
2630 OSL_ENSURE( !pVSh || m_pActionViewShell == pVSh,
2631 "CheckActionViewShell: Wer hat die SwViewShell ausgetauscht?" );
2632 #if OSL_DEBUG_LEVEL > 0
2633 if( m_pActionViewShell && !pVSh )
2634 pVSh = nullptr;
2635 #endif
2636 if( pVSh != m_pActionViewShell )
2637 m_pActionViewShell = nullptr;
2639 return m_pActionViewShell;
2642 void SwHTMLParser::SetAttr_( bool bChkEnd, bool bBeforeTable,
2643 HTMLAttrs *pPostIts )
2645 std::unique_ptr<SwPaM> pAttrPam( new SwPaM( *m_pPam->GetPoint() ) );
2646 const SwNodeIndex& rEndIdx = m_pPam->GetPoint()->nNode;
2647 const sal_Int32 nEndCnt = m_pPam->GetPoint()->nContent.GetIndex();
2648 HTMLAttr* pAttr;
2649 SwContentNode* pCNd;
2651 HTMLAttrs aFields;
2653 for( auto n = m_aSetAttrTab.size(); n; )
2655 pAttr = m_aSetAttrTab[ --n ];
2656 sal_uInt16 nWhich = pAttr->pItem->Which();
2658 sal_uLong nEndParaIdx = pAttr->GetEndParaIdx();
2659 bool bSetAttr;
2660 if( bChkEnd )
2662 // Zechen-Attribute mit Ende moeglich frueh,
2663 // also noch im aktuellen Absatz setzen (wegen JavaScript
2664 // und diversen Chats). das darf man aber nicht fuer Attribute,
2665 // die ueber den ganzen Absatz aufgspannt werden sollen, weil
2666 // sie aus Absatzvorlgen stammen, die nicht gesetzt werden
2667 // koennen. Weil die Attribute mit SETATTR_DONTREPLACE
2668 // eingefuegt werden, sollte man sie auch anchtraeglich
2669 // noch setzen koennen.
2670 bSetAttr = ( nEndParaIdx < rEndIdx.GetIndex() &&
2671 (RES_LR_SPACE != nWhich || !GetNumInfo().GetNumRule()) ) ||
2672 ( !pAttr->IsLikePara() &&
2673 nEndParaIdx == rEndIdx.GetIndex() &&
2674 pAttr->GetEndCnt() < nEndCnt &&
2675 (isCHRATR(nWhich) || isTXTATR_WITHEND(nWhich)) ) ||
2676 ( bBeforeTable &&
2677 nEndParaIdx == rEndIdx.GetIndex() &&
2678 !pAttr->GetEndCnt() );
2680 else
2682 // Attribute im Content-Bereich duerfen nicht gesetzt
2683 // werden, wenn wir in einem Sonderbereich stehen, aber
2684 // umgekekehrt schon.
2685 sal_uLong nEndOfIcons = m_pDoc->GetNodes().GetEndOfExtras().GetIndex();
2686 bSetAttr = nEndParaIdx < rEndIdx.GetIndex() ||
2687 rEndIdx.GetIndex() > nEndOfIcons ||
2688 nEndParaIdx <= nEndOfIcons;
2691 if( bSetAttr )
2693 // Das Attribute darf nicht in der liste der vorlaeufigen
2694 // Absatz-Attribute stehen, weil es sonst geloescht wurde.
2695 while( !m_aParaAttrs.empty() )
2697 OSL_ENSURE( pAttr != m_aParaAttrs.back(),
2698 "SetAttr: Attribut duerfte noch nicht gesetzt werden" );
2699 m_aParaAttrs.pop_back();
2702 // dann also setzen
2703 m_aSetAttrTab.erase( m_aSetAttrTab.begin() + n );
2705 while( pAttr )
2707 HTMLAttr *pPrev = pAttr->GetPrev();
2708 if( !pAttr->bValid )
2710 // ungueltige Attribute koennen gloescht werden
2711 delete pAttr;
2712 pAttr = pPrev;
2713 continue;
2716 pCNd = pAttr->nSttPara.GetNode().GetContentNode();
2717 if( !pCNd )
2719 // durch die elende Loescherei von Nodes kann auch mal
2720 // ein Index auf einen End-Node zeigen :-(
2721 if ( (pAttr->GetSttPara() == pAttr->GetEndPara()) &&
2722 !isTXTATR_NOEND(nWhich) )
2724 // wenn der End-Index auch auf den Node zeigt
2725 // brauchen wir auch kein Attribut mehr zu setzen,
2726 // es sei denn, es ist ein Text-Attribut.
2727 delete pAttr;
2728 pAttr = pPrev;
2729 continue;
2731 pCNd = m_pDoc->GetNodes().GoNext( &(pAttr->nSttPara) );
2732 if( pCNd )
2733 pAttr->nSttContent = 0;
2734 else
2736 OSL_ENSURE( false, "SetAttr: GoNext() failed!" );
2737 delete pAttr;
2738 pAttr = pPrev;
2739 continue;
2742 pAttrPam->GetPoint()->nNode = pAttr->nSttPara;
2744 // durch das Loeschen von BRs kann der Start-Index
2745 // auch mal hinter das Ende des Textes zeigen
2746 if( pAttr->nSttContent > pCNd->Len() )
2747 pAttr->nSttContent = pCNd->Len();
2748 pAttrPam->GetPoint()->nContent.Assign( pCNd, pAttr->nSttContent );
2750 pAttrPam->SetMark();
2751 if ( (pAttr->GetSttPara() != pAttr->GetEndPara()) &&
2752 !isTXTATR_NOEND(nWhich) )
2754 pCNd = pAttr->nEndPara.GetNode().GetContentNode();
2755 if( !pCNd )
2757 pCNd = SwNodes::GoPrevious( &(pAttr->nEndPara) );
2758 if( pCNd )
2759 pAttr->nEndContent = pCNd->Len();
2760 else
2762 OSL_ENSURE( false, "SetAttr: GoPrevious() failed!" );
2763 pAttrPam->DeleteMark();
2764 delete pAttr;
2765 pAttr = pPrev;
2766 continue;
2770 pAttrPam->GetPoint()->nNode = pAttr->nEndPara;
2772 else if( pAttr->IsLikePara() )
2774 pAttr->nEndContent = pCNd->Len();
2777 // durch das Loeschen von BRs kann der End-Index
2778 // auch mal hinter das Ende des Textes zeigen
2779 if( pAttr->nEndContent > pCNd->Len() )
2780 pAttr->nEndContent = pCNd->Len();
2782 pAttrPam->GetPoint()->nContent.Assign( pCNd, pAttr->nEndContent );
2783 if( bBeforeTable &&
2784 pAttrPam->GetPoint()->nNode.GetIndex() ==
2785 rEndIdx.GetIndex() )
2787 // wenn wir vor dem Einfuegen einer Tabelle stehen
2788 // und das Attribut im aktuellen Node beendet wird,
2789 // muessen wir es im Node davor beenden oder wegschmeissen,
2790 // wenn es erst in dem Node beginnt
2791 if( nWhich != RES_BREAK && nWhich != RES_PAGEDESC &&
2792 !isTXTATR_NOEND(nWhich) )
2794 if( pAttrPam->GetMark()->nNode.GetIndex() !=
2795 rEndIdx.GetIndex() )
2797 OSL_ENSURE( !pAttrPam->GetPoint()->nContent.GetIndex(),
2798 "Content-Position vor Tabelle nicht 0???" );
2799 pAttrPam->Move( fnMoveBackward );
2801 else
2803 pAttrPam->DeleteMark();
2804 delete pAttr;
2805 pAttr = pPrev;
2806 continue;
2811 switch( nWhich )
2813 case RES_FLTR_BOOKMARK: // insert bookmark
2815 const OUString sName( static_cast<SfxStringItem*>(pAttr->pItem)->GetValue() );
2816 IDocumentMarkAccess* const pMarkAccess = m_pDoc->getIDocumentMarkAccess();
2817 IDocumentMarkAccess::const_iterator_t ppBkmk = pMarkAccess->findMark( sName );
2818 if( ppBkmk != pMarkAccess->getAllMarksEnd() &&
2819 ppBkmk->get()->GetMarkStart() == *pAttrPam->GetPoint() )
2820 break; // do not generate duplicates on this position
2821 pAttrPam->DeleteMark();
2822 const ::sw::mark::IMark* const pNewMark = pMarkAccess->makeMark(
2823 *pAttrPam,
2824 sName,
2825 IDocumentMarkAccess::MarkType::BOOKMARK,
2826 ::sw::mark::InsertMode::New);
2828 // jump to bookmark
2829 if( JUMPTO_MARK == m_eJumpTo && pNewMark->GetName() == m_sJmpMark )
2831 m_bChkJumpMark = true;
2832 m_eJumpTo = JUMPTO_NONE;
2835 break;
2836 case RES_TXTATR_FIELD:
2837 case RES_TXTATR_ANNOTATION:
2838 case RES_TXTATR_INPUTFIELD:
2840 sal_uInt16 nFieldWhich =
2841 pPostIts
2842 ? static_cast<const SwFormatField *>(pAttr->pItem)->GetField()->GetTyp()->Which()
2843 : 0;
2844 if( pPostIts && (RES_POSTITFLD == nFieldWhich ||
2845 RES_SCRIPTFLD == nFieldWhich) )
2847 pPostIts->push_front( pAttr );
2849 else
2851 aFields.push_back( pAttr);
2854 pAttrPam->DeleteMark();
2855 pAttr = pPrev;
2856 continue;
2858 case RES_LR_SPACE:
2859 if( pAttrPam->GetPoint()->nNode.GetIndex() ==
2860 pAttrPam->GetMark()->nNode.GetIndex() &&
2861 pCNd )
2863 // wegen Numerierungen dieses Attribut direkt
2864 // am Node setzen
2865 pCNd->SetAttr( *pAttr->pItem );
2866 break;
2868 OSL_ENSURE( false,
2869 "LRSpace ueber mehrere Absaetze gesetzt!" );
2870 SAL_FALLTHROUGH; // (shouldn't reach this point anyway)
2872 // tdf#94088 expand RES_BACKGROUND to the new fill attribute
2873 // definitions in the range [XATTR_FILL_FIRST .. XATTR_FILL_LAST].
2874 // This is the right place in the future if the adapted fill attributes
2875 // may be handled more directly in HTML import to handle them.
2876 case RES_BACKGROUND:
2878 const SvxBrushItem& rBrush = static_cast< SvxBrushItem& >(*pAttr->pItem);
2879 SfxItemSet aNewSet(m_pDoc->GetAttrPool(), XATTR_FILL_FIRST, XATTR_FILL_LAST);
2881 setSvxBrushItemAsFillAttributesToTargetSet(rBrush, aNewSet);
2882 m_pDoc->getIDocumentContentOperations().InsertItemSet(*pAttrPam, aNewSet, SetAttrMode::DONTREPLACE);
2883 break;
2885 default:
2887 // ggfs. ein Bookmark anspringen
2888 if( RES_TXTATR_INETFMT == nWhich &&
2889 JUMPTO_MARK == m_eJumpTo &&
2890 m_sJmpMark == static_cast<SwFormatINetFormat*>(pAttr->pItem)->GetName() )
2892 m_bChkJumpMark = true;
2893 m_eJumpTo = JUMPTO_NONE;
2896 m_pDoc->getIDocumentContentOperations().InsertPoolItem( *pAttrPam, *pAttr->pItem, SetAttrMode::DONTREPLACE );
2898 pAttrPam->DeleteMark();
2900 delete pAttr;
2901 pAttr = pPrev;
2906 for( auto n = m_aMoveFlyFrames.size(); n; )
2908 SwFrameFormat *pFrameFormat = m_aMoveFlyFrames[ --n ];
2910 const SwFormatAnchor& rAnchor = pFrameFormat->GetAnchor();
2911 OSL_ENSURE( FLY_AT_PARA == rAnchor.GetAnchorId(),
2912 "Nur Auto-Rahmen brauchen eine Spezialbehandlung" );
2913 const SwPosition *pFlyPos = rAnchor.GetContentAnchor();
2914 sal_uLong nFlyParaIdx = pFlyPos->nNode.GetIndex();
2915 bool bMoveFly;
2916 if( bChkEnd )
2918 bMoveFly = nFlyParaIdx < rEndIdx.GetIndex() ||
2919 ( nFlyParaIdx == rEndIdx.GetIndex() &&
2920 m_aMoveFlyCnts[n] < nEndCnt );
2922 else
2924 sal_uLong nEndOfIcons = m_pDoc->GetNodes().GetEndOfExtras().GetIndex();
2925 bMoveFly = nFlyParaIdx < rEndIdx.GetIndex() ||
2926 rEndIdx.GetIndex() > nEndOfIcons ||
2927 nFlyParaIdx <= nEndOfIcons;
2929 if( bMoveFly )
2931 pFrameFormat->DelFrames();
2932 *pAttrPam->GetPoint() = *pFlyPos;
2933 pAttrPam->GetPoint()->nContent.Assign( pAttrPam->GetContentNode(),
2934 m_aMoveFlyCnts[n] );
2935 SwFormatAnchor aAnchor( rAnchor );
2936 aAnchor.SetType( FLY_AT_CHAR );
2937 aAnchor.SetAnchor( pAttrPam->GetPoint() );
2938 pFrameFormat->SetFormatAttr( aAnchor );
2940 const SwFormatHoriOrient& rHoriOri = pFrameFormat->GetHoriOrient();
2941 if( text::HoriOrientation::LEFT == rHoriOri.GetHoriOrient() )
2943 SwFormatHoriOrient aHoriOri( rHoriOri );
2944 aHoriOri.SetRelationOrient( text::RelOrientation::CHAR );
2945 pFrameFormat->SetFormatAttr( aHoriOri );
2947 const SwFormatVertOrient& rVertOri = pFrameFormat->GetVertOrient();
2948 if( text::VertOrientation::TOP == rVertOri.GetVertOrient() )
2950 SwFormatVertOrient aVertOri( rVertOri );
2951 aVertOri.SetRelationOrient( text::RelOrientation::CHAR );
2952 pFrameFormat->SetFormatAttr( aVertOri );
2955 pFrameFormat->MakeFrames();
2956 m_aMoveFlyFrames.erase( m_aMoveFlyFrames.begin() + n );
2957 m_aMoveFlyCnts.erase( m_aMoveFlyCnts.begin() + n );
2960 while( !aFields.empty() )
2962 pAttr = aFields[0];
2964 pCNd = pAttr->nSttPara.GetNode().GetContentNode();
2965 pAttrPam->GetPoint()->nNode = pAttr->nSttPara;
2966 pAttrPam->GetPoint()->nContent.Assign( pCNd, pAttr->nSttContent );
2968 if( bBeforeTable &&
2969 pAttrPam->GetPoint()->nNode.GetIndex() == rEndIdx.GetIndex() )
2971 OSL_ENSURE( !bBeforeTable, "Aha, der Fall tritt also doch ein" );
2972 OSL_ENSURE( !pAttrPam->GetPoint()->nContent.GetIndex(),
2973 "Content-Position vor Tabelle nicht 0???" );
2974 // !!!
2975 pAttrPam->Move( fnMoveBackward );
2978 m_pDoc->getIDocumentContentOperations().InsertPoolItem( *pAttrPam, *pAttr->pItem );
2980 aFields.pop_front();
2981 delete pAttr;
2985 void SwHTMLParser::NewAttr( HTMLAttr **ppAttr, const SfxPoolItem& rItem )
2987 // Font-Hoehen und -Farben- sowie Escapement-Attribute duerfen nicht
2988 // zusammengefasst werden. Sie werden deshalb in einer Liste gespeichert,
2989 // in der das zuletzt aufgespannte Attribut vorne steht und der Count
2990 // immer 1 ist. Fuer alle anderen Attribute wird der Count einfach
2991 // hochgezaehlt.
2992 if( *ppAttr )
2994 HTMLAttr *pAttr = new HTMLAttr( *m_pPam->GetPoint(), rItem,
2995 ppAttr );
2996 pAttr->InsertNext( *ppAttr );
2997 (*ppAttr) = pAttr;
2999 else
3000 (*ppAttr) = new HTMLAttr( *m_pPam->GetPoint(), rItem, ppAttr );
3003 bool SwHTMLParser::EndAttr( HTMLAttr* pAttr, bool bChkEmpty )
3005 bool bRet = true;
3007 // Der Listenkopf ist im Attribut gespeichert
3008 HTMLAttr **ppHead = pAttr->ppHead;
3010 OSL_ENSURE( ppHead, "keinen Attributs-Listenkopf gefunden!" );
3012 // die aktuelle Position als Ende-Position merken
3013 const SwNodeIndex* pEndIdx = &m_pPam->GetPoint()->nNode;
3014 sal_Int32 nEndCnt = m_pPam->GetPoint()->nContent.GetIndex();
3016 // WIrd das zueltzt gestartete oder ein frueher gestartetes Attribut
3017 // beendet?
3018 HTMLAttr *pLast = nullptr;
3019 if( ppHead && pAttr != *ppHead )
3021 // Es wird nicht das zuletzt gestartete Attribut beendet
3023 // Dann suche wir das unmittelbar danach gestartete Attribut, das
3024 // ja ebenfalls noch nicht beendet wurde (sonst stuende es nicht
3025 // mehr in der Liste
3026 pLast = *ppHead;
3027 while( pLast && pLast->GetNext() != pAttr )
3028 pLast = pLast->GetNext();
3030 OSL_ENSURE( pLast, "Attribut nicht in eigener Liste gefunden!" );
3033 bool bMoveBack = false;
3034 sal_uInt16 nWhich = pAttr->pItem->Which();
3035 if( !nEndCnt && RES_PARATR_BEGIN <= nWhich &&
3036 *pEndIdx != pAttr->GetSttPara() )
3038 // dann eine Contentnt Position zurueck!
3039 bMoveBack = m_pPam->Move( fnMoveBackward );
3040 nEndCnt = m_pPam->GetPoint()->nContent.GetIndex();
3043 // nun das Attrubut beenden
3044 HTMLAttr *pNext = pAttr->GetNext();
3046 bool bInsert;
3047 sal_uInt16 nScriptItem = 0;
3048 bool bScript = false;
3049 // ein Bereich ??
3050 if( !bChkEmpty || (RES_PARATR_BEGIN <= nWhich && bMoveBack) ||
3051 RES_PAGEDESC == nWhich || RES_BREAK == nWhich ||
3052 *pEndIdx != pAttr->GetSttPara() ||
3053 nEndCnt != pAttr->GetSttCnt() )
3055 bInsert = true;
3056 // We do some optimization for script dependent attributes here.
3057 if( *pEndIdx == pAttr->GetSttPara() )
3059 bool bFont = false;
3060 lcl_swhtml_getItemInfo( *pAttr, bScript, bFont, nScriptItem );
3063 else
3065 bInsert = false;
3068 if( bInsert && bScript )
3070 const SwTextNode *pTextNd = pAttr->GetSttPara().GetNode()
3071 .GetTextNode();
3072 OSL_ENSURE( pTextNd, "No text node" );
3073 const OUString& rText = pTextNd->GetText();
3074 sal_uInt16 nScriptText = g_pBreakIt->GetBreakIter()->getScriptType(
3075 rText, pAttr->GetSttCnt() );
3076 sal_Int32 nScriptEnd = g_pBreakIt->GetBreakIter()
3077 ->endOfScript( rText, pAttr->GetSttCnt(), nScriptText );
3078 while (nScriptEnd < nEndCnt && nScriptEnd != -1)
3080 if( nScriptItem == nScriptText )
3082 HTMLAttr *pSetAttr = pAttr->Clone( *pEndIdx, nScriptEnd );
3083 pSetAttr->ClearPrev();
3084 if( pNext )
3085 pNext->InsertPrev( pSetAttr );
3086 else
3088 if (pSetAttr->bInsAtStart)
3089 m_aSetAttrTab.push_front( pSetAttr );
3090 else
3091 m_aSetAttrTab.push_back( pSetAttr );
3094 pAttr->nSttContent = nScriptEnd;
3095 nScriptText = g_pBreakIt->GetBreakIter()->getScriptType(
3096 rText, nScriptEnd );
3097 nScriptEnd = g_pBreakIt->GetBreakIter()
3098 ->endOfScript( rText, nScriptEnd, nScriptText );
3100 bInsert = nScriptItem == nScriptText;
3102 if( bInsert )
3104 pAttr->nEndPara = *pEndIdx;
3105 pAttr->nEndContent = nEndCnt;
3106 pAttr->bInsAtStart = RES_TXTATR_INETFMT != nWhich &&
3107 RES_TXTATR_CHARFMT != nWhich;
3109 if( !pNext )
3111 // keine offenen Attribute dieses Typs mehr da,
3112 // dann koennen alle gesetzt werden, es sei denn
3113 // sie haengen noch von einem anderen Attribut ab,
3114 // dann werden sie dort angehaengt
3115 if (pAttr->bInsAtStart)
3116 m_aSetAttrTab.push_front( pAttr );
3117 else
3118 m_aSetAttrTab.push_back( pAttr );
3120 else
3122 // es gibt noch andere offene Attribute des Typs,
3123 // daher muss das Setzen zurueckgestellt werden.
3124 // das aktuelle Attribut wird deshalb hinten an die
3125 // Previous-Liste des Nachfolgers angehaengt
3126 pNext->InsertPrev( pAttr );
3129 else
3131 // dann nicht einfuegen, sondern Loeschen. Durch das "tuerken" von
3132 // Vorlagen durch harte Attributierung koennen sich auch mal andere
3133 // leere Attribute in der Prev-Liste befinden, die dann trotzdem
3134 // gesetzt werden muessen
3135 HTMLAttr *pPrev = pAttr->GetPrev();
3136 bRet = false;
3137 delete pAttr;
3139 if( pPrev )
3141 // Die Previous-Attribute muessen trotzdem gesetzt werden.
3142 if( pNext )
3143 pNext->InsertPrev( pPrev );
3144 else
3146 if (pPrev->bInsAtStart)
3147 m_aSetAttrTab.push_front( pPrev );
3148 else
3149 m_aSetAttrTab.push_back( pPrev );
3155 // wenn das erste Attribut der Liste gesetzt wurde muss noch der
3156 // Listenkopf korrigiert werden.
3157 if( pLast )
3158 pLast->pNext = pNext;
3159 else if( ppHead )
3160 *ppHead = pNext;
3162 if( bMoveBack )
3163 m_pPam->Move( fnMoveForward );
3165 return bRet;
3168 void SwHTMLParser::DeleteAttr( HTMLAttr* pAttr )
3170 // preliminary paragraph attributes are not allowed here, they could
3171 // be set here and then the pointers become invalid!
3172 OSL_ENSURE(m_aParaAttrs.empty(),
3173 "Danger: there are non-final paragraph attributes");
3174 if( !m_aParaAttrs.empty() )
3175 m_aParaAttrs.clear();
3177 // Der Listenkopf ist im Attribut gespeichert
3178 HTMLAttr **ppHead = pAttr->ppHead;
3180 OSL_ENSURE( ppHead, "keinen Attributs-Listenkopf gefunden!" );
3182 // Wird das zueltzt gestartete oder ein frueher gestartetes Attribut
3183 // entfernt?
3184 HTMLAttr *pLast = nullptr;
3185 if( ppHead && pAttr != *ppHead )
3187 // Es wird nicht das zuletzt gestartete Attribut beendet
3189 // Dann suche wir das unmittelbar danach gestartete Attribut, das
3190 // ja ebenfalls noch nicht beendet wurde (sonst stuende es nicht
3191 // mehr in der Liste
3192 pLast = *ppHead;
3193 while( pLast && pLast->GetNext() != pAttr )
3194 pLast = pLast->GetNext();
3196 OSL_ENSURE( pLast, "Attribut nicht in eigener Liste gefunden!" );
3199 // nun das Attrubut entfernen
3200 HTMLAttr *pNext = pAttr->GetNext();
3201 HTMLAttr *pPrev = pAttr->GetPrev();
3202 delete pAttr;
3204 if( pPrev )
3206 // Die Previous-Attribute muessen trotzdem gesetzt werden.
3207 if( pNext )
3208 pNext->InsertPrev( pPrev );
3209 else
3211 if (pPrev->bInsAtStart)
3212 m_aSetAttrTab.push_front( pPrev );
3213 else
3214 m_aSetAttrTab.push_back( pPrev );
3218 // wenn das erste Attribut der Liste entfernt wurde muss noch der
3219 // Listenkopf korrigiert werden.
3220 if( pLast )
3221 pLast->pNext = pNext;
3222 else if( ppHead )
3223 *ppHead = pNext;
3226 void SwHTMLParser::SaveAttrTab( HTMLAttrTable& rNewAttrTab )
3228 // preliminary paragraph attributes are not allowed here, they could
3229 // be set here and then the pointers become invalid!
3230 OSL_ENSURE(m_aParaAttrs.empty(),
3231 "Danger: there are non-final paragraph attributes");
3232 if( !m_aParaAttrs.empty() )
3233 m_aParaAttrs.clear();
3235 HTMLAttr** pHTMLAttributes = reinterpret_cast<HTMLAttr**>(&m_aAttrTab);
3236 HTMLAttr** pSaveAttributes = reinterpret_cast<HTMLAttr**>(&rNewAttrTab);
3238 for (auto nCnt = sizeof(HTMLAttrTable) / sizeof(HTMLAttr*); nCnt--; ++pHTMLAttributes, ++pSaveAttributes)
3240 *pSaveAttributes = *pHTMLAttributes;
3242 HTMLAttr *pAttr = *pSaveAttributes;
3243 while (pAttr)
3245 pAttr->SetHead(pSaveAttributes);
3246 pAttr = pAttr->GetNext();
3249 *pHTMLAttributes = nullptr;
3253 void SwHTMLParser::SplitAttrTab( HTMLAttrTable& rNewAttrTab,
3254 bool bMoveEndBack )
3256 // preliminary paragraph attributes are not allowed here, they could
3257 // be set here and then the pointers become invalid!
3258 OSL_ENSURE(m_aParaAttrs.empty(),
3259 "Danger: there are non-final paragraph attributes");
3260 if( !m_aParaAttrs.empty() )
3261 m_aParaAttrs.clear();
3263 const SwNodeIndex& nSttIdx = m_pPam->GetPoint()->nNode;
3264 SwNodeIndex nEndIdx( nSttIdx );
3266 // alle noch offenen Attribute beenden und hinter der Tabelle
3267 // neu aufspannen
3268 HTMLAttr** pHTMLAttributes = reinterpret_cast<HTMLAttr**>(&m_aAttrTab);
3269 HTMLAttr** pSaveAttributes = reinterpret_cast<HTMLAttr**>(&rNewAttrTab);
3270 bool bSetAttr = true;
3271 const sal_Int32 nSttCnt = m_pPam->GetPoint()->nContent.GetIndex();
3272 sal_Int32 nEndCnt = nSttCnt;
3274 if( bMoveEndBack )
3276 sal_uLong nOldEnd = nEndIdx.GetIndex();
3277 sal_uLong nTmpIdx;
3278 if( ( nTmpIdx = m_pDoc->GetNodes().GetEndOfExtras().GetIndex()) >= nOldEnd ||
3279 ( nTmpIdx = m_pDoc->GetNodes().GetEndOfAutotext().GetIndex()) >= nOldEnd )
3281 nTmpIdx = m_pDoc->GetNodes().GetEndOfInserts().GetIndex();
3283 SwContentNode* pCNd = SwNodes::GoPrevious(&nEndIdx);
3285 // keine Attribute setzen, wenn der PaM aus dem Content-Bereich
3286 // herausgeschoben wurde.
3287 bSetAttr = pCNd && nTmpIdx < nEndIdx.GetIndex();
3289 nEndCnt = (bSetAttr ? pCNd->Len() : 0);
3291 for (auto nCnt = sizeof(HTMLAttrTable) / sizeof(HTMLAttr*); nCnt--; (++pHTMLAttributes, ++pSaveAttributes))
3293 HTMLAttr *pAttr = *pHTMLAttributes;
3294 *pSaveAttributes = nullptr;
3295 while( pAttr )
3297 HTMLAttr *pNext = pAttr->GetNext();
3298 HTMLAttr *pPrev = pAttr->GetPrev();
3300 if( bSetAttr &&
3301 ( pAttr->GetSttParaIdx() < nEndIdx.GetIndex() ||
3302 (pAttr->GetSttPara() == nEndIdx &&
3303 pAttr->GetSttCnt() != nEndCnt) ) )
3305 // das Attribut muss vor der Liste gesetzt werden. Da wir
3306 // das Original noch brauchen, weil Zeiger auf das Attribut
3307 // noch in den Kontexten existieren, muessen wir es clonen.
3308 // Die Next-Liste geht dabei verloren, aber die
3309 // Previous-Liste bleibt erhalten
3310 HTMLAttr *pSetAttr = pAttr->Clone( nEndIdx, nEndCnt );
3312 if( pNext )
3313 pNext->InsertPrev( pSetAttr );
3314 else
3316 if (pSetAttr->bInsAtStart)
3317 m_aSetAttrTab.push_front( pSetAttr );
3318 else
3319 m_aSetAttrTab.push_back( pSetAttr );
3322 else if( pPrev )
3324 // Wenn das Attribut nicht gesetzt vor der Tabelle
3325 // gesetzt werden muss, muessen der Previous-Attribute
3326 // trotzdem gesetzt werden.
3327 if( pNext )
3328 pNext->InsertPrev( pPrev );
3329 else
3331 if (pPrev->bInsAtStart)
3332 m_aSetAttrTab.push_front( pPrev );
3333 else
3334 m_aSetAttrTab.push_back( pPrev );
3338 // den Start des Attributs neu setzen und die Verkettungen
3339 // aufbrechen
3340 pAttr->Reset(nSttIdx, nSttCnt, pSaveAttributes);
3342 if (*pSaveAttributes)
3344 HTMLAttr *pSAttr = *pSaveAttributes;
3345 while( pSAttr->GetNext() )
3346 pSAttr = pSAttr->GetNext();
3347 pSAttr->InsertNext( pAttr );
3349 else
3350 *pSaveAttributes = pAttr;
3352 pAttr = pNext;
3355 *pHTMLAttributes = nullptr;
3359 void SwHTMLParser::RestoreAttrTab( HTMLAttrTable& rNewAttrTab )
3361 // preliminary paragraph attributes are not allowed here, they could
3362 // be set here and then the pointers become invalid!
3363 OSL_ENSURE(m_aParaAttrs.empty(),
3364 "Danger: there are non-final paragraph attributes");
3365 if( !m_aParaAttrs.empty() )
3366 m_aParaAttrs.clear();
3368 HTMLAttr** pHTMLAttributes = reinterpret_cast<HTMLAttr**>(&m_aAttrTab);
3369 HTMLAttr** pSaveAttributes = reinterpret_cast<HTMLAttr**>(&rNewAttrTab);
3371 for (auto nCnt = sizeof(HTMLAttrTable) / sizeof(HTMLAttr*); nCnt--; ++pHTMLAttributes, ++pSaveAttributes)
3373 OSL_ENSURE(!*pHTMLAttributes, "Die Attribut-Tabelle ist nicht leer!");
3375 *pHTMLAttributes = *pSaveAttributes;
3377 HTMLAttr *pAttr = *pHTMLAttributes;
3378 while (pAttr)
3380 OSL_ENSURE( !pAttr->GetPrev() || !pAttr->GetPrev()->ppHead,
3381 "Previous-Attribut hat noch einen Header" );
3382 pAttr->SetHead(pHTMLAttributes);
3383 pAttr = pAttr->GetNext();
3386 *pSaveAttributes = nullptr;
3390 void SwHTMLParser::InsertAttr( const SfxPoolItem& rItem, bool bInsAtStart )
3392 HTMLAttr* pTmp = new HTMLAttr( *m_pPam->GetPoint(),
3393 rItem );
3394 if (bInsAtStart)
3395 m_aSetAttrTab.push_front( pTmp );
3396 else
3397 m_aSetAttrTab.push_back( pTmp );
3400 void SwHTMLParser::InsertAttrs( HTMLAttrs& rAttrs )
3402 while( !rAttrs.empty() )
3404 HTMLAttr *pAttr = rAttrs.front();
3405 InsertAttr( pAttr->GetItem(), false );
3406 rAttrs.pop_front();
3407 delete pAttr;
3411 void SwHTMLParser::NewStdAttr( int nToken )
3413 OUString aId, aStyle, aLang, aDir;
3414 OUString aClass;
3416 const HTMLOptions& rHTMLOptions = GetOptions();
3417 for (size_t i = rHTMLOptions.size(); i; )
3419 const HTMLOption& rOption = rHTMLOptions[--i];
3420 switch( rOption.GetToken() )
3422 case HTML_O_ID:
3423 aId = rOption.GetString();
3424 break;
3425 case HTML_O_STYLE:
3426 aStyle = rOption.GetString();
3427 break;
3428 case HTML_O_CLASS:
3429 aClass = rOption.GetString();
3430 break;
3431 case HTML_O_LANG:
3432 aLang = rOption.GetString();
3433 break;
3434 case HTML_O_DIR:
3435 aDir = rOption.GetString();
3436 break;
3440 // einen neuen Kontext anlegen
3441 HTMLAttrContext *pCntxt = new HTMLAttrContext( static_cast< sal_uInt16 >(nToken) );
3443 // Styles parsen
3444 if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) )
3446 SfxItemSet aItemSet( m_pDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
3447 SvxCSS1PropertyInfo aPropInfo;
3449 if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) )
3451 if( HTML_SPAN_ON != nToken || aClass.isEmpty() ||
3452 !CreateContainer( aClass, aItemSet, aPropInfo, pCntxt ) )
3453 DoPositioning( aItemSet, aPropInfo, pCntxt );
3454 InsertAttrs( aItemSet, aPropInfo, pCntxt, true );
3458 // den Kontext merken
3459 PushContext( pCntxt );
3462 void SwHTMLParser::NewStdAttr( int nToken,
3463 HTMLAttr **ppAttr, const SfxPoolItem & rItem,
3464 HTMLAttr **ppAttr2, const SfxPoolItem *pItem2,
3465 HTMLAttr **ppAttr3, const SfxPoolItem *pItem3 )
3467 OUString aId, aStyle, aClass, aLang, aDir;
3469 const HTMLOptions& rHTMLOptions = GetOptions();
3470 for (size_t i = rHTMLOptions.size(); i; )
3472 const HTMLOption& rOption = rHTMLOptions[--i];
3473 switch( rOption.GetToken() )
3475 case HTML_O_ID:
3476 aId = rOption.GetString();
3477 break;
3478 case HTML_O_STYLE:
3479 aStyle = rOption.GetString();
3480 break;
3481 case HTML_O_CLASS:
3482 aClass = rOption.GetString();
3483 break;
3484 case HTML_O_LANG:
3485 aLang = rOption.GetString();
3486 break;
3487 case HTML_O_DIR:
3488 aDir = rOption.GetString();
3489 break;
3493 // einen neuen Kontext anlegen
3494 HTMLAttrContext *pCntxt = new HTMLAttrContext( static_cast< sal_uInt16 >(nToken) );
3496 // Styles parsen
3497 if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) )
3499 SfxItemSet aItemSet( m_pDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
3500 SvxCSS1PropertyInfo aPropInfo;
3502 aItemSet.Put( rItem );
3503 if( pItem2 )
3504 aItemSet.Put( *pItem2 );
3505 if( pItem3 )
3506 aItemSet.Put( *pItem3 );
3508 if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) )
3509 DoPositioning( aItemSet, aPropInfo, pCntxt );
3511 InsertAttrs( aItemSet, aPropInfo, pCntxt, true );
3513 else
3515 InsertAttr( ppAttr ,rItem, pCntxt );
3516 if( pItem2 )
3518 OSL_ENSURE( ppAttr2, "missing table entry for item2" );
3519 InsertAttr( ppAttr2, *pItem2, pCntxt );
3521 if( pItem3 )
3523 OSL_ENSURE( ppAttr3, "missing table entry for item3" );
3524 InsertAttr( ppAttr3, *pItem3, pCntxt );
3528 // den Kontext merken
3529 PushContext( pCntxt );
3532 void SwHTMLParser::EndTag( int nToken )
3534 // den Kontext holen
3535 HTMLAttrContext *pCntxt = PopContext( static_cast< sal_uInt16 >(nToken & ~1) );
3536 if( pCntxt )
3538 // und ggf. die Attribute beenden
3539 EndContext( pCntxt );
3540 delete pCntxt;
3544 void SwHTMLParser::NewBasefontAttr()
3546 OUString aId, aStyle, aClass, aLang, aDir;
3547 sal_uInt16 nSize = 3;
3549 const HTMLOptions& rHTMLOptions = GetOptions();
3550 for (size_t i = rHTMLOptions.size(); i; )
3552 const HTMLOption& rOption = rHTMLOptions[--i];
3553 switch( rOption.GetToken() )
3555 case HTML_O_SIZE:
3556 nSize = (sal_uInt16)rOption.GetNumber();
3557 break;
3558 case HTML_O_ID:
3559 aId = rOption.GetString();
3560 break;
3561 case HTML_O_STYLE:
3562 aStyle = rOption.GetString();
3563 break;
3564 case HTML_O_CLASS:
3565 aClass = rOption.GetString();
3566 break;
3567 case HTML_O_LANG:
3568 aLang = rOption.GetString();
3569 break;
3570 case HTML_O_DIR:
3571 aDir = rOption.GetString();
3572 break;
3576 if( nSize < 1 )
3577 nSize = 1;
3579 if( nSize > 7 )
3580 nSize = 7;
3582 // einen neuen Kontext anlegen
3583 HTMLAttrContext *pCntxt = new HTMLAttrContext( HTML_BASEFONT_ON );
3585 // Styles parsen
3586 if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) )
3588 SfxItemSet aItemSet( m_pDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
3589 SvxCSS1PropertyInfo aPropInfo;
3591 //CJK has different defaults
3592 SvxFontHeightItem aFontHeight( m_aFontHeights[nSize-1], 100, RES_CHRATR_FONTSIZE );
3593 aItemSet.Put( aFontHeight );
3594 SvxFontHeightItem aFontHeightCJK( m_aFontHeights[nSize-1], 100, RES_CHRATR_CJK_FONTSIZE );
3595 aItemSet.Put( aFontHeightCJK );
3596 //Complex type can contain so many types of letters,
3597 //that it's not really worthy to bother, IMO.
3598 //Still, I have set a default.
3599 SvxFontHeightItem aFontHeightCTL( m_aFontHeights[nSize-1], 100, RES_CHRATR_CTL_FONTSIZE );
3600 aItemSet.Put( aFontHeightCTL );
3602 if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) )
3603 DoPositioning( aItemSet, aPropInfo, pCntxt );
3605 InsertAttrs( aItemSet, aPropInfo, pCntxt, true );
3607 else
3609 SvxFontHeightItem aFontHeight( m_aFontHeights[nSize-1], 100, RES_CHRATR_FONTSIZE );
3610 InsertAttr( &m_aAttrTab.pFontHeight, aFontHeight, pCntxt );
3611 SvxFontHeightItem aFontHeightCJK( m_aFontHeights[nSize-1], 100, RES_CHRATR_CJK_FONTSIZE );
3612 InsertAttr( &m_aAttrTab.pFontHeightCJK, aFontHeightCJK, pCntxt );
3613 SvxFontHeightItem aFontHeightCTL( m_aFontHeights[nSize-1], 100, RES_CHRATR_CTL_FONTSIZE );
3614 InsertAttr( &m_aAttrTab.pFontHeightCTL, aFontHeightCTL, pCntxt );
3617 // den Kontext merken
3618 PushContext( pCntxt );
3620 // die Font-Size merken
3621 m_aBaseFontStack.push_back( nSize );
3624 void SwHTMLParser::EndBasefontAttr()
3626 EndTag( HTML_BASEFONT_ON );
3628 // Stack-Unterlauf in Tabellen vermeiden
3629 if( m_aBaseFontStack.size() > m_nBaseFontStMin )
3630 m_aBaseFontStack.erase( m_aBaseFontStack.begin() + m_aBaseFontStack.size() - 1 );
3633 void SwHTMLParser::NewFontAttr( int nToken )
3635 sal_uInt16 nBaseSize =
3636 ( m_aBaseFontStack.size() > m_nBaseFontStMin
3637 ? (m_aBaseFontStack[m_aBaseFontStack.size()-1] & FONTSIZE_MASK)
3638 : 3 );
3639 sal_uInt16 nFontSize =
3640 ( m_aFontStack.size() > m_nFontStMin
3641 ? (m_aFontStack[m_aFontStack.size()-1] & FONTSIZE_MASK)
3642 : nBaseSize );
3644 OUString aFace, aId, aStyle, aClass, aLang, aDir;
3645 Color aColor;
3646 sal_uLong nFontHeight = 0; // tatsaechlich einzustellende Font-Hoehe
3647 sal_uInt16 nSize = 0; // Fontgroesse in Netscape-Notation (1-7)
3648 bool bColor = false;
3650 const HTMLOptions& rHTMLOptions = GetOptions();
3651 for (size_t i = rHTMLOptions.size(); i; )
3653 const HTMLOption& rOption = rHTMLOptions[--i];
3654 switch( rOption.GetToken() )
3656 case HTML_O_SIZE:
3657 if( HTML_FONT_ON==nToken && !rOption.GetString().isEmpty() )
3659 sal_Int32 nSSize;
3660 if( '+' == rOption.GetString()[0] ||
3661 '-' == rOption.GetString()[0] )
3662 nSSize = nBaseSize + rOption.GetSNumber();
3663 else
3664 nSSize = (sal_Int32)rOption.GetNumber();
3666 if( nSSize < 1 )
3667 nSSize = 1;
3668 else if( nSSize > 7 )
3669 nSSize = 7;
3671 nSize = (sal_uInt16)nSSize;
3672 nFontHeight = m_aFontHeights[nSize-1];
3674 break;
3675 case HTML_O_COLOR:
3676 if( HTML_FONT_ON==nToken )
3678 rOption.GetColor( aColor );
3679 bColor = true;
3681 break;
3682 case HTML_O_FACE:
3683 if( HTML_FONT_ON==nToken )
3684 aFace = rOption.GetString();
3685 break;
3686 case HTML_O_ID:
3687 aId = rOption.GetString();
3688 break;
3689 case HTML_O_STYLE:
3690 aStyle = rOption.GetString();
3691 break;
3692 case HTML_O_CLASS:
3693 aClass = rOption.GetString();
3694 break;
3695 case HTML_O_LANG:
3696 aLang = rOption.GetString();
3697 break;
3698 case HTML_O_DIR:
3699 aDir = rOption.GetString();
3700 break;
3704 if( HTML_FONT_ON != nToken )
3706 // HTML_BIGPRINT_ON oder HTML_SMALLPRINT_ON
3708 // in Ueberschriften bestimmt die aktuelle Ueberschrift
3709 // die Font-Hoehe und nicht BASEFONT
3710 sal_uInt16 nPoolId = GetCurrFormatColl()->GetPoolFormatId();
3711 if( (nPoolId>=RES_POOLCOLL_HEADLINE1 &&
3712 nPoolId<=RES_POOLCOLL_HEADLINE6) )
3714 // wenn die Schriftgroesse in der Ueberschrift noch
3715 // nicht veraendert ist, die aus der Vorlage nehmen
3716 if( m_nFontStHeadStart==m_aFontStack.size() )
3717 nFontSize = static_cast< sal_uInt16 >(6 - (nPoolId - RES_POOLCOLL_HEADLINE1));
3719 else
3720 nPoolId = 0;
3722 if( HTML_BIGPRINT_ON == nToken )
3723 nSize = ( nFontSize<7 ? nFontSize+1 : 7 );
3724 else
3725 nSize = ( nFontSize>1 ? nFontSize-1 : 1 );
3727 // in Ueberschriften wird die neue Fonthoehe wenn moeglich aus
3728 // den Vorlagen geholt.
3729 if( nPoolId && nSize>=1 && nSize <=6 )
3730 nFontHeight =
3731 m_pCSS1Parser->GetTextCollFromPool(
3732 RES_POOLCOLL_HEADLINE1+6-nSize )->GetSize().GetHeight();
3733 else
3734 nFontHeight = m_aFontHeights[nSize-1];
3737 OSL_ENSURE( !nSize == !nFontHeight, "HTML-Font-Size != Font-Height" );
3739 OUString aFontName, aStyleName;
3740 FontFamily eFamily = FAMILY_DONTKNOW; // Family und Pitch,
3741 FontPitch ePitch = PITCH_DONTKNOW; // falls nicht gefunden
3742 rtl_TextEncoding eEnc = osl_getThreadTextEncoding();
3744 if( !aFace.isEmpty() && !m_pCSS1Parser->IsIgnoreFontFamily() )
3746 const FontList *pFList = nullptr;
3747 SwDocShell *pDocSh = m_pDoc->GetDocShell();
3748 if( pDocSh )
3750 const SvxFontListItem *pFListItem =
3751 static_cast<const SvxFontListItem *>(pDocSh->GetItem(SID_ATTR_CHAR_FONTLIST));
3752 if( pFListItem )
3753 pFList = pFListItem->GetFontList();
3756 bool bFound = false;
3757 sal_Int32 nStrPos = 0;
3758 while( nStrPos!= -1 )
3760 OUString aFName = aFace.getToken( 0, ',', nStrPos );
3761 aFName = comphelper::string::strip(aFName, ' ');
3762 if( !aFName.isEmpty() )
3764 if( !bFound && pFList )
3766 sal_Handle hFont = pFList->GetFirstFontMetric( aFName );
3767 if( nullptr != hFont )
3769 const FontMetric& rFMetric = FontList::GetFontMetric( hFont );
3770 if( RTL_TEXTENCODING_DONTKNOW != rFMetric.GetCharSet() )
3772 bFound = true;
3773 if( RTL_TEXTENCODING_SYMBOL == rFMetric.GetCharSet() )
3774 eEnc = RTL_TEXTENCODING_SYMBOL;
3778 if( !aFontName.isEmpty() )
3779 aFontName += ";";
3780 aFontName += aFName;
3785 // einen neuen Kontext anlegen
3786 HTMLAttrContext *pCntxt = new HTMLAttrContext( static_cast< sal_uInt16 >(nToken) );
3788 // Styles parsen
3789 if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) )
3791 SfxItemSet aItemSet( m_pDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
3792 SvxCSS1PropertyInfo aPropInfo;
3794 if( nFontHeight )
3796 SvxFontHeightItem aFontHeight( nFontHeight, 100, RES_CHRATR_FONTSIZE );
3797 aItemSet.Put( aFontHeight );
3798 SvxFontHeightItem aFontHeightCJK( nFontHeight, 100, RES_CHRATR_CJK_FONTSIZE );
3799 aItemSet.Put( aFontHeightCJK );
3800 SvxFontHeightItem aFontHeightCTL( nFontHeight, 100, RES_CHRATR_CTL_FONTSIZE );
3801 aItemSet.Put( aFontHeightCTL );
3803 if( bColor )
3804 aItemSet.Put( SvxColorItem(aColor, RES_CHRATR_COLOR) );
3805 if( !aFontName.isEmpty() )
3807 SvxFontItem aFont( eFamily, aFontName, aStyleName, ePitch, eEnc, RES_CHRATR_FONT );
3808 aItemSet.Put( aFont );
3809 SvxFontItem aFontCJK( eFamily, aFontName, aStyleName, ePitch, eEnc, RES_CHRATR_CJK_FONT );
3810 aItemSet.Put( aFontCJK );
3811 SvxFontItem aFontCTL( eFamily, aFontName, aStyleName, ePitch, eEnc, RES_CHRATR_CTL_FONT );
3812 aItemSet.Put( aFontCTL );
3815 if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) )
3816 DoPositioning( aItemSet, aPropInfo, pCntxt );
3818 InsertAttrs( aItemSet, aPropInfo, pCntxt, true );
3820 else
3822 if( nFontHeight )
3824 SvxFontHeightItem aFontHeight( nFontHeight, 100, RES_CHRATR_FONTSIZE );
3825 InsertAttr( &m_aAttrTab.pFontHeight, aFontHeight, pCntxt );
3826 SvxFontHeightItem aFontHeightCJK( nFontHeight, 100, RES_CHRATR_CJK_FONTSIZE );
3827 InsertAttr( &m_aAttrTab.pFontHeight, aFontHeightCJK, pCntxt );
3828 SvxFontHeightItem aFontHeightCTL( nFontHeight, 100, RES_CHRATR_CTL_FONTSIZE );
3829 InsertAttr( &m_aAttrTab.pFontHeight, aFontHeightCTL, pCntxt );
3831 if( bColor )
3832 InsertAttr( &m_aAttrTab.pFontColor, SvxColorItem(aColor, RES_CHRATR_COLOR), pCntxt );
3833 if( !aFontName.isEmpty() )
3835 SvxFontItem aFont( eFamily, aFontName, aStyleName, ePitch, eEnc, RES_CHRATR_FONT );
3836 InsertAttr( &m_aAttrTab.pFont, aFont, pCntxt );
3837 SvxFontItem aFontCJK( eFamily, aFontName, aStyleName, ePitch, eEnc, RES_CHRATR_CJK_FONT );
3838 InsertAttr( &m_aAttrTab.pFont, aFontCJK, pCntxt );
3839 SvxFontItem aFontCTL( eFamily, aFontName, aStyleName, ePitch, eEnc, RES_CHRATR_CTL_FONT );
3840 InsertAttr( &m_aAttrTab.pFont, aFontCTL, pCntxt );
3844 // den Kontext merken
3845 PushContext( pCntxt );
3847 m_aFontStack.push_back( nSize );
3850 void SwHTMLParser::EndFontAttr( int nToken )
3852 EndTag( nToken );
3854 // Stack-Unterlauf in Tabellen vermeiden
3855 if( m_aFontStack.size() > m_nFontStMin )
3856 m_aFontStack.erase( m_aFontStack.begin() + m_aFontStack.size() - 1 );
3859 void SwHTMLParser::NewPara()
3861 if( m_pPam->GetPoint()->nContent.GetIndex() )
3862 AppendTextNode( AM_SPACE );
3863 else
3864 AddParSpace();
3866 m_eParaAdjust = SVX_ADJUST_END;
3867 OUString aId, aStyle, aClass, aLang, aDir;
3869 const HTMLOptions& rHTMLOptions = GetOptions();
3870 for (size_t i = rHTMLOptions.size(); i; )
3872 const HTMLOption& rOption = rHTMLOptions[--i];
3873 switch( rOption.GetToken() )
3875 case HTML_O_ID:
3876 aId = rOption.GetString();
3877 break;
3878 case HTML_O_ALIGN:
3879 m_eParaAdjust = (SvxAdjust)rOption.GetEnum( aHTMLPAlignTable, static_cast< sal_uInt16 >(m_eParaAdjust) );
3880 break;
3881 case HTML_O_STYLE:
3882 aStyle = rOption.GetString();
3883 break;
3884 case HTML_O_CLASS:
3885 aClass = rOption.GetString();
3886 break;
3887 case HTML_O_LANG:
3888 aLang = rOption.GetString();
3889 break;
3890 case HTML_O_DIR:
3891 aDir = rOption.GetString();
3892 break;
3896 // einen neuen Kontext anlegen
3897 HTMLAttrContext *pCntxt =
3898 !aClass.isEmpty() ? new HTMLAttrContext( HTML_PARABREAK_ON,
3899 RES_POOLCOLL_TEXT, aClass )
3900 : new HTMLAttrContext( HTML_PARABREAK_ON );
3902 // Styles parsen (Class nicht beruecksichtigen. Das geht nur, solange
3903 // keine der CSS1-Properties der Klasse hart formatiert werden muss!!!)
3904 if( HasStyleOptions( aStyle, aId, aEmptyOUStr, &aLang, &aDir ) )
3906 SfxItemSet aItemSet( m_pDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
3907 SvxCSS1PropertyInfo aPropInfo;
3909 if( ParseStyleOptions( aStyle, aId, aEmptyOUStr, aItemSet, aPropInfo, &aLang, &aDir ) )
3911 OSL_ENSURE( aClass.isEmpty() || !m_pCSS1Parser->GetClass( aClass ),
3912 "Class wird nicht beruecksichtigt" );
3913 DoPositioning( aItemSet, aPropInfo, pCntxt );
3914 InsertAttrs( aItemSet, aPropInfo, pCntxt );
3918 if( SVX_ADJUST_END != m_eParaAdjust )
3919 InsertAttr( &m_aAttrTab.pAdjust, SvxAdjustItem(m_eParaAdjust, RES_PARATR_ADJUST), pCntxt );
3921 // und auf den Stack packen
3922 PushContext( pCntxt );
3924 // die aktuelle Vorlage oder deren Attribute setzen
3925 SetTextCollAttrs( !aClass.isEmpty() ? pCntxt : nullptr );
3927 // Laufbalkenanzeige
3928 ShowStatline();
3930 OSL_ENSURE( !m_nOpenParaToken, "Jetzt geht ein offenes Absatz-Element verloren" );
3931 m_nOpenParaToken = HTML_PARABREAK_ON;
3934 void SwHTMLParser::EndPara( bool bReal )
3936 if( HTML_LI_ON==m_nOpenParaToken && m_pTable )
3938 #if OSL_DEBUG_LEVEL > 0
3939 const SwNumRule *pNumRule = m_pPam->GetNode().GetTextNode()->GetNumRule();
3940 OSL_ENSURE( pNumRule, "Wo ist die Numrule geblieben" );
3941 #endif
3944 // leere Absaetze werden von Netscape uebersprungen, von uns jetzt auch
3945 if( bReal )
3947 if( m_pPam->GetPoint()->nContent.GetIndex() )
3948 AppendTextNode( AM_SPACE );
3949 else
3950 AddParSpace();
3953 // wenn ein DD oder DT offen war, handelt es sich um eine
3954 // implizite Def-Liste, die jetzt beendet werden muss
3955 if( (m_nOpenParaToken==HTML_DT_ON || m_nOpenParaToken==HTML_DD_ON) &&
3956 m_nDefListDeep)
3958 m_nDefListDeep--;
3961 // den Kontext vom Stack holen. Er kann auch von einer implizit
3962 // geoeffneten Definitionsliste kommen
3963 HTMLAttrContext *pCntxt =
3964 PopContext( static_cast< sal_uInt16 >(m_nOpenParaToken ? (m_nOpenParaToken & ~1)
3965 : HTML_PARABREAK_ON) );
3967 // Attribute beenden
3968 if( pCntxt )
3970 EndContext( pCntxt );
3971 SetAttr(); // Absatz-Atts wegen JavaScript moeglichst schnell setzen
3972 delete pCntxt;
3975 // und die bisherige Vorlage neu setzen
3976 if( bReal )
3977 SetTextCollAttrs();
3979 m_nOpenParaToken = 0;
3982 void SwHTMLParser::NewHeading( int nToken )
3984 m_eParaAdjust = SVX_ADJUST_END;
3986 OUString aId, aStyle, aClass, aLang, aDir;
3988 const HTMLOptions& rHTMLOptions = GetOptions();
3989 for (size_t i = rHTMLOptions.size(); i; )
3991 const HTMLOption& rOption = rHTMLOptions[--i];
3992 switch( rOption.GetToken() )
3994 case HTML_O_ID:
3995 aId = rOption.GetString();
3996 break;
3997 case HTML_O_ALIGN:
3998 m_eParaAdjust = (SvxAdjust)rOption.GetEnum( aHTMLPAlignTable, static_cast< sal_uInt16 >(m_eParaAdjust) );
3999 break;
4000 case HTML_O_STYLE:
4001 aStyle = rOption.GetString();
4002 break;
4003 case HTML_O_CLASS:
4004 aClass = rOption.GetString();
4005 break;
4006 case HTML_O_LANG:
4007 aLang = rOption.GetString();
4008 break;
4009 case HTML_O_DIR:
4010 aDir = rOption.GetString();
4011 break;
4015 // einen neuen Absatz aufmachen
4016 if( m_pPam->GetPoint()->nContent.GetIndex() )
4017 AppendTextNode( AM_SPACE );
4018 else
4019 AddParSpace();
4021 // die passende Vorlage suchen
4022 sal_uInt16 nTextColl;
4023 switch( nToken )
4025 case HTML_HEAD1_ON: nTextColl = RES_POOLCOLL_HEADLINE1; break;
4026 case HTML_HEAD2_ON: nTextColl = RES_POOLCOLL_HEADLINE2; break;
4027 case HTML_HEAD3_ON: nTextColl = RES_POOLCOLL_HEADLINE3; break;
4028 case HTML_HEAD4_ON: nTextColl = RES_POOLCOLL_HEADLINE4; break;
4029 case HTML_HEAD5_ON: nTextColl = RES_POOLCOLL_HEADLINE5; break;
4030 case HTML_HEAD6_ON: nTextColl = RES_POOLCOLL_HEADLINE6; break;
4031 default: nTextColl = RES_POOLCOLL_STANDARD; break;
4034 // den Kontext anlegen
4035 HTMLAttrContext *pCntxt = new HTMLAttrContext( static_cast< sal_uInt16 >(nToken), nTextColl, aClass );
4037 // Styles parsen (zu Class siehe auch NewPara)
4038 if( HasStyleOptions( aStyle, aId, aEmptyOUStr, &aLang, &aDir ) )
4040 SfxItemSet aItemSet( m_pDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
4041 SvxCSS1PropertyInfo aPropInfo;
4043 if( ParseStyleOptions( aStyle, aId, aEmptyOUStr, aItemSet, aPropInfo, &aLang, &aDir ) )
4045 OSL_ENSURE( aClass.isEmpty() || !m_pCSS1Parser->GetClass( aClass ),
4046 "Class wird nicht beruecksichtigt" );
4047 DoPositioning( aItemSet, aPropInfo, pCntxt );
4048 InsertAttrs( aItemSet, aPropInfo, pCntxt );
4052 if( SVX_ADJUST_END != m_eParaAdjust )
4053 InsertAttr( &m_aAttrTab.pAdjust, SvxAdjustItem(m_eParaAdjust, RES_PARATR_ADJUST), pCntxt );
4055 // udn auf den Stack packen
4056 PushContext( pCntxt );
4058 // und die Vorlage oder deren Attribute setzen
4059 SetTextCollAttrs( pCntxt );
4061 m_nFontStHeadStart = m_aFontStack.size();
4063 // Laufbalkenanzeige
4064 ShowStatline();
4067 void SwHTMLParser::EndHeading()
4069 // einen neuen Absatz aufmachen
4070 if( m_pPam->GetPoint()->nContent.GetIndex() )
4071 AppendTextNode( AM_SPACE );
4072 else
4073 AddParSpace();
4075 // Kontext zu dem Token suchen und vom Stack holen
4076 HTMLAttrContext *pCntxt = nullptr;
4077 auto nPos = m_aContexts.size();
4078 while( !pCntxt && nPos>m_nContextStMin )
4080 switch( m_aContexts[--nPos]->GetToken() )
4082 case HTML_HEAD1_ON:
4083 case HTML_HEAD2_ON:
4084 case HTML_HEAD3_ON:
4085 case HTML_HEAD4_ON:
4086 case HTML_HEAD5_ON:
4087 case HTML_HEAD6_ON:
4088 pCntxt = m_aContexts[nPos];
4089 m_aContexts.erase( m_aContexts.begin() + nPos );
4090 break;
4094 // und noch Attribute beenden
4095 if( pCntxt )
4097 EndContext( pCntxt );
4098 SetAttr(); // Absatz-Atts wegen JavaScript moeglichst schnell setzen
4099 delete pCntxt;
4102 // die bisherige Vorlage neu setzen
4103 SetTextCollAttrs();
4105 m_nFontStHeadStart = m_nFontStMin;
4108 void SwHTMLParser::NewTextFormatColl( int nToken, sal_uInt16 nColl )
4110 OUString aId, aStyle, aClass, aLang, aDir;
4112 const HTMLOptions& rHTMLOptions = GetOptions();
4113 for (size_t i = rHTMLOptions.size(); i; )
4115 const HTMLOption& rOption = rHTMLOptions[--i];
4116 switch( rOption.GetToken() )
4118 case HTML_O_ID:
4119 aId = rOption.GetString();
4120 break;
4121 case HTML_O_STYLE:
4122 aStyle = rOption.GetString();
4123 break;
4124 case HTML_O_CLASS:
4125 aClass = rOption.GetString();
4126 break;
4127 case HTML_O_LANG:
4128 aLang = rOption.GetString();
4129 break;
4130 case HTML_O_DIR:
4131 aDir = rOption.GetString();
4132 break;
4136 // einen neuen Absatz aufmachen
4137 SwHTMLAppendMode eMode = AM_NORMAL;
4138 switch( nToken )
4140 case HTML_LISTING_ON:
4141 case HTML_XMP_ON:
4142 // Diese beiden Tags werden jetzt auf die PRE-Vorlage gemappt.
4143 // Fuer dem Fall, dass ein CLASS angegeben ist, loeschen wir
4144 // es damit wir nicht die CLASS der PRE-Vorlage bekommen.
4145 aClass = aEmptyOUStr;
4146 SAL_FALLTHROUGH;
4147 case HTML_BLOCKQUOTE_ON:
4148 case HTML_BLOCKQUOTE30_ON:
4149 case HTML_PREFORMTXT_ON:
4150 eMode = AM_SPACE;
4151 break;
4152 case HTML_ADDRESS_ON:
4153 eMode = AM_NOSPACE; // ADDRESS kann auf einen <P> ohne </P> folgen
4154 break;
4155 case HTML_DT_ON:
4156 case HTML_DD_ON:
4157 eMode = AM_SOFTNOSPACE;
4158 break;
4159 default:
4160 OSL_ENSURE( false, "unbekannte Vorlage" );
4161 break;
4163 if( m_pPam->GetPoint()->nContent.GetIndex() )
4164 AppendTextNode( eMode );
4165 else if( AM_SPACE==eMode )
4166 AddParSpace();
4168 // ... und in einem Kontext merken
4169 HTMLAttrContext *pCntxt = new HTMLAttrContext( static_cast< sal_uInt16 >(nToken), nColl, aClass );
4171 // Styles parsen (zu Class siehe auch NewPara)
4172 if( HasStyleOptions( aStyle, aId, aEmptyOUStr, &aLang, &aDir ) )
4174 SfxItemSet aItemSet( m_pDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
4175 SvxCSS1PropertyInfo aPropInfo;
4177 if( ParseStyleOptions( aStyle, aId, aEmptyOUStr, aItemSet, aPropInfo, &aLang, &aDir ) )
4179 OSL_ENSURE( aClass.isEmpty() || !m_pCSS1Parser->GetClass( aClass ),
4180 "Class wird nicht beruecksichtigt" );
4181 DoPositioning( aItemSet, aPropInfo, pCntxt );
4182 InsertAttrs( aItemSet, aPropInfo, pCntxt );
4186 PushContext( pCntxt );
4188 // die neue Vorlage setzen
4189 SetTextCollAttrs( pCntxt );
4191 // Laufbalkenanzeige aktualisieren
4192 ShowStatline();
4195 void SwHTMLParser::EndTextFormatColl( int nToken )
4197 SwHTMLAppendMode eMode = AM_NORMAL;
4198 switch( nToken & ~1 )
4200 case HTML_BLOCKQUOTE_ON:
4201 case HTML_BLOCKQUOTE30_ON:
4202 case HTML_PREFORMTXT_ON:
4203 case HTML_LISTING_ON:
4204 case HTML_XMP_ON:
4205 eMode = AM_SPACE;
4206 break;
4207 case HTML_ADDRESS_ON:
4208 case HTML_DT_ON:
4209 case HTML_DD_ON:
4210 eMode = AM_SOFTNOSPACE;
4211 break;
4212 default:
4213 OSL_ENSURE( false, "unbekannte Vorlage" );
4214 break;
4216 if( m_pPam->GetPoint()->nContent.GetIndex() )
4217 AppendTextNode( eMode );
4218 else if( AM_SPACE==eMode )
4219 AddParSpace();
4221 // den aktuellen Kontext vom Stack holen
4222 HTMLAttrContext *pCntxt = PopContext( static_cast< sal_uInt16 >(nToken & ~1) );
4224 // und noch Attribute beenden
4225 if( pCntxt )
4227 EndContext( pCntxt );
4228 SetAttr(); // Absatz-Atts wegen JavaScript moeglichst schnell setzen
4229 delete pCntxt;
4232 // und die bisherige Vorlage setzen
4233 SetTextCollAttrs();
4236 void SwHTMLParser::NewDefList()
4238 OUString aId, aStyle, aClass, aLang, aDir;
4240 const HTMLOptions& rHTMLOptions = GetOptions();
4241 for (size_t i = rHTMLOptions.size(); i; )
4243 const HTMLOption& rOption = rHTMLOptions[--i];
4244 switch( rOption.GetToken() )
4246 case HTML_O_ID:
4247 aId = rOption.GetString();
4248 break;
4249 case HTML_O_STYLE:
4250 aStyle = rOption.GetString();
4251 break;
4252 case HTML_O_CLASS:
4253 aClass = rOption.GetString();
4254 break;
4255 case HTML_O_LANG:
4256 aLang = rOption.GetString();
4257 break;
4258 case HTML_O_DIR:
4259 aDir = rOption.GetString();
4260 break;
4264 // einen neuen Absatz aufmachen
4265 bool bSpace = (GetNumInfo().GetDepth() + m_nDefListDeep) == 0;
4266 if( m_pPam->GetPoint()->nContent.GetIndex() )
4267 AppendTextNode( bSpace ? AM_SPACE : AM_SOFTNOSPACE );
4268 else if( bSpace )
4269 AddParSpace();
4271 // ein Level mehr
4272 m_nDefListDeep++;
4274 bool bInDD = false, bNotInDD = false;
4275 auto nPos = m_aContexts.size();
4276 while( !bInDD && !bNotInDD && nPos>m_nContextStMin )
4278 sal_uInt16 nCntxtToken = m_aContexts[--nPos]->GetToken();
4279 switch( nCntxtToken )
4281 case HTML_DEFLIST_ON:
4282 case HTML_DIRLIST_ON:
4283 case HTML_MENULIST_ON:
4284 case HTML_ORDERLIST_ON:
4285 case HTML_UNORDERLIST_ON:
4286 bNotInDD = true;
4287 break;
4288 case HTML_DD_ON:
4289 bInDD = true;
4290 break;
4294 // ... und in einem Kontext merken
4295 HTMLAttrContext *pCntxt = new HTMLAttrContext( HTML_DEFLIST_ON );
4297 // darin auch die Raender merken
4298 sal_uInt16 nLeft=0, nRight=0;
4299 short nIndent=0;
4300 GetMarginsFromContext( nLeft, nRight, nIndent );
4302 // Die Einrueckung, die sich schon aus einem DL-ergibt, entspricht der
4303 // eines DT auf dem aktuellen Level, und die entspricht der eines
4304 // DD auf dem Level davor. Fue einen Level >=2 muss also ein DD-Abstand
4305 // hinzugefuegt werden
4306 if( !bInDD && m_nDefListDeep > 1 )
4309 // und den der DT-Vorlage des aktuellen Levels
4310 SvxLRSpaceItem rLRSpace =
4311 m_pCSS1Parser->GetTextFormatColl( RES_POOLCOLL_HTML_DD, aEmptyOUStr )
4312 ->GetLRSpace();
4313 nLeft = nLeft + static_cast< sal_uInt16 >(rLRSpace.GetTextLeft());
4316 pCntxt->SetMargins( nLeft, nRight, nIndent );
4318 // Styles parsen
4319 if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) )
4321 SfxItemSet aItemSet( m_pDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
4322 SvxCSS1PropertyInfo aPropInfo;
4324 if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) )
4326 DoPositioning( aItemSet, aPropInfo, pCntxt );
4327 InsertAttrs( aItemSet, aPropInfo, pCntxt );
4331 PushContext( pCntxt );
4333 // die Attribute der neuen Vorlage setzen
4334 if( m_nDefListDeep > 1 )
4335 SetTextCollAttrs( pCntxt );
4338 void SwHTMLParser::EndDefList()
4340 bool bSpace = (GetNumInfo().GetDepth() + m_nDefListDeep) == 1;
4341 if( m_pPam->GetPoint()->nContent.GetIndex() )
4342 AppendTextNode( bSpace ? AM_SPACE : AM_SOFTNOSPACE );
4343 else if( bSpace )
4344 AddParSpace();
4346 // ein Level weniger
4347 if( m_nDefListDeep > 0 )
4348 m_nDefListDeep--;
4350 // den aktuellen Kontext vom Stack holen
4351 HTMLAttrContext *pCntxt = PopContext( HTML_DEFLIST_ON );
4353 // und noch Attribute beenden
4354 if( pCntxt )
4356 EndContext( pCntxt );
4357 SetAttr(); // Absatz-Atts wegen JavaScript moeglichst schnell setzen
4358 delete pCntxt;
4361 // und Vorlage setzen
4362 SetTextCollAttrs();
4365 void SwHTMLParser::NewDefListItem( int nToken )
4367 // festellen, ob das DD/DT in einer DL vorkommt
4368 bool bInDefList = false, bNotInDefList = false;
4369 auto nPos = m_aContexts.size();
4370 while( !bInDefList && !bNotInDefList && nPos>m_nContextStMin )
4372 sal_uInt16 nCntxtToken = m_aContexts[--nPos]->GetToken();
4373 switch( nCntxtToken )
4375 case HTML_DEFLIST_ON:
4376 bInDefList = true;
4377 break;
4378 case HTML_DIRLIST_ON:
4379 case HTML_MENULIST_ON:
4380 case HTML_ORDERLIST_ON:
4381 case HTML_UNORDERLIST_ON:
4382 bNotInDefList = true;
4383 break;
4387 // wenn nicht, implizit eine neue DL aufmachen
4388 if( !bInDefList )
4390 m_nDefListDeep++;
4391 OSL_ENSURE( !m_nOpenParaToken,
4392 "Jetzt geht ein offenes Absatz-Element verloren" );
4393 m_nOpenParaToken = static_cast< sal_uInt16 >(nToken);
4396 NewTextFormatColl( nToken, static_cast< sal_uInt16 >(nToken==HTML_DD_ON ? RES_POOLCOLL_HTML_DD
4397 : RES_POOLCOLL_HTML_DT) );
4400 void SwHTMLParser::EndDefListItem( int nToken, bool /*bLastPara*/ )
4402 // einen neuen Absatz aufmachen
4403 if( !nToken && m_pPam->GetPoint()->nContent.GetIndex() )
4404 AppendTextNode( AM_SOFTNOSPACE );
4406 // Kontext zu dem Token suchen und vom Stack holen
4407 nToken &= ~1;
4408 HTMLAttrContext *pCntxt = nullptr;
4409 auto nPos = m_aContexts.size();
4410 while( !pCntxt && nPos>m_nContextStMin )
4412 sal_uInt16 nCntxtToken = m_aContexts[--nPos]->GetToken();
4413 switch( nCntxtToken )
4415 case HTML_DD_ON:
4416 case HTML_DT_ON:
4417 if( !nToken || nToken == nCntxtToken )
4419 pCntxt = m_aContexts[nPos];
4420 m_aContexts.erase( m_aContexts.begin() + nPos );
4422 break;
4423 case HTML_DEFLIST_ON:
4424 // keine DD/DT ausserhalb der aktuelen DefListe betrachten
4425 case HTML_DIRLIST_ON:
4426 case HTML_MENULIST_ON:
4427 case HTML_ORDERLIST_ON:
4428 case HTML_UNORDERLIST_ON:
4429 // und auch nicht ausserhalb einer anderen Liste
4430 nPos = m_nContextStMin;
4431 break;
4435 // und noch Attribute beenden
4436 if( pCntxt )
4438 EndContext( pCntxt );
4439 SetAttr(); // Absatz-Atts wegen JavaScript moeglichst schnell setzen
4440 delete pCntxt;
4444 bool SwHTMLParser::HasCurrentParaFlys( bool bNoSurroundOnly,
4445 bool bSurroundOnly ) const
4447 // bNoSurroundOnly: Der Absatz enthaelt mindestens einen Rahmen
4448 // ohne Umlauf
4449 // bSurroundOnly: Der Absatz enthaelt mindestens einen Rahmen
4450 // mit Umlauf aber keinen ohne Umlauf
4451 // sonst: Der Absatz enthaelt irgendeinen Rahmen
4452 SwNodeIndex& rNodeIdx = m_pPam->GetPoint()->nNode;
4454 const SwFrameFormats& rFrameFormatTable = *m_pDoc->GetSpzFrameFormats();
4456 bool bFound = false;
4457 for ( size_t i=0; i<rFrameFormatTable.size(); i++ )
4459 const SwFrameFormat *const pFormat = rFrameFormatTable[i];
4460 SwFormatAnchor const*const pAnchor = &pFormat->GetAnchor();
4461 // Ein Rahmen wurde gefunden, wenn
4462 // - er absatzgebunden ist, und
4463 // - im aktuellen Absatz verankert ist, und
4464 // - jeder absatzgebunene Rahmen zaehlt, oder
4465 // - (nur Rahmen oder umlauf zaehlen und ) der Rahmen keinen
4466 // Umlauf besitzt
4467 SwPosition const*const pAPos = pAnchor->GetContentAnchor();
4468 if (pAPos &&
4469 ((FLY_AT_PARA == pAnchor->GetAnchorId()) ||
4470 (FLY_AT_CHAR == pAnchor->GetAnchorId())) &&
4471 pAPos->nNode == rNodeIdx )
4473 if( !(bNoSurroundOnly || bSurroundOnly) )
4475 bFound = true;
4476 break;
4478 else
4480 // Wenn Rahmen mit Umlauf gesucht sind,
4481 // auch keine mit Durchlauf beachten. Dabei handelt es
4482 // sich (noch) um HIDDEN-Controls, und denen weicht man
4483 // besser auch nicht aus.
4484 SwSurround eSurround = pFormat->GetSurround().GetSurround();
4485 if( bNoSurroundOnly )
4487 if( SURROUND_NONE==eSurround )
4489 bFound = true;
4490 break;
4493 if( bSurroundOnly )
4495 if( SURROUND_NONE==eSurround )
4497 bFound = false;
4498 break;
4500 else if( SURROUND_THROUGHT!=eSurround )
4502 bFound = true;
4503 // weitersuchen: Es koennten ja noch welche ohne
4504 // Umlauf kommen ...
4511 return bFound;
4514 // die speziellen Methoden zum Einfuegen von Objecten
4516 const SwFormatColl *SwHTMLParser::GetCurrFormatColl() const
4518 const SwContentNode* pCNd = m_pPam->GetContentNode();
4519 return &pCNd->GetAnyFormatColl();
4522 void SwHTMLParser::SetTextCollAttrs( HTMLAttrContext *pContext )
4524 SwTextFormatColl *pCollToSet = nullptr; // die zu setzende Vorlage
4525 SfxItemSet *pItemSet = nullptr; // der Set fuer harte Attrs
4526 sal_uInt16 nTopColl = pContext ? pContext->GetTextFormatColl() : 0;
4527 const OUString& rTopClass = pContext ? pContext->GetClass() : aEmptyOUStr;
4528 sal_uInt16 nDfltColl = RES_POOLCOLL_TEXT;
4530 bool bInPRE=false; // etwas Kontext Info
4532 sal_uInt16 nLeftMargin = 0, nRightMargin = 0; // die Einzuege und
4533 short nFirstLineIndent = 0; // Abstaende
4535 for( auto i = m_nContextStAttrMin; i < m_aContexts.size(); ++i )
4537 const HTMLAttrContext *pCntxt = m_aContexts[i];
4539 sal_uInt16 nColl = pCntxt->GetTextFormatColl();
4540 if( nColl )
4542 // Es gibt eine Vorlage, die zu setzen ist. Dann
4543 // muss zunaechst einmal entschieden werden,
4544 // ob die Vorlage auch gesetzt werden kann
4545 bool bSetThis = true;
4546 switch( nColl )
4548 case RES_POOLCOLL_HTML_PRE:
4549 bInPRE = true;
4550 break;
4551 case RES_POOLCOLL_TEXT:
4552 // <TD><P CLASS=xxx> muss TD.xxx werden
4553 if( nDfltColl==RES_POOLCOLL_TABLE ||
4554 nDfltColl==RES_POOLCOLL_TABLE_HDLN )
4555 nColl = nDfltColl;
4556 break;
4557 case RES_POOLCOLL_HTML_HR:
4558 // <HR> auch in <PRE> als Vorlage setzen, sonst kann man sie
4559 // nicht mehr exportieren
4560 break;
4561 default:
4562 if( bInPRE )
4563 bSetThis = false;
4564 break;
4567 SwTextFormatColl *pNewColl =
4568 m_pCSS1Parser->GetTextFormatColl( nColl, pCntxt->GetClass() );
4570 if( bSetThis )
4572 // wenn jetzt eine andere Vorlage gesetzt werden soll als
4573 // bisher, muss die bishere Vorlage durch harte Attributierung
4574 // ersetzt werden
4576 if( pCollToSet )
4578 // die Attribute, die bisherige Vorlage setzt
4579 // hart einfuegen
4580 if( !pItemSet )
4581 pItemSet = new SfxItemSet( pCollToSet->GetAttrSet() );
4582 else
4584 const SfxItemSet& rCollSet = pCollToSet->GetAttrSet();
4585 SfxItemSet aItemSet( *rCollSet.GetPool(),
4586 rCollSet.GetRanges() );
4587 aItemSet.Set( rCollSet );
4588 pItemSet->Put( aItemSet );
4590 // aber die Attribute, die aktuelle Vorlage setzt
4591 // entfernen, weil sie sonst spaeter ueberschrieben
4592 // werden
4593 pItemSet->Differentiate( pNewColl->GetAttrSet() );
4596 pCollToSet = pNewColl;
4598 else
4600 // hart Attributieren
4601 if( !pItemSet )
4602 pItemSet = new SfxItemSet( pNewColl->GetAttrSet() );
4603 else
4605 const SfxItemSet& rCollSet = pNewColl->GetAttrSet();
4606 SfxItemSet aItemSet( *rCollSet.GetPool(),
4607 rCollSet.GetRanges() );
4608 aItemSet.Set( rCollSet );
4609 pItemSet->Put( aItemSet );
4613 else
4615 // vielliecht gibt es ja eine Default-Vorlage?
4616 nColl = pCntxt->GetDfltTextFormatColl();
4617 if( nColl )
4618 nDfltColl = nColl;
4621 // ggf. neue Absatz-Einzuege holen
4622 if( pCntxt->IsLRSpaceChanged() )
4624 sal_uInt16 nLeft=0, nRight=0;
4626 pCntxt->GetMargins( nLeft, nRight, nFirstLineIndent );
4627 nLeftMargin = nLeft;
4628 nRightMargin = nRight;
4632 // wenn im aktuellen Kontext eine neue Vorlage gesetzt werden soll,
4633 // muessen deren Absatz-Abstaende noch in den Kontext eingetragen werden
4634 if( pContext && nTopColl )
4636 // <TD><P CLASS=xxx> muss TD.xxx werden
4637 if( nTopColl==RES_POOLCOLL_TEXT &&
4638 (nDfltColl==RES_POOLCOLL_TABLE ||
4639 nDfltColl==RES_POOLCOLL_TABLE_HDLN) )
4640 nTopColl = nDfltColl;
4642 const SwTextFormatColl *pTopColl =
4643 m_pCSS1Parser->GetTextFormatColl( nTopColl, rTopClass );
4644 const SfxItemSet& rItemSet = pTopColl->GetAttrSet();
4645 const SfxPoolItem *pItem;
4646 if( SfxItemState::SET == rItemSet.GetItemState(RES_LR_SPACE,true, &pItem) )
4648 const SvxLRSpaceItem *pLRItem =
4649 static_cast<const SvxLRSpaceItem *>(pItem);
4651 sal_Int32 nLeft = pLRItem->GetTextLeft();
4652 sal_Int32 nRight = pLRItem->GetRight();
4653 nFirstLineIndent = pLRItem->GetTextFirstLineOfst();
4655 // In Definitions-Listen enthalten die Abstaende auch die der
4656 // vorhergehenden Level
4657 if( RES_POOLCOLL_HTML_DD == nTopColl )
4659 const SvxLRSpaceItem& rDTLRSpace = m_pCSS1Parser
4660 ->GetTextFormatColl( RES_POOLCOLL_HTML_DT, aEmptyOUStr )
4661 ->GetLRSpace();
4662 nLeft -= rDTLRSpace.GetTextLeft();
4663 nRight -= rDTLRSpace.GetRight();
4665 else if( RES_POOLCOLL_HTML_DT == nTopColl )
4667 nLeft = 0;
4668 nRight = 0;
4671 // die Absatz-Abstaende addieren sich
4672 nLeftMargin = nLeftMargin + static_cast< sal_uInt16 >(nLeft);
4673 nRightMargin = nRightMargin + static_cast< sal_uInt16 >(nRight);
4675 pContext->SetMargins( nLeftMargin, nRightMargin,
4676 nFirstLineIndent );
4678 if( SfxItemState::SET == rItemSet.GetItemState(RES_UL_SPACE,true, &pItem) )
4680 const SvxULSpaceItem *pULItem =
4681 static_cast<const SvxULSpaceItem *>(pItem);
4682 pContext->SetULSpace( pULItem->GetUpper(), pULItem->GetLower() );
4686 // wenn gar keine Vorlage im Kontext gesetzt ist, Textkoerper nehmen
4687 if( !pCollToSet )
4689 pCollToSet = m_pCSS1Parser->GetTextCollFromPool( nDfltColl );
4690 const SvxLRSpaceItem& rLRItem = pCollToSet->GetLRSpace();
4691 if( !nLeftMargin )
4692 nLeftMargin = static_cast< sal_uInt16 >(rLRItem.GetTextLeft());
4693 if( !nRightMargin )
4694 nRightMargin = static_cast< sal_uInt16 >(rLRItem.GetRight());
4695 if( !nFirstLineIndent )
4696 nFirstLineIndent = rLRItem.GetTextFirstLineOfst();
4699 // bisherige harte Attributierung des Absatzes entfernen
4700 if( !m_aParaAttrs.empty() )
4702 for( auto pParaAttr : m_aParaAttrs )
4703 pParaAttr->Invalidate();
4705 m_aParaAttrs.clear();
4708 // Die Vorlage setzen
4709 m_pDoc->SetTextFormatColl( *m_pPam, pCollToSet );
4711 // ggf. noch den Absatz-Einzug korrigieren
4712 const SvxLRSpaceItem& rLRItem = pCollToSet->GetLRSpace();
4713 bool bSetLRSpace;
4715 bSetLRSpace = nLeftMargin != rLRItem.GetTextLeft() ||
4716 nFirstLineIndent != rLRItem.GetTextFirstLineOfst() ||
4717 nRightMargin != rLRItem.GetRight();
4719 if( bSetLRSpace )
4721 SvxLRSpaceItem aLRItem( rLRItem );
4722 aLRItem.SetTextLeft( nLeftMargin );
4723 aLRItem.SetRight( nRightMargin );
4724 aLRItem.SetTextFirstLineOfst( nFirstLineIndent );
4725 if( pItemSet )
4726 pItemSet->Put( aLRItem );
4727 else
4729 NewAttr( &m_aAttrTab.pLRSpace, aLRItem );
4730 m_aAttrTab.pLRSpace->SetLikePara();
4731 m_aParaAttrs.push_back( m_aAttrTab.pLRSpace );
4732 EndAttr( m_aAttrTab.pLRSpace, false );
4736 // und nun noch die Attribute setzen
4737 if( pItemSet )
4739 InsertParaAttrs( *pItemSet );
4740 delete pItemSet;
4744 void SwHTMLParser::NewCharFormat( int nToken )
4746 OUString aId, aStyle, aLang, aDir;
4747 OUString aClass;
4749 const HTMLOptions& rHTMLOptions = GetOptions();
4750 for (size_t i = rHTMLOptions.size(); i; )
4752 const HTMLOption& rOption = rHTMLOptions[--i];
4753 switch( rOption.GetToken() )
4755 case HTML_O_ID:
4756 aId = rOption.GetString();
4757 break;
4758 case HTML_O_STYLE:
4759 aStyle = rOption.GetString();
4760 break;
4761 case HTML_O_CLASS:
4762 aClass = rOption.GetString();
4763 break;
4764 case HTML_O_LANG:
4765 aLang = rOption.GetString();
4766 break;
4767 case HTML_O_DIR:
4768 aDir = rOption.GetString();
4769 break;
4773 // einen neuen Kontext anlegen
4774 HTMLAttrContext *pCntxt = new HTMLAttrContext( static_cast< sal_uInt16 >(nToken) );
4776 // die Vorlage setzen und im Kontext merken
4777 SwCharFormat* pCFormat = m_pCSS1Parser->GetChrFormat( static_cast< sal_uInt16 >(nToken), aClass );
4778 OSL_ENSURE( pCFormat, "keine Zeichenvorlage zu Token gefunden" );
4780 // Styles parsen (zu Class siehe auch NewPara)
4781 if( HasStyleOptions( aStyle, aId, aEmptyOUStr, &aLang, &aDir ) )
4783 SfxItemSet aItemSet( m_pDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
4784 SvxCSS1PropertyInfo aPropInfo;
4786 if( ParseStyleOptions( aStyle, aId, aEmptyOUStr, aItemSet, aPropInfo, &aLang, &aDir ) )
4788 OSL_ENSURE( aClass.isEmpty() || !m_pCSS1Parser->GetClass( aClass ),
4789 "Class wird nicht beruecksichtigt" );
4790 DoPositioning( aItemSet, aPropInfo, pCntxt );
4791 InsertAttrs( aItemSet, aPropInfo, pCntxt, true );
4795 // Zeichen-Vorlagen werden in einem eigenen Stack gehalten und
4796 // koennen nie durch Styles eingefuegt werden. Das Attribut ist deshalb
4797 // auch gar nicht im CSS1-Which-Range enthalten
4798 if( pCFormat )
4799 InsertAttr( &m_aAttrTab.pCharFormats, SwFormatCharFormat( pCFormat ), pCntxt );
4801 // den Kontext merken
4802 PushContext( pCntxt );
4805 void SwHTMLParser::InsertSpacer()
4807 // und es ggf. durch die Optionen veraendern
4808 OUString aId;
4809 sal_Int16 eVertOri = text::VertOrientation::TOP;
4810 sal_Int16 eHoriOri = text::HoriOrientation::NONE;
4811 Size aSize( 0, 0);
4812 long nSize = 0;
4813 bool bPrcWidth = false;
4814 bool bPrcHeight = false;
4815 sal_uInt16 nType = HTML_SPTYPE_HORI;
4817 const HTMLOptions& rHTMLOptions = GetOptions();
4818 for (size_t i = rHTMLOptions.size(); i; )
4820 const HTMLOption& rOption = rHTMLOptions[--i];
4821 switch( rOption.GetToken() )
4823 case HTML_O_ID:
4824 aId = rOption.GetString();
4825 break;
4826 case HTML_O_TYPE:
4827 rOption.GetEnum( nType, aHTMLSpacerTypeTable );
4828 break;
4829 case HTML_O_ALIGN:
4830 eVertOri =
4831 rOption.GetEnum( aHTMLImgVAlignTable,
4832 eVertOri );
4833 eHoriOri =
4834 rOption.GetEnum( aHTMLImgHAlignTable,
4835 eHoriOri );
4836 break;
4837 case HTML_O_WIDTH:
4838 // erstmal nur als Pixelwerte merken!
4839 bPrcWidth = (rOption.GetString().indexOf('%') != -1);
4840 aSize.Width() = (long)rOption.GetNumber();
4841 break;
4842 case HTML_O_HEIGHT:
4843 // erstmal nur als Pixelwerte merken!
4844 bPrcHeight = (rOption.GetString().indexOf('%') != -1);
4845 aSize.Height() = (long)rOption.GetNumber();
4846 break;
4847 case HTML_O_SIZE:
4848 // erstmal nur als Pixelwerte merken!
4849 nSize = rOption.GetNumber();
4850 break;
4854 switch( nType )
4856 case HTML_SPTYPE_BLOCK:
4858 // einen leeren Textrahmen anlegen
4860 // den Itemset holen
4861 SfxItemSet aFrameSet( m_pDoc->GetAttrPool(),
4862 RES_FRMATR_BEGIN, RES_FRMATR_END-1 );
4863 if( !IsNewDoc() )
4864 Reader::ResetFrameFormatAttrs( aFrameSet );
4866 // den Anker und die Ausrichtung setzen
4867 SetAnchorAndAdjustment( eVertOri, eHoriOri, aFrameSet );
4869 // und noch die Groesse des Rahmens
4870 Size aDfltSz( MINFLY, MINFLY );
4871 Size aSpace( 0, 0 );
4872 SfxItemSet aDummyItemSet( m_pDoc->GetAttrPool(),
4873 m_pCSS1Parser->GetWhichMap() );
4874 SvxCSS1PropertyInfo aDummyPropInfo;
4876 SetFixSize( aSize, aDfltSz, bPrcWidth, bPrcHeight,
4877 aDummyItemSet, aDummyPropInfo, aFrameSet );
4878 SetSpace( aSpace, aDummyItemSet, aDummyPropInfo, aFrameSet );
4880 // den Inhalt schuetzen
4881 SvxProtectItem aProtectItem( RES_PROTECT) ;
4882 aProtectItem.SetContentProtect( true );
4883 aFrameSet.Put( aProtectItem );
4885 // der Rahmen anlegen
4886 RndStdIds eAnchorId =
4887 static_cast<const SwFormatAnchor &>(aFrameSet.Get(RES_ANCHOR)).GetAnchorId();
4888 SwFrameFormat *pFlyFormat = m_pDoc->MakeFlySection( eAnchorId,
4889 m_pPam->GetPoint(), &aFrameSet );
4890 // Ggf Frames anlegen und auto-geb. Rahmen registrieren
4891 RegisterFlyFrame( pFlyFormat );
4893 break;
4894 case HTML_SPTYPE_VERT:
4895 if( nSize > 0 )
4897 if( nSize && Application::GetDefaultDevice() )
4899 nSize = Application::GetDefaultDevice()
4900 ->PixelToLogic( Size(0,nSize),
4901 MapMode(MapUnit::MapTwip) ).Height();
4904 // einen Absatz-Abstand setzen
4905 SwTextNode *pTextNode = nullptr;
4906 if( !m_pPam->GetPoint()->nContent.GetIndex() )
4908 // den unteren Absatz-Abstand des vorherigen Nodes aendern,
4909 // wenn moeglich
4911 SetAttr(); // noch offene Absatz-Attribute setzen
4913 pTextNode = m_pDoc->GetNodes()[m_pPam->GetPoint()->nNode.GetIndex()-1]
4914 ->GetTextNode();
4916 // Wenn der Abstz davor kein Textenode ist, dann wird jetzt
4917 // ein leere Absatz angelegt, der eh schon eine Zeilenhoehe
4918 // Abstand erzeugt.
4919 if( !pTextNode )
4920 nSize = nSize>HTML_PARSPACE ? nSize-HTML_PARSPACE : 0;
4923 if( pTextNode )
4925 SvxULSpaceItem aULSpace( static_cast<const SvxULSpaceItem&>(pTextNode
4926 ->SwContentNode::GetAttr( RES_UL_SPACE )) );
4927 aULSpace.SetLower( aULSpace.GetLower() + (sal_uInt16)nSize );
4928 pTextNode->SetAttr( aULSpace );
4930 else
4932 NewAttr( &m_aAttrTab.pULSpace, SvxULSpaceItem( 0, (sal_uInt16)nSize, RES_UL_SPACE ) );
4933 EndAttr( m_aAttrTab.pULSpace, false );
4935 AppendTextNode(); // nicht am Abstand drehen!
4938 break;
4939 case HTML_SPTYPE_HORI:
4940 if( nSize > 0 )
4942 // wenn der Absatz noch leer ist, einen Erstzeilen-Einzug
4943 // setzen, sondern Sperrschrift ueber einem Space aufspannen
4945 if( nSize && Application::GetDefaultDevice() )
4947 nSize = Application::GetDefaultDevice()
4948 ->PixelToLogic( Size(nSize,0),
4949 MapMode(MapUnit::MapTwip) ).Width();
4952 if( !m_pPam->GetPoint()->nContent.GetIndex() )
4954 sal_uInt16 nLeft=0, nRight=0;
4955 short nIndent = 0;
4957 GetMarginsFromContextWithNumBul( nLeft, nRight, nIndent );
4958 nIndent = nIndent + (short)nSize;
4960 SvxLRSpaceItem aLRItem( RES_LR_SPACE );
4961 aLRItem.SetTextLeft( nLeft );
4962 aLRItem.SetRight( nRight );
4963 aLRItem.SetTextFirstLineOfst( nIndent );
4965 NewAttr( &m_aAttrTab.pLRSpace, aLRItem );
4966 EndAttr( m_aAttrTab.pLRSpace, false );
4968 else
4970 NewAttr( &m_aAttrTab.pKerning, SvxKerningItem( (short)nSize, RES_CHRATR_KERNING ) );
4971 OUString aTmp( ' ' );
4972 m_pDoc->getIDocumentContentOperations().InsertString( *m_pPam, aTmp );
4973 EndAttr( m_aAttrTab.pKerning );
4979 sal_uInt16 SwHTMLParser::ToTwips( sal_uInt16 nPixel )
4981 if( nPixel && Application::GetDefaultDevice() )
4983 long nTwips = Application::GetDefaultDevice()->PixelToLogic(
4984 Size( nPixel, nPixel ), MapMode( MapUnit::MapTwip ) ).Width();
4985 return nTwips <= USHRT_MAX ? (sal_uInt16)nTwips : USHRT_MAX;
4987 else
4988 return nPixel;
4991 SwTwips SwHTMLParser::GetCurrentBrowseWidth()
4993 const SwTwips nWidth = SwHTMLTableLayout::GetBrowseWidth( *m_pDoc );
4994 if( nWidth )
4995 return nWidth;
4997 if( !m_aHTMLPageSize.Width() )
4999 const SwFrameFormat& rPgFormat = m_pCSS1Parser->GetMasterPageDesc()->GetMaster();
5001 const SwFormatFrameSize& rSz = rPgFormat.GetFrameSize();
5002 const SvxLRSpaceItem& rLR = rPgFormat.GetLRSpace();
5003 const SvxULSpaceItem& rUL = rPgFormat.GetULSpace();
5004 const SwFormatCol& rCol = rPgFormat.GetCol();
5006 m_aHTMLPageSize.Width() = rSz.GetWidth() - rLR.GetLeft() - rLR.GetRight();
5007 m_aHTMLPageSize.Height() = rSz.GetHeight() - rUL.GetUpper() - rUL.GetLower();
5009 if( 1 < rCol.GetNumCols() )
5010 m_aHTMLPageSize.Width() /= rCol.GetNumCols();
5013 return m_aHTMLPageSize.Width();
5016 void SwHTMLParser::InsertIDOption()
5018 OUString aId;
5019 const HTMLOptions& rHTMLOptions = GetOptions();
5020 for (size_t i = rHTMLOptions.size(); i; )
5022 const HTMLOption& rOption = rHTMLOptions[--i];
5023 if( HTML_O_ID==rOption.GetToken() )
5025 aId = rOption.GetString();
5026 break;
5030 if( !aId.isEmpty() )
5031 InsertBookmark( aId );
5034 void SwHTMLParser::InsertLineBreak()
5036 // <BR CLEAR=xxx> wird wie folgt behandelt:
5037 // 1.) Es werden nur nur absatzgebundene Rahmen betrachtet, die
5038 // im aktuellen Absatz verankert sind.
5039 // 2.) Fuer linksbuendig ausgerichtete Rahmen wird bei CLEAR=LEFT
5040 // oder ALL und auf rechtsbuendige ausgerichtete Rahmen bei
5041 // CLEAR=RIGHT oder ALL der Durchlauf wie folgt geaendert:
5042 // 3.) Wenn der Absatz keinen Text enthaelt, bekommt der Rahmen keinen
5043 // Umlauf
5044 // 4.) sonst erhaelt ein links ausgerichteter Rahmen eine rechten
5045 // "nur Anker" Umlauf und recht rechst ausg. Rahmen einen linken
5046 // "nur Anker" Umlauf.
5047 // 5.) wenn in einem nicht-leeren Absatz der Umlauf eines Rahmens
5048 // geaendert wird, wird ein neuer Absatz aufgemacht
5049 // 6.) Wenn von keinem Rahmen der Umlauf geaendert wird, wird ein
5050 // harter Zeilenumbruch eingefuegt
5052 OUString aId, aStyle, aClass; // die ID der Bookmark
5053 bool bClearLeft = false, bClearRight = false;
5054 bool bCleared = false; // wurde ein CLEAR ausgefuehrt?
5056 // dann holen wir mal die Optionen
5057 const HTMLOptions& rHTMLOptions = GetOptions();
5058 for (size_t i = rHTMLOptions.size(); i; )
5060 const HTMLOption& rOption = rHTMLOptions[--i];
5061 switch( rOption.GetToken() )
5063 case HTML_O_CLEAR:
5065 const OUString &rClear = rOption.GetString();
5066 if( rClear.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_AL_all ) )
5068 bClearLeft = true;
5069 bClearRight = true;
5071 else if( rClear.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_AL_left ) )
5072 bClearLeft = true;
5073 else if( rClear.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_AL_right ) )
5074 bClearRight = true;
5076 break;
5077 case HTML_O_ID:
5078 aId = rOption.GetString();
5079 break;
5080 case HTML_O_STYLE:
5081 aStyle = rOption.GetString();
5082 break;
5083 case HTML_O_CLASS:
5084 aClass = rOption.GetString();
5085 break;
5089 // CLEAR wird nur fuer den aktuellen Absaetz unterstuetzt
5090 if( bClearLeft || bClearRight )
5092 SwNodeIndex& rNodeIdx = m_pPam->GetPoint()->nNode;
5093 SwTextNode* pTextNd = rNodeIdx.GetNode().GetTextNode();
5094 if( pTextNd )
5096 const SwFrameFormats& rFrameFormatTable = *m_pDoc->GetSpzFrameFormats();
5098 for( size_t i=0; i<rFrameFormatTable.size(); i++ )
5100 SwFrameFormat *const pFormat = rFrameFormatTable[i];
5101 SwFormatAnchor const*const pAnchor = &pFormat->GetAnchor();
5102 SwPosition const*const pAPos = pAnchor->GetContentAnchor();
5103 if (pAPos &&
5104 ((FLY_AT_PARA == pAnchor->GetAnchorId()) ||
5105 (FLY_AT_CHAR == pAnchor->GetAnchorId())) &&
5106 pAPos->nNode == rNodeIdx &&
5107 pFormat->GetSurround().GetSurround() != SURROUND_NONE )
5109 sal_Int16 eHori = RES_DRAWFRMFMT == pFormat->Which()
5110 ? text::HoriOrientation::LEFT
5111 : pFormat->GetHoriOrient().GetHoriOrient();
5113 SwSurround eSurround = SURROUND_PARALLEL;
5114 if( m_pPam->GetPoint()->nContent.GetIndex() )
5116 if( bClearLeft && text::HoriOrientation::LEFT==eHori )
5117 eSurround = SURROUND_RIGHT;
5118 else if( bClearRight && text::HoriOrientation::RIGHT==eHori )
5119 eSurround = SURROUND_LEFT;
5121 else if( (bClearLeft && text::HoriOrientation::LEFT==eHori) ||
5122 (bClearRight && text::HoriOrientation::RIGHT==eHori) )
5124 eSurround = SURROUND_NONE;
5127 if( SURROUND_PARALLEL != eSurround )
5129 SwFormatSurround aSurround( eSurround );
5130 if( SURROUND_NONE != eSurround )
5131 aSurround.SetAnchorOnly( true );
5132 pFormat->SetFormatAttr( aSurround );
5133 bCleared = true;
5135 } // Anker ist nicht im Node
5136 } // Schleife ueber Fly-Frames
5137 } // kein Text-Node
5138 } // kein CLEAR
5140 // Styles parsen
5141 SvxFormatBreakItem aBreakItem( SvxBreak::NONE, RES_BREAK );
5142 bool bBreakItem = false;
5143 if( HasStyleOptions( aStyle, aId, aClass ) )
5145 SfxItemSet aItemSet( m_pDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
5146 SvxCSS1PropertyInfo aPropInfo;
5148 if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo ) )
5150 if( m_pCSS1Parser->SetFormatBreak( aItemSet, aPropInfo ) )
5152 aBreakItem = static_cast<const SvxFormatBreakItem &>(aItemSet.Get( RES_BREAK ));
5153 bBreakItem = true;
5155 if( !aPropInfo.m_aId.isEmpty() )
5156 InsertBookmark( aPropInfo.m_aId );
5160 if( bBreakItem && SvxBreak::PageAfter==aBreakItem.GetBreak() )
5162 NewAttr( &m_aAttrTab.pBreak, aBreakItem );
5163 EndAttr( m_aAttrTab.pBreak, false );
5166 if( !bCleared && !bBreakItem )
5168 // wenn kein CLEAR ausgefuehrt werden sollte oder konnte, wird
5169 // ein Zeilenumbruch eingef?gt
5170 OUString sTmp( (sal_Unicode)0x0a ); // make the Mac happy :-)
5171 m_pDoc->getIDocumentContentOperations().InsertString( *m_pPam, sTmp );
5173 else if( m_pPam->GetPoint()->nContent.GetIndex() )
5175 // wenn ein clear in einem nicht-leeren Absatz ausgefuehrt wurde,
5176 // muss anschliessen ein neuer Absatz aufgemacht werden
5177 // MIB 21.02.97: Eigentlich muesste man hier den unteren Absatz-
5178 // Absatnd auf 0 drehen. Das geht aber bei sowas wie <BR ..><P>
5179 // schief (>Netscape). Deshalb lassen wir das erstmal.
5180 AppendTextNode( AM_NOSPACE );
5182 if( bBreakItem && SvxBreak::PageBefore==aBreakItem.GetBreak() )
5184 NewAttr( &m_aAttrTab.pBreak, aBreakItem );
5185 EndAttr( m_aAttrTab.pBreak, false );
5189 void SwHTMLParser::InsertHorzRule()
5191 sal_uInt16 nSize = 0;
5192 sal_uInt16 nWidth = 0;
5194 SvxAdjust eAdjust = SVX_ADJUST_END;
5196 bool bPrcWidth = false;
5197 bool bNoShade = false;
5198 bool bColor = false;
5200 Color aColor;
5201 OUString aId;
5203 // dann holen wir mal die Optionen
5204 const HTMLOptions& rHTMLOptions = GetOptions();
5205 for (size_t i = rHTMLOptions.size(); i; )
5207 const HTMLOption& rOption = rHTMLOptions[--i];
5208 switch( rOption.GetToken() )
5210 case HTML_O_ID:
5211 aId = rOption.GetString();
5212 break;
5213 case HTML_O_SIZE:
5214 nSize = (sal_uInt16)rOption.GetNumber();
5215 break;
5216 case HTML_O_WIDTH:
5217 bPrcWidth = (rOption.GetString().indexOf('%') != -1);
5218 nWidth = (sal_uInt16)rOption.GetNumber();
5219 if( bPrcWidth && nWidth>=100 )
5221 // 100%-Linien sind der default-Fall (keine Attrs neotig)
5222 nWidth = 0;
5223 bPrcWidth = false;
5225 break;
5226 case HTML_O_ALIGN:
5227 eAdjust =
5228 (SvxAdjust)rOption.GetEnum( aHTMLPAlignTable, static_cast< sal_uInt16 >(eAdjust) );
5229 break;
5230 case HTML_O_NOSHADE:
5231 bNoShade = true;
5232 break;
5233 case HTML_O_COLOR:
5234 rOption.GetColor( aColor );
5235 bColor = true;
5236 break;
5240 if( m_pPam->GetPoint()->nContent.GetIndex() )
5241 AppendTextNode( AM_NOSPACE );
5242 if( m_nOpenParaToken )
5243 EndPara();
5244 AppendTextNode();
5245 m_pPam->Move( fnMoveBackward );
5247 // ... und in einem Kontext merken
5248 HTMLAttrContext *pCntxt =
5249 new HTMLAttrContext( HTML_HORZRULE, RES_POOLCOLL_HTML_HR, aEmptyOUStr );
5251 PushContext( pCntxt );
5253 // die neue Vorlage setzen
5254 SetTextCollAttrs( pCntxt );
5256 // die harten Attribute an diesem Absatz werden nie mehr ungueltig
5257 if( !m_aParaAttrs.empty() )
5258 m_aParaAttrs.clear();
5260 if( nSize>0 || bColor || bNoShade )
5262 // Farbe und/oder Breite der Linie setzen
5263 if( !bColor )
5264 aColor.SetColor( COL_GRAY );
5266 SvxBorderLine aBorderLine( &aColor );
5267 if( nSize )
5269 long nPWidth = 0;
5270 long nPHeight = (long)nSize;
5271 SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight );
5272 if ( !bNoShade )
5274 aBorderLine.SetBorderLineStyle(table::BorderLineStyle::DOUBLE);
5276 aBorderLine.SetWidth( nPHeight );
5278 else if( bNoShade )
5280 aBorderLine.SetWidth( DEF_LINE_WIDTH_2 );
5282 else
5284 aBorderLine.SetBorderLineStyle(table::BorderLineStyle::DOUBLE);
5285 aBorderLine.SetWidth( DEF_LINE_WIDTH_0 );
5288 SvxBoxItem aBoxItem(RES_BOX);
5289 aBoxItem.SetLine( &aBorderLine, SvxBoxItemLine::BOTTOM );
5290 HTMLAttr* pTmp = new HTMLAttr( *m_pPam->GetPoint(), aBoxItem );
5291 m_aSetAttrTab.push_back( pTmp );
5293 if( nWidth )
5295 // Wenn wir in keiner Tabelle sind, wird die Breitenangabe durch
5296 // Absatz-Einzuege "getuerkt". In einer Tabelle macht das wenig
5297 // Sinn. Um zu Vermeiden, dass die Linie bei der Breitenberechnung
5298 // beruecksichtigt wird, bekommt sie aber trotzdem entsprechendes
5299 // LRSpace-Item verpasst.
5300 if( !m_pTable )
5302 // Laenge und Ausrichtung der Linie ueber Absatz-Einzuege "tuerken"
5303 long nBrowseWidth = GetCurrentBrowseWidth();
5304 nWidth = bPrcWidth ? (sal_uInt16)((nWidth*nBrowseWidth) / 100)
5305 : ToTwips( (sal_uInt16)nBrowseWidth );
5306 if( nWidth < MINLAY )
5307 nWidth = MINLAY;
5309 if( (long)nWidth < nBrowseWidth )
5311 const SwFormatColl *pColl = GetCurrFormatColl();
5312 SvxLRSpaceItem aLRItem( pColl->GetLRSpace() );
5313 long nDist = nBrowseWidth - nWidth;
5315 switch( eAdjust )
5317 case SVX_ADJUST_RIGHT:
5318 aLRItem.SetTextLeft( (sal_uInt16)nDist );
5319 break;
5320 case SVX_ADJUST_LEFT:
5321 aLRItem.SetRight( (sal_uInt16)nDist );
5322 break;
5323 case SVX_ADJUST_CENTER:
5324 default:
5325 nDist /= 2;
5326 aLRItem.SetTextLeft( (sal_uInt16)nDist );
5327 aLRItem.SetRight( (sal_uInt16)nDist );
5328 break;
5331 HTMLAttr* pTmp = new HTMLAttr( *m_pPam->GetPoint(), aLRItem );
5332 m_aSetAttrTab.push_back( pTmp );
5337 // Bookmarks koennen nicht in Hyperlinks eingefueht werden
5338 if( !aId.isEmpty() )
5339 InsertBookmark( aId );
5341 // den aktuellen Kontext vom Stack holen
5342 HTMLAttrContext *pPoppedContext = PopContext( HTML_HORZRULE );
5343 OSL_ENSURE( pPoppedContext==pCntxt, "wo kommt denn da ein HR-Kontext her?" );
5344 delete pPoppedContext;
5346 m_pPam->Move( fnMoveForward );
5348 // und im Absatz danach die dort aktuelle Vorlage setzen
5349 SetTextCollAttrs();
5352 void SwHTMLParser::ParseMoreMetaOptions()
5354 OUString aName, aContent;
5355 bool bHTTPEquiv = false;
5357 const HTMLOptions& rHTMLOptions = GetOptions();
5358 for (size_t i = rHTMLOptions.size(); i; )
5360 const HTMLOption& rOption = rHTMLOptions[--i];
5361 switch( rOption.GetToken() )
5363 case HTML_O_NAME:
5364 aName = rOption.GetString();
5365 bHTTPEquiv = false;
5366 break;
5367 case HTML_O_HTTPEQUIV:
5368 aName = rOption.GetString();
5369 bHTTPEquiv = true;
5370 break;
5371 case HTML_O_CONTENT:
5372 aContent = rOption.GetString();
5373 break;
5377 // Hier wird es etwas tricky: Wir wissen genau, da? die Dok-Info
5378 // nicht geaendert wurde. Deshalb genuegt es, auf Generator und
5379 // auf refresh abzufragen, um noch nicht verarbeitete Token zu finden,
5380 // denn das sind die einzigen, die die Dok-Info nicht modifizieren.
5381 if( aName.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_META_generator ) ||
5382 aName.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_META_refresh ) ||
5383 aName.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_META_content_type ) ||
5384 aName.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_META_content_script_type ) )
5385 return;
5387 aContent = aContent.replaceAll("\r", "").replaceAll("\n", "");
5389 if( aName.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_META_sdendnote ) )
5391 FillEndNoteInfo( aContent );
5392 return;
5395 if( aName.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_META_sdfootnote ) )
5397 FillFootNoteInfo( aContent );
5398 return;
5401 OUStringBuffer sText;
5402 sText.append("HTML: <");
5403 sText.append(OOO_STRING_SVTOOLS_HTML_meta);
5404 sText.append(' ');
5405 if( bHTTPEquiv )
5406 sText.append(OOO_STRING_SVTOOLS_HTML_O_httpequiv);
5407 else
5408 sText.append(OOO_STRING_SVTOOLS_HTML_O_name);
5409 sText.append("=\"");
5410 sText.append(aName);
5411 sText.append("\" ");
5412 sText.append(OOO_STRING_SVTOOLS_HTML_O_content);
5413 sText.append("=\"");
5414 sText.append(aContent);
5415 sText.append("\">");
5417 SwPostItField aPostItField(
5418 static_cast<SwPostItFieldType*>(m_pDoc->getIDocumentFieldsAccess().GetSysFieldType( RES_POSTITFLD )),
5419 aEmptyOUStr, sText.makeStringAndClear(), aEmptyOUStr, aEmptyOUStr, DateTime( DateTime::SYSTEM ) );
5420 SwFormatField aFormatField( aPostItField );
5421 InsertAttr( aFormatField, false );
5424 HTMLAttr::HTMLAttr( const SwPosition& rPos, const SfxPoolItem& rItem,
5425 HTMLAttr **ppHd ) :
5426 nSttPara( rPos.nNode ),
5427 nEndPara( rPos.nNode ),
5428 nSttContent( rPos.nContent.GetIndex() ),
5429 nEndContent(rPos.nContent.GetIndex() ),
5430 bInsAtStart( true ),
5431 bLikePara( false ),
5432 bValid( true ),
5433 pNext( nullptr ),
5434 pPrev( nullptr ),
5435 ppHead( ppHd )
5437 pItem = rItem.Clone();
5440 HTMLAttr::HTMLAttr( const HTMLAttr &rAttr, const SwNodeIndex &rEndPara,
5441 sal_Int32 nEndCnt, HTMLAttr **ppHd ) :
5442 nSttPara( rAttr.nSttPara ),
5443 nEndPara( rEndPara ),
5444 nSttContent( rAttr.nSttContent ),
5445 nEndContent( nEndCnt ),
5446 bInsAtStart( rAttr.bInsAtStart ),
5447 bLikePara( rAttr.bLikePara ),
5448 bValid( rAttr.bValid ),
5449 pNext( nullptr ),
5450 pPrev( nullptr ),
5451 ppHead( ppHd )
5453 pItem = rAttr.pItem->Clone();
5456 HTMLAttr::~HTMLAttr()
5458 delete pItem;
5461 HTMLAttr *HTMLAttr::Clone(const SwNodeIndex& rEndPara, sal_Int32 nEndCnt) const
5463 // das Attribut mit der alten Start-Position neu anlegen
5464 HTMLAttr *pNew = new HTMLAttr( *this, rEndPara, nEndCnt, ppHead );
5466 // die Previous-Liste muss uebernommen werden, die Next-Liste nicht!
5467 pNew->pPrev = pPrev;
5469 return pNew;
5472 void HTMLAttr::Reset(const SwNodeIndex& rSttPara, sal_Int32 nSttCnt,
5473 HTMLAttr **ppHd)
5475 // den Anfang (und das Ende) neu setzen
5476 nSttPara = rSttPara;
5477 nSttContent = nSttCnt;
5478 nEndPara = rSttPara;
5479 nEndContent = nSttCnt;
5481 // den Head korrigieren und die Verkettungen aufheben
5482 pNext = nullptr;
5483 pPrev = nullptr;
5484 ppHead = ppHd;
5487 void HTMLAttr::InsertPrev( HTMLAttr *pPrv )
5489 OSL_ENSURE( !pPrv->pNext || pPrv->pNext == this,
5490 "HTMLAttr::InsertPrev: pNext falsch" );
5491 pPrv->pNext = nullptr;
5493 OSL_ENSURE( nullptr == pPrv->ppHead || ppHead == pPrv->ppHead,
5494 "HTMLAttr::InsertPrev: ppHead falsch" );
5495 pPrv->ppHead = nullptr;
5497 HTMLAttr *pAttr = this;
5498 while( pAttr->GetPrev() )
5499 pAttr = pAttr->GetPrev();
5501 pAttr->pPrev = pPrv;
5504 bool SwHTMLParser::ParseMetaOptions(
5505 const uno::Reference<document::XDocumentProperties> & i_xDocProps,
5506 SvKeyValueIterator *i_pHeader )
5508 // always call base ParseMetaOptions, it sets the encoding (#i96700#)
5509 bool ret( HTMLParser::ParseMetaOptions(i_xDocProps, i_pHeader) );
5510 if (!ret && IsNewDoc())
5512 ParseMoreMetaOptions();
5514 return ret;
5517 // override so we can parse DOCINFO field subtypes INFO[1-4]
5518 void SwHTMLParser::AddMetaUserDefined( OUString const & i_rMetaName )
5520 // unless we already have 4 names, append the argument to m_InfoNames
5521 OUString* pName // the first empty string in m_InfoNames
5522 (m_InfoNames[0].isEmpty() ? &m_InfoNames[0] :
5523 (m_InfoNames[1].isEmpty() ? &m_InfoNames[1] :
5524 (m_InfoNames[2].isEmpty() ? &m_InfoNames[2] :
5525 (m_InfoNames[3].isEmpty() ? &m_InfoNames[3] : nullptr ))));
5526 if (pName)
5528 (*pName) = i_rMetaName;
5532 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */