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