1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: htmlfldw.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
35 #include <com/sun/star/i18n/ScriptType.hpp>
36 #include <tools/string.hxx>
37 #include <svtools/htmlkywd.hxx>
38 #include <svtools/htmlout.hxx>
39 #include <svtools/htmltokn.h>
42 #include <breakit.hxx>
46 #include "docufld.hxx"
48 #include "htmlfld.hxx"
49 #include "wrthtml.hxx"
51 using namespace nsSwDocInfoSubType
;
53 const sal_Char
*SwHTMLWriter::GetNumFormat( USHORT nFmt
)
55 const sal_Char
*pFmtStr
= 0;
57 switch( (SvxExtNumType
)nFmt
)
59 case SVX_NUM_CHARS_UPPER_LETTER
: pFmtStr
= OOO_STRING_SW_HTML_FF_uletter
; break;
60 case SVX_NUM_CHARS_LOWER_LETTER
: pFmtStr
= OOO_STRING_SW_HTML_FF_lletter
; break;
61 case SVX_NUM_ROMAN_UPPER
: pFmtStr
= OOO_STRING_SW_HTML_FF_uroman
; break;
62 case SVX_NUM_ROMAN_LOWER
: pFmtStr
= OOO_STRING_SW_HTML_FF_lroman
; break;
63 case SVX_NUM_ARABIC
: pFmtStr
= OOO_STRING_SW_HTML_FF_arabic
; break;
64 case SVX_NUM_NUMBER_NONE
: pFmtStr
= OOO_STRING_SW_HTML_FF_none
; break;
65 case SVX_NUM_CHAR_SPECIAL
: pFmtStr
= OOO_STRING_SW_HTML_FF_char
; break;
66 case SVX_NUM_PAGEDESC
: pFmtStr
= OOO_STRING_SW_HTML_FF_page
; break;
67 case SVX_NUM_CHARS_UPPER_LETTER_N
: pFmtStr
= OOO_STRING_SW_HTML_FF_ulettern
; break;
68 case SVX_NUM_CHARS_LOWER_LETTER_N
: pFmtStr
= OOO_STRING_SW_HTML_FF_llettern
; break;
76 extern BOOL
lcl_css1atr_equalFontItems( const SfxPoolItem
& r1
, const SfxPoolItem
& r2
);
77 static Writer
& OutHTML_SwField( Writer
& rWrt
, const SwField
* pFld
,
78 const SwTxtNode
& rTxtNd
, xub_StrLen nFldPos
)
80 SwHTMLWriter
& rHTMLWrt
= (SwHTMLWriter
&)rWrt
;
82 const SwFieldType
* pFldTyp
= pFld
->GetTyp();
83 USHORT nField
= pFldTyp
->Which();
84 ULONG nFmt
= pFld
->GetFormat();
86 const sal_Char
*pTypeStr
=0, // TYPE
87 *pSubStr
=0, // SUBTYPE
88 *pFmtStr
=0; // FORMAT (SW)
89 String aValue
; // VALUE (SW)
90 BOOL bNumFmt
=FALSE
; // SDNUM (Number-Formatter-Format)
91 BOOL bNumValue
=FALSE
; // SDVAL (Number-Formatter-Value)
92 double dNumValue
= 0.0; // SDVAL (Number-Formatter-Value)
93 BOOL bFixed
=FALSE
; // SDFIXED
94 String aName
; // NAME (CUSTOM)
99 pTypeStr
= OOO_STRING_SW_HTML_FT_sender
;
100 switch( (SwExtUserSubType
)pFld
->GetSubType() )
102 case EU_COMPANY
: pSubStr
= OOO_STRING_SW_HTML_FS_company
; break;
103 case EU_FIRSTNAME
: pSubStr
= OOO_STRING_SW_HTML_FS_firstname
; break;
104 case EU_NAME
: pSubStr
= OOO_STRING_SW_HTML_FS_name
; break;
105 case EU_SHORTCUT
: pSubStr
= OOO_STRING_SW_HTML_FS_shortcut
; break;
106 case EU_STREET
: pSubStr
= OOO_STRING_SW_HTML_FS_street
; break;
107 case EU_COUNTRY
: pSubStr
= OOO_STRING_SW_HTML_FS_country
; break;
108 case EU_ZIP
: pSubStr
= OOO_STRING_SW_HTML_FS_zip
; break;
109 case EU_CITY
: pSubStr
= OOO_STRING_SW_HTML_FS_city
; break;
110 case EU_TITLE
: pSubStr
= OOO_STRING_SW_HTML_FS_title
; break;
111 case EU_POSITION
: pSubStr
= OOO_STRING_SW_HTML_FS_position
; break;
112 case EU_PHONE_PRIVATE
: pSubStr
= OOO_STRING_SW_HTML_FS_pphone
; break;
113 case EU_PHONE_COMPANY
: pSubStr
= OOO_STRING_SW_HTML_FS_cphone
; break;
114 case EU_FAX
: pSubStr
= OOO_STRING_SW_HTML_FS_fax
; break;
115 case EU_EMAIL
: pSubStr
= OOO_STRING_SW_HTML_FS_email
; break;
116 case EU_STATE
: pSubStr
= OOO_STRING_SW_HTML_FS_state
; break;
120 ASSERT( pSubStr
, "ubekannter Subtyp fuer SwExtUserField" );
121 bFixed
= ((const SwExtUserField
*)pFld
)->IsFixed();
125 pTypeStr
= OOO_STRING_SW_HTML_FT_author
;
126 switch( (SwAuthorFormat
)nFmt
& 0xff)
128 case AF_NAME
: pFmtStr
= OOO_STRING_SW_HTML_FF_name
; break;
129 case AF_SHORTCUT
: pFmtStr
= OOO_STRING_SW_HTML_FF_shortcut
; break;
131 ASSERT( pFmtStr
, "ubekanntes Format fuer SwAuthorField" );
132 bFixed
= ((const SwAuthorField
*)pFld
)->IsFixed();
135 case RES_DATETIMEFLD
:
136 pTypeStr
= OOO_STRING_SW_HTML_FT_datetime
;
138 if( ((SwDateTimeField
*)pFld
)->IsFixed() )
141 dNumValue
= ((SwDateTimeField
*)pFld
)->GetValue();
145 case RES_PAGENUMBERFLD
:
147 pTypeStr
= OOO_STRING_SW_HTML_FT_page
;
148 SwPageNumSubType eSubType
= (SwPageNumSubType
)pFld
->GetSubType();
151 case PG_RANDOM
: pSubStr
= OOO_STRING_SW_HTML_FS_random
; break;
152 case PG_NEXT
: pSubStr
= OOO_STRING_SW_HTML_FS_next
; break;
153 case PG_PREV
: pSubStr
= OOO_STRING_SW_HTML_FS_prev
; break;
155 ASSERT( pSubStr
, "ubekannter Subtyp fuer SwPageNumberField" );
156 pFmtStr
= SwHTMLWriter::GetNumFormat( static_cast< sal_uInt16
>(nFmt
) );
158 if( (SvxExtNumType
)nFmt
==SVX_NUM_CHAR_SPECIAL
)
160 aValue
= ((const SwPageNumberField
*)pFld
)->GetUserString();
164 const String
& rValue
= pFld
->GetPar2();
165 short nValue
= (short)rValue
.ToInt32();
166 if( (eSubType
== PG_NEXT
&& nValue
!=1) ||
167 (eSubType
== PG_PREV
&& nValue
!=-1) ||
168 (eSubType
== PG_RANDOM
&& nValue
!=0) )
177 USHORT nSubType
= pFld
->GetSubType();
178 pTypeStr
= OOO_STRING_SW_HTML_FT_docinfo
;
179 USHORT nExtSubType
= nSubType
& 0x0f00;
184 case DI_TITEL
: pSubStr
= OOO_STRING_SW_HTML_FS_title
; break;
185 case DI_THEMA
: pSubStr
= OOO_STRING_SW_HTML_FS_theme
; break;
186 case DI_KEYS
: pSubStr
= OOO_STRING_SW_HTML_FS_keys
; break;
187 case DI_COMMENT
: pSubStr
= OOO_STRING_SW_HTML_FS_comment
; break;
188 case DI_CREATE
: pSubStr
= OOO_STRING_SW_HTML_FS_create
; break;
189 case DI_CHANGE
: pSubStr
= OOO_STRING_SW_HTML_FS_change
; break;
190 case DI_CUSTOM
: pSubStr
= OOO_STRING_SW_HTML_FS_custom
; break;
191 default: pTypeStr
= 0; break;
194 if( DI_CUSTOM
== nSubType
) {
195 aName
= static_cast<const SwDocInfoField
*>(pFld
)->GetName();
198 if( DI_CREATE
== nSubType
|| DI_CHANGE
== nSubType
)
200 switch( nExtSubType
)
203 pFmtStr
= OOO_STRING_SW_HTML_FF_author
;
206 pFmtStr
= OOO_STRING_SW_HTML_FF_time
;
210 pFmtStr
= OOO_STRING_SW_HTML_FF_date
;
215 bFixed
= ((const SwDocInfoField
*)pFld
)->IsFixed();
220 // Fuer ein fixes Feld och den Num-Value ausgeben.
221 // Fixe Felder ohne Zahlenformate sollte es
222 // eigentlich nicht geben. ASSERT ist unten.
223 dNumValue
= ((const SwDocInfoField
*)pFld
)->GetValue();
228 // Nicht fixe Felder muessen kein Zahlenformat haben,
229 // wenn sie aus 4.0-Dokumenten stammen.
238 pTypeStr
= OOO_STRING_SW_HTML_FT_docstat
;
239 USHORT nSubType
= pFld
->GetSubType();
242 case DS_PAGE
: pSubStr
= OOO_STRING_SW_HTML_FS_page
; break;
243 case DS_PARA
: pSubStr
= OOO_STRING_SW_HTML_FS_para
; break;
244 case DS_WORD
: pSubStr
= OOO_STRING_SW_HTML_FS_word
; break;
245 case DS_CHAR
: pSubStr
= OOO_STRING_SW_HTML_FS_char
; break;
246 case DS_TBL
: pSubStr
= OOO_STRING_SW_HTML_FS_tbl
; break;
247 case DS_GRF
: pSubStr
= OOO_STRING_SW_HTML_FS_grf
; break;
248 case DS_OLE
: pSubStr
= OOO_STRING_SW_HTML_FS_ole
; break;
249 default: pTypeStr
= 0; break;
251 pFmtStr
= SwHTMLWriter::GetNumFormat( static_cast< sal_uInt16
>(nFmt
) );
255 case RES_FILENAMEFLD
:
256 pTypeStr
= OOO_STRING_SW_HTML_FT_filename
;
257 switch( (SwFileNameFormat
)(nFmt
& ~FF_FIXED
) )
259 case FF_NAME
: pFmtStr
= OOO_STRING_SW_HTML_FF_name
; break;
260 case FF_PATHNAME
: pFmtStr
= OOO_STRING_SW_HTML_FF_pathname
; break;
261 case FF_PATH
: pFmtStr
= OOO_STRING_SW_HTML_FF_path
; break;
262 case FF_NAME_NOEXT
: pFmtStr
= OOO_STRING_SW_HTML_FF_name_noext
; break;
266 bFixed
= ((const SwFileNameField
*)pFld
)->IsFixed();
267 ASSERT( pFmtStr
, "unbekanntes Format fuer SwFileNameField" );
271 // <SDFIELD>-Tag ausgeben
274 ByteString
sOut( '<' );
275 ((((sOut
+= OOO_STRING_SVTOOLS_HTML_sdfield
) += ' ') += OOO_STRING_SVTOOLS_HTML_O_type
) += '=')
278 (((sOut
+= ' ') += OOO_STRING_SVTOOLS_HTML_O_subtype
) += '=') += pSubStr
;
280 (((sOut
+= ' ') += OOO_STRING_SVTOOLS_HTML_O_format
) += '=') += pFmtStr
;
283 (((sOut
+= ' ') += OOO_STRING_SVTOOLS_HTML_O_name
) += "=\"");
284 rWrt
.Strm() << sOut
.GetBuffer();
285 HTMLOutFuncs::Out_String( rWrt
.Strm(), aName
, rHTMLWrt
.eDestEnc
, &rHTMLWrt
.aNonConvertableCharacters
);
290 ((sOut
+= ' ') += OOO_STRING_SVTOOLS_HTML_O_value
) += "=\"";
291 rWrt
.Strm() << sOut
.GetBuffer();
292 HTMLOutFuncs::Out_String( rWrt
.Strm(), aValue
, rHTMLWrt
.eDestEnc
, &rHTMLWrt
.aNonConvertableCharacters
);
297 ASSERT( nFmt
, "Zahlenformat ist 0" );
298 sOut
= HTMLOutFuncs::CreateTableDataOptionsValNum( sOut
,
299 bNumValue
, dNumValue
, nFmt
,
300 *rHTMLWrt
.pDoc
->GetNumberFormatter(),
301 rHTMLWrt
.eDestEnc
, &rHTMLWrt
.aNonConvertableCharacters
);
305 (sOut
+= ' ') += OOO_STRING_SVTOOLS_HTML_O_sdfixed
;
307 rWrt
.Strm() << sOut
.GetBuffer();
310 // Inhalt des Feldes ausgeben
311 String
sExpand( pFld
->Expand() );
312 sal_Bool bNeedsCJKProcessing
= sal_False
;
315 sal_uInt16 nScriptType
= pBreakIt
->GetBreakIter()->getScriptType( sExpand
, 0 );
316 xub_StrLen nPos
= (xub_StrLen
)pBreakIt
->GetBreakIter()->endOfScript( sExpand
, 0,
320 SwHTMLWriter::GetCSS1ScriptForScriptType( nScriptType
);
321 if( nPos
< sExpand
.Len() || nScript
!= rHTMLWrt
.nCSS1Script
)
323 bNeedsCJKProcessing
= sal_True
;
327 if( bNeedsCJKProcessing
)
329 SfxItemSet
aScriptItemSet( rWrt
.pDoc
->GetAttrPool(),
330 RES_CHRATR_FONT
, RES_CHRATR_FONTSIZE
,
331 RES_CHRATR_POSTURE
, RES_CHRATR_POSTURE
,
332 RES_CHRATR_WEIGHT
, RES_CHRATR_WEIGHT
,
333 RES_CHRATR_CJK_FONT
, RES_CHRATR_CTL_WEIGHT
,
335 rTxtNd
.GetAttr( aScriptItemSet
, nFldPos
, nFldPos
+1 );
337 sal_uInt16 aWesternWhichIds
[4] =
338 { RES_CHRATR_FONT
, RES_CHRATR_FONTSIZE
,
339 RES_CHRATR_POSTURE
, RES_CHRATR_WEIGHT
};
340 sal_uInt16 aCJKWhichIds
[4] =
341 { RES_CHRATR_CJK_FONT
, RES_CHRATR_CJK_FONTSIZE
,
342 RES_CHRATR_CJK_POSTURE
, RES_CHRATR_CJK_WEIGHT
};
343 sal_uInt16 aCTLWhichIds
[4] =
344 { RES_CHRATR_CTL_FONT
, RES_CHRATR_CTL_FONTSIZE
,
345 RES_CHRATR_CTL_POSTURE
, RES_CHRATR_CTL_WEIGHT
};
347 sal_uInt16
*pRefWhichIds
= 0;
348 switch( rHTMLWrt
.nCSS1Script
)
350 case CSS1_OUTMODE_WESTERN
:
351 pRefWhichIds
= aWesternWhichIds
;
353 case CSS1_OUTMODE_CJK
:
354 pRefWhichIds
= aCJKWhichIds
;
356 case CSS1_OUTMODE_CTL
:
357 pRefWhichIds
= aCTLWhichIds
;
364 sal_uInt16 nScriptType
= pBreakIt
->GetBreakIter()->getScriptType( sExpand
, nPos
);
366 SwHTMLWriter::GetCSS1ScriptForScriptType( nScriptType
);
367 xub_StrLen nEndPos
= (xub_StrLen
)pBreakIt
->GetBreakIter()->endOfScript(
368 sExpand
, nPos
, nScriptType
);
369 if( nScript
!= CSS1_OUTMODE_ANY_SCRIPT
&&
370 /* #108791# */ nScript
!= rHTMLWrt
.nCSS1Script
)
372 sal_uInt16
*pWhichIds
= 0;
375 case CSS1_OUTMODE_WESTERN
: pWhichIds
= aWesternWhichIds
; break;
376 case CSS1_OUTMODE_CJK
: pWhichIds
= aCJKWhichIds
; break;
377 case CSS1_OUTMODE_CTL
: pWhichIds
= aCTLWhichIds
; break;
380 rHTMLWrt
.bTagOn
= TRUE
;
381 const SfxPoolItem
*aItems
[5];
382 sal_uInt16 nItems
= 0;
383 for( sal_uInt16 i
=0; i
<4; i
++ )
385 const SfxPoolItem
*pRefItem
=
386 aScriptItemSet
.GetItem( pRefWhichIds
[i
] );
387 const SfxPoolItem
*pItem
=
388 aScriptItemSet
.GetItem( pWhichIds
[i
] );
389 if( pRefItem
&& pItem
&&
390 !(0==i
? lcl_css1atr_equalFontItems( *pRefItem
, *pItem
)
391 : *pRefItem
== *pItem
) )
393 Out( aHTMLAttrFnTab
, *pItem
, rHTMLWrt
);
394 aItems
[nItems
++] = pItem
;
398 HTMLOutFuncs::Out_String( rWrt
.Strm(), sExpand
.Copy( nPos
, nEndPos
),
399 rHTMLWrt
.eDestEnc
, &rHTMLWrt
.aNonConvertableCharacters
);
401 rHTMLWrt
.bTagOn
= FALSE
;
403 Out( aHTMLAttrFnTab
, *aItems
[--nItems
], rHTMLWrt
);
408 HTMLOutFuncs::Out_String( rWrt
.Strm(), sExpand
.Copy( nPos
, nEndPos
),
409 rHTMLWrt
.eDestEnc
, &rHTMLWrt
.aNonConvertableCharacters
);
413 while( nPos
< sExpand
.Len() );
417 HTMLOutFuncs::Out_String( rWrt
.Strm(), sExpand
,
418 rHTMLWrt
.eDestEnc
, &rHTMLWrt
.aNonConvertableCharacters
);
423 HTMLOutFuncs::Out_AsciiTag( rWrt
.Strm(), OOO_STRING_SVTOOLS_HTML_sdfield
, FALSE
);
429 Writer
& OutHTML_SwFmtFld( Writer
& rWrt
, const SfxPoolItem
& rHt
)
431 SwFmtFld
& rFld
= (SwFmtFld
&)rHt
;
432 const SwField
* pFld
= rFld
.GetFld();
433 const SwFieldType
* pFldTyp
= pFld
->GetTyp();
435 if( RES_SETEXPFLD
== pFldTyp
->Which() &&
436 (nsSwGetSetExpType::GSE_STRING
& pFld
->GetSubType()) )
439 if( pFldTyp
->GetName().EqualsAscii("HTML_ON" ) )
441 else if( !pFldTyp
->GetName().EqualsAscii( "HTML_OFF" ) )
444 String
rTxt( pFld
->GetPar2() );
445 rTxt
.EraseLeadingChars().EraseTrailingChars();
449 // TODO: HTML-Tags are written without entitities, that for, characters
450 // not contained in the destination encoding are lost!
451 ByteString
sTmp( rTxt
, ((SwHTMLWriter
&)rWrt
).eDestEnc
);
452 rWrt
.Strm() << sTmp
.GetBuffer() << '>';
454 else if( RES_POSTITFLD
== pFldTyp
->Which() )
456 // Kommentare werden im ANSI-Zeichensetz, aber mit System-Zeilen-
457 // Umbruechen gesschrieben.
458 const String
& rComment
= pFld
->GetPar2();
459 BOOL bWritten
= FALSE
;
461 if( (rComment
.Len() >= 6 && '<' == rComment
.GetChar(0) &&
462 '>' == rComment
.GetChar(rComment
.Len()-1) &&
463 rComment
.Copy( 1, 4 ).EqualsIgnoreCaseAscii(OOO_STRING_SVTOOLS_HTML_meta
)) ||
464 (rComment
.Len() >= 7 &&
465 rComment
.Copy( 0, 4 ).EqualsAscii( "<!--" ) &&
466 rComment
.Copy( rComment
.Len()-3, 3 ).EqualsAscii( "-->" )) )
468 // META-Tags direkt ausgeben
469 String
sComment( rComment
);
470 sComment
.ConvertLineEnd( GetSystemLineEnd() );
471 // TODO: HTML-Tags are written without entitities, that for,
472 // characters not contained in the destination encoding are lost!
473 ByteString
sTmp( sComment
, ((SwHTMLWriter
&)rWrt
).eDestEnc
);
474 rWrt
.Strm() << sTmp
.GetBuffer();
477 else if( rComment
.Len() >= 7 &&
478 '>' == rComment
.GetChar(rComment
.Len()-1) &&
479 rComment
.Copy(0,5).EqualsIgnoreCaseAscii("HTML:") )
481 String
sComment( rComment
.Copy(5) );
482 sComment
.EraseLeadingChars();
483 if( '<' == sComment
.GetChar(0) )
485 sComment
.ConvertLineEnd( GetSystemLineEnd() );
486 // TODO: HTML-Tags are written without entitities, that for,
487 // characters not contained in the destination encoding are
489 ByteString
sTmp( sComment
, ((SwHTMLWriter
&)rWrt
).eDestEnc
);
490 rWrt
.Strm() << sTmp
.GetBuffer();
498 ByteString
sOut( '<' );
500 String
sComment( rComment
);
501 sComment
.ConvertLineEnd( GetSystemLineEnd() );
503 (((sOut
+= OOO_STRING_SVTOOLS_HTML_comment
) += ' ')
504 += ByteString( sComment
, ((SwHTMLWriter
&)rWrt
).eDestEnc
))
506 rWrt
.Strm() << sOut
.GetBuffer();
509 else if( RES_SCRIPTFLD
== pFldTyp
->Which() )
511 SwHTMLWriter
& rHTMLWrt
= (SwHTMLWriter
&)rWrt
;
512 if( rHTMLWrt
.bLFPossible
)
513 rHTMLWrt
.OutNewLine( TRUE
);
515 BOOL bURL
= ((const SwScriptField
*)pFld
)->IsCodeURL();
516 const String
& rType
= pFld
->GetPar1();
517 String aContents
, aURL
;
519 aURL
= pFld
->GetPar2();
521 aContents
= pFld
->GetPar2();
523 // sonst ist es der Script-Inhalt selbst. Da nur noh JavaScript
524 // in Feldern landet, muss es sich um JavaSrript handeln ...:)
525 HTMLOutFuncs::OutScript( rWrt
.Strm(), rWrt
.GetBaseURL(), aContents
, rType
, JAVASCRIPT
,
526 aURL
, 0, 0, rHTMLWrt
.eDestEnc
, &rHTMLWrt
.aNonConvertableCharacters
);
528 if( rHTMLWrt
.bLFPossible
)
529 rHTMLWrt
.OutNewLine( TRUE
);
533 const SwTxtFld
*pTxtFld
= rFld
.GetTxtFld();
534 ASSERT( pTxtFld
, "Where is the txt fld?" );
536 OutHTML_SwField( rWrt
, pFld
, pTxtFld
->GetTxtNode(),
537 *pTxtFld
->GetStart() );