blob: d38e8233115b7554f80e3c9514984fd27ea5c939 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"
#include "hintids.hxx"
#include <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 );
}
}