diff options
Diffstat (limited to 'sw/source/filter/html')
36 files changed, 47307 insertions, 0 deletions
diff --git a/sw/source/filter/html/SwAppletImpl.cxx b/sw/source/filter/html/SwAppletImpl.cxx new file mode 100644 index 000000000000..a6ae6622a340 --- /dev/null +++ b/sw/source/filter/html/SwAppletImpl.cxx @@ -0,0 +1,208 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" +#include <SwAppletImpl.hxx> +#include <svtools/htmlkywd.hxx> +#include <svl/urihelper.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/embed/EmbedStates.hpp> + +#include <comphelper/embeddedobjectcontainer.hxx> +#include <sot/clsids.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <svtools/embedhlp.hxx> + +using namespace com::sun::star; + +namespace { + +static char const sHTML_O_archive[] = "ARCHIVE"; +static char const sHTML_O_Archives[] = "ARCHIVES"; +static char const sHTML_O_Object[] = "OBJECT"; + +} + +sal_uInt16 SwApplet_Impl::GetOptionType( const String& rName, sal_Bool bApplet ) +{ + sal_uInt16 nType = bApplet ? SWHTML_OPTTYPE_PARAM : SWHTML_OPTTYPE_TAG; + + switch( rName.GetChar(0) ) + { + case 'A': + case 'a': + if( rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_align ) || + rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_alt ) ) + nType = SWHTML_OPTTYPE_IGNORE; + else if( bApplet && + (rName.EqualsIgnoreCaseAscii( sHTML_O_archive ) || + rName.EqualsIgnoreCaseAscii( sHTML_O_Archives )) ) + nType = SWHTML_OPTTYPE_TAG; + break; + case 'C': + case 'c': + if( rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_class ) || + (bApplet && (rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_code ) || + rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_codebase ))) ) + nType = SWHTML_OPTTYPE_IGNORE; + break; + case 'H': + case 'h': + if( rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_height ) ) + nType = SWHTML_OPTTYPE_SIZE; + else if( rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_hspace ) || + (!bApplet && rName.EqualsIgnoreCaseAscii( OOO_STRING_SW_HTML_O_Hidden )) ) + nType = SWHTML_OPTTYPE_IGNORE; + break; + case 'I': + case 'i': + if( rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_id ) ) + nType = SWHTML_OPTTYPE_IGNORE; + break; + case 'M': + case 'm': + if( bApplet && rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_mayscript ) ) + nType = SWHTML_OPTTYPE_IGNORE; + break; + case 'N': + case 'n': + if( rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_name ) ) + nType = SWHTML_OPTTYPE_IGNORE; + break; + case 'O': + case 'o': + if( bApplet && rName.EqualsIgnoreCaseAscii( sHTML_O_Object ) ) + nType = SWHTML_OPTTYPE_TAG; + break; + case 'S': + case 's': + if( rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_style ) || + (!bApplet && rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_src )) ) + nType = SWHTML_OPTTYPE_IGNORE; + break; + case 'T': + case 't': + if( !bApplet && rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_type ) ) + nType = SWHTML_OPTTYPE_IGNORE; + break; + case 'V': + case 'v': + if( rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_vspace ) ) + nType = SWHTML_OPTTYPE_IGNORE; + break; + case 'W': + case 'w': + if( rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_width ) ) + nType = SWHTML_OPTTYPE_SIZE; + break; + } + + return nType; +} +SwApplet_Impl::SwApplet_Impl( SfxItemPool& rPool, sal_uInt16 nWhich1, sal_uInt16 nWhich2 ) : + aItemSet( rPool, nWhich1, nWhich2 ) +{ +} + +void SwApplet_Impl::CreateApplet( const String& rCode, const String& rName, + sal_Bool bMayScript, const String& rCodeBase, + const String& rDocumentBaseURL ) +{ + comphelper::EmbeddedObjectContainer aCnt; + ::rtl::OUString aName; + + // create Applet; it will be in running state + xApplet = aCnt.CreateEmbeddedObject( SvGlobalName( SO3_APPLET_CLASSID ).GetByteSequence(), aName ); + ::svt::EmbeddedObjectRef::TryRunningState( xApplet ); + + INetURLObject aUrlBase(rDocumentBaseURL); + aUrlBase.removeSegment(); + + String sDocBase = aUrlBase.GetMainURL(INetURLObject::NO_DECODE); + uno::Reference < beans::XPropertySet > xSet( xApplet->getComponent(), uno::UNO_QUERY ); + if ( xSet.is() ) + { + xSet->setPropertyValue( ::rtl::OUString::createFromAscii("AppletCode"), uno::makeAny( ::rtl::OUString( rCode ) ) ); + xSet->setPropertyValue( ::rtl::OUString::createFromAscii("AppletName"), uno::makeAny( ::rtl::OUString( rName ) ) ); + xSet->setPropertyValue( ::rtl::OUString::createFromAscii("AppletIsScript"), uno::makeAny( sal_Bool(bMayScript) ) ); + xSet->setPropertyValue( ::rtl::OUString::createFromAscii("AppletDocBase"), uno::makeAny( ::rtl::OUString(sDocBase) ) ); + if ( rCodeBase.Len() ) + xSet->setPropertyValue( ::rtl::OUString::createFromAscii("AppletCodeBase"), uno::makeAny( ::rtl::OUString( rCodeBase ) ) ); + else + xSet->setPropertyValue( ::rtl::OUString::createFromAscii("AppletCodeBase"), uno::makeAny( ::rtl::OUString( sDocBase ) ) ); + } +} +#ifdef SOLAR_JAVA +sal_Bool SwApplet_Impl::CreateApplet( const String& rBaseURL ) +{ + String aCode, aName, aCodeBase; + sal_Bool bMayScript = sal_False; + + sal_uInt32 nArgCount = aCommandList.Count(); + for( sal_uInt32 i=0; i<nArgCount; i++ ) + { + const SvCommand& rArg = aCommandList[i]; + const String& rName = rArg.GetCommand(); + if( rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_code ) ) + aCode = rArg.GetArgument(); + else if( rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_codebase ) ) + aCodeBase = INetURLObject::GetAbsURL( rBaseURL, rArg.GetArgument() ); + else if( rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_name ) ) + aName = rArg.GetArgument(); + else if( rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_mayscript ) ) + bMayScript = sal_True; + } + + if( !aCode.Len() ) + return sal_False; + CreateApplet( aCode, aName, bMayScript, aCodeBase, rBaseURL ); + return sal_True; +} +#endif + +SwApplet_Impl::~SwApplet_Impl() +{ +} +void SwApplet_Impl::FinishApplet() +{ + //xApplet->EnableSetModified( sal_True ); + uno::Reference < beans::XPropertySet > xSet( xApplet->getComponent(), uno::UNO_QUERY ); + if ( xSet.is() ) + { + uno::Sequence < beans::PropertyValue > aProps; + aCommandList.FillSequence( aProps ); + xSet->setPropertyValue( ::rtl::OUString::createFromAscii("AppletCommands"), uno::makeAny( aProps ) ); + } +} + +#ifdef SOLAR_JAVA +void SwApplet_Impl::AppendParam( const String& rName, const String& rValue ) +{ + aCommandList.Append( rName, rValue ); +} +#endif diff --git a/sw/source/filter/html/css1atr.cxx b/sw/source/filter/html/css1atr.cxx new file mode 100644 index 000000000000..63925788ee1a --- /dev/null +++ b/sw/source/filter/html/css1atr.cxx @@ -0,0 +1,3859 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + + +#include "hintids.hxx" +#include <vcl/svapp.hxx> +#include <vcl/wrkwin.hxx> +#include <svl/whiter.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/ulspitem.hxx> +#include <editeng/brshitem.hxx> +#include <editeng/brkitem.hxx> +#include <editeng/keepitem.hxx> +#include <editeng/widwitem.hxx> +#include <editeng/spltitem.hxx> +#include <editeng/orphitem.hxx> +#include <svx/xoutbmp.hxx> +#include <editeng/langitem.hxx> +#include <editeng/frmdiritem.hxx> +#include <svtools/htmlout.hxx> +#include <svtools/htmlkywd.hxx> +#include <svx/htmlmode.hxx> +#include <svl/urihelper.hxx> +#include <tools/urlobj.hxx> +#include <tools/bigint.hxx> +#include <unotools/charclass.hxx> +#include <i18npool/mslangid.hxx> +#include <charfmt.hxx> +#include <fmtcol.hxx> +#include <fmtfsize.hxx> +#include <fmtornt.hxx> +#include <fmtpdsc.hxx> +#include <fmtlsplt.hxx> +#include <pagedesc.hxx> +#include <fmtanchr.hxx> +#include <docary.hxx> +#include <pam.hxx> +#include <viewsh.hxx> +#include <viewopt.hxx> +#include <swtable.hxx> +// OTES +#include <ftninfo.hxx> +#include <ftnidx.hxx> +#include <txtftn.hxx> +#include <fmtftn.hxx> +// FOOTNOTES +#include <dcontact.hxx> + +#include "doc.hxx" +#include "swerror.h" +#include "charatr.hxx" +#include "paratr.hxx" +#include "frmatr.hxx" +#include "poolfmt.hxx" +#include "fltini.hxx" +#include "css1kywd.hxx" +#include "wrthtml.hxx" +#include "htmlnum.hxx" + +#include <IDocumentStylePoolAccess.hxx> +#include <numrule.hxx> + +/* + * 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 + +#endif + +#define HTML_HEADSPACE (12*20) + +#define CSS1_BACKGROUND_ATTR 1 +#define CSS1_BACKGROUND_PAGE 2 +#define CSS1_BACKGROUND_TABLE 3 +#define CSS1_BACKGROUND_FLY 4 +#define CSS1_BACKGROUND_SECTION 5 + +#define CSS1_FRMSIZE_WIDTH 0x01 +#define CSS1_FRMSIZE_VARHEIGHT 0x02 +#define CSS1_FRMSIZE_MINHEIGHT 0x04 +#define CSS1_FRMSIZE_FIXHEIGHT 0x08 +#define CSS1_FRMSIZE_ANYHEIGHT 0x0e +#define CSS1_FRMSIZE_PIXEL 0x10 + +using namespace ::com::sun::star; + +//----------------------------------------------------------------------- + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_rule_end, " }" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_span_tag_end, "\">" ); +const sal_Char cCSS1_style_opt_end = '\"'; + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sHTML_FTN_fontheight, "57%" ); + +extern SwAttrFnTab aCSS1AttrFnTab; + +static Writer& OutCSS1_SwFmt( Writer& rWrt, const SwFmt& rFmt, + IDocumentStylePoolAccess /*SwDoc*/ *pDoc, SwDoc *pTemplate ); +static Writer& OutCSS1_SwPageDesc( Writer& rWrt, const SwPageDesc& rFmt, + IDocumentStylePoolAccess /*SwDoc*/ *pDoc, SwDoc *pTemplate, + sal_uInt16 nRefPoolId, sal_Bool bExtRef, + sal_Bool bPseudo=sal_True ); +static Writer& OutCSS1_SwFtnInfo( Writer& rWrt, const SwEndNoteInfo& rInfo, + SwDoc *pDoc, sal_uInt16 nNotes, sal_Bool bEndNote ); +static void OutCSS1_SwFmtDropAttrs( SwHTMLWriter& rHWrt, + const SwFmtDrop& rDrop, + const SfxItemSet *pCharFmtItemSet=0 ); +static Writer& OutCSS1_SvxTxtLn_SvxCrOut_SvxBlink( Writer& rWrt, + const SvxUnderlineItem *pUItem, + const SvxOverlineItem *pOItem, + const SvxCrossedOutItem *pCOItem, + const SvxBlinkItem *pBItem ); +static Writer& OutCSS1_SvxFontWeight( Writer& rWrt, const SfxPoolItem& rHt ); +static Writer& OutCSS1_SvxPosture( Writer& rWrt, const SfxPoolItem& rHt ); +static Writer& OutCSS1_SvxULSpace( Writer& rWrt, const SfxPoolItem& rHt ); +static Writer& OutCSS1_SvxLRSpace( Writer& rWrt, const SfxPoolItem& rHt ); +static Writer& OutCSS1_SvxULSpace_SvxLRSpace( Writer& rWrt, + const SvxULSpaceItem *pULSpace, + const SvxLRSpaceItem *pLRSpace ); +static Writer& OutCSS1_SvxULSpace_SvxLRSpace( Writer& rWrt, + const SfxItemSet& rItemSet, + sal_Bool bDeep ); +static Writer& OutCSS1_SvxBrush( Writer& rWrt, const SfxPoolItem& rHt, + sal_uInt16 nMode, const String *pGrfName ); +static Writer& OutCSS1_SvxBrush( Writer& rWrt, const SfxPoolItem& rHt ); +static Writer& OutCSS1_SvxBox( Writer& rWrt, const SfxPoolItem& rHt ); +static Writer& OutCSS1_SwFmtFrmSize( Writer& rWrt, const SfxPoolItem& rHt, + sal_uInt16 nMode ); +static Writer& OutCSS1_SvxFmtBreak_SwFmtPDesc_SvxFmtKeep( Writer& rWrt, + const SfxItemSet& rItemSet, + sal_Bool bDeep ); +static Writer& OutCSS1_SwFmtLayoutSplit( Writer& rWrt, const SfxPoolItem& rHt ); + +static void ConvToHex( sal_uInt16 nHex, ByteString& rStr ) +{ + sal_Char aNToABuf[] = "00"; + + // Pointer an das Bufferende setzen + sal_Char *pStr = aNToABuf + (sizeof(aNToABuf)-1); + for( sal_uInt8 n = 0; n < 2; ++n ) + { + *(--pStr) = (sal_Char)(nHex & 0xf ) + 48; + if( *pStr > '9' ) + *pStr += 39; + nHex >>= 4; + } + + rStr.Append( aNToABuf ); +} + +static void GetCSS1Color( const Color& rColor, ByteString& rStr ) +{ + rStr += '#'; + + ConvToHex( rColor.GetRed(), rStr ); + ConvToHex( rColor.GetGreen(), rStr ); + ConvToHex( rColor.GetBlue(), rStr ); +} + +class SwCSS1OutMode +{ + SwHTMLWriter& rWrt; + sal_uInt16 nOldMode; + +public: + + SwCSS1OutMode( SwHTMLWriter& rHWrt, sal_uInt16 nMode, sal_Bool bStartFirst=sal_True, + const String *pSelector=0 ) : + rWrt( rHWrt ), + nOldMode( rHWrt.nCSS1OutMode ) + { + rWrt.nCSS1OutMode = nMode; + if( bStartFirst ) + rWrt.bFirstCSS1Property = sal_True; + if( pSelector ) + rWrt.aCSS1Selector = *pSelector; + } + + ~SwCSS1OutMode() + { + rWrt.nCSS1OutMode = nOldMode; + } +}; + + + +void SwHTMLWriter::OutCSS1_Property( const sal_Char *pProp, + const sal_Char *pVal, + const String *pSVal ) +{ + ByteString sOut; + + if( bFirstCSS1Rule && (nCSS1OutMode & CSS1_OUTMODE_RULE_ON)!=0 ) + { + bFirstCSS1Rule = sal_False; + OutNewLine(); + ((((sOut += '<') += OOO_STRING_SVTOOLS_HTML_style) += ' ') += OOO_STRING_SVTOOLS_HTML_O_type) += "=\"text/css\">"; + Strm() << sOut.GetBuffer(); + sOut.Erase(); + OutNewLine(); + Strm() << '<' << OOO_STRING_SVTOOLS_HTML_comment; + + IncIndentLevel(); + } + + if( bFirstCSS1Property ) + { + switch( nCSS1OutMode & CSS1_OUTMODE_ANY_ON ) + { + case CSS1_OUTMODE_SPAN_TAG_ON: + case CSS1_OUTMODE_SPAN_TAG1_ON: + if( bTagOn ) + { + ((((sOut += '<') += OOO_STRING_SVTOOLS_HTML_span) += ' ') += OOO_STRING_SVTOOLS_HTML_O_style) += "=\""; + } + else + { + HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_span, sal_False ); + return; + } + break; + + case CSS1_OUTMODE_RULE_ON: + { + ByteString sTmp( aCSS1Selector, eDestEnc ); + OutNewLine(); + (sOut = sTmp) += " { "; + } + break; + + case CSS1_OUTMODE_STYLE_OPT_ON: + ((sOut = ' ') += OOO_STRING_SVTOOLS_HTML_O_style) += "=\""; + break; + } + bFirstCSS1Property = sal_False; + } + else + { + sOut += "; "; + } + + + (sOut += pProp) += ": "; + if( nCSS1OutMode & CSS1_OUTMODE_ENCODE ) + { + // In STYLE-Optionen den String codieren + Strm() << sOut.GetBuffer(); + sOut.Erase(); + if( pVal ) + HTMLOutFuncs::Out_String( Strm(), String::CreateFromAscii(pVal), + eDestEnc, &aNonConvertableCharacters ); + else if( pSVal ) + HTMLOutFuncs::Out_String( Strm(), *pSVal, eDestEnc, &aNonConvertableCharacters ); + } + else + { + // Im STYLE-Tag des String direct ausgeben + if( pVal ) + sOut += pVal; + else if( pSVal ) + { + ByteString sTmp( *pSVal, eDestEnc ); + sOut += sTmp; + } + } + + if( sOut.Len() ) + Strm() << sOut.GetBuffer(); +} + +static void AddUnitPropertyValue( long nVal, FieldUnit eUnit, ByteString& rOut ) +{ + if( nVal < 0 ) + { + // Vorzeichen extra behandeln + nVal = -nVal; + rOut += '-'; + } + + // Die umgerechnete Einheit ergibt sich aus (x * nMul)/(nDiv*nFac*10) + long nMul = 1000; + long nDiv = 1; + long nFac = 100; + const sal_Char *pUnit; + switch( eUnit ) + { + case FUNIT_100TH_MM: + ASSERT( FUNIT_MM == eUnit, "Masseinheit wird nicht unterstuetzt" ); + case FUNIT_MM: + // 0.01mm = 0.57twip + nMul = 25400; // 25.4 * 1000 + nDiv = 1440; // 72 * 20; + nFac = 100; + pUnit = sCSS1_UNIT_mm; + break; + + case FUNIT_M: + case FUNIT_KM: + ASSERT( FUNIT_CM == eUnit, "Masseinheit wird nicht unterstuetzt" ); + case FUNIT_CM: +#ifdef EXACT_VALUES + // 0.001cm = 0.57twip + nMul = 25400; // 2.54 * 10000 + nDiv = 1440; // 72 * 20; + nFac = 1000; +#else + // 0.01cm = 5.7twip (ist zwar ungenau, aber die UI ist auch ungenau) + nMul = 2540; // 2.54 * 1000 + nDiv = 1440; // 72 * 20; + nFac = 100; +#endif + pUnit = sCSS1_UNIT_cm; + break; + + case FUNIT_TWIP: + ASSERT( FUNIT_POINT == eUnit, "Masseinheit wird nicht unterstuetzt" ); + case FUNIT_POINT: +#ifdef EXACT_VALUES + // 0.01pt = 0.2twip + nMul = 1000; + nDiv = 20; + nFac = 100; +#else + // 0.1pt = 2.0twip (ist zwar ungenau, aber die UI ist auch ungenau) + nMul = 100; + nDiv = 20; + nFac = 10; +#endif + pUnit = sCSS1_UNIT_pt; + break; + + case FUNIT_PICA: +#ifdef EXACT_VALUES + // 0.001pc = 0.24twip + nMul = 10000; + nDiv = 12 * 20; + nFac = 1000; +#else + // 0.01pc = 2.40twip (ist zwar ungenau, aber die UI ist auch ungenau) + nMul = 1000; + nDiv = 240; // 12 * 20; + nFac = 100; +#endif + pUnit = sCSS1_UNIT_pc; + break; + + case FUNIT_NONE: + case FUNIT_FOOT: + case FUNIT_MILE: + case FUNIT_CUSTOM: + case FUNIT_PERCENT: + case FUNIT_INCH: + default: + ASSERT( FUNIT_INCH == eUnit, "Masseinheit wird nicht unterstuetzt" ); +#ifdef EXACT_VALUES + // 0.0001in = 0.144twip + nMul = 100000; + nDiv = 1440; // 72 * 20; + nFac = 10000; +#else + // 0.01in = 14.4twip (ist zwar ungenau, aber die UI ist auch ungenau) + nMul = 1000; + nDiv = 1440; // 72 * 20; + nFac = 100; +#endif + pUnit = sCSS1_UNIT_inch; + break; + } + + long nLongVal = 0; + sal_Bool bOutLongVal = sal_True; + if( nVal > LONG_MAX / nMul ) + { + // Zum Unrechnen der Einheit wird ein BigInt benoetigt +#ifdef SAL_INT64_IS_STRUCT + BigInt nBigVal( nVal ); + nBigVal *= nMul; + nBigVal /= nDiv; + nBigVal += 5; + nBigVal /= 10; + + if( nBigVal.IsLong() ) + { + // Zum Ausgeben des Wertes reicht ein long. + nLongVal = (long)nBigVal; + } + else + { + BigInt nBigFac( nFac ); + BigInt nBig10( 10 ); + rOut += (long)(nBigVal / nBigFac); + if( !(nBigVal % nBigFac).IsZero() ) + { + rOut += '.'; + while( nFac > 1 && !(nBigVal % nBigFac).IsZero() ) + { + nFac /= 10; + nBigFac = nFac; + rOut += (int)((nBigVal / nBigFac) % nBig10 ); + } + } + bOutLongVal = sal_False; + } +#else + sal_Int64 nBigVal( nVal ); + nBigVal *= nMul; + nBigVal /= nDiv; + nBigVal += 5; + nBigVal /= 10; + + if( nBigVal <= LONG_MAX ) + { + // Zum Ausgeben des Wertes reicht ein long. + nLongVal = (long)nBigVal; + } + else + { + rOut += ByteString::CreateFromInt64( nBigVal / (sal_Int64)nFac ); + if( (nBigVal % (sal_Int64)nFac) != 0 ) + { + rOut += '.'; + while( nFac > 1 && (nBigVal % (sal_Int64)nFac) != 0 ) + { + nFac /= 10; + rOut += ByteString::CreateFromInt64( + (nBigVal / (sal_Int64)nFac) % (sal_Int64)10 ); + } + } + bOutLongVal = sal_False; + } +#endif + } + else + { + nLongVal = nVal * nMul; + nLongVal /= nDiv; + nLongVal += 5; + nLongVal /= 10; + } + + if( bOutLongVal ) + { + rOut += ByteString::CreateFromInt32( nLongVal/nFac ); + if( (nLongVal % nFac) != 0 ) + { + rOut += '.'; + while( nFac > 1 && (nLongVal % nFac) != 0 ) + { + nFac /= 10; + rOut += ByteString::CreateFromInt32( (nLongVal / nFac) % 10 ); + } + } + } + + rOut.Append( pUnit ); +} + +void SwHTMLWriter::OutCSS1_UnitProperty( const sal_Char *pProp, long nVal ) +{ + ByteString sOut; + AddUnitPropertyValue( nVal, eCSS1Unit, sOut ); + OutCSS1_PropertyAscii( pProp, sOut ); +} + +void SwHTMLWriter::OutCSS1_PixelProperty( const sal_Char *pProp, long nVal, + sal_Bool bVert ) +{ + if( nVal && Application::GetDefaultDevice() ) + { + Size aSz( bVert ? 0 : nVal, bVert ? nVal : 0 ); + aSz = Application::GetDefaultDevice()->LogicToPixel( aSz, MapMode( MAP_TWIP) ); + nVal = bVert ? aSz.Height() : aSz.Width(); + if( !nVal ) + nVal = 1; + } + + ByteString sOut( ByteString::CreateFromInt32( nVal ) ); + sOut.Append( sCSS1_UNIT_px ); + OutCSS1_PropertyAscii( pProp, sOut ); +} + +void SwHTMLWriter::OutCSS1_SfxItemSet( const SfxItemSet& rItemSet, + sal_Bool bDeep ) +{ + // den ItemSet ausgeben, und zwar inklusive aller Attribute + Out_SfxItemSet( aCSS1AttrFnTab, *this, rItemSet, bDeep ); + + // ein par Attribute benoetigen eine Spezial-Behandlung + const SfxPoolItem *pItem = 0; + + // Underline, Overline, CrossedOut und Blink bilden zusammen eine CSS1-Property + // (geht natuerlich nicht bei Hints) + if( !IsCSS1Source(CSS1_OUTMODE_HINT) ) + { + const SvxUnderlineItem *pUnderlineItem = 0; + if( SFX_ITEM_SET==rItemSet.GetItemState( RES_CHRATR_UNDERLINE, bDeep, &pItem )) + pUnderlineItem = (const SvxUnderlineItem *)pItem; + + const SvxOverlineItem *pOverlineItem = 0; + if( SFX_ITEM_SET==rItemSet.GetItemState( RES_CHRATR_OVERLINE, bDeep, &pItem )) + pOverlineItem = (const SvxOverlineItem *)pItem; + + const SvxCrossedOutItem *pCrossedOutItem = 0; + if( SFX_ITEM_SET==rItemSet.GetItemState( RES_CHRATR_CROSSEDOUT, bDeep, &pItem )) + pCrossedOutItem = (const SvxCrossedOutItem *)pItem; + + const SvxBlinkItem *pBlinkItem = 0; + if( SFX_ITEM_SET==rItemSet.GetItemState( RES_CHRATR_BLINK, bDeep, &pItem )) + pBlinkItem = (const SvxBlinkItem *)pItem; + + if( pUnderlineItem || pOverlineItem || pCrossedOutItem || pBlinkItem ) + OutCSS1_SvxTxtLn_SvxCrOut_SvxBlink( *this, pUnderlineItem, + pOverlineItem, + pCrossedOutItem, + pBlinkItem ); + + OutCSS1_SvxFmtBreak_SwFmtPDesc_SvxFmtKeep( *this, rItemSet, bDeep ); + } + + if( !bFirstCSS1Property ) + { + // wenn eine Property als Bestandteil einer Style-Option + // ausgegeben wurde, muss die Optiomn noch beendet werden + ByteString sOut; + switch( nCSS1OutMode & CSS1_OUTMODE_ANY_OFF ) + { + case CSS1_OUTMODE_SPAN_TAG_OFF: + sOut = sCSS1_span_tag_end; + break; + + case CSS1_OUTMODE_STYLE_OPT_OFF: + sOut = cCSS1_style_opt_end; + break; + + case CSS1_OUTMODE_RULE_OFF: + sOut = sCSS1_rule_end; + break; + } + if( sOut.Len() ) + Strm() << sOut.GetBuffer(); + } +} + +void SwHTMLWriter::OutStyleSheet( const SwPageDesc& rPageDesc, sal_Bool bUsed ) +{ + bFirstCSS1Rule = sal_True; + +// Feature: PrintExt + if( IsHTMLMode(HTMLMODE_PRINT_EXT) ) + { + const SwPageDesc *pFirstPageDesc = 0; + sal_uInt16 nFirstRefPoolId = RES_POOLPAGE_HTML; + bCSS1IgnoreFirstPageDesc = sal_True; + + // Erstmal versuchen wir zu erraten, wie das Dokument so augebaut ist. + // Erlaubt sind nur die Vorlagen HTML, erste Seite, linke Seite und + // rechte Seite. + // Eine erste Seite wird nur exportiert, wenn die erste Seite auch + // wirklich die Vorlage "erste Seite" ist. + // Linke und rechte Seiten werden nur exportiert, wenn diese beiden + // Vorlagen untereinander verkettet werden. + // Wenn andere Vorlagen verwendet werden, wird nur in sehr einfachen + // Faellen etwas exportiert. + const SwPageDesc *pPageDesc = &rPageDesc; + const SwPageDesc *pFollow = rPageDesc.GetFollow(); + if( RES_POOLPAGE_FIRST == pPageDesc->GetPoolFmtId() && + pFollow != pPageDesc && + !IsPoolUserFmt( pFollow->GetPoolFmtId() ) ) + { + // Das Dokument hat eine erste Seite + pFirstPageDesc = pPageDesc; + pPageDesc = pFollow; + pFollow = pPageDesc->GetFollow(); + } + + IDocumentStylePoolAccess* pStylePoolAccess = getIDocumentStylePoolAccess(); + if( pPageDesc == pFollow ) + { + // Das Dokument ist einseitig. Egal welche Seite verwendet wird, + // es wird kein zweiseitiges Dokument daraus gemacht. + // Die Attributierung wird relativ zur HTML-Seitenvorlage + // aus der HTML-Vorlage exportiert. + OutCSS1_SwPageDesc( *this, *pPageDesc, pStylePoolAccess, pTemplate, + RES_POOLPAGE_HTML, sal_True, sal_False ); + nFirstRefPoolId = pFollow->GetPoolFmtId(); + } + else if( (RES_POOLPAGE_LEFT == pPageDesc->GetPoolFmtId() && + RES_POOLPAGE_RIGHT == pFollow->GetPoolFmtId()) || + (RES_POOLPAGE_RIGHT == pPageDesc->GetPoolFmtId() && + RES_POOLPAGE_LEFT == pFollow->GetPoolFmtId()) ) + { + // Das Dokument ist zweiseitig + OutCSS1_SwPageDesc( *this, *pPageDesc, pStylePoolAccess, pTemplate, + RES_POOLPAGE_HTML, sal_True ); + OutCSS1_SwPageDesc( *this, *pFollow, pStylePoolAccess, pTemplate, + RES_POOLPAGE_HTML, sal_True ); + nFirstRefPoolId = RES_POOLPAGE_RIGHT; + bCSS1IgnoreFirstPageDesc = sal_False; + } + // Alles andere bekommen wir nicht hin. + + if( pFirstPageDesc ) + OutCSS1_SwPageDesc( *this, *pFirstPageDesc, pStylePoolAccess, pTemplate, + nFirstRefPoolId, sal_False ); + } +// /Feature: PrintExt + + + // The text body style has to be exported always (if it is changed compared + // to the template), because it is used as reference for any style + // that maps to <P>, and that's especially the standard style + getIDocumentStylePoolAccess()->GetTxtCollFromPool( RES_POOLCOLL_TEXT, false ); + + // das Default-TextStyle wir nicht mit ausgegeben !! + // das 0-Style ist das Default, wird nie ausgegeben !! + sal_uInt16 nArrLen = pDoc->GetTxtFmtColls()->Count(); + sal_uInt16 i; + + for( i = 1; i < nArrLen; i++ ) + { + const SwTxtFmtColl* pColl = (*pDoc->GetTxtFmtColls())[i]; + sal_uInt16 nPoolId = pColl->GetPoolFmtId(); + if( !bUsed || nPoolId == RES_POOLCOLL_TEXT || + pDoc->IsUsed( *pColl ) ) + OutCSS1_SwFmt( *this, *pColl, pDoc, pTemplate ); + } + + // das Default-TextStyle wir nicht mit ausgegeben !! + nArrLen = pDoc->GetCharFmts()->Count(); + for( i=1; i<nArrLen; i++ ) + { + const SwCharFmt *pCFmt = (*pDoc->GetCharFmts())[i]; + sal_uInt16 nPoolId = pCFmt->GetPoolFmtId(); + if( !bUsed || nPoolId == RES_POOLCHR_INET_NORMAL || + nPoolId == RES_POOLCHR_INET_VISIT || + pDoc->IsUsed( *pCFmt ) ) + OutCSS1_SwFmt( *this, *pCFmt, pDoc, pTemplate ); + } + + const SwFtnIdxs& rIdxs = pDoc->GetFtnIdxs(); + nArrLen = rIdxs.Count(); + sal_uInt16 nEnd = 0, nFtn = 0; + for( i=0; i < nArrLen; i++ ) + { + if( rIdxs[i]->GetFtn().IsEndNote() ) + nEnd++; + else + nFtn++; + } + OutCSS1_SwFtnInfo( *this, pDoc->GetFtnInfo(), pDoc, nFtn, sal_False ); + OutCSS1_SwFtnInfo( *this, pDoc->GetEndNoteInfo(), pDoc, nEnd, sal_True ); + + if( !bFirstCSS1Rule ) + { + DecIndentLevel(); + OutNewLine(); + Strm() << "-->"; + + OutNewLine(); + HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_style, sal_False ); + } + else + { + bFirstCSS1Rule = sal_False; + } + + nDfltTopMargin = 0; + nDfltBottomMargin = 0; +} + +//----------------------------------------------------------------------- + +// wenn pPseudo gesetzt ist werden Styles-Sheets ausgegeben, +// sonst wird nur nach Token und Class fuer ein Format gesucht +sal_uInt16 SwHTMLWriter::GetCSS1Selector( const SwFmt *pFmt, ByteString& rToken, + String& rClass, sal_uInt16& rRefPoolId, + String *pPseudo ) +{ + sal_uInt16 nDeep = 0; + rToken.Erase(); rClass.Erase(); + rRefPoolId = 0; + if( pPseudo ) + pPseudo->Erase(); + + sal_Bool bChrFmt = RES_CHRFMT==pFmt->Which(); + + // Nach oben die Formate abklappern, bis man auf eine Standard- + // oder eine HTML-Tag-Vorlage trifft + const SwFmt *pPFmt = pFmt; + while( pPFmt && !pPFmt->IsDefault() ) + { + sal_Bool bStop = sal_False; + sal_uInt16 nPoolId = pPFmt->GetPoolFmtId(); + if( USER_FMT & nPoolId ) + { + // Benutzer-Vorlagen + const String& rNm = pPFmt->GetName(); + switch( rNm.GetChar(0) ) + { + // nicht mehr unterstuetzt: + // OOO_STRING_SVTOOLS_HTML_author + // OOO_STRING_SVTOOLS_HTML_acronym + // OOO_STRING_SVTOOLS_HTML_abbreviation + // OOO_STRING_SVTOOLS_HTML_deletedtext + // OOO_STRING_SVTOOLS_HTML_insertedtext + // OOO_STRING_SVTOOLS_HTML_language + // OOO_STRING_SVTOOLS_HTML_person + case 'B': if( !bChrFmt && rNm.EqualsAscii(OOO_STRING_SVTOOLS_HTML_blockquote) ) + { + rRefPoolId = RES_POOLCOLL_HTML_BLOCKQUOTE; + rToken.Assign( OOO_STRING_SVTOOLS_HTML_blockquote ); + } + break; + case 'C': if( bChrFmt ) + { + if( rNm.EqualsAscii(OOO_STRING_SVTOOLS_HTML_citiation) ) + { + rRefPoolId = RES_POOLCHR_HTML_CITIATION; + rToken.Assign( OOO_STRING_SVTOOLS_HTML_citiation ); + } + else if( rNm.EqualsAscii(OOO_STRING_SVTOOLS_HTML_code) ) + { + rRefPoolId = RES_POOLCHR_HTML_CODE; + rToken.Assign( OOO_STRING_SVTOOLS_HTML_code ); + } + } + break; + case 'D': if( bChrFmt && rNm.EqualsAscii(OOO_STRING_SVTOOLS_HTML_definstance) ) + { + rRefPoolId = RES_POOLCHR_HTML_DEFINSTANCE; + rToken.Assign( OOO_STRING_SVTOOLS_HTML_definstance); + } + else if( !bChrFmt ) + { + sal_uInt16 nDefListLvl = GetDefListLvl( rNm, nPoolId ); + // Die Vorlagen DD 1/DT 1 werden ausgegeben, + // aber keine von ihnen abgeleiteten Vorlagen, + // auch nicht DD 2/DT 2 etc. + if( nDefListLvl ) + { + if( pPseudo && + (nDeep || (nDefListLvl & 0x0fff) > 1) ) + { + bStop = sal_True; + } + else if( nDefListLvl & HTML_DLCOLL_DD ) + { + rRefPoolId = RES_POOLCOLL_HTML_DD; + rToken.Assign( OOO_STRING_SVTOOLS_HTML_dd ); + } + else + { + rRefPoolId = RES_POOLCOLL_HTML_DT; + rToken.Assign( OOO_STRING_SVTOOLS_HTML_dt ); + } + } + } + break; + case 'E': if( bChrFmt && rNm.EqualsAscii( OOO_STRING_SVTOOLS_HTML_emphasis ) ) + { + rRefPoolId = RES_POOLCHR_HTML_EMPHASIS; + rToken.Assign( OOO_STRING_SVTOOLS_HTML_emphasis ); + } + break; + case 'H': if( !bChrFmt && rNm.EqualsAscii( OOO_STRING_SVTOOLS_HTML_horzrule ) ) + // HR nicht ausgeben! + bStop = (nDeep==0); + break; + case 'K': if( bChrFmt && rNm.EqualsAscii( OOO_STRING_SVTOOLS_HTML_keyboard ) ) + { + rRefPoolId = RES_POOLCHR_HTML_KEYBOARD; + rToken.Assign( OOO_STRING_SVTOOLS_HTML_keyboard ); + } + break; + case 'L': if( !bChrFmt && rNm.EqualsAscii( OOO_STRING_SVTOOLS_HTML_listing ) ) + { + // Listing als PRE exportieren bzw. von + // PRE abgeleitete Vorlage exportieren + rToken.Assign( OOO_STRING_SVTOOLS_HTML_preformtxt ); + rRefPoolId = RES_POOLCOLL_HTML_PRE; + nDeep = CSS1_FMT_CMPREF; + } + break; + case 'P': if( !bChrFmt && rNm.EqualsAscii( OOO_STRING_SVTOOLS_HTML_preformtxt ) ) + { + rRefPoolId = RES_POOLCOLL_HTML_PRE; + rToken.Assign( OOO_STRING_SVTOOLS_HTML_preformtxt ); + } + break; + case 'S': if( bChrFmt ) + { + if( rNm.EqualsAscii( OOO_STRING_SVTOOLS_HTML_sample ) ) + { + rRefPoolId = RES_POOLCHR_HTML_SAMPLE; + rToken.Assign( OOO_STRING_SVTOOLS_HTML_sample ); + } + else if( rNm.EqualsAscii( OOO_STRING_SVTOOLS_HTML_strong ) ) + { + rRefPoolId = RES_POOLCHR_HTML_STRONG; + rToken.Assign( OOO_STRING_SVTOOLS_HTML_strong ); + } + } + break; + case 'T': if( bChrFmt && rNm.EqualsAscii( OOO_STRING_SVTOOLS_HTML_teletype ) ) + { + rRefPoolId = RES_POOLCHR_HTML_TELETYPE; + rToken.Assign( OOO_STRING_SVTOOLS_HTML_teletype ); + } + break; + case 'V': if( bChrFmt && rNm.EqualsAscii( OOO_STRING_SVTOOLS_HTML_variable ) ) + { + rRefPoolId = RES_POOLCHR_HTML_VARIABLE; + rToken.Assign( OOO_STRING_SVTOOLS_HTML_variable ); + } + break; + case 'X': if( !bChrFmt && rNm.EqualsAscii( OOO_STRING_SVTOOLS_HTML_xmp ) ) + { + // XMP als PRE exportieren (aber nicht die + // Vorlage als Style) + rToken.Assign( OOO_STRING_SVTOOLS_HTML_preformtxt ); + rRefPoolId = RES_POOLCOLL_HTML_PRE; + nDeep = CSS1_FMT_CMPREF; + } + break; + } + + // Wenn eine PoolId gesetzt ist, entspricht der Name der + // Vorlage dem szugehoerigen Token + ASSERT( rRefPoolId != 0 == rToken.Len() > 0, + "Token missing" ); + } + else + { + // Pool-Vorlagen + switch( nPoolId ) + { + // Absatz-Vorlagen + case RES_POOLCOLL_HEADLINE_BASE: + case RES_POOLCOLL_STANDARD: + // diese Vorlagen nicht ausgeben + bStop = (nDeep==0); + break; + case RES_POOLCOLL_TEXT: + rToken.Assign( OOO_STRING_SVTOOLS_HTML_parabreak ); + break; + case RES_POOLCOLL_HEADLINE1: + rToken.Assign( OOO_STRING_SVTOOLS_HTML_head1 ); + break; + case RES_POOLCOLL_HEADLINE2: + rToken.Assign( OOO_STRING_SVTOOLS_HTML_head2 ); + break; + case RES_POOLCOLL_HEADLINE3: + rToken.Assign( OOO_STRING_SVTOOLS_HTML_head3 ); + break; + case RES_POOLCOLL_HEADLINE4: + rToken.Assign( OOO_STRING_SVTOOLS_HTML_head4 ); + break; + case RES_POOLCOLL_HEADLINE5: + rToken.Assign( OOO_STRING_SVTOOLS_HTML_head5 ); + break; + case RES_POOLCOLL_HEADLINE6: + rToken.Assign( OOO_STRING_SVTOOLS_HTML_head6 ); + break; + case RES_POOLCOLL_SENDADRESS: + rToken.Assign( OOO_STRING_SVTOOLS_HTML_address ); + break; + case RES_POOLCOLL_HTML_BLOCKQUOTE: + rToken.Assign( OOO_STRING_SVTOOLS_HTML_blockquote ); + break; + case RES_POOLCOLL_HTML_PRE: + rToken.Assign( OOO_STRING_SVTOOLS_HTML_preformtxt ); + break; + + case RES_POOLCOLL_HTML_DD: + rToken.Assign( OOO_STRING_SVTOOLS_HTML_dd ); + break; + case RES_POOLCOLL_HTML_DT: + rToken.Assign( OOO_STRING_SVTOOLS_HTML_dt ); + break; + + case RES_POOLCOLL_TABLE: + if( pPseudo ) + { + rToken.Assign( OOO_STRING_SVTOOLS_HTML_tabledata ); + rToken.Append( ' ' ); + rToken.Append( OOO_STRING_SVTOOLS_HTML_parabreak ); + } + else + rToken.Assign( OOO_STRING_SVTOOLS_HTML_parabreak ); + break; + case RES_POOLCOLL_TABLE_HDLN: + if( pPseudo ) + { + rToken.Assign( OOO_STRING_SVTOOLS_HTML_tableheader ); + rToken.Append( ' ' ); + rToken.Append( OOO_STRING_SVTOOLS_HTML_parabreak ); + } + else + rToken.Assign( OOO_STRING_SVTOOLS_HTML_parabreak ); + break; + case RES_POOLCOLL_HTML_HR: + // HR nicht ausgeben! + bStop = (nDeep==0); + break; + case RES_POOLCOLL_FOOTNOTE: + if( !nDeep ) + { + rToken.Assign( OOO_STRING_SVTOOLS_HTML_parabreak ); + rClass.AssignAscii( OOO_STRING_SVTOOLS_HTML_sdfootnote ); + rRefPoolId = RES_POOLCOLL_TEXT; + nDeep = CSS1_FMT_CMPREF; + } + break; + case RES_POOLCOLL_ENDNOTE: + if( !nDeep ) + { + rToken.Assign( OOO_STRING_SVTOOLS_HTML_parabreak ); + rClass.AssignAscii( OOO_STRING_SVTOOLS_HTML_sdendnote ); + rRefPoolId = RES_POOLCOLL_TEXT; + nDeep = CSS1_FMT_CMPREF; + } + break; + + // Zeichen-Vorlagen + case RES_POOLCHR_HTML_EMPHASIS: + rToken.Assign( OOO_STRING_SVTOOLS_HTML_emphasis ); + break; + case RES_POOLCHR_HTML_CITIATION: + rToken.Assign( OOO_STRING_SVTOOLS_HTML_citiation ); + break; + case RES_POOLCHR_HTML_STRONG: + rToken.Assign( OOO_STRING_SVTOOLS_HTML_strong ); + break; + case RES_POOLCHR_HTML_CODE: + rToken.Assign( OOO_STRING_SVTOOLS_HTML_code ); + break; + case RES_POOLCHR_HTML_SAMPLE: + rToken.Assign( OOO_STRING_SVTOOLS_HTML_sample ); + break; + case RES_POOLCHR_HTML_KEYBOARD: + rToken.Assign( OOO_STRING_SVTOOLS_HTML_keyboard ); + break; + case RES_POOLCHR_HTML_VARIABLE: + rToken.Assign( OOO_STRING_SVTOOLS_HTML_variable ); + break; + case RES_POOLCHR_HTML_DEFINSTANCE: + rToken.Assign( OOO_STRING_SVTOOLS_HTML_definstance ); + break; + case RES_POOLCHR_HTML_TELETYPE: + rToken.Assign( OOO_STRING_SVTOOLS_HTML_teletype ); + break; + + case RES_POOLCHR_INET_NORMAL: + if( pPseudo ) + { + rToken.Assign( OOO_STRING_SVTOOLS_HTML_anchor ); + pPseudo->AssignAscii( sCSS1_link ); + } + break; + case RES_POOLCHR_INET_VISIT: + if( pPseudo ) + { + rToken.Assign( OOO_STRING_SVTOOLS_HTML_anchor ); + pPseudo->AssignAscii( sCSS1_visited ); + } + break; + } + + // Wenn ein Token gesetzt ist, enthaelt nPoolId die dazugehoerige + // Vorlage + if( rToken.Len() && !rRefPoolId ) + rRefPoolId = nPoolId; + } + + if( rToken.Len() || bStop ) + { + // Anhalten wenn eine HTML-Tag-Vorlage gefunden wurde + break; + } + else + { + // sonst weitersuchen + nDeep++; + pPFmt = pPFmt->DerivedFrom(); + } + } + + if( rToken.Len() ) + { + // Es ist eine HTML-Tag-Vorlage + if( !nDeep ) + nDeep = CSS1_FMT_ISTAG; + } + else + { + // Es ist keine HTML-Tag-Vorlage und auch keine davon abgeleitete + nDeep = 0; + } + if( nDeep > 0 && nDeep < CSS1_FMT_SPECIAL ) + { + // Wenn die Vorlage von einer HTML-Vorlage abgeleitet ist, + // wird sie als <TOKEN>.<CLASS> exportiert, sonst als .<CLASS>. + // <CLASS> ergibt sich aus dem Namen der Vorlage durch entfernen + // aller Zeichen vor und inklusive dem ersten '.' + rClass = pFmt->GetName(); + xub_StrLen nPos = rClass.Search( '.' ); + if( nPos != STRING_NOTFOUND && rClass.Len() > nPos+1 ) + { + rClass.Erase( 0, nPos+1 ); + } + + GetAppCharClass().toLower( rClass ); + while( STRING_NOTFOUND != rClass.SearchAndReplace( '.', '-' ) ) + ; + while( STRING_NOTFOUND != rClass.SearchAndReplace( ' ', '-' ) ) + ; + while( STRING_NOTFOUND != rClass.SearchAndReplace( '_', '-' ) ) + ; + } + + return nDeep; +} + +static sal_uInt16 GetCSS1Selector( const SwFmt *pFmt, String& rSelector, + sal_uInt16& rRefPoolId ) +{ + ByteString aToken; + String aClass; + String aPseudo; + + sal_uInt16 nDeep = SwHTMLWriter::GetCSS1Selector( pFmt, aToken, aClass, + rRefPoolId, &aPseudo ); + if( nDeep ) + { + if( aToken.Len() ) + rSelector = String( aToken, RTL_TEXTENCODING_ASCII_US ); + else + rSelector.Erase(); + + if( aClass.Len() ) + (rSelector += '.') += aClass; + if( aPseudo.Len() ) + (rSelector += ':') += aPseudo; + } + + return nDeep; +} + +const SwFmt *SwHTMLWriter::GetTemplateFmt( sal_uInt16 nPoolFmtId, + IDocumentStylePoolAccess* pTemplate /*SwDoc *pTemplate*/) +{ + const SwFmt *pRefFmt = 0; + + if( pTemplate ) + { + ASSERT( !(USER_FMT & nPoolFmtId), + "In der Dok-Vorlage gibt es keine Benutzer-Vorlagen" ); + if( POOLGRP_NOCOLLID & nPoolFmtId ) + pRefFmt = pTemplate->GetCharFmtFromPool( nPoolFmtId ); + else + pRefFmt = pTemplate->GetTxtCollFromPool( nPoolFmtId, false ); + } + + return pRefFmt; +} + +const SwFmt *SwHTMLWriter::GetParentFmt( const SwFmt& rFmt, sal_uInt16 nDeep ) +{ + ASSERT( nDeep != USHRT_MAX, "GetParent fuer HTML-Vorlage aufgerufen!" ); + const SwFmt *pRefFmt = 0; + + if( nDeep > 0 ) + { + // hier wird die HTML-Tag-Vorlage, von der die Vorlage abgeleitet + // ist als Referenz geholt + pRefFmt = &rFmt; + for( sal_uInt16 i=nDeep; i>0; i-- ) + pRefFmt = pRefFmt->DerivedFrom(); + + if( pRefFmt && pRefFmt->IsDefault() ) + pRefFmt = 0; + } + + return pRefFmt; +} + +sal_Bool lcl_css1atr_equalFontItems( const SfxPoolItem& r1, const SfxPoolItem& r2 ) +{ + return ((const SvxFontItem &)r1).GetFamilyName() == + ((const SvxFontItem &)r2).GetFamilyName() && + ((const SvxFontItem &)r1).GetFamily() == + ((const SvxFontItem &)r2).GetFamily(); +} + +void SwHTMLWriter::SubtractItemSet( SfxItemSet& rItemSet, + const SfxItemSet& rRefItemSet, + sal_Bool bSetDefaults, + sal_Bool bClearSame, + const SfxItemSet *pRefScriptItemSet ) +{ + ASSERT( bSetDefaults || bClearSame, + "SwHTMLWriter::SubtractItemSet: Bei diesen Flags passiert nix" ); + SfxItemSet aRefItemSet( *rRefItemSet.GetPool(), rRefItemSet.GetRanges() ); + aRefItemSet.Set( rRefItemSet ); + + // und mit dem Attr-Set der Vorlage vergleichen + SfxWhichIter aIter( rItemSet ); + sal_uInt16 nWhich = aIter.FirstWhich(); + while( nWhich ) + { + const SfxPoolItem *pRefItem, *pItem; + sal_Bool bItemSet = ( SFX_ITEM_SET == + rItemSet.GetItemState( nWhich, sal_False, &pItem) ); + sal_Bool bRefItemSet; + + if( pRefScriptItemSet ) + { + switch( nWhich ) + { + case RES_CHRATR_FONT: + case RES_CHRATR_FONTSIZE: + case RES_CHRATR_LANGUAGE: + case RES_CHRATR_POSTURE: + case RES_CHRATR_WEIGHT: + 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: + 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: + bRefItemSet = ( SFX_ITEM_SET == + pRefScriptItemSet->GetItemState( nWhich, sal_True, &pRefItem) ); + break; + default: + bRefItemSet = ( SFX_ITEM_SET == + aRefItemSet.GetItemState( nWhich, sal_False, &pRefItem) ); + break; + } + } + else + { + bRefItemSet = ( SFX_ITEM_SET == + aRefItemSet.GetItemState( nWhich, sal_False, &pRefItem) ); + } + + if( bItemSet ) + { + if( (bClearSame || pRefScriptItemSet) && bRefItemSet && + ( *pItem == *pRefItem || + ((RES_CHRATR_FONT == nWhich || + RES_CHRATR_CJK_FONT == nWhich || + RES_CHRATR_CTL_FONT == nWhich) && + lcl_css1atr_equalFontItems( *pItem, *pRefItem )) ) ) + { + // das Attribut ist mit dem gleichen Wert in beiden + // Vorlagen vorhanden und muss nicht ausgegeben werden + rItemSet.ClearItem( nWhich ); + } + } + else + { + if( (bSetDefaults || pRefScriptItemSet) && bRefItemSet ) + { + // das Attribut ist nur in der Referenz vorhanden. Das + // Default muss ggf. ausgegeben werden + rItemSet.Put( rItemSet.GetPool()->GetDefaultItem(nWhich) ); + } + } + + nWhich = aIter.NextWhich(); + } +} + +void SwHTMLWriter::PrepareFontList( const SvxFontItem& rFontItem, + String& rNames, + sal_Unicode cQuote, sal_Bool bGeneric ) +{ + rNames = aEmptyStr; + const String& rName = rFontItem.GetFamilyName(); + sal_Bool bContainsKeyword = sal_False; + if( rName.Len() ) + { + xub_StrLen nStrPos = 0; + while( nStrPos != STRING_NOTFOUND ) + { + String aName = rName.GetToken( 0, ';', nStrPos ); + aName.EraseTrailingChars().EraseLeadingChars(); + if( !aName.Len() ) + continue; + + sal_Bool bIsKeyword = sal_False; + switch( aName.GetChar( 0 ) ) + { + case 'c': + case 'C': + bIsKeyword = aName.EqualsIgnoreCaseAscii( sCSS1_PV_cursive ); + break; + + case 'f': + case 'F': + bIsKeyword = aName.EqualsIgnoreCaseAscii( sCSS1_PV_fantasy ); + break; + + case 'm': + case 'M': + bIsKeyword = aName.EqualsIgnoreCaseAscii( sCSS1_PV_monospace ); + break; + + case 's': + case 'S': + bIsKeyword = + aName.EqualsIgnoreCaseAscii( sCSS1_PV_serif ) || + aName.EqualsIgnoreCaseAscii( sCSS1_PV_sans_serif ); + break; + } + + bContainsKeyword |= bIsKeyword; + + if( rNames.Len() ) + rNames.AppendAscii( ", " ); + if( cQuote && !bIsKeyword ) + rNames += cQuote; + rNames += aName; + if( cQuote && !bIsKeyword ) + rNames += cQuote; + } + } + + if( !bContainsKeyword && bGeneric ) + { + const sal_Char *pStr = 0; + switch( rFontItem.GetFamily() ) + { + case FAMILY_ROMAN: pStr = sCSS1_PV_serif; break; + case FAMILY_SWISS: pStr = sCSS1_PV_sans_serif; break; + case FAMILY_SCRIPT: pStr = sCSS1_PV_cursive; break; + case FAMILY_DECORATIVE: pStr = sCSS1_PV_fantasy; break; + case FAMILY_MODERN: pStr = sCSS1_PV_monospace; break; + default: + ; + } + + if( pStr ) + { + if( rNames.Len() ) + rNames.AppendAscii( ", " ); + rNames.AppendAscii( pStr ); + } + } +} + +sal_Bool SwHTMLWriter::HasScriptDependentItems( const SfxItemSet& rItemSet, + sal_Bool bCheckDropCap ) +{ + static sal_uInt16 aWhichIds[] = + { + RES_CHRATR_FONT, RES_CHRATR_CJK_FONT, RES_CHRATR_CTL_FONT, + RES_CHRATR_FONTSIZE, RES_CHRATR_CJK_FONTSIZE, RES_CHRATR_CTL_FONTSIZE, + RES_CHRATR_LANGUAGE, RES_CHRATR_CJK_LANGUAGE, RES_CHRATR_CTL_LANGUAGE, + RES_CHRATR_POSTURE, RES_CHRATR_CJK_POSTURE, RES_CHRATR_CTL_POSTURE, + RES_CHRATR_WEIGHT, RES_CHRATR_CJK_WEIGHT, RES_CHRATR_CTL_WEIGHT, + 0, 0, 0 + }; + + for( sal_uInt16 i=0; aWhichIds[i]; i += 3 ) + { + const SfxPoolItem *pItem = 0, *pItemCJK = 0, *pItemCTL = 0, *pTmp; + sal_uInt16 nItemCount = 0; + if( SFX_ITEM_SET == rItemSet.GetItemState( aWhichIds[i], sal_False, + &pTmp ) ) + { + pItem = pTmp; + nItemCount++; + } + if( SFX_ITEM_SET == rItemSet.GetItemState( aWhichIds[i+1], sal_False, + &pTmp ) ) + { + pItemCJK = pTmp; + nItemCount++; + } + if( SFX_ITEM_SET == rItemSet.GetItemState( aWhichIds[i+2], sal_False, + &pTmp ) ) + { + pItemCTL = pTmp; + nItemCount++; + } + + // If some of the items are set, but not all, we need script dependent + // styles + if( nItemCount > 0 && nItemCount < 3 ) + return sal_True; + + if( 3 == nItemCount ) + { + // If all items are set, but some of them have different values, + // we need script dependent styles, too. For font items, we have + // to take care about their special HTML/CSS1 representation. + if( RES_CHRATR_FONT == aWhichIds[i] ) + { + if( !lcl_css1atr_equalFontItems( *pItem, *pItemCJK ) || + !lcl_css1atr_equalFontItems( *pItem, *pItemCTL ) || + !lcl_css1atr_equalFontItems( *pItemCJK, *pItemCTL ) ) + return sal_True; + } + else + { + if( !( *pItem == *pItemCJK ) || + !( *pItem == *pItemCTL ) || + !( *pItemCJK == *pItemCTL ) ) + return sal_True; + } + } + } + + const SfxPoolItem *pItem; + if( bCheckDropCap && + SFX_ITEM_SET == rItemSet.GetItemState( RES_PARATR_DROP, sal_True, + &pItem ) ) + { + const SwFmtDrop *pDrop = (const SwFmtDrop *)pItem; + const SwCharFmt *pDCCharFmt = pDrop->GetCharFmt(); + if( pDCCharFmt ) + { + SfxItemSet aTstItemSet( *pDCCharFmt->GetAttrSet().GetPool(), + RES_CHRATR_FONT, RES_CHRATR_FONT, + RES_CHRATR_POSTURE, RES_CHRATR_POSTURE, + RES_CHRATR_WEIGHT, RES_CHRATR_WEIGHT, + RES_CHRATR_CJK_FONT, RES_CHRATR_CJK_FONT, + RES_CHRATR_CJK_POSTURE, RES_CHRATR_CJK_WEIGHT, + RES_CHRATR_CTL_FONT, RES_CHRATR_CTL_FONT, + RES_CHRATR_CTL_POSTURE, RES_CHRATR_CTL_WEIGHT, + 0 ); + aTstItemSet.Set( pDCCharFmt->GetAttrSet(), sal_True ); + return HasScriptDependentItems( aTstItemSet, sal_False ); + } + } + + return sal_False; +} + +static sal_Bool OutCSS1Rule( SwHTMLWriter& rHTMLWrt, const String& rSelector, + const SfxItemSet& rItemSet, sal_Bool bHasClass, + sal_Bool bCheckForPseudo ) +{ + sal_Bool bScriptDependent = sal_False; + if( SwHTMLWriter::HasScriptDependentItems( rItemSet, + rHTMLWrt.IsHTMLMode(HTMLMODE_DROPCAPS) && bHasClass ) ) + { + bScriptDependent = sal_True; + String aSelector( rSelector ); + + String aPseudo; + if( bCheckForPseudo ) + { + xub_StrLen nPos = aSelector.SearchBackward( ':' ); + if( STRING_NOTFOUND != nPos ) + { + aPseudo = aSelector.Copy( nPos ); + aSelector.Erase( nPos ); + } + } + + if( !bHasClass ) + { + // If we are exporting styles for a tag we have to export a tag + // rule for all properties that aren't style dependent and + // some class rule for the additional style dependen properties + { + SwCSS1OutMode aMode( rHTMLWrt, CSS1_OUTMODE_NO_SCRIPT|CSS1_OUTMODE_RULE|CSS1_OUTMODE_TEMPLATE, + sal_True, &rSelector ); + rHTMLWrt.OutCSS1_SfxItemSet( rItemSet, sal_False ); + } + + SfxItemSet aScriptItemSet( *rItemSet.GetPool(), + RES_CHRATR_FONT, RES_CHRATR_FONTSIZE, + RES_CHRATR_LANGUAGE, RES_CHRATR_POSTURE, + RES_CHRATR_WEIGHT, RES_CHRATR_WEIGHT, + RES_CHRATR_CJK_FONT, RES_CHRATR_CTL_WEIGHT, + 0 ); + aScriptItemSet.Put( rItemSet ); + + String aNewSelector( aSelector ); + aNewSelector.AppendAscii( RTL_CONSTASCII_STRINGPARAM(".western") ); + aNewSelector.Append( aPseudo ); + { + SwCSS1OutMode aMode( rHTMLWrt, CSS1_OUTMODE_WESTERN|CSS1_OUTMODE_RULE|CSS1_OUTMODE_TEMPLATE, + sal_True, &aNewSelector ); + rHTMLWrt.OutCSS1_SfxItemSet( aScriptItemSet, sal_False ); + } + + aNewSelector = aSelector; + aNewSelector.AppendAscii( RTL_CONSTASCII_STRINGPARAM(".cjk") ); + aNewSelector.Append( aPseudo ); + { + SwCSS1OutMode aMode( rHTMLWrt, CSS1_OUTMODE_CJK|CSS1_OUTMODE_RULE|CSS1_OUTMODE_TEMPLATE, + sal_True, &aNewSelector ); + rHTMLWrt.OutCSS1_SfxItemSet( aScriptItemSet, sal_False ); + } + + aNewSelector = aSelector; + aNewSelector.AppendAscii( RTL_CONSTASCII_STRINGPARAM(".ctl") ); + aNewSelector.Append( aPseudo ); + { + SwCSS1OutMode aMode( rHTMLWrt, CSS1_OUTMODE_CTL|CSS1_OUTMODE_RULE|CSS1_OUTMODE_TEMPLATE, + sal_True, &aNewSelector ); + rHTMLWrt.OutCSS1_SfxItemSet( aScriptItemSet, sal_False ); + } + } + else + { + // If ther are script dependencies and we are derived from a tag, + // when we have to export a style dependent class for all + // scripts + String aNewSelector( aSelector ); + aNewSelector.AppendAscii( RTL_CONSTASCII_STRINGPARAM("-western") ); + aNewSelector.Append( aPseudo ); + { + SwCSS1OutMode aMode( rHTMLWrt, CSS1_OUTMODE_WESTERN|CSS1_OUTMODE_RULE|CSS1_OUTMODE_TEMPLATE, + sal_True, &aNewSelector ); + rHTMLWrt.OutCSS1_SfxItemSet( rItemSet, sal_False ); + } + + aNewSelector = aSelector; + aNewSelector.AppendAscii( RTL_CONSTASCII_STRINGPARAM("-cjk") ); + aNewSelector.Append( aPseudo ); + { + SwCSS1OutMode aMode( rHTMLWrt, CSS1_OUTMODE_CJK|CSS1_OUTMODE_RULE|CSS1_OUTMODE_TEMPLATE, + sal_True, &aNewSelector ); + rHTMLWrt.OutCSS1_SfxItemSet( rItemSet, sal_False ); + } + + aNewSelector = aSelector; + aNewSelector.AppendAscii( RTL_CONSTASCII_STRINGPARAM("-ctl") ); + aNewSelector.Append( aPseudo ); + { + SwCSS1OutMode aMode( rHTMLWrt, CSS1_OUTMODE_CTL|CSS1_OUTMODE_RULE|CSS1_OUTMODE_TEMPLATE, + sal_True, &aNewSelector ); + rHTMLWrt.OutCSS1_SfxItemSet( rItemSet, sal_False ); + } + } + } + else + { + // If there are no script dependencies, when all items are + // exported in one step. For hyperlinks only, a script information + // must be there, because these two chr formats don't support + // script dependencies by now. + SwCSS1OutMode aMode( rHTMLWrt, + rHTMLWrt.nCSS1Script|CSS1_OUTMODE_RULE|CSS1_OUTMODE_TEMPLATE, + sal_True, &rSelector ); + rHTMLWrt.OutCSS1_SfxItemSet( rItemSet, sal_False ); + } + + return bScriptDependent; +} + +static void OutCSS1DropCapRule( + SwHTMLWriter& rHTMLWrt, const String& rSelector, + const SwFmtDrop& rDrop, sal_Bool bHasClass, + sal_Bool bHasScriptDependencies ) +{ + const SwCharFmt *pDCCharFmt = rDrop.GetCharFmt(); + if( (bHasScriptDependencies && bHasClass) || + (pDCCharFmt && SwHTMLWriter::HasScriptDependentItems( pDCCharFmt->GetAttrSet(), sal_False ) ) ) + { + String aSelector( rSelector ); + + String aPseudo; + xub_StrLen nPos = aSelector.SearchBackward( ':' ); + if( STRING_NOTFOUND != nPos ) + { + aPseudo = aSelector.Copy( nPos ); + aSelector.Erase( nPos ); + } + + if( !bHasClass ) + { + // If we are exporting styles for a tag we have to export a tag + // rule for all properties that aren't style dependent and + // some class rule for the additional style dependen properties + { + SwCSS1OutMode aMode( rHTMLWrt, CSS1_OUTMODE_NO_SCRIPT|CSS1_OUTMODE_RULE|CSS1_OUTMODE_DROPCAP, + sal_True, &rSelector ); + OutCSS1_SwFmtDropAttrs( rHTMLWrt, rDrop ); + } + + SfxItemSet aScriptItemSet( rHTMLWrt.pDoc->GetAttrPool(), + RES_CHRATR_FONT, RES_CHRATR_FONTSIZE, + RES_CHRATR_LANGUAGE, RES_CHRATR_POSTURE, + RES_CHRATR_WEIGHT, RES_CHRATR_WEIGHT, + RES_CHRATR_CJK_FONT, RES_CHRATR_CTL_WEIGHT, + 0 ); + if( pDCCharFmt ) + aScriptItemSet.Set( pDCCharFmt->GetAttrSet(), sal_True ); + + String aNewSelector( aSelector ); + aNewSelector.AppendAscii( RTL_CONSTASCII_STRINGPARAM(".western") ); + aNewSelector.Append( aPseudo ); + { + SwCSS1OutMode aMode( rHTMLWrt, CSS1_OUTMODE_WESTERN|CSS1_OUTMODE_RULE|CSS1_OUTMODE_DROPCAP, + sal_True, &aNewSelector ); + OutCSS1_SwFmtDropAttrs( rHTMLWrt, rDrop, &aScriptItemSet ); + } + + aNewSelector = aSelector; + aNewSelector.AppendAscii( RTL_CONSTASCII_STRINGPARAM(".cjk") ); + aNewSelector.Append( aPseudo ); + { + SwCSS1OutMode aMode( rHTMLWrt, CSS1_OUTMODE_CJK|CSS1_OUTMODE_RULE|CSS1_OUTMODE_DROPCAP, + sal_True, &aNewSelector ); + OutCSS1_SwFmtDropAttrs( rHTMLWrt, rDrop, &aScriptItemSet ); + } + + aNewSelector = aSelector; + aNewSelector.AppendAscii( RTL_CONSTASCII_STRINGPARAM(".ctl") ); + aNewSelector.Append( aPseudo ); + { + SwCSS1OutMode aMode( rHTMLWrt, CSS1_OUTMODE_CTL|CSS1_OUTMODE_RULE|CSS1_OUTMODE_DROPCAP, + sal_True, &aNewSelector ); + OutCSS1_SwFmtDropAttrs( rHTMLWrt, rDrop, &aScriptItemSet ); + } + } + else + { + // If ther are script dependencies and we are derived from a tag, + // when we have to export a style dependent class for all + // scripts + String aNewSelector( aSelector ); + aNewSelector.AppendAscii( RTL_CONSTASCII_STRINGPARAM("-western") ); + aNewSelector.Append( aPseudo ); + { + SwCSS1OutMode aMode( rHTMLWrt, CSS1_OUTMODE_WESTERN|CSS1_OUTMODE_RULE|CSS1_OUTMODE_DROPCAP, + sal_True, &aNewSelector ); + OutCSS1_SwFmtDropAttrs( rHTMLWrt, rDrop ); + } + + aNewSelector = aSelector; + aNewSelector.AppendAscii( RTL_CONSTASCII_STRINGPARAM("-cjk") ); + aNewSelector.Append( aPseudo ); + { + SwCSS1OutMode aMode( rHTMLWrt, CSS1_OUTMODE_CJK|CSS1_OUTMODE_RULE|CSS1_OUTMODE_DROPCAP, + sal_True, &aNewSelector ); + OutCSS1_SwFmtDropAttrs( rHTMLWrt, rDrop ); + } + + aNewSelector = aSelector; + aNewSelector.AppendAscii( RTL_CONSTASCII_STRINGPARAM("-ctl") ); + aNewSelector.Append( aPseudo ); + { + SwCSS1OutMode aMode( rHTMLWrt, CSS1_OUTMODE_CTL|CSS1_OUTMODE_RULE|CSS1_OUTMODE_DROPCAP, + sal_True, &aNewSelector ); + OutCSS1_SwFmtDropAttrs( rHTMLWrt, rDrop ); + } + } + } + else + { + // If there are no script dependencies, when all items are + // exported in one step. For hyperlinks only, a script information + // must be there, because these two chr formats don't support + // script dependencies by now. + SwCSS1OutMode aMode( rHTMLWrt, + rHTMLWrt.nCSS1Script|CSS1_OUTMODE_RULE|CSS1_OUTMODE_DROPCAP, + sal_True, &rSelector ); + OutCSS1_SwFmtDropAttrs( rHTMLWrt, rDrop ); + } +} + +static Writer& OutCSS1_SwFmt( Writer& rWrt, const SwFmt& rFmt, + IDocumentStylePoolAccess/*SwDoc*/ *pDoc, SwDoc *pTemplate ) +{ + SwHTMLWriter & rHTMLWrt = (SwHTMLWriter&)rWrt; + + sal_Bool bCharFmt = sal_False; + switch( rFmt.Which() ) + { + case RES_CHRFMT: + bCharFmt = sal_True; + break; + + case RES_TXTFMTCOLL: + case RES_CONDTXTFMTCOLL: + // diese Vorlagen-Typen koennen exportiert werden + break; + + default: + // und diese nicht + return rWrt; + } + + // den Selector und die auszugebende Attr-Set-Tiefe ermitteln + String aSelector; + sal_uInt16 nRefPoolId = 0; + sal_uInt16 nDeep = GetCSS1Selector( &rFmt, aSelector, nRefPoolId ); + if( !nDeep ) + return rWrt; // von keiner HTML-Vorlage abgeleitet + + sal_uInt16 nPoolFmtId = rFmt.GetPoolFmtId(); + + // Den auszugebenden Attr-Set bestimmen. Hier muessen 3 Faelle + // unterschieden werden: + // - HTML-Tag-Vorlagen (nDeep==USHRT_MAX): + // Es werden die Attrs ausgegeben + // - die in der Vorlage gesetzt sind, aber nicht im Original aus + // der HTML-Vorlage + // - die Default-Attrs fuer die Attrs, die im Original aus der + // HTML-Vorlage gesetzt sind, aber nicht in der vorliegeden Vorlage. + // - direkt von HTML-Vorlagen abgeleitete Vorlagen (nDeep==1): + // Es weren nur die Attribute des Vorlagen-Item-Set ohne seine + // Parents ausgegeben. + // - indirekt von HTML-Tag-Vorlagen abgeleitete Vorlagen (nDeep>1) + // Es werden die Attribute des Vorlagen-Item-Sets inkl. seiner Parents, + // aber ohne die Attribute, die in der HTML-Tag-Vorlage gesetzt sind, + // ausgegeben. + + // einen Item-Set mit allen Attributen aus der Vorlage anlegen + // (ausser fuer nDeep==1) + const SfxItemSet& rFmtItemSet = rFmt.GetAttrSet(); + SfxItemSet aItemSet( *rFmtItemSet.GetPool(), rFmtItemSet.GetRanges() ); + aItemSet.Set( rFmtItemSet, sal_True ); // Was nDeep!=1 that is not working + // for script dependent items buts should + // not make a deifference for any other + + sal_Bool bSetDefaults = sal_True, bClearSame = sal_True; + const SwFmt *pRefFmt = 0; + const SwFmt *pRefFmtScript = 0; + switch( nDeep ) + { + case CSS1_FMT_ISTAG: + pRefFmt = SwHTMLWriter::GetTemplateFmt( nRefPoolId, pTemplate ); + break; + case CSS1_FMT_CMPREF: + pRefFmt = SwHTMLWriter::GetTemplateFmt( nRefPoolId, pDoc ); + pRefFmtScript = SwHTMLWriter::GetTemplateFmt( nRefPoolId, pTemplate ); + bClearSame = sal_False; + break; + default: + pRefFmt = SwHTMLWriter::GetParentFmt( rFmt, nDeep ); + pRefFmtScript = SwHTMLWriter::GetTemplateFmt( nRefPoolId, pTemplate ); + bSetDefaults = sal_False; + break; + } + + if( pRefFmt ) + { + // Den Item-Set der Referenz-Vorlage (inkl. seiner Parents) vom + // ItemSet abziehen + SwHTMLWriter::SubtractItemSet( aItemSet, pRefFmt->GetAttrSet(), + bSetDefaults, bClearSame, + pRefFmtScript + ? &pRefFmtScript->GetAttrSet() + : 0 ); + + if( !bCharFmt ) + { + const SvxULSpaceItem& rULItem = pRefFmt->GetULSpace(); + rHTMLWrt.nDfltTopMargin = rULItem.GetUpper(); + rHTMLWrt.nDfltBottomMargin = rULItem.GetLower(); + } + } + else if( CSS1_FMT_ISTAG==nDeep && !bCharFmt ) + { + // die Default-Abstaende nach oben und unten setzen (fuer den + // Fall, dass es keine Vorlage als Referenz gibt) + rHTMLWrt.nDfltTopMargin = 0; + rHTMLWrt.nDfltBottomMargin = HTML_PARSPACE; + if( USER_FMT & nPoolFmtId ) + { + // Benutzer-Vorlagen + const String& rNm = rFmt.GetName(); + switch( rNm.GetChar(0) ) + { + case 'D': if( rNm.EqualsAscii("DD 1") || rNm.EqualsAscii("DT 1") ) + rHTMLWrt.nDfltBottomMargin = 0; + break; + case 'L': if(rNm.EqualsAscii(OOO_STRING_SVTOOLS_HTML_listing) ) + rHTMLWrt.nDfltBottomMargin = 0; + break; + case 'P': if( rNm.EqualsAscii(OOO_STRING_SVTOOLS_HTML_preformtxt) ) + rHTMLWrt.nDfltBottomMargin = 0; + break; + case 'X': if( rNm.EqualsAscii(OOO_STRING_SVTOOLS_HTML_xmp) ) + rHTMLWrt.nDfltBottomMargin = 0; + break; + } + } + else + { + // Pool-Vorlagen + switch( nPoolFmtId ) + { + case RES_POOLCOLL_HEADLINE1: + case RES_POOLCOLL_HEADLINE2: + case RES_POOLCOLL_HEADLINE3: + case RES_POOLCOLL_HEADLINE4: + case RES_POOLCOLL_HEADLINE5: + case RES_POOLCOLL_HEADLINE6: + rHTMLWrt.nDfltTopMargin = HTML_HEADSPACE; + break; + case RES_POOLCOLL_SENDADRESS: + case RES_POOLCOLL_HTML_DT: + case RES_POOLCOLL_HTML_DD: + case RES_POOLCOLL_HTML_PRE: + rHTMLWrt.nDfltBottomMargin = 0; + break; + } + } + } + + // wo nicht auszugeben ist ... + if( !aItemSet.Count() ) + return rWrt; + + // There is no support for script dependent hyperlinks by now. + sal_Bool bCheckForPseudo = sal_False; + if( bCharFmt && + (RES_POOLCHR_INET_NORMAL==nRefPoolId || + RES_POOLCHR_INET_VISIT==nRefPoolId) ) + bCheckForPseudo = sal_True; + + + // jetzt die Attribute (inkl. Selektor) ausgeben + sal_Bool bHasScriptDependencies = sal_False; + if( OutCSS1Rule( rHTMLWrt, aSelector, aItemSet, CSS1_FMT_ISTAG != nDeep, + bCheckForPseudo ) ) + { + if( bCharFmt ) + rHTMLWrt.aScriptTextStyles.Insert( new String( rFmt.GetName() ) ); + else + { + if( nPoolFmtId==RES_POOLCOLL_TEXT ) + rHTMLWrt.aScriptParaStyles.Insert + (new String( pDoc->GetTxtCollFromPool + ( RES_POOLCOLL_STANDARD, false )->GetName() + ) ); + rHTMLWrt.aScriptParaStyles.Insert( new String( rFmt.GetName() ) ); + } + bHasScriptDependencies = sal_True; + } + + if( nPoolFmtId==RES_POOLCOLL_TEXT && !rHTMLWrt.bFirstCSS1Property ) + rHTMLWrt.bPoolCollTextModified = sal_True; + + // Drop-Caps ausgeben + const SfxPoolItem *pItem; + if( rHTMLWrt.IsHTMLMode(HTMLMODE_DROPCAPS) && + SFX_ITEM_SET==aItemSet.GetItemState( RES_PARATR_DROP, sal_False, &pItem )) + { + String sOut( aSelector ); + sOut.Append( ':'); + sOut.AppendAscii( sCSS1_first_letter ); + const SwFmtDrop *pDrop = (const SwFmtDrop *)pItem; + OutCSS1DropCapRule( rHTMLWrt, sOut, *pDrop, CSS1_FMT_ISTAG != nDeep, bHasScriptDependencies ); + } + + return rWrt; +} + +static Writer& OutCSS1_SwPageDesc( Writer& rWrt, const SwPageDesc& rPageDesc, + IDocumentStylePoolAccess/*SwDoc*/ *pDoc, SwDoc *pTemplate, + sal_uInt16 nRefPoolId, sal_Bool bExtRef, + sal_Bool bPseudo ) +{ + SwHTMLWriter & rHTMLWrt = (SwHTMLWriter&)rWrt; + + const SwPageDesc* pRefPageDesc = 0; + if( !bExtRef ) + pRefPageDesc = pDoc->GetPageDescFromPool( nRefPoolId, false ); + else if( pTemplate ) + pRefPageDesc = pTemplate->GetPageDescFromPool( nRefPoolId, false ); + + String aSelector( '@' ); + aSelector.AppendAscii( sCSS1_page ); + + if( bPseudo ) + { + const sal_Char *pPseudo = 0; + switch( rPageDesc.GetPoolFmtId() ) + { + case RES_POOLPAGE_FIRST: pPseudo = sCSS1_first; break; + case RES_POOLPAGE_LEFT: pPseudo = sCSS1_left; break; + case RES_POOLPAGE_RIGHT: pPseudo = sCSS1_right; break; + } + if( pPseudo ) + { + aSelector.Append( ':' ); + aSelector.AppendAscii( pPseudo ); + } + } + + SwCSS1OutMode aMode( rHTMLWrt, CSS1_OUTMODE_RULE_ON|CSS1_OUTMODE_TEMPLATE, + sal_True, &aSelector ); + + // Die Groesse: Wenn sie sich nur durch das Landscape-Flag unterscheidet, + // wird nur Portrait oder Landscape exportiert. Sonst wird die Groesse + // exportiert. + sal_Bool bRefLandscape = pRefPageDesc ? pRefPageDesc->GetLandscape() : sal_False; + Size aRefSz; + const Size& rSz = rPageDesc.GetMaster().GetFrmSize().GetSize(); + if( pRefPageDesc ) + { + aRefSz = pRefPageDesc->GetMaster().GetFrmSize().GetSize(); + if( bRefLandscape != rPageDesc.GetLandscape() ) + { + long nTmp = aRefSz.Height(); + aRefSz.Height() = aRefSz.Width(); + aRefSz.Width() = nTmp; + } + } + + // Boeser uebler Hack: Auf der Seiten-Tabpage gibt es leichte + // Rundungsfehler bei der Seitengroesse. Unter anderem wegen bug + // 25535 wird dummerweise auch noch immer Size-Item vom Dialog geputtet, + // auch wenn man gar nichts geaendert hat. Folge: Sobald man einmal im + // Seiten-Dialog war und ihn mit OK verlassen hat, bekommt man eine + // neue Seitengroesse, die dann hier exportiert wuerde. Um das + // vermeiden erlauben wir hier kleine Abweichungen. + if( Abs( rSz.Width() - aRefSz.Width() ) <= 2 && + Abs( rSz.Height() - aRefSz.Height() ) <= 2 ) + { + if( bRefLandscape != rPageDesc.GetLandscape() ) + { + rHTMLWrt.OutCSS1_PropertyAscii( sCSS1_P_size, + rPageDesc.GetLandscape() ? sCSS1_PV_landscape + : sCSS1_PV_portrait ); + } + } + else + { + ByteString sVal; + AddUnitPropertyValue( rSz.Width(), rHTMLWrt.GetCSS1Unit(), sVal ); + sVal += ' '; + AddUnitPropertyValue( rSz.Height(), rHTMLWrt.GetCSS1Unit(), sVal ); + rHTMLWrt.OutCSS1_PropertyAscii( sCSS1_P_size, sVal ); + } + + // Die Abstand-Attribute koennen auf gwohnte Weise exportiert werden + const SwFrmFmt &rMaster = rPageDesc.GetMaster(); + SfxItemSet aItemSet( *rMaster.GetAttrSet().GetPool(), + RES_LR_SPACE, RES_UL_SPACE ); + aItemSet.Set( rMaster.GetAttrSet(), sal_True ); + + if( pRefPageDesc ) + { + SwHTMLWriter::SubtractItemSet( aItemSet, + pRefPageDesc->GetMaster().GetAttrSet(), + sal_True ); + } + + OutCSS1_SvxULSpace_SvxLRSpace( rWrt, aItemSet, sal_False ); + + // Wenn fuer einen Pseudo-Selektor keine Property ausgegeben wurde, muessen + // wir trotzdem etwas ausgeben, damit beim Import die entsprechende + // Vorlage angelegt wird. + if( rHTMLWrt.bFirstCSS1Property && bPseudo ) + { + rHTMLWrt.OutNewLine(); + ByteString sTmp( aSelector, rHTMLWrt.eDestEnc ); + rWrt.Strm() << sTmp.GetBuffer() << " {"; + rHTMLWrt.bFirstCSS1Property = sal_False; + } + + if( !rHTMLWrt.bFirstCSS1Property ) + rWrt.Strm() << sCSS1_rule_end; + + return rWrt; +} + +static Writer& OutCSS1_SwFtnInfo( Writer& rWrt, const SwEndNoteInfo& rInfo, + SwDoc *pDoc, sal_uInt16 nNotes, sal_Bool bEndNote ) +{ + SwHTMLWriter & rHTMLWrt = (SwHTMLWriter&)rWrt; + + String aSelector; + + if( nNotes > 0 ) + { + aSelector.AssignAscii( OOO_STRING_SVTOOLS_HTML_anchor ); + aSelector.Append( '.'); + aSelector.AppendAscii( bEndNote ? OOO_STRING_SVTOOLS_HTML_sdendnote_anc + : OOO_STRING_SVTOOLS_HTML_sdfootnote_anc ); + SwCSS1OutMode aMode( rHTMLWrt, CSS1_OUTMODE_RULE|CSS1_OUTMODE_TEMPLATE, + sal_True, &aSelector ); + rHTMLWrt.OutCSS1_PropertyAscii( sCSS1_P_font_size, + sHTML_FTN_fontheight ); + rHTMLWrt.Strm() << sCSS1_rule_end; + } + + const SwCharFmt *pSymCharFmt = rInfo.GetCharFmt( *pDoc ); + if( pSymCharFmt ) + { + const SfxItemSet& rFmtItemSet = pSymCharFmt->GetAttrSet(); + SfxItemSet aItemSet( *rFmtItemSet.GetPool(), rFmtItemSet.GetRanges() ); + aItemSet.Set( rFmtItemSet, sal_True ); + + // Wenn es Fuss- bzw. Endnoten gibt, dann muessen alles Attribute + // ausgegeben werden, damit Netscape das Dokument richtig anzeigt. + // Anderenfalls genuegt es, die Unterschiede zur Fuss-/Endnoten + // Vorlage rauszuschreiben. + if( nNotes == 0 && rHTMLWrt.pTemplate ) + { + SwFmt *pRefFmt = rHTMLWrt.pTemplate->GetCharFmtFromPool( + static_cast< sal_uInt16 >(bEndNote ? RES_POOLCHR_ENDNOTE : RES_POOLCHR_FOOTNOTE) ); + if( pRefFmt ) + SwHTMLWriter::SubtractItemSet( aItemSet, pRefFmt->GetAttrSet(), + sal_True ); + } + if( aItemSet.Count() ) + { + aSelector.AssignAscii( OOO_STRING_SVTOOLS_HTML_anchor ); + aSelector.Append( '.'); + aSelector.AppendAscii( bEndNote ? OOO_STRING_SVTOOLS_HTML_sdendnote_sym + : OOO_STRING_SVTOOLS_HTML_sdfootnote_sym ); + if( OutCSS1Rule( rHTMLWrt, aSelector, aItemSet, sal_True, sal_False )) + rHTMLWrt.aScriptTextStyles.Insert( new String( pSymCharFmt->GetName() ) ); + } + } + + return rWrt; +} + +Writer& OutCSS1_BodyTagStyleOpt( Writer& rWrt, const SfxItemSet& rItemSet, + String aEmbBGGrfName ) +{ + SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt; + + SwCSS1OutMode aMode( rHTMLWrt, CSS1_OUTMODE_STYLE_OPT_ON | + CSS1_OUTMODE_ENCODE|CSS1_OUTMODE_BODY ); + + + // Es werden nur die Attribute der Seiten-Vorlage ausgegeben. + // Die Attribute der Standard-Absatz-Vorlage werden schon beim + // Export der Absatz-Vorlagen beruecksichtigt. + + const SfxPoolItem *pItem; + if( SFX_ITEM_SET == rItemSet.GetItemState( RES_BACKGROUND, sal_False, + &pItem ) ) + { + OutCSS1_SvxBrush( rWrt, *pItem, CSS1_BACKGROUND_PAGE, + &aEmbBGGrfName ); + } + + if( SFX_ITEM_SET == rItemSet.GetItemState( RES_BOX, sal_False, + &pItem )) + { + OutCSS1_SvxBox( rWrt, *pItem ); + } + + if( !rHTMLWrt.bFirstCSS1Property ) + { + // wenn eine Property als Bestandteil einer Style-Option + // ausgegeben wurde, muss die Optiomn noch beendet werden + rWrt.Strm() << '\"'; + } + + return rWrt; +} + +Writer& OutCSS1_ParaTagStyleOpt( Writer& rWrt, const SfxItemSet& rItemSet ) +{ + SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt; + + SwCSS1OutMode aMode( rHTMLWrt, rHTMLWrt.nCSS1Script|CSS1_OUTMODE_STYLE_OPT | + CSS1_OUTMODE_ENCODE|CSS1_OUTMODE_PARA ); + rHTMLWrt.OutCSS1_SfxItemSet( rItemSet, sal_False ); + + return rWrt; +} + +Writer& OutCSS1_HintSpanTag( Writer& rWrt, const SfxPoolItem& rHt ) +{ + SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt; + + SwCSS1OutMode aMode( rHTMLWrt, CSS1_OUTMODE_SPAN_TAG | + CSS1_OUTMODE_ENCODE|CSS1_OUTMODE_HINT ); + + Out( aCSS1AttrFnTab, rHt, rWrt ); + + if( !rHTMLWrt.bFirstCSS1Property && rHTMLWrt.bTagOn ) + rWrt.Strm() << sCSS1_span_tag_end; + + return rWrt; +} + +Writer& OutCSS1_HintStyleOpt( Writer& rWrt, const SfxPoolItem& rHt ) +{ + SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt; + + SwCSS1OutMode aMode( rHTMLWrt, CSS1_OUTMODE_STYLE_OPT_ON | + CSS1_OUTMODE_ENCODE| + CSS1_OUTMODE_HINT ); + + Out( aCSS1AttrFnTab, rHt, rWrt ); + + if( !rHTMLWrt.bFirstCSS1Property ) + rWrt.Strm() << '\"'; + + return rWrt; +} + +// Wrapper fuer die Ausgabe von Tabellen-Hintergruenden +Writer& OutCSS1_TableBGStyleOpt( Writer& rWrt, const SfxPoolItem& rHt ) +{ + SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt; + + SwCSS1OutMode aMode( rHTMLWrt, CSS1_OUTMODE_STYLE_OPT_ON | + CSS1_OUTMODE_ENCODE| + CSS1_OUTMODE_TABLEBOX ); + OutCSS1_SvxBrush( rWrt, rHt, CSS1_BACKGROUND_TABLE, 0 ); + + if( !rHTMLWrt.bFirstCSS1Property ) + rWrt.Strm() << '\"'; + + return rWrt; +} + + +Writer& OutCSS1_NumBulListStyleOpt( Writer& rWrt, const SwNumRule& rNumRule, + sal_uInt8 nLevel ) +{ + SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt; + + SwCSS1OutMode aMode( rHTMLWrt, CSS1_OUTMODE_STYLE_OPT | + CSS1_OUTMODE_ENCODE|CSS1_OUTMODE_PARA ); + + const SwNumFmt& rNumFmt = rNumRule.Get( nLevel ); + + long nLSpace = rNumFmt.GetAbsLSpace(); + long nFirstLineOffset = rNumFmt.GetFirstLineOffset(); + long nDfltFirstLineOffset = HTML_NUMBUL_INDENT; + if( nLevel > 0 ) + { + const SwNumFmt& rPrevNumFmt = rNumRule.Get( nLevel-1 ); + nLSpace -= rPrevNumFmt.GetAbsLSpace(); + nDfltFirstLineOffset = rPrevNumFmt.GetFirstLineOffset(); + } + + if( rHTMLWrt.IsHTMLMode(HTMLMODE_LSPACE_IN_NUMBUL) && + nLSpace != HTML_NUMBUL_MARGINLEFT ) + rHTMLWrt.OutCSS1_UnitProperty( sCSS1_P_margin_left, nLSpace ); + + if( rHTMLWrt.IsHTMLMode(HTMLMODE_FRSTLINE_IN_NUMBUL) && + nFirstLineOffset != nDfltFirstLineOffset ) + rHTMLWrt.OutCSS1_UnitProperty( sCSS1_P_text_indent, nFirstLineOffset ); + + if( !rHTMLWrt.bFirstCSS1Property ) + rWrt.Strm() << '\"'; + + return rWrt; +} + +//----------------------------------------------------------------------- + +void SwHTMLWriter::OutCSS1_FrmFmtOptions( const SwFrmFmt& rFrmFmt, + sal_uInt32 nFrmOpts, + const SdrObject *pSdrObj, + const SfxItemSet *pItemSet ) +{ + SwCSS1OutMode aMode( *this, CSS1_OUTMODE_STYLE_OPT_ON | + CSS1_OUTMODE_ENCODE| + CSS1_OUTMODE_FRAME ); + + const SwFmtHoriOrient& rHoriOri = rFrmFmt.GetHoriOrient(); + SvxLRSpaceItem aLRItem( rFrmFmt.GetLRSpace() ); + SvxULSpaceItem aULItem( rFrmFmt.GetULSpace() ); + if( nFrmOpts & HTML_FRMOPT_S_ALIGN ) + { + const SwFmtAnchor& rAnchor = rFrmFmt.GetAnchor(); + switch( rAnchor.GetAnchorId() ) + { + case FLY_AT_PARA: + case FLY_AT_CHAR: + if( text::RelOrientation::FRAME == rHoriOri.GetRelationOrient() || + text::RelOrientation::PRINT_AREA == rHoriOri.GetRelationOrient() ) + { + if( !(nFrmOpts & HTML_FRMOPT_ALIGN) ) + { + // float + const sal_Char *pStr = text::HoriOrientation::RIGHT==rHoriOri.GetHoriOrient() + ? sCSS1_PV_right + : sCSS1_PV_left; + OutCSS1_PropertyAscii( sCSS1_P_float, pStr ); + } + break; + } + + case FLY_AT_PAGE: + case FLY_AT_FLY: + { + // position + OutCSS1_PropertyAscii( sCSS1_P_position, sCSS1_PV_absolute ); + + // Fuer top/left muessen die Abstaende des Rahmens von + // der Position abgezogen werden, da sie in CSS1 noch + // zur Position addiert werden. + // Das funktioniert auch fuer automatisch ausgerichtete + // Rahmen, obwohl der Abstand da ja auch im Writer noch + // addiert wird. Denn auch in diesem Fall enthalten + // die Orient-Attribute die korrekte Position + + // top + long nXPos=0, nYPos=0; + sal_Bool bOutXPos = sal_False, bOutYPos = sal_False; + if( RES_DRAWFRMFMT == rFrmFmt.Which() ) + { + ASSERT( pSdrObj, "Kein SdrObject uebergeben. Ineffizient" ); + if( !pSdrObj ) + pSdrObj = rFrmFmt.FindSdrObject(); + ASSERT( pSdrObj, "Wo ist das SdrObject" ); + if( pSdrObj ) + { + Point aPos( pSdrObj->GetRelativePos() ); + nXPos = aPos.A(); + nYPos = aPos.B(); + } + bOutXPos = bOutYPos = sal_True; + } + else + { + bOutXPos = text::RelOrientation::CHAR != rHoriOri.GetRelationOrient(); + nXPos = text::HoriOrientation::NONE == rHoriOri.GetHoriOrient() + ? rHoriOri.GetPos() : 0; + + const SwFmtVertOrient& rVertOri = rFrmFmt.GetVertOrient(); + bOutYPos = text::RelOrientation::CHAR != rVertOri.GetRelationOrient(); + nYPos = text::VertOrientation::NONE == rVertOri.GetVertOrient() + ? rVertOri.GetPos() : 0; + } + + if( bOutYPos ) + { + if( IsHTMLMode( HTMLMODE_FLY_MARGINS) ) + { + nYPos -= aULItem.GetUpper(); + if( nYPos < 0 ) + { + aULItem.SetUpper( (sal_uInt16)(aULItem.GetUpper() + nYPos) ); + nYPos = 0; + } + } + + OutCSS1_UnitProperty( sCSS1_P_top, nYPos ); + } + + if( bOutXPos ) + { + // left + if( IsHTMLMode( HTMLMODE_FLY_MARGINS) ) + { + nXPos -= aLRItem.GetLeft(); + if( nXPos < 0 ) + { + aLRItem.SetLeft( (sal_uInt16)(aLRItem.GetLeft() + nXPos) ); + nXPos = 0; + } + } + + OutCSS1_UnitProperty( sCSS1_P_left, nXPos ); + } + } + break; + + default: + ; + } + } + + // width/height + if( nFrmOpts & HTML_FRMOPT_S_SIZE ) + { + if( RES_DRAWFRMFMT == rFrmFmt.Which() ) + { + ASSERT( pSdrObj, "Kein SdrObject uebergeben. Ineffizient" ); + if( !pSdrObj ) + pSdrObj = rFrmFmt.FindSdrObject(); + ASSERT( pSdrObj, "Wo ist das SdrObject" ); + if( pSdrObj ) + { + Size aTwipSz( pSdrObj->GetLogicRect().GetSize() ); + if( nFrmOpts & HTML_FRMOPT_S_WIDTH ) + { + if( nFrmOpts & HTML_FRMOPT_S_PIXSIZE ) + OutCSS1_PixelProperty( sCSS1_P_width, aTwipSz.Width(), + sal_False ); + else + OutCSS1_UnitProperty( sCSS1_P_width, aTwipSz.Width() ); + } + if( nFrmOpts & HTML_FRMOPT_S_HEIGHT ) + { + if( nFrmOpts & HTML_FRMOPT_S_PIXSIZE ) + OutCSS1_PixelProperty( sCSS1_P_height, aTwipSz.Height(), + sal_True ); + else + OutCSS1_UnitProperty( sCSS1_P_height, aTwipSz.Height() ); + } + } + } + else + { + ASSERT( HTML_FRMOPT_ABSSIZE & nFrmOpts, + "Absolute Groesse wird exportiert" ); + ASSERT( HTML_FRMOPT_ANYSIZE & nFrmOpts, + "Jede Groesse wird exportiert" ); + sal_uInt16 nMode = 0; + if( nFrmOpts & HTML_FRMOPT_S_WIDTH ) + nMode |= CSS1_FRMSIZE_WIDTH; + if( nFrmOpts & HTML_FRMOPT_S_HEIGHT ) + nMode |= (CSS1_FRMSIZE_MINHEIGHT|CSS1_FRMSIZE_FIXHEIGHT); + if( nFrmOpts & HTML_FRMOPT_S_PIXSIZE ) + nMode |= CSS1_FRMSIZE_PIXEL; + + OutCSS1_SwFmtFrmSize( *this, rFrmFmt.GetFrmSize(), nMode ); + } + } + + const SfxItemSet& rItemSet = rFrmFmt.GetAttrSet(); + // margin-* + if( (nFrmOpts & HTML_FRMOPT_S_SPACE) && + IsHTMLMode( HTMLMODE_FLY_MARGINS) ) + { + const SvxLRSpaceItem *pLRItem = 0; + const SvxULSpaceItem *pULItem = 0; + if( SFX_ITEM_SET == rItemSet.GetItemState( RES_LR_SPACE, sal_True ) ) + pLRItem = &aLRItem; + if( SFX_ITEM_SET == rItemSet.GetItemState( RES_UL_SPACE, sal_True ) ) + pULItem = &aULItem; + if( pLRItem || pULItem ) + OutCSS1_SvxULSpace_SvxLRSpace( *this, pULItem, pLRItem ); + } + + // border + if( nFrmOpts & HTML_FRMOPT_S_BORDER ) + { + const SfxPoolItem* pItem; + if( nFrmOpts & HTML_FRMOPT_S_NOBORDER ) + OutCSS1_SvxBox( *this, rFrmFmt.GetBox() ); + else if( SFX_ITEM_SET==rItemSet.GetItemState( RES_BOX, sal_True, &pItem ) ) + OutCSS1_SvxBox( *this, *pItem ); + } + + // background (wenn, dann muss auch eine Farbe ausgegeben werden) + if( nFrmOpts & HTML_FRMOPT_S_BACKGROUND ) + OutCSS1_FrmFmtBackground( rFrmFmt ); + + if( pItemSet ) + OutCSS1_SfxItemSet( *pItemSet, sal_False ); + + if( !bFirstCSS1Property ) + Strm() << '\"'; +} + +void SwHTMLWriter::OutCSS1_TableFrmFmtOptions( const SwFrmFmt& rFrmFmt ) +{ + SwCSS1OutMode aMode( *this, CSS1_OUTMODE_STYLE_OPT_ON | + CSS1_OUTMODE_ENCODE| + CSS1_OUTMODE_TABLE ); + + const SfxPoolItem *pItem; + const SfxItemSet& rItemSet = rFrmFmt.GetAttrSet(); + if( SFX_ITEM_SET==rItemSet.GetItemState( RES_BACKGROUND, sal_False, &pItem ) ) + OutCSS1_SvxBrush( *this, *pItem, CSS1_BACKGROUND_TABLE, 0 ); + + if( IsHTMLMode( HTMLMODE_PRINT_EXT ) ) + OutCSS1_SvxFmtBreak_SwFmtPDesc_SvxFmtKeep( *this, rItemSet, sal_False ); + + if( SFX_ITEM_SET==rItemSet.GetItemState( RES_LAYOUT_SPLIT, sal_False, &pItem ) ) + OutCSS1_SwFmtLayoutSplit( *this, *pItem ); + + if( !bFirstCSS1Property ) + Strm() << '\"'; +} + +void SwHTMLWriter::OutCSS1_SectionFmtOptions( const SwFrmFmt& rFrmFmt ) +{ + SwCSS1OutMode aMode( *this, CSS1_OUTMODE_STYLE_OPT_ON | + CSS1_OUTMODE_ENCODE| + CSS1_OUTMODE_SECTION ); + + const SfxPoolItem *pItem; + const SfxItemSet& rItemSet = rFrmFmt.GetAttrSet(); + if( SFX_ITEM_SET==rItemSet.GetItemState( RES_BACKGROUND, sal_False, &pItem ) ) + OutCSS1_SvxBrush( *this, *pItem, CSS1_BACKGROUND_SECTION, 0 ); + + if( !bFirstCSS1Property ) + Strm() << '\"'; +} + +static sal_Bool OutCSS1_FrmFmtBrush( SwHTMLWriter& rWrt, + const SvxBrushItem& rBrushItem ) +{ + sal_Bool bWritten = sal_False; + /// OD 02.09.2002 #99657# + /// output brush of frame format, if its background color is not "no fill"/"auto fill" + /// or it has a background graphic. + if( rBrushItem.GetColor() != COL_TRANSPARENT || + 0 != rBrushItem.GetGraphicLink() || + 0 != rBrushItem.GetGraphicPos() ) + { + OutCSS1_SvxBrush( rWrt, rBrushItem, CSS1_BACKGROUND_FLY, 0 ); + bWritten = sal_True; + } + return bWritten; +} + +void SwHTMLWriter::OutCSS1_FrmFmtBackground( const SwFrmFmt& rFrmFmt ) +{ + // Wenn der Rahmen selbst einen Hintergrund hat, wird der ausgegeben. + if( OutCSS1_FrmFmtBrush( *this, rFrmFmt.GetBackground() ) ) + return; + + // Wenn der Rahmen nicht seitengebunden ist, wird sonst muss der + // Hintergrund vom Anker betrachtet + const SwFmtAnchor& rAnchor = rFrmFmt.GetAnchor(); + RndStdIds eAnchorId = rAnchor.GetAnchorId(); + const SwPosition *pAnchorPos = rAnchor.GetCntntAnchor(); + if (FLY_AT_PAGE != eAnchorId && pAnchorPos) + { + const SwNode& rNode = pAnchorPos->nNode.GetNode(); + if( rNode.IsCntntNode() ) + { + // Wenn der Rahmen in einem Content-Node verankert ist, + // wird der Hintergrund von Content-Node ausgegeben, wenn + // der einen hat. + if( OutCSS1_FrmFmtBrush( *this, + rNode.GetCntntNode()->GetSwAttrSet().GetBackground()) ) + return; + + // Sonst koennen wir evtl. auch in einer Tabelle stehen + const SwTableNode *pTableNd = rNode.FindTableNode(); + if( pTableNd ) + { + const SwStartNode *pBoxSttNd = rNode.FindTableBoxStartNode(); + const SwTableBox *pBox = + pTableNd->GetTable().GetTblBox( pBoxSttNd->GetIndex() ); + + // Wenn die Box einen Hintergrund hat, nehmen wir den. + if( OutCSS1_FrmFmtBrush( *this, + pBox->GetFrmFmt()->GetBackground() ) ) + return; + + // Sonst betrachten wir den der Lines + const SwTableLine *pLine = pBox->GetUpper(); + while( pLine ) + { + if( OutCSS1_FrmFmtBrush( *this, + pLine->GetFrmFmt()->GetBackground() ) ) + return; + pBox = pLine->GetUpper(); + pLine = pBox ? pBox->GetUpper() : 0; + } + + // Wenn da auch nichts war den der Tabelle. + if( OutCSS1_FrmFmtBrush( *this, + pTableNd->GetTable().GetFrmFmt()->GetBackground() ) ) + return; + } + + } + + // Wenn der Anker wieder in einem Fly-Frame steht, dann + // wird der Hintergrund des Fly-Frames ausgegeben. + const SwFrmFmt *pFrmFmt = rNode.GetFlyFmt(); + if( pFrmFmt ) + { + OutCSS1_FrmFmtBackground( *pFrmFmt ); + return; + } + } + + // Schliesslich bleibt noch der Hintergrund der Seite uebrig und als + // letzte Rettung das Item der Config. + ASSERT( pCurrPageDesc, "Keine Seiten-Vorlage gemerkt" ); + if( !OutCSS1_FrmFmtBrush( *this, + pCurrPageDesc->GetMaster().GetBackground() ) ) + { + Color aColor( COL_WHITE ); + + // Die Hintergrund-Farbe wird normalerweise nur in Browse-Mode + // benutzt. Wir benutzen si bei einem HTML-Dokument immer und + // bei einem Text-Dokument nur, wenn es im Browse-Mode angezeigt + // wird. + if( pDoc->get(IDocumentSettingAccess::HTML_MODE) || + pDoc->get(IDocumentSettingAccess::BROWSE_MODE)) + { + ViewShell *pVSh = 0; + pDoc->GetEditShell( &pVSh ); + if ( pVSh && + COL_TRANSPARENT != pVSh->GetViewOptions()->GetRetoucheColor().GetColor()) + aColor = pVSh->GetViewOptions()->GetRetoucheColor().GetColor(); + } + + ByteString sOut; + GetCSS1Color( aColor, sOut ); + OutCSS1_PropertyAscii( sCSS1_P_background, sOut ); + } +} + +//----------------------------------------------------------------------- + +static Writer& OutCSS1_SvxTxtLn_SvxCrOut_SvxBlink( Writer& rWrt, + const SvxUnderlineItem *pUItem, + const SvxOverlineItem *pOItem, + const SvxCrossedOutItem *pCOItem, + const SvxBlinkItem *pBItem ) +{ + SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt; + sal_Bool bNone = sal_False; + + const sal_Char *pUStr = 0; + if( pUItem ) + { + switch( pUItem->GetLineStyle() ) + { + case UNDERLINE_NONE: + bNone = sal_True; + break; + case UNDERLINE_DONTKNOW: + break; + default: + if( !rHTMLWrt.IsCSS1Source( CSS1_OUTMODE_PARA ) ) + { + // das geht auch in HTML und muss nicht als STYLE-Option + // und darf nicht als Hint geschrieben werden + ASSERT( !rHTMLWrt.IsCSS1Source(CSS1_OUTMODE_HINT), + "Underline als Hint schreiben?" ); + pUStr = sCSS1_PV_underline; + } + break; + } + } + + const sal_Char *pOStr = 0; + if( pOItem ) + { + switch( pOItem->GetLineStyle() ) + { + case UNDERLINE_NONE: + bNone = sal_True; + break; + case UNDERLINE_DONTKNOW: + break; + default: + if( !rHTMLWrt.IsCSS1Source( CSS1_OUTMODE_PARA ) ) + { + // das geht auch in HTML und muss nicht als STYLE-Option + // und darf nicht als Hint geschrieben werden + ASSERT( !rHTMLWrt.IsCSS1Source(CSS1_OUTMODE_HINT), + "Overline als Hint schreiben?" ); + pOStr = sCSS1_PV_overline; + } + break; + } + } + + const sal_Char *pCOStr = 0; + if( pCOItem ) + { + switch( pCOItem->GetStrikeout() ) + { + case STRIKEOUT_NONE: + bNone = sal_True; + break; + case STRIKEOUT_DONTKNOW: + break; + default: + if( !rHTMLWrt.IsCSS1Source( CSS1_OUTMODE_PARA ) ) + { + // das geht auch in HTML und muss nicht als STYLE-Option + // und darf nicht als Hint geschrieben werden + ASSERT( !rHTMLWrt.IsCSS1Source(CSS1_OUTMODE_HINT), + "CrossedOut als Hint schreiben?" ); + pCOStr = sCSS1_PV_line_through; + } + break; + } + } + + const sal_Char *pBStr = 0; + if( pBItem && rHTMLWrt.IsHTMLMode(HTMLMODE_BLINK) ) + { + if( !pBItem->GetValue() ) + { + bNone = sal_True; + } + else if( !rHTMLWrt.IsCSS1Source( CSS1_OUTMODE_PARA ) ) + { + // das geht auch in HTML und muss nicht als STYLE-Option + // und darf nicht als Hint geschrieben werden + ASSERT( !rHTMLWrt.IsCSS1Source(CSS1_OUTMODE_HINT), + "Blink als Hint schreiben?" ); + pBStr = sCSS1_PV_blink; + } + } + + ByteString sOut; + if( pUStr ) + sOut.Append( pUStr ); + + if( pOStr ) + { + if( sOut.Len() ) + sOut += ' '; + + sOut.Append( pOStr ); + } + + if( pCOStr ) + { + if( sOut.Len() ) + sOut += ' '; + + sOut.Append( pCOStr ); + } + + if( pBStr ) + { + if( sOut.Len() ) + sOut += ' '; + + sOut.Append( pBStr ); + } + + if( sOut.Len() ) + rHTMLWrt.OutCSS1_PropertyAscii( sCSS1_P_text_decoration, sOut ); + else if( bNone ) + rHTMLWrt.OutCSS1_PropertyAscii( sCSS1_P_text_decoration, sCSS1_PV_none ); + + return rWrt; +} + + +static Writer& OutCSS1_SvxCaseMap( Writer& rWrt, const SfxPoolItem& rHt ) +{ + SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt; + + if( !rHTMLWrt.IsHTMLMode(HTMLMODE_SMALL_CAPS) ) + return rWrt; + + const sal_Char *pStr = 0; + switch( ((const SvxCaseMapItem&)rHt).GetCaseMap() ) + { + case SVX_CASEMAP_NOT_MAPPED: pStr = sCSS1_PV_normal; break; + case SVX_CASEMAP_KAPITAELCHEN: pStr = sCSS1_PV_small_caps; break; + default: + ; + } + + if( pStr ) + rHTMLWrt.OutCSS1_PropertyAscii( sCSS1_P_font_variant, pStr ); + + return rWrt; +} + + +static Writer& OutCSS1_SvxColor( Writer& rWrt, const SfxPoolItem& rHt ) +{ + SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt; + + // Farben muessen nicht in der Style-Option ausgegeben werden. + if( rHTMLWrt.IsCSS1Source( CSS1_OUTMODE_PARA ) && + !rHTMLWrt.bCfgPreferStyles ) + return rWrt; + ASSERT( !rHTMLWrt.IsCSS1Source(CSS1_OUTMODE_HINT), + "Farbe wirklich als Hint ausgeben?" ); + + Color aColor( ((const SvxColorItem&)rHt).GetValue() ); + if( COL_AUTO == aColor.GetColor() ) + aColor.SetColor( COL_BLACK ); + + ByteString sOut; + GetCSS1Color( aColor, sOut ); + + rHTMLWrt.OutCSS1_PropertyAscii( sCSS1_P_color, sOut ); + + return rWrt; +} + + +static Writer& OutCSS1_SvxCrossedOut( Writer& rWrt, const SfxPoolItem& rHt ) +{ + // Mit dieser Methode werden nur Hints ausgegeben! + // Sonst wird OutCSS1_SvxTxtLn_SvxCrOut_SvxBlink() direkt aufgerufen. + + if( ((SwHTMLWriter&)rWrt).IsCSS1Source(CSS1_OUTMODE_HINT) ) + OutCSS1_SvxTxtLn_SvxCrOut_SvxBlink( rWrt, + 0, 0, (const SvxCrossedOutItem *)&rHt, 0 ); + + return rWrt; +} + +static Writer& OutCSS1_SvxFont( Writer& rWrt, const SfxPoolItem& rHt ) +{ + SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt; + + // Fonts muessen nicht in der Style-Option ausgegeben werden. + if( rHTMLWrt.IsCSS1Source( CSS1_OUTMODE_PARA ) ) + return rWrt; + + sal_uInt16 nScript = CSS1_OUTMODE_WESTERN; + switch( rHt.Which() ) + { + case RES_CHRATR_CJK_FONT: nScript = CSS1_OUTMODE_CJK; break; + case RES_CHRATR_CTL_FONT: nScript = CSS1_OUTMODE_CTL; break; + } + if( !rHTMLWrt.IsCSS1Script( nScript ) ) + return rWrt; + + ASSERT( !rHTMLWrt.IsCSS1Source(CSS1_OUTMODE_HINT), + "Font wirklich als Hint ausgeben?" ); + + String sOut; + // MS IE3b1 hat mit einfachen Haekchen Probleme + sal_uInt16 nMode = rHTMLWrt.nCSS1OutMode & CSS1_OUTMODE_ANY_ON; + sal_Unicode cQuote = nMode == CSS1_OUTMODE_RULE_ON ? '\"' : '\''; + SwHTMLWriter::PrepareFontList( ((const SvxFontItem&)rHt), sOut, cQuote, + sal_True ); + + rHTMLWrt.OutCSS1_Property( sCSS1_P_font_family, sOut ); + + return rWrt; +} + +static Writer& OutCSS1_SvxFontHeight( Writer& rWrt, const SfxPoolItem& rHt ) +{ + SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt; + + // Font-Hoehen muessen nicht in der Style-Option ausgegeben werden. + // Fuer Drop-Caps wird ein andewres font-size ausgegeben + if( rHTMLWrt.IsCSS1Source( CSS1_OUTMODE_PARA ) || + rHTMLWrt.IsCSS1Source( CSS1_OUTMODE_DROPCAP ) ) + return rWrt; + + sal_uInt16 nScript = CSS1_OUTMODE_WESTERN; + switch( rHt.Which() ) + { + case RES_CHRATR_CJK_FONTSIZE: nScript = CSS1_OUTMODE_CJK; break; + case RES_CHRATR_CTL_FONTSIZE: nScript = CSS1_OUTMODE_CTL; break; + } + if( !rHTMLWrt.IsCSS1Script( nScript ) ) + return rWrt; + + sal_uInt32 nHeight = ((const SvxFontHeightItem&)rHt).GetHeight(); + if( rHTMLWrt.IsCSS1Source(CSS1_OUTMODE_HINT) ) + { + // einen Hint nur dann ausgeben wenn es auch was bringt + sal_uInt16 nSize = rHTMLWrt.GetHTMLFontSize( nHeight ); + if( rHTMLWrt.aFontHeights[nSize-1] == nHeight ) + return rWrt; + } + ByteString sHeight( ByteString::CreateFromInt32( + (sal_Int32)(nHeight/20) ) ); + sHeight.Append( sCSS1_UNIT_pt ); + + rHTMLWrt.OutCSS1_PropertyAscii( sCSS1_P_font_size, sHeight ); + + return rWrt; +} + +static Writer& OutCSS1_SvxPosture( Writer& rWrt, const SfxPoolItem& rHt ) +{ + SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt; + + sal_uInt16 nScript = CSS1_OUTMODE_WESTERN; + switch( rHt.Which() ) + { + case RES_CHRATR_CJK_POSTURE: nScript = CSS1_OUTMODE_CJK; break; + case RES_CHRATR_CTL_POSTURE: nScript = CSS1_OUTMODE_CTL; break; + } + if( !rHTMLWrt.IsCSS1Script( nScript ) ) + return rWrt; + + const sal_Char *pStr = 0; + switch( ((const SvxPostureItem&)rHt).GetPosture() ) + { + case ITALIC_NONE: pStr = sCSS1_PV_normal; break; + case ITALIC_OBLIQUE: pStr = sCSS1_PV_oblique; break; + case ITALIC_NORMAL: + if( !rHTMLWrt.IsCSS1Source( CSS1_OUTMODE_PARA ) ) + { + // das geht auch in HTML und muss nicht als STYLE-Option + // und darf nicht als Hint geschrieben werden + ASSERT( !rHTMLWrt.IsCSS1Source(CSS1_OUTMODE_HINT), + "Italic als Hint schreiben?" ); + pStr = sCSS1_PV_italic; + } + break; + default: + ; + } + + if( pStr ) + rHTMLWrt.OutCSS1_PropertyAscii( sCSS1_P_font_style, pStr ); + + return rWrt; +} + +static Writer& OutCSS1_SvxKerning( Writer& rWrt, const SfxPoolItem& rHt ) +{ + SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt; + + // Kerning-Item nur ausgeben, wenn volle Style-Unterst?tzung da ist + if( !rHTMLWrt.IsHTMLMode(HTMLMODE_FULL_STYLES) ) + return rWrt; + + sal_Int16 nValue = ((const SvxKerningItem&)rHt).GetValue(); + if( nValue ) + { + ByteString sOut; + if( nValue < 0 ) + { + sOut = '-'; + nValue = -nValue; + } + + // Breite als n.n pt + nValue = (nValue + 1) / 2; // 1/10pt + sOut.Append( ByteString::CreateFromInt32( (sal_Int32)(nValue / 10) ) ); + sOut.Append( '.' ); + sOut.Append( ByteString::CreateFromInt32( (sal_Int32)(nValue % 10) ) ); + sOut.Append( sCSS1_UNIT_pt ); + + rHTMLWrt.OutCSS1_PropertyAscii( sCSS1_P_letter_spacing, sOut ); + } + else + { + rHTMLWrt.OutCSS1_PropertyAscii( sCSS1_P_letter_spacing, + sCSS1_PV_normal ); + } + + return rWrt; +} + +static Writer& OutCSS1_SvxLanguage( Writer& rWrt, const SfxPoolItem& rHt ) +{ + SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt; + + // Language will be exported rules only + if( rHTMLWrt.IsCSS1Source( CSS1_OUTMODE_PARA ) ) + return rWrt; + + sal_uInt16 nScript = CSS1_OUTMODE_WESTERN; + switch( rHt.Which() ) + { + case RES_CHRATR_CJK_LANGUAGE: nScript = CSS1_OUTMODE_CJK; break; + case RES_CHRATR_CTL_LANGUAGE: nScript = CSS1_OUTMODE_CTL; break; + } + if( !rHTMLWrt.IsCSS1Script( nScript ) ) + return rWrt; + + ASSERT( !rHTMLWrt.IsCSS1Source(CSS1_OUTMODE_HINT), + "Language wirklich als Hint ausgeben?" ); + + LanguageType eLang = ((const SvxLanguageItem &)rHt).GetLanguage(); + if( LANGUAGE_DONTKNOW == eLang ) + return rWrt; + + String sOut = MsLangId::convertLanguageToIsoString( eLang ); + + rHTMLWrt.OutCSS1_Property( sCSS1_P_so_language, sOut ); + + return rWrt; +} + +static Writer& OutCSS1_SvxUnderline( Writer& rWrt, const SfxPoolItem& rHt ) +{ + // Mit dieser Methode werden nur Hints ausgegeben! + // Sonst wird OutCSS1_SvxTxtLn_SvxCrOut_SvxBlink() direkt aufgerufen. + + if( ((SwHTMLWriter&)rWrt).IsCSS1Source(CSS1_OUTMODE_HINT) ) + OutCSS1_SvxTxtLn_SvxCrOut_SvxBlink( rWrt, + (const SvxUnderlineItem *)&rHt, 0, 0, 0 ); + + return rWrt; +} + + +static Writer& OutCSS1_SvxOverline( Writer& rWrt, const SfxPoolItem& rHt ) +{ + // Mit dieser Methode werden nur Hints ausgegeben! + // Sonst wird OutCSS1_SvxTxtLn_SvxCrOut_SvxBlink() direkt aufgerufen. + + if( ((SwHTMLWriter&)rWrt).IsCSS1Source(CSS1_OUTMODE_HINT) ) + OutCSS1_SvxTxtLn_SvxCrOut_SvxBlink( rWrt, + 0, (const SvxOverlineItem *)&rHt, 0, 0 ); + + return rWrt; +} + + +static Writer& OutCSS1_SvxFontWeight( Writer& rWrt, const SfxPoolItem& rHt ) +{ + SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt; + + sal_uInt16 nScript = CSS1_OUTMODE_WESTERN; + switch( rHt.Which() ) + { + case RES_CHRATR_CJK_WEIGHT: nScript = CSS1_OUTMODE_CJK; break; + case RES_CHRATR_CTL_WEIGHT: nScript = CSS1_OUTMODE_CTL; break; + } + if( !rHTMLWrt.IsCSS1Script( nScript ) ) + return rWrt; + + const sal_Char *pStr = 0; + switch( ((const SvxWeightItem&)rHt).GetWeight() ) + { + case WEIGHT_ULTRALIGHT: pStr = sCSS1_PV_extra_light; break; + case WEIGHT_LIGHT: pStr = sCSS1_PV_light; break; + case WEIGHT_SEMILIGHT: pStr = sCSS1_PV_demi_light; break; + case WEIGHT_NORMAL: pStr = sCSS1_PV_normal; break; + case WEIGHT_SEMIBOLD: pStr = sCSS1_PV_demi_bold; break; + case WEIGHT_BOLD: + if( !rHTMLWrt.IsCSS1Source( CSS1_OUTMODE_PARA ) ) + { + // das geht auch in HTML und muss nicht als STYLE-Option + // und darf nicht als Hint geschrieben werden + ASSERT( !rHTMLWrt.IsCSS1Source(CSS1_OUTMODE_HINT), + "Fett als Hint schreiben?" ); + pStr = sCSS1_PV_bold; + } + break; + case WEIGHT_ULTRABOLD: pStr = sCSS1_PV_extra_bold; break; + default: + pStr = sCSS1_PV_normal;; + } + + if( pStr ) + rHTMLWrt.OutCSS1_PropertyAscii( sCSS1_P_font_weight, pStr ); + + return rWrt; +} + +static Writer& OutCSS1_SvxBlink( Writer& rWrt, const SfxPoolItem& rHt ) +{ + // Mit dieser Methode werden nur Hints ausgegeben! + // Sonst wird OutCSS1_SvxTxtLn_SvxCrOut_SvxBlink() direkt aufgerufen. + + if( ((SwHTMLWriter&)rWrt).IsCSS1Source(CSS1_OUTMODE_HINT) ) + OutCSS1_SvxTxtLn_SvxCrOut_SvxBlink( rWrt, + 0, 0, 0, (const SvxBlinkItem *)&rHt ); + + return rWrt; +} + +static Writer& OutCSS1_SvxLineSpacing( Writer& rWrt, const SfxPoolItem& rHt ) +{ + SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt; + + // #60393#: Netscape4 hat massive Probleme mit den Zellenhoehen + // wenn der Zeilenabstand innerhalb einer Tabelle geaendert wird + // und die Breite der Tabelle nicht automatisch berechnet wird + // (also wenn eine WIDTH-Option vorhanden ist). + if( rHTMLWrt.bOutTable && rHTMLWrt.bCfgNetscape4 ) + return rWrt; + + const SvxLineSpacingItem& rLSItem = (const SvxLineSpacingItem&)rHt; + + sal_uInt16 nHeight = 0; + sal_uInt16 nPrcHeight = 0; + SvxLineSpace eLineSpace = rLSItem.GetLineSpaceRule(); + switch( rLSItem.GetInterLineSpaceRule() ) + { + case SVX_INTER_LINE_SPACE_OFF: + case SVX_INTER_LINE_SPACE_FIX: + { + switch( eLineSpace ) + { + case SVX_LINE_SPACE_MIN: + case SVX_LINE_SPACE_FIX: + nHeight = rLSItem.GetLineHeight(); + break; + case SVX_LINE_SPACE_AUTO: + nPrcHeight = 100; + break; + default: + ; + } + } + break; + case SVX_INTER_LINE_SPACE_PROP: + nPrcHeight = rLSItem.GetPropLineSpace(); + break; + + default: + ; + } + + if( nHeight ) + rHTMLWrt.OutCSS1_UnitProperty( sCSS1_P_line_height, (long)nHeight ); + else if( nPrcHeight ) + { + ByteString sHeight( + ByteString::CreateFromInt32( (sal_Int32)nPrcHeight ) ); + sHeight += '%'; + rHTMLWrt.OutCSS1_PropertyAscii( sCSS1_P_line_height, sHeight ); + } + + return rWrt; + +} + +static Writer& OutCSS1_SvxAdjust( Writer& rWrt, const SfxPoolItem& rHt ) +{ + SwHTMLWriter & rHTMLWrt = (SwHTMLWriter&)rWrt; + + // Alignment in Style-Option nur ausgeben, wenn das Tag kein + // ALIGN=xxx zulaesst + if( rHTMLWrt.IsCSS1Source( CSS1_OUTMODE_PARA ) && + !rHTMLWrt.bNoAlign) + return rWrt; + + const sal_Char* pStr = 0; + switch( ((const SvxAdjustItem&)rHt).GetAdjust() ) + { + case SVX_ADJUST_LEFT: pStr = sCSS1_PV_left; break; + case SVX_ADJUST_RIGHT: pStr = sCSS1_PV_right; break; + case SVX_ADJUST_BLOCK: pStr = sCSS1_PV_justify; break; + case SVX_ADJUST_CENTER: pStr = sCSS1_PV_center; break; + default: + ; + } + + if( pStr ) + rHTMLWrt.OutCSS1_PropertyAscii( sCSS1_P_text_align, pStr ); + + return rWrt; +} + +static Writer& OutCSS1_SvxFmtSplit( Writer& rWrt, const SfxPoolItem& rHt ) +{ + SwHTMLWriter & rHTMLWrt = (SwHTMLWriter&)rWrt; + + const sal_Char *pStr = ((const SvxFmtSplitItem&)rHt).GetValue() + ? sCSS1_PV_auto + : sCSS1_PV_avoid; + rHTMLWrt.OutCSS1_PropertyAscii( sCSS1_P_page_break_inside, pStr ); + + return rWrt; +} + +static Writer& OutCSS1_SwFmtLayoutSplit( Writer& rWrt, const SfxPoolItem& rHt ) +{ + SwHTMLWriter & rHTMLWrt = (SwHTMLWriter&)rWrt; + + const sal_Char *pStr = ((const SwFmtLayoutSplit&)rHt).GetValue() + ? sCSS1_PV_auto + : sCSS1_PV_avoid; + rHTMLWrt.OutCSS1_PropertyAscii( sCSS1_P_page_break_inside, pStr ); + + return rWrt; +} + +static Writer& OutCSS1_SvxWidows( Writer& rWrt, const SfxPoolItem& rHt ) +{ + SwHTMLWriter & rHTMLWrt = (SwHTMLWriter&)rWrt; + + ByteString aStr( + ByteString::CreateFromInt32( ((const SvxWidowsItem&)rHt).GetValue() ) ); + rHTMLWrt.OutCSS1_PropertyAscii( sCSS1_P_widows, aStr ); + + return rWrt; +} + +static Writer& OutCSS1_SvxOrphans( Writer& rWrt, const SfxPoolItem& rHt ) +{ + SwHTMLWriter & rHTMLWrt = (SwHTMLWriter&)rWrt; + + ByteString aStr( + ByteString::CreateFromInt32( ((const SvxOrphansItem&)rHt).GetValue() ) ); + rHTMLWrt.OutCSS1_PropertyAscii( sCSS1_P_orphans, aStr ); + + return rWrt; +} + +static void OutCSS1_SwFmtDropAttrs( SwHTMLWriter& rHWrt, + const SwFmtDrop& rDrop, + const SfxItemSet *pCharFmtItemSet ) +{ + // Text fliesst rechts drumrum + rHWrt.OutCSS1_PropertyAscii( sCSS1_P_float, sCSS1_PV_left ); + + // Anzahl der Zeilen -> %-Angabe fuer Font-Hoehe! + ByteString sOut( ByteString::CreateFromInt32( rDrop.GetLines()*100 ) ); + sOut += '%'; + rHWrt.OutCSS1_PropertyAscii( sCSS1_P_font_size, sOut ); + + // Abstand zum Text = rechter Rand + sal_uInt16 nDistance = rDrop.GetDistance(); + if( nDistance > 0 ) + rHWrt.OutCSS1_UnitProperty( sCSS1_P_margin_right, nDistance ); + + const SwCharFmt *pDCCharFmt = rDrop.GetCharFmt(); + if( pCharFmtItemSet ) + rHWrt.OutCSS1_SfxItemSet( *pCharFmtItemSet ); + else if( pDCCharFmt ) + rHWrt.OutCSS1_SfxItemSet( pDCCharFmt->GetAttrSet() ); + else if( (rHWrt.nCSS1OutMode & CSS1_OUTMODE_ANY_OFF) == CSS1_OUTMODE_RULE_OFF ) + rHWrt.Strm() << sCSS1_rule_end; + +} + +static Writer& OutCSS1_SwFmtDrop( Writer& rWrt, const SfxPoolItem& rHt ) +{ + SwHTMLWriter & rHTMLWrt = (SwHTMLWriter&)rWrt; + + // nie als Option eines Absatzes ausgeben, sondern nur als Hints + if( !rHTMLWrt.IsCSS1Source(CSS1_OUTMODE_HINT) ) + return rWrt; + + if( rHTMLWrt.bTagOn ) + { + SwCSS1OutMode aMode( rHTMLWrt, + rHTMLWrt.nCSS1Script|CSS1_OUTMODE_SPAN_TAG1_ON|CSS1_OUTMODE_ENCODE| + CSS1_OUTMODE_DROPCAP ); + + OutCSS1_SwFmtDropAttrs( rHTMLWrt, (const SwFmtDrop&)rHt ); + // Ein "> wird schon vom aufrufenden OutCSS1_HintAsSpanTag geschrieben. + } + else + { + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_span, sal_False ); + } + + return rWrt; +} + +static Writer& OutCSS1_SwFmtFrmSize( Writer& rWrt, const SfxPoolItem& rHt, + sal_uInt16 nMode ) +{ + SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt; + + ByteString sOut; + const SwFmtFrmSize& rFSItem = (const SwFmtFrmSize&)rHt; + + if( nMode & CSS1_FRMSIZE_WIDTH ) + { + sal_uInt8 nPrcWidth = rFSItem.GetWidthPercent(); + if( nPrcWidth ) + { + (sOut = ByteString::CreateFromInt32( nPrcWidth) ) += '%'; + rHTMLWrt.OutCSS1_PropertyAscii( sCSS1_P_width, sOut ); + } + else if( nMode & CSS1_FRMSIZE_PIXEL ) + { + rHTMLWrt.OutCSS1_PixelProperty( sCSS1_P_width, + rFSItem.GetSize().Width(), sal_False ); + } + else + { + rHTMLWrt.OutCSS1_UnitProperty( sCSS1_P_width, + rFSItem.GetSize().Width() ); + } + } + + if( nMode & CSS1_FRMSIZE_ANYHEIGHT ) + { + sal_Bool bOutHeight = sal_False; + switch( rFSItem.GetHeightSizeType() ) + { + case ATT_FIX_SIZE: + bOutHeight = (nMode & CSS1_FRMSIZE_FIXHEIGHT) != 0; + break; + case ATT_MIN_SIZE: + bOutHeight = (nMode & CSS1_FRMSIZE_MINHEIGHT) != 0; + break; + case ATT_VAR_SIZE: + bOutHeight = (nMode & CSS1_FRMSIZE_VARHEIGHT) != 0; + break; + default: + ASSERT( bOutHeight, "Hoehe wird nicht exportiert" ); + break; + } + + if( bOutHeight ) + { + sal_uInt8 nPrcHeight = rFSItem.GetHeightPercent(); + if( nPrcHeight ) + { + (sOut = ByteString::CreateFromInt32( nPrcHeight ) ) += '%'; + rHTMLWrt.OutCSS1_PropertyAscii( sCSS1_P_height, sOut ); + } + else if( nMode & CSS1_FRMSIZE_PIXEL ) + { + rHTMLWrt.OutCSS1_PixelProperty( sCSS1_P_height, + rFSItem.GetSize().Width(), + sal_True ); + } + else + { + rHTMLWrt.OutCSS1_UnitProperty( sCSS1_P_height, + rFSItem.GetSize().Height() ); + } + } + } + + return rWrt; +} + +static Writer& OutCSS1_SvxLRSpace( Writer& rWrt, const SfxPoolItem& rHt ) +{ + SwHTMLWriter & rHTMLWrt = (SwHTMLWriter&)rWrt; + + const SvxLRSpaceItem& rLRItem = (const SvxLRSpaceItem&)rHt; + + // Der Export der harten Attributierung ist unnoetig, wenn die + // neuen Werte denen der aktuellen Vorlage entsprechen + + // Einen linken Rand kann es durch eine Liste bereits in der + // Umgebung geben + long nLeftMargin = (long)rLRItem.GetTxtLeft() - rHTMLWrt.nLeftMargin; + if( rHTMLWrt.nDfltLeftMargin != nLeftMargin ) + { + rHTMLWrt.OutCSS1_UnitProperty( sCSS1_P_margin_left, nLeftMargin ); + } + + if( rHTMLWrt.nDfltRightMargin != rLRItem.GetRight() ) + { + rHTMLWrt.OutCSS1_UnitProperty( sCSS1_P_margin_right, + (long)rLRItem.GetRight() ); + } + + // Der Erstzeilen-Einzug kann den Platz fuer eine Numerierung + // enthalten + long nFirstLineIndent = (long)rLRItem.GetTxtFirstLineOfst() - + rHTMLWrt.nFirstLineIndent; + if( rHTMLWrt.nDfltFirstLineIndent != nFirstLineIndent ) + { + rHTMLWrt.OutCSS1_UnitProperty( sCSS1_P_text_indent, + nFirstLineIndent ); + } + + return rWrt; +} + +static Writer& OutCSS1_SvxULSpace( Writer& rWrt, const SfxPoolItem& rHt ) +{ + SwHTMLWriter & rHTMLWrt = (SwHTMLWriter&)rWrt; + + const SvxULSpaceItem& rULItem = (const SvxULSpaceItem&)rHt; + + if( rHTMLWrt.nDfltTopMargin != rULItem.GetUpper() ) + { + rHTMLWrt.OutCSS1_UnitProperty( sCSS1_P_margin_top, + (long)rULItem.GetUpper() ); + } + + if( rHTMLWrt.nDfltBottomMargin != rULItem.GetLower() ) + { + rHTMLWrt.OutCSS1_UnitProperty( sCSS1_P_margin_bottom, + (long)rULItem.GetLower() ); + } + + return rWrt; +} + +static Writer& OutCSS1_SvxULSpace_SvxLRSpace( Writer& rWrt, + const SvxULSpaceItem *pULItem, + const SvxLRSpaceItem *pLRItem ) +{ + SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt; + + if( pLRItem && pULItem && + pLRItem->GetLeft() == pLRItem->GetRight() && + pLRItem->GetLeft() == pULItem->GetUpper() && + pLRItem->GetLeft() == pULItem->GetLower() && + pLRItem->GetLeft() != rHTMLWrt.nDfltLeftMargin && + pLRItem->GetRight() != rHTMLWrt.nDfltRightMargin && + pULItem->GetUpper() != rHTMLWrt.nDfltTopMargin && + pULItem->GetLower() != rHTMLWrt.nDfltBottomMargin ) + { + rHTMLWrt.OutCSS1_UnitProperty( sCSS1_P_margin, (long)pLRItem->GetLeft() ); + } + else + { + if( pLRItem ) + OutCSS1_SvxLRSpace( rWrt, *pLRItem ); + if( pULItem ) + OutCSS1_SvxULSpace( rWrt, *pULItem ); + } + + return rWrt; +} + +static Writer& OutCSS1_SvxULSpace_SvxLRSpace( Writer& rWrt, + const SfxItemSet& rItemSet, + sal_Bool bDeep ) +{ + const SvxULSpaceItem *pULSpace = 0; + const SvxLRSpaceItem *pLRSpace = 0; + const SfxPoolItem *pItem; + if( SFX_ITEM_SET == rItemSet.GetItemState( RES_LR_SPACE, bDeep, &pItem ) ) + pLRSpace = (const SvxLRSpaceItem *)pItem; + + if( SFX_ITEM_SET == rItemSet.GetItemState( RES_UL_SPACE, bDeep, &pItem ) ) + pULSpace = (const SvxULSpaceItem *)pItem; + + if( pLRSpace || pULSpace ) + OutCSS1_SvxULSpace_SvxLRSpace( rWrt, pULSpace, pLRSpace ); + + return rWrt; +} + +static Writer& OutCSS1_SvxFmtBreak_SwFmtPDesc_SvxFmtKeep( Writer& rWrt, + const SvxFmtBreakItem *pBreakItem, + const SwFmtPageDesc *pPDescItem, + const SvxFmtKeepItem *pKeepItem ) +{ + SwHTMLWriter & rHTMLWrt = (SwHTMLWriter&)rWrt; + + if( !rHTMLWrt.IsHTMLMode(HTMLMODE_PRINT_EXT) ) + return rWrt; + + const sal_Char *pBreakBefore = 0; + const sal_Char *pBreakAfter = 0; + + if( pKeepItem ) + { + pBreakAfter = pKeepItem->GetValue() ? sCSS1_PV_avoid : sCSS1_PV_auto; + } + if( pBreakItem ) + { + switch( pBreakItem->GetBreak() ) + { + case SVX_BREAK_NONE: + pBreakBefore = sCSS1_PV_auto; + if( !pBreakAfter ) + pBreakAfter = sCSS1_PV_auto; + break; + + case SVX_BREAK_PAGE_BEFORE: + pBreakBefore = sCSS1_PV_always; + break; + + case SVX_BREAK_PAGE_AFTER: + pBreakAfter= sCSS1_PV_always; + break; + + default: + ; + } + } + if( pPDescItem ) + { + const SwPageDesc *pPDesc = pPDescItem->GetPageDesc(); + if( pPDesc ) + { + switch( pPDesc->GetPoolFmtId() ) + { + case RES_POOLPAGE_LEFT: pBreakBefore = sCSS1_PV_left; break; + case RES_POOLPAGE_RIGHT: pBreakBefore = sCSS1_PV_right; break; + default: pBreakBefore = sCSS1_PV_always; break; + } + } + else if( !pBreakBefore ) + { + pBreakBefore = sCSS1_PV_auto; + } + } + + if( pBreakBefore ) + rHTMLWrt.OutCSS1_PropertyAscii( sCSS1_P_page_break_before, + pBreakBefore ); + if( pBreakAfter ) + rHTMLWrt.OutCSS1_PropertyAscii( sCSS1_P_page_break_after, + pBreakAfter ); + + return rWrt; +} + +static Writer& OutCSS1_SvxFmtBreak_SwFmtPDesc_SvxFmtKeep( Writer& rWrt, + const SfxItemSet& rItemSet, + sal_Bool bDeep ) +{ + SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt; + const SfxPoolItem *pItem; + const SvxFmtBreakItem *pBreakItem = 0; + if( SFX_ITEM_SET==rItemSet.GetItemState( RES_BREAK, bDeep, &pItem )) + pBreakItem = (const SvxFmtBreakItem *)pItem; + + const SwFmtPageDesc *pPDescItem = 0; + if( ( !rHTMLWrt.IsCSS1Source( CSS1_OUTMODE_PARA ) || + !rHTMLWrt.bCSS1IgnoreFirstPageDesc || + rHTMLWrt.pStartNdIdx->GetIndex() != + rHTMLWrt.pCurPam->GetPoint()->nNode.GetIndex() ) && + SFX_ITEM_SET==rItemSet.GetItemState( RES_PAGEDESC, bDeep, &pItem )) + pPDescItem = (const SwFmtPageDesc*)pItem; + + const SvxFmtKeepItem *pKeepItem = 0; + if( SFX_ITEM_SET==rItemSet.GetItemState( RES_KEEP, bDeep, &pItem )) + pKeepItem = (const SvxFmtKeepItem *)pItem; + + if( pBreakItem || pPDescItem || pKeepItem ) + OutCSS1_SvxFmtBreak_SwFmtPDesc_SvxFmtKeep( rWrt, pBreakItem, + pPDescItem, pKeepItem ); + + return rWrt; +} + +// Wrapper fuer OutCSS1_SfxItemSet etc. +static Writer& OutCSS1_SvxBrush( Writer& rWrt, const SfxPoolItem& rHt ) +{ + OutCSS1_SvxBrush( rWrt, rHt, CSS1_BACKGROUND_ATTR, 0 ); + return rWrt; +} + + +static Writer& OutCSS1_SvxBrush( Writer& rWrt, const SfxPoolItem& rHt, + sal_uInt16 nMode, const String *pGrfName ) +{ + SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt; + + // Das Zeichen-Attribut wird nicht ausgegeben, wenn gerade + // Optionen ausgegeben werden + if( rHt.Which() < RES_CHRATR_END && + rHTMLWrt.IsCSS1Source( CSS1_OUTMODE_PARA ) ) + return rWrt; + + // Erstmal ein par Werte holen +// const Brush &rBrush = ((const SvxBrushItem &)rHt).GetBrush(); + const Color & rColor = ((const SvxBrushItem &)rHt).GetColor(); + const String *pLink = pGrfName ? pGrfName + : ((const SvxBrushItem &)rHt).GetGraphicLink(); + SvxGraphicPosition ePos = ((const SvxBrushItem &)rHt).GetGraphicPos(); + + if( CSS1_BACKGROUND_PAGE==nMode ) + { + // Fuer Seitenvorlagen wurde der Grafik-Name uebergeben. Es wird + // nur ein Attribut ausgegeben, wenn die Grafik nicht gekachelt ist. + ASSERT( pLink, "Wo ist der Grafik-Name der Seitenvorlage?" ); + if( !pLink || !pLink->Len() || GPOS_TILED==ePos ) + return rWrt; + } + + // Erstmal die Farbe holen + sal_Bool bColor = sal_False; + /// OD 02.09.2002 #99657# + /// set <bTransparent> to sal_True, if color is "no fill"/"auto fill" + sal_Bool bTransparent = (rColor.GetColor() == COL_TRANSPARENT); + Color aColor; + if( !bTransparent ) + { + aColor = rColor; + bColor = sal_True; + } + + // und jetzt eine Grafik + String sGrfNm; + + if( !pLink ) + { + // embeddete Grafik -> WriteEmbedded schreiben + const Graphic* pGrf = ((const SvxBrushItem &)rHt).GetGraphic(); + if( pGrf ) + { + // Grafik als (JPG-)File speichern + const String* pTempFileName = rHTMLWrt.GetOrigFileName(); + if( pTempFileName ) + sGrfNm = *pTempFileName; + sal_uInt16 nErr = XOutBitmap::WriteGraphic( *pGrf, sGrfNm, + String::CreateFromAscii("JPG"), + XOUTBMP_USE_NATIVE_IF_POSSIBLE ); + if( !nErr ) // fehlerhaft, da ist nichts auszugeben + { + sGrfNm = URIHelper::SmartRel2Abs( + INetURLObject(rWrt.GetBaseURL()), sGrfNm, + URIHelper::GetMaybeFileHdl() ); + pLink = &sGrfNm; + } + else + { + rHTMLWrt.nWarn = WARN_SWG_POOR_LOAD | WARN_SW_WRITE_BASE; + } + } + } + else if( !pGrfName && rHTMLWrt.bCfgCpyLinkedGrfs ) + { + sGrfNm = *pLink; + rWrt.CopyLocalFileToINet( sGrfNm ); + pLink = &sGrfNm; + } + + // In Tabellen wird nur dann etwas exportiert, wenn eine Grafik + // existiert. + if( CSS1_BACKGROUND_TABLE==nMode && !pLink ) + return rWrt; + + // ggf. noch die Ausrichtung der Grafik + const sal_Char *pRepeat = 0, *pHori = 0, *pVert = 0; + if( pLink ) + { + if( GPOS_TILED==ePos ) + { + pRepeat = sCSS1_PV_repeat; + } + else + { + switch( ePos ) + { + case GPOS_LT: + case GPOS_MT: + case GPOS_RT: + pHori = sCSS1_PV_top; + break; + + case GPOS_LM: + case GPOS_MM: + case GPOS_RM: + pHori = sCSS1_PV_middle; + break; + + case GPOS_LB: + case GPOS_MB: + case GPOS_RB: + pHori = sCSS1_PV_bottom; + break; + + default: + ; + } + + switch( ePos ) + { + case GPOS_LT: + case GPOS_LM: + case GPOS_LB: + pVert = sCSS1_PV_left; + break; + + case GPOS_MT: + case GPOS_MM: + case GPOS_MB: + pVert = sCSS1_PV_center; + break; + + case GPOS_RT: + case GPOS_RM: + case GPOS_RB: + pVert = sCSS1_PV_right; + break; + + default: + ; + } + + if( pHori || pVert ) + pRepeat = sCSS1_PV_no_repeat; + } + } + + // jetzt den String zusammen bauen + String sOut; + if( !pLink && !bColor ) + { + // keine Farbe und kein Link, aber ein transparenter Brush + if( bTransparent && CSS1_BACKGROUND_FLY != nMode ) + sOut.AssignAscii( sCSS1_PV_transparent ); + } + else + { + if( bColor ) + { + ByteString sTmp; + GetCSS1Color( aColor, sTmp ); + sOut += String( sTmp, RTL_TEXTENCODING_ASCII_US ); + } + + if( pLink ) + { + if( bColor ) + sOut += ' '; + + sOut.AppendAscii( sCSS1_url ); + sOut.Append( '(' ); + sOut.Append( String(URIHelper::simpleNormalizedMakeRelative(rWrt.GetBaseURL(), + *pLink))); + + sOut.Append( ')' ); + + if( pRepeat ) + { + sOut.Append( ' ' ); + sOut.AppendAscii( pRepeat ); + } + + if( pHori ) + { + sOut.Append( ' ' ); + sOut.AppendAscii( pHori ); + } + if( pVert ) + { + sOut.Append( ' ' ); + sOut.AppendAscii( pVert ); + } + + sOut.Append( ' ' ); + sOut.AppendAscii( sCSS1_PV_scroll ); + } + } + + if( sOut.Len() ) + rHTMLWrt.OutCSS1_Property( sCSS1_P_background, sOut ); + + return rWrt; +} + +static void OutCSS1_SvxBorderLine( SwHTMLWriter& rHTMLWrt, + const sal_Char *pProperty, + const SvxBorderLine *pLine ) +{ + if( !pLine ) + { + rHTMLWrt.OutCSS1_PropertyAscii( pProperty, sCSS1_PV_none ); + return; + } + + sal_Bool bDouble = sal_False; + sal_Int32 nWidth = pLine->GetOutWidth(); + if( pLine->GetInWidth() ) + { + nWidth += pLine->GetDistance(); + nWidth += pLine->GetInWidth(); + bDouble = sal_True; + } + + ByteString sOut; + if( Application::GetDefaultDevice() && + nWidth <= Application::GetDefaultDevice()->PixelToLogic( + Size( 1, 1 ), MapMode( MAP_TWIP) ).Width() ) + { + // Wenn die Breite kleiner ist als ein Pixel, dann als 1px + // ausgeben, damit Netscape und IE die Linie auch darstellen. + sOut += "1px"; + } + else + { + nWidth *= 5; // 1/100pt + + // Breite als n.nn pt + sOut += ByteString::CreateFromInt32( nWidth / 100 ); + (((sOut += '.') + += ByteString::CreateFromInt32((nWidth/10) % 10)) + += ByteString::CreateFromInt32(nWidth % 10)) += sCSS1_UNIT_pt; + } + + // Linien-Stil: solid oder double + ((sOut += ' ') + += (bDouble ? sCSS1_PV_double : sCSS1_PV_solid)) += ' '; + + // und noch die Farbe + GetCSS1Color( pLine->GetColor(), sOut ); + + rHTMLWrt.OutCSS1_PropertyAscii( pProperty, sOut ); +} + +static Writer& OutCSS1_SvxBox( Writer& rWrt, const SfxPoolItem& rHt ) +{ + SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt; + + // Das Zeichen-Attribut wird nicht ausgegeben, wenn gerade + // Optionen ausgegeben werden + if( !rHTMLWrt.IsHTMLMode(HTMLMODE_PARA_BORDER)) + return rWrt; + + const SvxBoxItem& rBoxItem = (const SvxBoxItem&)rHt; + const SvxBorderLine *pTop = rBoxItem.GetTop(); + const SvxBorderLine *pBottom = rBoxItem.GetBottom(); + const SvxBorderLine *pLeft = rBoxItem.GetLeft(); + const SvxBorderLine *pRight = rBoxItem.GetRight(); + + if( (pTop && pBottom && pLeft && pRight && + *pTop == *pBottom && *pTop == *pLeft && *pTop == *pRight) || + (!pTop && !pBottom && !pLeft && !pRight) ) + { + // alle Linien gesetzt und gleich oder alle Linien nicht gesetzt + // => border : ... + OutCSS1_SvxBorderLine( rHTMLWrt, sCSS1_P_border, pTop ); + } + else + { + // sonst alle Linien individuell ausgeben + OutCSS1_SvxBorderLine( rHTMLWrt, sCSS1_P_border_top, pTop ); + OutCSS1_SvxBorderLine( rHTMLWrt, sCSS1_P_border_bottom, pBottom ); + OutCSS1_SvxBorderLine( rHTMLWrt, sCSS1_P_border_left, pLeft ); + OutCSS1_SvxBorderLine( rHTMLWrt, sCSS1_P_border_right, pRight ); + } + + long nTopDist = pTop ? rBoxItem.GetDistance( BOX_LINE_TOP ) : 0; + long nBottomDist = pBottom ? rBoxItem.GetDistance( BOX_LINE_BOTTOM ) : 0; + long nLeftDist = pLeft ? rBoxItem.GetDistance( BOX_LINE_LEFT ) : 0; + long nRightDist = pRight ? rBoxItem.GetDistance( BOX_LINE_RIGHT ) : 0; + + if( nTopDist == nBottomDist && nLeftDist == nRightDist ) + { + ByteString sVal; + AddUnitPropertyValue( nTopDist, rHTMLWrt.GetCSS1Unit(), sVal ); + if( nTopDist != nLeftDist ) + { + sVal += ' '; + AddUnitPropertyValue( nLeftDist, rHTMLWrt.GetCSS1Unit(), sVal ); + } + rHTMLWrt.OutCSS1_PropertyAscii( sCSS1_P_padding, sVal ); + } + else + { + rHTMLWrt.OutCSS1_UnitProperty( sCSS1_P_padding_top, nTopDist ); + rHTMLWrt.OutCSS1_UnitProperty( sCSS1_P_padding_bottom, nBottomDist ); + rHTMLWrt.OutCSS1_UnitProperty( sCSS1_P_padding_left, nLeftDist ); + rHTMLWrt.OutCSS1_UnitProperty( sCSS1_P_padding_right, nRightDist ); + } + + return rWrt; +} + +static Writer& OutCSS1_SvxFrameDirection( Writer& rWrt, const SfxPoolItem& rHt ) +{ + SwHTMLWriter& rHTMLWrt = static_cast< SwHTMLWriter& >( rWrt ); + + // Language will be exported rules only + if( !rHTMLWrt.IsCSS1Source( CSS1_OUTMODE_TEMPLATE ) ) + return rWrt; + + sal_uInt16 nDir = + static_cast< const SvxFrameDirectionItem& >( rHt ).GetValue(); + sal_Char *pStr = 0; + switch( nDir ) + { + case FRMDIR_HORI_LEFT_TOP: + case FRMDIR_VERT_TOP_LEFT: + pStr = sCSS1_PV_ltr; + break; + case FRMDIR_HORI_RIGHT_TOP: + case FRMDIR_VERT_TOP_RIGHT: + pStr = sCSS1_PV_rtl; + break; + case FRMDIR_ENVIRONMENT: + pStr = sCSS1_PV_inherit; + break; + } + + if( pStr ) + rHTMLWrt.OutCSS1_PropertyAscii( sCSS1_P_direction, pStr ); + + 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 aCSS1AttrFnTab = { +/* RES_CHRATR_CASEMAP */ OutCSS1_SvxCaseMap, +/* RES_CHRATR_CHARSETCOLOR */ 0, +/* RES_CHRATR_COLOR */ OutCSS1_SvxColor, +/* RES_CHRATR_CONTOUR */ 0, +/* RES_CHRATR_CROSSEDOUT */ OutCSS1_SvxCrossedOut, +/* RES_CHRATR_ESCAPEMENT */ 0, +/* RES_CHRATR_FONT */ OutCSS1_SvxFont, +/* RES_CHRATR_FONTSIZE */ OutCSS1_SvxFontHeight, +/* RES_CHRATR_KERNING */ OutCSS1_SvxKerning, +/* RES_CHRATR_LANGUAGE */ OutCSS1_SvxLanguage, +/* RES_CHRATR_POSTURE */ OutCSS1_SvxPosture, +/* RES_CHRATR_PROPORTIONALFONTSIZE*/0, +/* RES_CHRATR_SHADOWED */ 0, +/* RES_CHRATR_UNDERLINE */ OutCSS1_SvxUnderline, +/* RES_CHRATR_WEIGHT */ OutCSS1_SvxFontWeight, +/* RES_CHRATR_WORDLINEMODE */ 0, +/* RES_CHRATR_AUTOKERN */ 0, +/* RES_CHRATR_BLINK */ OutCSS1_SvxBlink, +/* RES_CHRATR_NOHYPHEN */ 0, // Neu: nicht trennen +/* RES_CHRATR_NOLINEBREAK */ 0, // Neu: nicht umbrechen +/* RES_CHRATR_BACKGROUND */ OutCSS1_SvxBrush, // Neu: Zeichenhintergrund +/* RES_CHRATR_CJK_FONT */ OutCSS1_SvxFont, +/* RES_CHRATR_CJK_FONTSIZE */ OutCSS1_SvxFontHeight, +/* RES_CHRATR_CJK_LANGUAGE */ OutCSS1_SvxLanguage, +/* RES_CHRATR_CJK_POSTURE */ OutCSS1_SvxPosture, +/* RES_CHRATR_CJK_WEIGHT */ OutCSS1_SvxFontWeight, +/* RES_CHRATR_CTL_FONT */ OutCSS1_SvxFont, +/* RES_CHRATR_CTL_FONTSIZE */ OutCSS1_SvxFontHeight, +/* RES_CHRATR_CTL_LANGUAGE */ OutCSS1_SvxLanguage, +/* RES_CHRATR_CTL_POSTURE */ OutCSS1_SvxPosture, +/* RES_CHRATR_CTL_WEIGHT */ OutCSS1_SvxFontWeight, +/* 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 */ OutCSS1_SvxOverline, +/* RES_CHRATR_DUMMY1 */ 0, +/* RES_CHRATR_DUMMY2 */ 0, + +/* RES_TXTATR_REFMARK */ 0, +/* RES_TXTATR_TOXMARK */ 0, +/* RES_TXTATR_META */ 0, +/* RES_TXTATR_METAFIELD */ 0, +/* RES_TXTATR_AUTOFMT */ 0, +/* RES_TXTATR_INETFMT */ 0, +/* RES_TXTATR_CHARFMT */ 0, +/* RES_TXTATR_CJK_RUBY */ 0, +/* RES_TXTATR_UNKNOWN_CONTAINER */ 0, +/* RES_TXTATR_DUMMY5 */ 0, + +/* RES_TXTATR_FIELD */ 0, +/* RES_TXTATR_FLYCNT */ 0, +/* RES_TXTATR_FTN */ 0, +/* RES_TXTATR_DUMMY4 */ 0, +/* RES_TXTATR_DUMMY3 */ 0, +/* RES_TXTATR_DUMMY1 */ 0, // Dummy: +/* RES_TXTATR_DUMMY2 */ 0, // Dummy: + +/* RES_PARATR_LINESPACING */ OutCSS1_SvxLineSpacing, +/* RES_PARATR_ADJUST */ OutCSS1_SvxAdjust, +/* RES_PARATR_SPLIT */ OutCSS1_SvxFmtSplit, +/* RES_PARATR_WIDOWS */ OutCSS1_SvxWidows, +/* RES_PARATR_ORPHANS */ OutCSS1_SvxOrphans, +/* RES_PARATR_TABSTOP */ 0, +/* RES_PARATR_HYPHENZONE*/ 0, +/* RES_PARATR_DROP */ OutCSS1_SwFmtDrop, +/* 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_OUTLINELEVEL */ 0, // new since cws outlinelevel + +/* 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 */ OutCSS1_SvxLRSpace, +/* RES_UL_SPACE */ OutCSS1_SvxULSpace, +/* 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 */ OutCSS1_SvxBrush, +/* RES_BOX */ OutCSS1_SvxBox, +/* 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_CHAIN */ 0, +/* RES_TEXTGRID */ 0, +/* RES_LINENUMBER */ 0, +/* RES_FTN_AT_TXTEND */ 0, +/* RES_END_AT_TXTEND */ 0, +/* RES_COLUMNBALANCE */ 0, +/* RES_FRAMEDIR */ OutCSS1_SvxFrameDirection, +/* RES_HEADER_FOOTER_EAT_SPACING */ 0, +/* 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 +}; diff --git a/sw/source/filter/html/css1kywd.cxx b/sw/source/filter/html/css1kywd.cxx new file mode 100644 index 000000000000..63d319a8ac12 --- /dev/null +++ b/sw/source/filter/html/css1kywd.cxx @@ -0,0 +1,281 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include "css1kywd.hxx" + +/* */ + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS_mimetype, "text/css" ); + +/* */ + +// ein par allgemeine Strings + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_import, "import" ); + +// Feature: PrintExt +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_page, "page" ); +//sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_media, "media" ); +// /Feature: PrintExt + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_important, "important" ); + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_link, "link" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_visited, "visited" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_first_letter, "first-letter" ); + +// Feature: PrintExt +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_left, "left" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_right, "right" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_first, "first" ); +// /Feature: PrintExt + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_url, "url" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_rgb, "rgb" ); + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_UNIT_pt, "pt" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_UNIT_mm, "mm" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_UNIT_cm, "cm" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_UNIT_pc, "pc" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_UNIT_inch, "in" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_UNIT_px, "px" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_UNIT_em, "em" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_UNIT_ex, "ex" ); + +/* */ + +// Strings fuer Font-Properties + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_font_family, "font-family" ); + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_serif, "serif" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_sans_serif, "sans-serif" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_cursive, "cursive" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_fantasy, "fantasy" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_monospace, "monospace" ); + + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_font_style, "font-style" ); + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_normal, "normal" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_italic, "italic" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_oblique, "oblique" ); + + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_font_variant, "font-variant" ); + +//sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_normal, "normal" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_small_caps, "small-caps" ); + + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_font_weight, "font-weight" ); + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_extra_light, "extra-light" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_light, "light" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_demi_light, "demi-light" ); +//sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_medium, "medium" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_demi_bold, "demi-bold" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_bold, "bold" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_extra_bold, "extra-bold" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_lighter, "lighter" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_bolder, "bolder" ); + + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_font_size, "font-size" ); + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_xx_small, "xx-small" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_x_small, "x-small" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_small, "small" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_medium, "medium" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_large, "large" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_x_large, "x-large" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_xx_large, "xx-large" ); + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_larger, "larger" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_smaller, "smaller" ); + + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_font, "font" ); + + + +/* */ + +// Strings fuer Farb- und Hintergrund-Properties + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_color, "color" ); + + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_background, "background" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_background_color, "background-color" ); + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_transparent, "transparent" ); + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_repeat, "repeat" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_repeat_x, "repeat-x" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_repeat_y, "repeat-y" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_no_repeat, "no-repeat" ); + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_top, "top" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_middle, "middle" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_bottom, "bottom" ); + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_scroll, "scroll" ); + + +/* */ + +// Strings fuer Text-Properties + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_letter_spacing, "letter-spacing" ); + + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_text_decoration, "text-decoration" ); + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_none, "none" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_underline, "underline" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_overline, "overline" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_line_through, "line-through" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_blink, "blink" ); + + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_text_align, "text-align" ); + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_left, "left" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_center, "center" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_right, "right" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_justify, "justify" ); + + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_text_indent, "text-indent" ); + + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_line_height, "line-height" ); + + +/* */ + +// Strings fuer Box-Properties + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_margin_left, "margin-left" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_margin_right, "margin-right" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_margin_top, "margin-top" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_margin_bottom, "margin-bottom" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_margin, "margin" ); + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_padding_top, "padding-top" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_padding_bottom, "padding-bottom" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_padding_left, "padding-left" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_padding_right, "padding-right" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_padding, "padding" ); + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_auto, "auto" ); + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_border_left_width, "border-left-width" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_border_right_width, "border-right-width" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_border_top_width, "border-top-width" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_border_bottom_width, "border-bottom-width" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_border_width, "border-width" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_border_color, "border-color" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_border_style, "border-style" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_border_left, "border-left" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_border_right, "border-right" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_border_top, "border-top" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_border_bottom, "border-bottom" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_border, "border" ); + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_thin, "thin" ); +//sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_medium, "medium" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_thick, "thick" ); + +//sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_none, "none" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_dotted, "dotted" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_dashed, "dashed" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_solid, "solid" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_double, "double" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_groove, "groove" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_ridge, "ridge" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_inset, "inset" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_outset, "outset" ); + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_width, "width" ); + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_height, "height" ); + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_float, "float" ); + +/* */ + +// Strings fuer Positioning + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_position, "position" ); + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_absolute, "absolute" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_relative, "relative" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_static, "static" ); + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_left, "left" ); + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_top, "top" ); + +/* */ + +// Feature: PrintExt + +// Strings fuer Printing Extensions + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_page_break_before, "page-break-before" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_page_break_after, "page-break-after" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_page_break_inside, "page-break-inside" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_size, "size" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_widows, "widows" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_orphans, "orphans" ); +//sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_marks, "marks" ); + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_always, "always" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_avoid, "avoid" ); + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_portrait, "portrait" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_landscape, "landscape" ); + +//sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_crop, "crop" ); +//sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_cross, "cross" ); + +// /Feature: PrintExt + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_class_abs_pos, "sd-abs-pos" ); + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_so_language, "so-language" ); + +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_P_direction, "direction" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_ltr, "ltr" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_rtl, "rtl" ); +sal_Char __FAR_DATA CSS1_CONSTASCII_DEF( sCSS1_PV_inherit, "inherit" ); diff --git a/sw/source/filter/html/css1kywd.hxx b/sw/source/filter/html/css1kywd.hxx new file mode 100644 index 000000000000..7994ab32c616 --- /dev/null +++ b/sw/source/filter/html/css1kywd.hxx @@ -0,0 +1,291 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CSS1KYWD_HXX +#define _CSS1KYWD_HXX + +#include <tools/string.hxx> + +#ifndef CSS1_CONSTASCII_DECL +#define CSS1_CONSTASCII_DECL( n, s ) n[sizeof(s)] +#endif +#ifndef CSS1_CONSTASCII_DEF +#define CSS1_CONSTASCII_DEF( n, s ) n[sizeof(s)] = s +#endif + +/* */ + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS_mimetype, "text/css" ); + +/* */ + +// ein par allgemeine Strings + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_import, "import" ); + +// Feature: PrintExt +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_page, "page" ); +//sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_media, "media" ); +// /Feature: PrintExt + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_important, "important" ); + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_link, "link" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_visited, "visited" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_first_letter, "first-letter" ); + +// Feature: PrintExt +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_left, "left" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_right, "right" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_first, "first" ); +// /Feature: PrintExt + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_url, "url" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_rgb, "rgb" ); + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_UNIT_pt, "pt" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_UNIT_mm, "mm" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_UNIT_cm, "cm" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_UNIT_pc, "pc" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_UNIT_inch, "in" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_UNIT_px, "px" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_UNIT_em, "em" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_UNIT_ex, "ex" ); + +/* */ + +// Strings fuer Font-Properties + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_font_family, "font-family" ); + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_serif, "serif" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_sans_serif, "sans-serif" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_cursive, "cursive" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_fantasy, "fantasy" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_monospace, "monospace" ); + + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_font_style, "font-style" ); + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_normal, "normal" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_italic, "italic" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_oblique, "oblique" ); + + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_font_variant, "font-variant" ); + +//sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_normal, "normal" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_small_caps, "small-caps" ); + + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_font_weight, "font-weight" ); + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_extra_light, "extra-light" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_light, "light" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_demi_light, "demi-light" ); +//sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_medium, "medium" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_demi_bold, "demi-bold" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_bold, "bold" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_extra_bold, "extra-bold" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_lighter, "lighter" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_bolder, "bolder" ); + + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_font_size, "font-size" ); + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_xx_small, "xx-small" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_x_small, "x-small" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_small, "small" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_medium, "medium" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_large, "large" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_x_large, "x-large" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_xx_large, "xx-large" ); + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_larger, "larger" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_smaller, "smaller" ); + + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_font, "font" ); + + + +/* */ + +// Strings fuer Farb- und Hintergrund-Properties + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_color, "color" ); + + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_background, "background" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_background_color, "background-color" ); + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_transparent, "transparent" ); + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_repeat, "repeat" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_repeat_x, "repeat-x" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_repeat_y, "repeat-y" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_no_repeat, "no-repeat" ); + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_top, "top" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_middle, "middle" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_bottom, "bottom" ); + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_scroll, "scroll" ); + + +/* */ + +// Strings fuer Text-Properties + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_letter_spacing, "letter-spacing" ); + + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_text_decoration, "text-decoration" ); + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_none, "none" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_underline, "underline" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_overline, "overline" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_line_through, "line-through" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_blink, "blink" ); + + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_text_align, "text-align" ); + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_left, "left" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_center, "center" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_right, "right" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_justify, "justify" ); + + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_text_indent, "text-indent" ); + + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_line_height, "line-height" ); + + +/* */ + +// Strings fuer Box-Properties + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_margin_left, "margin-left" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_margin_right, "margin-right" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_margin_top, "margin-top" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_margin_bottom, "margin-bottom" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_margin, "margin" ); + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_padding_top, "padding-top" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_padding_bottom, "padding-bottom" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_padding_left, "padding-left" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_padding_right, "padding-right" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_padding, "padding" ); + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_auto, "auto" ); + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_border_left_width, "border-left-width" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_border_right_width, "border-right-width" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_border_top_width, "border-top-width" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_border_bottom_width, "border-bottom-width" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_border_width, "border-width" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_border_color, "border-color" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_border_style, "border-style" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_border_left, "border-left" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_border_right, "border-right" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_border_top, "border-top" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_border_bottom, "border-bottom" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_border, "border" ); + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_thin, "thin" ); +//sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_medium, "medium" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_thick, "thick" ); + +//sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_none, "none" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_dotted, "dotted" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_dashed, "dashed" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_solid, "solid" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_double, "double" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_groove, "groove" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_ridge, "ridge" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_inset, "inset" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_outset, "outset" ); + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_width, "width" ); + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_height, "height" ); + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_float, "float" ); + +/* */ + +// Strings fuer Positioning + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_position, "position" ); + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_absolute, "absolute" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_relative, "relative" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_static, "static" ); + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_left, "left" ); + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_top, "top" ); + +/* */ + +// Feature: PrintExt + +// Strings fuer Printing Extensions + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_page_break_before, "page-break-before" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_page_break_after, "page-break-after" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_page_break_inside, "page-break-inside" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_size, "size" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_widows, "widows" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_orphans, "orphans" ); +//sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_marks, "marks" ); + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_always, "always" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_avoid, "avoid" ); + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_portrait, "portrait" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_landscape, "landscape" ); + +//sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_crop, "crop" ); +//sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_cross, "cross" ); + +// /Feature: PrintExt + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_class_abs_pos, "sd-abs-pos" ); + + +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_so_language, "so-language" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_P_direction, "direction" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_ltr, "ltr" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_rtl, "rtl" ); +extern sal_Char __FAR_DATA CSS1_CONSTASCII_DECL( sCSS1_PV_inherit, "inherit" ); + +#endif + + diff --git a/sw/source/filter/html/htmlatr.cxx b/sw/source/filter/html/htmlatr.cxx new file mode 100644 index 000000000000..c057db76e72c --- /dev/null +++ b/sw/source/filter/html/htmlatr.cxx @@ -0,0 +1,3494 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <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( RES_TXTATR_FIELD == pHt->Which() ) // Felder nicht + continue; // ausgeben + + if ( pHt->GetEnd() && !pHt->HasDummyChar() ) + { + xub_StrLen nHtEnd = *pHt->GetEnd(), + 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->GetEnd() && !pHt->HasDummyChar() ) + { + if( RES_CHRATR_KERNING == pHt->Which() && + rHTMLWrt.IsHTMLMode(HTMLMODE_FIRSTLINE) && + *pHt->GetEnd() - 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->GetEnd() != 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->GetEnd() + 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()).GetFld()->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 ) + { + sal_Unicode c = rStr.GetChar( nStrPos ); + // versuche nach ungefaehr 255 Zeichen eine neue Zeile zu + // beginnen, aber nicht in PRE und nur bei Spaces + 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 = 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 ); + } + else + HTMLOutFuncs::Out_Char( rWrt.Strm(), c, aContext, &rHTMLWrt.aNonConvertableCharacters ); + + // Wenn das letzte Zeichen eines Absatzed ein harter + // Zeilen-Umbruch ist brauchen wir noch ein <BR> mehr, weil + // Netscape & Co in diesem Fall fuer den naechsten Absatz + // nicht in die naechste Zeile gehen. + 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 + 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, + +/* 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_DUMMY5 */ 0, + +/* RES_TXTATR_FIELD */ OutHTML_SwFmtFld, +/* RES_TXTATR_FLYCNT */ OutHTML_SwFlyCnt, +/* RES_TXTATR_FTN */ OutHTML_SwFmtFtn, +/* RES_TXTATR_DUMMY4 */ 0, +/* 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 +}; diff --git a/sw/source/filter/html/htmlbas.cxx b/sw/source/filter/html/htmlbas.cxx new file mode 100644 index 000000000000..da10cc927b35 --- /dev/null +++ b/sw/source/filter/html/htmlbas.cxx @@ -0,0 +1,363 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <hintids.hxx> + +#include <sfx2/sfx.hrc> + +#define _SVSTDARR_STRINGSSORTDTOR +#include <svl/svstdarr.hxx> +#include <basic/sbx.hxx> +#include <basic/basmgr.hxx> +#include <basic/sbmod.hxx> +#include <sfx2/evntconf.hxx> +#include <sfx2/app.hxx> +#include <svtools/htmlout.hxx> +#include <svtools/htmltokn.h> +#include <svtools/htmlkywd.hxx> + +#include <com/sun/star/document/XEventsSupplier.hpp> +#include <com/sun/star/uno/Reference.hxx> + +#include <fmtornt.hxx> +#include <fmtfld.hxx> + +#include "doc.hxx" +#include "docsh.hxx" +#include "docufld.hxx" +#include "wrthtml.hxx" +#include "swhtml.hxx" + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::container; + + +static HTMLOutEvent __FAR_DATA aBodyEventTable[] = +{ + { OOO_STRING_SVTOOLS_HTML_O_SDonload, OOO_STRING_SVTOOLS_HTML_O_onload, SFX_EVENT_OPENDOC }, + { OOO_STRING_SVTOOLS_HTML_O_SDonunload, OOO_STRING_SVTOOLS_HTML_O_onunload, SFX_EVENT_PREPARECLOSEDOC }, + { OOO_STRING_SVTOOLS_HTML_O_SDonfocus, OOO_STRING_SVTOOLS_HTML_O_onfocus, SFX_EVENT_ACTIVATEDOC }, + { OOO_STRING_SVTOOLS_HTML_O_SDonblur, OOO_STRING_SVTOOLS_HTML_O_onblur, SFX_EVENT_DEACTIVATEDOC }, + { 0, 0, 0 } +}; + + +void SwHTMLParser::NewScript() +{ + ParseScriptOptions( aScriptType, sBaseURL, eScriptLang, aScriptURL, + aBasicLib, aBasicModule ); + + if( aScriptURL.Len() ) + { + // Den Inhalt des Script-Tags ignorieren + bIgnoreRawData = sal_True; + } +} + +void SwHTMLParser::EndScript() +{ + sal_Bool bInsIntoBasic = sal_False, + bInsSrcIntoFld = sal_False; + + switch( eScriptLang ) + { + case HTML_SL_STARBASIC: + bInsIntoBasic = sal_True; + break; + default: + bInsSrcIntoFld = sal_True; + break; + } + + bIgnoreRawData = sal_False; + aScriptSource.ConvertLineEnd(); + +// MIB 23.5.97: SGML-Kommentare brauchen nicht mehr entfernt zu werden, +// weil JS das jetzt selber kann. +// RemoveSGMLComment( aScriptSource, sal_True ); + + // Ausser StarBasic und unbenutzem JavaScript jedes Script oder den + // Modulnamen in einem Feld merken merken + if( bInsSrcIntoFld && !bIgnoreHTMLComments ) + { + SwScriptFieldType *pType = + (SwScriptFieldType*)pDoc->GetSysFldType( RES_SCRIPTFLD ); + + SwScriptField aFld( pType, aScriptType, + aScriptURL.Len() ? aScriptURL : aScriptSource, + aScriptURL.Len()!=0 ); + InsertAttr( SwFmtFld( aFld ) ); + } + + SwDocShell *pDocSh = pDoc->GetDocShell(); + if( aScriptSource.Len() && pDocSh && + bInsIntoBasic && IsNewDoc() ) + { + // Fuer JavaScript und StarBasic noch ein Basic-Modul anlegen + // Das Basic entfernt natuerlich weiterhin keine SGML-Kommentare + RemoveSGMLComment( aScriptSource, sal_True ); + + // get library name + ::rtl::OUString aLibName; + if( aBasicLib.Len() ) + aLibName = aBasicLib; + else + aLibName = ::rtl::OUString::createFromAscii( "Standard" ); + + // get module library container + Reference< script::XLibraryContainer > xModLibContainer( pDocSh->GetBasicContainer(), UNO_QUERY ); + + if ( xModLibContainer.is() ) + { + Reference< container::XNameContainer > xModLib; + if ( xModLibContainer->hasByName( aLibName ) ) + { + // get module library + Any aElement = xModLibContainer->getByName( aLibName ); + aElement >>= xModLib; + } + else + { + // create module library + xModLib = xModLibContainer->createLibrary( aLibName ); + } + + if ( xModLib.is() ) + { + if( !aBasicModule.Len() ) + { + // create module name + sal_Bool bFound = sal_True; + while( bFound ) + { + aBasicModule.AssignAscii( "Modul" ); + aBasicModule += String::CreateFromInt32( (sal_Int32)(++nSBModuleCnt) ); + bFound = xModLib->hasByName( ::rtl::OUString( aBasicModule ) ); + } + } + + // create module + ::rtl::OUString aModName( aBasicModule ); + if ( !xModLib->hasByName( aModName ) ) + { + Any aElement; + aElement <<= ::rtl::OUString( aScriptSource ); + xModLib->insertByName( aModName , aElement ); + } + } + } + + // get dialog library container + Reference< script::XLibraryContainer > xDlgLibContainer( pDocSh->GetDialogContainer(), UNO_QUERY ); + + if ( xDlgLibContainer.is() ) + { + if ( !xDlgLibContainer->hasByName( aLibName ) ) + { + // create dialog library + xDlgLibContainer->createLibrary( aLibName ); + } + } + } + + aScriptSource.Erase(); + aScriptType.Erase(); + aScriptURL.Erase(); + + aBasicLib.Erase(); + aBasicModule.Erase(); +} + +void SwHTMLParser::AddScriptSource() +{ + // Hier merken wir und nur ein par Strings + if( aToken.Len() > 2 && + (HTML_SL_STARBASIC==eScriptLang && aToken.GetChar( 0 ) == '\'') ) + { + xub_StrLen nPos = STRING_NOTFOUND; + if( !aBasicLib.Len() ) + { + nPos = aToken.SearchAscii( OOO_STRING_SVTOOLS_HTML_SB_library ); + if( nPos != STRING_NOTFOUND ) + { + aBasicLib = + aToken.Copy( nPos + sizeof(OOO_STRING_SVTOOLS_HTML_SB_library) - 1 ); + aBasicLib.EraseLeadingChars().EraseTrailingChars(); + } + } + + if( !aBasicModule.Len() && nPos==STRING_NOTFOUND ) + { + nPos = aToken.SearchAscii( OOO_STRING_SVTOOLS_HTML_SB_module ); + if( nPos != STRING_NOTFOUND ) + { + aBasicModule = + aToken.Copy( nPos + sizeof(OOO_STRING_SVTOOLS_HTML_SB_module) - 1 ); + aBasicModule.EraseLeadingChars().EraseTrailingChars(); + } + } + + if( nPos==STRING_NOTFOUND ) + { + if( aScriptSource.Len() ) + aScriptSource += '\n'; + (aScriptSource += aToken); + } + } + else if( aScriptSource.Len() || aToken.Len() ) + { + // Leerzeilen am Anfang werden ignoriert + if( aScriptSource.Len() ) + { + aScriptSource += '\n'; + } + else + { + // Wir stehen hinter dem CR/LF der Zeile davor + nScriptStartLineNr = GetLineNr() - 1; + } + aScriptSource += aToken; + } +} + +void SwHTMLParser::InsertBasicDocEvent( rtl::OUString aEvent, const String& rName, + ScriptType eScrType, + const String& rScrType ) +{ + ASSERT( rName.Len(), "InsertBasicDocEvent() ohne Macro gerufen" ); + if( !rName.Len() ) + return; + + SwDocShell *pDocSh = pDoc->GetDocShell(); + ASSERT( pDocSh, "Wo ist die DocShell?" ); + if( !pDocSh ) + return; + + String sEvent( rName ); + sEvent.ConvertLineEnd(); + String sScriptType; + if( EXTENDED_STYPE == eScrType ) + sScriptType = rScrType; + + rtl::OUString aEventName; + + SfxEventConfiguration::ConfigureEvent( aEvent, SvxMacro( sEvent, sScriptType, eScrType ), + pDocSh ); +} + +void SwHTMLWriter::OutBasic() +{ + if( !bCfgStarBasic ) + return; + + BasicManager *pBasicMan = pDoc->GetDocShell()->GetBasicManager(); + ASSERT( pBasicMan, "Wo ist der Basic-Manager?" ); + //JP 17.07.96: Bug 29538 - nur das DocumentBasic schreiben + if( !pBasicMan || pBasicMan == SFX_APP()->GetBasicManager() ) + { + return; + } + + // und jetzt alle StarBasic-Module und alle unbenutzen JavaSrript-Module + // ausgeben + for( sal_uInt16 i=0; i<pBasicMan->GetLibCount(); i++ ) + { + StarBASIC *pBasic = pBasicMan->GetLib( i ); + const String& rLibName = pBasic->GetName(); + + SbxArray *pModules = pBasic->GetModules(); + for( sal_uInt16 j=0; j<pModules->Count(); j++ ) + { + const SbModule *pModule = PTR_CAST( SbModule, pModules->Get(j) ); + ASSERT( pModule, "Wo ist das Modul?" ); + + String sLang( + String::CreateFromAscii( SVX_MACRO_LANGUAGE_STARBASIC ) ); + ScriptType eType = STARBASIC; + + if( 0==i && 0==j ) + { + OutNewLine(); + ByteString sOut( '<' ); + sOut.Append( OOO_STRING_SVTOOLS_HTML_meta ); + sOut.Append( ' ' ); + sOut.Append( OOO_STRING_SVTOOLS_HTML_O_httpequiv ); + sOut.Append( "=\"" ); + sOut.Append( OOO_STRING_SVTOOLS_HTML_META_content_script_type ); + sOut.Append( "\" " ); + sOut.Append( OOO_STRING_SVTOOLS_HTML_O_content ); + sOut.Append( "=\"text/x-" ); + Strm() << sOut.GetBuffer(); + // Entities aren't welcome here + ByteString sLang8( sLang, eDestEnc ); + Strm() << sLang8.GetBuffer() << "\">"; + } + + const String& rModName = pModule->GetName(); + Strm() << SwHTMLWriter::sNewLine; // nicht einruecken! + HTMLOutFuncs::OutScript( Strm(), GetBaseURL(), pModule->GetSource(), + sLang, eType, aEmptyStr, + &rLibName, &rModName, + eDestEnc, &aNonConvertableCharacters ); + } + } +} + +static const char* aEventNames[] = +{ + "OnLoad", "OnPrepareUnload", "OnFocus", "OnUnfocus" +}; + +void SwHTMLWriter::OutBasicBodyEvents() +{ + SwDocShell *pDocSh = pDoc->GetDocShell(); + if( !pDocSh ) + return; + + SvxMacroTableDtor *pDocTable = new SvxMacroTableDtor; + + uno::Reference< document::XEventsSupplier > xSup( pDocSh->GetModel(), uno::UNO_QUERY ); + uno::Reference < container::XNameReplace > xEvents = xSup->getEvents(); + for ( sal_Int32 i=0; i<4; i++ ) + { + SvxMacro* pMacro = SfxEventConfiguration::ConvertToMacro( xEvents->getByName( ::rtl::OUString::createFromAscii(aEventNames[i]) ), pDocSh, sal_True ); + if ( pMacro ) + pDocTable->Insert( aBodyEventTable[i].nEvent, pMacro ); + } + + if( pDocTable && pDocTable->Count() ) + HTMLOutFuncs::Out_Events( Strm(), *pDocTable, aBodyEventTable, + bCfgStarBasic, eDestEnc, &aNonConvertableCharacters ); +} + + diff --git a/sw/source/filter/html/htmlcss1.cxx b/sw/source/filter/html/htmlcss1.cxx new file mode 100644 index 000000000000..2287bddb9e21 --- /dev/null +++ b/sw/source/filter/html/htmlcss1.cxx @@ -0,0 +1,2477 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + + +#include "hintids.hxx" +#include <svl/itemiter.hxx> +#include <svl/whiter.hxx> +#include <svl/urihelper.hxx> +#include <i18npool/mslangid.hxx> +#include <sfx2/docfile.hxx> +#include <vcl/svapp.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/brshitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/boxitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/flstitem.hxx> +#include <editeng/brkitem.hxx> +#include <editeng/keepitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/langitem.hxx> +#include <editeng/frmdiritem.hxx> +#include <svtools/htmltokn.h> +#include <svtools/htmlkywd.hxx> +#include <fmtpdsc.hxx> +#include <fmtanchr.hxx> +#include <fmtornt.hxx> +#include <fmtsrnd.hxx> +#include <fmtfsize.hxx> +#include "frmatr.hxx" +#include <charfmt.hxx> +#include <docary.hxx> +#include <svx/svxids.hrc> + +#include "doc.hxx" +#include "pam.hxx" +#include "ndtxt.hxx" +#include "poolfmt.hxx" +#include "docsh.hxx" +#include "paratr.hxx" +#include "pagedesc.hxx" +#include "css1kywd.hxx" +#include "swcss1.hxx" +#include "htmlnum.hxx" +#include "swhtml.hxx" +#include <numrule.hxx> + +using namespace ::com::sun::star; + + +// Wie viele Zeilen/Zeichen sind fuer DropCaps erlaubt? +// (Gibt es vielleicht woanders entsprechende Werte?) +#define MAX_DROPCAP_LINES 9 +#define MAX_DROPCAP_CHARS 9 + +void lcl_swcss1_setEncoding( SwFmt& rFmt, rtl_TextEncoding eEnc ); + +/* */ + +// Implementierung des SwCSS1Parsers (eigentlich swcss1.cxx) +static struct SwCSS1ItemIds +{ + sal_uInt16 nFmtBreak; + sal_uInt16 nFmtPageDesc; + sal_uInt16 nFmtKeep; + + SwCSS1ItemIds() : + nFmtBreak( RES_BREAK ), + nFmtPageDesc( RES_PAGEDESC ), + nFmtKeep( RES_KEEP ) + {} + +} aItemIds; + +void SwCSS1Parser::ChgPageDesc( const SwPageDesc *pPageDesc, + const SwPageDesc& rNewPageDesc ) +{ + sal_uInt16 nPageDescs = pDoc->GetPageDescCnt(); + sal_uInt16 i; + for( i=0; i<nPageDescs; i++ ) + if( pPageDesc == &(const_cast<const SwDoc *>(pDoc)->GetPageDesc(i)) ) + { + pDoc->ChgPageDesc( i, rNewPageDesc ); + return; + } + + ASSERT( i<nPageDescs, "Seitenvorlage nicht gefunden" ); +} + +SwCSS1Parser::SwCSS1Parser( SwDoc *pD, sal_uInt32 aFHeights[7], const String& rBaseURL, sal_Bool bNewDoc ) : + SvxCSS1Parser( pD->GetAttrPool(), rBaseURL, MM50/2, + (sal_uInt16*)&aItemIds, sizeof(aItemIds) / sizeof(sal_uInt16) ), + pDoc( pD ), + nDropCapCnt( 0 ), + bIsNewDoc( bNewDoc ), + bBodyBGColorSet( sal_False ), + bBodyBackgroundSet( sal_False ), + bBodyTextSet( sal_False ), + bBodyLinkSet( sal_False ), + bBodyVLinkSet( sal_False ), + bSetFirstPageDesc( sal_False ), + bSetRightPageDesc( sal_False ), + bTableHeaderTxtCollSet( sal_False ), + bTableTxtCollSet( sal_False ), + bLinkCharFmtsSet( sal_False ) +{ + aFontHeights[0] = aFHeights[0]; + aFontHeights[1] = aFHeights[1]; + aFontHeights[2] = aFHeights[2]; + aFontHeights[3] = aFHeights[3]; + aFontHeights[4] = aFHeights[4]; + aFontHeights[5] = aFHeights[5]; + aFontHeights[6] = aFHeights[6]; +} + +SwCSS1Parser::~SwCSS1Parser() +{ +} + + +/* */ + +// Feature: PrintExt +sal_Bool SwCSS1Parser::SetFmtBreak( SfxItemSet& rItemSet, + const SvxCSS1PropertyInfo& rPropInfo ) +{ + SvxBreak eBreak = SVX_BREAK_NONE; + sal_Bool bKeep = sal_False; + sal_Bool bSetKeep = sal_False, bSetBreak = sal_False, bSetPageDesc = sal_False; + const SwPageDesc *pPageDesc = 0; + switch( rPropInfo.ePageBreakBefore ) + { + case SVX_CSS1_PBREAK_ALWAYS: + eBreak = SVX_BREAK_PAGE_BEFORE; + bSetBreak = sal_True; + break; + case SVX_CSS1_PBREAK_LEFT: + pPageDesc = GetLeftPageDesc( sal_True ); + bSetPageDesc = sal_True; + break; + case SVX_CSS1_PBREAK_RIGHT: + pPageDesc = GetRightPageDesc( sal_True ); + bSetPageDesc = sal_True; + break; + case SVX_CSS1_PBREAK_AUTO: + bSetBreak = bSetPageDesc = sal_True; + break; +// case SVX_CSS1_PBREAK_AVOID: + // Hier koennte man SvxKeepItem am Absatz davor einfuegen +// break; + default: + ; + } + switch( rPropInfo.ePageBreakAfter ) + { + case SVX_CSS1_PBREAK_ALWAYS: + case SVX_CSS1_PBREAK_LEFT: + case SVX_CSS1_PBREAK_RIGHT: + // LEFT/RIGHT koennte man auch am Absatz davor setzen + eBreak = SVX_BREAK_PAGE_AFTER; + bSetBreak = sal_True; + break; + case SVX_CSS1_PBREAK_AUTO: + bSetBreak = bSetKeep = bSetPageDesc = sal_True; + break; + case SVX_CSS1_PBREAK_AVOID: + bKeep = bSetKeep = sal_True; + break; + default: + ; + } + + if( bSetBreak ) + rItemSet.Put( SvxFmtBreakItem( eBreak, RES_BREAK ) ); + if( bSetPageDesc ) + rItemSet.Put( SwFmtPageDesc( pPageDesc ) ); + if( bSetKeep ) + rItemSet.Put( SvxFmtKeepItem( bKeep, RES_KEEP ) ); + + return bSetBreak; +} +// /Feature: PrintExt + +static void SetCharFmtAttrs( SwCharFmt *pCharFmt, SfxItemSet& rItemSet ) +{ + const SfxPoolItem *pItem; + static sal_uInt16 aWhichIds[3] = { RES_CHRATR_FONTSIZE,RES_CHRATR_CJK_FONTSIZE, + RES_CHRATR_CTL_FONTSIZE }; + for( sal_uInt16 i=0; i<3; i++ ) + { + if( SFX_ITEM_SET == rItemSet.GetItemState( aWhichIds[i], sal_False, + &pItem ) && + ((const SvxFontHeightItem *)pItem)->GetProp() != 100) + { + // %-Angaben beim FontHeight-Item werden nicht unterstuetzt + rItemSet.ClearItem( aWhichIds[i] ); + } + } + + pCharFmt->SetFmtAttr( rItemSet ); + + if( SFX_ITEM_SET == rItemSet.GetItemState( RES_BACKGROUND, sal_False, &pItem ) ) + { + // Ein Brush-Item mit RES_BACKGROUND muss noch in eines mit + // RES_CHRATR_BACKGROUND gewandelt werden + + SvxBrushItem aBrushItem( *(const SvxBrushItem *)pItem ); + aBrushItem.SetWhich( RES_CHRATR_BACKGROUND ); + pCharFmt->SetFmtAttr( aBrushItem ); + } +} + +void SwCSS1Parser::SetLinkCharFmts() +{ + ASSERT( !bLinkCharFmtsSet, "Aufruf von SetLinkCharFmts unnoetig" ); + + SvxCSS1MapEntry *pStyleEntry = + GetTag( String::CreateFromAscii(OOO_STRING_SVTOOLS_HTML_anchor) ); + SwCharFmt *pUnvisited = 0, *pVisited = 0; + if( pStyleEntry ) + { + SfxItemSet& rItemSet = pStyleEntry->GetItemSet(); + sal_Bool bColorSet = (SFX_ITEM_SET==rItemSet.GetItemState(RES_CHRATR_COLOR, + sal_False)); + pUnvisited = GetCharFmtFromPool( RES_POOLCHR_INET_NORMAL ); + SetCharFmtAttrs( pUnvisited, rItemSet ); + bBodyLinkSet |= bColorSet; + + pVisited = GetCharFmtFromPool( RES_POOLCHR_INET_VISIT ); + SetCharFmtAttrs( pVisited, rItemSet ); + bBodyVLinkSet |= bColorSet; + } + + String sTmp( String::CreateFromAscii(OOO_STRING_SVTOOLS_HTML_anchor) ); + sTmp.Append( ':' ); + sTmp.AppendAscii( sCSS1_link ); + pStyleEntry = GetTag( sTmp ); + if( pStyleEntry ) + { + SfxItemSet& rItemSet = pStyleEntry->GetItemSet(); + sal_Bool bColorSet = (SFX_ITEM_SET==rItemSet.GetItemState(RES_CHRATR_COLOR, + sal_False)); + if( !pUnvisited ) + pUnvisited = GetCharFmtFromPool( RES_POOLCHR_INET_NORMAL ); + SetCharFmtAttrs( pUnvisited, rItemSet ); + bBodyLinkSet |= bColorSet; + } + + sTmp.AssignAscii( OOO_STRING_SVTOOLS_HTML_anchor ); + sTmp.Assign( ':' ); + sTmp.AppendAscii( sCSS1_visited ); + pStyleEntry = GetTag( sTmp ); + if( pStyleEntry ) + { + SfxItemSet& rItemSet = pStyleEntry->GetItemSet(); + sal_Bool bColorSet = (SFX_ITEM_SET==rItemSet.GetItemState(RES_CHRATR_COLOR, + sal_False)); + if( !pVisited ) + pVisited = GetCharFmtFromPool( RES_POOLCHR_INET_VISIT ); + SetCharFmtAttrs( pVisited, rItemSet ); + bBodyVLinkSet |= bColorSet; + } + + bLinkCharFmtsSet = sal_True; +} + +static void SetTxtCollAttrs( SwTxtFmtColl *pColl, SfxItemSet& rItemSet, + SvxCSS1PropertyInfo& rPropInfo, + SwCSS1Parser *pCSS1Parser ) +{ + const SfxItemSet& rCollItemSet = pColl->GetAttrSet(); + const SfxPoolItem *pCollItem, *pItem; + + // linker, rechter Rand und Erstzeilen-Einzug + if( (rPropInfo.bLeftMargin || rPropInfo.bRightMargin || + rPropInfo.bTextIndent) && + (!rPropInfo.bLeftMargin || !rPropInfo.bRightMargin || + !rPropInfo.bTextIndent) && + SFX_ITEM_SET == rCollItemSet.GetItemState(RES_LR_SPACE,sal_True,&pCollItem) && + SFX_ITEM_SET == rItemSet.GetItemState(RES_LR_SPACE,sal_False,&pItem) ) + { + const SvxLRSpaceItem *pLRItem = (const SvxLRSpaceItem *)pItem; + + SvxLRSpaceItem aLRItem( *((const SvxLRSpaceItem *)pCollItem) ); + if( rPropInfo.bLeftMargin ) + aLRItem.SetTxtLeft( pLRItem->GetTxtLeft() ); + if( rPropInfo.bRightMargin ) + aLRItem.SetRight( pLRItem->GetRight() ); + if( rPropInfo.bTextIndent ) + aLRItem.SetTxtFirstLineOfst( pLRItem->GetTxtFirstLineOfst() ); + + rItemSet.Put( aLRItem ); + } + + // oberer und unterer Rand + if( (rPropInfo.bTopMargin || rPropInfo.bBottomMargin) && + (!rPropInfo.bTopMargin || !rPropInfo.bBottomMargin) && + SFX_ITEM_SET == rCollItemSet.GetItemState(RES_UL_SPACE,sal_True, + &pCollItem) && + SFX_ITEM_SET == rItemSet.GetItemState(RES_UL_SPACE,sal_False,&pItem) ) + { + const SvxULSpaceItem *pULItem = (const SvxULSpaceItem *)pItem; + + SvxULSpaceItem aULItem( *((const SvxULSpaceItem *)pCollItem) ); + if( rPropInfo.bTopMargin ) + aULItem.SetUpper( pULItem->GetUpper() ); + if( rPropInfo.bBottomMargin ) + aULItem.SetLower( pULItem->GetLower() ); + + rItemSet.Put( aULItem ); + } + + static sal_uInt16 aWhichIds[3] = { RES_CHRATR_FONTSIZE,RES_CHRATR_CJK_FONTSIZE, + RES_CHRATR_CTL_FONTSIZE }; + for( sal_uInt16 i=0; i<3; i++ ) + { + if( SFX_ITEM_SET == rItemSet.GetItemState( aWhichIds[i], sal_False, + &pItem ) && + ((const SvxFontHeightItem *)pItem)->GetProp() != 100) + { + // %-Angaben beim FontHeight-Item werden nicht unterstuetzt + rItemSet.ClearItem( aWhichIds[i] ); + } + } + +// Feature: PrintExt + pCSS1Parser->SetFmtBreak( rItemSet, rPropInfo ); +// /Feature: PrintExt + + pColl->SetFmtAttr( rItemSet ); +} + +void SwCSS1Parser::SetTableTxtColl( sal_Bool bHeader ) +{ + ASSERT( !(bHeader ? bTableHeaderTxtCollSet : bTableTxtCollSet), + "Aufruf von SetTableTxtColl unnoetig" ); + + sal_uInt16 nPoolId; + String sTag; + if( bHeader ) + { + nPoolId = RES_POOLCOLL_TABLE_HDLN; + sTag.AssignAscii( OOO_STRING_SVTOOLS_HTML_tableheader ); + } + else + { + nPoolId = RES_POOLCOLL_TABLE; + sTag.AssignAscii( OOO_STRING_SVTOOLS_HTML_tabledata ); + } + + SwTxtFmtColl *pColl = 0; + + // The following entries will never be used again and may be changed. + SvxCSS1MapEntry *pStyleEntry = GetTag( sTag ); + if( pStyleEntry ) + { + pColl = GetTxtFmtColl( nPoolId, aEmptyStr ); + SetTxtCollAttrs( pColl, pStyleEntry->GetItemSet(), + pStyleEntry->GetPropertyInfo(), this ); + } + + String sTmp( sTag ); + sTmp.Append( ' ' ); + sTmp.AppendAscii( OOO_STRING_SVTOOLS_HTML_parabreak ); + pStyleEntry = GetTag( sTmp ); + if( pStyleEntry ) + { + if( !pColl ) + pColl = GetTxtFmtColl( nPoolId, aEmptyStr ); + SetTxtCollAttrs( pColl, pStyleEntry->GetItemSet(), + pStyleEntry->GetPropertyInfo(), this ); + } + + if( bHeader ) + bTableHeaderTxtCollSet = sal_True; + else + bTableTxtCollSet = sal_True; +} + +void SwCSS1Parser::SetPageDescAttrs( const SvxBrushItem *pBrush, + SfxItemSet *pItemSet2 ) +{ + SvxBrushItem aBrushItem( RES_BACKGROUND ); + SvxBoxItem aBoxItem( RES_BOX ); + SvxFrameDirectionItem aFrmDirItem(FRMDIR_ENVIRONMENT, RES_FRAMEDIR); + sal_Bool bSetBrush = pBrush!=0, bSetBox = sal_False, bSetFrmDir = sal_False; + if( pBrush ) + aBrushItem = *pBrush; + + if( pItemSet2 ) + { + const SfxPoolItem *pItem = 0; + if( SFX_ITEM_SET == pItemSet2->GetItemState( RES_BACKGROUND, sal_False, + &pItem ) ) + { + // ein Hintergrund wird gesetzt + aBrushItem = *((const SvxBrushItem *)pItem); + pItemSet2->ClearItem( RES_BACKGROUND ); + bSetBrush = sal_True; + } + + if( SFX_ITEM_SET == pItemSet2->GetItemState( RES_BOX, sal_False, &pItem ) ) + { + // eine Umrandung wird gesetzt + aBoxItem = *((const SvxBoxItem *)pItem); + pItemSet2->ClearItem( RES_BOX ); + bSetBox = sal_True; + } + + if( SFX_ITEM_SET == pItemSet2->GetItemState( RES_BOX, sal_False, &pItem ) ) + { + // eine Umrandung wird gesetzt + aBoxItem = *((const SvxBoxItem *)pItem); + pItemSet2->ClearItem( RES_BOX ); + bSetBox = sal_True; + } + + if( SFX_ITEM_SET == pItemSet2->GetItemState( RES_FRAMEDIR, sal_False, &pItem ) ) + { + // eine Umrandung wird gesetzt + aFrmDirItem = *static_cast< const SvxFrameDirectionItem *>( pItem ); + pItemSet2->ClearItem( RES_FRAMEDIR ); + bSetFrmDir = sal_True; + } + } + + if( bSetBrush || bSetBox || bSetFrmDir ) + { + static sal_uInt16 aPoolIds[] = { RES_POOLPAGE_HTML, RES_POOLPAGE_FIRST, + RES_POOLPAGE_LEFT, RES_POOLPAGE_RIGHT }; + for( sal_uInt16 i=0; i<4; i++ ) + { + const SwPageDesc *pPageDesc = GetPageDesc( aPoolIds[i], sal_False ); + if( pPageDesc ) + { + SwPageDesc aNewPageDesc( *pPageDesc ); + SwFrmFmt &rMaster = aNewPageDesc.GetMaster(); + if( bSetBrush ) + rMaster.SetFmtAttr( aBrushItem ); + if( bSetBox ) + rMaster.SetFmtAttr( aBoxItem ); + if( bSetFrmDir ) + rMaster.SetFmtAttr( aFrmDirItem ); + + ChgPageDesc( pPageDesc, aNewPageDesc ); + } + } + } +} + +// Feature: PrintExt +void SwCSS1Parser::SetPageDescAttrs( const SwPageDesc *pPageDesc, + SfxItemSet& rItemSet, + const SvxCSS1PropertyInfo& rPropInfo ) +{ + if( !pPageDesc ) + return; + + SwPageDesc aNewPageDesc( *pPageDesc ); + SwFrmFmt &rMaster = aNewPageDesc.GetMaster(); + const SfxItemSet& rPageItemSet = rMaster.GetAttrSet(); + const SfxPoolItem *pPageItem, *pItem; + sal_Bool bChanged = sal_False; + + // linker, rechter Rand und Erstzeilen-Einzug + if( (rPropInfo.bLeftMargin || rPropInfo.bRightMargin) && + SFX_ITEM_SET == rItemSet.GetItemState(RES_LR_SPACE,sal_False,&pItem) ) + { + if( (!rPropInfo.bLeftMargin || !rPropInfo.bRightMargin) && + SFX_ITEM_SET == rPageItemSet.GetItemState(RES_LR_SPACE, + sal_True,&pPageItem) ) + { + const SvxLRSpaceItem *pLRItem = (const SvxLRSpaceItem *)pItem; + + SvxLRSpaceItem aLRItem( *((const SvxLRSpaceItem *)pPageItem) ); + if( rPropInfo.bLeftMargin ) + aLRItem.SetLeft( pLRItem->GetLeft() ); + if( rPropInfo.bRightMargin ) + aLRItem.SetRight( pLRItem->GetRight() ); + + rMaster.SetFmtAttr( aLRItem ); + } + else + { + rMaster.SetFmtAttr( *pItem ); + } + bChanged = sal_True; + } + + // oberer und unterer Rand + if( (rPropInfo.bTopMargin || rPropInfo.bBottomMargin) && + SFX_ITEM_SET == rItemSet.GetItemState(RES_UL_SPACE,sal_False,&pItem) ) + { + if( (!rPropInfo.bTopMargin || !rPropInfo.bBottomMargin) && + SFX_ITEM_SET == rPageItemSet.GetItemState(RES_UL_SPACE, + sal_True,&pPageItem) ) + { + const SvxULSpaceItem *pULItem = (const SvxULSpaceItem *)pItem; + + SvxULSpaceItem aULItem( *((const SvxULSpaceItem *)pPageItem) ); + if( rPropInfo.bTopMargin ) + aULItem.SetUpper( pULItem->GetUpper() ); + if( rPropInfo.bBottomMargin ) + aULItem.SetLower( pULItem->GetLower() ); + + rMaster.SetFmtAttr( aULItem ); + } + else + { + rMaster.SetFmtAttr( *pItem ); + } + bChanged = sal_True; + } + + // die Groesse + if( rPropInfo.eSizeType != SVX_CSS1_STYPE_NONE ) + { + if( rPropInfo.eSizeType == SVX_CSS1_STYPE_TWIP ) + { + rMaster.SetFmtAttr( SwFmtFrmSize( ATT_FIX_SIZE, rPropInfo.nWidth, + rPropInfo.nHeight ) ); + bChanged = sal_True; + } + else + { + // Bei "size: auto|portrait|landscape" bleibt die bisherige + // Groesse der Vorlage erhalten. Bei "landscape" und "portrait" + // wird das Landscape-Flag gesetzt und evtl. die Breite/Hoehe + // vertauscht. + SwFmtFrmSize aFrmSz( rMaster.GetFrmSize() ); + sal_Bool bLandscape = aNewPageDesc.GetLandscape(); + if( ( bLandscape && + rPropInfo.eSizeType == SVX_CSS1_STYPE_PORTRAIT ) || + ( !bLandscape && + rPropInfo.eSizeType == SVX_CSS1_STYPE_LANDSCAPE ) ) + { + SwTwips nTmp = aFrmSz.GetHeight(); + aFrmSz.SetHeight( aFrmSz.GetWidth() ); + aFrmSz.SetWidth( nTmp ); + rMaster.SetFmtAttr( aFrmSz ); + aNewPageDesc.SetLandscape( !bLandscape ); + bChanged = sal_True; + } + } + } + + // Geht das wirklich? + if( SFX_ITEM_SET == rItemSet.GetItemState( RES_BACKGROUND, sal_False, &pItem ) ) + { + // eine Umrandung wird gesetzt + rMaster.SetFmtAttr( *pItem ); + rItemSet.ClearItem( RES_BACKGROUND ); + bChanged = sal_True; + } + + if( bChanged ) + ChgPageDesc( pPageDesc, aNewPageDesc ); +} +// /Feature: PrintExt + +const SvxBrushItem& SwCSS1Parser::GetPageDescBackground() const +{ + return pDoc->GetPageDescFromPool( RES_POOLPAGE_HTML, false ) + ->GetMaster().GetBackground(); +} + +sal_uInt16 SwCSS1Parser::GetScriptFromClass( String& rClass, + sal_Bool bSubClassOnly ) +{ + sal_uInt16 nScriptFlags = CSS1_SCRIPT_ALL; + xub_StrLen nLen = rClass.Len(); + xub_StrLen nPos = nLen > 4 ? rClass.SearchBackward( '-' ) : STRING_NOTFOUND; + + if( STRING_NOTFOUND == nPos ) + { + if( bSubClassOnly ) + return nScriptFlags; + nPos = 0; + } + else + { + nPos++; + nLen = nLen - nPos; + } + + switch( nLen ) + { + case 3: + if( rClass.EqualsIgnoreCaseAscii( "cjk", nPos, 3 ) ) + { + nScriptFlags = CSS1_SCRIPT_CJK; + } + else if( rClass.EqualsIgnoreCaseAscii( "ctl", nPos, 3 ) ) + { + nScriptFlags = CSS1_SCRIPT_CTL; + } + break; + case 7: + if( rClass.EqualsIgnoreCaseAscii( "western", nPos, 7 ) ) + { + nScriptFlags = CSS1_SCRIPT_WESTERN; + } + break; + } + if( CSS1_SCRIPT_ALL != nScriptFlags ) + { + if( nPos ) + { + rClass.Erase( nPos-1 ); + } + else + { + rClass.Erase(); + } + } + + return nScriptFlags; +} + +static CSS1SelectorType GetTokenAndClass( const CSS1Selector *pSelector, + String& rToken, String& rClass, + sal_uInt16& rScriptFlags ) +{ + rToken = pSelector->GetString(); + rClass.Erase(); + rScriptFlags = CSS1_SCRIPT_ALL; + + CSS1SelectorType eType = pSelector->GetType(); + if( CSS1_SELTYPE_ELEM_CLASS==eType ) + { + xub_StrLen nPos = rToken.Search( '.' ); + ASSERT( nPos != STRING_NOTFOUND, "kein Punkt in Class-Selektor???" ); + if( nPos != STRING_NOTFOUND ) + { + rClass = rToken.Copy( nPos+1 ); + rToken.Erase( nPos ); + + rScriptFlags = SwCSS1Parser::GetScriptFromClass( rClass, sal_False ); + if( !rClass.Len() ) + eType = CSS1_SELTYPE_ELEMENT; + } + } + + rToken.ToUpperAscii(); + return eType; +} + +extern sal_Bool lcl_css1atr_equalFontItems( const SfxPoolItem& r1, const SfxPoolItem& r2 ); + +static void RemoveScriptItems( SfxItemSet& rItemSet, sal_uInt16 nScript, + const SfxItemSet *pParentItemSet = 0 ) +{ + static sal_uInt16 aWhichIds[3][5] = + { + { RES_CHRATR_FONT, RES_CHRATR_FONTSIZE, RES_CHRATR_LANGUAGE, + RES_CHRATR_POSTURE, RES_CHRATR_WEIGHT }, + { RES_CHRATR_CJK_FONT, RES_CHRATR_CJK_FONTSIZE, RES_CHRATR_CJK_LANGUAGE, + RES_CHRATR_CJK_POSTURE, RES_CHRATR_CJK_WEIGHT }, + { RES_CHRATR_CTL_FONT, RES_CHRATR_CTL_FONTSIZE, RES_CHRATR_CTL_LANGUAGE, + RES_CHRATR_CTL_POSTURE, RES_CHRATR_CTL_WEIGHT } + }; + + sal_uInt16 aClearItems[3] = { sal_False, sal_False, sal_False }; + switch( nScript ) + { + case CSS1_SCRIPT_WESTERN: + aClearItems[1] = aClearItems[2] = sal_True; + break; + case CSS1_SCRIPT_CJK: + aClearItems[0] = aClearItems[2] = sal_True; + break; + case CSS1_SCRIPT_CTL: + aClearItems[0] = aClearItems[1] = sal_True; + break; + case CSS1_SCRIPT_ALL: + break; + default: + ASSERT( aClearItems[0], "unknown script type" ); + break; + } + + for( sal_uInt16 j=0; j < 3; j++ ) + { + for( sal_uInt16 i=0; i < 5; i++ ) + { + sal_uInt16 nWhich = aWhichIds[j][i]; + const SfxPoolItem *pItem; + if( aClearItems[j] || + (pParentItemSet && + SFX_ITEM_SET == rItemSet.GetItemState( nWhich, sal_False, &pItem ) && + (0==i ? lcl_css1atr_equalFontItems( *pItem, pParentItemSet->Get(nWhich, sal_True ) ) + : *pItem == pParentItemSet->Get(nWhich, sal_True ) ) ) ) + { + rItemSet.ClearItem( nWhich ); + } + } + } +} + +sal_Bool SwCSS1Parser::StyleParsed( const CSS1Selector *pSelector, + SfxItemSet& rItemSet, + SvxCSS1PropertyInfo& rPropInfo ) +{ + if( !bIsNewDoc ) + return sal_True; + + CSS1SelectorType eSelType = pSelector->GetType(); + const CSS1Selector *pNext = pSelector->GetNext(); + + if( CSS1_SELTYPE_ID==eSelType && !pNext ) + { + InsertId( pSelector->GetString(), rItemSet, rPropInfo ); + } + else if( CSS1_SELTYPE_CLASS==eSelType && !pNext ) + { + String aClass( pSelector->GetString() ); + sal_uInt16 nScript = GetScriptFromClass( aClass ); + if( CSS1_SCRIPT_ALL != nScript ) + { + SfxItemSet aScriptItemSet( rItemSet ); + RemoveScriptItems( aScriptItemSet, nScript ); + InsertClass( aClass, aScriptItemSet, rPropInfo ); + } + else + { + InsertClass( aClass, rItemSet, rPropInfo ); + } + } + else if( CSS1_SELTYPE_PAGE==eSelType ) + { + if( !pNext || + (CSS1_SELTYPE_PSEUDO == pNext->GetType() && + (pNext->GetString().EqualsIgnoreCaseAscii(sCSS1_left) || + pNext->GetString().EqualsIgnoreCaseAscii(sCSS1_right) || + pNext->GetString().EqualsIgnoreCaseAscii(sCSS1_first)) ) ) + // || CSS1_SELTYPE_ELEMENT == pNext->GetType() ) + { + String aName; + if( pNext ) + aName = pNext->GetString(); + InsertPage( aName, + pNext != 0 /*CSS1_SELTYPE_PSEUDO == pNext->GetType()*/, + rItemSet, rPropInfo ); + } + } + + if( CSS1_SELTYPE_ELEMENT != eSelType && + CSS1_SELTYPE_ELEM_CLASS != eSelType) + return sal_True; + + // Token und Class zu dem Selektor holen + String aToken2, aClass; + sal_uInt16 nScript; + eSelType = GetTokenAndClass( pSelector, aToken2, aClass, nScript ); + int nToken2 = GetHTMLToken( aToken2 ); + + // und noch ein ganz par Infos zum naechsten Element + CSS1SelectorType eNextType = pNext ? pNext->GetType() + : CSS1_SELTYPE_ELEMENT; + + // Erstmal ein par Spezialfaelle + if( CSS1_SELTYPE_ELEMENT==eSelType ) + { + switch( nToken2 ) + { + case HTML_ANCHOR_ON: + if( !pNext ) + { + InsertTag( aToken2, rItemSet, rPropInfo ); + return sal_False; + } + else if( pNext && CSS1_SELTYPE_PSEUDO == eNextType ) + { + // vielleicht A:visited oder A:link + + String aPseudo( pNext->GetString() ); + aPseudo.ToLowerAscii(); + + sal_Bool bInsert = sal_False; + switch( aPseudo.GetChar( 0 )) + { + case 'l': + if( aPseudo.EqualsAscii(sCSS1_link) ) + { + bInsert = sal_True; + } + break; + case 'v': + if( aPseudo.EqualsAscii(sCSS1_visited) ) + { + bInsert = sal_True; + } + break; + } + if( bInsert ) + { + String sTmp( aToken2 ); + (sTmp += ':') += aPseudo; + if( CSS1_SCRIPT_ALL != nScript ) + { + SfxItemSet aScriptItemSet( rItemSet ); + RemoveScriptItems( aScriptItemSet, nScript ); + InsertTag( sTmp, aScriptItemSet, rPropInfo ); + } + else + { + InsertTag( sTmp, rItemSet, rPropInfo ); + } + return sal_False; + } + } + break; + case HTML_BODY_ON: + if( !pNext ) + { + // BODY + + // Den Hintergrund muessen wir vor dem Setzen abfragen, + // denn in SetPageDescAttrs wird er geloescht. + const SfxPoolItem *pItem; + if( SFX_ITEM_SET==rItemSet.GetItemState(RES_BACKGROUND,sal_False,&pItem) ) + { + const SvxBrushItem *pBrushItem = + (const SvxBrushItem *)pItem; + + /// OD 02.09.2002 #99657# + /// Body has a background color, if it is not "no fill"/"auto fill" + if( pBrushItem->GetColor() != COL_TRANSPARENT ) + bBodyBGColorSet = sal_True; + if( GPOS_NONE != pBrushItem->GetGraphicPos() ) + bBodyBackgroundSet = sal_True; + } + + // Border and Padding + rPropInfo.SetBoxItem( rItemSet, MIN_BORDER_DIST ); + + // Ein par Attribute muessen an der Seitenvorlage gesetzt werden, + // und zwar die, die nicht vererbt werden + SetPageDescAttrs( 0, &rItemSet ); + + // alle noch uebrigen Optionen koennen an der Standard-Vorlage + // gesetzt werden und gelten dann automatisch als defaults + if( SFX_ITEM_SET==rItemSet.GetItemState(RES_CHRATR_COLOR,sal_False) ) + bBodyTextSet = sal_True; + SetTxtCollAttrs( + GetTxtCollFromPool( RES_POOLCOLL_STANDARD ), + rItemSet, rPropInfo, this ); + + return sal_False; + } + break; + } + } + else if( CSS1_SELTYPE_ELEM_CLASS==eSelType && HTML_ANCHOR_ON==nToken2 && + !pNext && aClass.Len() >= 9 && + ('s' == aClass.GetChar(0) || 'S' == aClass.GetChar(0)) ) + { + sal_uInt16 nPoolFmtId = 0; + if( aClass.EqualsIgnoreCaseAscii(OOO_STRING_SVTOOLS_HTML_sdendnote_sym) ) + nPoolFmtId = RES_POOLCHR_ENDNOTE; + else if( aClass.EqualsIgnoreCaseAscii(OOO_STRING_SVTOOLS_HTML_sdfootnote_sym) ) + nPoolFmtId = RES_POOLCHR_FOOTNOTE; + if( nPoolFmtId ) + { + if( CSS1_SCRIPT_ALL == nScript ) + { + SetCharFmtAttrs( GetCharFmtFromPool(nPoolFmtId), rItemSet ); + } + else + { + SfxItemSet aScriptItemSet( rItemSet ); + RemoveScriptItems( aScriptItemSet, nScript ); + SetCharFmtAttrs( GetCharFmtFromPool(nPoolFmtId), + aScriptItemSet); + } + return sal_False; + } + } + + // Jetzt werden die Selektoren verarbeitet, die zu einer Absatz-Vorlage + // gehoehren + sal_uInt16 nPoolCollId = 0; + switch( nToken2 ) + { + case HTML_HEAD1_ON: + nPoolCollId = RES_POOLCOLL_HEADLINE1; + break; + case HTML_HEAD2_ON: + nPoolCollId = RES_POOLCOLL_HEADLINE2; + break; + case HTML_HEAD3_ON: + nPoolCollId = RES_POOLCOLL_HEADLINE3; + break; + case HTML_HEAD4_ON: + nPoolCollId = RES_POOLCOLL_HEADLINE4; + break; + case HTML_HEAD5_ON: + nPoolCollId = RES_POOLCOLL_HEADLINE5; + break; + case HTML_HEAD6_ON: + nPoolCollId = RES_POOLCOLL_HEADLINE6; + break; + case HTML_PARABREAK_ON: + if( aClass.Len() >= 9 && + ('s' == aClass.GetChar(0) || 'S' == aClass.GetChar(0)) ) + { + if( aClass.EqualsIgnoreCaseAscii(OOO_STRING_SVTOOLS_HTML_sdendnote) ) + nPoolCollId = RES_POOLCOLL_ENDNOTE; + else if( aClass.EqualsIgnoreCaseAscii(OOO_STRING_SVTOOLS_HTML_sdfootnote) ) + nPoolCollId = RES_POOLCOLL_FOOTNOTE; + + if( nPoolCollId ) + aClass = aEmptyStr; + else + nPoolCollId = RES_POOLCOLL_TEXT; + } + else + { + nPoolCollId = RES_POOLCOLL_TEXT; + } + break; + case HTML_ADDRESS_ON: + nPoolCollId = RES_POOLCOLL_SENDADRESS; + break; + case HTML_BLOCKQUOTE_ON: + nPoolCollId = RES_POOLCOLL_HTML_BLOCKQUOTE; + break; + case HTML_DT_ON: + nPoolCollId = RES_POOLCOLL_HTML_DT; + break; + case HTML_DD_ON: + nPoolCollId = RES_POOLCOLL_HTML_DD; + break; + case HTML_PREFORMTXT_ON: + nPoolCollId = RES_POOLCOLL_HTML_PRE; + break; + case HTML_TABLEHEADER_ON: + case HTML_TABLEDATA_ON: + if( CSS1_SELTYPE_ELEMENT==eSelType && !pNext ) + { + InsertTag( aToken2, rItemSet, rPropInfo ); + return sal_False; + } + else if( CSS1_SELTYPE_ELEMENT==eSelType && pNext && + (CSS1_SELTYPE_ELEMENT==eNextType || + CSS1_SELTYPE_ELEM_CLASS==eNextType) ) + { + // nicht TH und TD, aber TH P und TD P + String aSubToken, aSubClass; + GetTokenAndClass( pNext, aSubToken, aSubClass, nScript ); + if( HTML_PARABREAK_ON == GetHTMLToken( aSubToken ) ) + { + aClass = aSubClass; + pNext = pNext->GetNext(); + eNextType = pNext ? pNext->GetType() : CSS1_SELTYPE_ELEMENT; + + if( aClass.Len() || pNext ) + { + nPoolCollId = static_cast< sal_uInt16 >( + HTML_TABLEHEADER_ON == nToken2 ? RES_POOLCOLL_TABLE_HDLN + : RES_POOLCOLL_TABLE ); + } + else + { + String sTmp( aToken2 ); + sTmp += ' '; + sTmp.AppendAscii( OOO_STRING_SVTOOLS_HTML_parabreak ); + + if( CSS1_SCRIPT_ALL == nScript ) + { + InsertTag( sTmp, rItemSet, rPropInfo ); + } + else + { + SfxItemSet aScriptItemSet( rItemSet ); + RemoveScriptItems( aScriptItemSet, nScript ); + InsertTag( sTmp, aScriptItemSet, rPropInfo ); + } + + return sal_False; + } + } + } + break; + + default: + ; + } + + if( nPoolCollId ) + { + if( !pNext || + (CSS1_SELTYPE_PSEUDO==eNextType && +#ifdef FULL_FIRST_LETTER + pNext->GetString().EqualsIgnoreCaseAscii(sCSS1_first_letter)) ) +#else + pNext->GetString().EqualsIgnoreCaseAscii(sCSS1_first_letter) && + SVX_ADJUST_LEFT == rPropInfo.eFloat) ) +#endif + { + // Entweder kein zusammengesetzter Selektor oder + // ein X:first-line { float: left; ... } + + // Die Vorlage Suchen bzw. Anlegen + SwTxtFmtColl *pColl = GetTxtFmtColl( nPoolCollId, aEmptyStr ); + SwTxtFmtColl* pParentColl = 0; + if( aClass.Len() ) + { + String aName( pColl->GetName() ); + AddClassName( aName, aClass ); + + pParentColl = pColl; + pColl = pDoc->FindTxtFmtCollByName( aName ); + if( !pColl ) + pColl = pDoc->MakeTxtFmtColl( aName, pParentColl ); + } + if( !pNext ) + { + // nur die Attribute an der Vorlage setzen + const SfxPoolItem *pItem; + const SvxBoxItem *pBoxItem = 0; + if( SFX_ITEM_SET == + pColl->GetAttrSet().GetItemState(RES_BOX,sal_True,&pItem) ) + pBoxItem = (const SvxBoxItem *)pItem; + rPropInfo.SetBoxItem( rItemSet, MIN_BORDER_DIST, pBoxItem ); + if( CSS1_SCRIPT_ALL == nScript && !pParentColl ) + { + SetTxtCollAttrs( pColl, rItemSet, rPropInfo, this ); + } + else + { + SfxItemSet aScriptItemSet( rItemSet ); + RemoveScriptItems( aScriptItemSet, nScript, + pParentColl ? &pParentColl->GetAttrSet() : 0 ); + SetTxtCollAttrs( pColl, aScriptItemSet, rPropInfo, this ); + } + } + else + { + // ein Drop-Cap-Attribut basteln + SwFmtDrop aDrop( pColl->GetDrop() ); + aDrop.GetChars() = 1; + + // die Attribute in das DropCap-Attribut einfuegen + if( CSS1_SCRIPT_ALL == nScript ) + { + FillDropCap( aDrop, rItemSet, &pColl->GetName() ); + } + else + { + SfxItemSet aScriptItemSet( rItemSet ); + if( CSS1_SCRIPT_WESTERN != nScript ) + { + aScriptItemSet.ClearItem( RES_CHRATR_FONT ); + aScriptItemSet.ClearItem( RES_CHRATR_LANGUAGE ); + aScriptItemSet.ClearItem( RES_CHRATR_POSTURE ); + aScriptItemSet.ClearItem( RES_CHRATR_WEIGHT ); + } + if( CSS1_SCRIPT_CJK != nScript ) + { + aScriptItemSet.ClearItem( RES_CHRATR_CJK_FONT ); + aScriptItemSet.ClearItem( RES_CHRATR_CJK_LANGUAGE ); + aScriptItemSet.ClearItem( RES_CHRATR_CJK_POSTURE ); + aScriptItemSet.ClearItem( RES_CHRATR_CJK_WEIGHT ); + } + if( CSS1_SCRIPT_CTL != nScript ) + { + aScriptItemSet.ClearItem( RES_CHRATR_CTL_FONT ); + aScriptItemSet.ClearItem( RES_CHRATR_CTL_LANGUAGE ); + aScriptItemSet.ClearItem( RES_CHRATR_CTL_POSTURE ); + aScriptItemSet.ClearItem( RES_CHRATR_CTL_WEIGHT ); + } + FillDropCap( aDrop, aScriptItemSet, &pColl->GetName() ); + } + + // Das Attribut nur setzen, wenn float: left angegeben wurde + // und das Initial ueber mehrere Zeilen geht. Sonst wird die + // ggf. angelegte Zeichen-Vorlage spaeter ueber den Namen + // gesucht und gesetzt. + if( aDrop.GetLines() > 1 && + (SVX_ADJUST_LEFT == rPropInfo.eFloat || + CSS1_SCRIPT_ALL == nScript) ) + { + pColl->SetFmtAttr( aDrop ); + } + } + + return sal_False; + } + + return sal_True; + } + + // Jetzt werden die Selektoten verarbeitet, die zu einer Zechenvorlage + // gehoehren. Zusammengesetzte gibt es hier allerdings nich nicht. + if( pNext ) + return sal_True; + + SwCharFmt *pCFmt = GetChrFmt( static_cast< sal_uInt16 >(nToken2), aEmptyStr ); + if( pCFmt ) + { + SwCharFmt *pParentCFmt = 0; + if( aClass.Len() ) + { + String aName( pCFmt->GetName() ); + AddClassName( aName, aClass ); + pParentCFmt = pCFmt; + + pCFmt = pDoc->FindCharFmtByName( aName ); + if( !pCFmt ) + { + pCFmt = pDoc->MakeCharFmt( aName, pParentCFmt ); + pCFmt->SetAuto( sal_False ); + } + } + + if( CSS1_SCRIPT_ALL == nScript && !pParentCFmt ) + { + SetCharFmtAttrs( pCFmt, rItemSet ); + } + else + { + SfxItemSet aScriptItemSet( rItemSet ); + RemoveScriptItems( aScriptItemSet, nScript, + pParentCFmt ? &pParentCFmt->GetAttrSet() : 0 ); + SetCharFmtAttrs( pCFmt, aScriptItemSet ); + } + return sal_False; + } + + return sal_True; +} + +sal_uInt32 SwCSS1Parser::GetFontHeight( sal_uInt16 nSize ) const +{ + return aFontHeights[ nSize>6 ? 6 : nSize ]; +} + +const FontList *SwCSS1Parser::GetFontList() const +{ + const FontList *pFList = 0; + SwDocShell *pDocSh = pDoc->GetDocShell(); + if( pDocSh ) + { + const SvxFontListItem *pFListItem = + (const SvxFontListItem *)pDocSh->GetItem(SID_ATTR_CHAR_FONTLIST); + if( pFListItem ) + pFList = pFListItem->GetFontList(); + } + + return pFList; +} + +/* */ + +SwCharFmt* SwCSS1Parser::GetChrFmt( sal_uInt16 nToken2, const String& rClass ) const +{ + // die entsprechende Vorlage suchen + sal_uInt16 nPoolId = 0; + const sal_Char* sName = 0; + switch( nToken2 ) + { + case HTML_EMPHASIS_ON: nPoolId = RES_POOLCHR_HTML_EMPHASIS; break; + case HTML_CITIATION_ON: nPoolId = RES_POOLCHR_HTML_CITIATION; break; + case HTML_STRONG_ON: nPoolId = RES_POOLCHR_HTML_STRONG; break; + case HTML_CODE_ON: nPoolId = RES_POOLCHR_HTML_CODE; break; + case HTML_SAMPLE_ON: nPoolId = RES_POOLCHR_HTML_SAMPLE; break; + case HTML_KEYBOARD_ON: nPoolId = RES_POOLCHR_HTML_KEYBOARD; break; + case HTML_VARIABLE_ON: nPoolId = RES_POOLCHR_HTML_VARIABLE; break; + case HTML_DEFINSTANCE_ON: nPoolId = RES_POOLCHR_HTML_DEFINSTANCE; break; + case HTML_TELETYPE_ON: nPoolId = RES_POOLCHR_HTML_TELETYPE; break; + + case HTML_SHORTQUOTE_ON: sName = OOO_STRING_SVTOOLS_HTML_shortquote; break; + case HTML_LANGUAGE_ON: sName = OOO_STRING_SVTOOLS_HTML_language; break; + case HTML_AUTHOR_ON: sName = OOO_STRING_SVTOOLS_HTML_author; break; + case HTML_PERSON_ON: sName = OOO_STRING_SVTOOLS_HTML_person; break; + case HTML_ACRONYM_ON: sName = OOO_STRING_SVTOOLS_HTML_acronym; break; + case HTML_ABBREVIATION_ON: sName = OOO_STRING_SVTOOLS_HTML_abbreviation; break; + case HTML_INSERTEDTEXT_ON: sName = OOO_STRING_SVTOOLS_HTML_insertedtext; break; + case HTML_DELETEDTEXT_ON: sName = OOO_STRING_SVTOOLS_HTML_deletedtext; break; + } + + // die Vorlage suchen oder anlegen (geht nur mit Namen) + if( !nPoolId && !sName ) + return 0; + + // Die Vorlage (ohne Class) suchen oder anlegen + SwCharFmt *pCFmt = 0; + if( nPoolId ) + { + pCFmt = GetCharFmtFromPool( nPoolId ); + } + else + { + String sCName( String::CreateFromAscii(sName) ); + pCFmt = pDoc->FindCharFmtByName( sCName ); + if( !pCFmt ) + { + pCFmt = pDoc->MakeCharFmt( sCName, pDoc->GetDfltCharFmt() ); + pCFmt->SetAuto( sal_False ); + } + } + + ASSERT( pCFmt, "Keine Zeichen-Vorlage???" ); + + // Wenn es eine Klasse gibt, die Klassen-Vorlage suchen aber nicht + // neu anlegen. + String aClass( rClass ); + GetScriptFromClass( aClass, sal_False ); + if( aClass.Len() ) + { + String aTmp( pCFmt->GetName() ); + AddClassName( aTmp, aClass ); + SwCharFmt *pClassCFmt = pDoc->FindCharFmtByName( aTmp ); + if( pClassCFmt ) + { + pCFmt = pClassCFmt; + } + else + { + SvxCSS1MapEntry *pClass = GetClass( aClass ); + if( pClass ) + { + pCFmt = pDoc->MakeCharFmt( aTmp, pCFmt ); + pCFmt->SetAuto( sal_False ); + SfxItemSet aItemSet( pClass->GetItemSet() ); + SetCharFmtAttrs( pCFmt, aItemSet ); + } + } + } + + return pCFmt; +} + + +/* */ + +SwTxtFmtColl *SwCSS1Parser::GetTxtCollFromPool( sal_uInt16 nPoolId ) const +{ + sal_uInt16 nOldArrLen = pDoc->GetTxtFmtColls()->Count(); + + SwTxtFmtColl *pColl = pDoc->GetTxtCollFromPool( nPoolId, false ); + + if( bIsNewDoc ) + { + sal_uInt16 nArrLen = pDoc->GetTxtFmtColls()->Count(); + for( sal_uInt16 i=nOldArrLen; i<nArrLen; i++ ) + lcl_swcss1_setEncoding( *(*pDoc->GetTxtFmtColls())[i], + GetDfltEncoding() ); + } + + return pColl; +} + +SwCharFmt *SwCSS1Parser::GetCharFmtFromPool( sal_uInt16 nPoolId ) const +{ + sal_uInt16 nOldArrLen = pDoc->GetCharFmts()->Count(); + + SwCharFmt *pCharFmt = pDoc->GetCharFmtFromPool( nPoolId ); + + if( bIsNewDoc ) + { + sal_uInt16 nArrLen = pDoc->GetCharFmts()->Count(); + + for( sal_uInt16 i=nOldArrLen; i<nArrLen; i++ ) + lcl_swcss1_setEncoding( *(*pDoc->GetCharFmts())[i], + GetDfltEncoding() ); + } + + return pCharFmt; +} + +SwTxtFmtColl *SwCSS1Parser::GetTxtFmtColl( sal_uInt16 nTxtColl, + const String& rClass ) +{ + SwTxtFmtColl* pColl = 0; + + String aClass( rClass ); + GetScriptFromClass( aClass, sal_False ); + if( RES_POOLCOLL_TEXT == nTxtColl && aClass.Len() >= 9 && + ('s' == aClass.GetChar(0) || 'S' == aClass.GetChar(0) ) ) + { + if( aClass.EqualsIgnoreCaseAscii(OOO_STRING_SVTOOLS_HTML_sdendnote) ) + { + nTxtColl = RES_POOLCOLL_ENDNOTE; + aClass = aEmptyStr; + } + else if( aClass.EqualsIgnoreCaseAscii(OOO_STRING_SVTOOLS_HTML_sdfootnote) ) + { + nTxtColl = RES_POOLCOLL_FOOTNOTE; + aClass = aEmptyStr; + } + } + + String sName; + if( USER_FMT & nTxtColl ) // eine vom Reader angelegte + { + ASSERT( !this, "Wo kommt die Benutzer-Vorlage her?" ); + pColl = GetTxtCollFromPool( RES_POOLCOLL_STANDARD ); + } + else + { + pColl = GetTxtCollFromPool( nTxtColl ); + } + + ASSERT( pColl, "Keine Absatz-Vorlage???" ); + if( aClass.Len() ) + { + String aTmp( pColl->GetName() ); + AddClassName( aTmp, aClass ); + SwTxtFmtColl* pClassColl = pDoc->FindTxtFmtCollByName( aTmp ); + + if( !pClassColl && + (nTxtColl==RES_POOLCOLL_TABLE || + nTxtColl==RES_POOLCOLL_TABLE_HDLN) ) + { + // Wenn dieser Fall eintritt, dann wurde ein <TD><P CLASS=foo> + // gelesen, aber die TD.foo Vorlage nicht gefunden. Dann muessen + // wir P.foo nehmen, wenn es sie gibt. + SwTxtFmtColl* pCollText = + GetTxtCollFromPool( RES_POOLCOLL_TEXT ); + aTmp = pCollText->GetName(); + AddClassName( aTmp, aClass ); + pClassColl = pDoc->FindTxtFmtCollByName( aTmp ); + } + + if( pClassColl ) + { + pColl = pClassColl; + } + else + { + const SvxCSS1MapEntry *pClass = GetClass( aClass ); + if( pClass ) + { + pColl = pDoc->MakeTxtFmtColl( aTmp, pColl ); + SfxItemSet aItemSet( pClass->GetItemSet() ); + SvxCSS1PropertyInfo aPropInfo( pClass->GetPropertyInfo() ); + aPropInfo.SetBoxItem( aItemSet, MIN_BORDER_DIST ); + sal_Bool bPositioned = MayBePositioned( pClass->GetPropertyInfo() ); + if( bPositioned ) + aItemSet.ClearItem( RES_BACKGROUND ); + SetTxtCollAttrs( pColl, aItemSet, aPropInfo, + this ); + } + } + + } + + if( pColl ) + lcl_swcss1_setEncoding( *pColl, GetDfltEncoding() ); + + return pColl; +} + +SwPageDesc *SwCSS1Parser::GetMasterPageDesc() +{ + return pDoc->GetPageDescFromPool( RES_POOLPAGE_HTML, false ); +} + +static SwPageDesc *FindPageDesc( SwDoc *pDoc, sal_uInt16 nPoolId, sal_uInt16& rPage ) +{ + sal_uInt16 nPageDescs = pDoc->GetPageDescCnt(); + for( rPage=0; rPage < nPageDescs && + const_cast<const SwDoc *>(pDoc)-> + GetPageDesc(rPage).GetPoolFmtId() != nPoolId; rPage++ ) + ; + + return rPage < nPageDescs ? &pDoc->_GetPageDesc( rPage ) : 0; +} + +const SwPageDesc *SwCSS1Parser::GetPageDesc( sal_uInt16 nPoolId, sal_Bool bCreate ) +{ + if( RES_POOLPAGE_HTML == nPoolId ) + return pDoc->GetPageDescFromPool( RES_POOLPAGE_HTML, false ); + + sal_uInt16 nPage; + const SwPageDesc *pPageDesc = FindPageDesc( pDoc, nPoolId, nPage ); + if( !pPageDesc && bCreate ) + { + // Die erste Seite wird aus der rechten Seite erzeugt, wenn es die + // gibt. + SwPageDesc *pMasterPageDesc = 0; + if( RES_POOLPAGE_FIRST == nPoolId ) + pMasterPageDesc = FindPageDesc( pDoc, RES_POOLPAGE_RIGHT, nPage ); + if( !pMasterPageDesc ) + pMasterPageDesc = pDoc->GetPageDescFromPool( RES_POOLPAGE_HTML, false ); + + // Die neue Seitenvorlage entsteht aus dem Master durch kopieren. + SwPageDesc *pNewPageDesc = pDoc-> + GetPageDescFromPool( nPoolId, false ); + + // dazu brauchen wir auch die Nummer der neuen Vorlage + pPageDesc = FindPageDesc( pDoc, nPoolId, nPage ); + ASSERT( pPageDesc==pNewPageDesc, "Seitenvorlage nicht gefunden" ); + + pDoc->CopyPageDesc( *pMasterPageDesc, *pNewPageDesc, sal_False ); + + // Die Vorlagen an ihren neuen Zweck anpassen. + const SwPageDesc *pFollow = 0; + sal_Bool bSetFollowFollow = sal_False; + switch( nPoolId ) + { + case RES_POOLPAGE_FIRST: + // Wenn es schon eine linke Seite gibt, dann ist das die + // Folge-Vorlage, sonst ist es die HTML-Vorlage. + pFollow = GetLeftPageDesc(); + if( !pFollow ) + pFollow = pMasterPageDesc; + break; + + case RES_POOLPAGE_RIGHT: + // Wenn die linke Vorlage schon angelegt ist, passiert hier gar + // nichts. Sonst wird die linke Vorlage angelegt und sorgt auch + // fuer die richtige Verkettung mit der rechten Voralge. + GetLeftPageDesc( sal_True ); + break; + + case RES_POOLPAGE_LEFT: + // Die rechte Vorlage wird angelegt, wenn sie noch nicht existiert. + // Es findet aber keine Verkettung statt. + // Wenn schon eine erste Seitenvorlage existiert, wird die linke + // Vorlage die Folge-Vorlage der ersten Seite. + pFollow = GetRightPageDesc( sal_True ); + bSetFollowFollow = sal_True; + { + const SwPageDesc *pFirstPageDesc = GetFirstPageDesc(); + if( pFirstPageDesc ) + { + SwPageDesc aNewFirstPageDesc( *pFirstPageDesc ); + aNewFirstPageDesc.SetFollow( pNewPageDesc ); + ChgPageDesc( pFirstPageDesc, aNewFirstPageDesc ); + } + } + break; + } + + if( pFollow ) + { + SwPageDesc aNewPageDesc( *pNewPageDesc ); + aNewPageDesc.SetFollow( pFollow ); + ChgPageDesc( pNewPageDesc, aNewPageDesc ); + + if( bSetFollowFollow ) + { + SwPageDesc aNewFollowPageDesc( *pFollow ); + aNewFollowPageDesc.SetFollow( pNewPageDesc ); + ChgPageDesc( pFollow, aNewFollowPageDesc ); + } + } + pPageDesc = pNewPageDesc; + } + + return pPageDesc; +} + + +sal_Bool SwCSS1Parser::MayBePositioned( const SvxCSS1PropertyInfo& rPropInfo, + sal_Bool bAutoWidth ) +{ + // abs-pos + // left/top none auto twip perc + // + // none Z Z - - + // auto Z Z - - + // twip Z Z S/R - + // perc - - - - + // + // - das Tag wird absolut positioniert und left/top sind beide + // gegeben und enthalten auch keine %-Angabe, oder + // - das Tag soll fliessen, und + // - es wurde eine Breite angegeben (in beiden Faellen noetig) + return ( ( SVX_CSS1_POS_ABSOLUTE == rPropInfo.ePosition && + SVX_CSS1_LTYPE_PERCENTAGE != rPropInfo.eLeftType && + SVX_CSS1_LTYPE_PERCENTAGE != rPropInfo.eTopType && + (SVX_CSS1_LTYPE_TWIP == rPropInfo.eLeftType || + SVX_CSS1_LTYPE_TWIP != rPropInfo.eTopType) ) || + ( SVX_ADJUST_END != rPropInfo.eFloat ) ) && + ( bAutoWidth || + SVX_CSS1_LTYPE_TWIP == rPropInfo.eWidthType || + SVX_CSS1_LTYPE_PERCENTAGE == rPropInfo.eWidthType ); +} + + +/* */ + +void SwCSS1Parser::AddClassName( String& rFmtName, const String& rClass ) +{ + ASSERT( rClass.Len(), "Style-Klasse ohne Laenge?" ); + +// ?????????? +// String aTmp( rClass ); +// GetpApp()->GetAppInternational().ToLower( aTmp ); + + (rFmtName += '.') += rClass; +} + +/* */ + +void SwCSS1Parser::FillDropCap( SwFmtDrop& rDrop, + SfxItemSet& rItemSet, + const String *pName ) +{ + // die Anzahl der Zeilen entspricht in etwa einer %-Angabe + // fuer die Hoehe (was passiert mit absoluten Hoehen???) + sal_uInt8 nLines = rDrop.GetLines(); + const SfxPoolItem *pItem; + if( SFX_ITEM_SET == rItemSet.GetItemState( RES_CHRATR_FONTSIZE, sal_False, &pItem ) ) + { + sal_uInt16 nProp = ((const SvxFontHeightItem *)pItem)->GetProp(); + nLines = (sal_uInt8)((nProp + 50) / 100); + if( nLines < 1 ) + nLines = 1; + else if( nLines > MAX_DROPCAP_LINES ) + nLines = MAX_DROPCAP_LINES; + + // Nur wenn nLines>1 ist, wird das Attribut auch gesetzt. Dann + // brauchen wir die Font-Hoehe aber auch nicht in der Zeichen-Vorlage. + if( nLines > 1 ) + { + rItemSet.ClearItem( RES_CHRATR_FONTSIZE ); + rItemSet.ClearItem( RES_CHRATR_CJK_FONTSIZE ); + rItemSet.ClearItem( RES_CHRATR_CTL_FONTSIZE ); + } + } + + // Bei harter Attributierung (pName==0) koennen wir aufhoehren, wenn + // das Initial nur ueber eine Zeile geht. +#ifdef FULL_FIRST_LETTER + if( nLines<=1 && !pName ) +#else + if( nLines<=1 ) +#endif + return; + + rDrop.GetLines() = nLines; + + // ein rechter Rand wird der Abstand zum Text! + if( SFX_ITEM_SET == rItemSet.GetItemState( RES_LR_SPACE, sal_False, &pItem ) ) + { + rDrop.GetDistance() = static_cast< sal_uInt16 >( + ((const SvxLRSpaceItem *)pItem)->GetRight() ); + rItemSet.ClearItem( RES_LR_SPACE ); + } + + // Fuer alle anderen Attribute eine Zeichen-Vorlage anlegen + if( rItemSet.Count() ) + { + SwCharFmt *pCFmt = 0; + String aName; + if( pName ) + { + aName = *pName; + AddFirstLetterExt( aName ); + pCFmt = pDoc->FindCharFmtByName( aName ); + } + else + { + do + { + aName.AssignAscii( sCSS1_first_letter ); + aName.Append( ' ' ); + aName.Append( + String::CreateFromInt32( (sal_Int32)(++nDropCapCnt) ) ); + } + while( pDoc->FindCharFmtByName(aName) ); + } + + if( !pCFmt ) + { + pCFmt = pDoc->MakeCharFmt( aName, pDoc->GetDfltCharFmt() ); + pCFmt->SetAuto( sal_False ); + } + SetCharFmtAttrs( pCFmt, rItemSet ); + + // Die Zeichenvorlage braucht nur im Attribut gesetzt werden, wenn + // auch das Attribut gesetzt wird. + if( nLines > 1 ) + rDrop.SetCharFmt( pCFmt ); + } +} + +/* */ + +// CSS1-sezifisches des SwHTMLParsers + +_HTMLAttr **SwHTMLParser::GetAttrTabEntry( sal_uInt16 nWhich ) +{ + // den zu dem Item gehoehrenden Tabellen-Eintrag ermitteln ... + _HTMLAttr **ppAttr = 0; + switch( nWhich ) + { + case RES_CHRATR_BLINK: + ppAttr = &aAttrTab.pBlink; + break; + case RES_CHRATR_CASEMAP: + ppAttr = &aAttrTab.pCaseMap; + break; + case RES_CHRATR_COLOR: + ppAttr = &aAttrTab.pFontColor; + break; + case RES_CHRATR_CROSSEDOUT: + ppAttr = &aAttrTab.pStrike; + break; + case RES_CHRATR_ESCAPEMENT: + ppAttr = &aAttrTab.pEscapement; + break; + case RES_CHRATR_FONT: + ppAttr = &aAttrTab.pFont; + break; + case RES_CHRATR_CJK_FONT: + ppAttr = &aAttrTab.pFontCJK; + break; + case RES_CHRATR_CTL_FONT: + ppAttr = &aAttrTab.pFontCTL; + break; + case RES_CHRATR_FONTSIZE: + ppAttr = &aAttrTab.pFontHeight; + break; + case RES_CHRATR_CJK_FONTSIZE: + ppAttr = &aAttrTab.pFontHeightCJK; + break; + case RES_CHRATR_CTL_FONTSIZE: + ppAttr = &aAttrTab.pFontHeightCTL; + break; + case RES_CHRATR_KERNING: + ppAttr = &aAttrTab.pKerning; + break; + case RES_CHRATR_POSTURE: + ppAttr = &aAttrTab.pItalic; + break; + case RES_CHRATR_CJK_POSTURE: + ppAttr = &aAttrTab.pItalicCJK; + break; + case RES_CHRATR_CTL_POSTURE: + ppAttr = &aAttrTab.pItalicCTL; + break; + case RES_CHRATR_UNDERLINE: + ppAttr = &aAttrTab.pUnderline; + break; + case RES_CHRATR_WEIGHT: + ppAttr = &aAttrTab.pBold; + break; + case RES_CHRATR_CJK_WEIGHT: + ppAttr = &aAttrTab.pBoldCJK; + break; + case RES_CHRATR_CTL_WEIGHT: + ppAttr = &aAttrTab.pBoldCTL; + break; + case RES_CHRATR_BACKGROUND: + ppAttr = &aAttrTab.pCharBrush; + break; + + case RES_PARATR_LINESPACING: + ppAttr = &aAttrTab.pLineSpacing; + break; + case RES_PARATR_ADJUST: + ppAttr = &aAttrTab.pAdjust; + break; + + case RES_LR_SPACE: + ppAttr = &aAttrTab.pLRSpace; + break; + case RES_UL_SPACE: + ppAttr = &aAttrTab.pULSpace; + break; + case RES_BOX: + ppAttr = &aAttrTab.pBox; + break; + case RES_BACKGROUND: + ppAttr = &aAttrTab.pBrush; + break; + case RES_BREAK: + ppAttr = &aAttrTab.pBreak; + break; + case RES_PAGEDESC: + ppAttr = &aAttrTab.pPageDesc; + break; + case RES_PARATR_SPLIT: + ppAttr = &aAttrTab.pSplit; + break; + case RES_PARATR_WIDOWS: + ppAttr = &aAttrTab.pWidows; + break; + case RES_PARATR_ORPHANS: + ppAttr = &aAttrTab.pOrphans; + break; + case RES_KEEP: + ppAttr = &aAttrTab.pKeep; + break; + + case RES_CHRATR_LANGUAGE: + ppAttr = &aAttrTab.pLanguage; + break; + case RES_CHRATR_CJK_LANGUAGE: + ppAttr = &aAttrTab.pLanguageCJK; + break; + case RES_CHRATR_CTL_LANGUAGE: + ppAttr = &aAttrTab.pLanguageCTL; + break; + + case RES_FRAMEDIR: + ppAttr = &aAttrTab.pDirection; + break; + } + + return ppAttr; +} + +void SwHTMLParser::NewStyle() +{ + String sType; + + const HTMLOptions *pOptions2 = GetOptions(); + for( sal_uInt16 i = pOptions2->Count(); i; ) + { + const HTMLOption *pOption = (*pOptions2)[--i]; + if( HTML_O_TYPE==pOption->GetToken() ) + sType = pOption->GetString(); + } + + bIgnoreRawData = sType.Len() && + !sType.GetToken(0,';').EqualsAscii(sCSS_mimetype); +} + +void SwHTMLParser::EndStyle() +{ + bIgnoreRawData = sal_False; + + if( aStyleSource.Len() ) + { + pCSS1Parser->ParseStyleSheet( aStyleSource ); + aStyleSource.Erase(); + } +} + +sal_Bool SwHTMLParser::FileDownload( const String& rURL, + String& rStr ) +{ + // View wegschmeissen (wegen Reschedule) + ViewShell *pOldVSh = CallEndAction(); + + // Ein Medium anlegen + SfxMedium aDLMedium( rURL, STREAM_READ | STREAM_SHARE_DENYWRITE, sal_False ); + + // Medium registrieren, damit abgebrochen werden kann + if( pDoc->GetDocShell() ) + pDoc->GetDocShell()->RegisterTransfer( aDLMedium ); + + SvStream* pStream = aDLMedium.GetInStream(); + if( pStream ) + { + SvMemoryStream aStream; + aStream << *pStream; + + aStream.Seek( STREAM_SEEK_TO_END ); + DBG_ASSERT( aStream.Tell() < STRING_MAXLEN, + "File zu lang fuer einen String, Ende abgeschnitten" ); + xub_StrLen nLen = aStream.Tell() < STRING_MAXLEN + ? (xub_StrLen)aStream.Tell() + : STRING_MAXLEN; + + rStr = String( (const sal_Char *)aStream.GetData(), nLen, + GetSrcEncoding() ); + } + + + // wurde abgebrochen? + if( ( pDoc->GetDocShell() && pDoc->GetDocShell()->IsAbortingImport() ) + || 1 == pDoc->getReferenceCount() ) + { + // wurde der Import vom SFX abgebrochen? + eState = SVPAR_ERROR; + pStream = 0; + } + + // View wieder anlgen +#if OSL_DEBUG_LEVEL > 1 + ViewShell *pVSh = +#endif + CallStartAction( pOldVSh ); +#if OSL_DEBUG_LEVEL > 1 + ASSERT( pOldVSh == pVSh, "FileDownload: ViewShell wurde ausgetauscht" ); + (void) pVSh; +#endif + + return pStream!=0; +} + +void SwHTMLParser::InsertLink() +{ + sal_Bool bFinishDownload = sal_False; + if( pPendStack ) + { + ASSERT( ShouldFinishFileDownload(), + "Pending-Stack ohne File-Download?" ); + + SwPendingStack* pTmp = pPendStack->pNext; + delete pPendStack; + pPendStack = pTmp; + ASSERT( !pPendStack, "Wo kommt der Pending-Stack her?" ); + + bFinishDownload = sal_True; + } + else + { + String sRel, sHRef, sType; + + const HTMLOptions *pOptions2 = GetOptions(); + for( sal_uInt16 i = pOptions2->Count(); i; ) + { + const HTMLOption *pOption = (*pOptions2)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_REL: + sRel = pOption->GetString(); + break; + case HTML_O_HREF: + sHRef = URIHelper::SmartRel2Abs( INetURLObject( sBaseURL ), pOption->GetString(), Link(), false ); + break; + case HTML_O_TYPE: + sType = pOption->GetString(); + break; + } + } + + if( sHRef.Len() && sRel.EqualsIgnoreCaseAscii( "STYLESHEET" ) && + ( !sType.Len() || + sType.GetToken(0,';').EqualsAscii(sCSS_mimetype) ) ) + { + if( GetMedium() ) + { + // Download des Style-Source starten + StartFileDownload( sHRef, 0, pDoc->GetDocShell() ); + if( IsParserWorking() ) + { + // Der Style wurde synchron geladen und wir koennen + // es direkt aufrufen. + bFinishDownload = sal_True; + } + else + { + // Der Style wird asynchron geladen und ist erst beim + // naechsten Continue-Aufruf da. Wir muessen deshalb einen + // Pending-Stack anlegen, damit wir hierher zurueckkehren + pPendStack = new SwPendingStack( HTML_LINK, pPendStack ); + } + } + else + { + // File synchron holen + String sSource; + if( FileDownload( sHRef, sSource ) ) + pCSS1Parser->ParseStyleSheet( sSource ); + } + } + } + + if( bFinishDownload ) + { + String sSource; + if( FinishFileDownload(sSource) && sSource.Len() ) + pCSS1Parser->ParseStyleSheet( sSource ); + } +} + +sal_Bool SwCSS1Parser::ParseStyleSheet( const String& rIn ) +{ + if( !SvxCSS1Parser::ParseStyleSheet( rIn ) ) + return sal_False; + + SwPageDesc *pMasterPageDesc = + pDoc->GetPageDescFromPool( RES_POOLPAGE_HTML, false ); + + SvxCSS1MapEntry *pPageEntry = GetPage( aEmptyStr, sal_False ); + if( pPageEntry ) + { + // @page (wirkt auf alle Seiten, die es schon gibt + + SetPageDescAttrs( pMasterPageDesc, pPageEntry->GetItemSet(), + pPageEntry->GetPropertyInfo() ); + + // Fuer alle anderen Seiten-Vorlagen, die es schon gibt, + // muessen die Attribute auch noch gesetzt werden + + SetPageDescAttrs( GetFirstPageDesc(), pPageEntry->GetItemSet(), + pPageEntry->GetPropertyInfo() ); + SetPageDescAttrs( GetLeftPageDesc(), pPageEntry->GetItemSet(), + pPageEntry->GetPropertyInfo() ); + SetPageDescAttrs( GetRightPageDesc(), pPageEntry->GetItemSet(), + pPageEntry->GetPropertyInfo() ); +// if( pNamedPageDescs ) +// { +// for( sal_uInt16 i=0; i<pNamedPageDescs->Count(); i++ ) +// SetPageDescAttrs( (*pNamedPageDescs)[i], +// pPageEntry->GetItemSet(), +// pPageEntry->GetPropertyInfo() ); +// } + + } + + pPageEntry = GetPage( String::CreateFromAscii(sCSS1_first), sal_True ); + if( pPageEntry ) + { + SetPageDescAttrs( GetFirstPageDesc(sal_True), pPageEntry->GetItemSet(), + pPageEntry->GetPropertyInfo() ); + bSetFirstPageDesc = sal_True; + } + + pPageEntry = GetPage( String::CreateFromAscii(sCSS1_right), sal_True ); + if( pPageEntry ) + { + SetPageDescAttrs( GetRightPageDesc(sal_True), pPageEntry->GetItemSet(), + pPageEntry->GetPropertyInfo() ); + bSetRightPageDesc = sal_True; + } + + pPageEntry = GetPage( String::CreateFromAscii(sCSS1_left), sal_True ); + if( pPageEntry ) + SetPageDescAttrs( GetLeftPageDesc(sal_True), pPageEntry->GetItemSet(), + pPageEntry->GetPropertyInfo() ); + + // und jetzt noch die benannten Vorlagen +// for( sal_uInt16 i=0; i < GetPageCount(); i++ ) +// { +// pPageEntry = GetPage( i ); +// const String& rKey = pPageEntry->GetKey(); +// if( !rKey.Len() || rKey.GetChar(0) == ':' ) +// continue; +// +// String aName( rKey ); +// GetpApp()->GetAppInternational().ToLower( aName ); +// sal_uInt16 nPage = pDoc->MakePageDesc( aName ); +// SwPageDesc *pPageDesc = &pDoc->_GetPageDesc( nPage ); +// +// // Die neue Seitenvorlage entsteht aus dem Master durch kopieren. +// pDoc->CopyPageDesc( *pMasterPageDesc, *pPageDesc ); +// SetPageDescAttrs( pPageDesc, pPageEntry->GetItemSet(), +// pPageEntry->GetPropertyInfo() ); +// +// if( !pNamedPageDescs ) +// pNamedPageDescs = new SwHTMLPageDescs; +// pNamedPageDescs->Insert( pPageDesc, pNamedPageDescs->Count() ); +// } + + return sal_True; +} + +sal_Bool SwHTMLParser::ParseStyleOptions( const String &rStyle, + const String &rId, + const String &rClass, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo &rPropInfo, + const String *pLang, + const String *pDir ) +{ + sal_Bool bRet = sal_False; + + if( rClass.Len() ) + { + String aClass( rClass ); + SwCSS1Parser::GetScriptFromClass( aClass ); + SvxCSS1MapEntry *pClass = pCSS1Parser->GetClass( aClass ); + if( pClass ) + { + pCSS1Parser->MergeStyles( pClass->GetItemSet(), + pClass->GetPropertyInfo(), + rItemSet, rPropInfo, sal_False ); + bRet = sal_True; + } + } + + if( rId.Len() ) + { + SvxCSS1MapEntry *pId = pCSS1Parser->GetId( rId ); + if( pId ) + pCSS1Parser->MergeStyles( pId->GetItemSet(), + pId->GetPropertyInfo(), + rItemSet, rPropInfo, rClass.Len()!=0 ); + rPropInfo.aId = rId; + bRet = sal_True; + } + + if( rStyle.Len() ) + { + pCSS1Parser->ParseStyleOption( rStyle, rItemSet, rPropInfo ); + bRet = sal_True; + } + + if( bRet ) + rPropInfo.SetBoxItem( rItemSet, MIN_BORDER_DIST ); + + if( pLang && pLang->Len() ) + { + LanguageType eLang = MsLangId::convertIsoStringToLanguage( *pLang ); + if( LANGUAGE_DONTKNOW != eLang ) + { + SvxLanguageItem aLang( eLang, RES_CHRATR_LANGUAGE ); + rItemSet.Put( aLang ); + aLang.SetWhich( RES_CHRATR_CJK_LANGUAGE ); + rItemSet.Put( aLang ); + aLang.SetWhich( RES_CHRATR_CTL_LANGUAGE ); + rItemSet.Put( aLang ); + + bRet = sal_True; + } + } + if( pDir && pDir->Len() ) + { + String aValue( *pDir ); + aValue.ToUpperAscii(); + SvxFrameDirection eDir = FRMDIR_ENVIRONMENT; + if( aValue.EqualsAscii( "LTR" ) ) + eDir = FRMDIR_HORI_LEFT_TOP; + else if( aValue.EqualsAscii( "RTL" ) ) + eDir = FRMDIR_HORI_RIGHT_TOP; + + if( FRMDIR_ENVIRONMENT != eDir ) + { + SvxFrameDirectionItem aDir( eDir, RES_FRAMEDIR ); + rItemSet.Put( aDir ); + + bRet = sal_True; + } + } + + return bRet; +} + +void SwHTMLParser::SetAnchorAndAdjustment( const SfxItemSet & /*rItemSet*/, + const SvxCSS1PropertyInfo &rPropInfo, + SfxItemSet &rFrmItemSet ) +{ + SwFmtAnchor aAnchor; + + sal_Int16 eHoriOri = text::HoriOrientation::NONE; + sal_Int16 eVertOri = text::VertOrientation::NONE; + sal_Int16 eHoriRel = text::RelOrientation::FRAME; + sal_Int16 eVertRel = text::RelOrientation::FRAME; + SwTwips nHoriPos = 0, nVertPos = 0; + SwSurround eSurround = SURROUND_THROUGHT; + if( SVX_CSS1_POS_ABSOLUTE == rPropInfo.ePosition ) + { + if( SVX_CSS1_LTYPE_TWIP == rPropInfo.eLeftType && + SVX_CSS1_LTYPE_TWIP == rPropInfo.eTopType ) + { + // Absolut positionierte Objekte sind seitengebunden, wenn + // sie nicht schon in einem Rahmen stehen und sonst + // Rahmengebunden. + const SwStartNode *pFlySttNd = + pPam->GetPoint()->nNode.GetNode().FindFlyStartNode(); + if( pFlySttNd ) + { + aAnchor.SetType( FLY_AT_FLY ); + SwPosition aPos( *pFlySttNd ); + aAnchor.SetAnchor( &aPos ); + } + else + { + aAnchor.SetType( FLY_AT_PAGE ); + aAnchor.SetPageNum( 1 ); + } + nHoriPos = rPropInfo.nLeft; + nVertPos = rPropInfo.nTop; + } + else + { + aAnchor.SetType( FLY_AT_PARA ); + aAnchor.SetAnchor( pPam->GetPoint() ); + eVertOri = text::VertOrientation::TOP; + eVertRel = text::RelOrientation::CHAR; + if( SVX_CSS1_LTYPE_TWIP == rPropInfo.eLeftType ) + { + eHoriOri = text::HoriOrientation::NONE; + eHoriRel = text::RelOrientation::PAGE_FRAME; + nHoriPos = rPropInfo.nLeft; + } + else + { + eHoriOri = text::HoriOrientation::LEFT; + eHoriRel = text::RelOrientation::FRAME; // wird noch umgeschossen + } + } + } + else + { + // fliessende Objekte werden Absatzgebunden eingefuegt, wenn + // der Absatz noch leer ist und sonst auto-gebunden. + // Auto-gebundene Rahmen werden zunaechst an der Position davor + // eingefuegt und erst spaeter verschoben. + xub_StrLen nCntnt = pPam->GetPoint()->nContent.GetIndex(); + if( nCntnt ) + { + aAnchor.SetType( FLY_AT_CHAR ); + pPam->Move( fnMoveBackward ); + eVertOri = text::VertOrientation::CHAR_BOTTOM; + eVertRel = text::RelOrientation::CHAR; + } + else + { + aAnchor.SetType( FLY_AT_PARA ); + eVertOri = text::VertOrientation::TOP; + eVertRel = text::RelOrientation::PRINT_AREA; + } + + aAnchor.SetAnchor( pPam->GetPoint() ); + + if( nCntnt ) + pPam->Move( fnMoveForward ); + + sal_uInt16 nLeftSpace = 0, nRightSpace = 0; + short nIndent = 0; + GetMarginsFromContextWithNumBul( nLeftSpace, nRightSpace, nIndent ); + + if( SVX_ADJUST_RIGHT==rPropInfo.eFloat ) + { + eHoriOri = text::HoriOrientation::RIGHT; + eHoriRel = nRightSpace ? text::RelOrientation::PRINT_AREA : text::RelOrientation::FRAME; + eSurround = SURROUND_LEFT; + } + else + { + eHoriOri = text::HoriOrientation::LEFT; + eHoriRel = nLeftSpace ? text::RelOrientation::PRINT_AREA : text::RelOrientation::FRAME; + eSurround = SURROUND_RIGHT; + } + } + rFrmItemSet.Put( aAnchor ); + + // Absolut Positioniert mit Durchlauf + rFrmItemSet.Put( SwFmtHoriOrient( nHoriPos, eHoriOri, eHoriRel ) ); + rFrmItemSet.Put( SwFmtVertOrient( nVertPos, eVertOri, eVertRel ) ); + rFrmItemSet.Put( SwFmtSurround( eSurround ) ); +} + +void SwHTMLParser::SetVarSize( SfxItemSet & /*rItemSet*/, + SvxCSS1PropertyInfo &rPropInfo, + SfxItemSet &rFrmItemSet, + SwTwips nDfltWidth, sal_uInt8 nDfltPrcWidth ) +{ + SwFrmSize eSize = ATT_MIN_SIZE; + SwTwips nWidth = nDfltWidth, nHeight = MINFLY; + sal_uInt8 nPrcWidth = nDfltPrcWidth, nPrcHeight = 0; + switch( rPropInfo.eWidthType ) + { + case SVX_CSS1_LTYPE_PERCENTAGE: + nPrcWidth = rPropInfo.nWidth > 0 ? (sal_uInt8)rPropInfo.nWidth : 1; + nWidth = MINFLY; + break; + case SVX_CSS1_LTYPE_TWIP: + nWidth = rPropInfo.nWidth > MINFLY ? rPropInfo.nWidth : MINFLY; + nPrcWidth = 0; + break; + default: + ; + } + switch( rPropInfo.eHeightType ) + { + case SVX_CSS1_LTYPE_PERCENTAGE: + nPrcHeight = rPropInfo.nHeight > 0 ? (sal_uInt8)rPropInfo.nHeight : 1; + break; + case SVX_CSS1_LTYPE_TWIP: + // Netscape und MS-IE interpretieren die Hoehe regelwiedrig + // als Mindest-Hoehe, also machwn wir das auch so. + nHeight = rPropInfo.nHeight > MINFLY ? rPropInfo.nHeight : MINFLY; + break; + default: + ; + } + + SwFmtFrmSize aFrmSize( eSize, nWidth, nHeight ); + aFrmSize.SetWidthPercent( nPrcWidth ); + aFrmSize.SetHeightPercent( nPrcHeight ); + rFrmItemSet.Put( aFrmSize ); +} + +void SwHTMLParser::SetFrmFmtAttrs( SfxItemSet &rItemSet, + SvxCSS1PropertyInfo & /*rPropInfo*/, + sal_uInt16 nFlags, + SfxItemSet &rFrmItemSet ) +{ + const SfxPoolItem *pItem; + if( (nFlags & HTML_FF_BOX) != 0 && + SFX_ITEM_SET==rItemSet.GetItemState( RES_BOX, sal_True, &pItem ) ) + { + if( (nFlags & HTML_FF_PADDING) == 0 ) + { + SvxBoxItem aBoxItem( *(const SvxBoxItem *)pItem ); + // Alle 4 Seiten gleichzeitig auf 0 setzen + aBoxItem.SetDistance( 0 ); + rFrmItemSet.Put( aBoxItem ); + } + else + { + rFrmItemSet.Put( *pItem ); + } + rItemSet.ClearItem( RES_BOX ); + } + + if( (nFlags & HTML_FF_BACKGROUND) != 0 && + SFX_ITEM_SET==rItemSet.GetItemState( RES_BACKGROUND, sal_True, &pItem ) ) + { + rFrmItemSet.Put( *pItem ); + rItemSet.ClearItem( RES_BACKGROUND ); + } + + if( (nFlags & HTML_FF_DIRECTION) != 0 && + SFX_ITEM_SET==rItemSet.GetItemState( RES_FRAMEDIR, sal_True, &pItem ) ) + { + rFrmItemSet.Put( *pItem ); + rItemSet.ClearItem( RES_FRAMEDIR ); + } +} + + +/* */ + +_HTMLAttrContext *SwHTMLParser::PopContext( sal_uInt16 nToken, sal_uInt16 nLimit, + sal_Bool bRemove ) +{ + sal_uInt16 nPos = aContexts.Count(); + if( nPos <= nContextStMin ) + return 0; + + sal_Bool bFound = 0==nToken; + if( nToken ) + { + // Stack-Eintrag zu dem Token suchen + while( nPos > nContextStMin ) + { + sal_uInt16 nCntxtToken = aContexts[--nPos]->GetToken(); + if( nCntxtToken == nToken ) + { + bFound = sal_True; + break; + } + else if( nCntxtToken == nLimit ) // 0 als Token kommt nicht vor + { + break; + } + } + } + else + { + nPos--; + } + + _HTMLAttrContext *pCntxt = 0; + if( bFound ) + { + pCntxt = aContexts[nPos]; + if( bRemove ) + aContexts.Remove( nPos, 1 ); + } + + return pCntxt; +} + +sal_Bool SwHTMLParser::GetMarginsFromContext( sal_uInt16& nLeft, + sal_uInt16& nRight, + short& nIndent, + sal_Bool bIgnoreTopContext ) const +{ + sal_uInt16 nPos = aContexts.Count(); + if( bIgnoreTopContext ) + { + if( !nPos ) + return sal_False; + else + nPos--; + } + + while( nPos > nContextStAttrMin ) + { + const _HTMLAttrContext *pCntxt = aContexts[--nPos]; + if( pCntxt->IsLRSpaceChanged() ) + { + pCntxt->GetMargins( nLeft, nRight, nIndent ); + return sal_True; + } + } + + return sal_False; +} + +sal_Bool SwHTMLParser::GetMarginsFromContextWithNumBul( sal_uInt16& nLeft, + sal_uInt16& nRight, + short& nIndent ) const +{ + sal_Bool bRet = GetMarginsFromContext( nLeft, nRight, nIndent ); + const SwHTMLNumRuleInfo& rInfo = ((SwHTMLParser*)this)->GetNumInfo(); + if( rInfo.GetDepth() ) + { + sal_uInt8 nLevel = (sal_uInt8)( (rInfo.GetDepth() <= MAXLEVEL ? rInfo.GetDepth() + : MAXLEVEL) - 1 ); + const SwNumFmt& rNumFmt = rInfo.GetNumRule()->Get(nLevel); + nLeft = nLeft + rNumFmt.GetAbsLSpace(); + nIndent = rNumFmt.GetFirstLineOffset(); + } + + return bRet; +} + +void SwHTMLParser::GetULSpaceFromContext( sal_uInt16& nUpper, + sal_uInt16& nLower ) const +{ + sal_uInt16 nDfltColl = 0; + String aDfltClass; + + sal_uInt16 nPos = aContexts.Count(); + while( nPos > nContextStAttrMin ) + { + const _HTMLAttrContext *pCntxt = aContexts[--nPos]; + if( pCntxt->IsULSpaceChanged() ) + { + pCntxt->GetULSpace( nUpper, nLower ); + return; + } + else if( !nDfltColl ) + { + nDfltColl = pCntxt->GetDfltTxtFmtColl(); + if( nDfltColl ) + aDfltClass = pCntxt->GetClass(); + } + } + + if( !nDfltColl ) + nDfltColl = RES_POOLCOLL_TEXT; + + const SwTxtFmtColl *pColl = + pCSS1Parser->GetTxtFmtColl( nDfltColl, aDfltClass ); + const SvxULSpaceItem& rULSpace = pColl->GetULSpace(); + nUpper = rULSpace.GetUpper(); + nLower = rULSpace.GetLower(); +} + +void SwHTMLParser::EndContextAttrs( _HTMLAttrContext *pContext, sal_Bool bRemove ) +{ + _HTMLAttrs &rAttrs = pContext->GetAttrs(); + for( sal_uInt16 i=0; i<rAttrs.Count(); i++ ) + { + _HTMLAttr *pAttr = rAttrs[i]; + + if( RES_PARATR_DROP==pAttr->GetItem().Which() ) + { + // Fuer DropCaps noch die Anzahl der Zeichen anpassen. Wenn + // es am Ende 0 sind, wird das Attribut invalidiert und dann + // von _SetAttr gar nicht erst gesetzt. + xub_StrLen nChars = pPam->GetPoint()->nContent.GetIndex(); + if( nChars < 1 ) + pAttr->Invalidate(); + else if( nChars > MAX_DROPCAP_CHARS ) + nChars = MAX_DROPCAP_CHARS; + ((SwFmtDrop&)pAttr->GetItem()).GetChars() = (sal_uInt8)nChars; + } + + EndAttr( pAttr ); + } + + if( bRemove && rAttrs.Count() ) + rAttrs.Remove( 0, rAttrs.Count() ); +} + +void SwHTMLParser::InsertParaAttrs( const SfxItemSet& rItemSet ) +{ + SfxItemIter aIter( rItemSet ); + + const SfxPoolItem *pItem = aIter.FirstItem(); + while( pItem ) + { + // den zu dem Item gehoehrenden Tabellen-Eintrag ermitteln ... + sal_uInt16 nWhich = pItem->Which(); + _HTMLAttr **ppAttr = GetAttrTabEntry( nWhich ); + + if( ppAttr ) + { + NewAttr( ppAttr, *pItem ); + if( RES_PARATR_BEGIN > nWhich ) + (*ppAttr)->SetLikePara(); + aParaAttrs.Insert( *ppAttr, aParaAttrs.Count() ); + EndAttr( *ppAttr, 0, sal_False ); + } + + pItem = aIter.NextItem(); + } +} + +void lcl_swcss1_setEncoding( SwFmt& rFmt, rtl_TextEncoding eEnc ) +{ + if( RTL_TEXTENCODING_DONTKNOW == eEnc ) + return; + + const SfxItemSet& rItemSet = rFmt.GetAttrSet(); + static sal_uInt16 aWhichIds[3] = { RES_CHRATR_FONT, RES_CHRATR_CJK_FONT, + RES_CHRATR_CTL_FONT }; + const SfxPoolItem *pItem; + for( sal_uInt16 i=0; i<3; i++ ) + { + if( SFX_ITEM_SET == rItemSet.GetItemState( aWhichIds[i], sal_False,&pItem ) ) + { + const SvxFontItem& rFont = *(const SvxFontItem *)pItem; + if( RTL_TEXTENCODING_SYMBOL != rFont.GetCharSet() ) + { + SvxFontItem aFont( rFont.GetFamily(), rFont.GetFamilyName(), + rFont.GetStyleName(), rFont.GetPitch(), + eEnc, aWhichIds[i]); + rFmt.SetFmtAttr( aFont ); + } + } + } +} + +void SwCSS1Parser::SetDfltEncoding( rtl_TextEncoding eEnc ) +{ + if( eEnc != GetDfltEncoding() ) + { + if( bIsNewDoc ) + { + // Set new encoding as pool default + static sal_uInt16 aWhichIds[3] = { RES_CHRATR_FONT, RES_CHRATR_CJK_FONT, + RES_CHRATR_CTL_FONT }; + sal_uInt16 i; + for( i=0; i<3; i++ ) + { + const SvxFontItem& rDfltFont = + (const SvxFontItem&)pDoc->GetDefault( aWhichIds[i]); + SvxFontItem aFont( rDfltFont.GetFamily(), + rDfltFont.GetFamilyName(), + rDfltFont.GetStyleName(), + rDfltFont.GetPitch(), + eEnc, aWhichIds[i] ); + pDoc->SetDefault( aFont ); + } + + // Change all paragraph styles that do specify a font. + sal_uInt16 nArrLen = pDoc->GetTxtFmtColls()->Count(); + for( i=1; i<nArrLen; i++ ) + lcl_swcss1_setEncoding( *(*pDoc->GetTxtFmtColls())[i], eEnc ); + + // Change all character styles that do specify a font. + nArrLen = pDoc->GetCharFmts()->Count(); + for( i=1; i<nArrLen; i++ ) + lcl_swcss1_setEncoding( *(*pDoc->GetCharFmts())[i], eEnc ); + } + + SvxCSS1Parser::SetDfltEncoding( eEnc ); + } +} diff --git a/sw/source/filter/html/htmlctxt.cxx b/sw/source/filter/html/htmlctxt.cxx new file mode 100644 index 000000000000..e60f6800cd58 --- /dev/null +++ b/sw/source/filter/html/htmlctxt.cxx @@ -0,0 +1,752 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include "hintids.hxx" +#include <svl/itemiter.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/brshitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <svtools/htmltokn.h> + +#include "doc.hxx" +#include "pam.hxx" +#include "ndtxt.hxx" +#include "shellio.hxx" +#include "paratr.hxx" +#include "htmlnum.hxx" +#include "css1kywd.hxx" +#include "swcss1.hxx" +#include "swhtml.hxx" + +using namespace ::com::sun::star; + + +/* */ + + +class _HTMLAttrContext_SaveDoc +{ + SwHTMLNumRuleInfo aNumRuleInfo; // In Umgebung gueltige Numerierung + SwPosition *pPos; // hierhin beim verlassen den + // Kontexts zurueckgesprungen + _HTMLAttrTable *pAttrTab; // In Umgebung gueltige Attribute, + // wenn Attributierung nicht + // beibehalten werden soll. + + sal_uInt16 nContextStMin; // In Umgebung gueltige Stack- + // Untergrenze, wenn der Stack + // geschuetzt werden soll. + sal_uInt16 nContextStAttrMin; // In Umgebung gueltige Stack- + // Untergrenze, wenn die Attribute + // nicht beibehalten werden sollen. + + sal_Bool bStripTrailingPara : 1; // letzen Absatz entfernen? + sal_Bool bKeepNumRules : 1; // Numerierung beibehalten? + sal_Bool bPopStack : 1; // Stack-Elemente oberhalb des + // zu schliessenden entfernen? + sal_Bool bFixHeaderDist : 1; + sal_Bool bFixFooterDist : 1; + +public: + + _HTMLAttrContext_SaveDoc() : + pPos( 0 ), pAttrTab( 0 ), + nContextStMin( USHRT_MAX ), nContextStAttrMin( USHRT_MAX ), + bStripTrailingPara( sal_False ), bKeepNumRules( sal_False ), + bPopStack( sal_False ), + bFixHeaderDist( sal_False ), bFixFooterDist( sal_False ) + {} + + ~_HTMLAttrContext_SaveDoc() { delete pPos; delete pAttrTab; } + + // Die Position gehoert uns, muss also angelegt und zerstoert werden + void SetPos( const SwPosition& rPos ) { pPos = new SwPosition(rPos); } + const SwPosition *GetPos() const { return pPos; } + + // Der Index gehoert uns nicht. Kein Anlgen und Zerstoeren. + void SetNumInfo( const SwHTMLNumRuleInfo& rInf ) { aNumRuleInfo.Set(rInf); } + const SwHTMLNumRuleInfo& GetNumInfo() const { return aNumRuleInfo; } + + _HTMLAttrTable *GetAttrTab( sal_Bool bCreate= sal_False ); + + void SetContextStMin( sal_uInt16 nMin ) { nContextStMin = nMin; } + sal_uInt16 GetContextStMin() const { return nContextStMin; } + + void SetContextStAttrMin( sal_uInt16 nMin ) { nContextStAttrMin = nMin; } + sal_uInt16 GetContextStAttrMin() const { return nContextStAttrMin; } + + void SetStripTrailingPara( sal_Bool bSet ) { bStripTrailingPara = bSet; } + sal_Bool GetStripTrailingPara() const { return bStripTrailingPara; } + + void SetKeepNumRules( sal_Bool bSet ) { bKeepNumRules = bSet; } + sal_Bool GetKeepNumRules() const { return bKeepNumRules; } + + void SetFixHeaderDist( sal_Bool bSet ) { bFixHeaderDist = bSet; } + sal_Bool GetFixHeaderDist() const { return bFixHeaderDist; } + + void SetFixFooterDist( sal_Bool bSet ) { bFixFooterDist = bSet; } + sal_Bool GetFixFooterDist() const { return bFixFooterDist; } +}; + +_HTMLAttrTable *_HTMLAttrContext_SaveDoc::GetAttrTab( sal_Bool bCreate ) +{ + if( !pAttrTab && bCreate ) + { + pAttrTab = new _HTMLAttrTable; + memset( pAttrTab, 0, sizeof( _HTMLAttrTable )); + } + return pAttrTab; +} + +/* */ + +_HTMLAttrContext_SaveDoc *_HTMLAttrContext::GetSaveDocContext( sal_Bool bCreate ) +{ + if( !pSaveDocContext && bCreate ) + pSaveDocContext = new _HTMLAttrContext_SaveDoc; + + return pSaveDocContext; +} + +void _HTMLAttrContext::ClearSaveDocContext() +{ + delete pSaveDocContext; + pSaveDocContext = 0; +} + +/* */ + +void SwHTMLParser::SplitAttrTab( const SwPosition& rNewPos ) +{ + // Hier darf es keine vorlauefigen Absatz-Attribute geben, den die + // koennten jetzt gesetzt werden und dann sind die Zeiger ungueltig!!! + ASSERT( !aParaAttrs.Count(), + "Hoechste Gefahr: Es gibt noch nicht-endgueltige Absatz-Attribute" ); + if( aParaAttrs.Count() ) + aParaAttrs.Remove( 0, aParaAttrs.Count() ); + + const SwNodeIndex* pOldEndPara = &pPam->GetPoint()->nNode; + xub_StrLen nOldEndCnt = pPam->GetPoint()->nContent.GetIndex(); + + const SwNodeIndex& rNewSttPara = rNewPos.nNode; + xub_StrLen nNewSttCnt = rNewPos.nContent.GetIndex(); + + sal_Bool bMoveBack = sal_False; + + // alle noch offenen Attribute beenden und hinter der Tabelle + // neu aufspannen + _HTMLAttr** pTbl = (_HTMLAttr**)&aAttrTab; + for( sal_uInt16 nCnt = sizeof( _HTMLAttrTable ) / sizeof( _HTMLAttr* ); + nCnt--; ++pTbl ) + { + _HTMLAttr *pAttr = *pTbl; + while( pAttr ) + { + _HTMLAttr *pNext = pAttr->GetNext(); + _HTMLAttr *pPrev = pAttr->GetPrev(); + + sal_uInt16 nWhich = pAttr->pItem->Which(); + if( !nOldEndCnt && RES_PARATR_BEGIN <= nWhich && + pAttr->GetSttParaIdx() < pOldEndPara->GetIndex() ) + { + // Das Attribut muss eine Content-Position weiter vorne + // beendet werden + if( !bMoveBack ) + { + bMoveBack = pPam->Move( fnMoveBackward ); + nOldEndCnt = pPam->GetPoint()->nContent.GetIndex(); + } + } + else if( bMoveBack ) + { + pPam->Move( fnMoveForward ); + nOldEndCnt = pPam->GetPoint()->nContent.GetIndex(); + } + + if( (RES_PARATR_BEGIN <= nWhich && bMoveBack) || + pAttr->GetSttParaIdx() < pOldEndPara->GetIndex() || + (pAttr->GetSttPara() == *pOldEndPara && + pAttr->GetSttCnt() != nOldEndCnt) ) + { + // Das Attribut muss gesetzt werden. Da wir + // das Original noch brauchen, weil Zeiger auf das Attribut + // noch in den Kontexten existieren, muessen wir es clonen. + // Die Next-Liste geht dabei verloren, aber die + // Previous-Liste bleibt erhalten + _HTMLAttr *pSetAttr = pAttr->Clone( *pOldEndPara, nOldEndCnt ); + + if( pNext ) + pNext->InsertPrev( pSetAttr ); + else + { + sal_uInt16 nTmp = + pSetAttr->bInsAtStart ? 0 : aSetAttrTab.Count(); + aSetAttrTab.Insert( pSetAttr, nTmp ); + } + } + else if( pPrev ) + { + // Wenn das Attribut nicht gesetzt vor der Tabelle + // gesetzt werden muss, muessen der Previous-Attribute + // trotzdem gesetzt werden. + if( pNext ) + pNext->InsertPrev( pPrev ); + else + { + sal_uInt16 nTmp = pPrev->bInsAtStart ? 0 : aSetAttrTab.Count(); + aSetAttrTab.Insert( pPrev, nTmp ); + } + } + + // den Start des Attributs neu setzen + pAttr->nSttPara = rNewSttPara; + pAttr->nEndPara = rNewSttPara; + pAttr->nSttCntnt = nNewSttCnt; + pAttr->nEndCntnt = nNewSttCnt; + pAttr->pPrev = 0; + + pAttr = pNext; + } + } + + if( bMoveBack ) + pPam->Move( fnMoveForward ); + +} + +void SwHTMLParser::SaveDocContext( _HTMLAttrContext *pCntxt, + sal_uInt16 nFlags, + const SwPosition *pNewPos ) +{ + _HTMLAttrContext_SaveDoc *pSave = pCntxt->GetSaveDocContext( sal_True ); + pSave->SetStripTrailingPara( (HTML_CNTXT_STRIP_PARA & nFlags) != 0 ); + pSave->SetKeepNumRules( (HTML_CNTXT_KEEP_NUMRULE & nFlags) != 0 ); + pSave->SetFixHeaderDist( (HTML_CNTXT_HEADER_DIST & nFlags) != 0 ); + pSave->SetFixFooterDist( (HTML_CNTXT_FOOTER_DIST & nFlags) != 0 ); + + if( pNewPos ) + { + // Wenn der PaM an eine andere Position gesetzt wird, muss + // die Numerierung gerettet werden.. + if( !pSave->GetKeepNumRules() ) + { + // Die Numerierung soll nicht beibehalten werden. Also muss + // der aktuelle Zustand gerettet und die Numerierung + // anschliessend ausgeschaltet werden. + pSave->SetNumInfo( GetNumInfo() ); + GetNumInfo().Clear(); + } + + if( (HTML_CNTXT_KEEP_ATTRS & nFlags) != 0 ) + { + // Attribute an aktueller Position beenden und an neuer neu anfangen + SplitAttrTab( *pNewPos ); + } + else + { + _HTMLAttrTable *pSaveAttrTab = pSave->GetAttrTab( sal_True ); + SaveAttrTab( *pSaveAttrTab ); + } + + + pSave->SetPos( *pPam->GetPoint() ); + *pPam->GetPoint() = *pNewPos; + } + + // Mit dem Setzen von nContextStMin koennen automatisch auch + // keine gerade offenen Listen (DL/OL/UL) mehr beendet werden. + if( (HTML_CNTXT_PROTECT_STACK & nFlags) != 0 ) + { + pSave->SetContextStMin( nContextStMin ); + nContextStMin = aContexts.Count(); + + if( (HTML_CNTXT_KEEP_ATTRS & nFlags) == 0 ) + { + pSave->SetContextStAttrMin( nContextStAttrMin ); + nContextStAttrMin = aContexts.Count(); + } + } +} + +void SwHTMLParser::RestoreDocContext( _HTMLAttrContext *pCntxt ) +{ + _HTMLAttrContext_SaveDoc *pSave = pCntxt->GetSaveDocContext(); + if( !pSave ) + return; + + if( pSave->GetStripTrailingPara() ) + StripTrailingPara(); + + if( pSave->GetPos() ) + { + if( pSave->GetFixHeaderDist() || pSave->GetFixFooterDist() ) + FixHeaderFooterDistance( pSave->GetFixHeaderDist(), + pSave->GetPos() ); + + _HTMLAttrTable *pSaveAttrTab = pSave->GetAttrTab(); + if( !pSaveAttrTab ) + { + // Attribute an aktueller Position beenden und an alter neu + // anfangen. + SplitAttrTab( *pSave->GetPos() ); + } + else + { + RestoreAttrTab( *pSaveAttrTab ); + } + + *pPam->GetPoint() = *pSave->GetPos(); + + // Die bisherigen Attribute koennen wir schonmal setzen. + SetAttr(); + } + + if( USHRT_MAX != pSave->GetContextStMin() ) + { + nContextStMin = pSave->GetContextStMin(); + if( USHRT_MAX != pSave->GetContextStAttrMin() ) + nContextStAttrMin = pSave->GetContextStAttrMin(); + } + + if( !pSave->GetKeepNumRules() ) + { + // Die bisherige gemerkte Numerierung wieder setzen + GetNumInfo().Set( pSave->GetNumInfo() ); + } + + pCntxt->ClearSaveDocContext(); +} + +/* */ + +void SwHTMLParser::EndContext( _HTMLAttrContext *pContext ) +{ + if( pContext->GetPopStack() ) + { + // Alle noch offenen Kontexte beenden. Der eigene + // Kontext muss bereits geloscht sein! + while( aContexts.Count() > nContextStMin ) + { + _HTMLAttrContext *pCntxt = PopContext(); + ASSERT( pCntxt != pContext, + "Kontext noch im Stack" ); + if( pCntxt == pContext ) + break; + + EndContext( pCntxt ); + delete pCntxt; + } + } + + // Alle noch offenen Attribute beenden + if( pContext->HasAttrs() ) + EndContextAttrs( pContext ); + + // Falls ein Bereich geoeffnet wurde, den verlassen. Da Bereiche + // auch innerhalb von absolut positionierten Objekten angelegt werden, + // muss das passieren, bever ein alter Dokument-Kontext restauriert wird. + if( pContext->GetSpansSection() ) + EndSection(); + + // Rahmen und sonstige Sonderbereiche verlassen. + if( pContext->HasSaveDocContext() ) + RestoreDocContext( pContext ); + + // Ggf. noch einen Ansatz-Umbruch einfuegen + if( AM_NONE != pContext->GetAppendMode() && + pPam->GetPoint()->nContent.GetIndex() ) + AppendTxtNode( pContext->GetAppendMode() ); + + // PRE-/LISTING- und XMP-Umgebungen wieder starten + if( pContext->IsFinishPREListingXMP() ) + FinishPREListingXMP(); + + if( pContext->IsRestartPRE() ) + StartPRE(); + + if( pContext->IsRestartXMP() ) + StartXMP(); + + if( pContext->IsRestartListing() ) + StartListing(); +} + +void SwHTMLParser::ClearContext( _HTMLAttrContext *pContext ) +{ + _HTMLAttrs &rAttrs = pContext->GetAttrs(); + for( sal_uInt16 i=0; i<rAttrs.Count(); i++ ) + { + // einfaches Loeschen reicht hier nicht, weil das + // Attribut auch aus seiner Liste ausgetragen werden + // muss. Theoretisch koennt man natuerlich auch die Liste + // und die Attribute getrennt loeschen, aber wenn man + // dann was falsch gemacht hat, sieht es uebel aus. + DeleteAttr( rAttrs[i] ); + } + + ASSERT( !pContext->GetSpansSection(), + "Bereich kann nicht mehr verlassen werden" ); + + ASSERT( !pContext->HasSaveDocContext(), + "Rahmen kann nicht mehr verlassen werden" ); + + // PRE-/LISTING- und XMP-Umgebungen wieder starten + if( pContext->IsFinishPREListingXMP() ) + FinishPREListingXMP(); + + if( pContext->IsRestartPRE() ) + StartPRE(); + + if( pContext->IsRestartXMP() ) + StartXMP(); + + if( pContext->IsRestartListing() ) + StartListing(); +} + +/* */ + +sal_Bool SwHTMLParser::DoPositioning( SfxItemSet &rItemSet, + SvxCSS1PropertyInfo &rPropInfo, + _HTMLAttrContext *pContext ) +{ + sal_Bool bRet = sal_False; + + // Unter folgenden Umstaenden wird jetzt ein Rahmen aufgemacht: + // - das Tag wird absolut positioniert und left/top sind beide + // gegeben und enthalten auch keine %-Angabe, oder + // - das Tag soll fliessen, und + // - es wurde eine Breite angegeben (in beiden Faellen noetig) + if( SwCSS1Parser::MayBePositioned( rPropInfo ) ) + { + SfxItemSet aFrmItemSet( pDoc->GetAttrPool(), + RES_FRMATR_BEGIN, RES_FRMATR_END-1 ); + if( !IsNewDoc() ) + Reader::ResetFrmFmtAttrs(aFrmItemSet ); + + // Ausrichtung setzen + SetAnchorAndAdjustment( text::VertOrientation::NONE, text::HoriOrientation::NONE, rItemSet, rPropInfo, + aFrmItemSet ); + + // Groesse setzen + SetVarSize( rItemSet, rPropInfo, aFrmItemSet ); + + // Abstaende setzen + SetSpace( Size(0,0), rItemSet, rPropInfo, aFrmItemSet ); + + // Sonstige CSS1-Attribute Setzen + SetFrmFmtAttrs( rItemSet, rPropInfo, + HTML_FF_BOX|HTML_FF_PADDING|HTML_FF_BACKGROUND|HTML_FF_DIRECTION, + aFrmItemSet ); + + InsertFlyFrame( aFrmItemSet, pContext, rPropInfo.aId, + CONTEXT_FLAGS_ABSPOS ); + pContext->SetPopStack( sal_True ); + rPropInfo.aId.Erase(); + bRet = sal_True; + } + + return bRet; +} + +sal_Bool SwHTMLParser::CreateContainer( const String& rClass, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo &rPropInfo, + _HTMLAttrContext *pContext ) +{ + sal_Bool bRet = sal_False; + if( rClass.EqualsIgnoreCaseAscii(sCSS1_class_abs_pos) && + pCSS1Parser->MayBePositioned( rPropInfo ) ) + { + // Container-Klasse + SfxItemSet *pFrmItemSet = pContext->GetFrmItemSet( pDoc ); + if( !IsNewDoc() ) + Reader::ResetFrmFmtAttrs( *pFrmItemSet ); + + SetAnchorAndAdjustment( text::VertOrientation::NONE, text::HoriOrientation::NONE, + rItemSet, rPropInfo, *pFrmItemSet ); + Size aDummy(0,0); + SetFixSize( aDummy, aDummy, sal_False, sal_False, rItemSet, rPropInfo, + *pFrmItemSet ); + SetSpace( aDummy, rItemSet, rPropInfo, *pFrmItemSet ); + SetFrmFmtAttrs( rItemSet, rPropInfo, HTML_FF_BOX|HTML_FF_BACKGROUND|HTML_FF_DIRECTION, + *pFrmItemSet ); + + bRet = sal_True; + } + + return bRet; +} + +/* */ + +void SwHTMLParser::InsertAttrs( SfxItemSet &rItemSet, + SvxCSS1PropertyInfo &rPropInfo, + _HTMLAttrContext *pContext, + sal_Bool bCharLvl ) +{ + // Ein DropCap-Attribut basteln, wenn auf Zeichen-Ebene vor dem + // ersten Zeichen ein float: left vorkommt + if( bCharLvl && !pPam->GetPoint()->nContent.GetIndex() && + SVX_ADJUST_LEFT == rPropInfo.eFloat ) + { + SwFmtDrop aDrop; + aDrop.GetChars() = 1; + + pCSS1Parser->FillDropCap( aDrop, rItemSet ); + + // Nur wenn das Initial auch ueber mehrere Zeilen geht, wird das + // DropCap-Attribut gesetzt. Sonst setzten wir die Attribute hart. + if( aDrop.GetLines() > 1 ) + { + NewAttr( &aAttrTab.pDropCap, aDrop ); + + _HTMLAttrs &rAttrs = pContext->GetAttrs(); + rAttrs.Insert( aAttrTab.pDropCap, rAttrs.Count() ); + + return; + } + } + +// Feature: PrintExt + if( !bCharLvl ) + pCSS1Parser->SetFmtBreak( rItemSet, rPropInfo ); +// /Feature: PrintExt + + ASSERT( aContexts.Count() <= nContextStAttrMin || + aContexts[aContexts.Count()-1] != pContext, + "SwHTMLParser::InsertAttrs: Kontext doch schon auf dem Stack" ); + + SfxItemIter aIter( rItemSet ); + + const SfxPoolItem *pItem = aIter.FirstItem(); + while( pItem ) + { + _HTMLAttr **ppAttr = 0; + + switch( pItem->Which() ) + { + case RES_LR_SPACE: + { + // Absatz-Einzuege muessen addiert werden und werden immer + // nur absatzweise gesetzt (fuer den ersten Absatz hier, + // fuer alle folgenden in SetTxtCollAttrs) + + const SvxLRSpaceItem *pLRItem = + (const SvxLRSpaceItem *)pItem; + + // die bisherigen Absatz-Abstaende holen (ohne die vom + // obersten Kontext, denn den veraendern wir ja gerade) ... + sal_uInt16 nOldLeft = 0, nOldRight = 0; + short nOldIndent = 0; + sal_Bool bIgnoreTop = aContexts.Count() > nContextStMin && + aContexts[aContexts.Count()-1] == pContext; + GetMarginsFromContext( nOldLeft, nOldRight, nOldIndent, + bIgnoreTop ); + + + // und noch die aktuell gueltigen + sal_uInt16 nLeft = nOldLeft, nRight = nOldRight; + short nIndent = nOldIndent; + pContext->GetMargins( nLeft, nRight, nIndent ); + + // ... und die neuen Abstaende zu den alten addieren + // Hier werden nicht die aus dem Item genommen, sondern die + // extra gemerkten, weil die auch negativ sein koennen. Die + // Abfrage ueber das Item funktioniert aber trotzdem, denn + // fuer negative Werte wird das Item (mit Wert 0) auch + // eingefuegt. + if( rPropInfo.bLeftMargin ) + { + ASSERT( rPropInfo.nLeftMargin < 0 || + rPropInfo.nLeftMargin == pLRItem->GetTxtLeft(), + "linker Abstand stimmt nicht mit Item ueberein" ); + if( rPropInfo.nLeftMargin < 0 && + -rPropInfo.nLeftMargin > nOldLeft ) + nLeft = 0; + else + nLeft = nOldLeft + static_cast< sal_uInt16 >(rPropInfo.nLeftMargin); + } + if( rPropInfo.bRightMargin ) + { + ASSERT( rPropInfo.nRightMargin < 0 || + rPropInfo.nRightMargin == pLRItem->GetRight(), + "rechter Abstand stimmt nicht mit Item ueberein" ); + if( rPropInfo.nRightMargin < 0 && + -rPropInfo.nRightMargin > nOldRight ) + nRight = 0; + else + nRight = nOldRight + static_cast< sal_uInt16 >(rPropInfo.nRightMargin); + } + if( rPropInfo.bTextIndent ) + nIndent = pLRItem->GetTxtFirstLineOfst(); + + // und die Werte fuer nachfolgende Absaetze merken + pContext->SetMargins( nLeft, nRight, nIndent ); + + // das Attribut noch am aktuellen Absatz setzen + SvxLRSpaceItem aLRItem( *pLRItem ); + aLRItem.SetTxtFirstLineOfst( nIndent ); + aLRItem.SetTxtLeft( nLeft ); + aLRItem.SetRight( nRight ); + NewAttr( &aAttrTab.pLRSpace, aLRItem ); + EndAttr( aAttrTab.pLRSpace, 0, sal_False ); + } + break; + + case RES_UL_SPACE: + if( !rPropInfo.bTopMargin || !rPropInfo.bBottomMargin ) + { + sal_uInt16 nUpper = 0, nLower = 0; + GetULSpaceFromContext( nUpper, nLower ); + SvxULSpaceItem aULSpace( *((const SvxULSpaceItem *)pItem) ); + if( !rPropInfo.bTopMargin ) + aULSpace.SetUpper( nUpper ); + if( !rPropInfo.bBottomMargin ) + aULSpace.SetLower( nLower ); + + NewAttr( &aAttrTab.pULSpace, aULSpace ); + + // ... und noch die Kontext-Information speichern + _HTMLAttrs &rAttrs = pContext->GetAttrs(); + rAttrs.Insert( aAttrTab.pULSpace, rAttrs.Count() ); + + pContext->SetULSpace( aULSpace.GetUpper(), aULSpace.GetLower() ); + } + else + { + ppAttr = &aAttrTab.pULSpace; + } + break; + case RES_CHRATR_FONTSIZE: + // es werden keine Attribute mit %-Angaben gesetzt + if( ((const SvxFontHeightItem *)pItem)->GetProp() == 100 ) + ppAttr = &aAttrTab.pFontHeight; + break; + case RES_CHRATR_CJK_FONTSIZE: + // es werden keine Attribute mit %-Angaben gesetzt + if( ((const SvxFontHeightItem *)pItem)->GetProp() == 100 ) + ppAttr = &aAttrTab.pFontHeightCJK; + break; + case RES_CHRATR_CTL_FONTSIZE: + // es werden keine Attribute mit %-Angaben gesetzt + if( ((const SvxFontHeightItem *)pItem)->GetProp() == 100 ) + ppAttr = &aAttrTab.pFontHeightCTL; + break; + + case RES_BACKGROUND: + if( bCharLvl ) + { + // das Frame-Attr ggf. in ein Char-Attr umwandeln + SvxBrushItem aBrushItem( *(const SvxBrushItem *)pItem ); + aBrushItem.SetWhich( RES_CHRATR_BACKGROUND ); + + // Das Attribut setzen ... + NewAttr( &aAttrTab.pCharBrush, aBrushItem ); + + // ... und noch die Kontext-Information speichern + _HTMLAttrs &rAttrs = pContext->GetAttrs(); + rAttrs.Insert( aAttrTab.pCharBrush, rAttrs.Count() ); + } + else if( pContext->GetToken() != HTML_TABLEHEADER_ON && + pContext->GetToken() != HTML_TABLEDATA_ON ) + { + ppAttr = &aAttrTab.pBrush; + } + break; + + default: + // den zu dem Item gehoehrenden Tabellen-Eintrag ermitteln ... + ppAttr = GetAttrTabEntry( pItem->Which() ); + break; + } + + if( ppAttr ) + { + // Das Attribut setzen ... + NewAttr( ppAttr, *pItem ); + + // ... und noch die Kontext-Information speichern + _HTMLAttrs &rAttrs = pContext->GetAttrs(); + rAttrs.Insert( *ppAttr, rAttrs.Count() ); + } + + // auf zum naechsten Item + pItem = aIter.NextItem(); + } + + if( rPropInfo.aId.Len() ) + InsertBookmark( rPropInfo.aId ); +} + +void SwHTMLParser::InsertAttr( _HTMLAttr **ppAttr, const SfxPoolItem & rItem, + _HTMLAttrContext *pCntxt ) +{ + if( !ppAttr ) + { + ppAttr = GetAttrTabEntry( rItem.Which() ); + if( !ppAttr ) + return; + } + + // das Attribut setzen + NewAttr( ppAttr, rItem ); + + // und im Kontext merken + _HTMLAttrs &rAttrs = pCntxt->GetAttrs(); + rAttrs.Insert( *ppAttr, rAttrs.Count() ); +} + +void SwHTMLParser::SplitPREListingXMP( _HTMLAttrContext *pCntxt ) +{ + // PRE/Listing/XMP soll beim beenden des Kontexts beendet werden. + pCntxt->SetFinishPREListingXMP( sal_True ); + + // Und die jetzt gueltigen Flags sollen wieder gesetzt werden. + if( IsReadPRE() ) + pCntxt->SetRestartPRE( sal_True ); + if( IsReadXMP() ) + pCntxt->SetRestartXMP( sal_True ); + if( IsReadListing() ) + pCntxt->SetRestartListing( sal_True ); + + // PRE/Listing/XMP wird auuserdem sofort beendet + FinishPREListingXMP(); +} + +SfxItemSet *_HTMLAttrContext::GetFrmItemSet( SwDoc *pCreateDoc ) +{ + if( !pFrmItemSet && pCreateDoc ) + pFrmItemSet = new SfxItemSet( pCreateDoc->GetAttrPool(), + RES_FRMATR_BEGIN, RES_FRMATR_END-1 ); + return pFrmItemSet; +} diff --git a/sw/source/filter/html/htmldraw.cxx b/sw/source/filter/html/htmldraw.cxx new file mode 100644 index 000000000000..e973ad3df26d --- /dev/null +++ b/sw/source/filter/html/htmldraw.cxx @@ -0,0 +1,859 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include "hintids.hxx" +#include <vcl/svapp.hxx> +#include <vcl/wrkwin.hxx> +#include <svx/svdmodel.hxx> +#include <svx/svdpage.hxx> +#include <svx/svdobj.hxx> +#include <svx/svdotext.hxx> +#include <editeng/eeitem.hxx> + +#ifndef _OUTLINER_HXX //autogen +#define _EEITEMID_HXX +#include <editeng/outliner.hxx> +#endif +#include <svx/xfillit.hxx> +#include <editeng/colritem.hxx> +#include <editeng/brshitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/ulspitem.hxx> +#include <svl/itemiter.hxx> +#include <svl/whiter.hxx> +#include <svtools/htmlout.hxx> +#include <svtools/htmltokn.h> +#include <svtools/htmlkywd.hxx> +#include <svx/svdpool.hxx> + + +#include "charatr.hxx" +#include <frmfmt.hxx> +#include <fmtanchr.hxx> +#include <fmtsrnd.hxx> +#include "ndtxt.hxx" +#include "doc.hxx" +#include "dcontact.hxx" +#include "poolfmt.hxx" +#include "swcss1.hxx" +#include "swhtml.hxx" +#include "wrthtml.hxx" + +using namespace ::com::sun::star; + + +const sal_uInt32 HTML_FRMOPTS_MARQUEE = + HTML_FRMOPT_ALIGN | + HTML_FRMOPT_SPACE; + +const sal_uInt32 HTML_FRMOPTS_MARQUEE_CSS1 = + HTML_FRMOPT_S_ALIGN | + HTML_FRMOPT_S_SPACE; + +static HTMLOptionEnum __FAR_DATA aHTMLMarqBehaviorTable[] = +{ + { OOO_STRING_SVTOOLS_HTML_BEHAV_scroll, SDRTEXTANI_SCROLL }, + { OOO_STRING_SVTOOLS_HTML_BEHAV_alternate, SDRTEXTANI_ALTERNATE }, + { OOO_STRING_SVTOOLS_HTML_BEHAV_slide, SDRTEXTANI_SLIDE }, + { 0, 0 } +}; + +static HTMLOptionEnum __FAR_DATA aHTMLMarqDirectionTable[] = +{ + { OOO_STRING_SVTOOLS_HTML_AL_left, SDRTEXTANI_LEFT }, + { OOO_STRING_SVTOOLS_HTML_AL_right, SDRTEXTANI_RIGHT }, + { 0, 0 } +}; + +/* */ +void SwHTMLParser::InsertDrawObject( SdrObject* pNewDrawObj, + const Size& rPixSpace, + sal_Int16 eVertOri, + sal_Int16 eHoriOri, + SfxItemSet& rCSS1ItemSet, + SvxCSS1PropertyInfo& rCSS1PropInfo, + sal_Bool bHidden ) +{ + // always on top of text. + // OD 02.07.2003 #108784# but in invisible layer. <ConnectToLayout> will + // move the object to the visible layer. + pNewDrawObj->SetLayer( pDoc->GetInvisibleHeavenId() ); + + SfxItemSet aFrmSet( pDoc->GetAttrPool(), + RES_FRMATR_BEGIN, RES_FRMATR_END-1 ); + if( !IsNewDoc() ) + Reader::ResetFrmFmtAttrs( aFrmSet ); + + sal_uInt16 nLeftSpace = 0, nRightSpace = 0, nUpperSpace = 0, nLowerSpace = 0; + if( (rPixSpace.Width() || rPixSpace.Height()) && Application::GetDefaultDevice() ) + { + Size aTwipSpc( rPixSpace.Width(), rPixSpace.Height() ); + aTwipSpc = + Application::GetDefaultDevice()->PixelToLogic( aTwipSpc, + MapMode(MAP_TWIP) ); + nLeftSpace = nRightSpace = (sal_uInt16)aTwipSpc.Width(); + nUpperSpace = nLowerSpace = (sal_uInt16)aTwipSpc.Height(); + } + + // linken/rechten Rand setzen + const SfxPoolItem *pItem; + if( SFX_ITEM_SET==rCSS1ItemSet.GetItemState( RES_LR_SPACE, sal_True, &pItem ) ) + { + // Ggf. den Erstzeilen-Einzug noch plaetten + const SvxLRSpaceItem *pLRItem = (const SvxLRSpaceItem *)pItem; + SvxLRSpaceItem aLRItem( *pLRItem ); + aLRItem.SetTxtFirstLineOfst( 0 ); + if( rCSS1PropInfo.bLeftMargin ) + { + nLeftSpace = static_cast< sal_uInt16 >(aLRItem.GetLeft()); + rCSS1PropInfo.bLeftMargin = sal_False; + } + if( rCSS1PropInfo.bRightMargin ) + { + nRightSpace = static_cast< sal_uInt16 >(aLRItem.GetRight()); + rCSS1PropInfo.bRightMargin = sal_False; + } + rCSS1ItemSet.ClearItem( RES_LR_SPACE ); + } + if( nLeftSpace || nRightSpace ) + { + SvxLRSpaceItem aLRItem( RES_LR_SPACE ); + aLRItem.SetLeft( nLeftSpace ); + aLRItem.SetRight( nRightSpace ); + aFrmSet.Put( aLRItem ); + } + + // oberen/unteren Rand setzen + if( SFX_ITEM_SET==rCSS1ItemSet.GetItemState( RES_UL_SPACE, sal_True, &pItem ) ) + { + // Ggf. den Erstzeilen-Einzug noch plaetten + const SvxULSpaceItem *pULItem = (const SvxULSpaceItem *)pItem; + if( rCSS1PropInfo.bTopMargin ) + { + nUpperSpace = pULItem->GetUpper(); + rCSS1PropInfo.bTopMargin = sal_False; + } + if( rCSS1PropInfo.bBottomMargin ) + { + nLowerSpace = pULItem->GetLower(); + rCSS1PropInfo.bBottomMargin = sal_False; + } + + rCSS1ItemSet.ClearItem( RES_UL_SPACE ); + } + if( nUpperSpace || nLowerSpace ) + { + SvxULSpaceItem aULItem( RES_UL_SPACE ); + aULItem.SetUpper( nUpperSpace ); + aULItem.SetLower( nLowerSpace ); + aFrmSet.Put( aULItem ); + } + + SwFmtAnchor aAnchor( FLY_AS_CHAR ); + if( SVX_CSS1_POS_ABSOLUTE == rCSS1PropInfo.ePosition && + SVX_CSS1_LTYPE_TWIP == rCSS1PropInfo.eLeftType && + SVX_CSS1_LTYPE_TWIP == rCSS1PropInfo.eTopType ) + { + const SwStartNode *pFlySttNd = + pPam->GetPoint()->nNode.GetNode().FindFlyStartNode(); + + if( pFlySttNd ) + { + aAnchor.SetType( FLY_AT_FLY ); + SwPosition aPos( *pFlySttNd ); + aAnchor.SetAnchor( &aPos ); + } + else + { + aAnchor.SetType( FLY_AT_PAGE ); + } + // OD 2004-04-13 #i26791# - direct positioning for <SwDoc::Insert(..)> + pNewDrawObj->SetRelativePos( Point(rCSS1PropInfo.nLeft + nLeftSpace, + rCSS1PropInfo.nTop + nUpperSpace) ); + aFrmSet.Put( SwFmtSurround(SURROUND_THROUGHT) ); + } + else if( SVX_ADJUST_LEFT == rCSS1PropInfo.eFloat || + text::HoriOrientation::LEFT == eHoriOri ) + { + aAnchor.SetType( FLY_AT_PARA ); + aFrmSet.Put( SwFmtSurround(bHidden ? SURROUND_THROUGHT + : SURROUND_RIGHT) ); + // OD 2004-04-13 #i26791# - direct positioning for <SwDoc::Insert(..)> + pNewDrawObj->SetRelativePos( Point(nLeftSpace, nUpperSpace) ); + } + else if( text::VertOrientation::NONE != eVertOri ) + { + aFrmSet.Put( SwFmtVertOrient( 0, eVertOri ) ); + } + + if (FLY_AT_PAGE == aAnchor.GetAnchorId()) + { + aAnchor.SetPageNum( 1 ); + } + else if( FLY_AT_FLY != aAnchor.GetAnchorId() ) + { + aAnchor.SetAnchor( pPam->GetPoint() ); + } + aFrmSet.Put( aAnchor ); + + pDoc->Insert( *pPam, *pNewDrawObj, &aFrmSet, NULL ); +} + +/* */ + +static void PutEEPoolItem( SfxItemSet &rEEItemSet, + const SfxPoolItem& rSwItem ) +{ + + sal_uInt16 nEEWhich = 0; + + switch( rSwItem.Which() ) + { + case RES_CHRATR_COLOR: nEEWhich = EE_CHAR_COLOR; break; + case RES_CHRATR_CROSSEDOUT: nEEWhich = EE_CHAR_STRIKEOUT; break; + case RES_CHRATR_ESCAPEMENT: nEEWhich = EE_CHAR_ESCAPEMENT; break; + case RES_CHRATR_FONT: nEEWhich = EE_CHAR_FONTINFO; break; + case RES_CHRATR_CJK_FONT: nEEWhich = EE_CHAR_FONTINFO_CJK; break; + case RES_CHRATR_CTL_FONT: nEEWhich = EE_CHAR_FONTINFO_CTL; break; + case RES_CHRATR_FONTSIZE: nEEWhich = EE_CHAR_FONTHEIGHT; break; + case RES_CHRATR_CJK_FONTSIZE: nEEWhich = EE_CHAR_FONTHEIGHT_CJK; break; + case RES_CHRATR_CTL_FONTSIZE: nEEWhich = EE_CHAR_FONTHEIGHT_CTL; break; + case RES_CHRATR_KERNING: nEEWhich = EE_CHAR_KERNING; break; + case RES_CHRATR_POSTURE: nEEWhich = EE_CHAR_ITALIC; break; + case RES_CHRATR_CJK_POSTURE: nEEWhich = EE_CHAR_ITALIC_CJK; break; + case RES_CHRATR_CTL_POSTURE: nEEWhich = EE_CHAR_ITALIC_CTL; break; + case RES_CHRATR_UNDERLINE: nEEWhich = EE_CHAR_UNDERLINE; break; + case RES_CHRATR_WEIGHT: nEEWhich = EE_CHAR_WEIGHT; break; + case RES_CHRATR_CJK_WEIGHT: nEEWhich = EE_CHAR_WEIGHT_CJK; break; + case RES_CHRATR_CTL_WEIGHT: nEEWhich = EE_CHAR_WEIGHT_CTL; break; + case RES_BACKGROUND: + case RES_CHRATR_BACKGROUND: + { + const SvxBrushItem& rBrushItem = (const SvxBrushItem&)rSwItem; + rEEItemSet.Put( XFillStyleItem(XFILL_SOLID) ); + rEEItemSet.Put( XFillColorItem(aEmptyStr, + rBrushItem.GetColor()) ); + } + break; + } + + if( nEEWhich ) + { + SfxPoolItem *pEEItem = rSwItem.Clone(); + pEEItem->SetWhich( nEEWhich ); + rEEItemSet.Put( *pEEItem ); + delete pEEItem; + } +} + +void SwHTMLParser::NewMarquee( HTMLTable *pCurTable ) +{ + + ASSERT( !pMarquee, "Marquee in Marquee???" ); + aContents.Erase(); + + String aId, aStyle, aClass; + + long nWidth=0, nHeight=0; + sal_Bool bPrcWidth = sal_False, bDirection = sal_False, bBGColor = sal_False; + Size aSpace( 0, 0 ); + sal_Int16 eVertOri = text::VertOrientation::TOP; + sal_Int16 eHoriOri = text::HoriOrientation::NONE; + SdrTextAniKind eAniKind = SDRTEXTANI_SCROLL; + SdrTextAniDirection eAniDir = SDRTEXTANI_LEFT; + sal_uInt16 nCount = 0, nDelay = 60; + sal_Int16 nAmount = -6; + Color aBGColor; + + const HTMLOptions *pHTMLOptions = GetOptions(); + sal_uInt16 nArrLen = pHTMLOptions->Count(); + for ( sal_uInt16 i=0; i<nArrLen; i++ ) + { + const HTMLOption *pOption = (*pHTMLOptions)[i]; + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + + case HTML_O_BEHAVIOR: + eAniKind = + (SdrTextAniKind)pOption->GetEnum( aHTMLMarqBehaviorTable, + static_cast< sal_uInt16 >(eAniKind) ); + break; + + case HTML_O_BGCOLOR: + pOption->GetColor( aBGColor ); + bBGColor = sal_True; + break; + + case HTML_O_DIRECTION: + eAniDir = + (SdrTextAniDirection)pOption->GetEnum( aHTMLMarqDirectionTable, + static_cast< sal_uInt16 >(eAniDir) ); + bDirection = sal_True; + break; + + case HTML_O_LOOP: + if( pOption->GetString(). + EqualsIgnoreCaseAscii(OOO_STRING_SVTOOLS_HTML_LOOP_infinite) ) + { + nCount = 0; + } + else + { + sal_uInt32 nLoop = pOption->GetSNumber(); + nCount = (sal_uInt16)(nLoop>0 ? nLoop : 0 ); + } + break; + + case HTML_O_SCROLLAMOUNT: + nAmount = -((sal_Int16)pOption->GetNumber()); + break; + + case HTML_O_SCROLLDELAY: + nDelay = (sal_uInt16)pOption->GetNumber(); + break; + + case HTML_O_WIDTH: + // erstmal nur als Pixelwerte merken! + nWidth = pOption->GetNumber(); + bPrcWidth = pOption->GetString().Search('%') != STRING_NOTFOUND; + if( bPrcWidth && nWidth>100 ) + nWidth = 100; + break; + + case HTML_O_HEIGHT: + // erstmal nur als Pixelwerte merken! + nHeight = pOption->GetNumber(); + if( pOption->GetString().Search('%') != STRING_NOTFOUND ) + nHeight = 0; + break; + + case HTML_O_HSPACE: + // erstmal nur als Pixelwerte merken! + aSpace.Height() = pOption->GetNumber(); + break; + + case HTML_O_VSPACE: + // erstmal nur als Pixelwerte merken! + aSpace.Width() = pOption->GetNumber(); + break; + + case HTML_O_ALIGN: + eVertOri = + pOption->GetEnum( aHTMLImgVAlignTable, + text::VertOrientation::TOP ); + eHoriOri = + pOption->GetEnum( aHTMLImgHAlignTable, + text::HoriOrientation::NONE ); + break; + } + } + + // Ein DrawTxtobj anlegen + // --> OD 2005-08-08 #i52858# - method name changed + SdrModel* pModel = pDoc->GetOrCreateDrawModel(); + // <-- + SdrPage* pPg = pModel->GetPage( 0 ); + pMarquee = SdrObjFactory::MakeNewObject( SdrInventor, + OBJ_TEXT, pPg, pModel ); + if( !pMarquee ) + return; + + pPg->InsertObject( pMarquee ); + + if( aId.Len() ) + InsertBookmark( aId ); + + // (Nur) Alternate leueft per Default von links nach rechts + if( SDRTEXTANI_ALTERNATE==eAniKind && !bDirection ) + eAniDir = SDRTEXTANI_RIGHT; + + // die fuer das Scrollen benoetigten Attribute umsetzen + sal_uInt16 aWhichMap[7] = { XATTR_FILL_FIRST, XATTR_FILL_LAST, + SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST, + EE_CHAR_START, EE_CHAR_END, + 0 }; + SfxItemSet aItemSet( pModel->GetItemPool(), aWhichMap ); + aItemSet.Put( SdrTextAutoGrowWidthItem( sal_False ) ); + aItemSet.Put( SdrTextAutoGrowHeightItem( sal_True ) ); + aItemSet.Put( SdrTextAniKindItem( eAniKind ) ); + aItemSet.Put( SdrTextAniDirectionItem( eAniDir ) ); + aItemSet.Put( SdrTextAniCountItem( nCount ) ); + aItemSet.Put( SdrTextAniDelayItem( nDelay ) ); + aItemSet.Put( SdrTextAniAmountItem( nAmount ) ); + if( SDRTEXTANI_ALTERNATE==eAniKind ) + { + // (Nur) Alternate startet und stoppt per default Inside + aItemSet.Put( SdrTextAniStartInsideItem(sal_True) ); + aItemSet.Put( SdrTextAniStopInsideItem(sal_True) ); + if( SDRTEXTANI_LEFT==eAniDir ) + aItemSet.Put( SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_RIGHT) ); + } + + // die Default-Farbe (aus der Standard-Vorlage) setzen, damit ueberhaupt + // eine sinnvolle Farbe gesetzt ist. + const Color& rDfltColor = + pCSS1Parser->GetTxtCollFromPool( RES_POOLCOLL_STANDARD ) + ->GetColor().GetValue(); + aItemSet.Put( SvxColorItem( rDfltColor, EE_CHAR_COLOR ) ); + + // Die Attribute der aktuellen Absatzvorlage setzen + sal_uInt16 nWhichIds[] = + { + RES_CHRATR_COLOR, RES_CHRATR_CROSSEDOUT, RES_CHRATR_ESCAPEMENT, + RES_CHRATR_FONT, RES_CHRATR_FONTSIZE, RES_CHRATR_KERNING, + RES_CHRATR_POSTURE, RES_CHRATR_UNDERLINE, RES_CHRATR_WEIGHT, + RES_CHRATR_BACKGROUND, + 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, + 0 + }; + SwTxtNode const*const pTxtNd = + pPam->GetPoint()->nNode.GetNode().GetTxtNode(); + if( pTxtNd ) + { + const SfxItemSet& rItemSet = pTxtNd->GetAnyFmtColl().GetAttrSet(); + const SfxPoolItem *pItem; + for( sal_uInt16 i=0; nWhichIds[i]; i++ ) + { + if( SFX_ITEM_SET == rItemSet.GetItemState( nWhichIds[i], sal_True, &pItem ) ) + PutEEPoolItem( aItemSet, *pItem ); + } + } + + // die Attribute der Umgebung am Draw-Objekt setzen + _HTMLAttr** pTbl = (_HTMLAttr**)&aAttrTab; + for( sal_uInt16 nCnt = sizeof( _HTMLAttrTable ) / sizeof( _HTMLAttr* ); + nCnt--; ++pTbl ) + { + _HTMLAttr *pAttr = *pTbl; + if( pAttr ) + PutEEPoolItem( aItemSet, pAttr->GetItem() ); + } + + if( bBGColor ) + { + aItemSet.Put( XFillStyleItem(XFILL_SOLID) ); + aItemSet.Put( XFillColorItem(aEmptyStr, aBGColor) ); + } + + // Styles parsen (funktioniert hier nur fuer Attribute, die auch + // am Zeichen-Objekt gesetzt werden koennen) + SfxItemSet aStyleItemSet( pDoc->GetAttrPool(), + pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + if( HasStyleOptions( aStyle, aId, aClass ) && + ParseStyleOptions( aStyle, aId, aClass, aStyleItemSet, aPropInfo ) ) + { + SfxItemIter aIter( aStyleItemSet ); + + const SfxPoolItem *pItem = aIter.FirstItem(); + while( pItem ) + { + PutEEPoolItem( aItemSet, *pItem ); + pItem = aIter.NextItem(); + } + } + + // jetzt noch die Groesse setzen + Size aTwipSz( bPrcWidth ? 0 : nWidth, nHeight ); + if( (aTwipSz.Width() || aTwipSz.Height()) && Application::GetDefaultDevice() ) + { + aTwipSz = Application::GetDefaultDevice() + ->PixelToLogic( aTwipSz, MapMode( MAP_TWIP ) ); + } + + if( SVX_CSS1_LTYPE_TWIP== aPropInfo.eWidthType ) + { + aTwipSz.Width() = aPropInfo.nWidth; + nWidth = 1; // != 0; + bPrcWidth = sal_False; + } + if( SVX_CSS1_LTYPE_TWIP== aPropInfo.eHeightType ) + aTwipSz.Height() = aPropInfo.nHeight; + + bFixMarqueeWidth = sal_False; + if( !nWidth || bPrcWidth ) + { + if( pTable ) + { + if( !pCurTable ) + { + // Die Laufschrift steht in einer Tabelle, aber nicht + // in einer Zelle. Da jetzt keine vernuenftige Zuordung + // zu einer Zelle moeglich ist, passen wir hir die + // Breite dem Inhalt der Laufschrift an. + bFixMarqueeWidth = sal_True; + } + else if( !nWidth ) + { + // Da wir wissen, in welcher Zelle die Laufschrift ist, + // koennen wir die Breite auch anpassen. Keine Breitenangabe + // wird wie 100% behandelt. + nWidth = 100; + bPrcWidth = sal_True; + } + aTwipSz.Width() = MINLAY; + } + else + { + long nBrowseWidth = GetCurrentBrowseWidth(); + aTwipSz.Width() = !nWidth ? nBrowseWidth + : (nWidth*nBrowseWidth) / 100; + } + } + + // Die Hoehe ist nur eine Mindest-Hoehe + if( aTwipSz.Height() < MINFLY ) + aTwipSz.Height() = MINFLY; + aItemSet.Put( SdrTextMinFrameHeightItem( aTwipSz.Height() ) ); + + pMarquee->SetMergedItemSetAndBroadcast(aItemSet); + + if( aTwipSz.Width() < MINFLY ) + aTwipSz.Width() = MINFLY; + pMarquee->SetLogicRect( Rectangle( 0, 0, aTwipSz.Width(), aTwipSz.Height() ) ); + + // und das Objekt in das Dok einfuegen + InsertDrawObject( pMarquee, aSpace, eVertOri, eHoriOri, aStyleItemSet, + aPropInfo ); + + // Das Zeichen-Objekt der Tabelle bekanntmachen. Ist ein bisserl + // umstaendlich, weil noch ueber den Parser gegangen wird, obwohl die + // Tabelle bekannt ist, aber anderenfalls muesste man die Tabelle + // oeffentlich machen, und das ist auch nicht schoen. Das globale + // pTable kann uebrigens auch nicht verwendet werden, denn die + // Laufschrift kann sich auch mal in einer Sub-Tabelle befinden. + if( pCurTable && bPrcWidth) + RegisterDrawObjectToTable( pCurTable, pMarquee, (sal_uInt8)nWidth ); +} + +void SwHTMLParser::EndMarquee() +{ + ASSERT( pMarquee && OBJ_TEXT==pMarquee->GetObjIdentifier(), + "kein Marquee oder falscher Typ" ); + + if( bFixMarqueeWidth ) + { + // Da es keine fixe Hoehe gibt, das Text-Objekt erstmal breiter + // als den Text machen, damit nicht umgebrochen wird. + const Rectangle& rOldRect = pMarquee->GetLogicRect(); + pMarquee->SetLogicRect( Rectangle( rOldRect.TopLeft(), + Size( USHRT_MAX, 240 ) ) ); + } + + // den gesammelten Text einfuegen + ((SdrTextObj*)pMarquee)->SetText( aContents ); + pMarquee->SetMergedItemSetAndBroadcast( pMarquee->GetMergedItemSet() ); + + if( bFixMarqueeWidth ) + { + // die Groesse dem Text anpassen. + ((SdrTextObj*)pMarquee)->FitFrameToTextSize(); + } + + aContents.Erase(); + pMarquee = 0; +} + +void SwHTMLParser::InsertMarqueeText() +{ + ASSERT( pMarquee && OBJ_TEXT==pMarquee->GetObjIdentifier(), + "kein Marquee oder falscher Typ" ); + + // das akteulle Textstueck an den Text anhaengen + aContents += aToken; +} + +void SwHTMLParser::ResizeDrawObject( SdrObject* pObj, SwTwips nWidth ) +{ + ASSERT( OBJ_TEXT==pObj->GetObjIdentifier(), + "kein Marquee oder falscher Typ" ); + + if( OBJ_TEXT!=pObj->GetObjIdentifier() ) + return; + + // die alte Groesse + const Rectangle& rOldRect = pObj->GetLogicRect(); + Size aNewSz( nWidth, rOldRect.GetSize().Height() ); + pObj->SetLogicRect( Rectangle( rOldRect.TopLeft(), aNewSz ) ); +} + +/* */ + +const SdrObject *SwHTMLWriter::GetMarqueeTextObj( const SwDrawFrmFmt& rFmt ) +{ + const SdrObject* pObj = rFmt.FindSdrObject(); + return (pObj && ::IsMarqueeTextObj( *pObj )) ? pObj : 0; +} + +void SwHTMLWriter::GetEEAttrsFromDrwObj( SfxItemSet& rItemSet, + const SdrObject *pObj, + sal_Bool bSetDefaults ) +{ + // die Edit script::Engine-Attribute aus dem Objekt holen + SfxItemSet rObjItemSet = pObj->GetMergedItemSet(); + + // ueber die Edit script::Engine-Attribute iterieren und die Attribute + // in SW-Attrs wandeln bzw. default setzen + SfxWhichIter aIter( rObjItemSet ); + sal_uInt16 nEEWhich = aIter.FirstWhich(); + while( nEEWhich ) + { + const SfxPoolItem *pEEItem; + sal_Bool bSet = SFX_ITEM_SET == rObjItemSet.GetItemState( nEEWhich, sal_False, + &pEEItem ); + + if( bSet || bSetDefaults ) + { + sal_uInt16 nSwWhich = 0; + switch( nEEWhich ) + { + case EE_CHAR_COLOR: nSwWhich = RES_CHRATR_COLOR; break; + case EE_CHAR_STRIKEOUT: nSwWhich = RES_CHRATR_CROSSEDOUT; break; + case EE_CHAR_ESCAPEMENT: nSwWhich = RES_CHRATR_ESCAPEMENT; break; + case EE_CHAR_FONTINFO: nSwWhich = RES_CHRATR_FONT; break; + case EE_CHAR_FONTINFO_CJK: nSwWhich = RES_CHRATR_CJK_FONT; break; + case EE_CHAR_FONTINFO_CTL: nSwWhich = RES_CHRATR_CTL_FONT; break; + case EE_CHAR_FONTHEIGHT: nSwWhich = RES_CHRATR_FONTSIZE; break; + case EE_CHAR_FONTHEIGHT_CJK:nSwWhich = RES_CHRATR_CJK_FONTSIZE; break; + case EE_CHAR_FONTHEIGHT_CTL:nSwWhich = RES_CHRATR_CTL_FONTSIZE; break; + case EE_CHAR_KERNING: nSwWhich = RES_CHRATR_KERNING; break; + case EE_CHAR_ITALIC: nSwWhich = RES_CHRATR_POSTURE; break; + case EE_CHAR_ITALIC_CJK: nSwWhich = RES_CHRATR_CJK_POSTURE; break; + case EE_CHAR_ITALIC_CTL: nSwWhich = RES_CHRATR_CTL_POSTURE; break; + case EE_CHAR_UNDERLINE: nSwWhich = RES_CHRATR_UNDERLINE; break; + case EE_CHAR_WEIGHT: nSwWhich = RES_CHRATR_WEIGHT; break; + case EE_CHAR_WEIGHT_CJK: nSwWhich = RES_CHRATR_CJK_WEIGHT; break; + case EE_CHAR_WEIGHT_CTL: nSwWhich = RES_CHRATR_CTL_WEIGHT; break; + } + + if( nSwWhich ) + { + // wenn das Item nicht gesetzt ist nehmen wir ggf. das + // Default-Item + if( !bSet ) + pEEItem = &rObjItemSet.GetPool()->GetDefaultItem(nEEWhich); + + // jetzt Clonen wir das Item mit der Which-Id des Writers + SfxPoolItem *pSwItem = pEEItem->Clone(); + pSwItem->SetWhich( nSwWhich ); + rItemSet.Put( *pSwItem ); + delete pSwItem; + } + } + + nEEWhich = aIter.NextWhich(); + } +} + + +Writer& OutHTML_DrawFrmFmtAsMarquee( Writer& rWrt, + const SwDrawFrmFmt& rFmt, + const SdrObject& rSdrObject ) +{ + SwHTMLWriter & rHTMLWrt = (SwHTMLWriter&)rWrt; + + ASSERT( rWrt.pDoc->GetDrawModel(), "Da gibt's ein Draw-Obj ohne ein Draw-Model zu haben?" ); + const SdrTextObj *pTextObj = (const SdrTextObj *)&rSdrObject; + + // Gibt es ueberhaupt auszugebenden Text + const OutlinerParaObject *pOutlinerParaObj = + pTextObj->GetOutlinerParaObject(); + if( !pOutlinerParaObj ) + return rWrt; + + ByteString sOut( '<' ); + sOut += OOO_STRING_SVTOOLS_HTML_marquee; + + // Die Attribute des Objektd holen + const SfxItemSet& rItemSet = pTextObj->GetMergedItemSet(); + + // BEHAVIOUR + SdrTextAniKind eAniKind = pTextObj->GetTextAniKind(); + ASSERT( SDRTEXTANI_SCROLL==eAniKind || + SDRTEXTANI_ALTERNATE==eAniKind || + SDRTEXTANI_SLIDE==eAniKind, + "Text-Draw-Objekt nicht fuer Marquee geeignet" ) + + const sal_Char *pStr = 0; + switch( eAniKind ) + { + case SDRTEXTANI_SCROLL: pStr = OOO_STRING_SVTOOLS_HTML_BEHAV_scroll; break; + case SDRTEXTANI_SLIDE: pStr = OOO_STRING_SVTOOLS_HTML_BEHAV_slide; break; + case SDRTEXTANI_ALTERNATE: pStr = OOO_STRING_SVTOOLS_HTML_BEHAV_alternate; break; + default: + ; + } + + if( pStr ) + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_behavior) += '=') += pStr; + + // DIRECTION + pStr = 0; + SdrTextAniDirection eAniDir = pTextObj->GetTextAniDirection(); + switch( eAniDir ) + { + case SDRTEXTANI_LEFT: pStr = OOO_STRING_SVTOOLS_HTML_AL_left; break; + case SDRTEXTANI_RIGHT: pStr = OOO_STRING_SVTOOLS_HTML_AL_right; break; + default: + ; + } + + if( pStr ) + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_direction) += '=') += pStr; + + // LOOP + sal_Int32 nCount = + ((const SdrTextAniCountItem&)rItemSet.Get( SDRATTR_TEXT_ANICOUNT )) + .GetValue(); + if( 0==nCount ) + nCount = SDRTEXTANI_SLIDE==eAniKind ? 1 : -1; + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_loop) += '=') + += ByteString::CreateFromInt32( nCount ); + + // SCROLLDELAY + sal_uInt16 nDelay = + ((const SdrTextAniDelayItem&)rItemSet.Get( SDRATTR_TEXT_ANIDELAY )) + .GetValue(); + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_scrolldelay) += '=') + += ByteString::CreateFromInt32( nDelay ); + + // SCROLLAMOUNT + sal_Int16 nAmount = + ((const SdrTextAniAmountItem&)rItemSet.Get( SDRATTR_TEXT_ANIAMOUNT )) + .GetValue(); + if( nAmount < 0 ) + { + nAmount = -nAmount; + } + else if( nAmount && Application::GetDefaultDevice() ) + { + nAmount = (sal_uInt16)(Application::GetDefaultDevice() + ->LogicToPixel( Size(nAmount,0), + MapMode(MAP_TWIP) ).Width()); + } + if( nAmount ) + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_scrollamount) += '=') + += ByteString::CreateFromInt32( nAmount ); + + Size aTwipSz( pTextObj->GetLogicRect().GetSize() ); + if( pTextObj->IsAutoGrowWidth() ) + aTwipSz.Width() = 0; + // Die Hoehe ist bei MS eine Mindesthoehe, also geben wir auch die + // Mindestheoehe aus, wenn es sie gibt. Da eine Mindesthoehe MINFLY + // mit hoher Wahrscheinlichkeit vom Import kommt, wird sie nicht mit + // ausgegeben. Falsch machen kann man da nichst, denn jeder Font ist + // hoeher. + if( pTextObj->IsAutoGrowHeight() ) + { + aTwipSz.Height() = pTextObj->GetMinTextFrameHeight(); + if( MINFLY==aTwipSz.Height() ) + aTwipSz.Height() = 0; + } + + if( (aTwipSz.Width() || aTwipSz.Height()) && + Application::GetDefaultDevice() ) + { + Size aPixelSz = + Application::GetDefaultDevice()->LogicToPixel( aTwipSz, + MapMode(MAP_TWIP) ); + if( !aPixelSz.Width() && aTwipSz.Width() ) + aPixelSz.Width() = 1; + if( !aPixelSz.Height() && aTwipSz.Height() ) + aPixelSz.Height() = 1; + + if( aPixelSz.Width() ) + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_width) += '=') + += ByteString::CreateFromInt32( aPixelSz.Width() ); + + if( aPixelSz.Height() ) + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_height) += '=') + += ByteString::CreateFromInt32( aPixelSz.Height() ); + } + + // BGCOLOR + XFillStyle eFillStyle = + ((const XFillStyleItem&)rItemSet.Get(XATTR_FILLSTYLE)).GetValue(); + if( XFILL_SOLID==eFillStyle ) + { + const Color& rFillColor = + ((const XFillColorItem&)rItemSet.Get(XATTR_FILLCOLOR)).GetColorValue(); + + ((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_bgcolor) += '='; + rWrt.Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_Color( rWrt.Strm(), rFillColor, rHTMLWrt.eDestEnc ); + sOut.Erase(); + } + + if( sOut.Len() ) + rWrt.Strm() << sOut.GetBuffer(); + + // und nun noch ALIGN, HSPACE und VSPACE + ByteString aEndTags; + sal_uInt32 nFrmFlags = HTML_FRMOPTS_MARQUEE; + if( rHTMLWrt.IsHTMLMode( HTMLMODE_ABS_POS_DRAW ) ) + nFrmFlags |= HTML_FRMOPTS_MARQUEE_CSS1; + rHTMLWrt.OutFrmFmtOptions( rFmt, aEmptyStr, aEndTags, nFrmFlags ); + if( rHTMLWrt.IsHTMLMode( HTMLMODE_ABS_POS_DRAW ) ) + rHTMLWrt.OutCSS1_FrmFmtOptions( rFmt, nFrmFlags, &rSdrObject ); + + + rWrt.Strm() << '>'; + + // Was jetzt kommt ist das Gegenstueck zu SdrTextObjectt::SetText() + Outliner aOutliner(0, OUTLINERMODE_TEXTOBJECT); + aOutliner.SetUpdateMode( sal_False ); + aOutliner.SetText( *pOutlinerParaObj ); + String aText( aOutliner.GetText( aOutliner.GetParagraph(0), + aOutliner.GetParagraphCount() ) ); + HTMLOutFuncs::Out_String( rWrt.Strm(), aText, + rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_marquee, sal_False ); + + if( aEndTags.Len() ) + rWrt.Strm() << aEndTags.GetBuffer(); + + return rWrt; +} + + diff --git a/sw/source/filter/html/htmlfld.cxx b/sw/source/filter/html/htmlfld.cxx new file mode 100644 index 000000000000..1419f771fe71 --- /dev/null +++ b/sw/source/filter/html/htmlfld.cxx @@ -0,0 +1,670 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + + +#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> +#include <com/sun/star/document/XDocumentProperties.hpp> + +#include "docsh.hxx" +#include <svtools/htmltokn.h> +#include <svl/zformat.hxx> +#include <unotools/useroptions.hxx> +#include <fmtfld.hxx> +#include <ndtxt.hxx> +#include <doc.hxx> +#include <fldbas.hxx> +#include <docufld.hxx> +#include <flddat.hxx> +#include <htmlfld.hxx> +#include <swhtml.hxx> + +using namespace nsSwDocInfoSubType; +using namespace ::com::sun::star; + +struct HTMLNumFmtTblEntry +{ + const sal_Char *pName; + NfIndexTableOffset eFmt; +}; + +static HTMLOptionEnum __FAR_DATA aHTMLFldTypeTable[] = +{ + { OOO_STRING_SW_HTML_FT_author, RES_AUTHORFLD }, + { OOO_STRING_SW_HTML_FT_sender, RES_EXTUSERFLD }, + { "DATE", RES_DATEFLD }, + { "TIME", RES_TIMEFLD }, + { OOO_STRING_SW_HTML_FT_datetime,RES_DATETIMEFLD }, + { OOO_STRING_SW_HTML_FT_page, RES_PAGENUMBERFLD }, + { OOO_STRING_SW_HTML_FT_docinfo, RES_DOCINFOFLD }, + { OOO_STRING_SW_HTML_FT_docstat, RES_DOCSTATFLD }, + { OOO_STRING_SW_HTML_FT_filename,RES_FILENAMEFLD }, + { 0, 0 } +}; + +static HTMLNumFmtTblEntry __FAR_DATA aHTMLDateFldFmtTable[] = +{ + { "SSYS", NF_DATE_SYSTEM_SHORT }, + { "LSYS", NF_DATE_SYSTEM_LONG }, + { "DMY", NF_DATE_SYS_DDMMYY, }, + { "DMYY", NF_DATE_SYS_DDMMYYYY, }, + { "DMMY", NF_DATE_SYS_DMMMYY, }, + { "DMMYY", NF_DATE_SYS_DMMMYYYY, }, + { "DMMMY", NF_DATE_DIN_DMMMMYYYY }, + { "DMMMYY", NF_DATE_DIN_DMMMMYYYY }, + { "DDMMY", NF_DATE_SYS_NNDMMMYY }, + { "DDMMMY", NF_DATE_SYS_NNDMMMMYYYY }, + { "DDMMMYY", NF_DATE_SYS_NNDMMMMYYYY }, + { "DDDMMMY", NF_DATE_SYS_NNNNDMMMMYYYY }, + { "DDDMMMYY", NF_DATE_SYS_NNNNDMMMMYYYY }, + { "MY", NF_DATE_SYS_MMYY }, + { "MD", NF_DATE_DIN_MMDD }, + { "YMD", NF_DATE_DIN_YYMMDD }, + { "YYMD", NF_DATE_DIN_YYYYMMDD }, + { 0, NF_NUMERIC_START } +}; + +static HTMLNumFmtTblEntry __FAR_DATA aHTMLTimeFldFmtTable[] = +{ + { "SYS", NF_TIME_HHMMSS }, + { "SSMM24", NF_TIME_HHMM }, + { "SSMM12", NF_TIME_HHMMAMPM }, + { 0, NF_NUMERIC_START } +}; + +static HTMLOptionEnum __FAR_DATA aHTMLPageNumFldFmtTable[] = +{ + { OOO_STRING_SW_HTML_FF_uletter, SVX_NUM_CHARS_UPPER_LETTER }, + { OOO_STRING_SW_HTML_FF_lletter, SVX_NUM_CHARS_LOWER_LETTER }, + { OOO_STRING_SW_HTML_FF_uroman, SVX_NUM_ROMAN_UPPER }, + { OOO_STRING_SW_HTML_FF_lroman, SVX_NUM_ROMAN_LOWER }, + { OOO_STRING_SW_HTML_FF_arabic, SVX_NUM_ARABIC }, + { OOO_STRING_SW_HTML_FF_none, SVX_NUM_NUMBER_NONE }, + { OOO_STRING_SW_HTML_FF_char, SVX_NUM_CHAR_SPECIAL }, + { OOO_STRING_SW_HTML_FF_page, SVX_NUM_PAGEDESC }, + { OOO_STRING_SW_HTML_FF_ulettern, SVX_NUM_CHARS_UPPER_LETTER_N }, + { OOO_STRING_SW_HTML_FF_llettern, SVX_NUM_CHARS_LOWER_LETTER_N }, + { 0, 0 } +}; + + +static HTMLOptionEnum __FAR_DATA aHTMLExtUsrFldSubTable[] = +{ + { OOO_STRING_SW_HTML_FS_company, EU_COMPANY }, + { OOO_STRING_SW_HTML_FS_firstname, EU_FIRSTNAME }, + { OOO_STRING_SW_HTML_FS_name, EU_NAME }, + { OOO_STRING_SW_HTML_FS_shortcut, EU_SHORTCUT }, + { OOO_STRING_SW_HTML_FS_street, EU_STREET }, + { OOO_STRING_SW_HTML_FS_country, EU_COUNTRY }, + { OOO_STRING_SW_HTML_FS_zip, EU_ZIP }, + { OOO_STRING_SW_HTML_FS_city, EU_CITY }, + { OOO_STRING_SW_HTML_FS_title, EU_TITLE }, + { OOO_STRING_SW_HTML_FS_position, EU_POSITION }, + { OOO_STRING_SW_HTML_FS_pphone, EU_PHONE_PRIVATE }, + { OOO_STRING_SW_HTML_FS_cphone, EU_PHONE_COMPANY }, + { OOO_STRING_SW_HTML_FS_fax, EU_FAX }, + { OOO_STRING_SW_HTML_FS_email, EU_EMAIL }, + { OOO_STRING_SW_HTML_FS_state, EU_STATE }, + { 0, 0 } +}; + +static HTMLOptionEnum __FAR_DATA aHTMLAuthorFldFmtTable[] = +{ + { OOO_STRING_SW_HTML_FF_name, AF_NAME }, + { OOO_STRING_SW_HTML_FF_shortcut, AF_SHORTCUT }, + { 0, 0 } +}; + +static HTMLOptionEnum __FAR_DATA aHTMLPageNumFldSubTable[] = +{ + { OOO_STRING_SW_HTML_FS_random, PG_RANDOM }, + { OOO_STRING_SW_HTML_FS_next, PG_NEXT }, + { OOO_STRING_SW_HTML_FS_prev, PG_PREV }, + { 0, 0 } +}; + +// UGLY: these are extensions of nsSwDocInfoSubType (in inc/docufld.hxx) +// these are necessary for importing document info fields written by +// older versions of OOo (< 3.0) which did not have DI_CUSTOM fields + const SwDocInfoSubType DI_INFO1 = DI_SUBTYPE_END + 1; + const SwDocInfoSubType DI_INFO2 = DI_SUBTYPE_END + 2; + const SwDocInfoSubType DI_INFO3 = DI_SUBTYPE_END + 3; + const SwDocInfoSubType DI_INFO4 = DI_SUBTYPE_END + 4; + +static HTMLOptionEnum __FAR_DATA aHTMLDocInfoFldSubTable[] = +{ + { OOO_STRING_SW_HTML_FS_title, DI_TITEL }, + { OOO_STRING_SW_HTML_FS_theme, DI_THEMA }, + { OOO_STRING_SW_HTML_FS_keys, DI_KEYS }, + { OOO_STRING_SW_HTML_FS_comment, DI_COMMENT }, + { "INFO1", DI_INFO1 }, + { "INFO2", DI_INFO2 }, + { "INFO3", DI_INFO3 }, + { "INFO4", DI_INFO4 }, + { OOO_STRING_SW_HTML_FS_custom, DI_CUSTOM }, + { OOO_STRING_SW_HTML_FS_create, DI_CREATE }, + { OOO_STRING_SW_HTML_FS_change, DI_CHANGE }, + { 0, 0 } +}; + +static HTMLOptionEnum __FAR_DATA aHTMLDocInfoFldFmtTable[] = +{ + { OOO_STRING_SW_HTML_FF_author, DI_SUB_AUTHOR }, + { OOO_STRING_SW_HTML_FF_time, DI_SUB_TIME }, + { OOO_STRING_SW_HTML_FF_date, DI_SUB_DATE }, + { 0, 0 } +}; + +static HTMLOptionEnum __FAR_DATA aHTMLDocStatFldSubTable[] = +{ + { OOO_STRING_SW_HTML_FS_page, DS_PAGE }, + { OOO_STRING_SW_HTML_FS_para, DS_PARA }, + { OOO_STRING_SW_HTML_FS_word, DS_WORD }, + { OOO_STRING_SW_HTML_FS_char, DS_CHAR }, + { OOO_STRING_SW_HTML_FS_tbl, DS_TBL }, + { OOO_STRING_SW_HTML_FS_grf, DS_GRF }, + { OOO_STRING_SW_HTML_FS_ole, DS_OLE }, + { 0, 0 } +}; + +static HTMLOptionEnum __FAR_DATA aHTMLFileNameFldFmtTable[] = +{ + { OOO_STRING_SW_HTML_FF_name, FF_NAME }, + { OOO_STRING_SW_HTML_FF_pathname, FF_PATHNAME }, + { OOO_STRING_SW_HTML_FF_path, FF_PATH }, + { OOO_STRING_SW_HTML_FF_name_noext, FF_NAME_NOEXT }, + { 0, 0 } +}; + +/* */ + +sal_uInt16 SwHTMLParser::GetNumType( const String& rStr, sal_uInt16 nDfltType ) +{ + sal_uInt16 nType = nDfltType; + const HTMLOptionEnum *pOptEnums = aHTMLPageNumFldFmtTable; + while( pOptEnums->pName ) + if( !rStr.EqualsIgnoreCaseAscii( pOptEnums->pName ) ) + pOptEnums++; + else + break; + + if( pOptEnums->pName ) + nType = pOptEnums->nValue; + + return nType; +} + + +void SwHTMLParser::NewField() +{ + sal_Bool bKnownType = sal_False, bFixed = sal_False, + bHasNumFmt = sal_False, bHasNumValue = sal_False; + sal_uInt16 nType = 0; + String aValue, aNumFmt, aNumValue, aName; + const HTMLOption *pSubOption=0, *pFmtOption=0; + + const HTMLOptions *pHTMLOptions = GetOptions(); + sal_uInt16 i; + + for( i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_TYPE: + bKnownType = pOption->GetEnum( nType, aHTMLFldTypeTable ); + break; + case HTML_O_SUBTYPE: + pSubOption = pOption; + break; + case HTML_O_FORMAT: + pFmtOption = pOption; + break; + case HTML_O_NAME: + aName = pOption->GetString(); + break; + case HTML_O_VALUE: + aValue = pOption->GetString(); + break; + case HTML_O_SDNUM: + aNumFmt = pOption->GetString(); + bHasNumFmt = sal_True; + break; + case HTML_O_SDVAL: + aNumValue = pOption->GetString(); + bHasNumValue = sal_True; + break; + case HTML_O_SDFIXED: + bFixed = sal_True; + break; + } + } + + if( !bKnownType ) + return; + + // Autor und Absender werden nur als als variables Feld eingefuegt, + // wenn man das Dok selbst als letztes geaendert hat oder es noch + // niemend geandert hat und man das Dok erstellt hat. Sonst + // wird ein Fixed-Feld daraus gemacht. + if( !bFixed && + (RES_EXTUSERFLD == (RES_FIELDS)nType || + RES_AUTHORFLD == (RES_FIELDS)nType) ) + { + SvtUserOptions aOpt; + const String& rUser = aOpt.GetFullName(); + SwDocShell *pDocShell(pDoc->GetDocShell()); + DBG_ASSERT(pDocShell, "no SwDocShell"); + if (pDocShell) { + uno::Reference<document::XDocumentPropertiesSupplier> xDPS( + pDocShell->GetModel(), uno::UNO_QUERY_THROW); + uno::Reference<document::XDocumentProperties> xDocProps( + xDPS->getDocumentProperties()); + DBG_ASSERT(xDocProps.is(), "Doc has no DocumentProperties"); + const String& rChanged = xDocProps->getModifiedBy(); + const String& rCreated = xDocProps->getAuthor(); + if( !rUser.Len() || + (rChanged.Len() ? rUser != rChanged : rUser != rCreated) ) + bFixed = sal_True; + } + } + + sal_uInt16 nWhich = nType; + if( RES_DATEFLD==nType || RES_TIMEFLD==nType ) + nWhich = RES_DATETIMEFLD; + + SwFieldType* pType = pDoc->GetSysFldType( nWhich ); + SwField *pFld = 0; + sal_Bool bInsOnEndTag = sal_False; + + switch( (RES_FIELDS)nType ) + { + case RES_EXTUSERFLD: + if( pSubOption ) + { + sal_uInt16 nSub; + sal_uLong nFmt = 0; + if( bFixed ) + { + nFmt |= AF_FIXED; + bInsOnEndTag = sal_True; + } + if( pSubOption->GetEnum( nSub, aHTMLExtUsrFldSubTable ) ) + pFld = new SwExtUserField( (SwExtUserFieldType*)pType, + nSub, nFmt ); + } + break; + + case RES_AUTHORFLD: + { + sal_uInt16 nFmt = AF_NAME; + if( pFmtOption ) + pFmtOption->GetEnum( nFmt, aHTMLAuthorFldFmtTable ); + if( bFixed ) + { + nFmt |= AF_FIXED; + bInsOnEndTag = sal_True; + } + + pFld = new SwAuthorField( (SwAuthorFieldType *)pType, nFmt ); + } + break; + + case RES_DATEFLD: + case RES_TIMEFLD: + { + sal_uLong nNumFmt = 0; + sal_uLong nTime = Time().GetTime(), nDate = Date().GetDate(); + sal_uInt16 nSub = 0; + sal_Bool bValidFmt = sal_False; + HTMLNumFmtTblEntry * pFmtTbl; + + if( RES_DATEFLD==nType ) + { + nSub = DATEFLD; + pFmtTbl = aHTMLDateFldFmtTable; + if( aValue.Len() ) + nDate = (sal_uLong)aValue.ToInt32(); + } + else + { + nSub = TIMEFLD; + pFmtTbl = aHTMLTimeFldFmtTable; + if( aValue.Len() ) + nTime = (sal_uLong)aValue.ToInt32(); + } + if( aValue.Len() ) + nSub |= FIXEDFLD; + + SvNumberFormatter *pFormatter = pDoc->GetNumberFormatter(); + if( pFmtOption ) + { + const String& rFmt = pFmtOption->GetString(); + for( sal_uInt16 k = 0; pFmtTbl[k].pName; k++ ) + { + if( rFmt.EqualsIgnoreCaseAscii( pFmtTbl[k].pName ) ) + { + nNumFmt = pFormatter->GetFormatIndex( + pFmtTbl[k].eFmt, LANGUAGE_SYSTEM); + bValidFmt = sal_True; + break; + } + } + } + if( !bValidFmt ) + nNumFmt = pFormatter->GetFormatIndex( pFmtTbl[i].eFmt, + LANGUAGE_SYSTEM); + + pFld = new SwDateTimeField( (SwDateTimeFieldType *)pType, + nSub, nNumFmt ); + + if (nSub & FIXEDFLD) + ((SwDateTimeField *)pFld)->SetDateTime( DateTime(Date(nDate), Time(nTime)) ); + } + break; + + case RES_DATETIMEFLD: + if( bHasNumFmt ) + { + sal_uInt16 nSub = 0; + + SvNumberFormatter *pFormatter = pDoc->GetNumberFormatter(); + sal_uInt32 nNumFmt; + LanguageType eLang; + double dValue = GetTableDataOptionsValNum( + nNumFmt, eLang, aNumValue, aNumFmt, + *pDoc->GetNumberFormatter() ); + short nFmtType = pFormatter->GetType( nNumFmt ); + switch( nFmtType ) + { + case NUMBERFORMAT_DATE: nSub = DATEFLD; break; + case NUMBERFORMAT_TIME: nSub = TIMEFLD; break; + } + + if( nSub ) + { + if( bHasNumValue ) + nSub |= FIXEDFLD; + + pFld = new SwDateTimeField( (SwDateTimeFieldType *)pType, + nSub, nNumFmt ); + if( bHasNumValue ) + ((SwDateTimeField *)pFld)->SetValue( dValue ); + } + } + break; + + case RES_PAGENUMBERFLD: + if( pSubOption ) + { + sal_uInt16 nSub; + if( pSubOption->GetEnum( nSub, aHTMLPageNumFldSubTable ) ) + { + sal_uInt16 nFmt = SVX_NUM_PAGEDESC; + if( pFmtOption ) + pFmtOption->GetEnum( nFmt, aHTMLPageNumFldFmtTable ); + + short nOff = 0; + + if( (SvxExtNumType)nFmt!=SVX_NUM_CHAR_SPECIAL && aValue.Len() ) + nOff = (short)aValue.ToInt32(); + else if( (SwPageNumSubType)nSub == PG_NEXT ) + nOff = 1; + else if( (SwPageNumSubType)nSub == PG_PREV ) + nOff = -1; + + if( (SvxExtNumType)nFmt==SVX_NUM_CHAR_SPECIAL && + (SwPageNumSubType)nSub==PG_RANDOM ) + nFmt = SVX_NUM_PAGEDESC; + + pFld = new SwPageNumberField( (SwPageNumberFieldType *)pType, nSub, nFmt, nOff ); + if( (SvxExtNumType)nFmt==SVX_NUM_CHAR_SPECIAL ) + ((SwPageNumberField *)pFld)->SetUserString( aValue ); + } + } + break; + + case RES_DOCINFOFLD: + if( pSubOption ) + { + sal_uInt16 nSub; + if( pSubOption->GetEnum( nSub, aHTMLDocInfoFldSubTable ) ) + { + sal_uInt16 nExtSub = 0; + if( DI_CREATE==(SwDocInfoSubType)nSub || + DI_CHANGE==(SwDocInfoSubType)nSub ) + { + nExtSub = DI_SUB_AUTHOR; + if( pFmtOption ) + pFmtOption->GetEnum( nExtSub, aHTMLDocInfoFldFmtTable ); + nSub |= nExtSub; + } + + sal_uInt32 nNumFmt = 0; + double dValue = 0; + if( bHasNumFmt && (DI_SUB_DATE==nExtSub || DI_SUB_TIME==nExtSub) ) + { + LanguageType eLang; + dValue = GetTableDataOptionsValNum( + nNumFmt, eLang, aNumValue, aNumFmt, + *pDoc->GetNumberFormatter() ); + bFixed &= bHasNumValue; + } + else + bHasNumValue = sal_False; + + if( nSub >= DI_INFO1 && nSub <= DI_INFO4 && aName.Len() == 0 ) + { + // backward compatibility for OOo 2: + // map to names stored in AddMetaUserDefined + aName = m_InfoNames[nSub - DI_INFO1]; + nSub = DI_CUSTOM; + } + + if( bFixed ) + { + nSub |= DI_SUB_FIXED; + bInsOnEndTag = sal_True; + } + + pFld = new SwDocInfoField( (SwDocInfoFieldType *)pType, + nSub, aName, nNumFmt ); + if( bHasNumValue ) + ((SwDocInfoField*)pFld)->SetValue( dValue ); + } + } + break; + + case RES_DOCSTATFLD: + if( pSubOption ) + { + sal_uInt16 nSub; + if( pSubOption->GetEnum( nSub, aHTMLDocStatFldSubTable ) ) + { + sal_uInt16 nFmt = SVX_NUM_ARABIC; + if( pFmtOption ) + pFmtOption->GetEnum( nFmt, aHTMLPageNumFldFmtTable ); + pFld = new SwDocStatField( (SwDocStatFieldType *)pType, + nSub, nFmt ); + bUpdateDocStat |= (DS_PAGE != nFmt); + } + } + break; + + case RES_FILENAMEFLD: + { + sal_uInt16 nFmt = FF_NAME; + if( pFmtOption ) + pFmtOption->GetEnum( nFmt, aHTMLFileNameFldFmtTable ); + if( bFixed ) + { + nFmt |= FF_FIXED; + bInsOnEndTag = sal_True; + } + + pFld = new SwFileNameField( (SwFileNameFieldType *)pType, nFmt ); + } + break; + default: + ; + } + + if( pFld ) + { + if( bInsOnEndTag ) + { + pField = pFld; + } + else + { + pDoc->InsertPoolItem( *pPam, SwFmtFld(*pFld), 0 ); + delete pFld; + } + bInField = sal_True; + } +} + +void SwHTMLParser::EndField() +{ + if( pField ) + { + switch( pField->Which() ) + { + case RES_DOCINFOFLD: + ASSERT( ((SwDocInfoField*)pField)->IsFixed(), + "DokInfo-Feld haette nicht gemerkt werden muessen" ); + ((SwDocInfoField*)pField)->SetExpansion( aContents ); + break; + + case RES_EXTUSERFLD: + ASSERT( ((SwExtUserField*)pField)->IsFixed(), + "ExtUser-Feld haette nicht gemerkt werden muessen" ); + ((SwExtUserField*)pField)->SetExpansion( aContents ); + break; + + case RES_AUTHORFLD: + ASSERT( ((SwAuthorField*)pField)->IsFixed(), + "Author-Feld haette nicht gemerkt werden muessen" ); + ((SwAuthorField*)pField)->SetExpansion( aContents ); + break; + + case RES_FILENAMEFLD: + ASSERT( ((SwFileNameField*)pField)->IsFixed(), + "FileName-Feld haette nicht gemerkt werden muessen" ); + ((SwFileNameField*)pField)->SetExpansion( aContents ); + break; + } + + pDoc->InsertPoolItem( *pPam, SwFmtFld(*pField), 0 ); + delete pField; + pField = 0; + } + + bInField = sal_False; + aContents.Erase(); +} + +void SwHTMLParser::InsertFieldText() +{ + if( pField ) + { + // das aktuelle Textstueck an den Text anhaengen + aContents += aToken; + } +} + +void SwHTMLParser::InsertCommentText( const sal_Char *pTag ) +{ + sal_Bool bEmpty = aContents.Len() == 0; + if( !bEmpty ) + aContents += '\n'; + + aContents += aToken; + if( bEmpty && pTag ) + { + String aTmp( aContents ); + aContents.AssignAscii( "HTML: <" ); + aContents.AppendAscii( pTag ); + aContents.Append( '>' ); + aContents.Append( aTmp ); + } +} + +void SwHTMLParser::InsertComment( const String& rComment, const sal_Char *pTag ) +{ + String aComment( rComment ); + if( pTag ) + { + aComment.AppendAscii( "</" ); + aComment.AppendAscii( pTag ); + aComment.Append( '>' ); + } + + // MIB 24.06.97: Wenn ein PostIt nach einen Space eingefuegt + // werden soll, fuegen wir es vor dem Space ein. Dann gibt es + // weniger Probleme beim Formatieren (bug #40483#) + xub_StrLen nPos = pPam->GetPoint()->nContent.GetIndex(); + SwTxtNode *pTxtNd = pPam->GetNode()->GetTxtNode(); + sal_Bool bMoveFwd = sal_False; + if( nPos>0 && pTxtNd && ' '==pTxtNd->GetTxt().GetChar(nPos-1) ) + { + bMoveFwd = sal_True; + + sal_uLong nNodeIdx = pPam->GetPoint()->nNode.GetIndex(); + xub_StrLen nIdx = pPam->GetPoint()->nContent.GetIndex(); + for( sal_uInt16 i = aSetAttrTab.Count(); i > 0; ) + { + _HTMLAttr *pAttr = aSetAttrTab[--i]; + if( pAttr->GetSttParaIdx() != nNodeIdx || + pAttr->GetSttCnt() != nIdx ) + break; + + if( RES_TXTATR_FIELD == pAttr->pItem->Which() && + RES_SCRIPTFLD == ((const SwFmtFld *)pAttr->pItem)->GetFld() + ->GetTyp()->Which() ) + { + bMoveFwd = sal_False; + break; + } + } + + if( bMoveFwd ) + pPam->Move( fnMoveBackward ); + } + + SwPostItField aPostItFld( + (SwPostItFieldType*)pDoc->GetSysFldType( RES_POSTITFLD ), + aEmptyStr, aComment, DateTime() ); + InsertAttr( SwFmtFld( aPostItFld ) ); + + if( bMoveFwd ) + pPam->Move( fnMoveForward ); +} + diff --git a/sw/source/filter/html/htmlfld.hxx b/sw/source/filter/html/htmlfld.hxx new file mode 100644 index 000000000000..2ba89a9af6de --- /dev/null +++ b/sw/source/filter/html/htmlfld.hxx @@ -0,0 +1,92 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _HTMLFLD_HXX +#define _HTMLFLD_HXX + +#include "sal/config.h" + +#define OOO_STRING_SW_HTML_FT_author "AUTHOR" +#define OOO_STRING_SW_HTML_FT_sender "SENDER" +#define OOO_STRING_SW_HTML_FT_datetime "DATETIME" +#define OOO_STRING_SW_HTML_FT_page "PAGE" +#define OOO_STRING_SW_HTML_FT_docinfo "DOCINFO" +#define OOO_STRING_SW_HTML_FT_docstat "DOCSTAT" +#define OOO_STRING_SW_HTML_FT_filename "FILENAME" +#define OOO_STRING_SW_HTML_FS_company "COMPANY" +#define OOO_STRING_SW_HTML_FS_firstname "FIRSTNAME" +#define OOO_STRING_SW_HTML_FS_name "NAME" +#define OOO_STRING_SW_HTML_FS_shortcut "SHORTCUT" +#define OOO_STRING_SW_HTML_FS_street "STREET" +#define OOO_STRING_SW_HTML_FS_country "COUNTRY" +#define OOO_STRING_SW_HTML_FS_zip "ZIP" +#define OOO_STRING_SW_HTML_FS_city "CITY" +#define OOO_STRING_SW_HTML_FS_title "TITLE" +#define OOO_STRING_SW_HTML_FS_position "POSITION" +#define OOO_STRING_SW_HTML_FS_pphone "PPHONE" +#define OOO_STRING_SW_HTML_FS_cphone "CPHONE" +#define OOO_STRING_SW_HTML_FS_fax "FAX" +#define OOO_STRING_SW_HTML_FS_email "EMAIL" +#define OOO_STRING_SW_HTML_FS_state "STATE" +#define OOO_STRING_SW_HTML_FS_random "RANDOM" +#define OOO_STRING_SW_HTML_FS_next "NEXT" +#define OOO_STRING_SW_HTML_FS_prev "PREV" +#define OOO_STRING_SW_HTML_FS_theme "THEME" +#define OOO_STRING_SW_HTML_FS_keys "KEYS" +#define OOO_STRING_SW_HTML_FS_comment "COMMENT" +#define OOO_STRING_SW_HTML_FS_custom "CUSTOM" +#define OOO_STRING_SW_HTML_FS_create "CREATE" +#define OOO_STRING_SW_HTML_FS_change "CHANGE" +#define OOO_STRING_SW_HTML_FS_page "PAGE" +#define OOO_STRING_SW_HTML_FS_para "PARAGRAPH" +#define OOO_STRING_SW_HTML_FS_word "WORD" +#define OOO_STRING_SW_HTML_FS_char "CHAR" +#define OOO_STRING_SW_HTML_FS_tbl "TABLE" +#define OOO_STRING_SW_HTML_FS_grf "GRAPHIC" +#define OOO_STRING_SW_HTML_FS_ole "OLE" +#define OOO_STRING_SW_HTML_FF_name "NAME" +#define OOO_STRING_SW_HTML_FF_shortcut "SHORTCUT" +#define OOO_STRING_SW_HTML_FF_uletter "ULETTER" +#define OOO_STRING_SW_HTML_FF_lletter "LLETTER" +#define OOO_STRING_SW_HTML_FF_uroman "UROMAN" +#define OOO_STRING_SW_HTML_FF_lroman "LROMAN" +#define OOO_STRING_SW_HTML_FF_arabic "ARABIC" +#define OOO_STRING_SW_HTML_FF_none "NONE" +#define OOO_STRING_SW_HTML_FF_char "CHAR" +#define OOO_STRING_SW_HTML_FF_page "PAGE" +#define OOO_STRING_SW_HTML_FF_ulettern "ULETTERN" +#define OOO_STRING_SW_HTML_FF_llettern "LLETTERN" +#define OOO_STRING_SW_HTML_FF_author "AUTHOR" +#define OOO_STRING_SW_HTML_FF_time "TIME" +#define OOO_STRING_SW_HTML_FF_date "DATE" +#define OOO_STRING_SW_HTML_FF_pathname "PATHNAME" +#define OOO_STRING_SW_HTML_FF_path "PATH" +#define OOO_STRING_SW_HTML_FF_name_noext "NAME-NOEXT" + +#endif + + diff --git a/sw/source/filter/html/htmlfldw.cxx b/sw/source/filter/html/htmlfldw.cxx new file mode 100644 index 000000000000..177d39dc5d4b --- /dev/null +++ b/sw/source/filter/html/htmlfldw.cxx @@ -0,0 +1,539 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <com/sun/star/i18n/ScriptType.hpp> +#include <tools/string.hxx> +#include <svtools/htmlkywd.hxx> +#include <svtools/htmlout.hxx> +#include <svtools/htmltokn.h> +#include <fmtfld.hxx> +#include <doc.hxx> +#include <breakit.hxx> +#include <ndtxt.hxx> +#include <txtfld.hxx> +#include "fldbas.hxx" +#include "docufld.hxx" +#include "flddat.hxx" +#include "htmlfld.hxx" +#include "wrthtml.hxx" + +using namespace nsSwDocInfoSubType; + +const sal_Char *SwHTMLWriter::GetNumFormat( sal_uInt16 nFmt ) +{ + const sal_Char *pFmtStr = 0; + + switch( (SvxExtNumType)nFmt ) + { + case SVX_NUM_CHARS_UPPER_LETTER: pFmtStr = OOO_STRING_SW_HTML_FF_uletter; break; + case SVX_NUM_CHARS_LOWER_LETTER: pFmtStr = OOO_STRING_SW_HTML_FF_lletter; break; + case SVX_NUM_ROMAN_UPPER: pFmtStr = OOO_STRING_SW_HTML_FF_uroman; break; + case SVX_NUM_ROMAN_LOWER: pFmtStr = OOO_STRING_SW_HTML_FF_lroman; break; + case SVX_NUM_ARABIC: pFmtStr = OOO_STRING_SW_HTML_FF_arabic; break; + case SVX_NUM_NUMBER_NONE: pFmtStr = OOO_STRING_SW_HTML_FF_none; break; + case SVX_NUM_CHAR_SPECIAL: pFmtStr = OOO_STRING_SW_HTML_FF_char; break; + case SVX_NUM_PAGEDESC: pFmtStr = OOO_STRING_SW_HTML_FF_page; break; + case SVX_NUM_CHARS_UPPER_LETTER_N: pFmtStr = OOO_STRING_SW_HTML_FF_ulettern; break; + case SVX_NUM_CHARS_LOWER_LETTER_N: pFmtStr = OOO_STRING_SW_HTML_FF_llettern; break; + default: + ; + } + + return pFmtStr; +} + +extern sal_Bool lcl_css1atr_equalFontItems( const SfxPoolItem& r1, const SfxPoolItem& r2 ); +static Writer& OutHTML_SwField( Writer& rWrt, const SwField* pFld, + const SwTxtNode& rTxtNd, xub_StrLen nFldPos ) +{ + SwHTMLWriter & rHTMLWrt = (SwHTMLWriter&)rWrt; + + const SwFieldType* pFldTyp = pFld->GetTyp(); + sal_uInt16 nField = pFldTyp->Which(); + sal_uLong nFmt = pFld->GetFormat(); + + const sal_Char *pTypeStr=0, // TYPE + *pSubStr=0, // SUBTYPE + *pFmtStr=0; // FORMAT (SW) + String aValue; // VALUE (SW) + sal_Bool bNumFmt=sal_False; // SDNUM (Number-Formatter-Format) + sal_Bool bNumValue=sal_False; // SDVAL (Number-Formatter-Value) + double dNumValue = 0.0; // SDVAL (Number-Formatter-Value) + sal_Bool bFixed=sal_False; // SDFIXED + String aName; // NAME (CUSTOM) + + switch( nField ) + { + case RES_EXTUSERFLD: + pTypeStr = OOO_STRING_SW_HTML_FT_sender; + switch( (SwExtUserSubType)pFld->GetSubType() ) + { + case EU_COMPANY: pSubStr = OOO_STRING_SW_HTML_FS_company; break; + case EU_FIRSTNAME: pSubStr = OOO_STRING_SW_HTML_FS_firstname; break; + case EU_NAME: pSubStr = OOO_STRING_SW_HTML_FS_name; break; + case EU_SHORTCUT: pSubStr = OOO_STRING_SW_HTML_FS_shortcut; break; + case EU_STREET: pSubStr = OOO_STRING_SW_HTML_FS_street; break; + case EU_COUNTRY: pSubStr = OOO_STRING_SW_HTML_FS_country; break; + case EU_ZIP: pSubStr = OOO_STRING_SW_HTML_FS_zip; break; + case EU_CITY: pSubStr = OOO_STRING_SW_HTML_FS_city; break; + case EU_TITLE: pSubStr = OOO_STRING_SW_HTML_FS_title; break; + case EU_POSITION: pSubStr = OOO_STRING_SW_HTML_FS_position; break; + case EU_PHONE_PRIVATE: pSubStr = OOO_STRING_SW_HTML_FS_pphone; break; + case EU_PHONE_COMPANY: pSubStr = OOO_STRING_SW_HTML_FS_cphone; break; + case EU_FAX: pSubStr = OOO_STRING_SW_HTML_FS_fax; break; + case EU_EMAIL: pSubStr = OOO_STRING_SW_HTML_FS_email; break; + case EU_STATE: pSubStr = OOO_STRING_SW_HTML_FS_state; break; + default: + ; + } + ASSERT( pSubStr, "ubekannter Subtyp fuer SwExtUserField" ); + bFixed = ((const SwExtUserField*)pFld)->IsFixed(); + break; + + case RES_AUTHORFLD: + pTypeStr = OOO_STRING_SW_HTML_FT_author; + switch( (SwAuthorFormat)nFmt & 0xff) + { + case AF_NAME: pFmtStr = OOO_STRING_SW_HTML_FF_name; break; + case AF_SHORTCUT: pFmtStr = OOO_STRING_SW_HTML_FF_shortcut; break; + } + ASSERT( pFmtStr, "ubekanntes Format fuer SwAuthorField" ); + bFixed = ((const SwAuthorField*)pFld)->IsFixed(); + break; + + case RES_DATETIMEFLD: + pTypeStr = OOO_STRING_SW_HTML_FT_datetime; + bNumFmt = sal_True; + if( ((SwDateTimeField*)pFld)->IsFixed() ) + { + bNumValue = sal_True; + dNumValue = ((SwDateTimeField*)pFld)->GetValue(); + } + break; + + case RES_PAGENUMBERFLD: + { + pTypeStr = OOO_STRING_SW_HTML_FT_page; + SwPageNumSubType eSubType = (SwPageNumSubType)pFld->GetSubType(); + switch( eSubType ) + { + case PG_RANDOM: pSubStr = OOO_STRING_SW_HTML_FS_random; break; + case PG_NEXT: pSubStr = OOO_STRING_SW_HTML_FS_next; break; + case PG_PREV: pSubStr = OOO_STRING_SW_HTML_FS_prev; break; + } + ASSERT( pSubStr, "ubekannter Subtyp fuer SwPageNumberField" ); + pFmtStr = SwHTMLWriter::GetNumFormat( static_cast< sal_uInt16 >(nFmt) ); + + if( (SvxExtNumType)nFmt==SVX_NUM_CHAR_SPECIAL ) + { + aValue = ((const SwPageNumberField *)pFld)->GetUserString(); + } + else + { + const String& rValue = pFld->GetPar2(); + short nValue = (short)rValue.ToInt32(); + if( (eSubType == PG_NEXT && nValue!=1) || + (eSubType == PG_PREV && nValue!=-1) || + (eSubType == PG_RANDOM && nValue!=0) ) + { + aValue = rValue; + } + } + } + break; + case RES_DOCINFOFLD: + { + sal_uInt16 nSubType = pFld->GetSubType(); + pTypeStr = OOO_STRING_SW_HTML_FT_docinfo; + sal_uInt16 nExtSubType = nSubType & 0x0f00; + nSubType &= 0x00ff; + + switch( nSubType ) + { + case DI_TITEL: pSubStr = OOO_STRING_SW_HTML_FS_title; break; + case DI_THEMA: pSubStr = OOO_STRING_SW_HTML_FS_theme; break; + case DI_KEYS: pSubStr = OOO_STRING_SW_HTML_FS_keys; break; + case DI_COMMENT: pSubStr = OOO_STRING_SW_HTML_FS_comment; break; + case DI_CREATE: pSubStr = OOO_STRING_SW_HTML_FS_create; break; + case DI_CHANGE: pSubStr = OOO_STRING_SW_HTML_FS_change; break; + case DI_CUSTOM: pSubStr = OOO_STRING_SW_HTML_FS_custom; break; + default: pTypeStr = 0; break; + } + + if( DI_CUSTOM == nSubType ) { + aName = static_cast<const SwDocInfoField*>(pFld)->GetName(); + } + + if( DI_CREATE == nSubType || DI_CHANGE == nSubType ) + { + switch( nExtSubType ) + { + case DI_SUB_AUTHOR: + pFmtStr = OOO_STRING_SW_HTML_FF_author; + break; + case DI_SUB_TIME: + pFmtStr = OOO_STRING_SW_HTML_FF_time; + bNumFmt = sal_True; + break; + case DI_SUB_DATE: + pFmtStr = OOO_STRING_SW_HTML_FF_date; + bNumFmt = sal_True; + break; + } + } + bFixed = ((const SwDocInfoField*)pFld)->IsFixed(); + if( bNumFmt ) + { + if( bFixed ) + { + // Fuer ein fixes Feld och den Num-Value ausgeben. + // Fixe Felder ohne Zahlenformate sollte es + // eigentlich nicht geben. ASSERT ist unten. + dNumValue = ((const SwDocInfoField*)pFld)->GetValue(); + bNumValue = sal_True; + } + else if( !nFmt ) + { + // Nicht fixe Felder muessen kein Zahlenformat haben, + // wenn sie aus 4.0-Dokumenten stammen. + bNumFmt = sal_False; + } + } + } + break; + + case RES_DOCSTATFLD: + { + pTypeStr = OOO_STRING_SW_HTML_FT_docstat; + sal_uInt16 nSubType = pFld->GetSubType(); + switch( nSubType ) + { + case DS_PAGE: pSubStr = OOO_STRING_SW_HTML_FS_page; break; + case DS_PARA: pSubStr = OOO_STRING_SW_HTML_FS_para; break; + case DS_WORD: pSubStr = OOO_STRING_SW_HTML_FS_word; break; + case DS_CHAR: pSubStr = OOO_STRING_SW_HTML_FS_char; break; + case DS_TBL: pSubStr = OOO_STRING_SW_HTML_FS_tbl; break; + case DS_GRF: pSubStr = OOO_STRING_SW_HTML_FS_grf; break; + case DS_OLE: pSubStr = OOO_STRING_SW_HTML_FS_ole; break; + default: pTypeStr = 0; break; + } + pFmtStr = SwHTMLWriter::GetNumFormat( static_cast< sal_uInt16 >(nFmt) ); + } + break; + + case RES_FILENAMEFLD: + pTypeStr = OOO_STRING_SW_HTML_FT_filename; + switch( (SwFileNameFormat)(nFmt & ~FF_FIXED) ) + { + case FF_NAME: pFmtStr = OOO_STRING_SW_HTML_FF_name; break; + case FF_PATHNAME: pFmtStr = OOO_STRING_SW_HTML_FF_pathname; break; + case FF_PATH: pFmtStr = OOO_STRING_SW_HTML_FF_path; break; + case FF_NAME_NOEXT: pFmtStr = OOO_STRING_SW_HTML_FF_name_noext; break; + default: + ; + } + bFixed = ((const SwFileNameField*)pFld)->IsFixed(); + ASSERT( pFmtStr, "unbekanntes Format fuer SwFileNameField" ); + break; + } + + // <SDFIELD>-Tag ausgeben + if( pTypeStr ) + { + ByteString sOut( '<' ); + ((((sOut += OOO_STRING_SVTOOLS_HTML_sdfield) += ' ') += OOO_STRING_SVTOOLS_HTML_O_type) += '=') + += pTypeStr; + if( pSubStr ) + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_subtype) += '=') += pSubStr; + if( pFmtStr ) + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_format) += '=') += pFmtStr; + if( aName.Len() ) + { + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_name) += "=\""); + rWrt.Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( rWrt.Strm(), aName, rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + sOut = '\"'; + } + if( aValue.Len() ) + { + ((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_value) += "=\""; + rWrt.Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( rWrt.Strm(), aValue, rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + sOut = '\"'; + } + if( bNumFmt ) + { + ASSERT( nFmt, "Zahlenformat ist 0" ); + sOut = HTMLOutFuncs::CreateTableDataOptionsValNum( sOut, + bNumValue, dNumValue, nFmt, + *rHTMLWrt.pDoc->GetNumberFormatter(), + rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + + } + if( bFixed ) + (sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_sdfixed; + sOut += '>'; + rWrt.Strm() << sOut.GetBuffer(); + } + + // Inhalt des Feldes ausgeben + String const sExpand( pFld->ExpandField(true) ); + sal_Bool bNeedsCJKProcessing = sal_False; + if( sExpand.Len() ) + { + sal_uInt16 nScriptType = pBreakIt->GetBreakIter()->getScriptType( sExpand, 0 ); + xub_StrLen nPos = (xub_StrLen)pBreakIt->GetBreakIter()->endOfScript( sExpand, 0, + nScriptType ); + + sal_uInt16 nScript = + SwHTMLWriter::GetCSS1ScriptForScriptType( nScriptType ); + if( nPos < sExpand.Len() || nScript != rHTMLWrt.nCSS1Script ) + { + bNeedsCJKProcessing = sal_True; + } + } + + if( bNeedsCJKProcessing ) + { + SfxItemSet aScriptItemSet( rWrt.pDoc->GetAttrPool(), + RES_CHRATR_FONT, RES_CHRATR_FONTSIZE, + RES_CHRATR_POSTURE, RES_CHRATR_POSTURE, + RES_CHRATR_WEIGHT, RES_CHRATR_WEIGHT, + RES_CHRATR_CJK_FONT, RES_CHRATR_CTL_WEIGHT, + 0 ); + rTxtNd.GetAttr( aScriptItemSet, nFldPos, nFldPos+1 ); + + sal_uInt16 aWesternWhichIds[4] = + { RES_CHRATR_FONT, RES_CHRATR_FONTSIZE, + RES_CHRATR_POSTURE, RES_CHRATR_WEIGHT }; + sal_uInt16 aCJKWhichIds[4] = + { RES_CHRATR_CJK_FONT, RES_CHRATR_CJK_FONTSIZE, + RES_CHRATR_CJK_POSTURE, RES_CHRATR_CJK_WEIGHT }; + sal_uInt16 aCTLWhichIds[4] = + { RES_CHRATR_CTL_FONT, RES_CHRATR_CTL_FONTSIZE, + RES_CHRATR_CTL_POSTURE, RES_CHRATR_CTL_WEIGHT }; + + sal_uInt16 *pRefWhichIds = 0; + switch( rHTMLWrt.nCSS1Script ) + { + case CSS1_OUTMODE_WESTERN: + pRefWhichIds = aWesternWhichIds; + break; + case CSS1_OUTMODE_CJK: + pRefWhichIds = aCJKWhichIds; + break; + case CSS1_OUTMODE_CTL: + pRefWhichIds = aCTLWhichIds; + break; + } + + xub_StrLen nPos = 0; + do + { + sal_uInt16 nScriptType = pBreakIt->GetBreakIter()->getScriptType( sExpand, nPos ); + sal_uInt16 nScript = + SwHTMLWriter::GetCSS1ScriptForScriptType( nScriptType ); + xub_StrLen nEndPos = (xub_StrLen)pBreakIt->GetBreakIter()->endOfScript( + sExpand, nPos, nScriptType ); + if( nScript != CSS1_OUTMODE_ANY_SCRIPT && + /* #108791# */ nScript != rHTMLWrt.nCSS1Script ) + { + sal_uInt16 *pWhichIds = 0; + switch( nScript ) + { + case CSS1_OUTMODE_WESTERN: pWhichIds = aWesternWhichIds; break; + case CSS1_OUTMODE_CJK: pWhichIds = aCJKWhichIds; break; + case CSS1_OUTMODE_CTL: pWhichIds = aCTLWhichIds; break; + } + + rHTMLWrt.bTagOn = sal_True; + const SfxPoolItem *aItems[5]; + sal_uInt16 nItems = 0; + for( sal_uInt16 i=0; i<4; i++ ) + { + const SfxPoolItem *pRefItem = + aScriptItemSet.GetItem( pRefWhichIds[i] ); + const SfxPoolItem *pItem = + aScriptItemSet.GetItem( pWhichIds[i] ); + if( pRefItem && pItem && + !(0==i ? lcl_css1atr_equalFontItems( *pRefItem, *pItem ) + : *pRefItem == *pItem) ) + { + Out( aHTMLAttrFnTab, *pItem, rHTMLWrt ); + aItems[nItems++] = pItem; + } + } + + HTMLOutFuncs::Out_String( rWrt.Strm(), sExpand.Copy( nPos, nEndPos ), + rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + + rHTMLWrt.bTagOn = sal_False; + while( nItems ) + Out( aHTMLAttrFnTab, *aItems[--nItems], rHTMLWrt ); + + } + else + { + HTMLOutFuncs::Out_String( rWrt.Strm(), sExpand.Copy( nPos, nEndPos ), + rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + } + nPos = nEndPos; + } + while( nPos < sExpand.Len() ); + } + else + { + HTMLOutFuncs::Out_String( rWrt.Strm(), sExpand, + rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + } + + // Off-Tag ausgeben + if( pTypeStr ) + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_sdfield, sal_False ); + + return rWrt; +} + + +Writer& OutHTML_SwFmtFld( Writer& rWrt, const SfxPoolItem& rHt ) +{ + SwFmtFld & rFld = (SwFmtFld&)rHt; + const SwField* pFld = rFld.GetFld(); + const SwFieldType* pFldTyp = pFld->GetTyp(); + + if( RES_SETEXPFLD == pFldTyp->Which() && + (nsSwGetSetExpType::GSE_STRING & pFld->GetSubType()) ) + { + int bOn = sal_False; + if( pFldTyp->GetName().EqualsAscii("HTML_ON" ) ) + bOn = sal_True; + else if( !pFldTyp->GetName().EqualsAscii( "HTML_OFF" ) ) + return rWrt; + + String rTxt( pFld->GetPar2() ); + rTxt.EraseLeadingChars().EraseTrailingChars(); + rWrt.Strm() << '<'; + if( !bOn ) + rWrt.Strm() << '/'; + // TODO: HTML-Tags are written without entitities, that for, characters + // not contained in the destination encoding are lost! + ByteString sTmp( rTxt, ((SwHTMLWriter&)rWrt).eDestEnc ); + rWrt.Strm() << sTmp.GetBuffer() << '>'; + } + else if( RES_POSTITFLD == pFldTyp->Which() ) + { + // Kommentare werden im ANSI-Zeichensetz, aber mit System-Zeilen- + // Umbruechen gesschrieben. + const String& rComment = pFld->GetPar2(); + sal_Bool bWritten = sal_False; + + if( (rComment.Len() >= 6 && '<' == rComment.GetChar(0) && + '>' == rComment.GetChar(rComment.Len()-1) && + rComment.Copy( 1, 4 ).EqualsIgnoreCaseAscii(OOO_STRING_SVTOOLS_HTML_meta)) || + (rComment.Len() >= 7 && + rComment.Copy( 0, 4 ).EqualsAscii( "<!--" ) && + rComment.Copy( rComment.Len()-3, 3 ).EqualsAscii( "-->" )) ) + { + // META-Tags direkt ausgeben + String sComment( rComment ); + sComment.ConvertLineEnd( GetSystemLineEnd() ); + // TODO: HTML-Tags are written without entitities, that for, + // characters not contained in the destination encoding are lost! + ByteString sTmp( sComment, ((SwHTMLWriter&)rWrt).eDestEnc ); + rWrt.Strm() << sTmp.GetBuffer(); + bWritten = sal_True; + } + else if( rComment.Len() >= 7 && + '>' == rComment.GetChar(rComment.Len()-1) && + rComment.Copy(0,5).EqualsIgnoreCaseAscii("HTML:") ) + { + String sComment( rComment.Copy(5) ); + sComment.EraseLeadingChars(); + if( '<' == sComment.GetChar(0) ) + { + sComment.ConvertLineEnd( GetSystemLineEnd() ); + // TODO: HTML-Tags are written without entitities, that for, + // characters not contained in the destination encoding are + // lost! + ByteString sTmp( sComment, ((SwHTMLWriter&)rWrt).eDestEnc ); + rWrt.Strm() << sTmp.GetBuffer(); + bWritten = sal_True; + } + + } + + if( !bWritten ) + { + ByteString sOut( '<' ); + + String sComment( rComment ); + sComment.ConvertLineEnd( GetSystemLineEnd() ); + // TODO: ??? + (((sOut += OOO_STRING_SVTOOLS_HTML_comment) += ' ') + += ByteString( sComment, ((SwHTMLWriter&)rWrt).eDestEnc )) + += " -->"; + rWrt.Strm() << sOut.GetBuffer(); + } + } + else if( RES_SCRIPTFLD == pFldTyp->Which() ) + { + SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt; + if( rHTMLWrt.bLFPossible ) + rHTMLWrt.OutNewLine( sal_True ); + + sal_Bool bURL = ((const SwScriptField *)pFld)->IsCodeURL(); + const String& rType = pFld->GetPar1(); + String aContents, aURL; + if(bURL) + aURL = pFld->GetPar2(); + else + aContents = pFld->GetPar2(); + + // sonst ist es der Script-Inhalt selbst. Da nur noh JavaScript + // in Feldern landet, muss es sich um JavaSrript handeln ...:) + HTMLOutFuncs::OutScript( rWrt.Strm(), rWrt.GetBaseURL(), aContents, rType, JAVASCRIPT, + aURL, 0, 0, rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + + if( rHTMLWrt.bLFPossible ) + rHTMLWrt.OutNewLine( sal_True ); + } + else + { + const SwTxtFld *pTxtFld = rFld.GetTxtFld(); + ASSERT( pTxtFld, "Where is the txt fld?" ); + if( pTxtFld ) + OutHTML_SwField( rWrt, pFld, pTxtFld->GetTxtNode(), + *pTxtFld->GetStart() ); + } + return rWrt; +} + + diff --git a/sw/source/filter/html/htmlfly.cxx b/sw/source/filter/html/htmlfly.cxx new file mode 100644 index 000000000000..9fcf12461db4 --- /dev/null +++ b/sw/source/filter/html/htmlfly.cxx @@ -0,0 +1,1929 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <com/sun/star/text/HoriOrientation.hpp> +#include <com/sun/star/text/VertOrientation.hpp> +#include <com/sun/star/text/RelOrientation.hpp> +#include <svx/svxids.hrc> +#include "hintids.hxx" +#include <tools/string.hxx> +#include <svl/urihelper.hxx> +#include <vcl/svapp.hxx> +#include <vcl/wrkwin.hxx> +#include <svtools/htmlkywd.hxx> +#include <svtools/htmlout.hxx> +#include <svtools/imap.hxx> +#include <svtools/imapobj.hxx> +#include <svtools/htmlcfg.hxx> +#include <svx/xoutbmp.hxx> +#include <editeng/boxitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/brshitem.hxx> + + +#include <fmtanchr.hxx> +#include <fmtornt.hxx> +#include <fmturl.hxx> +#include <fmtfsize.hxx> +#include <fmtclds.hxx> +#include <fmtcntnt.hxx> +#include <fmtsrnd.hxx> +#include <fmtinfmt.hxx> +#include <txtinet.hxx> +#include "frmatr.hxx" +#include <grfatr.hxx> +#include <flypos.hxx> +#include <docary.hxx> +#include <ndgrf.hxx> + +#include "doc.hxx" +#include "ndtxt.hxx" +#include "pam.hxx" +#include "swerror.h" +#include "frmfmt.hxx" +#include "wrthtml.hxx" +#include "css1kywd.hxx" +#include "htmlfly.hxx" + +using namespace ::com::sun::star; + +//////////////////////////////////////////////////////////// + +const sal_uLong HTML_FRMOPTS_IMG_ALL = + HTML_FRMOPT_ALT | + HTML_FRMOPT_SIZE | + HTML_FRMOPT_ANYSIZE | + HTML_FRMOPT_BORDER | + HTML_FRMOPT_NAME; +const sal_uLong HTML_FRMOPTS_IMG_CNTNR = + HTML_FRMOPTS_IMG_ALL | + HTML_FRMOPT_ABSSIZE; +const sal_uLong HTML_FRMOPTS_IMG = + HTML_FRMOPTS_IMG_ALL | + HTML_FRMOPT_ALIGN | + HTML_FRMOPT_SPACE | + HTML_FRMOPT_BRCLEAR; +const sal_uLong HTML_FRMOPTS_IMG_CSS1 = + HTML_FRMOPT_S_ALIGN | + HTML_FRMOPT_S_SPACE; + +const sal_uLong HTML_FRMOPTS_DIV = + HTML_FRMOPT_ID | + HTML_FRMOPT_S_ALIGN | + HTML_FRMOPT_S_SIZE | + HTML_FRMOPT_ANYSIZE | + HTML_FRMOPT_ABSSIZE | + HTML_FRMOPT_S_SPACE | + HTML_FRMOPT_S_BORDER | + HTML_FRMOPT_S_BACKGROUND | + HTML_FRMOPT_BRCLEAR | + HTML_FRMOPT_DIR; + +const sal_uLong HTML_FRMOPTS_MULTICOL = + HTML_FRMOPT_ID | + HTML_FRMOPT_WIDTH | + HTML_FRMOPT_ANYSIZE | + HTML_FRMOPT_ABSSIZE | + HTML_FRMOPT_DIR; +const sal_uLong HTML_FRMOPTS_MULTICOL_CNTNR = + HTML_FRMOPTS_MULTICOL; +const sal_uLong HTML_FRMOPTS_MULTICOL_CSS1 = + HTML_FRMOPT_S_ALIGN | + HTML_FRMOPT_S_SIZE | + HTML_FRMOPT_S_SPACE | + HTML_FRMOPT_S_BORDER| + HTML_FRMOPT_S_BACKGROUND; + +const sal_uLong HTML_FRMOPTS_SPACER = + HTML_FRMOPT_ALIGN | + HTML_FRMOPT_SIZE | + HTML_FRMOPT_ANYSIZE | + HTML_FRMOPT_BRCLEAR | + HTML_FRMOPT_MARGINSIZE | + HTML_FRMOPT_ABSSIZE; + +const sal_uLong HTML_FRMOPTS_CNTNR = + HTML_FRMOPT_S_ALIGN | + HTML_FRMOPT_S_SPACE | + HTML_FRMOPT_S_WIDTH | + HTML_FRMOPT_ANYSIZE | + HTML_FRMOPT_ABSSIZE | + HTML_FRMOPT_S_PIXSIZE; + + +static Writer& OutHTML_FrmFmtTableNode( Writer& rWrt, const SwFrmFmt& rFrmFmt ); +static Writer& OutHTML_FrmFmtAsMulticol( Writer& rWrt, const SwFrmFmt& rFmt, + sal_Bool bInCntnr ); +static Writer& OutHTML_FrmFmtAsSpacer( Writer& rWrt, const SwFrmFmt& rFmt ); +static Writer& OutHTML_FrmFmtAsDivOrSpan( Writer& rWrt, + const SwFrmFmt& rFrmFmt, sal_Bool bSpan ); +static Writer& OutHTML_FrmFmtAsImage( Writer& rWrt, const SwFrmFmt& rFmt, + sal_Bool bInCntnr ); + +static Writer& OutHTML_FrmFmtGrfNode( Writer& rWrt, const SwFrmFmt& rFmt, + sal_Bool bInCntnr ); + +static Writer& OutHTML_FrmFmtAsMarquee( Writer& rWrt, const SwFrmFmt& rFrmFmt, + const SdrObject& rSdrObj ); +//----------------------------------------------------------------------- + +extern HTMLOutEvent __FAR_DATA aAnchorEventTable[]; + +static HTMLOutEvent __FAR_DATA aImageEventTable[] = +{ + { OOO_STRING_SVTOOLS_HTML_O_SDonload, OOO_STRING_SVTOOLS_HTML_O_onload, SVX_EVENT_IMAGE_LOAD }, + { OOO_STRING_SVTOOLS_HTML_O_SDonabort, OOO_STRING_SVTOOLS_HTML_O_onabort, SVX_EVENT_IMAGE_ABORT }, + { OOO_STRING_SVTOOLS_HTML_O_SDonerror, OOO_STRING_SVTOOLS_HTML_O_onerror, SVX_EVENT_IMAGE_ERROR }, + { 0, 0, 0 } +}; + +static HTMLOutEvent __FAR_DATA aIMapEventTable[] = +{ + { 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 } +}; + + + +SV_IMPL_OP_PTRARR_SORT( SwHTMLPosFlyFrms, SwHTMLPosFlyFrmPtr ) + +sal_uInt16 SwHTMLWriter::GuessFrmType( const SwFrmFmt& rFrmFmt, + const SdrObject*& rpSdrObj ) +{ + SwHTMLFrmType eType; + + if( RES_DRAWFRMFMT == rFrmFmt.Which() ) + { + // Als Default irgendein Zeichen-Objekt + eType = HTML_FRMTYPE_DRAW; + + const SdrObject *pObj = + SwHTMLWriter::GetMarqueeTextObj( (const SwDrawFrmFmt &)rFrmFmt ); + if( pObj ) + { + // Laufschrift + rpSdrObj = pObj; + eType = HTML_FRMTYPE_MARQUEE; + } + else + { + pObj = GetHTMLControl( (const SwDrawFrmFmt &)rFrmFmt ); + + if( pObj ) + { + // Form-Control + rpSdrObj = pObj; + eType = HTML_FRMTYPE_CONTROL; + } + } + } + else + { + // Als Default ein Textrahmen + eType = HTML_FRMTYPE_TEXT; + + const SwFmtCntnt& rFlyCntnt = rFrmFmt.GetCntnt(); + sal_uLong nStt = rFlyCntnt.GetCntntIdx()->GetIndex()+1; + const SwNode* pNd = pDoc->GetNodes()[ nStt ]; + + if( pNd->IsGrfNode() ) + { + // Grafik - Node + eType = HTML_FRMTYPE_GRF; + } + else if( pNd->IsOLENode() ) + { + // Applet, Plugin, Floating-Frame + eType = (SwHTMLFrmType)GuessOLENodeFrmType( *pNd ); + } + else + { + sal_uLong nEnd = pDoc->GetNodes()[nStt-1]->EndOfSectionIndex(); + + const SfxPoolItem* pItem; + const SfxItemSet& rItemSet = rFrmFmt.GetAttrSet(); + if( SFX_ITEM_SET == rItemSet.GetItemState( RES_COL, + sal_True, &pItem ) && + ((const SwFmtCol *)pItem)->GetNumCols() > 1 ) + { + // spaltiger Rahmen + eType = HTML_FRMTYPE_MULTICOL; + } + else if( pNd->IsTableNode() ) + { + const SwTableNode *pTblNd = pNd->GetTableNode(); + sal_uLong nTblEnd = pTblNd->EndOfSectionIndex(); + + if( nTblEnd+1 == nEnd ) + { + // Tabelle + eType = HTML_FRMTYPE_TABLE; + } + else if( nTblEnd+2 == nEnd ) + { + // Tabelle mit Unterschrft + eType = HTML_FRMTYPE_TABLE_CAP; + } + } + else if( pNd->IsTxtNode() ) + { + const SwTxtNode *pTxtNd = pNd->GetTxtNode(); + + sal_Bool bEmpty = sal_False; + if( nStt==nEnd-1 && !pTxtNd->Len() ) + { + // leerer Rahmen? Nur wenn kein Rahmen am + // Text- oder Start-Node verankert ist. + bEmpty = sal_True; + if( pHTMLPosFlyFrms ) + { + for( sal_uInt16 i=0; i<pHTMLPosFlyFrms->Count(); i++ ) + { + sal_uLong nIdx = (*pHTMLPosFlyFrms)[i] + ->GetNdIndex().GetIndex(); + bEmpty = (nIdx != nStt) && (nIdx != nStt-1); + if( !bEmpty || nIdx > nStt ) + break; + } + } + } + if( bEmpty ) + { + const SvxBrushItem& rBrush = rFrmFmt.GetBackground(); + /// OD 02.09.2002 #99657# + /// background is not empty, if it has a background graphic + /// or its background color is not "no fill"/"auto fill". + if( GPOS_NONE != rBrush.GetGraphicPos() || + rBrush.GetColor() != COL_TRANSPARENT ) + bEmpty = sal_False; + } + if( bEmpty ) + { + // leerer Rahmen + eType = HTML_FRMTYPE_EMPTY; + } + else if( pDoc->GetNodes()[nStt+1]->IsTableNode() ) + { + const SwTableNode *pTblNd = + pDoc->GetNodes()[nStt+1]->GetTableNode(); + if( pTblNd->EndOfSectionIndex()+1 == nEnd ) + { + // Tabelle mit Ueberschrift + eType = HTML_FRMTYPE_TABLE_CAP; + } + } + } + } + } + + return static_cast< sal_uInt16 >(eType); +} + +void SwHTMLWriter::CollectFlyFrms() +{ + ASSERT( HTML_CFG_MAX+1 == MAX_BROWSERS, + "number of browser configurations has changed" ); + + sal_uInt8 nSz = (sal_uInt8)Min( pDoc->GetSpzFrmFmts()->Count(), sal_uInt16(255) ); + SwPosFlyFrms aFlyPos( nSz, nSz ); + pDoc->GetAllFlyFmts( aFlyPos, bWriteAll ? 0 : pCurPam, sal_True ); + + for( sal_uInt16 i=0; i< aFlyPos.Count(); i++ ) + { + const SwFrmFmt& rFrmFmt = aFlyPos[i]->GetFmt(); + const SdrObject *pSdrObj = 0; + const SwPosition *pAPos; + const SwCntntNode *pACNd; + SwHTMLFrmType eType = (SwHTMLFrmType)GuessFrmType( rFrmFmt, pSdrObj ); + + sal_uInt8 nMode; + const SwFmtAnchor& rAnchor = rFrmFmt.GetAnchor(); + sal_Int16 eHoriRel = rFrmFmt.GetHoriOrient().GetRelationOrient(); + switch( rAnchor.GetAnchorId() ) + { + case FLY_AT_PAGE: + case FLY_AT_FLY: + nMode = aHTMLOutFrmPageFlyTable[eType][nExportMode]; + break; + + case FLY_AT_PARA: + // Absatz-gebundene Rahmen werden nur dann vor den + // Absatz geschrieben, wenn der Absatz einen Abstand + // hat. + if( text::RelOrientation::FRAME == eHoriRel && + (pAPos = rAnchor.GetCntntAnchor()) != 0 && + (pACNd = pAPos->nNode.GetNode().GetCntntNode()) != 0 ) + { + const SvxLRSpaceItem& rLRItem = + (const SvxLRSpaceItem&)pACNd->GetAttr(RES_LR_SPACE); + if( rLRItem.GetTxtLeft() || rLRItem.GetRight() ) + { + nMode = aHTMLOutFrmParaFrameTable[eType][nExportMode]; + break; + } + } + nMode = aHTMLOutFrmParaPrtAreaTable[eType][nExportMode]; + break; + + case FLY_AT_CHAR: + if( text::RelOrientation::FRAME == eHoriRel || text::RelOrientation::PRINT_AREA == eHoriRel ) + nMode = aHTMLOutFrmParaPrtAreaTable[eType][nExportMode]; + else + nMode = aHTMLOutFrmParaOtherTable[eType][nExportMode]; + break; + + default: + nMode = aHTMLOutFrmParaPrtAreaTable[eType][nExportMode]; + break; + } + + if( !pHTMLPosFlyFrms ) + pHTMLPosFlyFrms = new SwHTMLPosFlyFrms; + + SwHTMLPosFlyFrm *pNew = + new SwHTMLPosFlyFrm( *aFlyPos[i], pSdrObj, nMode ); + pHTMLPosFlyFrms->Insert( pNew ); + } +} + +sal_Bool SwHTMLWriter::OutFlyFrm( sal_uLong nNdIdx, xub_StrLen nCntntIdx, sal_uInt8 nPos, + HTMLOutContext *pContext ) +{ + sal_Bool bFlysLeft = sal_False; // Noch Flys an aktueller Node-Position da? + + // OutFlyFrm kan rekursiv aufgerufen werden. Deshalb muss man + // manchmal wieder von vorne anfangen, nachdem ein Fly ausgegeben + // wurde. + sal_Bool bRestart = sal_True; + while( pHTMLPosFlyFrms && bRestart ) + { + bFlysLeft = bRestart = sal_False; + + // suche nach dem Anfang der FlyFrames + sal_uInt16 i; + + for( i = 0; i < pHTMLPosFlyFrms->Count() && + (*pHTMLPosFlyFrms)[i]->GetNdIndex().GetIndex() < nNdIdx; i++ ) + ; + for( ; !bRestart && i < pHTMLPosFlyFrms->Count() && + (*pHTMLPosFlyFrms)[i]->GetNdIndex().GetIndex() == nNdIdx; i++ ) + { + SwHTMLPosFlyFrm *pPosFly = (*pHTMLPosFlyFrms)[i]; + if( ( HTML_POS_ANY == nPos || + pPosFly->GetOutPos() == nPos ) && + pPosFly->GetCntntIndex() == nCntntIdx ) + { + // Erst entfernen ist wichtig, weil in tieferen + // Rekursionen evtl. weitere Eintraege oder das + // ganze Array geloscht werden koennte. + pHTMLPosFlyFrms->Remove( i, 1 ); + i--; + if( !pHTMLPosFlyFrms->Count() ) + { + delete pHTMLPosFlyFrms; + pHTMLPosFlyFrms = 0; + bRestart = sal_True; // nicht wirklich, nur raus + // aus der Schleife + } + + if( pContext ) + { + HTMLOutFuncs::FlushToAscii(Strm(), *pContext ); + pContext = 0; // one time only + } + + OutFrmFmt( pPosFly->GetOutMode(), pPosFly->GetFmt(), + pPosFly->GetSdrObject() ); + switch( pPosFly->GetOutFn() ) + { + case HTML_OUT_DIV: + case HTML_OUT_SPAN: + case HTML_OUT_MULTICOL: + case HTML_OUT_TBLNODE: + bRestart = sal_True; // Hier wird's evtl rekursiv + break; + } + delete pPosFly; + } + else + { + bFlysLeft = sal_True; + } + } + } + + return bFlysLeft; +} + +void SwHTMLWriter::OutFrmFmt( sal_uInt8 nMode, const SwFrmFmt& rFrmFmt, + const SdrObject *pSdrObject ) +{ + sal_uInt8 nCntnrMode = SwHTMLPosFlyFrm::GetOutCntnr( nMode ); + sal_uInt8 nOutMode = SwHTMLPosFlyFrm::GetOutFn(nMode); + const sal_Char *pCntnrStr = 0; + if( HTML_CNTNR_NONE != nCntnrMode ) + { + + if( bLFPossible && HTML_CNTNR_DIV == nCntnrMode ) + OutNewLine(); + + ByteString sOut( '<' ); + pCntnrStr = (HTML_CNTNR_DIV == nCntnrMode) + ? OOO_STRING_SVTOOLS_HTML_division + : OOO_STRING_SVTOOLS_HTML_span; + sOut += pCntnrStr; + ((((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_class) += "=\"") + += sCSS1_class_abs_pos) += '\"'; + Strm() << sOut.GetBuffer(); + + // Fuer Nicht-Zeichenobekte eine Breite ausgeben + sal_uLong nFrmFlags = HTML_FRMOPTS_CNTNR; + + // Fuer spaltige Rahmen koennen wir auch noch den Hintergrund ausgeben. + if( HTML_OUT_MULTICOL == nOutMode ) + nFrmFlags |= HTML_FRMOPT_S_BACKGROUND|HTML_FRMOPT_S_BORDER; + + if( IsHTMLMode( HTMLMODE_BORDER_NONE ) ) + nFrmFlags |= HTML_FRMOPT_S_NOBORDER; + OutCSS1_FrmFmtOptions( rFrmFmt, nFrmFlags, pSdrObject ); + Strm() << '>'; + + if( HTML_CNTNR_DIV == nCntnrMode ) + { + IncIndentLevel(); + bLFPossible = sal_True; + } + } + + switch( nOutMode ) + { + case HTML_OUT_TBLNODE: // OK + ASSERT( !pCntnrStr, "Table: Container ist hier nicht vorgesehen" ); + OutHTML_FrmFmtTableNode( *this, rFrmFmt ); + break; + case HTML_OUT_GRFNODE: // OK + OutHTML_FrmFmtGrfNode( *this, rFrmFmt, pCntnrStr != 0 ); + break; + case HTML_OUT_OLENODE: // OK + OutHTML_FrmFmtOLENode( *this, rFrmFmt, pCntnrStr != 0 ); + break; + case HTML_OUT_OLEGRF: // OK + OutHTML_FrmFmtOLENodeGrf( *this, rFrmFmt, pCntnrStr != 0 ); + break; + case HTML_OUT_DIV: + case HTML_OUT_SPAN: + ASSERT( !pCntnrStr, "Div: Container ist hier nicht vorgesehen" ); + OutHTML_FrmFmtAsDivOrSpan( *this, rFrmFmt, HTML_OUT_SPAN==nOutMode ); + break; + case HTML_OUT_MULTICOL: // OK + OutHTML_FrmFmtAsMulticol( *this, rFrmFmt, pCntnrStr != 0 ); + break; + case HTML_OUT_SPACER: // OK + ASSERT( !pCntnrStr, "Spacer: Container ist hier nicht vorgesehen" ); + OutHTML_FrmFmtAsSpacer( *this, rFrmFmt ); + break; + case HTML_OUT_CONTROL: // OK + OutHTML_DrawFrmFmtAsControl( *this, + (const SwDrawFrmFmt &)rFrmFmt, *pSdrObject, + pCntnrStr != 0 ); + break; + case HTML_OUT_AMARQUEE: + OutHTML_FrmFmtAsMarquee( *this, rFrmFmt, *pSdrObject ); + break; + case HTML_OUT_MARQUEE: + ASSERT( !pCntnrStr, "Marquee: Container ist hier nicht vorgesehen" ); + OutHTML_DrawFrmFmtAsMarquee( *this, + (const SwDrawFrmFmt &)rFrmFmt, *pSdrObject ); + break; + case HTML_OUT_GRFFRM: + OutHTML_FrmFmtAsImage( *this, rFrmFmt, pCntnrStr != 0 ); + break; + } + + if( HTML_CNTNR_DIV == nCntnrMode ) + { + DecIndentLevel(); + if( bLFPossible ) + OutNewLine(); + HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_division, sal_False ); + bLFPossible = sal_True; + } + else if( HTML_CNTNR_SPAN == nCntnrMode ) + HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_span, sal_False ); +} + + +void SwHTMLWriter::OutFrmFmtOptions( const SwFrmFmt &rFrmFmt, + const String& rAlternateTxt, + ByteString &rEndTags, + sal_uInt32 nFrmOpts ) +{ + ByteString sOut; + const SfxPoolItem* pItem; + const SfxItemSet& rItemSet = rFrmFmt.GetAttrSet(); + + // Name + if( (nFrmOpts & (HTML_FRMOPT_ID|HTML_FRMOPT_NAME)) && + rFrmFmt.GetName().Len() ) + { + const sal_Char *pStr = + (nFrmOpts & HTML_FRMOPT_ID) ? OOO_STRING_SVTOOLS_HTML_O_id : OOO_STRING_SVTOOLS_HTML_O_name; + ((sOut += ' ') += pStr) += "=\""; + Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( Strm(), rFrmFmt.GetName(), eDestEnc, &aNonConvertableCharacters ); + sOut = '\"'; + } + + // Name + if( nFrmOpts & HTML_FRMOPT_DIR ) + { + sal_uInt16 nDir = GetHTMLDirection( rItemSet ); + Strm() << sOut.GetBuffer(); + sOut.Erase(); + OutDirection( nDir ); + } + + + // ALT + if( (nFrmOpts & HTML_FRMOPT_ALT) && rAlternateTxt.Len() ) + { + ((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_alt) += "=\""; + Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( Strm(), rAlternateTxt, eDestEnc, &aNonConvertableCharacters ); + sOut = '\"'; + } + + // ALIGN + const sal_Char *pStr = 0; + RndStdIds eAnchorId = rFrmFmt.GetAnchor().GetAnchorId(); + if( (nFrmOpts & HTML_FRMOPT_ALIGN) && + ((FLY_AT_PARA == eAnchorId) || (FLY_AT_CHAR == eAnchorId)) ) + { + // MIB 12.3.98: Ist es nicht schlauer, absatzgebundene + // Rahmen notfalls links auszurichten als sie + // zeichengebunden einzufuegen??? + const SwFmtHoriOrient& rHoriOri = rFrmFmt.GetHoriOrient(); + if( !(nFrmOpts & HTML_FRMOPT_S_ALIGN) || + text::RelOrientation::FRAME == rHoriOri.GetRelationOrient() || + text::RelOrientation::PRINT_AREA == rHoriOri.GetRelationOrient() ) + { + pStr = text::HoriOrientation::RIGHT == rHoriOri.GetHoriOrient() + ? OOO_STRING_SVTOOLS_HTML_AL_right + : OOO_STRING_SVTOOLS_HTML_AL_left; + } + } + if( (nFrmOpts & HTML_FRMOPT_ALIGN) && !pStr && + ( (nFrmOpts & HTML_FRMOPT_S_ALIGN) == 0 || + (FLY_AS_CHAR == eAnchorId) ) && + SFX_ITEM_SET == rItemSet.GetItemState( RES_VERT_ORIENT, sal_True, &pItem )) + { + switch( ((SwFmtVertOrient*)pItem)->GetVertOrient() ) + { + case text::VertOrientation::LINE_TOP: pStr = OOO_STRING_SVTOOLS_HTML_VA_top; break; + case text::VertOrientation::CHAR_TOP: + case text::VertOrientation::BOTTOM: pStr = OOO_STRING_SVTOOLS_HTML_VA_texttop; break; // geht nicht + case text::VertOrientation::LINE_CENTER: + case text::VertOrientation::CHAR_CENTER: pStr = OOO_STRING_SVTOOLS_HTML_VA_absmiddle; break; // geht nicht + case text::VertOrientation::CENTER: pStr = OOO_STRING_SVTOOLS_HTML_VA_middle; break; + case text::VertOrientation::LINE_BOTTOM: + case text::VertOrientation::CHAR_BOTTOM: pStr = OOO_STRING_SVTOOLS_HTML_VA_absbottom; break; // geht nicht + case text::VertOrientation::TOP: pStr = OOO_STRING_SVTOOLS_HTML_VA_bottom; break; + case text::VertOrientation::NONE: break; + } + } + if( pStr ) + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_align) += '=') += pStr; + + + // HSPACE und VSPACE + Size aTwipSpc( 0, 0 ); + if( (nFrmOpts & (HTML_FRMOPT_SPACE|HTML_FRMOPT_MARGINSIZE)) && + SFX_ITEM_SET == rItemSet.GetItemState( RES_LR_SPACE, sal_True, &pItem )) + { + aTwipSpc.Width() = + ( ((SvxLRSpaceItem*)pItem)->GetLeft() + + ((SvxLRSpaceItem*)pItem)->GetRight() ) / 2; + nDfltLeftMargin = nDfltRightMargin = aTwipSpc.Width(); + } + if( (nFrmOpts & (HTML_FRMOPT_SPACE|HTML_FRMOPT_MARGINSIZE)) && + SFX_ITEM_SET == rItemSet.GetItemState( RES_UL_SPACE, sal_True, &pItem )) + { + aTwipSpc.Height() = + ( ((SvxULSpaceItem*)pItem)->GetUpper() + + ((SvxULSpaceItem*)pItem)->GetLower() ) / 2; + nDfltTopMargin = nDfltBottomMargin = (sal_uInt16)aTwipSpc.Height(); + } + + if( (nFrmOpts & HTML_FRMOPT_SPACE) && + (aTwipSpc.Width() || aTwipSpc.Height()) && + Application::GetDefaultDevice() ) + { + Size aPixelSpc = + Application::GetDefaultDevice()->LogicToPixel( aTwipSpc, + MapMode(MAP_TWIP) ); + if( !aPixelSpc.Width() && aTwipSpc.Width() ) + aPixelSpc.Width() = 1; + if( !aPixelSpc.Height() && aTwipSpc.Height() ) + aPixelSpc.Height() = 1; + + if( aPixelSpc.Width() ) + { + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_hspace) += '=') + += ByteString::CreateFromInt32( aPixelSpc.Width() ); + } + + if( aPixelSpc.Height() ) + { + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_vspace) += '=') + += ByteString::CreateFromInt32( aPixelSpc.Height() ); + } + } + + // Der Abstand muss bei der Groesse beruecksichtigt, wenn das entsprechende + // Flag gesetzt ist. + if( (nFrmOpts & HTML_FRMOPT_MARGINSIZE) ) + { + aTwipSpc.Width() *= -2; + aTwipSpc.Height() *= -2; + } + else + { + aTwipSpc.Width() = 0; + aTwipSpc.Height() = 0; + } + + if( !(nFrmOpts & HTML_FRMOPT_ABSSIZE) && + SFX_ITEM_SET == rItemSet.GetItemState( RES_BOX, sal_True, &pItem )) + { + const SvxBoxItem* pBoxItem = (const SvxBoxItem*)pItem; + + aTwipSpc.Width() += pBoxItem->CalcLineSpace( BOX_LINE_LEFT ); + aTwipSpc.Width() += pBoxItem->CalcLineSpace( BOX_LINE_RIGHT ); + aTwipSpc.Height() += pBoxItem->CalcLineSpace( BOX_LINE_TOP ); + aTwipSpc.Height() += pBoxItem->CalcLineSpace( BOX_LINE_BOTTOM ); + } + + // WIDTH und/oder HEIGHT + // ATT_VAR_SIZE/ATT_MIN_SIZE nur ausgeben, wenn ANYSIZE gesezut ist + if( (nFrmOpts & HTML_FRMOPT_SIZE) && + SFX_ITEM_SET == rItemSet.GetItemState( RES_FRM_SIZE, sal_True, &pItem ) && + ( (nFrmOpts & HTML_FRMOPT_ANYSIZE) || + ATT_FIX_SIZE == ((const SwFmtFrmSize *)pItem)->GetHeightSizeType()) ) + { + const SwFmtFrmSize *pFSItem = (const SwFmtFrmSize *)pItem; + sal_uInt8 nPrcWidth = pFSItem->GetWidthPercent(); + sal_uInt8 nPrcHeight = pFSItem->GetHeightPercent(); + + // Groesse des Objekts Twips ohne Raender + Size aTwipSz( (nPrcWidth ? 0 + : pFSItem->GetWidth()-aTwipSpc.Width()), + (nPrcHeight ? 0 + : pFSItem->GetHeight()-aTwipSpc.Height()) ); + + ASSERT( aTwipSz.Width() >= 0 && aTwipSz.Height() >= 0, + "Rahmengroesse minus Abstand < 0!!!???" ); + if( aTwipSz.Width() < 0 ) + aTwipSz.Width() = 0; + if( aTwipSz.Height() < 0 ) + aTwipSz.Height() = 0; + + Size aPixelSz( 0, 0 ); + if( (aTwipSz.Width() || aTwipSz.Height()) && + Application::GetDefaultDevice() ) + { + aPixelSz = + Application::GetDefaultDevice()->LogicToPixel( aTwipSz, + MapMode(MAP_TWIP) ); + if( !aPixelSz.Width() && aTwipSz.Width() ) + aPixelSz.Width() = 1; + if( !aPixelSz.Height() && aTwipSz.Height() ) + aPixelSz.Height() = 1; + } + + if( (nFrmOpts & HTML_FRMOPT_WIDTH) && + ((nPrcWidth && nPrcWidth!=255) || aPixelSz.Width()) ) + { + ((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_width) += '='; + if( nPrcWidth ) + (sOut += ByteString::CreateFromInt32( nPrcWidth )) += '%'; + else + sOut += ByteString::CreateFromInt32( aPixelSz.Width() ); + } + + if( (nFrmOpts & HTML_FRMOPT_HEIGHT) && + ((nPrcHeight && nPrcHeight!=255) || aPixelSz.Height()) ) + { + ((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_height) += '='; + if( nPrcHeight ) + (sOut += ByteString::CreateFromInt32( nPrcHeight )) += '%'; + else + sOut += ByteString::CreateFromInt32( aPixelSz.Height() ); + } + } + + if( sOut.Len() ) + Strm() << sOut.GetBuffer(); + + // Umlauf fuer absatzgeb. Grafiken als <BR CLEAR=...> in den String + // schreiben + if( (nFrmOpts & HTML_FRMOPT_BRCLEAR) && + ((FLY_AT_PARA == rFrmFmt.GetAnchor().GetAnchorId()) || + (FLY_AT_CHAR == rFrmFmt.GetAnchor().GetAnchorId())) && + SFX_ITEM_SET == rItemSet.GetItemState( RES_SURROUND, sal_True, &pItem )) + { + const SwFmtSurround* pSurround = (const SwFmtSurround*)pItem; + sal_Int16 eHoriOri = rFrmFmt.GetHoriOrient().GetHoriOrient(); + pStr = 0; + SwSurround eSurround = pSurround->GetSurround(); + sal_Bool bAnchorOnly = pSurround->IsAnchorOnly(); + switch( eHoriOri ) + { + case text::HoriOrientation::RIGHT: + { + switch( eSurround ) + { + case SURROUND_NONE: + case SURROUND_RIGHT: + pStr = OOO_STRING_SVTOOLS_HTML_AL_right; + break; + case SURROUND_LEFT: + case SURROUND_PARALLEL: + if( bAnchorOnly ) + bClearRight = sal_True; + break; + default: + ; + } + } + break; + + default: + // #67508#: If a frame is centered, it gets left aligned. This + // should be taken into account here, too. + { + switch( eSurround ) + { + case SURROUND_NONE: + case SURROUND_LEFT: + pStr = OOO_STRING_SVTOOLS_HTML_AL_left; + break; + case SURROUND_RIGHT: + case SURROUND_PARALLEL: + if( bAnchorOnly ) + bClearLeft = sal_True; + break; + default: + ; + } + } + break; + + } + + if( pStr ) + { + (((((((sOut = '<') += OOO_STRING_SVTOOLS_HTML_linebreak) += ' ') + += OOO_STRING_SVTOOLS_HTML_O_clear) += '=') += pStr) += '>') += rEndTags; + rEndTags = sOut; + } + } +} + + +Writer& OutHTML_Image( Writer& rWrt, const SwFrmFmt &rFrmFmt, + const String &rGrfName, const String& rAlternateTxt, + const Size &rRealSize, sal_uInt32 nFrmOpts, + const sal_Char *pMarkType, + const ImageMap *pAltImgMap ) +{ + SwHTMLWriter & rHTMLWrt = (SwHTMLWriter&)rWrt; + + // 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 ); + } + + String aGrfNm( rGrfName ); + if( !HTMLOutFuncs::PrivateURLToInternalImg(aGrfNm) ) + aGrfNm = URIHelper::simpleNormalizedMakeRelative( rWrt.GetBaseURL(), aGrfNm); + + const SfxPoolItem* pItem; + const SfxItemSet& rItemSet = rFrmFmt.GetAttrSet(); + + const SwFmtURL *pURLItem = 0; + + // das URL-Attribut nur beruecksichtigen, wenn keine Image-Map + // uebergeben wurde + if( !pAltImgMap && + SFX_ITEM_SET == rItemSet.GetItemState( RES_URL, sal_True, &pItem )) + { + pURLItem = (const SwFmtURL *)pItem; + } + + // Image-Map rausschreiben + const ImageMap *pIMap = pAltImgMap; + if( !pIMap && pURLItem ) + { + pIMap = pURLItem->GetMap(); + } + + String aIMapName; + if( pIMap ) + { + // den Namen eindeutig machen + aIMapName = pIMap->GetName(); + String aNameBase; + if( aIMapName.Len() ) + aNameBase = aIMapName; + else + aNameBase.AssignAscii( OOO_STRING_SVTOOLS_HTML_map ); + if( !aIMapName.Len() ) + (aIMapName = aNameBase) + += String::CreateFromInt32( rHTMLWrt.nImgMapCnt ); + + sal_Bool bFound; + do + { + bFound = sal_False; + for( sal_uInt16 i=0; i<rHTMLWrt.aImgMapNames.Count(); i++ ) + { + // TODO: Unicode: Comparison is case insensitive for ASCII + // characters only now! + if( aIMapName.EqualsIgnoreCaseAscii(*rHTMLWrt.aImgMapNames[i]) ) + { + bFound = sal_True; + break; + } + } + if( bFound ) + { + rHTMLWrt.nImgMapCnt++; + (aIMapName = aNameBase) + += String::CreateFromInt32( rHTMLWrt.nImgMapCnt ); + } + + } while( bFound ); + + sal_Bool bScale = sal_False; + //Size aGrfSize( rNode.GetTwipSize() ); + Fraction aScaleX( 1, 1 ); + Fraction aScaleY( 1, 1 ); + + const SwFmtFrmSize& rFrmSize = rFrmFmt.GetFrmSize(); + const SvxBoxItem& rBox = rFrmFmt.GetBox(); + + if( !rFrmSize.GetWidthPercent() && rRealSize.Width() ) + { + SwTwips nWidth = rFrmSize.GetWidth(); + nWidth -= ( rBox.CalcLineSpace(BOX_LINE_LEFT) + + rBox.CalcLineSpace(BOX_LINE_RIGHT) ); + + ASSERT( nWidth>0, "Gibt es 0 twip breite Grafiken!?" ); + if( nWidth<=0 ) // sollte nicht passieren + nWidth = 1; + + if( rRealSize.Width() != nWidth ) + { + aScaleX = Fraction( nWidth, rRealSize.Width() ); + bScale = sal_True; + } + } + if( !rFrmSize.GetHeightPercent() && rRealSize.Height() ) + { + SwTwips nHeight = rFrmSize.GetHeight(); + nHeight -= ( rBox.CalcLineSpace(BOX_LINE_TOP) + + rBox.CalcLineSpace(BOX_LINE_BOTTOM) ); + + ASSERT( nHeight>0, "Gibt es 0 twip hohe Grafiken!?" ); + if( nHeight<=0 ) + nHeight = 1; + + if( rRealSize.Height() != nHeight ) + { + aScaleY = Fraction( nHeight, rRealSize.Height() ); + bScale = sal_True; + } + } + + rHTMLWrt.aImgMapNames.Insert( new String(aIMapName), + rHTMLWrt.aImgMapNames.Count() ); + + ByteString aIndMap, aIndArea; + const sal_Char *pLF = 0, *pIndArea = 0, *pIndMap = 0; +#if defined(UNX) + sal_Char aLF[2] = "\x00"; +#endif + + if( rHTMLWrt.bLFPossible ) + { + rHTMLWrt.OutNewLine( sal_True ); + rHTMLWrt.GetIndentString( aIndMap ); + rHTMLWrt.GetIndentString( aIndArea, 1 ); +#if defined(UNX) + aLF[0] = SwHTMLWriter::sNewLine; + pLF = aLF; +#else + pLF = SwHTMLWriter::sNewLine; +#endif + pIndArea = aIndArea.GetBuffer(); + pIndMap = aIndMap.GetBuffer(); + } + + if( bScale ) + { + ImageMap aScaledIMap( *pIMap ); + aScaledIMap.Scale( aScaleX, aScaleY ); + HTMLOutFuncs::Out_ImageMap( rWrt.Strm(), rWrt.GetBaseURL(), aScaledIMap, aIMapName, + aIMapEventTable, + rHTMLWrt.bCfgStarBasic, + pLF, pIndArea, pIndMap, + rHTMLWrt.eDestEnc, + &rHTMLWrt.aNonConvertableCharacters ); + } + else + { + HTMLOutFuncs::Out_ImageMap( rWrt.Strm(), rWrt.GetBaseURL(), *pIMap, aIMapName, + aIMapEventTable, + rHTMLWrt.bCfgStarBasic, + pLF, pIndArea, pIndMap, + rHTMLWrt.eDestEnc, + &rHTMLWrt.aNonConvertableCharacters ); + } + } + + // wenn meoglich vor der Grafik einen Zeilen-Umbruch ausgeben + if( rHTMLWrt.bLFPossible ) + rHTMLWrt.OutNewLine( sal_True ); + + // Attribute die ausserhelb der Grafik geschreiben werden muessen sammeln + ByteString sOut; + ByteString aEndTags; + + // implizite Sprungmarke -> <A NAME=...></A>...<IMG ...> + if( pMarkType && rFrmFmt.GetName().Len() ) + rHTMLWrt.OutImplicitMark( rFrmFmt.GetName(), pMarkType ); + + // URL -> <A>...<IMG ... >...</A> + const SvxMacroItem *pMacItem = 0; + if( SFX_ITEM_SET == rItemSet.GetItemState( RES_FRMMACRO, sal_True, &pItem )) + pMacItem = (const SvxMacroItem *)pItem; + + if( pURLItem || pMacItem ) + { + String aMapURL; + String aName; + String aTarget; + if( pURLItem ) + { + aMapURL = pURLItem->GetURL(); + aName = pURLItem->GetName(); + aTarget = pURLItem->GetTargetFrameName(); + } + sal_Bool bEvents = pMacItem && pMacItem->GetMacroTable().Count(); + + if( aMapURL.Len() || aName.Len() || aTarget.Len() || bEvents ) + { + (sOut = '<') += OOO_STRING_SVTOOLS_HTML_anchor; + + // Ein HREF nur Ausgaben, wenn es einen Link oder Makros gibt + if( aMapURL.Len() || bEvents ) + { + ((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_href) += "=\""; + rWrt.Strm() << sOut.GetBuffer(); + rHTMLWrt.OutHyperlinkHRefValue( aMapURL ); + sOut = '\"'; + } + + if( aName.Len() ) + { + ((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_name) += "=\""; + rWrt.Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( rWrt.Strm(), aName, + rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + sOut = '\"'; + } + + if( aTarget.Len() ) + { + ((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_target) += "=\""; + rWrt.Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( rWrt.Strm(), aTarget, + rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + sOut = '\"'; + } + if( sOut.Len() ) + { + rWrt.Strm() << sOut.GetBuffer(); + sOut.Erase(); + } + + if( pMacItem ) + { + const SvxMacroTableDtor& rMacTable = pMacItem->GetMacroTable(); + if( rMacTable.Count() ) + HTMLOutFuncs::Out_Events( rWrt.Strm(), rMacTable, + aAnchorEventTable, + rHTMLWrt.bCfgStarBasic, + rHTMLWrt.eDestEnc, + &rHTMLWrt.aNonConvertableCharacters ); + } + + rWrt.Strm() << ">"; + (((sOut = "</") += OOO_STRING_SVTOOLS_HTML_anchor) += ">") += aEndTags; + aEndTags = sOut; + } + } + + // Umrandung -> <FONT COLOR = ...>...<IMG ... >...</FONT> + sal_uInt16 nBorderWidth = 0; + if( (nFrmOpts & HTML_FRMOPT_BORDER) && + SFX_ITEM_SET == rItemSet.GetItemState( RES_BOX, sal_True, &pItem )) + { + Size aTwipBorder( 0, 0 ); + const SvxBoxItem* pBoxItem = (const SvxBoxItem*)pItem; + + const SvxBorderLine *pColBorderLine = 0; + const SvxBorderLine *pBorderLine = pBoxItem->GetLeft(); + if( pBorderLine ) + { + pColBorderLine = pBorderLine; + aTwipBorder.Width() += pBorderLine->GetOutWidth(); + } + + pBorderLine = pBoxItem->GetRight(); + if( pBorderLine ) + { + pColBorderLine = pBorderLine; + aTwipBorder.Width() += pBorderLine->GetOutWidth(); + } + + pBorderLine = pBoxItem->GetTop(); + if( pBorderLine ) + { + pColBorderLine = pBorderLine; + aTwipBorder.Height() += pBorderLine->GetOutWidth(); + } + + pBorderLine = pBoxItem->GetBottom(); + if( pBorderLine ) + { + pColBorderLine = pBorderLine; + aTwipBorder.Height() += pBorderLine->GetOutWidth(); + } + + aTwipBorder.Width() /= 2; + aTwipBorder.Height() /= 2; + + if( (aTwipBorder.Width() || aTwipBorder.Height()) && + Application::GetDefaultDevice() ) + { + Size aPixelBorder = + Application::GetDefaultDevice()->LogicToPixel( aTwipBorder, + MapMode(MAP_TWIP) ); + if( !aPixelBorder.Width() && aTwipBorder.Width() ) + aPixelBorder.Width() = 1; + if( !aPixelBorder.Height() && aTwipBorder.Height() ) + aPixelBorder.Height() = 1; + + if( aPixelBorder.Width() ) + aPixelBorder.Height() = 0; + + nBorderWidth = + (sal_uInt16)(aPixelBorder.Width() + aPixelBorder.Height()); + } + + if( pColBorderLine ) + { + sOut = '<'; + (((sOut += OOO_STRING_SVTOOLS_HTML_font) += ' ') += OOO_STRING_SVTOOLS_HTML_O_color) += '='; + rWrt.Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_Color( rWrt.Strm(), + pColBorderLine->GetColor(), rHTMLWrt.eDestEnc ) << '>'; + + (((sOut = "</" ) += OOO_STRING_SVTOOLS_HTML_font) += '>') += aEndTags; + aEndTags = sOut; + } + } + + sOut = '<'; + (((sOut += OOO_STRING_SVTOOLS_HTML_image) += ' ') += OOO_STRING_SVTOOLS_HTML_O_src) += "=\""; + rWrt.Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( rWrt.Strm(), aGrfNm, rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ) << '\"'; + + // Events + sOut.Erase(); + if( SFX_ITEM_SET == rItemSet.GetItemState( RES_FRMMACRO, sal_True, &pItem )) + { + const SvxMacroTableDtor& rMacTable = + ((const SvxMacroItem *)pItem)->GetMacroTable(); + if( rMacTable.Count() ) + HTMLOutFuncs::Out_Events( rWrt.Strm(), rMacTable, aImageEventTable, + rHTMLWrt.bCfgStarBasic, rHTMLWrt.eDestEnc, + &rHTMLWrt.aNonConvertableCharacters ); + } + + // ALT, ALIGN, WIDTH, HEIGHT, HSPACE, VSPACE + rHTMLWrt.OutFrmFmtOptions( rFrmFmt, rAlternateTxt, aEndTags, nFrmOpts ); + if( rHTMLWrt.IsHTMLMode( HTMLMODE_ABS_POS_FLY ) ) + rHTMLWrt.OutCSS1_FrmFmtOptions( rFrmFmt, nFrmOpts ); + + + if( nFrmOpts & HTML_FRMOPT_BORDER ) + { + (((sOut = ' ') += OOO_STRING_SVTOOLS_HTML_O_border) += '=') + += ByteString::CreateFromInt32( nBorderWidth ); + rWrt.Strm() << sOut.GetBuffer(); + } + + if( pURLItem && pURLItem->IsServerMap() ) + { + (sOut = ' ') += OOO_STRING_SVTOOLS_HTML_O_ismap; + rWrt.Strm() << sOut.GetBuffer(); + } + if( aIMapName.Len() ) + { + ((sOut = ' ') += OOO_STRING_SVTOOLS_HTML_O_usemap) += "=\"#"; + rWrt.Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( rWrt.Strm(), aIMapName, rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ) << '\"'; + } + + rHTMLWrt.Strm() << '>'; + + if( aEndTags.Len() ) + rWrt.Strm() << aEndTags.GetBuffer(); + + 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 rHTMLWrt; +} + +Writer& OutHTML_BulletImage( Writer& rWrt, + const sal_Char *pTag, + const SvxBrushItem* pBrush, + String &rGrfName, + const Size &rSize, + const SwFmtVertOrient* pVertOrient ) +{ + SwHTMLWriter & rHTMLWrt = (SwHTMLWriter&)rWrt; + + // Wenn es ein BrushItem gibt, muss die Grafiknoch exportiert werden + const String *pLink = 0; + if( pBrush ) + { + pLink = pBrush->GetGraphicLink(); + + // embeddete Grafik -> WriteEmbedded schreiben + if( !pLink ) + { + const Graphic* pGrf = pBrush->GetGraphic(); + if( pGrf ) + { + // Grafik als (JPG-)File speichern + if( rHTMLWrt.GetOrigFileName() ) + rGrfName = *rHTMLWrt.GetOrigFileName(); + sal_uInt16 nErr = XOutBitmap::WriteGraphic( *pGrf, rGrfName, + String::CreateFromAscii("JPG"), + (XOUTBMP_USE_GIF_IF_SENSIBLE | + XOUTBMP_USE_NATIVE_IF_POSSIBLE)); + if( !nErr ) + { + rGrfName = URIHelper::SmartRel2Abs( + INetURLObject( rWrt.GetBaseURL() ), rGrfName, + URIHelper::GetMaybeFileHdl() ); + pLink = &rGrfName; + } + else + { + rHTMLWrt.nWarn = WARN_SWG_POOR_LOAD | WARN_SW_WRITE_BASE; + } + } + } + else + { + rGrfName = *pLink; + if( rHTMLWrt.bCfgCpyLinkedGrfs ) + { + rHTMLWrt.CopyLocalFileToINet( rGrfName ); + pLink = &rGrfName; + } + } + } + else + { + pLink = &rGrfName; + } + + ByteString sOut; + if( pTag ) + (sOut += '<') += pTag; + + if( pLink ) + { + sOut += ' '; + String s( *pLink ); + if( !HTMLOutFuncs::PrivateURLToInternalImg(s) ) + s = URIHelper::simpleNormalizedMakeRelative( rWrt.GetBaseURL(), s); + (sOut += OOO_STRING_SVTOOLS_HTML_O_src) += "=\""; + rWrt.Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( rWrt.Strm(), s, rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + sOut = '\"'; + + // Groesse des Objekts Twips ohne Raender + Size aPixelSz( 0, 0 ); + if( (rSize.Width() || rSize.Height()) && Application::GetDefaultDevice() ) + { + aPixelSz = + Application::GetDefaultDevice()->LogicToPixel( rSize, + MapMode(MAP_TWIP) ); + if( !aPixelSz.Width() && rSize.Width() ) + aPixelSz.Width() = 1; + if( !aPixelSz.Height() && rSize.Height() ) + aPixelSz.Height() = 1; + } + + if( aPixelSz.Width() ) + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_width) += '=') + += ByteString::CreateFromInt32( aPixelSz.Width() ); + + if( aPixelSz.Height() ) + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_height) += '=') + += ByteString::CreateFromInt32( aPixelSz.Height() ); + + if( pVertOrient ) + { + const sal_Char *pStr = 0; + switch( pVertOrient->GetVertOrient() ) + { + case text::VertOrientation::LINE_TOP: pStr = OOO_STRING_SVTOOLS_HTML_VA_top; break; + case text::VertOrientation::CHAR_TOP: + case text::VertOrientation::BOTTOM: pStr = OOO_STRING_SVTOOLS_HTML_VA_texttop; break; // geht nicht + case text::VertOrientation::LINE_CENTER: + case text::VertOrientation::CHAR_CENTER: pStr = OOO_STRING_SVTOOLS_HTML_VA_absmiddle; break; // geht nicht + case text::VertOrientation::CENTER: pStr = OOO_STRING_SVTOOLS_HTML_VA_middle; break; + case text::VertOrientation::LINE_BOTTOM: + case text::VertOrientation::CHAR_BOTTOM: pStr = OOO_STRING_SVTOOLS_HTML_VA_absbottom; break; // geht nicht + case text::VertOrientation::TOP: pStr = OOO_STRING_SVTOOLS_HTML_VA_bottom; break; + case text::VertOrientation::NONE: break; + } + if( pStr ) + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_align) += '=') += pStr; + } + } + + if( pTag ) + sOut += '>'; + rWrt.Strm() << sOut.GetBuffer(); + + return rWrt; +} + + +//----------------------------------------------------------------------- + +static Writer& OutHTML_FrmFmtTableNode( Writer& rWrt, const SwFrmFmt& rFrmFmt ) +{ + SwHTMLWriter & rHTMLWrt = (SwHTMLWriter&)rWrt; + + const SwFmtCntnt& rFlyCntnt = rFrmFmt.GetCntnt(); + sal_uLong nStt = rFlyCntnt.GetCntntIdx()->GetIndex()+1; + sal_uLong nEnd = rHTMLWrt.pDoc->GetNodes()[nStt-1]->EndOfSectionIndex(); + + String aCaption; + sal_Bool bTopCaption = sal_False; + + // Nicht const, weil GetTable spater mal nicht const ist + SwNode *pNd = rHTMLWrt.pDoc->GetNodes()[ nStt ]; + SwTableNode *pTblNd = pNd->GetTableNode(); + const SwTxtNode *pTxtNd = pNd->GetTxtNode(); + if( !pTblNd && pTxtNd ) + { + // Tabelle mit Ueberschrift + bTopCaption = sal_True; + pTblNd = rHTMLWrt.pDoc->GetNodes()[nStt+1]->GetTableNode(); + } + ASSERT( pTblNd, "Rahmen enthaelt keine Tabelle" ); + if( pTblNd ) + { + sal_uLong nTblEnd = pTblNd->EndOfSectionIndex(); + ASSERT( nTblEnd == nEnd - 1 || + (nTblEnd == nEnd - 2 && !bTopCaption), + "Ungeuelter Rahmen-Inhalt fuer Tabelle" ); + + if( nTblEnd == nEnd - 2 ) + pTxtNd = rHTMLWrt.pDoc->GetNodes()[nTblEnd+1]->GetTxtNode(); + } + if( pTxtNd ) + aCaption = pTxtNd->GetTxt(); + + { + HTMLSaveData aSaveData( rHTMLWrt, pTblNd->GetIndex()+1, + pTblNd->EndOfSectionIndex(), + sal_True, &rFrmFmt ); + rHTMLWrt.bOutFlyFrame = sal_True; + OutHTML_SwTblNode( rHTMLWrt, *pTblNd, &rFrmFmt, &aCaption, + bTopCaption ); + } + + return rWrt; +} + +static Writer & OutHTML_FrmFmtAsMulticol( Writer& rWrt, + const SwFrmFmt& rFrmFmt, + sal_Bool bInCntnr ) +{ + SwHTMLWriter & rHTMLWrt = (SwHTMLWriter&)rWrt; + + rHTMLWrt.ChangeParaToken( 0 ); + + // Die aktulle <DL> beenden! + rHTMLWrt.OutAndSetDefList( 0 ); + + // als Multicol ausgeben + if( rHTMLWrt.bLFPossible ) + rHTMLWrt.OutNewLine(); + + ByteString sOut( '<' ); + sOut += OOO_STRING_SVTOOLS_HTML_multicol; + + const SwFmtCol& rFmtCol = rFrmFmt.GetCol(); + + // die Anzahl der Spalten als COLS ausgeben + sal_uInt16 nCols = rFmtCol.GetNumCols(); + if( nCols ) + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_cols) += '=') + += ByteString::CreateFromInt32( nCols ); + + // die Gutter-Breite (Minimalwert) als GUTTER + sal_uInt16 nGutter = rFmtCol.GetGutterWidth( sal_True ); + if( nGutter!=USHRT_MAX ) + { + if( nGutter && Application::GetDefaultDevice() ) + { + nGutter = (sal_uInt16)Application::GetDefaultDevice() + ->LogicToPixel( Size(nGutter,0), + MapMode(MAP_TWIP) ).Width(); + } + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_gutter) += '=') + += ByteString::CreateFromInt32( nGutter ); + } + + rWrt.Strm() << sOut.GetBuffer(); + + // WIDTH + sal_uLong nFrmFlags = bInCntnr ? HTML_FRMOPTS_MULTICOL_CNTNR + : HTML_FRMOPTS_MULTICOL; + if( rHTMLWrt.IsHTMLMode( HTMLMODE_ABS_POS_FLY ) && !bInCntnr ) + nFrmFlags |= HTML_FRMOPTS_MULTICOL_CSS1; + ByteString aEndTags; + rHTMLWrt.OutFrmFmtOptions( rFrmFmt, aEmptyStr, aEndTags, nFrmFlags ); + if( rHTMLWrt.IsHTMLMode( HTMLMODE_ABS_POS_FLY ) && !bInCntnr ) + rHTMLWrt.OutCSS1_FrmFmtOptions( rFrmFmt, nFrmFlags ); + + rWrt.Strm() << '>'; + + rHTMLWrt.bLFPossible = sal_True; + rHTMLWrt.IncIndentLevel(); // den Inhalt von Multicol einruecken; + + const SwFmtCntnt& rFlyCntnt = rFrmFmt.GetCntnt(); + sal_uLong nStt = rFlyCntnt.GetCntntIdx()->GetIndex(); + const SwStartNode* pSttNd = rWrt.pDoc->GetNodes()[nStt]->GetStartNode(); + ASSERT( pSttNd, "Wo ist der Start-Node" ); + + { + // in einem Block damit rechtzeitig vor dem Ende der alte Zustand + // wieder hergestellt wird. + HTMLSaveData aSaveData( rHTMLWrt, nStt+1, + pSttNd->EndOfSectionIndex(), + sal_True, &rFrmFmt ); + rHTMLWrt.bOutFlyFrame = sal_True; + rHTMLWrt.Out_SwDoc( rWrt.pCurPam ); + } + +// rHTMLWrt.ChangeParaToken( 0 ); // MIB 8.7.97: Passiert jetzt in Out_SwDoc + + rHTMLWrt.DecIndentLevel(); // den Inhalt von Multicol einruecken; + if( rHTMLWrt.bLFPossible ) + rHTMLWrt.OutNewLine(); + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_multicol, sal_False ); + rHTMLWrt.bLFPossible = sal_True; + + return rWrt; +} + +static Writer& OutHTML_FrmFmtAsSpacer( Writer& rWrt, const SwFrmFmt& rFrmFmt ) +{ + SwHTMLWriter & rHTMLWrt = (SwHTMLWriter&)rWrt; + + // wenn meoglich vor der Grafik einen Zeilen-Umbruch ausgeben + if( rHTMLWrt.bLFPossible ) + rHTMLWrt.OutNewLine( sal_True ); + + ByteString sOut('<'); + ((((sOut += OOO_STRING_SVTOOLS_HTML_spacer) += ' ') += OOO_STRING_SVTOOLS_HTML_O_type) += '=') + += OOO_STRING_SVTOOLS_HTML_SPTYPE_block; + rWrt.Strm() << sOut.GetBuffer(); + + // ALIGN, WIDTH, HEIGHT + ByteString aEndTags; + rHTMLWrt.OutFrmFmtOptions( rFrmFmt, aEmptyStr, aEndTags, + HTML_FRMOPTS_SPACER ); + + rWrt.Strm() << '>'; + if( aEndTags.Len() ) + rWrt.Strm() << aEndTags.GetBuffer(); + + return rWrt; +} + +static Writer& OutHTML_FrmFmtAsDivOrSpan( Writer& rWrt, + const SwFrmFmt& rFrmFmt, sal_Bool bSpan) +{ + SwHTMLWriter & rHTMLWrt = (SwHTMLWriter&)rWrt; + + const sal_Char *pStr = 0; + if( !bSpan ) + { + rHTMLWrt.ChangeParaToken( 0 ); + + // Die aktulle <DL> beenden! + rHTMLWrt.OutAndSetDefList( 0 ); + pStr = OOO_STRING_SVTOOLS_HTML_division; + } + else + pStr = OOO_STRING_SVTOOLS_HTML_span; + + // als DIV ausgeben + if( rHTMLWrt.bLFPossible ) + rHTMLWrt.OutNewLine(); + + ByteString sOut( '<' ); + sOut += pStr; + + rWrt.Strm() << sOut.GetBuffer(); + ByteString aEndTags; + sal_uLong nFrmFlags = HTML_FRMOPTS_DIV; + if( rHTMLWrt.IsHTMLMode( HTMLMODE_BORDER_NONE ) ) + nFrmFlags |= HTML_FRMOPT_S_NOBORDER; + rHTMLWrt.OutFrmFmtOptions( rFrmFmt, aEmptyStr, aEndTags, nFrmFlags ); + rHTMLWrt.OutCSS1_FrmFmtOptions( rFrmFmt, nFrmFlags ); + rWrt.Strm() << '>'; + + rHTMLWrt.IncIndentLevel(); // den Inhalt einruecken + rHTMLWrt.bLFPossible = sal_True; + + const SwFmtCntnt& rFlyCntnt = rFrmFmt.GetCntnt(); + sal_uLong nStt = rFlyCntnt.GetCntntIdx()->GetIndex(); + + // Am Start-Node verankerte Rahmen-gebundene Rahmen ausgeben + rHTMLWrt.OutFlyFrm( nStt, 0, HTML_POS_ANY ); + + const SwStartNode* pSttNd = rWrt.pDoc->GetNodes()[nStt]->GetStartNode(); + ASSERT( pSttNd, "Wo ist der Start-Node" ); + + { + // in einem Block damit rechtzeitig vor dem Ende der alte Zustand + // wieder hergestellt wird. + HTMLSaveData aSaveData( rHTMLWrt, nStt+1, + pSttNd->EndOfSectionIndex(), + sal_True, &rFrmFmt ); + rHTMLWrt.bOutFlyFrame = sal_True; + rHTMLWrt.Out_SwDoc( rWrt.pCurPam ); + } + + rHTMLWrt.DecIndentLevel(); // den Inhalt von Multicol einruecken; + if( rHTMLWrt.bLFPossible ) + rHTMLWrt.OutNewLine(); + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), pStr, sal_False ); + + if( aEndTags.Len() ) + rWrt.Strm() << aEndTags.GetBuffer(); + + return rWrt; +} + +static Writer & OutHTML_FrmFmtAsImage( Writer& rWrt, const SwFrmFmt& rFrmFmt, + sal_Bool /*bInCntnr*/ ) +{ + SwHTMLWriter & rHTMLWrt = (SwHTMLWriter&)rWrt; + + ImageMap aIMap; + Graphic aGrf( ((SwFrmFmt &)rFrmFmt).MakeGraphic( &aIMap ) ); + + String aGrfNm; + if( rHTMLWrt.GetOrigFileName() ) + aGrfNm = *rHTMLWrt.GetOrigFileName(); + if( aGrf.GetType() == GRAPHIC_NONE || + XOutBitmap::WriteGraphic( aGrf, aGrfNm, + String::CreateFromAscii( "JPG" ), + (XOUTBMP_USE_GIF_IF_POSSIBLE| + XOUTBMP_USE_NATIVE_IF_POSSIBLE) ) != 0 ) + { + // leer oder fehlerhaft, da ist nichts auszugeben + rHTMLWrt.nWarn = WARN_SWG_POOR_LOAD | WARN_SW_WRITE_BASE; + return rWrt; + } + + aGrfNm = URIHelper::SmartRel2Abs( + INetURLObject(rWrt.GetBaseURL()), aGrfNm, + URIHelper::GetMaybeFileHdl() ); + Size aSz( 0, 0 ); + OutHTML_Image( rWrt, rFrmFmt, aGrfNm, rFrmFmt.GetName(), aSz, + HTML_FRMOPTS_GENIMG, pMarkToFrame, + aIMap.GetIMapObjectCount() ? &aIMap : 0 ); + return rWrt; +} + + +static Writer& OutHTML_FrmFmtGrfNode( Writer& rWrt, const SwFrmFmt& rFrmFmt, + sal_Bool bInCntnr ) +{ + SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt; + + const SwFmtCntnt& rFlyCntnt = rFrmFmt.GetCntnt(); + sal_uLong nStt = rFlyCntnt.GetCntntIdx()->GetIndex()+1; + SwGrfNode *pGrfNd = rHTMLWrt.pDoc->GetNodes()[ nStt ]->GetGrfNode(); + ASSERT( pGrfNd, "Grf-Node erwartet" ); + if( !pGrfNd ) + return rWrt; + + const SwMirrorGrf& rMirror = pGrfNd->GetSwAttrSet().GetMirrorGrf(); + + String aGrfNm; + if( !pGrfNd->IsLinkedFile() || RES_MIRROR_GRAPH_DONT != rMirror.GetValue() ) + { + // Grafik als File-Referenz speichern (als JPEG-Grafik speichern) + if( rHTMLWrt.GetOrigFileName() ) + aGrfNm = *rHTMLWrt.GetOrigFileName(); + pGrfNd->SwapIn( sal_True ); + + sal_uLong nFlags = XOUTBMP_USE_GIF_IF_SENSIBLE | + XOUTBMP_USE_NATIVE_IF_POSSIBLE; + switch( rMirror.GetValue() ) + { + case RES_MIRROR_GRAPH_VERT: nFlags = XOUTBMP_MIRROR_HORZ; break; + case RES_MIRROR_GRAPH_HOR: nFlags = XOUTBMP_MIRROR_VERT; break; + case RES_MIRROR_GRAPH_BOTH: + nFlags = XOUTBMP_MIRROR_VERT | XOUTBMP_MIRROR_HORZ; + break; + } + + Size aMM100Size; + const SwFmtFrmSize& rSize = rFrmFmt.GetFrmSize(); + aMM100Size = OutputDevice::LogicToLogic( rSize.GetSize(), + MapMode( MAP_TWIP ), MapMode( MAP_100TH_MM )); + + sal_uInt16 nErr = XOutBitmap::WriteGraphic( pGrfNd->GetGrf(), aGrfNm, + String::CreateFromAscii("JPG"), nFlags, &aMM100Size ); + if( nErr ) // fehlerhaft, da ist nichts auszugeben + { + rHTMLWrt.nWarn = WARN_SWG_POOR_LOAD | WARN_SW_WRITE_BASE; + return rWrt; + } + aGrfNm = URIHelper::SmartRel2Abs( + INetURLObject(rWrt.GetBaseURL()), aGrfNm, + URIHelper::GetMaybeFileHdl() ); + } + else + { + pGrfNd->GetFileFilterNms( &aGrfNm, 0 ); + if( rHTMLWrt.bCfgCpyLinkedGrfs ) + rWrt.CopyLocalFileToINet( aGrfNm ); + } + + sal_uLong nFrmFlags = bInCntnr ? HTML_FRMOPTS_IMG_CNTNR : HTML_FRMOPTS_IMG; + if( rHTMLWrt.IsHTMLMode( HTMLMODE_ABS_POS_FLY ) && !bInCntnr ) + nFrmFlags |= HTML_FRMOPTS_IMG_CSS1; + OutHTML_Image( rWrt, rFrmFmt, aGrfNm, pGrfNd->GetTitle(), + pGrfNd->GetTwipSize(), nFrmFlags, pMarkToGraphic ); + + return rWrt; +} + + +static Writer& OutHTML_FrmFmtAsMarquee( Writer& rWrt, const SwFrmFmt& rFrmFmt, + const SdrObject& rSdrObj ) +{ + SwHTMLWriter & rHTMLWrt = (SwHTMLWriter&)rWrt; + + // die Edit-Engine-Attribute des Objekts als SW-Attribute holen + // und als Hints einsortieren + const SfxItemSet& rFmtItemSet = rFrmFmt.GetAttrSet(); + SfxItemSet aItemSet( *rFmtItemSet.GetPool(), RES_CHRATR_BEGIN, + RES_CHRATR_END ); + SwHTMLWriter::GetEEAttrsFromDrwObj( aItemSet, &rSdrObj, sal_True ); + sal_Bool bCfgOutStylesOld = rHTMLWrt.bCfgOutStyles; + rHTMLWrt.bCfgOutStyles = sal_False; + rHTMLWrt.bTxtAttr = sal_True; + rHTMLWrt.bTagOn = sal_True; + Out_SfxItemSet( aHTMLAttrFnTab, rWrt, aItemSet, sal_False ); + rHTMLWrt.bTxtAttr = sal_False; + + OutHTML_DrawFrmFmtAsMarquee( rHTMLWrt, + (const SwDrawFrmFmt &)rFrmFmt, + rSdrObj ); + rHTMLWrt.bTxtAttr = sal_True; + rHTMLWrt.bTagOn = sal_False; + Out_SfxItemSet( aHTMLAttrFnTab, rWrt, aItemSet, sal_False ); + rHTMLWrt.bTxtAttr = sal_False; + rHTMLWrt.bCfgOutStyles = bCfgOutStylesOld; + + return rWrt; +} + +//----------------------------------------------------------------------- + +Writer& OutHTML_HeaderFooter( Writer& rWrt, const SwFrmFmt& rFrmFmt, + sal_Bool bHeader ) +{ + SwHTMLWriter & rHTMLWrt = (SwHTMLWriter&)rWrt; + + // als Multicol ausgeben + rHTMLWrt.OutNewLine(); + ByteString sOut( OOO_STRING_SVTOOLS_HTML_division ); + ((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_type) += '='; + sOut += (bHeader ? "HEADER" : "FOOTER" ); + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), sOut.GetBuffer() ); + + rHTMLWrt.IncIndentLevel(); // den Inhalt von Multicol einruecken; + + // Einen Spacer fuer den Absatnd zusammenbasteln. Da durch das + // <DL> bzw. </DL> immer einer Absatz-Abstand entsteht, wird der + // ggf. abgezogen. + const SvxULSpaceItem& rULSpace = rFrmFmt.GetULSpace(); + sal_uInt16 nSize = bHeader ? rULSpace.GetLower() : rULSpace.GetUpper(); + rHTMLWrt.nHeaderFooterSpace = nSize; + + ByteString aSpacer; + if( rHTMLWrt.IsHTMLMode(HTMLMODE_VERT_SPACER) && + nSize > HTML_PARSPACE && Application::GetDefaultDevice() ) + { + nSize -= HTML_PARSPACE; + nSize = (sal_Int16)Application::GetDefaultDevice() + ->LogicToPixel( Size(nSize,0), MapMode(MAP_TWIP) ).Width(); + + ((((((((aSpacer = OOO_STRING_SVTOOLS_HTML_spacer) += ' ') + += OOO_STRING_SVTOOLS_HTML_O_type) += '=') += OOO_STRING_SVTOOLS_HTML_SPTYPE_vertical) += ' ') + += OOO_STRING_SVTOOLS_HTML_O_size) += '=') += ByteString::CreateFromInt32(nSize); + } + + const SwFmtCntnt& rFlyCntnt = rFrmFmt.GetCntnt(); + sal_uLong nStt = rFlyCntnt.GetCntntIdx()->GetIndex(); + const SwStartNode* pSttNd = rWrt.pDoc->GetNodes()[nStt]->GetStartNode(); + ASSERT( pSttNd, "Wo ist der Start-Node" ); + + if( !bHeader && aSpacer.Len() ) + { + rHTMLWrt.OutNewLine(); + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), aSpacer.GetBuffer() ); + } + + { + // in einem Block damit rechtzeitig vor dem Ende der alte Zustand + // wieder hergestellt wird. pFlyFmt braucht hier nicht gestzt zu + // werden, denn PageDesc-Attribute koennen hier nicht vorkommen + HTMLSaveData aSaveData( rHTMLWrt, nStt+1, + pSttNd->EndOfSectionIndex() ); + + if( bHeader ) + rHTMLWrt.bOutHeader = sal_True; + else + rHTMLWrt.bOutFooter = sal_True; + + rHTMLWrt.Out_SwDoc( rWrt.pCurPam ); + } + + if( bHeader && aSpacer.Len() ) + { + rHTMLWrt.OutNewLine(); + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), aSpacer.GetBuffer() ); + } + + rHTMLWrt.DecIndentLevel(); // den Inhalt von Multicol einruecken; + rHTMLWrt.OutNewLine(); + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_division, sal_False ); + + rHTMLWrt.nHeaderFooterSpace = 0; + + return rWrt; +} + + +void SwHTMLWriter::AddLinkTarget( const String& rURL ) +{ + if( !rURL.Len() || rURL.GetChar(0) != '#' ) + return; + + // There might be a '|' as delimiter (if the link has been inserted + // freshly) or a '%7c' or a '%7C' if the document has been saved and + // loaded already. + xub_StrLen nPos = rURL.Len(); + sal_Bool bFound = sal_False, bEncoded = sal_False; + while( !bFound && nPos > 0 ) + { + sal_Unicode c = rURL.GetChar( --nPos ); + switch( c ) + { + case cMarkSeperator: + bFound = sal_True; + break; + case '%': + bFound = (rURL.Len() - nPos) >=3 && + rURL.GetChar( nPos+1 ) == '7' && + ((c =rURL.GetChar( nPos+2 )) == 'C' || c == 'c'); + if( bFound ) + bEncoded = sal_True; + } + } + if( !bFound || nPos < 2 ) // mindetsens "#a|..." + return; + + String aURL( rURL.Copy( 1 ) ); + + String sCmp( aURL.Copy( bEncoded ? nPos+2 : nPos ) ); // nPos-1+1/3 (-1 wg. Erase) + sCmp.EraseAllChars(); + if( !sCmp.Len() ) + return; + + sCmp.ToLowerAscii(); + + if( sCmp.EqualsAscii( pMarkToRegion ) || + sCmp.EqualsAscii( pMarkToFrame ) || + sCmp.EqualsAscii( pMarkToGraphic ) || + sCmp.EqualsAscii( pMarkToOLE ) || + sCmp.EqualsAscii( pMarkToTable ) ) + { + // Einfach nur in einem sortierten Array merken + if( bEncoded ) + { + aURL.Erase( nPos, 2 ); + aURL.SetChar( nPos-1, cMarkSeperator ); + } + aImplicitMarks.Insert( new String( aURL ) ); + } + else if( sCmp.EqualsAscii( pMarkToOutline ) ) + { + // Hier brauchen wir Position und Name. Deshalb sortieren wir + // ein sal_uInt16 und ein String-Array selbst + String aOutline( aURL.Copy( 0, nPos-1 ) ); + SwPosition aPos( *pCurPam->GetPoint() ); + if( pDoc->GotoOutline( aPos, aOutline ) ) + { + sal_uLong nIdx = aPos.nNode.GetIndex(); + + sal_uInt16 nIns=0; + while( nIns < aOutlineMarkPoss.Count() && + aOutlineMarkPoss[nIns] < nIdx ) + nIns++; + + aOutlineMarkPoss.Insert( nIdx, nIns ); + if( bEncoded ) + { + aURL.Erase( nPos, 2 ); + aURL.SetChar( nPos-1, cMarkSeperator ); + } + aOutlineMarks.Insert( new String( aURL ), nIns ); + } + } + else if( sCmp.EqualsAscii( pMarkToText ) ) + { + // + } +} + +void SwHTMLWriter::CollectLinkTargets() +{ + const SwFmtINetFmt* pINetFmt; + const SwTxtINetFmt* pTxtAttr; + const SwTxtNode* pTxtNd; + + sal_uInt32 n, nMaxItems = pDoc->GetAttrPool().GetItemCount2( RES_TXTATR_INETFMT ); + for( n = 0; n < nMaxItems; ++n ) + { + if( 0 != (pINetFmt = (SwFmtINetFmt*)pDoc->GetAttrPool().GetItem2( + RES_TXTATR_INETFMT, n ) ) && + 0 != ( pTxtAttr = pINetFmt->GetTxtINetFmt()) && + 0 != ( pTxtNd = pTxtAttr->GetpTxtNode() ) && + pTxtNd->GetNodes().IsDocNodes() ) + { + AddLinkTarget( pINetFmt->GetValue() ); + } + } + + const SwFmtURL *pURL; + nMaxItems = pDoc->GetAttrPool().GetItemCount2( RES_URL ); + for( n = 0; n < nMaxItems; ++n ) + { + if( 0 != (pURL = (SwFmtURL*)pDoc->GetAttrPool().GetItem2( + RES_URL, n ) ) ) + { + AddLinkTarget( pURL->GetURL() ); + const ImageMap *pIMap = pURL->GetMap(); + if( pIMap ) + { + for( sal_uInt16 i=0; i<pIMap->GetIMapObjectCount(); i++ ) + { + const IMapObject* pObj = pIMap->GetIMapObject( i ); + if( pObj ) + { + AddLinkTarget( pObj->GetURL() ); + } + } + } + } + } +} + +//----------------------------------------------------------------------- + +SwHTMLPosFlyFrm::SwHTMLPosFlyFrm( const SwPosFlyFrm& rPosFly, + const SdrObject *pSdrObj, + sal_uInt8 nOutMode ) : + pFrmFmt( &rPosFly.GetFmt() ), + pSdrObject( pSdrObj ), + pNdIdx( new SwNodeIndex( rPosFly.GetNdIndex() ) ), + nOrdNum( rPosFly.GetOrdNum() ), + nCntntIdx( 0 ), + nOutputMode( nOutMode ) +{ + const SwFmtAnchor& rAnchor = rPosFly.GetFmt().GetAnchor(); + if ((FLY_AT_CHAR == rAnchor.GetAnchorId()) && + HTML_POS_INSIDE == GetOutPos() ) + { + // Auto-gebundene Rahmen werden ein Zeichen weiter hinten + // ausgegeben, weil dann die Positionierung mit Netscape + // uebereinstimmt. + ASSERT( rAnchor.GetCntntAnchor(), "Keine Anker-Position?" ); + if( rAnchor.GetCntntAnchor() ) + { + nCntntIdx = rAnchor.GetCntntAnchor()->nContent.GetIndex(); + sal_Int16 eHoriRel = rPosFly.GetFmt().GetHoriOrient(). + GetRelationOrient(); + if( text::RelOrientation::FRAME == eHoriRel || text::RelOrientation::PRINT_AREA == eHoriRel ) + { + const SwCntntNode *pCNd = pNdIdx->GetNode().GetCntntNode(); + ASSERT( pCNd, "Kein Content-Node an PaM-Position" ); + if( pCNd && nCntntIdx < pCNd->Len() ) + nCntntIdx++; + } + } + } +} + +sal_Bool SwHTMLPosFlyFrm::operator<( const SwHTMLPosFlyFrm& rFrm ) const +{ + if( pNdIdx->GetIndex() == rFrm.pNdIdx->GetIndex() ) + { + if( nCntntIdx == rFrm.nCntntIdx ) + { + if( GetOutPos() == rFrm.GetOutPos() ) + return nOrdNum < rFrm.nOrdNum; + else + return GetOutPos() < rFrm.GetOutPos(); + } + else + return nCntntIdx < rFrm.nCntntIdx; + } + else + return pNdIdx->GetIndex() < rFrm.pNdIdx->GetIndex(); +} + + diff --git a/sw/source/filter/html/htmlfly.hxx b/sw/source/filter/html/htmlfly.hxx new file mode 100644 index 000000000000..ff91c0a3732c --- /dev/null +++ b/sw/source/filter/html/htmlfly.hxx @@ -0,0 +1,137 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _HTMLFLY_HXX +#define _HTMLFLY_HXX + +#include <tools/solar.h> +#include <tools/string.hxx> + +#ifndef _SVARRAY_H +#include <svl/svarray.hxx> +#endif + +class SdrObject; +class SwFrmFmt; +class SwNodeIndex; +class SwPosFlyFrm; + +// ACHTUNG: Die Werte dieses Enumgs gehen direkt in die +// Augabe Tabelle!!! +enum SwHTMLFrmType +{ + HTML_FRMTYPE_TABLE, + HTML_FRMTYPE_TABLE_CAP, + HTML_FRMTYPE_MULTICOL, + HTML_FRMTYPE_EMPTY, + HTML_FRMTYPE_TEXT, + HTML_FRMTYPE_GRF, + HTML_FRMTYPE_PLUGIN, + HTML_FRMTYPE_APPLET, + HTML_FRMTYPE_IFRAME, + HTML_FRMTYPE_OLE, + HTML_FRMTYPE_MARQUEE, + HTML_FRMTYPE_CONTROL, + HTML_FRMTYPE_DRAW, + HTML_FRMTYPE_END +}; + +#define HTML_OUT_TBLNODE 0x00 +#define HTML_OUT_GRFNODE 0x01 +#define HTML_OUT_OLENODE 0x02 +#define HTML_OUT_DIV 0x03 +#define HTML_OUT_MULTICOL 0x04 +#define HTML_OUT_SPACER 0x05 +#define HTML_OUT_CONTROL 0x06 +#define HTML_OUT_AMARQUEE 0x07 +#define HTML_OUT_MARQUEE 0x08 +#define HTML_OUT_GRFFRM 0x09 +#define HTML_OUT_OLEGRF 0x0a +#define HTML_OUT_SPAN 0x0b +#define HTML_OUT_MASK 0x0f + +#define HTML_POS_PREFIX 0x00 +#define HTML_POS_BEFORE 0x10 +#define HTML_POS_INSIDE 0x20 +#define HTML_POS_ANY 0x30 +#define HTML_POS_MASK 0x30 + +#define HTML_CNTNR_NONE 0x00 +#define HTML_CNTNR_SPAN 0x40 +#define HTML_CNTNR_DIV 0x80 +#define HTML_CNTNR_MASK 0xc0 + + +const sal_uInt16 MAX_FRMTYPES = HTML_FRMTYPE_END; +const sal_uInt16 MAX_BROWSERS = 4; + +extern sal_uInt8 aHTMLOutFrmPageFlyTable[MAX_FRMTYPES][MAX_BROWSERS]; +extern sal_uInt8 aHTMLOutFrmParaFrameTable[MAX_FRMTYPES][MAX_BROWSERS]; +extern sal_uInt8 aHTMLOutFrmParaPrtAreaTable[MAX_FRMTYPES][MAX_BROWSERS]; +extern sal_uInt8 aHTMLOutFrmParaOtherTable[MAX_FRMTYPES][MAX_BROWSERS]; +extern sal_uInt8 aHTMLOutFrmAsCharTable[MAX_FRMTYPES][MAX_BROWSERS]; + +class SwHTMLPosFlyFrm +{ + const SwFrmFmt *pFrmFmt; // der Rahmen + const SdrObject *pSdrObject; // ggf. Sdr-Objekt + SwNodeIndex *pNdIdx; // Node-Index + sal_uInt32 nOrdNum; // Aus SwPosFlyFrm + xub_StrLen nCntntIdx; // seine Position im Content + sal_uInt8 nOutputMode; // Ausgabe-Infos + +public: + + SwHTMLPosFlyFrm( const SwPosFlyFrm& rPosFly, + const SdrObject *pSdrObj, sal_uInt8 nOutMode ); + + sal_Bool operator==( const SwHTMLPosFlyFrm& ) const { return sal_False; } + sal_Bool operator<( const SwHTMLPosFlyFrm& ) const; + + const SwFrmFmt& GetFmt() const { return *pFrmFmt; } + const SdrObject *GetSdrObject() const { return pSdrObject; } + + const SwNodeIndex& GetNdIndex() const { return *pNdIdx; } + + xub_StrLen GetCntntIndex() const { return nCntntIdx; } + + sal_uInt8 GetOutMode() const { return nOutputMode; } + + static sal_uInt8 GetOutFn( sal_uInt8 nMode ) { return nMode & HTML_OUT_MASK; } + static sal_uInt8 GetOutPos( sal_uInt8 nMode ) { return nMode & HTML_POS_MASK; } + static sal_uInt8 GetOutCntnr( sal_uInt8 nMode ) { return nMode & HTML_CNTNR_MASK; } + + sal_uInt8 GetOutFn() const { return nOutputMode & HTML_OUT_MASK; } + sal_uInt8 GetOutPos() const { return nOutputMode & HTML_POS_MASK; } + sal_uInt8 GetOutCntnr() const { return nOutputMode & HTML_CNTNR_MASK; } +}; + +typedef SwHTMLPosFlyFrm *SwHTMLPosFlyFrmPtr; +SV_DECL_PTRARR_SORT( SwHTMLPosFlyFrms, SwHTMLPosFlyFrmPtr, 10, 10 ) + + +#endif diff --git a/sw/source/filter/html/htmlflyt.cxx b/sw/source/filter/html/htmlflyt.cxx new file mode 100644 index 000000000000..fa1f82ded113 --- /dev/null +++ b/sw/source/filter/html/htmlflyt.cxx @@ -0,0 +1,516 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include "htmlfly.hxx" + + +#define TE(t,p,c) (sal_uInt8)( HTML_OUT_##t | HTML_POS_##p | HTML_CNTNR_##c ) + +sal_uInt8 aHTMLOutFrmPageFlyTable[MAX_FRMTYPES][MAX_BROWSERS] = +{ + { + // Textrahmen mit Tabelle + TE(TBLNODE, BEFORE, NONE), // HTML 3.2 + TE(DIV, PREFIX, NONE), // IE 4 + TE(DIV, PREFIX, NONE), // SW + TE(DIV, PREFIX, NONE) // Netscape 4! + }, + { + // Textrahmen mit Tabelle und Ueberschrift + TE(TBLNODE, BEFORE, NONE), // HTML 3.2 + TE(DIV, PREFIX, NONE), // IE 4 + TE(DIV, PREFIX, NONE), // SW + TE(DIV, PREFIX, NONE) // Netscape 4 + }, + { + // spaltiger Rahmen + TE(GRFFRM, INSIDE, NONE), // HTML 3.2 + TE(GRFFRM, PREFIX, NONE), // IE 4 + TE(MULTICOL,PREFIX, NONE), // SW + TE(MULTICOL,PREFIX, DIV) // Netscape 4 + }, + { + // leerer Textreahmen + TE(GRFFRM, INSIDE, NONE), // HTML 3.2 + TE(DIV, PREFIX, NONE), // IE 4 + TE(DIV, PREFIX, NONE), // SW + TE(DIV, PREFIX, NONE) // Netscape 4 + }, + { + // sonstiger Textreahmen + TE(GRFFRM, INSIDE, NONE), // HTML 3.2 + TE(DIV, PREFIX, NONE), // IE 4 + TE(DIV, PREFIX, NONE), // SW + TE(DIV, PREFIX, NONE) // Netscape 4 + }, + { + // Grafik-Node + TE(GRFNODE, INSIDE, NONE), // HTML 3.2 + TE(GRFNODE, PREFIX, NONE), // IE 4 + TE(GRFNODE, PREFIX, NONE), // SW + TE(GRFNODE, PREFIX, SPAN) // Netscape 4 + }, + { + // Plugin + TE(OLENODE, INSIDE, NONE), // HTML 3.2 + TE(OLENODE, PREFIX, NONE), // IE 4 + TE(OLENODE, PREFIX, NONE), // SW + TE(OLENODE, PREFIX, SPAN) // Netscape 4 + }, + { + // Applet + TE(OLENODE, INSIDE, NONE), // HTML 3.2 + TE(OLENODE, PREFIX, NONE), // IE 4 + TE(OLENODE, PREFIX, NONE), // SW + TE(OLENODE, PREFIX, SPAN) // Netscape 4 + }, + { + // Floating-Frame + TE(OLEGRF, INSIDE, NONE), // HTML 3.2 + TE(OLENODE, PREFIX, NONE), // IE 4 + TE(OLENODE, PREFIX, NONE), // SW + TE(OLEGRF, PREFIX, SPAN) // Netscape 4 + }, + { + // sonstige OLE-Objekte + TE(OLEGRF, INSIDE, NONE), // HTML 3.2 + TE(OLEGRF, PREFIX, NONE), // IE 4 + TE(OLEGRF, PREFIX, NONE), // SW + TE(OLEGRF, PREFIX, SPAN) // Netscape 4 + }, + { + // Laufschrift + TE(GRFFRM, INSIDE, NONE), // HTML 3.2 + TE(AMARQUEE,PREFIX, NONE), // IE 4 + TE(AMARQUEE,PREFIX, NONE), // SW + TE(GRFFRM, PREFIX, SPAN) // Netscape 4 + }, + { + // Controls + TE(CONTROL, INSIDE, NONE), // HTML 3.2 + TE(CONTROL, PREFIX, NONE), // IE 4 + TE(CONTROL, PREFIX, NONE), // SW + // Netscape schaltet FORM bei Controls in abs.-pos. SPAN aus. + TE(CONTROL, INSIDE, NONE) // Netscape 4 + }, + { + // sonstige Zeichen-Objekte + TE(GRFFRM, INSIDE, NONE), // HTML 3.2 + TE(GRFFRM, PREFIX, NONE), // IE 4 + TE(GRFFRM, PREFIX, NONE), // SW + TE(GRFFRM, PREFIX, SPAN) // Netscape 4 + } +}; + +sal_uInt8 aHTMLOutFrmParaFrameTable[MAX_FRMTYPES][MAX_BROWSERS] = +{ + { + // Textrahmen mit Tabelle + TE(TBLNODE, BEFORE, NONE), // HTML 3.2 + TE(TBLNODE, BEFORE, NONE), // IE 4 + TE(TBLNODE, BEFORE, NONE), // SW + TE(TBLNODE, BEFORE, NONE) // Netscape 4 + }, + { + // Textrahmen mit Tabelle und Ueberschrift + TE(TBLNODE, BEFORE, NONE), // HTML 3.2 + TE(DIV, BEFORE, NONE), // IE 4 + TE(DIV, BEFORE, NONE), // SW + TE(TBLNODE, BEFORE, NONE) // Netscape 4 + }, + { + // spaltiger Rahmen + TE(GRFFRM, BEFORE, NONE), // HTML 3.2 + TE(GRFFRM, BEFORE, NONE), // IE 4 + TE(MULTICOL,BEFORE, NONE), // SW + TE(MULTICOL,BEFORE, DIV) // Netscape 4 + }, + { + // leerer Textreahmen + TE(GRFFRM, BEFORE, NONE), // HTML 3.2 + TE(DIV, BEFORE, NONE), // IE 4 + TE(SPACER, BEFORE, NONE), // SW + TE(SPACER, BEFORE, NONE) // Netscape 4 + }, + { + // sonstiger Textreahmen + TE(GRFFRM, BEFORE, NONE), // HTML 3.2 + TE(DIV, BEFORE, NONE), // IE 4 + TE(DIV, BEFORE, NONE), // SW + TE(DIV, BEFORE, NONE) // Netscape 4 + }, + { + // Grafik-Node + TE(GRFNODE, BEFORE, NONE), // HTML 3.2 + TE(GRFNODE, BEFORE, NONE), // IE 4 + TE(GRFNODE, BEFORE, NONE), // SW + TE(GRFNODE, BEFORE, NONE) // Netscape 4 + }, + { + // Plugin + TE(OLENODE, BEFORE, NONE), // HTML 3.2 + TE(OLENODE, BEFORE, NONE), // IE 4 + TE(OLENODE, BEFORE, NONE), // SW + TE(OLENODE, BEFORE, NONE) // Netscape 4 + }, + { + // Applet + TE(OLENODE, BEFORE, NONE), // HTML 3.2 + TE(OLENODE, BEFORE, NONE), // IE 4 + TE(OLENODE, BEFORE, NONE), // SW + TE(OLENODE, BEFORE, NONE) // Netscape 4 + }, + { + // Floating-Frame + TE(OLEGRF, BEFORE, NONE), // HTML 3.2 + TE(OLENODE, BEFORE, NONE), // IE 4 + TE(OLENODE, BEFORE, NONE), // SW + TE(OLEGRF, BEFORE, NONE) // Netscape 4 + }, + { + // sonstige OLE-Objekte + TE(OLEGRF, BEFORE, NONE), // HTML 3.2 + TE(OLEGRF, BEFORE, NONE), // IE 4 + TE(OLEGRF, BEFORE, NONE), // SW + TE(OLEGRF, BEFORE, NONE) // Netscape 4 + }, + { + // Laufschrift (fuer Netscape 4 im Container, damit + // die LAufschrift an der richtigen Stelle erscheint + TE(GRFFRM, BEFORE, NONE), // HTML 3.2 + TE(AMARQUEE,BEFORE, NONE), // IE 4 + TE(AMARQUEE,BEFORE, NONE), // SW + TE(GRFFRM, BEFORE, NONE) // Netscape 4 + }, + { + // Controls + TE(CONTROL, INSIDE, NONE), // HTML 3.2 + TE(CONTROL, BEFORE, NONE), // IE 4 + TE(CONTROL, BEFORE, NONE), // SW + // hier koennte man einen Container draus machen (Import fehlt) + TE(CONTROL, BEFORE, NONE) // Netscape 4 + }, + { + // sonstige Zeichen-Objekte + TE(GRFFRM, BEFORE, NONE), // HTML 3.2 + TE(GRFFRM, BEFORE, NONE), // IE 4 + TE(GRFFRM, BEFORE, NONE), // SW + TE(GRFFRM, BEFORE, NONE) // Netscape 4 + } +}; + +sal_uInt8 aHTMLOutFrmParaPrtAreaTable[MAX_FRMTYPES][MAX_BROWSERS] = +{ + { + // Textrahmen mit Tabelle + TE(TBLNODE, INSIDE, NONE), // HTML 3.2 + TE(TBLNODE, INSIDE, NONE), // IE 4 + TE(TBLNODE, INSIDE, NONE), // SW + TE(TBLNODE, INSIDE, NONE) // Netscape 4 + }, + { + // Textrahmen mit Tabelle und Ueberschrift + TE(TBLNODE, INSIDE, NONE), // HTML 3.2 + TE(SPAN, INSIDE, NONE), // IE 4 + TE(SPAN, INSIDE, NONE), // SW + TE(SPAN, INSIDE, NONE) // Netscape 4 + }, + { + // spaltiger Rahmen + TE(GRFFRM, INSIDE, NONE), // HTML 3.2 + TE(GRFFRM, INSIDE, NONE), // IE 4 + TE(MULTICOL,INSIDE, NONE), // SW + TE(MULTICOL,INSIDE, SPAN) // Netscape 4 + }, + { + // leerer Textreahmen + TE(GRFFRM, INSIDE, NONE), // HTML 3.2 + TE(SPAN, INSIDE, NONE), // IE 4 + TE(SPACER, INSIDE, NONE), // SW + TE(SPACER, INSIDE, NONE) // Netscape 4 + }, + { + // sonstiger Textreahmen + TE(GRFFRM, INSIDE, NONE), // HTML 3.2 + TE(SPAN, INSIDE, NONE), // IE 4 + TE(SPAN, INSIDE, NONE), // SW + TE(SPAN, INSIDE, NONE) // Netscape 4 + }, + { + // Grafik-Node + TE(GRFNODE, INSIDE, NONE), // HTML 3.2 + TE(GRFNODE, INSIDE, NONE), // IE 4 + TE(GRFNODE, INSIDE, NONE), // SW + TE(GRFNODE, INSIDE, NONE) // Netscape 4 + }, + { + // Plugin + TE(OLENODE, INSIDE, NONE), // HTML 3.2 + TE(OLENODE, INSIDE, NONE), // IE 4 + TE(OLENODE, INSIDE, NONE), // SW + TE(OLENODE, INSIDE, NONE) // Netscape 4 + }, + { + // Applet + TE(OLENODE, INSIDE, NONE), // HTML 3.2 + TE(OLENODE, INSIDE, NONE), // IE 4 + TE(OLENODE, INSIDE, NONE), // SW + TE(OLENODE, INSIDE, NONE) // Netscape 4 + }, + { + // Floating-Frame + TE(OLEGRF, INSIDE, NONE), // HTML 3.2 + TE(OLENODE, INSIDE, NONE), // IE 4 + TE(OLENODE, INSIDE, NONE), // SW + TE(OLEGRF, INSIDE, NONE) // Netscape 4 + }, + { + // sonstige OLE-Objekte + TE(OLEGRF, INSIDE, NONE), // HTML 3.2 + TE(OLEGRF, INSIDE, NONE), // IE 4 + TE(OLEGRF, INSIDE, NONE), // SW + TE(OLEGRF, INSIDE, NONE) // Netscape 4 + }, + { + // Laufschrift + TE(GRFFRM, INSIDE, NONE), // HTML 3.2 + TE(AMARQUEE,INSIDE, NONE), // IE 4 + TE(AMARQUEE,INSIDE, NONE), // SW + TE(GRFFRM, INSIDE, NONE) // Netscape 4 + }, + { + // Controls + TE(CONTROL, INSIDE, NONE), // HTML 3.2 + TE(CONTROL, INSIDE, NONE), // IE 4 + TE(CONTROL, INSIDE, NONE), // SW + // hier koennte man einen Container draus machen (Import fehlt) + TE(CONTROL, INSIDE, NONE) // Netscape 4 + }, + { + // sonstige Zeichen-Objekte + TE(GRFFRM, INSIDE, NONE), // HTML 3.2 + TE(GRFFRM, INSIDE, NONE), // IE 4 + TE(GRFFRM, INSIDE, NONE), // SW + TE(GRFFRM, INSIDE, NONE) // Netscape 4 + } +}; + +sal_uInt8 aHTMLOutFrmParaOtherTable[MAX_FRMTYPES][MAX_BROWSERS] = +{ + { + // Textrahmen mit Tabelle + TE(TBLNODE, BEFORE, NONE), // HTML 3.2 + TE(SPAN, INSIDE, NONE), // IE 4 + TE(SPAN, INSIDE, NONE), // SW + TE(SPAN, INSIDE, NONE) // Netscape 4 + }, + { + // Textrahmen mit Tabelle und Ueberschrift + TE(TBLNODE, BEFORE, NONE), // HTML 3.2 + TE(SPAN, INSIDE, NONE), // IE 4 + TE(SPAN, INSIDE, NONE), // SW + TE(SPAN, INSIDE, NONE) // Netscape 4 + }, + { + // spaltiger Rahmen + TE(GRFFRM, INSIDE, NONE), // HTML 3.2 + TE(GRFFRM, INSIDE, NONE), // IE 4 + TE(MULTICOL,INSIDE, NONE), // SW + TE(MULTICOL,INSIDE, SPAN) // Netscape 4 + }, + { + // leerer Textreahmen + TE(GRFFRM, INSIDE, NONE), // HTML 3.2 + TE(SPAN, INSIDE, NONE), // IE 4 + TE(SPAN, INSIDE, NONE), // SW + TE(SPAN, INSIDE, NONE) // Netscape 4 + }, + { + // sonstiger Textreahmen + TE(GRFFRM, INSIDE, NONE), // HTML 3.2 + TE(SPAN, INSIDE, NONE), // IE 4 + TE(SPAN, INSIDE, NONE), // SW + TE(SPAN, INSIDE, NONE) // Netscape 4 + }, + { + // Grafik-Node + TE(GRFNODE, INSIDE, NONE), // HTML 3.2 + TE(GRFNODE, INSIDE, NONE), // IE 4 + TE(GRFNODE, INSIDE, NONE), // SW + TE(GRFNODE, INSIDE, SPAN) // Netscape 4 + }, + { + // Plugin + TE(OLENODE, INSIDE, NONE), // HTML 3.2 + TE(OLENODE, INSIDE, NONE), // IE 4 + TE(OLENODE, INSIDE, NONE), // SW + TE(OLENODE, INSIDE, SPAN) // Netscape 4 + }, + { + // Applet + TE(OLENODE, INSIDE, NONE), // HTML 3.2 + TE(OLENODE, INSIDE, NONE), // IE 4 + TE(OLENODE, INSIDE, NONE), // SW + TE(OLENODE, INSIDE, SPAN) // Netscape 4 + }, + { + // Floating-Frame + TE(OLEGRF, INSIDE, NONE), // HTML 3.2 + TE(OLENODE, INSIDE, NONE), // IE 4 + TE(OLENODE, INSIDE, NONE), // SW + TE(OLEGRF, INSIDE, SPAN) // Netscape 4 + }, + { + // sonstige OLE-Objekte + TE(OLEGRF, INSIDE, NONE), // HTML 3.2 + TE(OLEGRF, INSIDE, NONE), // IE 4 + TE(OLEGRF, INSIDE, NONE), // SW + TE(OLEGRF, INSIDE, SPAN) // Netscape 4 + }, + { + // Laufschrift + TE(GRFFRM, INSIDE, NONE), // HTML 3.2 + TE(AMARQUEE,INSIDE, NONE), // IE 4 + TE(AMARQUEE,INSIDE, NONE), // SW + TE(GRFFRM, INSIDE, SPAN) // Netscape 4 + }, + { + // Controls + TE(CONTROL, INSIDE, NONE), // HTML 3.2 + TE(CONTROL, INSIDE, NONE), // IE 4 + TE(CONTROL, INSIDE, NONE), // SW + // Netscape schaltet FORM bei Controls in abs.-pos. SPAN aus. + TE(CONTROL, INSIDE, NONE) // Netscape 4 + }, + { + // sonstige Zeichen-Objekte + TE(GRFFRM, INSIDE, NONE), // HTML 3.2 + TE(GRFFRM, INSIDE, NONE), // IE 4 + TE(GRFFRM, INSIDE, NONE), // SW + TE(GRFFRM, INSIDE, SPAN) // Netscape 4 + } +}; + +sal_uInt8 aHTMLOutFrmAsCharTable[MAX_FRMTYPES][MAX_BROWSERS] = +{ + { + // Textrahmen mit Tabelle + TE(GRFFRM, INSIDE, NONE), // HTML 3.2 + TE(GRFFRM, INSIDE, NONE), // IE 4 + TE(GRFFRM, INSIDE, NONE), // SW + TE(GRFFRM, INSIDE, NONE) // Netscape 4 + }, + { + // Textrahmen mit Tabelle und Ueberschrift + TE(GRFFRM, INSIDE, NONE), // HTML 3.2 + TE(GRFFRM, INSIDE, NONE), // IE 4 + TE(GRFFRM, INSIDE, NONE), // SW + TE(GRFFRM, INSIDE, NONE) // Netscape 4 + }, + { + // spaltiger Rahmen + TE(GRFFRM, INSIDE, NONE), // HTML 3.2 + TE(GRFFRM, INSIDE, NONE), // IE 4 + TE(MULTICOL,INSIDE, NONE), // SW + TE(MULTICOL,INSIDE, NONE) // Netscape 4 + }, + { + // leerer Textreahmen + TE(GRFFRM, INSIDE, NONE), // HTML 3.2 + TE(GRFFRM, INSIDE, NONE), // IE 4 + TE(SPACER, INSIDE, NONE), // SW + TE(SPACER, INSIDE, NONE) // Netscape 4 + }, + { + // sonstiger Textreahmen + TE(GRFFRM, INSIDE, NONE), // HTML 3.2 + TE(GRFFRM, INSIDE, NONE), // IE 4 + TE(GRFFRM, INSIDE, NONE), // SW + TE(GRFFRM, INSIDE, NONE) // Netscape 4 + }, + { + // Grafik-Node + TE(GRFNODE, INSIDE, NONE), // HTML 3.2 + TE(GRFNODE, INSIDE, NONE), // IE 4 + TE(GRFNODE, INSIDE, NONE), // SW + TE(GRFNODE, INSIDE, NONE) // Netscape 4 + }, + { + // Plugin + TE(OLENODE, INSIDE, NONE), // HTML 3.2 + TE(OLENODE, INSIDE, NONE), // IE 4 + TE(OLENODE, INSIDE, NONE), // SW + TE(OLENODE, INSIDE, NONE) // Netscape 4 + }, + { + // Applet + TE(OLENODE, INSIDE, NONE), // HTML 3.2 + TE(OLENODE, INSIDE, NONE), // IE 4 + TE(OLENODE, INSIDE, NONE), // SW + TE(OLENODE, INSIDE, NONE) // Netscape 4 + }, + { + // Floating-Frame + TE(OLEGRF, INSIDE, NONE), // HTML 3.2 + TE(OLENODE, INSIDE, NONE), // IE 4 + TE(OLENODE, INSIDE, NONE), // SW + TE(OLEGRF, INSIDE, NONE) // Netscape 4 + }, + { + // sonstige OLE-Objekte + TE(OLEGRF, INSIDE, NONE), // HTML 3.2 + TE(OLEGRF, INSIDE, NONE), // IE 4 + TE(OLEGRF, INSIDE, NONE), // SW + TE(OLEGRF, INSIDE, NONE) // Netscape 4 + }, + { + // Laufschrift (kann immer als MARQUEE exportiert werden, weil + // der Inhalt an der richtigen Stelle erscheint + TE(MARQUEE, INSIDE, NONE), // HTML 3.2 + TE(MARQUEE, INSIDE, NONE), // IE 4 + TE(MARQUEE, INSIDE, NONE), // SW + TE(MARQUEE, INSIDE, NONE) // Netscape 4 + }, + { + // Controls + TE(CONTROL, INSIDE, NONE), // HTML 3.2 + TE(CONTROL, INSIDE, NONE), // IE 4 + TE(CONTROL, INSIDE, NONE), // SW + TE(CONTROL, INSIDE, NONE) // Netscape 4 + }, + { + // sonstige Zeichen-Objekte + TE(GRFFRM, INSIDE, NONE), // HTML 3.2 + TE(GRFFRM, INSIDE, NONE), // IE 4 + TE(GRFFRM, INSIDE, NONE), // SW + TE(GRFFRM, INSIDE, NONE) // Netscape 4 + } +}; + diff --git a/sw/source/filter/html/htmlform.cxx b/sw/source/filter/html/htmlform.cxx new file mode 100644 index 000000000000..d3a92cf01b85 --- /dev/null +++ b/sw/source/filter/html/htmlform.cxx @@ -0,0 +1,2661 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <hintids.hxx> +#include <vcl/svapp.hxx> +#include <vcl/wrkwin.hxx> + +#include <toolkit/helper/vclunohelper.hxx> +#include <svtools/htmlkywd.hxx> +#include <svtools/htmltokn.h> +#include <svl/urihelper.hxx> +#include <sfx2/request.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/viewfrm.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/brshitem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/crsditem.hxx> +#include <svx/svdouno.hxx> +#include <svx/fmglob.hxx> +#include <com/sun/star/form/ListSourceType.hpp> +#include <com/sun/star/form/FormButtonType.hpp> +#include <com/sun/star/form/FormSubmitEncoding.hpp> +#include <com/sun/star/form/FormSubmitMethod.hpp> +#include <com/sun/star/drawing/XDrawPageSupplier.hpp> +#include <com/sun/star/script/XEventAttacherManager.hpp> +#include <com/sun/star/text/WrapTextMode.hpp> +#include <com/sun/star/text/HoriOrientation.hpp> +#include <com/sun/star/text/VertOrientation.hpp> +#include <com/sun/star/text/TextContentAnchorType.hpp> +#include <com/sun/star/container/XIndexContainer.hpp> +#include <com/sun/star/drawing/XControlShape.hpp> +#include <com/sun/star/awt/XTextLayoutConstrains.hpp> +#include <com/sun/star/awt/XLayoutConstrains.hpp> +#include <com/sun/star/awt/XImageConsumer.hpp> +#include <com/sun/star/awt/ImageStatus.hpp> +#include <com/sun/star/form/XImageProducerSupplier.hpp> +#include <com/sun/star/form/XForm.hpp> +#include <doc.hxx> +#include <pam.hxx> +#include <swtable.hxx> +#include <fmtanchr.hxx> +#include <htmltbl.hxx> +#include <docsh.hxx> +#include <viewsh.hxx> +#include <unodraw.hxx> +#include <unotextrange.hxx> +#include "dcontact.hxx" + +#include "swcss1.hxx" +#include "swhtml.hxx" +#include "htmlform.hxx" + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::form; +using ::rtl::OUString; + +const sal_uInt16 TABINDEX_MIN = 0; +const sal_uInt16 TABINDEX_MAX = 32767; + +static HTMLOptionEnum __FAR_DATA aHTMLFormMethodTable[] = +{ + { OOO_STRING_SVTOOLS_HTML_METHOD_get, FormSubmitMethod_GET }, + { OOO_STRING_SVTOOLS_HTML_METHOD_post, FormSubmitMethod_POST }, + { 0, 0 } +}; + +static HTMLOptionEnum __FAR_DATA aHTMLFormEncTypeTable[] = +{ + { OOO_STRING_SVTOOLS_HTML_ET_url, FormSubmitEncoding_URL }, + { OOO_STRING_SVTOOLS_HTML_ET_multipart, FormSubmitEncoding_MULTIPART }, + { OOO_STRING_SVTOOLS_HTML_ET_text, FormSubmitEncoding_TEXT }, + { 0, 0 } +}; + +enum HTMLWordWrapMode { HTML_WM_OFF, HTML_WM_HARD, HTML_WM_SOFT }; + +static HTMLOptionEnum __FAR_DATA aHTMLTextAreaWrapTable[] = +{ + { OOO_STRING_SVTOOLS_HTML_WW_off, HTML_WM_OFF }, + { OOO_STRING_SVTOOLS_HTML_WW_hard, HTML_WM_HARD }, + { OOO_STRING_SVTOOLS_HTML_WW_soft, HTML_WM_SOFT }, + { OOO_STRING_SVTOOLS_HTML_WW_physical,HTML_WM_HARD }, + { OOO_STRING_SVTOOLS_HTML_WW_virtual, HTML_WM_SOFT }, + { 0, 0 } +}; + +HTMLEventType __FAR_DATA aEventTypeTable[] = +{ + HTML_ET_ONSUBMITFORM, + HTML_ET_ONRESETFORM, + HTML_ET_ONGETFOCUS, + HTML_ET_ONLOSEFOCUS, + HTML_ET_ONCLICK, + HTML_ET_ONCLICK_ITEM, + HTML_ET_ONCHANGE, + HTML_ET_ONSELECT, + HTML_ET_END +}; + +const sal_Char * __FAR_DATA aEventListenerTable[] = +{ + "XSubmitListener", + "XResetListener", + "XFocusListener", + "XFocusListener", + "XApproveActionListener", + "XItemListener", + "XChangeListener", + "" +}; + +const sal_Char * __FAR_DATA aEventMethodTable[] = +{ + "approveSubmit", + "approveReset", + "focusGained", + "focusLost", + "approveAction", + "itemStateChanged", + "changed", + "" +}; + +const sal_Char * __FAR_DATA aEventSDOptionTable[] = +{ + OOO_STRING_SVTOOLS_HTML_O_SDonsubmit, + OOO_STRING_SVTOOLS_HTML_O_SDonreset, + OOO_STRING_SVTOOLS_HTML_O_SDonfocus, + OOO_STRING_SVTOOLS_HTML_O_SDonblur, + OOO_STRING_SVTOOLS_HTML_O_SDonclick, + OOO_STRING_SVTOOLS_HTML_O_SDonclick, + OOO_STRING_SVTOOLS_HTML_O_SDonchange, + 0 +}; + +const sal_Char * __FAR_DATA aEventOptionTable[] = +{ + OOO_STRING_SVTOOLS_HTML_O_onsubmit, + OOO_STRING_SVTOOLS_HTML_O_onreset, + OOO_STRING_SVTOOLS_HTML_O_onfocus, + OOO_STRING_SVTOOLS_HTML_O_onblur, + OOO_STRING_SVTOOLS_HTML_O_onclick, + OOO_STRING_SVTOOLS_HTML_O_onclick, + OOO_STRING_SVTOOLS_HTML_O_onchange, + 0 +}; + +/* */ + +class SwHTMLForm_Impl +{ + SwDocShell *pDocSh; + + SvKeyValueIterator *pHeaderAttrs; + + // gecachte Interfaces + uno::Reference< drawing::XDrawPage > xDrawPage; + uno::Reference< container::XIndexContainer > xForms; + uno::Reference< drawing::XShapes > xShapes; + uno::Reference< XMultiServiceFactory > xServiceFactory; + + uno::Reference< script::XEventAttacherManager > xControlEventManager; + uno::Reference< script::XEventAttacherManager > xFormEventManager; + + // Kontext-Informationen + uno::Reference< container::XIndexContainer > xFormComps; + uno::Reference< beans::XPropertySet > xFCompPropSet; + uno::Reference< drawing::XShape > xShape; + + String sText; + SvStringsDtor aStringList; + SvStringsDtor aValueList; + SvUShorts aSelectedList; + +public: + + SwHTMLForm_Impl( SwDocShell *pDSh ) : + pDocSh( pDSh ), + pHeaderAttrs( pDSh ? pDSh->GetHeaderAttributes() : 0 ) + { + ASSERT( pDocSh, "Keine DocShell, keine Controls" ); + } + + const uno::Reference< XMultiServiceFactory >& GetServiceFactory(); + const uno::Reference< drawing::XDrawPage >& GetDrawPage(); + const uno::Reference< drawing::XShapes >& GetShapes(); + const uno::Reference< script::XEventAttacherManager >& GetControlEventManager(); + const uno::Reference< script::XEventAttacherManager >& GetFormEventManager(); + const uno::Reference< container::XIndexContainer >& GetForms(); + + const uno::Reference< container::XIndexContainer >& GetFormComps() const + { + return xFormComps; + } + + void SetFormComps( const uno::Reference< container::XIndexContainer >& r ) + { + xFormComps = r; + } + + void ReleaseFormComps() { xFormComps = 0; xControlEventManager = 0; } + + const uno::Reference< beans::XPropertySet >& GetFCompPropSet() const + { + return xFCompPropSet; + } + + void SetFCompPropSet( const uno::Reference< beans::XPropertySet >& r ) + { + xFCompPropSet = r; + } + + void ReleaseFCompPropSet() { xFCompPropSet = 0; } + + const uno::Reference< drawing::XShape >& GetShape() const { return xShape; } + void SetShape( const uno::Reference< drawing::XShape >& r ) { xShape = r; } + void ReleaseShape() { xShape = 0; } + + String& GetText() { return sText; } + void EraseText() { sText = aEmptyStr; } + + SvStringsDtor& GetStringList() { return aStringList; } + void EraseStringList() + { + aStringList.DeleteAndDestroy( 0, aStringList.Count() ); + } + + SvStringsDtor& GetValueList() { return aValueList; } + void EraseValueList() + { + aValueList.DeleteAndDestroy( 0, aValueList.Count() ); + } + + SvUShorts& GetSelectedList() { return aSelectedList; } + void EraseSelectedList() + { + aSelectedList.Remove( 0, aSelectedList.Count() ); + } + + SvKeyValueIterator *GetHeaderAttrs() const { return pHeaderAttrs; } +}; + +const uno::Reference< XMultiServiceFactory >& SwHTMLForm_Impl::GetServiceFactory() +{ + if( !xServiceFactory.is() && pDocSh ) + { + xServiceFactory = + uno::Reference< XMultiServiceFactory >( pDocSh->GetBaseModel(), + UNO_QUERY ); + ASSERT( xServiceFactory.is(), + "XServiceFactory nicht vom Model erhalten" ); + } + return xServiceFactory; +} + + +const uno::Reference< drawing::XDrawPage >& SwHTMLForm_Impl::GetDrawPage() +{ + if( !xDrawPage.is() && pDocSh ) + { + uno::Reference< drawing::XDrawPageSupplier > xTxtDoc( pDocSh->GetBaseModel(), + UNO_QUERY ); + ASSERT( xTxtDoc.is(), + "drawing::XDrawPageSupplier nicht vom XModel erhalten" ); + xDrawPage = xTxtDoc->getDrawPage(); + ASSERT( xDrawPage.is(), "drawing::XDrawPage nicht erhalten" ); + } + return xDrawPage; +} + +const uno::Reference< container::XIndexContainer >& SwHTMLForm_Impl::GetForms() +{ + if( !xForms.is() ) + { + GetDrawPage(); + if( xDrawPage.is() ) + { + uno::Reference< XFormsSupplier > xFormsSupplier( xDrawPage, UNO_QUERY ); + ASSERT( xFormsSupplier.is(), + "XFormsSupplier nicht vom drawing::XDrawPage erhalten" ); + + uno::Reference< container::XNameContainer > xNameCont = + xFormsSupplier->getForms(); + xForms = uno::Reference< container::XIndexContainer >( xNameCont, + UNO_QUERY ); + + ASSERT( xForms.is(), "XForms nicht erhalten" ); + } + } + return xForms; +} + + +const uno::Reference< drawing::XShapes > & SwHTMLForm_Impl::GetShapes() +{ + if( !xShapes.is() ) + { + GetDrawPage(); + if( xDrawPage.is() ) + { + xShapes = uno::Reference< drawing::XShapes >( xDrawPage, UNO_QUERY ); + ASSERT( xShapes.is(), + "XShapes nicht vom drawing::XDrawPage erhalten" ); + } + } + return xShapes; +} + +const uno::Reference< script::XEventAttacherManager >& + SwHTMLForm_Impl::GetControlEventManager() +{ + if( !xControlEventManager.is() && xFormComps.is() ) + { + xControlEventManager = + uno::Reference< script::XEventAttacherManager >( xFormComps, UNO_QUERY ); + ASSERT( xControlEventManager.is(), + "uno::Reference< XEventAttacherManager > nicht von xFormComps erhalten" ); + } + + return xControlEventManager; +} + +const uno::Reference< script::XEventAttacherManager >& + SwHTMLForm_Impl::GetFormEventManager() +{ + if( !xFormEventManager.is() ) + { + GetForms(); + if( xForms.is() ) + { + xFormEventManager = + uno::Reference< script::XEventAttacherManager >( xForms, UNO_QUERY ); + ASSERT( xFormEventManager.is(), + "uno::Reference< XEventAttacherManager > nicht von xForms erhalten" ); + } + } + + return xFormEventManager; +} + +class SwHTMLImageWatcher : + public cppu::WeakImplHelper2< awt::XImageConsumer, XEventListener > +{ + uno::Reference< drawing::XShape > xShape; // das control + uno::Reference< XImageProducerSupplier > xSrc; + uno::Reference< awt::XImageConsumer > xThis; // man selbst + sal_Bool bSetWidth; + sal_Bool bSetHeight; + + void clear(); + +public: + + SwHTMLImageWatcher( const uno::Reference< drawing::XShape > & rShape, + sal_Bool bWidth, sal_Bool bHeight ); + ~SwHTMLImageWatcher(); + + // startProduction darf nicht im Konstruktor gerufen werden, weil + // wir und ggf. selbst zerstoeren ... Deshlab eine eigene Methode. + void start() { xSrc->getImageProducer()->startProduction(); } + + // UNO Anbindung + + // XImageConsumer + virtual void SAL_CALL init( sal_Int32 Width, sal_Int32 Height) + throw( uno::RuntimeException ); + virtual void SAL_CALL setColorModel( + sal_Int16 BitCount, const uno::Sequence< sal_Int32 >& RGBAPal, + sal_Int32 RedMask, sal_Int32 GreenMask, sal_Int32 BlueMask, + sal_Int32 AlphaMask) + throw( uno::RuntimeException ); + virtual void SAL_CALL setPixelsByBytes( + sal_Int32 X, sal_Int32 Y, sal_Int32 Width, sal_Int32 Height, + const uno::Sequence< sal_Int8 >& ProducerData, + sal_Int32 Offset, sal_Int32 Scansize) + throw( uno::RuntimeException ); + virtual void SAL_CALL setPixelsByLongs( + sal_Int32 X, sal_Int32 Y, sal_Int32 Width, sal_Int32 Height, + const uno::Sequence< sal_Int32 >& ProducerData, + sal_Int32 Offset, sal_Int32 Scansize) + throw( uno::RuntimeException ); + virtual void SAL_CALL complete( + sal_Int32 Status, + const uno::Reference< awt::XImageProducer > & Producer) + throw( uno::RuntimeException ); + + // XEventListener + virtual void SAL_CALL disposing( const EventObject& Source ) throw ( uno::RuntimeException); +}; + +SwHTMLImageWatcher::SwHTMLImageWatcher( + const uno::Reference< drawing::XShape >& rShape, + sal_Bool bWidth, sal_Bool bHeight ) : + xShape( rShape ), + bSetWidth( bWidth ), bSetHeight( bHeight ) +{ + // Die Quelle des Images merken + uno::Reference< drawing::XControlShape > xControlShape( xShape, UNO_QUERY ); + uno::Reference< awt::XControlModel > xControlModel( + xControlShape->getControl() ); + xSrc = uno::Reference< XImageProducerSupplier >( xControlModel, UNO_QUERY ); + ASSERT( xSrc.is(), "Kein XImageProducerSupplier" ); + + // Als Event-Listener am Shape anmelden, damit wir es beim dispose + // loslassen ko”nnen ... + uno::Reference< XEventListener > xEvtLstnr = (XEventListener *)this; + uno::Reference< XComponent > xComp( xShape, UNO_QUERY ); + xComp->addEventListener( xEvtLstnr ); + + // Zum Schluss halten wir noch eine Referenz auf uns selbst, damit + // wir am Leben bleiben ... (eigentlich sollte das nicht neotig sein, + // weil wir ja noch an diversen anderen Stellen angemeldet sind) + xThis = (awt::XImageConsumer *)this; + + // und am ImageProducer anmelden, um die Groesse zu erehalten ... + xSrc->getImageProducer()->addConsumer( xThis ); +} + +SwHTMLImageWatcher::~SwHTMLImageWatcher() +{ +} + +void SwHTMLImageWatcher::clear() +{ + // Am Shape als Event-Listener abmelden + uno::Reference< XEventListener > xEvtLstnr = (XEventListener *)this; + uno::Reference< XComponent > xComp( xShape, UNO_QUERY ); + xComp->removeEventListener( xEvtLstnr ); + + // Am ImageProducer abmelden + uno::Reference<awt::XImageProducer> xProd = xSrc->getImageProducer(); + if( xProd.is() ) + xProd->removeConsumer( xThis ); +} + +//------------------------------------------------------------------------------ + +void SwHTMLImageWatcher::init( sal_Int32 Width, sal_Int32 Height ) + throw( uno::RuntimeException ) +{ + ASSERT( bSetWidth || bSetHeight, + "Breite oder Hoehe muss angepasst werden" ); + + // Wenn keine Breite oder Hoehe angegeben ist, ist das das init von + // der leeren Grafik, die angezeigt wird, bevor der Stream einer + // asynchron anzuzeigenden Grfik verfuegbar ist. + if( !Width && !Height ) + return; + + awt::Size aNewSz; + aNewSz.Width = Width; + aNewSz.Height = Height; + if( Application::GetDefaultDevice() ) + { + Size aTmp(aNewSz.Width, aNewSz.Height); + aTmp = Application::GetDefaultDevice() + ->PixelToLogic( aTmp, MapMode( MAP_100TH_MM ) ); + aNewSz.Width = aTmp.Width(); + aNewSz.Height = aTmp.Height(); + } + + if( !bSetWidth || !bSetHeight ) + { + awt::Size aSz( xShape->getSize() ); + if( bSetWidth && aNewSz.Height ) + { + aNewSz.Width *= aSz.Height; + aNewSz.Width /= aNewSz.Height; + aNewSz.Height = aSz.Height; + } + if( bSetHeight && aNewSz.Width ) + { + aNewSz.Height *= aSz.Width; + aNewSz.Height /= aNewSz.Width; + aNewSz.Width = aSz.Width; + } + } + if( aNewSz.Width < MINFLY ) + aNewSz.Width = MINFLY; + if( aNewSz.Height < MINFLY ) + aNewSz.Height = MINFLY; + + xShape->setSize( aNewSz ); + if( bSetWidth ) + { + // Wenn das Control in einer Tabelle verankert ist, muesen + // die Tabellen-Spalten neu berechnet werden + + // Um an den SwXShape* zu gelangen, brauchen wir ein Interface, + // das auch vom SwXShape implementiert wird. + + uno::Reference< beans::XPropertySet > xPropSet( xShape, UNO_QUERY ); + uno::Reference< XUnoTunnel> xTunnel( xPropSet, UNO_QUERY ); + SwXShape *pSwShape = xTunnel.is() ? + reinterpret_cast< SwXShape * >( sal::static_int_cast< sal_IntPtr>( + xTunnel->getSomething(SwXShape::getUnoTunnelId()) )) + : 0; + + ASSERT( pSwShape, "Wo ist das SW-Shape?" ); + if( pSwShape ) + { + SwFrmFmt *pFrmFmt = pSwShape->GetFrmFmt(); + + const SwDoc *pDoc = pFrmFmt->GetDoc(); + const SwPosition* pAPos = pFrmFmt->GetAnchor().GetCntntAnchor(); + SwNode *pANd; + SwTableNode *pTblNd; + if( pAPos && + 0 != (pANd = & pAPos->nNode.GetNode()) && + 0 != (pTblNd = pANd->FindTableNode()) ) + { + const sal_Bool bLastGrf = !pTblNd->GetTable().DecGrfsThatResize(); + SwHTMLTableLayout *pLayout = + pTblNd->GetTable().GetHTMLTableLayout(); + if( pLayout ) + { + const sal_uInt16 nBrowseWidth = + pLayout->GetBrowseWidthByTable( *pDoc ); + + if ( nBrowseWidth ) + { + pLayout->Resize( nBrowseWidth, sal_True, sal_True, + bLastGrf ? HTMLTABLE_RESIZE_NOW + : 500 ); + } + } + } + } + } + + // uns selbst abmelden und loeschen + clear(); + uno::Reference< awt::XImageConsumer > xTmp = (awt::XImageConsumer*)this; + xThis = 0; +} + +void SwHTMLImageWatcher::setColorModel( + sal_Int16, const Sequence< sal_Int32 >&, sal_Int32, sal_Int32, + sal_Int32, sal_Int32 ) + throw( uno::RuntimeException ) +{ +} + +void SwHTMLImageWatcher::setPixelsByBytes( + sal_Int32, sal_Int32, sal_Int32, sal_Int32, + const Sequence< sal_Int8 >&, sal_Int32, sal_Int32 ) + throw( uno::RuntimeException ) +{ +} + + +void SwHTMLImageWatcher::setPixelsByLongs( + sal_Int32, sal_Int32, sal_Int32, sal_Int32, + const Sequence< sal_Int32 >&, sal_Int32, sal_Int32 ) + throw( uno::RuntimeException ) +{ +} + + +void SwHTMLImageWatcher::complete( sal_Int32 Status, + const uno::Reference< awt::XImageProducer >& ) + throw( uno::RuntimeException ) +{ + if( awt::ImageStatus::IMAGESTATUS_ERROR == Status || awt::ImageStatus::IMAGESTATUS_ABORTED == Status ) + { + // uns selbst abmelden und loeschen + clear(); + uno::Reference< awt::XImageConsumer > xTmp = (awt::XImageConsumer*)this; + xThis = 0; + } +} + +void SwHTMLImageWatcher::disposing(const lang::EventObject& evt) throw ( uno::RuntimeException) +{ + uno::Reference< awt::XImageConsumer > xTmp; + + // Wenn das Shape verschwindet soll muessen wir es loslassen + uno::Reference< drawing::XShape > xTmpShape; + if( evt.Source == xShape ) + { + clear(); + xTmp = (awt::XImageConsumer*)this; + xThis = 0; + } +} + +void SwHTMLParser::DeleteFormImpl() +{ + delete pFormImpl; + pFormImpl = 0; +} + +static void lcl_html_setFixedFontProperty( + const uno::Reference< beans::XPropertySet >& rPropSet ) +{ + Font aFixedFont( OutputDevice::GetDefaultFont( + DEFAULTFONT_FIXED, LANGUAGE_ENGLISH_US, + DEFAULTFONT_FLAGS_ONLYONE ) ); + Any aTmp; + aTmp <<= OUString( aFixedFont.GetName() ); + rPropSet->setPropertyValue( OUString::createFromAscii("FontName"), aTmp ); + + aTmp <<= OUString( aFixedFont.GetStyleName() ); + rPropSet->setPropertyValue( OUString::createFromAscii("FontStyleName"), + aTmp ); + + aTmp <<= (sal_Int16) aFixedFont.GetFamily(); + rPropSet->setPropertyValue( OUString::createFromAscii("FontFamily"), aTmp ); + + aTmp <<= (sal_Int16) aFixedFont.GetCharSet(); + rPropSet->setPropertyValue( OUString::createFromAscii("FontCharset"), + aTmp ); + + aTmp <<= (sal_Int16) aFixedFont.GetPitch(); + rPropSet->setPropertyValue( OUString::createFromAscii("FontPitch"), aTmp ); + + float fVal(10.); + aTmp.setValue( &fVal, ::getCppuType(&fVal )); + rPropSet->setPropertyValue( OUString::createFromAscii("FontHeight"), aTmp ); +} + +class SwHTMLFormPendingStackData_Impl: public SwPendingStackData +{ + uno::Reference< drawing::XShape > xShape; + Size aTextSz; + sal_Bool bMinWidth; + sal_Bool bMinHeight; + +public: + + SwHTMLFormPendingStackData_Impl( + const uno::Reference< drawing::XShape > & rShape, const Size& rTextSz, + sal_Bool bMinW, sal_Bool bMinH ) : + xShape( rShape ), + aTextSz( rTextSz ), + bMinWidth( bMinW ), + bMinHeight( bMinH ) + {} + + const uno::Reference< drawing::XShape >& GetShape() const { return xShape; } + const Size& GetTextSize() const { return aTextSz; } + sal_Bool IsMinWidth() const { return bMinWidth; } + sal_Bool IsMinHeight() const { return bMinHeight; } +}; + +void SwHTMLParser::SetPendingControlSize( int nToken ) +{ + ASSERT( pPendStack, "Wo ist der Pending Stack?" ); + SwHTMLFormPendingStackData_Impl *pData = + (SwHTMLFormPendingStackData_Impl *)pPendStack->pData; + + SwPendingStack* pTmp = pPendStack->pNext; + delete pPendStack; + pPendStack = pTmp; + ASSERT( !pPendStack, "Wo kommt der Pending-Stack her?" ); + + SetControlSize( pData->GetShape(), pData->GetTextSize(), + pData->IsMinWidth(), pData->IsMinHeight(), + nToken ); + delete pData; +} + +void SwHTMLParser::SetControlSize( const uno::Reference< drawing::XShape >& rShape, + const Size& rTextSz, + sal_Bool bMinWidth, + sal_Bool bMinHeight, + int nToken ) +{ + nToken = 0; + if( !rTextSz.Width() && !rTextSz.Height() && !bMinWidth && !bMinHeight ) + return; + + // Um an den SwXShape* zu gelangen, brauchen wir ein Interface, + // das auch vom SwXShape implementiert wird. + uno::Reference< beans::XPropertySet > xPropSet( rShape, UNO_QUERY ); + + ViewShell *pVSh; + pDoc->GetEditShell( &pVSh ); + if( !pVSh && !nEventId ) + { + // If there is no view shell by now and the doc shell is an internal + // one, no view shell will be created. That for, we have to do that of + // our own. This happens if a linked section is inserted or refreshed. + SwDocShell *pDocSh = pDoc->GetDocShell(); + if( pDocSh ) + { + if ( pDocSh->GetMedium() ) + { + // if there is no hidden property in the MediaDescriptor it should be removed after loading + SFX_ITEMSET_ARG( pDocSh->GetMedium()->GetItemSet(), pHiddenItem, SfxBoolItem, SID_HIDDEN, sal_False ); + bRemoveHidden = ( pHiddenItem == NULL || !pHiddenItem->GetValue() ); + } + + pTempViewFrame = SfxViewFrame::LoadHiddenDocument( *pDocSh, 0 ); + CallStartAction(); + pDoc->GetEditShell( &pVSh ); + } + } + + uno::Reference< XUnoTunnel> xTunnel( xPropSet, UNO_QUERY ); + SwXShape *pSwShape = xTunnel.is() ? + reinterpret_cast< SwXShape *>( sal::static_int_cast< sal_IntPtr >( + xTunnel->getSomething(SwXShape::getUnoTunnelId()) )) + : 0; + + ASSERT( pSwShape, "Wo ist das SW-Shape?" ); + + // es muss ein Draw-Format sein + SwFrmFmt *pFrmFmt = pSwShape->GetFrmFmt(); + ASSERT( RES_DRAWFRMFMT == pFrmFmt->Which(), "Kein DrawFrmFmt" ); + + // Schauen, ob es ein SdrObject dafuer gibt + const SdrObject *pObj = pFrmFmt->FindSdrObject(); + ASSERT( pObj, "SdrObject nicht gefunden" ); + ASSERT( FmFormInventor == pObj->GetObjInventor(), "falscher Inventor" ); + + const SdrView* pDrawView = pVSh ? pVSh->GetDrawView() : 0; + + SdrUnoObj *pFormObj = PTR_CAST( SdrUnoObj, pObj ); + uno::Reference< awt::XControl > xControl; + if ( pDrawView && pVSh->GetWin() ) + xControl = pFormObj->GetUnoControl( *pDrawView, *pVSh->GetWin() ); + + awt::Size aSz( rShape->getSize() ); + awt::Size aNewSz( 0, 0 ); + + // #i71248# ensure we got a XControl before apllying corrections + if(xControl.is()) + { + if( bMinWidth || bMinHeight ) + { + uno::Reference< awt::XLayoutConstrains > xLC( xControl, UNO_QUERY ); + awt::Size aTmpSz( xLC->getPreferredSize() ); + if( bMinWidth ) + aNewSz.Width = aTmpSz.Width; + if( bMinHeight ) + aNewSz.Height = aTmpSz.Height; + } + if( rTextSz.Width() || rTextSz.Height()) + { + uno::Reference< awt::XTextLayoutConstrains > xLC( xControl, UNO_QUERY ); + ASSERT( xLC.is(), "kein XTextLayoutConstrains" ); + if( xLC.is() ) + { + awt::Size aTmpSz( rTextSz.Width(), rTextSz.Height() ); + if( -1 == rTextSz.Width() ) + { + aTmpSz.Width = 0; + aTmpSz.Height = nSelectEntryCnt; + } + aTmpSz = xLC->getMinimumSize( static_cast< sal_Int16 >(aTmpSz.Width), static_cast< sal_Int16 >(aTmpSz.Height) ); + if( rTextSz.Width() ) + aNewSz.Width = aTmpSz.Width; + if( rTextSz.Height() ) + aNewSz.Height = aTmpSz.Height; + } + } + } + + if( Application::GetDefaultDevice() ) + { + Size aTmpSz( aNewSz.Width, aNewSz.Height ); + aTmpSz = Application::GetDefaultDevice() + ->PixelToLogic( aTmpSz, MapMode( MAP_100TH_MM ) ); + aNewSz.Width = aTmpSz.Width(); + aNewSz.Height = aTmpSz.Height(); + } + if( aNewSz.Width ) + { + if( aNewSz.Width < MINLAY ) + aNewSz.Width = MINLAY; + aSz.Width = aNewSz.Width; + } + if( aNewSz.Height ) + { + if( aNewSz.Height < MINLAY ) + aNewSz.Height = MINLAY; + aSz.Height = aNewSz.Height; + } + + rShape->setSize( aSz ); +} + +static void lcl_html_setEvents( + const uno::Reference< script::XEventAttacherManager > & rEvtMn, + sal_uInt32 nPos, const SvxMacroTableDtor& rMacroTbl, + const SvStringsDtor& rUnoMacroTbl, + const SvStringsDtor& rUnoMacroParamTbl, + const String& rType ) +{ + // Erstmal muss die Anzahl der Events ermittelt werden ... + sal_Int32 nEvents = 0; + sal_uInt16 i; + + for( i = 0; HTML_ET_END != aEventTypeTable[i]; i++ ) + { + const SvxMacro *pMacro = rMacroTbl.Get( aEventTypeTable[i] ); + // Solange nicht alle Events implementiert sind, enthaelt die + // Tabelle auch Leerstrings! + if( pMacro && aEventListenerTable[i] ) + nEvents++; + } + for( i=0; i< rUnoMacroTbl.Count(); i++ ) + { + const String& rStr = *rUnoMacroTbl[i]; + xub_StrLen nIndex = 0; + if( !rStr.GetToken( 0, '-', nIndex ).Len() || STRING_NOTFOUND == nIndex ) + continue; + if( !rStr.GetToken( 0, '-', nIndex ).Len() || STRING_NOTFOUND == nIndex ) + continue; + if( nIndex < rStr.Len() ) + nEvents++; + } + + if( 0==nEvents ) + return; + + Sequence<script::ScriptEventDescriptor> aDescs( nEvents ); + script::ScriptEventDescriptor* pDescs = aDescs.getArray(); + sal_Int32 nEvent = 0; + + for( i=0; HTML_ET_END != aEventTypeTable[i]; i++ ) + { + const SvxMacro *pMacro = rMacroTbl.Get( aEventTypeTable[i] ); + if( pMacro && aEventListenerTable[i] ) + { + script::ScriptEventDescriptor& rDesc = pDescs[nEvent++]; + rDesc.ListenerType = + OUString::createFromAscii(aEventListenerTable[i]); + rDesc.EventMethod = OUString::createFromAscii(aEventMethodTable[i]); + rDesc.ScriptType = pMacro->GetLanguage(); + rDesc.ScriptCode = pMacro->GetMacName(); + } + } + + for( i=0; i< rUnoMacroTbl.Count(); i++ ) + { + const String& rStr = *rUnoMacroTbl[i]; + xub_StrLen nIndex = 0; + String sListener( rStr.GetToken( 0, '-', nIndex ) ); + if( !sListener.Len() || STRING_NOTFOUND == nIndex ) + continue; + + String sMethod( rStr.GetToken( 0, '-', nIndex ) ); + if( !sMethod.Len() || STRING_NOTFOUND == nIndex ) + continue; + + String sCode( rStr.Copy( nIndex ) ); + if( !sCode.Len() ) + continue; + + script::ScriptEventDescriptor& rDesc = pDescs[nEvent++]; + rDesc.ListenerType = sListener; + rDesc.EventMethod = sMethod; + rDesc.ScriptType = rType; + rDesc.ScriptCode = sCode; + rDesc.AddListenerParam = OUString(); + + if( rUnoMacroParamTbl.Count() ) + { + String sSearch( sListener ); + sSearch += '-'; + sSearch += sMethod; + sSearch += '-'; + xub_StrLen nLen = sSearch.Len(); + for( sal_uInt16 j=0; j < rUnoMacroParamTbl.Count(); j++ ) + { + const String& rParam = *rUnoMacroParamTbl[j]; + if( rParam.CompareTo( sSearch, nLen ) == COMPARE_EQUAL && + rParam.Len() > nLen ) + { + rDesc.AddListenerParam = rParam.Copy(nLen); + break; + } + } + } + } + rEvtMn->registerScriptEvents( nPos, aDescs ); +} + +static void lcl_html_getEvents( const String& rOption, const String& rValue, + SvStringsDtor& rUnoMacroTbl, + SvStringsDtor& rUnoMacroParamTbl ) +{ + if( rOption.CompareIgnoreCaseToAscii( OOO_STRING_SVTOOLS_HTML_O_sdevent, + sizeof(OOO_STRING_SVTOOLS_HTML_O_sdevent)-1 ) == COMPARE_EQUAL ) + { + String *pEvent = new String( rOption.Copy(sizeof(OOO_STRING_SVTOOLS_HTML_O_sdevent)-1) ); + *pEvent += '-'; + *pEvent += rValue; + rUnoMacroTbl.Insert( pEvent, rUnoMacroTbl.Count() ); + } + else if( rOption.CompareIgnoreCaseToAscii( OOO_STRING_SVTOOLS_HTML_O_sdaddparam, + sizeof(OOO_STRING_SVTOOLS_HTML_O_sdaddparam)-1 ) == COMPARE_EQUAL ) + { + String *pParam = + new String( rOption.Copy( sizeof(OOO_STRING_SVTOOLS_HTML_O_sdaddparam)-1 ) ); + *pParam += '-'; + *pParam += rValue; + rUnoMacroParamTbl.Insert( pParam, rUnoMacroParamTbl.Count() ); + } +} + +uno::Reference< drawing::XShape > SwHTMLParser::InsertControl( + const uno::Reference< XFormComponent > & rFComp, + const uno::Reference< beans::XPropertySet > & rFCompPropSet, + const Size& rSize, sal_Int16 eVertOri, sal_Int16 eHoriOri, + SfxItemSet& rCSS1ItemSet, SvxCSS1PropertyInfo& rCSS1PropInfo, + const SvxMacroTableDtor& rMacroTbl, const SvStringsDtor& rUnoMacroTbl, + const SvStringsDtor& rUnoMacroParamTbl, sal_Bool bSetFCompPropSet, + sal_Bool bHidden ) +{ + uno::Reference< drawing::XShape > xShape; + + const uno::Reference< container::XIndexContainer > & rFormComps = + pFormImpl->GetFormComps(); + Any aAny( &rFComp, ::getCppuType( (uno::Reference< XFormComponent>*)0 ) ); + rFormComps->insertByIndex( rFormComps->getCount(), aAny ); + + if( !bHidden ) + { + Any aTmp; + sal_uInt16 nLeftSpace = 0, nRightSpace = 0, + nUpperSpace = 0, nLowerSpace = 0; + + const uno::Reference< XMultiServiceFactory > & rServiceFactory = + pFormImpl->GetServiceFactory(); + if( !rServiceFactory.is() ) + return xShape; + + uno::Reference< XInterface > xCreate = + rServiceFactory ->createInstance( + OUString::createFromAscii("com.sun.star.drawing.ControlShape")); + if( !xCreate.is() ) + return xShape; + + xShape = uno::Reference< drawing::XShape >( xCreate, UNO_QUERY ); + + DBG_ASSERT( xShape.is(), "XShape nicht erhalten" ); + awt::Size aTmpSz; + aTmpSz.Width = rSize.Width(); + aTmpSz.Height = rSize.Height(); + xShape->setSize( aTmpSz ); + + uno::Reference< beans::XPropertySet > xShapePropSet( xCreate, UNO_QUERY ); + + // linken/rechten Rand setzen + const SfxPoolItem *pItem; + if( SFX_ITEM_SET==rCSS1ItemSet.GetItemState( RES_LR_SPACE, sal_True, + &pItem ) ) + { + // Ggf. den Erstzeilen-Einzug noch plaetten + const SvxLRSpaceItem *pLRItem = (const SvxLRSpaceItem *)pItem; + SvxLRSpaceItem aLRItem( *pLRItem ); + aLRItem.SetTxtFirstLineOfst( 0 ); + if( rCSS1PropInfo.bLeftMargin ) + { + nLeftSpace = static_cast< sal_uInt16 >(TWIP_TO_MM100( aLRItem.GetLeft() )); + rCSS1PropInfo.bLeftMargin = sal_False; + } + if( rCSS1PropInfo.bRightMargin ) + { + nRightSpace = static_cast< sal_uInt16 >(TWIP_TO_MM100( aLRItem.GetRight() )); + rCSS1PropInfo.bRightMargin = sal_False; + } + rCSS1ItemSet.ClearItem( RES_LR_SPACE ); + } + if( nLeftSpace || nRightSpace ) + { + Any aAny2; + aAny2 <<= (sal_Int32)nLeftSpace; + xShapePropSet->setPropertyValue( + OUString::createFromAscii( "LeftMargin" ), aAny2 ); + + aAny2 <<= (sal_Int32)nRightSpace; + xShapePropSet->setPropertyValue( + OUString::createFromAscii( "RightMargin" ), aAny2 ); + } + + // oberen/unteren Rand setzen + if( SFX_ITEM_SET==rCSS1ItemSet.GetItemState( RES_UL_SPACE, sal_True, + &pItem ) ) + { + // Ggf. den Erstzeilen-Einzug noch plaetten + const SvxULSpaceItem *pULItem = (const SvxULSpaceItem *)pItem; + if( rCSS1PropInfo.bTopMargin ) + { + nUpperSpace = TWIP_TO_MM100_UNSIGNED( pULItem->GetUpper() ); + rCSS1PropInfo.bTopMargin = sal_False; + } + if( rCSS1PropInfo.bBottomMargin ) + { + nLowerSpace = TWIP_TO_MM100_UNSIGNED( pULItem->GetLower() ); + rCSS1PropInfo.bBottomMargin = sal_False; + } + + rCSS1ItemSet.ClearItem( RES_UL_SPACE ); + } + if( nUpperSpace || nLowerSpace ) + { + uno::Any aAny2; + aAny2 <<= (sal_Int32)nUpperSpace; + xShapePropSet->setPropertyValue( + OUString::createFromAscii( "TopMargin" ), aAny2 ); + + aAny2 <<= (sal_Int32)nLowerSpace; + xShapePropSet->setPropertyValue( + OUString::createFromAscii( "BottomMargin" ), aAny2 ); + } + + uno::Reference< beans::XPropertySetInfo > xPropSetInfo = + rFCompPropSet->getPropertySetInfo(); + OUString sPropName = OUString::createFromAscii( "BackgroundColor" ); + if( SFX_ITEM_SET==rCSS1ItemSet.GetItemState( RES_BACKGROUND, sal_True, + &pItem ) && + xPropSetInfo->hasPropertyByName( sPropName ) ) + { + const Color &rColor = ((const SvxBrushItem *)pItem)->GetColor(); + /// OD 02.09.2002 #99657# + /// copy color, if color is not "no fill"/"auto fill" + if( rColor.GetColor() != COL_TRANSPARENT ) + { + /// OD 02.09.2002 #99657# + /// copy complete color with transparency + aTmp <<= static_cast<sal_Int32>(rColor.GetColor()); + rFCompPropSet->setPropertyValue( sPropName, aTmp ); + } + + } + + sPropName = OUString::createFromAscii( "TextColor" ); + if( SFX_ITEM_SET==rCSS1ItemSet.GetItemState( RES_CHRATR_COLOR, sal_True, + &pItem ) && + xPropSetInfo->hasPropertyByName( sPropName ) ) + { + aTmp <<= (sal_Int32)((const SvxColorItem *)pItem)->GetValue() + .GetRGBColor(); + rFCompPropSet->setPropertyValue( sPropName, aTmp ); + } + + sPropName = OUString::createFromAscii( "FontHeight" ); + if( SFX_ITEM_SET==rCSS1ItemSet.GetItemState( RES_CHRATR_FONTSIZE, + sal_True, &pItem ) && + xPropSetInfo->hasPropertyByName( sPropName ) ) + { + float fVal = static_cast< float >( + (((SvxFontHeightItem *)pItem)->GetHeight()) / 20.0 ); + aTmp.setValue( &fVal, ::getCppuType(&fVal)); + rFCompPropSet->setPropertyValue( sPropName, aTmp ); + } + + if( SFX_ITEM_SET==rCSS1ItemSet.GetItemState( RES_CHRATR_FONT, sal_True, + &pItem ) ) + { + const SvxFontItem *pFontItem = (SvxFontItem *)pItem; + sPropName = OUString::createFromAscii( "FontName" ); + if( xPropSetInfo->hasPropertyByName( sPropName ) ) + { + aTmp <<= OUString( pFontItem->GetFamilyName() ); + rFCompPropSet->setPropertyValue( sPropName, aTmp ); + } + sPropName = OUString::createFromAscii( "FontStyleName" ); + if( xPropSetInfo->hasPropertyByName( sPropName ) ) + { + aTmp <<= OUString( pFontItem->GetStyleName() ); + rFCompPropSet->setPropertyValue( sPropName, aTmp ); + } + sPropName = OUString::createFromAscii( "FontFamily" ); + if( xPropSetInfo->hasPropertyByName( sPropName ) ) + { + aTmp <<= (sal_Int16)pFontItem->GetFamily() ; + rFCompPropSet->setPropertyValue( sPropName, aTmp ); + } + sPropName = OUString::createFromAscii( "FontCharset" ); + if( xPropSetInfo->hasPropertyByName( sPropName ) ) + { + aTmp <<= (sal_Int16)pFontItem->GetCharSet() ; + rFCompPropSet->setPropertyValue( sPropName, aTmp ); + } + sPropName = OUString::createFromAscii( "FontPitch" ); + if( xPropSetInfo->hasPropertyByName( sPropName ) ) + { + aTmp <<= (sal_Int16)pFontItem->GetPitch() ; + rFCompPropSet->setPropertyValue( sPropName, aTmp ); + } + } + + sPropName = OUString::createFromAscii( "FontWeight" ); + if( SFX_ITEM_SET==rCSS1ItemSet.GetItemState( RES_CHRATR_WEIGHT, + sal_True, &pItem ) && + xPropSetInfo->hasPropertyByName( sPropName ) ) + { + float fVal = VCLUnoHelper::ConvertFontWeight( + ((SvxWeightItem *)pItem)->GetWeight() ); + aTmp.setValue( &fVal, ::getCppuType(&fVal)); + rFCompPropSet->setPropertyValue( sPropName, aTmp ); + } + + sPropName = OUString::createFromAscii( "FontSlant" ); + if( SFX_ITEM_SET==rCSS1ItemSet.GetItemState( RES_CHRATR_POSTURE, + sal_True, &pItem ) && + xPropSetInfo->hasPropertyByName( sPropName ) ) + { + aTmp <<= (sal_Int16)((SvxPostureItem *)pItem)->GetPosture(); + rFCompPropSet->setPropertyValue( sPropName, aTmp ); + } + + sPropName = OUString::createFromAscii( "FontUnderline" ); + if( SFX_ITEM_SET==rCSS1ItemSet.GetItemState( RES_CHRATR_UNDERLINE, + sal_True, &pItem ) && + xPropSetInfo->hasPropertyByName( sPropName ) ) + { + aTmp <<= (sal_Int16)((SvxUnderlineItem *)pItem)->GetLineStyle(); + rFCompPropSet->setPropertyValue( sPropName, aTmp ); + } + + sPropName = OUString::createFromAscii( "FontStrikeout" ); + if( SFX_ITEM_SET==rCSS1ItemSet.GetItemState( RES_CHRATR_CROSSEDOUT, + sal_True, &pItem ) && + xPropSetInfo->hasPropertyByName( sPropName ) ) + { + aTmp <<= (sal_Int16)((SvxCrossedOutItem *)pItem)->GetStrikeout(); + rFCompPropSet->setPropertyValue( sPropName, aTmp ); + } + + uno::Reference< text::XTextRange > xTxtRg; + sal_Int16 nAnchorType = text::TextContentAnchorType_AS_CHARACTER; + sal_Bool bSetPos = sal_False, bSetSurround = sal_False; + sal_Int32 nXPos = 0, nYPos = 0; + sal_Int16 nSurround = text::WrapTextMode_NONE; + if( SVX_CSS1_POS_ABSOLUTE == rCSS1PropInfo.ePosition && + SVX_CSS1_LTYPE_TWIP == rCSS1PropInfo.eLeftType && + SVX_CSS1_LTYPE_TWIP == rCSS1PropInfo.eTopType ) + { + const SwStartNode *pFlySttNd = + pPam->GetPoint()->nNode.GetNode().FindFlyStartNode(); + + if( pFlySttNd ) + { + nAnchorType = text::TextContentAnchorType_AT_FRAME; + SwPaM aPaM( *pFlySttNd ); + + uno::Reference< text::XText > xDummyTxtRef; // unsauber, aber laut OS geht das ... + xTxtRg = new SwXTextRange( aPaM, xDummyTxtRef ); + } + else + { + nAnchorType = text::TextContentAnchorType_AT_PAGE; + } + nXPos = TWIP_TO_MM100( rCSS1PropInfo.nLeft ) + nLeftSpace; + nYPos = TWIP_TO_MM100( rCSS1PropInfo.nTop ) + nUpperSpace; + bSetPos = sal_True; + + nSurround = text::WrapTextMode_THROUGHT; + bSetSurround = sal_True; + } + else if( SVX_ADJUST_LEFT == rCSS1PropInfo.eFloat || + text::HoriOrientation::LEFT == eHoriOri ) + { + nAnchorType = text::TextContentAnchorType_AT_PARAGRAPH; + nXPos = nLeftSpace; + nYPos = nUpperSpace; + bSetPos = sal_True; + nSurround = text::WrapTextMode_RIGHT; + bSetSurround = sal_True; + } + else if( text::VertOrientation::NONE != eVertOri ) + { + sal_Int16 nVertOri = text::VertOrientation::NONE; + switch( eVertOri ) + { + case text::VertOrientation::NONE: + nVertOri = text::VertOrientation::NONE; + break; + case text::VertOrientation::TOP: + nVertOri = text::VertOrientation::TOP; + break; + case text::VertOrientation::CENTER: + nVertOri = text::VertOrientation::CENTER; + break; + case text::VertOrientation::BOTTOM: + nVertOri = text::VertOrientation::BOTTOM; + break; + case text::VertOrientation::CHAR_TOP: + nVertOri = text::VertOrientation::CHAR_TOP; + break; + case text::VertOrientation::CHAR_CENTER: + nVertOri = text::VertOrientation::CHAR_CENTER; + break; + case text::VertOrientation::CHAR_BOTTOM: + nVertOri = text::VertOrientation::CHAR_BOTTOM; + break; + case text::VertOrientation::LINE_TOP: + nVertOri = text::VertOrientation::LINE_TOP; + break; + case text::VertOrientation::LINE_CENTER: + nVertOri = text::VertOrientation::LINE_CENTER; + break; + case text::VertOrientation::LINE_BOTTOM: + nVertOri = text::VertOrientation::LINE_BOTTOM; + break; + } + aTmp <<= (sal_Int16)nVertOri ; + xShapePropSet->setPropertyValue( + OUString::createFromAscii( "VertOrient" ), aTmp ); + } + + aTmp <<= (sal_Int16)nAnchorType ; + xShapePropSet->setPropertyValue( + OUString::createFromAscii( "AnchorType" ), aTmp ); + + if( text::TextContentAnchorType_AT_PAGE == nAnchorType ) + { + aTmp <<= (sal_Int16) 1 ; + xShapePropSet->setPropertyValue( + OUString::createFromAscii( "AnchorPageNo" ), aTmp ); + } + else + { + if( !xTxtRg.is() ) + { + uno::Reference< text::XText > xDummyTxtRef; // unsauber, aber laut OS geht das ... + xTxtRg = new SwXTextRange( *pPam, xDummyTxtRef ); + } + + aTmp.setValue( &xTxtRg, + ::getCppuType((uno::Reference< text::XTextRange>*)0)); + xShapePropSet->setPropertyValue( + OUString::createFromAscii( "TextRange" ), aTmp ); + } + + if( bSetPos ) + { + aTmp <<= (sal_Int16)text::HoriOrientation::NONE; + xShapePropSet->setPropertyValue( + OUString::createFromAscii( "HoriOrient" ), aTmp ); + aTmp <<= (sal_Int32)nXPos ; + xShapePropSet->setPropertyValue( + OUString::createFromAscii( "HoriOrientPosition" ), aTmp ); + + aTmp <<= (sal_Int16)text::VertOrientation::NONE; + xShapePropSet->setPropertyValue( + OUString::createFromAscii( "VertOrient" ), aTmp ); + aTmp <<= (sal_Int32)nYPos ; + xShapePropSet->setPropertyValue( + OUString::createFromAscii( "VertOrientPosition" ), aTmp ); + } + if( bSetSurround ) + { + aTmp <<= (sal_Int16)nSurround ; + xShapePropSet->setPropertyValue( + OUString::createFromAscii( "Surround" ), aTmp ); + } + + pFormImpl->GetShapes()->add(xShape); + + // Das Control-Model am Control-Shape setzen + uno::Reference< drawing::XControlShape > xControlShape( xShape, UNO_QUERY ); + uno::Reference< awt::XControlModel > xControlModel( rFComp, UNO_QUERY ); + xControlShape->setControl( xControlModel ); + } + + // Da beim Einfuegen der Controls der Fokus gesetzt wird, werden + // auch schon Fokus-Events verschickt. Damit die nicht evtl. schon + // vorhendene JavaSCript-Eents rufen, werden die Events nachtraeglich + // gesetzt. + if( rMacroTbl.Count() || rUnoMacroTbl.Count() ) + { + lcl_html_setEvents( pFormImpl->GetControlEventManager(), + rFormComps->getCount() - 1, + rMacroTbl, rUnoMacroTbl, rUnoMacroParamTbl, + GetScriptTypeString(pFormImpl->GetHeaderAttrs()) ); + } + + if( bSetFCompPropSet ) + { + pFormImpl->SetFCompPropSet( rFCompPropSet ); + } + + return xShape; +} + +void SwHTMLParser::NewForm( sal_Bool bAppend ) +{ + // Gibt es schon eine Form? + if( pFormImpl && pFormImpl->GetFormComps().is() ) + return; + + if( bAppend ) + { + if( pPam->GetPoint()->nContent.GetIndex() ) + AppendTxtNode( AM_SPACE ); + else + AddParSpace(); + } + + if( !pFormImpl ) + pFormImpl = new SwHTMLForm_Impl( pDoc->GetDocShell() ); + + String aAction( sBaseURL ); + String sName, sTarget; + sal_uInt16 nEncType = FormSubmitEncoding_URL; + sal_uInt16 nMethod = FormSubmitMethod_GET; + SvxMacroTableDtor aMacroTbl; + SvStringsDtor aUnoMacroTbl; + SvStringsDtor aUnoMacroParamTbl; + SvKeyValueIterator *pHeaderAttrs = pFormImpl->GetHeaderAttrs(); + ScriptType eDfltScriptType = GetScriptType( pHeaderAttrs ); + const String& rDfltScriptType = GetScriptTypeString( pHeaderAttrs ); + + const HTMLOptions *pHTMLOptions = GetOptions(); + for( sal_uInt16 i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + ScriptType eScriptType2 = eDfltScriptType; + sal_uInt16 nEvent = 0; + sal_Bool bSetEvent = sal_False; + + switch( pOption->GetToken() ) + { + case HTML_O_ACTION: + aAction = pOption->GetString(); + break; + case HTML_O_METHOD: + nMethod = pOption->GetEnum( aHTMLFormMethodTable, nMethod ); + break; + case HTML_O_ENCTYPE: + nEncType = pOption->GetEnum( aHTMLFormEncTypeTable, nEncType ); + break; + case HTML_O_TARGET: + sTarget = pOption->GetString(); + break; + case HTML_O_NAME: + sName = pOption->GetString(); + break; + + case HTML_O_SDONSUBMIT: + eScriptType2 = STARBASIC; + case HTML_O_ONSUBMIT: + nEvent = HTML_ET_ONSUBMITFORM; + bSetEvent = sal_True; + break; + + case HTML_O_SDONRESET: + eScriptType2 = STARBASIC; + case HTML_O_ONRESET: + nEvent = HTML_ET_ONRESETFORM; + bSetEvent = sal_True; + break; + + default: + lcl_html_getEvents( pOption->GetTokenString(), + pOption->GetString(), + aUnoMacroTbl, aUnoMacroParamTbl ); + break; + } + + if( bSetEvent ) + { + String sEvent( pOption->GetString() ); + if( sEvent.Len() ) + { + sEvent.ConvertLineEnd(); + String aScriptType2; + if( EXTENDED_STYPE==eScriptType2 ) + aScriptType2 = rDfltScriptType; + aMacroTbl.Insert( nEvent, new SvxMacro( sEvent, aScriptType2, + eScriptType2 ) ); + } + } + } + + const uno::Reference< XMultiServiceFactory > & rSrvcMgr = + pFormImpl->GetServiceFactory(); + if( !rSrvcMgr.is() ) + return; + + uno::Reference< XInterface > xInt = rSrvcMgr->createInstance( + OUString::createFromAscii( "com.sun.star.form.component.Form" ) ); + if( !xInt.is() ) + return; + + uno::Reference< XForm > xForm( xInt, UNO_QUERY ); + DBG_ASSERT( xForm.is(), "keine Form?" ); + + uno::Reference< container::XIndexContainer > xFormComps( xForm, UNO_QUERY ); + pFormImpl->SetFormComps( xFormComps ); + + uno::Reference< beans::XPropertySet > xFormPropSet( xForm, UNO_QUERY ); + + Any aTmp; + aTmp <<= OUString(sName); + xFormPropSet->setPropertyValue( OUString::createFromAscii( "Name" ), aTmp ); + + if( aAction.Len() ) + { + aAction = URIHelper::SmartRel2Abs(INetURLObject(sBaseURL), aAction, Link(), false); + } + else + { + // Bei leerer URL das Directory nehmen + INetURLObject aURLObj( aPathToFile ); + aAction = aURLObj.GetPartBeforeLastName(); + } + aTmp <<= OUString(aAction); + xFormPropSet->setPropertyValue( OUString::createFromAscii( "TargetURL" ), + aTmp ); + + FormSubmitMethod eMethod = (FormSubmitMethod)nMethod; + aTmp.setValue( &eMethod, ::getCppuType((const FormSubmitMethod*)0) ); + xFormPropSet->setPropertyValue( OUString::createFromAscii( "SubmitMethod" ), + aTmp ); + + FormSubmitEncoding eEncType = (FormSubmitEncoding)nEncType; + aTmp.setValue( &eEncType, ::getCppuType((const FormSubmitEncoding*)0) ); + xFormPropSet->setPropertyValue( + OUString::createFromAscii( "SubmitEncoding" ), aTmp ); + + if( sTarget.Len() ) + { + aTmp <<= OUString(sTarget); + xFormPropSet->setPropertyValue( + OUString::createFromAscii( "TargetFrame" ), aTmp ); + } + + const uno::Reference< container::XIndexContainer > & rForms = + pFormImpl->GetForms(); + Any aAny( &xForm, ::getCppuType((uno::Reference< XForm>*)0) ); + rForms->insertByIndex( rForms->getCount(), aAny ); + if( aMacroTbl.Count() ) + lcl_html_setEvents( pFormImpl->GetFormEventManager(), + rForms->getCount() - 1, + aMacroTbl, aUnoMacroTbl, aUnoMacroParamTbl, + rDfltScriptType ); +} + +void SwHTMLParser::EndForm( sal_Bool bAppend ) +{ + if( pFormImpl && pFormImpl->GetFormComps().is() ) + { + if( bAppend ) + { + if( pPam->GetPoint()->nContent.GetIndex() ) + AppendTxtNode( AM_SPACE ); + else + AddParSpace(); + } + + pFormImpl->ReleaseFormComps(); + } +} + +void SwHTMLParser::InsertInput() +{ + if( pPendStack ) + { + SetPendingControlSize( HTML_INPUT ); + return; + } + + if( !pFormImpl || !pFormImpl->GetFormComps().is() ) + return; + + String sImgSrc, aId, aClass, aStyle, sText; + String sName; + SvxMacroTableDtor aMacroTbl; + SvStringsDtor aUnoMacroTbl; + SvStringsDtor aUnoMacroParamTbl; + sal_uInt16 nSize = 0; + sal_Int16 nMaxLen = 0; + sal_Int16 nChecked = STATE_NOCHECK; + sal_Int32 nTabIndex = TABINDEX_MAX + 1; + HTMLInputType eType = HTML_IT_TEXT; + sal_Bool bDisabled = sal_False, bValue = sal_False; + sal_Bool bSetGrfWidth = sal_False, bSetGrfHeight = sal_False; + sal_Bool bHidden = sal_False; + long nWidth=0, nHeight=0; + sal_Int16 eVertOri = text::VertOrientation::TOP; + sal_Int16 eHoriOri = text::HoriOrientation::NONE; + SvKeyValueIterator *pHeaderAttrs = pFormImpl->GetHeaderAttrs(); + ScriptType eDfltScriptType = GetScriptType( pHeaderAttrs ); + const String& rDfltScriptType = GetScriptTypeString( pHeaderAttrs ); + + sal_uInt16 nKeepCRLFToken = HTML_O_VALUE; + const HTMLOptions *pHTMLOptions = GetOptions( &nKeepCRLFToken ); + for( sal_uInt16 i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + ScriptType eScriptType2 = eDfltScriptType; + sal_uInt16 nEvent = 0; + sal_Bool bSetEvent = sal_False; + + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + case HTML_O_TYPE: + eType = pOption->GetInputType(); + break; + case HTML_O_NAME: + sName = pOption->GetString(); + break; + case HTML_O_VALUE: + sText = pOption->GetString(); + bValue = sal_True; + break; + case HTML_O_CHECKED: + nChecked = STATE_CHECK; + break; + case HTML_O_DISABLED: + bDisabled = sal_True; + break; + case HTML_O_MAXLENGTH: + nMaxLen = (sal_Int16)pOption->GetNumber(); + break; + case HTML_O_SIZE: + nSize = (sal_uInt16)pOption->GetNumber(); + break; + case HTML_O_SRC: + sImgSrc = pOption->GetString(); + break; + case HTML_O_WIDTH: + // erstmal nur als Pixelwerte merken! + nWidth = pOption->GetNumber(); + break; + case HTML_O_HEIGHT: + // erstmal nur als Pixelwerte merken! + nHeight = pOption->GetNumber(); + break; + case HTML_O_ALIGN: + eVertOri = + pOption->GetEnum( aHTMLImgVAlignTable, eVertOri ); + eHoriOri = + pOption->GetEnum( aHTMLImgHAlignTable, eHoriOri ); + break; + case HTML_O_TABINDEX: + // erstmal nur als Pixelwerte merken! + nTabIndex = pOption->GetNumber(); + break; + + case HTML_O_SDONFOCUS: + eScriptType2 = STARBASIC; + case HTML_O_ONFOCUS: + nEvent = HTML_ET_ONGETFOCUS; + bSetEvent = sal_True; + break; + + case HTML_O_SDONBLUR: // eigtl. nur EDIT + eScriptType2 = STARBASIC; + case HTML_O_ONBLUR: + nEvent = HTML_ET_ONLOSEFOCUS; + bSetEvent = sal_True; + break; + + case HTML_O_SDONCLICK: + eScriptType2 = STARBASIC; + case HTML_O_ONCLICK: + nEvent = HTML_ET_ONCLICK; + bSetEvent = sal_True; + break; + + case HTML_O_SDONCHANGE: // eigtl. nur EDIT + eScriptType2 = STARBASIC; + case HTML_O_ONCHANGE: + nEvent = HTML_ET_ONCHANGE; + bSetEvent = sal_True; + break; + + case HTML_O_SDONSELECT: // eigtl. nur EDIT + eScriptType2 = STARBASIC; + case HTML_O_ONSELECT: + nEvent = HTML_ET_ONSELECT; + bSetEvent = sal_True; + break; + + default: + lcl_html_getEvents( pOption->GetTokenString(), + pOption->GetString(), + aUnoMacroTbl, aUnoMacroParamTbl ); + break; + } + + if( bSetEvent ) + { + String sEvent( pOption->GetString() ); + if( sEvent.Len() ) + { + sEvent.ConvertLineEnd(); + String aScriptType2; + if( EXTENDED_STYPE==eScriptType2 ) + aScriptType2 = rDfltScriptType; + aMacroTbl.Insert( nEvent, new SvxMacro( sEvent, aScriptType2, + eScriptType2 ) ); + } + } + } + + if( HTML_IT_IMAGE==eType ) + { + // Image-Controls ohne Image-URL werden ignoriert (wie bei MS) + if( !sImgSrc.Len() ) + return; + } + else + { + // ALIGN fuer alle Controls auszuwerten ist keine so gute Idee, + // solange Absatz-gebundene Controls die Hoehe von Tabellen-Zellen + // nicht beeinflussen + // (#64110#, http://www.telekom.de/katalog-online/onlineshop.html) + eVertOri = text::VertOrientation::TOP; + eHoriOri = text::HoriOrientation::NONE; + } + + // Defaults entsprechen HTML_IT_TEXT + const sal_Char *pType = "TextField"; + sal_Bool bKeepCRLFInValue = sal_False; + switch( eType ) + { + case HTML_IT_CHECKBOX: + pType = "CheckBox"; + bKeepCRLFInValue = sal_True; + break; + + case HTML_IT_RADIO: + pType = "RadioButton"; + bKeepCRLFInValue = sal_True; + break; + + case HTML_IT_PASSWORD: + bKeepCRLFInValue = sal_True; + break; + + case HTML_IT_BUTTON: + bKeepCRLFInValue = sal_True; + case HTML_IT_SUBMIT: + case HTML_IT_RESET: + pType = "CommandButton"; + break; + + case HTML_IT_IMAGE: + pType = "ImageButton"; + break; + + case HTML_IT_FILE: + pType = "FileControl"; + break; + + case HTML_IT_HIDDEN: + pType = "HiddenControl"; + bKeepCRLFInValue = sal_True; + break; + default: + ; + } + + // Fuer ein par Controls mussen CR/LF noch aus dem VALUE + // geloescht werden. + if( !bKeepCRLFInValue ) + { + sText.EraseAllChars( _CR ); + sText.EraseAllChars( _LF ); + } + + const uno::Reference< XMultiServiceFactory > & rServiceFactory = + pFormImpl->GetServiceFactory(); + if( !rServiceFactory.is() ) + return; + + String sServiceName( + OUString::createFromAscii("com.sun.star.form.component.") ); + sServiceName.AppendAscii( pType ); + uno::Reference< XInterface > xInt = + rServiceFactory->createInstance( sServiceName ); + if( !xInt.is() ) + return; + + uno::Reference< XFormComponent > xFComp( xInt, UNO_QUERY ); + if( !xFComp.is() ) + return; + + uno::Reference< beans::XPropertySet > xPropSet( xFComp, UNO_QUERY ); + + Any aTmp; + aTmp <<= OUString(sName); + xPropSet->setPropertyValue( OUString::createFromAscii( "Name" ), aTmp ); + + if( HTML_IT_HIDDEN != eType ) + { + if( nTabIndex >= TABINDEX_MIN && nTabIndex <= TABINDEX_MAX ) + { + aTmp <<= (sal_Int16) (sal_Int16)nTabIndex ; + xPropSet->setPropertyValue( OUString::createFromAscii( "TabIndex" ), aTmp ); + } + + if( bDisabled ) + { + sal_Bool bFalse = sal_False; + aTmp.setValue(&bFalse, ::getBooleanCppuType() ); + xPropSet->setPropertyValue( OUString::createFromAscii( "Enabled" ), aTmp ); + } + } + + aTmp <<= OUString(sText); + + Size aSz( 0, 0 ); // defaults + Size aTextSz( 0, 0 ); // Text-Size + sal_Bool bMinWidth = sal_False, bMinHeight = sal_False; + sal_Bool bUseSize = sal_False; + switch( eType ) + { + case HTML_IT_CHECKBOX: + case HTML_IT_RADIO: + { + if( !bValue ) + aTmp <<= OUString::createFromAscii( OOO_STRING_SVTOOLS_HTML_on ); + xPropSet->setPropertyValue( OUString::createFromAscii( "RefValue" ), + aTmp ); + aTmp <<= OUString(); + xPropSet->setPropertyValue( OUString::createFromAscii( "Label" ), + aTmp ); + // #53559#: Beim RadioButton darf die DefaultChecked-Property + // erst gesetzt werden, wenn das Control angelegt und ein + // activateTabOrder gerufen wurde, weil es sonst noch zu der + // vorhergehenden Gruppe gehoert. + if( HTML_IT_CHECKBOX == eType ) + { + aTmp <<= (sal_Int16) nChecked ; + xPropSet->setPropertyValue( + OUString::createFromAscii( "DefaultState" ), aTmp ); + } + + SvxMacro *pMacro = aMacroTbl.Get( HTML_ET_ONCLICK ); + if( pMacro ) + { + aMacroTbl.Remove( HTML_ET_ONCLICK ); + aMacroTbl.Insert( HTML_ET_ONCLICK_ITEM, pMacro ); + } + // SIZE auszuwerten duerfte hier keinen Sinn machen??? + bMinWidth = bMinHeight = sal_True; + } + break; + + case HTML_IT_IMAGE: + { + // SIZE = WIDTH + aSz.Width() = nSize ? nSize : nWidth; + aSz.Width() = nWidth; + aSz.Height() = nHeight; + if( (aSz.Width() || aSz.Height()) && Application::GetDefaultDevice() ) + { + aSz = Application::GetDefaultDevice() + ->PixelToLogic( aSz, MapMode( MAP_100TH_MM ) ); + } + FormButtonType eButtonType = FormButtonType_SUBMIT; + aTmp.setValue( &eButtonType, + ::getCppuType((const FormButtonType*)0)); + xPropSet->setPropertyValue( + OUString::createFromAscii( "ButtonType" ), aTmp ); + + aTmp <<= (sal_Int16) 0 ; + xPropSet->setPropertyValue( OUString::createFromAscii( "Border" ), + aTmp ); + } + break; + + case HTML_IT_BUTTON: + case HTML_IT_SUBMIT: + case HTML_IT_RESET: + { + FormButtonType eButtonType; + switch( eType ) + { + case HTML_IT_BUTTON: + eButtonType = FormButtonType_PUSH; + break; + case HTML_IT_SUBMIT: + eButtonType = FormButtonType_SUBMIT; + if( !sText.Len() ) + sText.AssignAscii( OOO_STRING_SVTOOLS_HTML_IT_submit ); + break; + case HTML_IT_RESET: + eButtonType = FormButtonType_RESET; + if( !sText.Len() ) + sText.AssignAscii( OOO_STRING_SVTOOLS_HTML_IT_reset ); + break; + default: + ; + } + aTmp <<= OUString(sText); + xPropSet->setPropertyValue( OUString::createFromAscii( "Label" ), + aTmp ); + + aTmp.setValue( &eButtonType, + ::getCppuType((const FormButtonType*)0)); + xPropSet->setPropertyValue( + OUString::createFromAscii( "ButtonType" ), aTmp ); + + bMinWidth = bMinHeight = sal_True; + bUseSize = sal_True; + } + break; + + case HTML_IT_PASSWORD: + case HTML_IT_TEXT: + case HTML_IT_FILE: + if( HTML_IT_FILE != eType ) + { + // Beim File-Control wird der VALUE aus Sicherheitsgruenden ignoriert. + xPropSet->setPropertyValue( + OUString::createFromAscii( "DefaultText" ), aTmp ); + if( nMaxLen != 0 ) + { + aTmp <<= (sal_Int16) nMaxLen ; + xPropSet->setPropertyValue( + OUString::createFromAscii( "MaxTextLen" ), aTmp ); + } + } + + if( HTML_IT_PASSWORD == eType ) + { + aTmp <<= (sal_Int16)'*' ; + xPropSet->setPropertyValue( OUString::createFromAscii( "EchoChar" ), + aTmp ); + } + + lcl_html_setFixedFontProperty( xPropSet ); + + if( !nSize ) + nSize = 20; + aTextSz.Width() = nSize; + bMinHeight = sal_True; + break; + + case HTML_IT_HIDDEN: + xPropSet->setPropertyValue( OUString::createFromAscii( "HiddenValue" ), + aTmp ); + bHidden = sal_True; + break; + default: + ; + } + + if( bUseSize && nSize>0 ) + { + if( Application::GetDefaultDevice() ) + { + Size aNewSz( nSize, 0 ); + aNewSz = Application::GetDefaultDevice() + ->PixelToLogic( aNewSz, MapMode( MAP_100TH_MM ) ); + aSz.Width() = aNewSz.Width(); + ASSERT( !aTextSz.Width(), "Text-Breite ist gegeben" ); + bMinWidth = sal_False; + } + } + + SfxItemSet aCSS1ItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aCSS1PropInfo; + if( HasStyleOptions( aStyle, aId, aClass ) ) + { + ParseStyleOptions( aStyle, aId, aClass, aCSS1ItemSet, aCSS1PropInfo ); + if( aId.Len() ) + InsertBookmark( aId ); + } + + if( SVX_CSS1_LTYPE_TWIP== aCSS1PropInfo.eWidthType ) + { + aSz.Width() = TWIP_TO_MM100( aCSS1PropInfo.nWidth ); + aTextSz.Width() = 0; + bMinWidth = sal_False; + } + if( SVX_CSS1_LTYPE_TWIP== aCSS1PropInfo.eHeightType ) + { + aSz.Height() = TWIP_TO_MM100( aCSS1PropInfo.nHeight ); + aTextSz.Height() = 0; + bMinHeight = sal_False; + } + + // Beim Image-Button bei nicht gegebern Groesse einen sinnvollen Default + // setzen + if( HTML_IT_IMAGE== eType ) + { + if( !aSz.Width() ) + { + aSz.Width() = HTML_DFLT_IMG_WIDTH; + bSetGrfWidth = sal_True; + if( pTable != 0 ) + IncGrfsThatResizeTable(); + } + if( !aSz.Height() ) + { + aSz.Height() = HTML_DFLT_IMG_HEIGHT; + bSetGrfHeight = sal_True; + } + } + if( aSz.Width() < MINFLY ) + aSz.Width() = MINFLY; + if( aSz.Height() < MINFLY ) + aSz.Height() = MINFLY; + + uno::Reference< drawing::XShape > xShape = InsertControl( + xFComp, xPropSet, aSz, + eVertOri, eHoriOri, + aCSS1ItemSet, aCSS1PropInfo, + aMacroTbl, aUnoMacroTbl, + aUnoMacroParamTbl, sal_False, + bHidden ); + if( aTextSz.Width() || aTextSz.Height() || bMinWidth || bMinHeight ) + { + ASSERT( !(bSetGrfWidth || bSetGrfHeight), "Grafikgroesse anpassen???" ); + SetControlSize( xShape, aTextSz, bMinWidth, bMinHeight, HTML_INPUT ); + } + + if( HTML_IT_RADIO == eType ) + { + aTmp <<= (sal_Int16) nChecked ; + xPropSet->setPropertyValue( OUString::createFromAscii( "DefaultState" ), aTmp ); + } + + if( HTML_IT_IMAGE == eType ) + { + // Die URL erst nach dem Einfuegen setzen, weil sich der + // Download der Grafik erst dann am XModel anmelden kann, + // wenn das Control eingefuegt ist. + aTmp <<= OUString( URIHelper::SmartRel2Abs(INetURLObject(sBaseURL), sImgSrc, Link(), false)); + xPropSet->setPropertyValue( OUString::createFromAscii( "ImageURL" ), + aTmp ); + } + + if( bSetGrfWidth || bSetGrfHeight ) + { + SwHTMLImageWatcher* pWatcher = + new SwHTMLImageWatcher( xShape, bSetGrfWidth, bSetGrfHeight ); + uno::Reference< awt::XImageConsumer > xCons = pWatcher; + pWatcher->start(); + } +} + +void SwHTMLParser::NewTextArea() +{ + if( pPendStack ) + { + SetPendingControlSize( HTML_TEXTAREA_ON ); + return; + } + + ASSERT( !bTextArea, "TextArea in TextArea???" ); + ASSERT( !pFormImpl || !pFormImpl->GetFCompPropSet().is(), + "TextArea in Control???" ); + + if( !pFormImpl || !pFormImpl->GetFormComps().is() ) + { + // Spezialbehandlung fuer TextArea auch untem im Parser beenden + FinishTextArea(); + return; + } + + String aId, aClass, aStyle; + String sName; + sal_Int32 nTabIndex = TABINDEX_MAX + 1; + SvxMacroTableDtor aMacroTbl; + SvStringsDtor aUnoMacroTbl; + SvStringsDtor aUnoMacroParamTbl; + sal_uInt16 nRows = 0, nCols = 0; + sal_uInt16 nWrap = HTML_WM_OFF; + sal_Bool bDisabled = sal_False; + SvKeyValueIterator *pHeaderAttrs = pFormImpl->GetHeaderAttrs(); + ScriptType eDfltScriptType = GetScriptType( pHeaderAttrs ); + const String& rDfltScriptType = GetScriptTypeString( pHeaderAttrs ); + + const HTMLOptions *pHTMLOptions = GetOptions(); + for( sal_uInt16 i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + ScriptType eScriptType2 = eDfltScriptType; + sal_uInt16 nEvent = 0; + sal_Bool bSetEvent = sal_False; + + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + case HTML_O_NAME: + sName = pOption->GetString(); + break; + case HTML_O_DISABLED: + bDisabled = sal_True; + break; + case HTML_O_ROWS: + nRows = (sal_uInt16)pOption->GetNumber(); + break; + case HTML_O_COLS: + nCols = (sal_uInt16)pOption->GetNumber(); + break; + case HTML_O_WRAP: + nWrap = pOption->GetEnum( aHTMLTextAreaWrapTable, nWrap ); + break; + + case HTML_O_TABINDEX: + nTabIndex = pOption->GetSNumber(); + break; + + case HTML_O_SDONFOCUS: + eScriptType2 = STARBASIC; + case HTML_O_ONFOCUS: + nEvent = HTML_ET_ONGETFOCUS; + bSetEvent = sal_True; + break; + + case HTML_O_SDONBLUR: + eScriptType2 = STARBASIC; + case HTML_O_ONBLUR: + nEvent = HTML_ET_ONLOSEFOCUS; + bSetEvent = sal_True; + break; + + case HTML_O_SDONCLICK: + eScriptType2 = STARBASIC; + case HTML_O_ONCLICK: + nEvent = HTML_ET_ONCLICK; + bSetEvent = sal_True; + break; + + case HTML_O_SDONCHANGE: + eScriptType2 = STARBASIC; + case HTML_O_ONCHANGE: + nEvent = HTML_ET_ONCHANGE; + bSetEvent = sal_True; + break; + + case HTML_O_SDONSELECT: + eScriptType2 = STARBASIC; + case HTML_O_ONSELECT: + nEvent = HTML_ET_ONSELECT; + bSetEvent = sal_True; + break; + + default: + lcl_html_getEvents( pOption->GetTokenString(), + pOption->GetString(), + aUnoMacroTbl, aUnoMacroParamTbl ); + break; + } + + if( bSetEvent ) + { + String sEvent( pOption->GetString() ); + if( sEvent.Len() ) + { + sEvent.ConvertLineEnd(); + if( EXTENDED_STYPE==eScriptType2 ) + aScriptType = rDfltScriptType; + aMacroTbl.Insert( nEvent, new SvxMacro( sEvent, aScriptType, + eScriptType2 ) ); + } + } + } + + + const uno::Reference< lang::XMultiServiceFactory > & rSrvcMgr = + pFormImpl->GetServiceFactory(); + if( !rSrvcMgr.is() ) + { + FinishTextArea(); + return; + } + uno::Reference< uno::XInterface > xInt = rSrvcMgr->createInstance( + OUString::createFromAscii( "com.sun.star.form.component.TextField" ) ); + if( !xInt.is() ) + { + FinishTextArea(); + return; + } + + uno::Reference< XFormComponent > xFComp( xInt, UNO_QUERY ); + DBG_ASSERT( xFComp.is(), "keine FormComponent?" ); + + uno::Reference< beans::XPropertySet > xPropSet( xFComp, UNO_QUERY ); + + Any aTmp; + aTmp <<= OUString(sName); + xPropSet->setPropertyValue( OUString::createFromAscii( "Name" ), aTmp ); + + sal_Bool bTrue = sal_True; + aTmp.setValue( &bTrue, ::getBooleanCppuType() ); + xPropSet->setPropertyValue( OUString::createFromAscii( "MultiLine" ), + aTmp ); + xPropSet->setPropertyValue( OUString::createFromAscii( "VScroll" ), aTmp ); + if( HTML_WM_OFF == nWrap ) + xPropSet->setPropertyValue( OUString::createFromAscii( "HScroll" ), + aTmp ); + if( HTML_WM_HARD == nWrap ) + xPropSet->setPropertyValue( + OUString::createFromAscii( "HardLineBreaks" ), aTmp ); + + if( nTabIndex >= TABINDEX_MIN && nTabIndex <= TABINDEX_MAX ) + { + aTmp <<= (sal_Int16)nTabIndex ; + xPropSet->setPropertyValue( OUString::createFromAscii( "TabIndex" ), + aTmp ); + } + + lcl_html_setFixedFontProperty( xPropSet ); + + if( bDisabled ) + { + sal_Bool bFalse = sal_False; + aTmp.setValue( &bFalse, ::getBooleanCppuType() ); + xPropSet->setPropertyValue( OUString::createFromAscii( "Enabled" ), + aTmp ); + } + + ASSERT( !pFormImpl->GetText().Len(), "Text ist nicht leer!" ); + + if( !nCols ) + nCols = 20; + if( !nRows ) + nRows = 1; + + Size aTextSz( nCols, nRows ); + + SfxItemSet aCSS1ItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aCSS1PropInfo; + if( HasStyleOptions( aStyle, aId, aClass ) ) + { + ParseStyleOptions( aStyle, aId, aClass, aCSS1ItemSet, aCSS1PropInfo ); + if( aId.Len() ) + InsertBookmark( aId ); + } + + Size aSz( MINFLY, MINFLY ); + if( SVX_CSS1_LTYPE_TWIP== aCSS1PropInfo.eWidthType ) + { + aSz.Width() = TWIP_TO_MM100( aCSS1PropInfo.nWidth ); + aTextSz.Width() = 0; + } + if( SVX_CSS1_LTYPE_TWIP== aCSS1PropInfo.eHeightType ) + { + aSz.Height() = TWIP_TO_MM100( aCSS1PropInfo.nHeight ); + aTextSz.Height() = 0; + } + if( aSz.Width() < MINFLY ) + aSz.Width() = MINFLY; + if( aSz.Height() < MINFLY ) + aSz.Height() = MINFLY; + + uno::Reference< drawing::XShape > xShape = InsertControl( xFComp, xPropSet, aSz, + text::VertOrientation::TOP, text::HoriOrientation::NONE, + aCSS1ItemSet, aCSS1PropInfo, + aMacroTbl, aUnoMacroTbl, + aUnoMacroParamTbl ); + if( aTextSz.Width() || aTextSz.Height() ) + SetControlSize( xShape, aTextSz, sal_False, sal_False, + HTML_TEXTAREA_ON ); + + // einen neuen Kontext anlegen + _HTMLAttrContext *pCntxt = new _HTMLAttrContext( HTML_TEXTAREA_ON ); + + // und PRE/Listing/XMP voruebergehend aussetzen + SplitPREListingXMP( pCntxt ); + PushContext( pCntxt ); + + bTextArea = sal_True; + bTAIgnoreNewPara = sal_True; +} + +void SwHTMLParser::EndTextArea() +{ + ASSERT( bTextArea, "keine TextArea oder falscher Typ" ); + ASSERT( pFormImpl && pFormImpl->GetFCompPropSet().is(), + "TextArea fehlt" ); + + const uno::Reference< beans::XPropertySet > & rPropSet = + pFormImpl->GetFCompPropSet(); + + Any aTmp; + aTmp <<= OUString(pFormImpl->GetText()); + rPropSet->setPropertyValue( OUString::createFromAscii( "DefaultText" ), + aTmp ); + pFormImpl->EraseText(); + + pFormImpl->ReleaseFCompPropSet(); + + // den Kontext holen + _HTMLAttrContext *pCntxt = PopContext( HTML_TEXTAREA_ON ); + if( pCntxt ) + { + // und ggf. die Attribute beenden + EndContext( pCntxt ); + delete pCntxt; + } + + bTextArea = sal_False; +} + + +void SwHTMLParser::InsertTextAreaText( sal_uInt16 nToken ) +{ + ASSERT( bTextArea, "keine TextArea oder falscher Typ" ); + ASSERT( pFormImpl && pFormImpl->GetFCompPropSet().is(), + "TextArea fehlt" ); + + String& rText = pFormImpl->GetText(); + switch( nToken) + { + case HTML_TEXTTOKEN: + rText += aToken; + break; + case HTML_NEWPARA: + if( !bTAIgnoreNewPara ) + rText += '\n'; // das ist hier richtig!!! + break; + default: + rText += '<'; + rText += sSaveToken; + if( aToken.Len() ) + { + rText += ' '; + rText += aToken; + } + rText += '>'; + } + + bTAIgnoreNewPara = sal_False; +} + +void SwHTMLParser::NewSelect() +{ + if( pPendStack ) + { + SetPendingControlSize( HTML_SELECT_ON ); + return; + } + + ASSERT( !bSelect, "Select in Select???" ); + ASSERT( !pFormImpl || !pFormImpl->GetFCompPropSet().is(), + "Select in Control???" ); + + if( !pFormImpl || !pFormImpl->GetFormComps().is() ) + return; + + String aId, aClass, aStyle; + String sName; + sal_Int32 nTabIndex = TABINDEX_MAX + 1; + SvxMacroTableDtor aMacroTbl; + SvStringsDtor aUnoMacroTbl; + SvStringsDtor aUnoMacroParamTbl; + sal_Bool bMultiple = sal_False; + sal_Bool bDisabled = sal_False; + nSelectEntryCnt = 1; + SvKeyValueIterator *pHeaderAttrs = pFormImpl->GetHeaderAttrs(); + ScriptType eDfltScriptType = GetScriptType( pHeaderAttrs ); + const String& rDfltScriptType = GetScriptTypeString( pHeaderAttrs ); + + const HTMLOptions *pHTMLOptions = GetOptions(); + for( sal_uInt16 i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + ScriptType eScriptType2 = eDfltScriptType; + sal_uInt16 nEvent = 0; + sal_Bool bSetEvent = sal_False; + + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + case HTML_O_NAME: + sName = pOption->GetString(); + break; + case HTML_O_MULTIPLE: + bMultiple = sal_True; + break; + case HTML_O_DISABLED: + bDisabled = sal_True; + break; + case HTML_O_SIZE: + nSelectEntryCnt = (sal_uInt16)pOption->GetNumber(); + break; + + case HTML_O_TABINDEX: + nTabIndex = pOption->GetSNumber(); + break; + + case HTML_O_SDONFOCUS: + eScriptType2 = STARBASIC; + case HTML_O_ONFOCUS: + nEvent = HTML_ET_ONGETFOCUS; + bSetEvent = sal_True; + break; + + case HTML_O_SDONBLUR: + eScriptType2 = STARBASIC; + case HTML_O_ONBLUR: + nEvent = HTML_ET_ONLOSEFOCUS; + bSetEvent = sal_True; + break; + + case HTML_O_SDONCLICK: + eScriptType2 = STARBASIC; + case HTML_O_ONCLICK: + nEvent = HTML_ET_ONCLICK; + bSetEvent = sal_True; + break; + + case HTML_O_SDONCHANGE: + eScriptType2 = STARBASIC; + case HTML_O_ONCHANGE: + nEvent = HTML_ET_ONCHANGE; + bSetEvent = sal_True; + break; + + default: + lcl_html_getEvents( pOption->GetTokenString(), + pOption->GetString(), + aUnoMacroTbl, aUnoMacroParamTbl ); + break; + } + + if( bSetEvent ) + { + String sEvent( pOption->GetString() ); + if( sEvent.Len() ) + { + sEvent.ConvertLineEnd(); + if( EXTENDED_STYPE==eScriptType2 ) + aScriptType = rDfltScriptType; + aMacroTbl.Insert( nEvent, new SvxMacro( sEvent, aScriptType, + eScriptType2 ) ); + } + } + } + + const uno::Reference< lang::XMultiServiceFactory > & rSrvcMgr = + pFormImpl->GetServiceFactory(); + if( !rSrvcMgr.is() ) + { + FinishTextArea(); + return; + } + uno::Reference< uno::XInterface > xInt = rSrvcMgr->createInstance( + OUString::createFromAscii( "com.sun.star.form.component.ListBox" ) ); + if( !xInt.is() ) + { + FinishTextArea(); + return; + } + + uno::Reference< XFormComponent > xFComp( xInt, UNO_QUERY ); + DBG_ASSERT(xFComp.is(), "keine FormComponent?"); + + uno::Reference< beans::XPropertySet > xPropSet( xFComp, UNO_QUERY ); + + Any aTmp; + aTmp <<= OUString(sName); + xPropSet->setPropertyValue( OUString::createFromAscii( "Name" ), aTmp ); + + if( nTabIndex >= TABINDEX_MIN && nTabIndex <= TABINDEX_MAX ) + { + aTmp <<= (sal_Int16)nTabIndex ; + xPropSet->setPropertyValue( OUString::createFromAscii( "TabIndex" ), + aTmp ); + } + + if( bDisabled ) + { + sal_Bool bFalse = sal_False; + aTmp.setValue( &bFalse, ::getBooleanCppuType() ); + xPropSet->setPropertyValue( OUString::createFromAscii( "Enabled" ), + aTmp ); + } + + Size aTextSz( 0, 0 ); + sal_Bool bMinWidth = sal_True, bMinHeight = sal_True; + if( !bMultiple && 1==nSelectEntryCnt ) + { + sal_Bool bTrue = sal_True; + aTmp.setValue( &bTrue, ::getBooleanCppuType() ); + xPropSet->setPropertyValue( OUString::createFromAscii( "Dropdown" ), + aTmp ); + } + else + { + if( nSelectEntryCnt <= 1 ) // 4 Zeilen als default + nSelectEntryCnt = 4; + + if( bMultiple ) + { + sal_Bool bTrue = sal_True; + aTmp.setValue( &bTrue, ::getBooleanCppuType() ); + xPropSet->setPropertyValue( + OUString::createFromAscii( "MultiSelection" ), aTmp ); + } + aTextSz.Height() = nSelectEntryCnt; + bMinHeight = sal_False; + } + + SfxItemSet aCSS1ItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aCSS1PropInfo; + if( HasStyleOptions( aStyle, aId, aClass ) ) + { + ParseStyleOptions( aStyle, aId, aClass, aCSS1ItemSet, aCSS1PropInfo ); + if( aId.Len() ) + InsertBookmark( aId ); + } + + Size aSz( MINFLY, MINFLY ); + bFixSelectWidth = bFixSelectHeight = sal_True; + if( SVX_CSS1_LTYPE_TWIP== aCSS1PropInfo.eWidthType ) + { + aSz.Width() = TWIP_TO_MM100( aCSS1PropInfo.nWidth ); + bFixSelectWidth = sal_False; + bMinWidth = sal_False; + } + if( SVX_CSS1_LTYPE_TWIP== aCSS1PropInfo.eHeightType ) + { + aSz.Height() = TWIP_TO_MM100( aCSS1PropInfo.nHeight ); + aTextSz.Height() = sal_False; + bMinHeight = sal_False; + } + if( aSz.Width() < MINFLY ) + aSz.Width() = MINFLY; + if( aSz.Height() < MINFLY ) + aSz.Height() = MINFLY; + + uno::Reference< drawing::XShape > xShape = InsertControl( xFComp, xPropSet, aSz, + text::VertOrientation::TOP, text::HoriOrientation::NONE, + aCSS1ItemSet, aCSS1PropInfo, + aMacroTbl, aUnoMacroTbl, + aUnoMacroParamTbl ); + if( bFixSelectWidth ) + pFormImpl->SetShape( xShape ); + if( aTextSz.Height() || bMinWidth || bMinHeight ) + SetControlSize( xShape, aTextSz, bMinWidth, bMinHeight, + HTML_SELECT_ON ); + + // einen neuen Kontext anlegen + _HTMLAttrContext *pCntxt = new _HTMLAttrContext( HTML_SELECT_ON ); + + // und PRE/Listing/XMP voruebergehend aussetzen + SplitPREListingXMP( pCntxt ); + PushContext( pCntxt ); + + bSelect = sal_True; +} + +void SwHTMLParser::EndSelect() +{ + if( pPendStack ) + { + SetPendingControlSize( HTML_SELECT_OFF ); + return; + } + + ASSERT( bSelect, "keine Select" ); + ASSERT( pFormImpl && pFormImpl->GetFCompPropSet().is(), + "kein Select-Control" ); + + const uno::Reference< beans::XPropertySet > & rPropSet = + pFormImpl->GetFCompPropSet(); + + // die Groesse anpassen + Size aNewSz( MINFLY, MINFLY ); + + sal_uInt16 nEntryCnt = pFormImpl->GetStringList().Count(); + if( nEntryCnt ) + { + Sequence<OUString> aList( (sal_Int32)nEntryCnt ); + Sequence<OUString> aValueList( (sal_Int32)nEntryCnt ); + OUString *pStrings = aList.getArray(); + OUString *pValues = aValueList.getArray(); + sal_uInt16 i; + + for( i = 0; i < nEntryCnt; i++ ) + { + String sText( *pFormImpl->GetStringList()[i] ); + sText.EraseTrailingChars(); + pStrings[i] = sText; + + sText = *pFormImpl->GetValueList()[i]; + pValues[i] = sText; + } + + Any aAny( &aList, ::getCppuType((uno::Sequence<OUString>*)0) ); + + rPropSet->setPropertyValue( + OUString::createFromAscii( "StringItemList" ), aAny ); + + aAny <<= ListSourceType_VALUELIST; + rPropSet->setPropertyValue( + OUString::createFromAscii( "ListSourceType" ), aAny ); + + aAny.setValue( &aValueList, ::getCppuType((uno::Sequence<OUString>*)0) ); + + rPropSet->setPropertyValue( OUString::createFromAscii( "ListSource" ), + aAny ); + + sal_uInt16 nSelCnt = pFormImpl->GetSelectedList().Count(); + if( !nSelCnt && 1 == nSelectEntryCnt && nEntryCnt ) + { + // In einer DropDown-Listbox sollte immer ein Eintrag selektiert + // sein. + pFormImpl->GetSelectedList().Insert( (sal_uInt16)0, (sal_uInt16)0 ); + nSelCnt = 1; + } + Sequence<sal_Int16> aSelList( (sal_Int32)nSelCnt ); + sal_Int16 *pSels = aSelList.getArray(); + for( i=0; i<nSelCnt; i++ ) + { + pSels[i] = (sal_Int16)pFormImpl->GetSelectedList()[i]; + } + aAny.setValue( &aSelList, + ::getCppuType((uno::Sequence<sal_Int16>*)0) ); + + rPropSet->setPropertyValue( + OUString::createFromAscii( "DefaultSelection" ), aAny ); + + pFormImpl->EraseStringList(); + pFormImpl->EraseValueList(); + } + + pFormImpl->EraseSelectedList(); + + if( bFixSelectWidth ) + { + ASSERT( pFormImpl->GetShape().is(), "Kein Shape gemerkt" ); + Size aTextSz( -1, 0 ); + SetControlSize( pFormImpl->GetShape(), aTextSz, sal_False, sal_False, + HTML_SELECT_OFF ); + } + + pFormImpl->ReleaseFCompPropSet(); + + // den Kontext holen + _HTMLAttrContext *pCntxt = PopContext( HTML_SELECT_ON ); + if( pCntxt ) + { + // und ggf. die Attribute beenden + EndContext( pCntxt ); + delete pCntxt; + } + + bSelect = sal_False; +} + +void SwHTMLParser::InsertSelectOption() +{ + ASSERT( bSelect, "keine Select" ); + ASSERT( pFormImpl && pFormImpl->GetFCompPropSet().is(), + "kein Select-Control" ); + + bLBEntrySelected = sal_False; + String aValue; + + const HTMLOptions *pHTMLOptions = GetOptions(); + for( sal_uInt16 i = pHTMLOptions->Count(); i; ) + { + HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_ID: + // erstmal weglassen!!! + break; + case HTML_O_SELECTED: + bLBEntrySelected = sal_True; + break; + case HTML_O_VALUE: + aValue = pOption->GetString(); + if( !aValue.Len() ) + aValue.AssignAscii( "$$$empty$$$" ); + break; + } + } + + sal_uInt16 nEntryCnt = pFormImpl->GetStringList().Count(); + pFormImpl->GetStringList().Insert( new String( aEmptyStr ), nEntryCnt ); + pFormImpl->GetValueList().Insert( new String( aValue ), nEntryCnt ); + if( bLBEntrySelected ) + pFormImpl->GetSelectedList().Insert( nEntryCnt, + pFormImpl->GetSelectedList().Count() ); +} + +void SwHTMLParser::InsertSelectText() +{ + ASSERT( bSelect, "keine Select" ); + ASSERT( pFormImpl && pFormImpl->GetFCompPropSet().is(), + "kein Select-Control" ); + + sal_uInt16 nEntryCnt = pFormImpl->GetStringList().Count(); + if( nEntryCnt ) + { + String& rText = *pFormImpl->GetStringList()[nEntryCnt-1]; + + if( aToken.Len() && ' '==aToken.GetChar( 0 ) ) + { + xub_StrLen nLen = rText.Len(); + if( !nLen || ' '==rText.GetChar( nLen-1 )) + aToken.Erase( 0, 1 ); + } + if( aToken.Len() ) + rText += aToken; + } +} + diff --git a/sw/source/filter/html/htmlform.hxx b/sw/source/filter/html/htmlform.hxx new file mode 100644 index 000000000000..2deac9db0b5c --- /dev/null +++ b/sw/source/filter/html/htmlform.hxx @@ -0,0 +1,52 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _HTMLFORM_HXX +#define _HTMLFORM_HXX + + +enum HTMLEventType +{ + HTML_ET_ONSUBMITFORM, HTML_ET_ONRESETFORM, + HTML_ET_ONGETFOCUS, HTML_ET_ONLOSEFOCUS, + HTML_ET_ONCLICK, HTML_ET_ONCLICK_ITEM, + HTML_ET_ONCHANGE, HTML_ET_ONSELECT, + HTML_ET_END +}; + +extern HTMLEventType __FAR_DATA aEventTypeTable[]; +extern const sal_Char * __FAR_DATA aEventListenerTable[]; +extern const sal_Char * __FAR_DATA aEventMethodTable[]; +extern const sal_Char * __FAR_DATA aEventSDOptionTable[]; +extern const sal_Char * __FAR_DATA aEventOptionTable[]; + + + + +#endif + + diff --git a/sw/source/filter/html/htmlforw.cxx b/sw/source/filter/html/htmlforw.cxx new file mode 100644 index 000000000000..d44a543dfa5a --- /dev/null +++ b/sw/source/filter/html/htmlforw.cxx @@ -0,0 +1,1447 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/form/FormSubmitEncoding.hpp> +#include <com/sun/star/form/FormSubmitMethod.hpp> +#include <com/sun/star/form/FormButtonType.hpp> +#include <com/sun/star/script/XEventAttacher.hpp> +#include <com/sun/star/script/XEventAttacherManager.hpp> +#include <com/sun/star/drawing/XDrawPageSupplier.hpp> +#include <com/sun/star/form/XFormsSupplier.hpp> +#include <com/sun/star/form/XForm.hpp> +#include <com/sun/star/form/FormComponentType.hpp> +#include <com/sun/star/awt/XTextLayoutConstrains.hpp> +#include <hintids.hxx> +#include <vcl/svapp.hxx> +#include <vcl/wrkwin.hxx> +#include <svl/macitem.hxx> +#include <tools/urlobj.hxx> +#include <svtools/htmlout.hxx> +#include <svtools/htmltokn.h> +#include <svtools/htmlkywd.hxx> +#include <svl/urihelper.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <svx/svdouno.hxx> +#include <svx/fmglob.hxx> +#include <editeng/brshitem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/crsditem.hxx> +#include <docsh.hxx> +#include <fmtanchr.hxx> +#include <docary.hxx> +#include <viewsh.hxx> +#include "pam.hxx" +#include "doc.hxx" +#include "ndtxt.hxx" +#include "dcontact.hxx" +#include "flypos.hxx" +#include "wrthtml.hxx" +#include "htmlfly.hxx" +#include "htmlform.hxx" + + +using namespace ::com::sun::star; +using ::rtl::OUString; +/* */ + +const sal_uInt32 HTML_FRMOPTS_CONTROL = + 0; +const sal_uInt32 HTML_FRMOPTS_CONTROL_CSS1 = + HTML_FRMOPT_S_ALIGN | + HTML_FRMOPT_S_SIZE | + HTML_FRMOPT_S_SPACE | + HTML_FRMOPT_BRCLEAR; +const sal_uInt32 HTML_FRMOPTS_IMG_CONTROL = + HTML_FRMOPT_ALIGN | + HTML_FRMOPT_BRCLEAR; +const sal_uInt32 HTML_FRMOPTS_IMG_CONTROL_CSS1 = + HTML_FRMOPT_S_ALIGN | + HTML_FRMOPT_S_SPACE; + + +/* */ + +struct HTMLControl +{ + // die Form, zu der das Control gehoert + uno::Reference< container::XIndexContainer > xFormComps; + sal_uLong nNdIdx; // der Node, in dem es verankert ist + xub_StrLen nCount; // wie viele Controls sind in dem Node + + HTMLControl( const uno::Reference< container::XIndexContainer > & rForm, + sal_uInt32 nIdx ); + ~HTMLControl(); + + // operatoren fuer das Sort-Array + sal_Bool operator==( const HTMLControl& rCtrl ) + { + return nNdIdx == rCtrl.nNdIdx; + } + sal_Bool operator<( const HTMLControl& rCtrl ) + { + return nNdIdx < rCtrl.nNdIdx; + } +}; + +SV_IMPL_OP_PTRARR_SORT( HTMLControls, HTMLControl* ) + +/* */ + +void lcl_html_outEvents( SvStream& rStrm, + const uno::Reference< form::XFormComponent > rFormComp, + sal_Bool bCfgStarBasic, + rtl_TextEncoding eDestEnc, + String *pNonConvertableChars ) +{ + uno::Reference< container::XChild > xChild( rFormComp, uno::UNO_QUERY ); + uno::Reference< uno::XInterface > xParentIfc = xChild->getParent(); + ASSERT( xParentIfc.is(), "lcl_html_outEvents: no parent interface" ); + if( !xParentIfc.is() ) + return; + uno::Reference< container::XIndexAccess > xIndexAcc( xParentIfc, uno::UNO_QUERY ); + uno::Reference< script::XEventAttacherManager > xEventManager( xParentIfc, + uno::UNO_QUERY ); + if( !xIndexAcc.is() || !xEventManager.is() ) + return; + + // Und die Position des ControlModel darin suchen + sal_Int32 nCount = xIndexAcc->getCount(), nPos; + for( nPos = 0 ; nPos < nCount; nPos++ ) + { + uno::Any aTmp = xIndexAcc->getByIndex(nPos); + ASSERT( aTmp.getValueType() == + ::getCppuType( (uno::Reference<form::XFormComponent>*)0 ) || + aTmp.getValueType() == + ::getCppuType( (uno::Reference<form::XForm>*)0 ), + "lcl_html_outEvents: falsche Reflection" ); + if( aTmp.getValueType() == + ::getCppuType( (uno::Reference< form::XFormComponent >*)0) ) + + { + if( rFormComp == + *(uno::Reference< form::XFormComponent > *)aTmp.getValue() ) + break; + } + else if( aTmp.getValueType() == + ::getCppuType( (uno::Reference< form::XForm>*)0) ) + { + uno::Reference< form::XFormComponent > xFC( + *(uno::Reference< form::XForm > *)aTmp.getValue(), uno::UNO_QUERY ); + if( rFormComp == xFC ) + break; + } + } + + if( nPos == nCount ) + return; + + uno::Sequence< script::ScriptEventDescriptor > aDescs = + xEventManager->getScriptEvents( nPos ); + nCount = aDescs.getLength(); + if( !nCount ) + return; + + const script::ScriptEventDescriptor *pDescs = aDescs.getConstArray(); + for( sal_Int32 i = 0; i < nCount; i++ ) + { + ScriptType eScriptType = EXTENDED_STYPE; + String aScriptType( pDescs[i].ScriptType ); + if( aScriptType.EqualsIgnoreCaseAscii(SVX_MACRO_LANGUAGE_JAVASCRIPT) ) + eScriptType = JAVASCRIPT; + else if( aScriptType.EqualsIgnoreCaseAscii(SVX_MACRO_LANGUAGE_STARBASIC ) ) + eScriptType = STARBASIC; + if( JAVASCRIPT != eScriptType && !bCfgStarBasic ) + continue; + + String sListener( pDescs[i].ListenerType ); + xub_StrLen nTok = sListener.GetTokenCount( '.' ); + if( nTok ) + sListener = sListener.GetToken( nTok-1, '.' ); + String sMethod( pDescs[i].EventMethod ); + + const sal_Char *pOpt = 0; + for( sal_uInt16 j=0; aEventListenerTable[j]; j++ ) + { + if( sListener.EqualsAscii( aEventListenerTable[j] ) && + sMethod.EqualsAscii( aEventMethodTable[j] ) ) + { + pOpt = (STARBASIC==eScriptType ? aEventSDOptionTable + : aEventOptionTable)[j]; + break; + } + } + + ByteString sOut( ' ' ); + if( pOpt && (EXTENDED_STYPE != eScriptType || + !pDescs[i].AddListenerParam.getLength()) ) + sOut += pOpt; + else + (((sOut += OOO_STRING_SVTOOLS_HTML_O_sdevent) + += ByteString( sListener, RTL_TEXTENCODING_ASCII_US)) += '-') + += ByteString( sMethod, RTL_TEXTENCODING_ASCII_US); + sOut += "=\""; + rStrm << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( rStrm, pDescs[i].ScriptCode, eDestEnc, pNonConvertableChars ); + rStrm << '\"'; + if( EXTENDED_STYPE == eScriptType && + pDescs[i].AddListenerParam.getLength() ) + { + (((((sOut = ' ') += OOO_STRING_SVTOOLS_HTML_O_sdaddparam) + += ByteString( sListener, RTL_TEXTENCODING_ASCII_US)) += '-') + += ByteString( sMethod, RTL_TEXTENCODING_ASCII_US)) + += "=\""; + rStrm << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( rStrm, pDescs[i].AddListenerParam, + eDestEnc, pNonConvertableChars ); + rStrm << '\"'; + } + } +} + +sal_Bool lcl_html_isHTMLControl( sal_Int16 nClassId ) +{ + sal_Bool bRet = sal_False; + + switch( nClassId ) + { + case form::FormComponentType::TEXTFIELD: + case form::FormComponentType::COMMANDBUTTON: + case form::FormComponentType::RADIOBUTTON: + case form::FormComponentType::CHECKBOX: + case form::FormComponentType::LISTBOX: + case form::FormComponentType::IMAGEBUTTON: + case form::FormComponentType::FILECONTROL: + bRet = sal_True; + break; + } + + return bRet; +} + +sal_Bool SwHTMLWriter::HasControls() const +{ + sal_uInt32 nStartIdx = pCurPam->GetPoint()->nNode.GetIndex(); + sal_uInt16 i; + + // Skip all controls in front of the current paragraph + for( i = 0; i < aHTMLControls.Count() && + aHTMLControls[i]->nNdIdx < nStartIdx; i++ ) + ; + + return i < aHTMLControls.Count() && aHTMLControls[i]->nNdIdx == nStartIdx; +} + +void SwHTMLWriter::OutForm( sal_Bool bTag_On, const SwStartNode *pStartNd ) +{ + if( bPreserveForm ) // wir sind in einer Tabelle oder einem Bereich + return; // ueber dem eine Form aufgespannt wurde + + if( !bTag_On ) + { + // die Form beenden wenn alle Controls ausgegeben wurden + if( pxFormComps && pxFormComps->is() && + (*pxFormComps)->getCount() == nFormCntrlCnt ) + { + OutForm( sal_False, *pxFormComps ); + (*pxFormComps) = 0; + } + return; + } + + uno::Reference< container::XIndexContainer > xNewFormComps; // die neue Form + sal_uInt32 nStartIdx = pStartNd ? pStartNd->GetIndex() + : pCurPam->GetPoint()->nNode.GetIndex(); + + // Ueberspringen von Controls vor dem interesanten Bereich + sal_uInt16 i; + for( i = 0; i < aHTMLControls.Count() && + aHTMLControls[i]->nNdIdx < nStartIdx; i++ ) + ; + + if( !pStartNd ) + { + // Check fuer einen einzelnen Node: da ist nur interessant, ob + // es zu dem Node ein Control gibt und zu welcher Form es gehoert + if( i < aHTMLControls.Count() && + aHTMLControls[i]->nNdIdx == nStartIdx ) + xNewFormComps = aHTMLControls[i]->xFormComps; + } + else + { + // wir klappern eine Tabelle/einen Bereich ab: hier interessiert uns: + // - ob es Controls mit unterschiedlichen Start-Nodes gibt + // - ob es eine Form gibt, fuer die nicht alle Controls in der + // Tabelle/dem Bereich liegen + + uno::Reference< container::XIndexContainer > xCurrentFormComps;// die aktuelle Form in der Tabelle + const SwStartNode *pCurrentStNd = 0; // und der Start-Node eines Ctrls + xub_StrLen nCurrentCtrls = 0; // und die in ihr gefundenen Controls + sal_uInt32 nEndIdx = pStartNd->EndOfSectionIndex(); + for( ; i < aHTMLControls.Count() && + aHTMLControls[i]->nNdIdx <= nEndIdx; i++ ) + { + const SwStartNode *pCntrlStNd = + pDoc->GetNodes()[aHTMLControls[i]->nNdIdx]->StartOfSectionNode(); + + if( xCurrentFormComps.is() ) + { + // Wir befinden uns bereits in einer Form ... + if( xCurrentFormComps==aHTMLControls[i]->xFormComps ) + { + // ... und das Control befindet sich auch darin ... + if( pCurrentStNd!=pCntrlStNd ) + { + // ... aber es liegt in einer anderen Zelle: + // Dann muessen eir eine Form ueber der Tabelle + // aufmachen + xNewFormComps = xCurrentFormComps; + break; + } + nCurrentCtrls = nCurrentCtrls + aHTMLControls[i]->nCount; + } + else + { + // ... aber das Control liegt in einer anderen Zelle: + // Da tun wir so, als ob wir eine neue Form aufmachen + // und suchen weiter. + xCurrentFormComps = aHTMLControls[i]->xFormComps; + pCurrentStNd = pCntrlStNd; + nCurrentCtrls = aHTMLControls[i]->nCount; + } + } + else + { + // Wir befinden uns noch in keiner Form: + // Da tun wir mal so, als ob wie wir die Form aufmachen. + xCurrentFormComps = aHTMLControls[i]->xFormComps; + pCurrentStNd = pCntrlStNd; + nCurrentCtrls = aHTMLControls[i]->nCount; + } + } + if( !xNewFormComps.is() && xCurrentFormComps.is() && + nCurrentCtrls != xCurrentFormComps->getCount() ) + { + // In der Tablle/dem Bereich sollte eine Form aufgemacht werden, + // die nicht vollstaendig in der Tabelle liegt. Dan muessen + // wie die Form jetzt ebenfalls oeffen. + xNewFormComps = xCurrentFormComps; + } + } + + if( xNewFormComps.is() && + (!pxFormComps || !(xNewFormComps == *pxFormComps)) ) + { + // Es soll eine Form aufgemacht werden ... + if( pxFormComps && pxFormComps->is() ) + { + // .. es ist aber noch eine Form offen: Das ist in + // jedem Fall eine Fehler, aber wir schliessen die alte + // Form trotzdem + OutForm( sal_False, *pxFormComps ); + + //!!!nWarn = 1; // Control wird falscher Form zugeordnet + } + + if( !pxFormComps ) + pxFormComps = new uno::Reference< container::XIndexContainer > ; + *pxFormComps = xNewFormComps; + + OutForm( sal_True, *pxFormComps ); + uno::Reference< beans::XPropertySet > xTmp; + OutHiddenControls( *pxFormComps, xTmp ); + } +} + +void SwHTMLWriter::OutHiddenForms() +{ + // Ohne DrawModel kann es auch keine Controls geben. Dann darf man + // auch nicht per UNO auf das Dok zugreifen, weil sonst ein DrawModel + // angelegt wird. + if( !pDoc->GetDrawModel() ) + return; + + SwDocShell *pDocSh = pDoc->GetDocShell(); + if( !pDocSh ) + return; + + uno::Reference< drawing::XDrawPageSupplier > xDPSupp( pDocSh->GetBaseModel(), + uno::UNO_QUERY ); + ASSERT( xDPSupp.is(), "XTextDocument nicht vom XModel erhalten" ); + uno::Reference< drawing::XDrawPage > xDrawPage = xDPSupp->getDrawPage(); + + ASSERT( xDrawPage.is(), "XDrawPage nicht erhalten" ); + if( !xDrawPage.is() ) + return; + + uno::Reference< form::XFormsSupplier > xFormsSupplier( xDrawPage, uno::UNO_QUERY ); + ASSERT( xFormsSupplier.is(), + "XFormsSupplier nicht vom XDrawPage erhalten" ); + + uno::Reference< container::XNameContainer > xTmp = xFormsSupplier->getForms(); + ASSERT( xTmp.is(), "XForms nicht erhalten" ); + uno::Reference< container::XIndexContainer > xForms( xTmp, uno::UNO_QUERY ); + ASSERT( xForms.is(), "XForms ohne container::XIndexContainer?" ); + + sal_Int32 nCount = xForms->getCount(); + for( sal_Int32 i=0; i<nCount; i++) + { + uno::Any aTmp = xForms->getByIndex( i ); + ASSERT( aTmp.getValueType() == + ::getCppuType((uno::Reference< form::XForm >*)0), + "OutHiddenForms: falsche Reflection" ); + if( aTmp.getValueType() == + ::getCppuType((uno::Reference< form::XForm >*)0) ) + OutHiddenForm( *(uno::Reference< form::XForm > *)aTmp.getValue() ); + } +} + +void SwHTMLWriter::OutHiddenForm( const uno::Reference< form::XForm > & rForm ) +{ + uno::Reference< container::XIndexContainer > xFormComps( rForm, uno::UNO_QUERY ); + if( !xFormComps.is() ) + return; + + sal_Int32 nCount = xFormComps->getCount(); + sal_Bool bHiddenOnly = nCount > 0, bHidden = sal_False; + for( sal_Int32 i=0; i<nCount; i++ ) + { + uno::Any aTmp = xFormComps->getByIndex( i ); + ASSERT( aTmp.getValueType() == + ::getCppuType((uno::Reference<form::XFormComponent>*)0), + "OutHiddenForm: falsche Reflection" ); + if( aTmp.getValueType() != + ::getCppuType((uno::Reference<form::XFormComponent>*)0) ) + continue; + + uno::Reference< form::XFormComponent > xFormComp = + *(uno::Reference< form::XFormComponent > *)aTmp.getValue(); + uno::Reference< form::XForm > xForm( xFormComp, uno::UNO_QUERY ); + if( xForm.is() ) + OutHiddenForm( xForm ); + + if( bHiddenOnly ) + { + uno::Reference< beans::XPropertySet > xPropSet( xFormComp, uno::UNO_QUERY ); + OUString sPropName = OUString::createFromAscii( "ClassId" ); + if( xPropSet->getPropertySetInfo()->hasPropertyByName( sPropName ) ) + { + uno::Any aAny2 = xPropSet->getPropertyValue( sPropName ); + if( aAny2.getValueType() == ::getCppuType((sal_Int16*)0) ) + { + if( form::FormComponentType::HIDDENCONTROL == + *(sal_Int16*)aAny2.getValue() ) + bHidden = sal_True; + else if( lcl_html_isHTMLControl( + *(sal_Int16*)aAny2.getValue() ) ) + bHiddenOnly = sal_False; + } + } + } + } + + if( bHidden && bHiddenOnly ) + { + OutForm( sal_True, xFormComps ); + uno::Reference< beans::XPropertySet > xTmp; + OutHiddenControls( xFormComps, xTmp ); + OutForm( sal_False, xFormComps ); + } +} + +void SwHTMLWriter::OutForm( sal_Bool bOn, + const uno::Reference< container::XIndexContainer > & rFormComps ) +{ + nFormCntrlCnt = 0; + + if( !bOn ) + { + DecIndentLevel(); // Inhalt der Form einruecken + if( bLFPossible ) + OutNewLine(); + HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_form, sal_False ); + bLFPossible = sal_True; + + return; + } + + // die neue Form wird geoeffnet + if( bLFPossible ) + OutNewLine(); + ByteString sOut( '<' ); + sOut += OOO_STRING_SVTOOLS_HTML_form; + + uno::Reference< beans::XPropertySet > xFormPropSet( rFormComps, uno::UNO_QUERY ); + + uno::Any aTmp = xFormPropSet->getPropertyValue( + OUString::createFromAscii( "Name" ) ); + if( aTmp.getValueType() == ::getCppuType((const OUString*)0) && + ((OUString*)aTmp.getValue())->getLength() ) + { + ((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_name) += "=\""; + Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( Strm(), *(OUString*)aTmp.getValue(), + eDestEnc, &aNonConvertableCharacters ); + sOut = '\"'; + } + + aTmp = xFormPropSet->getPropertyValue( + OUString::createFromAscii( "TargetURL" ) ); + if( aTmp.getValueType() == ::getCppuType((const OUString*)0) && + ((OUString*)aTmp.getValue())->getLength() ) + { + ((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_action) += "=\""; + Strm() << sOut.GetBuffer(); + String aURL( *(OUString*)aTmp.getValue() ); + aURL = URIHelper::simpleNormalizedMakeRelative( GetBaseURL(), aURL); + HTMLOutFuncs::Out_String( Strm(), aURL, eDestEnc, &aNonConvertableCharacters ); + sOut = '\"'; + } + + aTmp = xFormPropSet->getPropertyValue( + OUString::createFromAscii( "SubmitMethod" ) ); + if( aTmp.getValueType() == ::getCppuType((const form::FormSubmitMethod*)0) ) + { + form::FormSubmitMethod eMethod = + *( form::FormSubmitMethod*)aTmp.getValue(); + if( form::FormSubmitMethod_POST==eMethod ) + { + ((((sOut += ' ') + += OOO_STRING_SVTOOLS_HTML_O_method) += "=\"") + += OOO_STRING_SVTOOLS_HTML_METHOD_post) += '\"'; + } + } + aTmp = xFormPropSet->getPropertyValue( + OUString::createFromAscii( "SubmitEncoding" ) ); + if( aTmp.getValueType()==::getCppuType((const form::FormSubmitEncoding*)0) ) + { + form::FormSubmitEncoding eEncType = + *( form::FormSubmitEncoding*)aTmp.getValue(); + const sal_Char *pStr = 0; + switch( eEncType ) + { + case form::FormSubmitEncoding_MULTIPART: + pStr = OOO_STRING_SVTOOLS_HTML_ET_multipart; + break; + case form::FormSubmitEncoding_TEXT: + pStr = OOO_STRING_SVTOOLS_HTML_ET_text; + break; + default: + ; + } + + if( pStr ) + { + ((((sOut += ' ') + += OOO_STRING_SVTOOLS_HTML_O_enctype) += "=\"") + += pStr) += '\"'; + } + } + + aTmp = xFormPropSet->getPropertyValue( + OUString::createFromAscii( "TargetFrame" ) ); + if( aTmp.getValueType() == ::getCppuType((const OUString*)0)&& + ((OUString*)aTmp.getValue())->getLength() ) + { + ((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_target) += "=\""; + Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( Strm(), *(OUString*)aTmp.getValue(), + eDestEnc, &aNonConvertableCharacters ); + sOut = '\"'; + } + + Strm() << sOut.GetBuffer(); + uno::Reference< form::XFormComponent > xFormComp( rFormComps, uno::UNO_QUERY ); + lcl_html_outEvents( Strm(), xFormComp, bCfgStarBasic, eDestEnc, &aNonConvertableCharacters ); + Strm() << '>'; + + IncIndentLevel(); // Inhalt der Form einruecken + bLFPossible = sal_True; +} + +void SwHTMLWriter::OutHiddenControls( + const uno::Reference< container::XIndexContainer > & rFormComps, + const uno::Reference< beans::XPropertySet > & rPropSet ) +{ + sal_Int32 nCount = rFormComps->getCount(); + sal_Int32 nPos = 0; + sal_Bool bDone = sal_False; + if( rPropSet.is() ) + { + uno::Reference< form::XFormComponent > xFC( rPropSet, uno::UNO_QUERY ); + for( nPos=0; !bDone && nPos < nCount; nPos++ ) + { + uno::Any aTmp = rFormComps->getByIndex( nPos ); + ASSERT( aTmp.getValueType() == + ::getCppuType((uno::Reference< form::XFormComponent>*)0), + "OutHiddenControls: falsche Reflection" ); + bDone = aTmp.getValueType() == + ::getCppuType((uno::Reference< form::XFormComponent>*)0) && + *(uno::Reference< form::XFormComponent > *)aTmp.getValue() == + xFC; + } + } + + for( ; nPos < nCount; nPos++ ) + { + uno::Any aTmp = rFormComps->getByIndex( nPos ); + ASSERT( aTmp.getValueType() == + ::getCppuType((uno::Reference< form::XFormComponent>*)0), + "OutHiddenControls: falsche Reflection" ); + if( aTmp.getValueType() != + ::getCppuType((uno::Reference< form::XFormComponent>*)0) ) + continue; + uno::Reference< form::XFormComponent > xFC = + *(uno::Reference< form::XFormComponent > *)aTmp.getValue(); + uno::Reference< beans::XPropertySet > xPropSet( xFC, uno::UNO_QUERY ); + + OUString sPropName = OUString::createFromAscii( "ClassId" ); + if( !xPropSet->getPropertySetInfo()->hasPropertyByName( sPropName ) ) + continue; + + aTmp = xPropSet->getPropertyValue( sPropName ); + if( aTmp.getValueType() != ::getCppuType((const sal_Int16*)0) ) + continue; + + if( form::FormComponentType::HIDDENCONTROL == + *(sal_Int16*) aTmp.getValue() ) + { + if( bLFPossible ) + OutNewLine( sal_True ); + ByteString sOut( '<' ); + ((((sOut += OOO_STRING_SVTOOLS_HTML_input) += ' ') += + OOO_STRING_SVTOOLS_HTML_O_type) += '=') += OOO_STRING_SVTOOLS_HTML_IT_hidden; + + aTmp = xPropSet->getPropertyValue( + OUString::createFromAscii( "Name" ) ); + if( aTmp.getValueType() == ::getCppuType((const OUString*)0) && + ((OUString*)aTmp.getValue())->getLength() ) + { + (( sOut += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_name ) += "=\""; + Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( Strm(), *(OUString*)aTmp.getValue(), + eDestEnc, &aNonConvertableCharacters ); + sOut = '\"'; + } + aTmp = xPropSet->getPropertyValue( + OUString::createFromAscii( "HiddenValue" ) ); + if( aTmp.getValueType() == ::getCppuType((const OUString*)0) && + ((OUString*)aTmp.getValue())->getLength() ) + { + ((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_value) += "=\""; + Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( Strm(), *(OUString*)aTmp.getValue(), + eDestEnc, &aNonConvertableCharacters ); + sOut = '\"'; + } + sOut += '>'; + Strm() << sOut.GetBuffer(); + + nFormCntrlCnt++; + } + else if( lcl_html_isHTMLControl( *(sal_Int16*) aTmp.getValue() ) ) + { + break; + } + } +} + +/* */ + +// hier folgen die Ausgabe-Routinen, dadurch sind die form::Forms gebuendelt: + +const SdrObject *SwHTMLWriter::GetHTMLControl( const SwDrawFrmFmt& rFmt ) +{ + // es muss ein Draw-Format sein + ASSERT( RES_DRAWFRMFMT == rFmt.Which(), + "GetHTMLControl nuer fuer Draw-Formate erlaubt" ); + + // Schauen, ob es ein SdrObject dafuer gibt + const SdrObject *pObj = rFmt.FindSdrObject(); + if( !pObj || FmFormInventor != pObj->GetObjInventor() ) + return 0; + + SdrUnoObj *pFormObj = PTR_CAST( SdrUnoObj, pObj ); + uno::Reference< awt::XControlModel > xControlModel = + pFormObj->GetUnoControlModel(); + + ASSERT( xControlModel.is(), "UNO-Control ohne Model" ); + if( !xControlModel.is() ) + return 0; + + uno::Reference< beans::XPropertySet > xPropSet( xControlModel, uno::UNO_QUERY ); + + OUString sPropName = OUString::createFromAscii( "ClassId" ); + if( !xPropSet->getPropertySetInfo()->hasPropertyByName( sPropName ) ) + return 0; + + uno::Any aTmp = xPropSet->getPropertyValue( sPropName ); + if( aTmp.getValueType() == ::getCppuType((const sal_Int16*)0)&& + lcl_html_isHTMLControl( *(sal_Int16*) aTmp.getValue() ) ) + { + return pObj; + } + + return 0; +} + +static void GetControlSize( const SdrObject& rSdrObj, Size& rSz, + SwDoc *pDoc ) +{ + ViewShell *pVSh = 0; + pDoc->GetEditShell( &pVSh ); + if( !pVSh ) + return; + + SdrUnoObj *pFormObj = PTR_CAST( SdrUnoObj, &rSdrObj ); + uno::Reference< awt::XControl > xControl; + SdrView* pDrawView = pVSh->GetDrawView(); + ASSERT( pDrawView && pVSh->GetWin(), "no DrawView or window!" ); + if ( pDrawView && pVSh->GetWin() ) + xControl = pFormObj->GetUnoControl( *pDrawView, *pVSh->GetWin() ); + uno::Reference< awt::XTextLayoutConstrains > xLC( xControl, uno::UNO_QUERY ); + ASSERT( xLC.is(), "kein XTextLayoutConstrains" ); + if( !xLC.is() ) + return; + + sal_Int16 nCols=0, nLines=0; + xLC->getColumnsAndLines( nCols, nLines ); + rSz.Width() = nCols; + rSz.Height() = nLines; +} + +Writer& OutHTML_DrawFrmFmtAsControl( Writer& rWrt, + const SwDrawFrmFmt& rFmt, + const SdrObject& rSdrObject, + sal_Bool bInCntnr ) +{ + SwHTMLWriter & rHTMLWrt = (SwHTMLWriter&)rWrt; + + SdrUnoObj *pFormObj = PTR_CAST( SdrUnoObj, &rSdrObject ); + uno::Reference< awt::XControlModel > xControlModel = + pFormObj->GetUnoControlModel(); + + ASSERT( xControlModel.is(), "UNO-Control ohne Model" ); + if( !xControlModel.is() ) + return rWrt; + + uno::Reference< beans::XPropertySet > xPropSet( xControlModel, uno::UNO_QUERY ); + uno::Reference< beans::XPropertySetInfo > xPropSetInfo = + xPropSet->getPropertySetInfo(); + +//!!! if( rHTMLWrt.pForm != pVCSbxCtrl->GetVCForm() ) +//!!! rHTMLWrt.nWarn = 1; // Control wird falscher Form zugeordnet + rHTMLWrt.nFormCntrlCnt++; + + enum Tag { TAG_INPUT, TAG_SELECT, TAG_TEXTAREA, TAG_NONE }; + static char const * const TagNames[] = { + OOO_STRING_SVTOOLS_HTML_input, OOO_STRING_SVTOOLS_HTML_select, + OOO_STRING_SVTOOLS_HTML_textarea }; + Tag eTag = TAG_INPUT; + enum Type { + TYPE_TEXT, TYPE_PASSWORD, TYPE_CHECKBOX, TYPE_RADIO, TYPE_FILE, + TYPE_SUBMIT, TYPE_IMAGE, TYPE_RESET, TYPE_BUTTON, TYPE_NONE }; + static char const * const TypeNames[] = { + OOO_STRING_SVTOOLS_HTML_IT_text, OOO_STRING_SVTOOLS_HTML_IT_password, + OOO_STRING_SVTOOLS_HTML_IT_checkbox, OOO_STRING_SVTOOLS_HTML_IT_radio, + OOO_STRING_SVTOOLS_HTML_IT_file, OOO_STRING_SVTOOLS_HTML_IT_submit, + OOO_STRING_SVTOOLS_HTML_IT_image, OOO_STRING_SVTOOLS_HTML_IT_reset, + OOO_STRING_SVTOOLS_HTML_IT_button }; + Type eType = TYPE_NONE; + OUString sValue; + ByteString sOptions; + sal_Bool bEmptyValue = sal_False; + uno::Any aTmp = xPropSet->getPropertyValue( + OUString::createFromAscii( "ClassId" ) ); + sal_Int16 nClassId = *(sal_Int16*) aTmp.getValue(); + sal_uInt32 nFrmOpts = HTML_FRMOPTS_CONTROL; + switch( nClassId ) + { + case form::FormComponentType::CHECKBOX: + case form::FormComponentType::RADIOBUTTON: + eType = (form::FormComponentType::CHECKBOX == nClassId + ? TYPE_CHECKBOX : TYPE_RADIO); + aTmp = xPropSet->getPropertyValue( + OUString::createFromAscii( "DefaultState" ) ); + if( aTmp.getValueType() == ::getCppuType((const sal_Int16*)0) && + STATE_NOCHECK != *(sal_Int16*) aTmp.getValue() ) + { + (sOptions += ' ') += OOO_STRING_SVTOOLS_HTML_O_checked; + } + + aTmp = xPropSet->getPropertyValue( + OUString::createFromAscii( "RefValue" ) ); + if( aTmp.getValueType() == ::getCppuType((const OUString*)0) ) + + { + const OUString& rVal = *(OUString*)aTmp.getValue(); + if( !rVal.getLength() ) + bEmptyValue = sal_True; + else if( rVal.compareToAscii( OOO_STRING_SVTOOLS_HTML_on ) != 0 ) + sValue = rVal; + } + break; + + case form::FormComponentType::COMMANDBUTTON: + { + form::FormButtonType eButtonType = form::FormButtonType_PUSH; + aTmp = xPropSet->getPropertyValue( + OUString::createFromAscii( "ButtonType" ) ); + if( aTmp.getValueType() == + ::getCppuType((const form::FormButtonType*)0) ) + eButtonType = *( form::FormButtonType*)aTmp.getValue(); + + switch( eButtonType ) + { + case form::FormButtonType_RESET: + eType = TYPE_RESET; + break; + case form::FormButtonType_SUBMIT: + eType = TYPE_SUBMIT; + break; + case form::FormButtonType_PUSH: + default: + eType = TYPE_BUTTON; + } + + aTmp = xPropSet->getPropertyValue( + OUString::createFromAscii( "Label" ) ); + if( aTmp.getValueType() == ::getCppuType((const OUString*)0) && + ((OUString*)aTmp.getValue())->getLength() ) + { + sValue = *(OUString*)aTmp.getValue(); + } + } + break; + + case form::FormComponentType::LISTBOX: + if( rHTMLWrt.bLFPossible ) + rHTMLWrt.OutNewLine( sal_True ); + eTag = TAG_SELECT; + aTmp = xPropSet->getPropertyValue( + OUString::createFromAscii( "Dropdown" ) ); + if( aTmp.getValueType() == ::getBooleanCppuType() && + !*(sal_Bool*)aTmp.getValue() ) + { + Size aSz( 0, 0 ); + GetControlSize( rSdrObject, aSz, rWrt.pDoc ); + + // wieviele sind sichtbar ?? + if( aSz.Height() ) + (((sOptions += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_size ) += '=' ) + += ByteString::CreateFromInt32( aSz.Height() ); + + aTmp = xPropSet->getPropertyValue( + OUString::createFromAscii( "MultiSelection" ) ); + if( aTmp.getValueType() == ::getBooleanCppuType() && + *(sal_Bool*)aTmp.getValue() ) + { + (sOptions += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_multiple; + } + } + break; + + case form::FormComponentType::TEXTFIELD: + { + Size aSz( 0, 0 ); + GetControlSize( rSdrObject, aSz, rWrt.pDoc ); + + sal_Bool bMultiLine = sal_False; + OUString sMultiLine( OUString::createFromAscii( "MultiLine" ) ); + if( xPropSetInfo->hasPropertyByName( sMultiLine ) ) + { + aTmp = xPropSet->getPropertyValue( sMultiLine ); + bMultiLine = aTmp.getValueType() == ::getBooleanCppuType() && + *(sal_Bool*)aTmp.getValue(); + } + + if( bMultiLine ) + { + if( rHTMLWrt.bLFPossible ) + rHTMLWrt.OutNewLine( sal_True ); + eTag = TAG_TEXTAREA; + + if( aSz.Height() ) + (((sOptions += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_rows ) += '=' ) + += ByteString::CreateFromInt32( aSz.Height() ); + if( aSz.Width() ) + (((sOptions += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_cols ) += '=' ) + += ByteString::CreateFromInt32( aSz.Width() ); + + aTmp = xPropSet->getPropertyValue( + OUString::createFromAscii( "HScroll" ) ); + if( aTmp.getValueType() == ::getVoidCppuType() || + (aTmp.getValueType() == ::getBooleanCppuType() && + !*(sal_Bool*)aTmp.getValue()) ) + { + const sal_Char *pWrapStr = 0; + aTmp = xPropSet->getPropertyValue( + OUString::createFromAscii( "HardLineBreaks" ) ); + pWrapStr = + (aTmp.getValueType() == ::getBooleanCppuType() && + *(sal_Bool*)aTmp.getValue()) ? OOO_STRING_SVTOOLS_HTML_WW_hard + : OOO_STRING_SVTOOLS_HTML_WW_soft; + (((sOptions += ' ') += OOO_STRING_SVTOOLS_HTML_O_wrap) += '=') += pWrapStr; + } + } + else + { + eType = TYPE_TEXT; + OUString sEchoChar( OUString::createFromAscii( "EchoChar" ) ); + if( xPropSetInfo->hasPropertyByName( sEchoChar ) ) + { + aTmp = xPropSet->getPropertyValue( sEchoChar ); + if( aTmp.getValueType() == ::getCppuType((const sal_Int16*)0) && + *(sal_Int16*)aTmp.getValue() != 0 ) + eType = TYPE_PASSWORD; + } + + if( aSz.Width() ) + (((sOptions += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_size ) += '=' ) + += ByteString::CreateFromInt32( aSz.Width() ); + + aTmp = xPropSet->getPropertyValue( + OUString::createFromAscii( "MaxTextLen" ) ); + if( aTmp.getValueType() == ::getCppuType((const sal_Int16*)0) && + *(sal_Int16*) aTmp.getValue() != 0 ) + { + (((sOptions += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_maxlength ) += '=' ) + += ByteString::CreateFromInt32( + *(sal_Int16*) aTmp.getValue() ); + } + + OUString sDefaultText( OUString::createFromAscii( "DefaultText" ) ); + if( xPropSetInfo->hasPropertyByName( sDefaultText ) ) + { + aTmp = xPropSet->getPropertyValue( sDefaultText ); + if( aTmp.getValueType() == ::getCppuType((const OUString*)0) && + ((OUString*)aTmp.getValue())->getLength() ) + { + sValue = *(OUString*)aTmp.getValue(); + } + } + } + } + break; + + case form::FormComponentType::FILECONTROL: + { + Size aSz( 0, 0 ); + GetControlSize( rSdrObject, aSz, rWrt.pDoc ); + eType = TYPE_FILE; + + if( aSz.Width() ) + (((sOptions += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_size ) += '=' ) + += ByteString::CreateFromInt32( aSz.Width() ); + + // VALUE vim form aus Sicherheitsgruenden nicht exportieren + } + break; + + + case form::FormComponentType::IMAGEBUTTON: + eType = TYPE_IMAGE; + nFrmOpts = HTML_FRMOPTS_IMG_CONTROL; + break; + + default: // kennt HTML nicht + eTag = TAG_NONE; // also ueberspringen + break; + } + + if( eTag == TAG_NONE ) + return rWrt; + + ByteString sOut( '<' ); + sOut += TagNames[eTag]; + if( eType != TYPE_NONE ) + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_type) += '=') += + TypeNames[eType]; + + aTmp = xPropSet->getPropertyValue( OUString::createFromAscii( "Name" ) ); + if( aTmp.getValueType() == ::getCppuType((const OUString*)0) && + ((OUString*)aTmp.getValue())->getLength() ) + { + (( sOut += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_name ) += "=\""; + rWrt.Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( rWrt.Strm(), *(OUString*)aTmp.getValue(), + rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + sOut = '\"'; + } + + aTmp = xPropSet->getPropertyValue( OUString::createFromAscii( "Enabled" ) ); + if( aTmp.getValueType() == ::getBooleanCppuType() && + !*(sal_Bool*)aTmp.getValue() ) + { + (( sOut += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_disabled ); + } + + if( sValue.getLength() || bEmptyValue ) + { + ((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_value) += "=\""; + rWrt.Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( rWrt.Strm(), sValue, rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + sOut = '\"'; + } + + sOut += sOptions; + + if( TYPE_IMAGE == eType ) + { + aTmp = xPropSet->getPropertyValue( + OUString::createFromAscii( "ImageURL" ) ); + if( aTmp.getValueType() == ::getCppuType((const OUString*)0) && + ((OUString*)aTmp.getValue())->getLength() ) + { + ((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_src) += "=\""; + rWrt.Strm() << sOut.GetBuffer(); + + HTMLOutFuncs::Out_String( rWrt.Strm(), + URIHelper::simpleNormalizedMakeRelative( rWrt.GetBaseURL(), *(OUString*)aTmp.getValue()), + rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + sOut = '\"'; + } + + Size aTwipSz( rSdrObject.GetLogicRect().GetSize() ); + Size aPixelSz( 0, 0 ); + if( (aTwipSz.Width() || aTwipSz.Height()) && + Application::GetDefaultDevice() ) + { + aPixelSz = + Application::GetDefaultDevice()->LogicToPixel( aTwipSz, + MapMode(MAP_TWIP) ); + if( !aPixelSz.Width() && aTwipSz.Width() ) + aPixelSz.Width() = 1; + if( !aPixelSz.Height() && aTwipSz.Height() ) + aPixelSz.Height() = 1; + } + + if( aPixelSz.Width() ) + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_width) += '=') + += ByteString::CreateFromInt32( aPixelSz.Width() ); + + if( aPixelSz.Height() ) + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_height) += '=') + += ByteString::CreateFromInt32( aPixelSz.Height() ); + } + + aTmp = xPropSet->getPropertyValue( + OUString::createFromAscii( "TabIndex" ) ); + if( aTmp.getValueType() == ::getCppuType((const sal_Int16*)0) ) + { + sal_Int16 nTabIndex = *(sal_Int16*) aTmp.getValue(); + if( nTabIndex > 0 ) + { + if( nTabIndex >= 32767 ) + nTabIndex = 32767; + + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_tabindex) += '=') + += ByteString::CreateFromInt32( nTabIndex ); + } + } + + if( sOut.Len() ) + { + rWrt.Strm() << sOut.GetBuffer(); + sOut.Erase(); + } + + ASSERT( !bInCntnr, "Container wird fuer Controls nicht unterstuertzt" ); + if( rHTMLWrt.IsHTMLMode( HTMLMODE_ABS_POS_DRAW ) && !bInCntnr ) + { + // Wenn Zeichen-Objekte nicht absolut positioniert werden duerfen, + // das entsprechende Flag loeschen. + nFrmOpts |= (TYPE_IMAGE == eType + ? HTML_FRMOPTS_IMG_CONTROL_CSS1 + : HTML_FRMOPTS_CONTROL_CSS1); + } + ByteString aEndTags; + if( nFrmOpts != 0 ) + rHTMLWrt.OutFrmFmtOptions( rFmt, aEmptyStr, aEndTags, nFrmOpts ); + + if( rHTMLWrt.bCfgOutStyles ) + { + sal_Bool bEdit = TAG_TEXTAREA == eTag || TYPE_FILE == eType || + TYPE_TEXT == eType; + + SfxItemSet aItemSet( rHTMLWrt.pDoc->GetAttrPool(), RES_CHRATR_BEGIN, + RES_CHRATR_END ); + OUString sPropName = OUString::createFromAscii( "BackgroundColor" ); + if( xPropSetInfo->hasPropertyByName( sPropName ) ) + { + aTmp = xPropSet->getPropertyValue( sPropName ); + if( aTmp.getValueType() == ::getCppuType((const sal_Int32*)0) ) + { + Color aCol(*(sal_Int32*)aTmp .getValue()); + aItemSet.Put( SvxBrushItem( aCol, RES_CHRATR_BACKGROUND ) ); + } + } + sPropName = OUString::createFromAscii( "TextColor" ); + if( xPropSetInfo->hasPropertyByName( sPropName ) ) + { + aTmp = xPropSet->getPropertyValue( sPropName ); + if( aTmp.getValueType() == ::getCppuType((const sal_Int32*)0) ) + { + Color aColor( *(sal_Int32*)aTmp .getValue() ); + aItemSet.Put( SvxColorItem( aColor, RES_CHRATR_COLOR ) ); + } + } + sPropName = OUString::createFromAscii( "FontHeight" ); + if( xPropSetInfo->hasPropertyByName( sPropName ) ) + { + aTmp = xPropSet->getPropertyValue( sPropName ); + if( aTmp.getValueType() == ::getCppuType((const float*)0) ) + + { + float nHeight = *(float*)aTmp.getValue(); + if( nHeight > 0 && (!bEdit || nHeight != 10.) ) + aItemSet.Put( SvxFontHeightItem( sal_Int16(nHeight * 20.), 100, RES_CHRATR_FONTSIZE ) ); + } + } + sPropName = OUString::createFromAscii( "FontName" ); + if( xPropSetInfo->hasPropertyByName( sPropName ) ) + { + aTmp = xPropSet->getPropertyValue( sPropName ); + if( aTmp.getValueType() == ::getCppuType((const OUString*)0) && + ((OUString*)aTmp.getValue())->getLength() ) + { + Font aFixedFont( OutputDevice::GetDefaultFont( + DEFAULTFONT_FIXED, LANGUAGE_ENGLISH_US, + DEFAULTFONT_FLAGS_ONLYONE ) ); + String aFName( *(OUString*)aTmp.getValue() ); + if( !bEdit || aFName != aFixedFont.GetName() ) + { + FontFamily eFamily = FAMILY_DONTKNOW; + sPropName = OUString::createFromAscii( "FontFamily" ); + if( xPropSetInfo->hasPropertyByName( sPropName ) ) + { + aTmp = xPropSet->getPropertyValue( sPropName ); + if( aTmp.getValueType() == ::getCppuType((const sal_Int16*)0)) + eFamily = (FontFamily)*(sal_Int16*) aTmp.getValue(); + } + SvxFontItem aItem( eFamily, aFName, aEmptyStr, PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW, RES_CHRATR_FONT ); + aItemSet.Put( aItem ); + } + } + } + sPropName = OUString::createFromAscii( "FontWeight" ); + if( xPropSetInfo->hasPropertyByName( sPropName ) ) + { + aTmp = xPropSet->getPropertyValue( sPropName ); + if( aTmp.getValueType() == ::getCppuType((const float*)0) ) + { + FontWeight eWeight = + VCLUnoHelper::ConvertFontWeight( *(float*)aTmp.getValue() ); + if( eWeight != WEIGHT_DONTKNOW && eWeight != WEIGHT_NORMAL ) + aItemSet.Put( SvxWeightItem( eWeight, RES_CHRATR_WEIGHT ) ); + } + } + sPropName = OUString::createFromAscii( "FontSlant" ); + if( xPropSetInfo->hasPropertyByName( sPropName ) ) + { + aTmp = xPropSet->getPropertyValue( sPropName ); + if( aTmp.getValueType() == ::getCppuType((const sal_Int16*)0)) + { + FontItalic eItalic = (FontItalic)*(sal_Int16*)aTmp.getValue(); + if( eItalic != ITALIC_DONTKNOW && eItalic != ITALIC_NONE ) + aItemSet.Put( SvxPostureItem( eItalic, RES_CHRATR_POSTURE ) ); + } + } + sPropName = OUString::createFromAscii( "FontUnderline" ); + if( xPropSetInfo->hasPropertyByName( sPropName ) ) + { + aTmp = xPropSet->getPropertyValue( sPropName ); + if( aTmp.getValueType() == ::getCppuType((const sal_Int16*)0) ) + { + FontUnderline eUnderline = + (FontUnderline)*(sal_Int16*)aTmp.getValue(); + if( eUnderline != UNDERLINE_DONTKNOW && + eUnderline != UNDERLINE_NONE ) + aItemSet.Put( SvxUnderlineItem( eUnderline, RES_CHRATR_UNDERLINE ) ); + } + } + sPropName = OUString::createFromAscii( "FontStrikeout" ); + if( xPropSetInfo->hasPropertyByName( sPropName ) ) + { + aTmp = xPropSet->getPropertyValue( sPropName ); + if( aTmp.getValueType() == ::getCppuType((const sal_Int16*)0)) + { + FontStrikeout eStrikeout = + (FontStrikeout)*(sal_Int16*)aTmp.getValue(); + if( eStrikeout != STRIKEOUT_DONTKNOW && + eStrikeout != STRIKEOUT_NONE ) + aItemSet.Put( SvxCrossedOutItem( eStrikeout, RES_CHRATR_CROSSEDOUT ) ); + } + } + + rHTMLWrt.OutCSS1_FrmFmtOptions( rFmt, nFrmOpts, &rSdrObject, + &aItemSet ); + } + + uno::Reference< form::XFormComponent > xFormComp( xControlModel, uno::UNO_QUERY ); + lcl_html_outEvents( rWrt.Strm(), xFormComp, rHTMLWrt.bCfgStarBasic, + rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + + rWrt.Strm() << '>'; + + if( TAG_SELECT == eTag ) + { + aTmp = xPropSet->getPropertyValue( + OUString::createFromAscii( "StringItemList" ) ); + if( aTmp.getValueType() == ::getCppuType((uno::Sequence<OUString>*)0) ) + { + rHTMLWrt.IncIndentLevel(); // der Inhalt von Select darf + // eingerueckt werden + uno::Sequence<OUString> aList( *(uno::Sequence<OUString>*)aTmp.getValue() ); + sal_Int32 nCnt = aList.getLength(); + const OUString *pStrings = aList.getConstArray(); + + const OUString *pValues = 0; + sal_Int32 nValCnt = 0; + aTmp = xPropSet->getPropertyValue( + OUString::createFromAscii( "ListSource" ) ); + uno::Sequence<OUString> aValList; + if( aTmp.getValueType() == ::getCppuType((uno::Sequence<OUString>*)0) ) + { + aValList = *(uno::Sequence<OUString>*)aTmp.getValue(); + nValCnt = aValList.getLength(); + pValues = aValList.getConstArray(); + } + + uno::Any aSelTmp = xPropSet->getPropertyValue( + OUString::createFromAscii( "DefaultSelection" ) ); + const sal_Int16 *pSels = 0; + sal_Int32 nSel = 0; + sal_Int32 nSelCnt = 0; + uno::Sequence<sal_Int16> aSelList; + if( aSelTmp.getValueType() ==::getCppuType((uno::Sequence<sal_Int16>*)0)) + { + aSelList = *(uno::Sequence<sal_Int16>*)aSelTmp.getValue(); + nSelCnt = aSelList.getLength(); + pSels = aSelList.getConstArray(); + } + + for( sal_Int32 i = 0; i < nCnt; i++ ) + { + OUString sVal; + sal_Bool bSelected = sal_False, bEmptyVal = sal_False; + if( i < nValCnt ) + { + const OUString& rVal = pValues[i]; + if( rVal.compareToAscii( "$$$empty$$$" ) == 0 ) + bEmptyVal = sal_True; + else + sVal = rVal; + } + + bSelected = (nSel < nSelCnt) && pSels[nSel] == i; + if( bSelected ) + nSel++; + + rHTMLWrt.OutNewLine(); // jede Option bekommt eine eigene Zeile + (sOut = '<') += OOO_STRING_SVTOOLS_HTML_option; + if( sVal.getLength() || bEmptyVal ) + { + ((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_value) += "=\""; + rWrt.Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( rWrt.Strm(), sVal, + rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + sOut = '\"'; + } + if( bSelected ) + (sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_selected; + + sOut += '>'; + rWrt.Strm() << sOut.GetBuffer(); + + HTMLOutFuncs::Out_String( rWrt.Strm(), pStrings[i], + rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + } + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_option, sal_False ); + + rHTMLWrt.DecIndentLevel(); + rHTMLWrt.OutNewLine();// das </SELECT> bekommt eine eigene Zeile + } + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_select, sal_False ); + } + else if( TAG_TEXTAREA == eTag ) + { + // In TextAreas duerfen keine zusaetzlichen Spaces oder LF exportiert + // werden! + String sVal; + aTmp = xPropSet->getPropertyValue( + OUString::createFromAscii( "DefaultText" ) ); + if( aTmp.getValueType() == ::getCppuType((const OUString*)0)&& + ((OUString*)aTmp.getValue())->getLength() ) + { + sVal = String( *(OUString*)aTmp.getValue() ); + } + if( sVal.Len() ) + { + sVal.ConvertLineEnd( LINEEND_LF ); + xub_StrLen nPos = 0; + while ( nPos != STRING_NOTFOUND ) + { + if( nPos ) + rWrt.Strm() << SwHTMLWriter::sNewLine; + String aLine = sVal.GetToken( 0, 0x0A, nPos ); + HTMLOutFuncs::Out_String( rWrt.Strm(), aLine, + rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + } + } + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_textarea, sal_False ); + } + else if( TYPE_CHECKBOX == eType || TYPE_RADIO == eType ) + { + aTmp = xPropSet->getPropertyValue( OUString::createFromAscii("Label") ); + if( aTmp.getValueType() == ::getCppuType((const OUString*)0) && + ((OUString*)aTmp.getValue())->getLength() ) + { + sValue = *(OUString*)aTmp.getValue(); + HTMLOutFuncs::Out_String( rWrt.Strm(), sValue, + rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ) << ' '; + } + } + + if( aEndTags.Len() ) + rWrt.Strm() << aEndTags.GetBuffer(); + + // Controls sind nicht absatz-gebunden, deshalb kein LF mehr ausgeben! + rHTMLWrt.bLFPossible = sal_False; + + if( rHTMLWrt.pxFormComps && rHTMLWrt.pxFormComps->is() ) + rHTMLWrt.OutHiddenControls( *rHTMLWrt.pxFormComps, xPropSet ); + return rWrt; +} + +/* */ + +// Ermitteln, ob eine Format zu einem Control gehoert und wenn ja +// dessen Form zurueckgeben +static void AddControl( HTMLControls& rControls, + const SdrObject *pSdrObj, + sal_uInt32 nNodeIdx ) +{ + SdrUnoObj *pFormObj = PTR_CAST( SdrUnoObj, pSdrObj ); + ASSERT( pFormObj, "Doch kein FormObj" ); + uno::Reference< awt::XControlModel > xControlModel = + pFormObj->GetUnoControlModel(); + if( !xControlModel.is() ) + return; + + uno::Reference< form::XFormComponent > xFormComp( xControlModel, uno::UNO_QUERY ); + uno::Reference< uno::XInterface > xIfc = xFormComp->getParent(); + uno::Reference< form::XForm > xForm(xIfc, uno::UNO_QUERY); + + ASSERT( xForm.is(), "Wo ist die Form?" ); + if( xForm.is() ) + { + uno::Reference< container::XIndexContainer > xFormComps( xForm, uno::UNO_QUERY ); + HTMLControl *pHCntrl = new HTMLControl( xFormComps, nNodeIdx ); + if( !rControls.C40_PTR_INSERT( HTMLControl, pHCntrl ) ) + { + sal_uInt16 nPos = 0; + if( rControls.Seek_Entry(pHCntrl,&nPos) && + rControls[nPos]->xFormComps==xFormComps ) + rControls[nPos]->nCount++; + delete pHCntrl; + } + } +} + + +void SwHTMLWriter::GetControls() +{ + // Idee: die absatz- und zeichengebundenen Controls werden erst einmal + // eingesammelt. Dabei wird fuer jedes Control des Absatz-Position + // und VCForm in einem Array gemerkt. + // Ueber dieses Array laesst sich dann feststellen, wo form::Forms geoeffnet + // und geschlossen werden muessen. + sal_uInt16 i; + if( pHTMLPosFlyFrms ) + { + // die absatz-gebundenen Controls einsammeln + for( i=0; i<pHTMLPosFlyFrms->Count(); i++ ) + { + const SwHTMLPosFlyFrm* pPosFlyFrm = pHTMLPosFlyFrms->GetObject( i ); + if( HTML_OUT_CONTROL != pPosFlyFrm->GetOutFn() ) + continue; + + const SdrObject *pSdrObj = pPosFlyFrm->GetSdrObject(); + ASSERT( pSdrObj, "Wo ist das SdrObject?" ); + if( !pSdrObj ) + continue; + + AddControl( aHTMLControls, pSdrObj, + pPosFlyFrm->GetNdIndex().GetIndex() ); + } + } + + // und jetzt die in einem zeichengebundenen Rahmen + const SwSpzFrmFmts* pSpzFrmFmts = pDoc->GetSpzFrmFmts(); + for( i=0; i<pSpzFrmFmts->Count(); i++ ) + { + const SwFrmFmt *pFrmFmt = (*pSpzFrmFmts)[i]; + if( RES_DRAWFRMFMT != pFrmFmt->Which() ) + continue; + + const SwFmtAnchor& rAnchor = pFrmFmt->GetAnchor(); + const SwPosition *pPos = rAnchor.GetCntntAnchor(); + if ((FLY_AS_CHAR != rAnchor.GetAnchorId()) || !pPos) + continue; + + const SdrObject *pSdrObj = + SwHTMLWriter::GetHTMLControl( *(const SwDrawFrmFmt*)pFrmFmt ); + if( !pSdrObj ) + continue; + + AddControl( aHTMLControls, pSdrObj, pPos->nNode.GetIndex() ); + } +} + +/* */ + +HTMLControl::HTMLControl( + const uno::Reference< container::XIndexContainer > & rFormComps, + sal_uInt32 nIdx ) : + xFormComps( rFormComps ), nNdIdx( nIdx ), nCount( 1 ) +{} + + +HTMLControl::~HTMLControl() +{} + + diff --git a/sw/source/filter/html/htmlftn.cxx b/sw/source/filter/html/htmlftn.cxx new file mode 100644 index 000000000000..6c96722b5009 --- /dev/null +++ b/sw/source/filter/html/htmlftn.cxx @@ -0,0 +1,621 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + + + +#include <svtools/htmlout.hxx> +#include <svtools/htmlkywd.hxx> +#include <errhdl.hxx> +#include <ndindex.hxx> +#include <fmtftn.hxx> +#include <txtftn.hxx> +#include <ftninfo.hxx> +#include <doc.hxx> +#include <ndtxt.hxx> +#include <charfmt.hxx> + + +#include "swhtml.hxx" +#include "wrthtml.hxx" + +typedef SwTxtFtn *SwTxtFtnPtr; +SV_DECL_PTRARR( SwHTMLTxtFtns, SwTxtFtnPtr, 1, 1 ) + +struct SwHTMLFootEndNote_Impl +{ + SwHTMLTxtFtns aTxtFtns; + SvStringsDtor aNames; + + String sName; + String sContent; // Infos fuer die letzte Fussnote + sal_Bool bEndNote; + sal_Bool bFixed; +}; + + +xub_StrLen lcl_html_getNextPart( String& rPart, const String& rContent, + xub_StrLen nPos ) +{ + rPart = aEmptyStr; + xub_StrLen nLen = rContent.Len(); + if( nPos >= nLen ) + { + nPos = STRING_MAXLEN; + } + else + { + sal_Bool bQuoted = sal_False, bDone = sal_False; + for( ; nPos < nLen && !bDone; nPos++ ) + { + sal_Unicode c = rContent.GetChar( nPos ); + switch( c ) + { + case '\\': + if( bQuoted ) + rPart += c; + bQuoted = !bQuoted; + break; + + case ';': + if( bQuoted ) + rPart += c; + else + bDone = sal_True; + bQuoted = sal_False; + break; + + default: + rPart += c; + bQuoted = sal_False; + break; + } + } + } + + return nPos; +} + +xub_StrLen lcl_html_getEndNoteInfo( SwEndNoteInfo& rInfo, + const String& rContent, + sal_Bool bEndNote ) +{ + xub_StrLen nStrPos = 0; + for( sal_uInt16 nPart = 0; nPart < 4; nPart++ ) + { + String aPart; + if( STRING_MAXLEN != nStrPos ) + nStrPos = lcl_html_getNextPart( aPart, rContent, nStrPos ); + + switch( nPart ) + { + case 0: + rInfo.aFmt.SetNumberingType( static_cast< sal_Int16 >(bEndNote ? SVX_NUM_ROMAN_LOWER : SVX_NUM_ARABIC)); + if( aPart.Len() ) + rInfo.aFmt.SetNumberingType(SwHTMLParser::GetNumType( aPart, + rInfo.aFmt.GetNumberingType() )); + break; + + case 1: + rInfo.nFtnOffset = aPart.Len() == 0 ? 0 : (sal_uInt16)aPart.ToInt32(); + break; + + case 2: + rInfo.SetPrefix( aPart ); + break; + + case 3: + rInfo.SetSuffix( aPart ); + break; + } + } + + return nStrPos; +} + +void SwHTMLParser::FillEndNoteInfo( const String& rContent ) +{ + SwEndNoteInfo aInfo( pDoc->GetEndNoteInfo() ); + lcl_html_getEndNoteInfo( aInfo, rContent, sal_True ); + pDoc->SetEndNoteInfo( aInfo ); +} + +void SwHTMLParser::FillFootNoteInfo( const String& rContent ) +{ + SwFtnInfo aInfo( pDoc->GetFtnInfo() ); + + xub_StrLen nStrPos = lcl_html_getEndNoteInfo( aInfo, rContent, sal_False ); + + for( sal_uInt16 nPart = 4; nPart < 8; nPart++ ) + { + String aPart; + if( STRING_MAXLEN != nStrPos ) + nStrPos = lcl_html_getNextPart( aPart, rContent, nStrPos ); + + switch( nPart ) + { + case 4: + aInfo.eNum = FTNNUM_DOC; + if( aPart.Len() ) + { + switch( aPart.GetChar(0) ) + { + case 'D': aInfo.eNum = FTNNUM_DOC; break; + case 'C': aInfo.eNum = FTNNUM_CHAPTER; break; + case 'P': aInfo.eNum = FTNNUM_PAGE; break; + } + } + break; + + case 5: + aInfo.ePos = FTNPOS_PAGE; + if( aPart.Len() ) + { + switch( aPart.GetChar(0) ) + { + case 'C': aInfo.ePos = FTNPOS_CHAPTER; break; + case 'P': aInfo.ePos = FTNPOS_PAGE; break; + } + } + break; + + case 6: + aInfo.aQuoVadis = aPart; + break; + + case 7: + aInfo.aErgoSum = aPart; + break; + } + } + + pDoc->SetFtnInfo( aInfo ); +} + +void SwHTMLParser::InsertFootEndNote( const String& rName, sal_Bool bEndNote, + sal_Bool bFixed ) +{ + if( !pFootEndNoteImpl ) + pFootEndNoteImpl = new SwHTMLFootEndNote_Impl; + + pFootEndNoteImpl->sName = rName; + if( pFootEndNoteImpl->sName.Len() > 3 ) + pFootEndNoteImpl->sName.Erase( pFootEndNoteImpl->sName.Len() - 3 ); + // TODO: ToUpperAscii??? + pFootEndNoteImpl->sName.ToUpperAscii(); + + pFootEndNoteImpl->bEndNote = bEndNote; + pFootEndNoteImpl->bFixed = bFixed; + pFootEndNoteImpl->sContent = aEmptyStr; +} + +void SwHTMLParser::FinishFootEndNote() +{ + if( !pFootEndNoteImpl ) + return; + + SwFmtFtn aFtn( pFootEndNoteImpl->bEndNote ); + if( pFootEndNoteImpl->bFixed ) + aFtn.SetNumStr( pFootEndNoteImpl->sContent ); + + pDoc->InsertPoolItem( *pPam, aFtn, 0 ); + SwTxtFtn * const pTxtFtn = static_cast<SwTxtFtn *>( + pPam->GetNode()->GetTxtNode()->GetTxtAttrForCharAt( + pPam->GetPoint()->nContent.GetIndex() - 1, RES_TXTATR_FTN ) ); + // In Kopf- und Fusszeilen duerfen keine Fussnoten eingefuegt werden. + if( pTxtFtn ) + { + pFootEndNoteImpl->aTxtFtns.Insert( pTxtFtn, + pFootEndNoteImpl->aTxtFtns.Count() ); + + pFootEndNoteImpl->aNames.Insert( new String(pFootEndNoteImpl->sName), + pFootEndNoteImpl->aNames.Count() ); + } + pFootEndNoteImpl->sName = aEmptyStr; + pFootEndNoteImpl->sContent = aEmptyStr; + pFootEndNoteImpl->bFixed = sal_False; +} + +void SwHTMLParser::InsertFootEndNoteText() +{ + if( pFootEndNoteImpl && pFootEndNoteImpl->bFixed ) + pFootEndNoteImpl->sContent += aToken; +} + +void SwHTMLParser::DeleteFootEndNoteImpl() +{ + delete pFootEndNoteImpl; + pFootEndNoteImpl = 0; +} + +SwNodeIndex *SwHTMLParser::GetFootEndNoteSection( const String& rName ) +{ + SwNodeIndex *pStartNodeIdx = 0; + + if( pFootEndNoteImpl ) + { + String aName( rName ); + // TODO: ToUpperAscii + aName.ToUpperAscii(); + + sal_uInt16 nCount = pFootEndNoteImpl->aNames.Count(); + for( sal_uInt16 i=0; i<nCount; i++ ) + { + if( *pFootEndNoteImpl->aNames[i] == aName ) + { + pStartNodeIdx = pFootEndNoteImpl->aTxtFtns[i]->GetStartNode(); + pFootEndNoteImpl->aNames.DeleteAndDestroy( i, 1 ); + pFootEndNoteImpl->aTxtFtns.Remove( i, 1 ); + if( !pFootEndNoteImpl->aNames.Count() ) + { + delete pFootEndNoteImpl; + pFootEndNoteImpl = 0; + } + + break; + } + } + } + + return pStartNodeIdx; +} + +Writer& OutHTML_SwFmtFtn( Writer& rWrt, const SfxPoolItem& rHt ) +{ + SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt; + + SwFmtFtn& rFmtFtn = (SwFmtFtn&)rHt; + SwTxtFtn *pTxtFtn = rFmtFtn.GetTxtFtn(); + if( !pTxtFtn ) + return rWrt; + + String sFtnName, sClass; + sal_uInt16 nPos; + if( rFmtFtn.IsEndNote() ) + { + nPos = rHTMLWrt.pFootEndNotes ? rHTMLWrt.pFootEndNotes->Count() : 0; + ASSERT( nPos == rHTMLWrt.nFootNote + rHTMLWrt.nEndNote, + "OutHTML_SwFmtFtn: Position falsch" ); + sClass.AssignAscii( OOO_STRING_SVTOOLS_HTML_sdendnote_anc ); + sFtnName.AssignAscii( OOO_STRING_SVTOOLS_HTML_sdendnote ); + sFtnName += String::CreateFromInt32( (sal_Int32)(++rHTMLWrt.nEndNote) ); + } + else + { + nPos = rHTMLWrt.nFootNote; + sClass.AssignAscii( OOO_STRING_SVTOOLS_HTML_sdfootnote_anc ); + sFtnName.AssignAscii( OOO_STRING_SVTOOLS_HTML_sdfootnote); + sFtnName += String::CreateFromInt32( (sal_Int32)(++rHTMLWrt.nFootNote)); + } + + if( !rHTMLWrt.pFootEndNotes ) + rHTMLWrt.pFootEndNotes = new SwHTMLTxtFtns; + rHTMLWrt.pFootEndNotes->Insert( pTxtFtn, nPos ); + + ByteString sOut( '<' ); + (((sOut += OOO_STRING_SVTOOLS_HTML_anchor) += ' ') += OOO_STRING_SVTOOLS_HTML_O_class) += "=\""; + rWrt.Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( rWrt.Strm(), sClass, rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + ((sOut = "\" ") += OOO_STRING_SVTOOLS_HTML_O_name) += "=\""; + rWrt.Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( rWrt.Strm(), sFtnName, rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + (((sOut = OOO_STRING_SVTOOLS_HTML_FTN_anchor) += "\" ") += OOO_STRING_SVTOOLS_HTML_O_href) += "=\"#"; + rWrt.Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( rWrt.Strm(), sFtnName, rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + (sOut = OOO_STRING_SVTOOLS_HTML_FTN_symbol)+= '\"'; + if( rFmtFtn.GetNumStr().Len() ) + (sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_sdfixed; + sOut += '>'; + rWrt.Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_superscript, sal_True ); + + HTMLOutFuncs::Out_String( rWrt.Strm(), rFmtFtn.GetViewNumStr(*rWrt.pDoc), + rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_superscript, sal_False ); + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_anchor, sal_False ); + + return rWrt; +} + +void SwHTMLWriter::OutFootEndNotes() +{ + ASSERT( pFootEndNotes, + "SwHTMLWriter::OutFootEndNotes(): unnoetiger Aufruf" ); + if( !pFootEndNotes ) + return; + +#ifdef DBG_UTIL + sal_uInt16 nFtn = nFootNote, nEn = nEndNote; +#endif + nFootNote = 0, nEndNote = 0; + + for( sal_uInt16 i=0; i<pFootEndNotes->Count(); i++ ) + { + SwTxtFtn *pTxtFtn = (*pFootEndNotes)[i]; + pFmtFtn = &pTxtFtn->GetFtn(); + + String sFtnName, sClass; + if( pFmtFtn->IsEndNote() ) + { + sClass.AssignAscii( OOO_STRING_SVTOOLS_HTML_sdendnote ); + sFtnName.AssignAscii( OOO_STRING_SVTOOLS_HTML_sdendnote ); + sFtnName.Append( String::CreateFromInt32((sal_Int32)(++nEndNote)) ); + } + else + { + sClass.AssignAscii( OOO_STRING_SVTOOLS_HTML_sdfootnote ); + sFtnName.AssignAscii( OOO_STRING_SVTOOLS_HTML_sdfootnote ); + sFtnName.Append( String::CreateFromInt32((sal_Int32)(++nFootNote))); + } + + if( bLFPossible ) + OutNewLine(); + ByteString sOut( '<' ); + (((sOut += OOO_STRING_SVTOOLS_HTML_division) += ' ') += OOO_STRING_SVTOOLS_HTML_O_id) += "=\""; + Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( Strm(), sFtnName, eDestEnc, &aNonConvertableCharacters ); + Strm() << "\">"; + + bLFPossible = sal_True; + IncIndentLevel(); // Inhalt von <DIV> einruecken + + ASSERT( pTxtFtn, "SwHTMLWriter::OutFootEndNotes: SwTxtFtn fehlt" ); + SwNodeIndex *pSttNdIdx = pTxtFtn->GetStartNode(); + ASSERT( pSttNdIdx, + "SwHTMLWriter::OutFootEndNotes: StartNode-Index fehlt" ); + if( pSttNdIdx ) + { + HTMLSaveData aSaveData( *this, pSttNdIdx->GetIndex()+1, + pSttNdIdx->GetNode().EndOfSectionIndex(), sal_False ); + Out_SwDoc( pCurPam ); + } + + DecIndentLevel(); // Inhalt von <DIV> einruecken + if( bLFPossible ) + OutNewLine(); + HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_division, sal_False ); + bLFPossible = sal_True; + + ASSERT( !pFmtFtn, + "SwHTMLWriter::OutFootEndNotes: Ftn wurde nicht ausgegeben" ); + if( pFmtFtn ) + { + if( pFmtFtn->IsEndNote() ) + nEndNote++; + else + nFootNote++; + + pFmtFtn = 0; + } + } + +#ifdef DBG_UTIL + ASSERT( nFtn == nFootNote, + "SwHTMLWriter::OutFootEndNotes: Anzahl Fussnoten stimmt nicht" ); + ASSERT( nEn == nEndNote, + "SwHTMLWriter::OutFootEndNotes: Anzahl Endnoten stimmt nicht" ); +#endif + + delete pFootEndNotes; + pFootEndNotes = 0; + nFootNote = nEndNote = 0; +} + +String SwHTMLWriter::GetFootEndNoteSym( const SwFmtFtn& rFmtFtn ) +{ + const SwEndNoteInfo * pInfo = 0; + if( rFmtFtn.GetNumStr().Len() == 0 ) + pInfo = rFmtFtn.IsEndNote() ? &pDoc->GetEndNoteInfo() + : &pDoc->GetFtnInfo(); + + String sRet; + if( pInfo ) + sRet = pInfo->GetPrefix(); + sRet += rFmtFtn.GetViewNumStr( *pDoc ); + if( pInfo ) + sRet += pInfo->GetSuffix(); + + return sRet; +} + +void SwHTMLWriter::OutFootEndNoteSym( const SwFmtFtn& rFmtFtn, + const String& rNum, + sal_uInt16 nScript ) +{ + const SwEndNoteInfo *pInfo; + + String sFtnName, sClass, sPrefix, sSuffix; + if( rFmtFtn.IsEndNote() ) + { + sClass.AssignAscii( OOO_STRING_SVTOOLS_HTML_sdendnote_sym ); + sFtnName.AssignAscii( OOO_STRING_SVTOOLS_HTML_sdendnote ); + sFtnName.Append( String::CreateFromInt32((sal_Int32)nEndNote) ); + pInfo = &pDoc->GetEndNoteInfo(); + } + else + { + sClass.AssignAscii( OOO_STRING_SVTOOLS_HTML_sdfootnote_sym ); + sFtnName.AssignAscii( OOO_STRING_SVTOOLS_HTML_sdfootnote ); + sFtnName.Append( String::CreateFromInt32((sal_Int32)nFootNote)); + pInfo = &pDoc->GetFtnInfo(); + } + + const SwCharFmt *pSymCharFmt = pInfo->GetCharFmt( *pDoc ); + if( pSymCharFmt && aScriptTextStyles.Seek_Entry( (String *)&pSymCharFmt->GetName() ) ) + { + switch( nScript ) + { + case CSS1_OUTMODE_WESTERN: + sClass.AppendAscii( RTL_CONSTASCII_STRINGPARAM("-western") ); + break; + case CSS1_OUTMODE_CJK: + sClass.AppendAscii( RTL_CONSTASCII_STRINGPARAM("-cjk") ); + break; + case CSS1_OUTMODE_CTL: + sClass.AppendAscii( RTL_CONSTASCII_STRINGPARAM("-ctl") ); + break; + } + } + + ByteString sOut( '<' ); + (((sOut += OOO_STRING_SVTOOLS_HTML_anchor) += ' ') += OOO_STRING_SVTOOLS_HTML_O_class) += "=\""; + Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( Strm(), sClass, eDestEnc, &aNonConvertableCharacters ); + ((sOut = "\" ") += OOO_STRING_SVTOOLS_HTML_O_name) += "=\""; + Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( Strm(), sFtnName, eDestEnc, &aNonConvertableCharacters ); + (((sOut = OOO_STRING_SVTOOLS_HTML_FTN_symbol) +="\" ") += OOO_STRING_SVTOOLS_HTML_O_href) += "=\"#"; + Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( Strm(), sFtnName, eDestEnc, &aNonConvertableCharacters ); + (sOut = OOO_STRING_SVTOOLS_HTML_FTN_anchor) += "\">"; + Strm() << sOut.GetBuffer(); + + HTMLOutFuncs::Out_String( Strm(), rNum, eDestEnc, &aNonConvertableCharacters ); + HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_anchor, sal_False ); +} + +sal_uInt16 lcl_html_fillEndNoteInfo( const SwEndNoteInfo& rInfo, + String *pParts, + sal_Bool bEndNote ) +{ + sal_uInt16 nParts = 0; + sal_Int16 eFmt = rInfo.aFmt.GetNumberingType(); + if( (bEndNote ? SVX_NUM_ROMAN_LOWER : SVX_NUM_ARABIC) != eFmt ) + { + const sal_Char *pStr = SwHTMLWriter::GetNumFormat( eFmt ); + if( pStr ) + { + pParts[0] = String::CreateFromAscii( pStr ); + nParts = 1; + } + } + if( rInfo.nFtnOffset > 0 ) + { + pParts[1] = String::CreateFromInt32( (sal_Int32)rInfo.nFtnOffset ); + nParts = 2; + } + if( rInfo.GetPrefix().Len() > 0 ) + { + pParts[2] = rInfo.GetPrefix(); + nParts = 3; + } + if( rInfo.GetSuffix().Len() > 0 ) + { + pParts[3] = rInfo.GetSuffix(); + nParts = 4; + } + + return nParts; +} + +void lcl_html_outFootEndNoteInfo( Writer& rWrt, String *pParts, + sal_uInt16 nParts, const sal_Char *pName ) +{ + SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt; + + String aContent; + for( sal_uInt16 i=0; i<nParts; i++ ) + { + xub_StrLen nPos = 0; + String aTmp( pParts[i] ); + String aRep( String::CreateFromAscii("\\\\") ); + while( STRING_NOTFOUND != (nPos = aTmp.SearchAndReplaceAscii( "\\", + aRep, nPos ) ) ) + nPos += 2; + nPos = 0; + aRep.AssignAscii( "\\;" ); + while( STRING_NOTFOUND != (nPos = aTmp.SearchAndReplaceAscii( ";", + aRep, nPos ) ) ) + nPos += 2; + if( i > 0 ) + aContent += ';'; + aContent += aTmp; + } + + rHTMLWrt.OutNewLine(); + ByteString sOut( '<' ); + (((((((sOut += OOO_STRING_SVTOOLS_HTML_meta) += ' ') + += OOO_STRING_SVTOOLS_HTML_O_name) += "=\"") += pName) += "\" ") + += OOO_STRING_SVTOOLS_HTML_O_content) += "=\""; + rWrt.Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( rWrt.Strm(), aContent, rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + rWrt.Strm() << "\">"; +} + +void SwHTMLWriter::OutFootEndNoteInfo() +{ + // Nummerntyp (1 bzw. i) + // Offset (0) + // Davor + // Dahinter + // Dok/Seite/Kap (D) + // Position (S) + // Folgeseite + // Beginn + + { + const SwFtnInfo& rInfo = pDoc->GetFtnInfo(); + String aParts[8]; + sal_uInt16 nParts = lcl_html_fillEndNoteInfo( rInfo, aParts, sal_False ); + if( rInfo.eNum != FTNNUM_DOC ) + { + aParts[4] = rInfo.eNum == FTNNUM_CHAPTER ? 'C' : 'P'; + nParts = 5; + } + if( rInfo.ePos != FTNPOS_PAGE) + { + aParts[5] = 'C'; + nParts = 6; + } + if( rInfo.aQuoVadis.Len() > 0 ) + { + aParts[6] = rInfo.aQuoVadis; + nParts = 7; + } + if( rInfo.aErgoSum.Len() > 0 ) + { + aParts[7] = rInfo.aErgoSum; + nParts = 8; + } + if( nParts > 0 ) + lcl_html_outFootEndNoteInfo( *this, aParts, nParts, + OOO_STRING_SVTOOLS_HTML_META_sdfootnote ); + } + + { + const SwEndNoteInfo& rInfo = pDoc->GetEndNoteInfo(); + String aParts[4]; + sal_uInt16 nParts = lcl_html_fillEndNoteInfo( rInfo, aParts, sal_True ); + if( nParts > 0 ) + lcl_html_outFootEndNoteInfo( *this, aParts, nParts, + OOO_STRING_SVTOOLS_HTML_META_sdendnote ); + } +} + diff --git a/sw/source/filter/html/htmlgrin.cxx b/sw/source/filter/html/htmlgrin.cxx new file mode 100644 index 000000000000..415c6447fac8 --- /dev/null +++ b/sw/source/filter/html/htmlgrin.cxx @@ -0,0 +1,1447 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include "hintids.hxx" +#include <vcl/svapp.hxx> +#include <vcl/wrkwin.hxx> +#include <svx/svxids.hrc> +#include <sfx2/sfx.hrc> +#include <i18npool/mslangid.hxx> +#include <svl/stritem.hxx> +#include <svl/urihelper.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/adjitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/brshitem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/boxitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/langitem.hxx> +#include <editeng/scripttypeitem.hxx> +#include <sfx2/docfile.hxx> +#include <svtools/imap.hxx> +#include <svtools/htmltokn.h> +#include <svtools/htmlkywd.hxx> +#include <unotools/eventcfg.hxx> + +#include <fmtornt.hxx> +#include <fmturl.hxx> +#include <fmtanchr.hxx> +#include <fmtsrnd.hxx> +#include <fmtinfmt.hxx> +#include <fmtcntnt.hxx> +#include <fmtanchr.hxx> +#include <fmtfsize.hxx> +#include <fmtinfmt.hxx> +#include "frmatr.hxx" +#include "charatr.hxx" +#include <frmfmt.hxx> +#include <charfmt.hxx> +#include <docary.hxx> +#include <docsh.hxx> +#include <pam.hxx> +#include <doc.hxx> +#include <ndtxt.hxx> +#include <shellio.hxx> +#include <poolfmt.hxx> +#include <IMark.hxx> +#include <ndgrf.hxx> +#include <htmlnum.hxx> +#include <swcss1.hxx> +#include <swhtml.hxx> +#include <numrule.hxx> +#include <boost/shared_ptr.hpp> + +using namespace ::com::sun::star; + + +HTMLOptionEnum __FAR_DATA aHTMLImgHAlignTable[] = +{ + { OOO_STRING_SVTOOLS_HTML_AL_left, text::HoriOrientation::LEFT }, + { OOO_STRING_SVTOOLS_HTML_AL_right, text::HoriOrientation::RIGHT }, + { 0, 0 } +}; + + +HTMLOptionEnum __FAR_DATA aHTMLImgVAlignTable[] = +{ + { OOO_STRING_SVTOOLS_HTML_VA_top, text::VertOrientation::LINE_TOP }, + { OOO_STRING_SVTOOLS_HTML_VA_texttop, text::VertOrientation::CHAR_TOP }, + { OOO_STRING_SVTOOLS_HTML_VA_middle, text::VertOrientation::CENTER }, + { OOO_STRING_SVTOOLS_HTML_AL_center, text::VertOrientation::CENTER }, + { OOO_STRING_SVTOOLS_HTML_VA_absmiddle, text::VertOrientation::LINE_CENTER }, + { OOO_STRING_SVTOOLS_HTML_VA_bottom, text::VertOrientation::TOP }, + { OOO_STRING_SVTOOLS_HTML_VA_baseline, text::VertOrientation::TOP }, + { OOO_STRING_SVTOOLS_HTML_VA_absbottom, text::VertOrientation::LINE_BOTTOM }, + { 0, 0 } +}; + +SV_IMPL_PTRARR( ImageMaps, ImageMapPtr ) + +ImageMap *SwHTMLParser::FindImageMap( const String& rName ) const +{ + ImageMap *pMap = 0; + + ASSERT( rName.GetChar(0) != '#', "FindImageName: Name beginnt mit #!" ); + + if( pImageMaps ) + { + for( sal_uInt16 i=0; i<pImageMaps->Count(); i++ ) + { + ImageMap *pIMap = (*pImageMaps)[i]; + if( rName.EqualsIgnoreCaseAscii( pIMap->GetName() ) ) + { + pMap = pIMap; + break; + } + } + } + return pMap; +} + +void SwHTMLParser::ConnectImageMaps() +{ + SwNodes& rNds = pDoc->GetNodes(); + // auf den Start-Node der 1. Section + sal_uLong nIdx = rNds.GetEndOfAutotext().StartOfSectionIndex() + 1; + sal_uLong nEndIdx = rNds.GetEndOfAutotext().GetIndex(); + + SwGrfNode* pGrfNd; + while( nMissingImgMaps > 0 && nIdx < nEndIdx ) + { + SwNode *pNd = rNds[nIdx + 1]; + if( 0 != (pGrfNd = pNd->GetGrfNode()) ) + { + SwFrmFmt *pFmt = pGrfNd->GetFlyFmt(); + SwFmtURL aURL( pFmt->GetURL() ); + const ImageMap *pIMap = aURL.GetMap(); + if( pIMap && pIMap->GetIMapObjectCount()==0 ) + { + // Die (leere) Image-Map des Nodes wird entweder + // durch die jetzt gefundene Image-Map ersetzt + // oder geloescht. + ImageMap *pNewIMap = + FindImageMap( pIMap->GetName() ); + aURL.SetMap( pNewIMap ); + pFmt->SetFmtAttr( aURL ); + if( !pGrfNd->IsScaleImageMap() ) + { + // die Grafikgroesse ist mitlerweile da oder dir + // Grafik muss nicht skaliert werden + pGrfNd->ScaleImageMap(); + } + nMissingImgMaps--; // eine Map weniger suchen + } + } + nIdx = rNds[nIdx]->EndOfSectionIndex() + 1; + } +} + + +/* */ + +void SwHTMLParser::SetAnchorAndAdjustment( sal_Int16 eVertOri, + sal_Int16 eHoriOri, + const SfxItemSet &rCSS1ItemSet, + const SvxCSS1PropertyInfo &rCSS1PropInfo, + SfxItemSet& rFrmItemSet ) +{ + const SfxItemSet *pCntnrItemSet = 0; + sal_uInt16 i = aContexts.Count(); + while( !pCntnrItemSet && i > nContextStMin ) + pCntnrItemSet = aContexts[--i]->GetFrmItemSet(); + + if( pCntnrItemSet ) + { + // Wenn wir und in einem Container befinden wird die Verankerung + // des Containers uebernommen. + rFrmItemSet.Put( *pCntnrItemSet ); + } + else if( pCSS1Parser->MayBePositioned( rCSS1PropInfo, sal_True ) ) + { + // Wenn die Ausrichtung anhand der CSS1-Optionen gesetzt werden kann + // werden die benutzt. + SetAnchorAndAdjustment( rCSS1ItemSet, rCSS1PropInfo, rFrmItemSet ); + } + else + { + // Sonst wird die Ausrichtung entsprechend der normalen HTML-Optionen + // gesetzt. + SetAnchorAndAdjustment( eVertOri, eHoriOri, rFrmItemSet ); + } +} + +void SwHTMLParser::SetAnchorAndAdjustment( sal_Int16 eVertOri, + sal_Int16 eHoriOri, + SfxItemSet& rFrmSet, + sal_Bool bDontAppend ) +{ + sal_Bool bMoveBackward = sal_False; + SwFmtAnchor aAnchor( FLY_AS_CHAR ); + sal_Int16 eVertRel = text::RelOrientation::FRAME; + + if( text::HoriOrientation::NONE != eHoriOri ) + { + // den Absatz-Einzug bestimmen + sal_uInt16 nLeftSpace = 0, nRightSpace = 0; + short nIndent = 0; + GetMarginsFromContextWithNumBul( nLeftSpace, nRightSpace, nIndent ); + + // Horizonale Ausrichtung und Umlauf bestimmen. + sal_Int16 eHoriRel; + SwSurround eSurround; + switch( eHoriOri ) + { + case text::HoriOrientation::LEFT: + eHoriRel = nLeftSpace ? text::RelOrientation::PRINT_AREA : text::RelOrientation::FRAME; + eSurround = SURROUND_RIGHT; + break; + case text::HoriOrientation::RIGHT: + eHoriRel = nRightSpace ? text::RelOrientation::PRINT_AREA : text::RelOrientation::FRAME; + eSurround = SURROUND_LEFT; + break; + case text::HoriOrientation::CENTER: // fuer Tabellen + eHoriRel = text::RelOrientation::FRAME; + eSurround = SURROUND_NONE; + break; + default: + eHoriRel = text::RelOrientation::FRAME; + eSurround = SURROUND_PARALLEL; + break; + } + + // Einen neuen Absatz aufmachen, wenn der aktuelle + // absatzgebundene Rahmen ohne Umlauf enthaelt. + if( !bDontAppend && HasCurrentParaFlys( sal_True ) ) + { + // Wenn der Absatz nur Grafiken enthaelt, braucht er + // auch keinen unteren Absatz-Abstand. Da hier auch bei + // Verwendung von Styles kein Abstand enstehen soll, wird + // hier auch geweohnlich attributiert !!! + sal_uInt16 nUpper=0, nLower=0; + GetULSpaceFromContext( nUpper, nLower ); + InsertAttr( SvxULSpaceItem( nUpper, 0, RES_UL_SPACE ), sal_False, sal_True ); + + AppendTxtNode( AM_NOSPACE ); + + if( nUpper ) + { + NewAttr( &aAttrTab.pULSpace, SvxULSpaceItem( 0, nLower, RES_UL_SPACE ) ); + aParaAttrs.Insert( aAttrTab.pULSpace, aParaAttrs.Count() ); + EndAttr( aAttrTab.pULSpace, 0, sal_False ); + } + } + + // Vertikale Ausrichtung und Verankerung bestimmen. + xub_StrLen nCntnt = pPam->GetPoint()->nContent.GetIndex(); + if( nCntnt ) + { + aAnchor.SetType( FLY_AT_CHAR ); + bMoveBackward = sal_True; + eVertOri = text::VertOrientation::CHAR_BOTTOM; + eVertRel = text::RelOrientation::CHAR; + } + else + { + aAnchor.SetType( FLY_AT_PARA ); + eVertOri = text::VertOrientation::TOP; + eVertRel = text::RelOrientation::PRINT_AREA; + } + + rFrmSet.Put( SwFmtHoriOrient( 0, eHoriOri, eHoriRel) ); + + rFrmSet.Put( SwFmtSurround( eSurround ) ); + } + rFrmSet.Put( SwFmtVertOrient( 0, eVertOri, eVertRel) ); + + if( bMoveBackward ) + pPam->Move( fnMoveBackward ); + + aAnchor.SetAnchor( pPam->GetPoint() ); + + if( bMoveBackward ) + pPam->Move( fnMoveForward ); + + rFrmSet.Put( aAnchor ); +} + +void SwHTMLParser::RegisterFlyFrm( SwFrmFmt *pFlyFmt ) +{ + // automatisch verankerte Rahmen muessen noch um eine Position + // nach vorne verschoben werden. + if( RES_DRAWFRMFMT != pFlyFmt->Which() && + (FLY_AT_PARA == pFlyFmt->GetAnchor().GetAnchorId()) && + SURROUND_THROUGHT == pFlyFmt->GetSurround().GetSurround() ) + { + aMoveFlyFrms.Insert( pFlyFmt, aMoveFlyFrms.Count() ); + aMoveFlyCnts.push_back( pPam->GetPoint()->nContent.GetIndex() ); + } +} + +/* */ + +void SwHTMLParser::GetDefaultScriptType( ScriptType& rType, + String& rTypeStr ) const +{ + SwDocShell *pDocSh = pDoc->GetDocShell(); + SvKeyValueIterator* pHeaderAttrs = pDocSh ? pDocSh->GetHeaderAttributes() + : 0; + rType = GetScriptType( pHeaderAttrs ); + rTypeStr = GetScriptTypeString( pHeaderAttrs ); +} + +/* */ + +void SwHTMLParser::InsertImage() +{ + // und jetzt auswerten + String sGrfNm, sAltNm, aId, aClass, aStyle, aMap, sHTMLGrfName; + sal_Int16 eVertOri = text::VertOrientation::TOP; + sal_Int16 eHoriOri = text::HoriOrientation::NONE; + long nWidth=0, nHeight=0; + long nVSpace=0, nHSpace=0; + + sal_uInt16 nBorder = (aAttrTab.pINetFmt ? 1 : 0); + sal_Bool bIsMap = sal_False; + sal_Bool bPrcWidth = sal_False; + sal_Bool bPrcHeight = sal_False; + SvxMacroItem aMacroItem(RES_FRMMACRO); + + ScriptType eDfltScriptType; + String sDfltScriptType; + GetDefaultScriptType( eDfltScriptType, sDfltScriptType ); + + const HTMLOptions *pHTMLOptions = GetOptions(); + for( sal_uInt16 i = pHTMLOptions->Count(); i; ) + { + sal_uInt16 nEvent = 0; + ScriptType eScriptType2 = eDfltScriptType; + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + case HTML_O_SRC: + sGrfNm = pOption->GetString(); + if( !InternalImgToPrivateURL(sGrfNm) ) + sGrfNm = INetURLObject::GetAbsURL( sBaseURL, sGrfNm ); + break; + case HTML_O_ALIGN: + eVertOri = + pOption->GetEnum( aHTMLImgVAlignTable, + text::VertOrientation::TOP ); + eHoriOri = + pOption->GetEnum( aHTMLImgHAlignTable, + text::HoriOrientation::NONE ); + break; + case HTML_O_WIDTH: + // erstmal nur als Pixelwerte merken! + nWidth = pOption->GetNumber(); + bPrcWidth = (pOption->GetString().Search('%') != STRING_NOTFOUND); + if( bPrcWidth && nWidth>100 ) + nWidth = 100; + break; + case HTML_O_HEIGHT: + // erstmal nur als Pixelwerte merken! + nHeight = pOption->GetNumber(); + bPrcHeight = (pOption->GetString().Search('%') != STRING_NOTFOUND); + if( bPrcHeight && nHeight>100 ) + nHeight = 100; + break; + case HTML_O_VSPACE: + nVSpace = pOption->GetNumber(); + break; + case HTML_O_HSPACE: + nHSpace = pOption->GetNumber(); + break; + case HTML_O_ALT: + sAltNm = pOption->GetString(); + break; + case HTML_O_BORDER: + nBorder = (sal_uInt16)pOption->GetNumber(); + break; + case HTML_O_ISMAP: + bIsMap = sal_True; + break; + case HTML_O_USEMAP: + aMap = pOption->GetString(); + break; + case HTML_O_NAME: + sHTMLGrfName = pOption->GetString(); + break; + + case HTML_O_SDONLOAD: + eScriptType2 = STARBASIC; + case HTML_O_ONLOAD: + nEvent = SVX_EVENT_IMAGE_LOAD; + goto IMAGE_SETEVENT; + + case HTML_O_SDONABORT: + eScriptType2 = STARBASIC; + case HTML_O_ONABORT: + nEvent = SVX_EVENT_IMAGE_ABORT; + goto IMAGE_SETEVENT; + + case HTML_O_SDONERROR: + eScriptType2 = STARBASIC; + case HTML_O_ONERROR: + nEvent = SVX_EVENT_IMAGE_ERROR; + goto IMAGE_SETEVENT; +IMAGE_SETEVENT: + { + String sTmp( pOption->GetString() ); + if( sTmp.Len() ) + { + sTmp.ConvertLineEnd(); + String sScriptType; + if( EXTENDED_STYPE == eScriptType2 ) + sScriptType = sDfltScriptType; + aMacroItem.SetMacro( nEvent, + SvxMacro( sTmp, sScriptType, eScriptType2 )); + } + } + break; + } + } + + if( !sGrfNm.Len() ) + return; + + // Wenn wir in einer Numerierung stehen und der Absatz noch leer und + // nicht numeriert ist, handelt es sich vielleicht um die Grafik + // einer Bullet-Liste + if( !pPam->GetPoint()->nContent.GetIndex() && + GetNumInfo().GetDepth() > 0 && GetNumInfo().GetDepth() <= MAXLEVEL && + aBulletGrfs[GetNumInfo().GetDepth()-1].Len() && + aBulletGrfs[GetNumInfo().GetDepth()-1]==sGrfNm ) + { + SwTxtNode* pTxtNode = pPam->GetNode()->GetTxtNode(); + + if( pTxtNode && ! pTxtNode->IsCountedInList()) + { + ASSERT( pTxtNode->GetActualListLevel() == GetNumInfo().GetLevel(), + "Numerierungs-Ebene stimmt nicht" ); + + pTxtNode->SetCountedInList( true ); + + // Rule invalisieren ist noetig, weil zwischem dem einlesen + // des LI und der Grafik ein EndAction gerufen worden sein kann. + if( GetNumInfo().GetNumRule() ) + GetNumInfo().GetNumRule()->SetInvalidRule( sal_True ); + + // Die Vorlage novh mal setzen. Ist noetig, damit der + // Erstzeilen-Einzug stimmt. + SetTxtCollAttrs(); + + return; + } + } + + SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + if( HasStyleOptions( aStyle, aId, aClass ) ) + ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo ); + + SfxItemSet aFrmSet( pDoc->GetAttrPool(), + RES_FRMATR_BEGIN, RES_FRMATR_END-1 ); + if( !IsNewDoc() ) + Reader::ResetFrmFmtAttrs( aFrmSet ); + + // Umrandung setzen + long nHBorderWidth = 0, nVBorderWidth = 0; + if( nBorder ) + { + nHBorderWidth = (long)nBorder; + nVBorderWidth = (long)nBorder; + SvxCSS1Parser::PixelToTwip( nVBorderWidth, nHBorderWidth ); + + SvxBorderLine aHBorderLine; + SvxBorderLine aVBorderLine; + + SvxCSS1Parser::SetBorderWidth( aHBorderLine, + (sal_uInt16)nHBorderWidth, sal_False ); + if( nHBorderWidth == nVBorderWidth ) + aVBorderLine.SetOutWidth( aHBorderLine.GetOutWidth() ); + else + SvxCSS1Parser::SetBorderWidth( aVBorderLine, + (sal_uInt16)nVBorderWidth, sal_False ); + + // die tatsaechlich gesetzter Rahmenbreite benutzen und nicht die + // Wunschbreite! + nHBorderWidth = aHBorderLine.GetOutWidth(); + nVBorderWidth = aVBorderLine.GetOutWidth(); + + if( aAttrTab.pINetFmt ) + { + const String& rURL = + ((const SwFmtINetFmt&)aAttrTab.pINetFmt->GetItem()).GetValue(); + + pCSS1Parser->SetATagStyles(); + sal_uInt16 nPoolId = static_cast< sal_uInt16 >(pDoc->IsVisitedURL( rURL ) + ? RES_POOLCHR_INET_VISIT + : RES_POOLCHR_INET_NORMAL); + const SwCharFmt *pCharFmt = pCSS1Parser->GetCharFmtFromPool( nPoolId ); + aHBorderLine.SetColor( pCharFmt->GetColor().GetValue() ); + aVBorderLine.SetColor( aHBorderLine.GetColor() ); + } + else + { + const SvxColorItem& rColorItem = aAttrTab.pFontColor ? + (const SvxColorItem &)aAttrTab.pFontColor->GetItem() : + (const SvxColorItem &)pDoc->GetDefault(RES_CHRATR_COLOR); + aHBorderLine.SetColor( rColorItem.GetValue() ); + aVBorderLine.SetColor( aHBorderLine.GetColor() ); + } + + + SvxBoxItem aBoxItem( RES_BOX ); + aBoxItem.SetLine( &aHBorderLine, BOX_LINE_TOP ); + aBoxItem.SetLine( &aHBorderLine, BOX_LINE_BOTTOM ); + aBoxItem.SetLine( &aVBorderLine, BOX_LINE_LEFT ); + aBoxItem.SetLine( &aVBorderLine, BOX_LINE_RIGHT ); + aFrmSet.Put( aBoxItem ); + } + + // Ausrichtung setzen + SetAnchorAndAdjustment( eVertOri, eHoriOri, aItemSet, aPropInfo, aFrmSet ); + + // Abstaende setzen + SetSpace( Size( nHSpace, nVSpace), aItemSet, aPropInfo, aFrmSet ); + + // Sonstige CSS1-Attribute Setzen + SetFrmFmtAttrs( aItemSet, aPropInfo, HTML_FF_BOX, aFrmSet ); + + Size aTwipSz( bPrcWidth ? 0 : nWidth, bPrcHeight ? 0 : nHeight ); + if( (aTwipSz.Width() || aTwipSz.Height()) && Application::GetDefaultDevice() ) + { + aTwipSz = Application::GetDefaultDevice() + ->PixelToLogic( aTwipSz, MapMode( MAP_TWIP ) ); + } + + // CSS1-Groesse auf "normale" Groesse umrechnen + switch( aPropInfo.eWidthType ) + { + case SVX_CSS1_LTYPE_TWIP: + aTwipSz.Width() = aPropInfo.nWidth; + nWidth = 1; // != 0 + bPrcWidth = sal_False; + break; + case SVX_CSS1_LTYPE_PERCENTAGE: + aTwipSz.Width() = 0; + nWidth = aPropInfo.nWidth; + bPrcWidth = sal_True; + break; + default: + ; + } + switch( aPropInfo.eHeightType ) + { + case SVX_CSS1_LTYPE_TWIP: + aTwipSz.Height() = aPropInfo.nHeight; + nHeight = 1; // != 0 + bPrcHeight = sal_False; + break; + case SVX_CSS1_LTYPE_PERCENTAGE: + aTwipSz.Height() = 0; + nHeight = aPropInfo.nHeight; + bPrcHeight = sal_True; + break; + default: + ; + } + + Size aGrfSz( 0, 0 ); + sal_Bool bSetTwipSize = sal_True; // Twip-Size am Node setzen? + sal_Bool bChangeFrmSize = sal_False; // Frame-Format nachtraeglich anpassen? + sal_Bool bRequestGrfNow = sal_False; + sal_Bool bSetScaleImageMap = sal_False; + sal_uInt8 nPrcWidth = 0, nPrcHeight = 0; + + if( !nWidth || !nHeight ) + { + // Es fehlt die Breite oder die Hoehe + // Wenn die Grfik in einer Tabelle steht, wird sie gleich + // angefordert, damit sie eventuell schon da ist, bevor die + // Tabelle layoutet wird. + if( pTable!=0 && !nWidth ) + { + bRequestGrfNow = sal_True; + IncGrfsThatResizeTable(); + } + + // Die Groesse des Rahmens wird nachtraeglich gesetzt + bChangeFrmSize = sal_True; + aGrfSz = aTwipSz; + if( !nWidth && !nHeight ) + { + aTwipSz.Width() = HTML_DFLT_IMG_WIDTH; + aTwipSz.Height() = HTML_DFLT_IMG_HEIGHT; + } + else if( nWidth ) + { + // eine %-Angabe + if( bPrcWidth ) + { + nPrcWidth = (sal_uInt8)nWidth; + nPrcHeight = 255; + } + else + { + aTwipSz.Height() = HTML_DFLT_IMG_HEIGHT; + } + } + else if( nHeight ) + { + if( bPrcHeight ) + { + nPrcHeight = (sal_uInt8)nHeight; + nPrcWidth = 255; + } + else + { + aTwipSz.Width() = HTML_DFLT_IMG_WIDTH; + } + } + } + else + { + // Breite und Hoehe wurden angegeben und brauchen nicht gesetzt + // zu werden + bSetTwipSize = sal_False; + + if( bPrcWidth ) + nPrcWidth = (sal_uInt8)nWidth; + + if( bPrcHeight ) + nPrcHeight = (sal_uInt8)nHeight; + } + + // Image-Map setzen + aMap.EraseTrailingChars(); + if( aMap.Len() ) + { + // Da wir nur lokale Image-Maps kennen nehmen wireinfach alles + // hinter dem # als Namen + xub_StrLen nPos = aMap.Search( '#' ); + String aName; + if ( STRING_NOTFOUND==nPos ) + aName = aMap ; + else + aName = aMap.Copy(nPos+1); + + ImageMap *pImgMap = FindImageMap( aName ); + if( pImgMap ) + { + SwFmtURL aURL; aURL.SetMap( pImgMap );//wird kopieiert + + bSetScaleImageMap = !nPrcWidth || !nPrcHeight; + aFrmSet.Put( aURL ); + } + else + { + ImageMap aEmptyImgMap( aName ); + SwFmtURL aURL; aURL.SetMap( &aEmptyImgMap );//wird kopieiert + aFrmSet.Put( aURL ); + nMissingImgMaps++; // es fehlen noch Image-Maps + + // die Grafik muss beim SetTwipSize skaliert werden, wenn + // wir keine Groesse am Node gesetzt haben oder die Groesse + // nicht der Grafikgroesse entsprach. + bSetScaleImageMap = sal_True; + } + } + + // min. Werte einhalten !! + if( nPrcWidth ) + { + ASSERT( !aTwipSz.Width(), + "Wieso ist da trotz %-Angabe eine Breite gesetzt?" ); + aTwipSz.Width() = aGrfSz.Width() ? aGrfSz.Width() + : HTML_DFLT_IMG_WIDTH; + } + else + { + aTwipSz.Width() += 2*nVBorderWidth; + if( aTwipSz.Width() < MINFLY ) + aTwipSz.Width() = MINFLY; + } + if( nPrcHeight ) + { + ASSERT( !aTwipSz.Height(), + "Wieso ist da trotz %-Angabe eine Hoehe gesetzt?" ); + aTwipSz.Height() = aGrfSz.Height() ? aGrfSz.Height() + : HTML_DFLT_IMG_HEIGHT; + } + else + { + aTwipSz.Height() += 2*nHBorderWidth; + if( aTwipSz.Height() < MINFLY ) + aTwipSz.Height() = MINFLY; + } + + SwFmtFrmSize aFrmSize( ATT_FIX_SIZE, aTwipSz.Width(), aTwipSz.Height() ); + aFrmSize.SetWidthPercent( nPrcWidth ); + aFrmSize.SetHeightPercent( nPrcHeight ); + aFrmSet.Put( aFrmSize ); + + Graphic aEmptyGrf; + aEmptyGrf.SetDefaultType(); + SwFrmFmt *pFlyFmt = pDoc->Insert( *pPam, sGrfNm, aEmptyStr, &aEmptyGrf, + &aFrmSet, NULL, NULL ); + SwGrfNode *pGrfNd = pDoc->GetNodes()[ pFlyFmt->GetCntnt().GetCntntIdx() + ->GetIndex()+1 ]->GetGrfNode(); + + if( sHTMLGrfName.Len() ) + { + pFlyFmt->SetName( sHTMLGrfName ); + + // ggfs. eine Grafik anspringen + if( JUMPTO_GRAPHIC == eJumpTo && sHTMLGrfName == sJmpMark ) + { + bChkJumpMark = sal_True; + eJumpTo = JUMPTO_NONE; + } + } + + if( sAltNm.Len() ) + pGrfNd->SetTitle( sAltNm ); + + if( bSetTwipSize ) + pGrfNd->SetTwipSize( aGrfSz ); + + pGrfNd->SetChgTwipSize( bChangeFrmSize, bChangeFrmSize ); + + if( bSetScaleImageMap ) + pGrfNd->SetScaleImageMap( sal_True ); + + if( aAttrTab.pINetFmt ) + { + const SwFmtINetFmt &rINetFmt = + (const SwFmtINetFmt&)aAttrTab.pINetFmt->GetItem(); + + SwFmtURL aURL( pFlyFmt->GetURL() ); + + aURL.SetURL( rINetFmt.GetValue(), bIsMap ); + aURL.SetTargetFrameName( rINetFmt.GetTargetFrame() ); + aURL.SetName( rINetFmt.GetName() ); + pFlyFmt->SetFmtAttr( aURL ); + + { + const SvxMacro *pMacro; + static sal_uInt16 __READONLY_DATA aEvents[] = { + SFX_EVENT_MOUSEOVER_OBJECT, + SFX_EVENT_MOUSECLICK_OBJECT, + SFX_EVENT_MOUSEOUT_OBJECT, + 0 }; + + for( sal_uInt16 n = 0; aEvents[ n ]; ++n ) + if( 0 != ( pMacro = rINetFmt.GetMacro( aEvents[ n ] ) )) + aMacroItem.SetMacro( aEvents[ n ], *pMacro ); + } + + if ((FLY_AS_CHAR == pFlyFmt->GetAnchor().GetAnchorId()) && + aAttrTab.pINetFmt->GetSttPara() == + pPam->GetPoint()->nNode && + aAttrTab.pINetFmt->GetSttCnt() == + pPam->GetPoint()->nContent.GetIndex() - 1 ) + { + // das Attribut wurde unmitellbar vor einer zeichengeb. + // Grafik eingefuegt, also verschieben wir es + aAttrTab.pINetFmt->SetStart( *pPam->GetPoint() ); + + // Wenn das Attribut auch ein Sprungziel ist, fuegen + // wir noch eine Bookmark vor der Grafik ein, weil das + // SwFmtURL kein Sprungziel ist. + if( rINetFmt.GetName().Len() ) + { + pPam->Move( fnMoveBackward ); + InsertBookmark( rINetFmt.GetName() ); + pPam->Move( fnMoveForward ); + } + } + + } + + if( aMacroItem.GetMacroTable().Count() ) + pFlyFmt->SetFmtAttr( aMacroItem ); + + // Wenn die Grafik gleich angeforder wird, muss dies geschehen, + // nachdem das Format vollstaendig aufgebaut ist, weil es evtl. + // gleich (synchron) angepasst wird (war bug #40983#) + if( bRequestGrfNow ) + { + pGrfNd->SwapIn(); + } + + // Ggf. Frames anlegen und Auto-gebundenen Rahmen registrieren + RegisterFlyFrm( pFlyFmt ); + + if( aId.Len() ) + InsertBookmark( aId ); +} + +/* */ + +void SwHTMLParser::InsertBodyOptions() +{ + pDoc->SetTxtFmtColl( *pPam, + pCSS1Parser->GetTxtCollFromPool( RES_POOLCOLL_TEXT ) ); + + String aBackGround, aId, aStyle, aLang, aDir; + Color aBGColor, aTextColor, aLinkColor, aVLinkColor; + sal_Bool bBGColor=sal_False, bTextColor=sal_False; + sal_Bool bLinkColor=sal_False, bVLinkColor=sal_False; + + ScriptType eDfltScriptType; + String sDfltScriptType; + GetDefaultScriptType( eDfltScriptType, sDfltScriptType ); + + const HTMLOptions *pHTMLOptions = GetOptions(); + for( sal_uInt16 i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + ScriptType eScriptType2 = eDfltScriptType; + rtl::OUString aEvent; + sal_Bool bSetEvent = sal_False; + + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_BACKGROUND: + aBackGround = pOption->GetString(); + break; + case HTML_O_BGCOLOR: + pOption->GetColor( aBGColor ); + bBGColor = sal_True; + break; + case HTML_O_TEXT: + pOption->GetColor( aTextColor ); + bTextColor = sal_True; + break; + case HTML_O_LINK: + pOption->GetColor( aLinkColor ); + bLinkColor = sal_True; + break; + case HTML_O_VLINK: + pOption->GetColor( aVLinkColor ); + bVLinkColor = sal_True; + break; + + case HTML_O_SDONLOAD: + eScriptType2 = STARBASIC; + case HTML_O_ONLOAD: + aEvent = GlobalEventConfig::GetEventName( STR_EVENT_OPENDOC ); + bSetEvent = sal_True; + break; + + case HTML_O_SDONUNLOAD: + eScriptType2 = STARBASIC; + case HTML_O_ONUNLOAD: + aEvent = GlobalEventConfig::GetEventName( STR_EVENT_PREPARECLOSEDOC ); + bSetEvent = sal_True; + break; + + case HTML_O_SDONFOCUS: + eScriptType2 = STARBASIC; + case HTML_O_ONFOCUS: + aEvent = GlobalEventConfig::GetEventName( STR_EVENT_ACTIVATEDOC ); + bSetEvent = sal_True; + break; + + case HTML_O_SDONBLUR: + eScriptType2 = STARBASIC; + case HTML_O_ONBLUR: + aEvent = GlobalEventConfig::GetEventName( STR_EVENT_DEACTIVATEDOC ); + bSetEvent = sal_True; + break; + + case HTML_O_ONERROR: +// if( bAnyStarBasic ) +// InsertBasicDocEvent( SFX_EVENT_ACTIVATEDOC, +// pOption->GetString() ); + break; + + case HTML_O_STYLE: + aStyle = pOption->GetString(); + bTextColor = sal_True; + break; + case HTML_O_LANG: + aLang = pOption->GetString(); + break; + case HTML_O_DIR: + aDir = pOption->GetString(); + break; + } + + if( bSetEvent ) + { + const String& rEvent = pOption->GetString(); + if( rEvent.Len() ) + InsertBasicDocEvent( aEvent, rEvent, eScriptType2, + sDfltScriptType ); + } + } + + if( bTextColor && !pCSS1Parser->IsBodyTextSet() ) + { + // Die Textfarbe wird an der Standard-Vorlage gesetzt + pCSS1Parser->GetTxtCollFromPool( RES_POOLCOLL_STANDARD ) + ->SetFmtAttr( SvxColorItem(aTextColor, RES_CHRATR_COLOR) ); + pCSS1Parser->SetBodyTextSet(); + } + + + // Die Item fuer die Seitenvorlage vorbereiten (Hintergrund, Umrandung) + // Beim BrushItem muessen schon gesetzte werte erhalten bleiben! + SvxBrushItem aBrushItem( pCSS1Parser->GetPageDescBackground() ); + sal_Bool bSetBrush = sal_False; + + if( bBGColor && !pCSS1Parser->IsBodyBGColorSet() ) + { + // Hintergrundfarbe aus "BGCOLOR" + String aLink; + if( aBrushItem.GetGraphicLink() ) + aLink = *aBrushItem.GetGraphicLink(); + SvxGraphicPosition ePos = aBrushItem.GetGraphicPos(); + + aBrushItem.SetColor( aBGColor ); + + if( aLink.Len() ) + { + aBrushItem.SetGraphicLink( aLink ); + aBrushItem.SetGraphicPos( ePos ); + } + bSetBrush = sal_True; + pCSS1Parser->SetBodyBGColorSet(); + } + + if( aBackGround.Len() && !pCSS1Parser->IsBodyBackgroundSet() ) + { + // Hintergrundgrafik aus "BACKGROUND" + aBrushItem.SetGraphicLink( INetURLObject::GetAbsURL( sBaseURL, aBackGround ) ); + aBrushItem.SetGraphicPos( GPOS_TILED ); + bSetBrush = sal_True; + pCSS1Parser->SetBodyBackgroundSet(); + } + + if( aStyle.Len() || aDir.Len() ) + { + SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + String aDummy; + ParseStyleOptions( aStyle, aDummy, aDummy, aItemSet, aPropInfo, 0, &aDir ); + + // Ein par Attribute muessen an der Seitenvorlage gesetzt werden, + // und zwar die, die nicht vererbit werden + pCSS1Parser->SetPageDescAttrs( bSetBrush ? &aBrushItem : 0, + &aItemSet ); + + const SfxPoolItem *pItem; + static sal_uInt16 aWhichIds[3] = { RES_CHRATR_FONTSIZE, + RES_CHRATR_CJK_FONTSIZE, + RES_CHRATR_CTL_FONTSIZE }; + for( sal_uInt16 i=0; i<3; i++ ) + { + if( SFX_ITEM_SET == aItemSet.GetItemState( aWhichIds[i], sal_False, + &pItem ) && + static_cast <const SvxFontHeightItem * >(pItem)->GetProp() != 100) + { + sal_uInt32 nHeight = + ( aFontHeights[2] * + static_cast <const SvxFontHeightItem * >(pItem)->GetProp() ) / 100; + SvxFontHeightItem aNewItem( nHeight, 100, aWhichIds[i] ); + aItemSet.Put( aNewItem ); + } + } + + // alle noch uebrigen Optionen koennen an der Standard-Vorlage + // gesetzt werden und gelten dann automatisch als defaults + pCSS1Parser->GetTxtCollFromPool( RES_POOLCOLL_STANDARD ) + ->SetFmtAttr( aItemSet ); + } + else if( bSetBrush ) + { + pCSS1Parser->SetPageDescAttrs( &aBrushItem ); + } + + if( bLinkColor && !pCSS1Parser->IsBodyLinkSet() ) + { + SwCharFmt *pCharFmt = + pCSS1Parser->GetCharFmtFromPool(RES_POOLCHR_INET_NORMAL); + pCharFmt->SetFmtAttr( SvxColorItem(aLinkColor, RES_CHRATR_COLOR) ); + pCSS1Parser->SetBodyLinkSet(); + } + if( bVLinkColor && !pCSS1Parser->IsBodyVLinkSet() ) + { + SwCharFmt *pCharFmt = + pCSS1Parser->GetCharFmtFromPool(RES_POOLCHR_INET_VISIT); + pCharFmt->SetFmtAttr( SvxColorItem(aVLinkColor, RES_CHRATR_COLOR) ); + pCSS1Parser->SetBodyVLinkSet(); + } + if( aLang.Len() ) + { + LanguageType eLang = MsLangId::convertIsoStringToLanguage( aLang ); + sal_uInt16 nWhich = 0; + if( LANGUAGE_DONTKNOW != eLang ) + { + switch( SvtLanguageOptions::GetScriptTypeOfLanguage( eLang ) ) + { + case SCRIPTTYPE_LATIN: + nWhich = RES_CHRATR_LANGUAGE; + break; + case SCRIPTTYPE_ASIAN: + nWhich = RES_CHRATR_CJK_LANGUAGE; + break; + case SCRIPTTYPE_COMPLEX: + nWhich = RES_CHRATR_CTL_LANGUAGE; + break; + } + if( nWhich ) + { + SvxLanguageItem aLanguage( eLang, nWhich ); + aLanguage.SetWhich( nWhich ); + pDoc->SetDefault( aLanguage ); + } + } + } + + if( aId.Len() ) + InsertBookmark( aId ); +} + +/* */ + +void SwHTMLParser::NewAnchor() +{ + // den voherigen Link beenden, falls es einen gab + _HTMLAttrContext *pOldCntxt = PopContext( HTML_ANCHOR_ON ); + if( pOldCntxt ) + { + // und ggf. die Attribute beenden + EndContext( pOldCntxt ); + delete pOldCntxt; + } + + SvxMacroTableDtor aMacroTbl; + String sHRef, aName, sTarget; + String aId, aStyle, aClass, aLang, aDir; + sal_Bool bHasHRef = sal_False, bFixed = sal_False; + + ScriptType eDfltScriptType; + String sDfltScriptType; + GetDefaultScriptType( eDfltScriptType, sDfltScriptType ); + + const HTMLOptions *pHTMLOptions = GetOptions(); + for( sal_uInt16 i = pHTMLOptions->Count(); i; ) + { + sal_uInt16 nEvent = 0; + ScriptType eScriptType2 = eDfltScriptType; + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_NAME: + aName = pOption->GetString(); + break; + + case HTML_O_HREF: + sHRef = pOption->GetString(); + bHasHRef = sal_True; + break; + case HTML_O_TARGET: + sTarget = pOption->GetString(); + break; + + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + case HTML_O_SDFIXED: + bFixed = sal_True; + break; + case HTML_O_LANG: + aLang = pOption->GetString(); + break; + case HTML_O_DIR: + aDir = pOption->GetString(); + break; + + case HTML_O_SDONCLICK: + eScriptType2 = STARBASIC; + case HTML_O_ONCLICK: + nEvent = SFX_EVENT_MOUSECLICK_OBJECT; + goto ANCHOR_SETEVENT; + + case HTML_O_SDONMOUSEOVER: + eScriptType2 = STARBASIC; + case HTML_O_ONMOUSEOVER: + nEvent = SFX_EVENT_MOUSEOVER_OBJECT; + goto ANCHOR_SETEVENT; + + case HTML_O_SDONMOUSEOUT: + eScriptType2 = STARBASIC; + case HTML_O_ONMOUSEOUT: + nEvent = SFX_EVENT_MOUSEOUT_OBJECT; + goto ANCHOR_SETEVENT; +ANCHOR_SETEVENT: + { + String sTmp( pOption->GetString() ); + if( sTmp.Len() ) + { + sTmp.ConvertLineEnd(); + String sScriptType; + if( EXTENDED_STYPE == eScriptType2 ) + sScriptType = sDfltScriptType; + aMacroTbl.Insert( nEvent, + new SvxMacro( sTmp, sScriptType, eScriptType2 )); + } + } + break; + + } + } + + // Sprungziele, die unseren ipmliziten Zielen entsprechen, schmeissen + // wir hier ganz rigoros raus. + if( aName.Len() ) + { + String sDecoded( INetURLObject::decode( aName, INET_HEX_ESCAPE, + INetURLObject::DECODE_UNAMBIGUOUS, + RTL_TEXTENCODING_UTF8 )); + xub_StrLen nPos = sDecoded.SearchBackward( cMarkSeperator ); + if( STRING_NOTFOUND != nPos ) + { + String sCmp( sDecoded.Copy( nPos+1 ) ); + sCmp.EraseAllChars(); + if( sCmp.Len() ) + { + sCmp.ToLowerAscii(); + if( sCmp.EqualsAscii( pMarkToRegion ) || + sCmp.EqualsAscii( pMarkToFrame ) || + sCmp.EqualsAscii( pMarkToGraphic ) || + sCmp.EqualsAscii( pMarkToOLE ) || + sCmp.EqualsAscii( pMarkToTable ) || + sCmp.EqualsAscii( pMarkToOutline ) || + sCmp.EqualsAscii( pMarkToText ) ) + { + aName.Erase(); + } + } + } + } + + // einen neuen Kontext anlegen + _HTMLAttrContext *pCntxt = new _HTMLAttrContext( HTML_ANCHOR_ON ); + + sal_Bool bEnAnchor = sal_False, bFtnAnchor = sal_False, bFtnEnSymbol = sal_False; + String aFtnName; + String aStrippedClass( aClass ); + SwCSS1Parser::GetScriptFromClass( aStrippedClass, sal_False ); + if( aStrippedClass.Len() >=9 && bHasHRef && sHRef.Len() > 1 && + ('s' == aStrippedClass.GetChar(0) || 'S' == aStrippedClass.GetChar(0)) && + ('d' == aStrippedClass.GetChar(1) || 'D' == aStrippedClass.GetChar(1)) ) + { + if( aStrippedClass.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_sdendnote_anc ) ) + bEnAnchor = sal_True; + else if( aStrippedClass.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_sdfootnote_anc ) ) + bFtnAnchor = sal_True; + else if( aStrippedClass.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_sdendnote_sym ) || + aStrippedClass.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_sdfootnote_sym ) ) + bFtnEnSymbol = sal_True; + if( bEnAnchor || bFtnAnchor || bFtnEnSymbol ) + { + aFtnName = sHRef.Copy( 1 ); + aClass = aStrippedClass = aName = aEmptyStr; + bHasHRef = sal_False; + } + } + + // Styles parsen + if( HasStyleOptions( aStyle, aId, aStrippedClass, &aLang, &aDir ) ) + { + SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + + if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) ) + { + DoPositioning( aItemSet, aPropInfo, pCntxt ); + InsertAttrs( aItemSet, aPropInfo, pCntxt, sal_True ); + } + } + + if( bHasHRef ) + { + if( sHRef.Len() ) + { + sHRef = URIHelper::SmartRel2Abs( INetURLObject(sBaseURL), sHRef, Link(), false ); + } + else + { + // Bei leerer URL das Directory nehmen + INetURLObject aURLObj( aPathToFile ); + sHRef = aURLObj.GetPartBeforeLastName(); + } + + pCSS1Parser->SetATagStyles(); + SwFmtINetFmt aINetFmt( sHRef, sTarget ); + aINetFmt.SetName( aName ); + + if( aMacroTbl.Count() ) + aINetFmt.SetMacroTbl( &aMacroTbl ); + + // das Default-Attribut setzen + InsertAttr( &aAttrTab.pINetFmt, aINetFmt, pCntxt ); + } + else if( aName.Len() ) + { + InsertBookmark( aName ); + } + + if( bEnAnchor || bFtnAnchor ) + { + InsertFootEndNote( aFtnName, bEnAnchor, bFixed ); + bInFootEndNoteAnchor = bCallNextToken = sal_True; + } + else if( bFtnEnSymbol ) + { + bInFootEndNoteSymbol = bCallNextToken = sal_True; + } + + // den Kontext merken + PushContext( pCntxt ); +} + +void SwHTMLParser::EndAnchor() +{ + if( bInFootEndNoteAnchor ) + { + FinishFootEndNote(); + bInFootEndNoteAnchor = sal_False; + } + else if( bInFootEndNoteSymbol ) + { + bInFootEndNoteSymbol = sal_False; + } + + EndTag( HTML_ANCHOR_OFF ); +} + +/* */ + +void SwHTMLParser::InsertBookmark( const String& rName ) +{ + _HTMLAttr* pTmp = new _HTMLAttr( *pPam->GetPoint(), + SfxStringItem( RES_FLTR_BOOKMARK, rName )); + aSetAttrTab.Insert( pTmp, aSetAttrTab.Count() ); +} + +sal_Bool SwHTMLParser::HasCurrentParaBookmarks( sal_Bool bIgnoreStack ) const +{ + sal_Bool bHasMarks = sal_False; + sal_uLong nNodeIdx = pPam->GetPoint()->nNode.GetIndex(); + + // first step: are there still bookmark in the attribute-stack? + // bookmarks are added to the end of the stack - thus we only have + // to check the last bookmark + if( !bIgnoreStack ) + { + _HTMLAttr* pAttr; + for( sal_uInt16 i = aSetAttrTab.Count(); i; ) + { + pAttr = aSetAttrTab[ --i ]; + if( RES_FLTR_BOOKMARK == pAttr->pItem->Which() ) + { + if( pAttr->GetSttParaIdx() == nNodeIdx ) + bHasMarks = sal_True; + break; + } + } + } + + if( !bHasMarks ) + { + // second step: when we didnt find a bookmark, check if there is one + // set already + IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess(); + for(IDocumentMarkAccess::const_iterator_t ppMark = pMarkAccess->getMarksBegin(); + ppMark != pMarkAccess->getMarksEnd(); + ppMark++) + { + const ::sw::mark::IMark* pBookmark = ppMark->get(); + sal_uLong nBookNdIdx = pBookmark->GetMarkPos().nNode.GetIndex(); + if( nBookNdIdx==nNodeIdx ) + { + bHasMarks = sal_True; + break; + } + else if( nBookNdIdx > nNodeIdx ) + break; + } + } + + return bHasMarks; +} + +/* */ + +void SwHTMLParser::StripTrailingPara() +{ + sal_Bool bSetSmallFont = sal_False; + + SwCntntNode* pCNd = pPam->GetCntntNode(); + if( !pPam->GetPoint()->nContent.GetIndex() ) + { + if( pCNd && pCNd->StartOfSectionIndex()+2 < + pCNd->EndOfSectionIndex() ) + { + sal_uLong nNodeIdx = pPam->GetPoint()->nNode.GetIndex(); + + const SwSpzFrmFmts& rFrmFmtTbl = *pDoc->GetSpzFrmFmts(); + + for( sal_uInt16 i=0; i<rFrmFmtTbl.Count(); i++ ) + { + SwFrmFmt const*const pFmt = rFrmFmtTbl[i]; + SwFmtAnchor const*const pAnchor = &pFmt->GetAnchor(); + SwPosition const*const pAPos = pAnchor->GetCntntAnchor(); + if (pAPos && + ((FLY_AT_PARA == pAnchor->GetAnchorId()) || + (FLY_AT_CHAR == pAnchor->GetAnchorId())) && + pAPos->nNode == nNodeIdx ) + + return; // den Knoten duerfen wir nicht loeschen + } + + SetAttr( sal_False ); // die noch offenen Attribute muessen + // beendet werden, bevor der Node + // geloescht wird, weil sonst der + // End-Index in die Botanik zeigt + + if( pCNd->Len() && pCNd->IsTxtNode() ) + { + // es wurden Felder in den Node eingefuegt, die muessen + // wir jetzt verschieben + SwTxtNode *pPrvNd = pDoc->GetNodes()[nNodeIdx-1]->GetTxtNode(); + if( pPrvNd ) + { + SwIndex aSrc( pCNd, 0 ); + pCNd->GetTxtNode()->CutText( pPrvNd, aSrc, pCNd->Len() ); + } + } + + // jetz muessen wir noch eventuell vorhandene Bookmarks + // verschieben + IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess(); + for(IDocumentMarkAccess::const_iterator_t ppMark = pMarkAccess->getMarksBegin(); + ppMark != pMarkAccess->getMarksEnd(); + ppMark++) + { + ::sw::mark::IMark* pMark = ppMark->get(); + sal_uLong nBookNdIdx = pMark->GetMarkPos().nNode.GetIndex(); + if(nBookNdIdx==nNodeIdx) + { + SwNodeIndex nNewNdIdx(pPam->GetPoint()->nNode); + SwCntntNode* pNd = pDoc->GetNodes().GoPrevious(&nNewNdIdx); + if(!pNd) + { + ASSERT(!this, "Hoppla, wo ist mein Vorgaenger-Node"); + return; + } + // --> OD 2007-09-27 #i81002# - refactoring + // Do not directly manipulate member of <SwBookmark> + { + SwPosition aNewPos(*pNd); + aNewPos.nContent.Assign(pNd, pNd->Len()); + const SwPaM aPaM(aNewPos); + pMarkAccess->repositionMark(ppMark->get(), aPaM); + } + // <-- + } + else if( nBookNdIdx > nNodeIdx ) + break; + } + + pPam->GetPoint()->nContent.Assign( 0, 0 ); + pPam->SetMark(); + pPam->DeleteMark(); + pDoc->GetNodes().Delete( pPam->GetPoint()->nNode ); + pPam->Move( fnMoveBackward, fnGoNode ); + } + else if( pCNd && pCNd->IsTxtNode() && pTable ) + { + // In leeren Zellen stellen wir einen kleinen Font ein, damit die + // Zelle nicht hoeher wird als die Grafik bzw. so niedrig wie + // moeglich bleibt. + bSetSmallFont = sal_True; + } + } + else if( pCNd && pCNd->IsTxtNode() && pTable && + pCNd->StartOfSectionIndex()+2 == + pCNd->EndOfSectionIndex() ) + { + // Wenn die Zelle nur zeichengebundene Grafiken/Rahmen enthaelt + // stellen wir ebenfalls einen kleinen Font ein. + bSetSmallFont = sal_True; + SwTxtNode* pTxtNd = pCNd->GetTxtNode(); + + xub_StrLen nPos = pPam->GetPoint()->nContent.GetIndex(); + while( bSetSmallFont && nPos>0 ) + { + --nPos; + bSetSmallFont = + (CH_TXTATR_BREAKWORD == pTxtNd->GetTxt().GetChar( nPos )) && + (0 != pTxtNd->GetTxtAttrForCharAt( nPos, RES_TXTATR_FLYCNT )); + } + } + + if( bSetSmallFont ) + { + SvxFontHeightItem aFontHeight( 40, 100, RES_CHRATR_FONTSIZE ); + pCNd->SetAttr( aFontHeight ); + aFontHeight.SetWhich( RES_CHRATR_CJK_FONTSIZE ); + pCNd->SetAttr( aFontHeight ); + aFontHeight.SetWhich( RES_CHRATR_CTL_FONTSIZE ); + pCNd->SetAttr( aFontHeight ); + } +} + diff --git a/sw/source/filter/html/htmlnum.cxx b/sw/source/filter/html/htmlnum.cxx new file mode 100644 index 000000000000..e6df6e3978e0 --- /dev/null +++ b/sw/source/filter/html/htmlnum.cxx @@ -0,0 +1,987 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <com/sun/star/style/NumberingType.hpp> +#include <hintids.hxx> +#include <svtools/htmltokn.h> +#include <svtools/htmlkywd.hxx> +#include <svtools/htmlout.hxx> +#include <svl/urihelper.hxx> +#include <editeng/brshitem.hxx> +#include <editeng/lrspitem.hxx> +#include <vcl/svapp.hxx> +#include <vcl/wrkwin.hxx> +#include <numrule.hxx> +#include <doc.hxx> +#include <docary.hxx> +#include <poolfmt.hxx> +#include <ndtxt.hxx> +#include <paratr.hxx> + +#include "htmlnum.hxx" +#include "swcss1.hxx" +#include "swhtml.hxx" +#include "wrthtml.hxx" + +#include <SwNodeNum.hxx> + +using namespace ::com::sun::star; + +// TODO: Unicode: Are these characters the correct ones? +#define HTML_BULLETCHAR_DISC (0xe008) +#define HTML_BULLETCHAR_CIRCLE (0xe009) +#define HTML_BULLETCHAR_SQUARE (0xe00b) + + +// <UL TYPE=...> +static HTMLOptionEnum __FAR_DATA aHTMLULTypeTable[] = +{ + { OOO_STRING_SVTOOLS_HTML_ULTYPE_disc, HTML_BULLETCHAR_DISC }, + { OOO_STRING_SVTOOLS_HTML_ULTYPE_circle, HTML_BULLETCHAR_CIRCLE }, + { OOO_STRING_SVTOOLS_HTML_ULTYPE_square, HTML_BULLETCHAR_SQUARE }, + { 0, 0 } +}; + +/* */ + +void SwHTMLNumRuleInfo::Set( const SwTxtNode& rTxtNd ) +{ + // --> OD 2006-06-12 #b6435904# + // export all numberings, except the outline numbering. +// if( rTxtNd.GetNumRule() && ! rTxtNd.IsOutline()) + const SwNumRule* pTxtNdNumRule( rTxtNd.GetNumRule() ); + if ( pTxtNdNumRule && + pTxtNdNumRule != rTxtNd.GetDoc()->GetOutlineNumRule() ) + { + pNumRule = const_cast<SwNumRule*>(pTxtNdNumRule); + nDeep = static_cast< sal_uInt16 >(pNumRule ? rTxtNd.GetActualListLevel() + 1 : 0); + bNumbered = rTxtNd.IsCountedInList(); + // --> OD 2008-02-27 #refactorlists# + // --> OD 2005-11-16 #i57919# + // correction of refactoring done by cws swnumtree: + // <bRestart> has to be set to <true>, if numbering is restarted at this + // text node and the start value equals <USHRT_MAX>. + // Start value <USHRT_MAX> indicates, that at this text node the numbering + // is restarted with the value given at the corresponding level. +// bRestart = rTxtNd.IsListRestart() && +// GetNum() && rTxtNd.GetNum()->GetStartValue() == USHRT_MAX; + bRestart = rTxtNd.IsListRestart() && !rTxtNd.HasAttrListRestartValue(); + // <-- + } + // <-- + else + { + pNumRule = 0; + nDeep = 0; + bNumbered = bRestart = sal_False; + } +} + +/* */ + +void SwHTMLParser::NewNumBulList( int nToken ) +{ + SwHTMLNumRuleInfo& rInfo = GetNumInfo(); + + // Erstmal einen neuen Absatz aufmachen + sal_Bool bSpace = (rInfo.GetDepth() + nDefListDeep) == 0; + if( pPam->GetPoint()->nContent.GetIndex() ) + AppendTxtNode( bSpace ? AM_SPACE : AM_NOSPACE, sal_False ); + else if( bSpace ) + AddParSpace(); + + // Die Numerierung-Ebene erhoehen + rInfo.IncDepth(); + sal_uInt8 nLevel = (sal_uInt8)( (rInfo.GetDepth() <= MAXLEVEL ? rInfo.GetDepth() + : MAXLEVEL) - 1 ); + + // ggf. ein Regelwerk anlegen + if( !rInfo.GetNumRule() ) + { + sal_uInt16 nPos = pDoc->MakeNumRule( pDoc->GetUniqueNumRuleName() ); + rInfo.SetNumRule( pDoc->GetNumRuleTbl()[nPos] ); + } + + // das Format anpassen, falls es fuer den Level noch nicht + // geschehen ist! + sal_Bool bNewNumFmt = rInfo.GetNumRule()->GetNumFmt( nLevel ) == 0; + sal_Bool bChangeNumFmt = sal_False; + + // das default Numerierungsformat erstellen + SwNumFmt aNumFmt( rInfo.GetNumRule()->Get(nLevel) ); + rInfo.SetNodeStartValue( nLevel ); + if( bNewNumFmt ) + { + sal_uInt16 nChrFmtPoolId = 0; + if( HTML_ORDERLIST_ON == nToken ) + { + aNumFmt.SetNumberingType(SVX_NUM_ARABIC); + nChrFmtPoolId = RES_POOLCHR_NUM_LEVEL; + } + else + { + // Wir setzen hier eine Zeichenvorlage, weil die UI das auch + // so macht. Dadurch wurd immer auch eine 9pt-Schrift + // eingestellt, was in Netscape nicht der Fall ist. Bisher hat + // das noch niemanden gestoert. + // --> OD 2008-06-03 #i63395# + // Only apply user defined default bullet font + if ( numfunc::IsDefBulletFontUserDefined() ) + { + aNumFmt.SetBulletFont( &numfunc::GetDefBulletFont() ); + } + // <-- + aNumFmt.SetNumberingType(SVX_NUM_CHAR_SPECIAL); + aNumFmt.SetBulletChar( cBulletChar ); // das Bulletzeichen !! + nChrFmtPoolId = RES_POOLCHR_BUL_LEVEL; + } + + sal_uInt16 nAbsLSpace = HTML_NUMBUL_MARGINLEFT; + + short nFirstLineIndent = HTML_NUMBUL_INDENT; + if( nLevel > 0 ) + { + const SwNumFmt& rPrevNumFmt = rInfo.GetNumRule()->Get( nLevel-1 ); + nAbsLSpace = nAbsLSpace + rPrevNumFmt.GetAbsLSpace(); + nFirstLineIndent = rPrevNumFmt.GetFirstLineOffset(); + } + aNumFmt.SetAbsLSpace( nAbsLSpace ); + aNumFmt.SetFirstLineOffset( nFirstLineIndent ); + aNumFmt.SetCharFmt( pCSS1Parser->GetCharFmtFromPool(nChrFmtPoolId) ); + + bChangeNumFmt = sal_True; + } + else if( 1 != aNumFmt.GetStart() ) + { + // Wenn die Ebene schon mal benutzt wurde, muss der Start-Wert + // ggf. hart am Absatz gesetzt werden. + rInfo.SetNodeStartValue( nLevel, 1 ); + } + + // und es ggf. durch die Optionen veraendern + String aId, aStyle, aClass, aBulletSrc, aLang, aDir; + sal_Int16 eVertOri = text::VertOrientation::NONE; + sal_uInt16 nWidth=USHRT_MAX, nHeight=USHRT_MAX; + const HTMLOptions *pHTMLOptions = GetOptions(); + for( sal_uInt16 i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_TYPE: + if( bNewNumFmt && pOption->GetString().Len() ) + { + switch( nToken ) + { + case HTML_ORDERLIST_ON: + bChangeNumFmt = sal_True; + switch( pOption->GetString().GetChar(0) ) + { + case 'A': aNumFmt.SetNumberingType(SVX_NUM_CHARS_UPPER_LETTER); break; + case 'a': aNumFmt.SetNumberingType(SVX_NUM_CHARS_LOWER_LETTER); break; + case 'I': aNumFmt.SetNumberingType(SVX_NUM_ROMAN_UPPER); break; + case 'i': aNumFmt.SetNumberingType(SVX_NUM_ROMAN_LOWER); break; + default: bChangeNumFmt = sal_False; + } + break; + + case HTML_UNORDERLIST_ON: + aNumFmt.SetBulletChar( (sal_Unicode)pOption->GetEnum( + aHTMLULTypeTable,aNumFmt.GetBulletChar() ) ); + bChangeNumFmt = sal_True; + break; + } + } + break; + case HTML_O_START: + { + sal_uInt16 nStart = (sal_uInt16)pOption->GetNumber(); + if( bNewNumFmt ) + { + aNumFmt.SetStart( nStart ); + bChangeNumFmt = sal_True; + } + else + { + rInfo.SetNodeStartValue( nLevel, nStart ); + } + } + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + case HTML_O_LANG: + aLang = pOption->GetString(); + break; + case HTML_O_DIR: + aDir = pOption->GetString(); + break; + case HTML_O_SRC: + if( bNewNumFmt ) + { + aBulletSrc = pOption->GetString(); + if( !InternalImgToPrivateURL(aBulletSrc) ) + aBulletSrc = URIHelper::SmartRel2Abs( INetURLObject( sBaseURL ), aBulletSrc, Link(), false ); + } + break; + case HTML_O_WIDTH: + nWidth = (sal_uInt16)pOption->GetNumber(); + break; + case HTML_O_HEIGHT: + nHeight = (sal_uInt16)pOption->GetNumber(); + break; + case HTML_O_ALIGN: + eVertOri = + (sal_Int16)pOption->GetEnum( aHTMLImgVAlignTable, + static_cast< sal_uInt16 >(eVertOri) ); + break; + } + } + + if( aBulletSrc.Len() ) + { + // Eine Bullet-Liste mit Grafiken + aNumFmt.SetNumberingType(SVX_NUM_BITMAP); + + // Die Grafik als Brush anlegen + SvxBrushItem aBrushItem( RES_BACKGROUND ); + aBrushItem.SetGraphicLink( aBulletSrc ); + aBrushItem.SetGraphicPos( GPOS_AREA ); + + // Die Groesse nur beachten, wenn Breite und Hoehe vorhanden sind + Size aTwipSz( nWidth, nHeight), *pTwipSz=0; + if( nWidth!=USHRT_MAX && nHeight!=USHRT_MAX ) + { + aTwipSz = + Application::GetDefaultDevice()->PixelToLogic( aTwipSz, + MapMode(MAP_TWIP) ); + pTwipSz = &aTwipSz; + } + + // Die Ausrichtung auch nur beachten, wenn eine Ausrichtung + // angegeben wurde + aNumFmt.SetGraphicBrush( &aBrushItem, pTwipSz, + text::VertOrientation::NONE!=eVertOri ? &eVertOri : 0); + + // Und noch die Grafik merken, um sie in den Absaetzen nicht + // einzufuegen + aBulletGrfs[nLevel] = aBulletSrc; + bChangeNumFmt = sal_True; + } + else + aBulletGrfs[nLevel].Erase(); + + // den aktuellen Absatz erst einmal nicht numerieren + { + sal_uInt8 nLvl = nLevel; + // --> OD 2008-04-02 #refactorlists# +// SetNoNum(&nLvl, sal_True); // #115962# +// SetNodeNum( nLvl ); + SetNodeNum( nLvl, false ); + // <-- + } + + // einen neuen Kontext anlegen + _HTMLAttrContext *pCntxt = new _HTMLAttrContext( static_cast< sal_uInt16 >(nToken) ); + + // Styles parsen + if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) ) + { + SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + + if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) ) + { + if( bNewNumFmt ) + { + if( aPropInfo.bLeftMargin ) + { + // Der Der Default-Einzug wurde schon eingefuegt. + sal_uInt16 nAbsLSpace = + aNumFmt.GetAbsLSpace() - HTML_NUMBUL_MARGINLEFT; + if( aPropInfo.nLeftMargin < 0 && + nAbsLSpace < -aPropInfo.nLeftMargin ) + nAbsLSpace = 0U; + else if( aPropInfo.nLeftMargin > USHRT_MAX || + (long)nAbsLSpace + + aPropInfo.nLeftMargin > USHRT_MAX ) + nAbsLSpace = USHRT_MAX; + else + nAbsLSpace = nAbsLSpace + (sal_uInt16)aPropInfo.nLeftMargin; + + aNumFmt.SetAbsLSpace( nAbsLSpace ); + bChangeNumFmt = sal_True; + } + if( aPropInfo.bTextIndent ) + { + short nTextIndent = + ((const SvxLRSpaceItem &)aItemSet.Get( RES_LR_SPACE )) + .GetTxtFirstLineOfst(); + aNumFmt.SetFirstLineOffset( nTextIndent ); + bChangeNumFmt = sal_True; + } + } + aPropInfo.bLeftMargin = aPropInfo.bTextIndent = sal_False; + if( !aPropInfo.bRightMargin ) + aItemSet.ClearItem( RES_LR_SPACE ); + + // --> OD 2008-06-26 #i89812# + // Perform change to list style before calling <DoPositioning(..)>, + // because <DoPositioning(..)> may open a new context and thus may + // clear the <SwHTMLNumRuleInfo> instance hold by local variable <rInfo>. + if( bChangeNumFmt ) + { + rInfo.GetNumRule()->Set( nLevel, aNumFmt ); + pDoc->ChgNumRuleFmts( *rInfo.GetNumRule() ); + bChangeNumFmt = sal_False; + } + // <-- + + DoPositioning( aItemSet, aPropInfo, pCntxt ); + + InsertAttrs( aItemSet, aPropInfo, pCntxt ); + } + } + + if( bChangeNumFmt ) + { + rInfo.GetNumRule()->Set( nLevel, aNumFmt ); + pDoc->ChgNumRuleFmts( *rInfo.GetNumRule() ); + } + + PushContext( pCntxt ); + + // die Attribute der neuen Vorlage setzen + SetTxtCollAttrs( pCntxt ); +} + +void SwHTMLParser::EndNumBulList( int nToken ) +{ + SwHTMLNumRuleInfo& rInfo = GetNumInfo(); + + // Ein neuer Absatz muss aufgemacht werden, wenn + // - der aktuelle nicht leer ist, also Text oder absatzgebundene Objekte + // enthaelt. + // - der aktuelle Absatz numeriert ist. + sal_Bool bAppend = pPam->GetPoint()->nContent.GetIndex() > 0; + if( !bAppend ) + { + SwTxtNode* pTxtNode = pPam->GetNode()->GetTxtNode(); + + bAppend = (pTxtNode && ! pTxtNode->IsOutline() && pTxtNode->IsCountedInList()) || + + HasCurrentParaFlys(); + } + + sal_Bool bSpace = (rInfo.GetDepth() + nDefListDeep) == 1; + if( bAppend ) + AppendTxtNode( bSpace ? AM_SPACE : AM_NOSPACE, sal_False ); + else if( bSpace ) + AddParSpace(); + + // den aktuellen Kontext vom Stack holen + _HTMLAttrContext *pCntxt = nToken!=0 ? PopContext( static_cast< sal_uInt16 >(nToken & ~1) ) : 0; + + // Keine Liste aufgrund eines Tokens beenden, wenn der Kontext + // nie angelgt wurde oder nicht beendet werden darf. + if( rInfo.GetDepth()>0 && (!nToken || pCntxt) ) + { + rInfo.DecDepth(); + if( !rInfo.GetDepth() ) // wars der letze Level ? + { + // Die noch nicht angepassten Formate werden jetzt noch + // angepasst, damit es sich besser Editieren laesst. + const SwNumFmt *pRefNumFmt = 0; + sal_Bool bChanged = sal_False; + for( sal_uInt16 i=0; i<MAXLEVEL; i++ ) + { + const SwNumFmt *pNumFmt = rInfo.GetNumRule()->GetNumFmt(i); + if( pNumFmt ) + { + pRefNumFmt = pNumFmt; + } + else if( pRefNumFmt ) + { + SwNumFmt aNumFmt( rInfo.GetNumRule()->Get(i) ); + aNumFmt.SetNumberingType(pRefNumFmt->GetNumberingType() != SVX_NUM_BITMAP + ? pRefNumFmt->GetNumberingType() : style::NumberingType::CHAR_SPECIAL); + if( SVX_NUM_CHAR_SPECIAL == aNumFmt.GetNumberingType() ) + { + // --> OD 2008-06-03 #i63395# + // Only apply user defined default bullet font + if ( numfunc::IsDefBulletFontUserDefined() ) + { + aNumFmt.SetBulletFont( &numfunc::GetDefBulletFont() ); + } + // <-- + aNumFmt.SetBulletChar( cBulletChar ); + } + aNumFmt.SetAbsLSpace( (i+1) * HTML_NUMBUL_MARGINLEFT ); + aNumFmt.SetFirstLineOffset( HTML_NUMBUL_INDENT ); + aNumFmt.SetCharFmt( pRefNumFmt->GetCharFmt() ); + rInfo.GetNumRule()->Set( i, aNumFmt ); + bChanged = sal_True; + } + } + if( bChanged ) + pDoc->ChgNumRuleFmts( *rInfo.GetNumRule() ); + + // Beim letzen Append wurde das NumRule-Item und das + // NodeNum-Objekt mit kopiert. Beides muessen wir noch + // loeschen. Das ResetAttr loescht das NodeNum-Objekt mit! + pPam->GetNode()->GetTxtNode()->ResetAttr( RES_PARATR_NUMRULE ); + + rInfo.Clear(); + } + else + { + // den naechsten Absatz erstmal nicht numerieren + // --> OD 2008-04-02 #refactorlists# +// SetNodeNum( rInfo.GetLevel() | NO_NUMLEVEL ); + SetNodeNum( rInfo.GetLevel(), false ); + // <-- + } + } + + // und noch Attribute beenden + sal_Bool bSetAttrs = sal_False; + if( pCntxt ) + { + EndContext( pCntxt ); + delete pCntxt; + bSetAttrs = sal_True; + } + + if( nToken ) + SetTxtCollAttrs(); + + if( bSetAttrs ) + SetAttr(); // Absatz-Atts wegen JavaScript moeglichst schnell setzen + +} + +/* */ + +void SwHTMLParser::NewNumBulListItem( int nToken ) +{ + sal_uInt8 nLevel = GetNumInfo().GetLevel(); + String aId, aStyle, aClass, aLang, aDir; + sal_uInt16 nStart = HTML_LISTHEADER_ON != nToken + ? GetNumInfo().GetNodeStartValue( nLevel ) + : USHRT_MAX; + if( USHRT_MAX != nStart ) + GetNumInfo().SetNodeStartValue( nLevel ); + + const HTMLOptions *pHTMLOptions = GetOptions(); + for( sal_uInt16 i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_VALUE: + nStart = (sal_uInt16)pOption->GetNumber(); + break; + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + case HTML_O_LANG: + aLang = pOption->GetString(); + break; + case HTML_O_DIR: + aDir = pOption->GetString(); + break; + } + } + + // einen neuen Absatz aufmachen + if( pPam->GetPoint()->nContent.GetIndex() ) + AppendTxtNode( AM_NOSPACE, sal_False ); + bNoParSpace = sal_False; // In <LI> wird kein Abstand eingefuegt! + + // --> OD 2008-04-02 #refactorlists# +// if( HTML_LISTHEADER_ON==nToken ) +// SetNoNum(&nLevel, sal_True); + const bool bCountedInList( HTML_LISTHEADER_ON==nToken ? false : true ); + // <-- + + _HTMLAttrContext *pCntxt = new _HTMLAttrContext( static_cast< sal_uInt16 >(nToken) ); + + String aNumRuleName; + if( GetNumInfo().GetNumRule() ) + { + aNumRuleName = GetNumInfo().GetNumRule()->GetName(); + } + else + { + aNumRuleName = pDoc->GetUniqueNumRuleName(); + // --> OD 2008-02-11 #newlistlevelattrs# + SwNumRule aNumRule( aNumRuleName, + SvxNumberFormat::LABEL_WIDTH_AND_POSITION ); + // <-- + SwNumFmt aNumFmt( aNumRule.Get( 0 ) ); + // --> OD 2008-06-03 #i63395# + // Only apply user defined default bullet font + if ( numfunc::IsDefBulletFontUserDefined() ) + { + aNumFmt.SetBulletFont( &numfunc::GetDefBulletFont() ); + } + // <-- + aNumFmt.SetNumberingType(SVX_NUM_CHAR_SPECIAL); + aNumFmt.SetBulletChar( cBulletChar ); // das Bulletzeichen !! + aNumFmt.SetCharFmt( pCSS1Parser->GetCharFmtFromPool(RES_POOLCHR_BUL_LEVEL) ); + aNumFmt.SetLSpace( (sal_uInt16)(-HTML_NUMBUL_INDENT) ); + aNumFmt.SetFirstLineOffset( HTML_NUMBUL_INDENT ); + aNumRule.Set( 0, aNumFmt ); + + pDoc->MakeNumRule( aNumRuleName, &aNumRule ); + + ASSERT( !nOpenParaToken, + "Jetzt geht ein offenes Absatz-Element verloren" ); + // Wir tun so, als ob wir in einem Absatz sind. Dann wird + // beim naechsten Absatz wenigstens die Numerierung + // weggeschmissen, die nach dem naechsten AppendTxtNode uebernommen + // wird. + nOpenParaToken = static_cast< sal_uInt16 >(nToken); + } + + SwTxtNode* pTxtNode = pPam->GetNode()->GetTxtNode(); + ((SwCntntNode *)pTxtNode)->SetAttr( SwNumRuleItem(aNumRuleName) ); + pTxtNode->SetAttrListLevel(nLevel); + // --> OD 2005-11-14 #i57656# + // <IsCounted()> state of text node has to be adjusted accordingly. + if ( /*nLevel >= 0 &&*/ nLevel < MAXLEVEL ) + { + // --> OD 2008-04-02 #refactorlists# + pTxtNode->SetCountedInList( bCountedInList ); + // <-- + } + // <-- + // --> OD 2005-11-15 #i57919# + // correction of refactoring done by cws swnumtree + // - <nStart> contains the start value, if the numbering has to be restarted + // at this text node. Value <USHRT_MAX> indicates, that numbering isn't + // restarted at this text node + if ( nStart != USHRT_MAX ) + { + pTxtNode->SetListRestart( true ); + pTxtNode->SetAttrListRestartValue( nStart ); + } + // <-- + + if( GetNumInfo().GetNumRule() ) + GetNumInfo().GetNumRule()->SetInvalidRule( sal_True ); + + // Styles parsen + if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) ) + { + SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + + if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) ) + { + DoPositioning( aItemSet, aPropInfo, pCntxt ); + InsertAttrs( aItemSet, aPropInfo, pCntxt ); + } + } + + PushContext( pCntxt ); + + // die neue Vorlage setzen + SetTxtCollAttrs( pCntxt ); + + // Laufbalkenanzeige aktualisieren + ShowStatline(); +} + +void SwHTMLParser::EndNumBulListItem( int nToken, sal_Bool bSetColl, + sal_Bool /*bLastPara*/ ) +{ + // einen neuen Absatz aufmachen + if( !nToken && pPam->GetPoint()->nContent.GetIndex() ) + AppendTxtNode( AM_NOSPACE ); + + // Kontext zu dem Token suchen und vom Stack holen + _HTMLAttrContext *pCntxt = 0; + sal_uInt16 nPos = aContexts.Count(); + nToken &= ~1; + while( !pCntxt && nPos>nContextStMin ) + { + sal_uInt16 nCntxtToken = aContexts[--nPos]->GetToken(); + switch( nCntxtToken ) + { + case HTML_LI_ON: + case HTML_LISTHEADER_ON: + if( !nToken || nToken == nCntxtToken ) + { + pCntxt = aContexts[nPos]; + aContexts.Remove( nPos, 1 ); + } + break; + case HTML_ORDERLIST_ON: + case HTML_UNORDERLIST_ON: + case HTML_MENULIST_ON: + case HTML_DIRLIST_ON: + // keine LI/LH ausserhalb der aktuellen Liste betrachten + nPos = nContextStMin; + break; + } + } + + // und noch Attribute beenden + if( pCntxt ) + { + EndContext( pCntxt ); + SetAttr(); // Absatz-Atts wegen JavaScript moeglichst schnell setzen + delete pCntxt; + } + + // und die bisherige Vorlage setzen + if( bSetColl ) + SetTxtCollAttrs(); +} + +/* */ + +// --> OD 2008-04-02 #refactorlists# +void SwHTMLParser::SetNodeNum( sal_uInt8 nLevel, bool bCountedInList ) +{ + SwTxtNode* pTxtNode = pPam->GetNode()->GetTxtNode(); + ASSERT( pTxtNode, "Kein Text-Node an PaM-Position" ); + + ASSERT( GetNumInfo().GetNumRule(), "Kein Numerierungs-Regel" ); + const String& rName = GetNumInfo().GetNumRule()->GetName(); + ((SwCntntNode *)pTxtNode)->SetAttr( SwNumRuleItem(rName) ); + + // --> OD 2008-04-02 #refactorlists# +// // --> OD 2005-11-14 #i57656# +// // consider usage of NO_NUMLEVEL - see implementation of <SwTxtNode::SetLevel(..)> +// if ( /*nLevel >= 0 &&*/ ( nLevel & NO_NUMLEVEL ) ) +// { +// pTxtNode->SetAttrListLevel( nLevel & ~NO_NUMLEVEL ); +// pTxtNode->SetCountedInList( false ); +// } +// else +// { +// pTxtNode->SetAttrListLevel( nLevel ); +// pTxtNode->SetCountedInList( true ); +// } + pTxtNode->SetAttrListLevel( nLevel ); + pTxtNode->SetCountedInList( bCountedInList ); + // <-- + + // NumRule invalidieren, weil sie durch ein EndAction bereits + // auf valid geschaltet worden sein kann. + GetNumInfo().GetNumRule()->SetInvalidRule( sal_False ); +} + + +/* */ + +void SwHTMLWriter::FillNextNumInfo() +{ + pNextNumRuleInfo = 0; + + sal_uLong nPos = pCurPam->GetPoint()->nNode.GetIndex() + 1; + + sal_Bool bTable = sal_False; + do + { + const SwNode* pNd = pDoc->GetNodes()[nPos]; + if( pNd->IsTxtNode() ) + { + // Der naechste wird als naechstes ausgegeben. + pNextNumRuleInfo = new SwHTMLNumRuleInfo( *pNd->GetTxtNode() ); + + // Vor einer Tabelle behalten wir erst einmal die alte Ebene bei, + // wenn die gleiche Numerierung hinter der Tabelle + // fortgesetzt wird und dort nicht von vorne numeriert + // wird. Die Tabelle wird ann beim Import so weit eingeruckt, + // wie es der Num-Ebene entspricht. + if( bTable && + pNextNumRuleInfo->GetNumRule()==GetNumInfo().GetNumRule() && + !pNextNumRuleInfo->IsRestart() ) + { + pNextNumRuleInfo->SetDepth( GetNumInfo().GetDepth() ); + } + } + else if( pNd->IsTableNode() ) + { + // Eine Tabelle wird uebersprungen, also den Node + // hinter der Tabelle betrachten. + nPos = pNd->EndOfSectionIndex() + 1; + bTable = sal_True; + } + else + { + // In allen anderen Faellen ist die Numerierung erstmal + // zu Ende. + pNextNumRuleInfo = new SwHTMLNumRuleInfo; + } + } + while( !pNextNumRuleInfo ); +} + +void SwHTMLWriter::ClearNextNumInfo() +{ + delete pNextNumRuleInfo; + pNextNumRuleInfo = 0; +} + +Writer& OutHTML_NumBulListStart( SwHTMLWriter& rWrt, + const SwHTMLNumRuleInfo& rInfo ) +{ + SwHTMLNumRuleInfo& rPrevInfo = rWrt.GetNumInfo(); + sal_Bool bSameRule = rPrevInfo.GetNumRule() == rInfo.GetNumRule(); + if( bSameRule && rPrevInfo.GetDepth() >= rInfo.GetDepth() && + !rInfo.IsRestart() ) + { + return rWrt; + } + + sal_Bool bStartValue = sal_False; + if( !bSameRule && rInfo.GetDepth() ) + { + String aName( rInfo.GetNumRule()->GetName() ); + if( rWrt.aNumRuleNames.Seek_Entry( &aName ) ) + { + // The rule has been applied before + sal_Int16 eType = rInfo.GetNumRule() + ->Get( rInfo.GetDepth()-1 ).GetNumberingType(); + if( SVX_NUM_CHAR_SPECIAL != eType && SVX_NUM_BITMAP != eType ) + { + // If its a numbering rule, the current number should be + // exported as start value, but only if there are no nodes + // within the numbering that have a lower level + bStartValue = sal_True; + if( rInfo.GetDepth() > 1 ) + { + sal_uLong nPos = + rWrt.pCurPam->GetPoint()->nNode.GetIndex() + 1; + do + { + const SwNode* pNd = rWrt.pDoc->GetNodes()[nPos]; + if( pNd->IsTxtNode() ) + { + const SwTxtNode *pTxtNd = pNd->GetTxtNode(); + if( !pTxtNd->GetNumRule() ) + { + // node isn't numbered => check completed + break; + } + + ASSERT(! pTxtNd->IsOutline(), + "outline not expected"); + + if( pTxtNd->GetActualListLevel() + 1 < + rInfo.GetDepth() ) + { + // node is numbered, but level is lower + // => check completed + bStartValue = sal_False; + break; + } + nPos++; + } + else if( pNd->IsTableNode() ) + { + // skip table + nPos = pNd->EndOfSectionIndex() + 1; + } + else + { + // end node or sections start node -> check + // completed + break; + } + } + while( sal_True ); + } + } + } + else + { + rWrt.aNumRuleNames.Insert( new String( aName ) ); + } + } + + + DBG_ASSERT( rWrt.nLastParaToken == 0, + "<PRE> wurde nicht vor <OL> beendet." ); + sal_uInt16 nPrevDepth = + (bSameRule && !rInfo.IsRestart()) ? rPrevInfo.GetDepth() : 0; + + for( sal_uInt16 i=nPrevDepth; i<rInfo.GetDepth(); i++ ) + { + rWrt.OutNewLine(); // <OL>/<UL> in eine neue Zeile + + rWrt.aBulletGrfs[i].Erase(); + ByteString sOut( '<' ); + const SwNumFmt& rNumFmt = rInfo.GetNumRule()->Get( i ); + sal_Int16 eType = rNumFmt.GetNumberingType(); + if( SVX_NUM_CHAR_SPECIAL == eType ) + { + // Aufzaehlungs-Liste: <OL> + sOut += OOO_STRING_SVTOOLS_HTML_unorderlist; + + // den Typ ueber das Bullet-Zeichen bestimmen + const sal_Char *pStr = 0; + switch( rNumFmt.GetBulletChar() ) + { + case HTML_BULLETCHAR_DISC: + pStr = OOO_STRING_SVTOOLS_HTML_ULTYPE_disc; + break; + case HTML_BULLETCHAR_CIRCLE: + pStr = OOO_STRING_SVTOOLS_HTML_ULTYPE_circle; + break; + case HTML_BULLETCHAR_SQUARE: + pStr = OOO_STRING_SVTOOLS_HTML_ULTYPE_square; + break; + } + + if( pStr ) + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_type) += '=') += pStr; + } + else if( SVX_NUM_BITMAP == eType ) + { + // Aufzaehlungs-Liste: <OL> + sOut += OOO_STRING_SVTOOLS_HTML_unorderlist; + rWrt.Strm() << sOut.GetBuffer(); + sOut.Erase(); + + OutHTML_BulletImage( rWrt, + 0, + rNumFmt.GetBrush(), + rWrt.aBulletGrfs[i], + rNumFmt.GetGraphicSize(), + rNumFmt.GetGraphicOrientation() ); + } + else + { + // Numerierungs-Liste: <UL> + sOut += OOO_STRING_SVTOOLS_HTML_orderlist; + + // den Typ ueber das Format bestimmen + sal_Char cType = 0; + switch( eType ) + { + case SVX_NUM_CHARS_UPPER_LETTER: cType = 'A'; break; + case SVX_NUM_CHARS_LOWER_LETTER: cType = 'a'; break; + case SVX_NUM_ROMAN_UPPER: cType = 'I'; break; + case SVX_NUM_ROMAN_LOWER: cType = 'i'; break; + } + if( cType ) + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_type) += '=') += cType; + + sal_uInt16 nStartVal = rNumFmt.GetStart(); + if( bStartValue && 1 == nStartVal && i == rInfo.GetDepth()-1 ) + { + // --> OD 2005-11-02 #i51089 - TUNING# + if ( rWrt.pCurPam->GetNode()->GetTxtNode()->GetNum() ) + { + nStartVal = static_cast< sal_uInt16 >( rWrt.pCurPam->GetNode() + ->GetTxtNode()->GetNumberVector()[i] ); + } + else + { + ASSERT( false, + "<OutHTML_NumBulListStart(..) - text node has no number." ); + } + } + if( nStartVal != 1 ) + { + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_start) += '=') + += ByteString::CreateFromInt32( nStartVal ); + } + } + + if( sOut.Len() ) + rWrt.Strm() << sOut.GetBuffer(); + + if( rWrt.bCfgOutStyles ) + OutCSS1_NumBulListStyleOpt( rWrt, *rInfo.GetNumRule(), (sal_uInt8)i ); + + rWrt.Strm() << '>'; + + rWrt.IncIndentLevel(); // Inhalt von <OL> einruecken + } + + return rWrt; +} + +Writer& OutHTML_NumBulListEnd( SwHTMLWriter& rWrt, + const SwHTMLNumRuleInfo& rNextInfo ) +{ + SwHTMLNumRuleInfo& rInfo = rWrt.GetNumInfo(); + sal_Bool bSameRule = rNextInfo.GetNumRule() == rInfo.GetNumRule(); + if( bSameRule && rNextInfo.GetDepth() >= rInfo.GetDepth() && + !rNextInfo.IsRestart() ) + { + return rWrt; + } + + DBG_ASSERT( rWrt.nLastParaToken == 0, + "<PRE> wurde nicht vor </OL> beendet." ); + sal_uInt16 nNextDepth = + (bSameRule && !rNextInfo.IsRestart()) ? rNextInfo.GetDepth() : 0; + + // MIB 23.7.97: Die Schleife muss doch rueckwaerts durchlaufen + // werden, weil die Reihenfolge von </OL>/</UL> stimmen muss + for( sal_uInt16 i=rInfo.GetDepth(); i>nNextDepth; i-- ) + { + rWrt.DecIndentLevel(); // Inhalt von <OL> einruecken + if( rWrt.bLFPossible ) + rWrt.OutNewLine(); // </OL>/</UL> in eine neue Zeile + + // es wird also eine Liste angefangen oder beendet: + sal_Int16 eType = rInfo.GetNumRule()->Get( i-1 ).GetNumberingType(); + const sal_Char *pStr; + if( SVX_NUM_CHAR_SPECIAL == eType || SVX_NUM_BITMAP == eType) + pStr = OOO_STRING_SVTOOLS_HTML_unorderlist; + else + pStr = OOO_STRING_SVTOOLS_HTML_orderlist; + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), pStr, sal_False ); + rWrt.bLFPossible = sal_True; + } + + return rWrt; +} diff --git a/sw/source/filter/html/htmlnum.hxx b/sw/source/filter/html/htmlnum.hxx new file mode 100644 index 000000000000..7f7f02bc1015 --- /dev/null +++ b/sw/source/filter/html/htmlnum.hxx @@ -0,0 +1,131 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _HTMLNUM_HXX +#define _HTMLNUM_HXX + +#include <swtypes.hxx> +#include <string.h> + +#define HTML_NUMBUL_MARGINLEFT (MM50*2 + MM50/2) +#define HTML_NUMBUL_INDENT (-MM50) + +class SwTxtNode; +class SwNumRule; + +class SwHTMLNumRuleInfo +{ + sal_uInt16 aNumStarts[MAXLEVEL]; + SwNumRule * pNumRule; // Aktuelle Numerierung + sal_uInt16 nDeep; // aktuelle Num-Tiefe (1, 2, 3, ...) + sal_Bool bRestart : 1; // Export: Numerierung neu starten + sal_Bool bNumbered : 1; // Export: Absatz ist numeriert + +public: + + inline void Set( const SwHTMLNumRuleInfo& rInf ); + void Set( const SwTxtNode& rTxtNd ); + + SwHTMLNumRuleInfo() : + pNumRule( 0 ), nDeep( 0 ), + bRestart( sal_False ), bNumbered( sal_False ) + { + memset( &aNumStarts, 0xff, sizeof( aNumStarts ) ); + } + + SwHTMLNumRuleInfo( const SwHTMLNumRuleInfo& rInf ) : + pNumRule( rInf.pNumRule ), nDeep( rInf.nDeep ), + bRestart( rInf.bRestart ), bNumbered( rInf.bNumbered ) + { + memcpy( &aNumStarts, &rInf.aNumStarts, sizeof( aNumStarts ) ); + } + + SwHTMLNumRuleInfo( const SwTxtNode& rTxtNd ) { Set( rTxtNd ); } + inline SwHTMLNumRuleInfo& operator=( const SwHTMLNumRuleInfo& rInf ); + + inline void Clear(); + + void SetNumRule( const SwNumRule *pRule ) { pNumRule = (SwNumRule *)pRule; } + SwNumRule *GetNumRule() { return pNumRule; } + const SwNumRule *GetNumRule() const { return pNumRule; } + + void SetDepth( sal_uInt16 nDepth ) { nDeep = nDepth; } + sal_uInt16 GetDepth() const { return nDeep; } + sal_uInt16 IncDepth() { return ++nDeep; } + sal_uInt16 DecDepth() { return nDeep==0 ? 0 : --nDeep; } + inline sal_uInt8 GetLevel() const; + + void SetRestart( sal_Bool bSet ) { bRestart = bSet; } + sal_Bool IsRestart() const { return bRestart; } + + void SetNumbered( sal_Bool bSet ) { bNumbered = bSet; } + sal_Bool IsNumbered() const { return bNumbered; } + + inline void SetNodeStartValue( sal_uInt8 nLvl, sal_uInt16 nVal=USHRT_MAX ); + sal_uInt16 GetNodeStartValue( sal_uInt8 nLvl ) const { return aNumStarts[nLvl]; } +}; + +inline SwHTMLNumRuleInfo& SwHTMLNumRuleInfo::operator=( + const SwHTMLNumRuleInfo& rInf ) +{ + Set( rInf ); + return *this; +} + +inline void SwHTMLNumRuleInfo::Set( const SwHTMLNumRuleInfo& rInf ) +{ + pNumRule = rInf.pNumRule; + nDeep = rInf.nDeep; + bRestart = rInf.bRestart; + bNumbered = rInf.bNumbered; + memcpy( &aNumStarts, &rInf.aNumStarts, sizeof( aNumStarts ) ); +} + +inline void SwHTMLNumRuleInfo::Clear() +{ + pNumRule = 0; + nDeep = 0; + bRestart = bNumbered = sal_False; + memset( &aNumStarts, 0xff, sizeof( aNumStarts ) ); +} + +inline sal_uInt8 SwHTMLNumRuleInfo::GetLevel() const +{ + return + (sal_uInt8)( pNumRule!=0 && nDeep != 0 + ? ( nDeep<=MAXLEVEL ? nDeep-1 : MAXLEVEL - 1 ) + : 0 ); +} + +inline void SwHTMLNumRuleInfo::SetNodeStartValue( sal_uInt8 nLvl, sal_uInt16 nVal ) +{ + aNumStarts[nLvl] = nVal; +} + + +#endif + + diff --git a/sw/source/filter/html/htmlplug.cxx b/sw/source/filter/html/htmlplug.cxx new file mode 100644 index 000000000000..e5bddbd5eb5e --- /dev/null +++ b/sw/source/filter/html/htmlplug.cxx @@ -0,0 +1,1401 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" +#include <com/sun/star/embed/EmbedStates.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> + +#include "hintids.hxx" +#include <svl/urihelper.hxx> +#define _SVSTDARR_ULONGS +#include <svl/svstdarr.hxx> +#include <vcl/svapp.hxx> +#include <sfx2/frmhtml.hxx> +#include <sfx2/frmhtmlw.hxx> +#include <vcl/wrkwin.hxx> +#include <sot/storage.hxx> +#include <svx/xoutbmp.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/lrspitem.hxx> +#include <svtools/htmlkywd.hxx> +#include <svtools/htmltokn.h> +#include <SwAppletImpl.hxx> +#include <fmtornt.hxx> +#include <fmtfsize.hxx> +#include <fmtsrnd.hxx> +#include <fmtanchr.hxx> +#include <fmtcntnt.hxx> +#include <frmfmt.hxx> + +#include <svl/ownlist.hxx> +#include "pam.hxx" +#include "doc.hxx" +#include "ndtxt.hxx" +#include "swerror.h" +#include "ndole.hxx" +#include "swtable.hxx" +#include "swhtml.hxx" +#include "wrthtml.hxx" +#include "htmlfly.hxx" +#include "swcss1.hxx" +#include <com/sun/star/embed/XClassifiedObject.hpp> +#include <com/sun/star/embed/EmbedStates.hpp> +#include <comphelper/embeddedobjectcontainer.hxx> +#include <sot/clsids.hxx> + +using namespace com::sun::star; + +#define HTML_DFLT_EMBED_WIDTH ((MM50*5)/2) +#define HTML_DFLT_EMBED_HEIGHT ((MM50*5)/2) + +#define HTML_DFLT_APPLET_WIDTH ((MM50*5)/2) +#define HTML_DFLT_APPLET_HEIGHT ((MM50*5)/2) + +namespace { + +static char const sHTML_O_Hidden_False[] = "sal_False"; + +} + +const sal_uLong HTML_FRMOPTS_EMBED_ALL = + HTML_FRMOPT_ALT | + HTML_FRMOPT_SIZE | + HTML_FRMOPT_NAME; +const sal_uLong HTML_FRMOPTS_EMBED_CNTNR = + HTML_FRMOPTS_EMBED_ALL | + HTML_FRMOPT_ABSSIZE; +const sal_uLong HTML_FRMOPTS_EMBED = + HTML_FRMOPTS_EMBED_ALL | + HTML_FRMOPT_ALIGN | + HTML_FRMOPT_SPACE | + HTML_FRMOPT_BRCLEAR | + HTML_FRMOPT_NAME; +const sal_uLong HTML_FRMOPTS_HIDDEN_EMBED = + HTML_FRMOPT_ALT | + HTML_FRMOPT_NAME; + +const sal_uLong HTML_FRMOPTS_APPLET_ALL = + HTML_FRMOPT_ALT | + HTML_FRMOPT_SIZE; +const sal_uLong HTML_FRMOPTS_APPLET_CNTNR = + HTML_FRMOPTS_APPLET_ALL | + HTML_FRMOPT_ABSSIZE; +const sal_uLong HTML_FRMOPTS_APPLET = + HTML_FRMOPTS_APPLET_ALL | + HTML_FRMOPT_ALIGN | + HTML_FRMOPT_SPACE | + HTML_FRMOPT_BRCLEAR; + +const sal_uLong HTML_FRMOPTS_IFRAME_ALL = + HTML_FRMOPT_ALT | + HTML_FRMOPT_SIZE; +const sal_uLong HTML_FRMOPTS_IFRAME_CNTNR = + HTML_FRMOPTS_IFRAME_ALL | + HTML_FRMOPT_ABSSIZE; +const sal_uLong HTML_FRMOPTS_IFRAME = + HTML_FRMOPTS_IFRAME_ALL | + HTML_FRMOPT_ALIGN | + HTML_FRMOPT_SPACE | + HTML_FRMOPT_BORDER | + HTML_FRMOPT_BRCLEAR; + +const sal_uLong HTML_FRMOPTS_OLE_CSS1 = + HTML_FRMOPT_S_ALIGN | + HTML_FRMOPT_S_SPACE; + +/* */ + +void SwHTMLParser::SetFixSize( const Size& rPixSize, + const Size& rTwipDfltSize, + sal_Bool bPrcWidth, sal_Bool bPrcHeight, + SfxItemSet& /*rCSS1ItemSet*/, + SvxCSS1PropertyInfo& rCSS1PropInfo, + SfxItemSet& rFlyItemSet ) +{ + // absolulte Groessenangaben in Twip umrechnen + sal_uInt8 nPrcWidth = 0, nPrcHeight = 0; + Size aTwipSz( bPrcWidth || USHRT_MAX==rPixSize.Width() ? 0 : rPixSize.Width(), + bPrcHeight || USHRT_MAX==rPixSize.Height() ? 0 : rPixSize.Height() ); + if( (aTwipSz.Width() || aTwipSz.Height()) && Application::GetDefaultDevice() ) + { + aTwipSz = + Application::GetDefaultDevice()->PixelToLogic( aTwipSz, + MapMode(MAP_TWIP) ); + } + + // die Breite bearbeiten + if( SVX_CSS1_LTYPE_PERCENTAGE == rCSS1PropInfo.eWidthType ) + { + nPrcWidth = (sal_uInt8)rCSS1PropInfo.nWidth; + aTwipSz.Width() = rTwipDfltSize.Width(); + } + else if( SVX_CSS1_LTYPE_TWIP== rCSS1PropInfo.eWidthType ) + { + aTwipSz.Width() = rCSS1PropInfo.nWidth; + } + else if( bPrcWidth && rPixSize.Width() ) + { + nPrcWidth = (sal_uInt8)rPixSize.Width(); + if( nPrcWidth > 100 ) + nPrcWidth = 100; + + aTwipSz.Width() = rTwipDfltSize.Width(); + } + else if( USHRT_MAX==rPixSize.Width() ) + { + aTwipSz.Width() = rTwipDfltSize.Width(); + } + if( aTwipSz.Width() < MINFLY ) + { + aTwipSz.Width() = MINFLY; + } + + // Hoehe bearbeiten + if( SVX_CSS1_LTYPE_PERCENTAGE == rCSS1PropInfo.eHeightType ) + { + nPrcHeight = (sal_uInt8)rCSS1PropInfo.nHeight; + aTwipSz.Height() = rTwipDfltSize.Height(); + } + else if( SVX_CSS1_LTYPE_TWIP== rCSS1PropInfo.eHeightType ) + { + aTwipSz.Height() = rCSS1PropInfo.nHeight; + } + else if( bPrcHeight && rPixSize.Height() ) + { + nPrcHeight = (sal_uInt8)rPixSize.Height(); + if( nPrcHeight > 100 ) + nPrcHeight = 100; + + aTwipSz.Height() = rTwipDfltSize.Height(); + } + else if( USHRT_MAX==rPixSize.Height() ) + { + aTwipSz.Height() = rTwipDfltSize.Height(); + } + if( aTwipSz.Height() < MINFLY ) + { + aTwipSz.Height() = MINFLY; + } + + // Size setzen + SwFmtFrmSize aFrmSize( ATT_FIX_SIZE, aTwipSz.Width(), aTwipSz.Height() ); + aFrmSize.SetWidthPercent( nPrcWidth ); + aFrmSize.SetHeightPercent( nPrcHeight ); + rFlyItemSet.Put( aFrmSize ); +} + +void SwHTMLParser::SetSpace( const Size& rPixSpace, + SfxItemSet& rCSS1ItemSet, + SvxCSS1PropertyInfo& rCSS1PropInfo, + SfxItemSet& rFlyItemSet ) +{ + sal_Int32 nLeftSpace = 0, nRightSpace = 0; + sal_uInt16 nUpperSpace = 0, nLowerSpace = 0; + if( (rPixSpace.Width() || rPixSpace.Height()) && Application::GetDefaultDevice() ) + { + Size aTwipSpc( rPixSpace.Width(), rPixSpace.Height() ); + aTwipSpc = + Application::GetDefaultDevice()->PixelToLogic( aTwipSpc, + MapMode(MAP_TWIP) ); + nLeftSpace = nRightSpace = aTwipSpc.Width(); + nUpperSpace = nLowerSpace = (sal_uInt16)aTwipSpc.Height(); + } + + // linken/rechten Rand setzen + const SfxPoolItem *pItem; + if( SFX_ITEM_SET==rCSS1ItemSet.GetItemState( RES_LR_SPACE, sal_True, &pItem ) ) + { + // Ggf. den Erstzeilen-Einzug noch plaetten + const SvxLRSpaceItem *pLRItem = (const SvxLRSpaceItem *)pItem; + SvxLRSpaceItem aLRItem( *pLRItem ); + aLRItem.SetTxtFirstLineOfst( 0 ); + if( rCSS1PropInfo.bLeftMargin ) + { + nLeftSpace = aLRItem.GetLeft(); + rCSS1PropInfo.bLeftMargin = sal_False; + } + if( rCSS1PropInfo.bRightMargin ) + { + nRightSpace = aLRItem.GetRight(); + rCSS1PropInfo.bRightMargin = sal_False; + } + rCSS1ItemSet.ClearItem( RES_LR_SPACE ); + } + if( nLeftSpace > 0 || nRightSpace > 0 ) + { + SvxLRSpaceItem aLRItem( RES_LR_SPACE ); + aLRItem.SetLeft( nLeftSpace > 0 ? nLeftSpace : 0 ); + aLRItem.SetRight( nRightSpace > 0 ? nRightSpace : 0 ); + rFlyItemSet.Put( aLRItem ); + if( nLeftSpace ) + { + const SwFmtHoriOrient& rHoriOri = + (const SwFmtHoriOrient&)rFlyItemSet.Get( RES_HORI_ORIENT ); + if( text::HoriOrientation::NONE == rHoriOri.GetHoriOrient() ) + { + SwFmtHoriOrient aHoriOri( rHoriOri ); + aHoriOri.SetPos( aHoriOri.GetPos() + nLeftSpace ); + rFlyItemSet.Put( aHoriOri ); + } + } + } + + // oberen/unteren Rand setzen + if( SFX_ITEM_SET==rCSS1ItemSet.GetItemState( RES_UL_SPACE, sal_True, &pItem ) ) + { + // Ggf. den Erstzeilen-Einzug noch plaetten + const SvxULSpaceItem *pULItem = (const SvxULSpaceItem *)pItem; + if( rCSS1PropInfo.bTopMargin ) + { + nUpperSpace = pULItem->GetUpper(); + rCSS1PropInfo.bTopMargin = sal_False; + } + if( rCSS1PropInfo.bBottomMargin ) + { + nLowerSpace = pULItem->GetLower(); + rCSS1PropInfo.bBottomMargin = sal_False; + } + rCSS1ItemSet.ClearItem( RES_UL_SPACE ); + } + if( nUpperSpace || nLowerSpace ) + { + SvxULSpaceItem aULItem( RES_UL_SPACE ); + aULItem.SetUpper( nUpperSpace ); + aULItem.SetLower( nLowerSpace ); + rFlyItemSet.Put( aULItem ); + if( nUpperSpace ) + { + const SwFmtVertOrient& rVertOri = + (const SwFmtVertOrient&)rFlyItemSet.Get( RES_VERT_ORIENT ); + if( text::VertOrientation::NONE == rVertOri.GetVertOrient() ) + { + SwFmtVertOrient aVertOri( rVertOri ); + aVertOri.SetPos( aVertOri.GetPos() + nUpperSpace ); + rFlyItemSet.Put( aVertOri ); + } + } + } +} + +/* */ + +void SwHTMLParser::InsertEmbed() +{ + String aURL, aType, aName, aAlt, aId, aStyle, aClass; + Size aSize( USHRT_MAX, USHRT_MAX ); + Size aSpace( USHRT_MAX, USHRT_MAX ); + sal_Bool bPrcWidth = sal_False, bPrcHeight = sal_False, bHidden = sal_False; + sal_Int16 eVertOri = text::VertOrientation::NONE; + sal_Int16 eHoriOri = text::HoriOrientation::NONE; + SvCommandList aCmdLst; + const HTMLOptions *pHTMLOptions = GetOptions(); + + // Die Optionen werden vorwaerts gelesen, weil die Plugins sie in + // dieser Reihenfolge erwarten. Trotzdem darf immer nur der erste + // Wert einer Option beruecksichtigt werden. + sal_uInt16 nArrLen = pHTMLOptions->Count(); + for( sal_uInt16 i=0; i<nArrLen; i++ ) + { + const HTMLOption *pOption = (*pHTMLOptions)[i]; + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + case HTML_O_NAME: + aName = pOption->GetString(); + break; + case HTML_O_SRC: + if( !aURL.Len() ) + aURL = pOption->GetString(); + break; + case HTML_O_ALT: + aAlt = pOption->GetString(); + break; + case HTML_O_TYPE: + if( !aType.Len() ) + aType = pOption->GetString(); + break; + case HTML_O_ALIGN: + if( eVertOri==text::VertOrientation::NONE && eHoriOri==text::HoriOrientation::NONE ) + { + eVertOri = pOption->GetEnum( aHTMLImgVAlignTable, eVertOri ); + eHoriOri = pOption->GetEnum( aHTMLImgHAlignTable, eHoriOri ); + } + break; + case HTML_O_WIDTH: + if( USHRT_MAX==aSize.Width() ) + { + bPrcWidth = (pOption->GetString().Search('%') != STRING_NOTFOUND); + aSize.Width() = (long)pOption->GetNumber(); + } + break; + case HTML_O_HEIGHT: + if( USHRT_MAX==aSize.Height() ) + { + bPrcHeight = (pOption->GetString().Search('%') != STRING_NOTFOUND); + aSize.Height() = (long)pOption->GetNumber(); + } + break; + case HTML_O_HSPACE: + if( USHRT_MAX==aSpace.Width() ) + aSpace.Width() = (long)pOption->GetNumber(); + break; + case HTML_O_VSPACE: + if( USHRT_MAX==aSpace.Height() ) + aSpace.Height() = (long)pOption->GetNumber(); + break; + case HTML_O_UNKNOWN: + if( pOption->GetTokenString().EqualsIgnoreCaseAscii( OOO_STRING_SW_HTML_O_Hidden ) ) + bHidden = + !pOption->GetString().EqualsIgnoreCaseAscii( sHTML_O_Hidden_False ); + break; + } + + // Es werden alle Parameter an das Plugin weitergereicht + aCmdLst.Append( pOption->GetTokenString(), pOption->GetString() ); + } + + SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + if( HasStyleOptions( aStyle, aId, aClass ) ) + ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo ); + + // Die Default-Werte umsetzen (ausser Hoehe/Breite, das macht schon + // SetFrmSize() fuer uns) + if( eVertOri==text::VertOrientation::NONE && eHoriOri==text::HoriOrientation::NONE ) + eVertOri = text::VertOrientation::TOP; + if( USHRT_MAX==aSpace.Width() ) + aSpace.Width() = 0; + if( USHRT_MAX==aSpace.Height() ) + aSpace.Height() = 0; + if( bHidden ) + { + // Size (0,0) wird in SetFrmSize auf (MINFLY, MINFLY) umgebogen + aSize.Width() = 0; aSize.Height() = 0; + aSpace.Width() = 0; aSpace.Height() = 0; + bPrcWidth = bPrcHeight = sal_False; + } + + // die URL aufbereiten + INetURLObject aURLObj; + bool bHasURL = aURL.Len() && + aURLObj.SetURL( + URIHelper::SmartRel2Abs( + INetURLObject(sBaseURL), aURL, + URIHelper::GetMaybeFileHdl()) ); + + // #109761# do not insert plugin if it has neither URL nor type + bool bHasType = aType.Len() != 0; + if( !bHasURL && !bHasType ) + return; + + // das Plugin anlegen + comphelper::EmbeddedObjectContainer aCnt; + ::rtl::OUString aObjName; + uno::Reference < embed::XEmbeddedObject > xObj = aCnt.CreateEmbeddedObject( SvGlobalName( SO3_PLUGIN_CLASSID ).GetByteSequence(), aObjName ); + if ( svt::EmbeddedObjectRef::TryRunningState( xObj ) ) + { + uno::Reference < beans::XPropertySet > xSet( xObj->getComponent(), uno::UNO_QUERY ); + if ( xSet.is() ) + { + if( bHasURL ) + xSet->setPropertyValue( ::rtl::OUString::createFromAscii("PluginURL"), + uno::makeAny( ::rtl::OUString( aURL ) ) ); + if( bHasType ) + xSet->setPropertyValue( ::rtl::OUString::createFromAscii("PluginMimeType"), + uno::makeAny( ::rtl::OUString( aType ) ) ); + + uno::Sequence < beans::PropertyValue > aProps; + aCmdLst.FillSequence( aProps ); + xSet->setPropertyValue( ::rtl::OUString::createFromAscii("PluginCommands"), uno::makeAny( aProps ) ); + + // TODO/LATER: EnableSetModified?! + //pPlugin->EnableSetModified( sal_True ); + } + } + + SfxItemSet aFrmSet( pDoc->GetAttrPool(), + RES_FRMATR_BEGIN, RES_FRMATR_END-1 ); + if( !IsNewDoc() ) + Reader::ResetFrmFmtAttrs( aFrmSet ); + + // den Anker setzen + if( !bHidden ) + { + SetAnchorAndAdjustment( eVertOri, eHoriOri, aItemSet, aPropInfo, aFrmSet ); + } + else + { + SwFmtAnchor aAnchor( FLY_AT_PARA ); + aAnchor.SetAnchor( pPam->GetPoint() ); + aFrmSet.Put( aAnchor ); + aFrmSet.Put( SwFmtHoriOrient( 0, text::HoriOrientation::LEFT, text::RelOrientation::FRAME) ); + aFrmSet.Put( SwFmtSurround( SURROUND_THROUGHT ) ); + aFrmSet.Put( SwFmtVertOrient( 0, text::VertOrientation::TOP, text::RelOrientation::PRINT_AREA ) ); + } + + // und noch die Groesse des Rahmens + Size aDfltSz( HTML_DFLT_EMBED_WIDTH, HTML_DFLT_EMBED_HEIGHT ); + SetFixSize( aSize, aDfltSz, bPrcWidth, bPrcHeight, aItemSet, aPropInfo, + aFrmSet ); + SetSpace( aSpace, aItemSet, aPropInfo, aFrmSet ); + + // und in das Dok einfuegen + SwFrmFmt* pFlyFmt = + pDoc->Insert( *pPam, ::svt::EmbeddedObjectRef( xObj, embed::Aspects::MSOLE_CONTENT ), &aFrmSet, NULL, NULL ); + + // Namen am FrmFmt setzen + if( aName.Len() ) + pFlyFmt->SetName( aName ); + + // den alternativen Text setzen + SwNoTxtNode *pNoTxtNd = + pDoc->GetNodes()[ pFlyFmt->GetCntnt().GetCntntIdx() + ->GetIndex()+1 ]->GetNoTxtNode(); + pNoTxtNd->SetTitle( aAlt ); + + // Ggf Frames anlegen und auto-geb. Rahmen registrieren + if( !bHidden ) + { + // HIDDEN-Plugins sollen absatzgebunden bleiben. Da RegisterFlyFrm + // absatzgebundene Rahmen mit DUrchlauf in am Zeichen gebundene + // Rahmen umwandelt, muessen die Frames hier von Hand angelegt werden. + RegisterFlyFrm( pFlyFmt ); + } +} + +/* */ + +#ifdef SOLAR_JAVA +void SwHTMLParser::NewObject() +{ + String aClassID, aName, aStandBy, aId, aStyle, aClass; + Size aSize( USHRT_MAX, USHRT_MAX ); + Size aSpace( 0, 0 ); + sal_Int16 eVertOri = text::VertOrientation::TOP; + sal_Int16 eHoriOri = text::HoriOrientation::NONE; + + sal_Bool bPrcWidth = sal_False, bPrcHeight = sal_False, + bDeclare = sal_False; + // Eine neue Command-List anlegen + if( pAppletImpl ) + delete pAppletImpl; + pAppletImpl = new SwApplet_Impl( pDoc->GetAttrPool(), + RES_FRMATR_BEGIN, RES_FRMATR_END-1 ); + + const HTMLOptions *pHTMLOptions = GetOptions(); + for( sal_uInt16 i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + case HTML_O_DECLARE: + bDeclare = sal_True; + break; + case HTML_O_CLASSID: + aClassID = pOption->GetString(); + break; + case HTML_O_CODEBASE: + break; + case HTML_O_DATA: + break; + case HTML_O_TYPE: + break; + case HTML_O_CODETYPE: + break; + case HTML_O_ARCHIVE: + case HTML_O_UNKNOWN: + break; + case HTML_O_STANDBY: + aStandBy = pOption->GetString(); + break; + case HTML_O_WIDTH: + bPrcWidth = (pOption->GetString().Search('%') != STRING_NOTFOUND); + aSize.Width() = (long)pOption->GetNumber(); + break; + case HTML_O_HEIGHT: + bPrcHeight = (pOption->GetString().Search('%') != STRING_NOTFOUND); + aSize.Height() = (long)pOption->GetNumber(); + break; + case HTML_O_ALIGN: + eVertOri = pOption->GetEnum( aHTMLImgVAlignTable, eVertOri ); + eHoriOri = pOption->GetEnum( aHTMLImgHAlignTable, eHoriOri ); + break; + case HTML_O_USEMAP: + break; + case HTML_O_NAME: + aName = pOption->GetString(); + break; + case HTML_O_HSPACE: + aSpace.Width() = (long)pOption->GetNumber(); + break; + case HTML_O_VSPACE: + aSpace.Height() = (long)pOption->GetNumber(); + break; + case HTML_O_BORDER: + break; + + case HTML_O_SDONCLICK: + case HTML_O_ONCLICK: + case HTML_O_SDONMOUSEOVER: + case HTML_O_ONMOUSEOVER: + case HTML_O_SDONMOUSEOUT: + case HTML_O_ONMOUSEOUT: + break; + } + // Es werden alle Parameter auch an das Applet weitergereicht + pAppletImpl->AppendParam( pOption->GetTokenString(), + pOption->GetString() ); + + } + + // Objects that are declared only are not evaluated. Moreover, only + // Java applets are supported. + sal_Bool bIsApplet = sal_False;; + + if( !bDeclare && aClassID.Len() == 42 && + aClassID.EqualsAscii( "clsid:", 0, 6 ) ) + { + aClassID.Erase( 0, 6 ); + SvGlobalName aCID; + if( aCID.MakeId( aClassID ) ) + { + SvGlobalName aJavaCID( 0x8AD9C840UL, 0x044EU, 0x11D1U, 0xB3U, 0xE9U, + 0x00U, 0x80U, 0x5FU, 0x49U, 0x9DU, 0x93U ); + + bIsApplet = aJavaCID == aCID; + } + } + + if( !bIsApplet ) + { + delete pAppletImpl; + pAppletImpl = 0; + return; + } + + pAppletImpl->SetAltText( aStandBy ); + + SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + if( HasStyleOptions( aStyle, aId, aClass ) ) + ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo ); + + SfxItemSet& rFrmSet = pAppletImpl->GetItemSet(); + if( !IsNewDoc() ) + Reader::ResetFrmFmtAttrs( rFrmSet ); + + // den Anker und die Ausrichtung setzen + SetAnchorAndAdjustment( eVertOri, eHoriOri, aItemSet, aPropInfo, rFrmSet ); + + // und noch die Groesse des Rahmens + Size aDfltSz( HTML_DFLT_APPLET_WIDTH, HTML_DFLT_APPLET_HEIGHT ); + SetFixSize( aSize, aDfltSz, bPrcWidth, bPrcHeight, aItemSet, aPropInfo, + rFrmSet ); + SetSpace( aSpace, aItemSet, aPropInfo, rFrmSet ); +} +#endif + +void SwHTMLParser::EndObject() +{ +#ifdef SOLAR_JAVA + if( !pAppletImpl ) + return; + if( pAppletImpl->CreateApplet( sBaseURL ) ) + { + pAppletImpl->FinishApplet(); + + // und in das Dok einfuegen + SwFrmFmt* pFlyFmt = + pDoc->Insert( *pPam, + ::svt::EmbeddedObjectRef( pAppletImpl->GetApplet(), embed::Aspects::MSOLE_CONTENT ), + &pAppletImpl->GetItemSet(), + NULL, + NULL ); + + // den alternativen Namen setzen + SwNoTxtNode *pNoTxtNd = + pDoc->GetNodes()[ pFlyFmt->GetCntnt().GetCntntIdx() + ->GetIndex()+1 ]->GetNoTxtNode(); + pNoTxtNd->SetTitle( pAppletImpl->GetAltText() ); + + // Ggf Frames anlegen und auto-geb. Rahmen registrieren + RegisterFlyFrm( pFlyFmt ); + + delete pAppletImpl; + pAppletImpl = 0; + } +#endif +} + +#ifdef SOLAR_JAVA +void SwHTMLParser::InsertApplet() +{ + String aCodeBase, aCode, aName, aAlt, aId, aStyle, aClass; + Size aSize( USHRT_MAX, USHRT_MAX ); + Size aSpace( 0, 0 ); + sal_Bool bPrcWidth = sal_False, bPrcHeight = sal_False, bMayScript = sal_False; + sal_Int16 eVertOri = text::VertOrientation::TOP; + sal_Int16 eHoriOri = text::HoriOrientation::NONE; + + // Eine neue Command-List anlegen + if( pAppletImpl ) + delete pAppletImpl; + pAppletImpl = new SwApplet_Impl( pDoc->GetAttrPool(), RES_FRMATR_BEGIN, RES_FRMATR_END-1 ); + + const HTMLOptions *pHTMLOptions = GetOptions(); + for( sal_uInt16 i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + case HTML_O_CODEBASE: + aCodeBase = pOption->GetString(); + break; + case HTML_O_CODE: + aCode = pOption->GetString(); + break; + case HTML_O_NAME: + aName = pOption->GetString(); + break; + case HTML_O_ALT: + aAlt = pOption->GetString(); + break; + case HTML_O_ALIGN: + eVertOri = pOption->GetEnum( aHTMLImgVAlignTable, eVertOri ); + eHoriOri = pOption->GetEnum( aHTMLImgHAlignTable, eHoriOri ); + break; + case HTML_O_WIDTH: + bPrcWidth = (pOption->GetString().Search('%') != STRING_NOTFOUND); + aSize.Width() = (long)pOption->GetNumber(); + break; + case HTML_O_HEIGHT: + bPrcHeight = (pOption->GetString().Search('%') != STRING_NOTFOUND); + aSize.Height() = (long)pOption->GetNumber(); + break; + case HTML_O_HSPACE: + aSpace.Width() = (long)pOption->GetNumber(); + break; + case HTML_O_VSPACE: + aSpace.Height() = (long)pOption->GetNumber(); + break; + case HTML_O_MAYSCRIPT: + bMayScript = sal_True; + break; + } + + // Es werden alle Parameter auch an das Applet weitergereicht + pAppletImpl->AppendParam( pOption->GetTokenString(), + pOption->GetString() ); + } + + if( !aCode.Len() ) + { + delete pAppletImpl; + pAppletImpl = 0; + return; + } + + if ( aCodeBase.Len() ) + aCodeBase = INetURLObject::GetAbsURL( sBaseURL, aCodeBase ); + pAppletImpl->CreateApplet( aCode, aName, bMayScript, aCodeBase, sBaseURL );//, aAlt ); + pAppletImpl->SetAltText( aAlt ); + + SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + if( HasStyleOptions( aStyle, aId, aClass ) ) + ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo ); + + SfxItemSet& rFrmSet = pAppletImpl->GetItemSet(); + if( !IsNewDoc() ) + Reader::ResetFrmFmtAttrs( rFrmSet ); + + // den Anker und die Ausrichtung setzen + SetAnchorAndAdjustment( eVertOri, eHoriOri, aItemSet, aPropInfo, rFrmSet ); + + // und noch die Groesse des Rahmens + Size aDfltSz( HTML_DFLT_APPLET_WIDTH, HTML_DFLT_APPLET_HEIGHT ); + SetFixSize( aSize, aDfltSz, bPrcWidth, bPrcHeight, aItemSet, aPropInfo, + rFrmSet ); + SetSpace( aSpace, aItemSet, aPropInfo, rFrmSet ); +} +#endif + +void SwHTMLParser::EndApplet() +{ +#ifdef SOLAR_JAVA + if( !pAppletImpl ) + return; + + pAppletImpl->FinishApplet(); + + // und in das Dok einfuegen + SwFrmFmt* pFlyFmt = + pDoc->Insert( *pPam, + ::svt::EmbeddedObjectRef( pAppletImpl->GetApplet(), embed::Aspects::MSOLE_CONTENT ), + &pAppletImpl->GetItemSet(), + NULL, + NULL ); + + // den alternativen Namen setzen + SwNoTxtNode *pNoTxtNd = + pDoc->GetNodes()[ pFlyFmt->GetCntnt().GetCntntIdx() + ->GetIndex()+1 ]->GetNoTxtNode(); + pNoTxtNd->SetTitle( pAppletImpl->GetAltText() ); + + // Ggf Frames anlegen und auto-geb. Rahmen registrieren + RegisterFlyFrm( pFlyFmt ); + + delete pAppletImpl; + pAppletImpl = 0; +#endif +} + +void SwHTMLParser::InsertParam() +{ +#ifdef SOLAR_JAVA + if( !pAppletImpl ) + return; + + String aName, aValue; + + const HTMLOptions *pHTMLOptions = GetOptions(); + for( sal_uInt16 i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_NAME: + aName = pOption->GetString(); + break; + case HTML_O_VALUE: + aValue = pOption->GetString(); + break; + } + } + + if( !aName.Len() ) + return; + + pAppletImpl->AppendParam( aName, aValue ); +#endif +} + + +/* */ + +void SwHTMLParser::InsertFloatingFrame() +{ + String aAlt, aId, aStyle, aClass; + Size aSize( USHRT_MAX, USHRT_MAX ); + Size aSpace( 0, 0 ); + sal_Bool bPrcWidth = sal_False, bPrcHeight = sal_False; + sal_Int16 eVertOri = text::VertOrientation::TOP; + sal_Int16 eHoriOri = text::HoriOrientation::NONE; + + const HTMLOptions *pHTMLOptions = GetOptions(); + + // Erstmal die Optionen f?r das Writer-Frame-Format holen + sal_uInt16 nArrLen = pHTMLOptions->Count(); + for ( sal_uInt16 i=0; i<nArrLen; i++ ) + { + const HTMLOption *pOption = (*pHTMLOptions)[i]; + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + case HTML_O_ALT: + aAlt = pOption->GetString(); + break; + case HTML_O_ALIGN: + eVertOri = pOption->GetEnum( aHTMLImgVAlignTable, eVertOri ); + eHoriOri = pOption->GetEnum( aHTMLImgHAlignTable, eHoriOri ); + break; + case HTML_O_WIDTH: + bPrcWidth = (pOption->GetString().Search('%') != STRING_NOTFOUND); + aSize.Width() = (long)pOption->GetNumber(); + break; + case HTML_O_HEIGHT: + bPrcHeight = (pOption->GetString().Search('%') != STRING_NOTFOUND); + aSize.Height() = (long)pOption->GetNumber(); + break; + case HTML_O_HSPACE: + aSpace.Width() = (long)pOption->GetNumber(); + break; + case HTML_O_VSPACE: + aSpace.Height() = (long)pOption->GetNumber(); + break; + } + } + + // und jetzt die fuer den SfxFrame + SfxFrameDescriptor aFrameDesc; + + SfxFrameHTMLParser::ParseFrameOptions( &aFrameDesc, pHTMLOptions, sBaseURL ); + + // den Floating-Frame anlegen + comphelper::EmbeddedObjectContainer aCnt; + ::rtl::OUString aObjName; + uno::Reference < embed::XEmbeddedObject > xObj = aCnt.CreateEmbeddedObject( SvGlobalName( SO3_IFRAME_CLASSID ).GetByteSequence(), aObjName ); + + //pFrame->EnableSetModified( sal_False ); + try + { + // TODO/MBA: testing + if ( svt::EmbeddedObjectRef::TryRunningState( xObj ) ) + { + uno::Reference < beans::XPropertySet > xSet( xObj->getComponent(), uno::UNO_QUERY ); + if ( xSet.is() ) + { + ::rtl::OUString aName = aFrameDesc.GetName(); + ScrollingMode eScroll = aFrameDesc.GetScrollingMode(); + sal_Bool bHasBorder = aFrameDesc.HasFrameBorder(); + Size aMargin = aFrameDesc.GetMargin(); + + xSet->setPropertyValue( ::rtl::OUString::createFromAscii("FrameURL"), uno::makeAny( ::rtl::OUString( aFrameDesc.GetURL().GetMainURL( INetURLObject::NO_DECODE ) ) ) ); + xSet->setPropertyValue( ::rtl::OUString::createFromAscii("FrameName"), uno::makeAny( aName ) ); + + if ( eScroll == ScrollingAuto ) + xSet->setPropertyValue( ::rtl::OUString::createFromAscii("FrameIsAutoScroll"), + uno::makeAny( sal_True ) ); + else + xSet->setPropertyValue( ::rtl::OUString::createFromAscii("FrameIsScrollingMode"), + uno::makeAny( (sal_Bool) ( eScroll == ScrollingYes) ) ); + + //if ( aFrmDescr.IsFrameBorderSet() ) + xSet->setPropertyValue( ::rtl::OUString::createFromAscii("FrameIsBorder"), + uno::makeAny( bHasBorder ) ); + /*else + xSet->setPropertyValue( ::rtl::OUString::createFromAscii("FrameIsAutoBorder"), + uno::makeAny( sal_True ) );*/ + + xSet->setPropertyValue( ::rtl::OUString::createFromAscii("FrameMarginWidth"), + uno::makeAny( sal_Int32( aMargin.Width() ) ) ); + + xSet->setPropertyValue( ::rtl::OUString::createFromAscii("FrameMarginHeight"), + uno::makeAny( sal_Int32( aMargin.Height() ) ) ); + } + } + } + catch ( uno::Exception& ) + { + } + + //pFrame->EnableSetModified( sal_True ); + + SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + if( HasStyleOptions( aStyle, aId, aClass ) ) + ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo ); + + // den Itemset holen + SfxItemSet aFrmSet( pDoc->GetAttrPool(), + RES_FRMATR_BEGIN, RES_FRMATR_END-1 ); + if( !IsNewDoc() ) + Reader::ResetFrmFmtAttrs( aFrmSet ); + + // den Anker und die Ausrichtung setzen + SetAnchorAndAdjustment( eVertOri, eHoriOri, aItemSet, aPropInfo, aFrmSet ); + + // und noch die Groesse des Rahmens + Size aDfltSz( HTML_DFLT_APPLET_WIDTH, HTML_DFLT_APPLET_HEIGHT ); + SetFixSize( aSize, aDfltSz, bPrcWidth, bPrcHeight, aItemSet, aPropInfo, + aFrmSet ); + SetSpace( aSpace, aItemSet, aPropInfo, aFrmSet ); + + // und in das Dok einfuegen + SwFrmFmt* pFlyFmt = + pDoc->Insert( *pPam, ::svt::EmbeddedObjectRef( xObj, embed::Aspects::MSOLE_CONTENT ), &aFrmSet, NULL, NULL ); + + // den alternativen Namen setzen + SwNoTxtNode *pNoTxtNd = + pDoc->GetNodes()[ pFlyFmt->GetCntnt().GetCntntIdx() + ->GetIndex()+1 ]->GetNoTxtNode(); + pNoTxtNd->SetTitle( aAlt ); + + // Ggf Frames anlegen und auto-geb. Rahmen registrieren + RegisterFlyFrm( pFlyFmt ); + + bInFloatingFrame = sal_True; +} + +/* */ + +/* +#define SWHTML_OPTTYPE_IGNORE 0 +#define SWHTML_OPTTYPE_TAG 1 +#define SWHTML_OPTTYPE_PARAM 2 + + +static sal_uInt16 GetOptionType( const String& rName, sal_Bool bApplet ) +{ + sal_uInt16 nType = bApplet ? SWHTML_OPTTYPE_PARAM : SWHTML_OPTTYPE_TAG; + + switch( rName.GetChar(0) ) + { + case 'A': + case 'a': + if( rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_align ) || + rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_alt ) ) + nType = SWHTML_OPTTYPE_IGNORE; + else if( bApplet && + (rName.EqualsIgnoreCaseAscii( sHTML_O_archive ) || + rName.EqualsIgnoreCaseAscii( sHTML_O_Archives )) ) + nType = SWHTML_OPTTYPE_TAG; + break; + case 'C': + case 'c': + if( rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_class ) || + (bApplet && (rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_code ) || + rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_codebase ))) ) + nType = SWHTML_OPTTYPE_IGNORE; + break; + case 'H': + case 'h': + if( rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_height ) || + rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_hspace ) || + (!bApplet && rName.EqualsIgnoreCaseAscii( OOO_STRING_SW_HTML_O_Hidden )) ) + nType = SWHTML_OPTTYPE_IGNORE; + break; + case 'I': + case 'i': + if( rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_id ) ) + nType = SWHTML_OPTTYPE_IGNORE; + break; + case 'M': + case 'm': + if( bApplet && rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_mayscript ) ) + nType = SWHTML_OPTTYPE_IGNORE; + break; + case 'N': + case 'n': + if( rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_name ) ) + nType = SWHTML_OPTTYPE_IGNORE; + break; + case 'O': + case 'o': + if( bApplet && rName.EqualsIgnoreCaseAscii( sHTML_O_Object ) ) + nType = SWHTML_OPTTYPE_TAG; + break; + case 'S': + case 's': + if( rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_style ) || + (!bApplet && rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_src )) ) + nType = SWHTML_OPTTYPE_IGNORE; + break; + case 'T': + case 't': + if( !bApplet && rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_type ) ) + nType = SWHTML_OPTTYPE_IGNORE; + break; + case 'V': + case 'v': + if( rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_vspace ) ) + nType = SWHTML_OPTTYPE_IGNORE; + break; + case 'W': + case 'w': + if( rName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_O_width ) ) + nType = SWHTML_OPTTYPE_IGNORE; + break; + } + + return nType; +} +*/ + +sal_uInt16 SwHTMLWriter::GuessOLENodeFrmType( const SwNode& rNode ) +{ + SwOLEObj& rObj = ((SwOLENode*)rNode.GetOLENode())->GetOLEObj(); + + SwHTMLFrmType eType = HTML_FRMTYPE_OLE; + + uno::Reference < embed::XClassifiedObject > xClass ( rObj.GetOleRef(), uno::UNO_QUERY ); + SvGlobalName aClass( xClass->getClassID() ); + if( aClass == SvGlobalName( SO3_PLUGIN_CLASSID ) ) + { + eType = HTML_FRMTYPE_PLUGIN; + } + else if( aClass == SvGlobalName( SO3_IFRAME_CLASSID ) ) + { + eType = HTML_FRMTYPE_IFRAME; + } +#ifdef SOLAR_JAVA + else if( aClass == SvGlobalName( SO3_APPLET_CLASSID ) ) + { + eType = HTML_FRMTYPE_APPLET; + } +#endif + + return static_cast< sal_uInt16 >(eType); +} + +Writer& OutHTML_FrmFmtOLENode( Writer& rWrt, const SwFrmFmt& rFrmFmt, + sal_Bool bInCntnr ) +{ + SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt; + + const SwFmtCntnt& rFlyCntnt = rFrmFmt.GetCntnt(); + sal_uLong nStt = rFlyCntnt.GetCntntIdx()->GetIndex()+1; + SwOLENode *pOLENd = rHTMLWrt.pDoc->GetNodes()[ nStt ]->GetOLENode(); + + ASSERT( pOLENd, "OLE-Node erwartet" ); + if( !pOLENd ) + return rWrt; + + SwOLEObj &rObj = pOLENd->GetOLEObj(); + + uno::Reference < embed::XEmbeddedObject > xObj( rObj.GetOleRef() ); + if ( !svt::EmbeddedObjectRef::TryRunningState( xObj ) ) + return rWrt; + + uno::Reference < beans::XPropertySet > xSet( xObj->getComponent(), uno::UNO_QUERY ); + sal_Bool bHiddenEmbed = sal_False; + + if( !xSet.is() ) + { + DBG_ERROR("Unknown Object" ); + return rWrt; + } + + ByteString aEndTags; + sal_uLong nFrmOpts; + + // wenn meoglich vor dem "Objekt" einen Zeilen-Umbruch ausgeben + if( rHTMLWrt.bLFPossible ) + rHTMLWrt.OutNewLine( sal_True ); + + if( rFrmFmt.GetName().Len() ) + rHTMLWrt.OutImplicitMark( rFrmFmt.GetName(), + pMarkToOLE ); + uno::Any aAny; + SvGlobalName aGlobName( xObj->getClassID() ); + ByteString sOut('<'); + if( aGlobName == SvGlobalName( SO3_PLUGIN_CLASSID ) ) + { + // erstmal das Plug-spezifische + sOut += OOO_STRING_SVTOOLS_HTML_embed; + + ::rtl::OUString aStr; + String aURL; + aAny = xSet->getPropertyValue( ::rtl::OUString::createFromAscii("PluginURL" ) ); + if( (aAny >>= aStr) && aStr.getLength() ) + { + aURL = URIHelper::simpleNormalizedMakeRelative( rWrt.GetBaseURL(), + aStr); + } + + if( aURL.Len() ) + { + ((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_src) += "=\""; + rWrt.Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( rWrt.Strm(), aURL, rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + sOut = '\"'; + } + + ::rtl::OUString aType; + aAny = xSet->getPropertyValue( ::rtl::OUString::createFromAscii("PluginMimeType" ) ); + if( (aAny >>= aType) && aType.getLength() ) + { + ((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_type) += "=\""; + rWrt.Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( rWrt.Strm(), aType, rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + sOut = '\"'; + } + + if ((FLY_AT_PARA == rFrmFmt.GetAnchor().GetAnchorId()) && + SURROUND_THROUGHT == rFrmFmt.GetSurround().GetSurround() ) + { + // Das Plugin ist HIDDEN + (sOut += ' ') += OOO_STRING_SW_HTML_O_Hidden; + nFrmOpts = HTML_FRMOPTS_HIDDEN_EMBED; + bHiddenEmbed = sal_True; + } + else + { + nFrmOpts = bInCntnr ? HTML_FRMOPTS_EMBED_CNTNR + : HTML_FRMOPTS_EMBED; + } + } + else if( aGlobName == SvGlobalName( SO3_APPLET_CLASSID ) ) + { + // oder das Applet-Spezifische + + sOut += OOO_STRING_SVTOOLS_HTML_applet; + + // CODEBASE + ::rtl::OUString aCd; + aAny = xSet->getPropertyValue( ::rtl::OUString::createFromAscii("AppletCodeBase" ) ); + if( (aAny >>= aCd) && aCd.getLength() ) + { + String sCodeBase( URIHelper::simpleNormalizedMakeRelative(rWrt.GetBaseURL(), aCd) ); + if( sCodeBase.Len() ) + { + ((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_codebase) += "=\""; + rWrt.Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( rWrt.Strm(), sCodeBase, rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + sOut = '\"'; + } + } + + // CODE + ::rtl::OUString aClass; + aAny = xSet->getPropertyValue( ::rtl::OUString::createFromAscii("AppletCode" ) ); + aAny >>= aClass; + ((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_code) += "=\""; + rWrt.Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( rWrt.Strm(), aClass, rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + sOut = '\"'; + + // NAME + ::rtl::OUString aAppletName; + aAny = xSet->getPropertyValue( ::rtl::OUString::createFromAscii("AppletName" ) ); + aAny >>= aAppletName; + if( aAppletName.getLength() ) + { + ((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_name) += "=\""; + rWrt.Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( rWrt.Strm(), aAppletName, rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + sOut = '\"'; + } + + sal_Bool bScript = sal_False; + aAny = xSet->getPropertyValue( ::rtl::OUString::createFromAscii("AppletIsScript" ) ); + aAny >>= bScript; + if( bScript ) + (sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_mayscript; + + nFrmOpts = bInCntnr ? HTML_FRMOPTS_APPLET_CNTNR + : HTML_FRMOPTS_APPLET; + } + else + { + // oder das Flating-Frame spezifische + + sOut += OOO_STRING_SVTOOLS_HTML_iframe; + rWrt.Strm() << sOut.GetBuffer(); + + SfxFrameHTMLWriter::Out_FrameDescriptor( rWrt.Strm(), rWrt.GetBaseURL(), + xSet, + rHTMLWrt.eDestEnc, + &rHTMLWrt.aNonConvertableCharacters ); + sOut.Erase(); + + nFrmOpts = bInCntnr ? HTML_FRMOPTS_IFRAME_CNTNR + : HTML_FRMOPTS_IFRAME; + } + + rWrt.Strm() << sOut.GetBuffer(); + + // ALT, WIDTH, HEIGHT, HSPACE, VSPACE, ALIGN + if( rHTMLWrt.IsHTMLMode( HTMLMODE_ABS_POS_FLY ) && !bHiddenEmbed ) + nFrmOpts |= HTML_FRMOPTS_OLE_CSS1; + rHTMLWrt.OutFrmFmtOptions( rFrmFmt, pOLENd->GetTitle(), + aEndTags, nFrmOpts ); + if( rHTMLWrt.IsHTMLMode( HTMLMODE_ABS_POS_FLY ) && !bHiddenEmbed ) + rHTMLWrt.OutCSS1_FrmFmtOptions( rFrmFmt, nFrmOpts ); + + if( aGlobName == SvGlobalName( SO3_APPLET_CLASSID ) ) + { + // fuer Applets die Parameter als eigene Tags ausgeben + // und ein </APPLET> schreiben + + uno::Sequence < beans::PropertyValue > aProps; + aAny = xSet->getPropertyValue( ::rtl::OUString::createFromAscii("AppletCommands" ) ); + aAny >>= aProps; + + SvCommandList aCommands; + aCommands.FillFromSequence( aProps ); + SvULongs aParams; + sal_uLong i = aCommands.Count(); + while( i > 0 ) + { + const SvCommand& rCommand = aCommands[ --i ]; + const String& rName = rCommand.GetCommand(); + sal_uInt16 nType = SwApplet_Impl::GetOptionType( rName, sal_True ); + if( SWHTML_OPTTYPE_TAG == nType ) + { + const String& rValue = rCommand.GetArgument(); + rWrt.Strm() << ' '; + HTMLOutFuncs::Out_String( rWrt.Strm(), rName, rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + rWrt.Strm() << "=\""; + HTMLOutFuncs::Out_String( rWrt.Strm(), rValue, rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ) << '\"'; + } + else if( SWHTML_OPTTYPE_PARAM == nType ) + { + aParams.Insert( i, aParams.Count() ); + } + } + + rHTMLWrt.Strm() << '>'; + + rHTMLWrt.IncIndentLevel(); // Inhalt von Applet einruecken + + sal_uInt16 ii = aParams.Count(); + while( ii > 0 ) + { + const SvCommand& rCommand = aCommands[ aParams[--ii] ]; + const String& rName = rCommand.GetCommand(); + const String& rValue = rCommand.GetArgument(); + rHTMLWrt.OutNewLine(); + ((((sOut = '<') += OOO_STRING_SVTOOLS_HTML_param) += ' ') += OOO_STRING_SVTOOLS_HTML_O_name) + += "=\""; + rWrt.Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( rWrt.Strm(), rName, rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + ((sOut = "\" ") += OOO_STRING_SVTOOLS_HTML_O_value) += "=\""; + rWrt.Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( rWrt.Strm(), rValue, rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ) << "\">"; + } + + rHTMLWrt.DecIndentLevel(); // Inhalt von Applet einruecken + if( aCommands.Count() ) + rHTMLWrt.OutNewLine(); + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_applet, sal_False ); + } + else + if( aGlobName == SvGlobalName( SO3_PLUGIN_CLASSID ) ) + { + // fuer Plugins die Paramater als Optionen schreiben + + uno::Sequence < beans::PropertyValue > aProps; + aAny = xSet->getPropertyValue( ::rtl::OUString::createFromAscii("PluginCommands" ) ); + aAny >>= aProps; + + SvCommandList aCommands; + aCommands.FillFromSequence( aProps ); + for( sal_uLong i=0; i<aCommands.Count(); i++ ) + { + const SvCommand& rCommand = aCommands[ i ]; + const String& rName = rCommand.GetCommand(); + + if( SwApplet_Impl::GetOptionType( rName, sal_False ) == SWHTML_OPTTYPE_TAG ) + { + const String& rValue = rCommand.GetArgument(); + rWrt.Strm() << ' '; + HTMLOutFuncs::Out_String( rWrt.Strm(), rName, rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + rWrt.Strm() << "=\""; + HTMLOutFuncs::Out_String( rWrt.Strm(), rValue, rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ) << '\"'; + } + } + rHTMLWrt.Strm() << '>'; + } + else + { + // und fuer Floating-Frames einfach noch ein </IFRAME> + // ausgeben + + rHTMLWrt.Strm() << '>'; + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_iframe, sal_False ); + } + + if( aEndTags.Len() ) + rWrt.Strm() << aEndTags.GetBuffer(); + + return rWrt; +} + +Writer& OutHTML_FrmFmtOLENodeGrf( Writer& rWrt, const SwFrmFmt& rFrmFmt, + sal_Bool bInCntnr ) +{ + SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt; + + const SwFmtCntnt& rFlyCntnt = rFrmFmt.GetCntnt(); + sal_uLong nStt = rFlyCntnt.GetCntntIdx()->GetIndex()+1; + SwOLENode *pOLENd = rHTMLWrt.pDoc->GetNodes()[ nStt ]->GetOLENode(); + + ASSERT( pOLENd, "OLE-Node erwartet" ); + if( !pOLENd ) + return rWrt; + + // Inhalt des Nodes als Grafik speichern + //uno::Reference < embed::XEmbeddedObject > xObj = pOLENd->GetOLEObj().GetOleRef(); + //GDIMetaFile aPic; + //if( xObj.is() && xRef->GetGDIMetaFile( aPic ).GetActionCount() ) + { + //Graphic aGrf( aPic ); + Graphic aGrf( *pOLENd->GetGraphic() ); + String aGrfNm; + const String* pTempFileName = rHTMLWrt.GetOrigFileName(); + if(pTempFileName) + aGrfNm = *pTempFileName; + + sal_uInt16 nErr = XOutBitmap::WriteGraphic( aGrf, aGrfNm, + String::CreateFromAscii("JPG"), + (XOUTBMP_USE_GIF_IF_POSSIBLE | + XOUTBMP_USE_NATIVE_IF_POSSIBLE) ); + if( nErr ) // fehlerhaft, da ist nichts auszugeben + { + rHTMLWrt.nWarn = WARN_SWG_POOR_LOAD | WARN_SW_WRITE_BASE; + return rWrt; + } + aGrfNm = URIHelper::SmartRel2Abs( + INetURLObject(rWrt.GetBaseURL()), aGrfNm, + URIHelper::GetMaybeFileHdl() ); + sal_uLong nFlags = bInCntnr ? HTML_FRMOPTS_GENIMG_CNTNR + : HTML_FRMOPTS_GENIMG; + OutHTML_Image( rWrt, rFrmFmt, aGrfNm, + pOLENd->GetTitle(), pOLENd->GetTwipSize(), + nFlags, pMarkToOLE ); + } + + return rWrt; +} + + diff --git a/sw/source/filter/html/htmlsect.cxx b/sw/source/filter/html/htmlsect.cxx new file mode 100644 index 000000000000..2959a55a0ea8 --- /dev/null +++ b/sw/source/filter/html/htmlsect.cxx @@ -0,0 +1,860 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <rtl/uri.hxx> + +#include <svl/urihelper.hxx> +#include <vcl/svapp.hxx> +#include <vcl/wrkwin.hxx> +#include <editeng/adjitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/brkitem.hxx> +#include <svtools/htmltokn.h> +#include <svtools/htmlkywd.hxx> +#include <sfx2/linkmgr.hxx> + +#include "hintids.hxx" +#include <fmtornt.hxx> +#include <fmthdft.hxx> +#include <fmtcntnt.hxx> +#include <fmtfsize.hxx> +#include <fmtclds.hxx> +#include <fmtanchr.hxx> +#include <fmtpdsc.hxx> +#include <fmtsrnd.hxx> +#include <fmtflcnt.hxx> +#include "frmatr.hxx" +#include "doc.hxx" +#include "pam.hxx" +#include "ndtxt.hxx" +#include "shellio.hxx" +#include "section.hxx" +#include "poolfmt.hxx" +#include "pagedesc.hxx" +#include "swtable.hxx" +#include "viewsh.hxx" +#include "swcss1.hxx" +#include "swhtml.hxx" + +#define CONTEXT_FLAGS_MULTICOL (HTML_CNTXT_STRIP_PARA | \ + HTML_CNTXT_KEEP_NUMRULE | \ + HTML_CNTXT_KEEP_ATTRS) +//#define CONTEXT_FLAGS_HDRFTR (HTML_CNTXT_STRIP_PARA|HTML_CNTXT_PROTECT_STACK) +#define CONTEXT_FLAGS_HDRFTR (CONTEXT_FLAGS_MULTICOL) +#define CONTEXT_FLAGS_FTN (CONTEXT_FLAGS_MULTICOL) + + +using namespace ::com::sun::star; + + +/* */ + +void SwHTMLParser::NewDivision( int nToken ) +{ + String aId, aHRef, aStyle, aClass, aLang, aDir; + SvxAdjust eAdjust = HTML_CENTER_ON==nToken ? SVX_ADJUST_CENTER + : SVX_ADJUST_END; + + sal_Bool bHeader=sal_False, bFooter=sal_False; + const HTMLOptions *pHTMLOptions = GetOptions(); + for( sal_uInt16 i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_ALIGN: + if( HTML_DIVISION_ON==nToken ) + eAdjust = (SvxAdjust)pOption->GetEnum( aHTMLPAlignTable, + static_cast< sal_uInt16 >(eAdjust) ); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + case HTML_O_LANG: + aLang = pOption->GetString(); + break; + case HTML_O_DIR: + aDir = pOption->GetString(); + break; + case HTML_O_HREF: + aHRef = pOption->GetString(); + break; + case HTML_O_TYPE: + { + const String& rType = pOption->GetString(); + if( rType.EqualsIgnoreCaseAscii( "HEADER" ) ) + bHeader = sal_True; + else if( rType.EqualsIgnoreCaseAscii( "FOOTER" ) ) + bFooter = sal_True; + } + } + } + + sal_Bool bAppended = sal_False; + if( pPam->GetPoint()->nContent.GetIndex() ) + { + AppendTxtNode( bHeader||bFooter||aId.Len()||aHRef.Len() ? AM_NORMAL + : AM_NOSPACE ); + bAppended = sal_True; + } + + _HTMLAttrContext *pCntxt = new _HTMLAttrContext( static_cast< sal_uInt16 >(nToken) ); + + sal_Bool bStyleParsed = sal_False, bPositioned = sal_False; + SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) ) + { + bStyleParsed = ParseStyleOptions( aStyle, aId, aClass, + aItemSet, aPropInfo, &aLang, &aDir ); + if( bStyleParsed ) + { + bPositioned = HTML_DIVISION_ON == nToken && aClass.Len() && + CreateContainer( aClass, aItemSet, aPropInfo, + pCntxt ); + if( !bPositioned ) + bPositioned = DoPositioning( aItemSet, aPropInfo, pCntxt ); + } + } + + if( !bPositioned && (bHeader || bFooter) && IsNewDoc() ) + { + SwPageDesc *pPageDesc = pCSS1Parser->GetMasterPageDesc(); + SwFrmFmt& rPageFmt = pPageDesc->GetMaster(); + + SwFrmFmt *pHdFtFmt; + sal_Bool bNew = sal_False; + sal_uInt16 nFlags = CONTEXT_FLAGS_HDRFTR; + if( bHeader ) + { + pHdFtFmt = (SwFrmFmt*)rPageFmt.GetHeader().GetHeaderFmt(); + if( !pHdFtFmt ) + { + // noch keine Header, dann erzeuge einen. + rPageFmt.SetFmtAttr( SwFmtHeader( sal_True )); + pHdFtFmt = (SwFrmFmt*)rPageFmt.GetHeader().GetHeaderFmt(); + bNew = sal_True; + } + nFlags |= HTML_CNTXT_HEADER_DIST; + } + else + { + pHdFtFmt = (SwFrmFmt*)rPageFmt.GetFooter().GetFooterFmt(); + if( !pHdFtFmt ) + { + // noch keine Footer, dann erzeuge einen. + rPageFmt.SetFmtAttr( SwFmtFooter( sal_True )); + pHdFtFmt = (SwFrmFmt*)rPageFmt.GetFooter().GetFooterFmt(); + bNew = sal_True; + } + nFlags |= HTML_CNTXT_FOOTER_DIST; + } + + const SwFmtCntnt& rFlyCntnt = pHdFtFmt->GetCntnt(); + const SwNodeIndex& rCntntStIdx = *rFlyCntnt.GetCntntIdx(); + SwCntntNode *pCNd; + + if( bNew ) + { + pCNd = pDoc->GetNodes()[rCntntStIdx.GetIndex()+1] + ->GetCntntNode(); + } + else + { + // Einen neuen Node zu Beginn der Section anlegen + SwNodeIndex aSttIdx( rCntntStIdx, 1 ); + pCNd = pDoc->GetNodes().MakeTxtNode( aSttIdx, + pCSS1Parser->GetTxtCollFromPool(RES_POOLCOLL_TEXT)); + + // Den bisherigen Inhalt der Section loeschen + SwPaM aDelPam( aSttIdx ); + aDelPam.SetMark(); + + const SwStartNode *pStNd = + (const SwStartNode *) &rCntntStIdx.GetNode(); + aDelPam.GetPoint()->nNode = pStNd->EndOfSectionIndex() - 1; + + pDoc->DelFullPara( aDelPam ); + + // Die Seitenvorlage aktualisieren + for( sal_uInt16 i=0; i < pDoc->GetPageDescCnt(); i++ ) + { + if( RES_POOLPAGE_HTML==const_cast<const SwDoc *>(pDoc) + ->GetPageDesc(i).GetPoolFmtId() ) + { + pDoc->ChgPageDesc( i, *pPageDesc ); + break; + } + } + } + + SwPosition aNewPos( SwNodeIndex( rCntntStIdx, 1 ), SwIndex( pCNd, 0 ) ); + SaveDocContext( pCntxt, nFlags, &aNewPos ); + } + else if( !bPositioned && aId.Len() > 9 && + ('s' == aId.GetChar(0) || 'S' == aId.GetChar(0) ) && + ('d' == aId.GetChar(1) || 'D' == aId.GetChar(1) ) ) + { + sal_Bool bEndNote = sal_False, bFootNote = sal_False; + if( aId.CompareIgnoreCaseToAscii( OOO_STRING_SVTOOLS_HTML_sdendnote, 9 ) == COMPARE_EQUAL ) + bEndNote = sal_True; + else if( aId.CompareIgnoreCaseToAscii( OOO_STRING_SVTOOLS_HTML_sdfootnote, 10 ) == COMPARE_EQUAL ) + bFootNote = sal_True; + if( bFootNote || bEndNote ) + { + SwNodeIndex *pStartNdIdx = GetFootEndNoteSection( aId ); + if( pStartNdIdx ) + { + SwCntntNode *pCNd = + pDoc->GetNodes()[pStartNdIdx->GetIndex()+1]->GetCntntNode(); + SwNodeIndex aTmpSwNodeIndex = SwNodeIndex(*pCNd); + SwPosition aNewPos( aTmpSwNodeIndex, SwIndex( pCNd, 0 ) ); + SaveDocContext( pCntxt, CONTEXT_FLAGS_FTN, &aNewPos ); + aId = aPropInfo.aId = aEmptyStr; + } + } + } + + // Bereiche fuegen wir in Rahmen nur dann ein, wenn der Bereich gelinkt ist. + if( (aId.Len() && !bPositioned) || aHRef.Len() ) + { + // Bereich einfuegen (muss vor dem Setzten von Attributen erfolgen, + // weil die Section vor der PaM-Position eingefuegt. + + // wenn wir im ersten Node einer Section stehen, wir die neue + // Section nicht in der aktuellen, sondern vor der aktuellen + // Section eingefuegt. Deshalb muessen wir dann einen Node + // einfuegen. UND IN LOESCHEN!!! + if( !bAppended ) + { + SwNodeIndex aPrvNdIdx( pPam->GetPoint()->nNode, -1 ); + if (aPrvNdIdx.GetNode().IsSectionNode()) + { + AppendTxtNode(); + bAppended = sal_True; + } + } + _HTMLAttrs *pPostIts = bAppended ? 0 : new _HTMLAttrs; + SetAttr( sal_True, sal_True, pPostIts ); + + // Namen der Section eindeutig machen + String aName( pDoc->GetUniqueSectionName( aId.Len() ? &aId : 0 ) ); + + if( aHRef.Len() ) + { + sal_Unicode cDelim = 255U; + String aURL; + xub_StrLen nPos = aHRef.SearchBackward( cDelim ); + xub_StrLen nPos2 = STRING_NOTFOUND; + if( STRING_NOTFOUND != nPos ) + { + nPos2 = aHRef.SearchBackward( cDelim, nPos ); + if( STRING_NOTFOUND != nPos2 ) + { + xub_StrLen nTmp = nPos; + nPos = nPos2; + nPos2 = nTmp; + } + } + if( STRING_NOTFOUND == nPos ) + { + aURL = URIHelper::SmartRel2Abs(INetURLObject( sBaseURL ), aHRef, Link(), false); + } + else + { + aURL = URIHelper::SmartRel2Abs(INetURLObject( sBaseURL ), aHRef.Copy( 0, nPos ), Link(), false ); + aURL += sfx2::cTokenSeperator; + if( STRING_NOTFOUND == nPos2 ) + { + aURL += aHRef.Copy( nPos+1 ); + } + else + { + aURL += aHRef.Copy( nPos+1, nPos2 - (nPos+1) ); + aURL += sfx2::cTokenSeperator; + aURL += String(rtl::Uri::decode( aHRef.Copy( nPos2+1 ), + rtl_UriDecodeWithCharset, + RTL_TEXTENCODING_ISO_8859_1 )); + } + } + aHRef = aURL; + } + + SwSectionData aSection( (aHRef.Len()) ? FILE_LINK_SECTION + : CONTENT_SECTION, aName ); + if( aHRef.Len() ) + { + aSection.SetLinkFileName( aHRef ); + aSection.SetProtectFlag(true); + } + + SfxItemSet aFrmItemSet( pDoc->GetAttrPool(), + RES_FRMATR_BEGIN, RES_FRMATR_END-1 ); + if( !IsNewDoc() ) + Reader::ResetFrmFmtAttrs(aFrmItemSet ); + + const SfxPoolItem *pItem; + if( SFX_ITEM_SET == aItemSet.GetItemState( RES_BACKGROUND, sal_False, + &pItem ) ) + { + aFrmItemSet.Put( *pItem ); + aItemSet.ClearItem( RES_BACKGROUND ); + } + if( SFX_ITEM_SET == aItemSet.GetItemState( RES_FRAMEDIR, sal_False, + &pItem ) ) + { + aFrmItemSet.Put( *pItem ); + aItemSet.ClearItem( RES_FRAMEDIR ); + } + + pDoc->InsertSwSection( *pPam, aSection, 0, &aFrmItemSet, false ); + + // ggfs. einen Bereich anspringen + if( JUMPTO_REGION == eJumpTo && aName == sJmpMark ) + { + bChkJumpMark = sal_True; + eJumpTo = JUMPTO_NONE; + } + + SwTxtNode* pOldTxtNd = + (bAppended) ? 0 : pPam->GetPoint()->nNode.GetNode().GetTxtNode(); + + pPam->Move( fnMoveBackward ); + + // PageDesc- und SwFmtBreak Attribute vom aktuellen Node in den + // (ersten) Node des Bereich verschieben. + if( pOldTxtNd ) + MovePageDescAttrs( pOldTxtNd, pPam->GetPoint()->nNode.GetIndex(), + sal_True ); + + if( pPostIts ) + { + // noch vorhandene PostIts in den ersten Absatz + // der Tabelle setzen + InsertAttrs( *pPostIts ); + delete pPostIts; + pPostIts = 0; + } + + pCntxt->SetSpansSection( sal_True ); + + // keine text::Bookmarks mit dem gleichen Namen wie Bereiche einfuegen + if( aPropInfo.aId.Len() && aPropInfo.aId==aName ) + aPropInfo.aId.Erase(); + } + else + { + pCntxt->SetAppendMode( AM_NOSPACE ); + } + + if( SVX_ADJUST_END != eAdjust ) + { + InsertAttr( &aAttrTab.pAdjust, SvxAdjustItem(eAdjust, RES_PARATR_ADJUST), pCntxt ); + } + + // Style parsen + if( bStyleParsed ) + InsertAttrs( aItemSet, aPropInfo, pCntxt, sal_True ); + + PushContext( pCntxt ); +} + +void SwHTMLParser::EndDivision( int /*nToken*/ ) +{ + // Stack-Eintrag zu dem Token suchen (weil wir noch den Div-Stack + // haben unterscheiden wir erst einmal nicht zwischen DIV und CENTER + _HTMLAttrContext *pCntxt = 0; + sal_uInt16 nPos = aContexts.Count(); + while( !pCntxt && nPos>nContextStMin ) + { + switch( aContexts[--nPos]->GetToken() ) + { + case HTML_CENTER_ON: + case HTML_DIVISION_ON: + pCntxt = aContexts[nPos]; + aContexts.Remove( nPos, 1 ); + break; + } + } + + if( pCntxt ) + { + // Attribute beenden + EndContext( pCntxt ); + SetAttr(); // Absatz-Atts wegen JavaScript moeglichst schnell setzen + + delete pCntxt; + } +} + +void SwHTMLParser::FixHeaderFooterDistance( sal_Bool bHeader, + const SwPosition *pOldPos ) +{ + SwPageDesc *pPageDesc = pCSS1Parser->GetMasterPageDesc(); + SwFrmFmt& rPageFmt = pPageDesc->GetMaster(); + + SwFrmFmt *pHdFtFmt = + bHeader ? (SwFrmFmt*)rPageFmt.GetHeader().GetHeaderFmt() + : (SwFrmFmt*)rPageFmt.GetFooter().GetFooterFmt(); + ASSERT( pHdFtFmt, "Doch keine Kopf- oder Fusszeile" ); + + const SwFmtCntnt& rFlyCntnt = pHdFtFmt->GetCntnt(); + const SwNodeIndex& rCntntStIdx = *rFlyCntnt.GetCntntIdx(); + + sal_uLong nPrvNxtIdx; + if( bHeader ) + { + nPrvNxtIdx = rCntntStIdx.GetNode().EndOfSectionIndex()-1; + } + else + { + nPrvNxtIdx = pOldPos->nNode.GetIndex() - 1; + } + + sal_uInt16 nSpace = 0; + SwTxtNode *pTxtNode = pDoc->GetNodes()[nPrvNxtIdx]->GetTxtNode(); + if( pTxtNode ) + { + const SvxULSpaceItem& rULSpace = + ((const SvxULSpaceItem&)pTxtNode + ->SwCntntNode::GetAttr( RES_UL_SPACE )); + + // Der untere Absatz-Abstand wird zum Abstand zur + // Kopf- oder Fusszeile + nSpace = rULSpace.GetLower(); + + // und anschliessend auf einen vernuenftigen Wert + // gesetzt + const SvxULSpaceItem& rCollULSpace = + pTxtNode->GetAnyFmtColl().GetULSpace(); + if( rCollULSpace.GetUpper() == rULSpace.GetUpper() ) + pTxtNode->ResetAttr( RES_UL_SPACE ); + else + pTxtNode->SetAttr( + SvxULSpaceItem( rULSpace.GetUpper(), + rCollULSpace.GetLower(), RES_UL_SPACE ) ); + } + + if( bHeader ) + { + nPrvNxtIdx = pOldPos->nNode.GetIndex(); + } + else + { + nPrvNxtIdx = rCntntStIdx.GetIndex() + 1; + } + + pTxtNode = pDoc->GetNodes()[nPrvNxtIdx] + ->GetTxtNode(); + if( pTxtNode ) + { + const SvxULSpaceItem& rULSpace = + ((const SvxULSpaceItem&)pTxtNode + ->SwCntntNode::GetAttr( RES_UL_SPACE )); + + // Der obere Absatz-Abstand wird zum Abstand zur + // Kopf- oder Fusszeile, wenn er groesser ist als + // der untere vom Absatz davor + if( rULSpace.GetUpper() > nSpace ) + nSpace = rULSpace.GetUpper(); + + // und anschliessend auf einen vernuenftigen Wert gesetzt + const SvxULSpaceItem& rCollULSpace = + pTxtNode->GetAnyFmtColl().GetULSpace(); + if( rCollULSpace.GetLower() == rULSpace.GetLower() ) + pTxtNode->ResetAttr( RES_UL_SPACE ); + else + pTxtNode->SetAttr( + SvxULSpaceItem( rCollULSpace.GetUpper(), + rULSpace.GetLower(), RES_UL_SPACE ) ); + } + + SvxULSpaceItem aULSpace( RES_UL_SPACE ); + if( bHeader ) + aULSpace.SetLower( nSpace ); + else + aULSpace.SetUpper( nSpace ); + + pHdFtFmt->SetFmtAttr( aULSpace ); +} + +sal_Bool SwHTMLParser::EndSection( sal_Bool bLFStripped ) +{ + SwEndNode *pEndNd = pDoc->GetNodes()[pPam->GetPoint()->nNode.GetIndex()+1] + ->GetEndNode(); + if( pEndNd && pEndNd->StartOfSectionNode()->IsSectionNode() ) + { + // den Bereich beenden + if( !bLFStripped ) + StripTrailingPara(); + pPam->Move( fnMoveForward ); + return sal_True; + } + + ASSERT( !this, "Falsche PaM Position Beenden eines Bereichs" ); + + return sal_False; +} + +sal_Bool SwHTMLParser::EndSections( sal_Bool bLFStripped ) +{ + sal_Bool bSectionClosed = sal_False; + sal_uInt16 nPos = aContexts.Count(); + while( nPos>nContextStMin ) + { + _HTMLAttrContext *pCntxt = aContexts[--nPos]; + if( pCntxt->GetSpansSection() && EndSection( bLFStripped ) ) + { + bSectionClosed = sal_True; + pCntxt->SetSpansSection( sal_False ); + bLFStripped = sal_False; + } + } + + return bSectionClosed; +} + +/* */ + +void SwHTMLParser::NewMultiCol() +{ + String aId, aStyle, aClass, aLang, aDir; + long nWidth = 100; + sal_uInt16 nCols = 0, nGutter = 10; + sal_Bool bPrcWidth = sal_True; + + const HTMLOptions *pHTMLOptions = GetOptions(); + sal_uInt16 i; + + for( i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + case HTML_O_LANG: + aLang = pOption->GetString(); + break; + case HTML_O_DIR: + aDir = pOption->GetString(); + break; + case HTML_O_COLS: + nCols = (sal_uInt16)pOption->GetNumber(); + break; + case HTML_O_WIDTH: + nWidth = pOption->GetNumber(); + bPrcWidth = (pOption->GetString().Search('%') != STRING_NOTFOUND); + if( bPrcWidth && nWidth>100 ) + nWidth = 100; + break; + case HTML_O_GUTTER: + nGutter = (sal_uInt16)pOption->GetNumber(); + break; + + } + } + + _HTMLAttrContext *pCntxt = new _HTMLAttrContext( HTML_MULTICOL_ON ); + + //.is the multicol elememt contained in a container? That may be the + // case for 5.0 documents. + sal_Bool bInCntnr = sal_False; + i = aContexts.Count(); + while( !bInCntnr && i > nContextStMin ) + bInCntnr = 0 != aContexts[--i]->GetFrmItemSet(); + + // Parse style sheets, but don't position anything by now. + sal_Bool bStyleParsed = sal_False; + SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) ) + bStyleParsed = ParseStyleOptions( aStyle, aId, aClass, + aItemSet, aPropInfo, &aLang, &aDir ); + + // Calculate width. + sal_uInt8 nPrcWidth = bPrcWidth ? (sal_uInt8)nWidth : 0; + sal_uInt16 nTwipWidth = 0; + if( !bPrcWidth && nWidth && Application::GetDefaultDevice() ) + { + nTwipWidth = (sal_uInt16)Application::GetDefaultDevice() + ->PixelToLogic( Size(nWidth, 0), + MapMode(MAP_TWIP) ).Width(); + } + + if( !nPrcWidth && nTwipWidth < MINFLY ) + nTwipWidth = MINFLY; + + // Do positioning. + sal_Bool bPositioned = sal_False; + if( bInCntnr || pCSS1Parser->MayBePositioned( aPropInfo, sal_True ) ) + { + SfxItemSet aFrmItemSet( pDoc->GetAttrPool(), + RES_FRMATR_BEGIN, RES_FRMATR_END-1 ); + if( !IsNewDoc() ) + Reader::ResetFrmFmtAttrs(aFrmItemSet ); + + SetAnchorAndAdjustment( text::VertOrientation::NONE, text::HoriOrientation::NONE, aItemSet, aPropInfo, + aFrmItemSet ); + + // The width is either the WIDTH attribute's value or contained + // in some style option. + SetVarSize( aItemSet, aPropInfo, aFrmItemSet, nTwipWidth, nPrcWidth ); + + SetSpace( Size(0,0), aItemSet, aPropInfo, aFrmItemSet ); + + // Set some other frame attributes. If the background is set, its + // it will be cleared here. That for, it won't be set at the section, + // too. + SetFrmFmtAttrs( aItemSet, aPropInfo, + HTML_FF_BOX|HTML_FF_BACKGROUND|HTML_FF_PADDING|HTML_FF_DIRECTION, + aFrmItemSet ); + + // Insert fly frame. If the are columns, the fly frame's name is not + // the sections name but a generated one. + String aFlyName( aEmptyStr ); + if( nCols < 2 ) + { + aFlyName = aId; + aPropInfo.aId.Erase(); + } + + InsertFlyFrame( aFrmItemSet, pCntxt, aFlyName, CONTEXT_FLAGS_ABSPOS ); + + pCntxt->SetPopStack( sal_True ); + bPositioned = sal_True; + } + + sal_Bool bAppended = sal_False; + if( !bPositioned ) + { + if( pPam->GetPoint()->nContent.GetIndex() ) + { + AppendTxtNode( AM_SPACE ); + bAppended = sal_True; + } + else + { + AddParSpace(); + } + } + + // If there are less then 2 columns, no section is inserted. + if( nCols >= 2 ) + { + if( !bAppended ) + { + // If the pam is at the start of a section, a additional text + // node must be inserted. Otherwise, the new section will be + // inserted in front of the old one. + SwNodeIndex aPrvNdIdx( pPam->GetPoint()->nNode, -1 ); + if (aPrvNdIdx.GetNode().IsSectionNode()) + { + AppendTxtNode(); + bAppended = sal_True; + } + } + _HTMLAttrs *pPostIts = bAppended ? 0 : new _HTMLAttrs; + SetAttr( sal_True, sal_True, pPostIts ); + + // Make section name unique. + String aName( pDoc->GetUniqueSectionName( aId.Len() ? &aId : 0 ) ); + SwSectionData aSection( CONTENT_SECTION, aName ); + + SfxItemSet aFrmItemSet( pDoc->GetAttrPool(), + RES_FRMATR_BEGIN, RES_FRMATR_END-1 ); + if( !IsNewDoc() ) + Reader::ResetFrmFmtAttrs(aFrmItemSet ); + + if( nGutter && Application::GetDefaultDevice() ) + { + nGutter = (sal_uInt16)Application::GetDefaultDevice() + ->PixelToLogic( Size(nGutter, 0), + MapMode(MAP_TWIP) ).Width(); + } + + SwFmtCol aFmtCol; +#ifndef WIDTH_SUPPORTED_BY_SECTIONS + nPrcWidth = 100; +#endif + + aFmtCol.Init( nCols, nGutter, nPrcWidth ? USHRT_MAX : nTwipWidth ); + aFrmItemSet.Put( aFmtCol ); + + const SfxPoolItem *pItem; + if( SFX_ITEM_SET == aItemSet.GetItemState( RES_BACKGROUND, sal_False, + &pItem ) ) + { + aFrmItemSet.Put( *pItem ); + aItemSet.ClearItem( RES_BACKGROUND ); + } + if( SFX_ITEM_SET == aItemSet.GetItemState( RES_FRAMEDIR, sal_False, + &pItem ) ) + { + aFrmItemSet.Put( *pItem ); + aItemSet.ClearItem( RES_FRAMEDIR ); + } + pDoc->InsertSwSection( *pPam, aSection, 0, &aFrmItemSet, false ); + + // Jump to section, if this is requested. + if( JUMPTO_REGION == eJumpTo && aName == sJmpMark ) + { + bChkJumpMark = sal_True; + eJumpTo = JUMPTO_NONE; + } + + SwTxtNode* pOldTxtNd = + (bAppended) ? 0 : pPam->GetPoint()->nNode.GetNode().GetTxtNode(); + + pPam->Move( fnMoveBackward ); + + // Move PageDesc and SwFmtBreak attributes of the current node + // to the section's first node. + if( pOldTxtNd ) + MovePageDescAttrs( pOldTxtNd, pPam->GetPoint()->nNode.GetIndex(), + sal_True ); + + if( pPostIts ) + { + // Move pending PostIts into the section. + InsertAttrs( *pPostIts ); + delete pPostIts; + pPostIts = 0; + } + + pCntxt->SetSpansSection( sal_True ); + + // Insert a bookmark if its name differs from the section's name only. + if( aPropInfo.aId.Len() && aPropInfo.aId==aName ) + aPropInfo.aId.Erase(); + } + + // Additional attributes must be set as hard ones. + if( bStyleParsed ) + InsertAttrs( aItemSet, aPropInfo, pCntxt, sal_True ); + + PushContext( pCntxt ); +} + +/* */ + +void SwHTMLParser::InsertFlyFrame( const SfxItemSet& rItemSet, + _HTMLAttrContext *pCntxt, + const String& rName, + sal_uInt16 nFlags ) +{ + RndStdIds eAnchorId = + ((const SwFmtAnchor&)rItemSet.Get( RES_ANCHOR )).GetAnchorId(); + + // Den Rahmen anlegen + SwFlyFrmFmt* pFlyFmt = pDoc->MakeFlySection( eAnchorId, pPam->GetPoint(), + &rItemSet ); + // Ggf. den Namen setzen + if( rName.Len() ) + pFlyFmt->SetName( rName ); + + RegisterFlyFrm( pFlyFmt ); + + const SwFmtCntnt& rFlyCntnt = pFlyFmt->GetCntnt(); + const SwNodeIndex& rFlyCntIdx = *rFlyCntnt.GetCntntIdx(); + SwCntntNode *pCNd = pDoc->GetNodes()[rFlyCntIdx.GetIndex()+1] + ->GetCntntNode(); + + SwPosition aNewPos( SwNodeIndex( rFlyCntIdx, 1 ), SwIndex( pCNd, 0 ) ); + SaveDocContext( pCntxt, nFlags, &aNewPos ); +} + + +/* */ + +void SwHTMLParser::MovePageDescAttrs( SwNode *pSrcNd, + sal_uLong nDestIdx, + sal_Bool bFmtBreak ) +{ + SwCntntNode* pDestCntntNd = + pDoc->GetNodes()[nDestIdx]->GetCntntNode(); + + ASSERT( pDestCntntNd, "Wieso ist das Ziel kein Content-Node?" ); + + if( pSrcNd->IsCntntNode() ) + { + SwCntntNode* pSrcCntntNd = pSrcNd->GetCntntNode(); + + const SfxPoolItem* pItem; + if( SFX_ITEM_SET == pSrcCntntNd->GetSwAttrSet() + .GetItemState( RES_PAGEDESC, sal_False, &pItem ) && + ((SwFmtPageDesc *)pItem)->GetPageDesc() ) + { + pDestCntntNd->SetAttr( *pItem ); + pSrcCntntNd->ResetAttr( RES_PAGEDESC ); + } + if( SFX_ITEM_SET == pSrcCntntNd->GetSwAttrSet() + .GetItemState( RES_BREAK, sal_False, &pItem ) ) + { + switch( ((SvxFmtBreakItem *)pItem)->GetBreak() ) + { + case SVX_BREAK_PAGE_BEFORE: + case SVX_BREAK_PAGE_AFTER: + case SVX_BREAK_PAGE_BOTH: + if( bFmtBreak ) + pDestCntntNd->SetAttr( *pItem ); + pSrcCntntNd->ResetAttr( RES_BREAK ); + default: + ; + } + } + } + else if( pSrcNd->IsTableNode() ) + { + SwFrmFmt *pFrmFmt = pSrcNd->GetTableNode()->GetTable().GetFrmFmt(); + + const SfxPoolItem* pItem; + if( SFX_ITEM_SET == pFrmFmt->GetAttrSet(). + GetItemState( RES_PAGEDESC, sal_False, &pItem ) ) + { + pDestCntntNd->SetAttr( *pItem ); + pFrmFmt->ResetFmtAttr( RES_PAGEDESC ); + } + } +} + diff --git a/sw/source/filter/html/htmltab.cxx b/sw/source/filter/html/htmltab.cxx new file mode 100644 index 000000000000..28d87439c73f --- /dev/null +++ b/sw/source/filter/html/htmltab.cxx @@ -0,0 +1,5599 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" +//#define TEST_RESIZE + + +#include "hintids.hxx" +#include <vcl/svapp.hxx> +#ifndef _WRKWIN_HXX //autogen +#include <vcl/wrkwin.hxx> +#endif +#include <editeng/boxitem.hxx> +#include <editeng/brshitem.hxx> +#include <editeng/adjitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/brkitem.hxx> +#include <editeng/spltitem.hxx> +#include <svtools/htmltokn.h> +#include <svtools/htmlkywd.hxx> +#include <svl/urihelper.hxx> + + +#include <fmtornt.hxx> +#include <frmfmt.hxx> +#include <fmtfsize.hxx> +#include <fmtsrnd.hxx> +#include <fmtpdsc.hxx> +#include <fmtcntnt.hxx> +#include <fmtanchr.hxx> +#include <fmtlsplt.hxx> +#include "frmatr.hxx" +#include "pam.hxx" +#include "doc.hxx" +#include "ndtxt.hxx" +#include "shellio.hxx" +#include "poolfmt.hxx" +#include "swtable.hxx" +#include "cellatr.hxx" +#ifdef TEST_RESIZE +#include "viewsh.hxx" +#endif +#include "htmltbl.hxx" +#include "swtblfmt.hxx" +#include "htmlnum.hxx" +#include "swhtml.hxx" +#include "swcss1.hxx" +#include <numrule.hxx> + +#define NETSCAPE_DFLT_BORDER 1 +#define NETSCAPE_DFLT_CELLPADDING 1 +#define NETSCAPE_DFLT_CELLSPACING 2 + +//#define FIX56334 + +using namespace ::com::sun::star; + + +static HTMLOptionEnum __FAR_DATA aHTMLTblVAlignTable[] = +{ + { OOO_STRING_SVTOOLS_HTML_VA_top, text::VertOrientation::NONE }, + { OOO_STRING_SVTOOLS_HTML_VA_middle, text::VertOrientation::CENTER }, + { OOO_STRING_SVTOOLS_HTML_VA_bottom, text::VertOrientation::BOTTOM }, + { 0, 0 } +}; + + +/* */ + +// Die Optionen eines Table-Tags + +struct HTMLTableOptions +{ + sal_uInt16 nCols; + sal_uInt16 nWidth; + sal_uInt16 nHeight; + sal_uInt16 nCellPadding; + sal_uInt16 nCellSpacing; + sal_uInt16 nBorder; + sal_uInt16 nHSpace; + sal_uInt16 nVSpace; + + SvxAdjust eAdjust; + sal_Int16 eVertOri; + HTMLTableFrame eFrame; + HTMLTableRules eRules; + + sal_Bool bPrcWidth : 1; + sal_Bool bTableAdjust : 1; + sal_Bool bBGColor : 1; + + Color aBorderColor; + Color aBGColor; + + String aBGImage, aStyle, aId, aClass, aDir; + + HTMLTableOptions( const HTMLOptions *pOptions, SvxAdjust eParentAdjust ); +}; + +/* */ + +class _HTMLTableContext +{ + SwHTMLNumRuleInfo aNumRuleInfo; // Vor der Tabelle gueltige Numerierung + + SwTableNode *pTblNd; // der Tabellen-Node + SwFrmFmt *pFrmFmt; // der Fly frame::Frame, in dem die Tabelle steht + SwPosition *pPos; // die Position hinter der Tabelle + + sal_uInt16 nContextStAttrMin; + sal_uInt16 nContextStMin; + + sal_Bool bRestartPRE : 1; + sal_Bool bRestartXMP : 1; + sal_Bool bRestartListing : 1; + +public: + + _HTMLAttrTable aAttrTab; // und die Attribute + + _HTMLTableContext( SwPosition *pPs, sal_uInt16 nCntxtStMin, + sal_uInt16 nCntxtStAttrMin ) : + pTblNd( 0 ), + pFrmFmt( 0 ), + pPos( pPs ), + nContextStAttrMin( nCntxtStAttrMin ), + nContextStMin( nCntxtStMin ), + bRestartPRE( sal_False ), + bRestartXMP( sal_False ), + bRestartListing( sal_False ) + { + memset( &aAttrTab, 0, sizeof( _HTMLAttrTable )); + } + + ~_HTMLTableContext(); + + void SetNumInfo( const SwHTMLNumRuleInfo& rInf ) { aNumRuleInfo.Set(rInf); } + const SwHTMLNumRuleInfo& GetNumInfo() const { return aNumRuleInfo; }; + + void SavePREListingXMP( SwHTMLParser& rParser ); + void RestorePREListingXMP( SwHTMLParser& rParser ); + + SwPosition *GetPos() const { return pPos; } + + void SetTableNode( SwTableNode *pNd ) { pTblNd = pNd; } + SwTableNode *GetTableNode() const { return pTblNd; } + + void SetFrmFmt( SwFrmFmt *pFmt ) { pFrmFmt = pFmt; } + SwFrmFmt *GetFrmFmt() const { return pFrmFmt; } + + sal_uInt16 GetContextStMin() const { return nContextStMin; } + sal_uInt16 GetContextStAttrMin() const { return nContextStAttrMin; } +}; + +/* */ + +// der Inhalt einer Zelle ist eine verkettete Liste mit SwStartNodes und +// HTMLTables. + +class HTMLTableCnts +{ + HTMLTableCnts *pNext; // der naechste Inhalt + + // von den beiden naechsten Pointern darf nur einer gesetzt sein! + const SwStartNode *pStartNode; // ein Abastz + HTMLTable *pTable; // eine Tabelle + + SwHTMLTableLayoutCnts* pLayoutInfo; + + sal_Bool bNoBreak; + + void InitCtor(); + +public: + + HTMLTableCnts( const SwStartNode* pStNd ); + HTMLTableCnts( HTMLTable* pTab ); + + ~HTMLTableCnts(); // nur in ~HTMLTableCell erlaubt + + // Ermitteln des SwStartNode bzw. der HTMLTable + const SwStartNode *GetStartNode() const { return pStartNode; } + const HTMLTable *GetTable() const { return pTable; } + HTMLTable *GetTable() { return pTable; } + + // hinzufuegen eines neuen Knotens am Listenende + void Add( HTMLTableCnts* pNewCnts ); + + // Ermitteln des naechsten Knotens + const HTMLTableCnts *Next() const { return pNext; } + HTMLTableCnts *Next() { return pNext; } + + inline void SetTableBox( SwTableBox *pBox ); + + void SetNoBreak() { bNoBreak = sal_True; } + + SwHTMLTableLayoutCnts *CreateLayoutInfo(); +}; + +/* */ + +// Eine Zelle der HTML-Tabelle + +class HTMLTableCell +{ + // !!!ACHTUNG!!!!! Fuer jeden neuen Pointer muss die SetProtected- + // Methode (und natuerlich der Destruktor) bearbeitet werden. + HTMLTableCnts *pContents; // der Inhalt der Zelle + SvxBrushItem *pBGBrush; // Hintergrund der Zelle + // !!!ACHTUNG!!!!! + + sal_uInt32 nNumFmt; + sal_uInt16 nRowSpan; // ROWSPAN der Zelle + sal_uInt16 nColSpan; // COLSPAN der Zelle + sal_uInt16 nWidth; // WIDTH der Zelle + double nValue; + sal_Int16 eVertOri; // vertikale Ausrichtung der Zelle + sal_Bool bProtected : 1; // Zelle darf nicht belegt werden + sal_Bool bRelWidth : 1; // nWidth ist %-Angabe + sal_Bool bHasNumFmt : 1; + sal_Bool bHasValue : 1; + sal_Bool bNoWrap : 1; + sal_Bool mbCovered : 1; + +public: + + HTMLTableCell(); // neue Zellen sind immer leer + + ~HTMLTableCell(); // nur in ~HTMLTableRow erlaubt + + // Belegen einer nicht-leeren Zelle + void Set( HTMLTableCnts *pCnts, sal_uInt16 nRSpan, sal_uInt16 nCSpan, + sal_Int16 eVertOri, SvxBrushItem *pBGBrush, + sal_Bool bHasNumFmt, sal_uInt32 nNumFmt, + sal_Bool bHasValue, double nValue, sal_Bool bNoWrap, sal_Bool bCovered ); + + // Schuetzen einer leeren 1x1-Zelle + void SetProtected(); + + // Setzen/Ermitteln des Inhalts einer Zelle + void SetContents( HTMLTableCnts *pCnts ) { pContents = pCnts; } + const HTMLTableCnts *GetContents() const { return pContents; } + HTMLTableCnts *GetContents() { return pContents; } + + // ROWSPAN/COLSPAN der Zelle Setzen/Ermitteln + void SetRowSpan( sal_uInt16 nRSpan ) { nRowSpan = nRSpan; } + sal_uInt16 GetRowSpan() const { return nRowSpan; } + + void SetColSpan( sal_uInt16 nCSpan ) { nColSpan = nCSpan; } + sal_uInt16 GetColSpan() const { return nColSpan; } + + inline void SetWidth( sal_uInt16 nWidth, sal_Bool bRelWidth ); + + const SvxBrushItem *GetBGBrush() const { return pBGBrush; } + + inline sal_Bool GetNumFmt( sal_uInt32& rNumFmt ) const; + inline sal_Bool GetValue( double& rValue ) const; + + sal_Int16 GetVertOri() const { return eVertOri; } + + // Ist die Zelle belegt oder geschuetzt? + sal_Bool IsUsed() const { return pContents!=0 || bProtected; } + + SwHTMLTableLayoutCell *CreateLayoutInfo(); + + sal_Bool IsCovered() const { return mbCovered; } +}; + +/* */ + +// Eine Zeile der HTML-Tabelle + +typedef HTMLTableCell* HTMLTableCellPtr; +SV_DECL_PTRARR_DEL(HTMLTableCells,HTMLTableCellPtr,5,5) + +class HTMLTableRow +{ + HTMLTableCells *pCells; // die Zellen der Zeile + + sal_Bool bIsEndOfGroup : 1; + sal_Bool bSplitable : 1; + + sal_uInt16 nHeight; // Optionen von <TR>/<TD> + sal_uInt16 nEmptyRows; // wieviele Leere Zeilen folgen + + SvxAdjust eAdjust; + sal_Int16 eVertOri; + SvxBrushItem *pBGBrush; // Hintergrund der Zelle aus STYLE + +public: + + sal_Bool bBottomBorder; // kommt hinter der Zeile eine Linie? + + HTMLTableRow( sal_uInt16 nCells=0 ); // die Zellen der Zeile sind leer + + ~HTMLTableRow(); + + inline void SetHeight( sal_uInt16 nHeight ); + sal_uInt16 GetHeight() const { return nHeight; } + + // Ermitteln einer Zelle + inline HTMLTableCell *GetCell( sal_uInt16 nCell ) const; + inline const HTMLTableCells *GetCells() const { return pCells; } + + + inline void SetAdjust( SvxAdjust eAdj ) { eAdjust = eAdj; } + inline SvxAdjust GetAdjust() const { return eAdjust; } + + inline void SetVertOri( sal_Int16 eV) { eVertOri = eV; } + inline sal_Int16 GetVertOri() const { return eVertOri; } + + void SetBGBrush( SvxBrushItem *pBrush ) { pBGBrush = pBrush; } + const SvxBrushItem *GetBGBrush() const { return pBGBrush; } + + inline void SetEndOfGroup() { bIsEndOfGroup = sal_True; } + inline sal_Bool IsEndOfGroup() const { return bIsEndOfGroup; } + + void IncEmptyRows() { nEmptyRows++; } + sal_uInt16 GetEmptyRows() const { return nEmptyRows; } + + // Expandieren einer Zeile durch hinzufuegen leerer Zellen + void Expand( sal_uInt16 nCells, sal_Bool bOneCell=sal_False ); + + // Verkuerzen einer Zeile durch loesen von leeren Zellen + void Shrink( sal_uInt16 nCells ); + + void SetSplitable( sal_Bool bSet ) { bSplitable = bSet; } + sal_Bool IsSplitable() const { return bSplitable; } +}; + +/* */ + +// Eine Spalte der HTML-Tabelle + +class HTMLTableColumn +{ + sal_Bool bIsEndOfGroup; + + sal_uInt16 nWidth; // Optionen von <COL> + sal_Bool bRelWidth; + + SvxAdjust eAdjust; + sal_Int16 eVertOri; + + SwFrmFmt *aFrmFmts[6]; + + inline sal_uInt16 GetFrmFmtIdx( sal_Bool bBorderLine, + sal_Int16 eVertOri ) const; + +public: + + sal_Bool bLeftBorder; // kommt vor der Spalte eine Linie + + HTMLTableColumn(); + + inline void SetWidth( sal_uInt16 nWidth, sal_Bool bRelWidth); + + inline void SetAdjust( SvxAdjust eAdj ) { eAdjust = eAdj; } + inline SvxAdjust GetAdjust() const { return eAdjust; } + + inline void SetVertOri( sal_Int16 eV) { eVertOri = eV; } + inline sal_Int16 GetVertOri() const { return eVertOri; } + + inline void SetEndOfGroup() { bIsEndOfGroup = sal_True; } + inline sal_Bool IsEndOfGroup() const { return bIsEndOfGroup; } + + inline void SetFrmFmt( SwFrmFmt *pFmt, sal_Bool bBorderLine, + sal_Int16 eVertOri ); + inline SwFrmFmt *GetFrmFmt( sal_Bool bBorderLine, + sal_Int16 eVertOri ) const; + + SwHTMLTableLayoutColumn *CreateLayoutInfo(); +}; + +/* */ + +// eine HTML-Tabelle + +typedef HTMLTableRow* HTMLTableRowPtr; +SV_DECL_PTRARR_DEL(HTMLTableRows,HTMLTableRowPtr,5,5) + +typedef HTMLTableColumn* HTMLTableColumnPtr; +SV_DECL_PTRARR_DEL(HTMLTableColumns,HTMLTableColumnPtr,5,5) + +SV_DECL_PTRARR(SdrObjects,SdrObject *,1,1) + +class HTMLTable +{ + String aId; + String aStyle; + String aClass; + String aDir; + + SdrObjects *pResizeDrawObjs;// SDR-Objekte + SvUShorts *pDrawObjPrcWidths; // Spalte des Zeichen-Objekts und dessen + // relative Breite + + HTMLTableRows *pRows; // die Zeilen der Tabelle + HTMLTableColumns *pColumns; // die Spalten der Tabelle + + sal_uInt16 nRows; // Anzahl Zeilen + sal_uInt16 nCols; // Anzahl Spalten + sal_uInt16 nFilledCols; // Anzahl tatsaechlich gefuellter Spalten + + sal_uInt16 nCurRow; // aktuelle Zeile + sal_uInt16 nCurCol; // aktuelle Spalte + + sal_uInt16 nLeftMargin; // Abstand zum linken Rand (aus Absatz) + sal_uInt16 nRightMargin; // Abstand zum rechten Rand (aus Absatz) + + sal_uInt16 nCellPadding; // Abstand Umrandung zum Text + sal_uInt16 nCellSpacing; // Abstand zwischen zwei Zellen + sal_uInt16 nHSpace; + sal_uInt16 nVSpace; + + sal_uInt16 nBoxes; // Wievele Boxen enthaelt die Tabelle + + const SwStartNode *pPrevStNd; // der Table-Node oder der Start-Node + // der vorhergehenden Section + const SwTable *pSwTable; // die SW-Tabelle (nur auf dem Top-Level) + SwTableBox *pBox1; // die TableBox, die beim Erstellen + // der Top-Level-Tabelle angelegt wird + + SwTableBoxFmt *pBoxFmt; // das frame::Frame-Format einer SwTableBox + SwTableLineFmt *pLineFmt; // das frame::Frame-Format einer SwTableLine + SwTableLineFmt *pLineFrmFmtNoHeight; + SvxBrushItem *pBGBrush; // Hintergrund der Tabelle + SvxBrushItem *pInhBGBrush; // "geerbter" Hintergrund der Tabelle + const SwStartNode *pCaptionStartNode; // Start-Node der Tabellen-Ueberschrift + + SvxBorderLine aTopBorderLine; // die Linie fuer die Umrandung + SvxBorderLine aBottomBorderLine;// die Linie fuer die Umrandung + SvxBorderLine aLeftBorderLine; // die Linie fuer die Umrandung + SvxBorderLine aRightBorderLine; // die Linie fuer die Umrandung + SvxBorderLine aBorderLine; // die Linie fuer die Umrandung + SvxBorderLine aInhLeftBorderLine; // die Linie fuer die Umrandung + SvxBorderLine aInhRightBorderLine; // die Linie fuer die Umrandung + sal_Bool bTopBorder; // besitzt die Tabelle oben eine Linie + sal_Bool bRightBorder; // besitzt die Tabelle rechts eine Linie + sal_Bool bTopAlwd; // duerfen die Raender gesetzt werden? + sal_Bool bRightAlwd; + sal_Bool bFillerTopBorder; // bekommt eine linke/rechter Filler- + sal_Bool bFillerBottomBorder; // Zelle eine obere/untere Umrandung? + sal_Bool bInhLeftBorder; + sal_Bool bInhRightBorder; + sal_Bool bBordersSet; // die Umrandung wurde bereits gesetzt + sal_Bool bForceFrame; + sal_Bool bTableAdjustOfTag; // stammt nTableAdjust aus <TABLE>? + sal_uInt32 nHeadlineRepeat; // repeating rows + sal_Bool bIsParentHead; + sal_Bool bHasParentSection; + sal_Bool bMakeTopSubTable; + sal_Bool bHasToFly; + sal_Bool bFixedCols; + sal_Bool bColSpec; // Gab es COL(GROUP)-Elemente? + sal_Bool bPrcWidth; // Breite ist eine %-Angabe + + SwHTMLParser *pParser; // der aktuelle Parser + HTMLTable *pTopTable; // die Tabelle auf dem Top-Level + HTMLTableCnts *pParentContents; + + _HTMLTableContext *pContext; // der Kontext der Tabelle + + SwHTMLTableLayout *pLayoutInfo; + + + // die folgenden Parameter stammen aus der dem <TABLE>-Tag + sal_uInt16 nWidth; // die Breite der Tabelle + sal_uInt16 nHeight; // absolute Hoehe der Tabelle + SvxAdjust eTableAdjust; // drawing::Alignment der Tabelle + sal_Int16 eVertOri; // Default vertikale Ausr. der Zellen + sal_uInt16 nBorder; // Breite der auesseren Umrandung + HTMLTableFrame eFrame; // Rahmen um die Tabelle + HTMLTableRules eRules; // Ramhen in der Tabelle + sal_Bool bTopCaption; // Ueberschrift ueber der Tabelle + + void InitCtor( const HTMLTableOptions *pOptions ); + + // Korigieren des Row-Spans fuer alle Zellen oberhalb der + // angegeben Zelle und der Zelle selbst, fuer die den anegebenen + // Inhalt besitzen. Die angegeben Zelle bekommt den Row-Span 1 + void FixRowSpan( sal_uInt16 nRow, sal_uInt16 nCol, const HTMLTableCnts *pCnts ); + + // Schuetzen der angegeben Zelle und den darunterliegenden + void ProtectRowSpan( sal_uInt16 nRow, sal_uInt16 nCol, sal_uInt16 nRowSpan ); + + // Suchen des SwStartNodes der logisch vorhergehenden Box + // bei nRow==nCell==USHRT_MAX wird der allerletzte Start-Node + // der Tabelle zurueckgegeben + const SwStartNode* GetPrevBoxStartNode( sal_uInt16 nRow, sal_uInt16 nCell ) const; + + sal_uInt16 GetTopCellSpace( sal_uInt16 nRow, sal_uInt16 nRowSpan, + sal_Bool bSwBorders=sal_True ) const; + sal_uInt16 GetBottomCellSpace( sal_uInt16 nRow, sal_uInt16 nRowSpan, + sal_Bool bSwBorders=sal_True ) const; + + // Anpassen des frame::Frame-Formates einer Box + void FixFrameFmt( SwTableBox *pBox, sal_uInt16 nRow, sal_uInt16 nCol, + sal_uInt16 nRowSpan, sal_uInt16 nColSpan, + sal_Bool bFirstPara=sal_True, sal_Bool bLastPara=sal_True ) const; + void FixFillerFrameFmt( SwTableBox *pBox, sal_Bool bRight ) const; + + // den Inhalt (Lines/Boxen) eine Tabelle erstellen + void _MakeTable( SwTableBox *pUpper=0 ); + + // Anlegen einer neuen SwTableBox, die einen SwStartNode enthaelt + SwTableBox *NewTableBox( const SwStartNode *pStNd, + SwTableLine *pUpper ) const; + + // Erstellen einer SwTableLine aus den Zellen des Rechtecks + // (nTopRow/nLeftCol) inklusive bis (nBottomRow/nRightRow) exklusive + SwTableLine *MakeTableLine( SwTableBox *pUpper, + sal_uInt16 nTopRow, sal_uInt16 nLeftCol, + sal_uInt16 nBottomRow, sal_uInt16 nRightCol ); + + // Erstellen einer SwTableBox aus dem Inhalt einer Zelle + SwTableBox *MakeTableBox( SwTableLine *pUpper, + HTMLTableCnts *pCnts, + sal_uInt16 nTopRow, sal_uInt16 nLeftCol, + sal_uInt16 nBootomRow, sal_uInt16 nRightCol ); + + // der Autolayout-Algorithmus + + // Setzen der Umrandung anhand der Vorgaben der Parent-Tabelle + void InheritBorders( const HTMLTable *pParent, + sal_uInt16 nRow, sal_uInt16 nCol, + sal_uInt16 nRowSpan, sal_uInt16 nColSpan, + sal_Bool bFirstPara, sal_Bool bLastPara ); + + // Linke und rechte Umrandung der umgebenen Tabelle erben + void InheritVertBorders( const HTMLTable *pParent, + sal_uInt16 nCol, sal_uInt16 nColSpan ); + + + // Setzen der Umrandung anhand der Benutzervorgaben + void SetBorders(); + + // wurde die Umrandung der Tabelle schon gesetzt + sal_Bool BordersSet() const { return bBordersSet; } + + const SvxBrushItem *GetBGBrush() const { return pBGBrush; } + const SvxBrushItem *GetInhBGBrush() const { return pInhBGBrush; } + + sal_uInt16 GetBorderWidth( const SvxBorderLine& rBLine, + sal_Bool bWithDistance=sal_False ) const; + +public: + + sal_Bool bFirstCell; // wurde schon eine Zelle angelegt? + + HTMLTable( SwHTMLParser* pPars, HTMLTable *pTopTab, + sal_Bool bParHead, sal_Bool bHasParentSec, + sal_Bool bTopTbl, sal_Bool bHasToFly, + const HTMLTableOptions *pOptions ); + + ~HTMLTable(); + + // Ermitteln einer Zelle + inline HTMLTableCell *GetCell( sal_uInt16 nRow, sal_uInt16 nCell ) const; + + // Ueberschrift setzen/ermitteln + inline void SetCaption( const SwStartNode *pStNd, sal_Bool bTop ); + const SwStartNode *GetCaptionStartNode() const { return pCaptionStartNode; } + sal_Bool IsTopCaption() const { return bTopCaption; } + + SvxAdjust GetTableAdjust( sal_Bool bAny ) const + { + return (bTableAdjustOfTag || bAny) ? eTableAdjust : SVX_ADJUST_END; + } + sal_Int16 GetVertOri() const { return eVertOri; } + + sal_uInt16 GetHSpace() const { return nHSpace; } + sal_uInt16 GetVSpace() const { return nVSpace; } + + sal_Bool HasPrcWidth() const { return bPrcWidth; } + sal_uInt8 GetPrcWidth() const { return bPrcWidth ? (sal_uInt8)nWidth : 0; } + + sal_uInt16 GetMinWidth() const + { + sal_uInt32 nMin = pLayoutInfo->GetMin(); + return nMin < USHRT_MAX ? (sal_uInt16)nMin : USHRT_MAX; + } + + // von Zeilen oder Spalten geerbtes drawing::Alignment holen + SvxAdjust GetInheritedAdjust() const; + sal_Int16 GetInheritedVertOri() const; + + // Einfuegen einer Zelle an der aktuellen Position + void InsertCell( HTMLTableCnts *pCnts, sal_uInt16 nRowSpan, sal_uInt16 nColSpan, + sal_uInt16 nWidth, sal_Bool bRelWidth, sal_uInt16 nHeight, + sal_Int16 eVertOri, SvxBrushItem *pBGBrush, + sal_Bool bHasNumFmt, sal_uInt32 nNumFmt, + sal_Bool bHasValue, double nValue, sal_Bool bNoWrap ); + + // Start/Ende einer neuen Zeile bekanntgeben + void OpenRow( SvxAdjust eAdjust, sal_Int16 eVertOri, + SvxBrushItem *pBGBrush ); + void CloseRow( sal_Bool bEmpty ); + + // Ende einer neuen Section bekanntgeben + inline void CloseSection( sal_Bool bHead ); + + // Ende einer Spalten-Gruppe bekanntgeben + inline void CloseColGroup( sal_uInt16 nSpan, sal_uInt16 nWidth, sal_Bool bRelWidth, + SvxAdjust eAdjust, sal_Int16 eVertOri ); + + // Einfuegen einer Spalte + void InsertCol( sal_uInt16 nSpan, sal_uInt16 nWidth, sal_Bool bRelWidth, + SvxAdjust eAdjust, sal_Int16 eVertOri ); + + // Beenden einer Tab-Definition (MUSS fuer ALLE Tabs aufgerufen werden) + void CloseTable(); + + // SwTable konstruieren (inkl. der Child-Tabellen) + void MakeTable( SwTableBox *pUpper, sal_uInt16 nAbsAvail, + sal_uInt16 nRelAvail=0, sal_uInt16 nAbsLeftSpace=0, + sal_uInt16 nAbsRightSpace=0, sal_uInt16 nInhAbsSpace=0 ); + + inline sal_Bool IsNewDoc() const { return pParser->IsNewDoc(); } + + void SetHasParentSection( sal_Bool bSet ) { bHasParentSection = bSet; } + sal_Bool HasParentSection() const { return bHasParentSection; } + + void SetParentContents( HTMLTableCnts *pCnts ) { pParentContents = pCnts; } + HTMLTableCnts *GetParentContents() const { return pParentContents; } + + void MakeParentContents(); + + sal_Bool GetIsParentHeader() const { return bIsParentHead; } + + sal_Bool IsMakeTopSubTable() const { return bMakeTopSubTable; } + void SetHasToFly() { bHasToFly=sal_True; } + sal_Bool HasToFly() const { return bHasToFly; } + + void SetTable( const SwStartNode *pStNd, _HTMLTableContext *pCntxt, + sal_uInt16 nLeft, sal_uInt16 nRight, + const SwTable *pSwTab=0, sal_Bool bFrcFrame=sal_False ); + + _HTMLTableContext *GetContext() const { return pContext; } + + SwHTMLTableLayout *CreateLayoutInfo(); + + sal_Bool HasColTags() const { return bColSpec; } + + sal_uInt16 IncGrfsThatResize() { return pSwTable ? ((SwTable *)pSwTable)->IncGrfsThatResize() : 0; } + + void RegisterDrawObject( SdrObject *pObj, sal_uInt8 nPrcWidth ); + + const SwTable *GetSwTable() const { return pSwTable; } + + void SetBGBrush( const SvxBrushItem& rBrush ) { delete pBGBrush; pBGBrush = new SvxBrushItem( rBrush ); } + + const String& GetId() const { return aId; } + const String& GetClass() const { return aClass; } + const String& GetStyle() const { return aStyle; } + const String& GetDirection() const { return aDir; } + + void IncBoxCount() { nBoxes++; } + sal_Bool IsOverflowing() const { return nBoxes > 64000; } +}; + +SV_IMPL_PTRARR(HTMLTableCells,HTMLTableCellPtr) +SV_IMPL_PTRARR(HTMLTableRows,HTMLTableRowPtr) +SV_IMPL_PTRARR(HTMLTableColumns,HTMLTableColumnPtr) + +/* */ + + +void HTMLTableCnts::InitCtor() +{ + pNext = 0; + pLayoutInfo = 0; + + bNoBreak = sal_False; +} + +HTMLTableCnts::HTMLTableCnts( const SwStartNode* pStNd ): + pStartNode(pStNd), pTable(0) +{ + InitCtor(); +} + +HTMLTableCnts::HTMLTableCnts( HTMLTable* pTab ): + pStartNode(0), pTable(pTab) +{ + InitCtor(); +} + +HTMLTableCnts::~HTMLTableCnts() +{ + delete pTable; // die Tabellen brauchen wir nicht mehr + delete pNext; +} + +void HTMLTableCnts::Add( HTMLTableCnts* pNewCnts ) +{ + HTMLTableCnts *pCnts = this; + + while( pCnts->pNext ) + pCnts = pCnts->pNext; + + pCnts->pNext = pNewCnts; +} + +inline void HTMLTableCnts::SetTableBox( SwTableBox *pBox ) +{ + ASSERT( pLayoutInfo, "Da sit noch keine Layout-Info" ); + if( pLayoutInfo ) + pLayoutInfo->SetTableBox( pBox ); +} + +SwHTMLTableLayoutCnts *HTMLTableCnts::CreateLayoutInfo() +{ + if( !pLayoutInfo ) + { + SwHTMLTableLayoutCnts *pNextInfo = pNext ? pNext->CreateLayoutInfo() : 0; + SwHTMLTableLayout *pTableInfo = pTable ? pTable->CreateLayoutInfo() : 0; + + pLayoutInfo = new SwHTMLTableLayoutCnts( pStartNode, pTableInfo, + bNoBreak, pNextInfo ); + } + + return pLayoutInfo; +} + +/* */ + +HTMLTableCell::HTMLTableCell(): + pContents(0), + pBGBrush(0), + nNumFmt(0), + nRowSpan(1), + nColSpan(1), + nWidth( 0 ), + nValue(0), + eVertOri( text::VertOrientation::NONE ), + bProtected(sal_False), + bRelWidth( sal_False ), + bHasNumFmt(sal_False), + bHasValue(sal_False), + mbCovered(sal_False) +{} + +HTMLTableCell::~HTMLTableCell() +{ + // der Inhalt ist in mehrere Zellen eingetragen, darf aber nur einmal + // geloescht werden + if( 1==nRowSpan && 1==nColSpan ) + { + delete pContents; + delete pBGBrush; + } +} + +void HTMLTableCell::Set( HTMLTableCnts *pCnts, sal_uInt16 nRSpan, sal_uInt16 nCSpan, + sal_Int16 eVert, SvxBrushItem *pBrush, + sal_Bool bHasNF, sal_uInt32 nNF, sal_Bool bHasV, double nVal, + sal_Bool bNWrap, sal_Bool bCovered ) +{ + pContents = pCnts; + nRowSpan = nRSpan; + nColSpan = nCSpan; + bProtected = sal_False; + eVertOri = eVert; + pBGBrush = pBrush; + + bHasNumFmt = bHasNF; + bHasValue = bHasV; + nNumFmt = nNF; + nValue = nVal; + + bNoWrap = bNWrap; + mbCovered = bCovered; +} + +inline void HTMLTableCell::SetWidth( sal_uInt16 nWdth, sal_Bool bRelWdth ) +{ + nWidth = nWdth; + bRelWidth = bRelWdth; +} + +void HTMLTableCell::SetProtected() +{ + // Die Inhalte dieser Zelle mussen nich irgenwo anders verankert + // sein, weil sie nicht geloescht werden!!! + + // Inhalt loeschen + pContents = 0; + + // Hintergrundfarbe kopieren. + if( pBGBrush ) + pBGBrush = new SvxBrushItem( *pBGBrush ); + + nRowSpan = 1; + nColSpan = 1; + bProtected = sal_True; +} + +inline sal_Bool HTMLTableCell::GetNumFmt( sal_uInt32& rNumFmt ) const +{ + rNumFmt = nNumFmt; + return bHasNumFmt; +} + +inline sal_Bool HTMLTableCell::GetValue( double& rValue ) const +{ + rValue = nValue; + return bHasValue; +} + +SwHTMLTableLayoutCell *HTMLTableCell::CreateLayoutInfo() +{ + SwHTMLTableLayoutCnts *pCntInfo = pContents ? pContents->CreateLayoutInfo() : 0; + + return new SwHTMLTableLayoutCell( pCntInfo, nRowSpan, nColSpan, nWidth, + bRelWidth, bNoWrap ); +} + +/* */ + +HTMLTableRow::HTMLTableRow( sal_uInt16 nCells ): + pCells(new HTMLTableCells), + bIsEndOfGroup(sal_False), + bSplitable( sal_False ), + nHeight(0), + nEmptyRows(0), + eAdjust(SVX_ADJUST_END), + eVertOri(text::VertOrientation::TOP), + pBGBrush(0), + bBottomBorder(sal_False) +{ + for( sal_uInt16 i=0; i<nCells; i++ ) + { + pCells->Insert( new HTMLTableCell, pCells->Count() ); + } + + ASSERT( nCells==pCells->Count(), + "Zellenzahl in neuer HTML-Tabellenzeile stimmt nicht" ); +} + +HTMLTableRow::~HTMLTableRow() +{ + delete pCells; + delete pBGBrush; +} + +inline void HTMLTableRow::SetHeight( sal_uInt16 nHght ) +{ + if( nHght > nHeight ) + nHeight = nHght; +} + +inline HTMLTableCell *HTMLTableRow::GetCell( sal_uInt16 nCell ) const +{ + ASSERT( nCell<pCells->Count(), + "ungueltiger Zellen-Index in HTML-Tabellenzeile" ); + return (*pCells)[nCell]; +} + +void HTMLTableRow::Expand( sal_uInt16 nCells, sal_Bool bOneCell ) +{ + // die Zeile wird mit einer einzigen Zelle aufgefuellt, wenn + // bOneCell gesetzt ist. Das geht, nur fuer Zeilen, in die keine + // Zellen mehr eingefuegt werden! + + sal_uInt16 nColSpan = nCells-pCells->Count(); + for( sal_uInt16 i=pCells->Count(); i<nCells; i++ ) + { + HTMLTableCell *pCell = new HTMLTableCell; + if( bOneCell ) + pCell->SetColSpan( nColSpan ); + + pCells->Insert( pCell, pCells->Count() ); + nColSpan--; + } + + ASSERT( nCells==pCells->Count(), + "Zellenzahl in expandierter HTML-Tabellenzeile stimmt nicht" ); +} + +void HTMLTableRow::Shrink( sal_uInt16 nCells ) +{ + ASSERT( nCells < pCells->Count(), "Anzahl Zellen falsch" ); + +#ifdef DBG_UTIL + sal_uInt16 nEnd = pCells->Count(); +#endif + // The colspan of empty cells at the end has to be fixed to the new + // number of cells. + sal_uInt16 i=nCells; + while( i ) + { + HTMLTableCell *pCell = (*pCells)[--i]; + if( !pCell->GetContents() ) + { + ASSERT( pCell->GetColSpan() == nEnd - i, + "invalid col span for empty cell at row end" ); + pCell->SetColSpan( nCells-i); + } + else + break; + } +#ifdef DBG_UTIL + for( i=nCells; i<nEnd; i++ ) + { + HTMLTableCell *pCell = (*pCells)[i]; + ASSERT( pCell->GetRowSpan() == 1, + "RowSpan von zu loesender Zelle ist falsch" ); + ASSERT( pCell->GetColSpan() == nEnd - i, + "ColSpan von zu loesender Zelle ist falsch" ); + ASSERT( !pCell->GetContents(), "Zu loeschende Zelle hat Inhalt" ); + } +#endif + + pCells->DeleteAndDestroy( nCells, pCells->Count()-nCells ); +} + +/* */ + +HTMLTableColumn::HTMLTableColumn(): + bIsEndOfGroup(sal_False), + nWidth(0), bRelWidth(sal_False), + eAdjust(SVX_ADJUST_END), eVertOri(text::VertOrientation::TOP), + bLeftBorder(sal_False) +{ + for( sal_uInt16 i=0; i<6; i++ ) + aFrmFmts[i] = 0; +} + +inline void HTMLTableColumn::SetWidth( sal_uInt16 nWdth, sal_Bool bRelWdth ) +{ + if( bRelWidth==bRelWdth ) + { + if( nWdth > nWidth ) + nWidth = nWdth; + } + else + nWidth = nWdth; + bRelWidth = bRelWdth; +} + +inline SwHTMLTableLayoutColumn *HTMLTableColumn::CreateLayoutInfo() +{ + return new SwHTMLTableLayoutColumn( nWidth, bRelWidth, bLeftBorder ); +} + +inline sal_uInt16 HTMLTableColumn::GetFrmFmtIdx( sal_Bool bBorderLine, + sal_Int16 eVertOrient ) const +{ + ASSERT( text::VertOrientation::TOP != eVertOrient, "Top ist nicht erlaubt" ); + sal_uInt16 n = bBorderLine ? 3 : 0; + switch( eVertOrient ) + { + case text::VertOrientation::CENTER: n+=1; break; + case text::VertOrientation::BOTTOM: n+=2; break; + default: + ; + } + return n; +} + +inline void HTMLTableColumn::SetFrmFmt( SwFrmFmt *pFmt, sal_Bool bBorderLine, + sal_Int16 eVertOrient ) +{ + aFrmFmts[GetFrmFmtIdx(bBorderLine,eVertOrient)] = pFmt; +} + +inline SwFrmFmt *HTMLTableColumn::GetFrmFmt( sal_Bool bBorderLine, + sal_Int16 eVertOrient ) const +{ + return aFrmFmts[GetFrmFmtIdx(bBorderLine,eVertOrient)]; +} + +/* */ + + +void HTMLTable::InitCtor( const HTMLTableOptions *pOptions ) +{ + pResizeDrawObjs = 0; + pDrawObjPrcWidths = 0; + + pRows = new HTMLTableRows; + pColumns = new HTMLTableColumns; + nRows = 0; + nCurRow = 0; nCurCol = 0; + + pBox1 = 0; + pBoxFmt = 0; pLineFmt = 0; + pLineFrmFmtNoHeight = 0; + pInhBGBrush = 0; + + pPrevStNd = 0; + pSwTable = 0; + + bTopBorder = sal_False; bRightBorder = sal_False; + bTopAlwd = sal_True; bRightAlwd = sal_True; + bFillerTopBorder = sal_False; bFillerBottomBorder = sal_False; + bInhLeftBorder = sal_False; bInhRightBorder = sal_False; + bBordersSet = sal_False; + bForceFrame = sal_False; + nHeadlineRepeat = 0; + + nLeftMargin = 0; + nRightMargin = 0; + + const Color& rBorderColor = pOptions->aBorderColor; + + long nBorderOpt = (long)pOptions->nBorder; + long nPWidth = nBorderOpt==USHRT_MAX ? NETSCAPE_DFLT_BORDER + : nBorderOpt; + long nPHeight = nBorderOpt==USHRT_MAX ? 0 : nBorderOpt; + SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight ); + + // nBorder gibt die Breite der Umrandung an, wie sie in die + // Breitenberechnung in Netscape einfliesst. Wenn pOption->nBorder + // == USHRT_MAX, wurde keine BORDER-Option angegeben. Trotzdem fliesst + // eine 1 Pixel breite Umrandung in die Breitenberechnung mit ein. + nBorder = (sal_uInt16)nPWidth; + if( nBorderOpt==USHRT_MAX ) + nPWidth = 0; + + // HACK: ein Pixel-breite Linien sollen zur Haarlinie werden, wenn + // wir mit doppelter Umrandung arbeiten + if( pOptions->nCellSpacing!=0 && nBorderOpt==1 ) + { + nPWidth = 1; + nPHeight = 1; + } + + SvxCSS1Parser::SetBorderWidth( aTopBorderLine, (sal_uInt16)nPHeight, + pOptions->nCellSpacing!=0, sal_True ); + aTopBorderLine.SetColor( rBorderColor ); + aBottomBorderLine = aTopBorderLine; + + if( nPWidth == nPHeight ) + { + aLeftBorderLine = aTopBorderLine; + } + else + { + SvxCSS1Parser::SetBorderWidth( aLeftBorderLine, (sal_uInt16)nPWidth, + pOptions->nCellSpacing!=0, sal_True ); + aLeftBorderLine.SetColor( rBorderColor ); + } + aRightBorderLine = aLeftBorderLine; + + if( pOptions->nCellSpacing != 0 ) + { + aBorderLine.SetOutWidth( DEF_DOUBLE_LINE7_OUT ); + aBorderLine.SetInWidth( DEF_DOUBLE_LINE7_IN ); + aBorderLine.SetDistance( DEF_DOUBLE_LINE7_DIST ); + } + else + { + aBorderLine.SetOutWidth( DEF_LINE_WIDTH_1 ); + } + aBorderLine.SetColor( rBorderColor ); + + if( nCellPadding ) + { + if( nCellPadding==USHRT_MAX ) + nCellPadding = MIN_BORDER_DIST; // default + else + { + nCellPadding = pParser->ToTwips( nCellPadding ); + if( nCellPadding<MIN_BORDER_DIST ) + nCellPadding = MIN_BORDER_DIST; + } + } + if( nCellSpacing ) + { + if( nCellSpacing==USHRT_MAX ) + nCellSpacing = NETSCAPE_DFLT_CELLSPACING; + nCellSpacing = pParser->ToTwips( nCellSpacing ); + } + + nPWidth = pOptions->nHSpace; + nPHeight = pOptions->nVSpace; + SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight ); + nHSpace = (sal_uInt16)nPWidth; + nVSpace = (sal_uInt16)nPHeight; + + bColSpec = sal_False; + + pBGBrush = pParser->CreateBrushItem( + pOptions->bBGColor ? &(pOptions->aBGColor) : 0, + pOptions->aBGImage, aEmptyStr, aEmptyStr, aEmptyStr ); + + pContext = 0; + pParentContents = 0; + + aId = pOptions->aId; + aClass = pOptions->aClass; + aStyle = pOptions->aStyle; + aDir = pOptions->aDir; +} + +HTMLTable::HTMLTable( SwHTMLParser* pPars, HTMLTable *pTopTab, + sal_Bool bParHead, + sal_Bool bHasParentSec, sal_Bool bTopTbl, sal_Bool bHasToFlw, + const HTMLTableOptions *pOptions ) : + nCols( pOptions->nCols ), + nFilledCols( 0 ), + nCellPadding( pOptions->nCellPadding ), + nCellSpacing( pOptions->nCellSpacing ), + nBoxes( 1 ), + pCaptionStartNode( 0 ), + bTableAdjustOfTag( pTopTab ? sal_False : pOptions->bTableAdjust ), + bIsParentHead( bParHead ), + bHasParentSection( bHasParentSec ), + bMakeTopSubTable( bTopTbl ), + bHasToFly( bHasToFlw ), + bFixedCols( pOptions->nCols>0 ), + bPrcWidth( pOptions->bPrcWidth ), + pParser( pPars ), + pTopTable( pTopTab ? pTopTab : this ), + pLayoutInfo( 0 ), + nWidth( pOptions->nWidth ), + nHeight( pTopTab ? 0 : pOptions->nHeight ), + eTableAdjust( pOptions->eAdjust ), + eVertOri( pOptions->eVertOri ), + eFrame( pOptions->eFrame ), + eRules( pOptions->eRules ), + bTopCaption( sal_False ), + bFirstCell( !pTopTab ) +{ + InitCtor( pOptions ); + + for( sal_uInt16 i=0; i<nCols; i++ ) + pColumns->Insert( new HTMLTableColumn, pColumns->Count() ); +} + + +HTMLTable::~HTMLTable() +{ + delete pResizeDrawObjs; + delete pDrawObjPrcWidths; + + delete pRows; + delete pColumns; + delete pBGBrush; + delete pInhBGBrush; + + delete pContext; + + // pLayoutInfo wurde entweder bereits geloescht oder muss aber es + // in den Besitz der SwTable uebergegangen. +} + +SwHTMLTableLayout *HTMLTable::CreateLayoutInfo() +{ + sal_uInt16 nW = bPrcWidth ? nWidth : pParser->ToTwips( nWidth ); + + sal_uInt16 nBorderWidth = GetBorderWidth( aBorderLine, sal_True ); + sal_uInt16 nLeftBorderWidth = + ((*pColumns)[0])->bLeftBorder ? GetBorderWidth( aLeftBorderLine, sal_True ) : 0; + sal_uInt16 nRightBorderWidth = + bRightBorder ? GetBorderWidth( aRightBorderLine, sal_True ) : 0; + sal_uInt16 nInhLeftBorderWidth = 0; + sal_uInt16 nInhRightBorderWidth = 0; + + pLayoutInfo = new SwHTMLTableLayout( + pSwTable, + nRows, nCols, bFixedCols, bColSpec, + nW, bPrcWidth, nBorder, nCellPadding, + nCellSpacing, eTableAdjust, + nLeftMargin, nRightMargin, + nBorderWidth, nLeftBorderWidth, nRightBorderWidth, + nInhLeftBorderWidth, nInhRightBorderWidth ); + + sal_Bool bExportable = sal_True; + sal_uInt16 i; + for( i=0; i<nRows; i++ ) + { + HTMLTableRow *pRow = (*pRows)[i]; + for( sal_uInt16 j=0; j<nCols; j++ ) + { + SwHTMLTableLayoutCell *pLayoutCell = + pRow->GetCell(j)->CreateLayoutInfo(); + + pLayoutInfo->SetCell( pLayoutCell, i, j ); + + if( bExportable ) + { + SwHTMLTableLayoutCnts *pLayoutCnts = + pLayoutCell->GetContents(); + bExportable = !pLayoutCnts || + ( pLayoutCnts->GetStartNode() && + !pLayoutCnts->GetNext() ); + } + } + } + + pLayoutInfo->SetExportable( bExportable ); + + for( i=0; i<nCols; i++ ) + pLayoutInfo->SetColumn( ((*pColumns)[i])->CreateLayoutInfo(), i ); + + return pLayoutInfo; +} + +inline void HTMLTable::SetCaption( const SwStartNode *pStNd, sal_Bool bTop ) +{ + pCaptionStartNode = pStNd; + bTopCaption = bTop; +} + +void HTMLTable::FixRowSpan( sal_uInt16 nRow, sal_uInt16 nCol, + const HTMLTableCnts *pCnts ) +{ + sal_uInt16 nRowSpan=1; + HTMLTableCell *pCell; + while( ( pCell=GetCell(nRow,nCol), pCell->GetContents()==pCnts ) ) + { + pCell->SetRowSpan( nRowSpan ); + if( pLayoutInfo ) + pLayoutInfo->GetCell(nRow,nCol)->SetRowSpan( nRowSpan ); + + if( !nRow ) break; + nRowSpan++; nRow--; + } +} + +void HTMLTable::ProtectRowSpan( sal_uInt16 nRow, sal_uInt16 nCol, sal_uInt16 nRowSpan ) +{ + for( sal_uInt16 i=0; i<nRowSpan; i++ ) + { + GetCell(nRow+i,nCol)->SetProtected(); + if( pLayoutInfo ) + pLayoutInfo->GetCell(nRow+i,nCol)->SetProtected(); + } +} + + +// Suchen des SwStartNodes der letzten belegten Vorgaengerbox +const SwStartNode* HTMLTable::GetPrevBoxStartNode( sal_uInt16 nRow, sal_uInt16 nCol ) const +{ + const HTMLTableCnts *pPrevCnts = 0; + + if( 0==nRow ) + { + // immer die Vorgaenger-Zelle + if( nCol>0 ) + pPrevCnts = GetCell( 0, nCol-1 )->GetContents(); + else + return pPrevStNd; + } + else if( USHRT_MAX==nRow && USHRT_MAX==nCol ) + // der Contents der letzten Zelle + pPrevCnts = GetCell( nRows-1, nCols-1 )->GetContents(); + else + { + sal_uInt16 i; + HTMLTableRow *pPrevRow = (*pRows)[nRow-1]; + + // evtl. eine Zelle in der aktuellen Zeile + i = nCol; + while( i ) + { + i--; + if( 1 == pPrevRow->GetCell(i)->GetRowSpan() ) + { + pPrevCnts = GetCell(nRow,i)->GetContents(); + break; + } + } + + // sonst die letzte gefuellte Zelle der Zeile davor suchen + if( !pPrevCnts ) + { + i = nCols; + while( !pPrevCnts && i ) + { + i--; + pPrevCnts = pPrevRow->GetCell(i)->GetContents(); + } + } + } + ASSERT( pPrevCnts, "keine gefuellte Vorgaenger-Zelle gefunden" ); + if( !pPrevCnts ) + { + pPrevCnts = GetCell(0,0)->GetContents(); + if( !pPrevCnts ) + return pPrevStNd; + } + + while( pPrevCnts->Next() ) + pPrevCnts = pPrevCnts->Next(); + + return ( pPrevCnts->GetStartNode() ? pPrevCnts->GetStartNode() + : pPrevCnts->GetTable()->GetPrevBoxStartNode( USHRT_MAX, USHRT_MAX ) ); +} + + +static sal_Bool IsBoxEmpty( const SwTableBox *pBox ) +{ + const SwStartNode *pSttNd = pBox->GetSttNd(); + if( pSttNd && + pSttNd->GetIndex() + 2 == pSttNd->EndOfSectionIndex() ) + { + const SwCntntNode *pCNd = + pSttNd->GetNodes()[pSttNd->GetIndex()+1]->GetCntntNode(); + if( pCNd && !pCNd->Len() ) + return sal_True; + } + + return sal_False; +} + +sal_uInt16 HTMLTable::GetTopCellSpace( sal_uInt16 nRow, sal_uInt16 nRowSpan, + sal_Bool bSwBorders ) const +{ + sal_uInt16 nSpace = nCellPadding; + + if( nRow == 0 ) + { + nSpace += nBorder + nCellSpacing; + if( bSwBorders ) + { + sal_uInt16 nTopBorderWidth = + GetBorderWidth( aTopBorderLine, sal_True ); + if( nSpace < nTopBorderWidth ) + nSpace = nTopBorderWidth; + } + } + else if( bSwBorders && ((*pRows)[nRow+nRowSpan-1])->bBottomBorder && + nSpace < MIN_BORDER_DIST ) + { + ASSERT( !nCellPadding, "GetTopCellSpace: CELLPADDING!=0" ); + // Wenn die Gegenueberliegende Seite umrandet ist muessen + // wir zumindest den minimalen Abstand zum Inhalt + // beruecksichtigen. (Koennte man zusaetzlich auch an + // nCellPadding festmachen.) + nSpace = MIN_BORDER_DIST; + } + + return nSpace; +} + +sal_uInt16 HTMLTable::GetBottomCellSpace( sal_uInt16 nRow, sal_uInt16 nRowSpan, + sal_Bool bSwBorders ) const +{ + sal_uInt16 nSpace = nCellSpacing + nCellPadding; + + if( nRow+nRowSpan == nRows ) + { + nSpace = nSpace + nBorder; + + if( bSwBorders ) + { + sal_uInt16 nBottomBorderWidth = + GetBorderWidth( aBottomBorderLine, sal_True ); + if( nSpace < nBottomBorderWidth ) + nSpace = nBottomBorderWidth; + } + } + else if( bSwBorders ) + { + if( ((*pRows)[nRow+nRowSpan+1])->bBottomBorder ) + { + sal_uInt16 nBorderWidth = GetBorderWidth( aBorderLine, sal_True ); + if( nSpace < nBorderWidth ) + nSpace = nBorderWidth; + } + else if( nRow==0 && bTopBorder && nSpace < MIN_BORDER_DIST ) + { + ASSERT( GetBorderWidth( aTopBorderLine, sal_True ) > 0, + "GetBottomCellSpace: |aTopLine| == 0" ); + ASSERT( !nCellPadding, "GetBottomCellSpace: CELLPADDING!=0" ); + // Wenn die Gegenueberliegende Seite umrandet ist muessen + // wir zumindest den minimalen Abstand zum Inhalt + // beruecksichtigen. (Koennte man zusaetzlich auch an + // nCellPadding festmachen.) + nSpace = MIN_BORDER_DIST; + } + } + + return nSpace; +} + +void HTMLTable::FixFrameFmt( SwTableBox *pBox, + sal_uInt16 nRow, sal_uInt16 nCol, + sal_uInt16 nRowSpan, sal_uInt16 nColSpan, + sal_Bool bFirstPara, sal_Bool bLastPara ) const +{ + SwFrmFmt *pFrmFmt = 0; // frame::Frame-Format + sal_Int16 eVOri = text::VertOrientation::NONE; + const SvxBrushItem *pBGBrushItem = 0; // Hintergrund + sal_Bool bTopLine = sal_False, bBottomLine = sal_False, bLastBottomLine = sal_False; + sal_Bool bReUsable = sal_False; // Format nochmals verwendbar? + sal_uInt16 nEmptyRows = 0; + sal_Bool bHasNumFmt = sal_False; + sal_Bool bHasValue = sal_False; + sal_uInt32 nNumFmt = 0; + double nValue = 0.0; + + HTMLTableColumn *pColumn = (*pColumns)[nCol]; + + if( pBox->GetSttNd() ) + { + // die Hintergrundfarbe/-grafik bestimmen + const HTMLTableCell *pCell = GetCell( nRow, nCol ); + pBGBrushItem = pCell->GetBGBrush(); + if( !pBGBrushItem ) + { + // Wenn die Zelle ueber mehrere Zeilen geht muss ein evtl. + // an der Zeile gesetzter Hintergrund an die Zelle uebernommen + // werden. +#ifndef FIX56334 + // Wenn es sich um eine Tabelle in der Tabelle handelt und + // die Zelle ueber die gesamte Heoehe der Tabelle geht muss + // ebenfalls der Hintergrund der Zeile uebernommen werden, weil + // die Line von der GC (zu Recht) wegoptimiert wird. + if( nRowSpan > 1 || (this != pTopTable && nRowSpan==nRows) ) +#else + if( nRowSpan > 1 ) +#endif + { + pBGBrushItem = ((*pRows)[nRow])->GetBGBrush(); + if( !pBGBrushItem && this != pTopTable ) + { + pBGBrushItem = GetBGBrush(); + if( !pBGBrushItem ) + pBGBrushItem = GetInhBGBrush(); + } + } + } + + bTopLine = 0==nRow && bTopBorder && bFirstPara; + if( ((*pRows)[nRow+nRowSpan-1])->bBottomBorder && bLastPara ) + { + nEmptyRows = ((*pRows)[nRow+nRowSpan-1])->GetEmptyRows(); + if( nRow+nRowSpan == nRows ) + bLastBottomLine = sal_True; + else + bBottomLine = sal_True; + } + + eVOri = pCell->GetVertOri(); + bHasNumFmt = pCell->GetNumFmt( nNumFmt ); + if( bHasNumFmt ) + bHasValue = pCell->GetValue( nValue ); + + if( nColSpan==1 && !bTopLine && !bLastBottomLine && !nEmptyRows && + !pBGBrushItem && !bHasNumFmt ) + { + pFrmFmt = pColumn->GetFrmFmt( bBottomLine, eVOri ); + bReUsable = !pFrmFmt; + } + } + + if( !pFrmFmt ) + { + pFrmFmt = pBox->ClaimFrmFmt(); + + // die Breite der Box berechnen + SwTwips nFrmWidth = (SwTwips)pLayoutInfo->GetColumn(nCol) + ->GetRelColWidth(); + for( sal_uInt16 i=1; i<nColSpan; i++ ) + nFrmWidth += (SwTwips)pLayoutInfo->GetColumn(nCol+i) + ->GetRelColWidth(); + + // die Umrandung nur an Edit-Boxen setzen (bei der oberen und unteren + // Umrandung muss beruecks. werden, ob es sich um den ersten oder + // letzen Absatz der Zelle handelt) + if( pBox->GetSttNd() ) + { + sal_Bool bSet = (nCellPadding > 0); + + SvxBoxItem aBoxItem( RES_BOX ); + long nInnerFrmWidth = nFrmWidth; + + if( bTopLine ) + { + aBoxItem.SetLine( &aTopBorderLine, BOX_LINE_TOP ); + bSet = sal_True; + } + if( bLastBottomLine ) + { + aBoxItem.SetLine( &aBottomBorderLine, BOX_LINE_BOTTOM ); + bSet = sal_True; + } + else if( bBottomLine ) + { + if( nEmptyRows && !aBorderLine.GetInWidth() ) + { + // Leere Zeilen koennen zur Zeit nur dann ueber + // dicke Linien simuliert werden, wenn die Linie + // einfach ist. + SvxBorderLine aThickBorderLine( aBorderLine ); + + sal_uInt16 nBorderWidth = aBorderLine.GetOutWidth(); + nBorderWidth *= (nEmptyRows + 1); + SvxCSS1Parser::SetBorderWidth( aThickBorderLine, + nBorderWidth, sal_False ); + aBoxItem.SetLine( &aThickBorderLine, BOX_LINE_BOTTOM ); + } + else + { + aBoxItem.SetLine( &aBorderLine, BOX_LINE_BOTTOM ); + } + bSet = sal_True; + } + if( ((*pColumns)[nCol])->bLeftBorder ) + { + const SvxBorderLine& rBorderLine = + 0==nCol ? aLeftBorderLine : aBorderLine; + aBoxItem.SetLine( &rBorderLine, BOX_LINE_LEFT ); + nInnerFrmWidth -= GetBorderWidth( rBorderLine ); + bSet = sal_True; + } + if( nCol+nColSpan == nCols && bRightBorder ) + { + aBoxItem.SetLine( &aRightBorderLine, BOX_LINE_RIGHT ); + nInnerFrmWidth -= GetBorderWidth( aRightBorderLine ); + bSet = sal_True; + } + + if( bSet ) + { + // fix #30588#: BorderDist nicht mehr Bestandteil + // einer Zelle mit fixer Breite + sal_uInt16 nBDist = static_cast< sal_uInt16 >( + (2*nCellPadding <= nInnerFrmWidth) ? nCellPadding + : (nInnerFrmWidth / 2) ); + // wir setzen das Item nur, wenn es eine Umrandung gibt + // oder eine sheet::Border-Distanz vorgegeben ist. Fehlt letztere, + // dann gibt es eine Umrandung, und wir muessen die Distanz + // setzen + aBoxItem.SetDistance( nBDist ? nBDist : MIN_BORDER_DIST ); + pFrmFmt->SetFmtAttr( aBoxItem ); + } + else + pFrmFmt->ResetFmtAttr( RES_BOX ); + + if( pBGBrushItem ) + { + pFrmFmt->SetFmtAttr( *pBGBrushItem ); + } + else + pFrmFmt->ResetFmtAttr( RES_BACKGROUND ); + + // fix #41003#: Format nur setzten, wenn es auch einen Value + // gibt oder die Box leer ist. + if( bHasNumFmt && (bHasValue || IsBoxEmpty(pBox)) ) + { + sal_Bool bLock = pFrmFmt->GetDoc()->GetNumberFormatter() + ->IsTextFormat( nNumFmt ); + SfxItemSet aItemSet( *pFrmFmt->GetAttrSet().GetPool(), + RES_BOXATR_FORMAT, RES_BOXATR_VALUE ); + SvxAdjust eAdjust = SVX_ADJUST_END; + SwCntntNode *pCNd = 0; + if( !bLock ) + { + const SwStartNode *pSttNd = pBox->GetSttNd(); + pCNd = pSttNd->GetNodes()[pSttNd->GetIndex()+1] + ->GetCntntNode(); + const SfxPoolItem *pItem; + if( pCNd && pCNd->HasSwAttrSet() && + SFX_ITEM_SET==pCNd->GetpSwAttrSet()->GetItemState( + RES_PARATR_ADJUST, sal_False, &pItem ) ) + { + eAdjust = ((const SvxAdjustItem *)pItem) + ->GetAdjust(); + } + } + aItemSet.Put( SwTblBoxNumFormat(nNumFmt) ); + if( bHasValue ) + aItemSet.Put( SwTblBoxValue(nValue) ); + + if( bLock ) + pFrmFmt->LockModify(); + pFrmFmt->SetFmtAttr( aItemSet ); + if( bLock ) + pFrmFmt->UnlockModify(); + else if( pCNd && SVX_ADJUST_END != eAdjust ) + { + SvxAdjustItem aAdjItem( eAdjust, RES_PARATR_ADJUST ); + pCNd->SetAttr( aAdjItem ); + } + } + else + pFrmFmt->ResetFmtAttr( RES_BOXATR_FORMAT ); + + ASSERT( eVOri != text::VertOrientation::TOP, "text::VertOrientation::TOP ist nicht erlaubt!" ); + if( text::VertOrientation::NONE != eVOri ) + { + pFrmFmt->SetFmtAttr( SwFmtVertOrient( 0, eVOri ) ); + } + else + pFrmFmt->ResetFmtAttr( RES_VERT_ORIENT ); + + if( bReUsable ) + pColumn->SetFrmFmt( pFrmFmt, bBottomLine, eVOri ); + } + else + { + pFrmFmt->ResetFmtAttr( RES_BOX ); + pFrmFmt->ResetFmtAttr( RES_BACKGROUND ); + pFrmFmt->ResetFmtAttr( RES_VERT_ORIENT ); + pFrmFmt->ResetFmtAttr( RES_BOXATR_FORMAT ); + } + } + else + { + ASSERT( pBox->GetSttNd() || + SFX_ITEM_SET!=pFrmFmt->GetAttrSet().GetItemState( + RES_VERT_ORIENT, sal_False ), + "Box ohne Inhalt hat vertikale Ausrichtung" ); + pBox->ChgFrmFmt( (SwTableBoxFmt*)pFrmFmt ); + } + +} + +void HTMLTable::FixFillerFrameFmt( SwTableBox *pBox, sal_Bool bRight ) const +{ + SwFrmFmt *pFrmFmt = pBox->ClaimFrmFmt(); + + if( bFillerTopBorder || bFillerBottomBorder || + (!bRight && bInhLeftBorder) || (bRight && bInhRightBorder) ) + { + SvxBoxItem aBoxItem( RES_BOX ); + if( bFillerTopBorder ) + aBoxItem.SetLine( &aTopBorderLine, BOX_LINE_TOP ); + if( bFillerBottomBorder ) + aBoxItem.SetLine( &aBottomBorderLine, BOX_LINE_BOTTOM ); + if( !bRight && bInhLeftBorder ) + aBoxItem.SetLine( &aInhLeftBorderLine, BOX_LINE_LEFT ); + if( bRight && bInhRightBorder ) + aBoxItem.SetLine( &aInhRightBorderLine, BOX_LINE_RIGHT ); + aBoxItem.SetDistance( MIN_BORDER_DIST ); + pFrmFmt->SetFmtAttr( aBoxItem ); + } + else + { + pFrmFmt->ResetFmtAttr( RES_BOX ); + } + + if( GetInhBGBrush() ) + pFrmFmt->SetFmtAttr( *GetInhBGBrush() ); + else + pFrmFmt->ResetFmtAttr( RES_BACKGROUND ); + + pFrmFmt->ResetFmtAttr( RES_VERT_ORIENT ); + pFrmFmt->ResetFmtAttr( RES_BOXATR_FORMAT ); +} + +SwTableBox *HTMLTable::NewTableBox( const SwStartNode *pStNd, + SwTableLine *pUpper ) const +{ + SwTableBox *pBox; + + if( pTopTable->pBox1 && + pTopTable->pBox1->GetSttNd() == pStNd ) + { + // wenn der StartNode dem StartNode der initial angelegten Box + // entspricht nehmen wir diese Box + pBox = pTopTable->pBox1; + pBox->SetUpper( pUpper ); + pTopTable->pBox1 = 0; + } + else + pBox = new SwTableBox( pBoxFmt, *pStNd, pUpper ); + + return pBox; +} + + +static void ResetLineFrmFmtAttrs( SwFrmFmt *pFrmFmt ) +{ + pFrmFmt->ResetFmtAttr( RES_FRM_SIZE ); + pFrmFmt->ResetFmtAttr( RES_BACKGROUND ); + ASSERT( SFX_ITEM_SET!=pFrmFmt->GetAttrSet().GetItemState( + RES_VERT_ORIENT, sal_False ), + "Zeile hat vertikale Ausrichtung" ); +} + +// !!! kann noch vereinfacht werden +SwTableLine *HTMLTable::MakeTableLine( SwTableBox *pUpper, + sal_uInt16 nTopRow, sal_uInt16 nLeftCol, + sal_uInt16 nBottomRow, sal_uInt16 nRightCol ) +{ + SwTableLine *pLine; + if( this==pTopTable && !pUpper && 0==nTopRow ) + pLine = (pSwTable->GetTabLines())[0]; + else + pLine = new SwTableLine( pLineFrmFmtNoHeight ? pLineFrmFmtNoHeight + : pLineFmt, + 0, pUpper ); + + HTMLTableRow *pTopRow = (*pRows)[nTopRow]; + sal_uInt16 nRowHeight = pTopRow->GetHeight(); + const SvxBrushItem *pBGBrushItem = 0; +#ifndef FIX56334 + if( this == pTopTable || nTopRow>0 || nBottomRow<nRows ) + { + // An der Line eine Frabe zu setzen macht keinen Sinn, wenn sie + // die auesserste und gleichzeitig einzige Zeile einer Tabelle in + // der Tabelle ist. +#endif + pBGBrushItem = pTopRow->GetBGBrush(); + + if( !pBGBrushItem && this != pTopTable ) + { + // Ein an einer Tabellen in der Tabelle gesetzter Hintergrund + // wird an den Rows gesetzt. Das gilt auch fuer den Hintergrund + // der Zelle, in dem die Tabelle vorkommt. + pBGBrushItem = GetBGBrush(); + if( !pBGBrushItem ) + pBGBrushItem = GetInhBGBrush(); + } +#ifndef FIX56334 + } +#endif + if( nTopRow==nBottomRow-1 && (nRowHeight || pBGBrushItem) ) + { + SwTableLineFmt *pFrmFmt = (SwTableLineFmt*)pLine->ClaimFrmFmt(); + ResetLineFrmFmtAttrs( pFrmFmt ); + + if( nRowHeight ) + { + // Tabellenhoehe einstellen. Da es sich um eine + // Mindesthoehe handelt, kann sie genauso wie in + // Netscape berechnet werden, also ohne Beruecksichtigung + // der tatsaechlichen Umrandungsbreite. + nRowHeight += GetTopCellSpace( nTopRow, 1, sal_False ) + + GetBottomCellSpace( nTopRow, 1, sal_False ); + + pFrmFmt->SetFmtAttr( SwFmtFrmSize( ATT_MIN_SIZE, 0, nRowHeight ) ); + } + + if( pBGBrushItem ) + { + pFrmFmt->SetFmtAttr( *pBGBrushItem ); + } + + } + else if( !pLineFrmFmtNoHeight ) + { + // sonst muessen wir die Hoehe aus dem Attribut entfernen + // und koennen uns das Format merken + pLineFrmFmtNoHeight = (SwTableLineFmt*)pLine->ClaimFrmFmt(); + + ResetLineFrmFmtAttrs( pLineFrmFmtNoHeight ); + } + + + SwTableBoxes& rBoxes = pLine->GetTabBoxes(); + + sal_uInt16 nStartCol = nLeftCol; + while( nStartCol<nRightCol ) + { + sal_uInt16 nCol = nStartCol; + sal_uInt16 nSplitCol = nRightCol; + sal_Bool bSplitted = sal_False; + while( !bSplitted ) + { + ASSERT( nCol < nRightCol, "Zu weit gelaufen" ); + + HTMLTableCell *pCell = GetCell(nTopRow,nCol); + const sal_Bool bSplit = 1 == pCell->GetColSpan(); + +#ifdef DBG_UTIL + if( nCol == nRightCol-1 ) + { + ASSERT( bSplit, "Split-Flag falsch" ); + } +#endif + if( bSplit ) + { + SwTableBox* pBox = 0; + HTMLTableCell *pCell2 = GetCell( nTopRow, nStartCol ); + if( pCell2->GetColSpan() == (nCol+1-nStartCol) ) + { + // Die HTML-Tabellen-Zellen bilden genau eine Box. + // Dann muss hinter der Box gesplittet werden + nSplitCol = nCol + 1; + + long nBoxRowSpan = pCell2->GetRowSpan(); + if ( !pCell2->GetContents() || pCell2->IsCovered() ) + { + if ( pCell2->IsCovered() ) + nBoxRowSpan = -1 * nBoxRowSpan; + + const SwStartNode* pPrevStartNd = + GetPrevBoxStartNode( nTopRow, nStartCol ); + HTMLTableCnts *pCnts = new HTMLTableCnts( + pParser->InsertTableSection(pPrevStartNd) ); + SwHTMLTableLayoutCnts *pCntsLayoutInfo = + pCnts->CreateLayoutInfo(); + + pCell2->SetContents( pCnts ); + SwHTMLTableLayoutCell *pCurrCell = pLayoutInfo->GetCell( nTopRow, nStartCol ); + pCurrCell->SetContents( pCntsLayoutInfo ); + if( nBoxRowSpan < 0 ) + pCurrCell->SetRowSpan( 0 ); + + // ggf. COLSPAN beachten + for( sal_uInt16 j=nStartCol+1; j<nSplitCol; j++ ) + { + GetCell(nTopRow,j)->SetContents( pCnts ); + pLayoutInfo->GetCell( nTopRow, j ) + ->SetContents( pCntsLayoutInfo ); + } + } + + pBox = MakeTableBox( pLine, pCell2->GetContents(), + nTopRow, nStartCol, + nBottomRow, nSplitCol ); + + if ( 1 != nBoxRowSpan ) + pBox->setRowSpan( nBoxRowSpan ); + + bSplitted = sal_True; + } + + ASSERT( pBox, "Colspan trouble" ) + + if( pBox ) + rBoxes.C40_INSERT( SwTableBox, pBox, rBoxes.Count() ); + } + nCol++; + } + nStartCol = nSplitCol; + } + + return pLine; +} + +SwTableBox *HTMLTable::MakeTableBox( SwTableLine *pUpper, + HTMLTableCnts *pCnts, + sal_uInt16 nTopRow, sal_uInt16 nLeftCol, + sal_uInt16 nBottomRow, sal_uInt16 nRightCol ) +{ + SwTableBox *pBox; + sal_uInt16 nColSpan = nRightCol - nLeftCol; + sal_uInt16 nRowSpan = nBottomRow - nTopRow; + + if( !pCnts->Next() ) + { + // nur eine Inhalts-Section + if( pCnts->GetStartNode() ) + { + // und die ist keine Tabelle + pBox = NewTableBox( pCnts->GetStartNode(), pUpper ); + pCnts->SetTableBox( pBox ); + } + else + { + pCnts->GetTable()->InheritVertBorders( this, nLeftCol, + nRightCol-nLeftCol ); + // und die ist eine Tabelle: dann bauen wir eine neue + // Box und fuegen die Zeilen der Tabelle in die Zeilen + // der Box ein + pBox = new SwTableBox( pBoxFmt, 0, pUpper ); + sal_uInt16 nAbs, nRel; + pLayoutInfo->GetAvail( nLeftCol, nColSpan, nAbs, nRel ); + sal_uInt16 nLSpace = pLayoutInfo->GetLeftCellSpace( nLeftCol, nColSpan ); + sal_uInt16 nRSpace = pLayoutInfo->GetRightCellSpace( nLeftCol, nColSpan ); + sal_uInt16 nInhSpace = pLayoutInfo->GetInhCellSpace( nLeftCol, nColSpan ); + pCnts->GetTable()->MakeTable( pBox, nAbs, nRel, nLSpace, nRSpace, + nInhSpace ); + } + } + else + { + // mehrere Inhalts Sections: dann brauchen wir eine Box mit Zeilen + pBox = new SwTableBox( pBoxFmt, 0, pUpper ); + SwTableLines& rLines = pBox->GetTabLines(); + sal_Bool bFirstPara = sal_True; + + while( pCnts ) + { + if( pCnts->GetStartNode() ) + { + // normale Absaetze werden zu einer Box in einer Zeile + SwTableLine *pLine = + new SwTableLine( pLineFrmFmtNoHeight ? pLineFrmFmtNoHeight + : pLineFmt, 0, pBox ); + if( !pLineFrmFmtNoHeight ) + { + // Wenn es noch kein Line-Format ohne Hoehe gibt, koennen + // wir uns dieses her als soleches merken + pLineFrmFmtNoHeight = (SwTableLineFmt*)pLine->ClaimFrmFmt(); + + ResetLineFrmFmtAttrs( pLineFrmFmtNoHeight ); + } + + SwTableBox* pCntBox = NewTableBox( pCnts->GetStartNode(), + pLine ); + pCnts->SetTableBox( pCntBox ); + FixFrameFmt( pCntBox, nTopRow, nLeftCol, nRowSpan, nColSpan, + bFirstPara, 0==pCnts->Next() ); + pLine->GetTabBoxes().C40_INSERT( SwTableBox, pCntBox, + pLine->GetTabBoxes().Count() ); + + rLines.C40_INSERT( SwTableLine, pLine, rLines.Count() ); + } + else + { + pCnts->GetTable()->InheritVertBorders( this, nLeftCol, + nRightCol-nLeftCol ); + // Tabellen werden direkt eingetragen + sal_uInt16 nAbs, nRel; + pLayoutInfo->GetAvail( nLeftCol, nColSpan, nAbs, nRel ); + sal_uInt16 nLSpace = pLayoutInfo->GetLeftCellSpace( nLeftCol, + nColSpan ); + sal_uInt16 nRSpace = pLayoutInfo->GetRightCellSpace( nLeftCol, + nColSpan ); + sal_uInt16 nInhSpace = pLayoutInfo->GetInhCellSpace( nLeftCol, nColSpan ); + pCnts->GetTable()->MakeTable( pBox, nAbs, nRel, nLSpace, + nRSpace, nInhSpace ); + } + + pCnts = pCnts->Next(); + bFirstPara = sal_False; + } + } + + FixFrameFmt( pBox, nTopRow, nLeftCol, nRowSpan, nColSpan ); + + return pBox; +} + +void HTMLTable::InheritBorders( const HTMLTable *pParent, + sal_uInt16 nRow, sal_uInt16 nCol, + sal_uInt16 nRowSpan, sal_uInt16 /*nColSpan*/, + sal_Bool bFirstPara, sal_Bool bLastPara ) +{ + ASSERT( nRows>0 && nCols>0 && nCurRow==nRows, + "Wurde CloseTable nicht aufgerufen?" ); + + // Die Child-Tabelle muss einen Rahmen bekommen, wenn die umgebende + // Zelle einen Rand an der betreffenden Seite besitzt. + // Der obere bzw. untere Rand wird nur gesetzt, wenn die Tabelle + // ale erster bzw. letzter Absatz in der Zelle vorkommt. Ansonsten + // Fuer den linken/rechten Rand kann noch nicht entschieden werden, + // ob eine Umrandung der Tabelle noetig/moeglich ist, weil das davon + // abhaengt, ob "Filler"-Zellen eingefuegt werden. Hier werden deshalb + // erstmal nur Informationen gesammelt + // + if( 0==nRow && pParent->bTopBorder && bFirstPara ) + { + bTopBorder = sal_True; + bFillerTopBorder = sal_True; // auch Filler bekommt eine Umrandung + aTopBorderLine = pParent->aTopBorderLine; + } + if( ((*pParent->pRows)[nRow+nRowSpan-1])->bBottomBorder && bLastPara ) + { + ((*pRows)[nRows-1])->bBottomBorder = sal_True; + bFillerBottomBorder = sal_True; // auch Filler bekommt eine Umrandung + aBottomBorderLine = + nRow+nRowSpan==pParent->nRows ? pParent->aBottomBorderLine + : pParent->aBorderLine; + } + + + // Die Child Tabelle darf keinen oberen oder linken Rahmen bekommen, + // wenn der bereits durch die umgebende Tabelle gesetzt ist. + // Sie darf jedoch immer einen oberen Rand bekommen, wenn die Tabelle + // nicht der erste Absatz in der Zelle ist. + bTopAlwd = ( !bFirstPara || (pParent->bTopAlwd && + (0==nRow || !((*pParent->pRows)[nRow-1])->bBottomBorder)) ); + + // die Child-Tabelle muss die Farbe der Zelle erben, in der sie + // vorkommt, wenn sie keine eigene besitzt + const SvxBrushItem *pInhBG = pParent->GetCell(nRow,nCol)->GetBGBrush(); + if( !pInhBG && pParent != pTopTable && + pParent->GetCell(nRow,nCol)->GetRowSpan() == pParent->nRows ) + { + // die ganze umgebende Tabelle ist eine Tabelle in der Tabelle + // und besteht nur aus einer Line, die bei der GC (zu Recht) + // wegoptimiert wird. Deshalb muss der Hintergrund der Line in + // diese Tabelle uebernommen werden. + pInhBG = ((*pParent->pRows)[nRow])->GetBGBrush(); + if( !pInhBG ) + pInhBG = pParent->GetBGBrush(); + if( !pInhBG ) + pInhBG = pParent->GetInhBGBrush(); + } + if( pInhBG ) + pInhBGBrush = new SvxBrushItem( *pInhBG ); +} + +void HTMLTable::InheritVertBorders( const HTMLTable *pParent, + sal_uInt16 nCol, sal_uInt16 nColSpan ) +{ + sal_uInt16 nInhLeftBorderWidth = 0; + sal_uInt16 nInhRightBorderWidth = 0; + + if( nCol+nColSpan==pParent->nCols && pParent->bRightBorder ) + { + bInhRightBorder = sal_True; // erstmal nur merken + aInhRightBorderLine = pParent->aRightBorderLine; + nInhRightBorderWidth = + GetBorderWidth( aInhRightBorderLine, sal_True ) + MIN_BORDER_DIST; + } + + if( ((*pParent->pColumns)[nCol])->bLeftBorder ) + { + bInhLeftBorder = sal_True; // erstmal nur merken + aInhLeftBorderLine = 0==nCol ? pParent->aLeftBorderLine + : pParent->aBorderLine; + nInhLeftBorderWidth = + GetBorderWidth( aInhLeftBorderLine, sal_True ) + MIN_BORDER_DIST; + } + + if( !bInhLeftBorder && (bFillerTopBorder || bFillerBottomBorder) ) + nInhLeftBorderWidth = 2 * MIN_BORDER_DIST; + if( !bInhRightBorder && (bFillerTopBorder || bFillerBottomBorder) ) + nInhRightBorderWidth = 2 * MIN_BORDER_DIST; + pLayoutInfo->SetInhBorderWidths( nInhLeftBorderWidth, + nInhRightBorderWidth ); + + bRightAlwd = ( pParent->bRightAlwd && + (nCol+nColSpan==pParent->nCols || + !((*pParent->pColumns)[nCol+nColSpan])->bLeftBorder) ); +} + +void HTMLTable::SetBorders() +{ + sal_uInt16 i; + for( i=1; i<nCols; i++ ) + if( HTML_TR_ALL==eRules || HTML_TR_COLS==eRules || + ((HTML_TR_ROWS==eRules || HTML_TR_GROUPS==eRules) && + ((*pColumns)[i-1])->IsEndOfGroup()) ) + ((*pColumns)[i])->bLeftBorder = sal_True; + + for( i=0; i<nRows-1; i++ ) + if( HTML_TR_ALL==eRules || HTML_TR_ROWS==eRules || + ((HTML_TR_COLS==eRules || HTML_TR_GROUPS==eRules) && + ((*pRows)[i])->IsEndOfGroup()) ) + ((*pRows)[i])->bBottomBorder = sal_True; + + if( bTopAlwd && (HTML_TF_ABOVE==eFrame || HTML_TF_HSIDES==eFrame || + HTML_TF_BOX==eFrame) ) + bTopBorder = sal_True; + if( HTML_TF_BELOW==eFrame || HTML_TF_HSIDES==eFrame || + HTML_TF_BOX==eFrame ) + ((*pRows)[nRows-1])->bBottomBorder = sal_True; + if( /*bRightAlwd &&*/ (HTML_TF_RHS==eFrame || HTML_TF_VSIDES==eFrame || + HTML_TF_BOX==eFrame) ) + bRightBorder = sal_True; + if( HTML_TF_LHS==eFrame || HTML_TF_VSIDES==eFrame || HTML_TF_BOX==eFrame ) + ((*pColumns)[0])->bLeftBorder = sal_True; + + for( i=0; i<nRows; i++ ) + { + HTMLTableRow *pRow = (*pRows)[i]; + for( sal_uInt16 j=0; j<nCols; j++ ) + { + HTMLTableCell *pCell = pRow->GetCell(j); + if( pCell->GetContents() ) + { + HTMLTableCnts *pCnts = pCell->GetContents(); + sal_Bool bFirstPara = sal_True; + while( pCnts ) + { + HTMLTable *pTable = pCnts->GetTable(); + if( pTable && !pTable->BordersSet() ) + { + pTable->InheritBorders( this, i, j, + pCell->GetRowSpan(), + pCell->GetColSpan(), + bFirstPara, + 0==pCnts->Next() ); + pTable->SetBorders(); + } + bFirstPara = sal_False; + pCnts = pCnts->Next(); + } + } + } + } + + bBordersSet = sal_True; +} + +sal_uInt16 HTMLTable::GetBorderWidth( const SvxBorderLine& rBLine, + sal_Bool bWithDistance ) const +{ + sal_uInt16 nBorderWidth = rBLine.GetOutWidth() + rBLine.GetInWidth() + + rBLine.GetDistance(); + if( bWithDistance ) + { + if( nCellPadding ) + nBorderWidth = nBorderWidth + nCellPadding; + else if( nBorderWidth ) + nBorderWidth = nBorderWidth + MIN_BORDER_DIST; + } + + return nBorderWidth; +} + +inline HTMLTableCell *HTMLTable::GetCell( sal_uInt16 nRow, + sal_uInt16 nCell ) const +{ + ASSERT( nRow<pRows->Count(), + "ungueltiger Zeilen-Index in HTML-Tabelle" ); + return ((*pRows)[nRow])->GetCell( nCell ); +} + + + +SvxAdjust HTMLTable::GetInheritedAdjust() const +{ + SvxAdjust eAdjust = (nCurCol<nCols ? ((*pColumns)[nCurCol])->GetAdjust() + : SVX_ADJUST_END ); + if( SVX_ADJUST_END==eAdjust ) + eAdjust = ((*pRows)[nCurRow])->GetAdjust(); + + return eAdjust; +} + +sal_Int16 HTMLTable::GetInheritedVertOri() const +{ + // text::VertOrientation::TOP ist der default! + sal_Int16 eVOri = ((*pRows)[nCurRow])->GetVertOri(); + if( text::VertOrientation::TOP==eVOri && nCurCol<nCols ) + eVOri = ((*pColumns)[nCurCol])->GetVertOri(); + if( text::VertOrientation::TOP==eVOri ) + eVOri = eVertOri; + + ASSERT( eVertOri != text::VertOrientation::TOP, "text::VertOrientation::TOP ist nicht erlaubt!" ); + return eVOri; +} + +void HTMLTable::InsertCell( HTMLTableCnts *pCnts, + sal_uInt16 nRowSpan, sal_uInt16 nColSpan, + sal_uInt16 nCellWidth, sal_Bool bRelWidth, sal_uInt16 nCellHeight, + sal_Int16 eVertOrient, SvxBrushItem *pBGBrushItem, + sal_Bool bHasNumFmt, sal_uInt32 nNumFmt, + sal_Bool bHasValue, double nValue, sal_Bool bNoWrap ) +{ + if( !nRowSpan || (sal_uInt32)nCurRow + nRowSpan > USHRT_MAX ) + nRowSpan = 1; + + if( !nColSpan || (sal_uInt32)nCurCol + nColSpan > USHRT_MAX ) + nColSpan = 1; + + sal_uInt16 nColsReq = nCurCol + nColSpan; // benoetigte Spalten + sal_uInt16 nRowsReq = nCurRow + nRowSpan; // benoetigte Zeilen + sal_uInt16 i, j; + + // falls wir mehr Spalten benoetigen als wir zur Zeit haben, + // muessen wir in allen Zeilen noch Zellen hinzufuegen + if( nCols < nColsReq ) + { + for( i=nCols; i<nColsReq; i++ ) + pColumns->Insert( new HTMLTableColumn, pColumns->Count() ); + for( i=0; i<nRows; i++ ) + ((*pRows)[i])->Expand( nColsReq, i<nCurRow ); + nCols = nColsReq; + ASSERT( pColumns->Count()==nCols, + "Anzahl der Spalten nach Expandieren stimmt nicht" ); + } + if( nColsReq > nFilledCols ) + nFilledCols = nColsReq; + + // falls wir mehr Zeilen benoetigen als wir zur Zeit haben, + // muessen wir noch neue Zeilen hinzufuegen + if( nRows < nRowsReq ) + { + for( i=nRows; i<nRowsReq; i++ ) + pRows->Insert( new HTMLTableRow(nCols), pRows->Count() ); + nRows = nRowsReq; + ASSERT( nRows==pRows->Count(), "Zeilenzahl in Insert stimmt nicht" ); + } + + // Testen, ob eine Ueberschneidung vorliegt und diese + // gegebenfalls beseitigen + sal_uInt16 nSpanedCols = 0; + if( nCurRow>0 ) + { + HTMLTableRow *pCurRow = (*pRows)[nCurRow]; + for( i=nCurCol; i<nColsReq; i++ ) + { + HTMLTableCell *pCell = pCurRow->GetCell(i); + if( pCell->GetContents() ) + { + // Der Inhalt reicht von einer weiter oben stehenden Zelle + // hier herein. Inhalt und Farbe der Zelle sind deshalb in + // jedem Fall noch dort verankert und koennen deshalb + // ueberschrieben werden bzw. von ProtectRowSpan geloescht + // (Inhalt) oder kopiert (Farbe) werden. + nSpanedCols = i + pCell->GetColSpan(); + FixRowSpan( nCurRow-1, i, pCell->GetContents() ); + if( pCell->GetRowSpan() > nRowSpan ) + ProtectRowSpan( nRowsReq, i, + pCell->GetRowSpan()-nRowSpan ); + } + } + for( i=nColsReq; i<nSpanedCols; i++ ) + { + // Auch diese Inhalte sind in jedem Fall nich in der Zeile + // darueber verankert. + HTMLTableCell *pCell = pCurRow->GetCell(i); + FixRowSpan( nCurRow-1, i, pCell->GetContents() ); + ProtectRowSpan( nCurRow, i, pCell->GetRowSpan() ); + } + } + + // Fill the cells + for( i=nColSpan; i>0; i-- ) + { + for( j=nRowSpan; j>0; j-- ) + { + const bool bCovered = i != nColSpan || j != nRowSpan; + GetCell( nRowsReq-j, nColsReq-i ) + ->Set( pCnts, j, i, eVertOrient, pBGBrushItem, + bHasNumFmt, nNumFmt, bHasValue, nValue, bNoWrap, bCovered ); + } + } + + Size aTwipSz( bRelWidth ? 0 : nCellWidth, nCellHeight ); + if( (aTwipSz.Width() || aTwipSz.Height()) && Application::GetDefaultDevice() ) + { + aTwipSz = Application::GetDefaultDevice() + ->PixelToLogic( aTwipSz, MapMode( MAP_TWIP ) ); + } + + // die Breite nur in die erste Zelle setzen! + if( nCellWidth ) + { + sal_uInt16 nTmp = bRelWidth ? nCellWidth : (sal_uInt16)aTwipSz.Width(); + GetCell( nCurRow, nCurCol )->SetWidth( nTmp, bRelWidth ); + } + + // Ausserdem noch die Hoehe merken + if( nCellHeight && 1==nRowSpan ) + { + if( nCellHeight < MINLAY ) + nCellHeight = MINLAY; + ((*pRows)[nCurRow])->SetHeight( (sal_uInt16)aTwipSz.Height() ); + } + + // den Spaltenzaehler hinter die neuen Zellen setzen + nCurCol = nColsReq; + if( nSpanedCols > nCurCol ) + nCurCol = nSpanedCols; + + // und die naechste freie Zelle suchen + while( nCurCol<nCols && GetCell(nCurRow,nCurCol)->IsUsed() ) + nCurCol++; +} + +inline void HTMLTable::CloseSection( sal_Bool bHead ) +{ + // die vorhergende Section beenden, falls es schon eine Zeile gibt + ASSERT( nCurRow<=nRows, "ungeultige aktuelle Zeile" ); + if( nCurRow>0 && nCurRow<=nRows ) + ((*pRows)[nCurRow-1])->SetEndOfGroup(); + if( bHead /*&& nCurRow==1*/ ) +// bHeadlineRepeat = sal_True; + nHeadlineRepeat = nCurRow; +} + +void HTMLTable::OpenRow( SvxAdjust eAdjust, sal_Int16 eVertOrient, + SvxBrushItem *pBGBrushItem ) +{ + sal_uInt16 nRowsReq = nCurRow+1; // Anzahl benoetigter Zeilen; + + // die naechste Zeile anlegen, falls sie nicht schon da ist + if( nRows<nRowsReq ) + { + for( sal_uInt16 i=nRows; i<nRowsReq; i++ ) + pRows->Insert( new HTMLTableRow(nCols), pRows->Count() ); + nRows = nRowsReq; + ASSERT( nRows==pRows->Count(), + "Zeilenzahl in OpenRow stimmt nicht" ); + } + + HTMLTableRow *pCurRow = ((*pRows)[nCurRow]); + pCurRow->SetAdjust( eAdjust ); + pCurRow->SetVertOri( eVertOrient ); + if( pBGBrushItem ) + ((*pRows)[nCurRow])->SetBGBrush( pBGBrushItem ); + + // den Spaltenzaehler wieder an den Anfang setzen + nCurCol=0; + + // und die naechste freie Zelle suchen + while( nCurCol<nCols && GetCell(nCurRow,nCurCol)->IsUsed() ) + nCurCol++; +} + +void HTMLTable::CloseRow( sal_Bool bEmpty ) +{ + ASSERT( nCurRow<nRows, "aktulle Zeile hinter dem Tabellenende" ); + + // leere Zellen bekommen einfach einen etwas dickeren unteren Rand! + if( bEmpty ) + { + if( nCurRow > 0 ) + ((*pRows)[nCurRow-1])->IncEmptyRows(); + return; + } + + HTMLTableRow *pRow = (*pRows)[nCurRow]; + + // den COLSPAN aller leeren Zellen am Zeilenende so anpassen, dass + // eine Zelle daraus wird. Das kann man hier machen (und auf keinen + // Fall frueher), weill jetzt keine Zellen mehr in die Zeile eingefuegt + // werden. + sal_uInt16 i=nCols; + while( i ) + { + HTMLTableCell *pCell = pRow->GetCell(--i); + if( !pCell->GetContents() ) + { + sal_uInt16 nColSpan = nCols-i; + if( nColSpan > 1 ) + pCell->SetColSpan( nColSpan ); + } + else + break; + } + + + nCurRow++; +} + +inline void HTMLTable::CloseColGroup( sal_uInt16 nSpan, sal_uInt16 _nWidth, + sal_Bool bRelWidth, SvxAdjust eAdjust, + sal_Int16 eVertOrient ) +{ + if( nSpan ) + InsertCol( nSpan, _nWidth, bRelWidth, eAdjust, eVertOrient ); + + ASSERT( nCurCol<=nCols, "ungueltige Spalte" ); + if( nCurCol>0 && nCurCol<=nCols ) + ((*pColumns)[nCurCol-1])->SetEndOfGroup(); +} + +void HTMLTable::InsertCol( sal_uInt16 nSpan, sal_uInt16 nColWidth, sal_Bool bRelWidth, + SvxAdjust eAdjust, sal_Int16 eVertOrient ) +{ + // --> OD, MIB 2004-11-08 #i35143# - no columns, if rows already exist. + if ( nRows > 0 ) + return; + // <-- + + sal_uInt16 i; + + if( !nSpan ) + nSpan = 1; + + sal_uInt16 nColsReq = nCurCol + nSpan; // benoetigte Spalten + + if( nCols < nColsReq ) + { + for( i=nCols; i<nColsReq; i++ ) + pColumns->Insert( new HTMLTableColumn, pColumns->Count() ); + nCols = nColsReq; + } + + Size aTwipSz( bRelWidth ? 0 : nColWidth, 0 ); + if( aTwipSz.Width() && Application::GetDefaultDevice() ) + { + aTwipSz = Application::GetDefaultDevice() + ->PixelToLogic( aTwipSz, MapMode( MAP_TWIP ) ); + } + + for( i=nCurCol; i<nColsReq; i++ ) + { + HTMLTableColumn *pCol = (*pColumns)[i]; + sal_uInt16 nTmp = bRelWidth ? nColWidth : (sal_uInt16)aTwipSz.Width(); + pCol->SetWidth( nTmp, bRelWidth ); + pCol->SetAdjust( eAdjust ); + pCol->SetVertOri( eVertOrient ); + } + + bColSpec = sal_True; + + nCurCol = nColsReq; +} + + +void HTMLTable::CloseTable() +{ + sal_uInt16 i; + + // Die Anzahl der Tabellenzeilen richtet sich nur nach den + // <TR>-Elementen (d.h. nach nCurRow). Durch ROWSPAN aufgespannte + // Zeilen hinter Zeile nCurRow muessen wir deshalb loeschen + // und vor allem aber den ROWSPAN in den darueberliegenden Zeilen + // anpassen. + if( nRows>nCurRow ) + { + HTMLTableRow *pPrevRow = (*pRows)[nCurRow-1]; + HTMLTableCell *pCell; + for( i=0; i<nCols; i++ ) + if( ( pCell=pPrevRow->GetCell(i), pCell->GetRowSpan() > 1 ) ) + { + FixRowSpan( nCurRow-1, i, pCell->GetContents() ); + ProtectRowSpan( nCurRow, i, (*pRows)[nCurRow]->GetCell(i)->GetRowSpan() ); + } + for( i=nRows-1; i>=nCurRow; i-- ) + pRows->DeleteAndDestroy(i); + nRows = nCurRow; + } + + // falls die Tabelle keine Spalte hat, muessen wir eine hinzufuegen + if( 0==nCols ) + { + pColumns->Insert( new HTMLTableColumn, pColumns->Count() ); + for( i=0; i<nRows; i++ ) + ((*pRows)[i])->Expand(1); + nCols = 1; + nFilledCols = 1; + } + + // falls die Tabelle keine Zeile hat, muessen wir eine hinzufuegen + if( 0==nRows ) + { + pRows->Insert( new HTMLTableRow(nCols), pRows->Count() ); + nRows = 1; + nCurRow = 1; + } + + if( nFilledCols < nCols ) + { + pColumns->DeleteAndDestroy( nFilledCols, nCols-nFilledCols ); + for( i=0; i<nRows; i++ ) + ((*pRows)[i])->Shrink( nFilledCols ); + nCols = nFilledCols; + } +} + +void HTMLTable::_MakeTable( SwTableBox *pBox ) +{ + SwTableLines& rLines = (pBox ? pBox->GetTabLines() + : ((SwTable *)pSwTable)->GetTabLines() ); + + // jetzt geht's richtig los ... + + for( sal_uInt16 i=0; i<nRows; i++ ) + { + SwTableLine *pLine = MakeTableLine( pBox, i, 0, i+1, nCols ); + if( pBox || i > 0 ) + rLines.C40_INSERT( SwTableLine, pLine, rLines.Count() ); + } +} + +/* Wie werden Tabellen ausgerichtet? + +erste Zeile: ohne Absatz-Einzuege +zweite Zeile: mit Absatz-Einzuegen + +ALIGN= LEFT RIGHT CENTER - +------------------------------------------------------------------------- +xxx bei Tabellen mit WIDTH=nn% ist die Prozent-Angabe von Bedeutung: +xxx nn = 100 text::HoriOrientation::FULL text::HoriOrientation::FULL text::HoriOrientation::FULL text::HoriOrientation::FULL % +xxx text::HoriOrientation::NONE text::HoriOrientation::NONE text::HoriOrientation::NONE % text::HoriOrientation::NONE % +xxx nn < 100 Rahmen F Rahmen F text::HoriOrientation::CENTER % text::HoriOrientation::LEFT % +xxx Rahmen F Rahmen F text::HoriOrientation::CENTER % text::HoriOrientation::NONE % + +bei Tabellen mit WIDTH=nn% ist die Prozent-Angabe von Bedeutung: +nn = 100 text::HoriOrientation::LEFT text::HoriOrientation::RIGHT text::HoriOrientation::CENTER % text::HoriOrientation::LEFT % + text::HoriOrientation::LEFT_AND text::HoriOrientation::RIGHT text::HoriOrientation::CENTER % text::HoriOrientation::LEFT_AND % +nn < 100 Rahmen F Rahmen F text::HoriOrientation::CENTER % text::HoriOrientation::LEFT % + Rahmen F Rahmen F text::HoriOrientation::CENTER % text::HoriOrientation::NONE % + +sonst die berechnete Breite w +w = avail* text::HoriOrientation::LEFT text::HoriOrientation::RIGHT text::HoriOrientation::CENTER text::HoriOrientation::LEFT + HORI_LEDT_AND text::HoriOrientation::RIGHT text::HoriOrientation::CENTER text::HoriOrientation::LEFT_AND +w < avail Rahmen L Rahmen L text::HoriOrientation::CENTER text::HoriOrientation::LEFT + Rahmen L Rahmen L text::HoriOrientation::CENTER text::HoriOrientation::NONE + +xxx *) wenn fuer die Tabelle keine Groesse angegeben wurde, wird immer +xxx text::HoriOrientation::FULL genommen + +*/ + +void HTMLTable::MakeTable( SwTableBox *pBox, sal_uInt16 nAbsAvail, + sal_uInt16 nRelAvail, sal_uInt16 nAbsLeftSpace, + sal_uInt16 nAbsRightSpace, sal_uInt16 nInhAbsSpace ) +{ + ASSERT( nRows>0 && nCols>0 && nCurRow==nRows, + "Wurde CloseTable nicht aufgerufen?" ); + + ASSERT( (pLayoutInfo==0) == (this==pTopTable), + "Top-Tabelle hat keine Layout-Info oder umgekehrt" ); + + if( this==pTopTable ) + { + // Umrandung der Tabelle und aller in ihr enthaltenen berechnen + SetBorders(); + + // Schritt 1: Die benoetigten Layout-Strukturen werden angelegt + // (inklusive Tabellen in Tabellen). + CreateLayoutInfo(); + + // Schritt 2: Die minimalen und maximalen Spaltenbreiten werden + // berechnet (inklusive Tabellen in Tabellen). Da wir noch keine + // Boxen haben, arabeiten wir noch auf den Start-Nodes. + pLayoutInfo->AutoLayoutPass1(); + } + + // Schritt 3: Die tatsaechlichen Spaltenbreiten dieser Tabelle werden + // berechnet (nicht von Tabellen in Tabellen). Dies muss jetzt schon + // sein, damit wir entscheiden koennen ob Filler-Zellen benoetigt werden + // oder nicht (deshalb war auch Pass1 schon noetig). + pLayoutInfo->AutoLayoutPass2( nAbsAvail, nRelAvail, nAbsLeftSpace, + nAbsRightSpace, nInhAbsSpace ); + + if( this!=pTopTable ) + { + // die linke und rechte Umrandung der Tabelle kann jetzt entgueltig + // festgelegt werden + if( pLayoutInfo->GetRelRightFill() == 0 ) + { + if( !bRightBorder ) + { + // linke Umrandung von auesserer Tabelle uebernehmen + if( bInhRightBorder ) + { + bRightBorder = sal_True; + aRightBorderLine = aInhRightBorderLine; + } + } + else + { + // Umrandung nur setzen, wenn es erlaubt ist + bRightBorder = bRightAlwd; + } + } + + if( pLayoutInfo->GetRelLeftFill() == 0 && + !((*pColumns)[0])->bLeftBorder && + bInhLeftBorder ) + { + // ggf. rechte Umrandung von auesserer Tabelle uebernehmen + ((*pColumns)[0])->bLeftBorder = sal_True; + aLeftBorderLine = aInhLeftBorderLine; + } + } + + // Fuer die Top-Table muss die Ausrichtung gesetzt werden + if( this==pTopTable ) + { + sal_Int16 eHoriOri; + if( bForceFrame ) + { + // Die Tabelle soll in einen Rahmen und ist auch schmaler + // als der verfuegbare Platz und nicht 100% breit. + // Dann kommt sie in einen Rahmen + eHoriOri = bPrcWidth ? text::HoriOrientation::FULL : text::HoriOrientation::LEFT; + } + else switch( eTableAdjust ) + { + // Die Tabelle passt entweder auf die Seite, soll aber in keinen + // Rahmen oder sie ist Breiter als die Seite und soll deshalb + // in keinen Rahmen + + case SVX_ADJUST_RIGHT: + // in rechtsbuendigen Tabellen kann nicht auf den rechten + // Rand Ruecksicht genommen werden + eHoriOri = text::HoriOrientation::RIGHT; + break; + case SVX_ADJUST_CENTER: + // zentrierte Tabellen nehmen keine Ruecksicht auf Raender! + eHoriOri = text::HoriOrientation::CENTER; + break; + case SVX_ADJUST_LEFT: + default: + // linksbuendige Tabellen nehmen nur auf den linken Rand + // Ruecksicht + eHoriOri = nLeftMargin ? text::HoriOrientation::LEFT_AND_WIDTH : text::HoriOrientation::LEFT; + break; + } + + // das Tabellenform holen und anpassen + SwFrmFmt *pFrmFmt = pSwTable->GetFrmFmt(); + pFrmFmt->SetFmtAttr( SwFmtHoriOrient(0,eHoriOri) ); + if( text::HoriOrientation::LEFT_AND_WIDTH==eHoriOri ) + { + ASSERT( nLeftMargin || nRightMargin, + "Da gibt's wohl noch Reste von relativen Breiten" ); + + // The right margin will be ignored anyway. + SvxLRSpaceItem aLRItem( pSwTable->GetFrmFmt()->GetLRSpace() ); + aLRItem.SetLeft( nLeftMargin ); + aLRItem.SetRight( nRightMargin ); + pFrmFmt->SetFmtAttr( aLRItem ); + } + + if( bPrcWidth && text::HoriOrientation::FULL!=eHoriOri ) + { + pFrmFmt->LockModify(); + SwFmtFrmSize aFrmSize( pFrmFmt->GetFrmSize() ); + aFrmSize.SetWidthPercent( (sal_uInt8)nWidth ); + pFrmFmt->SetFmtAttr( aFrmSize ); + pFrmFmt->UnlockModify(); + } + } + + // die Default Line- und Box-Formate holen + if( this==pTopTable ) + { + // die erste Box merken und aus der ersten Zeile ausketten + SwTableLine *pLine1 = (pSwTable->GetTabLines())[0]; + pBox1 = (pLine1->GetTabBoxes())[0]; + pLine1->GetTabBoxes().Remove(0); + + pLineFmt = (SwTableLineFmt*)pLine1->GetFrmFmt(); + pBoxFmt = (SwTableBoxFmt*)pBox1->GetFrmFmt(); + } + else + { + pLineFmt = (SwTableLineFmt*)pTopTable->pLineFmt; + pBoxFmt = (SwTableBoxFmt*)pTopTable->pBoxFmt; + } + + // ggf. muessen fuer Tabellen in Tabellen "Filler"-Zellen eingefuegt + // werden + if( this != pTopTable && + ( pLayoutInfo->GetRelLeftFill() > 0 || + pLayoutInfo->GetRelRightFill() > 0 ) ) + { + ASSERT( pBox, "kein TableBox fuer Tabelle in Tabelle" ); + + SwTableLines& rLines = pBox->GetTabLines(); + + // dazu brauchen wir erstmal ein eine neue Table-Line in der Box + SwTableLine *pLine = + new SwTableLine( pLineFrmFmtNoHeight ? pLineFrmFmtNoHeight + : pLineFmt, 0, pBox ); + rLines.C40_INSERT( SwTableLine, pLine, rLines.Count() ); + + // Sicherstellen, dass wie ein Format ohne Hoehe erwischt haben + if( !pLineFrmFmtNoHeight ) + { + // sonst muessen wir die Hoehe aus dem Attribut entfernen + // und koennen uns das Format merken + pLineFrmFmtNoHeight = (SwTableLineFmt*)pLine->ClaimFrmFmt(); + + ResetLineFrmFmtAttrs( pLineFrmFmtNoHeight ); + } + + SwTableBoxes& rBoxes = pLine->GetTabBoxes(); + SwTableBox *pNewBox; + + // ggf. links eine Zelle einfuegen + if( pLayoutInfo->GetRelLeftFill() > 0 ) + { + // pPrevStNd ist der Vorgaenger-Start-Node der Tabelle. Den + // "Filler"-Node fuegen wir einfach dahinter ein ... + pPrevStNd = pParser->InsertTableSection( pPrevStNd ); + + pNewBox = NewTableBox( pPrevStNd, pLine ); + rBoxes.C40_INSERT( SwTableBox, pNewBox, rBoxes.Count() ); + FixFillerFrameFmt( pNewBox, sal_False ); + pLayoutInfo->SetLeftFillerBox( pNewBox ); + } + + // jetzt die Tabelle bearbeiten + pNewBox = new SwTableBox( pBoxFmt, 0, pLine ); + rBoxes.C40_INSERT( SwTableBox, pNewBox, rBoxes.Count() ); + + SwFrmFmt *pFrmFmt = pNewBox->ClaimFrmFmt(); + pFrmFmt->ResetFmtAttr( RES_BOX ); + pFrmFmt->ResetFmtAttr( RES_BACKGROUND ); + pFrmFmt->ResetFmtAttr( RES_VERT_ORIENT ); + pFrmFmt->ResetFmtAttr( RES_BOXATR_FORMAT ); + + + _MakeTable( pNewBox ); + + // und noch ggf. rechts eine Zelle einfuegen + if( pLayoutInfo->GetRelRightFill() > 0 ) + { + const SwStartNode *pStNd = + GetPrevBoxStartNode( USHRT_MAX, USHRT_MAX ); + pStNd = pParser->InsertTableSection( pStNd ); + + pNewBox = NewTableBox( pStNd, pLine ); + rBoxes.C40_INSERT( SwTableBox, pNewBox, rBoxes.Count() ); + + FixFillerFrameFmt( pNewBox, sal_True ); + pLayoutInfo->SetRightFillerBox( pNewBox ); + } + } + else + { + _MakeTable( pBox ); + } + + // zum Schluss fuehren wir noch eine Garbage-Collection fuer die + // Top-Level-Tabelle durch + if( this==pTopTable ) + { + if( 1==nRows && nHeight && 1==pSwTable->GetTabLines().Count() ) + { + // Hoehe einer einzeiligen Tabelle als Mindesthoehe der + // Zeile setzen. (War mal fixe Hoehe, aber das gibt manchmal + // Probleme (fix #34972#) und ist auch nicht Netscape 4.0 + // konform + nHeight = pParser->ToTwips( nHeight ); + if( nHeight < MINLAY ) + nHeight = MINLAY; + + (pSwTable->GetTabLines())[0]->ClaimFrmFmt(); + (pSwTable->GetTabLines())[0]->GetFrmFmt() + ->SetFmtAttr( SwFmtFrmSize( ATT_MIN_SIZE, 0, nHeight ) ); + } + + if( GetBGBrush() ) + pSwTable->GetFrmFmt()->SetFmtAttr( *GetBGBrush() ); + + ((SwTable *)pSwTable)->SetRowsToRepeat( static_cast< sal_uInt16 >(nHeadlineRepeat) ); + ((SwTable *)pSwTable)->GCLines(); + + sal_Bool bIsInFlyFrame = pContext && pContext->GetFrmFmt(); + if( bIsInFlyFrame && !nWidth ) + { + SvxAdjust eTblAdjust = GetTableAdjust(sal_False); + if( eTblAdjust != SVX_ADJUST_LEFT && + eTblAdjust != SVX_ADJUST_RIGHT ) + { + // Wenn eine Tabelle ohne Breitenangabe nicht links oder + // rechts umflossen werden soll, dann stacken wir sie + // in einem Rahmen mit 100%-Breite, damit ihre Groesse + // angepasst wird. Der Rahmen darf nicht angepasst werden. + ASSERT( HasToFly(), "Warum ist die Tabelle in einem Rahmen?" ); + sal_uInt32 nMin = pLayoutInfo->GetMin(); + if( nMin > USHRT_MAX ) + nMin = USHRT_MAX; + SwFmtFrmSize aFlyFrmSize( ATT_VAR_SIZE, (SwTwips)nMin, MINLAY ); + aFlyFrmSize.SetWidthPercent( 100 ); + pContext->GetFrmFmt()->SetFmtAttr( aFlyFrmSize ); + bIsInFlyFrame = sal_False; + } + else + { + // Links und rechts ausgerichtete Tabellen ohne Breite + // duerfen leider nicht in der Breite angepasst werden, denn + // sie wuerden nur schrumpfen aber nie wachsen. + pLayoutInfo->SetMustNotRecalc( sal_True ); + if( pContext->GetFrmFmt()->GetAnchor().GetCntntAnchor() + ->nNode.GetNode().FindTableNode() ) + { + sal_uInt32 nMax = pLayoutInfo->GetMax(); + if( nMax > USHRT_MAX ) + nMax = USHRT_MAX; + SwFmtFrmSize aFlyFrmSize( ATT_VAR_SIZE, (SwTwips)nMax, MINLAY ); + pContext->GetFrmFmt()->SetFmtAttr( aFlyFrmSize ); + bIsInFlyFrame = sal_False; + } + else + { + pLayoutInfo->SetMustNotResize( sal_True ); + } + } + } + pLayoutInfo->SetMayBeInFlyFrame( bIsInFlyFrame ); + + // Nur Tabellen mit relativer Breite oder ohne Breite muessen + // angepasst werden. + pLayoutInfo->SetMustResize( bPrcWidth || !nWidth ); + + pLayoutInfo->SetWidths(); + + ((SwTable *)pSwTable)->SetHTMLTableLayout( pLayoutInfo ); + + if( pResizeDrawObjs ) + { + sal_uInt16 nCount = pResizeDrawObjs->Count(); + for( sal_uInt16 i=0; i<nCount; i++ ) + { + SdrObject *pObj = (*pResizeDrawObjs)[i]; + sal_uInt16 nRow = (*pDrawObjPrcWidths)[3*i]; + sal_uInt16 nCol = (*pDrawObjPrcWidths)[3*i+1]; + sal_uInt8 nPrcWidth = (sal_uInt8)(*pDrawObjPrcWidths)[3*i+2]; + + SwHTMLTableLayoutCell *pLayoutCell = + pLayoutInfo->GetCell( nRow, nCol ); + sal_uInt16 nColSpan = pLayoutCell->GetColSpan(); + + sal_uInt16 nWidth2, nDummy; + pLayoutInfo->GetAvail( nCol, nColSpan, nWidth2, nDummy ); + nWidth2 = nWidth2 - pLayoutInfo->GetLeftCellSpace( nCol, nColSpan ); + nWidth2 = nWidth2 - pLayoutInfo->GetRightCellSpace( nCol, nColSpan ); + nWidth2 = static_cast< sal_uInt16 >(((long)nWidth * nPrcWidth) / 100); + + pParser->ResizeDrawObject( pObj, nWidth2 ); + } + } + } +} + +void HTMLTable::SetTable( const SwStartNode *pStNd, _HTMLTableContext *pCntxt, + sal_uInt16 nLeft, sal_uInt16 nRight, + const SwTable *pSwTab, sal_Bool bFrcFrame ) +{ + pPrevStNd = pStNd; + pSwTable = pSwTab; + pContext = pCntxt; + + nLeftMargin = nLeft; + nRightMargin = nRight; + + bForceFrame = bFrcFrame; +} + +void HTMLTable::RegisterDrawObject( SdrObject *pObj, sal_uInt8 nPrcWidth ) +{ + if( !pResizeDrawObjs ) + pResizeDrawObjs = new SdrObjects; + pResizeDrawObjs->C40_INSERT( SdrObject, pObj, pResizeDrawObjs->Count() ); + + if( !pDrawObjPrcWidths ) + pDrawObjPrcWidths = new SvUShorts; + pDrawObjPrcWidths->Insert( nCurRow, pDrawObjPrcWidths->Count() ); + pDrawObjPrcWidths->Insert( nCurCol, pDrawObjPrcWidths->Count() ); + pDrawObjPrcWidths->Insert( (sal_uInt16)nPrcWidth, pDrawObjPrcWidths->Count() ); +} + +void HTMLTable::MakeParentContents() +{ + if( !GetContext() && !HasParentSection() ) + { + SetParentContents( + pParser->InsertTableContents( GetIsParentHeader() ) ); + + SetHasParentSection( sal_True ); + } +} + +_HTMLTableContext::~_HTMLTableContext() +{ + delete pPos; +} + +void _HTMLTableContext::SavePREListingXMP( SwHTMLParser& rParser ) +{ + bRestartPRE = rParser.IsReadPRE(); + bRestartXMP = rParser.IsReadXMP(); + bRestartListing = rParser.IsReadListing(); + rParser.FinishPREListingXMP(); +} + +void _HTMLTableContext::RestorePREListingXMP( SwHTMLParser& rParser ) +{ + rParser.FinishPREListingXMP(); + + if( bRestartPRE ) + rParser.StartPRE(); + + if( bRestartXMP ) + rParser.StartXMP(); + + if( bRestartListing ) + rParser.StartListing(); +} + +/* */ + +const SwStartNode *SwHTMLParser::InsertTableSection + ( const SwStartNode *pPrevStNd ) +{ + ASSERT( pPrevStNd, "Start-Node ist NULL" ); + + pCSS1Parser->SetTDTagStyles(); + SwTxtFmtColl *pColl = pCSS1Parser->GetTxtCollFromPool( RES_POOLCOLL_TABLE ); + + const SwStartNode *pStNd; + if( pTable && pTable->bFirstCell ) + { + SwNode *const pNd = & pPam->GetPoint()->nNode.GetNode(); + pNd->GetTxtNode()->ChgFmtColl( pColl ); + pStNd = pNd->FindTableBoxStartNode(); + pTable->bFirstCell = sal_False; + } + else + { + const SwNode* pNd; + if( pPrevStNd->IsTableNode() ) + pNd = pPrevStNd; + else + pNd = pPrevStNd->EndOfSectionNode(); + SwNodeIndex nIdx( *pNd, 1 ); + pStNd = pDoc->GetNodes().MakeTextSection( nIdx, SwTableBoxStartNode, + pColl ); + pTable->IncBoxCount(); + } + + SwCntntNode *pCNd = pDoc->GetNodes()[pStNd->GetIndex()+1] ->GetCntntNode(); + SvxFontHeightItem aFontHeight( 40, 100, RES_CHRATR_FONTSIZE ); + pCNd->SetAttr( aFontHeight ); + aFontHeight.SetWhich( RES_CHRATR_CJK_FONTSIZE ); + pCNd->SetAttr( aFontHeight ); + aFontHeight.SetWhich( RES_CHRATR_CTL_FONTSIZE ); + pCNd->SetAttr( aFontHeight ); + + return pStNd; +} + +const SwStartNode *SwHTMLParser::InsertTableSection( sal_uInt16 nPoolId ) +{ + switch( nPoolId ) + { + case RES_POOLCOLL_TABLE_HDLN: + pCSS1Parser->SetTHTagStyles(); + break; + case RES_POOLCOLL_TABLE: + pCSS1Parser->SetTDTagStyles(); + break; + } + + SwTxtFmtColl *pColl = pCSS1Parser->GetTxtCollFromPool( nPoolId ); + + SwNode *const pNd = & pPam->GetPoint()->nNode.GetNode(); + const SwStartNode *pStNd; + if( pTable && pTable->bFirstCell ) + { + pNd->GetTxtNode()->ChgFmtColl( pColl ); + pTable->bFirstCell = sal_False; + pStNd = pNd->FindTableBoxStartNode(); + } + else + { + SwTableNode *pTblNd = pNd->FindTableNode(); + if( pTblNd->GetTable().GetHTMLTableLayout() ) + { // if there is already a HTMTableLayout, this table is already finished + // and we have to look for the right table in the environment + SwTableNode *pOutTbl = pTblNd; + do { + pTblNd = pOutTbl; + pOutTbl = pOutTbl->StartOfSectionNode()->FindTableNode(); + } while( pOutTbl && pTblNd->GetTable().GetHTMLTableLayout() ); + } + SwNodeIndex aIdx( *pTblNd->EndOfSectionNode() ); + pStNd = pDoc->GetNodes().MakeTextSection( aIdx, SwTableBoxStartNode, + pColl ); + + pPam->GetPoint()->nNode = pStNd->GetIndex() + 1; + SwTxtNode *pTxtNd = pPam->GetPoint()->nNode.GetNode().GetTxtNode(); + pPam->GetPoint()->nContent.Assign( pTxtNd, 0 ); + pTable->IncBoxCount(); + } + + return pStNd; +} + +SwStartNode *SwHTMLParser::InsertTempTableCaptionSection() +{ + SwTxtFmtColl *pColl = pCSS1Parser->GetTxtCollFromPool( RES_POOLCOLL_TEXT ); + SwNodeIndex& rIdx = pPam->GetPoint()->nNode; + rIdx = pDoc->GetNodes().GetEndOfExtras(); + SwStartNode *pStNd = pDoc->GetNodes().MakeTextSection( rIdx, + SwNormalStartNode, pColl ); + + rIdx = pStNd->GetIndex() + 1; + pPam->GetPoint()->nContent.Assign( rIdx.GetNode().GetTxtNode(), 0 ); + + return pStNd; +} + + +xub_StrLen SwHTMLParser::StripTrailingLF() +{ + xub_StrLen nStripped = 0; + + xub_StrLen nLen = pPam->GetPoint()->nContent.GetIndex(); + if( nLen ) + { + SwTxtNode* pTxtNd = pPam->GetPoint()->nNode.GetNode().GetTxtNode(); + // vorsicht, wenn Kommentare nicht uebrlesen werden!!! + if( pTxtNd ) + { + xub_StrLen nPos = nLen; + xub_StrLen nLFCount = 0; + while( nPos && '\x0a' == (pTxtNd->GetTxt()).GetChar(--nPos) ) + nLFCount++; + + if( nLFCount ) + { +// MIB 6.6.97: Warum sollte man bei leeren Absaetzen nur ein LF loeschen? +// Das stimmt doch irgendwi nicht ... +// if( nLFCount == nLen ) +// { +// // nur Lfs, dann nur ein LF loeschen +// nLFCount = 1; +// } +// else if( nLFCount > 2 ) + if( nLFCount > 2 ) + { + // Bei Netscape entspricht ein Absatz-Ende zwei LFs + // (mit einem kommt man in die naechste Zeile, das + // zweite erzeugt eine Leerzeile) Diesen Abstand + // erreichen wie aber schon mit dem unteren + // Absatz-Abstand. Wenn nach den <BR> ein neuer + // Absatz aufgemacht wird, wird das Maximum des Abstands, + // der sich aus den BR und dem P ergibt genommen. + // Deshalb muessen wir 2 bzw. alle bei weniger + // als zweien loeschen + nLFCount = 2; + } + + nPos = nLen - nLFCount; + SwIndex nIdx( pTxtNd, nPos ); + pTxtNd->EraseText( nIdx, nLFCount ); + nStripped = nLFCount; + } + } + } + + return nStripped; +} + +SvxBrushItem* SwHTMLParser::CreateBrushItem( const Color *pColor, + const String& rImageURL, + const String& rStyle, + const String& rId, + const String& rClass ) +{ + SvxBrushItem *pBrushItem = 0; + + if( rStyle.Len() || rId.Len() || rClass.Len() ) + { + SfxItemSet aItemSet( pDoc->GetAttrPool(), RES_BACKGROUND, + RES_BACKGROUND ); + SvxCSS1PropertyInfo aPropInfo; + + if( rClass.Len() ) + { + String aClass( rClass ); + SwCSS1Parser::GetScriptFromClass( aClass ); + SvxCSS1MapEntry *pClass = pCSS1Parser->GetClass( aClass ); + if( pClass ) + aItemSet.Put( pClass->GetItemSet() ); + } + + if( rId.Len() ) + { + SvxCSS1MapEntry *pId = pCSS1Parser->GetId( rId ); + if( pId ) + aItemSet.Put( pId->GetItemSet() ); + } + + pCSS1Parser->ParseStyleOption( rStyle, aItemSet, aPropInfo ); + const SfxPoolItem *pItem = 0; + if( SFX_ITEM_SET == aItemSet.GetItemState( RES_BACKGROUND, sal_False, + &pItem ) ) + { + pBrushItem = new SvxBrushItem( *((const SvxBrushItem *)pItem) ); + } + } + + if( !pBrushItem && (pColor || rImageURL.Len()) ) + { + pBrushItem = new SvxBrushItem(RES_BACKGROUND); + + if( pColor ) + pBrushItem->SetColor(*pColor); + + if( rImageURL.Len() ) + { + pBrushItem->SetGraphicLink( URIHelper::SmartRel2Abs( INetURLObject(sBaseURL), rImageURL, Link(), false) ); + pBrushItem->SetGraphicPos( GPOS_TILED ); + } + } + + return pBrushItem; +} + +/* */ + +class _SectionSaveStruct : public SwPendingStackData +{ + sal_uInt16 nBaseFontStMinSave, nFontStMinSave, nFontStHeadStartSave; + sal_uInt16 nDefListDeepSave, nContextStMinSave, nContextStAttrMinSave; + +public: + + HTMLTable *pTable; + + _SectionSaveStruct( SwHTMLParser& rParser ); + virtual ~_SectionSaveStruct(); + + sal_uInt16 GetContextStAttrMin() const { return nContextStAttrMinSave; } + + void Restore( SwHTMLParser& rParser ); +}; + +_SectionSaveStruct::_SectionSaveStruct( SwHTMLParser& rParser ) : + nBaseFontStMinSave(0), nFontStMinSave(0), nFontStHeadStartSave(0), + nDefListDeepSave(0), nContextStMinSave(0), nContextStAttrMinSave(0), + pTable( 0 ) +{ + // Font-Stacks einfrieren + nBaseFontStMinSave = rParser.nBaseFontStMin; + rParser.nBaseFontStMin = rParser.aBaseFontStack.Count(); + + nFontStMinSave = rParser.nFontStMin; + nFontStHeadStartSave = rParser.nFontStHeadStart; + rParser.nFontStMin = rParser.aFontStack.Count(); + + // Kontext-Stack einfrieren + nContextStMinSave = rParser.nContextStMin; + nContextStAttrMinSave = rParser.nContextStAttrMin; + rParser.nContextStMin = rParser.aContexts.Count(); + rParser.nContextStAttrMin = rParser.nContextStMin; + + // und noch ein par Zaehler retten + nDefListDeepSave = rParser.nDefListDeep; + rParser.nDefListDeep = 0; +} + +_SectionSaveStruct::~_SectionSaveStruct() +{} + +void _SectionSaveStruct::Restore( SwHTMLParser& rParser ) +{ + // Font-Stacks wieder auftauen + sal_uInt16 nMin = rParser.nBaseFontStMin; + if( rParser.aBaseFontStack.Count() > nMin ) + rParser.aBaseFontStack.Remove( nMin, + rParser.aBaseFontStack.Count() - nMin ); + rParser.nBaseFontStMin = nBaseFontStMinSave; + + + nMin = rParser.nFontStMin; + if( rParser.aFontStack.Count() > nMin ) + rParser.aFontStack.Remove( nMin, + rParser.aFontStack.Count() - nMin ); + rParser.nFontStMin = nFontStMinSave; + rParser.nFontStHeadStart = nFontStHeadStartSave; + + // Der Kontext-Stack muss schon aufgeraeumt sein! + ASSERT( rParser.aContexts.Count() == rParser.nContextStMin && + rParser.aContexts.Count() == rParser.nContextStAttrMin, + "Der Kontext-Stack wurde nicht aufgeraeumt" ); + rParser.nContextStMin = nContextStMinSave; + rParser.nContextStAttrMin = nContextStAttrMinSave; + + // und noch ein par Zaehler rekonstruieren + rParser.nDefListDeep = nDefListDeepSave; + + // und ein par Flags zuruecksetzen + rParser.bNoParSpace = sal_False; + rParser.nOpenParaToken = 0; + + if( rParser.aParaAttrs.Count() ) + rParser.aParaAttrs.Remove( 0, rParser.aParaAttrs.Count() ); +} + +/* */ + +class _CellSaveStruct : public _SectionSaveStruct +{ + String aStyle, aId, aClass, aLang, aDir; + String aBGImage; + Color aBGColor; + + HTMLTableCnts* pCnts; // Liste aller Inhalte + HTMLTableCnts* pCurrCnts; // der aktuelle Inhalt oder 0 + SwNodeIndex *pNoBreakEndParaIdx;// Absatz-Index eines </NOBR> + + double nValue; + + sal_uInt32 nNumFmt; + + sal_uInt16 nRowSpan, nColSpan, nWidth, nHeight; + xub_StrLen nNoBreakEndCntntPos; // Zeichen-Index eines </NOBR> + + SvxAdjust eAdjust; + sal_Int16 eVertOri; + + sal_Bool bHead : 1; + sal_Bool bPrcWidth : 1; + sal_Bool bHasNumFmt : 1; + sal_Bool bHasValue : 1; + sal_Bool bBGColor : 1; + sal_Bool bNoWrap : 1; // NOWRAP-Option + sal_Bool bNoBreak : 1; // NOBREAK-Tag + +public: + + _CellSaveStruct( SwHTMLParser& rParser, HTMLTable *pCurTable, sal_Bool bHd, + sal_Bool bReadOpt ); + + virtual ~_CellSaveStruct(); + + void AddContents( HTMLTableCnts *pNewCnts ); + HTMLTableCnts *GetFirstContents() { return pCnts; } + + void ClearIsInSection() { pCurrCnts = 0; } + sal_Bool IsInSection() const { return pCurrCnts!=0; } + HTMLTableCnts *GetCurrContents() const { return pCurrCnts; } + + void InsertCell( SwHTMLParser& rParser, HTMLTable *pCurTable ); + + sal_Bool IsHeaderCell() const { return bHead; } + + void StartNoBreak( const SwPosition& rPos ); + void EndNoBreak( const SwPosition& rPos ); + void CheckNoBreak( const SwPosition& rPos, SwDoc *pDoc ); +}; + + +_CellSaveStruct::_CellSaveStruct( SwHTMLParser& rParser, HTMLTable *pCurTable, + sal_Bool bHd, sal_Bool bReadOpt ) : + _SectionSaveStruct( rParser ), + pCnts( 0 ), + pCurrCnts( 0 ), + pNoBreakEndParaIdx( 0 ), + nValue( 0.0 ), + nNumFmt( 0 ), + nRowSpan( 1 ), + nColSpan( 1 ), + nWidth( 0 ), + nHeight( 0 ), + nNoBreakEndCntntPos( 0 ), + eAdjust( pCurTable->GetInheritedAdjust() ), + eVertOri( pCurTable->GetInheritedVertOri() ), + bHead( bHd ), + bPrcWidth( sal_False ), + bHasNumFmt( sal_False ), + bHasValue( sal_False ), + bBGColor( sal_False ), + bNoWrap( sal_False ), + bNoBreak( sal_False ) +{ + String aNumFmt, aValue; + + if( bReadOpt ) + { + const HTMLOptions *pOptions = rParser.GetOptions(); + for( sal_uInt16 i = pOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_COLSPAN: + nColSpan = (sal_uInt16)pOption->GetNumber(); + break; + case HTML_O_ROWSPAN: + nRowSpan = (sal_uInt16)pOption->GetNumber(); + break; + case HTML_O_ALIGN: + eAdjust = (SvxAdjust)pOption->GetEnum( + aHTMLPAlignTable, static_cast< sal_uInt16 >(eAdjust) ); + break; + case HTML_O_VALIGN: + eVertOri = pOption->GetEnum( + aHTMLTblVAlignTable, eVertOri ); + break; + case HTML_O_WIDTH: + nWidth = (sal_uInt16)pOption->GetNumber(); // nur fuer Netscape + bPrcWidth = (pOption->GetString().Search('%') != STRING_NOTFOUND); + if( bPrcWidth && nWidth>100 ) + nWidth = 100; + break; + case HTML_O_HEIGHT: + nHeight = (sal_uInt16)pOption->GetNumber(); // nur fuer Netscape + if( pOption->GetString().Search('%') != STRING_NOTFOUND) + nHeight = 0; // keine %-Angaben beruecksichtigen + break; + case HTML_O_BGCOLOR: + // Leere BGCOLOR bei <TABLE>, <TR> und <TD>/<TH> wie Netscape + // ignorieren, bei allen anderen Tags *wirklich* nicht. + if( pOption->GetString().Len() ) + { + pOption->GetColor( aBGColor ); + bBGColor = sal_True; + } + break; + case HTML_O_BACKGROUND: + aBGImage = pOption->GetString(); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + case HTML_O_LANG: + aLang = pOption->GetString(); + break; + case HTML_O_DIR: + aDir = pOption->GetString(); + break; + case HTML_O_SDNUM: + aNumFmt = pOption->GetString(); + bHasNumFmt = sal_True; + break; + case HTML_O_SDVAL: + bHasValue = sal_True; + aValue = pOption->GetString(); + break; + case HTML_O_NOWRAP: + bNoWrap = sal_True; + break; + } + } + + if( aId.Len() ) + rParser.InsertBookmark( aId ); + } + + if( bHasNumFmt ) + { + LanguageType eLang; + nValue = rParser.GetTableDataOptionsValNum( + nNumFmt, eLang, aValue, aNumFmt, + *rParser.pDoc->GetNumberFormatter() ); + } + + // einen neuen Kontext anlegen, aber das drawing::Alignment-Attribut + // nicht dort verankern, weil es noch ger keine Section gibt, in der + // es gibt. + sal_uInt16 nToken, nColl; + if( bHead ) + { + nToken = HTML_TABLEHEADER_ON; + nColl = RES_POOLCOLL_TABLE_HDLN; + } + else + { + nToken = HTML_TABLEDATA_ON; + nColl = RES_POOLCOLL_TABLE; + } + _HTMLAttrContext *pCntxt = new _HTMLAttrContext( nToken, nColl, aEmptyStr, sal_True ); + if( SVX_ADJUST_END != eAdjust ) + rParser.InsertAttr( &rParser.aAttrTab.pAdjust, SvxAdjustItem(eAdjust, RES_PARATR_ADJUST), + pCntxt ); + + if( rParser.HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) ) + { + SfxItemSet aItemSet( rParser.pDoc->GetAttrPool(), + rParser.pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + + if( rParser.ParseStyleOptions( aStyle, aId, aClass, aItemSet, + aPropInfo, &aLang, &aDir ) ) + rParser.InsertAttrs( aItemSet, aPropInfo, pCntxt ); + } + + rParser.SplitPREListingXMP( pCntxt ); + + rParser.PushContext( pCntxt ); +} + +_CellSaveStruct::~_CellSaveStruct() +{ + delete pNoBreakEndParaIdx; +} + +void _CellSaveStruct::AddContents( HTMLTableCnts *pNewCnts ) +{ + if( pCnts ) + pCnts->Add( pNewCnts ); + else + pCnts = pNewCnts; + + pCurrCnts = pNewCnts; +} + +void _CellSaveStruct::InsertCell( SwHTMLParser& rParser, + HTMLTable *pCurTable ) +{ +#ifdef DBG_UTIL + // Die Attribute muessen schon beim Auefrauemen des Kontext-Stacks + // entfernt worden sein, sonst ist etwas schiefgelaufen. Das + // Checken wir mal eben ... + // MIB 8.1.98: Wenn ausserhalb einer Zelle Attribute geoeffnet + // wurden stehen diese noch in der Attribut-Tabelle und werden erst + // ganz zum Schluss durch die CleanContext-Aufrufe in BuildTable + // geloescht. Damit es in diesem Fall keine Asserts gibt findet dann + // keine Ueberpruefung statt. Erkennen tut man diesen Fall an + // nContextStAttrMin: Der gemerkte Wert nContextStAttrMinSave ist der + // Wert, den nContextStAttrMin beim Start der Tabelle hatte. Und + // der aktuelle Wert von nContextStAttrMin entspricht der Anzahl der + // Kontexte, die beim Start der Zelle vorgefunden wurden. Sind beide + // Werte unterschiedlich, wurden ausserhalb der Zelle Kontexte + // angelegt und wir ueberpruefen nichts. + + if( rParser.nContextStAttrMin == GetContextStAttrMin() ) + { + _HTMLAttr** pTbl = (_HTMLAttr**)&rParser.aAttrTab; + + for( sal_uInt16 nCnt = sizeof( _HTMLAttrTable ) / sizeof( _HTMLAttr* ); + nCnt--; ++pTbl ) + { + ASSERT( !*pTbl, "Die Attribut-Tabelle ist nicht leer" ); + } + } +#endif + + // jetzt muessen wir noch die Zelle an der aktuellen Position einfuegen + SvxBrushItem *pBrushItem = + rParser.CreateBrushItem( bBGColor ? &aBGColor : 0, aBGImage, + aStyle, aId, aClass ); + pCurTable->InsertCell( pCnts, nRowSpan, nColSpan, nWidth, + bPrcWidth, nHeight, eVertOri, pBrushItem, + bHasNumFmt, nNumFmt, bHasValue, nValue, + bNoWrap ); + Restore( rParser ); +} + +void _CellSaveStruct::StartNoBreak( const SwPosition& rPos ) +{ + if( !pCnts || + (!rPos.nContent.GetIndex() && pCurrCnts==pCnts && + pCnts->GetStartNode() && + pCnts->GetStartNode()->GetIndex() + 1 == + rPos.nNode.GetIndex()) ) + { + bNoBreak = sal_True; + } +} + +void _CellSaveStruct::EndNoBreak( const SwPosition& rPos ) +{ + if( bNoBreak ) + { + delete pNoBreakEndParaIdx; + pNoBreakEndParaIdx = new SwNodeIndex( rPos.nNode ); + nNoBreakEndCntntPos = rPos.nContent.GetIndex(); + bNoBreak = sal_False; + } +} + +void _CellSaveStruct::CheckNoBreak( const SwPosition& rPos, SwDoc * /*pDoc*/ ) +{ + if( pCnts && pCurrCnts==pCnts ) + { + if( bNoBreak ) + { + // <NOBR> wurde nicht beendet + pCnts->SetNoBreak(); + } + else if( pNoBreakEndParaIdx && + pNoBreakEndParaIdx->GetIndex() == rPos.nNode.GetIndex() ) + { + if( nNoBreakEndCntntPos == rPos.nContent.GetIndex() ) + { + // <NOBR> wurde unmittelbar vor dem Zellen-Ende beendet + pCnts->SetNoBreak(); + } + else if( nNoBreakEndCntntPos + 1 == rPos.nContent.GetIndex() ) + { + SwTxtNode const*const pTxtNd(rPos.nNode.GetNode().GetTxtNode()); + if( pTxtNd ) + { + sal_Unicode cLast = + pTxtNd->GetTxt().GetChar(nNoBreakEndCntntPos); + if( ' '==cLast || '\x0a'==cLast ) + { + // Zwischem dem </NOBR> und dem Zellen-Ende gibt es nur + // ein Blank oder einen Zeilenumbruch. + pCnts->SetNoBreak(); + } + } + } + } + } +} + + + +HTMLTableCnts *SwHTMLParser::InsertTableContents( + sal_Bool bHead ) +{ + // eine neue Section anlegen, der PaM steht dann darin + const SwStartNode *pStNd = + InsertTableSection( static_cast< sal_uInt16 >(bHead ? RES_POOLCOLL_TABLE_HDLN + : RES_POOLCOLL_TABLE) ); + + if( GetNumInfo().GetNumRule() ) + { + // 1. Absatz auf nicht numeriert setzen + sal_uInt8 nLvl = GetNumInfo().GetLevel(); + // --> OD 2008-04-02 #refactorlists# +// SetNoNum(&nLvl, sal_True); +// SetNodeNum( nLvl); + SetNodeNum( nLvl, false ); + } + + // Attributierungs-Anfang neu setzen + const SwNodeIndex& rSttPara = pPam->GetPoint()->nNode; + xub_StrLen nSttCnt = pPam->GetPoint()->nContent.GetIndex(); + + _HTMLAttr** pTbl = (_HTMLAttr**)&aAttrTab; + for( sal_uInt16 nCnt = sizeof( _HTMLAttrTable ) / sizeof( _HTMLAttr* ); + nCnt--; ++pTbl ) + { + + _HTMLAttr *pAttr = *pTbl; + while( pAttr ) + { + ASSERT( !pAttr->GetPrev(), "Attribut hat Previous-Liste" ); + pAttr->nSttPara = rSttPara; + pAttr->nEndPara = rSttPara; + pAttr->nSttCntnt = nSttCnt; + pAttr->nEndCntnt = nSttCnt; + + pAttr = pAttr->GetNext(); + } + } + + return new HTMLTableCnts( pStNd ); +} + +sal_uInt16 SwHTMLParser::IncGrfsThatResizeTable() +{ + return pTable ? pTable->IncGrfsThatResize() : 0; +} + +void SwHTMLParser::RegisterDrawObjectToTable( HTMLTable *pCurTable, + SdrObject *pObj, sal_uInt8 nPrcWidth ) +{ + pCurTable->RegisterDrawObject( pObj, nPrcWidth ); +} + +void SwHTMLParser::BuildTableCell( HTMLTable *pCurTable, sal_Bool bReadOptions, + sal_Bool bHead ) +{ + if( !IsParserWorking() && !pPendStack ) + return; + + _CellSaveStruct* pSaveStruct; + + int nToken = 0; + sal_Bool bPending = sal_False; + if( pPendStack ) + { + pSaveStruct = (_CellSaveStruct*)pPendStack->pData; + + SwPendingStack* pTmp = pPendStack->pNext; + delete pPendStack; + pPendStack = pTmp; + nToken = pPendStack ? pPendStack->nToken : GetSaveToken(); + bPending = SVPAR_ERROR == eState && pPendStack != 0; + + SaveState( nToken ); + } + else + { + // <TH> bzw. <TD> wurde bereits gelesen + if( pTable->IsOverflowing() ) + { + SaveState( 0 ); + return; + } + + if( !pCurTable->GetContext() ) + { + sal_Bool bTopTable = pTable==pCurTable; + + // die Tabelle besitzt noch keinen Inhalt, d.h. die eigentliche + // Tabelle muss erst noch angelegt werden + + static sal_uInt16 aWhichIds[] = + { + RES_PARATR_SPLIT, RES_PARATR_SPLIT, + RES_PAGEDESC, RES_PAGEDESC, + RES_BREAK, RES_BREAK, + RES_BACKGROUND, RES_BACKGROUND, + RES_KEEP, RES_KEEP, + RES_LAYOUT_SPLIT, RES_LAYOUT_SPLIT, + RES_FRAMEDIR, RES_FRAMEDIR, + 0 + }; + + SfxItemSet aItemSet( pDoc->GetAttrPool(), aWhichIds ); + SvxCSS1PropertyInfo aPropInfo; + + sal_Bool bStyleParsed = ParseStyleOptions( pCurTable->GetStyle(), + pCurTable->GetId(), + pCurTable->GetClass(), + aItemSet, aPropInfo, + 0, &pCurTable->GetDirection() ); + const SfxPoolItem *pItem = 0; + if( bStyleParsed ) + { + if( SFX_ITEM_SET == aItemSet.GetItemState( + RES_BACKGROUND, sal_False, &pItem ) ) + { + pCurTable->SetBGBrush( *(const SvxBrushItem *)pItem ); + aItemSet.ClearItem( RES_BACKGROUND ); + } + if( SFX_ITEM_SET == aItemSet.GetItemState( + RES_PARATR_SPLIT, sal_False, &pItem ) ) + { + aItemSet.Put( + SwFmtLayoutSplit( ((const SvxFmtSplitItem *)pItem) + ->GetValue() ) ); + aItemSet.ClearItem( RES_PARATR_SPLIT ); + } + } + + // Den linken/rechten Absatzeinzug ermitteln + sal_uInt16 nLeftSpace = 0; + sal_uInt16 nRightSpace = 0; + short nIndent; + GetMarginsFromContextWithNumBul( nLeftSpace, nRightSpace, nIndent ); + + // die aktuelle Position an die wir irgendwann zurueckkehren + SwPosition *pSavePos = 0; + sal_Bool bForceFrame = sal_False; + sal_Bool bAppended = sal_False; + sal_Bool bParentLFStripped = sal_False; + if( bTopTable ) + { + SvxAdjust eTblAdjust = pTable->GetTableAdjust(sal_False); + + // Wenn die Tabelle links oder rechts ausgerivchtet ist, + // oder in einen Rahmen soll, dann kommt sie auch in einen + // solchen. + bForceFrame = eTblAdjust == SVX_ADJUST_LEFT || + eTblAdjust == SVX_ADJUST_RIGHT || + pCurTable->HasToFly(); + + // Entweder kommt die Tabelle in keinen Rahmen und befindet + // sich in keinem Rahmen (wird also durch Zellen simuliert), + // oder es gibt bereits Inhalt an der entsprechenden Stelle. + ASSERT( !bForceFrame || pCurTable->HasParentSection(), + "Tabelle im Rahmen hat keine Umgebung!" ); +// SCHOEN WAER'S, aber wie bekommen den Inhalt nicht zurueck +// in die umgebende Zelle +// if( bForceFrame && !pCurTable->HasParentSection() ) +// { +// pCurTable->SetParentContents( +// InsertTableContents( sal_False, SVX_ADJUST_END ) ); +// pCurTable->SetHasParentSection( sal_True ); +// } + + sal_Bool bAppend = sal_False; + if( bForceFrame ) + { + // Wenn die Tabelle in einen Rahmen kommt, muss + // nur ein neuer Absatz aufgemacht werden, wenn + // der Absatz Rahmen ohne Umlauf enthaelt. + bAppend = HasCurrentParaFlys(sal_True); + } + else + { + // Sonst muss ein neuer Absatz aufgemacht werden, + // wenn der Absatz nicht leer ist, oder Rahmen + // oder text::Bookmarks enthaelt. + bAppend = + pPam->GetPoint()->nContent.GetIndex() || + HasCurrentParaFlys() || + HasCurrentParaBookmarks(); + } + if( bAppend ) + { + if( !pPam->GetPoint()->nContent.GetIndex() ) + { + pDoc->SetTxtFmtColl( *pPam, + pCSS1Parser->GetTxtCollFromPool(RES_POOLCOLL_STANDARD) ); + SvxFontHeightItem aFontHeight( 40, 100, RES_CHRATR_FONTSIZE ); + + _HTMLAttr* pTmp = + new _HTMLAttr( *pPam->GetPoint(), aFontHeight ); + aSetAttrTab.Insert( pTmp, aSetAttrTab.Count() ); + + aFontHeight.SetWhich( RES_CHRATR_CJK_FONTSIZE ); + pTmp = new _HTMLAttr( *pPam->GetPoint(), aFontHeight ); + aSetAttrTab.Insert( pTmp, aSetAttrTab.Count() ); + + aFontHeight.SetWhich( RES_CHRATR_CTL_FONTSIZE ); + pTmp = new _HTMLAttr( *pPam->GetPoint(), aFontHeight ); + aSetAttrTab.Insert( pTmp, aSetAttrTab.Count() ); + + pTmp = new _HTMLAttr( *pPam->GetPoint(), + SvxULSpaceItem( 0, 0, RES_UL_SPACE ) ); + aSetAttrTab.Insert( pTmp, 0 ); // ja, 0, weil schon + // vom Tabellenende vorher + // was gesetzt sein kann. + } + AppendTxtNode( AM_NOSPACE ); + bAppended = sal_True; + } + else if( aParaAttrs.Count() ) + { + if( !bForceFrame ) + { + // Der Absatz wird gleich hinter die Tabelle + // verschoben. Deshalb entfernen wir alle harten + // Attribute des Absatzes + + for( sal_uInt16 i=0; i<aParaAttrs.Count(); i++ ) + aParaAttrs[i]->Invalidate(); + } + + aParaAttrs.Remove( 0, aParaAttrs.Count() ); + } + + pSavePos = new SwPosition( *pPam->GetPoint() ); + } + else if( pCurTable->HasParentSection() ) + { + bParentLFStripped = StripTrailingLF() > 0; + + // Absaetze bzw. ueberschriften beeenden + nOpenParaToken = 0; + nFontStHeadStart = nFontStMin; + + // die harten Attribute an diesem Absatz werden nie mehr ungueltig + if( aParaAttrs.Count() ) + aParaAttrs.Remove( 0, aParaAttrs.Count() ); + } + + // einen Tabellen Kontext anlegen + _HTMLTableContext *pTCntxt = + new _HTMLTableContext( pSavePos, nContextStMin, + nContextStAttrMin ); + + // alle noch offenen Attribute beenden und hinter der Tabelle + // neu aufspannen + _HTMLAttrs *pPostIts = 0; + if( !bForceFrame && (bTopTable || pCurTable->HasParentSection()) ) + { + SplitAttrTab( pTCntxt->aAttrTab, bTopTable ); + // Wenn wir einen schon vorhandenen Absatz verwenden, duerfen + // in den keine PostIts eingefuegt werden, weil der Absatz + // ja hinter die Tabelle wandert. Sie werden deshalb in den + // ersten Absatz der Tabelle verschoben. + // Bei Tabellen in Tabellen duerfen ebenfalls keine PostIts + // in einen noch leeren Absatz eingefuegt werden, weil + // der sonat nicht geloescht wird. + if( (bTopTable && !bAppended) || + (!bTopTable && !bParentLFStripped && + !pPam->GetPoint()->nContent.GetIndex()) ) + pPostIts = new _HTMLAttrs; + SetAttr( bTopTable, bTopTable, pPostIts ); + } + else + { + SaveAttrTab( pTCntxt->aAttrTab ); + if( bTopTable && !bAppended ) + { + pPostIts = new _HTMLAttrs; + SetAttr( sal_True, sal_True, pPostIts ); + } + } + bNoParSpace = sal_False; + + // Aktuelle Numerierung retten und auschalten. + pTCntxt->SetNumInfo( GetNumInfo() ); + GetNumInfo().Clear(); + pTCntxt->SavePREListingXMP( *this ); + + if( bTopTable ) + { + if( bForceFrame ) + { + // Die Tabelle soll in einen Rahmen geschaufelt werden. + + SfxItemSet aFrmSet( pDoc->GetAttrPool(), + RES_FRMATR_BEGIN, RES_FRMATR_END-1 ); + if( !pCurTable->IsNewDoc() ) + Reader::ResetFrmFmtAttrs( aFrmSet ); + + SwSurround eSurround = SURROUND_NONE; + sal_Int16 eHori; + + switch( pCurTable->GetTableAdjust(sal_True) ) + { + case SVX_ADJUST_RIGHT: + eHori = text::HoriOrientation::RIGHT; + eSurround = SURROUND_LEFT; + break; + case SVX_ADJUST_CENTER: + eHori = text::HoriOrientation::CENTER; + break; + case SVX_ADJUST_LEFT: + eSurround = SURROUND_RIGHT; + default: + eHori = text::HoriOrientation::LEFT; + break; + } + SetAnchorAndAdjustment( text::VertOrientation::NONE, eHori, aFrmSet, + sal_True ); + aFrmSet.Put( SwFmtSurround(eSurround) ); + + SwFmtFrmSize aFrmSize( ATT_VAR_SIZE, 20*MM50, MINLAY ); + aFrmSize.SetWidthPercent( 100 ); + aFrmSet.Put( aFrmSize ); + + sal_uInt16 nSpace = pCurTable->GetHSpace(); + if( nSpace ) + aFrmSet.Put( SvxLRSpaceItem(nSpace,nSpace, 0, 0, RES_LR_SPACE) ); + nSpace = pCurTable->GetVSpace(); + if( nSpace ) + aFrmSet.Put( SvxULSpaceItem(nSpace,nSpace, RES_UL_SPACE) ); + + RndStdIds eAnchorId = ((const SwFmtAnchor&)aFrmSet. + Get( RES_ANCHOR )). + GetAnchorId(); + SwFrmFmt *pFrmFmt = pDoc->MakeFlySection( + eAnchorId, pPam->GetPoint(), &aFrmSet ); + + pTCntxt->SetFrmFmt( pFrmFmt ); + const SwFmtCntnt& rFlyCntnt = pFrmFmt->GetCntnt(); + pPam->GetPoint()->nNode = *rFlyCntnt.GetCntntIdx(); + SwCntntNode *pCNd = + pDoc->GetNodes().GoNext( &(pPam->GetPoint()->nNode) ); + pPam->GetPoint()->nContent.Assign( pCNd, 0 ); + + // automatisch verankerte Rahmen muessen noch um + // eine Position nach vorne verschoben werden. + //if( FLY_AUTO_CNTNT==eAnchorId ) + // aMoveFlyFrms.C40_INSERT( SwFrmFmt, pFrmFmt, + // aMoveFlyFrms.Count() ); + } + + // eine SwTable mit einer Box anlegen und den PaM in den + // Inhalt der Box-Section bewegen (der Ausrichtungs-Parameter + // ist erstmal nur ein Dummy und wird spaeter noch richtig + // gesetzt) + ASSERT( !pPam->GetPoint()->nContent.GetIndex(), + "Der Absatz hinter der Tabelle ist nicht leer!" ); + const SwTable* pSwTable = pDoc->InsertTable( + SwInsertTableOptions( tabopts::HEADLINE_NO_BORDER, 1 ), + *pPam->GetPoint(), 1, 1, text::HoriOrientation::LEFT ); + + if( bForceFrame ) + { + SwNodeIndex aDstIdx( pPam->GetPoint()->nNode ); + pPam->Move( fnMoveBackward ); + pDoc->GetNodes().Delete( aDstIdx ); + } + else + { + if( bStyleParsed ) + { + pCSS1Parser->SetFmtBreak( aItemSet, aPropInfo ); + pSwTable->GetFrmFmt()->SetFmtAttr( aItemSet ); + } + pPam->Move( fnMoveBackward ); + } + + SwNode const*const pNd = & pPam->GetPoint()->nNode.GetNode(); + if( !bAppended && !bForceFrame ) + { + SwTxtNode *const pOldTxtNd = + pSavePos->nNode.GetNode().GetTxtNode(); + ASSERT( pOldTxtNd, "Wieso stehen wir in keinem Txt-Node?" ); + SwFrmFmt *pFrmFmt = pSwTable->GetFrmFmt(); + + const SfxPoolItem* pItem2; + if( SFX_ITEM_SET == pOldTxtNd->GetSwAttrSet() + .GetItemState( RES_PAGEDESC, sal_False, &pItem2 ) && + ((SwFmtPageDesc *)pItem2)->GetPageDesc() ) + { + pFrmFmt->SetFmtAttr( *pItem2 ); + pOldTxtNd->ResetAttr( RES_PAGEDESC ); + } + if( SFX_ITEM_SET == pOldTxtNd->GetSwAttrSet() + .GetItemState( RES_BREAK, sal_True, &pItem2 ) ) + { + switch( ((SvxFmtBreakItem *)pItem2)->GetBreak() ) + { + case SVX_BREAK_PAGE_BEFORE: + case SVX_BREAK_PAGE_AFTER: + case SVX_BREAK_PAGE_BOTH: + pFrmFmt->SetFmtAttr( *pItem2 ); + pOldTxtNd->ResetAttr( RES_BREAK ); + default: + ; + } + } + } + + if( !bAppended && pPostIts ) + { + // noch vorhandene PostIts in den ersten Absatz + // der Tabelle setzen + InsertAttrs( *pPostIts ); + delete pPostIts; + pPostIts = 0; + } + + pTCntxt->SetTableNode( (SwTableNode *)pNd->FindTableNode() ); + + pCurTable->SetTable( pTCntxt->GetTableNode(), pTCntxt, + nLeftSpace, nRightSpace, + pSwTable, bForceFrame ); + + ASSERT( !pPostIts, "ubenutzte PostIts" ); + } + else + { + // noch offene Bereiche muessen noch entfernt werden + if( EndSections( bParentLFStripped ) ) + bParentLFStripped = sal_False; + + if( pCurTable->HasParentSection() ) + { + // dannach entfernen wir ein ggf. zu viel vorhandenen + // leeren Absatz, aber nur, wenn er schon vor dem + // entfernen von LFs leer war + if( !bParentLFStripped ) + StripTrailingPara(); + + if( pPostIts ) + { + // noch vorhandene PostIts an das Ende des jetzt + // aktuellen Absatzes schieben + InsertAttrs( *pPostIts ); + delete pPostIts; + pPostIts = 0; + } + } + + SwNode const*const pNd = & pPam->GetPoint()->nNode.GetNode(); + const SwStartNode *pStNd = (pTable->bFirstCell ? pNd->FindTableNode() + : pNd->FindTableBoxStartNode() ); + + pCurTable->SetTable( pStNd, pTCntxt, nLeftSpace, nRightSpace ); + } + + // Den Kontext-Stack einfrieren, denn es koennen auch mal + // irgendwo ausserhalb von Zellen Attribute gesetzt werden. + // Darf nicht frueher passieren, weil eventuell noch im + // Stack gesucht wird!!! + nContextStMin = aContexts.Count(); + nContextStAttrMin = nContextStMin; + } + + pSaveStruct = new _CellSaveStruct( *this, pCurTable, bHead, + bReadOptions ); + + // ist beim ersten GetNextToken schon pending, muss bei + // wiederaufsetzen auf jedenfall neu gelesen werden! + SaveState( 0 ); + } + + if( !nToken ) + nToken = GetNextToken(); // Token nach <TABLE> + + sal_Bool bDone = sal_False; + while( (IsParserWorking() && !bDone) || bPending ) + { + SaveState( nToken ); + + nToken = FilterToken( nToken ); + + ASSERT( pPendStack || !bCallNextToken || pSaveStruct->IsInSection(), + "Wo ist die Section gebieben?" ); + if( !pPendStack && bCallNextToken && pSaveStruct->IsInSection() ) + { + // NextToken direkt aufrufen (z.B. um den Inhalt von + // Floating-Frames oder Applets zu ignorieren) + NextToken( nToken ); + } + else switch( nToken ) + { + case HTML_TABLEHEADER_ON: + case HTML_TABLEDATA_ON: + case HTML_TABLEROW_ON: + case HTML_TABLEROW_OFF: + case HTML_THEAD_ON: + case HTML_THEAD_OFF: + case HTML_TFOOT_ON: + case HTML_TFOOT_OFF: + case HTML_TBODY_ON: + case HTML_TBODY_OFF: + case HTML_TABLE_OFF: + SkipToken(-1); + case HTML_TABLEHEADER_OFF: + case HTML_TABLEDATA_OFF: + bDone = sal_True; + break; + case HTML_TABLE_ON: + { + sal_Bool bTopTable = sal_False; + sal_Bool bHasToFly = sal_False; + SvxAdjust eTabAdjust = SVX_ADJUST_END; + if( !pPendStack ) + { + // nur wenn eine neue Tabelle aufgemacht wird, aber + // nicht wenn nach einem Pending in der Tabelle + // weitergelesen wird! + pSaveStruct->pTable = pTable; + + // HACK: Eine Section fuer eine Tabelle anlegen, die + // in einen Rahmen kommt. + if( !pSaveStruct->IsInSection() ) + { + // Diese Schleife muss vorwartes sein, weil die + // erste Option immer gewinnt. + sal_Bool bNeedsSection = sal_False; + const HTMLOptions *pHTMLOptions = GetOptions(); + for( sal_uInt16 i=0; i<pHTMLOptions->Count(); i++ ) + { + const HTMLOption *pOption = (*pHTMLOptions)[i]; + if( HTML_O_ALIGN==pOption->GetToken() ) + { + SvxAdjust eAdjust = + (SvxAdjust)pOption->GetEnum( + aHTMLPAlignTable, SVX_ADJUST_END ); + bNeedsSection = SVX_ADJUST_LEFT == eAdjust || + SVX_ADJUST_RIGHT == eAdjust; + break; + } + } + if( bNeedsSection ) + { + pSaveStruct->AddContents( + InsertTableContents(bHead ) ); + } + } + else + { + // Wenn wir mitlerweile in einem Rahmen stehen + // koennen wir erneut eine echte Tabelle aufmachen. + // Wir erkennen das daran, dass wir keinen + // Tabellen-Node mehr finden. + bTopTable = (0 == + pPam->GetPoint()->nNode.GetNode().FindTableNode()); + + // Wenn im aktuellen Absatz Flys verankert sind, + // muss die neue Tabelle in einen Rahmen. + bHasToFly = HasCurrentParaFlys(sal_False,sal_True); + } + + // in der Zelle kann sich ein Bereich befinden! + eTabAdjust = aAttrTab.pAdjust + ? ((const SvxAdjustItem&)aAttrTab.pAdjust->GetItem()). + GetAdjust() + : SVX_ADJUST_END; + } + + HTMLTable *pSubTable = BuildTable( eTabAdjust, + bHead, + pSaveStruct->IsInSection(), + bTopTable, bHasToFly ); + if( SVPAR_PENDING != GetStatus() ) + { + // nur wenn die Tabelle wirklich zu Ende ist! + if( pSubTable ) + { + ASSERT( pSubTable->GetTableAdjust(sal_False)!= SVX_ADJUST_LEFT && + pSubTable->GetTableAdjust(sal_False)!= SVX_ADJUST_RIGHT, + "links oder rechts ausgerichtete Tabellen gehoehren in Rahmen" ); + + + HTMLTableCnts *pParentContents = + pSubTable->GetParentContents(); + if( pParentContents ) + { + ASSERT( !pSaveStruct->IsInSection(), + "Wo ist die Section geblieben" ); + + // Wenn jetzt keine Tabelle kommt haben wir eine + // Section + pSaveStruct->AddContents( pParentContents ); + } + + const SwStartNode *pCapStNd = + pSubTable->GetCaptionStartNode(); + + if( pSubTable->GetContext() ) + { + ASSERT( !pSubTable->GetContext()->GetFrmFmt(), + "Tabelle steht im Rahmen" ); + + if( pCapStNd && pSubTable->IsTopCaption() ) + { + pSaveStruct->AddContents( + new HTMLTableCnts(pCapStNd) ); + } + + pSaveStruct->AddContents( + new HTMLTableCnts(pSubTable) ); + + if( pCapStNd && !pSubTable->IsTopCaption() ) + { + pSaveStruct->AddContents( + new HTMLTableCnts(pCapStNd) ); + } + + // Jetzt haben wir keine Section mehr + pSaveStruct->ClearIsInSection(); + } + else if( pCapStNd ) + { + // Da wir diese Sction nicht mehr loeschen + // koennen (sie koeente zur erster Box + // gehoeren), fuegen wir sie ein. + pSaveStruct->AddContents( + new HTMLTableCnts(pCapStNd) ); + + // Jetzt haben wir keine Section mehr + pSaveStruct->ClearIsInSection(); + } + } + + pTable = pSaveStruct->pTable; + } + } + break; + + case HTML_NOBR_ON: + // HACK fuer MS: Steht das <NOBR> zu beginn der Zelle? + pSaveStruct->StartNoBreak( *pPam->GetPoint() ); + break; + + case HTML_NOBR_OFF: + pSaveStruct->EndNoBreak( *pPam->GetPoint() ); + break; + + case HTML_COMMENT: + // Mit Kommentar-Feldern werden Spaces nicht mehr geloescht + // ausserdem wollen wir fuer einen Kommentar keine neue Zelle + // anlegen !!! + NextToken( nToken ); + break; + + case HTML_MARQUEE_ON: + if( !pSaveStruct->IsInSection() ) + { + // eine neue Section anlegen, der PaM steht dann darin + pSaveStruct->AddContents( + InsertTableContents( bHead ) ); + } + bCallNextToken = sal_True; + NewMarquee( pCurTable ); + break; + + case HTML_TEXTTOKEN: + // keine Section fuer einen leeren String anlegen + if( !pSaveStruct->IsInSection() && 1==aToken.Len() && + ' '==aToken.GetChar(0) ) + break; + default: + if( !pSaveStruct->IsInSection() ) + { + // eine neue Section anlegen, der PaM steht dann darin + pSaveStruct->AddContents( + InsertTableContents( bHead ) ); + } + + if( IsParserWorking() || bPending ) + NextToken( nToken ); + break; + } + + ASSERT( !bPending || !pPendStack, + "SwHTMLParser::BuildTableCell: Es gibt wieder einen Pend-Stack" ); + bPending = sal_False; + if( IsParserWorking() ) + SaveState( 0 ); + + if( !bDone ) + nToken = GetNextToken(); + } + + if( SVPAR_PENDING == GetStatus() ) + { + pPendStack = new SwPendingStack( bHead ? HTML_TABLEHEADER_ON + : HTML_TABLEDATA_ON, pPendStack ); + pPendStack->pData = pSaveStruct; + + return; + } + + // Falls der Inhalt der Zelle leer war, muessen wir noch einen + // leeren Inhalt anlegen. Ausserdem legen wir einen leeren Inhalt + // an, wenn die Zelle mit einer Tabelle aufgehoert hat und keine + // COL-Tags hatte (sonst wurde sie wahrscheinlich von uns exportiert, + // und dann wollen wir natuerlich keinen zusaetzlichen Absatz haben). + if( !pSaveStruct->GetFirstContents() || + (!pSaveStruct->IsInSection() && !pCurTable->HasColTags()) ) + { + ASSERT( pSaveStruct->GetFirstContents() || + !pSaveStruct->IsInSection(), + "Section oder nicht, das ist hier die Frage" ); + const SwStartNode *pStNd = + InsertTableSection( static_cast< sal_uInt16 >(pSaveStruct->IsHeaderCell() + ? RES_POOLCOLL_TABLE_HDLN + : RES_POOLCOLL_TABLE )); + const SwEndNode *pEndNd = pStNd->EndOfSectionNode(); + SwCntntNode *pCNd = pDoc->GetNodes()[pEndNd->GetIndex()-1] ->GetCntntNode(); + SvxFontHeightItem aFontHeight( 40, 100, RES_CHRATR_FONTSIZE ); + pCNd->SetAttr( aFontHeight ); + aFontHeight.SetWhich( RES_CHRATR_CJK_FONTSIZE ); + pCNd->SetAttr( aFontHeight ); + aFontHeight.SetWhich( RES_CHRATR_CTL_FONTSIZE ); + pCNd->SetAttr( aFontHeight ); + + pSaveStruct->AddContents( new HTMLTableCnts(pStNd) ); + pSaveStruct->ClearIsInSection(); + } + + if( pSaveStruct->IsInSection() ) + { + pSaveStruct->CheckNoBreak( *pPam->GetPoint(), pDoc ); + + // Alle noch offenen Kontexte beenden. Wir nehmen hier + // AttrMin, weil nContxtStMin evtl. veraendert wurde. + // Da es durch EndContext wieder restauriert wird, geht das. + while( aContexts.Count() > nContextStAttrMin+1 ) + { + _HTMLAttrContext *pCntxt = PopContext(); + EndContext( pCntxt ); + delete pCntxt; + } + + // LFs am Absatz-Ende entfernen + if( StripTrailingLF()==0 && !pPam->GetPoint()->nContent.GetIndex() ) + StripTrailingPara(); + + // falls fuer die Zelle eine Ausrichtung gesetzt wurde, muessen + // wir die beenden + _HTMLAttrContext *pCntxt = PopContext(); + EndContext( pCntxt ); + delete pCntxt; + } + else + { + // Alle noch offenen Kontexte beenden + while( aContexts.Count() > nContextStAttrMin ) + { + _HTMLAttrContext *pCntxt = PopContext(); + ClearContext( pCntxt ); + delete pCntxt; + } + } + + // auch eine Numerierung muss beendet werden + GetNumInfo().Clear(); + + SetAttr( sal_False ); + + pSaveStruct->InsertCell( *this, pCurTable ); + + // wir stehen jetzt (wahrschenlich) vor <TH>, <TD>, <TR> oder </TABLE> + delete pSaveStruct; +} + + +class _RowSaveStruct : public SwPendingStackData +{ +public: + SvxAdjust eAdjust; + sal_Int16 eVertOri; + sal_Bool bHasCells; + + _RowSaveStruct() : + eAdjust( SVX_ADJUST_END ), eVertOri( text::VertOrientation::TOP ), bHasCells( sal_False ) + {} +}; + + +void SwHTMLParser::BuildTableRow( HTMLTable *pCurTable, sal_Bool bReadOptions, + SvxAdjust eGrpAdjust, + sal_Int16 eGrpVertOri ) +{ + // <TR> wurde bereist gelesen + + if( !IsParserWorking() && !pPendStack ) + return; + + int nToken = 0; + _RowSaveStruct* pSaveStruct; + + sal_Bool bPending = sal_False; + if( pPendStack ) + { + pSaveStruct = (_RowSaveStruct*)pPendStack->pData; + + SwPendingStack* pTmp = pPendStack->pNext; + delete pPendStack; + pPendStack = pTmp; + nToken = pPendStack ? pPendStack->nToken : GetSaveToken(); + bPending = SVPAR_ERROR == eState && pPendStack != 0; + + SaveState( nToken ); + } + else + { + SvxAdjust eAdjust = eGrpAdjust; + sal_Int16 eVertOri = eGrpVertOri; + Color aBGColor; + String aBGImage, aStyle, aId, aClass; + sal_Bool bBGColor = sal_False; + pSaveStruct = new _RowSaveStruct; + + if( bReadOptions ) + { + const HTMLOptions *pHTMLOptions = GetOptions(); + for( sal_uInt16 i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_ALIGN: + eAdjust = (SvxAdjust)pOption->GetEnum( + aHTMLPAlignTable, static_cast< sal_uInt16 >(eAdjust) ); + break; + case HTML_O_VALIGN: + eVertOri = pOption->GetEnum( + aHTMLTblVAlignTable, eVertOri ); + break; + case HTML_O_BGCOLOR: + // Leere BGCOLOR bei <TABLE>, <TR> und <TD>/<TH> wie Netsc. + // ignorieren, bei allen anderen Tags *wirklich* nicht. + if( pOption->GetString().Len() ) + { + pOption->GetColor( aBGColor ); + bBGColor = sal_True; + } + break; + case HTML_O_BACKGROUND: + aBGImage = pOption->GetString(); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass= pOption->GetString(); + break; + } + } + } + + if( aId.Len() ) + InsertBookmark( aId ); + + SvxBrushItem *pBrushItem = + CreateBrushItem( bBGColor ? &aBGColor : 0, aBGImage, aStyle, + aId, aClass ); + pCurTable->OpenRow( eAdjust, eVertOri, pBrushItem ); + // ist beim ersten GetNextToken schon pending, muss bei + // wiederaufsetzen auf jedenfall neu gelesen werden! + SaveState( 0 ); + } + + if( !nToken ) + nToken = GetNextToken(); // naechstes Token + + sal_Bool bDone = sal_False; + while( (IsParserWorking() && !bDone) || bPending ) + { + SaveState( nToken ); + + nToken = FilterToken( nToken ); + + ASSERT( pPendStack || !bCallNextToken || + pCurTable->GetContext() || pCurTable->HasParentSection(), + "Wo ist die Section gebieben?" ); + if( !pPendStack && bCallNextToken && + (pCurTable->GetContext() || pCurTable->HasParentSection()) ) + { + // NextToken direkt aufrufen (z.B. um den Inhalt von + // Floating-Frames oder Applets zu ignorieren) + NextToken( nToken ); + } + else switch( nToken ) + { + case HTML_TABLE_ON: + if( !pCurTable->GetContext() ) + { + SkipToken( -1 ); + bDone = sal_True; + } +// else +// { +// NextToken( nToken ); +// } + break; + case HTML_TABLEROW_ON: + case HTML_THEAD_ON: + case HTML_THEAD_OFF: + case HTML_TBODY_ON: + case HTML_TBODY_OFF: + case HTML_TFOOT_ON: + case HTML_TFOOT_OFF: + case HTML_TABLE_OFF: + SkipToken( -1 ); + case HTML_TABLEROW_OFF: + bDone = sal_True; + break; + case HTML_TABLEHEADER_ON: + case HTML_TABLEDATA_ON: + BuildTableCell( pCurTable, sal_True, HTML_TABLEHEADER_ON==nToken ); + if( SVPAR_PENDING != GetStatus() ) + { + pSaveStruct->bHasCells = sal_True; + bDone = pTable->IsOverflowing(); + } + break; + case HTML_CAPTION_ON: + BuildTableCaption( pCurTable ); + bDone = pTable->IsOverflowing(); + break; + case HTML_CAPTION_OFF: + case HTML_TABLEHEADER_OFF: + case HTML_TABLEDATA_OFF: + case HTML_COLGROUP_ON: + case HTML_COLGROUP_OFF: + case HTML_COL_ON: + case HTML_COL_OFF: + // wo keine Zelle anfing kann auch keine aufhoehren, oder? + // und die ganzen anderen Tokens haben hier auch nicht zu + // suchen und machen nur die Tabelle kaputt + break; + case HTML_MULTICOL_ON: + // spaltige Rahmen koennen wir hier leider nicht einguegen + break; + case HTML_FORM_ON: + NewForm( sal_False ); // keinen neuen Absatz aufmachen! + break; + case HTML_FORM_OFF: + EndForm( sal_False ); // keinen neuen Absatz aufmachen! + break; + case HTML_COMMENT: + NextToken( nToken ); + break; + case HTML_MAP_ON: + // eine Image-Map fuegt nichts ein, deshalb koennen wir sie + // problemlos auch ohne Zelle parsen + NextToken( nToken ); + break; + case HTML_TEXTTOKEN: + if( (pCurTable->GetContext() || + !pCurTable->HasParentSection()) && + 1==aToken.Len() && ' '==aToken.GetChar(0) ) + break; + default: + pCurTable->MakeParentContents(); + NextToken( nToken ); + break; + } + + ASSERT( !bPending || !pPendStack, + "SwHTMLParser::BuildTableRow: Es gibt wieder einen Pend-Stack" ); + bPending = sal_False; + if( IsParserWorking() ) + SaveState( 0 ); + + if( !bDone ) + nToken = GetNextToken(); + } + + if( SVPAR_PENDING == GetStatus() ) + { + pPendStack = new SwPendingStack( HTML_TABLEROW_ON, pPendStack ); + pPendStack->pData = pSaveStruct; + } + else + { + pCurTable->CloseRow( !pSaveStruct->bHasCells ); + delete pSaveStruct; + } + + // wir stehen jetzt (wahrscheinlich) vor <TR> oder </TABLE> +} + +void SwHTMLParser::BuildTableSection( HTMLTable *pCurTable, + sal_Bool bReadOptions, + sal_Bool bHead ) +{ + // <THEAD>, <TBODY> bzw. <TFOOT> wurde bereits gelesen + if( !IsParserWorking() && !pPendStack ) + return; + + int nToken = 0; + sal_Bool bPending = sal_False; + _RowSaveStruct* pSaveStruct; + + if( pPendStack ) + { + pSaveStruct = (_RowSaveStruct*)pPendStack->pData; + + SwPendingStack* pTmp = pPendStack->pNext; + delete pPendStack; + pPendStack = pTmp; + nToken = pPendStack ? pPendStack->nToken : GetSaveToken(); + bPending = SVPAR_ERROR == eState && pPendStack != 0; + + SaveState( nToken ); + } + else + { + pSaveStruct = new _RowSaveStruct; + + if( bReadOptions ) + { + const HTMLOptions *pHTMLOptions = GetOptions(); + for( sal_uInt16 i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_ID: + InsertBookmark( pOption->GetString() ); + break; + case HTML_O_ALIGN: + pSaveStruct->eAdjust = + (SvxAdjust)pOption->GetEnum( aHTMLPAlignTable, + static_cast< sal_uInt16 >(pSaveStruct->eAdjust) ); + break; + case HTML_O_VALIGN: + pSaveStruct->eVertOri = + pOption->GetEnum( aHTMLTblVAlignTable, + pSaveStruct->eVertOri ); + break; + } + } + } + + // ist beim ersten GetNextToken schon pending, muss bei + // wiederaufsetzen auf jedenfall neu gelesen werden! + SaveState( 0 ); + } + + if( !nToken ) + nToken = GetNextToken(); // naechstes Token + + sal_Bool bDone = sal_False; + while( (IsParserWorking() && !bDone) || bPending ) + { + SaveState( nToken ); + + nToken = FilterToken( nToken ); + + ASSERT( pPendStack || !bCallNextToken || + pCurTable->GetContext() || pCurTable->HasParentSection(), + "Wo ist die Section gebieben?" ); + if( !pPendStack && bCallNextToken && + (pCurTable->GetContext() || pCurTable->HasParentSection()) ) + { + // NextToken direkt aufrufen (z.B. um den Inhalt von + // Floating-Frames oder Applets zu ignorieren) + NextToken( nToken ); + } + else switch( nToken ) + { + case HTML_TABLE_ON: + if( !pCurTable->GetContext() ) + { + SkipToken( -1 ); + bDone = sal_True; + } +// else +// { +// NextToken( nToken ); +// } + break; + case HTML_THEAD_ON: + case HTML_TFOOT_ON: + case HTML_TBODY_ON: + case HTML_TABLE_OFF: + SkipToken( -1 ); + case HTML_THEAD_OFF: + case HTML_TBODY_OFF: + case HTML_TFOOT_OFF: + bDone = sal_True; + break; + case HTML_CAPTION_ON: + BuildTableCaption( pCurTable ); + bDone = pTable->IsOverflowing(); + break; + case HTML_CAPTION_OFF: + break; + case HTML_TABLEHEADER_ON: + case HTML_TABLEDATA_ON: + SkipToken( -1 ); + BuildTableRow( pCurTable, sal_False, pSaveStruct->eAdjust, + pSaveStruct->eVertOri ); + bDone = pTable->IsOverflowing(); + break; + case HTML_TABLEROW_ON: + BuildTableRow( pCurTable, sal_True, pSaveStruct->eAdjust, + pSaveStruct->eVertOri ); + bDone = pTable->IsOverflowing(); + break; + case HTML_MULTICOL_ON: + // spaltige Rahmen koennen wir hier leider nicht einguegen + break; + case HTML_FORM_ON: + NewForm( sal_False ); // keinen neuen Absatz aufmachen! + break; + case HTML_FORM_OFF: + EndForm( sal_False ); // keinen neuen Absatz aufmachen! + break; + case HTML_TEXTTOKEN: + // Blank-Strings sind Folge von CR+LF und kein Text + if( (pCurTable->GetContext() || + !pCurTable->HasParentSection()) && + 1==aToken.Len() && ' '==aToken.GetChar(0) ) + break; + default: + pCurTable->MakeParentContents(); + NextToken( nToken ); + } + + ASSERT( !bPending || !pPendStack, + "SwHTMLParser::BuildTableSection: Es gibt wieder einen Pend-Stack" ); + bPending = sal_False; + if( IsParserWorking() ) + SaveState( 0 ); + + if( !bDone ) + nToken = GetNextToken(); + } + + if( SVPAR_PENDING == GetStatus() ) + { + pPendStack = new SwPendingStack( bHead ? HTML_THEAD_ON + : HTML_TBODY_ON, pPendStack ); + pPendStack->pData = pSaveStruct; + } + else + { + pCurTable->CloseSection( bHead ); + delete pSaveStruct; + } + + // wir stehen jetzt (wahrscheinlich) vor <TBODY>,... oder </TABLE> +} + +struct _TblColGrpSaveStruct : public SwPendingStackData +{ + sal_uInt16 nColGrpSpan; + sal_uInt16 nColGrpWidth; + sal_Bool bRelColGrpWidth; + SvxAdjust eColGrpAdjust; + sal_Int16 eColGrpVertOri; + + inline _TblColGrpSaveStruct(); + + + inline void CloseColGroup( HTMLTable *pTable ); +}; + +inline _TblColGrpSaveStruct::_TblColGrpSaveStruct() : + nColGrpSpan( 1 ), nColGrpWidth( 0 ), + bRelColGrpWidth( sal_False ), eColGrpAdjust( SVX_ADJUST_END ), + eColGrpVertOri( text::VertOrientation::TOP ) +{} + + +inline void _TblColGrpSaveStruct::CloseColGroup( HTMLTable *pTable ) +{ + pTable->CloseColGroup( nColGrpSpan, nColGrpWidth, + bRelColGrpWidth, eColGrpAdjust, eColGrpVertOri ); +} + +void SwHTMLParser::BuildTableColGroup( HTMLTable *pCurTable, + sal_Bool bReadOptions ) +{ + // <COLGROUP> wurde bereits gelesen, wenn bReadOptions + + if( !IsParserWorking() && !pPendStack ) + return; + + int nToken = 0; + sal_Bool bPending = sal_False; + _TblColGrpSaveStruct* pSaveStruct; + + if( pPendStack ) + { + pSaveStruct = (_TblColGrpSaveStruct*)pPendStack->pData; + + SwPendingStack* pTmp = pPendStack->pNext; + delete pPendStack; + pPendStack = pTmp; + nToken = pPendStack ? pPendStack->nToken : GetSaveToken(); + bPending = SVPAR_ERROR == eState && pPendStack != 0; + + SaveState( nToken ); + } + else + { + + pSaveStruct = new _TblColGrpSaveStruct; + if( bReadOptions ) + { + const HTMLOptions *pColGrpOptions = GetOptions(); + for( sal_uInt16 i = pColGrpOptions->Count(); i; ) + { + const HTMLOption *pColGrpOption = (*pColGrpOptions)[--i]; + switch( pColGrpOption->GetToken() ) + { + case HTML_O_ID: + InsertBookmark( pColGrpOption->GetString() ); + break; + case HTML_O_SPAN: + pSaveStruct->nColGrpSpan = (sal_uInt16)pColGrpOption->GetNumber(); + break; + case HTML_O_WIDTH: + pSaveStruct->nColGrpWidth = (sal_uInt16)pColGrpOption->GetNumber(); + pSaveStruct->bRelColGrpWidth = + (pColGrpOption->GetString().Search('*') != STRING_NOTFOUND); + break; + case HTML_O_ALIGN: + pSaveStruct->eColGrpAdjust = + (SvxAdjust)pColGrpOption->GetEnum( aHTMLPAlignTable, + static_cast< sal_uInt16 >(pSaveStruct->eColGrpAdjust) ); + break; + case HTML_O_VALIGN: + pSaveStruct->eColGrpVertOri = + pColGrpOption->GetEnum( aHTMLTblVAlignTable, + pSaveStruct->eColGrpVertOri ); + break; + } + } + } + // ist beim ersten GetNextToken schon pending, muss bei + // wiederaufsetzen auf jedenfall neu gelesen werden! + SaveState( 0 ); + } + + if( !nToken ) + nToken = GetNextToken(); // naechstes Token + + sal_Bool bDone = sal_False; + while( (IsParserWorking() && !bDone) || bPending ) + { + SaveState( nToken ); + + nToken = FilterToken( nToken ); + + ASSERT( pPendStack || !bCallNextToken || + pCurTable->GetContext() || pCurTable->HasParentSection(), + "Wo ist die Section gebieben?" ); + if( !pPendStack && bCallNextToken && + (pCurTable->GetContext() || pCurTable->HasParentSection()) ) + { + // NextToken direkt aufrufen (z.B. um den Inhalt von + // Floating-Frames oder Applets zu ignorieren) + NextToken( nToken ); + } + else switch( nToken ) + { + case HTML_TABLE_ON: + if( !pCurTable->GetContext() ) + { + SkipToken( -1 ); + bDone = sal_True; + } +// else +// { +// NextToken( nToken ); +// } + break; + case HTML_COLGROUP_ON: + case HTML_THEAD_ON: + case HTML_TFOOT_ON: + case HTML_TBODY_ON: + case HTML_TABLEROW_ON: + case HTML_TABLE_OFF: + SkipToken( -1 ); + case HTML_COLGROUP_OFF: + bDone = sal_True; + break; + case HTML_COL_ON: + { + sal_uInt16 nColSpan = 1; + sal_uInt16 nColWidth = pSaveStruct->nColGrpWidth; + sal_Bool bRelColWidth = pSaveStruct->bRelColGrpWidth; + SvxAdjust eColAdjust = pSaveStruct->eColGrpAdjust; + sal_Int16 eColVertOri = pSaveStruct->eColGrpVertOri; + + const HTMLOptions *pColOptions = GetOptions(); + for( sal_uInt16 i = pColOptions->Count(); i; ) + { + const HTMLOption *pColOption = (*pColOptions)[--i]; + switch( pColOption->GetToken() ) + { + case HTML_O_ID: + InsertBookmark( pColOption->GetString() ); + break; + case HTML_O_SPAN: + nColSpan = (sal_uInt16)pColOption->GetNumber(); + break; + case HTML_O_WIDTH: + nColWidth = (sal_uInt16)pColOption->GetNumber(); + bRelColWidth = + (pColOption->GetString().Search('*') != STRING_NOTFOUND); + break; + case HTML_O_ALIGN: + eColAdjust = + (SvxAdjust)pColOption->GetEnum( aHTMLPAlignTable, + static_cast< sal_uInt16 >(eColAdjust) ); + break; + case HTML_O_VALIGN: + eColVertOri = + pColOption->GetEnum( aHTMLTblVAlignTable, + eColVertOri ); + break; + } + } + pCurTable->InsertCol( nColSpan, nColWidth, bRelColWidth, + eColAdjust, eColVertOri ); + + // die Angaben in <COLGRP> sollen ignoriert werden, wenn + // <COL>-Elemente existieren + pSaveStruct->nColGrpSpan = 0; + } + break; + case HTML_COL_OFF: + break; // Ignorieren + case HTML_MULTICOL_ON: + // spaltige Rahmen koennen wir hier leider nicht einguegen + break; + case HTML_TEXTTOKEN: + if( (pCurTable->GetContext() || + !pCurTable->HasParentSection()) && + 1==aToken.Len() && ' '==aToken.GetChar(0) ) + break; + default: + pCurTable->MakeParentContents(); + NextToken( nToken ); + } + + ASSERT( !bPending || !pPendStack, + "SwHTMLParser::BuildTableColGrp: Es gibt wieder einen Pend-Stack" ); + bPending = sal_False; + if( IsParserWorking() ) + SaveState( 0 ); + + if( !bDone ) + nToken = GetNextToken(); + } + + if( SVPAR_PENDING == GetStatus() ) + { + pPendStack = new SwPendingStack( HTML_COL_ON, pPendStack ); + pPendStack->pData = pSaveStruct; + } + else + { + pSaveStruct->CloseColGroup( pCurTable ); + delete pSaveStruct; + } +} + +class _CaptionSaveStruct : public _SectionSaveStruct +{ + SwPosition aSavePos; + SwHTMLNumRuleInfo aNumRuleInfo; // gueltige Numerierung + +public: + + _HTMLAttrTable aAttrTab; // und die Attribute + + _CaptionSaveStruct( SwHTMLParser& rParser, const SwPosition& rPos ) : + _SectionSaveStruct( rParser ), aSavePos( rPos ) + { + rParser.SaveAttrTab( aAttrTab ); + + // Die aktuelle Numerierung wurde gerettet und muss nur + // noch beendet werden. + aNumRuleInfo.Set( rParser.GetNumInfo() ); + rParser.GetNumInfo().Clear(); + } + + const SwPosition& GetPos() const { return aSavePos; } + + void RestoreAll( SwHTMLParser& rParser ) + { + // Die alten Stack wiederherstellen + Restore( rParser ); + + // Die alte Attribut-Tabelle wiederherstellen + rParser.RestoreAttrTab( aAttrTab ); + + // Die alte Numerierung wieder aufspannen + rParser.GetNumInfo().Set( aNumRuleInfo ); + } + + virtual ~_CaptionSaveStruct(); +}; + +_CaptionSaveStruct::~_CaptionSaveStruct() +{} + +void SwHTMLParser::BuildTableCaption( HTMLTable *pCurTable ) +{ + // <CAPTION> wurde bereits gelesen + + if( !IsParserWorking() && !pPendStack ) + return; + + int nToken = 0; + _CaptionSaveStruct* pSaveStruct; + + if( pPendStack ) + { + pSaveStruct = (_CaptionSaveStruct*)pPendStack->pData; + + SwPendingStack* pTmp = pPendStack->pNext; + delete pPendStack; + pPendStack = pTmp; + nToken = pPendStack ? pPendStack->nToken : GetSaveToken(); + ASSERT( !pPendStack, "Wo kommt hier ein Pending-Stack her?" ); + + SaveState( nToken ); + } + else + { + if( pTable->IsOverflowing() ) + { + SaveState( 0 ); + return; + } + + sal_Bool bTop = sal_True; + const HTMLOptions *pHTMLOptions = GetOptions(); + for ( sal_uInt16 i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + if( HTML_O_ALIGN == pOption->GetToken() ) + { + if( pOption->GetString().EqualsIgnoreCaseAscii(OOO_STRING_SVTOOLS_HTML_VA_bottom)) + bTop = sal_False; + } + } + + // Alte PaM-Position retten. + pSaveStruct = new _CaptionSaveStruct( *this, *pPam->GetPoint() ); + + // Eine Text-Section im Icons-Bereich als Container fuer die + // Ueberschrift anlegen und PaM dort reinstellen. + const SwStartNode *pStNd; + if( pTable == pCurTable ) + pStNd = InsertTempTableCaptionSection(); + else + pStNd = InsertTableSection( RES_POOLCOLL_TEXT ); + + _HTMLAttrContext *pCntxt = new _HTMLAttrContext( HTML_CAPTION_ON ); + + // Tabellen-Ueberschriften sind immer zentriert. + NewAttr( &aAttrTab.pAdjust, SvxAdjustItem(SVX_ADJUST_CENTER, RES_PARATR_ADJUST) ); + + _HTMLAttrs &rAttrs = pCntxt->GetAttrs(); + rAttrs.Insert( aAttrTab.pAdjust, rAttrs.Count() ); + + PushContext( pCntxt ); + + // StartNode der Section an der Tabelle merken. + pCurTable->SetCaption( pStNd, bTop ); + + // ist beim ersten GetNextToken schon pending, muss bei + // wiederaufsetzen auf jedenfall neu gelesen werden! + SaveState( 0 ); + } + + if( !nToken ) + nToken = GetNextToken(); // naechstes Token + + // </CAPTION> wird laut DTD benoetigt + sal_Bool bDone = sal_False; + while( IsParserWorking() && !bDone ) + { + SaveState( nToken ); + + nToken = FilterToken( nToken ); + + switch( nToken ) + { + case HTML_TABLE_ON: + if( !pPendStack ) + { + pSaveStruct->pTable = pTable; + sal_Bool bHasToFly = pSaveStruct->pTable!=pCurTable; + BuildTable( pCurTable->GetTableAdjust( sal_True ), + sal_False, sal_True, sal_True, bHasToFly ); + } + else + { + BuildTable( SVX_ADJUST_END ); + } + if( SVPAR_PENDING != GetStatus() ) + { + pTable = pSaveStruct->pTable; + } + break; + case HTML_TABLE_OFF: + case HTML_COLGROUP_ON: + case HTML_THEAD_ON: + case HTML_TFOOT_ON: + case HTML_TBODY_ON: + case HTML_TABLEROW_ON: + SkipToken( -1 ); + bDone = sal_True; + break; + + case HTML_CAPTION_OFF: + bDone = sal_True; + break; + default: + int nNxtToken = nToken; + if( pPendStack ) + { + SwPendingStack* pTmp = pPendStack->pNext; + delete pPendStack; + pPendStack = pTmp; + + ASSERT( !pTmp, "weiter kann es nicht gehen!" ); + nNxtToken = 0; // neu lesen + } + + if( IsParserWorking() ) + NextToken( nToken ); + break; + } + + if( IsParserWorking() ) + SaveState( 0 ); + + if( !bDone ) + nToken = GetNextToken(); + } + + if( SVPAR_PENDING==GetStatus() ) + { + pPendStack = new SwPendingStack( HTML_CAPTION_ON, pPendStack ); + pPendStack->pData = pSaveStruct; + return; + } + + // Alle noch offenen Kontexte beenden + while( aContexts.Count() > nContextStAttrMin+1 ) + { + _HTMLAttrContext *pCntxt = PopContext(); + EndContext( pCntxt ); + delete pCntxt; + } + + // LF am Absatz-Ende entfernen + sal_Bool bLFStripped = StripTrailingLF() > 0; + + if( pTable==pCurTable ) + { + // Beim spaeteren verschieben der Beschriftung vor oder hinter + // die Tabelle wird der letzte Absatz nicht mitverschoben. + // Deshalb muss sich am Ende der Section immer ein leerer + // Absatz befinden. + if( pPam->GetPoint()->nContent.GetIndex() || bLFStripped ) + AppendTxtNode( AM_NOSPACE ); + } + else + { + // LFs am Absatz-Ende entfernen + if( !pPam->GetPoint()->nContent.GetIndex() && !bLFStripped ) + StripTrailingPara(); + } + + // falls fuer die Zelle eine Ausrichtung gesetzt wurde, muessen + // wir die beenden + _HTMLAttrContext *pCntxt = PopContext(); + EndContext( pCntxt ); + delete pCntxt; + + SetAttr( sal_False ); + + // Stacks und Attribut-Tabelle wiederherstellen + pSaveStruct->RestoreAll( *this ); + + // PaM wiederherstellen. + *pPam->GetPoint() = pSaveStruct->GetPos(); + + delete pSaveStruct; +} + +class _TblSaveStruct : public SwPendingStackData +{ +public: + HTMLTable *pCurTable; + + _TblSaveStruct( HTMLTable *pCurTbl ) : + pCurTable( pCurTbl ) + {} + + virtual ~_TblSaveStruct(); + + // Aufbau der Tabelle anstossen und die Tabelle ggf. in einen + // Rahmen packen. Wenn sal_True zurueckgegeben wird muss noch ein + // Absatz eingefuegt werden! + void MakeTable( sal_uInt16 nWidth, SwPosition& rPos, SwDoc *pDoc ); +}; + +_TblSaveStruct::~_TblSaveStruct() +{} + + +void _TblSaveStruct::MakeTable( sal_uInt16 nWidth, SwPosition& rPos, SwDoc *pDoc ) +{ + pCurTable->MakeTable( 0, nWidth ); + + _HTMLTableContext *pTCntxt = pCurTable->GetContext(); + ASSERT( pTCntxt, "Wo ist der Tabellen-Kontext" ); + + SwTableNode *pTblNd = pTCntxt->GetTableNode(); + ASSERT( pTblNd, "Wo ist der Tabellen-Node" ); + + if( pDoc->GetRootFrm() && pTblNd ) + { + // Existiert schon ein Layout, dann muss an dieser Tabelle die + // BoxFrames neu erzeugt werden. + + if( pTCntxt->GetFrmFmt() ) + { + pTCntxt->GetFrmFmt()->DelFrms(); + pTblNd->DelFrms(); + pTCntxt->GetFrmFmt()->MakeFrms(); + } + else + { + pTblNd->DelFrms(); + SwNodeIndex aIdx( *pTblNd->EndOfSectionNode(), 1 ); + ASSERT( aIdx.GetIndex() <= pTCntxt->GetPos()->nNode.GetIndex(), + "unerwarteter Node fuer das Tabellen-Layout" ); + pTblNd->MakeFrms( &aIdx ); + } + } + + rPos = *pTCntxt->GetPos(); +} + + +HTMLTableOptions::HTMLTableOptions( const HTMLOptions *pOptions, + SvxAdjust eParentAdjust ) : + nCols( 0 ), + nWidth( 0 ), nHeight( 0 ), + nCellPadding( USHRT_MAX ), nCellSpacing( USHRT_MAX ), + nBorder( USHRT_MAX ), + nHSpace( 0 ), nVSpace( 0 ), + eAdjust( eParentAdjust ), eVertOri( text::VertOrientation::CENTER ), + eFrame( HTML_TF_VOID ), eRules( HTML_TR_NONE ), + bPrcWidth( sal_False ), + bTableAdjust( sal_False ), + bBGColor( sal_False ), + aBorderColor( COL_GRAY ) +{ + sal_Bool bBorderColor = sal_False; + sal_Bool bHasFrame = sal_False, bHasRules = sal_False; + + for( sal_uInt16 i = pOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_COLS: + nCols = (sal_uInt16)pOption->GetNumber(); + break; + case HTML_O_WIDTH: + nWidth = (sal_uInt16)pOption->GetNumber(); + bPrcWidth = (pOption->GetString().Search('%') != STRING_NOTFOUND); + if( bPrcWidth && nWidth>100 ) + nWidth = 100; + break; + case HTML_O_HEIGHT: + nHeight = (sal_uInt16)pOption->GetNumber(); + if( pOption->GetString().Search('%') != STRING_NOTFOUND ) + nHeight = 0; // keine %-Anagben benutzen!!! + break; + case HTML_O_CELLPADDING: + nCellPadding = (sal_uInt16)pOption->GetNumber(); + break; + case HTML_O_CELLSPACING: + nCellSpacing = (sal_uInt16)pOption->GetNumber(); + break; + case HTML_O_ALIGN: + { + sal_uInt16 nAdjust = static_cast< sal_uInt16 >(eAdjust); + if( pOption->GetEnum( nAdjust, aHTMLPAlignTable ) ) + { + eAdjust = (SvxAdjust)nAdjust; + bTableAdjust = sal_True; + } + } + break; + case HTML_O_VALIGN: + eVertOri = pOption->GetEnum( aHTMLTblVAlignTable, eVertOri ); + break; + case HTML_O_BORDER: + // BORDER und BORDER=BORDER wie BORDER=1 behandeln + if( pOption->GetString().Len() && + !pOption->GetString().EqualsIgnoreCaseAscii(OOO_STRING_SVTOOLS_HTML_O_border) ) + nBorder = (sal_uInt16)pOption->GetNumber(); + else + nBorder = 1; + + if( !bHasFrame ) + eFrame = ( nBorder ? HTML_TF_BOX : HTML_TF_VOID ); + if( !bHasRules ) + eRules = ( nBorder ? HTML_TR_ALL : HTML_TR_NONE ); + break; + case HTML_O_FRAME: + eFrame = pOption->GetTableFrame(); + bHasFrame = sal_True; + break; + case HTML_O_RULES: + eRules = pOption->GetTableRules(); + bHasRules = sal_True; + break; + case HTML_O_BGCOLOR: + // Leere BGCOLOR bei <TABLE>, <TR> und <TD>/<TH> wie Netscape + // ignorieren, bei allen anderen Tags *wirklich* nicht. + if( pOption->GetString().Len() ) + { + pOption->GetColor( aBGColor ); + bBGColor = sal_True; + } + break; + case HTML_O_BACKGROUND: + aBGImage = pOption->GetString(); + break; + case HTML_O_BORDERCOLOR: + pOption->GetColor( aBorderColor ); + bBorderColor = sal_True; + break; + case HTML_O_BORDERCOLORDARK: + if( !bBorderColor ) + pOption->GetColor( aBorderColor ); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + case HTML_O_DIR: + aDir = pOption->GetString(); + break; + case HTML_O_HSPACE: + nHSpace = (sal_uInt16)pOption->GetNumber(); + break; + case HTML_O_VSPACE: + nVSpace = (sal_uInt16)pOption->GetNumber(); + break; + } + } + + if( nCols && !nWidth ) + { + nWidth = 100; + bPrcWidth = sal_True; + } + + // Wenn BORDER=0 oder kein BORDER gegeben ist, daan darf es auch + // keine Umrandung geben + if( 0==nBorder || USHRT_MAX==nBorder ) + { + eFrame = HTML_TF_VOID; + eRules = HTML_TR_NONE; + } +} + + +HTMLTable *SwHTMLParser::BuildTable( SvxAdjust eParentAdjust, + sal_Bool bIsParentHead, + sal_Bool bHasParentSection, + sal_Bool bMakeTopSubTable, + sal_Bool bHasToFly ) +{ + if( !IsParserWorking() && !pPendStack ) + return 0; + + int nToken = 0; + sal_Bool bPending = sal_False; + _TblSaveStruct* pSaveStruct; + + if( pPendStack ) + { + pSaveStruct = (_TblSaveStruct*)pPendStack->pData; + + SwPendingStack* pTmp = pPendStack->pNext; + delete pPendStack; + pPendStack = pTmp; + nToken = pPendStack ? pPendStack->nToken : GetSaveToken(); + bPending = SVPAR_ERROR == eState && pPendStack != 0; + + SaveState( nToken ); + } + else + { + pTable = 0; + HTMLTableOptions *pTblOptions = + new HTMLTableOptions( GetOptions(), eParentAdjust ); + + if( pTblOptions->aId.Len() ) + InsertBookmark( pTblOptions->aId ); + + HTMLTable *pCurTable = new HTMLTable( this, pTable, + bIsParentHead, + bHasParentSection, + bMakeTopSubTable, + bHasToFly, + pTblOptions ); + if( !pTable ) + pTable = pCurTable; + + pSaveStruct = new _TblSaveStruct( pCurTable ); + + delete pTblOptions; + + // ist beim ersten GetNextToken schon pending, muss bei + // wiederaufsetzen auf jedenfall neu gelesen werden! + SaveState( 0 ); + } + + HTMLTable *pCurTable = pSaveStruct->pCurTable; + + // </TABLE> wird laut DTD benoetigt + if( !nToken ) + nToken = GetNextToken(); // naechstes Token + + sal_Bool bDone = sal_False; + while( (IsParserWorking() && !bDone) || bPending ) + { + SaveState( nToken ); + + nToken = FilterToken( nToken ); + + ASSERT( pPendStack || !bCallNextToken || + pCurTable->GetContext() || pCurTable->HasParentSection(), + "Wo ist die Section gebieben?" ); + if( !pPendStack && bCallNextToken && + (pCurTable->GetContext() || pCurTable->HasParentSection()) ) + { + // NextToken direkt aufrufen (z.B. um den Inhalt von + // Floating-Frames oder Applets zu ignorieren) + NextToken( nToken ); + } + else switch( nToken ) + { + case HTML_TABLE_ON: + if( !pCurTable->GetContext() ) + { + // Wenn noch keine Tabelle eingefuegt wurde, + // die naechste Tabelle lesen + SkipToken( -1 ); + bDone = sal_True; + } +// else +// { +// NextToken( nToken ); +// } + break; + case HTML_TABLE_OFF: + bDone = sal_True; + break; + case HTML_CAPTION_ON: + BuildTableCaption( pCurTable ); + bDone = pTable->IsOverflowing(); + break; + case HTML_COL_ON: + SkipToken( -1 ); + BuildTableColGroup( pCurTable, sal_False ); + break; + case HTML_COLGROUP_ON: + BuildTableColGroup( pCurTable, sal_True ); + break; + case HTML_TABLEROW_ON: + case HTML_TABLEHEADER_ON: + case HTML_TABLEDATA_ON: + SkipToken( -1 ); + BuildTableSection( pCurTable, sal_False, sal_False ); + bDone = pTable->IsOverflowing(); + break; + case HTML_THEAD_ON: + case HTML_TFOOT_ON: + case HTML_TBODY_ON: + BuildTableSection( pCurTable, sal_True, HTML_THEAD_ON==nToken ); + bDone = pTable->IsOverflowing(); + break; + case HTML_MULTICOL_ON: + // spaltige Rahmen koennen wir hier leider nicht einguegen + break; + case HTML_FORM_ON: + NewForm( sal_False ); // keinen neuen Absatz aufmachen! + break; + case HTML_FORM_OFF: + EndForm( sal_False ); // keinen neuen Absatz aufmachen! + break; + case HTML_TEXTTOKEN: + // Blank-Strings sind u. U. eine Folge von CR+LF und kein Text + if( (pCurTable->GetContext() || + !pCurTable->HasParentSection()) && + 1==aToken.Len() && ' '==aToken.GetChar(0) ) + break; + default: + pCurTable->MakeParentContents(); + NextToken( nToken ); + break; + } + + ASSERT( !bPending || !pPendStack, + "SwHTMLParser::BuildTable: Es gibt wieder einen Pend-Stack" ); + bPending = sal_False; + if( IsParserWorking() ) + SaveState( 0 ); + + if( !bDone ) + nToken = GetNextToken(); + } + + if( SVPAR_PENDING == GetStatus() ) + { + pPendStack = new SwPendingStack( HTML_TABLE_ON, pPendStack ); + pPendStack->pData = pSaveStruct; + return 0; + } + + _HTMLTableContext *pTCntxt = pCurTable->GetContext(); + if( pTCntxt ) + { + // Die Tabelle wurde auch angelegt + + // Tabellen-Struktur anpassen + pCurTable->CloseTable(); + + // ausserhalb von Zellen begonnene Kontexte beenden + // muss vor(!) dem Umsetzten der Attribut Tabelle existieren, + // weil die aktuelle danach nicht mehr existiert + while( aContexts.Count() > nContextStAttrMin ) + { + _HTMLAttrContext *pCntxt = PopContext(); + ClearContext( pCntxt ); + delete pCntxt; + } + + nContextStMin = pTCntxt->GetContextStMin(); + nContextStAttrMin = pTCntxt->GetContextStAttrMin(); + + if( pTable==pCurTable ) + { + // Tabellen-Beschriftung setzen + const SwStartNode *pCapStNd = pTable->GetCaptionStartNode(); + if( pCapStNd ) + { + // Der letzte Absatz der Section wird nie mitkopiert. Deshalb + // muss die Section mindestens zwei Absaetze enthalten. + + if( pCapStNd->EndOfSectionIndex() - pCapStNd->GetIndex() > 2 ) + { + // Start-Node und letzten Absatz nicht mitkopieren. + SwNodeRange aSrcRg( *pCapStNd, 1, + *pCapStNd->EndOfSectionNode(), -1 ); + + sal_Bool bTop = pTable->IsTopCaption(); + SwStartNode *pTblStNd = pTCntxt->GetTableNode(); + + ASSERT( pTblStNd, "Wo ist der Tabellen-Node" ); + ASSERT( pTblStNd==pPam->GetNode()->FindTableNode(), + "Stehen wir in der falschen Tabelle?" ); + + SwNode* pNd; + if( bTop ) + pNd = pTblStNd; + else + pNd = pTblStNd->EndOfSectionNode(); + SwNodeIndex aDstIdx( *pNd, bTop ? 0 : 1 ); + + pDoc->MoveNodeRange( aSrcRg, aDstIdx, + IDocumentContentOperations::DOC_MOVEDEFAULT ); + + // Wenn die Caption vor der Tabelle eingefuegt wurde muss + // eine an der Tabelle gestzte Seitenvorlage noch in den + // ersten Absatz der Ueberschrift verschoben werden. + // Ausserdem muessen alle gemerkten Indizes, die auf den + // Tabellen-Node zeigen noch verschoben werden. + if( bTop ) + { + MovePageDescAttrs( pTblStNd, aSrcRg.aStart.GetIndex(), + sal_False ); + } + } + + // Die Section wird jetzt nicht mehr gebraucht. + pPam->SetMark(); + pPam->DeleteMark(); + pDoc->DeleteSection( (SwStartNode *)pCapStNd ); + pTable->SetCaption( 0, sal_False ); + } + + // SwTable aufbereiten + sal_uInt16 nBrowseWidth = (sal_uInt16)GetCurrentBrowseWidth(); + pSaveStruct->MakeTable( nBrowseWidth, *pPam->GetPoint(), pDoc ); + +#ifdef TEST_RESIZE + const SwTable *pSwTable = pTable->GetSwTable(); + SwHTMLTableLayout *pLayoutInfo = + pSwTable ? ((SwTable *)pSwTable)->GetHTMLTableLayout() : 0; + if( pLayoutInfo ) + { + ViewShell *pVSh = CheckActionViewShell(); + if( pVSh ) + { + CallEndAction( sal_False, sal_False ); + CallStartAction( pVSh, sal_False ); + + sal_uInt16 nNewBrwoseWidth = + (sal_uInt16)GetCurrentBrowseWidth(); + if( nBrowseWidth != nNewBrowseWidth ) + pLayoutInfo->Resize( nNewBrowseWidth ); + } + } +#endif + } + + GetNumInfo().Set( pTCntxt->GetNumInfo() ); + pTCntxt->RestorePREListingXMP( *this ); + RestoreAttrTab( pTCntxt->aAttrTab ); + + if( pTable==pCurTable ) + { + // oberen Absatz-Abstand einstellen + bUpperSpace = sal_True; + SetTxtCollAttrs(); + + nParaCnt = nParaCnt - Min(nParaCnt, pTCntxt->GetTableNode()->GetTable().GetTabSortBoxes().Count()); + + // ggfs. eine Tabelle anspringen + if( JUMPTO_TABLE == eJumpTo && pTable->GetSwTable() && + pTable->GetSwTable()->GetFrmFmt()->GetName() == sJmpMark ) + { + bChkJumpMark = sal_True; + eJumpTo = JUMPTO_NONE; + } + + // fix #37886#: Wenn Import abgebrochen wurde kein erneutes Show + // aufrufen, weil die ViewShell schon geloescht wurde! + // fix #41669#: Genuegt nicht. Auch im ACCEPTING_STATE darf + // kein Show aufgerufen werden, weil sonst waehrend des + // Reschedules der Parser zerstoert wird, wenn noch ein + // DataAvailable-Link kommt. Deshalb: Nur im WORKING-State. + if( !nParaCnt && SVPAR_WORKING == GetStatus() ) + Show(); + } + } + else if( pTable==pCurTable ) + { + // Es wurde gar keine Tabelle gelesen. + + // Dann muss eine evtl gelesene Beschriftung noch geloescht werden. + const SwStartNode *pCapStNd = pCurTable->GetCaptionStartNode(); + if( pCapStNd ) + { + pPam->SetMark(); + pPam->DeleteMark(); + pDoc->DeleteSection( (SwStartNode *)pCapStNd ); + pCurTable->SetCaption( 0, sal_False ); + } + } + + if( pTable == pCurTable ) + { + delete pSaveStruct->pCurTable; + pSaveStruct->pCurTable = 0; + pTable = 0; + } + + HTMLTable* pRetTbl = pSaveStruct->pCurTable; + delete pSaveStruct; + + return pRetTbl; +} + + diff --git a/sw/source/filter/html/htmltabw.cxx b/sw/source/filter/html/htmltabw.cxx new file mode 100644 index 000000000000..8560061d9131 --- /dev/null +++ b/sw/source/filter/html/htmltabw.cxx @@ -0,0 +1,1268 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <hintids.hxx> +#include <vcl/svapp.hxx> +#include <svtools/htmlout.hxx> +#include <svtools/htmltokn.h> +#include <svtools/htmlkywd.hxx> +#ifndef _WRKWIN_HXX //autogen +#include <vcl/wrkwin.hxx> +#endif +#include <editeng/ulspitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/brshitem.hxx> +#include <editeng/boxitem.hxx> +#include <com/sun/star/form/XFormsSupplier.hpp> +#include <com/sun/star/form/XForm.hpp> +#include <com/sun/star/form/XImageProducerSupplier.hpp> +#include <com/sun/star/form/XFormController.hpp> +#include <com/sun/star/container/XContainer.hpp> +#include <com/sun/star/container/XIndexContainer.hpp> +#include <com/sun/star/container/XSet.hpp> +#include <fmtornt.hxx> +#include <frmfmt.hxx> +#include <fmtfsize.hxx> +#include <fmtsrnd.hxx> +#include <frmatr.hxx> +#include <doc.hxx> +#include <pam.hxx> +#include <ndtxt.hxx> +#include <swrect.hxx> +#include <cellatr.hxx> +#include <poolfmt.hxx> +#include <swtable.hxx> +#include <htmltbl.hxx> +#include <htmlnum.hxx> +#include <wrthtml.hxx> +#include <wrtswtbl.hxx> +#ifdef DBG_UTIL +#ifndef _VIEWSH_HXX +#include <viewsh.hxx> +#endif +#include <viewopt.hxx> +#endif +#include <sal/types.h> + +//#define MAX_DEPTH (USHRT_MAX) +#define MAX_DEPTH (3) + +using namespace ::com::sun::star; + + +class SwHTMLWrtTable : public SwWriteTable +{ + void Pixelize( sal_uInt16& rValue ); + void PixelizeBorders(); + + void OutTableCell( SwHTMLWriter& rWrt, const SwWriteTableCell *pCell, + sal_Bool bOutVAlign ) const; + + void OutTableCells( SwHTMLWriter& rWrt, + const SwWriteTableCells& rCells, + const SvxBrushItem *pBrushItem ) const; + + virtual sal_Bool ShouldExpandSub( const SwTableBox *pBox, + sal_Bool bExpandedBefore, sal_uInt16 nDepth ) const; + + static sal_Bool HasTabBackground( const SwTableLine& rLine, + sal_Bool bTop, sal_Bool bBottom, sal_Bool bLeft, sal_Bool bRight ); + static sal_Bool HasTabBackground( const SwTableBox& rBox, + sal_Bool bTop, sal_Bool bBottom, sal_Bool bLeft, sal_Bool bRight ); + +public: + SwHTMLWrtTable( const SwTableLines& rLines, long nWidth, sal_uInt32 nBWidth, + sal_Bool bRel, sal_uInt16 nNumOfRowsToRepeat, + sal_uInt16 nLeftSub=0, sal_uInt16 nRightSub=0 ); + SwHTMLWrtTable( const SwHTMLTableLayout *pLayoutInfo ); + + void Write( SwHTMLWriter& rWrt, sal_Int16 eAlign=text::HoriOrientation::NONE, + sal_Bool bTHead=sal_False, const SwFrmFmt *pFrmFmt=0, + const String *pCaption=0, sal_Bool bTopCaption=sal_False, + sal_uInt16 nHSpace=0, sal_uInt16 nVSpace=0 ) const; +}; + + +SwHTMLWrtTable::SwHTMLWrtTable( const SwTableLines& rLines, long nWidth, + sal_uInt32 nBWidth, sal_Bool bRel, sal_uInt16 nNumOfRowsToRepeat, + sal_uInt16 nLSub, sal_uInt16 nRSub ) + : SwWriteTable( rLines, nWidth, nBWidth, bRel, MAX_DEPTH, nLSub, nRSub, nNumOfRowsToRepeat ) +{ + PixelizeBorders(); +} + +SwHTMLWrtTable::SwHTMLWrtTable( const SwHTMLTableLayout *pLayoutInfo ) + : SwWriteTable( pLayoutInfo ) +{ + // Einige Twip-Werte an Pixel-Grenzen anpassen + if( bCollectBorderWidth ) + PixelizeBorders(); +} + +void SwHTMLWrtTable::Pixelize( sal_uInt16& rValue ) +{ + if( rValue && Application::GetDefaultDevice() ) + { + Size aSz( rValue, 0 ); + aSz = Application::GetDefaultDevice()->LogicToPixel( aSz, MapMode(MAP_TWIP) ); + if( !aSz.Width() ) + aSz.Width() = 1; + aSz = Application::GetDefaultDevice()->PixelToLogic( aSz, MapMode(MAP_TWIP) ); + rValue = (sal_uInt16)aSz.Width(); + } +} + +void SwHTMLWrtTable::PixelizeBorders() +{ + Pixelize( nBorder ); + Pixelize( nCellSpacing ); + Pixelize( nCellPadding ); +} + +sal_Bool SwHTMLWrtTable::HasTabBackground( const SwTableBox& rBox, + sal_Bool bTop, sal_Bool bBottom, sal_Bool bLeft, sal_Bool bRight ) +{ + ASSERT( bTop || bBottom || bLeft || bRight, + "HasTabBackground: darf nicht aufgerufen werden" ); + + sal_Bool bRet = sal_False; + if( rBox.GetSttNd() ) + { + const SvxBrushItem& rBrushItem = + rBox.GetFrmFmt()->GetBackground(); + + /// OD 02.09.2002 #99657# + /// The table box has a background, if its background color is not "no fill"/ + /// "auto fill" or it has a background graphic. + bRet = rBrushItem.GetColor() != COL_TRANSPARENT || + rBrushItem.GetGraphicLink() || rBrushItem.GetGraphic(); + } + else + { + const SwTableLines& rLines = rBox.GetTabLines(); + sal_uInt16 nCount = rLines.Count(); + sal_Bool bLeftRight = bLeft || bRight; + for( sal_uInt16 i=0; !bRet && i<nCount; i++ ) + { + sal_Bool bT = bTop && 0 == i; + sal_Bool bB = bBottom && nCount-1 == i; + if( bT || bB || bLeftRight ) + bRet = HasTabBackground( *rLines[i], bT, bB, bLeft, bRight); + } + } + + return bRet; +} + +sal_Bool SwHTMLWrtTable::HasTabBackground( const SwTableLine& rLine, + sal_Bool bTop, sal_Bool bBottom, sal_Bool bLeft, sal_Bool bRight ) +{ + ASSERT( bTop || bBottom || bLeft || bRight, + "HasTabBackground: darf nicht aufgerufen werden" ); + + sal_Bool bRet = sal_False; + const SvxBrushItem& rBrushItem = rLine.GetFrmFmt()->GetBackground(); + /// OD 02.09.2002 #99657# + /// The table line has a background, if its background color is not "no fill"/ + /// "auto fill" or it has a background graphic. + bRet = rBrushItem.GetColor() != COL_TRANSPARENT || + rBrushItem.GetGraphicLink() || rBrushItem.GetGraphic(); + + if( !bRet ) + { + const SwTableBoxes& rBoxes = rLine.GetTabBoxes(); + sal_uInt16 nCount = rBoxes.Count(); + sal_Bool bTopBottom = bTop || bBottom; + for( sal_uInt16 i=0; !bRet && i<nCount; i++ ) + { + sal_Bool bL = bLeft && 0 == i; + sal_Bool bR = bRight && nCount-1 == i; + if( bTopBottom || bL || bR ) + bRet = HasTabBackground( *rBoxes[i], bTop, bBottom, bL, bR ); + } + } + + return bRet; +} + +sal_Bool lcl_WrtHTMLTbl_HasTabBorders( const SwTableLine*& rpLine, void* pPara ); + +sal_Bool lcl_WrtHTMLTbl_HasTabBorders( const SwTableBox*& rpBox, void* pPara ) +{ + sal_Bool *pBorders = (sal_Bool *)pPara; + if( *pBorders ) + return sal_False; + + if( !rpBox->GetSttNd() ) + { + ((SwTableBox *)rpBox)->GetTabLines().ForEach( + &lcl_WrtHTMLTbl_HasTabBorders, pPara ); + } + else + { + const SvxBoxItem& rBoxItem = + (const SvxBoxItem&)rpBox->GetFrmFmt()->GetFmtAttr( RES_BOX ); + + *pBorders = rBoxItem.GetTop() || rBoxItem.GetBottom() || + rBoxItem.GetLeft() || rBoxItem.GetRight(); + } + + return !*pBorders; +} + +sal_Bool lcl_WrtHTMLTbl_HasTabBorders( const SwTableLine*& rpLine, void* pPara ) +{ + sal_Bool *pBorders = (sal_Bool *)pPara; + if( *pBorders ) + return sal_False; + + ((SwTableLine *)rpLine)->GetTabBoxes().ForEach( + &lcl_WrtHTMLTbl_HasTabBorders, pPara ); + return !*pBorders; +} + + +sal_Bool SwHTMLWrtTable::ShouldExpandSub( const SwTableBox *pBox, + sal_Bool bExpandedBefore, + sal_uInt16 nDepth ) const +{ + sal_Bool bExpand = !pBox->GetSttNd() && nDepth>0; + if( bExpand && bExpandedBefore ) + { + // MIB 30.6.97: Wenn schon eine Box expandiert wurde, wird eine + // weitere nur expandiert, wenn sie Umrandungen besitzt. + sal_Bool bBorders = sal_False; + lcl_WrtHTMLTbl_HasTabBorders( pBox, &bBorders ); + if( !bBorders ) + bBorders = HasTabBackground( *pBox, sal_True, sal_True, sal_True, sal_True ); + bExpand = bBorders; + } + + return bExpand; +} + + +// Eine Box als einzelne Zelle schreiben +void SwHTMLWrtTable::OutTableCell( SwHTMLWriter& rWrt, + const SwWriteTableCell *pCell, + sal_Bool bOutVAlign ) const +{ + const SwTableBox *pBox = pCell->GetBox(); + sal_uInt16 nRow = pCell->GetRow(); + sal_uInt16 nCol = pCell->GetCol(); + sal_uInt16 nRowSpan = pCell->GetRowSpan(); + sal_uInt16 nColSpan = pCell->GetColSpan(); + + if ( !nRowSpan ) + return; + + SwWriteTableCol *pCol = aCols[nCol]; + +// sal_Bool bOutWidth = nColSpan>1 || pCol->GetOutWidth(); + sal_Bool bOutWidth = sal_True; //nColSpan==1 && pCol->GetOutWidth(); + + const SwStartNode* pSttNd = pBox->GetSttNd(); + sal_Bool bHead = sal_False; + if( pSttNd ) + { + sal_uLong nNdPos = pSttNd->GetIndex()+1; + + // Art der Zelle (TD/TH) bestimmen + SwNode* pNd; + while( !( pNd = rWrt.pDoc->GetNodes()[nNdPos])->IsEndNode() ) + { + if( pNd->IsTxtNode() ) + { + // nur Absaetzte betrachten, an denen man was erkennt + // Das ist der Fall, wenn die Vorlage eine der Tabellen-Vorlagen + // ist oder von einer der beiden abgelitten ist. + const SwFmt *pFmt = &((SwTxtNode*)pNd)->GetAnyFmtColl(); + sal_uInt16 nPoolId = pFmt->GetPoolFmtId(); + while( !pFmt->IsDefault() && + RES_POOLCOLL_TABLE_HDLN!=nPoolId && + RES_POOLCOLL_TABLE!=nPoolId ) + { + pFmt = pFmt->DerivedFrom(); + nPoolId = pFmt->GetPoolFmtId(); + } + + if( !pFmt->IsDefault() ) + { + bHead = (RES_POOLCOLL_TABLE_HDLN==nPoolId); + break; + } + } + nNdPos++; + } + } + + rWrt.OutNewLine(); // <TH>/<TD> in neue Zeile + ByteString sOut( '<' ); + sOut += (bHead ? OOO_STRING_SVTOOLS_HTML_tableheader : OOO_STRING_SVTOOLS_HTML_tabledata ); + + // ROW- und COLSPAN ausgeben + if( nRowSpan>1 ) + (((sOut += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_rowspan ) += '=') + += ByteString::CreateFromInt32( nRowSpan ); + if( nColSpan > 1 ) + (((sOut += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_colspan ) += '=') + += ByteString::CreateFromInt32( nColSpan ); + +#ifndef PURE_HTML + long nWidth = 0; + sal_uInt32 nPrcWidth = USHRT_MAX; + if( bOutWidth ) + { + if( bLayoutExport ) + { + if( pCell->HasPrcWidthOpt() ) + { + nPrcWidth = pCell->GetWidthOpt(); + } + else + { + nWidth = pCell->GetWidthOpt(); + if( !nWidth ) + bOutWidth = sal_False; + } + } + else + { + if( HasRelWidths() ) + nPrcWidth = (sal_uInt16)GetPrcWidth(nCol,nColSpan); + else + nWidth = GetAbsWidth( nCol, nColSpan ); + } + } + + long nHeight = pCell->GetHeight() > 0 + ? GetAbsHeight( pCell->GetHeight(), nRow, nRowSpan ) + : 0; + Size aPixelSz( nWidth, nHeight ); + + // WIDTH ausgeben (Grrr: nur fuer Netscape) + if( (aPixelSz.Width() || aPixelSz.Height()) && Application::GetDefaultDevice() ) + { + Size aOldSz( aPixelSz ); + aPixelSz = Application::GetDefaultDevice()->LogicToPixel( aPixelSz, + MapMode(MAP_TWIP) ); + if( aOldSz.Width() && !aPixelSz.Width() ) + aPixelSz.Width() = 1; + if( aOldSz.Height() && !aPixelSz.Height() ) + aPixelSz.Height() = 1; + } + + // WIDTH ausgeben: Aus Layout oder berechnet + if( bOutWidth ) + { + ((sOut += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_width ) += '='; + if( nPrcWidth != USHRT_MAX ) + (sOut += ByteString::CreateFromInt32(nPrcWidth)) += '%'; + else + sOut += ByteString::CreateFromInt32(aPixelSz.Width()); + if( !bLayoutExport && nColSpan==1 ) + pCol->SetOutWidth( sal_False ); + } + + if( nHeight ) + { + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_height) += '=') + += ByteString::CreateFromInt32(aPixelSz.Height()); + } +#endif + + const SfxItemSet& rItemSet = pBox->GetFrmFmt()->GetAttrSet(); + const SfxPoolItem *pItem; + + // ALIGN wird jetzt nur noch an den Absaetzen ausgegeben + + // VALIGN ausgeben + if( bOutVAlign ) + { + sal_Int16 eVertOri = pCell->GetVertOri(); + if( text::VertOrientation::TOP==eVertOri || text::VertOrientation::BOTTOM==eVertOri ) + { + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_valign) += '=') + += (text::VertOrientation::TOP==eVertOri ? OOO_STRING_SVTOOLS_HTML_VA_top : OOO_STRING_SVTOOLS_HTML_VA_bottom); + } + } + + rWrt.Strm() << sOut.GetBuffer(); + sOut.Erase(); + + rWrt.bTxtAttr = sal_False; + rWrt.bOutOpts = sal_True; + const SvxBrushItem *pBrushItem = 0; + if( SFX_ITEM_SET==rItemSet.GetItemState( RES_BACKGROUND, sal_False, &pItem ) ) + { + pBrushItem = (const SvxBrushItem *)pItem; + } + if( !pBrushItem ) + pBrushItem = pCell->GetBackground(); + + if( pBrushItem ) + { + // Hintergrund ausgeben + String aDummy; + rWrt.OutBackground( pBrushItem, aDummy, sal_False ); + + if( rWrt.bCfgOutStyles ) + OutCSS1_TableBGStyleOpt( rWrt, *pBrushItem ); + } + + sal_uInt32 nNumFmt = 0; + double nValue = 0.0; + sal_Bool bNumFmt = sal_False, bValue = sal_False; + if( SFX_ITEM_SET==rItemSet.GetItemState( RES_BOXATR_FORMAT, sal_False, &pItem ) ) + { + nNumFmt = ((const SwTblBoxNumFormat *)pItem)->GetValue(); + bNumFmt = sal_True; + } + if( SFX_ITEM_SET==rItemSet.GetItemState( RES_BOXATR_VALUE, sal_False, &pItem ) ) + { + nValue = ((const SwTblBoxValue *)pItem)->GetValue(); + bValue = sal_True; + if( !bNumFmt ) + nNumFmt = pBox->GetFrmFmt()->GetTblBoxNumFmt().GetValue(); + } + + if( bNumFmt || bValue ) + sOut = HTMLOutFuncs::CreateTableDataOptionsValNum( sOut, + bValue, nValue, nNumFmt, *rWrt.pDoc->GetNumberFormatter(), + rWrt.eDestEnc, &rWrt.aNonConvertableCharacters ); + sOut += '>'; + rWrt.Strm() << sOut.GetBuffer(); + rWrt.bLFPossible = sal_True; + + rWrt.IncIndentLevel(); // den Inhalt von <TD>...</TD> einruecken + + if( pSttNd ) + { + HTMLSaveData aSaveData( rWrt, pSttNd->GetIndex()+1, + pSttNd->EndOfSectionIndex() ); + rWrt.Out_SwDoc( rWrt.pCurPam ); + } + else + { + sal_uInt16 nTWidth; + sal_uInt32 nBWidth; + sal_uInt16 nLSub, nRSub; + if( HasRelWidths() ) + { + nTWidth = 100; + nBWidth = GetRawWidth( nCol, nColSpan ); + nLSub = 0; + nRSub = 0; + } + else + { + nTWidth = GetAbsWidth( nCol, nColSpan ); + nBWidth = nTWidth; + nLSub = GetLeftSpace( nCol ); + nRSub = GetRightSpace( nCol, nColSpan ); + } + + SwHTMLWrtTable aTableWrt( pBox->GetTabLines(), nTWidth, + nBWidth, HasRelWidths(), nLSub, nRSub ); + aTableWrt.Write( rWrt ); + } + + rWrt.DecIndentLevel(); // den Inhalt von <TD>...</TD> einruecken + + if( rWrt.bLFPossible ) + rWrt.OutNewLine(); + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), bHead ? OOO_STRING_SVTOOLS_HTML_tableheader + : OOO_STRING_SVTOOLS_HTML_tabledata, + sal_False ); + rWrt.bLFPossible = sal_True; +} + + +// Eine Line als Zeilen ausgeben +void SwHTMLWrtTable::OutTableCells( SwHTMLWriter& rWrt, + const SwWriteTableCells& rCells, + const SvxBrushItem *pBrushItem ) const +{ + // Wenn die Zeile mehr als eine Zelle nethaelt und alle Zellen + // die gleiche Ausrichtung besitzen, das VALIGN an der Zeile statt der + // Zelle ausgeben + sal_Int16 eRowVertOri = text::VertOrientation::NONE; + if( rCells.Count() > 1 ) + { + for( sal_uInt16 nCell = 0; nCell<rCells.Count(); nCell++ ) + { + sal_Int16 eCellVertOri = rCells[nCell]->GetVertOri(); + if( 0==nCell ) + { + eRowVertOri = eCellVertOri; + } + else if( eRowVertOri != eCellVertOri ) + { + eRowVertOri = text::VertOrientation::NONE; + break; + } + } + } + + rWrt.OutNewLine(); // <TR> in neuer Zeile + rWrt.Strm() << '<' << OOO_STRING_SVTOOLS_HTML_tablerow; + if( pBrushItem ) + { + String aDummy; + rWrt.OutBackground( pBrushItem, aDummy, sal_False ); + + rWrt.bTxtAttr = sal_False; + rWrt.bOutOpts = sal_True; + if( rWrt.bCfgOutStyles ) + OutCSS1_TableBGStyleOpt( rWrt, *pBrushItem ); + } + + if( text::VertOrientation::TOP==eRowVertOri || text::VertOrientation::BOTTOM==eRowVertOri ) + { + ByteString sOut( ' ' ); + ((sOut += OOO_STRING_SVTOOLS_HTML_O_valign) += '=') + += (text::VertOrientation::TOP==eRowVertOri ? OOO_STRING_SVTOOLS_HTML_VA_top : OOO_STRING_SVTOOLS_HTML_VA_bottom); + rWrt.Strm() << sOut.GetBuffer(); + } + + rWrt.Strm() << '>'; + + rWrt.IncIndentLevel(); // Inhalt von <TR>...</TR> einruecken + + for( sal_uInt16 nCell = 0; nCell<rCells.Count(); nCell++ ) + OutTableCell( rWrt, rCells[nCell], text::VertOrientation::NONE==eRowVertOri ); + + rWrt.DecIndentLevel(); // Inhalt von <TR>...</TR> einruecken + + rWrt.OutNewLine(); // </TR> in neuer Zeile + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_tablerow, sal_False ); +} + + + +void SwHTMLWrtTable::Write( SwHTMLWriter& rWrt, sal_Int16 eAlign, + sal_Bool bTHead, const SwFrmFmt *pFrmFmt, + const String *pCaption, sal_Bool bTopCaption, + sal_uInt16 nHSpace, sal_uInt16 nVSpace ) const +{ + sal_uInt16 nRow; + + // Wert fuer FRAME bestimmen + sal_uInt16 nFrameMask = 15; + if( !(aRows[0])->bTopBorder ) + nFrameMask &= ~1; + if( !(aRows[aRows.Count()-1])->bBottomBorder ) + nFrameMask &= ~2; + if( !(aCols[0])->bLeftBorder ) + nFrameMask &= ~4; + if( !(aCols[aCols.Count()-1])->bRightBorder ) + nFrameMask &= ~8; + + // Wert fur RULES bestimmen + sal_Bool bRowsHaveBorder = sal_False; + sal_Bool bRowsHaveBorderOnly = sal_True; + SwWriteTableRow *pRow = aRows[0]; + for( nRow=1; nRow < aRows.Count(); nRow++ ) + { + SwWriteTableRow *pNextRow = aRows[nRow]; + sal_Bool bBorder = ( pRow->bBottomBorder || pNextRow->bTopBorder ); + bRowsHaveBorder |= bBorder; + bRowsHaveBorderOnly &= bBorder; + + sal_uInt16 nBorder2 = pRow->bBottomBorder ? pRow->nBottomBorder : USHRT_MAX; + if( pNextRow->bTopBorder && pNextRow->nTopBorder < nBorder2 ) + nBorder2 = pNextRow->nTopBorder; + + pRow->bBottomBorder = bBorder; + pRow->nBottomBorder = nBorder2; + + pNextRow->bTopBorder = bBorder; + pNextRow->nTopBorder = nBorder2; + + pRow = pNextRow; + } + + sal_Bool bColsHaveBorder = sal_False; + sal_Bool bColsHaveBorderOnly = sal_True; + SwWriteTableCol *pCol = aCols[0]; + sal_uInt16 nCol; + for( nCol=1; nCol<aCols.Count(); nCol++ ) + { + SwWriteTableCol *pNextCol = aCols[nCol]; + sal_Bool bBorder = ( pCol->bRightBorder || pNextCol->bLeftBorder ); + bColsHaveBorder |= bBorder; + bColsHaveBorderOnly &= bBorder; + pCol->bRightBorder = bBorder; + pNextCol->bLeftBorder = bBorder; + pCol = pNextCol; + } + + + // vorhergende Aufzaehlung etc. beenden + rWrt.ChangeParaToken( 0 ); + + if( rWrt.bLFPossible ) + rWrt.OutNewLine(); // <TABLE> in neue Zeile + ByteString sOut( '<' ); + sOut += OOO_STRING_SVTOOLS_HTML_table; + + sal_uInt16 nOldDirection = rWrt.nDirection; + if( pFrmFmt ) + rWrt.nDirection = rWrt.GetHTMLDirection( pFrmFmt->GetAttrSet() ); + if( rWrt.bOutFlyFrame || nOldDirection != rWrt.nDirection ) + { + rWrt.Strm() << sOut.GetBuffer(); + sOut.Erase(); + rWrt.OutDirection( rWrt.nDirection ); + } + + // COLS ausgeben: Nur bei Export ueber Layout, wenn es beim Import + // vorhanden war. + if( bColsOption ) + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_cols) += '=') + += ByteString::CreateFromInt32( aCols.Count() ); + + // ALIGN= ausgeben + if( text::HoriOrientation::RIGHT == eAlign ) + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_align ) += '=') += OOO_STRING_SVTOOLS_HTML_AL_right; + else if( text::HoriOrientation::CENTER == eAlign ) + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_align ) += '=') += OOO_STRING_SVTOOLS_HTML_AL_center; + else if( text::HoriOrientation::LEFT == eAlign ) + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_align ) += '=') += OOO_STRING_SVTOOLS_HTML_AL_left; + + // WIDTH ausgeben: Stammt aus Layout oder ist berechnet + if( nTabWidth ) + { + ((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_width ) += '='; + if( HasRelWidths() ) + (sOut += ByteString::CreateFromInt32( nTabWidth )) += '%'; + else if( Application::GetDefaultDevice() ) + { + long nPixWidth = Application::GetDefaultDevice()->LogicToPixel( + Size(nTabWidth,0), MapMode(MAP_TWIP) ).Width(); + if( !nPixWidth ) + nPixWidth = 1; + + sOut += ByteString::CreateFromInt32( nPixWidth ); + } + else + { + ASSERT( Application::GetDefaultDevice(), "kein Application-Window!?" ); + sOut += "100%"; + } + } + + if( (nHSpace || nVSpace) && Application::GetDefaultDevice()) + { + Size aPixelSpc = + Application::GetDefaultDevice()->LogicToPixel( Size(nHSpace,nVSpace), + MapMode(MAP_TWIP) ); + if( !aPixelSpc.Width() && nHSpace ) + aPixelSpc.Width() = 1; + if( !aPixelSpc.Height() && nVSpace ) + aPixelSpc.Height() = 1; + + if( aPixelSpc.Width() ) + { + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_hspace) += '=') + += ByteString::CreateFromInt32( aPixelSpc.Width() ); + } + + if( aPixelSpc.Height() ) + { + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_vspace) += '=') + += ByteString::CreateFromInt32( aPixelSpc.Height() ); + } + } + + // BORDER ausgeben, aber nur wenn wir die Umrandung selbst berechnet + // haben oder die Umrandung 0 ist oder es irgendwelche Umrandungen gibt. + // Anderenfalls enthaelt nBorder naemlich nur die Breite der Umrandung, + // die genutzt wird, wenn gar kein sheet::Border angegeben ist. + sal_Bool bHasAnyBorders = nFrameMask || bColsHaveBorder || bRowsHaveBorder; + if( bCollectBorderWidth || nBorder==0 || bHasAnyBorders ) + (((sOut += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_border ) += '=') + += ByteString::CreateFromInt32( rWrt.ToPixel( nBorder ) ); + + // BORDERCOLOR ausgeben + + if( (sal_uInt32)-1 != nBorderColor && rWrt.bCfgOutStyles && bHasAnyBorders ) + { + ((sOut += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_bordercolor ) += '='; + rWrt.Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_Color( rWrt.Strm(), nBorderColor, rWrt.eDestEnc ); + sOut.Erase(); + } + + // CELLPADDING ausgeben: Stammt aus Layout oder ist berechnet + (((sOut += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_cellpadding ) += '=') + += ByteString::CreateFromInt32( rWrt.ToPixel( nCellPadding ) ); + + // CELLSPACING ausgeben: Stammt aus Layout oder ist berechnet + (((sOut += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_cellspacing ) += '=') + += ByteString::CreateFromInt32( rWrt.ToPixel( nCellSpacing ) ); + + // FRAME/RULES ausgeben (nur sinnvoll, wenn border!=0) + if( nBorder!=0 && (bCollectBorderWidth || bHasAnyBorders) ) + { + const sal_Char *pFrame = 0; + switch( nFrameMask ) + { + case 0: pFrame = OOO_STRING_SVTOOLS_HTML_TF_void ;break; + case 1: pFrame = OOO_STRING_SVTOOLS_HTML_TF_above ;break; + case 2: pFrame = OOO_STRING_SVTOOLS_HTML_TF_below ;break; + case 3: pFrame = OOO_STRING_SVTOOLS_HTML_TF_hsides ;break; + case 4: pFrame = OOO_STRING_SVTOOLS_HTML_TF_lhs ;break; + case 8: pFrame = OOO_STRING_SVTOOLS_HTML_TF_rhs ;break; + case 12: pFrame = OOO_STRING_SVTOOLS_HTML_TF_vsides ;break; + //FRAME=BOX ist der default wenn BORDER>0 + //case 15: + //default: pFrame = OOO_STRING_SVTOOLS_HTML_TF_box ;break; // geht nicht + }; + if( pFrame ) + (((sOut += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_frame ) += '=') += pFrame; + + const sal_Char *pRules = 0; + if( aCols.Count() > 1 && aRows.Count() > 1 ) + { + if( !bColsHaveBorder ) + { + if( !bRowsHaveBorder ) + pRules = OOO_STRING_SVTOOLS_HTML_TR_none; + else if( bRowsHaveBorderOnly ) + pRules = OOO_STRING_SVTOOLS_HTML_TR_rows; + else + pRules = OOO_STRING_SVTOOLS_HTML_TR_groups; + } + else if( bColsHaveBorderOnly ) + { + if( !bRowsHaveBorder || !bRowsHaveBorderOnly ) + pRules = OOO_STRING_SVTOOLS_HTML_TR_cols; + } + else + { + if( !bRowsHaveBorder ) + pRules = OOO_STRING_SVTOOLS_HTML_TR_groups; + else if( bRowsHaveBorderOnly ) + pRules = OOO_STRING_SVTOOLS_HTML_TR_rows; + else + pRules = OOO_STRING_SVTOOLS_HTML_TR_groups; + } + } + else if( aRows.Count() > 1 ) + { + if( !bRowsHaveBorder ) + pRules = OOO_STRING_SVTOOLS_HTML_TR_none; + else if( !bRowsHaveBorderOnly ) + pRules = OOO_STRING_SVTOOLS_HTML_TR_groups; + } + else if( aCols.Count() > 1 ) + { + if( !bColsHaveBorder ) + pRules = OOO_STRING_SVTOOLS_HTML_TR_none; + else if( !bColsHaveBorderOnly ) + pRules = OOO_STRING_SVTOOLS_HTML_TR_groups; + } + + if( pRules ) + (((sOut += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_rules ) += '=') += pRules; + } + rWrt.Strm() << sOut.GetBuffer(); + + // Hintergrund ausgeben + if( pFrmFmt ) + { + String aDummy; + rWrt.OutBackground( pFrmFmt->GetAttrSet(), aDummy, sal_False ); + + if( rWrt.bCfgOutStyles && pFrmFmt ) + rWrt.OutCSS1_TableFrmFmtOptions( *pFrmFmt ); + } + + sOut = '>'; + rWrt.Strm() << sOut.GetBuffer(); + + rWrt.IncIndentLevel(); // Inhalte von Table einruecken + + // Ueberschrift ausgeben + if( pCaption && pCaption->Len() ) + { + rWrt.OutNewLine(); // <CAPTION> in neue Zeile + ByteString sOutStr( OOO_STRING_SVTOOLS_HTML_caption ); + (((sOutStr += ' ') += OOO_STRING_SVTOOLS_HTML_O_align) += '=') + += (bTopCaption ? OOO_STRING_SVTOOLS_HTML_VA_top : OOO_STRING_SVTOOLS_HTML_VA_bottom); + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), sOutStr.GetBuffer(), sal_True ); + HTMLOutFuncs::Out_String( rWrt.Strm(), *pCaption, rWrt.eDestEnc, &rWrt.aNonConvertableCharacters ); + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_caption, sal_False ); + } + + sal_uInt16 nCols = aCols.Count(); + + // <COLGRP>/<COL> ausgeben: Bei Export ueber Layout nur wenn beim + // Import welche da waren, sonst immer. + sal_Bool bColGroups = (bColsHaveBorder && !bColsHaveBorderOnly); + if( bColTags ) + { + if( bColGroups ) + { + rWrt.OutNewLine(); // <COLGRP> in neue Zeile + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_colgroup, sal_True ); + + rWrt.IncIndentLevel(); // Inhalt von <COLGRP> einruecken + } + + for( nCol=0; nCol<nCols; nCol++ ) + { + rWrt.OutNewLine(); // <COL> in neue Zeile + + const SwWriteTableCol *pColumn = aCols[nCol]; + + ByteString sOutStr( '<' ); + sOutStr += OOO_STRING_SVTOOLS_HTML_col; + + sal_uInt32 nWidth; + sal_Bool bRel; + if( bLayoutExport ) + { + bRel = pColumn->HasRelWidthOpt(); + nWidth = pColumn->GetWidthOpt(); + } + else + { + bRel = HasRelWidths(); + nWidth = bRel ? GetRelWidth(nCol,1) : GetAbsWidth(nCol,1); + } + + ((sOutStr += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_width ) += '='; + if( bRel ) + { + (sOutStr += ByteString::CreateFromInt32( nWidth ) ) += '*'; + } + else + { + sOutStr += ByteString::CreateFromInt32( rWrt.ToPixel( nWidth ) ); + } + sOutStr += '>'; + rWrt.Strm() << sOutStr.GetBuffer(); + + if( bColGroups && pColumn->bRightBorder && nCol<nCols-1 ) + { + rWrt.DecIndentLevel(); // Inhalt von <COLGRP> einruecken + rWrt.OutNewLine(); // </COLGRP> in neue Zeile + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_colgroup, + sal_False ); + rWrt.OutNewLine(); // <COLGRP> in neue Zeile + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_colgroup, + sal_True ); + rWrt.IncIndentLevel(); // Inhalt von <COLGRP> einruecken + } + } + if( bColGroups ) + { + rWrt.DecIndentLevel(); // Inhalt von <COLGRP> einruecken + + rWrt.OutNewLine(); // </COLGRP> in neue Zeile + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_colgroup, + sal_False ); + } + } + + // die Lines als Tabellenzeilen rausschreiben + + // <TBODY> ausgeben? + sal_Bool bTSections = (bRowsHaveBorder && !bRowsHaveBorderOnly); + sal_Bool bTBody = bTSections; + + // Wenn Sections ausgegeben werden muessen darf ein THEAD um die erste + // Zeile nur ausgegeben werden, wenn unter der Zeile eine Linie ist + if( bTHead && + (bTSections || bColGroups) && + nHeadEndRow<aRows.Count()-1 && !aRows[nHeadEndRow]->bBottomBorder ) + bTHead = sal_False; + + // <TBODY> aus ausgeben, wenn <THEAD> ausgegeben wird. + bTSections |= bTHead; + + if( bTSections ) + { + rWrt.OutNewLine(); // <THEAD>/<TDATA> in neue Zeile + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), + bTHead ? OOO_STRING_SVTOOLS_HTML_thead : OOO_STRING_SVTOOLS_HTML_tbody, sal_True ); + + rWrt.IncIndentLevel(); // Inhalt von <THEAD>/<TDATA> einr. + } + + for( nRow = 0; nRow < aRows.Count(); nRow++ ) + { + const SwWriteTableRow *pRow2 = aRows[nRow]; + + OutTableCells( rWrt, pRow2->GetCells(), pRow2->GetBackground() ); + if( !nCellSpacing && nRow < aRows.Count()-1 && pRow2->bBottomBorder && + pRow2->nBottomBorder > DEF_LINE_WIDTH_1 ) + { + sal_uInt16 nCnt = (pRow2->nBottomBorder / DEF_LINE_WIDTH_1) - 1; + for( ; nCnt; nCnt-- ) + { + rWrt.OutNewLine(); + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_tablerow, + sal_True ); + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_tablerow, + sal_False ); + } + } + if( ( (bTHead && nRow==nHeadEndRow) || + (bTBody && pRow2->bBottomBorder) ) && + nRow < aRows.Count()-1 ) + { + rWrt.DecIndentLevel(); // Inhalt von <THEAD>/<TDATA> einr. + rWrt.OutNewLine(); // </THEAD>/</TDATA> in neue Zeile + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), + bTHead ? OOO_STRING_SVTOOLS_HTML_thead : OOO_STRING_SVTOOLS_HTML_tbody, sal_False ); + rWrt.OutNewLine(); // <THEAD>/<TDATA> in neue Zeile + + if( bTHead && nRow==nHeadEndRow ) + bTHead = sal_False; + + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), + bTHead ? OOO_STRING_SVTOOLS_HTML_thead : OOO_STRING_SVTOOLS_HTML_tbody, sal_True ); + rWrt.IncIndentLevel(); // Inhalt von <THEAD>/<TDATA> einr. + } + } + + if( bTSections ) + { + rWrt.DecIndentLevel(); // Inhalt von <THEAD>/<TDATA> einr. + + rWrt.OutNewLine(); // </THEAD>/</TDATA> in neue Zeile + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), + bTHead ? OOO_STRING_SVTOOLS_HTML_thead : OOO_STRING_SVTOOLS_HTML_tbody, sal_False ); + } + + rWrt.DecIndentLevel(); // Inhalt von <TABLE> einr. + + rWrt.OutNewLine(); // </TABLE> in neue Zeile + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_table, sal_False ); + + rWrt.nDirection = nOldDirection; +} + +Writer& OutHTML_SwTblNode( Writer& rWrt, SwTableNode & rNode, + const SwFrmFmt *pFlyFrmFmt, + const String *pCaption, sal_Bool bTopCaption ) +{ + + SwTable& rTbl = rNode.GetTable(); + + SwHTMLWriter & rHTMLWrt = (SwHTMLWriter&)rWrt; + rHTMLWrt.bOutTable = sal_True; + + // die horizontale Ausrichtung des Rahmens hat (falls vorhanden) + // Prioritaet. NONE bedeutet, dass keine horizontale + // Ausrichtung geschrieben wird. + sal_Int16 eFlyHoriOri = text::HoriOrientation::NONE; + SwSurround eSurround = SURROUND_NONE; + sal_uInt8 nFlyPrcWidth = 0; + long nFlyWidth = 0; + sal_uInt16 nFlyHSpace = 0; + sal_uInt16 nFlyVSpace = 0; + if( pFlyFrmFmt ) + { + eSurround = pFlyFrmFmt->GetSurround().GetSurround(); + const SwFmtFrmSize& rFrmSize = pFlyFrmFmt->GetFrmSize(); + nFlyPrcWidth = rFrmSize.GetWidthPercent(); + nFlyWidth = rFrmSize.GetSize().Width(); + + eFlyHoriOri = pFlyFrmFmt->GetHoriOrient().GetHoriOrient(); + if( text::HoriOrientation::NONE == eFlyHoriOri ) + eFlyHoriOri = text::HoriOrientation::LEFT; + + const SvxLRSpaceItem& rLRSpace = pFlyFrmFmt->GetLRSpace(); + nFlyHSpace = static_cast< sal_uInt16 >((rLRSpace.GetLeft() + rLRSpace.GetRight()) / 2); + + const SvxULSpaceItem& rULSpace = pFlyFrmFmt->GetULSpace(); + nFlyVSpace = (rULSpace.GetUpper() + rULSpace.GetLower()) / 2; + } + + // ggf. eine FORM oeffnen + sal_Bool bPreserveForm = sal_False; + if( !rHTMLWrt.bPreserveForm ) + { + rHTMLWrt.OutForm( sal_True, &rNode ); + bPreserveForm = (rHTMLWrt.pxFormComps && rHTMLWrt.pxFormComps->is() ); + rHTMLWrt.bPreserveForm = bPreserveForm; + } + + SwFrmFmt *pFmt = rTbl.GetFrmFmt(); + + const SwFmtFrmSize& rFrmSize = pFmt->GetFrmSize(); + long nWidth = rFrmSize.GetSize().Width(); + sal_uInt8 nPrcWidth = rFrmSize.GetWidthPercent(); + sal_uInt16 nBaseWidth = (sal_uInt16)nWidth; + + sal_Int16 eTabHoriOri = pFmt->GetHoriOrient().GetHoriOrient(); + + // text::HoriOrientation::NONE und text::HoriOrientation::FULL Tabellen benoetigen relative Breiten + sal_uInt16 nNewDefListLvl = 0; + sal_Bool bRelWidths = sal_False; + sal_Bool bCheckDefList = sal_False; + switch( eTabHoriOri ) + { + case text::HoriOrientation::FULL: + // Tabellen mit automatischer Ausrichtung werden zu Tabellen + // mit 100%-Breite + bRelWidths = sal_True; + nWidth = 100; + eTabHoriOri = text::HoriOrientation::LEFT; + break; + case text::HoriOrientation::NONE: + { + const SvxLRSpaceItem& aLRItem = pFmt->GetLRSpace(); + if( aLRItem.GetRight() ) + { + // Die Tabellenbreite wird anhand des linken und rechten + // Abstandes bestimmt. Deshalb versuchen wir die + // tatsaechliche Breite der Tabelle zu bestimmen. Wenn + // das nicht geht, machen wir eine 100% breite Tabelle + // draus. + nWidth = pFmt->FindLayoutRect(sal_True).Width(); + if( !nWidth ) + { + bRelWidths = sal_True; + nWidth = 100; + } + + } + else if( nPrcWidth ) + { + // Ohne rechten Rand bleibt die %-Breite erhalten + nWidth = nPrcWidth; + bRelWidths = sal_True; + } + else + { + // Ohne rechten Rand bleibt auch eine absolute Breite erhalten + // Wir versuchen aber trotzdem ueber das Layout die + // tatsachliche Breite zu ermitteln. + long nRealWidth = pFmt->FindLayoutRect(sal_True).Width(); + if( nRealWidth ) + nWidth = nRealWidth; + } + bCheckDefList = sal_True; + } + break; + case text::HoriOrientation::LEFT_AND_WIDTH: + eTabHoriOri = text::HoriOrientation::LEFT; + bCheckDefList = sal_True; + // no break + default: + // In allen anderen Faellen kann eine absolute oder relative + // Breite direkt uebernommen werden. + if( nPrcWidth ) + { + bRelWidths = sal_True; + nWidth = nPrcWidth; + } + break; + } + + if( bCheckDefList ) + { + ASSERT( !rHTMLWrt.GetNumInfo().GetNumRule() || + rHTMLWrt.GetNextNumInfo(), + "NumInfo fuer naechsten Absatz fehlt!" ); + const SvxLRSpaceItem& aLRItem = pFmt->GetLRSpace(); + if( aLRItem.GetLeft() > 0 && rHTMLWrt.nDefListMargin > 0 && + ( !rHTMLWrt.GetNumInfo().GetNumRule() || + ( rHTMLWrt.GetNextNumInfo() && + (rHTMLWrt.GetNextNumInfo()->IsRestart() || + rHTMLWrt.GetNumInfo().GetNumRule() != + rHTMLWrt.GetNextNumInfo()->GetNumRule()) ) ) ) + { + // Wenn der Absatz vor der Tabelle nicht numeriert ist oder + // der Absatz nach der Tabelle mit einer anderen oder + // (gar keiner) Regel numeriert ist, koennen wir + // die Einrueckung ueber eine DL regeln. Sonst behalten wir + // die Einrueckung der Numerierung bei. + nNewDefListLvl = static_cast< sal_uInt16 >( + (aLRItem.GetLeft() + (rHTMLWrt.nDefListMargin/2)) / + rHTMLWrt.nDefListMargin ); + } + } + + if( !pFlyFrmFmt && nNewDefListLvl != rHTMLWrt.nDefListLvl ) + rHTMLWrt.OutAndSetDefList( nNewDefListLvl ); + + if( nNewDefListLvl ) + { + if( rHTMLWrt.bLFPossible ) + rHTMLWrt.OutNewLine(); + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_dd ); + } + + // eFlyHoriOri und eTabHoriOri besitzen nun nur noch die Werte + // LEFT/CENTER und RIGHT! + if( eFlyHoriOri!=text::HoriOrientation::NONE ) + { + eTabHoriOri = eFlyHoriOri; + // MIB 4.7.97: Wenn die Tabelle eine relative Breite besitzt, + // dann richtet sich ihre Breite nach der des Rahmens, also + // exportieren wir dessen Breite. Bei fixer Breite ist die Breite + // der Tabelle massgeblich. Wer Tabellen mit relativer Breite <100% + // in Rahmen steckt, ist selber schuld wenn nix Gutes bei rauskommt. + if( bRelWidths ) + { + nWidth = nFlyPrcWidth ? nFlyPrcWidth : nFlyWidth; + bRelWidths = nFlyPrcWidth > 0; + } + } + + sal_Int16 eDivHoriOri = text::HoriOrientation::NONE; + switch( eTabHoriOri ) + { + case text::HoriOrientation::LEFT: + // Wenn eine linksbuendigeTabelle keinen rechtsseiigen Durchlauf + // hat, brauchen wir auch kein ALIGN=LEFT in der Tabelle. + if( eSurround==SURROUND_NONE || eSurround==SURROUND_LEFT ) + eTabHoriOri = text::HoriOrientation::NONE; + break; + case text::HoriOrientation::RIGHT: + // Aehnliches gilt fuer rechtsbuendigeTabelle, hier nehmen wir + // stattdessen ein <DIV ALIGN=RIGHT>. + if( eSurround==SURROUND_NONE || eSurround==SURROUND_RIGHT ) + { + eDivHoriOri = text::HoriOrientation::RIGHT; + eTabHoriOri = text::HoriOrientation::NONE; + } + break; + case text::HoriOrientation::CENTER: + // ALIGN=CENTER versteht so gut wie keiner, deshalb verzichten wir + // daruf und nehmen ein <CENTER>. + eDivHoriOri = text::HoriOrientation::CENTER; + eTabHoriOri = text::HoriOrientation::NONE; + break; + default: + ; + } + if( text::HoriOrientation::NONE==eTabHoriOri ) + nFlyHSpace = nFlyVSpace = 0; + + if( pFmt->GetName().Len() ) + rHTMLWrt.OutImplicitMark( pFmt->GetName(), pMarkToTable ); + + if( text::HoriOrientation::NONE!=eDivHoriOri ) + { + if( rHTMLWrt.bLFPossible ) + rHTMLWrt.OutNewLine(); // <CENTER> in neuer Zeile + if( text::HoriOrientation::CENTER==eDivHoriOri ) + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_center, sal_True ); + else + { + ByteString sOut( OOO_STRING_SVTOOLS_HTML_division ); + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_align) += '=') += OOO_STRING_SVTOOLS_HTML_AL_right; + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), sOut.GetBuffer(), + sal_True ); + } + rHTMLWrt.IncIndentLevel(); // Inhalt von <CENTER> einruecken + rHTMLWrt.bLFPossible = sal_True; + } + + // Wenn die Tabelle in keinem Rahmen ist kann man immer ein LF ausgeben. + if( text::HoriOrientation::NONE==eTabHoriOri ) + rHTMLWrt.bLFPossible = sal_True; + + const SwHTMLTableLayout *pLayout = rTbl.GetHTMLTableLayout(); + +#ifdef DBG_UTIL + ViewShell *pSh; + rWrt.pDoc->GetEditShell( &pSh ); + if ( pSh && pSh->GetViewOptions()->IsTest1() ) + pLayout = 0; +#endif + + if( pLayout && pLayout->IsExportable() ) + { + SwHTMLWrtTable aTableWrt( pLayout ); + aTableWrt.Write( rHTMLWrt, eTabHoriOri, rTbl.GetRowsToRepeat() > 0, + pFmt, pCaption, bTopCaption, + nFlyHSpace, nFlyVSpace ); + } + else + { + SwHTMLWrtTable aTableWrt( rTbl.GetTabLines(), nWidth, + nBaseWidth, bRelWidths, rTbl.GetRowsToRepeat() ); + aTableWrt.Write( rHTMLWrt, eTabHoriOri, rTbl.GetRowsToRepeat() > 0, + pFmt, pCaption, bTopCaption, + nFlyHSpace, nFlyVSpace ); + } + + // Wenn die Tabelle in keinem Rahmen war kann man immer ein LF ausgeben. + if( text::HoriOrientation::NONE==eTabHoriOri ) + rHTMLWrt.bLFPossible = sal_True; + + if( text::HoriOrientation::NONE!=eDivHoriOri ) + { + rHTMLWrt.DecIndentLevel(); // Inhalt von <CENTER> einruecken + rHTMLWrt.OutNewLine(); // </CENTER> in neue Teile + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), + text::HoriOrientation::CENTER==eDivHoriOri ? OOO_STRING_SVTOOLS_HTML_center + : OOO_STRING_SVTOOLS_HTML_division, sal_False ); + rHTMLWrt.bLFPossible = sal_True; + } + + // Pam hinter die Tabelle verschieben + rHTMLWrt.pCurPam->GetPoint()->nNode = *rNode.EndOfSectionNode(); + + if( bPreserveForm ) + { + rHTMLWrt.bPreserveForm = sal_False; + rHTMLWrt.OutForm( sal_False ); + } + + rHTMLWrt.bOutTable = sal_False; + + if( rHTMLWrt.GetNextNumInfo() && + !rHTMLWrt.GetNextNumInfo()->IsRestart() && + rHTMLWrt.GetNextNumInfo()->GetNumRule() == + rHTMLWrt.GetNumInfo().GetNumRule() ) + { + // Wenn der Absatz hinter der Tabelle mit der gleichen Regel + // numeriert ist wie der Absatz vor der Tabelle, dann steht in + // der NumInfo des naechsten Absatzes noch die Ebene des Absatzes + // vor der Tabelle. Es muss deshalb die NumInfo noch einmal geholt + // werden um ggf. die Num-Liste noch zu beenden. + rHTMLWrt.ClearNextNumInfo(); + rHTMLWrt.FillNextNumInfo(); + OutHTML_NumBulListEnd( rHTMLWrt, *rHTMLWrt.GetNextNumInfo() ); + } + return rWrt; +} + + diff --git a/sw/source/filter/html/htmlvsh.hxx b/sw/source/filter/html/htmlvsh.hxx new file mode 100644 index 000000000000..18e0129fd0a3 --- /dev/null +++ b/sw/source/filter/html/htmlvsh.hxx @@ -0,0 +1,55 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _HTMLVSH_HXX +#define _HTMLVSH_HXX + +#include <calbck.hxx> +class ViewShell; + + +class SwHTMLViewShellClient : public SwClient +{ + virtual void Modify( SfxPoolItem *pOld, SfxPoolItem *pNew ); + +public: + + SwHTMLViewShellClient( ViewShell *pVSh ); + + virtual ~SwHTMLViewShellClient(); + + void Register( ViewShell *pVsh ); + void DeRegister(); + + /*inline*/ ViewShell *GetViewShell(); // im swhtml.cxx +}; + + + +#endif + + diff --git a/sw/source/filter/html/parcss1.cxx b/sw/source/filter/html/parcss1.cxx new file mode 100644 index 000000000000..8c43bd6206ae --- /dev/null +++ b/sw/source/filter/html/parcss1.cxx @@ -0,0 +1,1426 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <ctype.h> +#include <stdlib.h> +#include <stdio.h> +#include <limits.h> +#include <rtl/ustrbuf.hxx> +#include <tools/debug.hxx> +#include <vcl/svapp.hxx> +#include <svtools/htmltokn.h> + +#include "css1kywd.hxx" +#include "parcss1.hxx" + + +// Loop-Check: Um Endlos-Schleifen zu vermeiden, wird in jeder +// Schalife geprueft, ob ein Fortschritt in der Eingabe-Position +// stattgefunden hat +#define LOOP_CHECK + +#ifdef LOOP_CHECK + +#define LOOP_CHECK_DECL \ + xub_StrLen nOldInPos = STRING_MAXLEN; +#define LOOP_CHECK_RESTART \ + nOldInPos = STRING_MAXLEN; +#define LOOP_CHECK_CHECK( where ) \ + DBG_ASSERT( nOldInPos!=nInPos || cNextCh==(sal_Unicode)EOF, where ); \ + if( nOldInPos==nInPos && cNextCh!=(sal_Unicode)EOF ) \ + break; \ + else \ + nOldInPos = nInPos; + +#else + +#define LOOP_CHECK_DECL +#define LOOP_CHECK_RESTART +#define LOOP_CHECK_CHECK( where ) + +#endif + + + +const sal_Int32 MAX_LEN = 1024; + +/* */ + +void CSS1Parser::InitRead( const String& rIn ) +{ + nlLineNr = 0; + nlLinePos = 0; + + bWhiteSpace = sal_True; // Wenn noch nichts gelesen wurde ist das wie WS + bEOF = sal_False; + eState = CSS1_PAR_WORKING; + nValue = 0.; + + aIn = rIn; + nInPos = 0; + cNextCh = GetNextChar(); + nToken = GetNextToken(); +} + +sal_Unicode CSS1Parser::GetNextChar() +{ + if( nInPos >= aIn.Len() ) + { + bEOF = sal_True; + return (sal_Unicode)EOF; + } + + sal_Unicode c = aIn.GetChar( nInPos ); + nInPos++; + + if( c == '\n' ) + { + IncLineNr(); + SetLinePos( 1L ); + } + else + IncLinePos(); + + return c; +} + +/* */ + +// Diese Funktion realisiert den in +// +// http://www.w3.orh/pub/WWW/TR/WD-css1.html +// bzw. http://www.w3.orh/pub/WWW/TR/WD-css1-960220.html +// +// beschriebenen Scanner fuer CSS1. Es handelt sich um eine direkte +// Umsetzung der dort beschriebenen Lex-Grammatik +// +CSS1Token CSS1Parser::GetNextToken() +{ + CSS1Token nRet = CSS1_NULL; + aToken.Erase(); + + do { + // Merken, ob davor White-Space gelesen wurde + sal_Bool bPrevWhiteSpace = bWhiteSpace; + bWhiteSpace = sal_False; + + sal_Bool bNextCh = sal_True; + switch( cNextCh ) + { + case '/': // COMMENT | '/' + { + cNextCh = GetNextChar(); + if( '*' == cNextCh ) + { + // COMMENT + cNextCh = GetNextChar(); + + sal_Bool bAsterix = sal_False; + while( !(bAsterix && '/'==cNextCh) && !IsEOF() ) + { + bAsterix = ('*'==cNextCh); + cNextCh = GetNextChar(); + } + } + else + { + // '/' + bNextCh = sal_False; + nRet = CSS1_SLASH; + } + } + break; + + case '@': // '@import' | '@XXX' + { + cNextCh = GetNextChar(); + if( ('A' <= cNextCh && cNextCh <= 'Z') || + ('a' <= cNextCh && cNextCh <= 'z') ) + { + // den naechsten Identifer scannen + ::rtl::OUStringBuffer sTmpBuffer( 32L ); + do { + sTmpBuffer.append( cNextCh ); + cNextCh = GetNextChar(); + } while( ('A' <= cNextCh && cNextCh <= 'Z') || + ('a' <= cNextCh && cNextCh <= 'z') || + ('0' <= cNextCh && cNextCh <= '9') || + '-'==cNextCh && !IsEOF() ); + + aToken += String(sTmpBuffer.makeStringAndClear()); + + // und schauen, ob wir ihn kennen + switch( aToken.GetChar(0) ) + { + case 'i': + case 'I': + if( aToken.EqualsIgnoreCaseAscii(sCSS1_import) ) + nRet = CSS1_IMPORT_SYM; + break; +// /Feature: PrintExt + case 'p': + case 'P': + if( aToken.EqualsIgnoreCaseAscii(sCSS1_page) ) + nRet = CSS1_PAGE_SYM; + break; +// /Feature: PrintExt + } + + // Fehlerbehandlung: '@ident' und alles bis + // zu einem Semikolon der dem Ende des folgenden + // Blocks ignorieren + if( CSS1_NULL==nRet ) + { + aToken.Erase(); + sal_uInt16 nBlockLvl = 0; + sal_Unicode cQuoteCh = 0; + sal_Bool bDone = sal_False, bEscape = sal_False; + while( !bDone && !IsEOF() ) + { + sal_Bool bOldEscape = bEscape; + bEscape = sal_False; + switch( cNextCh ) + { + case '{': + if( !cQuoteCh && !bOldEscape ) + nBlockLvl++;; + break; + case ';': + if( !cQuoteCh && !bOldEscape ) + bDone = nBlockLvl==0; + break; + case '}': + if( !cQuoteCh && !bOldEscape ) + bDone = --nBlockLvl==0; + break; + case '\"': + case '\'': + if( !bOldEscape ) + { + if( cQuoteCh ) + { + if( cQuoteCh == cNextCh ) + cQuoteCh = 0; + } + else + { + cQuoteCh = cNextCh; + } + } + break; + case '\\': + if( !bOldEscape ) + bEscape = sal_True; + break; + } + cNextCh = GetNextChar(); + } + } + + bNextCh = sal_False; + } + } + break; + + case '!': // '!' 'legal' | '!' 'important' | syntax error + { + // White Space ueberlesen + cNextCh = GetNextChar(); + while( ( ' ' == cNextCh || + (cNextCh >= 0x09 && cNextCh <= 0x0d) ) && !IsEOF() ) + { + bWhiteSpace = sal_True; + cNextCh = GetNextChar(); + } + + if( 'i'==cNextCh || 'I'==cNextCh) + { + // den naechsten Identifer scannen + ::rtl::OUStringBuffer sTmpBuffer( 32L ); + do { + sTmpBuffer.append( cNextCh ); + cNextCh = GetNextChar(); + } while( ('A' <= cNextCh && cNextCh <= 'Z') || + ('a' <= cNextCh && cNextCh <= 'z') || + ('0' <= cNextCh && cNextCh <= '9') || + '-' == cNextCh && !IsEOF() ); + + aToken += String(sTmpBuffer.makeStringAndClear()); + + if( ('i'==aToken.GetChar(0) || 'I'==aToken.GetChar(0)) && + aToken.EqualsIgnoreCaseAscii(sCSS1_important) ) + { + // '!' 'important' + nRet = CSS1_IMPORTANT_SYM; + } + else + { + // Fehlerbehandlung: '!' ignorieren, IDENT nicht + nRet = CSS1_IDENT; + } + + bWhiteSpace = sal_False; + bNextCh = sal_False; + } + else + { + // Fehlerbehandlung: '!' ignorieren + bNextCh = sal_False; + } + } + break; + + case '\"': + case '\'': // STRING + { + // \... geht noch nicht!!! + sal_Unicode cQuoteChar = cNextCh; + cNextCh = GetNextChar(); + + ::rtl::OUStringBuffer sTmpBuffer( MAX_LEN ); + do { + sTmpBuffer.append( cNextCh ); + cNextCh = GetNextChar(); + } while( cQuoteChar != cNextCh && !IsEOF() ); + + aToken += String(sTmpBuffer.makeStringAndClear()); + + nRet = CSS1_STRING; + } + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': // NUMBER | PERCENTAGE | LENGTH + { + // die aktuelle Position retten + xub_StrLen nInPosSave = nInPos; + sal_Unicode cNextChSave = cNextCh; + sal_uInt32 nlLineNrSave = nlLineNr; + sal_uInt32 nlLinePosSave = nlLinePos; + sal_Bool bEOFSave = bEOF; + + // erstmal versuchen eine Hex-Zahl zu scannen + ::rtl::OUStringBuffer sTmpBuffer( 16 ); + do { + sTmpBuffer.append( cNextCh ); + cNextCh = GetNextChar(); + } while( sTmpBuffer.getLength() < 7 && + ( ('0'<=cNextCh && '9'>=cNextCh) || + ('A'<=cNextCh && 'F'>=cNextCh) || + ('a'<=cNextCh && 'f'>=cNextCh) ) && + !IsEOF() ); + + if( sTmpBuffer.getLength()==6 ) + { + // wir haben eine hexadezimale Farbe gefunden + aToken += String(sTmpBuffer.makeStringAndClear()); + nRet = CSS1_HEXCOLOR; + bNextCh = sal_False; + + break; + } + + // sonst versuchen wir es mit einer Zahl + nInPos = nInPosSave; + cNextCh = cNextChSave; + nlLineNr = nlLineNrSave; + nlLinePos = nlLinePosSave; + bEOF = bEOFSave; + + // erstmal die Zahl scannen + sTmpBuffer.setLength( 0L ); + do { + sTmpBuffer.append( cNextCh ); + cNextCh = GetNextChar(); + } while( (('0'<=cNextCh && '9'>=cNextCh) || '.'==cNextCh) && + !IsEOF() ); + + aToken += String(sTmpBuffer.makeStringAndClear()); + nValue = aToken.ToDouble(); + + // White Space ueberlesen + while( ( ' ' == cNextCh || + (cNextCh >= 0x09 && cNextCh <= 0x0d) ) && !IsEOF() ) + { + bWhiteSpace = sal_True; + cNextCh = GetNextChar(); + } + + // und nun Schauen, ob es eine Einheit gibt + switch( cNextCh ) + { + case '%': // PERCENTAGE + bWhiteSpace = sal_False; + nRet = CSS1_PERCENTAGE; + break; + + case 'c': + case 'C': // LENGTH cm | LENGTH IDENT + case 'e': + case 'E': // LENGTH (em | ex) | LENGTH IDENT + case 'i': + case 'I': // LENGTH inch | LENGTH IDENT + case 'p': + case 'P': // LENGTH (pt | px | pc) | LENGTH IDENT + case 'm': + case 'M': // LENGTH mm | LENGTH IDENT + { + // die aktuelle Position retten + xub_StrLen nInPosOld = nInPos; + sal_Unicode cNextChOld = cNextCh; + sal_uLong nlLineNrOld = nlLineNr; + sal_uLong nlLinePosOld = nlLinePos; + sal_Bool bEOFOld = bEOF; + + // den naechsten Identifer scannen + String aIdent; + ::rtl::OUStringBuffer sTmpBuffer2( 64L ); + do { + sTmpBuffer2.append( cNextCh ); + cNextCh = GetNextChar(); + } while( ( ('A' <= cNextCh && cNextCh <= 'Z') || + ('a' <= cNextCh && cNextCh <= 'z') || + ('0' <= cNextCh && cNextCh <= '9') || + '-'==cNextCh) && !IsEOF() ); + + aIdent += String(sTmpBuffer2.makeStringAndClear()); + + // Ist es eine Einheit? + const sal_Char *pCmp1 = 0, *pCmp2 = 0, *pCmp3 = 0; + double nScale1 = 1., nScale2 = 1., nScale3 = 1.; + CSS1Token nToken1 = CSS1_LENGTH, + nToken2 = CSS1_LENGTH, + nToken3 = CSS1_LENGTH; + switch( aIdent.GetChar(0) ) + { + case 'c': + case 'C': + pCmp1 = sCSS1_UNIT_cm; + nScale1 = (72.*20.)/2.54; // twip + break; + case 'e': + case 'E': + pCmp1 = sCSS1_UNIT_em; + nToken1 = CSS1_EMS; + + pCmp2 = sCSS1_UNIT_ex; + nToken2 = CSS1_EMX; + break; + case 'i': + case 'I': + pCmp1 = sCSS1_UNIT_inch; + nScale1 = 72.*20.; // twip + break; + case 'm': + case 'M': + pCmp1 = sCSS1_UNIT_mm; + nScale1 = (72.*20.)/25.4; // twip + break; + case 'p': + case 'P': + pCmp1 = sCSS1_UNIT_pt; + nScale1 = 20.; // twip + + pCmp2 = sCSS1_UNIT_pc; + nScale2 = 12.*20.; // twip + + pCmp3 = sCSS1_UNIT_px; + nToken3 = CSS1_PIXLENGTH; + break; + } + + double nScale = 0.0; + DBG_ASSERT( pCmp1, "Wo kommt das erste Zeichen her?" ); + if( aIdent.EqualsIgnoreCaseAscii(pCmp1) ) + { + nScale = nScale1; + nRet = nToken1; + } + else if( pCmp2 && + aIdent.EqualsIgnoreCaseAscii(pCmp2) ) + { + nScale = nScale2; + nRet = nToken2; + } + else if( pCmp3 && + aIdent.EqualsIgnoreCaseAscii(pCmp3) ) + { + nScale = nScale3; + nRet = nToken3; + } + else + { + nRet = CSS1_NUMBER; + } + + if( CSS1_LENGTH==nRet && nScale!=1.0 ) + nValue *= nScale; + + if( nRet == CSS1_NUMBER ) + { + nInPos = nInPosOld; + cNextCh = cNextChOld; + nlLineNr = nlLineNrOld; + nlLinePos = nlLinePosOld; + bEOF = bEOFOld; + } + else + { + bWhiteSpace = sal_False; + } + bNextCh = sal_False; + } + break; + default: // NUMBER IDENT + bNextCh = sal_False; + nRet = CSS1_NUMBER; + break; + } + } + break; + + case ':': // ':' + // link/visited/active abfangen !!! + nRet = CSS1_COLON; + break; + + case '.': // DOT_W_WS | DOT_WO_WS + nRet = bPrevWhiteSpace ? CSS1_DOT_W_WS : CSS1_DOT_WO_WS; + break; + + // case '/': siehe oben + + case '+': // '+' + nRet = CSS1_PLUS; + break; + + case '-': // '-' + nRet = CSS1_MINUS; + break; + + case '{': // '{' + nRet = CSS1_OBRACE; + break; + + case '}': // '}' + nRet = CSS1_CBRACE; + break; + + case ';': // ';' + nRet = CSS1_SEMICOLON; + break; + + case ',': // ',' + nRet = CSS1_COMMA; + break; + + case '#': // '#' + cNextCh = GetNextChar(); + if( ('0'<=cNextCh && '9'>=cNextCh) || + ('a'<=cNextCh && 'f'>=cNextCh) || + ('A'<=cNextCh && 'F'>=cNextCh) ) + { + // die aktuelle Position retten + xub_StrLen nInPosSave = nInPos; + sal_Unicode cNextChSave = cNextCh; + sal_uLong nlLineNrSave = nlLineNr; + sal_uLong nlLinePosSave = nlLinePos; + sal_Bool bEOFSave = bEOF; + + // erstmal versuchen eine Hex-Zahl zu scannen + ::rtl::OUStringBuffer sTmpBuffer( 6L ); + do { + sTmpBuffer.append( cNextCh ); + cNextCh = GetNextChar(); + } while( sTmpBuffer.getLength() < 7 && + ( ('0'<=cNextCh && '9'>=cNextCh) || + ('A'<=cNextCh && 'F'>=cNextCh) || + ('a'<=cNextCh && 'f'>=cNextCh) ) && + !IsEOF() ); + + if( sTmpBuffer.getLength()==6 || sTmpBuffer.getLength()==3 ) + { + // wir haben eine hexadezimale Farbe gefunden + aToken += String(sTmpBuffer.makeStringAndClear()); + nRet = CSS1_HEXCOLOR; + bNextCh = sal_False; + + break; + } + + // sonst versuchen wir es mit einer Zahl + nInPos = nInPosSave; + cNextCh = cNextChSave; + nlLineNr = nlLineNrSave; + nlLinePos = nlLinePosSave; + bEOF = bEOFSave; + } + + nRet = CSS1_HASH; + bNextCh = sal_False; + break; + + case ' ': + case '\t': + case '\r': + case '\n': // White-Space + bWhiteSpace = sal_True; + break; + + case (sal_Unicode)EOF: + if( IsEOF() ) + { + eState = CSS1_PAR_ACCEPTED; + bNextCh = sal_False; + break; + } + // kein break; + + default: // IDENT | syntax error + // TODO IsAlpha + if( ('A' <= cNextCh && cNextCh <= 'Z') || + ('a' <= cNextCh && cNextCh <= 'z') ) + { + // IDENT + + sal_Bool bHexColor = sal_True; + + // den naechsten Identifer scannen + ::rtl::OUStringBuffer sTmpBuffer( 64L ); + do { + sTmpBuffer.append( cNextCh ); + if( bHexColor ) + { + bHexColor = sTmpBuffer.getLength()<7 && + ( ('0'<=cNextCh && '9'>=cNextCh) || + ('A'<=cNextCh && 'F'>=cNextCh) || + ('a'<=cNextCh && 'f'>=cNextCh) ); + } + cNextCh = GetNextChar(); + // TODO: AlphaNumeric + } while( ( ('0'<=cNextCh && '9'>=cNextCh) || + ('A'<=cNextCh && 'Z'>=cNextCh) || + ('a'<=cNextCh && 'z'>=cNextCh) || + '-'==cNextCh ) && + !IsEOF() ); + + aToken += String(sTmpBuffer.makeStringAndClear()); + + if( bHexColor && sTmpBuffer.getLength()==6 ) + { + bNextCh = sal_False; + nRet = CSS1_HEXCOLOR; + + break; + } + if( '('==cNextCh && + ( (('u'==aToken.GetChar(0) || 'U'==aToken.GetChar(0)) && + aToken.EqualsIgnoreCaseAscii(sCSS1_url)) || + (('r'==aToken.GetChar(0) || 'R'==aToken.GetChar(0)) && + aToken.EqualsIgnoreCaseAscii(sCSS1_rgb)) ) ) + { + sal_uInt16 nNestCnt = 0; + ::rtl::OUStringBuffer sTmpBuffer2( 64L ); + do { + sTmpBuffer2.append( cNextCh ); + switch( cNextCh ) + { + case '(': nNestCnt++; break; + case ')': nNestCnt--; break; + } + cNextCh = GetNextChar(); + } while( (nNestCnt>1 || ')'!=cNextCh) && !IsEOF() ); + sTmpBuffer2.append( cNextCh ); + aToken += String(sTmpBuffer2.makeStringAndClear()); + bNextCh = sal_True; + nRet = 'u'==aToken.GetChar(0) || 'U'==aToken.GetChar(0) + ? CSS1_URL + : CSS1_RGB; + } + else + { + bNextCh = sal_False; + nRet = CSS1_IDENT; + } + } + // Fehlerbehandlung: Zeichen ignorieren + break; + } + if( bNextCh ) + cNextCh = GetNextChar(); + + } while( CSS1_NULL==nRet && IsParserWorking() ); + + return nRet; +} + + +/* */ + + +// Dies folegenden Funktionen realisieren den in +// +// http://www.w3.orh/pub/WWW/TR/WD-css1.html +// bzw. http://www.w3.orh/pub/WWW/TR/WD-css1-960220.html +// +// beschriebenen Parser fuer CSS1. Es handelt sich um eine direkte +// Umsetzung der dort beschriebenen Grammatik + +// stylesheet +// : import* rule* +// +// import +// : IMPORT_SYM url +// +// url +// : STRING +// +void CSS1Parser::ParseStyleSheet() +{ + LOOP_CHECK_DECL + + // import* + sal_Bool bDone = sal_False; + while( !bDone && IsParserWorking() ) + { + LOOP_CHECK_CHECK( "Endlos-Schleife in ParseStyleSheet()/import *" ) + + switch( nToken ) + { + case CSS1_IMPORT_SYM: + // IMPORT_SYM url + // url ueberspringen wir ungeprueft + nToken = GetNextToken(); + break; + case CSS1_IDENT: // Look-Aheads + case CSS1_DOT_W_WS: + case CSS1_HASH: +// /Feature: PrintExt + case CSS1_PAGE_SYM: +// /Feature: PrintExt + // rule + bDone = sal_True; + break; + default: + // Fehlerbehandlung: ueberlesen + break; + } + + if( !bDone ) + nToken = GetNextToken(); + } + + LOOP_CHECK_RESTART + + // rule * + while( IsParserWorking() ) + { + LOOP_CHECK_CHECK( "Endlos-Schleife in ParseStyleSheet()/rule *" ) + + switch( nToken ) + { + case CSS1_IDENT: // Look-Aheads + case CSS1_DOT_W_WS: + case CSS1_HASH: +// /Feature: PrintExt + case CSS1_PAGE_SYM: +// /Feature: PrintExt + // rule + ParseRule(); + break; + default: + // Fehlerbehandlung: ueberlesen + nToken = GetNextToken(); + break; + } + } +} + +// rule +// : selector [ ',' selector ]* +// '{' declaration [ ';' declaration ]* '}' +// +void CSS1Parser::ParseRule() +{ + // selector + CSS1Selector *pSelector = ParseSelector(); + if( !pSelector ) + return; + + // Selektor verarbeiten + if( SelectorParsed( pSelector, sal_True ) ) + delete pSelector; + + LOOP_CHECK_DECL + + // [ ',' selector ]* + while( CSS1_COMMA==nToken && IsParserWorking() ) + { + LOOP_CHECK_CHECK( "Endlos-Schleife in ParseRule()/selector *" ) + + // ',' ueberelesen + nToken = GetNextToken(); + + // selector + pSelector = ParseSelector(); + if( !pSelector ) + return; + + // Selektor verarbeiten + if( SelectorParsed( pSelector, sal_False ) ) + delete pSelector; + } + + // '{' + if( CSS1_OBRACE != nToken ) + return; + nToken = GetNextToken(); + + // declaration + String aProperty; + CSS1Expression *pExpr = ParseDeclaration( aProperty ); + if( !pExpr ) + return; + + // expression verarbeiten + if( DeclarationParsed( aProperty, pExpr ) ) + delete pExpr; + + LOOP_CHECK_RESTART + + // [ ';' declaration ]* + while( CSS1_SEMICOLON==nToken && IsParserWorking() ) + { + LOOP_CHECK_CHECK( "Endlos-Schleife in ParseRule()/declaration *" ) + + // ';' + nToken = GetNextToken(); + + // declaration + if( CSS1_IDENT == nToken ) + { + CSS1Expression *pExp = ParseDeclaration( aProperty ); + if( pExp ) + { + // expression verarbeiten + if( DeclarationParsed( aProperty, pExp ) ) + delete pExp; + } + } + } + + // '}' + if( CSS1_CBRACE == nToken ) + nToken = GetNextToken(); +} + +// selector +// : simple_selector+ [ ':' pseudo_element ]? +// +// simple_selector +// : element_name [ DOT_WO_WS class ]? +// | DOT_W_WS class +// | id_selector +// +// element_name +// : IDENT +// +// class +// : IDENT +// +// id_selector +// : '#' IDENT +// +// pseude_element +// : IDENT +// +CSS1Selector *CSS1Parser::ParseSelector() +{ + CSS1Selector *pRoot = 0, *pLast = 0; + + sal_Bool bDone = sal_False; + CSS1Selector *pNew = 0; + + LOOP_CHECK_DECL + + // simple_selector+ + while( !bDone && IsParserWorking() ) + { + LOOP_CHECK_CHECK( "Endlos-Schleife in ParseSelector()" ) + + sal_Bool bNextToken = sal_True; + + switch( nToken ) + { + case CSS1_IDENT: + { + // element_name [ DOT_WO_WS class ]? + + // element_name + String aElement = aToken; + CSS1SelectorType eType = CSS1_SELTYPE_ELEMENT; + nToken = GetNextToken(); + + if( CSS1_DOT_WO_WS == nToken ) + { + // DOT_WO_WS + nToken = GetNextToken(); + + // class + if( CSS1_IDENT == nToken ) + { + (aElement += '.') += aToken; + eType = CSS1_SELTYPE_ELEM_CLASS; + } + else + { + // class fehlt + return pRoot; + } + } + else + { + // das war jetzt ein Look-Ahead + bNextToken = sal_False; + } + pNew = new CSS1Selector( eType, aElement ); + } + break; + case CSS1_DOT_W_WS: + // DOT_W_WS class + + // DOT_W_WS + nToken = GetNextToken(); + + if( CSS1_IDENT==nToken ) + { + // class + pNew = new CSS1Selector( CSS1_SELTYPE_CLASS, aToken ); + } + else + { + // class fehlt + return pRoot; + } + break; + case CSS1_HASH: + // '#' id_selector + + // '#' + nToken = GetNextToken(); + + if( CSS1_IDENT==nToken ) + { + // id_selector + pNew = new CSS1Selector( CSS1_SELTYPE_ID, aToken ); + } + else + { + // id_selector fehlt + return pRoot; + } + break; + +// /Feature: PrintExt + case CSS1_PAGE_SYM: + { + // @page + pNew = new CSS1Selector( CSS1_SELTYPE_PAGE, aToken ); + } + break; +// /Feature: PrintExt + + default: + // wir wissen nicht was kommt, also aufhoehren + bDone = sal_True; + break; + } + + // falls ein Selektor angelegt wurd, ihn speichern + if( pNew ) + { + DBG_ASSERT( (pRoot!=0) == (pLast!=0), + "Root-Selektor, aber kein Last" ); + if( pLast ) + pLast->SetNext( pNew ); + else + pRoot = pNew; + + pLast = pNew; + pNew = 0; + } + + if( bNextToken && !bDone ) + nToken = GetNextToken(); + } + + if( !pRoot ) + { + // simple_selector fehlt + return pRoot; + } + + // [ ':' pseudo_element ]? + if( CSS1_COLON==nToken && IsParserWorking() ) + { + // ':' pseudo element + nToken = GetNextToken(); + if( CSS1_IDENT==nToken ) + { + pLast->SetNext( new CSS1Selector(CSS1_SELTYPE_PSEUDO,aToken) ); + nToken = GetNextToken(); + } + else + { + // pseudo_element fehlt + return pRoot; + } + } + + return pRoot; +} + +// declaration +// : property ':' expr prio? +// | /* empty */ +// +// expression +// : term [ operator term ]* +// +// term +// : unary_operator? +// [ NUMBER | STRING | PERCENTAGE | LENGTH | EMS | EXS | IDENT | +// HEXCOLOR | URL | RGB ] +// +// operator +// : '/' | ',' | /* empty */ +// +// unary_operator +// : '-' | '+' +// +// property +// : ident +// +// das Vorzeichen wird nur fuer numerische Werte (ausser PERCENTAGE) +// beruecksichtigt und wird auf nValue angewendet! +CSS1Expression *CSS1Parser::ParseDeclaration( String& rProperty ) +{ + CSS1Expression *pRoot = 0, *pLast = 0; + + // property + if( CSS1_IDENT != nToken ) + { + // property fehlt + return pRoot; + } + rProperty = aToken; + + nToken = GetNextToken(); + + + // ':' + if( CSS1_COLON != nToken ) + { + // ':' fehlt + return pRoot; + } + nToken = GetNextToken(); + + // term [operator term]* + // hier sind wir sehr lax, was die Syntax angeht, sollte aber kein + // Problem sein + sal_Bool bDone = sal_False; + sal_Unicode cSign = 0, cOp = 0; + CSS1Expression *pNew = 0; + + LOOP_CHECK_DECL + + while( !bDone && IsParserWorking() ) + { + LOOP_CHECK_CHECK( "Endlos-Schleife in ParseDeclaration()" ) + + switch( nToken ) + { + case CSS1_MINUS: + cSign = '-'; + break; + + case CSS1_PLUS: + cSign = '+'; + break; + + case CSS1_NUMBER: + case CSS1_LENGTH: + case CSS1_PIXLENGTH: + case CSS1_EMS: + case CSS1_EMX: + if( '-'==cSign ) + nValue = -nValue; + case CSS1_STRING: + case CSS1_PERCENTAGE: + case CSS1_IDENT: + case CSS1_URL: + case CSS1_RGB: + case CSS1_HEXCOLOR: + pNew = new CSS1Expression( nToken, aToken, nValue, cOp ); + nValue = 0; // sonst landet das auch im naechsten Ident + cSign = 0; + cOp = 0; + break; + + case CSS1_SLASH: + cOp = '/'; + cSign = 0; + break; + + case CSS1_COMMA: + cOp = ','; + cSign = 0; + break; + + default: + bDone = sal_True; + break; + } + + // falls ein Expression angelegt wurde, diesen speichern + if( pNew ) + { + DBG_ASSERT( (pRoot!=0) == (pLast!=0), + "Root-Selektor, aber kein Last" ); + if( pLast ) + pLast->SetNext( pNew ); + else + pRoot = pNew; + + pLast = pNew; + pNew = 0; + } + + if( !bDone ) + nToken = GetNextToken(); + } + + if( !pRoot ) + { + // term fehlt + return pRoot; + } + + // prio? + if( CSS1_IMPORTANT_SYM==nToken ) + { + // IMPORTANT_SYM + nToken = GetNextToken(); + } + + return pRoot; +} + +/* */ + +CSS1Parser::CSS1Parser() +{ +} + +CSS1Parser::~CSS1Parser() +{ +} + +/* */ + +sal_Bool CSS1Parser::ParseStyleSheet( const String& rIn ) +{ + String aTmp( rIn ); + + sal_Unicode c; + while( aTmp.Len() && + ( ' '==(c=aTmp.GetChar(0)) || '\t'==c || '\r'==c || '\n'==c ) ) + aTmp.Erase( 0, 1 ); + + while( aTmp.Len() && ( ' '==(c=aTmp.GetChar( aTmp.Len()-1)) + || '\t'==c || '\r'==c || '\n'==c ) ) + aTmp.Erase( aTmp.Len()-1 ); + + // SGML-Kommentare entfernen + if( aTmp.Len() >= 4 && + aTmp.CompareToAscii("<!--",4) == COMPARE_EQUAL ) + aTmp.Erase( 0, 4 ); + + if( aTmp.Len() >=3 && + aTmp.Copy(aTmp.Len()-3).CompareToAscii("-->") == COMPARE_EQUAL ) + aTmp.Erase( aTmp.Len()-3 ); + + if( !aTmp.Len() ) + return sal_True; + + InitRead( aTmp ); + + ParseStyleSheet(); + + return sal_True; +} + + +sal_Bool CSS1Parser::ParseStyleOption( const String& rIn ) +{ + if( !rIn.Len() ) + return sal_True; + + InitRead( rIn ); + + String aProperty; + CSS1Expression *pExpr = ParseDeclaration( aProperty ); + if( !pExpr ) + { + return sal_False; + } + + // expression verarbeiten + if( DeclarationParsed( aProperty, pExpr ) ) + delete pExpr; + + LOOP_CHECK_DECL + + // [ ';' declaration ]* + while( CSS1_SEMICOLON==nToken && IsParserWorking() ) + { + LOOP_CHECK_CHECK( "Endlos-Schleife in ParseStyleOption()" ) + + nToken = GetNextToken(); + if( CSS1_IDENT==nToken ) + { + CSS1Expression *pExp = ParseDeclaration( aProperty ); + if( pExp ) + { + // expression verarbeiten + if( DeclarationParsed( aProperty, pExp ) ) + delete pExp; + } + } + } + + return sal_True; +} + +sal_Bool CSS1Parser::SelectorParsed( const CSS1Selector * /* pSelector */, sal_Bool /*bFirst*/ ) +{ + // Selektor loeschen + return sal_True; +} + +sal_Bool CSS1Parser::DeclarationParsed( const String& /*rProperty*/, + const CSS1Expression * /* pExpr */ ) +{ + // Deklaration loeschen + return sal_True; +} + + +/* */ + +CSS1Selector::~CSS1Selector() +{ + delete pNext; +} + +/* */ + +CSS1Expression::~CSS1Expression() +{ + delete pNext; +} + +sal_Bool CSS1Expression::GetURL( String& rURL ) const +{ + DBG_ASSERT( CSS1_URL==eType, "CSS1-Ausruck ist keine Farbe URL" ); + + DBG_ASSERT( aValue.CompareIgnoreCaseToAscii( sCSS1_url, 3 ) == + COMPARE_EQUAL && + aValue.Len() > 5 && + '(' == aValue.GetChar(3) && + ')' == aValue.GetChar(aValue.Len()-1), + "keine gueltiges URL(...)" ); + + sal_Bool bRet = sal_False; + + if( aValue.Len() > 5 ) + { + rURL = aValue.Copy( 4, aValue.Len()-5 ); + rURL.EraseTrailingChars(); + rURL.EraseLeadingChars(); + bRet = sal_True; + } + + return bRet; +} + +sal_Bool CSS1Expression::GetColor( Color &rColor ) const +{ + DBG_ASSERT( CSS1_IDENT==eType || CSS1_RGB==eType || + CSS1_HEXCOLOR==eType || CSS1_STRING==eType, + "CSS1-Ausruck kann keine Farbe sein" ); + + sal_Bool bRet = sal_False; + sal_uLong nColor = ULONG_MAX; + + switch( eType ) + { + case CSS1_RGB: + { + sal_uInt8 aColors[3] = { 0, 0, 0 }; + + DBG_ASSERT( aValue.CompareIgnoreCaseToAscii( sCSS1_rgb, 3 ) + == COMPARE_EQUAL && + aValue.Len() > 5 && + '(' == aValue.GetChar( 3 ) && + ')' == aValue.GetChar( aValue.Len()-1), + "keine gueltiges RGB(...)" ); + + String aColorStr( aValue.Copy( 4, aValue.Len()-1 ) ); + + xub_StrLen nPos = 0; + sal_uInt16 nCol = 0; + + while( nCol < 3 && nPos < aColorStr.Len() ) + { + sal_Unicode c; + while( nPos < aColorStr.Len() && + ((c=aColorStr.GetChar(nPos)) == ' ' || c == '\t' || + c == '\n' || c== '\r' ) ) + nPos++; + + xub_StrLen nEnd = aColorStr.Search( ',', nPos ); + String aNumber; + if( STRING_NOTFOUND==nEnd ) + { + aNumber = aColorStr.Copy(nPos); + nPos = aColorStr.Len(); + } + else + { + aNumber = aColorStr.Copy( nPos, nEnd-nPos ); + nPos = nEnd+1; + } + + sal_uInt16 nNumber = (sal_uInt16)aNumber.ToInt32(); + if( aNumber.Search('%') != STRING_NOTFOUND ) + { + if( nNumber > 100 ) + nNumber = 100; + nNumber *= 255; + nNumber /= 100; + } + else if( nNumber > 255 ) + nNumber = 255; + + aColors[nCol] = (sal_uInt8)nNumber; + nCol ++; + } + + rColor.SetRed( aColors[0] ); + rColor.SetGreen( aColors[1] ); + rColor.SetBlue( aColors[2] ); + + bRet = sal_True; // etwas anderes als eine Farbe kann es nicht sein + } + break; + + case CSS1_IDENT: + case CSS1_STRING: + { + String aTmp( aValue ); + aTmp.ToUpperAscii(); + nColor = GetHTMLColor( aTmp ); + bRet = nColor != ULONG_MAX; + } + if( bRet || CSS1_STRING != eType || !aValue.Len() || + aValue.GetChar( 0 )!='#' ) + break; + + case CSS1_HEXCOLOR: + { + // HACK fuer MS-IE: DIe Farbe kann auch in einem String stehen + xub_StrLen nOffset = CSS1_STRING==eType ? 1 : 0; + sal_Bool bDouble = aValue.Len()-nOffset == 3; + xub_StrLen i = nOffset, nEnd = (bDouble ? 3 : 6) + nOffset; + + nColor = 0; + for( ; i<nEnd; i++ ) + { + sal_Unicode c = (i<aValue.Len() ? aValue.GetChar(i) + : '0' ); + if( c >= '0' && c <= '9' ) + c -= 48; + else if( c >= 'A' && c <= 'F' ) + c -= 55; + else if( c >= 'a' && c <= 'f' ) + c -= 87; + else + c = 16; + + nColor *= 16; + if( c<16 ) + nColor += c; + if( bDouble ) + { + nColor *= 16; + if( c<16 ) + nColor += c; + } + } + // bRet = i==6; + bRet = sal_True; + } + break; + default: + ; + } + + + if( bRet && nColor!=ULONG_MAX ) + { + rColor.SetRed( (sal_uInt8)((nColor & 0x00ff0000UL) >> 16) ); + rColor.SetGreen( (sal_uInt8)((nColor & 0x0000ff00UL) >> 8) ); + rColor.SetBlue( (sal_uInt8)(nColor & 0x000000ffUL) ); + } + + return bRet; +} + diff --git a/sw/source/filter/html/parcss1.hxx b/sw/source/filter/html/parcss1.hxx new file mode 100644 index 000000000000..7d85f05e4a7f --- /dev/null +++ b/sw/source/filter/html/parcss1.hxx @@ -0,0 +1,307 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _PARCSS1_HXX +#define _PARCSS1_HXX + +#include <tools/string.hxx> + +class Color; + +/* */ + +// Die Tokens des CSS1-Parsers +enum CSS1Token +{ + CSS1_NULL, + CSS1_UNKOWN, + + CSS1_IDENT, + CSS1_STRING, + CSS1_NUMBER, + CSS1_PERCENTAGE, + CSS1_LENGTH, // eine absolute Groesse in 1/100 MM + CSS1_PIXLENGTH, // eine Pixel-Groesse + CSS1_EMS, + CSS1_EMX, + CSS1_HEXCOLOR, + + CSS1_DOT_W_WS, + CSS1_DOT_WO_WS, + CSS1_COLON, + CSS1_SLASH, + CSS1_PLUS, + CSS1_MINUS, + CSS1_OBRACE, + CSS1_CBRACE, + CSS1_SEMICOLON, + CSS1_COMMA, + CSS1_HASH, + + CSS1_IMPORT_SYM, +// Feature: PrintExt + CSS1_PAGE_SYM, +// /Feature: PrintExt + + CSS1_IMPORTANT_SYM, + + CSS1_URL, + CSS1_RGB +}; + + +// die Zustaende des Parsers +enum CSS1ParserState +{ + CSS1_PAR_ACCEPTED = 0, + CSS1_PAR_WORKING, + CSS1_PAR_ERROR +}; + + +/* */ + +enum CSS1SelectorType +{ + CSS1_SELTYPE_ELEMENT, + CSS1_SELTYPE_ELEM_CLASS, + CSS1_SELTYPE_CLASS, + CSS1_SELTYPE_ID, + CSS1_SELTYPE_PSEUDO, +// Feature: PrintExt + CSS1_SELTYPE_PAGE +// /Feature: PrintExt + +}; + +// Die folegende Klasse beschreibt einen Simple-Selector, also +// - einen HTML-Element-Namen +// - einen HTML-Element-Namen mit Klasse (durch '.' getrennt) +// - eine Klasse (ohne Punkt) +// - eine mit ID=xxx gesetzte ID aus einem HTML-Dokument +// oder +// - ein Pseudo-Element +// +// Die Simple-Sektoren werden in einer Liste zu vollstaendigen +// Selektoren verkettet +class CSS1Selector +{ + CSS1SelectorType eType; // Art des Selektors + String aSelector; // der Selektor selbst + CSS1Selector *pNext; // die naechste Komponente + +public: + + CSS1Selector( CSS1SelectorType eTyp, const String &rSel ) + : eType(eTyp), aSelector( rSel ), pNext( 0 ) + {} + + ~CSS1Selector(); + + CSS1SelectorType GetType() const { return eType; } + const String& GetString() const { return aSelector; } + + void SetNext( CSS1Selector *pNxt ) { pNext = pNxt; } + const CSS1Selector *GetNext() const { return pNext; } +}; + + +/* */ + +// Die folegende Klasse beschreibt einen Teil-Ausdruck einer +// CSS1-Deklaration sie besteht aus +// +// - dem Typ des Ausdrucks (entspricht dem Token) +// - dem eigentlichen Wert als String und ggf. double +// der double-Wert enthaelt das Vorzeichen fuer NUMBER und LENGTH +// - und dem Operator, mit dem er mit dem *Vorganger*-Ausdruck +// verknuepft ist. +// +struct CSS1Expression +{ + sal_Unicode cOp; // Art der Verkuepfung mit dem Vorgaenger + CSS1Token eType; // der Typ des Wertes + String aValue; // und sein Wert als String + double nValue; // und als Zahl (TWIPs fuer LENGTH) + CSS1Expression *pNext; // die naechste Komponente + +public: + + CSS1Expression( CSS1Token eTyp, const String &rVal, + double nVal, sal_Unicode cO = 0 ) + : cOp(cO), eType(eTyp), aValue(rVal), nValue(nVal), pNext(0) + {} + + ~CSS1Expression(); + + inline void Set( CSS1Token eTyp, const String &rVal, double nVal, + sal_Unicode cO = 0 ); + + CSS1Token GetType() const { return eType; } + const String& GetString() const { return aValue; } + double GetNumber() const { return nValue; } + inline sal_uInt32 GetULength() const; + inline sal_Int32 GetSLength() const; + sal_Unicode GetOp() const { return cOp; } + + + sal_Bool GetURL( String& rURL ) const; + sal_Bool GetColor( Color &rRGB ) const; + + void SetNext( CSS1Expression *pNxt ) { pNext = pNxt; } + const CSS1Expression *GetNext() const { return pNext; } +}; + +inline void CSS1Expression::Set( CSS1Token eTyp, const String &rVal, + double nVal, sal_Unicode cO ) +{ + cOp = cO; eType = eTyp; aValue = rVal; nValue = nVal; pNext = 0; +} + +inline sal_uInt32 CSS1Expression::GetULength() const +{ + return nValue < 0. ? 0UL : (sal_uInt32)(nValue + .5); +} + +inline sal_Int32 CSS1Expression::GetSLength() const +{ + return (sal_Int32)(nValue + (nValue < 0. ? -.5 : .5 )); +} + +/* */ + +// Diese Klasse parst den Inhalt eines Style-Elements oder eine Style-Option +// und bereitet ihn ein wenig auf. +// +// Das Ergebnis des Parsers wird durch die Mehtoden SelectorParsed() +// und DeclarationParsed() an abgeleitete Parser uebergeben. Bsp: +// +// H1, H2 { font-weight: bold; text-align: right } +// | | | | +// | | | DeclP( 'text-align', 'right' ) +// | | DeclP( 'font-weight', 'bold' ) +// | SelP( 'H2', sal_False ) +// SelP( 'H1', sal_True ) +// +class CSS1Parser +{ + sal_Bool bWhiteSpace : 1; // White-Space gelesen? + sal_Bool bEOF : 1; // Ende des "Files" ? + + sal_Unicode cNextCh; // naechstes Zeichen + + xub_StrLen nInPos; // aktuelle Position im Input-String + + sal_uInt32 nlLineNr; // akt. Zeilen Nummer + sal_uInt32 nlLinePos; // akt. Spalten Nummer + + double nValue; // der Wert des Tokens als Zahl + + CSS1ParserState eState; // der akteulle Zustand der Parsers + CSS1Token nToken; // das aktuelle Token + + String aIn; // der zu parsende String + String aToken; // das Token als String + + // Parsen vorbereiten + void InitRead( const String& rIn ); + + // das naechste Zeichen holen + sal_Unicode GetNextChar(); + + // das naechste Token holen + CSS1Token GetNextToken(); + + // arbeitet der Parser noch? + sal_Bool IsParserWorking() const { return CSS1_PAR_WORKING == eState; } + + sal_Bool IsEOF() const { return bEOF; } + + sal_uInt32 IncLineNr() { return ++nlLineNr; } + sal_uInt32 IncLinePos() { return ++nlLinePos; } + inline sal_uInt32 SetLineNr( sal_uInt32 nlNum ); // inline unten + inline sal_uInt32 SetLinePos( sal_uInt32 nlPos ); // inline unten + + // Parsen von Teilen der Grammatik + void ParseRule(); + CSS1Selector *ParseSelector(); + CSS1Expression *ParseDeclaration( String& rProperty ); + +protected: + + void ParseStyleSheet(); + + // Den Inhalt eines HTML-Style-Elements parsen. + // Fuer jeden Selektor und jede Deklaration wird + // SelectorParsed() bzw. DeclarationParsed() aufgerufen. + sal_Bool ParseStyleSheet( const String& rIn ); + + // Den Inhalt einer HTML-Style-Option parsen. + // F�r jede Deklaration wird DeclarationParsed() aufgerufen. + sal_Bool ParseStyleOption( const String& rIn ); + + // Diese Methode wird aufgerufen, wenn ein Selektor geparsed wurde + // Wenn 'bFirst' gesetzt ist, beginnt mit dem Selektor eine neue + // Deklaration. Wird sal_True zurueckgegeben, wird der Selektor + // geloscht, sonst nicht. + // Die Implementierung dieser Methode gibt nur sal_True zuruck. + virtual sal_Bool SelectorParsed( const CSS1Selector *pSelector, + sal_Bool bFirst ); + + // Diese Methode wird fuer jede geparsete Property aufgerufen. Wird + // sal_True zurueckgegeben wird der Selektor geloscht, sonst nicht. + // Die Implementierung dieser Methode gibt nur sal_True zuruck. + virtual sal_Bool DeclarationParsed( const String& rProperty, + const CSS1Expression *pExpr ); + +public: + + CSS1Parser(); + virtual ~CSS1Parser(); + + inline sal_uInt32 GetLineNr() const { return nlLineNr; } + inline sal_uInt32 GetLinePos() const { return nlLinePos; } +}; + +inline sal_uInt32 CSS1Parser::SetLineNr( sal_uInt32 nlNum ) +{ + sal_uInt32 nlOld = nlLineNr; + nlLineNr = nlNum; + return nlOld; +} + +inline sal_uInt32 CSS1Parser::SetLinePos( sal_uInt32 nlPos ) +{ + sal_uInt32 nlOld = nlLinePos; + nlLinePos = nlPos; + return nlOld; +} + + +#endif + + diff --git a/sw/source/filter/html/svxcss1.cxx b/sw/source/filter/html/svxcss1.cxx new file mode 100644 index 000000000000..0590f7881799 --- /dev/null +++ b/sw/source/filter/html/svxcss1.cxx @@ -0,0 +1,3311 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <stdlib.h> + +#ifndef _SVX_SVXIDS_HRC +#include <svx/svxids.hrc> +#endif +#include <i18npool/mslangid.hxx> +#include <svtools/ctrltool.hxx> +#include <svl/urihelper.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/adjitem.hxx> +#include <editeng/blnkitem.hxx> +#include <editeng/crsditem.hxx> +#include <editeng/kernitem.hxx> +#include <editeng/lspcitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/cmapitem.hxx> +#include <editeng/brshitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/boxitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/langitem.hxx> +#include <svl/itempool.hxx> +#include <editeng/spltitem.hxx> +#include <editeng/widwitem.hxx> +#include <editeng/frmdiritem.hxx> +#include <editeng/orphitem.hxx> +#include <svtools/svparser.hxx> +#include <vcl/svapp.hxx> +#include <vcl/wrkwin.hxx> + +#include "css1kywd.hxx" +#include "svxcss1.hxx" + +// die Funktionen zum Parsen einer CSS1-Property sind von folgendem Typ: +typedef void (*FnParseCSS1Prop)( const CSS1Expression *pExpr, + SfxItemSet& rItemSet, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& rParser ); + +SV_IMPL_PTRARR( CSS1Selectors, CSS1Selector* ) + + +/* */ + +static CSS1PropertyEnum __READONLY_DATA aFontSizeTable[] = +{ + { sCSS1_PV_xx_small, 0 }, + { sCSS1_PV_x_small, 1 }, + { sCSS1_PV_small, 2 }, + { sCSS1_PV_medium, 3 }, + { sCSS1_PV_large, 4 }, + { sCSS1_PV_x_large, 5 }, + { sCSS1_PV_xx_large, 6 }, + { 0, 0 } +}; + +static CSS1PropertyEnum __READONLY_DATA aFontFamilyTable[] = +{ + { sCSS1_PV_serif, FAMILY_ROMAN }, + { sCSS1_PV_sans_serif, FAMILY_SWISS }, + { sCSS1_PV_cursive, FAMILY_SCRIPT }, + { sCSS1_PV_fantasy, FAMILY_DECORATIVE }, + { sCSS1_PV_monospace, FAMILY_MODERN }, + { 0, 0 } +}; + +static CSS1PropertyEnum __READONLY_DATA aFontWeightTable[] = +{ + { sCSS1_PV_extra_light, WEIGHT_NORMAL }, // WEIGHT_ULTRALIGHT (OBS) + { sCSS1_PV_light, WEIGHT_NORMAL }, // WEIGHT_LIGHT (OBSOLETE) + { sCSS1_PV_demi_light, WEIGHT_NORMAL }, // WEIGHT_SEMILIGHT (OBS) + { sCSS1_PV_medium, WEIGHT_NORMAL }, // WEIGHT_MEDIUM (OBS) + { sCSS1_PV_normal, WEIGHT_NORMAL }, // WEIGHT_MEDIUM + { sCSS1_PV_demi_bold, WEIGHT_NORMAL }, // WEIGHT_SEMIBOLD (OBS) + { sCSS1_PV_bold, WEIGHT_BOLD }, // WEIGHT_BOLD (OBSOLETE) + { sCSS1_PV_extra_bold, WEIGHT_BOLD }, // WEIGHT_ULTRABOLD (OBS) + { sCSS1_PV_bolder, WEIGHT_BOLD }, + { sCSS1_PV_lighter, WEIGHT_NORMAL }, + { 0, 0 } +}; + +static CSS1PropertyEnum __READONLY_DATA aFontStyleTable[] = +{ + { sCSS1_PV_normal, ITALIC_NONE }, + { sCSS1_PV_italic, ITALIC_NORMAL }, + { sCSS1_PV_oblique, ITALIC_NORMAL }, + { 0, 0 } +}; + +static CSS1PropertyEnum __READONLY_DATA aFontVariantTable[] = +{ + { sCSS1_PV_normal, SVX_CASEMAP_NOT_MAPPED }, + { sCSS1_PV_small_caps, SVX_CASEMAP_KAPITAELCHEN }, + { 0, 0 } +}; + +static CSS1PropertyEnum __READONLY_DATA aDirectionTable[] = +{ + { sCSS1_PV_ltr, FRMDIR_HORI_LEFT_TOP }, + { sCSS1_PV_rtl, FRMDIR_HORI_RIGHT_TOP }, + { sCSS1_PV_inherit, FRMDIR_ENVIRONMENT }, + { 0, 0 } +}; + +/* */ + +static CSS1PropertyEnum __READONLY_DATA aBGRepeatTable[] = +{ + { sCSS1_PV_repeat, GPOS_TILED }, + { sCSS1_PV_repeat_x, GPOS_TILED }, + { sCSS1_PV_repeat_y, GPOS_TILED }, + { sCSS1_PV_no_repeat, GPOS_NONE }, + { 0, 0 } +}; + +static CSS1PropertyEnum __READONLY_DATA aBGHoriPosTable[] = +{ + { sCSS1_PV_left, GPOS_LT }, + { sCSS1_PV_center, GPOS_MT }, + { sCSS1_PV_right, GPOS_RT }, + { 0, 0 } +}; + +static CSS1PropertyEnum __READONLY_DATA aBGVertPosTable[] = +{ + { sCSS1_PV_top, GPOS_LT }, + { sCSS1_PV_middle, GPOS_LM }, + { sCSS1_PV_bottom, GPOS_LB }, + { 0, 0 } +}; + +/* */ + +static CSS1PropertyEnum __READONLY_DATA aTextAlignTable[] = +{ + { sCSS1_PV_left, SVX_ADJUST_LEFT }, + { sCSS1_PV_center, SVX_ADJUST_CENTER }, + { sCSS1_PV_right, SVX_ADJUST_RIGHT }, + { sCSS1_PV_justify, SVX_ADJUST_BLOCK }, + { 0, 0 } +}; + +/* */ + +static CSS1PropertyEnum __READONLY_DATA aBorderWidthTable[] = +{ + { sCSS1_PV_thin, 0 }, // DEF_LINE_WIDTH_0 / DEF_DOUBLE_LINE0 + { sCSS1_PV_medium, 1 }, // DEF_LINE_WIDTH_1 / DEF_DOUBLE_LINE1 + { sCSS1_PV_thick, 2 }, // DEF_LINE_WIDTH_2 / DEF_DOUBLE_LINE2 + { 0, 0 } +}; + +enum CSS1BorderStyle { CSS1_BS_NONE, CSS1_BS_SINGLE, CSS1_BS_DOUBLE }; + +static CSS1PropertyEnum __READONLY_DATA aBorderStyleTable[] = +{ + { sCSS1_PV_none, CSS1_BS_NONE }, + { sCSS1_PV_dotted, CSS1_BS_SINGLE }, + { sCSS1_PV_dashed, CSS1_BS_SINGLE }, + { sCSS1_PV_solid, CSS1_BS_SINGLE }, + { sCSS1_PV_double, CSS1_BS_DOUBLE }, + { sCSS1_PV_groove, CSS1_BS_SINGLE }, + { sCSS1_PV_ridge, CSS1_BS_SINGLE }, + { sCSS1_PV_inset, CSS1_BS_SINGLE }, + { sCSS1_PV_outset, CSS1_BS_SINGLE }, + { 0, 0 } +}; + +static CSS1PropertyEnum __READONLY_DATA aFloatTable[] = +{ + { sCSS1_PV_left, SVX_ADJUST_LEFT }, + { sCSS1_PV_right, SVX_ADJUST_RIGHT }, + { sCSS1_PV_none, SVX_ADJUST_END }, + { 0, 0 } +}; + +static CSS1PropertyEnum __READONLY_DATA aPositionTable[] = +{ + { sCSS1_PV_absolute, SVX_CSS1_POS_ABSOLUTE }, + { sCSS1_PV_relative, SVX_CSS1_POS_RELATIVE }, + { sCSS1_PV_static, SVX_CSS1_POS_STATIC }, + { 0, 0 } +}; + +// Feature: PrintExt +static CSS1PropertyEnum __READONLY_DATA aSizeTable[] = +{ + { sCSS1_PV_auto, SVX_CSS1_STYPE_AUTO }, + { sCSS1_PV_landscape, SVX_CSS1_STYPE_LANDSCAPE }, + { sCSS1_PV_portrait, SVX_CSS1_STYPE_PORTRAIT }, + { 0, 0 } +}; + +static CSS1PropertyEnum __READONLY_DATA aPageBreakTable[] = +{ + { sCSS1_PV_auto, SVX_CSS1_PBREAK_AUTO }, + { sCSS1_PV_always, SVX_CSS1_PBREAK_ALWAYS }, + { sCSS1_PV_avoid, SVX_CSS1_PBREAK_AVOID }, + { sCSS1_PV_left, SVX_CSS1_PBREAK_LEFT }, + { sCSS1_PV_right, SVX_CSS1_PBREAK_RIGHT }, + { 0, 0 } +}; + +// /Feature: PrintExt + +/* */ + +// Ein Eintrag besteht aus vier USHORTs. Der erste ist die Gesamtbreite, +// die anderen sind die 3 Einzelbreiten + +#define SBORDER_ENTRY( n ) \ + DEF_LINE_WIDTH_##n, DEF_LINE_WIDTH_##n, 0, 0 + +#define DBORDER_ENTRY( n ) \ + DEF_DOUBLE_LINE##n##_OUT + DEF_DOUBLE_LINE##n##_IN + \ + DEF_DOUBLE_LINE##n##_DIST, \ + DEF_DOUBLE_LINE##n##_OUT, \ + DEF_DOUBLE_LINE##n##_IN, \ + DEF_DOUBLE_LINE##n##_DIST + +#define TDBORDER_ENTRY( n ) \ + DEF_DOUBLE_LINE##n##_OUT, \ + DEF_DOUBLE_LINE##n##_OUT, \ + DEF_DOUBLE_LINE##n##_IN, \ + DEF_DOUBLE_LINE##n##_DIST + + +static sal_uInt16 __READONLY_DATA aSBorderWidths[] = +{ + SBORDER_ENTRY( 0 ), SBORDER_ENTRY( 1 ), SBORDER_ENTRY( 2 ), + SBORDER_ENTRY( 3 ), SBORDER_ENTRY( 4 ) +}; + +static sal_uInt16 __READONLY_DATA aDBorderWidths[] = +{ + DBORDER_ENTRY( 0 ), + DBORDER_ENTRY( 7 ), + DBORDER_ENTRY( 1 ), + DBORDER_ENTRY( 8 ), + DBORDER_ENTRY( 4 ), + DBORDER_ENTRY( 9 ), + DBORDER_ENTRY( 3 ), + DBORDER_ENTRY( 10 ), + DBORDER_ENTRY( 2 ), + DBORDER_ENTRY( 5 ) +}; + +static sal_uInt16 __READONLY_DATA aTDBorderWidths[] = +{ + TDBORDER_ENTRY( 7 ), TDBORDER_ENTRY( 8 ), TDBORDER_ENTRY( 9 ), + TDBORDER_ENTRY( 10 ) +}; + +#undef SBORDER_ENTRY +#undef DBORDER_ENTRY + +/* */ + +struct SvxCSS1ItemIds +{ + sal_uInt16 nFont; + sal_uInt16 nFontCJK; + sal_uInt16 nFontCTL; + sal_uInt16 nPosture; + sal_uInt16 nPostureCJK; + sal_uInt16 nPostureCTL; + sal_uInt16 nWeight; + sal_uInt16 nWeightCJK; + sal_uInt16 nWeightCTL; + sal_uInt16 nFontHeight; + sal_uInt16 nFontHeightCJK; + sal_uInt16 nFontHeightCTL; + sal_uInt16 nUnderline; + sal_uInt16 nOverline; + sal_uInt16 nCrossedOut; + sal_uInt16 nColor; + sal_uInt16 nKerning; + sal_uInt16 nCaseMap; + sal_uInt16 nBlink; + + sal_uInt16 nLineSpacing; + sal_uInt16 nAdjust; + sal_uInt16 nWidows; + sal_uInt16 nOrphans; + sal_uInt16 nFmtSplit; + + sal_uInt16 nLRSpace; + sal_uInt16 nULSpace; + sal_uInt16 nBox; + sal_uInt16 nBrush; + + sal_uInt16 nLanguage; + sal_uInt16 nLanguageCJK; + sal_uInt16 nLanguageCTL; + sal_uInt16 nDirection; +}; + + +static SvxCSS1ItemIds aItemIds; + + +/* */ + +struct SvxCSS1BorderInfo +{ + Color aColor; + sal_uInt16 nAbsWidth; + sal_uInt16 nNamedWidth; + CSS1BorderStyle eStyle; + + SvxCSS1BorderInfo() : + aColor( COL_BLACK ), nAbsWidth( USHRT_MAX ), + nNamedWidth( USHRT_MAX ), eStyle( CSS1_BS_NONE ) + {} + + SvxCSS1BorderInfo( const SvxCSS1BorderInfo& rInfo ) : + aColor( rInfo.aColor ), nAbsWidth( rInfo.nAbsWidth ), + nNamedWidth( rInfo.nNamedWidth ), eStyle( rInfo.eStyle ) + {} + + void SetBorderLine( sal_uInt16 nLine, SvxBoxItem &rBoxItem ) const; +}; + +void SvxCSS1BorderInfo::SetBorderLine( sal_uInt16 nLine, SvxBoxItem &rBoxItem ) const +{ + if( CSS1_BS_NONE==eStyle || nAbsWidth==0 || + (nAbsWidth==USHRT_MAX && nNamedWidth==USHRT_MAX) ) + { + rBoxItem.SetLine( 0, nLine ); + return; + } + + SvxBorderLine aBorderLine( &aColor ); + + // Linien-Stil doppelt oder einfach? + sal_Bool bDouble = eStyle == CSS1_BS_DOUBLE; + + // benannte Breite umrechnenen, wenn keine absolute gegeben ist + if( nAbsWidth==USHRT_MAX ) + { + const sal_uInt16 *aWidths = bDouble ? aDBorderWidths : aSBorderWidths; + sal_uInt16 nNWidth = nNamedWidth * 4; + aBorderLine.SetOutWidth( aWidths[nNWidth+1] ); + aBorderLine.SetInWidth( aWidths[nNWidth+2] ); + aBorderLine.SetDistance( aWidths[nNWidth+3] ); + } + else + { + SvxCSS1Parser::SetBorderWidth( aBorderLine, nAbsWidth, bDouble ); + } + + rBoxItem.SetLine( &aBorderLine, nLine ); +} + + +/* */ + +SvxCSS1PropertyInfo::SvxCSS1PropertyInfo() +{ + for( sal_uInt16 i=0; i<4; i++ ) + aBorderInfos[i] = 0; + + Clear(); +} + +SvxCSS1PropertyInfo::SvxCSS1PropertyInfo( const SvxCSS1PropertyInfo& rProp ) : + aId( rProp.aId ), + bTopMargin( rProp.bTopMargin ), + bBottomMargin( rProp.bBottomMargin ), + bLeftMargin( rProp.bLeftMargin ), + bRightMargin( rProp.bRightMargin ), + bTextIndent( rProp.bTextIndent ), + eFloat( rProp.eFloat ), + ePosition( rProp.ePosition ), + nTopBorderDistance( rProp.nTopBorderDistance ), + nBottomBorderDistance( rProp.nBottomBorderDistance ), + nLeftBorderDistance( rProp.nLeftBorderDistance ), + nRightBorderDistance( rProp.nRightBorderDistance ), + nLeft( rProp.nLeft ), + nTop( rProp.nTop ), + nWidth( rProp.nWidth ), + nHeight( rProp.nHeight ), + nLeftMargin( rProp.nLeftMargin ), + nRightMargin( rProp.nRightMargin ), + eLeftType( rProp.eLeftType ), + eTopType( rProp.eTopType ), + eWidthType( rProp.eWidthType ), + eHeightType( rProp.eHeightType ), +// Feature: PrintExt + eSizeType( rProp.eSizeType ), + ePageBreakBefore( rProp.ePageBreakBefore ), + ePageBreakAfter( rProp.ePageBreakAfter ) +// /Feature: PrintExt +{ + for( sal_uInt16 i=0; i<4; i++ ) + aBorderInfos[i] = rProp.aBorderInfos[i] + ? new SvxCSS1BorderInfo( *rProp.aBorderInfos[i] ) + : 0; +} + +SvxCSS1PropertyInfo::~SvxCSS1PropertyInfo() +{ + DestroyBorderInfos(); +} + +void SvxCSS1PropertyInfo::DestroyBorderInfos() +{ + for( sal_uInt16 i=0; i<4; i++ ) + { + delete aBorderInfos[i]; + aBorderInfos[i] = 0; + } +} + +void SvxCSS1PropertyInfo::Clear() +{ + aId.Erase(); + bTopMargin = bBottomMargin = sal_False; + bLeftMargin = bRightMargin = bTextIndent = sal_False; + nLeftMargin = nRightMargin = 0; + eFloat = SVX_ADJUST_END; + + ePosition = SVX_CSS1_POS_NONE; + nTopBorderDistance = nBottomBorderDistance = + nLeftBorderDistance = nRightBorderDistance = USHRT_MAX; + nLeft = nTop = nWidth = nHeight = 0; + eLeftType = eTopType = eWidthType = eHeightType = SVX_CSS1_LTYPE_NONE; + +// Feature: PrintExt + eSizeType = SVX_CSS1_STYPE_NONE; + ePageBreakBefore = SVX_CSS1_PBREAK_NONE; + ePageBreakAfter = SVX_CSS1_PBREAK_NONE; + + DestroyBorderInfos(); +} + +void SvxCSS1PropertyInfo::Merge( const SvxCSS1PropertyInfo& rProp ) +{ + if( rProp.bTopMargin ) + bTopMargin = sal_True; + if( rProp.bBottomMargin ) + bBottomMargin = sal_True; + + if( rProp.bLeftMargin ) + { + bLeftMargin = sal_True; + nLeftMargin = rProp.nLeftMargin; + } + if( rProp.bRightMargin ) + { + bRightMargin = sal_True; + nRightMargin = rProp.nRightMargin; + } + if( rProp.bTextIndent ) + bTextIndent = sal_True; + + for( sal_uInt16 i=0; i<4; i++ ) + { + if( rProp.aBorderInfos[i] ) + { + if( aBorderInfos[i] ) + delete aBorderInfos[i]; + + aBorderInfos[i] = new SvxCSS1BorderInfo( *rProp.aBorderInfos[i] ); + } + } + + if( USHRT_MAX != rProp.nTopBorderDistance ) + nTopBorderDistance = rProp.nTopBorderDistance; + if( USHRT_MAX != rProp.nBottomBorderDistance ) + nBottomBorderDistance = rProp.nBottomBorderDistance; + if( USHRT_MAX != rProp.nLeftBorderDistance ) + nLeftBorderDistance = rProp.nLeftBorderDistance; + if( USHRT_MAX != rProp.nRightBorderDistance ) + nRightBorderDistance = rProp.nRightBorderDistance; + + if( rProp.eFloat != SVX_ADJUST_END ) + eFloat = rProp.eFloat; + + if( rProp.ePosition != SVX_CSS1_POS_NONE ) + ePosition = rProp.ePosition; + +// Feature: PrintExt + if( rProp.eSizeType != SVX_CSS1_STYPE_NONE ) + { + eSizeType = rProp.eSizeType; + nWidth = rProp.nWidth; + nHeight = rProp.nHeight; + } + + if( rProp.ePageBreakBefore != SVX_CSS1_PBREAK_NONE ) + ePageBreakBefore = rProp.ePageBreakBefore; + + if( rProp.ePageBreakAfter != SVX_CSS1_PBREAK_NONE ) + ePageBreakAfter = rProp.ePageBreakAfter; + +// /Feature: PrintExt + + if( rProp.eLeftType != SVX_CSS1_LTYPE_NONE ) + { + eLeftType = rProp.eLeftType; + nLeft = rProp.nLeft; + } + + if( rProp.eTopType != SVX_CSS1_LTYPE_NONE ) + { + eTopType = rProp.eTopType; + nTop = rProp.nTop; + } + + if( rProp.eWidthType != SVX_CSS1_LTYPE_NONE ) + { + eWidthType = rProp.eWidthType; + nWidth = rProp.nWidth; + } + + if( rProp.eHeightType != SVX_CSS1_LTYPE_NONE ) + { + eHeightType = rProp.eHeightType; + nHeight = rProp.nHeight; + } +} + +SvxCSS1BorderInfo *SvxCSS1PropertyInfo::GetBorderInfo( sal_uInt16 nLine, sal_Bool bCreate ) +{ + sal_uInt16 nPos = 0; + switch( nLine ) + { + case BOX_LINE_TOP: nPos = 0; break; + case BOX_LINE_BOTTOM: nPos = 1; break; + case BOX_LINE_LEFT: nPos = 2; break; + case BOX_LINE_RIGHT: nPos = 3; break; + } + + if( !aBorderInfos[nPos] && bCreate ) + aBorderInfos[nPos] = new SvxCSS1BorderInfo; + + return aBorderInfos[nPos]; +} + +void SvxCSS1PropertyInfo::CopyBorderInfo( sal_uInt16 nSrcLine, sal_uInt16 nDstLine, + sal_uInt16 nWhat ) +{ + SvxCSS1BorderInfo *pSrcInfo = GetBorderInfo( nSrcLine, sal_False ); + if( !pSrcInfo ) + return; + + SvxCSS1BorderInfo *pDstInfo = GetBorderInfo( nDstLine ); + if( (nWhat & SVX_CSS1_BORDERINFO_WIDTH) != 0 ) + { + pDstInfo->nAbsWidth = pSrcInfo->nAbsWidth; + pDstInfo->nNamedWidth = pSrcInfo->nNamedWidth; + } + + if( (nWhat & SVX_CSS1_BORDERINFO_COLOR) != 0 ) + pDstInfo->aColor = pSrcInfo->aColor; + + if( (nWhat & SVX_CSS1_BORDERINFO_STYLE) != 0 ) + pDstInfo->eStyle = pSrcInfo->eStyle; +} + +void SvxCSS1PropertyInfo::CopyBorderInfo( sal_uInt16 nCount, sal_uInt16 nWhat ) +{ + if( nCount==0 ) + { + CopyBorderInfo( BOX_LINE_BOTTOM, BOX_LINE_TOP, nWhat ); + CopyBorderInfo( BOX_LINE_TOP, BOX_LINE_LEFT, nWhat ); + } + if( nCount<=1 ) + { + CopyBorderInfo( BOX_LINE_LEFT, BOX_LINE_RIGHT, nWhat ); + } +} + +void SvxCSS1PropertyInfo::SetBoxItem( SfxItemSet& rItemSet, + sal_uInt16 nMinBorderDist, + const SvxBoxItem *pDfltItem, + sal_Bool bTable ) +{ + sal_Bool bChg = nTopBorderDistance != USHRT_MAX || + nBottomBorderDistance != USHRT_MAX || + nLeftBorderDistance != USHRT_MAX || + nRightBorderDistance != USHRT_MAX; + sal_uInt16 i; + + for( i = 0; !bChg && i < 4; i++ ) + bChg = aBorderInfos[i]!=0; + + if( !bChg ) + return; + + SvxBoxItem aBoxItem( aItemIds.nBox ); + if( pDfltItem ) + aBoxItem = *pDfltItem; + + SvxCSS1BorderInfo *pInfo = GetBorderInfo( BOX_LINE_TOP, sal_False ); + if( pInfo ) + pInfo->SetBorderLine( BOX_LINE_TOP, aBoxItem ); + + pInfo = GetBorderInfo( BOX_LINE_BOTTOM, sal_False ); + if( pInfo ) + pInfo->SetBorderLine( BOX_LINE_BOTTOM, aBoxItem ); + + pInfo = GetBorderInfo( BOX_LINE_LEFT, sal_False ); + if( pInfo ) + pInfo->SetBorderLine( BOX_LINE_LEFT, aBoxItem ); + + pInfo = GetBorderInfo( BOX_LINE_RIGHT, sal_False ); + if( pInfo ) + pInfo->SetBorderLine( BOX_LINE_RIGHT, aBoxItem ); + + for( i=0; i<4; i++ ) + { + sal_uInt16 nLine = BOX_LINE_TOP, nDist = 0; + switch( i ) + { + case 0: nLine = BOX_LINE_TOP; + nDist = nTopBorderDistance; + nTopBorderDistance = USHRT_MAX; + break; + case 1: nLine = BOX_LINE_BOTTOM; + nDist = nBottomBorderDistance; + nBottomBorderDistance = USHRT_MAX; + break; + case 2: nLine = BOX_LINE_LEFT; + nDist = nLeftBorderDistance; + nLeftBorderDistance = USHRT_MAX; + break; + case 3: nLine = BOX_LINE_RIGHT; + nDist = nRightBorderDistance; + nRightBorderDistance = USHRT_MAX; + break; + } + + if( aBoxItem.GetLine( nLine ) ) + { + if( USHRT_MAX == nDist ) + nDist = aBoxItem.GetDistance( nLine ); + + if( nDist < nMinBorderDist ) + nDist = nMinBorderDist; + } + else + { + if( USHRT_MAX == nDist ) + nDist = aBoxItem.GetDistance( nLine ); + + if( !bTable ) + nDist = 0U; + else if( nDist && nDist < nMinBorderDist ) + nDist = nMinBorderDist; + } + + aBoxItem.SetDistance( nDist, nLine ); + } + + rItemSet.Put( aBoxItem ); + + DestroyBorderInfos(); +} + + +/* */ + +SvxCSS1MapEntry::SvxCSS1MapEntry( const String& rKey, const SfxItemSet& rItemSet, + const SvxCSS1PropertyInfo& rProp ) : + aKey( rKey ), + aItemSet( rItemSet ), + aPropInfo( rProp ) +{ + // TODO: ToUpperAscii + aKey.ToUpperAscii(); +} + +#if defined( ICC ) || defined( BLC ) +sal_Bool operator==( const SvxCSS1MapEntry& rE1, const SvxCSS1MapEntry& rE2 ) +{ + return rE1.aKey==rE2.aKey; +} + +sal_Bool operator<( const SvxCSS1MapEntry& rE1, const SvxCSS1MapEntry& rE2 ) +{ + return rE1.aKey<rE2.aKey; +} +#endif + +SV_IMPL_OP_PTRARR_SORT( SvxCSS1Map, SvxCSS1MapEntryPtr ) + +/* */ + +sal_Bool SvxCSS1Parser::StyleParsed( const CSS1Selector * /*pSelector*/, + SfxItemSet& /*rItemSet*/, + SvxCSS1PropertyInfo& /*rPropInfo*/ ) +{ + // wie man sieht passiert hier gar nichts + return sal_True; +} + +sal_Bool SvxCSS1Parser::SelectorParsed( const CSS1Selector *pSelector, + sal_Bool bFirst ) +{ + if( bFirst ) + { + DBG_ASSERT( pSheetItemSet, "Wo ist der Item-Set fuer Style-Sheets?" ); + + // Dieses ist der erste Selektor einer Rule, also muessen + // die bisher geparsten Items auf die Styles verteilt werden +// pSheetPropInfo->CreateBoxItem( *pSheetItemSet, GetDfltBorderDist() ); + for( sal_uInt16 i=0; i<aSelectors.Count(); i++ ) + { + StyleParsed( aSelectors[i], *pSheetItemSet, *pSheetPropInfo ); + } + pSheetItemSet->ClearItem(); + pSheetPropInfo->Clear(); + + // und die naechste Rule vorbereiten + if( aSelectors.Count() ) + aSelectors.DeleteAndDestroy( 0, aSelectors.Count() ); + } + + aSelectors.C40_INSERT( CSS1Selector, pSelector, aSelectors.Count() ); + + return sal_False; // den Selektor haben wir gespeichert. Loeschen toedlich! +} + + +sal_Bool SvxCSS1Parser::DeclarationParsed( const String& rProperty, + const CSS1Expression *pExpr ) +{ + DBG_ASSERT( pExpr, "DeclarationParsed() ohne Expression" ); + + if( !pExpr ) + return sal_True; + + ParseProperty( rProperty, pExpr ); + + return sal_True; // die Deklaration brauchen wir nicht mehr. Loeschen! +} + +/* */ + +SvxCSS1Parser::SvxCSS1Parser( SfxItemPool& rPool, const String& rBaseURL, sal_uInt16 nMinFixLineSp, + sal_uInt16 *pWhichIds, sal_uInt16 nWhichIds ) : + CSS1Parser(), + sBaseURL( rBaseURL ), + pSheetItemSet(0), + pItemSet(0), + pSearchEntry( 0 ), + nMinFixLineSpace( nMinFixLineSp ), + eDfltEnc( RTL_TEXTENCODING_DONTKNOW ), + nScriptFlags( CSS1_SCRIPT_ALL ), + bIgnoreFontFamily( sal_False ) +{ + // Item-Ids auch initialisieren + aItemIds.nFont = rPool.GetTrueWhich( SID_ATTR_CHAR_FONT, sal_False ); + aItemIds.nFontCJK = rPool.GetTrueWhich( SID_ATTR_CHAR_CJK_FONT, sal_False ); + aItemIds.nFontCTL = rPool.GetTrueWhich( SID_ATTR_CHAR_CTL_FONT, sal_False ); + aItemIds.nPosture = rPool.GetTrueWhich( SID_ATTR_CHAR_POSTURE, sal_False ); + aItemIds.nPostureCJK = rPool.GetTrueWhich( SID_ATTR_CHAR_CJK_POSTURE, sal_False ); + aItemIds.nPostureCTL = rPool.GetTrueWhich( SID_ATTR_CHAR_CTL_POSTURE, sal_False ); + aItemIds.nWeight = rPool.GetTrueWhich( SID_ATTR_CHAR_WEIGHT, sal_False ); + aItemIds.nWeightCJK = rPool.GetTrueWhich( SID_ATTR_CHAR_CJK_WEIGHT, sal_False ); + aItemIds.nWeightCTL = rPool.GetTrueWhich( SID_ATTR_CHAR_CTL_WEIGHT, sal_False ); + aItemIds.nFontHeight = rPool.GetTrueWhich( SID_ATTR_CHAR_FONTHEIGHT, sal_False ); + aItemIds.nFontHeightCJK = rPool.GetTrueWhich( SID_ATTR_CHAR_CJK_FONTHEIGHT, sal_False ); + aItemIds.nFontHeightCTL = rPool.GetTrueWhich( SID_ATTR_CHAR_CTL_FONTHEIGHT, sal_False ); + aItemIds.nUnderline = rPool.GetTrueWhich( SID_ATTR_CHAR_UNDERLINE, sal_False ); + aItemIds.nOverline = rPool.GetTrueWhich( SID_ATTR_CHAR_OVERLINE, sal_False ); + aItemIds.nCrossedOut = rPool.GetTrueWhich( SID_ATTR_CHAR_STRIKEOUT, sal_False ); + aItemIds.nColor = rPool.GetTrueWhich( SID_ATTR_CHAR_COLOR, sal_False ); + aItemIds.nKerning = rPool.GetTrueWhich( SID_ATTR_CHAR_KERNING, sal_False ); + aItemIds.nCaseMap = rPool.GetTrueWhich( SID_ATTR_CHAR_CASEMAP, sal_False ); + aItemIds.nBlink = rPool.GetTrueWhich( SID_ATTR_FLASH, sal_False ); + + aItemIds.nLineSpacing = rPool.GetTrueWhich( SID_ATTR_PARA_LINESPACE, sal_False ); + aItemIds.nAdjust = rPool.GetTrueWhich( SID_ATTR_PARA_ADJUST, sal_False ); + aItemIds.nWidows = rPool.GetTrueWhich( SID_ATTR_PARA_WIDOWS, sal_False ); + aItemIds.nOrphans = rPool.GetTrueWhich( SID_ATTR_PARA_ORPHANS, sal_False ); + aItemIds.nFmtSplit = rPool.GetTrueWhich( SID_ATTR_PARA_SPLIT, sal_False ); + + aItemIds.nLRSpace = rPool.GetTrueWhich( SID_ATTR_LRSPACE, sal_False ); + aItemIds.nULSpace = rPool.GetTrueWhich( SID_ATTR_ULSPACE, sal_False ); + aItemIds.nBox = rPool.GetTrueWhich( SID_ATTR_BORDER_OUTER, sal_False ); + aItemIds.nBrush = rPool.GetTrueWhich( SID_ATTR_BRUSH, sal_False ); + + aItemIds.nLanguage = rPool.GetTrueWhich( SID_ATTR_CHAR_LANGUAGE, sal_False ); + aItemIds.nLanguageCJK = rPool.GetTrueWhich( SID_ATTR_CHAR_CJK_LANGUAGE, sal_False ); + aItemIds.nLanguageCTL = rPool.GetTrueWhich( SID_ATTR_CHAR_CTL_LANGUAGE, sal_False ); + aItemIds.nDirection = rPool.GetTrueWhich( SID_ATTR_FRAMEDIRECTION, sal_False ); + + aWhichMap.Insert( (sal_uInt16)0, (sal_uInt16)0 ); + SvParser::BuildWhichTbl( aWhichMap, (sal_uInt16 *)&aItemIds, + sizeof(aItemIds) / sizeof(sal_uInt16) ); + if( pWhichIds && nWhichIds ) + SvParser::BuildWhichTbl( aWhichMap, pWhichIds, nWhichIds ); + + pSheetItemSet = new SfxItemSet( rPool, aWhichMap.GetData() ); + pSheetPropInfo = new SvxCSS1PropertyInfo; + pSearchEntry = new SvxCSS1MapEntry( rPool, aWhichMap.GetData() ); +} + +SvxCSS1Parser::~SvxCSS1Parser() +{ + delete pSheetItemSet; + delete pSheetPropInfo; + delete pSearchEntry; +} + + +/* */ + +sal_Bool SvxCSS1Parser::ParseStyleSheet( const String& rIn ) +{ + pItemSet = pSheetItemSet; + pPropInfo = pSheetPropInfo; + + sal_Bool bSuccess = CSS1Parser::ParseStyleSheet( rIn ); + + // die bisher geparsten Items auf die Styles verteilt werden +// pSheetPropInfo->CreateBoxItem( *pSheetItemSet, GetDfltBorderDist() ); + for( sal_uInt16 i=0; i<aSelectors.Count(); i++ ) + { + StyleParsed( aSelectors[i], *pSheetItemSet, *pSheetPropInfo ); + } + + // und etwas aufrauemen + if( aSelectors.Count() ) + aSelectors.DeleteAndDestroy( 0, aSelectors.Count() ); + pSheetItemSet->ClearItem(); + pSheetPropInfo->Clear(); + + pItemSet = 0; + pPropInfo = 0; + + return bSuccess; +} + +sal_Bool SvxCSS1Parser::ParseStyleOption( const String& rIn, + SfxItemSet& rItemSet, + SvxCSS1PropertyInfo& rPropInfo ) +{ + pItemSet = &rItemSet; + pPropInfo = &rPropInfo; + + sal_Bool bSuccess = CSS1Parser::ParseStyleOption( rIn ); + rItemSet.ClearItem( aItemIds.nDirection ); +// pPropInfo->CreateBoxItem( *pItemSet, GetDfltBorderDist() ); + + pItemSet = 0; + pPropInfo = 0; + + return bSuccess; +} + +/* */ + +sal_Bool SvxCSS1Parser::GetEnum( const CSS1PropertyEnum *pPropTable, + const String &rValue, sal_uInt16& rEnum ) +{ + String aValue( rValue ); + aValue.ToLowerAscii(); + while( pPropTable->pName ) + { + if( !rValue.EqualsIgnoreCaseAscii( pPropTable->pName ) ) + pPropTable++; + else + break; + } + + if( pPropTable->pName ) + rEnum = pPropTable->nEnum; + + return (pPropTable->pName != 0); +} + +void SvxCSS1Parser::PixelToTwip( long &rWidth, long &rHeight ) +{ + if( Application::GetDefaultDevice() ) + { + Size aTwipSz( rWidth, rHeight ); + aTwipSz = Application::GetDefaultDevice()->PixelToLogic( aTwipSz, + MapMode(MAP_TWIP) ); + + rWidth = aTwipSz.Width(); + rHeight = aTwipSz.Height(); + } +} + +void SvxCSS1Parser::SetBorderWidth( SvxBorderLine& aBorderLine, sal_uInt16 nWidth, + sal_Bool bDouble, sal_Bool bTable ) +{ + const sal_uInt16 *aWidths; + sal_uInt16 nSize; + if( !bDouble ) + { + aWidths = aSBorderWidths; + nSize = sizeof( aSBorderWidths ); + } + else if( bTable ) + { + aWidths = aTDBorderWidths; + nSize = sizeof( aTDBorderWidths ); + } + else + { + aWidths = aDBorderWidths; + nSize = sizeof( aDBorderWidths ); + } + + sal_uInt16 i = (nSize / sizeof(sal_uInt16)) - 4; + while( i>0 && + nWidth <= ((aWidths[i] + aWidths[i-4]) / 2) ) + { + DBG_ASSERT( aWidths[i] > aWidths[i-4], + "Linienbreiten sind nicht sortiert!" ); + i -= 4; + } + + aBorderLine.SetOutWidth( aWidths[i+1] ); + aBorderLine.SetInWidth( aWidths[i+2] ); + aBorderLine.SetDistance( aWidths[i+3] ); +} + +sal_uInt32 SvxCSS1Parser::GetFontHeight( sal_uInt16 nSize ) const +{ + sal_uInt16 nHeight; + + switch( nSize ) + { + case 0: nHeight = 8*20; break; + case 1: nHeight = 10*20; break; + case 2: nHeight = 11*20; break; + case 3: nHeight = 12*20; break; + case 4: nHeight = 17*20; break; + case 5: nHeight = 20*20; break; + case 6: + default: nHeight = 32*20; break; + } + + return nHeight; +} + +const FontList *SvxCSS1Parser::GetFontList() const +{ + return 0; +} + +SvxCSS1MapEntry *SvxCSS1Parser::GetMapEntry( const String& rKey, + const SvxCSS1Map& rMap ) const +{ + pSearchEntry->SetKey( rKey ); + + SvxCSS1MapEntry *pRet = 0; + sal_uInt16 nPos; + if( rMap.Seek_Entry( pSearchEntry, &nPos ) ) + pRet = rMap[nPos]; + + return pRet; +} + +void SvxCSS1Parser::InsertMapEntry( const String& rKey, + const SfxItemSet& rItemSet, + const SvxCSS1PropertyInfo& rProp, + SvxCSS1Map& rMap ) +{ + SvxCSS1MapEntry *pEntry = GetMapEntry( rKey, rMap ); + if( pEntry ) + { + MergeStyles( rItemSet, rProp, + pEntry->GetItemSet(), pEntry->GetPropertyInfo(), sal_True ); + } + else + { + rMap.Insert( new SvxCSS1MapEntry( rKey, rItemSet, rProp ) ); + } +} + + +void SvxCSS1Parser::MergeStyles( const SfxItemSet& rSrcSet, + const SvxCSS1PropertyInfo& rSrcInfo, + SfxItemSet& rTargetSet, + SvxCSS1PropertyInfo& rTargetInfo, + sal_Bool bSmart ) +{ + if( !bSmart ) + { + rTargetSet.Put( rSrcSet ); + } + else + { + SvxLRSpaceItem aLRSpace( (const SvxLRSpaceItem&)rTargetSet.Get(aItemIds.nLRSpace) ); + SvxULSpaceItem aULSpace( (const SvxULSpaceItem&)rTargetSet.Get(aItemIds.nULSpace) ); + SvxBoxItem aBox( (const SvxBoxItem&)rTargetSet.Get(aItemIds.nBox) ); + + rTargetSet.Put( rSrcSet ); + + if( rSrcInfo.bLeftMargin || rSrcInfo.bRightMargin || + rSrcInfo.bTextIndent ) + { + const SvxLRSpaceItem& rNewLRSpace = + (const SvxLRSpaceItem&)rSrcSet.Get( aItemIds.nLRSpace ); + + if( rSrcInfo.bLeftMargin ) + aLRSpace.SetLeft( rNewLRSpace.GetLeft() ); + if( rSrcInfo.bRightMargin ) + aLRSpace.SetRight( rNewLRSpace.GetRight() ); + if( rSrcInfo.bTextIndent ) + aLRSpace.SetTxtFirstLineOfst( rNewLRSpace.GetTxtFirstLineOfst() ); + + rTargetSet.Put( aLRSpace ); + } + + if( rSrcInfo.bTopMargin || rSrcInfo.bBottomMargin ) + { + const SvxULSpaceItem& rNewULSpace = + (const SvxULSpaceItem&)rSrcSet.Get( aItemIds.nULSpace ); + + if( rSrcInfo.bTopMargin ) + aULSpace.SetUpper( rNewULSpace.GetUpper() ); + if( rSrcInfo.bBottomMargin ) + aULSpace.SetLower( rNewULSpace.GetLower() ); + + rTargetSet.Put( aULSpace ); + } + } + + rTargetInfo.Merge( rSrcInfo ); +} + +void SvxCSS1Parser::SetDfltEncoding( rtl_TextEncoding eEnc ) +{ + eDfltEnc = eEnc; +} + +/* */ + +static void ParseCSS1_font_size( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& /*rPropInfo*/, + const SvxCSS1Parser& rParser ) +{ + DBG_ASSERT( pExpr, "kein Ausdruck" ); + + sal_uLong nHeight = 0; + sal_uInt16 nPropHeight = 100; + + switch( pExpr->GetType() ) + { + case CSS1_LENGTH: + nHeight = pExpr->GetULength(); + break; + case CSS1_PIXLENGTH: + { + long nPWidth = 0; + long nPHeight = (long)pExpr->GetNumber(); + SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight ); + nHeight = (sal_uLong)nPHeight; + } + break; +//#ifdef PERCENTAGE_POSSIBLE + case CSS1_PERCENTAGE: + // nur fuer Drop-Caps! + nPropHeight = (sal_uInt16)pExpr->GetNumber(); + break; +//#endif + case CSS1_IDENT: + { + sal_uInt16 nSize; +#ifdef PERCENTAGE_POSSIBLE + const String& rValue = pExpr->GetString(); +#endif + if( SvxCSS1Parser::GetEnum( aFontSizeTable, pExpr->GetString(), + nSize ) ) + { + nHeight = rParser.GetFontHeight( nSize ); + } +#ifdef PERCENTAGE_POSSIBLE + else if( rValue.EqualsIgnoreCaseAscii( sCSS1_PV_larger ) ) + { + nPropHeight = 150; + } + else if( rValue.EqualsIgnoreCaseAscii( sCSS1_PV_smaller ) ) + { + nPropHeight = 67; + } +#endif + } + break; + + default: + ; + } + + if( nHeight || nPropHeight!=100 ) + { + SvxFontHeightItem aFontHeight( nHeight, nPropHeight, + aItemIds.nFontHeight ); + if( rParser.IsSetWesternProps() ) + rItemSet.Put( aFontHeight ); + if( rParser.IsSetCJKProps() ) + { + aFontHeight.SetWhich( aItemIds.nFontHeightCJK ); + rItemSet.Put( aFontHeight ); + } + if( rParser.IsSetCTLProps() ) + { + aFontHeight.SetWhich( aItemIds.nFontHeightCTL ); + rItemSet.Put( aFontHeight ); + } + } +} + +/* */ + + +static void ParseCSS1_font_family( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& /*rPropInfo*/, + const SvxCSS1Parser& rParser ) +{ + DBG_ASSERT( pExpr, "kein Ausdruck" ); + + String aName, aStyleName, aDfltName; + FontFamily eFamily = FAMILY_DONTKNOW; + FontPitch ePitch = PITCH_DONTKNOW; + rtl_TextEncoding eEnc = rParser.GetDfltEncoding(); + const FontList *pFList = rParser.GetFontList(); + sal_Bool bFirst = sal_True; + sal_Bool bFound = sal_False; + while( pExpr && (bFirst || ','==pExpr->GetOp() || !pExpr->GetOp()) ) + { + CSS1Token eType = pExpr->GetType(); + if( CSS1_IDENT==eType || CSS1_STRING==eType ) + { + String aIdent( pExpr->GetString() ); + + if( CSS1_IDENT==eType ) + { + // Alle nachfolgenden id's sammeln und mit einem + // Space getrennt hintendranhaengen + const CSS1Expression *pNext = pExpr->GetNext(); + while( pNext && !pNext->GetOp() && + CSS1_IDENT==pNext->GetType() ) + { + (aIdent += ' ') += pNext->GetString(); + pExpr = pNext; + pNext = pExpr->GetNext(); + } + } + if( aIdent.Len() ) + { + if( !bFound && pFList ) + { + sal_Handle hFont = pFList->GetFirstFontInfo( aIdent ); + if( 0 != hFont ) + { + const FontInfo& rFInfo = pFList->GetFontInfo( hFont ); + if( RTL_TEXTENCODING_DONTKNOW != rFInfo.GetCharSet() ) + { + bFound = sal_True; + if( RTL_TEXTENCODING_SYMBOL == rFInfo.GetCharSet() ) + eEnc = RTL_TEXTENCODING_SYMBOL; + } + } + } + if( !bFirst ) + aName += ';'; + aName += aIdent; + } + } + + pExpr = pExpr->GetNext(); + bFirst = sal_False; + } + + if( aName.Len() && !rParser.IsIgnoreFontFamily() ) + { + SvxFontItem aFont( eFamily, aName, aStyleName, ePitch, + eEnc, aItemIds.nFont ); + if( rParser.IsSetWesternProps() ) + rItemSet.Put( aFont ); + if( rParser.IsSetCJKProps() ) + { + aFont.SetWhich( aItemIds.nFontCJK ); + rItemSet.Put( aFont ); + } + if( rParser.IsSetCTLProps() ) + { + aFont.SetWhich( aItemIds.nFontCTL ); + rItemSet.Put( aFont ); + } + } +} + +/* */ + +static void ParseCSS1_font_weight( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& /*rPropInfo*/, + const SvxCSS1Parser& rParser ) +{ + DBG_ASSERT( pExpr, "kein Ausdruck" ); + + switch( pExpr->GetType() ) + { + case CSS1_IDENT: + case CSS1_STRING: // MS-IE, was sonst + { + sal_uInt16 nWeight; + if( SvxCSS1Parser::GetEnum( aFontWeightTable, pExpr->GetString(), + nWeight ) ) + { + SvxWeightItem aWeight( (FontWeight)nWeight, aItemIds.nWeight ); + if( rParser.IsSetWesternProps() ) + rItemSet.Put( aWeight ); + if( rParser.IsSetCJKProps() ) + { + aWeight.SetWhich( aItemIds.nWeightCJK ); + rItemSet.Put( aWeight ); + } + if( rParser.IsSetCTLProps() ) + { + aWeight.SetWhich( aItemIds.nWeightCTL ); + rItemSet.Put( aWeight ); + } + } + } + break; + case CSS1_NUMBER: + { + sal_uInt16 nWeight = (sal_uInt16)pExpr->GetNumber(); + SvxWeightItem aWeight( nWeight>400 ? WEIGHT_BOLD : WEIGHT_NORMAL, + aItemIds.nWeight ); + if( rParser.IsSetWesternProps() ) + rItemSet.Put( aWeight ); + if( rParser.IsSetCJKProps() ) + { + aWeight.SetWhich( aItemIds.nWeightCJK ); + rItemSet.Put( aWeight ); + } + if( rParser.IsSetCTLProps() ) + { + aWeight.SetWhich( aItemIds.nWeightCTL ); + rItemSet.Put( aWeight ); + } + } + break; + + default: + ; + } +} + +/* */ + +static void ParseCSS1_font_style( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& /*rPropInfo*/, + const SvxCSS1Parser& rParser ) +{ + DBG_ASSERT( pExpr, "kein Ausdruck" ); + + sal_Bool bPosture = sal_False; + sal_Bool bCaseMap = sal_False; + FontItalic eItalic = ITALIC_NONE; + SvxCaseMap eCaseMap = SVX_CASEMAP_NOT_MAPPED; + + // normal | italic || small-caps | oblique || small-caps | small-caps + // (wobei nor noch normal | italic und oblique zulaessig sind + + // der Wert kann zwei Werte enthalten! + for( sal_uInt16 i=0; pExpr && i<2; i++ ) + { + // Auch hier hinterlaesst MS-IEs Parser seine Spuren + if( (CSS1_IDENT==pExpr->GetType() || CSS1_STRING==pExpr->GetType()) && + !pExpr->GetOp() ) + { + const String& rValue = pExpr->GetString(); + // erstmal pruefen, ob es ein Italic-Wert oder 'normal' ist + sal_uInt16 nItalic; + if( SvxCSS1Parser::GetEnum( aFontStyleTable, rValue, nItalic ) ) + { + eItalic = (FontItalic)nItalic; + if( !bCaseMap && ITALIC_NONE==eItalic ) + { + // fuer 'normal' muessen wir auch die case-map aussch. + eCaseMap = SVX_CASEMAP_NOT_MAPPED; + bCaseMap = sal_True; + } + bPosture = sal_True; + } + else if( !bCaseMap && + rValue.EqualsIgnoreCaseAscii(sCSS1_PV_small_caps) ) + { + eCaseMap = SVX_CASEMAP_KAPITAELCHEN; + bCaseMap = sal_True; + } + } + + // den naechsten Ausdruck holen + pExpr = pExpr->GetNext(); + } + + if( bPosture ) + { + SvxPostureItem aPosture( eItalic, aItemIds.nPosture ); + if( rParser.IsSetWesternProps() ) + rItemSet.Put( aPosture ); + if( rParser.IsSetCJKProps() ) + { + aPosture.SetWhich( aItemIds.nPostureCJK ); + rItemSet.Put( aPosture ); + } + if( rParser.IsSetCTLProps() ) + { + aPosture.SetWhich( aItemIds.nPostureCTL ); + rItemSet.Put( aPosture ); + } + } + + if( bCaseMap ) + rItemSet.Put( SvxCaseMapItem( eCaseMap, aItemIds.nCaseMap ) ); +} + +/* */ + +static void ParseCSS1_font_variant( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& /*rPropInfo*/, + const SvxCSS1Parser& /*rParser*/ ) +{ + DBG_ASSERT( pExpr, "kein Ausdruck" ); + + // normal | small-caps + + switch( pExpr->GetType() ) + { + case CSS1_IDENT: + { + sal_uInt16 nCaseMap; + if( SvxCSS1Parser::GetEnum( aFontVariantTable, pExpr->GetString(), + nCaseMap ) ) + { + rItemSet.Put( SvxCaseMapItem( (SvxCaseMap)nCaseMap, + aItemIds.nCaseMap ) ); + } + } + default: + ; + } +} + +/* */ + +static void ParseCSS1_color( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& /*rPropInfo*/, + const SvxCSS1Parser& /*rParser*/ ) +{ + DBG_ASSERT( pExpr, "kein Ausdruck" ); + + switch( pExpr->GetType() ) + { + case CSS1_IDENT: + case CSS1_RGB: + case CSS1_HEXCOLOR: + case CSS1_STRING: // Wegen MS-IE + { + Color aColor; + if( pExpr->GetColor( aColor ) ) + rItemSet.Put( SvxColorItem( aColor, aItemIds.nColor ) ); + } + break; + default: + ; + } +} + +static void ParseCSS1_direction( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& /*rPropInfo*/, + const SvxCSS1Parser& /*rParser*/ ) +{ + DBG_ASSERT( pExpr, "kein Ausdruck" ); + + sal_uInt16 nDir; + switch( pExpr->GetType() ) + { + case CSS1_IDENT: + case CSS1_STRING: + if( SvxCSS1Parser::GetEnum( aDirectionTable, pExpr->GetString(), + nDir ) ) + { + rItemSet.Put( SvxFrameDirectionItem( + static_cast < SvxFrameDirection >( nDir ), + aItemIds.nDirection ) ); + } + break; + default: + ; + } +} + +/* */ + +static void MergeHori( SvxGraphicPosition& ePos, SvxGraphicPosition eHori ) +{ + DBG_ASSERT( GPOS_LT==eHori || GPOS_MT==eHori || GPOS_RT==eHori, + "vertikale Position nicht oben" ); + + switch( ePos ) + { + case GPOS_LT: + case GPOS_MT: + case GPOS_RT: + ePos = eHori; + break; + + case GPOS_LM: + case GPOS_MM: + case GPOS_RM: + ePos = GPOS_LT==eHori ? GPOS_LM : (GPOS_MT==eHori ? GPOS_MM : GPOS_RM); + break; + + case GPOS_LB: + case GPOS_MB: + case GPOS_RB: + ePos = GPOS_LT==eHori ? GPOS_LB : (GPOS_MT==eHori ? GPOS_MB : GPOS_RB); + break; + + default: + ; + } +} + +static void MergeVert( SvxGraphicPosition& ePos, SvxGraphicPosition eVert ) +{ + DBG_ASSERT( GPOS_LT==eVert || GPOS_LM==eVert || GPOS_LB==eVert, + "horizontale Position nicht links" ); + + switch( ePos ) + { + case GPOS_LT: + case GPOS_LM: + case GPOS_LB: + ePos = eVert; + break; + + case GPOS_MT: + case GPOS_MM: + case GPOS_MB: + ePos = GPOS_LT==eVert ? GPOS_MT : (GPOS_LM==eVert ? GPOS_MM : GPOS_MB); + break; + + case GPOS_RT: + case GPOS_RM: + case GPOS_RB: + ePos = GPOS_LT==eVert ? GPOS_RT : (GPOS_LM==eVert ? GPOS_RM : GPOS_RB); + break; + + default: + ; + } +} + +static void ParseCSS1_background( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& /*rPropInfo*/, + const SvxCSS1Parser& rParser ) +{ + DBG_ASSERT( pExpr, "kein Ausdruck" ); + + Color aColor; + String aURL; + + sal_Bool bColor = sal_False, bTransparent = sal_False; + SvxGraphicPosition eRepeat = GPOS_TILED; + SvxGraphicPosition ePos = GPOS_LT; + sal_Bool bHori = sal_False, bVert = sal_False; + + while( pExpr && !pExpr->GetOp() ) + { + switch( pExpr->GetType() ) + { + case CSS1_URL: + pExpr->GetURL( aURL ); + break; + + case CSS1_RGB: + bColor = pExpr->GetColor( aColor ); + break; + + case CSS1_LENGTH: + case CSS1_PIXLENGTH: + { + // da wir keine absolute Positionierung koennen, + // unterscheiden wir nur zwischen 0 und !0. Deshalb + // koennen Pixel auch wie alle anderen Einheiten behandelt + // werden. + + sal_uLong nLength = (sal_uLong)pExpr->GetNumber(); + if( !bHori ) + { + ePos = nLength ? GPOS_MM : GPOS_LT; + bHori = sal_True; + } + else if( !bVert ) + { + MergeVert( ePos, (nLength ? GPOS_LM : GPOS_LT) ); + bVert = sal_True; + } + } + break; + + case CSS1_PERCENTAGE: + { + // die %-Angabe wird auf den enum abgebildet + + sal_uInt16 nPerc = (sal_uInt16)pExpr->GetNumber(); + if( !bHori ) + { + ePos = nPerc < 25 ? GPOS_LT + : (nPerc < 75 ? GPOS_MM + : GPOS_RB); + } + else if( !bVert ) + { + SvxGraphicPosition eVert = + nPerc < 25 ? GPOS_LT: (nPerc < 75 ? GPOS_LM + : GPOS_LB); + MergeVert( ePos, eVert ); + } + } + break; + + case CSS1_IDENT: + case CSS1_HEXCOLOR: + case CSS1_STRING: // Wegen MS-IE + { + sal_uInt16 nEnum; + const String &rValue = pExpr->GetString(); + if( rValue.EqualsIgnoreCaseAscii( sCSS1_PV_transparent ) ) + { + bTransparent = sal_True; + } + if( SvxCSS1Parser::GetEnum( aBGRepeatTable, rValue, nEnum ) ) + { + eRepeat = (SvxGraphicPosition)nEnum; + } + else if( SvxCSS1Parser::GetEnum( aBGHoriPosTable, rValue, nEnum ) ) + { + // <position>, horizontal + MergeHori( ePos, (SvxGraphicPosition)nEnum ); + } + else if( SvxCSS1Parser::GetEnum( aBGVertPosTable, rValue, nEnum ) ) + { + // <position>, vertikal + MergeVert( ePos, (SvxGraphicPosition)nEnum ); + } + else if( !bColor ) + { + // <color> + bColor = pExpr->GetColor( aColor ); + } + // <scroll> kennen wir nicht + } + break; + + default: + ; + } + + pExpr = pExpr->GetNext(); + } + + // transparent schlaegt alles + if( bTransparent ) + { + bColor = sal_False; + aURL.Erase(); + } + + // repeat hat prio gegenueber einer Position + if( GPOS_NONE == eRepeat ) + eRepeat = ePos; + + if( bTransparent || bColor || aURL.Len() ) + { + SvxBrushItem aBrushItem( aItemIds.nBrush ); + + if( bTransparent ) + aBrushItem.SetColor( Color(COL_TRANSPARENT)); + else if( bColor ) + aBrushItem.SetColor( aColor ); + + if( aURL.Len() ) + { + aBrushItem.SetGraphicLink( URIHelper::SmartRel2Abs( INetURLObject( rParser.GetBaseURL()), aURL, Link(), false ) ); + aBrushItem.SetGraphicPos( eRepeat ); + } + + rItemSet.Put( aBrushItem ); + } +} + +static void ParseCSS1_background_color( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& /*rPropInfo*/, + const SvxCSS1Parser& /*rParser*/ ) +{ + DBG_ASSERT( pExpr, "kein Ausdruck" ); + + Color aColor; + + sal_Bool bColor = sal_False, bTransparent = sal_False; + + switch( pExpr->GetType() ) + { + case CSS1_RGB: + bColor = pExpr->GetColor( aColor ); + break; + case CSS1_IDENT: + case CSS1_HEXCOLOR: + case CSS1_STRING: // Wegen MS-IE + if( pExpr->GetString().EqualsIgnoreCaseAscii( sCSS1_PV_transparent ) ) + { + bTransparent = sal_True; + } + else + { + // <color> + bColor = pExpr->GetColor( aColor ); + } + break; + default: + ; + } + + if( bTransparent || bColor ) + { + SvxBrushItem aBrushItem( aItemIds.nBrush ); + + if( bTransparent ) + aBrushItem.SetColor( Color(COL_TRANSPARENT) ); + else if( bColor ) + aBrushItem.SetColor( aColor); + + rItemSet.Put( aBrushItem ); + } +} + +/* */ + +static void ParseCSS1_line_height( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& /*rPropInfo*/, + const SvxCSS1Parser& rParser ) +{ + DBG_ASSERT( pExpr, "kein Ausdruck" ); + + sal_uInt16 nHeight = 0; + sal_uInt8 nPropHeight = 0; + + switch( pExpr->GetType() ) + { + case CSS1_LENGTH: + nHeight = (sal_uInt16)pExpr->GetULength(); + break; + case CSS1_PIXLENGTH: + { + long nPWidth = 0; + long nPHeight = (long)pExpr->GetNumber(); + SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight ); + nHeight = (sal_uInt16)nPHeight; + } + break; + case CSS1_PERCENTAGE: + { + sal_uInt16 nPHeight = (sal_uInt16)pExpr->GetNumber(); + nPropHeight = nPHeight <= 200 ? (sal_uInt8)nPHeight : 200; + } + break; + case CSS1_NUMBER: + { + sal_uInt16 nPHeight = (sal_uInt16)(pExpr->GetNumber() * 100); + nPropHeight = nPHeight <= 200 ? (sal_uInt8)nPHeight : 200; + } + break; + default: + ; + } + + if( nHeight ) + { + if( nHeight < rParser.GetMinFixLineSpace() ) + nHeight = rParser.GetMinFixLineSpace(); + SvxLineSpacingItem aLSItem( nHeight, aItemIds.nLineSpacing ); + aLSItem.SetLineHeight( nHeight ); + // --> OD 2006-07-26 #138463# + // interpret <line-height> attribute as minimum line height + aLSItem.GetLineSpaceRule() = SVX_LINE_SPACE_MIN; + // <-- + aLSItem.GetInterLineSpaceRule() = SVX_INTER_LINE_SPACE_OFF; + rItemSet.Put( aLSItem ); + } + else if( nPropHeight ) + { + SvxLineSpacingItem aLSItem( nPropHeight, aItemIds.nLineSpacing ); + aLSItem.GetLineSpaceRule() = SVX_LINE_SPACE_AUTO; + if( 100 == nPropHeight ) + aLSItem.GetInterLineSpaceRule() = SVX_INTER_LINE_SPACE_OFF; + else + aLSItem.SetPropLineSpace( nPropHeight ); + rItemSet.Put( aLSItem ); + } + +} + +/* */ + +static void ParseCSS1_font( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& rParser ) +{ + DBG_ASSERT( pExpr, "kein Ausdruck" ); + + FontItalic eItalic = ITALIC_NONE; + SvxCaseMap eCaseMap = SVX_CASEMAP_NOT_MAPPED; + FontWeight eWeight = WEIGHT_NORMAL; + + // [ <font-style> || <font-variant> || <font-weight> ] ? + while( pExpr && !pExpr->GetOp() && + (CSS1_IDENT==pExpr->GetType() || + CSS1_STRING==pExpr->GetType() || + CSS1_NUMBER==pExpr->GetType()) ) + { + if( CSS1_IDENT==pExpr->GetType() || + CSS1_STRING==pExpr->GetType() ) + { + const String& rValue = pExpr->GetString(); + + sal_uInt16 nEnum; + + if( SvxCSS1Parser::GetEnum( aFontStyleTable, rValue, nEnum ) ) + { + eItalic = (FontItalic)nEnum; + } + else if( SvxCSS1Parser::GetEnum( aFontVariantTable, rValue, nEnum ) ) + { + eCaseMap = (SvxCaseMap)nEnum; + } + else if( SvxCSS1Parser::GetEnum( aFontWeightTable, rValue, nEnum ) ) + { + eWeight = (FontWeight)nEnum; + } + } + else + { + eWeight = (sal_uInt16)pExpr->GetNumber() > 400 ? WEIGHT_BOLD + : WEIGHT_NORMAL; + } + + pExpr = pExpr->GetNext(); + } + + if( !pExpr || pExpr->GetOp() ) + return; + + // Da "font" alle Werte zurecksetzt, fuer die nichts angegeben ist, + // tun wir das hier. + SvxPostureItem aPosture( eItalic, aItemIds.nPosture ); + if( rParser.IsSetWesternProps() ) + rItemSet.Put( aPosture ); + if( rParser.IsSetCJKProps() ) + { + aPosture.SetWhich( aItemIds.nPostureCJK ); + rItemSet.Put( aPosture ); + } + if( rParser.IsSetCTLProps() ) + { + aPosture.SetWhich( aItemIds.nPostureCTL ); + rItemSet.Put( aPosture ); + } + + rItemSet.Put( SvxCaseMapItem( eCaseMap, aItemIds.nCaseMap ) ); + + SvxWeightItem aWeight( eWeight, aItemIds.nWeight ); + if( rParser.IsSetWesternProps() ) + rItemSet.Put( aWeight ); + if( rParser.IsSetCJKProps() ) + { + aWeight.SetWhich( aItemIds.nWeightCJK ); + rItemSet.Put( aWeight ); + } + if( rParser.IsSetCTLProps() ) + { + aWeight.SetWhich( aItemIds.nWeightCTL ); + rItemSet.Put( aWeight ); + } + + + // font-size + CSS1Expression aExpr( pExpr->GetType(), pExpr->GetString(), + pExpr->GetNumber() ); + ParseCSS1_font_size( &aExpr, rItemSet, rPropInfo, rParser ); + pExpr = pExpr->GetNext(); + + if( !pExpr ) + return; + + // [ '/' line-height ]? + if( '/' == pExpr->GetOp() ) + { + // '/' line-height + aExpr.Set( pExpr->GetType(), pExpr->GetString(), pExpr->GetNumber() ); + ParseCSS1_line_height( &aExpr, rItemSet, rPropInfo, rParser ); + + pExpr = pExpr->GetNext(); + } + + if( !pExpr || pExpr->GetOp() ) + return; + + // font-family + ParseCSS1_font_family( pExpr, rItemSet, rPropInfo, rParser ); +} + +/* */ + +static void ParseCSS1_letter_spacing( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& /*rPropInfo*/, + const SvxCSS1Parser& /*rParser*/ ) +{ + DBG_ASSERT( pExpr, "kein Ausdruck" ); + + switch( pExpr->GetType() ) + { + case CSS1_LENGTH: + rItemSet.Put( SvxKerningItem( (short)pExpr->GetSLength(), + aItemIds.nKerning ) ); + break; + + case CSS1_PIXLENGTH: + { + long nPWidth = (long)pExpr->GetNumber(); + long nPHeight = 0; + SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight ); + rItemSet.Put( SvxKerningItem( (short)nPWidth, aItemIds.nKerning ) ); + } + break; + + case CSS1_NUMBER: + if( pExpr->GetNumber() == 0 ) + { + // eigentlich unnoetig, aber wir sind ja tollerant + rItemSet.Put( SvxKerningItem( (short)0, aItemIds.nKerning ) ); + } + break; + + case CSS1_IDENT: + case CSS1_STRING: // Vorschtshalber auch MS-IE + if( pExpr->GetString().EqualsIgnoreCaseAscii(sCSS1_PV_normal) ) + { + rItemSet.Put( SvxKerningItem( (short)0, aItemIds.nKerning ) ); + } + break; + default: + ; + } +} + +/* */ + +static void ParseCSS1_text_decoration( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& /*rPropInfo*/, + const SvxCSS1Parser& /*rParser*/ ) +{ + DBG_ASSERT( pExpr, "kein Ausdruck" ); + + sal_Bool bUnderline = sal_False; + sal_Bool bOverline = sal_False; + sal_Bool bCrossedOut = sal_False; + sal_Bool bBlink = sal_False; + sal_Bool bBlinkOn = sal_False; + FontUnderline eUnderline = UNDERLINE_NONE; + FontUnderline eOverline = UNDERLINE_NONE; + FontStrikeout eCrossedOut = STRIKEOUT_NONE; + + // der Wert kann zwei Werte enthalten! Und MS-IE auch Strings + while( pExpr && (pExpr->GetType() == CSS1_IDENT || + pExpr->GetType() == CSS1_STRING) && !pExpr->GetOp() ) + { + String aValue = pExpr->GetString(); + aValue.ToLowerAscii(); + sal_Bool bKnown = sal_False; + + switch( aValue.GetChar( 0 ) ) + { + case 'n': + if( aValue.EqualsAscii( sCSS1_PV_none ) ) + { + bUnderline = sal_True; + eUnderline = UNDERLINE_NONE; + + bOverline = sal_True; + eOverline = UNDERLINE_NONE; + + bCrossedOut = sal_True; + eCrossedOut = STRIKEOUT_NONE; + + bBlink = sal_True; + bBlinkOn = sal_False; + + bKnown = sal_True; + } + break; + + case 'u': + if( aValue.EqualsAscii( sCSS1_PV_underline ) ) + { + bUnderline = sal_True; + eUnderline = UNDERLINE_SINGLE; + + bKnown = sal_True; + } + break; + + case 'o': + if( aValue.EqualsAscii( sCSS1_PV_overline ) ) + { + bOverline = sal_True; + eOverline = UNDERLINE_SINGLE; + + bKnown = sal_True; + } + break; + + case 'l': + if( aValue.EqualsAscii( sCSS1_PV_line_through ) ) + { + bCrossedOut = sal_True; + eCrossedOut = STRIKEOUT_SINGLE; + + bKnown = sal_True; + } + break; + + case 'b': + if( aValue.EqualsAscii( sCSS1_PV_blink ) ) + { + bBlink = sal_True; + bBlinkOn = sal_True; + + bKnown = sal_True; + } + break; + } + + if( !bKnown ) + { + bUnderline = sal_True; + eUnderline = UNDERLINE_SINGLE; + } + + pExpr = pExpr->GetNext(); + } + + if( bUnderline ) + rItemSet.Put( SvxUnderlineItem( eUnderline, aItemIds.nUnderline ) ); + + if( bOverline ) + rItemSet.Put( SvxOverlineItem( eOverline, aItemIds.nOverline ) ); + + if( bCrossedOut ) + rItemSet.Put( SvxCrossedOutItem( eCrossedOut, aItemIds.nCrossedOut ) ); + + if( bBlink ) + rItemSet.Put( SvxBlinkItem( bBlinkOn, aItemIds.nBlink ) ); +} + +/* */ + +static void ParseCSS1_text_align( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& /*rPropInfo*/, + const SvxCSS1Parser& /*rParser*/ ) +{ + DBG_ASSERT( pExpr, "kein Ausdruck" ); + + if( CSS1_IDENT==pExpr->GetType() || + CSS1_STRING==pExpr->GetType() ) // MS-IE, mal wieder + { + sal_uInt16 nAdjust; + if( SvxCSS1Parser::GetEnum( aTextAlignTable, pExpr->GetString(), + nAdjust ) ) + { + rItemSet.Put( SvxAdjustItem( (SvxAdjust)nAdjust, + aItemIds.nAdjust ) ); + } + } +} + +/* */ + +static void ParseCSS1_text_indent( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& /*rParser*/ ) +{ + DBG_ASSERT( pExpr, "kein Ausdruck" ); + + short nIndent = 0; + sal_Bool bSet = sal_False; + switch( pExpr->GetType() ) + { + case CSS1_LENGTH: + nIndent = (short)pExpr->GetSLength(); + bSet = sal_True; + break; + case CSS1_PIXLENGTH: + { + long nPWidth = (long)pExpr->GetNumber(); + long nPHeight = 0; + SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight ); + nIndent = (short)nPWidth; + bSet = sal_True; + } + break; + case CSS1_PERCENTAGE: + // koennen wir nicht + break; + default: + ; + } + + if( bSet ) + { + const SfxPoolItem* pItem; + if( SFX_ITEM_SET == rItemSet.GetItemState( aItemIds.nLRSpace, sal_False, + &pItem ) ) + { + SvxLRSpaceItem aLRItem( *((const SvxLRSpaceItem*)pItem) ); + aLRItem.SetTxtFirstLineOfst( nIndent ); + rItemSet.Put( aLRItem ); + } + else + { + SvxLRSpaceItem aLRItem( aItemIds.nLRSpace ); + aLRItem.SetTxtFirstLineOfst( nIndent ); + rItemSet.Put( aLRItem ); + } + rPropInfo.bTextIndent = sal_True; + } +} + +/* */ + +static void ParseCSS1_margin_left( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& /*rParser*/ ) +{ + DBG_ASSERT( pExpr, "kein Ausdruck" ); + + long nLeft = 0; + sal_Bool bSet = sal_False; + switch( pExpr->GetType() ) + { + case CSS1_LENGTH: + { + nLeft = pExpr->GetSLength(); + bSet = sal_True; + } + break; + case CSS1_PIXLENGTH: + { + nLeft = (long)pExpr->GetNumber(); + long nPHeight = 0; + SvxCSS1Parser::PixelToTwip( nLeft, nPHeight ); + bSet = sal_True; + } + break; + case CSS1_PERCENTAGE: + // koennen wir nicht + break; + default: + ; + } + + if( bSet ) + { + rPropInfo.nLeftMargin = nLeft; + if( nLeft < 0 ) + nLeft = 0; + const SfxPoolItem* pItem; + if( SFX_ITEM_SET == rItemSet.GetItemState( aItemIds.nLRSpace, sal_False, + &pItem ) ) + { + SvxLRSpaceItem aLRItem( *((const SvxLRSpaceItem*)pItem) ); + aLRItem.SetTxtLeft( (sal_uInt16)nLeft ); + rItemSet.Put( aLRItem ); + } + else + { + SvxLRSpaceItem aLRItem( aItemIds.nLRSpace ); + aLRItem.SetTxtLeft( (sal_uInt16)nLeft ); + rItemSet.Put( aLRItem ); + } + rPropInfo.bLeftMargin = sal_True; + } +} + +/* */ + +static void ParseCSS1_margin_right( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& /*rParser*/ ) +{ + DBG_ASSERT( pExpr, "kein Ausdruck" ); + + long nRight = 0; + sal_Bool bSet = sal_False; + switch( pExpr->GetType() ) + { + case CSS1_LENGTH: + { + nRight = pExpr->GetSLength(); + bSet = sal_True; + } + break; + case CSS1_PIXLENGTH: + { + nRight = (long)pExpr->GetNumber(); + long nPHeight = 0; + SvxCSS1Parser::PixelToTwip( nRight, nPHeight ); + bSet = sal_True; + } + break; + case CSS1_PERCENTAGE: + // koennen wir nicht + break; + default: + ; + } + + if( bSet ) + { + rPropInfo.nRightMargin = nRight; + if( nRight < 0 ) + nRight = 0; + const SfxPoolItem* pItem; + if( SFX_ITEM_SET == rItemSet.GetItemState( aItemIds.nLRSpace, sal_False, + &pItem ) ) + { + SvxLRSpaceItem aLRItem( *((const SvxLRSpaceItem*)pItem) ); + aLRItem.SetRight( (sal_uInt16)nRight ); + rItemSet.Put( aLRItem ); + } + else + { + SvxLRSpaceItem aLRItem( aItemIds.nLRSpace ); + aLRItem.SetRight( (sal_uInt16)nRight ); + rItemSet.Put( aLRItem ); + } + rPropInfo.bRightMargin = sal_True; + } +} + +/* */ + +static void ParseCSS1_margin_top( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& /*rParser*/ ) +{ + DBG_ASSERT( pExpr, "kein Ausdruck" ); + + sal_uInt16 nUpper = 0; + sal_Bool bSet = sal_False; + switch( pExpr->GetType() ) + { + case CSS1_LENGTH: + { + long nTmp = pExpr->GetSLength(); + if( nTmp < 0 ) + nTmp = 0; + nUpper = (sal_uInt16)nTmp; + bSet = sal_True; + } + break; + case CSS1_PIXLENGTH: + { + long nPWidth = 0; + long nPHeight = (long)pExpr->GetNumber(); + if( nPHeight < 0 ) + nPHeight = 0; + SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight ); + nUpper = (sal_uInt16)nPHeight; + bSet = sal_True; + } + break; + case CSS1_PERCENTAGE: + // koennen wir nicht + break; + default: + ; + } + + if( bSet ) + { + const SfxPoolItem* pItem; + if( SFX_ITEM_SET == rItemSet.GetItemState( aItemIds.nULSpace, sal_False, + &pItem ) ) + { + SvxULSpaceItem aULItem( *((const SvxULSpaceItem*)pItem) ); + aULItem.SetUpper( nUpper ); + rItemSet.Put( aULItem ); + } + else + { + SvxULSpaceItem aULItem( aItemIds.nULSpace ); + aULItem.SetUpper( nUpper ); + rItemSet.Put( aULItem ); + } + rPropInfo.bTopMargin = sal_True; + } +} + +/* */ + +static void ParseCSS1_margin_bottom( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& /*rParser*/ ) +{ + DBG_ASSERT( pExpr, "kein Ausdruck" ); + + sal_uInt16 nLower = 0; + sal_Bool bSet = sal_False; + switch( pExpr->GetType() ) + { + case CSS1_LENGTH: + { + long nTmp = pExpr->GetSLength(); + if( nTmp < 0 ) + nTmp = 0; + nLower = (sal_uInt16)nTmp; + bSet = sal_True; + } + break; + case CSS1_PIXLENGTH: + { + long nPWidth = 0; + long nPHeight = (long)pExpr->GetNumber(); + if( nPHeight < 0 ) + nPHeight = 0; + SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight ); + nLower = (sal_uInt16)nPHeight; + bSet = sal_True; + } + break; + case CSS1_PERCENTAGE: + // koennen wir nicht + break; + default: + ; + } + + if( bSet ) + { + const SfxPoolItem* pItem; + if( SFX_ITEM_SET == rItemSet.GetItemState( aItemIds.nULSpace, sal_False, + &pItem ) ) + { + SvxULSpaceItem aULItem( *((const SvxULSpaceItem*)pItem) ); + aULItem.SetLower( nLower ); + rItemSet.Put( aULItem ); + } + else + { + SvxULSpaceItem aULItem( aItemIds.nULSpace ); + aULItem.SetLower( nLower ); + rItemSet.Put( aULItem ); + } + rPropInfo.bBottomMargin = sal_True; + } +} + +/* */ + +static void ParseCSS1_margin( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& /*rParser*/ ) +{ + DBG_ASSERT( pExpr, "kein Ausdruck" ); + + long nMargins[4] = { 0, 0, 0, 0 }; + sal_Bool bSetMargins[4] = { sal_False, sal_False, sal_False, sal_False }; + + for( sal_uInt16 i=0; pExpr && i<4 && !pExpr->GetOp(); i++ ) + { + sal_Bool bSetThis = sal_False; + long nMargin = 0; + + switch( pExpr->GetType() ) + { + case CSS1_LENGTH: + { + nMargin = pExpr->GetSLength(); + bSetThis = sal_True; + } + break; + case CSS1_PIXLENGTH: + { + long nPWidth = 0; + nMargin = (long)pExpr->GetNumber(); + SvxCSS1Parser::PixelToTwip( nPWidth, nMargin ); + bSetThis = sal_True; + } + break; + case CSS1_PERCENTAGE: + // koennen wir nicht + break; + default: + ; + } + + if( bSetThis ) + { + // 0 = top + // 1 = right + // 2 = bottom + // 3 = left + switch( i ) + { + case 0: + nMargins[0] = nMargins[1] =nMargins[2] = nMargins[3] = nMargin; + bSetMargins[0] = bSetMargins[1] = + bSetMargins[2] = bSetMargins[3] = sal_True; + break; + case 1: + nMargins[1] = nMargins[3] = nMargin; // right + left + bSetMargins[1] = bSetMargins[3] = sal_True; + break; + case 2: + nMargins[2] = nMargin; // bottom + bSetMargins[2] = sal_True; + break; + case 3: + nMargins[3] = nMargin; // left + bSetMargins[3] = sal_True; + break; + } + } + pExpr = pExpr->GetNext(); + } + + if( bSetMargins[3] || bSetMargins[1] ) + { + if( bSetMargins[3] ) + { + rPropInfo.bLeftMargin = sal_True; + rPropInfo.nLeftMargin = nMargins[3]; + if( nMargins[3] < 0 ) + nMargins[3] = 0; + } + if( bSetMargins[1] ) + { + rPropInfo.bRightMargin = sal_True; + rPropInfo.nRightMargin = nMargins[1]; + if( nMargins[1] < 0 ) + nMargins[1] = 0; + } + + const SfxPoolItem* pItem; + if( SFX_ITEM_SET == rItemSet.GetItemState( aItemIds.nLRSpace, sal_False, + &pItem ) ) + { + SvxLRSpaceItem aLRItem( *((const SvxLRSpaceItem*)pItem) ); + if( bSetMargins[3] ) + aLRItem.SetLeft( (sal_uInt16)nMargins[3] ); + if( bSetMargins[1] ) + aLRItem.SetRight( (sal_uInt16)nMargins[1] ); + rItemSet.Put( aLRItem ); + } + else + { + SvxLRSpaceItem aLRItem( aItemIds.nLRSpace ); + if( bSetMargins[3] ) + aLRItem.SetLeft( (sal_uInt16)nMargins[3] ); + if( bSetMargins[1] ) + aLRItem.SetRight( (sal_uInt16)nMargins[1] ); + rItemSet.Put( aLRItem ); + } + } + + if( bSetMargins[0] || bSetMargins[2] ) + { + if( nMargins[0] < 0 ) + nMargins[0] = 0; + if( nMargins[2] < 0 ) + nMargins[2] = 0; + + const SfxPoolItem* pItem; + if( SFX_ITEM_SET == rItemSet.GetItemState( aItemIds.nULSpace, sal_False, + &pItem ) ) + { + SvxULSpaceItem aULItem( *((const SvxULSpaceItem*)pItem) ); + if( bSetMargins[0] ) + aULItem.SetUpper( (sal_uInt16)nMargins[0] ); + if( bSetMargins[2] ) + aULItem.SetLower( (sal_uInt16)nMargins[2] ); + rItemSet.Put( aULItem ); + } + else + { + SvxULSpaceItem aULItem( aItemIds.nULSpace ); + if( bSetMargins[0] ) + aULItem.SetUpper( (sal_uInt16)nMargins[0] ); + if( bSetMargins[2] ) + aULItem.SetLower( (sal_uInt16)nMargins[2] ); + rItemSet.Put( aULItem ); + } + + rPropInfo.bTopMargin |= bSetMargins[0]; + rPropInfo.bBottomMargin |= bSetMargins[2]; + } +} + +/* */ + +static sal_Bool ParseCSS1_padding_xxx( const CSS1Expression *pExpr, + SfxItemSet & /*rItemSet*/, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& /*rParser*/, + sal_uInt16 nWhichLine ) +{ + DBG_ASSERT( pExpr, "kein Ausdruck" ); + + sal_Bool bSet = sal_False; + sal_uInt16 nDist = 0; + + switch( pExpr->GetType() ) + { + case CSS1_LENGTH: + { + long nTmp = pExpr->GetSLength(); + if( nTmp < 0 ) + nTmp = 0; + else if( nTmp > USHRT_MAX-1 ) + nTmp = USHRT_MAX-1; + nDist = (sal_uInt16)nTmp; + bSet = sal_True; + } + break; + case CSS1_PIXLENGTH: + { + long nPWidth = (long)pExpr->GetNumber(); + long nPHeight = 0; + if( nPWidth < 0 ) + nPWidth = 0; + SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight ); + if( nPWidth > USHRT_MAX-1 ) + nPWidth = USHRT_MAX-1; + nDist = (sal_uInt16)nPWidth; + bSet = sal_True; + } + break; + case CSS1_PERCENTAGE: + // koennen wir nicht + break; + default: + ; + } + + if( bSet ) + { + switch( nWhichLine ) + { + case BOX_LINE_TOP: rPropInfo.nTopBorderDistance = nDist; break; + case BOX_LINE_BOTTOM: rPropInfo.nBottomBorderDistance = nDist;break; + case BOX_LINE_LEFT: rPropInfo.nLeftBorderDistance = nDist; break; + case BOX_LINE_RIGHT: rPropInfo.nRightBorderDistance = nDist; break; + } + } + + return bSet; +} + +/* */ + +static void ParseCSS1_padding_top( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& rParser ) +{ + ParseCSS1_padding_xxx( pExpr, rItemSet, rPropInfo, rParser, BOX_LINE_TOP ); +} + +static void ParseCSS1_padding_bottom( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& rParser ) +{ + ParseCSS1_padding_xxx( pExpr, rItemSet, rPropInfo, rParser, + BOX_LINE_BOTTOM ); +} + +static void ParseCSS1_padding_left( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& rParser ) +{ + ParseCSS1_padding_xxx( pExpr, rItemSet, rPropInfo, rParser, BOX_LINE_LEFT ); +} + +static void ParseCSS1_padding_right( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& rParser ) +{ + ParseCSS1_padding_xxx( pExpr, rItemSet, rPropInfo, rParser, + BOX_LINE_RIGHT ); +} + +static void ParseCSS1_padding( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& rParser ) +{ + sal_uInt16 n=0; + while( n<4 && pExpr && !pExpr->GetOp() ) + { + sal_uInt16 nLine = n==0 || n==2 ? BOX_LINE_BOTTOM : BOX_LINE_LEFT; + if( ParseCSS1_padding_xxx( pExpr, rItemSet, rPropInfo, rParser, + nLine ) ) + { + if( n==0 ) + { + rPropInfo.nTopBorderDistance = rPropInfo.nBottomBorderDistance; + rPropInfo.nLeftBorderDistance = rPropInfo.nTopBorderDistance; + } + if( n <= 1 ) + rPropInfo.nRightBorderDistance = rPropInfo.nLeftBorderDistance; + } + + pExpr = pExpr->GetNext(); + n++; + } +} + +/* */ + +static void ParseCSS1_border_xxx( const CSS1Expression *pExpr, + SfxItemSet & /*rItemSet*/, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& /*rParser*/, + sal_uInt16 nWhichLine, sal_Bool bAll ) +{ + DBG_ASSERT( pExpr, "kein Ausdruck" ); + + sal_uInt16 nWidth = USHRT_MAX; // die Linien-Dicke + sal_uInt16 nNWidth = 1; // benannte Linien-Dicke (und default) + CSS1BorderStyle eStyle = CSS1_BS_NONE; // Linien-Style + Color aColor; + sal_Bool bColor = sal_False; + + while( pExpr && !pExpr->GetOp() ) + { + switch( pExpr->GetType() ) + { + case CSS1_RGB: + case CSS1_HEXCOLOR: + if( pExpr->GetColor( aColor ) ) + bColor = sal_True; + break; + + case CSS1_IDENT: + { + const String& rValue = pExpr->GetString(); + sal_uInt16 nValue; + if( SvxCSS1Parser::GetEnum( aBorderWidthTable, rValue, nValue ) ) + { + nNWidth = nValue; + } + else if( SvxCSS1Parser::GetEnum( aBorderStyleTable, rValue, nValue ) ) + { + eStyle = (CSS1BorderStyle)nValue; + } + else if( pExpr->GetColor( aColor ) ) + { + bColor = sal_True; + } + } + break; + + case CSS1_LENGTH: + nWidth = (sal_uInt16)pExpr->GetULength(); + break; + + case CSS1_PIXLENGTH: + { + sal_Bool bHori = nWhichLine == BOX_LINE_TOP || + nWhichLine == BOX_LINE_BOTTOM; + // Ein Pixel wird zur Haarlinie (ist huebscher) + long nWidthL = (long)pExpr->GetNumber(); + if( nWidthL > 1 ) + { + long nPWidth = bHori ? 0 : nWidthL; + long nPHeight = bHori ? nWidthL : 0; + SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight ); + nWidth = (sal_uInt16)(bHori ? nPHeight : nPWidth); + } + else + nWidth = 1; + } + break; + + default: + ; + } + + pExpr = pExpr->GetNext(); + } + + for( sal_uInt16 i=0; i<4; i++ ) + { + sal_uInt16 nLine = 0; + switch( i ) + { + case 0: nLine = BOX_LINE_TOP; break; + case 1: nLine = BOX_LINE_BOTTOM; break; + case 2: nLine = BOX_LINE_LEFT; break; + case 3: nLine = BOX_LINE_RIGHT; break; + } + + if( bAll || nLine == nWhichLine ) + { + SvxCSS1BorderInfo *pInfo = rPropInfo.GetBorderInfo( nLine ); + pInfo->eStyle = eStyle; + pInfo->nAbsWidth = nWidth; + pInfo->nNamedWidth = nNWidth; + if( bColor ) + pInfo->aColor = aColor; + } + } +} + +static void ParseCSS1_border_xxx_width( const CSS1Expression *pExpr, + SfxItemSet & /*rItemSet*/, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& /*rParser*/, + sal_uInt16 nWhichLine ) +{ + DBG_ASSERT( pExpr, "kein Ausdruck" ); + + sal_uInt16 nWidth = USHRT_MAX; // die Linien-Dicke + sal_uInt16 nNWidth = 1; // benannte Linien-Dicke (und default) + + switch( pExpr->GetType() ) + { + case CSS1_IDENT: + { + sal_uInt16 nValue; + if( SvxCSS1Parser::GetEnum( aBorderWidthTable, pExpr->GetString(), nValue ) ) + { + nNWidth = nValue; + } + } + break; + + case CSS1_LENGTH: + nWidth = (sal_uInt16)pExpr->GetULength(); + break; + + case CSS1_PIXLENGTH: + { + sal_Bool bHori = nWhichLine == BOX_LINE_TOP || + nWhichLine == BOX_LINE_BOTTOM; + long nWidthL = (long)pExpr->GetNumber(); + long nPWidth = bHori ? 0 : nWidthL; + long nPHeight = bHori ? nWidthL : 0; + SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight ); + nWidth = (sal_uInt16)(bHori ? nPHeight : nPWidth); + } + break; + + default: + ; + } + + SvxCSS1BorderInfo *pInfo = rPropInfo.GetBorderInfo( nWhichLine ); + pInfo->nAbsWidth = nWidth; + pInfo->nNamedWidth = nNWidth; +} + +/* */ + +static void ParseCSS1_border_top_width( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& rParser ) +{ + ParseCSS1_border_xxx_width( pExpr, rItemSet, rPropInfo, rParser, BOX_LINE_TOP ); +} + +static void ParseCSS1_border_right_width( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& rParser ) +{ + ParseCSS1_border_xxx_width( pExpr, rItemSet, rPropInfo, rParser, BOX_LINE_RIGHT ); +} + +static void ParseCSS1_border_bottom_width( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& rParser ) +{ + ParseCSS1_border_xxx_width( pExpr, rItemSet, rPropInfo, rParser, BOX_LINE_BOTTOM ); +} + +static void ParseCSS1_border_left_width( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& rParser ) +{ + ParseCSS1_border_xxx_width( pExpr, rItemSet, rPropInfo, rParser, BOX_LINE_LEFT ); +} + +static void ParseCSS1_border_width( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& rParser ) +{ + sal_uInt16 n=0; + while( n<4 && pExpr && !pExpr->GetOp() ) + { + sal_uInt16 nLine = n==0 || n==2 ? BOX_LINE_BOTTOM : BOX_LINE_LEFT; + ParseCSS1_border_xxx_width( pExpr, rItemSet, rPropInfo, rParser, nLine ); + rPropInfo.CopyBorderInfo( n, SVX_CSS1_BORDERINFO_WIDTH ); + + pExpr = pExpr->GetNext(); + n++; + } +} + +static void ParseCSS1_border_color( const CSS1Expression *pExpr, + SfxItemSet & /*rItemSet*/, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& /*rParser*/ ) +{ + sal_uInt16 n=0; + while( n<4 && pExpr && !pExpr->GetOp() ) + { + sal_uInt16 nLine = n==0 || n==2 ? BOX_LINE_BOTTOM : BOX_LINE_LEFT; + Color aColor; + switch( pExpr->GetType() ) + { + case CSS1_RGB: + case CSS1_HEXCOLOR: + case CSS1_IDENT: + if( pExpr->GetColor( aColor ) ) + rPropInfo.GetBorderInfo( nLine )->aColor = aColor; + break; + default: + ; + } + rPropInfo.CopyBorderInfo( n, SVX_CSS1_BORDERINFO_COLOR ); + + pExpr = pExpr->GetNext(); + n++; + } +} + +static void ParseCSS1_border_style( const CSS1Expression *pExpr, + SfxItemSet & /*rItemSet*/, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& /*rParser*/ ) +{ + sal_uInt16 n=0; + while( n<4 && pExpr && !pExpr->GetOp() ) + { + sal_uInt16 nLine = n==0 || n==2 ? BOX_LINE_BOTTOM : BOX_LINE_LEFT; + sal_uInt16 nValue; + if( CSS1_IDENT==pExpr->GetType() && + SvxCSS1Parser::GetEnum( aBorderStyleTable, pExpr->GetString(), + nValue ) ) + { + rPropInfo.GetBorderInfo( nLine )->eStyle = (CSS1BorderStyle)nValue; + } + rPropInfo.CopyBorderInfo( n, SVX_CSS1_BORDERINFO_STYLE ); + + pExpr = pExpr->GetNext(); + n++; + } +} + + +static void ParseCSS1_border_top( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& rParser ) +{ + ParseCSS1_border_xxx( pExpr, rItemSet, rPropInfo, rParser, BOX_LINE_TOP, sal_False ); +} + +static void ParseCSS1_border_right( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& rParser ) +{ + ParseCSS1_border_xxx( pExpr, rItemSet, rPropInfo, rParser, BOX_LINE_RIGHT, sal_False ); +} + +static void ParseCSS1_border_bottom( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& rParser ) +{ + ParseCSS1_border_xxx( pExpr, rItemSet, rPropInfo, rParser, BOX_LINE_BOTTOM, sal_False ); +} + +static void ParseCSS1_border_left( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& rParser ) +{ + ParseCSS1_border_xxx( pExpr, rItemSet, rPropInfo, rParser, BOX_LINE_LEFT, sal_False ); +} + +static void ParseCSS1_border( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& rParser ) +{ + ParseCSS1_border_xxx( pExpr, rItemSet, rPropInfo, rParser, 0, sal_True ); +} + +/* */ + +static void ParseCSS1_float( const CSS1Expression *pExpr, + SfxItemSet & /*rItemSet*/, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& /*rParser*/ ) +{ + DBG_ASSERT( pExpr, "kein Ausdruck" ); + + if( CSS1_IDENT==pExpr->GetType() ) + { + sal_uInt16 nFloat; + if( SvxCSS1Parser::GetEnum( aFloatTable, pExpr->GetString(), nFloat ) ) + rPropInfo.eFloat = (SvxAdjust)nFloat; + } +} + + +/* */ + +static void ParseCSS1_position( const CSS1Expression *pExpr, + SfxItemSet & /*rItemSet*/, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& /*rParser*/ ) +{ + DBG_ASSERT( pExpr, "kein Ausdruck" ); + + if( CSS1_IDENT==pExpr->GetType() ) + { + sal_uInt16 nPos; + if( SvxCSS1Parser::GetEnum( aPositionTable, pExpr->GetString(), nPos ) ) + rPropInfo.ePosition = (SvxCSS1Position)nPos; + } +} + +/* */ + +static void ParseCSS1_length( const CSS1Expression *pExpr, + long& rLength, + SvxCSS1LengthType& rLengthType, + sal_Bool bHori ) +{ + switch( pExpr->GetType() ) + { + case CSS1_IDENT: + if( pExpr->GetString().EqualsIgnoreCaseAscii( sCSS1_PV_auto ) ) + { + rLength = 0; + rLengthType = SVX_CSS1_LTYPE_AUTO; + } + break; + + case CSS1_LENGTH: + rLength = pExpr->GetSLength(); + rLengthType = SVX_CSS1_LTYPE_TWIP; + break; + + case CSS1_PIXLENGTH: + case CSS1_NUMBER: // wegen Netscape und IE + { + long nWidthL = (long)pExpr->GetNumber(); + long nPWidth = bHori ? 0 : nWidthL; + long nPHeight = bHori ? nWidthL : 0; + SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight ); + rLength = (bHori ? nPHeight : nPWidth); + rLengthType = SVX_CSS1_LTYPE_TWIP; + } + break; + + case CSS1_PERCENTAGE: + rLength = (long)pExpr->GetNumber(); + if( rLength > 100 ) + rLength = 100; + rLengthType = SVX_CSS1_LTYPE_PERCENTAGE; + break; + + default: + ; + } +} + +/* */ + +static void ParseCSS1_width( const CSS1Expression *pExpr, + SfxItemSet & /*rItemSet*/, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& /*rParser*/ ) +{ + ParseCSS1_length( pExpr, rPropInfo.nWidth, rPropInfo.eWidthType, sal_True ); +} + +static void ParseCSS1_height( const CSS1Expression *pExpr, + SfxItemSet & /*rItemSet*/, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& /*rParser*/ ) +{ + ParseCSS1_length( pExpr, rPropInfo.nHeight, rPropInfo.eHeightType, sal_False ); +} + +static void ParseCSS1_left( const CSS1Expression *pExpr, + SfxItemSet & /*rItemSet*/, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& /*rParser*/ ) +{ + ParseCSS1_length( pExpr, rPropInfo.nLeft, rPropInfo.eLeftType, sal_True ); +} + +static void ParseCSS1_top( const CSS1Expression *pExpr, + SfxItemSet & /*rItemSet*/, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& /*rParser*/ ) +{ + ParseCSS1_length( pExpr, rPropInfo.nTop, rPropInfo.eTopType, sal_False ); +} + +/* */ + +// Feature: PrintExt +static void ParseCSS1_size( const CSS1Expression *pExpr, + SfxItemSet & /*rItemSet*/, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& /*rParser*/ ) +{ + sal_uInt16 n=0; + while( n<2 && pExpr && !pExpr->GetOp() ) + { + switch( pExpr->GetType() ) + { + case CSS1_IDENT: + { + sal_uInt16 nValue; + if( SvxCSS1Parser::GetEnum( aSizeTable, pExpr->GetString(), + nValue ) ) + { + rPropInfo.eSizeType = (SvxCSS1SizeType)nValue; + } + } + break; + + case CSS1_LENGTH: + rPropInfo.nHeight = pExpr->GetSLength(); + if( n==0 ) + rPropInfo.nWidth = rPropInfo.nHeight; + rPropInfo.eSizeType = SVX_CSS1_STYPE_TWIP; + break; + + case CSS1_PIXLENGTH: + { + long nPHeight = (long)pExpr->GetNumber(); + long nPWidth = n==0 ? nPHeight : 0; + SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight ); + rPropInfo.nHeight = nPHeight; + if( n==0 ) + rPropInfo.nWidth = nPWidth; + rPropInfo.eSizeType = SVX_CSS1_STYPE_TWIP; + } + break; + + default: + ; + } + + pExpr = pExpr->GetNext(); + n++; + } +} + +// /Feature: PrintExt + +/* */ + +// Feature: PrintExt + +static void ParseCSS1_page_break_xxx( const CSS1Expression *pExpr, + SvxCSS1PageBreak& rPBreak ) +{ + if( CSS1_IDENT == pExpr->GetType() ) + { + sal_uInt16 nValue; + if( SvxCSS1Parser::GetEnum( aPageBreakTable, pExpr->GetString(), + nValue ) ) + { + rPBreak = (SvxCSS1PageBreak)nValue; + } + } +} + +static void ParseCSS1_page_break_before( const CSS1Expression *pExpr, + SfxItemSet & /*rItemSet*/, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& /*rParser*/ ) +{ + ParseCSS1_page_break_xxx( pExpr, rPropInfo.ePageBreakBefore ); +} + +static void ParseCSS1_page_break_after( const CSS1Expression *pExpr, + SfxItemSet & /*rItemSet*/, + SvxCSS1PropertyInfo& rPropInfo, + const SvxCSS1Parser& /*rParser*/ ) +{ + ParseCSS1_page_break_xxx( pExpr, rPropInfo.ePageBreakAfter ); +} + +static void ParseCSS1_page_break_inside( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& /*rPropInfo*/, + const SvxCSS1Parser& /*rParser*/ ) +{ + SvxCSS1PageBreak eBreak(SVX_CSS1_PBREAK_NONE); + ParseCSS1_page_break_xxx( pExpr, eBreak ); + + sal_Bool bSetSplit = sal_False, bSplit = sal_True; + switch( eBreak ) + { + case SVX_CSS1_PBREAK_AUTO: + bSetSplit = sal_True; + break; + case SVX_CSS1_PBREAK_AVOID: + bSplit = sal_False; + bSetSplit = sal_True; + break; + default: + ; + } + + if( bSetSplit ) + rItemSet.Put( SvxFmtSplitItem( bSplit, aItemIds.nFmtSplit ) ); +} + +static void ParseCSS1_widows( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& /*rPropInfo*/, + const SvxCSS1Parser& /*rParser*/ ) +{ + if( CSS1_NUMBER == pExpr->GetType() ) + { + sal_uInt8 nVal = pExpr->GetNumber() <= 255 + ? (sal_uInt8)pExpr->GetNumber() + : 255; + SvxWidowsItem aWidowsItem( nVal, aItemIds.nWidows ); + rItemSet.Put( aWidowsItem ); + } +} + +static void ParseCSS1_orphans( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& /*rPropInfo*/, + const SvxCSS1Parser& /*rParser*/ ) +{ + if( CSS1_NUMBER == pExpr->GetType() ) + { + sal_uInt8 nVal = pExpr->GetNumber() <= 255 + ? (sal_uInt8)pExpr->GetNumber() + : 255; + SvxOrphansItem aOrphansItem( nVal, aItemIds.nOrphans ); + rItemSet.Put( aOrphansItem ); + } +} +// /Feature: PrintExt + +static void ParseCSS1_so_language( const CSS1Expression *pExpr, + SfxItemSet &rItemSet, + SvxCSS1PropertyInfo& /*rPropInfo*/, + const SvxCSS1Parser& rParser ) +{ + if( CSS1_IDENT == pExpr->GetType() || + CSS1_STRING == pExpr->GetType() ) + { + LanguageType eLang = MsLangId::convertIsoStringToLanguage( pExpr->GetString() ); + if( LANGUAGE_DONTKNOW != eLang ) + { + SvxLanguageItem aLang( eLang, aItemIds.nLanguage ); + if( rParser.IsSetWesternProps() ) + rItemSet.Put( aLang ); + if( rParser.IsSetCJKProps() ) + { + aLang.SetWhich( aItemIds.nLanguageCJK ); + rItemSet.Put( aLang ); + } + if( rParser.IsSetCTLProps() ) + { + aLang.SetWhich( aItemIds.nLanguageCTL ); + rItemSet.Put( aLang ); + } + } + } +} + +/* */ + +// die Zuordung Property zu parsender Funktion +struct CSS1PropEntry +{ + union + { + const sal_Char *sName; + String *pName; + }; + FnParseCSS1Prop pFunc; +}; + +#define CSS1_PROP_ENTRY(p) \ + { { sCSS1_P_##p }, ParseCSS1_##p } + + +// die Tabelle mit den Zuordnungen +static CSS1PropEntry __FAR_DATA aCSS1PropFnTab[] = +{ + CSS1_PROP_ENTRY(background), + CSS1_PROP_ENTRY(background_color), + CSS1_PROP_ENTRY(border_top_width), + CSS1_PROP_ENTRY(border_right_width), + CSS1_PROP_ENTRY(border_bottom_width), + CSS1_PROP_ENTRY(border_left_width), + CSS1_PROP_ENTRY(border_width), + CSS1_PROP_ENTRY(border_color), + CSS1_PROP_ENTRY(border_style), + CSS1_PROP_ENTRY(border_top), + CSS1_PROP_ENTRY(border_right), + CSS1_PROP_ENTRY(border_bottom), + CSS1_PROP_ENTRY(border_left), + CSS1_PROP_ENTRY(border), + CSS1_PROP_ENTRY(color), + CSS1_PROP_ENTRY(direction), + CSS1_PROP_ENTRY(float), + CSS1_PROP_ENTRY(font_size), + CSS1_PROP_ENTRY(font_family), + CSS1_PROP_ENTRY(font_style), + CSS1_PROP_ENTRY(font_variant), + CSS1_PROP_ENTRY(font_weight), + CSS1_PROP_ENTRY(letter_spacing), + CSS1_PROP_ENTRY(line_height), + CSS1_PROP_ENTRY(font), + CSS1_PROP_ENTRY(text_align), + CSS1_PROP_ENTRY(text_decoration), + CSS1_PROP_ENTRY(text_indent), + CSS1_PROP_ENTRY(margin_left), + CSS1_PROP_ENTRY(margin_right), + CSS1_PROP_ENTRY(margin_top), + CSS1_PROP_ENTRY(margin_bottom), + CSS1_PROP_ENTRY(margin), + CSS1_PROP_ENTRY(padding_top), + CSS1_PROP_ENTRY(padding_bottom), + CSS1_PROP_ENTRY(padding_left), + CSS1_PROP_ENTRY(padding_right), + CSS1_PROP_ENTRY(padding), + CSS1_PROP_ENTRY(position), + CSS1_PROP_ENTRY(left), + CSS1_PROP_ENTRY(top), + CSS1_PROP_ENTRY(width), + CSS1_PROP_ENTRY(height), +// Feature: PrintExt + CSS1_PROP_ENTRY(size), + CSS1_PROP_ENTRY(page_break_before), + CSS1_PROP_ENTRY(page_break_after), + CSS1_PROP_ENTRY(page_break_inside), + CSS1_PROP_ENTRY(widows), + CSS1_PROP_ENTRY(orphans), +// /Feature: PrintExt + CSS1_PROP_ENTRY(so_language) +}; + +/* */ + +static int __FAR_DATA bSortedPropFns = sal_False; + +extern "C" +{ +static int +#if defined( WNT ) + __cdecl +#endif +#if defined( ICC ) + _Optlink +#endif + CSS1PropEntryCompare( const void *pFirst, const void *pSecond) +{ + int nRet; + if( ((CSS1PropEntry*)pFirst)->pFunc ) + { + if( ((CSS1PropEntry*)pSecond)->pFunc ) + nRet = strcmp( ((CSS1PropEntry*)pFirst)->sName , + ((CSS1PropEntry*)pSecond)->sName ); + else + nRet = -1 * ((CSS1PropEntry*)pSecond)->pName->CompareToAscii( + ((CSS1PropEntry*)pFirst)->sName ); + } + else + { + if( ((CSS1PropEntry*)pSecond)->pFunc ) + nRet = ((CSS1PropEntry*)pFirst)->pName->CompareToAscii( + ((CSS1PropEntry*)pSecond)->sName ); + else + nRet = ((CSS1PropEntry*)pFirst)->pName->CompareTo( + *((CSS1PropEntry*)pSecond)->pName ); + } + + return nRet; +} +} + +void SvxCSS1Parser::ParseProperty( const String& rProperty, + const CSS1Expression *pExpr ) +{ + DBG_ASSERT( pItemSet, "DeclarationParsed() ohne ItemSet" ); + + if( !bSortedPropFns ) + { + qsort( (void*) aCSS1PropFnTab, + sizeof( aCSS1PropFnTab ) / sizeof( CSS1PropEntry ), + sizeof( CSS1PropEntry ), + CSS1PropEntryCompare ); + bSortedPropFns = sal_True; + } + + String aTmp( rProperty ); + aTmp.ToLowerAscii(); + + CSS1PropEntry aSrch; + aSrch.pName = &aTmp; + aSrch.pFunc = 0; + + void* pFound; + if( 0 != ( pFound = bsearch( (char *) &aSrch, + (void*) aCSS1PropFnTab, + sizeof( aCSS1PropFnTab ) / sizeof( CSS1PropEntry ), + sizeof( CSS1PropEntry ), + CSS1PropEntryCompare ))) + { + (((CSS1PropEntry*)pFound)->pFunc)( pExpr, *pItemSet, *pPropInfo, *this ); + } +} diff --git a/sw/source/filter/html/svxcss1.hxx b/sw/source/filter/html/svxcss1.hxx new file mode 100644 index 000000000000..e5f706334538 --- /dev/null +++ b/sw/source/filter/html/svxcss1.hxx @@ -0,0 +1,435 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _SVXCSS1_HXX +#define _SVXCSS1_HXX + +#include <tools/string.hxx> +#include <svl/itemset.hxx> +#include <editeng/svxenum.hxx> + +#ifndef _SVSTDARR_HXX +#define _SVSTDARR_USHORTS +#include <svl/svstdarr.hxx> +#endif +#include <rtl/textenc.h> +#include "parcss1.hxx" + +class SfxItemPool; +class SvxBoxItem; +class FontList; + +/* */ + +enum SvxCSS1Position +{ + SVX_CSS1_POS_NONE, // nichts angegeben + SVX_CSS1_POS_STATIC, // normal + SVX_CSS1_POS_ABSOLUTE, // absolut + SVX_CSS1_POS_RELATIVE, // relativ + SVX_CSS1_POS_END +}; + + +enum SvxCSS1LengthType +{ + SVX_CSS1_LTYPE_NONE, // nichts angegeben + SVX_CSS1_LTYPE_AUTO, // automatisch + SVX_CSS1_LTYPE_TWIP, // twip + SVX_CSS1_LTYPE_PERCENTAGE, // %-Angabe + SVX_CSS1_LTYPE_END +}; + +// Feature: PrintExt +enum SvxCSS1SizeType +{ + SVX_CSS1_STYPE_NONE, // nichts angegeben + SVX_CSS1_STYPE_AUTO, // automatisch + SVX_CSS1_STYPE_TWIP, // twip + SVX_CSS1_STYPE_LANDSCAPE, // Landscape + SVX_CSS1_STYPE_PORTRAIT, // Landscape + SVX_CSS1_STYPE_END +}; + +enum SvxCSS1PageBreak +{ + SVX_CSS1_PBREAK_NONE, // nichts angegeben + SVX_CSS1_PBREAK_AUTO, // automatisch + SVX_CSS1_PBREAK_ALWAYS, // immer + SVX_CSS1_PBREAK_AVOID, // nie + SVX_CSS1_PBREAK_LEFT, // naechste Seite ist eine linke + SVX_CSS1_PBREAK_RIGHT, // naechste Seite ist eine rechte + SVX_CSS1_PBREAK_END +}; + +// /Feature: PrintExt + +#define CSS1_SCRIPT_WESTERN 0x01 +#define CSS1_SCRIPT_CJK 0x02 +#define CSS1_SCRIPT_CTL 0x04 +#define CSS1_SCRIPT_ALL 0x07 + +/* */ + +struct CSS1PropertyEnum +{ + const sal_Char *pName; // Wert einer Property + sal_uInt16 nEnum; // und der dazugehoerige Wert eines Enums +}; + + +/* */ + +class SvxBorderLine; + +SV_DECL_PTRARR_DEL( CSS1Selectors, CSS1Selector*, 1, 1 ) + +#define SVX_CSS1_BORDERINFO_WIDTH 1 +#define SVX_CSS1_BORDERINFO_COLOR 2 +#define SVX_CSS1_BORDERINFO_STYLE 4 + +struct SvxCSS1BorderInfo; +class SvxCSS1PropertyInfo +{ + SvxCSS1BorderInfo *aBorderInfos[4]; + + void DestroyBorderInfos(); + +public: + + String aId; // ID fuer Bookmarks, Rahmen etc. + + sal_Bool bTopMargin : 1; + sal_Bool bBottomMargin : 1; + + sal_Bool bLeftMargin : 1; + sal_Bool bRightMargin : 1; + sal_Bool bTextIndent : 1; + + SvxAdjust eFloat; + + SvxCSS1Position ePosition; + + sal_uInt16 nTopBorderDistance; + sal_uInt16 nBottomBorderDistance; + sal_uInt16 nLeftBorderDistance; + sal_uInt16 nRightBorderDistance; + + long nLeft, nTop; + long nWidth, nHeight; + long nLeftMargin, nRightMargin; + + SvxCSS1LengthType eLeftType, eTopType; + SvxCSS1LengthType eWidthType, eHeightType; + +// Feature: PrintExt + SvxCSS1SizeType eSizeType; + + SvxCSS1PageBreak ePageBreakBefore; + SvxCSS1PageBreak ePageBreakAfter; +// /Feature: PrintExt + + SvxCSS1PropertyInfo(); + SvxCSS1PropertyInfo( const SvxCSS1PropertyInfo& rProp ); + ~SvxCSS1PropertyInfo(); + + void Merge( const SvxCSS1PropertyInfo& rProp ); + + void Clear(); + + SvxCSS1BorderInfo *GetBorderInfo( sal_uInt16 nLine, sal_Bool bCreate=sal_True ); + void CopyBorderInfo( sal_uInt16 nSrcLine, sal_uInt16 nDstLine, sal_uInt16 nWhat ); + void CopyBorderInfo( sal_uInt16 nCount, sal_uInt16 nWhat ); + + void SetBoxItem( SfxItemSet& rItemSet, sal_uInt16 nMinBorderDist, + const SvxBoxItem* pDflt=0, sal_Bool bTable = sal_False ); + +}; + +class SvxCSS1MapEntry +{ + String aKey; + SfxItemSet aItemSet; + SvxCSS1PropertyInfo aPropInfo; + +public: + + SvxCSS1MapEntry( SfxItemPool& rPool, const sal_uInt16 *pWhichMap ) : + aItemSet( rPool, pWhichMap ) + {} + + SvxCSS1MapEntry( const String& rKey, const SfxItemSet& rItemSet, + const SvxCSS1PropertyInfo& rProp ); + + + const SfxItemSet& GetItemSet() const { return aItemSet; } + SfxItemSet& GetItemSet() { return aItemSet; } + + const SvxCSS1PropertyInfo& GetPropertyInfo() const { return aPropInfo; } + SvxCSS1PropertyInfo& GetPropertyInfo() { return aPropInfo; } + + const String& GetKey() const { return aKey; } + // TODO: ToUpperAscii -> ??? + void SetKey( const String& rKey ) { aKey = rKey; aKey.ToUpperAscii(); } + + friend sal_Bool operator==( const SvxCSS1MapEntry& rE1, + const SvxCSS1MapEntry& rE2 ); + friend sal_Bool operator<( const SvxCSS1MapEntry& rE1, + const SvxCSS1MapEntry& rE2 ); +}; + +typedef SvxCSS1MapEntry *SvxCSS1MapEntryPtr; +SV_DECL_PTRARR_SORT_DEL( SvxCSS1Map, SvxCSS1MapEntryPtr, 5, 5 ) + + +#if !defined( ICC ) && !defined( BLC ) +inline sal_Bool operator==( const SvxCSS1MapEntry& rE1, const SvxCSS1MapEntry& rE2 ) +{ + return rE1.aKey==rE2.aKey; +} + +inline sal_Bool operator<( const SvxCSS1MapEntry& rE1, const SvxCSS1MapEntry& rE2 ) +{ + return rE1.aKey<rE2.aKey; +} +#endif + +// Diese Klasse bereitet den Output des CSS1-Parsers auf, +// indem die CSS1-Properties in SvxItem(Set)s umgewandelt werden. +// Ausserdem werden die Selektoren samt zugehoeriger Item-Set +// gespeichert. +// Ein abgeleiteter Parser kann dies fuer einzelne Selektoren unterdruecken, +// indem er die Methode StyleParsed ueberlaed. + +class SvxCSS1Parser : public CSS1Parser +{ + CSS1Selectors aSelectors; // Liste der "offenen" Selectoren + + SvxCSS1Map aIds; + SvxCSS1Map aClasses; + SvxCSS1Map aPages; + SvxCSS1Map aTags; + + String sBaseURL; + + SfxItemSet *pSheetItemSet; // der Item-Set fuer Style-Sheets + SfxItemSet *pItemSet; // der aktuelle Item-Set + SvxCSS1MapEntry *pSearchEntry; + + SvxCSS1PropertyInfo *pSheetPropInfo; + SvxCSS1PropertyInfo *pPropInfo; + + sal_uInt16 nMinFixLineSpace; // Mindest-Abstand fuer festen Zeilenabstand + + rtl_TextEncoding eDfltEnc; + sal_uInt16 nScriptFlags; + + sal_Bool bIgnoreFontFamily; + + void ParseProperty( const String& rProperty, + const CSS1Expression *pExpr ); + + SvUShorts aWhichMap; // Which-Map des Parser + + using CSS1Parser::ParseStyleOption; + +protected: + + using CSS1Parser::ParseStyleSheet; + + // Diese Methode wird fuer jeden Selektor mit dem zugehoerigen + // Item-Set aufgerufen. Fuer einen Selektor koennen mehrere + // Aufrufe erfolgen. + // wenn sal_True zuruckgegeben wird, wird der Item-Set bzw. der + // Selektor nicht mehr gespeichert! + // Der ItemSet darf entsprechend modifiziert werden! + // Die Implementierung dieser Methode gibt sal_False zurueck. + virtual sal_Bool StyleParsed( const CSS1Selector *pSelector, + SfxItemSet& rItemSet, + SvxCSS1PropertyInfo& rPropInfo ); + + // Diese Methode wird aufgerufen, wenn ein Selektor geparst wurde + // Wenn bFirst gesetzt ist, wird der Inhalt von aItemSet in alle + // zuletzt angelegten Styles kopiert. + // Diese Methode sollte in abgleiteten Parsern nicht mehr + // ueberladen werden! + virtual sal_Bool SelectorParsed( const CSS1Selector *pSelector, + sal_Bool bFirst ); + + // Diese Methode wird fuer jede geparste Property aufgerufen + // sie fuegt das Item in den ItemSet 'pItemSet' ein + // Sie sollte in abgeleiteten Parsern nicht mehr ueberladen werden! + virtual sal_Bool DeclarationParsed( const String& rProperty, + const CSS1Expression *pExpr ); + +public: + + + SvxCSS1Parser( SfxItemPool& rPool, + const String& rBaseURL, + sal_uInt16 nMinFixLineSp, + sal_uInt16 *pWhichIds=0, sal_uInt16 nWhichIds=0 ); + virtual ~SvxCSS1Parser(); + + sal_Bool IsIgnoreFontFamily() const { return bIgnoreFontFamily; } + void SetIgnoreFontFamily( sal_Bool bSet ) { bIgnoreFontFamily = bSet; } + + // Parsen eines Style-Sheets. Fuer jeden gefundenen Selektor + // wird StyleParsed mit dem entsprechenem Item-Set aufgerufen + virtual sal_Bool ParseStyleSheet( const String& rIn ); + + // Parsen einer Style-Option. Hier wird einfach nur der Item-Set + // gefuellt. + sal_Bool ParseStyleOption( const String& rIn, SfxItemSet& rItemSet, + SvxCSS1PropertyInfo& rPropInfo ); + + // Umwandeln eines Strings in den Wert eines Enums + static sal_Bool GetEnum( const CSS1PropertyEnum *pPropTable, + const String& rValue, sal_uInt16 &rEnum ); + + // Pixel in Twips wandeln + static void PixelToTwip( long &nWidth, long &nHeight ); + + // Die Breite einer Umrandung einstellen + static void SetBorderWidth( SvxBorderLine& aBorderLine, sal_uInt16 nWidth, + sal_Bool bDouble, sal_Bool bTable=sal_False ); + + // Die Font-Hoehe fuer eine bestimmte Font-Groesse (0-6) ermitteln + virtual sal_uInt32 GetFontHeight( sal_uInt16 nSize ) const; + + virtual const FontList *GetFontList() const; + + const sal_uInt16 *GetWhichMap() const { return aWhichMap.GetData(); } + + SvxCSS1MapEntry *GetMapEntry( const String& rKey, + const SvxCSS1Map& rMap ) const; + + void InsertMapEntry( const String& rKey, const SfxItemSet& rItemSet, + const SvxCSS1PropertyInfo& rProp, SvxCSS1Map& rMap ); + + void InsertId( const String& rId, const SfxItemSet& rItemSet, + const SvxCSS1PropertyInfo& rProp ); + + inline SvxCSS1MapEntry *GetId( const String& rId ) const; + + void InsertClass( const String& rClass, const SfxItemSet& rItemSet, + const SvxCSS1PropertyInfo& rProp ); + + inline SvxCSS1MapEntry *GetClass( const String& rClass ) const; + + inline void InsertPage( const String& rPage, sal_Bool bPseudo, + const SfxItemSet& rItemSet, + const SvxCSS1PropertyInfo& rProp ); + + inline SvxCSS1MapEntry *GetPage( const String& rPage, sal_Bool bPseudo ) const; + + inline SvxCSS1MapEntry *GetPage( sal_uInt16 i ) const { return aPages[i]; } + sal_uInt16 GetPageCount() const { return aPages.Count(); } + + void InsertTag( const String& rTag, const SfxItemSet& rItemSet, + const SvxCSS1PropertyInfo& rProp ); + + inline SvxCSS1MapEntry *GetTag( const String& rTag ) const; + + void MergeStyles( const SfxItemSet& rSrcSet, + const SvxCSS1PropertyInfo& rSrcInfo, + SfxItemSet& rTargetSet, + SvxCSS1PropertyInfo& rTargetInfo, + sal_Bool bSmart ); + + sal_uInt16 GetMinFixLineSpace() const { return nMinFixLineSpace; } + + virtual void SetDfltEncoding( rtl_TextEncoding eEnc ); + rtl_TextEncoding GetDfltEncoding() const { return eDfltEnc; } + + sal_Bool IsSetWesternProps() const { return (nScriptFlags & CSS1_SCRIPT_WESTERN) != 0; } + sal_Bool IsSetCJKProps() const { return (nScriptFlags & CSS1_SCRIPT_CJK) != 0; } + sal_Bool IsSetCTLProps() const { return (nScriptFlags & CSS1_SCRIPT_CTL) != 0; } + + const String& GetBaseURL() const { return sBaseURL;} + +}; + +inline void SvxCSS1Parser::InsertId( const String& rId, + const SfxItemSet& rItemSet, + const SvxCSS1PropertyInfo& rProp ) +{ + InsertMapEntry( rId, rItemSet, rProp, aIds ); +} + +inline SvxCSS1MapEntry *SvxCSS1Parser::GetId( const String& rId ) const +{ + return GetMapEntry( rId, aIds ); +} + +inline void SvxCSS1Parser::InsertClass( const String& rClass, + const SfxItemSet& rItemSet, + const SvxCSS1PropertyInfo& rProp ) +{ + InsertMapEntry( rClass, rItemSet, rProp, aClasses ); +} + +inline SvxCSS1MapEntry *SvxCSS1Parser::GetClass( const String& rClass ) const +{ + return GetMapEntry( rClass, aClasses ); +} + +inline void SvxCSS1Parser::InsertPage( const String& rPage, + sal_Bool bPseudo, + const SfxItemSet& rItemSet, + const SvxCSS1PropertyInfo& rProp ) +{ + String aKey( rPage ); + if( bPseudo ) + aKey.Insert( ':', 0 ); + InsertMapEntry( aKey, rItemSet, rProp, aPages ); +} + +inline SvxCSS1MapEntry *SvxCSS1Parser::GetPage( const String& rPage, + sal_Bool bPseudo ) const +{ + String aKey( rPage ); + if( bPseudo ) + aKey.Insert( ':', 0 ); + return GetMapEntry( aKey, aPages ); +} + +inline void SvxCSS1Parser::InsertTag( const String& rTag, + const SfxItemSet& rItemSet, + const SvxCSS1PropertyInfo& rProp ) +{ + InsertMapEntry( rTag, rItemSet, rProp, aTags ); +} + +inline SvxCSS1MapEntry *SvxCSS1Parser::GetTag( const String& rTag ) const +{ + return GetMapEntry( rTag, aTags ); +} + + +#endif + + diff --git a/sw/source/filter/html/swcss1.hxx b/sw/source/filter/html/swcss1.hxx new file mode 100644 index 000000000000..f0bbd758dce3 --- /dev/null +++ b/sw/source/filter/html/swcss1.hxx @@ -0,0 +1,227 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _SWCSS1_HXX +#define _SWCSS1_HXX + +#include "poolfmt.hxx" + +#include "svxcss1.hxx" + +class SwDoc; +class SwFmt; +class SwCharFmt; +class SwTxtFmtColl; +class SvxBrushItem; +class SwFmtDrop; +class SwPageDesc; + +// Dieser Header seiht zwar harmlos aus, included aber eben doch +// ganz unauffaellig das ein oder andere! Andererseits wird diese +// Klasse recht selten benoetigt. Deshalb ein eigener Header. + + +class SwCSS1Parser : public SvxCSS1Parser +{ + SwDoc *pDoc; + + sal_uLong aFontHeights[7]; + + sal_uInt16 nDropCapCnt; + + sal_Bool bIsNewDoc : 1; + + sal_Bool bBodyBGColorSet : 1; + sal_Bool bBodyBackgroundSet : 1; + sal_Bool bBodyTextSet : 1; + sal_Bool bBodyLinkSet : 1; + sal_Bool bBodyVLinkSet : 1; + + sal_Bool bSetFirstPageDesc : 1; + sal_Bool bSetRightPageDesc : 1; + + sal_Bool bTableHeaderTxtCollSet : 1; + sal_Bool bTableTxtCollSet : 1; + + sal_Bool bLinkCharFmtsSet : 1; + + // die Vorlagen fuer DL anlegen + SwTxtFmtColl* GetDefListTxtFmtColl( sal_uInt16 nCollId, sal_uInt16 nDeep ); + + const SwPageDesc* GetPageDesc( sal_uInt16 nPoolId, sal_Bool bCreate ); + + void SetTableTxtColl( sal_Bool bHeader ); + void SetLinkCharFmts(); + +protected: + virtual sal_Bool StyleParsed( const CSS1Selector *pSelector, + SfxItemSet& rItemSet, + SvxCSS1PropertyInfo& rPropInfo ); + + using CSS1Parser::ParseStyleSheet; + +public: + SwCSS1Parser( SwDoc *pDoc, sal_uInt32 aFHeight[7], const String& rBaseURL, sal_Bool bNewDoc ); + virtual ~SwCSS1Parser(); + + virtual sal_Bool ParseStyleSheet( const String& rIn ); + + // Die Font-Hoehe fuer eine bestimmte Font-Groesse (0-6) ermitteln + virtual sal_uInt32 GetFontHeight( sal_uInt16 nSize ) const; + + // Die aktuelle Font-Liste holen (auch 0 ist erlaubt) + virtual const FontList *GetFontList() const; + + // das Zeichen-Format zu einem Token und einer ggf leeren Klasse + // ermitteln + SwCharFmt* GetChrFmt( sal_uInt16 nToken, const String& rClass ) const; + + // eine TextFmtColl zu einer Pool-Id ermitteln + SwTxtFmtColl *GetTxtFmtColl( sal_uInt16 nTxtColl, const String& rClass ); + + // This methods do the same as the one of SwDoc, but change the + // encoding if required. + SwTxtFmtColl *GetTxtCollFromPool( sal_uInt16 nPoolId ) const; + SwCharFmt *GetCharFmtFromPool( sal_uInt16 nPoolId ) const; + + // Die linke oder rechte Seiten-Vorlage holen. In Dokumenten mit nur + // einer Vorlage gibt es nur eine rechtee Seite. + // Ansonsten ist die rechte Seite die HTML-Poolvorlage und die linke + // eine Benutzter-Vorlage, die on-demand angelegt wird, wenn + // bCreate gesetzt ist. + SwPageDesc* GetMasterPageDesc(); + inline const SwPageDesc* GetFirstPageDesc( sal_Bool bCreate=sal_False ); + inline const SwPageDesc* GetRightPageDesc( sal_Bool bCreate=sal_False ); + inline const SwPageDesc* GetLeftPageDesc( sal_Bool bCreate=sal_False ); + + // Attribute an der HTML-Seitenvorlage setzen (gesetzte Attribute + // werden aus dem Item-Set geloescht ). Wird fuer's BODY-Tag + // aufgerufen. + void SetPageDescAttrs( const SvxBrushItem *pBrush, + SfxItemSet *pItemSet=0 ); + + void ChgPageDesc( const SwPageDesc *pPageDesc, + const SwPageDesc& rNewPageDesc ); + + // Wird fuer @page aufgerufen. + void SetPageDescAttrs( const SwPageDesc *pPageDesc, SfxItemSet& rItemSet, + const SvxCSS1PropertyInfo& rPropInfo ); + + // Fuellen eines DropCap-Attributs + void FillDropCap( SwFmtDrop& rDrop, SfxItemSet& rItemSet, + const String *pName=0 ); + + sal_Bool SetFmtBreak( SfxItemSet& rItemSet, + const SvxCSS1PropertyInfo& rPropInfo ); + + + static void AddClassName( String& rFmtName, const String& rClass ); + + static inline void AddFirstLetterExt( String& rFmtName ); + + static sal_Bool MayBePositioned( const SvxCSS1PropertyInfo& rPropInfo, + sal_Bool bAutoWidth=sal_False ); + + static sal_uInt16 GetScriptFromClass( String& rClass, + sal_Bool bSubClassOnly = sal_True ); + + sal_Bool IsBodyBGColorSet() const { return bBodyBGColorSet; } + sal_Bool IsBodyBackgroundSet() const { return bBodyBackgroundSet; } + sal_Bool IsBodyTextSet() const { return bBodyTextSet; } + sal_Bool IsBodyLinkSet() const { return bBodyLinkSet; } + sal_Bool IsBodyVLinkSet() const { return bBodyVLinkSet; } + + sal_Bool IsSetFirstPageDesc() const { return bSetFirstPageDesc; } + sal_Bool IsSetRightPageDesc() const { return bSetRightPageDesc; } + + void SetBodyBGColorSet() { bBodyBGColorSet = sal_True; } + void SetBodyBackgroundSet() { bBodyBackgroundSet = sal_True; } + void SetBodyTextSet() { bBodyTextSet = sal_True; } + void SetBodyLinkSet() { bBodyLinkSet = sal_True; } + void SetBodyVLinkSet() { bBodyVLinkSet = sal_True; } + + const SvxBrushItem& GetPageDescBackground() const; + + inline void SetTHTagStyles(); + inline void SetTDTagStyles(); + inline void SetATagStyles(); + inline void SetDelayedStyles(); + + virtual void SetDfltEncoding( rtl_TextEncoding eEnc ); +}; + + +inline void SwCSS1Parser::AddFirstLetterExt( String& rFmtName ) +{ + rFmtName.AppendAscii( ".FL", 3 ); // first letter +} + +inline const SwPageDesc* SwCSS1Parser::GetFirstPageDesc( sal_Bool bCreate ) +{ + return GetPageDesc( RES_POOLPAGE_FIRST, bCreate ); +} + +inline const SwPageDesc* SwCSS1Parser::GetRightPageDesc( sal_Bool bCreate ) +{ + return GetPageDesc( RES_POOLPAGE_RIGHT, bCreate ); +} + +inline const SwPageDesc* SwCSS1Parser::GetLeftPageDesc( sal_Bool bCreate ) +{ + return GetPageDesc( RES_POOLPAGE_LEFT, bCreate ); +} + +inline void SwCSS1Parser::SetTHTagStyles() +{ + if( !bTableHeaderTxtCollSet ) + SetTableTxtColl( sal_True ); +} + +inline void SwCSS1Parser::SetTDTagStyles() +{ + if( !bTableTxtCollSet ) + SetTableTxtColl( sal_False ); +} + + +inline void SwCSS1Parser::SetATagStyles() +{ + if( !bLinkCharFmtsSet ) + SetLinkCharFmts(); +} + +inline void SwCSS1Parser::SetDelayedStyles() +{ + SetTHTagStyles(); + SetTDTagStyles(); + SetATagStyles(); +} + + +#endif + + diff --git a/sw/source/filter/html/swhtml.cxx b/sw/source/filter/html/swhtml.cxx new file mode 100644 index 000000000000..b9c8b63d60f7 --- /dev/null +++ b/sw/source/filter/html/swhtml.cxx @@ -0,0 +1,5523 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> +#include <com/sun/star/document/XDocumentProperties.hpp> +#include <com/sun/star/i18n/ScriptType.hpp> +#include <sfx2/sfx.hrc> +#include <svx/svxids.hrc> +#ifdef DBG_UTIL +#include <stdlib.h> +#endif +#include <hintids.hxx> + +#define _SVSTDARR_STRINGS +#include <svl/svstdarr.hxx> +#include <svl/stritem.hxx> +#include <svtools/imap.hxx> +#include <svtools/htmltokn.h> +#include <svtools/htmlkywd.hxx> +#include <svtools/ctrltool.hxx> +#include <unotools/pathoptions.hxx> +#include <vcl/svapp.hxx> +#include <vcl/wrkwin.hxx> +#include <sfx2/fcontnr.hxx> +#include <sfx2/docfile.hxx> + +#include <svtools/htmlcfg.hxx> +#include <sfx2/linkmgr.hxx> +#include <editeng/kernitem.hxx> +#include <editeng/boxitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/brkitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/crsditem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/escpitem.hxx> +#include <editeng/blnkitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/adjitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/protitem.hxx> +#include <editeng/flstitem.hxx> + + +#include <frmatr.hxx> +#include <charatr.hxx> +#include <fmtfld.hxx> +#include <fmtpdsc.hxx> +#include <txtfld.hxx> +#include <fmtanchr.hxx> +#include <fmtsrnd.hxx> +#include <fmtfsize.hxx> +#include <fmtclds.hxx> +#include <fchrfmt.hxx> +#include <fmtinfmt.hxx> +#include <docary.hxx> +#include <docstat.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <pam.hxx> +#include <ndtxt.hxx> +#include <mdiexp.hxx> // ...Percent() +#include <expfld.hxx> +#include <poolfmt.hxx> +#include <pagedesc.hxx> +#include <IMark.hxx> // fuer SwBookmark ... +#include <docsh.hxx> +#include <editsh.hxx> // fuer Start/EndAction +#include <docufld.hxx> +#include <swcss1.hxx> +#include <htmlvsh.hxx> +#include <fltini.hxx> +#include <htmltbl.hxx> +#include <htmlnum.hxx> +#include <swhtml.hxx> +#include <linkenum.hxx> +#include <breakit.hxx> +#include <SwAppletImpl.hxx> + +#include <sfx2/viewfrm.hxx> + +#include <statstr.hrc> // ResId fuer Statusleiste +#include <swerror.h> + +#define FONTSIZE_MASK 7 +#define FONTCOLOR_MASK (1<<15) +#define FONT_MASK (1<<14) + +#define HTML_ESC_PROP 80 +#define HTML_ESC_SUPER DFLT_ESC_SUPER +#define HTML_ESC_SUB DFLT_ESC_SUB + +#define HTML_SPTYPE_NONE 0 +#define HTML_SPTYPE_BLOCK 1 +#define HTML_SPTYPE_HORI 2 +#define HTML_SPTYPE_VERT 3 + +#ifndef TOOLS_CONSTASCII_STRINGPARAM +#define TOOLS_CONSTASCII_STRINGPARAM( constAsciiStr ) constAsciiStr, sizeof( constAsciiStr )-1 +#endif + +using namespace ::com::sun::star; + +// <P ALIGN=xxx>, <Hn ALIGN=xxx>, <TD ALIGN=xxx> usw. +HTMLOptionEnum __FAR_DATA aHTMLPAlignTable[] = +{ + { OOO_STRING_SVTOOLS_HTML_AL_left, SVX_ADJUST_LEFT }, + { OOO_STRING_SVTOOLS_HTML_AL_center, SVX_ADJUST_CENTER }, + { OOO_STRING_SVTOOLS_HTML_AL_middle, SVX_ADJUST_CENTER }, // Netscape + { OOO_STRING_SVTOOLS_HTML_AL_right, SVX_ADJUST_RIGHT }, + { OOO_STRING_SVTOOLS_HTML_AL_justify, SVX_ADJUST_BLOCK }, + { OOO_STRING_SVTOOLS_HTML_AL_char, SVX_ADJUST_LEFT }, + { 0, 0 } +}; + +// <SPACER TYPE=...> +static HTMLOptionEnum __FAR_DATA aHTMLSpacerTypeTable[] = +{ + { OOO_STRING_SVTOOLS_HTML_SPTYPE_block, HTML_SPTYPE_BLOCK }, + { OOO_STRING_SVTOOLS_HTML_SPTYPE_horizontal, HTML_SPTYPE_HORI }, + { OOO_STRING_SVTOOLS_HTML_SPTYPE_vertical, HTML_SPTYPE_VERT }, + { 0, 0 } +}; + +SV_IMPL_PTRARR( _HTMLAttrs, _HTMLAttrPtr ) + +HTMLReader::HTMLReader() +{ + bTmplBrowseMode = sal_True; +} + +String HTMLReader::GetTemplateName() const +{ + String sTemplate( + String::CreateFromAscii(TOOLS_CONSTASCII_STRINGPARAM("internal")) ); + sTemplate += INET_PATH_TOKEN; + sTemplate.AppendAscii( TOOLS_CONSTASCII_STRINGPARAM("html") ); + String sTemplateWithoutExt( sTemplate ); +#ifndef MAC_WITHOUT_EXT + // --> OD 2005-01-26 - first search for OpenDocument Writer/Web template + sTemplate.AppendAscii( TOOLS_CONSTASCII_STRINGPARAM(".oth") ); + // <-- +#endif + + SvtPathOptions aPathOpt; + // OpenDocument Writer/Web template (extension .oth) + sal_Bool bSet = aPathOpt.SearchFile( sTemplate, SvtPathOptions::PATH_TEMPLATE ); + +#ifndef MAC_WITHOUT_EXT + if( !bSet ) + { + // 6.0 (extension .stw) + sTemplate = sTemplateWithoutExt; + // --> OD 2005-01-26 - no OpenDocument Writer/Web template found. + // search for OpenOffice.org Writer/Web template + sTemplate.AppendAscii( TOOLS_CONSTASCII_STRINGPARAM(".stw") ); + // <-- + bSet = aPathOpt.SearchFile( sTemplate, SvtPathOptions::PATH_TEMPLATE ); + } +#endif + + if( !bSet ) + { + sTemplate.Erase(); + ASSERT( !this, + "Die html.vor befindet sich nicht mehr im definierten Directory!"); + } + + return sTemplate; +} + +int HTMLReader::SetStrmStgPtr() +{ + ASSERT( pMedium, "Wo ist das Medium??" ); + + if( pMedium->IsRemote() || !pMedium->IsStorage() ) + { + pStrm = pMedium->GetInStream(); + return sal_True; + } + return sal_False; + +} + + // Aufruf fuer die allg. Reader-Schnittstelle +sal_uLong HTMLReader::Read( SwDoc &rDoc, const String& rBaseURL, SwPaM &rPam, const String & rName ) +{ + if( !pStrm ) + { + ASSERT( pStrm, "HTML-Read ohne Stream" ); + return ERR_SWG_READ_ERROR; + } + + if( !bInsertMode ) + { + Reader::SetNoOutlineNum( rDoc ); + Reader::ResetFrmFmts( rDoc ); + + // Die HTML-Seitenvorlage setzen, wenn des kein HTML-Dokument ist, + // sonst ist sie schon gesetzt. + if( !rDoc.get(IDocumentSettingAccess::HTML_MODE) ) + { + rDoc.InsertPoolItem( rPam, SwFmtPageDesc( + rDoc.GetPageDescFromPool( RES_POOLPAGE_HTML, false )), 0 ); + } + } + + // damit keiner das Doc klaut! + rDoc.acquire(); + sal_uLong nRet = 0; + SvParserRef xParser = new SwHTMLParser( &rDoc, rPam, *pStrm, + rName, rBaseURL, !bInsertMode, pMedium, + IsReadUTF8(), + bIgnoreHTMLComments ); + + SvParserState eState = xParser->CallParser(); + + if( SVPAR_PENDING == eState ) + pStrm->ResetError(); + else if( SVPAR_ACCEPTED != eState ) + { + String sErr( String::CreateFromInt32((sal_Int32)xParser->GetLineNr())); + sErr += ','; + sErr += String::CreateFromInt32((sal_Int32)xParser->GetLinePos()); + + // den Stream als Fehlernummer Transporter benutzen + nRet = *new StringErrorInfo( ERR_FORMAT_ROWCOL, sErr, + ERRCODE_BUTTON_OK | ERRCODE_MSG_ERROR ); + } + + + return nRet; +} + + +/* */ + +SwHTMLParser::SwHTMLParser( SwDoc* pD, const SwPaM& rCrsr, SvStream& rIn, + const String& rPath, + const String& rBaseURL, + int bReadNewDoc, + SfxMedium* pMed, sal_Bool bReadUTF8, + sal_Bool bNoHTMLComments ) + : SfxHTMLParser( rIn, static_cast< sal_Bool >(bReadNewDoc), pMed ), + SwClient( 0 ), + aPathToFile( rPath ), + sBaseURL( rBaseURL ), + pAppletImpl( 0 ), + pCSS1Parser( 0 ), + pNumRuleInfo( new SwHTMLNumRuleInfo ), + pPendStack( 0 ), + pDoc( pD ), + pActionViewShell( 0 ), + pSttNdIdx( 0 ), + pTable(0), + pFormImpl( 0 ), + pMarquee( 0 ), + pField( 0 ), + pImageMap( 0 ), + pImageMaps( 0 ), + pFootEndNoteImpl( 0 ), + nScriptStartLineNr( 0 ), + nBaseFontStMin( 0 ), + nFontStMin( 0 ), + nDefListDeep( 0 ), + nFontStHeadStart( 0 ), + nSBModuleCnt( 0 ), + nMissingImgMaps( 0 ), + nParaCnt( 5 ), + // --> OD 2007-10-26 #i83625# + nContextStMin( 0 ), + nContextStAttrMin( 0 ), + // <-- + nOpenParaToken( 0 ), + eJumpTo( JUMPTO_NONE ), +#ifdef DBG_UTIL + nContinue( 0 ), +#endif + eParaAdjust( SVX_ADJUST_END ), + bDocInitalized( sal_False ), + bSetModEnabled( sal_False ), + bInFloatingFrame( sal_False ), + bInField( sal_False ), + bCallNextToken( sal_False ), + bIgnoreRawData( sal_False ), + bNoParSpace( sal_False ), + bInNoEmbed( sal_False ), + bInTitle( sal_False ), + bUpdateDocStat( sal_False ), + bFixSelectWidth( sal_False ), + bFixSelectHeight( sal_False ), + bTextArea( sal_False ), + bSelect( sal_False ), + bInFootEndNoteAnchor( sal_False ), + bInFootEndNoteSymbol( sal_False ), +// bIgnoreHTMLComments( bNoHTMLComments ) + bIgnoreHTMLComments( bNoHTMLComments ), + bRemoveHidden( sal_False ), + pTempViewFrame(0) +{ + nEventId = 0; + bUpperSpace = bViewCreated = bChkJumpMark = + bSetCrsr = sal_False; + + eScriptLang = HTML_SL_UNKNOWN; + bAnyStarBasic = sal_True; + + pPam = new SwPaM( *rCrsr.GetPoint() ); + memset( &aAttrTab, 0, sizeof( _HTMLAttrTable )); + + // Die Font-Groessen 1-7 aus der INI-Datei lesen + SvxHtmlOptions* pHtmlOptions = SvxHtmlOptions::Get(); + aFontHeights[0] = pHtmlOptions->GetFontSize( 0 ) * 20; + aFontHeights[1] = pHtmlOptions->GetFontSize( 1 ) * 20; + aFontHeights[2] = pHtmlOptions->GetFontSize( 2 ) * 20; + aFontHeights[3] = pHtmlOptions->GetFontSize( 3 ) * 20; + aFontHeights[4] = pHtmlOptions->GetFontSize( 4 ) * 20; + aFontHeights[5] = pHtmlOptions->GetFontSize( 5 ) * 20; + aFontHeights[6] = pHtmlOptions->GetFontSize( 6 ) * 20; + + bKeepUnknown = pHtmlOptions->IsImportUnknown(); + + if(bReadNewDoc) + { + SvxFontHeightItem aFontHeight(aFontHeights[2], 100, RES_CHRATR_FONTSIZE); + pDoc->SetDefault( aFontHeight ); + aFontHeight.SetWhich( RES_CHRATR_CJK_FONTSIZE ); + pDoc->SetDefault( aFontHeight ); + aFontHeight.SetWhich( RES_CHRATR_CTL_FONTSIZE ); + pDoc->SetDefault( aFontHeight ); + } + + // Waehrend des Imports in den HTML-Modus schalten, damit die + // richrigen Vorlagen angelegt werden + bOldIsHTMLMode = pDoc->get(IDocumentSettingAccess::HTML_MODE); + pDoc->set(IDocumentSettingAccess::HTML_MODE, true); + + pCSS1Parser = new SwCSS1Parser( pDoc, aFontHeights, sBaseURL, IsNewDoc() ); + pCSS1Parser->SetIgnoreFontFamily( pHtmlOptions->IsIgnoreFontFamily() ); + + if( bReadUTF8 ) + { + SetSrcEncoding( RTL_TEXTENCODING_UTF8 ); + } + else + { + SwDocShell *pDocSh = pDoc->GetDocShell(); + SvKeyValueIterator *pHeaderAttrs = + pDocSh->GetHeaderAttributes(); + if( pHeaderAttrs ) + SetEncodingByHTTPHeader( pHeaderAttrs ); + } + pCSS1Parser->SetDfltEncoding( gsl_getSystemTextEncoding() ); + + // Timer nur bei ganz normalen Dokumenten aufsetzen! + SwDocShell* pDocSh = pDoc->GetDocShell(); + if( pDocSh ) + { + bViewCreated = sal_True; // nicht, synchron laden + + // es ist ein Sprungziel vorgegeben. + + if( pMed ) + { + sJmpMark = pMed->GetURLObject().GetMark(); + if( sJmpMark.Len() ) + { + eJumpTo = JUMPTO_MARK; + String sCmp; + xub_StrLen nLastPos, nPos = 0; + while( STRING_NOTFOUND != ( nLastPos = + sJmpMark.Search( cMarkSeperator, nPos + 1 )) ) + nPos = nLastPos; + + if( nPos && ( sCmp = sJmpMark.Copy( nPos + 1 ) ). + EraseAllChars().Len() ) + { + sCmp.ToLowerAscii(); + if( sCmp.EqualsAscii( pMarkToRegion ) ) + eJumpTo = JUMPTO_REGION; + else if( sCmp.EqualsAscii( pMarkToTable ) ) + eJumpTo = JUMPTO_TABLE; + else if( sCmp.EqualsAscii( pMarkToGraphic ) ) + eJumpTo = JUMPTO_GRAPHIC; + else if( sCmp.EqualsAscii( pMarkToOutline ) || + sCmp.EqualsAscii( pMarkToText ) || + sCmp.EqualsAscii( pMarkToFrame ) ) + eJumpTo = JUMPTO_NONE; // das ist nichts gueltiges! + else + // ansonsten ist das ein normaler (Book)Mark + nPos = STRING_LEN; + } + else + nPos = STRING_LEN; + + sJmpMark.Erase( nPos ); + if( !sJmpMark.Len() ) + eJumpTo = JUMPTO_NONE; + } + } + } +} + +__EXPORT SwHTMLParser::~SwHTMLParser() +{ +#ifdef DBG_UTIL + ASSERT( !nContinue, "DTOR im Continue - Das geht schief!!!" ); +#endif + sal_Bool bAsync = pDoc->IsInLoadAsynchron(); + pDoc->SetInLoadAsynchron( sal_False ); + pDoc->set(IDocumentSettingAccess::HTML_MODE, bOldIsHTMLMode); + + if( pDoc->GetDocShell() && nEventId ) + Application::RemoveUserEvent( nEventId ); + + // das DocumentDetected kann ggfs. die DocShells loeschen, darum nochmals + // abfragen + if( pDoc->GetDocShell() ) + { + // Gelinkte Bereiche updaten + sal_uInt16 nLinkMode = pDoc->getLinkUpdateMode( true ); + if( nLinkMode != NEVER && bAsync && + SFX_CREATE_MODE_INTERNAL!=pDoc->GetDocShell()->GetCreateMode() ) + pDoc->GetLinkManager().UpdateAllLinks( nLinkMode == MANUAL, + sal_True, sal_False ); + + if ( pDoc->GetDocShell()->IsLoading() ) + { + // --> OD 2006-11-07 #i59688# + pDoc->GetDocShell()->LoadingFinished(); + } + } + + delete pSttNdIdx; + + if( aSetAttrTab.Count() ) + { + ASSERT( !aSetAttrTab.Count(),"Es stehen noch Attribute auf dem Stack" ); + aSetAttrTab.DeleteAndDestroy( 0, aSetAttrTab.Count() ); + } + + delete pPam; + delete pCSS1Parser; + delete pNumRuleInfo; + DeleteFormImpl(); + DeleteFootEndNoteImpl(); + + ASSERT( !pTable, "Es existiert noch eine offene Tabelle" ); + delete pImageMaps; + //delete pTable; + + ASSERT( !pPendStack, + "SwHTMLParser::~SwHTMLParser: Hier sollte es keinen Pending-Stack mehr geben" ); + while( pPendStack ) + { + SwPendingStack* pTmp = pPendStack; + pPendStack = pPendStack->pNext; + delete pTmp->pData; + delete pTmp; + } + + if( !pDoc->release() ) + { + // keiner will mehr das Doc haben, also weg damit + delete pDoc; + pDoc = NULL; + } + + if ( pTempViewFrame ) + { + pTempViewFrame->DoClose(); + + // the temporary view frame is hidden, so the hidden flag might need to be removed + if ( bRemoveHidden && pDoc && pDoc->GetDocShell() && pDoc->GetDocShell()->GetMedium() ) + pDoc->GetDocShell()->GetMedium()->GetItemSet()->ClearItem( SID_HIDDEN ); + } +} + +IMPL_LINK( SwHTMLParser, AsyncCallback, void*, /*pVoid*/ ) +{ + nEventId=0; + + // --> FME 2005-08-18 #i47907# If the document has already been destructed, + // the parser should be aware of this: + if( ( pDoc->GetDocShell() && pDoc->GetDocShell()->IsAbortingImport() ) + || 1 == pDoc->getReferenceCount() ) + { + // wurde der Import vom SFX abgebrochen? + eState = SVPAR_ERROR; + } + // <-- + + GetAsynchCallLink().Call(0); + return 0; +} + +SvParserState __EXPORT SwHTMLParser::CallParser() +{ + // einen temporaeren Index anlegen, auf Pos 0 so wird er nicht bewegt! + pSttNdIdx = new SwNodeIndex( pDoc->GetNodes() ); + if( !IsNewDoc() ) // in ein Dokument einfuegen ? + { + const SwPosition* pPos = pPam->GetPoint(); + + pDoc->SplitNode( *pPos, false ); + + *pSttNdIdx = pPos->nNode.GetIndex()-1; + pDoc->SplitNode( *pPos, false ); + + SwPaM aInsertionRangePam( *pPos ); + + pPam->Move( fnMoveBackward ); + + // #106634# split any redline over the insertion point + aInsertionRangePam.SetMark(); + *aInsertionRangePam.GetPoint() = *pPam->GetPoint(); + aInsertionRangePam.Move( fnMoveBackward ); + pDoc->SplitRedline( aInsertionRangePam ); + + pDoc->SetTxtFmtColl( *pPam, + pCSS1Parser->GetTxtCollFromPool( RES_POOLCOLL_STANDARD )); + } + + if( GetMedium() ) + { + if( !bViewCreated ) + { + nEventId = Application::PostUserEvent( LINK( this, SwHTMLParser, AsyncCallback ), 0 ); + } + else + { + bViewCreated = sal_True; + nEventId = 0; + } + } + + // Laufbalken anzeigen + else if( !GetMedium() || !GetMedium()->IsRemote() ) + { + rInput.Seek(STREAM_SEEK_TO_END); + rInput.ResetError(); + ::StartProgress( STR_STATSTR_W4WREAD, 0, rInput.Tell(), + pDoc->GetDocShell() ); + rInput.Seek(STREAM_SEEK_TO_BEGIN); + rInput.ResetError(); + } + + SwPageDesc& rDesc = pDoc->_GetPageDesc( 0 ); + rDesc.Add( this ); + + SvParserState eRet = HTMLParser::CallParser(); + return eRet; +} + +void __EXPORT SwHTMLParser::Continue( int nToken ) +{ +#ifdef DBG_UTIL + ASSERT( !nContinue, "Continue im Continue - Das sollte doch nicht sein, oder?" ); + nContinue++; +#endif + + // Wenn der Import (vom SFX) abgebrochen wurde, wird ein Fehler + // gesetzt aber trotzdem noch weiter gemacht, damit vernuenftig + // aufgeraeumt wird. + ASSERT( SVPAR_ERROR!=eState, + "SwHTMLParser::Continue: bereits ein Fehler gesetzt" ); + if( pDoc->GetDocShell() && pDoc->GetDocShell()->IsAbortingImport() ) + eState = SVPAR_ERROR; + + // Die ViewShell vom Dokument holen, merken und als aktuelle setzen. + ViewShell *pInitVSh = CallStartAction(); + + if( SVPAR_ERROR != eState && GetMedium() && !bViewCreated ) + { + // Beim ersten Aufruf erstmal returnen, Doc anzeigen + // und auf Timer Callback warten. + // An dieser Stelle wurde im CallParser gerade mal ein Zeichen + // gelesen und ein SaveState(0) gerufen. + eState = SVPAR_PENDING; + bViewCreated = sal_True; + pDoc->SetInLoadAsynchron( sal_True ); + +#ifdef DBG_UTIL + nContinue--; +#endif + + return; + } + + bSetModEnabled = sal_False; + if( pDoc->GetDocShell() && + 0 != (bSetModEnabled = pDoc->GetDocShell()->IsEnableSetModified()) ) + { + pDoc->GetDocShell()->EnableSetModified( sal_False ); + } + + // waehrend des einlesens kein OLE-Modified rufen + Link aOLELink( pDoc->GetOle2Link() ); + pDoc->SetOle2Link( Link() ); + + sal_Bool bModified = pDoc->IsModified(); + bool const bWasUndo = pDoc->GetIDocumentUndoRedo().DoesUndo(); + pDoc->GetIDocumentUndoRedo().DoUndo(false); + + // Wenn der Import abgebrochen wird, kein Continue mehr rufen. + // Falls ein Pending-Stack existiert aber durch einen Aufruf + // von NextToken dafuer sorgen, dass der Pending-Stack noch + // beendet wird. + if( SVPAR_ERROR == eState ) + { + ASSERT( !pPendStack || pPendStack->nToken, + "SwHTMLParser::Continue: Pending-Stack ohne Token" ); + if( pPendStack && pPendStack->nToken ) + NextToken( pPendStack->nToken ); + ASSERT( !pPendStack, + "SwHTMLParser::Continue: Es gibt wieder einen Pend-Stack" ); + } + else + { + HTMLParser::Continue( pPendStack ? pPendStack->nToken : nToken ); + } + + // Laufbalken wieder abschalten + EndProgress( pDoc->GetDocShell() ); + + sal_Bool bLFStripped = sal_False; + if( SVPAR_PENDING != GetStatus() ) + { + // noch die letzten Attribute setzen + { + if( aScriptSource.Len() ) + { + SwScriptFieldType *pType = + (SwScriptFieldType*)pDoc->GetSysFldType( RES_SCRIPTFLD ); + + SwScriptField aFld( pType, aScriptType, aScriptSource, + sal_False ); + InsertAttr( SwFmtFld( aFld ) ); + } + + if( pAppletImpl ) + { + if( pAppletImpl->GetApplet().is() ) + EndApplet(); + else + EndObject(); + } + + // ggf. ein noch vorhandes LF hinter dem letzen Absatz entfernen + if( IsNewDoc() ) + bLFStripped = StripTrailingLF() > 0; + + // noch offene Nummerierungen beenden. + while( GetNumInfo().GetNumRule() ) + EndNumBulList(); + + ASSERT( !nContextStMin, "Es gibt geschuetzte Kontexte" ); + nContextStMin = 0; + while( aContexts.Count() ) + { + _HTMLAttrContext *pCntxt = PopContext(); + if( pCntxt ) + { + EndContext( pCntxt ); + delete pCntxt; + } + } + + if( aParaAttrs.Count() ) + aParaAttrs.Remove( 0, aParaAttrs.Count() ); + + SetAttr( sal_False ); + + // Noch die erst verzoegert gesetzten Styles setzen + pCSS1Parser->SetDelayedStyles(); + } + + // den Start wieder korrigieren + if( !IsNewDoc() && pSttNdIdx->GetIndex() ) + { + SwTxtNode* pTxtNode = pSttNdIdx->GetNode().GetTxtNode(); + SwNodeIndex aNxtIdx( *pSttNdIdx ); + if( pTxtNode && pTxtNode->CanJoinNext( &aNxtIdx )) + { + xub_StrLen nStt = pTxtNode->GetTxt().Len(); + // wenn der Cursor noch in dem Node steht, dann setze in an das Ende + if( pPam->GetPoint()->nNode == aNxtIdx ) + { + pPam->GetPoint()->nNode = *pSttNdIdx; + pPam->GetPoint()->nContent.Assign( pTxtNode, nStt ); + } + +#ifdef DBG_UTIL +// !!! sollte nicht moeglich sein, oder ?? +ASSERT( pSttNdIdx->GetIndex()+1 != pPam->GetBound( sal_True ).nNode.GetIndex(), + "Pam.Bound1 steht noch im Node" ); +ASSERT( pSttNdIdx->GetIndex()+1 != pPam->GetBound( sal_False ).nNode.GetIndex(), + "Pam.Bound2 steht noch im Node" ); + +if( pSttNdIdx->GetIndex()+1 == pPam->GetBound( sal_True ).nNode.GetIndex() ) +{ + xub_StrLen nCntPos = pPam->GetBound( sal_True ).nContent.GetIndex(); + pPam->GetBound( sal_True ).nContent.Assign( pTxtNode, + pTxtNode->GetTxt().Len() + nCntPos ); +} +if( pSttNdIdx->GetIndex()+1 == pPam->GetBound( sal_False ).nNode.GetIndex() ) +{ + xub_StrLen nCntPos = pPam->GetBound( sal_False ).nContent.GetIndex(); + pPam->GetBound( sal_False ).nContent.Assign( pTxtNode, + pTxtNode->GetTxt().Len() + nCntPos ); +} +#endif + // Zeichen Attribute beibehalten! + SwTxtNode* pDelNd = aNxtIdx.GetNode().GetTxtNode(); + if( pTxtNode->GetTxt().Len() ) + pDelNd->FmtToTxtAttr( pTxtNode ); + else + pTxtNode->ChgFmtColl( pDelNd->GetTxtColl() ); + pTxtNode->JoinNext(); + } + } + } + + if( SVPAR_ACCEPTED == eState ) + { + if( nMissingImgMaps ) + { + // es fehlen noch ein paar Image-Map zuordungen. + // vielleicht sind die Image-Maps ja jetzt da? + ConnectImageMaps(); + } + + // jetzt noch den letzten ueberfluessigen Absatz loeschen + SwPosition* pPos = pPam->GetPoint(); + if( !pPos->nContent.GetIndex() && !bLFStripped ) + { + SwTxtNode* pAktNd; + sal_uLong nNodeIdx = pPos->nNode.GetIndex(); + + sal_Bool bHasFlysOrMarks = + HasCurrentParaFlys() || HasCurrentParaBookmarks( sal_True ); + + if( IsNewDoc() ) + { + const SwNode *pPrev = pDoc->GetNodes()[nNodeIdx -1]; + if( !pPam->GetPoint()->nContent.GetIndex() && + ( pPrev->IsCntntNode() || + (pPrev->IsEndNode() && + pPrev->StartOfSectionNode()->IsSectionNode()) ) ) + { + SwCntntNode* pCNd = pPam->GetCntntNode(); + if( pCNd && pCNd->StartOfSectionIndex()+2 < + pCNd->EndOfSectionIndex() && !bHasFlysOrMarks ) + { + ViewShell *pVSh = CheckActionViewShell(); + SwCrsrShell *pCrsrSh = pVSh && pVSh->ISA(SwCrsrShell) + ? static_cast < SwCrsrShell * >( pVSh ) + : 0; + if( pCrsrSh && + pCrsrSh->GetCrsr()->GetPoint() + ->nNode.GetIndex() == nNodeIdx ) + { + pCrsrSh->MovePara(fnParaPrev, fnParaEnd ); + pCrsrSh->SetMark(); + pCrsrSh->ClearMark(); + } + pPam->GetBound(sal_True).nContent.Assign( 0, 0 ); + pPam->GetBound(sal_False).nContent.Assign( 0, 0 ); + pDoc->GetNodes().Delete( pPam->GetPoint()->nNode ); + } + } + } + else if( 0 != ( pAktNd = pDoc->GetNodes()[ nNodeIdx ]->GetTxtNode()) && !bHasFlysOrMarks ) + { + if( pAktNd->CanJoinNext( &pPos->nNode )) + { + SwTxtNode* pNextNd = pPos->nNode.GetNode().GetTxtNode(); + pPos->nContent.Assign( pNextNd, 0 ); + pPam->SetMark(); pPam->DeleteMark(); + pNextNd->JoinPrev(); + } + else if( !pAktNd->GetTxt().Len() ) + { + pPos->nContent.Assign( 0, 0 ); + pPam->SetMark(); pPam->DeleteMark(); + pDoc->GetNodes().Delete( pPos->nNode, 1 ); + pPam->Move( fnMoveBackward ); + } + } + } + + // nun noch das SplitNode vom Anfang aufheben + else if( !IsNewDoc() ) + { + if( pPos->nContent.GetIndex() ) // dann gabs am Ende kein <P>, + pPam->Move( fnMoveForward, fnGoNode ); // als zum naechsten Node + SwTxtNode* pTxtNode = pPos->nNode.GetNode().GetTxtNode(); + SwNodeIndex aPrvIdx( pPos->nNode ); + if( pTxtNode && pTxtNode->CanJoinPrev( &aPrvIdx ) && + *pSttNdIdx <= aPrvIdx ) + { + // eigentlich muss hier ein JoinNext erfolgen, aber alle Cursor + // usw. sind im pTxtNode angemeldet, so dass der bestehen + // bleiben MUSS. + + // Absatz in Zeichen-Attribute umwandeln, aus dem Prev die + // Absatzattribute und die Vorlage uebernehmen! + SwTxtNode* pPrev = aPrvIdx.GetNode().GetTxtNode(); + pTxtNode->ChgFmtColl( pPrev->GetTxtColl() ); + pTxtNode->FmtToTxtAttr( pPrev ); + pTxtNode->ResetAllAttr(); + + if( pPrev->HasSwAttrSet() ) + pTxtNode->SetAttr( *pPrev->GetpSwAttrSet() ); + + if( &pPam->GetBound(sal_True).nNode.GetNode() == pPrev ) + pPam->GetBound(sal_True).nContent.Assign( pTxtNode, 0 ); + if( &pPam->GetBound(sal_False).nNode.GetNode() == pPrev ) + pPam->GetBound(sal_False).nContent.Assign( pTxtNode, 0 ); + + pTxtNode->JoinPrev(); + } + } + + // und noch die DocumentInfo aufbereiten + if( IsNewDoc() ) + { + SwDocShell *pDocShell(pDoc->GetDocShell()); + DBG_ASSERT(pDocShell, "no SwDocShell"); + if (pDocShell) { + uno::Reference<document::XDocumentPropertiesSupplier> xDPS( + pDocShell->GetModel(), uno::UNO_QUERY_THROW); + uno::Reference<document::XDocumentProperties> xDocProps( + xDPS->getDocumentProperties()); + DBG_ASSERT(xDocProps.is(), "DocumentProperties is null"); + if ( xDocProps.is() && (xDocProps->getAutoloadSecs() > 0) && + xDocProps->getAutoloadURL().equalsAscii("") ) + { + xDocProps->setAutoloadURL(aPathToFile); + } + } + } + + if( bUpdateDocStat ) + { + SwDocStat aStat( pDoc->GetDocStat() ); + pDoc->UpdateDocStat( aStat ); + } + } + + if( SVPAR_PENDING != GetStatus() ) + delete pSttNdIdx, pSttNdIdx = 0; + + // sollte der Parser der Letzte sein, der das Doc haelt, dann braucht + // man hier auch nichts mehr tun, Doc wird gleich zerstoert! + if( 1 < pDoc->getReferenceCount() ) + { + if( bWasUndo ) + { + pDoc->GetIDocumentUndoRedo().DelAllUndoObj(); + pDoc->GetIDocumentUndoRedo().DoUndo(true); + } + else if( !pInitVSh ) + { + // Wenn zu Beginn des Continue keine Shell vorhanden war, + // kann trotzdem mitlerweile eine angelegt worden sein. + // In dieses Fall stimmt das bWasUndo-Flag nicht und + // wir muessen das Undo noch anschalten. + ViewShell *pTmpVSh = CheckActionViewShell(); + if( pTmpVSh ) + { + pDoc->GetIDocumentUndoRedo().DoUndo(true); + } + } + + pDoc->SetOle2Link( aOLELink ); + if( !bModified ) + pDoc->ResetModified(); + if( bSetModEnabled && pDoc->GetDocShell() ) + { + pDoc->GetDocShell()->EnableSetModified( sal_True ); + bSetModEnabled = sal_False; // this is unnecessary here + } + } + + + // Wenn die Dokuemnt-ViewShell noch existiert und eine Action + // offen ist (muss bei Abbruch nicht sein), die Action beenden, + // uns von der Shell abmelden und schliesslich die alte Shell + // wieder rekonstruieren. + CallEndAction( sal_True ); + +#ifdef DBG_UTIL + nContinue--; +#endif +} + +void SwHTMLParser::Modify( SfxPoolItem *pOld, SfxPoolItem *pNew ) +{ + switch( pOld ? pOld->Which() : pNew ? pNew->Which() : 0 ) + { + case RES_OBJECTDYING: + if( ((SwPtrMsgPoolItem *)pOld)->pObject == pRegisteredIn ) + { + // dann uns selbst beenden + pRegisteredIn->Remove( this ); + ReleaseRef(); // ansonsten sind wir fertig! + } + break; + } +} + +void SwHTMLParser::DocumentDetected() +{ + ASSERT( !bDocInitalized, "DocumentDetected mehrfach aufgerufen" ); + bDocInitalized = sal_True; + if( IsNewDoc() ) + { + if( IsInHeader() ) + FinishHeader( sal_True ); + + CallEndAction( sal_True, sal_True ); + + pDoc->GetIDocumentUndoRedo().DoUndo(false); + // Durch das DocumentDetected wurde im allgemeinen eine + // ViewShell angelegt. Es kann aber auch sein, dass sie + // erst spaeter angelegt wird, naemlich dann, wenn die UI + // gecaptured ist. + CallStartAction(); + } +} + +// wird fuer jedes Token gerufen, das in CallParser erkannt wird +void __EXPORT SwHTMLParser::NextToken( int nToken ) +{ + if( ( pDoc->GetDocShell() && pDoc->GetDocShell()->IsAbortingImport() ) + || 1 == pDoc->getReferenceCount() ) + { + // wurde der Import vom SFX abgebrochen? Wenn ein Pending-Stack + // existiert den noch aufraumen + eState = SVPAR_ERROR; + ASSERT( !pPendStack || pPendStack->nToken, + "SwHTMLParser::NextToken: Pending-Stack ohne Token" ); + if( 1 == pDoc->getReferenceCount() || !pPendStack ) + return ; + } + +#ifdef DBG_UTIL + if( pPendStack ) + { + switch( nToken ) + { + // Tabellen werden ueber rekusive Methodenaufrufe gelesen + case HTML_TABLE_ON: + // Bei CSS-Deklarationen muss evtl. noch auf das + // Ende eines File-Downloads gewartet werden. + case HTML_LINK: + // Bei Controls muss evtl. noch die Groesse gesetzt werden. + case HTML_INPUT: + case HTML_TEXTAREA_ON: + case HTML_SELECT_ON: + case HTML_SELECT_OFF: + break; + default: + ASSERT( !pPendStack, "Unbekanntes Token fuer Pending-Stack" ); + break; + } + } +#endif + + // Die folgeneden Spezialfaelle muessen vor der Filter-Detection behandelt + // werden, denn der Inhalt des Titels, etc. wird auch in Netcape nicht + // zur Filter-Detection herangezogen. + if( !pPendStack ) + { + if( bInTitle ) + { + switch( nToken ) + { + case HTML_TITLE_OFF: + if( IsNewDoc() && sTitle.Len() ) + { + if( pDoc->GetDocShell() ) { + uno::Reference<document::XDocumentPropertiesSupplier> + xDPS(pDoc->GetDocShell()->GetModel(), + uno::UNO_QUERY_THROW); + uno::Reference<document::XDocumentProperties> xDocProps( + xDPS->getDocumentProperties()); + DBG_ASSERT(xDocProps.is(), "no DocumentProperties"); + if (xDocProps.is()) { + xDocProps->setTitle(sTitle); + } + + pDoc->GetDocShell()->SetTitle( sTitle ); + } + } + bInTitle = sal_False; + sTitle.Erase(); + break; + + case HTML_NONBREAKSPACE: + sTitle += ' '; + break; + + case HTML_SOFTHYPH: + sTitle += '-'; + break; + + case HTML_TEXTTOKEN: + sTitle += aToken; + break; + + default: + sTitle += '<'; + if( (HTML_TOKEN_ONOFF & nToken) && (1 & nToken) ) + sTitle += '/'; + sTitle += sSaveToken; + if( aToken.Len() ) + { + sTitle += ' '; + sTitle += aToken; + } + sTitle += '>'; + break; + } + + return; + } + } + + // Wenn wir noch nicht wissen, was fuer ein Dokument wir vor uns haben, + // versuchen wir das erstmal rauszufinden. Das muss fuer Controls in + // Fall vor dem Einfuegen des Controls passieren, weil beim Einfuegen + // bereits eine View benoetigt wird. + if( !bDocInitalized ) + DocumentDetected(); + + sal_Bool bGetIDOption = sal_False, bInsertUnknown = sal_False; + sal_Bool bUpperSpaceSave = bUpperSpace; + bUpperSpace = sal_False; + + // Die folgenden Speziallfaelle muessen oder koennen nach der + // Filter-Detection erfolgen. + if( !pPendStack ) + { + if( bInFloatingFrame ) + { + // <SCRIPT> wird hier (von uns) ignoriert, weil es auch in + // Applets ignoriert wird! + if( HTML_IFRAME_OFF == nToken ) + { + bCallNextToken = sal_False; + EndFloatingFrame(); + } + + return; + } + else if( bInNoEmbed ) + { + switch( nToken ) + { + case HTML_NOEMBED_OFF: + aContents.ConvertLineEnd(); + InsertComment( aContents, OOO_STRING_SVTOOLS_HTML_noembed ); + aContents.Erase(); + bCallNextToken = sal_False; + bInNoEmbed = sal_False; + break; + + case HTML_RAWDATA: + InsertCommentText( OOO_STRING_SVTOOLS_HTML_noembed ); + break; + + default: + ASSERT( !this, "SwHTMLParser::NextToken: ungueltiges Tag" ); + break; + } + + return; + } + else if( pAppletImpl ) + { + // in einem Applet interessieren uns (erstmal) nur <PARAM>-Tags + // und das </APPLET>. + // <SCRIPT> wird hier (von Netscape) ignoriert! + + switch( nToken ) + { + case HTML_APPLET_OFF: + bCallNextToken = sal_False; + EndApplet(); + break; + case HTML_OBJECT_OFF: + bCallNextToken = sal_False; + EndObject(); + break; + + case HTML_PARAM: + InsertParam(); + break; + } + + return; + } + else if( bTextArea ) + { + // in einer TextArea wird alles bis zum </TEXTAREA> als Text + // eingefuegt + // <SCRIPT> wird hier (von Netscape) ignoriert! + + switch( nToken ) + { + case HTML_TEXTAREA_OFF: + bCallNextToken = sal_False; + EndTextArea(); + break; + + default: + InsertTextAreaText( static_cast< sal_uInt16 >(nToken) ); + break; + } + + return; + } + else if( bSelect ) + { + // MUSS nach bNoScript kommen! + switch( nToken ) + { + case HTML_SELECT_OFF: + bCallNextToken = sal_False; + EndSelect(); + return; + + case HTML_OPTION: + InsertSelectOption(); + return; + + case HTML_TEXTTOKEN: + InsertSelectText(); + return; + + case HTML_INPUT: + case HTML_SCRIPT_ON: + case HTML_SCRIPT_OFF: + case HTML_NOSCRIPT_ON: + case HTML_NOSCRIPT_OFF: + case HTML_RAWDATA: + // im normalen switch bahandeln + break; + + default: + // ignorieren + return; + } + } + else if( pMarquee ) + { + // in einer TextArea wird alles bis zum </TEXTAREA> als Text + // eingefuegt + // Die <SCRIPT>-Tags werden vom MS-IE ignoriert, von uns das + // geasmte Script + switch( nToken ) + { + case HTML_MARQUEE_OFF: + bCallNextToken = sal_False; + EndMarquee(); + break; + + case HTML_TEXTTOKEN: + InsertMarqueeText(); + break; + } + + return; + } + else if( bInField ) + { + switch( nToken ) + { + case HTML_SDFIELD_OFF: + bCallNextToken = sal_False; + EndField(); + break; + + case HTML_TEXTTOKEN: + InsertFieldText(); + break; + } + + return; + } + else if( bInFootEndNoteAnchor || bInFootEndNoteSymbol ) + { + switch( nToken ) + { + case HTML_ANCHOR_OFF: + EndAnchor(); + bCallNextToken = sal_False; + break; + + case HTML_TEXTTOKEN: + InsertFootEndNoteText(); + break; + } + return; + } + else if( aUnknownToken.Len() ) + { + // Unbekannte Token im Header werden nur durch ein passendes + // End-Token, </HEAD> oder <BODY> wieder beendet. Darin wird Text + // ignoriert. + switch( nToken ) + { + case HTML_UNKNOWNCONTROL_OFF: + if( aUnknownToken.CompareTo(sSaveToken) != COMPARE_EQUAL ) + return; + case HTML_FRAMESET_ON: + case HTML_HEAD_OFF: + case HTML_BODY_ON: + case HTML_IMAGE: // Warum auch immer Netscape das tut. + aUnknownToken.Erase(); + break; + case HTML_TEXTTOKEN: + return; + default: + break; + } + } + } + + switch( nToken ) + { + case HTML_BODY_ON: + if( aStyleSource.Len() ) + { + pCSS1Parser->ParseStyleSheet( aStyleSource ); + aStyleSource.Erase(); + } + if( IsNewDoc() ) + { + InsertBodyOptions(); + // Falls es eine Vorlage fuer die erste oder rechte Seite gibt, + // setzen wir die hier. + const SwPageDesc *pPageDesc = 0; + if( pCSS1Parser->IsSetFirstPageDesc() ) + pPageDesc = pCSS1Parser->GetFirstPageDesc(); + else if( pCSS1Parser->IsSetRightPageDesc() ) + pPageDesc = pCSS1Parser->GetRightPageDesc(); + + if( pPageDesc ) + { + pDoc->InsertPoolItem( *pPam, SwFmtPageDesc( pPageDesc ), 0 ); + } + } + break; + + case HTML_LINK: + InsertLink(); + break; + + case HTML_BASE: + { + const HTMLOptions *pHTMLOptions = GetOptions(); + for( sal_uInt16 i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[ --i ]; + switch( pOption->GetToken() ) + { + case HTML_O_HREF: + sBaseURL = pOption->GetString(); + break; + case HTML_O_TARGET: + if( IsNewDoc() ) + { + SwDocShell *pDocShell(pDoc->GetDocShell()); + DBG_ASSERT(pDocShell, "no SwDocShell"); + if (pDocShell) { + uno::Reference<document::XDocumentPropertiesSupplier> xDPS( + pDocShell->GetModel(), uno::UNO_QUERY_THROW); + uno::Reference<document::XDocumentProperties> + xDocProps(xDPS->getDocumentProperties()); + DBG_ASSERT(xDocProps.is(),"no DocumentProperties"); + if (xDocProps.is()) { + xDocProps->setDefaultTarget( + pOption->GetString()); + } + } + } + break; + } + } + } + break; + + case HTML_META: + { + SvKeyValueIterator *pHTTPHeader = 0; + if( IsNewDoc() ) + { + SwDocShell *pDocSh = pDoc->GetDocShell(); + if( pDocSh ) + pHTTPHeader = pDocSh->GetHeaderAttributes(); + } + SwDocShell *pDocShell(pDoc->GetDocShell()); + DBG_ASSERT(pDocShell, "no SwDocShell"); + if (pDocShell) + { + uno::Reference<document::XDocumentProperties> xDocProps; + if (IsNewDoc()) + { + const uno::Reference<document::XDocumentPropertiesSupplier> + xDPS( pDocShell->GetModel(), uno::UNO_QUERY_THROW ); + xDocProps = xDPS->getDocumentProperties(); + DBG_ASSERT(xDocProps.is(), "DocumentProperties is null"); + } + ParseMetaOptions( xDocProps, pHTTPHeader ); + } + } + break; + + case HTML_TITLE_ON: + bInTitle = sal_True; + break; + + case HTML_SCRIPT_ON: + NewScript(); + break; + + case HTML_SCRIPT_OFF: + EndScript(); + break; + + case HTML_NOSCRIPT_ON: + case HTML_NOSCRIPT_OFF: + bInsertUnknown = sal_True; + break; + + case HTML_STYLE_ON: + NewStyle(); + break; + + case HTML_STYLE_OFF: + EndStyle(); + break; + + case HTML_RAWDATA: + if( !bIgnoreRawData ) + { + if( IsReadScript() ) + { + AddScriptSource(); + } + else if( IsReadStyle() ) + { + if( aStyleSource.Len() ) + aStyleSource += '\n'; + aStyleSource += aToken; + } + } + break; + + case HTML_OBJECT_ON: +#ifdef SOLAR_JAVA + NewObject(); + bCallNextToken = pAppletImpl!=0 && pTable!=0; +#endif + break; + + case HTML_APPLET_ON: +#ifdef SOLAR_JAVA + InsertApplet(); + bCallNextToken = pAppletImpl!=0 && pTable!=0; +#endif + break; + + case HTML_IFRAME_ON: + InsertFloatingFrame(); + bCallNextToken = bInFloatingFrame && pTable!=0; + break; + + case HTML_LINEBREAK: + if( !IsReadPRE() ) + { + InsertLineBreak(); + break; + } + else + bGetIDOption = sal_True; + // <BR>s in <PRE> aehneln echten LFs, deshalb kein break + + case HTML_NEWPARA: + // CR in PRE/LISTING/XMP + { + if( HTML_NEWPARA==nToken || + pPam->GetPoint()->nContent.GetIndex() ) + { + AppendTxtNode(); // lf gibts hier nicht, deshalb unkritisch + SetTxtCollAttrs(); + } + // Laufbalkenanzeige + if( !GetMedium() || !GetMedium()->IsRemote() ) + ::SetProgressState( rInput.Tell(), pDoc->GetDocShell() ); + } + break; + + case HTML_NONBREAKSPACE: + pDoc->InsertString( *pPam, CHAR_HARDBLANK ); + break; + + case HTML_SOFTHYPH: + pDoc->InsertString( *pPam, CHAR_SOFTHYPHEN ); + break; + + case HTML_LINEFEEDCHAR: + if( pPam->GetPoint()->nContent.GetIndex() ) + AppendTxtNode(); + if( !pTable && !pDoc->IsInHeaderFooter( pPam->GetPoint()->nNode ) ) + { + NewAttr( &aAttrTab.pBreak, SvxFmtBreakItem(SVX_BREAK_PAGE_BEFORE, RES_BREAK) ); + EndAttr( aAttrTab.pBreak, 0, sal_False ); + } + break; + + case HTML_TEXTTOKEN: + // dann fuege den String ein, ohne das Attribute am Ende + // aufgespannt werden. + if( aToken.Len() && ' '==aToken.GetChar(0) && !IsReadPRE() ) + { + xub_StrLen nPos = pPam->GetPoint()->nContent.GetIndex(); + if( nPos ) + { + const String& rText = + pPam->GetPoint()->nNode.GetNode().GetTxtNode()->GetTxt(); + sal_Unicode cLast = rText.GetChar(--nPos); + if( ' ' == cLast || '\x0a' == cLast) + aToken.Erase(0,1); + } + else + aToken.Erase(0,1); + + if( !aToken.Len() ) + { + bUpperSpace = bUpperSpaceSave; + break; + } + } + + if( aToken.Len() ) + { + if( !bDocInitalized ) + DocumentDetected(); + pDoc->InsertString( *pPam, aToken ); + + // wenn es noch vorlaefige Absatz-Attribute gibt, der Absatz aber + // nicht leer ist, dann sind die Absatz-Attribute entgueltig. + if( aParaAttrs.Count() ) + aParaAttrs.Remove( 0, aParaAttrs.Count() ); + + SetAttr(); + } + break; + + case HTML_HORZRULE: + InsertHorzRule(); + break; + + case HTML_IMAGE: + InsertImage(); + // sollte der Parser der Letzte sein, der das Doc haelt, dann kann + // man hier abbrechen und einen Fehler setzen. + if( 1 == pDoc->getReferenceCount() ) + { + eState = SVPAR_ERROR; + } + break; + + case HTML_SPACER: + InsertSpacer(); + break; + + case HTML_EMBED: + InsertEmbed(); + break; + + case HTML_NOEMBED_ON: + bInNoEmbed = sal_True; + bCallNextToken = pTable!=0; + ReadRawData( OOO_STRING_SVTOOLS_HTML_noembed ); + break; + + case HTML_DEFLIST_ON: + if( nOpenParaToken ) + EndPara(); + NewDefList(); + break; + case HTML_DEFLIST_OFF: + if( nOpenParaToken ) + EndPara(); + EndDefListItem( 0, sal_False, 1==nDefListDeep ); + EndDefList(); + break; + + case HTML_DD_ON: + case HTML_DT_ON: + if( nOpenParaToken ) + EndPara(); + EndDefListItem( 0, sal_False );// <DD>/<DT> beenden und keine Vorl. setzen + NewDefListItem( nToken ); + break; + + case HTML_DD_OFF: + case HTML_DT_OFF: + // siehe HTML_LI_OFF + // eigentlich muesste man ein DD/DT jetzt beenden. Da aber sowhl + // Netscape als auch Microsoft das nicht tun, machen wir das eben + // auch nicht. + EndDefListItem( nToken, sal_False ); + break; + + // Bereiche + case HTML_DIVISION_ON: + case HTML_CENTER_ON: + if( nOpenParaToken ) + { + if( IsReadPRE() ) + nOpenParaToken = 0; + else + EndPara(); + } + NewDivision( nToken ); + break; + + case HTML_DIVISION_OFF: + case HTML_CENTER_OFF: + if( nOpenParaToken ) + { + if( IsReadPRE() ) + nOpenParaToken = 0; + else + EndPara(); + } + EndDivision( nToken ); + break; + + case HTML_MULTICOL_ON: + if( nOpenParaToken ) + EndPara(); + NewMultiCol(); + break; + + case HTML_MULTICOL_OFF: + if( nOpenParaToken ) + EndPara(); + EndTag( HTML_MULTICOL_ON ); + break; + + case HTML_MARQUEE_ON: + NewMarquee(); + bCallNextToken = pMarquee!=0 && pTable!=0; + break; + + case HTML_FORM_ON: + NewForm(); + break; + case HTML_FORM_OFF: + EndForm(); + break; + + // Vorlagen: + case HTML_PARABREAK_ON: + if( nOpenParaToken ) + EndPara( sal_True ); + NewPara(); + break; + + case HTML_PARABREAK_OFF: + EndPara( sal_True ); + break; + + case HTML_ADDRESS_ON: + if( nOpenParaToken ) + EndPara(); + NewTxtFmtColl( HTML_ADDRESS_ON, RES_POOLCOLL_SENDADRESS ); + break; + + case HTML_ADDRESS_OFF: + if( nOpenParaToken ) + EndPara(); + EndTxtFmtColl( HTML_ADDRESS_OFF ); + break; + + case HTML_BLOCKQUOTE_ON: + case HTML_BLOCKQUOTE30_ON: + if( nOpenParaToken ) + EndPara(); + NewTxtFmtColl( HTML_BLOCKQUOTE_ON, RES_POOLCOLL_HTML_BLOCKQUOTE ); + break; + + case HTML_BLOCKQUOTE_OFF: + case HTML_BLOCKQUOTE30_OFF: + if( nOpenParaToken ) + EndPara(); + EndTxtFmtColl( HTML_BLOCKQUOTE_ON ); + break; + + case HTML_PREFORMTXT_ON: + case HTML_LISTING_ON: + case HTML_XMP_ON: + if( nOpenParaToken ) + EndPara(); + NewTxtFmtColl( nToken, RES_POOLCOLL_HTML_PRE ); + break; + + case HTML_PREFORMTXT_OFF: + bNoParSpace = sal_True; // der letzte PRE-Absatz muss einen Zeilenabstand bekommen + EndTxtFmtColl( HTML_PREFORMTXT_OFF ); + break; + + case HTML_LISTING_OFF: + case HTML_XMP_OFF: + EndTxtFmtColl( nToken ); + break; + + case HTML_HEAD1_ON: + case HTML_HEAD2_ON: + case HTML_HEAD3_ON: + case HTML_HEAD4_ON: + case HTML_HEAD5_ON: + case HTML_HEAD6_ON: + if( nOpenParaToken ) + { + if( IsReadPRE() ) + nOpenParaToken = 0; + else + EndPara(); + } + NewHeading( nToken ); + break; + + case HTML_HEAD1_OFF: + case HTML_HEAD2_OFF: + case HTML_HEAD3_OFF: + case HTML_HEAD4_OFF: + case HTML_HEAD5_OFF: + case HTML_HEAD6_OFF: + EndHeading(); + break; + + case HTML_TABLE_ON: + if( pPendStack ) + BuildTable( SVX_ADJUST_END ); + else + { + if( nOpenParaToken ) + EndPara(); + ASSERT( !pTable, "Tabelle in Tabelle darf hier nicht vorkommen" ); + if( !pTable && (IsNewDoc() || !pPam->GetNode()->FindTableNode()) && + (pPam->GetPoint()->nNode.GetIndex() > + pDoc->GetNodes().GetEndOfExtras().GetIndex() || + !pPam->GetNode()->FindFootnoteStartNode() ) ) + { + if ( nParaCnt < 5 ) + Show(); // bis hierhin schon mal anzeigen + + SvxAdjust eAdjust = aAttrTab.pAdjust + ? ((const SvxAdjustItem&)aAttrTab.pAdjust->GetItem()). + GetAdjust() + : SVX_ADJUST_END; + BuildTable( eAdjust ); + } + else + bInsertUnknown = bKeepUnknown; + } + break; + + // Listen + case HTML_DIRLIST_ON: + case HTML_MENULIST_ON: + case HTML_ORDERLIST_ON: + case HTML_UNORDERLIST_ON: + if( nOpenParaToken ) + EndPara(); + NewNumBulList( nToken ); + break; + + case HTML_DIRLIST_OFF: + case HTML_MENULIST_OFF: + case HTML_ORDERLIST_OFF: + case HTML_UNORDERLIST_OFF: + if( nOpenParaToken ) + EndPara(); + EndNumBulListItem( 0, sal_True, GetNumInfo().GetDepth()==1 ); + EndNumBulList( nToken ); + break; + + case HTML_LI_ON: + case HTML_LISTHEADER_ON: + if( nOpenParaToken && + (pPam->GetPoint()->nContent.GetIndex() + || HTML_PARABREAK_ON==nOpenParaToken) ) + { + // nure bei <P><LI> den Absatz beenden, aber nicht bei <DD><LI> + EndPara(); + } + + EndNumBulListItem( 0, sal_False );// <LI>/<LH> beenden und keine Vorl. setzen + NewNumBulListItem( nToken ); + break; + + case HTML_LI_OFF: + case HTML_LISTHEADER_OFF: + EndNumBulListItem( nToken, sal_False ); + break; + + // Attribute : + case HTML_ITALIC_ON: + { + SvxPostureItem aPosture( ITALIC_NORMAL, RES_CHRATR_POSTURE ); + SvxPostureItem aPostureCJK( ITALIC_NORMAL, RES_CHRATR_CJK_POSTURE ); + SvxPostureItem aPostureCTL( ITALIC_NORMAL, RES_CHRATR_CTL_POSTURE ); + NewStdAttr( HTML_ITALIC_ON, + &aAttrTab.pItalic, aPosture, + &aAttrTab.pItalicCJK, &aPostureCJK, + &aAttrTab.pItalicCTL, &aPostureCTL ); + } + break; + + case HTML_BOLD_ON: + { + SvxWeightItem aWeight( WEIGHT_BOLD, RES_CHRATR_WEIGHT ); + SvxWeightItem aWeightCJK( WEIGHT_BOLD, RES_CHRATR_CJK_WEIGHT ); + SvxWeightItem aWeightCTL( WEIGHT_BOLD, RES_CHRATR_CTL_WEIGHT ); + NewStdAttr( HTML_BOLD_ON, + &aAttrTab.pBold, aWeight, + &aAttrTab.pBoldCJK, &aWeightCJK, + &aAttrTab.pBoldCTL, &aWeightCTL ); + } + break; + + + case HTML_STRIKE_ON: + case HTML_STRIKETHROUGH_ON: + { + NewStdAttr( HTML_STRIKE_ON, &aAttrTab.pStrike, + SvxCrossedOutItem(STRIKEOUT_SINGLE, RES_CHRATR_CROSSEDOUT) ); + } + break; + + case HTML_UNDERLINE_ON: + { + NewStdAttr( HTML_UNDERLINE_ON, &aAttrTab.pUnderline, + SvxUnderlineItem(UNDERLINE_SINGLE, RES_CHRATR_UNDERLINE) ); + } + break; + + case HTML_SUPERSCRIPT_ON: + { + NewStdAttr( HTML_SUPERSCRIPT_ON, &aAttrTab.pEscapement, + SvxEscapementItem(HTML_ESC_SUPER,HTML_ESC_PROP, RES_CHRATR_ESCAPEMENT) ); + } + break; + + case HTML_SUBSCRIPT_ON: + { + NewStdAttr( HTML_SUBSCRIPT_ON, &aAttrTab.pEscapement, + SvxEscapementItem(HTML_ESC_SUB,HTML_ESC_PROP, RES_CHRATR_ESCAPEMENT) ); + } + break; + + case HTML_BLINK_ON: + { + NewStdAttr( HTML_BLINK_ON, &aAttrTab.pBlink, + SvxBlinkItem( sal_True, RES_CHRATR_BLINK ) ); + } + break; + + case HTML_SPAN_ON: + NewStdAttr( HTML_SPAN_ON ); + break; + + + case HTML_ITALIC_OFF: + case HTML_BOLD_OFF: + case HTML_STRIKE_OFF: + case HTML_UNDERLINE_OFF: + case HTML_SUPERSCRIPT_OFF: + case HTML_SUBSCRIPT_OFF: + case HTML_BLINK_OFF: + case HTML_SPAN_OFF: + EndTag( nToken ); + break; + + case HTML_STRIKETHROUGH_OFF: + EndTag( HTML_STRIKE_OFF ); + break; + + case HTML_BASEFONT_ON: + NewBasefontAttr(); + break; + case HTML_BASEFONT_OFF: + EndBasefontAttr(); + break; + case HTML_FONT_ON: + case HTML_BIGPRINT_ON: + case HTML_SMALLPRINT_ON: + NewFontAttr( nToken ); + break; + case HTML_FONT_OFF: + case HTML_BIGPRINT_OFF: + case HTML_SMALLPRINT_OFF: + EndFontAttr( nToken ); + break; + + case HTML_EMPHASIS_ON: + case HTML_CITIATION_ON: + case HTML_STRONG_ON: + case HTML_CODE_ON: + case HTML_SAMPLE_ON: + case HTML_KEYBOARD_ON: + case HTML_VARIABLE_ON: + case HTML_DEFINSTANCE_ON: + case HTML_SHORTQUOTE_ON: + case HTML_LANGUAGE_ON: + case HTML_AUTHOR_ON: + case HTML_PERSON_ON: + case HTML_ACRONYM_ON: + case HTML_ABBREVIATION_ON: + case HTML_INSERTEDTEXT_ON: + case HTML_DELETEDTEXT_ON: + + case HTML_TELETYPE_ON: + NewCharFmt( nToken ); + break; + + case HTML_SDFIELD_ON: + NewField(); + bCallNextToken = bInField && pTable!=0; + break; + + case HTML_EMPHASIS_OFF: + case HTML_CITIATION_OFF: + case HTML_STRONG_OFF: + case HTML_CODE_OFF: + case HTML_SAMPLE_OFF: + case HTML_KEYBOARD_OFF: + case HTML_VARIABLE_OFF: + case HTML_DEFINSTANCE_OFF: + case HTML_SHORTQUOTE_OFF: + case HTML_LANGUAGE_OFF: + case HTML_AUTHOR_OFF: + case HTML_PERSON_OFF: + case HTML_ACRONYM_OFF: + case HTML_ABBREVIATION_OFF: + case HTML_INSERTEDTEXT_OFF: + case HTML_DELETEDTEXT_OFF: + + case HTML_TELETYPE_OFF: + EndTag( nToken ); + break; + + case HTML_HEAD_OFF: + if( aStyleSource.Len() ) + { + pCSS1Parser->ParseStyleSheet( aStyleSource ); + aStyleSource.Erase(); + } + break; + + case HTML_DOCTYPE: + case HTML_BODY_OFF: + case HTML_HTML_OFF: + case HTML_HEAD_ON: + case HTML_TITLE_OFF: + break; // nicht weiter auswerten, oder??? + case HTML_HTML_ON: + { + const HTMLOptions *pHTMLOptions = GetOptions(); + for( sal_uInt16 i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[ --i ]; + if( HTML_O_DIR == pOption->GetToken() ) + { + const String& rDir = pOption->GetString(); + SfxItemSet aItemSet( pDoc->GetAttrPool(), + pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + String aDummy; + ParseStyleOptions( aDummy, aDummy, aDummy, aItemSet, + aPropInfo, 0, &rDir ); + + pCSS1Parser->SetPageDescAttrs( 0, &aItemSet ); + break; + } + } + } + break; + + case HTML_INPUT: + InsertInput(); + break; + + case HTML_TEXTAREA_ON: + NewTextArea(); + bCallNextToken = bTextArea && pTable!=0; + break; + + case HTML_SELECT_ON: + NewSelect(); + bCallNextToken = bSelect && pTable!=0; + break; + + case HTML_ANCHOR_ON: + NewAnchor(); + break; + + case HTML_ANCHOR_OFF: + EndAnchor(); + break; + + case HTML_COMMENT: + if( ( aToken.Len() > 5 ) && ( ! bIgnoreHTMLComments ) ) + { + // als Post-It einfuegen + // MIB 8.12.2000: If there are no space characters right behind + // the <!-- and on front of the -->, leave the comment untouched. + if( ' ' == aToken.GetChar( 3 ) && + ' ' == aToken.GetChar( aToken.Len()-3 ) ) + { + String aComment( aToken.Copy( 3, aToken.Len()-5 ) ); + aComment.EraseLeadingChars().EraseTrailingChars(); + InsertComment( aComment ); + } + else + { + String aComment( '<' ); + (aComment += aToken) += '>'; + InsertComment( aComment ); + } + } + break; + + case HTML_MAP_ON: + // Image Maps werden asynchron gelesen: Zunaechst wird nur eine + // ImageMap angelegt. Die Bereiche kommen spaeter. Trozdem wird + // die ImageMap schon in das IMap-Array eingetragen, denn sie + // koennte ja schon verwendet werden. + pImageMap = new ImageMap; + if( ParseMapOptions( pImageMap) ) + { + if( !pImageMaps ) + pImageMaps = new ImageMaps; + pImageMaps->Insert( pImageMap, pImageMaps->Count() ); + } + else + { + delete pImageMap; + pImageMap = 0; + } + break; + + case HTML_MAP_OFF: + // jetzt gibt es keine ImageMap mehr (IMap nicht Loeschen, denn + // die stckt ja schon in dem Array!) + pImageMap = 0; + break; + + case HTML_AREA: + if( pImageMap ) + ParseAreaOptions( pImageMap, sBaseURL, SFX_EVENT_MOUSEOVER_OBJECT, + SFX_EVENT_MOUSEOUT_OBJECT ); + break; + + case HTML_FRAMESET_ON: + bInsertUnknown = bKeepUnknown; + break; + + case HTML_NOFRAMES_ON: + if( IsInHeader() ) + FinishHeader( sal_True ); + bInsertUnknown = bKeepUnknown; + break; + + case HTML_UNKNOWNCONTROL_ON: + // Im Header muss der Inhalt von unbekannten Token ignoriert werden, + // es sei denn, das Token faengt mit einem '!' an. + if( IsInHeader() && !IsReadPRE() && !aUnknownToken.Len() && + sSaveToken.Len() && '!' != sSaveToken.GetChar(0) && + '%' != sSaveToken.GetChar(0) ) + aUnknownToken = sSaveToken; + // kein break + + default: + bInsertUnknown = bKeepUnknown; + break; + } + + if( bGetIDOption ) + InsertIDOption(); + + if( bInsertUnknown ) + { + String aComment( + String::CreateFromAscii(TOOLS_CONSTASCII_STRINGPARAM("HTML: <")) ); + if( (HTML_TOKEN_ONOFF & nToken) != 0 && (1 & nToken) != 0 ) + aComment += '/'; + aComment += sSaveToken; + if( aToken.Len() ) + { + UnescapeToken(); + (aComment += ' ') += aToken; + } + aComment += '>'; + InsertComment( aComment ); + } + + // wenn es noch vorlaefige Absatz-Attribute gibt, der Absatz aber + // nicht leer ist, dann sind die Absatz-Attribute entgueltig. + if( aParaAttrs.Count() && pPam->GetPoint()->nContent.GetIndex() ) + aParaAttrs.Remove( 0, aParaAttrs.Count() ); +} + +/* */ + +extern sal_Bool lcl_css1atr_equalFontItems( const SfxPoolItem& r1, const SfxPoolItem& r2 ); + +void lcl_swhtml_getItemInfo( const _HTMLAttr& rAttr, + sal_Bool& rScriptDependent, sal_Bool& rFont, + sal_uInt16& rScriptType ) +{ + sal_uInt16 nWhich = rAttr.GetItem().Which(); + switch( nWhich ) + { + case RES_CHRATR_FONT: + rFont = sal_True; + case RES_CHRATR_FONTSIZE: + case RES_CHRATR_LANGUAGE: + case RES_CHRATR_POSTURE: + case RES_CHRATR_WEIGHT: + rScriptType = i18n::ScriptType::LATIN; + rScriptDependent = sal_True; + break; + case RES_CHRATR_CJK_FONT: + rFont = sal_True; + case RES_CHRATR_CJK_FONTSIZE: + case RES_CHRATR_CJK_LANGUAGE: + case RES_CHRATR_CJK_POSTURE: + case RES_CHRATR_CJK_WEIGHT: + rScriptType = i18n::ScriptType::ASIAN; + rScriptDependent = sal_True; + break; + case RES_CHRATR_CTL_FONT: + rFont = sal_True; + case RES_CHRATR_CTL_FONTSIZE: + case RES_CHRATR_CTL_LANGUAGE: + case RES_CHRATR_CTL_POSTURE: + case RES_CHRATR_CTL_WEIGHT: + rScriptType = i18n::ScriptType::COMPLEX; + rScriptDependent = sal_True; + break; + default: + rScriptDependent = sal_False; + rFont = sal_False; + break; + } +} + +sal_Bool SwHTMLParser::AppendTxtNode( SwHTMLAppendMode eMode, sal_Bool bUpdateNum ) +{ + // Ein harter Zeilen-Umbruch am Ende muss immer entfernt werden. + // Einen zweiten ersetzen wir durch einen Absatz-Abstand. + xub_StrLen nLFStripped = StripTrailingLF(); + if( (AM_NOSPACE==eMode || AM_SOFTNOSPACE==eMode) && nLFStripped > 1 ) + eMode = AM_SPACE; + + // die harten Attribute an diesem Absatz werden nie mehr ungueltig + if( aParaAttrs.Count() ) + aParaAttrs.Remove( 0, aParaAttrs.Count() ); + + if( AM_SPACE==eMode || AM_NOSPACE==eMode ) + { + SwTxtNode *pTxtNode = + pPam->GetPoint()->nNode.GetNode().GetTxtNode(); + + const SvxULSpaceItem& rULSpace = + (const SvxULSpaceItem&)pTxtNode->SwCntntNode::GetAttr( RES_UL_SPACE ); + + sal_Bool bChange = AM_NOSPACE==eMode ? rULSpace.GetLower() > 0 + : rULSpace.GetLower() == 0; + + if( bChange ) + { + const SvxULSpaceItem& rCollULSpace = + pTxtNode->GetAnyFmtColl().GetULSpace(); + + sal_Bool bMayReset = AM_NOSPACE==eMode ? rCollULSpace.GetLower() == 0 + : rCollULSpace.GetLower() > 0; + + if( bMayReset && + rCollULSpace.GetUpper() == rULSpace.GetUpper() ) + { + pTxtNode->ResetAttr( RES_UL_SPACE ); + } + else + { + pTxtNode->SetAttr( + SvxULSpaceItem( rULSpace.GetUpper(), + AM_NOSPACE==eMode ? 0 : HTML_PARSPACE, RES_UL_SPACE ) ); + } + } + } + bNoParSpace = AM_NOSPACE==eMode || AM_SOFTNOSPACE==eMode; + + SwPosition aOldPos( *pPam->GetPoint() ); + + sal_Bool bRet = pDoc->AppendTxtNode( *pPam->GetPoint() ); + + // Zeichen-Attribute aufspalten und ggf keine setzen, die ueber den + // ganzen Absatz gesetzt sind + const SwNodeIndex& rEndIdx = aOldPos.nNode; + xub_StrLen nEndCnt = aOldPos.nContent.GetIndex(); + const SwPosition& rPos = *pPam->GetPoint(); + + _HTMLAttr** pTbl = (_HTMLAttr**)&aAttrTab; + for( sal_uInt16 nCnt = sizeof( _HTMLAttrTable ) / sizeof( _HTMLAttr* ); + nCnt--; ++pTbl ) + { + _HTMLAttr *pAttr = *pTbl; + if( pAttr && pAttr->GetItem().Which() < RES_PARATR_BEGIN ) + { + sal_Bool bWholePara = sal_False; + + while( pAttr ) + { + _HTMLAttr *pNext = pAttr->GetNext(); + if( pAttr->GetSttParaIdx() < rEndIdx.GetIndex() || + (!bWholePara && + pAttr->GetSttPara() == rEndIdx && + pAttr->GetSttCnt() != nEndCnt) ) + { + bWholePara = + pAttr->GetSttPara() == rEndIdx && + pAttr->GetSttCnt() == 0; + + xub_StrLen nStt = pAttr->nSttCntnt; + sal_Bool bScript = sal_False, bFont = sal_False; + sal_uInt16 nScriptItem; + sal_Bool bInsert = sal_True; + lcl_swhtml_getItemInfo( *pAttr, bScript, bFont, + nScriptItem ); + // den besehrigen Teil setzen + if( bInsert && bScript ) + { + const SwTxtNode *pTxtNd = + pAttr->GetSttPara().GetNode().GetTxtNode(); + ASSERT( pTxtNd, "No text node" ); + if( pTxtNd ) + { + const String& rText = pTxtNd->GetTxt(); + sal_uInt16 nScriptTxt = + pBreakIt->GetBreakIter()->getScriptType( + rText, pAttr->GetSttCnt() ); + xub_StrLen nScriptEnd = (xub_StrLen)pBreakIt->GetBreakIter() + ->endOfScript( rText, nStt, nScriptTxt ); + while( nScriptEnd < nEndCnt ) + { + if( nScriptItem == nScriptTxt ) + { + _HTMLAttr *pSetAttr = + pAttr->Clone( rEndIdx, nScriptEnd ); + pSetAttr->nSttCntnt = nStt; + pSetAttr->ClearPrev(); + if( !pNext || bWholePara ) + { + sal_uInt16 nTmp = pSetAttr->bInsAtStart ? 0 + : aSetAttrTab.Count(); + aSetAttrTab.Insert( pSetAttr, nTmp ); + } + else + pNext->InsertPrev( pSetAttr ); + } + nStt = nScriptEnd; + nScriptTxt = pBreakIt->GetBreakIter()->getScriptType( + rText, nStt ); + nScriptEnd = (xub_StrLen)pBreakIt->GetBreakIter() + ->endOfScript( rText, nStt, nScriptTxt ); + } + bInsert = nScriptItem == nScriptTxt; + } + } + if( bInsert ) + { + _HTMLAttr *pSetAttr = + pAttr->Clone( rEndIdx, nEndCnt ); + pSetAttr->nSttCntnt = nStt; + + // Wenn das Attribut den gesamten Absatz umspannt, werden + // alle auesseren Attribute nicht mehr beachtet. Deshalb + // darf es auch nicht in die Prev-Liste eines ausseren + // Attributs eingetragen werden, denn dieses wird ja + // erstmal nicht gesetzt. Das fuehrt zu verschiebenungen, + // wenn Felder ins Rennen kommen (siehe #51020#) + if( !pNext || bWholePara ) + { + sal_uInt16 nTmp = pSetAttr->bInsAtStart ? 0 + : aSetAttrTab.Count(); + aSetAttrTab.Insert( pSetAttr, nTmp ); + } + else + pNext->InsertPrev( pSetAttr ); + } + else + { + _HTMLAttr *pPrev = pAttr->GetPrev(); + if( pPrev ) + { + // Die Previous-Attribute muessen trotzdem gesetzt werden. + if( !pNext || bWholePara ) + { + sal_uInt16 nTmp = pPrev->bInsAtStart ? 0 : aSetAttrTab.Count(); + aSetAttrTab.Insert( pPrev, nTmp ); + } + else + pNext->InsertPrev( pPrev ); + } + } + pAttr->ClearPrev(); + } + + pAttr->SetStart( rPos ); + pAttr = pNext; + } + } + } + + if( bUpdateNum ) + { + if( GetNumInfo().GetDepth() ) + { + sal_uInt8 nLvl = GetNumInfo().GetLevel(); + // --> OD 2008-04-02 #refactorlists# +// SetNoNum (&nLvl, sal_True); +// SetNodeNum( nLvl); + SetNodeNum( nLvl, false ); + // <-- + } + else + pPam->GetNode()->GetTxtNode()->ResetAttr( RES_PARATR_NUMRULE ); + } + + // Attrubute im Absatz davor sollte man jetzt setzen (wegen JavaScript) + SetAttr(); + + // Now it is time to get rid of all script dependent hints that are + // equal to the settings in the style + SwTxtNode *pTxtNd = rEndIdx.GetNode().GetTxtNode(); + ASSERT( pTxtNd, "There is the txt node" ); + sal_uInt16 nCntAttr = (pTxtNd && pTxtNd->GetpSwpHints()) + ? pTxtNd->GetSwpHints().Count() : 0; + if( nCntAttr ) + { + // These are the end position of all script depenent hints. + // If we find a hint that starts before the current end position, + // we have to set it. If we finf a hint that start behind or at + // that position, we have to take the hint's value into account. + // If it is equal to the style, or in fact the paragarph's value + // for that hint, the hint is removed. Otherwise it's end position + // is remembered. + xub_StrLen aEndPos[15] = + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + SwpHints& rHints = pTxtNd->GetSwpHints(); + for( sal_uInt16 i=0; i < nCntAttr; i++ ) + { + SwTxtAttr *pHt = rHints.GetTextHint( i ); + sal_uInt16 nWhich = pHt->Which(); + sal_Int16 nIdx = -1; + if( RES_CHRATR_CJK_FONT <= nWhich && + nWhich <= RES_CHRATR_CTL_WEIGHT ) + { + nIdx = static_cast< sal_uInt16 >(nWhich - RES_CHRATR_CJK_FONT + 5); + } + else switch( nWhich ) + { + case RES_CHRATR_FONT: nIdx = 0; break; + case RES_CHRATR_FONTSIZE: nIdx = 1; break; + case RES_CHRATR_LANGUAGE: nIdx = 2; break; + case RES_CHRATR_POSTURE: nIdx = 3; break; + case RES_CHRATR_WEIGHT: nIdx = 4; break; + } + if( nIdx != -1 ) + { + xub_StrLen nStt = *pHt->GetStart(); + if( nStt >= aEndPos[nIdx] ) + { + sal_Bool bFont = (nIdx % 5) == 0; + const SfxPoolItem& rItem = + ((const SwCntntNode *)pTxtNd)->GetAttr( nWhich ); + if( bFont ? lcl_css1atr_equalFontItems(rItem,pHt->GetAttr()) + : rItem == pHt->GetAttr() ) + { + // The hint is the same as set in the paragraph and + // therfor, it can be deleted + // CAUTION!!! This WILL delete the hint and it MAY + // also delete the SwpHints!!! To avoid any trouble + // we leave the loop immediately if this is the last + // hint. + pTxtNd->DeleteAttribute( pHt ); + if( 1 == nCntAttr ) + break; + i--; + nCntAttr--; + } + else + { + // The hint is deifferent. Therfor all hints within that + // hint have to be ignored. + aEndPos[nIdx] = pHt->GetEnd() ? *pHt->GetEnd() : nStt; + } + } + else + { + // The hint starts before another one ends. + // The hint in this case is not deleted + ASSERT( pHt->GetEnd() && *pHt->GetEnd() <= aEndPos[nIdx], + "hints aren't nested properly!" ); + } + } + } + } + + + if( !pTable && !--nParaCnt ) + Show(); + + return bRet; +} + +void SwHTMLParser::AddParSpace() +{ + if( !bNoParSpace ) + return; + + bNoParSpace = sal_False; + + sal_uLong nNdIdx = pPam->GetPoint()->nNode.GetIndex() - 1; + + SwTxtNode *pTxtNode = pDoc->GetNodes()[nNdIdx]->GetTxtNode(); + if( !pTxtNode ) + return; + + SvxULSpaceItem rULSpace = + (const SvxULSpaceItem&)pTxtNode->SwCntntNode::GetAttr( RES_UL_SPACE ); + if( !rULSpace.GetLower() ) + { + const SvxULSpaceItem& rCollULSpace = + pTxtNode->GetAnyFmtColl().GetULSpace(); + if( rCollULSpace.GetLower() && + rCollULSpace.GetUpper() == rULSpace.GetUpper() ) + { + pTxtNode->ResetAttr( RES_UL_SPACE ); + } + else + { + pTxtNode->SetAttr( + SvxULSpaceItem( rULSpace.GetUpper(), HTML_PARSPACE, RES_UL_SPACE ) ); + } + } +} + + +void SwHTMLParser::Show() +{ + // Hier wird + // - ein EndAction gerufen, damit formatiert wird + // - ein Reschedule gerufen, + // - die eiegen View-Shell wieder gesetzt + // - und Start-Action gerufen + + ASSERT( SVPAR_WORKING==eState, "Show nicht im Working-State - Das kann ins Auge gehen" ); + ViewShell *pOldVSh = CallEndAction(); + + GetpApp()->Reschedule(); + + if( ( pDoc->GetDocShell() && pDoc->GetDocShell()->IsAbortingImport() ) + || 1 == pDoc->getReferenceCount() ) + { + // wurde der Import vom SFX abgebrochen? + eState = SVPAR_ERROR; + } + + // Die ViewShell nochmal holen, denn sie koennte im Reschedule + // zerstoert wirden sein. + ViewShell *pVSh = CallStartAction( pOldVSh ); + + // ist der aktuelle Node nicht mehr sichtbar, dann benutzen wir + // eine groessere Schrittweite + if( pVSh ) + { + nParaCnt = (pPam->GetPoint()->nNode.GetNode().IsInVisibleArea(pVSh)) + ? 5 : 50; + } +} + +void SwHTMLParser::ShowStatline() +{ + // Hier wird + // - ein Reschedule gerufen, damit gescrollt werden kann + // - die eiegen View-Shell wieder gesetzt + // - ein Start/End-Action gerufen, wenn gescrollt wurde. + + ASSERT( SVPAR_WORKING==eState, "ShowStatLine nicht im Working-State - Das kann ins Auge gehen" ); + + // Laufbalkenanzeige + if( !GetMedium() || !GetMedium()->IsRemote() ) + { + ::SetProgressState( rInput.Tell(), pDoc->GetDocShell() ); + CheckActionViewShell(); + } + else + { + GetpApp()->Reschedule(); + + if( ( pDoc->GetDocShell() && pDoc->GetDocShell()->IsAbortingImport() ) + || 1 == pDoc->getReferenceCount() ) + // wurde der Import vom SFX abgebrochen? + eState = SVPAR_ERROR; + + ViewShell *pVSh = CheckActionViewShell(); + if( pVSh && pVSh->HasInvalidRect() ) + { + CallEndAction( sal_False, sal_False ); + CallStartAction( pVSh, sal_False ); + } + } +} + +ViewShell *SwHTMLParser::CallStartAction( ViewShell *pVSh, sal_Bool bChkPtr ) +{ + ASSERT( !pActionViewShell, "CallStartAction: ViewShell schon gesetzt" ); + + if( !pVSh || bChkPtr ) + { +#ifdef DBG_UTIL + ViewShell *pOldVSh = pVSh; +#endif + pDoc->GetEditShell( &pVSh ); + ASSERT( !pVSh || !pOldVSh || pOldVSh == pVSh, "CallStartAction: Wer hat die ViewShell ausgetauscht?" ); +#ifdef DBG_UTIL + if( pOldVSh && !pVSh ) + pVSh = 0; +#endif + } + pActionViewShell = pVSh; + + if( pActionViewShell ) + { + if( pActionViewShell->ISA( SwEditShell ) ) + ((SwEditShell*)pActionViewShell)->StartAction(); + else + pActionViewShell->StartAction(); + } + + return pActionViewShell; +} + +ViewShell *SwHTMLParser::CallEndAction( sal_Bool bChkAction, sal_Bool bChkPtr ) +{ + if( bChkPtr ) + { + ViewShell *pVSh = 0; + pDoc->GetEditShell( &pVSh ); + ASSERT( !pVSh || pActionViewShell == pVSh, + "CallEndAction: Wer hat die ViewShell ausgetauscht?" ); +#if OSL_DEBUG_LEVEL > 1 + if( pActionViewShell && !pVSh ) + pVSh = 0; +#endif + if( pVSh != pActionViewShell ) + pActionViewShell = 0; + } + + if( !pActionViewShell || (bChkAction && !pActionViewShell->ActionPend()) ) + return pActionViewShell; + + if( bSetCrsr ) + { + // an allen CrsrEditShells die Cursor auf den Doc-Anfang setzen + ViewShell *pSh = pActionViewShell; + do { + if( pSh->IsA( TYPE( SwCrsrShell ) ) ) + ((SwCrsrShell*)pSh)->SttEndDoc(sal_True); + pSh = (ViewShell *)pSh->GetNext(); + } while( pSh != pActionViewShell ); + + bSetCrsr = sal_False; + } + if( pActionViewShell->ISA( SwEditShell ) ) + { + //Schon gescrollt?, dann dafuer sorgen, dass die View sich nicht bewegt! + const sal_Bool bOldLock = pActionViewShell->IsViewLocked(); + pActionViewShell->LockView( sal_True ); + const sal_Bool bOldEndActionByVirDev = pActionViewShell->IsEndActionByVirDev(); + pActionViewShell->SetEndActionByVirDev( sal_True );; + ((SwEditShell*)pActionViewShell)->EndAction(); + pActionViewShell->SetEndActionByVirDev( bOldEndActionByVirDev ); + pActionViewShell->LockView( bOldLock ); + + // bChkJumpMark ist nur gesetzt, wenn das Object auch gefunden wurde + if( bChkJumpMark ) + { + const Point aVisSttPos( DOCUMENTBORDER, DOCUMENTBORDER ); + if( GetMedium() && aVisSttPos == pActionViewShell->VisArea().Pos() ) + ::JumpToSwMark( pActionViewShell, + GetMedium()->GetURLObject().GetMark() ); + bChkJumpMark = sal_False; + } + } + else + pActionViewShell->EndAction(); + + // sollte der Parser der Letzte sein, der das Doc haelt, dann kann + // man hier abbrechen und einen Fehler setzen. + if( 1 == pDoc->getReferenceCount() ) + { + eState = SVPAR_ERROR; + } + + ViewShell *pVSh = pActionViewShell; + pActionViewShell = 0; + + return pVSh; +} + +ViewShell *SwHTMLParser::CheckActionViewShell() +{ + ViewShell *pVSh = 0; + pDoc->GetEditShell( &pVSh ); + ASSERT( !pVSh || pActionViewShell == pVSh, + "CheckActionViewShell: Wer hat die ViewShell ausgetauscht?" ); +#if OSL_DEBUG_LEVEL > 1 + if( pActionViewShell && !pVSh ) + pVSh = 0; +#endif + if( pVSh != pActionViewShell ) + pActionViewShell = 0; + + return pActionViewShell; +} + +/* */ + +void SwHTMLParser::_SetAttr( sal_Bool bChkEnd, sal_Bool bBeforeTable, + _HTMLAttrs *pPostIts ) +{ + SwPaM* pAttrPam = new SwPaM( *pPam->GetPoint() ); + const SwNodeIndex& rEndIdx = pPam->GetPoint()->nNode; + xub_StrLen nEndCnt = pPam->GetPoint()->nContent.GetIndex(); + _HTMLAttr* pAttr; + SwCntntNode* pCNd; + sal_uInt16 n; + + _HTMLAttrs aFields( 5, 5 ); + + for( n = aSetAttrTab.Count(); n; ) + { + pAttr = aSetAttrTab[ --n ]; + sal_uInt16 nWhich = pAttr->pItem->Which(); + + sal_uLong nEndParaIdx = pAttr->GetEndParaIdx(); + sal_Bool bSetAttr; + if( bChkEnd ) + { + // fix #42192#: Zechen-Attribute mit Ende moeglich frueh, + // also noch im aktuellen Absatz setzen (wegen JavaScript + // und diversen Chats). das darf man aber nicht fuer Attribute, + // die ueber den ganzen Absatz aufgspannt werden sollen, weil + // sie aus Absatzvorlgen stammen, die nicht gesetzt werden + // koennen. Weil die Attribute mit SETATTR_DONTREPLACE + // eingefuegt werden, sollte man sie auch anchtraeglich + // noch setzen koennen. + bSetAttr = ( nEndParaIdx < rEndIdx.GetIndex() && + (RES_LR_SPACE != nWhich || !GetNumInfo().GetNumRule()) ) || + ( !pAttr->IsLikePara() && + nEndParaIdx == rEndIdx.GetIndex() && + pAttr->GetEndCnt() < nEndCnt && + (isCHRATR(nWhich) || isTXTATR_WITHEND(nWhich)) ) || + ( bBeforeTable && + nEndParaIdx == rEndIdx.GetIndex() && + !pAttr->GetEndCnt() ); + } + else + { + // Attribiute im Content-Bereich duerfen nicht gesetzt + // werden, wenn wir in einem Sonderbereich stehen, aber + // umgekekehrt schon. + sal_uLong nEndOfIcons = pDoc->GetNodes().GetEndOfExtras().GetIndex(); + bSetAttr = nEndParaIdx < rEndIdx.GetIndex() || + rEndIdx.GetIndex() > nEndOfIcons || + nEndParaIdx <= nEndOfIcons; + } + + if( bSetAttr ) + { + // Das Attribute darf nicht in der liste der vorlaeufigen + // Absatz-Attribute stehen, weil es sonst geloescht wurde. + sal_uInt16 ii = aParaAttrs.Count(); + while( ii-- ) + { + ASSERT( pAttr != aParaAttrs[ii], + "SetAttr: Attribut duerfte noch nicht gesetzt werden" ); + aParaAttrs.Remove( ii ); + } + + + // dann also setzen + aSetAttrTab.Remove( n, 1 ); + + while( pAttr ) + { + _HTMLAttr *pPrev = pAttr->GetPrev(); + if( !pAttr->bValid ) + { + // ungueltige Attribute koennen gloescht werden + delete pAttr; + pAttr = pPrev; + continue; //break; + } + + + pCNd = pAttr->nSttPara.GetNode().GetCntntNode(); + if( !pCNd ) + { + // durch die elende Loescherei von Nodes kann auch mal + // ein Index auf einen End-Node zeigen :-( + if ( (pAttr->GetSttPara() == pAttr->GetEndPara()) && + !isTXTATR_NOEND(nWhich) ) + { + // wenn der End-Index auch auf den Node zeigt + // brauchen wir auch kein Attribut mehr zu setzen, + // es sei denn, es ist ein Text-Attribut. + delete pAttr; + pAttr = pPrev; + continue; //break; + } + pCNd = pDoc->GetNodes().GoNext( &(pAttr->nSttPara) ); + if( pCNd ) + pAttr->nSttCntnt = 0; + else + { + ASSERT( !this, "SetAttr: GoNext() failed!" ); + delete pAttr; + pAttr = pPrev; + continue; // break; + } + } + pAttrPam->GetPoint()->nNode = pAttr->nSttPara; + + + + // durch das Loeschen von BRs kann der Start-Index + // auch mal hinter das Ende des Textes zeigen + if( pAttr->nSttCntnt > pCNd->Len() ) + pAttr->nSttCntnt = pCNd->Len(); + pAttrPam->GetPoint()->nContent.Assign( pCNd, pAttr->nSttCntnt ); + + pAttrPam->SetMark(); + if ( (pAttr->GetSttPara() != pAttr->GetEndPara()) && + !isTXTATR_NOEND(nWhich) ) + { + pCNd = pAttr->nEndPara.GetNode().GetCntntNode(); + if( !pCNd ) + { + pCNd = pDoc->GetNodes().GoPrevious( &(pAttr->nEndPara) ); + if( pCNd ) + pAttr->nEndCntnt = pCNd->Len(); + else + { + ASSERT( !this, "SetAttr: GoPrevious() failed!" ); + pAttrPam->DeleteMark(); + delete pAttr; + pAttr = pPrev; + continue; // break; + } + } + + pAttrPam->GetPoint()->nNode = pAttr->nEndPara; + } + else if( pAttr->IsLikePara() ) + { + pAttr->nEndCntnt = pCNd->Len(); + } + + // durch das Loeschen von BRs kann der End-Index + // auch mal hinter das Ende des Textes zeigen + if( pAttr->nEndCntnt > pCNd->Len() ) + pAttr->nEndCntnt = pCNd->Len(); + + pAttrPam->GetPoint()->nContent.Assign( pCNd, pAttr->nEndCntnt ); + if( bBeforeTable && + pAttrPam->GetPoint()->nNode.GetIndex() == + rEndIdx.GetIndex() ) + { + // wenn wir vor dem Einfuegen einer Tabelle stehen + // und das Attribut im aktuellen Node beendet wird, + // muessen wir es im Node davor beenden oder wegschmeissen, + // wenn es erst in dem Node beginnt + if( nWhich != RES_BREAK && nWhich != RES_PAGEDESC && + !isTXTATR_NOEND(nWhich) ) + { + if( pAttrPam->GetMark()->nNode.GetIndex() != + rEndIdx.GetIndex() ) + { + ASSERT( !pAttrPam->GetPoint()->nContent.GetIndex(), + "Content-Position vor Tabelle nicht 0???" ); + pAttrPam->Move( fnMoveBackward ); + } + else + { + pAttrPam->DeleteMark(); + delete pAttr; + pAttr = pPrev; + continue; + } + } + } + + switch( nWhich ) + { + case RES_FLTR_BOOKMARK: // insert bookmark + { + const String sName( ((SfxStringItem*)pAttr->pItem)->GetValue() ); + IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess(); + IDocumentMarkAccess::const_iterator_t ppBkmk = pMarkAccess->findMark( sName ); + if( ppBkmk != pMarkAccess->getMarksEnd() && + ppBkmk->get()->GetMarkStart() == *pAttrPam->GetPoint() ) + break; // do not generate duplicates on this position + pAttrPam->DeleteMark(); + const ::sw::mark::IMark* const pNewMark = pMarkAccess->makeMark( + *pAttrPam, + sName, + IDocumentMarkAccess::BOOKMARK ); + + // jump to bookmark + if( JUMPTO_MARK == eJumpTo && pNewMark->GetName() == ::rtl::OUString(sJmpMark) ) + { + bChkJumpMark = sal_True; + eJumpTo = JUMPTO_NONE; + } + } + break; + case RES_TXTATR_FIELD: + { + sal_uInt16 nFldWhich = + pPostIts ? ((const SwFmtFld *)pAttr->pItem) + ->GetFld()->GetTyp()->Which() : 0; + if( pPostIts && (RES_POSTITFLD == nFldWhich || + RES_SCRIPTFLD == nFldWhich) ) + { + pPostIts->Insert( pAttr, 0 ); + } + else + { + aFields.Insert( pAttr, aFields.Count() ); + } + } + pAttrPam->DeleteMark(); + pAttr = pPrev; + continue; + + case RES_LR_SPACE: + if( pAttrPam->GetPoint()->nNode.GetIndex() == + pAttrPam->GetMark()->nNode.GetIndex() && + pCNd ) + { + // wegen Numerierungen dieses Attribut direkt + // am Node setzen + pCNd->SetAttr( *pAttr->pItem ); + break; + } + ASSERT( !this, + "LRSpace ueber mehrere Absaetze gesetzt!" ); + // kein break (hier sollen wir trotzdem nie hinkommen; + default: + + // ggfs. ein Bookmark anspringen + if( RES_TXTATR_INETFMT == nWhich && + JUMPTO_MARK == eJumpTo && + sJmpMark == ((SwFmtINetFmt*)pAttr->pItem)->GetName() ) + { + bChkJumpMark = sal_True; + eJumpTo = JUMPTO_NONE; + } + + pDoc->InsertPoolItem( *pAttrPam, *pAttr->pItem, nsSetAttrMode::SETATTR_DONTREPLACE ); + } + pAttrPam->DeleteMark(); + + delete pAttr; + pAttr = pPrev; + } + } + } + + for( n = aMoveFlyFrms.Count(); n; ) + { + SwFrmFmt *pFrmFmt = aMoveFlyFrms[ --n ]; + + const SwFmtAnchor& rAnchor = pFrmFmt->GetAnchor(); + ASSERT( FLY_AT_PARA == rAnchor.GetAnchorId(), + "Nur Auto-Rahmen brauchen eine Spezialbehandlung" ); + const SwPosition *pFlyPos = rAnchor.GetCntntAnchor(); + sal_uLong nFlyParaIdx = pFlyPos->nNode.GetIndex(); + sal_Bool bMoveFly; + if( bChkEnd ) + { + bMoveFly = nFlyParaIdx < rEndIdx.GetIndex() || + ( nFlyParaIdx == rEndIdx.GetIndex() && + aMoveFlyCnts[n] < nEndCnt ); + } + else + { + sal_uLong nEndOfIcons = pDoc->GetNodes().GetEndOfExtras().GetIndex(); + bMoveFly = nFlyParaIdx < rEndIdx.GetIndex() || + rEndIdx.GetIndex() > nEndOfIcons || + nFlyParaIdx <= nEndOfIcons; + } + if( bMoveFly ) + { + pFrmFmt->DelFrms(); + *pAttrPam->GetPoint() = *pFlyPos; + pAttrPam->GetPoint()->nContent.Assign( pAttrPam->GetCntntNode(), + aMoveFlyCnts[n] ); + SwFmtAnchor aAnchor( rAnchor ); + aAnchor.SetType( FLY_AT_CHAR ); + aAnchor.SetAnchor( pAttrPam->GetPoint() ); + pFrmFmt->SetFmtAttr( aAnchor ); + + const SwFmtHoriOrient& rHoriOri = pFrmFmt->GetHoriOrient(); + if( text::HoriOrientation::LEFT == rHoriOri.GetHoriOrient() ) + { + SwFmtHoriOrient aHoriOri( rHoriOri ); + aHoriOri.SetRelationOrient( text::RelOrientation::CHAR ); + pFrmFmt->SetFmtAttr( aHoriOri ); + } + const SwFmtVertOrient& rVertOri = pFrmFmt->GetVertOrient(); + if( text::VertOrientation::TOP == rVertOri.GetVertOrient() ) + { + SwFmtVertOrient aVertOri( rVertOri ); + aVertOri.SetRelationOrient( text::RelOrientation::CHAR ); + pFrmFmt->SetFmtAttr( aVertOri ); + } + + pFrmFmt->MakeFrms(); + aMoveFlyFrms.Remove( n, 1 ); + aMoveFlyCnts.erase( aMoveFlyCnts.begin() + n ); + } + } + while( aFields.Count() ) + { + pAttr = aFields[0]; + + pCNd = pAttr->nSttPara.GetNode().GetCntntNode(); + pAttrPam->GetPoint()->nNode = pAttr->nSttPara; + pAttrPam->GetPoint()->nContent.Assign( pCNd, pAttr->nSttCntnt ); + + if( bBeforeTable && + pAttrPam->GetPoint()->nNode.GetIndex() == rEndIdx.GetIndex() ) + { + ASSERT( !bBeforeTable, "Aha, der Fall tritt also doch ein" ); + ASSERT( !pAttrPam->GetPoint()->nContent.GetIndex(), + "Content-Position vor Tabelle nicht 0???" ); + // !!! + pAttrPam->Move( fnMoveBackward ); + } + + pDoc->InsertPoolItem( *pAttrPam, *pAttr->pItem, 0 ); + + aFields.Remove( 0, 1 ); + delete pAttr; + } + + delete pAttrPam; +} + +void SwHTMLParser::NewAttr( _HTMLAttr **ppAttr, const SfxPoolItem& rItem ) +{ + // Font-Hoehen und -Farben- sowie Escapement-Attribute duerfen nicht + // zusammengefasst werden. Sie werden deshalb in einer Liste gespeichert, + // in der das zuletzt aufgespannte Attribut vorne steht und der Count + // immer 1 ist. Fuer alle anderen Attribute wird der Count einfach + // hochgezaehlt. + if( *ppAttr ) + { + _HTMLAttr *pAttr = new _HTMLAttr( *pPam->GetPoint(), rItem, + ppAttr ); + pAttr->InsertNext( *ppAttr ); + (*ppAttr) = pAttr; + } + else + (*ppAttr) = new _HTMLAttr( *pPam->GetPoint(), rItem, ppAttr ); +} + + +void SwHTMLParser::EndAttr( _HTMLAttr* pAttr, _HTMLAttr **ppDepAttr, + sal_Bool bChkEmpty ) +{ + ASSERT( !ppDepAttr, "SwHTMLParser::EndAttr: ppDepAttr-Feature ungetestet?" ); + // Der Listenkopf ist im Attribut gespeichert + _HTMLAttr **ppHead = pAttr->ppHead; + + ASSERT( ppHead, "keinen Attributs-Listenkopf gefunden!" ); + + // die aktuelle Psoition als Ende-Position merken + const SwNodeIndex* pEndIdx = &pPam->GetPoint()->nNode; + xub_StrLen nEndCnt = pPam->GetPoint()->nContent.GetIndex(); + + // WIrd das zueltzt gestartete oder ein frueher gestartetes Attribut + // beendet? + _HTMLAttr *pLast = 0; + if( ppHead && pAttr != *ppHead ) + { + // Es wird nicht das zuletzt gestartete Attribut beendet + + // Dann suche wir das unmittelbar danach gestartete Attribut, das + // ja ebenfalls noch nicht beendet wurde (sonst stuende es nicht + // mehr in der Liste + pLast = *ppHead; + while( pLast && pLast->GetNext() != pAttr ) + pLast = pLast->GetNext(); + + ASSERT( pLast, "Attribut nicht in eigener Liste gefunden!" ); + + // das Attribut nicht an der PaM-Psoition beenden, sondern da, + // wo das danch gestartete Attribut anfing??? + //pEndIdx = &pPrev->GetSttPara(); + //nEndCnt = pPrev->GetSttCnt(); + } + + sal_Bool bMoveBack = sal_False; + sal_uInt16 nWhich = pAttr->pItem->Which(); + if( /*!pLast &&*/ !nEndCnt && RES_PARATR_BEGIN <= nWhich && + *pEndIdx != pAttr->GetSttPara() ) + { + // dann eine Cntntnt Position zurueck! + bMoveBack = pPam->Move( fnMoveBackward ); + nEndCnt = pPam->GetPoint()->nContent.GetIndex(); + } + + // nun das Attrubut beenden + _HTMLAttr *pNext = pAttr->GetNext(); + + + sal_Bool bInsert; + sal_uInt16 nScriptItem = 0; + sal_Bool bScript = sal_False, bFont = sal_False; + // ein Bereich ?? + if( !bChkEmpty || (RES_PARATR_BEGIN <= nWhich && bMoveBack) || + RES_PAGEDESC == nWhich || RES_BREAK == nWhich || + *pEndIdx != pAttr->GetSttPara() || + nEndCnt != pAttr->GetSttCnt() ) + { + bInsert = sal_True; + // We do some optimization for script depenedent attribtes here. + if( *pEndIdx == pAttr->GetSttPara() ) + { + lcl_swhtml_getItemInfo( *pAttr, bScript, bFont, nScriptItem ); + } + } + else + { + bInsert = sal_False; + } + + if( bInsert && bScript ) + { + const SwTxtNode *pTxtNd = pAttr->GetSttPara().GetNode() + .GetTxtNode(); + ASSERT( pTxtNd, "No text node" ); + const String& rText = pTxtNd->GetTxt(); + sal_uInt16 nScriptTxt = pBreakIt->GetBreakIter()->getScriptType( + rText, pAttr->GetSttCnt() ); + xub_StrLen nScriptEnd = (xub_StrLen)pBreakIt->GetBreakIter() + ->endOfScript( rText, pAttr->GetSttCnt(), nScriptTxt ); + while( nScriptEnd < nEndCnt ) + { + if( nScriptItem == nScriptTxt ) + { + _HTMLAttr *pSetAttr = pAttr->Clone( *pEndIdx, nScriptEnd ); + pSetAttr->ClearPrev(); + if( pNext ) + pNext->InsertPrev( pSetAttr ); + else + { + sal_uInt16 nTmp = pSetAttr->bInsAtStart ? 0 + : aSetAttrTab.Count(); + aSetAttrTab.Insert( pSetAttr, nTmp ); + } + } + pAttr->nSttCntnt = nScriptEnd; + nScriptTxt = pBreakIt->GetBreakIter()->getScriptType( + rText, nScriptEnd ); + nScriptEnd = (xub_StrLen)pBreakIt->GetBreakIter() + ->endOfScript( rText, nScriptEnd, nScriptTxt ); + } + bInsert = nScriptItem == nScriptTxt; + } + if( bInsert ) + { + pAttr->nEndPara = *pEndIdx; + pAttr->nEndCntnt = nEndCnt; + pAttr->bInsAtStart = RES_TXTATR_INETFMT != nWhich && + RES_TXTATR_CHARFMT != nWhich; + + if( !pNext ) + { + // keine offenen Attribute dieses Typs mehr da, + // dann koennen alle gesetzt werden, es sei denn + // sie haengen noch von einem anderen Attribut ab, + // dann werden sie dort angehaengt + if( ppDepAttr && *ppDepAttr ) + (*ppDepAttr)->InsertPrev( pAttr ); + else + { + sal_uInt16 nTmp = pAttr->bInsAtStart ? 0 : aSetAttrTab.Count(); + aSetAttrTab.Insert( pAttr, nTmp ); + } + } + else + { + // es gibt noch andere offene Attribute des Typs, + // daher muss das Setzen zurueckgestellt werden. + // das aktuelle Attribut wird deshalb hinten an die + // Previous-Liste des Nachfolgers angehaengt + pNext->InsertPrev( pAttr ); + } + } + else + { + // dann nicht einfuegen, sondern Loeschen. Durch das "tuerken" von + // Vorlagen durch harte Attributierung koennen sich auch mal andere + // leere Attribute in der Prev-Liste befinden, die dann trotzdem + // gesetzt werden muessen + _HTMLAttr *pPrev = pAttr->GetPrev(); + delete pAttr; + + if( pPrev ) + { + // Die Previous-Attribute muessen trotzdem gesetzt werden. + if( pNext ) + pNext->InsertPrev( pPrev ); + else + { + sal_uInt16 nTmp = pPrev->bInsAtStart ? 0 : aSetAttrTab.Count(); + aSetAttrTab.Insert( pPrev, nTmp ); + } + } + + } + + // wenn das erste Attribut der Liste gesetzt wurde muss noch der + // Listenkopf korrigiert werden. + if( pLast ) + pLast->pNext = pNext; + else if( ppHead ) + *ppHead = pNext; + + if( bMoveBack ) + pPam->Move( fnMoveForward ); +} + +void SwHTMLParser::DeleteAttr( _HTMLAttr* pAttr ) +{ + // Hier darf es keine vorlauefigen Absatz-Attribute geben, den die + // koennten jetzt gesetzt werden und dann sind die Zeiger ungueltig!!! + ASSERT( !aParaAttrs.Count(), + "Hoechste Gefahr: Es gibt noch nicht-endgueltige Absatz-Attribute" ); + if( aParaAttrs.Count() ) + aParaAttrs.Remove( 0, aParaAttrs.Count() ); + + // Der Listenkopf ist im Attribut gespeichert + _HTMLAttr **ppHead = pAttr->ppHead; + + ASSERT( ppHead, "keinen Attributs-Listenkopf gefunden!" ); + + // Wird das zueltzt gestartete oder ein frueher gestartetes Attribut + // entfernt? + _HTMLAttr *pLast = 0; + if( ppHead && pAttr != *ppHead ) + { + // Es wird nicht das zuletzt gestartete Attribut beendet + + // Dann suche wir das unmittelbar danach gestartete Attribut, das + // ja ebenfalls noch nicht beendet wurde (sonst stuende es nicht + // mehr in der Liste + pLast = *ppHead; + while( pLast && pLast->GetNext() != pAttr ) + pLast = pLast->GetNext(); + + ASSERT( pLast, "Attribut nicht in eigener Liste gefunden!" ); + } + + // nun das Attrubut entfernen + _HTMLAttr *pNext = pAttr->GetNext(); + _HTMLAttr *pPrev = pAttr->GetPrev(); + delete pAttr; + + if( pPrev ) + { + // Die Previous-Attribute muessen trotzdem gesetzt werden. + if( pNext ) + pNext->InsertPrev( pPrev ); + else + { + sal_uInt16 nTmp = pPrev->bInsAtStart ? 0 : aSetAttrTab.Count(); + aSetAttrTab.Insert( pPrev, nTmp ); + } + } + + // wenn das erste Attribut der Liste entfernt wurde muss noch der + // Listenkopf korrigiert werden. + if( pLast ) + pLast->pNext = pNext; + else if( ppHead ) + *ppHead = pNext; +} + +void SwHTMLParser::SaveAttrTab( _HTMLAttrTable& rNewAttrTab ) +{ + // Hier darf es keine vorlauefigen Absatz-Attribute geben, den die + // koennten jetzt gesetzt werden und dann sind die Zeiger ungueltig!!! + ASSERT( !aParaAttrs.Count(), + "Hoechste Gefahr: Es gibt noch nicht-endgueltige Absatz-Attribute" ); + if( aParaAttrs.Count() ) + aParaAttrs.Remove( 0, aParaAttrs.Count() ); + + _HTMLAttr** pTbl = (_HTMLAttr**)&aAttrTab; + _HTMLAttr** pSaveTbl = (_HTMLAttr**)&rNewAttrTab; + + for( sal_uInt16 nCnt = sizeof( _HTMLAttrTable ) / sizeof( _HTMLAttr* ); + nCnt--; (++pTbl, ++pSaveTbl) ) + { + *pSaveTbl = *pTbl; + + _HTMLAttr *pAttr = *pSaveTbl; + while( pAttr ) + { + pAttr->SetHead( pSaveTbl ); + pAttr = pAttr->GetNext(); + } + + *pTbl = 0; + } +} + +void SwHTMLParser::SplitAttrTab( _HTMLAttrTable& rNewAttrTab, + sal_Bool bMoveEndBack ) +{ + // Hier darf es keine vorlauefigen Absatz-Attribute geben, den die + // koennten jetzt gesetzt werden und dann sind die Zeiger ungueltig!!! + ASSERT( !aParaAttrs.Count(), + "Hoechste Gefahr: Es gibt noch nicht-endgueltige Absatz-Attribute" ); + if( aParaAttrs.Count() ) + aParaAttrs.Remove( 0, aParaAttrs.Count() ); + + const SwNodeIndex& nSttIdx = pPam->GetPoint()->nNode; + SwNodeIndex nEndIdx( nSttIdx ); + + // alle noch offenen Attribute beenden und hinter der Tabelle + // neu aufspannen + _HTMLAttr** pTbl = (_HTMLAttr**)&aAttrTab; + _HTMLAttr** pSaveTbl = (_HTMLAttr**)&rNewAttrTab; + sal_Bool bSetAttr = sal_True; + xub_StrLen nSttCnt = pPam->GetPoint()->nContent.GetIndex(); + xub_StrLen nEndCnt = nSttCnt; + + if( bMoveEndBack ) + { + sal_uLong nOldEnd = nEndIdx.GetIndex(); + sal_uLong nTmpIdx; + if( ( nTmpIdx = pDoc->GetNodes().GetEndOfExtras().GetIndex()) >= nOldEnd || + ( nTmpIdx = pDoc->GetNodes().GetEndOfAutotext().GetIndex()) >= nOldEnd ) + { + nTmpIdx = pDoc->GetNodes().GetEndOfInserts().GetIndex(); + } + SwCntntNode* pCNd = pDoc->GetNodes().GoPrevious(&nEndIdx); + + // keine Attribute setzen, wenn der PaM aus dem Content-Bereich + // herausgeschoben wurde. + bSetAttr = pCNd && nTmpIdx < nEndIdx.GetIndex(); + + nEndCnt = (bSetAttr ? pCNd->Len() : 0); + } + for( sal_uInt16 nCnt = sizeof( _HTMLAttrTable ) / sizeof( _HTMLAttr* ); + nCnt--; (++pTbl, ++pSaveTbl) ) + { + _HTMLAttr *pAttr = *pTbl; + *pSaveTbl = 0; + while( pAttr ) + { + _HTMLAttr *pNext = pAttr->GetNext(); + _HTMLAttr *pPrev = pAttr->GetPrev(); + + if( bSetAttr && + ( pAttr->GetSttParaIdx() < nEndIdx.GetIndex() || + (pAttr->GetSttPara() == nEndIdx && + pAttr->GetSttCnt() != nEndCnt) ) ) + { + // das Attribut muss vor der Liste gesetzt werden. Da wir + // das Original noch brauchen, weil Zeiger auf das Attribut + // noch in den Kontexten existieren, muessen wir es clonen. + // Die Next-Liste geht dabei verloren, aber die + // Previous-Liste bleibt erhalten + _HTMLAttr *pSetAttr = pAttr->Clone( nEndIdx, nEndCnt ); + + if( pNext ) + pNext->InsertPrev( pSetAttr ); + else + { + sal_uInt16 nTmp = pSetAttr->bInsAtStart ? 0 + : aSetAttrTab.Count(); + aSetAttrTab.Insert( pSetAttr, nTmp ); + } + } + else if( pPrev ) + { + // Wenn das Attribut nicht gesetzt vor der Tabelle + // gesetzt werden muss, muessen der Previous-Attribute + // trotzdem gesetzt werden. + if( pNext ) + pNext->InsertPrev( pPrev ); + else + { + sal_uInt16 nTmp = pPrev->bInsAtStart ? 0 : aSetAttrTab.Count(); + aSetAttrTab.Insert( pPrev, nTmp ); + } + } + + // den Start des Attributs neu setzen und die Verkettungen + // aufbrechen + pAttr->Reset( nSttIdx, nSttCnt, pSaveTbl ); + + if( *pSaveTbl ) + { + _HTMLAttr *pSAttr = *pSaveTbl; + while( pSAttr->GetNext() ) + pSAttr = pSAttr->GetNext(); + pSAttr->InsertNext( pAttr ); + } + else + *pSaveTbl = pAttr; + + pAttr = pNext; + } + + *pTbl = 0; + } +} + +void SwHTMLParser::RestoreAttrTab( const _HTMLAttrTable& rNewAttrTab, + sal_Bool bSetNewStart ) +{ + // Hier darf es keine vorlauefigen Absatz-Attribute geben, den die + // koennten jetzt gesetzt werden und dann sind die Zeiger ungueltig!!! + ASSERT( !aParaAttrs.Count(), + "Hoechste Gefahr: Es gibt noch nicht-endgueltige Absatz-Attribute" ); + if( aParaAttrs.Count() ) + aParaAttrs.Remove( 0, aParaAttrs.Count() ); + + _HTMLAttr** pTbl = (_HTMLAttr**)&aAttrTab; + _HTMLAttr** pSaveTbl = (_HTMLAttr**)&rNewAttrTab; + + for( sal_uInt16 nCnt = sizeof( _HTMLAttrTable ) / sizeof( _HTMLAttr* ); + nCnt--; (++pTbl, ++pSaveTbl) ) + { + ASSERT( !*pTbl, "Die Attribut-Tabelle ist nicht leer!" ); + + const SwPosition *pPos = pPam->GetPoint(); + const SwNodeIndex& rSttPara = pPos->nNode; + xub_StrLen nSttCnt = pPos->nContent.GetIndex(); + + *pTbl = *pSaveTbl; + + _HTMLAttr *pAttr = *pTbl; + while( pAttr ) + { + ASSERT( !pAttr->GetPrev() || !pAttr->GetPrev()->ppHead, + "Previous-Attribut hat noch einen Header" ); + pAttr->SetHead( pTbl ); + if( bSetNewStart ) + { + pAttr->nSttPara = rSttPara; + pAttr->nEndPara = rSttPara; + pAttr->nSttCntnt = nSttCnt; + pAttr->nEndCntnt = nSttCnt; + } + pAttr = pAttr->GetNext(); + } + + *pSaveTbl = 0; + } +} + +void SwHTMLParser::InsertAttr( const SfxPoolItem& rItem, sal_Bool bLikePara, + sal_Bool bInsAtStart ) +{ + _HTMLAttr* pTmp = new _HTMLAttr( *pPam->GetPoint(), + rItem ); + if( bLikePara ) + pTmp->SetLikePara(); + sal_uInt16 nTmp = bInsAtStart ? 0 : aSetAttrTab.Count(); + aSetAttrTab.Insert( pTmp, nTmp ); +} + +void SwHTMLParser::InsertAttrs( _HTMLAttrs& rAttrs ) +{ + while( rAttrs.Count() ) + { + _HTMLAttr *pAttr = rAttrs[0]; + InsertAttr( pAttr->GetItem() ); + rAttrs.Remove( 0, 1 ); + delete pAttr; + } +} + +/* */ + +void SwHTMLParser::NewStdAttr( int nToken ) +{ + String aId, aStyle, aClass, aLang, aDir; + + const HTMLOptions *pHTMLOptions = GetOptions(); + for( sal_uInt16 i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + case HTML_O_LANG: + aLang = pOption->GetString(); + break; + case HTML_O_DIR: + aDir = pOption->GetString(); + break; + } + } + + // einen neuen Kontext anlegen + _HTMLAttrContext *pCntxt = new _HTMLAttrContext( static_cast< sal_uInt16 >(nToken) ); + + // Styles parsen + if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) ) + { + SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + + if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) ) + { + if( HTML_SPAN_ON != nToken || !aClass.Len() || + !CreateContainer( aClass, aItemSet, aPropInfo, pCntxt ) ) + DoPositioning( aItemSet, aPropInfo, pCntxt ); + InsertAttrs( aItemSet, aPropInfo, pCntxt, sal_True ); + } + } + + // den Kontext merken + PushContext( pCntxt ); +} + +void SwHTMLParser::NewStdAttr( int nToken, + _HTMLAttr **ppAttr, const SfxPoolItem & rItem, + _HTMLAttr **ppAttr2, const SfxPoolItem *pItem2, + _HTMLAttr **ppAttr3, const SfxPoolItem *pItem3 ) +{ + String aId, aStyle, aClass, aLang, aDir; + + const HTMLOptions *pHTMLOptions = GetOptions(); + for( sal_uInt16 i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + case HTML_O_LANG: + aLang = pOption->GetString(); + break; + case HTML_O_DIR: + aDir = pOption->GetString(); + break; + } + } + + // einen neuen Kontext anlegen + _HTMLAttrContext *pCntxt = new _HTMLAttrContext( static_cast< sal_uInt16 >(nToken) ); + + // Styles parsen + if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) ) + { + SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + + aItemSet.Put( rItem ); + if( pItem2 ) + aItemSet.Put( *pItem2 ); + if( pItem3 ) + aItemSet.Put( *pItem3 ); + + if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) ) + DoPositioning( aItemSet, aPropInfo, pCntxt ); + + InsertAttrs( aItemSet, aPropInfo, pCntxt, sal_True ); + } + else + { + InsertAttr( ppAttr ,rItem, pCntxt ); + if( pItem2 ) + { + ASSERT( ppAttr2, "missing table entry for item2" ); + InsertAttr( ppAttr2, *pItem2, pCntxt ); + } + if( pItem3 ) + { + ASSERT( ppAttr3, "missing table entry for item3" ); + InsertAttr( ppAttr3, *pItem3, pCntxt ); + } + } + + // den Kontext merken + PushContext( pCntxt ); +} + +void SwHTMLParser::EndTag( int nToken ) +{ + // den Kontext holen + _HTMLAttrContext *pCntxt = PopContext( static_cast< sal_uInt16 >(nToken & ~1) ); + if( pCntxt ) + { + // und ggf. die Attribute beenden + EndContext( pCntxt ); + delete pCntxt; + } +} + + +void SwHTMLParser::NewBasefontAttr() +{ + String aId, aStyle, aClass, aLang, aDir; + sal_uInt16 nSize = 3; + + const HTMLOptions *pHTMLOptions = GetOptions(); + for( sal_uInt16 i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_SIZE: + nSize = (sal_uInt16)pOption->GetNumber(); + break; + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + case HTML_O_LANG: + aLang = pOption->GetString(); + break; + case HTML_O_DIR: + aDir = pOption->GetString(); + break; + } + } + + if( nSize < 1 ) + nSize = 1; + + if( nSize > 7 ) + nSize = 7; + + // einen neuen Kontext anlegen + _HTMLAttrContext *pCntxt = new _HTMLAttrContext( HTML_BASEFONT_ON ); + + // Styles parsen + if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) ) + { + SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + + SvxFontHeightItem aFontHeight( aFontHeights[nSize-1], 100, RES_CHRATR_FONTSIZE ); + aItemSet.Put( aFontHeight ); + aFontHeight.SetWhich( RES_CHRATR_CJK_FONTSIZE ); + aItemSet.Put( aFontHeight ); + aFontHeight.SetWhich( RES_CHRATR_CTL_FONTSIZE ); + aItemSet.Put( aFontHeight ); + + if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) ) + DoPositioning( aItemSet, aPropInfo, pCntxt ); + + InsertAttrs( aItemSet, aPropInfo, pCntxt, sal_True ); + } + else + { + SvxFontHeightItem aFontHeight( aFontHeights[nSize-1], 100, RES_CHRATR_FONTSIZE ); + InsertAttr( &aAttrTab.pFontHeight, aFontHeight, pCntxt ); + aFontHeight.SetWhich( RES_CHRATR_CJK_FONTSIZE ); + InsertAttr( &aAttrTab.pFontHeightCJK, aFontHeight, pCntxt ); + aFontHeight.SetWhich( RES_CHRATR_CTL_FONTSIZE ); + InsertAttr( &aAttrTab.pFontHeightCTL, aFontHeight, pCntxt ); + } + + // den Kontext merken + PushContext( pCntxt ); + + // die Font-Size merken + aBaseFontStack.Insert( nSize, aBaseFontStack.Count() ); +} + +void SwHTMLParser::EndBasefontAttr() +{ + EndTag( HTML_BASEFONT_ON ); + + // Stack-Unterlauf in Tabellen vermeiden + if( aBaseFontStack.Count() > nBaseFontStMin ) + aBaseFontStack.Remove( aBaseFontStack.Count()-1, 1 ); +} + +void SwHTMLParser::NewFontAttr( int nToken ) +{ + sal_uInt16 nBaseSize = + ( aBaseFontStack.Count() > nBaseFontStMin + ? (aBaseFontStack[aBaseFontStack.Count()-1] & FONTSIZE_MASK) + : 3 ); + sal_uInt16 nFontSize = + ( aFontStack.Count() > nFontStMin + ? (aFontStack[aFontStack.Count()-1] & FONTSIZE_MASK) + : nBaseSize ); + + String aFace, aId, aStyle, aClass, aLang, aDir; + Color aColor; + sal_uLong nFontHeight = 0; // tatsaechlich einzustellende Font-Hoehe + sal_uInt16 nSize = 0; // Fontgroesse in Netscape-Notation (1-7) + sal_Bool bColor = sal_False; + + const HTMLOptions *pHTMLOptions = GetOptions(); + for( sal_uInt16 i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_SIZE: + if( HTML_FONT_ON==nToken && pOption->GetString().Len() ) + { + sal_Int32 nSSize; + if( '+' == pOption->GetString().GetChar(0) || + '-' == pOption->GetString().GetChar(0) ) + nSSize = nBaseSize + pOption->GetSNumber(); + else + nSSize = (sal_Int32)pOption->GetNumber(); + + if( nSSize < 1 ) + nSSize = 1; + else if( nSSize > 7 ) + nSSize = 7; + + nSize = (sal_uInt16)nSSize; + nFontHeight = aFontHeights[nSize-1]; + } + break; + case HTML_O_COLOR: + if( HTML_FONT_ON==nToken ) + { + pOption->GetColor( aColor ); + bColor = sal_True; + } + break; + case HTML_O_FACE: + if( HTML_FONT_ON==nToken ) + aFace = pOption->GetString(); + break; + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + case HTML_O_LANG: + aLang = pOption->GetString(); + break; + case HTML_O_DIR: + aDir = pOption->GetString(); + break; + } + } + + if( HTML_FONT_ON != nToken ) + { + // HTML_BIGPRINT_ON oder HTML_SMALLPRINT_ON + + // in Ueberschriften bestimmt die aktuelle Ueberschrift + // die Font-Hoehe und nicht BASEFONT + sal_uInt16 nPoolId = GetCurrFmtColl()->GetPoolFmtId(); + if( (nPoolId>=RES_POOLCOLL_HEADLINE1 && + nPoolId<=RES_POOLCOLL_HEADLINE6) ) + { + // wenn die Schriftgroesse in der Ueberschrift noch + // nicht veraendert ist, die aus der Vorlage nehmen + if( nFontStHeadStart==aFontStack.Count() ) + nFontSize = static_cast< sal_uInt16 >(6 - (nPoolId - RES_POOLCOLL_HEADLINE1)); + } + else + nPoolId = 0; + + if( HTML_BIGPRINT_ON == nToken ) + nSize = ( nFontSize<7 ? nFontSize+1 : 7 ); + else + nSize = ( nFontSize>1 ? nFontSize-1 : 1 ); + + // in Ueberschriften wird die neue Fonthoehe wenn moeglich aus + // den Vorlagen geholt. + if( nPoolId && nSize>=1 && nSize <=6 ) + nFontHeight = + pCSS1Parser->GetTxtCollFromPool( + RES_POOLCOLL_HEADLINE1+6-nSize )->GetSize().GetHeight(); + else + nFontHeight = aFontHeights[nSize-1]; + } + + ASSERT( !nSize == !nFontHeight, "HTML-Font-Size != Font-Height" ); + + String aFontName, aStyleName; + FontFamily eFamily = FAMILY_DONTKNOW; // Family und Pitch, + FontPitch ePitch = PITCH_DONTKNOW; // falls nicht gefunden + rtl_TextEncoding eEnc = gsl_getSystemTextEncoding(); + + if( aFace.Len() && !pCSS1Parser->IsIgnoreFontFamily() ) + { + const FontList *pFList = 0; + SwDocShell *pDocSh = pDoc->GetDocShell(); + if( pDocSh ) + { + const SvxFontListItem *pFListItem = + (const SvxFontListItem *)pDocSh->GetItem(SID_ATTR_CHAR_FONTLIST); + if( pFListItem ) + pFList = pFListItem->GetFontList(); + } + + sal_Bool bFound = sal_False; + xub_StrLen nStrPos = 0; + while( nStrPos!=STRING_NOTFOUND ) + { + String aFName = aFace.GetToken( 0, ',', nStrPos ); + aFName.EraseTrailingChars().EraseLeadingChars(); + if( aFName.Len() ) + { + if( !bFound && pFList ) + { + sal_Handle hFont = pFList->GetFirstFontInfo( aFName ); + if( 0 != hFont ) + { + const FontInfo& rFInfo = pFList->GetFontInfo( hFont ); + if( RTL_TEXTENCODING_DONTKNOW != rFInfo.GetCharSet() ) + { + bFound = sal_True; + if( RTL_TEXTENCODING_SYMBOL == rFInfo.GetCharSet() ) + eEnc = RTL_TEXTENCODING_SYMBOL; + } + } + } + if( aFontName.Len() ) + aFontName += ';'; + aFontName += aFName; + } + } + } + + + // einen neuen Kontext anlegen + _HTMLAttrContext *pCntxt = new _HTMLAttrContext( static_cast< sal_uInt16 >(nToken) ); + + // Styles parsen + if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) ) + { + SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + + if( nFontHeight ) + { + SvxFontHeightItem aFontHeight( nFontHeight, 100, RES_CHRATR_FONTSIZE ); + aItemSet.Put( aFontHeight ); + aFontHeight.SetWhich( RES_CHRATR_CJK_FONTSIZE ); + aItemSet.Put( aFontHeight ); + aFontHeight.SetWhich( RES_CHRATR_CTL_FONTSIZE ); + aItemSet.Put( aFontHeight ); + } + if( bColor ) + aItemSet.Put( SvxColorItem(aColor, RES_CHRATR_COLOR) ); + if( aFontName.Len() ) + { + SvxFontItem aFont( eFamily, aFontName, aStyleName, ePitch, eEnc, RES_CHRATR_FONT ); + aItemSet.Put( aFont ); + aFont.SetWhich( RES_CHRATR_CJK_FONT ); + aItemSet.Put( aFont ); + aFont.SetWhich( RES_CHRATR_CTL_FONT ); + aItemSet.Put( aFont ); + } + + + if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) ) + DoPositioning( aItemSet, aPropInfo, pCntxt ); + + InsertAttrs( aItemSet, aPropInfo, pCntxt, sal_True ); + } + else + { + if( nFontHeight ) + { + SvxFontHeightItem aFontHeight( nFontHeight, 100, RES_CHRATR_FONTSIZE ); + InsertAttr( &aAttrTab.pFontHeight, aFontHeight, pCntxt ); + aFontHeight.SetWhich( RES_CHRATR_CJK_FONTSIZE ); + InsertAttr( &aAttrTab.pFontHeightCJK, aFontHeight, pCntxt ); + aFontHeight.SetWhich( RES_CHRATR_CTL_FONTSIZE ); + InsertAttr( &aAttrTab.pFontHeightCTL, aFontHeight, pCntxt ); + } + if( bColor ) + InsertAttr( &aAttrTab.pFontColor, SvxColorItem(aColor, RES_CHRATR_COLOR), pCntxt ); + if( aFontName.Len() ) + { + SvxFontItem aFont( eFamily, aFontName, aStyleName, ePitch, eEnc, RES_CHRATR_FONT ); + InsertAttr( &aAttrTab.pFont, aFont, pCntxt ); + aFont.SetWhich( RES_CHRATR_CJK_FONT ); + InsertAttr( &aAttrTab.pFontCJK, aFont, pCntxt ); + aFont.SetWhich( RES_CHRATR_CTL_FONT ); + InsertAttr( &aAttrTab.pFontCTL, aFont, pCntxt ); + } + } + + // den Kontext merken + PushContext( pCntxt ); + + aFontStack.Insert( nSize, aFontStack.Count() ); +} + +void SwHTMLParser::EndFontAttr( int nToken ) +{ + EndTag( nToken ); + + // Stack-Unterlauf in Tabellen vermeiden + if( aFontStack.Count() > nFontStMin ) + aFontStack.Remove( aFontStack.Count()-1, 1 ); +} + +/* */ + +void SwHTMLParser::NewPara() +{ + if( pPam->GetPoint()->nContent.GetIndex() ) + AppendTxtNode( AM_SPACE ); + else + AddParSpace(); + + eParaAdjust = SVX_ADJUST_END; + String aId, aStyle, aClass, aLang, aDir; + + const HTMLOptions *pHTMLOptions = GetOptions(); + for( sal_uInt16 i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_ALIGN: + eParaAdjust = (SvxAdjust)pOption->GetEnum( aHTMLPAlignTable, static_cast< sal_uInt16 >(eParaAdjust) ); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + case HTML_O_LANG: + aLang = pOption->GetString(); + break; + case HTML_O_DIR: + aDir = pOption->GetString(); + break; + } + } + + // einen neuen Kontext anlegen + _HTMLAttrContext *pCntxt = + aClass.Len() ? new _HTMLAttrContext( HTML_PARABREAK_ON, + RES_POOLCOLL_TEXT, aClass ) + : new _HTMLAttrContext( HTML_PARABREAK_ON ); + + // Styles parsen (Class nicht beruecksichtigen. Das geht nur, solange + // keine der CSS1-Properties der Klasse hart formatiert werden muss!!!) + if( HasStyleOptions( aStyle, aId, aEmptyStr, &aLang, &aDir ) ) + { + SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + + if( ParseStyleOptions( aStyle, aId, aEmptyStr, aItemSet, aPropInfo, &aLang, &aDir ) ) + { + ASSERT( !aClass.Len() || !pCSS1Parser->GetClass( aClass ), + "Class wird nicht beruecksichtigt" ); + DoPositioning( aItemSet, aPropInfo, pCntxt ); + InsertAttrs( aItemSet, aPropInfo, pCntxt ); + } + } + + if( SVX_ADJUST_END != eParaAdjust ) + InsertAttr( &aAttrTab.pAdjust, SvxAdjustItem(eParaAdjust, RES_PARATR_ADJUST), pCntxt ); + + // und auf den Stack packen + PushContext( pCntxt ); + + // die aktuelle Vorlage oder deren Attribute setzen + SetTxtCollAttrs( aClass.Len() ? pCntxt : 0 ); + + // Laufbalkenanzeige + ShowStatline(); + + ASSERT( !nOpenParaToken, "Jetzt geht ein offenes Absatz-Element verloren" ); + nOpenParaToken = HTML_PARABREAK_ON; +} + +void SwHTMLParser::EndPara( sal_Bool bReal ) +{ + if( HTML_LI_ON==nOpenParaToken && pTable ) + { +#ifdef DBG_UTIL + const SwNumRule *pNumRule = pPam->GetNode()->GetTxtNode()->GetNumRule(); +#endif + ASSERT( pNumRule, "Wo ist die Numrule geblieben" ); + } + + // leere Absaetze werden von Netscape uebersprungen, von uns jetzt auch + if( bReal ) + { + if( pPam->GetPoint()->nContent.GetIndex() ) + AppendTxtNode( AM_SPACE ); + else + AddParSpace(); + } + + // wenn ein DD oder DT offen war, handelt es sich um eine + // implizite Def-Liste, die jetzt beendet werden muss + if( (nOpenParaToken==HTML_DT_ON || nOpenParaToken==HTML_DD_ON) && + nDefListDeep) + { + nDefListDeep--; + } + + // den Kontext vom Stack holen. Er kann auch von einer implizit + // geoeffneten Definitionsliste kommen + _HTMLAttrContext *pCntxt = + PopContext( static_cast< sal_uInt16 >(nOpenParaToken ? (nOpenParaToken & ~1) + : HTML_PARABREAK_ON) ); + + // Attribute beenden + if( pCntxt ) + { + EndContext( pCntxt ); + SetAttr(); // Absatz-Atts wegen JavaScript moeglichst schnell setzen + delete pCntxt; + } + + // und die bisherige Vorlage neu setzen + if( bReal ) + SetTxtCollAttrs(); + + nOpenParaToken = 0; +} + + +void SwHTMLParser::NewHeading( int nToken ) +{ + eParaAdjust = SVX_ADJUST_END; + + String aId, aStyle, aClass, aLang, aDir; + + const HTMLOptions *pHTMLOptions = GetOptions(); + for( sal_uInt16 i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_ALIGN: + eParaAdjust = (SvxAdjust)pOption->GetEnum( aHTMLPAlignTable, static_cast< sal_uInt16 >(eParaAdjust) ); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + case HTML_O_LANG: + aLang = pOption->GetString(); + break; + case HTML_O_DIR: + aDir = pOption->GetString(); + break; + } + } + + // einen neuen Absatz aufmachen + if( pPam->GetPoint()->nContent.GetIndex() ) + AppendTxtNode( AM_SPACE ); + else + AddParSpace(); + + // die passende Vorlage suchen + sal_uInt16 nTxtColl; + switch( nToken ) + { + case HTML_HEAD1_ON: nTxtColl = RES_POOLCOLL_HEADLINE1; break; + case HTML_HEAD2_ON: nTxtColl = RES_POOLCOLL_HEADLINE2; break; + case HTML_HEAD3_ON: nTxtColl = RES_POOLCOLL_HEADLINE3; break; + case HTML_HEAD4_ON: nTxtColl = RES_POOLCOLL_HEADLINE4; break; + case HTML_HEAD5_ON: nTxtColl = RES_POOLCOLL_HEADLINE5; break; + case HTML_HEAD6_ON: nTxtColl = RES_POOLCOLL_HEADLINE6; break; + default: nTxtColl = RES_POOLCOLL_STANDARD; break; + } + + // den Kontext anlegen + _HTMLAttrContext *pCntxt = new _HTMLAttrContext( static_cast< sal_uInt16 >(nToken), nTxtColl, aClass ); + + // Styles parsen (zu Class siehe auch NewPara) + if( HasStyleOptions( aStyle, aId, aEmptyStr, &aLang, &aDir ) ) + { + SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + + if( ParseStyleOptions( aStyle, aId, aEmptyStr, aItemSet, aPropInfo, &aLang, &aDir ) ) + { + ASSERT( !aClass.Len() || !pCSS1Parser->GetClass( aClass ), + "Class wird nicht beruecksichtigt" ); + DoPositioning( aItemSet, aPropInfo, pCntxt ); + InsertAttrs( aItemSet, aPropInfo, pCntxt ); + } + } + + if( SVX_ADJUST_END != eParaAdjust ) + InsertAttr( &aAttrTab.pAdjust, SvxAdjustItem(eParaAdjust, RES_PARATR_ADJUST), pCntxt ); + + // udn auf den Stack packen + PushContext( pCntxt ); + + // und die Vorlage oder deren Attribute setzen + SetTxtCollAttrs( pCntxt ); + + nFontStHeadStart = aFontStack.Count(); + + // Laufbalkenanzeige + ShowStatline(); +} + +void SwHTMLParser::EndHeading() +{ + // einen neuen Absatz aufmachen + if( pPam->GetPoint()->nContent.GetIndex() ) + AppendTxtNode( AM_SPACE ); + else + AddParSpace(); + + // Kontext zu dem Token suchen und vom Stack holen + _HTMLAttrContext *pCntxt = 0; + sal_uInt16 nPos = aContexts.Count(); + while( !pCntxt && nPos>nContextStMin ) + { + switch( aContexts[--nPos]->GetToken() ) + { + case HTML_HEAD1_ON: + case HTML_HEAD2_ON: + case HTML_HEAD3_ON: + case HTML_HEAD4_ON: + case HTML_HEAD5_ON: + case HTML_HEAD6_ON: + pCntxt = aContexts[nPos]; + aContexts.Remove( nPos, 1 ); + break; + } + } + + // und noch Attribute beenden + if( pCntxt ) + { + EndContext( pCntxt ); + SetAttr(); // Absatz-Atts wegen JavaScript moeglichst schnell setzen + delete pCntxt; + } + + // die bisherige Vorlage neu setzen + SetTxtCollAttrs(); + + nFontStHeadStart = nFontStMin; +} + +/* */ + +void SwHTMLParser::NewTxtFmtColl( int nToken, sal_uInt16 nColl ) +{ + String aId, aStyle, aClass, aLang, aDir; + + const HTMLOptions *pHTMLOptions = GetOptions(); + for( sal_uInt16 i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + case HTML_O_LANG: + aLang = pOption->GetString(); + break; + case HTML_O_DIR: + aDir = pOption->GetString(); + break; + } + } + + // einen neuen Absatz aufmachen + SwHTMLAppendMode eMode = AM_NORMAL; + switch( nToken ) + { + case HTML_LISTING_ON: + case HTML_XMP_ON: + // Diese beiden Tags werden jetzt auf die PRE-Vorlage gemappt. + // Fuer dem Fall, dass ein CLASS angegeben ist, loeschen wir + // es damit wir nicht die CLASS der PRE-Vorlage bekommen. + aClass = aEmptyStr; + case HTML_BLOCKQUOTE_ON: + case HTML_BLOCKQUOTE30_ON: + case HTML_PREFORMTXT_ON: + eMode = AM_SPACE; + break; + case HTML_ADDRESS_ON: + eMode = AM_NOSPACE; // ADDRESS kann auf einen <P> ohne </P> folgen + break; + case HTML_DT_ON: + case HTML_DD_ON: + eMode = AM_SOFTNOSPACE; + break; + default: + ASSERT( !this, "unbekannte Vorlage" ); + break; + } + if( pPam->GetPoint()->nContent.GetIndex() ) + AppendTxtNode( eMode ); + else if( AM_SPACE==eMode ) + AddParSpace(); + + // ... und in einem Kontext merken + _HTMLAttrContext *pCntxt = new _HTMLAttrContext( static_cast< sal_uInt16 >(nToken), nColl, aClass ); + + // Styles parsen (zu Class siehe auch NewPara) + if( HasStyleOptions( aStyle, aId, aEmptyStr, &aLang, &aDir ) ) + { + SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + + if( ParseStyleOptions( aStyle, aId, aEmptyStr, aItemSet, aPropInfo, &aLang, &aDir ) ) + { + ASSERT( !aClass.Len() || !pCSS1Parser->GetClass( aClass ), + "Class wird nicht beruecksichtigt" ); + DoPositioning( aItemSet, aPropInfo, pCntxt ); + InsertAttrs( aItemSet, aPropInfo, pCntxt ); + } + } + + PushContext( pCntxt ); + + // die neue Vorlage setzen + SetTxtCollAttrs( pCntxt ); + + // Laufbalkenanzeige aktualisieren + ShowStatline(); +} + +void SwHTMLParser::EndTxtFmtColl( int nToken ) +{ + SwHTMLAppendMode eMode = AM_NORMAL; + switch( nToken & ~1 ) + { + case HTML_BLOCKQUOTE_ON: + case HTML_BLOCKQUOTE30_ON: + case HTML_PREFORMTXT_ON: + case HTML_LISTING_ON: + case HTML_XMP_ON: + eMode = AM_SPACE; + break; + case HTML_ADDRESS_ON: + case HTML_DT_ON: + case HTML_DD_ON: + eMode = AM_SOFTNOSPACE; + break; + default: + ASSERT( !this, "unbekannte Vorlage" ); + break; + } + if( pPam->GetPoint()->nContent.GetIndex() ) + AppendTxtNode( eMode ); + else if( AM_SPACE==eMode ) + AddParSpace(); + + // den aktuellen Kontext vom Stack holen + _HTMLAttrContext *pCntxt = PopContext( static_cast< sal_uInt16 >(nToken & ~1) ); + + // und noch Attribute beenden + if( pCntxt ) + { + EndContext( pCntxt ); + SetAttr(); // Absatz-Atts wegen JavaScript moeglichst schnell setzen + delete pCntxt; + } + + // und die bisherige Vorlage setzen + SetTxtCollAttrs(); +} + +/* */ + +void SwHTMLParser::NewDefList() +{ + String aId, aStyle, aClass, aLang, aDir; + + const HTMLOptions *pHTMLOptions = GetOptions(); + for( sal_uInt16 i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + case HTML_O_LANG: + aLang = pOption->GetString(); + break; + case HTML_O_DIR: + aDir = pOption->GetString(); + break; + } + } + + // einen neuen Absatz aufmachen + sal_Bool bSpace = (GetNumInfo().GetDepth() + nDefListDeep) == 0; + if( pPam->GetPoint()->nContent.GetIndex() ) + AppendTxtNode( bSpace ? AM_SPACE : AM_SOFTNOSPACE ); + else if( bSpace ) + AddParSpace(); + + // ein Level mehr + nDefListDeep++; + + + sal_Bool bInDD = sal_False, bNotInDD = sal_False; + sal_uInt16 nPos = aContexts.Count(); + while( !bInDD && !bNotInDD && nPos>nContextStMin ) + { + sal_uInt16 nCntxtToken = aContexts[--nPos]->GetToken(); + switch( nCntxtToken ) + { + case HTML_DEFLIST_ON: + case HTML_DIRLIST_ON: + case HTML_MENULIST_ON: + case HTML_ORDERLIST_ON: + case HTML_UNORDERLIST_ON: + bNotInDD = sal_True; + break; + case HTML_DD_ON: + bInDD = sal_True; + break; + } + } + + + // ... und in einem Kontext merken + _HTMLAttrContext *pCntxt = new _HTMLAttrContext( HTML_DEFLIST_ON ); + + // darin auch die Raender merken + sal_uInt16 nLeft=0, nRight=0; + short nIndent=0; + GetMarginsFromContext( nLeft, nRight, nIndent ); + + // Die Einrueckung, die sich schon aus einem DL-ergibt, entspricht der + // eines DT auf dem aktuellen Level, und die entspricht der eines + // DD auf dem Level davor. Fue einen Level >=2 muss also ein DD-Abstand + // hinzugefuegt werden + if( !bInDD && nDefListDeep > 1 ) + { + + // und den der DT-Vorlage des aktuellen Levels + SvxLRSpaceItem rLRSpace = + pCSS1Parser->GetTxtFmtColl( RES_POOLCOLL_HTML_DD, aEmptyStr ) + ->GetLRSpace(); + nLeft = nLeft + static_cast< sal_uInt16 >(rLRSpace.GetTxtLeft()); + } + + pCntxt->SetMargins( nLeft, nRight, nIndent ); + + // Styles parsen + if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) ) + { + SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + + if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) ) + { + DoPositioning( aItemSet, aPropInfo, pCntxt ); + InsertAttrs( aItemSet, aPropInfo, pCntxt ); + } + } + + PushContext( pCntxt ); + + // die Attribute der neuen Vorlage setzen + if( nDefListDeep > 1 ) + SetTxtCollAttrs( pCntxt ); +} + +void SwHTMLParser::EndDefList() +{ + sal_Bool bSpace = (GetNumInfo().GetDepth() + nDefListDeep) == 1; + if( pPam->GetPoint()->nContent.GetIndex() ) + AppendTxtNode( bSpace ? AM_SPACE : AM_SOFTNOSPACE ); + else if( bSpace ) + AddParSpace(); + + // ein Level weniger + if( nDefListDeep > 0 ) + nDefListDeep--; + + // den aktuellen Kontext vom Stack holen + _HTMLAttrContext *pCntxt = PopContext( HTML_DEFLIST_ON ); + + // und noch Attribute beenden + if( pCntxt ) + { + EndContext( pCntxt ); + SetAttr(); // Absatz-Atts wegen JavaScript moeglichst schnell setzen + delete pCntxt; + } + + // und Vorlage setzen + SetTxtCollAttrs(); +} + +void SwHTMLParser::NewDefListItem( int nToken ) +{ + // festellen, ob das DD/DT in einer DL vorkommt + sal_Bool bInDefList = sal_False, bNotInDefList = sal_False; + sal_uInt16 nPos = aContexts.Count(); + while( !bInDefList && !bNotInDefList && nPos>nContextStMin ) + { + sal_uInt16 nCntxtToken = aContexts[--nPos]->GetToken(); + switch( nCntxtToken ) + { + case HTML_DEFLIST_ON: + bInDefList = sal_True; + break; + case HTML_DIRLIST_ON: + case HTML_MENULIST_ON: + case HTML_ORDERLIST_ON: + case HTML_UNORDERLIST_ON: + bNotInDefList = sal_True; + break; + } + } + + // wenn nicht, implizit eine neue DL aufmachen + if( !bInDefList ) + { + nDefListDeep++; + ASSERT( !nOpenParaToken, + "Jetzt geht ein offenes Absatz-Element verloren" ); + nOpenParaToken = static_cast< sal_uInt16 >(nToken); + } + + NewTxtFmtColl( nToken, static_cast< sal_uInt16 >(nToken==HTML_DD_ON ? RES_POOLCOLL_HTML_DD + : RES_POOLCOLL_HTML_DT) ); +} + +void SwHTMLParser::EndDefListItem( int nToken, sal_Bool bSetColl, + sal_Bool /*bLastPara*/ ) +{ + // einen neuen Absatz aufmachen + if( !nToken && pPam->GetPoint()->nContent.GetIndex() ) + AppendTxtNode( AM_SOFTNOSPACE ); + + // Kontext zu dem Token suchen und vom Stack holen + nToken &= ~1; + _HTMLAttrContext *pCntxt = 0; + sal_uInt16 nPos = aContexts.Count(); + while( !pCntxt && nPos>nContextStMin ) + { + sal_uInt16 nCntxtToken = aContexts[--nPos]->GetToken(); + switch( nCntxtToken ) + { + case HTML_DD_ON: + case HTML_DT_ON: + if( !nToken || nToken == nCntxtToken ) + { + pCntxt = aContexts[nPos]; + aContexts.Remove( nPos, 1 ); + } + break; + case HTML_DEFLIST_ON: + // keine DD/DT ausserhalb der aktuelen DefListe betrachten + case HTML_DIRLIST_ON: + case HTML_MENULIST_ON: + case HTML_ORDERLIST_ON: + case HTML_UNORDERLIST_ON: + // und auch nicht ausserhalb einer anderen Liste + nPos = nContextStMin; + break; + } + } + + // und noch Attribute beenden + if( pCntxt ) + { + EndContext( pCntxt ); + SetAttr(); // Absatz-Atts wegen JavaScript moeglichst schnell setzen + delete pCntxt; + } + + // und die bisherige Vorlage setzen + if( bSetColl ) + SetTxtCollAttrs(); +} + +/* */ + +sal_Bool SwHTMLParser::HasCurrentParaFlys( sal_Bool bNoSurroundOnly, + sal_Bool bSurroundOnly ) const +{ + // bNoSurroundOnly: Der Absatz enthaelt mindestens einen Rahmen + // ohne Umlauf + // bSurroundOnly: Der Absatz enthaelt mindestens einen Rahmen + // mit Umlauf aber keinen ohne Umlauf + // sonst: Der Absatz enthaelt irgendeinen Rahmen + SwNodeIndex& rNodeIdx = pPam->GetPoint()->nNode; + + const SwSpzFrmFmts& rFrmFmtTbl = *pDoc->GetSpzFrmFmts(); + + sal_Bool bFound = sal_False; + for ( sal_uInt16 i=0; i<rFrmFmtTbl.Count(); i++ ) + { + SwFrmFmt *const pFmt = rFrmFmtTbl[i]; + SwFmtAnchor const*const pAnchor = &pFmt->GetAnchor(); + // Ein Rahmen wurde gefunden, wenn + // - er absatzgebunden ist, und + // - im aktuellen Absatz verankert ist, und + // - jeder absatzgebunene Rahmen zaehlt, oder + // - (nur Rahmen oder umlauf zaehlen und ) der Rahmen keinen + // Umlauf besitzt + SwPosition const*const pAPos = pAnchor->GetCntntAnchor(); + if (pAPos && + ((FLY_AT_PARA == pAnchor->GetAnchorId()) || + (FLY_AT_CHAR == pAnchor->GetAnchorId())) && + pAPos->nNode == rNodeIdx ) + { + if( !(bNoSurroundOnly || bSurroundOnly) ) + { + bFound = sal_True; + break; + } + else + { + // fix #42282#: Wenn Rahmen mit Umlauf gesucht sind, + // auch keine mit Durchlauf beachten. Dabei handelt es + // sich (noch) um HIDDEN-Controls, und denen weicht man + // besser auch nicht aus. + SwSurround eSurround = pFmt->GetSurround().GetSurround(); + if( bNoSurroundOnly ) + { + if( SURROUND_NONE==eSurround ) + { + bFound = sal_True; + break; + } + } + if( bSurroundOnly ) + { + if( SURROUND_NONE==eSurround ) + { + bFound = sal_False; + break; + } + else if( SURROUND_THROUGHT!=eSurround ) + { + bFound = sal_True; + // weitersuchen: Es koennten ja noch welche ohne + // Umlauf kommen ... + } + } + } + } + } + + return bFound; +} + +/* */ + +// die speziellen Methoden zum Einfuegen von Objecten + +const SwFmtColl *SwHTMLParser::GetCurrFmtColl() const +{ + const SwCntntNode* pCNd = pPam->GetCntntNode(); + return &pCNd->GetAnyFmtColl(); +} + + +void SwHTMLParser::SetTxtCollAttrs( _HTMLAttrContext *pContext ) +{ + SwTxtFmtColl *pCollToSet = 0; // die zu setzende Vorlage + SfxItemSet *pItemSet = 0; // der Set fuer harte Attrs + sal_uInt16 nTopColl = pContext ? pContext->GetTxtFmtColl() : 0; + const String& rTopClass = pContext ? pContext->GetClass() : (const String&) aEmptyStr; + sal_uInt16 nDfltColl = RES_POOLCOLL_TEXT; + + sal_Bool bInPRE=sal_False; // etwas Kontext Info + + sal_uInt16 nLeftMargin = 0, nRightMargin = 0; // die Einzuege und + short nFirstLineIndent = 0; // Abstaende + sal_uInt16 i; + + for( i = nContextStAttrMin; i < aContexts.Count(); i++ ) + { + const _HTMLAttrContext *pCntxt = aContexts[i]; + + sal_uInt16 nColl = pCntxt->GetTxtFmtColl(); + if( nColl ) + { + // Es gibt eine Vorlage, die zu setzen ist. Dann + // muss zunaechst einmal entschieden werden, + // ob die Vorlage auch gesetzt werden kann + sal_Bool bSetThis = sal_True; + switch( nColl ) + { + case sal_uInt16(RES_POOLCOLL_HTML_PRE): + bInPRE = sal_True; + break; + case sal_uInt16(RES_POOLCOLL_TEXT): + // <TD><P CLASS=xxx> muss TD.xxx werden + if( nDfltColl==RES_POOLCOLL_TABLE || + nDfltColl==RES_POOLCOLL_TABLE_HDLN ) + nColl = nDfltColl; + break; + case sal_uInt16(RES_POOLCOLL_HTML_HR): + // <HR> auch in <PRE> als Vorlage setzen, sonst kann man sie + // nicht mehr exportieren + break; + default: + if( bInPRE ) + bSetThis = sal_False; + break; + } + + SwTxtFmtColl *pNewColl = + pCSS1Parser->GetTxtFmtColl( nColl, pCntxt->GetClass() ); + + if( bSetThis ) + { + // wenn jetzt eine andere Vorlage gesetzt werden soll als + // bisher, muss die bishere Vorlage durch harte Attributierung + // ersetzt werden + + if( pCollToSet ) + { + // die Attribute, die die bisherige Vorlage setzt + // hart einfuegen + if( !pItemSet ) + pItemSet = new SfxItemSet( pCollToSet->GetAttrSet() ); + else + { + const SfxItemSet& rCollSet = pCollToSet->GetAttrSet(); + SfxItemSet aItemSet( *rCollSet.GetPool(), + rCollSet.GetRanges() ); + aItemSet.Set( rCollSet ); + pItemSet->Put( aItemSet ); + } + // aber die Attribute, die aktuelle Vorlage setzt + // entfernen, weil sie sonst spaeter ueberschrieben + // werden + pItemSet->Differentiate( pNewColl->GetAttrSet() ); + } + + pCollToSet = pNewColl; + } + else + { + // hart Attributieren + if( !pItemSet ) + pItemSet = new SfxItemSet( pNewColl->GetAttrSet() ); + else + { + const SfxItemSet& rCollSet = pNewColl->GetAttrSet(); + SfxItemSet aItemSet( *rCollSet.GetPool(), + rCollSet.GetRanges() ); + aItemSet.Set( rCollSet ); + pItemSet->Put( aItemSet ); + } + } + } + else + { + // vielliecht gibt es ja eine Default-Vorlage? + nColl = pCntxt->GetDfltTxtFmtColl(); + if( nColl ) + nDfltColl = nColl; + } + + // ggf. neue Absatz-Einzuege holen + if( pCntxt->IsLRSpaceChanged() ) + { + sal_uInt16 nLeft=0, nRight=0; + + pCntxt->GetMargins( nLeft, nRight, nFirstLineIndent ); + nLeftMargin = nLeft; + nRightMargin = nRight; + } + } + + // wenn im aktuellen Kontext eine neue Vorlage gesetzt werden soll, + // muessen deren Absatz-Abstaende noch in den Kontext eingetragen werden + if( pContext && nTopColl ) + { + // <TD><P CLASS=xxx> muss TD.xxx werden + if( nTopColl==RES_POOLCOLL_TEXT && + (nDfltColl==RES_POOLCOLL_TABLE || + nDfltColl==RES_POOLCOLL_TABLE_HDLN) ) + nTopColl = nDfltColl; + + const SwTxtFmtColl *pTopColl = + pCSS1Parser->GetTxtFmtColl( nTopColl, rTopClass ); + const SfxItemSet& rItemSet = pTopColl->GetAttrSet(); + const SfxPoolItem *pItem; + if( SFX_ITEM_SET == rItemSet.GetItemState(RES_LR_SPACE,sal_True, &pItem) ) + { + const SvxLRSpaceItem *pLRItem = + (const SvxLRSpaceItem *)pItem; + + sal_Int32 nLeft = pLRItem->GetTxtLeft(); + sal_Int32 nRight = pLRItem->GetRight(); + nFirstLineIndent = pLRItem->GetTxtFirstLineOfst(); + + // In Definitions-Listen enthalten die Abstaende auch die der + // vorhergehenden Level + if( RES_POOLCOLL_HTML_DD == nTopColl ) + { + const SvxLRSpaceItem& rDTLRSpace = pCSS1Parser + ->GetTxtFmtColl( RES_POOLCOLL_HTML_DT, aEmptyStr ) + ->GetLRSpace(); + nLeft -= rDTLRSpace.GetTxtLeft(); + nRight -= rDTLRSpace.GetRight(); + } + else if( RES_POOLCOLL_HTML_DT == nTopColl ) + { + nLeft = 0; + nRight = 0; + } + + // die Absatz-Abstaende addieren sich + nLeftMargin = nLeftMargin + static_cast< sal_uInt16 >(nLeft); + nRightMargin = nRightMargin + static_cast< sal_uInt16 >(nRight); + + pContext->SetMargins( nLeftMargin, nRightMargin, + nFirstLineIndent ); + } + if( SFX_ITEM_SET == rItemSet.GetItemState(RES_UL_SPACE,sal_True, &pItem) ) + { + const SvxULSpaceItem *pULItem = + (const SvxULSpaceItem *)pItem; + pContext->SetULSpace( pULItem->GetUpper(), pULItem->GetLower() ); + } + } + + // wenn gar keine Vorlage im Kontext gesetzt ist, Textkoerper nehmen + if( !pCollToSet ) + { + pCollToSet = pCSS1Parser->GetTxtCollFromPool( nDfltColl ); + const SvxLRSpaceItem& rLRItem = pCollToSet->GetLRSpace(); + if( !nLeftMargin ) + nLeftMargin = static_cast< sal_uInt16 >(rLRItem.GetTxtLeft()); + if( !nRightMargin ) + nRightMargin = static_cast< sal_uInt16 >(rLRItem.GetRight()); + if( !nFirstLineIndent ) + nFirstLineIndent = rLRItem.GetTxtFirstLineOfst(); + } + + // bisherige harte Attributierung des Absatzes entfernen + if( aParaAttrs.Count() ) + { + for( i=0; i<aParaAttrs.Count(); i++ ) + aParaAttrs[i]->Invalidate(); + + aParaAttrs.Remove( 0, aParaAttrs.Count() ); + } + + // Die Vorlage setzen + pDoc->SetTxtFmtColl( *pPam, pCollToSet ); + + // ggf. noch den Absatz-Einzug korrigieren + const SvxLRSpaceItem& rLRItem = pCollToSet->GetLRSpace(); + sal_Bool bSetLRSpace; + + bSetLRSpace = nLeftMargin != rLRItem.GetTxtLeft() || + nFirstLineIndent != rLRItem.GetTxtFirstLineOfst() || + nRightMargin != rLRItem.GetRight(); + + if( bSetLRSpace ) + { + SvxLRSpaceItem aLRItem( rLRItem ); + aLRItem.SetTxtLeft( nLeftMargin ); + aLRItem.SetRight( nRightMargin ); + aLRItem.SetTxtFirstLineOfst( nFirstLineIndent ); + if( pItemSet ) + pItemSet->Put( aLRItem ); + else + { + NewAttr( &aAttrTab.pLRSpace, aLRItem ); + aAttrTab.pLRSpace->SetLikePara(); + aParaAttrs.Insert( aAttrTab.pLRSpace, aParaAttrs.Count() ); + EndAttr( aAttrTab.pLRSpace, 0, sal_False ); + } + } + + // und nun noch die Attribute setzen + if( pItemSet ) + { + InsertParaAttrs( *pItemSet ); + delete pItemSet; + } +} + +/* */ + +void SwHTMLParser::NewCharFmt( int nToken ) +{ + String aId, aStyle, aClass, aLang, aDir; + + const HTMLOptions *pHTMLOptions = GetOptions(); + for( sal_uInt16 i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + case HTML_O_LANG: + aLang = pOption->GetString(); + break; + case HTML_O_DIR: + aDir = pOption->GetString(); + break; + } + } + + // einen neuen Kontext anlegen + _HTMLAttrContext *pCntxt = new _HTMLAttrContext( static_cast< sal_uInt16 >(nToken) ); + + // die Vorlage setzen und im Kontext merken + SwCharFmt* pCFmt = pCSS1Parser->GetChrFmt( static_cast< sal_uInt16 >(nToken), aClass ); + ASSERT( pCFmt, "keine Zeichenvorlage zu Token gefunden" ); + + + // Styles parsen (zu Class siehe auch NewPara) + if( HasStyleOptions( aStyle, aId, aEmptyStr, &aLang, &aDir ) ) + { + SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + + if( ParseStyleOptions( aStyle, aId, aEmptyStr, aItemSet, aPropInfo, &aLang, &aDir ) ) + { + ASSERT( !aClass.Len() || !pCSS1Parser->GetClass( aClass ), + "Class wird nicht beruecksichtigt" ); + DoPositioning( aItemSet, aPropInfo, pCntxt ); + InsertAttrs( aItemSet, aPropInfo, pCntxt, sal_True ); + } + } + + // Zeichen-Vorlagen werden in einem eigenen Stack gehalten und + // koennen nie durch Styles eingefuegt werden. Das Attribut ist deshalb + // auch gar nicht im CSS1-Which-Range enthalten + if( pCFmt ) + InsertAttr( &aAttrTab.pCharFmts, SwFmtCharFmt( pCFmt ), pCntxt ); + + // den Kontext merken + PushContext( pCntxt ); +} + + +/* */ + +void SwHTMLParser::InsertSpacer() +{ + // und es ggf. durch die Optionen veraendern + String aId; + sal_Int16 eVertOri = text::VertOrientation::TOP; + sal_Int16 eHoriOri = text::HoriOrientation::NONE; + Size aSize( 0, 0); + long nSize = 0; + sal_Bool bPrcWidth = sal_False; + sal_Bool bPrcHeight = sal_False; + sal_uInt16 nType = HTML_SPTYPE_HORI; + + const HTMLOptions *pHTMLOptions = GetOptions(); + for( sal_uInt16 i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_TYPE: + pOption->GetEnum( nType, aHTMLSpacerTypeTable ); + break; + case HTML_O_ALIGN: + eVertOri = + pOption->GetEnum( aHTMLImgVAlignTable, + eVertOri ); + eHoriOri = + pOption->GetEnum( aHTMLImgHAlignTable, + eHoriOri ); + break; + case HTML_O_WIDTH: + // erstmal nur als Pixelwerte merken! + bPrcWidth = (pOption->GetString().Search('%') != STRING_NOTFOUND); + aSize.Width() = (long)pOption->GetNumber(); + break; + case HTML_O_HEIGHT: + // erstmal nur als Pixelwerte merken! + bPrcHeight = (pOption->GetString().Search('%') != STRING_NOTFOUND); + aSize.Height() = (long)pOption->GetNumber(); + break; + case HTML_O_SIZE: + // erstmal nur als Pixelwerte merken! + nSize = pOption->GetNumber(); + break; + } + } + + switch( nType ) + { + case HTML_SPTYPE_BLOCK: + { + // einen leeren Textrahmen anlegen + + // den Itemset holen + SfxItemSet aFrmSet( pDoc->GetAttrPool(), + RES_FRMATR_BEGIN, RES_FRMATR_END-1 ); + if( !IsNewDoc() ) + Reader::ResetFrmFmtAttrs( aFrmSet ); + + // den Anker und die Ausrichtung setzen + SetAnchorAndAdjustment( eVertOri, eHoriOri, aFrmSet ); + + // und noch die Groesse des Rahmens + Size aDfltSz( MINFLY, MINFLY ); + Size aSpace( 0, 0 ); + SfxItemSet aDummyItemSet( pDoc->GetAttrPool(), + pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aDummyPropInfo; + + SetFixSize( aSize, aDfltSz, bPrcWidth, bPrcHeight, + aDummyItemSet, aDummyPropInfo, aFrmSet ); + SetSpace( aSpace, aDummyItemSet, aDummyPropInfo, aFrmSet ); + + // den Inhalt schuetzen + SvxProtectItem aProtectItem( RES_PROTECT) ; + aProtectItem.SetCntntProtect( sal_True ); + aFrmSet.Put( aProtectItem ); + + // der Rahmen anlegen + RndStdIds eAnchorId = + ((const SwFmtAnchor &)aFrmSet.Get(RES_ANCHOR)).GetAnchorId(); + SwFrmFmt *pFlyFmt = pDoc->MakeFlySection( eAnchorId, + pPam->GetPoint(), &aFrmSet ); + // Ggf Frames anlegen und auto-geb. Rahmen registrieren + RegisterFlyFrm( pFlyFmt ); + } + break; + case HTML_SPTYPE_VERT: + if( nSize > 0 ) + { + if( nSize && Application::GetDefaultDevice() ) + { + nSize = Application::GetDefaultDevice() + ->PixelToLogic( Size(0,nSize), + MapMode(MAP_TWIP) ).Height(); + } + + // einen Absatz-Abstand setzen + SwTxtNode *pTxtNode = 0; + if( !pPam->GetPoint()->nContent.GetIndex() ) + { + // den unteren Absatz-Abstand des vorherigen Nodes aendern, + // wenn moeglich + + SetAttr(); // noch offene Absatz-Attribute setzen + + pTxtNode = pDoc->GetNodes()[pPam->GetPoint()->nNode.GetIndex()-1] + ->GetTxtNode(); + + // Wenn der Abstz davor kein Txtenode ist, dann wird jetzt + // ein leere Absatz angelegt, der eh schon eine Zeilenhoehe + // Abstand erzeugt. + if( !pTxtNode ) + nSize = nSize>HTML_PARSPACE ? nSize-HTML_PARSPACE : 0; + } + + if( pTxtNode ) + { + SvxULSpaceItem aULSpace( (const SvxULSpaceItem&)pTxtNode + ->SwCntntNode::GetAttr( RES_UL_SPACE ) ); + aULSpace.SetLower( aULSpace.GetLower() + (sal_uInt16)nSize ); + pTxtNode->SetAttr( aULSpace ); + } + else + { + NewAttr( &aAttrTab.pULSpace, SvxULSpaceItem( 0, (sal_uInt16)nSize, RES_UL_SPACE ) ); + EndAttr( aAttrTab.pULSpace, 0, sal_False ); + + AppendTxtNode(); // nicht am Abstand drehen! + } + } + break; + case HTML_SPTYPE_HORI: + if( nSize > 0 ) + { + // wenn der Absatz noch leer ist, einen Erstzeilen-Einzug + // setzen, sondern Sperrschrift ueber einem Space aufspannen + + if( nSize && Application::GetDefaultDevice() ) + { + nSize = Application::GetDefaultDevice() + ->PixelToLogic( Size(nSize,0), + MapMode(MAP_TWIP) ).Width(); + } + + if( !pPam->GetPoint()->nContent.GetIndex() ) + { + sal_uInt16 nLeft=0, nRight=0; + short nIndent = 0; + + GetMarginsFromContextWithNumBul( nLeft, nRight, nIndent ); + nIndent = nIndent + (short)nSize; + + SvxLRSpaceItem aLRItem( RES_LR_SPACE ); + aLRItem.SetTxtLeft( nLeft ); + aLRItem.SetRight( nRight ); + aLRItem.SetTxtFirstLineOfst( nIndent ); + + NewAttr( &aAttrTab.pLRSpace, aLRItem ); + EndAttr( aAttrTab.pLRSpace, 0, sal_False ); + } + else + { + NewAttr( &aAttrTab.pKerning, SvxKerningItem( (short)nSize, RES_CHRATR_KERNING ) ); + String aTmp( ' ' ); + pDoc->InsertString( *pPam, aTmp ); + EndAttr( aAttrTab.pKerning ); + } + } + } +} + +sal_uInt16 SwHTMLParser::ToTwips( sal_uInt16 nPixel ) const +{ + if( nPixel && Application::GetDefaultDevice() ) + { + long nTwips = Application::GetDefaultDevice()->PixelToLogic( + Size( nPixel, nPixel ), MapMode( MAP_TWIP ) ).Width(); + return nTwips <= USHRT_MAX ? (sal_uInt16)nTwips : USHRT_MAX; + } + else + return nPixel; +} + +SwTwips SwHTMLParser::GetCurrentBrowseWidth() +{ + const SwTwips nWidth = SwHTMLTableLayout::GetBrowseWidth( *pDoc ); + if( nWidth ) + return nWidth; + + if( !aHTMLPageSize.Width() ) + { + const SwFrmFmt& rPgFmt = pCSS1Parser->GetMasterPageDesc()->GetMaster(); + + const SwFmtFrmSize& rSz = rPgFmt.GetFrmSize(); + const SvxLRSpaceItem& rLR = rPgFmt.GetLRSpace(); + const SvxULSpaceItem& rUL = rPgFmt.GetULSpace(); + const SwFmtCol& rCol = rPgFmt.GetCol(); + + aHTMLPageSize.Width() = rSz.GetWidth() - rLR.GetLeft() - rLR.GetRight(); + aHTMLPageSize.Height() = rSz.GetHeight() - rUL.GetUpper() - rUL.GetLower(); + + if( 1 < rCol.GetNumCols() ) + aHTMLPageSize.Width() /= rCol.GetNumCols(); + } + + return aHTMLPageSize.Width(); +} + + +/* */ + +void SwHTMLParser::InsertIDOption() +{ + String aId; + const HTMLOptions *pHTMLOptions = GetOptions(); + for( sal_uInt16 i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + if( HTML_O_ID==pOption->GetToken() ) + { + aId = pOption->GetString(); + break; + } + } + + if( aId.Len() ) + InsertBookmark( aId ); +} + + +/* */ + + +void SwHTMLParser::InsertLineBreak() +{ + // <BR CLEAR=xxx> wird wie folgt behandelt: + // 1.) Es werden nur nur absatzgebundene Rahmen betrachtet, die + // im aktuellen Absatz verankert sind. + // 2.) Fuer linksbuendig ausgerichtete Rahmen wird bei CLEAR=LEFT + // oder ALL und auf rechtsbuendige ausgerichtete Rahmen bei + // CLEAR=RIGHT oder ALL der Durchlauf wie folgt geaendert: + // 3.) Wenn der Absatz keinen Text enthaelt, bekommt der Rahmen keinen + // Umlauf + // 4.) sonst erhaelt ein links ausgerichteter Rahmen eine rechten + // "nur Anker" Umlauf und recht rechst ausg. Rahmen einen linken + // "nur Anker" Umlauf. + // 5.) wenn in einem nicht-leeren Absatz der Umlauf eines Rahmens + // geaendert wird, wird ein neuer Absatz aufgemacht + // 6.) Wenn von keinem Rahmen der Umlauf geaendert wird, wird ein + // harter Zeilenumbruch eingefuegt + + String aId, aStyle, aClass; // die ID der Bookmark + sal_Bool bClearLeft = sal_False, bClearRight = sal_False; + sal_Bool bCleared = sal_False; // wurde ein CLEAR ausgefuehrt? + + // dann holen wir mal die Optionen + const HTMLOptions *pHTMLOptions = GetOptions(); + for( sal_uInt16 i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_CLEAR: + { + const String &aClear = pOption->GetString(); + if( aClear.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_AL_all ) ) + { + bClearLeft = sal_True; + bClearRight = sal_True; + } + else if( aClear.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_AL_left ) ) + bClearLeft = sal_True; + else if( aClear.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_AL_right ) ) + bClearRight = sal_True; + } + break; + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_STYLE: + aStyle = pOption->GetString(); + break; + case HTML_O_CLASS: + aClass = pOption->GetString(); + break; + } + } + + // CLEAR wird nur fuer den aktuellen Absaetz unterstuetzt + if( bClearLeft || bClearRight ) + { + SwNodeIndex& rNodeIdx = pPam->GetPoint()->nNode; + SwTxtNode* pTxtNd = rNodeIdx.GetNode().GetTxtNode(); + if( pTxtNd ) + { + const SwSpzFrmFmts& rFrmFmtTbl = *pDoc->GetSpzFrmFmts(); + + for( sal_uInt16 i=0; i<rFrmFmtTbl.Count(); i++ ) + { + SwFrmFmt *const pFmt = rFrmFmtTbl[i]; + SwFmtAnchor const*const pAnchor = &pFmt->GetAnchor(); + SwPosition const*const pAPos = pAnchor->GetCntntAnchor(); + if (pAPos && + ((FLY_AT_PARA == pAnchor->GetAnchorId()) || + (FLY_AT_CHAR == pAnchor->GetAnchorId())) && + pAPos->nNode == rNodeIdx && + pFmt->GetSurround().GetSurround() != SURROUND_NONE ) + { + sal_Int16 eHori = RES_DRAWFRMFMT == pFmt->Which() + ? text::HoriOrientation::LEFT + : pFmt->GetHoriOrient().GetHoriOrient(); + + SwSurround eSurround = SURROUND_PARALLEL; + if( pPam->GetPoint()->nContent.GetIndex() ) + { + if( bClearLeft && text::HoriOrientation::LEFT==eHori ) + eSurround = SURROUND_RIGHT; + else if( bClearRight && text::HoriOrientation::RIGHT==eHori ) + eSurround = SURROUND_LEFT; + } + else if( (bClearLeft && text::HoriOrientation::LEFT==eHori) || + (bClearRight && text::HoriOrientation::RIGHT==eHori) ) + { + eSurround = SURROUND_NONE; + } + + if( SURROUND_PARALLEL != eSurround ) + { + SwFmtSurround aSurround( eSurround ); + if( SURROUND_NONE != eSurround ) + aSurround.SetAnchorOnly( sal_True ); + pFmt->SetFmtAttr( aSurround ); + bCleared = sal_True; + } + } // Anker ist nicht im Node + } // Schleife ueber Fly-Frames + } // kein Text-Node + } // kein CLEAR + + // Styles parsen + SvxFmtBreakItem aBreakItem( SVX_BREAK_NONE, RES_BREAK ); + sal_Bool bBreakItem = sal_False; + if( HasStyleOptions( aStyle, aId, aClass ) ) + { + SfxItemSet aItemSet( pDoc->GetAttrPool(), pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + + if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo ) ) + { + if( pCSS1Parser->SetFmtBreak( aItemSet, aPropInfo ) ) + { + aBreakItem = (const SvxFmtBreakItem &)aItemSet.Get( RES_BREAK ); + bBreakItem = sal_True; + } + if( aPropInfo.aId.Len() ) + InsertBookmark( aPropInfo.aId ); + } + } + + if( bBreakItem && SVX_BREAK_PAGE_AFTER==aBreakItem.GetBreak() ) + { + NewAttr( &aAttrTab.pBreak, aBreakItem ); + EndAttr( aAttrTab.pBreak, 0, sal_False ); + } + + if( !bCleared && !bBreakItem ) + { + // wenn kein CLEAR ausgefuehrt werden sollte oder konnte, wird + // ein Zeilenumbruch eingef?gt + String sTmp( (sal_Unicode)0x0a ); // make the Mac happy :-) + pDoc->InsertString( *pPam, sTmp ); + } + else if( pPam->GetPoint()->nContent.GetIndex() ) + { + // wenn ein Claer in einem nicht-leeren Absatz ausgefuehrt wurde, + // muss anschliessen ein neuer Absatz aufgemacht werden + // MIB 21.02.97: Eigentlich muesste man hier den unteren Absatz- + // Absatnd auf 0 drehen. Das geht aber bei sowas wie <BR ..><P> + // schief (>Netacpe). Deshalb lassen wir das erstmal. + AppendTxtNode( AM_NOSPACE ); + } + if( bBreakItem && SVX_BREAK_PAGE_BEFORE==aBreakItem.GetBreak() ) + { + NewAttr( &aAttrTab.pBreak, aBreakItem ); + EndAttr( aAttrTab.pBreak, 0, sal_False ); + } +} + +void SwHTMLParser::InsertHorzRule() +{ + sal_uInt16 nSize = 0; + sal_uInt16 nWidth = 0; + + SvxAdjust eAdjust = SVX_ADJUST_END; + + sal_Bool bPrcWidth = sal_False; + sal_Bool bNoShade = sal_False; + sal_Bool bColor = sal_False; + + Color aColor; + String aId; + + // dann holen wir mal die Optionen + const HTMLOptions *pHTMLOptions = GetOptions(); + for( sal_uInt16 i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[--i]; + switch( pOption->GetToken() ) + { + case HTML_O_ID: + aId = pOption->GetString(); + break; + case HTML_O_SIZE: + nSize = (sal_uInt16)pOption->GetNumber(); + break; + case HTML_O_WIDTH: + bPrcWidth = (pOption->GetString().Search('%') != STRING_NOTFOUND); + nWidth = (sal_uInt16)pOption->GetNumber(); + if( bPrcWidth && nWidth>=100 ) + { + // 100%-Linien sind der default-Fall (keine Attrs neotig) + nWidth = 0; + bPrcWidth = sal_False; + } + break; + case HTML_O_ALIGN: + eAdjust = + (SvxAdjust)pOption->GetEnum( aHTMLPAlignTable, static_cast< sal_uInt16 >(eAdjust) ); + break; + case HTML_O_NOSHADE: + bNoShade = sal_True; + break; + case HTML_O_COLOR: + pOption->GetColor( aColor ); + bColor = sal_True; + break; + } + } + + if( pPam->GetPoint()->nContent.GetIndex() ) + AppendTxtNode( AM_NOSPACE ); + if( nOpenParaToken ) + EndPara(); + AppendTxtNode(); + pPam->Move( fnMoveBackward ); + + // ... und in einem Kontext merken + _HTMLAttrContext *pCntxt = + new _HTMLAttrContext( HTML_HORZRULE, RES_POOLCOLL_HTML_HR, aEmptyStr ); + + PushContext( pCntxt ); + + // die neue Vorlage setzen + SetTxtCollAttrs( pCntxt ); + + // die harten Attribute an diesem Absatz werden nie mehr ungueltig + if( aParaAttrs.Count() ) + aParaAttrs.Remove( 0, aParaAttrs.Count() ); + + if( nSize>0 || bColor || bNoShade ) + { + // Farbe und/oder Breite der Linie setzen + if( !bColor ) + aColor.SetColor( COL_GRAY ); + + SvxBorderLine aBorderLine( &aColor ); + if( nSize ) + { + long nPWidth = 0; + long nPHeight = (long)nSize; + SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight ); + SvxCSS1Parser::SetBorderWidth( aBorderLine, (sal_uInt16)nPHeight, + !bNoShade ); + } + else if( bNoShade ) + { + aBorderLine.SetOutWidth( DEF_LINE_WIDTH_2 ); + } + else + { + aBorderLine.SetOutWidth( DEF_DOUBLE_LINE0_OUT ); + aBorderLine.SetInWidth( DEF_DOUBLE_LINE0_IN ); + aBorderLine.SetDistance( DEF_DOUBLE_LINE0_DIST ); + } + + SvxBoxItem aBoxItem(RES_BOX); + aBoxItem.SetLine( &aBorderLine, BOX_LINE_BOTTOM ); + _HTMLAttr* pTmp = new _HTMLAttr( *pPam->GetPoint(), aBoxItem ); + aSetAttrTab.Insert( pTmp, aSetAttrTab.Count() ); + } + if( nWidth ) + { + // Wenn wir in keiner Tabelle sind, wird die Breitenangabe durch + // Absatz-Einzuege "getuerkt". In einer Tabelle macht das wenig + // Sinn. Um zu Vermeiden, dass die Linie bei der Breitenberechnung + // beruecksichtigt wird, bekommt sie aber trotzdem entsprechendes + // LRSpace-Item verpasst. +#ifdef FIX41370 + const SwFmtColl *pColl = GetCurrFmtColl(); + SvxLRSpaceItem aLRItem( pColl->GetLRSpace() ); +#endif + if( !pTable ) + { + // Laenge und Ausrichtung der Linie ueber Absatz-Einzuege "tuerken" + long nBrowseWidth = GetCurrentBrowseWidth(); + nWidth = bPrcWidth ? (sal_uInt16)((nWidth*nBrowseWidth) / 100) + : ToTwips( (sal_uInt16)nBrowseWidth ); + if( nWidth < MINLAY ) + nWidth = MINLAY; + + if( (long)nWidth < nBrowseWidth ) + { +#ifndef FIX41370 + const SwFmtColl *pColl = GetCurrFmtColl(); + SvxLRSpaceItem aLRItem( pColl->GetLRSpace() ); +#endif + long nDist = nBrowseWidth - nWidth; + + switch( eAdjust ) + { + case SVX_ADJUST_RIGHT: + aLRItem.SetTxtLeft( (sal_uInt16)nDist ); + break; + case SVX_ADJUST_LEFT: + aLRItem.SetRight( (sal_uInt16)nDist ); + break; + case SVX_ADJUST_CENTER: + default: + nDist /= 2; + aLRItem.SetTxtLeft( (sal_uInt16)nDist ); + aLRItem.SetRight( (sal_uInt16)nDist ); + break; + } + +#ifndef FIX41370 + _HTMLAttr* pTmp = new _HTMLAttr( *pPam->GetPoint(), aLRItem ); + aSetAttrTab.Insert( pTmp, aSetAttrTab.Count() ); +#endif + } + } + +#ifdef FIX41370 + _HTMLAttr* pTmp = new _HTMLAttr( *pPam->GetPoint(), aLRItem ); + aSetAttrTab.Insert( pTmp, aSetAttrTab.Count() ); +#endif + } + + // Bookmarks koennen nicht in Hyperlinks eingefueht werden + if( aId.Len() ) + InsertBookmark( aId ); + + // den aktuellen Kontext vom Stack holen + _HTMLAttrContext *pPoppedContext = PopContext( HTML_HORZRULE ); + ASSERT( pPoppedContext==pCntxt, "wo kommt denn da ein HR-Kontext her?" ); + delete pPoppedContext; + + pPam->Move( fnMoveForward ); + + // und im Absatz danach die dort aktuelle Vorlage setzen + SetTxtCollAttrs(); +} + +void SwHTMLParser::ParseMoreMetaOptions() +{ + String aName, aContent; + sal_Bool bHTTPEquiv = sal_False; + + const HTMLOptions *pHTMLOptions = GetOptions(); + for( sal_uInt16 i = pHTMLOptions->Count(); i; ) + { + const HTMLOption *pOption = (*pHTMLOptions)[ --i ]; + switch( pOption->GetToken() ) + { + case HTML_O_NAME: + aName = pOption->GetString(); + bHTTPEquiv = sal_False; + break; + case HTML_O_HTTPEQUIV: + aName = pOption->GetString(); + bHTTPEquiv = sal_True; + break; + case HTML_O_CONTENT: + aContent = pOption->GetString(); + break; + } + } + + // Hier wird es etwas tricky: Wir wissen genau, da? die Dok-Info + // nicht geaendert wurde. Deshalb genuegt es, auf Generator und + // auf refresh abzufragen, um noch nicht verarbeitete Token zu finden, + // denn das sind die einzigen, die die Dok-Info nicht modifizieren. + if( aName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_META_generator ) || + aName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_META_refresh ) || + aName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_META_content_type ) || + aName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_META_content_script_type ) ) + return; + + aContent.EraseAllChars( _CR ); + aContent.EraseAllChars( _LF ); + + if( aName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_META_sdendnote ) ) + { + FillEndNoteInfo( aContent ); + return; + } + + if( aName.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_META_sdfootnote ) ) + { + FillFootNoteInfo( aContent ); + return; + } + + String sText( + String::CreateFromAscii(TOOLS_CONSTASCII_STRINGPARAM("HTML: <")) ); + sText.AppendAscii( TOOLS_CONSTASCII_STRINGPARAM(OOO_STRING_SVTOOLS_HTML_meta) ); + sText.Append( ' ' ); + if( bHTTPEquiv ) + sText.AppendAscii( TOOLS_CONSTASCII_STRINGPARAM(OOO_STRING_SVTOOLS_HTML_O_httpequiv) ); + else + sText.AppendAscii( TOOLS_CONSTASCII_STRINGPARAM(OOO_STRING_SVTOOLS_HTML_O_name) ); + sText.AppendAscii( TOOLS_CONSTASCII_STRINGPARAM("=\"") ); + sText.Append( aName ); + sText.AppendAscii( TOOLS_CONSTASCII_STRINGPARAM("\" ") ); + sText.AppendAscii( TOOLS_CONSTASCII_STRINGPARAM(OOO_STRING_SVTOOLS_HTML_O_content) ); + sText.AppendAscii( TOOLS_CONSTASCII_STRINGPARAM("=\"") ); + sText.Append( aContent ); + sText.AppendAscii( TOOLS_CONSTASCII_STRINGPARAM("\">") ); + + SwPostItField aPostItFld( + (SwPostItFieldType*)pDoc->GetSysFldType( RES_POSTITFLD ), + aEmptyStr, sText, DateTime() ); + SwFmtFld aFmtFld( aPostItFld ); + InsertAttr( aFmtFld ); +} + +/* */ + +_HTMLAttr::_HTMLAttr( const SwPosition& rPos, const SfxPoolItem& rItem, + _HTMLAttr **ppHd ) : + nSttPara( rPos.nNode ), + nEndPara( rPos.nNode ), + nSttCntnt( rPos.nContent.GetIndex() ), + nEndCntnt(rPos.nContent.GetIndex() ), + bInsAtStart( sal_True ), + bLikePara( sal_False ), + bValid( sal_True ), + nCount( 1 ), + pNext( 0 ), + pPrev( 0 ), + ppHead( ppHd ) +{ + pItem = rItem.Clone(); +} + +_HTMLAttr::_HTMLAttr( const _HTMLAttr &rAttr, const SwNodeIndex &rEndPara, + sal_uInt16 nEndCnt, _HTMLAttr **ppHd ) : + nSttPara( rAttr.nSttPara ), + nEndPara( rEndPara ), + nSttCntnt( rAttr.nSttCntnt ), + nEndCntnt( nEndCnt ), + bInsAtStart( rAttr.bInsAtStart ), + bLikePara( rAttr.bLikePara ), + bValid( rAttr.bValid ), + nCount( rAttr.nCount ), + pNext( 0 ), + pPrev( 0 ), + ppHead( ppHd ) +{ + pItem = rAttr.pItem->Clone(); +} + +_HTMLAttr::~_HTMLAttr() +{ + delete pItem; +} + +_HTMLAttr *_HTMLAttr::Clone( const SwNodeIndex& rEndPara, sal_uInt16 nEndCnt ) const +{ + // das Attribut mit der alten Start-Position neu anlegen + _HTMLAttr *pNew = new _HTMLAttr( *this, rEndPara, nEndCnt, ppHead ); + + // die Previous-Liste muss uebernommen werden, die Next-Liste nicht! + pNew->pPrev = pPrev; + + return pNew; +} + +void _HTMLAttr::Reset( const SwNodeIndex& rSttPara, sal_uInt16 nSttCnt, + _HTMLAttr **ppHd ) +{ + // den Anfang (und das Ende) neu setzen + nSttPara = rSttPara; + nSttCntnt = nSttCnt; + nEndPara = rSttPara; + nEndCntnt = nSttCnt; + + // den Head korrigieren und die Verkettungen aufheben + pNext = 0; + pPrev = 0; + ppHead = ppHd; +} + +void _HTMLAttr::InsertPrev( _HTMLAttr *pPrv ) +{ + ASSERT( !pPrv->pNext || pPrv->pNext == this, + "_HTMLAttr::InsertPrev: pNext falsch" ); + pPrv->pNext = 0; + + ASSERT( 0 == pPrv->ppHead || ppHead == pPrv->ppHead, + "_HTMLAttr::InsertPrev: ppHead falsch" ); + pPrv->ppHead = 0; + + _HTMLAttr *pAttr = this; + while( pAttr->GetPrev() ) + pAttr = pAttr->GetPrev(); + + pAttr->pPrev = pPrv; +} + +bool SwHTMLParser::ParseMetaOptions( + const uno::Reference<document::XDocumentProperties> & i_xDocProps, + SvKeyValueIterator *i_pHeader ) +{ + // always call base ParseMetaOptions, it sets the encoding (#i96700#) + bool ret( HTMLParser::ParseMetaOptions(i_xDocProps, i_pHeader) ); + if (!ret && IsNewDoc()) + { + ParseMoreMetaOptions(); + } + return ret; +} + +// override so we can parse DOCINFO field subtypes INFO[1-4] +void SwHTMLParser::AddMetaUserDefined( ::rtl::OUString const & i_rMetaName ) +{ + // unless we already have 4 names, append the argument to m_InfoNames + ::rtl::OUString* pName // the first empty string in m_InfoNames + (!m_InfoNames[0].getLength() ? &m_InfoNames[0] : + (!m_InfoNames[1].getLength() ? &m_InfoNames[1] : + (!m_InfoNames[2].getLength() ? &m_InfoNames[2] : + (!m_InfoNames[3].getLength() ? &m_InfoNames[3] : 0 )))); + if (pName) + { + (*pName) = i_rMetaName; + } +} + diff --git a/sw/source/filter/html/swhtml.hxx b/sw/source/filter/html/swhtml.hxx new file mode 100644 index 000000000000..c7f897018dc7 --- /dev/null +++ b/sw/source/filter/html/swhtml.hxx @@ -0,0 +1,1040 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _SWHTML_HXX +#define _SWHTML_HXX + +#if !defined(_SVSTDARR_XUB_STRLEN_DECL) || !defined(_SVSTDARR_LONGS_DECL) || \ + !defined(_SVSTDARR_USHORTS_DECL) || !defined(_SVSTDARR_STRINGSDTOR_DECL) +#ifndef _SVSTDARR_XUB_STRLEN_DECL +#define _SVSTDARR_XUB_STRLEN +#endif +#ifndef _SVSTDARR_LONGS_DECL +#define _SVSTDARR_LONGS +#endif +#ifndef _SVSTDARR_USHORTS_DECL +#define _SVSTDARR_USHORTS +#endif +#ifndef _SVSTDARR_STRINGSDTOR_DECL +#define _SVSTDARR_STRINGSDTOR +#endif +#include <svl/svstdarr.hxx> +#endif +#include <tools/urlobj.hxx> +#include <sfx2/sfxhtml.hxx> +#include <svl/macitem.hxx> +#include <editeng/svxenum.hxx> +#include <fmtornt.hxx> +#include <com/sun/star/drawing/XShape.hpp> +#include <com/sun/star/form/XFormComponent.hpp> +#include <pam.hxx> + +#include "calbck.hxx" +#include "htmlvsh.hxx" + +class SfxMedium; +class SfxViewFrame; +class SdrObject; +class SvxMacroTableDtor; +class SvStringsDtor; +class SwDoc; +class SwPaM; +class ViewShell; +class SwStartNode; +class SwFmtColl; +class SwField; +class SwHTMLForm_Impl; +class SwApplet_Impl; +struct SwHTMLFootEndNote_Impl; +class HTMLTableCnts; +struct SwPendingStack; +class SvxCSS1PropertyInfo; + +#define HTML_PARSPACE (MM50) + +#define HTML_DFLT_IMG_WIDTH (MM50*4) +#define HTML_DFLT_IMG_HEIGHT (MM50*2) + +// ein par Sachen, die man oefter mal braucht +extern HTMLOptionEnum __FAR_DATA aHTMLPAlignTable[]; +extern HTMLOptionEnum __FAR_DATA aHTMLImgHAlignTable[]; +extern HTMLOptionEnum __FAR_DATA aHTMLImgVAlignTable[]; + + +// der Attribut Stack: + +class _HTMLAttr; +typedef _HTMLAttr *_HTMLAttrPtr; +SV_DECL_PTRARR( _HTMLAttrs, _HTMLAttrPtr, 5, 5 ) + +class _HTMLAttr +{ + friend class SwHTMLParser; + friend class _CellSaveStruct; + + SwNodeIndex nSttPara, nEndPara; + xub_StrLen nSttCntnt, nEndCntnt; + sal_Bool bInsAtStart : 1; + sal_Bool bLikePara : 1; // Attribut ueber dem gesamten Absatz setzen + sal_Bool bValid : 1; // ist das Attribut gueltig? + + SfxPoolItem* pItem; + sal_uInt16 nCount; // Anzahl noch zu schliessender Attrs mit einem Wert + _HTMLAttr *pNext; // noch zu schliessene Attrs mit unterschiedl. Werten + _HTMLAttr *pPrev; // bereits geschlossene aber noch nicht gesetze Attrs + _HTMLAttr **ppHead; // der Listenkopf + + _HTMLAttr( const SwPosition& rPos, const SfxPoolItem& rItem, + _HTMLAttr **pHd=0 ); + + _HTMLAttr( const _HTMLAttr &rAttr, const SwNodeIndex &rEndPara, + xub_StrLen nEndCnt, _HTMLAttr **pHd ); + +public: + + ~_HTMLAttr(); + + _HTMLAttr *Clone( const SwNodeIndex& rEndPara, xub_StrLen nEndCnt ) const; + void Reset( const SwNodeIndex& rSttPara, xub_StrLen nSttCnt, + _HTMLAttr **pHd ); + inline void SetStart( const SwPosition& rPos ); + + sal_uInt32 GetSttParaIdx() const { return nSttPara.GetIndex(); } + sal_uInt32 GetEndParaIdx() const { return nEndPara.GetIndex(); } + + const SwNodeIndex& GetSttPara() const { return nSttPara; } + const SwNodeIndex& GetEndPara() const { return nEndPara; } + + xub_StrLen GetSttCnt() const { return nSttCntnt; } + xub_StrLen GetEndCnt() const { return nEndCntnt; } + + sal_Bool IsLikePara() const { return bLikePara; } + void SetLikePara( sal_Bool bPara=sal_True ) { bLikePara = bPara; } + + SfxPoolItem& GetItem() { return *pItem; } + const SfxPoolItem& GetItem() const { return *pItem; } + + _HTMLAttr *GetNext() const { return pNext; } + void InsertNext( _HTMLAttr *pNxt ) { pNext = pNxt; } + + _HTMLAttr *GetPrev() const { return pPrev; } + void InsertPrev( _HTMLAttr *pPrv ); + void ClearPrev() { pPrev = 0; } + + void SetHead( _HTMLAttr **ppHd ) { ppHead = ppHd; } + + // Beim Setzen von Attributen aus Vorlagen kann es passieren, + // dass Attribute doch nicht mehr gesetzt werden sollen. Die zu loeschen + // waere sehr aufwendig, da man nicht so genau weiss, wo sie eingekettet + // sind. Sie werden deshalb einfach invalidiert und erst beim naechsten + // _SetAttr() geloescht. + void Invalidate() { bValid = sal_False; } + sal_Bool IsValid() const { return bValid; } +}; + +// Tabelle der Attribute: Hier ist die Reihenfolge wichtig: Die Attribute +// vorne in der Tabelle werden in EndAllAttrs auch zuerst gesetzt. +struct _HTMLAttrTable +{ + _HTMLAttr + *pKeep, // ::com::sun::star::frame::Frame-Attribure + *pBox, + *pBrush, + *pBreak, + *pPageDesc, + + *pLRSpace, // Absatz-Attribute + *pULSpace, + *pLineSpacing, + *pAdjust, + *pDropCap, + *pSplit, + *pWidows, + *pOrphans, + *pDirection, + + *pCharFmts, // Text-Attribute + *pINetFmt, + + *pBold, // Zeichen-Attribute + *pBoldCJK, + *pBoldCTL, + *pItalic, + *pItalicCJK, + *pItalicCTL, + *pStrike, + *pUnderline, + *pBlink, + *pFont, + *pFontCJK, + *pFontCTL, + *pFontHeight, + *pFontHeightCJK, + *pFontHeightCTL, + *pFontColor, + *pEscapement, + *pCaseMap, + *pKerning, // (nur fuer SPACER) + *pCharBrush, // Zeichen-Hintergrund + *pLanguage, + *pLanguageCJK, + *pLanguageCTL + ; +}; + +class _HTMLAttrContext_SaveDoc; + +enum SwHTMLAppendMode { + AM_NORMAL, // keine Absatz-Abstand-Behandlung + AM_NOSPACE, // Abstand hart auf 0cm setzen + AM_SPACE, // Abstand hart auf 0.5cm setzen + AM_SOFTNOSPACE, // Abstand nicht setzen aber 0cm merken + AM_NONE // gar kein Append +}; + +class _HTMLAttrContext +{ + _HTMLAttrs aAttrs; // die in dem Kontext gestarteten Attribute + + String aClass; // die Klasse des Kontexts + + _HTMLAttrContext_SaveDoc *pSaveDocContext; + SfxItemSet *pFrmItemSet; + + sal_uInt16 nToken; // das Token, zu dem der Kontext gehoehrt + + sal_uInt16 nTxtFmtColl; // eine in dem Kontext begonnene Vorlage oder 0 + + sal_uInt16 nLeftMargin; // ein veraenderter linker Rand + sal_uInt16 nRightMargin; // ein veraenderter rechter Rand + sal_uInt16 nFirstLineIndent; // ein veraenderter Erstzeilen-Einzug + + sal_uInt16 nUpperSpace; + sal_uInt16 nLowerSpace; + + SwHTMLAppendMode eAppend; + + sal_Bool bLRSpaceChanged : 1;// linker/rechtr Rand, Einzug veraendert? + sal_Bool bULSpaceChanged : 1;// oberer/unterer Rand veraendert? + sal_Bool bDfltTxtFmtColl : 1;// nTxtFmtColl ist nur ein default + sal_Bool bSpansSection : 1; // Der Kontext spannt eine SwSection auf + sal_Bool bPopStack : 1; // Oberhalb liegende Stack-Elemente entf. + sal_Bool bFinishPREListingXMP : 1; + sal_Bool bRestartPRE : 1; + sal_Bool bRestartXMP : 1; + sal_Bool bRestartListing : 1; + +public: + void ClearSaveDocContext(); + + _HTMLAttrContext( sal_uInt16 nTokn, sal_uInt16 nPoolId, const String& rClass, + sal_Bool bDfltColl=sal_False ) : + aClass( rClass ), + pSaveDocContext( 0 ), + pFrmItemSet( 0 ), + nToken( nTokn ), + nTxtFmtColl( nPoolId ), + nLeftMargin( 0 ), + nRightMargin( 0 ), + nFirstLineIndent( 0 ), + nUpperSpace( 0 ), + nLowerSpace( 0 ), + eAppend( AM_NONE ), + bLRSpaceChanged( sal_False ), + bULSpaceChanged( sal_False ), + bDfltTxtFmtColl( bDfltColl ), + bSpansSection( sal_False ), + bPopStack( sal_False ), + bFinishPREListingXMP( sal_False ), + bRestartPRE( sal_False ), + bRestartXMP( sal_False ), + bRestartListing( sal_False ) + {} + + _HTMLAttrContext( sal_uInt16 nTokn ) : + pSaveDocContext( 0 ), + pFrmItemSet( 0 ), + nToken( nTokn ), + nTxtFmtColl( 0 ), + nLeftMargin( 0 ), + nRightMargin( 0 ), + nFirstLineIndent( 0 ), + nUpperSpace( 0 ), + nLowerSpace( 0 ), + eAppend( AM_NONE ), + bLRSpaceChanged( sal_False ), + bULSpaceChanged( sal_False ), + bDfltTxtFmtColl( sal_False ), + bSpansSection( sal_False ), + bPopStack( sal_False ), + bFinishPREListingXMP( sal_False ), + bRestartPRE( sal_False ), + bRestartXMP( sal_False ), + bRestartListing( sal_False ) + {} + + ~_HTMLAttrContext() { ClearSaveDocContext(); delete pFrmItemSet; } + + sal_uInt16 GetToken() const { return nToken; } + + sal_uInt16 GetTxtFmtColl() const { return bDfltTxtFmtColl ? 0 : nTxtFmtColl; } + sal_uInt16 GetDfltTxtFmtColl() const { return bDfltTxtFmtColl ? nTxtFmtColl : 0; } + + const String& GetClass() const { return aClass; } + + inline void SetMargins( sal_uInt16 nLeft, sal_uInt16 nRight, short nIndent ); + + inline sal_Bool IsLRSpaceChanged() const { return bLRSpaceChanged; } + inline void GetMargins( sal_uInt16& nLeft, sal_uInt16& nRight, + short &nIndent ) const; + + inline void SetULSpace( sal_uInt16 nUpper, sal_uInt16 nLower ); + inline sal_Bool IsULSpaceChanged() const { return bULSpaceChanged; } + inline void GetULSpace( sal_uInt16& rUpper, sal_uInt16& rLower ) const; + + sal_Bool HasAttrs() const { return aAttrs.Count() != 0; } + const _HTMLAttrs& GetAttrs() const { return aAttrs; } + _HTMLAttrs& GetAttrs() { return aAttrs; } + + void SetSpansSection( sal_Bool bSet ) { bSpansSection = bSet; } + sal_Bool GetSpansSection() const { return bSpansSection; } + + void SetPopStack( sal_Bool bSet ) { bPopStack = bSet; } + sal_Bool GetPopStack() const { return bPopStack; } + + sal_Bool HasSaveDocContext() const { return pSaveDocContext!=0; } + _HTMLAttrContext_SaveDoc *GetSaveDocContext( sal_Bool bCreate=sal_False ); + + const SfxItemSet *GetFrmItemSet() const { return pFrmItemSet; } + SfxItemSet *GetFrmItemSet( SwDoc *pCreateDoc ); + + void SetFinishPREListingXMP( sal_Bool bSet ) { bFinishPREListingXMP = bSet; } + sal_Bool IsFinishPREListingXMP() const { return bFinishPREListingXMP; } + + void SetRestartPRE( sal_Bool bSet ) { bRestartPRE = bSet; } + sal_Bool IsRestartPRE() const { return bRestartPRE; } + + void SetRestartXMP( sal_Bool bSet ) { bRestartXMP = bSet; } + sal_Bool IsRestartXMP() const { return bRestartXMP; } + + void SetRestartListing( sal_Bool bSet ) { bRestartListing = bSet; } + sal_Bool IsRestartListing() const { return bRestartListing; } + + void SetAppendMode( SwHTMLAppendMode eMode=AM_NORMAL ) { eAppend = eMode; } + SwHTMLAppendMode GetAppendMode() const { return eAppend; } +}; + +typedef _HTMLAttrContext *_HTMLAttrContextPtr; +SV_DECL_PTRARR( _HTMLAttrContexts, _HTMLAttrContextPtr, 5, 5 ) + +class HTMLTable; +class SwCSS1Parser; +class SwHTMLNumRuleInfo; + +typedef ImageMap *ImageMapPtr; +SV_DECL_PTRARR_DEL( ImageMaps, ImageMapPtr, 1, 1 ) +typedef SwFrmFmt *SwFrmFmtPtr; +SV_DECL_PTRARR( SwHTMLFrmFmts, SwFrmFmtPtr, 2, 2 ) + +#define HTML_CNTXT_PROTECT_STACK 0x0001 +#define HTML_CNTXT_STRIP_PARA 0x0002 +#define HTML_CNTXT_KEEP_NUMRULE 0x0004 +#define HTML_CNTXT_HEADER_DIST 0x0008 +#define HTML_CNTXT_FOOTER_DIST 0x0010 +#define HTML_CNTXT_KEEP_ATTRS 0x0020 + +#define CONTEXT_FLAGS_ABSPOS \ + (HTML_CNTXT_PROTECT_STACK | \ + HTML_CNTXT_STRIP_PARA) + +#define HTML_FF_BOX 0x0001 +#define HTML_FF_BACKGROUND 0x0002 +#define HTML_FF_PADDING 0x0004 +#define HTML_FF_DIRECTION 0x0008 + +class SwHTMLParser : public SfxHTMLParser, public SwClient +{ + friend class _SectionSaveStruct; + friend class _CellSaveStruct; + friend class _CaptionSaveStruct; + + String aPathToFile; + String sBaseURL; + String sSaveBaseURL; + String aBasicLib; + String aBasicModule; + String aScriptSource; // Inhalt des aktuellen Script-Blocks + String aScriptType; // Type des gelesenen Scripts (StarBasic/VB/JAVA) + String aScriptURL; // URL eines Scripts + String aStyleSource; // Inhalt des aktuellen Style-Sheets + String aContents; // Text des akteullen Marquee, Feldes etc. + String sTitle; + String aUnknownToken; // ein gestartetes unbekanntes Token + String aBulletGrfs[MAXLEVEL]; + String sJmpMark; + + SvUShorts aBaseFontStack; // Stack fuer <BASEFONT> + // Bit 0-2: Fontgroesse (1-7) + SvUShorts aFontStack; // Stack fuer <FONT>, <BIG>, <SMALL> + // Bit 0-2: Fontgroesse (1-7) + // Bit 15: Fontfarbe wurde gesetzt + + _HTMLAttrs aSetAttrTab;// "geschlossene", noch nicht gesetzte Attr. + _HTMLAttrs aParaAttrs; // vorlauefige Absatz-Attribute + _HTMLAttrTable aAttrTab; // "offene" Attribute + _HTMLAttrContexts aContexts;// der aktuelle Attribut/Token-Kontext + SwHTMLFrmFmts aMoveFlyFrms;// Fly-Frames, the anchor is moved + SvXub_StrLens aMoveFlyCnts;// and the Content-Positions + + SwApplet_Impl *pAppletImpl; // das aktuelle Applet + + SwCSS1Parser *pCSS1Parser; // der Style-Sheet-Parser + SwHTMLNumRuleInfo *pNumRuleInfo; + SwPendingStack *pPendStack; + + SwDoc *pDoc; + SwPaM *pPam; // SwPosition duerfte doch reichen, oder ?? + ViewShell *pActionViewShell; // ViewShell, an der das StartAction + // gerufen wurde. + SwNodeIndex *pSttNdIdx; + + HTMLTable *pTable; // die aktuelle "auesserste" Tabelle + SwHTMLForm_Impl *pFormImpl;// die aktuelle Form + SdrObject *pMarquee; // aktuelles Marquee + SwField *pField; // aktuelles Feld + ImageMap *pImageMap; // aktuelle Image-Map + ImageMaps *pImageMaps;// alle gelesenen Image-Maps + SwHTMLFootEndNote_Impl *pFootEndNoteImpl; + + Size aHTMLPageSize; // die Seitengroesse der HTML-Vorlage + + sal_uInt32 aFontHeights[7]; // die Font-Hoehen 1-7 + sal_uInt32 nScriptStartLineNr; // Zeilennummer eines Script-Blocks + sal_uLong nEventId; + + sal_uInt16 nBaseFontStMin; // + sal_uInt16 nFontStMin; // + sal_uInt16 nDefListDeep; // + sal_uInt16 nFontStHeadStart; // Elemente im Font-Stack bei <Hn> + sal_uInt16 nSBModuleCnt; // Zaehler fuer Basic-Module + sal_uInt16 nMissingImgMaps; // Wie viele Image-Maps fehlen noch? + sal_uInt16 nParaCnt; + sal_uInt16 nContextStMin; // Untergrenze fuer PopContext + sal_uInt16 nContextStAttrMin; // Untergrenze fuer Attributierung + sal_uInt16 nSelectEntryCnt; // Anzahl der Eintraege der akt. Listbox + sal_uInt16 nOpenParaToken; // ein geoeffnetes Absatz-Element + + enum JumpToMarks { JUMPTO_NONE, JUMPTO_MARK, JUMPTO_TABLE, JUMPTO_FRAME, + JUMPTO_REGION, JUMPTO_GRAPHIC } eJumpTo; + +#ifdef DBG_UTIL + sal_uInt16 nContinue; // Tiefe der Continue-Aufrufe +#endif + + SvxAdjust eParaAdjust; // Ausrichtung des aktuellen Absatz + HTMLScriptLanguage eScriptLang; // die aktuelle Script-Language + + sal_Bool bOldIsHTMLMode : 1; // War's mal ein HTML-Dokument? + + sal_Bool bDocInitalized : 1; // Dokument bzw. Shell wurden initialisiert + // Flag um doppeltes init durch Rekursion + // zu verhindern. + sal_Bool bViewCreated : 1; // die View wurde schon erzeugt (asynchron) + sal_Bool bSetCrsr : 1; // Crsr wieder auf den Anfang setzen + sal_Bool bSetModEnabled : 1; + + sal_Bool bInFloatingFrame : 1; // Wir sind in einen Floating ::com::sun::star::frame::Frame + sal_Bool bInField : 1; + sal_Bool bKeepUnknown : 1; // unbekannte/nicht unterstuetze Tokens beh. + // 8 + sal_Bool bCallNextToken : 1; // In Tabellen: NextToken in jedem Fall rufen + sal_Bool bIgnoreRawData : 1; // Inhalt eines Scripts/Styles ignorieren. + sal_Bool bLBEntrySelected : 1; // Ist der aktuelle Listbox-Eintrag selekt. + sal_Bool bTAIgnoreNewPara : 1; // naechstes LF in TextArea ignorieren? + sal_Bool bFixMarqueeWidth : 1; // Groesse einer Laufschrift anpassen? + sal_Bool bFixMarqueeHeight : 1; + + sal_Bool bUpperSpace : 1; // obererer Absatz-Abstand wird benoetigt + sal_Bool bNoParSpace : 1; + // 16 + + sal_Bool bAnyStarBasic : 1; // gibt es ueberhaupt ein StarBasic-Modul + sal_Bool bInNoEmbed : 1; // Wir sind in einem NOEMBED-Bereich + + sal_Bool bInTitle : 1; // Wir sind im Titel + + sal_Bool bChkJumpMark : 1; // springe ggfs. zu einem vorgegebenem Mark + sal_Bool bUpdateDocStat : 1; + sal_Bool bFixSelectWidth : 1; // Breite eines Selects neu setzen? + sal_Bool bFixSelectHeight : 1; // Breite eines Selects neu setzen? + sal_Bool bTextArea : 1; + // 24 + sal_Bool bSelect : 1; + sal_Bool bInFootEndNoteAnchor : 1; + sal_Bool bInFootEndNoteSymbol : 1; + sal_Bool bIgnoreHTMLComments : 1; + sal_Bool bRemoveHidden : 1; // the filter implementation might set the hidden flag + + /// the names corresponding to the DOCINFO field subtypes INFO[1-4] + ::rtl::OUString m_InfoNames[4]; + + SfxViewFrame* pTempViewFrame; + + void DeleteFormImpl(); + + void DocumentDetected(); + void Show(); + void ShowStatline(); + ViewShell *CallStartAction( ViewShell *pVSh = 0, sal_Bool bChkPtr = sal_True ); + ViewShell *CallEndAction( sal_Bool bChkAction = sal_False, sal_Bool bChkPtr = sal_True ); + ViewShell *CheckActionViewShell(); + + DECL_LINK( AsyncCallback, void* ); + + // Attribute am Dok setzen + void _SetAttr( sal_Bool bChkEnd, sal_Bool bBeforeTable, _HTMLAttrs *pPostIts ); + inline void SetAttr( sal_Bool bChkEnd = sal_True, sal_Bool bBeforeTable = sal_False, + _HTMLAttrs *pPostIts = 0 ) + { + if( aSetAttrTab.Count() || aMoveFlyFrms.Count() ) + _SetAttr( bChkEnd, bBeforeTable, pPostIts ); + } + + _HTMLAttr **GetAttrTabEntry( sal_uInt16 nWhich ); + + // Einen neuen Textknoten an PaM-Position anlegen + sal_Bool AppendTxtNode( SwHTMLAppendMode eMode=AM_NORMAL, sal_Bool bUpdateNum=sal_True ); + void AddParSpace(); + + // Ein Attribut beginnen/beenden + // ppDepAttr gibt einen Attribut-Tabellen-Eintrag an, dessen Attribute + // gesetzt sein muessen, bevor das Attribut beendet werden darf + void NewAttr( _HTMLAttr **ppAttr, const SfxPoolItem& rItem ); + void EndAttr( _HTMLAttr *pAttr, _HTMLAttr **ppDepAttr=0, + sal_Bool bChkEmpty=sal_True ); + void DeleteAttr( _HTMLAttr* pAttr ); + + void EndContextAttrs( _HTMLAttrContext *pContext, sal_Bool bRemove=sal_False ); + void SaveAttrTab( _HTMLAttrTable& rNewAttrTab ); + void SplitAttrTab( const SwPosition& rNewPos ); + void SplitAttrTab( _HTMLAttrTable& rNewAttrTab, sal_Bool bMoveEndBack = sal_True ); + void RestoreAttrTab( const _HTMLAttrTable& rNewAttrTab, + sal_Bool bSetNewStart = sal_False ); + void InsertAttr( const SfxPoolItem& rItem, sal_Bool bLikePara = sal_False, + sal_Bool bInsAtStart=sal_False ); + void InsertAttrs( _HTMLAttrs& rAttrs ); + + sal_Bool DoPositioning( SfxItemSet &rItemSet, + SvxCSS1PropertyInfo &rPropInfo, + _HTMLAttrContext *pContext ); + sal_Bool CreateContainer( const String& rClass, SfxItemSet &rItemSet, + SvxCSS1PropertyInfo &rPropInfo, + _HTMLAttrContext *pContext ); + sal_Bool EndSection( sal_Bool bLFStripped=sal_False ); + + void InsertAttrs( SfxItemSet &rItemSet, SvxCSS1PropertyInfo &rPropInfo, + _HTMLAttrContext *pContext, sal_Bool bCharLvl=sal_False ); + void InsertAttr( _HTMLAttr **ppAttr, const SfxPoolItem & rItem, + _HTMLAttrContext *pCntxt ); + void SplitPREListingXMP( _HTMLAttrContext *pCntxt ); + void FixHeaderFooterDistance( sal_Bool bHeader, const SwPosition *pOldPos ); + + void EndContext( _HTMLAttrContext *pContext ); + void ClearContext( _HTMLAttrContext *pContext ); + + const SwFmtColl *GetCurrFmtColl() const; + + SwTwips GetCurrentBrowseWidth(); + + SwHTMLNumRuleInfo& GetNumInfo() { return *pNumRuleInfo; } + // --> OD 2008-04-02 #refactorlists# + // add parameter <bCountedInList> + void SetNodeNum( sal_uInt8 nLevel, bool bCountedInList ); + // <-- + + // Verwalten von Absatz-Vorlagen + + // die Vorlagen auf dem Stack bzw. deren Attribute setzen + void SetTxtCollAttrs( _HTMLAttrContext *pContext = 0 ); + + void InsertParaAttrs( const SfxItemSet& rItemSet ); + + // Verwalten des Attribut-Kontexts + + // aktuellen Kontext merken + inline void PushContext( _HTMLAttrContext *pCntxt ); + + // den obersten/spezifizierten Kontext holen, aber nicht ausserhalb + // des Kontexts mit Token nLimit suchen. Wenn bRemove gesetzt ist, + // wird er entfernt + _HTMLAttrContext *PopContext( sal_uInt16 nToken=0, sal_uInt16 nLimit=0, + sal_Bool bRemove=sal_True ); + inline const _HTMLAttrContext *GetTopContext() const; + + sal_Bool GetMarginsFromContext( sal_uInt16 &nLeft, sal_uInt16 &nRight, short& nIndent, + sal_Bool bIgnoreCurrent=sal_False ) const; + sal_Bool GetMarginsFromContextWithNumBul( sal_uInt16 &nLeft, sal_uInt16 &nRight, + short& nIndent ) const; + void GetULSpaceFromContext( sal_uInt16 &rUpper, sal_uInt16 &rLower ) const; + + + void MovePageDescAttrs( SwNode *pSrcNd, sal_uLong nDestIdx, sal_Bool bFmtBreak ); + + // Behandlung von Tags auf Absatz-Ebene + + // <P> und <H1> bis <H6> + void NewPara(); + void EndPara( sal_Bool bReal = sal_False ); + void NewHeading( int nToken ); + void EndHeading(); + + // <ADDRESS>, <BLOCKQUOTE> und <PRE> + void NewTxtFmtColl( int nToken, sal_uInt16 nPoolId ); + void EndTxtFmtColl( int nToken ); + + // <DIV> und <CENTER> + void NewDivision( int nToken ); + void EndDivision( int nToken ); + + // Fly-Frames einfuegen/verlassen + void InsertFlyFrame( const SfxItemSet& rItemSet, _HTMLAttrContext *pCntxt, + const String& rId, sal_uInt16 nFlags ); + + void SaveDocContext( _HTMLAttrContext *pCntxt, sal_uInt16 nFlags, + const SwPosition *pNewPos ); + void RestoreDocContext( _HTMLAttrContext *pCntxt ); + + // alle durch <DIV> aufgespannten Bereiche verlassen + sal_Bool EndSections( sal_Bool bLFStripped ); + + // <MULTICOL> + void NewMultiCol(); + void EndMultiCol(); + + // <MARQUEE> + void NewMarquee( HTMLTable *pCurTable=0 ); + void EndMarquee(); + void InsertMarqueeText(); + + // Behandluung von Listen + + // Numerierungs <OL> und Aufzaehlungs-Listen <UL> mit <LI> + void NewNumBulList( int nToken ); + void EndNumBulList( int nToken=0 ); + void NewNumBulListItem( int nToken ); + void EndNumBulListItem( int nToken=0, sal_Bool bSetColl=sal_True, + sal_Bool bLastPara=sal_False ); + + // Definitions-Listen <DL> mit <DD>, <DT> + void NewDefList(); + void EndDefList(); + void NewDefListItem( int nToken ); + void EndDefListItem( int nToken=0, sal_Bool bSetColl=sal_True, + sal_Bool bLastPara=sal_False ); + + + // Behandlung von Tags auf Zeichen-Ebene + + // Tags wie <B>, <I> etc behandeln, die ein bestimmtes Attribut + // an und ausschalten, oder die wie SPAN nur Attribute aus Styles holen + void NewStdAttr( int nToken ); + void NewStdAttr( int nToken, + _HTMLAttr **ppAttr, const SfxPoolItem & rItem, + _HTMLAttr **ppAttr2=0, const SfxPoolItem *pItem2=0, + _HTMLAttr **ppAttr3=0, const SfxPoolItem *pItem3=0 ); + void EndTag( int nToken ); + + // Font-Attribute behandeln + void NewBasefontAttr(); // fuer <BASEFONT> + void EndBasefontAttr(); + void NewFontAttr( int nToken ); // fuer <FONT>, <BIG> und <SMALL> + void EndFontAttr( int nToken ); + + // Tags, die durch Zeichenvorlagen realisiert werden + void NewCharFmt( int nToken ); + + // <SDFIELD> +public: + static sal_uInt16 GetNumType( const String& rStr, sal_uInt16 eDfltType ); +private: + void NewField(); + void EndField(); + void InsertFieldText(); + + // <SPACER> + void InsertSpacer(); + + // Einfuegen von Grafiken, Plugins und Applets + + // Image-Maps suchen und mit Grafik-Nodes verbinden + ImageMap *FindImageMap( const String& rURL ) const; + void ConnectImageMaps(); + + // Verankerung eines Fly-Frames bestimmen und entsprechende Attribute + // in den Attrset setzen (htmlgrin.cxx) + void SetAnchorAndAdjustment( sal_Int16 eVertOri, + sal_Int16 eHoriOri, + const SfxItemSet &rItemSet, + const SvxCSS1PropertyInfo &rPropInfo, + SfxItemSet& rFrmSet ); + void SetAnchorAndAdjustment( sal_Int16 eVertOri, + sal_Int16 eHoriOri, + SfxItemSet& rFrmSet, + sal_Bool bDontAppend=sal_False ); + void SetAnchorAndAdjustment( const SfxItemSet &rItemSet, + const SvxCSS1PropertyInfo &rPropInfo, + SfxItemSet &rFrmItemSet ); + + void SetFrmFmtAttrs( SfxItemSet &rItemSet, SvxCSS1PropertyInfo &rPropInfo, + sal_uInt16 nFlags, SfxItemSet &rFrmItemSet ); + + // Frames anlegen und Auto-gebundene Rahmen registrieren + void RegisterFlyFrm( SwFrmFmt *pFlyFrm ); + + // Die Groesse des Fly-Frames an die Vorgaben und Gegebenheiten anpassen + // (nicht fuer Grafiken, deshalb htmlplug.cxx) + void SetFixSize( const Size& rPixSize, const Size& rTwipDfltSize, + sal_Bool bPrcWidth, sal_Bool bPrcHeight, + SfxItemSet &rItemSet, SvxCSS1PropertyInfo &rPropInfo, + SfxItemSet& rFlyItemSet ); + void SetVarSize( SfxItemSet &rItemSet, SvxCSS1PropertyInfo &rPropInfo, + SfxItemSet& rFlyItemSet, SwTwips nDfltWidth=MINLAY, + sal_uInt8 nDltPrcWidth=0 ); + void SetSpace( const Size& rPixSpace, SfxItemSet &rItemSet, + SvxCSS1PropertyInfo &rPropInfo, SfxItemSet& rFlyItemSet ); + + sal_uInt16 IncGrfsThatResizeTable(); + + void GetDefaultScriptType( ScriptType& rType, + String& rTypeStr ) const; + + // die eigentlichen Einfuege-Methoden fuer <IMG>, <EMBED> und <APPLET> + // und <PARAM> + void InsertImage(); // htmlgrin.cxx + void InsertEmbed(); // htmlplug.cxx + +#ifdef SOLAR_JAVA + void NewObject(); // htmlplug.cxx +#endif + void EndObject(); // CommandLine mit Applet verkn. (htmlplug.cxx) +#ifdef SOLAR_JAVA + void InsertApplet(); // htmlplug.cxx +#endif + void EndApplet(); // CommandLine mit Applet verkn. (htmlplug.cxx) + void InsertParam(); // htmlplug.cxx + + void InsertFloatingFrame(); + void EndFloatingFrame() { bInFloatingFrame = sal_False; } + + // <BODY>-Tag auswerten: Hintergrund-Grafiken und -Farben setzen (htmlgrin.cxx) + void InsertBodyOptions(); + + + // Einfuegen von Links und ::com::sun::star::text::Bookmarks (htmlgrin.cxx) + + // <A>-Tag auswerten: einen Link bzw. eine ::com::sun::star::text::Bookmark einfuegen + void NewAnchor(); + void EndAnchor(); + + // eine ::com::sun::star::text::Bookmark einfuegen + void InsertBookmark( const String& rName ); + + + void InsertCommentText( const sal_Char *pTag = 0 ); + void InsertComment( const String& rName, const sal_Char *pTag = 0 ); + + // sind im aktuellen Absatz ::com::sun::star::text::Bookmarks vorhanden? + sal_Bool HasCurrentParaBookmarks( sal_Bool bIgnoreStack=sal_False ) const; + + + // Einfuegen von Script/Basic-Elementen + + // das zueletzt gelsene Basic-Modul parsen (htmlbas.cxx) + void NewScript(); + void EndScript(); + + void AddScriptSource(); + + // ein Event in die SFX-Konfiguation eintragen (htmlbas.cxx) + void InsertBasicDocEvent( rtl::OUString aEventName, const String& rName, + ScriptType eScrType, const String& rScrType ); + + // ein Event an ein VC-Control anhaengen (htmlform.cxx) + void InsertBasicCtrlEvent( sal_uInt16 nEvent, const String& rName ); + + // Einfuegen von Styles + + // <STYLE> + void NewStyle(); + void EndStyle(); + + inline sal_Bool HasStyleOptions( const String &rStyle, const String &rId, + const String &rClass, const String *pLang=0, + const String *pDir=0 ); + sal_Bool ParseStyleOptions( const String &rStyle, const String &rId, + const String &rClass, SfxItemSet &rItemSet, + SvxCSS1PropertyInfo &rPropInfo, + const String *pLang=0, const String *pDir=0 ); + + + // Einfuegen von Controls und ::com::sun::star::form::Forms (htmlform.cxx) + + // Ein Draw-Objekt in das Dokuement eintragen + void InsertDrawObject( SdrObject* pNewDrawObj, const Size& rSpace, + sal_Int16 eVertOri, + sal_Int16 eHoriOri, + SfxItemSet& rCSS1ItemSet, + SvxCSS1PropertyInfo& rCSS1PropInfo, + sal_Bool bHidden=sal_False ); + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > InsertControl( const ::com::sun::star::uno::Reference< ::com::sun::star::form::XFormComponent > & rFormComp, + const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > & rFCompPropSet, + const Size& rSize, + sal_Int16 eVertOri, + sal_Int16 eHoriOri, + SfxItemSet& rCSS1ItemSet, + SvxCSS1PropertyInfo& rCSS1PropInfo, + const SvxMacroTableDtor& rMacroTbl, + const SvStringsDtor& rUnoMacroTbl, + const SvStringsDtor& rUnoMacroParamTbl, + sal_Bool bSetPropSet = sal_True, + sal_Bool bHidden = sal_False ); + void SetControlSize( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > & rShape, const Size& rTextSz, + sal_Bool bMinWidth, sal_Bool bMinHeight, int nToken ); + void SetPendingControlSize( int nToken ); + +public: + void ResizeDrawObject( SdrObject* pObj, SwTwips nWidth ); +private: + void RegisterDrawObjectToTable( HTMLTable *pCurTable, SdrObject* pObj, + sal_uInt8 nWidth ); + + + // eine neue Form beginnen + void NewForm( sal_Bool bAppend=sal_True ); + void EndForm( sal_Bool bAppend=sal_True ); + + // die Einfuege-Methoden fuer <INPUT>, <TEXTAREA> und <SELECT> + void InsertInput(); + + void NewTextArea(); + void InsertTextAreaText( sal_uInt16 nToken ); + void EndTextArea(); + + void NewSelect(); + void InsertSelectOption(); + void InsertSelectText(); + void EndSelect(); + + // Einfuegen von Tabellen (htmltab.cxx) + +public: // wird in Tabellen benoetigt + + // einen Boxen-Inhalt hinter dem angegebenen Node einfuegen + const SwStartNode *InsertTableSection( const SwStartNode *pPrevStNd ); + + // Einen Boxen-Inhalt am Ende der Tabelle einfuegen, in der der PaM + // steht un den PaM in die Zelle schieben + const SwStartNode *InsertTableSection( sal_uInt16 nPoolId ); + + // Einfeuge-Methoden fuer die diversen Tabellen-Tags + HTMLTableCnts *InsertTableContents( sal_Bool bHead ); + +private: + // Eine Section fuer die voruebergende Aufnahme der Tabellen-Ueberschrift + // anlegen + SwStartNode *InsertTempTableCaptionSection(); + + void BuildTableCell( HTMLTable *pTable, sal_Bool bReadOptions, sal_Bool bHead ); + void BuildTableRow( HTMLTable *pTable, sal_Bool bReadOptions, + SvxAdjust eGrpAdjust, sal_Int16 eVertOri ); + void BuildTableSection( HTMLTable *pTable, sal_Bool bReadOptions, sal_Bool bHead ); + void BuildTableColGroup( HTMLTable *pTable, sal_Bool bReadOptions ); + void BuildTableCaption( HTMLTable *pTable ); + HTMLTable *BuildTable( SvxAdjust eCellAdjust, + sal_Bool bIsParentHead = sal_False, + sal_Bool bHasParentSection=sal_True, + sal_Bool bIsInMulticol = sal_False, + sal_Bool bHasToFlow = sal_False ); + + + // sonstiges ... + + void ParseMoreMetaOptions(); + + sal_Bool FileDownload( const String& rURL, String& rStr ); + void InsertLink(); + + void InsertIDOption(); + void InsertLineBreak(); + void InsertHorzRule(); + + void FillEndNoteInfo( const String& rContent ); + void FillFootNoteInfo( const String& rContent ); + void InsertFootEndNote( const String& rName, sal_Bool bEndNote, sal_Bool bFixed ); + void FinishFootEndNote(); + void InsertFootEndNoteText(); + SwNodeIndex *GetFootEndNoteSection( const String& rName ); + void DeleteFootEndNoteImpl(); + + // Line-Break am Ende eines Absatzes entfernen + xub_StrLen StripTrailingLF(); + + // Einen leeren Absatz an der PaM-Position entfernen + void StripTrailingPara(); + + // sind im aktuellen Absatz Fly-Frames vorhanden? + sal_Bool HasCurrentParaFlys( sal_Bool bNoSurroundOnly = sal_False, + sal_Bool bSurroundOnly = sal_False ) const; + +public: // wird in Tabellen benoetigt + + // generieren eines BrushItems (mit new) oder 0 + SvxBrushItem* CreateBrushItem( const Color *pColor, + const String &rImageURL, + const String &rStyle, + const String &rId, + const String &rClass ); + +protected: + // wird fuer jedes Token gerufen, das in CallParser erkannt wird + virtual void NextToken( int nToken ); + virtual ~SwHTMLParser(); + + // wird das Dok geloescht, ist auch der Parser zu loeschen + virtual void Modify( SfxPoolItem *pOld, SfxPoolItem *pNew ); + + virtual void AddMetaUserDefined( ::rtl::OUString const & i_rMetaName ); + +public: + + SwHTMLParser( SwDoc* pD, const SwPaM& rCrsr, SvStream& rIn, + const String& rFileName, + const String& rBaseURL, + int bReadNewDoc = sal_True, + SfxMedium* pMed = 0, sal_Bool bReadUTF8 = sal_False, + sal_Bool bIgnoreHTMLComments = sal_False ); + + virtual SvParserState CallParser(); // Aufruf des Parsers + + + sal_uInt16 ToTwips( sal_uInt16 nPixel ) const; + + // fuers asynchrone lesen aus dem SvStream + virtual void Continue( int nToken ); + + virtual bool ParseMetaOptions( const ::com::sun::star::uno::Reference< + ::com::sun::star::document::XDocumentProperties>&, + SvKeyValueIterator* ); +}; + + +struct SwPendingStackData +{ + virtual ~SwPendingStackData() {} +}; + +struct SwPendingStack +{ + int nToken; + SwPendingStackData* pData; + SwPendingStack* pNext; + + SwPendingStack( int nTkn, SwPendingStack* pNxt ) + : nToken( nTkn ), pData( 0 ), pNext( pNxt ) + {} +}; + +inline void _HTMLAttr::SetStart( const SwPosition& rPos ) +{ + nSttPara = rPos.nNode; + nSttCntnt = rPos.nContent.GetIndex(); + nEndPara = nSttPara; + nEndCntnt = nSttCntnt; +} + +inline void _HTMLAttrContext::SetMargins( sal_uInt16 nLeft, sal_uInt16 nRight, + short nIndent ) +{ + nLeftMargin = nLeft; + nRightMargin = nRight; + nFirstLineIndent = nIndent; + bLRSpaceChanged = sal_True; +} + +inline void _HTMLAttrContext::GetMargins( sal_uInt16& nLeft, + sal_uInt16& nRight, + short& nIndent ) const +{ + if( bLRSpaceChanged ) + { + nLeft = nLeftMargin; + nRight = nRightMargin; + nIndent = nFirstLineIndent; + } +} + +inline void _HTMLAttrContext::SetULSpace( sal_uInt16 nUpper, sal_uInt16 nLower ) +{ + nUpperSpace = nUpper; + nLowerSpace = nLower; + bULSpaceChanged = sal_True; +} + +inline void _HTMLAttrContext::GetULSpace( sal_uInt16& rUpper, + sal_uInt16& rLower ) const +{ + if( bULSpaceChanged ) + { + rUpper = nUpperSpace; + rLower = nLowerSpace; + } +} + +inline sal_Bool SwHTMLParser::HasStyleOptions( const String &rStyle, + const String &rId, + const String &rClass, + const String *pLang, + const String *pDir ) +{ + return rStyle.Len() || rId.Len() || rClass.Len() || + (pLang && pLang->Len()) || (pDir && pDir->Len()); +} + +inline const _HTMLAttrContext *SwHTMLParser::GetTopContext() const +{ + return aContexts.Count() > nContextStMin + ? aContexts[aContexts.Count()-1] : 0; +} + +inline void SwHTMLParser::PushContext( _HTMLAttrContext *pCntxt ) +{ + aContexts.Insert( pCntxt, aContexts.Count() ); +} + + +#endif + + diff --git a/sw/source/filter/html/wrthtml.cxx b/sw/source/filter/html/wrthtml.cxx new file mode 100644 index 000000000000..0e14dc1f42de --- /dev/null +++ b/sw/source/filter/html/wrthtml.cxx @@ -0,0 +1,1439 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <stdlib.h> +#include <hintids.hxx> +#include <svl/urihelper.hxx> +#include <rtl/tencinfo.h> +#include <vcl/wrkwin.hxx> +#include <sfx2/linkmgr.hxx> + +#include <svtools/htmlcfg.hxx> +#include <vcl/svapp.hxx> +#include <i18npool/mslangid.hxx> +#include <sfx2/frmhtmlw.hxx> +#include <svx/xoutbmp.hxx> +#include <svx/htmlmode.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/brshitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/scripttypeitem.hxx> +#include <editeng/langitem.hxx> +#include <svl/stritem.hxx> +#include <editeng/frmdiritem.hxx> + +#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> +#include <com/sun/star/document/XDocumentProperties.hpp> +#include <com/sun/star/form/XFormsSupplier.hpp> +#include <com/sun/star/form/XForm.hpp> +#include <com/sun/star/form/XImageProducerSupplier.hpp> +#include <com/sun/star/form/XFormController.hpp> +#include <com/sun/star/container/XContainer.hpp> +#include <com/sun/star/container/XIndexContainer.hpp> +#include <com/sun/star/container/XSet.hpp> +#include <fmthdft.hxx> +#include <fmtfld.hxx> +#include <fmtpdsc.hxx> +#include <txatbase.hxx> +#include <frmatr.hxx> +#include <charfmt.hxx> +#include <docary.hxx> +#include <pam.hxx> +#include <doc.hxx> +#include <ndtxt.hxx> +#include <mdiexp.hxx> // ...Percent() +#include <fltini.hxx> +#include <viewopt.hxx> +#include <IMark.hxx> // fuer SwBookmark ... +#include <poolfmt.hxx> +#include <pagedesc.hxx> +#include <section.hxx> +#include <swtable.hxx> +#include <fldbas.hxx> +#include <fmtclds.hxx> +#ifndef _DOCSH_HXX +#include <docsh.hxx> +#endif +#include <wrthtml.hxx> +#include <htmlnum.hxx> +#include <htmlfly.hxx> +#include <swmodule.hxx> + +#ifndef _STATSTR_HRC +#include <statstr.hrc> // ResId fuer Statusleiste +#endif +#include <swerror.h> + +#define MAX_INDENT_LEVEL 20 + +#if defined(UNX) +const sal_Char SwHTMLWriter::sNewLine = '\012'; +#else +const sal_Char __FAR_DATA SwHTMLWriter::sNewLine[] = "\015\012"; +#endif + +static sal_Char __FAR_DATA sIndentTabs[MAX_INDENT_LEVEL+2] = + "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; + +SwHTMLWriter::SwHTMLWriter( const String& rBaseURL ) +{ + SetBaseURL( rBaseURL ); + bFirstLine = sal_True; + nBkmkTabPos = -1; + pDfltColor = 0; + nImgMapCnt = 1; + pStartNdIdx = 0; + pTemplate = 0; + pNumRuleInfo = new SwHTMLNumRuleInfo; + pNextNumRuleInfo = 0; + pFootEndNotes = 0; + pFmtFtn = 0; + eDestEnc = RTL_TEXTENCODING_MS_1252; + nDirection = FRMDIR_HORI_LEFT_TOP; +} + + +__EXPORT SwHTMLWriter::~SwHTMLWriter() +{ + delete pNumRuleInfo; +} + +sal_uLong SwHTMLWriter::WriteStream() +{ + // neue Konfiguration setzen + SvxHtmlOptions* pHtmlOptions = SvxHtmlOptions::Get(); + + // die Fontgroessen 1-7 + aFontHeights[0] = pHtmlOptions->GetFontSize( 0 ) * 20; + aFontHeights[1] = pHtmlOptions->GetFontSize( 1 ) * 20; + aFontHeights[2] = pHtmlOptions->GetFontSize( 2 ) * 20; + aFontHeights[3] = pHtmlOptions->GetFontSize( 3 ) * 20; + aFontHeights[4] = pHtmlOptions->GetFontSize( 4 ) * 20; + aFontHeights[5] = pHtmlOptions->GetFontSize( 5 ) * 20; + aFontHeights[6] = pHtmlOptions->GetFontSize( 6 ) * 20; + + // ueberhaupt Styles ausgeben + // (dann auch obere und untere Absatz-Abstaende) + nExportMode = pHtmlOptions->GetExportMode(); + nHTMLMode = GetHtmlMode(0); + if( HTML_CFG_WRITER==nExportMode || + HTML_CFG_NS40==nExportMode ) + nHTMLMode |= HTMLMODE_BLOCK_SPACER; + + if( HTML_CFG_WRITER==nExportMode || HTML_CFG_MSIE==nExportMode ) + nHTMLMode |= (HTMLMODE_FLOAT_FRAME | HTMLMODE_LSPACE_IN_NUMBUL); + + if( HTML_CFG_MSIE==nExportMode ) + nHTMLMode |= HTMLMODE_NBSP_IN_TABLES; + + if( HTML_CFG_WRITER==nExportMode || HTML_CFG_NS40==nExportMode || + HTML_CFG_MSIE==nExportMode ) + nHTMLMode |= HTMLMODE_ABS_POS_FLY|HTMLMODE_ABS_POS_DRAW; + + if( HTML_CFG_WRITER==nExportMode ) +// nHTMLMode |= HTMLMODE_FLY_MARGINS | HTMLMODE_FRSTLINE_IN_NUMBUL; + nHTMLMode |= HTMLMODE_FLY_MARGINS; + + if( HTML_CFG_NS40==nExportMode ) + nHTMLMode |= HTMLMODE_BORDER_NONE; + + if( HTML_CFG_HTML32!=nExportMode ) + nHTMLMode |= HTMLMODE_FONT_GENERIC; + + if( HTML_CFG_NS40==nExportMode ) + nHTMLMode |= HTMLMODE_NO_CONTROL_CENTERING; + + bCfgOutStyles = IsHTMLMode(HTMLMODE_SOME_STYLES | + HTMLMODE_FULL_STYLES); + bCfgNetscape4 = (HTML_CFG_NS40==nExportMode); + + if( IsHTMLMode(HTMLMODE_SOME_STYLES | HTMLMODE_FULL_STYLES) ) + nHTMLMode |= HTMLMODE_PRINT_EXT; + + const sal_Char *pHelpHack = getenv( "HelpEx" ); + if( pHelpHack ) + { + ByteString aTmp( pHelpHack ); + if( aTmp.EqualsIgnoreCaseAscii( "Hilfe" ) ) + nHTMLMode |= HTMLMODE_NO_BR_AT_PAREND; + } + + eCSS1Unit = (FieldUnit)SW_MOD()->GetMetric( pDoc->get(IDocumentSettingAccess::HTML_MODE) ); + + sal_Bool bWriteUTF8 = bWriteClipboardDoc; + eDestEnc = bWriteUTF8 ? RTL_TEXTENCODING_UTF8 + : pHtmlOptions->GetTextEncoding(); + const sal_Char *pCharSet = + rtl_getBestMimeCharsetFromTextEncoding( eDestEnc ); + eDestEnc = rtl_getTextEncodingFromMimeCharset( pCharSet ); + + // fuer Netscape optimieren heisst Spacer- und Multicol ausgeben +// bCfgMultiCol = pHtmlOptions->IsNetscape3(); +// bCfgSpacer = pHtmlOptions->IsNetscape3(); + + // wenn Styles exportiert werden, wird ein Style einem HTML-Tag manchmal + // vorgezogen, wenn nicht fuer Netscape exportiert wird + // bCfgPreferStyles = bCfgOutStyles; // && !pHtmlOptions->IsNetscape3(); + + // Nur noch fuer den MS-IE ziehen wir den Export von Styles vor. + bCfgPreferStyles = HTML_CFG_MSIE==nExportMode; + + bCfgStarBasic = pHtmlOptions->IsStarBasic(); + + bCfgFormFeed = !IsHTMLMode(HTMLMODE_PRINT_EXT); + bCfgCpyLinkedGrfs = pHtmlOptions->IsSaveGraphicsLocal(); + + // die HTML-Vorlage holen + sal_Bool bOldHTMLMode = sal_False; + sal_uInt16 nOldTxtFmtCollCnt = 0, nOldCharFmtCnt = 0; + + ASSERT( !pTemplate, "Wo kommt denn die HTML-Vorlage hier her?" ); + pTemplate = ((HTMLReader*)ReadHTML)->GetTemplateDoc(); + if( pTemplate ) + { + pTemplate->acquire(); + bOldHTMLMode = pTemplate->get(IDocumentSettingAccess::HTML_MODE); + pTemplate->set(IDocumentSettingAccess::HTML_MODE, true); + + nOldTxtFmtCollCnt = pTemplate->GetTxtFmtColls()->Count(); + nOldCharFmtCnt = pTemplate->GetCharFmts()->Count(); + } + + if( bShowProgress ) + ::StartProgress( STR_STATSTR_W4WWRITE, 0, pDoc->GetNodes().Count(), + pDoc->GetDocShell()); + + pDfltColor = 0; + pFootEndNotes = 0; + pFmtFtn = 0; + bOutTable = bOutHeader = bOutFooter = bOutFlyFrame = sal_False; + pxFormComps = 0; + nFormCntrlCnt = 0; + bPreserveForm = sal_False; + bClearLeft = bClearRight = sal_False; + bLFPossible = sal_False; + + nLeftMargin = nDfltLeftMargin = nDfltRightMargin = 0; + nDfltTopMargin = nDfltBottomMargin = 0; + nFirstLineIndent = nDfltFirstLineIndent = 0; + bPoolCollTextModified = sal_False; + bFirstCSS1Property = bFirstCSS1Rule = sal_False; + bCSS1IgnoreFirstPageDesc = sal_False; + nIndentLvl = 0; + nWhishLineLen = 70; + nLastLFPos = 0; + nDefListLvl = 0; + nDefListMargin = ((pTemplate && !bCfgOutStyles) ? pTemplate : pDoc) + ->GetTxtCollFromPool( RES_POOLCOLL_HTML_DD, false ) + ->GetLRSpace().GetTxtLeft(); + nHeaderFooterSpace = 0; + nTxtAttrsToIgnore = 0; + nCSS1OutMode = 0; + sal_uInt16 nScript = SvtLanguageOptions::GetScriptTypeOfLanguage( + static_cast< LanguageType >( GetAppLanguage() ) ); + switch( nScript ) + { + case SCRIPTTYPE_ASIAN: + nCSS1Script = CSS1_OUTMODE_CJK; + break; + case SCRIPTTYPE_COMPLEX: + nCSS1Script = CSS1_OUTMODE_CTL; + break; + default: + nCSS1Script = CSS1_OUTMODE_WESTERN; + break; + } + eLang = ((const SvxLanguageItem&)pDoc + ->GetDefault(GetLangWhichIdFromScript(nCSS1Script))).GetLanguage(); + + nFootNote = nEndNote = 0; + + nWarn = 0; + GetNumInfo().Clear(); + pNextNumRuleInfo = 0; + + ByteString aStartTags; + + // Tabellen und Bereiche am Doc.-Anfang beachten + { + SwTableNode * pTNd = pCurPam->GetNode()->FindTableNode(); + if( pTNd && bWriteAll ) + { + // mit dem Tabellen-Node anfangen !! + pCurPam->GetPoint()->nNode = *pTNd; + + if( bWriteOnlyFirstTable ) + pCurPam->GetMark()->nNode = *pTNd->EndOfSectionNode(); + } + + // erster Node (der einen Seitenumbruch enthalten darf) + pStartNdIdx = new SwNodeIndex( pCurPam->GetPoint()->nNode ); + + SwSectionNode * pSNd = pCurPam->GetNode()->FindSectionNode(); + while( pSNd ) + { + if( bWriteAll ) + { + // mit dem Section-Node anfangen !! + pCurPam->GetPoint()->nNode = *pSNd; + } + else + { + ASSERT( FILE_LINK_SECTION != pSNd->GetSection().GetType(), + "Export gelinkter Bereiche am Dok-Anfang ist nicht implemntiert" ); + + // nur das Tag fuer die Section merken + ByteString aName; + HTMLOutFuncs::ConvertStringToHTML( + pSNd->GetSection().GetSectionName(), + aName, eDestEnc, &aNonConvertableCharacters ); + + ByteString sOut( '<' ); + (((((((sOut += OOO_STRING_SVTOOLS_HTML_division) + += ' ') += OOO_STRING_SVTOOLS_HTML_O_id) += "=\"") + += aName) += '\"') + += '>') += aStartTags; + + aStartTags = sOut; + } + // FindSectionNode() an einem SectionNode liefert den selben! + pSNd = pSNd->StartOfSectionNode()->FindSectionNode(); + } + } + + + // Tabelle fuer die freifliegenden Rahmen erzeugen, aber nur wenn + // das gesamte Dokument geschrieben wird + pHTMLPosFlyFrms = 0; + CollectFlyFrms(); + nLastParaToken = 0; + GetControls(); + CollectLinkTargets(); + + sal_uInt16 nHeaderAttrs = 0; + pCurrPageDesc = MakeHeader( nHeaderAttrs ); + + bLFPossible = sal_True; + + // Formulare, die nur HiddenControls enthalten ausgeben. + OutHiddenForms(); + + if( aStartTags.Len() ) + Strm() << aStartTags.GetBuffer(); + + const SfxPoolItem *pItem; + const SfxItemSet& rPageItemSet = pCurrPageDesc->GetMaster().GetAttrSet(); + if( !bWriteClipboardDoc && pDoc->GetDocShell() && + (!pDoc->get(IDocumentSettingAccess::HTML_MODE) && + !pDoc->get(IDocumentSettingAccess::BROWSE_MODE)) && + SFX_ITEM_SET == rPageItemSet.GetItemState( RES_HEADER, sal_True, &pItem) ) + { + const SwFrmFmt *pHeaderFmt = + ((const SwFmtHeader *)pItem)->GetHeaderFmt(); + if( pHeaderFmt ) + OutHTML_HeaderFooter( *this, *pHeaderFmt, sal_True ); + } + + nTxtAttrsToIgnore = nHeaderAttrs; + Out_SwDoc( pOrigPam ); + nTxtAttrsToIgnore = 0; + + if( pxFormComps && pxFormComps->is() ) + OutForm( sal_False, *pxFormComps ); + + if( pFootEndNotes ) + OutFootEndNotes(); + + if( !bWriteClipboardDoc && pDoc->GetDocShell() && + (!pDoc->get(IDocumentSettingAccess::HTML_MODE) && !pDoc->get(IDocumentSettingAccess::BROWSE_MODE)) && + SFX_ITEM_SET == rPageItemSet.GetItemState( RES_FOOTER, sal_True, &pItem) ) + { + const SwFrmFmt *pFooterFmt = + ((const SwFmtFooter *)pItem)->GetFooterFmt(); + if( pFooterFmt ) + OutHTML_HeaderFooter( *this, *pFooterFmt, sal_False ); + } + + if( bLFPossible ) + OutNewLine(); + HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_body, sal_False ); + OutNewLine(); + HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_html, sal_False ); + + // loesche die Tabelle mit den freifliegenden Rahmen + sal_uInt16 i; + ASSERT( !pHTMLPosFlyFrms, "Wurden nicht alle Rahmen ausgegeben" ); + if( pHTMLPosFlyFrms ) + { + pHTMLPosFlyFrms->DeleteAndDestroy( 0, pHTMLPosFlyFrms->Count() ); + delete pHTMLPosFlyFrms; + pHTMLPosFlyFrms = 0; + } + + if( aHTMLControls.Count() ) + aHTMLControls.DeleteAndDestroy( sal_uInt16(0), aHTMLControls.Count() ); + + if( aChrFmtInfos.Count() ) + aChrFmtInfos.DeleteAndDestroy( sal_uInt16(0), aChrFmtInfos.Count() ); + + if( aTxtCollInfos.Count() ) + aTxtCollInfos.DeleteAndDestroy( sal_uInt16(0), aTxtCollInfos.Count() ); + + if( aImgMapNames.Count() ) + aImgMapNames.DeleteAndDestroy( sal_uInt16(0), aImgMapNames.Count() ); + + if( aImplicitMarks.Count() ) + aImplicitMarks.DeleteAndDestroy( sal_uInt16(0), aImplicitMarks.Count() ); + + if( aOutlineMarks.Count() ) + aOutlineMarks.DeleteAndDestroy( sal_uInt16(0), aOutlineMarks.Count() ); + + if( aOutlineMarkPoss.Count() ) + aOutlineMarkPoss.Remove( sal_uInt16(0), aOutlineMarkPoss.Count() ); + + if( aNumRuleNames.Count() ) + aNumRuleNames.DeleteAndDestroy( sal_uInt16(0), aNumRuleNames.Count() ); + + if( aScriptParaStyles.Count() ) + aScriptParaStyles.DeleteAndDestroy( sal_uInt16(0), aScriptParaStyles.Count() ); + if( aScriptTextStyles.Count() ) + aScriptTextStyles.DeleteAndDestroy( sal_uInt16(0), aScriptTextStyles.Count() ); + + delete pDfltColor; + pDfltColor = 0; + + delete pStartNdIdx; + pStartNdIdx = 0; + + delete pxFormComps; + pxFormComps = 0; + + ASSERT( !pFootEndNotes, + "SwHTMLWriter::Write: Ftns nicht durch OutFootEndNotes geloescht" ); + + pCurrPageDesc = 0; + + ClearNextNumInfo(); + + for( i=0; i<MAXLEVEL; i++ ) + aBulletGrfs[i].Erase(); + + aNonConvertableCharacters.Erase(); + + if( bShowProgress ) + ::EndProgress( pDoc->GetDocShell() ); + + if( pTemplate ) + { + // Waehrend des Exports angelegte Zeichen- und Abastzvorlagen + // loeschen + sal_uInt16 nTxtFmtCollCnt = pTemplate->GetTxtFmtColls()->Count(); + while( nTxtFmtCollCnt > nOldTxtFmtCollCnt ) + pTemplate->DelTxtFmtColl( --nTxtFmtCollCnt ); + ASSERT( pTemplate->GetTxtFmtColls()->Count() == nOldTxtFmtCollCnt, + "falsche Anzahl TxtFmtColls geloescht" ); + + sal_uInt16 nCharFmtCnt = pTemplate->GetCharFmts()->Count(); + while( nCharFmtCnt > nOldCharFmtCnt ) + pTemplate->DelCharFmt( --nCharFmtCnt ); + ASSERT( pTemplate->GetCharFmts()->Count() == nOldCharFmtCnt, + "falsche Anzahl CharFmts geloescht" ); + + // HTML-Modus wieder restaurieren + pTemplate->set(IDocumentSettingAccess::HTML_MODE, bOldHTMLMode); + + if( 0 == pTemplate->release() ) + delete pTemplate; + + pTemplate = 0; + } + + return nWarn; +} + +const SwFmtCol *lcl_html_GetFmtCol( const SwHTMLWriter& rHTMLWrt, + const SwSection& rSection, + const SwSectionFmt& rFmt ) +{ + const SwFmtCol *pCol = 0; + + const SfxPoolItem* pItem; + if( rHTMLWrt.IsHTMLMode( HTMLMODE_FRM_COLUMNS ) && + FILE_LINK_SECTION != rSection.GetType() && + SFX_ITEM_SET == rFmt.GetAttrSet().GetItemState(RES_COL,sal_False,&pItem) && + ((const SwFmtCol *)pItem)->GetNumCols() > 1 ) + { + pCol = (const SwFmtCol *)pItem; + } + + return pCol; +} + +sal_Bool lcl_html_IsMultiColStart( const SwHTMLWriter& rHTMLWrt, sal_uLong nIndex ) +{ + sal_Bool bRet = sal_False; + const SwSectionNode *pSectNd = + rHTMLWrt.pDoc->GetNodes()[nIndex]->GetSectionNode(); + if( pSectNd ) + { + const SwSection& rSection = pSectNd->GetSection(); + const SwSectionFmt *pFmt = rSection.GetFmt(); + if( pFmt && lcl_html_GetFmtCol( rHTMLWrt, rSection, *pFmt ) ) + bRet = sal_True; + } + + return bRet; +} + +sal_Bool lcl_html_IsMultiColEnd( const SwHTMLWriter& rHTMLWrt, sal_uLong nIndex ) +{ + sal_Bool bRet = sal_False; + const SwEndNode *pEndNd = rHTMLWrt.pDoc->GetNodes()[nIndex]->GetEndNode(); + if( pEndNd ) + bRet = lcl_html_IsMultiColStart( rHTMLWrt, + pEndNd->StartOfSectionIndex() ); + + return bRet; +} + + +void lcl_html_OutSectionStartTag( SwHTMLWriter& rHTMLWrt, + const SwSection& rSection, + const SwSectionFmt& rFmt, + const SwFmtCol *pCol, + sal_Bool bContinued=sal_False ) +{ + ASSERT( pCol || !bContinued, "Continuation of DIV" ); + + if( rHTMLWrt.bLFPossible ) + rHTMLWrt.OutNewLine(); + + const sal_Char *pTag = pCol ? OOO_STRING_SVTOOLS_HTML_multicol : OOO_STRING_SVTOOLS_HTML_division; + + ByteString sOut( '<' ); + sOut += pTag; + + const String& rName = rSection.GetSectionName(); + if( rName.Len() && !bContinued ) + { + ((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_id) += "=\""; + rHTMLWrt.Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( rHTMLWrt.Strm(), rName, rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + sOut = '\"'; + } + + sal_uInt16 nDir = rHTMLWrt.GetHTMLDirection( rFmt.GetAttrSet() ); + rHTMLWrt.Strm() << sOut.GetBuffer(); + sOut.Erase(); + rHTMLWrt.OutDirection( nDir ); + + if( FILE_LINK_SECTION == rSection.GetType() ) + { + ((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_href) += "=\""; + rHTMLWrt.Strm() << sOut.GetBuffer(); + + const String& aFName = rSection.GetLinkFileName(); + String aURL( aFName.GetToken(0,sfx2::cTokenSeperator) ); + String aFilter( aFName.GetToken(1,sfx2::cTokenSeperator) ); + String aSection( aFName.GetToken(2,sfx2::cTokenSeperator) ); + + String aEncURL( URIHelper::simpleNormalizedMakeRelative(rHTMLWrt.GetBaseURL(), aURL ) ); + sal_Unicode cDelim = 255U; + sal_Bool bURLContainsDelim = + (STRING_NOTFOUND != aEncURL.Search( cDelim ) ); + + HTMLOutFuncs::Out_String( rHTMLWrt.Strm(), aEncURL, + rHTMLWrt.eDestEnc, + &rHTMLWrt.aNonConvertableCharacters ); + const sal_Char *pDelim = "ÿ"; + if( aFilter.Len() || aSection.Len() || bURLContainsDelim ) + rHTMLWrt.Strm() << pDelim; + if( aFilter.Len() ) + HTMLOutFuncs::Out_String( rHTMLWrt.Strm(), aFilter, + rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + if( aSection.Len() || bURLContainsDelim ) + rHTMLWrt.Strm() << pDelim; + if( aSection.Len() ) + { + xub_StrLen nPos = aSection.Search( '%' ); + while( STRING_NOTFOUND != nPos ) + { + aSection.Erase( nPos, 1 ); + aSection.InsertAscii( "%25", nPos ); + nPos = aSection.Search( '%', nPos+3 ); + } + nPos = aSection.Search( cDelim ); + while( STRING_NOTFOUND != nPos ) + { + aSection.Erase( nPos, 1 ); + aSection.InsertAscii( "%FF", nPos ); + nPos = aSection.Search( cDelim, nPos+3 ); + } + HTMLOutFuncs::Out_String( rHTMLWrt.Strm(), aSection, + rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters ); + } + sOut = '\"'; + } + else if( pCol ) + { + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_cols) += '=') + += ByteString::CreateFromInt32( pCol->GetNumCols() ); + + // minumum gutter width + sal_uInt16 nGutter = pCol->GetGutterWidth( sal_True ); + if( nGutter!=USHRT_MAX ) + { + if( nGutter && Application::GetDefaultDevice() ) + { + nGutter = (sal_uInt16)Application::GetDefaultDevice() + ->LogicToPixel( Size(nGutter,0), + MapMode(MAP_TWIP) ).Width(); + } + (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_gutter) += '=') + += ByteString::CreateFromInt32( nGutter ); + } + } + + rHTMLWrt.Strm() << sOut.GetBuffer(); + if( rHTMLWrt.IsHTMLMode( rHTMLWrt.bCfgOutStyles ) ) + rHTMLWrt.OutCSS1_SectionFmtOptions( rFmt ); + + rHTMLWrt.Strm() << '>'; + + rHTMLWrt.bLFPossible = sal_True; + if( rName.Len() && !bContinued ) + rHTMLWrt.OutImplicitMark( rName, pMarkToRegion ); + + rHTMLWrt.IncIndentLevel(); +} + +void lcl_html_OutSectionEndTag( SwHTMLWriter& rHTMLWrt, + const SwFmtCol *pCol ) +{ + const sal_Char *pTag = pCol ? OOO_STRING_SVTOOLS_HTML_multicol : OOO_STRING_SVTOOLS_HTML_division; + + rHTMLWrt.DecIndentLevel(); + if( rHTMLWrt.bLFPossible ) + rHTMLWrt.OutNewLine(); + HTMLOutFuncs::Out_AsciiTag( rHTMLWrt.Strm(), pTag, sal_False ); + rHTMLWrt.bLFPossible = sal_True; +} + +static Writer& OutHTML_Section( Writer& rWrt, const SwSectionNode& rSectNd ) +{ + SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt; + + // End <PRE> and any <DL>, because a definition list's level may + // change inside the section. + rHTMLWrt.ChangeParaToken( 0 ); + rHTMLWrt.OutAndSetDefList( 0 ); + + const SwSection& rSection = rSectNd.GetSection(); + const SwSectionFmt *pFmt = rSection.GetFmt(); + ASSERT( pFmt, "Section without a format?" ); + + sal_Bool bStartTag = sal_True; + sal_Bool bEndTag = sal_True; + const SwSectionFmt *pSurrFmt = 0; + const SwSectionNode *pSurrSectNd = 0; + const SwSection *pSurrSection = 0; + const SwFmtCol *pSurrCol = 0; + + sal_uInt32 nSectSttIdx = rSectNd.GetIndex(); + sal_uInt32 nSectEndIdx = rSectNd.EndOfSectionIndex(); + const SwFmtCol *pCol = lcl_html_GetFmtCol( rHTMLWrt, rSection, *pFmt ); + if( pCol ) + { + // If the next node is a columned section node, too, don't export + // an empty section. + if( lcl_html_IsMultiColStart( rHTMLWrt, nSectSttIdx+1 ) ) + bStartTag = sal_False; + + // The same applies if the section end with another columned section. + if( lcl_html_IsMultiColEnd( rHTMLWrt, nSectEndIdx-1 ) ) + bEndTag = sal_False; + + //.is there a columned section arround this one? + const SwStartNode *pSttNd = rSectNd.StartOfSectionNode(); + if( pSttNd ) + { + pSurrSectNd = pSttNd->FindSectionNode(); + if( pSurrSectNd ) + { + const SwStartNode *pBoxSttNd = pSttNd->FindTableBoxStartNode(); + if( !pBoxSttNd || + pBoxSttNd->GetIndex() < pSurrSectNd->GetIndex() ) + { + pSurrSection = &pSurrSectNd->GetSection(); + pSurrFmt = pSurrSection->GetFmt(); + if( pSurrFmt ) + pSurrCol = lcl_html_GetFmtCol( rHTMLWrt, *pSurrSection, + *pSurrFmt ); + } + } + } + } + + // The surrounding section must be closed before the current one is + // opended, except that it start immediatly before the current one or + // another end immediately before the current one + if( pSurrCol && nSectSttIdx - pSurrSectNd->GetIndex() > 1 && + !lcl_html_IsMultiColEnd( rHTMLWrt, nSectSttIdx-1 ) ) + lcl_html_OutSectionEndTag( rHTMLWrt, pSurrCol ); + + if( bStartTag ) + lcl_html_OutSectionStartTag( rHTMLWrt, rSection, *pFmt, pCol ); + + { + HTMLSaveData aSaveData( rHTMLWrt, + rHTMLWrt.pCurPam->GetPoint()->nNode.GetIndex()+1, + rSectNd.EndOfSectionIndex(), + sal_False, pFmt ); + rHTMLWrt.Out_SwDoc( rHTMLWrt.pCurPam ); + } + + rHTMLWrt.pCurPam->GetPoint()->nNode = *rSectNd.EndOfSectionNode(); + + if( bEndTag ) + lcl_html_OutSectionEndTag( rHTMLWrt, pCol ); + + // The surrounding section must be started again, except that it ends + // immeditaly behind the current one. + if( pSurrCol && + pSurrSectNd->EndOfSectionIndex() - nSectEndIdx > 1 && + !lcl_html_IsMultiColStart( rHTMLWrt, nSectEndIdx+1 ) ) + lcl_html_OutSectionStartTag( rHTMLWrt, *pSurrSection, *pSurrFmt, + pSurrCol, sal_True ); + + return rWrt; +} + +void SwHTMLWriter::Out_SwDoc( SwPaM* pPam ) +{ + sal_Bool bSaveWriteAll = bWriteAll; // sichern + + // suche die naechste text::Bookmark-Position aus der text::Bookmark-Tabelle + nBkmkTabPos = bWriteAll ? FindPos_Bkmk( *pCurPam->GetPoint() ) : -1; + + // gebe alle Bereiche des Pams in das HTML-File aus. + do { + bWriteAll = bSaveWriteAll; + bFirstLine = sal_True; + + // suche den ersten am Pam-auszugebenen FlyFrame + // fehlt noch: + + while( pCurPam->GetPoint()->nNode.GetIndex() < pCurPam->GetMark()->nNode.GetIndex() || + (pCurPam->GetPoint()->nNode.GetIndex() == pCurPam->GetMark()->nNode.GetIndex() && + pCurPam->GetPoint()->nContent.GetIndex() <= pCurPam->GetMark()->nContent.GetIndex()) ) + { + SwNode * pNd = pCurPam->GetNode(); + + ASSERT( !(pNd->IsGrfNode() || pNd->IsOLENode()), + "Grf- oder OLE-Node hier unerwartet" ); + if( pNd->IsTxtNode() ) + { + SwTxtNode* pTxtNd = pNd->GetTxtNode(); + + if( !bFirstLine ) + pCurPam->GetPoint()->nContent.Assign( pTxtNd, 0 ); + + OutHTML_SwTxtNode( *this, *pTxtNd ); + } + else if( pNd->IsTableNode() ) + { + OutHTML_SwTblNode( *this, *pNd->GetTableNode(), 0 ); + nBkmkTabPos = bWriteAll ? FindPos_Bkmk( *pCurPam->GetPoint() ) : -1; + } + else if( pNd->IsSectionNode() ) + { + OutHTML_Section( *this, *pNd->GetSectionNode() ); + nBkmkTabPos = bWriteAll ? FindPos_Bkmk( *pCurPam->GetPoint() ) : -1; + } + else if( pNd == &pDoc->GetNodes().GetEndOfContent() ) + break; + + pCurPam->GetPoint()->nNode++; // Bewegen + sal_uInt32 nPos = pCurPam->GetPoint()->nNode.GetIndex(); + + if( bShowProgress ) + ::SetProgressState( nPos, pDoc->GetDocShell() ); // Wie weit ? + + /* sollen nur die Selectierten Bereiche gesichert werden, so + * duerfen nur die vollstaendigen Nodes gespeichert werde, + * d.H. der 1. und n. Node teilweise, der 2. bis n-1. Node + * vollstaendig. (vollstaendig heisst mit allen Formaten! ) + */ + bWriteAll = bSaveWriteAll || + nPos != pCurPam->GetMark()->nNode.GetIndex(); + bFirstLine = sal_False; + bOutFooter = sal_False; // Nach einem Node keine Fusszeile mehr + } + + ChangeParaToken( 0 ); // MIB 8.7.97: Machen wir jetzt hier und nicht + // beim Aufrufer + OutAndSetDefList( 0 ); + + } while( CopyNextPam( &pPam ) ); // bis alle PaM's bearbeitet + + bWriteAll = bSaveWriteAll; // wieder auf alten Wert zurueck +} + + +// schreibe die StyleTabelle, algemeine Angaben,Header/Footer/Footnotes +static void OutBodyColor( const sal_Char *pTag, const SwFmt *pFmt, + SwHTMLWriter& rHWrt ) +{ + const SwFmt *pRefFmt = 0; + + if( rHWrt.pTemplate ) + pRefFmt = SwHTMLWriter::GetTemplateFmt( pFmt->GetPoolFmtId(), + rHWrt.pTemplate ); + + const SvxColorItem *pColorItem = 0; + + const SfxItemSet& rItemSet = pFmt->GetAttrSet(); + const SfxPoolItem *pRefItem = 0, *pItem = 0; + sal_Bool bItemSet = SFX_ITEM_SET == rItemSet.GetItemState( RES_CHRATR_COLOR, + sal_True, &pItem); + sal_Bool bRefItemSet = pRefFmt && + SFX_ITEM_SET == pRefFmt->GetAttrSet().GetItemState( RES_CHRATR_COLOR, + sal_True, &pRefItem); + if( bItemSet ) + { + // wenn das Item nur in der Vorlage des aktuellen Doks gesetzt + // ist oder einen anderen Wert hat, als in der HTML-Vorlage, + // wird es gesetzt + const SvxColorItem *pCItem = (const SvxColorItem*)pItem; + + if( !bRefItemSet ) + { + pColorItem = pCItem; + } + else + { + Color aColor( pCItem->GetValue() ); + if( COL_AUTO == aColor.GetColor() ) + aColor.SetColor( COL_BLACK ); + + Color aRefColor( ((const SvxColorItem*)pRefItem)->GetValue() ); + if( COL_AUTO == aRefColor.GetColor() ) + aRefColor.SetColor( COL_BLACK ); + + if( !aColor.IsRGBEqual( aRefColor ) ) + pColorItem = pCItem; + } + } + else if( bRefItemSet ) + { + // Das Item war in der HTML-Vorlage noch gesetzt, also geben wir + // das Default aus + pColorItem = (const SvxColorItem*)&rItemSet.GetPool() + ->GetDefaultItem( RES_CHRATR_COLOR ); + } + + if( pColorItem ) + { + ByteString sOut( ' ' ); + (sOut += pTag) += '='; + rHWrt.Strm() << sOut.GetBuffer(); + Color aColor( pColorItem->GetValue() ); + if( COL_AUTO == aColor.GetColor() ) + aColor.SetColor( COL_BLACK ); + HTMLOutFuncs::Out_Color( rHWrt.Strm(), aColor, rHWrt.eDestEnc ); + if( RES_POOLCOLL_STANDARD==pFmt->GetPoolFmtId() ) + rHWrt.pDfltColor = new Color( aColor ); + } +} + +sal_uInt16 SwHTMLWriter::OutHeaderAttrs() +{ + sal_uLong nIdx = pCurPam->GetPoint()->nNode.GetIndex(); + sal_uLong nEndIdx = pCurPam->GetMark()->nNode.GetIndex(); + + SwTxtNode *pTxtNd = 0; + while( nIdx<=nEndIdx && + 0==(pTxtNd=pDoc->GetNodes()[nIdx]->GetTxtNode()) ) + nIdx++; + + ASSERT( pTxtNd, "Kein Text-Node gefunden" ); + if( !pTxtNd || !pTxtNd->HasHints() ) + return 0; + + sal_uInt16 nAttrs = 0; + sal_uInt16 nCntAttr = pTxtNd->GetSwpHints().Count(); + xub_StrLen nOldPos = 0; + for( sal_uInt16 i=0; i<nCntAttr; i++ ) + { + const SwTxtAttr *pHt = pTxtNd->GetSwpHints()[i]; + if( !pHt->GetEnd() ) + { + xub_StrLen nPos = *pHt->GetStart(); + if( nPos-nOldPos > 1 || RES_TXTATR_FIELD != pHt->Which() ) + break; + + sal_uInt16 nFldWhich = ((const SwFmtFld&)pHt->GetAttr()).GetFld() + ->GetTyp()->Which(); + if( RES_POSTITFLD!=nFldWhich && + RES_SCRIPTFLD!=nFldWhich ) + break; + + OutNewLine(); + OutHTML_SwFmtFld( *this, pHt->GetAttr() ); + nOldPos = nPos; + nAttrs++; + } + } + + return nAttrs; +} + +const SwPageDesc *SwHTMLWriter::MakeHeader( sal_uInt16 &rHeaderAttrs ) +{ + ByteString sOut( OOO_STRING_SVTOOLS_HTML_doctype ); + (sOut += ' ') += + (HTML_CFG_HTML32==nExportMode ? OOO_STRING_SVTOOLS_HTML_doctype32 + : OOO_STRING_SVTOOLS_HTML_doctype40); + HTMLOutFuncs::Out_AsciiTag( Strm(), sOut.GetBuffer() ); + + // baue den Vorspann + OutNewLine(); + HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_html ); + + OutNewLine(); + HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_head ); + + IncIndentLevel(); // Inhalt von <HEAD> einruecken + + // DokumentInfo + ByteString sIndent; + GetIndentString( sIndent ); +// OutNewLine(); + using namespace ::com::sun::star; + uno::Reference<document::XDocumentProperties> xDocProps; + SwDocShell *pDocShell(pDoc->GetDocShell()); + if (pDocShell) { + uno::Reference<document::XDocumentPropertiesSupplier> xDPS( + pDocShell->GetModel(), uno::UNO_QUERY_THROW); + xDocProps.set(xDPS->getDocumentProperties()); + } + + // xDocProps may be null here (when copying) + SfxFrameHTMLWriter::Out_DocInfo( Strm(), GetBaseURL(), xDocProps, + sIndent.GetBuffer(), eDestEnc, + &aNonConvertableCharacters ); + + // Kommentare und Meta-Tags des ersten Absatzes + rHeaderAttrs = OutHeaderAttrs(); + + OutFootEndNoteInfo(); + + const SwPageDesc *pPageDesc = 0; + //if( !pDoc->IsHTMLMode() ) + //{ + // In Nicht-HTML-Dokumenten wird die erste gesetzte Seitenvorlage + // exportiert und wenn keine gesetzt ist die Standard-Vorlage + sal_uLong nNodeIdx = pCurPam->GetPoint()->nNode.GetIndex(); + + while( nNodeIdx < pDoc->GetNodes().Count() ) + { + SwNode *pNd = pDoc->GetNodes()[ nNodeIdx ]; + if( pNd->IsCntntNode() ) + { + pPageDesc = ((const SwFmtPageDesc &)pNd->GetCntntNode() + ->GetAttr(RES_PAGEDESC)).GetPageDesc(); + break; + } + else if( pNd->IsTableNode() ) + { + pPageDesc = pNd->GetTableNode()->GetTable().GetFrmFmt() + ->GetPageDesc().GetPageDesc(); + break; + } + + nNodeIdx++; + } + + if( !pPageDesc ) + pPageDesc = &const_cast<const SwDoc *>(pDoc)->GetPageDesc( 0 ); + //} + //else + //{ + // In HTML-Dokumenten nehmen wir immer die HTML-Vorlage + // pPageDesc = pDoc->GetPageDescFromPool( RES_POOLPAGE_HTML ); + //} + + // und nun ... das Style-Sheet!!! + if( bCfgOutStyles ) + { + OutStyleSheet( *pPageDesc ); + } + + // und nun ... das BASIC und JavaScript! + if( pDoc->GetDocShell() ) // nur mit DocShell ist Basic moeglich + OutBasic(); + + DecIndentLevel(); // Inhalt von <HEAD> einruecken + OutNewLine(); + HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_head, sal_False ); + + // der Body wird nicht eingerueckt, weil sonst alles eingerueckt waere! + OutNewLine(); + sOut = '<'; + sOut += OOO_STRING_SVTOOLS_HTML_body; + Strm() << sOut.GetBuffer(); + sOut.Erase(); + + // language + OutLanguage( eLang ); + + // Textfarbe ausgeben, wenn sie an der Standard-Vorlage gesetzt ist + // und sich geaendert hat. + OutBodyColor( OOO_STRING_SVTOOLS_HTML_O_text, + pDoc->GetTxtCollFromPool( RES_POOLCOLL_STANDARD, false ), + *this ); + + // Farben fuer (un)besuchte Links + OutBodyColor( OOO_STRING_SVTOOLS_HTML_O_link, + pDoc->GetCharFmtFromPool( RES_POOLCHR_INET_NORMAL ), + *this ); + OutBodyColor( OOO_STRING_SVTOOLS_HTML_O_vlink, + pDoc->GetCharFmtFromPool( RES_POOLCHR_INET_VISIT ), + *this ); + + const SfxItemSet& rItemSet = pPageDesc->GetMaster().GetAttrSet(); + + String aEmbGrfName; + OutBackground( rItemSet, aEmbGrfName, sal_True ); + + nDirection = GetHTMLDirection( rItemSet ); + OutDirection( nDirection ); + + if( bCfgOutStyles ) + OutCSS1_BodyTagStyleOpt( *this, rItemSet, aEmbGrfName ); + + // Events anhaengen + if( pDoc->GetDocShell() ) // nur mit DocShell ist Basic moeglich + OutBasicBodyEvents(); + + Strm() << '>'; + + return pPageDesc; +} + +void SwHTMLWriter::OutAnchor( const String& rName ) +{ + ByteString sOut( '<' ); + (((sOut += OOO_STRING_SVTOOLS_HTML_anchor) += ' ') += OOO_STRING_SVTOOLS_HTML_O_name) += "=\""; + Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( Strm(), rName, eDestEnc, &aNonConvertableCharacters ) << "\">"; + HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_anchor, sal_False ); +} + +void SwHTMLWriter::OutBookmarks() +{ + // hole das aktuelle Bookmark + const ::sw::mark::IMark* pBookmark = NULL; + IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess(); + if(nBkmkTabPos != -1) + pBookmark = (pMarkAccess->getMarksBegin() + nBkmkTabPos)->get(); + // Ausgabe aller Bookmarks in diesem Absatz. Die Content-Position + // wird vorerst nicht beruecksichtigt! + sal_uInt32 nNode = pCurPam->GetPoint()->nNode.GetIndex(); + while( nBkmkTabPos != -1 && + pBookmark->GetMarkPos().nNode.GetIndex() == nNode ) + { + // Der Bereich derBookmark wird erstam ignoriert, da er von uns + // auch nicht eingelesen wird. + + // erst die SWG spezifischen Daten: + if(dynamic_cast< const ::sw::mark::IBookmark* >(pBookmark) && pBookmark->GetName().getLength() ) + OutAnchor( pBookmark->GetName() ); + + if( ++nBkmkTabPos >= pMarkAccess->getMarksCount() ) + nBkmkTabPos = -1; + else + pBookmark = (pMarkAccess->getMarksBegin() + nBkmkTabPos)->get(); + } + + sal_uInt16 nPos; + for( nPos = 0; nPos < aOutlineMarkPoss.Count() && + aOutlineMarkPoss[nPos] < nNode; nPos++ ) + ; + + while( nPos < aOutlineMarkPoss.Count() && aOutlineMarkPoss[nPos] == nNode ) + { + String sMark( *aOutlineMarks[nPos] ); + sMark.SearchAndReplaceAll( '?', '_' ); // '?' causes problems in IE/Netscape 5 + OutAnchor( sMark ); + aOutlineMarkPoss.Remove( nPos, 1 ); + aOutlineMarks.DeleteAndDestroy( nPos, 1 ); + } +} + +void SwHTMLWriter::OutImplicitMark( const String& rMark, + const sal_Char *pMarkType ) +{ + if( rMark.Len() && aImplicitMarks.Count() ) + { + String sMark( rMark ); + sMark.Append( cMarkSeperator ); + sMark.AppendAscii( pMarkType ); + sal_uInt16 nPos; + if( aImplicitMarks.Seek_Entry( &sMark, &nPos ) ) + { + sMark.SearchAndReplaceAll( '?', '_' ); // '?' causes problems in IE/Netscape 5 + OutAnchor( sMark ); + aImplicitMarks.DeleteAndDestroy( nPos, 1 ); + } + } +} + +void SwHTMLWriter::OutHyperlinkHRefValue( const String& rURL ) +{ + String sURL( rURL ); + xub_StrLen nPos = sURL.SearchBackward( cMarkSeperator ); + if( STRING_NOTFOUND != nPos ) + { + String sCmp( sURL.Copy( nPos+1 ) ); + sCmp.EraseAllChars(); + if( sCmp.Len() ) + { + sCmp.ToLowerAscii(); + if( sCmp.EqualsAscii( pMarkToRegion ) || + sCmp.EqualsAscii( pMarkToFrame ) || + sCmp.EqualsAscii( pMarkToGraphic ) || + sCmp.EqualsAscii( pMarkToOLE ) || + sCmp.EqualsAscii( pMarkToTable ) || + sCmp.EqualsAscii( pMarkToOutline ) || + sCmp.EqualsAscii( pMarkToText ) ) + { + sURL.SearchAndReplaceAll( '?', '_' ); // '?' causes problems in IE/Netscape 5 + } + } + } + + sURL = URIHelper::simpleNormalizedMakeRelative( GetBaseURL(), sURL); + HTMLOutFuncs::Out_String( Strm(), sURL, eDestEnc, + &aNonConvertableCharacters ); +} + +void SwHTMLWriter::OutBackground( const SvxBrushItem *pBrushItem, + String& rEmbGrfNm, sal_Bool bGraphic ) +{ + const Color &rBackColor = pBrushItem->GetColor(); + /// OD 02.09.2002 #99657# + /// check, if background color is not "no fill"/"auto fill", instead of + /// only checking, if transparency is not set. + if( rBackColor.GetColor() != COL_TRANSPARENT ) + { + ByteString sOut( ' ' ); + (sOut += OOO_STRING_SVTOOLS_HTML_O_bgcolor) += '='; + Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_Color( Strm(), rBackColor, eDestEnc); + } + + if( !bGraphic ) + return; + + const String *pLink = pBrushItem->GetGraphicLink(); + + // embeddete Grafik -> WriteEmbedded schreiben + if( !pLink ) + { + const Graphic* pGrf = pBrushItem->GetGraphic(); + if( pGrf ) + { + // Grafik als (JPG-)File speichern + const String* pTempFileName = GetOrigFileName(); + if(pTempFileName) + rEmbGrfNm = *pTempFileName; + sal_uInt16 nErr = XOutBitmap::WriteGraphic( *pGrf, rEmbGrfNm, + String::CreateFromAscii( "JPG" ), + XOUTBMP_USE_NATIVE_IF_POSSIBLE ); + if( !nErr ) // fehlerhaft, da ist nichts auszugeben + { + rEmbGrfNm = URIHelper::SmartRel2Abs( + INetURLObject( GetBaseURL() ), rEmbGrfNm, + URIHelper::GetMaybeFileHdl() ); + pLink = &rEmbGrfNm; + } + else + { + nWarn = WARN_SWG_POOR_LOAD | WARN_SW_WRITE_BASE; + } + } + } + else + { + rEmbGrfNm = *pLink; + if( bCfgCpyLinkedGrfs ) + { + CopyLocalFileToINet( rEmbGrfNm ); + pLink = &rEmbGrfNm; + } + } + + if( pLink ) + { + ByteString sOut( ' ' ); + String s( URIHelper::simpleNormalizedMakeRelative( GetBaseURL(), *pLink)); + (sOut += OOO_STRING_SVTOOLS_HTML_O_background) += "=\""; + Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( Strm(), s, eDestEnc, &aNonConvertableCharacters ) << '\"'; + } +} + +void SwHTMLWriter::OutBackground( const SfxItemSet& rItemSet, + String& rEmbGrfNm, sal_Bool bGraphic ) +{ + const SfxPoolItem* pItem; + if( SFX_ITEM_SET == rItemSet.GetItemState( RES_BACKGROUND, sal_False, + &pItem )) + { + OutBackground( ((const SvxBrushItem*)pItem), rEmbGrfNm, bGraphic ); + } +} + +sal_uInt16 SwHTMLWriter::GetLangWhichIdFromScript( sal_uInt16 nScript ) +{ + sal_uInt16 nWhichId; + switch( nScript ) + { + case CSS1_OUTMODE_CJK: + nWhichId = RES_CHRATR_CJK_LANGUAGE; + break; + case CSS1_OUTMODE_CTL: + nWhichId = RES_CHRATR_CJK_LANGUAGE; + break; + default: + nWhichId = RES_CHRATR_LANGUAGE; + break; + } + return nWhichId; +} + +void SwHTMLWriter::OutLanguage( LanguageType nLang ) +{ + if( LANGUAGE_DONTKNOW != nLang ) + { + ByteString sOut( ' ' ); + (sOut += OOO_STRING_SVTOOLS_HTML_O_lang) += "=\""; + Strm() << sOut.GetBuffer(); + HTMLOutFuncs::Out_String( Strm(), MsLangId::convertLanguageToIsoString(nLang), + eDestEnc, &aNonConvertableCharacters ) << '"'; + } +} + +sal_uInt16 SwHTMLWriter::GetHTMLDirection( const SfxItemSet& rItemSet ) const +{ + return GetHTMLDirection( + static_cast < const SvxFrameDirectionItem& >( rItemSet.Get( RES_FRAMEDIR ) ) + .GetValue() ); +} + +sal_uInt16 SwHTMLWriter::GetHTMLDirection( sal_uInt16 nDir ) const +{ + switch( nDir ) + { + case FRMDIR_VERT_TOP_LEFT: + nDir = FRMDIR_HORI_LEFT_TOP; + break; + case FRMDIR_VERT_TOP_RIGHT: + nDir = FRMDIR_HORI_RIGHT_TOP; + break; + case FRMDIR_ENVIRONMENT: + nDir = nDirection; + } + + return nDir; +} + +void SwHTMLWriter::OutDirection( sal_uInt16 nDir ) +{ + const sal_Char *pValue = 0; + switch( nDir ) + { + case FRMDIR_HORI_LEFT_TOP: + case FRMDIR_VERT_TOP_LEFT: + pValue = "LTR"; + break; + case FRMDIR_HORI_RIGHT_TOP: + case FRMDIR_VERT_TOP_RIGHT: + pValue = "RTL"; + break; + } + if( pValue != 0 ) + { + ByteString sOut( ' ' ); + (((sOut += OOO_STRING_SVTOOLS_HTML_O_dir) += "=\"") += pValue) += '\"'; + Strm() << sOut.GetBuffer(); + } +} + +void SwHTMLWriter::GetIndentString( ByteString& rStr, sal_uInt16 nIncLvl ) +{ + // etwas umstaendlich, aber wir haben nur einen Indent-String! + sal_uInt16 nLevel = nIndentLvl + nIncLvl; + + if( nLevel && nLevel <= MAX_INDENT_LEVEL) + { + sIndentTabs[nLevel] = 0; + rStr = sIndentTabs; + sIndentTabs[nLevel] = '\t'; + } +} + +void SwHTMLWriter::OutNewLine( sal_Bool bCheck ) +{ + if( !bCheck || (Strm().Tell()-nLastLFPos) > nIndentLvl ) + { + Strm() << sNewLine; + nLastLFPos = Strm().Tell(); + } + + if( nIndentLvl && nIndentLvl <= MAX_INDENT_LEVEL) + { + sIndentTabs[nIndentLvl] = 0; + Strm() << sIndentTabs; + sIndentTabs[nIndentLvl] = '\t'; + } +} + +sal_uInt16 SwHTMLWriter::GetHTMLFontSize( sal_uInt32 nHeight ) const +{ + sal_uInt16 nSize = 1; + for( sal_uInt16 i=6; i>0; i-- ) + { + if( nHeight > (aFontHeights[i] + aFontHeights[i-1])/2 ) + { + nSize = i+1; + break; + } + } + + return nSize; +} + +// Struktur speichert die aktuellen Daten des Writers zwischen, um +// einen anderen Dokument-Teil auszugeben, wie z.B. Header/Footer +HTMLSaveData::HTMLSaveData( SwHTMLWriter& rWriter, sal_uLong nStt, + sal_uLong nEnd, sal_Bool bSaveNum, + const SwFrmFmt *pFrmFmt ) : + rWrt( rWriter ), + pOldPam( rWrt.pCurPam ), + pOldEnd( rWrt.GetEndPaM() ), + pOldNumRuleInfo( 0 ), + pOldNextNumRuleInfo( 0 ), + nOldDefListLvl( rWrt.nDefListLvl ), + nOldDirection( rWrt.nDirection ), + bOldOutHeader( rWrt.bOutHeader ), + bOldOutFooter( rWrt.bOutFooter ), + bOldOutFlyFrame( rWrt.bOutFlyFrame ) +{ + bOldWriteAll = rWrt.bWriteAll; + + rWrt.pCurPam = rWrt.NewSwPaM( *rWrt.pDoc, nStt, nEnd ); + + // Tabelle in Sonderbereichen erkennen + if( nStt != rWrt.pCurPam->GetMark()->nNode.GetIndex() ) + { + const SwNode *pNd = rWrt.pDoc->GetNodes()[ nStt ]; + if( pNd->IsTableNode() || pNd->IsSectionNode() ) + rWrt.pCurPam->GetMark()->nNode = nStt; + } + + rWrt.SetEndPaM( rWrt.pCurPam ); + rWrt.pCurPam->Exchange( ); + rWrt.bWriteAll = sal_True; + rWrt.nDefListLvl = 0; + rWrt.bOutHeader = rWrt.bOutFooter = sal_False; + + // Ggf. die aktuelle Numerierungs-Info merken, damit sie wieder + // neu aufgenommen werden kann. Nur dann belibt auch die Numerierungs- + // Info des nachsten Absatz gueltig. + if( bSaveNum ) + { + pOldNumRuleInfo = new SwHTMLNumRuleInfo( rWrt.GetNumInfo() ); + pOldNextNumRuleInfo = rWrt.GetNextNumInfo(); + rWrt.SetNextNumInfo( 0 ); + } + else + { + rWrt.ClearNextNumInfo(); + } + + // Die Numerierung wird in jedem Fall unterbrochen. + rWrt.GetNumInfo().Clear(); + + if( pFrmFmt ) + rWrt.nDirection = rWrt.GetHTMLDirection( pFrmFmt->GetAttrSet() ); +} + + +HTMLSaveData::~HTMLSaveData() +{ + delete rWrt.pCurPam; // Pam wieder loeschen + + rWrt.pCurPam = pOldPam; + rWrt.SetEndPaM( pOldEnd ); + rWrt.bWriteAll = bOldWriteAll; + rWrt.nBkmkTabPos = bOldWriteAll ? rWrt.FindPos_Bkmk( *pOldPam->GetPoint() ) : -1; + rWrt.nLastParaToken = 0; + rWrt.nDefListLvl = nOldDefListLvl; + rWrt.nDirection = nOldDirection; + rWrt.bOutHeader = bOldOutHeader; + rWrt.bOutFooter = bOldOutFooter; + rWrt.bOutFlyFrame = bOldOutFlyFrame; + + // Ggf. die Numerierung von vor der Section fortsetzen. Die Numerierung + // des naecshten Absatz wird in jedem Fall ungueltig. + if( pOldNumRuleInfo ) + { + rWrt.GetNumInfo().Set( *pOldNumRuleInfo ); + delete pOldNumRuleInfo; + rWrt.SetNextNumInfo( pOldNextNumRuleInfo ); + } + else + { + rWrt.GetNumInfo().Clear(); + rWrt.ClearNextNumInfo(); + } +} + + +void GetHTMLWriter( const String&, const String& rBaseURL, WriterRef& xRet ) +{ + xRet = new SwHTMLWriter( rBaseURL ); +} + + diff --git a/sw/source/filter/html/wrthtml.hxx b/sw/source/filter/html/wrthtml.hxx new file mode 100644 index 000000000000..bee6d63b805e --- /dev/null +++ b/sw/source/filter/html/wrthtml.hxx @@ -0,0 +1,603 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _WRTHTML_HXX +#define _WRTHTML_HXX + + +#include <com/sun/star/container/XIndexContainer.hpp> +#include <com/sun/star/form/XForm.hpp> +#include <vcl/field.hxx> +#define _SVSTDARR_STRINGSDTOR +#define _SVSTDARR_STRINGSSORTDTOR +#define _SVSTDARR_ULONGS +#include <svl/svstdarr.hxx> +#include <i18npool/lang.h> +#include <tools/stream.hxx> + +#include "shellio.hxx" +#include "wrt_fn.hxx" + +// einige Forward Deklarationen +class Color; +class SwFrmFmt; +class SwFlyFrmFmt; +class SwDrawFrmFmt; +class SwFmtINetFmt; +class SwFmtVertOrient; +class SwFmtFtn; +class SwStartNode; +class SwTableNode; +class SwPageDesc; +class SwNodeIndex; +class ImageMap; +class SwNumRule; +class SdrObject; +class SvxBrushItem; +class SvxFontItem; +class SwHTMLNumRuleInfo; +class SwHTMLPosFlyFrms; +class SwHTMLTxtFtns; + +extern SwAttrFnTab aHTMLAttrFnTab; + +//#define HTML_PARSPACE ((MM50 * 7) / 10) +#define HTML_PARSPACE (MM50) + +// Flags fuer die Ausgabe von Rahmen aller Art +// BORDER geht nur bei OutHTML_Image +// ANYSIZE gibt an, ob auch VAR_SIZE und MIN_SIZE angaben exportiert werden +// ABSSIZE gibt an, ob Abstand und Umrandung ignoriert werden sollen +const sal_uInt32 HTML_FRMOPT_ALIGN = 1<<0; +const sal_uInt32 HTML_FRMOPT_S_ALIGN = 1<<1; + +const sal_uInt32 HTML_FRMOPT_WIDTH = 1<<2; +const sal_uInt32 HTML_FRMOPT_HEIGHT = 1<<3; +const sal_uInt32 HTML_FRMOPT_SIZE = HTML_FRMOPT_WIDTH|HTML_FRMOPT_HEIGHT; +const sal_uInt32 HTML_FRMOPT_S_WIDTH = 1<<4; +const sal_uInt32 HTML_FRMOPT_S_HEIGHT = 1<<5; +const sal_uInt32 HTML_FRMOPT_S_SIZE = HTML_FRMOPT_S_WIDTH|HTML_FRMOPT_S_HEIGHT; +const sal_uInt32 HTML_FRMOPT_ANYSIZE = 1<<6; +const sal_uInt32 HTML_FRMOPT_ABSSIZE = 1<<7; +const sal_uInt32 HTML_FRMOPT_MARGINSIZE = 1<<8; + +const sal_uInt32 HTML_FRMOPT_SPACE = 1<<9; +const sal_uInt32 HTML_FRMOPT_S_SPACE = 1<<10; + +const sal_uInt32 HTML_FRMOPT_BORDER = 1<<11; +const sal_uInt32 HTML_FRMOPT_S_BORDER = 1<<12; +const sal_uInt32 HTML_FRMOPT_S_NOBORDER = 1<<13; + +const sal_uInt32 HTML_FRMOPT_S_BACKGROUND = 1<<14; + +const sal_uInt32 HTML_FRMOPT_NAME = 1<<15; +const sal_uInt32 HTML_FRMOPT_ALT = 1<<16; +const sal_uInt32 HTML_FRMOPT_BRCLEAR = 1<<17; +const sal_uInt32 HTML_FRMOPT_S_PIXSIZE = 1<<18; +const sal_uInt32 HTML_FRMOPT_ID = 1<<19; +const sal_uInt32 HTML_FRMOPT_DIR = 1<<20; + + +const sal_uInt32 HTML_FRMOPTS_GENIMG_ALL = + HTML_FRMOPT_ALT | + HTML_FRMOPT_SIZE | + HTML_FRMOPT_ABSSIZE | + HTML_FRMOPT_NAME; +const sal_uInt32 HTML_FRMOPTS_GENIMG_CNTNR = HTML_FRMOPTS_GENIMG_ALL; +const sal_uInt32 HTML_FRMOPTS_GENIMG = + HTML_FRMOPTS_GENIMG_ALL | + HTML_FRMOPT_ALIGN | + HTML_FRMOPT_SPACE | + HTML_FRMOPT_BRCLEAR; + +#define HTMLMODE_BLOCK_SPACER 0x00010000 +#define HTMLMODE_FLOAT_FRAME 0x00020000 +#define HTMLMODE_VERT_SPACER 0x00040000 +#define HTMLMODE_NBSP_IN_TABLES 0x00080000 +#define HTMLMODE_LSPACE_IN_NUMBUL 0x00100000 +#define HTMLMODE_NO_BR_AT_PAREND 0x00200000 +#define HTMLMODE_PRINT_EXT 0x00400000 +#define HTMLMODE_ABS_POS_FLY 0x00800000 +#define HTMLMODE_ABS_POS_DRAW 0x01000000 +#define HTMLMODE_FLY_MARGINS 0x02000000 +#define HTMLMODE_BORDER_NONE 0x04000000 +#define HTMLMODE_FONT_GENERIC 0x08000000 +#define HTMLMODE_FRSTLINE_IN_NUMBUL 0x10000000 +#define HTMLMODE_NO_CONTROL_CENTERING 0x20000000 + +#define HTML_DLCOLL_DD 0x4000 +#define HTML_DLCOLL_DT 0x8000 + +#define CSS1_FMT_ISTAG (USHRT_MAX) +#define CSS1_FMT_CMPREF (USHRT_MAX-1) +#define CSS1_FMT_SPECIAL (USHRT_MAX-1) + +// Die folgenden Flags bestimmen nur, welche Descriptoren, Tags, Optionen etc. +// ausgegeben werden ... +// bit 0,1,2 +#define CSS1_OUTMODE_SPAN_NO_ON 0x0000U +#define CSS1_OUTMODE_SPAN_TAG_ON 0x0001U +#define CSS1_OUTMODE_STYLE_OPT_ON 0x0002U +#define CSS1_OUTMODE_RULE_ON 0x0003U +#define CSS1_OUTMODE_SPAN_TAG1_ON 0x0004U +#define CSS1_OUTMODE_ANY_ON 0x0007U + +// bit 3,4,5 +#define CSS1_OUTMODE_SPAN_NO_OFF 0x0000U +#define CSS1_OUTMODE_SPAN_TAG_OFF ((sal_uInt16)(0x0001U << 3)) +#define CSS1_OUTMODE_STYLE_OPT_OFF ((sal_uInt16)(0x0002U << 3)) +#define CSS1_OUTMODE_RULE_OFF ((sal_uInt16)(0x0003U << 3)) +#define CSS1_OUTMODE_SPAN_TAG1_OFF ((sal_uInt16)(0x0004U << 3)) +#define CSS1_OUTMODE_ANY_OFF ((sal_uInt16)(0x0007U << 3)) + +#define CSS1_OUTMODE_ONOFF(a) (CSS1_OUTMODE_##a##_ON|CSS1_OUTMODE_##a##_OFF) +#define CSS1_OUTMODE_SPAN_TAG CSS1_OUTMODE_ONOFF(SPAN_TAG) +#define CSS1_OUTMODE_STYLE_OPT CSS1_OUTMODE_ONOFF(STYLE_OPT) +#define CSS1_OUTMODE_RULE CSS1_OUTMODE_ONOFF(RULE) +#define CSS1_OUTMODE_SPAN_TAG1 CSS1_OUTMODE_ONOFF(TAG1) + +// Die folgenden Flags legen fest, was ausgegeben wird +// bit 6,7,8,9 +#define CSS1_OUTMODE_TEMPLATE 0x0000U +#define CSS1_OUTMODE_BODY ((sal_uInt16)(0x0001U << 6)) +#define CSS1_OUTMODE_PARA ((sal_uInt16)(0x0002U << 6)) +#define CSS1_OUTMODE_HINT ((sal_uInt16)(0x0003U << 6)) +#define CSS1_OUTMODE_FRAME ((sal_uInt16)(0x0004U << 6)) +#define CSS1_OUTMODE_TABLE ((sal_uInt16)(0x0005U << 6)) +#define CSS1_OUTMODE_TABLEBOX ((sal_uInt16)(0x0006U << 6)) +#define CSS1_OUTMODE_DROPCAP ((sal_uInt16)(0x0007U << 6)) +#define CSS1_OUTMODE_SECTION ((sal_uInt16)(0x0008U << 6)) +#define CSS1_OUTMODE_SOURCE ((sal_uInt16)(0x000fU << 6)) + +// bit 10 +#define CSS1_OUTMODE_ENCODE ((sal_uInt16)(0x0001U << 10)) + +// bit 11,12,13 +// don't care about script +#define CSS1_OUTMODE_ANY_SCRIPT 0x0000U +// no cjk or ctl items +#define CSS1_OUTMODE_WESTERN ((sal_uInt16)(0x0001U << 11)) +// no western or ctl items +#define CSS1_OUTMODE_CJK ((sal_uInt16)(0x0002U << 11)) +// no western or cjk items +#define CSS1_OUTMODE_CTL ((sal_uInt16)(0x0003U << 11)) +// no western, cjk or ctl items +#define CSS1_OUTMODE_NO_SCRIPT ((sal_uInt16)(0x0004U << 11)) +#define CSS1_OUTMODE_SCRIPT ((sal_uInt16)(0x0007U << 11)) + +// der HTML-Writer +struct HTMLControl; +SV_DECL_PTRARR_SORT_DEL( HTMLControls, HTMLControl*, 1, 1 ) +SV_DECL_PTRARR( INetFmts, SwFmtINetFmt*, 1, 1 ) + +struct SwHTMLFmtInfo; +SV_DECL_PTRARR_SORT_DEL( SwHTMLFmtInfos, SwHTMLFmtInfo*, 1, 1 ) + +class IDocumentStylePoolAccess; + +class SwHTMLWriter : public Writer +{ + SwHTMLPosFlyFrms *pHTMLPosFlyFrms; + SwHTMLNumRuleInfo *pNumRuleInfo;// aktuelle Numerierung + SwHTMLNumRuleInfo *pNextNumRuleInfo; + sal_uInt32 nHTMLMode; // Beschreibung der Export-Konfiguration + + FieldUnit eCSS1Unit; + + sal_uInt16 OutHeaderAttrs(); + const SwPageDesc *MakeHeader( sal_uInt16& rHeaderAtrs ); + void GetControls(); + + void AddLinkTarget( const String& rURL ); + void CollectLinkTargets(); + +protected: + sal_uLong WriteStream(); + +public: +#if defined(UNX) + static const sal_Char sNewLine; // nur \012 oder \015 +#else + static const sal_Char __FAR_DATA sNewLine[]; // \015\012 +#endif + + SvStringsDtor aImgMapNames; // geschriebene Image Maps + SvStringsSortDtor aImplicitMarks;// implizite Stprungmarken + SvStringsDtor aOutlineMarks; // geschriebene Image Maps + SvStringsSortDtor aNumRuleNames;// Names of exported num rules + SvStringsSortDtor aScriptParaStyles;// script dependent para styles + SvStringsSortDtor aScriptTextStyles;// script dependent text styles + SvULongs aOutlineMarkPoss; + HTMLControls aHTMLControls; // die zu schreibenden ::com::sun::star::form::Forms + SwHTMLFmtInfos aChrFmtInfos; + SwHTMLFmtInfos aTxtCollInfos; + INetFmts aINetFmts; // die "offenen" INet-Attribute + SwHTMLTxtFtns *pFootEndNotes; + + String aCSS1Selector; // der Selektor eines Styles + String aNonConvertableCharacters; + String aBulletGrfs[MAXLEVEL]; // die Grafiken fuer Listen + + ::com::sun::star::uno::Reference< ::com::sun::star::container::XIndexContainer > *pxFormComps; // die aktuelle Form + + SwDoc *pTemplate; // die HTML-Vorlage + Color *pDfltColor; // default Farbe + SwNodeIndex *pStartNdIdx; // Index des ersten Absatz + const SwPageDesc *pCurrPageDesc;// Die aktuelle Seiten-Vorlage + const SwFmtFtn *pFmtFtn; + + sal_uInt32 aFontHeights[7]; // die Font-Hoehen 1-7 + + sal_uInt32 nWarn; // Result-Code fuer Warnungen + sal_uInt32 nLastLFPos; // letzte Position eines LF + + sal_uInt16 nLastParaToken; // fuers Absaetze zusammenhalten + sal_Int32 nBkmkTabPos; // akt. Position in der Bookmark-Tabelle + sal_uInt16 nImgMapCnt; // zum eindeutig + sal_uInt16 nFormCntrlCnt; + sal_uInt16 nEndNote; + sal_uInt16 nFootNote; + sal_Int32 nLeftMargin; // linker Einzug (z.B. aus Listen) + sal_Int32 nDfltLeftMargin; // die dafaults, der nicht geschrieben + sal_Int32 nDfltRightMargin; // werden muessen (aus der Vorlage) + short nFirstLineIndent; // Erstzeilen-Einzug (aus Listen) + short nDfltFirstLineIndent; // nicht zu schreibender default + sal_uInt16 nDfltTopMargin; // die defaults, der nicht geschrieben + sal_uInt16 nDfltBottomMargin; // werden muessen (aus der Vorlage) + sal_uInt16 nIndentLvl; // wie weit ist eingerueckt? + xub_StrLen nWhishLineLen; // wie lang darf eine Zeile werden? + sal_uInt16 nDefListLvl; // welcher DL-Level existiert gerade + sal_Int32 nDefListMargin; // Wie weit wird in DL eingerueckt + sal_uInt16 nHeaderFooterSpace; + sal_uInt16 nTxtAttrsToIgnore; + sal_uInt16 nExportMode; + sal_uInt16 nCSS1OutMode; + sal_uInt16 nCSS1Script; // contains default script (that's the one + // that is not contained in class names) + sal_uInt16 nDirection; // the current direction + + rtl_TextEncoding eDestEnc; + LanguageType eLang; + + // Beschreibung der Export-Konfiguration + // 0 + sal_Bool bCfgOutStyles : 1; // Styles exportieren + sal_Bool bCfgPreferStyles : 1; // Styles herkoemmlichen Tags vorziehen + sal_Bool bCfgFormFeed : 1; // Form-Feeds exportieren + sal_Bool bCfgStarBasic : 1; // StarBasic exportieren + sal_Bool bCfgCpyLinkedGrfs : 1; + + // Beschreibung dessen, was exportiert wird + + sal_Bool bFirstLine : 1; // wird die 1. Zeile ausgegeben ? + sal_Bool bTagOn : 1; // Tag an oder aus/Attr-Start oder -Ende + + // Die folgenden beiden Flags geben an, wir Attribute exportiert werden: + // bTxtAttr bOutOpts + // 0 0 Style-Sheets + // 1 0 Hints: Jedes Attribut wird als eignes Tag + // geschrieben und es gibt ein End-Tag + // 0 1 (Absatz-)Attribute: Das Attribut wird als Option + // eines bereits geschrieben Tags exportiert. Es + // gibt kein End-Tag. + sal_Bool bTxtAttr : 1; + // 8 + sal_Bool bOutOpts : 1; + + sal_Bool bOutTable : 1; // wird der Tabelleninhalt geschrieben? + sal_Bool bOutHeader : 1; + sal_Bool bOutFooter : 1; + sal_Bool bOutFlyFrame : 1; + + // Flags fuer Style-Export + + sal_Bool bFirstCSS1Rule : 1; // wurde schon eine Property ausgegeben + sal_Bool bFirstCSS1Property : 1; // wurde schon eine Property ausgegeben + sal_Bool bPoolCollTextModified : 1; // die Textkoerper-Vorlage wurde + // modifiziert. + // 16 + sal_Bool bCSS1IgnoreFirstPageDesc : 1; + + // was muss/kann/darf nicht ausgegeben werden? + + sal_Bool bNoAlign : 1; // HTML-Tag erlaubt kein ALIGN=... + sal_Bool bClearLeft : 1; // <BR CLEAR=LEFT> am Absatz-Ende ausg. + sal_Bool bClearRight : 1; // <BR CLEAR=RIGHT> am Absatz-Ende ausg. + sal_Bool bLFPossible : 1; // ein Zeilenumbruch darf eingef. werden + + // sonstiges + + sal_Bool bPreserveForm : 1; // die aktuelle Form beibehalten + + sal_Bool bCfgNetscape4 : 1; // Netscape4 Hacks + // 23 + + SwHTMLWriter( const String& rBaseURL ); + virtual ~SwHTMLWriter(); + + void Out_SwDoc( SwPaM* ); // schreibe den makierten Bereich + + // gebe alle an in aktuellen Ansatz stehenden ::com::sun::star::text::Bookmarks aus + void OutAnchor( const String& rName ); + void OutBookmarks(); + void OutImplicitMark( const String& rMark, const sal_Char *pMarkType ); + void OutHyperlinkHRefValue( const String& rURL ); + + // gebe die evt. an der akt. Position stehenden FlyFrame aus. + sal_Bool OutFlyFrm( sal_uLong nNdIdx, xub_StrLen nCntntIdx, + sal_uInt8 nPos, HTMLOutContext *pContext = 0 ); + void OutFrmFmt( sal_uInt8 nType, const SwFrmFmt& rFmt, + const SdrObject *pSdrObj ); + + void OutForm( sal_Bool bTagOn=sal_True, const SwStartNode *pStNd=0 ); + void OutHiddenForms(); + void OutHiddenForm( const ::com::sun::star::uno::Reference< + ::com::sun::star::form::XForm > & rForm ); + + void OutForm( sal_Bool bOn, const ::com::sun::star::uno::Reference< ::com::sun::star::container::XIndexContainer > & rFormComps ); + void OutHiddenControls( const ::com::sun::star::uno::Reference< + ::com::sun::star::container::XIndexContainer > & rFormComps, + const ::com::sun::star::uno::Reference< + ::com::sun::star::beans::XPropertySet > & rPropSet ); + sal_Bool HasControls() const; + + void OutFootEndNoteInfo(); + void OutFootEndNotes(); + String GetFootEndNoteSym( const SwFmtFtn& rFmtFtn ); + void OutFootEndNoteSym( const SwFmtFtn& rFmtFtn, const String& rNum, + sal_uInt16 nScript ); + +#ifdef JAVA_BASIC_IDE + void OutBasicModule( const String& rName, const String& rLanguage ); +#endif + void OutBasic(); + + void OutAndSetDefList( sal_uInt16 nNewLvl ); + + void OutStyleSheet( const SwPageDesc& rPageDesc, sal_Bool bUsed=sal_True ); + + inline void OutCSS1_PropertyAscii( const sal_Char *pProp, + const sal_Char *pVal ); + inline void OutCSS1_PropertyAscii( const sal_Char *pProp, + const ByteString& rVal ); + inline void OutCSS1_Property( const sal_Char *pProp, const String& rVal ); + void OutCSS1_Property( const sal_Char *pProp, const sal_Char *pVal, + const String *pSVal ); + void OutCSS1_UnitProperty( const sal_Char *pProp, long nVal ); + void OutCSS1_PixelProperty( const sal_Char *pProp, long nVal, sal_Bool bVert ); + void OutCSS1_SfxItemSet( const SfxItemSet& rItemSet, sal_Bool bDeep=sal_True ); + + // BODY-Tag-Events aus der SFX-Konfigaurion + void OutBasicBodyEvents(); + + // BACKGROUND/BGCOLOR-Option + void OutBackground( const SvxBrushItem *pBrushItem, String& rEmbGrfNm, + sal_Bool bGraphic ); + void OutBackground( const SfxItemSet& rItemSet, String &rEmbGrfName, + sal_Bool bGraphic ); + + void OutLanguage( LanguageType eLang ); + sal_uInt16 GetHTMLDirection( sal_uInt16 nDir ) const; + sal_uInt16 GetHTMLDirection( const SfxItemSet& rItemSet ) const; + void OutDirection( sal_uInt16 nDir ); + + // ALT/ALIGN/WIDTH/HEIGHT/HSPACE/VSPACE-Optionen des aktuellen + // Frame-Formats ausgeben und ggf. ein <BR CLEAR=...> vorne an + // rEndTags anhaengen + void OutFrmFmtOptions( const SwFrmFmt& rFrmFmt, const String& rAltTxt, + ByteString &rEndTags, sal_uInt32 nFrmOpts ); + void OutCSS1_TableFrmFmtOptions( const SwFrmFmt& rFrmFmt ); + void OutCSS1_SectionFmtOptions( const SwFrmFmt& rFrmFmt ); + void OutCSS1_FrmFmtOptions( const SwFrmFmt& rFrmFmt, sal_uInt32 nFrmOpts, + const SdrObject *pSdrObj=0, + const SfxItemSet *pItemSet=0 ); + void OutCSS1_FrmFmtBackground( const SwFrmFmt& rFrmFmt ); + + void ChangeParaToken( sal_uInt16 nNew ); + + void IncIndentLevel() { nIndentLvl++; } + void DecIndentLevel() { if ( nIndentLvl ) nIndentLvl--; } + void GetIndentString( ByteString& rStr, sal_uInt16 nIncLvl=0 ); + + xub_StrLen GetLineLen() { return (xub_StrLen)(Strm().Tell()-nLastLFPos); } + void OutNewLine( sal_Bool bCheck=sal_False ); + + // fuer HTMLSaveData + SwPaM* GetEndPaM() { return pOrigPam; } + void SetEndPaM( SwPaM* pPam ) { pOrigPam = pPam; } + + sal_uInt32 ToPixel( sal_uInt32 nVal ) const; + + sal_uInt16 GuessFrmType( const SwFrmFmt& rFrmFmt, + const SdrObject*& rpStrObj ); + sal_uInt16 GuessOLENodeFrmType( const SwNode& rNd ); + + void CollectFlyFrms(); + + sal_uInt16 GetHTMLFontSize( sal_uInt32 nFontHeight ) const; + + // Die aktuelle Numerierungs-Information holen. + SwHTMLNumRuleInfo& GetNumInfo() { return *pNumRuleInfo; } + + // Die Numerierungs-Information des naechsten Absatz holen. Sie + // muss noch nicht vorhanden sein! + SwHTMLNumRuleInfo *GetNextNumInfo() { return pNextNumRuleInfo; } + + // Die Numerierungs-Information des naechsten Absatz setzen. + void SetNextNumInfo( SwHTMLNumRuleInfo *pNxt ) { pNextNumRuleInfo=pNxt; } + + // Die Numerierungs-Information des naeschten Absatz fuellen. + void FillNextNumInfo(); + + // Die Numerierungs-Information des naeschten Absatz loeschen. + void ClearNextNumInfo(); + + static const SdrObject *GetHTMLControl( const SwDrawFrmFmt& rFmt ); + static const SdrObject *GetMarqueeTextObj( const SwDrawFrmFmt& rFmt ); + static sal_uInt16 GetCSS1Selector( const SwFmt *pFmt, ByteString& rToken, + String& rClass, sal_uInt16& rRefPoolId, + String *pPseudo=0 ); + + static const SwFmt *GetTemplateFmt( sal_uInt16 nPoolId, IDocumentStylePoolAccess* /*SwDoc*/ pTemplate ); + static const SwFmt *GetParentFmt( const SwFmt& rFmt, sal_uInt16 nDeep ); + + static void SubtractItemSet( SfxItemSet& rItemSet, + const SfxItemSet& rRefItemSet, + sal_Bool bSetDefaults, + sal_Bool bClearSame = sal_True, + const SfxItemSet *pRefScriptItemSet=0 ); + static sal_Bool HasScriptDependentItems( const SfxItemSet& rItemSet, + sal_Bool bCheckDropCap ); + + static void GetEEAttrsFromDrwObj( SfxItemSet& rItemSet, + const SdrObject *pObj, + sal_Bool bSetDefaults ); + + static sal_uInt16 GetDefListLvl( const String& rNm, sal_uInt16 nPoolId ); + + sal_uInt32 GetHTMLMode() const { return nHTMLMode; } + sal_Bool IsHTMLMode( sal_uInt32 nMode ) const { return (nHTMLMode & nMode) != 0; } + + inline sal_Bool IsCSS1Source( sal_uInt16 n ) const; + inline sal_Bool IsCSS1Script( sal_uInt16 n ) const; + + static const sal_Char *GetNumFormat( sal_uInt16 nFmt ); + static void PrepareFontList( const SvxFontItem& rFontItem, String& rNames, + sal_Unicode cQuote, sal_Bool bGeneric ); + static sal_uInt16 GetCSS1ScriptForScriptType( sal_uInt16 nScriptType ); + static sal_uInt16 GetLangWhichIdFromScript( sal_uInt16 nScript ); + + FieldUnit GetCSS1Unit() const { return eCSS1Unit; } +}; + +inline sal_Bool SwHTMLWriter::IsCSS1Source( sal_uInt16 n ) const +{ + return n == (nCSS1OutMode & CSS1_OUTMODE_SOURCE); +} + +inline sal_Bool SwHTMLWriter::IsCSS1Script( sal_uInt16 n ) const +{ + sal_uInt16 nScript = (nCSS1OutMode & CSS1_OUTMODE_SCRIPT); + return CSS1_OUTMODE_ANY_SCRIPT == nScript || n == nScript; +} + +inline void SwHTMLWriter::OutCSS1_PropertyAscii( const sal_Char *pProp, + const sal_Char *pVal ) +{ + OutCSS1_Property( pProp, pVal, 0 ); +} + +inline void SwHTMLWriter::OutCSS1_PropertyAscii( const sal_Char *pProp, + const ByteString& rVal ) +{ + OutCSS1_Property( pProp, rVal.GetBuffer(), 0 ); +} + +inline void SwHTMLWriter::OutCSS1_Property( const sal_Char *pProp, + const String& rVal ) +{ + OutCSS1_Property( pProp, 0, &rVal ); +} + +// Struktur speichert die aktuellen Daten des Writers zwischen, um +// einen anderen Dokument-Teil auszugeben, wie z.B. Header/Footer +// Mit den beiden USHORTs im CTOR wird ein neuer PaM erzeugt und auf +// die Position im Dokument gesetzt. +// Im Destructor werden alle Daten wieder restauriert und der angelegte +// Pam wieder geloescht. + +struct HTMLSaveData +{ + SwHTMLWriter& rWrt; + SwPaM* pOldPam, *pOldEnd; + SwHTMLNumRuleInfo *pOldNumRuleInfo; // Owner = this + SwHTMLNumRuleInfo *pOldNextNumRuleInfo; // Owner = HTML-Writer + sal_uInt16 nOldDefListLvl; + sal_uInt16 nOldDirection; + sal_Bool bOldWriteAll : 1; + sal_Bool bOldOutHeader : 1; + sal_Bool bOldOutFooter : 1; + sal_Bool bOldOutFlyFrame : 1; + const SwFlyFrmFmt* pOldFlyFmt; + + HTMLSaveData( SwHTMLWriter&, sal_uLong nStt, sal_uLong nEnd, + sal_Bool bSaveNum=sal_True, + const SwFrmFmt *pFrmFmt=0 ); + ~HTMLSaveData(); +}; + + +// einige Funktions-Deklarationen +Writer& OutHTML_FrmFmtOLENode( Writer& rWrt, const SwFrmFmt& rFmt, + sal_Bool bInCntnr ); +Writer& OutHTML_FrmFmtOLENodeGrf( Writer& rWrt, const SwFrmFmt& rFmt, + sal_Bool bInCntnr ); + +Writer& OutHTML_SwTxtNode( Writer&, const SwCntntNode& ); +Writer& OutHTML_SwTblNode( Writer& , SwTableNode &, const SwFrmFmt *, + const String* pCaption=0, sal_Bool bTopCaption=sal_False ); + +Writer& OutHTML_DrawFrmFmtAsControl( Writer& rWrt, const SwDrawFrmFmt& rFmt, + const SdrObject& rSdrObj, sal_Bool bInCntnr ); +Writer& OutHTML_DrawFrmFmtAsMarquee( Writer& rWrt, const SwDrawFrmFmt& rFmt, + const SdrObject& rSdrObj ); + +Writer& OutHTML_HeaderFooter( Writer& rWrt, const SwFrmFmt& rFrmFmt, + sal_Bool bHeader ); + +Writer& OutHTML_Image( Writer&, const SwFrmFmt& rFmt, + const String& rGrfName, const String& rAlternateTxt, + const Size& rRealSize, sal_uInt32 nFrmOpts, + const sal_Char *pMarkType = 0, + const ImageMap *pGenImgMap = 0 ); +Writer& OutHTML_BulletImage( Writer& rWrt, const sal_Char *pTag, + const SvxBrushItem* pBrush, String &rGrfName, + const Size &rSize, + const SwFmtVertOrient* pVertOrient ); + +Writer& OutHTML_SwFmtFld( Writer& rWrt, const SfxPoolItem& rHt ); +Writer& OutHTML_SwFmtFtn( Writer& rWrt, const SfxPoolItem& rHt ); +Writer& OutHTML_INetFmt( Writer&, const SwFmtINetFmt& rINetFmt, sal_Bool bOn ); + +Writer& OutCSS1_BodyTagStyleOpt( Writer& rWrt, const SfxItemSet& rItemSet, + String aEmbBGGrfName ); +Writer& OutCSS1_ParaTagStyleOpt( Writer& rWrt, const SfxItemSet& rItemSet ); + +Writer& OutCSS1_HintSpanTag( Writer& rWrt, const SfxPoolItem& rHt ); +Writer& OutCSS1_HintStyleOpt( Writer& rWrt, const SfxPoolItem& rHt ); + +Writer& OutCSS1_TableBGStyleOpt( Writer& rWrt, const SfxPoolItem& rHt ); +Writer& OutCSS1_NumBulListStyleOpt( Writer& rWrt, const SwNumRule& rNumRule, + sal_uInt8 nLevel ); + +Writer& OutHTML_NumBulListStart( SwHTMLWriter& rWrt, + const SwHTMLNumRuleInfo& rInfo ); +Writer& OutHTML_NumBulListEnd( SwHTMLWriter& rWrt, + const SwHTMLNumRuleInfo& rNextInfo ); + + +#endif // _WRTHTML_HXX + |