pjs/layout/tables/celldata.h

522 строки
16 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#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
* nsnull
*/
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
*/
PRUint32 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(PRUint32 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
*/
PRUint32 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(PRUint32 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 nsnull 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 PRUint16 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(PRInt32 p2t, PRUint16 px) { return (px - px / 2) * p2t; }
static inline nscoord
BC_BORDER_RIGHT_HALF_COORD(PRInt32 p2t, PRUint16 px) { return ( px / 2) * p2t; }
static inline nscoord
BC_BORDER_BOTTOM_HALF_COORD(PRInt32 p2t, PRUint16 px) { return ( px / 2) * p2t; }
static inline nscoord
BC_BORDER_LEFT_HALF_COORD(PRInt32 p2t, PRUint16 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 nsnull;
}
inline void CellData::Init(nsTableCellFrame* aCellFrame)
{
mOrigCell = aCellFrame;
}
inline bool CellData::IsOrig() const
{
return ((nsnull != 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 PRUint32 CellData::GetRowSpanOffset() const
{
if ((SPAN == (SPAN & mBits)) && ((ROW_SPAN == (ROW_SPAN & mBits)))) {
return (PRUint32)((mBits & ROW_SPAN_OFFSET) >> ROW_SPAN_SHIFT);
}
return 0;
}
inline void CellData::SetRowSpanOffset(PRUint32 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 PRUint32 CellData::GetColSpanOffset() const
{
if ((SPAN == (SPAN & mBits)) && ((COL_SPAN == (COL_SPAN & mBits)))) {
return (PRUint32)((mBits & COL_SPAN_OFFSET) >> COL_SPAN_SHIFT);
}
return 0;
}
inline void CellData::SetColSpanOffset(PRUint32 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