/* -*- 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 "nsCoord.h" #include "mozilla/gfx/Types.h" class nsTableCellFrame; class nsCellMap; class BCCellData; #define MAX_ROWSPAN 65534 // the cellmap can not handle more. #define MAX_COLSPAN 1000 // limit as IE and opera do. If this ever changes, // change COL_SPAN_OFFSET/COL_SPAN_SHIFT accordingly. /** * 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; /** is the entry spanned by a zero colspan * zero colspans span all cells starting from the originating cell towards * the end of the colgroup or a cell originating in the same row * or a rowspanned entry * @return is true if the entry is spanned by a zero colspan */ bool IsZeroColSpan() const; /** mark the current entry as spanned by a zero colspan * @param aIsZero if true mark the entry as covered by a zero colspan */ void SetZeroColSpan(bool aIsZero); /** 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; /** constructor. * @param aOrigCell the table cell frame which will be stored in mOrigCell. */ CellData(nsTableCellFrame* aOrigCell); // implemented in nsCellMap.cpp /** destructor */ ~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 be an unsigned long because it must match the size of // mOrigCell on both 32- and 64-bit platforms. union { nsTableCellFrame* mOrigCell; unsigned long 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 }; 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(PR_BITMASK(sizeof(BCPixelSize) * 8)) static inline nscoord BC_BORDER_TOP_HALF_COORD(int32_t p2t, uint16_t px) { return (px - px / 2) * p2t; } static inline nscoord BC_BORDER_RIGHT_HALF_COORD(int32_t p2t, uint16_t px) { return ( px / 2) * p2t; } static inline nscoord BC_BORDER_BOTTOM_HALF_COORD(int32_t p2t, uint16_t px) { return ( px / 2) * p2t; } static inline nscoord BC_BORDER_LEFT_HALF_COORD(int32_t p2t, uint16_t px) { return (px - px / 2) * p2t; } #define BC_BORDER_TOP_HALF(px) ((px) - (px) / 2) #define BC_BORDER_RIGHT_HALF(px) ((px) / 2) #define BC_BORDER_BOTTOM_HALF(px) ((px) / 2) #define BC_BORDER_LEFT_HALF(px) ((px) - (px) / 2) // BCData stores the top and left border info and the corner connecting the two. class BCData { public: BCData(); ~BCData(); nscoord GetLeftEdge(BCBorderOwner& aOwner, bool& aStart) const; void SetLeftEdge(BCBorderOwner aOwner, nscoord aSize, bool aStart); nscoord GetTopEdge(BCBorderOwner& aOwner, bool& aStart) const; void SetTopEdge(BCBorderOwner aOwner, nscoord aSize, bool aStart); BCPixelSize GetCorner(mozilla::css::Side& aCornerOwner, bool& aBevel) const; void SetCorner(BCPixelSize aSubSize, mozilla::css::Side aOwner, bool aBevel); bool IsLeftStart() const; void SetLeftStart(bool aValue); bool IsTopStart() const; void SetTopStart(bool aValue); protected: BCPixelSize mLeftSize; // size in pixels of left border BCPixelSize mTopSize; // size in pixels of top border BCPixelSize mCornerSubSize; // size of the largest border not in the // dominant plane (for example, if corner is // owned by the segment to its top or bottom, // then the size is the max of the border // sizes of the segments to its left or right. unsigned mLeftOwner: 4; // owner of left border unsigned mTopOwner: 4; // owner of top border unsigned mLeftStart: 1; // set if this is the start of a vertical border segment unsigned mTopStart: 1; // set if this is the start of a horizontal border segment unsigned mCornerSide: 2; // mozilla::css::Side of the owner of the upper left 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: 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 three bits of flags. 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 - 3)) // there is a col span #define COL_SPAN_0 (1 << (COL_SPAN_SHIFT - 2)) // the col span is 0 #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 bool CellData::IsZeroColSpan() const { return (SPAN == (SPAN & mBits)) && (COL_SPAN == (COL_SPAN & mBits)) && (COL_SPAN_0 == (COL_SPAN_0 & mBits)); } inline void CellData::SetZeroColSpan(bool aIsZeroSpan) { if (SPAN == (SPAN & mBits)) { if (aIsZeroSpan) { mBits |= COL_SPAN_0; } else { mBits &= ~COL_SPAN_0; } } } 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() { mLeftOwner = mTopOwner = eCellOwner; mLeftStart = mTopStart = 1; mLeftSize = mCornerSubSize = mTopSize = 0; mCornerSide = NS_SIDE_TOP; mCornerBevel = false; } inline BCData::~BCData() { } inline nscoord BCData::GetLeftEdge(BCBorderOwner& aOwner, bool& aStart) const { aOwner = (BCBorderOwner)mLeftOwner; aStart = (bool)mLeftStart; return (nscoord)mLeftSize; } inline void BCData::SetLeftEdge(BCBorderOwner aOwner, nscoord aSize, bool aStart) { mLeftOwner = aOwner; mLeftSize = (aSize > MAX_BORDER_WIDTH) ? MAX_BORDER_WIDTH : aSize; mLeftStart = aStart; } inline nscoord BCData::GetTopEdge(BCBorderOwner& aOwner, bool& aStart) const { aOwner = (BCBorderOwner)mTopOwner; aStart = (bool)mTopStart; return (nscoord)mTopSize; } inline void BCData::SetTopEdge(BCBorderOwner aOwner, nscoord aSize, bool aStart) { mTopOwner = aOwner; mTopSize = (aSize > MAX_BORDER_WIDTH) ? MAX_BORDER_WIDTH : aSize; mTopStart = aStart; } inline BCPixelSize BCData::GetCorner(mozilla::css::Side& aOwnerSide, bool& aBevel) const { aOwnerSide = mozilla::css::Side(mCornerSide); aBevel = (bool)mCornerBevel; return mCornerSubSize; } inline void BCData::SetCorner(BCPixelSize aSubSize, mozilla::css::Side aOwnerSide, bool aBevel) { mCornerSubSize = aSubSize; mCornerSide = aOwnerSide; mCornerBevel = aBevel; } inline bool BCData::IsLeftStart() const { return (bool)mLeftStart; } inline void BCData::SetLeftStart(bool aValue) { mLeftStart = aValue; } inline bool BCData::IsTopStart() const { return (bool)mTopStart; } inline void BCData::SetTopStart(bool aValue) { mTopStart = aValue; } #endif