xref: /trunk/main/sw/source/filter/html/htmltab.cxx (revision 6cd1b732)
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 //#define TEST_RESIZE
27 
28 
29 #include "hintids.hxx"
30 #include <vcl/svapp.hxx>
31 #ifndef _WRKWIN_HXX //autogen
32 #include <vcl/wrkwin.hxx>
33 #endif
34 #include <editeng/boxitem.hxx>
35 #include <editeng/brshitem.hxx>
36 #include <editeng/adjitem.hxx>
37 #include <editeng/fhgtitem.hxx>
38 #include <editeng/ulspitem.hxx>
39 #include <editeng/lrspitem.hxx>
40 #include <editeng/brkitem.hxx>
41 #include <editeng/spltitem.hxx>
42 #include <svtools/htmltokn.h>
43 #include <svtools/htmlkywd.hxx>
44 #include <svl/urihelper.hxx>
45 
46 
47 #include <fmtornt.hxx>
48 #include <frmfmt.hxx>
49 #include <fmtfsize.hxx>
50 #include <fmtsrnd.hxx>
51 #include <fmtpdsc.hxx>
52 #include <fmtcntnt.hxx>
53 #include <fmtanchr.hxx>
54 #include <fmtlsplt.hxx>
55 #include "frmatr.hxx"
56 #include "pam.hxx"
57 #include "doc.hxx"
58 #include "ndtxt.hxx"
59 #include "shellio.hxx"
60 #include "poolfmt.hxx"
61 #include "swtable.hxx"
62 #include "cellatr.hxx"
63 #ifdef TEST_RESIZE
64 #include "viewsh.hxx"
65 #endif
66 #include "htmltbl.hxx"
67 #include "swtblfmt.hxx"
68 #include "htmlnum.hxx"
69 #include "swhtml.hxx"
70 #include "swcss1.hxx"
71 #include <numrule.hxx>
72 
73 #define NETSCAPE_DFLT_BORDER 1
74 #define NETSCAPE_DFLT_CELLPADDING 1
75 #define NETSCAPE_DFLT_CELLSPACING 2
76 
77 //#define FIX56334
78 
79 using namespace ::com::sun::star;
80 
81 
82 static HTMLOptionEnum __FAR_DATA aHTMLTblVAlignTable[] =
83 {
84 	{ OOO_STRING_SVTOOLS_HTML_VA_top,         text::VertOrientation::NONE       },
85 	{ OOO_STRING_SVTOOLS_HTML_VA_middle,      text::VertOrientation::CENTER     },
86 	{ OOO_STRING_SVTOOLS_HTML_VA_bottom,      text::VertOrientation::BOTTOM     },
87 	{ 0,					0				}
88 };
89 
90 
91 
92 // Die Optionen eines Table-Tags
93 
94 struct HTMLTableOptions
95 {
96 	sal_uInt16 nCols;
97 	sal_uInt16 nWidth;
98 	sal_uInt16 nHeight;
99 	sal_uInt16 nCellPadding;
100 	sal_uInt16 nCellSpacing;
101 	sal_uInt16 nBorder;
102 	sal_uInt16 nHSpace;
103 	sal_uInt16 nVSpace;
104 
105 	SvxAdjust eAdjust;
106 	sal_Int16 eVertOri;
107 	HTMLTableFrame eFrame;
108 	HTMLTableRules eRules;
109 
110 	sal_Bool bPrcWidth : 1;
111 	sal_Bool bTableAdjust : 1;
112 	sal_Bool bBGColor : 1;
113 
114 	Color aBorderColor;
115 	Color aBGColor;
116 
117 	String aBGImage, aStyle, aId, aClass, aDir;
118 
119 	HTMLTableOptions( const HTMLOptions *pOptions, SvxAdjust eParentAdjust );
120 };
121 
122 
123 class _HTMLTableContext
124 {
125 	SwHTMLNumRuleInfo aNumRuleInfo;	// Vor der Tabelle gueltige Numerierung
126 
127 	SwTableNode *pTblNd;			// der Tabellen-Node
128 	SwFrmFmt *pFrmFmt;				// der Fly frame::Frame, in dem die Tabelle steht
129 	SwPosition *pPos;				// die Position hinter der Tabelle
130 
131 	sal_uInt16 nContextStAttrMin;
132 	sal_uInt16 nContextStMin;
133 
134 	sal_Bool	bRestartPRE : 1;
135 	sal_Bool	bRestartXMP : 1;
136 	sal_Bool	bRestartListing : 1;
137 
138 public:
139 
140 	_HTMLAttrTable aAttrTab;		// und die Attribute
141 
_HTMLTableContext(SwPosition * pPs,sal_uInt16 nCntxtStMin,sal_uInt16 nCntxtStAttrMin)142 	_HTMLTableContext( SwPosition *pPs, sal_uInt16 nCntxtStMin,
143 					   sal_uInt16 nCntxtStAttrMin ) :
144 		pTblNd( 0 ),
145 		pFrmFmt( 0 ),
146 		pPos( pPs ),
147 		nContextStAttrMin( nCntxtStAttrMin ),
148 		nContextStMin( nCntxtStMin ),
149 		bRestartPRE( sal_False ),
150 		bRestartXMP( sal_False ),
151 		bRestartListing( sal_False )
152 	{
153 		memset( &aAttrTab, 0, sizeof( _HTMLAttrTable ));
154 	}
155 
156 	~_HTMLTableContext();
157 
SetNumInfo(const SwHTMLNumRuleInfo & rInf)158 	void SetNumInfo( const SwHTMLNumRuleInfo& rInf ) { aNumRuleInfo.Set(rInf); }
GetNumInfo() const159 	const SwHTMLNumRuleInfo& GetNumInfo() const { return aNumRuleInfo; };
160 
161 	void SavePREListingXMP( SwHTMLParser& rParser );
162 	void RestorePREListingXMP( SwHTMLParser& rParser );
163 
GetPos() const164 	SwPosition *GetPos() const { return pPos; }
165 
SetTableNode(SwTableNode * pNd)166 	void SetTableNode( SwTableNode *pNd ) { pTblNd = pNd; }
GetTableNode() const167 	SwTableNode *GetTableNode() const { return pTblNd; }
168 
SetFrmFmt(SwFrmFmt * pFmt)169 	void SetFrmFmt( SwFrmFmt *pFmt ) { pFrmFmt = pFmt; }
GetFrmFmt() const170 	SwFrmFmt *GetFrmFmt() const { return pFrmFmt; }
171 
GetContextStMin() const172 	sal_uInt16 GetContextStMin() const { return nContextStMin; }
GetContextStAttrMin() const173 	sal_uInt16 GetContextStAttrMin() const { return nContextStAttrMin; }
174 };
175 
176 
177 // der Inhalt einer Zelle ist eine verkettete Liste mit SwStartNodes und
178 // HTMLTables.
179 
180 class HTMLTableCnts
181 {
182 	HTMLTableCnts *pNext;				// der naechste Inhalt
183 
184 	// von den beiden naechsten Pointern darf nur einer gesetzt sein!
185 	const SwStartNode *pStartNode;		// ein Absatz
186 	HTMLTable *pTable;					// eine Tabelle
187 
188 	SwHTMLTableLayoutCnts* pLayoutInfo;
189 
190 	sal_Bool bNoBreak;
191 
192 	void InitCtor();
193 
194 public:
195 
196 	HTMLTableCnts( const SwStartNode* pStNd );
197 	HTMLTableCnts( HTMLTable* pTab );
198 
199 	~HTMLTableCnts();					// nur in ~HTMLTableCell erlaubt
200 
201 	// Ermitteln des SwStartNode bzw. der HTMLTable
GetStartNode() const202 	const SwStartNode *GetStartNode() const { return pStartNode; }
GetTable() const203 	const HTMLTable *GetTable() const { return pTable; }
GetTable()204 	HTMLTable *GetTable() { return pTable; }
205 
206 	// hinzufuegen eines neuen Knotens am Listenende
207 	void Add( HTMLTableCnts* pNewCnts );
208 
209 	// Ermitteln des naechsten Knotens
Next() const210 	const HTMLTableCnts *Next() const { return pNext; }
Next()211 	HTMLTableCnts *Next() { return pNext; }
212 
213 	inline void SetTableBox( SwTableBox *pBox );
214 
SetNoBreak()215 	void SetNoBreak() { bNoBreak = sal_True; }
216 
217 	SwHTMLTableLayoutCnts *CreateLayoutInfo();
218 };
219 
220 
221 // Eine Zelle der HTML-Tabelle
222 
223 class HTMLTableCell
224 {
225 	// !!!ACHTUNG!!!!! Fuer jeden neuen Pointer muss die SetProtected-
226 	// Methode (und natuerlich der Destruktor) bearbeitet werden.
227 	HTMLTableCnts *pContents;  		// der Inhalt der Zelle
228 	SvxBrushItem *pBGBrush;	   		// Hintergrund der Zelle
229 	// !!!ACHTUNG!!!!!
230 
231 	sal_uInt32 nNumFmt;
232 	sal_uInt16 nRowSpan;				// ROWSPAN der Zelle
233 	sal_uInt16 nColSpan;	  			// COLSPAN der Zelle
234 	sal_uInt16 nWidth;					// WIDTH der Zelle
235 	double nValue;
236 	sal_Int16 eVertOri;         // vertikale Ausrichtung der Zelle
237 	sal_Bool bProtected : 1;			// Zelle darf nicht belegt werden
238 	sal_Bool bRelWidth : 1;				// nWidth ist %-Angabe
239 	sal_Bool bHasNumFmt : 1;
240 	sal_Bool bHasValue : 1;
241 	sal_Bool bNoWrap : 1;
242 	sal_Bool mbCovered : 1;
243 
244 public:
245 
246 	HTMLTableCell();				// neue Zellen sind immer leer
247 
248 	~HTMLTableCell();				// nur in ~HTMLTableRow erlaubt
249 
250 	// Belegen einer nicht-leeren Zelle
251 	void Set( HTMLTableCnts *pCnts, sal_uInt16 nRSpan, sal_uInt16 nCSpan,
252               sal_Int16 eVertOri, SvxBrushItem *pBGBrush,
253 			  sal_Bool bHasNumFmt, sal_uInt32 nNumFmt,
254               sal_Bool bHasValue, double nValue, sal_Bool bNoWrap, sal_Bool bCovered );
255 
256 	// Schuetzen einer leeren 1x1-Zelle
257 	void SetProtected();
258 
259 	// Setzen/Ermitteln des Inhalts einer Zelle
SetContents(HTMLTableCnts * pCnts)260 	void SetContents( HTMLTableCnts *pCnts ) { pContents = pCnts; }
GetContents() const261 	const HTMLTableCnts *GetContents() const { return pContents; }
GetContents()262 	HTMLTableCnts *GetContents() { return pContents; }
263 
264 	// ROWSPAN/COLSPAN der Zelle Setzen/Ermitteln
SetRowSpan(sal_uInt16 nRSpan)265 	void SetRowSpan( sal_uInt16 nRSpan ) { nRowSpan = nRSpan; }
GetRowSpan() const266 	sal_uInt16 GetRowSpan() const { return nRowSpan; }
267 
SetColSpan(sal_uInt16 nCSpan)268 	void SetColSpan( sal_uInt16 nCSpan ) { nColSpan = nCSpan; }
GetColSpan() const269 	sal_uInt16 GetColSpan() const { return nColSpan; }
270 
271 	inline void SetWidth( sal_uInt16 nWidth, sal_Bool bRelWidth );
272 
GetBGBrush() const273 	const SvxBrushItem *GetBGBrush() const { return pBGBrush; }
274 
275 	inline sal_Bool GetNumFmt( sal_uInt32& rNumFmt ) const;
276 	inline sal_Bool GetValue( double& rValue ) const;
277 
GetVertOri() const278 	sal_Int16 GetVertOri() const { return eVertOri; }
279 
280 	// Ist die Zelle belegt oder geschuetzt?
IsUsed() const281 	sal_Bool IsUsed() const { return pContents!=0 || bProtected; }
282 
283 	SwHTMLTableLayoutCell *CreateLayoutInfo();
284 
IsCovered() const285 	sal_Bool IsCovered() const { return mbCovered; }
286 };
287 
288 
289 // Eine Zeile der HTML-Tabelle
290 
291 typedef HTMLTableCell* HTMLTableCellPtr;
292 SV_DECL_PTRARR_DEL(HTMLTableCells,HTMLTableCellPtr,5,5)
293 
294 class HTMLTableRow
295 {
296 	HTMLTableCells *pCells;				// die Zellen der Zeile
297 
298 	sal_Bool bIsEndOfGroup : 1;
299 	sal_Bool bSplitable : 1;
300 
301 	sal_uInt16 nHeight;						// Optionen von <TR>/<TD>
302 	sal_uInt16 nEmptyRows;					// wieviele Leere Zeilen folgen
303 
304 	SvxAdjust eAdjust;
305 	sal_Int16 eVertOri;
306 	SvxBrushItem *pBGBrush;	   			// Hintergrund der Zelle aus STYLE
307 
308 public:
309 
310 	sal_Bool bBottomBorder;					// kommt hinter der Zeile eine Linie?
311 
312 	HTMLTableRow( sal_uInt16 nCells=0 );	// die Zellen der Zeile sind leer
313 
314 	~HTMLTableRow();
315 
316 	inline void SetHeight( sal_uInt16 nHeight );
GetHeight() const317 	sal_uInt16 GetHeight() const { return nHeight; }
318 
319 	// Ermitteln einer Zelle
320 	inline HTMLTableCell *GetCell( sal_uInt16 nCell ) const;
GetCells() const321 	inline const HTMLTableCells *GetCells() const { return pCells; }
322 
323 
SetAdjust(SvxAdjust eAdj)324 	inline void SetAdjust( SvxAdjust eAdj ) { eAdjust = eAdj; }
GetAdjust() const325 	inline SvxAdjust GetAdjust() const { return eAdjust; }
326 
SetVertOri(sal_Int16 eV)327 	inline void SetVertOri( sal_Int16 eV) { eVertOri = eV; }
GetVertOri() const328 	inline sal_Int16 GetVertOri() const { return eVertOri; }
329 
SetBGBrush(SvxBrushItem * pBrush)330 	void SetBGBrush( SvxBrushItem *pBrush ) { pBGBrush = pBrush; }
GetBGBrush() const331 	const SvxBrushItem *GetBGBrush() const { return pBGBrush; }
332 
SetEndOfGroup()333 	inline void SetEndOfGroup() { bIsEndOfGroup = sal_True; }
IsEndOfGroup() const334 	inline sal_Bool IsEndOfGroup() const { return bIsEndOfGroup; }
335 
IncEmptyRows()336 	void IncEmptyRows() { nEmptyRows++; }
GetEmptyRows() const337 	sal_uInt16 GetEmptyRows() const { return nEmptyRows; }
338 
339 	// Expandieren einer Zeile durch hinzufuegen leerer Zellen
340 	void Expand( sal_uInt16 nCells, sal_Bool bOneCell=sal_False );
341 
342 	// Verkuerzen einer Zeile durch loesen von leeren Zellen
343 	void Shrink( sal_uInt16 nCells );
344 
SetSplitable(sal_Bool bSet)345 	void SetSplitable( sal_Bool bSet ) { bSplitable = bSet; }
IsSplitable() const346 	sal_Bool IsSplitable() const { return bSplitable; }
347 };
348 
349 
350 // Eine Spalte der HTML-Tabelle
351 
352 class HTMLTableColumn
353 {
354 	sal_Bool bIsEndOfGroup;
355 
356 	sal_uInt16 nWidth;						// Optionen von <COL>
357 	sal_Bool bRelWidth;
358 
359 	SvxAdjust eAdjust;
360 	sal_Int16 eVertOri;
361 
362 	SwFrmFmt *aFrmFmts[6];
363 
364 	inline sal_uInt16 GetFrmFmtIdx( sal_Bool bBorderLine,
365                                 sal_Int16 eVertOri ) const;
366 
367 public:
368 
369 	sal_Bool bLeftBorder; 					// kommt vor der Spalte eine Linie
370 
371 	HTMLTableColumn();
372 
373 	inline void SetWidth( sal_uInt16 nWidth, sal_Bool bRelWidth);
374 
SetAdjust(SvxAdjust eAdj)375 	inline void SetAdjust( SvxAdjust eAdj ) { eAdjust = eAdj; }
GetAdjust() const376 	inline SvxAdjust GetAdjust() const { return eAdjust; }
377 
SetVertOri(sal_Int16 eV)378     inline void SetVertOri( sal_Int16 eV) { eVertOri = eV; }
GetVertOri() const379     inline sal_Int16 GetVertOri() const { return eVertOri; }
380 
SetEndOfGroup()381 	inline void SetEndOfGroup() { bIsEndOfGroup = sal_True; }
IsEndOfGroup() const382 	inline sal_Bool IsEndOfGroup() const { return bIsEndOfGroup; }
383 
384 	inline void SetFrmFmt( SwFrmFmt *pFmt, sal_Bool bBorderLine,
385                            sal_Int16 eVertOri );
386 	inline SwFrmFmt *GetFrmFmt( sal_Bool bBorderLine,
387                                 sal_Int16 eVertOri ) const;
388 
389 	SwHTMLTableLayoutColumn *CreateLayoutInfo();
390 };
391 
392 
393 // eine HTML-Tabelle
394 
395 typedef HTMLTableRow* HTMLTableRowPtr;
396 SV_DECL_PTRARR_DEL(HTMLTableRows,HTMLTableRowPtr,5,5)
397 
398 typedef HTMLTableColumn* HTMLTableColumnPtr;
399 SV_DECL_PTRARR_DEL(HTMLTableColumns,HTMLTableColumnPtr,5,5)
400 
401 SV_DECL_PTRARR(SdrObjects,SdrObject *,1,1)
402 
403 class HTMLTable
404 {
405 	String aId;
406 	String aStyle;
407 	String aClass;
408 	String aDir;
409 
410 	SdrObjects *pResizeDrawObjs;// SDR-Objekte
411 	SvUShorts *pDrawObjPrcWidths;	// Spalte des Zeichen-Objekts und dessen
412 									// relative Breite
413 
414 	HTMLTableRows *pRows;			// die Zeilen der Tabelle
415 	HTMLTableColumns *pColumns;     // die Spalten der Tabelle
416 
417 	sal_uInt16 nRows;					// Anzahl Zeilen
418 	sal_uInt16 nCols;       			// Anzahl Spalten
419 	sal_uInt16 nFilledCols;				// Anzahl tatsaechlich gefuellter Spalten
420 
421 	sal_uInt16 nCurRow;					// aktuelle Zeile
422 	sal_uInt16 nCurCol;     			// aktuelle Spalte
423 
424 	sal_uInt16 nLeftMargin;				// Abstand zum linken Rand (aus Absatz)
425 	sal_uInt16 nRightMargin;		   	// Abstand zum rechten Rand (aus Absatz)
426 
427 	sal_uInt16 nCellPadding;			// Abstand Umrandung zum Text
428 	sal_uInt16 nCellSpacing;			// Abstand zwischen zwei Zellen
429 	sal_uInt16 nHSpace;
430 	sal_uInt16 nVSpace;
431 
432 	sal_uInt16 nBoxes;					// Wieviele Boxen enthaelt die Tabelle
433 
434 	const SwStartNode *pPrevStNd;	// der Table-Node oder der Start-Node
435 									// der vorhergehenden Section
436 	const SwTable *pSwTable;		// die SW-Tabelle (nur auf dem Top-Level)
437 	SwTableBox *pBox1;				// die TableBox, die beim Erstellen
438 									// der Top-Level-Tabelle angelegt wird
439 
440 	SwTableBoxFmt *pBoxFmt;         // das frame::Frame-Format einer SwTableBox
441 	SwTableLineFmt *pLineFmt;       // das frame::Frame-Format einer SwTableLine
442 	SwTableLineFmt *pLineFrmFmtNoHeight;
443 	SvxBrushItem *pBGBrush;	   		// Hintergrund der Tabelle
444 	SvxBrushItem *pInhBGBrush;	   	// "geerbter" Hintergrund der Tabelle
445 	const SwStartNode *pCaptionStartNode;	// Start-Node der Tabellen-Ueberschrift
446 
447 	SvxBorderLine aTopBorderLine;	// die Linie fuer die Umrandung
448 	SvxBorderLine aBottomBorderLine;// die Linie fuer die Umrandung
449 	SvxBorderLine aLeftBorderLine;	// die Linie fuer die Umrandung
450 	SvxBorderLine aRightBorderLine;	// die Linie fuer die Umrandung
451 	SvxBorderLine aBorderLine;		// die Linie fuer die Umrandung
452 	SvxBorderLine aInhLeftBorderLine;	// die Linie fuer die Umrandung
453 	SvxBorderLine aInhRightBorderLine;	// die Linie fuer die Umrandung
454 	sal_Bool bTopBorder;				// besitzt die Tabelle oben eine Linie
455 	sal_Bool bRightBorder;              // besitzt die Tabelle rechts eine Linie
456 	sal_Bool bTopAlwd; 					// duerfen die Raender gesetzt werden?
457 	sal_Bool bRightAlwd;
458 	sal_Bool bFillerTopBorder;			// bekommt eine linke/rechter Filler-
459 	sal_Bool bFillerBottomBorder;		// Zelle eine obere/untere Umrandung?
460 	sal_Bool bInhLeftBorder;
461 	sal_Bool bInhRightBorder;
462 	sal_Bool bBordersSet;				// die Umrandung wurde bereits gesetzt
463 	sal_Bool bForceFrame;
464 	sal_Bool bTableAdjustOfTag;			// stammt nTableAdjust aus <TABLE>?
465 	sal_uInt32 nHeadlineRepeat;			// repeating rows
466 	sal_Bool bIsParentHead;
467 	sal_Bool bHasParentSection;
468 	sal_Bool bMakeTopSubTable;
469 	sal_Bool bHasToFly;
470 	sal_Bool bFixedCols;
471 	sal_Bool bColSpec;					// Gab es COL(GROUP)-Elemente?
472 	sal_Bool bPrcWidth;					// Breite ist eine %-Angabe
473 
474 	SwHTMLParser *pParser;			// der aktuelle Parser
475 	HTMLTable *pTopTable;			// die Tabelle auf dem Top-Level
476 	HTMLTableCnts *pParentContents;
477 
478 	_HTMLTableContext *pContext;	// der Kontext der Tabelle
479 
480 	SwHTMLTableLayout *pLayoutInfo;
481 
482 
483 	// die folgenden Parameter stammen aus der dem <TABLE>-Tag
484 	sal_uInt16 nWidth;					// die Breite der Tabelle
485 	sal_uInt16 nHeight;					// absolute Hoehe der Tabelle
486 	SvxAdjust eTableAdjust;         // drawing::Alignment der Tabelle
487 	sal_Int16 eVertOri;         // Default vertikale Ausr. der Zellen
488 	sal_uInt16 nBorder;					// Breite der auesseren Umrandung
489 	HTMLTableFrame eFrame;			// Rahmen um die Tabelle
490 	HTMLTableRules eRules;			// Rahmen in der Tabelle
491 	sal_Bool bTopCaption;				// Ueberschrift ueber der Tabelle
492 
493 	void InitCtor( const HTMLTableOptions *pOptions );
494 
495 	// Korrigieren des Row-Spans fuer alle Zellen oberhalb der
496 	// angegeben Zelle und der Zelle selbst, fuer die den angegebenen
497 	// Inhalt besitzen. Die angegeben Zelle bekommt den Row-Span 1
498 	void FixRowSpan( sal_uInt16 nRow, sal_uInt16 nCol, const HTMLTableCnts *pCnts );
499 
500 	// Schuetzen der angegeben Zelle und den darunterliegenden
501 	void ProtectRowSpan( sal_uInt16 nRow, sal_uInt16 nCol, sal_uInt16 nRowSpan );
502 
503 	// Suchen des SwStartNodes der logisch vorhergehenden Box
504 	// bei nRow==nCell==USHRT_MAX wird der allerletzte Start-Node
505 	// der Tabelle zurueckgegeben
506 	const SwStartNode* GetPrevBoxStartNode( sal_uInt16 nRow, sal_uInt16 nCell ) const;
507 
508 	sal_uInt16 GetTopCellSpace( sal_uInt16 nRow, sal_uInt16 nRowSpan,
509 							sal_Bool bSwBorders=sal_True ) const;
510 	sal_uInt16 GetBottomCellSpace( sal_uInt16 nRow, sal_uInt16 nRowSpan,
511 							   sal_Bool bSwBorders=sal_True ) const;
512 
513 	// Anpassen des frame::Frame-Formates einer Box
514 	void FixFrameFmt( SwTableBox *pBox, sal_uInt16 nRow, sal_uInt16 nCol,
515 					  sal_uInt16 nRowSpan, sal_uInt16 nColSpan,
516 					  sal_Bool bFirstPara=sal_True, sal_Bool bLastPara=sal_True ) const;
517 	void FixFillerFrameFmt( SwTableBox *pBox, sal_Bool bRight ) const;
518 
519 	// den Inhalt (Lines/Boxen) eine Tabelle erstellen
520 	void _MakeTable( SwTableBox *pUpper=0 );
521 
522 	// Anlegen einer neuen SwTableBox, die einen SwStartNode enthaelt
523 	SwTableBox *NewTableBox( const SwStartNode *pStNd,
524 							 SwTableLine *pUpper ) const;
525 
526 	// Erstellen einer SwTableLine aus den Zellen des Rechtecks
527 	// (nTopRow/nLeftCol) inklusive bis (nBottomRow/nRightRow) exklusive
528 	SwTableLine *MakeTableLine( SwTableBox *pUpper,
529 								sal_uInt16 nTopRow, sal_uInt16 nLeftCol,
530 								sal_uInt16 nBottomRow, sal_uInt16 nRightCol );
531 
532 	// Erstellen einer SwTableBox aus dem Inhalt einer Zelle
533 	SwTableBox *MakeTableBox( SwTableLine *pUpper,
534 							  HTMLTableCnts *pCnts,
535 							  sal_uInt16 nTopRow, sal_uInt16 nLeftCol,
536 							  sal_uInt16 nBootomRow, sal_uInt16 nRightCol );
537 
538 	// der Autolayout-Algorithmus
539 
540 	// Setzen der Umrandung anhand der Vorgaben der Parent-Tabelle
541 	void InheritBorders( const HTMLTable *pParent,
542 						 sal_uInt16 nRow, sal_uInt16 nCol,
543 						 sal_uInt16 nRowSpan, sal_uInt16 nColSpan,
544 						 sal_Bool bFirstPara, sal_Bool bLastPara );
545 
546 	// Linke und rechte Umrandung der umgebenen Tabelle erben
547 	void InheritVertBorders( const HTMLTable *pParent,
548 							 sal_uInt16 nCol, sal_uInt16 nColSpan );
549 
550 
551 	// Setzen der Umrandung anhand der Benutzervorgaben
552 	void SetBorders();
553 
554 	// wurde die Umrandung der Tabelle schon gesetzt
BordersSet() const555 	sal_Bool BordersSet() const { return bBordersSet; }
556 
GetBGBrush() const557 	const SvxBrushItem *GetBGBrush() const { return pBGBrush; }
GetInhBGBrush() const558 	const SvxBrushItem *GetInhBGBrush() const { return pInhBGBrush; }
559 
560 	sal_uInt16 GetBorderWidth( const SvxBorderLine& rBLine,
561 						   sal_Bool bWithDistance=sal_False ) const;
562 
563 public:
564 
565 	sal_Bool bFirstCell;				// wurde schon eine Zelle angelegt?
566 
567 	HTMLTable( SwHTMLParser* pPars, HTMLTable *pTopTab,
568 			   sal_Bool bParHead, sal_Bool bHasParentSec,
569 			   sal_Bool bTopTbl, sal_Bool bHasToFly,
570 			   const HTMLTableOptions *pOptions );
571 
572 	~HTMLTable();
573 
574 	// Ermitteln einer Zelle
575 	inline HTMLTableCell *GetCell( sal_uInt16 nRow, sal_uInt16 nCell ) const;
576 
577 	// Ueberschrift setzen/ermitteln
578 	inline void SetCaption( const SwStartNode *pStNd, sal_Bool bTop );
GetCaptionStartNode() const579 	const SwStartNode *GetCaptionStartNode() const { return pCaptionStartNode; }
IsTopCaption() const580 	sal_Bool IsTopCaption() const { return bTopCaption; }
581 
GetTableAdjust(sal_Bool bAny) const582 	SvxAdjust GetTableAdjust( sal_Bool bAny ) const
583 	{
584 		return (bTableAdjustOfTag || bAny) ? eTableAdjust : SVX_ADJUST_END;
585 	}
GetVertOri() const586 	sal_Int16 GetVertOri() const { return eVertOri; }
587 
GetHSpace() const588 	sal_uInt16 GetHSpace() const { return nHSpace; }
GetVSpace() const589 	sal_uInt16 GetVSpace() const { return nVSpace; }
590 
HasPrcWidth() const591 	sal_Bool HasPrcWidth() const { return bPrcWidth; }
GetPrcWidth() const592 	sal_uInt8 GetPrcWidth() const { return bPrcWidth ? (sal_uInt8)nWidth : 0; }
593 
GetMinWidth() const594 	sal_uInt16 GetMinWidth() const
595 	{
596 		sal_uInt32 nMin = pLayoutInfo->GetMin();
597 		return nMin < USHRT_MAX ? (sal_uInt16)nMin : USHRT_MAX;
598 	}
599 
600 	// von Zeilen oder Spalten geerbtes drawing::Alignment holen
601 	SvxAdjust GetInheritedAdjust() const;
602 	sal_Int16 GetInheritedVertOri() const;
603 
604 	// Einfuegen einer Zelle an der aktuellen Position
605 	void InsertCell( HTMLTableCnts *pCnts, sal_uInt16 nRowSpan, sal_uInt16 nColSpan,
606 					 sal_uInt16 nWidth, sal_Bool bRelWidth, sal_uInt16 nHeight,
607                      sal_Int16 eVertOri, SvxBrushItem *pBGBrush,
608 					 sal_Bool bHasNumFmt, sal_uInt32 nNumFmt,
609                      sal_Bool bHasValue, double nValue, sal_Bool bNoWrap );
610 
611 	// Start/Ende einer neuen Zeile bekanntgeben
612 	void OpenRow( SvxAdjust eAdjust, sal_Int16 eVertOri,
613 				  SvxBrushItem *pBGBrush );
614 	void CloseRow( sal_Bool bEmpty );
615 
616 	// Ende einer neuen Section bekanntgeben
617 	inline void CloseSection( sal_Bool bHead );
618 
619 	// Ende einer Spalten-Gruppe bekanntgeben
620 	inline void CloseColGroup( sal_uInt16 nSpan, sal_uInt16 nWidth, sal_Bool bRelWidth,
621                                SvxAdjust eAdjust, sal_Int16 eVertOri );
622 
623 	// Einfuegen einer Spalte
624 	void InsertCol( sal_uInt16 nSpan, sal_uInt16 nWidth, sal_Bool bRelWidth,
625                     SvxAdjust eAdjust, sal_Int16 eVertOri );
626 
627 	// Beenden einer Tab-Definition (MUSS fuer ALLE Tabs aufgerufen werden)
628 	void CloseTable();
629 
630 	// SwTable konstruieren (inkl. der Child-Tabellen)
631 	void MakeTable( SwTableBox *pUpper, sal_uInt16 nAbsAvail,
632 					sal_uInt16 nRelAvail=0, sal_uInt16 nAbsLeftSpace=0,
633 					sal_uInt16 nAbsRightSpace=0, sal_uInt16 nInhAbsSpace=0 );
634 
IsNewDoc() const635 	inline sal_Bool IsNewDoc() const { return pParser->IsNewDoc(); }
636 
SetHasParentSection(sal_Bool bSet)637 	void SetHasParentSection( sal_Bool bSet ) { bHasParentSection = bSet; }
HasParentSection() const638 	sal_Bool HasParentSection() const { return bHasParentSection; }
639 
SetParentContents(HTMLTableCnts * pCnts)640 	void SetParentContents( HTMLTableCnts *pCnts ) { pParentContents = pCnts; }
GetParentContents() const641 	HTMLTableCnts *GetParentContents() const { return pParentContents; }
642 
643 	void MakeParentContents();
644 
GetIsParentHeader() const645 	sal_Bool GetIsParentHeader() const { return bIsParentHead; }
646 
IsMakeTopSubTable() const647 	sal_Bool IsMakeTopSubTable() const { return bMakeTopSubTable; }
SetHasToFly()648 	void SetHasToFly() { bHasToFly=sal_True; }
HasToFly() const649 	sal_Bool HasToFly() const { return bHasToFly; }
650 
651 	void SetTable( const SwStartNode *pStNd, _HTMLTableContext *pCntxt,
652 				   sal_uInt16 nLeft, sal_uInt16 nRight,
653 				   const SwTable *pSwTab=0, sal_Bool bFrcFrame=sal_False );
654 
GetContext() const655 	_HTMLTableContext *GetContext() const { return pContext; }
656 
657 	SwHTMLTableLayout *CreateLayoutInfo();
658 
HasColTags() const659 	sal_Bool HasColTags() const { return bColSpec; }
660 
IncGrfsThatResize()661 	sal_uInt16 IncGrfsThatResize() { return pSwTable ? ((SwTable *)pSwTable)->IncGrfsThatResize() : 0; }
662 
663 	void RegisterDrawObject( SdrObject *pObj, sal_uInt8 nPrcWidth );
664 
GetSwTable() const665 	const SwTable *GetSwTable() const { return pSwTable; }
666 
SetBGBrush(const SvxBrushItem & rBrush)667 	void SetBGBrush( const SvxBrushItem& rBrush ) { delete pBGBrush; pBGBrush = new SvxBrushItem( rBrush ); }
668 
GetId() const669 	const String& GetId() const { return aId; }
GetClass() const670 	const String& GetClass() const { return aClass; }
GetStyle() const671 	const String& GetStyle() const { return aStyle; }
GetDirection() const672 	const String& GetDirection() const { return aDir; }
673 
IncBoxCount()674 	void IncBoxCount() { nBoxes++; }
IsOverflowing() const675 	sal_Bool IsOverflowing() const { return nBoxes > 64000; }
676 };
677 
SV_IMPL_PTRARR(HTMLTableCells,HTMLTableCellPtr)678 SV_IMPL_PTRARR(HTMLTableCells,HTMLTableCellPtr)
679 SV_IMPL_PTRARR(HTMLTableRows,HTMLTableRowPtr)
680 SV_IMPL_PTRARR(HTMLTableColumns,HTMLTableColumnPtr)
681 
682 
683 
684 void HTMLTableCnts::InitCtor()
685 {
686 	pNext = 0;
687 	pLayoutInfo = 0;
688 
689 	bNoBreak = sal_False;
690 }
691 
HTMLTableCnts(const SwStartNode * pStNd)692 HTMLTableCnts::HTMLTableCnts( const SwStartNode* pStNd ):
693 	pStartNode(pStNd), pTable(0)
694 {
695 	InitCtor();
696 }
697 
HTMLTableCnts(HTMLTable * pTab)698 HTMLTableCnts::HTMLTableCnts( HTMLTable* pTab ):
699 	pStartNode(0), pTable(pTab)
700 {
701 	InitCtor();
702 }
703 
~HTMLTableCnts()704 HTMLTableCnts::~HTMLTableCnts()
705 {
706 	delete pTable;				// die Tabellen brauchen wir nicht mehr
707 	delete pNext;
708 }
709 
Add(HTMLTableCnts * pNewCnts)710 void HTMLTableCnts::Add( HTMLTableCnts* pNewCnts )
711 {
712 	HTMLTableCnts *pCnts = this;
713 
714 	while( pCnts->pNext )
715 		pCnts = pCnts->pNext;
716 
717 	pCnts->pNext = pNewCnts;
718 }
719 
SetTableBox(SwTableBox * pBox)720 inline void HTMLTableCnts::SetTableBox( SwTableBox *pBox )
721 {
722 	ASSERT( pLayoutInfo, "Da ist noch keine Layout-Info" );
723 	if( pLayoutInfo )
724 		pLayoutInfo->SetTableBox( pBox );
725 }
726 
CreateLayoutInfo()727 SwHTMLTableLayoutCnts *HTMLTableCnts::CreateLayoutInfo()
728 {
729 	if( !pLayoutInfo )
730 	{
731 		SwHTMLTableLayoutCnts *pNextInfo = pNext ? pNext->CreateLayoutInfo() : 0;
732 		SwHTMLTableLayout *pTableInfo = pTable ? pTable->CreateLayoutInfo() : 0;
733 
734 		pLayoutInfo = new SwHTMLTableLayoutCnts( pStartNode, pTableInfo,
735 												 bNoBreak, pNextInfo );
736 	}
737 
738 	return pLayoutInfo;
739 }
740 
741 
HTMLTableCell()742 HTMLTableCell::HTMLTableCell():
743 	pContents(0),
744 	pBGBrush(0),
745 	nNumFmt(0),
746 	nRowSpan(1),
747 	nColSpan(1),
748 	nWidth( 0 ),
749 	nValue(0),
750     eVertOri( text::VertOrientation::NONE ),
751 	bProtected(sal_False),
752 	bRelWidth( sal_False ),
753 	bHasNumFmt(sal_False),
754     bHasValue(sal_False),
755     mbCovered(sal_False)
756 {}
757 
~HTMLTableCell()758 HTMLTableCell::~HTMLTableCell()
759 {
760 	// der Inhalt ist in mehrere Zellen eingetragen, darf aber nur einmal
761 	// geloescht werden
762 	if( 1==nRowSpan && 1==nColSpan )
763 	{
764 		delete pContents;
765 		delete pBGBrush;
766 	}
767 }
768 
Set(HTMLTableCnts * pCnts,sal_uInt16 nRSpan,sal_uInt16 nCSpan,sal_Int16 eVert,SvxBrushItem * pBrush,sal_Bool bHasNF,sal_uInt32 nNF,sal_Bool bHasV,double nVal,sal_Bool bNWrap,sal_Bool bCovered)769 void HTMLTableCell::Set( HTMLTableCnts *pCnts, sal_uInt16 nRSpan, sal_uInt16 nCSpan,
770                          sal_Int16 eVert, SvxBrushItem *pBrush,
771 						 sal_Bool bHasNF, sal_uInt32 nNF, sal_Bool bHasV, double nVal,
772                          sal_Bool bNWrap, sal_Bool bCovered )
773 {
774 	pContents = pCnts;
775 	nRowSpan = nRSpan;
776 	nColSpan = nCSpan;
777 	bProtected = sal_False;
778 	eVertOri = eVert;
779 	pBGBrush = pBrush;
780 
781 	bHasNumFmt = bHasNF;
782 	bHasValue = bHasV;
783 	nNumFmt = nNF;
784 	nValue = nVal;
785 
786 	bNoWrap = bNWrap;
787     mbCovered = bCovered;
788 }
789 
SetWidth(sal_uInt16 nWdth,sal_Bool bRelWdth)790 inline void HTMLTableCell::SetWidth( sal_uInt16 nWdth, sal_Bool bRelWdth )
791 {
792 	nWidth = nWdth;
793 	bRelWidth = bRelWdth;
794 }
795 
SetProtected()796 void HTMLTableCell::SetProtected()
797 {
798 	// Die Inhalte dieser Zelle muessen nicht irgendwo anders verankert
799 	// sein, weil sie nicht geloescht werden!!!
800 
801 	// Inhalt loeschen
802 	pContents = 0;
803 
804 	// Hintergrundfarbe kopieren.
805 	if( pBGBrush )
806 		pBGBrush = new SvxBrushItem( *pBGBrush );
807 
808 	nRowSpan = 1;
809 	nColSpan = 1;
810 	bProtected = sal_True;
811 }
812 
GetNumFmt(sal_uInt32 & rNumFmt) const813 inline sal_Bool HTMLTableCell::GetNumFmt( sal_uInt32& rNumFmt ) const
814 {
815 	rNumFmt = nNumFmt;
816 	return bHasNumFmt;
817 }
818 
GetValue(double & rValue) const819 inline sal_Bool HTMLTableCell::GetValue( double& rValue ) const
820 {
821 	rValue = nValue;
822 	return bHasValue;
823 }
824 
CreateLayoutInfo()825 SwHTMLTableLayoutCell *HTMLTableCell::CreateLayoutInfo()
826 {
827 	SwHTMLTableLayoutCnts *pCntInfo = pContents ? pContents->CreateLayoutInfo() : 0;
828 
829 	return new SwHTMLTableLayoutCell( pCntInfo, nRowSpan, nColSpan, nWidth,
830 									  bRelWidth, bNoWrap );
831 }
832 
833 
HTMLTableRow(sal_uInt16 nCells)834 HTMLTableRow::HTMLTableRow( sal_uInt16 nCells ):
835 	pCells(new HTMLTableCells),
836 	bIsEndOfGroup(sal_False),
837 	bSplitable( sal_False ),
838 	nHeight(0),
839 	nEmptyRows(0),
840 	eAdjust(SVX_ADJUST_END),
841     eVertOri(text::VertOrientation::TOP),
842 	pBGBrush(0),
843 	bBottomBorder(sal_False)
844 {
845 	for( sal_uInt16 i=0; i<nCells; i++ )
846 	{
847 		pCells->Insert( new HTMLTableCell, pCells->Count() );
848 	}
849 
850 	ASSERT( nCells==pCells->Count(),
851 			"Zellenzahl in neuer HTML-Tabellenzeile stimmt nicht" );
852 }
853 
~HTMLTableRow()854 HTMLTableRow::~HTMLTableRow()
855 {
856 	delete pCells;
857 	delete pBGBrush;
858 }
859 
SetHeight(sal_uInt16 nHght)860 inline void HTMLTableRow::SetHeight( sal_uInt16 nHght )
861 {
862 	if( nHght > nHeight  )
863 		nHeight = nHght;
864 }
865 
GetCell(sal_uInt16 nCell) const866 inline HTMLTableCell *HTMLTableRow::GetCell( sal_uInt16 nCell ) const
867 {
868 	ASSERT( nCell<pCells->Count(),
869 		"ungueltiger Zellen-Index in HTML-Tabellenzeile" );
870 	return (*pCells)[nCell];
871 }
872 
Expand(sal_uInt16 nCells,sal_Bool bOneCell)873 void HTMLTableRow::Expand( sal_uInt16 nCells, sal_Bool bOneCell )
874 {
875 	// die Zeile wird mit einer einzigen Zelle aufgefuellt, wenn
876 	// bOneCell gesetzt ist. Das geht, nur fuer Zeilen, in die keine
877 	// Zellen mehr eingefuegt werden!
878 
879 	sal_uInt16 nColSpan = nCells-pCells->Count();
880 	for( sal_uInt16 i=pCells->Count(); i<nCells; i++ )
881 	{
882 		HTMLTableCell *pCell = new HTMLTableCell;
883 		if( bOneCell )
884 			pCell->SetColSpan( nColSpan );
885 
886 		pCells->Insert( pCell, pCells->Count() );
887 		nColSpan--;
888 	}
889 
890 	ASSERT( nCells==pCells->Count(),
891 			"Zellenzahl in expandierter HTML-Tabellenzeile stimmt nicht" );
892 }
893 
Shrink(sal_uInt16 nCells)894 void HTMLTableRow::Shrink( sal_uInt16 nCells )
895 {
896 	ASSERT( nCells < pCells->Count(), "Anzahl Zellen falsch" );
897 
898 #ifdef DBG_UTIL
899 	 sal_uInt16 nEnd = pCells->Count();
900 #endif
901 	// The colspan of empty cells at the end has to be fixed to the new
902 	// number of cells.
903 	sal_uInt16 i=nCells;
904 	while( i )
905 	{
906 		HTMLTableCell *pCell = (*pCells)[--i];
907 		if( !pCell->GetContents() )
908 		{
909 			ASSERT( pCell->GetColSpan() == nEnd - i,
910 					"invalid col span for empty cell at row end" );
911 			pCell->SetColSpan( nCells-i);
912 		}
913 		else
914 			break;
915 	}
916 #ifdef DBG_UTIL
917 	for( i=nCells; i<nEnd; i++ )
918 	{
919 		HTMLTableCell *pCell = (*pCells)[i];
920 		ASSERT( pCell->GetRowSpan() == 1,
921 				"RowSpan von zu loesender Zelle ist falsch" );
922 		ASSERT( pCell->GetColSpan() == nEnd - i,
923 					"ColSpan von zu loesender Zelle ist falsch" );
924 		ASSERT( !pCell->GetContents(), "Zu loeschende Zelle hat Inhalt" );
925 	}
926 #endif
927 
928 	pCells->DeleteAndDestroy( nCells, pCells->Count()-nCells );
929 }
930 
931 
HTMLTableColumn()932 HTMLTableColumn::HTMLTableColumn():
933 	bIsEndOfGroup(sal_False),
934 	nWidth(0), bRelWidth(sal_False),
935     eAdjust(SVX_ADJUST_END), eVertOri(text::VertOrientation::TOP),
936 	bLeftBorder(sal_False)
937 {
938 	for( sal_uInt16 i=0; i<6; i++ )
939 		aFrmFmts[i] = 0;
940 }
941 
SetWidth(sal_uInt16 nWdth,sal_Bool bRelWdth)942 inline void HTMLTableColumn::SetWidth( sal_uInt16 nWdth, sal_Bool bRelWdth )
943 {
944 	if( bRelWidth==bRelWdth )
945 	{
946 		if( nWdth > nWidth )
947 			nWidth = nWdth;
948 	}
949 	else
950 		nWidth = nWdth;
951 	bRelWidth = bRelWdth;
952 }
953 
CreateLayoutInfo()954 inline SwHTMLTableLayoutColumn *HTMLTableColumn::CreateLayoutInfo()
955 {
956 	return new SwHTMLTableLayoutColumn( nWidth, bRelWidth, bLeftBorder );
957 }
958 
GetFrmFmtIdx(sal_Bool bBorderLine,sal_Int16 eVertOrient) const959 inline sal_uInt16 HTMLTableColumn::GetFrmFmtIdx( sal_Bool bBorderLine,
960                                              sal_Int16 eVertOrient ) const
961 {
962     ASSERT( text::VertOrientation::TOP != eVertOrient, "TOP is not allowed!" );
963 	sal_uInt16 n = bBorderLine ? 3 : 0;
964 	switch( eVertOrient )
965 	{
966     case text::VertOrientation::CENTER:   n+=1;   break;
967     case text::VertOrientation::BOTTOM:   n+=2;   break;
968 	default:
969 		;
970 	}
971 	return n;
972 }
973 
SetFrmFmt(SwFrmFmt * pFmt,sal_Bool bBorderLine,sal_Int16 eVertOrient)974 inline void HTMLTableColumn::SetFrmFmt( SwFrmFmt *pFmt, sal_Bool bBorderLine,
975                                         sal_Int16 eVertOrient )
976 {
977 	aFrmFmts[GetFrmFmtIdx(bBorderLine,eVertOrient)] = pFmt;
978 }
979 
GetFrmFmt(sal_Bool bBorderLine,sal_Int16 eVertOrient) const980 inline SwFrmFmt *HTMLTableColumn::GetFrmFmt( sal_Bool bBorderLine,
981                                              sal_Int16 eVertOrient ) const
982 {
983 	return aFrmFmts[GetFrmFmtIdx(bBorderLine,eVertOrient)];
984 }
985 
986 
987 
InitCtor(const HTMLTableOptions * pOptions)988 void HTMLTable::InitCtor( const HTMLTableOptions *pOptions )
989 {
990 	pResizeDrawObjs = 0;
991 	pDrawObjPrcWidths = 0;
992 
993 	pRows = new HTMLTableRows;
994 	pColumns = new HTMLTableColumns;
995 	nRows = 0;
996 	nCurRow = 0; nCurCol = 0;
997 
998 	pBox1 = 0;
999 	pBoxFmt = 0; pLineFmt = 0;
1000 	pLineFrmFmtNoHeight = 0;
1001 	pInhBGBrush = 0;
1002 
1003 	pPrevStNd = 0;
1004 	pSwTable = 0;
1005 
1006 	bTopBorder = sal_False; bRightBorder = sal_False;
1007 	bTopAlwd = sal_True; bRightAlwd = sal_True;
1008 	bFillerTopBorder = sal_False; bFillerBottomBorder = sal_False;
1009 	bInhLeftBorder = sal_False; bInhRightBorder = sal_False;
1010 	bBordersSet = sal_False;
1011 	bForceFrame = sal_False;
1012 	nHeadlineRepeat = 0;
1013 
1014 	nLeftMargin = 0;
1015 	nRightMargin = 0;
1016 
1017 	const Color& rBorderColor = pOptions->aBorderColor;
1018 
1019 	long nBorderOpt = (long)pOptions->nBorder;
1020 	long nPWidth = nBorderOpt==USHRT_MAX ? NETSCAPE_DFLT_BORDER
1021 										 : nBorderOpt;
1022 	long nPHeight = nBorderOpt==USHRT_MAX ? 0 : nBorderOpt;
1023 	SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight );
1024 
1025 	// nBorder gibt die Breite der Umrandung an, wie sie in die
1026 	// Breitenberechnung in Netscape einfliesst. Wenn pOption->nBorder
1027 	// == USHRT_MAX, wurde keine BORDER-Option angegeben. Trotzdem fliesst
1028 	// eine 1 Pixel breite Umrandung in die Breitenberechnung mit ein.
1029 	nBorder = (sal_uInt16)nPWidth;
1030 	if( nBorderOpt==USHRT_MAX )
1031 		nPWidth = 0;
1032 
1033 	// HACK: ein Pixel-breite Linien sollen zur Haarlinie werden, wenn
1034 	// wir mit doppelter Umrandung arbeiten
1035 	if( pOptions->nCellSpacing!=0 && nBorderOpt==1 )
1036 	{
1037 		nPWidth = 1;
1038 		nPHeight = 1;
1039 	}
1040 
1041 	SvxCSS1Parser::SetBorderWidth( aTopBorderLine, (sal_uInt16)nPHeight,
1042 								   pOptions->nCellSpacing!=0, sal_True );
1043 	aTopBorderLine.SetColor( rBorderColor );
1044 	aBottomBorderLine = aTopBorderLine;
1045 
1046 	if( nPWidth == nPHeight )
1047 	{
1048 		aLeftBorderLine = aTopBorderLine;
1049 	}
1050 	else
1051 	{
1052 		SvxCSS1Parser::SetBorderWidth( aLeftBorderLine, (sal_uInt16)nPWidth,
1053 									   pOptions->nCellSpacing!=0, sal_True );
1054 		aLeftBorderLine.SetColor( rBorderColor );
1055 	}
1056 	aRightBorderLine = aLeftBorderLine;
1057 
1058 	if( pOptions->nCellSpacing != 0 )
1059 	{
1060 		aBorderLine.SetOutWidth( DEF_DOUBLE_LINE7_OUT );
1061 		aBorderLine.SetInWidth( DEF_DOUBLE_LINE7_IN );
1062 		aBorderLine.SetDistance( DEF_DOUBLE_LINE7_DIST );
1063 	}
1064 	else
1065 	{
1066 		aBorderLine.SetOutWidth( DEF_LINE_WIDTH_1 );
1067 	}
1068 	aBorderLine.SetColor( rBorderColor );
1069 
1070 	if( nCellPadding )
1071 	{
1072 		if( nCellPadding==USHRT_MAX )
1073 			nCellPadding = MIN_BORDER_DIST;	// default
1074 		else
1075 		{
1076 			nCellPadding = pParser->ToTwips( nCellPadding );
1077 			if( nCellPadding<MIN_BORDER_DIST  )
1078 				nCellPadding = MIN_BORDER_DIST;
1079 		}
1080 	}
1081 	if( nCellSpacing )
1082 	{
1083 		if( nCellSpacing==USHRT_MAX )
1084 			nCellSpacing = NETSCAPE_DFLT_CELLSPACING;
1085 		nCellSpacing = pParser->ToTwips( nCellSpacing );
1086 	}
1087 
1088 	nPWidth = pOptions->nHSpace;
1089 	nPHeight = pOptions->nVSpace;
1090 	SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight );
1091 	nHSpace = (sal_uInt16)nPWidth;
1092 	nVSpace = (sal_uInt16)nPHeight;
1093 
1094 	bColSpec = sal_False;
1095 
1096 	pBGBrush = pParser->CreateBrushItem(
1097 					pOptions->bBGColor ? &(pOptions->aBGColor) : 0,
1098 					pOptions->aBGImage, aEmptyStr, aEmptyStr, aEmptyStr );
1099 
1100 	pContext = 0;
1101 	pParentContents = 0;
1102 
1103 	aId = pOptions->aId;
1104 	aClass = pOptions->aClass;
1105 	aStyle = pOptions->aStyle;
1106 	aDir = pOptions->aDir;
1107 }
1108 
HTMLTable(SwHTMLParser * pPars,HTMLTable * pTopTab,sal_Bool bParHead,sal_Bool bHasParentSec,sal_Bool bTopTbl,sal_Bool bHasToFlw,const HTMLTableOptions * pOptions)1109 HTMLTable::HTMLTable( SwHTMLParser* pPars, HTMLTable *pTopTab,
1110 					  sal_Bool bParHead,
1111 					  sal_Bool bHasParentSec, sal_Bool bTopTbl, sal_Bool bHasToFlw,
1112 					  const HTMLTableOptions *pOptions ) :
1113 	nCols( pOptions->nCols ),
1114 	nFilledCols( 0 ),
1115 	nCellPadding( pOptions->nCellPadding ),
1116 	nCellSpacing( pOptions->nCellSpacing ),
1117 	nBoxes( 1 ),
1118 	pCaptionStartNode( 0 ),
1119 	bTableAdjustOfTag( pTopTab ? sal_False : pOptions->bTableAdjust ),
1120 	bIsParentHead( bParHead ),
1121 	bHasParentSection( bHasParentSec ),
1122 	bMakeTopSubTable( bTopTbl ),
1123 	bHasToFly( bHasToFlw ),
1124 	bFixedCols( pOptions->nCols>0 ),
1125 	bPrcWidth( pOptions->bPrcWidth ),
1126 	pParser( pPars ),
1127 	pTopTable( pTopTab ? pTopTab : this ),
1128 	pLayoutInfo( 0 ),
1129 	nWidth( pOptions->nWidth ),
1130 	nHeight( pTopTab ? 0 : pOptions->nHeight ),
1131 	eTableAdjust( pOptions->eAdjust ),
1132 	eVertOri( pOptions->eVertOri ),
1133 	eFrame( pOptions->eFrame ),
1134 	eRules( pOptions->eRules ),
1135 	bTopCaption( sal_False ),
1136 	bFirstCell( !pTopTab )
1137 {
1138 	InitCtor( pOptions );
1139 
1140 	for( sal_uInt16 i=0; i<nCols; i++ )
1141 		pColumns->Insert( new HTMLTableColumn, pColumns->Count() );
1142 }
1143 
1144 
~HTMLTable()1145 HTMLTable::~HTMLTable()
1146 {
1147 	delete pResizeDrawObjs;
1148 	delete pDrawObjPrcWidths;
1149 
1150 	delete pRows;
1151 	delete pColumns;
1152 	delete pBGBrush;
1153 	delete pInhBGBrush;
1154 
1155 	delete pContext;
1156 
1157 	// pLayoutInfo wurde entweder bereits geloescht oder muss aber es
1158 	// in den Besitz der SwTable uebergegangen.
1159 }
1160 
CreateLayoutInfo()1161 SwHTMLTableLayout *HTMLTable::CreateLayoutInfo()
1162 {
1163 	sal_uInt16 nW = bPrcWidth ? nWidth : pParser->ToTwips( nWidth );
1164 
1165 	sal_uInt16 nBorderWidth = GetBorderWidth( aBorderLine, sal_True );
1166 	sal_uInt16 nLeftBorderWidth =
1167 		((*pColumns)[0])->bLeftBorder ? GetBorderWidth( aLeftBorderLine, sal_True ) : 0;
1168 	sal_uInt16 nRightBorderWidth =
1169 		bRightBorder ? GetBorderWidth( aRightBorderLine, sal_True ) : 0;
1170 	sal_uInt16 nInhLeftBorderWidth = 0;
1171 	sal_uInt16 nInhRightBorderWidth = 0;
1172 
1173 	pLayoutInfo = new SwHTMLTableLayout(
1174 						pSwTable,
1175 						nRows, nCols, bFixedCols, bColSpec,
1176 						nW, bPrcWidth, nBorder, nCellPadding,
1177 						nCellSpacing, eTableAdjust,
1178 						nLeftMargin, nRightMargin,
1179 						nBorderWidth, nLeftBorderWidth, nRightBorderWidth,
1180 						nInhLeftBorderWidth, nInhRightBorderWidth );
1181 
1182 	sal_Bool bExportable = sal_True;
1183 	sal_uInt16 i;
1184 	for( i=0; i<nRows; i++ )
1185 	{
1186 		HTMLTableRow *pRow = (*pRows)[i];
1187 		for( sal_uInt16 j=0; j<nCols; j++ )
1188 		{
1189 			SwHTMLTableLayoutCell *pLayoutCell =
1190 				pRow->GetCell(j)->CreateLayoutInfo();
1191 
1192 			pLayoutInfo->SetCell( pLayoutCell, i, j );
1193 
1194 			if( bExportable )
1195 			{
1196 				SwHTMLTableLayoutCnts *pLayoutCnts =
1197 					pLayoutCell->GetContents();
1198 				bExportable = !pLayoutCnts ||
1199 							  ( pLayoutCnts->GetStartNode() &&
1200 								!pLayoutCnts->GetNext() );
1201 			}
1202 		}
1203 	}
1204 
1205 	pLayoutInfo->SetExportable( bExportable );
1206 
1207 	for( i=0; i<nCols; i++ )
1208 		pLayoutInfo->SetColumn( ((*pColumns)[i])->CreateLayoutInfo(), i );
1209 
1210 	return pLayoutInfo;
1211 }
1212 
SetCaption(const SwStartNode * pStNd,sal_Bool bTop)1213 inline void HTMLTable::SetCaption( const SwStartNode *pStNd, sal_Bool bTop )
1214 {
1215 	pCaptionStartNode = pStNd;
1216 	bTopCaption = bTop;
1217 }
1218 
FixRowSpan(sal_uInt16 nRow,sal_uInt16 nCol,const HTMLTableCnts * pCnts)1219 void HTMLTable::FixRowSpan( sal_uInt16 nRow, sal_uInt16 nCol,
1220 							const HTMLTableCnts *pCnts )
1221 {
1222 	sal_uInt16 nRowSpan=1;
1223 	HTMLTableCell *pCell;
1224 	while( ( pCell=GetCell(nRow,nCol), pCell->GetContents()==pCnts ) )
1225 	{
1226 		pCell->SetRowSpan( nRowSpan );
1227 		if( pLayoutInfo )
1228 			pLayoutInfo->GetCell(nRow,nCol)->SetRowSpan( nRowSpan );
1229 
1230 		if( !nRow ) break;
1231 		nRowSpan++; nRow--;
1232 	}
1233 }
1234 
ProtectRowSpan(sal_uInt16 nRow,sal_uInt16 nCol,sal_uInt16 nRowSpan)1235 void HTMLTable::ProtectRowSpan( sal_uInt16 nRow, sal_uInt16 nCol, sal_uInt16 nRowSpan )
1236 {
1237 	for( sal_uInt16 i=0; i<nRowSpan; i++ )
1238 	{
1239 		GetCell(nRow+i,nCol)->SetProtected();
1240 		if( pLayoutInfo )
1241 			pLayoutInfo->GetCell(nRow+i,nCol)->SetProtected();
1242 	}
1243 }
1244 
1245 
1246 // Suchen des SwStartNodes der letzten belegten Vorgaengerbox
GetPrevBoxStartNode(sal_uInt16 nRow,sal_uInt16 nCol) const1247 const SwStartNode* HTMLTable::GetPrevBoxStartNode( sal_uInt16 nRow, sal_uInt16 nCol ) const
1248 {
1249 	const HTMLTableCnts *pPrevCnts = 0;
1250 
1251 	if( 0==nRow )
1252 	{
1253 		// immer die Vorgaenger-Zelle
1254 		if( nCol>0 )
1255 			pPrevCnts = GetCell( 0, nCol-1 )->GetContents();
1256 		else
1257 			return pPrevStNd;
1258 	}
1259 	else if( USHRT_MAX==nRow && USHRT_MAX==nCol )
1260 		// der Contents der letzten Zelle
1261 		pPrevCnts = GetCell( nRows-1, nCols-1 )->GetContents();
1262 	else
1263 	{
1264 		sal_uInt16 i;
1265 		HTMLTableRow *pPrevRow = (*pRows)[nRow-1];
1266 
1267 		// evtl. eine Zelle in der aktuellen Zeile
1268 		i = nCol;
1269 		while( i )
1270 		{
1271 			i--;
1272 			if( 1 == pPrevRow->GetCell(i)->GetRowSpan() )
1273 			{
1274 				pPrevCnts = GetCell(nRow,i)->GetContents();
1275 				break;
1276 			}
1277 		}
1278 
1279 		// sonst die letzte gefuellte Zelle der Zeile davor suchen
1280 		if( !pPrevCnts )
1281 		{
1282 			i = nCols;
1283 			while( !pPrevCnts && i )
1284 			{
1285 				i--;
1286 				pPrevCnts = pPrevRow->GetCell(i)->GetContents();
1287 			}
1288 		}
1289 	}
1290 	ASSERT( pPrevCnts, "keine gefuellte Vorgaenger-Zelle gefunden" );
1291 	if( !pPrevCnts )
1292 	{
1293 		pPrevCnts = GetCell(0,0)->GetContents();
1294 		if( !pPrevCnts )
1295 			return pPrevStNd;
1296 	}
1297 
1298 	while( pPrevCnts->Next() )
1299 		pPrevCnts = pPrevCnts->Next();
1300 
1301 	return ( pPrevCnts->GetStartNode() ? pPrevCnts->GetStartNode()
1302 			   : pPrevCnts->GetTable()->GetPrevBoxStartNode( USHRT_MAX, USHRT_MAX ) );
1303 }
1304 
1305 
IsBoxEmpty(const SwTableBox * pBox)1306 static sal_Bool IsBoxEmpty( const SwTableBox *pBox )
1307 {
1308 	const SwStartNode *pSttNd = pBox->GetSttNd();
1309 	if( pSttNd &&
1310 		pSttNd->GetIndex() + 2 == pSttNd->EndOfSectionIndex() )
1311 	{
1312 		const SwCntntNode *pCNd =
1313 			pSttNd->GetNodes()[pSttNd->GetIndex()+1]->GetCntntNode();
1314 		if( pCNd && !pCNd->Len() )
1315 			return sal_True;
1316 	}
1317 
1318 	return sal_False;
1319 }
1320 
GetTopCellSpace(sal_uInt16 nRow,sal_uInt16 nRowSpan,sal_Bool bSwBorders) const1321 sal_uInt16 HTMLTable::GetTopCellSpace( sal_uInt16 nRow, sal_uInt16 nRowSpan,
1322 								   sal_Bool bSwBorders ) const
1323 {
1324 	sal_uInt16 nSpace = nCellPadding;
1325 
1326 	if( nRow == 0 )
1327 	{
1328 		nSpace += nBorder + nCellSpacing;
1329 		if( bSwBorders )
1330 		{
1331 			sal_uInt16 nTopBorderWidth =
1332 				GetBorderWidth( aTopBorderLine, sal_True );
1333 			if( nSpace < nTopBorderWidth )
1334 				nSpace = nTopBorderWidth;
1335 		}
1336 	}
1337 	else if( bSwBorders && ((*pRows)[nRow+nRowSpan-1])->bBottomBorder &&
1338 			 nSpace < MIN_BORDER_DIST )
1339 	{
1340 		ASSERT( !nCellPadding, "GetTopCellSpace: CELLPADDING!=0" );
1341 		// Wenn die Gegenueberliegende Seite umrandet ist muessen
1342 		// wir zumindest den minimalen Abstand zum Inhalt
1343 		// beruecksichtigen. (Koennte man zusaetzlich auch an
1344 		// nCellPadding festmachen.)
1345 		nSpace = MIN_BORDER_DIST;
1346 	}
1347 
1348 	return nSpace;
1349 }
1350 
GetBottomCellSpace(sal_uInt16 nRow,sal_uInt16 nRowSpan,sal_Bool bSwBorders) const1351 sal_uInt16 HTMLTable::GetBottomCellSpace( sal_uInt16 nRow, sal_uInt16 nRowSpan,
1352 									  sal_Bool bSwBorders ) const
1353 {
1354 	sal_uInt16 nSpace = nCellSpacing + nCellPadding;
1355 
1356 	if( nRow+nRowSpan == nRows )
1357 	{
1358         nSpace = nSpace + nBorder;
1359 
1360 		if( bSwBorders )
1361 		{
1362 			sal_uInt16 nBottomBorderWidth =
1363 				GetBorderWidth( aBottomBorderLine, sal_True );
1364 			if( nSpace < nBottomBorderWidth )
1365 				nSpace = nBottomBorderWidth;
1366 		}
1367 	}
1368 	else if( bSwBorders )
1369 	{
1370 		if( ((*pRows)[nRow+nRowSpan+1])->bBottomBorder )
1371 		{
1372 			sal_uInt16 nBorderWidth = GetBorderWidth( aBorderLine, sal_True );
1373 			if( nSpace < nBorderWidth )
1374 				nSpace = nBorderWidth;
1375 		}
1376 		else if( nRow==0 && bTopBorder && nSpace < MIN_BORDER_DIST )
1377 		{
1378 			ASSERT( GetBorderWidth( aTopBorderLine, sal_True ) > 0,
1379 					"GetBottomCellSpace: |aTopLine| == 0" );
1380 			ASSERT( !nCellPadding, "GetBottomCellSpace: CELLPADDING!=0" );
1381 			// Wenn die Gegenueberliegende Seite umrandet ist muessen
1382 			// wir zumindest den minimalen Abstand zum Inhalt
1383 			// beruecksichtigen. (Koennte man zusaetzlich auch an
1384 			// nCellPadding festmachen.)
1385 			nSpace = MIN_BORDER_DIST;
1386 		}
1387 	}
1388 
1389 	return nSpace;
1390 }
1391 
FixFrameFmt(SwTableBox * pBox,sal_uInt16 nRow,sal_uInt16 nCol,sal_uInt16 nRowSpan,sal_uInt16 nColSpan,sal_Bool bFirstPara,sal_Bool bLastPara) const1392 void HTMLTable::FixFrameFmt( SwTableBox *pBox,
1393 							 sal_uInt16 nRow, sal_uInt16 nCol,
1394 							 sal_uInt16 nRowSpan, sal_uInt16 nColSpan,
1395 							 sal_Bool bFirstPara, sal_Bool bLastPara ) const
1396 {
1397     SwFrmFmt *pFrmFmt = 0;      // frame::Frame-Format
1398     sal_Int16 eVOri = text::VertOrientation::NONE;
1399 	const SvxBrushItem *pBGBrushItem = 0;	// Hintergrund
1400 	sal_Bool bTopLine = sal_False, bBottomLine = sal_False, bLastBottomLine = sal_False;
1401 	sal_Bool bReUsable = sal_False;		// Format nochmals verwendbar?
1402 	sal_uInt16 nEmptyRows = 0;
1403 	sal_Bool bHasNumFmt = sal_False;
1404 	sal_Bool bHasValue = sal_False;
1405     sal_uInt32 nNumFmt = 0;
1406     double nValue = 0.0;
1407 
1408 	HTMLTableColumn *pColumn = (*pColumns)[nCol];
1409 
1410 	if( pBox->GetSttNd() )
1411 	{
1412 		// die Hintergrundfarbe/-grafik bestimmen
1413 		const HTMLTableCell *pCell = GetCell( nRow, nCol );
1414 		pBGBrushItem = pCell->GetBGBrush();
1415 		if( !pBGBrushItem )
1416 		{
1417 			// Wenn die Zelle ueber mehrere Zeilen geht muss ein evtl.
1418 			// an der Zeile gesetzter Hintergrund an die Zelle uebernommen
1419 			// werden.
1420 #ifndef FIX56334
1421 			// Wenn es sich um eine Tabelle in der Tabelle handelt und
1422 			// die Zelle ueber die gesamte Hoehe der Tabelle geht muss
1423 			// ebenfalls der Hintergrund der Zeile uebernommen werden, weil
1424 			// die Line von der GC (zu Recht) wegoptimiert wird.
1425 			if( nRowSpan > 1 || (this != pTopTable && nRowSpan==nRows) )
1426 #else
1427 			if( nRowSpan > 1 )
1428 #endif
1429 			{
1430 				pBGBrushItem = ((*pRows)[nRow])->GetBGBrush();
1431 				if( !pBGBrushItem && this != pTopTable )
1432 				{
1433 					pBGBrushItem = GetBGBrush();
1434 					if( !pBGBrushItem )
1435 						pBGBrushItem = GetInhBGBrush();
1436 				}
1437 			}
1438 		}
1439 
1440 		bTopLine = 0==nRow && bTopBorder && bFirstPara;
1441 		if( ((*pRows)[nRow+nRowSpan-1])->bBottomBorder && bLastPara )
1442 		{
1443 			nEmptyRows = ((*pRows)[nRow+nRowSpan-1])->GetEmptyRows();
1444 			if( nRow+nRowSpan == nRows )
1445 				bLastBottomLine = sal_True;
1446 			else
1447 				bBottomLine = sal_True;
1448 		}
1449 
1450 		eVOri = pCell->GetVertOri();
1451 		bHasNumFmt = pCell->GetNumFmt( nNumFmt );
1452 		if( bHasNumFmt )
1453 			bHasValue = pCell->GetValue( nValue );
1454 
1455 		if( nColSpan==1 && !bTopLine && !bLastBottomLine &&	!nEmptyRows &&
1456 			!pBGBrushItem && !bHasNumFmt )
1457 		{
1458 			pFrmFmt = pColumn->GetFrmFmt( bBottomLine, eVOri );
1459 			bReUsable = !pFrmFmt;
1460 		}
1461 	}
1462 
1463 	if( !pFrmFmt )
1464 	{
1465 		pFrmFmt = pBox->ClaimFrmFmt();
1466 
1467 		// die Breite der Box berechnen
1468 		SwTwips nFrmWidth = (SwTwips)pLayoutInfo->GetColumn(nCol)
1469 												->GetRelColWidth();
1470 		for( sal_uInt16 i=1; i<nColSpan; i++ )
1471 			nFrmWidth += (SwTwips)pLayoutInfo->GetColumn(nCol+i)
1472 											 ->GetRelColWidth();
1473 
1474 		// die Umrandung nur an Edit-Boxen setzen (bei der oberen und unteren
1475 		// Umrandung muss beruecks. werden, ob es sich um den ersten oder
1476 		// letzten Absatz der Zelle handelt)
1477 		if( pBox->GetSttNd() )
1478 		{
1479 			sal_Bool bSet = (nCellPadding > 0);
1480 
1481             SvxBoxItem aBoxItem( RES_BOX );
1482 			long nInnerFrmWidth = nFrmWidth;
1483 
1484 			if( bTopLine )
1485 			{
1486 				aBoxItem.SetLine( &aTopBorderLine, BOX_LINE_TOP );
1487 				bSet = sal_True;
1488 			}
1489 			if( bLastBottomLine )
1490 			{
1491 				aBoxItem.SetLine( &aBottomBorderLine, BOX_LINE_BOTTOM );
1492 				bSet = sal_True;
1493 			}
1494 			else if( bBottomLine )
1495 			{
1496 				if( nEmptyRows && !aBorderLine.GetInWidth() )
1497 				{
1498 					// Leere Zeilen koennen zur Zeit nur dann ueber
1499 					// dicke Linien simuliert werden, wenn die Linie
1500 					// einfach ist.
1501 					SvxBorderLine aThickBorderLine( aBorderLine );
1502 
1503 					sal_uInt16 nBorderWidth = aBorderLine.GetOutWidth();
1504 					nBorderWidth *= (nEmptyRows + 1);
1505 					SvxCSS1Parser::SetBorderWidth( aThickBorderLine,
1506 												   nBorderWidth, sal_False );
1507 					aBoxItem.SetLine( &aThickBorderLine, BOX_LINE_BOTTOM );
1508 				}
1509 				else
1510 				{
1511 					aBoxItem.SetLine( &aBorderLine, BOX_LINE_BOTTOM );
1512 				}
1513 				bSet = sal_True;
1514 			}
1515 			if( ((*pColumns)[nCol])->bLeftBorder )
1516 			{
1517 				const SvxBorderLine& rBorderLine =
1518 					0==nCol ? aLeftBorderLine : aBorderLine;
1519 				aBoxItem.SetLine( &rBorderLine, BOX_LINE_LEFT );
1520 				nInnerFrmWidth -= GetBorderWidth( rBorderLine );
1521 				bSet = sal_True;
1522 			}
1523 			if( nCol+nColSpan == nCols && bRightBorder )
1524 			{
1525 				aBoxItem.SetLine( &aRightBorderLine, BOX_LINE_RIGHT );
1526 				nInnerFrmWidth -= GetBorderWidth( aRightBorderLine );
1527 				bSet = sal_True;
1528 			}
1529 
1530 			if( bSet )
1531 			{
1532 				// fix #30588#: BorderDist nicht mehr Bestandteil
1533 				// einer Zelle mit fixer Breite
1534                 sal_uInt16 nBDist = static_cast< sal_uInt16 >(
1535 					(2*nCellPadding <= nInnerFrmWidth) ? nCellPadding
1536                                                       : (nInnerFrmWidth / 2) );
1537 				// wir setzen das Item nur, wenn es eine Umrandung gibt
1538                 // oder eine sheet::Border-Distanz vorgegeben ist. Fehlt letztere,
1539 				// dann gibt es eine Umrandung, und wir muessen die Distanz
1540 				// setzen
1541 				aBoxItem.SetDistance( nBDist ? nBDist : MIN_BORDER_DIST );
1542                 pFrmFmt->SetFmtAttr( aBoxItem );
1543 			}
1544 			else
1545                 pFrmFmt->ResetFmtAttr( RES_BOX );
1546 
1547 			if( pBGBrushItem )
1548 			{
1549                 pFrmFmt->SetFmtAttr( *pBGBrushItem );
1550 			}
1551 			else
1552                 pFrmFmt->ResetFmtAttr( RES_BACKGROUND );
1553 
1554 			// fix #41003#: Format nur setzten, wenn es auch einen Value
1555 			// gibt oder die Box leer ist.
1556 			if( bHasNumFmt && (bHasValue || IsBoxEmpty(pBox)) )
1557 			{
1558 				sal_Bool bLock = pFrmFmt->GetDoc()->GetNumberFormatter()
1559 									 ->IsTextFormat( nNumFmt );
1560 				SfxItemSet aItemSet( *pFrmFmt->GetAttrSet().GetPool(),
1561 									 RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
1562 				SvxAdjust eAdjust = SVX_ADJUST_END;
1563 				SwCntntNode *pCNd = 0;
1564 				if( !bLock )
1565 				{
1566 					const SwStartNode *pSttNd = pBox->GetSttNd();
1567 					pCNd = pSttNd->GetNodes()[pSttNd->GetIndex()+1]
1568 								 ->GetCntntNode();
1569 					const SfxPoolItem *pItem;
1570                     if( pCNd && pCNd->HasSwAttrSet() &&
1571 						SFX_ITEM_SET==pCNd->GetpSwAttrSet()->GetItemState(
1572 							RES_PARATR_ADJUST, sal_False, &pItem ) )
1573 					{
1574 						eAdjust = ((const SvxAdjustItem *)pItem)
1575 							->GetAdjust();
1576 					}
1577 				}
1578 				aItemSet.Put( SwTblBoxNumFormat(nNumFmt) );
1579 				if( bHasValue )
1580 					aItemSet.Put( SwTblBoxValue(nValue) );
1581 
1582 				if( bLock )
1583 					pFrmFmt->LockModify();
1584                 pFrmFmt->SetFmtAttr( aItemSet );
1585 				if( bLock )
1586 					pFrmFmt->UnlockModify();
1587 				else if( pCNd && SVX_ADJUST_END != eAdjust )
1588 				{
1589                     SvxAdjustItem aAdjItem( eAdjust, RES_PARATR_ADJUST );
1590 					pCNd->SetAttr( aAdjItem );
1591 				}
1592 			}
1593 			else
1594                 pFrmFmt->ResetFmtAttr( RES_BOXATR_FORMAT );
1595 
1596             ASSERT( eVOri != text::VertOrientation::TOP, "text::VertOrientation::TOP is not allowed!" );
1597             if( text::VertOrientation::NONE != eVOri )
1598 			{
1599                 pFrmFmt->SetFmtAttr( SwFmtVertOrient( 0, eVOri ) );
1600 			}
1601 			else
1602                 pFrmFmt->ResetFmtAttr( RES_VERT_ORIENT );
1603 
1604 			if( bReUsable )
1605 				pColumn->SetFrmFmt( pFrmFmt, bBottomLine, eVOri );
1606 		}
1607 		else
1608 		{
1609             pFrmFmt->ResetFmtAttr( RES_BOX );
1610             pFrmFmt->ResetFmtAttr( RES_BACKGROUND );
1611             pFrmFmt->ResetFmtAttr( RES_VERT_ORIENT );
1612             pFrmFmt->ResetFmtAttr( RES_BOXATR_FORMAT );
1613 		}
1614 	}
1615 	else
1616 	{
1617 		ASSERT( pBox->GetSttNd() ||
1618 				SFX_ITEM_SET!=pFrmFmt->GetAttrSet().GetItemState(
1619 									RES_VERT_ORIENT, sal_False ),
1620 				"Box ohne Inhalt hat vertikale Ausrichtung" );
1621 		pBox->ChgFrmFmt( (SwTableBoxFmt*)pFrmFmt );
1622 	}
1623 
1624 }
1625 
FixFillerFrameFmt(SwTableBox * pBox,sal_Bool bRight) const1626 void HTMLTable::FixFillerFrameFmt( SwTableBox *pBox, sal_Bool bRight ) const
1627 {
1628 	SwFrmFmt *pFrmFmt = pBox->ClaimFrmFmt();
1629 
1630 	if( bFillerTopBorder || bFillerBottomBorder ||
1631 		(!bRight && bInhLeftBorder) || (bRight && bInhRightBorder) )
1632 	{
1633         SvxBoxItem aBoxItem( RES_BOX );
1634 		if( bFillerTopBorder )
1635 			aBoxItem.SetLine( &aTopBorderLine, BOX_LINE_TOP );
1636 		if( bFillerBottomBorder )
1637 			aBoxItem.SetLine( &aBottomBorderLine, BOX_LINE_BOTTOM );
1638 		if( !bRight && bInhLeftBorder )
1639 			aBoxItem.SetLine( &aInhLeftBorderLine, BOX_LINE_LEFT );
1640 		if( bRight && bInhRightBorder )
1641 			aBoxItem.SetLine( &aInhRightBorderLine, BOX_LINE_RIGHT );
1642 		aBoxItem.SetDistance( MIN_BORDER_DIST );
1643         pFrmFmt->SetFmtAttr( aBoxItem );
1644 	}
1645 	else
1646 	{
1647         pFrmFmt->ResetFmtAttr( RES_BOX );
1648 	}
1649 
1650 	if( GetInhBGBrush() )
1651         pFrmFmt->SetFmtAttr( *GetInhBGBrush() );
1652 	else
1653         pFrmFmt->ResetFmtAttr( RES_BACKGROUND );
1654 
1655     pFrmFmt->ResetFmtAttr( RES_VERT_ORIENT );
1656     pFrmFmt->ResetFmtAttr( RES_BOXATR_FORMAT );
1657 }
1658 
NewTableBox(const SwStartNode * pStNd,SwTableLine * pUpper) const1659 SwTableBox *HTMLTable::NewTableBox( const SwStartNode *pStNd,
1660 									SwTableLine *pUpper ) const
1661 {
1662 	SwTableBox *pBox;
1663 
1664 	if( pTopTable->pBox1 &&
1665 		pTopTable->pBox1->GetSttNd() == pStNd )
1666 	{
1667 		// wenn der StartNode dem StartNode der initial angelegten Box
1668 		// entspricht nehmen wir diese Box
1669 		pBox = pTopTable->pBox1;
1670 		pBox->SetUpper( pUpper );
1671 		pTopTable->pBox1 = 0;
1672 	}
1673 	else
1674 		pBox = new SwTableBox( pBoxFmt, *pStNd, pUpper );
1675 
1676 	return pBox;
1677 }
1678 
1679 
ResetLineFrmFmtAttrs(SwFrmFmt * pFrmFmt)1680 static void ResetLineFrmFmtAttrs( SwFrmFmt *pFrmFmt )
1681 {
1682     pFrmFmt->ResetFmtAttr( RES_FRM_SIZE );
1683     pFrmFmt->ResetFmtAttr( RES_BACKGROUND );
1684 	ASSERT( SFX_ITEM_SET!=pFrmFmt->GetAttrSet().GetItemState(
1685 								RES_VERT_ORIENT, sal_False ),
1686 			"Zeile hat vertikale Ausrichtung" );
1687 }
1688 
1689 // !!! kann noch vereinfacht werden
MakeTableLine(SwTableBox * pUpper,sal_uInt16 nTopRow,sal_uInt16 nLeftCol,sal_uInt16 nBottomRow,sal_uInt16 nRightCol)1690 SwTableLine *HTMLTable::MakeTableLine( SwTableBox *pUpper,
1691 									   sal_uInt16 nTopRow, sal_uInt16 nLeftCol,
1692 									   sal_uInt16 nBottomRow, sal_uInt16 nRightCol )
1693 {
1694 	SwTableLine *pLine;
1695 	if( this==pTopTable && !pUpper && 0==nTopRow )
1696 		pLine = (pSwTable->GetTabLines())[0];
1697 	else
1698 		pLine = new SwTableLine( pLineFrmFmtNoHeight ? pLineFrmFmtNoHeight
1699 													 : pLineFmt,
1700 								 0, pUpper );
1701 
1702 	HTMLTableRow *pTopRow = (*pRows)[nTopRow];
1703 	sal_uInt16 nRowHeight = pTopRow->GetHeight();
1704 	const SvxBrushItem *pBGBrushItem = 0;
1705 #ifndef FIX56334
1706 	if( this == pTopTable || nTopRow>0 || nBottomRow<nRows )
1707 	{
1708 		// An der Line eine Farbe zu setzen macht keinen Sinn, wenn sie
1709 		// die auesserste und gleichzeitig einzige Zeile einer Tabelle in
1710 		// der Tabelle ist.
1711 #endif
1712 		pBGBrushItem = pTopRow->GetBGBrush();
1713 
1714 		if( !pBGBrushItem && this != pTopTable )
1715 		{
1716 			// Ein an einer Tabellen in der Tabelle gesetzter Hintergrund
1717 			// wird an den Rows gesetzt. Das gilt auch fuer den Hintergrund
1718 			// der Zelle, in dem die Tabelle vorkommt.
1719 			pBGBrushItem = GetBGBrush();
1720 			if( !pBGBrushItem )
1721 				pBGBrushItem = GetInhBGBrush();
1722 		}
1723 #ifndef FIX56334
1724 	}
1725 #endif
1726 	if( nTopRow==nBottomRow-1 && (nRowHeight || pBGBrushItem) )
1727 	{
1728 		SwTableLineFmt *pFrmFmt = (SwTableLineFmt*)pLine->ClaimFrmFmt();
1729 		ResetLineFrmFmtAttrs( pFrmFmt );
1730 
1731 		if( nRowHeight )
1732 		{
1733 			// Tabellenhoehe einstellen. Da es sich um eine
1734 			// Mindesthoehe handelt, kann sie genauso wie in
1735 			// Netscape berechnet werden, also ohne Beruecksichtigung
1736 			// der tatsaechlichen Umrandungsbreite.
1737 			nRowHeight += GetTopCellSpace( nTopRow, 1, sal_False ) +
1738 					   GetBottomCellSpace( nTopRow, 1, sal_False );
1739 
1740             pFrmFmt->SetFmtAttr( SwFmtFrmSize( ATT_MIN_SIZE, 0, nRowHeight ) );
1741 		}
1742 
1743 		if( pBGBrushItem )
1744 		{
1745             pFrmFmt->SetFmtAttr( *pBGBrushItem );
1746 		}
1747 
1748 	}
1749 	else if( !pLineFrmFmtNoHeight )
1750 	{
1751 		// sonst muessen wir die Hoehe aus dem Attribut entfernen
1752 		// und koennen uns das Format merken
1753 		pLineFrmFmtNoHeight = (SwTableLineFmt*)pLine->ClaimFrmFmt();
1754 
1755 		ResetLineFrmFmtAttrs( pLineFrmFmtNoHeight );
1756 	}
1757 
1758 
1759 	SwTableBoxes& rBoxes = pLine->GetTabBoxes();
1760 
1761 	sal_uInt16 nStartCol = nLeftCol;
1762 	while( nStartCol<nRightCol )
1763 	{
1764 		sal_uInt16 nCol = nStartCol;
1765 		sal_uInt16 nSplitCol = nRightCol;
1766 		sal_Bool bSplitted = sal_False;
1767 		while( !bSplitted )
1768 		{
1769 			ASSERT( nCol < nRightCol, "Zu weit gelaufen" );
1770 
1771 			HTMLTableCell *pCell = GetCell(nTopRow,nCol);
1772     		const sal_Bool bSplit = 1 == pCell->GetColSpan();
1773 
1774 #ifdef DBG_UTIL
1775 			if( nCol == nRightCol-1 )
1776 			{
1777 				ASSERT( bSplit, "Split-Flag falsch" );
1778 			}
1779 #endif
1780             if( bSplit )
1781 			{
1782 				SwTableBox* pBox = 0;
1783                 HTMLTableCell *pCell2 = GetCell( nTopRow, nStartCol );
1784                 if( pCell2->GetColSpan() == (nCol+1-nStartCol) )
1785 				{
1786                     // Die HTML-Tabellen-Zellen bilden genau eine Box.
1787 					// Dann muss hinter der Box gesplittet werden
1788 					nSplitCol = nCol + 1;
1789 
1790                     long nBoxRowSpan = pCell2->GetRowSpan();
1791                     if ( !pCell2->GetContents() || pCell2->IsCovered() )
1792                     {
1793                         if ( pCell2->IsCovered() )
1794                             nBoxRowSpan = -1 * nBoxRowSpan;
1795 
1796                         const SwStartNode* pPrevStartNd =
1797 							GetPrevBoxStartNode( nTopRow, nStartCol );
1798 						HTMLTableCnts *pCnts = new HTMLTableCnts(
1799                             pParser->InsertTableSection(pPrevStartNd) );
1800 						SwHTMLTableLayoutCnts *pCntsLayoutInfo =
1801 							pCnts->CreateLayoutInfo();
1802 
1803                         pCell2->SetContents( pCnts );
1804 						SwHTMLTableLayoutCell *pCurrCell = pLayoutInfo->GetCell( nTopRow, nStartCol );
1805                         pCurrCell->SetContents( pCntsLayoutInfo );
1806                         if( nBoxRowSpan < 0 )
1807                             pCurrCell->SetRowSpan( 0 );
1808 
1809 						// ggf. COLSPAN beachten
1810 						for( sal_uInt16 j=nStartCol+1; j<nSplitCol; j++ )
1811 						{
1812 							GetCell(nTopRow,j)->SetContents( pCnts );
1813 							pLayoutInfo->GetCell( nTopRow, j )
1814 									   ->SetContents( pCntsLayoutInfo );
1815 						}
1816 					}
1817 
1818                     pBox = MakeTableBox( pLine, pCell2->GetContents(),
1819 										 nTopRow, nStartCol,
1820 										 nBottomRow, nSplitCol );
1821 
1822                     if ( 1 != nBoxRowSpan )
1823                         pBox->setRowSpan( nBoxRowSpan );
1824 
1825 					bSplitted = sal_True;
1826 				}
1827 
1828                 ASSERT( pBox, "Colspan trouble" )
1829 
1830                 if( pBox )
1831 					rBoxes.C40_INSERT( SwTableBox, pBox, rBoxes.Count() );
1832 			}
1833 			nCol++;
1834 		}
1835 		nStartCol = nSplitCol;
1836 	}
1837 
1838 	return pLine;
1839 }
1840 
MakeTableBox(SwTableLine * pUpper,HTMLTableCnts * pCnts,sal_uInt16 nTopRow,sal_uInt16 nLeftCol,sal_uInt16 nBottomRow,sal_uInt16 nRightCol)1841 SwTableBox *HTMLTable::MakeTableBox( SwTableLine *pUpper,
1842 									 HTMLTableCnts *pCnts,
1843 									 sal_uInt16 nTopRow, sal_uInt16 nLeftCol,
1844 									 sal_uInt16 nBottomRow, sal_uInt16 nRightCol )
1845 {
1846 	SwTableBox *pBox;
1847 	sal_uInt16 nColSpan = nRightCol - nLeftCol;
1848 	sal_uInt16 nRowSpan = nBottomRow - nTopRow;
1849 
1850 	if( !pCnts->Next() )
1851 	{
1852 		// nur eine Inhalts-Section
1853 		if( pCnts->GetStartNode() )
1854 		{
1855 			// und die ist keine Tabelle
1856 			pBox = NewTableBox( pCnts->GetStartNode(), pUpper );
1857 			pCnts->SetTableBox( pBox );
1858 		}
1859 		else
1860 		{
1861 			pCnts->GetTable()->InheritVertBorders( this, nLeftCol,
1862 												   nRightCol-nLeftCol );
1863 			// und die ist eine Tabelle: dann bauen wir eine neue
1864 			// Box und fuegen die Zeilen der Tabelle in die Zeilen
1865 			// der Box ein
1866 			pBox = new SwTableBox( pBoxFmt, 0, pUpper );
1867 			sal_uInt16 nAbs, nRel;
1868 			pLayoutInfo->GetAvail( nLeftCol, nColSpan, nAbs, nRel );
1869 			sal_uInt16 nLSpace = pLayoutInfo->GetLeftCellSpace( nLeftCol, nColSpan );
1870 			sal_uInt16 nRSpace = pLayoutInfo->GetRightCellSpace( nLeftCol, nColSpan );
1871 			sal_uInt16 nInhSpace = pLayoutInfo->GetInhCellSpace( nLeftCol, nColSpan );
1872 			pCnts->GetTable()->MakeTable( pBox, nAbs, nRel, nLSpace, nRSpace,
1873 										  nInhSpace );
1874 		}
1875 	}
1876 	else
1877 	{
1878 		// mehrere Inhalts Sections: dann brauchen wir eine Box mit Zeilen
1879         pBox = new SwTableBox( pBoxFmt, 0, pUpper );
1880 		SwTableLines& rLines = pBox->GetTabLines();
1881 		sal_Bool bFirstPara = sal_True;
1882 
1883 		while( pCnts )
1884 		{
1885 			if( pCnts->GetStartNode() )
1886 			{
1887 				// normale Absaetze werden zu einer Box in einer Zeile
1888 				SwTableLine *pLine =
1889 					new SwTableLine( pLineFrmFmtNoHeight ? pLineFrmFmtNoHeight
1890 														 : pLineFmt, 0, pBox );
1891 				if( !pLineFrmFmtNoHeight )
1892 				{
1893 					// Wenn es noch kein Line-Format ohne Hoehe gibt, koennen
1894 					// wir uns dieses her als solches merken
1895 					pLineFrmFmtNoHeight = (SwTableLineFmt*)pLine->ClaimFrmFmt();
1896 
1897 					ResetLineFrmFmtAttrs( pLineFrmFmtNoHeight );
1898 				}
1899 
1900 				SwTableBox* pCntBox = NewTableBox( pCnts->GetStartNode(),
1901 												   pLine );
1902 				pCnts->SetTableBox( pCntBox );
1903 				FixFrameFmt( pCntBox, nTopRow, nLeftCol, nRowSpan, nColSpan,
1904 							 bFirstPara, 0==pCnts->Next() );
1905 				pLine->GetTabBoxes().C40_INSERT( SwTableBox, pCntBox,
1906 											 pLine->GetTabBoxes().Count() );
1907 
1908 				rLines.C40_INSERT( SwTableLine, pLine, rLines.Count() );
1909 			}
1910 			else
1911 			{
1912 				pCnts->GetTable()->InheritVertBorders( this, nLeftCol,
1913 													   nRightCol-nLeftCol );
1914 				// Tabellen werden direkt eingetragen
1915 				sal_uInt16 nAbs, nRel;
1916 				pLayoutInfo->GetAvail( nLeftCol, nColSpan, nAbs, nRel );
1917 				sal_uInt16 nLSpace = pLayoutInfo->GetLeftCellSpace( nLeftCol,
1918 																nColSpan );
1919 				sal_uInt16 nRSpace = pLayoutInfo->GetRightCellSpace( nLeftCol,
1920 																 nColSpan );
1921 				sal_uInt16 nInhSpace = pLayoutInfo->GetInhCellSpace( nLeftCol, nColSpan );
1922 				pCnts->GetTable()->MakeTable( pBox, nAbs, nRel, nLSpace,
1923 											  nRSpace, nInhSpace );
1924 			}
1925 
1926 			pCnts = pCnts->Next();
1927 			bFirstPara = sal_False;
1928 		}
1929 	}
1930 
1931 	FixFrameFmt( pBox, nTopRow, nLeftCol, nRowSpan, nColSpan );
1932 
1933 	return pBox;
1934 }
1935 
InheritBorders(const HTMLTable * pParent,sal_uInt16 nRow,sal_uInt16 nCol,sal_uInt16 nRowSpan,sal_uInt16,sal_Bool bFirstPara,sal_Bool bLastPara)1936 void HTMLTable::InheritBorders( const HTMLTable *pParent,
1937 								sal_uInt16 nRow, sal_uInt16 nCol,
1938 								sal_uInt16 nRowSpan, sal_uInt16 /*nColSpan*/,
1939 								sal_Bool bFirstPara, sal_Bool bLastPara )
1940 {
1941 	ASSERT( nRows>0 && nCols>0 && nCurRow==nRows,
1942 			"Wurde CloseTable nicht aufgerufen?" );
1943 
1944 	// Die Child-Tabelle muss einen Rahmen bekommen, wenn die umgebende
1945 	// Zelle einen Rand an der betreffenden Seite besitzt.
1946 	// Der obere bzw. untere Rand wird nur gesetzt, wenn die Tabelle
1947 	// als erster bzw. letzter Absatz in der Zelle vorkommt. Ansonsten
1948 	// Fuer den linken/rechten Rand kann noch nicht entschieden werden,
1949 	// ob eine Umrandung der Tabelle noetig/moeglich ist, weil das davon
1950 	// abhaengt, ob "Filler"-Zellen eingefuegt werden. Hier werden deshalb
1951 	// erstmal nur Informationen gesammelt
1952 	//
1953 	if( 0==nRow && pParent->bTopBorder && bFirstPara )
1954 	{
1955 		bTopBorder = sal_True;
1956 		bFillerTopBorder = sal_True; // auch Filler bekommt eine Umrandung
1957 		aTopBorderLine = pParent->aTopBorderLine;
1958 	}
1959 	if( ((*pParent->pRows)[nRow+nRowSpan-1])->bBottomBorder && bLastPara )
1960 	{
1961 		((*pRows)[nRows-1])->bBottomBorder = sal_True;
1962 		bFillerBottomBorder = sal_True; // auch Filler bekommt eine Umrandung
1963 		aBottomBorderLine =
1964 			nRow+nRowSpan==pParent->nRows ? pParent->aBottomBorderLine
1965 										  : pParent->aBorderLine;
1966 	}
1967 
1968 
1969 	// Die Child Tabelle darf keinen oberen oder linken Rahmen bekommen,
1970 	// wenn der bereits durch die umgebende Tabelle gesetzt ist.
1971 	// Sie darf jedoch immer einen oberen Rand bekommen, wenn die Tabelle
1972 	// nicht der erste Absatz in der Zelle ist.
1973 	bTopAlwd = ( !bFirstPara || (pParent->bTopAlwd &&
1974 				 (0==nRow || !((*pParent->pRows)[nRow-1])->bBottomBorder)) );
1975 
1976 	// die Child-Tabelle muss die Farbe der Zelle erben, in der sie
1977 	// vorkommt, wenn sie keine eigene besitzt
1978 	const SvxBrushItem *pInhBG = pParent->GetCell(nRow,nCol)->GetBGBrush();
1979 	if( !pInhBG && pParent != pTopTable &&
1980 		pParent->GetCell(nRow,nCol)->GetRowSpan() == pParent->nRows )
1981 	{
1982 		// die ganze umgebende Tabelle ist eine Tabelle in der Tabelle
1983 		// und besteht nur aus einer Line, die bei der GC (zu Recht)
1984 		// wegoptimiert wird. Deshalb muss der Hintergrund der Line in
1985 		// diese Tabelle uebernommen werden.
1986 		pInhBG = ((*pParent->pRows)[nRow])->GetBGBrush();
1987 		if( !pInhBG )
1988 			pInhBG = pParent->GetBGBrush();
1989 		if( !pInhBG )
1990 			pInhBG = pParent->GetInhBGBrush();
1991 	}
1992 	if( pInhBG )
1993 		pInhBGBrush = new SvxBrushItem( *pInhBG );
1994 }
1995 
InheritVertBorders(const HTMLTable * pParent,sal_uInt16 nCol,sal_uInt16 nColSpan)1996 void HTMLTable::InheritVertBorders( const HTMLTable *pParent,
1997 								 sal_uInt16 nCol, sal_uInt16 nColSpan )
1998 {
1999 	sal_uInt16 nInhLeftBorderWidth = 0;
2000 	sal_uInt16 nInhRightBorderWidth = 0;
2001 
2002 	if( nCol+nColSpan==pParent->nCols && pParent->bRightBorder )
2003 	{
2004 		bInhRightBorder = sal_True;	// erstmal nur merken
2005 		aInhRightBorderLine = pParent->aRightBorderLine;
2006 		nInhRightBorderWidth =
2007 			GetBorderWidth( aInhRightBorderLine, sal_True ) + MIN_BORDER_DIST;
2008 	}
2009 
2010 	if( ((*pParent->pColumns)[nCol])->bLeftBorder )
2011 	{
2012 		bInhLeftBorder = sal_True;	// erstmal nur merken
2013 		aInhLeftBorderLine = 0==nCol ? pParent->aLeftBorderLine
2014 									 : pParent->aBorderLine;
2015 		nInhLeftBorderWidth =
2016 			GetBorderWidth( aInhLeftBorderLine, sal_True ) + MIN_BORDER_DIST;
2017 	}
2018 
2019 	if( !bInhLeftBorder && (bFillerTopBorder || bFillerBottomBorder) )
2020 		nInhLeftBorderWidth = 2 * MIN_BORDER_DIST;
2021 	if( !bInhRightBorder && (bFillerTopBorder || bFillerBottomBorder) )
2022 		nInhRightBorderWidth = 2 * MIN_BORDER_DIST;
2023 	pLayoutInfo->SetInhBorderWidths( nInhLeftBorderWidth,
2024 									 nInhRightBorderWidth );
2025 
2026 	bRightAlwd = ( pParent->bRightAlwd &&
2027 				  (nCol+nColSpan==pParent->nCols ||
2028 				   !((*pParent->pColumns)[nCol+nColSpan])->bLeftBorder) );
2029 }
2030 
SetBorders()2031 void HTMLTable::SetBorders()
2032 {
2033 	sal_uInt16 i;
2034 	for( i=1; i<nCols; i++ )
2035 		if( HTML_TR_ALL==eRules || HTML_TR_COLS==eRules ||
2036 			((HTML_TR_ROWS==eRules || HTML_TR_GROUPS==eRules) &&
2037 			 ((*pColumns)[i-1])->IsEndOfGroup()) )
2038 			((*pColumns)[i])->bLeftBorder = sal_True;
2039 
2040 	for( i=0; i<nRows-1; i++ )
2041 		if( HTML_TR_ALL==eRules || HTML_TR_ROWS==eRules ||
2042 			((HTML_TR_COLS==eRules || HTML_TR_GROUPS==eRules) &&
2043 			 ((*pRows)[i])->IsEndOfGroup()) )
2044 			((*pRows)[i])->bBottomBorder = sal_True;
2045 
2046 	if( bTopAlwd && (HTML_TF_ABOVE==eFrame || HTML_TF_HSIDES==eFrame ||
2047 					 HTML_TF_BOX==eFrame) )
2048 		bTopBorder = sal_True;
2049 	if( HTML_TF_BELOW==eFrame || HTML_TF_HSIDES==eFrame ||
2050 		HTML_TF_BOX==eFrame )
2051 		((*pRows)[nRows-1])->bBottomBorder = sal_True;
2052 	if( /*bRightAlwd &&*/ (HTML_TF_RHS==eFrame || HTML_TF_VSIDES==eFrame ||
2053 					  HTML_TF_BOX==eFrame) )
2054 		bRightBorder = sal_True;
2055 	if( HTML_TF_LHS==eFrame || HTML_TF_VSIDES==eFrame || HTML_TF_BOX==eFrame )
2056 		((*pColumns)[0])->bLeftBorder = sal_True;
2057 
2058 	for( i=0; i<nRows; i++ )
2059 	{
2060 		HTMLTableRow *pRow = (*pRows)[i];
2061 		for( sal_uInt16 j=0; j<nCols; j++ )
2062 		{
2063 			HTMLTableCell *pCell = pRow->GetCell(j);
2064 			if( pCell->GetContents()  )
2065 			{
2066 				HTMLTableCnts *pCnts = pCell->GetContents();
2067 				sal_Bool bFirstPara = sal_True;
2068 				while( pCnts )
2069 				{
2070 					HTMLTable *pTable = pCnts->GetTable();
2071 					if( pTable && !pTable->BordersSet() )
2072 					{
2073 						pTable->InheritBorders( this, i, j,
2074 												pCell->GetRowSpan(),
2075 												pCell->GetColSpan(),
2076 												bFirstPara,
2077 												0==pCnts->Next() );
2078 						pTable->SetBorders();
2079 					}
2080 					bFirstPara = sal_False;
2081 					pCnts = pCnts->Next();
2082 				}
2083 			}
2084 		}
2085 	}
2086 
2087 	bBordersSet = sal_True;
2088 }
2089 
GetBorderWidth(const SvxBorderLine & rBLine,sal_Bool bWithDistance) const2090 sal_uInt16 HTMLTable::GetBorderWidth( const SvxBorderLine& rBLine,
2091 								  sal_Bool bWithDistance ) const
2092 {
2093 	sal_uInt16 nBorderWidth = rBLine.GetOutWidth() + rBLine.GetInWidth() +
2094 					rBLine.GetDistance();
2095 	if( bWithDistance )
2096 	{
2097 		if( nCellPadding )
2098             nBorderWidth = nBorderWidth + nCellPadding;
2099 		else if( nBorderWidth )
2100             nBorderWidth = nBorderWidth + MIN_BORDER_DIST;
2101 	}
2102 
2103 	return nBorderWidth;
2104 }
2105 
GetCell(sal_uInt16 nRow,sal_uInt16 nCell) const2106 inline HTMLTableCell *HTMLTable::GetCell( sal_uInt16 nRow,
2107 										  sal_uInt16 nCell ) const
2108 {
2109 	ASSERT( nRow<pRows->Count(),
2110 		"ungueltiger Zeilen-Index in HTML-Tabelle" );
2111 	return ((*pRows)[nRow])->GetCell( nCell );
2112 }
2113 
2114 
2115 
GetInheritedAdjust() const2116 SvxAdjust HTMLTable::GetInheritedAdjust() const
2117 {
2118 	SvxAdjust eAdjust = (nCurCol<nCols ? ((*pColumns)[nCurCol])->GetAdjust()
2119 									   : SVX_ADJUST_END );
2120 	if( SVX_ADJUST_END==eAdjust )
2121 		eAdjust = ((*pRows)[nCurRow])->GetAdjust();
2122 
2123 	return eAdjust;
2124 }
2125 
GetInheritedVertOri() const2126 sal_Int16 HTMLTable::GetInheritedVertOri() const
2127 {
2128     // text::VertOrientation::TOP ist der default!
2129     sal_Int16 eVOri = ((*pRows)[nCurRow])->GetVertOri();
2130     if( text::VertOrientation::TOP==eVOri && nCurCol<nCols )
2131 		eVOri = ((*pColumns)[nCurCol])->GetVertOri();
2132     if( text::VertOrientation::TOP==eVOri )
2133 		eVOri = eVertOri;
2134 
2135     ASSERT( eVertOri != text::VertOrientation::TOP, "text::VertOrientation::TOP is not allowed!" );
2136 	return eVOri;
2137 }
2138 
InsertCell(HTMLTableCnts * pCnts,sal_uInt16 nRowSpan,sal_uInt16 nColSpan,sal_uInt16 nCellWidth,sal_Bool bRelWidth,sal_uInt16 nCellHeight,sal_Int16 eVertOrient,SvxBrushItem * pBGBrushItem,sal_Bool bHasNumFmt,sal_uInt32 nNumFmt,sal_Bool bHasValue,double nValue,sal_Bool bNoWrap)2139 void HTMLTable::InsertCell( HTMLTableCnts *pCnts,
2140 							sal_uInt16 nRowSpan, sal_uInt16 nColSpan,
2141 							sal_uInt16 nCellWidth, sal_Bool bRelWidth, sal_uInt16 nCellHeight,
2142                             sal_Int16 eVertOrient, SvxBrushItem *pBGBrushItem,
2143 							sal_Bool bHasNumFmt, sal_uInt32 nNumFmt,
2144                             sal_Bool bHasValue, double nValue, sal_Bool bNoWrap )
2145 {
2146 	if( !nRowSpan || (sal_uInt32)nCurRow + nRowSpan > USHRT_MAX )
2147 		nRowSpan = 1;
2148 
2149 	if( !nColSpan || (sal_uInt32)nCurCol + nColSpan > USHRT_MAX )
2150 		nColSpan = 1;
2151 
2152 	sal_uInt16 nColsReq = nCurCol + nColSpan;		// benoetigte Spalten
2153 	sal_uInt16 nRowsReq = nCurRow + nRowSpan;		// benoetigte Zeilen
2154 	sal_uInt16 i, j;
2155 
2156 	// falls wir mehr Spalten benoetigen als wir zur Zeit haben,
2157 	// muessen wir in allen Zeilen noch Zellen hinzufuegen
2158 	if( nCols < nColsReq )
2159 	{
2160 		for( i=nCols; i<nColsReq; i++ )
2161 			pColumns->Insert( new HTMLTableColumn, pColumns->Count() );
2162 		for( i=0; i<nRows; i++ )
2163 			((*pRows)[i])->Expand( nColsReq, i<nCurRow );
2164 		nCols = nColsReq;
2165 		ASSERT( pColumns->Count()==nCols,
2166 				"Anzahl der Spalten nach Expandieren stimmt nicht" );
2167 	}
2168 	if( nColsReq > nFilledCols )
2169 		nFilledCols = nColsReq;
2170 
2171 	// falls wir mehr Zeilen benoetigen als wir zur Zeit haben,
2172 	// muessen wir noch neue Zeilen hinzufuegen
2173 	if( nRows < nRowsReq )
2174 	{
2175 		for( i=nRows; i<nRowsReq; i++ )
2176 			pRows->Insert( new HTMLTableRow(nCols), pRows->Count() );
2177 		nRows = nRowsReq;
2178 		ASSERT( nRows==pRows->Count(), "Zeilenzahl in Insert stimmt nicht" );
2179 	}
2180 
2181 	// Testen, ob eine Ueberschneidung vorliegt und diese
2182 	// gegebenenfalls beseitigen
2183 	sal_uInt16 nSpanedCols = 0;
2184 	if( nCurRow>0 )
2185 	{
2186 		HTMLTableRow *pCurRow = (*pRows)[nCurRow];
2187 		for( i=nCurCol; i<nColsReq; i++ )
2188 		{
2189 			HTMLTableCell *pCell = pCurRow->GetCell(i);
2190 			if( pCell->GetContents() )
2191 			{
2192 				// Der Inhalt reicht von einer weiter oben stehenden Zelle
2193 				// hier herein. Inhalt und Farbe der Zelle sind deshalb in
2194 				// jedem Fall noch dort verankert und koennen deshalb
2195 				// ueberschrieben werden bzw. von ProtectRowSpan geloescht
2196 				// (Inhalt) oder kopiert (Farbe) werden.
2197 				nSpanedCols = i + pCell->GetColSpan();
2198 				FixRowSpan( nCurRow-1, i, pCell->GetContents() );
2199 				if( pCell->GetRowSpan() > nRowSpan )
2200 					ProtectRowSpan( nRowsReq, i,
2201 									pCell->GetRowSpan()-nRowSpan );
2202 			}
2203 		}
2204 		for( i=nColsReq; i<nSpanedCols; i++ )
2205 		{
2206 			// Auch diese Inhalte sind in jedem Fall nicht in der Zeile
2207 			// darueber verankert.
2208 			HTMLTableCell *pCell = pCurRow->GetCell(i);
2209 			FixRowSpan( nCurRow-1, i, pCell->GetContents() );
2210 			ProtectRowSpan( nCurRow, i, pCell->GetRowSpan() );
2211 		}
2212 	}
2213 
2214     // Fill the cells
2215     for( i=nColSpan; i>0; i-- )
2216     {
2217         for( j=nRowSpan; j>0; j-- )
2218         {
2219             const bool bCovered = i != nColSpan || j != nRowSpan;
2220             GetCell( nRowsReq-j, nColsReq-i )
2221                 ->Set( pCnts, j, i, eVertOrient, pBGBrushItem,
2222                        bHasNumFmt, nNumFmt, bHasValue, nValue, bNoWrap, bCovered );
2223         }
2224     }
2225 
2226 	Size aTwipSz( bRelWidth ? 0 : nCellWidth, nCellHeight );
2227 	if( (aTwipSz.Width() || aTwipSz.Height()) && Application::GetDefaultDevice() )
2228 	{
2229 		aTwipSz = Application::GetDefaultDevice()
2230 					->PixelToLogic( aTwipSz, MapMode( MAP_TWIP ) );
2231 	}
2232 
2233 	// die Breite nur in die erste Zelle setzen!
2234 	if( nCellWidth )
2235 	{
2236 		sal_uInt16 nTmp = bRelWidth ? nCellWidth : (sal_uInt16)aTwipSz.Width();
2237 		GetCell( nCurRow, nCurCol )->SetWidth( nTmp, bRelWidth );
2238 	}
2239 
2240 	// Ausserdem noch die Hoehe merken
2241 	if( nCellHeight && 1==nRowSpan )
2242 	{
2243 		if( nCellHeight < MINLAY )
2244 			nCellHeight = MINLAY;
2245 		((*pRows)[nCurRow])->SetHeight( (sal_uInt16)aTwipSz.Height() );
2246 	}
2247 
2248 	// den Spaltenzaehler hinter die neuen Zellen setzen
2249 	nCurCol = nColsReq;
2250 	if( nSpanedCols > nCurCol )
2251 		nCurCol = nSpanedCols;
2252 
2253 	// und die naechste freie Zelle suchen
2254 	while( nCurCol<nCols && GetCell(nCurRow,nCurCol)->IsUsed() )
2255 		nCurCol++;
2256 }
2257 
CloseSection(sal_Bool bHead)2258 inline void HTMLTable::CloseSection( sal_Bool bHead )
2259 {
2260 	// die vorhergehende Section beenden, falls es schon eine Zeile gibt
2261 	ASSERT( nCurRow<=nRows, "ungueltige aktuelle Zeile" );
2262 	if( nCurRow>0 && nCurRow<=nRows )
2263 		((*pRows)[nCurRow-1])->SetEndOfGroup();
2264 	if( bHead /*&& nCurRow==1*/ )
2265 //		bHeadlineRepeat = sal_True;
2266 		nHeadlineRepeat = nCurRow;
2267 }
2268 
OpenRow(SvxAdjust eAdjust,sal_Int16 eVertOrient,SvxBrushItem * pBGBrushItem)2269 void HTMLTable::OpenRow( SvxAdjust eAdjust, sal_Int16 eVertOrient,
2270 						 SvxBrushItem *pBGBrushItem )
2271 {
2272 	sal_uInt16 nRowsReq = nCurRow+1;	// Anzahl benoetigter Zeilen;
2273 
2274 	// die naechste Zeile anlegen, falls sie nicht schon da ist
2275 	if( nRows<nRowsReq )
2276 	{
2277 		for( sal_uInt16 i=nRows; i<nRowsReq; i++ )
2278 			pRows->Insert( new HTMLTableRow(nCols), pRows->Count() );
2279 		nRows = nRowsReq;
2280 		ASSERT( nRows==pRows->Count(),
2281 				"Zeilenzahl in OpenRow stimmt nicht" );
2282 	}
2283 
2284 	HTMLTableRow *pCurRow = ((*pRows)[nCurRow]);
2285 	pCurRow->SetAdjust( eAdjust );
2286 	pCurRow->SetVertOri( eVertOrient );
2287 	if( pBGBrushItem )
2288 		((*pRows)[nCurRow])->SetBGBrush( pBGBrushItem );
2289 
2290 	// den Spaltenzaehler wieder an den Anfang setzen
2291 	nCurCol=0;
2292 
2293 	// und die naechste freie Zelle suchen
2294 	while( nCurCol<nCols && GetCell(nCurRow,nCurCol)->IsUsed() )
2295 		nCurCol++;
2296 }
2297 
CloseRow(sal_Bool bEmpty)2298 void HTMLTable::CloseRow( sal_Bool bEmpty )
2299 {
2300 	ASSERT( nCurRow<nRows, "aktuelle Zeile hinter dem Tabellenende" );
2301 
2302 	// leere Zellen bekommen einfach einen etwas dickeren unteren Rand!
2303 	if( bEmpty )
2304 	{
2305 		if( nCurRow > 0 )
2306 			((*pRows)[nCurRow-1])->IncEmptyRows();
2307 		return;
2308 	}
2309 
2310 	HTMLTableRow *pRow = (*pRows)[nCurRow];
2311 
2312 	// den COLSPAN aller leeren Zellen am Zeilenende so anpassen, dass
2313 	// eine Zelle daraus wird. Das kann man hier machen (und auf keinen
2314 	// Fall frueher), weil jetzt keine Zellen mehr in die Zeile eingefuegt
2315 	// werden.
2316 	sal_uInt16 i=nCols;
2317 	while( i )
2318 	{
2319 		HTMLTableCell *pCell = pRow->GetCell(--i);
2320 		if( !pCell->GetContents() )
2321 		{
2322 			sal_uInt16 nColSpan = nCols-i;
2323 			if( nColSpan > 1 )
2324 				pCell->SetColSpan( nColSpan );
2325 		}
2326 		else
2327 			break;
2328 	}
2329 
2330 
2331 	nCurRow++;
2332 }
2333 
CloseColGroup(sal_uInt16 nSpan,sal_uInt16 _nWidth,sal_Bool bRelWidth,SvxAdjust eAdjust,sal_Int16 eVertOrient)2334 inline void HTMLTable::CloseColGroup( sal_uInt16 nSpan, sal_uInt16 _nWidth,
2335 									  sal_Bool bRelWidth, SvxAdjust eAdjust,
2336                                       sal_Int16 eVertOrient )
2337 {
2338 	if( nSpan )
2339 		InsertCol( nSpan, _nWidth, bRelWidth, eAdjust, eVertOrient );
2340 
2341 	ASSERT( nCurCol<=nCols, "ungueltige Spalte" );
2342 	if( nCurCol>0 && nCurCol<=nCols )
2343 		((*pColumns)[nCurCol-1])->SetEndOfGroup();
2344 }
2345 
InsertCol(sal_uInt16 nSpan,sal_uInt16 nColWidth,sal_Bool bRelWidth,SvxAdjust eAdjust,sal_Int16 eVertOrient)2346 void HTMLTable::InsertCol( sal_uInt16 nSpan, sal_uInt16 nColWidth, sal_Bool bRelWidth,
2347                            SvxAdjust eAdjust, sal_Int16 eVertOrient )
2348 {
2349     // --> OD, MIB 2004-11-08 #i35143# - no columns, if rows already exist.
2350     if ( nRows > 0 )
2351         return;
2352     // <--
2353 
2354 	sal_uInt16 i;
2355 
2356 	if( !nSpan )
2357 		nSpan = 1;
2358 
2359 	sal_uInt16 nColsReq = nCurCol + nSpan;		// benoetigte Spalten
2360 
2361 	if( nCols < nColsReq )
2362 	{
2363 		for( i=nCols; i<nColsReq; i++ )
2364 			pColumns->Insert( new HTMLTableColumn, pColumns->Count() );
2365 		nCols = nColsReq;
2366 	}
2367 
2368 	Size aTwipSz( bRelWidth ? 0 : nColWidth, 0 );
2369 	if( aTwipSz.Width() && Application::GetDefaultDevice() )
2370 	{
2371 		aTwipSz = Application::GetDefaultDevice()
2372 					->PixelToLogic( aTwipSz, MapMode( MAP_TWIP ) );
2373 	}
2374 
2375 	for( i=nCurCol; i<nColsReq; i++ )
2376 	{
2377 		HTMLTableColumn *pCol = (*pColumns)[i];
2378 		sal_uInt16 nTmp = bRelWidth ? nColWidth : (sal_uInt16)aTwipSz.Width();
2379 		pCol->SetWidth( nTmp, bRelWidth );
2380 		pCol->SetAdjust( eAdjust );
2381 		pCol->SetVertOri( eVertOrient );
2382 	}
2383 
2384 	bColSpec = sal_True;
2385 
2386 	nCurCol = nColsReq;
2387 }
2388 
2389 
CloseTable()2390 void HTMLTable::CloseTable()
2391 {
2392 	sal_uInt16 i;
2393 
2394 	// Die Anzahl der Tabellenzeilen richtet sich nur nach den
2395 	// <TR>-Elementen (d.h. nach nCurRow). Durch ROWSPAN aufgespannte
2396 	// Zeilen hinter Zeile nCurRow muessen wir deshalb loeschen
2397 	// und vor allem aber den ROWSPAN in den darueberliegenden Zeilen
2398 	// anpassen.
2399 	if( nRows>nCurRow )
2400 	{
2401 		HTMLTableRow *pPrevRow = (*pRows)[nCurRow-1];
2402 		HTMLTableCell *pCell;
2403 		for( i=0; i<nCols; i++ )
2404 			if( ( pCell=pPrevRow->GetCell(i), pCell->GetRowSpan() > 1 ) )
2405 			{
2406 				FixRowSpan( nCurRow-1, i, pCell->GetContents() );
2407 				ProtectRowSpan( nCurRow, i, (*pRows)[nCurRow]->GetCell(i)->GetRowSpan() );
2408 			}
2409 		for( i=nRows-1; i>=nCurRow; i-- )
2410 			pRows->DeleteAndDestroy(i);
2411 		nRows = nCurRow;
2412 	}
2413 
2414 	// falls die Tabelle keine Spalte hat, muessen wir eine hinzufuegen
2415 	if( 0==nCols )
2416 	{
2417 		pColumns->Insert( new HTMLTableColumn, pColumns->Count() );
2418 		for( i=0; i<nRows; i++ )
2419 			((*pRows)[i])->Expand(1);
2420 		nCols = 1;
2421 		nFilledCols = 1;
2422 	}
2423 
2424 	// falls die Tabelle keine Zeile hat, muessen wir eine hinzufuegen
2425 	if( 0==nRows )
2426 	{
2427 		pRows->Insert( new HTMLTableRow(nCols), pRows->Count() );
2428 		nRows = 1;
2429 		nCurRow = 1;
2430 	}
2431 
2432 	if( nFilledCols < nCols )
2433 	{
2434 		pColumns->DeleteAndDestroy( nFilledCols, nCols-nFilledCols );
2435 		for( i=0; i<nRows; i++ )
2436 			((*pRows)[i])->Shrink( nFilledCols );
2437 		nCols = nFilledCols;
2438 	}
2439 }
2440 
_MakeTable(SwTableBox * pBox)2441 void HTMLTable::_MakeTable( SwTableBox *pBox )
2442 {
2443 	SwTableLines& rLines = (pBox ? pBox->GetTabLines()
2444 								 : ((SwTable *)pSwTable)->GetTabLines() );
2445 
2446 	// jetzt geht's richtig los ...
2447 
2448 	for( sal_uInt16 i=0; i<nRows; i++ )
2449 	{
2450 		SwTableLine *pLine = MakeTableLine( pBox, i, 0, i+1, nCols );
2451 		if( pBox || i > 0 )
2452 			rLines.C40_INSERT( SwTableLine, pLine, rLines.Count() );
2453 	}
2454 }
2455 
2456 /* Wie werden Tabellen ausgerichtet?
2457 
2458 erste Zeile: ohne Absatz-Einzuege
2459 zweite Zeile: mit Absatz-Einzuegen
2460 
2461 ALIGN=			LEFT		  	RIGHT			CENTER		  	-
2462 -------------------------------------------------------------------------
2463 xxx bei Tabellen mit WIDTH=nn% ist die Prozent-Angabe von Bedeutung:
2464 xxx nn = 100        text::HoriOrientation::FULL       text::HoriOrientation::FULL       text::HoriOrientation::FULL       text::HoriOrientation::FULL %
2465 xxx             text::HoriOrientation::NONE       text::HoriOrientation::NONE       text::HoriOrientation::NONE %     text::HoriOrientation::NONE %
2466 xxx nn < 100        Rahmen F        Rahmen F        text::HoriOrientation::CENTER %   text::HoriOrientation::LEFT %
2467 xxx             Rahmen F        Rahmen F        text::HoriOrientation::CENTER %   text::HoriOrientation::NONE %
2468 
2469 bei Tabellen mit WIDTH=nn% ist die Prozent-Angabe von Bedeutung:
2470 nn = 100        text::HoriOrientation::LEFT       text::HoriOrientation::RIGHT      text::HoriOrientation::CENTER %   text::HoriOrientation::LEFT %
2471                 text::HoriOrientation::LEFT_AND   text::HoriOrientation::RIGHT      text::HoriOrientation::CENTER %   text::HoriOrientation::LEFT_AND %
2472 nn < 100        Rahmen F        Rahmen F        text::HoriOrientation::CENTER %   text::HoriOrientation::LEFT %
2473                 Rahmen F        Rahmen F        text::HoriOrientation::CENTER %   text::HoriOrientation::NONE %
2474 
2475 sonst die berechnete Breite w
2476 w = avail*      text::HoriOrientation::LEFT       text::HoriOrientation::RIGHT      text::HoriOrientation::CENTER     text::HoriOrientation::LEFT
2477                 HORI_LEDT_AND   text::HoriOrientation::RIGHT      text::HoriOrientation::CENTER     text::HoriOrientation::LEFT_AND
2478 w < avail       Rahmen L        Rahmen L        text::HoriOrientation::CENTER     text::HoriOrientation::LEFT
2479                 Rahmen L        Rahmen L        text::HoriOrientation::CENTER     text::HoriOrientation::NONE
2480 
2481 xxx *) wenn fuer die Tabelle keine Groesse angegeben wurde, wird immer
2482 xxx   text::HoriOrientation::FULL genommen
2483 
2484 */
2485 
MakeTable(SwTableBox * pBox,sal_uInt16 nAbsAvail,sal_uInt16 nRelAvail,sal_uInt16 nAbsLeftSpace,sal_uInt16 nAbsRightSpace,sal_uInt16 nInhAbsSpace)2486 void HTMLTable::MakeTable( SwTableBox *pBox, sal_uInt16 nAbsAvail,
2487 						   sal_uInt16 nRelAvail, sal_uInt16 nAbsLeftSpace,
2488 						   sal_uInt16 nAbsRightSpace, sal_uInt16 nInhAbsSpace )
2489 {
2490 	ASSERT( nRows>0 && nCols>0 && nCurRow==nRows,
2491 			"Wurde CloseTable nicht aufgerufen?" );
2492 
2493 	ASSERT( (pLayoutInfo==0) == (this==pTopTable),
2494 			"Top-Tabelle hat keine Layout-Info oder umgekehrt" );
2495 
2496 	if( this==pTopTable )
2497 	{
2498 		// Umrandung der Tabelle und aller in ihr enthaltenen berechnen
2499 		SetBorders();
2500 
2501 		// Schritt 1: Die benoetigten Layout-Strukturen werden angelegt
2502 		// (inklusive Tabellen in Tabellen).
2503 		CreateLayoutInfo();
2504 
2505 		// Schritt 2: Die minimalen und maximalen Spaltenbreiten werden
2506 		// berechnet (inklusive Tabellen in Tabellen). Da wir noch keine
2507 		// Boxen haben, arabeiten wir noch auf den Start-Nodes.
2508 		pLayoutInfo->AutoLayoutPass1();
2509 	}
2510 
2511 	// Schritt 3: Die tatsaechlichen Spaltenbreiten dieser Tabelle werden
2512 	// berechnet (nicht von Tabellen in Tabellen). Dies muss jetzt schon
2513 	// sein, damit wir entscheiden koennen ob Filler-Zellen benoetigt werden
2514 	// oder nicht (deshalb war auch Pass1 schon noetig).
2515 	pLayoutInfo->AutoLayoutPass2( nAbsAvail, nRelAvail, nAbsLeftSpace,
2516 								  nAbsRightSpace, nInhAbsSpace );
2517 
2518 	if( this!=pTopTable )
2519 	{
2520 		// die linke und rechte Umrandung der Tabelle kann jetzt endgueltig
2521 		// festgelegt werden
2522 		if( pLayoutInfo->GetRelRightFill() == 0 )
2523 		{
2524 			if( !bRightBorder )
2525 			{
2526 				// linke Umrandung von auesserer Tabelle uebernehmen
2527 				if( bInhRightBorder )
2528 				{
2529 					bRightBorder = sal_True;
2530 					aRightBorderLine = aInhRightBorderLine;
2531 				}
2532 			}
2533 			else
2534 			{
2535 				// Umrandung nur setzen, wenn es erlaubt ist
2536 				bRightBorder = bRightAlwd;
2537 			}
2538 		}
2539 
2540 		if( pLayoutInfo->GetRelLeftFill() == 0 &&
2541 			!((*pColumns)[0])->bLeftBorder &&
2542 			bInhLeftBorder )
2543 		{
2544 			// ggf. rechte Umrandung von auesserer Tabelle uebernehmen
2545 			((*pColumns)[0])->bLeftBorder = sal_True;
2546 			aLeftBorderLine = aInhLeftBorderLine;
2547 		}
2548 	}
2549 
2550 	// Fuer die Top-Table muss die Ausrichtung gesetzt werden
2551 	if( this==pTopTable )
2552 	{
2553         sal_Int16 eHoriOri;
2554 		if( bForceFrame )
2555 		{
2556 			// Die Tabelle soll in einen Rahmen und ist auch schmaler
2557 			// als der verfuegbare Platz und nicht 100% breit.
2558 			// Dann kommt sie in einen Rahmen
2559             eHoriOri = bPrcWidth ? text::HoriOrientation::FULL : text::HoriOrientation::LEFT;
2560 		}
2561 		else switch( eTableAdjust )
2562 		{
2563 			// Die Tabelle passt entweder auf die Seite, soll aber in keinen
2564 			// Rahmen oder sie ist Breiter als die Seite und soll deshalb
2565 			// in keinen Rahmen
2566 
2567 		case SVX_ADJUST_RIGHT:
2568 			// in rechtsbuendigen Tabellen kann nicht auf den rechten
2569 			// Rand Ruecksicht genommen werden
2570             eHoriOri = text::HoriOrientation::RIGHT;
2571 			break;
2572 		case SVX_ADJUST_CENTER:
2573 			// zentrierte Tabellen nehmen keine Ruecksicht auf Raender!
2574             eHoriOri = text::HoriOrientation::CENTER;
2575 			break;
2576 		case SVX_ADJUST_LEFT:
2577 		default:
2578 			// linksbuendige Tabellen nehmen nur auf den linken Rand
2579 			// Ruecksicht
2580             eHoriOri = nLeftMargin ? text::HoriOrientation::LEFT_AND_WIDTH : text::HoriOrientation::LEFT;
2581 			break;
2582 		}
2583 
2584 		// das Tabellenform holen und anpassen
2585 		SwFrmFmt *pFrmFmt = pSwTable->GetFrmFmt();
2586         pFrmFmt->SetFmtAttr( SwFmtHoriOrient(0,eHoriOri) );
2587         if( text::HoriOrientation::LEFT_AND_WIDTH==eHoriOri )
2588 		{
2589 			ASSERT( nLeftMargin || nRightMargin,
2590 					"Da gibt's wohl noch Reste von relativen Breiten" );
2591 
2592 			// The right margin will be ignored anyway.
2593 			SvxLRSpaceItem aLRItem( pSwTable->GetFrmFmt()->GetLRSpace() );
2594 			aLRItem.SetLeft( nLeftMargin );
2595 			aLRItem.SetRight( nRightMargin );
2596             pFrmFmt->SetFmtAttr( aLRItem );
2597 		}
2598 
2599         if( bPrcWidth && text::HoriOrientation::FULL!=eHoriOri )
2600 		{
2601 			pFrmFmt->LockModify();
2602 			SwFmtFrmSize aFrmSize( pFrmFmt->GetFrmSize() );
2603 			aFrmSize.SetWidthPercent( (sal_uInt8)nWidth );
2604             pFrmFmt->SetFmtAttr( aFrmSize );
2605 			pFrmFmt->UnlockModify();
2606 		}
2607 	}
2608 
2609 	// die Default Line- und Box-Formate holen
2610 	if( this==pTopTable )
2611 	{
2612 		// die erste Box merken und aus der ersten Zeile ausketten
2613 		SwTableLine *pLine1 = (pSwTable->GetTabLines())[0];
2614 		pBox1 = (pLine1->GetTabBoxes())[0];
2615 		pLine1->GetTabBoxes().Remove(0);
2616 
2617 		pLineFmt = (SwTableLineFmt*)pLine1->GetFrmFmt();
2618 		pBoxFmt = (SwTableBoxFmt*)pBox1->GetFrmFmt();
2619 	}
2620 	else
2621 	{
2622 		pLineFmt = (SwTableLineFmt*)pTopTable->pLineFmt;
2623 		pBoxFmt = (SwTableBoxFmt*)pTopTable->pBoxFmt;
2624 	}
2625 
2626 	// ggf. muessen fuer Tabellen in Tabellen "Filler"-Zellen eingefuegt
2627 	// werden
2628 	if( this != pTopTable &&
2629 		( pLayoutInfo->GetRelLeftFill() > 0  ||
2630 		  pLayoutInfo->GetRelRightFill() > 0 ) )
2631 	{
2632 		ASSERT( pBox, "kein TableBox fuer Tabelle in Tabelle" );
2633 
2634 		SwTableLines& rLines = pBox->GetTabLines();
2635 
2636 		// dazu brauchen wir erstmal ein eine neue Table-Line in der Box
2637 		SwTableLine *pLine =
2638 			new SwTableLine( pLineFrmFmtNoHeight ? pLineFrmFmtNoHeight
2639 												 : pLineFmt, 0, pBox );
2640 		rLines.C40_INSERT( SwTableLine, pLine, rLines.Count() );
2641 
2642 		// Sicherstellen, dass wie ein Format ohne Hoehe erwischt haben
2643 		if( !pLineFrmFmtNoHeight )
2644 		{
2645 			// sonst muessen wir die Hoehe aus dem Attribut entfernen
2646 			// und koennen uns das Format merken
2647 			pLineFrmFmtNoHeight = (SwTableLineFmt*)pLine->ClaimFrmFmt();
2648 
2649 			ResetLineFrmFmtAttrs( pLineFrmFmtNoHeight );
2650 		}
2651 
2652 		SwTableBoxes& rBoxes = pLine->GetTabBoxes();
2653 		SwTableBox *pNewBox;
2654 
2655 		// ggf. links eine Zelle einfuegen
2656 		if( pLayoutInfo->GetRelLeftFill() > 0 )
2657 		{
2658 			// pPrevStNd ist der Vorgaenger-Start-Node der Tabelle. Den
2659 			// "Filler"-Node fuegen wir einfach dahinter ein ...
2660 			pPrevStNd = pParser->InsertTableSection( pPrevStNd );
2661 
2662 			pNewBox = NewTableBox( pPrevStNd, pLine );
2663 			rBoxes.C40_INSERT( SwTableBox, pNewBox, rBoxes.Count() );
2664 			FixFillerFrameFmt( pNewBox, sal_False );
2665 			pLayoutInfo->SetLeftFillerBox( pNewBox );
2666 		}
2667 
2668 		// jetzt die Tabelle bearbeiten
2669 		pNewBox = new SwTableBox( pBoxFmt, 0, pLine );
2670 		rBoxes.C40_INSERT( SwTableBox, pNewBox, rBoxes.Count() );
2671 
2672 		SwFrmFmt *pFrmFmt = pNewBox->ClaimFrmFmt();
2673         pFrmFmt->ResetFmtAttr( RES_BOX );
2674         pFrmFmt->ResetFmtAttr( RES_BACKGROUND );
2675         pFrmFmt->ResetFmtAttr( RES_VERT_ORIENT );
2676         pFrmFmt->ResetFmtAttr( RES_BOXATR_FORMAT );
2677 
2678 
2679 		_MakeTable( pNewBox );
2680 
2681 		// und noch ggf. rechts eine Zelle einfuegen
2682 		if( pLayoutInfo->GetRelRightFill() > 0 )
2683 		{
2684 			const SwStartNode *pStNd =
2685 				GetPrevBoxStartNode( USHRT_MAX, USHRT_MAX );
2686 			pStNd = pParser->InsertTableSection( pStNd );
2687 
2688 			pNewBox = NewTableBox( pStNd, pLine );
2689 			rBoxes.C40_INSERT( SwTableBox, pNewBox, rBoxes.Count() );
2690 
2691 			FixFillerFrameFmt( pNewBox, sal_True );
2692 			pLayoutInfo->SetRightFillerBox( pNewBox );
2693 		}
2694 	}
2695 	else
2696 	{
2697 		_MakeTable( pBox );
2698 	}
2699 
2700 	// zum Schluss fuehren wir noch eine Garbage-Collection fuer die
2701 	// Top-Level-Tabelle durch
2702 	if( this==pTopTable )
2703 	{
2704 		if( 1==nRows && nHeight && 1==pSwTable->GetTabLines().Count() )
2705 		{
2706 			// Hoehe einer einzeiligen Tabelle als Mindesthoehe der
2707 			// Zeile setzen. (War mal fixe Hoehe, aber das gibt manchmal
2708 			// Probleme (fix #34972#) und ist auch nicht Netscape 4.0
2709 			// konform
2710 			nHeight = pParser->ToTwips( nHeight );
2711 			if( nHeight < MINLAY )
2712 				nHeight = MINLAY;
2713 
2714 			(pSwTable->GetTabLines())[0]->ClaimFrmFmt();
2715 			(pSwTable->GetTabLines())[0]->GetFrmFmt()
2716                 ->SetFmtAttr( SwFmtFrmSize( ATT_MIN_SIZE, 0, nHeight ) );
2717 		}
2718 
2719 		if( GetBGBrush() )
2720             pSwTable->GetFrmFmt()->SetFmtAttr( *GetBGBrush() );
2721 
2722         ((SwTable *)pSwTable)->SetRowsToRepeat( static_cast< sal_uInt16 >(nHeadlineRepeat) );
2723 		((SwTable *)pSwTable)->GCLines();
2724 
2725 		sal_Bool bIsInFlyFrame = pContext && pContext->GetFrmFmt();
2726 		if( bIsInFlyFrame && !nWidth )
2727 		{
2728 			SvxAdjust eTblAdjust = GetTableAdjust(sal_False);
2729 			if( eTblAdjust != SVX_ADJUST_LEFT &&
2730 				eTblAdjust != SVX_ADJUST_RIGHT )
2731 			{
2732 				// Wenn eine Tabelle ohne Breitenangabe nicht links oder
2733 				// rechts umflossen werden soll, dann stacken wir sie
2734 				// in einem Rahmen mit 100%-Breite, damit ihre Groesse
2735 				// angepasst wird. Der Rahmen darf nicht angepasst werden.
2736 				ASSERT( HasToFly(), "Warum ist die Tabelle in einem Rahmen?" );
2737 				sal_uInt32 nMin = pLayoutInfo->GetMin();
2738 				if( nMin > USHRT_MAX )
2739 					nMin = USHRT_MAX;
2740 				SwFmtFrmSize aFlyFrmSize( ATT_VAR_SIZE, (SwTwips)nMin, MINLAY );
2741 				aFlyFrmSize.SetWidthPercent( 100 );
2742                 pContext->GetFrmFmt()->SetFmtAttr( aFlyFrmSize );
2743 				bIsInFlyFrame = sal_False;
2744 			}
2745 			else
2746 			{
2747 				// Links und rechts ausgerichtete Tabellen ohne Breite
2748 				// duerfen leider nicht in der Breite angepasst werden, denn
2749 				// sie wuerden nur schrumpfen aber nie wachsen.
2750 				pLayoutInfo->SetMustNotRecalc( sal_True );
2751 				if( pContext->GetFrmFmt()->GetAnchor().GetCntntAnchor()
2752 					->nNode.GetNode().FindTableNode() )
2753 				{
2754 					sal_uInt32 nMax = pLayoutInfo->GetMax();
2755 					if( nMax > USHRT_MAX )
2756 						nMax = USHRT_MAX;
2757 					SwFmtFrmSize aFlyFrmSize( ATT_VAR_SIZE, (SwTwips)nMax, MINLAY );
2758                     pContext->GetFrmFmt()->SetFmtAttr( aFlyFrmSize );
2759 					bIsInFlyFrame = sal_False;
2760 				}
2761 				else
2762 				{
2763 					pLayoutInfo->SetMustNotResize( sal_True );
2764 				}
2765 			}
2766 		}
2767 		pLayoutInfo->SetMayBeInFlyFrame( bIsInFlyFrame );
2768 
2769 		// Nur Tabellen mit relativer Breite oder ohne Breite muessen
2770 		// angepasst werden.
2771 		pLayoutInfo->SetMustResize( bPrcWidth || !nWidth );
2772 
2773 		pLayoutInfo->SetWidths();
2774 
2775 		((SwTable *)pSwTable)->SetHTMLTableLayout( pLayoutInfo );
2776 
2777 		if( pResizeDrawObjs )
2778 		{
2779 			sal_uInt16 nCount = pResizeDrawObjs->Count();
2780 			for( sal_uInt16 i=0; i<nCount; i++ )
2781 			{
2782 				SdrObject *pObj = (*pResizeDrawObjs)[i];
2783 				sal_uInt16 nRow = (*pDrawObjPrcWidths)[3*i];
2784 				sal_uInt16 nCol = (*pDrawObjPrcWidths)[3*i+1];
2785 				sal_uInt8 nPrcWidth = (sal_uInt8)(*pDrawObjPrcWidths)[3*i+2];
2786 
2787 				SwHTMLTableLayoutCell *pLayoutCell =
2788 					pLayoutInfo->GetCell( nRow, nCol );
2789 				sal_uInt16 nColSpan = pLayoutCell->GetColSpan();
2790 
2791 				sal_uInt16 nWidth2, nDummy;
2792 				pLayoutInfo->GetAvail( nCol, nColSpan, nWidth2, nDummy );
2793                 nWidth2 = nWidth2 - pLayoutInfo->GetLeftCellSpace( nCol, nColSpan );
2794                 nWidth2 = nWidth2 - pLayoutInfo->GetRightCellSpace( nCol, nColSpan );
2795                 nWidth2 = static_cast< sal_uInt16 >(((long)nWidth * nPrcWidth) / 100);
2796 
2797 				pParser->ResizeDrawObject( pObj, nWidth2 );
2798 			}
2799 		}
2800 	}
2801 }
2802 
SetTable(const SwStartNode * pStNd,_HTMLTableContext * pCntxt,sal_uInt16 nLeft,sal_uInt16 nRight,const SwTable * pSwTab,sal_Bool bFrcFrame)2803 void HTMLTable::SetTable( const SwStartNode *pStNd, _HTMLTableContext *pCntxt,
2804 						  sal_uInt16 nLeft, sal_uInt16 nRight,
2805 						  const SwTable *pSwTab, sal_Bool bFrcFrame )
2806 {
2807 	pPrevStNd = pStNd;
2808 	pSwTable = pSwTab;
2809 	pContext = pCntxt;
2810 
2811 	nLeftMargin = nLeft;
2812 	nRightMargin = nRight;
2813 
2814 	bForceFrame = bFrcFrame;
2815 }
2816 
RegisterDrawObject(SdrObject * pObj,sal_uInt8 nPrcWidth)2817 void HTMLTable::RegisterDrawObject( SdrObject *pObj, sal_uInt8 nPrcWidth )
2818 {
2819 	if( !pResizeDrawObjs )
2820 		pResizeDrawObjs = new SdrObjects;
2821 	pResizeDrawObjs->C40_INSERT( SdrObject, pObj, pResizeDrawObjs->Count() );
2822 
2823 	if( !pDrawObjPrcWidths )
2824 		pDrawObjPrcWidths = new SvUShorts;
2825 	pDrawObjPrcWidths->Insert( nCurRow, pDrawObjPrcWidths->Count() );
2826 	pDrawObjPrcWidths->Insert( nCurCol, pDrawObjPrcWidths->Count() );
2827 	pDrawObjPrcWidths->Insert( (sal_uInt16)nPrcWidth, pDrawObjPrcWidths->Count() );
2828 }
2829 
MakeParentContents()2830 void HTMLTable::MakeParentContents()
2831 {
2832 	if( !GetContext() && !HasParentSection() )
2833 	{
2834 		SetParentContents(
2835 			pParser->InsertTableContents( GetIsParentHeader() ) );
2836 
2837 		SetHasParentSection( sal_True );
2838 	}
2839 }
2840 
~_HTMLTableContext()2841 _HTMLTableContext::~_HTMLTableContext()
2842 {
2843 	delete pPos;
2844 }
2845 
SavePREListingXMP(SwHTMLParser & rParser)2846 void _HTMLTableContext::SavePREListingXMP( SwHTMLParser& rParser )
2847 {
2848 	bRestartPRE = rParser.IsReadPRE();
2849 	bRestartXMP = rParser.IsReadXMP();
2850 	bRestartListing = rParser.IsReadListing();
2851 	rParser.FinishPREListingXMP();
2852 }
2853 
RestorePREListingXMP(SwHTMLParser & rParser)2854 void _HTMLTableContext::RestorePREListingXMP( SwHTMLParser& rParser )
2855 {
2856 	rParser.FinishPREListingXMP();
2857 
2858 	if( bRestartPRE )
2859 		rParser.StartPRE();
2860 
2861 	if( bRestartXMP )
2862 		rParser.StartXMP();
2863 
2864 	if( bRestartListing )
2865 		rParser.StartListing();
2866 }
2867 
2868 
InsertTableSection(const SwStartNode * pPrevStNd)2869 const SwStartNode *SwHTMLParser::InsertTableSection
2870 	( const SwStartNode *pPrevStNd )
2871 {
2872 	ASSERT( pPrevStNd, "Start-Node ist NULL" );
2873 
2874 	pCSS1Parser->SetTDTagStyles();
2875 	SwTxtFmtColl *pColl = pCSS1Parser->GetTxtCollFromPool( RES_POOLCOLL_TABLE );
2876 
2877 	const SwStartNode *pStNd;
2878 	if( pTable && pTable->bFirstCell )
2879 	{
2880         SwNode *const pNd = & pPam->GetPoint()->nNode.GetNode();
2881 		pNd->GetTxtNode()->ChgFmtColl( pColl );
2882 		pStNd = pNd->FindTableBoxStartNode();
2883 		pTable->bFirstCell = sal_False;
2884 	}
2885 	else
2886 	{
2887 		const SwNode* pNd;
2888 		if( pPrevStNd->IsTableNode() )
2889 			pNd = pPrevStNd;
2890 		else
2891 			pNd = pPrevStNd->EndOfSectionNode();
2892 		SwNodeIndex nIdx( *pNd, 1 );
2893 		pStNd = pDoc->GetNodes().MakeTextSection( nIdx, SwTableBoxStartNode,
2894 												  pColl );
2895 		pTable->IncBoxCount();
2896 	}
2897 
2898 	SwCntntNode *pCNd = pDoc->GetNodes()[pStNd->GetIndex()+1] ->GetCntntNode();
2899     SvxFontHeightItem aFontHeight( 40, 100, RES_CHRATR_FONTSIZE );
2900 	pCNd->SetAttr( aFontHeight );
2901 	aFontHeight.SetWhich( RES_CHRATR_CJK_FONTSIZE );
2902 	pCNd->SetAttr( aFontHeight );
2903 	aFontHeight.SetWhich( RES_CHRATR_CTL_FONTSIZE );
2904 	pCNd->SetAttr( aFontHeight );
2905 
2906 	return pStNd;
2907 }
2908 
InsertTableSection(sal_uInt16 nPoolId)2909 const SwStartNode *SwHTMLParser::InsertTableSection( sal_uInt16 nPoolId )
2910 {
2911 	switch( nPoolId )
2912 	{
2913 	case RES_POOLCOLL_TABLE_HDLN:
2914 		pCSS1Parser->SetTHTagStyles();
2915 		break;
2916 	case RES_POOLCOLL_TABLE:
2917 		pCSS1Parser->SetTDTagStyles();
2918 		break;
2919 	}
2920 
2921 	SwTxtFmtColl *pColl = pCSS1Parser->GetTxtCollFromPool( nPoolId );
2922 
2923     SwNode *const pNd = & pPam->GetPoint()->nNode.GetNode();
2924 	const SwStartNode *pStNd;
2925 	if( pTable && pTable->bFirstCell )
2926 	{
2927 		pNd->GetTxtNode()->ChgFmtColl( pColl );
2928 		pTable->bFirstCell = sal_False;
2929 		pStNd = pNd->FindTableBoxStartNode();
2930 	}
2931 	else
2932 	{
2933 		SwTableNode *pTblNd = pNd->FindTableNode();
2934         if( pTblNd->GetTable().GetHTMLTableLayout() )
2935         { // if there is already a HTMTableLayout, this table is already finished
2936           // and we have to look for the right table in the environment
2937             SwTableNode *pOutTbl = pTblNd;
2938             do {
2939                 pTblNd = pOutTbl;
2940                 pOutTbl = pOutTbl->StartOfSectionNode()->FindTableNode();
2941             } while( pOutTbl && pTblNd->GetTable().GetHTMLTableLayout() );
2942         }
2943 		SwNodeIndex aIdx( *pTblNd->EndOfSectionNode() );
2944 		pStNd = pDoc->GetNodes().MakeTextSection( aIdx, SwTableBoxStartNode,
2945 												  pColl );
2946 
2947 		pPam->GetPoint()->nNode = pStNd->GetIndex() + 1;
2948 		SwTxtNode *pTxtNd = pPam->GetPoint()->nNode.GetNode().GetTxtNode();
2949 		pPam->GetPoint()->nContent.Assign( pTxtNd, 0 );
2950 		pTable->IncBoxCount();
2951 	}
2952 
2953 	return pStNd;
2954 }
2955 
InsertTempTableCaptionSection()2956 SwStartNode *SwHTMLParser::InsertTempTableCaptionSection()
2957 {
2958 	SwTxtFmtColl *pColl = pCSS1Parser->GetTxtCollFromPool( RES_POOLCOLL_TEXT );
2959 	SwNodeIndex& rIdx = pPam->GetPoint()->nNode;
2960 	rIdx = pDoc->GetNodes().GetEndOfExtras();
2961 	SwStartNode *pStNd = pDoc->GetNodes().MakeTextSection( rIdx,
2962 										  SwNormalStartNode, pColl );
2963 
2964 	rIdx = pStNd->GetIndex() + 1;
2965 	pPam->GetPoint()->nContent.Assign( rIdx.GetNode().GetTxtNode(), 0 );
2966 
2967 	return pStNd;
2968 }
2969 
2970 
StripTrailingLF()2971 xub_StrLen SwHTMLParser::StripTrailingLF()
2972 {
2973 	xub_StrLen nStripped = 0;
2974 
2975 	xub_StrLen nLen = pPam->GetPoint()->nContent.GetIndex();
2976 	if( nLen )
2977 	{
2978 		SwTxtNode* pTxtNd = pPam->GetPoint()->nNode.GetNode().GetTxtNode();
2979 		// vorsicht, wenn Kommentare nicht ueberlesen werden!!!
2980 		if( pTxtNd )
2981 		{
2982 			xub_StrLen nPos = nLen;
2983 			xub_StrLen nLFCount = 0;
2984 			while( nPos && '\x0a' == (pTxtNd->GetTxt()).GetChar(--nPos) )
2985 				nLFCount++;
2986 
2987 			if( nLFCount )
2988 			{
2989 // MIB 6.6.97: Warum sollte man bei leeren Absaetzen nur ein LF loeschen?
2990 // Das stimmt doch irgendwie nicht ...
2991 //				if( nLFCount == nLen )
2992 //				{
2993 //					// nur Lfs, dann nur ein LF loeschen
2994 //					nLFCount = 1;
2995 //				}
2996 //				else if( nLFCount > 2 )
2997 				if( nLFCount > 2 )
2998 				{
2999 					// Bei Netscape entspricht ein Absatz-Ende zwei LFs
3000 					// (mit einem kommt man in die naechste Zeile, das
3001 					// zweite erzeugt eine Leerzeile) Diesen Abstand
3002 					// erreichen wie aber schon mit dem unteren
3003 					// Absatz-Abstand. Wenn nach den <BR> ein neuer
3004 					// Absatz aufgemacht wird, wird das Maximum des Abstands,
3005 					// der sich aus den BR und dem P ergibt genommen.
3006 					// Deshalb muessen wir 2 bzw. alle bei weniger
3007 					// als zweien loeschen
3008 					nLFCount = 2;
3009 				}
3010 
3011 				nPos = nLen - nLFCount;
3012 				SwIndex nIdx( pTxtNd, nPos );
3013                 pTxtNd->EraseText( nIdx, nLFCount );
3014 				nStripped = nLFCount;
3015 			}
3016 		}
3017 	}
3018 
3019 	return nStripped;
3020 }
3021 
CreateBrushItem(const Color * pColor,const String & rImageURL,const String & rStyle,const String & rId,const String & rClass)3022 SvxBrushItem* SwHTMLParser::CreateBrushItem( const Color *pColor,
3023 											 const String& rImageURL,
3024 											 const String& rStyle,
3025 											 const String& rId,
3026 											 const String& rClass )
3027 {
3028 	SvxBrushItem *pBrushItem = 0;
3029 
3030 	if( rStyle.Len() || rId.Len() || rClass.Len() )
3031 	{
3032 		SfxItemSet aItemSet( pDoc->GetAttrPool(), RES_BACKGROUND,
3033 												  RES_BACKGROUND );
3034 		SvxCSS1PropertyInfo aPropInfo;
3035 
3036 		if( rClass.Len() )
3037 		{
3038 			String aClass( rClass );
3039 			SwCSS1Parser::GetScriptFromClass( aClass );
3040 			SvxCSS1MapEntry *pClass = pCSS1Parser->GetClass( aClass );
3041 			if( pClass )
3042 				aItemSet.Put( pClass->GetItemSet() );
3043 		}
3044 
3045 		if( rId.Len() )
3046 		{
3047 			SvxCSS1MapEntry *pId = pCSS1Parser->GetId( rId );
3048 			if( pId )
3049 				aItemSet.Put( pId->GetItemSet() );
3050 		}
3051 
3052 		pCSS1Parser->ParseStyleOption( rStyle, aItemSet, aPropInfo );
3053 		const SfxPoolItem *pItem = 0;
3054 		if( SFX_ITEM_SET == aItemSet.GetItemState( RES_BACKGROUND, sal_False,
3055 												   &pItem ) )
3056 		{
3057 			pBrushItem = new SvxBrushItem( *((const SvxBrushItem *)pItem) );
3058 		}
3059 	}
3060 
3061 	if( !pBrushItem && (pColor || rImageURL.Len()) )
3062 	{
3063         pBrushItem = new SvxBrushItem(RES_BACKGROUND);
3064 
3065 		if( pColor )
3066 			pBrushItem->SetColor(*pColor);
3067 
3068 		if( rImageURL.Len() )
3069 		{
3070             pBrushItem->SetGraphicLink( URIHelper::SmartRel2Abs( INetURLObject(sBaseURL), rImageURL, Link(), false) );
3071 			pBrushItem->SetGraphicPos( GPOS_TILED );
3072 		}
3073 	}
3074 
3075 	return pBrushItem;
3076 }
3077 
3078 
3079 class _SectionSaveStruct : public SwPendingStackData
3080 {
3081 	sal_uInt16 nBaseFontStMinSave, nFontStMinSave, nFontStHeadStartSave;
3082 	sal_uInt16 nDefListDeepSave, nContextStMinSave, nContextStAttrMinSave;
3083 
3084 public:
3085 
3086 	HTMLTable *pTable;
3087 
3088 	_SectionSaveStruct( SwHTMLParser& rParser );
3089 	virtual ~_SectionSaveStruct();
3090 
GetContextStAttrMin() const3091 	sal_uInt16 GetContextStAttrMin() const { return nContextStAttrMinSave; }
3092 
3093 	void Restore( SwHTMLParser& rParser );
3094 };
3095 
_SectionSaveStruct(SwHTMLParser & rParser)3096 _SectionSaveStruct::_SectionSaveStruct( SwHTMLParser& rParser ) :
3097 	nBaseFontStMinSave(0), nFontStMinSave(0), nFontStHeadStartSave(0),
3098 	nDefListDeepSave(0), nContextStMinSave(0), nContextStAttrMinSave(0),
3099 	pTable( 0 )
3100 {
3101 	// Font-Stacks einfrieren
3102 	nBaseFontStMinSave = rParser.nBaseFontStMin;
3103 	rParser.nBaseFontStMin = rParser.aBaseFontStack.Count();
3104 
3105 	nFontStMinSave = rParser.nFontStMin;
3106 	nFontStHeadStartSave = rParser.nFontStHeadStart;
3107 	rParser.nFontStMin = rParser.aFontStack.Count();
3108 
3109 	// Kontext-Stack einfrieren
3110 	nContextStMinSave = rParser.nContextStMin;
3111 	nContextStAttrMinSave = rParser.nContextStAttrMin;
3112 	rParser.nContextStMin = rParser.aContexts.Count();
3113 	rParser.nContextStAttrMin = rParser.nContextStMin;
3114 
3115 	// und noch ein paar Zaehler retten
3116 	nDefListDeepSave = rParser.nDefListDeep;
3117 	rParser.nDefListDeep = 0;
3118 }
3119 
~_SectionSaveStruct()3120 _SectionSaveStruct::~_SectionSaveStruct()
3121 {}
3122 
Restore(SwHTMLParser & rParser)3123 void _SectionSaveStruct::Restore( SwHTMLParser& rParser )
3124 {
3125 	// Font-Stacks wieder auftauen
3126 	sal_uInt16 nMin = rParser.nBaseFontStMin;
3127 	if( rParser.aBaseFontStack.Count() > nMin )
3128 		rParser.aBaseFontStack.Remove( nMin,
3129 								rParser.aBaseFontStack.Count() - nMin );
3130 	rParser.nBaseFontStMin = nBaseFontStMinSave;
3131 
3132 
3133 	nMin = rParser.nFontStMin;
3134 	if( rParser.aFontStack.Count() > nMin )
3135 		rParser.aFontStack.Remove( nMin,
3136 							rParser.aFontStack.Count() - nMin );
3137 	rParser.nFontStMin = nFontStMinSave;
3138 	rParser.nFontStHeadStart = nFontStHeadStartSave;
3139 
3140 	// Der Kontext-Stack muss schon aufgeraeumt sein!
3141 	ASSERT( rParser.aContexts.Count() == rParser.nContextStMin &&
3142 			rParser.aContexts.Count() == rParser.nContextStAttrMin,
3143 			"Der Kontext-Stack wurde nicht aufgeraeumt" );
3144 	rParser.nContextStMin = nContextStMinSave;
3145 	rParser.nContextStAttrMin = nContextStAttrMinSave;
3146 
3147 	// und noch ein paar Zaehler rekonstruieren
3148 	rParser.nDefListDeep = nDefListDeepSave;
3149 
3150 	// und ein paar Flags zuruecksetzen
3151 	rParser.bNoParSpace = sal_False;
3152 	rParser.nOpenParaToken = 0;
3153 
3154 	if( rParser.aParaAttrs.Count() )
3155 		rParser.aParaAttrs.Remove( 0, rParser.aParaAttrs.Count() );
3156 }
3157 
3158 
3159 class _CellSaveStruct : public _SectionSaveStruct
3160 {
3161 	String aStyle, aId, aClass, aLang, aDir;
3162 	String aBGImage;
3163 	Color aBGColor;
3164 
3165 	HTMLTableCnts* pCnts;			// Liste aller Inhalte
3166 	HTMLTableCnts* pCurrCnts;	// der aktuelle Inhalt oder 0
3167 	SwNodeIndex *pNoBreakEndParaIdx;// Absatz-Index eines </NOBR>
3168 
3169 	double nValue;
3170 
3171 	sal_uInt32 nNumFmt;
3172 
3173 	sal_uInt16 nRowSpan, nColSpan, nWidth, nHeight;
3174 	xub_StrLen nNoBreakEndCntntPos;		// Zeichen-Index eines </NOBR>
3175 
3176 	SvxAdjust eAdjust;
3177     sal_Int16 eVertOri;
3178 
3179 	sal_Bool bHead : 1;
3180 	sal_Bool bPrcWidth : 1;
3181 	sal_Bool bHasNumFmt : 1;
3182 	sal_Bool bHasValue : 1;
3183 	sal_Bool bBGColor : 1;
3184 	sal_Bool bNoWrap : 1;		// NOWRAP-Option
3185 	sal_Bool bNoBreak : 1; 		// NOBREAK-Tag
3186 
3187 public:
3188 
3189 	_CellSaveStruct( SwHTMLParser& rParser, HTMLTable *pCurTable, sal_Bool bHd,
3190 					 sal_Bool bReadOpt );
3191 
3192 	virtual ~_CellSaveStruct();
3193 
3194 	void AddContents( HTMLTableCnts *pNewCnts );
GetFirstContents()3195 	HTMLTableCnts *GetFirstContents() { return pCnts; }
3196 
ClearIsInSection()3197 	void ClearIsInSection() { pCurrCnts = 0; }
IsInSection() const3198 	sal_Bool IsInSection() const { return pCurrCnts!=0; }
GetCurrContents() const3199 	HTMLTableCnts *GetCurrContents() const { return pCurrCnts; }
3200 
3201 	void InsertCell( SwHTMLParser& rParser, HTMLTable *pCurTable );
3202 
IsHeaderCell() const3203 	sal_Bool IsHeaderCell() const { return bHead; }
3204 
3205 	void StartNoBreak( const SwPosition& rPos );
3206 	void EndNoBreak( const SwPosition& rPos );
3207 	void CheckNoBreak( const SwPosition& rPos, SwDoc *pDoc );
3208 };
3209 
3210 
_CellSaveStruct(SwHTMLParser & rParser,HTMLTable * pCurTable,sal_Bool bHd,sal_Bool bReadOpt)3211 _CellSaveStruct::_CellSaveStruct( SwHTMLParser& rParser, HTMLTable *pCurTable,
3212 								  sal_Bool bHd, sal_Bool bReadOpt ) :
3213 	_SectionSaveStruct( rParser ),
3214 	pCnts( 0 ),
3215 	pCurrCnts( 0 ),
3216 	pNoBreakEndParaIdx( 0 ),
3217 	nValue( 0.0 ),
3218 	nNumFmt( 0 ),
3219 	nRowSpan( 1 ),
3220 	nColSpan( 1 ),
3221 	nWidth( 0 ),
3222 	nHeight( 0 ),
3223 	nNoBreakEndCntntPos( 0 ),
3224 	eAdjust( pCurTable->GetInheritedAdjust() ),
3225 	eVertOri( pCurTable->GetInheritedVertOri() ),
3226 	bHead( bHd ),
3227 	bPrcWidth( sal_False ),
3228 	bHasNumFmt( sal_False ),
3229 	bHasValue( sal_False ),
3230 	bBGColor( sal_False ),
3231 	bNoWrap( sal_False ),
3232 	bNoBreak( sal_False )
3233 {
3234 	String aNumFmt, aValue;
3235 
3236 	if( bReadOpt )
3237 	{
3238 		const HTMLOptions *pOptions = rParser.GetOptions();
3239 		for( sal_uInt16 i = pOptions->Count(); i; )
3240 		{
3241 			const HTMLOption *pOption = (*pOptions)[--i];
3242 			switch( pOption->GetToken() )
3243 			{
3244 			case HTML_O_ID:
3245 				aId = pOption->GetString();
3246 				break;
3247 			case HTML_O_COLSPAN:
3248 				nColSpan = (sal_uInt16)pOption->GetNumber();
3249 				break;
3250 			case HTML_O_ROWSPAN:
3251 				nRowSpan = (sal_uInt16)pOption->GetNumber();
3252 				break;
3253 			case HTML_O_ALIGN:
3254 				eAdjust = (SvxAdjust)pOption->GetEnum(
3255                                         aHTMLPAlignTable, static_cast< sal_uInt16 >(eAdjust) );
3256 				break;
3257 			case HTML_O_VALIGN:
3258                 eVertOri = pOption->GetEnum(
3259                                         aHTMLTblVAlignTable, eVertOri );
3260 				break;
3261 			case HTML_O_WIDTH:
3262 				nWidth = (sal_uInt16)pOption->GetNumber();	// nur fuer Netscape
3263 				bPrcWidth = (pOption->GetString().Search('%') != STRING_NOTFOUND);
3264 				if( bPrcWidth && nWidth>100 )
3265 					nWidth = 100;
3266 				break;
3267 			case HTML_O_HEIGHT:
3268 				nHeight = (sal_uInt16)pOption->GetNumber();	// nur fuer Netscape
3269 				if( pOption->GetString().Search('%') != STRING_NOTFOUND)
3270 					nHeight = 0;	// keine %-Angaben beruecksichtigen
3271 				break;
3272 			case HTML_O_BGCOLOR:
3273 				// Leere BGCOLOR bei <TABLE>, <TR> und <TD>/<TH> wie Netscape
3274 				// ignorieren, bei allen anderen Tags *wirklich* nicht.
3275 				if( pOption->GetString().Len() )
3276 				{
3277 					pOption->GetColor( aBGColor );
3278 					bBGColor = sal_True;
3279 				}
3280 				break;
3281 			case HTML_O_BACKGROUND:
3282 				aBGImage = pOption->GetString();
3283 				break;
3284 			case HTML_O_STYLE:
3285 				aStyle = pOption->GetString();
3286 				break;
3287 			case HTML_O_CLASS:
3288 				aClass = pOption->GetString();
3289 				break;
3290 			case HTML_O_LANG:
3291 				aLang = pOption->GetString();
3292 				break;
3293 			case HTML_O_DIR:
3294 				aDir = pOption->GetString();
3295 				break;
3296 			case HTML_O_SDNUM:
3297 				aNumFmt = pOption->GetString();
3298 				bHasNumFmt = sal_True;
3299 				break;
3300 			case HTML_O_SDVAL:
3301 				bHasValue = sal_True;
3302 				aValue = pOption->GetString();
3303 				break;
3304 			case HTML_O_NOWRAP:
3305 				bNoWrap = sal_True;
3306 				break;
3307 			}
3308 		}
3309 
3310 		if( aId.Len() )
3311 			rParser.InsertBookmark( aId );
3312 	}
3313 
3314 	if( bHasNumFmt )
3315 	{
3316 		LanguageType eLang;
3317 		nValue = rParser.GetTableDataOptionsValNum(
3318 							nNumFmt, eLang, aValue, aNumFmt,
3319 							*rParser.pDoc->GetNumberFormatter() );
3320 	}
3321 
3322     // einen neuen Kontext anlegen, aber das drawing::Alignment-Attribut
3323 	// nicht dort verankern, weil es noch gar keine Section gibt, in der
3324 	// es gibt.
3325 	sal_uInt16 nToken, nColl;
3326 	if( bHead )
3327 	{
3328 		nToken = HTML_TABLEHEADER_ON;
3329 		nColl = RES_POOLCOLL_TABLE_HDLN;
3330 	}
3331 	else
3332 	{
3333 		nToken = HTML_TABLEDATA_ON;
3334 		nColl = RES_POOLCOLL_TABLE;
3335 	}
3336 	_HTMLAttrContext *pCntxt = new _HTMLAttrContext( nToken, nColl, aEmptyStr, sal_True );
3337 	if( SVX_ADJUST_END != eAdjust )
3338         rParser.InsertAttr( &rParser.aAttrTab.pAdjust, SvxAdjustItem(eAdjust, RES_PARATR_ADJUST),
3339 							pCntxt );
3340 
3341 	if( rParser.HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) )
3342 	{
3343 		SfxItemSet aItemSet( rParser.pDoc->GetAttrPool(),
3344 							 rParser.pCSS1Parser->GetWhichMap() );
3345 		SvxCSS1PropertyInfo aPropInfo;
3346 
3347 		if( rParser.ParseStyleOptions( aStyle, aId, aClass, aItemSet,
3348 									   aPropInfo, &aLang, &aDir ) )
3349 			rParser.InsertAttrs( aItemSet, aPropInfo, pCntxt );
3350 	}
3351 
3352 	rParser.SplitPREListingXMP( pCntxt );
3353 
3354 	rParser.PushContext( pCntxt );
3355 }
3356 
~_CellSaveStruct()3357 _CellSaveStruct::~_CellSaveStruct()
3358 {
3359 	delete pNoBreakEndParaIdx;
3360 }
3361 
AddContents(HTMLTableCnts * pNewCnts)3362 void _CellSaveStruct::AddContents( HTMLTableCnts *pNewCnts )
3363 {
3364 	if( pCnts )
3365 		pCnts->Add( pNewCnts );
3366 	else
3367 		pCnts = pNewCnts;
3368 
3369 	pCurrCnts = pNewCnts;
3370 }
3371 
InsertCell(SwHTMLParser & rParser,HTMLTable * pCurTable)3372 void _CellSaveStruct::InsertCell( SwHTMLParser& rParser,
3373 								  HTMLTable *pCurTable )
3374 {
3375 #ifdef DBG_UTIL
3376 	// Die Attribute muessen schon beim Auefrauemen des Kontext-Stacks
3377 	// entfernt worden sein, sonst ist etwas schiefgelaufen. Das
3378 	// Checken wir mal eben ...
3379 	// MIB 8.1.98: Wenn ausserhalb einer Zelle Attribute geoeffnet
3380 	// wurden stehen diese noch in der Attribut-Tabelle und werden erst
3381 	// ganz zum Schluss durch die CleanContext-Aufrufe in BuildTable
3382 	// geloescht. Damit es in diesem Fall keine Asserts gibt findet dann
3383 	// keine Ueberpruefung statt. Erkennen tut man diesen Fall an
3384 	// nContextStAttrMin: Der gemerkte Wert nContextStAttrMinSave ist der
3385 	// Wert, den nContextStAttrMin beim Start der Tabelle hatte. Und
3386 	// der aktuelle Wert von nContextStAttrMin entspricht der Anzahl der
3387 	// Kontexte, die beim Start der Zelle vorgefunden wurden. Sind beide
3388 	// Werte unterschiedlich, wurden ausserhalb der Zelle Kontexte
3389 	// angelegt und wir ueberpruefen nichts.
3390 
3391 	if( rParser.nContextStAttrMin == GetContextStAttrMin() )
3392 	{
3393 		_HTMLAttr** pTbl = (_HTMLAttr**)&rParser.aAttrTab;
3394 
3395 		for( sal_uInt16 nCnt = sizeof( _HTMLAttrTable ) / sizeof( _HTMLAttr* );
3396 			nCnt--; ++pTbl )
3397 		{
3398 			ASSERT( !*pTbl, "Die Attribut-Tabelle ist nicht leer" );
3399 		}
3400 	}
3401 #endif
3402 
3403 	// jetzt muessen wir noch die Zelle an der aktuellen Position einfuegen
3404 	SvxBrushItem *pBrushItem =
3405 		rParser.CreateBrushItem( bBGColor ? &aBGColor : 0, aBGImage,
3406 								 aStyle, aId, aClass );
3407 	pCurTable->InsertCell( pCnts, nRowSpan, nColSpan, nWidth,
3408 						   bPrcWidth, nHeight, eVertOri, pBrushItem,
3409 						   bHasNumFmt, nNumFmt, bHasValue, nValue,
3410 						   bNoWrap );
3411 	Restore( rParser );
3412 }
3413 
StartNoBreak(const SwPosition & rPos)3414 void _CellSaveStruct::StartNoBreak( const SwPosition& rPos )
3415 {
3416 	if( !pCnts ||
3417 		(!rPos.nContent.GetIndex() && pCurrCnts==pCnts &&
3418 		 pCnts->GetStartNode() &&
3419 		 pCnts->GetStartNode()->GetIndex() + 1 ==
3420 			rPos.nNode.GetIndex()) )
3421 	{
3422 		bNoBreak = sal_True;
3423 	}
3424 }
3425 
EndNoBreak(const SwPosition & rPos)3426 void _CellSaveStruct::EndNoBreak( const SwPosition& rPos )
3427 {
3428 	if( bNoBreak )
3429 	{
3430 		delete pNoBreakEndParaIdx;
3431 		pNoBreakEndParaIdx = new SwNodeIndex( rPos.nNode );
3432 		nNoBreakEndCntntPos = rPos.nContent.GetIndex();
3433 		bNoBreak = sal_False;
3434 	}
3435 }
3436 
CheckNoBreak(const SwPosition & rPos,SwDoc *)3437 void _CellSaveStruct::CheckNoBreak( const SwPosition& rPos, SwDoc * /*pDoc*/ )
3438 {
3439 	if( pCnts && pCurrCnts==pCnts )
3440 	{
3441 		if( bNoBreak )
3442 		{
3443 			// <NOBR> wurde nicht beendet
3444 			pCnts->SetNoBreak();
3445 		}
3446 		else if( pNoBreakEndParaIdx &&
3447 				 pNoBreakEndParaIdx->GetIndex() == rPos.nNode.GetIndex() )
3448 		{
3449 			if( nNoBreakEndCntntPos == rPos.nContent.GetIndex() )
3450 			{
3451 				// <NOBR> wurde unmittelbar vor dem Zellen-Ende beendet
3452 				pCnts->SetNoBreak();
3453 			}
3454 			else if( nNoBreakEndCntntPos + 1 == rPos.nContent.GetIndex() )
3455 			{
3456                 SwTxtNode const*const pTxtNd(rPos.nNode.GetNode().GetTxtNode());
3457 				if( pTxtNd )
3458 				{
3459 					sal_Unicode cLast =
3460 							pTxtNd->GetTxt().GetChar(nNoBreakEndCntntPos);
3461 					if( ' '==cLast || '\x0a'==cLast )
3462 					{
3463 						// Zwischem dem </NOBR> und dem Zellen-Ende gibt es nur
3464 						// ein Blank oder einen Zeilenumbruch.
3465 						pCnts->SetNoBreak();
3466 					}
3467 				}
3468 			}
3469 		}
3470 	}
3471 }
3472 
3473 
3474 
InsertTableContents(sal_Bool bHead)3475 HTMLTableCnts *SwHTMLParser::InsertTableContents(
3476 										sal_Bool bHead )
3477 {
3478 	// eine neue Section anlegen, der PaM steht dann darin
3479 	const SwStartNode *pStNd =
3480         InsertTableSection( static_cast< sal_uInt16 >(bHead ? RES_POOLCOLL_TABLE_HDLN
3481                                            : RES_POOLCOLL_TABLE) );
3482 
3483 	if( GetNumInfo().GetNumRule() )
3484 	{
3485 		// 1. Absatz auf nicht numeriert setzen
3486         sal_uInt8 nLvl = GetNumInfo().GetLevel();
3487         // --> OD 2008-04-02 #refactorlists#
3488 //        SetNoNum(&nLvl, sal_True);
3489 //        SetNodeNum( nLvl);
3490         SetNodeNum( nLvl, false );
3491 	}
3492 
3493 	// Attributierungs-Anfang neu setzen
3494 	const SwNodeIndex& rSttPara = pPam->GetPoint()->nNode;
3495 	xub_StrLen nSttCnt = pPam->GetPoint()->nContent.GetIndex();
3496 
3497 	_HTMLAttr** pTbl = (_HTMLAttr**)&aAttrTab;
3498 	for( sal_uInt16 nCnt = sizeof( _HTMLAttrTable ) / sizeof( _HTMLAttr* );
3499 		nCnt--; ++pTbl )
3500 	{
3501 
3502 		_HTMLAttr *pAttr = *pTbl;
3503 		while( pAttr )
3504 		{
3505 			ASSERT( !pAttr->GetPrev(), "Attribut hat Previous-Liste" );
3506 			pAttr->nSttPara = rSttPara;
3507 			pAttr->nEndPara = rSttPara;
3508 			pAttr->nSttCntnt = nSttCnt;
3509 			pAttr->nEndCntnt = nSttCnt;
3510 
3511 			pAttr = pAttr->GetNext();
3512 		}
3513 	}
3514 
3515 	return new HTMLTableCnts( pStNd );
3516 }
3517 
IncGrfsThatResizeTable()3518 sal_uInt16 SwHTMLParser::IncGrfsThatResizeTable()
3519 {
3520 	return pTable ? pTable->IncGrfsThatResize() : 0;
3521 }
3522 
RegisterDrawObjectToTable(HTMLTable * pCurTable,SdrObject * pObj,sal_uInt8 nPrcWidth)3523 void SwHTMLParser::RegisterDrawObjectToTable( HTMLTable *pCurTable,
3524 										SdrObject *pObj, sal_uInt8 nPrcWidth )
3525 {
3526 	pCurTable->RegisterDrawObject( pObj, nPrcWidth );
3527 }
3528 
BuildTableCell(HTMLTable * pCurTable,sal_Bool bReadOptions,sal_Bool bHead)3529 void SwHTMLParser::BuildTableCell( HTMLTable *pCurTable, sal_Bool bReadOptions,
3530 								   sal_Bool bHead )
3531 {
3532 	if( !IsParserWorking() && !pPendStack )
3533 		return;
3534 
3535 	_CellSaveStruct* pSaveStruct;
3536 
3537 	int nToken = 0;
3538 	sal_Bool bPending = sal_False;
3539 	if( pPendStack )
3540 	{
3541 		pSaveStruct = (_CellSaveStruct*)pPendStack->pData;
3542 
3543 		SwPendingStack* pTmp = pPendStack->pNext;
3544 		delete pPendStack;
3545 		pPendStack = pTmp;
3546 		nToken = pPendStack ? pPendStack->nToken : GetSaveToken();
3547 		bPending = SVPAR_ERROR == eState && pPendStack != 0;
3548 
3549 		SaveState( nToken );
3550 	}
3551 	else
3552 	{
3553 		// <TH> bzw. <TD> wurde bereits gelesen
3554 		if( pTable->IsOverflowing() )
3555 		{
3556 			SaveState( 0 );
3557 			return;
3558 		}
3559 
3560 		if( !pCurTable->GetContext() )
3561 		{
3562 			sal_Bool bTopTable = pTable==pCurTable;
3563 
3564 			// die Tabelle besitzt noch keinen Inhalt, d.h. die eigentliche
3565 			// Tabelle muss erst noch angelegt werden
3566 
3567 			static sal_uInt16 aWhichIds[] =
3568 			{
3569 				RES_PARATR_SPLIT,	RES_PARATR_SPLIT,
3570 				RES_PAGEDESC,		RES_PAGEDESC,
3571 				RES_BREAK,			RES_BREAK,
3572 				RES_BACKGROUND, 	RES_BACKGROUND,
3573 				RES_KEEP,			RES_KEEP,
3574 				RES_LAYOUT_SPLIT,	RES_LAYOUT_SPLIT,
3575 				RES_FRAMEDIR,		RES_FRAMEDIR,
3576 				0
3577 			};
3578 
3579 			SfxItemSet aItemSet( pDoc->GetAttrPool(), aWhichIds );
3580 			SvxCSS1PropertyInfo aPropInfo;
3581 
3582 			sal_Bool bStyleParsed = ParseStyleOptions( pCurTable->GetStyle(),
3583 												   pCurTable->GetId(),
3584 												   pCurTable->GetClass(),
3585 												   aItemSet, aPropInfo,
3586 				   								   0, &pCurTable->GetDirection() );
3587 			const SfxPoolItem *pItem = 0;
3588 			if( bStyleParsed )
3589 			{
3590 				if( SFX_ITEM_SET == aItemSet.GetItemState(
3591 										RES_BACKGROUND, sal_False, &pItem ) )
3592 				{
3593 					pCurTable->SetBGBrush( *(const SvxBrushItem *)pItem );
3594 					aItemSet.ClearItem( RES_BACKGROUND );
3595 				}
3596 				if( SFX_ITEM_SET == aItemSet.GetItemState(
3597 										RES_PARATR_SPLIT, sal_False, &pItem ) )
3598 				{
3599 					aItemSet.Put(
3600 						SwFmtLayoutSplit( ((const SvxFmtSplitItem *)pItem)
3601 												->GetValue() ) );
3602 					aItemSet.ClearItem( RES_PARATR_SPLIT );
3603 				}
3604 			}
3605 
3606 			// Den linken/rechten Absatzeinzug ermitteln
3607 			sal_uInt16 nLeftSpace = 0;
3608 			sal_uInt16 nRightSpace = 0;
3609 			short nIndent;
3610 			GetMarginsFromContextWithNumBul( nLeftSpace, nRightSpace, nIndent );
3611 
3612 			// die aktuelle Position an die wir irgendwann zurueckkehren
3613 			SwPosition *pSavePos = 0;
3614 			sal_Bool bForceFrame = sal_False;
3615 			sal_Bool bAppended = sal_False;
3616 			sal_Bool bParentLFStripped = sal_False;
3617 			if( bTopTable )
3618 			{
3619 				SvxAdjust eTblAdjust = pTable->GetTableAdjust(sal_False);
3620 
3621 				// Wenn die Tabelle links oder rechts ausgerichtet ist,
3622 				// oder in einen Rahmen soll, dann kommt sie auch in einen
3623 				// solchen.
3624 				bForceFrame = eTblAdjust == SVX_ADJUST_LEFT ||
3625 							  eTblAdjust == SVX_ADJUST_RIGHT ||
3626 							  pCurTable->HasToFly();
3627 
3628 				// Entweder kommt die Tabelle in keinen Rahmen und befindet
3629 				// sich in keinem Rahmen (wird also durch Zellen simuliert),
3630 				// oder es gibt bereits Inhalt an der entsprechenden Stelle.
3631 				ASSERT( !bForceFrame || pCurTable->HasParentSection(),
3632 						"Tabelle im Rahmen hat keine Umgebung!" );
3633 //				SCHOEN WAER'S, aber wie bekommen den Inhalt nicht zurueck
3634 //				in die umgebende Zelle
3635 //				if( bForceFrame && !pCurTable->HasParentSection() )
3636 //				{
3637 //					pCurTable->SetParentContents(
3638 //						InsertTableContents( sal_False, SVX_ADJUST_END ) );
3639 //					pCurTable->SetHasParentSection( sal_True );
3640 //				}
3641 
3642 				sal_Bool bAppend = sal_False;
3643 				if( bForceFrame )
3644 				{
3645 					// Wenn die Tabelle in einen Rahmen kommt, muss
3646 					// nur ein neuer Absatz aufgemacht werden, wenn
3647 					// der Absatz Rahmen ohne Umlauf enthaelt.
3648 					bAppend = HasCurrentParaFlys(sal_True);
3649 				}
3650 				else
3651 				{
3652 					// Sonst muss ein neuer Absatz aufgemacht werden,
3653 					// wenn der Absatz nicht leer ist, oder Rahmen
3654                     // oder text::Bookmarks enthaelt.
3655 					bAppend =
3656 						pPam->GetPoint()->nContent.GetIndex() ||
3657 						HasCurrentParaFlys() ||
3658 						HasCurrentParaBookmarks();
3659 				}
3660 				if( bAppend )
3661 				{
3662 					if( !pPam->GetPoint()->nContent.GetIndex() )
3663 					{
3664 						pDoc->SetTxtFmtColl( *pPam,
3665 							pCSS1Parser->GetTxtCollFromPool(RES_POOLCOLL_STANDARD) );
3666                         SvxFontHeightItem aFontHeight( 40, 100, RES_CHRATR_FONTSIZE );
3667 
3668 						_HTMLAttr* pTmp =
3669 							new _HTMLAttr( *pPam->GetPoint(), aFontHeight );
3670 						aSetAttrTab.Insert( pTmp, aSetAttrTab.Count() );
3671 
3672 						aFontHeight.SetWhich( RES_CHRATR_CJK_FONTSIZE );
3673 						pTmp = new _HTMLAttr( *pPam->GetPoint(), aFontHeight );
3674 						aSetAttrTab.Insert( pTmp, aSetAttrTab.Count() );
3675 
3676 						aFontHeight.SetWhich( RES_CHRATR_CTL_FONTSIZE );
3677 						pTmp = new _HTMLAttr( *pPam->GetPoint(), aFontHeight );
3678 						aSetAttrTab.Insert( pTmp, aSetAttrTab.Count() );
3679 
3680 						pTmp = new _HTMLAttr( *pPam->GetPoint(),
3681                                             SvxULSpaceItem( 0, 0, RES_UL_SPACE ) );
3682 						aSetAttrTab.Insert( pTmp, 0 ); // ja, 0, weil schon
3683 														// vom Tabellenende vorher
3684 														// was gesetzt sein kann.
3685 					}
3686 					AppendTxtNode( AM_NOSPACE );
3687 					bAppended = sal_True;
3688 				}
3689 				else if( aParaAttrs.Count() )
3690 				{
3691 					if( !bForceFrame )
3692 					{
3693 						// Der Absatz wird gleich hinter die Tabelle
3694 						// verschoben. Deshalb entfernen wir alle harten
3695 						// Attribute des Absatzes
3696 
3697 						for( sal_uInt16 i=0; i<aParaAttrs.Count(); i++ )
3698 							aParaAttrs[i]->Invalidate();
3699 					}
3700 
3701 					aParaAttrs.Remove( 0, aParaAttrs.Count() );
3702 				}
3703 
3704 				pSavePos = new SwPosition( *pPam->GetPoint() );
3705 			}
3706 			else if( pCurTable->HasParentSection() )
3707 			{
3708 				bParentLFStripped = StripTrailingLF() > 0;
3709 
3710 				// Absaetze bzw. ueberschriften beeenden
3711 				nOpenParaToken = 0;
3712 				nFontStHeadStart = nFontStMin;
3713 
3714 				// die harten Attribute an diesem Absatz werden nie mehr ungueltig
3715 				if( aParaAttrs.Count() )
3716 					aParaAttrs.Remove( 0, aParaAttrs.Count() );
3717             }
3718 
3719 			// einen Tabellen Kontext anlegen
3720 			_HTMLTableContext *pTCntxt =
3721 						new _HTMLTableContext( pSavePos, nContextStMin,
3722 											   nContextStAttrMin );
3723 
3724 			// alle noch offenen Attribute beenden und hinter der Tabelle
3725 			// neu aufspannen
3726 			_HTMLAttrs *pPostIts = 0;
3727 			if( !bForceFrame && (bTopTable || pCurTable->HasParentSection()) )
3728 			{
3729 				SplitAttrTab( pTCntxt->aAttrTab, bTopTable );
3730 				// Wenn wir einen schon vorhandenen Absatz verwenden, duerfen
3731 				// in den keine PostIts eingefuegt werden, weil der Absatz
3732 				// ja hinter die Tabelle wandert. Sie werden deshalb in den
3733 				// ersten Absatz der Tabelle verschoben.
3734 				// Bei Tabellen in Tabellen duerfen ebenfalls keine PostIts
3735 				// in einen noch leeren Absatz eingefuegt werden, weil
3736 				// der sonst nicht geloescht wird.
3737 				if( (bTopTable && !bAppended) ||
3738 					(!bTopTable && !bParentLFStripped &&
3739 					 !pPam->GetPoint()->nContent.GetIndex()) )
3740 					pPostIts = new _HTMLAttrs;
3741 				SetAttr( bTopTable, bTopTable, pPostIts );
3742 			}
3743 			else
3744 			{
3745 				SaveAttrTab( pTCntxt->aAttrTab );
3746 				if( bTopTable && !bAppended )
3747 				{
3748 					pPostIts = new _HTMLAttrs;
3749 					SetAttr( sal_True, sal_True, pPostIts );
3750 				}
3751 			}
3752 			bNoParSpace = sal_False;
3753 
3754 			// Aktuelle Nummerierung retten und ausschalten.
3755 			pTCntxt->SetNumInfo( GetNumInfo() );
3756 			GetNumInfo().Clear();
3757 			pTCntxt->SavePREListingXMP( *this );
3758 
3759 			if( bTopTable )
3760 			{
3761 				if( bForceFrame )
3762 				{
3763 					// Die Tabelle soll in einen Rahmen geschaufelt werden.
3764 
3765 					SfxItemSet aFrmSet( pDoc->GetAttrPool(),
3766 										RES_FRMATR_BEGIN, RES_FRMATR_END-1 );
3767 					if( !pCurTable->IsNewDoc() )
3768 						Reader::ResetFrmFmtAttrs( aFrmSet );
3769 
3770 					SwSurround eSurround = SURROUND_NONE;
3771                     sal_Int16 eHori;
3772 
3773 					switch( pCurTable->GetTableAdjust(sal_True) )
3774 					{
3775 					case SVX_ADJUST_RIGHT:
3776                         eHori = text::HoriOrientation::RIGHT;
3777 						eSurround = SURROUND_LEFT;
3778 						break;
3779 					case SVX_ADJUST_CENTER:
3780                         eHori = text::HoriOrientation::CENTER;
3781 						break;
3782 					case SVX_ADJUST_LEFT:
3783 						eSurround = SURROUND_RIGHT;
3784 					default:
3785                         eHori = text::HoriOrientation::LEFT;
3786 						break;
3787 					}
3788                     SetAnchorAndAdjustment( text::VertOrientation::NONE, eHori, aFrmSet,
3789 											sal_True );
3790 					aFrmSet.Put( SwFmtSurround(eSurround) );
3791 
3792 					SwFmtFrmSize aFrmSize( ATT_VAR_SIZE, 20*MM50, MINLAY );
3793 					aFrmSize.SetWidthPercent( 100 );
3794 					aFrmSet.Put( aFrmSize );
3795 
3796 					sal_uInt16 nSpace = pCurTable->GetHSpace();
3797 					if( nSpace )
3798                         aFrmSet.Put( SvxLRSpaceItem(nSpace,nSpace, 0, 0, RES_LR_SPACE) );
3799 					nSpace = pCurTable->GetVSpace();
3800 					if( nSpace )
3801                         aFrmSet.Put( SvxULSpaceItem(nSpace,nSpace, RES_UL_SPACE) );
3802 
3803 					RndStdIds eAnchorId = ((const SwFmtAnchor&)aFrmSet.
3804 												Get( RES_ANCHOR )).
3805 												GetAnchorId();
3806 					SwFrmFmt *pFrmFmt =  pDoc->MakeFlySection(
3807 								eAnchorId, pPam->GetPoint(), &aFrmSet );
3808 
3809 					pTCntxt->SetFrmFmt( pFrmFmt );
3810 					const SwFmtCntnt& rFlyCntnt = pFrmFmt->GetCntnt();
3811 					pPam->GetPoint()->nNode = *rFlyCntnt.GetCntntIdx();
3812 					SwCntntNode *pCNd =
3813 						pDoc->GetNodes().GoNext( &(pPam->GetPoint()->nNode) );
3814 					pPam->GetPoint()->nContent.Assign( pCNd, 0 );
3815 
3816 					// automatisch verankerte Rahmen muessen noch um
3817 					// eine Position nach vorne verschoben werden.
3818 					//if( FLY_AUTO_CNTNT==eAnchorId )
3819 					//	aMoveFlyFrms.C40_INSERT( SwFrmFmt, pFrmFmt,
3820 					//							 aMoveFlyFrms.Count() );
3821 				}
3822 
3823 				// eine SwTable mit einer Box anlegen und den PaM in den
3824 				// Inhalt der Box-Section bewegen (der Ausrichtungs-Parameter
3825 				// ist erstmal nur ein Dummy und wird spaeter noch richtig
3826 				// gesetzt)
3827 				ASSERT( !pPam->GetPoint()->nContent.GetIndex(),
3828 						"Der Absatz hinter der Tabelle ist nicht leer!" );
3829                 const SwTable* pSwTable = pDoc->InsertTable(
3830                         SwInsertTableOptions( tabopts::HEADLINE_NO_BORDER, 1 ),
3831                         *pPam->GetPoint(), 1, 1, text::HoriOrientation::LEFT );
3832 
3833 				if( bForceFrame )
3834 				{
3835 					SwNodeIndex aDstIdx( pPam->GetPoint()->nNode );
3836 					pPam->Move( fnMoveBackward );
3837 					pDoc->GetNodes().Delete( aDstIdx );
3838 				}
3839 				else
3840 				{
3841 					if( bStyleParsed )
3842 					{
3843 						pCSS1Parser->SetFmtBreak( aItemSet, aPropInfo );
3844                         pSwTable->GetFrmFmt()->SetFmtAttr( aItemSet );
3845 					}
3846 					pPam->Move( fnMoveBackward );
3847 				}
3848 
3849                 SwNode const*const pNd = & pPam->GetPoint()->nNode.GetNode();
3850 				if( !bAppended && !bForceFrame )
3851 				{
3852                     SwTxtNode *const pOldTxtNd =
3853                         pSavePos->nNode.GetNode().GetTxtNode();
3854 					ASSERT( pOldTxtNd, "Wieso stehen wir in keinem Txt-Node?" );
3855 					SwFrmFmt *pFrmFmt = pSwTable->GetFrmFmt();
3856 
3857 					const SfxPoolItem* pItem2;
3858 					if( SFX_ITEM_SET ==	pOldTxtNd->GetSwAttrSet()
3859 							.GetItemState( RES_PAGEDESC, sal_False, &pItem2 ) &&
3860 						((SwFmtPageDesc *)pItem2)->GetPageDesc() )
3861 					{
3862                         pFrmFmt->SetFmtAttr( *pItem2 );
3863 						pOldTxtNd->ResetAttr( RES_PAGEDESC );
3864 					}
3865 					if( SFX_ITEM_SET ==	pOldTxtNd->GetSwAttrSet()
3866 							.GetItemState( RES_BREAK, sal_True, &pItem2 ) )
3867 					{
3868 						switch( ((SvxFmtBreakItem *)pItem2)->GetBreak() )
3869 						{
3870 						case SVX_BREAK_PAGE_BEFORE:
3871 						case SVX_BREAK_PAGE_AFTER:
3872 						case SVX_BREAK_PAGE_BOTH:
3873                             pFrmFmt->SetFmtAttr( *pItem2 );
3874 							pOldTxtNd->ResetAttr( RES_BREAK );
3875 						default:
3876 							;
3877 						}
3878 					}
3879 				}
3880 
3881 				if( !bAppended && pPostIts )
3882 				{
3883 					// noch vorhandene PostIts in den ersten Absatz
3884 					// der Tabelle setzen
3885 					InsertAttrs( *pPostIts );
3886 					delete pPostIts;
3887 					pPostIts = 0;
3888 				}
3889 
3890 				pTCntxt->SetTableNode( (SwTableNode *)pNd->FindTableNode() );
3891 
3892 				pCurTable->SetTable( pTCntxt->GetTableNode(), pTCntxt,
3893 									 nLeftSpace, nRightSpace,
3894 									 pSwTable, bForceFrame );
3895 
3896 				ASSERT( !pPostIts, "ubenutzte PostIts" );
3897 			}
3898 			else
3899 			{
3900 				// noch offene Bereiche muessen noch entfernt werden
3901 				if( EndSections( bParentLFStripped ) )
3902 					bParentLFStripped = sal_False;
3903 
3904 				if( pCurTable->HasParentSection() )
3905 				{
3906 					// danach entfernen wir ein ggf. zu viel vorhandenen
3907 					// leeren Absatz, aber nur, wenn er schon vor dem
3908 					// entfernen von LFs leer war
3909 					if( !bParentLFStripped )
3910 						StripTrailingPara();
3911 
3912 					if( pPostIts )
3913 					{
3914 						// noch vorhandene PostIts an das Ende des jetzt
3915 						// aktuellen Absatzes schieben
3916 						InsertAttrs( *pPostIts );
3917 						delete pPostIts;
3918 						pPostIts = 0;
3919 					}
3920 				}
3921 
3922                 SwNode const*const pNd = & pPam->GetPoint()->nNode.GetNode();
3923 				const SwStartNode *pStNd = (pTable->bFirstCell ? pNd->FindTableNode()
3924 															: pNd->FindTableBoxStartNode() );
3925 
3926 				pCurTable->SetTable( pStNd, pTCntxt, nLeftSpace, nRightSpace );
3927 			}
3928 
3929 			// Den Kontext-Stack einfrieren, denn es koennen auch mal
3930 			// irgendwo ausserhalb von Zellen Attribute gesetzt werden.
3931 			// Darf nicht frueher passieren, weil eventuell noch im
3932 			// Stack gesucht wird!!!
3933 			nContextStMin = aContexts.Count();
3934 			nContextStAttrMin = nContextStMin;
3935 		}
3936 
3937 		pSaveStruct = new _CellSaveStruct( *this, pCurTable, bHead,
3938 											bReadOptions );
3939 
3940 		// ist beim ersten GetNextToken schon pending, muss bei
3941 		// wiederaufsetzen auf jeden Fall neu gelesen werden!
3942 		SaveState( 0 );
3943 	}
3944 
3945 	if( !nToken )
3946 		nToken = GetNextToken();	// Token nach <TABLE>
3947 
3948 	sal_Bool bDone = sal_False;
3949 	while( (IsParserWorking() && !bDone) || bPending )
3950 	{
3951 		SaveState( nToken );
3952 
3953 		nToken = FilterToken( nToken );
3954 
3955 		ASSERT( pPendStack || !bCallNextToken || pSaveStruct->IsInSection(),
3956 				"Wo ist die Section gebieben?" );
3957 		if( !pPendStack && bCallNextToken && pSaveStruct->IsInSection() )
3958 		{
3959 			// NextToken direkt aufrufen (z.B. um den Inhalt von
3960 			// Floating-Frames oder Applets zu ignorieren)
3961 			NextToken( nToken );
3962 		}
3963 		else switch( nToken )
3964 		{
3965 		case HTML_TABLEHEADER_ON:
3966 		case HTML_TABLEDATA_ON:
3967 		case HTML_TABLEROW_ON:
3968 		case HTML_TABLEROW_OFF:
3969 		case HTML_THEAD_ON:
3970 		case HTML_THEAD_OFF:
3971 		case HTML_TFOOT_ON:
3972 		case HTML_TFOOT_OFF:
3973 		case HTML_TBODY_ON:
3974 		case HTML_TBODY_OFF:
3975 		case HTML_TABLE_OFF:
3976 			SkipToken(-1);
3977 		case HTML_TABLEHEADER_OFF:
3978 		case HTML_TABLEDATA_OFF:
3979 			bDone = sal_True;
3980 			break;
3981 		case HTML_TABLE_ON:
3982 			{
3983 				sal_Bool bTopTable = sal_False;
3984 				sal_Bool bHasToFly = sal_False;
3985 				SvxAdjust eTabAdjust = SVX_ADJUST_END;
3986 				if( !pPendStack )
3987 				{
3988 					// nur wenn eine neue Tabelle aufgemacht wird, aber
3989 					// nicht wenn nach einem Pending in der Tabelle
3990 					// weitergelesen wird!
3991 					pSaveStruct->pTable = pTable;
3992 
3993 					// HACK: Eine Section fuer eine Tabelle anlegen, die
3994 					// in einen Rahmen kommt.
3995 					if( !pSaveStruct->IsInSection() )
3996 					{
3997 						// Diese Schleife muss vorwaerts sein, weil die
3998 						// erste Option immer gewinnt.
3999 						sal_Bool bNeedsSection = sal_False;
4000 						const HTMLOptions *pHTMLOptions = GetOptions();
4001 						for( sal_uInt16 i=0; i<pHTMLOptions->Count(); i++ )
4002 						{
4003 							const HTMLOption *pOption = (*pHTMLOptions)[i];
4004 							if( HTML_O_ALIGN==pOption->GetToken() )
4005 							{
4006 								SvxAdjust eAdjust =
4007 									(SvxAdjust)pOption->GetEnum(
4008 											aHTMLPAlignTable, SVX_ADJUST_END );
4009 								bNeedsSection = SVX_ADJUST_LEFT == eAdjust ||
4010 												SVX_ADJUST_RIGHT == eAdjust;
4011 								break;
4012 							}
4013 						}
4014 						if( bNeedsSection )
4015 						{
4016 							pSaveStruct->AddContents(
4017 								InsertTableContents(bHead  ) );
4018 						}
4019 					}
4020 					else
4021 					{
4022 						// Wenn wir mittlerweile in einem Rahmen stehen
4023 						// koennen wir erneut eine echte Tabelle aufmachen.
4024 						// Wir erkennen das daran, dass wir keinen
4025 						// Tabellen-Node mehr finden.
4026                         bTopTable = (0 ==
4027                             pPam->GetPoint()->nNode.GetNode().FindTableNode());
4028 
4029 						// Wenn im aktuellen Absatz Flys verankert sind,
4030 						// muss die neue Tabelle in einen Rahmen.
4031 						bHasToFly = HasCurrentParaFlys(sal_False,sal_True);
4032 					}
4033 
4034 					// in der Zelle kann sich ein Bereich befinden!
4035 					eTabAdjust = aAttrTab.pAdjust
4036 						? ((const SvxAdjustItem&)aAttrTab.pAdjust->GetItem()).
4037 												 GetAdjust()
4038 						: SVX_ADJUST_END;
4039 				}
4040 
4041 				HTMLTable *pSubTable = BuildTable( eTabAdjust,
4042 												   bHead,
4043 												   pSaveStruct->IsInSection(),
4044 												   bTopTable, bHasToFly );
4045 				if( SVPAR_PENDING != GetStatus() )
4046 				{
4047 					// nur wenn die Tabelle wirklich zu Ende ist!
4048 					if( pSubTable )
4049 					{
4050 						ASSERT( pSubTable->GetTableAdjust(sal_False)!= SVX_ADJUST_LEFT &&
4051 								pSubTable->GetTableAdjust(sal_False)!= SVX_ADJUST_RIGHT,
4052 								"links oder rechts ausgerichtete Tabellen gehoehren in Rahmen" );
4053 
4054 
4055 						HTMLTableCnts *pParentContents =
4056 							pSubTable->GetParentContents();
4057 						if( pParentContents )
4058 						{
4059 							ASSERT( !pSaveStruct->IsInSection(),
4060 									"Wo ist die Section geblieben" );
4061 
4062 							// Wenn jetzt keine Tabelle kommt haben wir eine
4063 							// Section
4064 							pSaveStruct->AddContents( pParentContents );
4065 						}
4066 
4067 						const SwStartNode *pCapStNd =
4068 								pSubTable->GetCaptionStartNode();
4069 
4070 						if( pSubTable->GetContext() )
4071 						{
4072 							ASSERT( !pSubTable->GetContext()->GetFrmFmt(),
4073 									"Tabelle steht im Rahmen" );
4074 
4075 							if( pCapStNd && pSubTable->IsTopCaption() )
4076 							{
4077 								pSaveStruct->AddContents(
4078 									new HTMLTableCnts(pCapStNd) );
4079 							}
4080 
4081 							pSaveStruct->AddContents(
4082 								new HTMLTableCnts(pSubTable) );
4083 
4084 							if( pCapStNd && !pSubTable->IsTopCaption() )
4085 							{
4086 								pSaveStruct->AddContents(
4087 									new HTMLTableCnts(pCapStNd) );
4088 							}
4089 
4090 							// Jetzt haben wir keine Section mehr
4091 							pSaveStruct->ClearIsInSection();
4092 						}
4093 						else if( pCapStNd )
4094 						{
4095 							// Da wir diese Section nicht mehr loeschen
4096 							// koennen (sie koennte zur erster Box
4097 							// gehoeren), fuegen wir sie ein.
4098 							pSaveStruct->AddContents(
4099 								new HTMLTableCnts(pCapStNd) );
4100 
4101 							// Jetzt haben wir keine Section mehr
4102 							pSaveStruct->ClearIsInSection();
4103 						}
4104 					}
4105 
4106 					pTable = pSaveStruct->pTable;
4107 				}
4108 			}
4109 			break;
4110 
4111 		case HTML_NOBR_ON:
4112 			// HACK fuer MS: Steht das <NOBR> zu beginn der Zelle?
4113 			pSaveStruct->StartNoBreak( *pPam->GetPoint() );
4114 			break;
4115 
4116 		case HTML_NOBR_OFF:
4117 				pSaveStruct->EndNoBreak( *pPam->GetPoint() );
4118 			break;
4119 
4120 		case HTML_COMMENT:
4121 			// Mit Kommentar-Feldern werden Spaces nicht mehr geloescht
4122 			// ausserdem wollen wir fuer einen Kommentar keine neue Zelle
4123 			// anlegen !!!
4124 			NextToken( nToken );
4125 			break;
4126 
4127 		case HTML_MARQUEE_ON:
4128 			if( !pSaveStruct->IsInSection() )
4129 			{
4130 				// eine neue Section anlegen, der PaM steht dann darin
4131 				pSaveStruct->AddContents(
4132 					InsertTableContents( bHead ) );
4133 			}
4134 			bCallNextToken = sal_True;
4135 			NewMarquee( pCurTable );
4136 			break;
4137 
4138 		case HTML_TEXTTOKEN:
4139 			// keine Section fuer einen leeren String anlegen
4140 			if( !pSaveStruct->IsInSection() && 1==aToken.Len() &&
4141 				' '==aToken.GetChar(0) )
4142 				break;
4143 		default:
4144 			if( !pSaveStruct->IsInSection() )
4145 			{
4146 				// eine neue Section anlegen, der PaM steht dann darin
4147 				pSaveStruct->AddContents(
4148 					InsertTableContents( bHead ) );
4149 			}
4150 
4151 			if( IsParserWorking() || bPending )
4152 				NextToken( nToken );
4153 			break;
4154 		}
4155 
4156 		ASSERT( !bPending || !pPendStack,
4157 				"SwHTMLParser::BuildTableCell: Es gibt wieder einen Pend-Stack" );
4158 		bPending = sal_False;
4159 		if( IsParserWorking() )
4160 			SaveState( 0 );
4161 
4162 		if( !bDone )
4163 			nToken = GetNextToken();
4164 	}
4165 
4166 	if( SVPAR_PENDING == GetStatus() )
4167 	{
4168 		pPendStack = new SwPendingStack( bHead ? HTML_TABLEHEADER_ON
4169 											   : HTML_TABLEDATA_ON, pPendStack );
4170 		pPendStack->pData = pSaveStruct;
4171 
4172 		return;
4173 	}
4174 
4175 	// Falls der Inhalt der Zelle leer war, muessen wir noch einen
4176 	// leeren Inhalt anlegen. Ausserdem legen wir einen leeren Inhalt
4177 	// an, wenn die Zelle mit einer Tabelle aufgehoert hat und keine
4178 	// COL-Tags hatte (sonst wurde sie wahrscheinlich von uns exportiert,
4179 	// und dann wollen wir natuerlich keinen zusaetzlichen Absatz haben).
4180 	if( !pSaveStruct->GetFirstContents() ||
4181 		(!pSaveStruct->IsInSection() && !pCurTable->HasColTags()) )
4182 	{
4183 		ASSERT( pSaveStruct->GetFirstContents() ||
4184 				!pSaveStruct->IsInSection(),
4185 				"Section oder nicht, das ist hier die Frage" );
4186 		const SwStartNode *pStNd =
4187             InsertTableSection( static_cast< sal_uInt16 >(pSaveStruct->IsHeaderCell()
4188 										? RES_POOLCOLL_TABLE_HDLN
4189                                         : RES_POOLCOLL_TABLE ));
4190 		const SwEndNode *pEndNd = pStNd->EndOfSectionNode();
4191 		SwCntntNode *pCNd = pDoc->GetNodes()[pEndNd->GetIndex()-1] ->GetCntntNode();
4192         SvxFontHeightItem aFontHeight( 40, 100, RES_CHRATR_FONTSIZE );
4193 		pCNd->SetAttr( aFontHeight );
4194 		aFontHeight.SetWhich( RES_CHRATR_CJK_FONTSIZE );
4195 		pCNd->SetAttr( aFontHeight );
4196 		aFontHeight.SetWhich( RES_CHRATR_CTL_FONTSIZE );
4197 		pCNd->SetAttr( aFontHeight );
4198 
4199 		pSaveStruct->AddContents( new HTMLTableCnts(pStNd) );
4200 		pSaveStruct->ClearIsInSection();
4201 	}
4202 
4203 	if( pSaveStruct->IsInSection() )
4204 	{
4205 		pSaveStruct->CheckNoBreak( *pPam->GetPoint(), pDoc );
4206 
4207 		// Alle noch offenen Kontexte beenden. Wir nehmen hier
4208 		// AttrMin, weil nContxtStMin evtl. veraendert wurde.
4209 		// Da es durch EndContext wieder restauriert wird, geht das.
4210 		while( aContexts.Count() > nContextStAttrMin+1 )
4211 		{
4212 			_HTMLAttrContext *pCntxt = PopContext();
4213 			EndContext( pCntxt );
4214 			delete pCntxt;
4215 		}
4216 
4217 		// LFs am Absatz-Ende entfernen
4218 		if( StripTrailingLF()==0 && !pPam->GetPoint()->nContent.GetIndex() )
4219 			StripTrailingPara();
4220 
4221         // falls fuer die Zelle eine Ausrichtung gesetzt wurde, muessen
4222 		// wir die beenden
4223 		_HTMLAttrContext *pCntxt = PopContext();
4224 		EndContext( pCntxt );
4225 		delete pCntxt;
4226 	}
4227 	else
4228 	{
4229 		// Alle noch offenen Kontexte beenden
4230 		while( aContexts.Count() > nContextStAttrMin )
4231 		{
4232 			_HTMLAttrContext *pCntxt = PopContext();
4233 			ClearContext( pCntxt );
4234 			delete pCntxt;
4235 		}
4236 	}
4237 
4238 	// auch eine Nummerierung muss beendet werden
4239 	GetNumInfo().Clear();
4240 
4241 	SetAttr( sal_False );
4242 
4243 	pSaveStruct->InsertCell( *this, pCurTable );
4244 
4245 	// wir stehen jetzt (wahrschenlich) vor <TH>, <TD>, <TR> oder </TABLE>
4246 	delete pSaveStruct;
4247 }
4248 
4249 
4250 class _RowSaveStruct : public SwPendingStackData
4251 {
4252 public:
4253 	SvxAdjust eAdjust;
4254     sal_Int16 eVertOri;
4255 	sal_Bool bHasCells;
4256 
_RowSaveStruct()4257 	_RowSaveStruct() :
4258         eAdjust( SVX_ADJUST_END ), eVertOri( text::VertOrientation::TOP ), bHasCells( sal_False )
4259 	{}
4260 };
4261 
4262 
BuildTableRow(HTMLTable * pCurTable,sal_Bool bReadOptions,SvxAdjust eGrpAdjust,sal_Int16 eGrpVertOri)4263 void SwHTMLParser::BuildTableRow( HTMLTable *pCurTable, sal_Bool bReadOptions,
4264 								  SvxAdjust eGrpAdjust,
4265                                   sal_Int16 eGrpVertOri )
4266 {
4267 	// <TR> wurde bereist gelesen
4268 
4269 	if( !IsParserWorking() && !pPendStack )
4270 		return;
4271 
4272 	int nToken = 0;
4273 	_RowSaveStruct* pSaveStruct;
4274 
4275 	sal_Bool bPending = sal_False;
4276 	if( pPendStack )
4277 	{
4278 		pSaveStruct = (_RowSaveStruct*)pPendStack->pData;
4279 
4280 		SwPendingStack* pTmp = pPendStack->pNext;
4281 		delete pPendStack;
4282 		pPendStack = pTmp;
4283 		nToken = pPendStack ? pPendStack->nToken : GetSaveToken();
4284 		bPending = SVPAR_ERROR == eState && pPendStack != 0;
4285 
4286 		SaveState( nToken );
4287 	}
4288 	else
4289 	{
4290 		SvxAdjust eAdjust = eGrpAdjust;
4291         sal_Int16 eVertOri = eGrpVertOri;
4292 		Color aBGColor;
4293 		String aBGImage, aStyle, aId, aClass;
4294 		sal_Bool bBGColor = sal_False;
4295 		pSaveStruct = new _RowSaveStruct;
4296 
4297 		if( bReadOptions )
4298 		{
4299 			const HTMLOptions *pHTMLOptions = GetOptions();
4300 			for( sal_uInt16 i = pHTMLOptions->Count(); i; )
4301 			{
4302 				const HTMLOption *pOption = (*pHTMLOptions)[--i];
4303 				switch( pOption->GetToken() )
4304 				{
4305 				case HTML_O_ID:
4306 					aId = pOption->GetString();
4307 					break;
4308 				case HTML_O_ALIGN:
4309 					eAdjust = (SvxAdjust)pOption->GetEnum(
4310                                     aHTMLPAlignTable, static_cast< sal_uInt16 >(eAdjust) );
4311 					break;
4312 				case HTML_O_VALIGN:
4313                     eVertOri = pOption->GetEnum(
4314                                     aHTMLTblVAlignTable, eVertOri );
4315 					break;
4316 				case HTML_O_BGCOLOR:
4317 					// Leere BGCOLOR bei <TABLE>, <TR> und <TD>/<TH> wie Netsc.
4318 					// ignorieren, bei allen anderen Tags *wirklich* nicht.
4319 					if( pOption->GetString().Len() )
4320 					{
4321 						pOption->GetColor( aBGColor );
4322 						bBGColor = sal_True;
4323 					}
4324 					break;
4325 				case HTML_O_BACKGROUND:
4326 					aBGImage = pOption->GetString();
4327 					break;
4328 				case HTML_O_STYLE:
4329 					aStyle = pOption->GetString();
4330 					break;
4331 				case HTML_O_CLASS:
4332 					aClass= pOption->GetString();
4333 					break;
4334 				}
4335 			}
4336 		}
4337 
4338 		if( aId.Len() )
4339 			InsertBookmark( aId );
4340 
4341 		SvxBrushItem *pBrushItem =
4342 			CreateBrushItem( bBGColor ? &aBGColor : 0, aBGImage, aStyle,
4343 							 aId, aClass );
4344 		pCurTable->OpenRow( eAdjust, eVertOri, pBrushItem );
4345 		// ist beim ersten GetNextToken schon pending, muss bei
4346 		// wiederaufsetzen auf jeden Fall neu gelesen werden!
4347 		SaveState( 0 );
4348 	}
4349 
4350 	if( !nToken )
4351 		nToken = GetNextToken();	// naechstes Token
4352 
4353 	sal_Bool bDone = sal_False;
4354 	while( (IsParserWorking() && !bDone) || bPending )
4355 	{
4356 		SaveState( nToken );
4357 
4358 		nToken = FilterToken( nToken );
4359 
4360 		ASSERT( pPendStack || !bCallNextToken ||
4361 				pCurTable->GetContext() || pCurTable->HasParentSection(),
4362 				"Wo ist die Section gebieben?" );
4363 		if( !pPendStack && bCallNextToken &&
4364 			(pCurTable->GetContext() || pCurTable->HasParentSection()) )
4365 		{
4366 			// NextToken direkt aufrufen (z.B. um den Inhalt von
4367 			// Floating-Frames oder Applets zu ignorieren)
4368 			NextToken( nToken );
4369 		}
4370 		else switch( nToken )
4371 		{
4372 		case HTML_TABLE_ON:
4373 			if( !pCurTable->GetContext()  )
4374 			{
4375 				SkipToken( -1 );
4376 				bDone = sal_True;
4377 			}
4378 //			else
4379 //			{
4380 //				NextToken( nToken );
4381 //			}
4382 			break;
4383 		case HTML_TABLEROW_ON:
4384 		case HTML_THEAD_ON:
4385 		case HTML_THEAD_OFF:
4386 		case HTML_TBODY_ON:
4387 		case HTML_TBODY_OFF:
4388 		case HTML_TFOOT_ON:
4389 		case HTML_TFOOT_OFF:
4390 		case HTML_TABLE_OFF:
4391 			SkipToken( -1 );
4392 		case HTML_TABLEROW_OFF:
4393 			bDone = sal_True;
4394 			break;
4395 		case HTML_TABLEHEADER_ON:
4396 		case HTML_TABLEDATA_ON:
4397 			BuildTableCell( pCurTable, sal_True, HTML_TABLEHEADER_ON==nToken );
4398 			if( SVPAR_PENDING != GetStatus() )
4399 			{
4400 				pSaveStruct->bHasCells = sal_True;
4401 				bDone = pTable->IsOverflowing();
4402 			}
4403 			break;
4404 		case HTML_CAPTION_ON:
4405 			BuildTableCaption( pCurTable );
4406 			bDone = pTable->IsOverflowing();
4407 			break;
4408 		case HTML_CAPTION_OFF:
4409 		case HTML_TABLEHEADER_OFF:
4410 		case HTML_TABLEDATA_OFF:
4411 		case HTML_COLGROUP_ON:
4412 		case HTML_COLGROUP_OFF:
4413 		case HTML_COL_ON:
4414 		case HTML_COL_OFF:
4415 			// wo keine Zelle anfing kann auch keine aufhoeren, oder?
4416 			// und die ganzen anderen Tokens haben hier auch nicht zu
4417 			// suchen und machen nur die Tabelle kaputt
4418 			break;
4419 		case HTML_MULTICOL_ON:
4420 			// spaltige Rahmen koennen wir hier leider nicht einfuegen
4421 			break;
4422 		case HTML_FORM_ON:
4423 			NewForm( sal_False );	// keinen neuen Absatz aufmachen!
4424 			break;
4425 		case HTML_FORM_OFF:
4426 			EndForm( sal_False );	// keinen neuen Absatz aufmachen!
4427 			break;
4428 		case HTML_COMMENT:
4429 			NextToken( nToken );
4430 			break;
4431 		case HTML_MAP_ON:
4432 			// eine Image-Map fuegt nichts ein, deshalb koennen wir sie
4433 			// problemlos auch ohne Zelle parsen
4434 			NextToken( nToken );
4435 			break;
4436 		case HTML_TEXTTOKEN:
4437 			if( (pCurTable->GetContext() ||
4438 				 !pCurTable->HasParentSection()) &&
4439 				1==aToken.Len() && ' '==aToken.GetChar(0) )
4440 				break;
4441 		default:
4442 			pCurTable->MakeParentContents();
4443 			NextToken( nToken );
4444 			break;
4445 		}
4446 
4447 		ASSERT( !bPending || !pPendStack,
4448 				"SwHTMLParser::BuildTableRow: Es gibt wieder einen Pend-Stack" );
4449 		bPending = sal_False;
4450 		if( IsParserWorking() )
4451 			SaveState( 0 );
4452 
4453 		if( !bDone )
4454 			nToken = GetNextToken();
4455 	}
4456 
4457 	if( SVPAR_PENDING == GetStatus() )
4458 	{
4459 		pPendStack = new SwPendingStack( HTML_TABLEROW_ON, pPendStack );
4460 		pPendStack->pData = pSaveStruct;
4461 	}
4462 	else
4463 	{
4464 		pCurTable->CloseRow( !pSaveStruct->bHasCells );
4465 		delete pSaveStruct;
4466 	}
4467 
4468 	// wir stehen jetzt (wahrscheinlich) vor <TR> oder </TABLE>
4469 }
4470 
BuildTableSection(HTMLTable * pCurTable,sal_Bool bReadOptions,sal_Bool bHead)4471 void SwHTMLParser::BuildTableSection( HTMLTable *pCurTable,
4472 									  sal_Bool bReadOptions,
4473 									  sal_Bool bHead )
4474 {
4475 	// <THEAD>, <TBODY> bzw. <TFOOT> wurde bereits gelesen
4476 	if( !IsParserWorking() && !pPendStack )
4477 		return;
4478 
4479 	int nToken = 0;
4480 	sal_Bool bPending = sal_False;
4481 	_RowSaveStruct* pSaveStruct;
4482 
4483 	if( pPendStack )
4484 	{
4485 		pSaveStruct = (_RowSaveStruct*)pPendStack->pData;
4486 
4487 		SwPendingStack* pTmp = pPendStack->pNext;
4488 		delete pPendStack;
4489 		pPendStack = pTmp;
4490 		nToken = pPendStack ? pPendStack->nToken : GetSaveToken();
4491 		bPending = SVPAR_ERROR == eState && pPendStack != 0;
4492 
4493 		SaveState( nToken );
4494 	}
4495 	else
4496 	{
4497 		pSaveStruct = new _RowSaveStruct;
4498 
4499 		if( bReadOptions )
4500 		{
4501 			const HTMLOptions *pHTMLOptions = GetOptions();
4502 			for( sal_uInt16 i = pHTMLOptions->Count(); i; )
4503 			{
4504 				const HTMLOption *pOption = (*pHTMLOptions)[--i];
4505 				switch( pOption->GetToken() )
4506 				{
4507 				case HTML_O_ID:
4508 					InsertBookmark( pOption->GetString() );
4509 					break;
4510 				case HTML_O_ALIGN:
4511 					pSaveStruct->eAdjust =
4512 						(SvxAdjust)pOption->GetEnum( aHTMLPAlignTable,
4513                                                      static_cast< sal_uInt16 >(pSaveStruct->eAdjust) );
4514 					break;
4515 				case HTML_O_VALIGN:
4516 					pSaveStruct->eVertOri =
4517                         pOption->GetEnum( aHTMLTblVAlignTable,
4518                                           pSaveStruct->eVertOri );
4519 					break;
4520 				}
4521 			}
4522 		}
4523 
4524 		// ist beim ersten GetNextToken schon pending, muss bei
4525 		// wiederaufsetzen auf jeden Fall neu gelesen werden!
4526 		SaveState( 0 );
4527 	}
4528 
4529 	if( !nToken )
4530 		nToken = GetNextToken();	// naechstes Token
4531 
4532 	sal_Bool bDone = sal_False;
4533 	while( (IsParserWorking() && !bDone) || bPending )
4534 	{
4535 		SaveState( nToken );
4536 
4537 		nToken = FilterToken( nToken );
4538 
4539 		ASSERT( pPendStack || !bCallNextToken ||
4540 				pCurTable->GetContext() || pCurTable->HasParentSection(),
4541 				"Wo ist die Section gebieben?" );
4542 		if( !pPendStack && bCallNextToken &&
4543 			(pCurTable->GetContext() || pCurTable->HasParentSection()) )
4544 		{
4545 			// NextToken direkt aufrufen (z.B. um den Inhalt von
4546 			// Floating-Frames oder Applets zu ignorieren)
4547 			NextToken( nToken );
4548 		}
4549 		else switch( nToken )
4550 		{
4551 		case HTML_TABLE_ON:
4552 			if( !pCurTable->GetContext()  )
4553 			{
4554 				SkipToken( -1 );
4555 				bDone = sal_True;
4556 			}
4557 //			else
4558 //			{
4559 //				NextToken( nToken );
4560 //			}
4561 			break;
4562 		case HTML_THEAD_ON:
4563 		case HTML_TFOOT_ON:
4564 		case HTML_TBODY_ON:
4565 		case HTML_TABLE_OFF:
4566 			SkipToken( -1 );
4567 		case HTML_THEAD_OFF:
4568 		case HTML_TBODY_OFF:
4569 		case HTML_TFOOT_OFF:
4570 			bDone = sal_True;
4571 			break;
4572 		case HTML_CAPTION_ON:
4573 			BuildTableCaption( pCurTable );
4574 			bDone = pTable->IsOverflowing();
4575 			break;
4576 		case HTML_CAPTION_OFF:
4577 			break;
4578 		case HTML_TABLEHEADER_ON:
4579 		case HTML_TABLEDATA_ON:
4580 			SkipToken( -1 );
4581 			BuildTableRow( pCurTable, sal_False, pSaveStruct->eAdjust,
4582 						   pSaveStruct->eVertOri );
4583 			bDone = pTable->IsOverflowing();
4584 			break;
4585 		case HTML_TABLEROW_ON:
4586 			BuildTableRow( pCurTable, sal_True,	pSaveStruct->eAdjust,
4587 						   pSaveStruct->eVertOri );
4588 			bDone = pTable->IsOverflowing();
4589 			break;
4590 		case HTML_MULTICOL_ON:
4591 			// spaltige Rahmen koennen wir hier leider nicht einfuegen
4592 			break;
4593 		case HTML_FORM_ON:
4594 			NewForm( sal_False );	// keinen neuen Absatz aufmachen!
4595 			break;
4596 		case HTML_FORM_OFF:
4597 			EndForm( sal_False );	// keinen neuen Absatz aufmachen!
4598 			break;
4599 		case HTML_TEXTTOKEN:
4600 			// Blank-Strings sind Folge von CR+LF und kein Text
4601 			if( (pCurTable->GetContext() ||
4602 				 !pCurTable->HasParentSection()) &&
4603 				1==aToken.Len() && ' '==aToken.GetChar(0) )
4604 				break;
4605 		default:
4606 			pCurTable->MakeParentContents();
4607 			NextToken( nToken );
4608 		}
4609 
4610 		ASSERT( !bPending || !pPendStack,
4611 				"SwHTMLParser::BuildTableSection: Es gibt wieder einen Pend-Stack" );
4612 		bPending = sal_False;
4613 		if( IsParserWorking() )
4614 			SaveState( 0 );
4615 
4616 		if( !bDone )
4617 			nToken = GetNextToken();
4618 	}
4619 
4620 	if( SVPAR_PENDING == GetStatus() )
4621 	{
4622 		pPendStack = new SwPendingStack( bHead ? HTML_THEAD_ON
4623 											   : HTML_TBODY_ON, pPendStack );
4624 		pPendStack->pData = pSaveStruct;
4625 	}
4626 	else
4627 	{
4628 		pCurTable->CloseSection( bHead );
4629 		delete pSaveStruct;
4630 	}
4631 
4632 	// wir stehen jetzt (wahrscheinlich) vor <TBODY>,... oder </TABLE>
4633 }
4634 
4635 struct _TblColGrpSaveStruct : public SwPendingStackData
4636 {
4637 	sal_uInt16 nColGrpSpan;
4638 	sal_uInt16 nColGrpWidth;
4639 	sal_Bool bRelColGrpWidth;
4640 	SvxAdjust eColGrpAdjust;
4641     sal_Int16 eColGrpVertOri;
4642 
4643 	inline _TblColGrpSaveStruct();
4644 
4645 
4646 	inline void CloseColGroup( HTMLTable *pTable );
4647 };
4648 
_TblColGrpSaveStruct()4649 inline _TblColGrpSaveStruct::_TblColGrpSaveStruct() :
4650 	nColGrpSpan( 1 ), nColGrpWidth( 0 ),
4651 	bRelColGrpWidth( sal_False ), eColGrpAdjust( SVX_ADJUST_END ),
4652     eColGrpVertOri( text::VertOrientation::TOP )
4653 {}
4654 
4655 
CloseColGroup(HTMLTable * pTable)4656 inline void _TblColGrpSaveStruct::CloseColGroup( HTMLTable *pTable )
4657 {
4658 	pTable->CloseColGroup( nColGrpSpan, nColGrpWidth,
4659 							bRelColGrpWidth, eColGrpAdjust,	eColGrpVertOri );
4660 }
4661 
BuildTableColGroup(HTMLTable * pCurTable,sal_Bool bReadOptions)4662 void SwHTMLParser::BuildTableColGroup( HTMLTable *pCurTable,
4663 									   sal_Bool bReadOptions )
4664 {
4665 	// <COLGROUP> wurde bereits gelesen, wenn bReadOptions
4666 
4667 	if( !IsParserWorking() && !pPendStack )
4668 		return;
4669 
4670 	int nToken = 0;
4671 	sal_Bool bPending = sal_False;
4672 	_TblColGrpSaveStruct* pSaveStruct;
4673 
4674 	if( pPendStack )
4675 	{
4676 		pSaveStruct = (_TblColGrpSaveStruct*)pPendStack->pData;
4677 
4678 		SwPendingStack* pTmp = pPendStack->pNext;
4679 		delete pPendStack;
4680 		pPendStack = pTmp;
4681 		nToken = pPendStack ? pPendStack->nToken : GetSaveToken();
4682 		bPending = SVPAR_ERROR == eState && pPendStack != 0;
4683 
4684 		SaveState( nToken );
4685 	}
4686 	else
4687 	{
4688 
4689 		pSaveStruct = new _TblColGrpSaveStruct;
4690 		if( bReadOptions )
4691 		{
4692 			const HTMLOptions *pColGrpOptions = GetOptions();
4693 			for( sal_uInt16 i = pColGrpOptions->Count(); i; )
4694 			{
4695 				const HTMLOption *pColGrpOption = (*pColGrpOptions)[--i];
4696 				switch( pColGrpOption->GetToken() )
4697 				{
4698 				case HTML_O_ID:
4699 					InsertBookmark( pColGrpOption->GetString() );
4700 					break;
4701 				case HTML_O_SPAN:
4702 					pSaveStruct->nColGrpSpan = (sal_uInt16)pColGrpOption->GetNumber();
4703 					break;
4704 				case HTML_O_WIDTH:
4705 					pSaveStruct->nColGrpWidth = (sal_uInt16)pColGrpOption->GetNumber();
4706 					pSaveStruct->bRelColGrpWidth =
4707 						(pColGrpOption->GetString().Search('*') != STRING_NOTFOUND);
4708 					break;
4709 				case HTML_O_ALIGN:
4710 					pSaveStruct->eColGrpAdjust =
4711 						(SvxAdjust)pColGrpOption->GetEnum( aHTMLPAlignTable,
4712                                                 static_cast< sal_uInt16 >(pSaveStruct->eColGrpAdjust) );
4713 					break;
4714 				case HTML_O_VALIGN:
4715 					pSaveStruct->eColGrpVertOri =
4716                         pColGrpOption->GetEnum( aHTMLTblVAlignTable,
4717                                                 pSaveStruct->eColGrpVertOri );
4718 					break;
4719 				}
4720 			}
4721 		}
4722 		// ist beim ersten GetNextToken schon pending, muss bei
4723 		// wiederaufsetzen auf jeden Fall neu gelesen werden!
4724 		SaveState( 0 );
4725 	}
4726 
4727 	if( !nToken )
4728 		nToken = GetNextToken();	// naechstes Token
4729 
4730 	sal_Bool bDone = sal_False;
4731 	while( (IsParserWorking() && !bDone) || bPending )
4732 	{
4733 		SaveState( nToken );
4734 
4735 		nToken = FilterToken( nToken );
4736 
4737 		ASSERT( pPendStack || !bCallNextToken ||
4738 				pCurTable->GetContext() || pCurTable->HasParentSection(),
4739 				"Wo ist die Section gebieben?" );
4740 		if( !pPendStack && bCallNextToken &&
4741 			(pCurTable->GetContext() || pCurTable->HasParentSection()) )
4742 		{
4743 			// NextToken direkt aufrufen (z.B. um den Inhalt von
4744 			// Floating-Frames oder Applets zu ignorieren)
4745 			NextToken( nToken );
4746 		}
4747 		else switch( nToken )
4748 		{
4749 		case HTML_TABLE_ON:
4750 			if( !pCurTable->GetContext()  )
4751 			{
4752 				SkipToken( -1 );
4753 				bDone = sal_True;
4754 			}
4755 //			else
4756 //			{
4757 //				NextToken( nToken );
4758 //			}
4759 			break;
4760 		case HTML_COLGROUP_ON:
4761 		case HTML_THEAD_ON:
4762 		case HTML_TFOOT_ON:
4763 		case HTML_TBODY_ON:
4764 		case HTML_TABLEROW_ON:
4765 		case HTML_TABLE_OFF:
4766 			SkipToken( -1 );
4767 		case HTML_COLGROUP_OFF:
4768 			bDone = sal_True;
4769 			break;
4770 		case HTML_COL_ON:
4771 			{
4772 				sal_uInt16 nColSpan = 1;
4773 				sal_uInt16 nColWidth = pSaveStruct->nColGrpWidth;
4774 				sal_Bool bRelColWidth = pSaveStruct->bRelColGrpWidth;
4775 				SvxAdjust eColAdjust = pSaveStruct->eColGrpAdjust;
4776                 sal_Int16 eColVertOri = pSaveStruct->eColGrpVertOri;
4777 
4778 				const HTMLOptions *pColOptions = GetOptions();
4779 				for( sal_uInt16 i = pColOptions->Count(); i; )
4780 				{
4781 					const HTMLOption *pColOption = (*pColOptions)[--i];
4782 					switch( pColOption->GetToken() )
4783 					{
4784 					case HTML_O_ID:
4785 						InsertBookmark( pColOption->GetString() );
4786 						break;
4787 					case HTML_O_SPAN:
4788 						nColSpan = (sal_uInt16)pColOption->GetNumber();
4789 						break;
4790 					case HTML_O_WIDTH:
4791 						nColWidth = (sal_uInt16)pColOption->GetNumber();
4792 						bRelColWidth =
4793 							(pColOption->GetString().Search('*') != STRING_NOTFOUND);
4794 						break;
4795 					case HTML_O_ALIGN:
4796 						eColAdjust =
4797 							(SvxAdjust)pColOption->GetEnum( aHTMLPAlignTable,
4798                                                             static_cast< sal_uInt16 >(eColAdjust) );
4799 						break;
4800 					case HTML_O_VALIGN:
4801 						eColVertOri =
4802                             pColOption->GetEnum( aHTMLTblVAlignTable,
4803                                                         eColVertOri );
4804 						break;
4805 					}
4806 				}
4807 				pCurTable->InsertCol( nColSpan, nColWidth, bRelColWidth,
4808 									  eColAdjust, eColVertOri );
4809 
4810 				// die Angaben in <COLGRP> sollen ignoriert werden, wenn
4811 				// <COL>-Elemente existieren
4812 				pSaveStruct->nColGrpSpan = 0;
4813 			}
4814 			break;
4815 		case HTML_COL_OFF:
4816 			break;		// Ignorieren
4817 		case HTML_MULTICOL_ON:
4818 			// spaltige Rahmen koennen wir hier leider nicht einfuegen
4819 			break;
4820 		case HTML_TEXTTOKEN:
4821 			if( (pCurTable->GetContext() ||
4822 				 !pCurTable->HasParentSection()) &&
4823 				1==aToken.Len() && ' '==aToken.GetChar(0) )
4824 				break;
4825 		default:
4826 			pCurTable->MakeParentContents();
4827 			NextToken( nToken );
4828 		}
4829 
4830 		ASSERT( !bPending || !pPendStack,
4831 				"SwHTMLParser::BuildTableColGrp: Es gibt wieder einen Pend-Stack" );
4832 		bPending = sal_False;
4833 		if( IsParserWorking() )
4834 			SaveState( 0 );
4835 
4836 		if( !bDone )
4837 			nToken = GetNextToken();
4838 	}
4839 
4840 	if( SVPAR_PENDING == GetStatus() )
4841 	{
4842 		pPendStack = new SwPendingStack( HTML_COL_ON, pPendStack );
4843 		pPendStack->pData = pSaveStruct;
4844 	}
4845 	else
4846 	{
4847 		pSaveStruct->CloseColGroup( pCurTable );
4848 		delete pSaveStruct;
4849 	}
4850 }
4851 
4852 class _CaptionSaveStruct : public _SectionSaveStruct
4853 {
4854 	SwPosition aSavePos;
4855 	SwHTMLNumRuleInfo aNumRuleInfo; // gueltige Nummerierung
4856 
4857 public:
4858 
4859 	_HTMLAttrTable aAttrTab;		// und die Attribute
4860 
_CaptionSaveStruct(SwHTMLParser & rParser,const SwPosition & rPos)4861 	_CaptionSaveStruct( SwHTMLParser& rParser, const SwPosition& rPos ) :
4862 		_SectionSaveStruct( rParser ), aSavePos( rPos )
4863 	{
4864 		rParser.SaveAttrTab( aAttrTab );
4865 
4866 		// Die aktuelle Nummerierung wurde gerettet und muss nur
4867 		// noch beendet werden.
4868         aNumRuleInfo.Set( rParser.GetNumInfo() );
4869 		rParser.GetNumInfo().Clear();
4870 	}
4871 
GetPos() const4872 	const SwPosition& GetPos() const { return aSavePos; }
4873 
RestoreAll(SwHTMLParser & rParser)4874 	void RestoreAll( SwHTMLParser& rParser )
4875 	{
4876 		// Die alten Stack wiederherstellen
4877 		Restore( rParser );
4878 
4879 		// Die alte Attribut-Tabelle wiederherstellen
4880 		rParser.RestoreAttrTab( aAttrTab );
4881 
4882 		// Die alte Nummerierung wieder aufspannen
4883 		rParser.GetNumInfo().Set( aNumRuleInfo );
4884 	}
4885 
4886 	virtual ~_CaptionSaveStruct();
4887 };
4888 
~_CaptionSaveStruct()4889 _CaptionSaveStruct::~_CaptionSaveStruct()
4890 {}
4891 
BuildTableCaption(HTMLTable * pCurTable)4892 void SwHTMLParser::BuildTableCaption( HTMLTable *pCurTable )
4893 {
4894 	// <CAPTION> wurde bereits gelesen
4895 
4896 	if( !IsParserWorking() && !pPendStack )
4897 		return;
4898 
4899 	int nToken = 0;
4900 	_CaptionSaveStruct* pSaveStruct;
4901 
4902 	if( pPendStack )
4903 	{
4904 		pSaveStruct = (_CaptionSaveStruct*)pPendStack->pData;
4905 
4906 		SwPendingStack* pTmp = pPendStack->pNext;
4907 		delete pPendStack;
4908 		pPendStack = pTmp;
4909 		nToken = pPendStack ? pPendStack->nToken : GetSaveToken();
4910 		ASSERT( !pPendStack, "Wo kommt hier ein Pending-Stack her?" );
4911 
4912 		SaveState( nToken );
4913 	}
4914 	else
4915 	{
4916 		if( pTable->IsOverflowing() )
4917 		{
4918 			SaveState( 0 );
4919 			return;
4920 		}
4921 
4922 		sal_Bool bTop = sal_True;
4923 		const HTMLOptions *pHTMLOptions = GetOptions();
4924 		for ( sal_uInt16 i = pHTMLOptions->Count(); i; )
4925 		{
4926 			const HTMLOption *pOption = (*pHTMLOptions)[--i];
4927 			if( HTML_O_ALIGN == pOption->GetToken() )
4928 			{
4929 				if( pOption->GetString().EqualsIgnoreCaseAscii(OOO_STRING_SVTOOLS_HTML_VA_bottom))
4930 					bTop = sal_False;
4931 			}
4932 		}
4933 
4934 		// Alte PaM-Position retten.
4935 		pSaveStruct = new _CaptionSaveStruct( *this, *pPam->GetPoint() );
4936 
4937 		// Eine Text-Section im Icons-Bereich als Container fuer die
4938 		// Ueberschrift anlegen und PaM dort reinstellen.
4939 		const SwStartNode *pStNd;
4940 		if( pTable == pCurTable )
4941 			pStNd = InsertTempTableCaptionSection();
4942 		else
4943 			pStNd = InsertTableSection( RES_POOLCOLL_TEXT );
4944 
4945 		_HTMLAttrContext *pCntxt = new _HTMLAttrContext( HTML_CAPTION_ON );
4946 
4947 		// Tabellen-Ueberschriften sind immer zentriert.
4948         NewAttr( &aAttrTab.pAdjust, SvxAdjustItem(SVX_ADJUST_CENTER, RES_PARATR_ADJUST) );
4949 
4950 		_HTMLAttrs &rAttrs = pCntxt->GetAttrs();
4951 		rAttrs.Insert( aAttrTab.pAdjust, rAttrs.Count() );
4952 
4953 		PushContext( pCntxt );
4954 
4955 		// StartNode der Section an der Tabelle merken.
4956 		pCurTable->SetCaption( pStNd, bTop );
4957 
4958 		// ist beim ersten GetNextToken schon pending, muss bei
4959 		// wiederaufsetzen auf jeden Fall neu gelesen werden!
4960 		SaveState( 0 );
4961 	}
4962 
4963 	if( !nToken )
4964 		nToken = GetNextToken();	// naechstes Token
4965 
4966 	// </CAPTION> wird laut DTD benoetigt
4967 	sal_Bool bDone = sal_False;
4968 	while( IsParserWorking() && !bDone )
4969 	{
4970 		SaveState( nToken );
4971 
4972 		nToken = FilterToken( nToken );
4973 
4974 		switch( nToken )
4975 		{
4976 		case HTML_TABLE_ON:
4977 			if( !pPendStack )
4978 			{
4979 				pSaveStruct->pTable = pTable;
4980 				sal_Bool bHasToFly = pSaveStruct->pTable!=pCurTable;
4981 				BuildTable( pCurTable->GetTableAdjust( sal_True ),
4982 							sal_False, sal_True, sal_True, bHasToFly );
4983 			}
4984 			else
4985 			{
4986 				BuildTable( SVX_ADJUST_END );
4987 			}
4988 			if( SVPAR_PENDING != GetStatus() )
4989 			{
4990 				pTable = pSaveStruct->pTable;
4991 			}
4992 			break;
4993 		case HTML_TABLE_OFF:
4994 		case HTML_COLGROUP_ON:
4995 		case HTML_THEAD_ON:
4996 		case HTML_TFOOT_ON:
4997 		case HTML_TBODY_ON:
4998 		case HTML_TABLEROW_ON:
4999 			SkipToken( -1 );
5000 			bDone = sal_True;
5001 			break;
5002 
5003 		case HTML_CAPTION_OFF:
5004 			bDone = sal_True;
5005 			break;
5006 		default:
5007 			int nNxtToken = nToken;
5008 			if( pPendStack )
5009 			{
5010 				SwPendingStack* pTmp = pPendStack->pNext;
5011 				delete pPendStack;
5012 				pPendStack = pTmp;
5013 
5014 				ASSERT( !pTmp, "weiter kann es nicht gehen!" );
5015 				nNxtToken = 0;	// neu lesen
5016 			}
5017 
5018 			if( IsParserWorking() )
5019 				NextToken( nToken );
5020 			break;
5021 		}
5022 
5023 		if( IsParserWorking() )
5024 			SaveState( 0 );
5025 
5026 		if( !bDone )
5027 			nToken = GetNextToken();
5028 	}
5029 
5030 	if( SVPAR_PENDING==GetStatus() )
5031 	{
5032 		pPendStack = new SwPendingStack( HTML_CAPTION_ON, pPendStack );
5033 		pPendStack->pData = pSaveStruct;
5034 		return;
5035 	}
5036 
5037 	// Alle noch offenen Kontexte beenden
5038 	while( aContexts.Count() > nContextStAttrMin+1 )
5039 	{
5040 		_HTMLAttrContext *pCntxt = PopContext();
5041 		EndContext( pCntxt );
5042 		delete pCntxt;
5043 	}
5044 
5045 	// LF am Absatz-Ende entfernen
5046 	sal_Bool bLFStripped = StripTrailingLF() > 0;
5047 
5048 	if( pTable==pCurTable )
5049 	{
5050 		// Beim spaeteren verschieben der Beschriftung vor oder hinter
5051 		// die Tabelle wird der letzte Absatz nicht mitverschoben.
5052 		// Deshalb muss sich am Ende der Section immer ein leerer
5053 		// Absatz befinden.
5054 		if( pPam->GetPoint()->nContent.GetIndex() || bLFStripped )
5055 			AppendTxtNode( AM_NOSPACE );
5056 	}
5057 	else
5058 	{
5059 		// LFs am Absatz-Ende entfernen
5060 		if( !pPam->GetPoint()->nContent.GetIndex() && !bLFStripped )
5061 			StripTrailingPara();
5062 	}
5063 
5064 	// falls fuer die Zelle eine Ausrichtung gesetzt wurde, muessen
5065 	// wir die beenden
5066 	_HTMLAttrContext *pCntxt = PopContext();
5067 	EndContext( pCntxt );
5068 	delete pCntxt;
5069 
5070 	SetAttr( sal_False );
5071 
5072 	// Stacks und Attribut-Tabelle wiederherstellen
5073 	pSaveStruct->RestoreAll( *this );
5074 
5075 	// PaM wiederherstellen.
5076 	*pPam->GetPoint() = pSaveStruct->GetPos();
5077 
5078 	delete pSaveStruct;
5079 }
5080 
5081 class _TblSaveStruct : public SwPendingStackData
5082 {
5083 public:
5084 	HTMLTable *pCurTable;
5085 
_TblSaveStruct(HTMLTable * pCurTbl)5086 	_TblSaveStruct( HTMLTable *pCurTbl ) :
5087 		pCurTable( pCurTbl )
5088 	{}
5089 
5090 	virtual ~_TblSaveStruct();
5091 
5092 	// Aufbau der Tabelle anstossen und die Tabelle ggf. in einen
5093 	// Rahmen packen. Wenn sal_True zurueckgegeben wird muss noch ein
5094 	// Absatz eingefuegt werden!
5095 	void MakeTable( sal_uInt16 nWidth, SwPosition& rPos, SwDoc *pDoc );
5096 };
5097 
~_TblSaveStruct()5098 _TblSaveStruct::~_TblSaveStruct()
5099 {}
5100 
5101 
MakeTable(sal_uInt16 nWidth,SwPosition & rPos,SwDoc * pDoc)5102 void _TblSaveStruct::MakeTable( sal_uInt16 nWidth, SwPosition& rPos, SwDoc *pDoc )
5103 {
5104 	pCurTable->MakeTable( 0, nWidth );
5105 
5106 	_HTMLTableContext *pTCntxt = pCurTable->GetContext();
5107 	ASSERT( pTCntxt, "Wo ist der Tabellen-Kontext" );
5108 
5109 	SwTableNode *pTblNd = pTCntxt->GetTableNode();
5110 	ASSERT( pTblNd, "Wo ist der Tabellen-Node" );
5111 
5112 	if( pDoc->GetCurrentViewShell() && pTblNd )	//swmod 071108//swmod 071225
5113 	{
5114 		// Existiert schon ein Layout, dann muss an dieser Tabelle die
5115 		// BoxFrames neu erzeugt werden.
5116 
5117 		if( pTCntxt->GetFrmFmt() )
5118 		{
5119 			pTCntxt->GetFrmFmt()->DelFrms();
5120 			pTblNd->DelFrms();
5121 			pTCntxt->GetFrmFmt()->MakeFrms();
5122 		}
5123 		else
5124 		{
5125 			pTblNd->DelFrms();
5126 			SwNodeIndex aIdx( *pTblNd->EndOfSectionNode(), 1 );
5127 			ASSERT( aIdx.GetIndex() <= pTCntxt->GetPos()->nNode.GetIndex(),
5128 					"unerwarteter Node fuer das Tabellen-Layout" );
5129 			pTblNd->MakeFrms( &aIdx );
5130 		}
5131 	}
5132 
5133 	rPos = *pTCntxt->GetPos();
5134 }
5135 
5136 
HTMLTableOptions(const HTMLOptions * pOptions,SvxAdjust eParentAdjust)5137 HTMLTableOptions::HTMLTableOptions( const HTMLOptions *pOptions,
5138 									SvxAdjust eParentAdjust ) :
5139 	nCols( 0 ),
5140 	nWidth( 0 ), nHeight( 0 ),
5141 	nCellPadding( USHRT_MAX ), nCellSpacing( USHRT_MAX ),
5142 	nBorder( USHRT_MAX ),
5143 	nHSpace( 0 ), nVSpace( 0 ),
5144     eAdjust( eParentAdjust ), eVertOri( text::VertOrientation::CENTER ),
5145 	eFrame( HTML_TF_VOID ), eRules( HTML_TR_NONE ),
5146 	bPrcWidth( sal_False ),
5147 	bTableAdjust( sal_False ),
5148 	bBGColor( sal_False ),
5149 	aBorderColor( COL_GRAY )
5150 {
5151 	sal_Bool bBorderColor = sal_False;
5152 	sal_Bool bHasFrame = sal_False, bHasRules = sal_False;
5153 
5154 	for( sal_uInt16 i = pOptions->Count(); i; )
5155 	{
5156 		const HTMLOption *pOption = (*pOptions)[--i];
5157 		switch( pOption->GetToken() )
5158 		{
5159 		case HTML_O_ID:
5160 			aId = pOption->GetString();
5161 			break;
5162 		case HTML_O_COLS:
5163 			nCols = (sal_uInt16)pOption->GetNumber();
5164 			break;
5165 		case HTML_O_WIDTH:
5166 			nWidth = (sal_uInt16)pOption->GetNumber();
5167 			bPrcWidth = (pOption->GetString().Search('%') != STRING_NOTFOUND);
5168 			if( bPrcWidth && nWidth>100 )
5169 				nWidth = 100;
5170 			break;
5171 		case HTML_O_HEIGHT:
5172 			nHeight = (sal_uInt16)pOption->GetNumber();
5173 			if( pOption->GetString().Search('%') != STRING_NOTFOUND )
5174 				nHeight = 0;	// keine %-Angaben benutzen!!!
5175 			break;
5176 		case HTML_O_CELLPADDING:
5177 			nCellPadding = (sal_uInt16)pOption->GetNumber();
5178 			break;
5179 		case HTML_O_CELLSPACING:
5180 			nCellSpacing = (sal_uInt16)pOption->GetNumber();
5181 			break;
5182 		case HTML_O_ALIGN:
5183 			{
5184                 sal_uInt16 nAdjust = static_cast< sal_uInt16 >(eAdjust);
5185 				if( pOption->GetEnum( nAdjust, aHTMLPAlignTable ) )
5186 				{
5187 					eAdjust = (SvxAdjust)nAdjust;
5188 					bTableAdjust = sal_True;
5189 				}
5190 			}
5191 			break;
5192 		case HTML_O_VALIGN:
5193             eVertOri = pOption->GetEnum( aHTMLTblVAlignTable, eVertOri );
5194 			break;
5195 		case HTML_O_BORDER:
5196 			// BORDER und BORDER=BORDER wie BORDER=1 behandeln
5197 			if( pOption->GetString().Len() &&
5198 				!pOption->GetString().EqualsIgnoreCaseAscii(OOO_STRING_SVTOOLS_HTML_O_border) )
5199 				nBorder = (sal_uInt16)pOption->GetNumber();
5200 			else
5201 				nBorder = 1;
5202 
5203 			if( !bHasFrame )
5204 				eFrame = ( nBorder ? HTML_TF_BOX : HTML_TF_VOID );
5205 			if( !bHasRules )
5206 				eRules = ( nBorder ? HTML_TR_ALL : HTML_TR_NONE );
5207 			break;
5208 		case HTML_O_FRAME:
5209 			eFrame = pOption->GetTableFrame();
5210 			bHasFrame = sal_True;
5211 			break;
5212 		case HTML_O_RULES:
5213 			eRules = pOption->GetTableRules();
5214 			bHasRules = sal_True;
5215 			break;
5216 		case HTML_O_BGCOLOR:
5217 			// Leere BGCOLOR bei <TABLE>, <TR> und <TD>/<TH> wie Netscape
5218 			// ignorieren, bei allen anderen Tags *wirklich* nicht.
5219 			if( pOption->GetString().Len() )
5220 			{
5221 				pOption->GetColor( aBGColor );
5222 				bBGColor = sal_True;
5223 			}
5224 			break;
5225 		case HTML_O_BACKGROUND:
5226 			aBGImage = pOption->GetString();
5227 			break;
5228 		case HTML_O_BORDERCOLOR:
5229 			pOption->GetColor( aBorderColor );
5230 			bBorderColor = sal_True;
5231 			break;
5232 		case HTML_O_BORDERCOLORDARK:
5233 			if( !bBorderColor )
5234 				pOption->GetColor( aBorderColor );
5235 			break;
5236 		case HTML_O_STYLE:
5237 			aStyle = pOption->GetString();
5238 			break;
5239 		case HTML_O_CLASS:
5240 			aClass = pOption->GetString();
5241 			break;
5242 		case HTML_O_DIR:
5243 			aDir = pOption->GetString();
5244 			break;
5245 		case HTML_O_HSPACE:
5246 			nHSpace = (sal_uInt16)pOption->GetNumber();
5247 			break;
5248 		case HTML_O_VSPACE:
5249 			nVSpace = (sal_uInt16)pOption->GetNumber();
5250 			break;
5251 		}
5252 	}
5253 
5254 	if( nCols && !nWidth )
5255 	{
5256 		nWidth = 100;
5257 		bPrcWidth = sal_True;
5258 	}
5259 
5260 	// Wenn BORDER=0 oder kein BORDER gegeben ist, dann darf es auch
5261 	// keine Umrandung geben
5262 	if( 0==nBorder || USHRT_MAX==nBorder )
5263 	{
5264 		eFrame = HTML_TF_VOID;
5265 		eRules = HTML_TR_NONE;
5266 	}
5267 }
5268 
5269 
BuildTable(SvxAdjust eParentAdjust,sal_Bool bIsParentHead,sal_Bool bHasParentSection,sal_Bool bMakeTopSubTable,sal_Bool bHasToFly)5270 HTMLTable *SwHTMLParser::BuildTable( SvxAdjust eParentAdjust,
5271 									 sal_Bool bIsParentHead,
5272 									 sal_Bool bHasParentSection,
5273 									 sal_Bool bMakeTopSubTable,
5274 									 sal_Bool bHasToFly )
5275 {
5276 	if( !IsParserWorking() && !pPendStack )
5277 		return 0;
5278 
5279 	int nToken = 0;
5280 	sal_Bool bPending = sal_False;
5281 	_TblSaveStruct* pSaveStruct;
5282 
5283 	if( pPendStack )
5284 	{
5285 		pSaveStruct = (_TblSaveStruct*)pPendStack->pData;
5286 
5287 		SwPendingStack* pTmp = pPendStack->pNext;
5288 		delete pPendStack;
5289 		pPendStack = pTmp;
5290 		nToken = pPendStack ? pPendStack->nToken : GetSaveToken();
5291 		bPending = SVPAR_ERROR == eState && pPendStack != 0;
5292 
5293 		SaveState( nToken );
5294 	}
5295 	else
5296 	{
5297 		pTable = 0;
5298 		HTMLTableOptions *pTblOptions =
5299 			new HTMLTableOptions( GetOptions(), eParentAdjust );
5300 
5301 		if( pTblOptions->aId.Len() )
5302 			InsertBookmark( pTblOptions->aId );
5303 
5304 		HTMLTable *pCurTable = new HTMLTable( this, pTable,
5305 											  bIsParentHead,
5306 											  bHasParentSection,
5307 											  bMakeTopSubTable,
5308 											  bHasToFly,
5309 											  pTblOptions );
5310 		if( !pTable )
5311 			pTable = pCurTable;
5312 
5313 		pSaveStruct = new _TblSaveStruct( pCurTable );
5314 
5315 		delete pTblOptions;
5316 
5317 		// ist beim ersten GetNextToken schon pending, muss bei
5318 		// wiederaufsetzen auf jeden Fall neu gelesen werden!
5319 		SaveState( 0 );
5320 	}
5321 
5322 	HTMLTable *pCurTable = pSaveStruct->pCurTable;
5323 
5324 	// </TABLE> wird laut DTD benoetigt
5325 	if( !nToken )
5326 		nToken = GetNextToken();	// naechstes Token
5327 
5328 	sal_Bool bDone = sal_False;
5329 	while( (IsParserWorking() && !bDone) || bPending )
5330 	{
5331 		SaveState( nToken );
5332 
5333 		nToken = FilterToken( nToken );
5334 
5335 		ASSERT( pPendStack || !bCallNextToken ||
5336 				pCurTable->GetContext() || pCurTable->HasParentSection(),
5337 				"Wo ist die Section gebieben?" );
5338 		if( !pPendStack && bCallNextToken &&
5339 			(pCurTable->GetContext() || pCurTable->HasParentSection()) )
5340 		{
5341 			// NextToken direkt aufrufen (z.B. um den Inhalt von
5342 			// Floating-Frames oder Applets zu ignorieren)
5343 			NextToken( nToken );
5344 		}
5345 		else switch( nToken )
5346 		{
5347 		case HTML_TABLE_ON:
5348 			if( !pCurTable->GetContext() )
5349 			{
5350 				// Wenn noch keine Tabelle eingefuegt wurde,
5351 				// die naechste Tabelle lesen
5352 				SkipToken( -1 );
5353 				bDone = sal_True;
5354 			}
5355 //			else
5356 //			{
5357 //				NextToken( nToken );
5358 //			}
5359 			break;
5360 		case HTML_TABLE_OFF:
5361 			bDone = sal_True;
5362 			break;
5363 		case HTML_CAPTION_ON:
5364 			BuildTableCaption( pCurTable );
5365 			bDone = pTable->IsOverflowing();
5366 			break;
5367 		case HTML_COL_ON:
5368 			SkipToken( -1 );
5369 			BuildTableColGroup( pCurTable, sal_False );
5370 			break;
5371 		case HTML_COLGROUP_ON:
5372 			BuildTableColGroup( pCurTable, sal_True );
5373 			break;
5374 		case HTML_TABLEROW_ON:
5375 		case HTML_TABLEHEADER_ON:
5376 		case HTML_TABLEDATA_ON:
5377 			SkipToken( -1 );
5378 			BuildTableSection( pCurTable, sal_False, sal_False );
5379 			bDone = pTable->IsOverflowing();
5380 			break;
5381 		case HTML_THEAD_ON:
5382 		case HTML_TFOOT_ON:
5383 		case HTML_TBODY_ON:
5384 			BuildTableSection( pCurTable, sal_True, HTML_THEAD_ON==nToken );
5385 			bDone = pTable->IsOverflowing();
5386 			break;
5387 		case HTML_MULTICOL_ON:
5388 			// spaltige Rahmen koennen wir hier leider nicht einfuegen
5389 			break;
5390 		case HTML_FORM_ON:
5391 			NewForm( sal_False );	// keinen neuen Absatz aufmachen!
5392 			break;
5393 		case HTML_FORM_OFF:
5394 			EndForm( sal_False );	// keinen neuen Absatz aufmachen!
5395 			break;
5396 		case HTML_TEXTTOKEN:
5397 			// Blank-Strings sind u. U. eine Folge von CR+LF und kein Text
5398 			if( (pCurTable->GetContext() ||
5399 				 !pCurTable->HasParentSection()) &&
5400 				1==aToken.Len() && ' '==aToken.GetChar(0) )
5401 				break;
5402 		default:
5403 			pCurTable->MakeParentContents();
5404 			NextToken( nToken );
5405 			break;
5406 		}
5407 
5408 		ASSERT( !bPending || !pPendStack,
5409 				"SwHTMLParser::BuildTable: Es gibt wieder einen Pend-Stack" );
5410 		bPending = sal_False;
5411 		if( IsParserWorking() )
5412 			SaveState( 0 );
5413 
5414 		if( !bDone )
5415 			nToken = GetNextToken();
5416 	}
5417 
5418 	if( SVPAR_PENDING == GetStatus() )
5419 	{
5420 		pPendStack = new SwPendingStack( HTML_TABLE_ON, pPendStack );
5421 		pPendStack->pData = pSaveStruct;
5422 		return 0;
5423 	}
5424 
5425 	_HTMLTableContext *pTCntxt = pCurTable->GetContext();
5426 	if( pTCntxt )
5427 	{
5428 		// Die Tabelle wurde auch angelegt
5429 
5430 		// Tabellen-Struktur anpassen
5431 		pCurTable->CloseTable();
5432 
5433 		// ausserhalb von Zellen begonnene Kontexte beenden
5434 		// muss vor(!) dem Umsetzten der Attribut Tabelle existieren,
5435 		// weil die aktuelle danach nicht mehr existiert
5436 		while( aContexts.Count() > nContextStAttrMin )
5437 		{
5438 			_HTMLAttrContext *pCntxt = PopContext();
5439 			ClearContext( pCntxt );
5440 			delete pCntxt;
5441 		}
5442 
5443 		nContextStMin = pTCntxt->GetContextStMin();
5444 		nContextStAttrMin = pTCntxt->GetContextStAttrMin();
5445 
5446 		if( pTable==pCurTable )
5447 		{
5448 			// Tabellen-Beschriftung setzen
5449 			const SwStartNode *pCapStNd = pTable->GetCaptionStartNode();
5450 			if( pCapStNd )
5451 			{
5452 				// Der letzte Absatz der Section wird nie mitkopiert. Deshalb
5453 				// muss die Section mindestens zwei Absaetze enthalten.
5454 
5455 				if( pCapStNd->EndOfSectionIndex() - pCapStNd->GetIndex() > 2 )
5456 				{
5457 					// Start-Node und letzten Absatz nicht mitkopieren.
5458 					SwNodeRange aSrcRg( *pCapStNd, 1,
5459 									*pCapStNd->EndOfSectionNode(), -1 );
5460 
5461 					sal_Bool bTop = pTable->IsTopCaption();
5462 					SwStartNode *pTblStNd = pTCntxt->GetTableNode();
5463 
5464 					ASSERT( pTblStNd, "Wo ist der Tabellen-Node" );
5465 					ASSERT( pTblStNd==pPam->GetNode()->FindTableNode(),
5466 							"Stehen wir in der falschen Tabelle?" );
5467 
5468 					SwNode* pNd;
5469 					if( bTop )
5470 						pNd = pTblStNd;
5471 					else
5472 						pNd = pTblStNd->EndOfSectionNode();
5473 					SwNodeIndex aDstIdx( *pNd, bTop ? 0 : 1 );
5474 
5475                     pDoc->MoveNodeRange( aSrcRg, aDstIdx,
5476                         IDocumentContentOperations::DOC_MOVEDEFAULT );
5477 
5478 					// Wenn die Caption vor der Tabelle eingefuegt wurde muss
5479 					// eine an der Tabelle gesetzte Seitenvorlage noch in den
5480 					// ersten Absatz der Ueberschrift verschoben werden.
5481 					// Ausserdem muessen alle gemerkten Indizes, die auf den
5482 					// Tabellen-Node zeigen noch verschoben werden.
5483 					if( bTop )
5484 					{
5485 						MovePageDescAttrs( pTblStNd, aSrcRg.aStart.GetIndex(),
5486 										   sal_False );
5487 					}
5488 				}
5489 
5490 				// Die Section wird jetzt nicht mehr gebraucht.
5491 				pPam->SetMark();
5492 				pPam->DeleteMark();
5493 				pDoc->DeleteSection( (SwStartNode *)pCapStNd );
5494 				pTable->SetCaption( 0, sal_False );
5495 			}
5496 
5497 			// SwTable aufbereiten
5498 			sal_uInt16 nBrowseWidth = (sal_uInt16)GetCurrentBrowseWidth();
5499 			pSaveStruct->MakeTable( nBrowseWidth, *pPam->GetPoint(), pDoc );
5500 
5501 #ifdef TEST_RESIZE
5502 			const SwTable *pSwTable = pTable->GetSwTable();
5503 			SwHTMLTableLayout *pLayoutInfo =
5504 				pSwTable ? ((SwTable *)pSwTable)->GetHTMLTableLayout() : 0;
5505 			if( pLayoutInfo )
5506 			{
5507 				ViewShell *pVSh = CheckActionViewShell();
5508 				if( pVSh )
5509 				{
5510 					CallEndAction( sal_False, sal_False );
5511 					CallStartAction( pVSh, sal_False );
5512 
5513 					sal_uInt16 nNewBrowseWidth =
5514 						(sal_uInt16)GetCurrentBrowseWidth();
5515 					if( nBrowseWidth != nNewBrowseWidth )
5516 						pLayoutInfo->Resize( nNewBrowseWidth );
5517 				}
5518 			}
5519 #endif
5520 		}
5521 
5522 		GetNumInfo().Set( pTCntxt->GetNumInfo() );
5523 		pTCntxt->RestorePREListingXMP( *this );
5524 		RestoreAttrTab( pTCntxt->aAttrTab );
5525 
5526 		if( pTable==pCurTable )
5527 		{
5528 			// oberen Absatz-Abstand einstellen
5529 			bUpperSpace = sal_True;
5530 			SetTxtCollAttrs();
5531 
5532 			nParaCnt = nParaCnt - Min(nParaCnt, pTCntxt->GetTableNode()->GetTable().GetTabSortBoxes().Count());
5533 
5534 			// ggfs. eine Tabelle anspringen
5535 			if( JUMPTO_TABLE == eJumpTo && pTable->GetSwTable() &&
5536 				pTable->GetSwTable()->GetFrmFmt()->GetName() == sJmpMark )
5537 			{
5538 				bChkJumpMark = sal_True;
5539 				eJumpTo = JUMPTO_NONE;
5540 			}
5541 
5542 			// fix #37886#: Wenn Import abgebrochen wurde kein erneutes Show
5543 			// aufrufen, weil die ViewShell schon geloescht wurde!
5544 			// fix #41669#: Genuegt nicht. Auch im ACCEPTING_STATE darf
5545 			// kein Show aufgerufen werden, weil sonst waehrend des
5546 			// Reschedules der Parser zerstoert wird, wenn noch ein
5547 			// DataAvailable-Link kommt. Deshalb: Nur im WORKING-State.
5548 			if( !nParaCnt && SVPAR_WORKING == GetStatus() )
5549 				Show();
5550 		}
5551 	}
5552 	else if( pTable==pCurTable )
5553 	{
5554 		// Es wurde gar keine Tabelle gelesen.
5555 
5556 		// Dann muss eine evtl. gelesene Beschriftung noch geloescht werden.
5557 		const SwStartNode *pCapStNd = pCurTable->GetCaptionStartNode();
5558 		if( pCapStNd )
5559 		{
5560 			pPam->SetMark();
5561 			pPam->DeleteMark();
5562 			pDoc->DeleteSection( (SwStartNode *)pCapStNd );
5563 			pCurTable->SetCaption( 0, sal_False );
5564 		}
5565 	}
5566 
5567 	if( pTable == pCurTable )
5568 	{
5569 		delete pSaveStruct->pCurTable;
5570 		pSaveStruct->pCurTable = 0;
5571 		pTable = 0;
5572 	}
5573 
5574 	HTMLTable* pRetTbl = pSaveStruct->pCurTable;
5575 	delete pSaveStruct;
5576 
5577 	return pRetTbl;
5578 }
5579 
5580