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 "nsITableCellLayout.h" // for MAX_COLSPAN / MAX_ROWSPAN
10 #include "nsCoord.h"
11 #include "mozilla/gfx/Types.h"
12 #include "mozilla/WritingModes.h"
13 #include <stdint.h>
14
15 class nsTableCellFrame;
16 class nsCellMap;
17 class BCCellData;
18
19 /**
20 * Data stored by nsCellMap to rationalize rowspan and colspan cells.
21 */
22 class CellData {
23 public:
24 /** Initialize the mOrigCell pointer
25 * @param aOrigCell the table cell frame which will be stored in mOrigCell.
26 */
27 void Init(nsTableCellFrame* aCellFrame);
28
29 /** does a cell originate from here
30 * @return is true if a cell corresponds to this cellmap entry
31 */
32 bool IsOrig() const;
33
34 /** is the celldata valid
35 * @return is true if no cell originates and the cell is not spanned by
36 * a row- or colspan. mBits are 0 in this case and mOrigCell is
37 * nullptr
38 */
39 bool IsDead() const;
40
41 /** is the entry spanned by row- or a colspan
42 * @return is true if the entry is spanned by a row- or colspan
43 */
44 bool IsSpan() const;
45
46 /** is the entry spanned by rowspan
47 * @return is true if the entry is spanned by a rowspan
48 */
49 bool IsRowSpan() const;
50
51 /** is the entry spanned by a zero rowspan
52 * zero rowspans span all cells starting from the originating cell down to
53 * the end of the rowgroup or a cell originating in the same column
54 * @return is true if the entry is spanned by a zero rowspan
55 */
56 bool IsZeroRowSpan() const;
57
58 /** mark the current entry as spanned by a zero rowspan
59 * @param aIsZero if true mark the entry as covered by a zero rowspan
60 */
61 void SetZeroRowSpan(bool aIsZero);
62
63 /** get the distance from the current entry to the corresponding origin of the
64 * rowspan
65 * @return containing the distance in the column to the originating cell
66 */
67 uint32_t GetRowSpanOffset() const;
68
69 /** set the distance from the current entry to the corresponding origin of
70 * the rowspan
71 * @param the distance in the column to the originating cell
72 */
73 void SetRowSpanOffset(uint32_t aSpan);
74
75 /** is the entry spanned by colspan
76 * @return is true if the entry is spanned by a colspan
77 */
78 bool IsColSpan() const;
79
80 /** get the distance from the current entry to the corresponding origin of
81 * the colspan
82 * @return containing the distance in the row to the originating cell
83 */
84 uint32_t GetColSpanOffset() const;
85
86 /** set the distance from the current entry to the corresponding origin of the
87 * colspan
88 * @param the distance in the column to the originating cell
89 */
90 void SetColSpanOffset(uint32_t aSpan);
91
92 /** is the entry spanned by a row- and a colspan
93 * @return is true if the entry is spanned by a row- and a colspan
94 */
95 bool IsOverlap() const;
96
97 /** mark the current entry as spanned by a row- and a colspan
98 * @param aOverlap if true mark the entry as covered by a row- and
99 * a colspan
100 */
101 void SetOverlap(bool aOverlap);
102
103 /** get the table cell frame for this entry
104 * @return a pointer to the cellframe, this will be nullptr when the entry
105 * is only a spanned entry
106 */
107 nsTableCellFrame* GetCellFrame() const;
108
109 private:
110 friend class nsCellMap;
111 friend class BCCellData;
112
113 /**
114 * Implemented in nsCellMap.cpp
115 *
116 * @param aOrigCell the table cell frame which will be stored in mOrigCell.
117 */
118 explicit CellData(nsTableCellFrame* aOrigCell);
119
120 ~CellData(); // implemented in nsCellMap.cpp
121
122 protected:
123 // this union relies on the assumption that an object (not primitive type)
124 // does not start on an odd bit boundary. If mSpan is 0 then mOrigCell is in
125 // effect and the data does not represent a span. If mSpan is 1, then mBits is
126 // in effect and the data represents a span. mBits must match the size of
127 // mOrigCell on both 32- and 64-bit platforms.
128 union {
129 nsTableCellFrame* mOrigCell;
130 uintptr_t mBits;
131 };
132 };
133
134 // Border Collapsing Cell Data
135 enum BCBorderOwner {
136 eTableOwner = 0,
137 eColGroupOwner = 1,
138 eAjaColGroupOwner = 2, // col group to the left
139 eColOwner = 3,
140 eAjaColOwner = 4, // col to the left
141 eRowGroupOwner = 5,
142 eAjaRowGroupOwner = 6, // row group above
143 eRowOwner = 7,
144 eAjaRowOwner = 8, // row above
145 eCellOwner = 9,
146 eAjaCellOwner = 10 // cell to the top or to the left
147 };
148
149 // BCPixelSize is in device pixels.
150 typedef uint16_t BCPixelSize;
151
152 // These are the max sizes that are stored. If they are exceeded, then the max
153 // is stored and the actual value is computed when needed.
154 #define MAX_BORDER_WIDTH nscoord((1u << (sizeof(BCPixelSize) * 8)) - 1)
155
156 // The half of border on inline/block-axis start side
BC_BORDER_START_HALF(BCPixelSize px)157 static inline BCPixelSize BC_BORDER_START_HALF(BCPixelSize px) {
158 return px - px / 2;
159 }
160 // The half of border on inline/block-axis end side
BC_BORDER_END_HALF(BCPixelSize px)161 static inline BCPixelSize BC_BORDER_END_HALF(BCPixelSize px) { return px / 2; }
162
BC_BORDER_START_HALF_COORD(int32_t d2a,BCPixelSize px)163 static inline nscoord BC_BORDER_START_HALF_COORD(int32_t d2a, BCPixelSize px) {
164 return BC_BORDER_START_HALF(px) * d2a;
165 }
BC_BORDER_END_HALF_COORD(int32_t d2a,BCPixelSize px)166 static inline nscoord BC_BORDER_END_HALF_COORD(int32_t d2a, BCPixelSize px) {
167 return BC_BORDER_END_HALF(px) * d2a;
168 }
169
170 // BCData stores the bstart and istart border info and the corner connecting the
171 // two.
172 class BCData {
173 public:
174 BCData();
175
176 ~BCData();
177
178 nscoord GetIStartEdge(BCBorderOwner& aOwner, bool& aStart) const;
179
180 void SetIStartEdge(BCBorderOwner aOwner, nscoord aSize, bool aStart);
181
182 nscoord GetBStartEdge(BCBorderOwner& aOwner, bool& aStart) const;
183
184 void SetBStartEdge(BCBorderOwner aOwner, nscoord aSize, bool aStart);
185
186 BCPixelSize GetCorner(mozilla::LogicalSide& aCornerOwner, bool& aBevel) const;
187
188 void SetCorner(BCPixelSize aSubSize, mozilla::LogicalSide aOwner,
189 bool aBevel);
190
IsIStartStart()191 inline bool IsIStartStart() const { return (bool)mIStartStart; }
192
SetIStartStart(bool aValue)193 inline void SetIStartStart(bool aValue) { mIStartStart = aValue; }
194
IsBStartStart()195 inline bool IsBStartStart() const { return (bool)mBStartStart; }
196
SetBStartStart(bool aValue)197 inline void SetBStartStart(bool aValue) { mBStartStart = aValue; }
198
199 protected:
200 BCPixelSize mIStartSize; // size in pixels of iStart border
201 BCPixelSize mBStartSize; // size in pixels of bStart border
202 BCPixelSize mCornerSubSize; // size of the largest border not in the
203 // dominant plane (for example, if corner is
204 // owned by the segment to its bStart or bEnd,
205 // then the size is the max of the border
206 // sizes of the segments to its iStart or iEnd.
207 unsigned mIStartOwner : 4; // owner of iStart border
208 unsigned mBStartOwner : 4; // owner of bStart border
209 unsigned mIStartStart : 1; // set if this is the start of a block-dir border
210 // segment
211 unsigned mBStartStart : 1; // set if this is the start of an inline-dir
212 // border segment
213 unsigned mCornerSide : 2; // LogicalSide of the owner of the bStart-iStart
214 // corner relative to the corner
215 unsigned mCornerBevel : 1; // is the corner beveled (only two segments,
216 // perpendicular, not dashed or dotted).
217 };
218
219 // BCCellData entries replace CellData entries in the cell map if the border
220 // collapsing model is in effect. BCData for a row and col entry contains the
221 // left and top borders of cell at that row and col and the corner connecting
222 // the two. The right borders of the cells in the last col and the bottom
223 // borders of the last row are stored in separate BCData entries in the cell
224 // map.
225 class BCCellData : public CellData {
226 public:
227 explicit BCCellData(nsTableCellFrame* aOrigCell);
228 ~BCCellData();
229
230 BCData mData;
231 };
232
233 // The layout of a celldata is as follows. The top 10 bits are the colspan
234 // offset (which is enough to represent our allowed values 1-1000 for colspan).
235 // Then there are two bits of flags.
236 // XXXmats Then one unused bit that we should decide how to use in bug 862624.
237 // Then 16 bits of rowspan offset (which
238 // lets us represent numbers up to 65535. Then another 3 bits of flags.
239
240 // num bits to shift right to get right aligned col span
241 #define COL_SPAN_SHIFT 22
242 // num bits to shift right to get right aligned row span
243 #define ROW_SPAN_SHIFT 3
244
245 // the col offset to the data containing the original cell.
246 #define COL_SPAN_OFFSET (0x3FF << COL_SPAN_SHIFT)
247 // the row offset to the data containing the original cell
248 #define ROW_SPAN_OFFSET (0xFFFF << ROW_SPAN_SHIFT)
249
250 // And the flags
251 #define SPAN 0x00000001 // there a row or col span
252 #define ROW_SPAN 0x00000002 // there is a row span
253 #define ROW_SPAN_0 0x00000004 // the row span is 0
254 #define COL_SPAN (1 << (COL_SPAN_SHIFT - 2)) // there is a col span
255 #define OVERLAP \
256 (1 << (COL_SPAN_SHIFT - 1)) // there is a row span and
257 // col span but not by
258 // same cell
259
GetCellFrame()260 inline nsTableCellFrame* CellData::GetCellFrame() const {
261 if (SPAN != (SPAN & mBits)) {
262 return mOrigCell;
263 }
264 return nullptr;
265 }
266
Init(nsTableCellFrame * aCellFrame)267 inline void CellData::Init(nsTableCellFrame* aCellFrame) {
268 mOrigCell = aCellFrame;
269 }
270
IsOrig()271 inline bool CellData::IsOrig() const {
272 return ((nullptr != mOrigCell) && (SPAN != (SPAN & mBits)));
273 }
274
IsDead()275 inline bool CellData::IsDead() const { return (0 == mBits); }
276
IsSpan()277 inline bool CellData::IsSpan() const { return (SPAN == (SPAN & mBits)); }
278
IsRowSpan()279 inline bool CellData::IsRowSpan() const {
280 return (SPAN == (SPAN & mBits)) && (ROW_SPAN == (ROW_SPAN & mBits));
281 }
282
IsZeroRowSpan()283 inline bool CellData::IsZeroRowSpan() const {
284 return (SPAN == (SPAN & mBits)) && (ROW_SPAN == (ROW_SPAN & mBits)) &&
285 (ROW_SPAN_0 == (ROW_SPAN_0 & mBits));
286 }
287
SetZeroRowSpan(bool aIsZeroSpan)288 inline void CellData::SetZeroRowSpan(bool aIsZeroSpan) {
289 if (SPAN == (SPAN & mBits)) {
290 if (aIsZeroSpan) {
291 mBits |= ROW_SPAN_0;
292 } else {
293 mBits &= ~ROW_SPAN_0;
294 }
295 }
296 }
297
GetRowSpanOffset()298 inline uint32_t CellData::GetRowSpanOffset() const {
299 if ((SPAN == (SPAN & mBits)) && ((ROW_SPAN == (ROW_SPAN & mBits)))) {
300 return (uint32_t)((mBits & ROW_SPAN_OFFSET) >> ROW_SPAN_SHIFT);
301 }
302 return 0;
303 }
304
SetRowSpanOffset(uint32_t aSpan)305 inline void CellData::SetRowSpanOffset(uint32_t aSpan) {
306 mBits &= ~ROW_SPAN_OFFSET;
307 mBits |= (aSpan << ROW_SPAN_SHIFT);
308 mBits |= SPAN;
309 mBits |= ROW_SPAN;
310 }
311
IsColSpan()312 inline bool CellData::IsColSpan() const {
313 return (SPAN == (SPAN & mBits)) && (COL_SPAN == (COL_SPAN & mBits));
314 }
315
GetColSpanOffset()316 inline uint32_t CellData::GetColSpanOffset() const {
317 if ((SPAN == (SPAN & mBits)) && ((COL_SPAN == (COL_SPAN & mBits)))) {
318 return (uint32_t)((mBits & COL_SPAN_OFFSET) >> COL_SPAN_SHIFT);
319 }
320 return 0;
321 }
322
SetColSpanOffset(uint32_t aSpan)323 inline void CellData::SetColSpanOffset(uint32_t aSpan) {
324 mBits &= ~COL_SPAN_OFFSET;
325 mBits |= (aSpan << COL_SPAN_SHIFT);
326
327 mBits |= SPAN;
328 mBits |= COL_SPAN;
329 }
330
IsOverlap()331 inline bool CellData::IsOverlap() const {
332 return (SPAN == (SPAN & mBits)) && (OVERLAP == (OVERLAP & mBits));
333 }
334
SetOverlap(bool aOverlap)335 inline void CellData::SetOverlap(bool aOverlap) {
336 if (SPAN == (SPAN & mBits)) {
337 if (aOverlap) {
338 mBits |= OVERLAP;
339 } else {
340 mBits &= ~OVERLAP;
341 }
342 }
343 }
344
BCData()345 inline BCData::BCData() {
346 mIStartOwner = mBStartOwner = eCellOwner;
347 SetBStartStart(true);
348 SetIStartStart(true);
349 mIStartSize = mCornerSubSize = mBStartSize = 0;
350 mCornerSide = mozilla::eLogicalSideBStart;
351 mCornerBevel = false;
352 }
353
354 inline BCData::~BCData() = default;
355
GetIStartEdge(BCBorderOwner & aOwner,bool & aStart)356 inline nscoord BCData::GetIStartEdge(BCBorderOwner& aOwner,
357 bool& aStart) const {
358 aOwner = (BCBorderOwner)mIStartOwner;
359 aStart = IsIStartStart();
360
361 return (nscoord)mIStartSize;
362 }
363
SetIStartEdge(BCBorderOwner aOwner,nscoord aSize,bool aStart)364 inline void BCData::SetIStartEdge(BCBorderOwner aOwner, nscoord aSize,
365 bool aStart) {
366 mIStartOwner = aOwner;
367 mIStartSize = (aSize > MAX_BORDER_WIDTH) ? MAX_BORDER_WIDTH : aSize;
368 SetIStartStart(aStart);
369 }
370
GetBStartEdge(BCBorderOwner & aOwner,bool & aStart)371 inline nscoord BCData::GetBStartEdge(BCBorderOwner& aOwner,
372 bool& aStart) const {
373 aOwner = (BCBorderOwner)mBStartOwner;
374 aStart = IsBStartStart();
375
376 return (nscoord)mBStartSize;
377 }
378
SetBStartEdge(BCBorderOwner aOwner,nscoord aSize,bool aStart)379 inline void BCData::SetBStartEdge(BCBorderOwner aOwner, nscoord aSize,
380 bool aStart) {
381 mBStartOwner = aOwner;
382 mBStartSize = (aSize > MAX_BORDER_WIDTH) ? MAX_BORDER_WIDTH : aSize;
383 SetBStartStart(aStart);
384 }
385
GetCorner(mozilla::LogicalSide & aOwnerSide,bool & aBevel)386 inline BCPixelSize BCData::GetCorner(mozilla::LogicalSide& aOwnerSide,
387 bool& aBevel) const {
388 aOwnerSide = mozilla::LogicalSide(mCornerSide);
389 aBevel = (bool)mCornerBevel;
390 return mCornerSubSize;
391 }
392
SetCorner(BCPixelSize aSubSize,mozilla::LogicalSide aOwnerSide,bool aBevel)393 inline void BCData::SetCorner(BCPixelSize aSubSize,
394 mozilla::LogicalSide aOwnerSide, bool aBevel) {
395 mCornerSubSize = aSubSize;
396 mCornerSide = aOwnerSide;
397 mCornerBevel = aBevel;
398 }
399
400 #endif
401