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