layout/tables/celldata.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/tables/celldata.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,489 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +#ifndef CellData_h__
     1.9 +#define CellData_h__
    1.10 +
    1.11 +#include "nsISupports.h"
    1.12 +#include "nsCoord.h"
    1.13 +#include "mozilla/gfx/Types.h"
    1.14 +#include <stdint.h>
    1.15 +
    1.16 +class nsTableCellFrame;
    1.17 +class nsCellMap;
    1.18 +class BCCellData;
    1.19 +
    1.20 +
    1.21 +#define MAX_ROWSPAN 65534 // the cellmap can not handle more.
    1.22 +#define MAX_COLSPAN 1000 // limit as IE and opera do.  If this ever changes,
    1.23 +                         // change COL_SPAN_OFFSET/COL_SPAN_SHIFT accordingly.
    1.24 +
    1.25 +/**
    1.26 +  * Data stored by nsCellMap to rationalize rowspan and colspan cells.
    1.27 +  */
    1.28 +class CellData
    1.29 +{
    1.30 +public:
    1.31 +  /** Initialize the mOrigCell pointer
    1.32 +    * @param aOrigCell  the table cell frame which will be stored in mOrigCell.
    1.33 +    */
    1.34 +  void   Init(nsTableCellFrame* aCellFrame);
    1.35 +
    1.36 +  /** does a cell originate from here
    1.37 +    * @return    is true if a cell corresponds to this cellmap entry
    1.38 +    */
    1.39 +  bool IsOrig() const;
    1.40 +
    1.41 +  /** is the celldata valid
    1.42 +    * @return    is true if no cell originates and the cell is not spanned by
    1.43 +    *            a row- or colspan. mBits are 0 in this case and mOrigCell is
    1.44 +    *            nullptr
    1.45 +    */
    1.46 +  bool IsDead() const;
    1.47 +
    1.48 +  /** is the entry spanned by row- or a colspan
    1.49 +    * @return    is true if the entry is spanned by a row- or colspan
    1.50 +    */
    1.51 +  bool IsSpan() const;
    1.52 +
    1.53 +  /** is the entry spanned by rowspan
    1.54 +    * @return    is true if the entry is spanned by a rowspan
    1.55 +    */
    1.56 +  bool IsRowSpan() const;
    1.57 +
    1.58 +  /** is the entry spanned by a zero rowspan
    1.59 +    * zero rowspans span all cells starting from the originating cell down to
    1.60 +    * the end of the rowgroup or a cell originating in the same column
    1.61 +    * @return    is true if the entry is spanned by a zero rowspan
    1.62 +    */
    1.63 +  bool IsZeroRowSpan() const;
    1.64 +
    1.65 +  /** mark the current entry as spanned by a zero rowspan
    1.66 +    * @param aIsZero    if true mark the entry as covered by a zero rowspan
    1.67 +    */
    1.68 +  void SetZeroRowSpan(bool aIsZero);
    1.69 +
    1.70 +  /** get the distance from the current entry to the corresponding origin of the rowspan
    1.71 +    * @return    containing the distance in the column to the originating cell
    1.72 +    */
    1.73 +  uint32_t GetRowSpanOffset() const;
    1.74 +
    1.75 +  /** set the distance from the current entry to the corresponding origin of the rowspan
    1.76 +    * @param    the distance in the column to the originating cell
    1.77 +    */
    1.78 +  void SetRowSpanOffset(uint32_t aSpan);
    1.79 +
    1.80 +  /** is the entry spanned by colspan
    1.81 +    * @return    is true if the entry is spanned by a colspan
    1.82 +    */
    1.83 +  bool IsColSpan() const;
    1.84 +
    1.85 +  /** is the entry spanned by a zero colspan
    1.86 +    * zero colspans span all cells starting from the originating cell towards
    1.87 +    * the end of the colgroup or a cell originating in the same row
    1.88 +    * or a rowspanned entry
    1.89 +    * @return    is true if the entry is spanned by a zero colspan
    1.90 +    */
    1.91 +  bool IsZeroColSpan() const;
    1.92 +
    1.93 +  /** mark the current entry as spanned by a zero colspan
    1.94 +    * @param aIsZero    if true mark the entry as covered by a zero colspan
    1.95 +    */
    1.96 +  void SetZeroColSpan(bool aIsZero);
    1.97 +
    1.98 +  /** get the distance from the current entry to the corresponding origin of the colspan
    1.99 +    * @return    containing the distance in the row to the originating cell
   1.100 +    */
   1.101 +  uint32_t GetColSpanOffset() const;
   1.102 +
   1.103 +  /** set the distance from the current entry to the corresponding origin of the colspan
   1.104 +    * @param    the distance in the column to the originating cell
   1.105 +    */
   1.106 +  void SetColSpanOffset(uint32_t aSpan);
   1.107 +
   1.108 +  /** is the entry spanned by a row- and a colspan
   1.109 +    * @return    is true if the entry is spanned by a row- and a colspan
   1.110 +    */
   1.111 +  bool IsOverlap() const;
   1.112 +
   1.113 +  /** mark the current entry as spanned by a row- and a colspan
   1.114 +    * @param aOverlap    if true mark the entry as covered by a row- and a colspan
   1.115 +    */
   1.116 +  void SetOverlap(bool aOverlap);
   1.117 +
   1.118 +  /** get the table cell frame for this entry
   1.119 +    * @return    a pointer to the cellframe, this will be nullptr when the entry
   1.120 +    *            is only a spanned entry
   1.121 +    */
   1.122 +  nsTableCellFrame* GetCellFrame() const;
   1.123 +
   1.124 +private:
   1.125 +  friend class nsCellMap;
   1.126 +  friend class BCCellData;
   1.127 +
   1.128 +  /** constructor.
   1.129 +    * @param aOrigCell  the table cell frame which will be stored in mOrigCell.
   1.130 +    */
   1.131 +  CellData(nsTableCellFrame* aOrigCell);  // implemented in nsCellMap.cpp
   1.132 +
   1.133 +  /** destructor */
   1.134 +  ~CellData(); // implemented in nsCellMap.cpp
   1.135 +
   1.136 +protected:
   1.137 +
   1.138 +  // this union relies on the assumption that an object (not primitive type) does
   1.139 +  // not start on an odd bit boundary. If mSpan is 0 then mOrigCell is in effect
   1.140 +  // and the data does not represent a span. If mSpan is 1, then mBits is in
   1.141 +  // effect and the data represents a span.
   1.142 +  // mBits must match the size of mOrigCell on both 32- and 64-bit platforms.
   1.143 +  union {
   1.144 +    nsTableCellFrame* mOrigCell;
   1.145 +    uintptr_t         mBits;
   1.146 +  };
   1.147 +};
   1.148 +
   1.149 +// Border Collapsing Cell Data
   1.150 +enum BCBorderOwner
   1.151 +{
   1.152 +  eTableOwner        =  0,
   1.153 +  eColGroupOwner     =  1,
   1.154 +  eAjaColGroupOwner  =  2, // col group to the left
   1.155 +  eColOwner          =  3,
   1.156 +  eAjaColOwner       =  4, // col to the left
   1.157 +  eRowGroupOwner     =  5,
   1.158 +  eAjaRowGroupOwner  =  6, // row group above
   1.159 +  eRowOwner          =  7,
   1.160 +  eAjaRowOwner       =  8, // row above
   1.161 +  eCellOwner         =  9,
   1.162 +  eAjaCellOwner      = 10  // cell to the top or to the left
   1.163 +};
   1.164 +
   1.165 +typedef uint16_t BCPixelSize;
   1.166 +
   1.167 +// These are the max sizes that are stored. If they are exceeded, then the max is stored and
   1.168 +// the actual value is computed when needed.
   1.169 +#define MAX_BORDER_WIDTH nscoord((1u << (sizeof(BCPixelSize) * 8)) - 1)
   1.170 +
   1.171 +static inline nscoord
   1.172 +BC_BORDER_TOP_HALF_COORD(int32_t p2t, uint16_t px)    { return (px - px / 2) * p2t; }
   1.173 +static inline nscoord
   1.174 +BC_BORDER_RIGHT_HALF_COORD(int32_t p2t, uint16_t px)  { return (     px / 2) * p2t; }
   1.175 +static inline nscoord
   1.176 +BC_BORDER_BOTTOM_HALF_COORD(int32_t p2t, uint16_t px) { return (     px / 2) * p2t; }
   1.177 +static inline nscoord
   1.178 +BC_BORDER_LEFT_HALF_COORD(int32_t p2t, uint16_t px)   { return (px - px / 2) * p2t; }
   1.179 +
   1.180 +#define BC_BORDER_TOP_HALF(px)    ((px) - (px) / 2)
   1.181 +#define BC_BORDER_RIGHT_HALF(px)  ((px) / 2)
   1.182 +#define BC_BORDER_BOTTOM_HALF(px) ((px) / 2)
   1.183 +#define BC_BORDER_LEFT_HALF(px)   ((px) - (px) / 2)
   1.184 +
   1.185 +// BCData stores the top and left border info and the corner connecting the two.
   1.186 +class BCData
   1.187 +{
   1.188 +public:
   1.189 +  BCData();
   1.190 +
   1.191 +  ~BCData();
   1.192 +
   1.193 +  nscoord GetLeftEdge(BCBorderOwner& aOwner,
   1.194 +                      bool&        aStart) const;
   1.195 +
   1.196 +  void SetLeftEdge(BCBorderOwner aOwner,
   1.197 +                   nscoord       aSize,
   1.198 +                   bool          aStart);
   1.199 +
   1.200 +  nscoord GetTopEdge(BCBorderOwner& aOwner,
   1.201 +                     bool&        aStart) const;
   1.202 +
   1.203 +  void SetTopEdge(BCBorderOwner aOwner,
   1.204 +                  nscoord       aSize,
   1.205 +                  bool          aStart);
   1.206 +
   1.207 +  BCPixelSize GetCorner(mozilla::css::Side&       aCornerOwner,
   1.208 +                        bool&  aBevel) const;
   1.209 +
   1.210 +  void SetCorner(BCPixelSize aSubSize,
   1.211 +                 mozilla::css::Side aOwner,
   1.212 +                 bool    aBevel);
   1.213 +
   1.214 +  bool IsLeftStart() const;
   1.215 +
   1.216 +  void SetLeftStart(bool aValue);
   1.217 +
   1.218 +  bool IsTopStart() const;
   1.219 +
   1.220 +  void SetTopStart(bool aValue);
   1.221 +
   1.222 +
   1.223 +protected:
   1.224 +  BCPixelSize mLeftSize;      // size in pixels of left border
   1.225 +  BCPixelSize mTopSize;       // size in pixels of top border
   1.226 +  BCPixelSize mCornerSubSize; // size of the largest border not in the
   1.227 +                              //   dominant plane (for example, if corner is
   1.228 +                              //   owned by the segment to its top or bottom,
   1.229 +                              //   then the size is the max of the border
   1.230 +                              //   sizes of the segments to its left or right.
   1.231 +  unsigned mLeftOwner:     4; // owner of left border
   1.232 +  unsigned mTopOwner:      4; // owner of top border
   1.233 +  unsigned mLeftStart:     1; // set if this is the start of a vertical border segment
   1.234 +  unsigned mTopStart:      1; // set if this is the start of a horizontal border segment
   1.235 +  unsigned mCornerSide:    2; // mozilla::css::Side of the owner of the upper left corner relative to the corner
   1.236 +  unsigned mCornerBevel:   1; // is the corner beveled (only two segments, perpendicular, not dashed or dotted).
   1.237 +};
   1.238 +
   1.239 +// BCCellData entries replace CellData entries in the cell map if the border collapsing model is in
   1.240 +// effect. BCData for a row and col entry contains the left and top borders of cell at that row and
   1.241 +// col and the corner connecting the two. The right borders of the cells in the last col and the bottom
   1.242 +// borders of the last row are stored in separate BCData entries in the cell map.
   1.243 +class BCCellData : public CellData
   1.244 +{
   1.245 +public:
   1.246 +  BCCellData(nsTableCellFrame* aOrigCell);
   1.247 +  ~BCCellData();
   1.248 +
   1.249 +  BCData mData;
   1.250 +};
   1.251 +
   1.252 +
   1.253 +// The layout of a celldata is as follows.  The top 10 bits are the colspan
   1.254 +// offset (which is enough to represent our allowed values 1-1000 for colspan).
   1.255 +// Then there are three bits of flags.  Then 16 bits of rowspan offset (which
   1.256 +// lets us represent numbers up to 65535.  Then another 3 bits of flags.
   1.257 +
   1.258 +// num bits to shift right to get right aligned col span
   1.259 +#define COL_SPAN_SHIFT   22
   1.260 +// num bits to shift right to get right aligned row span
   1.261 +#define ROW_SPAN_SHIFT   3
   1.262 +
   1.263 +// the col offset to the data containing the original cell.
   1.264 +#define COL_SPAN_OFFSET  (0x3FF << COL_SPAN_SHIFT)
   1.265 +// the row offset to the data containing the original cell
   1.266 +#define ROW_SPAN_OFFSET  (0xFFFF << ROW_SPAN_SHIFT)
   1.267 +
   1.268 +// And the flags
   1.269 +#define SPAN             0x00000001 // there a row or col span
   1.270 +#define ROW_SPAN         0x00000002 // there is a row span
   1.271 +#define ROW_SPAN_0       0x00000004 // the row span is 0
   1.272 +#define COL_SPAN         (1 << (COL_SPAN_SHIFT - 3)) // there is a col span
   1.273 +#define COL_SPAN_0       (1 << (COL_SPAN_SHIFT - 2)) // the col span is 0
   1.274 +#define OVERLAP          (1 << (COL_SPAN_SHIFT - 1)) // there is a row span and
   1.275 +                                                     // col span but not by
   1.276 +                                                     // same cell
   1.277 +
   1.278 +inline nsTableCellFrame* CellData::GetCellFrame() const
   1.279 +{
   1.280 +  if (SPAN != (SPAN & mBits)) {
   1.281 +    return mOrigCell;
   1.282 +  }
   1.283 +  return nullptr;
   1.284 +}
   1.285 +
   1.286 +inline void CellData::Init(nsTableCellFrame* aCellFrame)
   1.287 +{
   1.288 +  mOrigCell = aCellFrame;
   1.289 +}
   1.290 +
   1.291 +inline bool CellData::IsOrig() const
   1.292 +{
   1.293 +  return ((nullptr != mOrigCell) && (SPAN != (SPAN & mBits)));
   1.294 +}
   1.295 +
   1.296 +inline bool CellData::IsDead() const
   1.297 +{
   1.298 +  return (0 == mBits);
   1.299 +}
   1.300 +
   1.301 +inline bool CellData::IsSpan() const
   1.302 +{
   1.303 +  return (SPAN == (SPAN & mBits));
   1.304 +}
   1.305 +
   1.306 +inline bool CellData::IsRowSpan() const
   1.307 +{
   1.308 +  return (SPAN     == (SPAN & mBits)) &&
   1.309 +         (ROW_SPAN == (ROW_SPAN & mBits));
   1.310 +}
   1.311 +
   1.312 +inline bool CellData::IsZeroRowSpan() const
   1.313 +{
   1.314 +  return (SPAN       == (SPAN & mBits))     &&
   1.315 +         (ROW_SPAN   == (ROW_SPAN & mBits)) &&
   1.316 +         (ROW_SPAN_0 == (ROW_SPAN_0 & mBits));
   1.317 +}
   1.318 +
   1.319 +inline void CellData::SetZeroRowSpan(bool aIsZeroSpan)
   1.320 +{
   1.321 +  if (SPAN == (SPAN & mBits)) {
   1.322 +    if (aIsZeroSpan) {
   1.323 +      mBits |= ROW_SPAN_0;
   1.324 +    }
   1.325 +    else {
   1.326 +      mBits &= ~ROW_SPAN_0;
   1.327 +    }
   1.328 +  }
   1.329 +}
   1.330 +
   1.331 +inline uint32_t CellData::GetRowSpanOffset() const
   1.332 +{
   1.333 +  if ((SPAN == (SPAN & mBits)) && ((ROW_SPAN == (ROW_SPAN & mBits)))) {
   1.334 +    return (uint32_t)((mBits & ROW_SPAN_OFFSET) >> ROW_SPAN_SHIFT);
   1.335 +  }
   1.336 +  return 0;
   1.337 +}
   1.338 +
   1.339 +inline void CellData::SetRowSpanOffset(uint32_t aSpan)
   1.340 +{
   1.341 +  mBits &= ~ROW_SPAN_OFFSET;
   1.342 +  mBits |= (aSpan << ROW_SPAN_SHIFT);
   1.343 +  mBits |= SPAN;
   1.344 +  mBits |= ROW_SPAN;
   1.345 +}
   1.346 +
   1.347 +inline bool CellData::IsColSpan() const
   1.348 +{
   1.349 +  return (SPAN     == (SPAN & mBits)) &&
   1.350 +         (COL_SPAN == (COL_SPAN & mBits));
   1.351 +}
   1.352 +
   1.353 +inline bool CellData::IsZeroColSpan() const
   1.354 +{
   1.355 +  return (SPAN       == (SPAN & mBits))     &&
   1.356 +         (COL_SPAN   == (COL_SPAN & mBits)) &&
   1.357 +         (COL_SPAN_0 == (COL_SPAN_0 & mBits));
   1.358 +}
   1.359 +
   1.360 +inline void CellData::SetZeroColSpan(bool aIsZeroSpan)
   1.361 +{
   1.362 +  if (SPAN == (SPAN & mBits)) {
   1.363 +    if (aIsZeroSpan) {
   1.364 +      mBits |= COL_SPAN_0;
   1.365 +    }
   1.366 +    else {
   1.367 +      mBits &= ~COL_SPAN_0;
   1.368 +    }
   1.369 +  }
   1.370 +}
   1.371 +
   1.372 +inline uint32_t CellData::GetColSpanOffset() const
   1.373 +{
   1.374 +  if ((SPAN == (SPAN & mBits)) && ((COL_SPAN == (COL_SPAN & mBits)))) {
   1.375 +    return (uint32_t)((mBits & COL_SPAN_OFFSET) >> COL_SPAN_SHIFT);
   1.376 +  }
   1.377 +  return 0;
   1.378 +}
   1.379 +
   1.380 +inline void CellData::SetColSpanOffset(uint32_t aSpan)
   1.381 +{
   1.382 +  mBits &= ~COL_SPAN_OFFSET;
   1.383 +  mBits |= (aSpan << COL_SPAN_SHIFT);
   1.384 +
   1.385 +  mBits |= SPAN;
   1.386 +  mBits |= COL_SPAN;
   1.387 +}
   1.388 +
   1.389 +inline bool CellData::IsOverlap() const
   1.390 +{
   1.391 +  return (SPAN == (SPAN & mBits)) && (OVERLAP == (OVERLAP & mBits));
   1.392 +}
   1.393 +
   1.394 +inline void CellData::SetOverlap(bool aOverlap)
   1.395 +{
   1.396 +  if (SPAN == (SPAN & mBits)) {
   1.397 +    if (aOverlap) {
   1.398 +      mBits |= OVERLAP;
   1.399 +    }
   1.400 +    else {
   1.401 +      mBits &= ~OVERLAP;
   1.402 +    }
   1.403 +  }
   1.404 +}
   1.405 +
   1.406 +inline BCData::BCData()
   1.407 +{
   1.408 +  mLeftOwner = mTopOwner = eCellOwner;
   1.409 +  mLeftStart = mTopStart = 1;
   1.410 +  mLeftSize = mCornerSubSize = mTopSize = 0;
   1.411 +  mCornerSide = NS_SIDE_TOP;
   1.412 +  mCornerBevel = false;
   1.413 +}
   1.414 +
   1.415 +inline BCData::~BCData()
   1.416 +{
   1.417 +}
   1.418 +
   1.419 +inline nscoord BCData::GetLeftEdge(BCBorderOwner& aOwner,
   1.420 +                                   bool&        aStart) const
   1.421 +{
   1.422 +  aOwner = (BCBorderOwner)mLeftOwner;
   1.423 +  aStart = (bool)mLeftStart;
   1.424 +
   1.425 +  return (nscoord)mLeftSize;
   1.426 +}
   1.427 +
   1.428 +inline void BCData::SetLeftEdge(BCBorderOwner  aOwner,
   1.429 +                                nscoord        aSize,
   1.430 +                                bool           aStart)
   1.431 +{
   1.432 +  mLeftOwner = aOwner;
   1.433 +  mLeftSize  = (aSize > MAX_BORDER_WIDTH) ? MAX_BORDER_WIDTH : aSize;
   1.434 +  mLeftStart = aStart;
   1.435 +}
   1.436 +
   1.437 +inline nscoord BCData::GetTopEdge(BCBorderOwner& aOwner,
   1.438 +                                  bool&        aStart) const
   1.439 +{
   1.440 +  aOwner = (BCBorderOwner)mTopOwner;
   1.441 +  aStart = (bool)mTopStart;
   1.442 +
   1.443 +  return (nscoord)mTopSize;
   1.444 +}
   1.445 +
   1.446 +inline void BCData::SetTopEdge(BCBorderOwner  aOwner,
   1.447 +                               nscoord        aSize,
   1.448 +                               bool           aStart)
   1.449 +{
   1.450 +  mTopOwner = aOwner;
   1.451 +  mTopSize  = (aSize > MAX_BORDER_WIDTH) ? MAX_BORDER_WIDTH : aSize;
   1.452 +  mTopStart = aStart;
   1.453 +}
   1.454 +
   1.455 +inline BCPixelSize BCData::GetCorner(mozilla::css::Side& aOwnerSide,
   1.456 +                                     bool&       aBevel) const
   1.457 +{
   1.458 +  aOwnerSide = mozilla::css::Side(mCornerSide);
   1.459 +  aBevel     = (bool)mCornerBevel;
   1.460 +  return mCornerSubSize;
   1.461 +}
   1.462 +
   1.463 +inline void BCData::SetCorner(BCPixelSize aSubSize,
   1.464 +                              mozilla::css::Side aOwnerSide,
   1.465 +                              bool    aBevel)
   1.466 +{
   1.467 +  mCornerSubSize = aSubSize;
   1.468 +  mCornerSide    = aOwnerSide;
   1.469 +  mCornerBevel   = aBevel;
   1.470 +}
   1.471 +
   1.472 +inline bool BCData::IsLeftStart() const
   1.473 +{
   1.474 +  return (bool)mLeftStart;
   1.475 +}
   1.476 +
   1.477 +inline void BCData::SetLeftStart(bool aValue)
   1.478 +{
   1.479 +  mLeftStart = aValue;
   1.480 +}
   1.481 +
   1.482 +inline bool BCData::IsTopStart() const
   1.483 +{
   1.484 +  return (bool)mTopStart;
   1.485 +}
   1.486 +
   1.487 +inline void BCData::SetTopStart(bool aValue)
   1.488 +{
   1.489 +  mTopStart = aValue;
   1.490 +}
   1.491 +
   1.492 +#endif

mercurial