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