|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 #ifndef CellData_h__ |
|
6 #define CellData_h__ |
|
7 |
|
8 #include "nsISupports.h" |
|
9 #include "nsCoord.h" |
|
10 #include "mozilla/gfx/Types.h" |
|
11 #include <stdint.h> |
|
12 |
|
13 class nsTableCellFrame; |
|
14 class nsCellMap; |
|
15 class BCCellData; |
|
16 |
|
17 |
|
18 #define MAX_ROWSPAN 65534 // the cellmap can not handle more. |
|
19 #define MAX_COLSPAN 1000 // limit as IE and opera do. If this ever changes, |
|
20 // change COL_SPAN_OFFSET/COL_SPAN_SHIFT accordingly. |
|
21 |
|
22 /** |
|
23 * Data stored by nsCellMap to rationalize rowspan and colspan cells. |
|
24 */ |
|
25 class CellData |
|
26 { |
|
27 public: |
|
28 /** Initialize the mOrigCell pointer |
|
29 * @param aOrigCell the table cell frame which will be stored in mOrigCell. |
|
30 */ |
|
31 void Init(nsTableCellFrame* aCellFrame); |
|
32 |
|
33 /** does a cell originate from here |
|
34 * @return is true if a cell corresponds to this cellmap entry |
|
35 */ |
|
36 bool IsOrig() const; |
|
37 |
|
38 /** is the celldata valid |
|
39 * @return is true if no cell originates and the cell is not spanned by |
|
40 * a row- or colspan. mBits are 0 in this case and mOrigCell is |
|
41 * nullptr |
|
42 */ |
|
43 bool IsDead() const; |
|
44 |
|
45 /** is the entry spanned by row- or a colspan |
|
46 * @return is true if the entry is spanned by a row- or colspan |
|
47 */ |
|
48 bool IsSpan() const; |
|
49 |
|
50 /** is the entry spanned by rowspan |
|
51 * @return is true if the entry is spanned by a rowspan |
|
52 */ |
|
53 bool IsRowSpan() const; |
|
54 |
|
55 /** is the entry spanned by a zero rowspan |
|
56 * zero rowspans span all cells starting from the originating cell down to |
|
57 * the end of the rowgroup or a cell originating in the same column |
|
58 * @return is true if the entry is spanned by a zero rowspan |
|
59 */ |
|
60 bool IsZeroRowSpan() const; |
|
61 |
|
62 /** mark the current entry as spanned by a zero rowspan |
|
63 * @param aIsZero if true mark the entry as covered by a zero rowspan |
|
64 */ |
|
65 void SetZeroRowSpan(bool aIsZero); |
|
66 |
|
67 /** get the distance from the current entry to the corresponding origin of the rowspan |
|
68 * @return containing the distance in the column to the originating cell |
|
69 */ |
|
70 uint32_t GetRowSpanOffset() const; |
|
71 |
|
72 /** set the distance from the current entry to the corresponding origin of the rowspan |
|
73 * @param the distance in the column to the originating cell |
|
74 */ |
|
75 void SetRowSpanOffset(uint32_t aSpan); |
|
76 |
|
77 /** is the entry spanned by colspan |
|
78 * @return is true if the entry is spanned by a colspan |
|
79 */ |
|
80 bool IsColSpan() const; |
|
81 |
|
82 /** is the entry spanned by a zero colspan |
|
83 * zero colspans span all cells starting from the originating cell towards |
|
84 * the end of the colgroup or a cell originating in the same row |
|
85 * or a rowspanned entry |
|
86 * @return is true if the entry is spanned by a zero colspan |
|
87 */ |
|
88 bool IsZeroColSpan() const; |
|
89 |
|
90 /** mark the current entry as spanned by a zero colspan |
|
91 * @param aIsZero if true mark the entry as covered by a zero colspan |
|
92 */ |
|
93 void SetZeroColSpan(bool aIsZero); |
|
94 |
|
95 /** get the distance from the current entry to the corresponding origin of the colspan |
|
96 * @return containing the distance in the row to the originating cell |
|
97 */ |
|
98 uint32_t GetColSpanOffset() const; |
|
99 |
|
100 /** set the distance from the current entry to the corresponding origin of the colspan |
|
101 * @param the distance in the column to the originating cell |
|
102 */ |
|
103 void SetColSpanOffset(uint32_t aSpan); |
|
104 |
|
105 /** is the entry spanned by a row- and a colspan |
|
106 * @return is true if the entry is spanned by a row- and a colspan |
|
107 */ |
|
108 bool IsOverlap() const; |
|
109 |
|
110 /** mark the current entry as spanned by a row- and a colspan |
|
111 * @param aOverlap if true mark the entry as covered by a row- and a colspan |
|
112 */ |
|
113 void SetOverlap(bool aOverlap); |
|
114 |
|
115 /** get the table cell frame for this entry |
|
116 * @return a pointer to the cellframe, this will be nullptr when the entry |
|
117 * is only a spanned entry |
|
118 */ |
|
119 nsTableCellFrame* GetCellFrame() const; |
|
120 |
|
121 private: |
|
122 friend class nsCellMap; |
|
123 friend class BCCellData; |
|
124 |
|
125 /** constructor. |
|
126 * @param aOrigCell the table cell frame which will be stored in mOrigCell. |
|
127 */ |
|
128 CellData(nsTableCellFrame* aOrigCell); // implemented in nsCellMap.cpp |
|
129 |
|
130 /** destructor */ |
|
131 ~CellData(); // implemented in nsCellMap.cpp |
|
132 |
|
133 protected: |
|
134 |
|
135 // this union relies on the assumption that an object (not primitive type) does |
|
136 // not start on an odd bit boundary. If mSpan is 0 then mOrigCell is in effect |
|
137 // and the data does not represent a span. If mSpan is 1, then mBits is in |
|
138 // effect and the data represents a span. |
|
139 // mBits must match the size of mOrigCell on both 32- and 64-bit platforms. |
|
140 union { |
|
141 nsTableCellFrame* mOrigCell; |
|
142 uintptr_t mBits; |
|
143 }; |
|
144 }; |
|
145 |
|
146 // Border Collapsing Cell Data |
|
147 enum BCBorderOwner |
|
148 { |
|
149 eTableOwner = 0, |
|
150 eColGroupOwner = 1, |
|
151 eAjaColGroupOwner = 2, // col group to the left |
|
152 eColOwner = 3, |
|
153 eAjaColOwner = 4, // col to the left |
|
154 eRowGroupOwner = 5, |
|
155 eAjaRowGroupOwner = 6, // row group above |
|
156 eRowOwner = 7, |
|
157 eAjaRowOwner = 8, // row above |
|
158 eCellOwner = 9, |
|
159 eAjaCellOwner = 10 // cell to the top or to the left |
|
160 }; |
|
161 |
|
162 typedef uint16_t BCPixelSize; |
|
163 |
|
164 // These are the max sizes that are stored. If they are exceeded, then the max is stored and |
|
165 // the actual value is computed when needed. |
|
166 #define MAX_BORDER_WIDTH nscoord((1u << (sizeof(BCPixelSize) * 8)) - 1) |
|
167 |
|
168 static inline nscoord |
|
169 BC_BORDER_TOP_HALF_COORD(int32_t p2t, uint16_t px) { return (px - px / 2) * p2t; } |
|
170 static inline nscoord |
|
171 BC_BORDER_RIGHT_HALF_COORD(int32_t p2t, uint16_t px) { return ( px / 2) * p2t; } |
|
172 static inline nscoord |
|
173 BC_BORDER_BOTTOM_HALF_COORD(int32_t p2t, uint16_t px) { return ( px / 2) * p2t; } |
|
174 static inline nscoord |
|
175 BC_BORDER_LEFT_HALF_COORD(int32_t p2t, uint16_t px) { return (px - px / 2) * p2t; } |
|
176 |
|
177 #define BC_BORDER_TOP_HALF(px) ((px) - (px) / 2) |
|
178 #define BC_BORDER_RIGHT_HALF(px) ((px) / 2) |
|
179 #define BC_BORDER_BOTTOM_HALF(px) ((px) / 2) |
|
180 #define BC_BORDER_LEFT_HALF(px) ((px) - (px) / 2) |
|
181 |
|
182 // BCData stores the top and left border info and the corner connecting the two. |
|
183 class BCData |
|
184 { |
|
185 public: |
|
186 BCData(); |
|
187 |
|
188 ~BCData(); |
|
189 |
|
190 nscoord GetLeftEdge(BCBorderOwner& aOwner, |
|
191 bool& aStart) const; |
|
192 |
|
193 void SetLeftEdge(BCBorderOwner aOwner, |
|
194 nscoord aSize, |
|
195 bool aStart); |
|
196 |
|
197 nscoord GetTopEdge(BCBorderOwner& aOwner, |
|
198 bool& aStart) const; |
|
199 |
|
200 void SetTopEdge(BCBorderOwner aOwner, |
|
201 nscoord aSize, |
|
202 bool aStart); |
|
203 |
|
204 BCPixelSize GetCorner(mozilla::css::Side& aCornerOwner, |
|
205 bool& aBevel) const; |
|
206 |
|
207 void SetCorner(BCPixelSize aSubSize, |
|
208 mozilla::css::Side aOwner, |
|
209 bool aBevel); |
|
210 |
|
211 bool IsLeftStart() const; |
|
212 |
|
213 void SetLeftStart(bool aValue); |
|
214 |
|
215 bool IsTopStart() const; |
|
216 |
|
217 void SetTopStart(bool aValue); |
|
218 |
|
219 |
|
220 protected: |
|
221 BCPixelSize mLeftSize; // size in pixels of left border |
|
222 BCPixelSize mTopSize; // size in pixels of top border |
|
223 BCPixelSize mCornerSubSize; // size of the largest border not in the |
|
224 // dominant plane (for example, if corner is |
|
225 // owned by the segment to its top or bottom, |
|
226 // then the size is the max of the border |
|
227 // sizes of the segments to its left or right. |
|
228 unsigned mLeftOwner: 4; // owner of left border |
|
229 unsigned mTopOwner: 4; // owner of top border |
|
230 unsigned mLeftStart: 1; // set if this is the start of a vertical border segment |
|
231 unsigned mTopStart: 1; // set if this is the start of a horizontal border segment |
|
232 unsigned mCornerSide: 2; // mozilla::css::Side of the owner of the upper left corner relative to the corner |
|
233 unsigned mCornerBevel: 1; // is the corner beveled (only two segments, perpendicular, not dashed or dotted). |
|
234 }; |
|
235 |
|
236 // BCCellData entries replace CellData entries in the cell map if the border collapsing model is in |
|
237 // effect. BCData for a row and col entry contains the left and top borders of cell at that row and |
|
238 // col and the corner connecting the two. The right borders of the cells in the last col and the bottom |
|
239 // borders of the last row are stored in separate BCData entries in the cell map. |
|
240 class BCCellData : public CellData |
|
241 { |
|
242 public: |
|
243 BCCellData(nsTableCellFrame* aOrigCell); |
|
244 ~BCCellData(); |
|
245 |
|
246 BCData mData; |
|
247 }; |
|
248 |
|
249 |
|
250 // The layout of a celldata is as follows. The top 10 bits are the colspan |
|
251 // offset (which is enough to represent our allowed values 1-1000 for colspan). |
|
252 // Then there are three bits of flags. Then 16 bits of rowspan offset (which |
|
253 // lets us represent numbers up to 65535. Then another 3 bits of flags. |
|
254 |
|
255 // num bits to shift right to get right aligned col span |
|
256 #define COL_SPAN_SHIFT 22 |
|
257 // num bits to shift right to get right aligned row span |
|
258 #define ROW_SPAN_SHIFT 3 |
|
259 |
|
260 // the col offset to the data containing the original cell. |
|
261 #define COL_SPAN_OFFSET (0x3FF << COL_SPAN_SHIFT) |
|
262 // the row offset to the data containing the original cell |
|
263 #define ROW_SPAN_OFFSET (0xFFFF << ROW_SPAN_SHIFT) |
|
264 |
|
265 // And the flags |
|
266 #define SPAN 0x00000001 // there a row or col span |
|
267 #define ROW_SPAN 0x00000002 // there is a row span |
|
268 #define ROW_SPAN_0 0x00000004 // the row span is 0 |
|
269 #define COL_SPAN (1 << (COL_SPAN_SHIFT - 3)) // there is a col span |
|
270 #define COL_SPAN_0 (1 << (COL_SPAN_SHIFT - 2)) // the col span is 0 |
|
271 #define OVERLAP (1 << (COL_SPAN_SHIFT - 1)) // there is a row span and |
|
272 // col span but not by |
|
273 // same cell |
|
274 |
|
275 inline nsTableCellFrame* CellData::GetCellFrame() const |
|
276 { |
|
277 if (SPAN != (SPAN & mBits)) { |
|
278 return mOrigCell; |
|
279 } |
|
280 return nullptr; |
|
281 } |
|
282 |
|
283 inline void CellData::Init(nsTableCellFrame* aCellFrame) |
|
284 { |
|
285 mOrigCell = aCellFrame; |
|
286 } |
|
287 |
|
288 inline bool CellData::IsOrig() const |
|
289 { |
|
290 return ((nullptr != mOrigCell) && (SPAN != (SPAN & mBits))); |
|
291 } |
|
292 |
|
293 inline bool CellData::IsDead() const |
|
294 { |
|
295 return (0 == mBits); |
|
296 } |
|
297 |
|
298 inline bool CellData::IsSpan() const |
|
299 { |
|
300 return (SPAN == (SPAN & mBits)); |
|
301 } |
|
302 |
|
303 inline bool CellData::IsRowSpan() const |
|
304 { |
|
305 return (SPAN == (SPAN & mBits)) && |
|
306 (ROW_SPAN == (ROW_SPAN & mBits)); |
|
307 } |
|
308 |
|
309 inline bool CellData::IsZeroRowSpan() const |
|
310 { |
|
311 return (SPAN == (SPAN & mBits)) && |
|
312 (ROW_SPAN == (ROW_SPAN & mBits)) && |
|
313 (ROW_SPAN_0 == (ROW_SPAN_0 & mBits)); |
|
314 } |
|
315 |
|
316 inline void CellData::SetZeroRowSpan(bool aIsZeroSpan) |
|
317 { |
|
318 if (SPAN == (SPAN & mBits)) { |
|
319 if (aIsZeroSpan) { |
|
320 mBits |= ROW_SPAN_0; |
|
321 } |
|
322 else { |
|
323 mBits &= ~ROW_SPAN_0; |
|
324 } |
|
325 } |
|
326 } |
|
327 |
|
328 inline uint32_t CellData::GetRowSpanOffset() const |
|
329 { |
|
330 if ((SPAN == (SPAN & mBits)) && ((ROW_SPAN == (ROW_SPAN & mBits)))) { |
|
331 return (uint32_t)((mBits & ROW_SPAN_OFFSET) >> ROW_SPAN_SHIFT); |
|
332 } |
|
333 return 0; |
|
334 } |
|
335 |
|
336 inline void CellData::SetRowSpanOffset(uint32_t aSpan) |
|
337 { |
|
338 mBits &= ~ROW_SPAN_OFFSET; |
|
339 mBits |= (aSpan << ROW_SPAN_SHIFT); |
|
340 mBits |= SPAN; |
|
341 mBits |= ROW_SPAN; |
|
342 } |
|
343 |
|
344 inline bool CellData::IsColSpan() const |
|
345 { |
|
346 return (SPAN == (SPAN & mBits)) && |
|
347 (COL_SPAN == (COL_SPAN & mBits)); |
|
348 } |
|
349 |
|
350 inline bool CellData::IsZeroColSpan() const |
|
351 { |
|
352 return (SPAN == (SPAN & mBits)) && |
|
353 (COL_SPAN == (COL_SPAN & mBits)) && |
|
354 (COL_SPAN_0 == (COL_SPAN_0 & mBits)); |
|
355 } |
|
356 |
|
357 inline void CellData::SetZeroColSpan(bool aIsZeroSpan) |
|
358 { |
|
359 if (SPAN == (SPAN & mBits)) { |
|
360 if (aIsZeroSpan) { |
|
361 mBits |= COL_SPAN_0; |
|
362 } |
|
363 else { |
|
364 mBits &= ~COL_SPAN_0; |
|
365 } |
|
366 } |
|
367 } |
|
368 |
|
369 inline uint32_t CellData::GetColSpanOffset() const |
|
370 { |
|
371 if ((SPAN == (SPAN & mBits)) && ((COL_SPAN == (COL_SPAN & mBits)))) { |
|
372 return (uint32_t)((mBits & COL_SPAN_OFFSET) >> COL_SPAN_SHIFT); |
|
373 } |
|
374 return 0; |
|
375 } |
|
376 |
|
377 inline void CellData::SetColSpanOffset(uint32_t aSpan) |
|
378 { |
|
379 mBits &= ~COL_SPAN_OFFSET; |
|
380 mBits |= (aSpan << COL_SPAN_SHIFT); |
|
381 |
|
382 mBits |= SPAN; |
|
383 mBits |= COL_SPAN; |
|
384 } |
|
385 |
|
386 inline bool CellData::IsOverlap() const |
|
387 { |
|
388 return (SPAN == (SPAN & mBits)) && (OVERLAP == (OVERLAP & mBits)); |
|
389 } |
|
390 |
|
391 inline void CellData::SetOverlap(bool aOverlap) |
|
392 { |
|
393 if (SPAN == (SPAN & mBits)) { |
|
394 if (aOverlap) { |
|
395 mBits |= OVERLAP; |
|
396 } |
|
397 else { |
|
398 mBits &= ~OVERLAP; |
|
399 } |
|
400 } |
|
401 } |
|
402 |
|
403 inline BCData::BCData() |
|
404 { |
|
405 mLeftOwner = mTopOwner = eCellOwner; |
|
406 mLeftStart = mTopStart = 1; |
|
407 mLeftSize = mCornerSubSize = mTopSize = 0; |
|
408 mCornerSide = NS_SIDE_TOP; |
|
409 mCornerBevel = false; |
|
410 } |
|
411 |
|
412 inline BCData::~BCData() |
|
413 { |
|
414 } |
|
415 |
|
416 inline nscoord BCData::GetLeftEdge(BCBorderOwner& aOwner, |
|
417 bool& aStart) const |
|
418 { |
|
419 aOwner = (BCBorderOwner)mLeftOwner; |
|
420 aStart = (bool)mLeftStart; |
|
421 |
|
422 return (nscoord)mLeftSize; |
|
423 } |
|
424 |
|
425 inline void BCData::SetLeftEdge(BCBorderOwner aOwner, |
|
426 nscoord aSize, |
|
427 bool aStart) |
|
428 { |
|
429 mLeftOwner = aOwner; |
|
430 mLeftSize = (aSize > MAX_BORDER_WIDTH) ? MAX_BORDER_WIDTH : aSize; |
|
431 mLeftStart = aStart; |
|
432 } |
|
433 |
|
434 inline nscoord BCData::GetTopEdge(BCBorderOwner& aOwner, |
|
435 bool& aStart) const |
|
436 { |
|
437 aOwner = (BCBorderOwner)mTopOwner; |
|
438 aStart = (bool)mTopStart; |
|
439 |
|
440 return (nscoord)mTopSize; |
|
441 } |
|
442 |
|
443 inline void BCData::SetTopEdge(BCBorderOwner aOwner, |
|
444 nscoord aSize, |
|
445 bool aStart) |
|
446 { |
|
447 mTopOwner = aOwner; |
|
448 mTopSize = (aSize > MAX_BORDER_WIDTH) ? MAX_BORDER_WIDTH : aSize; |
|
449 mTopStart = aStart; |
|
450 } |
|
451 |
|
452 inline BCPixelSize BCData::GetCorner(mozilla::css::Side& aOwnerSide, |
|
453 bool& aBevel) const |
|
454 { |
|
455 aOwnerSide = mozilla::css::Side(mCornerSide); |
|
456 aBevel = (bool)mCornerBevel; |
|
457 return mCornerSubSize; |
|
458 } |
|
459 |
|
460 inline void BCData::SetCorner(BCPixelSize aSubSize, |
|
461 mozilla::css::Side aOwnerSide, |
|
462 bool aBevel) |
|
463 { |
|
464 mCornerSubSize = aSubSize; |
|
465 mCornerSide = aOwnerSide; |
|
466 mCornerBevel = aBevel; |
|
467 } |
|
468 |
|
469 inline bool BCData::IsLeftStart() const |
|
470 { |
|
471 return (bool)mLeftStart; |
|
472 } |
|
473 |
|
474 inline void BCData::SetLeftStart(bool aValue) |
|
475 { |
|
476 mLeftStart = aValue; |
|
477 } |
|
478 |
|
479 inline bool BCData::IsTopStart() const |
|
480 { |
|
481 return (bool)mTopStart; |
|
482 } |
|
483 |
|
484 inline void BCData::SetTopStart(bool aValue) |
|
485 { |
|
486 mTopStart = aValue; |
|
487 } |
|
488 |
|
489 #endif |