xref: /aoo42x/main/sw/source/filter/html/htmltabw.cxx (revision efeef26f)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 
27 
28 #include <hintids.hxx>
29 #include <vcl/svapp.hxx>
30 #include <svtools/htmlout.hxx>
31 #include <svtools/htmltokn.h>
32 #include <svtools/htmlkywd.hxx>
33 #ifndef _WRKWIN_HXX //autogen
34 #include <vcl/wrkwin.hxx>
35 #endif
36 #include <editeng/ulspitem.hxx>
37 #include <editeng/lrspitem.hxx>
38 #include <editeng/brshitem.hxx>
39 #include <editeng/boxitem.hxx>
40 #include <com/sun/star/form/XFormsSupplier.hpp>
41 #include <com/sun/star/form/XForm.hpp>
42 #include <com/sun/star/form/XImageProducerSupplier.hpp>
43 #include <com/sun/star/form/XFormController.hpp>
44 #include <com/sun/star/container/XContainer.hpp>
45 #include <com/sun/star/container/XIndexContainer.hpp>
46 #include <com/sun/star/container/XSet.hpp>
47 #include <fmtornt.hxx>
48 #include <frmfmt.hxx>
49 #include <fmtfsize.hxx>
50 #include <fmtsrnd.hxx>
51 #include <frmatr.hxx>
52 #include <doc.hxx>
53 #include <pam.hxx>
54 #include <ndtxt.hxx>
55 #include <swrect.hxx>
56 #include <cellatr.hxx>
57 #include <poolfmt.hxx>
58 #include <swtable.hxx>
59 #include <htmltbl.hxx>
60 #include <htmlnum.hxx>
61 #include <wrthtml.hxx>
62 #include <wrtswtbl.hxx>
63 #ifdef DBG_UTIL
64 #ifndef _VIEWSH_HXX
65 #include <viewsh.hxx>
66 #endif
67 #include <viewopt.hxx>
68 #endif
69 #include <sal/types.h>
70 
71 //#define MAX_DEPTH (USHRT_MAX)
72 #define MAX_DEPTH (3)
73 
74 using namespace ::com::sun::star;
75 
76 
77 class SwHTMLWrtTable : public SwWriteTable
78 {
79 	void Pixelize( sal_uInt16& rValue );
80 	void PixelizeBorders();
81 
82 	void OutTableCell( SwHTMLWriter& rWrt, const SwWriteTableCell *pCell,
83 					   sal_Bool bOutVAlign ) const;
84 
85 	void OutTableCells( SwHTMLWriter& rWrt,
86 						const SwWriteTableCells& rCells,
87 						const SvxBrushItem *pBrushItem ) const;
88 
89 	virtual sal_Bool ShouldExpandSub( const SwTableBox *pBox,
90 							sal_Bool bExpandedBefore, sal_uInt16 nDepth ) const;
91 
92 	static sal_Bool HasTabBackground( const SwTableLine& rLine,
93 						sal_Bool bTop, sal_Bool bBottom, sal_Bool bLeft, sal_Bool bRight );
94 	static sal_Bool HasTabBackground( const SwTableBox& rBox,
95 						sal_Bool bTop, sal_Bool bBottom, sal_Bool bLeft, sal_Bool bRight );
96 
97 public:
98     SwHTMLWrtTable( const SwTableLines& rLines, long nWidth, sal_uInt32 nBWidth,
99                     sal_Bool bRel, sal_uInt16 nNumOfRowsToRepeat,
100 					sal_uInt16 nLeftSub=0, sal_uInt16 nRightSub=0 );
101 	SwHTMLWrtTable( const SwHTMLTableLayout *pLayoutInfo );
102 
103     void Write( SwHTMLWriter& rWrt, sal_Int16 eAlign=text::HoriOrientation::NONE,
104 				sal_Bool bTHead=sal_False, const SwFrmFmt *pFrmFmt=0,
105                 const String *pCaption=0, sal_Bool bTopCaption=sal_False,
106 				sal_uInt16 nHSpace=0, sal_uInt16 nVSpace=0 ) const;
107 };
108 
109 
SwHTMLWrtTable(const SwTableLines & rLines,long nWidth,sal_uInt32 nBWidth,sal_Bool bRel,sal_uInt16 nNumOfRowsToRepeat,sal_uInt16 nLSub,sal_uInt16 nRSub)110 SwHTMLWrtTable::SwHTMLWrtTable( const SwTableLines& rLines, long nWidth,
111                                 sal_uInt32 nBWidth, sal_Bool bRel, sal_uInt16 nNumOfRowsToRepeat,
112 								sal_uInt16 nLSub, sal_uInt16 nRSub )
113 	: SwWriteTable( rLines, nWidth, nBWidth, bRel, MAX_DEPTH, nLSub, nRSub, nNumOfRowsToRepeat )
114 {
115 	PixelizeBorders();
116 }
117 
SwHTMLWrtTable(const SwHTMLTableLayout * pLayoutInfo)118 SwHTMLWrtTable::SwHTMLWrtTable( const SwHTMLTableLayout *pLayoutInfo )
119 	: SwWriteTable( pLayoutInfo )
120 {
121 	// Einige Twip-Werte an Pixel-Grenzen anpassen
122 	if( bCollectBorderWidth )
123 		PixelizeBorders();
124 }
125 
Pixelize(sal_uInt16 & rValue)126 void SwHTMLWrtTable::Pixelize( sal_uInt16& rValue )
127 {
128 	if( rValue && Application::GetDefaultDevice() )
129 	{
130 		Size aSz( rValue, 0 );
131 		aSz = Application::GetDefaultDevice()->LogicToPixel( aSz, MapMode(MAP_TWIP) );
132 		if( !aSz.Width() )
133 			aSz.Width() = 1;
134 		aSz = Application::GetDefaultDevice()->PixelToLogic( aSz, MapMode(MAP_TWIP) );
135 		rValue = (sal_uInt16)aSz.Width();
136 	}
137 }
138 
PixelizeBorders()139 void SwHTMLWrtTable::PixelizeBorders()
140 {
141 	Pixelize( nBorder );
142 	Pixelize( nCellSpacing );
143 	Pixelize( nCellPadding );
144 }
145 
HasTabBackground(const SwTableBox & rBox,sal_Bool bTop,sal_Bool bBottom,sal_Bool bLeft,sal_Bool bRight)146 sal_Bool SwHTMLWrtTable::HasTabBackground( const SwTableBox& rBox,
147 						sal_Bool bTop, sal_Bool bBottom, sal_Bool bLeft, sal_Bool bRight )
148 {
149 	ASSERT( bTop || bBottom || bLeft || bRight,
150 			"HasTabBackground: darf nicht aufgerufen werden" );
151 
152 	sal_Bool bRet = sal_False;
153 	if( rBox.GetSttNd() )
154 	{
155 		const SvxBrushItem& rBrushItem =
156 			rBox.GetFrmFmt()->GetBackground();
157 
158         /// OD 02.09.2002 #99657#
159         /// The table box has a background, if its background color is not "no fill"/
160         /// "auto fill" or it has a background graphic.
161         bRet = rBrushItem.GetColor() != COL_TRANSPARENT ||
162 			   rBrushItem.GetGraphicLink() || rBrushItem.GetGraphic();
163 	}
164 	else
165 	{
166 		const SwTableLines& rLines = rBox.GetTabLines();
167 		sal_uInt16 nCount = rLines.Count();
168 		sal_Bool bLeftRight = bLeft || bRight;
169 		for( sal_uInt16 i=0; !bRet && i<nCount; i++ )
170 		{
171 			sal_Bool bT = bTop && 0 == i;
172 			sal_Bool bB = bBottom && nCount-1 == i;
173 			if( bT || bB || bLeftRight )
174 				bRet = HasTabBackground( *rLines[i], bT, bB, bLeft, bRight);
175 		}
176 	}
177 
178 	return bRet;
179 }
180 
HasTabBackground(const SwTableLine & rLine,sal_Bool bTop,sal_Bool bBottom,sal_Bool bLeft,sal_Bool bRight)181 sal_Bool SwHTMLWrtTable::HasTabBackground( const SwTableLine& rLine,
182 						sal_Bool bTop, sal_Bool bBottom, sal_Bool bLeft, sal_Bool bRight )
183 {
184 	ASSERT( bTop || bBottom || bLeft || bRight,
185 			"HasTabBackground: darf nicht aufgerufen werden" );
186 
187 	sal_Bool bRet = sal_False;
188 	const SvxBrushItem& rBrushItem = rLine.GetFrmFmt()->GetBackground();
189     /// OD 02.09.2002 #99657#
190     /// The table line has a background, if its background color is not "no fill"/
191     /// "auto fill" or it has a background graphic.
192     bRet = rBrushItem.GetColor() != COL_TRANSPARENT ||
193 		   rBrushItem.GetGraphicLink() || rBrushItem.GetGraphic();
194 
195 	if( !bRet )
196 	{
197 		const SwTableBoxes& rBoxes = rLine.GetTabBoxes();
198 		sal_uInt16 nCount = rBoxes.Count();
199 		sal_Bool bTopBottom = bTop || bBottom;
200 		for( sal_uInt16 i=0; !bRet && i<nCount; i++ )
201 		{
202 			sal_Bool bL = bLeft && 0 == i;
203 			sal_Bool bR = bRight && nCount-1 == i;
204 			if( bTopBottom || bL || bR )
205 				bRet = HasTabBackground( *rBoxes[i], bTop, bBottom, bL, bR );
206 		}
207 	}
208 
209 	return bRet;
210 }
211 
212 sal_Bool lcl_WrtHTMLTbl_HasTabBorders( const SwTableLine*& rpLine, void* pPara );
213 
lcl_WrtHTMLTbl_HasTabBorders(const SwTableBox * & rpBox,void * pPara)214 sal_Bool lcl_WrtHTMLTbl_HasTabBorders( const SwTableBox*& rpBox, void* pPara )
215 {
216 	sal_Bool *pBorders = (sal_Bool *)pPara;
217 	if( *pBorders )
218 		return sal_False;
219 
220 	if( !rpBox->GetSttNd() )
221 	{
222 		((SwTableBox *)rpBox)->GetTabLines().ForEach(
223 								&lcl_WrtHTMLTbl_HasTabBorders, pPara );
224 	}
225 	else
226 	{
227 		const SvxBoxItem& rBoxItem =
228             (const SvxBoxItem&)rpBox->GetFrmFmt()->GetFmtAttr( RES_BOX );
229 
230 		*pBorders = rBoxItem.GetTop() || rBoxItem.GetBottom() ||
231 					rBoxItem.GetLeft() || rBoxItem.GetRight();
232 	}
233 
234 	return !*pBorders;
235 }
236 
lcl_WrtHTMLTbl_HasTabBorders(const SwTableLine * & rpLine,void * pPara)237 sal_Bool lcl_WrtHTMLTbl_HasTabBorders( const SwTableLine*& rpLine, void* pPara )
238 {
239 	sal_Bool *pBorders = (sal_Bool *)pPara;
240 	if( *pBorders )
241 		return sal_False;
242 
243 	((SwTableLine *)rpLine)->GetTabBoxes().ForEach(
244 									&lcl_WrtHTMLTbl_HasTabBorders, pPara );
245 	return !*pBorders;
246 }
247 
248 
ShouldExpandSub(const SwTableBox * pBox,sal_Bool bExpandedBefore,sal_uInt16 nDepth) const249 sal_Bool SwHTMLWrtTable::ShouldExpandSub( const SwTableBox *pBox,
250 									  sal_Bool bExpandedBefore,
251 									  sal_uInt16 nDepth ) const
252 {
253 	sal_Bool bExpand = !pBox->GetSttNd() && nDepth>0;
254 	if( bExpand && bExpandedBefore )
255 	{
256 		// MIB 30.6.97: Wenn schon eine Box expandiert wurde, wird eine
257 		// weitere nur expandiert, wenn sie Umrandungen besitzt.
258 		sal_Bool bBorders = sal_False;
259 		lcl_WrtHTMLTbl_HasTabBorders( pBox, &bBorders );
260 		if( !bBorders )
261 			bBorders = HasTabBackground( *pBox, sal_True, sal_True, sal_True, sal_True );
262 		bExpand = bBorders;
263 	}
264 
265 	return bExpand;
266 }
267 
268 
269 // Eine Box als einzelne Zelle schreiben
OutTableCell(SwHTMLWriter & rWrt,const SwWriteTableCell * pCell,sal_Bool bOutVAlign) const270 void SwHTMLWrtTable::OutTableCell( SwHTMLWriter& rWrt,
271 								   const SwWriteTableCell *pCell,
272 								   sal_Bool bOutVAlign ) const
273 {
274 	const SwTableBox *pBox = pCell->GetBox();
275 	sal_uInt16 nRow = pCell->GetRow();
276 	sal_uInt16 nCol = pCell->GetCol();
277 	sal_uInt16 nRowSpan = pCell->GetRowSpan();
278 	sal_uInt16 nColSpan = pCell->GetColSpan();
279 
280     if ( !nRowSpan )
281         return;
282 
283 	SwWriteTableCol *pCol = aCols[nCol];
284 
285 //	sal_Bool bOutWidth = nColSpan>1 || pCol->GetOutWidth();
286 	sal_Bool bOutWidth = sal_True; //nColSpan==1 && pCol->GetOutWidth();
287 
288 	const SwStartNode* pSttNd = pBox->GetSttNd();
289 	sal_Bool bHead = sal_False;
290 	if( pSttNd )
291 	{
292 		sal_uLong nNdPos = pSttNd->GetIndex()+1;
293 
294 		// Art der Zelle (TD/TH) bestimmen
295 		SwNode* pNd;
296 		while( !( pNd = rWrt.pDoc->GetNodes()[nNdPos])->IsEndNode() )
297 		{
298 			if( pNd->IsTxtNode() )
299 			{
300 				// nur Absaetzte betrachten, an denen man was erkennt
301 				// Das ist der Fall, wenn die Vorlage eine der Tabellen-Vorlagen
302 				// ist oder von einer der beiden abgelitten ist.
303 				const SwFmt *pFmt = &((SwTxtNode*)pNd)->GetAnyFmtColl();
304 				sal_uInt16 nPoolId = pFmt->GetPoolFmtId();
305 				while( !pFmt->IsDefault() &&
306 					   RES_POOLCOLL_TABLE_HDLN!=nPoolId &&
307 					   RES_POOLCOLL_TABLE!=nPoolId )
308 				{
309 					pFmt = pFmt->DerivedFrom();
310 					nPoolId = pFmt->GetPoolFmtId();
311 				}
312 
313 				if( !pFmt->IsDefault() )
314 				{
315 					bHead = (RES_POOLCOLL_TABLE_HDLN==nPoolId);
316 					break;
317 				}
318 			}
319 			nNdPos++;
320 		}
321 	}
322 
323 	rWrt.OutNewLine();	// <TH>/<TD> in neue Zeile
324 	ByteString sOut( '<' );
325 	sOut += (bHead ? OOO_STRING_SVTOOLS_HTML_tableheader : OOO_STRING_SVTOOLS_HTML_tabledata );
326 
327 	// ROW- und COLSPAN ausgeben
328 	if( nRowSpan>1 )
329 		(((sOut += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_rowspan ) += '=')
330 			+= ByteString::CreateFromInt32( nRowSpan );
331 	if( nColSpan > 1 )
332 		(((sOut += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_colspan ) += '=')
333 			+= ByteString::CreateFromInt32( nColSpan );
334 
335 #ifndef PURE_HTML
336 	long nWidth = 0;
337     sal_uInt32 nPrcWidth = USHRT_MAX;
338 	if( bOutWidth )
339 	{
340 		if( bLayoutExport )
341 		{
342 			if( pCell->HasPrcWidthOpt() )
343 			{
344 				nPrcWidth = pCell->GetWidthOpt();
345 			}
346 			else
347 			{
348 				nWidth = pCell->GetWidthOpt();
349 				if( !nWidth )
350 					bOutWidth = sal_False;
351 			}
352 		}
353 		else
354 		{
355 			if( HasRelWidths() )
356 				nPrcWidth = (sal_uInt16)GetPrcWidth(nCol,nColSpan);
357 			else
358 				nWidth = GetAbsWidth( nCol, nColSpan );
359 		}
360 	}
361 
362 	long nHeight = pCell->GetHeight() > 0
363 						? GetAbsHeight( pCell->GetHeight(), nRow, nRowSpan )
364 						: 0;
365 	Size aPixelSz( nWidth, nHeight );
366 
367 	// WIDTH ausgeben (Grrr: nur fuer Netscape)
368 	if( (aPixelSz.Width() || aPixelSz.Height()) && Application::GetDefaultDevice() )
369 	{
370 		Size aOldSz( aPixelSz );
371 		aPixelSz = Application::GetDefaultDevice()->LogicToPixel( aPixelSz,
372 														MapMode(MAP_TWIP) );
373 		if( aOldSz.Width() && !aPixelSz.Width() )
374 			aPixelSz.Width() = 1;
375 		if( aOldSz.Height() && !aPixelSz.Height() )
376 			aPixelSz.Height() = 1;
377 	}
378 
379 	// WIDTH ausgeben: Aus Layout oder berechnet
380 	if( bOutWidth )
381 	{
382 		((sOut += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_width ) += '=';
383 		if( nPrcWidth != USHRT_MAX )
384 			(sOut += ByteString::CreateFromInt32(nPrcWidth)) += '%';
385 		else
386 			sOut += ByteString::CreateFromInt32(aPixelSz.Width());
387 		if( !bLayoutExport && nColSpan==1 )
388 			pCol->SetOutWidth( sal_False );
389 	}
390 
391 	if( nHeight )
392 	{
393 		(((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_height) += '=')
394 			+= ByteString::CreateFromInt32(aPixelSz.Height());
395 	}
396 #endif
397 
398 	const SfxItemSet& rItemSet = pBox->GetFrmFmt()->GetAttrSet();
399 	const SfxPoolItem *pItem;
400 
401 	// ALIGN wird jetzt nur noch an den Absaetzen ausgegeben
402 
403 	// VALIGN ausgeben
404 	if( bOutVAlign )
405 	{
406         sal_Int16 eVertOri = pCell->GetVertOri();
407         if( text::VertOrientation::TOP==eVertOri || text::VertOrientation::BOTTOM==eVertOri )
408 		{
409 			(((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_valign) += '=')
410                 += (text::VertOrientation::TOP==eVertOri ? OOO_STRING_SVTOOLS_HTML_VA_top : OOO_STRING_SVTOOLS_HTML_VA_bottom);
411 		}
412 	}
413 
414 	rWrt.Strm() << sOut.GetBuffer();
415 	sOut.Erase();
416 
417 	rWrt.bTxtAttr = sal_False;
418 	rWrt.bOutOpts = sal_True;
419 	const SvxBrushItem *pBrushItem = 0;
420 	if( SFX_ITEM_SET==rItemSet.GetItemState( RES_BACKGROUND, sal_False, &pItem ) )
421 	{
422 		pBrushItem = (const SvxBrushItem *)pItem;
423 	}
424 	if( !pBrushItem )
425 		pBrushItem = pCell->GetBackground();
426 
427 	if( pBrushItem )
428 	{
429 		// Hintergrund ausgeben
430 		String aDummy;
431 		rWrt.OutBackground( pBrushItem, aDummy, sal_False );
432 
433 		if( rWrt.bCfgOutStyles )
434 			OutCSS1_TableBGStyleOpt( rWrt, *pBrushItem );
435 	}
436 
437 	sal_uInt32 nNumFmt = 0;
438 	double nValue = 0.0;
439 	sal_Bool bNumFmt = sal_False, bValue = sal_False;
440 	if( SFX_ITEM_SET==rItemSet.GetItemState( RES_BOXATR_FORMAT, sal_False, &pItem ) )
441 	{
442 		nNumFmt = ((const SwTblBoxNumFormat *)pItem)->GetValue();
443 		bNumFmt = sal_True;
444 	}
445 	if( SFX_ITEM_SET==rItemSet.GetItemState( RES_BOXATR_VALUE, sal_False, &pItem ) )
446 	{
447 		nValue = ((const SwTblBoxValue *)pItem)->GetValue();
448 		bValue = sal_True;
449 		if( !bNumFmt )
450 			nNumFmt = pBox->GetFrmFmt()->GetTblBoxNumFmt().GetValue();
451 	}
452 
453 	if( bNumFmt || bValue )
454 		sOut = HTMLOutFuncs::CreateTableDataOptionsValNum( sOut,
455 					bValue, nValue, nNumFmt, *rWrt.pDoc->GetNumberFormatter(),
456                     rWrt.eDestEnc, &rWrt.aNonConvertableCharacters );
457 	sOut += '>';
458 	rWrt.Strm() << sOut.GetBuffer();
459 	rWrt.bLFPossible = sal_True;
460 
461 	rWrt.IncIndentLevel();	// den Inhalt von <TD>...</TD> einruecken
462 
463 	if( pSttNd )
464 	{
465 		HTMLSaveData aSaveData( rWrt, pSttNd->GetIndex()+1,
466 								pSttNd->EndOfSectionIndex() );
467 		rWrt.Out_SwDoc( rWrt.pCurPam );
468 	}
469 	else
470 	{
471         sal_uInt16 nTWidth;
472         sal_uInt32 nBWidth;
473         sal_uInt16 nLSub, nRSub;
474 		if( HasRelWidths() )
475 		{
476 			nTWidth = 100;
477 			nBWidth = GetRawWidth( nCol, nColSpan );
478 			nLSub = 0;
479 			nRSub = 0;
480 		}
481 		else
482 		{
483 			nTWidth = GetAbsWidth( nCol, nColSpan );
484 			nBWidth = nTWidth;
485 			nLSub = GetLeftSpace( nCol );
486 			nRSub = GetRightSpace( nCol, nColSpan );
487 		}
488 
489 		SwHTMLWrtTable aTableWrt( pBox->GetTabLines(), nTWidth,
490 								  nBWidth, HasRelWidths(), nLSub, nRSub );
491 		aTableWrt.Write( rWrt );
492 	}
493 
494 	rWrt.DecIndentLevel();	// den Inhalt von <TD>...</TD> einruecken
495 
496 	if( rWrt.bLFPossible )
497 		rWrt.OutNewLine();
498 	HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), bHead ? OOO_STRING_SVTOOLS_HTML_tableheader
499 											  	   : OOO_STRING_SVTOOLS_HTML_tabledata,
500 								sal_False );
501 	rWrt.bLFPossible = sal_True;
502 }
503 
504 
505 // Eine Line als Zeilen ausgeben
OutTableCells(SwHTMLWriter & rWrt,const SwWriteTableCells & rCells,const SvxBrushItem * pBrushItem) const506 void SwHTMLWrtTable::OutTableCells( SwHTMLWriter& rWrt,
507 								    const SwWriteTableCells& rCells,
508 									const SvxBrushItem *pBrushItem ) const
509 {
510 	// Wenn die Zeile mehr als eine Zelle nethaelt und alle Zellen
511 	// die gleiche Ausrichtung besitzen, das VALIGN an der Zeile statt der
512 	// Zelle ausgeben
513     sal_Int16 eRowVertOri = text::VertOrientation::NONE;
514 	if( rCells.Count() > 1 )
515 	{
516 		for( sal_uInt16 nCell = 0; nCell<rCells.Count(); nCell++ )
517 		{
518             sal_Int16 eCellVertOri = rCells[nCell]->GetVertOri();
519 			if( 0==nCell )
520 			{
521 				eRowVertOri = eCellVertOri;
522 			}
523 			else if( eRowVertOri != eCellVertOri )
524 			{
525                 eRowVertOri = text::VertOrientation::NONE;
526 				break;
527 			}
528 		}
529 	}
530 
531 	rWrt.OutNewLine();	// <TR> in neuer Zeile
532 	rWrt.Strm() << '<' << OOO_STRING_SVTOOLS_HTML_tablerow;
533 	if( pBrushItem )
534 	{
535 		String aDummy;
536 		rWrt.OutBackground( pBrushItem, aDummy, sal_False );
537 
538 		rWrt.bTxtAttr = sal_False;
539 		rWrt.bOutOpts = sal_True;
540 		if( rWrt.bCfgOutStyles )
541 			OutCSS1_TableBGStyleOpt( rWrt, *pBrushItem );
542 	}
543 
544     if( text::VertOrientation::TOP==eRowVertOri || text::VertOrientation::BOTTOM==eRowVertOri )
545 	{
546 		ByteString sOut( ' ' );
547 		((sOut += OOO_STRING_SVTOOLS_HTML_O_valign) += '=')
548             += (text::VertOrientation::TOP==eRowVertOri ? OOO_STRING_SVTOOLS_HTML_VA_top : OOO_STRING_SVTOOLS_HTML_VA_bottom);
549 		rWrt.Strm() << sOut.GetBuffer();
550 	}
551 
552 	rWrt.Strm() << '>';
553 
554 	rWrt.IncIndentLevel(); // Inhalt von <TR>...</TR> einruecken
555 
556 	for( sal_uInt16 nCell = 0; nCell<rCells.Count(); nCell++ )
557         OutTableCell( rWrt, rCells[nCell], text::VertOrientation::NONE==eRowVertOri );
558 
559 	rWrt.DecIndentLevel(); // Inhalt von <TR>...</TR> einruecken
560 
561 	rWrt.OutNewLine();	// </TR> in neuer Zeile
562 	HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_tablerow, sal_False );
563 }
564 
565 
566 
Write(SwHTMLWriter & rWrt,sal_Int16 eAlign,sal_Bool bTHead,const SwFrmFmt * pFrmFmt,const String * pCaption,sal_Bool bTopCaption,sal_uInt16 nHSpace,sal_uInt16 nVSpace) const567 void SwHTMLWrtTable::Write( SwHTMLWriter& rWrt, sal_Int16 eAlign,
568 							sal_Bool bTHead, const SwFrmFmt *pFrmFmt,
569 							const String *pCaption,	sal_Bool bTopCaption,
570 							sal_uInt16 nHSpace, sal_uInt16 nVSpace ) const
571 {
572 	sal_uInt16 nRow;
573 
574 	// Wert fuer FRAME bestimmen
575 	sal_uInt16 nFrameMask = 15;
576 	if( !(aRows[0])->bTopBorder )
577 		nFrameMask &= ~1;
578 	if( !(aRows[aRows.Count()-1])->bBottomBorder )
579 		nFrameMask &= ~2;
580 	if( !(aCols[0])->bLeftBorder )
581 		nFrameMask &= ~4;
582 	if( !(aCols[aCols.Count()-1])->bRightBorder )
583 		nFrameMask &= ~8;
584 
585 	// Wert fur RULES bestimmen
586 	sal_Bool bRowsHaveBorder = sal_False;
587 	sal_Bool bRowsHaveBorderOnly = sal_True;
588 	SwWriteTableRow *pRow = aRows[0];
589 	for( nRow=1; nRow < aRows.Count(); nRow++ )
590 	{
591 		SwWriteTableRow *pNextRow = aRows[nRow];
592 		sal_Bool bBorder = ( pRow->bBottomBorder || pNextRow->bTopBorder );
593 		bRowsHaveBorder |= bBorder;
594 		bRowsHaveBorderOnly &= bBorder;
595 
596 		sal_uInt16 nBorder2 = pRow->bBottomBorder ? pRow->nBottomBorder : USHRT_MAX;
597 		if( pNextRow->bTopBorder && pNextRow->nTopBorder < nBorder2 )
598 			nBorder2 = pNextRow->nTopBorder;
599 
600 		pRow->bBottomBorder = bBorder;
601 		pRow->nBottomBorder = nBorder2;
602 
603 		pNextRow->bTopBorder = bBorder;
604 		pNextRow->nTopBorder = nBorder2;
605 
606 		pRow = pNextRow;
607 	}
608 
609 	sal_Bool bColsHaveBorder = sal_False;
610 	sal_Bool bColsHaveBorderOnly = sal_True;
611 	SwWriteTableCol *pCol = aCols[0];
612 	sal_uInt16 nCol;
613 	for( nCol=1; nCol<aCols.Count(); nCol++ )
614 	{
615 		SwWriteTableCol *pNextCol = aCols[nCol];
616 		sal_Bool bBorder = ( pCol->bRightBorder || pNextCol->bLeftBorder );
617 		bColsHaveBorder |= bBorder;
618 		bColsHaveBorderOnly &= bBorder;
619 		pCol->bRightBorder = bBorder;
620 		pNextCol->bLeftBorder = bBorder;
621 		pCol = pNextCol;
622 	}
623 
624 
625 	// vorhergende Aufzaehlung etc. beenden
626 	rWrt.ChangeParaToken( 0 );
627 
628 	if( rWrt.bLFPossible )
629 		rWrt.OutNewLine();	// <TABLE> in neue Zeile
630 	ByteString sOut( '<' );
631 	sOut += OOO_STRING_SVTOOLS_HTML_table;
632 
633 	sal_uInt16 nOldDirection = rWrt.nDirection;
634 	if( pFrmFmt )
635 		rWrt.nDirection = rWrt.GetHTMLDirection( pFrmFmt->GetAttrSet() );
636 	if( rWrt.bOutFlyFrame || nOldDirection != rWrt.nDirection )
637 	{
638 		rWrt.Strm() << sOut.GetBuffer();
639 		sOut.Erase();
640 		rWrt.OutDirection( rWrt.nDirection );
641 	}
642 
643 	// COLS ausgeben: Nur bei Export ueber Layout, wenn es beim Import
644 	// vorhanden war.
645 	if( bColsOption )
646 		(((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_cols) += '=')
647 			+= ByteString::CreateFromInt32( aCols.Count() );
648 
649 	// ALIGN= ausgeben
650     if( text::HoriOrientation::RIGHT == eAlign )
651 		(((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_align ) += '=') += OOO_STRING_SVTOOLS_HTML_AL_right;
652     else if( text::HoriOrientation::CENTER == eAlign )
653 		(((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_align ) += '=') += OOO_STRING_SVTOOLS_HTML_AL_center;
654     else if( text::HoriOrientation::LEFT == eAlign )
655 		(((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_align ) += '=') += OOO_STRING_SVTOOLS_HTML_AL_left;
656 
657 	// WIDTH ausgeben: Stammt aus Layout oder ist berechnet
658 	if( nTabWidth )
659 	{
660 		((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_width ) += '=';
661 		if( HasRelWidths() )
662 			(sOut += ByteString::CreateFromInt32( nTabWidth )) += '%';
663 		else if( Application::GetDefaultDevice() )
664 		{
665 			long nPixWidth = Application::GetDefaultDevice()->LogicToPixel(
666 						Size(nTabWidth,0), MapMode(MAP_TWIP) ).Width();
667 			if( !nPixWidth )
668 				nPixWidth = 1;
669 
670 			sOut += ByteString::CreateFromInt32( nPixWidth );
671 		}
672 		else
673 		{
674 			ASSERT( Application::GetDefaultDevice(), "kein Application-Window!?" );
675 			sOut += "100%";
676 		}
677 	}
678 
679 	if( (nHSpace || nVSpace) && Application::GetDefaultDevice())
680 	{
681 		Size aPixelSpc =
682 			Application::GetDefaultDevice()->LogicToPixel( Size(nHSpace,nVSpace),
683 												   MapMode(MAP_TWIP) );
684 		if( !aPixelSpc.Width() && nHSpace )
685 			aPixelSpc.Width() = 1;
686 		if( !aPixelSpc.Height() && nVSpace )
687 			aPixelSpc.Height() = 1;
688 
689 		if( aPixelSpc.Width() )
690 		{
691 			(((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_hspace) += '=')
692 				+= ByteString::CreateFromInt32( aPixelSpc.Width() );
693 		}
694 
695 		if( aPixelSpc.Height() )
696 		{
697 			(((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_vspace) += '=')
698 				+= ByteString::CreateFromInt32( aPixelSpc.Height() );
699 		}
700 	}
701 
702 	// BORDER ausgeben, aber nur wenn wir die Umrandung selbst berechnet
703 	// haben oder die Umrandung 0 ist oder es irgendwelche Umrandungen gibt.
704 	// Anderenfalls enthaelt nBorder naemlich nur die Breite der Umrandung,
705     // die genutzt wird, wenn gar kein sheet::Border angegeben ist.
706 	sal_Bool bHasAnyBorders = nFrameMask || bColsHaveBorder || bRowsHaveBorder;
707 	if( bCollectBorderWidth || nBorder==0 || bHasAnyBorders )
708 		(((sOut += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_border ) += '=')
709 			+= ByteString::CreateFromInt32( rWrt.ToPixel( nBorder ) );
710 
711 	// BORDERCOLOR ausgeben
712 
713 	if( (sal_uInt32)-1 != nBorderColor && rWrt.bCfgOutStyles && bHasAnyBorders )
714 	{
715 		((sOut += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_bordercolor ) += '=';
716 		rWrt.Strm() << sOut.GetBuffer();
717 		HTMLOutFuncs::Out_Color( rWrt.Strm(), nBorderColor, rWrt.eDestEnc );
718 		sOut.Erase();
719 	}
720 
721 	// CELLPADDING ausgeben: Stammt aus Layout oder ist berechnet
722 	(((sOut += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_cellpadding ) += '=')
723 		+= ByteString::CreateFromInt32( rWrt.ToPixel( nCellPadding ) );
724 
725 	// CELLSPACING ausgeben: Stammt aus Layout oder ist berechnet
726 	(((sOut += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_cellspacing ) += '=')
727 		+= ByteString::CreateFromInt32( rWrt.ToPixel( nCellSpacing ) );
728 
729 	// FRAME/RULES ausgeben (nur sinnvoll, wenn border!=0)
730 	if( nBorder!=0 && (bCollectBorderWidth || bHasAnyBorders) )
731 	{
732 		const sal_Char *pFrame = 0;
733 		switch( nFrameMask )
734 		{
735 			case 0:  pFrame = OOO_STRING_SVTOOLS_HTML_TF_void		;break;
736 			case 1:  pFrame = OOO_STRING_SVTOOLS_HTML_TF_above	;break;
737 			case 2:  pFrame = OOO_STRING_SVTOOLS_HTML_TF_below	;break;
738 			case 3:  pFrame = OOO_STRING_SVTOOLS_HTML_TF_hsides	;break;
739 			case 4:  pFrame = OOO_STRING_SVTOOLS_HTML_TF_lhs		;break;
740 			case 8:  pFrame = OOO_STRING_SVTOOLS_HTML_TF_rhs		;break;
741 			case 12: pFrame = OOO_STRING_SVTOOLS_HTML_TF_vsides	;break;
742 			//FRAME=BOX ist der default wenn BORDER>0
743 			//case 15:
744 			//default: pFrame = OOO_STRING_SVTOOLS_HTML_TF_box		;break; // geht nicht
745 		};
746 		if( pFrame )
747 			(((sOut += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_frame ) += '=') += pFrame;
748 
749 		const sal_Char *pRules = 0;
750 		if( aCols.Count() > 1 && aRows.Count() > 1 )
751 		{
752 			if( !bColsHaveBorder )
753 			{
754 				if( !bRowsHaveBorder )
755 					pRules = OOO_STRING_SVTOOLS_HTML_TR_none;
756 				else if( bRowsHaveBorderOnly )
757 					pRules = OOO_STRING_SVTOOLS_HTML_TR_rows;
758 				else
759 					pRules = OOO_STRING_SVTOOLS_HTML_TR_groups;
760 			}
761 			else if( bColsHaveBorderOnly )
762 			{
763 				if( !bRowsHaveBorder || !bRowsHaveBorderOnly )
764 					pRules = OOO_STRING_SVTOOLS_HTML_TR_cols;
765 			}
766 			else
767 			{
768 				if( !bRowsHaveBorder )
769 					pRules = OOO_STRING_SVTOOLS_HTML_TR_groups;
770 				else if( bRowsHaveBorderOnly )
771 					pRules = OOO_STRING_SVTOOLS_HTML_TR_rows;
772 				else
773 					pRules = OOO_STRING_SVTOOLS_HTML_TR_groups;
774 			}
775 		}
776 		else if( aRows.Count() > 1 )
777 		{
778 			if( !bRowsHaveBorder )
779 				pRules = OOO_STRING_SVTOOLS_HTML_TR_none;
780 			else if( !bRowsHaveBorderOnly )
781 				pRules = OOO_STRING_SVTOOLS_HTML_TR_groups;
782 		}
783 		else if( aCols.Count() > 1 )
784 		{
785 			if( !bColsHaveBorder )
786 				pRules = OOO_STRING_SVTOOLS_HTML_TR_none;
787 			else if( !bColsHaveBorderOnly )
788 				pRules = OOO_STRING_SVTOOLS_HTML_TR_groups;
789 		}
790 
791 		if( pRules )
792 			(((sOut += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_rules ) += '=') += pRules;
793 	}
794 	rWrt.Strm() << sOut.GetBuffer();
795 
796 	// Hintergrund ausgeben
797 	if( pFrmFmt )
798 	{
799 		String aDummy;
800 		rWrt.OutBackground( pFrmFmt->GetAttrSet(), aDummy, sal_False );
801 
802 		if( rWrt.bCfgOutStyles && pFrmFmt )
803 			rWrt.OutCSS1_TableFrmFmtOptions( *pFrmFmt );
804 	}
805 
806 	sOut = '>';
807 	rWrt.Strm() << sOut.GetBuffer();
808 
809 	rWrt.IncIndentLevel(); // Inhalte von Table einruecken
810 
811 	// Ueberschrift ausgeben
812 	if( pCaption && pCaption->Len() )
813 	{
814 		rWrt.OutNewLine(); // <CAPTION> in neue Zeile
815 		ByteString sOutStr( OOO_STRING_SVTOOLS_HTML_caption );
816 		(((sOutStr += ' ') += OOO_STRING_SVTOOLS_HTML_O_align) += '=')
817 			+= (bTopCaption ? OOO_STRING_SVTOOLS_HTML_VA_top : OOO_STRING_SVTOOLS_HTML_VA_bottom);
818 		HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), sOutStr.GetBuffer(), sal_True );
819 		HTMLOutFuncs::Out_String( rWrt.Strm(), *pCaption, rWrt.eDestEnc, &rWrt.aNonConvertableCharacters	);
820 		HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_caption, sal_False );
821 	}
822 
823 	sal_uInt16 nCols = aCols.Count();
824 
825 	// <COLGRP>/<COL> ausgeben: Bei Export ueber Layout nur wenn beim
826 	// Import welche da waren, sonst immer.
827 	sal_Bool bColGroups = (bColsHaveBorder && !bColsHaveBorderOnly);
828 	if( bColTags )
829 	{
830 		if( bColGroups )
831 		{
832 			rWrt.OutNewLine(); // <COLGRP> in neue Zeile
833 			HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_colgroup, sal_True );
834 
835 			rWrt.IncIndentLevel(); // Inhalt von <COLGRP> einruecken
836 		}
837 
838 		for( nCol=0; nCol<nCols; nCol++ )
839 		{
840 			rWrt.OutNewLine(); // <COL> in neue Zeile
841 
842 			const SwWriteTableCol *pColumn = aCols[nCol];
843 
844 			ByteString sOutStr( '<' );
845 			sOutStr += OOO_STRING_SVTOOLS_HTML_col;
846 
847             sal_uInt32 nWidth;
848 			sal_Bool bRel;
849 			if( bLayoutExport )
850 			{
851 				bRel = pColumn->HasRelWidthOpt();
852 				nWidth = pColumn->GetWidthOpt();
853 			}
854 			else
855 			{
856 				bRel = HasRelWidths();
857 				nWidth = bRel ? GetRelWidth(nCol,1) : GetAbsWidth(nCol,1);
858 			}
859 
860 			((sOutStr += ' ' ) += OOO_STRING_SVTOOLS_HTML_O_width ) += '=';
861 			if( bRel )
862 			{
863 				(sOutStr += ByteString::CreateFromInt32( nWidth ) ) += '*';
864 			}
865 			else
866 			{
867 				sOutStr += ByteString::CreateFromInt32( rWrt.ToPixel( nWidth ) );
868 			}
869 			sOutStr += '>';
870 			rWrt.Strm() << sOutStr.GetBuffer();
871 
872 			if( bColGroups && pColumn->bRightBorder && nCol<nCols-1 )
873 			{
874 				rWrt.DecIndentLevel(); // Inhalt von <COLGRP> einruecken
875 				rWrt.OutNewLine(); // </COLGRP> in neue Zeile
876 				HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_colgroup,
877 											sal_False );
878 				rWrt.OutNewLine(); // <COLGRP> in neue Zeile
879 				HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_colgroup,
880 											sal_True );
881 				rWrt.IncIndentLevel(); // Inhalt von <COLGRP> einruecken
882 			}
883 		}
884 		if( bColGroups )
885 		{
886 			rWrt.DecIndentLevel(); // Inhalt von <COLGRP> einruecken
887 
888 			rWrt.OutNewLine(); // </COLGRP> in neue Zeile
889 			HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_colgroup,
890 										sal_False );
891 		}
892 	}
893 
894 	// die Lines als Tabellenzeilen rausschreiben
895 
896 	// <TBODY> ausgeben?
897 	sal_Bool bTSections = (bRowsHaveBorder && !bRowsHaveBorderOnly);
898 	sal_Bool bTBody = bTSections;
899 
900 	// Wenn Sections ausgegeben werden muessen darf ein THEAD um die erste
901 	// Zeile nur ausgegeben werden, wenn unter der Zeile eine Linie ist
902 	if( bTHead &&
903 		(bTSections || bColGroups) &&
904 		nHeadEndRow<aRows.Count()-1 && !aRows[nHeadEndRow]->bBottomBorder )
905 		bTHead = sal_False;
906 
907 	// <TBODY> aus ausgeben, wenn <THEAD> ausgegeben wird.
908 	bTSections |= bTHead;
909 
910 	if( bTSections )
911 	{
912 		rWrt.OutNewLine(); // <THEAD>/<TDATA> in neue Zeile
913 		HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(),
914 							bTHead ? OOO_STRING_SVTOOLS_HTML_thead : OOO_STRING_SVTOOLS_HTML_tbody, sal_True );
915 
916 		rWrt.IncIndentLevel(); // Inhalt von <THEAD>/<TDATA> einr.
917 	}
918 
919 	for( nRow = 0; nRow < aRows.Count(); nRow++ )
920 	{
921 		const SwWriteTableRow *pRow2 = aRows[nRow];
922 
923 		OutTableCells( rWrt, pRow2->GetCells(), pRow2->GetBackground() );
924 		if( !nCellSpacing && nRow < aRows.Count()-1 && pRow2->bBottomBorder &&
925 			pRow2->nBottomBorder > DEF_LINE_WIDTH_1 )
926 		{
927 			sal_uInt16 nCnt = (pRow2->nBottomBorder / DEF_LINE_WIDTH_1) - 1;
928 			for( ; nCnt; nCnt-- )
929 			{
930 				rWrt.OutNewLine();
931 				HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_tablerow,
932 											sal_True );
933 				HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_tablerow,
934 											sal_False );
935 			}
936 		}
937 		if( ( (bTHead && nRow==nHeadEndRow) ||
938 			  (bTBody && pRow2->bBottomBorder) ) &&
939 			nRow < aRows.Count()-1 )
940 		{
941 			rWrt.DecIndentLevel(); // Inhalt von <THEAD>/<TDATA> einr.
942 			rWrt.OutNewLine(); // </THEAD>/</TDATA> in neue Zeile
943 			HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(),
944 							bTHead ? OOO_STRING_SVTOOLS_HTML_thead : OOO_STRING_SVTOOLS_HTML_tbody, sal_False );
945 			rWrt.OutNewLine(); // <THEAD>/<TDATA> in neue Zeile
946 
947 			if( bTHead && nRow==nHeadEndRow )
948 				bTHead = sal_False;
949 
950 			HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(),
951 							bTHead ? OOO_STRING_SVTOOLS_HTML_thead : OOO_STRING_SVTOOLS_HTML_tbody, sal_True );
952 			rWrt.IncIndentLevel(); // Inhalt von <THEAD>/<TDATA> einr.
953 		}
954 	}
955 
956 	if( bTSections )
957 	{
958 		rWrt.DecIndentLevel(); // Inhalt von <THEAD>/<TDATA> einr.
959 
960 		rWrt.OutNewLine(); // </THEAD>/</TDATA> in neue Zeile
961 		HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(),
962 							bTHead ? OOO_STRING_SVTOOLS_HTML_thead : OOO_STRING_SVTOOLS_HTML_tbody, sal_False );
963 	}
964 
965 	rWrt.DecIndentLevel(); // Inhalt von <TABLE> einr.
966 
967 	rWrt.OutNewLine(); // </TABLE> in neue Zeile
968 	HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_table, sal_False );
969 
970 	rWrt.nDirection = nOldDirection;
971 }
972 
OutHTML_SwTblNode(Writer & rWrt,SwTableNode & rNode,const SwFrmFmt * pFlyFrmFmt,const String * pCaption,sal_Bool bTopCaption)973 Writer& OutHTML_SwTblNode( Writer& rWrt, SwTableNode & rNode,
974 						   const SwFrmFmt *pFlyFrmFmt,
975 						   const String *pCaption, sal_Bool bTopCaption )
976 {
977 
978 	SwTable& rTbl = rNode.GetTable();
979 
980 	SwHTMLWriter & rHTMLWrt = (SwHTMLWriter&)rWrt;
981 	rHTMLWrt.bOutTable = sal_True;
982 
983 	// die horizontale Ausrichtung des Rahmens hat (falls vorhanden)
984 	// Prioritaet. NONE bedeutet, dass keine horizontale
985 	// Ausrichtung geschrieben wird.
986     sal_Int16 eFlyHoriOri = text::HoriOrientation::NONE;
987 	SwSurround eSurround = SURROUND_NONE;
988 	sal_uInt8 nFlyPrcWidth = 0;
989 	long nFlyWidth = 0;
990 	sal_uInt16 nFlyHSpace = 0;
991 	sal_uInt16 nFlyVSpace = 0;
992 	if( pFlyFrmFmt )
993 	{
994 		eSurround = pFlyFrmFmt->GetSurround().GetSurround();
995 		const SwFmtFrmSize& rFrmSize = pFlyFrmFmt->GetFrmSize();
996 		nFlyPrcWidth = rFrmSize.GetWidthPercent();
997 		nFlyWidth = rFrmSize.GetSize().Width();
998 
999 		eFlyHoriOri = pFlyFrmFmt->GetHoriOrient().GetHoriOrient();
1000         if( text::HoriOrientation::NONE == eFlyHoriOri )
1001             eFlyHoriOri = text::HoriOrientation::LEFT;
1002 
1003 		const SvxLRSpaceItem& rLRSpace = pFlyFrmFmt->GetLRSpace();
1004         nFlyHSpace = static_cast< sal_uInt16 >((rLRSpace.GetLeft() + rLRSpace.GetRight()) / 2);
1005 
1006 		const SvxULSpaceItem& rULSpace = pFlyFrmFmt->GetULSpace();
1007 		nFlyVSpace = (rULSpace.GetUpper() + rULSpace.GetLower()) / 2;
1008 	}
1009 
1010 	// ggf. eine FORM oeffnen
1011 	sal_Bool bPreserveForm = sal_False;
1012 	if( !rHTMLWrt.bPreserveForm )
1013 	{
1014 		rHTMLWrt.OutForm( sal_True, &rNode );
1015 		bPreserveForm = (rHTMLWrt.pxFormComps && rHTMLWrt.pxFormComps->is() );
1016 		rHTMLWrt.bPreserveForm = bPreserveForm;
1017 	}
1018 
1019 	SwFrmFmt *pFmt = rTbl.GetFrmFmt();
1020 
1021 	const SwFmtFrmSize& rFrmSize = pFmt->GetFrmSize();
1022 	long nWidth = rFrmSize.GetSize().Width();
1023 	sal_uInt8 nPrcWidth = rFrmSize.GetWidthPercent();
1024 	sal_uInt16 nBaseWidth = (sal_uInt16)nWidth;
1025 
1026     sal_Int16 eTabHoriOri = pFmt->GetHoriOrient().GetHoriOrient();
1027 
1028     // text::HoriOrientation::NONE und text::HoriOrientation::FULL Tabellen benoetigen relative Breiten
1029 	sal_uInt16 nNewDefListLvl = 0;
1030 	sal_Bool bRelWidths = sal_False;
1031 	sal_Bool bCheckDefList = sal_False;
1032 	switch( eTabHoriOri )
1033 	{
1034     case text::HoriOrientation::FULL:
1035 		// Tabellen mit automatischer Ausrichtung werden zu Tabellen
1036 		// mit 100%-Breite
1037 		bRelWidths = sal_True;
1038 		nWidth = 100;
1039         eTabHoriOri = text::HoriOrientation::LEFT;
1040 		break;
1041     case text::HoriOrientation::NONE:
1042 		{
1043 			const SvxLRSpaceItem& aLRItem = pFmt->GetLRSpace();
1044 			if( aLRItem.GetRight() )
1045 			{
1046 				// Die Tabellenbreite wird anhand des linken und rechten
1047 				// Abstandes bestimmt. Deshalb versuchen wir die
1048 				// tatsaechliche Breite der Tabelle zu bestimmen. Wenn
1049 				// das nicht geht, machen wir eine 100% breite Tabelle
1050 				// draus.
1051 				nWidth = pFmt->FindLayoutRect(sal_True).Width();
1052 				if( !nWidth )
1053 				{
1054 					bRelWidths = sal_True;
1055 					nWidth = 100;
1056 				}
1057 
1058 			}
1059 			else if( nPrcWidth  )
1060 			{
1061 				// Ohne rechten Rand bleibt die %-Breite erhalten
1062 				nWidth = nPrcWidth;
1063 				bRelWidths = sal_True;
1064 			}
1065 			else
1066 			{
1067 				// Ohne rechten Rand bleibt auch eine absolute Breite erhalten
1068 				// Wir versuchen aber trotzdem ueber das Layout die
1069 				// tatsachliche Breite zu ermitteln.
1070 				long nRealWidth = pFmt->FindLayoutRect(sal_True).Width();
1071 				if( nRealWidth )
1072 					nWidth = nRealWidth;
1073 			}
1074 			bCheckDefList = sal_True;
1075 		}
1076 		break;
1077     case text::HoriOrientation::LEFT_AND_WIDTH:
1078         eTabHoriOri = text::HoriOrientation::LEFT;
1079 		bCheckDefList = sal_True;
1080 		// no break
1081 	default:
1082 		// In allen anderen Faellen kann eine absolute oder relative
1083 		// Breite direkt uebernommen werden.
1084 		if( nPrcWidth )
1085 		{
1086 			bRelWidths = sal_True;
1087 			nWidth = nPrcWidth;
1088 		}
1089 		break;
1090 	}
1091 
1092 	if( bCheckDefList )
1093 	{
1094 		ASSERT( !rHTMLWrt.GetNumInfo().GetNumRule() ||
1095 				rHTMLWrt.GetNextNumInfo(),
1096 				"NumInfo fuer naechsten Absatz fehlt!" );
1097 		const SvxLRSpaceItem& aLRItem = pFmt->GetLRSpace();
1098 		if( aLRItem.GetLeft() > 0 && rHTMLWrt.nDefListMargin > 0 &&
1099 			( !rHTMLWrt.GetNumInfo().GetNumRule() ||
1100 			  ( rHTMLWrt.GetNextNumInfo() &&
1101 				(rHTMLWrt.GetNextNumInfo()->IsRestart() ||
1102 				 rHTMLWrt.GetNumInfo().GetNumRule() !=
1103 					rHTMLWrt.GetNextNumInfo()->GetNumRule()) ) ) )
1104 		{
1105 			// Wenn der Absatz vor der Tabelle nicht numeriert ist oder
1106 			// der Absatz nach der Tabelle mit einer anderen oder
1107 			// (gar keiner) Regel numeriert ist, koennen wir
1108 			// die Einrueckung ueber eine DL regeln. Sonst behalten wir
1109 			// die Einrueckung der Numerierung bei.
1110             nNewDefListLvl = static_cast< sal_uInt16 >(
1111 				(aLRItem.GetLeft() + (rHTMLWrt.nDefListMargin/2)) /
1112                 rHTMLWrt.nDefListMargin );
1113 		}
1114 	}
1115 
1116 	if( !pFlyFrmFmt && nNewDefListLvl != rHTMLWrt.nDefListLvl )
1117 		rHTMLWrt.OutAndSetDefList( nNewDefListLvl );
1118 
1119 	if( nNewDefListLvl )
1120 	{
1121 		if( rHTMLWrt.bLFPossible )
1122 			rHTMLWrt.OutNewLine();
1123 		HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_dd );
1124 	}
1125 
1126 	// eFlyHoriOri und eTabHoriOri besitzen nun nur noch die Werte
1127 	// LEFT/CENTER und RIGHT!
1128     if( eFlyHoriOri!=text::HoriOrientation::NONE )
1129 	{
1130 		eTabHoriOri = eFlyHoriOri;
1131 		// MIB 4.7.97: Wenn die Tabelle eine relative Breite besitzt,
1132 		// dann richtet sich ihre Breite nach der des Rahmens, also
1133 		// exportieren wir dessen Breite. Bei fixer Breite ist die Breite
1134 		// der Tabelle massgeblich. Wer Tabellen mit relativer Breite <100%
1135 		// in Rahmen steckt, ist selber schuld wenn nix Gutes bei rauskommt.
1136 		if( bRelWidths )
1137 		{
1138 			nWidth = nFlyPrcWidth ? nFlyPrcWidth : nFlyWidth;
1139 			bRelWidths = nFlyPrcWidth > 0;
1140 		}
1141 	}
1142 
1143     sal_Int16 eDivHoriOri = text::HoriOrientation::NONE;
1144 	switch( eTabHoriOri )
1145 	{
1146     case text::HoriOrientation::LEFT:
1147 		// Wenn eine linksbuendigeTabelle keinen rechtsseiigen Durchlauf
1148 		// hat, brauchen wir auch kein ALIGN=LEFT in der Tabelle.
1149 		if( eSurround==SURROUND_NONE || eSurround==SURROUND_LEFT )
1150             eTabHoriOri = text::HoriOrientation::NONE;
1151 		break;
1152     case text::HoriOrientation::RIGHT:
1153 		// Aehnliches gilt fuer rechtsbuendigeTabelle, hier nehmen wir
1154 		// stattdessen ein <DIV ALIGN=RIGHT>.
1155 		if( eSurround==SURROUND_NONE || eSurround==SURROUND_RIGHT )
1156 		{
1157             eDivHoriOri = text::HoriOrientation::RIGHT;
1158             eTabHoriOri = text::HoriOrientation::NONE;
1159 		}
1160 		break;
1161     case text::HoriOrientation::CENTER:
1162 		// ALIGN=CENTER versteht so gut wie keiner, deshalb verzichten wir
1163 		// daruf und nehmen ein <CENTER>.
1164         eDivHoriOri = text::HoriOrientation::CENTER;
1165         eTabHoriOri = text::HoriOrientation::NONE;
1166 		break;
1167 	default:
1168 		;
1169 	}
1170     if( text::HoriOrientation::NONE==eTabHoriOri )
1171 		nFlyHSpace = nFlyVSpace = 0;
1172 
1173 	if( pFmt->GetName().Len() )
1174 		rHTMLWrt.OutImplicitMark( pFmt->GetName(), pMarkToTable );
1175 
1176     if( text::HoriOrientation::NONE!=eDivHoriOri )
1177 	{
1178 		if( rHTMLWrt.bLFPossible )
1179 			rHTMLWrt.OutNewLine();	// <CENTER> in neuer Zeile
1180         if( text::HoriOrientation::CENTER==eDivHoriOri )
1181 			HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_center, sal_True );
1182 		else
1183 		{
1184 			ByteString sOut( OOO_STRING_SVTOOLS_HTML_division );
1185 			(((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_align) += '=') += OOO_STRING_SVTOOLS_HTML_AL_right;
1186 			HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), sOut.GetBuffer(),
1187 										sal_True );
1188 		}
1189 		rHTMLWrt.IncIndentLevel();	// Inhalt von <CENTER> einruecken
1190 		rHTMLWrt.bLFPossible = sal_True;
1191 	}
1192 
1193 	// Wenn die Tabelle in keinem Rahmen ist kann man immer ein LF ausgeben.
1194     if( text::HoriOrientation::NONE==eTabHoriOri )
1195 		rHTMLWrt.bLFPossible = sal_True;
1196 
1197 	const SwHTMLTableLayout *pLayout = rTbl.GetHTMLTableLayout();
1198 
1199 #ifdef DBG_UTIL
1200 	ViewShell *pSh;
1201 	rWrt.pDoc->GetEditShell( &pSh );
1202 	if ( pSh && pSh->GetViewOptions()->IsTest1() )
1203 		pLayout = 0;
1204 #endif
1205 
1206 	if( pLayout && pLayout->IsExportable() )
1207 	{
1208 		SwHTMLWrtTable aTableWrt( pLayout );
1209         aTableWrt.Write( rHTMLWrt, eTabHoriOri, rTbl.GetRowsToRepeat() > 0,
1210 						 pFmt, pCaption, bTopCaption,
1211 						 nFlyHSpace, nFlyVSpace );
1212 	}
1213 	else
1214 	{
1215 		SwHTMLWrtTable aTableWrt( rTbl.GetTabLines(), nWidth,
1216                                   nBaseWidth, bRelWidths, rTbl.GetRowsToRepeat() );
1217         aTableWrt.Write( rHTMLWrt, eTabHoriOri, rTbl.GetRowsToRepeat() > 0,
1218 						 pFmt, pCaption, bTopCaption,
1219 						 nFlyHSpace, nFlyVSpace );
1220 	}
1221 
1222 	// Wenn die Tabelle in keinem Rahmen war kann man immer ein LF ausgeben.
1223     if( text::HoriOrientation::NONE==eTabHoriOri )
1224 		rHTMLWrt.bLFPossible = sal_True;
1225 
1226     if( text::HoriOrientation::NONE!=eDivHoriOri )
1227 	{
1228 		rHTMLWrt.DecIndentLevel();	// Inhalt von <CENTER> einruecken
1229 		rHTMLWrt.OutNewLine();		// </CENTER> in neue Teile
1230 		HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(),
1231                                text::HoriOrientation::CENTER==eDivHoriOri ? OOO_STRING_SVTOOLS_HTML_center
1232 														: OOO_STRING_SVTOOLS_HTML_division, sal_False );
1233 		rHTMLWrt.bLFPossible = sal_True;
1234 	}
1235 
1236 	// Pam hinter die Tabelle verschieben
1237 	rHTMLWrt.pCurPam->GetPoint()->nNode = *rNode.EndOfSectionNode();
1238 
1239 	if( bPreserveForm )
1240 	{
1241 		rHTMLWrt.bPreserveForm = sal_False;
1242 		rHTMLWrt.OutForm( sal_False );
1243 	}
1244 
1245 	rHTMLWrt.bOutTable = sal_False;
1246 
1247 	if( rHTMLWrt.GetNextNumInfo() &&
1248 		!rHTMLWrt.GetNextNumInfo()->IsRestart() &&
1249 		rHTMLWrt.GetNextNumInfo()->GetNumRule() ==
1250 			rHTMLWrt.GetNumInfo().GetNumRule() )
1251 	{
1252 		// Wenn der Absatz hinter der Tabelle mit der gleichen Regel
1253 		// numeriert ist wie der Absatz vor der Tabelle, dann steht in
1254 		// der NumInfo des naechsten Absatzes noch die Ebene des Absatzes
1255 		// vor der Tabelle. Es muss deshalb die NumInfo noch einmal geholt
1256 		// werden um ggf. die Num-Liste noch zu beenden.
1257 		rHTMLWrt.ClearNextNumInfo();
1258 		rHTMLWrt.FillNextNumInfo();
1259 		OutHTML_NumBulListEnd( rHTMLWrt, *rHTMLWrt.GetNextNumInfo() );
1260 	}
1261 	return rWrt;
1262 }
1263 
1264 
1265