зеркало из https://github.com/mozilla/gecko-dev.git
new class for collapsing borders, extracted from nsTableFrame, r=troy
This commit is contained in:
Родитель
ea13be0a26
Коммит
62b3a73832
|
@ -0,0 +1,872 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "nsIPresContext.h"
|
||||
#include "nsTableBorderCollapser.h"
|
||||
#include "nsTableFrame.h"
|
||||
#include "nsTableCellFrame.h"
|
||||
#include "nsTableColFrame.h"
|
||||
#include "nsCellMap.h"
|
||||
#include "cellData.h"
|
||||
|
||||
nsTableBorderCollapser::nsTableBorderCollapser(nsTableFrame& aTableFrame)
|
||||
:mTableFrame(aTableFrame)
|
||||
{
|
||||
}
|
||||
|
||||
nsTableBorderCollapser::~nsTableBorderCollapser()
|
||||
{
|
||||
for (PRInt32 sideX = 0; sideX < 4; sideX++) {
|
||||
nsBorderEdge* border = (nsBorderEdge *)(mBorderEdges.mEdges[sideX].ElementAt(0));
|
||||
while (border) {
|
||||
delete border;
|
||||
mBorderEdges.mEdges[sideX].RemoveElementAt(0);
|
||||
border = (nsBorderEdge *)(mBorderEdges.mEdges[sideX].ElementAt(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nsTableBorderCollapser::SetBorderEdgeLength(PRUint8 aSide,
|
||||
PRInt32 aIndex,
|
||||
nscoord aLength)
|
||||
{
|
||||
nsBorderEdge* border = (nsBorderEdge *)(mBorderEdges.mEdges[aSide].ElementAt(aIndex));
|
||||
if (border) {
|
||||
border->mLength = aLength;
|
||||
}
|
||||
}
|
||||
|
||||
void nsTableBorderCollapser::DidComputeHorizontalBorders(nsIPresContext& aPresContext,
|
||||
PRInt32 aStartRowIndex,
|
||||
PRInt32 aEndRowIndex)
|
||||
{
|
||||
// XXX: for now, this only does table edges. May need to do interior edges also? Probably not.
|
||||
PRInt32 lastRowIndex = mTableFrame.GetRowCount() - 1;
|
||||
PRInt32 lastColIndex = mTableFrame.GetColCount() - 1;
|
||||
if (0 == aStartRowIndex) {
|
||||
nsTableCellFrame* cellFrame = mTableFrame.GetCellInfoAt(0, 0);
|
||||
nsRect rowRect(0,0,0,0);
|
||||
if (cellFrame) {
|
||||
nsIFrame* rowFrame;
|
||||
cellFrame->GetParent(&rowFrame);
|
||||
rowFrame->GetRect(rowRect);
|
||||
nsBorderEdge* leftBorder = (nsBorderEdge *)(mBorderEdges.mEdges[NS_SIDE_LEFT].ElementAt(0));
|
||||
nsBorderEdge* rightBorder = (nsBorderEdge *)(mBorderEdges.mEdges[NS_SIDE_RIGHT].ElementAt(0));
|
||||
nsBorderEdge* topBorder = (nsBorderEdge *)(mBorderEdges.mEdges[NS_SIDE_TOP].ElementAt(0));
|
||||
if (leftBorder)
|
||||
leftBorder->mLength = rowRect.height + topBorder->mWidth;
|
||||
if (topBorder)
|
||||
topBorder = (nsBorderEdge *)(mBorderEdges.mEdges[NS_SIDE_TOP].ElementAt(lastColIndex));
|
||||
if (rightBorder)
|
||||
rightBorder->mLength = rowRect.height + topBorder->mWidth;
|
||||
}
|
||||
}
|
||||
|
||||
if (lastRowIndex <= aEndRowIndex) {
|
||||
nsTableCellFrame* cellFrame = mTableFrame.GetCellInfoAt(lastRowIndex, 0);
|
||||
nsRect rowRect(0,0,0,0);
|
||||
if (cellFrame) {
|
||||
nsIFrame* rowFrame;
|
||||
cellFrame->GetParent(&rowFrame);
|
||||
rowFrame->GetRect(rowRect);
|
||||
nsBorderEdge* leftBorder = (nsBorderEdge *)(mBorderEdges.mEdges[NS_SIDE_LEFT].ElementAt(lastRowIndex));
|
||||
nsBorderEdge* rightBorder = (nsBorderEdge *)(mBorderEdges.mEdges[NS_SIDE_RIGHT].ElementAt(lastRowIndex));
|
||||
nsBorderEdge* bottomBorder = (nsBorderEdge *)(mBorderEdges.mEdges[NS_SIDE_BOTTOM].ElementAt(0));
|
||||
if (leftBorder)
|
||||
leftBorder->mLength = rowRect.height + bottomBorder->mWidth;
|
||||
if (bottomBorder)
|
||||
bottomBorder = (nsBorderEdge *)(mBorderEdges.mEdges[NS_SIDE_BOTTOM].ElementAt(lastColIndex));
|
||||
if (rightBorder)
|
||||
rightBorder->mLength = rowRect.height + bottomBorder->mWidth;
|
||||
}
|
||||
}
|
||||
|
||||
for (PRInt32 borderX = NS_SIDE_TOP; borderX <= NS_SIDE_LEFT; borderX++) {
|
||||
if (!mBorderEdges.mEdges[borderX].ElementAt(0)) {
|
||||
mBorderEdges.mEdges[borderX].AppendElement(new nsBorderEdge());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// For every row between aStartRowIndex and aEndRowIndex (-1 == the end of the table),
|
||||
// walk across every edge and compute the border at that edge.
|
||||
// We compute each edge only once, arbitrarily choosing to compute right and bottom edges,
|
||||
// except for exterior cells that share a left or top edge with the table itself.
|
||||
// Distribute half the computed border to the appropriate adjacent objects
|
||||
// (always a cell frame or the table frame.) In the case of odd width,
|
||||
// the object on the right/bottom gets the extra portion
|
||||
|
||||
/* compute the top and bottom collapsed borders between aStartRowIndex and aEndRowIndex, inclusive */
|
||||
void nsTableBorderCollapser::ComputeHorizontalBorders(nsIPresContext& aPresContext,
|
||||
PRInt32 aStartRowIndex,
|
||||
PRInt32 aEndRowIndex)
|
||||
{
|
||||
PRInt32 colCount = mTableFrame.GetColCount();
|
||||
PRInt32 rowCount = mTableFrame.GetRowCount();
|
||||
if (aStartRowIndex >= rowCount) {
|
||||
return; // we don't have the requested row yet
|
||||
}
|
||||
|
||||
for (PRInt32 rowIndex = aStartRowIndex; (rowIndex < rowCount) && (rowIndex <= aEndRowIndex); rowIndex++) {
|
||||
for (PRInt32 colIndex = 0; colIndex < colCount; colIndex++) {
|
||||
if (0 == rowIndex) { // table is top neighbor
|
||||
ComputeTopBorderForEdgeAt(aPresContext, rowIndex, colIndex);
|
||||
}
|
||||
ComputeBottomBorderForEdgeAt(aPresContext, rowIndex, colIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* compute the left and right collapsed borders between aStartRowIndex and aEndRowIndex, inclusive */
|
||||
void nsTableBorderCollapser::ComputeVerticalBorders(nsIPresContext& aPresContext,
|
||||
PRInt32 aStartRowIndex,
|
||||
PRInt32 aEndRowIndex)
|
||||
{
|
||||
//nsCellMap* cellMap = mTableFrame.GetCellMap();
|
||||
//if (nsnull == cellMap)
|
||||
// return; // no info yet, so nothing useful to do
|
||||
|
||||
mTableFrame.CacheColFrames(aPresContext); // XXX why here?
|
||||
|
||||
// compute all the collapsing border values for the entire table
|
||||
// XXX: we have to make this more incremental!
|
||||
|
||||
PRInt32 colCount = mTableFrame.GetColCount();
|
||||
PRInt32 rowCount = mTableFrame.GetRowCount();
|
||||
PRInt32 endRowIndex = aEndRowIndex;
|
||||
if (-1 == endRowIndex)
|
||||
endRowIndex = rowCount-1;
|
||||
if (aStartRowIndex >= rowCount) {
|
||||
return; // we don't have the requested row yet
|
||||
}
|
||||
|
||||
for (PRInt32 rowX = aStartRowIndex; (rowX < rowCount) && (rowX <= endRowIndex); rowX++) {
|
||||
for (PRInt32 colX = 0; colX < colCount; colX++) {
|
||||
if (0 == colX) { // table is left neighbor
|
||||
ComputeLeftBorderForEdgeAt(aPresContext, rowX, colX);
|
||||
}
|
||||
ComputeRightBorderForEdgeAt(aPresContext, rowX, colX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nsTableBorderCollapser::ComputeLeftBorderForEdgeAt(nsIPresContext& aPresContext,
|
||||
PRInt32 aRowIndex,
|
||||
PRInt32 aColIndex)
|
||||
{
|
||||
PRInt32 numSegments = mBorderEdges.mEdges[NS_SIDE_LEFT].Count();
|
||||
while (numSegments <= aRowIndex) {
|
||||
nsBorderEdge* borderToAdd = new nsBorderEdge();
|
||||
mBorderEdges.mEdges[NS_SIDE_LEFT].AppendElement(borderToAdd);
|
||||
numSegments++;
|
||||
}
|
||||
// "border" is the border segment we are going to set
|
||||
nsBorderEdge *border = (nsBorderEdge *)(mBorderEdges.mEdges[NS_SIDE_LEFT].ElementAt(aRowIndex));
|
||||
if (!border)
|
||||
return;
|
||||
|
||||
// collect all the incident frames and compute the dominant border
|
||||
nsVoidArray styles;
|
||||
// styles are added to the array in the order least dominant -> most dominant
|
||||
// 1. table
|
||||
const nsStyleSpacing *spacing;
|
||||
mTableFrame.GetStyleData(eStyleStruct_Spacing, ((const nsStyleStruct *&)spacing));
|
||||
styles.AppendElement((void*)spacing);
|
||||
// 2. colgroup
|
||||
nsTableColFrame* colFrame;
|
||||
mTableFrame.GetColumnFrame(aColIndex, colFrame);
|
||||
nsIFrame* colGroupFrame;
|
||||
colFrame->GetParent(&colGroupFrame);
|
||||
colGroupFrame->GetStyleData(eStyleStruct_Spacing, ((const nsStyleStruct *&)spacing));
|
||||
styles.AppendElement((void*)spacing);
|
||||
// 3. col
|
||||
colFrame->GetStyleData(eStyleStruct_Spacing, ((const nsStyleStruct *&)spacing));
|
||||
styles.AppendElement((void*)spacing);
|
||||
// 4. rowgroup
|
||||
nsTableCellFrame* cellFrame = mTableFrame.GetCellInfoAt(aRowIndex, aColIndex);
|
||||
nsRect rowRect(0,0,0,0);
|
||||
if (cellFrame) {
|
||||
nsIFrame* rowFrame;
|
||||
cellFrame->GetParent(&rowFrame);
|
||||
rowFrame->GetRect(rowRect);
|
||||
nsIFrame* rowGroupFrame;
|
||||
rowFrame->GetParent(&rowGroupFrame);
|
||||
rowGroupFrame->GetStyleData(eStyleStruct_Spacing, ((const nsStyleStruct *&)spacing));
|
||||
styles.AppendElement((void*)spacing);
|
||||
// 5. row
|
||||
rowFrame->GetStyleData(eStyleStruct_Spacing, ((const nsStyleStruct *&)spacing));
|
||||
styles.AppendElement((void*)spacing);
|
||||
// 6. cell (need to do something smart for rowspanner with row frame)
|
||||
cellFrame->GetStyleData(eStyleStruct_Spacing, ((const nsStyleStruct *&)spacing));
|
||||
styles.AppendElement((void*)spacing);
|
||||
}
|
||||
ComputeBorderSegment(NS_SIDE_LEFT, &styles, *border, PR_FALSE);
|
||||
// now give half the computed border to the table segment, and half to the cell
|
||||
// to avoid rounding errors, we convert up to pixels, divide by 2, and
|
||||
// we give the odd pixel to the table border
|
||||
float t2p;
|
||||
aPresContext.GetTwipsToPixels(&t2p);
|
||||
float p2t;
|
||||
aPresContext.GetPixelsToTwips(&p2t);
|
||||
nscoord widthAsPixels = NSToCoordRound((float)(border->mWidth)*t2p);
|
||||
nscoord widthToAdd = 0;
|
||||
border->mWidth = widthAsPixels/2;
|
||||
if ((border->mWidth*2)!=widthAsPixels)
|
||||
widthToAdd = NSToCoordCeil(p2t);
|
||||
border->mWidth *= NSToCoordCeil(p2t);
|
||||
border->mLength = rowRect.height;
|
||||
border->mInsideNeighbor = cellFrame->mBorderEdges;
|
||||
// we need to factor in the table's horizontal borders.
|
||||
// but we can't compute that length here because we don't know how thick top and bottom borders are
|
||||
// see DidComputeHorizontalCollapsingBorders
|
||||
if (nsnull!=cellFrame)
|
||||
{
|
||||
cellFrame->SetBorderEdge(NS_SIDE_LEFT, aRowIndex, aColIndex, border, 0); // set the left edge of the cell frame
|
||||
}
|
||||
border->mWidth += widthToAdd;
|
||||
mBorderEdges.mMaxBorderWidth.left = PR_MAX(border->mWidth, mBorderEdges.mMaxBorderWidth.left);
|
||||
}
|
||||
|
||||
void nsTableBorderCollapser::ComputeRightBorderForEdgeAt(nsIPresContext& aPresContext,
|
||||
PRInt32 aRowIndex,
|
||||
PRInt32 aColIndex)
|
||||
{
|
||||
nsCellMap* cellMap = mTableFrame.GetCellMap();
|
||||
if (!cellMap) {
|
||||
return;
|
||||
}
|
||||
|
||||
PRInt32 colCount = mTableFrame.GetColCount();
|
||||
PRInt32 numSegments = mBorderEdges.mEdges[NS_SIDE_RIGHT].Count();
|
||||
while (numSegments <= aRowIndex) {
|
||||
nsBorderEdge* borderToAdd = new nsBorderEdge();
|
||||
mBorderEdges.mEdges[NS_SIDE_RIGHT].AppendElement(borderToAdd);
|
||||
numSegments++;
|
||||
}
|
||||
// "border" is the border segment we are going to set
|
||||
nsBorderEdge border;
|
||||
|
||||
// collect all the incident frames and compute the dominant border
|
||||
nsVoidArray styles;
|
||||
// styles are added to the array in the order least dominant -> most dominant
|
||||
// 1. table, only if this cell is in the right-most column and no rowspanning cell is
|
||||
// to it's right. Otherwise, we remember what cell is the right neighbor
|
||||
nsTableCellFrame* rightNeighborFrame=nsnull;
|
||||
|
||||
if ((colCount - 1) != aColIndex) {
|
||||
for (PRInt32 colIndex = aColIndex + 1; colIndex < colCount; colIndex++) {
|
||||
CellData* cd = cellMap->GetCellAt(aRowIndex, colIndex);
|
||||
if (cd) { // there's really a cell at (aRowIndex, colIndex)
|
||||
if (!cd->mOrigCell) { // the cell at (aRowIndex, colIndex) is the result of a span
|
||||
nsTableCellFrame* cell = nsnull;
|
||||
if (cd->mRowSpanData)
|
||||
cell = cd->mRowSpanData->mOrigCell;
|
||||
else if (cd->mColSpanData)
|
||||
cell = cd->mColSpanData->mOrigCell;
|
||||
NS_ASSERTION(cell, "bad cell map state, missing real cell");
|
||||
PRInt32 realRowIndex;
|
||||
cell->GetRowIndex (realRowIndex);
|
||||
if (realRowIndex!=aRowIndex) { // the span is caused by a rowspan
|
||||
rightNeighborFrame = cd->mRowSpanData->mOrigCell;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
rightNeighborFrame = cd->mOrigCell;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const nsStyleSpacing *spacing;
|
||||
if (!rightNeighborFrame) {
|
||||
// if rightNeighborFrame is null, our right neighbor is the table
|
||||
mTableFrame.GetStyleData(eStyleStruct_Spacing, ((const nsStyleStruct *&)spacing));
|
||||
styles.AppendElement((void*)spacing);
|
||||
}
|
||||
// 2. colgroup //XXX: need to test if we're really on a colgroup border
|
||||
nsTableColFrame* colFrame = cellMap->GetColumnFrame(aColIndex);
|
||||
nsIFrame* colGroupFrame;
|
||||
colFrame->GetParent(&colGroupFrame);
|
||||
colGroupFrame->GetStyleData(eStyleStruct_Spacing, ((const nsStyleStruct *&)spacing));
|
||||
styles.AppendElement((void*)spacing);
|
||||
// 3. col
|
||||
colFrame->GetStyleData(eStyleStruct_Spacing, ((const nsStyleStruct *&)spacing));
|
||||
styles.AppendElement((void*)spacing);
|
||||
// 4. rowgroup
|
||||
nsTableCellFrame* cellFrame = cellMap->GetCellInfoAt(aRowIndex, aColIndex);
|
||||
nsRect rowRect(0,0,0,0);
|
||||
if (cellFrame) {
|
||||
nsIFrame* rowFrame;
|
||||
cellFrame->GetParent(&rowFrame);
|
||||
rowFrame->GetRect(rowRect);
|
||||
nsIFrame* rowGroupFrame;
|
||||
rowFrame->GetParent(&rowGroupFrame);
|
||||
if (!rightNeighborFrame) {
|
||||
// if rightNeighborFrame is null, our right neighbor is the table so we include the rowgroup and row
|
||||
rowGroupFrame->GetStyleData(eStyleStruct_Spacing, ((const nsStyleStruct *&)spacing));
|
||||
styles.AppendElement((void*)spacing);
|
||||
// 5. row
|
||||
rowFrame->GetStyleData(eStyleStruct_Spacing, ((const nsStyleStruct *&)spacing));
|
||||
styles.AppendElement((void*)spacing);
|
||||
}
|
||||
// 6. cell (need to do something smart for rowspanner with row frame)
|
||||
cellFrame->GetStyleData(eStyleStruct_Spacing, ((const nsStyleStruct *&)spacing));
|
||||
styles.AppendElement((void*)spacing);
|
||||
}
|
||||
// 7. left edge of rightNeighborCell, if there is one
|
||||
if (rightNeighborFrame) {
|
||||
rightNeighborFrame->GetStyleData(eStyleStruct_Spacing, ((const nsStyleStruct *&)spacing));
|
||||
styles.AppendElement((void*)spacing);
|
||||
}
|
||||
ComputeBorderSegment(NS_SIDE_RIGHT, &styles, border, (nsnull != rightNeighborFrame));
|
||||
// now give half the computed border to each of the two neighbors
|
||||
// (the 2 cells, or the cell and the table)
|
||||
// to avoid rounding errors, we convert up to pixels, divide by 2, and
|
||||
// we give the odd pixel to the right cell border
|
||||
float t2p;
|
||||
aPresContext.GetTwipsToPixels(&t2p);
|
||||
float p2t;
|
||||
aPresContext.GetPixelsToTwips(&p2t);
|
||||
nscoord widthAsPixels = NSToCoordRound((float)(border.mWidth)*t2p);
|
||||
nscoord widthToAdd = 0;
|
||||
border.mWidth = widthAsPixels/2;
|
||||
if ((border.mWidth*2) != widthAsPixels)
|
||||
widthToAdd = NSToCoordCeil(p2t);
|
||||
border.mWidth *= NSToCoordCeil(p2t);
|
||||
border.mLength = rowRect.height;
|
||||
if (cellFrame) {
|
||||
cellFrame->SetBorderEdge(NS_SIDE_RIGHT, aRowIndex, aColIndex, &border, widthToAdd);
|
||||
}
|
||||
if (!rightNeighborFrame) {
|
||||
nsBorderEdge * tableBorder = (nsBorderEdge *)(mBorderEdges.mEdges[NS_SIDE_RIGHT].ElementAt(aRowIndex));
|
||||
*tableBorder = border;
|
||||
if (cellFrame) {
|
||||
tableBorder->mInsideNeighbor = cellFrame->mBorderEdges;
|
||||
}
|
||||
mBorderEdges.mMaxBorderWidth.right = PR_MAX(border.mWidth, mBorderEdges.mMaxBorderWidth.right);
|
||||
// since the table is our right neightbor, we need to factor in the table's horizontal borders.
|
||||
// can't compute that length here because we don't know how thick top and bottom borders are
|
||||
// see DidComputeHorizontalCollapsingBorders
|
||||
}
|
||||
else {
|
||||
rightNeighborFrame->SetBorderEdge(NS_SIDE_LEFT, aRowIndex, aColIndex, &border, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void nsTableBorderCollapser::ComputeTopBorderForEdgeAt(nsIPresContext& aPresContext,
|
||||
PRInt32 aRowIndex,
|
||||
PRInt32 aColIndex)
|
||||
{
|
||||
nsCellMap* cellMap = mTableFrame.GetCellMap();
|
||||
if (!cellMap) {
|
||||
return;
|
||||
}
|
||||
|
||||
PRInt32 numSegments = mBorderEdges.mEdges[NS_SIDE_TOP].Count();
|
||||
while (numSegments<=aColIndex) {
|
||||
nsBorderEdge* borderToAdd = new nsBorderEdge();
|
||||
mBorderEdges.mEdges[NS_SIDE_TOP].AppendElement(borderToAdd);
|
||||
numSegments++;
|
||||
}
|
||||
// "border" is the border segment we are going to set
|
||||
nsBorderEdge *border = (nsBorderEdge *)(mBorderEdges.mEdges[NS_SIDE_TOP].ElementAt(aColIndex));
|
||||
if (!border)
|
||||
return;
|
||||
|
||||
// collect all the incident frames and compute the dominant border
|
||||
nsVoidArray styles;
|
||||
// styles are added to the array in the order least dominant -> most dominant
|
||||
// 1. table
|
||||
const nsStyleSpacing *spacing;
|
||||
mTableFrame.GetStyleData(eStyleStruct_Spacing, ((const nsStyleStruct *&)spacing));
|
||||
styles.AppendElement((void*)spacing);
|
||||
// 2. colgroup
|
||||
nsTableColFrame* colFrame = cellMap->GetColumnFrame(aColIndex);
|
||||
nsIFrame* colGroupFrame;
|
||||
colFrame->GetParent(&colGroupFrame);
|
||||
colGroupFrame->GetStyleData(eStyleStruct_Spacing, ((const nsStyleStruct *&)spacing));
|
||||
styles.AppendElement((void*)spacing);
|
||||
// 3. col
|
||||
colFrame->GetStyleData(eStyleStruct_Spacing, ((const nsStyleStruct *&)spacing));
|
||||
styles.AppendElement((void*)spacing);
|
||||
// 4. rowgroup
|
||||
nsTableCellFrame* cellFrame = cellMap->GetCellInfoAt(aRowIndex, aColIndex);
|
||||
if (cellFrame) {
|
||||
nsIFrame* rowFrame;
|
||||
cellFrame->GetParent(&rowFrame);
|
||||
nsIFrame* rowGroupFrame;
|
||||
rowFrame->GetParent(&rowGroupFrame);
|
||||
rowGroupFrame->GetStyleData(eStyleStruct_Spacing, ((const nsStyleStruct *&)spacing));
|
||||
styles.AppendElement((void*)spacing);
|
||||
// 5. row
|
||||
rowFrame->GetStyleData(eStyleStruct_Spacing, ((const nsStyleStruct *&)spacing));
|
||||
styles.AppendElement((void*)spacing);
|
||||
// 6. cell (need to do something smart for rowspanner with row frame)
|
||||
cellFrame->GetStyleData(eStyleStruct_Spacing, ((const nsStyleStruct *&)spacing));
|
||||
styles.AppendElement((void*)spacing);
|
||||
}
|
||||
ComputeBorderSegment(NS_SIDE_TOP, &styles, *border, PR_FALSE);
|
||||
// now give half the computed border to the table segment, and half to the cell
|
||||
// to avoid rounding errors, we convert up to pixels, divide by 2, and
|
||||
// we give the odd pixel to the right border
|
||||
float t2p;
|
||||
aPresContext.GetTwipsToPixels(&t2p);
|
||||
float p2t;
|
||||
aPresContext.GetPixelsToTwips(&p2t);
|
||||
nscoord widthAsPixels = NSToCoordRound((float)(border->mWidth)*t2p);
|
||||
nscoord widthToAdd = 0;
|
||||
border->mWidth = widthAsPixels/2;
|
||||
if ((border->mWidth*2) != widthAsPixels)
|
||||
widthToAdd = NSToCoordCeil(p2t);
|
||||
border->mWidth *= NSToCoordCeil(p2t);
|
||||
border->mLength = mTableFrame.GetColumnWidth(aColIndex);
|
||||
border->mInsideNeighbor = cellFrame->mBorderEdges;
|
||||
if (0 == aColIndex) {
|
||||
// if we're the first column, factor in the thickness of the left table border
|
||||
nsBorderEdge *leftBorder = (nsBorderEdge *)(mBorderEdges.mEdges[NS_SIDE_LEFT].ElementAt(0));
|
||||
if (leftBorder)
|
||||
border->mLength += leftBorder->mWidth;
|
||||
}
|
||||
if ((cellMap->GetColCount() - 1) == aColIndex) {
|
||||
// if we're the last column, factor in the thickness of the right table border
|
||||
nsBorderEdge* rightBorder = (nsBorderEdge *)(mBorderEdges.mEdges[NS_SIDE_RIGHT].ElementAt(0));
|
||||
if (rightBorder)
|
||||
border->mLength += rightBorder->mWidth;
|
||||
}
|
||||
if (cellFrame) {
|
||||
cellFrame->SetBorderEdge(NS_SIDE_TOP, aRowIndex, aColIndex, border, 0); // set the top edge of the cell frame
|
||||
}
|
||||
border->mWidth += widthToAdd;
|
||||
mBorderEdges.mMaxBorderWidth.top = PR_MAX(border->mWidth, mBorderEdges.mMaxBorderWidth.top);
|
||||
}
|
||||
|
||||
void nsTableBorderCollapser::ComputeBottomBorderForEdgeAt(nsIPresContext& aPresContext,
|
||||
PRInt32 aRowIndex,
|
||||
PRInt32 aColIndex)
|
||||
{
|
||||
nsCellMap* cellMap = mTableFrame.GetCellMap();
|
||||
if (!cellMap) {
|
||||
return;
|
||||
}
|
||||
|
||||
PRInt32 rowCount = cellMap->GetRowCount();
|
||||
PRInt32 numSegments = mBorderEdges.mEdges[NS_SIDE_BOTTOM].Count();
|
||||
while (numSegments <= aColIndex) {
|
||||
nsBorderEdge* borderToAdd = new nsBorderEdge();
|
||||
mBorderEdges.mEdges[NS_SIDE_BOTTOM].AppendElement(borderToAdd);
|
||||
numSegments++;
|
||||
}
|
||||
// "border" is the border segment we are going to set
|
||||
nsBorderEdge border;
|
||||
|
||||
// collect all the incident frames and compute the dominant border
|
||||
nsVoidArray styles;
|
||||
// styles are added to the array in the order least dominant -> most dominant
|
||||
// 1. table, only if this cell is in the bottom-most row and no colspanning cell is
|
||||
// beneath it. Otherwise, we remember what cell is the bottom neighbor
|
||||
nsTableCellFrame* bottomNeighborFrame=nsnull;
|
||||
if ((rowCount-1) != aRowIndex) {
|
||||
for (PRInt32 rowIndex = aRowIndex + 1; rowIndex < rowCount; rowIndex++) {
|
||||
CellData* cd = cellMap->GetCellAt(rowIndex, aColIndex);
|
||||
if (cd) { // there's really a cell at (rowIndex, aColIndex)
|
||||
if (!cd->mOrigCell) {
|
||||
// the cell at (rowIndex, aColIndex) is the result of a span
|
||||
nsTableCellFrame* cell = nsnull;
|
||||
if (cd->mRowSpanData) // XXX should we check for a row span
|
||||
cell = cd->mRowSpanData->mOrigCell;
|
||||
else if (cd->mColSpanData)
|
||||
cell = cd->mColSpanData->mOrigCell;
|
||||
NS_ASSERTION( cell, "bad cell map state, missing real cell");
|
||||
PRInt32 realColIndex;
|
||||
cell->GetColIndex (realColIndex);
|
||||
if (realColIndex!=aColIndex) { // the span is caused by a colspan
|
||||
bottomNeighborFrame = cd->mColSpanData->mOrigCell;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
bottomNeighborFrame = cd->mOrigCell;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const nsStyleSpacing *spacing;
|
||||
if (!bottomNeighborFrame) {
|
||||
// if bottomNeighborFrame is null, our bottom neighbor is the table
|
||||
mTableFrame.GetStyleData(eStyleStruct_Spacing, ((const nsStyleStruct *&)spacing));
|
||||
styles.AppendElement((void*)spacing);
|
||||
|
||||
// 2. colgroup // XXX: need to deterine if we're on a colgroup boundary
|
||||
nsTableColFrame* colFrame = cellMap->GetColumnFrame(aColIndex);
|
||||
nsIFrame* colGroupFrame;
|
||||
colFrame->GetParent(&colGroupFrame);
|
||||
colGroupFrame->GetStyleData(eStyleStruct_Spacing, ((const nsStyleStruct *&)spacing));
|
||||
styles.AppendElement((void*)spacing);
|
||||
// 3. col
|
||||
colFrame->GetStyleData(eStyleStruct_Spacing, ((const nsStyleStruct *&)spacing));
|
||||
styles.AppendElement((void*)spacing);
|
||||
}
|
||||
// 4. rowgroup // XXX: use rowgroup only if we're on a table edge
|
||||
nsTableCellFrame* cellFrame = cellMap->GetCellInfoAt(aRowIndex, aColIndex);
|
||||
nsRect rowRect(0,0,0,0);
|
||||
if (cellFrame) {
|
||||
nsIFrame* rowFrame;
|
||||
cellFrame->GetParent(&rowFrame);
|
||||
rowFrame->GetRect(rowRect);
|
||||
nsIFrame* rowGroupFrame;
|
||||
rowFrame->GetParent(&rowGroupFrame);
|
||||
rowGroupFrame->GetStyleData(eStyleStruct_Spacing, ((const nsStyleStruct *&)spacing));
|
||||
styles.AppendElement((void*)spacing);
|
||||
// 5. row
|
||||
rowFrame->GetStyleData(eStyleStruct_Spacing, ((const nsStyleStruct *&)spacing));
|
||||
styles.AppendElement((void*)spacing);
|
||||
// 6. cell (need to do something smart for rowspanner with row frame)
|
||||
cellFrame->GetStyleData(eStyleStruct_Spacing, ((const nsStyleStruct *&)spacing));
|
||||
styles.AppendElement((void*)spacing);
|
||||
}
|
||||
// 7. top edge of bottomNeighborCell, if there is one
|
||||
if (bottomNeighborFrame) {
|
||||
bottomNeighborFrame->GetStyleData(eStyleStruct_Spacing, ((const nsStyleStruct *&)spacing));
|
||||
styles.AppendElement((void*)spacing);
|
||||
}
|
||||
ComputeBorderSegment(NS_SIDE_BOTTOM, &styles, border, (nsnull != bottomNeighborFrame));
|
||||
// now give half the computed border to each of the two neighbors
|
||||
// (the 2 cells, or the cell and the table)
|
||||
// to avoid rounding errors, we convert up to pixels, divide by 2, and
|
||||
// we give the odd pixel to the right cell border
|
||||
float t2p;
|
||||
aPresContext.GetTwipsToPixels(&t2p);
|
||||
float p2t;
|
||||
aPresContext.GetPixelsToTwips(&p2t);
|
||||
nscoord widthAsPixels = NSToCoordRound((float)(border.mWidth)*t2p);
|
||||
nscoord widthToAdd = 0;
|
||||
border.mWidth = widthAsPixels/2;
|
||||
if ((border.mWidth*2) != widthAsPixels)
|
||||
widthToAdd = NSToCoordCeil(p2t);
|
||||
border.mWidth *= NSToCoordCeil(p2t);
|
||||
border.mLength = mTableFrame.GetColumnWidth(aColIndex);
|
||||
if (cellFrame) {
|
||||
cellFrame->SetBorderEdge(NS_SIDE_BOTTOM, aRowIndex, aColIndex, &border, widthToAdd);
|
||||
}
|
||||
if (!bottomNeighborFrame) {
|
||||
nsBorderEdge* tableBorder = (nsBorderEdge *)(mBorderEdges.mEdges[NS_SIDE_BOTTOM].ElementAt(aColIndex));
|
||||
*tableBorder = border;
|
||||
if (cellFrame) {
|
||||
tableBorder->mInsideNeighbor = cellFrame->mBorderEdges;
|
||||
}
|
||||
mBorderEdges.mMaxBorderWidth.bottom = PR_MAX(border.mWidth, mBorderEdges.mMaxBorderWidth.bottom);
|
||||
// since the table is our bottom neightbor, we need to factor in the table's vertical borders.
|
||||
PRInt32 lastColIndex = cellMap->GetColCount()-1;
|
||||
if (0 == aColIndex) {
|
||||
// if we're the first column, factor in the thickness of the left table border
|
||||
nsBorderEdge *leftBorder = (nsBorderEdge *)(mBorderEdges.mEdges[NS_SIDE_LEFT].ElementAt(rowCount-1));
|
||||
if (leftBorder)
|
||||
tableBorder->mLength += leftBorder->mWidth;
|
||||
}
|
||||
if (lastColIndex == aColIndex) {
|
||||
// if we're the last column, factor in the thickness of the right table border
|
||||
nsBorderEdge *rightBorder = (nsBorderEdge *)(mBorderEdges.mEdges[NS_SIDE_RIGHT].ElementAt(rowCount-1));
|
||||
if (rightBorder)
|
||||
tableBorder->mLength += rightBorder->mWidth;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bottomNeighborFrame->SetBorderEdge(NS_SIDE_TOP, aRowIndex, aColIndex, &border, 0);
|
||||
}
|
||||
}
|
||||
|
||||
nscoord nsTableBorderCollapser::GetWidthForSide(const nsMargin& aBorder,
|
||||
PRUint8 aSide)
|
||||
{
|
||||
if (NS_SIDE_LEFT == aSide)
|
||||
return aBorder.left;
|
||||
else if (NS_SIDE_RIGHT == aSide)
|
||||
return aBorder.right;
|
||||
else if (NS_SIDE_TOP == aSide)
|
||||
return aBorder.top;
|
||||
else
|
||||
return aBorder.bottom;
|
||||
}
|
||||
|
||||
/* Given an Edge, find the opposing edge (top<-->bottom, left<-->right) */
|
||||
PRUint8 nsTableBorderCollapser::GetOpposingEdge(PRUint8 aEdge)
|
||||
{
|
||||
PRUint8 result;
|
||||
switch (aEdge)
|
||||
{
|
||||
case NS_SIDE_LEFT:
|
||||
result = NS_SIDE_RIGHT; break;
|
||||
case NS_SIDE_RIGHT:
|
||||
result = NS_SIDE_LEFT; break;
|
||||
case NS_SIDE_TOP:
|
||||
result = NS_SIDE_BOTTOM; break;
|
||||
case NS_SIDE_BOTTOM:
|
||||
result = NS_SIDE_TOP; break;
|
||||
default:
|
||||
result = NS_SIDE_TOP;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* returns BORDER_PRECEDENT_LOWER if aStyle1 is lower precedent that aStyle2
|
||||
* BORDER_PRECEDENT_HIGHER if aStyle1 is higher precedent that aStyle2
|
||||
* BORDER_PRECEDENT_EQUAL if aStyle1 and aStyle2 have the same precedence
|
||||
* (note, this is not necessarily the same as saying aStyle1==aStyle2)
|
||||
* this is a method on nsTableFrame because other objects might define their
|
||||
* own border precedence rules.
|
||||
*/
|
||||
PRUint8 nsTableBorderCollapser::CompareBorderStyles(PRUint8 aStyle1,
|
||||
PRUint8 aStyle2)
|
||||
{
|
||||
PRUint8 result=BORDER_PRECEDENT_HIGHER; // if we get illegal types for table borders, HIGHER is the default
|
||||
if (aStyle1 == aStyle2)
|
||||
result = BORDER_PRECEDENT_EQUAL;
|
||||
else if (NS_STYLE_BORDER_STYLE_HIDDEN==aStyle1)
|
||||
result = BORDER_PRECEDENT_HIGHER;
|
||||
else if (NS_STYLE_BORDER_STYLE_NONE==aStyle1)
|
||||
result = BORDER_PRECEDENT_LOWER;
|
||||
else if (NS_STYLE_BORDER_STYLE_NONE==aStyle2)
|
||||
result = BORDER_PRECEDENT_HIGHER;
|
||||
else if (NS_STYLE_BORDER_STYLE_HIDDEN==aStyle2)
|
||||
result = BORDER_PRECEDENT_LOWER;
|
||||
else {
|
||||
switch (aStyle1) {
|
||||
case NS_STYLE_BORDER_STYLE_BG_INSET:
|
||||
result = BORDER_PRECEDENT_LOWER;
|
||||
break;
|
||||
|
||||
case NS_STYLE_BORDER_STYLE_GROOVE:
|
||||
if (NS_STYLE_BORDER_STYLE_BG_INSET==aStyle2)
|
||||
result = BORDER_PRECEDENT_HIGHER;
|
||||
else
|
||||
result = BORDER_PRECEDENT_LOWER;
|
||||
break;
|
||||
|
||||
case NS_STYLE_BORDER_STYLE_BG_OUTSET:
|
||||
if (NS_STYLE_BORDER_STYLE_BG_INSET==aStyle2 ||
|
||||
NS_STYLE_BORDER_STYLE_GROOVE==aStyle2)
|
||||
result = BORDER_PRECEDENT_HIGHER;
|
||||
else
|
||||
result = BORDER_PRECEDENT_LOWER;
|
||||
break;
|
||||
|
||||
case NS_STYLE_BORDER_STYLE_RIDGE:
|
||||
if (NS_STYLE_BORDER_STYLE_BG_INSET==aStyle2 ||
|
||||
NS_STYLE_BORDER_STYLE_GROOVE==aStyle2 ||
|
||||
NS_STYLE_BORDER_STYLE_BG_OUTSET==aStyle2)
|
||||
result = BORDER_PRECEDENT_HIGHER;
|
||||
else
|
||||
result = BORDER_PRECEDENT_LOWER;
|
||||
break;
|
||||
|
||||
case NS_STYLE_BORDER_STYLE_DOTTED:
|
||||
if (NS_STYLE_BORDER_STYLE_BG_INSET==aStyle2 ||
|
||||
NS_STYLE_BORDER_STYLE_GROOVE==aStyle2 ||
|
||||
NS_STYLE_BORDER_STYLE_BG_OUTSET==aStyle2 ||
|
||||
NS_STYLE_BORDER_STYLE_RIDGE==aStyle2)
|
||||
result = BORDER_PRECEDENT_HIGHER;
|
||||
else
|
||||
result = BORDER_PRECEDENT_LOWER;
|
||||
break;
|
||||
|
||||
case NS_STYLE_BORDER_STYLE_DASHED:
|
||||
if (NS_STYLE_BORDER_STYLE_BG_INSET==aStyle2 ||
|
||||
NS_STYLE_BORDER_STYLE_GROOVE==aStyle2 ||
|
||||
NS_STYLE_BORDER_STYLE_BG_OUTSET==aStyle2 ||
|
||||
NS_STYLE_BORDER_STYLE_RIDGE==aStyle2 ||
|
||||
NS_STYLE_BORDER_STYLE_DOTTED==aStyle2)
|
||||
result = BORDER_PRECEDENT_HIGHER;
|
||||
else
|
||||
result = BORDER_PRECEDENT_LOWER;
|
||||
break;
|
||||
|
||||
case NS_STYLE_BORDER_STYLE_SOLID:
|
||||
if (NS_STYLE_BORDER_STYLE_BG_INSET==aStyle2 ||
|
||||
NS_STYLE_BORDER_STYLE_GROOVE==aStyle2 ||
|
||||
NS_STYLE_BORDER_STYLE_BG_OUTSET==aStyle2 ||
|
||||
NS_STYLE_BORDER_STYLE_RIDGE==aStyle2 ||
|
||||
NS_STYLE_BORDER_STYLE_DOTTED==aStyle2 ||
|
||||
NS_STYLE_BORDER_STYLE_DASHED==aStyle2)
|
||||
result = BORDER_PRECEDENT_HIGHER;
|
||||
else
|
||||
result = BORDER_PRECEDENT_LOWER;
|
||||
break;
|
||||
|
||||
case NS_STYLE_BORDER_STYLE_DOUBLE:
|
||||
result = BORDER_PRECEDENT_LOWER;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
This method is the CSS2 border conflict resolution algorithm
|
||||
The spec says to resolve conflicts in this order:
|
||||
1. any border with the style HIDDEN wins
|
||||
2. the widest border with a style that is not NONE wins
|
||||
3. the border styles are ranked in this order, highest to lowest precedence:
|
||||
double, solid, dashed, dotted, ridge, outset, groove, inset
|
||||
4. borders that are of equal width and style (differ only in color) have this precedence:
|
||||
cell, row, rowgroup, col, colgroup, table
|
||||
5. if all border styles are NONE, then that's the computed border style.
|
||||
This method assumes that the styles were added to aStyles in the reverse precedence order
|
||||
of their frame type, so that styles that come later in the list win over style
|
||||
earlier in the list if the tie-breaker gets down to #4.
|
||||
This method sets the out-param aBorder with the resolved border attributes
|
||||
*/
|
||||
void nsTableBorderCollapser::ComputeBorderSegment(PRUint8 aSide,
|
||||
nsVoidArray* aStyles,
|
||||
nsBorderEdge &aBorder,
|
||||
PRBool aFlipLastSide)
|
||||
{
|
||||
if (aStyles) {
|
||||
PRInt32 styleCount = aStyles->Count();
|
||||
if (0 != styleCount) {
|
||||
nsVoidArray sameWidthBorders;
|
||||
nsStyleSpacing * spacing;
|
||||
nsStyleSpacing * lastSpacing=nsnull;
|
||||
nsMargin border;
|
||||
PRInt32 maxWidth=0;
|
||||
PRUint8 side = aSide;
|
||||
PRInt32 i;
|
||||
for (i = 0; i < styleCount; i++) {
|
||||
spacing = (nsStyleSpacing *)(aStyles->ElementAt(i));
|
||||
if (aFlipLastSide && (i == styleCount-1)) {
|
||||
side = GetOpposingEdge(aSide);
|
||||
lastSpacing = spacing;
|
||||
}
|
||||
if (spacing->GetBorderStyle(side) == NS_STYLE_BORDER_STYLE_HIDDEN) {
|
||||
aBorder.mStyle=NS_STYLE_BORDER_STYLE_HIDDEN;
|
||||
aBorder.mWidth=0;
|
||||
return;
|
||||
}
|
||||
else if (spacing->GetBorderStyle(side)!=NS_STYLE_BORDER_STYLE_NONE) {
|
||||
spacing->GetBorder(border);
|
||||
nscoord borderWidth = GetWidthForSide(border, side);
|
||||
if (borderWidth == maxWidth)
|
||||
sameWidthBorders.AppendElement(spacing);
|
||||
else if (borderWidth > maxWidth) {
|
||||
maxWidth = borderWidth;
|
||||
sameWidthBorders.Clear();
|
||||
sameWidthBorders.AppendElement(spacing);
|
||||
}
|
||||
}
|
||||
}
|
||||
aBorder.mWidth = maxWidth;
|
||||
// now we've gone through each overlapping border once, and we have a list
|
||||
// of all styles with the same width. If there's more than one, resolve the
|
||||
// conflict based on border style
|
||||
styleCount = sameWidthBorders.Count();
|
||||
if (0 == styleCount) { // all borders were of style NONE
|
||||
aBorder.mWidth=0;
|
||||
aBorder.mStyle=NS_STYLE_BORDER_STYLE_NONE;
|
||||
return;
|
||||
}
|
||||
else if (1 == styleCount) { // there was just one border of the largest width
|
||||
spacing = (nsStyleSpacing *)(sameWidthBorders.ElementAt(0));
|
||||
side = aSide;
|
||||
if (spacing == lastSpacing)
|
||||
side = GetOpposingEdge(aSide);
|
||||
if (!spacing->GetBorderColor(side, aBorder.mColor)) {
|
||||
// XXX EEEK handle transparent border color somehow...
|
||||
}
|
||||
aBorder.mStyle = spacing->GetBorderStyle(side);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
nsStyleSpacing* winningStyleBorder;
|
||||
PRUint8 winningStyle=NS_STYLE_BORDER_STYLE_NONE;
|
||||
for (i = 0; i < styleCount; i++) {
|
||||
spacing = (nsStyleSpacing *)(sameWidthBorders.ElementAt(i));
|
||||
side = aSide;
|
||||
if (spacing == lastSpacing)
|
||||
side = GetOpposingEdge(aSide);
|
||||
PRUint8 thisStyle = spacing->GetBorderStyle(side);
|
||||
PRUint8 borderCompare = CompareBorderStyles(thisStyle, winningStyle);
|
||||
if (BORDER_PRECEDENT_HIGHER == borderCompare) {
|
||||
winningStyle = thisStyle;
|
||||
winningStyleBorder = spacing;
|
||||
}
|
||||
else if (BORDER_PRECEDENT_EQUAL == borderCompare) {
|
||||
// we're in lowest-to-highest precedence order, so later border styles win
|
||||
winningStyleBorder=spacing;
|
||||
}
|
||||
}
|
||||
aBorder.mStyle = winningStyle;
|
||||
side = aSide;
|
||||
if (winningStyleBorder == lastSpacing)
|
||||
side = GetOpposingEdge(aSide);
|
||||
if (!winningStyleBorder->GetBorderColor(side, aBorder.mColor)) {
|
||||
// XXX handle transparent border colors somehow
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void nsTableBorderCollapser::GetBorder(nsMargin& aBorder)
|
||||
{
|
||||
aBorder = mBorderEdges.mMaxBorderWidth;
|
||||
}
|
||||
|
||||
void nsTableBorderCollapser::GetBorderAt(PRInt32 aRowIndex,
|
||||
PRInt32 aColIndex,
|
||||
nsMargin& aBorder)
|
||||
{
|
||||
nsBorderEdge* border = (nsBorderEdge *)(mBorderEdges.mEdges[NS_SIDE_LEFT].ElementAt(aRowIndex));
|
||||
if (border) {
|
||||
aBorder.left = border->mWidth;
|
||||
}
|
||||
border = (nsBorderEdge *)(mBorderEdges.mEdges[NS_SIDE_RIGHT].ElementAt(aRowIndex));
|
||||
if (border) {
|
||||
aBorder.right = border->mWidth;
|
||||
}
|
||||
border = (nsBorderEdge *)(mBorderEdges.mEdges[NS_SIDE_TOP].ElementAt(aColIndex));
|
||||
if (border) {
|
||||
aBorder.top = border->mWidth;
|
||||
}
|
||||
border = (nsBorderEdge *)(mBorderEdges.mEdges[NS_SIDE_BOTTOM].ElementAt(aColIndex));
|
||||
if (border) {
|
||||
aBorder.bottom = border->mWidth;
|
||||
}
|
||||
}
|
||||
|
||||
void nsTableBorderCollapser::GetMaxBorder(PRInt32 aStartRowIndex,
|
||||
PRInt32 aEndRowIndex,
|
||||
PRInt32 aStartColIndex,
|
||||
PRInt32 aEndColIndex,
|
||||
nsMargin aBorder)
|
||||
{
|
||||
aBorder.top = aBorder.right = aBorder.bottom = aBorder.left = 0;
|
||||
for (PRInt32 rowX = aStartRowIndex; rowX <= aEndRowIndex; rowX++) {
|
||||
for (PRInt32 colX = aStartColIndex; colX <= aEndColIndex; colX++) {
|
||||
nsMargin border;
|
||||
GetBorderAt(rowX, colX, border);
|
||||
aBorder.top = PR_MAX(aBorder.top, border.top);
|
||||
aBorder.right = PR_MAX(aBorder.right, border.right);
|
||||
aBorder.bottom = PR_MAX(aBorder.bottom, border.bottom);
|
||||
aBorder.left = PR_MAX(aBorder.left, border.left);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
#ifndef nsTableBorderCollapser_h__
|
||||
#define nsTableBorderCollapser_h__
|
||||
|
||||
#include "nsIStyleContext.h"
|
||||
class nsTableFrame;
|
||||
|
||||
/**
|
||||
* Class for handling CSS border-style:collapse
|
||||
*/
|
||||
class nsTableBorderCollapser
|
||||
{
|
||||
public:
|
||||
nsTableBorderCollapser(nsTableFrame& aTableFrame);
|
||||
|
||||
~nsTableBorderCollapser();
|
||||
|
||||
/** notification that top and bottom borders have been computed */
|
||||
void DidComputeHorizontalBorders(nsIPresContext& aPresContext,
|
||||
PRInt32 aStartRowIndex,
|
||||
PRInt32 aEndRowIndex);
|
||||
|
||||
/** compute the left and right collapsed borders between aStartRowIndex and aEndRowIndex, inclusive */
|
||||
void ComputeVerticalBorders(nsIPresContext& aPresContext,
|
||||
PRInt32 aStartRowIndex,
|
||||
PRInt32 aEndRowIndex);
|
||||
|
||||
/** compute the top and bottom collapsed borders between aStartRowIndex and aEndRowIndex, inclusive */
|
||||
void ComputeHorizontalBorders(nsIPresContext& aPresContext,
|
||||
PRInt32 aStartRowIndex,
|
||||
PRInt32 aEndRowIndex);
|
||||
|
||||
/** compute the left borders for the table objects intersecting at (aRowIndex, aColIndex) */
|
||||
void ComputeLeftBorderForEdgeAt(nsIPresContext& aPresContext,
|
||||
PRInt32 aRowIndex,
|
||||
PRInt32 aColIndex);
|
||||
|
||||
/** compute the right border for the table cell at (aRowIndex, aColIndex)
|
||||
* and the appropriate border for that cell's right neighbor
|
||||
* (the left border for a neighboring cell, or the right table edge)
|
||||
*/
|
||||
void ComputeRightBorderForEdgeAt(nsIPresContext& aPresContext,
|
||||
PRInt32 aRowIndex,
|
||||
PRInt32 aColIndex);
|
||||
|
||||
/** compute the top borders for the table objects intersecting at (aRowIndex, aColIndex) */
|
||||
void ComputeTopBorderForEdgeAt(nsIPresContext& aPresContext,
|
||||
PRInt32 aRowIndex,
|
||||
PRInt32 aColIndex);
|
||||
|
||||
/** compute the bottom border for the table cell at (aRowIndex, aColIndex)
|
||||
* and the appropriate border for that cell's bottom neighbor
|
||||
* (the top border for a neighboring cell, or the bottom table edge)
|
||||
*/
|
||||
void ComputeBottomBorderForEdgeAt(nsIPresContext& aPresContext,
|
||||
PRInt32 aRowIndex,
|
||||
PRInt32 aColIndex);
|
||||
|
||||
/** at the time we initially compute collapsing borders, we don't yet have the
|
||||
* column widths. So we set them as a post-process of the column balancing algorithm.
|
||||
*/
|
||||
void SetHorizontalEdgeLengths();
|
||||
|
||||
/** @return the identifier representing the edge opposite from aEdge (left-right, top-bottom) */
|
||||
PRUint8 GetOpposingEdge(PRUint8 aEdge);
|
||||
|
||||
/** @return the computed width for aSide of aBorder */
|
||||
nscoord GetWidthForSide(const nsMargin& aBorder,
|
||||
PRUint8 aSide);
|
||||
|
||||
/** returns BORDER_PRECEDENT_LOWER if aStyle1 is lower precedent that aStyle2
|
||||
* BORDER_PRECEDENT_HIGHER if aStyle1 is higher precedent that aStyle2
|
||||
* BORDER_PRECEDENT_EQUAL if aStyle1 and aStyle2 have the same precedence
|
||||
* (note, this is not necessarily the same as saying aStyle1==aStyle2)
|
||||
* according to the CSS-2 collapsing borders for tables precedent rules.
|
||||
*/
|
||||
PRUint8 CompareBorderStyles(PRUint8 aStyle1,
|
||||
PRUint8 aStyle2);
|
||||
|
||||
/** helper to set the length of an edge for aSide border of this table frame */
|
||||
void SetBorderEdgeLength(PRUint8 aSide,
|
||||
PRInt32 aIndex,
|
||||
nscoord aLength);
|
||||
|
||||
/** Compute the style, width, and color of an edge in a collapsed-border table.
|
||||
* This method is the CSS2 border conflict resolution algorithm
|
||||
* The spec says to resolve conflicts in this order:<br>
|
||||
* 1. any border with the style HIDDEN wins<br>
|
||||
* 2. the widest border with a style that is not NONE wins<br>
|
||||
* 3. the border styles are ranked in this order, highest to lowest precedence:<br>
|
||||
* double, solid, dashed, dotted, ridge, outset, groove, inset<br>
|
||||
* 4. borders that are of equal width and style (differ only in color) have this precedence:<br>
|
||||
* cell, row, rowgroup, col, colgroup, table<br>
|
||||
* 5. if all border styles are NONE, then that's the computed border style.<br>
|
||||
* This method assumes that the styles were added to aStyles in the reverse precedence order
|
||||
* of their frame type, so that styles that come later in the list win over style
|
||||
* earlier in the list if the tie-breaker gets down to #4.
|
||||
* This method sets the out-param aBorder with the resolved border attributes
|
||||
*
|
||||
* @param aSide the side that is being compared
|
||||
* @param aStyles the resolved styles of the table objects intersecting at aSide
|
||||
* styles must be added to this list in reverse precedence order
|
||||
* @param aBorder [OUT] the border edge that we're computing. Results of the computation
|
||||
* are stored in aBorder: style, color, and width.
|
||||
* @param aFlipLastSide an indication of what the bordering object is: another cell, or the table itself.
|
||||
*/
|
||||
void ComputeBorderSegment(PRUint8 aSide,
|
||||
nsVoidArray* aStyles,
|
||||
nsBorderEdge& aBorder,
|
||||
PRBool aFlipLastSide);
|
||||
|
||||
void GetBorder(nsMargin& aBorder);
|
||||
|
||||
void GetBorderAt(PRInt32 aRowIndex,
|
||||
PRInt32 aColIndex,
|
||||
nsMargin& aBorder);
|
||||
|
||||
void GetMaxBorder(PRInt32 aStartRowIndex,
|
||||
PRInt32 aEndRowIndex,
|
||||
PRInt32 aStartColIndex,
|
||||
PRInt32 aEndColIndex,
|
||||
nsMargin aBorder);
|
||||
|
||||
nsBorderEdges* GetEdges();
|
||||
|
||||
protected:
|
||||
nsBorderEdges mBorderEdges;
|
||||
nsTableFrame& mTableFrame;
|
||||
};
|
||||
|
||||
inline nsBorderEdges* nsTableBorderCollapser::GetEdges()
|
||||
{
|
||||
return &mBorderEdges;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Загрузка…
Ссылка в новой задаче