diff options
Diffstat (limited to 'sw/source/filter/html/swhtml.cxx')
-rw-r--r-- | sw/source/filter/html/swhtml.cxx | 5529 |
1 files changed, 5529 insertions, 0 deletions
diff --git a/sw/source/filter/html/swhtml.cxx b/sw/source/filter/html/swhtml.cxx new file mode 100644 index 000000000000..551ebf937be2 --- /dev/null +++ b/sw/source/filter/html/swhtml.cxx @@ -0,0 +1,5529 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: swhtml.cxx,v $ + * $Revision: 1.51.98.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> +#include <com/sun/star/document/XDocumentProperties.hpp> +#include <com/sun/star/i18n/ScriptType.hpp> + +#ifndef PRODUCT +#include <stdlib.h> +#endif +#include <hintids.hxx> + +#define _SVSTDARR_STRINGS +#include <svtools/svstdarr.hxx> +#include <svtools/stritem.hxx> +#include <svtools/imap.hxx> +#include <svtools/htmltokn.h> +#include <svtools/htmlkywd.hxx> +#include <svtools/ctrltool.hxx> +#include <svtools/pathoptions.hxx> +#include <vcl/svapp.hxx> +#include <vcl/wrkwin.hxx> +#include <sfx2/fcontnr.hxx> +#include <sfx2/docfile.hxx> + +#include <svx/htmlcfg.hxx> +#include <svx/linkmgr.hxx> +#include <svx/kernitem.hxx> +#include <svx/boxitem.hxx> +#include <svx/fhgtitem.hxx> +#include <svx/brkitem.hxx> +#include <svx/postitem.hxx> +#include <svx/wghtitem.hxx> +#include <svx/crsditem.hxx> +#include <svx/udlnitem.hxx> +#include <svx/escpitem.hxx> +#include <svx/blnkitem.hxx> +#include <svx/ulspitem.hxx> +#include <svx/colritem.hxx> +#include <svx/fontitem.hxx> +#include <svx/adjitem.hxx> +#include <svx/lrspitem.hxx> +#include <svx/protitem.hxx> +#include <svx/flstitem.hxx> + + +#include <frmatr.hxx> +#include <charatr.hxx> +#include <fmtfld.hxx> +#include <fmtpdsc.hxx> +#include <txtfld.hxx> +#include <fmtanchr.hxx> +#include <fmtsrnd.hxx> +#include <fmtfsize.hxx> +#include <fmtclds.hxx> +#include <fchrfmt.hxx> +#include <fmtinfmt.hxx> +#include <docary.hxx> +#include <docstat.hxx> +#include <doc.hxx> +#include <pam.hxx> +#include <ndtxt.hxx> +#include <mdiexp.hxx> // ...Percent() +#include <expfld.hxx> +#include <poolfmt.hxx> +#include <pagedesc.hxx> +#include <IMark.hxx> // fuer SwBookmark ... +#include <docsh.hxx> +#include <editsh.hxx> // fuer Start/EndAction +#include <docufld.hxx> +#include <swcss1.hxx> +#include <htmlvsh.hxx> +#include <fltini.hxx> +#include <htmltbl.hxx> +#include <htmlnum.hxx> +#include <swhtml.hxx> +#include <linkenum.hxx> +#include <breakit.hxx> +#include <SwAppletImpl.hxx> + +#include <sfx2/viewfrm.hxx> + +#ifndef _STATSTR_HRC +#include <statstr.hrc> // ResId fuer Statusleiste +#endif +#include <swerror.h> + +#define FONTSIZE_MASK 7 +#define FONTCOLOR_MASK (1<<15) +#define FONT_MASK (1<<14) + +#define HTML_ESC_PROP 80 +#define HTML_ESC_SUPER DFLT_ESC_SUPER +#define HTML_ESC_SUB DFLT_ESC_SUB + +#define HTML_SPTYPE_NONE 0 +#define HTML_SPTYPE_BLOCK 1 +#define HTML_SPTYPE_HORI 2 +#define HTML_SPTYPE_VERT 3 + +#ifndef TOOLS_CONSTASCII_STRINGPARAM +#define TOOLS_CONSTASCII_STRINGPARAM( constAsciiStr ) constAsciiStr, sizeof( constAsciiStr )-1 +#endif + +using namespace ::com::sun::star; + +// <P ALIGN=xxx>, <Hn ALIGN=xxx>, <TD ALIGN=xxx> usw. +HTMLOptionEnum __FAR_DATA aHTMLPAlignTable[] = +{ + { OOO_STRING_SVTOOLS_HTML_AL_left, SVX_ADJUST_LEFT }, + { OOO_STRING_SVTOOLS_HTML_AL_center, SVX_ADJUST_CENTER }, + { OOO_STRING_SVTOOLS_HTML_AL_middle, SVX_ADJUST_CENTER }, // Netscape + { OOO_STRING_SVTOOLS_HTML_AL_right, SVX_ADJUST_RIGHT }, + { OOO_STRING_SVTOOLS_HTML_AL_justify, SVX_ADJUST_BLOCK }, + { OOO_STRING_SVTOOLS_HTML_AL_char, SVX_ADJUST_LEFT }, + { 0, 0 } +}; + +// <SPACER TYPE=...> +static HTMLOptionEnum __FAR_DATA aHTMLSpacerTypeTable[] = +{ + { OOO_STRING_SVTOOLS_HTML_SPTYPE_block, HTML_SPTYPE_BLOCK }, + { OOO_STRING_SVTOOLS_HTML_SPTYPE_horizontal, HTML_SPTYPE_HORI }, + { OOO_STRING_SVTOOLS_HTML_SPTYPE_vertical, HTML_SPTYPE_VERT }, + { 0, 0 } +}; + +SV_IMPL_PTRARR( _HTMLAttrs, _HTMLAttrPtr ) + +HTMLReader::HTMLReader() +{ + bTmplBrowseMode = TRUE; +} + +String HTMLReader::GetTemplateName() const +{ + String sTemplate( + String::CreateFromAscii(TOOLS_CONSTASCII_STRINGPARAM("internal")) ); + sTemplate += INET_PATH_TOKEN; + sTemplate.AppendAscii( TOOLS_CONSTASCII_STRINGPARAM("html") ); + String sTemplateWithoutExt( sTemplate ); +#ifndef MAC_WITHOUT_EXT + // --> OD 2005-01-26 - first search for OpenDocument Writer/Web template + sTemplate.AppendAscii( TOOLS_CONSTASCII_STRINGPARAM(".oth") ); + // <-- +#endif + + SvtPathOptions aPathOpt; + // OpenDocument Writer/Web template (extension .oth) + BOOL bSet = aPathOpt.SearchFile( sTemplate, SvtPathOptions::PATH_TEMPLATE ); + +#ifndef MAC_WITHOUT_EXT + if( !bSet ) + { + // 6.0 (extension .stw) + sTemplate = sTemplateWithoutExt; + // --> OD 2005-01-26 - no OpenDocument Writer/Web template found. + // search for OpenOffice.org Writer/Web template + sTemplate.AppendAscii( TOOLS_CONSTASCII_STRINGPARAM(".stw") ); + // <-- + bSet = aPathOpt.SearchFile( sTemplate, SvtPathOptions::PATH_TEMPLATE ); + } +#endif + + if( !bSet ) + { + sTemplate.Erase(); + ASSERT( !this, + "Die html.vor befindet sich nicht mehr im definierten Directory!"); + } + + return sTemplate; +} + +int HTMLReader::SetStrmStgPtr() +{ + ASSERT( pMedium, "Wo ist das Medium??" ); + + if( pMedium->IsRemote() || !pMedium->IsStorage() ) + { + pStrm = pMedium->GetInStream(); + return TRUE; + } + return FALSE; + +} + + // Aufruf fuer die allg. Reader-Schnittstelle +ULONG HTMLReader::Read( SwDoc &rDoc, const String& rBaseURL, SwPaM &rPam, const String & rName ) +{ + if( !pStrm ) + { + ASSERT( pStrm, "HTML-Read ohne Stream" ); + return ERR_SWG_READ_ERROR; + } + + if( !bInsertMode ) + { + Reader::SetNoOutlineNum( rDoc ); + Reader::ResetFrmFmts( rDoc ); + + // Die HTML-Seitenvorlage setzen, wenn des kein HTML-Dokument ist, + // sonst ist sie schon gesetzt. + if( !rDoc.get(IDocumentSettingAccess::HTML_MODE) ) + { + rDoc.InsertPoolItem( rPam, SwFmtPageDesc( + rDoc.GetPageDescFromPool( RES_POOLPAGE_HTML, false )), 0 ); + } + } + + // damit keiner das Doc klaut! + rDoc.acquire(); + ULONG nRet = 0; + SvParserRef xParser = new SwHTMLParser( &rDoc, rPam, *pStrm, + rName, rBaseURL, !bInsertMode, pMedium, + IsReadUTF8(), + bIgnoreHTMLComments ); + + SvParserState eState = xParser->CallParser(); + + if( SVPAR_PENDING == eState ) + pStrm->ResetError(); + else if( SVPAR_ACCEPTED != eState ) + { + String sErr( String::CreateFromInt32((sal_Int32)xParser->GetLineNr())); + sErr += ','; + sErr += String::CreateFromInt32((sal_Int32)xParser->GetLinePos()); + + // den Stream als Fehlernummer Transporter benutzen + nRet = *new StringErrorInfo( ERR_FORMAT_ROWCOL, sErr, + ERRCODE_BUTTON_OK | ERRCODE_MSG_ERROR ); + } + + + return nRet; +} + + +/* */ + +SwHTMLParser::SwHTMLParser( SwDoc* pD, const SwPaM& rCrsr, SvStream& rIn, + const String& rPath, + const String& rBaseURL, + int bReadNewDoc, + SfxMedium* pMed, BOOL bReadUTF8, + sal_Bool bNoHTMLComments ) + : SfxHTMLParser( rIn, static_cast< BOOL >(bReadNewDoc), pMed ), + SwClient( 0 ), + aPathToFile( rPath ), + sBaseURL( rBaseURL ), + pAppletImpl( 0 ), + pCSS1Parser( 0 ), + pNumRuleInfo( new SwHTMLNumRuleInfo ), + pPendStack( 0 ), + pDoc( pD ), + pActionViewShell( 0 ), + pSttNdIdx( 0 ), + pTable(0), + pFormImpl( 0 ), + pMarquee( 0 ), + pField( 0 ), + pImageMap( 0 ), + pImageMaps( 0 ), + pFootEndNoteImpl( 0 ), + nScriptStartLineNr( 0 ), + nBaseFontStMin( 0 ), + nFontStMin( 0 ), + nDefListDeep( 0 ), + nFontStHeadStart( 0 ), + nSBModuleCnt( 0 ), + nMissingImgMaps( 0 ), + nParaCnt( 5 ), + // --> OD 2007-10-26 #i83625# + nContextStMin( 0 ), + nContextStAttrMin( 0 ), + // <-- + nOpenParaToken( 0 ), + eJumpTo( JUMPTO_NONE ), +#ifndef PRODUCT + nContinue( 0 ), +#endif + eParaAdjust( SVX_ADJUST_END ), + bDocInitalized( FALSE ), + bSetModEnabled( FALSE ), + bInFloatingFrame( FALSE ), + bInField( FALSE ), + bCallNextToken( FALSE ), + bIgnoreRawData( FALSE ), + bNoParSpace( FALSE ), + bInNoEmbed( FALSE ), + bInTitle( FALSE ), + bUpdateDocStat( FALSE ), + bFixSelectWidth( FALSE ), + bFixSelectHeight( FALSE ), + bTextArea( FALSE ), + bSelect( FALSE ), + bInFootEndNoteAnchor( FALSE ), + bInFootEndNoteSymbol( FALSE ), +// bIgnoreHTMLComments( bNoHTMLComments ) + bIgnoreHTMLComments( bNoHTMLComments ), + bRemoveHidden( FALSE ), + pTempViewFrame(0) +{ + nEventId = 0; + bUpperSpace = bViewCreated = bChkJumpMark = + bSetCrsr = FALSE; + + eScriptLang = HTML_SL_UNKNOWN; + bAnyStarBasic = TRUE; + + pPam = new SwPaM( *rCrsr.GetPoint() ); + memset( &aAttrTab, 0, sizeof( _HTMLAttrTable )); + + // Die Font-Groessen 1-7 aus der INI-Datei lesen + SvxHtmlOptions* pHtmlOptions = SvxHtmlOptions::Get(); + aFontHeights[0] = pHtmlOptions->GetFontSize( 0 ) * 20; + aFontHeights[1] = pHtmlOptions->GetFontSize( 1 ) * 20; + aFontHeights[2] = pHtmlOptions->GetFontSize( 2 ) * 20; + aFontHeights[3] = pHtmlOptions->GetFontSize( 3 ) * 20; + aFontHeights[4] = pHtmlOptions->GetFontSize( 4 ) * 20; + aFontHeights[5] = pHtmlOptions->GetFontSize( 5 ) * 20; + aFontHeights[6] = pHtmlOptions->GetFontSize( 6 ) * 20; + + bKeepUnknown = pHtmlOptions->IsImportUnknown(); + + if(bReadNewDoc) + { + SvxFontHeightItem aFontHeight(aFontHeights[2], 100, RES_CHRATR_FONTSIZE); + pDoc->SetDefault( aFontHeight ); + aFontHeight.SetWhich( RES_CHRATR_CJK_FONTSIZE ); + pDoc->SetDefault( aFontHeight ); + aFontHeight.SetWhich( RES_CHRATR_CTL_FONTSIZE ); + pDoc->SetDefault( aFontHeight ); + } + + // Waehrend des Imports in den HTML-Modus schalten, damit die + // richrigen Vorlagen angelegt werden + bOldIsHTMLMode = pDoc->get(IDocumentSettingAccess::HTML_MODE); + pDoc->set(IDocumentSettingAccess::HTML_MODE, true); + + pCSS1Parser = new SwCSS1Parser( pDoc, aFontHeights, sBaseURL, IsNewDoc() ); + pCSS1Parser->SetIgnoreFontFamily( pHtmlOptions->IsIgnoreFontFamily() ); + + if( bReadUTF8 ) + { + SetSrcEncoding( RTL_TEXTENCODING_UTF8 ); + } + else + { + SwDocShell *pDocSh = pDoc->GetDocShell(); + SvKeyValueIterator *pHeaderAttrs = + pDocSh->GetHeaderAttributes(); + if( pHeaderAttrs ) + SetEncodingByHTTPHeader( pHeaderAttrs ); + } + pCSS1Parser->SetDfltEncoding( gsl_getSystemTextEncoding() ); + + // Timer nur bei ganz normalen Dokumenten aufsetzen! + SwDocShell* pDocSh = pDoc->GetDocShell(); + if( pDocSh ) + { + bViewCreated = TRUE; // nicht, synchron laden + + // es ist ein Sprungziel vorgegeben. + + if( pMed ) + { + sJmpMark = pMed->GetURLObject().GetMark(); + if( sJmpMark.Len() ) + { + eJumpTo = JUMPTO_MARK; + String sCmp; + xub_StrLen nLastPos, nPos = 0; + while( STRING_NOTFOUND != ( nLastPos = + sJmpMark.Search( cMarkSeperator, nPos + 1 )) ) + nPos = nLastPos; + + if( nPos && ( sCmp = sJmpMark.Copy( nPos + 1 ) ). + EraseAllChars().Len() ) + { + sCmp.ToLowerAscii(); + if( sCmp.EqualsAscii( pMarkToRegion ) ) + eJumpTo = JUMPTO_REGION; + else if( sCmp.EqualsAscii( pMarkToTable ) ) + eJumpTo = JUMPTO_TABLE; + else if( sCmp.EqualsAscii( pMarkToGraphic ) ) + eJumpTo = JUMPTO_GRAPHIC; + else if( sCmp.EqualsAscii( pMarkToOutline ) || + sCmp.EqualsAscii( pMarkToText ) || + sCmp.EqualsAscii( pMarkToFrame ) ) + eJumpTo = JUMPTO_NONE; // das ist nichts gueltiges! + else + // ansonsten ist das ein normaler (Book)Mark + nPos = STRING_LEN; + } + else + nPos = STRING_LEN; + + sJmpMark.Erase( nPos ); + if( !sJmpMark.Len() ) + eJumpTo = JUMPTO_NONE; + } + } + } +} + +__EXPORT SwHTMLParser::~SwHTMLParser() +{ +#ifndef PRODUCT + ASSERT( !nContinue, "DTOR im Continue - Das geht schief!!!" ); +#endif + BOOL bAsync = pDoc->IsInLoadAsynchron(); + pDoc->SetInLoadAsynchron( FALSE ); + pDoc->set(IDocumentSettingAccess::HTML_MODE, bOldIsHTMLMode); + + if( pDoc->GetDocShell() && nEventId ) + Application::RemoveUserEvent( nEventId ); + + // das DocumentDetected kann ggfs. die DocShells loeschen, darum nochmals + // abfragen + if( pDoc->GetDocShell() ) + { + // Gelinkte Bereiche updaten + USHORT nLinkMode = pDoc->getLinkUpdateMode( true ); + if( nLinkMode != NEVER && bAsync && + SFX_CREATE_MODE_INTERNAL!=pDoc->GetDocShell()->GetCreateMode() ) + pDoc->GetLinkManager().UpdateAllLinks( nLinkMode == MANUAL, + TRUE, FALSE ); + + if ( pDoc->GetDocShell()->IsLoading() ) + { + // --> OD 2006-11-07 #i59688# + pDoc->GetDocShell()->LoadingFinished(); + } + } + + delete pSttNdIdx; + + if( aSetAttrTab.Count() ) + { + ASSERT( !aSetAttrTab.Count(),"Es stehen noch Attribute auf dem Stack" ); + aSetAttrTab.DeleteAndDestroy( 0, aSetAttrTab.Count() ); + } + + delete pPam; + delete pCSS1Parser; + delete pNumRuleInfo; + DeleteFormImpl(); + DeleteFootEndNoteImpl(); + + ASSERT( !pTable, "Es existiert noch eine offene Tabelle" ); + delete pImageMaps; + //delete pTable; + + ASSERT( !pPendStack, + "SwHTMLParser::~SwHTMLParser: Hier sollte es keinen Pending-Stack mehr geben" ); + while( pPendStack ) + { + SwPendingStack* pTmp = pPendStack; + pPendStack = pPendStack->pNext; + delete pTmp->pData; + delete pTmp; + } + + if( !pDoc->release() ) + { + // keiner will mehr das Doc haben, also weg damit + delete pDoc; + pDoc = NULL; + } + + if ( pTempViewFrame ) + { + pTempViewFrame->DoClose(); + + // the temporary view frame is hidden, so the hidden flag might need to be removed + if ( bRemoveHidden && pDoc && pDoc->GetDocShell() && pDoc->GetDocShell()->GetMedium() ) + pDoc->GetDocShell()->GetMedium()->GetItemSet()->ClearItem( SID_HIDDEN ); + } +} + +IMPL_LINK( SwHTMLParser, AsyncCallback, void*, /*pVoid*/ ) +{ + nEventId=0; + + // --> FME 2005-08-18 #i47907# If the document has already been destructed, + // the parser should be aware of this: + if( ( pDoc->GetDocShell() && pDoc->GetDocShell()->IsAbortingImport() ) + || 1 == pDoc->getReferenceCount() ) + { + // wurde der Import vom SFX abgebrochen? + eState = SVPAR_ERROR; + } + // <-- + + GetAsynchCallLink().Call(0); + return 0; +} + +SvParserState __EXPORT SwHTMLParser::CallParser() +{ + // einen temporaeren Index anlegen, auf Pos 0 so wird er nicht bewegt! + pSttNdIdx = new SwNodeIndex( pDoc->GetNodes() ); + if( !IsNewDoc() ) // in ein Dokument einfuegen ? + { + const SwPosition* pPos = pPam->GetPoint(); + + pDoc->SplitNode( *pPos, false ); + + *pSttNdIdx = pPos->nNode.GetIndex()-1; + pDoc->SplitNode( *pPos, false ); + + SwPaM aInsertionRangePam( *pPos ); + + pPam->Move( fnMoveBackward ); + + // #106634# split any redline over the insertion point + aInsertionRangePam.SetMark(); + *aInsertionRangePam.GetPoint() = *pPam->GetPoint(); + aInsertionRangePam.Move( fnMoveBackward ); + pDoc->SplitRedline( aInsertionRangePam ); + + pDoc->SetTxtFmtColl( *pPam, + pCSS1Parser->GetTxtCollFromPool( RES_POOLCOLL_STANDARD )); + } + + if( GetMedium() ) + { + if( !bViewCreated ) + { + nEventId = Application::PostUserEvent( LINK( this, SwHTMLParser, AsyncCallback ), 0 ); + } + else + { + bViewCreated = TRUE; + nEventId = 0; + } + } + + // Laufbalken anzeigen + else if( !GetMedium() || !GetMedium()->IsRemote() ) + { + rInput.Seek(STREAM_SEEK_TO_END); + rInput.ResetError(); + ::StartProgress( STR_STATSTR_W4WREAD, 0, rInput.Tell(), + pDoc->GetDocShell() ); + rInput.Seek(STREAM_SEEK_TO_BEGIN); + rInput.ResetError(); + } + + SwPageDesc& rDesc = pDoc->_GetPageDesc( 0 ); + rDesc.Add( this ); + + SvParserState eRet = HTMLParser::CallParser(); + return eRet; +} + +void __EXPORT SwHTMLParser::Continue( int nToken ) +{ +#ifndef PRODUCT + ASSERT( !nContinue, "Continue im Continue - Das sollte doch nicht sein, oder?" ); + nContinue++; +#endif + + // Wenn der Import (vom SFX) abgebrochen wurde, wird ein Fehler + // gesetzt aber trotzdem noch weiter gemacht, damit vernuenftig + // aufgeraeumt wird. + ASSERT( SVPAR_ERROR!=eState, + "SwHTMLParser::Continue: bereits ein Fehler gesetzt" ); + if( pDoc->GetDocShell() && pDoc->GetDocShell()->IsAbortingImport() ) + eState = SVPAR_ERROR; + + // Die ViewShell vom Dokument holen, merken und als aktuelle setzen. + ViewShell *pInitVSh = CallStartAction(); + + if( SVPAR_ERROR != eState && GetMedium() && !bViewCreated ) + { + // Beim ersten Aufruf erstmal returnen, Doc anzeigen + // und auf Timer Callback warten. + // An dieser Stelle wurde im CallParser gerade mal ein Zeichen + // gelesen und ein SaveState(0) gerufen. + eState = SVPAR_PENDING; + bViewCreated = TRUE; + pDoc->SetInLoadAsynchron( TRUE ); + +#ifndef PRODUCT + nContinue--; +#endif + + return; + } + + bSetModEnabled = FALSE; + if( pDoc->GetDocShell() && + 0 != (bSetModEnabled = pDoc->GetDocShell()->IsEnableSetModified()) ) + { + pDoc->GetDocShell()->EnableSetModified( FALSE ); + } + + // waehrend des einlesens kein OLE-Modified rufen + Link aOLELink( pDoc->GetOle2Link() ); + pDoc->SetOle2Link( Link() ); + + BOOL bModified = pDoc->IsModified(); + BOOL bWasUndo = pDoc->DoesUndo(); + pDoc->DoUndo( FALSE ); + + // Wenn der Import abgebrochen wird, kein Continue mehr rufen. + // Falls ein Pending-Stack existiert aber durch einen Aufruf + // von NextToken dafuer sorgen, dass der Pending-Stack noch + // beendet wird. + if( SVPAR_ERROR == eState ) + { + ASSERT( !pPendStack || pPendStack->nToken, + "SwHTMLParser::Continue: Pending-Stack ohne Token" ); + if( pPendStack && pPendStack->nToken ) + NextToken( pPendStack->nToken ); + ASSERT( !pPendStack, + "SwHTMLParser::Continue: Es gibt wieder einen Pend-Stack" ); + } + else + { + HTMLParser::Continue( pPendStack ? pPendStack->nToken : nToken ); + } + + // Laufbalken wieder abschalten + EndProgress( pDoc->GetDocShell() ); + + BOOL bLFStripped = FALSE; + if( SVPAR_PENDING != GetStatus() ) + { + // noch die letzten Attribute setzen + { + if( aScriptSource.Len() ) + { + SwScriptFieldType *pType = + (SwScriptFieldType*)pDoc->GetSysFldType( RES_SCRIPTFLD ); + + SwScriptField aFld( pType, aScriptType, aScriptSource, + FALSE ); + InsertAttr( SwFmtFld( aFld ) ); + } + + if( pAppletImpl ) + { + if( pAppletImpl->GetApplet().is() ) + EndApplet(); + else + EndObject(); + } + + // ggf. ein noch vorhandes LF hinter dem letzen Absatz entfernen + if( IsNewDoc() ) + bLFStripped = StripTrailingLF() > 0; + + // noch offene Nummerierungen beenden. + while( GetNumInfo().GetNumRule() ) + EndNumBulList(); + + ASSERT( !nContextStMin, "Es gibt geschuetzte Kontexte" ); + nContextStMin = 0; + while( aContexts.Count() ) + { + _HTMLAttrContext *pCntxt = PopContext(); + if( pCntxt ) + { + EndContext( pCntxt ); + delete pCntxt; + } + } + + if( aParaAttrs.Count() ) + aParaAttrs.Remove( 0, aParaAttrs.Count() ); + + SetAttr( FALSE ); + + // Noch die erst verzoegert gesetzten Styles setzen + pCSS1Parser->SetDelayedStyles(); + } + + // den Start wieder korrigieren + if( !IsNewDoc() && pSttNdIdx->GetIndex() ) + { + SwTxtNode* pTxtNode = pSttNdIdx->GetNode().GetTxtNode(); + SwNodeIndex aNxtIdx( *pSttNdIdx ); + if( pTxtNode && pTxtNode->CanJoinNext( &aNxtIdx )) + { + xub_StrLen nStt = pTxtNode->GetTxt().Len(); + // wenn der Cursor noch in dem Node steht, dann setze in an das Ende + if( pPam->GetPoint()->nNode == aNxtIdx ) + { + pPam->GetPoint()->nNode = *pSttNdIdx; + pPam->GetPoint()->nContent.Assign( pTxtNode, nStt ); + } + +#ifndef PRODUCT +// !!! sollte nicht moeglich sein, oder ?? +ASSERT( pSttNdIdx->GetIndex()+1 != pPam->GetBound( TRUE ).nNode.GetIndex(), + "Pam.Bound1 steht noch im Node" ); +ASSERT( pSttNdIdx->GetIndex()+1 != pPam->GetBound( FALSE ).nNode.GetIndex(), + "Pam.Bound2 steht noch im Node" ); + +if( pSttNdIdx->GetIndex()+1 == pPam->GetBound( TRUE ).nNode.GetIndex() ) +{ + xub_StrLen nCntPos = pPam->GetBound( TRUE ).nContent.GetIndex(); + pPam->GetBound( TRUE ).nContent.Assign( pTxtNode, + pTxtNode->GetTxt().Len() + nCntPos ); +} +if( pSttNdIdx->GetIndex()+1 == pPam->GetBound( FALSE ).nNode.GetIndex() ) +{ + xub_StrLen nCntPos = pPam->GetBound( FALSE ).nContent.GetIndex(); + pPam->GetBound( FALSE ).nContent.Assign( pTxtNode, + pTxtNode->GetTxt().Len() + nCntPos ); +} +#endif + // Zeichen Attribute beibehalten! + SwTxtNode* pDelNd = aNxtIdx.GetNode().GetTxtNode(); + if( pTxtNode->GetTxt().Len() ) + pDelNd->FmtToTxtAttr( pTxtNode ); + else + pTxtNode->ChgFmtColl( pDelNd->GetTxtColl() ); + pTxtNode->JoinNext(); + } + } + } + + if( SVPAR_ACCEPTED == eState ) + { + if( nMissingImgMaps ) + { + // es fehlen noch ein paar Image-Map zuordungen. + // vielleicht sind die Image-Maps ja jetzt da? + ConnectImageMaps(); + } + + // jetzt noch den letzten ueberfluessigen Absatz loeschen + SwPosition* pPos = pPam->GetPoint(); + if( !pPos->nContent.GetIndex() && !bLFStripped ) + { + SwTxtNode* pAktNd; + ULONG nNodeIdx = pPos->nNode.GetIndex(); + + BOOL bHasFlysOrMarks = + HasCurrentParaFlys() || HasCurrentParaBookmarks( TRUE ); + + if( IsNewDoc() ) + { + const SwNode *pPrev = pDoc->GetNodes()[nNodeIdx -1]; + if( !pPam->GetPoint()->nContent.GetIndex() && + ( pPrev->IsCntntNode() || + (pPrev->IsEndNode() && + pPrev->StartOfSectionNode()->IsSectionNode()) ) ) + { + SwCntntNode* pCNd = pPam->GetCntntNode(); + if( pCNd && pCNd->StartOfSectionIndex()+2 < + pCNd->EndOfSectionIndex() && !bHasFlysOrMarks ) + { + ViewShell *pVSh = CheckActionViewShell(); + SwCrsrShell *pCrsrSh = pVSh && pVSh->ISA(SwCrsrShell) + ? static_cast < SwCrsrShell * >( pVSh ) + : 0; + if( pCrsrSh && + pCrsrSh->GetCrsr()->GetPoint() + ->nNode.GetIndex() == nNodeIdx ) + { + pCrsrSh->MovePara(fnParaPrev, fnParaEnd ); + pCrsrSh->SetMark(); + pCrsrSh->ClearMark(); + } + pPam->GetBound(TRUE).nContent.Assign( 0, 0 ); + pPam->GetBound(FALSE).nContent.Assign( 0, 0 ); + pDoc->GetNodes().Delete( pPam->GetPoint()->nNode ); + } + } + } + else if( 0 != ( pAktNd = pDoc->GetNodes()[ nNodeIdx ]->GetTxtNode()) && !bHasFlysOrMarks ) + { + if( pAktNd->CanJoinNext( &pPos->nNode )) + { + SwTxtNode* pNextNd = pPos->nNode.GetNode().GetTxtNode(); + pPos->nContent.Assign( pNextNd, 0 ); + pPam->SetMark(); pPam->DeleteMark(); + pNextNd->JoinPrev(); + } + else if( !pAktNd->GetTxt().Len() ) + { + pPos->nContent.Assign( 0, 0 ); + pPam->SetMark(); pPam->DeleteMark(); + pDoc->GetNodes().Delete( pPos->nNode, 1 ); + pPam->Move( fnMoveBackward ); + } + } + } + + // nun noch das SplitNode vom Anfang aufheben + else if( !IsNewDoc() ) + { + if( pPos->nContent.GetIndex() ) // dann gabs am Ende kein <P>, + pPam->Move( fnMoveForward, fnGoNode ); // als zum naechsten Node + SwTxtNode* pTxtNode = pPos->nNode.GetNode().GetTxtNode(); + SwNodeIndex aPrvIdx( pPos->nNode ); + if( pTxtNode && pTxtNode->CanJoinPrev( &aPrvIdx ) && + *pSttNdIdx <= aPrvIdx ) + { + // eigentlich muss hier ein JoinNext erfolgen, aber alle Cursor + // usw. sind im pTxtNode angemeldet, so dass der bestehen + // bleiben MUSS. + + // Absatz in Zeichen-Attribute umwandeln, aus dem Prev die + // Absatzattribute und die Vorlage uebernehmen! + SwTxtNode* pPrev = aPrvIdx.GetNode().GetTxtNode(); + pTxtNode->ChgFmtColl( pPrev->GetTxtColl() ); + pTxtNode->FmtToTxtAttr( pPrev ); + pTxtNode->ResetAllAttr(); + + if( pPrev->HasSwAttrSet() ) + pTxtNode->SetAttr( *pPrev->GetpSwAttrSet() ); + + if( &pPam->GetBound(TRUE).nNode.GetNode() == pPrev ) + pPam->GetBound(TRUE).nContent.Assign( pTxtNode, 0 ); + if( &pPam->GetBound(FALSE).nNode.GetNode() == pPrev ) + pPam->GetBound(FALSE).nContent.Assign( pTxtNode, 0 ); + + pTxtNode->JoinPrev(); + } + } + + // und noch die DocumentInfo aufbereiten + if( IsNewDoc() ) + { + SwDocShell *pDocShell(pDoc->GetDocShell()); + DBG_ASSERT(pDocShell, "no SwDocShell"); + if (pDocShell) { + uno::Reference<document::XDocumentPropertiesSupplier> xDPS( + pDocShell->GetModel(), uno::UNO_QUERY_THROW); + uno::Reference<document::XDocumentProperties> xDocProps( + xDPS->getDocumentProperties()); + DBG_ASSERT(xDocProps.is(), "DocumentProperties is null"); + if ( xDocProps.is() && (xDocProps->getAutoloadSecs() > 0) && + xDocProps->getAutoloadURL().equalsAscii("") ) + { + xDocProps->setAutoloadURL(aPathToFile); + } + } + } + + if( bUpdateDocStat ) + { + SwDocStat aStat( pDoc->GetDocStat() ); + pDoc->UpdateDocStat( aStat ); + } + } + + if( SVPAR_PENDING != GetStatus() ) + delete pSttNdIdx, pSttNdIdx = 0; + + // sollte der Parser der Letzte sein, der das Doc haelt, dann braucht + // man hier auch nichts mehr tun, Doc wird gleich zerstoert! + if( 1 < pDoc->getReferenceCount() ) + { + if( bWasUndo ) + { + pDoc->DelAllUndoObj(); + pDoc->DoUndo( TRUE ); + } + else if( !pInitVSh ) + { + // Wenn zu Beginn des Continue keine Shell vorhanden war, + // kann trotzdem mitlerweile eine angelegt worden sein. + // In dieses Fall stimmt das bWasUndo-Flag nicht und + // wir muessen das Undo noch anschalten. + ViewShell *pTmpVSh = CheckActionViewShell(); + if( pTmpVSh ) + pDoc->DoUndo( TRUE ); + } + + pDoc->SetOle2Link( aOLELink ); + if( !bModified ) + pDoc->ResetModified(); + if( bSetModEnabled && pDoc->GetDocShell() ) + { + pDoc->GetDocShell()->EnableSetModified( TRUE ); + bSetModEnabled = FALSE; // this is unnecessary here + } + } + + + // Wenn die Dokuemnt-ViewShell noch existiert und eine Action + // offen ist (muss bei Abbruch nicht sein), die Action beenden, + // uns von der Shell abmelden und schliesslich die alte Shell + // wieder rekonstruieren. + CallEndAction( TRUE ); + +#ifndef PRODUCT + nContinue--; +#endif +} + +void SwHTMLParser::Modify( SfxPoolItem *pOld, SfxPoolItem *pNew ) +{ + switch( pOld ? pOld->Which() : pNew ? pNew->Which() : 0 ) + { + case RES_OBJECTDYING: + if( ((SwPtrMsgPoolItem *)pOld)->pObject == pRegisteredIn ) + { + // dann uns selbst beenden + pRegisteredIn->Remove( this ); + ReleaseRef(); // ansonsten sind wir fertig! + } + break; + } +} + +void SwHTMLParser::DocumentDetected() +{ + ASSERT( !bDocInitalized, "DocumentDetected mehrfach aufgerufen" ); + bDocInitalized = TRUE; + if( IsNewDoc() ) + { + if( IsInHeader() ) + FinishHeader( TRUE ); + + CallEndAction( TRUE, TRUE ); + + pDoc->DoUndo( FALSE ); + // Durch das DocumentDetected wurde im allgemeinen eine + // ViewShell angelegt. Es kann aber auch sein, dass sie + // erst spaeter angelegt wird, naemlich dann, wenn die UI + // gecaptured ist. + CallStartAction(); + } +} + +// wird fuer jedes Token gerufen, das in CallParser erkannt wird +void __EXPORT SwHTMLParser::NextToken( int nToken ) +{ + if( ( pDoc->GetDocShell() && pDoc->GetDocShell()->IsAbortingImport() ) + || 1 == pDoc->getReferenceCount() ) + { + // wurde der Import vom SFX abgebrochen? Wenn ein Pending-Stack + // existiert den noch aufraumen + eState = SVPAR_ERROR; + ASSERT( !pPendStack || pPendStack->nToken, + "SwHTMLParser::NextToken: Pending-Stack ohne Token" ); + if( 1 == pDoc->getReferenceCount() || !pPendStack ) + return ; + } + +#ifndef PRODUCT + if( pPendStack ) + { + switch( nToken ) + { + // Tabellen werden ueber rekusive Methodenaufrufe gelesen + case HTML_TABLE_ON: + // Bei CSS-Deklarationen muss evtl. noch auf das + // Ende eines File-Downloads gewartet werden. + case HTML_LINK: + // Bei Controls muss evtl. noch die Groesse gesetzt werden. + case HTML_INPUT: + case HTML_TEXTAREA_ON: + case HTML_SELECT_ON: + case HTML_SELECT_OFF: + break; + default: + ASSERT( !pPendStack, "Unbekanntes Token fuer Pending-Stack" ); + break; + } + } +#endif + + // Die folgeneden Spezialfaelle muessen vor der Filter-Detection behandelt + // werden, denn der Inhalt des Titels, etc. wird auch in Netcape nicht + // zur Filter-Detection herangezogen. + if( !pPendStack ) + { + if( bInTitle ) + { + switch( nToken ) + { + case HTML_TITLE_OFF: + if( IsNewDoc() && sTitle.Len() ) + { + if( pDoc->GetDocShell() ) { + uno::Reference<document::XDocumentPropertiesSupplier> + xDPS(pDoc->GetDocShell()->GetModel(), + uno::UNO_QUERY_THROW); + uno::Reference<document::XDocumentProperties> xDocProps( + xDPS->getDocumentProperties()); + DBG_ASSERT(xDocProps.is(), "no DocumentProperties"); + if (xDocProps.is()) { + xDocProps->setTitle(sTitle); + } + + pDoc->GetDocShell()->SetTitle( sTitle ); + } + } + bInTitle = FALSE; + sTitle.Erase(); + break; + + case HTML_NONBREAKSPACE: + sTitle += ' '; + break; + + case HTML_SOFTHYPH: + sTitle += '-'; + break; + + case HTML_TEXTTOKEN: + sTitle += aToken; + break; + + default: + sTitle += '<'; + if( (HTML_TOKEN_ONOFF & nToken) && (1 & nToken) ) + sTitle += '/'; + sTitle += sSaveToken; + if( aToken.Len() ) + { + sTitle += ' '; + sTitle += aToken; + } + sTitle += '>'; + break; + } + + return; + } + } + + // Wenn wir noch nicht wissen, was fuer ein Dokument wir vor uns haben, + // versuchen wir das erstmal rauszufinden. Das muss fuer Controls in + // Fall vor dem Einfuegen des Controls passieren, weil beim Einfuegen + // bereits eine View benoetigt wird. + if( !bDocInitalized ) + DocumentDetected(); + + BOOL bGetIDOption = FALSE, bInsertUnknown = FALSE; + BOOL bUpperSpaceSave = bUpperSpace; + bUpperSpace = FALSE; + + // Die folgenden Speziallfaelle muessen oder koennen nach der + // Filter-Detection erfolgen. + if( !pPendStack ) + { + if( bInFloatingFrame ) + { + // <SCRIPT> wird hier (von uns) ignoriert, weil es auch in + // Applets ignoriert wird! + if( HTML_IFRAME_OFF == nToken ) + { + bCallNextToken = FALSE; + EndFloatingFrame(); + } + + return; + } + else if( bInNoEmbed ) + { + switch( nToken ) + { + case HTML_NOEMBED_OFF: + aContents.ConvertLineEnd(); + InsertComment( aContents, OOO_STRING_SVTOOLS_HTML_noembed ); + aContents.Erase(); + bCallNextToken = FALSE; + bInNoEmbed = FALSE; + break; + + case HTML_RAWDATA: + InsertCommentText( OOO_STRING_SVTOOLS_HTML_noembed ); + break; + + default: + ASSERT( !this, "SwHTMLParser::NextToken: ungueltiges Tag" ); + break; + } + + return; + } + else if( pAppletImpl ) + { + // in einem Applet interessieren uns (erstmal) nur <PARAM>-Tags + // und das </APPLET>. + // <SCRIPT> wird hier (von Netscape) ignoriert! + + switch( nToken ) + { + case HTML_APPLET_OFF: + bCallNextToken = FALSE; + EndApplet(); + break; + case HTML_OBJECT_OFF: + bCallNextToken = FALSE; + EndObject(); + break; + + case HTML_PARAM: + InsertParam(); + break; + } + + return; + } + else if( bTextArea ) + { + // in einer TextArea wird alles bis zum </TEXTAREA> als Text + // eingefuegt + // <SCRIPT> wird hier (von Netscape) ignoriert! + + switch( nToken ) + { + case HTML_TEXTAREA_OFF: + bCallNextToken = FALSE; + EndTextArea(); + break; + + default: + InsertTextAreaText( static_cast< sal_uInt16 >(nToken) ); + break; + } + + return; + } + else if( bSelect ) + { + // MUSS nach bNoScript kommen! + switch( nToken ) + { + case HTML_SELECT_OFF: + bCallNextToken = FALSE; + EndSelect(); + return; + + case HTML_OPTION: + InsertSelectOption(); + return; + + case HTML_TEXTTOKEN: + InsertSelectText(); + return; + + case HTML_INPUT: + case HTML_SCRIPT_ON: + case HTML_SCRIPT_OFF: + case HTML_NOSCRIPT_ON: + case HTML_NOSCRIPT_OFF: + case HTML_RAWDATA: + // im normalen switch bahandeln + break; + + default: + // ignorieren + return; + } + } + else if( pMarquee ) + { + // in einer TextArea wird alles bis zum </TEXTAREA> als Text + // eingefuegt + // Die <SCRIPT>-Tags werden vom MS-IE ignoriert, von uns das + // geasmte Script + switch( nToken ) + { + case HTML_MARQUEE_OFF: + bCallNextToken = FALSE; + EndMarquee(); + break; + + case HTML_TEXTTOKEN: + InsertMarqueeText(); + break; + } + + return; + } + else if( bInField ) + { + switch( nToken ) + { + case HTML_SDFIELD_OFF: + bCallNextToken = FALSE; + EndField(); + break; + + case HTML_TEXTTOKEN: + InsertFieldText(); + break; + } + + return; + } + else if( bInFootEndNoteAnchor || bInFootEndNoteSymbol ) + { + switch( nToken ) + { + case HTML_ANCHOR_OFF: + EndAnchor(); + bCallNextToken = FALSE; + break; + + case HTML_TEXTTOKEN: + InsertFootEndNoteText(); + break; + } + return; + } + else if( aUnknownToken.Len() ) + { + // Unbekannte Token im Header werden nur durch ein passendes + // End-Token, </HEAD> oder <BODY> wieder beendet. Darin wird Text + // ignoriert. + switch( nToken ) + { + case HTML_UNKNOWNCONTROL_OFF: + if( aUnknownToken.CompareTo(sSaveToken) != COMPARE_EQUAL ) + return; + case HTML_FRAMESET_ON: + case HTML_HEAD_OFF: + case HTML_BODY_ON: + case HTML_IMAGE: // Warum auch immer Netscape das tut. + aUnknownToken.Erase(); + break; + case HTML_TEXTTOKEN: + return; + default: + break; + } + } + } + + switch( nToken ) + { + case HTML_BODY_ON: + if( aStyleSource.Len() ) + { + pCSS1Parser->ParseStyleSheet( aStyleSource ); + aStyleSource.Erase(); + } + if( IsNewDoc() ) + { + InsertBodyOptions(); + // Falls es eine Vorlage fuer die erste oder rechte Seite gibt, + // setzen wir die hier. + const SwPageDesc *pPageDesc = 0; + if( pCSS1Parser->IsSetFirstPageDesc() ) + pPageDesc = pCSS1Parser->GetFirstPageDesc(); + else if( pCSS1Parser->IsSetRightPageDesc() ) + pPageDesc = pCSS1Parser->GetRightPageDesc(); + + if( pPageDesc ) + { + pDoc->InsertPoolItem( *pPam, SwFmtPageDesc( pPageDesc ), 0 ); + } + } + break; + + case HTML_LINK: + InsertLink(); + break; + + case HTML_BASE: + { + const HTMLOptions *pHTMLOptions = GetOptions(); + for( USHORT i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[ --i ]; + switch( pOption->GetToken() ) + { + case HTML_O_HREF: + sBaseURL = pOption->GetString(); + break; + case HTML_O_TARGET: + if( IsNewDoc() ) + { + SwDocShell *pDocShell(pDoc->GetDocShell()); + DBG_ASSERT(pDocShell, "no SwDocShell"); + if (pDocShell) { + uno::Reference<document::XDocumentPropertiesSupplier> xDPS( + pDocShell->GetModel(), uno::UNO_QUERY_THROW); + uno::Reference<document::XDocumentProperties> + xDocProps(xDPS->getDocumentProperties()); + DBG_ASSERT(xDocProps.is(),"no DocumentProperties"); + if (xDocProps.is()) { + xDocProps->setDefaultTarget( + pOption->GetString()); + } + } + } + break; + } + } + } + break; + + case HTML_META: + { + SvKeyValueIterator *pHTTPHeader = 0; + if( IsNewDoc() ) + { + SwDocShell *pDocSh = pDoc->GetDocShell(); + if( pDocSh ) + pHTTPHeader = pDocSh->GetHeaderAttributes(); + } + SwDocShell *pDocShell(pDoc->GetDocShell()); + DBG_ASSERT(pDocShell, "no SwDocShell"); + if (pDocShell) + { + uno::Reference<document::XDocumentProperties> xDocProps; + if (IsNewDoc()) + { + const uno::Reference<document::XDocumentPropertiesSupplier> + xDPS( pDocShell->GetModel(), uno::UNO_QUERY_THROW ); + xDocProps = xDPS->getDocumentProperties(); + DBG_ASSERT(xDocProps.is(), "DocumentProperties is null"); + } + ParseMetaOptions( xDocProps, pHTTPHeader ); + } + } + break; + + case HTML_TITLE_ON: + bInTitle = TRUE; + break; + + case HTML_SCRIPT_ON: + NewScript(); + break; + + case HTML_SCRIPT_OFF: + EndScript(); + break; + + case HTML_NOSCRIPT_ON: + case HTML_NOSCRIPT_OFF: + bInsertUnknown = TRUE; + break; + + case HTML_STYLE_ON: + NewStyle(); + break; + + case HTML_STYLE_OFF: + EndStyle(); + break; + + case HTML_RAWDATA: + if( !bIgnoreRawData ) + { + if( IsReadScript() ) + { + AddScriptSource(); + } + else if( IsReadStyle() ) + { + if( aStyleSource.Len() ) + aStyleSource += '\n'; + aStyleSource += aToken; + } + } + break; + + case HTML_OBJECT_ON: +#ifdef SOLAR_JAVA + NewObject(); + bCallNextToken = pAppletImpl!=0 && pTable!=0; +#endif + break; + + case HTML_APPLET_ON: +#ifdef SOLAR_JAVA + InsertApplet(); + bCallNextToken = pAppletImpl!=0 && pTable!=0; +#endif + break; + + case HTML_IFRAME_ON: + InsertFloatingFrame(); + bCallNextToken = bInFloatingFrame && pTable!=0; + break; + + case HTML_LINEBREAK: + if( !IsReadPRE() ) + { + InsertLineBreak(); + break; + } + else + bGetIDOption = TRUE; + // <BR>s in <PRE> aehneln echten LFs, deshalb kein break + + case HTML_NEWPARA: + // CR in PRE/LISTING/XMP + { + if( HTML_NEWPARA==nToken || + pPam->GetPoint()->nContent.GetIndex() ) + { + AppendTxtNode(); // lf gibts hier nicht, deshalb unkritisch + SetTxtCollAttrs(); + } + // Laufbalkenanzeige + if( !GetMedium() || !GetMedium()->IsRemote() ) + ::SetProgressState( rInput.Tell(), pDoc->GetDocShell() ); + } + break; + + case HTML_NONBREAKSPACE: + pDoc->InsertString( *pPam, CHAR_HARDBLANK ); + break; + + case HTML_SOFTHYPH: + pDoc->InsertString( *pPam, CHAR_SOFTHYPHEN ); + break; + + case HTML_LINEFEEDCHAR: + if( pPam->GetPoint()->nContent.GetIndex() ) + AppendTxtNode(); + if( !pTable && !pDoc->IsInHeaderFooter( pPam->GetPoint()->nNode ) ) + { + NewAttr( &aAttrTab.pBreak, SvxFmtBreakItem(SVX_BREAK_PAGE_BEFORE, RES_BREAK) ); + EndAttr( aAttrTab.pBreak, 0, FALSE ); + } + break; + + case HTML_TEXTTOKEN: + // dann fuege den String ein, ohne das Attribute am Ende + // aufgespannt werden. + if( aToken.Len() && ' '==aToken.GetChar(0) && !IsReadPRE() ) + { + xub_StrLen nPos = pPam->GetPoint()->nContent.GetIndex(); + if( nPos ) + { + const String& rText = + pDoc->GetNodes()[ pPam->GetPoint()->nNode ]->GetTxtNode() + ->GetTxt(); + sal_Unicode cLast = rText.GetChar(--nPos); + if( ' ' == cLast || '\x0a' == cLast) + aToken.Erase(0,1); + } + else + aToken.Erase(0,1); + + if( !aToken.Len() ) + { + bUpperSpace = bUpperSpaceSave; + break; + } + } + + if( aToken.Len() ) + { + if( !bDocInitalized ) + DocumentDetected(); + pDoc->InsertString( *pPam, aToken ); + + // wenn es noch vorlaefige Absatz-Attribute gibt, der Absatz aber + // nicht leer ist, dann sind die Absatz-Attribute entgueltig. + if( aParaAttrs.Count() ) + aParaAttrs.Remove( 0, aParaAttrs.Count() ); + + SetAttr(); + } + break; + + case HTML_HORZRULE: + InsertHorzRule(); + break; + + case HTML_IMAGE: + InsertImage(); + // sollte der Parser der Letzte sein, der das Doc haelt, dann kann + // man hier abbrechen und einen Fehler setzen. + if( 1 == pDoc->getReferenceCount() ) + { + eState = SVPAR_ERROR; + } + break; + + case HTML_SPACER: + InsertSpacer(); + break; + + case HTML_EMBED: + InsertEmbed(); + break; + + case HTML_NOEMBED_ON: + bInNoEmbed = TRUE; + bCallNextToken = pTable!=0; + ReadRawData( OOO_STRING_SVTOOLS_HTML_noembed ); + break; + + case HTML_DEFLIST_ON: + if( nOpenParaToken ) + EndPara(); + NewDefList(); + break; + case HTML_DEFLIST_OFF: + if( nOpenParaToken ) + EndPara(); + EndDefListItem( 0, FALSE, 1==nDefListDeep ); + EndDefList(); + break; + + case HTML_DD_ON: + case HTML_DT_ON: + if( nOpenParaToken ) + EndPara(); + EndDefListItem( 0, FALSE );// <DD>/<DT> beenden und keine Vorl. setzen + NewDefListItem( nToken ); + break; + + case HTML_DD_OFF: + case HTML_DT_OFF: + // siehe HTML_LI_OFF + // eigentlich muesste man ein DD/DT jetzt beenden. Da aber sowhl + // Netscape als auch Microsoft das nicht tun, machen wir das eben + // auch nicht. + EndDefListItem( nToken, FALSE ); + break; + + // Bereiche + case HTML_DIVISION_ON: + case HTML_CENTER_ON: + if( nOpenParaToken ) + { + if( IsReadPRE() ) + nOpenParaToken = 0; + else + EndPara(); + } + NewDivision( nToken ); + break; + + case HTML_DIVISION_OFF: + case HTML_CENTER_OFF: + if( nOpenParaToken ) + { + if( IsReadPRE() ) + nOpenParaToken = 0; + else + EndPara(); + } + EndDivision( nToken ); + break; + + case HTML_MULTICOL_ON: + if( nOpenParaToken ) + EndPara(); + NewMultiCol(); + break; + + case HTML_MULTICOL_OFF: + if( nOpenParaToken ) + EndPara(); + EndTag( HTML_MULTICOL_ON ); + break; + + case HTML_MARQUEE_ON: + NewMarquee(); + bCallNextToken = pMarquee!=0 && pTable!=0; + break; + + case HTML_FORM_ON: + NewForm(); + break; + case HTML_FORM_OFF: + EndForm(); + break; + + // Vorlagen: + case HTML_PARABREAK_ON: + if( nOpenParaToken ) + EndPara( TRUE ); + NewPara(); + break; + + case HTML_PARABREAK_OFF: + EndPara( TRUE ); + break; + + case HTML_ADDRESS_ON: + if( nOpenParaToken ) + EndPara(); + NewTxtFmtColl( HTML_ADDRESS_ON, RES_POOLCOLL_SENDADRESS ); + break; + + case HTML_ADDRESS_OFF: + if( nOpenParaToken ) + EndPara(); + EndTxtFmtColl( HTML_ADDRESS_OFF ); + break; + + case HTML_BLOCKQUOTE_ON: + case HTML_BLOCKQUOTE30_ON: + if( nOpenParaToken ) + EndPara(); + NewTxtFmtColl( HTML_BLOCKQUOTE_ON, RES_POOLCOLL_HTML_BLOCKQUOTE ); + break; + + case HTML_BLOCKQUOTE_OFF: + case HTML_BLOCKQUOTE30_OFF: + if( nOpenParaToken ) + EndPara(); + EndTxtFmtColl( HTML_BLOCKQUOTE_ON ); + break; + + case HTML_PREFORMTXT_ON: + case HTML_LISTING_ON: + case HTML_XMP_ON: + if( nOpenParaToken ) + EndPara(); + NewTxtFmtColl( nToken, RES_POOLCOLL_HTML_PRE ); + break; + + case HTML_PREFORMTXT_OFF: + bNoParSpace = TRUE; // der letzte PRE-Absatz muss einen Zeilenabstand bekommen + EndTxtFmtColl( HTML_PREFORMTXT_OFF ); + break; + + case HTML_LISTING_OFF: + case HTML_XMP_OFF: + EndTxtFmtColl( nToken ); + break; + + case HTML_HEAD1_ON: + case HTML_HEAD2_ON: + case HTML_HEAD3_ON: + case HTML_HEAD4_ON: + case HTML_HEAD5_ON: + case HTML_HEAD6_ON: + if( nOpenParaToken ) + { + if( IsReadPRE() ) + nOpenParaToken = 0; + else + EndPara(); + } + NewHeading( nToken ); + break; + + case HTML_HEAD1_OFF: + case HTML_HEAD2_OFF: + case HTML_HEAD3_OFF: + case HTML_HEAD4_OFF: + case HTML_HEAD5_OFF: + case HTML_HEAD6_OFF: + EndHeading(); + break; + + case HTML_TABLE_ON: + if( pPendStack ) + BuildTable( SVX_ADJUST_END ); + else + { + if( nOpenParaToken ) + EndPara(); + ASSERT( !pTable, "Tabelle in Tabelle darf hier nicht vorkommen" ); + if( !pTable && (IsNewDoc() || !pPam->GetNode()->FindTableNode()) && + (pPam->GetPoint()->nNode.GetIndex() > + pDoc->GetNodes().GetEndOfExtras().GetIndex() || + !pPam->GetNode()->FindFootnoteStartNode() ) ) + { + if ( nParaCnt < 5 ) + Show(); // bis hierhin schon mal anzeigen + + SvxAdjust eAdjust = aAttrTab.pAdjust + ? ((const SvxAdjustItem&)aAttrTab.pAdjust->GetItem()). + GetAdjust() + : SVX_ADJUST_END; + BuildTable( eAdjust ); + } + else + bInsertUnknown = bKeepUnknown; + } + break; + + // Listen + case HTML_DIRLIST_ON: + case HTML_MENULIST_ON: + case HTML_ORDERLIST_ON: + case HTML_UNORDERLIST_ON: + if( nOpenParaToken ) + EndPara(); + NewNumBulList( nToken ); + break; + + case HTML_DIRLIST_OFF: + case HTML_MENULIST_OFF: + case HTML_ORDERLIST_OFF: + case HTML_UNORDERLIST_OFF: + if( nOpenParaToken ) + EndPara(); + EndNumBulListItem( 0, TRUE, GetNumInfo().GetDepth()==1 ); + EndNumBulList( nToken ); + break; + + case HTML_LI_ON: + case HTML_LISTHEADER_ON: + if( nOpenParaToken && + (pPam->GetPoint()->nContent.GetIndex() + || HTML_PARABREAK_ON==nOpenParaToken) ) + { + // nure bei <P><LI> den Absatz beenden, aber nicht bei <DD><LI> + EndPara(); + } + + EndNumBulListItem( 0, FALSE );// <LI>/<LH> beenden und keine Vorl. setzen + NewNumBulListItem( nToken ); + break; + + case HTML_LI_OFF: + case HTML_LISTHEADER_OFF: + EndNumBulListItem( nToken, FALSE ); + break; + + // Attribute : + case HTML_ITALIC_ON: + { + SvxPostureItem aPosture( ITALIC_NORMAL, RES_CHRATR_POSTURE ); + SvxPostureItem aPostureCJK( ITALIC_NORMAL, RES_CHRATR_CJK_POSTURE ); + SvxPostureItem aPostureCTL( ITALIC_NORMAL, RES_CHRATR_CTL_POSTURE ); + NewStdAttr( HTML_ITALIC_ON, + &aAttrTab.pItalic, aPosture, + &aAttrTab.pItalicCJK, &aPostureCJK, + &aAttrTab.pItalicCTL, &aPostureCTL ); + } + break; + + case HTML_BOLD_ON: + { + SvxWeightItem aWeight( WEIGHT_BOLD, RES_CHRATR_WEIGHT ); + SvxWeightItem aWeightCJK( WEIGHT_BOLD, RES_CHRATR_CJK_WEIGHT ); + SvxWeightItem aWeightCTL( WEIGHT_BOLD, RES_CHRATR_CTL_WEIGHT ); + NewStdAttr( HTML_BOLD_ON, + &aAttrTab.pBold, aWeight, + &aAttrTab.pBoldCJK, &aWeightCJK, + &aAttrTab.pBoldCTL, &aWeightCTL ); + } + break; + + + case HTML_STRIKE_ON: + case HTML_STRIKETHROUGH_ON: + { + NewStdAttr( HTML_STRIKE_ON, &aAttrTab.pStrike, + SvxCrossedOutItem(STRIKEOUT_SINGLE, RES_CHRATR_CROSSEDOUT) ); + } + break; + + case HTML_UNDERLINE_ON: + { + NewStdAttr( HTML_UNDERLINE_ON, &aAttrTab.pUnderline, + SvxUnderlineItem(UNDERLINE_SINGLE, RES_CHRATR_UNDERLINE) ); + } + break; + + case HTML_SUPERSCRIPT_ON: + { + NewStdAttr( HTML_SUPERSCRIPT_ON, &aAttrTab.pEscapement, + SvxEscapementItem(HTML_ESC_SUPER,HTML_ESC_PROP, RES_CHRATR_ESCAPEMENT) ); + } + break; + + case HTML_SUBSCRIPT_ON: + { + NewStdAttr( HTML_SUBSCRIPT_ON, &aAttrTab.pEscapement, + SvxEscapementItem(HTML_ESC_SUB,HTML_ESC_PROP, RES_CHRATR_ESCAPEMENT) ); + } + break; + + case HTML_BLINK_ON: + { + NewStdAttr( HTML_BLINK_ON, &aAttrTab.pBlink, + SvxBlinkItem( TRUE, RES_CHRATR_BLINK ) ); + } + break; + + case HTML_SPAN_ON: + NewStdAttr( HTML_SPAN_ON ); + break; + + + case HTML_ITALIC_OFF: + case HTML_BOLD_OFF: + case HTML_STRIKE_OFF: + case HTML_UNDERLINE_OFF: + case HTML_SUPERSCRIPT_OFF: + case HTML_SUBSCRIPT_OFF: + case HTML_BLINK_OFF: + case HTML_SPAN_OFF: + EndTag( nToken ); + break; + + case HTML_STRIKETHROUGH_OFF: + EndTag( HTML_STRIKE_OFF ); + break; + + case HTML_BASEFONT_ON: + NewBasefontAttr(); + break; + case HTML_BASEFONT_OFF: + EndBasefontAttr(); + break; + case HTML_FONT_ON: + case HTML_BIGPRINT_ON: + case HTML_SMALLPRINT_ON: + NewFontAttr( nToken ); + break; + case HTML_FONT_OFF: + case HTML_BIGPRINT_OFF: + case HTML_SMALLPRINT_OFF: + EndFontAttr( nToken ); + break; + + case HTML_EMPHASIS_ON: + case HTML_CITIATION_ON: + case HTML_STRONG_ON: + case HTML_CODE_ON: + case HTML_SAMPLE_ON: + case HTML_KEYBOARD_ON: + case HTML_VARIABLE_ON: + case HTML_DEFINSTANCE_ON: + case HTML_SHORTQUOTE_ON: + case HTML_LANGUAGE_ON: + case HTML_AUTHOR_ON: + case HTML_PERSON_ON: + case HTML_ACRONYM_ON: + case HTML_ABBREVIATION_ON: + case HTML_INSERTEDTEXT_ON: + case HTML_DELETEDTEXT_ON: + + case HTML_TELETYPE_ON: + NewCharFmt( nToken ); + break; + + case HTML_SDFIELD_ON: + NewField(); + bCallNextToken = bInField && pTable!=0; + break; + + case HTML_EMPHASIS_OFF: + case HTML_CITIATION_OFF: + case HTML_STRONG_OFF: + case HTML_CODE_OFF: + case HTML_SAMPLE_OFF: + case HTML_KEYBOARD_OFF: + case HTML_VARIABLE_OFF: + case HTML_DEFINSTANCE_OFF: + case HTML_SHORTQUOTE_OFF: + case HTML_LANGUAGE_OFF: + case HTML_AUTHOR_OFF: + case HTML_PERSON_OFF: + case HTML_ACRONYM_OFF: + case HTML_ABBREVIATION_OFF: + case HTML_INSERTEDTEXT_OFF: + case HTML_DELETEDTEXT_OFF: + + case HTML_TELETYPE_OFF: + EndTag( nToken ); + break; + + case HTML_HEAD_OFF: + if( aStyleSource.Len() ) + { + pCSS1Parser->ParseStyleSheet( aStyleSource ); + aStyleSource.Erase(); + } + break; + + case HTML_DOCTYPE: + case HTML_BODY_OFF: + case HTML_HTML_OFF: + case HTML_HEAD_ON: + case HTML_TITLE_OFF: + break; // nicht weiter auswerten, oder??? + case HTML_HTML_ON: + { + const HTMLOptions *pHTMLOptions = GetOptions(); + for( USHORT i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[ --i ]; + if( HTML_O_DIR == pOption->GetToken() ) + { + const String& rDir = pOption->GetString(); + SfxItemSet aItemSet( pDoc->GetAttrPool(), + pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + String aDummy; + ParseStyleOptions( aDummy, aDummy, aDummy, aItemSet, + aPropInfo, 0, &rDir ); + + pCSS1Parser->SetPageDescAttrs( 0, &aItemSet ); + break; + } + } + } + break; + + case HTML_INPUT: + InsertInput(); + break; + + case HTML_TEXTAREA_ON: + NewTextArea(); + bCallNextToken = bTextArea && pTable!=0; + break; + + case HTML_SELECT_ON: + NewSelect(); + bCallNextToken = bSelect && pTable!=0; + break; + + case HTML_ANCHOR_ON: + NewAnchor(); + break; + + case HTML_ANCHOR_OFF: + EndAnchor(); + break; + + case HTML_COMMENT: + if( ( aToken.Len() > 5 ) && ( ! bIgnoreHTMLComments ) ) + { + // als Post-It einfuegen + // MIB 8.12.2000: If there are no space characters right behind + // the <!-- and on front of the -->, leave the comment untouched. + if( ' ' == aToken.GetChar( 3 ) && + ' ' == aToken.GetChar( aToken.Len()-3 ) ) + { + String aComment( aToken.Copy( 3, aToken.Len()-5 ) ); + aComment.EraseLeadingChars().EraseTrailingChars(); + InsertComment( aComment ); + } + else + { + String aComment( '<' ); + (aComment += aToken) += '>'; + InsertComment( aComment ); + } + } + break; + + case HTML_MAP_ON: + // Image Maps werden asynchron gelesen: Zunaechst wird nur eine + // ImageMap angelegt. Die Bereiche kommen spaeter. Trozdem wird + // die ImageMap schon in das IMap-Array eingetragen, denn sie + // koennte ja schon verwendet werden. + pImageMap = new ImageMap; + if( ParseMapOptions( pImageMap) ) + { + if( !pImageMaps ) + pImageMaps = new ImageMaps; + pImageMaps->Insert( pImageMap, pImageMaps->Count() ); + } + else + { + delete pImageMap; + pImageMap = 0; + } + break; + + case HTML_MAP_OFF: + // jetzt gibt es keine ImageMap mehr (IMap nicht Loeschen, denn + // die stckt ja schon in dem Array!) + pImageMap = 0; + break; + + case HTML_AREA: + if( pImageMap ) + ParseAreaOptions( pImageMap, sBaseURL, SFX_EVENT_MOUSEOVER_OBJECT, + SFX_EVENT_MOUSEOUT_OBJECT ); + break; + + case HTML_FRAMESET_ON: + bInsertUnknown = bKeepUnknown; + break; + + case HTML_NOFRAMES_ON: + if( IsInHeader() ) + FinishHeader( TRUE ); + bInsertUnknown = bKeepUnknown; + break; + + case HTML_UNKNOWNCONTROL_ON: + // Im Header muss der Inhalt von unbekannten Token ignoriert werden, + // es sei denn, das Token faengt mit einem '!' an. + if( IsInHeader() && !IsReadPRE() && !aUnknownToken.Len() && + sSaveToken.Len() && '!' != sSaveToken.GetChar(0) && + '%' != sSaveToken.GetChar(0) ) + aUnknownToken = sSaveToken; + // kein break + + default: + bInsertUnknown = bKeepUnknown; + break; + } + + if( bGetIDOption ) + InsertIDOption(); + + if( bInsertUnknown ) + { + String aComment( + String::CreateFromAscii(TOOLS_CONSTASCII_STRINGPARAM("HTML: <")) ); + if( (HTML_TOKEN_ONOFF & nToken) != 0 && (1 & nToken) != 0 ) + aComment += '/'; + aComment += sSaveToken; + if( aToken.Len() ) + { + UnescapeToken(); + (aComment += ' ') += aToken; + } + aComment += '>'; + InsertComment( aComment ); + } + + // wenn es noch vorlaefige Absatz-Attribute gibt, der Absatz aber + // nicht leer ist, dann sind die Absatz-Attribute entgueltig. + if( aParaAttrs.Count() && pPam->GetPoint()->nContent.GetIndex() ) + aParaAttrs.Remove( 0, aParaAttrs.Count() ); +} + +/* */ + +extern BOOL lcl_css1atr_equalFontItems( const SfxPoolItem& r1, const SfxPoolItem& r2 ); + +void lcl_swhtml_getItemInfo( const _HTMLAttr& rAttr, + sal_Bool& rScriptDependent, sal_Bool& rFont, + sal_uInt16& rScriptType ) +{ + sal_uInt16 nWhich = rAttr.GetItem().Which(); + switch( nWhich ) + { + case RES_CHRATR_FONT: + rFont = sal_True; + case RES_CHRATR_FONTSIZE: + case RES_CHRATR_LANGUAGE: + case RES_CHRATR_POSTURE: + case RES_CHRATR_WEIGHT: + rScriptType = i18n::ScriptType::LATIN; + rScriptDependent = sal_True; + break; + case RES_CHRATR_CJK_FONT: + rFont = sal_True; + case RES_CHRATR_CJK_FONTSIZE: + case RES_CHRATR_CJK_LANGUAGE: + case RES_CHRATR_CJK_POSTURE: + case RES_CHRATR_CJK_WEIGHT: + rScriptType = i18n::ScriptType::ASIAN; + rScriptDependent = sal_True; + break; + case RES_CHRATR_CTL_FONT: + rFont = sal_True; + case RES_CHRATR_CTL_FONTSIZE: + case RES_CHRATR_CTL_LANGUAGE: + case RES_CHRATR_CTL_POSTURE: + case RES_CHRATR_CTL_WEIGHT: + rScriptType = i18n::ScriptType::COMPLEX; + rScriptDependent = sal_True; + break; + default: + rScriptDependent = sal_False; + rFont = sal_False; + break; + } +} + +BOOL SwHTMLParser::AppendTxtNode( SwHTMLAppendMode eMode, BOOL bUpdateNum ) +{ + // Ein harter Zeilen-Umbruch am Ende muss immer entfernt werden. + // Einen zweiten ersetzen wir durch einen Absatz-Abstand. + xub_StrLen nLFStripped = StripTrailingLF(); + if( (AM_NOSPACE==eMode || AM_SOFTNOSPACE==eMode) && nLFStripped > 1 ) + eMode = AM_SPACE; + + // die harten Attribute an diesem Absatz werden nie mehr ungueltig + if( aParaAttrs.Count() ) + aParaAttrs.Remove( 0, aParaAttrs.Count() ); + + if( AM_SPACE==eMode || AM_NOSPACE==eMode ) + { + SwTxtNode *pTxtNode = + pDoc->GetNodes()[pPam->GetPoint()->nNode]->GetTxtNode(); + + const SvxULSpaceItem& rULSpace = + (const SvxULSpaceItem&)pTxtNode->SwCntntNode::GetAttr( RES_UL_SPACE ); + + BOOL bChange = AM_NOSPACE==eMode ? rULSpace.GetLower() > 0 + : rULSpace.GetLower() == 0; + + if( bChange ) + { + const SvxULSpaceItem& rCollULSpace = + pTxtNode->GetAnyFmtColl().GetULSpace(); + + BOOL bMayReset = AM_NOSPACE==eMode ? rCollULSpace.GetLower() == 0 + : rCollULSpace.GetLower() > 0; + + if( bMayReset && + rCollULSpace.GetUpper() == rULSpace.GetUpper() ) + { + pTxtNode->ResetAttr( RES_UL_SPACE ); + } + else + { + pTxtNode->SetAttr( + SvxULSpaceItem( rULSpace.GetUpper(), + AM_NOSPACE==eMode ? 0 : HTML_PARSPACE, RES_UL_SPACE ) ); + } + } + } + bNoParSpace = AM_NOSPACE==eMode || AM_SOFTNOSPACE==eMode; + + SwPosition aOldPos( *pPam->GetPoint() ); + + BOOL bRet = pDoc->AppendTxtNode( *pPam->GetPoint() ); + + // Zeichen-Attribute aufspalten und ggf keine setzen, die ueber den + // ganzen Absatz gesetzt sind + const SwNodeIndex& rEndIdx = aOldPos.nNode; + xub_StrLen nEndCnt = aOldPos.nContent.GetIndex(); + const SwPosition& rPos = *pPam->GetPoint(); + + _HTMLAttr** pTbl = (_HTMLAttr**)&aAttrTab; + for( USHORT nCnt = sizeof( _HTMLAttrTable ) / sizeof( _HTMLAttr* ); + nCnt--; ++pTbl ) + { + _HTMLAttr *pAttr = *pTbl; + if( pAttr && pAttr->GetItem().Which() < RES_PARATR_BEGIN ) + { + BOOL bWholePara = FALSE; + + while( pAttr ) + { + _HTMLAttr *pNext = pAttr->GetNext(); + if( pAttr->GetSttParaIdx() < rEndIdx.GetIndex() || + (!bWholePara && + pAttr->GetSttPara() == rEndIdx && + pAttr->GetSttCnt() != nEndCnt) ) + { + bWholePara = + pAttr->GetSttPara() == rEndIdx && + pAttr->GetSttCnt() == 0; + + xub_StrLen nStt = pAttr->nSttCntnt; + sal_Bool bScript = sal_False, bFont = sal_False; + sal_uInt16 nScriptItem; + sal_Bool bInsert = sal_True; + lcl_swhtml_getItemInfo( *pAttr, bScript, bFont, + nScriptItem ); + // den besehrigen Teil setzen + if( bInsert && bScript ) + { + const SwTxtNode *pTxtNd = + pAttr->GetSttPara().GetNode().GetTxtNode(); + ASSERT( pTxtNd, "No text node" ); + if( pTxtNd ) + { + const String& rText = pTxtNd->GetTxt(); + sal_uInt16 nScriptTxt = + pBreakIt->GetBreakIter()->getScriptType( + rText, pAttr->GetSttCnt() ); + xub_StrLen nScriptEnd = (xub_StrLen)pBreakIt->GetBreakIter() + ->endOfScript( rText, nStt, nScriptTxt ); + while( nScriptEnd < nEndCnt ) + { + if( nScriptItem == nScriptTxt ) + { + _HTMLAttr *pSetAttr = + pAttr->Clone( rEndIdx, nScriptEnd ); + pSetAttr->nSttCntnt = nStt; + pSetAttr->ClearPrev(); + if( !pNext || bWholePara ) + { + USHORT nTmp = pSetAttr->bInsAtStart ? 0 + : aSetAttrTab.Count(); + aSetAttrTab.Insert( pSetAttr, nTmp ); + } + else + pNext->InsertPrev( pSetAttr ); + } + nStt = nScriptEnd; + nScriptTxt = pBreakIt->GetBreakIter()->getScriptType( + rText, nStt ); + nScriptEnd = (xub_StrLen)pBreakIt->GetBreakIter() + ->endOfScript( rText, nStt, nScriptTxt ); + } + bInsert = nScriptItem == nScriptTxt; + } + } + if( bInsert ) + { + _HTMLAttr *pSetAttr = + pAttr->Clone( rEndIdx, nEndCnt ); + pSetAttr->nSttCntnt = nStt; + + // Wenn das Attribut den gesamten Absatz umspannt, werden + // alle auesseren Attribute nicht mehr beachtet. Deshalb + // darf es auch nicht in die Prev-Liste eines ausseren + // Attributs eingetragen werden, denn dieses wird ja + // erstmal nicht gesetzt. Das fuehrt zu verschiebenungen, + // wenn Felder ins Rennen kommen (siehe #51020#) + if( !pNext || bWholePara ) + { + USHORT nTmp = pSetAttr->bInsAtStart ? 0 + : aSetAttrTab.Count(); + aSetAttrTab.Insert( pSetAttr, nTmp ); + } + else + pNext->InsertPrev( pSetAttr ); + } + else + { + _HTMLAttr *pPrev = pAttr->GetPrev(); + if( pPrev ) + { + // Die Previous-Attribute muessen trotzdem gesetzt werden. + if( !pNext || bWholePara ) + { + USHORT nTmp = pPrev->bInsAtStart ? 0 : aSetAttrTab.Count(); + aSetAttrTab.Insert( pPrev, nTmp ); + } + else + pNext->InsertPrev( pPrev ); + } + } + pAttr->ClearPrev(); + } + + pAttr->SetStart( rPos ); + pAttr = pNext; + } + } + } + + if( bUpdateNum ) + { + if( GetNumInfo().GetDepth() ) + { + BYTE nLvl = GetNumInfo().GetLevel(); + // --> OD 2008-04-02 #refactorlists# +// SetNoNum (&nLvl, TRUE); +// SetNodeNum( nLvl); + SetNodeNum( nLvl, false ); + // <-- + } + else + pPam->GetNode()->GetTxtNode()->ResetAttr( RES_PARATR_NUMRULE ); + } + + // Attrubute im Absatz davor sollte man jetzt setzen (wegen JavaScript) + SetAttr(); + + // Now it is time to get rid of all script dependent hints that are + // equal to the settings in the style + SwTxtNode *pTxtNd = rEndIdx.GetNode().GetTxtNode(); + ASSERT( pTxtNd, "There is the txt node" ); + sal_uInt16 nCntAttr = (pTxtNd && pTxtNd->GetpSwpHints()) + ? pTxtNd->GetSwpHints().Count() : 0; + if( nCntAttr ) + { + // These are the end position of all script depenent hints. + // If we find a hint that starts before the current end position, + // we have to set it. If we finf a hint that start behind or at + // that position, we have to take the hint's value into account. + // If it is equal to the style, or in fact the paragarph's value + // for that hint, the hint is removed. Otherwise it's end position + // is remembered. + xub_StrLen aEndPos[15] = + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + SwpHints& rHints = pTxtNd->GetSwpHints(); + for( sal_uInt16 i=0; i < nCntAttr; i++ ) + { + SwTxtAttr *pHt = rHints.GetTextHint( i ); + sal_uInt16 nWhich = pHt->Which(); + sal_Int16 nIdx = -1; + if( RES_CHRATR_CJK_FONT <= nWhich && + nWhich <= RES_CHRATR_CTL_WEIGHT ) + { + nIdx = static_cast< USHORT >(nWhich - RES_CHRATR_CJK_FONT + 5); + } + else switch( nWhich ) + { + case RES_CHRATR_FONT: nIdx = 0; break; + case RES_CHRATR_FONTSIZE: nIdx = 1; break; + case RES_CHRATR_LANGUAGE: nIdx = 2; break; + case RES_CHRATR_POSTURE: nIdx = 3; break; + case RES_CHRATR_WEIGHT: nIdx = 4; break; + } + if( nIdx != -1 ) + { + xub_StrLen nStt = *pHt->GetStart(); + if( nStt >= aEndPos[nIdx] ) + { + sal_Bool bFont = (nIdx % 5) == 0; + const SfxPoolItem& rItem = + ((const SwCntntNode *)pTxtNd)->GetAttr( nWhich ); + if( bFont ? lcl_css1atr_equalFontItems(rItem,pHt->GetAttr()) + : rItem == pHt->GetAttr() ) + { + // The hint is the same as set in the paragraph and + // therfor, it can be deleted + // CAUTION!!! This WILL delete the hint and it MAY + // also delete the SwpHints!!! To avoid any trouble + // we leave the loop immediately if this is the last + // hint. + pTxtNd->DeleteAttribute( pHt ); + if( 1 == nCntAttr ) + break; + i--; + nCntAttr--; + } + else + { + // The hint is deifferent. Therfor all hints within that + // hint have to be ignored. + aEndPos[nIdx] = pHt->GetEnd() ? *pHt->GetEnd() : nStt; + } + } + else + { + // The hint starts before another one ends. + // The hint in this case is not deleted + ASSERT( pHt->GetEnd() && *pHt->GetEnd() <= aEndPos[nIdx], + "hints aren't nested properly!" ); + } + } + } + } + + + if( !pTable && !--nParaCnt ) + Show(); + + return bRet; +} + +void SwHTMLParser::AddParSpace() +{ + if( !bNoParSpace ) + return; + + bNoParSpace = FALSE; + + ULONG nNdIdx = pPam->GetPoint()->nNode.GetIndex() - 1; + + SwTxtNode *pTxtNode = pDoc->GetNodes()[nNdIdx]->GetTxtNode(); + if( !pTxtNode ) + return; + + SvxULSpaceItem rULSpace = + (const SvxULSpaceItem&)pTxtNode->SwCntntNode::GetAttr( RES_UL_SPACE ); + if( !rULSpace.GetLower() ) + { + const SvxULSpaceItem& rCollULSpace = + pTxtNode->GetAnyFmtColl().GetULSpace(); + if( rCollULSpace.GetLower() && + rCollULSpace.GetUpper() == rULSpace.GetUpper() ) + { + pTxtNode->ResetAttr( RES_UL_SPACE ); + } + else + { + pTxtNode->SetAttr( + SvxULSpaceItem( rULSpace.GetUpper(), HTML_PARSPACE, RES_UL_SPACE ) ); + } + } +} + + +void SwHTMLParser::Show() +{ + // Hier wird + // - ein EndAction gerufen, damit formatiert wird + // - ein Reschedule gerufen, + // - die eiegen View-Shell wieder gesetzt + // - und Start-Action gerufen + + ASSERT( SVPAR_WORKING==eState, "Show nicht im Working-State - Das kann ins Auge gehen" ); + ViewShell *pOldVSh = CallEndAction(); + + GetpApp()->Reschedule(); + + if( ( pDoc->GetDocShell() && pDoc->GetDocShell()->IsAbortingImport() ) + || 1 == pDoc->getReferenceCount() ) + { + // wurde der Import vom SFX abgebrochen? + eState = SVPAR_ERROR; + } + + // Die ViewShell nochmal holen, denn sie koennte im Reschedule + // zerstoert wirden sein. + ViewShell *pVSh = CallStartAction( pOldVSh ); + + // ist der aktuelle Node nicht mehr sichtbar, dann benutzen wir + // eine groessere Schrittweite + if( pVSh ) + nParaCnt = pDoc->GetNodes()[pPam->GetPoint()->nNode] + ->IsInVisibleArea(pVSh) ? 5 : 50; +} + +void SwHTMLParser::ShowStatline() +{ + // Hier wird + // - ein Reschedule gerufen, damit gescrollt werden kann + // - die eiegen View-Shell wieder gesetzt + // - ein Start/End-Action gerufen, wenn gescrollt wurde. + + ASSERT( SVPAR_WORKING==eState, "ShowStatLine nicht im Working-State - Das kann ins Auge gehen" ); + + // Laufbalkenanzeige + if( !GetMedium() || !GetMedium()->IsRemote() ) + { + ::SetProgressState( rInput.Tell(), pDoc->GetDocShell() ); + CheckActionViewShell(); + } + else + { + GetpApp()->Reschedule(); + + if( ( pDoc->GetDocShell() && pDoc->GetDocShell()->IsAbortingImport() ) + || 1 == pDoc->getReferenceCount() ) + // wurde der Import vom SFX abgebrochen? + eState = SVPAR_ERROR; + + ViewShell *pVSh = CheckActionViewShell(); + if( pVSh && pVSh->HasInvalidRect() ) + { + CallEndAction( FALSE, FALSE ); + CallStartAction( pVSh, FALSE ); + } + } +} + +ViewShell *SwHTMLParser::CallStartAction( ViewShell *pVSh, BOOL bChkPtr ) +{ + ASSERT( !pActionViewShell, "CallStartAction: ViewShell schon gesetzt" ); + + if( !pVSh || bChkPtr ) + { +#ifndef PRODUCT + ViewShell *pOldVSh = pVSh; +#endif + pDoc->GetEditShell( &pVSh ); + ASSERT( !pVSh || !pOldVSh || pOldVSh == pVSh, "CallStartAction: Wer hat die ViewShell ausgetauscht?" ); +#ifndef PRODUCT + if( pOldVSh && !pVSh ) + pVSh = 0; +#endif + } + pActionViewShell = pVSh; + + if( pActionViewShell ) + { + if( pActionViewShell->ISA( SwEditShell ) ) + ((SwEditShell*)pActionViewShell)->StartAction(); + else + pActionViewShell->StartAction(); + } + + return pActionViewShell; +} + +ViewShell *SwHTMLParser::CallEndAction( BOOL bChkAction, BOOL bChkPtr ) +{ + if( bChkPtr ) + { + ViewShell *pVSh = 0; + pDoc->GetEditShell( &pVSh ); + ASSERT( !pVSh || pActionViewShell == pVSh, + "CallEndAction: Wer hat die ViewShell ausgetauscht?" ); +#if OSL_DEBUG_LEVEL > 1 + if( pActionViewShell && !pVSh ) + pVSh = 0; +#endif + if( pVSh != pActionViewShell ) + pActionViewShell = 0; + } + + if( !pActionViewShell || (bChkAction && !pActionViewShell->ActionPend()) ) + return pActionViewShell; + + if( bSetCrsr ) + { + // an allen CrsrEditShells die Cursor auf den Doc-Anfang setzen + ViewShell *pSh = pActionViewShell; + do { + if( pSh->IsA( TYPE( SwCrsrShell ) ) ) + ((SwCrsrShell*)pSh)->SttEndDoc(TRUE); + pSh = (ViewShell *)pSh->GetNext(); + } while( pSh != pActionViewShell ); + + bSetCrsr = FALSE; + } + if( pActionViewShell->ISA( SwEditShell ) ) + { + //Schon gescrollt?, dann dafuer sorgen, dass die View sich nicht bewegt! + const BOOL bOldLock = pActionViewShell->IsViewLocked(); + pActionViewShell->LockView( TRUE ); + const BOOL bOldEndActionByVirDev = pActionViewShell->IsEndActionByVirDev(); + pActionViewShell->SetEndActionByVirDev( TRUE );; + ((SwEditShell*)pActionViewShell)->EndAction(); + pActionViewShell->SetEndActionByVirDev( bOldEndActionByVirDev ); + pActionViewShell->LockView( bOldLock ); + + // bChkJumpMark ist nur gesetzt, wenn das Object auch gefunden wurde + if( bChkJumpMark ) + { + const Point aVisSttPos( DOCUMENTBORDER, DOCUMENTBORDER ); + if( GetMedium() && aVisSttPos == pActionViewShell->VisArea().Pos() ) + ::JumpToSwMark( pActionViewShell, + GetMedium()->GetURLObject().GetMark() ); + bChkJumpMark = FALSE; + } + } + else + pActionViewShell->EndAction(); + + // sollte der Parser der Letzte sein, der das Doc haelt, dann kann + // man hier abbrechen und einen Fehler setzen. + if( 1 == pDoc->getReferenceCount() ) + { + eState = SVPAR_ERROR; + } + + ViewShell *pVSh = pActionViewShell; + pActionViewShell = 0; + + return pVSh; +} + +ViewShell *SwHTMLParser::CheckActionViewShell() +{ + ViewShell *pVSh = 0; + pDoc->GetEditShell( &pVSh ); + ASSERT( !pVSh || pActionViewShell == pVSh, + "CheckActionViewShell: Wer hat die ViewShell ausgetauscht?" ); +#if OSL_DEBUG_LEVEL > 1 + if( pActionViewShell && !pVSh ) + pVSh = 0; +#endif + if( pVSh != pActionViewShell ) + pActionViewShell = 0; + + return pActionViewShell; +} + +/* */ + +void SwHTMLParser::_SetAttr( BOOL bChkEnd, BOOL bBeforeTable, + _HTMLAttrs *pPostIts ) +{ + SwPaM* pAttrPam = new SwPaM( *pPam->GetPoint() ); + const SwNodeIndex& rEndIdx = pPam->GetPoint()->nNode; + xub_StrLen nEndCnt = pPam->GetPoint()->nContent.GetIndex(); + _HTMLAttr* pAttr; + SwCntntNode* pCNd; + USHORT n; + + _HTMLAttrs aFields( 5, 5 ); + + for( n = aSetAttrTab.Count(); n; ) + { + pAttr = aSetAttrTab[ --n ]; + USHORT nWhich = pAttr->pItem->Which(); + + ULONG nEndParaIdx = pAttr->GetEndParaIdx(); + BOOL bSetAttr; + if( bChkEnd ) + { + // fix #42192#: Zechen-Attribute mit Ende moeglich frueh, + // also noch im aktuellen Absatz setzen (wegen JavaScript + // und diversen Chats). das darf man aber nicht fuer Attribute, + // die ueber den ganzen Absatz aufgspannt werden sollen, weil + // sie aus Absatzvorlgen stammen, die nicht gesetzt werden + // koennen. Weil die Attribute mit SETATTR_DONTREPLACE + // eingefuegt werden, sollte man sie auch anchtraeglich + // noch setzen koennen. + bSetAttr = ( nEndParaIdx < rEndIdx.GetIndex() && + (RES_LR_SPACE != nWhich || !GetNumInfo().GetNumRule()) ) || + ( !pAttr->IsLikePara() && + nEndParaIdx == rEndIdx.GetIndex() && + pAttr->GetEndCnt() < nEndCnt && + (isCHRATR(nWhich) || isTXTATR_WITHEND(nWhich)) ) || + ( bBeforeTable && + nEndParaIdx == rEndIdx.GetIndex() && + !pAttr->GetEndCnt() ); + } + else + { + // Attribiute im Content-Bereich duerfen nicht gesetzt + // werden, wenn wir in einem Sonderbereich stehen, aber + // umgekekehrt schon. + ULONG nEndOfIcons = pDoc->GetNodes().GetEndOfExtras().GetIndex(); + bSetAttr = nEndParaIdx < rEndIdx.GetIndex() || + rEndIdx.GetIndex() > nEndOfIcons || + nEndParaIdx <= nEndOfIcons; + } + + if( bSetAttr ) + { + // Das Attribute darf nicht in der liste der vorlaeufigen + // Absatz-Attribute stehen, weil es sonst geloescht wurde. + USHORT ii = aParaAttrs.Count(); + while( ii-- ) + { + ASSERT( pAttr != aParaAttrs[ii], + "SetAttr: Attribut duerfte noch nicht gesetzt werden" ); + aParaAttrs.Remove( ii ); + } + + + // dann also setzen + aSetAttrTab.Remove( n, 1 ); + + while( pAttr ) + { + _HTMLAttr *pPrev = pAttr->GetPrev(); + if( !pAttr->bValid ) + { + // ungueltige Attribute koennen gloescht werden + delete pAttr; + pAttr = pPrev; + continue; //break; + } + + + pCNd = pDoc->GetNodes()[ pAttr->nSttPara ]->GetCntntNode(); + if( !pCNd ) + { + // durch die elende Loescherei von Nodes kann auch mal + // ein Index auf einen End-Node zeigen :-( + if ( (pAttr->GetSttPara() == pAttr->GetEndPara()) && + !isTXTATR_NOEND(nWhich) ) + { + // wenn der End-Index auch auf den Node zeigt + // brauchen wir auch kein Attribut mehr zu setzen, + // es sei denn, es ist ein Text-Attribut. + delete pAttr; + pAttr = pPrev; + continue; //break; + } + pCNd = pDoc->GetNodes().GoNext( &(pAttr->nSttPara) ); + if( pCNd ) + pAttr->nSttCntnt = 0; + else + { + ASSERT( !this, "SetAttr: GoNext() failed!" ); + delete pAttr; + pAttr = pPrev; + continue; // break; + } + } + pAttrPam->GetPoint()->nNode = pAttr->nSttPara; + + + + // durch das Loeschen von BRs kann der Start-Index + // auch mal hinter das Ende des Textes zeigen + if( pAttr->nSttCntnt > pCNd->Len() ) + pAttr->nSttCntnt = pCNd->Len(); + pAttrPam->GetPoint()->nContent.Assign( pCNd, pAttr->nSttCntnt ); + + pAttrPam->SetMark(); + if ( (pAttr->GetSttPara() != pAttr->GetEndPara()) && + !isTXTATR_NOEND(nWhich) ) + { + pCNd = pDoc->GetNodes()[ pAttr->nEndPara ]->GetCntntNode(); + if( !pCNd ) + { + pCNd = pDoc->GetNodes().GoPrevious( &(pAttr->nEndPara) ); + if( pCNd ) + pAttr->nEndCntnt = pCNd->Len(); + else + { + ASSERT( !this, "SetAttr: GoPrevious() failed!" ); + pAttrPam->DeleteMark(); + delete pAttr; + pAttr = pPrev; + continue; // break; + } + } + + pAttrPam->GetPoint()->nNode = pAttr->nEndPara; + } + else if( pAttr->IsLikePara() ) + { + pAttr->nEndCntnt = pCNd->Len(); + } + + // durch das Loeschen von BRs kann der End-Index + // auch mal hinter das Ende des Textes zeigen + if( pAttr->nEndCntnt > pCNd->Len() ) + pAttr->nEndCntnt = pCNd->Len(); + + pAttrPam->GetPoint()->nContent.Assign( pCNd, pAttr->nEndCntnt ); + if( bBeforeTable && + pAttrPam->GetPoint()->nNode.GetIndex() == + rEndIdx.GetIndex() ) + { + // wenn wir vor dem Einfuegen einer Tabelle stehen + // und das Attribut im aktuellen Node beendet wird, + // muessen wir es im Node davor beenden oder wegschmeissen, + // wenn es erst in dem Node beginnt + if( nWhich != RES_BREAK && nWhich != RES_PAGEDESC && + !isTXTATR_NOEND(nWhich) ) + { + if( pAttrPam->GetMark()->nNode.GetIndex() != + rEndIdx.GetIndex() ) + { + ASSERT( !pAttrPam->GetPoint()->nContent.GetIndex(), + "Content-Position vor Tabelle nicht 0???" ); + pAttrPam->Move( fnMoveBackward ); + } + else + { + pAttrPam->DeleteMark(); + delete pAttr; + pAttr = pPrev; + continue; + } + } + } + + switch( nWhich ) + { + case RES_FLTR_BOOKMARK: // insert bookmark + { + const String sName( ((SfxStringItem*)pAttr->pItem)->GetValue() ); + IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess(); + IDocumentMarkAccess::const_iterator_t ppBkmk = pMarkAccess->findMark( sName ); + if( ppBkmk != pMarkAccess->getMarksEnd() && + ppBkmk->get()->GetMarkStart() == *pAttrPam->GetPoint() ) + break; // do not generate duplicates on this position + pAttrPam->DeleteMark(); + const ::sw::mark::IMark* const pNewMark = pMarkAccess->makeMark( + *pAttrPam, + sName, + IDocumentMarkAccess::BOOKMARK ); + + // jump to bookmark + if( JUMPTO_MARK == eJumpTo && pNewMark->GetName() == ::rtl::OUString(sJmpMark) ) + { + bChkJumpMark = TRUE; + eJumpTo = JUMPTO_NONE; + } + } + break; + case RES_TXTATR_FIELD: + { + USHORT nFldWhich = + pPostIts ? ((const SwFmtFld *)pAttr->pItem) + ->GetFld()->GetTyp()->Which() : 0; + if( pPostIts && (RES_POSTITFLD == nFldWhich || + RES_SCRIPTFLD == nFldWhich) ) + { + pPostIts->Insert( pAttr, 0 ); + } + else + { + aFields.Insert( pAttr, aFields.Count() ); + } + } + pAttrPam->DeleteMark(); + pAttr = pPrev; + continue; + + case RES_LR_SPACE: + if( pAttrPam->GetPoint()->nNode.GetIndex() == + pAttrPam->GetMark()->nNode.GetIndex() && + pCNd ) + { + // wegen Numerierungen dieses Attribut direkt + // am Node setzen + pCNd->SetAttr( *pAttr->pItem ); + break; + } + ASSERT( !this, + "LRSpace ueber mehrere Absaetze gesetzt!" ); + // kein break (hier sollen wir trotzdem nie hinkommen; + default: + + // ggfs. ein Bookmark anspringen + if( RES_TXTATR_INETFMT == nWhich && + JUMPTO_MARK == eJumpTo && + sJmpMark == ((SwFmtINetFmt*)pAttr->pItem)->GetName() ) + { + bChkJumpMark = TRUE; + eJumpTo = JUMPTO_NONE; + } + + pDoc->InsertPoolItem( *pAttrPam, *pAttr->pItem, nsSetAttrMode::SETATTR_DONTREPLACE ); + } + pAttrPam->DeleteMark(); + + delete pAttr; + pAttr = pPrev; + } + } + } + + for( n = aMoveFlyFrms.Count(); n; ) + { + SwFrmFmt *pFrmFmt = aMoveFlyFrms[ --n ]; + + const SwFmtAnchor& rAnchor = pFrmFmt->GetAnchor(); + ASSERT( FLY_AT_CNTNT==rAnchor.GetAnchorId(), + "Nur Auto-Rahmen brauchen eine Spezialbehandlung" ); + const SwPosition *pFlyPos = rAnchor.GetCntntAnchor(); + ULONG nFlyParaIdx = pFlyPos->nNode.GetIndex(); + BOOL bMoveFly; + if( bChkEnd ) + { + bMoveFly = nFlyParaIdx < rEndIdx.GetIndex() || + ( nFlyParaIdx == rEndIdx.GetIndex() && + aMoveFlyCnts[n] < nEndCnt ); + } + else + { + ULONG nEndOfIcons = pDoc->GetNodes().GetEndOfExtras().GetIndex(); + bMoveFly = nFlyParaIdx < rEndIdx.GetIndex() || + rEndIdx.GetIndex() > nEndOfIcons || + nFlyParaIdx <= nEndOfIcons; + } + if( bMoveFly ) + { + pFrmFmt->DelFrms(); + *pAttrPam->GetPoint() = *pFlyPos; + pAttrPam->GetPoint()->nContent.Assign( pAttrPam->GetCntntNode(), + aMoveFlyCnts[n] ); + SwFmtAnchor aAnchor( rAnchor ); + aAnchor.SetType( FLY_AUTO_CNTNT ); + aAnchor.SetAnchor( pAttrPam->GetPoint() ); + pFrmFmt->SetFmtAttr( aAnchor ); + + const SwFmtHoriOrient& rHoriOri = pFrmFmt->GetHoriOrient(); + if( text::HoriOrientation::LEFT == rHoriOri.GetHoriOrient() ) + { + SwFmtHoriOrient aHoriOri( rHoriOri ); + aHoriOri.SetRelationOrient( text::RelOrientation::CHAR ); + pFrmFmt->SetFmtAttr( aHoriOri ); + } + const SwFmtVertOrient& rVertOri = pFrmFmt->GetVertOrient(); + if( text::VertOrientation::TOP == rVertOri.GetVertOrient() ) + { + SwFmtVertOrient aVertOri( rVertOri ); + aVertOri.SetRelationOrient( text::RelOrientation::CHAR ); + pFrmFmt->SetFmtAttr( aVertOri ); + } + + pFrmFmt->MakeFrms(); + aMoveFlyFrms.Remove( n, 1 ); + aMoveFlyCnts.Remove( n, 1 ); + } + } + while( aFields.Count() ) + { + pAttr = aFields[0]; + + pCNd = pDoc->GetNodes()[ pAttr->nSttPara ]->GetCntntNode(); + pAttrPam->GetPoint()->nNode = pAttr->nSttPara; + pAttrPam->GetPoint()->nContent.Assign( pCNd, pAttr->nSttCntnt ); + + if( bBeforeTable && + pAttrPam->GetPoint()->nNode.GetIndex() == rEndIdx.GetIndex() ) + { + ASSERT( !bBeforeTable, "Aha, der Fall tritt also doch ein" ); + ASSERT( !pAttrPam->GetPoint()->nContent.GetIndex(), + "Content-Position vor Tabelle nicht 0???" ); + // !!! + pAttrPam->Move( fnMoveBackward ); + } + + pDoc->InsertPoolItem( *pAttrPam, *pAttr->pItem, 0 ); + + aFields.Remove( 0, 1 ); + delete pAttr; + } + + delete pAttrPam; +} + +void SwHTMLParser::NewAttr( _HTMLAttr **ppAttr, const SfxPoolItem& rItem ) +{ + // Font-Hoehen und -Farben- sowie Escapement-Attribute duerfen nicht + // zusammengefasst werden. Sie werden deshalb in einer Liste gespeichert, + // in der das zuletzt aufgespannte Attribut vorne steht und der Count + // immer 1 ist. Fuer alle anderen Attribute wird der Count einfach + // hochgezaehlt. + if( *ppAttr ) + { + _HTMLAttr *pAttr = new _HTMLAttr( *pPam->GetPoint(), rItem, + ppAttr ); + pAttr->InsertNext( *ppAttr ); + (*ppAttr) = pAttr; + } + else + (*ppAttr) = new _HTMLAttr( *pPam->GetPoint(), rItem, ppAttr ); +} + + +void SwHTMLParser::EndAttr( _HTMLAttr* pAttr, _HTMLAttr **ppDepAttr, + BOOL bChkEmpty ) +{ + ASSERT( !ppDepAttr, "SwHTMLParser::EndAttr: ppDepAttr-Feature ungetestet?" ); + // Der Listenkopf ist im Attribut gespeichert + _HTMLAttr **ppHead = pAttr->ppHead; + + ASSERT( ppHead, "keinen Attributs-Listenkopf gefunden!" ); + + // die aktuelle Psoition als Ende-Position merken + const SwNodeIndex* pEndIdx = &pPam->GetPoint()->nNode; + xub_StrLen nEndCnt = pPam->GetPoint()->nContent.GetIndex(); + + // WIrd das zueltzt gestartete oder ein frueher gestartetes Attribut + // beendet? + _HTMLAttr *pLast = 0; + if( ppHead && pAttr != *ppHead ) + { + // Es wird nicht das zuletzt gestartete Attribut beendet + + // Dann suche wir das unmittelbar danach gestartete Attribut, das + // ja ebenfalls noch nicht beendet wurde (sonst stuende es nicht + // mehr in der Liste + pLast = *ppHead; + while( pLast && pLast->GetNext() != pAttr ) + pLast = pLast->GetNext(); + + ASSERT( pLast, "Attribut nicht in eigener Liste gefunden!" ); + + // das Attribut nicht an der PaM-Psoition beenden, sondern da, + // wo das danch gestartete Attribut anfing??? + //pEndIdx = &pPrev->GetSttPara(); + //nEndCnt = pPrev->GetSttCnt(); + } + + BOOL bMoveBack = FALSE; + USHORT nWhich = pAttr->pItem->Which(); + if( /*!pLast &&*/ !nEndCnt && RES_PARATR_BEGIN <= nWhich && + *pEndIdx != pAttr->GetSttPara() ) + { + // dann eine Cntntnt Position zurueck! + bMoveBack = pPam->Move( fnMoveBackward ); + nEndCnt = pPam->GetPoint()->nContent.GetIndex(); + } + + // nun das Attrubut beenden + _HTMLAttr *pNext = pAttr->GetNext(); + + + sal_Bool bInsert; + sal_uInt16 nScriptItem = 0; + sal_Bool bScript = sal_False, bFont = sal_False; + // ein Bereich ?? + if( !bChkEmpty || (RES_PARATR_BEGIN <= nWhich && bMoveBack) || + RES_PAGEDESC == nWhich || RES_BREAK == nWhich || + *pEndIdx != pAttr->GetSttPara() || + nEndCnt != pAttr->GetSttCnt() ) + { + bInsert = sal_True; + // We do some optimization for script depenedent attribtes here. + if( *pEndIdx == pAttr->GetSttPara() ) + { + lcl_swhtml_getItemInfo( *pAttr, bScript, bFont, nScriptItem ); + } + } + else + { + bInsert = sal_False; + } + + if( bInsert && bScript ) + { + const SwTxtNode *pTxtNd = pAttr->GetSttPara().GetNode() + .GetTxtNode(); + ASSERT( pTxtNd, "No text node" ); + const String& rText = pTxtNd->GetTxt(); + sal_uInt16 nScriptTxt = pBreakIt->GetBreakIter()->getScriptType( + rText, pAttr->GetSttCnt() ); + xub_StrLen nScriptEnd = (xub_StrLen)pBreakIt->GetBreakIter() + ->endOfScript( rText, pAttr->GetSttCnt(), nScriptTxt ); + while( nScriptEnd < nEndCnt ) + { + if( nScriptItem == nScriptTxt ) + { + _HTMLAttr *pSetAttr = pAttr->Clone( *pEndIdx, nScriptEnd ); + pSetAttr->ClearPrev(); + if( pNext ) + pNext->InsertPrev( pSetAttr ); + else + { + USHORT nTmp = pSetAttr->bInsAtStart ? 0 + : aSetAttrTab.Count(); + aSetAttrTab.Insert( pSetAttr, nTmp ); + } + } + pAttr->nSttCntnt = nScriptEnd; + nScriptTxt = pBreakIt->GetBreakIter()->getScriptType( + rText, nScriptEnd ); + nScriptEnd = (xub_StrLen)pBreakIt->GetBreakIter() + ->endOfScript( rText, nScriptEnd, nScriptTxt ); + } + bInsert = nScriptItem == nScriptTxt; + } + if( bInsert ) + { + pAttr->nEndPara = *pEndIdx; + pAttr->nEndCntnt = nEndCnt; + pAttr->bInsAtStart = RES_TXTATR_INETFMT != nWhich && + RES_TXTATR_CHARFMT != nWhich; + + if( !pNext ) + { + // keine offenen Attribute dieses Typs mehr da, + // dann koennen alle gesetzt werden, es sei denn + // sie haengen noch von einem anderen Attribut ab, + // dann werden sie dort angehaengt + if( ppDepAttr && *ppDepAttr ) + (*ppDepAttr)->InsertPrev( pAttr ); + else + { + USHORT nTmp = pAttr->bInsAtStart ? 0 : aSetAttrTab.Count(); + aSetAttrTab.Insert( pAttr, nTmp ); + } + } + else + { + // es gibt noch andere offene Attribute des Typs, + // daher muss das Setzen zurueckgestellt werden. + // das aktuelle Attribut wird deshalb hinten an die + // Previous-Liste des Nachfolgers angehaengt + pNext->InsertPrev( pAttr ); + } + } + else + { + // dann nicht einfuegen, sondern Loeschen. Durch das "tuerken" von + // Vorlagen durch harte Attributierung koennen sich auch mal andere + // leere Attribute in der Prev-Liste befinden, die dann trotzdem + // gesetzt werden muessen + _HTMLAttr *pPrev = pAttr->GetPrev(); + delete pAttr; + + if( pPrev ) + { + // Die Previous-Attribute muessen trotzdem gesetzt werden. + if( pNext ) + pNext->InsertPrev( pPrev ); + else + { + USHORT nTmp = pPrev->bInsAtStart ? 0 : aSetAttrTab.Count(); + aSetAttrTab.Insert( pPrev, nTmp ); + } + } + + } + + // wenn das erste Attribut der Liste gesetzt wurde muss noch der + // Listenkopf korrigiert werden. + if( pLast ) + pLast->pNext = pNext; + else if( ppHead ) + *ppHead = pNext; + + if( bMoveBack ) + pPam->Move( fnMoveForward ); +} + +void SwHTMLParser::DeleteAttr( _HTMLAttr* pAttr ) +{ + // Hier darf es keine vorlauefigen Absatz-Attribute geben, den die + // koennten jetzt gesetzt werden und dann sind die Zeiger ungueltig!!! + ASSERT( !aParaAttrs.Count(), + "Hoechste Gefahr: Es gibt noch nicht-endgueltige Absatz-Attribute" ); + if( aParaAttrs.Count() ) + aParaAttrs.Remove( 0, aParaAttrs.Count() ); + + // Der Listenkopf ist im Attribut gespeichert + _HTMLAttr **ppHead = pAttr->ppHead; + + ASSERT( ppHead, "keinen Attributs-Listenkopf gefunden!" ); + + // Wird das zueltzt gestartete oder ein frueher gestartetes Attribut + // entfernt? + _HTMLAttr *pLast = 0; + if( ppHead && pAttr != *ppHead ) + { + // Es wird nicht das zuletzt gestartete Attribut beendet + + // Dann suche wir das unmittelbar danach gestartete Attribut, das + // ja ebenfalls noch nicht beendet wurde (sonst stuende es nicht + // mehr in der Liste + pLast = *ppHead; + while( pLast && pLast->GetNext() != pAttr ) + pLast = pLast->GetNext(); + + ASSERT( pLast, "Attribut nicht in eigener Liste gefunden!" ); + } + + // nun das Attrubut entfernen + _HTMLAttr *pNext = pAttr->GetNext(); + _HTMLAttr *pPrev = pAttr->GetPrev(); + delete pAttr; + + if( pPrev ) + { + // Die Previous-Attribute muessen trotzdem gesetzt werden. + if( pNext ) + pNext->InsertPrev( pPrev ); + else + { + USHORT nTmp = pPrev->bInsAtStart ? 0 : aSetAttrTab.Count(); + aSetAttrTab.Insert( pPrev, nTmp ); + } + } + + // wenn das erste Attribut der Liste entfernt wurde muss noch der + // Listenkopf korrigiert werden. + if( pLast ) + pLast->pNext = pNext; + else if( ppHead ) + *ppHead = pNext; +} + +void SwHTMLParser::SaveAttrTab( _HTMLAttrTable& rNewAttrTab ) +{ + // Hier darf es keine vorlauefigen Absatz-Attribute geben, den die + // koennten jetzt gesetzt werden und dann sind die Zeiger ungueltig!!! + ASSERT( !aParaAttrs.Count(), + "Hoechste Gefahr: Es gibt noch nicht-endgueltige Absatz-Attribute" ); + if( aParaAttrs.Count() ) + aParaAttrs.Remove( 0, aParaAttrs.Count() ); + + _HTMLAttr** pTbl = (_HTMLAttr**)&aAttrTab; + _HTMLAttr** pSaveTbl = (_HTMLAttr**)&rNewAttrTab; + + for( USHORT nCnt = sizeof( _HTMLAttrTable ) / sizeof( _HTMLAttr* ); + nCnt--; (++pTbl, ++pSaveTbl) ) + { + *pSaveTbl = *pTbl; + + _HTMLAttr *pAttr = *pSaveTbl; + while( pAttr ) + { + pAttr->SetHead( pSaveTbl ); + pAttr = pAttr->GetNext(); + } + + *pTbl = 0; + } +} + +void SwHTMLParser::SplitAttrTab( _HTMLAttrTable& rNewAttrTab, + BOOL bMoveEndBack ) +{ + // Hier darf es keine vorlauefigen Absatz-Attribute geben, den die + // koennten jetzt gesetzt werden und dann sind die Zeiger ungueltig!!! + ASSERT( !aParaAttrs.Count(), + "Hoechste Gefahr: Es gibt noch nicht-endgueltige Absatz-Attribute" ); + if( aParaAttrs.Count() ) + aParaAttrs.Remove( 0, aParaAttrs.Count() ); + + const SwNodeIndex& nSttIdx = pPam->GetPoint()->nNode; + SwNodeIndex nEndIdx( nSttIdx ); + + // alle noch offenen Attribute beenden und hinter der Tabelle + // neu aufspannen + _HTMLAttr** pTbl = (_HTMLAttr**)&aAttrTab; + _HTMLAttr** pSaveTbl = (_HTMLAttr**)&rNewAttrTab; + BOOL bSetAttr = TRUE; + xub_StrLen nSttCnt = pPam->GetPoint()->nContent.GetIndex(); + xub_StrLen nEndCnt = nSttCnt; + + if( bMoveEndBack ) + { + ULONG nOldEnd = nEndIdx.GetIndex(); + ULONG nTmpIdx; + if( ( nTmpIdx = pDoc->GetNodes().GetEndOfExtras().GetIndex()) >= nOldEnd || + ( nTmpIdx = pDoc->GetNodes().GetEndOfAutotext().GetIndex()) >= nOldEnd ) + { + nTmpIdx = pDoc->GetNodes().GetEndOfInserts().GetIndex(); + } + SwCntntNode* pCNd = pDoc->GetNodes().GoPrevious(&nEndIdx); + + // keine Attribute setzen, wenn der PaM aus dem Content-Bereich + // herausgeschoben wurde. + bSetAttr = pCNd && nTmpIdx < nEndIdx.GetIndex(); + + nEndCnt = (bSetAttr ? pCNd->Len() : 0); + } + for( USHORT nCnt = sizeof( _HTMLAttrTable ) / sizeof( _HTMLAttr* ); + nCnt--; (++pTbl, ++pSaveTbl) ) + { + _HTMLAttr *pAttr = *pTbl; + *pSaveTbl = 0; + while( pAttr ) + { + _HTMLAttr *pNext = pAttr->GetNext(); + _HTMLAttr *pPrev = pAttr->GetPrev(); + + if( bSetAttr && + ( pAttr->GetSttParaIdx() < nEndIdx.GetIndex() || + (pAttr->GetSttPara() == nEndIdx && + pAttr->GetSttCnt() != nEndCnt) ) ) + { + // das Attribut muss vor der Liste gesetzt werden. Da wir + // das Original noch brauchen, weil Zeiger auf das Attribut + // noch in den Kontexten existieren, muessen wir es clonen. + // Die Next-Liste geht dabei verloren, aber die + // Previous-Liste bleibt erhalten + _HTMLAttr *pSetAttr = pAttr->Clone( nEndIdx, nEndCnt ); + + if( pNext ) + pNext->InsertPrev( pSetAttr ); + else + { + USHORT nTmp = pSetAttr->bInsAtStart ? 0 + : aSetAttrTab.Count(); + aSetAttrTab.Insert( pSetAttr, nTmp ); + } + } + else if( pPrev ) + { + // Wenn das Attribut nicht gesetzt vor der Tabelle + // gesetzt werden muss, muessen der Previous-Attribute + // trotzdem gesetzt werden. + if( pNext ) + pNext->InsertPrev( pPrev ); + else + { + USHORT nTmp = pPrev->bInsAtStart ? 0 : aSetAttrTab.Count(); + aSetAttrTab.Insert( pPrev, nTmp ); + } + } + + // den Start des Attributs neu setzen und die Verkettungen + // aufbrechen + pAttr->Reset( nSttIdx, nSttCnt, pSaveTbl ); + + if( *pSaveTbl ) + { + _HTMLAttr *pSAttr = *pSaveTbl; + while( pSAttr->GetNext() ) + pSAttr = pSAttr->GetNext(); + pSAttr->InsertNext( pAttr ); + } + else + *pSaveTbl = pAttr; + + pAttr = pNext; + } + + *pTbl = 0; + } +} + +void SwHTMLParser::RestoreAttrTab( const _HTMLAttrTable& rNewAttrTab, + BOOL bSetNewStart ) +{ + // Hier darf es keine vorlauefigen Absatz-Attribute geben, den die + // koennten jetzt gesetzt werden und dann sind die Zeiger ungueltig!!! + ASSERT( !aParaAttrs.Count(), + "Hoechste Gefahr: Es gibt noch nicht-endgueltige Absatz-Attribute" ); + if( aParaAttrs.Count() ) + aParaAttrs.Remove( 0, aParaAttrs.Count() ); + + _HTMLAttr** pTbl = (_HTMLAttr**)&aAttrTab; + _HTMLAttr** pSaveTbl = (_HTMLAttr**)&rNewAttrTab; + + for( USHORT nCnt = sizeof( _HTMLAttrTable ) / sizeof( _HTMLAttr* ); + nCnt--; (++pTbl, ++pSaveTbl) ) + { + ASSERT( !*pTbl, "Die Attribut-Tabelle ist nicht leer!" ); + + const SwPosition *pPos = pPam->GetPoint(); + const SwNodeIndex& rSttPara = pPos->nNode; + xub_StrLen nSttCnt = pPos->nContent.GetIndex(); + + *pTbl = *pSaveTbl; + + _HTMLAttr *pAttr = *pTbl; + while( pAttr ) + { + ASSERT( !pAttr->GetPrev() || !pAttr->GetPrev()->ppHead, + "Previous-Attribut hat noch einen Header" ); + pAttr->SetHead( pTbl ); + if( bSetNewStart ) + { + pAttr->nSttPara = rSttPara; + pAttr->nEndPara = rSttPara; + pAttr->nSttCntnt = nSttCnt; + pAttr->nEndCntnt = nSttCnt; + } + pAttr = pAttr->GetNext(); + } + + *pSaveTbl = 0; + } +} + +void SwHTMLParser::InsertAttr( const SfxPoolItem& rItem, BOOL bLikePara, + BOOL bInsAtStart ) +{ + _HTMLAttr* pTmp = new _HTMLAttr( *pPam->GetPoint(), + rItem ); + if( bLikePara ) + pTmp->SetLikePara(); + USHORT nTmp = bInsAtStart ? 0 : aSetAttrTab.Count(); + aSetAttrTab.Insert( pTmp, nTmp ); +} + +void SwHTMLParser::InsertAttrs( _HTMLAttrs& rAttrs ) +{ + while( rAttrs.Count() ) + { + _HTMLAttr *pAttr = rAttrs[0]; + InsertAttr( pAttr->GetItem() ); + rAttrs.Remove( 0, 1 ); + delete pAttr; + } +} + +/* */ + +void SwHTMLParser::NewStdAttr( int nToken ) +{ + String aId, aStyle, aClass, aLang, aDir; + + const HTMLOptions *pHTMLOptions = GetOptions(); + for( USHORT i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + case HTML_O_LANG: + aLang = pOption->GetString(); + break; + case HTML_O_DIR: + aDir = pOption->GetString(); + break; + } + } + + // einen neuen Kontext anlegen + _HTMLAttrContext *pCntxt = new _HTMLAttrContext( static_cast< sal_uInt16 >(nToken) ); + + // Styles parsen + if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) ) + { + SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + + if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) ) + { + if( HTML_SPAN_ON != nToken || !aClass.Len() || + !CreateContainer( aClass, aItemSet, aPropInfo, pCntxt ) ) + DoPositioning( aItemSet, aPropInfo, pCntxt ); + InsertAttrs( aItemSet, aPropInfo, pCntxt, TRUE ); + } + } + + // den Kontext merken + PushContext( pCntxt ); +} + +void SwHTMLParser::NewStdAttr( int nToken, + _HTMLAttr **ppAttr, const SfxPoolItem & rItem, + _HTMLAttr **ppAttr2, const SfxPoolItem *pItem2, + _HTMLAttr **ppAttr3, const SfxPoolItem *pItem3 ) +{ + String aId, aStyle, aClass, aLang, aDir; + + const HTMLOptions *pHTMLOptions = GetOptions(); + for( USHORT i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + case HTML_O_LANG: + aLang = pOption->GetString(); + break; + case HTML_O_DIR: + aDir = pOption->GetString(); + break; + } + } + + // einen neuen Kontext anlegen + _HTMLAttrContext *pCntxt = new _HTMLAttrContext( static_cast< sal_uInt16 >(nToken) ); + + // Styles parsen + if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) ) + { + SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + + aItemSet.Put( rItem ); + if( pItem2 ) + aItemSet.Put( *pItem2 ); + if( pItem3 ) + aItemSet.Put( *pItem3 ); + + if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) ) + DoPositioning( aItemSet, aPropInfo, pCntxt ); + + InsertAttrs( aItemSet, aPropInfo, pCntxt, TRUE ); + } + else + { + InsertAttr( ppAttr ,rItem, pCntxt ); + if( pItem2 ) + { + ASSERT( ppAttr2, "missing table entry for item2" ); + InsertAttr( ppAttr2, *pItem2, pCntxt ); + } + if( pItem3 ) + { + ASSERT( ppAttr3, "missing table entry for item3" ); + InsertAttr( ppAttr3, *pItem3, pCntxt ); + } + } + + // den Kontext merken + PushContext( pCntxt ); +} + +void SwHTMLParser::EndTag( int nToken ) +{ + // den Kontext holen + _HTMLAttrContext *pCntxt = PopContext( static_cast< sal_uInt16 >(nToken & ~1) ); + if( pCntxt ) + { + // und ggf. die Attribute beenden + EndContext( pCntxt ); + delete pCntxt; + } +} + + +void SwHTMLParser::NewBasefontAttr() +{ + String aId, aStyle, aClass, aLang, aDir; + USHORT nSize = 3; + + const HTMLOptions *pHTMLOptions = GetOptions(); + for( USHORT i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_SIZE: + nSize = (USHORT)pOption->GetNumber(); + break; + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + case HTML_O_LANG: + aLang = pOption->GetString(); + break; + case HTML_O_DIR: + aDir = pOption->GetString(); + break; + } + } + + if( nSize < 1 ) + nSize = 1; + + if( nSize > 7 ) + nSize = 7; + + // einen neuen Kontext anlegen + _HTMLAttrContext *pCntxt = new _HTMLAttrContext( HTML_BASEFONT_ON ); + + // Styles parsen + if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) ) + { + SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + + SvxFontHeightItem aFontHeight( aFontHeights[nSize-1], 100, RES_CHRATR_FONTSIZE ); + aItemSet.Put( aFontHeight ); + aFontHeight.SetWhich( RES_CHRATR_CJK_FONTSIZE ); + aItemSet.Put( aFontHeight ); + aFontHeight.SetWhich( RES_CHRATR_CTL_FONTSIZE ); + aItemSet.Put( aFontHeight ); + + if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) ) + DoPositioning( aItemSet, aPropInfo, pCntxt ); + + InsertAttrs( aItemSet, aPropInfo, pCntxt, TRUE ); + } + else + { + SvxFontHeightItem aFontHeight( aFontHeights[nSize-1], 100, RES_CHRATR_FONTSIZE ); + InsertAttr( &aAttrTab.pFontHeight, aFontHeight, pCntxt ); + aFontHeight.SetWhich( RES_CHRATR_CJK_FONTSIZE ); + InsertAttr( &aAttrTab.pFontHeightCJK, aFontHeight, pCntxt ); + aFontHeight.SetWhich( RES_CHRATR_CTL_FONTSIZE ); + InsertAttr( &aAttrTab.pFontHeightCTL, aFontHeight, pCntxt ); + } + + // den Kontext merken + PushContext( pCntxt ); + + // die Font-Size merken + aBaseFontStack.Insert( nSize, aBaseFontStack.Count() ); +} + +void SwHTMLParser::EndBasefontAttr() +{ + EndTag( HTML_BASEFONT_ON ); + + // Stack-Unterlauf in Tabellen vermeiden + if( aBaseFontStack.Count() > nBaseFontStMin ) + aBaseFontStack.Remove( aBaseFontStack.Count()-1, 1 ); +} + +void SwHTMLParser::NewFontAttr( int nToken ) +{ + USHORT nBaseSize = + ( aBaseFontStack.Count() > nBaseFontStMin + ? (aBaseFontStack[aBaseFontStack.Count()-1] & FONTSIZE_MASK) + : 3 ); + USHORT nFontSize = + ( aFontStack.Count() > nFontStMin + ? (aFontStack[aFontStack.Count()-1] & FONTSIZE_MASK) + : nBaseSize ); + + String aFace, aId, aStyle, aClass, aLang, aDir; + Color aColor; + ULONG nFontHeight = 0; // tatsaechlich einzustellende Font-Hoehe + USHORT nSize = 0; // Fontgroesse in Netscape-Notation (1-7) + BOOL bColor = FALSE; + + const HTMLOptions *pHTMLOptions = GetOptions(); + for( USHORT i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_SIZE: + if( HTML_FONT_ON==nToken && pOption->GetString().Len() ) + { + INT32 nSSize; + if( '+' == pOption->GetString().GetChar(0) || + '-' == pOption->GetString().GetChar(0) ) + nSSize = nBaseSize + pOption->GetSNumber(); + else + nSSize = (INT32)pOption->GetNumber(); + + if( nSSize < 1 ) + nSSize = 1; + else if( nSSize > 7 ) + nSSize = 7; + + nSize = (USHORT)nSSize; + nFontHeight = aFontHeights[nSize-1]; + } + break; + case HTML_O_COLOR: + if( HTML_FONT_ON==nToken ) + { + pOption->GetColor( aColor ); + bColor = TRUE; + } + break; + case HTML_O_FACE: + if( HTML_FONT_ON==nToken ) + aFace = pOption->GetString(); + break; + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + case HTML_O_LANG: + aLang = pOption->GetString(); + break; + case HTML_O_DIR: + aDir = pOption->GetString(); + break; + } + } + + if( HTML_FONT_ON != nToken ) + { + // HTML_BIGPRINT_ON oder HTML_SMALLPRINT_ON + + // in Ueberschriften bestimmt die aktuelle Ueberschrift + // die Font-Hoehe und nicht BASEFONT + USHORT nPoolId = GetCurrFmtColl()->GetPoolFmtId(); + if( (nPoolId>=RES_POOLCOLL_HEADLINE1 && + nPoolId<=RES_POOLCOLL_HEADLINE6) ) + { + // wenn die Schriftgroesse in der Ueberschrift noch + // nicht veraendert ist, die aus der Vorlage nehmen + if( nFontStHeadStart==aFontStack.Count() ) + nFontSize = static_cast< USHORT >(6 - (nPoolId - RES_POOLCOLL_HEADLINE1)); + } + else + nPoolId = 0; + + if( HTML_BIGPRINT_ON == nToken ) + nSize = ( nFontSize<7 ? nFontSize+1 : 7 ); + else + nSize = ( nFontSize>1 ? nFontSize-1 : 1 ); + + // in Ueberschriften wird die neue Fonthoehe wenn moeglich aus + // den Vorlagen geholt. + if( nPoolId && nSize>=1 && nSize <=6 ) + nFontHeight = + pCSS1Parser->GetTxtCollFromPool( + RES_POOLCOLL_HEADLINE1+6-nSize )->GetSize().GetHeight(); + else + nFontHeight = aFontHeights[nSize-1]; + } + + ASSERT( !nSize == !nFontHeight, "HTML-Font-Size != Font-Height" ); + + String aFontName, aStyleName; + FontFamily eFamily = FAMILY_DONTKNOW; // Family und Pitch, + FontPitch ePitch = PITCH_DONTKNOW; // falls nicht gefunden + rtl_TextEncoding eEnc = gsl_getSystemTextEncoding(); + + if( aFace.Len() && !pCSS1Parser->IsIgnoreFontFamily() ) + { + const FontList *pFList = 0; + SwDocShell *pDocSh = pDoc->GetDocShell(); + if( pDocSh ) + { + const SvxFontListItem *pFListItem = + (const SvxFontListItem *)pDocSh->GetItem(SID_ATTR_CHAR_FONTLIST); + if( pFListItem ) + pFList = pFListItem->GetFontList(); + } + + BOOL bFound = FALSE; + xub_StrLen nStrPos = 0; + while( nStrPos!=STRING_NOTFOUND ) + { + String aFName = aFace.GetToken( 0, ',', nStrPos ); + aFName.EraseTrailingChars().EraseLeadingChars(); + if( aFName.Len() ) + { + if( !bFound && pFList ) + { + sal_Handle hFont = pFList->GetFirstFontInfo( aFName ); + if( 0 != hFont ) + { + const FontInfo& rFInfo = pFList->GetFontInfo( hFont ); + if( RTL_TEXTENCODING_DONTKNOW != rFInfo.GetCharSet() ) + { + bFound = TRUE; + if( RTL_TEXTENCODING_SYMBOL == rFInfo.GetCharSet() ) + eEnc = RTL_TEXTENCODING_SYMBOL; + } + } + } + if( aFontName.Len() ) + aFontName += ';'; + aFontName += aFName; + } + } + } + + + // einen neuen Kontext anlegen + _HTMLAttrContext *pCntxt = new _HTMLAttrContext( static_cast< sal_uInt16 >(nToken) ); + + // Styles parsen + if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) ) + { + SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + + if( nFontHeight ) + { + SvxFontHeightItem aFontHeight( nFontHeight, 100, RES_CHRATR_FONTSIZE ); + aItemSet.Put( aFontHeight ); + aFontHeight.SetWhich( RES_CHRATR_CJK_FONTSIZE ); + aItemSet.Put( aFontHeight ); + aFontHeight.SetWhich( RES_CHRATR_CTL_FONTSIZE ); + aItemSet.Put( aFontHeight ); + } + if( bColor ) + aItemSet.Put( SvxColorItem(aColor, RES_CHRATR_COLOR) ); + if( aFontName.Len() ) + { + SvxFontItem aFont( eFamily, aFontName, aStyleName, ePitch, eEnc, RES_CHRATR_FONT ); + aItemSet.Put( aFont ); + aFont.SetWhich( RES_CHRATR_CJK_FONT ); + aItemSet.Put( aFont ); + aFont.SetWhich( RES_CHRATR_CTL_FONT ); + aItemSet.Put( aFont ); + } + + + if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) ) + DoPositioning( aItemSet, aPropInfo, pCntxt ); + + InsertAttrs( aItemSet, aPropInfo, pCntxt, TRUE ); + } + else + { + if( nFontHeight ) + { + SvxFontHeightItem aFontHeight( nFontHeight, 100, RES_CHRATR_FONTSIZE ); + InsertAttr( &aAttrTab.pFontHeight, aFontHeight, pCntxt ); + aFontHeight.SetWhich( RES_CHRATR_CJK_FONTSIZE ); + InsertAttr( &aAttrTab.pFontHeightCJK, aFontHeight, pCntxt ); + aFontHeight.SetWhich( RES_CHRATR_CTL_FONTSIZE ); + InsertAttr( &aAttrTab.pFontHeightCTL, aFontHeight, pCntxt ); + } + if( bColor ) + InsertAttr( &aAttrTab.pFontColor, SvxColorItem(aColor, RES_CHRATR_COLOR), pCntxt ); + if( aFontName.Len() ) + { + SvxFontItem aFont( eFamily, aFontName, aStyleName, ePitch, eEnc, RES_CHRATR_FONT ); + InsertAttr( &aAttrTab.pFont, aFont, pCntxt ); + aFont.SetWhich( RES_CHRATR_CJK_FONT ); + InsertAttr( &aAttrTab.pFontCJK, aFont, pCntxt ); + aFont.SetWhich( RES_CHRATR_CTL_FONT ); + InsertAttr( &aAttrTab.pFontCTL, aFont, pCntxt ); + } + } + + // den Kontext merken + PushContext( pCntxt ); + + aFontStack.Insert( nSize, aFontStack.Count() ); +} + +void SwHTMLParser::EndFontAttr( int nToken ) +{ + EndTag( nToken ); + + // Stack-Unterlauf in Tabellen vermeiden + if( aFontStack.Count() > nFontStMin ) + aFontStack.Remove( aFontStack.Count()-1, 1 ); +} + +/* */ + +void SwHTMLParser::NewPara() +{ + if( pPam->GetPoint()->nContent.GetIndex() ) + AppendTxtNode( AM_SPACE ); + else + AddParSpace(); + + eParaAdjust = SVX_ADJUST_END; + String aId, aStyle, aClass, aLang, aDir; + + const HTMLOptions *pHTMLOptions = GetOptions(); + for( USHORT i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_ALIGN: + eParaAdjust = (SvxAdjust)pOption->GetEnum( aHTMLPAlignTable, static_cast< sal_uInt16 >(eParaAdjust) ); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + case HTML_O_LANG: + aLang = pOption->GetString(); + break; + case HTML_O_DIR: + aDir = pOption->GetString(); + break; + } + } + + // einen neuen Kontext anlegen + _HTMLAttrContext *pCntxt = + aClass.Len() ? new _HTMLAttrContext( HTML_PARABREAK_ON, + RES_POOLCOLL_TEXT, aClass ) + : new _HTMLAttrContext( HTML_PARABREAK_ON ); + + // Styles parsen (Class nicht beruecksichtigen. Das geht nur, solange + // keine der CSS1-Properties der Klasse hart formatiert werden muss!!!) + if( HasStyleOptions( aStyle, aId, aEmptyStr, &aLang, &aDir ) ) + { + SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + + if( ParseStyleOptions( aStyle, aId, aEmptyStr, aItemSet, aPropInfo, &aLang, &aDir ) ) + { + ASSERT( !aClass.Len() || !pCSS1Parser->GetClass( aClass ), + "Class wird nicht beruecksichtigt" ); + DoPositioning( aItemSet, aPropInfo, pCntxt ); + InsertAttrs( aItemSet, aPropInfo, pCntxt ); + } + } + + if( SVX_ADJUST_END != eParaAdjust ) + InsertAttr( &aAttrTab.pAdjust, SvxAdjustItem(eParaAdjust, RES_PARATR_ADJUST), pCntxt ); + + // und auf den Stack packen + PushContext( pCntxt ); + + // die aktuelle Vorlage oder deren Attribute setzen + SetTxtCollAttrs( aClass.Len() ? pCntxt : 0 ); + + // Laufbalkenanzeige + ShowStatline(); + + ASSERT( !nOpenParaToken, "Jetzt geht ein offenes Absatz-Element verloren" ); + nOpenParaToken = HTML_PARABREAK_ON; +} + +void SwHTMLParser::EndPara( BOOL bReal ) +{ + if( HTML_LI_ON==nOpenParaToken && pTable ) + { +#ifndef PRODUCT + const SwNumRule *pNumRule = pPam->GetNode()->GetTxtNode()->GetNumRule(); +#endif + ASSERT( pNumRule, "Wo ist die Numrule geblieben" ); + } + + // leere Absaetze werden von Netscape uebersprungen, von uns jetzt auch + if( bReal ) + { + if( pPam->GetPoint()->nContent.GetIndex() ) + AppendTxtNode( AM_SPACE ); + else + AddParSpace(); + } + + // wenn ein DD oder DT offen war, handelt es sich um eine + // implizite Def-Liste, die jetzt beendet werden muss + if( (nOpenParaToken==HTML_DT_ON || nOpenParaToken==HTML_DD_ON) && + nDefListDeep) + { + nDefListDeep--; + } + + // den Kontext vom Stack holen. Er kann auch von einer implizit + // geoeffneten Definitionsliste kommen + _HTMLAttrContext *pCntxt = + PopContext( static_cast< sal_uInt16 >(nOpenParaToken ? (nOpenParaToken & ~1) + : HTML_PARABREAK_ON) ); + + // Attribute beenden + if( pCntxt ) + { + EndContext( pCntxt ); + SetAttr(); // Absatz-Atts wegen JavaScript moeglichst schnell setzen + delete pCntxt; + } + + // und die bisherige Vorlage neu setzen + if( bReal ) + SetTxtCollAttrs(); + + nOpenParaToken = 0; +} + + +void SwHTMLParser::NewHeading( int nToken ) +{ + eParaAdjust = SVX_ADJUST_END; + + String aId, aStyle, aClass, aLang, aDir; + + const HTMLOptions *pHTMLOptions = GetOptions(); + for( USHORT i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_ALIGN: + eParaAdjust = (SvxAdjust)pOption->GetEnum( aHTMLPAlignTable, static_cast< sal_uInt16 >(eParaAdjust) ); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + case HTML_O_LANG: + aLang = pOption->GetString(); + break; + case HTML_O_DIR: + aDir = pOption->GetString(); + break; + } + } + + // einen neuen Absatz aufmachen + if( pPam->GetPoint()->nContent.GetIndex() ) + AppendTxtNode( AM_SPACE ); + else + AddParSpace(); + + // die passende Vorlage suchen + USHORT nTxtColl; + switch( nToken ) + { + case HTML_HEAD1_ON: nTxtColl = RES_POOLCOLL_HEADLINE1; break; + case HTML_HEAD2_ON: nTxtColl = RES_POOLCOLL_HEADLINE2; break; + case HTML_HEAD3_ON: nTxtColl = RES_POOLCOLL_HEADLINE3; break; + case HTML_HEAD4_ON: nTxtColl = RES_POOLCOLL_HEADLINE4; break; + case HTML_HEAD5_ON: nTxtColl = RES_POOLCOLL_HEADLINE5; break; + case HTML_HEAD6_ON: nTxtColl = RES_POOLCOLL_HEADLINE6; break; + default: nTxtColl = RES_POOLCOLL_STANDARD; break; + } + + // den Kontext anlegen + _HTMLAttrContext *pCntxt = new _HTMLAttrContext( static_cast< sal_uInt16 >(nToken), nTxtColl, aClass ); + + // Styles parsen (zu Class siehe auch NewPara) + if( HasStyleOptions( aStyle, aId, aEmptyStr, &aLang, &aDir ) ) + { + SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + + if( ParseStyleOptions( aStyle, aId, aEmptyStr, aItemSet, aPropInfo, &aLang, &aDir ) ) + { + ASSERT( !aClass.Len() || !pCSS1Parser->GetClass( aClass ), + "Class wird nicht beruecksichtigt" ); + DoPositioning( aItemSet, aPropInfo, pCntxt ); + InsertAttrs( aItemSet, aPropInfo, pCntxt ); + } + } + + if( SVX_ADJUST_END != eParaAdjust ) + InsertAttr( &aAttrTab.pAdjust, SvxAdjustItem(eParaAdjust, RES_PARATR_ADJUST), pCntxt ); + + // udn auf den Stack packen + PushContext( pCntxt ); + + // und die Vorlage oder deren Attribute setzen + SetTxtCollAttrs( pCntxt ); + + nFontStHeadStart = aFontStack.Count(); + + // Laufbalkenanzeige + ShowStatline(); +} + +void SwHTMLParser::EndHeading() +{ + // einen neuen Absatz aufmachen + if( pPam->GetPoint()->nContent.GetIndex() ) + AppendTxtNode( AM_SPACE ); + else + AddParSpace(); + + // Kontext zu dem Token suchen und vom Stack holen + _HTMLAttrContext *pCntxt = 0; + USHORT nPos = aContexts.Count(); + while( !pCntxt && nPos>nContextStMin ) + { + switch( aContexts[--nPos]->GetToken() ) + { + case HTML_HEAD1_ON: + case HTML_HEAD2_ON: + case HTML_HEAD3_ON: + case HTML_HEAD4_ON: + case HTML_HEAD5_ON: + case HTML_HEAD6_ON: + pCntxt = aContexts[nPos]; + aContexts.Remove( nPos, 1 ); + break; + } + } + + // und noch Attribute beenden + if( pCntxt ) + { + EndContext( pCntxt ); + SetAttr(); // Absatz-Atts wegen JavaScript moeglichst schnell setzen + delete pCntxt; + } + + // die bisherige Vorlage neu setzen + SetTxtCollAttrs(); + + nFontStHeadStart = nFontStMin; +} + +/* */ + +void SwHTMLParser::NewTxtFmtColl( int nToken, USHORT nColl ) +{ + String aId, aStyle, aClass, aLang, aDir; + + const HTMLOptions *pHTMLOptions = GetOptions(); + for( USHORT i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + case HTML_O_LANG: + aLang = pOption->GetString(); + break; + case HTML_O_DIR: + aDir = pOption->GetString(); + break; + } + } + + // einen neuen Absatz aufmachen + SwHTMLAppendMode eMode = AM_NORMAL; + switch( nToken ) + { + case HTML_LISTING_ON: + case HTML_XMP_ON: + // Diese beiden Tags werden jetzt auf die PRE-Vorlage gemappt. + // Fuer dem Fall, dass ein CLASS angegeben ist, loeschen wir + // es damit wir nicht die CLASS der PRE-Vorlage bekommen. + aClass = aEmptyStr; + case HTML_BLOCKQUOTE_ON: + case HTML_BLOCKQUOTE30_ON: + case HTML_PREFORMTXT_ON: + eMode = AM_SPACE; + break; + case HTML_ADDRESS_ON: + eMode = AM_NOSPACE; // ADDRESS kann auf einen <P> ohne </P> folgen + break; + case HTML_DT_ON: + case HTML_DD_ON: + eMode = AM_SOFTNOSPACE; + break; + default: + ASSERT( !this, "unbekannte Vorlage" ); + break; + } + if( pPam->GetPoint()->nContent.GetIndex() ) + AppendTxtNode( eMode ); + else if( AM_SPACE==eMode ) + AddParSpace(); + + // ... und in einem Kontext merken + _HTMLAttrContext *pCntxt = new _HTMLAttrContext( static_cast< sal_uInt16 >(nToken), nColl, aClass ); + + // Styles parsen (zu Class siehe auch NewPara) + if( HasStyleOptions( aStyle, aId, aEmptyStr, &aLang, &aDir ) ) + { + SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + + if( ParseStyleOptions( aStyle, aId, aEmptyStr, aItemSet, aPropInfo, &aLang, &aDir ) ) + { + ASSERT( !aClass.Len() || !pCSS1Parser->GetClass( aClass ), + "Class wird nicht beruecksichtigt" ); + DoPositioning( aItemSet, aPropInfo, pCntxt ); + InsertAttrs( aItemSet, aPropInfo, pCntxt ); + } + } + + PushContext( pCntxt ); + + // die neue Vorlage setzen + SetTxtCollAttrs( pCntxt ); + + // Laufbalkenanzeige aktualisieren + ShowStatline(); +} + +void SwHTMLParser::EndTxtFmtColl( int nToken ) +{ + SwHTMLAppendMode eMode = AM_NORMAL; + switch( nToken & ~1 ) + { + case HTML_BLOCKQUOTE_ON: + case HTML_BLOCKQUOTE30_ON: + case HTML_PREFORMTXT_ON: + case HTML_LISTING_ON: + case HTML_XMP_ON: + eMode = AM_SPACE; + break; + case HTML_ADDRESS_ON: + case HTML_DT_ON: + case HTML_DD_ON: + eMode = AM_SOFTNOSPACE; + break; + default: + ASSERT( !this, "unbekannte Vorlage" ); + break; + } + if( pPam->GetPoint()->nContent.GetIndex() ) + AppendTxtNode( eMode ); + else if( AM_SPACE==eMode ) + AddParSpace(); + + // den aktuellen Kontext vom Stack holen + _HTMLAttrContext *pCntxt = PopContext( static_cast< sal_uInt16 >(nToken & ~1) ); + + // und noch Attribute beenden + if( pCntxt ) + { + EndContext( pCntxt ); + SetAttr(); // Absatz-Atts wegen JavaScript moeglichst schnell setzen + delete pCntxt; + } + + // und die bisherige Vorlage setzen + SetTxtCollAttrs(); +} + +/* */ + +void SwHTMLParser::NewDefList() +{ + String aId, aStyle, aClass, aLang, aDir; + + const HTMLOptions *pHTMLOptions = GetOptions(); + for( USHORT i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + case HTML_O_LANG: + aLang = pOption->GetString(); + break; + case HTML_O_DIR: + aDir = pOption->GetString(); + break; + } + } + + // einen neuen Absatz aufmachen + BOOL bSpace = (GetNumInfo().GetDepth() + nDefListDeep) == 0; + if( pPam->GetPoint()->nContent.GetIndex() ) + AppendTxtNode( bSpace ? AM_SPACE : AM_SOFTNOSPACE ); + else if( bSpace ) + AddParSpace(); + + // ein Level mehr + nDefListDeep++; + + + BOOL bInDD = FALSE, bNotInDD = FALSE; + USHORT nPos = aContexts.Count(); + while( !bInDD && !bNotInDD && nPos>nContextStMin ) + { + USHORT nCntxtToken = aContexts[--nPos]->GetToken(); + switch( nCntxtToken ) + { + case HTML_DEFLIST_ON: + case HTML_DIRLIST_ON: + case HTML_MENULIST_ON: + case HTML_ORDERLIST_ON: + case HTML_UNORDERLIST_ON: + bNotInDD = TRUE; + break; + case HTML_DD_ON: + bInDD = TRUE; + break; + } + } + + + // ... und in einem Kontext merken + _HTMLAttrContext *pCntxt = new _HTMLAttrContext( HTML_DEFLIST_ON ); + + // darin auch die Raender merken + sal_uInt16 nLeft=0, nRight=0; + short nIndent=0; + GetMarginsFromContext( nLeft, nRight, nIndent ); + + // Die Einrueckung, die sich schon aus einem DL-ergibt, entspricht der + // eines DT auf dem aktuellen Level, und die entspricht der eines + // DD auf dem Level davor. Fue einen Level >=2 muss also ein DD-Abstand + // hinzugefuegt werden + if( !bInDD && nDefListDeep > 1 ) + { + + // und den der DT-Vorlage des aktuellen Levels + SvxLRSpaceItem rLRSpace = + pCSS1Parser->GetTxtFmtColl( RES_POOLCOLL_HTML_DD, aEmptyStr ) + ->GetLRSpace(); + nLeft = nLeft + static_cast< sal_uInt16 >(rLRSpace.GetTxtLeft()); + } + + pCntxt->SetMargins( nLeft, nRight, nIndent ); + + // Styles parsen + if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) ) + { + SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + + if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) ) + { + DoPositioning( aItemSet, aPropInfo, pCntxt ); + InsertAttrs( aItemSet, aPropInfo, pCntxt ); + } + } + + PushContext( pCntxt ); + + // die Attribute der neuen Vorlage setzen + if( nDefListDeep > 1 ) + SetTxtCollAttrs( pCntxt ); +} + +void SwHTMLParser::EndDefList() +{ + BOOL bSpace = (GetNumInfo().GetDepth() + nDefListDeep) == 1; + if( pPam->GetPoint()->nContent.GetIndex() ) + AppendTxtNode( bSpace ? AM_SPACE : AM_SOFTNOSPACE ); + else if( bSpace ) + AddParSpace(); + + // ein Level weniger + if( nDefListDeep > 0 ) + nDefListDeep--; + + // den aktuellen Kontext vom Stack holen + _HTMLAttrContext *pCntxt = PopContext( HTML_DEFLIST_ON ); + + // und noch Attribute beenden + if( pCntxt ) + { + EndContext( pCntxt ); + SetAttr(); // Absatz-Atts wegen JavaScript moeglichst schnell setzen + delete pCntxt; + } + + // und Vorlage setzen + SetTxtCollAttrs(); +} + +void SwHTMLParser::NewDefListItem( int nToken ) +{ + // festellen, ob das DD/DT in einer DL vorkommt + BOOL bInDefList = FALSE, bNotInDefList = FALSE; + USHORT nPos = aContexts.Count(); + while( !bInDefList && !bNotInDefList && nPos>nContextStMin ) + { + USHORT nCntxtToken = aContexts[--nPos]->GetToken(); + switch( nCntxtToken ) + { + case HTML_DEFLIST_ON: + bInDefList = TRUE; + break; + case HTML_DIRLIST_ON: + case HTML_MENULIST_ON: + case HTML_ORDERLIST_ON: + case HTML_UNORDERLIST_ON: + bNotInDefList = TRUE; + break; + } + } + + // wenn nicht, implizit eine neue DL aufmachen + if( !bInDefList ) + { + nDefListDeep++; + ASSERT( !nOpenParaToken, + "Jetzt geht ein offenes Absatz-Element verloren" ); + nOpenParaToken = static_cast< sal_uInt16 >(nToken); + } + + NewTxtFmtColl( nToken, static_cast< USHORT >(nToken==HTML_DD_ON ? RES_POOLCOLL_HTML_DD + : RES_POOLCOLL_HTML_DT) ); +} + +void SwHTMLParser::EndDefListItem( int nToken, BOOL bSetColl, + BOOL /*bLastPara*/ ) +{ + // einen neuen Absatz aufmachen + if( !nToken && pPam->GetPoint()->nContent.GetIndex() ) + AppendTxtNode( AM_SOFTNOSPACE ); + + // Kontext zu dem Token suchen und vom Stack holen + nToken &= ~1; + _HTMLAttrContext *pCntxt = 0; + USHORT nPos = aContexts.Count(); + while( !pCntxt && nPos>nContextStMin ) + { + USHORT nCntxtToken = aContexts[--nPos]->GetToken(); + switch( nCntxtToken ) + { + case HTML_DD_ON: + case HTML_DT_ON: + if( !nToken || nToken == nCntxtToken ) + { + pCntxt = aContexts[nPos]; + aContexts.Remove( nPos, 1 ); + } + break; + case HTML_DEFLIST_ON: + // keine DD/DT ausserhalb der aktuelen DefListe betrachten + case HTML_DIRLIST_ON: + case HTML_MENULIST_ON: + case HTML_ORDERLIST_ON: + case HTML_UNORDERLIST_ON: + // und auch nicht ausserhalb einer anderen Liste + nPos = nContextStMin; + break; + } + } + + // und noch Attribute beenden + if( pCntxt ) + { + EndContext( pCntxt ); + SetAttr(); // Absatz-Atts wegen JavaScript moeglichst schnell setzen + delete pCntxt; + } + + // und die bisherige Vorlage setzen + if( bSetColl ) + SetTxtCollAttrs(); +} + +/* */ + +BOOL SwHTMLParser::HasCurrentParaFlys( BOOL bNoSurroundOnly, + BOOL bSurroundOnly ) const +{ + // bNoSurroundOnly: Der Absatz enthaelt mindestens einen Rahmen + // ohne Umlauf + // bSurroundOnly: Der Absatz enthaelt mindestens einen Rahmen + // mit Umlauf aber keinen ohne Umlauf + // sonst: Der Absatz enthaelt irgendeinen Rahmen + SwNodeIndex& rNodeIdx = pPam->GetPoint()->nNode; + + SwFrmFmt* pFmt; + const SwFmtAnchor* pAnchor; + const SwPosition* pAPos; + const SwSpzFrmFmts& rFrmFmtTbl = *pDoc->GetSpzFrmFmts(); + + USHORT i; + BOOL bFound = FALSE; + for( i=0; i<rFrmFmtTbl.Count(); i++ ) + { + pFmt = rFrmFmtTbl[i]; + pAnchor = &pFmt->GetAnchor(); + // Ein Rahmen wurde gefunden, wenn + // - er absatzgebunden ist, und + // - im aktuellen Absatz verankert ist, und + // - jeder absatzgebunene Rahmen zaehlt, oder + // - (nur Rahmen oder umlauf zaehlen und ) der Rahmen keinen + // Umlauf besitzt + + if( 0 != ( pAPos = pAnchor->GetCntntAnchor()) && + (FLY_AT_CNTNT == pAnchor->GetAnchorId() || + FLY_AUTO_CNTNT == pAnchor->GetAnchorId()) && + pAPos->nNode == rNodeIdx ) + { + if( !(bNoSurroundOnly || bSurroundOnly) ) + { + bFound = TRUE; + break; + } + else + { + // fix #42282#: Wenn Rahmen mit Umlauf gesucht sind, + // auch keine mit Durchlauf beachten. Dabei handelt es + // sich (noch) um HIDDEN-Controls, und denen weicht man + // besser auch nicht aus. + SwSurround eSurround = pFmt->GetSurround().GetSurround(); + if( bNoSurroundOnly ) + { + if( SURROUND_NONE==eSurround ) + { + bFound = TRUE; + break; + } + } + if( bSurroundOnly ) + { + if( SURROUND_NONE==eSurround ) + { + bFound = FALSE; + break; + } + else if( SURROUND_THROUGHT!=eSurround ) + { + bFound = TRUE; + // weitersuchen: Es koennten ja noch welche ohne + // Umlauf kommen ... + } + } + } + } + } + + return bFound; +} + +/* */ + +// die speziellen Methoden zum Einfuegen von Objecten + +const SwFmtColl *SwHTMLParser::GetCurrFmtColl() const +{ + const SwCntntNode* pCNd = pPam->GetCntntNode(); + return &pCNd->GetAnyFmtColl(); +} + + +void SwHTMLParser::SetTxtCollAttrs( _HTMLAttrContext *pContext ) +{ + SwTxtFmtColl *pCollToSet = 0; // die zu setzende Vorlage + SfxItemSet *pItemSet = 0; // der Set fuer harte Attrs + USHORT nTopColl = pContext ? pContext->GetTxtFmtColl() : 0; + const String& rTopClass = pContext ? pContext->GetClass() : (const String&) aEmptyStr; + USHORT nDfltColl = RES_POOLCOLL_TEXT; + + BOOL bInPRE=FALSE; // etwas Kontext Info + + USHORT nLeftMargin = 0, nRightMargin = 0; // die Einzuege und + short nFirstLineIndent = 0; // Abstaende + USHORT i; + + for( i = nContextStAttrMin; i < aContexts.Count(); i++ ) + { + const _HTMLAttrContext *pCntxt = aContexts[i]; + + USHORT nColl = pCntxt->GetTxtFmtColl(); + if( nColl ) + { + // Es gibt eine Vorlage, die zu setzen ist. Dann + // muss zunaechst einmal entschieden werden, + // ob die Vorlage auch gesetzt werden kann + BOOL bSetThis = TRUE; + switch( nColl ) + { + case USHORT(RES_POOLCOLL_HTML_PRE): + bInPRE = TRUE; + break; + case USHORT(RES_POOLCOLL_TEXT): + // <TD><P CLASS=xxx> muss TD.xxx werden + if( nDfltColl==RES_POOLCOLL_TABLE || + nDfltColl==RES_POOLCOLL_TABLE_HDLN ) + nColl = nDfltColl; + break; + case USHORT(RES_POOLCOLL_HTML_HR): + // <HR> auch in <PRE> als Vorlage setzen, sonst kann man sie + // nicht mehr exportieren + break; + default: + if( bInPRE ) + bSetThis = FALSE; + break; + } + + SwTxtFmtColl *pNewColl = + pCSS1Parser->GetTxtFmtColl( nColl, pCntxt->GetClass() ); + + if( bSetThis ) + { + // wenn jetzt eine andere Vorlage gesetzt werden soll als + // bisher, muss die bishere Vorlage durch harte Attributierung + // ersetzt werden + + if( pCollToSet ) + { + // die Attribute, die die bisherige Vorlage setzt + // hart einfuegen + if( !pItemSet ) + pItemSet = new SfxItemSet( pCollToSet->GetAttrSet() ); + else + { + const SfxItemSet& rCollSet = pCollToSet->GetAttrSet(); + SfxItemSet aItemSet( *rCollSet.GetPool(), + rCollSet.GetRanges() ); + aItemSet.Set( rCollSet ); + pItemSet->Put( aItemSet ); + } + // aber die Attribute, die aktuelle Vorlage setzt + // entfernen, weil sie sonst spaeter ueberschrieben + // werden + pItemSet->Differentiate( pNewColl->GetAttrSet() ); + } + + pCollToSet = pNewColl; + } + else + { + // hart Attributieren + if( !pItemSet ) + pItemSet = new SfxItemSet( pNewColl->GetAttrSet() ); + else + { + const SfxItemSet& rCollSet = pNewColl->GetAttrSet(); + SfxItemSet aItemSet( *rCollSet.GetPool(), + rCollSet.GetRanges() ); + aItemSet.Set( rCollSet ); + pItemSet->Put( aItemSet ); + } + } + } + else + { + // vielliecht gibt es ja eine Default-Vorlage? + nColl = pCntxt->GetDfltTxtFmtColl(); + if( nColl ) + nDfltColl = nColl; + } + + // ggf. neue Absatz-Einzuege holen + if( pCntxt->IsLRSpaceChanged() ) + { + USHORT nLeft=0, nRight=0; + + pCntxt->GetMargins( nLeft, nRight, nFirstLineIndent ); + nLeftMargin = nLeft; + nRightMargin = nRight; + } + } + + // wenn im aktuellen Kontext eine neue Vorlage gesetzt werden soll, + // muessen deren Absatz-Abstaende noch in den Kontext eingetragen werden + if( pContext && nTopColl ) + { + // <TD><P CLASS=xxx> muss TD.xxx werden + if( nTopColl==RES_POOLCOLL_TEXT && + (nDfltColl==RES_POOLCOLL_TABLE || + nDfltColl==RES_POOLCOLL_TABLE_HDLN) ) + nTopColl = nDfltColl; + + const SwTxtFmtColl *pTopColl = + pCSS1Parser->GetTxtFmtColl( nTopColl, rTopClass ); + const SfxItemSet& rItemSet = pTopColl->GetAttrSet(); + const SfxPoolItem *pItem; + if( SFX_ITEM_SET == rItemSet.GetItemState(RES_LR_SPACE,TRUE, &pItem) ) + { + const SvxLRSpaceItem *pLRItem = + (const SvxLRSpaceItem *)pItem; + + sal_Int32 nLeft = pLRItem->GetTxtLeft(); + sal_Int32 nRight = pLRItem->GetRight(); + nFirstLineIndent = pLRItem->GetTxtFirstLineOfst(); + + // In Definitions-Listen enthalten die Abstaende auch die der + // vorhergehenden Level + if( RES_POOLCOLL_HTML_DD == nTopColl ) + { + const SvxLRSpaceItem& rDTLRSpace = pCSS1Parser + ->GetTxtFmtColl( RES_POOLCOLL_HTML_DT, aEmptyStr ) + ->GetLRSpace(); + nLeft -= rDTLRSpace.GetTxtLeft(); + nRight -= rDTLRSpace.GetRight(); + } + else if( RES_POOLCOLL_HTML_DT == nTopColl ) + { + nLeft = 0; + nRight = 0; + } + + // die Absatz-Abstaende addieren sich + nLeftMargin = nLeftMargin + static_cast< sal_uInt16 >(nLeft); + nRightMargin = nRightMargin + static_cast< sal_uInt16 >(nRight); + + pContext->SetMargins( nLeftMargin, nRightMargin, + nFirstLineIndent ); + } + if( SFX_ITEM_SET == rItemSet.GetItemState(RES_UL_SPACE,TRUE, &pItem) ) + { + const SvxULSpaceItem *pULItem = + (const SvxULSpaceItem *)pItem; + pContext->SetULSpace( pULItem->GetUpper(), pULItem->GetLower() ); + } + } + + // wenn gar keine Vorlage im Kontext gesetzt ist, Textkoerper nehmen + if( !pCollToSet ) + { + pCollToSet = pCSS1Parser->GetTxtCollFromPool( nDfltColl ); + const SvxLRSpaceItem& rLRItem = pCollToSet->GetLRSpace(); + if( !nLeftMargin ) + nLeftMargin = static_cast< sal_uInt16 >(rLRItem.GetTxtLeft()); + if( !nRightMargin ) + nRightMargin = static_cast< sal_uInt16 >(rLRItem.GetRight()); + if( !nFirstLineIndent ) + nFirstLineIndent = rLRItem.GetTxtFirstLineOfst(); + } + + // bisherige harte Attributierung des Absatzes entfernen + if( aParaAttrs.Count() ) + { + for( i=0; i<aParaAttrs.Count(); i++ ) + aParaAttrs[i]->Invalidate(); + + aParaAttrs.Remove( 0, aParaAttrs.Count() ); + } + + // Die Vorlage setzen + pDoc->SetTxtFmtColl( *pPam, pCollToSet ); + + // ggf. noch den Absatz-Einzug korrigieren + const SvxLRSpaceItem& rLRItem = pCollToSet->GetLRSpace(); + BOOL bSetLRSpace; + + bSetLRSpace = nLeftMargin != rLRItem.GetTxtLeft() || + nFirstLineIndent != rLRItem.GetTxtFirstLineOfst() || + nRightMargin != rLRItem.GetRight(); + + if( bSetLRSpace ) + { + SvxLRSpaceItem aLRItem( rLRItem ); + aLRItem.SetTxtLeft( nLeftMargin ); + aLRItem.SetRight( nRightMargin ); + aLRItem.SetTxtFirstLineOfst( nFirstLineIndent ); + if( pItemSet ) + pItemSet->Put( aLRItem ); + else + { + NewAttr( &aAttrTab.pLRSpace, aLRItem ); + aAttrTab.pLRSpace->SetLikePara(); + aParaAttrs.Insert( aAttrTab.pLRSpace, aParaAttrs.Count() ); + EndAttr( aAttrTab.pLRSpace, 0, FALSE ); + } + } + + // und nun noch die Attribute setzen + if( pItemSet ) + { + InsertParaAttrs( *pItemSet ); + delete pItemSet; + } +} + +/* */ + +void SwHTMLParser::NewCharFmt( int nToken ) +{ + String aId, aStyle, aClass, aLang, aDir; + + const HTMLOptions *pHTMLOptions = GetOptions(); + for( USHORT i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + case HTML_O_LANG: + aLang = pOption->GetString(); + break; + case HTML_O_DIR: + aDir = pOption->GetString(); + break; + } + } + + // einen neuen Kontext anlegen + _HTMLAttrContext *pCntxt = new _HTMLAttrContext( static_cast< sal_uInt16 >(nToken) ); + + // die Vorlage setzen und im Kontext merken + SwCharFmt* pCFmt = pCSS1Parser->GetChrFmt( static_cast< sal_uInt16 >(nToken), aClass ); + ASSERT( pCFmt, "keine Zeichenvorlage zu Token gefunden" ); + + + // Styles parsen (zu Class siehe auch NewPara) + if( HasStyleOptions( aStyle, aId, aEmptyStr, &aLang, &aDir ) ) + { + SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + + if( ParseStyleOptions( aStyle, aId, aEmptyStr, aItemSet, aPropInfo, &aLang, &aDir ) ) + { + ASSERT( !aClass.Len() || !pCSS1Parser->GetClass( aClass ), + "Class wird nicht beruecksichtigt" ); + DoPositioning( aItemSet, aPropInfo, pCntxt ); + InsertAttrs( aItemSet, aPropInfo, pCntxt, TRUE ); + } + } + + // Zeichen-Vorlagen werden in einem eigenen Stack gehalten und + // koennen nie durch Styles eingefuegt werden. Das Attribut ist deshalb + // auch gar nicht im CSS1-Which-Range enthalten + if( pCFmt ) + InsertAttr( &aAttrTab.pCharFmts, SwFmtCharFmt( pCFmt ), pCntxt ); + + // den Kontext merken + PushContext( pCntxt ); +} + + +/* */ + +void SwHTMLParser::InsertSpacer() +{ + // und es ggf. durch die Optionen veraendern + String aId; + sal_Int16 eVertOri = text::VertOrientation::TOP; + sal_Int16 eHoriOri = text::HoriOrientation::NONE; + Size aSize( 0, 0); + long nSize = 0; + BOOL bPrcWidth = FALSE; + BOOL bPrcHeight = FALSE; + USHORT nType = HTML_SPTYPE_HORI; + + const HTMLOptions *pHTMLOptions = GetOptions(); + for( USHORT i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_TYPE: + pOption->GetEnum( nType, aHTMLSpacerTypeTable ); + break; + case HTML_O_ALIGN: + eVertOri = + pOption->GetEnum( aHTMLImgVAlignTable, + eVertOri ); + eHoriOri = + pOption->GetEnum( aHTMLImgHAlignTable, + eHoriOri ); + break; + case HTML_O_WIDTH: + // erstmal nur als Pixelwerte merken! + bPrcWidth = (pOption->GetString().Search('%') != STRING_NOTFOUND); + aSize.Width() = (long)pOption->GetNumber(); + break; + case HTML_O_HEIGHT: + // erstmal nur als Pixelwerte merken! + bPrcHeight = (pOption->GetString().Search('%') != STRING_NOTFOUND); + aSize.Height() = (long)pOption->GetNumber(); + break; + case HTML_O_SIZE: + // erstmal nur als Pixelwerte merken! + nSize = pOption->GetNumber(); + break; + } + } + + switch( nType ) + { + case HTML_SPTYPE_BLOCK: + { + // einen leeren Textrahmen anlegen + + // den Itemset holen + SfxItemSet aFrmSet( pDoc->GetAttrPool(), + RES_FRMATR_BEGIN, RES_FRMATR_END-1 ); + if( !IsNewDoc() ) + Reader::ResetFrmFmtAttrs( aFrmSet ); + + // den Anker und die Ausrichtung setzen + SetAnchorAndAdjustment( eVertOri, eHoriOri, aFrmSet ); + + // und noch die Groesse des Rahmens + Size aDfltSz( MINFLY, MINFLY ); + Size aSpace( 0, 0 ); + SfxItemSet aDummyItemSet( pDoc->GetAttrPool(), + pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aDummyPropInfo; + + SetFixSize( aSize, aDfltSz, bPrcWidth, bPrcHeight, + aDummyItemSet, aDummyPropInfo, aFrmSet ); + SetSpace( aSpace, aDummyItemSet, aDummyPropInfo, aFrmSet ); + + // den Inhalt schuetzen + SvxProtectItem aProtectItem( RES_PROTECT) ; + aProtectItem.SetCntntProtect( TRUE ); + aFrmSet.Put( aProtectItem ); + + // der Rahmen anlegen + RndStdIds eAnchorId = + ((const SwFmtAnchor &)aFrmSet.Get(RES_ANCHOR)).GetAnchorId(); + SwFrmFmt *pFlyFmt = pDoc->MakeFlySection( eAnchorId, + pPam->GetPoint(), &aFrmSet ); + // Ggf Frames anlegen und auto-geb. Rahmen registrieren + RegisterFlyFrm( pFlyFmt ); + } + break; + case HTML_SPTYPE_VERT: + if( nSize > 0 ) + { + if( nSize && Application::GetDefaultDevice() ) + { + nSize = Application::GetDefaultDevice() + ->PixelToLogic( Size(0,nSize), + MapMode(MAP_TWIP) ).Height(); + } + + // einen Absatz-Abstand setzen + SwTxtNode *pTxtNode = 0; + if( !pPam->GetPoint()->nContent.GetIndex() ) + { + // den unteren Absatz-Abstand des vorherigen Nodes aendern, + // wenn moeglich + + SetAttr(); // noch offene Absatz-Attribute setzen + + pTxtNode = pDoc->GetNodes()[pPam->GetPoint()->nNode.GetIndex()-1] + ->GetTxtNode(); + + // Wenn der Abstz davor kein Txtenode ist, dann wird jetzt + // ein leere Absatz angelegt, der eh schon eine Zeilenhoehe + // Abstand erzeugt. + if( !pTxtNode ) + nSize = nSize>HTML_PARSPACE ? nSize-HTML_PARSPACE : 0; + } + + if( pTxtNode ) + { + SvxULSpaceItem aULSpace( (const SvxULSpaceItem&)pTxtNode + ->SwCntntNode::GetAttr( RES_UL_SPACE ) ); + aULSpace.SetLower( aULSpace.GetLower() + (USHORT)nSize ); + pTxtNode->SetAttr( aULSpace ); + } + else + { + NewAttr( &aAttrTab.pULSpace, SvxULSpaceItem( 0, (USHORT)nSize, RES_UL_SPACE ) ); + EndAttr( aAttrTab.pULSpace, 0, FALSE ); + + AppendTxtNode(); // nicht am Abstand drehen! + } + } + break; + case HTML_SPTYPE_HORI: + if( nSize > 0 ) + { + // wenn der Absatz noch leer ist, einen Erstzeilen-Einzug + // setzen, sondern Sperrschrift ueber einem Space aufspannen + + if( nSize && Application::GetDefaultDevice() ) + { + nSize = Application::GetDefaultDevice() + ->PixelToLogic( Size(nSize,0), + MapMode(MAP_TWIP) ).Width(); + } + + if( !pPam->GetPoint()->nContent.GetIndex() ) + { + USHORT nLeft=0, nRight=0; + short nIndent = 0; + + GetMarginsFromContextWithNumBul( nLeft, nRight, nIndent ); + nIndent = nIndent + (short)nSize; + + SvxLRSpaceItem aLRItem( RES_LR_SPACE ); + aLRItem.SetTxtLeft( nLeft ); + aLRItem.SetRight( nRight ); + aLRItem.SetTxtFirstLineOfst( nIndent ); + + NewAttr( &aAttrTab.pLRSpace, aLRItem ); + EndAttr( aAttrTab.pLRSpace, 0, FALSE ); + } + else + { + NewAttr( &aAttrTab.pKerning, SvxKerningItem( (short)nSize, RES_CHRATR_KERNING ) ); + String aTmp( ' ' ); + pDoc->InsertString( *pPam, aTmp ); + EndAttr( aAttrTab.pKerning ); + } + } + } +} + +USHORT SwHTMLParser::ToTwips( USHORT nPixel ) const +{ + if( nPixel && Application::GetDefaultDevice() ) + { + long nTwips = Application::GetDefaultDevice()->PixelToLogic( + Size( nPixel, nPixel ), MapMode( MAP_TWIP ) ).Width(); + return nTwips <= USHRT_MAX ? (USHORT)nTwips : USHRT_MAX; + } + else + return nPixel; +} + +SwTwips SwHTMLParser::GetCurrentBrowseWidth() +{ + SwTwips nWidth = SwHTMLTableLayout::GetBrowseWidth( *pDoc ); + if( nWidth ) + return nWidth; + + if( !aHTMLPageSize.Width() ) + { + const SwFrmFmt& rPgFmt = pCSS1Parser->GetMasterPageDesc()->GetMaster(); + + const SwFmtFrmSize& rSz = rPgFmt.GetFrmSize(); + const SvxLRSpaceItem& rLR = rPgFmt.GetLRSpace(); + const SvxULSpaceItem& rUL = rPgFmt.GetULSpace(); + const SwFmtCol& rCol = rPgFmt.GetCol(); + + aHTMLPageSize.Width() = rSz.GetWidth() - rLR.GetLeft() - rLR.GetRight(); + aHTMLPageSize.Height() = rSz.GetHeight() - rUL.GetUpper() - rUL.GetLower(); + + if( 1 < rCol.GetNumCols() ) + aHTMLPageSize.Width() /= rCol.GetNumCols(); + } + + return aHTMLPageSize.Width(); +} + + +/* */ + +void SwHTMLParser::InsertIDOption() +{ + String aId; + const HTMLOptions *pHTMLOptions = GetOptions(); + for( USHORT i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + if( HTML_O_ID==pOption->GetToken() ) + { + aId = pOption->GetString(); + break; + } + } + + if( aId.Len() ) + InsertBookmark( aId ); +} + + +/* */ + + +void SwHTMLParser::InsertLineBreak() +{ + // <BR CLEAR=xxx> wird wie folgt behandelt: + // 1.) Es werden nur nur absatzgebundene Rahmen betrachtet, die + // im aktuellen Absatz verankert sind. + // 2.) Fuer linksbuendig ausgerichtete Rahmen wird bei CLEAR=LEFT + // oder ALL und auf rechtsbuendige ausgerichtete Rahmen bei + // CLEAR=RIGHT oder ALL der Durchlauf wie folgt geaendert: + // 3.) Wenn der Absatz keinen Text enthaelt, bekommt der Rahmen keinen + // Umlauf + // 4.) sonst erhaelt ein links ausgerichteter Rahmen eine rechten + // "nur Anker" Umlauf und recht rechst ausg. Rahmen einen linken + // "nur Anker" Umlauf. + // 5.) wenn in einem nicht-leeren Absatz der Umlauf eines Rahmens + // geaendert wird, wird ein neuer Absatz aufgemacht + // 6.) Wenn von keinem Rahmen der Umlauf geaendert wird, wird ein + // harter Zeilenumbruch eingefuegt + + String aId, aStyle, aClass; // die ID der Bookmark + BOOL bClearLeft = FALSE, bClearRight = FALSE; + BOOL bCleared = FALSE; // wurde ein CLEAR ausgefuehrt? + + // dann holen wir mal die Optionen + const HTMLOptions *pHTMLOptions = GetOptions(); + for( USHORT i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_CLEAR: + { + const String &aClear = pOption->GetString(); + if( aClear.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_AL_all ) ) + { + bClearLeft = TRUE; + bClearRight = TRUE; + } + else if( aClear.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_AL_left ) ) + bClearLeft = TRUE; + else if( aClear.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_AL_right ) ) + bClearRight = TRUE; + } + break; + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + } + } + + // CLEAR wird nur fuer den aktuellen Absaetz unterstuetzt + if( bClearLeft || bClearRight ) + { + SwNodeIndex& rNodeIdx = pPam->GetPoint()->nNode; + SwTxtNode* pTxtNd = rNodeIdx.GetNode().GetTxtNode(); + if( pTxtNd ) + { + SwFrmFmt* pFmt; + const SwFmtAnchor* pAnchor; + const SwPosition* pAPos; + const SwSpzFrmFmts& rFrmFmtTbl = *pDoc->GetSpzFrmFmts(); + + for( USHORT i=0; i<rFrmFmtTbl.Count(); i++ ) + { + pFmt = rFrmFmtTbl[i]; + pAnchor = &pFmt->GetAnchor(); + if( 0 != ( pAPos = pAnchor->GetCntntAnchor()) && + (FLY_AT_CNTNT == pAnchor->GetAnchorId() || + FLY_AUTO_CNTNT == pAnchor->GetAnchorId()) && + pAPos->nNode == rNodeIdx && + pFmt->GetSurround().GetSurround() != SURROUND_NONE ) + { + sal_Int16 eHori = RES_DRAWFRMFMT == pFmt->Which() + ? text::HoriOrientation::LEFT + : pFmt->GetHoriOrient().GetHoriOrient(); + + SwSurround eSurround = SURROUND_PARALLEL; + if( pPam->GetPoint()->nContent.GetIndex() ) + { + if( bClearLeft && text::HoriOrientation::LEFT==eHori ) + eSurround = SURROUND_RIGHT; + else if( bClearRight && text::HoriOrientation::RIGHT==eHori ) + eSurround = SURROUND_LEFT; + } + else if( (bClearLeft && text::HoriOrientation::LEFT==eHori) || + (bClearRight && text::HoriOrientation::RIGHT==eHori) ) + { + eSurround = SURROUND_NONE; + } + + if( SURROUND_PARALLEL != eSurround ) + { + SwFmtSurround aSurround( eSurround ); + if( SURROUND_NONE != eSurround ) + aSurround.SetAnchorOnly( TRUE ); + pFmt->SetFmtAttr( aSurround ); + bCleared = TRUE; + } + } // Anker ist nicht im Node + } // Schleife ueber Fly-Frames + } // kein Text-Node + } // kein CLEAR + + // Styles parsen + SvxFmtBreakItem aBreakItem( SVX_BREAK_NONE, RES_BREAK ); + BOOL bBreakItem = FALSE; + if( HasStyleOptions( aStyle, aId, aClass ) ) + { + SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + + if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo ) ) + { + if( pCSS1Parser->SetFmtBreak( aItemSet, aPropInfo ) ) + { + aBreakItem = (const SvxFmtBreakItem &)aItemSet.Get( RES_BREAK ); + bBreakItem = TRUE; + } + if( aPropInfo.aId.Len() ) + InsertBookmark( aPropInfo.aId ); + } + } + + if( bBreakItem && SVX_BREAK_PAGE_AFTER==aBreakItem.GetBreak() ) + { + NewAttr( &aAttrTab.pBreak, aBreakItem ); + EndAttr( aAttrTab.pBreak, 0, FALSE ); + } + + if( !bCleared && !bBreakItem ) + { + // wenn kein CLEAR ausgefuehrt werden sollte oder konnte, wird + // ein Zeilenumbruch eingef?gt + String sTmp( (sal_Unicode)0x0a ); // make the Mac happy :-) + pDoc->InsertString( *pPam, sTmp ); + } + else if( pPam->GetPoint()->nContent.GetIndex() ) + { + // wenn ein Claer in einem nicht-leeren Absatz ausgefuehrt wurde, + // muss anschliessen ein neuer Absatz aufgemacht werden + // MIB 21.02.97: Eigentlich muesste man hier den unteren Absatz- + // Absatnd auf 0 drehen. Das geht aber bei sowas wie <BR ..><P> + // schief (>Netacpe). Deshalb lassen wir das erstmal. + AppendTxtNode( AM_NOSPACE ); + } + if( bBreakItem && SVX_BREAK_PAGE_BEFORE==aBreakItem.GetBreak() ) + { + NewAttr( &aAttrTab.pBreak, aBreakItem ); + EndAttr( aAttrTab.pBreak, 0, FALSE ); + } +} + +void SwHTMLParser::InsertHorzRule() +{ + USHORT nSize = 0; + USHORT nWidth = 0; + + SvxAdjust eAdjust = SVX_ADJUST_END; + + BOOL bPrcWidth = FALSE; + BOOL bNoShade = FALSE; + BOOL bColor = FALSE; + + Color aColor; + String aId; + + // dann holen wir mal die Optionen + const HTMLOptions *pHTMLOptions = GetOptions(); + for( USHORT i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_SIZE: + nSize = (USHORT)pOption->GetNumber(); + break; + case HTML_O_WIDTH: + bPrcWidth = (pOption->GetString().Search('%') != STRING_NOTFOUND); + nWidth = (USHORT)pOption->GetNumber(); + if( bPrcWidth && nWidth>=100 ) + { + // 100%-Linien sind der default-Fall (keine Attrs neotig) + nWidth = 0; + bPrcWidth = FALSE; + } + break; + case HTML_O_ALIGN: + eAdjust = + (SvxAdjust)pOption->GetEnum( aHTMLPAlignTable, static_cast< sal_uInt16 >(eAdjust) ); + break; + case HTML_O_NOSHADE: + bNoShade = TRUE; + break; + case HTML_O_COLOR: + pOption->GetColor( aColor ); + bColor = TRUE; + break; + } + } + + if( pPam->GetPoint()->nContent.GetIndex() ) + AppendTxtNode( AM_NOSPACE ); + if( nOpenParaToken ) + EndPara(); + AppendTxtNode(); + pPam->Move( fnMoveBackward ); + + // ... und in einem Kontext merken + _HTMLAttrContext *pCntxt = + new _HTMLAttrContext( HTML_HORZRULE, RES_POOLCOLL_HTML_HR, aEmptyStr ); + + PushContext( pCntxt ); + + // die neue Vorlage setzen + SetTxtCollAttrs( pCntxt ); + + // die harten Attribute an diesem Absatz werden nie mehr ungueltig + if( aParaAttrs.Count() ) + aParaAttrs.Remove( 0, aParaAttrs.Count() ); + + if( nSize>0 || bColor || bNoShade ) + { + // Farbe und/oder Breite der Linie setzen + if( !bColor ) + aColor.SetColor( COL_GRAY ); + + SvxBorderLine aBorderLine( &aColor ); + if( nSize ) + { + long nPWidth = 0; + long nPHeight = (long)nSize; + SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight ); + SvxCSS1Parser::SetBorderWidth( aBorderLine, (USHORT)nPHeight, + !bNoShade ); + } + else if( bNoShade ) + { + aBorderLine.SetOutWidth( DEF_LINE_WIDTH_2 ); + } + else + { + aBorderLine.SetOutWidth( DEF_DOUBLE_LINE0_OUT ); + aBorderLine.SetInWidth( DEF_DOUBLE_LINE0_IN ); + aBorderLine.SetDistance( DEF_DOUBLE_LINE0_DIST ); + } + + SvxBoxItem aBoxItem(RES_BOX); + aBoxItem.SetLine( &aBorderLine, BOX_LINE_BOTTOM ); + _HTMLAttr* pTmp = new _HTMLAttr( *pPam->GetPoint(), aBoxItem ); + aSetAttrTab.Insert( pTmp, aSetAttrTab.Count() ); + } + if( nWidth ) + { + // Wenn wir in keiner Tabelle sind, wird die Breitenangabe durch + // Absatz-Einzuege "getuerkt". In einer Tabelle macht das wenig + // Sinn. Um zu Vermeiden, dass die Linie bei der Breitenberechnung + // beruecksichtigt wird, bekommt sie aber trotzdem entsprechendes + // LRSpace-Item verpasst. +#ifdef FIX41370 + const SwFmtColl *pColl = GetCurrFmtColl(); + SvxLRSpaceItem aLRItem( pColl->GetLRSpace() ); +#endif + if( !pTable ) + { + // Laenge und Ausrichtung der Linie ueber Absatz-Einzuege "tuerken" + long nBrowseWidth = GetCurrentBrowseWidth(); + nWidth = bPrcWidth ? (USHORT)((nWidth*nBrowseWidth) / 100) + : ToTwips( (USHORT)nBrowseWidth ); + if( nWidth < MINLAY ) + nWidth = MINLAY; + + if( (long)nWidth < nBrowseWidth ) + { +#ifndef FIX41370 + const SwFmtColl *pColl = GetCurrFmtColl(); + SvxLRSpaceItem aLRItem( pColl->GetLRSpace() ); +#endif + long nDist = nBrowseWidth - nWidth; + + switch( eAdjust ) + { + case SVX_ADJUST_RIGHT: + aLRItem.SetTxtLeft( (USHORT)nDist ); + break; + case SVX_ADJUST_LEFT: + aLRItem.SetRight( (USHORT)nDist ); + break; + case SVX_ADJUST_CENTER: + default: + nDist /= 2; + aLRItem.SetTxtLeft( (USHORT)nDist ); + aLRItem.SetRight( (USHORT)nDist ); + break; + } + +#ifndef FIX41370 + _HTMLAttr* pTmp = new _HTMLAttr( *pPam->GetPoint(), aLRItem ); + aSetAttrTab.Insert( pTmp, aSetAttrTab.Count() ); +#endif + } + } + +#ifdef FIX41370 + _HTMLAttr* pTmp = new _HTMLAttr( *pPam->GetPoint(), aLRItem ); + aSetAttrTab.Insert( pTmp, aSetAttrTab.Count() ); +#endif + } + + // Bookmarks koennen nicht in Hyperlinks eingefueht werden + if( aId.Len() ) + InsertBookmark( aId ); + + // den aktuellen Kontext vom Stack holen + _HTMLAttrContext *pPoppedContext = PopContext( HTML_HORZRULE ); + ASSERT( pPoppedContext==pCntxt, "wo kommt denn da ein HR-Kontext her?" ); + delete pPoppedContext; + + pPam->Move( fnMoveForward ); + + // und im Absatz danach die dort aktuelle Vorlage setzen + SetTxtCollAttrs(); +} + +void SwHTMLParser::ParseMoreMetaOptions() +{ + String aName, aContent; + BOOL bHTTPEquiv = FALSE; + + const HTMLOptions *pHTMLOptions = GetOptions(); + for( USHORT i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[ --i ]; + switch( pOption->GetToken() ) + { + case HTML_O_NAME: + aName = pOption->GetString(); + bHTTPEquiv = FALSE; + break; + case HTML_O_HTTPEQUIV: + aName = pOption->GetString(); + bHTTPEquiv = TRUE; + break; + case HTML_O_CONTENT: + aContent = pOption->GetString(); + break; + } + } + + // Hier wird es etwas tricky: Wir wissen genau, da? die Dok-Info + // nicht geaendert wurde. Deshalb genuegt es, auf Generator und + // auf refresh abzufragen, um noch nicht verarbeitete Token zu finden, + // denn das sind die einzigen, die die Dok-Info nicht modifizieren. + if( aName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_META_generator ) || + aName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_META_refresh ) || + aName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_META_content_type ) || + aName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_META_content_script_type ) ) + return; + + aContent.EraseAllChars( _CR ); + aContent.EraseAllChars( _LF ); + + if( aName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_META_sdendnote ) ) + { + FillEndNoteInfo( aContent ); + return; + } + + if( aName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_META_sdfootnote ) ) + { + FillFootNoteInfo( aContent ); + return; + } + + String sText( + String::CreateFromAscii(TOOLS_CONSTASCII_STRINGPARAM("HTML: <")) ); + sText.AppendAscii( TOOLS_CONSTASCII_STRINGPARAM(OOO_STRING_SVTOOLS_HTML_meta) ); + sText.Append( ' ' ); + if( bHTTPEquiv ) + sText.AppendAscii( TOOLS_CONSTASCII_STRINGPARAM(OOO_STRING_SVTOOLS_HTML_O_httpequiv) ); + else + sText.AppendAscii( TOOLS_CONSTASCII_STRINGPARAM(OOO_STRING_SVTOOLS_HTML_O_name) ); + sText.AppendAscii( TOOLS_CONSTASCII_STRINGPARAM("=\"") ); + sText.Append( aName ); + sText.AppendAscii( TOOLS_CONSTASCII_STRINGPARAM("\" ") ); + sText.AppendAscii( TOOLS_CONSTASCII_STRINGPARAM(OOO_STRING_SVTOOLS_HTML_O_content) ); + sText.AppendAscii( TOOLS_CONSTASCII_STRINGPARAM("=\"") ); + sText.Append( aContent ); + sText.AppendAscii( TOOLS_CONSTASCII_STRINGPARAM("\">") ); + + SwPostItField aPostItFld( + (SwPostItFieldType*)pDoc->GetSysFldType( RES_POSTITFLD ), + aEmptyStr, sText, DateTime() ); + SwFmtFld aFmtFld( aPostItFld ); + InsertAttr( aFmtFld ); +} + +/* */ + +_HTMLAttr::_HTMLAttr( const SwPosition& rPos, const SfxPoolItem& rItem, + _HTMLAttr **ppHd ) : + nSttPara( rPos.nNode ), + nEndPara( rPos.nNode ), + nSttCntnt( rPos.nContent.GetIndex() ), + nEndCntnt(rPos.nContent.GetIndex() ), + bInsAtStart( TRUE ), + bLikePara( FALSE ), + bValid( TRUE ), + nCount( 1 ), + pNext( 0 ), + pPrev( 0 ), + ppHead( ppHd ) +{ + pItem = rItem.Clone(); +} + +_HTMLAttr::_HTMLAttr( const _HTMLAttr &rAttr, const SwNodeIndex &rEndPara, + USHORT nEndCnt, _HTMLAttr **ppHd ) : + nSttPara( rAttr.nSttPara ), + nEndPara( rEndPara ), + nSttCntnt( rAttr.nSttCntnt ), + nEndCntnt( nEndCnt ), + bInsAtStart( rAttr.bInsAtStart ), + bLikePara( rAttr.bLikePara ), + bValid( rAttr.bValid ), + nCount( rAttr.nCount ), + pNext( 0 ), + pPrev( 0 ), + ppHead( ppHd ) +{ + pItem = rAttr.pItem->Clone(); +} + +_HTMLAttr::~_HTMLAttr() +{ + delete pItem; +} + +_HTMLAttr *_HTMLAttr::Clone( const SwNodeIndex& rEndPara, USHORT nEndCnt ) const +{ + // das Attribut mit der alten Start-Position neu anlegen + _HTMLAttr *pNew = new _HTMLAttr( *this, rEndPara, nEndCnt, ppHead ); + + // die Previous-Liste muss uebernommen werden, die Next-Liste nicht! + pNew->pPrev = pPrev; + + return pNew; +} + +void _HTMLAttr::Reset( const SwNodeIndex& rSttPara, USHORT nSttCnt, + _HTMLAttr **ppHd ) +{ + // den Anfang (und das Ende) neu setzen + nSttPara = rSttPara; + nSttCntnt = nSttCnt; + nEndPara = rSttPara; + nEndCntnt = nSttCnt; + + // den Head korrigieren und die Verkettungen aufheben + pNext = 0; + pPrev = 0; + ppHead = ppHd; +} + +void _HTMLAttr::InsertPrev( _HTMLAttr *pPrv ) +{ + ASSERT( !pPrv->pNext || pPrv->pNext == this, + "_HTMLAttr::InsertPrev: pNext falsch" ); + pPrv->pNext = 0; + + ASSERT( 0 == pPrv->ppHead || ppHead == pPrv->ppHead, + "_HTMLAttr::InsertPrev: ppHead falsch" ); + pPrv->ppHead = 0; + + _HTMLAttr *pAttr = this; + while( pAttr->GetPrev() ) + pAttr = pAttr->GetPrev(); + + pAttr->pPrev = pPrv; +} + +bool SwHTMLParser::ParseMetaOptions( + const uno::Reference<document::XDocumentProperties> & i_xDocProps, + SvKeyValueIterator *i_pHeader ) +{ + // always call base ParseMetaOptions, it sets the encoding (#i96700#) + bool ret( HTMLParser::ParseMetaOptions(i_xDocProps, i_pHeader) ); + if (!ret && IsNewDoc()) + { + ParseMoreMetaOptions(); + } + return ret; +} + +// override so we can parse DOCINFO field subtypes INFO[1-4] +void SwHTMLParser::AddMetaUserDefined( ::rtl::OUString const & i_rMetaName ) +{ + // unless we already have 4 names, append the argument to m_InfoNames + ::rtl::OUString* pName // the first empty string in m_InfoNames + (!m_InfoNames[0].getLength() ? &m_InfoNames[0] : + (!m_InfoNames[1].getLength() ? &m_InfoNames[1] : + (!m_InfoNames[2].getLength() ? &m_InfoNames[2] : + (!m_InfoNames[3].getLength() ? &m_InfoNames[3] : 0 )))); + if (pName) + { + (*pName) = i_rMetaName; + } +} + |