Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <stdlib.h>
21 : #include <hintids.hxx>
22 : #include <comphelper/string.hxx>
23 : #include <svl/urihelper.hxx>
24 : #include <rtl/tencinfo.h>
25 : #include <vcl/wrkwin.hxx>
26 : #include <sfx2/linkmgr.hxx>
27 :
28 : #include <svtools/htmlcfg.hxx>
29 : #include <vcl/svapp.hxx>
30 : #include <i18nlangtag/languagetag.hxx>
31 : #include <sfx2/frmhtmlw.hxx>
32 : #include <svx/xoutbmp.hxx>
33 : #include <sfx2/htmlmode.hxx>
34 : #include <editeng/lrspitem.hxx>
35 : #include <editeng/colritem.hxx>
36 : #include <editeng/brushitem.hxx>
37 : #include <editeng/fontitem.hxx>
38 : #include <editeng/scripttypeitem.hxx>
39 : #include <editeng/langitem.hxx>
40 : #include <svl/stritem.hxx>
41 : #include <editeng/frmdiritem.hxx>
42 :
43 : #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
44 : #include <com/sun/star/document/XDocumentProperties.hpp>
45 : #include <com/sun/star/form/XFormsSupplier.hpp>
46 : #include <com/sun/star/form/XForm.hpp>
47 : #include <com/sun/star/form/XImageProducerSupplier.hpp>
48 : #include <com/sun/star/form/XFormController.hpp>
49 : #include <com/sun/star/container/XContainer.hpp>
50 : #include <com/sun/star/container/XIndexContainer.hpp>
51 : #include <com/sun/star/container/XSet.hpp>
52 : #include <fmthdft.hxx>
53 : #include <fmtfld.hxx>
54 : #include <fmtpdsc.hxx>
55 : #include <txatbase.hxx>
56 : #include <frmatr.hxx>
57 : #include <charfmt.hxx>
58 : #include <docary.hxx>
59 : #include <pam.hxx>
60 : #include <doc.hxx>
61 : #include <ndtxt.hxx>
62 : #include <mdiexp.hxx>
63 : #include <fltini.hxx>
64 : #include <viewopt.hxx>
65 : #include <IMark.hxx>
66 : #include <poolfmt.hxx>
67 : #include <pagedesc.hxx>
68 : #include <section.hxx>
69 : #include <swtable.hxx>
70 : #include <fldbas.hxx>
71 : #include <fmtclds.hxx>
72 : #include <docsh.hxx>
73 : #include <wrthtml.hxx>
74 : #include <htmlnum.hxx>
75 : #include <htmlfly.hxx>
76 : #include <swmodule.hxx>
77 : #include <statstr.hrc>
78 : #include <swerror.h>
79 : #include <rtl/strbuf.hxx>
80 : #include <IDocumentSettingAccess.hxx>
81 : #include <IDocumentStylePoolAccess.hxx>
82 : #include <xmloff/odffields.hxx>
83 :
84 : #define MAX_INDENT_LEVEL 20
85 :
86 : using namespace css;
87 :
88 : static sal_Char sIndentTabs[MAX_INDENT_LEVEL+2] =
89 : "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
90 :
91 24 : SwHTMLWriter::SwHTMLWriter( const OUString& rBaseURL )
92 : : pHTMLPosFlyFrms(NULL)
93 24 : , pNumRuleInfo(new SwHTMLNumRuleInfo)
94 : , pNextNumRuleInfo(NULL)
95 : , nHTMLMode(0)
96 : , eCSS1Unit(FUNIT_NONE)
97 : , pFootEndNotes(NULL)
98 : , pxFormComps(NULL)
99 : , pTemplate(NULL)
100 : , pDfltColor(NULL)
101 : , pStartNdIdx(NULL)
102 : , pCurrPageDesc(NULL)
103 : , pFmtFtn(NULL)
104 : , nWarn(0)
105 : , nLastLFPos(0)
106 : , nLastParaToken(0)
107 : , nBkmkTabPos(-1)
108 : , nImgMapCnt(1)
109 : , nFormCntrlCnt(0)
110 : , nEndNote(0)
111 : , nFootNote(0)
112 : , nLeftMargin(0)
113 : , nDfltLeftMargin(0)
114 : , nDfltRightMargin(0)
115 : , nFirstLineIndent(0)
116 : , nDfltFirstLineIndent(0)
117 : , nDfltTopMargin(0)
118 : , nDfltBottomMargin(0)
119 : , nIndentLvl(0)
120 : , nWhishLineLen(0)
121 : , nDefListLvl(0)
122 : , nDefListMargin(0)
123 : , nHeaderFooterSpace(0)
124 : , nTxtAttrsToIgnore(0)
125 : , nExportMode(0)
126 : , nCSS1OutMode(0)
127 : , nCSS1Script(CSS1_OUTMODE_WESTERN)
128 : , nDirection(FRMDIR_HORI_LEFT_TOP)
129 : , eDestEnc(RTL_TEXTENCODING_MS_1252)
130 : , eLang(LANGUAGE_DONTKNOW)
131 : , bCfgOutStyles( false )
132 : , bCfgPreferStyles( false )
133 : , bCfgFormFeed( false )
134 : , bCfgStarBasic( false )
135 : , bCfgCpyLinkedGrfs( false )
136 : , bFirstLine(true)
137 : , bTagOn( false )
138 : , bTxtAttr( false )
139 : , bOutOpts( false )
140 : , bOutTable( false )
141 : , bOutHeader( false )
142 : , bOutFooter( false )
143 : , bOutFlyFrame( false )
144 : , bFirstCSS1Rule( false )
145 : , bFirstCSS1Property( false )
146 : , bPoolCollTextModified( false )
147 : , bCSS1IgnoreFirstPageDesc( false )
148 : , bNoAlign( false )
149 : , bClearLeft( false )
150 : , bClearRight( false )
151 : , bLFPossible( false )
152 : , bPreserveForm( false )
153 : , bCfgNetscape4( false )
154 : , mbSkipImages(false)
155 48 : , mbSkipHeaderFooter(false)
156 : {
157 24 : SetBaseURL(rBaseURL);
158 24 : }
159 :
160 72 : SwHTMLWriter::~SwHTMLWriter()
161 : {
162 24 : delete pNumRuleInfo;
163 48 : }
164 :
165 24 : void SwHTMLWriter::SetupFilterOptions(SfxMedium& rMedium)
166 : {
167 24 : const SfxItemSet* pSet = rMedium.GetItemSet();
168 24 : if (pSet == NULL)
169 16 : return;
170 :
171 : const SfxPoolItem* pItem;
172 24 : if (pSet->GetItemState( SID_FILE_FILTEROPTIONS, true, &pItem ) != SfxItemState::SET)
173 16 : return;
174 :
175 :
176 8 : OUString sFilterOptions = ((const SfxStringItem*)pItem)->GetValue();
177 8 : if (sFilterOptions == "SkipImages")
178 : {
179 6 : mbSkipImages = true;
180 : }
181 2 : else if (sFilterOptions == "SkipHeaderFooter")
182 : {
183 2 : mbSkipHeaderFooter = true;
184 8 : }
185 : }
186 :
187 24 : sal_uLong SwHTMLWriter::WriteStream()
188 : {
189 24 : SvxHtmlOptions& rHtmlOptions = SvxHtmlOptions::Get();
190 :
191 : // font heights 1-7
192 24 : aFontHeights[0] = rHtmlOptions.GetFontSize( 0 ) * 20;
193 24 : aFontHeights[1] = rHtmlOptions.GetFontSize( 1 ) * 20;
194 24 : aFontHeights[2] = rHtmlOptions.GetFontSize( 2 ) * 20;
195 24 : aFontHeights[3] = rHtmlOptions.GetFontSize( 3 ) * 20;
196 24 : aFontHeights[4] = rHtmlOptions.GetFontSize( 4 ) * 20;
197 24 : aFontHeights[5] = rHtmlOptions.GetFontSize( 5 ) * 20;
198 24 : aFontHeights[6] = rHtmlOptions.GetFontSize( 6 ) * 20;
199 :
200 : // ueberhaupt Styles ausgeben
201 : // (dann auch obere und untere Absatz-Abstaende)
202 24 : nExportMode = rHtmlOptions.GetExportMode();
203 24 : nHTMLMode = GetHtmlMode(0);
204 :
205 24 : if( HTML_CFG_WRITER == nExportMode || HTML_CFG_NS40 == nExportMode )
206 24 : nHTMLMode |= HTMLMODE_BLOCK_SPACER;
207 :
208 24 : if( HTML_CFG_WRITER == nExportMode || HTML_CFG_MSIE == nExportMode )
209 0 : nHTMLMode |= (HTMLMODE_FLOAT_FRAME | HTMLMODE_LSPACE_IN_NUMBUL);
210 :
211 24 : if( HTML_CFG_MSIE == nExportMode )
212 0 : nHTMLMode |= HTMLMODE_NBSP_IN_TABLES;
213 :
214 24 : if( HTML_CFG_WRITER == nExportMode || HTML_CFG_NS40 == nExportMode || HTML_CFG_MSIE == nExportMode )
215 24 : nHTMLMode |= HTMLMODE_ABS_POS_FLY | HTMLMODE_ABS_POS_DRAW;
216 :
217 24 : if( HTML_CFG_WRITER == nExportMode )
218 0 : nHTMLMode |= HTMLMODE_FLY_MARGINS;
219 :
220 24 : if( HTML_CFG_NS40 == nExportMode )
221 24 : nHTMLMode |= HTMLMODE_BORDER_NONE;
222 :
223 24 : nHTMLMode |= HTMLMODE_FONT_GENERIC;
224 :
225 24 : if( HTML_CFG_NS40==nExportMode )
226 24 : nHTMLMode |= HTMLMODE_NO_CONTROL_CENTERING;
227 :
228 24 : bCfgOutStyles = IsHTMLMode(HTMLMODE_SOME_STYLES | HTMLMODE_FULL_STYLES);
229 24 : bCfgNetscape4 = (HTML_CFG_NS40 == nExportMode);
230 :
231 24 : if( IsHTMLMode(HTMLMODE_SOME_STYLES | HTMLMODE_FULL_STYLES) )
232 24 : nHTMLMode |= HTMLMODE_PRINT_EXT;
233 :
234 24 : const sal_Char *pHelpHack = getenv( "HelpEx" );
235 24 : if( pHelpHack )
236 : {
237 0 : OString aTmp(pHelpHack);
238 0 : if (aTmp.equalsIgnoreAsciiCase("Hilfe"))
239 0 : nHTMLMode |= HTMLMODE_NO_BR_AT_PAREND;
240 : }
241 :
242 24 : eCSS1Unit = (FieldUnit)SW_MOD()->GetMetric( pDoc->getIDocumentSettingAccess().get(IDocumentSettingAccess::HTML_MODE) );
243 :
244 24 : bool bWriteUTF8 = bWriteClipboardDoc;
245 24 : eDestEnc = bWriteUTF8 ? RTL_TEXTENCODING_UTF8 : rHtmlOptions.GetTextEncoding();
246 24 : const sal_Char *pCharSet = rtl_getBestMimeCharsetFromTextEncoding( eDestEnc );
247 24 : eDestEnc = rtl_getTextEncodingFromMimeCharset( pCharSet );
248 :
249 : // Nur noch fuer den MS-IE ziehen wir den Export von Styles vor.
250 24 : bCfgPreferStyles = HTML_CFG_MSIE == nExportMode;
251 :
252 24 : bCfgStarBasic = rHtmlOptions.IsStarBasic();
253 :
254 24 : bCfgFormFeed = !IsHTMLMode(HTMLMODE_PRINT_EXT);
255 24 : bCfgCpyLinkedGrfs = rHtmlOptions.IsSaveGraphicsLocal();
256 :
257 : // die HTML-Vorlage holen
258 24 : bool bOldHTMLMode = false;
259 24 : sal_uInt16 nOldTxtFmtCollCnt = 0, nOldCharFmtCnt = 0;
260 :
261 : OSL_ENSURE( !pTemplate, "Wo kommt denn die HTML-Vorlage hier her?" );
262 24 : pTemplate = ((HTMLReader*)ReadHTML)->GetTemplateDoc();
263 24 : if( pTemplate )
264 : {
265 24 : pTemplate->acquire();
266 24 : bOldHTMLMode = pTemplate->getIDocumentSettingAccess().get(IDocumentSettingAccess::HTML_MODE);
267 24 : pTemplate->getIDocumentSettingAccess().set(IDocumentSettingAccess::HTML_MODE, true);
268 :
269 24 : nOldTxtFmtCollCnt = pTemplate->GetTxtFmtColls()->size();
270 24 : nOldCharFmtCnt = pTemplate->GetCharFmts()->size();
271 : }
272 :
273 24 : if( bShowProgress )
274 24 : ::StartProgress( STR_STATSTR_W4WWRITE, 0, pDoc->GetNodes().Count(),
275 48 : pDoc->GetDocShell());
276 :
277 24 : pDfltColor = 0;
278 24 : pFootEndNotes = 0;
279 24 : pFmtFtn = 0;
280 24 : bOutTable = bOutHeader = bOutFooter = bOutFlyFrame = false;
281 24 : pxFormComps = 0;
282 24 : nFormCntrlCnt = 0;
283 24 : bPreserveForm = false;
284 24 : bClearLeft = bClearRight = false;
285 24 : bLFPossible = false;
286 :
287 24 : nLeftMargin = nDfltLeftMargin = nDfltRightMargin = 0;
288 24 : nDfltTopMargin = nDfltBottomMargin = 0;
289 24 : nFirstLineIndent = nDfltFirstLineIndent = 0;
290 24 : bPoolCollTextModified = false;
291 24 : bFirstCSS1Property = bFirstCSS1Rule = false;
292 24 : bCSS1IgnoreFirstPageDesc = false;
293 24 : nIndentLvl = 0;
294 24 : nWhishLineLen = 70;
295 24 : nLastLFPos = 0;
296 24 : nDefListLvl = 0;
297 24 : nDefListMargin = ((pTemplate && !bCfgOutStyles) ? pTemplate : pDoc)
298 24 : ->getIDocumentStylePoolAccess().GetTxtCollFromPool( RES_POOLCOLL_HTML_DD, false )
299 24 : ->GetLRSpace().GetTxtLeft();
300 24 : nHeaderFooterSpace = 0;
301 24 : nTxtAttrsToIgnore = 0;
302 24 : nCSS1OutMode = 0;
303 24 : sal_uInt16 nScript = SvtLanguageOptions::GetScriptTypeOfLanguage( GetAppLanguage() );
304 24 : switch( nScript )
305 : {
306 : case SCRIPTTYPE_ASIAN:
307 0 : nCSS1Script = CSS1_OUTMODE_CJK;
308 0 : break;
309 : case SCRIPTTYPE_COMPLEX:
310 0 : nCSS1Script = CSS1_OUTMODE_CTL;
311 0 : break;
312 : default:
313 24 : nCSS1Script = CSS1_OUTMODE_WESTERN;
314 24 : break;
315 : }
316 : eLang = ((const SvxLanguageItem&)pDoc
317 24 : ->GetDefault(GetLangWhichIdFromScript(nCSS1Script))).GetLanguage();
318 :
319 24 : nFootNote = nEndNote = 0;
320 :
321 24 : nWarn = 0;
322 24 : GetNumInfo().Clear();
323 24 : pNextNumRuleInfo = 0;
324 :
325 24 : OString aStartTags;
326 :
327 : // Tabellen und Bereiche am Doc.-Anfang beachten
328 : {
329 24 : SwTableNode * pTNd = pCurPam->GetNode().FindTableNode();
330 24 : if( pTNd && bWriteAll )
331 : {
332 : // mit dem Tabellen-Node anfangen !!
333 2 : pCurPam->GetPoint()->nNode = *pTNd;
334 :
335 2 : if( bWriteOnlyFirstTable )
336 0 : pCurPam->GetMark()->nNode = *pTNd->EndOfSectionNode();
337 : }
338 :
339 : // erster Node (der einen Seitenumbruch enthalten darf)
340 24 : pStartNdIdx = new SwNodeIndex( pCurPam->GetPoint()->nNode );
341 :
342 24 : SwSectionNode * pSNd = pCurPam->GetNode().FindSectionNode();
343 48 : while( pSNd )
344 : {
345 0 : if( bWriteAll )
346 : {
347 : // mit dem Section-Node anfangen !!
348 0 : pCurPam->GetPoint()->nNode = *pSNd;
349 : }
350 : else
351 : {
352 : OSL_ENSURE( FILE_LINK_SECTION != pSNd->GetSection().GetType(),
353 : "Export gelinkter Bereiche am Dok-Anfang ist nicht implemntiert" );
354 :
355 : // nur das Tag fuer die Section merken
356 : OString aName = HTMLOutFuncs::ConvertStringToHTML(
357 0 : pSNd->GetSection().GetSectionName(), eDestEnc,
358 0 : &aNonConvertableCharacters );
359 :
360 0 : OStringBuffer sOut;
361 0 : sOut.append('<').append(OOO_STRING_SVTOOLS_HTML_division)
362 0 : .append(' ').append(OOO_STRING_SVTOOLS_HTML_O_id)
363 0 : .append("=\"").append(aName).append('\"').append('>')
364 0 : .append(aStartTags);
365 0 : aStartTags = sOut.makeStringAndClear();
366 : }
367 : // FindSectionNode() an einem SectionNode liefert den selben!
368 0 : pSNd = pSNd->StartOfSectionNode()->FindSectionNode();
369 : }
370 : }
371 :
372 : // Tabelle fuer die freifliegenden Rahmen erzeugen, aber nur wenn
373 : // das gesamte Dokument geschrieben wird
374 24 : pHTMLPosFlyFrms = 0;
375 24 : CollectFlyFrms();
376 24 : nLastParaToken = 0;
377 24 : GetControls();
378 24 : CollectLinkTargets();
379 :
380 24 : sal_uInt16 nHeaderAttrs = 0;
381 24 : pCurrPageDesc = MakeHeader( nHeaderAttrs );
382 :
383 24 : bLFPossible = true;
384 :
385 : // Formulare, die nur HiddenControls enthalten ausgeben.
386 24 : OutHiddenForms();
387 :
388 24 : if( !aStartTags.isEmpty() )
389 0 : Strm().WriteCharPtr( aStartTags.getStr() );
390 :
391 : const SfxPoolItem *pItem;
392 24 : const SfxItemSet& rPageItemSet = pCurrPageDesc->GetMaster().GetAttrSet();
393 96 : if( !bWriteClipboardDoc && pDoc->GetDocShell() &&
394 46 : (!pDoc->getIDocumentSettingAccess().get(IDocumentSettingAccess::HTML_MODE) &&
395 66 : !pDoc->getIDocumentSettingAccess().get(IDocumentSettingAccess::BROWSE_MODE)) &&
396 20 : SfxItemState::SET == rPageItemSet.GetItemState( RES_HEADER, true, &pItem) )
397 : {
398 : const SwFrmFmt *pHeaderFmt =
399 20 : ((const SwFmtHeader *)pItem)->GetHeaderFmt();
400 20 : if( pHeaderFmt )
401 0 : OutHTML_HeaderFooter( *this, *pHeaderFmt, true );
402 : }
403 :
404 24 : nTxtAttrsToIgnore = nHeaderAttrs;
405 24 : Out_SwDoc( pOrigPam );
406 24 : nTxtAttrsToIgnore = 0;
407 :
408 24 : if( pxFormComps && pxFormComps->is() )
409 0 : OutForm( false, *pxFormComps );
410 :
411 24 : if( pFootEndNotes )
412 0 : OutFootEndNotes();
413 :
414 96 : if( !bWriteClipboardDoc && pDoc->GetDocShell() &&
415 90 : (!pDoc->getIDocumentSettingAccess().get(IDocumentSettingAccess::HTML_MODE) && !pDoc->getIDocumentSettingAccess().get(IDocumentSettingAccess::BROWSE_MODE)) &&
416 20 : SfxItemState::SET == rPageItemSet.GetItemState( RES_FOOTER, true, &pItem) )
417 : {
418 : const SwFrmFmt *pFooterFmt =
419 20 : ((const SwFmtFooter *)pItem)->GetFooterFmt();
420 20 : if( pFooterFmt )
421 2 : OutHTML_HeaderFooter( *this, *pFooterFmt, false );
422 : }
423 :
424 24 : if( bLFPossible )
425 24 : OutNewLine();
426 24 : if (!mbSkipHeaderFooter)
427 : {
428 22 : HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_body, false );
429 22 : OutNewLine();
430 22 : HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_html, false );
431 : }
432 :
433 : // loesche die Tabelle mit den freifliegenden Rahmen
434 : sal_uInt16 i;
435 : OSL_ENSURE( !pHTMLPosFlyFrms, "Wurden nicht alle Rahmen ausgegeben" );
436 24 : if( pHTMLPosFlyFrms )
437 : {
438 0 : pHTMLPosFlyFrms->DeleteAndDestroyAll();
439 0 : delete pHTMLPosFlyFrms;
440 0 : pHTMLPosFlyFrms = 0;
441 : }
442 :
443 24 : aHTMLControls.DeleteAndDestroyAll();
444 :
445 24 : if( !aChrFmtInfos.empty() )
446 0 : aChrFmtInfos.clear();
447 :
448 24 : if( !aTxtCollInfos.empty() )
449 24 : aTxtCollInfos.clear();
450 :
451 24 : if(!aImgMapNames.empty())
452 2 : aImgMapNames.clear();
453 :
454 24 : aImplicitMarks.clear();
455 :
456 24 : aOutlineMarks.clear();
457 :
458 24 : aOutlineMarkPoss.clear();
459 :
460 24 : aNumRuleNames.clear();
461 :
462 24 : aScriptParaStyles.clear();
463 24 : aScriptTextStyles.clear();
464 :
465 24 : delete pDfltColor;
466 24 : pDfltColor = 0;
467 :
468 24 : delete pStartNdIdx;
469 24 : pStartNdIdx = 0;
470 :
471 24 : delete pxFormComps;
472 24 : pxFormComps = 0;
473 :
474 : OSL_ENSURE( !pFootEndNotes,
475 : "SwHTMLWriter::Write: Ftns nicht durch OutFootEndNotes geloescht" );
476 :
477 24 : pCurrPageDesc = 0;
478 :
479 24 : ClearNextNumInfo();
480 :
481 264 : for( i=0; i<MAXLEVEL; i++ )
482 240 : aBulletGrfs[i] = "";
483 :
484 24 : aNonConvertableCharacters = "";
485 :
486 24 : if( bShowProgress )
487 24 : ::EndProgress( pDoc->GetDocShell() );
488 :
489 24 : if( pTemplate )
490 : {
491 : // Waehrend des Exports angelegte Zeichen- und Abastzvorlagen
492 : // loeschen
493 24 : sal_uInt16 nTxtFmtCollCnt = pTemplate->GetTxtFmtColls()->size();
494 48 : while( nTxtFmtCollCnt > nOldTxtFmtCollCnt )
495 0 : pTemplate->DelTxtFmtColl( --nTxtFmtCollCnt );
496 : OSL_ENSURE( pTemplate->GetTxtFmtColls()->size() == nOldTxtFmtCollCnt,
497 : "falsche Anzahl TxtFmtColls geloescht" );
498 :
499 24 : sal_uInt16 nCharFmtCnt = pTemplate->GetCharFmts()->size();
500 124 : while( nCharFmtCnt > nOldCharFmtCnt )
501 76 : pTemplate->DelCharFmt( --nCharFmtCnt );
502 : OSL_ENSURE( pTemplate->GetCharFmts()->size() == nOldCharFmtCnt,
503 : "falsche Anzahl CharFmts geloescht" );
504 :
505 : // HTML-Modus wieder restaurieren
506 24 : pTemplate->getIDocumentSettingAccess().set(IDocumentSettingAccess::HTML_MODE, bOldHTMLMode);
507 :
508 24 : if( 0 == pTemplate->release() )
509 0 : delete pTemplate;
510 :
511 24 : pTemplate = 0;
512 : }
513 :
514 24 : return nWarn;
515 : }
516 :
517 0 : static const SwFmtCol *lcl_html_GetFmtCol( const SwSection& rSection,
518 : const SwSectionFmt& rFmt )
519 : {
520 0 : const SwFmtCol *pCol = 0;
521 :
522 : const SfxPoolItem* pItem;
523 0 : if( FILE_LINK_SECTION != rSection.GetType() &&
524 0 : SfxItemState::SET == rFmt.GetAttrSet().GetItemState(RES_COL,false,&pItem) &&
525 0 : ((const SwFmtCol *)pItem)->GetNumCols() > 1 )
526 : {
527 0 : pCol = (const SwFmtCol *)pItem;
528 : }
529 :
530 0 : return pCol;
531 : }
532 :
533 0 : static bool lcl_html_IsMultiColStart( const SwHTMLWriter& rHTMLWrt, sal_uLong nIndex )
534 : {
535 0 : bool bRet = false;
536 : const SwSectionNode *pSectNd =
537 0 : rHTMLWrt.pDoc->GetNodes()[nIndex]->GetSectionNode();
538 0 : if( pSectNd )
539 : {
540 0 : const SwSection& rSection = pSectNd->GetSection();
541 0 : const SwSectionFmt *pFmt = rSection.GetFmt();
542 0 : if( pFmt && lcl_html_GetFmtCol( rSection, *pFmt ) )
543 0 : bRet = true;
544 : }
545 :
546 0 : return bRet;
547 : }
548 :
549 0 : static bool lcl_html_IsMultiColEnd( const SwHTMLWriter& rHTMLWrt, sal_uLong nIndex )
550 : {
551 0 : bool bRet = false;
552 0 : const SwEndNode *pEndNd = rHTMLWrt.pDoc->GetNodes()[nIndex]->GetEndNode();
553 0 : if( pEndNd )
554 : bRet = lcl_html_IsMultiColStart( rHTMLWrt,
555 0 : pEndNd->StartOfSectionIndex() );
556 :
557 0 : return bRet;
558 : }
559 :
560 0 : static void lcl_html_OutSectionStartTag( SwHTMLWriter& rHTMLWrt,
561 : const SwSection& rSection,
562 : const SwSectionFmt& rFmt,
563 : const SwFmtCol *pCol,
564 : bool bContinued=false )
565 : {
566 : OSL_ENSURE( pCol || !bContinued, "Continuation of DIV" );
567 :
568 0 : if( rHTMLWrt.bLFPossible )
569 0 : rHTMLWrt.OutNewLine();
570 :
571 0 : OStringBuffer sOut;
572 0 : sOut.append('<').append(OOO_STRING_SVTOOLS_HTML_division);
573 :
574 0 : const OUString& rName = rSection.GetSectionName();
575 0 : if( !rName.isEmpty() && !bContinued )
576 : {
577 0 : sOut.append(" " + OString(OOO_STRING_SVTOOLS_HTML_O_id) + "=\"");
578 0 : rHTMLWrt.Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() );
579 0 : HTMLOutFuncs::Out_String( rHTMLWrt.Strm(), rName, rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters );
580 0 : sOut.append('\"');
581 : }
582 :
583 0 : sal_uInt16 nDir = rHTMLWrt.GetHTMLDirection( rFmt.GetAttrSet() );
584 0 : rHTMLWrt.Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() );
585 0 : rHTMLWrt.OutDirection( nDir );
586 :
587 0 : if( FILE_LINK_SECTION == rSection.GetType() )
588 : {
589 0 : sOut.append(" " + OString(OOO_STRING_SVTOOLS_HTML_O_href) + "=\"");
590 0 : rHTMLWrt.Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() );
591 :
592 0 : const OUString& aFName = rSection.GetLinkFileName();
593 0 : OUString aURL( aFName.getToken(0,sfx2::cTokenSeparator) );
594 0 : OUString aFilter( aFName.getToken(1,sfx2::cTokenSeparator) );
595 0 : OUString aSection( aFName.getToken(2,sfx2::cTokenSeparator) );
596 :
597 0 : OUString aEncURL( URIHelper::simpleNormalizedMakeRelative(rHTMLWrt.GetBaseURL(), aURL ) );
598 0 : sal_Unicode cDelim = 255U;
599 0 : bool bURLContainsDelim = (-1 != aEncURL.indexOf( cDelim ) );
600 :
601 0 : HTMLOutFuncs::Out_String( rHTMLWrt.Strm(), aEncURL,
602 : rHTMLWrt.eDestEnc,
603 0 : &rHTMLWrt.aNonConvertableCharacters );
604 0 : const sal_Char* pDelim = "ÿ";
605 0 : if( !aFilter.isEmpty() || !aSection.isEmpty() || bURLContainsDelim )
606 0 : rHTMLWrt.Strm().WriteCharPtr( pDelim );
607 0 : if( !aFilter.isEmpty() )
608 0 : HTMLOutFuncs::Out_String( rHTMLWrt.Strm(), aFilter, rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters );
609 0 : if( !aSection.isEmpty() || bURLContainsDelim )
610 0 : rHTMLWrt.Strm().WriteCharPtr( pDelim );
611 0 : if( !aSection.isEmpty() )
612 : {
613 0 : sal_Int32 nPos = aSection.indexOf( '%' );
614 0 : while( nPos != -1 )
615 : {
616 0 : aSection = aSection.replaceAt(nPos, 1, "%25");
617 0 : nPos = aSection.indexOf( '%', nPos+3 );
618 : }
619 0 : nPos = aSection.indexOf( cDelim );
620 0 : while( nPos != -1 )
621 : {
622 0 : aSection = aSection.replaceAt(nPos, 1, "%FF" );
623 0 : nPos = aSection.indexOf( cDelim, nPos+3 );
624 : }
625 0 : HTMLOutFuncs::Out_String( rHTMLWrt.Strm(), aSection,
626 0 : rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters );
627 : }
628 0 : sOut.append('\"');
629 : }
630 0 : else if( pCol )
631 : {
632 : // minumum gutter width
633 0 : sal_uInt16 nGutter = pCol->GetGutterWidth( true );
634 0 : if( nGutter!=USHRT_MAX )
635 : {
636 0 : if( nGutter && Application::GetDefaultDevice() )
637 : {
638 : nGutter = (sal_uInt16)Application::GetDefaultDevice()
639 0 : ->LogicToPixel( Size(nGutter, 0), MapMode(MAP_TWIP) ).Width();
640 : }
641 0 : sOut.append(" " + OString(OOO_STRING_SVTOOLS_HTML_O_gutter) + "=\"" + OString::number(nGutter) + "\"");
642 : }
643 : }
644 :
645 0 : rHTMLWrt.Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() );
646 0 : if( rHTMLWrt.IsHTMLMode( rHTMLWrt.bCfgOutStyles ? HTMLMODE_ON : 0 ) )
647 0 : rHTMLWrt.OutCSS1_SectionFmtOptions( rFmt, pCol );
648 :
649 0 : rHTMLWrt.Strm().WriteChar( '>' );
650 :
651 0 : rHTMLWrt.bLFPossible = true;
652 0 : if( !rName.isEmpty() && !bContinued )
653 0 : rHTMLWrt.OutImplicitMark( rName, "region" );
654 :
655 0 : rHTMLWrt.IncIndentLevel();
656 0 : }
657 :
658 0 : static void lcl_html_OutSectionEndTag( SwHTMLWriter& rHTMLWrt )
659 : {
660 0 : rHTMLWrt.DecIndentLevel();
661 0 : if( rHTMLWrt.bLFPossible )
662 0 : rHTMLWrt.OutNewLine();
663 0 : HTMLOutFuncs::Out_AsciiTag( rHTMLWrt.Strm(), OOO_STRING_SVTOOLS_HTML_division, false );
664 0 : rHTMLWrt.bLFPossible = true;
665 0 : }
666 :
667 0 : static Writer& OutHTML_Section( Writer& rWrt, const SwSectionNode& rSectNd )
668 : {
669 0 : SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt;
670 :
671 : // End <PRE> and any <DL>, because a definition list's level may
672 : // change inside the section.
673 0 : rHTMLWrt.ChangeParaToken( 0 );
674 0 : rHTMLWrt.OutAndSetDefList( 0 );
675 :
676 0 : const SwSection& rSection = rSectNd.GetSection();
677 0 : const SwSectionFmt *pFmt = rSection.GetFmt();
678 : OSL_ENSURE( pFmt, "Section without a format?" );
679 :
680 0 : bool bStartTag = true;
681 0 : bool bEndTag = true;
682 0 : const SwSectionFmt *pSurrFmt = 0;
683 0 : const SwSectionNode *pSurrSectNd = 0;
684 0 : const SwSection *pSurrSection = 0;
685 0 : const SwFmtCol *pSurrCol = 0;
686 :
687 0 : sal_uInt32 nSectSttIdx = rSectNd.GetIndex();
688 0 : sal_uInt32 nSectEndIdx = rSectNd.EndOfSectionIndex();
689 0 : const SwFmtCol *pCol = lcl_html_GetFmtCol( rSection, *pFmt );
690 0 : if( pCol )
691 : {
692 : // If the next node is a columned section node, too, don't export
693 : // an empty section.
694 0 : if( lcl_html_IsMultiColStart( rHTMLWrt, nSectSttIdx+1 ) )
695 0 : bStartTag = false;
696 :
697 : // The same applies if the section end with another columned section.
698 0 : if( lcl_html_IsMultiColEnd( rHTMLWrt, nSectEndIdx-1 ) )
699 0 : bEndTag = false;
700 :
701 : //.is there a columned section around this one?
702 0 : const SwStartNode *pSttNd = rSectNd.StartOfSectionNode();
703 0 : if( pSttNd )
704 : {
705 0 : pSurrSectNd = pSttNd->FindSectionNode();
706 0 : if( pSurrSectNd )
707 : {
708 0 : const SwStartNode *pBoxSttNd = pSttNd->FindTableBoxStartNode();
709 0 : if( !pBoxSttNd ||
710 0 : pBoxSttNd->GetIndex() < pSurrSectNd->GetIndex() )
711 : {
712 0 : pSurrSection = &pSurrSectNd->GetSection();
713 0 : pSurrFmt = pSurrSection->GetFmt();
714 0 : if( pSurrFmt )
715 : pSurrCol = lcl_html_GetFmtCol( *pSurrSection,
716 0 : *pSurrFmt );
717 : }
718 : }
719 : }
720 : }
721 :
722 : // The surrounding section must be closed before the current one is
723 : // opended, except that it start immediately before the current one or
724 : // another end immediately before the current one
725 0 : if( pSurrCol && nSectSttIdx - pSurrSectNd->GetIndex() > 1 &&
726 0 : !lcl_html_IsMultiColEnd( rHTMLWrt, nSectSttIdx-1 ) )
727 0 : lcl_html_OutSectionEndTag( rHTMLWrt );
728 :
729 0 : if( bStartTag )
730 0 : lcl_html_OutSectionStartTag( rHTMLWrt, rSection, *pFmt, pCol );
731 :
732 : {
733 : HTMLSaveData aSaveData( rHTMLWrt,
734 0 : rHTMLWrt.pCurPam->GetPoint()->nNode.GetIndex()+1,
735 : rSectNd.EndOfSectionIndex(),
736 0 : false, pFmt );
737 0 : rHTMLWrt.Out_SwDoc( rHTMLWrt.pCurPam );
738 : }
739 :
740 0 : rHTMLWrt.pCurPam->GetPoint()->nNode = *rSectNd.EndOfSectionNode();
741 :
742 0 : if( bEndTag )
743 0 : lcl_html_OutSectionEndTag( rHTMLWrt );
744 :
745 : // The surrounding section must be started again, except that it ends
746 : // immeditaly behind the current one.
747 0 : if( pSurrCol &&
748 0 : pSurrSectNd->EndOfSectionIndex() - nSectEndIdx > 1 &&
749 0 : !lcl_html_IsMultiColStart( rHTMLWrt, nSectEndIdx+1 ) )
750 : lcl_html_OutSectionStartTag( rHTMLWrt, *pSurrSection, *pSurrFmt,
751 0 : pSurrCol, true );
752 :
753 0 : return rWrt;
754 : }
755 :
756 546 : void SwHTMLWriter::Out_SwDoc( SwPaM* pPam )
757 : {
758 546 : bool bSaveWriteAll = bWriteAll; // sichern
759 :
760 : // suche die naechste text::Bookmark-Position aus der text::Bookmark-Tabelle
761 546 : nBkmkTabPos = bWriteAll ? FindPos_Bkmk( *pCurPam->GetPoint() ) : -1;
762 :
763 : // gebe alle Bereiche des Pams in das HTML-File aus.
764 546 : do {
765 546 : bWriteAll = bSaveWriteAll;
766 546 : bFirstLine = true;
767 :
768 : // suche den ersten am Pam-auszugebenen FlyFrame
769 : // fehlt noch:
770 :
771 3328 : while( pCurPam->GetPoint()->nNode.GetIndex() < pCurPam->GetMark()->nNode.GetIndex() ||
772 1614 : (pCurPam->GetPoint()->nNode.GetIndex() == pCurPam->GetMark()->nNode.GetIndex() &&
773 546 : pCurPam->GetPoint()->nContent.GetIndex() <= pCurPam->GetMark()->nContent.GetIndex()) )
774 : {
775 596 : SwNode& rNd = pCurPam->GetNode();
776 :
777 : OSL_ENSURE( !(rNd.IsGrfNode() || rNd.IsOLENode()),
778 : "Grf- oder OLE-Node hier unerwartet" );
779 596 : if( rNd.IsTxtNode() )
780 : {
781 570 : SwTxtNode* pTxtNd = rNd.GetTxtNode();
782 :
783 570 : if( !bFirstLine )
784 26 : pCurPam->GetPoint()->nContent.Assign( pTxtNd, 0 );
785 :
786 570 : OutHTML_SwTxtNode( *this, *pTxtNd );
787 : }
788 26 : else if( rNd.IsTableNode() )
789 : {
790 2 : OutHTML_SwTblNode( *this, *rNd.GetTableNode(), 0 );
791 2 : nBkmkTabPos = bWriteAll ? FindPos_Bkmk( *pCurPam->GetPoint() ) : -1;
792 : }
793 24 : else if( rNd.IsSectionNode() )
794 : {
795 0 : OutHTML_Section( *this, *rNd.GetSectionNode() );
796 0 : nBkmkTabPos = bWriteAll ? FindPos_Bkmk( *pCurPam->GetPoint() ) : -1;
797 : }
798 24 : else if( &rNd == &pDoc->GetNodes().GetEndOfContent() )
799 24 : break;
800 :
801 572 : pCurPam->GetPoint()->nNode++; // Bewegen
802 572 : sal_uInt32 nPos = pCurPam->GetPoint()->nNode.GetIndex();
803 :
804 572 : if( bShowProgress )
805 572 : ::SetProgressState( nPos, pDoc->GetDocShell() ); // Wie weit ?
806 :
807 : /* sollen nur die Selectierten Bereiche gesichert werden, so
808 : * duerfen nur die vollstaendigen Nodes gespeichert werde,
809 : * d.H. der 1. und n. Node teilweise, der 2. bis n-1. Node
810 : * vollstaendig. (vollstaendig heisst mit allen Formaten! )
811 : */
812 572 : bWriteAll = bSaveWriteAll ||
813 572 : nPos != pCurPam->GetMark()->nNode.GetIndex();
814 572 : bFirstLine = false;
815 572 : bOutFooter = false; // Nach einem Node keine Fusszeile mehr
816 : }
817 :
818 546 : ChangeParaToken( 0 ); // MIB 8.7.97: Machen wir jetzt hier und nicht
819 : // beim Aufrufer
820 546 : OutAndSetDefList( 0 );
821 :
822 546 : } while( CopyNextPam( &pPam ) ); // bis alle PaM's bearbeitet
823 :
824 546 : bWriteAll = bSaveWriteAll; // wieder auf alten Wert zurueck
825 546 : }
826 :
827 : // schreibe die StyleTabelle, algemeine Angaben,Header/Footer/Footnotes
828 66 : static void OutBodyColor( const sal_Char* pTag, const SwFmt *pFmt,
829 : SwHTMLWriter& rHWrt )
830 : {
831 66 : const SwFmt *pRefFmt = 0;
832 :
833 66 : if( rHWrt.pTemplate )
834 66 : pRefFmt = SwHTMLWriter::GetTemplateFmt( pFmt->GetPoolFmtId(),
835 132 : &rHWrt.pTemplate->getIDocumentStylePoolAccess() );
836 :
837 66 : const SvxColorItem *pColorItem = 0;
838 :
839 66 : const SfxItemSet& rItemSet = pFmt->GetAttrSet();
840 66 : const SfxPoolItem *pRefItem = 0, *pItem = 0;
841 : bool bItemSet = SfxItemState::SET == rItemSet.GetItemState( RES_CHRATR_COLOR,
842 66 : true, &pItem);
843 132 : bool bRefItemSet = pRefFmt &&
844 66 : SfxItemState::SET == pRefFmt->GetAttrSet().GetItemState( RES_CHRATR_COLOR,
845 132 : true, &pRefItem);
846 66 : if( bItemSet )
847 : {
848 : // wenn das Item nur in der Vorlage des aktuellen Doks gesetzt
849 : // ist oder einen anderen Wert hat, als in der HTML-Vorlage,
850 : // wird es gesetzt
851 52 : const SvxColorItem *pCItem = (const SvxColorItem*)pItem;
852 :
853 52 : if( !bRefItemSet )
854 : {
855 8 : pColorItem = pCItem;
856 : }
857 : else
858 : {
859 44 : Color aColor( pCItem->GetValue() );
860 44 : if( COL_AUTO == aColor.GetColor() )
861 0 : aColor.SetColor( COL_BLACK );
862 :
863 44 : Color aRefColor( ((const SvxColorItem*)pRefItem)->GetValue() );
864 44 : if( COL_AUTO == aRefColor.GetColor() )
865 0 : aRefColor.SetColor( COL_BLACK );
866 :
867 44 : if( !aColor.IsRGBEqual( aRefColor ) )
868 4 : pColorItem = pCItem;
869 : }
870 : }
871 14 : else if( bRefItemSet )
872 : {
873 : // Das Item war in der HTML-Vorlage noch gesetzt, also geben wir
874 : // das Default aus
875 0 : pColorItem = (const SvxColorItem*)&rItemSet.GetPool()
876 0 : ->GetDefaultItem( RES_CHRATR_COLOR );
877 : }
878 :
879 66 : if( pColorItem )
880 : {
881 12 : OStringBuffer sOut;
882 12 : sOut.append(" " + OString(pTag) + "=");
883 12 : rHWrt.Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() );
884 12 : Color aColor( pColorItem->GetValue() );
885 12 : if( COL_AUTO == aColor.GetColor() )
886 4 : aColor.SetColor( COL_BLACK );
887 12 : HTMLOutFuncs::Out_Color( rHWrt.Strm(), aColor, rHWrt.eDestEnc );
888 12 : if( RES_POOLCOLL_STANDARD==pFmt->GetPoolFmtId() )
889 8 : rHWrt.pDfltColor = new Color( aColor );
890 : }
891 66 : }
892 :
893 22 : sal_uInt16 SwHTMLWriter::OutHeaderAttrs()
894 : {
895 22 : sal_uLong nIdx = pCurPam->GetPoint()->nNode.GetIndex();
896 22 : sal_uLong nEndIdx = pCurPam->GetMark()->nNode.GetIndex();
897 :
898 22 : SwTxtNode *pTxtNd = 0;
899 74 : while( nIdx<=nEndIdx &&
900 26 : 0==(pTxtNd=pDoc->GetNodes()[nIdx]->GetTxtNode()) )
901 4 : nIdx++;
902 :
903 : OSL_ENSURE( pTxtNd, "Kein Text-Node gefunden" );
904 22 : if( !pTxtNd || !pTxtNd->HasHints() )
905 14 : return 0;
906 :
907 8 : sal_uInt16 nAttrs = 0;
908 8 : const size_t nCntAttr = pTxtNd->GetSwpHints().Count();
909 8 : sal_Int32 nOldPos = 0;
910 20 : for( size_t i=0; i<nCntAttr; ++i )
911 : {
912 14 : const SwTxtAttr *pHt = pTxtNd->GetSwpHints()[i];
913 14 : if( !pHt->End() )
914 : {
915 2 : sal_Int32 nPos = pHt->GetStart();
916 4 : if( nPos-nOldPos > 1
917 4 : || ( pHt->Which() != RES_TXTATR_FIELD
918 0 : && pHt->Which() != RES_TXTATR_ANNOTATION ) )
919 2 : break;
920 :
921 : const sal_uInt16 nFldWhich =
922 0 : ((const SwFmtFld&)pHt->GetAttr()).GetField()->GetTyp()->Which();
923 0 : if( RES_POSTITFLD!=nFldWhich &&
924 : RES_SCRIPTFLD!=nFldWhich )
925 0 : break;
926 :
927 0 : OutNewLine();
928 0 : OutHTML_SwFmtFld( *this, pHt->GetAttr() );
929 0 : nOldPos = nPos;
930 : OSL_ENSURE( nAttrs<SAL_MAX_UINT16, "Too many attributes" );
931 0 : nAttrs++;
932 : }
933 : }
934 :
935 8 : return nAttrs;
936 : }
937 :
938 24 : const SwPageDesc *SwHTMLWriter::MakeHeader( sal_uInt16 &rHeaderAttrs )
939 : {
940 24 : OStringBuffer sOut;
941 24 : if (!mbSkipHeaderFooter)
942 : {
943 22 : sOut.append(OString(OOO_STRING_SVTOOLS_HTML_doctype) + " " + OString(OOO_STRING_SVTOOLS_HTML_doctype40));
944 22 : HTMLOutFuncs::Out_AsciiTag( Strm(), sOut.makeStringAndClear().getStr() );
945 :
946 : // baue den Vorspann
947 22 : OutNewLine();
948 22 : HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_html );
949 :
950 22 : OutNewLine();
951 22 : HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_head );
952 :
953 22 : IncIndentLevel(); // Inhalt von <HEAD> einruecken
954 :
955 : // DokumentInfo
956 22 : OString sIndent = GetIndentString();
957 :
958 44 : uno::Reference<document::XDocumentProperties> xDocProps;
959 22 : SwDocShell *pDocShell(pDoc->GetDocShell());
960 22 : if (pDocShell)
961 : {
962 : uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
963 22 : pDocShell->GetModel(), uno::UNO_QUERY_THROW);
964 22 : xDocProps.set(xDPS->getDocumentProperties());
965 : }
966 :
967 : // xDocProps may be null here (when copying)
968 22 : SfxFrameHTMLWriter::Out_DocInfo( Strm(), GetBaseURL(), xDocProps,
969 : sIndent.getStr(), eDestEnc,
970 44 : &aNonConvertableCharacters );
971 :
972 : // Kommentare und Meta-Tags des ersten Absatzes
973 22 : rHeaderAttrs = OutHeaderAttrs();
974 :
975 44 : OutFootEndNoteInfo();
976 : }
977 :
978 24 : const SwPageDesc *pPageDesc = 0;
979 :
980 : // In Nicht-HTML-Dokumenten wird die erste gesetzte Seitenvorlage
981 : // exportiert und wenn keine gesetzt ist die Standard-Vorlage
982 24 : sal_uLong nNodeIdx = pCurPam->GetPoint()->nNode.GetIndex();
983 :
984 48 : while( nNodeIdx < pDoc->GetNodes().Count() )
985 : {
986 24 : SwNode *pNd = pDoc->GetNodes()[ nNodeIdx ];
987 24 : if( pNd->IsCntntNode() )
988 : {
989 : pPageDesc = ((const SwFmtPageDesc &)pNd->GetCntntNode()
990 22 : ->GetAttr(RES_PAGEDESC)).GetPageDesc();
991 22 : break;
992 : }
993 2 : else if( pNd->IsTableNode() )
994 : {
995 2 : pPageDesc = pNd->GetTableNode()->GetTable().GetFrmFmt()
996 2 : ->GetPageDesc().GetPageDesc();
997 2 : break;
998 : }
999 :
1000 0 : nNodeIdx++;
1001 : }
1002 :
1003 24 : if( !pPageDesc )
1004 6 : pPageDesc = &pDoc->GetPageDesc( 0 );
1005 :
1006 24 : if (!mbSkipHeaderFooter)
1007 : {
1008 : // und nun ... das Style-Sheet!!!
1009 22 : if( bCfgOutStyles )
1010 : {
1011 22 : OutStyleSheet( *pPageDesc );
1012 : }
1013 :
1014 : // und nun ... das BASIC und JavaScript!
1015 22 : if( pDoc->GetDocShell() ) // nur mit DocShell ist Basic moeglich
1016 22 : OutBasic();
1017 :
1018 22 : DecIndentLevel(); // Inhalt von <HEAD> einruecken
1019 22 : OutNewLine();
1020 22 : HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_head, false );
1021 :
1022 : // der Body wird nicht eingerueckt, weil sonst alles eingerueckt waere!
1023 22 : OutNewLine();
1024 22 : sOut.append("<" + OString(OOO_STRING_SVTOOLS_HTML_body));
1025 22 : Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() );
1026 :
1027 : // language
1028 22 : OutLanguage( eLang );
1029 :
1030 : // Textfarbe ausgeben, wenn sie an der Standard-Vorlage gesetzt ist
1031 : // und sich geaendert hat.
1032 : OutBodyColor( OOO_STRING_SVTOOLS_HTML_O_text,
1033 22 : pDoc->getIDocumentStylePoolAccess().GetTxtCollFromPool( RES_POOLCOLL_STANDARD, false ),
1034 22 : *this );
1035 :
1036 : // Farben fuer (un)besuchte Links
1037 : OutBodyColor( OOO_STRING_SVTOOLS_HTML_O_link,
1038 22 : pDoc->getIDocumentStylePoolAccess().GetCharFmtFromPool( RES_POOLCHR_INET_NORMAL ),
1039 22 : *this );
1040 : OutBodyColor( OOO_STRING_SVTOOLS_HTML_O_vlink,
1041 22 : pDoc->getIDocumentStylePoolAccess().GetCharFmtFromPool( RES_POOLCHR_INET_VISIT ),
1042 22 : *this );
1043 :
1044 22 : const SfxItemSet& rItemSet = pPageDesc->GetMaster().GetAttrSet();
1045 :
1046 22 : OutBackground( rItemSet, true );
1047 :
1048 22 : nDirection = GetHTMLDirection( rItemSet );
1049 22 : OutDirection( nDirection );
1050 :
1051 22 : if( bCfgOutStyles )
1052 22 : OutCSS1_BodyTagStyleOpt( *this, rItemSet );
1053 :
1054 : // Events anhaengen
1055 22 : if( pDoc->GetDocShell() ) // nur mit DocShell ist Basic moeglich
1056 22 : OutBasicBodyEvents();
1057 :
1058 22 : Strm().WriteChar( '>' );
1059 : }
1060 :
1061 24 : return pPageDesc;
1062 : }
1063 :
1064 8 : void SwHTMLWriter::OutAnchor( const OUString& rName )
1065 : {
1066 8 : OStringBuffer sOut;
1067 8 : sOut.append("<" + OString(OOO_STRING_SVTOOLS_HTML_anchor) + " " + OString(OOO_STRING_SVTOOLS_HTML_O_name) + "=\"");
1068 8 : Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() );
1069 8 : HTMLOutFuncs::Out_String( Strm(), rName, eDestEnc, &aNonConvertableCharacters ).WriteCharPtr( "\">" );
1070 8 : HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_anchor, false );
1071 8 : }
1072 :
1073 570 : void SwHTMLWriter::OutBookmarks()
1074 : {
1075 : // hole das aktuelle Bookmark
1076 570 : const ::sw::mark::IMark* pBookmark = NULL;
1077 570 : IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
1078 570 : if(nBkmkTabPos != -1)
1079 12 : pBookmark = (pMarkAccess->getAllMarksBegin() + nBkmkTabPos)->get();
1080 : // Ausgabe aller Bookmarks in diesem Absatz. Die Content-Position
1081 : // wird vorerst nicht beruecksichtigt!
1082 570 : sal_uInt32 nNode = pCurPam->GetPoint()->nNode.GetIndex();
1083 1734 : while( nBkmkTabPos != -1
1084 582 : && pBookmark->GetMarkPos().nNode.GetIndex() == nNode )
1085 : {
1086 : // Der Bereich derBookmark wird erstam ignoriert, da er von uns
1087 : // auch nicht eingelesen wird.
1088 :
1089 : // erst die SWG spezifischen Daten:
1090 12 : if ( dynamic_cast< const ::sw::mark::IBookmark* >(pBookmark) && !pBookmark->GetName().isEmpty() )
1091 : {
1092 8 : OutAnchor( pBookmark->GetName() );
1093 : }
1094 :
1095 12 : if( ++nBkmkTabPos >= pMarkAccess->getAllMarksCount() )
1096 2 : nBkmkTabPos = -1;
1097 : else
1098 10 : pBookmark = (pMarkAccess->getAllMarksBegin() + nBkmkTabPos)->get();
1099 : }
1100 :
1101 : sal_uInt32 nPos;
1102 570 : for( nPos = 0; nPos < aOutlineMarkPoss.size() &&
1103 0 : aOutlineMarkPoss[nPos] < nNode; nPos++ )
1104 : ;
1105 :
1106 1140 : while( nPos < aOutlineMarkPoss.size() && aOutlineMarkPoss[nPos] == nNode )
1107 : {
1108 0 : OUString sMark( aOutlineMarks[nPos] );
1109 0 : OutAnchor( sMark.replace('?', '_') ); // '?' causes problems in IE/Netscape 5
1110 0 : aOutlineMarkPoss.erase( aOutlineMarkPoss.begin()+nPos );
1111 0 : aOutlineMarks.erase( aOutlineMarks.begin() + nPos );
1112 0 : }
1113 570 : }
1114 :
1115 4 : void SwHTMLWriter::OutPointFieldmarks( const SwPosition& rPos )
1116 : {
1117 : // "point" fieldmarks that occupy single character space, as opposed to
1118 : // range fieldmarks that are associated with start and end points.
1119 :
1120 4 : const IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess();
1121 4 : if (!pMarkAccess)
1122 0 : return;
1123 :
1124 4 : const sw::mark::IFieldmark* pMark = pMarkAccess->getFieldmarkFor(rPos);
1125 4 : if (!pMark)
1126 0 : return;
1127 :
1128 4 : if (pMark->GetFieldname() == ODF_FORMCHECKBOX)
1129 : {
1130 : const sw::mark::ICheckboxFieldmark* pCheckBox =
1131 4 : dynamic_cast<const sw::mark::ICheckboxFieldmark*>(pMark);
1132 :
1133 4 : if (pCheckBox)
1134 : {
1135 4 : OString aOut("<");
1136 4 : aOut += OOO_STRING_SVTOOLS_HTML_input;
1137 4 : aOut += " ";
1138 4 : aOut += OOO_STRING_SVTOOLS_HTML_O_type;
1139 4 : aOut += "=\"";
1140 4 : aOut += OOO_STRING_SVTOOLS_HTML_IT_checkbox;
1141 4 : aOut += "\"";
1142 :
1143 4 : if (pCheckBox->IsChecked())
1144 : {
1145 2 : aOut += " ";
1146 2 : aOut += OOO_STRING_SVTOOLS_HTML_O_checked;
1147 2 : aOut += "=\"";
1148 2 : aOut += OOO_STRING_SVTOOLS_HTML_O_checked;
1149 2 : aOut += "\"";
1150 : }
1151 :
1152 4 : aOut += "/>";
1153 4 : Strm().WriteCharPtr(aOut.getStr());
1154 : }
1155 : }
1156 :
1157 : // TODO : Handle other single-point fieldmark types here (if any).
1158 : }
1159 :
1160 8 : void SwHTMLWriter::OutImplicitMark( const OUString& rMark,
1161 : const sal_Char *pMarkType )
1162 : {
1163 8 : if( !rMark.isEmpty() && !aImplicitMarks.empty() )
1164 : {
1165 0 : OUString sMark( rMark );
1166 0 : sMark + OUString(cMarkSeparator) + OUString::createFromAscii(pMarkType);
1167 0 : if( 0 != aImplicitMarks.erase( sMark ) )
1168 : {
1169 0 : OutAnchor(sMark.replace('?', '_')); // '?' causes problems in IE/Netscape 5
1170 0 : }
1171 : }
1172 8 : }
1173 :
1174 4 : OUString SwHTMLWriter::convertHyperlinkHRefValue(const OUString& rURL)
1175 : {
1176 4 : OUString sURL(rURL);
1177 4 : sal_Int32 nPos = sURL.lastIndexOf(cMarkSeparator);
1178 4 : if (nPos != -1)
1179 : {
1180 0 : OUString sCompare(comphelper::string::remove(sURL.copy(nPos + 1), ' '));
1181 0 : if (!sCompare.isEmpty())
1182 : {
1183 0 : sCompare = sCompare.toAsciiLowerCase();
1184 0 : if( sCompare == "region" || sCompare == "frame" ||
1185 0 : sCompare == "graphic" || sCompare == "ole" ||
1186 0 : sCompare == "table" || sCompare == "outline" ||
1187 0 : sCompare == "text" )
1188 : {
1189 0 : sURL = sURL.replace( '?', '_' ); // '?' causes problems in IE/Netscape 5
1190 : }
1191 0 : }
1192 : }
1193 4 : return URIHelper::simpleNormalizedMakeRelative(GetBaseURL(), sURL);
1194 : }
1195 :
1196 0 : void SwHTMLWriter::OutHyperlinkHRefValue( const OUString& rURL )
1197 : {
1198 0 : OUString sURL = convertHyperlinkHRefValue(rURL);
1199 0 : HTMLOutFuncs::Out_String( Strm(), sURL, eDestEnc, &aNonConvertableCharacters );
1200 0 : }
1201 :
1202 522 : void SwHTMLWriter::OutBackground( const SvxBrushItem *pBrushItem, bool bGraphic )
1203 : {
1204 522 : const Color &rBackColor = pBrushItem->GetColor();
1205 : /// check, if background color is not "no fill"/"auto fill", instead of
1206 : /// only checking, if transparency is not set.
1207 522 : if( rBackColor.GetColor() != COL_TRANSPARENT )
1208 : {
1209 522 : OStringBuffer sOut;
1210 522 : sOut.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_bgcolor).append('=');
1211 522 : Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() );
1212 522 : HTMLOutFuncs::Out_Color( Strm(), rBackColor, eDestEnc);
1213 : }
1214 :
1215 522 : if( !bGraphic )
1216 1044 : return;
1217 :
1218 0 : OUString aGraphicInBase64;
1219 0 : const Graphic* pGrf = pBrushItem->GetGraphic();
1220 0 : if( pGrf )
1221 : {
1222 0 : sal_uLong nErr = XOutBitmap::GraphicToBase64(*pGrf, aGraphicInBase64);
1223 0 : if( nErr )
1224 : {
1225 0 : nWarn = WARN_SWG_POOR_LOAD | WARN_SW_WRITE_BASE;
1226 : }
1227 0 : Strm().WriteCharPtr( " " OOO_STRING_SVTOOLS_HTML_O_background "=\"" );
1228 0 : Strm().WriteCharPtr( OOO_STRING_SVTOOLS_HTML_O_data ":" );
1229 0 : HTMLOutFuncs::Out_String( Strm(), aGraphicInBase64, eDestEnc, &aNonConvertableCharacters ).WriteChar( '\"' );
1230 0 : }
1231 : }
1232 :
1233 24 : void SwHTMLWriter::OutBackground( const SfxItemSet& rItemSet, bool bGraphic )
1234 : {
1235 : const SfxPoolItem* pItem;
1236 24 : if( SfxItemState::SET == rItemSet.GetItemState( RES_BACKGROUND, false,
1237 24 : &pItem ))
1238 : {
1239 2 : OutBackground( ((const SvxBrushItem*)pItem), bGraphic );
1240 : }
1241 24 : }
1242 :
1243 622 : sal_uInt16 SwHTMLWriter::GetLangWhichIdFromScript( sal_uInt16 nScript )
1244 : {
1245 : sal_uInt16 nWhichId;
1246 622 : switch( nScript )
1247 : {
1248 : case CSS1_OUTMODE_CJK:
1249 0 : nWhichId = RES_CHRATR_CJK_LANGUAGE;
1250 0 : break;
1251 : case CSS1_OUTMODE_CTL:
1252 0 : nWhichId = RES_CHRATR_CJK_LANGUAGE;
1253 0 : break;
1254 : default:
1255 622 : nWhichId = RES_CHRATR_LANGUAGE;
1256 622 : break;
1257 : }
1258 622 : return nWhichId;
1259 : }
1260 :
1261 550 : void SwHTMLWriter::OutLanguage( LanguageType nLang )
1262 : {
1263 550 : if( LANGUAGE_DONTKNOW != nLang )
1264 : {
1265 550 : OStringBuffer sOut;
1266 550 : sOut.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_lang)
1267 550 : .append("=\"");
1268 550 : Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() );
1269 550 : HTMLOutFuncs::Out_String( Strm(), LanguageTag::convertToBcp47(nLang),
1270 1100 : eDestEnc, &aNonConvertableCharacters ).WriteChar( '"' );
1271 : }
1272 550 : }
1273 :
1274 24 : sal_uInt16 SwHTMLWriter::GetHTMLDirection( const SfxItemSet& rItemSet ) const
1275 : {
1276 : return GetHTMLDirection(
1277 24 : static_cast < const SvxFrameDirectionItem& >( rItemSet.Get( RES_FRAMEDIR ) )
1278 24 : .GetValue() );
1279 : }
1280 :
1281 594 : sal_uInt16 SwHTMLWriter::GetHTMLDirection( sal_uInt16 nDir ) const
1282 : {
1283 594 : switch( nDir )
1284 : {
1285 : case FRMDIR_VERT_TOP_LEFT:
1286 0 : nDir = FRMDIR_HORI_LEFT_TOP;
1287 0 : break;
1288 : case FRMDIR_VERT_TOP_RIGHT:
1289 0 : nDir = FRMDIR_HORI_RIGHT_TOP;
1290 0 : break;
1291 : case FRMDIR_ENVIRONMENT:
1292 12 : nDir = nDirection;
1293 : }
1294 :
1295 594 : return nDir;
1296 : }
1297 :
1298 22 : void SwHTMLWriter::OutDirection( sal_uInt16 nDir )
1299 : {
1300 22 : OString sConverted = convertDirection(nDir);
1301 22 : if (!sConverted.isEmpty())
1302 : {
1303 22 : OStringBuffer sOut;
1304 22 : sOut.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_dir)
1305 22 : .append("=\"").append(sConverted).append('\"');
1306 22 : Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() );
1307 22 : }
1308 22 : }
1309 :
1310 22 : OString SwHTMLWriter::convertDirection(sal_uInt16 nDir)
1311 : {
1312 22 : OString sConverted;
1313 22 : switch (nDir)
1314 : {
1315 : case FRMDIR_HORI_LEFT_TOP:
1316 : case FRMDIR_VERT_TOP_LEFT:
1317 22 : sConverted = "ltr";
1318 22 : break;
1319 : case FRMDIR_HORI_RIGHT_TOP:
1320 : case FRMDIR_VERT_TOP_RIGHT:
1321 0 : sConverted = "rtl";
1322 0 : break;
1323 : }
1324 22 : return sConverted;
1325 : }
1326 :
1327 26 : OString SwHTMLWriter::GetIndentString(sal_uInt16 nIncLvl)
1328 : {
1329 26 : OString sRet;
1330 :
1331 : // etwas umstaendlich, aber wir haben nur einen Indent-String!
1332 26 : sal_uInt16 nLevel = nIndentLvl + nIncLvl;
1333 :
1334 26 : if( nLevel && nLevel <= MAX_INDENT_LEVEL)
1335 : {
1336 24 : sIndentTabs[nLevel] = 0;
1337 24 : sRet = sIndentTabs;
1338 24 : sIndentTabs[nLevel] = '\t';
1339 : }
1340 :
1341 26 : return sRet;
1342 : }
1343 :
1344 2664 : void SwHTMLWriter::OutNewLine( bool bCheck )
1345 : {
1346 2664 : if( !bCheck || (Strm().Tell()-nLastLFPos) > nIndentLvl )
1347 : {
1348 2664 : Strm().WriteCharPtr( SAL_NEWLINE_STRING );
1349 2664 : nLastLFPos = Strm().Tell();
1350 : }
1351 :
1352 2664 : if( nIndentLvl && nIndentLvl <= MAX_INDENT_LEVEL)
1353 : {
1354 2446 : sIndentTabs[nIndentLvl] = 0;
1355 2446 : Strm().WriteCharPtr( sIndentTabs );
1356 2446 : sIndentTabs[nIndentLvl] = '\t';
1357 : }
1358 2664 : }
1359 :
1360 10 : sal_uInt16 SwHTMLWriter::GetHTMLFontSize( sal_uInt32 nHeight ) const
1361 : {
1362 10 : sal_uInt16 nSize = 1;
1363 40 : for( sal_uInt16 i=6; i>0; i-- )
1364 : {
1365 40 : if( nHeight > (aFontHeights[i] + aFontHeights[i-1])/2 )
1366 : {
1367 10 : nSize = i+1;
1368 10 : break;
1369 : }
1370 : }
1371 :
1372 10 : return nSize;
1373 : }
1374 :
1375 : // Struktur speichert die aktuellen Daten des Writers zwischen, um
1376 : // einen anderen Dokument-Teil auszugeben, wie z.B. Header/Footer
1377 522 : HTMLSaveData::HTMLSaveData(SwHTMLWriter& rWriter, sal_uLong nStt,
1378 : sal_uLong nEnd, bool bSaveNum,
1379 : const SwFrmFmt *pFrmFmt)
1380 : : rWrt(rWriter)
1381 : , pOldPam(rWrt.pCurPam)
1382 522 : , pOldEnd(rWrt.GetEndPaM())
1383 : , pOldNumRuleInfo(0)
1384 : , pOldNextNumRuleInfo(0)
1385 : , nOldDefListLvl(rWrt.nDefListLvl)
1386 : , nOldDirection(rWrt.nDirection)
1387 : , bOldOutHeader(rWrt.bOutHeader)
1388 : , bOldOutFooter(rWrt.bOutFooter)
1389 : , bOldOutFlyFrame(rWrt.bOutFlyFrame)
1390 1044 : , pOldFlyFmt(NULL)
1391 : {
1392 522 : bOldWriteAll = rWrt.bWriteAll;
1393 :
1394 522 : rWrt.pCurPam = Writer::NewSwPaM( *rWrt.pDoc, nStt, nEnd );
1395 :
1396 : // Tabelle in Sonderbereichen erkennen
1397 522 : if( nStt != rWrt.pCurPam->GetMark()->nNode.GetIndex() )
1398 : {
1399 0 : const SwNode *pNd = rWrt.pDoc->GetNodes()[ nStt ];
1400 0 : if( pNd->IsTableNode() || pNd->IsSectionNode() )
1401 0 : rWrt.pCurPam->GetMark()->nNode = nStt;
1402 : }
1403 :
1404 522 : rWrt.SetEndPaM( rWrt.pCurPam );
1405 522 : rWrt.pCurPam->Exchange( );
1406 522 : rWrt.bWriteAll = true;
1407 522 : rWrt.nDefListLvl = 0;
1408 522 : rWrt.bOutHeader = rWrt.bOutFooter = false;
1409 :
1410 : // Ggf. die aktuelle Numerierungs-Info merken, damit sie wieder
1411 : // neu aufgenommen werden kann. Nur dann belibt auch die Numerierungs-
1412 : // Info des nachsten Absatz gueltig.
1413 522 : if( bSaveNum )
1414 : {
1415 522 : pOldNumRuleInfo = new SwHTMLNumRuleInfo( rWrt.GetNumInfo() );
1416 522 : pOldNextNumRuleInfo = rWrt.GetNextNumInfo();
1417 522 : rWrt.SetNextNumInfo( 0 );
1418 : }
1419 : else
1420 : {
1421 0 : rWrt.ClearNextNumInfo();
1422 : }
1423 :
1424 : // Die Numerierung wird in jedem Fall unterbrochen.
1425 522 : rWrt.GetNumInfo().Clear();
1426 :
1427 522 : if( pFrmFmt )
1428 0 : rWrt.nDirection = rWrt.GetHTMLDirection( pFrmFmt->GetAttrSet() );
1429 522 : }
1430 :
1431 522 : HTMLSaveData::~HTMLSaveData()
1432 : {
1433 522 : delete rWrt.pCurPam; // Pam wieder loeschen
1434 :
1435 522 : rWrt.pCurPam = pOldPam;
1436 522 : rWrt.SetEndPaM( pOldEnd );
1437 522 : rWrt.bWriteAll = bOldWriteAll;
1438 522 : rWrt.nBkmkTabPos = bOldWriteAll ? rWrt.FindPos_Bkmk( *pOldPam->GetPoint() ) : -1;
1439 522 : rWrt.nLastParaToken = 0;
1440 522 : rWrt.nDefListLvl = nOldDefListLvl;
1441 522 : rWrt.nDirection = nOldDirection;
1442 522 : rWrt.bOutHeader = bOldOutHeader;
1443 522 : rWrt.bOutFooter = bOldOutFooter;
1444 522 : rWrt.bOutFlyFrame = bOldOutFlyFrame;
1445 :
1446 : // Ggf. die Numerierung von vor der Section fortsetzen. Die Numerierung
1447 : // des naecshten Absatz wird in jedem Fall ungueltig.
1448 522 : if( pOldNumRuleInfo )
1449 : {
1450 522 : rWrt.GetNumInfo().Set( *pOldNumRuleInfo );
1451 522 : delete pOldNumRuleInfo;
1452 522 : rWrt.SetNextNumInfo( pOldNextNumRuleInfo );
1453 : }
1454 : else
1455 : {
1456 0 : rWrt.GetNumInfo().Clear();
1457 0 : rWrt.ClearNextNumInfo();
1458 : }
1459 522 : }
1460 :
1461 24 : void GetHTMLWriter( const OUString&, const OUString& rBaseURL, WriterRef& xRet )
1462 : {
1463 24 : xRet = new SwHTMLWriter( rBaseURL );
1464 294 : }
1465 :
1466 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|