diff options
Diffstat (limited to '')
-rw-r--r-- | layout/tables/celldata.h | 400 |
1 files changed, 400 insertions, 0 deletions
diff --git a/layout/tables/celldata.h b/layout/tables/celldata.h new file mode 100644 index 0000000000..681f0e9f28 --- /dev/null +++ b/layout/tables/celldata.h @@ -0,0 +1,400 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef CellData_h__ +#define CellData_h__ + +#include "nsISupports.h" +#include "nsITableCellLayout.h" // for MAX_COLSPAN / MAX_ROWSPAN +#include "nsCoord.h" +#include "mozilla/gfx/Types.h" +#include "mozilla/WritingModes.h" +#include <stdint.h> + +class nsTableCellFrame; +class nsCellMap; +class BCCellData; + +/** + * Data stored by nsCellMap to rationalize rowspan and colspan cells. + */ +class CellData { + public: + /** Initialize the mOrigCell pointer + * @param aOrigCell the table cell frame which will be stored in mOrigCell. + */ + void Init(nsTableCellFrame* aCellFrame); + + /** does a cell originate from here + * @return is true if a cell corresponds to this cellmap entry + */ + bool IsOrig() const; + + /** is the celldata valid + * @return is true if no cell originates and the cell is not spanned by + * a row- or colspan. mBits are 0 in this case and mOrigCell is + * nullptr + */ + bool IsDead() const; + + /** is the entry spanned by row- or a colspan + * @return is true if the entry is spanned by a row- or colspan + */ + bool IsSpan() const; + + /** is the entry spanned by rowspan + * @return is true if the entry is spanned by a rowspan + */ + bool IsRowSpan() const; + + /** is the entry spanned by a zero rowspan + * zero rowspans span all cells starting from the originating cell down to + * the end of the rowgroup or a cell originating in the same column + * @return is true if the entry is spanned by a zero rowspan + */ + bool IsZeroRowSpan() const; + + /** mark the current entry as spanned by a zero rowspan + * @param aIsZero if true mark the entry as covered by a zero rowspan + */ + void SetZeroRowSpan(bool aIsZero); + + /** get the distance from the current entry to the corresponding origin of the + * rowspan + * @return containing the distance in the column to the originating cell + */ + uint32_t GetRowSpanOffset() const; + + /** set the distance from the current entry to the corresponding origin of + * the rowspan + * @param the distance in the column to the originating cell + */ + void SetRowSpanOffset(uint32_t aSpan); + + /** is the entry spanned by colspan + * @return is true if the entry is spanned by a colspan + */ + bool IsColSpan() const; + + /** get the distance from the current entry to the corresponding origin of + * the colspan + * @return containing the distance in the row to the originating cell + */ + uint32_t GetColSpanOffset() const; + + /** set the distance from the current entry to the corresponding origin of the + * colspan + * @param the distance in the column to the originating cell + */ + void SetColSpanOffset(uint32_t aSpan); + + /** is the entry spanned by a row- and a colspan + * @return is true if the entry is spanned by a row- and a colspan + */ + bool IsOverlap() const; + + /** mark the current entry as spanned by a row- and a colspan + * @param aOverlap if true mark the entry as covered by a row- and + * a colspan + */ + void SetOverlap(bool aOverlap); + + /** get the table cell frame for this entry + * @return a pointer to the cellframe, this will be nullptr when the entry + * is only a spanned entry + */ + nsTableCellFrame* GetCellFrame() const; + + private: + friend class nsCellMap; + friend class BCCellData; + + /** + * Implemented in nsCellMap.cpp + * + * @param aOrigCell the table cell frame which will be stored in mOrigCell. + */ + explicit CellData(nsTableCellFrame* aOrigCell); + + ~CellData(); // implemented in nsCellMap.cpp + + protected: + // this union relies on the assumption that an object (not primitive type) + // does not start on an odd bit boundary. If mSpan is 0 then mOrigCell is in + // effect and the data does not represent a span. If mSpan is 1, then mBits is + // in effect and the data represents a span. mBits must match the size of + // mOrigCell on both 32- and 64-bit platforms. + union { + nsTableCellFrame* mOrigCell; + uintptr_t mBits; + }; +}; + +// Border Collapsing Cell Data +enum BCBorderOwner { + eTableOwner = 0, + eColGroupOwner = 1, + eAjaColGroupOwner = 2, // col group to the left + eColOwner = 3, + eAjaColOwner = 4, // col to the left + eRowGroupOwner = 5, + eAjaRowGroupOwner = 6, // row group above + eRowOwner = 7, + eAjaRowOwner = 8, // row above + eCellOwner = 9, + eAjaCellOwner = 10 // cell to the top or to the left +}; + +// BCPixelSize is in device pixels. +typedef uint16_t BCPixelSize; + +// These are the max sizes that are stored. If they are exceeded, then the max +// is stored and the actual value is computed when needed. +#define MAX_BORDER_WIDTH nscoord((1u << (sizeof(BCPixelSize) * 8)) - 1) + +// The half of border on inline/block-axis start side +static inline BCPixelSize BC_BORDER_START_HALF(BCPixelSize px) { + return px - px / 2; +} +// The half of border on inline/block-axis end side +static inline BCPixelSize BC_BORDER_END_HALF(BCPixelSize px) { return px / 2; } + +static inline nscoord BC_BORDER_START_HALF_COORD(int32_t d2a, BCPixelSize px) { + return BC_BORDER_START_HALF(px) * d2a; +} +static inline nscoord BC_BORDER_END_HALF_COORD(int32_t d2a, BCPixelSize px) { + return BC_BORDER_END_HALF(px) * d2a; +} + +// BCData stores the bstart and istart border info and the corner connecting the +// two. +class BCData { + public: + BCData(); + + ~BCData(); + + nscoord GetIStartEdge(BCBorderOwner& aOwner, bool& aStart) const; + + void SetIStartEdge(BCBorderOwner aOwner, nscoord aSize, bool aStart); + + nscoord GetBStartEdge(BCBorderOwner& aOwner, bool& aStart) const; + + void SetBStartEdge(BCBorderOwner aOwner, nscoord aSize, bool aStart); + + BCPixelSize GetCorner(mozilla::LogicalSide& aCornerOwner, bool& aBevel) const; + + void SetCorner(BCPixelSize aSubSize, mozilla::LogicalSide aOwner, + bool aBevel); + + inline bool IsIStartStart() const { return (bool)mIStartStart; } + + inline void SetIStartStart(bool aValue) { mIStartStart = aValue; } + + inline bool IsBStartStart() const { return (bool)mBStartStart; } + + inline void SetBStartStart(bool aValue) { mBStartStart = aValue; } + + protected: + BCPixelSize mIStartSize; // size in pixels of iStart border + BCPixelSize mBStartSize; // size in pixels of bStart border + BCPixelSize mCornerSubSize; // size of the largest border not in the + // dominant plane (for example, if corner is + // owned by the segment to its bStart or bEnd, + // then the size is the max of the border + // sizes of the segments to its iStart or iEnd. + unsigned mIStartOwner : 4; // owner of iStart border + unsigned mBStartOwner : 4; // owner of bStart border + unsigned mIStartStart : 1; // set if this is the start of a block-dir border + // segment + unsigned mBStartStart : 1; // set if this is the start of an inline-dir + // border segment + unsigned mCornerSide : 2; // LogicalSide of the owner of the bStart-iStart + // corner relative to the corner + unsigned mCornerBevel : 1; // is the corner beveled (only two segments, + // perpendicular, not dashed or dotted). +}; + +// BCCellData entries replace CellData entries in the cell map if the border +// collapsing model is in effect. BCData for a row and col entry contains the +// left and top borders of cell at that row and col and the corner connecting +// the two. The right borders of the cells in the last col and the bottom +// borders of the last row are stored in separate BCData entries in the cell +// map. +class BCCellData : public CellData { + public: + explicit BCCellData(nsTableCellFrame* aOrigCell); + ~BCCellData(); + + BCData mData; +}; + +// The layout of a celldata is as follows. The top 10 bits are the colspan +// offset (which is enough to represent our allowed values 1-1000 for colspan). +// Then there are two bits of flags. +// XXXmats Then one unused bit that we should decide how to use in bug 862624. +// Then 16 bits of rowspan offset (which +// lets us represent numbers up to 65535. Then another 3 bits of flags. + +// num bits to shift right to get right aligned col span +#define COL_SPAN_SHIFT 22 +// num bits to shift right to get right aligned row span +#define ROW_SPAN_SHIFT 3 + +// the col offset to the data containing the original cell. +#define COL_SPAN_OFFSET (0x3FF << COL_SPAN_SHIFT) +// the row offset to the data containing the original cell +#define ROW_SPAN_OFFSET (0xFFFF << ROW_SPAN_SHIFT) + +// And the flags +#define SPAN 0x00000001 // there a row or col span +#define ROW_SPAN 0x00000002 // there is a row span +#define ROW_SPAN_0 0x00000004 // the row span is 0 +#define COL_SPAN (1 << (COL_SPAN_SHIFT - 2)) // there is a col span +#define OVERLAP \ + (1 << (COL_SPAN_SHIFT - 1)) // there is a row span and + // col span but not by + // same cell + +inline nsTableCellFrame* CellData::GetCellFrame() const { + if (SPAN != (SPAN & mBits)) { + return mOrigCell; + } + return nullptr; +} + +inline void CellData::Init(nsTableCellFrame* aCellFrame) { + mOrigCell = aCellFrame; +} + +inline bool CellData::IsOrig() const { + return ((nullptr != mOrigCell) && (SPAN != (SPAN & mBits))); +} + +inline bool CellData::IsDead() const { return (0 == mBits); } + +inline bool CellData::IsSpan() const { return (SPAN == (SPAN & mBits)); } + +inline bool CellData::IsRowSpan() const { + return (SPAN == (SPAN & mBits)) && (ROW_SPAN == (ROW_SPAN & mBits)); +} + +inline bool CellData::IsZeroRowSpan() const { + return (SPAN == (SPAN & mBits)) && (ROW_SPAN == (ROW_SPAN & mBits)) && + (ROW_SPAN_0 == (ROW_SPAN_0 & mBits)); +} + +inline void CellData::SetZeroRowSpan(bool aIsZeroSpan) { + if (SPAN == (SPAN & mBits)) { + if (aIsZeroSpan) { + mBits |= ROW_SPAN_0; + } else { + mBits &= ~ROW_SPAN_0; + } + } +} + +inline uint32_t CellData::GetRowSpanOffset() const { + if ((SPAN == (SPAN & mBits)) && ((ROW_SPAN == (ROW_SPAN & mBits)))) { + return (uint32_t)((mBits & ROW_SPAN_OFFSET) >> ROW_SPAN_SHIFT); + } + return 0; +} + +inline void CellData::SetRowSpanOffset(uint32_t aSpan) { + mBits &= ~ROW_SPAN_OFFSET; + mBits |= (aSpan << ROW_SPAN_SHIFT); + mBits |= SPAN; + mBits |= ROW_SPAN; +} + +inline bool CellData::IsColSpan() const { + return (SPAN == (SPAN & mBits)) && (COL_SPAN == (COL_SPAN & mBits)); +} + +inline uint32_t CellData::GetColSpanOffset() const { + if ((SPAN == (SPAN & mBits)) && ((COL_SPAN == (COL_SPAN & mBits)))) { + return (uint32_t)((mBits & COL_SPAN_OFFSET) >> COL_SPAN_SHIFT); + } + return 0; +} + +inline void CellData::SetColSpanOffset(uint32_t aSpan) { + mBits &= ~COL_SPAN_OFFSET; + mBits |= (aSpan << COL_SPAN_SHIFT); + + mBits |= SPAN; + mBits |= COL_SPAN; +} + +inline bool CellData::IsOverlap() const { + return (SPAN == (SPAN & mBits)) && (OVERLAP == (OVERLAP & mBits)); +} + +inline void CellData::SetOverlap(bool aOverlap) { + if (SPAN == (SPAN & mBits)) { + if (aOverlap) { + mBits |= OVERLAP; + } else { + mBits &= ~OVERLAP; + } + } +} + +inline BCData::BCData() { + mIStartOwner = mBStartOwner = eCellOwner; + SetBStartStart(true); + SetIStartStart(true); + mIStartSize = mCornerSubSize = mBStartSize = 0; + mCornerSide = mozilla::eLogicalSideBStart; + mCornerBevel = false; +} + +inline BCData::~BCData() = default; + +inline nscoord BCData::GetIStartEdge(BCBorderOwner& aOwner, + bool& aStart) const { + aOwner = (BCBorderOwner)mIStartOwner; + aStart = IsIStartStart(); + + return (nscoord)mIStartSize; +} + +inline void BCData::SetIStartEdge(BCBorderOwner aOwner, nscoord aSize, + bool aStart) { + mIStartOwner = aOwner; + mIStartSize = (aSize > MAX_BORDER_WIDTH) ? MAX_BORDER_WIDTH : aSize; + SetIStartStart(aStart); +} + +inline nscoord BCData::GetBStartEdge(BCBorderOwner& aOwner, + bool& aStart) const { + aOwner = (BCBorderOwner)mBStartOwner; + aStart = IsBStartStart(); + + return (nscoord)mBStartSize; +} + +inline void BCData::SetBStartEdge(BCBorderOwner aOwner, nscoord aSize, + bool aStart) { + mBStartOwner = aOwner; + mBStartSize = (aSize > MAX_BORDER_WIDTH) ? MAX_BORDER_WIDTH : aSize; + SetBStartStart(aStart); +} + +inline BCPixelSize BCData::GetCorner(mozilla::LogicalSide& aOwnerSide, + bool& aBevel) const { + aOwnerSide = mozilla::LogicalSide(mCornerSide); + aBevel = (bool)mCornerBevel; + return mCornerSubSize; +} + +inline void BCData::SetCorner(BCPixelSize aSubSize, + mozilla::LogicalSide aOwnerSide, bool aBevel) { + mCornerSubSize = aSubSize; + mCornerSide = aOwnerSide; + mCornerBevel = aBevel; +} + +#endif |