blob: 2dad2c60453f0e6ffdadd8e9dc1392ce12bd6601 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"
#include <hintids.hxx>
#include <com/sun/star/i18n/ScriptType.hpp>
#include <vcl/svapp.hxx>
#include <vcl/wrkwin.hxx>
#include <tools/urlobj.hxx>
#include <sfx2/sfx.hrc>
#if !defined _SVSTDARR_XUB_STRLEN_DECL || !defined _SVSTDARR_USHORTS_DECL
#define _SVSTDARR_XUB_STRLEN
#define _SVSTDARR_USHORTS
#include <svl/svstdarr.hxx>
#endif
#include <svtools/htmlout.hxx>
#include <svtools/htmlkywd.hxx>
#include <svtools/htmltokn.h>
#include <svl/whiter.hxx>
#include <svx/htmlmode.hxx>
#include <editeng/escpitem.hxx>
#include <editeng/brkitem.hxx>
#include <editeng/boxitem.hxx>
#include <editeng/ulspitem.hxx>
#include <editeng/udlnitem.hxx>
#include <editeng/crsditem.hxx>
#include <editeng/blnkitem.hxx>
#include <editeng/cmapitem.hxx>
#include <editeng/colritem.hxx>
#include <editeng/fontitem.hxx>
#include <editeng/fhgtitem.hxx>
#include <editeng/postitem.hxx>
#include <editeng/kernitem.hxx>
#include <editeng/wghtitem.hxx>
#include <editeng/lspcitem.hxx>
#include <editeng/adjitem.hxx>
#include <editeng/lrspitem.hxx>
#include <editeng/brshitem.hxx>
#include <editeng/langitem.hxx>
#include <editeng/frmdiritem.hxx>
#include <fchrfmt.hxx>
#include <fmtautofmt.hxx>
#include <fmtfsize.hxx>
#include <fmtclds.hxx>
#include <fmtpdsc.hxx>
#include <fmtflcnt.hxx>
#include <fmtinfmt.hxx>
#include <fmtftn.hxx>
#include <txatbase.hxx>
#include <frmatr.hxx>
#include <charfmt.hxx>
#include <fmtfld.hxx>
#include <doc.hxx>
#include <pam.hxx>
#include <ndtxt.hxx>
#include <paratr.hxx>
#include <poolfmt.hxx>
#include <pagedesc.hxx>
#include <swtable.hxx>
#include "fldbas.hxx"
#include <breakit.hxx>
#include <htmlnum.hxx>
#include <wrthtml.hxx>
#include <htmlfly.hxx>
#include <numrule.hxx>
using namespace ::com::sun::star;
/*
* um nicht immer wieder nach einem Update festzustellen, das irgendwelche
* Hint-Ids dazugekommen sind, wird hier definiert, die Groesse der Tabelle
* definiert und mit der akt. verglichen. Bei unterschieden wird der
* Compiler schon meckern.
*
* diese Section und die dazugeherigen Tabellen muessen in folgenden Files
* gepflegt werden: rtf\rtfatr.cxx, sw6\sw6atr.cxx, w4w\w4watr.cxx
*/
#if !defined(UNX) && !defined(MSC) && !defined(PPC) && !defined(CSET) && !defined(__MWERKS__) && !defined(WTC) && !defined(__MINGW32__) && !defined(OS2)
#define ATTRFNTAB_SIZE 130
#if ATTRFNTAB_SIZE != POOLATTR_END - POOLATTR_BEGIN
#error Attribut-Tabelle ist ungueltigt. Wurden neue Hint-IDs zugefuegt ??
#endif
#ifdef FORMAT_TABELLE
// da sie nicht benutzt wird!
#define FORMATTAB_SIZE 7
#if FORMATTAB_SIZE != RES_FMT_END - RES_FMT_BEGIN
#error Format-Tabelle ist ungueltigt. Wurden neue Hint-IDs zugefuegt ??
#endif
#endif
#define NODETAB_SIZE 3
#if NODETAB_SIZE != RES_NODE_END - RES_NODE_BEGIN
#error Node-Tabelle ist ungueltigt. Wurden neue Hint-IDs zugefuegt ??
#endif
#endif
#define HTML_BULLETCHAR_DISC 34
#define HTML_BULLETCHAR_CIRCLE 38
#define HTML_BULLETCHAR_SQUARE 36
#define COLFUZZY 20
//-----------------------------------------------------------------------
HTMLOutEvent __FAR_DATA aAnchorEventTable[] =
{
{ OOO_STRING_SVTOOLS_HTML_O_SDonclick, OOO_STRING_SVTOOLS_HTML_O_onclick, SFX_EVENT_MOUSECLICK_OBJECT },
{ OOO_STRING_SVTOOLS_HTML_O_SDonmouseover, OOO_STRING_SVTOOLS_HTML_O_onmouseover, SFX_EVENT_MOUSEOVER_OBJECT },
{ OOO_STRING_SVTOOLS_HTML_O_SDonmouseout, OOO_STRING_SVTOOLS_HTML_O_onmouseout, SFX_EVENT_MOUSEOUT_OBJECT },
{ 0, 0, 0 }
};
static Writer& OutHTML_SvxAdjust( Writer& rWrt, const SfxPoolItem& rHt );
static Writer& OutHTML_HoriSpacer( Writer& rWrt, sal_Int16 nSize )
{
ASSERT( nSize>0, "horizontaler SPACER mit negativem Wert?" )
if( nSize <= 0 )
return rWrt;
if( Application::GetDefaultDevice() )
{
nSize = (sal_Int16)Application::GetDefaultDevice()
->LogicToPixel( Size(nSize,0), MapMode(MAP_TWIP) ).Width();
}
ByteString sOut( '<' );
(((((((((sOut += OOO_STRING_SVTOOLS_HTML_spacer)
+= ' ') += OOO_STRING_SVTOOLS_HTML_O_type) += '=') += OOO_STRING_SVTOOLS_HTML_SPTYPE_horizontal)
+= ' ') += OOO_STRING_SVTOOLS_HTML_O_size) += '=')
+=ByteString::CreateFromInt32(nSize)) += '>';
rWrt.Strm() << sOut.GetBuffer();
return rWrt;
}
sal_uInt16 SwHTMLWriter::GetDefListLvl( const String& rNm, sal_uInt16 nPoolId )
{
if( nPoolId == RES_POOLCOLL_HTML_DD )
{
return 1 | HTML_DLCOLL_DD;
}
else if( nPoolId == RES_POOLCOLL_HTML_DT )
{
return 1 | HTML_DLCOLL_DT;
}
String sDTDD( String::CreateFromAscii(OOO_STRING_SVTOOLS_HTML_dt) );
sDTDD += ' ';
if( COMPARE_EQUAL == sDTDD.CompareTo( rNm, sDTDD.Len() ) )
// DefinitionList - term
return (sal_uInt16)rNm.Copy( sDTDD.Len() ).ToInt32() | HTML_DLCOLL_DT;
sDTDD.AssignAscii( OOO_STRING_SVTOOLS_HTML_dd );
sDTDD += ' ';
if( COMPARE_EQUAL == sDTDD.CompareTo( rNm, sDTDD.Len() ) )
// DefinitionList - definition
return (sal_uInt16)rNm.Copy( sDTDD.Len() ).ToInt32() | HTML_DLCOLL_DD;
return 0;
}
void SwHTMLWriter::OutAndSetDefList( sal_uInt16 nNewLvl )
{
// eventuell muss erst mal eine Liste aufgemacht werden
if( nDefListLvl < nNewLvl )
{
// output </pre> for the previous(!) pararagraph, if required.
// Preferable, the <pre> is exported by OutHTML_SwFmtOff for the
// previous paragraph already, but that's not possible, because a very
// deep look at the next paragraph (this one) is required to figure
// out that a def list starts here.
ChangeParaToken( 0 );
// entsprechend dem Level-Unterschied schreiben!
for( sal_uInt16 i=nDefListLvl; i<nNewLvl; i++ )
{
if( bLFPossible )
OutNewLine();
HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_deflist, sal_True );
IncIndentLevel();
bLFPossible = sal_True;
}
}
else if( nDefListLvl > nNewLvl )
{
for( sal_uInt16 i=nNewLvl ; i < nDefListLvl; i++ )
{
DecIndentLevel();
if( bLFPossible )
OutNewLine();
HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_deflist, sal_False );
bLFPossible = sal_True;
}
}
nDefListLvl = nNewLvl;
}
void SwHTMLWriter::ChangeParaToken( sal_uInt16 nNew )
{
if( nNew != nLastParaToken && HTML_PREFORMTXT_ON == nLastParaToken )
{
HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_preformtxt, sal_False );
bLFPossible = sal_True;
}
nLastParaToken = nNew;
}
sal_uInt16 SwHTMLWriter::GetCSS1ScriptForScriptType( sal_uInt16 nScriptType )
{
sal_uInt16 nRet = CSS1_OUTMODE_ANY_SCRIPT;
switch( nScriptType )
{
case i18n::ScriptType::LATIN:
nRet = CSS1_OUTMODE_WESTERN;
break;
case i18n::ScriptType::ASIAN:
nRet = CSS1_OUTMODE_CJK;
break;
case i18n::ScriptType::COMPLEX:
nRet = CSS1_OUTMODE_CTL;
break;
}
return nRet;
}
// fuer die Formate muesste eine einzige Ausgabe-Funktion genuegen !
/*
* Formate wie folgt ausgeben:
* - fuer Formate, fuer die es entsprechende HTML-Tags gibt wird das
* Tag ausgegeben
* - fuer alle anderen wird ein Absatz-Tag <P> ausgegeben und bUserFmt
* gesetzt
* - Wenn eine Absatz-Ausrichtung am uebergebenen Item-Set des Nodes
* oder im Item-Set des Format gesetzt ist, wird ein ALIGN=xxx ausgegeben,
* sofern HTML es zulaesst
* - in jedem Fall wird harte Attributierung als STYLE-Option geschrieben.
* Wenn bUserFmt nicht gesetzt ist, wird nur der uebergebene Item-Set
* betrachtet. Sonst werden auch Attribute des Formats ausgegeben.
*/
struct SwHTMLTxtCollOutputInfo
{
ByteString aToken; // auszugendens End-Token
SfxItemSet *pItemSet; // harte Attributierung
sal_Bool bInNumBulList; // in einer Aufzaehlungs-Liste;
sal_Bool bParaPossible; // ein </P> darf zusaetzlich ausgegeben werden
sal_Bool bOutPara; // ein </P> soll ausgegeben werden
sal_Bool bOutDiv; // write a </DIV>
SwHTMLTxtCollOutputInfo() :
pItemSet( 0 ),
bInNumBulList( sal_False ),
bParaPossible( sal_False ),
bOutPara( sal_False ),
bOutDiv( sal_False )
{}
~SwHTMLTxtCollOutputInfo();
sal_Bool HasParaToken() const { return aToken.Len()==1 && aToken.GetChar(0)=='P'; }
sal_Bool ShouldOutputToken() const { return bOutPara || !HasParaToken(); }
};
SwHTMLTxtCollOutputInfo::~SwHTMLTxtCollOutputInfo()
{
delete pItemSet;
}
struct SwHTMLFmtInfo
{
const SwFmt *pFmt; // das Format selbst
const SwFmt *pRefFmt; // das Vergleichs-Format
ByteString aToken; // das auszugebende Token
String aClass; // die auszugebende Klasse
SfxItemSet *pItemSet; // der auszugebende Attribut-Set
sal_Int32 nLeftMargin; // ein par default-Werte fuer
sal_Int32 nRightMargin; // Absatz-Vorlagen
short nFirstLineIndent;
sal_uInt16 nTopMargin;
sal_uInt16 nBottomMargin;
sal_Bool bScriptDependent;
// Konstruktor fuer einen Dummy zum Suchen
SwHTMLFmtInfo( const SwFmt *pF ) :
pFmt( pF ), pItemSet( 0 )
{}
// Konstruktor zum Erstellen der Format-Info
SwHTMLFmtInfo( const SwFmt *pFmt, SwDoc *pDoc, SwDoc *pTemlate,
sal_Bool bOutStyles, LanguageType eDfltLang=LANGUAGE_DONTKNOW,
sal_uInt16 nScript=CSS1_OUTMODE_ANY_SCRIPT,
sal_Bool bHardDrop=sal_False );
~SwHTMLFmtInfo();
friend sal_Bool operator==( const SwHTMLFmtInfo& rInfo1,
const SwHTMLFmtInfo& rInfo2 )
{
return (long)rInfo1.pFmt == (long)rInfo2.pFmt;
}
friend sal_Bool operator<( const SwHTMLFmtInfo& rInfo1,
const SwHTMLFmtInfo& rInfo2 )
{
return (long)rInfo1.pFmt < (long)rInfo2.pFmt;
}
};
SV_IMPL_OP_PTRARR_SORT( SwHTMLFmtInfos, SwHTMLFmtInfo* )
SwHTMLFmtInfo::SwHTMLFmtInfo( const SwFmt *pF, SwDoc *pDoc, SwDoc *pTemplate,
sal_Bool bOutStyles,
LanguageType eDfltLang,
sal_uInt16 nCSS1Script, sal_Bool bHardDrop ) :
pFmt( pF ), pItemSet( 0 ), bScriptDependent( sal_False )
{
sal_uInt16 nRefPoolId = 0;
// Den Selektor des Formats holen
sal_uInt16 nDeep = SwHTMLWriter::GetCSS1Selector( pFmt, aToken, aClass,
nRefPoolId );
ASSERT( nDeep ? aToken.Len()>0 : aToken.Len()==0,
"Hier stimmt doch was mit dem Token nicht!" );
ASSERT( nDeep ? nRefPoolId : !nRefPoolId,
"Hier stimmt doch was mit der Vergleichs-Vorlage nicht!" );
sal_Bool bTxtColl = pFmt->Which() == RES_TXTFMTCOLL ||
pFmt->Which() == RES_CONDTXTFMTCOLL;
const SwFmt *pReferenceFmt = 0; // Vergleichs-Format
sal_Bool bSetDefaults = sal_True, bClearSame = sal_True;
if( nDeep != 0 )
{
// Es ist eine HTML-Tag-Vorlage oder die Vorlage ist von einer
// solchen abgeleitet
if( !bOutStyles )
{
// wenn keine Styles exportiert werden, muss evtl. zusaetlich
// harte Attributierung geschrieben werden
switch( nDeep )
{
case CSS1_FMT_ISTAG:
case CSS1_FMT_CMPREF:
// fuer HTML-Tag-Vorlagen die Unterscheide zum Original
// (sofern verfuegbar)
pReferenceFmt = SwHTMLWriter::GetTemplateFmt( nRefPoolId,
pTemplate );
break;
default:
// sonst die zur HTML-Tag-Vorlage des Originals oder des
// aktuellen Doks, wenn die nicht verfuegbar ist
if( pTemplate )
pReferenceFmt = SwHTMLWriter::GetTemplateFmt( nRefPoolId,
pTemplate );
else
pReferenceFmt = SwHTMLWriter::GetParentFmt( *pFmt, nDeep );
break;
}
}
}
else if( bTxtColl )
{
// Nicht von einer HTML-Tag-Vorlage abgeleitete Absatz-Vorlagen
// muessen als harte Attributierung relativ zur Textkoerper-Volage
// exportiert werden. Fuer Nicht-Styles-Export sollte die der
// HTML-Vorlage als Referenz dienen
if( !bOutStyles && pTemplate )
pReferenceFmt = pTemplate->GetTxtCollFromPool( RES_POOLCOLL_TEXT, false );
else
pReferenceFmt = pDoc->GetTxtCollFromPool( RES_POOLCOLL_TEXT, false );
}
if( pReferenceFmt || nDeep==0 )
{
pItemSet = new SfxItemSet( *pFmt->GetAttrSet().GetPool(),
pFmt->GetAttrSet().GetRanges() );
// wenn Unterschiede zu einer anderen Vorlage geschrieben werden
// sollen ist harte Attributierung noetig. Fuer Vorlagen, die
// nicht von HTML-Tag-Vorlagen abgeleitet sind, gilt das immer
pItemSet->Set( pFmt->GetAttrSet(), sal_True );
if( pReferenceFmt )
SwHTMLWriter::SubtractItemSet( *pItemSet, pReferenceFmt->GetAttrSet(),
bSetDefaults, bClearSame );
// einen leeren Item-Set gleich loeschen, das spart speater
// Arbeit
if( !pItemSet->Count() )
{
delete pItemSet;
pItemSet = 0;
}
}
if( bTxtColl )
{
if( bOutStyles )
{
// We have to add hard attributes for any script dependent
// item that is not accessed by the style
static sal_uInt16 aWhichIds[3][4] =
{
{ RES_CHRATR_FONT, RES_CHRATR_FONTSIZE,
RES_CHRATR_POSTURE, RES_CHRATR_WEIGHT },
{ RES_CHRATR_CJK_FONT, RES_CHRATR_CJK_FONTSIZE,
RES_CHRATR_CJK_POSTURE, RES_CHRATR_CJK_WEIGHT },
{ RES_CHRATR_CTL_FONT, RES_CHRATR_CTL_FONTSIZE,
RES_CHRATR_CTL_POSTURE, RES_CHRATR_CTL_WEIGHT }
};
sal_uInt16 nRef = 0;
sal_uInt16 aSets[2] = {0,0};
switch( nCSS1Script )
{
case CSS1_OUTMODE_WESTERN:
nRef = 0;
aSets[0] = 1;
aSets[1] = 2;
break;
case CSS1_OUTMODE_CJK:
nRef = 1;
aSets[0] = 0;
aSets[1] = 2;
break;
case CSS1_OUTMODE_CTL:
nRef = 2;
aSets[0] = 0;
aSets[1] = 1;
break;
}
for( sal_uInt16 i=0; i<4; i++ )
{
const SfxPoolItem& rRef = pFmt->GetFmtAttr( aWhichIds[nRef][i] );
for( sal_uInt16 j=0; j<2; j++ )
{
const SfxPoolItem& rSet = pFmt->GetFmtAttr( aWhichIds[aSets[j]][i] );
if( rSet != rRef )
{
if( !pItemSet )
pItemSet = new SfxItemSet( *pFmt->GetAttrSet().GetPool(),
pFmt->GetAttrSet().GetRanges() );
pItemSet->Put( rSet );
}
}
}
}
// Ggf. noch ein DropCap-Attribut uebernehmen
if( bOutStyles && bHardDrop && nDeep != 0 )
{
const SfxPoolItem *pItem;
if( SFX_ITEM_SET==pFmt->GetAttrSet().GetItemState(
RES_PARATR_DROP, sal_True, &pItem ) )
{
sal_Bool bPut = sal_True;
if( pTemplate )
{
pReferenceFmt = SwHTMLWriter::GetTemplateFmt( nRefPoolId, pTemplate );
const SfxPoolItem *pRefItem;
sal_Bool bRefItemSet =
SFX_ITEM_SET==pReferenceFmt->GetAttrSet().GetItemState(
RES_PARATR_DROP, sal_True, &pRefItem );
bPut = !bRefItemSet || *pItem!=*pRefItem;
}
if( bPut )
{
if( !pItemSet )
pItemSet = new SfxItemSet( *pFmt->GetAttrSet().GetPool(),
pFmt->GetAttrSet().GetRanges() );
pItemSet->Put( *pItem );
}
}
}
// Die diversen default-Abstaende aus der Vorlage oder der
// Vergleischs-Vorlage merken
const SvxLRSpaceItem &rLRSpace =
(pReferenceFmt ? pReferenceFmt : pFmt)->GetLRSpace();
nLeftMargin = rLRSpace.GetTxtLeft();
nRightMargin = rLRSpace.GetRight();
nFirstLineIndent = rLRSpace.GetTxtFirstLineOfst();
const SvxULSpaceItem &rULSpace =
(pReferenceFmt ? pReferenceFmt : pFmt)->GetULSpace();
nTopMargin = rULSpace.GetUpper();
nBottomMargin = rULSpace.GetLower();
// export language if it differs from the default language
sal_uInt16 nWhichId =
SwHTMLWriter::GetLangWhichIdFromScript( nCSS1Script );
const SvxLanguageItem& rLang =
(const SvxLanguageItem&)pFmt->GetFmtAttr( nWhichId );
LanguageType eLang = rLang.GetLanguage();
if( eLang != eDfltLang )
{
if( !pItemSet )
pItemSet = new SfxItemSet( *pFmt->GetAttrSet().GetPool(),
pFmt->GetAttrSet().GetRanges() );
pItemSet->Put( rLang );
}
static sal_uInt16 aWhichIds[3] =
{ RES_CHRATR_LANGUAGE, RES_CHRATR_CJK_LANGUAGE,
RES_CHRATR_CTL_LANGUAGE };
for( sal_uInt16 i=0; i<3; i++ )
{
if( aWhichIds[i] != nWhichId )
{
const SvxLanguageItem& rTmpLang =
(const SvxLanguageItem&)pFmt->GetFmtAttr(aWhichIds[i]);
if( rTmpLang.GetLanguage() != eLang )
{
if( !pItemSet )
pItemSet = new SfxItemSet( *pFmt->GetAttrSet().GetPool(),
pFmt->GetAttrSet().GetRanges() );
pItemSet->Put( rTmpLang );
}
}
}
}
}
SwHTMLFmtInfo::~SwHTMLFmtInfo()
{
delete pItemSet;
}
void OutHTML_SwFmt( Writer& rWrt, const SwFmt& rFmt,
const SfxItemSet *pNodeItemSet,
SwHTMLTxtCollOutputInfo& rInfo )
{
ASSERT( RES_CONDTXTFMTCOLL==rFmt.Which() || RES_TXTFMTCOLL==rFmt.Which(),
"keine Absatz-Vorlage" );
SwHTMLWriter & rHWrt = (SwHTMLWriter&)rWrt;
// Erstmal ein par Flags ...
sal_uInt16 nNewDefListLvl = 0;
sal_uInt16 nNumStart = USHRT_MAX;
sal_Bool bForceDL = sal_False;
sal_Bool bDT = sal_False;
rInfo.bInNumBulList = sal_False; // Wir sind in einer Liste?
sal_Bool bNumbered = sal_False; // Der aktuelle Absatz ist numeriert
sal_Bool bPara = sal_False; // das aktuelle Token ist <P>
rInfo.bParaPossible = sal_False; // ein <P> darf zusaetzlich ausgegeben werden
sal_Bool bNoEndTag = sal_False; // kein End-Tag ausgeben
rHWrt.bNoAlign = sal_False; // kein ALIGN=... moeglich
sal_Bool bNoStyle = sal_False; // kein STYLE=... moeglich
sal_uInt8 nBulletGrfLvl = 255; // Die auszugebende Bullet-Grafik
// Sind wir in einer Aufzaehlungs- oder Numerierungliste?
const SwTxtNode* pTxtNd = rWrt.pCurPam->GetNode()->GetTxtNode();
SwHTMLNumRuleInfo aNumInfo;
if( rHWrt.GetNextNumInfo() )
{
aNumInfo = *rHWrt.GetNextNumInfo();
rHWrt.ClearNextNumInfo();
}
else
{
aNumInfo.Set( *pTxtNd );
}
if( aNumInfo.GetNumRule() )
{
rInfo.bInNumBulList = sal_True;
nNewDefListLvl = 0;
// ist der aktuelle Absatz numeriert?
bNumbered = aNumInfo.IsNumbered();
sal_uInt8 nLvl = aNumInfo.GetLevel();
ASSERT( pTxtNd->GetActualListLevel() == nLvl,
"Gemerkter Num-Level ist falsch" );
ASSERT( bNumbered == static_cast< sal_Bool >(pTxtNd->IsCountedInList()),
"Gemerkter Numerierungs-Zustand ist falsch" );
if( bNumbered )
{
nBulletGrfLvl = nLvl; // nur veruebergehend!!!
// --> OD 2005-11-15 #i57919#
// correction of re-factoring done by cws swnumtree:
// - <nNumStart> has to contain the restart value, if the
// numbering is restarted at this text node. Value <USHRT_MAX>
// indicates, that no additional restart value has to be written.
if ( pTxtNd->IsListRestart() )
{
nNumStart = static_cast< sal_uInt16 >(pTxtNd->GetActualListStartValue());
}
// <--
DBG_ASSERT( rHWrt.nLastParaToken == 0,
"<PRE> wurde nicht vor <LI> beendet." );
}
}
// Jetzt holen wir das Token und ggf. die Klasse
SwHTMLFmtInfo aFmtInfo( &rFmt );
sal_uInt16 nArrayPos;
const SwHTMLFmtInfo *pFmtInfo;
if( rHWrt.aTxtCollInfos.Seek_Entry( &aFmtInfo, &nArrayPos ) )
{
pFmtInfo = rHWrt.aTxtCollInfos[nArrayPos];
}
else
{
pFmtInfo = new SwHTMLFmtInfo( &rFmt, rWrt.pDoc, rHWrt.pTemplate,
rHWrt.bCfgOutStyles, rHWrt.eLang,
rHWrt.nCSS1Script,
!rHWrt.IsHTMLMode(HTMLMODE_DROPCAPS) );
rHWrt.aTxtCollInfos.C40_PTR_INSERT( SwHTMLFmtInfo, pFmtInfo );
String aName( rFmt.GetName() );
if( rHWrt.aScriptParaStyles.Seek_Entry( &aName ) )
((SwHTMLFmtInfo *)pFmtInfo)->bScriptDependent = sal_True;
}
// Jetzt wird festgelegt, was aufgrund des Tokens so moeglich ist
sal_uInt16 nToken = 0; // Token fuer Tag-Wechsel
sal_Bool bOutNewLine = sal_False; // nur ein LF ausgeben?
if( pFmtInfo->aToken.Len() )
{
// Es ist eine HTML-Tag-Vorlage oder die Vorlage ist von einer
// solchen abgeleitet
rInfo.aToken = pFmtInfo->aToken;
// der erste Buchstabe reicht meistens
switch( rInfo.aToken.GetChar( 0 ) )
{
case 'A': ASSERT( rInfo.aToken.Equals(OOO_STRING_SVTOOLS_HTML_address),
"Doch kein ADDRESS?" );
rInfo.bParaPossible = sal_True;
rHWrt.bNoAlign = sal_True;
break;
case 'B': ASSERT( rInfo.aToken.Equals(OOO_STRING_SVTOOLS_HTML_blockquote),
"Doch kein BLOCKQUOTE?" );
rInfo.bParaPossible = sal_True;
rHWrt.bNoAlign = sal_True;
break;
case 'P': if( rInfo.aToken.Len() == 1 )
{
bPara = sal_True;
}
else
{
ASSERT( rInfo.aToken.Equals(OOO_STRING_SVTOOLS_HTML_preformtxt),
"Doch kein PRE?" );
if( HTML_PREFORMTXT_ON == rHWrt.nLastParaToken )
{
bOutNewLine = sal_True;
}
else
{
nToken = HTML_PREFORMTXT_ON;
rHWrt.bNoAlign = sal_True;
bNoEndTag = sal_True;
}
}
break;
case 'D': ASSERT( rInfo.aToken.Equals(OOO_STRING_SVTOOLS_HTML_dt) ||
rInfo.aToken.Equals(OOO_STRING_SVTOOLS_HTML_dd),
"Doch kein DD/DT?" );
bDT = rInfo.aToken.Equals(OOO_STRING_SVTOOLS_HTML_dt);
rInfo.bParaPossible = !bDT;
rHWrt.bNoAlign = sal_True;
bForceDL = sal_True;
break;
}
}
else
{
// alle Vorlagen, die nicht einem HTML-Tag entsprechen oder von
// diesem abgeleitet sind, werden als <P> exportiert
rInfo.aToken = OOO_STRING_SVTOOLS_HTML_parabreak;
bPara = sal_True;
}
// Falls noetig, die harte Attributierung der Vorlage uebernehmen
if( pFmtInfo->pItemSet )
{
ASSERT( !rInfo.pItemSet, "Wo kommt der Item-Set her?" );
rInfo.pItemSet = new SfxItemSet( *pFmtInfo->pItemSet );
}
// und noch die harte Attributierung des Absatzes dazunehmen
if( pNodeItemSet )
{
if( rInfo.pItemSet )
rInfo.pItemSet->Put( *pNodeItemSet );
else
rInfo.pItemSet = new SfxItemSet( *pNodeItemSet );
}
// den unteren Absatz-Abstand brauchen wir noch
const SvxULSpaceItem& rULSpace =
pNodeItemSet ? ((const SvxULSpaceItem &)pNodeItemSet->Get(RES_UL_SPACE))
: rFmt.GetULSpace();
if( (rHWrt.bOutHeader &&
rWrt.pCurPam->GetPoint()->nNode.GetIndex() ==
rWrt.pCurPam->GetMark()->nNode.GetIndex()) ||
rHWrt.bOutFooter )
{
if( rHWrt.bCfgOutStyles )
{
SvxULSpaceItem aULSpaceItem( rULSpace );
if( rHWrt.bOutHeader )
aULSpaceItem.SetLower( rHWrt.nHeaderFooterSpace );
else
aULSpaceItem.SetUpper( rHWrt.nHeaderFooterSpace );
if( !rInfo.pItemSet )
rInfo.pItemSet = new SfxItemSet(
*rFmt.GetAttrSet().GetPool(),
RES_UL_SPACE, RES_UL_SPACE );
rInfo.pItemSet->Put( aULSpaceItem );
}
rHWrt.bOutHeader = sal_False;
rHWrt.bOutFooter = sal_False;
}
if( bOutNewLine )
{
// nur einen Zeilen-Umbruch (ohne Einrueckung) am Absatz-Anfang
// ausgeben
rInfo.aToken.Erase(); // kein End-Tag ausgeben
rWrt.Strm() << SwHTMLWriter::sNewLine;
return;
}
// soll ein ALIGN=... geschrieben werden?
const SfxPoolItem* pAdjItem = 0;
const SfxPoolItem* pItem;
if( rInfo.pItemSet &&
SFX_ITEM_SET == rInfo.pItemSet->GetItemState( RES_PARATR_ADJUST,
sal_False, &pItem ) )
{
pAdjItem = pItem;
}
// Unteren Absatz-Abstand beachten ? (nie im letzen Absatz von
// Tabellen)
sal_Bool bUseParSpace = !rHWrt.bOutTable ||
(rWrt.pCurPam->GetPoint()->nNode.GetIndex() !=
rWrt.pCurPam->GetMark()->nNode.GetIndex());
// Wenn Styles exportiert werden, wird aus eingerueckten Absaetzen
// eine Definitions-Liste
const SvxLRSpaceItem& rLRSpace =
pNodeItemSet ? ((const SvxLRSpaceItem &)pNodeItemSet->Get(RES_LR_SPACE))
: rFmt.GetLRSpace();
if( (!rHWrt.bCfgOutStyles || bForceDL) && !rInfo.bInNumBulList )
{
sal_Int32 nLeftMargin;
if( bForceDL )
nLeftMargin = rLRSpace.GetTxtLeft();
else
nLeftMargin = rLRSpace.GetTxtLeft() > pFmtInfo->nLeftMargin
? rLRSpace.GetTxtLeft() - pFmtInfo->nLeftMargin
: 0;
if( nLeftMargin > 0 && rHWrt.nDefListMargin > 0 )
{
nNewDefListLvl = static_cast< sal_uInt16 >((nLeftMargin + (rHWrt.nDefListMargin/2)) /
rHWrt.nDefListMargin);
if( nNewDefListLvl == 0 && bForceDL && !bDT )
nNewDefListLvl = 1;
}
else
{
// If the left margin is 0 or negative, emulating indent
// with <dd> does not work. We then set a def list only if
// the dd style is used.
nNewDefListLvl = (bForceDL&& !bDT) ? 1 : 0;
}
sal_Bool bIsNextTxtNode =
rWrt.pDoc->GetNodes()[rWrt.pCurPam->GetPoint()->nNode.GetIndex()+1]
->IsTxtNode();
if( bForceDL && bDT )
{
// Statt eines DD muessen wir hier auch ein DT der Ebene
// darueber nehmen
nNewDefListLvl++;
}
else if( !nNewDefListLvl && !rHWrt.bCfgOutStyles && bPara &&
rULSpace.GetLower()==0 &&
((bUseParSpace && bIsNextTxtNode) || rHWrt.nDefListLvl==1) &&
(!pAdjItem || SVX_ADJUST_LEFT==
((const SvxAdjustItem *)pAdjItem)->GetAdjust()) )
{
// Absaetze ohne unteren Abstand als DT exportieren
nNewDefListLvl = 1;
bDT = sal_True;
rInfo.bParaPossible = sal_False;
rHWrt.bNoAlign = sal_True;
}
}
if( nNewDefListLvl != rHWrt.nDefListLvl )
rHWrt.OutAndSetDefList( nNewDefListLvl );
// ggf. eine Aufzaehlung- oder Numerierungsliste beginnen
if( rInfo.bInNumBulList )
{
ASSERT( !rHWrt.nDefListLvl, "DL in OL geht nicht!" );
OutHTML_NumBulListStart( rHWrt, aNumInfo );
if( bNumbered )
{
if( rHWrt.aBulletGrfs[nBulletGrfLvl].Len() )
bNumbered = sal_False;
else
nBulletGrfLvl = 255;
}
}
// Die Defaults aus der Vorlage merken, denn sie muessen nicht
// exportiert werden
rHWrt.nDfltLeftMargin = pFmtInfo->nLeftMargin;
rHWrt.nDfltRightMargin = pFmtInfo->nRightMargin;
rHWrt.nDfltFirstLineIndent = pFmtInfo->nFirstLineIndent;
if( rInfo.bInNumBulList )
{
if( !rHWrt.IsHTMLMode( HTMLMODE_LSPACE_IN_NUMBUL ) )
rHWrt.nDfltLeftMargin = rLRSpace.GetTxtLeft();
// In Numerierungs-Listen keinen Ertzeilen-Einzug ausgeben.
rHWrt.nFirstLineIndent = rLRSpace.GetTxtFirstLineOfst();
}
if( rInfo.bInNumBulList && bNumbered && bPara && !rHWrt.bCfgOutStyles )
{
// ein einzelnes LI hat keinen Abstand
rHWrt.nDfltTopMargin = 0;
rHWrt.nDfltBottomMargin = 0;
}
else if( rHWrt.nDefListLvl && bPara )
{
// ein einzelnes DD hat auch keinen Abstand
rHWrt.nDfltTopMargin = 0;
rHWrt.nDfltBottomMargin = 0;
}
else
{
rHWrt.nDfltTopMargin = pFmtInfo->nTopMargin;
// #60393#: Wenn im letzten Absatz einer Tabelle der
// untere Absatz-Abstand veraendert wird, vertut sich
// Netscape total. Deshalb exportieren wir hier erstmal
// nichts, indem wir den Abstand aus dem Absatz als Default
// setzen.
if( rHWrt.bCfgNetscape4 && !bUseParSpace )
rHWrt.nDfltBottomMargin = rULSpace.GetLower();
else
rHWrt.nDfltBottomMargin = pFmtInfo->nBottomMargin;
}
if( rHWrt.nDefListLvl )
{
rHWrt.nLeftMargin =
(rHWrt.nDefListLvl-1) * rHWrt.nDefListMargin;
}
if( rHWrt.bLFPossible )
rHWrt.OutNewLine(); // Absatz-Tag in neue Zeile
rInfo.bOutPara = sal_False;
// das ist jetzt unser neues Token
rHWrt.ChangeParaToken( nToken );
sal_Bool bHasParSpace = bUseParSpace && rULSpace.GetLower() > 0;
// ggf ein List-Item aufmachen
if( rInfo.bInNumBulList && bNumbered )
{
ByteString sOut( '<' );
sOut += OOO_STRING_SVTOOLS_HTML_li;
if( USHRT_MAX != nNumStart )
(((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_value) += '=')
+= ByteString::CreateFromInt32(nNumStart);
sOut += '>';
rWrt.Strm() << sOut.GetBuffer();
}
if( rHWrt.nDefListLvl > 0 && !bForceDL )
{
HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), bDT ? OOO_STRING_SVTOOLS_HTML_dt : OOO_STRING_SVTOOLS_HTML_dd );
}
if( pAdjItem &&
rHWrt.IsHTMLMode( HTMLMODE_NO_CONTROL_CENTERING ) &&
rHWrt.HasControls() )
{
// #64687#: The align=... attribute does behave strange in netscape
// if there are controls in a paragraph, because the control and
// all text behind the control does not recognize this attribute.
ByteString sOut( '<' );
sOut += OOO_STRING_SVTOOLS_HTML_division;
rWrt.Strm() << sOut.GetBuffer();
rHWrt.bTxtAttr = sal_False;
rHWrt.bOutOpts = sal_True;
OutHTML_SvxAdjust( rWrt, *pAdjItem );
rWrt.Strm() << '>';
pAdjItem = 0;
rHWrt.bNoAlign = sal_False;
rInfo.bOutDiv = sal_True;
rHWrt.IncIndentLevel();
rHWrt.bLFPossible = sal_True;
rHWrt.OutNewLine();
}
// fuer BLOCKQUOTE, ADDRESS und DD wird noch ein Absatz-Token
// ausgegeben, wenn,
// - keine Styles geschrieben werden, und
// - ein untere Abstand oder eine Absatz-Ausrichtung existiert
ByteString aToken = rInfo.aToken;
if( !rHWrt.bCfgOutStyles && rInfo.bParaPossible && !bPara &&
(bHasParSpace || pAdjItem) )
{
HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), rInfo.aToken.GetBuffer() );
aToken = OOO_STRING_SVTOOLS_HTML_parabreak;
bPara = sal_True;
rHWrt.bNoAlign = sal_False;
bNoStyle = sal_False;
}
LanguageType eLang = rInfo.pItemSet
? ((const SvxLanguageItem&)rInfo.pItemSet->Get(SwHTMLWriter::GetLangWhichIdFromScript(rHWrt.nCSS1Script))).GetLanguage()
: rHWrt.eLang;
if( rInfo.pItemSet )
{
static sal_uInt16 aWhichIds[3] = { RES_CHRATR_LANGUAGE, RES_CHRATR_CJK_LANGUAGE, RES_CHRATR_CTL_LANGUAGE };
for( sal_uInt16 i=0; i<3; i++ )
{
// export language if it differs from the default language only.
const SfxPoolItem *pTmpItem;
if( SFX_ITEM_SET == rInfo.pItemSet->GetItemState( aWhichIds[i],
sal_True, &pTmpItem ) &&
((const SvxLanguageItem *)pTmpItem)->GetLanguage() == eLang )
rInfo.pItemSet->ClearItem( aWhichIds[i] );
}
}
// and the text direction
sal_uInt16 nDir = rHWrt.GetHTMLDirection(
(pNodeItemSet ? static_cast < const SvxFrameDirectionItem& >(
pNodeItemSet->Get( RES_FRAMEDIR ) )
: rFmt.GetFrmDir() ).GetValue() );
// Ein <P> wird nur geschrieben, wenn
// - wir in keiner OL/UL/DL sind, oder
// - der Absatz einer OL/UL nicht numeriert ist, oder
// - keine Styles exportiert werden und
// - ein unterer Abstand oder
// - eine Absatz-Ausrichtung existiert, ode
// - Styles exportiert werden und,
// - die Textkoerper-Vorlage geaendert wurde, oder
// - ein Benutzer-Format exportiert wird, oder
// - Absatz-Attribute existieren
if( !bPara ||
(!rInfo.bInNumBulList && !rHWrt.nDefListLvl) ||
(rInfo.bInNumBulList && !bNumbered) ||
(!rHWrt.bCfgOutStyles &&
(bHasParSpace || pAdjItem ||
(eLang != LANGUAGE_DONTKNOW && eLang != rHWrt.eLang))) ||
nDir != rHWrt.nDirection ||
rHWrt.bCfgOutStyles )
{
// jetzt werden Optionen ausgegeben
rHWrt.bTxtAttr = sal_False;
rHWrt.bOutOpts = sal_True;
ByteString sOut( '<' );
sOut += aToken;
if( eLang != LANGUAGE_DONTKNOW && eLang != rHWrt.eLang )
{
rWrt.Strm() << sOut.GetBuffer();
rHWrt.OutLanguage( eLang );
sOut.Erase();
}
if( nDir != rHWrt.nDirection )
{
if( sOut.Len() )
{
rWrt.Strm() << sOut.GetBuffer();
sOut.Erase();
}
rHWrt.OutDirection( nDir );
}
if( rHWrt.bCfgOutStyles &&
(pFmtInfo->aClass.Len() || pFmtInfo->bScriptDependent) )
{
((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_class) += "=\"";
rWrt.Strm() << sOut.GetBuffer();
String aClass( pFmtInfo->aClass );
if( pFmtInfo->bScriptDependent )
{
if( aClass.Len() )
aClass += '-';
switch( rHWrt.nCSS1Script )
{
case CSS1_OUTMODE_WESTERN:
aClass.AppendAscii( RTL_CONSTASCII_STRINGPARAM("western") );
break;
case CSS1_OUTMODE_CJK:
aClass.AppendAscii( RTL_CONSTASCII_STRINGPARAM("cjk") );
break;
case CSS1_OUTMODE_CTL:
aClass.AppendAscii( RTL_CONSTASCII_STRINGPARAM("ctl") );
break;
}
}
HTMLOutFuncs::Out_String( rWrt.Strm(), aClass,
rHWrt.eDestEnc, &rHWrt.aNonConvertableCharacters );
sOut = '\"';
}
rWrt.Strm() << sOut.GetBuffer();
// ggf. Ausrichtung ausgeben.
if( !rHWrt.bNoAlign && pAdjItem )
OutHTML_SvxAdjust( rWrt, *pAdjItem );
// und nun ggf. noch die STYLE-Option
if( rHWrt.bCfgOutStyles && rInfo.pItemSet && !bNoStyle)
{
OutCSS1_ParaTagStyleOpt( rWrt, *rInfo.pItemSet );
}
rWrt.Strm() << '>';
// Soll ein </P> geschrieben wenrden
rInfo.bOutPara =
bPara &&
( rHWrt.bCfgOutStyles ||
(!rHWrt.bCfgOutStyles && bHasParSpace) );
// wenn kein End-Tag geschrieben werden soll, es loeschen
if( bNoEndTag )
rInfo.aToken.Erase();
}
// ??? Warum nicht ueber den Hint-Mechanismus ???
if( rHWrt.IsHTMLMode(HTMLMODE_FIRSTLINE) )
{
const SvxLRSpaceItem& rLRSpaceTmp =
pNodeItemSet ? ((const SvxLRSpaceItem &)pNodeItemSet->Get(RES_LR_SPACE))
: rFmt.GetLRSpace();
if( rLRSpaceTmp.GetTxtFirstLineOfst() > 0 )
{
OutHTML_HoriSpacer( rWrt, rLRSpaceTmp.GetTxtFirstLineOfst() );
}
}
if( nBulletGrfLvl != 255 )
{
ASSERT( aNumInfo.GetNumRule(), "Wo ist die Numerierung geblieben???" );
ASSERT( nBulletGrfLvl < MAXLEVEL, "So viele Ebenen gibt's nicht" );
const SwNumFmt& rNumFmt = aNumInfo.GetNumRule()->Get(nBulletGrfLvl);
OutHTML_BulletImage( rWrt, OOO_STRING_SVTOOLS_HTML_image, 0,
rHWrt.aBulletGrfs[nBulletGrfLvl],
rNumFmt.GetGraphicSize(), rNumFmt.GetGraphicOrientation() );
}
rHWrt.GetNumInfo() = aNumInfo;
// die Defaults zuruecksetzen
rHWrt.nDfltLeftMargin = 0;
rHWrt.nDfltRightMargin = 0;
rHWrt.nDfltFirstLineIndent = 0;
rHWrt.nDfltTopMargin = 0;
rHWrt.nDfltBottomMargin = 0;
rHWrt.nLeftMargin = 0;
rHWrt.nFirstLineIndent = 0;
}
void OutHTML_SwFmtOff( Writer& rWrt, const SwHTMLTxtCollOutputInfo& rInfo )
{
SwHTMLWriter & rHWrt = (SwHTMLWriter&)rWrt;
// wenn es kein Token gibt haben wir auch nichts auszugeben
if( !rInfo.aToken.Len() )
{
rHWrt.FillNextNumInfo();
const SwHTMLNumRuleInfo& rNextInfo = *rHWrt.GetNextNumInfo();
// Auch in PRE muss eine Bullet-Liste beendet werden
if( rInfo.bInNumBulList )
{
const SwHTMLNumRuleInfo& rNRInfo = rHWrt.GetNumInfo();
if( rNextInfo.GetNumRule() != rNRInfo.GetNumRule() ||
rNextInfo.GetDepth() != rNRInfo.GetDepth() ||
rNextInfo.IsNumbered() || rNextInfo.IsRestart() )
rHWrt.ChangeParaToken( 0 );
OutHTML_NumBulListEnd( rHWrt, rNextInfo );
}
else if( rNextInfo.GetNumRule() != 0 )
rHWrt.ChangeParaToken( 0 );
return;
}
if( rInfo.ShouldOutputToken() )
{
if( rHWrt.bLFPossible )
rHWrt.OutNewLine( sal_True );
// fuer BLOCKQUOTE, ADDRESS und DD wird ggf noch ein
// Absatz-Token ausgegeben, wenn
// - keine Styles geschrieben werden, und
// - ein untere Abstand existiert
if( rInfo.bParaPossible && rInfo.bOutPara )
HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_parabreak, sal_False );
HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), rInfo.aToken.GetBuffer(),
sal_False );
rHWrt.bLFPossible = !rInfo.aToken.Equals( OOO_STRING_SVTOOLS_HTML_dt ) &&
!rInfo.aToken.Equals( OOO_STRING_SVTOOLS_HTML_dd ) &&
!rInfo.aToken.Equals( OOO_STRING_SVTOOLS_HTML_li );
}
if( rInfo.bOutDiv )
{
rHWrt.DecIndentLevel();
if( rHWrt.bLFPossible )
rHWrt.OutNewLine();
HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_division, sal_False );
rHWrt.bLFPossible = sal_True;
}
// ggf. eine Aufzaehlung- oder Numerierungsliste beenden
if( rInfo.bInNumBulList )
{
rHWrt.FillNextNumInfo();
OutHTML_NumBulListEnd( rHWrt, *rHWrt.GetNextNumInfo() );
}
}
class HTMLSttEndPos
{
xub_StrLen nStart;
xub_StrLen nEnd;
SfxPoolItem* pItem;
public:
HTMLSttEndPos( const SfxPoolItem& rItem, xub_StrLen nStt, xub_StrLen nE );
~HTMLSttEndPos();
const SfxPoolItem *GetItem() const { return pItem; }
void SetStart( xub_StrLen nStt ) { nStart = nStt; }
xub_StrLen GetStart() const { return nStart; }
xub_StrLen GetEnd() const { return nEnd; }
void SetEnd( xub_StrLen nE ) { nEnd = nE; }
};
HTMLSttEndPos::HTMLSttEndPos( const SfxPoolItem& rItem, xub_StrLen nStt,
xub_StrLen nE ) :
nStart( nStt ),
nEnd( nE ),
pItem( rItem.Clone() )
{}
HTMLSttEndPos::~HTMLSttEndPos()
{
delete pItem;
}
typedef HTMLSttEndPos *HTMLSttEndPosPtr;
SV_DECL_PTRARR( _HTMLEndLst, HTMLSttEndPosPtr, 5, 5 )
enum HTMLOnOffState { HTML_NOT_SUPPORTED, // nicht unterst. Attribut
HTML_REAL_VALUE, // Attribut mit Wert
HTML_ON_VALUE, // Attribut entspricht On-Tag
HTML_OFF_VALUE, // Attribut entspricht Off-Tag
HTML_CHRFMT_VALUE, // Attribut fuer Zeichenvorlage
HTML_COLOR_VALUE, // Attribut fuer Vordergrundfarbe
HTML_STYLE_VALUE, // Attribut muss als Style exp.
HTML_DROPCAP_VALUE, // DropCap-Attributs
HTML_AUTOFMT_VALUE }; // Attribute for automatic character styles
class HTMLEndPosLst
{
_HTMLEndLst aStartLst; // nach Anfangs-Psoitionen sortierte Liste
_HTMLEndLst aEndLst; // nach End-Psotionen sortierte Liste
SvXub_StrLens aScriptChgLst; // positions where script changes
// 0 is not contained in this list,
// but the text length
// the script that is valif up to the position
// contained in aScriptChgList at the same index
::std::vector<sal_uInt16> aScriptLst;
SwDoc *pDoc; // das aktuelle Dokument
SwDoc* pTemplate; // die HTML-Vorlage (oder 0)
const Color* pDfltColor;// die Default-Vordergrund-Farbe
SvStringsSortDtor& rScriptTxtStyles; //
sal_uLong nHTMLMode;
sal_Bool bOutStyles : 1; // werden Styles exportiert
// die Position eines Items in der Start-/Ende-Liste suchen
sal_uInt16 _FindStartPos( const HTMLSttEndPos *pPos ) const;
sal_uInt16 _FindEndPos( const HTMLSttEndPos *pPos ) const;
// Eine SttEndPos in die Start- und Ende-Listen eintragen bzw. aus
// ihnen loeschen, wobei die Ende-Position bekannt ist
void _InsertItem( HTMLSttEndPos *pPos, sal_uInt16 nEndPos );
void _RemoveItem( sal_uInt16 nEndPos );
// die "Art" es Attributs ermitteln
HTMLOnOffState GetHTMLItemState( const SfxPoolItem& rItem );
// Existiert ein bestimmtes On-Tag-Item
sal_Bool ExistsOnTagItem( sal_uInt16 nWhich, xub_StrLen nPos );
// Existiert ein Item zum ausschalten eines Attributs, das genauso
// exportiert wird wie das uebergebene Item im gleichen Bereich?
sal_Bool ExistsOffTagItem( sal_uInt16 nWhich, xub_StrLen nStartPos,
xub_StrLen nEndPos );
// das Ende eines gesplitteten Items anpassen
void FixSplittedItem( HTMLSttEndPos *pPos, sal_uInt16 nStartPos,
xub_StrLen nNewEnd );
// Ein Attribut in die Listen eintragen und ggf. aufteilen
void InsertItem( const SfxPoolItem& rItem, xub_StrLen nStart,
xub_StrLen nEnd );
// Ein bereits vorhandenes Attribut aufteilen
void SplitItem( const SfxPoolItem& rItem, xub_StrLen nStart,
xub_StrLen nEnd );
// Insert without taking care of script
void InsertNoScript( const SfxPoolItem& rItem, xub_StrLen nStart,
xub_StrLen nEnd, SwHTMLFmtInfos& rFmtInfos,
sal_Bool bParaAttrs=sal_False );
const SwHTMLFmtInfo *GetFmtInfo( const SwFmt& rFmt,
SwHTMLFmtInfos& rFmtInfos );
public:
HTMLEndPosLst( SwDoc *pDoc, SwDoc* pTemplate, const Color* pDfltColor,
sal_Bool bOutStyles, sal_uLong nHTMLMode,
const String& rText, SvStringsSortDtor& rStyles );
~HTMLEndPosLst();
// Ein Attribut einfuegen
void Insert( const SfxPoolItem& rItem, xub_StrLen nStart, xub_StrLen nEnd,
SwHTMLFmtInfos& rFmtInfos, sal_Bool bParaAttrs=sal_False );
void Insert( const SfxItemSet& rItemSet, xub_StrLen nStart, xub_StrLen nEnd,
SwHTMLFmtInfos& rFmtInfos, sal_Bool bDeep,
sal_Bool bParaAttrs=sal_False );
void Insert( const SwDrawFrmFmt& rFmt, xub_StrLen nPos,
SwHTMLFmtInfos& rFmtInfos );
sal_uInt16 GetScriptAtPos( xub_StrLen nPos,
sal_uInt16 nWeak=CSS1_OUTMODE_ANY_SCRIPT );
void OutStartAttrs( SwHTMLWriter& rHWrt, xub_StrLen nPos,
HTMLOutContext *pContext = 0 );
void OutEndAttrs( SwHTMLWriter& rHWrt, xub_StrLen nPos,
HTMLOutContext *pContext = 0 );
sal_uInt16 Count() const { return aEndLst.Count(); }
sal_Bool IsHTMLMode( sal_uLong nMode ) const { return (nHTMLMode & nMode) != 0; }
};
sal_uInt16 HTMLEndPosLst::_FindStartPos( const HTMLSttEndPos *pPos ) const
{
sal_uInt16 i;
for( i = 0; i < aStartLst.Count() && aStartLst[i] != pPos; i++ )
;
ASSERT( i != aStartLst.Count(), "Item nicht in Start-Liste gefunden!" );
return i==aStartLst.Count() ? USHRT_MAX : i;
}
sal_uInt16 HTMLEndPosLst::_FindEndPos( const HTMLSttEndPos *pPos ) const
{
sal_uInt16 i;
for( i = 0; i < aEndLst.Count() && aEndLst[i] != pPos; i++ )
;
ASSERT( i != aEndLst.Count(), "Item nicht in Ende-Liste gefunden" );
return i==aEndLst.Count() ? USHRT_MAX : i;
}
void HTMLEndPosLst::_InsertItem( HTMLSttEndPos *pPos, sal_uInt16 nEndPos )
{
// In der Start-Liste das Attribut hinter allen vorher und an
// der gleichen Position gestarteten Attributen einfuegen
xub_StrLen nStart = pPos->GetStart();
sal_uInt16 i;
for( i = 0; i < aStartLst.Count() &&
aStartLst[i]->GetStart() <= nStart; i++ )
;
aStartLst.Insert( pPos, i );
// die Position in der Ende-Liste wurde uebergeben
aEndLst.Insert( pPos, nEndPos );
}
void HTMLEndPosLst::_RemoveItem( sal_uInt16 nEndPos )
{
HTMLSttEndPos *pPos = aEndLst[nEndPos];
// jetzt Suchen wir es in der Start-Liste
sal_uInt16 nStartPos = _FindStartPos( pPos );
if( nStartPos != USHRT_MAX )
aStartLst.Remove( nStartPos, 1 );
aEndLst.Remove( nEndPos, 1 );
delete pPos;
}
HTMLOnOffState HTMLEndPosLst::GetHTMLItemState( const SfxPoolItem& rItem )
{
HTMLOnOffState eState = HTML_NOT_SUPPORTED;
switch( rItem.Which() )
{
case RES_CHRATR_POSTURE:
case RES_CHRATR_CJK_POSTURE:
case RES_CHRATR_CTL_POSTURE:
switch( ((const SvxPostureItem&)rItem).GetPosture() )
{
case ITALIC_NORMAL:
eState = HTML_ON_VALUE;
break;
case ITALIC_NONE:
eState = HTML_OFF_VALUE;
break;
default:
if( IsHTMLMode(HTMLMODE_SOME_STYLES) )
eState = HTML_STYLE_VALUE;
break;
}
break;
case RES_CHRATR_CROSSEDOUT:
switch( ((const SvxCrossedOutItem&)rItem).GetStrikeout() )
{
case STRIKEOUT_SINGLE:
case STRIKEOUT_DOUBLE:
eState = HTML_ON_VALUE;
break;
case STRIKEOUT_NONE:
eState = HTML_OFF_VALUE;
break;
default:
;
}
break;
case RES_CHRATR_ESCAPEMENT:
switch( (const SvxEscapement)
((const SvxEscapementItem&)rItem).GetEnumValue() )
{
case SVX_ESCAPEMENT_SUPERSCRIPT:
case SVX_ESCAPEMENT_SUBSCRIPT:
eState = HTML_ON_VALUE;
break;
case SVX_ESCAPEMENT_OFF:
eState = HTML_OFF_VALUE;
break;
default:
;
}
break;
case RES_CHRATR_UNDERLINE:
switch( ((const SvxUnderlineItem&)rItem).GetLineStyle() )
{
case UNDERLINE_SINGLE:
eState = HTML_ON_VALUE;
break;
case UNDERLINE_NONE:
eState = HTML_OFF_VALUE;
break;
default:
if( IsHTMLMode(HTMLMODE_SOME_STYLES) )
eState = HTML_STYLE_VALUE;
break;
}
break;
case RES_CHRATR_OVERLINE:
if( IsHTMLMode(HTMLMODE_SOME_STYLES) )
eState = HTML_STYLE_VALUE;
break;
case RES_CHRATR_WEIGHT:
case RES_CHRATR_CJK_WEIGHT:
case RES_CHRATR_CTL_WEIGHT:
switch( ((const SvxWeightItem&)rItem).GetWeight() )
{
case WEIGHT_BOLD:
eState = HTML_ON_VALUE;
break;
case WEIGHT_NORMAL:
eState = HTML_OFF_VALUE;
break;
default:
if( IsHTMLMode(HTMLMODE_SOME_STYLES) )
eState = HTML_STYLE_VALUE;
break;
}
break;
case RES_CHRATR_BLINK:
if( IsHTMLMode(HTMLMODE_BLINK) )
eState = ((const SvxBlinkItem&)rItem).GetValue() ? HTML_ON_VALUE
: HTML_OFF_VALUE;
break;
case RES_CHRATR_COLOR:
eState = HTML_COLOR_VALUE;
break;
case RES_CHRATR_FONT:
case RES_CHRATR_FONTSIZE:
case RES_CHRATR_LANGUAGE:
case RES_CHRATR_CJK_FONT:
case RES_CHRATR_CJK_FONTSIZE:
case RES_CHRATR_CJK_LANGUAGE:
case RES_CHRATR_CTL_FONT:
case RES_CHRATR_CTL_FONTSIZE:
case RES_CHRATR_CTL_LANGUAGE:
case RES_TXTATR_INETFMT:
eState = HTML_REAL_VALUE;
break;
case RES_TXTATR_CHARFMT:
eState = HTML_CHRFMT_VALUE;
break;
case RES_TXTATR_AUTOFMT:
eState = HTML_AUTOFMT_VALUE;
break;
case RES_CHRATR_CASEMAP:
if( IsHTMLMode(HTMLMODE_SMALL_CAPS) )
eState = HTML_STYLE_VALUE;
case RES_CHRATR_KERNING:
if( IsHTMLMode(HTMLMODE_FULL_STYLES) )
eState = HTML_STYLE_VALUE;
break;
case RES_CHRATR_BACKGROUND:
if( IsHTMLMode(HTMLMODE_SOME_STYLES) )
eState = HTML_STYLE_VALUE;
break;
case RES_PARATR_DROP:
eState = HTML_DROPCAP_VALUE;
break;
// default:
// eState = HTML_NOT_SUPPORTED;
// break;
}
return eState;
}
sal_Bool HTMLEndPosLst::ExistsOnTagItem( sal_uInt16 nWhich, xub_StrLen nPos )
{
for( sal_uInt16 i=0; i<aStartLst.Count(); i++ )
{
HTMLSttEndPos *pTest = aStartLst[i];
if( pTest->GetStart() > nPos )
{
// dieses uns alle folgenden Attribute beginnen spaeter
break;
}
else if( pTest->GetEnd() > nPos )
{
// das Attribut beginnt vor oder an der aktuellen Position
// und endet hinter ihr
const SfxPoolItem *pItem = pTest->GetItem();
if( pItem->Which() == nWhich &&
HTML_ON_VALUE == GetHTMLItemState(*pItem) )
{
// ein On-Tag-Attibut wurde gefunden
return sal_True;
}
}
}
return sal_False;
}
sal_Bool HTMLEndPosLst::ExistsOffTagItem( sal_uInt16 nWhich, xub_StrLen nStartPos,
xub_StrLen nEndPos )
{
if( nWhich != RES_CHRATR_CROSSEDOUT &&
nWhich != RES_CHRATR_UNDERLINE &&
nWhich != RES_CHRATR_BLINK )
{
return sal_False;
}
for( sal_uInt16 i=0; i<aStartLst.Count(); i++ )
{
HTMLSttEndPos *pTest = aStartLst[i];
if( pTest->GetStart() > nStartPos )
{
// dieses uns alle folgenden Attribute beginnen spaeter
break;
}
else if( pTest->GetStart()==nStartPos &&
pTest->GetEnd()==nEndPos )
{
// das Attribut beginnt vor oder an der aktuellen Position
// und endet hinter ihr
const SfxPoolItem *pItem = pTest->GetItem();
sal_uInt16 nTstWhich = pItem->Which() ;
if( (nTstWhich == RES_CHRATR_CROSSEDOUT ||
nTstWhich == RES_CHRATR_UNDERLINE ||
nTstWhich == RES_CHRATR_BLINK) &&
HTML_OFF_VALUE == GetHTMLItemState(*pItem) )
{
// Ein Off-Tag-Attibut wurde gefunden, das genauso
// exportiert wird, wie das aktuelle Item
return sal_True;
}
}
}
return sal_False;
}
void HTMLEndPosLst::FixSplittedItem( HTMLSttEndPos *pPos, xub_StrLen nNewEnd,
sal_uInt16 nStartPos )
{
// die End-Position entsprechend fixen
pPos->SetEnd( nNewEnd );
// das Item aus der End-Liste entfernen
sal_uInt16 nEndPos = _FindEndPos( pPos );
if( nEndPos != USHRT_MAX )
aEndLst.Remove( nEndPos, 1 );
// es wird von nun an als letztes an der entsprechenden Position
// beendet
for( nEndPos=0; nEndPos < aEndLst.Count() &&
aEndLst[nEndPos]->GetEnd() <= nNewEnd; nEndPos++ )
;
aEndLst.Insert( pPos, nEndPos );
// jetzt noch die spaeter gestarteten Attribute anpassen
for( sal_uInt16 i=nStartPos+1; i<aStartLst.Count(); i++ )
{
HTMLSttEndPos *pTest = aStartLst[i];
xub_StrLen nTestEnd = pTest->GetEnd();
if( pTest->GetStart() >= nNewEnd )
{
// das Test-Attribut und alle folgenden beginnen, nachdem das
// gesplittete Attribut endet
break;
}
else if( nTestEnd > nNewEnd )
{
// das Test-Attribut beginnt, bevor das gesplittete Attribut
// endet und endet danach, muss also auch gesplittet werden
// das neue Ende setzen
pTest->SetEnd( nNewEnd );
// das Attribut aus der End-Liste entfernen
sal_uInt16 nEPos = _FindEndPos( pTest );
if( nEPos != USHRT_MAX )
aEndLst.Remove( nEPos, 1 );
// es endet jetzt als erstes Attribut an der entsprechenden
// Position. Diese Position in der Ende-Liste kennen wir schon.
aEndLst.Insert(pTest, nEndPos );
// den "Rest" des Attributs neu einfuegen
InsertItem( *pTest->GetItem(), nNewEnd, nTestEnd );
}
}
}
void HTMLEndPosLst::InsertItem( const SfxPoolItem& rItem, xub_StrLen nStart,
xub_StrLen nEnd )
{
sal_uInt16 i;
for( i = 0; i < aEndLst.Count(); i++ )
{
HTMLSttEndPos *pTest = aEndLst[i];
xub_StrLen nTestEnd = pTest->GetEnd();
if( nTestEnd <= nStart )
{
// das Test-Attribut endet, bevor das neue beginnt
continue;
}
else if( nTestEnd < nEnd )
{
// das Test-Attribut endet, bevor das neue endet. Das
// neue Attribut muss deshalb aufgesplittet werden
_InsertItem( new HTMLSttEndPos( rItem, nStart, nTestEnd ), i );
nStart = nTestEnd;
}
else
{
// das Test-Attribut (und alle folgenden) endet, bevor das neue
// endet
break;
}
}
// ein Attribut muss noch eingefuegt werden
_InsertItem( new HTMLSttEndPos( rItem, nStart, nEnd ), i );
}
void HTMLEndPosLst::SplitItem( const SfxPoolItem& rItem, xub_StrLen nStart,
xub_StrLen nEnd )
{
sal_uInt16 nWhich = rItem.Which();
// erstmal muessen wir die alten Items anhand der Startliste suchen
// und die neuen Item-Bereiche festlegen
for( sal_uInt16 i=0; i<aStartLst.Count(); i++ )
{
HTMLSttEndPos *pTest = aStartLst[i];
xub_StrLen nTestStart = pTest->GetStart();
xub_StrLen nTestEnd = pTest->GetEnd();
if( nTestStart >= nEnd )
{
// dieses und alle nachfolgenden Attribute beginnen spaeter
break;
}
else if( nTestEnd > nStart )
{
// das Test Attribut endet im zu loeschenenden Bereich
const SfxPoolItem *pItem = pTest->GetItem();
// nur entsprechende On-Tag Attribute muessen beruecksichtigt
// werden
if( pItem->Which() == nWhich &&
HTML_ON_VALUE == GetHTMLItemState( *pItem ) )
{
sal_Bool bDelete = sal_True;
if( nTestStart < nStart )
{
// der Start des neuen Attribut entspricht
// dem neuen Ende des Attribts
FixSplittedItem( pTest, nStart, i );
bDelete = sal_False;
}
else
{
// das Test-Item beginnt erst hinter dem neuen
// Ende des Attribts und kann deshalb komplett
// geloescht werden
aStartLst.Remove( i, 1 );
i--;
sal_uInt16 nEndPos = _FindEndPos( pTest );
if( nEndPos != USHRT_MAX )
aEndLst.Remove( nEndPos, 1 );
}
// ggf den zweiten Teil des gesplitteten Attribts einfuegen
if( nTestEnd > nEnd )
{
InsertItem( *pTest->GetItem(), nEnd, nTestEnd );
}
if( bDelete )
delete pTest;
}
}
}
}
const SwHTMLFmtInfo *HTMLEndPosLst::GetFmtInfo( const SwFmt& rFmt,
SwHTMLFmtInfos& rFmtInfos )
{
const SwHTMLFmtInfo *pFmtInfo;
SwHTMLFmtInfo aFmtInfo( &rFmt );
sal_uInt16 nPos;
if( rFmtInfos.Seek_Entry( &aFmtInfo, &nPos ) )
{
pFmtInfo = rFmtInfos[nPos];
}
else
{
pFmtInfo = new SwHTMLFmtInfo( &rFmt, pDoc, pTemplate,
bOutStyles );
rFmtInfos.C40_PTR_INSERT( SwHTMLFmtInfo, pFmtInfo );
String aName( rFmt.GetName() );
if( rScriptTxtStyles.Seek_Entry( &aName ) )
((SwHTMLFmtInfo *)pFmtInfo)->bScriptDependent = sal_True;
}
return pFmtInfo;
}
HTMLEndPosLst::HTMLEndPosLst( SwDoc *pD, SwDoc* pTempl,
const Color* pDfltCol, sal_Bool bStyles,
sal_uLong nMode, const String& rText,
SvStringsSortDtor& rStyles ):
pDoc( pD ),
pTemplate( pTempl ),
pDfltColor( pDfltCol ),
rScriptTxtStyles( rStyles ),
nHTMLMode( nMode ),
bOutStyles( bStyles )
{
xub_StrLen nEndPos = rText.Len();
xub_StrLen nPos = 0;
while( nPos < nEndPos )
{
sal_uInt16 nScript = pBreakIt->GetBreakIter()->getScriptType( rText, nPos );
nPos = (xub_StrLen)pBreakIt->GetBreakIter()->endOfScript( rText, nPos, nScript );
aScriptChgLst.push_back( nPos );
aScriptLst.push_back( nScript );
}
}
HTMLEndPosLst::~HTMLEndPosLst()
{
ASSERT( !aStartLst.Count(), "Start-Liste im Destruktor nicht leer" );
ASSERT( !aEndLst.Count(), "End-Liste im Destruktor nicht leer" );
}
void HTMLEndPosLst::InsertNoScript( const SfxPoolItem& rItem,
xub_StrLen nStart, xub_StrLen nEnd,
SwHTMLFmtInfos& rFmtInfos, sal_Bool bParaAttrs )
{
// kein Bereich ?? dann nicht aufnehmen, wird nie wirksam !!
if( nStart != nEnd )
{
sal_Bool bSet = sal_False, bSplit = sal_False;
switch( GetHTMLItemState(rItem) )
{
case HTML_ON_VALUE:
// das Attribut wird ausgegeben, wenn es nicht sowieso
// schon an ist
if( !ExistsOnTagItem( rItem.Which(), nStart ) )
bSet = sal_True;
break;
case HTML_OFF_VALUE:
// wenn das entsprechne Attribut an ist, wird es gesplittet,
// Zusaetlich wird es aber als Style ausgegeben, wenn es nicht
// am ganzen Absatz gesetzt ist, weil es dann ja schon mit dem
// ABsatz-Tag ausgegeben wurde.
if( ExistsOnTagItem( rItem.Which(), nStart ) )
bSplit = sal_True;
bSet = bOutStyles && !bParaAttrs &&
!ExistsOffTagItem( rItem.Which(), nStart, nEnd );
break;
case HTML_REAL_VALUE:
// das Attribut kann immer ausgegeben werden
bSet = sal_True;
break;
case HTML_STYLE_VALUE:
// Das Attribut kann nur als CSS1 ausgegeben werden. Wenn
// es am Absatz gesetzt ist, wurde es schon mit dem
// Absatz-Tag ausgegeben. Einzige Ausnahme ist das
// Zeichen-Hintergrund-Attribut. Es muss immer wie ein
// Hint behandelt werden.
bSet = bOutStyles &&
(!bParaAttrs
|| rItem.Which()==RES_CHRATR_BACKGROUND
|| rItem.Which()==RES_CHRATR_OVERLINE);
break;
case HTML_CHRFMT_VALUE:
{
ASSERT( RES_TXTATR_CHARFMT == rItem.Which(),
"Doch keine Zeichen-Vorlage" );
const SwFmtCharFmt& rChrFmt = (const SwFmtCharFmt&)rItem;
const SwCharFmt* pFmt = rChrFmt.GetCharFmt();
const SwHTMLFmtInfo *pFmtInfo = GetFmtInfo( *pFmt, rFmtInfos );
if( pFmtInfo->aToken.Len() )
{
// das Zeichenvorlagen-Tag muss vor den harten
// Attributen ausgegeben werden
InsertItem( rItem, nStart, nEnd );
}
if( pFmtInfo->pItemSet )
{
Insert( *pFmtInfo->pItemSet, nStart, nEnd,
rFmtInfos, sal_True, bParaAttrs );
}
}
break;
case HTML_AUTOFMT_VALUE:
{
const SwFmtAutoFmt& rAutoFmt = (const SwFmtAutoFmt&)rItem;
const boost::shared_ptr<SfxItemSet> pSet = rAutoFmt.GetStyleHandle();
if( pSet.get() )
Insert( *pSet.get(), nStart, nEnd, rFmtInfos, sal_True, bParaAttrs );
}
break;
case HTML_COLOR_VALUE:
// Eine Vordergrund-Farbe als Absatz-Attribut wird nur
// exportiert, wenn sie nicht der Default-Farbe entspricht.
{
ASSERT( RES_CHRATR_COLOR == rItem.Which(),
"Doch keine Vordergrund-Farbe" );
Color aColor( ((const SvxColorItem&)rItem).GetValue() );
if( COL_AUTO == aColor.GetColor() )
aColor.SetColor( COL_BLACK );
bSet = !bParaAttrs || !pDfltColor ||
!pDfltColor->IsRGBEqual( aColor );
}
break;
case HTML_DROPCAP_VALUE:
{
ASSERT( RES_PARATR_DROP == rItem.Which(),
"Doch kein Drop-Cap" );
const SwFmtDrop& rDrop = (const SwFmtDrop&)rItem;
nEnd = nStart + rDrop.GetChars();
if( !bOutStyles )
{
// Zumindest die Attribute der Zeichenvorlage uebernehmen
const SwCharFmt *pCharFmt = rDrop.GetCharFmt();
if( pCharFmt )
{
Insert( pCharFmt->GetAttrSet(), nStart, nEnd,
rFmtInfos, sal_True, bParaAttrs );
}
}
else
{
bSet = sal_True;
}
}
break;
default:
;
}
if( bSet )
InsertItem( rItem, nStart, nEnd );
if( bSplit )
SplitItem( rItem, nStart, nEnd );
}
}
void HTMLEndPosLst::Insert( const SfxPoolItem& rItem,
xub_StrLen nStart, xub_StrLen nEnd,
SwHTMLFmtInfos& rFmtInfos, sal_Bool bParaAttrs )
{
sal_Bool bDependsOnScript = sal_False, bDependsOnAnyScript = sal_False;
sal_uInt16 nScript = i18n::ScriptType::LATIN;
switch( rItem.Which() )
{
case RES_CHRATR_FONT:
case RES_CHRATR_FONTSIZE:
case RES_CHRATR_LANGUAGE:
case RES_CHRATR_POSTURE:
case RES_CHRATR_WEIGHT:
bDependsOnScript = sal_True;
nScript = i18n::ScriptType::LATIN;
break;
case RES_CHRATR_CJK_FONT:
case RES_CHRATR_CJK_FONTSIZE:
case RES_CHRATR_CJK_LANGUAGE:
case RES_CHRATR_CJK_POSTURE:
case RES_CHRATR_CJK_WEIGHT:
bDependsOnScript = sal_True;
nScript = i18n::ScriptType::ASIAN;
break;
case RES_CHRATR_CTL_FONT:
case RES_CHRATR_CTL_FONTSIZE:
case RES_CHRATR_CTL_LANGUAGE:
case RES_CHRATR_CTL_POSTURE:
case RES_CHRATR_CTL_WEIGHT:
bDependsOnScript = sal_True;
nScript = i18n::ScriptType::COMPLEX;
break;
case RES_TXTATR_CHARFMT:
{
const SwFmtCharFmt& rChrFmt = (const SwFmtCharFmt&)rItem;
const SwCharFmt* pFmt = rChrFmt.GetCharFmt();
const SwHTMLFmtInfo *pFmtInfo = GetFmtInfo( *pFmt, rFmtInfos );
if( pFmtInfo->bScriptDependent )
{
bDependsOnScript = sal_True;
bDependsOnAnyScript = sal_True;
}
}
break;
case RES_TXTATR_INETFMT:
{
if( GetFmtInfo( *pDoc->GetCharFmtFromPool(
RES_POOLCHR_INET_NORMAL), rFmtInfos )->bScriptDependent ||
GetFmtInfo( *pDoc->GetCharFmtFromPool(
RES_POOLCHR_INET_VISIT), rFmtInfos )->bScriptDependent )
{
bDependsOnScript = sal_True;
bDependsOnAnyScript = sal_True;
}
}
break;
}
if( bDependsOnScript )
{
xub_StrLen nPos = nStart;
for( size_t i=0; i < aScriptChgLst.size(); i++ )
{
xub_StrLen nChgPos = aScriptChgLst[i];
if( nPos >= nChgPos )
{
// the hint starts behind or at the next script change,
// so we may continue with this position.
continue;
}
if( nEnd <= nChgPos )
{
// the (rest of) the hint ends before or at the next script
// change, so we can insert it, but only if it belongs
// to the current script.
if( bDependsOnAnyScript || nScript == aScriptLst[i] )
InsertNoScript( rItem, nPos, nEnd, rFmtInfos,
bParaAttrs );
break;
}
// the hint starts before the next script change and ends behind
// it, so we can insert a hint upto the next script change and
// continue with the rest of the hint.
if( bDependsOnAnyScript || nScript == aScriptLst[i] )
InsertNoScript( rItem, nPos, nChgPos, rFmtInfos, bParaAttrs );
nPos = nChgPos;
}
}
else
{
InsertNoScript( rItem, nStart, nEnd, rFmtInfos, bParaAttrs );
}
}
void HTMLEndPosLst::Insert( const SfxItemSet& rItemSet,
xub_StrLen nStart, xub_StrLen nEnd,
SwHTMLFmtInfos& rFmtInfos,
sal_Bool bDeep, sal_Bool bParaAttrs )
{
SfxWhichIter aIter( rItemSet );
sal_uInt16 nWhich = aIter.FirstWhich();
while( nWhich )
{
const SfxPoolItem *pItem;
if( SFX_ITEM_SET == rItemSet.GetItemState( nWhich, bDeep, &pItem ) )
{
Insert( *pItem, nStart, nEnd, rFmtInfos, bParaAttrs );
}
nWhich = aIter.NextWhich();
}
}
void HTMLEndPosLst::Insert( const SwDrawFrmFmt& rFmt, xub_StrLen nPos,
SwHTMLFmtInfos& rFmtInfos )
{
// der Type-Cast ist nur noetig, um nicht seinetwegen
// svdrwobt.hxx zu includem
const SdrObject* pTextObj =
(const SdrObject *)SwHTMLWriter::GetMarqueeTextObj( rFmt );
if( pTextObj )
{
// die Edit-Engine-Attribute des Objekts als SW-Attribute holen
// und als Hints einsortieren. Wegen der Menge der Hints werden
// Styles hierbei nicht beruecksichtigt!
const SfxItemSet& rFmtItemSet = rFmt.GetAttrSet();
SfxItemSet aItemSet( *rFmtItemSet.GetPool(), RES_CHRATR_BEGIN,
RES_CHRATR_END );
SwHTMLWriter::GetEEAttrsFromDrwObj( aItemSet, pTextObj, sal_True );
sal_Bool bOutStylesOld = bOutStyles;
bOutStyles = sal_False;
Insert( aItemSet, nPos, nPos+1, rFmtInfos, sal_False, sal_False );
bOutStyles = bOutStylesOld;
}
}
sal_uInt16 HTMLEndPosLst::GetScriptAtPos( xub_StrLen nPos ,
sal_uInt16 nWeak )
{
sal_uInt16 nRet = CSS1_OUTMODE_ANY_SCRIPT;
size_t nScriptChgs = aScriptChgLst.size();
size_t i=0;
while( i < nScriptChgs && nPos >= aScriptChgLst[i] )
i++;
ASSERT( i < nScriptChgs, "script list is to short" );
if( i < nScriptChgs )
{
if( i18n::ScriptType::WEAK == aScriptLst[i] )
nRet = nWeak;
else
nRet = SwHTMLWriter::GetCSS1ScriptForScriptType( aScriptLst[i] );
}
return nRet;
}
void HTMLEndPosLst::OutStartAttrs( SwHTMLWriter& rHWrt, xub_StrLen nPos,
HTMLOutContext *pContext )
{
rHWrt.bTagOn = sal_True;
// die Attribute in der Start-Liste sind aufsteigend sortiert
for( sal_uInt16 i=0; i< aStartLst.Count(); i++ )
{
HTMLSttEndPos *pPos = aStartLst[i];
xub_StrLen nStart = pPos->GetStart();
if( nStart > nPos )
{
// dieses und alle folgenden Attribute werden erst noch geoeffnet
break;
}
else if( nStart == nPos )
{
// das Attribut ausgeben
sal_uInt16 nCSS1Script = rHWrt.nCSS1Script;
sal_uInt16 nWhich = pPos->GetItem()->Which();
if( RES_TXTATR_CHARFMT == nWhich ||
RES_TXTATR_INETFMT == nWhich ||
RES_PARATR_DROP == nWhich )
{
rHWrt.nCSS1Script = GetScriptAtPos( nPos, nCSS1Script );
}
if( pContext )
{
HTMLOutFuncs::FlushToAscii( rHWrt.Strm(), *pContext );
pContext = 0; // one time ony
}
Out( aHTMLAttrFnTab, *pPos->GetItem(), rHWrt );
rHWrt.nCSS1Script = nCSS1Script;
}
}
}
void HTMLEndPosLst::OutEndAttrs( SwHTMLWriter& rHWrt, xub_StrLen nPos,
HTMLOutContext *pContext )
{
rHWrt.bTagOn = sal_False;
// die Attribute in der End-Liste sind aufsteigend sortiert
sal_uInt16 i=0;
while( i < aEndLst.Count() )
{
HTMLSttEndPos *pPos = aEndLst[i];
xub_StrLen nEnd = pPos->GetEnd();
if( STRING_MAXLEN==nPos || nEnd == nPos )
{
if( pContext )
{
HTMLOutFuncs::FlushToAscii( rHWrt.Strm(), *pContext );
pContext = 0; // one time ony
}
Out( aHTMLAttrFnTab, *pPos->GetItem(), rHWrt );
_RemoveItem( i );
}
else if( nEnd > nPos )
{
// dieses und alle folgenden Attribute werden erst spaeter beendet
break;
}
else
{
// Das Attribut wird vor der aktuellen Position beendet. Das
// darf nicht sein, aber wie koennen trotzdem damit umgehen
ASSERT( nEnd >= nPos,
"Das Attribut sollte schon laengst beendet sein" );
i++;
}
}
}
/* Ausgabe der Nodes */
Writer& OutHTML_SwTxtNode( Writer& rWrt, const SwCntntNode& rNode )
{
SwTxtNode * pNd = &((SwTxtNode&)rNode);
SwHTMLWriter & rHTMLWrt = (SwHTMLWriter&)rWrt;
const String& rStr = pNd->GetTxt();
xub_StrLen nEnde = rStr.Len();
// Besonderheit: leere Node und HR-Vorlage (horizontaler Strich)
// nur ein <HR> ausgeben
sal_uInt16 nPoolId = pNd->GetAnyFmtColl().GetPoolFmtId();
if( !nEnde && (RES_POOLCOLL_HTML_HR==nPoolId ||
pNd->GetAnyFmtColl().GetName().EqualsAscii( OOO_STRING_SVTOOLS_HTML_horzrule) ) )
{
// dann die absatz-gebundenen Grafiken/OLE-Objekte im Absatz
// MIB 8.7.97: Ein <PRE> spannen wir um die Linie auf. Dann stimmen
// zwar die Abstaende nicht, aber sonst bekommen wir einen leeren
// Absatz hinter dem <HR> und das ist noch unschoener.
rHTMLWrt.ChangeParaToken( 0 );
// Alle an dem Node verankerten Rahmen ausgeben
rHTMLWrt.OutFlyFrm( rNode.GetIndex(), 0, HTML_POS_ANY );
if( rHTMLWrt.bLFPossible )
rHTMLWrt.OutNewLine(); // Absatz-Tag in eine neue Zeile
rHTMLWrt.bLFPossible = sal_True;
ByteString sOut( '<' );
sOut += OOO_STRING_SVTOOLS_HTML_horzrule;
const SfxItemSet* pItemSet = pNd->GetpSwAttrSet();
if( !pItemSet )
{
rWrt.Strm() << sOut.GetBuffer() << '>';
return rHTMLWrt;
}
const SfxPoolItem* pItem;
if( SFX_ITEM_SET == pItemSet->GetItemState( RES_LR_SPACE, sal_False, &pItem ))
{
sal_Int32 nLeft = ((SvxLRSpaceItem*)pItem)->GetLeft();
sal_Int32 nRight = ((SvxLRSpaceItem*)pItem)->GetRight();
if( nLeft || nRight )
{
const SwFrmFmt& rPgFmt =
rHTMLWrt.pDoc->GetPageDescFromPool
( RES_POOLPAGE_HTML, false )->GetMaster();
const SwFmtFrmSize& rSz = rPgFmt.GetFrmSize();
const SvxLRSpaceItem& rLR = rPgFmt.GetLRSpace();
const SwFmtCol& rCol = rPgFmt.GetCol();
long nPageWidth = rSz.GetWidth() - rLR.GetLeft() - rLR.GetRight();
if( 1 < rCol.GetNumCols() )
nPageWidth /= rCol.GetNumCols();
const SwTableNode* pTblNd = pNd->FindTableNode();
if( pTblNd )
{
const SwTableBox* pBox = pTblNd->GetTable().GetTblBox(
pNd->StartOfSectionIndex() );
if( pBox )
nPageWidth = pBox->GetFrmFmt()->GetFrmSize().GetWidth();
}
((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_width) += '=';
rWrt.Strm() << sOut.GetBuffer();
rWrt.OutULong( rHTMLWrt.ToPixel(nPageWidth-nLeft-nRight) );
((sOut = ' ') += OOO_STRING_SVTOOLS_HTML_O_align) += '=';
if( !nLeft )
sOut += OOO_STRING_SVTOOLS_HTML_AL_left;
else if( !nRight )
sOut += OOO_STRING_SVTOOLS_HTML_AL_right;
else
sOut += OOO_STRING_SVTOOLS_HTML_AL_center;
}
}
rWrt.Strm() << sOut.GetBuffer();
if( SFX_ITEM_SET == pItemSet->GetItemState( RES_BOX, sal_False, &pItem ))
{
const SvxBoxItem* pBoxItem = (const SvxBoxItem*)pItem;
const SvxBorderLine* pBorderLine = pBoxItem->GetBottom();
if( pBorderLine )
{
sal_uInt16 nWidth = pBorderLine->GetOutWidth() +
pBorderLine->GetInWidth() +
pBorderLine->GetDistance();
((sOut = ' ') += OOO_STRING_SVTOOLS_HTML_O_size) += '=';
rWrt.Strm() << sOut.GetBuffer();
rWrt.OutULong( rHTMLWrt.ToPixel(nWidth) );
const Color& rBorderColor = pBorderLine->GetColor();
if( !rBorderColor.IsRGBEqual( Color(COL_GRAY) ) )
{
((sOut = ' ') += OOO_STRING_SVTOOLS_HTML_O_color) += '=';
rWrt.Strm() << sOut.GetBuffer();
HTMLOutFuncs::Out_Color( rWrt.Strm(), rBorderColor,
rHTMLWrt.eDestEnc );
}
if( !pBorderLine->GetInWidth() )
{
(sOut = ' ') += OOO_STRING_SVTOOLS_HTML_O_noshade;
rWrt.Strm() << sOut.GetBuffer();
}
}
}
rWrt.Strm() << '>';
return rHTMLWrt;
}
// Die leeren Nodes mit 2pt Font-Hoehe und der Stand-Vorlage, die
// vor Tabellen und Bereichen eingefuegt werden, nicht exportieren,
// Bookmarks oder absatzgebundene Grafiken aber schon.
// MIB 21.7.97: Ausserdem auch keine leeren Tabellen-Zellen exportieren.
if( !nEnde && (nPoolId == RES_POOLCOLL_STANDARD ||
nPoolId == RES_POOLCOLL_TABLE ||
nPoolId == RES_POOLCOLL_TABLE_HDLN) )
{
// Der aktuelle Node ist leer und enthaelt Standard-Vorlage ...
const SfxPoolItem* pItem;
const SfxItemSet *pItemSet = pNd->GetpSwAttrSet();
if( pItemSet && pItemSet->Count() &&
SFX_ITEM_SET == pItemSet->GetItemState( RES_CHRATR_FONTSIZE, sal_False, &pItem ) &&
40 == ((const SvxFontHeightItem *)pItem)->GetHeight() )
{
// ... ausserdem ist die 2pt Schrift eingestellt ...
sal_uLong nNdPos = rWrt.pCurPam->GetPoint()->nNode.GetIndex();
const SwNode *pNextNd = rWrt.pDoc->GetNodes()[nNdPos+1];
const SwNode *pPrevNd = rWrt.pDoc->GetNodes()[nNdPos-1];
sal_Bool bStdColl = nPoolId == RES_POOLCOLL_STANDARD;
if( ( bStdColl && (pNextNd->IsTableNode() ||
pNextNd->IsSectionNode()) ) ||
( !bStdColl && pNextNd->IsEndNode() &&
pPrevNd->IsStartNode() &&
SwTableBoxStartNode==
pPrevNd->GetStartNode()->GetStartNodeType() ) )
{
// ... und er steht vor einer Tabelle ohne einem Bereich
rHTMLWrt.OutBookmarks();
rHTMLWrt.bLFPossible = !rHTMLWrt.nLastParaToken;
// Alle an dem Node verankerten Rahmen ausgeben
rHTMLWrt.OutFlyFrm( rNode.GetIndex(), 0, HTML_POS_ANY );
rHTMLWrt.bLFPossible = sal_False;
return rWrt;
}
}
}
// PagePreaks uns PagDescs abfangen
sal_Bool bPageBreakBehind = sal_False;
if( rHTMLWrt.bCfgFormFeed &&
!(rHTMLWrt.bOutTable || rHTMLWrt.bOutFlyFrame) &&
rHTMLWrt.pStartNdIdx->GetIndex() !=
rHTMLWrt.pCurPam->GetPoint()->nNode.GetIndex() )
{
sal_Bool bPageBreakBefore = sal_False;
const SfxPoolItem* pItem;
const SfxItemSet* pItemSet = pNd->GetpSwAttrSet();
if( pItemSet )
{
if( SFX_ITEM_SET ==
pItemSet->GetItemState( RES_PAGEDESC, sal_True, &pItem ) &&
((SwFmtPageDesc *)pItem)->GetPageDesc() )
bPageBreakBefore = sal_True;
else if( SFX_ITEM_SET ==
pItemSet->GetItemState( RES_BREAK, sal_True, &pItem ) )
{
switch( ((SvxFmtBreakItem *)pItem)->GetBreak() )
{
case SVX_BREAK_PAGE_BEFORE:
bPageBreakBefore = sal_True;
break;
case SVX_BREAK_PAGE_AFTER:
bPageBreakBehind = sal_True;
break;
case SVX_BREAK_PAGE_BOTH:
bPageBreakBefore = sal_True;
bPageBreakBehind = sal_True;
break;
default:
;
}
}
}
if( bPageBreakBefore )
rWrt.Strm() << '\f';
}
// eventuell eine Form oeffnen
rHTMLWrt.OutForm();
// An dem Node "verankerte" Seitenegebunde Rahmen ausgeben
sal_Bool bFlysLeft = rHTMLWrt.OutFlyFrm( rNode.GetIndex(),
0, HTML_POS_PREFIX );
// An dem Node verankerte Rahmen ausgeben, die vor dem
// Absatz-Tag geschrieben werden sollen.
if( bFlysLeft )
bFlysLeft = rHTMLWrt.OutFlyFrm( rNode.GetIndex(),
0, HTML_POS_BEFORE );
if( rHTMLWrt.pCurPam->GetPoint()->nNode == rHTMLWrt.pCurPam->GetMark()->nNode )
nEnde = rHTMLWrt.pCurPam->GetMark()->nContent.GetIndex();
// gibt es harte Attribute, die als Optionen geschrieben werden muessen?
rHTMLWrt.bTagOn = sal_True;
// jetzt das Tag des Absatzes ausgeben
const SwFmt& rFmt = pNd->GetAnyFmtColl();
SwHTMLTxtCollOutputInfo aFmtInfo;
sal_Bool bOldLFPossible = rHTMLWrt.bLFPossible;
OutHTML_SwFmt( rWrt, rFmt, pNd->GetpSwAttrSet(), aFmtInfo );
// Wenn vor dem Absatz-Tag keine neue Zeile aufgemacht wurde, dann
// tun wir das jetzt
rHTMLWrt.bLFPossible = !rHTMLWrt.nLastParaToken;
if( !bOldLFPossible && rHTMLWrt.bLFPossible )
rHTMLWrt.OutNewLine();
// dann die Bookmarks (inkl. End-Tag)
rHTMLWrt.bOutOpts = sal_False;
rHTMLWrt.OutBookmarks();
// jetzt ist noch mal eine gute Gelegenheit fuer ein LF, sofern es noch
// erlaubt ist
if( rHTMLWrt.bLFPossible &&
rHTMLWrt.GetLineLen() >= rHTMLWrt.nWhishLineLen )
{
rHTMLWrt.OutNewLine();
}
rHTMLWrt.bLFPossible = sal_False;
// Text, der aus einer Outline-Numerierung kommt ermitteln
xub_StrLen nOffset = 0;
String aOutlineTxt;
String aFullText;
// --> OD 2006-06-12 #b6435904#
// export numbering string as plain text only for the outline numbering,
// because the outline numbering isn't exported as a numbering - see <SwHTMLNumRuleInfo::Set(..)>
if ( pNd->IsOutline() &&
pNd->GetNumRule() == pNd->GetDoc()->GetOutlineNumRule() )
// <--
{
aOutlineTxt = pNd->GetNumString();
nOffset = nOffset + aOutlineTxt.Len();
aFullText = aOutlineTxt;
}
String aFootEndNoteSym;
if( rHTMLWrt.pFmtFtn )
{
aFootEndNoteSym = rHTMLWrt.GetFootEndNoteSym( *rHTMLWrt.pFmtFtn );
nOffset = nOffset + aFootEndNoteSym.Len();
aFullText += aFootEndNoteSym;
}
// gibt es harte Attribute, die als Tags geschrieben werden muessen?
aFullText += rStr;
HTMLEndPosLst aEndPosLst( rWrt.pDoc, rHTMLWrt.pTemplate,
rHTMLWrt.pDfltColor, rHTMLWrt.bCfgOutStyles,
rHTMLWrt.GetHTMLMode(), aFullText,
rHTMLWrt.aScriptTextStyles );
if( aFmtInfo.pItemSet )
{
aEndPosLst.Insert( *aFmtInfo.pItemSet, 0, nEnde + nOffset,
rHTMLWrt.aChrFmtInfos, sal_False, sal_True );
}
if( aOutlineTxt.Len() || rHTMLWrt.pFmtFtn )
{
// Absatz-Attribute ausgeben, damit der Text die Attribute des
// Absatzes bekommt.
aEndPosLst.OutStartAttrs( rHTMLWrt, 0 );
// Theoretisch muesste man hier die Zeichen-Vorlage der Numerierung
// beachten. Da man die ueber die UI nicht setzen kann, ignorieren
// wir sie erstmal.
if( aOutlineTxt.Len() )
HTMLOutFuncs::Out_String( rWrt.Strm(), aOutlineTxt,
rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters);
if( rHTMLWrt.pFmtFtn )
{
rHTMLWrt.OutFootEndNoteSym( *rHTMLWrt.pFmtFtn, aFootEndNoteSym,
aEndPosLst.GetScriptAtPos( aOutlineTxt.Len(), rHTMLWrt.nCSS1Script ) );
rHTMLWrt.pFmtFtn = 0;
}
}
// erstmal den Start berichtigen. D.h. wird nur ein Teil vom Satz
// ausgegeben, so muessen auch da die Attribute stimmen!!
rHTMLWrt.bTxtAttr = sal_True;
sal_uInt16 nAttrPos = 0;
xub_StrLen nStrPos = rHTMLWrt.pCurPam->GetPoint()->nContent.GetIndex();
const SwTxtAttr * pHt = 0;
sal_uInt16 nCntAttr = pNd->HasHints() ? pNd->GetSwpHints().Count() : 0;
if( nCntAttr && nStrPos > *( pHt = pNd->GetSwpHints()[ 0 ] )->GetStart() )
{
// Ok, es gibt vorher Attribute, die ausgegeben werden muessen
do {
aEndPosLst.OutEndAttrs( rHTMLWrt, nStrPos + nOffset );
nAttrPos++;
if( pHt->Which() == RES_TXTATR_FIELD
|| pHt->Which() == RES_TXTATR_ANNOTATION )
continue;
if ( pHt->End() && !pHt->HasDummyChar() )
{
const xub_StrLen nHtEnd = *pHt->End(),
nHtStt = *pHt->GetStart();
if( !rHTMLWrt.bWriteAll && nHtEnd <= nStrPos )
continue;
// leere Hints am Anfang nicht beachten, oder ??
if( nHtEnd == nHtStt )
continue;
// Attribut in die Liste aufnehemen
if( rHTMLWrt.bWriteAll )
aEndPosLst.Insert( pHt->GetAttr(), nHtStt + nOffset,
nHtEnd + nOffset,
rHTMLWrt.aChrFmtInfos );
else
{
xub_StrLen nTmpStt = nHtStt < nStrPos ? nStrPos : nHtStt;
xub_StrLen nTmpEnd = nHtEnd < nEnde ? nHtEnd : nEnde;
aEndPosLst.Insert( pHt->GetAttr(), nTmpStt + nOffset,
nTmpEnd + nOffset,
rHTMLWrt.aChrFmtInfos );
}
continue;
// aber nicht ausgeben, das erfolgt spaeter !!
}
} while( nAttrPos < nCntAttr && nStrPos >
*( pHt = pNd->GetSwpHints()[ nAttrPos ] )->GetStart() );
// dann gebe mal alle gesammelten Attribute von der String-Pos aus
aEndPosLst.OutEndAttrs( rHTMLWrt, nStrPos + nOffset );
aEndPosLst.OutStartAttrs( rHTMLWrt, nStrPos + nOffset );
}
sal_Bool bWriteBreak = (HTML_PREFORMTXT_ON != rHTMLWrt.nLastParaToken);
if( bWriteBreak && pNd->GetNumRule() )
bWriteBreak = sal_False;
{
HTMLOutContext aContext( rHTMLWrt.eDestEnc );
xub_StrLen nPreSplitPos = 0;
for( ; nStrPos < nEnde; nStrPos++ )
{
aEndPosLst.OutEndAttrs( rHTMLWrt, nStrPos + nOffset, &aContext );
// Die an der aktuellen Position verankerten Rahmen ausgeben
if( bFlysLeft )
bFlysLeft = rHTMLWrt.OutFlyFrm( rNode.GetIndex(),
nStrPos, HTML_POS_INSIDE,
&aContext );
sal_Bool bOutChar = sal_True;
const SwTxtAttr * pTxtHt = 0;
if( nAttrPos < nCntAttr && *pHt->GetStart() == nStrPos
&& nStrPos != nEnde )
{
do {
if ( pHt->End() && !pHt->HasDummyChar() )
{
if( RES_CHRATR_KERNING == pHt->Which() &&
rHTMLWrt.IsHTMLMode(HTMLMODE_FIRSTLINE) &&
*pHt->End() - nStrPos == 1 &&
' ' == rStr.GetChar(nStrPos) &&
((const SvxKerningItem&)pHt->GetAttr()).GetValue() > 0 )
{
// Wenn erlaubt, wird das Ding als Spacer exportiert
bOutChar = sal_False; // Space nicht ausgeben
bWriteBreak = sal_False; // der Absatz ist aber auch nicht leer
HTMLOutFuncs::FlushToAscii( rWrt.Strm(), aContext );
OutHTML_HoriSpacer( rWrt,
((const SvxKerningItem&)pHt->GetAttr()).GetValue() );
// Der Hint braucht nun doch nicht weiter
// beruecksichtigt werden.
}
else if( *pHt->End() != nStrPos )
{
// Hints mit Ende einsortieren, wenn sie keinen
// leeren Bereich aufspannen (Hints, die keinen
// Bereich aufspannen werden ignoriert
aEndPosLst.Insert( pHt->GetAttr(), nStrPos + nOffset,
*pHt->End() + nOffset,
rHTMLWrt.aChrFmtInfos );
}
}
else
{
// Hints ohne-Ende werden als letztes ausgebeben
ASSERT( !pTxtHt, "Wieso gibt es da schon ein Attribut ohne Ende?" );
if( rHTMLWrt.nTxtAttrsToIgnore>0 )
{
rHTMLWrt.nTxtAttrsToIgnore--;
}
else
{
pTxtHt = pHt;
sal_uInt16 nFldWhich;
if( RES_TXTATR_FIELD != pHt->Which()
|| ( RES_POSTITFLD != (nFldWhich = ((const SwFmtFld&)pHt->GetAttr()).GetField()->Which())
&& RES_SCRIPTFLD != nFldWhich ) )
{
bWriteBreak = sal_False;
}
}
bOutChar = sal_False; // keine 255 ausgeben
}
} while( ++nAttrPos < nCntAttr && nStrPos ==
*( pHt = pNd->GetSwpHints()[ nAttrPos ] )->GetStart() );
}
// Manche Draw-Formate koennen auch noch Attribute mitbringen
if( pTxtHt && RES_TXTATR_FLYCNT == pTxtHt->Which() )
{
const SwFrmFmt* pFrmFmt =
((const SwFmtFlyCnt &)pTxtHt->GetAttr()).GetFrmFmt();
if( RES_DRAWFRMFMT == pFrmFmt->Which() )
aEndPosLst.Insert( *((const SwDrawFrmFmt *)pFrmFmt),
nStrPos + nOffset,
rHTMLWrt.aChrFmtInfos );
}
aEndPosLst.OutEndAttrs( rHTMLWrt, nStrPos + nOffset, &aContext );
aEndPosLst.OutStartAttrs( rHTMLWrt, nStrPos + nOffset, &aContext );
if( pTxtHt )
{
rHTMLWrt.bLFPossible = !rHTMLWrt.nLastParaToken && nStrPos > 0 &&
rStr.GetChar(nStrPos-1) == ' ';
sal_uInt16 nCSS1Script = rHTMLWrt.nCSS1Script;
rHTMLWrt.nCSS1Script = aEndPosLst.GetScriptAtPos(
nStrPos + nOffset, nCSS1Script );
HTMLOutFuncs::FlushToAscii( rWrt.Strm(), aContext );
Out( aHTMLAttrFnTab, pTxtHt->GetAttr(), rHTMLWrt );
rHTMLWrt.nCSS1Script = nCSS1Script;
rHTMLWrt.bLFPossible = sal_False;
}
if( bOutChar )
{
// #i120442#: get the UTF-32 codepoint by converting an eventual UTF-16 unicode surrogate pair
sal_uInt64 c = rStr.GetChar( nStrPos );
if( nStrPos < nEnde - 1 )
{
const sal_Unicode d = rStr.GetChar( nStrPos + 1 );
if( (c >= 0xd800 && c <= 0xdbff) && (d >= 0xdc00 && d <= 0xdfff) )
{
sal_uInt64 templow = d&0x03ff;
sal_uInt64 temphi = ((c&0x03ff) + 0x0040)<<10;
c = temphi|templow;
nStrPos++;
}
}
// try to split a line after about 255 characters
// at a space character unless in a PRE-context
if( ' '==c && !rHTMLWrt.nLastParaToken )
{
xub_StrLen nLineLen;
if( rHTMLWrt.nLastParaToken )
nLineLen = nStrPos - nPreSplitPos;
else
nLineLen = rHTMLWrt.GetLineLen();
xub_StrLen nWordLen = rStr.Search( ' ', nStrPos+1 );
if( nWordLen == STRING_NOTFOUND )
nWordLen = nEnde;
nWordLen -= nStrPos;
if( nLineLen >= rHTMLWrt.nWhishLineLen ||
(nLineLen+nWordLen) >= rHTMLWrt.nWhishLineLen )
{
HTMLOutFuncs::FlushToAscii( rWrt.Strm(), aContext );
rHTMLWrt.OutNewLine();
bOutChar = sal_False;
if( rHTMLWrt.nLastParaToken )
nPreSplitPos = nStrPos+1;
}
}
if( bOutChar )
{
if( 0x0a == c )
{
HTMLOutFuncs::FlushToAscii( rWrt.Strm(), aContext );
HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_linebreak );
}
// #i120442#: if c is outside the unicode base plane output it as "&#******;"
else if( c > 0xffff)
{
ByteString sOut("&#");
sOut += ByteString::CreateFromInt64( (sal_uInt64)c );
sOut += ';';
rWrt.Strm() << sOut.GetBuffer();
}
else
HTMLOutFuncs::Out_Char( rWrt.Strm(), (sal_Unicode)c, aContext, &rHTMLWrt.aNonConvertableCharacters );
// if a paragraph's last character is a hard line break
// then we need to add an extra <br>
// because browsers like Mozilla wouldn't add a line for the next paragraph
bWriteBreak = (0x0a == c) &&
(HTML_PREFORMTXT_ON != rHTMLWrt.nLastParaToken);
}
}
}
HTMLOutFuncs::FlushToAscii( rWrt.Strm(), aContext );
}
aEndPosLst.OutEndAttrs( rHTMLWrt, STRING_MAXLEN );
// Die an der letzten Position verankerten Rahmen ausgeben
if( bFlysLeft )
bFlysLeft = rHTMLWrt.OutFlyFrm( rNode.GetIndex(),
nEnde, HTML_POS_INSIDE );
ASSERT( !bFlysLeft, "Es wurden nicht alle Rahmen gespeichert!" );
rHTMLWrt.bTxtAttr = sal_False;
if( bWriteBreak )
{
sal_Bool bEndOfCell = rHTMLWrt.bOutTable &&
rWrt.pCurPam->GetPoint()->nNode.GetIndex() ==
rWrt.pCurPam->GetMark()->nNode.GetIndex();
if( bEndOfCell && !nEnde &&
rHTMLWrt.IsHTMLMode(HTMLMODE_NBSP_IN_TABLES) )
{
// Wenn der letzte Absatz einer Tabellezelle leer ist und
// wir fuer den MS-IE exportieren, schreiben wir statt eines
// <BR> ein &nbsp;
rWrt.Strm() << '&' << OOO_STRING_SVTOOLS_HTML_S_nbsp << ';';
}
else
{
HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_linebreak );
const SvxULSpaceItem& rULSpace =
(const SvxULSpaceItem &)pNd->GetSwAttrSet().Get(RES_UL_SPACE);
if( rULSpace.GetLower() > 0 && !bEndOfCell &&
!rHTMLWrt.IsHTMLMode(HTMLMODE_NO_BR_AT_PAREND) )
HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_linebreak );
rHTMLWrt.bLFPossible = sal_True;
}
}
if( rHTMLWrt.bClearLeft || rHTMLWrt.bClearRight )
{
const sal_Char *pStr;
if( rHTMLWrt.bClearLeft )
{
if( rHTMLWrt.bClearRight )
pStr = OOO_STRING_SVTOOLS_HTML_AL_all;
else
pStr = OOO_STRING_SVTOOLS_HTML_AL_left;
}
else
pStr = OOO_STRING_SVTOOLS_HTML_AL_right;
ByteString sOut( OOO_STRING_SVTOOLS_HTML_linebreak );
(((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_clear) += '=') += pStr;
HTMLOutFuncs::Out_AsciiTag( rHTMLWrt.Strm(), sOut.GetBuffer() );
rHTMLWrt.bClearLeft = sal_False;
rHTMLWrt.bClearRight = sal_False;
rHTMLWrt.bLFPossible = sal_True;
}
// wenn ein LF nicht schon erlaubt ist wird es erlaubt, wenn der
// Absatz mit einem ' ' endet
if( !rHTMLWrt.bLFPossible && !rHTMLWrt.nLastParaToken &&
nEnde > 0 && ' ' == rStr.GetChar(nEnde-1) )
rHTMLWrt.bLFPossible = sal_True;
rHTMLWrt.bTagOn = sal_False;
OutHTML_SwFmtOff( rWrt, aFmtInfo );
// eventuell eine Form schliessen
rHTMLWrt.OutForm( sal_False );
if( bPageBreakBehind )
rWrt.Strm() << '\f';
return rHTMLWrt;
}
sal_uInt32 SwHTMLWriter::ToPixel( sal_uInt32 nVal ) const
{
if( Application::GetDefaultDevice() && nVal )
{
nVal = Application::GetDefaultDevice()->LogicToPixel(
Size( nVal, nVal ), MapMode( MAP_TWIP ) ).Width();
if( !nVal ) // wo ein Twip ist sollte auch ein Pixel sein
nVal = 1;
}
return nVal;
}
static Writer& OutHTML_CSS1Attr( Writer& rWrt, const SfxPoolItem& rHt )
{
// wenn gerade Hints geschrieben werden versuchen wir den Hint als
// CSS1-Attribut zu schreiben
if( ((SwHTMLWriter&)rWrt).bCfgOutStyles && ((SwHTMLWriter&)rWrt).bTxtAttr )
OutCSS1_HintSpanTag( rWrt, rHt );
return rWrt;
}
/* File CHRATR.HXX: */
static Writer& OutHTML_SvxColor( Writer& rWrt, const SfxPoolItem& rHt )
{
SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt;
if( rHTMLWrt.bOutOpts )
return rWrt;
// die Default-Farbe nur Schreiben, wenn sie als Hint vorkommt
//if( rHTMLWrt.bTagOn && !rHTMLWrt.bTxtAttr && rHTMLWrt.pDfltColor
// && rColor == *rHTMLWrt.pDfltColor )
// return rWrt;
if( !rHTMLWrt.bTxtAttr && rHTMLWrt.bCfgOutStyles && rHTMLWrt.bCfgPreferStyles )
{
// Font-Farbe nicht als Tag schreiben, wenn Styles normalen Tags
// vorgezogen werden
return rWrt;
}
if( rHTMLWrt.bTagOn )
{
Color aColor( ((const SvxColorItem&)rHt).GetValue() );
if( COL_AUTO == aColor.GetColor() )
aColor.SetColor( COL_BLACK );
ByteString sOut( '<' );
(((sOut += OOO_STRING_SVTOOLS_HTML_font) += ' ') += OOO_STRING_SVTOOLS_HTML_O_color) += '=';
rWrt.Strm() << sOut.GetBuffer();
HTMLOutFuncs::Out_Color( rWrt.Strm(), aColor, rHTMLWrt.eDestEnc ) << '>';
}
else
HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_font, sal_False );
return rWrt;
}
static Writer& OutHTML_SwPosture( Writer& rWrt, const SfxPoolItem& rHt )
{
SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt;
if( rHTMLWrt.bOutOpts )
return rWrt;
const FontItalic nPosture = ((const SvxPostureItem&)rHt).GetPosture();
if( ITALIC_NORMAL == nPosture )
{
HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_italic, rHTMLWrt.bTagOn );
}
else if( rHTMLWrt.bCfgOutStyles && rHTMLWrt.bTxtAttr )
{
// vielleicht als CSS1-Attribut ?
OutCSS1_HintSpanTag( rWrt, rHt );
}
return rWrt;
}
static Writer& OutHTML_SvxFont( Writer& rWrt, const SfxPoolItem& rHt )
{
SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt;
if( rHTMLWrt.bOutOpts )
return rWrt;
if( rHTMLWrt.bTagOn )
{
String aNames;
SwHTMLWriter::PrepareFontList( ((const SvxFontItem&)rHt), aNames, 0,
rHTMLWrt.IsHTMLMode(HTMLMODE_FONT_GENERIC) );
ByteString sOut( '<' );
(((sOut += OOO_STRING_SVTOOLS_HTML_font) += ' ') += OOO_STRING_SVTOOLS_HTML_O_face) += "=\"";
rWrt.Strm() << sOut.GetBuffer();
HTMLOutFuncs::Out_String( rWrt.Strm(), aNames, rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters )
<< "\">";
}
else
HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_font , sal_False );
return rWrt;
}
static Writer& OutHTML_SvxFontHeight( Writer& rWrt, const SfxPoolItem& rHt )
{
SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt;
if( rHTMLWrt.bOutOpts )
return rWrt;
if( rHTMLWrt.bTagOn )
{
ByteString sOut( '<' );
sOut += OOO_STRING_SVTOOLS_HTML_font;
sal_uInt32 nHeight = ((const SvxFontHeightItem&)rHt).GetHeight();
sal_uInt16 nSize = rHTMLWrt.GetHTMLFontSize( nHeight );
(((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_size) += '=')
+= ByteString::CreateFromInt32( nSize );
rWrt.Strm() << sOut.GetBuffer();
if( rHTMLWrt.bCfgOutStyles && rHTMLWrt.bTxtAttr &&
rHTMLWrt.aFontHeights[nSize-1] != nHeight )
{
// wenn die Groesse keiner HTML-Groesse entspricht,
// wird sie noch zusatzlich als Style-Option exportiert
OutCSS1_HintStyleOpt( rWrt, rHt );
}
rWrt.Strm() << '>';
}
else
{
HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_font, sal_False );
}
return rWrt;
}
static Writer& OutHTML_SvxLanguage( Writer& rWrt, const SfxPoolItem& rHt )
{
SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt;
if( rHTMLWrt.bOutOpts )
return rWrt;
LanguageType eLang = ((const SvxLanguageItem &)rHt).GetLanguage();
if( LANGUAGE_DONTKNOW == eLang )
return rWrt;
if( rHTMLWrt.bTagOn )
{
ByteString sOut( '<' );
sOut += OOO_STRING_SVTOOLS_HTML_span;
rWrt.Strm() << sOut.GetBuffer();
rHTMLWrt.OutLanguage( ((const SvxLanguageItem &)rHt).GetLanguage() );
rWrt.Strm() << '>';
}
else
{
HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_span, sal_False );
}
return rWrt;
}
static Writer& OutHTML_SwWeight( Writer& rWrt, const SfxPoolItem& rHt )
{
SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt;
if( rHTMLWrt.bOutOpts )
return rWrt;
const FontWeight nBold = ((const SvxWeightItem&)rHt).GetWeight();
if( WEIGHT_BOLD == nBold )
{
HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_bold, rHTMLWrt.bTagOn );
}
else if( rHTMLWrt.bCfgOutStyles && rHTMLWrt.bTxtAttr )
{
// vielleicht als CSS1-Attribut ?
OutCSS1_HintSpanTag( rWrt, rHt );
}
return rWrt;
}
static Writer& OutHTML_SwCrossedOut( Writer& rWrt, const SfxPoolItem& rHt )
{
SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt;
if( rHTMLWrt.bOutOpts )
return rWrt;
// Wegen Netscape schrieben wir hier STRIKE und nicht S raus!
const FontStrikeout nStrike = ((const SvxCrossedOutItem&)rHt).GetStrikeout();
if( STRIKEOUT_NONE != nStrike )
{
HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_strike, rHTMLWrt.bTagOn );
}
else if( rHTMLWrt.bCfgOutStyles && rHTMLWrt.bTxtAttr )
{
// vielleicht als CSS1-Attribut ?
OutCSS1_HintSpanTag( rWrt, rHt );
}
return rWrt;
}
static Writer& OutHTML_SvxEscapement( Writer& rWrt, const SfxPoolItem& rHt )
{
SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt;
if( rHTMLWrt.bOutOpts )
return rWrt;
const SvxEscapement eEscape =
(const SvxEscapement)((const SvxEscapementItem&)rHt).GetEnumValue();
const sal_Char *pStr = 0;
switch( eEscape )
{
case SVX_ESCAPEMENT_SUPERSCRIPT: pStr = OOO_STRING_SVTOOLS_HTML_superscript; break;
case SVX_ESCAPEMENT_SUBSCRIPT: pStr = OOO_STRING_SVTOOLS_HTML_subscript; break;
default:
;
}
if( pStr )
{
HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), pStr, rHTMLWrt.bTagOn );
}
else if( rHTMLWrt.bCfgOutStyles && rHTMLWrt.bTxtAttr )
{
// vielleicht als CSS1-Attribut ?
OutCSS1_HintSpanTag( rWrt, rHt );
}
return rWrt;
}
static Writer& OutHTML_SwUnderline( Writer& rWrt, const SfxPoolItem& rHt )
{
SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt;
if( rHTMLWrt.bOutOpts )
return rWrt;
const FontUnderline eUnder = ((const SvxUnderlineItem&)rHt).GetLineStyle();
if( UNDERLINE_NONE != eUnder )
{
HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_underline, rHTMLWrt.bTagOn );
}
else if( rHTMLWrt.bCfgOutStyles && rHTMLWrt.bTxtAttr )
{
// vielleicht als CSS1-Attribut ?
OutCSS1_HintSpanTag( rWrt, rHt );
}
return rWrt;
}
static Writer& OutHTML_SwFlyCnt( Writer& rWrt, const SfxPoolItem& rHt )
{
SwHTMLWriter & rHTMLWrt = (SwHTMLWriter&)rWrt;
SwFmtFlyCnt& rFlyCnt = (SwFmtFlyCnt&)rHt;
const SwFrmFmt& rFmt = *rFlyCnt.GetFrmFmt();
const SdrObject *pSdrObj = 0;
SwHTMLFrmType eType =
(SwHTMLFrmType)rHTMLWrt.GuessFrmType( rFmt, pSdrObj );
sal_uInt8 nMode = aHTMLOutFrmAsCharTable[eType][rHTMLWrt.nExportMode];
rHTMLWrt.OutFrmFmt( nMode, rFmt, pSdrObj );
return rWrt;
}
// Das ist jetzt unser Blink-Item. Blinkend wird eingeschaltet, indem man
// das Item auf sal_True setzt!
static Writer& OutHTML_SwBlink( Writer& rWrt, const SfxPoolItem& rHt )
{
SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt;
if( rHTMLWrt.bOutOpts || !rHTMLWrt.IsHTMLMode(HTMLMODE_BLINK) )
return rWrt;
if( ((const SvxBlinkItem&)rHt).GetValue() )
{
HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_blink, rHTMLWrt.bTagOn );
}
else if( rHTMLWrt.bCfgOutStyles && rHTMLWrt.bTxtAttr )
{
// vielleicht als CSS1-Attribut ?
OutCSS1_HintSpanTag( rWrt, rHt );
}
return rWrt;
}
Writer& OutHTML_INetFmt( Writer& rWrt, const SwFmtINetFmt& rINetFmt, sal_Bool bOn )
{
SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt;
String aURL( rINetFmt.GetValue() );
const SvxMacroTableDtor *pMacTable = rINetFmt.GetMacroTbl();
sal_Bool bEvents = pMacTable != 0 && pMacTable->Count() > 0;
// Gibt es ueberhaupt etwas auszugeben?
if( !aURL.Len() && !bEvents && !rINetFmt.GetName().Len() )
return rWrt;
// Tag aus? Dann nur ein </A> ausgeben.
if( !bOn )
{
HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_anchor, sal_False );
return rWrt;
}
ByteString sOut( '<' );
sOut += OOO_STRING_SVTOOLS_HTML_anchor;
sal_Bool bScriptDependent = sal_False;
{
const SwCharFmt* pFmt = rWrt.pDoc->GetCharFmtFromPool(
RES_POOLCHR_INET_NORMAL );
SwHTMLFmtInfo aFmtInfo( pFmt );
sal_uInt16 nPos;
if( rHTMLWrt.aChrFmtInfos.Seek_Entry( &aFmtInfo, &nPos ) )
{
bScriptDependent = rHTMLWrt.aChrFmtInfos[nPos]->bScriptDependent;
}
}
if( !bScriptDependent )
{
const SwCharFmt* pFmt = rWrt.pDoc->GetCharFmtFromPool(
RES_POOLCHR_INET_VISIT );
SwHTMLFmtInfo aFmtInfo( pFmt );
sal_uInt16 nPos;
if( rHTMLWrt.aChrFmtInfos.Seek_Entry( &aFmtInfo, &nPos ) )
{
bScriptDependent = rHTMLWrt.aChrFmtInfos[nPos]->bScriptDependent;
}
}
if( bScriptDependent )
{
((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_class) += "=\"";
switch( rHTMLWrt.nCSS1Script )
{
case CSS1_OUTMODE_WESTERN:
sOut += "western";
break;
case CSS1_OUTMODE_CJK:
sOut += "cjk";
break;
case CSS1_OUTMODE_CTL:
sOut += "ctl";
break;
}
sOut += '\"';
}
rWrt.Strm() << sOut.GetBuffer();
#define REL_HACK
#ifdef REL_HACK
String sRel;
#endif
if( aURL.Len() || bEvents )
{
#ifdef REL_HACK
String sTmp( aURL );
sTmp.ToUpperAscii();
xub_StrLen nPos = sTmp.SearchAscii( "\" REL=" );
if( nPos!=STRING_NOTFOUND )
{
sRel = aURL.Copy( nPos+1 );
aURL.Erase( nPos );
}
#endif
aURL.EraseLeadingChars().EraseTrailingChars();
((sOut = ' ') += OOO_STRING_SVTOOLS_HTML_O_href) += "=\"";
rWrt.Strm() << sOut.GetBuffer();
rHTMLWrt.OutHyperlinkHRefValue( aURL );
sOut = '\"';
}
else
sOut.Erase();
if( rINetFmt.GetName().Len() )
{
((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_name) += "=\"";
rWrt.Strm() << sOut.GetBuffer();
HTMLOutFuncs::Out_String( rWrt.Strm(), rINetFmt.GetName(),
rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters );
sOut = '\"';
}
const String& rTarget = rINetFmt.GetTargetFrame();
if( rTarget.Len() )
{
((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_target) += "=\"";
rWrt.Strm() << sOut.GetBuffer();
HTMLOutFuncs::Out_String( rWrt.Strm(), rTarget, rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters );
sOut = '\"';
}
#ifdef REL_HACK
if( sRel.Len() )
sOut += ByteString( sRel, RTL_TEXTENCODING_ASCII_US );
#endif
if( sOut.Len() )
rWrt.Strm() << sOut.GetBuffer();
if( bEvents )
HTMLOutFuncs::Out_Events( rWrt.Strm(), *pMacTable, aAnchorEventTable,
rHTMLWrt.bCfgStarBasic, rHTMLWrt.eDestEnc,
&rHTMLWrt.aNonConvertableCharacters );
rWrt.Strm() << ">";
return rWrt;
}
static Writer& OutHTML_SwFmtINetFmt( Writer& rWrt, const SfxPoolItem& rHt )
{
SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt;
if( rHTMLWrt.bOutOpts )
return rWrt;
const SwFmtINetFmt& rINetFmt = (const SwFmtINetFmt&)rHt;
if( rHTMLWrt.bTagOn )
{
// ggf. ein noch offenes Attribut voruebergehend beenden
if( rHTMLWrt.aINetFmts.Count() )
{
SwFmtINetFmt *pINetFmt =
rHTMLWrt.aINetFmts[ rHTMLWrt.aINetFmts.Count()-1 ];
OutHTML_INetFmt( rWrt, *pINetFmt, sal_False );
}
// jetzt das neue aufmachen
OutHTML_INetFmt( rWrt, rINetFmt, sal_True );
// und merken
const SwFmtINetFmt *pINetFmt = new SwFmtINetFmt( rINetFmt );
rHTMLWrt.aINetFmts.C40_INSERT( SwFmtINetFmt, pINetFmt,
rHTMLWrt.aINetFmts.Count() );
}
else
{
// das
OutHTML_INetFmt( rWrt, rINetFmt, sal_False );
ASSERT( rHTMLWrt.aINetFmts.Count(), "da fehlt doch ein URL-Attribut" );
if( rHTMLWrt.aINetFmts.Count() )
{
// das eigene Attribut vom Stack holen
SwFmtINetFmt *pINetFmt =
rHTMLWrt.aINetFmts[ rHTMLWrt.aINetFmts.Count()-1 ];
rHTMLWrt.aINetFmts.Remove( rHTMLWrt.aINetFmts.Count()-1, 1 );
delete pINetFmt;
}
if( rHTMLWrt.aINetFmts.Count() )
{
// es ist noch ein Attribut auf dem Stack, das wieder geoeffnet
// werden muss
SwFmtINetFmt *pINetFmt =
rHTMLWrt.aINetFmts[ rHTMLWrt.aINetFmts.Count()-1 ];
OutHTML_INetFmt( rWrt, *pINetFmt, sal_True );
}
}
return rWrt;
}
static Writer& OutHTML_SwTxtCharFmt( Writer& rWrt, const SfxPoolItem& rHt )
{
SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt;
if( rHTMLWrt.bOutOpts )
return rWrt;
const SwFmtCharFmt& rChrFmt = (const SwFmtCharFmt&)rHt;
const SwCharFmt* pFmt = rChrFmt.GetCharFmt();
if( !pFmt )
{
return rWrt;
}
SwHTMLFmtInfo aFmtInfo( pFmt );
sal_uInt16 nPos;
if( !rHTMLWrt.aChrFmtInfos.Seek_Entry( &aFmtInfo, &nPos ) )
return rWrt;
const SwHTMLFmtInfo *pFmtInfo = rHTMLWrt.aChrFmtInfos[nPos];
ASSERT( pFmtInfo, "Wieso gint es keine Infos ueber die Zeichenvorlage?" );
if( rHTMLWrt.bTagOn )
{
ByteString sOut( '<' );
if( pFmtInfo->aToken.Len() > 0 )
sOut += pFmtInfo->aToken;
else
sOut += OOO_STRING_SVTOOLS_HTML_span;
if( rHTMLWrt.bCfgOutStyles &&
(pFmtInfo->aClass.Len() || pFmtInfo->bScriptDependent) )
{
((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_class) += "=\"";
rWrt.Strm() << sOut.GetBuffer();
String aClass( pFmtInfo->aClass );
if( pFmtInfo->bScriptDependent )
{
if( aClass.Len() )
aClass += '-';
switch( rHTMLWrt.nCSS1Script )
{
case CSS1_OUTMODE_WESTERN:
aClass.AppendAscii( RTL_CONSTASCII_STRINGPARAM("western") );
break;
case CSS1_OUTMODE_CJK:
aClass.AppendAscii( RTL_CONSTASCII_STRINGPARAM("cjk") );
break;
case CSS1_OUTMODE_CTL:
aClass.AppendAscii( RTL_CONSTASCII_STRINGPARAM("ctl") );
break;
}
}
HTMLOutFuncs::Out_String( rWrt.Strm(), aClass,
rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters );
sOut = '\"';
}
sOut += '>';
rWrt.Strm() << sOut.GetBuffer();
}
else
{
HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(),
pFmtInfo->aToken.Len() ? pFmtInfo->aToken.GetBuffer()
: OOO_STRING_SVTOOLS_HTML_span,
sal_False );
}
return rWrt;
}
static Writer& OutHTML_SvxAdjust( Writer& rWrt, const SfxPoolItem& rHt )
{
SwHTMLWriter & rHTMLWrt = (SwHTMLWriter&)rWrt;
if( !rHTMLWrt.bOutOpts || !rHTMLWrt.bTagOn )
return rWrt;
SvxAdjustItem& rAdjust = (SvxAdjustItem&)rHt;
const sal_Char* pStr = 0;
switch( rAdjust.GetAdjust() )
{
case SVX_ADJUST_CENTER: pStr = OOO_STRING_SVTOOLS_HTML_AL_center; break;
case SVX_ADJUST_LEFT: pStr = OOO_STRING_SVTOOLS_HTML_AL_left; break;
case SVX_ADJUST_RIGHT: pStr = OOO_STRING_SVTOOLS_HTML_AL_right; break;
case SVX_ADJUST_BLOCK: pStr = OOO_STRING_SVTOOLS_HTML_AL_justify; break;
default:
;
}
if( pStr )
{
ByteString sOut( ' ' );
((sOut += OOO_STRING_SVTOOLS_HTML_O_align) += '=') += pStr;
rWrt.Strm() << sOut.GetBuffer();
}
return rWrt;
}
/*
* lege hier die Tabellen fuer die HTML-Funktions-Pointer auf
* die Ausgabe-Funktionen an.
* Es sind lokale Strukturen, die nur innerhalb der HTML-DLL
* bekannt sein muessen.
*/
SwAttrFnTab aHTMLAttrFnTab = {
/* RES_CHRATR_CASEMAP */ OutHTML_CSS1Attr,
/* RES_CHRATR_CHARSETCOLOR */ 0,
/* RES_CHRATR_COLOR */ OutHTML_SvxColor,
/* RES_CHRATR_CONTOUR */ 0,
/* RES_CHRATR_CROSSEDOUT */ OutHTML_SwCrossedOut,
/* RES_CHRATR_ESCAPEMENT */ OutHTML_SvxEscapement,
/* RES_CHRATR_FONT */ OutHTML_SvxFont,
/* RES_CHRATR_FONTSIZE */ OutHTML_SvxFontHeight,
/* RES_CHRATR_KERNING */ OutHTML_CSS1Attr,
/* RES_CHRATR_LANGUAGE */ OutHTML_SvxLanguage,
/* RES_CHRATR_POSTURE */ OutHTML_SwPosture,
/* RES_CHRATR_PROPORTIONALFONTSIZE*/0,
/* RES_CHRATR_SHADOWED */ 0,
/* RES_CHRATR_UNDERLINE */ OutHTML_SwUnderline,
/* RES_CHRATR_WEIGHT */ OutHTML_SwWeight,
/* RES_CHRATR_WORDLINEMODE */ 0,
/* RES_CHRATR_AUTOKERN */ 0,
/* RES_CHRATR_BLINK */ OutHTML_SwBlink,
/* RES_CHRATR_NOHYPHEN */ 0, // Neu: nicht trennen
/* RES_CHRATR_NOLINEBREAK */ 0, // Neu: nicht umbrechen
/* RES_CHRATR_BACKGROUND */ OutHTML_CSS1Attr, // Neu: Zeichenhintergrund
/* RES_CHRATR_CJK_FONT */ OutHTML_SvxFont,
/* RES_CHRATR_CJK_FONTSIZE */ OutHTML_SvxFontHeight,
/* RES_CHRATR_CJK_LANGUAGE */ OutHTML_SvxLanguage,
/* RES_CHRATR_CJK_POSTURE */ OutHTML_SwPosture,
/* RES_CHRATR_CJK_WEIGHT */ OutHTML_SwWeight,
/* RES_CHRATR_CTL_FONT */ OutHTML_SvxFont,
/* RES_CHRATR_CTL_FONTSIZE */ OutHTML_SvxFontHeight,
/* RES_CHRATR_CTL_LANGUAGE */ OutHTML_SvxLanguage,
/* RES_CHRATR_CTL_POSTURE */ OutHTML_SwPosture,
/* RES_CHRATR_CTL_WEIGHT */ OutHTML_SwWeight,
/* RES_CHRATR_ROTATE */ 0,
/* RES_CHRATR_EMPHASIS_MARK */ 0,
/* RES_CHRATR_TWO_LINES */ 0,
/* RES_CHRATR_SCALEW */ 0,
/* RES_CHRATR_RELIEF */ 0,
/* RES_CHRATR_HIDDEN */ 0,
/* RES_CHRATR_OVERLINE */ OutHTML_CSS1Attr,
/* RES_CHRATR_DUMMY1 */ 0,
/* RES_CHRATR_DUMMY2 */ 0,
//For i120935, Insert blank entry for RES_CHRATR_BIDITRL and RES_CHRATR_IDCTHINT, for keep the identical res order
/*RES_CHRATR_BIDIRTL*/ 0,
/*RES_CHRATR_IDCTHINT*/ 0,
/* RES_TXTATR_REFMARK */ 0,
/* RES_TXTATR_TOXMARK */ 0,
/* RES_TXTATR_META */ 0,
/* RES_TXTATR_METAFIELD */ 0,
/* RES_TXTATR_AUTOFMT */ 0,
/* RES_TXTATR_INETFMT */ OutHTML_SwFmtINetFmt,
/* RES_TXTATR_CHARFMT */ OutHTML_SwTxtCharFmt,
/* RES_TXTATR_CJK_RUBY */ 0,
/* RES_TXTATR_UNKNOWN_CONTAINER */ 0,
/* RES_TXTATR_INPUTFIELD */ OutHTML_SwFmtFld,
/* RES_TXTATR_FIELD */ OutHTML_SwFmtFld,
/* RES_TXTATR_FLYCNT */ OutHTML_SwFlyCnt,
/* RES_TXTATR_FTN */ OutHTML_SwFmtFtn,
/* RES_TXTATR_ANNOTATION */ OutHTML_SwFmtFld,
/* RES_TXTATR_DUMMY3 */ 0,
/* RES_TXTATR_DUMMY1 */ 0, // Dummy:
/* RES_TXTATR_DUMMY2 */ 0, // Dummy:
/* RES_PARATR_LINESPACING */ 0,
/* RES_PARATR_ADJUST */ OutHTML_SvxAdjust,
/* RES_PARATR_SPLIT */ 0,
/* RES_PARATR_WIDOWS */ 0,
/* RES_PARATR_ORPHANS */ 0,
/* RES_PARATR_TABSTOP */ 0,
/* RES_PARATR_HYPHENZONE*/ 0,
/* RES_PARATR_DROP */ OutHTML_CSS1Attr,
/* RES_PARATR_REGISTER */ 0, // neu: Registerhaltigkeit
/* RES_PARATR_NUMRULE */ 0, // Dummy:
/* RES_PARATR_SCRIPTSPACE */ 0, // Dummy:
/* RES_PARATR_HANGINGPUNCTUATION */ 0, // Dummy:
/* RES_PARATR_FORBIDDEN_RULES */ 0, // new
/* RES_PARATR_VERTALIGN */ 0, // new
/* RES_PARATR_SNAPTOGRID*/ 0, // new
/* RES_PARATR_CONNECT_TO_BORDER */ 0, // new
/* RES_PARATR_LIST_ID */ 0, // new
/* RES_PARATR_LIST_LEVEL */ 0, // new
/* RES_PARATR_LIST_ISRESTART */ 0, // new
/* RES_PARATR_LIST_RESTARTVALUE */ 0, // new
/* RES_PARATR_LIST_ISCOUNTED */ 0, // new
/* RES_FILL_ORDER */ 0,
/* RES_FRM_SIZE */ 0,
/* RES_PAPER_BIN */ 0,
/* RES_LR_SPACE */ 0,
/* RES_UL_SPACE */ 0,
/* RES_PAGEDESC */ 0,
/* RES_BREAK */ 0,
/* RES_CNTNT */ 0,
/* RES_HEADER */ 0,
/* RES_FOOTER */ 0,
/* RES_PRINT */ 0,
/* RES_OPAQUE */ 0,
/* RES_PROTECT */ 0,
/* RES_SURROUND */ 0,
/* RES_VERT_ORIENT */ 0,
/* RES_HORI_ORIENT */ 0,
/* RES_ANCHOR */ 0,
/* RES_BACKGROUND */ 0,
/* RES_BOX */ 0,
/* RES_SHADOW */ 0,
/* RES_FRMMACRO */ 0,
/* RES_COL */ 0,
/* RES_KEEP */ 0,
/* RES_URL */ 0,
/* RES_EDIT_IN_READONLY */ 0,
/* RES_LAYOUT_SPLIT */ 0,
/* RES_FRMATR_DUMMY1 */ 0, // Dummy:
/* RES_FRMATR_DUMMY2 */ 0, // Dummy:
/* RES_AUTO_STYLE */ 0, // Dummy:
/* RES_FRMATR_DUMMY4 */ 0, // Dummy:
/* RES_FRMATR_DUMMY5 */ 0, // Dummy:
/* RES_FRMATR_DUMMY6 */ 0, // Dummy:
/* RES_FRMATR_DUMMY7 */ 0, // Dummy:
/* RES_FRMATR_DUMMY8 */ 0, // Dummy:
/* RES_FRMATR_DUMMY9 */ 0, // Dummy:
/* RES_FOLLOW_TEXT_FLOW */ 0,
/* RES_WRAP_INFLUENCE_ON_OBJPOS */ 0,
/* RES_FRMATR_DUMMY2 */ 0, // Dummy:
/* RES_AUTO_STYLE */ 0, // Dummy:
/* RES_FRMATR_DUMMY4 */ 0, // Dummy:
/* RES_FRMATR_DUMMY5 */ 0, // Dummy:
/* RES_GRFATR_MIRRORGRF */ 0,
/* RES_GRFATR_CROPGRF */ 0,
/* RES_GRFATR_ROTATION */ 0,
/* RES_GRFATR_LUMINANCE */ 0,
/* RES_GRFATR_CONTRAST */ 0,
/* RES_GRFATR_CHANNELR */ 0,
/* RES_GRFATR_CHANNELG */ 0,
/* RES_GRFATR_CHANNELB */ 0,
/* RES_GRFATR_GAMMA */ 0,
/* RES_GRFATR_INVERT */ 0,
/* RES_GRFATR_TRANSPARENCY */ 0,
/* RES_GRFATR_DRWAMODE */ 0,
/* RES_GRFATR_DUMMY1 */ 0,
/* RES_GRFATR_DUMMY2 */ 0,
/* RES_GRFATR_DUMMY3 */ 0,
/* RES_GRFATR_DUMMY4 */ 0,
/* RES_GRFATR_DUMMY5 */ 0,
/* RES_BOXATR_FORMAT */ 0,
/* RES_BOXATR_FORMULA */ 0,
/* RES_BOXATR_VALUE */ 0
};