diff --git a/mozilla/content/html/content/src/nsHTMLTableElement.cpp b/mozilla/content/html/content/src/nsHTMLTableElement.cpp
index bbd8619d3b8..bcfbfc95a5d 100644
--- a/mozilla/content/html/content/src/nsHTMLTableElement.cpp
+++ b/mozilla/content/html/content/src/nsHTMLTableElement.cpp
@@ -1412,39 +1412,44 @@ MapAttributesIntoRule(const nsIHTMLMappedAttributes* aAttributes,
nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
}
else if (aData->mSID == eStyleStruct_Border && aData->mMarginData) {
- const nsStyleDisplay* readDisplay = (nsStyleDisplay*)
- aData->mStyleContext->GetStyleData(eStyleStruct_Display);
-
+ if (!aData->mStyleContext) return;
+ const nsStyleTableBorder* tableStyle =
+ (const nsStyleTableBorder*)aData->mStyleContext->GetStyleData(eStyleStruct_TableBorder);
+ const nsStyleDisplay* readDisplay =
+ (nsStyleDisplay*) aData->mStyleContext->GetStyleData(eStyleStruct_Display);
if (readDisplay &&
(readDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE_CELL)) {
- // set the cell's border from the table
- nsHTMLValue value;
- aAttributes->GetAttribute(nsHTMLAtoms::border, value);
- if (((value.GetUnit() == eHTMLUnit_Pixel) &&
- (value.GetPixelValue() > 0)) ||
- (value.GetUnit() == eHTMLUnit_Empty)) {
- if (aData->mMarginData->mBorderWidth->mLeft.GetUnit() == eCSSUnit_Null)
- aData->mMarginData->mBorderWidth->mLeft.SetFloatValue(1.0f, eCSSUnit_Pixel);
- if (aData->mMarginData->mBorderWidth->mRight.GetUnit() == eCSSUnit_Null)
- aData->mMarginData->mBorderWidth->mRight.SetFloatValue(1.0f, eCSSUnit_Pixel);
- if (aData->mMarginData->mBorderWidth->mTop.GetUnit() == eCSSUnit_Null)
- aData->mMarginData->mBorderWidth->mTop.SetFloatValue(1.0f, eCSSUnit_Pixel);
- if (aData->mMarginData->mBorderWidth->mBottom.GetUnit() == eCSSUnit_Null)
- aData->mMarginData->mBorderWidth->mBottom.SetFloatValue(1.0f, eCSSUnit_Pixel);
+ if (NS_STYLE_BORDER_SEPARATE == tableStyle->mBorderCollapse) {
+ // Set the cell's border from the table in the separate border model. If there is a border
+ // on the table, then the mapping to rules=all will take care of borders in the collapsing model.
+ nsHTMLValue value;
+ aAttributes->GetAttribute(nsHTMLAtoms::border, value);
+ if (((value.GetUnit() == eHTMLUnit_Pixel) &&
+ (value.GetPixelValue() > 0)) ||
+ (value.GetUnit() == eHTMLUnit_Empty)) {
+ if (aData->mMarginData->mBorderWidth->mLeft.GetUnit() == eCSSUnit_Null)
+ aData->mMarginData->mBorderWidth->mLeft.SetFloatValue(1.0f, eCSSUnit_Pixel);
+ if (aData->mMarginData->mBorderWidth->mRight.GetUnit() == eCSSUnit_Null)
+ aData->mMarginData->mBorderWidth->mRight.SetFloatValue(1.0f, eCSSUnit_Pixel);
+ if (aData->mMarginData->mBorderWidth->mTop.GetUnit() == eCSSUnit_Null)
+ aData->mMarginData->mBorderWidth->mTop.SetFloatValue(1.0f, eCSSUnit_Pixel);
+ if (aData->mMarginData->mBorderWidth->mBottom.GetUnit() == eCSSUnit_Null)
+ aData->mMarginData->mBorderWidth->mBottom.SetFloatValue(1.0f, eCSSUnit_Pixel);
- PRUint8 borderStyle = (eCompatibility_NavQuirks == mode)
- ? NS_STYLE_BORDER_STYLE_BG_INSET : NS_STYLE_BORDER_STYLE_INSET;
+ PRUint8 borderStyle = (eCompatibility_NavQuirks == mode)
+ ? NS_STYLE_BORDER_STYLE_BG_INSET : NS_STYLE_BORDER_STYLE_INSET;
// BG_INSET results in a border color based on background colors
// used for NavQuirks only...
- if (aData->mMarginData->mBorderStyle->mLeft.GetUnit() == eCSSUnit_Null)
- aData->mMarginData->mBorderStyle->mLeft.SetIntValue(borderStyle, eCSSUnit_Enumerated);
- if (aData->mMarginData->mBorderStyle->mRight.GetUnit() == eCSSUnit_Null)
- aData->mMarginData->mBorderStyle->mRight.SetIntValue(borderStyle, eCSSUnit_Enumerated);
- if (aData->mMarginData->mBorderStyle->mTop.GetUnit() == eCSSUnit_Null)
- aData->mMarginData->mBorderStyle->mTop.SetIntValue(borderStyle, eCSSUnit_Enumerated);
- if (aData->mMarginData->mBorderStyle->mBottom.GetUnit() == eCSSUnit_Null)
- aData->mMarginData->mBorderStyle->mBottom.SetIntValue(borderStyle, eCSSUnit_Enumerated);
+ if (aData->mMarginData->mBorderStyle->mLeft.GetUnit() == eCSSUnit_Null)
+ aData->mMarginData->mBorderStyle->mLeft.SetIntValue(borderStyle, eCSSUnit_Enumerated);
+ if (aData->mMarginData->mBorderStyle->mRight.GetUnit() == eCSSUnit_Null)
+ aData->mMarginData->mBorderStyle->mRight.SetIntValue(borderStyle, eCSSUnit_Enumerated);
+ if (aData->mMarginData->mBorderStyle->mTop.GetUnit() == eCSSUnit_Null)
+ aData->mMarginData->mBorderStyle->mTop.SetIntValue(borderStyle, eCSSUnit_Enumerated);
+ if (aData->mMarginData->mBorderStyle->mBottom.GetUnit() == eCSSUnit_Null)
+ aData->mMarginData->mBorderStyle->mBottom.SetIntValue(borderStyle, eCSSUnit_Enumerated);
+ }
}
}
else {
@@ -1458,7 +1463,6 @@ MapAttributesIntoRule(const nsIHTMLMappedAttributes* aAttributes,
PRUint8 borderStyle = (eCompatibility_NavQuirks == mode)
? NS_STYLE_BORDER_STYLE_BG_OUTSET :
NS_STYLE_BORDER_STYLE_OUTSET;
-
// bordercolor
nsHTMLValue value;
aAttributes->GetAttribute(nsHTMLAtoms::bordercolor, value);
@@ -1476,6 +1480,18 @@ MapAttributesIntoRule(const nsIHTMLMappedAttributes* aAttributes,
borderStyle = NS_STYLE_BORDER_STYLE_OUTSET; // use css outset
}
+ else if (NS_STYLE_BORDER_COLLAPSE == tableStyle->mBorderCollapse) {
+ // make the color grey
+ nscolor color = NS_RGB(80, 80, 80);
+ if (aData->mMarginData->mBorderColor->mLeft.GetUnit() == eCSSUnit_Null)
+ aData->mMarginData->mBorderColor->mLeft.SetColorValue(color);
+ if (aData->mMarginData->mBorderColor->mRight.GetUnit() == eCSSUnit_Null)
+ aData->mMarginData->mBorderColor->mRight.SetColorValue(color);
+ if (aData->mMarginData->mBorderColor->mTop.GetUnit() == eCSSUnit_Null)
+ aData->mMarginData->mBorderColor->mTop.SetColorValue(color);
+ if (aData->mMarginData->mBorderColor->mBottom.GetUnit() == eCSSUnit_Null)
+ aData->mMarginData->mBorderColor->mBottom.SetColorValue(color);
+ }
// border and frame
MapTableBorderInto(aAttributes, aData, borderStyle);
@@ -1500,7 +1516,6 @@ nsHTMLTableElement::GetMappedAttributeImpact(const nsIAtom* aAttribute, PRInt32
(aAttribute == nsHTMLAtoms::cellpadding) ||
(aAttribute == nsHTMLAtoms::cellspacing) ||
(aAttribute == nsHTMLAtoms::cols) ||
- (aAttribute == nsHTMLAtoms::rules) ||
(aAttribute == nsHTMLAtoms::border) ||
(aAttribute == nsHTMLAtoms::frame) ||
(aAttribute == nsHTMLAtoms::width) ||
@@ -1512,7 +1527,10 @@ nsHTMLTableElement::GetMappedAttributeImpact(const nsIAtom* aAttribute, PRInt32
else if (aAttribute == nsHTMLAtoms::bordercolor) {
aHint = NS_STYLE_HINT_VISUAL;
}
- else if (aAttribute == nsHTMLAtoms::align) {
+ else if ((aAttribute == nsHTMLAtoms::align) ||
+ (aAttribute == nsHTMLAtoms::rules)) {
+ // Changing to rules will force border-collapse. Unfortunately, if border-collapse was
+ // already in effect, then a frame change is not necessary.
aHint = NS_STYLE_HINT_FRAMECHANGE;
}
else if (!GetCommonMappedAttributesImpact(aAttribute, aHint)) {
diff --git a/mozilla/content/html/style/src/nsHTMLStyleSheet.cpp b/mozilla/content/html/style/src/nsHTMLStyleSheet.cpp
index 2421da50e03..1ec64eabe97 100644
--- a/mozilla/content/html/style/src/nsHTMLStyleSheet.cpp
+++ b/mozilla/content/html/style/src/nsHTMLStyleSheet.cpp
@@ -475,6 +475,254 @@ TableTHRule::MapRuleInfoInto(nsRuleData* aRuleData)
return NS_OK;
}
+static void
+ProcessTableRulesAttribute(nsStyleStruct* aStyleStruct,
+ nsRuleData* aRuleData,
+ PRUint8 aSide,
+ PRBool aGroup,
+ PRUint8 aRulesArg1,
+ PRUint8 aRulesArg2,
+ PRUint8 aRulesArg3)
+{
+ if (!aStyleStruct || !aRuleData || !aRuleData->mPresContext) return;
+
+ nsCOMPtr tableContext = getter_AddRefs(aRuleData->mStyleContext->GetParent()); if (!tableContext) return;
+ if (!aGroup) {
+ tableContext = getter_AddRefs(tableContext->GetParent()); if (!tableContext) return;
+ }
+
+ const nsStyleTable* tableData =
+ (const nsStyleTable*)tableContext->GetStyleData(eStyleStruct_Table);
+ if (tableData && ((aRulesArg1 == tableData->mRules) ||
+ (aRulesArg2 == tableData->mRules) ||
+ (aRulesArg3 == tableData->mRules))) {
+ const nsStyleBorder* tableBorderData =
+ (const nsStyleBorder*)tableContext->GetStyleData(eStyleStruct_Border); if (!tableBorderData) return;
+ PRUint8 tableBorderStyle = tableBorderData->GetBorderStyle(aSide);
+
+ nsStyleBorder* borderData = (nsStyleBorder*)aStyleStruct; if (!borderData) return;
+ PRUint8 borderStyle = borderData->GetBorderStyle(aSide);
+ // XXX It appears that the style system erronously applies the custom style rule after css style,
+ // consequently it does not properly fit into the casade. For now, assume that a border style of none
+ // implies that the style has not been set.
+ if (NS_STYLE_BORDER_STYLE_NONE == borderStyle) {
+ // use the table's border style if it is dashed or dotted, otherwise use solid
+ PRUint8 bStyle = ((NS_STYLE_BORDER_STYLE_NONE != tableBorderStyle) &&
+ (NS_STYLE_BORDER_STYLE_HIDDEN != tableBorderStyle))
+ ? tableBorderStyle : NS_STYLE_BORDER_STYLE_SOLID;
+ if ((NS_STYLE_BORDER_STYLE_DASHED != bStyle) &&
+ (NS_STYLE_BORDER_STYLE_DOTTED != bStyle) &&
+ (NS_STYLE_BORDER_STYLE_SOLID != bStyle)) {
+ bStyle = NS_STYLE_BORDER_STYLE_SOLID;
+ }
+ bStyle |= NS_STYLE_BORDER_STYLE_RULES_MASK;
+ borderData->SetBorderStyle(aSide, bStyle);
+
+ nscolor borderColor;
+ PRBool transparent, foreground;
+ borderData->GetBorderColor(aSide, borderColor, transparent, foreground);
+ if (transparent || foreground) {
+ // use the table's border color if it is set, otherwise use black
+ nscolor tableBorderColor;
+ tableBorderData->GetBorderColor(aSide, tableBorderColor, transparent, foreground);
+ borderColor = (transparent || foreground) ? NS_RGB(0,0,0) : tableBorderColor;
+ borderData->SetBorderColor(aSide, borderColor);
+ }
+ // set the border width to be 1 pixel
+ float p2t;
+ aRuleData->mPresContext->GetScaledPixelsToTwips(&p2t);
+ nscoord onePixel = NSToCoordRound(p2t);
+ nsStyleCoord coord(onePixel);
+ switch(aSide) {
+ case NS_SIDE_TOP:
+ borderData->mBorder.SetTop(coord);
+ break;
+ case NS_SIDE_RIGHT:
+ borderData->mBorder.SetRight(coord);
+ break;
+ case NS_SIDE_BOTTOM:
+ borderData->mBorder.SetBottom(coord);
+ break;
+ default: // NS_SIDE_LEFT
+ borderData->mBorder.SetLeft(coord);
+ break;
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------
+// this rule handles borders on a , , when rules is set on its
+// -----------------------------------------------------------
+class TableTbodyRule: public GenericTableRule {
+public:
+ TableTbodyRule(nsIHTMLStyleSheet* aSheet);
+ virtual ~TableTbodyRule();
+
+ void Reset()
+ {
+ GenericTableRule::Reset();
+ }
+
+ NS_IMETHOD MapRuleInfoInto(nsRuleData* aRuleData);
+};
+
+TableTbodyRule::TableTbodyRule(nsIHTMLStyleSheet* aSheet)
+: GenericTableRule(aSheet)
+{
+}
+
+TableTbodyRule::~TableTbodyRule()
+{
+}
+
+static void TbodyPostResolveCallback(nsStyleStruct* aStyleStruct, nsRuleData* aRuleData)
+{
+ ::ProcessTableRulesAttribute(aStyleStruct, aRuleData, NS_SIDE_TOP, PR_TRUE, NS_STYLE_TABLE_RULES_ALL,
+ NS_STYLE_TABLE_RULES_GROUPS, NS_STYLE_TABLE_RULES_ROWS);
+ ::ProcessTableRulesAttribute(aStyleStruct, aRuleData, NS_SIDE_BOTTOM, PR_TRUE, NS_STYLE_TABLE_RULES_ALL,
+ NS_STYLE_TABLE_RULES_GROUPS, NS_STYLE_TABLE_RULES_ROWS);
+}
+
+NS_IMETHODIMP
+TableTbodyRule::MapRuleInfoInto(nsRuleData* aRuleData)
+{
+ if (aRuleData && aRuleData->mSID == eStyleStruct_Border) {
+ aRuleData->mCanStoreInRuleTree = PR_FALSE;
+ aRuleData->mPostResolveCallback = &TbodyPostResolveCallback;
+ }
+ return NS_OK;
+}
+// -----------------------------------------------------------
+
+// -----------------------------------------------------------
+// this rule handles borders on a when rules is set on its
+// -----------------------------------------------------------
+class TableRowRule: public GenericTableRule {
+public:
+ TableRowRule(nsIHTMLStyleSheet* aSheet);
+ virtual ~TableRowRule();
+
+ void Reset()
+ {
+ GenericTableRule::Reset();
+ }
+
+ NS_IMETHOD MapRuleInfoInto(nsRuleData* aRuleData);
+};
+
+TableRowRule::TableRowRule(nsIHTMLStyleSheet* aSheet)
+: GenericTableRule(aSheet)
+{
+}
+
+TableRowRule::~TableRowRule()
+{
+}
+
+static void RowPostResolveCallback(nsStyleStruct* aStyleStruct, nsRuleData* aRuleData)
+{
+ ::ProcessTableRulesAttribute(aStyleStruct, aRuleData, NS_SIDE_TOP, PR_FALSE, NS_STYLE_TABLE_RULES_ALL,
+ NS_STYLE_TABLE_RULES_ROWS, NS_STYLE_TABLE_RULES_ROWS);
+ ::ProcessTableRulesAttribute(aStyleStruct, aRuleData, NS_SIDE_BOTTOM, PR_FALSE, NS_STYLE_TABLE_RULES_ALL,
+ NS_STYLE_TABLE_RULES_ROWS, NS_STYLE_TABLE_RULES_ROWS);
+}
+
+NS_IMETHODIMP
+TableRowRule::MapRuleInfoInto(nsRuleData* aRuleData)
+{
+ if (aRuleData && aRuleData->mSID == eStyleStruct_Border) {
+ aRuleData->mCanStoreInRuleTree = PR_FALSE;
+ aRuleData->mPostResolveCallback = &RowPostResolveCallback;
+ }
+ return NS_OK;
+}
+
+// -----------------------------------------------------------
+// this rule handles borders on a when rules is set on its
+// -----------------------------------------------------------
+class TableColgroupRule: public GenericTableRule {
+public:
+ TableColgroupRule(nsIHTMLStyleSheet* aSheet);
+ virtual ~TableColgroupRule();
+
+ void Reset()
+ {
+ GenericTableRule::Reset();
+ }
+
+ NS_IMETHOD MapRuleInfoInto(nsRuleData* aRuleData);
+};
+
+TableColgroupRule::TableColgroupRule(nsIHTMLStyleSheet* aSheet)
+: GenericTableRule(aSheet)
+{
+}
+
+TableColgroupRule::~TableColgroupRule()
+{
+}
+
+static void ColgroupPostResolveCallback(nsStyleStruct* aStyleStruct, nsRuleData* aRuleData)
+{
+ ::ProcessTableRulesAttribute(aStyleStruct, aRuleData, NS_SIDE_LEFT, PR_TRUE, NS_STYLE_TABLE_RULES_ALL,
+ NS_STYLE_TABLE_RULES_GROUPS, NS_STYLE_TABLE_RULES_COLS);
+ ::ProcessTableRulesAttribute(aStyleStruct, aRuleData, NS_SIDE_RIGHT, PR_TRUE, NS_STYLE_TABLE_RULES_ALL,
+ NS_STYLE_TABLE_RULES_GROUPS, NS_STYLE_TABLE_RULES_COLS);
+}
+
+NS_IMETHODIMP
+TableColgroupRule::MapRuleInfoInto(nsRuleData* aRuleData)
+{
+ if (aRuleData && aRuleData->mSID == eStyleStruct_Border) {
+ aRuleData->mCanStoreInRuleTree = PR_FALSE;
+ aRuleData->mPostResolveCallback = &ColgroupPostResolveCallback;
+ }
+ return NS_OK;
+}
+
+// -----------------------------------------------------------
+// this rule handles borders on a when rules is set on its
+// -----------------------------------------------------------
+class TableColRule: public GenericTableRule {
+public:
+ TableColRule(nsIHTMLStyleSheet* aSheet);
+ virtual ~TableColRule();
+
+ void Reset()
+ {
+ GenericTableRule::Reset();
+ }
+
+ NS_IMETHOD MapRuleInfoInto(nsRuleData* aRuleData);
+};
+
+TableColRule::TableColRule(nsIHTMLStyleSheet* aSheet)
+: GenericTableRule(aSheet)
+{
+}
+
+TableColRule::~TableColRule()
+{
+}
+
+static void ColPostResolveCallback(nsStyleStruct* aStyleStruct, nsRuleData* aRuleData)
+{
+ ::ProcessTableRulesAttribute(aStyleStruct, aRuleData, NS_SIDE_LEFT, PR_FALSE, NS_STYLE_TABLE_RULES_ALL,
+ NS_STYLE_TABLE_RULES_COLS, NS_STYLE_TABLE_RULES_COLS);
+ ::ProcessTableRulesAttribute(aStyleStruct, aRuleData, NS_SIDE_RIGHT, PR_FALSE, NS_STYLE_TABLE_RULES_ALL,
+ NS_STYLE_TABLE_RULES_COLS, NS_STYLE_TABLE_RULES_COLS);
+}
+
+NS_IMETHODIMP
+TableColRule::MapRuleInfoInto(nsRuleData* aRuleData)
+{
+ if (aRuleData && aRuleData->mSID == eStyleStruct_Border) {
+ aRuleData->mCanStoreInRuleTree = PR_FALSE;
+ aRuleData->mPostResolveCallback = &ColPostResolveCallback;
+ }
+ return NS_OK;
+}
// -----------------------------------------------------------
class AttributeKey: public nsHashKey
@@ -653,6 +901,10 @@ protected:
HTMLColorRule* mVisitedRule;
HTMLColorRule* mActiveRule;
HTMLDocumentColorRule* mDocumentColorRule;
+ TableTbodyRule* mTableTbodyRule;
+ TableRowRule* mTableRowRule;
+ TableColgroupRule* mTableColgroupRule;
+ TableColRule* mTableColRule;
TableTHRule* mTableTHRule;
// NOTE: if adding more rules, be sure to update
// the SizeOf method to include them
@@ -710,6 +962,26 @@ HTMLStyleSheetImpl::HTMLStyleSheetImpl(void)
nsresult
HTMLStyleSheetImpl::Init()
{
+ mTableTbodyRule = new TableTbodyRule(this);
+ if (!mTableTbodyRule)
+ return NS_ERROR_OUT_OF_MEMORY;
+ NS_ADDREF(mTableTbodyRule);
+
+ mTableRowRule = new TableRowRule(this);
+ if (!mTableRowRule)
+ return NS_ERROR_OUT_OF_MEMORY;
+ NS_ADDREF(mTableRowRule);
+
+ mTableColgroupRule = new TableColgroupRule(this);
+ if (!mTableColgroupRule)
+ return NS_ERROR_OUT_OF_MEMORY;
+ NS_ADDREF(mTableColgroupRule);
+
+ mTableColRule = new TableColRule(this);
+ if (!mTableColRule)
+ return NS_ERROR_OUT_OF_MEMORY;
+ NS_ADDREF(mTableColRule);
+
mTableTHRule = new TableTHRule(this);
if (!mTableTHRule)
return NS_ERROR_OUT_OF_MEMORY;
@@ -750,6 +1022,22 @@ HTMLStyleSheetImpl::~HTMLStyleSheetImpl()
mDocumentColorRule->mSheet = nsnull;
NS_RELEASE(mDocumentColorRule);
}
+ if (nsnull != mTableTbodyRule) {
+ mTableTbodyRule->mSheet = nsnull;
+ NS_RELEASE(mTableTbodyRule);
+ }
+ if (nsnull != mTableRowRule) {
+ mTableRowRule->mSheet = nsnull;
+ NS_RELEASE(mTableRowRule);
+ }
+ if (nsnull != mTableColgroupRule) {
+ mTableColgroupRule->mSheet = nsnull;
+ NS_RELEASE(mTableColgroupRule);
+ }
+ if (nsnull != mTableColRule) {
+ mTableColRule->mSheet = nsnull;
+ NS_RELEASE(mTableColRule);
+ }
if (nsnull != mTableTHRule) {
mTableTHRule->mSheet = nsnull;
NS_RELEASE(mTableTHRule);
@@ -848,6 +1136,18 @@ HTMLStyleSheetImpl::RulesMatching(ElementRuleProcessorData* aData,
else if (tag == nsHTMLAtoms::th) {
ruleWalker->Forward(mTableTHRule);
}
+ else if (tag == nsHTMLAtoms::tr) {
+ ruleWalker->Forward(mTableRowRule);
+ }
+ else if ((tag == nsHTMLAtoms::thead) || (tag == nsHTMLAtoms::tbody) || (tag == nsHTMLAtoms::tfoot)) {
+ ruleWalker->Forward(mTableTbodyRule);
+ }
+ else if (tag == nsHTMLAtoms::col) {
+ ruleWalker->Forward(mTableColRule);
+ }
+ else if (tag == nsHTMLAtoms::colgroup) {
+ ruleWalker->Forward(mTableColgroupRule);
+ }
else if (tag == nsHTMLAtoms::table) {
if (aData->mIsQuirkMode)
ruleWalker->Forward(mDocumentColorRule);
@@ -888,7 +1188,13 @@ NS_IMETHODIMP
HTMLStyleSheetImpl::RulesMatching(PseudoRuleProcessorData* aData,
nsIAtom* aMedium)
{
- // no pseudo frame style
+ nsIAtom* pseudoTag = aData->mPseudoTag;
+ if (pseudoTag == nsHTMLAtoms::tableColPseudo) {
+ nsRuleWalker *ruleWalker = aData->mRuleWalker;
+ if (ruleWalker) {
+ ruleWalker->Forward(mTableColRule);
+ }
+ }
return NS_OK;
}
@@ -1008,6 +1314,11 @@ HTMLStyleSheetImpl::Reset(nsIURI* aURL)
NS_RELEASE(mActiveRule);
}
mDocumentColorRule->Reset();
+
+ mTableTbodyRule->Reset();
+ mTableRowRule->Reset();
+ mTableColgroupRule->Reset();
+ mTableColRule->Reset();
mTableTHRule->Reset();
mMappedAttrTable.Enumerate(MappedDropSheet);
@@ -1264,6 +1575,10 @@ MappedSizeAttributes(nsHashKey *aKey, void *aData, void* closure)
* - mVisitedRule
* - mActiveRule
* - mDocumentColorRule
+* - mTableTbodyRule
+* - mTableRowRule
+* - mTableColgroupRule
+* - mTableColRule
* - mTableTHRule
* - mMappedAttrTable
* 2) Delegates (really) to the MappedAttributes in the mMappedAttrTable
@@ -1298,6 +1613,10 @@ HTMLStyleSheetImpl::SizeOf(nsISizeOfHandler *aSizeOfHandler, PRUint32 &aSize)
// - mVisitedRule : sizeof object
// - mActiveRule : sizeof object
// - mDocumentColorRule : sizeof object
+ // - mTableTbodyRule : sizeof object
+ // - mTableRowRule : sizeof object
+ // - mTableColgroupRule : sizeof object
+ // - mTableColRule : sizeof object
// - mTableTHRule : sizeof object
// - mMappedAttrTable
@@ -1321,6 +1640,26 @@ HTMLStyleSheetImpl::SizeOf(nsISizeOfHandler *aSizeOfHandler, PRUint32 &aSize)
tag = getter_AddRefs(NS_NewAtom("DocumentColorRule"));
aSizeOfHandler->AddSize(tag,localSize);
}
+ if(uniqueItems->AddItem((void*)mTableTbodyRule)){
+ localSize = sizeof(*mTableTbodyRule);
+ tag = getter_AddRefs(NS_NewAtom("TableTbodyRule"));
+ aSizeOfHandler->AddSize(tag,localSize);
+ }
+ if(uniqueItems->AddItem((void*)mTableRowRule)){
+ localSize = sizeof(*mTableRowRule);
+ tag = getter_AddRefs(NS_NewAtom("TableRowRule"));
+ aSizeOfHandler->AddSize(tag,localSize);
+ }
+ if(uniqueItems->AddItem((void*)mTableColgroupRule)){
+ localSize = sizeof(*mTableColgroupRule);
+ tag = getter_AddRefs(NS_NewAtom("TableColgroupRule"));
+ aSizeOfHandler->AddSize(tag,localSize);
+ }
+ if(uniqueItems->AddItem((void*)mTableColRule)){
+ localSize = sizeof(*mTableColRule);
+ tag = getter_AddRefs(NS_NewAtom("TableColRule"));
+ aSizeOfHandler->AddSize(tag,localSize);
+ }
if(uniqueItems->AddItem((void*)mTableTHRule)){
localSize = sizeof(*mTableTHRule);
tag = getter_AddRefs(NS_NewAtom("TableTHRule"));
diff --git a/mozilla/content/shared/public/nsCSSPropList.h b/mozilla/content/shared/public/nsCSSPropList.h
index ce14a5df95e..3007f42b36f 100644
--- a/mozilla/content/shared/public/nsCSSPropList.h
+++ b/mozilla/content/shared/public/nsCSSPropList.h
@@ -103,7 +103,7 @@ CSS_PROP(border-bottom-color, border_bottom_color, VISUAL)
CSS_PROP(-moz-border-bottom-colors, border_bottom_colors, VISUAL)
CSS_PROP(border-bottom-style, border_bottom_style, REFLOW) // on/off will need reflow
CSS_PROP(border-bottom-width, border_bottom_width, REFLOW)
-CSS_PROP(border-collapse, border_collapse, REFLOW)
+CSS_PROP(border-collapse, border_collapse, FRAMECHANGE)
CSS_PROP(border-color, border_color, VISUAL)
CSS_PROP(border-left, border_left, REFLOW)
CSS_PROP(border-left-color, border_left_color, VISUAL)
diff --git a/mozilla/content/shared/public/nsLayoutAtomList.h b/mozilla/content/shared/public/nsLayoutAtomList.h
index 8a8cfd14e5e..5cb1b488129 100644
--- a/mozilla/content/shared/public/nsLayoutAtomList.h
+++ b/mozilla/content/shared/public/nsLayoutAtomList.h
@@ -100,6 +100,7 @@ LAYOUT_ATOM(selectScrolledContentPseudo, ":-moz-select-scrolled-content")
// Alphabetical list of frame types
LAYOUT_ATOM(areaFrame, "AreaFrame")
+LAYOUT_ATOM(bcTableCellFrame, "BCTableCellFrame") // table cell in border collapsing model
LAYOUT_ATOM(blockFrame, "BlockFrame")
LAYOUT_ATOM(boxFrame, "BoxFrame")
LAYOUT_ATOM(brFrame, "BRFrame")
@@ -143,7 +144,8 @@ LAYOUT_ATOM(overflowProperty, "OverflowProperty") // list of nsIFra
LAYOUT_ATOM(overflowLinesProperty, "OverflowLinesProperty") // list of nsLineBox*
LAYOUT_ATOM(rowUnpaginatedHeightProperty, "RowUnpaginatedHeightProperty") // nscoord*
LAYOUT_ATOM(spaceManagerProperty, "SpaceManagerProperty") // the space manager for a block
-LAYOUT_ATOM(viewProperty, "ViewProperty") // nsView*
+LAYOUT_ATOM(tableBCProperty, "TableBCProperty") // table border collapsing info (e.g. damage area, table border widths)
+LAYOUT_ATOM(viewProperty, "ViewProperty")
// Alphabetical list of event handler names
LAYOUT_ATOM(onabort, "onabort")
diff --git a/mozilla/content/shared/public/nsStyleStruct.h b/mozilla/content/shared/public/nsStyleStruct.h
index 9627f3804b8..2303efea81c 100644
--- a/mozilla/content/shared/public/nsStyleStruct.h
+++ b/mozilla/content/shared/public/nsStyleStruct.h
@@ -465,7 +465,8 @@ struct nsStyleBorder: public nsStyleStruct {
// XXX these are deprecated methods
void CalcBorderFor(const nsIFrame* aFrame, nsMargin& aBorder) const;
-
+ void CalcBorderFor(const nsIFrame* aFrame, PRUint8 aSide, nscoord& aWidth) const;
+
protected:
PRPackedBool mHasCachedBorder;
nsMargin mCachedBorder;
diff --git a/mozilla/content/shared/src/nsStyleStruct.cpp b/mozilla/content/shared/src/nsStyleStruct.cpp
index 79bf6e4e9a9..4efb4816291 100644
--- a/mozilla/content/shared/src/nsStyleStruct.cpp
+++ b/mozilla/content/shared/src/nsStyleStruct.cpp
@@ -605,6 +605,28 @@ nsStyleBorder::CalcBorderFor(const nsIFrame* aFrame, nsMargin& aBorder) const
}
}
+void
+nsStyleBorder::CalcBorderFor(const nsIFrame* aFrame, PRUint8 aSide, nscoord& aWidth) const
+{
+ aWidth = 0;
+ // using mCachedBorder as above, doesn't work properly
+ nsStyleCoord coord;
+ switch(aSide) {
+ case NS_SIDE_TOP:
+ coord = mBorder.GetTop(coord);
+ break;
+ case NS_SIDE_RIGHT:
+ coord = mBorder.GetRight(coord);
+ break;
+ case NS_SIDE_BOTTOM:
+ coord = mBorder.GetBottom(coord);
+ break;
+ default: // NS_SIDE_LEFT
+ coord = mBorder.GetLeft(coord);
+ }
+ aWidth = CalcSideFor(aFrame, coord, NS_SPACING_BORDER, aSide, mBorderWidths, 3);
+}
+
nsStyleOutline::nsStyleOutline(nsIPresContext* aPresContext)
{
// XXX support mBorderWidths until deprecated methods are removed
@@ -862,7 +884,7 @@ nsStyleTable::nsStyleTable()
mLayoutStrategy = NS_STYLE_TABLE_LAYOUT_AUTO;
mCols = NS_STYLE_TABLE_COLS_NONE;
mFrame = NS_STYLE_TABLE_FRAME_NONE;
- mRules = NS_STYLE_TABLE_RULES_ALL;
+ mRules = NS_STYLE_TABLE_RULES_NONE;
mSpan = 1;
}
diff --git a/mozilla/layout/base/nsCSSFrameConstructor.cpp b/mozilla/layout/base/nsCSSFrameConstructor.cpp
index e20226d01b6..113297119be 100644
--- a/mozilla/layout/base/nsCSSFrameConstructor.cpp
+++ b/mozilla/layout/base/nsCSSFrameConstructor.cpp
@@ -52,8 +52,11 @@
#include "nsIPresContext.h"
#include "nsILinkHandler.h"
#include "nsIDocument.h"
+#include "nsTableFrame.h"
#include "nsTableColGroupFrame.h"
#include "nsTableColFrame.h"
+#include "nsIDOMHTMLTableColElement.h"
+#include "nsTableCellFrame.h" // to get IS_CELL_FRAME
#include "nsHTMLIIDs.h"
#include "nsIStyleFrameConstruction.h"
#include "nsHTMLParts.h"
@@ -859,6 +862,23 @@ nsFrameConstructorSaveState::~nsFrameConstructorSaveState()
}
}
+
+static
+PRBool IsBorderCollapse(nsIFrame* aFrame)
+{
+ nsIFrame* frame = aFrame;
+ while (frame) {
+ nsCOMPtr fType;
+ frame->GetFrameType(getter_AddRefs(fType));
+ if (nsLayoutAtoms::tableFrame == fType.get()) {
+ return ((nsTableFrame*)frame)->IsBorderCollapse();
+ }
+ frame->GetParent(&frame);
+ }
+ NS_ASSERTION(PR_FALSE, "program error");
+ return PR_FALSE;
+}
+
// -----------------------------------------------------------
// Structure used when creating table frames.
@@ -870,7 +890,7 @@ struct nsTableCreator {
virtual nsresult CreateTableColFrame(nsIFrame** aNewFrame);
virtual nsresult CreateTableColGroupFrame(nsIFrame** aNewFrame);
virtual nsresult CreateTableRowFrame(nsIFrame** aNewFrame);
- virtual nsresult CreateTableCellFrame(nsIFrame** aNewFrame);
+ virtual nsresult CreateTableCellFrame(nsIFrame* aParentFrame, nsIFrame** aNewFrame);
virtual nsresult CreateTableCellInnerFrame(nsIFrame** aNewFrame);
nsTableCreator(nsIPresShell* aPresShell)
@@ -919,8 +939,9 @@ nsTableCreator::CreateTableRowFrame(nsIFrame** aNewFrame) {
}
nsresult
-nsTableCreator::CreateTableCellFrame(nsIFrame** aNewFrame) {
- return NS_NewTableCellFrame(mPresShell, aNewFrame);
+nsTableCreator::CreateTableCellFrame(nsIFrame* aParentFrame,
+ nsIFrame** aNewFrame) {
+ return NS_NewTableCellFrame(mPresShell, IsBorderCollapse(aParentFrame), aNewFrame);
}
nsresult
@@ -1527,7 +1548,7 @@ IsTableRelated(nsIAtom* aParentType,
((nsLayoutAtoms::tableCaptionFrame == aParentType) ||
(nsLayoutAtoms::tableColGroupFrame == aParentType) ||
(nsLayoutAtoms::tableColFrame == aParentType) ||
- (nsLayoutAtoms::tableCellFrame == aParentType))) {
+ IS_TABLE_CELL(aParentType))) {
return PR_TRUE;
}
else return PR_FALSE;
@@ -1629,7 +1650,7 @@ ProcessPseudoFrames(nsIPresContext* aPresContext,
if (aPseudoFrames.mCellOuter.mFrame) {
rv = ProcessPseudoCellFrame(aPresContext, aPseudoFrames, aHighestFrame);
- if (nsLayoutAtoms::tableCellFrame == aHighestType) return rv;
+ if (IS_TABLE_CELL(aHighestType)) return rv;
}
if (aPseudoFrames.mRow.mFrame) {
rv = ProcessPseudoFrame(aPresContext, aPseudoFrames.mRow, aHighestFrame);
@@ -1650,7 +1671,7 @@ ProcessPseudoFrames(nsIPresContext* aPresContext,
}
if (aPseudoFrames.mCellOuter.mFrame) {
rv = ProcessPseudoCellFrame(aPresContext, aPseudoFrames, aHighestFrame);
- if (nsLayoutAtoms::tableCellFrame == aHighestType) return rv;
+ if (IS_TABLE_CELL(aHighestType)) return rv;
}
if (aPseudoFrames.mRow.mFrame) {
rv = ProcessPseudoFrame(aPresContext, aPseudoFrames.mRow, aHighestFrame);
@@ -1671,12 +1692,12 @@ ProcessPseudoFrames(nsIPresContext* aPresContext,
}
if (aPseudoFrames.mCellOuter.mFrame) {
rv = ProcessPseudoCellFrame(aPresContext, aPseudoFrames, aHighestFrame);
- if (nsLayoutAtoms::tableCellFrame == aHighestType) return rv;
+ if (IS_TABLE_CELL(aHighestType)) return rv;
}
}
- else if (nsLayoutAtoms::tableCellFrame == aPseudoFrames.mLowestType) {
+ else if (IS_TABLE_CELL(aPseudoFrames.mLowestType)) {
rv = ProcessPseudoCellFrame(aPresContext, aPseudoFrames, aHighestFrame);
- if (nsLayoutAtoms::tableCellFrame == aHighestType) return rv;
+ if (IS_TABLE_CELL(aHighestType)) return rv;
if (aPseudoFrames.mRow.mFrame) {
rv = ProcessPseudoFrame(aPresContext, aPseudoFrames.mRow, aHighestFrame);
@@ -1942,6 +1963,7 @@ nsCSSFrameConstructor::CreatePseudoCellFrame(nsIPresShell* aPresShell
// set pseudo data for the newly created frames
pseudoOuter.mChildList.AddChild(pseudoInner.mFrame);
+ // give it nsLayoutAtoms::tableCellFrame, if it is really nsLayoutAtoms::bcTableCellFrame, it will match later
aState.mPseudoFrames.mLowestType = nsLayoutAtoms::tableCellFrame;
// set pseudo data for the parent
@@ -2021,7 +2043,7 @@ nsCSSFrameConstructor::GetPseudoColGroupFrame(nsIPresShell* aPresShel
rv = CreatePseudoCellFrame(aPresShell, aPresContext, aTableCreator, aState, &aParentFrameIn);
created = PR_TRUE;
}
- if (created || (nsLayoutAtoms::tableCellFrame == parentFrameType.get()) || // cell parent
+ if (created || IS_TABLE_CELL(parentFrameType.get()) || // cell parent
!IsTableRelated(parentFrameType.get(), PR_TRUE)) { // block parent
rv = CreatePseudoTableFrame(aPresShell, aPresContext, aTableCreator, aState, &aParentFrameIn);
}
@@ -2065,7 +2087,7 @@ nsCSSFrameConstructor::GetPseudoRowGroupFrame(nsIPresShell* aPresShel
rv = CreatePseudoCellFrame(aPresShell, aPresContext, aTableCreator, aState, &aParentFrameIn);
created = PR_TRUE;
}
- if (created || (nsLayoutAtoms::tableCellFrame == parentFrameType.get()) || // cell parent
+ if (created || IS_TABLE_CELL(parentFrameType.get()) || // cell parent
!IsTableRelated(parentFrameType.get(), PR_TRUE)) { // block parent
rv = CreatePseudoTableFrame(aPresShell, aPresContext, aTableCreator, aState, &aParentFrameIn);
}
@@ -2102,7 +2124,7 @@ nsCSSFrameConstructor::GetPseudoRowFrame(nsIPresShell* aPresShell,
if (pseudoFrames.IsEmpty()) {
PRBool created = PR_FALSE;
- if ((nsLayoutAtoms::tableCellFrame == parentFrameType.get()) || // cell parent
+ if (IS_TABLE_CELL(parentFrameType.get()) || // cell parent
!IsTableRelated(parentFrameType.get(), PR_TRUE)) { // block parent
rv = CreatePseudoTableFrame(aPresShell, aPresContext, aTableCreator, aState, &aParentFrameIn);
created = PR_TRUE;
@@ -2230,7 +2252,7 @@ nsCSSFrameConstructor::GetParentFrame(nsIPresShell* aPresShell,
pseudoParentFrame = pseudoFrames.mRowGroup.mFrame;
}
}
- else if (nsLayoutAtoms::tableCellFrame == aChildFrameType) { // cell child
+ else if (IS_TABLE_CELL(aChildFrameType)) { // cell child
if (nsLayoutAtoms::tableRowFrame != parentFrameType.get()) { // need pseudo row parent
rv = GetPseudoRowFrame(aPresShell, aPresContext, aTableCreator, aState, aParentFrameIn);
if (NS_FAILED(rv)) return rv;
@@ -2572,7 +2594,7 @@ nsCSSFrameConstructor::ConstructTableColFrame(nsIPresShell* aPresShel
PRBool& aIsPseudoParent)
{
nsresult rv = NS_OK;
- if (!aPresShell || !aPresContext || !aParentFrameIn) return rv;
+ if (!aPresShell || !aPresContext || !aParentFrameIn || !aStyleContext) return rv;
nsIFrame* parentFrame = aParentFrameIn;
aIsPseudoParent = PR_FALSE;
@@ -2585,16 +2607,42 @@ nsCSSFrameConstructor::ConstructTableColFrame(nsIPresShell* aPresShel
}
}
- rv = aTableCreator.CreateTableColFrame(&aNewFrame);
- if (NS_FAILED(rv)) return rv;
- InitAndRestoreFrame(aPresContext, aState, aContent,
- parentFrame, aStyleContext, nsnull, aNewFrame);
+ rv = aTableCreator.CreateTableColFrame(&aNewFrame); if (NS_FAILED(rv)) return rv;
+ InitAndRestoreFrame(aPresContext, aState, aContent, parentFrame, aStyleContext, nsnull, aNewFrame);
+ // if the parent frame was anonymous then reparent the style context
+ nsCOMPtr parentStyleContext;
+ parentFrame->GetStyleContext(getter_AddRefs(parentStyleContext));
+ if (aIsPseudoParent) {
+ aPresContext->ReParentStyleContext(aNewFrame, parentStyleContext);
+ }
+
+ // construct additional col frames if the col frame has a span > 1
+ PRInt32 span = 1;
+ nsCOMPtr cgContent(do_QueryInterface(aContent));
+ if (cgContent) {
+ cgContent->GetSpan(&span);
+ nsIFrame* lastCol = aNewFrame;
+ for (PRInt32 spanX = 1; spanX < span; spanX++) {
+ nsCOMPtr styleContext;
+ aPresContext->ResolvePseudoStyleContextFor(aContent, nsHTMLAtoms::tableColPseudo, aStyleContext,
+ PR_FALSE, getter_AddRefs(styleContext));
+ nsIFrame* newCol;
+ rv = aTableCreator.CreateTableColFrame(&newCol); if (NS_FAILED(rv)) return rv;
+ InitAndRestoreFrame(aPresContext, aState, aContent, parentFrame, styleContext, nsnull, newCol);
+ if (aIsPseudoParent) {
+ aPresContext->ReParentStyleContext(newCol, aStyleContext);
+ }
+ ((nsTableColFrame*)newCol)->SetType(eColAnonymousCol);
+ lastCol->SetNextSibling(newCol);
+ lastCol = newCol;
+ }
+ }
+
if (!aIsPseudo) {
nsFrameItems childItems;
nsIFrame* captionFrame;
rv = TableProcessChildren(aPresShell, aPresContext, aState, aContent, aNewFrame,
- aTableCreator, childItems, captionFrame);
- if (NS_FAILED(rv)) return rv;
+ aTableCreator, childItems, captionFrame); if (NS_FAILED(rv)) return rv;
aNewFrame->SetInitialChildList(aPresContext, nsnull, childItems.childList);
if (aIsPseudoParent) {
aState.mPseudoFrames.mColGroup.mChildList.AddChild(aNewFrame);
@@ -2625,6 +2673,7 @@ nsCSSFrameConstructor::ConstructTableCellFrame(nsIPresShell* aPresShe
aIsPseudoParent = PR_FALSE;
if (!aIsPseudo) {
// this frame may have a pseudo parent
+ // use nsLayoutAtoms::tableCellFrame which will match if it is really nsLayoutAtoms::bcTableCellFrame
GetParentFrame(aPresShell, aPresContext, aTableCreator, *aParentFrameIn,
nsLayoutAtoms::tableCellFrame, aState, parentFrame, aIsPseudoParent);
if (!aIsPseudoParent && !aState.mPseudoFrames.IsEmpty()) {
@@ -2635,7 +2684,7 @@ nsCSSFrameConstructor::ConstructTableCellFrame(nsIPresShell* aPresShe
}
}
- rv = aTableCreator.CreateTableCellFrame(&aNewCellOuterFrame);
+ rv = aTableCreator.CreateTableCellFrame(parentFrame, &aNewCellOuterFrame);
if (NS_FAILED(rv)) return rv;
// Initialize the table cell frame
@@ -11328,7 +11377,7 @@ nsCSSFrameConstructor::CreateContinuingFrame(nsIPresShell* aPresShell,
// See if it's a table cell frame
cellFrame->GetFrameType(&tableType);
- if (nsLayoutAtoms::tableCellFrame == tableType) {
+ if (IS_TABLE_CELL(tableType)) {
nsIFrame* continuingCellFrame;
CreateContinuingFrame(aPresShell, aPresContext, cellFrame, newFrame, &continuingCellFrame);
@@ -11343,8 +11392,8 @@ nsCSSFrameConstructor::CreateContinuingFrame(nsIPresShell* aPresShell,
newFrame->SetInitialChildList(aPresContext, nsnull, newChildList.childList);
}
- } else if (nsLayoutAtoms::tableCellFrame == frameType) {
- rv = NS_NewTableCellFrame(aPresShell, &newFrame);
+ } else if (IS_TABLE_CELL(frameType)) {
+ rv = NS_NewTableCellFrame(aPresShell, IsBorderCollapse(aParentFrame), &newFrame);
if (NS_SUCCEEDED(rv)) {
newFrame->Init(aPresContext, content, aParentFrame, styleContext, aFrame);
nsHTMLContainerFrame::CreateViewForFrame(aPresContext, newFrame,
diff --git a/mozilla/layout/base/nsCSSRendering.cpp b/mozilla/layout/base/nsCSSRendering.cpp
index 543a729ae1f..ea8f7cdea80 100644
--- a/mozilla/layout/base/nsCSSRendering.cpp
+++ b/mozilla/layout/base/nsCSSRendering.cpp
@@ -514,6 +514,7 @@ void nsCSSRendering::DrawSide(nsIRenderingContext& aContext,
}
}
+
/**
* Draw a dotted/dashed sides of a box
*/
@@ -3821,3 +3822,356 @@ void FillOrInvertRect(nsIRenderingContext& aRC, const nsRect& aRect, PRBool aInv
}
}
+// Begin table border-collapsing section
+// These functions were written to not disrupt the normal ones and yet satisfy some additional requirements
+// At some point, all functions should be unified to include the additional functionality that these provide
+
+static nscoord
+RoundIntToPixel(nscoord aValue,
+ nscoord aTwipsPerPixel,
+ PRBool aRoundDown = PR_FALSE)
+{
+ nscoord halfPixel = NSToCoordRound(aTwipsPerPixel / 2.0f);
+ nscoord extra = aValue % aTwipsPerPixel;
+ nscoord finalValue = (!aRoundDown && (extra >= halfPixel)) ? aValue + (aTwipsPerPixel - extra) : aValue - extra;
+
+ return finalValue;
+}
+
+static nscoord
+RoundFloatToPixel(float aValue,
+ nscoord aTwipsPerPixel,
+ PRBool aRoundDown = PR_FALSE)
+{
+ return RoundIntToPixel(NSToCoordRound(aValue), aTwipsPerPixel, aRoundDown);
+}
+
+static void
+SetPoly(const nsRect& aRect,
+ nsPoint* poly)
+{
+ poly[0].x = aRect.x;
+ poly[0].y = aRect.y;
+ poly[1].x = aRect.x + aRect.width;
+ poly[1].y = aRect.y;
+ poly[2].x = aRect.x + aRect.width;
+ poly[2].y = aRect.y + aRect.height;
+ poly[3].x = aRect.x;
+ poly[3].y = aRect.y + aRect.height;
+ poly[4].x = aRect.x;
+ poly[4].y = aRect.y;
+}
+
+static void
+DrawSolidBorderSegment(nsIRenderingContext& aContext,
+ nsRect aRect,
+ nscoord aTwipsPerPixel,
+ PRUint8 aStartBevelSide = 0,
+ nscoord aStartBevelOffset = 0,
+ PRUint8 aEndBevelSide = 0,
+ nscoord aEndBevelOffset = 0)
+{
+
+ if ((aRect.width == aTwipsPerPixel) || (aRect.height == aTwipsPerPixel) ||
+ ((0 == aStartBevelOffset) && (0 == aEndBevelOffset))) {
+ // simple line or rectangle
+ if ((NS_SIDE_TOP == aStartBevelSide) || (NS_SIDE_BOTTOM == aStartBevelSide)) {
+ if (1 == aRect.height)
+ aContext.DrawLine(aRect.x, aRect.y, aRect.x, aRect.y + aRect.height);
+ else
+ aContext.FillRect(aRect);
+ }
+ else {
+ if (1 == aRect.width)
+ aContext.DrawLine(aRect.x, aRect.y, aRect.x + aRect.width, aRect.y);
+ else
+ aContext.FillRect(aRect);
+ }
+ }
+ else {
+ // polygon with beveling
+ nsPoint poly[5];
+ SetPoly(aRect, poly);
+ switch(aStartBevelSide) {
+ case NS_SIDE_TOP:
+ poly[0].x += aStartBevelOffset;
+ poly[4].x = poly[0].x;
+ break;
+ case NS_SIDE_BOTTOM:
+ poly[3].x += aStartBevelOffset;
+ break;
+ case NS_SIDE_RIGHT:
+ poly[1].y += aStartBevelOffset;
+ break;
+ case NS_SIDE_LEFT:
+ poly[0].y += aStartBevelOffset;
+ poly[4].y = poly[0].y;
+ }
+
+ switch(aEndBevelSide) {
+ case NS_SIDE_TOP:
+ poly[1].x -= aEndBevelOffset;
+ break;
+ case NS_SIDE_BOTTOM:
+ poly[2].x -= aEndBevelOffset;
+ break;
+ case NS_SIDE_RIGHT:
+ poly[2].y -= aEndBevelOffset;
+ break;
+ case NS_SIDE_LEFT:
+ poly[3].y -= aEndBevelOffset;
+ }
+
+ aContext.FillPolygon(poly, 5);
+ }
+
+
+}
+
+static void
+GetDashInfo(nscoord aBorderLength,
+ nscoord aDashLength,
+ nscoord aTwipsPerPixel,
+ PRInt32& aNumDashSpaces,
+ nscoord& aStartDashLength,
+ nscoord& aEndDashLength)
+{
+ aNumDashSpaces = 0;
+ if (aStartDashLength + aDashLength + aEndDashLength >= aBorderLength) {
+ aStartDashLength = aBorderLength;
+ aEndDashLength = 0;
+ }
+ else {
+ aNumDashSpaces = aBorderLength / (2 * aDashLength); // round down
+ nscoord foo = ((2 * aNumDashSpaces) - 1) * aDashLength;
+ nscoord extra = aBorderLength - aStartDashLength - aEndDashLength - (((2 * aNumDashSpaces) - 1) * aDashLength);
+ if (extra > 0) {
+ nscoord half = RoundIntToPixel(extra / 2, aTwipsPerPixel);
+ aStartDashLength += half;
+ aEndDashLength += (extra - half);
+ }
+ }
+}
+
+void
+nsCSSRendering::DrawTableBorderSegment(nsIRenderingContext& aContext,
+ PRUint8 aBorderStyle,
+ nscolor aBorderColor,
+ const nsStyleBackground* aBGColor,
+ const nsRect& aBorder,
+ float aPixelsToTwips,
+ PRUint8 aStartBevelSide,
+ nscoord aStartBevelOffset,
+ PRUint8 aEndBevelSide,
+ nscoord aEndBevelOffset)
+{
+ aContext.SetColor (aBorderColor);
+
+ PRBool horizontal = ((NS_SIDE_TOP == aStartBevelSide) || (NS_SIDE_BOTTOM == aStartBevelSide));
+ nscoord twipsPerPixel = NSIntPixelsToTwips(1, aPixelsToTwips);
+ PRBool ridgeGroove = NS_STYLE_BORDER_STYLE_RIDGE;
+
+ if ((twipsPerPixel >= aBorder.width) || (twipsPerPixel >= aBorder.height) ||
+ (NS_STYLE_BORDER_STYLE_DASHED == aBorderStyle) || (NS_STYLE_BORDER_STYLE_DOTTED == aBorderStyle)) {
+ // no beveling for 1 pixel border, dash or dot
+ aStartBevelOffset = 0;
+ aEndBevelOffset = 0;
+ }
+
+ switch (aBorderStyle) {
+ case NS_STYLE_BORDER_STYLE_NONE:
+ case NS_STYLE_BORDER_STYLE_HIDDEN:
+ case NS_STYLE_BORDER_STYLE_BLANK:
+ //NS_ASSERTION(PR_FALSE, "style of none, hidden, or blank");
+ break;
+ case NS_STYLE_BORDER_STYLE_DOTTED:
+ case NS_STYLE_BORDER_STYLE_DASHED:
+ {
+ nscoord dashLength = (NS_STYLE_BORDER_STYLE_DASHED == aBorderStyle) ? DASH_LENGTH : DOT_LENGTH;
+ // make the dash length proportional to the border thickness
+ dashLength *= (horizontal) ? aBorder.height : aBorder.width;
+ // make the min dash length for the ends 1/2 the dash length
+ nscoord minDashLength = (NS_STYLE_BORDER_STYLE_DASHED == aBorderStyle)
+ ? RoundFloatToPixel(((float)dashLength) / 2.0f, twipsPerPixel) : dashLength;
+ minDashLength = PR_MAX(minDashLength, twipsPerPixel);
+ nscoord numDashSpaces = 0;
+ nscoord startDashLength = minDashLength;
+ nscoord endDashLength = minDashLength;
+ if (horizontal) {
+ GetDashInfo(aBorder.width, dashLength, twipsPerPixel, numDashSpaces, startDashLength, endDashLength);
+ nsRect rect(aBorder.x, aBorder.y, startDashLength, aBorder.height);
+ DrawSolidBorderSegment(aContext, rect, PR_TRUE);
+ for (PRInt32 spaceX = 0; spaceX < numDashSpaces; spaceX++) {
+ rect.x += rect.width + dashLength;
+ rect.width = (spaceX == (numDashSpaces - 1)) ? endDashLength : dashLength;
+ DrawSolidBorderSegment(aContext, rect, PR_TRUE);
+ }
+ }
+ else {
+ GetDashInfo(aBorder.height, dashLength, twipsPerPixel, numDashSpaces, startDashLength, endDashLength);
+ nsRect rect(aBorder.x, aBorder.y, aBorder.width, startDashLength);
+ DrawSolidBorderSegment(aContext, rect, PR_FALSE);
+ for (PRInt32 spaceY = 0; spaceY < numDashSpaces; spaceY++) {
+ rect.y += rect.height + dashLength;
+ rect.height = (spaceY == (numDashSpaces - 1)) ? endDashLength : dashLength;
+ DrawSolidBorderSegment(aContext, rect, PR_FALSE);
+ }
+ }
+ }
+ break;
+ case NS_STYLE_BORDER_STYLE_GROOVE:
+ ridgeGroove = NS_STYLE_BORDER_STYLE_GROOVE; // and fall through to ridge
+ case NS_STYLE_BORDER_STYLE_RIDGE:
+ if ((horizontal && (twipsPerPixel >= aBorder.height)) ||
+ (!horizontal && (twipsPerPixel >= aBorder.width))) {
+ // a one pixel border
+ DrawSolidBorderSegment(aContext, aBorder, twipsPerPixel, aStartBevelSide, aStartBevelOffset,
+ aEndBevelSide, aEndBevelOffset);
+ }
+ else {
+ nscoord startBevel = (aStartBevelOffset > 0)
+ ? RoundFloatToPixel(0.5f * (float)aStartBevelOffset, twipsPerPixel, PR_TRUE) : 0;
+ nscoord endBevel = (aEndBevelOffset > 0)
+ ? RoundFloatToPixel(0.5f * (float)aEndBevelOffset, twipsPerPixel, PR_TRUE) : 0;
+ PRUint8 ridgeGrooveSide = (horizontal) ? NS_SIDE_TOP : NS_SIDE_LEFT;
+ aContext.SetColor (
+ MakeBevelColor (ridgeGrooveSide, ridgeGroove, aBGColor->mBackgroundColor, aBorderColor, PR_TRUE));
+ nsRect rect(aBorder);
+ nscoord half;
+ if (horizontal) { // top, bottom
+ half = RoundFloatToPixel(0.5f * (float)aBorder.height, twipsPerPixel);
+ rect.height = half;
+ if (NS_SIDE_TOP == aStartBevelSide) {
+ rect.x += startBevel;
+ rect.width -= startBevel;
+ }
+ if (NS_SIDE_TOP == aEndBevelSide) {
+ rect.width -= endBevel;
+ }
+ DrawSolidBorderSegment(aContext, rect, twipsPerPixel, aStartBevelSide,
+ startBevel, aEndBevelSide, endBevel);
+ }
+ else { // left, right
+ half = RoundFloatToPixel(0.5f * (float)aBorder.width, twipsPerPixel);
+ rect.width = half;
+ if (NS_SIDE_LEFT == aStartBevelSide) {
+ rect.y += startBevel;
+ rect.height -= startBevel;
+ }
+ if (NS_SIDE_LEFT == aEndBevelSide) {
+ rect.height -= endBevel;
+ }
+ DrawSolidBorderSegment(aContext, rect, twipsPerPixel, aStartBevelSide,
+ startBevel, aEndBevelSide, endBevel);
+ }
+
+ rect = aBorder;
+ ridgeGrooveSide = (NS_SIDE_TOP == ridgeGrooveSide) ? NS_SIDE_BOTTOM : NS_SIDE_RIGHT;
+ aContext.SetColor (
+ MakeBevelColor (ridgeGrooveSide, ridgeGroove, aBGColor->mBackgroundColor, aBorderColor, PR_TRUE));
+ if (horizontal) {
+ rect.y = rect.y + half;
+ rect.height = aBorder.height - half;
+ if (NS_SIDE_BOTTOM == aStartBevelSide) {
+ rect.x += startBevel;
+ rect.width -= startBevel;
+ }
+ if (NS_SIDE_BOTTOM == aEndBevelSide) {
+ rect.width -= endBevel;
+ }
+ DrawSolidBorderSegment(aContext, rect, twipsPerPixel, aStartBevelSide,
+ startBevel, aEndBevelSide, endBevel);
+ }
+ else {
+ rect.x = rect.x + half;
+ rect.width = aBorder.width - half;
+ if (NS_SIDE_RIGHT == aStartBevelSide) {
+ rect.y += aStartBevelOffset - startBevel;
+ rect.height -= startBevel;
+ }
+ if (NS_SIDE_RIGHT == aEndBevelSide) {
+ rect.height -= endBevel;
+ }
+ DrawSolidBorderSegment(aContext, rect, twipsPerPixel, aStartBevelSide,
+ startBevel, aEndBevelSide, endBevel);
+ }
+ }
+ break;
+ case NS_STYLE_BORDER_STYLE_DOUBLE:
+ if ((aBorder.width > 2) && (aBorder.height > 2)) {
+ nscoord startBevel = (aStartBevelOffset > 0)
+ ? RoundFloatToPixel(0.333333f * (float)aStartBevelOffset, twipsPerPixel) : 0;
+ nscoord endBevel = (aEndBevelOffset > 0)
+ ? RoundFloatToPixel(0.333333f * (float)aEndBevelOffset, twipsPerPixel) : 0;
+ if (horizontal) { // top, bottom
+ nscoord thirdHeight = RoundFloatToPixel(0.333333f * (float)aBorder.height, twipsPerPixel);
+
+ // draw the top line or rect
+ nsRect topRect(aBorder.x, aBorder.y, aBorder.width, thirdHeight);
+ if (NS_SIDE_TOP == aStartBevelSide) {
+ topRect.x += aStartBevelOffset - startBevel;
+ topRect.width -= aStartBevelOffset - startBevel;
+ }
+ if (NS_SIDE_TOP == aEndBevelSide) {
+ topRect.width -= aEndBevelOffset - endBevel;
+ }
+ DrawSolidBorderSegment(aContext, topRect, twipsPerPixel, aStartBevelSide,
+ startBevel, aEndBevelSide, endBevel);
+
+ // draw the botom line or rect
+ nscoord heightOffset = aBorder.height - thirdHeight;
+ nsRect bottomRect(aBorder.x, aBorder.y + heightOffset, aBorder.width, aBorder.height - heightOffset);
+ if (NS_SIDE_BOTTOM == aStartBevelSide) {
+ bottomRect.x += aStartBevelOffset - startBevel;
+ bottomRect.width -= aStartBevelOffset - startBevel;
+ }
+ if (NS_SIDE_BOTTOM == aEndBevelSide) {
+ bottomRect.width -= aEndBevelOffset - endBevel;
+ }
+ DrawSolidBorderSegment(aContext, bottomRect, twipsPerPixel, aStartBevelSide,
+ startBevel, aEndBevelSide, endBevel);
+ }
+ else { // left, right
+ nscoord thirdWidth = RoundFloatToPixel(0.333333f * (float)aBorder.width, twipsPerPixel);
+
+ nsRect leftRect(aBorder.x, aBorder.y, thirdWidth, aBorder.height);
+ if (NS_SIDE_LEFT == aStartBevelSide) {
+ leftRect.y += aStartBevelOffset - startBevel;
+ leftRect.height -= aStartBevelOffset - startBevel;
+ }
+ if (NS_SIDE_LEFT == aEndBevelSide) {
+ leftRect.height -= aEndBevelOffset - endBevel;
+ }
+ DrawSolidBorderSegment(aContext, leftRect, twipsPerPixel, aStartBevelSide,
+ startBevel, aEndBevelSide, endBevel);
+
+ nscoord widthOffset = aBorder.width - thirdWidth;
+ nsRect rightRect(aBorder.x + widthOffset, aBorder.y, aBorder.width - widthOffset, aBorder.height);
+ if (NS_SIDE_RIGHT == aStartBevelSide) {
+ rightRect.y += aStartBevelOffset - startBevel;
+ rightRect.height -= aStartBevelOffset - startBevel;
+ }
+ if (NS_SIDE_RIGHT == aEndBevelSide) {
+ rightRect.height -= aEndBevelOffset - endBevel;
+ }
+ DrawSolidBorderSegment(aContext, rightRect, twipsPerPixel, aStartBevelSide,
+ startBevel, aEndBevelSide, endBevel);
+ }
+ break;
+ }
+ // else fall through to solid
+ case NS_STYLE_BORDER_STYLE_SOLID:
+ DrawSolidBorderSegment(aContext, aBorder, twipsPerPixel, aStartBevelSide,
+ aStartBevelOffset, aEndBevelSide, aEndBevelOffset);
+ break;
+ case NS_STYLE_BORDER_STYLE_BG_OUTSET:
+ case NS_STYLE_BORDER_STYLE_BG_INSET:
+ case NS_STYLE_BORDER_STYLE_OUTSET:
+ case NS_STYLE_BORDER_STYLE_INSET:
+ NS_ASSERTION(PR_FALSE, "inset, outset should have been converted to groove, ridge");
+ break;
+ }
+}
+
+// End table border-collapsing section
+
diff --git a/mozilla/layout/base/nsCSSRendering.h b/mozilla/layout/base/nsCSSRendering.h
index 2e8282b0adb..360cdd17d88 100644
--- a/mozilla/layout/base/nsCSSRendering.h
+++ b/mozilla/layout/base/nsCSSRendering.h
@@ -180,6 +180,17 @@ public:
PRIntn aSkipSides,
nsRect* aGap);
+ // Draw a border segment in the table collapsing border model without beveling corners
+ static void DrawTableBorderSegment(nsIRenderingContext& aContext,
+ PRUint8 aBorderStyle,
+ nscolor aBorderColor,
+ const nsStyleBackground* aBGColor,
+ const nsRect& aBorderRect,
+ float aPixelsToTwips,
+ PRUint8 aStartBevelSide = 0,
+ nscoord aStartBevelOffset = 0,
+ PRUint8 aEndBevelSide = 0,
+ nscoord aEndBevelOffset = 0);
/**
* transform a color to a color that will show up on a printer if needed
* aMapColor - color to evaluate
diff --git a/mozilla/layout/base/nsLayoutAtomList.h b/mozilla/layout/base/nsLayoutAtomList.h
index 8a8cfd14e5e..5cb1b488129 100644
--- a/mozilla/layout/base/nsLayoutAtomList.h
+++ b/mozilla/layout/base/nsLayoutAtomList.h
@@ -100,6 +100,7 @@ LAYOUT_ATOM(selectScrolledContentPseudo, ":-moz-select-scrolled-content")
// Alphabetical list of frame types
LAYOUT_ATOM(areaFrame, "AreaFrame")
+LAYOUT_ATOM(bcTableCellFrame, "BCTableCellFrame") // table cell in border collapsing model
LAYOUT_ATOM(blockFrame, "BlockFrame")
LAYOUT_ATOM(boxFrame, "BoxFrame")
LAYOUT_ATOM(brFrame, "BRFrame")
@@ -143,7 +144,8 @@ LAYOUT_ATOM(overflowProperty, "OverflowProperty") // list of nsIFra
LAYOUT_ATOM(overflowLinesProperty, "OverflowLinesProperty") // list of nsLineBox*
LAYOUT_ATOM(rowUnpaginatedHeightProperty, "RowUnpaginatedHeightProperty") // nscoord*
LAYOUT_ATOM(spaceManagerProperty, "SpaceManagerProperty") // the space manager for a block
-LAYOUT_ATOM(viewProperty, "ViewProperty") // nsView*
+LAYOUT_ATOM(tableBCProperty, "TableBCProperty") // table border collapsing info (e.g. damage area, table border widths)
+LAYOUT_ATOM(viewProperty, "ViewProperty")
// Alphabetical list of event handler names
LAYOUT_ATOM(onabort, "onabort")
diff --git a/mozilla/layout/base/nsStyleConsts.h b/mozilla/layout/base/nsStyleConsts.h
index 7390e932a0c..888a2eb9c22 100644
--- a/mozilla/layout/base/nsStyleConsts.h
+++ b/mozilla/layout/base/nsStyleConsts.h
@@ -249,6 +249,9 @@
#define NS_STYLE_BORDER_STYLE_HIDDEN 10
#define NS_STYLE_BORDER_STYLE_BG_INSET 11
#define NS_STYLE_BORDER_STYLE_BG_OUTSET 12
+// a bit ORed onto the style for table border collapsing indicating that the style was
+// derived from a table with its rules attribute set
+#define NS_STYLE_BORDER_STYLE_RULES_MASK 0x10
// See nsStyleDisplay
#define NS_STYLE_CLEAR_NONE 0
diff --git a/mozilla/layout/base/public/nsHTMLReflowState.h b/mozilla/layout/base/public/nsHTMLReflowState.h
index e3b27df7c2d..d6afdf798cb 100644
--- a/mozilla/layout/base/public/nsHTMLReflowState.h
+++ b/mozilla/layout/base/public/nsHTMLReflowState.h
@@ -270,12 +270,13 @@ struct nsHTMLReflowState {
// Initialize a reflow state for a child frames reflow. Some state
// is copied from the parent reflow state; the remaining state is
- // computed.
+ // computed.
nsHTMLReflowState(nsIPresContext* aPresContext,
const nsHTMLReflowState& aParentReflowState,
nsIFrame* aFrame,
const nsSize& aAvailableSpace,
- nsReflowReason aReason);
+ nsReflowReason aReason,
+ PRBool aInit = PR_TRUE);
// Same as the previous except that the reason is taken from the
// parent's reflow state.
@@ -293,6 +294,13 @@ struct nsHTMLReflowState {
nscoord aContainingBlockWidth,
nscoord aContainingBlockHeight);
+ // This method initializes various data members. It is automatically
+ // called by the various constructors
+ void Init(nsIPresContext* aPresContext,
+ nscoord aContainingBlockWidth = -1,
+ nscoord aContainingBlockHeight = -1,
+ nsMargin* aBorder = nsnull,
+ nsMargin* aPadding = nsnull);
/**
* Get the containing block reflow state, starting from a frames
* parent reflow state (the parent reflow state may or may not end
@@ -352,15 +360,12 @@ struct nsHTMLReflowState {
protected:
- // This method initializes various data members. It is automatically
- // called by the various constructors
- void Init(nsIPresContext* aPresContext,
- nscoord aContainingBlockWidth = -1,
- nscoord aContainingBlockHeight = -1);
void InitConstraints(nsIPresContext* aPresContext,
nscoord aContainingBlockWidth,
- nscoord aContainingBlockHeight);
+ nscoord aContainingBlockHeight,
+ nsMargin* aBorder,
+ nsMargin* aPadding);
void CalculateHypotheticalBox(nsIPresContext* aPresContext,
nsIFrame* aPlaceholderFrame,
diff --git a/mozilla/layout/base/public/nsStyleConsts.h b/mozilla/layout/base/public/nsStyleConsts.h
index 7390e932a0c..888a2eb9c22 100644
--- a/mozilla/layout/base/public/nsStyleConsts.h
+++ b/mozilla/layout/base/public/nsStyleConsts.h
@@ -249,6 +249,9 @@
#define NS_STYLE_BORDER_STYLE_HIDDEN 10
#define NS_STYLE_BORDER_STYLE_BG_INSET 11
#define NS_STYLE_BORDER_STYLE_BG_OUTSET 12
+// a bit ORed onto the style for table border collapsing indicating that the style was
+// derived from a table with its rules attribute set
+#define NS_STYLE_BORDER_STYLE_RULES_MASK 0x10
// See nsStyleDisplay
#define NS_STYLE_CLEAR_NONE 0
diff --git a/mozilla/layout/generic/nsFrame.cpp b/mozilla/layout/generic/nsFrame.cpp
index d6b48651594..ada4ba390b8 100644
--- a/mozilla/layout/generic/nsFrame.cpp
+++ b/mozilla/layout/generic/nsFrame.cpp
@@ -4646,6 +4646,7 @@ void DR_State::InitFrameTypeTable()
AddFrameTypeInfo(nsLayoutAtoms::scrollFrame, "scroll", "scroll");
AddFrameTypeInfo(nsLayoutAtoms::tableCaptionFrame, "caption", "tableCaption");
AddFrameTypeInfo(nsLayoutAtoms::tableCellFrame, "cell", "tableCell");
+ AddFrameTypeInfo(nsLayoutAtoms::bcTableCellFrame, "bcCell", "bcTableCell");
AddFrameTypeInfo(nsLayoutAtoms::tableColFrame, "col", "tableCol");
AddFrameTypeInfo(nsLayoutAtoms::tableColGroupFrame, "colG", "tableColGroup");
AddFrameTypeInfo(nsLayoutAtoms::tableFrame, "tbl", "table");
diff --git a/mozilla/layout/generic/nsHTMLParts.h b/mozilla/layout/generic/nsHTMLParts.h
index 0085c46ff77..0e07379bbee 100644
--- a/mozilla/layout/generic/nsHTMLParts.h
+++ b/mozilla/layout/generic/nsHTMLParts.h
@@ -204,7 +204,7 @@ extern nsresult NS_NewTableColFrame(nsIPresShell* aPresShell, nsIFrame** aResult
extern nsresult NS_NewTableColGroupFrame(nsIPresShell* aPresShell, nsIFrame** aResult);
extern nsresult NS_NewTableRowFrame(nsIPresShell* aPresShell, nsIFrame** aResult);
extern nsresult NS_NewTableRowGroupFrame(nsIPresShell* aPresShell, nsIFrame** aResult);
-extern nsresult NS_NewTableCellFrame(nsIPresShell* aPresShell, nsIFrame** aResult);
+extern nsresult NS_NewTableCellFrame(nsIPresShell* aPresShell, PRBool aIsBorderCollapse, nsIFrame** aResult);
// XXX passing aWebShell into this is wrong
extern nsresult NS_NewHTMLContentSink(nsIHTMLContentSink** aInstancePtrResult,
diff --git a/mozilla/layout/generic/nsHTMLReflowState.cpp b/mozilla/layout/generic/nsHTMLReflowState.cpp
index 8d6855f27a5..92860c7cc46 100644
--- a/mozilla/layout/generic/nsHTMLReflowState.cpp
+++ b/mozilla/layout/generic/nsHTMLReflowState.cpp
@@ -51,6 +51,9 @@
#include "nsIPref.h"
#include "nsIServiceManager.h"
+#define IS_TABLE_CELL(frameType)\
+((nsLayoutAtoms::tableCellFrame == frameType) || (nsLayoutAtoms::bcTableCellFrame == frameType))
+
#ifdef NS_DEBUG
#undef NOISY_VERTICAL_ALIGN
#else
@@ -140,7 +143,8 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
const nsHTMLReflowState& aParentReflowState,
nsIFrame* aFrame,
const nsSize& aAvailableSpace,
- nsReflowReason aReason)
+ nsReflowReason aReason,
+ PRBool aInit)
: mReflowDepth(aParentReflowState.mReflowDepth + 1),
mFlags(aParentReflowState.mFlags)
{
@@ -159,7 +163,9 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage;
mPercentHeightObserver = aParentReflowState.mPercentHeightObserver;
- Init(aPresContext);
+ if (aInit) {
+ Init(aPresContext);
+ }
#ifdef IBMBIDI
mRightEdge = aParentReflowState.mRightEdge;
@@ -228,7 +234,9 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
void
nsHTMLReflowState::Init(nsIPresContext* aPresContext,
nscoord aContainingBlockWidth,
- nscoord aContainingBlockHeight)
+ nscoord aContainingBlockHeight,
+ nsMargin* aBorder,
+ nsMargin* aPadding)
{
mCompactMarginWidth = 0;
#ifdef DEBUG
@@ -244,7 +252,7 @@ nsHTMLReflowState::Init(nsIPresContext* aPresContext,
GetStyleData(frame, &mStyleText);
mFrameType = DetermineFrameType(frame, mStyleDisplay);
- InitConstraints(aPresContext, aContainingBlockWidth, aContainingBlockHeight);
+ InitConstraints(aPresContext, aContainingBlockWidth, aContainingBlockHeight, aBorder, aPadding);
}
const nsHTMLReflowState*
@@ -261,7 +269,7 @@ nsHTMLReflowState::GetContainingBlockReflowState(const nsHTMLReflowState* aParen
if (aParentRS->parentReflowState) {
nsCOMPtr fType;
aParentRS->parentReflowState->frame->GetFrameType(getter_AddRefs(fType));
- if (nsLayoutAtoms::tableCellFrame == fType.get()) {
+ if (IS_TABLE_CELL(fType.get())) {
aParentRS = aParentRS->parentReflowState;
}
}
@@ -1575,7 +1583,9 @@ static PRBool BlinkIsAllowed(void)
void
nsHTMLReflowState::InitConstraints(nsIPresContext* aPresContext,
nscoord aContainingBlockWidth,
- nscoord aContainingBlockHeight)
+ nscoord aContainingBlockHeight,
+ nsMargin* aBorder,
+ nsMargin* aPadding)
{
// If this is the root frame, then set the computed width and
// height equal to the available space
@@ -1633,7 +1643,7 @@ nsHTMLReflowState::InitConstraints(nsIPresContext* aPresContext,
}
else {
cbrs->frame->GetFrameType(getter_AddRefs(fType));
- if (nsLayoutAtoms::tableCellFrame == fType.get()) {
+ if (IS_TABLE_CELL(fType.get())) {
// use the cell's computed height
aContainingBlockHeight =
((nsHTMLReflowState*)cbrs)->mComputedHeight;
@@ -1647,10 +1657,26 @@ nsHTMLReflowState::InitConstraints(nsIPresContext* aPresContext,
// XXX fix to provide 0,0 for the top&bottom margins for
// inline-non-replaced elements
ComputeMargin(aContainingBlockWidth, cbrs);
- ComputePadding(aContainingBlockWidth, cbrs);
- if (!mStyleBorder->GetBorder(mComputedBorderPadding)) {
- // CSS2 has no percentage borders
- mComputedBorderPadding.SizeTo(0, 0, 0, 0);
+ if (aPadding) { // padding is an input arg
+ mComputedPadding.top = aPadding->top;
+ mComputedPadding.right = aPadding->right;
+ mComputedPadding.bottom = aPadding->bottom;
+ mComputedPadding.left = aPadding->left;
+ }
+ else {
+ ComputePadding(aContainingBlockWidth, cbrs);
+ }
+ if (aBorder) { // border is an input arg
+ mComputedBorderPadding.top = aBorder->top;
+ mComputedBorderPadding.right = aBorder->right;
+ mComputedBorderPadding.bottom = aBorder->bottom;
+ mComputedBorderPadding.left = aBorder->left;
+ }
+ else {
+ if (!mStyleBorder->GetBorder(mComputedBorderPadding)) {
+ // CSS2 has no percentage borders
+ mComputedBorderPadding.SizeTo(0, 0, 0, 0);
+ }
}
mComputedBorderPadding += mComputedPadding;
diff --git a/mozilla/layout/generic/nsHTMLReflowState.h b/mozilla/layout/generic/nsHTMLReflowState.h
index e3b27df7c2d..d6afdf798cb 100644
--- a/mozilla/layout/generic/nsHTMLReflowState.h
+++ b/mozilla/layout/generic/nsHTMLReflowState.h
@@ -270,12 +270,13 @@ struct nsHTMLReflowState {
// Initialize a reflow state for a child frames reflow. Some state
// is copied from the parent reflow state; the remaining state is
- // computed.
+ // computed.
nsHTMLReflowState(nsIPresContext* aPresContext,
const nsHTMLReflowState& aParentReflowState,
nsIFrame* aFrame,
const nsSize& aAvailableSpace,
- nsReflowReason aReason);
+ nsReflowReason aReason,
+ PRBool aInit = PR_TRUE);
// Same as the previous except that the reason is taken from the
// parent's reflow state.
@@ -293,6 +294,13 @@ struct nsHTMLReflowState {
nscoord aContainingBlockWidth,
nscoord aContainingBlockHeight);
+ // This method initializes various data members. It is automatically
+ // called by the various constructors
+ void Init(nsIPresContext* aPresContext,
+ nscoord aContainingBlockWidth = -1,
+ nscoord aContainingBlockHeight = -1,
+ nsMargin* aBorder = nsnull,
+ nsMargin* aPadding = nsnull);
/**
* Get the containing block reflow state, starting from a frames
* parent reflow state (the parent reflow state may or may not end
@@ -352,15 +360,12 @@ struct nsHTMLReflowState {
protected:
- // This method initializes various data members. It is automatically
- // called by the various constructors
- void Init(nsIPresContext* aPresContext,
- nscoord aContainingBlockWidth = -1,
- nscoord aContainingBlockHeight = -1);
void InitConstraints(nsIPresContext* aPresContext,
nscoord aContainingBlockWidth,
- nscoord aContainingBlockHeight);
+ nscoord aContainingBlockHeight,
+ nsMargin* aBorder,
+ nsMargin* aPadding);
void CalculateHypotheticalBox(nsIPresContext* aPresContext,
nsIFrame* aPlaceholderFrame,
diff --git a/mozilla/layout/html/base/src/nsFrame.cpp b/mozilla/layout/html/base/src/nsFrame.cpp
index d6b48651594..ada4ba390b8 100644
--- a/mozilla/layout/html/base/src/nsFrame.cpp
+++ b/mozilla/layout/html/base/src/nsFrame.cpp
@@ -4646,6 +4646,7 @@ void DR_State::InitFrameTypeTable()
AddFrameTypeInfo(nsLayoutAtoms::scrollFrame, "scroll", "scroll");
AddFrameTypeInfo(nsLayoutAtoms::tableCaptionFrame, "caption", "tableCaption");
AddFrameTypeInfo(nsLayoutAtoms::tableCellFrame, "cell", "tableCell");
+ AddFrameTypeInfo(nsLayoutAtoms::bcTableCellFrame, "bcCell", "bcTableCell");
AddFrameTypeInfo(nsLayoutAtoms::tableColFrame, "col", "tableCol");
AddFrameTypeInfo(nsLayoutAtoms::tableColGroupFrame, "colG", "tableColGroup");
AddFrameTypeInfo(nsLayoutAtoms::tableFrame, "tbl", "table");
diff --git a/mozilla/layout/html/base/src/nsHTMLParts.h b/mozilla/layout/html/base/src/nsHTMLParts.h
index 0085c46ff77..0e07379bbee 100644
--- a/mozilla/layout/html/base/src/nsHTMLParts.h
+++ b/mozilla/layout/html/base/src/nsHTMLParts.h
@@ -204,7 +204,7 @@ extern nsresult NS_NewTableColFrame(nsIPresShell* aPresShell, nsIFrame** aResult
extern nsresult NS_NewTableColGroupFrame(nsIPresShell* aPresShell, nsIFrame** aResult);
extern nsresult NS_NewTableRowFrame(nsIPresShell* aPresShell, nsIFrame** aResult);
extern nsresult NS_NewTableRowGroupFrame(nsIPresShell* aPresShell, nsIFrame** aResult);
-extern nsresult NS_NewTableCellFrame(nsIPresShell* aPresShell, nsIFrame** aResult);
+extern nsresult NS_NewTableCellFrame(nsIPresShell* aPresShell, PRBool aIsBorderCollapse, nsIFrame** aResult);
// XXX passing aWebShell into this is wrong
extern nsresult NS_NewHTMLContentSink(nsIHTMLContentSink** aInstancePtrResult,
diff --git a/mozilla/layout/html/base/src/nsHTMLReflowState.cpp b/mozilla/layout/html/base/src/nsHTMLReflowState.cpp
index 8d6855f27a5..92860c7cc46 100644
--- a/mozilla/layout/html/base/src/nsHTMLReflowState.cpp
+++ b/mozilla/layout/html/base/src/nsHTMLReflowState.cpp
@@ -51,6 +51,9 @@
#include "nsIPref.h"
#include "nsIServiceManager.h"
+#define IS_TABLE_CELL(frameType)\
+((nsLayoutAtoms::tableCellFrame == frameType) || (nsLayoutAtoms::bcTableCellFrame == frameType))
+
#ifdef NS_DEBUG
#undef NOISY_VERTICAL_ALIGN
#else
@@ -140,7 +143,8 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
const nsHTMLReflowState& aParentReflowState,
nsIFrame* aFrame,
const nsSize& aAvailableSpace,
- nsReflowReason aReason)
+ nsReflowReason aReason,
+ PRBool aInit)
: mReflowDepth(aParentReflowState.mReflowDepth + 1),
mFlags(aParentReflowState.mFlags)
{
@@ -159,7 +163,9 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage;
mPercentHeightObserver = aParentReflowState.mPercentHeightObserver;
- Init(aPresContext);
+ if (aInit) {
+ Init(aPresContext);
+ }
#ifdef IBMBIDI
mRightEdge = aParentReflowState.mRightEdge;
@@ -228,7 +234,9 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext,
void
nsHTMLReflowState::Init(nsIPresContext* aPresContext,
nscoord aContainingBlockWidth,
- nscoord aContainingBlockHeight)
+ nscoord aContainingBlockHeight,
+ nsMargin* aBorder,
+ nsMargin* aPadding)
{
mCompactMarginWidth = 0;
#ifdef DEBUG
@@ -244,7 +252,7 @@ nsHTMLReflowState::Init(nsIPresContext* aPresContext,
GetStyleData(frame, &mStyleText);
mFrameType = DetermineFrameType(frame, mStyleDisplay);
- InitConstraints(aPresContext, aContainingBlockWidth, aContainingBlockHeight);
+ InitConstraints(aPresContext, aContainingBlockWidth, aContainingBlockHeight, aBorder, aPadding);
}
const nsHTMLReflowState*
@@ -261,7 +269,7 @@ nsHTMLReflowState::GetContainingBlockReflowState(const nsHTMLReflowState* aParen
if (aParentRS->parentReflowState) {
nsCOMPtr fType;
aParentRS->parentReflowState->frame->GetFrameType(getter_AddRefs(fType));
- if (nsLayoutAtoms::tableCellFrame == fType.get()) {
+ if (IS_TABLE_CELL(fType.get())) {
aParentRS = aParentRS->parentReflowState;
}
}
@@ -1575,7 +1583,9 @@ static PRBool BlinkIsAllowed(void)
void
nsHTMLReflowState::InitConstraints(nsIPresContext* aPresContext,
nscoord aContainingBlockWidth,
- nscoord aContainingBlockHeight)
+ nscoord aContainingBlockHeight,
+ nsMargin* aBorder,
+ nsMargin* aPadding)
{
// If this is the root frame, then set the computed width and
// height equal to the available space
@@ -1633,7 +1643,7 @@ nsHTMLReflowState::InitConstraints(nsIPresContext* aPresContext,
}
else {
cbrs->frame->GetFrameType(getter_AddRefs(fType));
- if (nsLayoutAtoms::tableCellFrame == fType.get()) {
+ if (IS_TABLE_CELL(fType.get())) {
// use the cell's computed height
aContainingBlockHeight =
((nsHTMLReflowState*)cbrs)->mComputedHeight;
@@ -1647,10 +1657,26 @@ nsHTMLReflowState::InitConstraints(nsIPresContext* aPresContext,
// XXX fix to provide 0,0 for the top&bottom margins for
// inline-non-replaced elements
ComputeMargin(aContainingBlockWidth, cbrs);
- ComputePadding(aContainingBlockWidth, cbrs);
- if (!mStyleBorder->GetBorder(mComputedBorderPadding)) {
- // CSS2 has no percentage borders
- mComputedBorderPadding.SizeTo(0, 0, 0, 0);
+ if (aPadding) { // padding is an input arg
+ mComputedPadding.top = aPadding->top;
+ mComputedPadding.right = aPadding->right;
+ mComputedPadding.bottom = aPadding->bottom;
+ mComputedPadding.left = aPadding->left;
+ }
+ else {
+ ComputePadding(aContainingBlockWidth, cbrs);
+ }
+ if (aBorder) { // border is an input arg
+ mComputedBorderPadding.top = aBorder->top;
+ mComputedBorderPadding.right = aBorder->right;
+ mComputedBorderPadding.bottom = aBorder->bottom;
+ mComputedBorderPadding.left = aBorder->left;
+ }
+ else {
+ if (!mStyleBorder->GetBorder(mComputedBorderPadding)) {
+ // CSS2 has no percentage borders
+ mComputedBorderPadding.SizeTo(0, 0, 0, 0);
+ }
}
mComputedBorderPadding += mComputedPadding;
diff --git a/mozilla/layout/html/document/src/html.css b/mozilla/layout/html/document/src/html.css
index a501e25a540..61190f734f4 100644
--- a/mozilla/layout/html/document/src/html.css
+++ b/mozilla/layout/html/document/src/html.css
@@ -168,6 +168,10 @@ table[align="right"] {
text-align: start;
}
+table[rules] {
+ border-collapse: collapse;
+}
+
*|*:table-outer {
display: table;
margin: 0;
@@ -219,6 +223,11 @@ tr {
col, *|*:table-column {
display: table-column;
+ border: inherit;
+ width: inherit;
+ height: inherit;
+ background: inherit;
+ border: inherit;
}
colgroup, *|*:table-column-group {
diff --git a/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp b/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp
index e20226d01b6..113297119be 100644
--- a/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp
+++ b/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp
@@ -52,8 +52,11 @@
#include "nsIPresContext.h"
#include "nsILinkHandler.h"
#include "nsIDocument.h"
+#include "nsTableFrame.h"
#include "nsTableColGroupFrame.h"
#include "nsTableColFrame.h"
+#include "nsIDOMHTMLTableColElement.h"
+#include "nsTableCellFrame.h" // to get IS_CELL_FRAME
#include "nsHTMLIIDs.h"
#include "nsIStyleFrameConstruction.h"
#include "nsHTMLParts.h"
@@ -859,6 +862,23 @@ nsFrameConstructorSaveState::~nsFrameConstructorSaveState()
}
}
+
+static
+PRBool IsBorderCollapse(nsIFrame* aFrame)
+{
+ nsIFrame* frame = aFrame;
+ while (frame) {
+ nsCOMPtr fType;
+ frame->GetFrameType(getter_AddRefs(fType));
+ if (nsLayoutAtoms::tableFrame == fType.get()) {
+ return ((nsTableFrame*)frame)->IsBorderCollapse();
+ }
+ frame->GetParent(&frame);
+ }
+ NS_ASSERTION(PR_FALSE, "program error");
+ return PR_FALSE;
+}
+
// -----------------------------------------------------------
// Structure used when creating table frames.
@@ -870,7 +890,7 @@ struct nsTableCreator {
virtual nsresult CreateTableColFrame(nsIFrame** aNewFrame);
virtual nsresult CreateTableColGroupFrame(nsIFrame** aNewFrame);
virtual nsresult CreateTableRowFrame(nsIFrame** aNewFrame);
- virtual nsresult CreateTableCellFrame(nsIFrame** aNewFrame);
+ virtual nsresult CreateTableCellFrame(nsIFrame* aParentFrame, nsIFrame** aNewFrame);
virtual nsresult CreateTableCellInnerFrame(nsIFrame** aNewFrame);
nsTableCreator(nsIPresShell* aPresShell)
@@ -919,8 +939,9 @@ nsTableCreator::CreateTableRowFrame(nsIFrame** aNewFrame) {
}
nsresult
-nsTableCreator::CreateTableCellFrame(nsIFrame** aNewFrame) {
- return NS_NewTableCellFrame(mPresShell, aNewFrame);
+nsTableCreator::CreateTableCellFrame(nsIFrame* aParentFrame,
+ nsIFrame** aNewFrame) {
+ return NS_NewTableCellFrame(mPresShell, IsBorderCollapse(aParentFrame), aNewFrame);
}
nsresult
@@ -1527,7 +1548,7 @@ IsTableRelated(nsIAtom* aParentType,
((nsLayoutAtoms::tableCaptionFrame == aParentType) ||
(nsLayoutAtoms::tableColGroupFrame == aParentType) ||
(nsLayoutAtoms::tableColFrame == aParentType) ||
- (nsLayoutAtoms::tableCellFrame == aParentType))) {
+ IS_TABLE_CELL(aParentType))) {
return PR_TRUE;
}
else return PR_FALSE;
@@ -1629,7 +1650,7 @@ ProcessPseudoFrames(nsIPresContext* aPresContext,
if (aPseudoFrames.mCellOuter.mFrame) {
rv = ProcessPseudoCellFrame(aPresContext, aPseudoFrames, aHighestFrame);
- if (nsLayoutAtoms::tableCellFrame == aHighestType) return rv;
+ if (IS_TABLE_CELL(aHighestType)) return rv;
}
if (aPseudoFrames.mRow.mFrame) {
rv = ProcessPseudoFrame(aPresContext, aPseudoFrames.mRow, aHighestFrame);
@@ -1650,7 +1671,7 @@ ProcessPseudoFrames(nsIPresContext* aPresContext,
}
if (aPseudoFrames.mCellOuter.mFrame) {
rv = ProcessPseudoCellFrame(aPresContext, aPseudoFrames, aHighestFrame);
- if (nsLayoutAtoms::tableCellFrame == aHighestType) return rv;
+ if (IS_TABLE_CELL(aHighestType)) return rv;
}
if (aPseudoFrames.mRow.mFrame) {
rv = ProcessPseudoFrame(aPresContext, aPseudoFrames.mRow, aHighestFrame);
@@ -1671,12 +1692,12 @@ ProcessPseudoFrames(nsIPresContext* aPresContext,
}
if (aPseudoFrames.mCellOuter.mFrame) {
rv = ProcessPseudoCellFrame(aPresContext, aPseudoFrames, aHighestFrame);
- if (nsLayoutAtoms::tableCellFrame == aHighestType) return rv;
+ if (IS_TABLE_CELL(aHighestType)) return rv;
}
}
- else if (nsLayoutAtoms::tableCellFrame == aPseudoFrames.mLowestType) {
+ else if (IS_TABLE_CELL(aPseudoFrames.mLowestType)) {
rv = ProcessPseudoCellFrame(aPresContext, aPseudoFrames, aHighestFrame);
- if (nsLayoutAtoms::tableCellFrame == aHighestType) return rv;
+ if (IS_TABLE_CELL(aHighestType)) return rv;
if (aPseudoFrames.mRow.mFrame) {
rv = ProcessPseudoFrame(aPresContext, aPseudoFrames.mRow, aHighestFrame);
@@ -1942,6 +1963,7 @@ nsCSSFrameConstructor::CreatePseudoCellFrame(nsIPresShell* aPresShell
// set pseudo data for the newly created frames
pseudoOuter.mChildList.AddChild(pseudoInner.mFrame);
+ // give it nsLayoutAtoms::tableCellFrame, if it is really nsLayoutAtoms::bcTableCellFrame, it will match later
aState.mPseudoFrames.mLowestType = nsLayoutAtoms::tableCellFrame;
// set pseudo data for the parent
@@ -2021,7 +2043,7 @@ nsCSSFrameConstructor::GetPseudoColGroupFrame(nsIPresShell* aPresShel
rv = CreatePseudoCellFrame(aPresShell, aPresContext, aTableCreator, aState, &aParentFrameIn);
created = PR_TRUE;
}
- if (created || (nsLayoutAtoms::tableCellFrame == parentFrameType.get()) || // cell parent
+ if (created || IS_TABLE_CELL(parentFrameType.get()) || // cell parent
!IsTableRelated(parentFrameType.get(), PR_TRUE)) { // block parent
rv = CreatePseudoTableFrame(aPresShell, aPresContext, aTableCreator, aState, &aParentFrameIn);
}
@@ -2065,7 +2087,7 @@ nsCSSFrameConstructor::GetPseudoRowGroupFrame(nsIPresShell* aPresShel
rv = CreatePseudoCellFrame(aPresShell, aPresContext, aTableCreator, aState, &aParentFrameIn);
created = PR_TRUE;
}
- if (created || (nsLayoutAtoms::tableCellFrame == parentFrameType.get()) || // cell parent
+ if (created || IS_TABLE_CELL(parentFrameType.get()) || // cell parent
!IsTableRelated(parentFrameType.get(), PR_TRUE)) { // block parent
rv = CreatePseudoTableFrame(aPresShell, aPresContext, aTableCreator, aState, &aParentFrameIn);
}
@@ -2102,7 +2124,7 @@ nsCSSFrameConstructor::GetPseudoRowFrame(nsIPresShell* aPresShell,
if (pseudoFrames.IsEmpty()) {
PRBool created = PR_FALSE;
- if ((nsLayoutAtoms::tableCellFrame == parentFrameType.get()) || // cell parent
+ if (IS_TABLE_CELL(parentFrameType.get()) || // cell parent
!IsTableRelated(parentFrameType.get(), PR_TRUE)) { // block parent
rv = CreatePseudoTableFrame(aPresShell, aPresContext, aTableCreator, aState, &aParentFrameIn);
created = PR_TRUE;
@@ -2230,7 +2252,7 @@ nsCSSFrameConstructor::GetParentFrame(nsIPresShell* aPresShell,
pseudoParentFrame = pseudoFrames.mRowGroup.mFrame;
}
}
- else if (nsLayoutAtoms::tableCellFrame == aChildFrameType) { // cell child
+ else if (IS_TABLE_CELL(aChildFrameType)) { // cell child
if (nsLayoutAtoms::tableRowFrame != parentFrameType.get()) { // need pseudo row parent
rv = GetPseudoRowFrame(aPresShell, aPresContext, aTableCreator, aState, aParentFrameIn);
if (NS_FAILED(rv)) return rv;
@@ -2572,7 +2594,7 @@ nsCSSFrameConstructor::ConstructTableColFrame(nsIPresShell* aPresShel
PRBool& aIsPseudoParent)
{
nsresult rv = NS_OK;
- if (!aPresShell || !aPresContext || !aParentFrameIn) return rv;
+ if (!aPresShell || !aPresContext || !aParentFrameIn || !aStyleContext) return rv;
nsIFrame* parentFrame = aParentFrameIn;
aIsPseudoParent = PR_FALSE;
@@ -2585,16 +2607,42 @@ nsCSSFrameConstructor::ConstructTableColFrame(nsIPresShell* aPresShel
}
}
- rv = aTableCreator.CreateTableColFrame(&aNewFrame);
- if (NS_FAILED(rv)) return rv;
- InitAndRestoreFrame(aPresContext, aState, aContent,
- parentFrame, aStyleContext, nsnull, aNewFrame);
+ rv = aTableCreator.CreateTableColFrame(&aNewFrame); if (NS_FAILED(rv)) return rv;
+ InitAndRestoreFrame(aPresContext, aState, aContent, parentFrame, aStyleContext, nsnull, aNewFrame);
+ // if the parent frame was anonymous then reparent the style context
+ nsCOMPtr parentStyleContext;
+ parentFrame->GetStyleContext(getter_AddRefs(parentStyleContext));
+ if (aIsPseudoParent) {
+ aPresContext->ReParentStyleContext(aNewFrame, parentStyleContext);
+ }
+
+ // construct additional col frames if the col frame has a span > 1
+ PRInt32 span = 1;
+ nsCOMPtr cgContent(do_QueryInterface(aContent));
+ if (cgContent) {
+ cgContent->GetSpan(&span);
+ nsIFrame* lastCol = aNewFrame;
+ for (PRInt32 spanX = 1; spanX < span; spanX++) {
+ nsCOMPtr styleContext;
+ aPresContext->ResolvePseudoStyleContextFor(aContent, nsHTMLAtoms::tableColPseudo, aStyleContext,
+ PR_FALSE, getter_AddRefs(styleContext));
+ nsIFrame* newCol;
+ rv = aTableCreator.CreateTableColFrame(&newCol); if (NS_FAILED(rv)) return rv;
+ InitAndRestoreFrame(aPresContext, aState, aContent, parentFrame, styleContext, nsnull, newCol);
+ if (aIsPseudoParent) {
+ aPresContext->ReParentStyleContext(newCol, aStyleContext);
+ }
+ ((nsTableColFrame*)newCol)->SetType(eColAnonymousCol);
+ lastCol->SetNextSibling(newCol);
+ lastCol = newCol;
+ }
+ }
+
if (!aIsPseudo) {
nsFrameItems childItems;
nsIFrame* captionFrame;
rv = TableProcessChildren(aPresShell, aPresContext, aState, aContent, aNewFrame,
- aTableCreator, childItems, captionFrame);
- if (NS_FAILED(rv)) return rv;
+ aTableCreator, childItems, captionFrame); if (NS_FAILED(rv)) return rv;
aNewFrame->SetInitialChildList(aPresContext, nsnull, childItems.childList);
if (aIsPseudoParent) {
aState.mPseudoFrames.mColGroup.mChildList.AddChild(aNewFrame);
@@ -2625,6 +2673,7 @@ nsCSSFrameConstructor::ConstructTableCellFrame(nsIPresShell* aPresShe
aIsPseudoParent = PR_FALSE;
if (!aIsPseudo) {
// this frame may have a pseudo parent
+ // use nsLayoutAtoms::tableCellFrame which will match if it is really nsLayoutAtoms::bcTableCellFrame
GetParentFrame(aPresShell, aPresContext, aTableCreator, *aParentFrameIn,
nsLayoutAtoms::tableCellFrame, aState, parentFrame, aIsPseudoParent);
if (!aIsPseudoParent && !aState.mPseudoFrames.IsEmpty()) {
@@ -2635,7 +2684,7 @@ nsCSSFrameConstructor::ConstructTableCellFrame(nsIPresShell* aPresShe
}
}
- rv = aTableCreator.CreateTableCellFrame(&aNewCellOuterFrame);
+ rv = aTableCreator.CreateTableCellFrame(parentFrame, &aNewCellOuterFrame);
if (NS_FAILED(rv)) return rv;
// Initialize the table cell frame
@@ -11328,7 +11377,7 @@ nsCSSFrameConstructor::CreateContinuingFrame(nsIPresShell* aPresShell,
// See if it's a table cell frame
cellFrame->GetFrameType(&tableType);
- if (nsLayoutAtoms::tableCellFrame == tableType) {
+ if (IS_TABLE_CELL(tableType)) {
nsIFrame* continuingCellFrame;
CreateContinuingFrame(aPresShell, aPresContext, cellFrame, newFrame, &continuingCellFrame);
@@ -11343,8 +11392,8 @@ nsCSSFrameConstructor::CreateContinuingFrame(nsIPresShell* aPresShell,
newFrame->SetInitialChildList(aPresContext, nsnull, newChildList.childList);
}
- } else if (nsLayoutAtoms::tableCellFrame == frameType) {
- rv = NS_NewTableCellFrame(aPresShell, &newFrame);
+ } else if (IS_TABLE_CELL(frameType)) {
+ rv = NS_NewTableCellFrame(aPresShell, IsBorderCollapse(aParentFrame), &newFrame);
if (NS_SUCCEEDED(rv)) {
newFrame->Init(aPresContext, content, aParentFrame, styleContext, aFrame);
nsHTMLContainerFrame::CreateViewForFrame(aPresContext, newFrame,
diff --git a/mozilla/layout/html/style/src/nsCSSRendering.cpp b/mozilla/layout/html/style/src/nsCSSRendering.cpp
index 543a729ae1f..ea8f7cdea80 100644
--- a/mozilla/layout/html/style/src/nsCSSRendering.cpp
+++ b/mozilla/layout/html/style/src/nsCSSRendering.cpp
@@ -514,6 +514,7 @@ void nsCSSRendering::DrawSide(nsIRenderingContext& aContext,
}
}
+
/**
* Draw a dotted/dashed sides of a box
*/
@@ -3821,3 +3822,356 @@ void FillOrInvertRect(nsIRenderingContext& aRC, const nsRect& aRect, PRBool aInv
}
}
+// Begin table border-collapsing section
+// These functions were written to not disrupt the normal ones and yet satisfy some additional requirements
+// At some point, all functions should be unified to include the additional functionality that these provide
+
+static nscoord
+RoundIntToPixel(nscoord aValue,
+ nscoord aTwipsPerPixel,
+ PRBool aRoundDown = PR_FALSE)
+{
+ nscoord halfPixel = NSToCoordRound(aTwipsPerPixel / 2.0f);
+ nscoord extra = aValue % aTwipsPerPixel;
+ nscoord finalValue = (!aRoundDown && (extra >= halfPixel)) ? aValue + (aTwipsPerPixel - extra) : aValue - extra;
+
+ return finalValue;
+}
+
+static nscoord
+RoundFloatToPixel(float aValue,
+ nscoord aTwipsPerPixel,
+ PRBool aRoundDown = PR_FALSE)
+{
+ return RoundIntToPixel(NSToCoordRound(aValue), aTwipsPerPixel, aRoundDown);
+}
+
+static void
+SetPoly(const nsRect& aRect,
+ nsPoint* poly)
+{
+ poly[0].x = aRect.x;
+ poly[0].y = aRect.y;
+ poly[1].x = aRect.x + aRect.width;
+ poly[1].y = aRect.y;
+ poly[2].x = aRect.x + aRect.width;
+ poly[2].y = aRect.y + aRect.height;
+ poly[3].x = aRect.x;
+ poly[3].y = aRect.y + aRect.height;
+ poly[4].x = aRect.x;
+ poly[4].y = aRect.y;
+}
+
+static void
+DrawSolidBorderSegment(nsIRenderingContext& aContext,
+ nsRect aRect,
+ nscoord aTwipsPerPixel,
+ PRUint8 aStartBevelSide = 0,
+ nscoord aStartBevelOffset = 0,
+ PRUint8 aEndBevelSide = 0,
+ nscoord aEndBevelOffset = 0)
+{
+
+ if ((aRect.width == aTwipsPerPixel) || (aRect.height == aTwipsPerPixel) ||
+ ((0 == aStartBevelOffset) && (0 == aEndBevelOffset))) {
+ // simple line or rectangle
+ if ((NS_SIDE_TOP == aStartBevelSide) || (NS_SIDE_BOTTOM == aStartBevelSide)) {
+ if (1 == aRect.height)
+ aContext.DrawLine(aRect.x, aRect.y, aRect.x, aRect.y + aRect.height);
+ else
+ aContext.FillRect(aRect);
+ }
+ else {
+ if (1 == aRect.width)
+ aContext.DrawLine(aRect.x, aRect.y, aRect.x + aRect.width, aRect.y);
+ else
+ aContext.FillRect(aRect);
+ }
+ }
+ else {
+ // polygon with beveling
+ nsPoint poly[5];
+ SetPoly(aRect, poly);
+ switch(aStartBevelSide) {
+ case NS_SIDE_TOP:
+ poly[0].x += aStartBevelOffset;
+ poly[4].x = poly[0].x;
+ break;
+ case NS_SIDE_BOTTOM:
+ poly[3].x += aStartBevelOffset;
+ break;
+ case NS_SIDE_RIGHT:
+ poly[1].y += aStartBevelOffset;
+ break;
+ case NS_SIDE_LEFT:
+ poly[0].y += aStartBevelOffset;
+ poly[4].y = poly[0].y;
+ }
+
+ switch(aEndBevelSide) {
+ case NS_SIDE_TOP:
+ poly[1].x -= aEndBevelOffset;
+ break;
+ case NS_SIDE_BOTTOM:
+ poly[2].x -= aEndBevelOffset;
+ break;
+ case NS_SIDE_RIGHT:
+ poly[2].y -= aEndBevelOffset;
+ break;
+ case NS_SIDE_LEFT:
+ poly[3].y -= aEndBevelOffset;
+ }
+
+ aContext.FillPolygon(poly, 5);
+ }
+
+
+}
+
+static void
+GetDashInfo(nscoord aBorderLength,
+ nscoord aDashLength,
+ nscoord aTwipsPerPixel,
+ PRInt32& aNumDashSpaces,
+ nscoord& aStartDashLength,
+ nscoord& aEndDashLength)
+{
+ aNumDashSpaces = 0;
+ if (aStartDashLength + aDashLength + aEndDashLength >= aBorderLength) {
+ aStartDashLength = aBorderLength;
+ aEndDashLength = 0;
+ }
+ else {
+ aNumDashSpaces = aBorderLength / (2 * aDashLength); // round down
+ nscoord foo = ((2 * aNumDashSpaces) - 1) * aDashLength;
+ nscoord extra = aBorderLength - aStartDashLength - aEndDashLength - (((2 * aNumDashSpaces) - 1) * aDashLength);
+ if (extra > 0) {
+ nscoord half = RoundIntToPixel(extra / 2, aTwipsPerPixel);
+ aStartDashLength += half;
+ aEndDashLength += (extra - half);
+ }
+ }
+}
+
+void
+nsCSSRendering::DrawTableBorderSegment(nsIRenderingContext& aContext,
+ PRUint8 aBorderStyle,
+ nscolor aBorderColor,
+ const nsStyleBackground* aBGColor,
+ const nsRect& aBorder,
+ float aPixelsToTwips,
+ PRUint8 aStartBevelSide,
+ nscoord aStartBevelOffset,
+ PRUint8 aEndBevelSide,
+ nscoord aEndBevelOffset)
+{
+ aContext.SetColor (aBorderColor);
+
+ PRBool horizontal = ((NS_SIDE_TOP == aStartBevelSide) || (NS_SIDE_BOTTOM == aStartBevelSide));
+ nscoord twipsPerPixel = NSIntPixelsToTwips(1, aPixelsToTwips);
+ PRBool ridgeGroove = NS_STYLE_BORDER_STYLE_RIDGE;
+
+ if ((twipsPerPixel >= aBorder.width) || (twipsPerPixel >= aBorder.height) ||
+ (NS_STYLE_BORDER_STYLE_DASHED == aBorderStyle) || (NS_STYLE_BORDER_STYLE_DOTTED == aBorderStyle)) {
+ // no beveling for 1 pixel border, dash or dot
+ aStartBevelOffset = 0;
+ aEndBevelOffset = 0;
+ }
+
+ switch (aBorderStyle) {
+ case NS_STYLE_BORDER_STYLE_NONE:
+ case NS_STYLE_BORDER_STYLE_HIDDEN:
+ case NS_STYLE_BORDER_STYLE_BLANK:
+ //NS_ASSERTION(PR_FALSE, "style of none, hidden, or blank");
+ break;
+ case NS_STYLE_BORDER_STYLE_DOTTED:
+ case NS_STYLE_BORDER_STYLE_DASHED:
+ {
+ nscoord dashLength = (NS_STYLE_BORDER_STYLE_DASHED == aBorderStyle) ? DASH_LENGTH : DOT_LENGTH;
+ // make the dash length proportional to the border thickness
+ dashLength *= (horizontal) ? aBorder.height : aBorder.width;
+ // make the min dash length for the ends 1/2 the dash length
+ nscoord minDashLength = (NS_STYLE_BORDER_STYLE_DASHED == aBorderStyle)
+ ? RoundFloatToPixel(((float)dashLength) / 2.0f, twipsPerPixel) : dashLength;
+ minDashLength = PR_MAX(minDashLength, twipsPerPixel);
+ nscoord numDashSpaces = 0;
+ nscoord startDashLength = minDashLength;
+ nscoord endDashLength = minDashLength;
+ if (horizontal) {
+ GetDashInfo(aBorder.width, dashLength, twipsPerPixel, numDashSpaces, startDashLength, endDashLength);
+ nsRect rect(aBorder.x, aBorder.y, startDashLength, aBorder.height);
+ DrawSolidBorderSegment(aContext, rect, PR_TRUE);
+ for (PRInt32 spaceX = 0; spaceX < numDashSpaces; spaceX++) {
+ rect.x += rect.width + dashLength;
+ rect.width = (spaceX == (numDashSpaces - 1)) ? endDashLength : dashLength;
+ DrawSolidBorderSegment(aContext, rect, PR_TRUE);
+ }
+ }
+ else {
+ GetDashInfo(aBorder.height, dashLength, twipsPerPixel, numDashSpaces, startDashLength, endDashLength);
+ nsRect rect(aBorder.x, aBorder.y, aBorder.width, startDashLength);
+ DrawSolidBorderSegment(aContext, rect, PR_FALSE);
+ for (PRInt32 spaceY = 0; spaceY < numDashSpaces; spaceY++) {
+ rect.y += rect.height + dashLength;
+ rect.height = (spaceY == (numDashSpaces - 1)) ? endDashLength : dashLength;
+ DrawSolidBorderSegment(aContext, rect, PR_FALSE);
+ }
+ }
+ }
+ break;
+ case NS_STYLE_BORDER_STYLE_GROOVE:
+ ridgeGroove = NS_STYLE_BORDER_STYLE_GROOVE; // and fall through to ridge
+ case NS_STYLE_BORDER_STYLE_RIDGE:
+ if ((horizontal && (twipsPerPixel >= aBorder.height)) ||
+ (!horizontal && (twipsPerPixel >= aBorder.width))) {
+ // a one pixel border
+ DrawSolidBorderSegment(aContext, aBorder, twipsPerPixel, aStartBevelSide, aStartBevelOffset,
+ aEndBevelSide, aEndBevelOffset);
+ }
+ else {
+ nscoord startBevel = (aStartBevelOffset > 0)
+ ? RoundFloatToPixel(0.5f * (float)aStartBevelOffset, twipsPerPixel, PR_TRUE) : 0;
+ nscoord endBevel = (aEndBevelOffset > 0)
+ ? RoundFloatToPixel(0.5f * (float)aEndBevelOffset, twipsPerPixel, PR_TRUE) : 0;
+ PRUint8 ridgeGrooveSide = (horizontal) ? NS_SIDE_TOP : NS_SIDE_LEFT;
+ aContext.SetColor (
+ MakeBevelColor (ridgeGrooveSide, ridgeGroove, aBGColor->mBackgroundColor, aBorderColor, PR_TRUE));
+ nsRect rect(aBorder);
+ nscoord half;
+ if (horizontal) { // top, bottom
+ half = RoundFloatToPixel(0.5f * (float)aBorder.height, twipsPerPixel);
+ rect.height = half;
+ if (NS_SIDE_TOP == aStartBevelSide) {
+ rect.x += startBevel;
+ rect.width -= startBevel;
+ }
+ if (NS_SIDE_TOP == aEndBevelSide) {
+ rect.width -= endBevel;
+ }
+ DrawSolidBorderSegment(aContext, rect, twipsPerPixel, aStartBevelSide,
+ startBevel, aEndBevelSide, endBevel);
+ }
+ else { // left, right
+ half = RoundFloatToPixel(0.5f * (float)aBorder.width, twipsPerPixel);
+ rect.width = half;
+ if (NS_SIDE_LEFT == aStartBevelSide) {
+ rect.y += startBevel;
+ rect.height -= startBevel;
+ }
+ if (NS_SIDE_LEFT == aEndBevelSide) {
+ rect.height -= endBevel;
+ }
+ DrawSolidBorderSegment(aContext, rect, twipsPerPixel, aStartBevelSide,
+ startBevel, aEndBevelSide, endBevel);
+ }
+
+ rect = aBorder;
+ ridgeGrooveSide = (NS_SIDE_TOP == ridgeGrooveSide) ? NS_SIDE_BOTTOM : NS_SIDE_RIGHT;
+ aContext.SetColor (
+ MakeBevelColor (ridgeGrooveSide, ridgeGroove, aBGColor->mBackgroundColor, aBorderColor, PR_TRUE));
+ if (horizontal) {
+ rect.y = rect.y + half;
+ rect.height = aBorder.height - half;
+ if (NS_SIDE_BOTTOM == aStartBevelSide) {
+ rect.x += startBevel;
+ rect.width -= startBevel;
+ }
+ if (NS_SIDE_BOTTOM == aEndBevelSide) {
+ rect.width -= endBevel;
+ }
+ DrawSolidBorderSegment(aContext, rect, twipsPerPixel, aStartBevelSide,
+ startBevel, aEndBevelSide, endBevel);
+ }
+ else {
+ rect.x = rect.x + half;
+ rect.width = aBorder.width - half;
+ if (NS_SIDE_RIGHT == aStartBevelSide) {
+ rect.y += aStartBevelOffset - startBevel;
+ rect.height -= startBevel;
+ }
+ if (NS_SIDE_RIGHT == aEndBevelSide) {
+ rect.height -= endBevel;
+ }
+ DrawSolidBorderSegment(aContext, rect, twipsPerPixel, aStartBevelSide,
+ startBevel, aEndBevelSide, endBevel);
+ }
+ }
+ break;
+ case NS_STYLE_BORDER_STYLE_DOUBLE:
+ if ((aBorder.width > 2) && (aBorder.height > 2)) {
+ nscoord startBevel = (aStartBevelOffset > 0)
+ ? RoundFloatToPixel(0.333333f * (float)aStartBevelOffset, twipsPerPixel) : 0;
+ nscoord endBevel = (aEndBevelOffset > 0)
+ ? RoundFloatToPixel(0.333333f * (float)aEndBevelOffset, twipsPerPixel) : 0;
+ if (horizontal) { // top, bottom
+ nscoord thirdHeight = RoundFloatToPixel(0.333333f * (float)aBorder.height, twipsPerPixel);
+
+ // draw the top line or rect
+ nsRect topRect(aBorder.x, aBorder.y, aBorder.width, thirdHeight);
+ if (NS_SIDE_TOP == aStartBevelSide) {
+ topRect.x += aStartBevelOffset - startBevel;
+ topRect.width -= aStartBevelOffset - startBevel;
+ }
+ if (NS_SIDE_TOP == aEndBevelSide) {
+ topRect.width -= aEndBevelOffset - endBevel;
+ }
+ DrawSolidBorderSegment(aContext, topRect, twipsPerPixel, aStartBevelSide,
+ startBevel, aEndBevelSide, endBevel);
+
+ // draw the botom line or rect
+ nscoord heightOffset = aBorder.height - thirdHeight;
+ nsRect bottomRect(aBorder.x, aBorder.y + heightOffset, aBorder.width, aBorder.height - heightOffset);
+ if (NS_SIDE_BOTTOM == aStartBevelSide) {
+ bottomRect.x += aStartBevelOffset - startBevel;
+ bottomRect.width -= aStartBevelOffset - startBevel;
+ }
+ if (NS_SIDE_BOTTOM == aEndBevelSide) {
+ bottomRect.width -= aEndBevelOffset - endBevel;
+ }
+ DrawSolidBorderSegment(aContext, bottomRect, twipsPerPixel, aStartBevelSide,
+ startBevel, aEndBevelSide, endBevel);
+ }
+ else { // left, right
+ nscoord thirdWidth = RoundFloatToPixel(0.333333f * (float)aBorder.width, twipsPerPixel);
+
+ nsRect leftRect(aBorder.x, aBorder.y, thirdWidth, aBorder.height);
+ if (NS_SIDE_LEFT == aStartBevelSide) {
+ leftRect.y += aStartBevelOffset - startBevel;
+ leftRect.height -= aStartBevelOffset - startBevel;
+ }
+ if (NS_SIDE_LEFT == aEndBevelSide) {
+ leftRect.height -= aEndBevelOffset - endBevel;
+ }
+ DrawSolidBorderSegment(aContext, leftRect, twipsPerPixel, aStartBevelSide,
+ startBevel, aEndBevelSide, endBevel);
+
+ nscoord widthOffset = aBorder.width - thirdWidth;
+ nsRect rightRect(aBorder.x + widthOffset, aBorder.y, aBorder.width - widthOffset, aBorder.height);
+ if (NS_SIDE_RIGHT == aStartBevelSide) {
+ rightRect.y += aStartBevelOffset - startBevel;
+ rightRect.height -= aStartBevelOffset - startBevel;
+ }
+ if (NS_SIDE_RIGHT == aEndBevelSide) {
+ rightRect.height -= aEndBevelOffset - endBevel;
+ }
+ DrawSolidBorderSegment(aContext, rightRect, twipsPerPixel, aStartBevelSide,
+ startBevel, aEndBevelSide, endBevel);
+ }
+ break;
+ }
+ // else fall through to solid
+ case NS_STYLE_BORDER_STYLE_SOLID:
+ DrawSolidBorderSegment(aContext, aBorder, twipsPerPixel, aStartBevelSide,
+ aStartBevelOffset, aEndBevelSide, aEndBevelOffset);
+ break;
+ case NS_STYLE_BORDER_STYLE_BG_OUTSET:
+ case NS_STYLE_BORDER_STYLE_BG_INSET:
+ case NS_STYLE_BORDER_STYLE_OUTSET:
+ case NS_STYLE_BORDER_STYLE_INSET:
+ NS_ASSERTION(PR_FALSE, "inset, outset should have been converted to groove, ridge");
+ break;
+ }
+}
+
+// End table border-collapsing section
+
diff --git a/mozilla/layout/html/style/src/nsCSSRendering.h b/mozilla/layout/html/style/src/nsCSSRendering.h
index 2e8282b0adb..360cdd17d88 100644
--- a/mozilla/layout/html/style/src/nsCSSRendering.h
+++ b/mozilla/layout/html/style/src/nsCSSRendering.h
@@ -180,6 +180,17 @@ public:
PRIntn aSkipSides,
nsRect* aGap);
+ // Draw a border segment in the table collapsing border model without beveling corners
+ static void DrawTableBorderSegment(nsIRenderingContext& aContext,
+ PRUint8 aBorderStyle,
+ nscolor aBorderColor,
+ const nsStyleBackground* aBGColor,
+ const nsRect& aBorderRect,
+ float aPixelsToTwips,
+ PRUint8 aStartBevelSide = 0,
+ nscoord aStartBevelOffset = 0,
+ PRUint8 aEndBevelSide = 0,
+ nscoord aEndBevelOffset = 0);
/**
* transform a color to a color that will show up on a printer if needed
* aMapColor - color to evaluate
diff --git a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp
index 479cc30158f..b79d4379a67 100644
--- a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp
+++ b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.cpp
@@ -139,7 +139,7 @@ PRBool BasicTableLayoutStrategy::Initialize(nsIPresContext* aPresContex
nscoord minWidth, prefWidth;
mTableFrame->CalcMinAndPreferredWidths(aPresContext, aReflowState, PR_FALSE, minWidth, prefWidth);
if (hasPctCol && mTableFrame->IsAutoWidth()) {
- prefWidth = CalcPctAdjTableWidth(aReflowState, boxWidth, p2t);
+ prefWidth = CalcPctAdjTableWidth(*aPresContext, aReflowState, boxWidth, p2t);
}
// calc the desired width, considering if there is a specified width.
// don't use nsTableFrame::CalcDesiredWidth because it is based on table column widths.
@@ -195,7 +195,7 @@ ResetPctValues(nsTableFrame* aTableFrame,
// initialize the col percent and cell percent values to 0.
PRInt32 colX;
for (colX = 0; colX < aNumCols; colX++) {
- nsTableColFrame* colFrame = aTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = aTableFrame->GetColFrame(colX); if (!colFrame) ABORT0();
if (colFrame) {
colFrame->SetWidth(PCT, WIDTH_NOT_SET);
colFrame->SetWidth(PCT_ADJ, WIDTH_NOT_SET);
@@ -207,6 +207,7 @@ PRBool
BasicTableLayoutStrategy::BalanceColumnWidths(nsIPresContext* aPresContext,
const nsHTMLReflowState& aReflowState)
{
+ if (!aPresContext) ABORT1(PR_FALSE);
#ifdef DEBUG_TABLE_STRATEGY
printf("BalanceColumnWidths en count=%d \n", gsDebugCount++); mTableFrame->Dump(aPresContext, PR_FALSE, PR_TRUE, PR_FALSE);
#endif
@@ -220,8 +221,16 @@ BasicTableLayoutStrategy::BalanceColumnWidths(nsIPresContext* aPresCont
PRInt32 numCols = mTableFrame->GetColCount();
PRBool tableIsAutoWidth = mTableFrame->IsAutoWidth();
- nscoord horBorderPadding = aReflowState.mComputedBorderPadding.left +
- aReflowState.mComputedBorderPadding.right;
+
+ nscoord horOffset;
+ // get the reduction in available horizontal space due to borders and padding
+ if (mTableFrame->IsBorderCollapse()) {
+ nsMargin offset = mTableFrame->GetChildAreaOffset(*aPresContext, &aReflowState);
+ horOffset = offset.left + offset.right;
+ }
+ else {
+ horOffset = aReflowState.mComputedBorderPadding.left + aReflowState.mComputedBorderPadding.right;
+ }
// determine if the table is auto/fixed and get the fixed width if available
nscoord maxWidth = mTableFrame->CalcBorderBoxWidth(aPresContext, aReflowState);
@@ -238,19 +247,19 @@ BasicTableLayoutStrategy::BalanceColumnWidths(nsIPresContext* aPresCont
// An auto table returns a new table width based on percent cells/cols if they exist
nscoord perAdjTableWidth = 0;
if (mTableFrame->HasPctCol()) {
- perAdjTableWidth = AssignPctColumnWidths(aReflowState, maxWidth, tableIsAutoWidth, p2t);
+ perAdjTableWidth = AssignPctColumnWidths(*aPresContext, aReflowState, maxWidth, tableIsAutoWidth, p2t);
if (perAdjTableWidth > 0) {
// if an auto table has a pct col or cell, set the preferred table width
// here so that CalcPctAdjTableWidth wont't need to be called by the table
mTableFrame->SetPreferredWidth(perAdjTableWidth);
}
perAdjTableWidth = PR_MIN(perAdjTableWidth, maxWidth);
- perAdjTableWidth -= horBorderPadding;
+ perAdjTableWidth -= horOffset;
perAdjTableWidth = PR_MAX(perAdjTableWidth, 0);
}
// reduce the maxWidth by border and padding, since we will be dealing with content width
- maxWidth -= horBorderPadding;
+ maxWidth -= horOffset;
maxWidth = PR_MAX(0, maxWidth);
PRInt32 numNonZeroWidthCols = 0;
@@ -258,7 +267,7 @@ BasicTableLayoutStrategy::BalanceColumnWidths(nsIPresContext* aPresCont
nscoord minTableWidth = 0;
PRInt32 colX;
for (colX = 0; colX < numCols; colX++) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) ABORT1(PR_FALSE);
if (!colFrame) continue;
nscoord colMinWidth = colFrame->GetMinWidth();
mTableFrame->SetColumnWidth(colX, colMinWidth);
@@ -400,7 +409,7 @@ void BasicTableLayoutStrategy::AllocateFully(nscoord& aTotalAllocated,
{
PRInt32 numCols = mTableFrame->GetColCount();
for (PRInt32 colX = 0; colX < numCols; colX++) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) ABORT0();
if (!colFrame) continue;
if (!CanAllocate(aWidthType, aAllocTypes[colX], colFrame)) {
continue;
@@ -454,7 +463,7 @@ void BasicTableLayoutStrategy::AllocateUnconstrained(PRInt32 aAllocAmount,
}
else {
if (aExclude0Pro) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) ABORT0();
if (colFrame->GetConstraint() == e0ProportionConstraint) {
aAllocTypes[colX] = FINISHED;
}
@@ -467,7 +476,7 @@ void BasicTableLayoutStrategy::AllocateUnconstrained(PRInt32 aAllocAmount,
PRInt32 numColsAllocated = 0;
PRInt32 totalAllocated = 0;
for (colX = 0; colX < numCols; colX++) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) ABORT0();
PRBool skipColumn = aExclude0Pro && (e0ProportionConstraint == colFrame->GetConstraint());
if (FINISHED != aAllocTypes[colX] && !skipColumn ) {
divisor += mTableFrame->GetColumnWidth(colX);
@@ -477,7 +486,7 @@ void BasicTableLayoutStrategy::AllocateUnconstrained(PRInt32 aAllocAmount,
for (colX = 0; colX < numCols; colX++) {
if (FINISHED != aAllocTypes[colX]) {
if (aExclude0Pro) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) ABORT0();
if (colFrame && (e0ProportionConstraint == colFrame->GetConstraint())) {
continue;
}
@@ -533,7 +542,7 @@ BasicTableLayoutStrategy::ComputeNonPctColspanWidths(const nsHTMLReflowState& aR
PRInt32 colX;
for (colX = numCols - 1; colX >= 0; colX--) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) ABORT0();
if (!colFrame) continue;
colFrame->SetWidth(MIN_ADJ, WIDTH_NOT_SET);
colFrame->SetWidth(FIX_ADJ, WIDTH_NOT_SET);
@@ -698,7 +707,7 @@ BasicTableLayoutStrategy::ComputeNonPctColspanWidths(PRInt32 aWidthInd
PRInt32 spanX;
// accumulate the various divisors to be used later
for (spanX = 0; spanX < aColSpan; spanX++) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(aColIndex + spanX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(aColIndex + spanX); if (!colFrame) ABORT1(PR_FALSE);
if (!colFrame) continue;
nscoord minWidth = PR_MAX(colFrame->GetMinWidth(), 0);
nscoord pctWidth = PR_MAX(colFrame->GetPctWidth(), 0);
@@ -802,7 +811,7 @@ BasicTableLayoutStrategy::ComputeNonPctColspanWidths(PRInt32 aWidthInd
// get the correct numerator in a similar fashion to getting the divisor
for (spanX = 0; spanX < aColSpan; spanX++) {
if (usedWidth >= availWidth) break;
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(aColIndex + spanX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(aColIndex + spanX); if (!colFrame) ABORT1(PR_FALSE);
if (!colFrame) continue;
nscoord minWidth = colFrame->GetMinWidth();
nscoord pctWidth = PR_MAX(colFrame->GetPctWidth(), 0);
@@ -974,7 +983,7 @@ BasicTableLayoutStrategy::AssignNonPctColumnWidths(nsIPresContext* aPre
nscoord fixWidth = WIDTH_NOT_SET;
// Get column frame and reset it
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) ABORT1(PR_FALSE);
if (!colFrame) continue;
NS_ASSERTION(nsnull != colFrame, "bad col frame");
colFrame->ResetSizingInfo();
@@ -1079,7 +1088,7 @@ BasicTableLayoutStrategy::AssignNonPctColumnWidths(nsIPresContext* aPre
}
//set the table col fixed width if present
for (colX = 0; colX < numCols; colX++) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) ABORT1(PR_FALSE);
if (!colFrame) continue;
nscoord fixColWidth = colFrame->GetWidth(FIX);
// use the style width of a col only if the col hasn't gotten a fixed width from any cell
@@ -1140,7 +1149,7 @@ BasicTableLayoutStrategy::AssignNonPctColumnWidths(nsIPresContext* aPre
// Set the table col width for each col to the content min.
for (colX = 0; colX < numCols; colX++) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) ABORT1(PR_FALSE);
nscoord minWidth = colFrame->GetMinWidth();
mTableFrame->SetColumnWidth(colX, minWidth);
}
@@ -1159,7 +1168,7 @@ BasicTableLayoutStrategy::ReduceOverSpecifiedPctCols(nscoord aExcess)
{
nscoord numCols = mTableFrame->GetColCount();
for (PRInt32 colX = numCols - 1; (colX >= 0) && (aExcess > 0); colX--) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) ABORT0();
if (!colFrame) continue;
nscoord pctWidth = colFrame->GetWidth(PCT);
nscoord reduction = 0;
@@ -1198,7 +1207,8 @@ inline nscoord WrapupAssignPctColumnWidths(nsTableFrame* aTableFrame,
#endif
nscoord
-BasicTableLayoutStrategy::CalcPctAdjTableWidth(const nsHTMLReflowState& aReflowState,
+BasicTableLayoutStrategy::CalcPctAdjTableWidth(nsIPresContext& aPresContext,
+ const nsHTMLReflowState& aReflowState,
nscoord aAvailWidthIn,
float aPixelToTwips)
{
@@ -1219,7 +1229,7 @@ BasicTableLayoutStrategy::CalcPctAdjTableWidth(const nsHTMLReflowState& aReflowS
rawPctValues[colX] = 0.0f;
}
- nsMargin borderPadding = mTableFrame->GetBorderPadding(aReflowState);
+ nsMargin borderPadding = mTableFrame->GetContentAreaOffset(aPresContext, &aReflowState);
nscoord availWidth = aAvailWidthIn;
if (NS_UNCONSTRAINEDSIZE != availWidth) {
// adjust the avail width to exclude table border, padding and cell spacing
@@ -1227,7 +1237,7 @@ BasicTableLayoutStrategy::CalcPctAdjTableWidth(const nsHTMLReflowState& aReflowS
}
for (colX = 0; colX < numCols; colX++) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) ABORT1(0);
if (!colFrame) continue;
nscoord maxColBasis = -1;
// Scan the cells in the col
@@ -1282,7 +1292,7 @@ BasicTableLayoutStrategy::CalcPctAdjTableWidth(const nsHTMLReflowState& aReflowS
nscoord fixDesTotalNoPct = 0; // total of fix or des widths of cols without pct
for (colX = 0; colX < numCols; colX++) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) ABORT1(0);
nscoord fixWidth = colFrame->GetFixWidth();
nscoord fixDesWidth = (fixWidth > 0) ? fixWidth : colFrame->GetDesWidth();
fixDesTotal += fixDesWidth;
@@ -1329,7 +1339,8 @@ BasicTableLayoutStrategy::CalcPctAdjTableWidth(const nsHTMLReflowState& aReflowS
// Determine percentage col widths for each col frame
nscoord
-BasicTableLayoutStrategy::AssignPctColumnWidths(const nsHTMLReflowState& aReflowState,
+BasicTableLayoutStrategy::AssignPctColumnWidths(nsIPresContext& aPresContext,
+ const nsHTMLReflowState& aReflowState,
nscoord aAvailWidth,
PRBool aTableIsAutoWidth,
float aPixelToTwips)
@@ -1349,11 +1360,11 @@ BasicTableLayoutStrategy::AssignPctColumnWidths(const nsHTMLReflowState& aReflow
// on percent cells/cols. This probably should only be a NavQuirks thing, since
// a percentage based cell or column on an auto table should force the column to auto
nscoord basis = (aTableIsAutoWidth)
- ? CalcPctAdjTableWidth(aReflowState, aAvailWidth, aPixelToTwips)
+ ? CalcPctAdjTableWidth(aPresContext, aReflowState, aAvailWidth, aPixelToTwips)
: aAvailWidth;
// adjust the basis to exclude table border, padding and cell spacing
- nsMargin borderPadding = mTableFrame->GetBorderPadding(aReflowState);
+ nsMargin borderPadding = mTableFrame->GetContentAreaOffset(aPresContext, &aReflowState);
basis -= borderPadding.left + borderPadding.right + mCellSpacingTotal;
nscoord colPctTotal = 0;
@@ -1361,7 +1372,7 @@ BasicTableLayoutStrategy::AssignPctColumnWidths(const nsHTMLReflowState& aReflow
// Determine the percentage contribution for cols and for cells with colspan = 1
// Iterate backwards, similarly to the reasoning in AssignNonPctColumnWidths
for (colX = numCols - 1; colX >= 0; colX--) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) ABORT1(0);
if (!colFrame) continue;
nscoord maxColPctWidth = WIDTH_NOT_SET;
float maxColPct = 0.0f;
@@ -1431,7 +1442,7 @@ BasicTableLayoutStrategy::AssignPctColumnWidths(const nsHTMLReflowState& aReflow
}
// determine if the cell spans cols which have a pct value
for (PRInt32 spanX = 0; (spanX < colSpan) && !done; spanX++) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX + spanX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX + spanX); if (!colFrame) ABORT1(0);
if (!colFrame) continue;
if (colFrame->GetWidth(PCT) > 0) {
mTableFrame->SetHasCellSpanningPctCol(PR_TRUE);
@@ -1511,7 +1522,7 @@ BasicTableLayoutStrategy::AssignPctColumnWidths(const nsHTMLReflowState& aReflow
// accumulate the spanTotal as the max of MIN, DES, FIX, PCT
PRInt32 spanX;
for (spanX = 0; spanX < colSpan; spanX++) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX + spanX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX + spanX); if (!colFrame) ABORT1(0);
if (!colFrame) continue;
nscoord colPctWidth = colFrame->GetWidth(PCT);
if (colPctWidth > 0) { // skip pct cols
@@ -1546,7 +1557,7 @@ BasicTableLayoutStrategy::AssignPctColumnWidths(const nsHTMLReflowState& aReflow
// record the percent contributions for the spanned cols
PRInt32 usedColumns = colSpan;
for (spanX = colSpan-1; spanX >= 0; spanX--) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX + spanX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX + spanX); if (!colFrame) ABORT1(0);
if (!colFrame) continue;
if ((colFrame->GetWidth(PCT) > 0) || (canSkipPctAdj && (colFrame->GetWidth(PCT_ADJ) > 0))) {
// dont use pct cols or if we can skip the pct adj event do not take the PCT_ADJ cols
@@ -1621,7 +1632,7 @@ void BasicTableLayoutStrategy::CalculateTotals(PRInt32* aTotalCounts,
PRInt32 colX;
for (colX = 0; colX < numEffCols; colX++) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) ABORT0();
if (!colFrame) continue;
nscoord minCol = colFrame->GetMinWidth();
aTotalCounts[MIN_CON]++;
@@ -1820,7 +1831,7 @@ void BasicTableLayoutStrategy::AllocateConstrained(PRInt32 aAvailWidth,
PRInt32 colX;
// find out how many constrained cols there are
for (colX = 0; colX < numCols; colX++) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) ABORT0();
if (!colFrame) continue;
if (!CanAllocate(aWidthType, aAllocTypes[colX], colFrame)) {
continue;
@@ -1837,7 +1848,7 @@ void BasicTableLayoutStrategy::AllocateConstrained(PRInt32 aAvailWidth,
PRInt32 constrColX = 0;
// set the col info entries for each constrained col
for (colX = 0; colX < numCols; colX++) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) ABORT0();
if (!colFrame) continue;
if (!CanAllocate(aWidthType, aAllocTypes[colX], colFrame)) {
continue;
diff --git a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.h b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.h
index 793b8b79d40..69883aabd2c 100644
--- a/mozilla/layout/html/table/src/BasicTableLayoutStrategy.h
+++ b/mozilla/layout/html/table/src/BasicTableLayoutStrategy.h
@@ -93,7 +93,8 @@ public:
* @param aPixelToTwips - the number of twips in a pixel.
* @return - the basis for percent calculations
*/
- virtual nscoord CalcPctAdjTableWidth(const nsHTMLReflowState& aReflowState,
+ virtual nscoord CalcPctAdjTableWidth(nsIPresContext& aPresContext,
+ const nsHTMLReflowState& aReflowState,
nscoord aAvailWidth,
float aPixelToTwips);
void Dump(PRInt32 aIndent);
@@ -159,7 +160,8 @@ protected:
* @param aPixelToTwips - the number of twips in a pixel.
* @return - the adjusted basis including table border, padding and cell spacing
*/
- nscoord AssignPctColumnWidths(const nsHTMLReflowState& aReflowState,
+ nscoord AssignPctColumnWidths(nsIPresContext& aPresContext,
+ const nsHTMLReflowState& aReflowState,
nscoord aBasis,
PRBool aTableIsAutoWidth,
float aPixelToTwips);
diff --git a/mozilla/layout/html/table/src/celldata.h b/mozilla/layout/html/table/src/celldata.h
index cf977be70d6..b281df0e2e2 100644
--- a/mozilla/layout/html/table/src/celldata.h
+++ b/mozilla/layout/html/table/src/celldata.h
@@ -38,6 +38,7 @@
#define CellData_h__
#include "nsISupports.h"
+#include "nsCoord.h"
class nsTableCellFrame;
@@ -51,8 +52,9 @@ public:
~CellData();
+ void Init(nsTableCellFrame* aCellFrame);
PRBool IsOrig() const;
-
+ PRBool IsDead() const;
PRBool IsSpan() const;
PRBool IsRowSpan() const;
@@ -84,6 +86,93 @@ protected:
};
};
+// 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
+};
+
+// 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 64
+#define MAX_CORNER_SUB_WIDTH 128
+
+// BCData stores the top and left border info and the corner connecting the two.
+class BCData
+{
+public:
+ BCData();
+
+ ~BCData();
+
+ nscoord GetLeftEdge(BCBorderOwner& aOwner,
+ PRBool& aStart) const;
+
+ void SetLeftEdge(BCBorderOwner aOwner,
+ nscoord aSize,
+ PRBool aStart);
+
+ nscoord GetTopEdge(BCBorderOwner& aOwner,
+ PRBool& aStart) const;
+
+ void SetTopEdge(BCBorderOwner aOwner,
+ nscoord aSize,
+ PRBool aStart);
+
+ PRUint8 GetCorner(PRUint8& aCornerOwner,
+ PRPackedBool& aBevel) const;
+
+ void SetCorner(PRUint8 aOwner,
+ PRUint8 aSubSize,
+ PRBool aBevel);
+
+ PRBool IsLeftStart() const;
+
+ void SetLeftStart(PRBool aValue);
+
+ PRBool IsTopStart() const;
+
+ void SetTopStart(PRBool aValue);
+
+
+protected:
+ unsigned mLeftOwner: 4; // owner of left border
+ unsigned mLeftSize: 6; // size in pixels of left border
+ unsigned mLeftStart: 1; // set if this is the start of a vertical border segment
+ unsigned mCornerSide: 2; // side of the owner of the upper left corner relative to the corner
+ unsigned mCornerSubSize: 7; // size of the largest border not in the dominate 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 mCornerBevel: 1; // is the corner beveled (only two segments, perpendicular, not dashed or dotted).
+ unsigned mTopOwner: 4; // owner of top border
+ unsigned mTopSize: 6; // size in pixels of top border
+ unsigned mTopStart: 1; // set if this is the start of a horizontal border segment
+};
+
+// 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;
+};
+
+
#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
@@ -103,9 +192,19 @@ inline nsTableCellFrame* CellData::GetCellFrame() const
return nsnull;
}
+inline void CellData::Init(nsTableCellFrame* aCellFrame)
+{
+ mOrigCell = aCellFrame;
+}
+
inline PRBool CellData::IsOrig() const
{
- return (SPAN != (SPAN & mBits));
+ return ((nsnull != mOrigCell) && (SPAN != (SPAN & mBits)));
+}
+
+inline PRBool CellData::IsDead() const
+{
+ return (0 == mBits);
}
inline PRBool CellData::IsSpan() const
@@ -213,4 +312,88 @@ inline void CellData::SetOverlap(PRBool aOverlap)
}
}
+inline BCData::BCData()
+{
+ mLeftOwner = mTopOwner = eCellOwner;
+ mLeftStart = mTopStart = 1;
+ mLeftSize = mCornerSide = mCornerSubSize = mTopSize = 0;
+}
+
+inline BCData::~BCData()
+{
+}
+
+inline nscoord BCData::GetLeftEdge(BCBorderOwner& aOwner,
+ PRBool& aStart) const
+{
+ aOwner = (BCBorderOwner)mLeftOwner;
+ aStart = (PRBool)mLeftStart;
+
+ return (nscoord)mLeftSize;
+}
+
+inline void BCData::SetLeftEdge(BCBorderOwner aOwner,
+ nscoord aSize,
+ PRBool aStart)
+{
+ mLeftOwner = aOwner;
+ mLeftSize = (aSize > MAX_BORDER_WIDTH) ? MAX_BORDER_WIDTH : aSize;
+ mLeftStart = aStart;
+}
+
+inline nscoord BCData::GetTopEdge(BCBorderOwner& aOwner,
+ PRBool& aStart) const
+{
+ aOwner = (BCBorderOwner)mTopOwner;
+ aStart = (PRBool)mTopStart;
+
+ return (nscoord)mTopSize;
+}
+
+inline void BCData::SetTopEdge(BCBorderOwner aOwner,
+ nscoord aSize,
+ PRBool aStart)
+{
+ mTopOwner = aOwner;
+ mTopSize = (aSize > MAX_BORDER_WIDTH) ? MAX_BORDER_WIDTH : aSize;
+ mTopStart = aStart;
+}
+
+inline PRUint8 BCData::GetCorner(PRUint8& aOwnerSide,
+ PRPackedBool& aBevel) const
+{
+ aOwnerSide = mCornerSide;
+ aBevel = (PRBool)mCornerBevel;
+ return (PRUint8)mCornerSubSize;
+}
+
+inline void BCData::SetCorner(PRUint8 aSubSize,
+ PRUint8 aOwnerSide,
+ PRBool aBevel)
+{
+ mCornerSubSize = (aSubSize > MAX_CORNER_SUB_WIDTH) ? MAX_CORNER_SUB_WIDTH : aSubSize;
+ mCornerSide = aOwnerSide;
+ mCornerBevel = aBevel;
+}
+
+inline PRBool BCData::IsLeftStart() const
+{
+ return (PRBool)mLeftStart;
+}
+
+inline void BCData::SetLeftStart(PRBool aValue)
+{
+ mLeftStart = aValue;
+}
+
+inline PRBool BCData::IsTopStart() const
+{
+ return (PRBool)mTopStart;
+}
+
+inline void BCData::SetTopStart(PRBool aValue)
+{
+ mTopStart = aValue;
+}
+
#endif
diff --git a/mozilla/layout/html/table/src/nsCellMap.cpp b/mozilla/layout/html/table/src/nsCellMap.cpp
index 167268997e0..3b6a835cfe8 100644
--- a/mozilla/layout/html/table/src/nsCellMap.cpp
+++ b/mozilla/layout/html/table/src/nsCellMap.cpp
@@ -60,12 +60,25 @@ CellData::~CellData()
MOZ_COUNT_DTOR(CellData);
}
+BCCellData::BCCellData(nsTableCellFrame* aOrigCell)
+:CellData(aOrigCell)
+{
+ MOZ_COUNT_CTOR(BCCellData);
+}
+
+BCCellData::~BCCellData()
+{
+ MOZ_COUNT_DTOR(BCCellData);
+}
+
MOZ_DECL_CTOR_COUNTER(nsCellMap)
// nsTableCellMap
-nsTableCellMap::nsTableCellMap(nsIPresContext* aPresContext, nsTableFrame& aTableFrame)
-:mTableFrame(aTableFrame), mFirstMap(nsnull)
+nsTableCellMap::nsTableCellMap(nsIPresContext* aPresContext,
+ nsTableFrame& aTableFrame,
+ PRBool aBorderCollapse)
+:mTableFrame(aTableFrame), mFirstMap(nsnull), mBCInfo(nsnull)
{
MOZ_COUNT_CTOR(nsTableCellMap);
@@ -83,11 +96,17 @@ nsTableCellMap::nsTableCellMap(nsIPresContext* aPresContext, nsTableFrame& aTabl
InsertGroupCellMap(*rgFrame, prior);
}
}
+ if (aBorderCollapse) {
+ mBCInfo = new BCInfo();
+ }
}
nsTableCellMap::~nsTableCellMap()
{
MOZ_COUNT_DTOR(nsTableCellMap);
+
+ PRInt32 rowCount = GetRowCount();
+
nsCellMap* cellMap = mFirstMap;
while (cellMap) {
nsCellMap* next = cellMap->GetNextSibling();
@@ -95,15 +114,89 @@ nsTableCellMap::~nsTableCellMap()
cellMap = next;
}
- PRInt32 colCount = mCols.Count();
+ PRInt32 colCount = mCols.Count();
for (PRInt32 colX = 0; colX < colCount; colX++) {
nsColInfo* colInfo = (nsColInfo *)mCols.ElementAt(colX);
if (colInfo) {
delete colInfo;
}
}
+ if (mBCInfo) {
+ DeleteRightBottomBorders();
+ delete mBCInfo;
+ }
}
+// Get the bcData holding the border segments of the right edge of the table
+BCData*
+nsTableCellMap::GetRightMostBorder(PRInt32 aRowIndex)
+{
+ if (!mBCInfo) ABORT1(nsnull);
+
+ BCData* bcData;
+
+ PRInt32 numRows = mBCInfo->mRightBorders.Count();
+ if (aRowIndex < numRows) {
+ bcData = (BCData*)mBCInfo->mRightBorders.ElementAt(aRowIndex);
+ }
+ else {
+ for (PRInt32 rowX = numRows; rowX <= aRowIndex; rowX++) {
+ bcData = new BCData(); if (!bcData) ABORT1(nsnull);
+ mBCInfo->mRightBorders.AppendElement(bcData);
+ }
+ }
+ return bcData;
+}
+
+// Get the bcData holding the border segments of the bottom edge of the table
+BCData*
+nsTableCellMap::GetBottomMostBorder(PRInt32 aColIndex)
+{
+ if (!mBCInfo) ABORT1(nsnull);
+
+ BCData* bcData;
+
+ PRInt32 numCols = mBCInfo->mBottomBorders.Count();
+ if (aColIndex < numCols) {
+ bcData = (BCData*)mBCInfo->mBottomBorders.ElementAt(aColIndex);
+ }
+ else {
+ for (PRInt32 colX = numCols; colX <= aColIndex; colX++) {
+ bcData = new BCData(); if (!bcData) ABORT1(nsnull);
+ mBCInfo->mBottomBorders.AppendElement(bcData);
+ }
+ }
+ return bcData;
+}
+
+// delete the borders corresponding to the right and bottom edges of the table
+void
+nsTableCellMap::DeleteRightBottomBorders()
+{
+ if (mBCInfo) {
+ PRInt32 numCols = mBCInfo->mBottomBorders.Count();
+ if (numCols > 0) {
+ for (PRInt32 colX = numCols - 1; colX >= 0; colX--) {
+ BCData* bcData = (BCData*)mBCInfo->mBottomBorders.ElementAt(colX);
+ if (bcData) {
+ delete bcData;
+ }
+ mBCInfo->mBottomBorders.RemoveElementAt(colX);
+ }
+ }
+ PRUint32 numRows = mBCInfo->mRightBorders.Count();
+ if (numRows > 0) {
+ for (PRInt32 rowX = numRows - 1; rowX >= 0; rowX--) {
+ BCData* bcData = (BCData*)mBCInfo->mRightBorders.ElementAt(rowX);
+ if (bcData) {
+ delete bcData;
+ }
+ mBCInfo->mRightBorders.RemoveElementAt(rowX);
+ }
+ }
+ }
+}
+
void
nsTableCellMap::InsertGroupCellMap(nsCellMap* aPrevMap,
nsCellMap& aNewMap)
@@ -126,9 +219,11 @@ void nsTableCellMap::InsertGroupCellMap(nsTableRowGroupFrame& aNewGroup,
nsCellMap* newMap = new nsCellMap(aNewGroup);
if (newMap) {
nsCellMap* prevMap = nsnull;
+ nsCellMap* lastMap = mFirstMap;
if (aPrevGroup) {
nsCellMap* map = mFirstMap;
while (map) {
+ lastMap = map;
if (map->GetRowGroup() == aPrevGroup) {
prevMap = map;
break;
@@ -137,7 +232,13 @@ void nsTableCellMap::InsertGroupCellMap(nsTableRowGroupFrame& aNewGroup,
}
}
if (!prevMap) {
- aPrevGroup = nsnull;
+ if (aPrevGroup) {
+ prevMap = lastMap;
+ aPrevGroup = (prevMap) ? prevMap->GetRowGroup() : nsnull;
+ }
+ else {
+ aPrevGroup = nsnull;
+ }
}
InsertGroupCellMap(prevMap, *newMap);
}
@@ -164,6 +265,16 @@ void nsTableCellMap::RemoveGroupCellMap(nsTableRowGroupFrame* aGroup)
}
}
+nsCellMap*
+nsTableCellMap::GetMapFor(nsTableRowGroupFrame& aRowGroup)
+{
+ for (nsCellMap* map = mFirstMap; map; map = map->GetNextSibling()) {
+ if (&aRowGroup == map->GetRowGroup()) {
+ return map;
+ }
+ }
+ return nsnull;
+}
PRInt32
@@ -241,14 +352,15 @@ nsTableCellMap::GetRowCount() const
}
CellData*
-nsTableCellMap::GetCellAt(PRInt32 aRowIndex,
- PRInt32 aColIndex)
+nsTableCellMap::GetDataAt(PRInt32 aRowIndex,
+ PRInt32 aColIndex,
+ PRBool aUpdateZeroSpan)
{
PRInt32 rowIndex = aRowIndex;
nsCellMap* map = mFirstMap;
while (map) {
if (map->GetRowCount() > rowIndex) {
- return map->GetCellAt(*this, rowIndex, aColIndex);
+ return map->GetDataAt(*this, rowIndex, aColIndex, aUpdateZeroSpan);
}
rowIndex -= map->GetRowCount();
map = map->GetNextSibling();
@@ -268,6 +380,12 @@ nsTableCellMap::AddColsAtEnd(PRUint32 aNumCols)
if (colInfo) {
mCols.AppendElement(colInfo);
}
+ if (mBCInfo) {
+ BCData* bcData = new BCData();
+ if (bcData) {
+ mBCInfo->mBottomBorders.AppendElement(bcData);
+ }
+ }
}
}
@@ -283,6 +401,16 @@ nsTableCellMap::RemoveColsAtEnd()
if (colInfo) {
if ((colInfo->mNumCellsOrig <= 0) && (colInfo->mNumCellsSpan <= 0)) {
mCols.RemoveElementAt(colX);
+ if (mBCInfo) {
+ PRInt32 count = mBCInfo->mBottomBorders.Count();
+ if (colX < count) {
+ BCData* bcData = (BCData*)mBCInfo->mBottomBorders.ElementAt(colX);
+ if (bcData) {
+ delete bcData;
+ }
+ mBCInfo->mBottomBorders.RemoveElementAt(colX);
+ }
+ }
}
else break; // only remove until we encounter the 1st valid one
}
@@ -298,21 +426,44 @@ nsTableCellMap::InsertRows(nsIPresContext* aPresContext,
nsTableRowGroupFrame& aParent,
nsVoidArray& aRows,
PRInt32 aFirstRowIndex,
- PRBool aConsiderSpans)
+ PRBool aConsiderSpans,
+ nsRect& aDamageArea)
{
- NS_ASSERTION((aRows.Count() > 0) && (aFirstRowIndex >= 0), "nsTableCellMap::InsertRows called incorrectly");
+ PRInt32 numNewRows = aRows.Count();
+ if ((numNewRows <= 0) || (aFirstRowIndex < 0)) ABORT0();
+
PRInt32 rowIndex = aFirstRowIndex;
nsCellMap* cellMap = mFirstMap;
while (cellMap) {
- if (cellMap->GetRowGroup() == &aParent) {
- cellMap->InsertRows(aPresContext, *this, aRows, rowIndex, aConsiderSpans);
+ nsTableRowGroupFrame* rg = cellMap->GetRowGroup();
+ if (rg == &aParent) {
+ cellMap->InsertRows(aPresContext, *this, aRows, rowIndex, aConsiderSpans, aDamageArea);
+ aDamageArea.y = aFirstRowIndex;
+ aDamageArea.height = PR_MAX(0, GetRowCount() - aFirstRowIndex);
//Dump("after InsertRows");
+ if (mBCInfo) {
+ BCData* bcData;
+ PRInt32 count = mBCInfo->mRightBorders.Count();
+ if (aFirstRowIndex < count) {
+ for (PRInt32 rowX = aFirstRowIndex; rowX < aFirstRowIndex + numNewRows; rowX++) {
+ bcData = new BCData(); if (!bcData) ABORT0();
+ mBCInfo->mRightBorders.InsertElementAt(bcData, rowX);
+ }
+ }
+ else {
+ GetRightMostBorder(aFirstRowIndex); // this will create missing entries
+ for (PRInt32 rowX = aFirstRowIndex + 1; rowX < aFirstRowIndex + numNewRows; rowX++) {
+ bcData = new BCData(); if (!bcData) ABORT0();
+ mBCInfo->mRightBorders.AppendElement(bcData);
+ }
+ }
+ }
return;
}
rowIndex -= cellMap->GetRowCount();
cellMap = cellMap->GetNextSibling();
}
-
+
NS_ASSERTION(PR_FALSE, "Attempt to insert row into wrong map.");
}
@@ -320,13 +471,29 @@ void
nsTableCellMap::RemoveRows(nsIPresContext* aPresContext,
PRInt32 aFirstRowIndex,
PRInt32 aNumRowsToRemove,
- PRBool aConsiderSpans)
+ PRBool aConsiderSpans,
+ nsRect& aDamageArea)
{
PRInt32 rowIndex = aFirstRowIndex;
nsCellMap* cellMap = mFirstMap;
while (cellMap) {
if (cellMap->GetRowCount() > rowIndex) {
- cellMap->RemoveRows(aPresContext, *this, rowIndex, aNumRowsToRemove, aConsiderSpans);
+ cellMap->RemoveRows(aPresContext, *this, rowIndex, aNumRowsToRemove, aConsiderSpans, aDamageArea);
+ nsTableRowGroupFrame* rg = cellMap->GetRowGroup();
+ aDamageArea.y += (rg) ? rg->GetStartRowIndex() : 0;
+ aDamageArea.height = PR_MAX(0, GetRowCount() - aFirstRowIndex);
+ if (mBCInfo) {
+ BCData* bcData;
+ for (PRInt32 rowX = aFirstRowIndex + aNumRowsToRemove - 1; rowX >= aFirstRowIndex; rowX--) {
+ if (rowX < mBCInfo->mRightBorders.Count()) {
+ bcData = (BCData*)mBCInfo->mRightBorders.ElementAt(rowX);
+ if (bcData) {
+ delete bcData;
+ }
+ mBCInfo->mRightBorders.RemoveElementAt(rowX);
+ }
+ }
+ }
break;
}
rowIndex -= cellMap->GetRowCount();
@@ -344,7 +511,7 @@ nsTableCellMap::GetNumCellsOriginatingInRow(PRInt32 aRowIndex)
PRInt32 colIndex = 0;
do {
- cellData = GetCellAt(aRowIndex, colIndex);
+ cellData = GetDataAt(aRowIndex, colIndex);
if (cellData && cellData->GetCellFrame())
originCount++;
colIndex++;
@@ -353,10 +520,11 @@ nsTableCellMap::GetNumCellsOriginatingInRow(PRInt32 aRowIndex)
return originCount;
}
-PRInt32
+CellData*
nsTableCellMap::AppendCell(nsTableCellFrame& aCellFrame,
PRInt32 aRowIndex,
- PRBool aRebuildIfNecessary)
+ PRBool aRebuildIfNecessary,
+ nsRect& aDamageArea)
{
NS_ASSERTION(&aCellFrame == aCellFrame.GetFirstInFlow(), "invalid call on continuing frame");
nsIFrame* rgFrame = nsnull;
@@ -365,12 +533,14 @@ nsTableCellMap::AppendCell(nsTableCellFrame& aCellFrame,
rgFrame->GetParent(&rgFrame); // get the row group
if (!rgFrame) return 0;
- PRInt32 result = 0;
+ CellData* result = nsnull;
PRInt32 rowIndex = aRowIndex;
nsCellMap* cellMap = mFirstMap;
while (cellMap) {
if (cellMap->GetRowGroup() == rgFrame) {
- result = cellMap->AppendCell(*this, aCellFrame, rowIndex, aRebuildIfNecessary);
+ result = cellMap->AppendCell(*this, &aCellFrame, rowIndex, aRebuildIfNecessary, aDamageArea);
+ nsTableRowGroupFrame* rg = cellMap->GetRowGroup();
+ aDamageArea.y += (rg) ? rg->GetStartRowIndex() : 0;
break;
}
rowIndex -= cellMap->GetRowCount();
@@ -384,13 +554,17 @@ nsTableCellMap::AppendCell(nsTableCellFrame& aCellFrame,
void
nsTableCellMap::InsertCells(nsVoidArray& aCellFrames,
PRInt32 aRowIndex,
- PRInt32 aColIndexBefore)
+ PRInt32 aColIndexBefore,
+ nsRect& aDamageArea)
{
PRInt32 rowIndex = aRowIndex;
nsCellMap* cellMap = mFirstMap;
while (cellMap) {
if (cellMap->GetRowCount() > rowIndex) {
- cellMap->InsertCells(*this, aCellFrames, rowIndex, aColIndexBefore);
+ cellMap->InsertCells(*this, aCellFrames, rowIndex, aColIndexBefore, aDamageArea);
+ nsTableRowGroupFrame* rg = cellMap->GetRowGroup();
+ aDamageArea.y += (rg) ? rg->GetStartRowIndex() : 0;
+ aDamageArea.width = PR_MAX(0, GetColCount() - aColIndexBefore);
break;
}
rowIndex -= cellMap->GetRowCount();
@@ -402,15 +576,22 @@ nsTableCellMap::InsertCells(nsVoidArray& aCellFrames,
void
nsTableCellMap::RemoveCell(nsTableCellFrame* aCellFrame,
- PRInt32 aRowIndex)
+ PRInt32 aRowIndex,
+ nsRect& aDamageArea)
{
+ if (!aCellFrame) ABORT0();
NS_ASSERTION(aCellFrame == (nsTableCellFrame *)aCellFrame->GetFirstInFlow(),
"invalid call on continuing frame");
PRInt32 rowIndex = aRowIndex;
nsCellMap* cellMap = mFirstMap;
while (cellMap) {
if (cellMap->GetRowCount() > rowIndex) {
- cellMap->RemoveCell(*this, aCellFrame, rowIndex);
+ cellMap->RemoveCell(*this, aCellFrame, rowIndex, aDamageArea);
+ nsTableRowGroupFrame* rg = cellMap->GetRowGroup();
+ aDamageArea.y += (rg) ? rg->GetStartRowIndex() : 0;
+ PRInt32 colIndex;
+ aCellFrame->GetColIndex(colIndex);
+ aDamageArea.width = PR_MAX(0, GetColCount() - colIndex);
break;
}
rowIndex -= cellMap->GetRowCount();
@@ -448,7 +629,7 @@ nsTableCellMap::Dump(char* aString) const
}
nsCellMap* cellMap = mFirstMap;
while (cellMap) {
- cellMap->Dump();
+ cellMap->Dump(nsnull != mBCInfo);
cellMap = cellMap->GetNextSibling();
}
printf("***** END TABLE CELL MAP DUMP *****\n");
@@ -525,6 +706,237 @@ PRBool nsTableCellMap::ColHasSpanningCells(PRInt32 aColIndex)
return PR_FALSE;
}
+BCData*
+nsTableCellMap::GetBCData(PRUint8 aSide,
+ nsCellMap& aCellMap,
+ PRUint32 aRowIndex,
+ PRUint32 aColIndex,
+ PRBool aIsLowerRight)
+{
+ if (!mBCInfo || aIsLowerRight) ABORT1(nsnull);
+
+ BCCellData* cellData;
+ BCData* bcData = nsnull;
+
+ switch(aSide) {
+ case NS_SIDE_BOTTOM:
+ aRowIndex++;
+ case NS_SIDE_TOP:
+ cellData = (BCCellData*)aCellMap.GetDataAt(*this, aRowIndex, aColIndex, PR_FALSE);
+ if (cellData) {
+ bcData = &cellData->mData;
+ }
+ else {
+ NS_ASSERTION(aSide == NS_SIDE_BOTTOM, "program error");
+ // try the next row group
+ nsCellMap* cellMap = aCellMap.GetNextSibling();
+ if (cellMap) {
+ cellData = (BCCellData*)cellMap->GetDataAt(*this, aRowIndex, aColIndex, PR_FALSE);
+ if (cellData) {
+ bcData = &cellData->mData;
+ }
+ else {
+ BCData* bcData = GetBottomMostBorder(aColIndex);
+ }
+ }
+ }
+ break;
+ case NS_SIDE_RIGHT:
+ aColIndex++;
+ case NS_SIDE_LEFT:
+ cellData = (BCCellData*)aCellMap.GetDataAt(*this, aRowIndex, aColIndex, PR_FALSE);
+ if (cellData) {
+ bcData = &cellData->mData;
+ }
+ else {
+ NS_ASSERTION(aSide == NS_SIDE_RIGHT, "program error");
+ BCData* bcData = GetRightMostBorder(aRowIndex);
+ }
+ break;
+ }
+ return bcData;
+}
+
+// store the aSide border segment at coord = (aRowIndex, aColIndex). For top/left, store
+// the info at coord. For bottom/left store it at the adjacent location so that it is
+// top/left at that location. If the new location is at the right or bottom edge of the
+// table, then store it one of the special arrays (right most borders, bottom most borders).
+void
+nsTableCellMap::SetBCBorderEdge(PRUint8 aSide,
+ nsCellMap& aCellMap,
+ PRUint32 aCellMapStart,
+ PRUint32 aRowIndex,
+ PRUint32 aColIndex,
+ PRUint32 aLength,
+ BCBorderOwner aOwner,
+ nscoord aSize,
+ PRBool aChanged)
+{
+ if (!mBCInfo) ABORT0();
+ //if (aRowIndex >= 80) {
+ // NS_ASSERTION(PR_FALSE, "hello");
+ //}
+
+ BCCellData* cellData;
+ PRInt32 lastIndex, xIndex, yIndex;
+ PRInt32 xPos = aColIndex;
+ PRInt32 yPos = aRowIndex;
+ PRInt32 rgYPos = aRowIndex - aCellMapStart;
+ PRBool changed;
+
+ switch(aSide) {
+ case NS_SIDE_BOTTOM:
+ rgYPos++;
+ yPos++;
+ case NS_SIDE_TOP:
+ lastIndex = xPos + aLength - 1;
+ for (xIndex = xPos; xIndex <= lastIndex; xIndex++) {
+ changed = aChanged && (xIndex == xPos);
+ BCData* bcData = nsnull;
+ cellData = (BCCellData*)aCellMap.GetDataAt(*this, rgYPos, xIndex, PR_FALSE);
+ if (!cellData) {
+ PRInt32 numRgRows = aCellMap.GetRowCount();
+ if (yPos < numRgRows) { // add a dead cell data
+ nsRect damageArea;
+ cellData = (BCCellData*)aCellMap.AppendCell(*this, nsnull, rgYPos, PR_FALSE, damageArea); if (!cellData) ABORT0();
+ }
+ else {
+ NS_ASSERTION(aSide == NS_SIDE_BOTTOM, "program error");
+ // try the next non empty row group
+ nsCellMap* cellMap = aCellMap.GetNextSibling();
+ while (cellMap && (0 == cellMap->GetRowCount())) {
+ cellMap = cellMap->GetNextSibling();
+ }
+ if (cellMap) {
+ cellData = (BCCellData*)cellMap->GetDataAt(*this, 0, xIndex, PR_FALSE);
+ if (!cellData) { // add a dead cell
+ nsRect damageArea;
+ cellData = (BCCellData*)cellMap->AppendCell(*this, nsnull, 0, PR_FALSE, damageArea);
+ }
+ }
+ else { // must be at the end of the table
+ bcData = GetBottomMostBorder(xIndex);
+ }
+ }
+ }
+ if (!bcData && cellData) {
+ bcData = &cellData->mData;
+ }
+ if (bcData) {
+ bcData->SetTopEdge(aOwner, aSize, changed);
+ }
+ else NS_ASSERTION(PR_FALSE, "program error");
+ }
+ break;
+ case NS_SIDE_RIGHT:
+ xPos++;
+ case NS_SIDE_LEFT:
+ // since top, bottom borders were set, there should already be a cellData entry
+ lastIndex = rgYPos + aLength - 1;
+ for (yIndex = rgYPos; yIndex <= lastIndex; yIndex++) {
+ changed = aChanged && (yIndex == rgYPos);
+ cellData = (BCCellData*)aCellMap.GetDataAt(*this, yIndex, xPos, PR_FALSE);
+ if (cellData) {
+ cellData->mData.SetLeftEdge(aOwner, aSize, changed);
+ }
+ else {
+ NS_ASSERTION(aSide == NS_SIDE_RIGHT, "program error");
+ BCData* bcData = GetRightMostBorder(yIndex + aCellMapStart);
+ if (bcData) {
+ bcData->SetLeftEdge(aOwner, aSize, changed);
+ }
+ else NS_ASSERTION(PR_FALSE, "program error");
+ }
+ }
+ break;
+ }
+}
+
+// store corner info (aOwner, aSubSize, aBevel). For aCorner = eTopLeft, store the info at
+// (aRowIndex, aColIndex). For eTopRight, store it in the entry to the right where
+// it would be top left. For eBottomRight, store it in the entry to the bottom. etc.
+void
+nsTableCellMap::SetBCBorderCorner(Corner aCorner,
+ nsCellMap& aCellMap,
+ PRUint32 aCellMapStart,
+ PRUint32 aRowIndex,
+ PRUint32 aColIndex,
+ PRUint8 aOwner,
+ nscoord aSubSize,
+ PRBool aBevel,
+ PRBool aIsBottomRight)
+{
+ if (!mBCInfo) ABORT0();
+
+ if (aIsBottomRight) {
+ mBCInfo->mLowerRightCorner.SetCorner(aSubSize, aOwner, aBevel);
+ return;
+ }
+
+ PRInt32 xPos = aColIndex;
+ PRInt32 yPos = aRowIndex;
+ PRInt32 rgYPos = aRowIndex - aCellMapStart;
+
+ if (eTopRight == aCorner) {
+ xPos++;
+ }
+ else if (eBottomRight == aCorner) {
+ xPos++;
+ rgYPos++;
+ yPos++;
+ }
+ else if (eBottomLeft == aCorner) {
+ rgYPos++;
+ yPos++;
+ }
+
+ BCCellData* cellData = nsnull;
+ BCData* bcData = nsnull;
+ if (GetColCount() <= xPos) {
+ NS_ASSERTION(xPos == GetColCount(), "program error");
+ if (aIsBottomRight) { // at the bottom right corner
+ bcData = &mBCInfo->mLowerRightCorner;
+ }
+ else { // at the right edge of the table
+ bcData = GetRightMostBorder(yPos);
+ }
+ }
+ else {
+ cellData = (BCCellData*)aCellMap.GetDataAt(*this, rgYPos, xPos, PR_FALSE);
+ if (!cellData) {
+ PRInt32 numRgRows = aCellMap.GetRowCount();
+ if (yPos < numRgRows) { // add a dead cell data
+ nsRect damageArea;
+ cellData = (BCCellData*)aCellMap.AppendCell(*this, nsnull, rgYPos, PR_FALSE, damageArea);
+ }
+ else {
+ // try the next non empty row group
+ nsCellMap* cellMap = aCellMap.GetNextSibling();
+ while (cellMap && (0 == cellMap->GetRowCount())) {
+ cellMap = cellMap->GetNextSibling();
+ }
+ if (cellMap) {
+ cellData = (BCCellData*)cellMap->GetDataAt(*this, 0, xPos, PR_FALSE);
+ if (!cellData) { // add a dead cell
+ nsRect damageArea;
+ cellData = (BCCellData*)cellMap->AppendCell(*this, nsnull, 0, PR_FALSE, damageArea);
+ }
+ }
+ else { // must be a the bottom of the table
+ bcData = GetBottomMostBorder(xPos);
+ }
+ }
+ }
+ }
+ if (!bcData && cellData) {
+ bcData = &cellData->mData;
+ }
+ if (bcData) {
+ bcData->SetCorner(aSubSize, aOwner, aBevel);
+ }
+ else NS_ASSERTION(PR_FALSE, "program error");
+}
+
#ifdef DEBUG
void nsTableCellMap::SizeOf(nsISizeOfHandler* aHandler,
PRUint32* aResult) const
@@ -540,6 +952,7 @@ void nsTableCellMap::SizeOf(nsISizeOfHandler* aHandler,
mCols.SizeOf(aHandler, &voidArraySize);
sum += voidArraySize - sizeof(mCols);
+ // XXX need to so something for mBCInfo
*aResult = sum;
}
#endif
@@ -633,7 +1046,8 @@ nsCellMap::InsertRows(nsIPresContext* aPresContext,
nsTableCellMap& aMap,
nsVoidArray& aRows,
PRInt32 aFirstRowIndex,
- PRBool aConsiderSpans)
+ PRBool aConsiderSpans,
+ nsRect& aDamageArea)
{
PRInt32 numCols = aMap.GetColCount();
@@ -648,7 +1062,7 @@ nsCellMap::InsertRows(nsIPresContext* aPresContext,
}
if (!aConsiderSpans) {
- ExpandWithRows(aPresContext, aMap, aRows, aFirstRowIndex);
+ ExpandWithRows(aPresContext, aMap, aRows, aFirstRowIndex, aDamageArea);
return;
}
@@ -663,10 +1077,10 @@ nsCellMap::InsertRows(nsIPresContext* aPresContext,
}
if (spansCauseRebuild) {
- RebuildConsideringRows(aPresContext, aMap, aFirstRowIndex, &aRows);
+ RebuildConsideringRows(aPresContext, aMap, aFirstRowIndex, &aRows, 0, aDamageArea);
}
else {
- ExpandWithRows(aPresContext, aMap, aRows, aFirstRowIndex);
+ ExpandWithRows(aPresContext, aMap, aRows, aFirstRowIndex, aDamageArea);
}
}
@@ -675,7 +1089,8 @@ nsCellMap::RemoveRows(nsIPresContext* aPresContext,
nsTableCellMap& aMap,
PRInt32 aFirstRowIndex,
PRInt32 aNumRowsToRemove,
- PRBool aConsiderSpans)
+ PRBool aConsiderSpans,
+ nsRect& aDamageArea)
{
PRInt32 numRows = mRows.Count();
PRInt32 numCols = aMap.GetColCount();
@@ -684,7 +1099,7 @@ nsCellMap::RemoveRows(nsIPresContext* aPresContext,
return;
}
if (!aConsiderSpans) {
- ShrinkWithoutRows(aMap, aFirstRowIndex, aNumRowsToRemove);
+ ShrinkWithoutRows(aMap, aFirstRowIndex, aNumRowsToRemove, aDamageArea);
return;
}
PRInt32 endRowIndex = aFirstRowIndex + aNumRowsToRemove - 1;
@@ -696,50 +1111,70 @@ nsCellMap::RemoveRows(nsIPresContext* aPresContext,
0, numCols - 1);
if (spansCauseRebuild) {
- RebuildConsideringRows(aPresContext, aMap, aFirstRowIndex, nsnull, aNumRowsToRemove);
+ RebuildConsideringRows(aPresContext, aMap, aFirstRowIndex, nsnull, aNumRowsToRemove, aDamageArea);
}
else {
- ShrinkWithoutRows(aMap, aFirstRowIndex, aNumRowsToRemove);
+ ShrinkWithoutRows(aMap, aFirstRowIndex, aNumRowsToRemove, aDamageArea);
}
}
-PRInt32
+void
+SetDamageArea(PRInt32 aXOrigin,
+ PRInt32 aYOrigin,
+ PRInt32 aWidth,
+ PRInt32 aHeight,
+ nsRect& aDamageArea)
+{
+ aDamageArea.x = aXOrigin;
+ aDamageArea.y = aYOrigin;
+ aDamageArea.width = PR_MAX(1, aWidth);
+ aDamageArea.height = PR_MAX(1, aHeight);
+}
+
+
+CellData*
nsCellMap::AppendCell(nsTableCellMap& aMap,
- nsTableCellFrame& aCellFrame,
+ nsTableCellFrame* aCellFrame,
PRInt32 aRowIndex,
- PRBool aRebuildIfNecessary)
+ PRBool aRebuildIfNecessary,
+ nsRect& aDamageArea)
{
PRInt32 origNumMapRows = mRows.Count();
PRInt32 origNumCols = aMap.GetColCount();
PRBool zeroRowSpan;
- PRInt32 rowSpan = GetRowSpanForNewCell(aCellFrame, aRowIndex, zeroRowSpan);
+ PRInt32 rowSpan = (aCellFrame) ? GetRowSpanForNewCell(*aCellFrame, aRowIndex, zeroRowSpan) : 1;
// add new rows if necessary
PRInt32 endRowIndex = aRowIndex + rowSpan - 1;
if (endRowIndex >= origNumMapRows) {
Grow(aMap, 1 + endRowIndex - origNumMapRows);
}
- // get the first null CellData in the desired row. It may be 1 past the end if there are none
+ // get the first null or dead CellData in the desired row. It will equal origNumCols if there are none
+ CellData* origData = nsnull;
PRInt32 startColIndex;
for (startColIndex = 0; startColIndex < origNumCols; startColIndex++) {
- CellData* data = GetMapCellAt(aMap, aRowIndex, startColIndex, PR_TRUE);
+ CellData* data = GetDataAt(aMap, aRowIndex, startColIndex, PR_TRUE);
if (!data) {
- break; // we found the col
+ break;
+ }
+ else if (data->IsDead()) {
+ origData = data;
+ break;
}
}
+
PRBool zeroColSpan;
- PRInt32 colSpan = GetColSpanForNewCell(aCellFrame, startColIndex, origNumCols, zeroColSpan);
+ PRInt32 colSpan = (aCellFrame) ? GetColSpanForNewCell(*aCellFrame, startColIndex, origNumCols, zeroColSpan) : 1;
// if the new cell could potentially span into other rows and collide with
// originating cells there, we will play it safe and just rebuild the map
if (aRebuildIfNecessary && (aRowIndex < mRowCount - 1) && (rowSpan > 1)) {
nsAutoVoidArray newCellArray;
- newCellArray.AppendElement(&aCellFrame);
- RebuildConsideringCells(aMap, &newCellArray, aRowIndex, startColIndex, PR_TRUE);
- return startColIndex;
+ newCellArray.AppendElement(aCellFrame);
+ RebuildConsideringCells(aMap, &newCellArray, aRowIndex, startColIndex, PR_TRUE, aDamageArea);
+ return origData;
}
-
mRowCount = PR_MAX(mRowCount, aRowIndex + 1);
// add new cols to the table map if necessary
@@ -749,19 +1184,29 @@ nsCellMap::AppendCell(nsTableCellMap& aMap,
}
// Setup CellData for this cell
- CellData* origData = new CellData(&aCellFrame);
- if (!origData) return startColIndex;
- SetMapCellAt(aMap, *origData, aRowIndex, startColIndex, PR_TRUE);
+ if (origData) {
+ origData->Init(aCellFrame);
+ }
+ else {
+ origData = (aMap.mBCInfo) ? new BCCellData(aCellFrame) : new CellData(aCellFrame); if (!origData) ABORT1(origData);
+ SetDataAt(aMap, *origData, aRowIndex, startColIndex, PR_TRUE);
+ }
+
+ SetDamageArea(startColIndex, aRowIndex, 1 + endColIndex - startColIndex, 1 + endRowIndex - aRowIndex, aDamageArea);
+
+ if (!aCellFrame) {
+ return origData;
+ }
// initialize the cell frame
- aCellFrame.InitCellFrame(startColIndex);
+ aCellFrame->InitCellFrame(startColIndex);
// Create CellData objects for the rows that this cell spans. Set
// their mOrigCell to nsnull and their mSpanData to point to data.
for (PRInt32 rowX = aRowIndex; rowX <= endRowIndex; rowX++) {
for (PRInt32 colX = startColIndex; colX <= endColIndex; colX++) {
if ((rowX != aRowIndex) || (colX != startColIndex)) { // skip orig cell data done above
- CellData* cellData = GetMapCellAt(aMap, rowX, colX, PR_FALSE);
+ CellData* cellData = GetDataAt(aMap, rowX, colX, PR_FALSE);
if (cellData) {
if (cellData->IsOrig()) {
NS_ASSERTION(PR_FALSE, "cannot overlap originating cell");
@@ -796,8 +1241,8 @@ nsCellMap::AppendCell(nsTableCellMap& aMap,
}
}
else {
- cellData = new CellData(nsnull);
- if (!cellData) return startColIndex;
+ cellData = (aMap.mBCInfo) ? new BCCellData(nsnull) : new CellData(nsnull);
+ if (!cellData) return origData;
if (rowX > aRowIndex) {
cellData->SetRowSpanOffset(rowX - aRowIndex);
}
@@ -811,14 +1256,14 @@ nsCellMap::AppendCell(nsTableCellMap& aMap,
cellData->SetZeroColSpan(PR_TRUE);
}
// only count the 1st spanned col of a zero col span
- SetMapCellAt(aMap, *cellData, rowX, colX, (colX == startColIndex + 1));
+ SetDataAt(aMap, *cellData, rowX, colX, (colX == startColIndex + 1));
}
}
}
}
- //printf("appended cell=%p row=%d \n", &aCellFrame, aRowIndex);
+ //printf("appended cell=%p row=%d \n", aCellFrame, aRowIndex);
//aMap.Dump();
- return startColIndex;
+ return origData;
}
PRBool nsCellMap::CellsSpanOut(nsIPresContext* aPresContext,
@@ -832,7 +1277,7 @@ PRBool nsCellMap::CellsSpanOut(nsIPresContext* aPresContext,
while (cellFrame) {
nsIAtom* frameType;
cellFrame->GetFrameType(&frameType);
- if (nsLayoutAtoms::tableCellFrame == frameType) {
+ if (IS_TABLE_CELL(frameType)) {
PRBool zeroSpan;
PRInt32 rowSpan = GetRowSpanForNewCell((nsTableCellFrame &)*cellFrame, rowX, zeroSpan);
if (rowX + rowSpan > numNewRows) {
@@ -858,13 +1303,13 @@ PRBool nsCellMap::CellsSpanInOrOut(nsTableCellMap& aMap,
for (PRInt32 colX = aStartColIndex; colX <= aEndColIndex; colX++) {
CellData* cellData;
if (aStartRowIndex > 0) {
- cellData = GetMapCellAt(aMap, aStartRowIndex, colX, PR_TRUE);
+ cellData = GetDataAt(aMap, aStartRowIndex, colX, PR_TRUE);
if (cellData && (cellData->IsRowSpan())) {
return PR_TRUE; // there is a row span into the region
}
}
if (aEndRowIndex < mRowCount - 1) {
- cellData = GetMapCellAt(aMap, aEndRowIndex + 1, colX, PR_TRUE);
+ cellData = GetDataAt(aMap, aEndRowIndex + 1, colX, PR_TRUE);
if ((cellData) && (cellData->IsRowSpan())) {
return PR_TRUE; // there is a row span out of the region
}
@@ -872,7 +1317,7 @@ PRBool nsCellMap::CellsSpanInOrOut(nsTableCellMap& aMap,
}
if (aStartColIndex > 0) {
for (PRInt32 rowX = aStartRowIndex; rowX <= aEndRowIndex; rowX++) {
- CellData* cellData = GetMapCellAt(aMap, rowX, aStartColIndex, PR_TRUE);
+ CellData* cellData = GetDataAt(aMap, rowX, aStartColIndex, PR_TRUE);
if (cellData && (cellData->IsColSpan())) {
return PR_TRUE; // there is a col span into the region
}
@@ -891,7 +1336,8 @@ PRBool nsCellMap::CellsSpanInOrOut(nsTableCellMap& aMap,
void nsCellMap::InsertCells(nsTableCellMap& aMap,
nsVoidArray& aCellFrames,
PRInt32 aRowIndex,
- PRInt32 aColIndexBefore)
+ PRInt32 aColIndexBefore,
+ nsRect& aDamageArea)
{
if (aCellFrames.Count() == 0) return;
PRInt32 numCols = aMap.GetColCount();
@@ -903,7 +1349,7 @@ void nsCellMap::InsertCells(nsTableCellMap& aMap,
// get the starting col index of the 1st new cells
PRInt32 startColIndex;
for (startColIndex = aColIndexBefore + 1; startColIndex < numCols; startColIndex++) {
- CellData* data = GetMapCellAt(aMap, aRowIndex, startColIndex, PR_TRUE);
+ CellData* data = GetDataAt(aMap, aRowIndex, startColIndex, PR_TRUE);
if (!data || data->IsOrig()) { // stop unless it is a span
break;
}
@@ -942,10 +1388,10 @@ void nsCellMap::InsertCells(nsTableCellMap& aMap,
}
if (spansCauseRebuild) {
- RebuildConsideringCells(aMap, &aCellFrames, aRowIndex, startColIndex, PR_TRUE);
+ RebuildConsideringCells(aMap, &aCellFrames, aRowIndex, startColIndex, PR_TRUE, aDamageArea);
}
else {
- ExpandWithCells(aMap, aCellFrames, aRowIndex, startColIndex, rowSpan, zeroRowSpan);
+ ExpandWithCells(aMap, aCellFrames, aRowIndex, startColIndex, rowSpan, zeroRowSpan, aDamageArea);
}
}
@@ -953,7 +1399,8 @@ void
nsCellMap::ExpandWithRows(nsIPresContext* aPresContext,
nsTableCellMap& aMap,
nsVoidArray& aRowFrames,
- PRInt32 aStartRowIndexIn)
+ PRInt32 aStartRowIndexIn,
+ nsRect& aDamageArea)
{
PRInt32 startRowIndex = (aStartRowIndexIn >= 0) ? aStartRowIndexIn : 0;
PRInt32 numNewRows = aRowFrames.Count();
@@ -974,22 +1421,25 @@ nsCellMap::ExpandWithRows(nsIPresContext* aPresContext,
while (cFrame) {
nsIAtom* cFrameType;
cFrame->GetFrameType(&cFrameType);
- if (nsLayoutAtoms::tableCellFrame == cFrameType) {
- AppendCell(aMap, (nsTableCellFrame &)*cFrame, rowX, PR_FALSE);
+ if (IS_TABLE_CELL(cFrameType)) {
+ AppendCell(aMap, (nsTableCellFrame *)cFrame, rowX, PR_FALSE, aDamageArea);
}
NS_IF_RELEASE(cFrameType);
cFrame->GetNextSibling(&cFrame);
}
newRowIndex++;
}
+
+ SetDamageArea(0, startRowIndex, aMap.GetColCount(), 1 + endRowIndex - startRowIndex, aDamageArea);
}
void nsCellMap::ExpandWithCells(nsTableCellMap& aMap,
nsVoidArray& aCellFrames,
PRInt32 aRowIndex,
PRInt32 aColIndex,
- PRInt32 aRowSpan,
- PRBool aRowSpanIsZero)
+ PRInt32 aRowSpan, // same for all cells
+ PRBool aRowSpanIsZero,
+ nsRect& aDamageArea)
{
PRInt32 endRowIndex = aRowIndex + aRowSpan - 1;
PRInt32 startColIndex = aColIndex;
@@ -1000,7 +1450,7 @@ void nsCellMap::ExpandWithCells(nsTableCellMap& aMap,
// add cellData entries for the space taken up by the new cells
for (PRInt32 cellX = 0; cellX < numCells; cellX++) {
nsTableCellFrame* cellFrame = (nsTableCellFrame*) aCellFrames.ElementAt(cellX);
- CellData* origData = new CellData(cellFrame); // the originating cell
+ CellData* origData = (aMap.mBCInfo) ? new BCCellData(cellFrame) : new CellData(cellFrame); // the originating cell
if (!origData) return;
// set the starting and ending col index for the new cell
@@ -1022,7 +1472,7 @@ void nsCellMap::ExpandWithCells(nsTableCellMap& aMap,
row->InsertElementAt(nsnull, colX);
CellData* data = origData;
if ((rowX != aRowIndex) || (colX != startColIndex)) {
- data = new CellData(nsnull);
+ data = (aMap.mBCInfo) ? new BCCellData(nsnull) : new CellData(nsnull);
if (!data) return;
if (rowX > aRowIndex) {
data->SetRowSpanOffset(rowX - aRowIndex);
@@ -1038,11 +1488,13 @@ void nsCellMap::ExpandWithCells(nsTableCellMap& aMap,
}
}
// only count 1st spanned col of colspan=0
- SetMapCellAt(aMap, *data, rowX, colX, (colX == aColIndex + 1));
+ SetDataAt(aMap, *data, rowX, colX, (colX == aColIndex + 1));
}
}
cellFrame->InitCellFrame(startColIndex);
}
+ PRInt32 damageHeight = (aRowSpanIsZero) ? aMap.GetColCount() - aRowIndex : aRowSpan;
+ SetDamageArea(aColIndex, aRowIndex, 1 + endColIndex - aColIndex, damageHeight, aDamageArea);
PRInt32 rowX;
@@ -1090,7 +1542,8 @@ void nsCellMap::ExpandWithCells(nsTableCellMap& aMap,
void nsCellMap::ShrinkWithoutRows(nsTableCellMap& aMap,
PRInt32 aStartRowIndex,
- PRInt32 aNumRowsToRemove)
+ PRInt32 aNumRowsToRemove,
+ nsRect& aDamageArea)
{
PRInt32 endRowIndex = aStartRowIndex + aNumRowsToRemove - 1;
PRInt32 colCount = aMap.GetColCount();
@@ -1132,6 +1585,8 @@ void nsCellMap::ShrinkWithoutRows(nsTableCellMap& aMap,
mRowCount--;
}
aMap.RemoveColsAtEnd();
+
+ SetDamageArea(0, aStartRowIndex, aMap.GetColCount(), 0, aDamageArea);
}
PRInt32 nsCellMap::GetColSpanForNewCell(nsTableCellFrame& aCellFrameToAdd,
@@ -1162,15 +1617,15 @@ PRInt32 nsCellMap::GetEffectiveColSpan(nsTableCellMap& aMap,
PRInt32 colX;
CellData* data;
PRInt32 maxCols = numColsInTable;
- PRBool hitOverlap = PR_FALSE;
+ PRBool hitOverlap = PR_FALSE; // XXX this is not ever being set to PR_TRUE
for (colX = aColIndex + 1; colX < maxCols; colX++) {
- data = GetMapCellAt(aMap, aRowIndex, colX, PR_TRUE);
+ data = GetDataAt(aMap, aRowIndex, colX, PR_TRUE);
if (data) {
// for an overlapping situation get the colspan from the originating cell and
// use that as the max number of cols to iterate. Since this is rare, only
// pay the price of looking up the cell's colspan here.
if (!hitOverlap && data->IsOverlap()) {
- CellData* origData = GetMapCellAt(aMap, aRowIndex, aColIndex, PR_TRUE);
+ CellData* origData = GetDataAt(aMap, aRowIndex, aColIndex, PR_TRUE);
if (origData->IsOrig()) {
nsTableCellFrame* cellFrame = origData->GetCellFrame();
if (cellFrame) {
@@ -1223,7 +1678,7 @@ PRInt32 nsCellMap::GetRowSpan(nsTableCellMap& aMap,
PRInt32 rowCount = (aGetEffective) ? mRowCount : mRows.Count();
PRInt32 rowX;
for (rowX = aRowIndex + 1; rowX < rowCount; rowX++) {
- CellData* data = GetMapCellAt(aMap, rowX, aColIndex, PR_TRUE);
+ CellData* data = GetDataAt(aMap, rowX, aColIndex, PR_TRUE);
if (data) {
if (data->IsRowSpan()) {
rowSpan++;
@@ -1246,7 +1701,8 @@ PRInt32 nsCellMap::GetRowSpan(nsTableCellMap& aMap,
void nsCellMap::ShrinkWithoutCell(nsTableCellMap& aMap,
nsTableCellFrame& aCellFrame,
PRInt32 aRowIndex,
- PRInt32 aColIndex)
+ PRInt32 aColIndex,
+ nsRect& aDamageArea)
{
PRInt32 colX, rowX;
@@ -1258,6 +1714,8 @@ void nsCellMap::ShrinkWithoutCell(nsTableCellMap& aMap,
PRInt32 endRowIndex = aRowIndex + rowSpan - 1;
PRInt32 endColIndex = aColIndex + colSpan - 1;
+ SetDamageArea(aColIndex, aRowIndex, 1 + endColIndex - aColIndex, 1 + endRowIndex - aRowIndex, aDamageArea);
+
// adjust the col counts due to the deleted cell before removing it
for (colX = aColIndex; colX <= endColIndex; colX++) {
nsColInfo* colInfo = aMap.GetColInfoAt(colX);
@@ -1317,25 +1775,13 @@ void nsCellMap::ShrinkWithoutCell(nsTableCellMap& aMap,
aMap.RemoveColsAtEnd();
}
-void
-nsCellMap::RemoveCol(PRInt32 aColIndex)
-{
- PRInt32 numMapRows = mRows.Count();
- // remove the col from each of the rows
- for (PRInt32 rowX = 0; rowX < numMapRows; rowX++) {
- nsVoidArray* row = (nsVoidArray *)mRows.ElementAt(rowX);
- CellData* data = (CellData*) row->ElementAt(aColIndex);
- row->RemoveElementAt(aColIndex);
- delete data;
- }
-}
-
void
nsCellMap::RebuildConsideringRows(nsIPresContext* aPresContext,
nsTableCellMap& aMap,
PRInt32 aStartRowIndex,
nsVoidArray* aRowsToInsert,
- PRBool aNumRowsToRemove)
+ PRBool aNumRowsToRemove,
+ nsRect& aDamageArea)
{
// copy the old cell map into a new array
PRInt32 numOrigRows = mRows.Count();
@@ -1352,6 +1798,7 @@ nsCellMap::RebuildConsideringRows(nsIPresContext* aPresContext,
nsColInfo* colInfo = aMap.GetColInfoAt(colX);
colInfo->mNumCellsOrig = 0;
}
+
mRows.Clear();
mRowCount = 0;
if (aRowsToInsert) {
@@ -1366,7 +1813,7 @@ nsCellMap::RebuildConsideringRows(nsIPresContext* aPresContext,
// put in the original cell from the cell map
CellData* data = (CellData*) row->ElementAt(colX);
if (data && data->IsOrig()) {
- AppendCell(aMap, *data->GetCellFrame(), rowX, PR_FALSE);
+ AppendCell(aMap, data->GetCellFrame(), rowX, PR_FALSE, aDamageArea);
}
}
}
@@ -1382,8 +1829,8 @@ nsCellMap::RebuildConsideringRows(nsIPresContext* aPresContext,
while (cFrame) {
nsIAtom* cFrameType;
cFrame->GetFrameType(&cFrameType);
- if (nsLayoutAtoms::tableCellFrame == cFrameType) {
- AppendCell(aMap, (nsTableCellFrame &)*cFrame, rowX, PR_FALSE);
+ if (IS_TABLE_CELL(cFrameType)) {
+ AppendCell(aMap, (nsTableCellFrame *)cFrame, rowX, PR_FALSE, aDamageArea);
}
NS_IF_RELEASE(cFrameType);
cFrame->GetNextSibling(&cFrame);
@@ -1405,7 +1852,7 @@ nsCellMap::RebuildConsideringRows(nsIPresContext* aPresContext,
// put in the original cell from the cell map
CellData* data = (CellData*) row->ElementAt(colX);
if (data && data->IsOrig()) {
- AppendCell(aMap, *data->GetCellFrame(), rowX, PR_FALSE);
+ AppendCell(aMap, data->GetCellFrame(), rowX, PR_FALSE, aDamageArea);
}
}
rowX++;
@@ -1422,13 +1869,16 @@ nsCellMap::RebuildConsideringRows(nsIPresContext* aPresContext,
delete row;
}
delete [] origRows;
+
+ SetDamageArea(0, 0, aMap.GetColCount(), GetRowCount(), aDamageArea);
}
void nsCellMap::RebuildConsideringCells(nsTableCellMap& aMap,
nsVoidArray* aCellFrames,
PRInt32 aRowIndex,
PRInt32 aColIndex,
- PRBool aInsert)
+ PRBool aInsert,
+ nsRect& aDamageArea)
{
// copy the old cell map into a new array
PRInt32 mRowCountOrig = mRowCount;
@@ -1441,6 +1891,7 @@ void nsCellMap::RebuildConsideringCells(nsTableCellMap& aMap,
nsVoidArray* row = (nsVoidArray *)mRows.ElementAt(rowX);
origRows[rowX] = row;
}
+
// reinitialize data members
mRows.Clear();
mRowCount = 0;
@@ -1457,7 +1908,7 @@ void nsCellMap::RebuildConsideringCells(nsTableCellMap& aMap,
for (PRInt32 cellX = 0; cellX < numNewCells; cellX++) {
nsTableCellFrame* cell = (nsTableCellFrame*)aCellFrames->ElementAt(cellX);
if (cell) {
- AppendCell(aMap, *cell, rowX, PR_FALSE);
+ AppendCell(aMap, cell, rowX, PR_FALSE, aDamageArea);
}
}
}
@@ -1468,7 +1919,7 @@ void nsCellMap::RebuildConsideringCells(nsTableCellMap& aMap,
// put in the original cell from the cell map
CellData* data = (CellData*) row->ElementAt(colX);
if (data && data->IsOrig()) {
- AppendCell(aMap, *data->GetCellFrame(), rowX, PR_FALSE);
+ AppendCell(aMap, data->GetCellFrame(), rowX, PR_FALSE, aDamageArea);
}
}
}
@@ -1490,11 +1941,14 @@ void nsCellMap::RebuildConsideringCells(nsTableCellMap& aMap,
delete row;
}
delete [] origRows;
+
+ SetDamageArea(0, 0, aMap.GetColCount(), GetRowCount(), aDamageArea);
}
void nsCellMap::RemoveCell(nsTableCellMap& aMap,
nsTableCellFrame* aCellFrame,
- PRInt32 aRowIndex)
+ PRInt32 aRowIndex,
+ nsRect& aDamageArea)
{
PRInt32 numRows = mRows.Count();
if ((aRowIndex < 0) || (aRowIndex >= numRows)) {
@@ -1506,7 +1960,7 @@ void nsCellMap::RemoveCell(nsTableCellMap& aMap,
// get the starting col index of the cell to remove
PRInt32 startColIndex;
for (startColIndex = 0; startColIndex < numCols; startColIndex++) {
- CellData* data = GetMapCellAt(aMap, aRowIndex, startColIndex, PR_FALSE);
+ CellData* data = GetDataAt(aMap, aRowIndex, startColIndex, PR_FALSE);
if (data && (data->IsOrig()) && (aCellFrame == data->GetCellFrame())) {
break; // we found the col index
}
@@ -1523,15 +1977,15 @@ void nsCellMap::RemoveCell(nsTableCellMap& aMap,
// no extraneous cols at the end. The same is true for removing rows.
if (spansCauseRebuild) {
- RebuildConsideringCells(aMap, nsnull, aRowIndex, startColIndex, PR_FALSE);
+ RebuildConsideringCells(aMap, nsnull, aRowIndex, startColIndex, PR_FALSE, aDamageArea);
}
else {
- ShrinkWithoutCell(aMap, *aCellFrame, aRowIndex, startColIndex);
+ ShrinkWithoutCell(aMap, *aCellFrame, aRowIndex, startColIndex, aDamageArea);
}
}
#ifdef NS_DEBUG
-void nsCellMap::Dump() const
+void nsCellMap::Dump(PRBool aIsBorderCollapse) const
{
printf("\n ***** START GROUP CELL MAP DUMP ***** %p\n", this);
PRInt32 mapRowCount = mRows.Count();
@@ -1566,6 +2020,33 @@ void nsCellMap::Dump() const
printf("---- ");
}
}
+ if (aIsBorderCollapse) {
+ nscoord size;
+ BCBorderOwner owner;
+ PRUint8 side;
+ PRBool segStart;
+ PRPackedBool bevel;
+ for (PRInt32 i = 0; i <= 2; i++) {
+ printf("\n ");
+ for (colIndex = 0; colIndex < colCount; colIndex++) {
+ BCCellData* cd = (BCCellData *)row->ElementAt(colIndex);
+ if (cd) {
+ if (0 == i) {
+ size = cd->mData.GetTopEdge(owner, segStart);
+ printf("t=%d%d%d ", size, owner, segStart);
+ }
+ else if (1 == i) {
+ size = cd->mData.GetLeftEdge(owner, segStart);
+ printf("l=%d%d%d ", size, owner, segStart);
+ }
+ else {
+ size = cd->mData.GetCorner(side, bevel);
+ printf("c=%d%d%d ", size, side, bevel);
+ }
+ }
+ }
+ }
+ }
printf("\n");
}
@@ -1614,7 +2095,7 @@ nsCellMap::AdjustForZeroSpan(nsTableCellMap& aMap,
PRInt32 aColIndex)
{
PRInt32 numColsInTable = aMap.GetColCount();
- CellData* data = GetMapCellAt(aMap, aRowIndex, aColIndex, PR_FALSE);
+ CellData* data = GetDataAt(aMap, aRowIndex, aColIndex, PR_FALSE);
if (!data) return;
nsTableCellFrame* cell = (data->IsOrig()) ? data->GetCellFrame() : nsnull;
@@ -1640,7 +2121,7 @@ nsCellMap::AdjustForZeroSpan(nsTableCellMap& aMap,
PRBool cellsOrig = PR_FALSE;
if (colX >= aColIndex + MIN_NUM_COLS_FOR_ZERO_COLSPAN - 1) {
for (rowX = aRowIndex; rowX <= endRowIndex; rowX++) {
- CellData* cellData = GetMapCellAt(aMap, rowX, colX, PR_FALSE);
+ CellData* cellData = GetDataAt(aMap, rowX, colX, PR_FALSE);
if (cellData && cellData->IsOrig()) {
cellsOrig = PR_TRUE;
break; // there are cells in this col, so don't consider it
@@ -1650,9 +2131,9 @@ nsCellMap::AdjustForZeroSpan(nsTableCellMap& aMap,
if (cellsOrig) break;
for (rowX = aRowIndex; rowX <= endRowIndex; rowX++) {
if ((colX > aColIndex) || (rowX > aRowIndex)) {
- CellData* oldData = GetMapCellAt(aMap, rowX, colX, PR_FALSE);
+ CellData* oldData = GetDataAt(aMap, rowX, colX, PR_FALSE);
if (!oldData) {
- CellData* newData = new CellData(nsnull);
+ CellData* newData = (aMap.mBCInfo) ? new BCCellData(nsnull) : new CellData(nsnull);
if (!newData) return;
if (colX > aColIndex) {
newData->SetColSpanOffset(colX - aColIndex);
@@ -1663,7 +2144,7 @@ nsCellMap::AdjustForZeroSpan(nsTableCellMap& aMap,
newData->SetZeroRowSpan(PR_TRUE);
}
// colspan=0 is only counted as spanning the 1st col to the right of its origin
- SetMapCellAt(aMap, *newData, rowX, colX, (colX == aColIndex + 1));
+ SetDataAt(aMap, *newData, rowX, colX, (colX == aColIndex + 1));
}
}
}
@@ -1671,10 +2152,10 @@ nsCellMap::AdjustForZeroSpan(nsTableCellMap& aMap,
}
CellData*
-nsCellMap::GetMapCellAt(nsTableCellMap& aMap,
- PRInt32 aMapRowIndex,
- PRInt32 aColIndex,
- PRBool aUpdateZeroSpan)
+nsCellMap::GetDataAt(nsTableCellMap& aMap,
+ PRInt32 aMapRowIndex,
+ PRInt32 aColIndex,
+ PRBool aUpdateZeroSpan)
{
PRInt32 numColsInTable = aMap.GetColCount();
if ((aMapRowIndex < 0) || (aMapRowIndex >= mRows.Count())) {
@@ -1714,7 +2195,7 @@ nsCellMap::GetMapCellAt(nsTableCellMap& aMap,
PRInt32 prevColX = aColIndex - 1;
// find the last non null data in the same row
for ( ; prevColX > 0; prevColX--) {
- CellData* prevData = GetMapCellAt(aMap, aMapRowIndex, prevColX, PR_FALSE);
+ CellData* prevData = GetDataAt(aMap, aMapRowIndex, prevColX, PR_FALSE);
if (prevData) {
if (prevData->IsZeroColSpan()) {
PRInt32 colIndex = prevColX - prevData->GetColSpanOffset();
@@ -1729,29 +2210,18 @@ nsCellMap::GetMapCellAt(nsTableCellMap& aMap,
// if zero span adjustments were made the data may be available now
if (!data && didZeroExpand) {
- data = GetMapCellAt(aMap, aMapRowIndex, aColIndex, PR_FALSE);
+ data = GetDataAt(aMap, aMapRowIndex, aColIndex, PR_FALSE);
}
}
return data;
}
-CellData*
-nsCellMap::GetCellAt(nsTableCellMap& aMap,
- PRInt32 aRowIndex,
- PRInt32 aColIndex)
-{
- if ((0 > aRowIndex) || (aRowIndex >= mRowCount)) {
- return nsnull;
- }
- return GetMapCellAt(aMap, aRowIndex, aColIndex, PR_TRUE);
-}
-
// only called if the cell at aMapRowIndex, aColIndex is null
-void nsCellMap::SetMapCellAt(nsTableCellMap& aMap,
- CellData& aNewCell,
- PRInt32 aMapRowIndex,
- PRInt32 aColIndex,
- PRBool aCountZeroSpanAsSpan)
+void nsCellMap::SetDataAt(nsTableCellMap& aMap,
+ CellData& aNewCell,
+ PRInt32 aMapRowIndex,
+ PRInt32 aColIndex,
+ PRBool aCountZeroSpanAsSpan)
{
nsVoidArray* row = (nsVoidArray *)(mRows.SafeElementAt(aMapRowIndex));
if (row) {
@@ -1777,9 +2247,9 @@ void nsCellMap::SetMapCellAt(nsTableCellMap& aMap,
colInfo->mNumCellsSpan++;
}
}
- else NS_ASSERTION(PR_FALSE, "SetMapCellAt called with col index > table map num cols");
+ else NS_ASSERTION(PR_FALSE, "SetDataAt called with col index > table map num cols");
}
- else NS_ASSERTION(PR_FALSE, "SetMapCellAt called with row index > num rows");
+ else NS_ASSERTION(PR_FALSE, "SetDataAt called with row index > num rows");
}
nsTableCellFrame*
@@ -1792,7 +2262,7 @@ nsCellMap::GetCellInfoAt(nsTableCellMap& aMap,
if (aOriginates) {
*aOriginates = PR_FALSE;
}
- CellData* data = GetCellAt(aMap, aRowX, aColX);
+ CellData* data = GetDataAt(aMap, aRowX, aColX, PR_TRUE);
nsTableCellFrame* cellFrame = nsnull;
if (data) {
if (data->IsOrig()) {
@@ -1824,7 +2294,7 @@ PRBool nsCellMap::RowIsSpannedInto(nsTableCellMap& aMap,
return PR_FALSE;
}
for (PRInt32 colIndex = 0; colIndex < numColsInTable; colIndex++) {
- CellData* cd = GetCellAt(aMap, aRowIndex, colIndex);
+ CellData* cd = GetDataAt(aMap, aRowIndex, colIndex, PR_TRUE);
if (cd) { // there's really a cell at (aRowIndex, colIndex)
if (cd->IsSpan()) { // the cell at (aRowIndex, colIndex) is the result of a span
if (cd->IsRowSpan() && GetCellFrame(aRowIndex, colIndex, *cd, PR_TRUE)) { // XXX why the last check
@@ -1846,9 +2316,9 @@ PRBool nsCellMap::RowHasSpanningCells(nsTableCellMap& aMap,
if (aRowIndex != mRowCount - 1) {
// aRowIndex is not the last row, so we check the next row after aRowIndex for spanners
for (PRInt32 colIndex = 0; colIndex < numColsInTable; colIndex++) {
- CellData* cd = GetCellAt(aMap, aRowIndex, colIndex);
+ CellData* cd = GetDataAt(aMap, aRowIndex, colIndex, PR_TRUE);
if (cd && (cd->IsOrig())) { // cell originates
- CellData* cd2 = GetCellAt(aMap, aRowIndex + 1, colIndex);
+ CellData* cd2 = GetDataAt(aMap, aRowIndex + 1, colIndex, PR_TRUE);
if (cd2 && cd2->IsRowSpan()) { // cd2 is spanned by a row
if (cd->GetCellFrame() == GetCellFrame(aRowIndex + 1, colIndex, *cd2, PR_TRUE)) {
return PR_TRUE;
@@ -1869,9 +2339,9 @@ PRBool nsCellMap::ColHasSpanningCells(nsTableCellMap& aMap,
return PR_FALSE;
for (PRInt32 rowIndex = 0; rowIndex < mRowCount; rowIndex++) {
- CellData* cd = GetCellAt(aMap, rowIndex, aColIndex);
+ CellData* cd = GetDataAt(aMap, rowIndex, aColIndex, PR_TRUE);
if (cd && (cd->IsOrig())) { // cell originates
- CellData* cd2 = GetCellAt(aMap, rowIndex + 1, aColIndex);
+ CellData* cd2 = GetDataAt(aMap, rowIndex + 1, aColIndex, PR_TRUE);
if (cd2 && cd2->IsColSpan()) { // cd2 is spanned by a col
if (cd->GetCellFrame() == GetCellFrame(rowIndex + 1, aColIndex, *cd2, PR_FALSE)) {
return PR_TRUE;
diff --git a/mozilla/layout/html/table/src/nsCellMap.h b/mozilla/layout/html/table/src/nsCellMap.h
index 89211aa5f99..4b1b6df3b7f 100644
--- a/mozilla/layout/html/table/src/nsCellMap.h
+++ b/mozilla/layout/html/table/src/nsCellMap.h
@@ -40,6 +40,8 @@
#include "nscore.h"
#include "celldata.h"
#include "nsVoidArray.h"
+#include "nsRect.h"
+
class nsTableColFrame;
class nsTableCellFrame;
class nsIPresContext;
@@ -58,10 +60,27 @@ struct nsColInfo
PRInt32 aNumCellsSpan);
};
+enum Corner
+{
+ eTopLeft = 0,
+ eTopRight = 1,
+ eBottomRight = 2,
+ eBottomLeft = 3
+};
+
+struct BCInfo
+{
+ nsVoidArray mRightBorders;
+ nsVoidArray mBottomBorders;
+ BCData mLowerRightCorner;
+};
+
class nsTableCellMap
{
public:
- nsTableCellMap(nsIPresContext* aPresContext, nsTableFrame& aTableFrame);
+ nsTableCellMap(nsIPresContext* aPresContext,
+ nsTableFrame& aTableFrame,
+ PRBool aBorderCollapse);
/** destructor
* NOT VIRTUAL BECAUSE THIS CLASS SHOULD **NEVER** BE SUBCLASSED
@@ -69,43 +88,52 @@ public:
~nsTableCellMap();
void RemoveGroupCellMap(nsTableRowGroupFrame* aRowGroup);
+
void InsertGroupCellMap(nsTableRowGroupFrame& aNewRowGroup,
nsTableRowGroupFrame*& aPrevRowGroup);
+ nsCellMap* GetMapFor(nsTableRowGroupFrame& aRowGroup);
+
nsTableCellFrame* GetCellFrame(PRInt32 aRowIndex,
PRInt32 aColIndex,
CellData& aData,
PRBool aUseRowIfOverlap) const;
/** return the CellData for the cell at (aTableRowIndex, aTableColIndex) */
- CellData* GetCellAt(PRInt32 aRowIndex,
- PRInt32 aColIndex);
+ CellData* GetDataAt(PRInt32 aRowIndex,
+ PRInt32 aColIndex,
+ PRBool aUpdateZeroSpan = PR_TRUE);
nsColInfo* GetColInfoAt(PRInt32 aColIndex);
/** append the cellFrame at the end of the row at aRowIndex and return the col index
*/
- PRInt32 AppendCell(nsTableCellFrame& aCellFrame,
- PRInt32 aRowIndex,
- PRBool aRebuildIfNecessary);
+ CellData* AppendCell(nsTableCellFrame& aCellFrame,
+ PRInt32 aRowIndex,
+ PRBool aRebuildIfNecessary,
+ nsRect& aDamageArea);
void InsertCells(nsVoidArray& aCellFrames,
PRInt32 aRowIndex,
- PRInt32 aColIndexBefore);
+ PRInt32 aColIndexBefore,
+ nsRect& aDamageArea);
void RemoveCell(nsTableCellFrame* aCellFrame,
- PRInt32 aRowIndex);
+ PRInt32 aRowIndex,
+ nsRect& aDamageArea);
void InsertRows(nsIPresContext* aPresContext,
nsTableRowGroupFrame& aRowGroup,
nsVoidArray& aRows,
PRInt32 aFirstRowIndex,
- PRBool aConsiderSpans);
+ PRBool aConsiderSpans,
+ nsRect& aDamageArea);
void RemoveRows(nsIPresContext* aPresContext,
PRInt32 aFirstRowIndex,
PRInt32 aNumRowsToRemove,
- PRBool aConsiderSpans);
+ PRBool aConsiderSpans,
+ nsRect& aDamageArea);
PRInt32 GetNumCellsOriginatingInRow(PRInt32 aRowIndex);
PRInt32 GetNumCellsOriginatingInCol(PRInt32 aColIndex) const;
@@ -134,6 +162,32 @@ public:
PRBool ColIsSpannedInto(PRInt32 aColIndex);
PRBool ColHasSpanningCells(PRInt32 aColIndex);
+ BCData* GetBCData(PRUint8 aSide,
+ nsCellMap& aCellMap,
+ PRUint32 aYPos,
+ PRUint32 aXPos,
+ PRBool aIsLowerRight = PR_FALSE);
+
+ void SetBCBorderEdge(PRUint8 aEdge,
+ nsCellMap& aCellMap,
+ PRUint32 aCellMapStart,
+ PRUint32 aYPos,
+ PRUint32 aXPos,
+ PRUint32 aLength,
+ BCBorderOwner aOwner,
+ nscoord aSize,
+ PRBool aChanged);
+
+ void SetBCBorderCorner(Corner aCorner,
+ nsCellMap& aCellMap,
+ PRUint32 aCellMapStart,
+ PRUint32 aYPos,
+ PRUint32 aXPos,
+ PRUint8 aOwner,
+ nscoord aSubSize,
+ PRBool aBevel,
+ PRBool aIsBottomRight = PR_FALSE);
+
/** dump a representation of the cell map to stdout for debugging */
#ifdef NS_DEBUG
void Dump(char* aString = nsnull) const;
@@ -144,13 +198,21 @@ public:
#endif
protected:
+ BCData* GetRightMostBorder(PRInt32 aRowIndex);
+ BCData* GetBottomMostBorder(PRInt32 aColIndex);
+
friend class nsCellMap;
+ friend class BCMapCellIterator;
+ friend class BCMapBorderIterator;
void InsertGroupCellMap(nsCellMap* aPrevMap,
nsCellMap& aNewMap);
+ void DeleteRightBottomBorders();
- nsTableFrame& mTableFrame;
+ nsTableFrame& mTableFrame;
nsAutoVoidArray mCols;
- nsCellMap* mFirstMap;
+ nsCellMap* mFirstMap;
+ // border collapsing info
+ BCInfo* mBCInfo;
};
/** nsCellMap is a support class for nsTablePart.
@@ -190,40 +252,38 @@ public:
CellData& aData,
PRBool aUseRowSpanIfOverlap) const;
- /** return the CellData for the cell at (aTableRowIndex, aTableColIndex) */
- CellData* GetCellAt(nsTableCellMap& aMap,
- PRInt32 aRowIndex,
- PRInt32 aColIndex);
-
/** append the cellFrame at the end of the row at aRowIndex and return the col index
*/
- PRInt32 AppendCell(nsTableCellMap& aMap,
- nsTableCellFrame& aCellFrame,
- PRInt32 aRowIndex,
- PRBool aRebuildIfNecessary);
+ CellData* AppendCell(nsTableCellMap& aMap,
+ nsTableCellFrame* aCellFrame,
+ PRInt32 aRowIndex,
+ PRBool aRebuildIfNecessary,
+ nsRect& aDamageArea);
void InsertCells(nsTableCellMap& aMap,
nsVoidArray& aCellFrames,
PRInt32 aRowIndex,
- PRInt32 aColIndexBefore);
+ PRInt32 aColIndexBefore,
+ nsRect& aDamageArea);
void RemoveCell(nsTableCellMap& aMap,
nsTableCellFrame* aCellFrame,
- PRInt32 aRowIndex);
-
- void RemoveCol(PRInt32 aColIndex);
+ PRInt32 aRowIndex,
+ nsRect& aDamageArea);
void InsertRows(nsIPresContext* aPresContext,
nsTableCellMap& aMap,
nsVoidArray& aRows,
PRInt32 aFirstRowIndex,
- PRBool aConsiderSpans);
+ PRBool aConsiderSpans,
+ nsRect& aDamageArea);
void RemoveRows(nsIPresContext* aPresContext,
nsTableCellMap& aMap,
PRInt32 aFirstRowIndex,
PRInt32 aNumRowsToRemove,
- PRBool aConsiderSpans);
+ PRBool aConsiderSpans,
+ nsRect& aDamageArea);
PRInt32 GetNumCellsOriginatingInRow(PRInt32 aRowIndex) const;
PRInt32 GetNumCellsOriginatingInCol(PRInt32 aColIndex) const;
@@ -246,9 +306,20 @@ public:
PRBool ColHasSpanningCells(nsTableCellMap& aMap,
PRInt32 aColIndex);
+ PRInt32 GetRowSpan(nsTableCellMap& aMap,
+ PRInt32 aRowIndex,
+ PRInt32 aColIndex,
+ PRBool aGetEffective,
+ PRBool& aIsZeroRowSpan);
+
+ PRInt32 GetEffectiveColSpan(nsTableCellMap& aMap,
+ PRInt32 aRowIndex,
+ PRInt32 aColIndex,
+ PRBool& aIsZeroColSpan);
+
/** dump a representation of the cell map to stdout for debugging */
#ifdef NS_DEBUG
- void Dump() const;
+ void Dump(PRBool aIsBorderCollapse) const;
#endif
#ifdef DEBUG
@@ -257,6 +328,9 @@ public:
protected:
friend class nsTableCellMap;
+ friend class BCMapCellIterator;
+ friend class BCMapBorderIterator;
+ friend class nsTableFrame;
PRBool Grow(nsTableCellMap& aMap,
PRInt32 aNumRows,
@@ -266,51 +340,57 @@ protected:
PRInt32 aNumCols);
/** assign aCellData to the cell at (aRow,aColumn) */
- void SetMapCellAt(nsTableCellMap& aMap,
- CellData& aCellData,
- PRInt32 aMapRowIndex,
- PRInt32 aColIndex,
- PRBool aCountZeroSpanAsSpan);
+ void SetDataAt(nsTableCellMap& aMap,
+ CellData& aCellData,
+ PRInt32 aMapRowIndex,
+ PRInt32 aColIndex,
+ PRBool aCountZeroSpanAsSpan);
- CellData* GetMapCellAt(nsTableCellMap& aMap,
- PRInt32 aMapRowIndex,
- PRInt32 aColIndex,
- PRBool aUpdateZeroSpan);
+ CellData* GetDataAt(nsTableCellMap& aMap,
+ PRInt32 aMapRowIndex,
+ PRInt32 aColIndex,
+ PRBool aUpdateZeroSpan);
PRInt32 GetNumCellsIn(PRInt32 aColIndex) const;
void ExpandWithRows(nsIPresContext* aPresContext,
nsTableCellMap& aMap,
nsVoidArray& aRowFrames,
- PRInt32 aStartRowIndex);
+ PRInt32 aStartRowIndex,
+ nsRect& aDamageArea);
void ExpandWithCells(nsTableCellMap& aMap,
nsVoidArray& aCellFrames,
PRInt32 aRowIndex,
PRInt32 aColIndex,
PRInt32 aRowSpan,
- PRBool aRowSpanIsZero);
+ PRBool aRowSpanIsZero,
+ nsRect& aDamageArea);
void ShrinkWithoutRows(nsTableCellMap& aMap,
PRInt32 aFirstRowIndex,
- PRInt32 aNumRowsToRemove);
+ PRInt32 aNumRowsToRemove,
+ nsRect& aDamageArea);
void ShrinkWithoutCell(nsTableCellMap& aMap,
nsTableCellFrame& aCellFrame,
PRInt32 aRowIndex,
- PRInt32 aColIndex);
+ PRInt32 aColIndex,
+ nsRect& aDamageArea);
void RebuildConsideringRows(nsIPresContext* aPresContext,
nsTableCellMap& aMap,
PRInt32 aStartRowIndex,
nsVoidArray* aRowsToInsert,
- PRInt32 aNumRowsToRemove = 0);
+ PRInt32 aNumRowsToRemove,
+ nsRect& aDamageArea);
void RebuildConsideringCells(nsTableCellMap& aMap,
nsVoidArray* aCellFrames,
PRInt32 aRowIndex,
PRInt32 aColIndex,
- PRBool aInsert);
+ PRBool aInsert,
+ nsRect& aDamageArea);
PRBool CellsSpanOut(nsIPresContext* aPresContext,
nsVoidArray& aNewRows);
@@ -327,21 +407,10 @@ protected:
PRBool CreateEmptyRow(PRInt32 aRowIndex,
PRInt32 aNumCols);
- PRInt32 GetRowSpan(nsTableCellMap& aMap,
- PRInt32 aRowIndex,
- PRInt32 aColIndex,
- PRBool aGetEffective,
- PRBool& aIsZeroRowSpan);
-
PRInt32 GetRowSpanForNewCell(nsTableCellFrame& aCellFrameToAdd,
PRInt32 aRowIndex,
PRBool& aIsZeroRowSpan);
- PRInt32 GetEffectiveColSpan(nsTableCellMap& aMap,
- PRInt32 aRowIndex,
- PRInt32 aColIndex,
- PRBool& aIsZeroColSpan);
-
PRInt32 GetColSpanForNewCell(nsTableCellFrame& aCellFrameToAdd,
PRInt32 aColIndex,
PRInt32 aNumColsInTable,
diff --git a/mozilla/layout/html/table/src/nsITableLayoutStrategy.h b/mozilla/layout/html/table/src/nsITableLayoutStrategy.h
index 0349e3924d8..bae856d64b4 100644
--- a/mozilla/layout/html/table/src/nsITableLayoutStrategy.h
+++ b/mozilla/layout/html/table/src/nsITableLayoutStrategy.h
@@ -76,7 +76,8 @@ public:
* @param aPixelToTwips - the number of twips in a pixel.
* @return - the basis for percent calculations
*/
- virtual nscoord CalcPctAdjTableWidth(const nsHTMLReflowState& aReflowState,
+ virtual nscoord CalcPctAdjTableWidth(nsIPresContext& aPresContext,
+ const nsHTMLReflowState& aReflowState,
nscoord aAvailWidth,
float aPixelToTwips)=0;
diff --git a/mozilla/layout/html/table/src/nsTableCellFrame.cpp b/mozilla/layout/html/table/src/nsTableCellFrame.cpp
index 2c0e87b11de..06ca717b3bd 100644
--- a/mozilla/layout/html/table/src/nsTableCellFrame.cpp
+++ b/mozilla/layout/html/table/src/nsTableCellFrame.cpp
@@ -100,7 +100,7 @@ nsTableCellFrame::GetNextCell() const
while (childFrame) {
nsCOMPtr frameType;
childFrame->GetFrameType(getter_AddRefs(frameType));
- if (nsLayoutAtoms::tableCellFrame == frameType.get()) {
+ if (IS_TABLE_CELL(frameType.get())) {
return (nsTableCellFrame*)childFrame;
}
childFrame->GetNextSibling(&childFrame);
@@ -439,7 +439,7 @@ nsTableCellFrame::Paint(nsIPresContext* aPresContext,
if ((NS_SUCCEEDED(rv)) && tableFrame) {
const nsStyleTableBorder* tableStyle;
tableFrame->GetStyleData(eStyleStruct_TableBorder, ((const nsStyleStruct *&)tableStyle));
- if (NS_STYLE_BORDER_SEPARATE == tableFrame->GetBorderCollapseStyle()) {
+ if (!tableFrame->IsBorderCollapse()) {
nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this,
aDirtyRect, rect, *myBorder, mStyleContext, skipSides);
}
@@ -582,10 +582,9 @@ void nsTableCellFrame::VerticallyAlignChild(nsIPresContext* aPresContex
const nsStyleTextReset* textStyle =
(const nsStyleTextReset*)mStyleContext->GetStyleData(eStyleStruct_TextReset);
/* XXX: remove tableFrame when border-collapse inherits */
- nsTableFrame* tableFrame = nsnull;
- (void) nsTableFrame::GetTableFrame(this, tableFrame);
+ GET_PIXELS_TO_TWIPS(aPresContext, p2t);
nsMargin borderPadding;
- GetCellBorder (borderPadding, tableFrame);
+ GetBorderWidth (p2t, borderPadding);
nsMargin padding = nsTableFrame::GetPadding(aReflowState, this);
borderPadding += padding;
@@ -822,13 +821,13 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext,
PRBool contentEmptyBeforeReflow = GetContentEmpty();
/* XXX: remove tableFrame when border-collapse inherits */
- nsTableFrame* tableFrame=nsnull;
- rv = nsTableFrame::GetTableFrame(this, tableFrame);
+ nsTableFrame* tableFrame = nsnull;
+ rv = nsTableFrame::GetTableFrame(this, tableFrame); if (!tableFrame) ABORT1(NS_ERROR_NULL_POINTER);
nsTableFrame* tableFrameFirstInFlow = (nsTableFrame*)tableFrame->GetFirstInFlow();
nsMargin borderPadding = aReflowState.mComputedPadding;
nsMargin border;
- GetCellBorder(border, tableFrame);
+ GetBorderWidth(p2t, border);
if ((NS_UNCONSTRAINEDSIZE == availSize.width) || !contentEmptyBeforeReflow) {
borderPadding += border;
}
@@ -1130,51 +1129,6 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext,
return NS_OK;
}
-/**
- *
- * Update the border style to map to the HTML border style
- *
- */
-void nsTableCellFrame::MapHTMLBorderStyle(nsIPresContext* aPresContext,
- nsStyleBorder& aBorderStyle,
- nsTableFrame* aTableFrame)
-{
- //adjust the border style based on the table rules attribute
-
- /* The RULES code below has been disabled because collapsing borders have been disabled
- and RULES depend on collapsing borders
-
- const nsStyleTable* tableStyle;
- aTableFrame->GetStyleData(eStyleStruct_Table, (const nsStyleStruct *&)tableStyle);
-
- switch (tableStyle->mRules)
- {
- case NS_STYLE_TABLE_RULES_NONE:
- aBorderStyle.SetBorderStyle(NS_SIDE_TOP, NS_STYLE_BORDER_STYLE_NONE);
- aBorderStyle.SetBorderStyle(NS_SIDE_LEFT, NS_STYLE_BORDER_STYLE_NONE);
- aBorderStyle.SetBorderStyle(NS_SIDE_BOTTOM, NS_STYLE_BORDER_STYLE_NONE);
- aBorderStyle.SetBorderStyle(NS_SIDE_RIGHT, NS_STYLE_BORDER_STYLE_NONE);
- break;
-
- case NS_STYLE_TABLE_RULES_COLS:
- aBorderStyle.SetBorderStyle(NS_SIDE_TOP, NS_STYLE_BORDER_STYLE_NONE);
- aBorderStyle.SetBorderStyle(NS_SIDE_BOTTOM, NS_STYLE_BORDER_STYLE_NONE);
- break;
-
- case NS_STYLE_TABLE_RULES_ROWS:
- aBorderStyle.SetBorderStyle(NS_SIDE_LEFT, NS_STYLE_BORDER_STYLE_NONE);
- aBorderStyle.SetBorderStyle(NS_SIDE_RIGHT, NS_STYLE_BORDER_STYLE_NONE);
- break;
-
- default:
- // do nothing for "GROUPS" or "ALL" or for any illegal value
- // "GROUPS" will be handled in nsTableFrame::ProcessGroupRules
- break;
- }
- */
-}
-
-
PRBool nsTableCellFrame::ConvertToPixelValue(nsHTMLValue& aValue, PRInt32 aDefault, PRInt32& aResult)
{
if (aValue.GetUnit() == eHTMLUnit_Pixel)
@@ -1401,13 +1355,16 @@ nsTableCellFrame::GetNextCellInColumn(nsITableCellLayout **aCellLayout)
}
nsresult
-NS_NewTableCellFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
+NS_NewTableCellFrame(nsIPresShell* aPresShell,
+ PRBool aIsBorderCollapse,
+ nsIFrame** aNewFrame)
{
NS_PRECONDITION(aNewFrame, "null OUT ptr");
if (nsnull == aNewFrame) {
return NS_ERROR_NULL_POINTER;
}
- nsTableCellFrame* it = new (aPresShell) nsTableCellFrame;
+ nsTableCellFrame* it = (aIsBorderCollapse) ? new (aPresShell) nsBCTableCellFrame
+ : new (aPresShell) nsTableCellFrame;
if (nsnull == it) {
return NS_ERROR_OUT_OF_MEMORY;
}
@@ -1415,27 +1372,16 @@ NS_NewTableCellFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
return NS_OK;
}
-
-
-/* ----- methods from CellLayoutData ----- */
-
-void
-nsTableCellFrame::GetCellBorder(nsMargin& aBorder,
- nsTableFrame* aTableFrame)
+nsMargin*
+nsTableCellFrame::GetBorderWidth(float aPixelsToTwips,
+ nsMargin& aBorder) const
{
aBorder.left = aBorder.right = aBorder.top = aBorder.bottom = 0;
- if (nsnull==aTableFrame) {
- return;
- }
- if (NS_STYLE_BORDER_SEPARATE == aTableFrame->GetBorderCollapseStyle()) {
- const nsStyleBorder* borderData;
- GetStyleData(eStyleStruct_Border, (const nsStyleStruct*&)borderData);
- borderData->GetBorder(aBorder);
- }
- else {
- NS_ASSERTION(PR_FALSE, "not implemented");
- }
+ const nsStyleBorder* borderData;
+ GetStyleData(eStyleStruct_Border, (const nsStyleStruct*&)borderData);
+ borderData->GetBorder(aBorder);
+ return &aBorder;
}
NS_IMETHODIMP
@@ -1502,3 +1448,100 @@ nsTableCellFrame::SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const
return NS_OK;
}
#endif
+
+// nsBCTableCellFrame
+
+nsBCTableCellFrame::nsBCTableCellFrame()
+:nsTableCellFrame()
+{
+ mTopBorder = mRightBorder = mBottomBorder = mLeftBorder = 0;
+}
+
+nsBCTableCellFrame::~nsBCTableCellFrame()
+{
+}
+
+NS_IMETHODIMP
+nsBCTableCellFrame::GetFrameType(nsIAtom** aType) const
+{
+ NS_PRECONDITION(nsnull != aType, "null OUT parameter pointer");
+ *aType = nsLayoutAtoms::bcTableCellFrame;
+ NS_ADDREF(*aType);
+ return NS_OK;
+}
+
+#ifdef DEBUG
+NS_IMETHODIMP
+nsBCTableCellFrame::GetFrameName(nsAString& aResult) const
+{
+ return MakeFrameName(NS_LITERAL_STRING("BCTableCell"), aResult);
+}
+#endif
+
+void
+nsBCTableCellFrame::SetBorderWidth(const nsMargin& aBorder)
+{
+ mTopBorder = aBorder.top;
+ mRightBorder = aBorder.right;
+ mBottomBorder = aBorder.bottom;
+ mLeftBorder = aBorder.left;
+}
+
+nsMargin*
+nsBCTableCellFrame::GetBorderWidth(float aPixelsToTwips,
+ nsMargin& aBorder) const
+{
+ aBorder.top = (aPixelsToTwips) ? NSToCoordRound(aPixelsToTwips * mTopBorder) : mTopBorder;
+ aBorder.right = (aPixelsToTwips) ? NSToCoordRound(aPixelsToTwips * mRightBorder) : mRightBorder;
+ aBorder.bottom = (aPixelsToTwips) ? NSToCoordRound(aPixelsToTwips * mBottomBorder): mBottomBorder;
+ aBorder.left = (aPixelsToTwips) ? NSToCoordRound(aPixelsToTwips * mLeftBorder): mLeftBorder;
+ return &aBorder;
+}
+
+nscoord
+nsBCTableCellFrame::GetBorderWidth(PRUint8 aSide) const
+{
+ switch(aSide) {
+ case NS_SIDE_TOP:
+ return (PRUint8)mTopBorder;
+ case NS_SIDE_RIGHT:
+ return (PRUint8)mRightBorder;
+ case NS_SIDE_BOTTOM:
+ return (PRUint8)mBottomBorder;
+ default:
+ return (PRUint8)mLeftBorder;
+ }
+}
+
+void
+nsBCTableCellFrame::SetBorderWidth(PRUint8 aSide,
+ nscoord aValue)
+{
+ switch(aSide) {
+ case NS_SIDE_TOP:
+ mTopBorder = aValue;
+ break;
+ case NS_SIDE_RIGHT:
+ mRightBorder = aValue;
+ break;
+ case NS_SIDE_BOTTOM:
+ mBottomBorder = aValue;
+ break;
+ default:
+ mLeftBorder = aValue;
+ }
+}
+
+#ifdef DEBUG
+NS_IMETHODIMP
+nsBCTableCellFrame::SizeOf(nsISizeOfHandler* aHandler,
+ PRUint32* aResult) const
+{
+ if (!aResult) {
+ return NS_ERROR_NULL_POINTER;
+ }
+ PRUint32 sum = sizeof(*this);
+ *aResult = sum;
+ return NS_OK;
+}
+#endif
diff --git a/mozilla/layout/html/table/src/nsTableCellFrame.h b/mozilla/layout/html/table/src/nsTableCellFrame.h
index bba34cedb09..06474bfe35e 100644
--- a/mozilla/layout/html/table/src/nsTableCellFrame.h
+++ b/mozilla/layout/html/table/src/nsTableCellFrame.h
@@ -43,6 +43,7 @@
#include "nsTableRowFrame.h" // need to actually include this here to inline GetRowIndex
#include "nsIStyleContext.h"
#include "nsIPercentHeightObserver.h"
+#include "nsLayoutAtoms.h"
class nsTableFrame;
class nsHTMLValue;
@@ -266,6 +267,9 @@ public:
nsTableCellFrame* GetNextCell() const;
+ virtual nsMargin* GetBorderWidth(float aPixelsToTwips,
+ nsMargin& aBorder) const;
+
protected:
/** implement abstract method on nsHTMLContainerFrame */
virtual PRIntn GetSkipSides() const;
@@ -277,18 +281,11 @@ private:
// All these methods are support methods for RecalcLayoutData
nsIFrame* GetFrameAt(nsVoidArray* aList, PRInt32 aIndex);
- //XXX: aTableFrame can be removed as soon as border-collapse inherits correctly
- void GetCellBorder(nsMargin &aBorder, nsTableFrame *aTableFrame);
-
protected:
friend class nsTableRowFrame;
void MapBorderPadding(nsIPresContext* aPresContext);
- void MapHTMLBorderStyle(nsIPresContext* aPresContext,
- nsStyleBorder& aBorderStyle,
- nsTableFrame* aTableFrame);
-
void MapVAlignAttribute(nsIPresContext* aPresContext, nsTableFrame *aTableFrame);
void MapHAlignAttribute(nsIPresContext* aPresContext, nsTableFrame *aTableFrame);
@@ -421,6 +418,41 @@ inline void nsTableCellFrame::SetLastBlockHeight(nscoord aValue)
{
mBits.mLastBlockHeight = aValue;
}
+
+// nsBCTableCellFrame
+class nsBCTableCellFrame : public nsTableCellFrame
+{
+public:
+
+ nsBCTableCellFrame();
+
+ ~nsBCTableCellFrame();
+
+ NS_IMETHOD GetFrameType(nsIAtom** aType) const;
+
+ virtual nsMargin* GetBorderWidth(float aPixelsToTwips,
+ nsMargin& aBorder) const;
+ nscoord GetBorderWidth(PRUint8 aSide) const;
+
+ void SetBorderWidth(const nsMargin& aBorder);
+ void SetBorderWidth(PRUint8 aSide, nscoord aPixelValue);
+
+#ifdef DEBUG
+ NS_IMETHOD GetFrameName(nsAString& aResult) const;
+ NS_IMETHOD SizeOf(nsISizeOfHandler* aSizer, PRUint32* aResult) const;
+#endif
+
+private:
+
+ PRUint32 mTopBorder: 8;
+ PRUint32 mRightBorder: 8;
+ PRUint32 mBottomBorder: 8;
+ PRUint32 mLeftBorder: 8;
+};
+
+#define IS_TABLE_CELL(frameType)\
+((nsLayoutAtoms::tableCellFrame == frameType) || (nsLayoutAtoms::bcTableCellFrame == frameType))
+
#endif
diff --git a/mozilla/layout/html/table/src/nsTableColFrame.cpp b/mozilla/layout/html/table/src/nsTableColFrame.cpp
index ba970d16d9b..38368963da6 100644
--- a/mozilla/layout/html/table/src/nsTableColFrame.cpp
+++ b/mozilla/layout/html/table/src/nsTableColFrame.cpp
@@ -113,7 +113,8 @@ nsStyleCoord nsTableColFrame::GetStyleWidth() const
nsStyleCoord styleWidth = position->mWidth;
// the following should not be necessary since html.css defines table-col and
// :table-col to inherit. However, :table-col is not inheriting properly
- if (eStyleUnit_Auto == styleWidth.GetUnit()) {
+ if (eStyleUnit_Auto == styleWidth.GetUnit() ||
+ eStyleUnit_Inherit == styleWidth.GetUnit()) {
nsIFrame* parent;
GetParent(&parent);
nsCOMPtr styleContext;
@@ -305,6 +306,22 @@ nsTableColFrame::Init(nsIPresContext* aPresContext,
return rv;
}
+nsTableColFrame*
+nsTableColFrame::GetNextCol() const
+{
+ nsIFrame* childFrame;
+ GetNextSibling(&childFrame);
+ while (childFrame) {
+ nsCOMPtr frameType;
+ childFrame->GetFrameType(getter_AddRefs(frameType));
+ if (nsLayoutAtoms::tableColFrame == frameType.get()) {
+ return (nsTableColFrame*)childFrame;
+ }
+ childFrame->GetNextSibling(&childFrame);
+ }
+ return nsnull;
+}
+
NS_IMETHODIMP
nsTableColFrame::GetFrameType(nsIAtom** aType) const
{
diff --git a/mozilla/layout/html/table/src/nsTableColFrame.h b/mozilla/layout/html/table/src/nsTableColFrame.h
index ba2d0042b04..505a84b3726 100644
--- a/mozilla/layout/html/table/src/nsTableColFrame.h
+++ b/mozilla/layout/html/table/src/nsTableColFrame.h
@@ -102,6 +102,8 @@ public:
void SetColIndex (PRInt32 aColIndex);
+ nsTableColFrame* GetNextCol() const;
+
NS_IMETHOD Init(nsIPresContext* aPresContext,
nsIContent* aContent,
nsIFrame* aParent,
@@ -164,6 +166,11 @@ public:
void ResetSizingInfo();
+ nscoord GetLeftBorderWidth(float* aPixelsToTwips = nsnull);
+ void SetLeftBorderWidth(nscoord aWidth);
+ nscoord GetRightBorderWidth(float* aPixelsToTwips = nsnull);
+ void SetRightBorderWidth(nscoord aWidth);
+
void Dump(PRInt32 aIndent);
protected:
@@ -172,17 +179,46 @@ protected:
~nsTableColFrame();
// the starting index of the column (starting at 0) that this col object represents //
- PRInt32 mColIndex;
+ PRUint32 mColIndex: 16;
+ PRUint32 mLeftBorderWidth: 8; // stored as pixels
+ PRUint32 mRightBorderWidth: 8; // stored as pixels
+ // Widths including MIN_CON, DES_CON, FIX_CON, MIN_ADJ, DES_ADJ, FIX_ADJ, PCT, PCT_ADJ, MIN_PRO, FINAL
// Widths including MIN_CON, DES_CON, FIX_CON, MIN_ADJ, DES_ADJ, FIX_ADJ, PCT, PCT_ADJ, MIN_PRO, FINAL
// XXX these could be stored as pixels and converted to twips for a savings of 10 x 2 bytes.
nscoord mWidths[NUM_WIDTHS];
};
inline PRInt32 nsTableColFrame::GetColIndex() const
-{ return mColIndex; }
+{
+ return mColIndex;
+}
inline void nsTableColFrame::SetColIndex (PRInt32 aColIndex)
-{ mColIndex = aColIndex; }
+{
+ mColIndex = aColIndex;
+}
+
+inline nscoord nsTableColFrame::GetLeftBorderWidth(float* aPixelsToTwips)
+{
+ nscoord width = (aPixelsToTwips) ? NSToCoordRound(*aPixelsToTwips * mLeftBorderWidth) : mLeftBorderWidth;
+ return width;
+}
+
+inline void nsTableColFrame::SetLeftBorderWidth(nscoord aWidth)
+{
+ mLeftBorderWidth = aWidth;
+}
+
+inline nscoord nsTableColFrame::GetRightBorderWidth(float* aPixelsToTwips)
+{
+ nscoord width = (aPixelsToTwips) ? NSToCoordRound(*aPixelsToTwips * mRightBorderWidth) : mRightBorderWidth;
+ return width;
+}
+
+inline void nsTableColFrame::SetRightBorderWidth(nscoord aWidth)
+{
+ mRightBorderWidth = aWidth;
+}
#endif
diff --git a/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp b/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp
index 15c7dab5216..41a96c8d000 100644
--- a/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp
+++ b/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp
@@ -250,29 +250,6 @@ nsTableColGroupFrame::SetInitialChildList(nsIPresContext* aPresContext,
return NS_OK;
}
- nsIFrame* kidFrame = aChildList;
- while (kidFrame) {
- nsIAtom* kidType;
- kidFrame->GetFrameType(&kidType);
- if (nsLayoutAtoms::tableColFrame == kidType) {
- // Set the preliminary values for the column frame
- PRInt32 span = ((nsTableColFrame*)kidFrame)->GetSpan();
- if (span > 1) {
- nsTableColFrame* firstSpannedCol;
- tableFrame->CreateAnonymousColFrames(*aPresContext, *this, span - 1, eColAnonymousCol,
- PR_FALSE, (nsTableColFrame*)kidFrame, (nsIFrame **)&firstSpannedCol);
- nsIFrame* spanner = kidFrame;
- kidFrame->GetNextSibling(&kidFrame); // need to do this before we insert the new frames
- nsFrameList newChildren(aChildList); // used as a convience to hook up siblings
- newChildren.InsertFrames(this, (nsTableColFrame*)spanner, (nsIFrame *)firstSpannedCol);
- NS_RELEASE(kidType);
- continue;
- }
- }
- NS_IF_RELEASE(kidType);
- kidFrame->GetNextSibling(&kidFrame);
- }
-
mFrames.AppendFrames(this, aChildList);
return NS_OK;
}
diff --git a/mozilla/layout/html/table/src/nsTableFrame.cpp b/mozilla/layout/html/table/src/nsTableFrame.cpp
index 7a2d5dc94d6..718136af383 100644
--- a/mozilla/layout/html/table/src/nsTableFrame.cpp
+++ b/mozilla/layout/html/table/src/nsTableFrame.cpp
@@ -38,7 +38,6 @@
#include "nsCOMPtr.h"
#include "nsVoidArray.h"
#include "nsTableFrame.h"
-#include "nsTableBorderCollapser.h"
#include "nsIRenderingContext.h"
#include "nsIStyleContext.h"
#include "nsStyleConsts.h"
@@ -75,6 +74,7 @@
#include "nsIScrollableFrame.h"
#include "nsHTMLReflowCommand.h"
#include "nsIFrameManager.h"
+#include "nsStyleUtil.h"
// helper function for dealing with placeholder for positioned/floated table
static void GetPlaceholderFor(nsIPresContext& aPresContext, nsIFrame& aFrame, nsIFrame** aPlaceholder);
@@ -108,17 +108,19 @@ struct nsTableReflowState {
// The first body section row group frame, i.e. not a header or footer
nsIFrame* firstBodySection;
- nsTableReflowState(const nsHTMLReflowState& aReflowState,
+ nsTableReflowState(nsIPresContext& aPresContext,
+ const nsHTMLReflowState& aReflowState,
nsTableFrame& aTableFrame,
nsReflowReason aReason,
nscoord aAvailWidth,
nscoord aAvailHeight)
: reflowState(aReflowState)
{
- Init(aTableFrame, aReason, aAvailWidth, aAvailHeight);
+ Init(aPresContext, aTableFrame, aReason, aAvailWidth, aAvailHeight);
}
- void Init(nsTableFrame& aTableFrame,
+ void Init(nsIPresContext& aPresContext,
+ nsTableFrame& aTableFrame,
nsReflowReason aReason,
nscoord aAvailWidth,
nscoord aAvailHeight)
@@ -126,7 +128,7 @@ struct nsTableReflowState {
reason = aReason;
nsTableFrame* table = (nsTableFrame*)aTableFrame.GetFirstInFlow();
- nsMargin borderPadding = table->GetBorderPadding(reflowState);
+ nsMargin borderPadding = table->GetChildAreaOffset(aPresContext, &reflowState);
x = borderPadding.left;
y = borderPadding.top;
@@ -145,23 +147,16 @@ struct nsTableReflowState {
firstBodySection = nsnull;
}
- nsTableReflowState(const nsHTMLReflowState& aReflowState,
+ nsTableReflowState(nsIPresContext& aPresContext,
+ const nsHTMLReflowState& aReflowState,
nsTableFrame& aTableFrame)
: reflowState(aReflowState)
{
- Init(aTableFrame, aReflowState.reason, aReflowState.availableWidth, aReflowState.availableHeight);
+ Init(aPresContext, aTableFrame, aReflowState.reason, aReflowState.availableWidth, aReflowState.availableHeight);
}
};
-nscoord
-GetHorBorderPaddingWidth(const nsHTMLReflowState& aReflowState,
- nsTableFrame* aTableFrame)
-{
- nsMargin borderPadding = aTableFrame->GetBorderPadding(aReflowState);
- return borderPadding.left + borderPadding.right;
-}
-
/********************************************************************************
** nsTableFrame **
********************************************************************************/
@@ -169,6 +164,18 @@ GetHorBorderPaddingWidth(const nsHTMLReflowState& aReflowState,
static PRInt32 gRflCount = 0;
#endif
+struct BCPropertyData
+{
+ BCPropertyData() { mDamageArea.x = mDamageArea.y = mDamageArea.width = mDamageArea.height =
+ mTopBorderWidth = mRightBorderWidth = mBottomBorderWidth = mLeftBorderWidth = 0; }
+ nsRect mDamageArea;
+ PRUint8 mTopBorderWidth;
+ PRUint8 mRightBorderWidth;
+ PRUint8 mBottomBorderWidth;
+ PRUint8 mLeftBorderWidth;
+};
+
+
NS_IMETHODIMP
nsTableFrame::GetFrameType(nsIAtom** aType) const
{
@@ -193,6 +200,8 @@ nsTableFrame::nsTableFrame()
mBits.mNeedStrategyBalance = PR_TRUE;
mBits.mCellSpansPctCol = PR_FALSE;
mBits.mRequestedTimeoutReflow = PR_FALSE;
+ mBits.mNeedToCalcBCBorders = PR_FALSE;
+ mBits.mIsBorderCollapse = PR_FALSE;
#ifdef DEBUG_TABLE_REFLOW_TIMING
mTimer = new nsReflowTimer(this);
@@ -236,11 +245,6 @@ nsTableFrame::Init(nsIPresContext* aPresContext,
{
nsresult rv;
- // Create the cell map
- // XXX Why do we do this for continuing frames?
- mCellMap = new nsTableCellMap(aPresContext, *this);
- if (!mCellMap) return NS_ERROR_OUT_OF_MEMORY;
-
// Let the base class do its processing
rv = nsHTMLContainerFrame::Init(aPresContext, aContent, aParent, aContext,
aPrevInFlow);
@@ -248,6 +252,16 @@ nsTableFrame::Init(nsIPresContext* aPresContext,
// record that children that are ignorable whitespace should be excluded
mState |= NS_FRAME_EXCLUDE_IGNORABLE_WHITESPACE;
+ // see if border collapse is on, if so set it
+ const nsStyleTableBorder* tableStyle =
+ (const nsStyleTableBorder*)mStyleContext->GetStyleData(eStyleStruct_TableBorder);
+ PRBool borderCollapse = (NS_STYLE_BORDER_COLLAPSE == tableStyle->mBorderCollapse);
+ SetBorderCollapse(borderCollapse);
+ // Create the cell map
+ // XXX Why do we do this for continuing frames?
+ mCellMap = new nsTableCellMap(aPresContext, *this, borderCollapse);
+ if (!mCellMap) return NS_ERROR_OUT_OF_MEMORY;
+
if (aPrevInFlow) {
// set my width, because all frames in a table flow are the same width and
// code in nsTableOuterFrame depends on this being set
@@ -477,10 +491,11 @@ nsTableFrame::SetInitialChildList(nsIPresContext* aPresContext,
// anonymous ones due to cells in rows.
InsertColGroups(*aPresContext, 0, mColGroups.FirstChild());
AppendRowGroups(*aPresContext, mFrames.FirstChild());
- }
-
- if (HasGroupRules()) {
- ProcessGroupRules(aPresContext);
+ // calc collapsing borders if this is the default (row group, col group, child list)
+ if (!aChildList && IsBorderCollapse()) {
+ nsRect damageArea(0, 0, GetColCount(), GetRowCount());
+ SetBCDamageArea(*aPresContext, damageArea);
+ }
}
return rv;
@@ -500,7 +515,7 @@ void nsTableFrame::AttributeChangedFor(nsIPresContext* aPresContext,
{
nsIAtom* frameType;
aFrame->GetFrameType(&frameType);
- if (nsLayoutAtoms::tableCellFrame == frameType) {
+ if (IS_TABLE_CELL(frameType)) {
if ((nsHTMLAtoms::rowspan == aAttribute) ||
(nsHTMLAtoms::colspan == aAttribute)) {
nsTableCellMap* cellMap = GetCellMap();
@@ -550,7 +565,7 @@ PRInt32 nsTableFrame::GetRowCount () const
}
/* return the col count including dead cols */
-PRInt32 nsTableFrame::GetColCount ()
+PRInt32 nsTableFrame::GetColCount () const
{
PRInt32 colCount = 0;
nsTableCellMap* cellMap = GetCellMap();
@@ -562,7 +577,7 @@ PRInt32 nsTableFrame::GetColCount ()
}
/* return the effective col count */
-PRInt32 nsTableFrame::GetEffectiveColCount ()
+PRInt32 nsTableFrame::GetEffectiveColCount() const
{
PRInt32 colCount = GetColCount();
// don't count cols at the end that don't have originating cells
@@ -659,66 +674,6 @@ PRInt32 nsTableFrame::GetEffectiveCOLSAttribute()
return result;
}
-PRBool nsTableFrame::HasGroupRules() const
-{
- const nsStyleTable* tableStyle = nsnull;
- GetStyleData(eStyleStruct_Table, (const nsStyleStruct *&)tableStyle);
- if (NS_STYLE_TABLE_RULES_GROUPS == tableStyle->mRules) {
- return PR_TRUE;
- }
- return PR_FALSE;
-}
-
-// this won't work until bug 12948 is resolved and col groups are considered
-void nsTableFrame::ProcessGroupRules(nsIPresContext* aPresContext)
-{
-#if 0
- // The RULES code below has been disabled because collapsing borders have been disabled
- // and RULES depend on collapsing borders
- PRInt32 numCols = GetColCount();
-
- // process row groups
- nsIFrame* iFrame;
- for (iFrame = mFrames.FirstChild(); iFrame; iFrame->GetNextSibling(&iFrame)) {
- nsIAtom* frameType;
- iFrame->GetFrameType(&frameType);
- if (nsLayoutAtoms::tableRowGroupFrame == frameType) {
- nsTableRowGroupFrame* rgFrame = (nsTableRowGroupFrame *)iFrame;
- PRInt32 startRow = rgFrame->GetStartRowIndex();
- PRInt32 numGroupRows = rgFrame->GetRowCount();
- PRInt32 endRow = startRow + numGroupRows - 1;
- if (startRow == endRow) {
- continue;
- }
- for (PRInt32 rowX = startRow; rowX <= endRow; rowX++) {
- for (PRInt32 colX = 0; colX < numCols; colX++) {
- PRBool originates;
- nsTableCellFrame* cell = GetCellInfoAt(rowX, colX, &originates);
- if (originates) {
- nsCOMPtr styleContext;
- cell->GetStyleContext(getter_AddRefs(styleContext));
- nsStyleBorder* border = (nsStyleBorder*)styleContext->GetMutableStyleData(eStyleStruct_Border);
- if (rowX == startRow) {
- border->SetBorderStyle(NS_SIDE_BOTTOM, NS_STYLE_BORDER_STYLE_NONE);
- }
- else if (rowX == endRow) {
- border->SetBorderStyle(NS_SIDE_TOP, NS_STYLE_BORDER_STYLE_NONE);
- }
- else {
- border->SetBorderStyle(NS_SIDE_TOP, NS_STYLE_BORDER_STYLE_NONE);
- border->SetBorderStyle(NS_SIDE_BOTTOM, NS_STYLE_BORDER_STYLE_NONE);
- }
- styleContext->RecalcAutomaticData(aPresContext);
- }
- }
- }
- }
- NS_IF_RELEASE(frameType);
- }
-#endif
-}
-
-
void nsTableFrame::AdjustRowIndices(nsIPresContext* aPresContext,
PRInt32 aRowIndex,
PRInt32 aAdjustment)
@@ -833,6 +788,11 @@ void nsTableFrame::InsertCol(nsIPresContext& aPresContext,
}
}
}
+ // for now, just bail and recalc all of the collapsing borders
+ if (IsBorderCollapse()) {
+ nsRect damageArea(0, 0, PR_MAX(1, GetColCount()), PR_MAX(1, GetRowCount()));
+ SetBCDamageArea(aPresContext, damageArea);
+ }
}
void nsTableFrame::RemoveCol(nsIPresContext& aPresContext,
@@ -850,6 +810,11 @@ void nsTableFrame::RemoveCol(nsIPresContext& aPresContext,
CreateAnonymousColFrames(aPresContext, 1, eColAnonymousCell, PR_TRUE);
}
}
+ // for now, just bail and recalc all of the collapsing borders
+ if (IsBorderCollapse()) {
+ nsRect damageArea(0, 0, GetColCount(), GetRowCount());
+ SetBCDamageArea(aPresContext, damageArea);
+ }
}
/** Get the cell map for this table frame. It is not always mCellMap.
@@ -1075,14 +1040,16 @@ nsTableFrame::CreateAnonymousColFrames(nsIPresContext& aPresContext,
}
}
-PRInt32 nsTableFrame::AppendCell(nsIPresContext& aPresContext,
- nsTableCellFrame& aCellFrame,
- PRInt32 aRowIndex)
+void
+nsTableFrame::AppendCell(nsIPresContext& aPresContext,
+ nsTableCellFrame& aCellFrame,
+ PRInt32 aRowIndex)
{
PRInt32 colIndex = 0;
nsTableCellMap* cellMap = GetCellMap();
if (cellMap) {
- colIndex = cellMap->AppendCell(aCellFrame, aRowIndex, PR_TRUE);
+ nsRect damageArea(0,0,0,0);
+ cellMap->AppendCell(aCellFrame, aRowIndex, PR_TRUE, damageArea);
PRInt32 numColsInMap = GetColCount();
PRInt32 numColsInCache = mColFrames.Count();
PRInt32 numColsToAdd = numColsInMap - numColsInCache;
@@ -1090,8 +1057,10 @@ PRInt32 nsTableFrame::AppendCell(nsIPresContext& aPresContext,
// this sets the child list, updates the col cache and cell map
CreateAnonymousColFrames(aPresContext, numColsToAdd, eColAnonymousCell, PR_TRUE);
}
+ if (IsBorderCollapse()) {
+ SetBCDamageArea(aPresContext, damageArea);
+ }
}
- return colIndex;
}
void nsTableFrame::InsertCells(nsIPresContext& aPresContext,
@@ -1101,7 +1070,8 @@ void nsTableFrame::InsertCells(nsIPresContext& aPresContext,
{
nsTableCellMap* cellMap = GetCellMap();
if (cellMap) {
- cellMap->InsertCells(aCellFrames, aRowIndex, aColIndexBefore);
+ nsRect damageArea(0,0,0,0);
+ cellMap->InsertCells(aCellFrames, aRowIndex, aColIndexBefore, damageArea);
PRInt32 numColsInMap = GetColCount();
PRInt32 numColsInCache = mColFrames.Count();
PRInt32 numColsToAdd = numColsInMap - numColsInCache;
@@ -1109,6 +1079,9 @@ void nsTableFrame::InsertCells(nsIPresContext& aPresContext,
// this sets the child list, updates the col cache and cell map
CreateAnonymousColFrames(aPresContext, numColsToAdd, eColAnonymousCell, PR_TRUE);
}
+ if (IsBorderCollapse()) {
+ SetBCDamageArea(aPresContext, damageArea);
+ }
}
}
@@ -1145,7 +1118,8 @@ void nsTableFrame::RemoveCell(nsIPresContext& aPresContext,
{
nsTableCellMap* cellMap = GetCellMap();
if (cellMap) {
- cellMap->RemoveCell(aCellFrame, aRowIndex);
+ nsRect damageArea(0,0,0,0);
+ cellMap->RemoveCell(aCellFrame, aRowIndex, damageArea);
PRInt32 numColsInMap = GetColCount(); // cell map's notion of num cols
PRInt32 numColsInCache = mColFrames.Count();
if (numColsInCache > numColsInMap) {
@@ -1156,6 +1130,10 @@ void nsTableFrame::RemoveCell(nsIPresContext& aPresContext,
}
}
else NS_ASSERTION(numColsInCache == numColsInMap, "cell map has too many cols");
+
+ if (IsBorderCollapse()) {
+ SetBCDamageArea(aPresContext, damageArea);
+ }
}
}
@@ -1217,9 +1195,10 @@ nsTableFrame::InsertRows(nsIPresContext& aPresContext,
PRInt32 numColsToAdd = 0;
nsTableCellMap* cellMap = GetCellMap();
if (cellMap) {
+ nsRect damageArea(0,0,0,0);
PRInt32 origNumRows = cellMap->GetRowCount();
PRInt32 numNewRows = aRowFrames.Count();
- cellMap->InsertRows(&aPresContext, aRowGroupFrame, aRowFrames, aRowIndex, aConsiderSpans);
+ cellMap->InsertRows(&aPresContext, aRowGroupFrame, aRowFrames, aRowIndex, aConsiderSpans, damageArea);
PRInt32 numColsInMap = GetColCount(); // cell map's notion of num cols
PRInt32 numColsInCache = mColFrames.Count();
numColsToAdd = numColsInMap - numColsInCache;
@@ -1237,6 +1216,9 @@ nsTableFrame::InsertRows(nsIPresContext& aPresContext,
nsTableRowFrame* rowFrame = (nsTableRowFrame *) aRowFrames.ElementAt(rowX);
rowFrame->SetRowIndex(aRowIndex + rowX);
}
+ if (IsBorderCollapse()) {
+ SetBCDamageArea(aPresContext, damageArea);
+ }
}
//printf("insertRowsAfter \n");
@@ -1262,7 +1244,7 @@ void nsTableFrame::RemoveRows(nsIPresContext& aPresContext,
for (nsIFrame* kidFrame = aFirstFrame.FirstChild(); (kidFrame && !stopAsking); kidFrame = kidFrame->GetNextSibling()) {
nsCOMPtr kidType;
kidFrame->GetFrameType(getter_AddRefs(frameType));
- if (nsLayoutAtoms::tableCellFrame == kidType.get()) {
+ if (IS_TABLE_CELL(kidType.get())) {
nsTableCellFrame* cellFrame = (nsTableCellFrame*)kidFrame;
stopTelling = tableFrame->CellChangedWidth(*cellFrame, cellFrame->GetPass1MaxElementWidth(),
cellFrame->GetMaximumWidth(), PR_TRUE);
@@ -1275,7 +1257,8 @@ void nsTableFrame::RemoveRows(nsIPresContext& aPresContext,
PRInt32 firstRowIndex = aFirstRowFrame.GetRowIndex();
nsTableCellMap* cellMap = GetCellMap();
if (cellMap) {
- cellMap->RemoveRows(&aPresContext, firstRowIndex, aNumRowsToRemove, aConsiderSpans);
+ nsRect damageArea(0,0,0,0);
+ cellMap->RemoveRows(&aPresContext, firstRowIndex, aNumRowsToRemove, aConsiderSpans, damageArea);
// only remove cols that are of type eTypeAnonymous cell (they are at the end)
PRInt32 numColsInMap = GetColCount(); // cell map's notion of num cols
PRInt32 numColsInCache = mColFrames.Count();
@@ -1287,6 +1270,10 @@ void nsTableFrame::RemoveRows(nsIPresContext& aPresContext,
}
}
else NS_ASSERTION(numColsInCache == numColsInMap, "cell map has too many cols");
+
+ if (IsBorderCollapse()) {
+ SetBCDamageArea(aPresContext, damageArea);
+ }
}
AdjustRowIndices(&aPresContext, firstRowIndex, -aNumRowsToRemove);
//printf("removeRowsAfter\n");
@@ -1307,7 +1294,7 @@ void nsTableFrame::AppendRowGroups(nsIPresContext& aPresContext,
nsTableRowGroupFrame*
nsTableFrame::GetRowGroupFrame(nsIFrame* aFrame,
- nsIAtom* aFrameTypeIn)
+ nsIAtom* aFrameTypeIn) const
{
nsIFrame* rgFrame = nsnull;
nsIAtom* frameType = aFrameTypeIn;
@@ -1479,12 +1466,12 @@ nsTableFrame::Paint(nsIPresContext* aPresContext,
}
PRIntn skipSides = GetSkipSides();
- if (NS_STYLE_BORDER_SEPARATE == GetBorderCollapseStyle()) {
- nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this,
- aDirtyRect, rect, *border, mStyleContext, skipSides);
+ if (IsBorderCollapse()) {
+ PaintBCBorders(aPresContext, aRenderingContext, aDirtyRect);
}
else {
- // tbd
+ nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this,
+ aDirtyRect, rect, *border, mStyleContext, skipSides);
}
}
}
@@ -1703,6 +1690,7 @@ nsTableFrame::SetColumnDimensions(nsIPresContext* aPresContext,
nscoord aHeight,
const nsMargin& aBorderPadding)
{
+ if (!aPresContext) ABORT0();
nscoord colHeight = aHeight -= aBorderPadding.top + aBorderPadding.bottom;
nscoord cellSpacingX = GetCellSpacingX();
@@ -1831,7 +1819,7 @@ nsTableFrame::NotifyAncestorsOfSpecialReflow(nsIFrame& aFrame)
for (aFrame.GetParent(&parent); parent; parent->GetParent(&parent)) {
nsCOMPtr frameType;
parent->GetFrameType(getter_AddRefs(frameType));
- if (nsLayoutAtoms::tableCellFrame == frameType.get()) {
+ if (IS_TABLE_CELL(frameType.get())) {
((nsTableCellFrame*)parent)->SetNeedSpecialReflow(PR_TRUE);
}
else if (nsLayoutAtoms::tableRowFrame == frameType.get()) {
@@ -1901,8 +1889,13 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext,
PRBool isPaginated;
aPresContext->IsPaginated(&isPaginated);
-
- PRBool doCollapse = PR_FALSE;
+
+ // see if collapsing borders need to be calculated
+ if (!mPrevInFlow && IsBorderCollapse() && NeedToCalcBCBorders()) {
+ GET_TWIPS_TO_PIXELS(aPresContext, p2t);
+ CalcBCBorders(*aPresContext);
+ }
+ PRBool doCollapse = PR_FALSE; // collapsing rows, cols, etc.
aDesiredSize.width = aReflowState.availableWidth;
@@ -1926,7 +1919,7 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext,
// only do pass1 reflow on an auto layout table
nsReflowReason reason = (eReflowReason_Initial == aReflowState.reason)
? eReflowReason_Initial : eReflowReason_StyleChange;
- nsTableReflowState reflowState(aReflowState, *this, reason,
+ nsTableReflowState reflowState(*aPresContext, aReflowState, *this, reason,
NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
// reflow the children
ReflowChildren(aPresContext, reflowState, !HaveReflowedColGroups(), PR_FALSE, aStatus);
@@ -1982,7 +1975,7 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext,
}
// see if an extra reflow will be necessary in pagination mode when there is a specified table height
else if (isPaginated && (NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight)) {
- nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aReflowState);
+ nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aPresContext, aReflowState);
if ((tableSpecifiedHeight > 0) &&
(tableSpecifiedHeight != NS_UNCONSTRAINEDSIZE)) {
SetNeedToInitiateSpecialReflow(PR_TRUE);
@@ -2047,7 +2040,8 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext,
}
#endif
- SetColumnDimensions(aPresContext, aDesiredSize.height, aReflowState.mComputedBorderPadding);
+ nsMargin borderPadding = GetChildAreaOffset(*aPresContext, &aReflowState);
+ SetColumnDimensions(aPresContext, aDesiredSize.height, borderPadding);
if (doCollapse) {
AdjustForCollapsingRows(aPresContext, aDesiredSize.height);
AdjustForCollapsingCols(aPresContext, aDesiredSize.width);
@@ -2111,7 +2105,7 @@ nsTableFrame::ReflowTable(nsIPresContext* aPresContext,
// Constrain our reflow width to the computed table width (of the 1st in flow).
// and our reflow height to our avail height minus border, padding, cellspacing
aDesiredSize.width = GetDesiredWidth();
- nsTableReflowState reflowState(aReflowState, *this, aReason,
+ nsTableReflowState reflowState(*aPresContext, aReflowState, *this, aReason,
aDesiredSize.width, aAvailHeight);
ReflowChildren(aPresContext, reflowState, haveReflowedColGroups, PR_FALSE, aStatus);
@@ -2292,7 +2286,7 @@ nsTableFrame::CollapseRowGroupIfNecessary(nsIPresContext* aPresContext,
PRInt32 numCols = cellMap->GetColCount();
nsTableCellFrame* lastCell = nsnull;
for (int colX = 0; colX < numCols; colX++) {
- CellData* cellData = cellMap->GetCellAt(aRowX, colX);
+ CellData* cellData = cellMap->GetDataAt(aRowX, colX);
if (cellData && cellData->IsSpan()) { // a cell above is spanning into here
// adjust the real cell's rect only once
nsTableCellFrame* realCell = nsnull;
@@ -2389,7 +2383,7 @@ NS_METHOD nsTableFrame::AdjustForCollapsingCols(nsIPresContext* aPresContext,
nsTableCellFrame* lastCell = nsnull;
nsTableCellFrame* cellFrame = nsnull;
for (PRInt32 rowX = 0; rowX < numRows; rowX++) {
- CellData* cellData = cellMap->GetCellAt(rowX, colX);
+ CellData* cellData = cellMap->GetDataAt(rowX, colX);
nsRect cellRect;
if (cellData) {
if (cellData->IsOrig()) { // the cell originates at (rowX, colX)
@@ -2670,7 +2664,7 @@ nsTableFrame::IncrementalReflow(nsIPresContext* aPresContext,
nsTableFrame* table = (nsTableFrame*)GetFirstInFlow();
lastWidth = table->mRect.width;
}
- nsTableReflowState state(aReflowState, *this, eReflowReason_Incremental,
+ nsTableReflowState state(*aPresContext, aReflowState, *this, eReflowReason_Incremental,
lastWidth, aReflowState.availableHeight);
// determine if this frame is the target or not
@@ -2721,7 +2715,7 @@ nsTableFrame::IR_TargetIsMe(nsIPresContext* aPresContext,
break;
case eReflowType_ReflowDirty: {
// reflow the dirty children
- nsTableReflowState reflowState(aReflowState.reflowState, *this, eReflowReason_Initial,
+ nsTableReflowState reflowState(*aPresContext, aReflowState.reflowState, *this, eReflowReason_Initial,
aReflowState.availSize.width, aReflowState.availSize.height);
PRBool reflowedAtLeastOne;
ReflowChildren(aPresContext, reflowState, PR_FALSE, PR_TRUE, aStatus, &reflowedAtLeastOne);
@@ -2753,25 +2747,127 @@ NS_METHOD nsTableFrame::IR_StyleChanged(nsIPresContext* aPresContext,
return NS_OK;
}
-nsMargin
-nsTableFrame::GetBorderPadding(const nsHTMLReflowState& aReflowState) const
+static void
+DivideBCBorderSize(nscoord aPixelSize,
+ nscoord& aSmallHalf,
+ nscoord& aLargeHalf)
+{
+ aSmallHalf = aPixelSize / 2;
+ aLargeHalf = ((aSmallHalf + aSmallHalf) < aPixelSize) ? aSmallHalf + 1 : aSmallHalf;
+}
+
+nsMargin*
+nsTableFrame::GetBCBorder(nsIPresContext& aPresContext,
+ PRBool aInnerBorderOnly,
+ nsMargin& aBorder) const
+{
+ aBorder.top = aBorder.right = aBorder.bottom = aBorder.left = 0;
+
+ GET_PIXELS_TO_TWIPS(&aPresContext, p2t);
+ BCPropertyData* propData =
+ (BCPropertyData*)nsTableFrame::GetProperty(&aPresContext, (nsIFrame*)this, nsLayoutAtoms::tableBCProperty, PR_FALSE);
+ if (propData) {
+ nsCompatibility mode;
+ aPresContext.GetCompatibilityMode(&mode);
+ if ((eCompatibility_Standard == mode) || aInnerBorderOnly) {
+ nscoord smallHalf, largeHalf;
+
+ DivideBCBorderSize(propData->mTopBorderWidth, smallHalf, largeHalf);
+ aBorder.top += NSToCoordRound(p2t * (float)smallHalf);
+
+ DivideBCBorderSize(propData->mRightBorderWidth, smallHalf, largeHalf);
+ aBorder.right += NSToCoordRound(p2t * (float)largeHalf);
+
+ DivideBCBorderSize(propData->mBottomBorderWidth, smallHalf, largeHalf);
+ aBorder.bottom += NSToCoordRound(p2t * (float)largeHalf);
+
+ DivideBCBorderSize(propData->mLeftBorderWidth, smallHalf, largeHalf);
+ aBorder.left += NSToCoordRound(p2t * (float)smallHalf);
+ }
+ else {
+ aBorder.top += NSToCoordRound(p2t * (float)propData->mTopBorderWidth);
+ aBorder.right += NSToCoordRound(p2t * (float)propData->mRightBorderWidth);
+ aBorder.bottom += NSToCoordRound(p2t * (float)propData->mBottomBorderWidth);
+ aBorder.left += NSToCoordRound(p2t * (float)propData->mLeftBorderWidth);
+ }
+ }
+ return &aBorder;
+}
+
+static
+void GetSeparateModelBorderPadding(nsIPresContext& aPresContext,
+ const nsHTMLReflowState* aReflowState,
+ nsIStyleContext& aStyleContext,
+ nsMargin& aBorderPadding)
{
const nsStyleBorder* border =
- (const nsStyleBorder*)mStyleContext->GetStyleData(eStyleStruct_Border);
- nsMargin borderPadding;
- border->GetBorder(borderPadding);
- borderPadding += aReflowState.mComputedPadding;
- return borderPadding;
+ (const nsStyleBorder*)aStyleContext.GetStyleData(eStyleStruct_Border);
+ border->GetBorder(aBorderPadding);
+ if (aReflowState) {
+ aBorderPadding += aReflowState->mComputedPadding;
+ }
+}
+
+nsMargin
+nsTableFrame::GetChildAreaOffset(nsIPresContext& aPresContext,
+ const nsHTMLReflowState* aReflowState) const
+{
+ nsMargin offset(0,0,0,0);
+ if (IsBorderCollapse()) {
+ nsCompatibility mode;
+ aPresContext.GetCompatibilityMode(&mode);
+ if (eCompatibility_NavQuirks == mode) {
+ nsTableFrame* firstInFlow = (nsTableFrame*)GetFirstInFlow(); if (!firstInFlow) ABORT1(offset);
+ nscoord smallHalf, largeHalf;
+ GET_PIXELS_TO_TWIPS(&aPresContext, p2t);
+ BCPropertyData* propData =
+ (BCPropertyData*)nsTableFrame::GetProperty(&aPresContext, (nsIFrame*)firstInFlow, nsLayoutAtoms::tableBCProperty, PR_FALSE);
+ if (!propData) ABORT1(offset);
+
+ DivideBCBorderSize(propData->mTopBorderWidth, smallHalf, largeHalf);
+ offset.top += NSToCoordRound(p2t * (float)largeHalf);
+
+ DivideBCBorderSize(propData->mRightBorderWidth, smallHalf, largeHalf);
+ offset.right += NSToCoordRound(p2t * (float)smallHalf);
+
+ DivideBCBorderSize(propData->mBottomBorderWidth, smallHalf, largeHalf);
+ offset.bottom += NSToCoordRound(p2t * (float)smallHalf);
+
+ DivideBCBorderSize(propData->mLeftBorderWidth, smallHalf, largeHalf);
+ offset.left += NSToCoordRound(p2t * (float)largeHalf);
+ }
+ }
+ else {
+ if (!mStyleContext) ABORT1(offset);
+ GetSeparateModelBorderPadding(aPresContext, aReflowState, *mStyleContext, offset);
+ }
+ return offset;
+}
+
+nsMargin
+nsTableFrame::GetContentAreaOffset(nsIPresContext& aPresContext,
+ const nsHTMLReflowState* aReflowState) const
+{
+ nsMargin offset(0,0,0,0);
+ if (IsBorderCollapse()) {
+ GetBCBorder(aPresContext, PR_FALSE, offset);
+ }
+ else {
+ if (!mStyleContext) ABORT1(offset);
+ GetSeparateModelBorderPadding(aPresContext, aReflowState, *mStyleContext, offset);
+ }
+ return offset;
}
// Recovers the reflow state to what it should be if aKidFrame is about to be
// reflowed. Restores y, footerFrame, firstBodySection and availSize.height (if
// the height is constrained)
nsresult
-nsTableFrame::RecoverState(nsTableReflowState& aReflowState,
+nsTableFrame::RecoverState(nsIPresContext& aPresContext,
+ nsTableReflowState& aReflowState,
nsIFrame* aKidFrame)
{
- nsMargin borderPadding = GetBorderPadding(aReflowState.reflowState);
+ nsMargin borderPadding = GetChildAreaOffset(aPresContext, &aReflowState.reflowState);
aReflowState.y = borderPadding.top;
nscoord cellSpacingY = GetCellSpacingY();
@@ -2827,6 +2923,23 @@ nsTableFrame::RecoverState(nsTableReflowState& aReflowState,
return NS_OK;
}
+void
+nsTableFrame::InitChildReflowState(nsIPresContext& aPresContext,
+ nsHTMLReflowState& aReflowState)
+{
+ nsMargin collapseBorder;
+ nsMargin padding(0,0,0,0);
+ nsMargin* pCollapseBorder = nsnull;
+ if (IsBorderCollapse()) {
+ nsTableRowGroupFrame* rgFrame = GetRowGroupFrame(aReflowState.frame);
+ if (rgFrame) {
+ GET_PIXELS_TO_TWIPS(&aPresContext, p2t);
+ pCollapseBorder = rgFrame->GetBCBorderWidth(p2t, collapseBorder);
+ }
+ }
+ aReflowState.Init(&aPresContext, -1, -1, pCollapseBorder, &padding);
+}
+
NS_METHOD
nsTableFrame::IR_TargetIsChild(nsIPresContext* aPresContext,
nsTableReflowState& aReflowState,
@@ -2834,9 +2947,10 @@ nsTableFrame::IR_TargetIsChild(nsIPresContext* aPresContext,
nsIFrame* aNextFrame)
{
+ if (!aPresContext) ABORT1(NS_ERROR_NULL_POINTER);
nsresult rv;
// Recover the state as if aNextFrame is about to be reflowed
- RecoverState(aReflowState, aNextFrame);
+ RecoverState(*aPresContext, aReflowState, aNextFrame);
// Remember the old rect
nsRect oldKidRect;
@@ -2844,8 +2958,10 @@ nsTableFrame::IR_TargetIsChild(nsIPresContext* aPresContext,
// Pass along the reflow command, don't request a max element size, rows will do that
nsHTMLReflowMetrics desiredSize(nsnull);
- nsHTMLReflowState kidReflowState(aPresContext, aReflowState.reflowState,
- aNextFrame, aReflowState.availSize);
+ nsSize kidAvailSize(aReflowState.availSize);
+ nsHTMLReflowState kidReflowState(aPresContext, aReflowState.reflowState, aNextFrame,
+ kidAvailSize, aReflowState.reason);
+ InitChildReflowState(*aPresContext, kidReflowState);
rv = ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState,
aReflowState.x, aReflowState.y, 0, aStatus);
@@ -2969,7 +3085,7 @@ nsTableFrame::OrderRowGroups(nsVoidArray& aChildren,
PRUint32& aNumRowGroups,
nsIFrame** aFirstBody,
nsTableRowGroupFrame** aHead,
- nsTableRowGroupFrame** aFoot)
+ nsTableRowGroupFrame** aFoot) const
{
aChildren.Clear();
nsIFrame* head = nsnull;
@@ -3069,6 +3185,10 @@ nsTableFrame::ReflowChildren(nsIPresContext* aPresContext,
PRBool isPaginated;
aPresContext->IsPaginated(&isPaginated);
+ nsMargin collapseBorder;
+ nsMargin padding(0,0,0,0);
+ GET_PIXELS_TO_TWIPS(aPresContext, p2t);
+
nsAutoVoidArray rowGroups;
PRUint32 numRowGroups;
nsTableRowGroupFrame *thead, *tfoot;
@@ -3117,8 +3237,9 @@ nsTableFrame::ReflowChildren(nsIPresContext* aPresContext,
if (childX < numRowGroups) {
// Reflow the child into the available space
- nsHTMLReflowState kidReflowState(aPresContext, aReflowState.reflowState,
- kidFrame, kidAvailSize, aReflowState.reason);
+ nsHTMLReflowState kidReflowState(aPresContext, aReflowState.reflowState, kidFrame,
+ kidAvailSize, aReflowState.reason);
+ InitChildReflowState(*aPresContext, kidReflowState);
// XXX fix up bad mComputedWidth for scroll frame
kidReflowState.mComputedWidth = PR_MAX(kidReflowState.mComputedWidth, 0);
@@ -3172,8 +3293,9 @@ nsTableFrame::ReflowChildren(nsIPresContext* aPresContext,
}
if (repeatedFooter) {
kidAvailSize.height = repeatedFooterHeight;
- nsHTMLReflowState footerReflowState(aPresContext, aReflowState.reflowState,
- repeatedFooter, kidAvailSize, aReflowState.reason);
+ nsHTMLReflowState footerReflowState(aPresContext, aReflowState.reflowState, repeatedFooter,
+ kidAvailSize, aReflowState.reason);
+ InitChildReflowState(*aPresContext, footerReflowState);
aReflowState.y += cellSpacingY;
nsReflowStatus footerStatus;
rv = ReflowChild(repeatedFooter, aPresContext, desiredSize, footerReflowState,
@@ -3268,7 +3390,7 @@ void nsTableFrame::BalanceColumnWidths(nsIPresContext* aPresContext,
nscoord minWidth, prefWidth;
CalcMinAndPreferredWidths(aPresContext, aReflowState, PR_FALSE, minWidth, prefWidth);
SetMinWidth(minWidth);
- nscoord desWidth = CalcDesiredWidth(aReflowState);
+ nscoord desWidth = CalcDesiredWidth(*aPresContext, aReflowState);
SetDesiredWidth(desWidth);
SetPreferredWidth(prefWidth);
@@ -3285,7 +3407,8 @@ void nsTableFrame::BalanceColumnWidths(nsIPresContext* aPresContext,
// This width is based on the column widths array of the table.
// sum the width of each column and add in table insets
nscoord
-nsTableFrame::CalcDesiredWidth(const nsHTMLReflowState& aReflowState)
+nsTableFrame::CalcDesiredWidth(nsIPresContext& aPresContext,
+ const nsHTMLReflowState& aReflowState)
{
NS_ASSERTION(!mPrevInFlow, "never ever call me on a continuing frame!");
nsTableCellMap* cellMap = GetCellMap();
@@ -3308,8 +3431,9 @@ nsTableFrame::CalcDesiredWidth(const nsHTMLReflowState& aReflowState)
if (numCols > 0) {
tableWidth += cellSpacing; // add last cellspacing
- // Compute the insets (sum of border and padding)
- tableWidth += GetHorBorderPaddingWidth(aReflowState, this);
+ // Add the width between the border edge and the child area
+ nsMargin childOffset = GetChildAreaOffset(aPresContext, &aReflowState);
+ tableWidth += childOffset.left + childOffset.right;
}
return tableWidth;
@@ -3326,7 +3450,7 @@ nsTableFrame::CalcDesiredHeight(nsIPresContext* aPresContext,
return 0;
}
nscoord cellSpacingY = GetCellSpacingY();
- nsMargin borderPadding = GetBorderPadding(aReflowState);
+ nsMargin borderPadding = GetChildAreaOffset(*aPresContext, &aReflowState);
// get the natural height based on the last child's (row group or scroll frame) rect
nsAutoVoidArray rowGroups;
@@ -3346,7 +3470,7 @@ nsTableFrame::CalcDesiredHeight(nsIPresContext* aPresContext,
// see if a specified table height requires dividing additional space to rows
if (!mPrevInFlow) {
- nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aReflowState);
+ nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aPresContext, aReflowState);
if ((tableSpecifiedHeight > 0) &&
(tableSpecifiedHeight != NS_UNCONSTRAINEDSIZE) &&
(tableSpecifiedHeight > desiredHeight)) {
@@ -3391,7 +3515,9 @@ nsTableFrame::DistributeHeightToRows(nsIPresContext* aPresContext,
nscoord cellSpacingY = GetCellSpacingY();
nscoord sumOfRowHeights = 0;
- nscoord rowGroupYPos = aReflowState.mComputedBorderPadding.top + cellSpacingY;
+ nsMargin borderPadding;
+ GetChildAreaOffset(*aPresContext, &aReflowState);
+ nscoord rowGroupYPos = borderPadding.top + cellSpacingY;
nsVoidArray rowGroups;
PRUint32 numRowGroups;
@@ -3402,7 +3528,7 @@ nsTableFrame::DistributeHeightToRows(nsIPresContext* aPresContext,
// height, and base the pct on the table height. If the row group had a computed
// height, then this was already done in nsTableRowGroupFrame::CalculateRowHeights
nscoord pctBasis = aReflowState.mComputedHeight - (GetCellSpacingY() * (GetRowCount() + 1));
- nscoord yOriginRG = aReflowState.mComputedBorderPadding.top + GetCellSpacingY();
+ nscoord yOriginRG = borderPadding.top + GetCellSpacingY();
nscoord yEndRG = yOriginRG;
PRUint32 rgX;
for (rgX = 0; (rgX < numRowGroups); rgX++) {
@@ -3503,7 +3629,7 @@ nsTableFrame::DistributeHeightToRows(nsIPresContext* aPresContext,
// allocate the extra height to the unstyled row groups and rows
pctBasis = aAmount - amountUsed;
- yOriginRG = aReflowState.mComputedBorderPadding.top + cellSpacingY;
+ yOriginRG = borderPadding.top + cellSpacingY;
yEndRG = yOriginRG;
for (rgX = 0; rgX < numRowGroups; rgX++) {
nsTableRowGroupFrame* rgFrame = GetRowGroupFrame((nsIFrame*)rowGroups.ElementAt(rgX));
@@ -3817,61 +3943,6 @@ void nsTableFrame::SetColumnWidth(PRInt32 aColIndex, nscoord aWidth)
}
}
-// Update the border style to map to the HTML border style
-void nsTableFrame::MapHTMLBorderStyle(nsStyleBorder& aBorderStyle, nscoord aBorderWidth)
-{
- nsStyleCoord width;
- width.SetCoordValue(aBorderWidth);
- aBorderStyle.mBorder.SetTop(width);
- aBorderStyle.mBorder.SetLeft(width);
- aBorderStyle.mBorder.SetBottom(width);
- aBorderStyle.mBorder.SetRight(width);
-
- aBorderStyle.SetBorderStyle(NS_SIDE_TOP, NS_STYLE_BORDER_STYLE_BG_OUTSET);
- aBorderStyle.SetBorderStyle(NS_SIDE_LEFT, NS_STYLE_BORDER_STYLE_BG_OUTSET);
- aBorderStyle.SetBorderStyle(NS_SIDE_BOTTOM, NS_STYLE_BORDER_STYLE_BG_OUTSET);
- aBorderStyle.SetBorderStyle(NS_SIDE_RIGHT, NS_STYLE_BORDER_STYLE_BG_OUTSET);
-
- nsIStyleContext* styleContext = mStyleContext;
- const nsStyleBackground* colorData = (const nsStyleBackground*)
- styleContext->GetStyleData(eStyleStruct_Background);
-
- // Look until we find a style context with a NON-transparent background color
- while (styleContext) {
- if ((colorData->mBackgroundFlags & NS_STYLE_BG_COLOR_TRANSPARENT) != 0) {
- nsIStyleContext* temp = styleContext;
- styleContext = styleContext->GetParent();
- if (temp != mStyleContext)
- NS_RELEASE(temp);
- colorData = (const nsStyleBackground*)styleContext->GetStyleData(eStyleStruct_Background);
- }
- else {
- break;
- }
- }
-
- // Yaahoo, we found a style context which has a background color
-
- nscolor borderColor = 0xFFC0C0C0;
-
- if (styleContext) {
- borderColor = colorData->mBackgroundColor;
- if (styleContext != mStyleContext)
- NS_RELEASE(styleContext);
- }
-
- // if the border color is white, then shift to grey
- if (borderColor == 0xFFFFFFFF)
- borderColor = 0xFFC0C0C0;
-
- aBorderStyle.SetBorderColor(NS_SIDE_TOP, borderColor);
- aBorderStyle.SetBorderColor(NS_SIDE_LEFT, borderColor);
- aBorderStyle.SetBorderColor(NS_SIDE_BOTTOM, borderColor);
- aBorderStyle.SetBorderColor(NS_SIDE_RIGHT, borderColor);
-
-}
-
-
PRBool nsTableFrame::ConvertToPixelValue(nsHTMLValue& aValue, PRInt32 aDefault, PRInt32& aResult)
{
@@ -3887,10 +3958,6 @@ PRBool nsTableFrame::ConvertToPixelValue(nsHTMLValue& aValue, PRInt32 aDefault,
return PR_TRUE;
}
-void nsTableFrame::MapBorderMarginPadding(nsIPresContext* aPresContext)
-{
-}
-
nscoord
CalcPercentPadding(nscoord aBasis,
nsStyleCoord aStyleCoord)
@@ -3977,24 +4044,13 @@ nsTableFrame::GetPadding(const nsSize& aBasis,
return padding;
}
-PRUint8 nsTableFrame::GetBorderCollapseStyle()
-{
- /* the following has been commented out to turn off collapsing borders
- const nsStyleTable* tableStyle;
- GetStyleData(eStyleStruct_Table, (const nsStyleStruct *&)tableStyle);
- return tableStyle->mBorderCollapse;*/
- return NS_STYLE_BORDER_SEPARATE;
-}
-
-
// XXX: could cache this. But be sure to check style changes if you do!
nscoord nsTableFrame::GetCellSpacingX()
{
- const nsStyleTableBorder* tableStyle;
- GetStyleData(eStyleStruct_TableBorder, (const nsStyleStruct *&)tableStyle);
nscoord cellSpacing = 0;
- PRUint8 borderCollapseStyle = GetBorderCollapseStyle();
- if (NS_STYLE_BORDER_COLLAPSE != borderCollapseStyle) {
+ if (!IsBorderCollapse()) {
+ const nsStyleTableBorder* tableStyle;
+ GetStyleData(eStyleStruct_TableBorder, (const nsStyleStruct *&)tableStyle);
if (tableStyle->mBorderSpacingX.GetUnit() == eStyleUnit_Coord) {
cellSpacing = tableStyle->mBorderSpacingX.GetCoordValue();
}
@@ -4005,11 +4061,10 @@ nscoord nsTableFrame::GetCellSpacingX()
// XXX: could cache this. But be sure to check style changes if you do!
nscoord nsTableFrame::GetCellSpacingY()
{
- const nsStyleTableBorder* tableStyle;
- GetStyleData(eStyleStruct_TableBorder, (const nsStyleStruct *&)tableStyle);
nscoord cellSpacing = 0;
- PRUint8 borderCollapseStyle = GetBorderCollapseStyle();
- if (NS_STYLE_BORDER_COLLAPSE != borderCollapseStyle) {
+ if (!IsBorderCollapse()) {
+ const nsStyleTableBorder* tableStyle;
+ GetStyleData(eStyleStruct_TableBorder, (const nsStyleStruct *&)tableStyle);
if (tableStyle->mBorderSpacingY.GetUnit() == eStyleUnit_Coord) {
cellSpacing = tableStyle->mBorderSpacingY.GetCoordValue();
}
@@ -4113,7 +4168,7 @@ nsTableFrame::CalcBorderBoxWidth(nsIPresContext* aPresContext,
}
}
else if (width != NS_UNCONSTRAINEDSIZE) {
- nsMargin borderPadding = aState.mComputedBorderPadding;
+ nsMargin borderPadding = GetContentAreaOffset(*aPresContext, &aState);
width += borderPadding.left + borderPadding.right;
}
width = PR_MAX(width, 0);
@@ -4128,11 +4183,12 @@ nsTableFrame::CalcBorderBoxWidth(nsIPresContext* aPresContext,
}
nscoord
-nsTableFrame::CalcBorderBoxHeight(const nsHTMLReflowState& aState)
+nsTableFrame::CalcBorderBoxHeight(nsIPresContext* aPresContext,
+ const nsHTMLReflowState& aState)
{
nscoord height = aState.mComputedHeight;
if (NS_AUTOHEIGHT != height) {
- nsMargin borderPadding = aState.mComputedBorderPadding;
+ nsMargin borderPadding = GetContentAreaOffset(*aPresContext, &aState);
height += borderPadding.top + borderPadding.bottom;
}
height = PR_MAX(0, height);
@@ -4180,6 +4236,7 @@ nsTableFrame::CalcMinAndPreferredWidths(nsIPresContext* aPresContext,
nscoord& aMinWidth,
nscoord& aPrefWidth)
{
+ if (!aPresContext) ABORT0();
aMinWidth = aPrefWidth = 0;
nscoord spacingX = GetCellSpacingX();
@@ -4201,7 +4258,8 @@ nsTableFrame::CalcMinAndPreferredWidths(nsIPresContext* aPresContext,
}
// if it is not a degenerate table, add the last spacing on the right and the borderPadding
if (numCols > 0) {
- nscoord extra = spacingX + GetHorBorderPaddingWidth(aReflowState, this);
+ nsMargin childAreaOffset = GetChildAreaOffset(*aPresContext, &aReflowState);
+ nscoord extra = spacingX + childAreaOffset.left + childAreaOffset.right;
aMinWidth += extra;
aPrefWidth += extra;
}
@@ -4217,14 +4275,15 @@ nsTableFrame::CalcMinAndPreferredWidths(nsIPresContext* aPresContext,
if (mTableLayoutStrategy && IsAutoLayout()) {
float p2t;
aPresContext->GetPixelsToTwips(&p2t);
- aPrefWidth = mTableLayoutStrategy->CalcPctAdjTableWidth(aReflowState, availWidth, p2t);
+ aPrefWidth = mTableLayoutStrategy->CalcPctAdjTableWidth(*aPresContext, aReflowState, availWidth, p2t);
}
}
}
else { // a specified fix width becomes the min or preferred width
nscoord compWidth = aReflowState.mComputedWidth;
if ((NS_UNCONSTRAINEDSIZE != compWidth) && (0 != compWidth) && !isPctWidth) {
- compWidth += GetHorBorderPaddingWidth(aReflowState, this);
+ nsMargin contentOffset = GetContentAreaOffset(*aPresContext, &aReflowState);
+ compWidth += contentOffset.left + contentOffset.right;
aMinWidth = PR_MAX(aMinWidth, compWidth);
aPrefWidth = PR_MAX(aMinWidth, compWidth);
}
@@ -4288,7 +4347,7 @@ nsTableFrame::DumpRowGroup(nsIPresContext* aPresContext, nsIFrame* aKidFrame)
while (cellFrame) {
nsIAtom* cellType;
cellFrame->GetFrameType(&cellType);
- if (nsLayoutAtoms::tableCellFrame == cellType) {
+ if (IS_TABLE_CELL(cellType)) {
PRInt32 colIndex;
((nsTableCellFrame*)cellFrame)->GetColIndex(colIndex);
printf("cell(%d)=%p ", colIndex, cellFrame);
@@ -4557,6 +4616,2361 @@ PRInt32 nsTableFrame::GetNumCellsOriginatingInRow(PRInt32 aRowIndex) const
return 0;
}
+/********************************************************************************
+ * Collapsing Borders
+ *
+ * The CSS spec says to resolve border 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.
+ *******************************************************************************/
+
+void
+nsTableFrame::SetBCDamageArea(nsIPresContext& aPresContext,
+ const nsRect& aValue)
+{
+ nsRect newRect(aValue);
+ newRect.width = PR_MAX(1, newRect.width);
+ newRect.height = PR_MAX(1, newRect.height);
+
+ if (!IsBorderCollapse()) {
+ NS_ASSERTION(PR_FALSE, "invalid call - not border collapse model");
+ return;
+ }
+ SetNeedToCalcBCBorders(PR_TRUE);
+ // Get the property
+ BCPropertyData* value = (BCPropertyData*)nsTableFrame::GetProperty(&aPresContext, this, nsLayoutAtoms::tableBCProperty, PR_TRUE);
+ if (value) {
+ // for now just construct a union of the new and old damage areas
+ value->mDamageArea.UnionRect(value->mDamageArea, newRect);
+ }
+}
+/*****************************************************************
+ * BCMapCellIterator
+ ****************************************************************/
+struct BCMapCellInfo
+{
+ BCMapCellInfo();
+ void Reset();
+
+ CellData* cellData;
+ nsCellMap* cellMap;
+
+ nsTableRowGroupFrame* rg;
+
+ nsTableRowFrame* topRow;
+ nsTableRowFrame* bottomRow;
+
+ nsTableColGroupFrame* cg;
+
+ nsTableColFrame* leftCol;
+ nsTableColFrame* rightCol;
+
+ nsBCTableCellFrame* cell;
+
+ PRInt32 rowIndex;
+ PRInt32 rowSpan;
+ PRInt32 colIndex;
+ PRInt32 colSpan;
+
+ PRPackedBool rgTop;
+ PRPackedBool rgBottom;
+ PRPackedBool cgLeft;
+ PRPackedBool cgRight;
+};
+
+BCMapCellInfo::BCMapCellInfo()
+{
+ Reset();
+}
+
+void BCMapCellInfo::Reset()
+{
+ cellData = nsnull;
+ rg = nsnull;
+ topRow = nsnull;
+ bottomRow = nsnull;
+ cg = nsnull;
+ leftCol = nsnull;
+ rightCol = nsnull;
+ cell = nsnull;
+ rowIndex = rowSpan = colIndex = colSpan = 0;
+ rgTop = rgBottom = cgLeft = cgRight = PR_FALSE;
+}
+
+class BCMapCellIterator
+{
+public:
+ BCMapCellIterator(nsTableFrame& aTableFrame,
+ const nsRect& aDamageArea);
+
+ void First(BCMapCellInfo& aMapCellInfo);
+
+ void Next(BCMapCellInfo& aMapCellInfo);
+
+ void PeekRight(BCMapCellInfo& aRefInfo,
+ PRUint32 aRowIndex,
+ BCMapCellInfo& aAjaInfo);
+
+ void PeekBottom(BCMapCellInfo& aRefInfo,
+ PRUint32 aColIndex,
+ BCMapCellInfo& aAjaInfo);
+
+ PRBool IsNewRow() { return mIsNewRow; }
+
+ nsTableRowFrame* GetPrevRow() const { return mPrevRow; }
+
+ PRInt32 mRowGroupStart;
+ PRInt32 mRowGroupEnd;
+ PRBool mAtEnd;
+ nsCellMap* mCellMap;
+
+private:
+ void SetInfo(nsTableRowFrame* aRow,
+ PRInt32 aColIndex,
+ CellData* aCellData,
+ BCMapCellInfo& aMapInfo,
+ nsCellMap* aCellMap = nsnull);
+
+ PRBool SetNewRow(nsTableRowFrame* row = nsnull);
+ PRBool SetNewRowGroup();
+
+ nsTableFrame& mTableFrame;
+ nsTableCellMap* mTableCellMap;
+ nsVoidArray mRowGroups;
+ nsTableRowGroupFrame* mRowGroup;
+ PRInt32 mRowGroupIndex;
+ PRUint32 mNumRows;
+ nsTableRowFrame* mRow;
+ nsTableRowFrame* mPrevRow;
+ PRBool mIsNewRow;
+ PRInt32 mRowIndex;
+ PRUint32 mNumCols;
+ PRInt32 mColIndex;
+ nsPoint mAreaStart;
+ nsPoint mAreaEnd;
+};
+
+BCMapCellIterator::BCMapCellIterator(nsTableFrame& aTableFrame,
+ const nsRect& aDamageArea)
+:mTableFrame(aTableFrame)
+{
+ mTableCellMap = aTableFrame.GetCellMap();
+
+ mAreaStart.x = aDamageArea.x;
+ mAreaStart.y = aDamageArea.y;
+ mAreaEnd.y = aDamageArea.y + aDamageArea.height - 1;
+ mAreaEnd.x = aDamageArea.x + aDamageArea.width - 1;
+
+ mNumRows = mTableFrame.GetRowCount();
+ mRow = nsnull;
+ mRowIndex = 0;
+ mNumCols = mTableFrame.GetColCount();
+ mColIndex = 0;
+ mRowGroupIndex = -1;
+
+ // Get the ordered row groups
+ PRUint32 numRowGroups;
+ aTableFrame.OrderRowGroups(mRowGroups, numRowGroups, nsnull);
+
+ mAtEnd = PR_TRUE; // gets reset when First() is called
+}
+
+void
+BCMapCellIterator::SetInfo(nsTableRowFrame* aRow,
+ PRInt32 aColIndex,
+ CellData* aCellData,
+ BCMapCellInfo& aCellInfo,
+ nsCellMap* aCellMap)
+{
+ aCellInfo.cellData = aCellData;
+ aCellInfo.cellMap = (aCellMap) ? aCellMap : mCellMap;
+ aCellInfo.colIndex = aColIndex;
+
+ // row frame info
+ aCellInfo.rowIndex = 0;
+ if (aRow) {
+ aCellInfo.topRow = aRow;
+ aCellInfo.rowIndex = aRow->GetRowIndex();
+ }
+
+ // cell frame info
+ aCellInfo.cell = nsnull;
+ aCellInfo.rowSpan = 1;
+ aCellInfo.colSpan = 1;
+ if (aCellData) {
+ aCellInfo.cell = (nsBCTableCellFrame*)aCellData->GetCellFrame();
+ if (aCellInfo.cell) {
+ if (!aCellInfo.topRow) {
+ aCellInfo.cell->GetParent((nsIFrame**)&aCellInfo.topRow); if (!aCellInfo.topRow) ABORT0();
+ aCellInfo.rowIndex = aCellInfo.topRow->GetRowIndex();
+ }
+ PRBool ignore;
+ PRInt32 rgRowIndex = aCellInfo.rowIndex - mRowGroupStart;
+ aCellInfo.colSpan = mCellMap->GetEffectiveColSpan(*mTableCellMap, rgRowIndex, aColIndex, ignore);
+ aCellInfo.rowSpan = mCellMap->GetRowSpan(*mTableCellMap, rgRowIndex, aColIndex, PR_TRUE, ignore);
+ }
+ }
+ if (!aCellInfo.topRow) {
+ aCellInfo.topRow = mRow;
+ }
+
+ if (1 == aCellInfo.rowSpan) {
+ aCellInfo.bottomRow = aCellInfo.topRow;
+ }
+ else {
+ aCellInfo.bottomRow = aCellInfo.topRow->GetNextRow();
+ if (aCellInfo.bottomRow) {
+ for (PRInt32 spanX = 2; aCellInfo.bottomRow && (spanX < aCellInfo.rowSpan); spanX++) {
+ aCellInfo.bottomRow = aCellInfo.bottomRow->GetNextRow();
+ }
+ NS_ASSERTION(aCellInfo.bottomRow, "program error");
+ }
+ else {
+ NS_ASSERTION(PR_FALSE, "error in cell map");
+ aCellInfo.rowSpan = 1;
+ aCellInfo.bottomRow = aCellInfo.topRow;
+ }
+ }
+
+ // row group frame info
+ PRUint32 rgStart = mRowGroupStart;
+ PRUint32 rgEnd = mRowGroupEnd;
+ nsIFrame* parentFrame = nsnull;
+ aCellInfo.topRow->GetParent((nsIFrame**)&parentFrame);
+ aCellInfo.rg = mTableFrame.GetRowGroupFrame(parentFrame);
+ if (aCellInfo.rg != mRowGroup) {
+ rgStart = aCellInfo.rg->GetStartRowIndex();
+ rgEnd = rgStart + aCellInfo.rg->GetRowCount() - 1;
+ }
+ PRUint32 rowIndex = aCellInfo.topRow->GetRowIndex();
+ aCellInfo.rgTop = (rgStart == rowIndex);
+ aCellInfo.rgBottom = (rgEnd == rowIndex + aCellInfo.rowSpan - 1);
+
+ // col frame info
+ aCellInfo.leftCol = mTableFrame.GetColFrame(aColIndex); if (!aCellInfo.leftCol) ABORT0();
+
+ aCellInfo.rightCol = aCellInfo.leftCol;
+ if (aCellInfo.colSpan > 1) {
+ for (PRInt32 spanX = 1; spanX < aCellInfo.colSpan; spanX++) {
+ nsTableColFrame* colFrame = aCellInfo.rightCol->GetNextCol();
+ if (colFrame) {
+ aCellInfo.rightCol = colFrame;
+ }
+ else {
+ NS_ASSERTION(PR_FALSE, "program error");
+ break;
+ }
+ }
+ }
+
+ // col group frame info
+ aCellInfo.leftCol->GetParent((nsIFrame**)&aCellInfo.cg);
+ PRInt32 cgStart = aCellInfo.cg->GetStartColumnIndex();
+ PRInt32 cgEnd = PR_MAX(0, cgStart + aCellInfo.cg->GetColCount() - 1);
+ aCellInfo.cgLeft = (cgStart == aColIndex);
+ aCellInfo.cgRight = (cgEnd == aColIndex + (PRInt32)aCellInfo.colSpan - 1);
+}
+
+PRBool
+BCMapCellIterator::SetNewRow(nsTableRowFrame* aRow)
+{
+ mPrevRow = mRow;
+ if (aRow) {
+ mRow = aRow;
+ }
+ else if (mRow) {
+ mRow = mRow->GetNextRow();
+ }
+ if (mRow) {
+ mRowIndex = mRow->GetRowIndex();
+ // get to the first entry with an originating cell
+ PRInt32 rgRowIndex = mRowIndex - mRowGroupStart;
+ nsVoidArray* row = (nsVoidArray*)mCellMap->mRows.ElementAt(rgRowIndex); if (!row) ABORT1(PR_FALSE);
+ PRInt32 rowSize = row->Count();
+ for (mColIndex = mAreaStart.x; mColIndex <= mAreaEnd.x; mColIndex++) {
+ CellData* cellData = (mColIndex < rowSize) ? (CellData*)row->ElementAt(mColIndex) : nsnull;
+ if (!cellData) { // add a dead cell data
+ nsRect damageArea;
+ cellData = mCellMap->AppendCell(*mTableCellMap, nsnull, rgRowIndex, PR_FALSE, damageArea); if (!cellData) ABORT1(PR_FALSE);
+ }
+ if (cellData && (cellData->IsOrig() || cellData->IsDead())) {
+ break;
+ }
+ }
+ mIsNewRow = PR_TRUE;
+ }
+ else {
+ NS_ASSERTION(PR_FALSE, "program error");
+ mAtEnd = PR_TRUE;
+ }
+ return !mAtEnd;
+}
+
+PRBool
+BCMapCellIterator::SetNewRowGroup()
+{
+ mRowGroupIndex++;
+ PRInt32 numRowGroups = mRowGroups.Count();
+ for (PRInt32 rgX = mRowGroupIndex; (rgX < numRowGroups) && !mAtEnd; rgX++) {
+ nsIFrame* frame = (nsTableRowGroupFrame*)mRowGroups.ElementAt(mRowGroupIndex); if (!frame) ABORT1(PR_FALSE);
+ mRowGroup = mTableFrame.GetRowGroupFrame(frame); if (!mRowGroup) ABORT1(PR_FALSE);
+ mRowGroupStart = mRowGroup->GetStartRowIndex();
+ mRowGroupEnd = mRowGroupStart + mRowGroup->GetRowCount() - 1;
+ if (mRowGroupEnd >= 0) {
+ mCellMap = mTableCellMap->GetMapFor(*mRowGroup);
+ if (SetNewRow(mRowGroup->GetFirstRow())) {
+ return PR_TRUE;
+ }
+ else mAtEnd = PR_TRUE;
+ }
+ }
+ mAtEnd = PR_TRUE;
+ return !mAtEnd;
+}
+
+void
+BCMapCellIterator::First(BCMapCellInfo& aMapInfo)
+{
+ mAtEnd = PR_FALSE;
+ aMapInfo.Reset();
+
+ SetNewRowGroup(); // could set mAtEnd
+ while (!mAtEnd) {
+ if ((mAreaStart.y >= mRowGroupStart) && (mAreaStart.y <= mRowGroupEnd)) {
+ CellData* cellData = mCellMap->GetDataAt(*mTableCellMap, mAreaStart.y - mRowGroupStart, mAreaStart.x, PR_FALSE);
+ if (cellData) {
+ if (!cellData->IsOrig()) {
+ // if the start data does not have an originating cell, adjust it to have one
+ if (cellData->IsRowSpan()) {
+ mAreaStart.y -= cellData->GetRowSpanOffset();
+ NS_ASSERTION(mAreaStart.y >= 0, "program error");
+ }
+ if (cellData->IsColSpan()) {
+ mAreaStart.x -= cellData->GetColSpanOffset();
+ NS_ASSERTION(mAreaStart.x >= 0, "program error");
+ }
+ cellData = mCellMap->GetDataAt(*mTableCellMap, mAreaStart.y - mRowGroupStart, mAreaStart.x, PR_FALSE);
+ }
+ if (cellData && cellData->IsOrig()) {
+ SetInfo(mRow, mAreaStart.x, cellData, aMapInfo);
+ break;
+ }
+ else mAtEnd = PR_TRUE;
+ }
+ else mAtEnd = PR_TRUE;
+ }
+ SetNewRowGroup(); // could set mAtEnd
+ }
+}
+
+void
+BCMapCellIterator::Next(BCMapCellInfo& aMapInfo)
+{
+ if (mAtEnd) ABORT0();
+ aMapInfo.Reset();
+
+ mIsNewRow = PR_FALSE;
+ mColIndex++;
+ while ((mRowIndex <= mAreaEnd.y) && !mAtEnd) {
+ for (; mColIndex <= mAreaEnd.x; mColIndex++) {
+ PRInt32 rgRowIndex = mRowIndex - mRowGroupStart;
+ CellData* cellData = mCellMap->GetDataAt(*mTableCellMap, rgRowIndex, mColIndex, PR_FALSE);
+ if (!cellData) { // add a dead cell data
+ nsRect damageArea;
+ cellData = mCellMap->AppendCell(*mTableCellMap, nsnull, rgRowIndex, PR_FALSE, damageArea); if (!cellData) ABORT0();
+ }
+ if (cellData && (cellData->IsOrig() || cellData->IsDead())) {
+ SetInfo(mRow, mColIndex, cellData, aMapInfo);
+ return;
+ }
+ }
+ if (mRowIndex >= mRowGroupEnd) {
+ SetNewRowGroup(); // could set mAtEnd
+ }
+ else {
+ SetNewRow(); // could set mAtEnd
+ }
+ }
+ mAtEnd = PR_TRUE;
+}
+
+void
+BCMapCellIterator::PeekRight(BCMapCellInfo& aRefInfo,
+ PRUint32 aRowIndex,
+ BCMapCellInfo& aAjaInfo)
+{
+ aAjaInfo.Reset();
+ PRInt32 colIndex = aRefInfo.colIndex + aRefInfo.colSpan;
+ PRUint32 rgRowIndex = aRowIndex - mRowGroupStart;
+
+ CellData* cellData = mCellMap->GetDataAt(*mTableCellMap, rgRowIndex, colIndex, PR_FALSE);
+ if (!cellData) { // add a dead cell data
+ NS_ASSERTION(colIndex < mTableCellMap->GetColCount(), "program error");
+ nsRect damageArea;
+ cellData = mCellMap->AppendCell(*mTableCellMap, nsnull, rgRowIndex, PR_FALSE, damageArea); if (!cellData) ABORT0();
+ }
+ nsTableRowFrame* row = nsnull;
+ if (cellData->IsRowSpan()) {
+ rgRowIndex -= cellData->GetRowSpanOffset();
+ cellData = mCellMap->GetDataAt(*mTableCellMap, rgRowIndex, colIndex, PR_FALSE); if (!cellData) ABORT0();
+ }
+ else {
+ row = mRow;
+ }
+ SetInfo(row, colIndex, cellData, aAjaInfo);
+}
+
+void
+BCMapCellIterator::PeekBottom(BCMapCellInfo& aRefInfo,
+ PRUint32 aColIndex,
+ BCMapCellInfo& aAjaInfo)
+{
+ aAjaInfo.Reset();
+ PRInt32 rowIndex = aRefInfo.rowIndex + aRefInfo.rowSpan;
+ PRInt32 rgRowIndex = rowIndex - mRowGroupStart;
+ nsTableRowGroupFrame* rg = mRowGroup;
+ nsCellMap* cellMap = mCellMap;
+ nsTableRowFrame* nextRow = nsnull;
+ if (rowIndex > mRowGroupEnd) {
+ nsIFrame* frame = (nsTableRowGroupFrame*)mRowGroups.ElementAt(mRowGroupIndex + 1); if (!frame) ABORT0();
+ rg = mTableFrame.GetRowGroupFrame(frame);
+ if (rg) {
+ cellMap = mTableCellMap->GetMapFor(*rg);
+ rgRowIndex = 0;
+ nextRow = rg->GetFirstRow();
+ }
+ else return;
+ }
+ else {
+ // get the row within the same row group
+ nextRow = mRow;
+ for (PRInt32 i = 0; i < aRefInfo.rowSpan; i++) {
+ nextRow = nextRow->GetNextRow(); if (!nextRow) ABORT0();
+ }
+ }
+
+ CellData* cellData = cellMap->GetDataAt(*mTableCellMap, rgRowIndex, aColIndex, PR_FALSE);
+ if (!cellData) { // add a dead cell data
+ NS_ASSERTION(rgRowIndex < cellMap->GetRowCount(), "program error");
+ nsRect damageArea;
+ cellData = cellMap->AppendCell(*mTableCellMap, nsnull, rgRowIndex, PR_FALSE, damageArea); if (!cellData) ABORT0();
+ }
+ if (cellData->IsColSpan()) {
+ aColIndex -= cellData->GetColSpanOffset();
+ cellData = cellMap->GetDataAt(*mTableCellMap, rowIndex, aColIndex, PR_FALSE);
+ }
+ SetInfo(nextRow, aColIndex, cellData, aAjaInfo, cellMap);
+}
+
+// Assign priorities to border styles. For example, styleToPriority(NS_STYLE_BORDER_STYLE_SOLID)
+// will return the priority of NS_STYLE_BORDER_STYLE_SOLID.
+static PRUint8 styleToPriority[13] = { 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 7, 1, 2 };
+
+// Set aStyle and aWidth given aStyleBorder and aSide
+static void
+GetStyleInfo(const nsIFrame& aFrame,
+ PRUint8 aSide,
+ PRUint8& aStyle,
+ nscolor& aColor,
+ PRBool aIgnoreIfRules = PR_FALSE,
+ nscoord* aWidth = nsnull,
+ float* aTwipsToPixels = nsnull)
+{
+ const nsStyleBorder* styleData;
+ aFrame.GetStyleData(eStyleStruct_Border, (const nsStyleStruct *&)styleData); if (!styleData) ABORT0();
+
+ aStyle = styleData->GetBorderStyle(aSide);
+
+ // if the rules mask is set, set the style either to none or remove the mask
+ if (NS_STYLE_BORDER_STYLE_RULES_MASK & aStyle) {
+ if (aIgnoreIfRules) {
+ aStyle = NS_STYLE_BORDER_STYLE_NONE;
+ aColor = 0;
+ if (aWidth) {
+ *aWidth = 0;
+ }
+ return;
+ }
+ else {
+ aStyle &= ~NS_STYLE_BORDER_STYLE_RULES_MASK;
+ }
+ }
+
+ if ((NS_STYLE_BORDER_STYLE_NONE == aStyle) || (NS_STYLE_BORDER_STYLE_HIDDEN == aStyle)) {
+ if (aWidth) {
+ *aWidth = 0;
+ aColor = 0;
+ }
+ return;
+ }
+
+ if ((NS_STYLE_BORDER_STYLE_INSET == aStyle) ||
+ (NS_STYLE_BORDER_STYLE_BG_INSET == aStyle)) {
+ aStyle = NS_STYLE_BORDER_STYLE_GROOVE;
+ }
+ else if ((NS_STYLE_BORDER_STYLE_OUTSET == aStyle) ||
+ (NS_STYLE_BORDER_STYLE_BG_OUTSET == aStyle)) {
+ aStyle = NS_STYLE_BORDER_STYLE_RIDGE;
+ }
+ PRBool transparent, foreground;
+ styleData->GetBorderColor(aSide, aColor, transparent, foreground);
+ if (foreground) {
+ nsCOMPtr styleContext;
+ aFrame.GetStyleContext(getter_AddRefs(styleContext)); if(!styleContext) ABORT0();
+ const nsStyleColor* colorStyle = (const nsStyleColor*)styleContext->GetStyleData(eStyleStruct_Color);
+ aColor = colorStyle->mColor;
+ }
+ if (aWidth && aTwipsToPixels) {
+ *aWidth = 0;
+ nscoord width;
+ styleData->CalcBorderFor(&aFrame, aSide, width);
+ *aWidth = NSToCoordRound(*aTwipsToPixels * (float)width);
+ }
+}
+
+static PRBool
+CalcDominateBorder(PRBool aIsCorner,
+ BCBorderOwner aOwner1,
+ PRUint8 aStyle1,
+ PRUint16 aWidth1,
+ nscolor aColor1,
+ BCBorderOwner aOwner2,
+ PRUint8 aStyle2,
+ PRUint16 aWidth2,
+ nscolor aColor2,
+ BCBorderOwner& aDomOwner,
+ PRUint8& aDomStyle,
+ PRUint16& aDomWidth,
+ nscolor& aDomColor,
+ PRBool aSecondIsHorizontal)
+{
+ PRBool firstDominates = PR_TRUE;
+ if (NS_STYLE_BORDER_STYLE_HIDDEN == aStyle1) {
+ firstDominates = (aIsCorner) ? PR_FALSE : PR_TRUE;
+ }
+ else if (NS_STYLE_BORDER_STYLE_HIDDEN == aStyle2) {
+ firstDominates = (aIsCorner) ? PR_TRUE : PR_FALSE;
+ }
+ else if (aWidth1 < aWidth2) {
+ firstDominates = PR_FALSE;
+ }
+ else if (aWidth1 == aWidth2) {
+ if (styleToPriority[aStyle1] < styleToPriority[aStyle2]) {
+ firstDominates = PR_FALSE;
+ }
+ else if (styleToPriority[aStyle1] == styleToPriority[aStyle2]) {
+ if (aOwner1 == aOwner2) {
+ firstDominates = !aSecondIsHorizontal;
+ }
+ else if (aOwner1 < aOwner2) {
+ firstDominates = PR_FALSE;
+ }
+ }
+ }
+ if (firstDominates) {
+ aDomOwner = aOwner1;
+ aDomStyle = aStyle1;
+ aDomWidth = aWidth1;
+ aDomColor = aColor1;
+ }
+ else {
+ aDomOwner = aOwner2;
+ aDomStyle = aStyle2;
+ aDomWidth = aWidth2;
+ aDomColor = aColor2;
+ }
+ return firstDominates;
+}
+
+// calc the dominate border by considering the table, row/col group, row/col, cell,
+static void
+CalcDominateBorder(const nsIFrame* aTableFrame,
+ const nsIFrame* aColGroupFrame,
+ const nsIFrame* aColFrame,
+ const nsIFrame* aRowGroupFrame,
+ const nsIFrame* aRowFrame,
+ const nsIFrame* aCellFrame,
+ PRBool aIgnoreIfRules,
+ PRUint8 aSide,
+ PRBool aAja,
+ float aTwipsToPixels,
+ BCBorderOwner& aDomElem,
+ PRUint8& aDomStyle,
+ PRUint16& aDomWidth,
+ nscolor& aDomColor)
+{
+ PRUint8 style;
+ nscolor color;
+ aDomStyle = NS_STYLE_BORDER_STYLE_NONE;
+ nscoord width;
+ aDomWidth = 0;
+ PRBool horizontal = (NS_SIDE_TOP == aSide) || (NS_SIDE_BOTTOM == aSide);
+
+ // start with the table as dominate if present
+ if (aTableFrame) {
+ GetStyleInfo(*aTableFrame, aSide, style, color, aIgnoreIfRules, &width, &aTwipsToPixels);
+ aDomStyle = style;
+ aDomWidth = width;
+ aDomColor = color;
+ aDomElem = eTableOwner;
+ if (NS_STYLE_BORDER_STYLE_HIDDEN == style) {
+ return;
+ }
+ }
+ // see if the col row group is dominate
+ if (aColGroupFrame) {
+ GetStyleInfo(*aColGroupFrame, aSide, style, color, aIgnoreIfRules, &width, &aTwipsToPixels);
+ if ((NS_STYLE_BORDER_STYLE_HIDDEN == style) ||
+ (width > aDomWidth) ||
+ ((width == aDomWidth) &&
+ (styleToPriority[style] >= styleToPriority[aDomStyle]))) {
+ aDomStyle = style;
+ aDomWidth = width;
+ aDomColor = color;
+ aDomElem = (aAja && !horizontal) ? eAjaColGroupOwner : eColGroupOwner;
+ if (NS_STYLE_BORDER_STYLE_HIDDEN == style) {
+ return;
+ }
+ }
+ }
+ // see if the col is dominate
+ if (aColFrame) {
+ GetStyleInfo(*aColFrame, aSide, style, color, aIgnoreIfRules, &width, &aTwipsToPixels);
+ if ((NS_STYLE_BORDER_STYLE_HIDDEN == style) ||
+ (width > aDomWidth) ||
+ ((width == aDomWidth) &&
+ (styleToPriority[style] >= styleToPriority[aDomStyle]))) {
+ aDomStyle = style;
+ aDomWidth = width;
+ aDomColor = color;
+ aDomElem = (aAja && !horizontal) ? eAjaColOwner : eColOwner;
+ if (NS_STYLE_BORDER_STYLE_HIDDEN == style) {
+ return;
+ }
+ }
+ }
+ // see if the row row group is dominate
+ if (aRowGroupFrame) {
+ GetStyleInfo(*aRowGroupFrame, aSide, style, color, aIgnoreIfRules, &width, &aTwipsToPixels);
+ if ((NS_STYLE_BORDER_STYLE_HIDDEN == style) ||
+ (width > aDomWidth) ||
+ ((width == aDomWidth) &&
+ (styleToPriority[style] >= styleToPriority[aDomStyle]))) {
+ aDomStyle = style;
+ aDomWidth = width;
+ aDomColor = color;
+ aDomElem = (aAja && horizontal) ? eAjaRowGroupOwner : eRowGroupOwner;
+ if (NS_STYLE_BORDER_STYLE_HIDDEN == style) {
+ return;
+ }
+ }
+ }
+ // see if the row is dominate
+ if (aRowFrame) {
+ GetStyleInfo(*aRowFrame, aSide, style, color, aIgnoreIfRules, &width, &aTwipsToPixels);
+ if ((NS_STYLE_BORDER_STYLE_HIDDEN == style) ||
+ (width > aDomWidth) ||
+ ((width == aDomWidth) &&
+ (styleToPriority[style] >= styleToPriority[aDomStyle]))) {
+ aDomStyle = style;
+ aDomWidth = width;
+ aDomColor = color;
+ aDomElem = (aAja && horizontal) ? eAjaRowOwner : eRowOwner;
+ if (NS_STYLE_BORDER_STYLE_HIDDEN == style) {
+ return;
+ }
+ }
+ }
+ // see if the cell is dominate
+ if (aCellFrame) {
+ GetStyleInfo(*aCellFrame, aSide, style, color, aIgnoreIfRules, &width, &aTwipsToPixels);
+ if ((NS_STYLE_BORDER_STYLE_HIDDEN == style) ||
+ (width > aDomWidth) ||
+ ((width == aDomWidth) &&
+ (styleToPriority[style] >= styleToPriority[aDomStyle]))) {
+ aDomStyle = style;
+ aDomWidth = width;
+ aDomColor = color;
+ aDomElem = (aAja) ? eAjaCellOwner : eCellOwner;
+ }
+ }
+}
+
+static PRBool
+Perpendicular(PRUint8 aSide1,
+ PRUint8 aSide2)
+{
+ switch (aSide1) {
+ case NS_SIDE_TOP:
+ return (NS_SIDE_BOTTOM != aSide2);
+ case NS_SIDE_RIGHT:
+ return (NS_SIDE_LEFT != aSide2);
+ case NS_SIDE_BOTTOM:
+ return (NS_SIDE_TOP != aSide2);
+ default: // NS_SIDE_LEFT
+ return (NS_SIDE_RIGHT != aSide2);
+ }
+}
+
+// XXX allocate this as number-of-cols+1 instead of number-of-cols+1 * number-of-rows+1
+struct BCCornerInfo
+{
+ BCCornerInfo() { ownerColor = 0; ownerWidth = subWidth = ownerSide = ownerElem = subSide =
+ subElem = hasDashDot = numSegs = bevel = 0;
+ ownerStyle = 0xFF; subStyle = NS_STYLE_BORDER_STYLE_SOLID; }
+ void Set(PRUint8 aSide,
+ BCBorderOwner aBorderOwner,
+ PRUint8 aOwnerBStyle,
+ nscoord aOwnerWidth,
+ nscolor aOwnerColor);
+
+ void Update(PRUint8 aSide,
+ BCBorderOwner aBorderOwner,
+ PRUint8 aOwnerBStyle,
+ nscoord aOwnerWidth,
+ nscolor aOwnerColor);
+
+ nscolor ownerColor; // color of borderOwner
+ PRUint16 ownerWidth; // pixel width of borderOwner
+ PRUint16 subWidth; // pixel width of the largest border intersecting the border perpendicular
+ // to ownerSide
+ PRUint32 ownerSide:2; // side (e.g NS_SIDE_TOP, NS_SIDE_RIGHT, etc) of the border owning
+ // the corner relative to the corner
+ PRUint32 ownerElem:3; // elem type (e.g. eTable, eGroup, etc) owning the corner
+ PRUint32 ownerStyle:8; // border style of ownerElem
+ PRUint32 subSide:2; // side of border with subWidth relative to the corner
+ PRUint32 subElem:3; // elem type (e.g. eTable, eGroup, etc) of sub owner
+ PRUint32 subStyle:8; // border style of subElem
+ PRUint32 hasDashDot:1; // does a dashed, dotted segment enter the corner, they cannot be beveled
+ PRUint32 numSegs:3; // number of segments entering corner
+ PRUint32 bevel:1; // is the corner beveled (uses the above two fields together with subWidth)
+ PRUint32 unused:1;
+};
+
+void
+BCCornerInfo::Set(PRUint8 aSide,
+ BCBorderOwner aBorderOwner,
+ PRUint8 aOwnerBStyle,
+ nscoord aOwnerWidth,
+ nscolor aOwnerColor)
+{
+ ownerElem = aBorderOwner;
+ ownerStyle = aOwnerBStyle;
+ ownerWidth = aOwnerWidth;
+ ownerColor = aOwnerColor;
+ ownerSide = aSide;
+ hasDashDot = 0;
+ numSegs = 0;
+ if (aOwnerWidth > 0) {
+ numSegs++;
+ hasDashDot = (NS_STYLE_BORDER_STYLE_DASHED == aOwnerBStyle) ||
+ (NS_STYLE_BORDER_STYLE_DOTTED == aOwnerBStyle);
+ }
+ bevel = 0;
+ subWidth = 0;
+ // the following will get set later
+ subSide = ((aSide == NS_SIDE_LEFT) || (aSide == NS_SIDE_RIGHT)) ? NS_SIDE_TOP : NS_SIDE_LEFT;
+ subElem = eTableOwner;
+ subStyle = NS_STYLE_BORDER_STYLE_SOLID;
+}
+
+void
+BCCornerInfo::Update(PRUint8 aSide,
+ BCBorderOwner aBorderOwner,
+ PRUint8 aOwnerBStyle,
+ nscoord aOwnerWidth,
+ nscolor aOwnerColor)
+{
+ PRBool existingWins = PR_FALSE;
+ if (0xFF == ownerStyle) { // initial value indiating that it hasn't been set yet
+ Set(aSide, aBorderOwner, aOwnerBStyle, aOwnerWidth, aOwnerColor);
+ }
+ else {
+ PRBool horizontal = (NS_SIDE_LEFT == aSide) || (NS_SIDE_RIGHT == aSide); // relative to the corner
+ PRUint8 oldElem = ownerElem;
+ PRUint8 oldSide = ownerSide;
+ PRUint8 oldStyle = ownerStyle;
+ nscoord oldWidth = ownerWidth;
+ BCBorderOwner tempBorderOwner = (BCBorderOwner)ownerElem;
+ PRUint8 tempStyle = ownerStyle;
+ existingWins =
+ CalcDominateBorder(PR_TRUE, (BCBorderOwner)ownerElem, ownerStyle, ownerWidth, ownerColor,
+ (BCBorderOwner)aBorderOwner, aOwnerBStyle, aOwnerWidth, aOwnerColor,
+ tempBorderOwner, tempStyle, ownerWidth, ownerColor, horizontal);
+ ownerElem = tempBorderOwner;
+ ownerStyle = tempStyle;
+ if (existingWins) { // existing corner is dominate
+ if (::Perpendicular(ownerSide, aSide)) {
+ // see if the new sub info replaces the old
+ nscolor color;
+ tempBorderOwner = (BCBorderOwner)ownerElem;
+ PRUint8 tempStyle = subStyle;
+ PRBool firstWins =
+ CalcDominateBorder(PR_TRUE, (BCBorderOwner)subElem, subStyle, subWidth, color,
+ (BCBorderOwner)aBorderOwner, aOwnerBStyle, aOwnerWidth, aOwnerColor,
+ tempBorderOwner, tempStyle, subWidth, color, horizontal);
+ subElem = tempBorderOwner;
+ subStyle = tempStyle;
+ if (firstWins) {
+ subSide = aSide;
+ }
+ }
+ }
+ else { // input args are dominate
+ ownerSide = aSide;
+ if (::Perpendicular(oldSide, ownerSide)) {
+ subElem = oldElem;
+ subSide = oldSide;
+ subStyle = oldStyle;
+ subWidth = oldWidth;
+ }
+ }
+ if (aOwnerWidth > 0) {
+ numSegs++;
+ if (!hasDashDot && ((NS_STYLE_BORDER_STYLE_DASHED == aOwnerBStyle) ||
+ (NS_STYLE_BORDER_STYLE_DOTTED == aOwnerBStyle))) {
+ hasDashDot = 1;
+ }
+ }
+
+ // bevel the corner if only two perpendicular non dashed/dotted segments enter the corner
+ bevel = (2 == numSegs) && (subWidth > 1) && (0 == hasDashDot);
+ }
+}
+
+struct BCCorners
+{
+ BCCorners(PRInt32 aNumCorners,
+ PRInt32 aStartIndex);
+
+ ~BCCorners() { delete [] corners; }
+
+ BCCornerInfo& operator [](PRInt32 i) const
+ { NS_ASSERTION((i >= startIndex) && (i <= endIndex), "program error");
+ return corners[i - startIndex]; }
+
+ PRInt32 startIndex;
+ PRInt32 endIndex;
+ BCCornerInfo* corners;
+};
+
+BCCorners::BCCorners(PRInt32 aNumCorners,
+ PRInt32 aStartIndex)
+{
+ NS_ASSERTION((aNumCorners > 0) && (aStartIndex >= 0), "program error");
+ startIndex = aStartIndex;
+ endIndex = aStartIndex + aNumCorners - 1;
+ corners = new BCCornerInfo[aNumCorners];
+}
+
+struct BCCellBorder
+{
+ BCCellBorder() { Reset(); }
+ void Reset(PRUint32 aIndex = 0, PRUint32 aSpan = 1);
+ nscolor color;
+ PRUint16 index; // y index, not used for vertical borders
+ PRUint16 span; // row span
+ PRUint16 width;
+ PRUint8 style;
+};
+
+void
+BCCellBorder::Reset(PRUint32 aIndex,
+ PRUint32 aSpan)
+{
+ style = color = width = -1;
+ index = (PRUint16)aIndex;
+ span = (PRUint16)aSpan;
+}
+
+struct BCCellBorders
+{
+ BCCellBorders(PRInt32 aNumBorders,
+ PRInt32 aStartIndex);
+
+ ~BCCellBorders() { delete [] borders; }
+
+ BCCellBorder& operator [](PRInt32 i) const
+ { NS_ASSERTION((i >= startIndex) && (i <= endIndex), "program error");
+ return borders[i - startIndex]; }
+
+ PRInt32 startIndex;
+ PRInt32 endIndex;
+ BCCellBorder* borders;
+};
+
+BCCellBorders::BCCellBorders(PRInt32 aNumBorders,
+ PRInt32 aStartIndex)
+{
+ NS_ASSERTION((aNumBorders > 0) && (aStartIndex >= 0), "program error");
+ startIndex = aStartIndex;
+ endIndex = aStartIndex + aNumBorders - 1;
+ borders = new BCCellBorder[aNumBorders];
+}
+
+static PRBool
+SetBorder(PRUint8 aOwnerBStyle,
+ PRUint16 aOwnerWidth,
+ nscolor aOwnerColor,
+ BCCellBorder& aBorder)
+{
+ PRBool changed = (aOwnerBStyle != aBorder.style) || (aOwnerWidth != aBorder.width) ||
+ (aOwnerColor != aBorder.color);
+ aBorder.color = aOwnerColor;
+ aBorder.width = aOwnerWidth;
+ aBorder.style = aOwnerBStyle;
+
+ return changed;
+}
+
+static PRBool
+SetHorBorder(PRUint8 aOwnerBStyle,
+ PRUint16 aOwnerWidth,
+ PRUint32 aOwnerColor,
+ const BCCornerInfo& aCorner,
+ BCCellBorder& aBorder)
+{
+ PRBool startSeg = ::SetBorder(aOwnerBStyle, aOwnerWidth, aOwnerColor, aBorder);
+ if (!startSeg) {
+ startSeg = ((NS_SIDE_LEFT != aCorner.ownerSide) && (NS_SIDE_RIGHT != aCorner.ownerSide));
+ }
+ return startSeg;
+}
+
+// Make the damage area larger on the top and bottom by at least one row and on the left and right
+// at least one column. This is done so that adjacent elements are part of the border calculations.
+// The extra segments and borders outside the actual damage area will not be updated in the cell map,
+// because they in turn would need info from adjacent segments outside the damage area to be accurate.
+void
+nsTableFrame::ExpandBCDamageArea(nsRect& aRect) const
+{
+ PRInt32 numRows = GetRowCount();
+ PRInt32 numCols = GetColCount();
+
+ PRInt32 dStartX = aRect.x;
+ PRInt32 dEndX = aRect.XMost() - 1;
+ PRInt32 dStartY = aRect.y;
+ PRInt32 dEndY = aRect.YMost() - 1;
+
+ // expand the damage area in each direction
+ if (dStartX > 0) {
+ dStartX--;
+ }
+ if (dEndX < (numCols - 1)) {
+ dEndX++;
+ }
+ if (dStartY > 0) {
+ dStartY--;
+ }
+ if (dEndY < (numRows - 1)) {
+ dEndY++;
+ }
+ // Check the damage area so that there are no cells spanning in or out. If there are any then
+ // make the damage area as big as the table, similarly to the way the cell map decides whether
+ // to rebuild versus expand. This could be optimized to expand to the smallest area that contains
+ // no spanners, but it may not be worth the effort in general, and it would need to be done in the
+ // cell map as well.
+ if ((dStartX > 0) || (dEndX < (numCols - 1)) || (dStartY > 0) || (dEndY < (numRows - 1))) {
+ nsTableCellMap* tableCellMap = GetCellMap(); if (!tableCellMap) ABORT0();
+ PRBool haveSpanner = PR_FALSE;
+ // Get the ordered row groups
+ PRUint32 numRowGroups;
+ nsVoidArray rowGroups;
+ OrderRowGroups(rowGroups, numRowGroups, nsnull);
+ for (PRUint32 rgX = 0; rgX < numRowGroups; rgX++) {
+ nsIFrame* kidFrame = (nsIFrame*)rowGroups.ElementAt(rgX);
+ nsTableRowGroupFrame* rgFrame = GetRowGroupFrame(kidFrame); if (!rgFrame) ABORT0();
+ PRInt32 rgStartY = rgFrame->GetStartRowIndex();
+ PRInt32 rgEndY = rgStartY + rgFrame->GetRowCount() - 1;
+ if (dEndY < rgStartY)
+ break;
+ nsCellMap* cellMap = tableCellMap->GetMapFor(*rgFrame); if (!cellMap) ABORT0();
+ // check for spanners from above and below
+ if ((dStartY > 0) && (dStartY >= rgStartY) && (dStartY <= rgEndY)) {
+ nsVoidArray* row = (nsVoidArray*)cellMap->mRows.ElementAt(dStartY - rgStartY); if (!row) ABORT0();
+ for (PRInt32 x = dStartX; x <= dEndX; x++) {
+ CellData* cellData = (row->Count() > x) ? (CellData*)row->ElementAt(x) : nsnull;
+ if (cellData && (cellData->IsRowSpan())) {
+ haveSpanner = PR_TRUE;
+ break;
+ }
+ }
+ if (dEndY < rgEndY) {
+ row = (nsVoidArray*)cellMap->mRows.ElementAt(dEndY + 1 - rgStartY); if (!row) ABORT0();
+ for (PRInt32 x = dStartX; x <= dEndX; x++) {
+ CellData* cellData = (row->Count() > x) ? (CellData*)row->ElementAt(x) : nsnull;
+ if (cellData && (cellData->IsRowSpan())) {
+ haveSpanner = PR_TRUE;
+ break;
+ }
+ }
+ }
+ }
+ // check for spanners on the left and right
+ PRInt32 iterStartY = -1;
+ PRInt32 iterEndY = -1;
+ if ((dStartY >= rgStartY) && (dStartY <= rgEndY)) {
+ // the damage area starts in the row group
+ iterStartY = dStartY;
+ iterEndY = PR_MIN(dEndY, rgEndY);
+ }
+ else if ((dEndY >= rgStartY) && (dEndY <= rgEndY)) {
+ // the damage area ends in the row group
+ iterStartY = rgStartY;
+ iterEndY = PR_MIN(dEndY, rgStartY);
+ }
+ else if ((rgStartY >= dStartY) && (rgEndY <= dEndY)) {
+ // the damage area contains the row group
+ iterStartY = rgStartY;
+ iterEndY = rgEndY;
+ }
+ if ((iterStartY >= 0) && (iterEndY >= 0)) {
+ for (PRInt32 y = iterStartY; y <= iterEndY; y++) {
+ nsVoidArray* row = (nsVoidArray*)cellMap->mRows.ElementAt(y - rgStartY); if (!row) ABORT0();
+ CellData* cellData = (CellData*)row->ElementAt(dStartX);
+ if (cellData && (cellData->IsColSpan())) {
+ haveSpanner = PR_TRUE;
+ break;
+ }
+ if (dEndX < (numCols - 1)) {
+ cellData = (row->Count() > dEndX) ? (CellData*)row->ElementAt(dEndX + 1) : nsnull;
+ if (cellData && (cellData->IsColSpan())) {
+ haveSpanner = PR_TRUE;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ aRect.x = dStartX;
+ aRect.y = dStartY;
+ aRect.width = 1 + dEndX - dStartX;
+ aRect.height = 1 + dEndY - dStartY;
+}
+
+#define MAX_TABLE_BORDER_WIDTH 256
+static PRUint8
+LimitBorderWidth(PRUint16 aWidth)
+{
+ return PR_MIN(MAX_TABLE_BORDER_WIDTH, aWidth);
+}
+
+/* Here is the order for storing border edges in the cell map as a cell is processed. There are
+ n=colspan top and bottom border edges per cell and n=rowspan left and right border edges per cell.
+
+ 1) On the top edge of the table, store the top edge. Never store the top edge otherwise, since
+ a bottom edge from a cell above will take care of it.
+ 2) On the left edge of the table, store the left edge. Never store the left edge othewise, since
+ a right edge from a cell to the left will take care of it.
+ 3) Store the right edge (or edges if a row span)
+ 4) Store the bottom edge (or edges if a col span)
+
+ Since corners are computed with only an array of BCCornerInfo indexed by the number-of-cols, corner
+ calculations are somewhat complicated. Using an array with number-of-rows * number-of-col entries
+ would simplify this, but at an extra in memory cost of nearly 12 bytes per cell map entry. Collapsing
+ borders already have about an extra 8 byte per cell map entry overhead (this could be
+ reduced to 4 bytes if we are willing to not store border widths in nsTableCellFrame), Here are the
+ rules in priority order for storing cornes in the cell map as a cell is processed. top-left means the
+ left endpoint of the border edge on the top of the cell. There are n=colspan top and bottom border
+ edges per cell and n=rowspan left and right border edges per cell.
+
+ 1) On the top edge of the table, store the top-left corner, unless on the left edge of the table.
+ Never store the top-right corner, since it will get stored as a right-top corner.
+ 2) On the left edge of the table, store the left-top corner. Never store the left-bottom corner,
+ since it will get stored as a bottom-left corner.
+ 3) Store the right-top corner if (a) it is the top right corner of the table or (b) it is not on
+ the top edge of the table. Never store the right-bottom corner since it will get stored as a
+ bottom-right corner.
+ 4) Store the bottom-right corner, if it is the bottom right corner of the table. Never store it
+ otherwise, since it will get stored as either a right-top corner by a cell below or
+ a bottom-left corner from a cell to the right.
+ 5) Store the bottom-left corner, if (a) on the bottom edge of the table or (b) if the left edge hits
+ the top side of a colspan in its interior. Never store the corner otherwise, since it will
+ get stored as a right-top corner by a cell from below.
+ */
+
+#define TOP_DAMAGED(aRowIndex) ((aRowIndex) >= propData->mDamageArea.y)
+#define RIGHT_DAMAGED(aColIndex) ((aColIndex) <= propData->mDamageArea.XMost())
+#define BOTTOM_DAMAGED(aRowIndex) ((aRowIndex) <= propData->mDamageArea.YMost())
+#define LEFT_DAMAGED(aColIndex) ((aColIndex) >= propData->mDamageArea.x)
+
+// Calc the dominate border at every cell edge and corner within the current damage area
+void
+nsTableFrame::CalcBCBorders(nsIPresContext& aPresContext)
+{
+ nsTableCellMap* tableCellMap = GetCellMap(); if (!tableCellMap) ABORT0();
+ PRInt32 numRows = GetRowCount();
+ PRInt32 numCols = GetColCount();
+
+ // Get the property holding the table damage area and border widths
+ BCPropertyData* propData =
+ (BCPropertyData*)nsTableFrame::GetProperty(&aPresContext, this, nsLayoutAtoms::tableBCProperty, PR_FALSE);
+ if (!propData) ABORT0();
+ // calculate an expanded damage area
+ nsRect damageArea(propData->mDamageArea);
+ ExpandBCDamageArea(damageArea);
+
+ // segments that are on the table border edges need to be initialized only once
+ PRBool tableBorderReset[4];
+ for (PRUint32 sideX = NS_SIDE_TOP; sideX <= NS_SIDE_LEFT; sideX++) {
+ tableBorderReset[sideX] = PR_FALSE;
+ }
+ GET_TWIPS_TO_PIXELS(&aPresContext, t2p);
+
+ const nsStyleBorder* tableStyle =
+ (const nsStyleBorder*)mStyleContext->GetStyleData(eStyleStruct_Border);
+
+ // vertical borders indexed in x-direction (cols)
+ BCCellBorders lastVerBorders(damageArea.width + 1, damageArea.x); if (!lastVerBorders.borders) ABORT0();
+ BCCellBorder lastTopBorder, lastBottomBorder;
+ // horizontal borders indexed in x-direction (cols)
+ BCCellBorders lastBottomBorders(damageArea.width + 1, damageArea.x); if (!lastBottomBorders.borders) ABORT0();
+ PRBool startSeg;
+
+ BCMapCellInfo info, ajaInfo;
+ BCBorderOwner owner, ajaOwner;
+ nscolor ownerColor, ajaColor;
+ PRUint8 ownerBStyle, ajaBStyle;
+ PRUint16 ownerWidth, ajaWidth;
+ PRInt32 cellEndRowIndex = -1;
+ PRInt32 cellEndColIndex = -1;
+ nscoord smallHalf, largeHalf;
+ BCCorners topCorners(damageArea.width + 1, damageArea.x); if (!topCorners.corners) ABORT0();
+ BCCorners bottomCorners(damageArea.width + 1, damageArea.x); if (!bottomCorners.corners) ABORT0();
+ nsTableRowFrame* prevRow = nsnull;
+
+ BCMapCellIterator iter(*this, damageArea);
+ for (iter.First(info); !iter.mAtEnd; iter.Next(info)) {
+
+ cellEndRowIndex = info.rowIndex + info.rowSpan - 1;
+ cellEndColIndex = info.colIndex + info.colSpan - 1;
+ PRBool isBottomRight = (info.rowIndex == (numRows - 1)) && (info.colIndex == (numCols - 1));
+
+ PRBool bottomRowSpan = PR_FALSE;
+ // see if lastTopBorder, lastBottomBorder need to be reset
+ if (iter.IsNewRow()) {
+ lastTopBorder.Reset(info.rowIndex, info.rowSpan);
+ lastBottomBorder.Reset(cellEndRowIndex + 1, info.rowSpan);
+ }
+ else if (info.colIndex > damageArea.x) {
+ BCCellBorder& prevBorder = lastBottomBorders[info.colIndex - 1];
+ if (info.rowIndex > prevBorder.index - prevBorder.span) {
+ // the top border's left edge butts against the middle of a rowspan
+ lastTopBorder.Reset(info.rowIndex, info.rowSpan);
+ }
+ if (prevBorder.index > (cellEndRowIndex + 1)) {
+ // the bottom border's left edge butts against the middle of a rowspan
+ lastBottomBorder.Reset(cellEndRowIndex + 1, info.rowSpan);
+ bottomRowSpan = PR_TRUE;
+ }
+ }
+
+ // find the dominate border considernig the cell's top border and the table, row group, row
+ // if the border is at the top of the table, otherwise it was processed in a previous row
+ if (0 == info.rowIndex) {
+ if (!tableBorderReset[NS_SIDE_TOP]) {
+ propData->mTopBorderWidth = 0;
+ tableBorderReset[NS_SIDE_TOP] = PR_TRUE;
+ }
+ for (PRInt32 colX = info.colIndex; colX <= cellEndColIndex; colX++) {
+ nsIFrame* colFrame = GetColFrame(colX); if (!colFrame) ABORT0();
+ nsIFrame* cgFrame;
+ colFrame->GetParent(&cgFrame); if (!cgFrame) ABORT0();
+ CalcDominateBorder(this, cgFrame, colFrame, info.rg, info.topRow, info.cell, PR_TRUE, NS_SIDE_TOP,
+ PR_FALSE, t2p, owner, ownerBStyle, ownerWidth, ownerColor);
+ // update/store the top left & top right corners of the seg
+ BCCornerInfo& tlCorner = topCorners[colX]; // top left
+ if (0 == colX) {
+ tlCorner.Set(NS_SIDE_RIGHT, owner, ownerBStyle, ownerWidth, ownerColor);
+ }
+ else {
+ tlCorner.Update(NS_SIDE_RIGHT, owner, ownerBStyle, ownerWidth, ownerColor);
+ tableCellMap->SetBCBorderCorner(eTopLeft, *info.cellMap, 0, 0, colX,
+ tlCorner.ownerSide, tlCorner.subWidth, tlCorner.bevel);
+ }
+ topCorners[colX + 1].Set(NS_SIDE_LEFT, owner, ownerBStyle, ownerWidth, ownerColor); // top right
+ // update lastTopBorder and see if a new segment starts
+ startSeg = SetHorBorder(ownerBStyle, ownerWidth, ownerColor, tlCorner, lastTopBorder);
+ // store the border segment in the cell map
+ tableCellMap->SetBCBorderEdge(NS_SIDE_TOP, *info.cellMap, 0, 0, colX,
+ 1, owner, ownerWidth, startSeg);
+ // update the affected borders of the cell, row, and table
+ DivideBCBorderSize(ownerWidth, smallHalf, largeHalf);
+ if (info.cell) {
+ info.cell->SetBorderWidth(NS_SIDE_TOP, PR_MAX(smallHalf, info.cell->GetBorderWidth(NS_SIDE_TOP)));
+ }
+ if (info.topRow) {
+ info.topRow->SetTopBCBorderWidth(PR_MAX(smallHalf, info.topRow->GetTopBCBorderWidth()));
+ }
+ propData->mTopBorderWidth = LimitBorderWidth(PR_MAX(propData->mTopBorderWidth, (PRUint8)ownerWidth));
+ }
+ }
+ else {
+ // see if the top border needs to be the start of a segment due to a vertical border owning the corner
+ if (info.colIndex > 0) {
+ BCData& data = ((BCCellData*)info.cellData)->mData;
+ if (!data.IsTopStart()) {
+ PRUint8 cornerSide;
+ PRPackedBool bevel;
+ data.GetCorner(cornerSide, bevel);
+ if ((NS_SIDE_TOP == cornerSide) || (NS_SIDE_BOTTOM == cornerSide)) {
+ data.SetTopStart(PR_TRUE);
+ }
+ }
+ }
+ }
+
+ // find the dominate border considernig the cell's left border and the table, col group, col
+ // if the border is at the left of the table, otherwise it was processed in a previous col
+ if (0 == info.colIndex) {
+ if (!tableBorderReset[NS_SIDE_LEFT]) {
+ propData->mLeftBorderWidth = 0;
+ tableBorderReset[NS_SIDE_LEFT] = PR_TRUE;
+ }
+ for (PRInt32 rowX = info.rowIndex; rowX <= cellEndRowIndex; rowX++) {
+ nsTableRowFrame* rowFrame = (rowX == info.rowIndex) ? info.topRow : rowFrame->GetNextRow();
+ CalcDominateBorder(this, info.cg, info.leftCol, info.rg, rowFrame, info.cell, PR_TRUE, NS_SIDE_LEFT,
+ PR_FALSE, t2p, owner, ownerBStyle, ownerWidth, ownerColor);
+ BCCornerInfo& tlCorner = (0 == rowX) ? topCorners[0] : bottomCorners[0]; // top left
+ tlCorner.Update(NS_SIDE_BOTTOM, owner, ownerBStyle, ownerWidth, ownerColor);
+ tableCellMap->SetBCBorderCorner(eTopLeft, *info.cellMap, iter.mRowGroupStart, rowX,
+ 0, tlCorner.ownerSide, tlCorner.subWidth, tlCorner.bevel);
+ bottomCorners[0].Set(NS_SIDE_TOP, owner, ownerBStyle, ownerWidth, ownerColor); // bottom left
+ // update lastVerBordersBorder and see if a new segment starts
+ startSeg = SetBorder(ownerBStyle, ownerWidth, ownerColor, lastVerBorders[0]);
+ // store the border segment in the cell map
+ tableCellMap->SetBCBorderEdge(NS_SIDE_LEFT, *info.cellMap, iter.mRowGroupStart, rowX,
+ info.colIndex, 1, owner, ownerWidth, startSeg);
+ // update the left border of the cell, col and table
+ DivideBCBorderSize(ownerWidth, smallHalf, largeHalf);
+ if (info.cell) {
+ info.cell->SetBorderWidth(NS_SIDE_LEFT, PR_MAX(smallHalf, info.cell->GetBorderWidth(NS_SIDE_LEFT)));
+ }
+ if (info.leftCol) {
+ info.leftCol->SetLeftBorderWidth(PR_MAX(smallHalf, info.leftCol->GetLeftBorderWidth()));
+ }
+ propData->mLeftBorderWidth = LimitBorderWidth(PR_MAX(propData->mLeftBorderWidth, ownerWidth));
+ }
+ }
+
+ // find the dominate border considernig the cell's right border, adjacent cells and the table, row group, row
+ if (numCols == cellEndColIndex + 1) { // touches right edge of table
+ if (!tableBorderReset[NS_SIDE_RIGHT]) {
+ propData->mRightBorderWidth = 0;
+ tableBorderReset[NS_SIDE_RIGHT] = PR_TRUE;
+ }
+ for (PRInt32 rowX = info.rowIndex; rowX <= cellEndRowIndex; rowX++) {
+ nsTableRowFrame* rowFrame = (rowX == info.rowIndex) ? info.topRow : rowFrame->GetNextRow();
+ CalcDominateBorder(this, info.cg, info.rightCol, info.rg, rowFrame, info.cell, PR_TRUE, NS_SIDE_RIGHT,
+ PR_TRUE, t2p, owner, ownerBStyle, ownerWidth, ownerColor);
+ // update/store the top right & bottom right corners
+ BCCornerInfo& trCorner = (0 == rowX) ? topCorners[cellEndColIndex + 1] : bottomCorners[cellEndColIndex + 1];
+ trCorner.Update(NS_SIDE_BOTTOM, owner, ownerBStyle, ownerWidth, ownerColor); // top right
+ tableCellMap->SetBCBorderCorner(eTopRight, *info.cellMap, iter.mRowGroupStart, rowX,
+ cellEndColIndex, trCorner.ownerSide, trCorner.subWidth, trCorner.bevel);
+ BCCornerInfo& brCorner = bottomCorners[cellEndColIndex + 1];
+ brCorner.Set(NS_SIDE_TOP, owner, ownerBStyle, ownerWidth, ownerColor); // bottom right
+ tableCellMap->SetBCBorderCorner(eBottomRight, *info.cellMap, iter.mRowGroupStart, rowX,
+ cellEndColIndex, brCorner.ownerSide, brCorner.subWidth, brCorner.bevel);
+ // update lastVerBorders and see if a new segment starts
+ startSeg = SetBorder(ownerBStyle, ownerWidth, ownerColor, lastVerBorders[cellEndColIndex + 1]);
+ // store the border segment in the cell map and update cellBorders
+ tableCellMap->SetBCBorderEdge(NS_SIDE_RIGHT, *info.cellMap, iter.mRowGroupStart, rowX,
+ cellEndColIndex, 1, owner, ownerWidth, startSeg);
+ // update the affected borders of the cell, col, and table
+ DivideBCBorderSize(ownerWidth, smallHalf, largeHalf);
+ if (info.cell) {
+ info.cell->SetBorderWidth(NS_SIDE_RIGHT, PR_MAX(largeHalf, info.cell->GetBorderWidth(NS_SIDE_RIGHT)));
+ }
+ if (info.rightCol) {
+ info.rightCol->SetRightBorderWidth(PR_MAX(largeHalf, info.rightCol->GetRightBorderWidth()));
+ }
+ propData->mRightBorderWidth = LimitBorderWidth(PR_MAX(propData->mRightBorderWidth, ownerWidth));
+ }
+ }
+ else {
+ PRInt32 segLength = 0;
+ BCMapCellInfo priorAjaInfo;
+ for (PRInt32 rowX = info.rowIndex; rowX <= cellEndRowIndex; rowX += segLength) {
+ iter.PeekRight(info, rowX, ajaInfo);
+ const nsIFrame* cg = (info.cgRight) ? info.cg : nsnull;
+ CalcDominateBorder(nsnull, cg, info.rightCol, nsnull, nsnull, info.cell, PR_FALSE, NS_SIDE_RIGHT,
+ PR_TRUE, t2p, owner, ownerBStyle, ownerWidth, ownerColor);
+ cg = (ajaInfo.cgLeft) ? ajaInfo.cg : nsnull;
+ CalcDominateBorder(nsnull, cg, ajaInfo.leftCol, nsnull, nsnull, ajaInfo.cell, PR_FALSE, NS_SIDE_LEFT,
+ PR_FALSE, t2p, ajaOwner, ajaBStyle, ajaWidth, ajaColor);
+ CalcDominateBorder(PR_FALSE, owner, ownerBStyle, ownerWidth, ownerColor, ajaOwner, ajaBStyle,
+ ajaWidth, ajaColor, owner, ownerBStyle, ownerWidth, ownerColor, PR_FALSE);
+ segLength = PR_MAX(1, ajaInfo.rowIndex + ajaInfo.rowSpan - rowX);
+ segLength = PR_MIN(segLength, info.rowIndex + info.rowSpan - rowX);
+
+ // update lastVerBorders and see if a new segment starts
+ startSeg = SetBorder(ownerBStyle, ownerWidth, ownerColor, lastVerBorders[cellEndColIndex + 1]);
+ // store the border segment in the cell map and update cellBorders
+ if (RIGHT_DAMAGED(cellEndColIndex) && TOP_DAMAGED(rowX) && BOTTOM_DAMAGED(rowX)) {
+ tableCellMap->SetBCBorderEdge(NS_SIDE_RIGHT, *info.cellMap, iter.mRowGroupStart, rowX,
+ cellEndColIndex, segLength, owner, ownerWidth, startSeg);
+ // update the borders of the cells and cols affected
+ DivideBCBorderSize(ownerWidth, smallHalf, largeHalf);
+ if (info.cell) {
+ info.cell->SetBorderWidth(NS_SIDE_RIGHT, PR_MAX(largeHalf, info.cell->GetBorderWidth(NS_SIDE_RIGHT)));
+ }
+ if (info.rightCol) {
+ info.rightCol->SetRightBorderWidth(PR_MAX(largeHalf, info.rightCol->GetRightBorderWidth()));
+ }
+ if (ajaInfo.cell) {
+ ajaInfo.cell->SetBorderWidth(NS_SIDE_LEFT, PR_MAX(smallHalf, ajaInfo.cell->GetBorderWidth(NS_SIDE_LEFT)));
+ }
+ if (ajaInfo.leftCol) {
+ ajaInfo.leftCol->SetLeftBorderWidth(PR_MAX(smallHalf, ajaInfo.leftCol->GetLeftBorderWidth()));
+ }
+ }
+ // update the top right corner
+ PRBool hitsSpanOnRight = (rowX > ajaInfo.rowIndex) && (rowX < ajaInfo.rowIndex + ajaInfo.rowSpan);
+ BCCornerInfo* trCorner = ((0 == rowX) || hitsSpanOnRight)
+ ? &topCorners[cellEndColIndex + 1] : &bottomCorners[cellEndColIndex + 1];
+ trCorner->Update(NS_SIDE_BOTTOM, owner, ownerBStyle, ownerWidth, ownerColor);
+ // if this is not the first time through, consider the segment to the right
+ if (rowX != info.rowIndex) {
+ const nsIFrame* rg = (priorAjaInfo.rgBottom) ? priorAjaInfo.rg : nsnull;
+ CalcDominateBorder(nsnull, nsnull, nsnull, rg, priorAjaInfo.bottomRow, priorAjaInfo.cell, PR_FALSE,
+ NS_SIDE_BOTTOM, PR_TRUE, t2p, owner, ownerBStyle, ownerWidth, ownerColor);
+ rg = (ajaInfo.rgTop) ? ajaInfo.rg : nsnull;
+ CalcDominateBorder(nsnull, nsnull, nsnull, rg, ajaInfo.topRow, ajaInfo.cell, PR_FALSE, NS_SIDE_TOP,
+ PR_FALSE, t2p, ajaOwner, ajaBStyle, ajaWidth, ajaColor);
+ CalcDominateBorder(PR_FALSE, owner, ownerBStyle, ownerWidth, ownerColor, ajaOwner, ajaBStyle,
+ ajaWidth, ajaColor, owner, ownerBStyle, ownerWidth, ownerColor, PR_TRUE);
+ trCorner->Update(NS_SIDE_RIGHT, owner, ownerBStyle, ownerWidth, ownerColor);
+ }
+ // store the top right corner in the cell map
+ if (RIGHT_DAMAGED(cellEndColIndex) && TOP_DAMAGED(rowX)) {
+ if (0 != rowX) {
+ tableCellMap->SetBCBorderCorner(eTopRight, *info.cellMap, iter.mRowGroupStart, rowX, cellEndColIndex,
+ trCorner->ownerSide, trCorner->subWidth, trCorner->bevel);
+ }
+ // store any corners this cell spans together with the aja cell
+ for (PRInt32 rX = rowX + 1; rX < rowX + segLength; rX++) {
+ tableCellMap->SetBCBorderCorner(eBottomRight, *info.cellMap, iter.mRowGroupStart, rX,
+ cellEndColIndex, trCorner->ownerSide, trCorner->subWidth, PR_FALSE);
+ }
+ }
+ // update bottom right corner, topCorners, bottomCorners
+ hitsSpanOnRight = (rowX + segLength < ajaInfo.rowIndex + ajaInfo.rowSpan);
+ BCCornerInfo& brCorner = (hitsSpanOnRight) ? topCorners[cellEndColIndex + 1]
+ : bottomCorners[cellEndColIndex + 1];
+ brCorner.Set(NS_SIDE_TOP, owner, ownerBStyle, ownerWidth, ownerColor);
+ priorAjaInfo = ajaInfo;
+ }
+ }
+ for (PRInt32 colX = info.colIndex + 1; colX <= cellEndColIndex; colX++) {
+ lastVerBorders[colX].Reset();
+ }
+
+ // find the dominate border considernig the cell's bottom border, adjacent cells and the table, row group, row
+ if (numRows == cellEndRowIndex + 1) { // touches botom edge of table
+ if (!tableBorderReset[NS_SIDE_BOTTOM]) {
+ propData->mBottomBorderWidth = 0;
+ tableBorderReset[NS_SIDE_BOTTOM] = PR_TRUE;
+ }
+ for (PRInt32 colX = info.colIndex; colX <= cellEndColIndex; colX++) {
+ nsIFrame* colFrame = GetColFrame(colX); if (!colFrame) ABORT0();
+ nsIFrame* cgFrame;
+ colFrame->GetParent(&cgFrame); if (!cgFrame) ABORT0();
+ CalcDominateBorder(this, cgFrame, colFrame, info.rg, info.bottomRow, info.cell, PR_TRUE, NS_SIDE_BOTTOM,
+ PR_TRUE, t2p, owner, ownerBStyle, ownerWidth, ownerColor);
+ // update/store the bottom left & bottom right corners
+ BCCornerInfo& blCorner = bottomCorners[colX]; // bottom left
+ blCorner.Update(NS_SIDE_RIGHT, owner, ownerBStyle, ownerWidth, ownerColor);
+ tableCellMap->SetBCBorderCorner(eBottomLeft, *info.cellMap, iter.mRowGroupStart, cellEndRowIndex,
+ colX, blCorner.ownerSide, blCorner.subWidth, blCorner.bevel);
+ BCCornerInfo& brCorner = bottomCorners[colX + 1]; // bottom right
+ brCorner.Update(NS_SIDE_LEFT, owner, ownerBStyle, ownerWidth, ownerColor);
+ if (numCols == colX + 1) { // lower right corner of the table
+ tableCellMap->SetBCBorderCorner(eBottomRight, *info.cellMap, iter.mRowGroupStart, cellEndRowIndex,
+ colX, brCorner.ownerSide, brCorner.subWidth, brCorner.bevel, isBottomRight);
+ }
+ // update lastBottomBorder and see if a new segment starts
+ startSeg = SetHorBorder(ownerBStyle, ownerWidth, ownerColor, blCorner, lastBottomBorder);
+ // store the border segment in the cell map and update cellBorders
+ tableCellMap->SetBCBorderEdge(NS_SIDE_BOTTOM, *info.cellMap, iter.mRowGroupStart, cellEndRowIndex,
+ colX, 1, owner, ownerWidth, startSeg);
+ // update the bottom borders of the cell, the bottom row, and the table
+ DivideBCBorderSize(ownerWidth, smallHalf, largeHalf);
+ if (info.cell) {
+ info.cell->SetBorderWidth(NS_SIDE_BOTTOM, PR_MAX(largeHalf, info.cell->GetBorderWidth(NS_SIDE_BOTTOM)));
+ }
+ if (info.bottomRow) {
+ info.bottomRow->SetBottomBCBorderWidth(PR_MAX(largeHalf, info.bottomRow->GetBottomBCBorderWidth()));
+ }
+ propData->mBottomBorderWidth = LimitBorderWidth(PR_MAX(propData->mBottomBorderWidth, ownerWidth));
+ // update lastBottomBorders
+ lastBottomBorder.index = cellEndRowIndex + 1;
+ lastBottomBorder.span = info.rowSpan;
+ lastBottomBorders[colX] = lastBottomBorder;
+ }
+ }
+ else {
+ PRInt32 segLength = 0;
+ for (PRInt32 colX = info.colIndex; colX <= cellEndColIndex; colX += segLength) {
+ iter.PeekBottom(info, colX, ajaInfo);
+ const nsIFrame* rg = (info.rgBottom) ? info.rg : nsnull;
+ CalcDominateBorder(nsnull, nsnull, nsnull, rg, info.bottomRow, info.cell, PR_FALSE, NS_SIDE_BOTTOM,
+ PR_TRUE, t2p, owner, ownerBStyle, ownerWidth, ownerColor);
+ rg = (ajaInfo.rgTop) ? ajaInfo.rg : nsnull;
+ CalcDominateBorder(nsnull, nsnull, nsnull, rg, ajaInfo.topRow, ajaInfo.cell, PR_FALSE, NS_SIDE_TOP,
+ PR_FALSE, t2p, ajaOwner, ajaBStyle, ajaWidth, ajaColor);
+ CalcDominateBorder(PR_FALSE, owner, ownerBStyle, ownerWidth, ownerColor, ajaOwner, ajaBStyle, ajaWidth,
+ ajaColor, owner, ownerBStyle, ownerWidth, ownerColor, PR_TRUE);
+ segLength = PR_MAX(1, ajaInfo.colIndex + ajaInfo.colSpan - colX);
+ segLength = PR_MIN(segLength, info.colIndex + info.colSpan - colX);
+
+ // update, store the bottom left corner
+ BCCornerInfo& blCorner = bottomCorners[colX]; // bottom left
+ PRBool hitsSpanBelow = (colX > ajaInfo.colIndex) && (colX < ajaInfo.colIndex + ajaInfo.colSpan);
+ PRBool update = PR_TRUE;
+ if ((colX == info.colIndex) && (colX > damageArea.x)) {
+ PRInt32 prevRowIndex = lastBottomBorders[colX - 1].index;
+ if (prevRowIndex > cellEndRowIndex + 1) { // hits a rowspan on the right
+ update = PR_FALSE; // the corner was taken care of during the cell on the left
+ }
+ else if (prevRowIndex < cellEndRowIndex) { // spans below the cell to the left
+ topCorners[colX] = blCorner;
+ blCorner.Set(NS_SIDE_RIGHT, owner, ownerBStyle, ownerWidth, ownerColor);
+ update = PR_FALSE;
+ }
+ }
+ if (update) {
+ blCorner.Update(NS_SIDE_RIGHT, owner, ownerBStyle, ownerWidth, ownerColor);
+ }
+ if (BOTTOM_DAMAGED(cellEndRowIndex) && LEFT_DAMAGED(colX)) {
+ if (hitsSpanBelow) {
+ tableCellMap->SetBCBorderCorner(eBottomLeft, *info.cellMap, iter.mRowGroupStart, cellEndRowIndex, colX,
+ blCorner.ownerSide, blCorner.subWidth, blCorner.bevel);
+ }
+ // store any corners this cell spans together with the aja cell
+ for (PRInt32 cX = colX + 1; cX < colX + segLength; cX++) {
+ BCCornerInfo& corner = bottomCorners[cX];
+ corner.Set(NS_SIDE_RIGHT, owner, ownerBStyle, ownerWidth, ownerColor);
+ tableCellMap->SetBCBorderCorner(eBottomLeft, *info.cellMap, iter.mRowGroupStart, cellEndRowIndex,
+ cX, corner.ownerSide, corner.subWidth, PR_FALSE);
+ }
+ }
+ // update lastBottomBorders and see if a new segment starts
+ startSeg = SetHorBorder(ownerBStyle, ownerWidth, ownerColor, blCorner, lastBottomBorder);
+ lastBottomBorder.index = cellEndRowIndex + 1;
+ lastBottomBorder.span = info.rowSpan;
+ for (PRInt32 cX = colX; cX < colX + segLength; cX++) {
+ lastBottomBorders[cX] = lastBottomBorder;
+ }
+
+ // store the border segment the cell map and update cellBorders
+ if (BOTTOM_DAMAGED(cellEndRowIndex) && LEFT_DAMAGED(colX) && RIGHT_DAMAGED(colX)) {
+ tableCellMap->SetBCBorderEdge(NS_SIDE_BOTTOM, *info.cellMap, iter.mRowGroupStart, cellEndRowIndex,
+ colX, segLength, owner, ownerWidth, startSeg);
+ // update the borders of the affected cells and rows
+ DivideBCBorderSize(ownerWidth, smallHalf, largeHalf);
+ if (info.cell) {
+ info.cell->SetBorderWidth(NS_SIDE_BOTTOM, PR_MAX(largeHalf, info.cell->GetBorderWidth(NS_SIDE_BOTTOM)));
+ }
+ if (info.bottomRow) {
+ info.bottomRow->SetBottomBCBorderWidth(PR_MAX(largeHalf, info.bottomRow->GetBottomBCBorderWidth()));
+ }
+ if (ajaInfo.cell) {
+ ajaInfo.cell->SetBorderWidth(NS_SIDE_TOP, PR_MAX(smallHalf, ajaInfo.cell->GetBorderWidth(NS_SIDE_TOP)));
+ }
+ if (ajaInfo.topRow) {
+ ajaInfo.topRow->SetTopBCBorderWidth(PR_MAX(smallHalf, ajaInfo.topRow->GetTopBCBorderWidth()));
+ }
+ }
+ // update bottom right corner
+ BCCornerInfo& brCorner = bottomCorners[colX + segLength];
+ brCorner.Update(NS_SIDE_LEFT, owner, ownerBStyle, ownerWidth, ownerColor);
+ }
+ }
+
+ // see if the cell to the right had a rowspan and its lower left border needs be joined with this one's bottom
+ if ((numCols != cellEndColIndex + 1) && // there is a cell to the right
+ (lastBottomBorders[cellEndColIndex + 1].span > 1)) { // cell to right was a rowspan
+ BCCornerInfo& corner = bottomCorners[cellEndColIndex + 1];
+ if ((NS_SIDE_TOP != corner.ownerSide) && (NS_SIDE_BOTTOM != corner.ownerSide)) { // not a vertical owner
+ BCCellBorder& thisBorder = lastBottomBorder;
+ BCCellBorder& nextBorder = lastBottomBorders[info.colIndex + 1];
+ if ((thisBorder.color == nextBorder.color) && (thisBorder.width == nextBorder.width) &&
+ (thisBorder.style == nextBorder.style)) {
+ // set the flag on the next border indicating it is not the start of a new segment
+ if (iter.mCellMap) {
+ BCData* bcData = tableCellMap->GetBCData(NS_SIDE_BOTTOM, *iter.mCellMap, cellEndRowIndex,
+ cellEndColIndex + 1);
+ if (bcData) {
+ bcData->SetTopStart(PR_FALSE);
+ }
+ }
+ }
+ }
+ }
+ } // for (iter.First(info); info.cell; iter.Next(info)) {
+
+ // reset the bc flag and damage area
+ SetNeedToCalcBCBorders(PR_FALSE);
+ propData->mDamageArea.x = propData->mDamageArea.y = propData->mDamageArea.width = propData->mDamageArea.height = 0;
+ //mCellMap->Dump();
+}
+
+// Iterates over borders (left border, corner, top border) in the cell map within a damage area
+// from left to right, top to bottom. All members are in terms of the 1st in flow frames, except
+// where suffixed by InFlow.
+class BCMapBorderIterator
+{
+public:
+ BCMapBorderIterator(nsTableFrame& aTableFrameInFlow,
+ nsTableRowGroupFrame& aRowGroupFrameInFlow,
+ nsTableRowFrame& aRowInFlow,
+ const nsRect& aDamageArea);
+ void Reset(nsTableFrame& aTableFrameInFlow,
+ nsTableRowGroupFrame& aRowGroupFrameInFlow,
+ nsTableRowFrame& aRowInFlow,
+ const nsRect& aDamageArea);
+ void First();
+ void Next();
+
+ nsTableFrame* tableInFlow;
+ nsTableFrame* table;
+ nsTableCellMap* tableCellMap;
+ nsCellMap* cellMap;
+
+ nsVoidArray rowGroups;
+ nsTableRowGroupFrame* prevRg;
+ nsTableRowGroupFrame* rgInFlow;
+ nsTableRowGroupFrame* rg;
+ PRInt32 rowGroupIndex;
+ PRInt32 rowGroupStart;
+ PRInt32 rowGroupEnd;
+ PRInt32 numRows;
+
+ nsTableRowFrame* prevRow;
+ nsTableRowFrame* rowInFlow;
+ nsTableRowFrame* row;
+ PRInt32 numCols;
+ PRInt32 x;
+ PRInt32 y;
+
+ nsTableCellFrame* prevCell;
+ nsTableCellFrame* cell;
+ BCCellData* prevCellData;
+ BCCellData* cellData;
+ BCData* bcData;
+
+ PRBool IsTopMostTable() { return (y == 0) && !tableInFlow->GetPrevInFlow(); }
+ PRBool IsRightMostTable() { return (x >= numCols); }
+ PRBool IsBottomMostTable() { return (y >= numRows) && !tableInFlow->GetNextInFlow(); }
+ PRBool IsLeftMostTable() { return (x == 0); }
+ PRBool IsTopMost() { return (y == startY); }
+ PRBool IsRightMost() { return (x >= endX); }
+ PRBool IsBottomMost() { return (y >= endY); }
+ PRBool IsLeftMost() { return (x == startX); }
+ PRBool isNewRow;
+
+ PRInt32 startX;
+ PRInt32 startY;
+ PRInt32 endX;
+ PRInt32 endY;
+ PRBool isRepeatedHeader;
+ PRBool isRepeatedFooter;
+ PRBool atEnd;
+
+private:
+
+ PRBool SetNewRow(nsTableRowFrame* aRowInFlow = nsnull,
+ nsTableRowFrame* aRow = nsnull);
+ PRBool SetNewRowGroup(PRBool aSetInFlow);
+ void SetNewData(PRInt32 aY, PRInt32 aX);
+
+};
+
+BCMapBorderIterator::BCMapBorderIterator(nsTableFrame& aTableInFlow,
+ nsTableRowGroupFrame& aRowGroupInFlow,
+ nsTableRowFrame& aRowInFlow,
+ const nsRect& aDamageArea)
+{
+ Reset(aTableInFlow, aRowGroupInFlow, aRowInFlow, aDamageArea);
+}
+
+void
+BCMapBorderIterator::Reset(nsTableFrame& aTableInFlow,
+ nsTableRowGroupFrame& aRowGroupInFlow,
+ nsTableRowFrame& aRowInFlow,
+ const nsRect& aDamageArea)
+{
+ atEnd = PR_TRUE; // gets reset when First() is called
+
+ tableInFlow = &aTableInFlow;
+ table = (nsTableFrame*)aTableInFlow.GetFirstInFlow(); if (!table) ABORT0();
+ rgInFlow = &aRowGroupInFlow;
+ rowInFlow = &aRowInFlow;
+
+ tableCellMap = table->GetCellMap();
+
+ startX = aDamageArea.x;
+ startY = aDamageArea.y;
+ endY = aDamageArea.y + aDamageArea.height;
+ endX = aDamageArea.x + aDamageArea.width;
+
+ numRows = table->GetRowCount();
+ y = 0;
+ numCols = table->GetColCount();
+ x = 0;
+ rowGroupIndex = -1;
+ rg = nsnull;
+ row = nsnull;
+ cell = nsnull;
+ cellData = nsnull;
+
+ // Get the ordered row groups
+ PRUint32 numRowGroups;
+ table->OrderRowGroups(rowGroups, numRowGroups, nsnull);
+}
+
+void
+BCMapBorderIterator::SetNewData(PRInt32 aY,
+ PRInt32 aX)
+{
+ if (!tableCellMap || !tableCellMap->mBCInfo) ABORT0();
+
+ x = aX;
+ y = aY;
+ prevCellData = cellData;
+ if (IsRightMost() && IsBottomMost()) {
+ cell = nsnull;
+ bcData = &tableCellMap->mBCInfo->mLowerRightCorner;
+ }
+ else if (IsRightMost()) {
+ cellData = nsnull;
+ bcData = (BCData*)tableCellMap->mBCInfo->mRightBorders.ElementAt(aY);
+ }
+ else if (IsBottomMost()) {
+ cellData = nsnull;
+ bcData = (BCData*)tableCellMap->mBCInfo->mBottomBorders.ElementAt(aX);
+ }
+ else {
+ bcData = nsnull;
+ nsVoidArray* row = (nsVoidArray*)cellMap->mRows.ElementAt(y - rowGroupStart);
+ if (row) {
+ cellData = (row->Count() > x) ? (BCCellData*)row->ElementAt(x) : nsnull;
+ if (cellData) {
+ bcData = &cellData->mData;
+ if (!cellData->IsOrig()) {
+ if (cellData->IsRowSpan()) {
+ aY -= cellData->GetRowSpanOffset();
+ }
+ if (cellData->IsColSpan()) {
+ aX -= cellData->GetColSpanOffset();
+ }
+ if ((aX >= 0) && (aY >= 0)) {
+ row = (nsVoidArray*)cellMap->mRows.ElementAt(aY - rowGroupStart);
+ if (row) {
+ cellData = (BCCellData*)row->ElementAt(aX);
+ }
+ }
+ }
+ if (cellData->IsOrig()) {
+ prevCell = cell;
+ cell = cellData->GetCellFrame();
+ }
+ }
+ }
+ }
+}
+
+PRBool
+BCMapBorderIterator::SetNewRow(nsTableRowFrame* aRowInFlow,
+ nsTableRowFrame* aRow)
+{
+ prevRow = row;
+ row = (aRow) ? aRow : row->GetNextRow();
+ rowInFlow = (aRowInFlow) ? aRowInFlow : rowInFlow->GetNextRow();
+
+ if (rowInFlow && row) {
+ isNewRow = PR_TRUE;
+ y = row->GetRowIndex();
+ x = startX;
+ }
+ else {
+ atEnd = PR_TRUE;
+ }
+ return !atEnd;
+}
+
+
+PRBool
+BCMapBorderIterator::SetNewRowGroup(PRBool aSetInFlow)
+{
+ rowGroupIndex++;
+
+ isRepeatedHeader = PR_FALSE;
+ isRepeatedFooter = PR_FALSE;
+
+ if (rowGroupIndex < rowGroups.Count()) {
+ prevRg = rg;
+ nsIFrame* frame = (nsTableRowGroupFrame*)rowGroups.ElementAt(rowGroupIndex); if (!frame) ABORT1(PR_FALSE);
+ rg = table->GetRowGroupFrame(frame); if (!rg) ABORT1(PR_FALSE);
+ rowGroupStart = rg->GetStartRowIndex();
+ rowGroupEnd = rowGroupStart + rg->GetRowCount() - 1;
+
+ if (aSetInFlow) {
+ if (rgInFlow && tableInFlow->GetPrevInFlow()) {
+ // if there is a prev in flow, then the next rgInFlow is (a) either the previous ones next sibling
+ // or (b) the rg of the next sibling of the parent if the parent is a scroll frame
+ nsIFrame* frame = nsnull;
+ nsIFrame* parent = nsnull;
+ rgInFlow->GetParent(&parent);
+ if (parent == tableInFlow) {
+ rgInFlow->GetNextSibling(&frame);
+ }
+ else if (parent) {
+ parent->GetNextSibling(&frame);
+ }
+ rgInFlow = table->GetRowGroupFrame(frame);
+ if (!rgInFlow) {
+ atEnd = PR_TRUE;
+ ABORT1(PR_FALSE);
+ }
+ }
+ else {
+ rgInFlow = rg;
+ }
+ }
+ if (SetNewRow(rgInFlow->GetFirstRow(), rg->GetFirstRow())) {
+ cellMap = tableCellMap->GetMapFor(*rg);
+ }
+ if (rgInFlow && tableInFlow->GetPrevInFlow() && !rgInFlow->GetPrevInFlow()) {
+ // if rgInFlow doesn't have a prev in flow, then it may be a repeated header or footer
+ const nsStyleDisplay* display;
+ rgInFlow->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)display);
+ if (y == startY) {
+ isRepeatedHeader = (NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == display->mDisplay);
+ }
+ else {
+ isRepeatedFooter = (NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == display->mDisplay);
+ }
+ }
+ }
+ else {
+ atEnd = PR_TRUE;
+ }
+ return !atEnd;
+}
+
+void
+BCMapBorderIterator::First()
+{
+ if (!table || (startX >= numCols) || (startY >= numRows)) ABORT0();
+
+ atEnd = PR_FALSE;
+
+ PRUint32 numRowGroups = rowGroups.Count();
+ for (PRUint32 rgX = 0; rgX < numRowGroups; rgX++) {
+ nsIFrame* frame = (nsIFrame*)rowGroups.ElementAt(rgX);
+ nsTableRowGroupFrame* rowG = table->GetRowGroupFrame(frame);
+ if (rowG) {
+ PRInt32 start = rowG->GetStartRowIndex();
+ PRInt32 end = start + rowG->GetRowCount() - 1;
+ if ((startY >= start) && (startY <= end)) {
+ rowGroupIndex = rgX - 1; // SetNewRowGroup increments rowGroupIndex
+ if (SetNewRowGroup(PR_FALSE)) {
+ while ((y < startY) && !atEnd) {
+ SetNewRow();
+ }
+ if (!atEnd) {
+ SetNewData(startY, startX);
+ }
+ }
+ return;
+ }
+ }
+ }
+ atEnd = PR_TRUE;
+}
+
+void
+BCMapBorderIterator::Next()
+{
+ if (atEnd) ABORT0();
+ isNewRow = PR_FALSE;
+
+ x++;
+ if (x > endX) {
+ y++;
+ if (y == endY) {
+ x = startX;
+ }
+ else if (y < endY) {
+ if (y <= rowGroupEnd) {
+ SetNewRow();
+ }
+ else {
+ SetNewRowGroup(PR_TRUE);
+ }
+ }
+ else {
+ atEnd = PR_TRUE;
+ }
+ }
+ if (!atEnd) {
+ SetNewData(y, x);
+ }
+}
+
+// XXX if CalcVerCornerOffset and CalcHorCornerOffset remain similar, combine them
+static nscoord
+CalcVerCornerOffset(PRUint8 aCornerOwnerSide,
+ nscoord aCornerSubWidth,
+ nscoord aHorWidth,
+ PRBool aIsStartOfSeg,
+ PRBool aIsBevel,
+ float aPixelsToTwips)
+{
+ nscoord offset = 0;
+ nscoord smallHalf, largeHalf;
+ if ((NS_SIDE_TOP == aCornerOwnerSide) || (NS_SIDE_BOTTOM == aCornerOwnerSide)) {
+ DivideBCBorderSize(aCornerSubWidth, smallHalf, largeHalf);
+ if (aIsBevel) {
+ offset = (aIsStartOfSeg) ? -largeHalf : smallHalf;
+ }
+ else {
+ offset = (NS_SIDE_TOP == aCornerOwnerSide) ? smallHalf : -largeHalf;
+ }
+ }
+ else {
+ DivideBCBorderSize(aHorWidth, smallHalf, largeHalf);
+ if (aIsBevel) {
+ offset = (aIsStartOfSeg) ? -largeHalf : smallHalf;
+ }
+ else {
+ offset = (aIsStartOfSeg) ? smallHalf : -largeHalf;
+ }
+ }
+ return NSToCoordRound(aPixelsToTwips * (float)offset);
+}
+
+static nscoord
+CalcHorCornerOffset(PRUint8 aCornerOwnerSide,
+ nscoord aCornerSubWidth,
+ nscoord aVerWidth,
+ PRBool aIsStartOfSeg,
+ PRBool aIsBevel,
+ float aPixelsToTwips)
+{
+ nscoord offset = 0;
+ nscoord smallHalf, largeHalf;
+ if ((NS_SIDE_LEFT == aCornerOwnerSide) || (NS_SIDE_RIGHT == aCornerOwnerSide)) {
+ DivideBCBorderSize(aCornerSubWidth, smallHalf, largeHalf);
+ if (aIsBevel) {
+ offset = (aIsStartOfSeg) ? -largeHalf : smallHalf;
+ }
+ else {
+ offset = (NS_SIDE_LEFT == aCornerOwnerSide) ? smallHalf : -largeHalf;
+ }
+ }
+ else {
+ DivideBCBorderSize(aVerWidth, smallHalf, largeHalf);
+ if (aIsBevel) {
+ offset = (aIsStartOfSeg) ? -largeHalf : smallHalf;
+ }
+ else {
+ offset = (aIsStartOfSeg) ? smallHalf : -largeHalf;
+ }
+ }
+ return NSToCoordRound(aPixelsToTwips * (float)offset);
+}
+
+struct BCVerticalSeg
+{
+ BCVerticalSeg::BCVerticalSeg();
+
+ void Start(BCMapBorderIterator& aIter,
+ BCBorderOwner aBorderOwner,
+ nscoord aVerSegWidth,
+ nscoord aPrevHorSegHeight,
+ nscoord aHorSegHeight,
+ float aPixelsToTwips,
+ BCVerticalSeg* aVerInfoArray);
+
+ union {
+ nsTableColFrame* col;
+ PRInt32 colWidth;
+ };
+ PRInt32 colX;
+ nsTableCellFrame* ajaCell;
+ nsTableCellFrame* firstCell; // cell at the start of the segment
+ nsTableCellFrame* lastCell; // cell at the current end of the segment
+ PRInt32 segY;
+ PRInt32 segHeight;
+ PRInt16 segWidth; // width in pixels
+ PRUint8 owner;
+ PRUint8 bevelSide;
+ PRUint16 bevelOffset;
+};
+
+BCVerticalSeg::BCVerticalSeg()
+{
+ col = nsnull; firstCell = lastCell = ajaCell = nsnull; colX = segY = segHeight = 0;
+ segWidth = bevelOffset = 0; bevelSide = 0; owner = eCellOwner;
+}
+
+void
+BCVerticalSeg::Start(BCMapBorderIterator& aIter,
+ BCBorderOwner aBorderOwner,
+ nscoord aVerSegWidth,
+ nscoord aPrevHorSegHeight,
+ nscoord aHorSegHeight,
+ float aPixelsToTwips,
+ BCVerticalSeg* aVerInfoArray)
+{
+ PRUint8 ownerSide = 0;
+ PRPackedBool bevel = PR_FALSE;
+ PRInt32 xAdj = aIter.x - aIter.startX;
+
+ nscoord cornerSubWidth = (aIter.bcData) ? aIter.bcData->GetCorner(ownerSide, bevel) : 0;
+ PRBool topBevel = (aVerSegWidth > 0) ? bevel : PR_FALSE;
+ nscoord maxHorSegHeight = PR_MAX(aPrevHorSegHeight, aHorSegHeight);
+ nscoord offset = CalcVerCornerOffset(ownerSide, cornerSubWidth, maxHorSegHeight,
+ PR_TRUE, topBevel, aPixelsToTwips);
+
+ bevelOffset = (topBevel) ? maxHorSegHeight : 0;
+ bevelSide = (aHorSegHeight > 0) ? NS_SIDE_RIGHT : NS_SIDE_LEFT;
+ segY += offset;
+ segHeight = -offset;
+ segWidth = aVerSegWidth;
+ owner = aBorderOwner;
+ firstCell = aIter.cell;
+ if (xAdj > 0) {
+ ajaCell = aVerInfoArray[xAdj - 1].lastCell;
+ }
+}
+
+struct BCHorizontalSeg
+{
+ BCHorizontalSeg::BCHorizontalSeg();
+
+ void Start(BCMapBorderIterator& aIter,
+ BCBorderOwner aBorderOwner,
+ PRUint8 aCornerOwnerSide,
+ nscoord aSubWidth,
+ PRBool aBevel,
+ nscoord aTopVerSegWidth,
+ nscoord aBottomVerSegWidth,
+ nscoord aHorSegHeight,
+ nsTableCellFrame* aLastCell,
+ float aPixelsToTwips);
+
+ nscoord x;
+ nscoord y;
+ nscoord width;
+ nscoord height;
+ PRBool leftBevel;
+ nscoord leftBevelOffset;
+ PRUint8 leftBevelSide;
+ PRUint8 owner;
+ nsTableCellFrame* firstCell; // cell at the start of the segment
+ nsTableCellFrame* ajaCell;
+};
+
+BCHorizontalSeg::BCHorizontalSeg()
+{
+ x = y = width = height = leftBevel = leftBevelOffset = leftBevelSide = 0;
+ firstCell = ajaCell = nsnull;
+}
+
+
+void
+BCHorizontalSeg::Start(BCMapBorderIterator& aIter,
+ BCBorderOwner aBorderOwner,
+ PRUint8 aCornerOwnerSide,
+ nscoord aSubWidth,
+ PRBool aBevel,
+ nscoord aTopVerSegWidth,
+ nscoord aBottomVerSegWidth,
+ nscoord aHorSegHeight,
+ nsTableCellFrame* aLastCell,
+ float aPixelsToTwips)
+{
+ owner = aBorderOwner;
+ leftBevel = (aHorSegHeight > 0) ? aBevel : PR_FALSE;
+ nscoord maxVerSegWidth = PR_MAX(aTopVerSegWidth, aBottomVerSegWidth);
+ nscoord offset = CalcHorCornerOffset(aCornerOwnerSide, aSubWidth, maxVerSegWidth,
+ PR_TRUE, leftBevel, aPixelsToTwips);
+ leftBevelOffset = (leftBevel && (aHorSegHeight > 0)) ? maxVerSegWidth : 0;
+ leftBevelSide = (aBottomVerSegWidth > 0) ? NS_SIDE_BOTTOM : NS_SIDE_TOP;
+ x += offset;
+ width = -offset;
+ height = aHorSegHeight;
+ firstCell = aIter.cell;
+ ajaCell = (aIter.IsTopMost()) ? nsnull : aLastCell;
+}
+
+void
+nsTableFrame::PaintBCBorders(nsIPresContext* aPresContext,
+ nsIRenderingContext& aRenderingContext,
+ const nsRect& aDirtyRect)
+{
+ nsMargin childAreaOffset = GetChildAreaOffset(*aPresContext, nsnull);
+ nsTableFrame* firstInFlow = (nsTableFrame*)GetFirstInFlow(); if (!firstInFlow) ABORT0();
+ GET_PIXELS_TO_TWIPS(aPresContext, p2t);
+
+ PRInt32 startColX = childAreaOffset.left; // x position of first col in damage area
+ PRInt32 startRowY = (mPrevInFlow) ? 0 : childAreaOffset.top; // y position of first row in damage area
+
+ const nsStyleBackground* bgColor = nsStyleUtil::FindNonTransparentBackground(mStyleContext);
+ // determine the damage area in terms of rows and columns and finalize startColX and startRowY
+ PRUint32 startRowIndex, endRowIndex, startColIndex, endColIndex;
+ startRowIndex = endRowIndex = startColIndex = endColIndex = 0;
+
+ nsAutoVoidArray rowGroups;
+ PRUint32 numRowGroups;
+ OrderRowGroups(rowGroups, numRowGroups, nsnull);
+ PRBool done = PR_FALSE;
+ PRBool haveIntersect = PR_FALSE;
+ nsTableRowGroupFrame* inFlowRG = nsnull;
+ nsTableRowFrame* inFlowRow = nsnull;
+ // find startRowIndex, endRowIndex, startRowY
+ nscoord onePixel = NSToCoordRound(p2t);
+ PRInt32 rowY = startRowY;
+ for (PRUint32 rgX = 0; (rgX < numRowGroups) && !done; rgX++) {
+ nsIFrame* kidFrame = (nsIFrame*)rowGroups.ElementAt(rgX);
+ nsTableRowGroupFrame* rgFrame = GetRowGroupFrame(kidFrame); if (!rgFrame) ABORT0();
+ nsRect rowRect;
+ for (nsTableRowFrame* rowFrame = rgFrame->GetFirstRow(); rowFrame; rowFrame = rowFrame->GetNextRow()) {
+ // conservatively estimate the half border widths outside the row
+ nscoord topBorderHalf = (mPrevInFlow) ? 0 : rowFrame->GetTopBCBorderWidth(&p2t) + onePixel;
+ nscoord bottomBorderHalf = (mNextInFlow) ? 0 : rowFrame->GetBottomBCBorderWidth(&p2t) + onePixel;
+ // get the row rect relative to the table rather than the row group
+ rowFrame->GetRect(rowRect);
+ if (haveIntersect) {
+ if (aDirtyRect.YMost() >= (rowY - topBorderHalf)) {
+ nsTableRowFrame* fifRow = (nsTableRowFrame*)rowFrame->GetFirstInFlow(); if (!fifRow) ABORT0();
+ endRowIndex = fifRow->GetRowIndex();
+ }
+ else done = PR_TRUE;
+ }
+ else {
+ if ((rowY + rowRect.height + bottomBorderHalf) >= aDirtyRect.y) {
+ inFlowRG = rgFrame;
+ inFlowRow = rowFrame;
+ nsTableRowFrame* fifRow = (nsTableRowFrame*)rowFrame->GetFirstInFlow(); if (!fifRow) ABORT0();
+ startRowIndex = endRowIndex = fifRow->GetRowIndex();
+ haveIntersect = PR_TRUE;
+ }
+ else {
+ startRowY += rowRect.height;
+ }
+ }
+ rowY += rowRect.height;
+ }
+ }
+ if (!inFlowRG || !inFlowRow) ABORT0();
+
+ // find startColIndex, endColIndex, startColX
+ haveIntersect = PR_FALSE;
+ PRUint32 numCols = GetColCount();
+ if (0 == numCols) return;
+
+ nscoord x = 0;
+ for (PRUint32 colX = 0; colX < numCols; colX++) {
+ nsTableColFrame* colFrame = firstInFlow->GetColFrame(colX); if (!colFrame) ABORT0();
+ // conservatively estimate the half border widths outside the col
+ nscoord leftBorderHalf = colFrame->GetLeftBorderWidth(&p2t) + onePixel;
+ nscoord rightBorderHalf = colFrame->GetRightBorderWidth(&p2t) + onePixel;
+ // get the col rect relative to the table rather than the col group
+ nsRect rect;
+ colFrame->GetRect(rect);
+ if (haveIntersect) {
+ if (aDirtyRect.XMost() >= (x - leftBorderHalf)) {
+ endColIndex = colX;
+ }
+ else break;
+ }
+ else {
+ if ((x + rect.width + rightBorderHalf) >= aDirtyRect.x) {
+ startColIndex = endColIndex = colX;
+ haveIntersect = PR_TRUE;
+ }
+ else {
+ startColX += rect.width;
+ }
+ }
+ x += rect.width;
+ }
+
+ // iterate the cell map and build up border segments
+ nsRect damageArea(startColIndex, startRowIndex, 1 + endColIndex - startColIndex,
+ 1 + endRowIndex - startRowIndex);
+ BCVerticalSeg* verInfo = new BCVerticalSeg[damageArea.width + 1]; if (!verInfo) ABORT0();
+
+ BCBorderOwner borderOwner, ignoreBorderOwner;
+ PRUint8 ownerSide;
+ nscoord cornerSubWidth, smallHalf, largeHalf;
+ nsRect rowRect(0,0,0,0);
+ PRBool isSegStart, ignoreSegStart;
+ nscoord prevHorSegHeight = 0;
+ PRPackedBool bevel;
+ PRInt32 repeatedHeaderY = -99;
+ PRBool afterRepeatedHeader = PR_FALSE;
+ PRBool startRepeatedFooter = PR_FALSE;
+
+ // First, paint all of the vertical borders from top to bottom and left to right as they become complete
+ // They are painted first, since they are less efficient to paint than horizontal segments. They were
+ // stored with as few segments as possible (since horizontal borders are painted last and possibly over them).
+ BCMapBorderIterator iter(*this, *inFlowRG, *inFlowRow, damageArea);
+ for (iter.First(); !iter.atEnd; iter.Next()) {
+ nscoord verSegWidth = (iter.bcData) ? iter.bcData->GetLeftEdge(borderOwner, isSegStart) : 0;
+ nscoord horSegHeight = (iter.bcData) ? iter.bcData->GetTopEdge(ignoreBorderOwner, ignoreSegStart) : 0;
+
+ PRInt32 xAdj = iter.x - iter.startX;
+ if (iter.isNewRow) {
+ prevHorSegHeight = 0;
+ iter.rowInFlow->GetRect(rowRect);
+ if (iter.isRepeatedHeader) {
+ repeatedHeaderY = iter.y;
+ }
+ afterRepeatedHeader = !iter.isRepeatedHeader && (iter.y == (repeatedHeaderY + 1));
+ startRepeatedFooter = iter.isRepeatedFooter && (iter.y == iter.rowGroupStart) && (iter.y != iter.startY);
+ }
+ BCVerticalSeg& info = verInfo[xAdj];
+ if (!info.col) { // on the first damaged row and the first segment in the col
+ info.col = iter.IsRightMostTable() ? verInfo[xAdj - 1].col : firstInFlow->GetColFrame(iter.x); if (!info.col) ABORT0();
+ if (0 == xAdj) {
+ info.colX = startColX;
+ }
+ // set colX for the next column
+ if (!iter.IsRightMost()) {
+ nsRect colRect;
+ info.col->GetRect(colRect);
+ verInfo[xAdj + 1].colX = info.colX + colRect.width;
+ }
+ info.segY = startRowY;
+ info.Start(iter, borderOwner, verSegWidth, prevHorSegHeight, horSegHeight, p2t, verInfo);
+ info.lastCell = iter.cell;
+ }
+
+ if (!iter.IsTopMost() && (isSegStart || iter.IsBottomMost() || afterRepeatedHeader || startRepeatedFooter)) {
+ // paint the previous seg or the current one if iter.IsBottomMost()
+ if (info.segHeight > 0) {
+ cornerSubWidth = (iter.bcData) ? iter.bcData->GetCorner(ownerSide, bevel) : 0;
+ PRBool endBevel = (info.segWidth > 0) ? bevel : PR_FALSE;
+ nscoord bottomHorSegHeight = PR_MAX(prevHorSegHeight, horSegHeight);
+ nscoord endOffset = CalcVerCornerOffset(ownerSide, cornerSubWidth, bottomHorSegHeight,
+ PR_FALSE, endBevel, p2t);
+ info.segHeight += endOffset;
+ if (info.segWidth > 0) {
+ // get the border style, color and paint the segment
+ PRUint8 side = (iter.IsRightMost()) ? NS_SIDE_RIGHT : NS_SIDE_LEFT;
+ nsTableColGroupFrame* cg = nsnull;
+ nsTableColFrame* col = info.col; if (!col) ABORT0();
+ nsTableCellFrame* cell = info.firstCell;
+ PRUint8 style = NS_STYLE_BORDER_STYLE_SOLID;
+ nscolor color = 0xFFFFFFFF;
+ PRBool ignoreIfRules = (iter.IsRightMostTable() || iter.IsLeftMostTable());
+
+ switch (info.owner) {
+ case eTableOwner:
+ ::GetStyleInfo(*this, side, style, color);
+ break;
+ case eAjaColGroupOwner:
+ side = NS_SIDE_RIGHT;
+ if (!iter.IsRightMostTable() && (xAdj > 0)) {
+ col = verInfo[xAdj - 1].col;
+ } // and fall through
+ case eColGroupOwner:
+ if (col) {
+ col->GetParent((nsIFrame**)&cg);
+ if (cg) {
+ ::GetStyleInfo(*cg, side, style, color, ignoreIfRules);
+ }
+ }
+ break;
+ case eAjaColOwner:
+ side = NS_SIDE_RIGHT;
+ if (!iter.IsRightMostTable() && (xAdj > 0)) {
+ col = verInfo[xAdj - 1].col;
+ } // and fall through
+ case eColOwner:
+ if (col) {
+ ::GetStyleInfo(*col, side, style, color, ignoreIfRules);
+ }
+ break;
+ case eAjaRowGroupOwner:
+ NS_ASSERTION(PR_FALSE, "program error"); // and fall through
+ case eRowGroupOwner:
+ NS_ASSERTION(iter.IsLeftMostTable() || iter.IsRightMostTable(), "program error");
+ if (iter.rg) {
+ ::GetStyleInfo(*iter.rg, side, style, color, ignoreIfRules);
+ }
+ break;
+ case eAjaRowOwner:
+ NS_ASSERTION(PR_FALSE, "program error"); // and fall through
+ case eRowOwner:
+ NS_ASSERTION(iter.IsLeftMostTable() || iter.IsRightMostTable(), "program error");
+ if (iter.row) {
+ ::GetStyleInfo(*iter.row, side, style, color, ignoreIfRules);
+ }
+ break;
+ case eAjaCellOwner:
+ side = NS_SIDE_RIGHT;
+ cell = info.ajaCell; // and fall through
+ case eCellOwner:
+ if (cell) {
+ ::GetStyleInfo(*cell, side, style, color);
+ }
+ break;
+ }
+ DivideBCBorderSize(info.segWidth, smallHalf, largeHalf);
+ nsRect segRect(info.colX - NSToCoordRound(p2t * (float)largeHalf), info.segY,
+ NSToCoordRound(p2t * (float)info.segWidth), info.segHeight);
+ nscoord bottomBevelOffset = (endBevel) ? NSToCoordRound(p2t * (float)bottomHorSegHeight) : 0;
+ PRUint8 bottomBevelSide = (horSegHeight > 0) ? NS_SIDE_RIGHT : NS_SIDE_LEFT;
+ nsCSSRendering::DrawTableBorderSegment(aRenderingContext, style, color, bgColor, segRect, p2t,
+ info.bevelSide, NSToCoordRound(p2t * (float)info.bevelOffset),
+ bottomBevelSide, bottomBevelOffset);
+ } // if (info.segWidth > 0) {
+ info.segY = info.segY + info.segHeight - endOffset;
+ } // if (info.segHeight > 0)
+ info.Start(iter, borderOwner, verSegWidth, prevHorSegHeight, horSegHeight, p2t, verInfo);
+ } // if (!iter.IsTopMost() && (isSegStart || iter.IsBottomMost())) {
+
+ info.lastCell = iter.cell;
+ info.segHeight += rowRect.height;
+ prevHorSegHeight = horSegHeight;
+ } // for (iter.First(); !iter.atEnd; iter.Next()) {
+
+ // Next, paint all of the horizontal border segments from top to bottom reuse the verInfo
+ // array to keep tract of col widths and vertical segments for corner calculations
+ memset(verInfo, 0, damageArea.width * sizeof(BCVerticalSeg)); // XXX reinitialize properly
+ for (PRInt32 xIndex = 0; xIndex < damageArea.width; xIndex++) {
+ verInfo[xIndex].colWidth = -1;
+ }
+ PRInt32 nextY = startRowY;
+ BCHorizontalSeg horSeg;
+
+ iter.Reset(*this, *inFlowRG, *inFlowRow, damageArea);
+ for (iter.First(); !iter.atEnd; iter.Next()) {
+ nscoord leftSegWidth = (iter.bcData) ? iter.bcData->GetLeftEdge(ignoreBorderOwner, ignoreSegStart) : 0;
+ nscoord topSegHeight = (iter.bcData) ? iter.bcData->GetTopEdge(borderOwner, isSegStart) : 0;
+
+ PRInt32 xAdj = iter.x - iter.startX;
+ // store the current col width if it hasn't been already
+ if (verInfo[xAdj].colWidth < 0) {
+ if (iter.IsRightMostTable()) {
+ verInfo[xAdj].colWidth = verInfo[xAdj - 1].colWidth;
+ }
+ else {
+ nsTableColFrame* col = firstInFlow->GetColFrame(iter.x); if (!col) ABORT0();
+ nsRect colRect;
+ col->GetRect(colRect);
+ verInfo[xAdj].colWidth = colRect.width;
+ }
+ }
+ cornerSubWidth = (iter.bcData) ? iter.bcData->GetCorner(ownerSide, bevel) : 0;
+ nscoord verWidth = PR_MAX(verInfo[xAdj].segWidth, leftSegWidth);
+ if (iter.isNewRow || (iter.IsLeftMost() && iter.IsBottomMostTable())) {
+ iter.rowInFlow->GetRect(rowRect);
+ horSeg.y = nextY;
+ nextY = nextY + rowRect.height;
+ horSeg.x = startColX;
+ horSeg.Start(iter, borderOwner, ownerSide, cornerSubWidth, bevel, verInfo[xAdj].segWidth,
+ leftSegWidth, topSegHeight, verInfo[xAdj].lastCell, p2t);
+ }
+ PRBool verOwnsCorner = (NS_SIDE_TOP == ownerSide) || (NS_SIDE_BOTTOM == ownerSide);
+ if (!iter.IsLeftMost() && (isSegStart || iter.IsRightMost() || verOwnsCorner)) {
+ // paint the previous seg or the current one if iter.IsRightMost()
+ if (horSeg.width > 0) {
+ PRBool endBevel = (horSeg.height > 0) ? bevel : 0;
+ nscoord endOffset = CalcHorCornerOffset(ownerSide, cornerSubWidth, verWidth, PR_FALSE, endBevel, p2t);
+ horSeg.width += endOffset;
+ if (horSeg.height > 0) {
+ // get the border style, color and paint the segment
+ PRUint8 side = (iter.IsBottomMost()) ? NS_SIDE_BOTTOM : NS_SIDE_TOP;
+ nsIFrame* rg = iter.rg; if (!rg) ABORT0();
+ nsIFrame* row = iter.row; if (!row) ABORT0();
+ nsIFrame* cell = horSeg.firstCell; if (!cell) ABORT0();
+ nsIFrame* cg;
+ nsIFrame* col;
+
+ PRUint8 style = NS_STYLE_BORDER_STYLE_SOLID;
+ nscolor color = 0xFFFFFFFF;
+ PRBool ignoreIfRules = (iter.IsTopMostTable() || iter.IsBottomMostTable());
+
+ switch (horSeg.owner) {
+ case eTableOwner:
+ ::GetStyleInfo(*this, side, style, color);
+ break;
+ case eAjaColGroupOwner:
+ NS_ASSERTION(PR_FALSE, "program error"); // and fall through
+ case eColGroupOwner:
+ NS_ASSERTION(iter.IsTopMostTable() || iter.IsBottomMostTable(), "program error");
+ col = firstInFlow->GetColFrame(iter.x - 1); if (!col) ABORT0();
+ col->GetParent(&cg); if (!cg) ABORT0();
+ ::GetStyleInfo(*cg, side, style, color, ignoreIfRules);
+ break;
+ case eAjaColOwner:
+ NS_ASSERTION(PR_FALSE, "program error"); // and fall through
+ case eColOwner:
+ NS_ASSERTION(iter.IsTopMostTable() || iter.IsBottomMostTable(), "program error");
+ col = firstInFlow->GetColFrame(iter.x - 1); if (!col) ABORT0();
+ ::GetStyleInfo(*col, side, style, color, ignoreIfRules);
+ break;
+ case eAjaRowGroupOwner:
+ side = NS_SIDE_BOTTOM;
+ rg = (iter.IsBottomMostTable()) ? iter.rg : iter.prevRg; // and fall through
+ case eRowGroupOwner:
+ if (rg) {
+ ::GetStyleInfo(*rg, side, style, color, ignoreIfRules);
+ }
+ break;
+ case eAjaRowOwner:
+ side = NS_SIDE_BOTTOM;
+ row = iter.prevRow; // and fall through
+ case eRowOwner:
+ if (row) {
+ ::GetStyleInfo(*row, side, style, color, iter.IsBottomMostTable());
+ }
+ break;
+ case eAjaCellOwner:
+ side = NS_SIDE_BOTTOM;
+ // if this is null due to the damage area origin-y > 0, then the border won't show up anyway
+ cell = horSeg.ajaCell;
+ // and fall through
+ case eCellOwner:
+ if (cell) {
+ ::GetStyleInfo(*cell, side, style, color);
+ }
+ break;
+ }
+ DivideBCBorderSize(horSeg.height, smallHalf, largeHalf);
+ nsRect segRec(horSeg.x, horSeg.y - NSToCoordRound(p2t * (float)largeHalf), horSeg.width,
+ NSToCoordRound(p2t * (float)horSeg.height));
+ nscoord rightBevelOffset = (endBevel) ? NSToCoordRound(p2t * (float)verWidth) : 0;
+ PRUint8 rightBevelSide = (leftSegWidth > 0) ? NS_SIDE_BOTTOM : NS_SIDE_TOP;
+ nsCSSRendering::DrawTableBorderSegment(aRenderingContext, style, color, bgColor, segRec, p2t, horSeg.leftBevelSide,
+ NSToCoordRound(p2t * (float)horSeg.leftBevelOffset),
+ rightBevelSide, rightBevelOffset);
+ } // if (horSeg.height > 0) {
+ horSeg.x = horSeg.x + horSeg.width - endOffset;
+ } // if (horSeg.width > 0) {
+ horSeg.Start(iter, borderOwner, ownerSide, cornerSubWidth, bevel, verInfo[xAdj].segWidth,
+ leftSegWidth, topSegHeight, verInfo[xAdj].lastCell, p2t);
+ } // if (!iter.IsLeftMost() && (isSegStart || iter.IsRightMost() || verOwnsCorner)) {
+ horSeg.width += verInfo[xAdj].colWidth;
+ verInfo[xAdj].segWidth = leftSegWidth;
+ verInfo[xAdj].lastCell = iter.cell;
+ }
+ delete [] verInfo;
+}
/********************************************************************************
** DEBUG_TABLE_REFLOW and DEBUG_TABLE_REFLOW_TIMING **
@@ -4579,7 +6993,7 @@ GetFrameTypeName(nsIAtom* aFrameType,
strcpy(aName, "RowG");
else if (nsLayoutAtoms::tableRowFrame == aFrameType)
strcpy(aName, "Row");
- else if (nsLayoutAtoms::tableCellFrame == aFrameType)
+ else if (IS_TABLE_CELL(aFrameType))
strcpy(aName, "Cell");
else if (nsLayoutAtoms::blockFrame == aFrameType)
strcpy(aName, "Block");
@@ -4621,7 +7035,7 @@ void DebugGetIndent(const nsIFrame* aFrame,
(nsLayoutAtoms::tableFrame == frameType.get()) ||
(nsLayoutAtoms::tableRowGroupFrame == frameType.get()) ||
(nsLayoutAtoms::tableRowFrame == frameType.get()) ||
- (nsLayoutAtoms::tableCellFrame == frameType.get())) {
+ IS_TABLE_CELL(frameType.get())) {
numLevels++;
}
if (nsLayoutAtoms::blockFrame == frameType.get()) {
@@ -4630,7 +7044,7 @@ void DebugGetIndent(const nsIFrame* aFrame,
parent->GetParent(&grandParent);
nsCOMPtr gFrameType;
grandParent->GetFrameType(getter_AddRefs(gFrameType));
- if (nsLayoutAtoms::tableCellFrame == gFrameType.get()) {
+ if (IS_TABLE_CELL(gFrameType.get())) {
numLevels++;
}
}
@@ -4715,14 +7129,14 @@ nsReflowTimer* GetFrameTimer(nsIFrame* aFrame,
return ((nsTableRowGroupFrame*)aFrame)->mTimer;
else if (nsLayoutAtoms::tableRowFrame == aFrameType)
return ((nsTableRowFrame*)aFrame)->mTimer;
- else if (nsLayoutAtoms::tableCellFrame == aFrameType)
+ else if (IS_TABLE_CELL(aFrameType))
return ((nsTableCellFrame*)aFrame)->mTimer;
else if (nsLayoutAtoms::blockFrame == aFrameType) {
nsIFrame* parentFrame;
aFrame->GetParent(&parentFrame);
nsCOMPtr fType;
parentFrame->GetFrameType(getter_AddRefs(fType));
- if (nsLayoutAtoms::tableCellFrame == fType) {
+ if (IS_TABLE_CELL(fType)) {
nsTableCellFrame* cellFrame = (nsTableCellFrame*)parentFrame;
// fix up the block timer, which may be referring to the cell
if (cellFrame->mBlockTimer->mFrame == parentFrame) {
@@ -4967,7 +7381,7 @@ void nsTableFrame::DebugReflowDone(nsIFrame* aFrame)
ancestorTimer->mChildren.AppendElement(thisTimer);
nsCOMPtr fType;
aFrame->GetFrameType(getter_AddRefs(fType));
- if (nsLayoutAtoms::tableCellFrame == fType) {
+ if (IS_TABLE_CELL(fType)) {
// add the cell block timer as a child of the cell timer
nsTableCellFrame* cellFrame = (nsTableCellFrame*)aFrame;
cellFrame->mTimer->mChildren.AppendElement(cellFrame->mBlockTimer);
@@ -5056,6 +7470,16 @@ DestroyPointFunc(nsIPresContext* aPresContext,
delete (nsPoint*)aPropertyValue;
}
+// Destructor function for nscoord properties
+static void
+DestroyBCPropertyDataFunc(nsIPresContext* aPresContext,
+ nsIFrame* aFrame,
+ nsIAtom* aPropertyName,
+ void* aPropertyValue)
+{
+ delete (BCPropertyData*)aPropertyValue;
+}
+
void*
nsTableFrame::GetProperty(nsIPresContext* aPresContext,
nsIFrame* aFrame,
@@ -5089,6 +7513,10 @@ nsTableFrame::GetProperty(nsIPresContext* aPresContext,
value = new nscoord;
dtorFunc = DestroyCoordFunc;
}
+ else if (aPropertyName == nsLayoutAtoms::tableBCProperty) {
+ value = new BCPropertyData;
+ dtorFunc = DestroyBCPropertyDataFunc;
+ }
if (!value) return nsnull;
frameManager->SetFrameProperty(aFrame, aPropertyName, value, dtorFunc);
@@ -5160,7 +7588,7 @@ void DumpTableFramesRecur(nsIPresContext* aPresContext,
if (nsLayoutAtoms::tableFrame == fType.get() ||
nsLayoutAtoms::tableRowGroupFrame == fType.get() ||
nsLayoutAtoms::tableRowFrame == fType.get() ||
- nsLayoutAtoms::tableCellFrame == fType.get()) {
+ IS_TABLE_CELL(fType.get())) {
nsIFrame* child;
aFrame->FirstChild(aPresContext, nsnull, &child);
while(child) {
diff --git a/mozilla/layout/html/table/src/nsTableFrame.h b/mozilla/layout/html/table/src/nsTableFrame.h
index 4862e4a92c2..7dc64be49b4 100644
--- a/mozilla/layout/html/table/src/nsTableFrame.h
+++ b/mozilla/layout/html/table/src/nsTableFrame.h
@@ -53,7 +53,6 @@ class nsTableColFrame;
class nsTableRowGroupFrame;
class nsTableRowFrame;
class nsTableColGroupFrame;
-class nsTableBorderCollapser;
class nsITableLayoutStrategy;
class nsHTMLValue;
@@ -208,6 +207,8 @@ public:
nsIAtom* aPropertyName,
PRBool aCreateIfNecessary = PR_FALSE);
+ static float GetTwipsToPixels(nsIPresContext* aPresContext);
+
static nscoord RoundToPixel(nscoord aValue,
float aPixelToTwips,
nsPixelRound aRound= eAlwaysRoundUp);
@@ -249,7 +250,13 @@ public:
nsIAtom* aListName,
nsIFrame* aOldFrame);
- nsMargin GetBorderPadding(const nsHTMLReflowState& aReflowState) const;
+ // Get the offset from the border box to the area where the row groups fit
+ nsMargin GetChildAreaOffset(nsIPresContext& aPresContext,
+ const nsHTMLReflowState* aReflowState) const;
+
+ // Get the offset from the border box to the area where the content fits
+ nsMargin GetContentAreaOffset(nsIPresContext& aPresContext,
+ const nsHTMLReflowState* aReflowState) const;
/** helper method to find the table parent of any table frame object */
// TODO: today, this depends on display types. This should be changed to rely
@@ -297,6 +304,17 @@ public:
nsFramePaintLayer aWhichLayer,
PRUint32 aFlags = 0);
+ nsMargin* GetBCBorder(nsIPresContext& aPresContext,
+ PRBool aInnerBorderOnly,
+ nsMargin& aBorder) const;
+
+ void SetBCDamageArea(nsIPresContext& aPresContext,
+ const nsRect& aValue);
+
+ void PaintBCBorders(nsIPresContext* aPresContext,
+ nsIRenderingContext& aRenderingContext,
+ const nsRect& aDirtyRect);
+
NS_IMETHOD GetFrameForPoint(nsIPresContext* aPresContext,
const nsPoint& aPoint,
nsFramePaintLayer aWhichLayer,
@@ -371,15 +389,12 @@ public:
/** set the width of the column at aColIndex to aWidth */
virtual void SetColumnWidth(PRInt32 aColIndex, nscoord aWidth);
- /** helper to get the border collapse style value */
- virtual PRUint8 GetBorderCollapseStyle();
-
/** helper to get the cell spacing X style value */
virtual nscoord GetCellSpacingX();
/** helper to get the cell spacing Y style value */
virtual nscoord GetCellSpacingY();
-
+
/** return the row span of a cell, taking into account row span magic at the bottom
* of a table. The row span equals the number of rows spanned by aCell starting at
* aStartRowIndex, and can be smaller if aStartRowIndex is greater than the row
@@ -440,9 +455,9 @@ public:
/** empty the column frame cache */
void ClearColCache();
- virtual PRInt32 AppendCell(nsIPresContext& aPresContext,
- nsTableCellFrame& aCellFrame,
- PRInt32 aRowIndex);
+ virtual void AppendCell(nsIPresContext& aPresContext,
+ nsTableCellFrame& aCellFrame,
+ PRInt32 aRowIndex);
virtual void InsertCells(nsIPresContext& aPresContext,
nsVoidArray& aCellFrames,
@@ -522,6 +537,9 @@ protected:
/** destructor, responsible for mColumnLayoutData */
virtual ~nsTableFrame();
+ void InitChildReflowState(nsIPresContext& aPresContext,
+ nsHTMLReflowState& aReflowState);
+
/** implement abstract method on nsHTMLContainerFrame */
virtual PRIntn GetSkipSides() const;
@@ -619,7 +637,8 @@ protected:
nsIFrame* aKidFrame,
nscoord aDeltaY);
- nsresult RecoverState(nsTableReflowState& aReflowState,
+ nsresult RecoverState(nsIPresContext& aPresContext,
+ nsTableReflowState& aReflowState,
nsIFrame* aKidFrame);
NS_METHOD CollapseRowGroupIfNecessary(nsIPresContext* aPresContext,
@@ -646,10 +665,11 @@ public:
// calculate the computed height of aFrame including its border and padding given
// its reflow state.
- nscoord CalcBorderBoxHeight(const nsHTMLReflowState& aReflowState);
+ nscoord CalcBorderBoxHeight(nsIPresContext* aPresContext,
+ const nsHTMLReflowState& aReflowState);
// calculate the minimum width to layout aFrame and its desired width
// including border and padding given its reflow state and column width information
- void CalcMinAndPreferredWidths(nsIPresContext* aPresContextconst,
+ void CalcMinAndPreferredWidths(nsIPresContext* aPresContext,
const nsHTMLReflowState& aReflowState,
PRBool aCalcPrefWidthIfAutoWithPctCol,
nscoord& aMinWidth,
@@ -657,7 +677,8 @@ public:
protected:
// calcs the width of the table according to the computed widths of each column.
- virtual PRInt32 CalcDesiredWidth(const nsHTMLReflowState& aReflowState);
+ virtual PRInt32 CalcDesiredWidth(nsIPresContext& aPresContext,
+ const nsHTMLReflowState& aReflowState);
// return the desired height of this table accounting for the current
// reflow state, and for the table attributes and parent
@@ -699,7 +720,7 @@ public:
PRUint32& aNumRowGroups,
nsIFrame** aFirstBody = nsnull,
nsTableRowGroupFrame** aHead = nsnull,
- nsTableRowGroupFrame** aFoot = nsnull);
+ nsTableRowGroupFrame** aFoot = nsnull) const;
// Returns PR_TRUE if there are any cells above the row at
// aRowIndex and spanning into the row at aRowIndex
@@ -735,9 +756,6 @@ protected:
PRBool DidResizeReflow() const;
void SetResizeReflow(PRBool aValue);
- /** Support methods for DidSetStyleContext */
- void MapBorderMarginPadding(nsIPresContext* aPresContext);
- void MapHTMLBorderStyle(nsStyleBorder& aBorderStyle, nscoord aBorderWidth);
PRBool ConvertToPixelValue(nsHTMLValue& aValue,
PRInt32 aDefault,
PRInt32& aResult);
@@ -749,6 +767,11 @@ public:
PRBool NeedStrategyBalance() const;
void SetNeedStrategyBalance(PRBool aValue);
+ PRBool IsBorderCollapse() const;
+
+ PRBool NeedToCalcBCBorders() const;
+ void SetNeedToCalcBCBorders(PRBool aValue);
+
/** Get the cell map for this table frame. It is not always mCellMap.
* Only the firstInFlow has a legit cell map
*/
@@ -763,9 +786,6 @@ public:
PRInt32 aRowIndex,
PRInt32 anAdjustment);
- // Return PR_TRUE if rules=groups is set for the table content
- PRBool HasGroupRules() const;
-
// Remove cell borders which aren't bordering row and/or col groups
void ProcessGroupRules(nsIPresContext* aPresContext);
@@ -775,10 +795,16 @@ public:
* Return aFrame's child if aFrame is an nsScrollFrame, otherwise return aFrame
*/
nsTableRowGroupFrame* GetRowGroupFrame(nsIFrame* aFrame,
- nsIAtom* aFrameTypeIn = nsnull);
+ nsIAtom* aFrameTypeIn = nsnull) const;
protected:
+ void SetBorderCollapse(PRBool aValue);
+
+ void CalcBCBorders(nsIPresContext& aPresContext);
+
+ void ExpandBCDamageArea(nsRect& aRect) const;
+
PRBool HadInitialReflow() const;
void SetHadInitialReflow(PRBool aValue);
@@ -809,8 +835,8 @@ public: /* ----- Cell Map public methods ----- */
/** returns the number of columns in this table after redundant columns have been removed
*/
- virtual PRInt32 GetEffectiveColCount();
- virtual PRInt32 GetColCount();
+ virtual PRInt32 GetEffectiveColCount() const;
+ virtual PRInt32 GetColCount() const;
/** return the column frame at colIndex.
* returns nsnull if the col frame has not yet been allocated, or if aColIndex is out of range
@@ -886,6 +912,7 @@ protected:
unsigned mHasPctCol:1; // does any cell or col have a pct width
unsigned mCellSpansPctCol:1; // does any cell span a col with a pct width (or containing a cell with a pct width)
unsigned mDidResizeReflow:1; // did a resize reflow happen (indicating pass 2)
+ unsigned mIsBorderCollapse:1; // border collapsing model vs. separate model
// true if a descendant was reflowed normally since the last time we reflowed.
// We will likely need a timeout reflow (targeted either at us or below)
unsigned mDescendantReflowedNotTimeout:1;
@@ -896,7 +923,8 @@ protected:
unsigned mRowInserted:1;
unsigned mNeedSpecialReflow:1;
unsigned mNeedToInitiateSpecialReflow:1;
- unsigned : 20; // unused
+ unsigned mNeedToCalcBCBorders:1;
+ unsigned : 18; // unused
} mBits;
nsTableCellMap* mCellMap; // maintains the relationships between rows, cols, and cells
@@ -1054,8 +1082,26 @@ inline void nsTableFrame::SetPreferredWidth(nscoord aWidth)
mPreferredWidth = aWidth;
}
+inline PRBool nsTableFrame::IsBorderCollapse() const
+{
+ return (PRBool)mBits.mIsBorderCollapse;
+}
+
+inline void nsTableFrame::SetBorderCollapse(PRBool aValue)
+{
+ mBits.mIsBorderCollapse = aValue;
+}
+
+inline PRBool nsTableFrame::NeedToCalcBCBorders() const
+{
+ return (PRBool)mBits.mNeedToCalcBCBorders;
+}
+
+inline void nsTableFrame::SetNeedToCalcBCBorders(PRBool aValue)
+{
+ mBits.mNeedToCalcBCBorders = (unsigned)aValue;
+}
-
enum nsTableIteration {
eTableLTR = 0,
eTableRTL = 1,
@@ -1085,6 +1131,23 @@ protected:
PRInt32 mCount;
};
+#define ABORT0() \
+{NS_ASSERTION(PR_FALSE, "CellIterator program error"); \
+return;}
+
+#define ABORT1(aReturn) \
+{NS_ASSERTION(PR_FALSE, "CellIterator program error"); \
+return aReturn;}
+
+#define GET_PIXELS_TO_TWIPS(presContext,var) \
+ float var; \
+ (presContext)->GetScaledPixelsToTwips(&var);
+
+#define GET_TWIPS_TO_PIXELS(presContext,var) \
+ float var; \
+ (presContext)->GetScaledPixelsToTwips(&var); \
+ var = 1.0f / var;
+
#endif
diff --git a/mozilla/layout/html/table/src/nsTableOuterFrame.cpp b/mozilla/layout/html/table/src/nsTableOuterFrame.cpp
index cd77fdd51e4..d402caa1396 100644
--- a/mozilla/layout/html/table/src/nsTableOuterFrame.cpp
+++ b/mozilla/layout/html/table/src/nsTableOuterFrame.cpp
@@ -232,7 +232,14 @@ nsTableOuterFrame::SetInitialChildList(nsIPresContext* aPresContext,
}
else {
mFrames.SetFrames(aChildList);
- mInnerTableFrame = aChildList;
+ mInnerTableFrame = nsnull;
+ if (aChildList) {
+ nsCOMPtr fType;
+ aChildList->GetFrameType(getter_AddRefs(fType));
+ if (nsLayoutAtoms::tableFrame == fType.get()) {
+ mInnerTableFrame = (nsTableFrame*)aChildList;
+ }
+ }
}
return NS_OK;
@@ -466,21 +473,46 @@ FixAutoMargins(nscoord aAvailWidth,
}
}
+void
+nsTableOuterFrame::InitChildReflowState(nsIPresContext& aPresContext,
+ nsHTMLReflowState& aReflowState)
+
+{
+ nsMargin collapseBorder;
+ nsMargin collapsePadding(0,0,0,0);
+ nsMargin* pCollapseBorder = nsnull;
+ nsMargin* pCollapsePadding = nsnull;
+ if ((aReflowState.frame == mInnerTableFrame) && (mInnerTableFrame->IsBorderCollapse())) {
+ if (mInnerTableFrame->NeedToCalcBCBorders()) {
+ mInnerTableFrame->CalcBCBorders(aPresContext);
+ }
+ pCollapseBorder = mInnerTableFrame->GetBCBorder(aPresContext, PR_FALSE, collapseBorder);
+ pCollapsePadding = &collapsePadding;
+ }
+ aReflowState.Init(&aPresContext, -1, -1, pCollapseBorder, pCollapsePadding);
+}
+
// get the margin and padding data. nsHTMLReflowState doesn't handle the
// case of auto margins
void
-GetMarginPadding(nsIPresContext* aPresContext,
- const nsHTMLReflowState& aOuterRS,
- nsIFrame* aChildFrame,
- nsMargin& aMargin,
- nsMargin& aMarginNoAuto,
- nsMargin& aPadding)
+nsTableOuterFrame::GetMarginPadding(nsIPresContext* aPresContext,
+ const nsHTMLReflowState& aOuterRS,
+ nsIFrame* aChildFrame,
+ nsMargin& aMargin,
+ nsMargin& aMarginNoAuto,
+ nsMargin& aPadding)
{
+ if (!aPresContext) ABORT0();
+ GET_PIXELS_TO_TWIPS(aPresContext, p2t);
// construct a reflow state to compute margin and padding. Auto margins
// will not be computed at this time.
+
+ // create an init the child reflow state
nsHTMLReflowState childRS(aPresContext, aOuterRS, aChildFrame,
nsSize(aOuterRS.availableWidth, aOuterRS.availableHeight),
- eReflowReason_Resize);
+ eReflowReason_Resize, PR_FALSE);
+ InitChildReflowState(*aPresContext, childRS);
+
nsRect childRect;
aChildFrame->GetRect(childRect);
FixAutoMargins(aOuterRS.availableWidth, childRect.width, childRS);
@@ -931,6 +963,7 @@ nsTableOuterFrame::OuterReflowChild(nsIPresContext* aPresContext,
nsReflowReason aReflowReason,
nsReflowStatus& aStatus)
{
+ if (!aPresContext) ABORT1(NS_ERROR_NULL_POINTER);
aMargin = aPadding = nsMargin(0,0,0,0);
nscoord availWidth = GetChildAvailWidth(aPresContext, aChildFrame, aOuterRS,
@@ -946,9 +979,10 @@ nsTableOuterFrame::OuterReflowChild(nsIPresContext* aPresContext,
availHeight = nsTableFrame::RoundToPixel(availHeight, p2t, eAlwaysRoundDown);
}
- nsHTMLReflowState childRS(aPresContext, aOuterRS, aChildFrame,
- nsSize(availWidth, availHeight));
- childRS.reason = aReflowReason;
+ // create and init the child reflow state
+ nsHTMLReflowState childRS(aPresContext, aOuterRS, aChildFrame, nsSize(availWidth, availHeight),
+ aReflowReason);
+ InitChildReflowState(*aPresContext, childRS);
childRS.mPercentHeightObserver = nsnull; // the observer is for non table related frames inside cells
diff --git a/mozilla/layout/html/table/src/nsTableOuterFrame.h b/mozilla/layout/html/table/src/nsTableOuterFrame.h
index ee689ab6f08..16eaba4c89d 100644
--- a/mozilla/layout/html/table/src/nsTableOuterFrame.h
+++ b/mozilla/layout/html/table/src/nsTableOuterFrame.h
@@ -47,6 +47,7 @@ class nsReflowTimer;
#endif
struct nsStyleTable;
+class nsTableFrame;
class nsTableCaptionFrame : public nsBlockFrame
{
@@ -201,6 +202,9 @@ protected:
nsTableOuterFrame();
virtual ~nsTableOuterFrame();
+ void InitChildReflowState(nsIPresContext& aPresContext,
+ nsHTMLReflowState& aReflowState);
+
/** Always returns 0, since the outer table frame has no border of its own
* The inner table frame can answer this question in a meaningful way.
* @see nsHTMLContainerFrame::GetSkipSides */
@@ -362,11 +366,17 @@ protected:
PRBool aInnerChanged,
PRBool aCaptionChanged);
+ void GetMarginPadding(nsIPresContext* aPresContext,
+ const nsHTMLReflowState& aOuterRS,
+ nsIFrame* aChildFrame,
+ nsMargin& aMargin,
+ nsMargin& aMarginNoAuto,
+ nsMargin& aPadding);
private:
// used to keep track of this frame's children. They are redundant with mFrames, but more convient
- nsIFrame* mInnerTableFrame;
- nsIFrame* mCaptionFrame;
+ nsTableFrame* mInnerTableFrame;
+ nsIFrame* mCaptionFrame;
// used to track caption max element size
PRInt32 mMinCaptionWidth;
diff --git a/mozilla/layout/html/table/src/nsTableRowFrame.cpp b/mozilla/layout/html/table/src/nsTableRowFrame.cpp
index 59055548c3f..48687f0efb5 100644
--- a/mozilla/layout/html/table/src/nsTableRowFrame.cpp
+++ b/mozilla/layout/html/table/src/nsTableRowFrame.cpp
@@ -68,11 +68,6 @@ struct nsTableCellReflowState : public nsHTMLReflowState
const nsSize& aAvailableSpace,
nsReflowReason aReason);
- nsTableCellReflowState(nsIPresContext* aPresContext,
- const nsHTMLReflowState& aParentReflowState,
- nsIFrame* aFrame,
- const nsSize& aAvailableSpace);
-
void FixUp(const nsSize& aAvailSpace);
};
@@ -83,16 +78,43 @@ nsTableCellReflowState::nsTableCellReflowState(nsIPresContext* aPresCon
nsReflowReason aReason)
:nsHTMLReflowState(aPresContext, aParentRS, aFrame, aAvailSpace, aReason)
{
- FixUp(aAvailSpace);
}
-nsTableCellReflowState::nsTableCellReflowState(nsIPresContext* aPresContext,
- const nsHTMLReflowState& aParentRS,
- nsIFrame* aFrame,
- const nsSize& aAvailSpace)
- :nsHTMLReflowState(aPresContext, aParentRS, aFrame, aAvailSpace)
+void nsTableCellReflowState::FixUp(const nsSize& aAvailSpace)
{
- FixUp(aAvailSpace);
+ // fix the mComputed values during a pass 2 reflow since the cell can be a percentage base
+ if (NS_UNCONSTRAINEDSIZE != aAvailSpace.width) {
+ if (NS_UNCONSTRAINEDSIZE != mComputedWidth) {
+ mComputedWidth = aAvailSpace.width - mComputedBorderPadding.left - mComputedBorderPadding.right;
+ mComputedWidth = PR_MAX(0, mComputedWidth);
+ }
+ if (NS_UNCONSTRAINEDSIZE != mComputedHeight) {
+ if (NS_UNCONSTRAINEDSIZE != aAvailSpace.height) {
+ mComputedHeight = aAvailSpace.height - mComputedBorderPadding.top - mComputedBorderPadding.bottom;
+ mComputedHeight = PR_MAX(0, mComputedHeight);
+ }
+ }
+ }
+}
+
+void
+nsTableRowFrame::InitChildReflowState(nsIPresContext& aPresContext,
+ const nsSize& aAvailSize,
+ PRBool aBorderCollapse,
+ float aPixelsToTwips,
+ nsTableCellReflowState& aReflowState)
+{
+ nsMargin collapseBorder;
+ nsMargin* pCollapseBorder = nsnull;
+ if (aBorderCollapse) {
+ // we only reflow cells, so don't need to check frame type
+ nsBCTableCellFrame* bcCellFrame = (nsBCTableCellFrame*)aReflowState.frame;
+ if (bcCellFrame) {
+ pCollapseBorder = bcCellFrame->GetBorderWidth(aPixelsToTwips, collapseBorder);
+ }
+ }
+ aReflowState.Init(&aPresContext, -1, -1, pCollapseBorder);
+ aReflowState.FixUp(aAvailSize);
}
void
@@ -132,23 +154,6 @@ nsTableRowFrame::SetPctHeight(float aPctValue,
}
}
-void nsTableCellReflowState::FixUp(const nsSize& aAvailSpace)
-{
- // fix the mComputed values during a pass 2 reflow since the cell can be a percentage base
- if (NS_UNCONSTRAINEDSIZE != aAvailSpace.width) {
- if (NS_UNCONSTRAINEDSIZE != mComputedWidth) {
- mComputedWidth = aAvailSpace.width - mComputedBorderPadding.left - mComputedBorderPadding.right;
- mComputedWidth = PR_MAX(0, mComputedWidth);
- }
- if (NS_UNCONSTRAINEDSIZE != mComputedHeight) {
- if (NS_UNCONSTRAINEDSIZE != aAvailSpace.height) {
- mComputedHeight = aAvailSpace.height - mComputedBorderPadding.top - mComputedBorderPadding.bottom;
- mComputedHeight = PR_MAX(0, mComputedHeight);
- }
- }
- }
-}
-
// 'old' is old cached cell's desired size
// 'new' is new cell's size including style constraints
static PRBool
@@ -217,7 +222,7 @@ nsTableRowFrame::SetInitialChildList(nsIPresContext* aPresContext,
kidFrame->GetNextSibling(&kidFrame)) {
nsCOMPtr frameType;
kidFrame->GetFrameType(getter_AddRefs(frameType));
- if (nsLayoutAtoms::tableCellFrame == frameType.get()) {
+ if (IS_TABLE_CELL(frameType.get())) {
if (((nsTableCellFrame*)kidFrame)->GetRowSpan() > 1) {
mState |= NS_FRAME_OUTSIDE_CHILDREN;
}
@@ -241,7 +246,7 @@ nsTableRowFrame::AppendFrames(nsIPresContext* aPresContext,
for (nsIFrame* childFrame = aFrameList; childFrame; childFrame->GetNextSibling(&childFrame)) {
nsCOMPtr frameType;
childFrame->GetFrameType(getter_AddRefs(frameType));
- if (nsLayoutAtoms::tableCellFrame == frameType.get()) {
+ if (IS_TABLE_CELL(frameType.get())) {
// Add the cell to the cell map
tableFrame->AppendCell(*aPresContext, (nsTableCellFrame&)*childFrame, GetRowIndex());
// XXX this could be optimized with some effort
@@ -272,12 +277,13 @@ nsTableRowFrame::InsertFrames(nsIPresContext* aPresContext,
nsTableFrame::GetTableFrame(this, tableFrame);
// gather the new frames (only those which are cells) into an array
- nsTableCellFrame* prevCellFrame = (nsTableCellFrame *)nsTableFrame::GetFrameAtOrBefore(aPresContext, this, aPrevFrame, nsLayoutAtoms::tableCellFrame);
+ nsIAtom* cellFrameType = (tableFrame->IsBorderCollapse()) ? nsLayoutAtoms::bcTableCellFrame : nsLayoutAtoms::tableCellFrame;
+ nsTableCellFrame* prevCellFrame = (nsTableCellFrame *)nsTableFrame::GetFrameAtOrBefore(aPresContext, this, aPrevFrame, cellFrameType);
nsVoidArray cellChildren;
for (nsIFrame* childFrame = aFrameList; childFrame; childFrame->GetNextSibling(&childFrame)) {
nsCOMPtr frameType;
childFrame->GetFrameType(getter_AddRefs(frameType));
- if (nsLayoutAtoms::tableCellFrame == frameType.get()) {
+ if (IS_TABLE_CELL(frameType.get())) {
cellChildren.AppendElement(childFrame);
// XXX this could be optimized with some effort
tableFrame->SetNeedStrategyInit(PR_TRUE);
@@ -315,7 +321,7 @@ nsTableRowFrame::RemoveFrame(nsIPresContext* aPresContext,
if (tableFrame) {
nsCOMPtr frameType;
aOldFrame->GetFrameType(getter_AddRefs(frameType));
- if (nsLayoutAtoms::tableCellFrame == frameType.get()) {
+ if (IS_TABLE_CELL(frameType.get())) {
nsTableCellFrame* cellFrame = (nsTableCellFrame*)aOldFrame;
PRInt32 colIndex;
cellFrame->GetColIndex(colIndex);
@@ -372,7 +378,7 @@ nsTableRowFrame::GetFirstCell()
while (childFrame) {
nsCOMPtr frameType;
childFrame->GetFrameType(getter_AddRefs(frameType));
- if (nsLayoutAtoms::tableCellFrame == frameType.get()) {
+ if (IS_TABLE_CELL(frameType.get())) {
return (nsTableCellFrame*)childFrame;
}
childFrame->GetNextSibling(&childFrame);
@@ -398,7 +404,7 @@ nsTableRowFrame::DidResize(nsIPresContext* aPresContext,
while (childFrame) {
nsCOMPtr frameType;
childFrame->GetFrameType(getter_AddRefs(frameType));
- if (nsLayoutAtoms::tableCellFrame == frameType.get()) {
+ if (IS_TABLE_CELL(frameType.get())) {
nsTableCellFrame* cellFrame = (nsTableCellFrame*)childFrame;
nscoord cellHeight = mRect.height + GetHeightOfRowsSpannedBelowFirst(*cellFrame, *tableFrame);
@@ -534,7 +540,7 @@ nsTableRowFrame::CalcHeight(const nsHTMLReflowState& aReflowState)
for (nsIFrame* kidFrame = mFrames.FirstChild(); kidFrame; kidFrame->GetNextSibling(&kidFrame)) {
nsCOMPtr frameType;
kidFrame->GetFrameType(getter_AddRefs(frameType));
- if (nsLayoutAtoms::tableCellFrame == frameType.get()) {
+ if (IS_TABLE_CELL(frameType.get())) {
nscoord availWidth = ((nsTableCellFrame *)kidFrame)->GetPriorAvailWidth();
nsSize desSize = ((nsTableCellFrame *)kidFrame)->GetDesiredSize();
if ((NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight) && !mPrevInFlow) {
@@ -888,28 +894,29 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext,
aStatus = NS_FRAME_COMPLETE;
if (!mFrames.FirstChild()) return NS_OK;
- nsTableFrame* tableFrame = &aTableFrame;
- if (!tableFrame) return NS_ERROR_NULL_POINTER;
+ GET_PIXELS_TO_TWIPS(aPresContext, p2t);
+ PRBool borderCollapse = (((nsTableFrame*)aTableFrame.GetFirstInFlow())->IsBorderCollapse());
+
nsIFrame* tablePrevInFlow;
- tableFrame->GetPrevInFlow(&tablePrevInFlow);
+ aTableFrame.GetPrevInFlow(&tablePrevInFlow);
PRBool isPaginated;
aPresContext->IsPaginated(&isPaginated);
nsresult rv = NS_OK;
- nscoord cellSpacingX = tableFrame->GetCellSpacingX();
+ nscoord cellSpacingX = aTableFrame.GetCellSpacingX();
PRInt32 cellColSpan = 1; // must be defined here so it's set properly for non-cell kids
nsTableIteration dir = (aReflowState.availableWidth == NS_UNCONSTRAINEDSIZE)
? eTableLTR : eTableDIR;
nsTableIterator iter(aPresContext, *this, dir);
// remember the col index of the previous cell to handle rowspans into this row
- PRInt32 firstPrevColIndex = (iter.IsLeftToRight()) ? -1 : tableFrame->GetColCount();
+ PRInt32 firstPrevColIndex = (iter.IsLeftToRight()) ? -1 : aTableFrame.GetColCount();
PRInt32 prevColIndex = firstPrevColIndex;
nscoord x = 0; // running total of children x offset
- nsTableFrame* tableFirstInFlow = (nsTableFrame*)tableFrame->GetFirstInFlow();
- PRBool isAutoLayout = tableFrame->IsAutoLayout();
+ nsTableFrame* tableFirstInFlow = (nsTableFrame*)aTableFrame.GetFirstInFlow();
+ PRBool isAutoLayout = aTableFrame.IsAutoLayout();
PRBool needToNotifyTable = PR_TRUE;
nscoord paginatedHeight = 0;
// If the incremental reflow command is a StyleChanged reflow and
@@ -945,7 +952,7 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext,
doReflowChild = PR_FALSE;
}
if (aReflowState.mFlags.mSpecialHeightReflow) {
- if (!isPaginated && (nsLayoutAtoms::tableCellFrame == frameType.get() &&
+ if (!isPaginated && (IS_TABLE_CELL(frameType.get()) &&
!((nsTableCellFrame*)kidFrame)->NeedSpecialReflow())) {
kidFrame = iter.Next();
continue;
@@ -954,22 +961,22 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext,
// Reflow the child frame
if (doReflowChild) {
- if (nsLayoutAtoms::tableCellFrame == frameType.get()) {
+ if (IS_TABLE_CELL(frameType.get())) {
nsTableCellFrame* cellFrame = (nsTableCellFrame*)kidFrame;
PRInt32 cellColIndex;
cellFrame->GetColIndex(cellColIndex);
- cellColSpan = tableFrame->GetEffectiveColSpan(*cellFrame);
+ cellColSpan = aTableFrame.GetEffectiveColSpan(*cellFrame);
x += cellSpacingX;
// If the adjacent cell is in a prior row (because of a rowspan) add in the space
if ((iter.IsLeftToRight() && (prevColIndex != (cellColIndex - 1))) ||
(!iter.IsLeftToRight() && (prevColIndex != cellColIndex + cellColSpan))) {
- x += GetSpaceBetween(prevColIndex, cellColIndex, cellColSpan, *tableFrame,
+ x += GetSpaceBetween(prevColIndex, cellColIndex, cellColSpan, aTableFrame,
cellSpacingX, iter.IsLeftToRight());
}
// Calculate the available width for the table cell using the known column widths
nscoord availColWidth, availCellWidth;
- CalcAvailWidth(*tableFrame, GetComputedWidth(aReflowState, *tableFrame),
+ CalcAvailWidth(aTableFrame, GetComputedWidth(aReflowState, aTableFrame),
*cellFrame, cellSpacingX, availColWidth, availCellWidth);
if (0 == availColWidth) availColWidth = NS_UNCONSTRAINEDSIZE;
if (0 == availCellWidth) availCellWidth = NS_UNCONSTRAINEDSIZE;
@@ -1032,6 +1039,8 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext,
// Reflow the child
nsTableCellReflowState kidReflowState(aPresContext, aReflowState,
kidFrame, kidAvailSize, reason);
+ InitChildReflowState(*aPresContext, kidAvailSize, borderCollapse, p2t, kidReflowState);
+
nsReflowStatus status;
rv = ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState,
x, 0, 0, status);
@@ -1052,7 +1061,7 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext,
// allow the table to determine if/how the table needs to be rebalanced
if (cellToWatch && needToNotifyTable) {
- needToNotifyTable = !tableFrame->CellChangedWidth(*cellFrame, oldMaxWidth, oldMaxElemWidth);
+ needToNotifyTable = !aTableFrame.CellChangedWidth(*cellFrame, oldMaxWidth, oldMaxElemWidth);
}
// If any of the cells are not complete, then we're not complete
@@ -1081,10 +1090,10 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext,
// height may have changed, adjust descent to absorb any excess difference
nscoord ascent = cellFrame->GetDesiredAscent();
nscoord descent = desiredSize.height - ascent;
- UpdateHeight(desiredSize.height, ascent, descent, tableFrame, cellFrame);
+ UpdateHeight(desiredSize.height, ascent, descent, &aTableFrame, cellFrame);
}
else {
- PRInt32 rowSpan = tableFrame->GetEffectiveRowSpan((nsTableCellFrame&)*kidFrame);
+ PRInt32 rowSpan = aTableFrame.GetEffectiveRowSpan((nsTableCellFrame&)*kidFrame);
if ((1 == rowSpan) && (desiredSize.height > paginatedHeight)) {
paginatedHeight = desiredSize.height;
SetContentHeight(paginatedHeight);
@@ -1102,13 +1111,14 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext,
else {// it's an unknown frame type, give it a generic reflow and ignore the results
nsTableCellReflowState kidReflowState(aPresContext, aReflowState,
kidFrame, nsSize(0,0), eReflowReason_Resize);
+ InitChildReflowState(*aPresContext, nsSize(0,0), PR_FALSE, p2t, kidReflowState);
nsHTMLReflowMetrics desiredSize(nsnull);
nsReflowStatus status;
ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState, 0, 0, 0, status);
kidFrame->DidReflow(aPresContext, nsnull, NS_FRAME_REFLOW_FINISHED);
}
}
- else if (nsLayoutAtoms::tableCellFrame == frameType.get()) {
+ else if (IS_TABLE_CELL(frameType.get())) {
// we need to account for the cell's width even if it isn't reflowed
nsRect rect;
kidFrame->GetRect(rect);
@@ -1244,7 +1254,10 @@ nsTableRowFrame::IR_TargetIsChild(nsIPresContext* aPresContext,
// update its maximum width.
nsHTMLReflowMetrics cellMet(&kidMaxElementSize, isAutoLayout ?
NS_REFLOW_CALC_MAX_WIDTH : 0);
- nsTableCellReflowState kidRS(aPresContext, aReflowState, aNextFrame, cellAvailSize);
+ GET_PIXELS_TO_TWIPS(aPresContext, p2t);
+ nsTableCellReflowState kidRS(aPresContext, aReflowState, aNextFrame, cellAvailSize,
+ aReflowState.reason);
+ InitChildReflowState(*aPresContext, cellAvailSize, aTableFrame.IsBorderCollapse(), p2t, kidRS);
// Remember the current desired size, we'll need it later
nscoord oldCellMinWidth = cellFrame->GetPass1MaxElementWidth();
@@ -1492,13 +1505,20 @@ nsTableRowFrame::ReflowCellFrame(nsIPresContext* aPresContext,
nscoord aAvailableHeight,
nsReflowStatus& aStatus)
{
+ nsTableFrame* tableFrame = nsnull;
+ nsTableFrame::GetTableFrame(this, tableFrame); if (!tableFrame) ABORT1(0);
+
// Reflow the cell frame with the specified height. Use the existing width
nsSize cellSize;
aCellFrame->GetSize(cellSize);
nsSize availSize(cellSize.width, aAvailableHeight);
+ PRBool borderCollapse = ((nsTableFrame*)tableFrame->GetFirstInFlow())->IsBorderCollapse();
+ GET_PIXELS_TO_TWIPS(aPresContext, p2t);
nsTableCellReflowState cellReflowState(aPresContext, aReflowState, aCellFrame, availSize,
eReflowReason_Resize);
+ InitChildReflowState(*aPresContext, availSize, borderCollapse, p2t, cellReflowState);
+
nsHTMLReflowMetrics desiredSize(nsnull);
ReflowChild(aCellFrame, aPresContext, desiredSize, cellReflowState,
@@ -1534,7 +1554,7 @@ nsTableRowFrame::InsertCellFrame(nsTableCellFrame* aFrame,
for (nsIFrame* child = mFrames.FirstChild(); child; child->GetNextSibling(&child)) {
nsCOMPtr frameType;
child->GetFrameType(getter_AddRefs(frameType));
- if (nsLayoutAtoms::tableCellFrame != frameType.get()) {
+ if (!IS_TABLE_CELL(frameType.get())) {
nsTableCellFrame* cellFrame = (nsTableCellFrame*)child;
PRInt32 colIndex;
cellFrame->GetColIndex(colIndex);
diff --git a/mozilla/layout/html/table/src/nsTableRowFrame.h b/mozilla/layout/html/table/src/nsTableRowFrame.h
index 552ee7910b3..d05dc5eab6a 100644
--- a/mozilla/layout/html/table/src/nsTableRowFrame.h
+++ b/mozilla/layout/html/table/src/nsTableRowFrame.h
@@ -42,6 +42,7 @@
class nsTableFrame;
class nsTableCellFrame;
+struct nsTableCellReflowState;
#ifdef DEBUG_TABLE_REFLOW_TIMING
class nsReflowTimer;
@@ -240,6 +241,12 @@ public:
nscoord GetUnpaginatedHeight(nsIPresContext* aPresContext);
void SetUnpaginatedHeight(nsIPresContext* aPresContext, nscoord aValue);
+ nscoord GetTopBCBorderWidth(float* aPixelsToTwips = nsnull);
+ void SetTopBCBorderWidth(nscoord aWidth);
+ nscoord GetBottomBCBorderWidth(float* aPixelsToTwips = nsnull);
+ void SetBottomBCBorderWidth(nscoord aWidth);
+ nsMargin* GetBCBorderWidth(float aPixelsToTwips,
+ nsMargin& aBorder);
protected:
/** protected constructor.
@@ -247,6 +254,12 @@ protected:
*/
nsTableRowFrame();
+ void InitChildReflowState(nsIPresContext& aPresContext,
+ const nsSize& aAvailSize,
+ PRBool aBorderCollapse,
+ float aPixelsToTwips,
+ nsTableCellReflowState& aReflowState);
+
/** implement abstract method on nsHTMLContainerFrame */
virtual PRIntn GetSkipSides() const;
@@ -315,6 +328,10 @@ private:
nscoord mMaxCellAscent; // does include cells with rowspan > 1
nscoord mMaxCellDescent; // does *not* include cells with rowspan > 1
+ // border widths in pixels in the collapsing border model
+ unsigned mTopBorderWidth:8;
+ unsigned mBottomBorderWidth:8;
+
#ifdef DEBUG_TABLE_REFLOW_TIMING
public:
nsReflowTimer* mTimer;
@@ -421,4 +438,37 @@ inline void nsTableRowFrame::SetHasUnpaginatedHeight(PRBool aValue)
}
}
+inline nscoord nsTableRowFrame::GetTopBCBorderWidth(float* aPixelsToTwips)
+{
+ nscoord width = (aPixelsToTwips) ? NSToCoordRound(*aPixelsToTwips * mTopBorderWidth) : mTopBorderWidth;
+ return width;
+}
+
+inline void nsTableRowFrame::SetTopBCBorderWidth(nscoord aWidth)
+{
+ mTopBorderWidth = aWidth;
+}
+
+inline nscoord nsTableRowFrame::GetBottomBCBorderWidth(float* aPixelsToTwips)
+{
+ nscoord width = (aPixelsToTwips) ? NSToCoordRound(*aPixelsToTwips * mBottomBorderWidth) : mBottomBorderWidth;
+ return width;
+}
+
+inline void nsTableRowFrame::SetBottomBCBorderWidth(nscoord aWidth)
+{
+ mBottomBorderWidth = aWidth;
+}
+
+inline nsMargin* nsTableRowFrame::GetBCBorderWidth(float aPixelsToTwips,
+ nsMargin& aBorder)
+{
+ aBorder.left = aBorder.right = 0;
+
+ aBorder.top = NSToCoordRound(aPixelsToTwips * mTopBorderWidth);
+ aBorder.bottom = NSToCoordRound(aPixelsToTwips * mBottomBorderWidth);
+
+ return &aBorder;
+}
+
#endif
diff --git a/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp b/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp
index f0ff97530bb..2405a50a342 100644
--- a/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp
+++ b/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp
@@ -180,7 +180,7 @@ nsTableRowGroupFrame::InitRepeatedFrame(nsIPresContext* aPresContext,
nsIAtom* frameType;
copyCellFrame->GetFrameType(&frameType);
- if (nsLayoutAtoms::tableCellFrame == frameType) {
+ if (IS_TABLE_CELL(frameType)) {
#ifdef NS_DEBUG
nsIContent* content1;
nsIContent* content2;
@@ -360,6 +360,28 @@ nsTableRowGroupFrame::PlaceChild(nsIPresContext* aPresContext,
}
}
+void
+nsTableRowGroupFrame::InitChildReflowState(nsIPresContext& aPresContext,
+ PRBool aBorderCollapse,
+ float aPixelsToTwips,
+ nsHTMLReflowState& aReflowState)
+{
+ nsMargin collapseBorder;
+ nsMargin padding(0,0,0,0);
+ nsMargin* pCollapseBorder = nsnull;
+ if (aBorderCollapse) {
+ if (aReflowState.frame) {
+ nsCOMPtr fType;
+ aReflowState.frame->GetFrameType(getter_AddRefs(fType));
+ if (nsLayoutAtoms::tableRowFrame == fType.get()) {
+ nsTableRowFrame* rowFrame = (nsTableRowFrame*)aReflowState.frame;
+ pCollapseBorder = rowFrame->GetBCBorderWidth(aPixelsToTwips, collapseBorder);
+ }
+ }
+ }
+ aReflowState.Init(&aPresContext, -1, -1, pCollapseBorder, &padding);
+}
+
// Reflow the frames we've already created. If aDirtyOnly is set then only
// reflow dirty frames. This assumes that all of the dirty frames are contiguous.
NS_METHOD
@@ -372,8 +394,10 @@ nsTableRowGroupFrame::ReflowChildren(nsIPresContext* aPresContext,
nsTableRowFrame** aFirstRowReflowed)
{
nsTableFrame* tableFrame = nsnull;
- nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame);
- if (NS_FAILED(rv) || !tableFrame) return rv;
+ nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame); if (!tableFrame) ABORT1(rv);
+
+ PRBool borderCollapse = tableFrame->IsBorderCollapse();
+ GET_PIXELS_TO_TWIPS(aPresContext, p2t);
nscoord cellSpacingY = tableFrame->GetCellSpacingY();
@@ -439,6 +463,7 @@ nsTableRowGroupFrame::ReflowChildren(nsIPresContext* aPresContext,
}
nsHTMLReflowState kidReflowState(aPresContext, aReflowState.reflowState, kidFrame,
kidAvailSize, reason);
+ InitChildReflowState(*aPresContext, borderCollapse, p2t, kidReflowState);
// If this isn't the first row frame, then we can't be at the top of
// the page anymore...
@@ -555,7 +580,7 @@ HasMoreThanOneCell(nsTableCellMap* aCellMap,
PRInt32 colIndex = 0;
PRInt32 count = 0;
do {
- cellData = aCellMap->GetCellAt(aRowIndex, colIndex);
+ cellData = aCellMap->GetDataAt(aRowIndex, colIndex);
if (cellData && (cellData->GetCellFrame() || cellData->IsRowSpan()))
count++;
if (count > 1)
@@ -998,8 +1023,8 @@ nsTableRowGroupFrame::SplitRowGroup(nsIPresContext* aPresContext,
presShell->GetStyleSet(getter_AddRefs(styleSet));
if (!styleSet) {NS_ASSERTION(PR_FALSE, "no style set"); return NS_ERROR_NULL_POINTER;}
- float p2t;
- aPresContext->GetPixelsToTwips(&p2t);
+ GET_PIXELS_TO_TWIPS(aPresContext, p2t);
+ PRBool borderCollapse = ((nsTableFrame*)aTableFrame->GetFirstInFlow())->IsBorderCollapse();
nscoord availWidth = nsTableFrame::RoundToPixel(aReflowState.availableWidth, p2t);
nscoord availHeight = nsTableFrame::RoundToPixel(aReflowState.availableHeight, p2t);
@@ -1022,9 +1047,11 @@ nsTableRowGroupFrame::SplitRowGroup(nsIPresContext* aPresContext,
// row or there is at least 5% of the current page available
if (!prevRowFrame || (availHeight - aDesiredSize.height > pageHeight / 20)) {
// Reflow the row in the available space and have it split
- nsSize availSize(availWidth, availHeight - bounds.y);
- nsHTMLReflowState rowReflowState(aPresContext, aReflowState, rowFrame,
- availSize, eReflowReason_Resize);
+ nsSize availSize(availWidth, availHeight - bounds.y);
+ nsHTMLReflowState rowReflowState(aPresContext, aReflowState, rowFrame, availSize,
+ eReflowReason_Resize);
+ InitChildReflowState(*aPresContext, borderCollapse, p2t, rowReflowState);
+
nsHTMLReflowMetrics desiredSize(nsnull);
rv = ReflowChild(rowFrame, aPresContext, desiredSize, rowReflowState,
@@ -1530,6 +1557,10 @@ nsTableRowGroupFrame::IR_TargetIsChild(nsIPresContext* aPresContext,
{
nsresult rv;
+ nsTableFrame* tableFrame = nsnull;
+ nsTableFrame::GetTableFrame(this, tableFrame); if (!tableFrame) ABORT1(NS_ERROR_NULL_POINTER);
+ GET_PIXELS_TO_TWIPS(aPresContext, p2t);
+
// Recover the state as if aNextFrame is about to be reflowed
RecoverState(aReflowState, aNextFrame);
@@ -1540,9 +1571,11 @@ nsTableRowGroupFrame::IR_TargetIsChild(nsIPresContext* aPresContext,
// Reflow the child giving it as much room as it wants. We'll deal with
// splitting later after final determination of rows heights taking into
// account cells with row spans...
- nsSize kidAvailSize(aReflowState.availSize.width, NS_UNCONSTRAINEDSIZE);
- nsHTMLReflowState kidReflowState(aPresContext, aReflowState.reflowState,
- aNextFrame, kidAvailSize);
+ nsSize kidAvailSize(aReflowState.availSize.width, NS_UNCONSTRAINEDSIZE);
+ nsHTMLReflowState kidReflowState(aPresContext, aReflowState.reflowState, aNextFrame,
+ kidAvailSize, aReflowState.reason);
+ InitChildReflowState(*aPresContext, tableFrame->IsBorderCollapse(), p2t, kidReflowState);
+
nsSize kidMaxElementSize;
nsHTMLReflowMetrics desiredSize(aDesiredSize.maxElementSize ? &kidMaxElementSize : nsnull,
aDesiredSize.mFlags);
@@ -1715,6 +1748,28 @@ nsTableRowGroupFrame::SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) cons
}
#endif
+nsMargin*
+nsTableRowGroupFrame::GetBCBorderWidth(float aPixelsToTwips,
+ nsMargin& aBorder)
+{
+ aBorder.left = aBorder.right = 0;
+
+ nsTableRowFrame* firstRowFrame = nsnull;
+ nsTableRowFrame* lastRowFrame = nsnull;
+ for (nsTableRowFrame* rowFrame = GetFirstRow(); rowFrame; rowFrame = rowFrame->GetNextRow()) {
+ if(!firstRowFrame) {
+ firstRowFrame = rowFrame;
+ }
+ lastRowFrame = rowFrame;
+ }
+ if (firstRowFrame) {
+ aBorder.top = firstRowFrame->GetTopBCBorderWidth(&aPixelsToTwips);
+ aBorder.bottom = lastRowFrame->GetBottomBCBorderWidth(&aPixelsToTwips);
+ }
+
+ return &aBorder;
+}
+
//nsILineIterator methods for nsTableFrame
NS_IMETHODIMP
nsTableRowGroupFrame::GetNumLines(PRInt32* aResult)
@@ -1757,7 +1812,7 @@ nsTableRowGroupFrame::GetLine(PRInt32 aLineNumber,
*aLineFlags = 0;/// should we fill these in later?
// not gonna touch aLineBounds right now
- CellData* firstCellData = cellMap->GetCellAt(aLineNumber, 0);
+ CellData* firstCellData = cellMap->GetDataAt(aLineNumber, 0);
if(!firstCellData)
return NS_ERROR_FAILURE;
@@ -1767,7 +1822,7 @@ nsTableRowGroupFrame::GetLine(PRInt32 aLineNumber,
while((aLineNumber > 0)&&(!(*aFirstFrameOnLine)))
{
aLineNumber--;
- firstCellData = cellMap->GetCellAt(aLineNumber, 0);
+ firstCellData = cellMap->GetDataAt(aLineNumber, 0);
*aFirstFrameOnLine = (nsIFrame*)firstCellData->GetCellFrame();
}
}
@@ -1847,7 +1902,7 @@ nsTableRowGroupFrame::FindFrameAt(PRInt32 aLineNumber,
PRBool gotParentRect = PR_FALSE;
for(int i =0;i < cellCount; i++)
{
- cellData = cellMap->GetCellAt(aLineNumber, i);
+ cellData = cellMap->GetDataAt(aLineNumber, i);
tempFrame = (nsIFrame*)cellData->GetCellFrame();
if(!tempFrame)
@@ -1919,11 +1974,11 @@ nsTableRowGroupFrame::GetNextSiblingOnLine(nsIFrame*& aFrame,
PRInt32& colIndexRef = colIndex;
cellFrame->GetColIndex(colIndexRef);
- CellData* cellData = cellMap->GetCellAt(aLineNumber, colIndex + 1);
+ CellData* cellData = cellMap->GetDataAt(aLineNumber, colIndex + 1);
if(!cellData)// if this isnt a valid cell, drop down and check the next line
{
- cellData = cellMap->GetCellAt(aLineNumber + 1, 0);
+ cellData = cellMap->GetDataAt(aLineNumber + 1, 0);
if(!cellData)
{
//*aFrame = nsnull;
@@ -1940,14 +1995,14 @@ nsTableRowGroupFrame::GetNextSiblingOnLine(nsIFrame*& aFrame,
while((tempCol > 0) && (!aFrame))
{
tempCol--;
- cellData = cellMap->GetCellAt(aLineNumber, tempCol);
+ cellData = cellMap->GetDataAt(aLineNumber, tempCol);
aFrame = (nsIFrame*)cellData->GetCellFrame();
if(!aFrame && (tempCol==0))
{
while((tempRow > 0) && (!aFrame))
{
tempRow--;
- cellData = cellMap->GetCellAt(tempRow, 0);
+ cellData = cellMap->GetDataAt(tempRow, 0);
aFrame = (nsIFrame*)cellData->GetCellFrame();
}
}
diff --git a/mozilla/layout/html/table/src/nsTableRowGroupFrame.h b/mozilla/layout/html/table/src/nsTableRowGroupFrame.h
index 0a3859755b4..d259a63bdfb 100644
--- a/mozilla/layout/html/table/src/nsTableRowGroupFrame.h
+++ b/mozilla/layout/html/table/src/nsTableRowGroupFrame.h
@@ -216,6 +216,8 @@ public:
nscoord GetHeightOfRows(nsIPresContext* aPresContext);
nscoord GetHeightBasis(const nsHTMLReflowState& aReflowState);
+ nsMargin* GetBCBorderWidth(float aPixelsToTwips,
+ nsMargin& aBorder);
// nsILineIterator methods
public:
NS_IMETHOD GetNumLines(PRInt32* aResult);
@@ -251,6 +253,11 @@ public:
protected:
nsTableRowGroupFrame();
+ void InitChildReflowState(nsIPresContext& aPresContext,
+ PRBool aBorderCollapse,
+ float aPixelsToTwips,
+ nsHTMLReflowState& aReflowState);
+
/** implement abstract method on nsHTMLContainerFrame */
virtual PRIntn GetSkipSides() const;
diff --git a/mozilla/layout/style/html.css b/mozilla/layout/style/html.css
index a501e25a540..61190f734f4 100644
--- a/mozilla/layout/style/html.css
+++ b/mozilla/layout/style/html.css
@@ -168,6 +168,10 @@ table[align="right"] {
text-align: start;
}
+table[rules] {
+ border-collapse: collapse;
+}
+
*|*:table-outer {
display: table;
margin: 0;
@@ -219,6 +223,11 @@ tr {
col, *|*:table-column {
display: table-column;
+ border: inherit;
+ width: inherit;
+ height: inherit;
+ background: inherit;
+ border: inherit;
}
colgroup, *|*:table-column-group {
diff --git a/mozilla/layout/style/nsCSSPropList.h b/mozilla/layout/style/nsCSSPropList.h
index ce14a5df95e..3007f42b36f 100644
--- a/mozilla/layout/style/nsCSSPropList.h
+++ b/mozilla/layout/style/nsCSSPropList.h
@@ -103,7 +103,7 @@ CSS_PROP(border-bottom-color, border_bottom_color, VISUAL)
CSS_PROP(-moz-border-bottom-colors, border_bottom_colors, VISUAL)
CSS_PROP(border-bottom-style, border_bottom_style, REFLOW) // on/off will need reflow
CSS_PROP(border-bottom-width, border_bottom_width, REFLOW)
-CSS_PROP(border-collapse, border_collapse, REFLOW)
+CSS_PROP(border-collapse, border_collapse, FRAMECHANGE)
CSS_PROP(border-color, border_color, VISUAL)
CSS_PROP(border-left, border_left, REFLOW)
CSS_PROP(border-left-color, border_left_color, VISUAL)
diff --git a/mozilla/layout/style/nsHTMLStyleSheet.cpp b/mozilla/layout/style/nsHTMLStyleSheet.cpp
index 2421da50e03..1ec64eabe97 100644
--- a/mozilla/layout/style/nsHTMLStyleSheet.cpp
+++ b/mozilla/layout/style/nsHTMLStyleSheet.cpp
@@ -475,6 +475,254 @@ TableTHRule::MapRuleInfoInto(nsRuleData* aRuleData)
return NS_OK;
}
+static void
+ProcessTableRulesAttribute(nsStyleStruct* aStyleStruct,
+ nsRuleData* aRuleData,
+ PRUint8 aSide,
+ PRBool aGroup,
+ PRUint8 aRulesArg1,
+ PRUint8 aRulesArg2,
+ PRUint8 aRulesArg3)
+{
+ if (!aStyleStruct || !aRuleData || !aRuleData->mPresContext) return;
+
+ nsCOMPtr tableContext = getter_AddRefs(aRuleData->mStyleContext->GetParent()); if (!tableContext) return;
+ if (!aGroup) {
+ tableContext = getter_AddRefs(tableContext->GetParent()); if (!tableContext) return;
+ }
+
+ const nsStyleTable* tableData =
+ (const nsStyleTable*)tableContext->GetStyleData(eStyleStruct_Table);
+ if (tableData && ((aRulesArg1 == tableData->mRules) ||
+ (aRulesArg2 == tableData->mRules) ||
+ (aRulesArg3 == tableData->mRules))) {
+ const nsStyleBorder* tableBorderData =
+ (const nsStyleBorder*)tableContext->GetStyleData(eStyleStruct_Border); if (!tableBorderData) return;
+ PRUint8 tableBorderStyle = tableBorderData->GetBorderStyle(aSide);
+
+ nsStyleBorder* borderData = (nsStyleBorder*)aStyleStruct; if (!borderData) return;
+ PRUint8 borderStyle = borderData->GetBorderStyle(aSide);
+ // XXX It appears that the style system erronously applies the custom style rule after css style,
+ // consequently it does not properly fit into the casade. For now, assume that a border style of none
+ // implies that the style has not been set.
+ if (NS_STYLE_BORDER_STYLE_NONE == borderStyle) {
+ // use the table's border style if it is dashed or dotted, otherwise use solid
+ PRUint8 bStyle = ((NS_STYLE_BORDER_STYLE_NONE != tableBorderStyle) &&
+ (NS_STYLE_BORDER_STYLE_HIDDEN != tableBorderStyle))
+ ? tableBorderStyle : NS_STYLE_BORDER_STYLE_SOLID;
+ if ((NS_STYLE_BORDER_STYLE_DASHED != bStyle) &&
+ (NS_STYLE_BORDER_STYLE_DOTTED != bStyle) &&
+ (NS_STYLE_BORDER_STYLE_SOLID != bStyle)) {
+ bStyle = NS_STYLE_BORDER_STYLE_SOLID;
+ }
+ bStyle |= NS_STYLE_BORDER_STYLE_RULES_MASK;
+ borderData->SetBorderStyle(aSide, bStyle);
+
+ nscolor borderColor;
+ PRBool transparent, foreground;
+ borderData->GetBorderColor(aSide, borderColor, transparent, foreground);
+ if (transparent || foreground) {
+ // use the table's border color if it is set, otherwise use black
+ nscolor tableBorderColor;
+ tableBorderData->GetBorderColor(aSide, tableBorderColor, transparent, foreground);
+ borderColor = (transparent || foreground) ? NS_RGB(0,0,0) : tableBorderColor;
+ borderData->SetBorderColor(aSide, borderColor);
+ }
+ // set the border width to be 1 pixel
+ float p2t;
+ aRuleData->mPresContext->GetScaledPixelsToTwips(&p2t);
+ nscoord onePixel = NSToCoordRound(p2t);
+ nsStyleCoord coord(onePixel);
+ switch(aSide) {
+ case NS_SIDE_TOP:
+ borderData->mBorder.SetTop(coord);
+ break;
+ case NS_SIDE_RIGHT:
+ borderData->mBorder.SetRight(coord);
+ break;
+ case NS_SIDE_BOTTOM:
+ borderData->mBorder.SetBottom(coord);
+ break;
+ default: // NS_SIDE_LEFT
+ borderData->mBorder.SetLeft(coord);
+ break;
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------
+// this rule handles borders on a , , when rules is set on its
+// -----------------------------------------------------------
+class TableTbodyRule: public GenericTableRule {
+public:
+ TableTbodyRule(nsIHTMLStyleSheet* aSheet);
+ virtual ~TableTbodyRule();
+
+ void Reset()
+ {
+ GenericTableRule::Reset();
+ }
+
+ NS_IMETHOD MapRuleInfoInto(nsRuleData* aRuleData);
+};
+
+TableTbodyRule::TableTbodyRule(nsIHTMLStyleSheet* aSheet)
+: GenericTableRule(aSheet)
+{
+}
+
+TableTbodyRule::~TableTbodyRule()
+{
+}
+
+static void TbodyPostResolveCallback(nsStyleStruct* aStyleStruct, nsRuleData* aRuleData)
+{
+ ::ProcessTableRulesAttribute(aStyleStruct, aRuleData, NS_SIDE_TOP, PR_TRUE, NS_STYLE_TABLE_RULES_ALL,
+ NS_STYLE_TABLE_RULES_GROUPS, NS_STYLE_TABLE_RULES_ROWS);
+ ::ProcessTableRulesAttribute(aStyleStruct, aRuleData, NS_SIDE_BOTTOM, PR_TRUE, NS_STYLE_TABLE_RULES_ALL,
+ NS_STYLE_TABLE_RULES_GROUPS, NS_STYLE_TABLE_RULES_ROWS);
+}
+
+NS_IMETHODIMP
+TableTbodyRule::MapRuleInfoInto(nsRuleData* aRuleData)
+{
+ if (aRuleData && aRuleData->mSID == eStyleStruct_Border) {
+ aRuleData->mCanStoreInRuleTree = PR_FALSE;
+ aRuleData->mPostResolveCallback = &TbodyPostResolveCallback;
+ }
+ return NS_OK;
+}
+// -----------------------------------------------------------
+
+// -----------------------------------------------------------
+// this rule handles borders on a when rules is set on its
+// -----------------------------------------------------------
+class TableRowRule: public GenericTableRule {
+public:
+ TableRowRule(nsIHTMLStyleSheet* aSheet);
+ virtual ~TableRowRule();
+
+ void Reset()
+ {
+ GenericTableRule::Reset();
+ }
+
+ NS_IMETHOD MapRuleInfoInto(nsRuleData* aRuleData);
+};
+
+TableRowRule::TableRowRule(nsIHTMLStyleSheet* aSheet)
+: GenericTableRule(aSheet)
+{
+}
+
+TableRowRule::~TableRowRule()
+{
+}
+
+static void RowPostResolveCallback(nsStyleStruct* aStyleStruct, nsRuleData* aRuleData)
+{
+ ::ProcessTableRulesAttribute(aStyleStruct, aRuleData, NS_SIDE_TOP, PR_FALSE, NS_STYLE_TABLE_RULES_ALL,
+ NS_STYLE_TABLE_RULES_ROWS, NS_STYLE_TABLE_RULES_ROWS);
+ ::ProcessTableRulesAttribute(aStyleStruct, aRuleData, NS_SIDE_BOTTOM, PR_FALSE, NS_STYLE_TABLE_RULES_ALL,
+ NS_STYLE_TABLE_RULES_ROWS, NS_STYLE_TABLE_RULES_ROWS);
+}
+
+NS_IMETHODIMP
+TableRowRule::MapRuleInfoInto(nsRuleData* aRuleData)
+{
+ if (aRuleData && aRuleData->mSID == eStyleStruct_Border) {
+ aRuleData->mCanStoreInRuleTree = PR_FALSE;
+ aRuleData->mPostResolveCallback = &RowPostResolveCallback;
+ }
+ return NS_OK;
+}
+
+// -----------------------------------------------------------
+// this rule handles borders on a when rules is set on its
+// -----------------------------------------------------------
+class TableColgroupRule: public GenericTableRule {
+public:
+ TableColgroupRule(nsIHTMLStyleSheet* aSheet);
+ virtual ~TableColgroupRule();
+
+ void Reset()
+ {
+ GenericTableRule::Reset();
+ }
+
+ NS_IMETHOD MapRuleInfoInto(nsRuleData* aRuleData);
+};
+
+TableColgroupRule::TableColgroupRule(nsIHTMLStyleSheet* aSheet)
+: GenericTableRule(aSheet)
+{
+}
+
+TableColgroupRule::~TableColgroupRule()
+{
+}
+
+static void ColgroupPostResolveCallback(nsStyleStruct* aStyleStruct, nsRuleData* aRuleData)
+{
+ ::ProcessTableRulesAttribute(aStyleStruct, aRuleData, NS_SIDE_LEFT, PR_TRUE, NS_STYLE_TABLE_RULES_ALL,
+ NS_STYLE_TABLE_RULES_GROUPS, NS_STYLE_TABLE_RULES_COLS);
+ ::ProcessTableRulesAttribute(aStyleStruct, aRuleData, NS_SIDE_RIGHT, PR_TRUE, NS_STYLE_TABLE_RULES_ALL,
+ NS_STYLE_TABLE_RULES_GROUPS, NS_STYLE_TABLE_RULES_COLS);
+}
+
+NS_IMETHODIMP
+TableColgroupRule::MapRuleInfoInto(nsRuleData* aRuleData)
+{
+ if (aRuleData && aRuleData->mSID == eStyleStruct_Border) {
+ aRuleData->mCanStoreInRuleTree = PR_FALSE;
+ aRuleData->mPostResolveCallback = &ColgroupPostResolveCallback;
+ }
+ return NS_OK;
+}
+
+// -----------------------------------------------------------
+// this rule handles borders on a when rules is set on its
+// -----------------------------------------------------------
+class TableColRule: public GenericTableRule {
+public:
+ TableColRule(nsIHTMLStyleSheet* aSheet);
+ virtual ~TableColRule();
+
+ void Reset()
+ {
+ GenericTableRule::Reset();
+ }
+
+ NS_IMETHOD MapRuleInfoInto(nsRuleData* aRuleData);
+};
+
+TableColRule::TableColRule(nsIHTMLStyleSheet* aSheet)
+: GenericTableRule(aSheet)
+{
+}
+
+TableColRule::~TableColRule()
+{
+}
+
+static void ColPostResolveCallback(nsStyleStruct* aStyleStruct, nsRuleData* aRuleData)
+{
+ ::ProcessTableRulesAttribute(aStyleStruct, aRuleData, NS_SIDE_LEFT, PR_FALSE, NS_STYLE_TABLE_RULES_ALL,
+ NS_STYLE_TABLE_RULES_COLS, NS_STYLE_TABLE_RULES_COLS);
+ ::ProcessTableRulesAttribute(aStyleStruct, aRuleData, NS_SIDE_RIGHT, PR_FALSE, NS_STYLE_TABLE_RULES_ALL,
+ NS_STYLE_TABLE_RULES_COLS, NS_STYLE_TABLE_RULES_COLS);
+}
+
+NS_IMETHODIMP
+TableColRule::MapRuleInfoInto(nsRuleData* aRuleData)
+{
+ if (aRuleData && aRuleData->mSID == eStyleStruct_Border) {
+ aRuleData->mCanStoreInRuleTree = PR_FALSE;
+ aRuleData->mPostResolveCallback = &ColPostResolveCallback;
+ }
+ return NS_OK;
+}
// -----------------------------------------------------------
class AttributeKey: public nsHashKey
@@ -653,6 +901,10 @@ protected:
HTMLColorRule* mVisitedRule;
HTMLColorRule* mActiveRule;
HTMLDocumentColorRule* mDocumentColorRule;
+ TableTbodyRule* mTableTbodyRule;
+ TableRowRule* mTableRowRule;
+ TableColgroupRule* mTableColgroupRule;
+ TableColRule* mTableColRule;
TableTHRule* mTableTHRule;
// NOTE: if adding more rules, be sure to update
// the SizeOf method to include them
@@ -710,6 +962,26 @@ HTMLStyleSheetImpl::HTMLStyleSheetImpl(void)
nsresult
HTMLStyleSheetImpl::Init()
{
+ mTableTbodyRule = new TableTbodyRule(this);
+ if (!mTableTbodyRule)
+ return NS_ERROR_OUT_OF_MEMORY;
+ NS_ADDREF(mTableTbodyRule);
+
+ mTableRowRule = new TableRowRule(this);
+ if (!mTableRowRule)
+ return NS_ERROR_OUT_OF_MEMORY;
+ NS_ADDREF(mTableRowRule);
+
+ mTableColgroupRule = new TableColgroupRule(this);
+ if (!mTableColgroupRule)
+ return NS_ERROR_OUT_OF_MEMORY;
+ NS_ADDREF(mTableColgroupRule);
+
+ mTableColRule = new TableColRule(this);
+ if (!mTableColRule)
+ return NS_ERROR_OUT_OF_MEMORY;
+ NS_ADDREF(mTableColRule);
+
mTableTHRule = new TableTHRule(this);
if (!mTableTHRule)
return NS_ERROR_OUT_OF_MEMORY;
@@ -750,6 +1022,22 @@ HTMLStyleSheetImpl::~HTMLStyleSheetImpl()
mDocumentColorRule->mSheet = nsnull;
NS_RELEASE(mDocumentColorRule);
}
+ if (nsnull != mTableTbodyRule) {
+ mTableTbodyRule->mSheet = nsnull;
+ NS_RELEASE(mTableTbodyRule);
+ }
+ if (nsnull != mTableRowRule) {
+ mTableRowRule->mSheet = nsnull;
+ NS_RELEASE(mTableRowRule);
+ }
+ if (nsnull != mTableColgroupRule) {
+ mTableColgroupRule->mSheet = nsnull;
+ NS_RELEASE(mTableColgroupRule);
+ }
+ if (nsnull != mTableColRule) {
+ mTableColRule->mSheet = nsnull;
+ NS_RELEASE(mTableColRule);
+ }
if (nsnull != mTableTHRule) {
mTableTHRule->mSheet = nsnull;
NS_RELEASE(mTableTHRule);
@@ -848,6 +1136,18 @@ HTMLStyleSheetImpl::RulesMatching(ElementRuleProcessorData* aData,
else if (tag == nsHTMLAtoms::th) {
ruleWalker->Forward(mTableTHRule);
}
+ else if (tag == nsHTMLAtoms::tr) {
+ ruleWalker->Forward(mTableRowRule);
+ }
+ else if ((tag == nsHTMLAtoms::thead) || (tag == nsHTMLAtoms::tbody) || (tag == nsHTMLAtoms::tfoot)) {
+ ruleWalker->Forward(mTableTbodyRule);
+ }
+ else if (tag == nsHTMLAtoms::col) {
+ ruleWalker->Forward(mTableColRule);
+ }
+ else if (tag == nsHTMLAtoms::colgroup) {
+ ruleWalker->Forward(mTableColgroupRule);
+ }
else if (tag == nsHTMLAtoms::table) {
if (aData->mIsQuirkMode)
ruleWalker->Forward(mDocumentColorRule);
@@ -888,7 +1188,13 @@ NS_IMETHODIMP
HTMLStyleSheetImpl::RulesMatching(PseudoRuleProcessorData* aData,
nsIAtom* aMedium)
{
- // no pseudo frame style
+ nsIAtom* pseudoTag = aData->mPseudoTag;
+ if (pseudoTag == nsHTMLAtoms::tableColPseudo) {
+ nsRuleWalker *ruleWalker = aData->mRuleWalker;
+ if (ruleWalker) {
+ ruleWalker->Forward(mTableColRule);
+ }
+ }
return NS_OK;
}
@@ -1008,6 +1314,11 @@ HTMLStyleSheetImpl::Reset(nsIURI* aURL)
NS_RELEASE(mActiveRule);
}
mDocumentColorRule->Reset();
+
+ mTableTbodyRule->Reset();
+ mTableRowRule->Reset();
+ mTableColgroupRule->Reset();
+ mTableColRule->Reset();
mTableTHRule->Reset();
mMappedAttrTable.Enumerate(MappedDropSheet);
@@ -1264,6 +1575,10 @@ MappedSizeAttributes(nsHashKey *aKey, void *aData, void* closure)
* - mVisitedRule
* - mActiveRule
* - mDocumentColorRule
+* - mTableTbodyRule
+* - mTableRowRule
+* - mTableColgroupRule
+* - mTableColRule
* - mTableTHRule
* - mMappedAttrTable
* 2) Delegates (really) to the MappedAttributes in the mMappedAttrTable
@@ -1298,6 +1613,10 @@ HTMLStyleSheetImpl::SizeOf(nsISizeOfHandler *aSizeOfHandler, PRUint32 &aSize)
// - mVisitedRule : sizeof object
// - mActiveRule : sizeof object
// - mDocumentColorRule : sizeof object
+ // - mTableTbodyRule : sizeof object
+ // - mTableRowRule : sizeof object
+ // - mTableColgroupRule : sizeof object
+ // - mTableColRule : sizeof object
// - mTableTHRule : sizeof object
// - mMappedAttrTable
@@ -1321,6 +1640,26 @@ HTMLStyleSheetImpl::SizeOf(nsISizeOfHandler *aSizeOfHandler, PRUint32 &aSize)
tag = getter_AddRefs(NS_NewAtom("DocumentColorRule"));
aSizeOfHandler->AddSize(tag,localSize);
}
+ if(uniqueItems->AddItem((void*)mTableTbodyRule)){
+ localSize = sizeof(*mTableTbodyRule);
+ tag = getter_AddRefs(NS_NewAtom("TableTbodyRule"));
+ aSizeOfHandler->AddSize(tag,localSize);
+ }
+ if(uniqueItems->AddItem((void*)mTableRowRule)){
+ localSize = sizeof(*mTableRowRule);
+ tag = getter_AddRefs(NS_NewAtom("TableRowRule"));
+ aSizeOfHandler->AddSize(tag,localSize);
+ }
+ if(uniqueItems->AddItem((void*)mTableColgroupRule)){
+ localSize = sizeof(*mTableColgroupRule);
+ tag = getter_AddRefs(NS_NewAtom("TableColgroupRule"));
+ aSizeOfHandler->AddSize(tag,localSize);
+ }
+ if(uniqueItems->AddItem((void*)mTableColRule)){
+ localSize = sizeof(*mTableColRule);
+ tag = getter_AddRefs(NS_NewAtom("TableColRule"));
+ aSizeOfHandler->AddSize(tag,localSize);
+ }
if(uniqueItems->AddItem((void*)mTableTHRule)){
localSize = sizeof(*mTableTHRule);
tag = getter_AddRefs(NS_NewAtom("TableTHRule"));
diff --git a/mozilla/layout/style/nsStyleStruct.cpp b/mozilla/layout/style/nsStyleStruct.cpp
index 79bf6e4e9a9..4efb4816291 100644
--- a/mozilla/layout/style/nsStyleStruct.cpp
+++ b/mozilla/layout/style/nsStyleStruct.cpp
@@ -605,6 +605,28 @@ nsStyleBorder::CalcBorderFor(const nsIFrame* aFrame, nsMargin& aBorder) const
}
}
+void
+nsStyleBorder::CalcBorderFor(const nsIFrame* aFrame, PRUint8 aSide, nscoord& aWidth) const
+{
+ aWidth = 0;
+ // using mCachedBorder as above, doesn't work properly
+ nsStyleCoord coord;
+ switch(aSide) {
+ case NS_SIDE_TOP:
+ coord = mBorder.GetTop(coord);
+ break;
+ case NS_SIDE_RIGHT:
+ coord = mBorder.GetRight(coord);
+ break;
+ case NS_SIDE_BOTTOM:
+ coord = mBorder.GetBottom(coord);
+ break;
+ default: // NS_SIDE_LEFT
+ coord = mBorder.GetLeft(coord);
+ }
+ aWidth = CalcSideFor(aFrame, coord, NS_SPACING_BORDER, aSide, mBorderWidths, 3);
+}
+
nsStyleOutline::nsStyleOutline(nsIPresContext* aPresContext)
{
// XXX support mBorderWidths until deprecated methods are removed
@@ -862,7 +884,7 @@ nsStyleTable::nsStyleTable()
mLayoutStrategy = NS_STYLE_TABLE_LAYOUT_AUTO;
mCols = NS_STYLE_TABLE_COLS_NONE;
mFrame = NS_STYLE_TABLE_FRAME_NONE;
- mRules = NS_STYLE_TABLE_RULES_ALL;
+ mRules = NS_STYLE_TABLE_RULES_NONE;
mSpan = 1;
}
diff --git a/mozilla/layout/style/nsStyleStruct.h b/mozilla/layout/style/nsStyleStruct.h
index 9627f3804b8..2303efea81c 100644
--- a/mozilla/layout/style/nsStyleStruct.h
+++ b/mozilla/layout/style/nsStyleStruct.h
@@ -465,7 +465,8 @@ struct nsStyleBorder: public nsStyleStruct {
// XXX these are deprecated methods
void CalcBorderFor(const nsIFrame* aFrame, nsMargin& aBorder) const;
-
+ void CalcBorderFor(const nsIFrame* aFrame, PRUint8 aSide, nscoord& aWidth) const;
+
protected:
PRPackedBool mHasCachedBorder;
nsMargin mCachedBorder;
diff --git a/mozilla/layout/tables/BasicTableLayoutStrategy.cpp b/mozilla/layout/tables/BasicTableLayoutStrategy.cpp
index 479cc30158f..b79d4379a67 100644
--- a/mozilla/layout/tables/BasicTableLayoutStrategy.cpp
+++ b/mozilla/layout/tables/BasicTableLayoutStrategy.cpp
@@ -139,7 +139,7 @@ PRBool BasicTableLayoutStrategy::Initialize(nsIPresContext* aPresContex
nscoord minWidth, prefWidth;
mTableFrame->CalcMinAndPreferredWidths(aPresContext, aReflowState, PR_FALSE, minWidth, prefWidth);
if (hasPctCol && mTableFrame->IsAutoWidth()) {
- prefWidth = CalcPctAdjTableWidth(aReflowState, boxWidth, p2t);
+ prefWidth = CalcPctAdjTableWidth(*aPresContext, aReflowState, boxWidth, p2t);
}
// calc the desired width, considering if there is a specified width.
// don't use nsTableFrame::CalcDesiredWidth because it is based on table column widths.
@@ -195,7 +195,7 @@ ResetPctValues(nsTableFrame* aTableFrame,
// initialize the col percent and cell percent values to 0.
PRInt32 colX;
for (colX = 0; colX < aNumCols; colX++) {
- nsTableColFrame* colFrame = aTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = aTableFrame->GetColFrame(colX); if (!colFrame) ABORT0();
if (colFrame) {
colFrame->SetWidth(PCT, WIDTH_NOT_SET);
colFrame->SetWidth(PCT_ADJ, WIDTH_NOT_SET);
@@ -207,6 +207,7 @@ PRBool
BasicTableLayoutStrategy::BalanceColumnWidths(nsIPresContext* aPresContext,
const nsHTMLReflowState& aReflowState)
{
+ if (!aPresContext) ABORT1(PR_FALSE);
#ifdef DEBUG_TABLE_STRATEGY
printf("BalanceColumnWidths en count=%d \n", gsDebugCount++); mTableFrame->Dump(aPresContext, PR_FALSE, PR_TRUE, PR_FALSE);
#endif
@@ -220,8 +221,16 @@ BasicTableLayoutStrategy::BalanceColumnWidths(nsIPresContext* aPresCont
PRInt32 numCols = mTableFrame->GetColCount();
PRBool tableIsAutoWidth = mTableFrame->IsAutoWidth();
- nscoord horBorderPadding = aReflowState.mComputedBorderPadding.left +
- aReflowState.mComputedBorderPadding.right;
+
+ nscoord horOffset;
+ // get the reduction in available horizontal space due to borders and padding
+ if (mTableFrame->IsBorderCollapse()) {
+ nsMargin offset = mTableFrame->GetChildAreaOffset(*aPresContext, &aReflowState);
+ horOffset = offset.left + offset.right;
+ }
+ else {
+ horOffset = aReflowState.mComputedBorderPadding.left + aReflowState.mComputedBorderPadding.right;
+ }
// determine if the table is auto/fixed and get the fixed width if available
nscoord maxWidth = mTableFrame->CalcBorderBoxWidth(aPresContext, aReflowState);
@@ -238,19 +247,19 @@ BasicTableLayoutStrategy::BalanceColumnWidths(nsIPresContext* aPresCont
// An auto table returns a new table width based on percent cells/cols if they exist
nscoord perAdjTableWidth = 0;
if (mTableFrame->HasPctCol()) {
- perAdjTableWidth = AssignPctColumnWidths(aReflowState, maxWidth, tableIsAutoWidth, p2t);
+ perAdjTableWidth = AssignPctColumnWidths(*aPresContext, aReflowState, maxWidth, tableIsAutoWidth, p2t);
if (perAdjTableWidth > 0) {
// if an auto table has a pct col or cell, set the preferred table width
// here so that CalcPctAdjTableWidth wont't need to be called by the table
mTableFrame->SetPreferredWidth(perAdjTableWidth);
}
perAdjTableWidth = PR_MIN(perAdjTableWidth, maxWidth);
- perAdjTableWidth -= horBorderPadding;
+ perAdjTableWidth -= horOffset;
perAdjTableWidth = PR_MAX(perAdjTableWidth, 0);
}
// reduce the maxWidth by border and padding, since we will be dealing with content width
- maxWidth -= horBorderPadding;
+ maxWidth -= horOffset;
maxWidth = PR_MAX(0, maxWidth);
PRInt32 numNonZeroWidthCols = 0;
@@ -258,7 +267,7 @@ BasicTableLayoutStrategy::BalanceColumnWidths(nsIPresContext* aPresCont
nscoord minTableWidth = 0;
PRInt32 colX;
for (colX = 0; colX < numCols; colX++) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) ABORT1(PR_FALSE);
if (!colFrame) continue;
nscoord colMinWidth = colFrame->GetMinWidth();
mTableFrame->SetColumnWidth(colX, colMinWidth);
@@ -400,7 +409,7 @@ void BasicTableLayoutStrategy::AllocateFully(nscoord& aTotalAllocated,
{
PRInt32 numCols = mTableFrame->GetColCount();
for (PRInt32 colX = 0; colX < numCols; colX++) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) ABORT0();
if (!colFrame) continue;
if (!CanAllocate(aWidthType, aAllocTypes[colX], colFrame)) {
continue;
@@ -454,7 +463,7 @@ void BasicTableLayoutStrategy::AllocateUnconstrained(PRInt32 aAllocAmount,
}
else {
if (aExclude0Pro) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) ABORT0();
if (colFrame->GetConstraint() == e0ProportionConstraint) {
aAllocTypes[colX] = FINISHED;
}
@@ -467,7 +476,7 @@ void BasicTableLayoutStrategy::AllocateUnconstrained(PRInt32 aAllocAmount,
PRInt32 numColsAllocated = 0;
PRInt32 totalAllocated = 0;
for (colX = 0; colX < numCols; colX++) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) ABORT0();
PRBool skipColumn = aExclude0Pro && (e0ProportionConstraint == colFrame->GetConstraint());
if (FINISHED != aAllocTypes[colX] && !skipColumn ) {
divisor += mTableFrame->GetColumnWidth(colX);
@@ -477,7 +486,7 @@ void BasicTableLayoutStrategy::AllocateUnconstrained(PRInt32 aAllocAmount,
for (colX = 0; colX < numCols; colX++) {
if (FINISHED != aAllocTypes[colX]) {
if (aExclude0Pro) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) ABORT0();
if (colFrame && (e0ProportionConstraint == colFrame->GetConstraint())) {
continue;
}
@@ -533,7 +542,7 @@ BasicTableLayoutStrategy::ComputeNonPctColspanWidths(const nsHTMLReflowState& aR
PRInt32 colX;
for (colX = numCols - 1; colX >= 0; colX--) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) ABORT0();
if (!colFrame) continue;
colFrame->SetWidth(MIN_ADJ, WIDTH_NOT_SET);
colFrame->SetWidth(FIX_ADJ, WIDTH_NOT_SET);
@@ -698,7 +707,7 @@ BasicTableLayoutStrategy::ComputeNonPctColspanWidths(PRInt32 aWidthInd
PRInt32 spanX;
// accumulate the various divisors to be used later
for (spanX = 0; spanX < aColSpan; spanX++) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(aColIndex + spanX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(aColIndex + spanX); if (!colFrame) ABORT1(PR_FALSE);
if (!colFrame) continue;
nscoord minWidth = PR_MAX(colFrame->GetMinWidth(), 0);
nscoord pctWidth = PR_MAX(colFrame->GetPctWidth(), 0);
@@ -802,7 +811,7 @@ BasicTableLayoutStrategy::ComputeNonPctColspanWidths(PRInt32 aWidthInd
// get the correct numerator in a similar fashion to getting the divisor
for (spanX = 0; spanX < aColSpan; spanX++) {
if (usedWidth >= availWidth) break;
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(aColIndex + spanX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(aColIndex + spanX); if (!colFrame) ABORT1(PR_FALSE);
if (!colFrame) continue;
nscoord minWidth = colFrame->GetMinWidth();
nscoord pctWidth = PR_MAX(colFrame->GetPctWidth(), 0);
@@ -974,7 +983,7 @@ BasicTableLayoutStrategy::AssignNonPctColumnWidths(nsIPresContext* aPre
nscoord fixWidth = WIDTH_NOT_SET;
// Get column frame and reset it
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) ABORT1(PR_FALSE);
if (!colFrame) continue;
NS_ASSERTION(nsnull != colFrame, "bad col frame");
colFrame->ResetSizingInfo();
@@ -1079,7 +1088,7 @@ BasicTableLayoutStrategy::AssignNonPctColumnWidths(nsIPresContext* aPre
}
//set the table col fixed width if present
for (colX = 0; colX < numCols; colX++) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) ABORT1(PR_FALSE);
if (!colFrame) continue;
nscoord fixColWidth = colFrame->GetWidth(FIX);
// use the style width of a col only if the col hasn't gotten a fixed width from any cell
@@ -1140,7 +1149,7 @@ BasicTableLayoutStrategy::AssignNonPctColumnWidths(nsIPresContext* aPre
// Set the table col width for each col to the content min.
for (colX = 0; colX < numCols; colX++) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) ABORT1(PR_FALSE);
nscoord minWidth = colFrame->GetMinWidth();
mTableFrame->SetColumnWidth(colX, minWidth);
}
@@ -1159,7 +1168,7 @@ BasicTableLayoutStrategy::ReduceOverSpecifiedPctCols(nscoord aExcess)
{
nscoord numCols = mTableFrame->GetColCount();
for (PRInt32 colX = numCols - 1; (colX >= 0) && (aExcess > 0); colX--) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) ABORT0();
if (!colFrame) continue;
nscoord pctWidth = colFrame->GetWidth(PCT);
nscoord reduction = 0;
@@ -1198,7 +1207,8 @@ inline nscoord WrapupAssignPctColumnWidths(nsTableFrame* aTableFrame,
#endif
nscoord
-BasicTableLayoutStrategy::CalcPctAdjTableWidth(const nsHTMLReflowState& aReflowState,
+BasicTableLayoutStrategy::CalcPctAdjTableWidth(nsIPresContext& aPresContext,
+ const nsHTMLReflowState& aReflowState,
nscoord aAvailWidthIn,
float aPixelToTwips)
{
@@ -1219,7 +1229,7 @@ BasicTableLayoutStrategy::CalcPctAdjTableWidth(const nsHTMLReflowState& aReflowS
rawPctValues[colX] = 0.0f;
}
- nsMargin borderPadding = mTableFrame->GetBorderPadding(aReflowState);
+ nsMargin borderPadding = mTableFrame->GetContentAreaOffset(aPresContext, &aReflowState);
nscoord availWidth = aAvailWidthIn;
if (NS_UNCONSTRAINEDSIZE != availWidth) {
// adjust the avail width to exclude table border, padding and cell spacing
@@ -1227,7 +1237,7 @@ BasicTableLayoutStrategy::CalcPctAdjTableWidth(const nsHTMLReflowState& aReflowS
}
for (colX = 0; colX < numCols; colX++) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) ABORT1(0);
if (!colFrame) continue;
nscoord maxColBasis = -1;
// Scan the cells in the col
@@ -1282,7 +1292,7 @@ BasicTableLayoutStrategy::CalcPctAdjTableWidth(const nsHTMLReflowState& aReflowS
nscoord fixDesTotalNoPct = 0; // total of fix or des widths of cols without pct
for (colX = 0; colX < numCols; colX++) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) ABORT1(0);
nscoord fixWidth = colFrame->GetFixWidth();
nscoord fixDesWidth = (fixWidth > 0) ? fixWidth : colFrame->GetDesWidth();
fixDesTotal += fixDesWidth;
@@ -1329,7 +1339,8 @@ BasicTableLayoutStrategy::CalcPctAdjTableWidth(const nsHTMLReflowState& aReflowS
// Determine percentage col widths for each col frame
nscoord
-BasicTableLayoutStrategy::AssignPctColumnWidths(const nsHTMLReflowState& aReflowState,
+BasicTableLayoutStrategy::AssignPctColumnWidths(nsIPresContext& aPresContext,
+ const nsHTMLReflowState& aReflowState,
nscoord aAvailWidth,
PRBool aTableIsAutoWidth,
float aPixelToTwips)
@@ -1349,11 +1360,11 @@ BasicTableLayoutStrategy::AssignPctColumnWidths(const nsHTMLReflowState& aReflow
// on percent cells/cols. This probably should only be a NavQuirks thing, since
// a percentage based cell or column on an auto table should force the column to auto
nscoord basis = (aTableIsAutoWidth)
- ? CalcPctAdjTableWidth(aReflowState, aAvailWidth, aPixelToTwips)
+ ? CalcPctAdjTableWidth(aPresContext, aReflowState, aAvailWidth, aPixelToTwips)
: aAvailWidth;
// adjust the basis to exclude table border, padding and cell spacing
- nsMargin borderPadding = mTableFrame->GetBorderPadding(aReflowState);
+ nsMargin borderPadding = mTableFrame->GetContentAreaOffset(aPresContext, &aReflowState);
basis -= borderPadding.left + borderPadding.right + mCellSpacingTotal;
nscoord colPctTotal = 0;
@@ -1361,7 +1372,7 @@ BasicTableLayoutStrategy::AssignPctColumnWidths(const nsHTMLReflowState& aReflow
// Determine the percentage contribution for cols and for cells with colspan = 1
// Iterate backwards, similarly to the reasoning in AssignNonPctColumnWidths
for (colX = numCols - 1; colX >= 0; colX--) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) ABORT1(0);
if (!colFrame) continue;
nscoord maxColPctWidth = WIDTH_NOT_SET;
float maxColPct = 0.0f;
@@ -1431,7 +1442,7 @@ BasicTableLayoutStrategy::AssignPctColumnWidths(const nsHTMLReflowState& aReflow
}
// determine if the cell spans cols which have a pct value
for (PRInt32 spanX = 0; (spanX < colSpan) && !done; spanX++) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX + spanX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX + spanX); if (!colFrame) ABORT1(0);
if (!colFrame) continue;
if (colFrame->GetWidth(PCT) > 0) {
mTableFrame->SetHasCellSpanningPctCol(PR_TRUE);
@@ -1511,7 +1522,7 @@ BasicTableLayoutStrategy::AssignPctColumnWidths(const nsHTMLReflowState& aReflow
// accumulate the spanTotal as the max of MIN, DES, FIX, PCT
PRInt32 spanX;
for (spanX = 0; spanX < colSpan; spanX++) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX + spanX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX + spanX); if (!colFrame) ABORT1(0);
if (!colFrame) continue;
nscoord colPctWidth = colFrame->GetWidth(PCT);
if (colPctWidth > 0) { // skip pct cols
@@ -1546,7 +1557,7 @@ BasicTableLayoutStrategy::AssignPctColumnWidths(const nsHTMLReflowState& aReflow
// record the percent contributions for the spanned cols
PRInt32 usedColumns = colSpan;
for (spanX = colSpan-1; spanX >= 0; spanX--) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX + spanX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX + spanX); if (!colFrame) ABORT1(0);
if (!colFrame) continue;
if ((colFrame->GetWidth(PCT) > 0) || (canSkipPctAdj && (colFrame->GetWidth(PCT_ADJ) > 0))) {
// dont use pct cols or if we can skip the pct adj event do not take the PCT_ADJ cols
@@ -1621,7 +1632,7 @@ void BasicTableLayoutStrategy::CalculateTotals(PRInt32* aTotalCounts,
PRInt32 colX;
for (colX = 0; colX < numEffCols; colX++) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) ABORT0();
if (!colFrame) continue;
nscoord minCol = colFrame->GetMinWidth();
aTotalCounts[MIN_CON]++;
@@ -1820,7 +1831,7 @@ void BasicTableLayoutStrategy::AllocateConstrained(PRInt32 aAvailWidth,
PRInt32 colX;
// find out how many constrained cols there are
for (colX = 0; colX < numCols; colX++) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) ABORT0();
if (!colFrame) continue;
if (!CanAllocate(aWidthType, aAllocTypes[colX], colFrame)) {
continue;
@@ -1837,7 +1848,7 @@ void BasicTableLayoutStrategy::AllocateConstrained(PRInt32 aAvailWidth,
PRInt32 constrColX = 0;
// set the col info entries for each constrained col
for (colX = 0; colX < numCols; colX++) {
- nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX);
+ nsTableColFrame* colFrame = mTableFrame->GetColFrame(colX); if (!colFrame) ABORT0();
if (!colFrame) continue;
if (!CanAllocate(aWidthType, aAllocTypes[colX], colFrame)) {
continue;
diff --git a/mozilla/layout/tables/BasicTableLayoutStrategy.h b/mozilla/layout/tables/BasicTableLayoutStrategy.h
index 793b8b79d40..69883aabd2c 100644
--- a/mozilla/layout/tables/BasicTableLayoutStrategy.h
+++ b/mozilla/layout/tables/BasicTableLayoutStrategy.h
@@ -93,7 +93,8 @@ public:
* @param aPixelToTwips - the number of twips in a pixel.
* @return - the basis for percent calculations
*/
- virtual nscoord CalcPctAdjTableWidth(const nsHTMLReflowState& aReflowState,
+ virtual nscoord CalcPctAdjTableWidth(nsIPresContext& aPresContext,
+ const nsHTMLReflowState& aReflowState,
nscoord aAvailWidth,
float aPixelToTwips);
void Dump(PRInt32 aIndent);
@@ -159,7 +160,8 @@ protected:
* @param aPixelToTwips - the number of twips in a pixel.
* @return - the adjusted basis including table border, padding and cell spacing
*/
- nscoord AssignPctColumnWidths(const nsHTMLReflowState& aReflowState,
+ nscoord AssignPctColumnWidths(nsIPresContext& aPresContext,
+ const nsHTMLReflowState& aReflowState,
nscoord aBasis,
PRBool aTableIsAutoWidth,
float aPixelToTwips);
diff --git a/mozilla/layout/tables/celldata.h b/mozilla/layout/tables/celldata.h
index cf977be70d6..b281df0e2e2 100644
--- a/mozilla/layout/tables/celldata.h
+++ b/mozilla/layout/tables/celldata.h
@@ -38,6 +38,7 @@
#define CellData_h__
#include "nsISupports.h"
+#include "nsCoord.h"
class nsTableCellFrame;
@@ -51,8 +52,9 @@ public:
~CellData();
+ void Init(nsTableCellFrame* aCellFrame);
PRBool IsOrig() const;
-
+ PRBool IsDead() const;
PRBool IsSpan() const;
PRBool IsRowSpan() const;
@@ -84,6 +86,93 @@ protected:
};
};
+// 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
+};
+
+// 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 64
+#define MAX_CORNER_SUB_WIDTH 128
+
+// BCData stores the top and left border info and the corner connecting the two.
+class BCData
+{
+public:
+ BCData();
+
+ ~BCData();
+
+ nscoord GetLeftEdge(BCBorderOwner& aOwner,
+ PRBool& aStart) const;
+
+ void SetLeftEdge(BCBorderOwner aOwner,
+ nscoord aSize,
+ PRBool aStart);
+
+ nscoord GetTopEdge(BCBorderOwner& aOwner,
+ PRBool& aStart) const;
+
+ void SetTopEdge(BCBorderOwner aOwner,
+ nscoord aSize,
+ PRBool aStart);
+
+ PRUint8 GetCorner(PRUint8& aCornerOwner,
+ PRPackedBool& aBevel) const;
+
+ void SetCorner(PRUint8 aOwner,
+ PRUint8 aSubSize,
+ PRBool aBevel);
+
+ PRBool IsLeftStart() const;
+
+ void SetLeftStart(PRBool aValue);
+
+ PRBool IsTopStart() const;
+
+ void SetTopStart(PRBool aValue);
+
+
+protected:
+ unsigned mLeftOwner: 4; // owner of left border
+ unsigned mLeftSize: 6; // size in pixels of left border
+ unsigned mLeftStart: 1; // set if this is the start of a vertical border segment
+ unsigned mCornerSide: 2; // side of the owner of the upper left corner relative to the corner
+ unsigned mCornerSubSize: 7; // size of the largest border not in the dominate 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 mCornerBevel: 1; // is the corner beveled (only two segments, perpendicular, not dashed or dotted).
+ unsigned mTopOwner: 4; // owner of top border
+ unsigned mTopSize: 6; // size in pixels of top border
+ unsigned mTopStart: 1; // set if this is the start of a horizontal border segment
+};
+
+// 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;
+};
+
+
#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
@@ -103,9 +192,19 @@ inline nsTableCellFrame* CellData::GetCellFrame() const
return nsnull;
}
+inline void CellData::Init(nsTableCellFrame* aCellFrame)
+{
+ mOrigCell = aCellFrame;
+}
+
inline PRBool CellData::IsOrig() const
{
- return (SPAN != (SPAN & mBits));
+ return ((nsnull != mOrigCell) && (SPAN != (SPAN & mBits)));
+}
+
+inline PRBool CellData::IsDead() const
+{
+ return (0 == mBits);
}
inline PRBool CellData::IsSpan() const
@@ -213,4 +312,88 @@ inline void CellData::SetOverlap(PRBool aOverlap)
}
}
+inline BCData::BCData()
+{
+ mLeftOwner = mTopOwner = eCellOwner;
+ mLeftStart = mTopStart = 1;
+ mLeftSize = mCornerSide = mCornerSubSize = mTopSize = 0;
+}
+
+inline BCData::~BCData()
+{
+}
+
+inline nscoord BCData::GetLeftEdge(BCBorderOwner& aOwner,
+ PRBool& aStart) const
+{
+ aOwner = (BCBorderOwner)mLeftOwner;
+ aStart = (PRBool)mLeftStart;
+
+ return (nscoord)mLeftSize;
+}
+
+inline void BCData::SetLeftEdge(BCBorderOwner aOwner,
+ nscoord aSize,
+ PRBool aStart)
+{
+ mLeftOwner = aOwner;
+ mLeftSize = (aSize > MAX_BORDER_WIDTH) ? MAX_BORDER_WIDTH : aSize;
+ mLeftStart = aStart;
+}
+
+inline nscoord BCData::GetTopEdge(BCBorderOwner& aOwner,
+ PRBool& aStart) const
+{
+ aOwner = (BCBorderOwner)mTopOwner;
+ aStart = (PRBool)mTopStart;
+
+ return (nscoord)mTopSize;
+}
+
+inline void BCData::SetTopEdge(BCBorderOwner aOwner,
+ nscoord aSize,
+ PRBool aStart)
+{
+ mTopOwner = aOwner;
+ mTopSize = (aSize > MAX_BORDER_WIDTH) ? MAX_BORDER_WIDTH : aSize;
+ mTopStart = aStart;
+}
+
+inline PRUint8 BCData::GetCorner(PRUint8& aOwnerSide,
+ PRPackedBool& aBevel) const
+{
+ aOwnerSide = mCornerSide;
+ aBevel = (PRBool)mCornerBevel;
+ return (PRUint8)mCornerSubSize;
+}
+
+inline void BCData::SetCorner(PRUint8 aSubSize,
+ PRUint8 aOwnerSide,
+ PRBool aBevel)
+{
+ mCornerSubSize = (aSubSize > MAX_CORNER_SUB_WIDTH) ? MAX_CORNER_SUB_WIDTH : aSubSize;
+ mCornerSide = aOwnerSide;
+ mCornerBevel = aBevel;
+}
+
+inline PRBool BCData::IsLeftStart() const
+{
+ return (PRBool)mLeftStart;
+}
+
+inline void BCData::SetLeftStart(PRBool aValue)
+{
+ mLeftStart = aValue;
+}
+
+inline PRBool BCData::IsTopStart() const
+{
+ return (PRBool)mTopStart;
+}
+
+inline void BCData::SetTopStart(PRBool aValue)
+{
+ mTopStart = aValue;
+}
+
#endif
diff --git a/mozilla/layout/tables/nsCellMap.cpp b/mozilla/layout/tables/nsCellMap.cpp
index 167268997e0..3b6a835cfe8 100644
--- a/mozilla/layout/tables/nsCellMap.cpp
+++ b/mozilla/layout/tables/nsCellMap.cpp
@@ -60,12 +60,25 @@ CellData::~CellData()
MOZ_COUNT_DTOR(CellData);
}
+BCCellData::BCCellData(nsTableCellFrame* aOrigCell)
+:CellData(aOrigCell)
+{
+ MOZ_COUNT_CTOR(BCCellData);
+}
+
+BCCellData::~BCCellData()
+{
+ MOZ_COUNT_DTOR(BCCellData);
+}
+
MOZ_DECL_CTOR_COUNTER(nsCellMap)
// nsTableCellMap
-nsTableCellMap::nsTableCellMap(nsIPresContext* aPresContext, nsTableFrame& aTableFrame)
-:mTableFrame(aTableFrame), mFirstMap(nsnull)
+nsTableCellMap::nsTableCellMap(nsIPresContext* aPresContext,
+ nsTableFrame& aTableFrame,
+ PRBool aBorderCollapse)
+:mTableFrame(aTableFrame), mFirstMap(nsnull), mBCInfo(nsnull)
{
MOZ_COUNT_CTOR(nsTableCellMap);
@@ -83,11 +96,17 @@ nsTableCellMap::nsTableCellMap(nsIPresContext* aPresContext, nsTableFrame& aTabl
InsertGroupCellMap(*rgFrame, prior);
}
}
+ if (aBorderCollapse) {
+ mBCInfo = new BCInfo();
+ }
}
nsTableCellMap::~nsTableCellMap()
{
MOZ_COUNT_DTOR(nsTableCellMap);
+
+ PRInt32 rowCount = GetRowCount();
+
nsCellMap* cellMap = mFirstMap;
while (cellMap) {
nsCellMap* next = cellMap->GetNextSibling();
@@ -95,15 +114,89 @@ nsTableCellMap::~nsTableCellMap()
cellMap = next;
}
- PRInt32 colCount = mCols.Count();
+ PRInt32 colCount = mCols.Count();
for (PRInt32 colX = 0; colX < colCount; colX++) {
nsColInfo* colInfo = (nsColInfo *)mCols.ElementAt(colX);
if (colInfo) {
delete colInfo;
}
}
+ if (mBCInfo) {
+ DeleteRightBottomBorders();
+ delete mBCInfo;
+ }
}
+// Get the bcData holding the border segments of the right edge of the table
+BCData*
+nsTableCellMap::GetRightMostBorder(PRInt32 aRowIndex)
+{
+ if (!mBCInfo) ABORT1(nsnull);
+
+ BCData* bcData;
+
+ PRInt32 numRows = mBCInfo->mRightBorders.Count();
+ if (aRowIndex < numRows) {
+ bcData = (BCData*)mBCInfo->mRightBorders.ElementAt(aRowIndex);
+ }
+ else {
+ for (PRInt32 rowX = numRows; rowX <= aRowIndex; rowX++) {
+ bcData = new BCData(); if (!bcData) ABORT1(nsnull);
+ mBCInfo->mRightBorders.AppendElement(bcData);
+ }
+ }
+ return bcData;
+}
+
+// Get the bcData holding the border segments of the bottom edge of the table
+BCData*
+nsTableCellMap::GetBottomMostBorder(PRInt32 aColIndex)
+{
+ if (!mBCInfo) ABORT1(nsnull);
+
+ BCData* bcData;
+
+ PRInt32 numCols = mBCInfo->mBottomBorders.Count();
+ if (aColIndex < numCols) {
+ bcData = (BCData*)mBCInfo->mBottomBorders.ElementAt(aColIndex);
+ }
+ else {
+ for (PRInt32 colX = numCols; colX <= aColIndex; colX++) {
+ bcData = new BCData(); if (!bcData) ABORT1(nsnull);
+ mBCInfo->mBottomBorders.AppendElement(bcData);
+ }
+ }
+ return bcData;
+}
+
+// delete the borders corresponding to the right and bottom edges of the table
+void
+nsTableCellMap::DeleteRightBottomBorders()
+{
+ if (mBCInfo) {
+ PRInt32 numCols = mBCInfo->mBottomBorders.Count();
+ if (numCols > 0) {
+ for (PRInt32 colX = numCols - 1; colX >= 0; colX--) {
+ BCData* bcData = (BCData*)mBCInfo->mBottomBorders.ElementAt(colX);
+ if (bcData) {
+ delete bcData;
+ }
+ mBCInfo->mBottomBorders.RemoveElementAt(colX);
+ }
+ }
+ PRUint32 numRows = mBCInfo->mRightBorders.Count();
+ if (numRows > 0) {
+ for (PRInt32 rowX = numRows - 1; rowX >= 0; rowX--) {
+ BCData* bcData = (BCData*)mBCInfo->mRightBorders.ElementAt(rowX);
+ if (bcData) {
+ delete bcData;
+ }
+ mBCInfo->mRightBorders.RemoveElementAt(rowX);
+ }
+ }
+ }
+}
+
void
nsTableCellMap::InsertGroupCellMap(nsCellMap* aPrevMap,
nsCellMap& aNewMap)
@@ -126,9 +219,11 @@ void nsTableCellMap::InsertGroupCellMap(nsTableRowGroupFrame& aNewGroup,
nsCellMap* newMap = new nsCellMap(aNewGroup);
if (newMap) {
nsCellMap* prevMap = nsnull;
+ nsCellMap* lastMap = mFirstMap;
if (aPrevGroup) {
nsCellMap* map = mFirstMap;
while (map) {
+ lastMap = map;
if (map->GetRowGroup() == aPrevGroup) {
prevMap = map;
break;
@@ -137,7 +232,13 @@ void nsTableCellMap::InsertGroupCellMap(nsTableRowGroupFrame& aNewGroup,
}
}
if (!prevMap) {
- aPrevGroup = nsnull;
+ if (aPrevGroup) {
+ prevMap = lastMap;
+ aPrevGroup = (prevMap) ? prevMap->GetRowGroup() : nsnull;
+ }
+ else {
+ aPrevGroup = nsnull;
+ }
}
InsertGroupCellMap(prevMap, *newMap);
}
@@ -164,6 +265,16 @@ void nsTableCellMap::RemoveGroupCellMap(nsTableRowGroupFrame* aGroup)
}
}
+nsCellMap*
+nsTableCellMap::GetMapFor(nsTableRowGroupFrame& aRowGroup)
+{
+ for (nsCellMap* map = mFirstMap; map; map = map->GetNextSibling()) {
+ if (&aRowGroup == map->GetRowGroup()) {
+ return map;
+ }
+ }
+ return nsnull;
+}
PRInt32
@@ -241,14 +352,15 @@ nsTableCellMap::GetRowCount() const
}
CellData*
-nsTableCellMap::GetCellAt(PRInt32 aRowIndex,
- PRInt32 aColIndex)
+nsTableCellMap::GetDataAt(PRInt32 aRowIndex,
+ PRInt32 aColIndex,
+ PRBool aUpdateZeroSpan)
{
PRInt32 rowIndex = aRowIndex;
nsCellMap* map = mFirstMap;
while (map) {
if (map->GetRowCount() > rowIndex) {
- return map->GetCellAt(*this, rowIndex, aColIndex);
+ return map->GetDataAt(*this, rowIndex, aColIndex, aUpdateZeroSpan);
}
rowIndex -= map->GetRowCount();
map = map->GetNextSibling();
@@ -268,6 +380,12 @@ nsTableCellMap::AddColsAtEnd(PRUint32 aNumCols)
if (colInfo) {
mCols.AppendElement(colInfo);
}
+ if (mBCInfo) {
+ BCData* bcData = new BCData();
+ if (bcData) {
+ mBCInfo->mBottomBorders.AppendElement(bcData);
+ }
+ }
}
}
@@ -283,6 +401,16 @@ nsTableCellMap::RemoveColsAtEnd()
if (colInfo) {
if ((colInfo->mNumCellsOrig <= 0) && (colInfo->mNumCellsSpan <= 0)) {
mCols.RemoveElementAt(colX);
+ if (mBCInfo) {
+ PRInt32 count = mBCInfo->mBottomBorders.Count();
+ if (colX < count) {
+ BCData* bcData = (BCData*)mBCInfo->mBottomBorders.ElementAt(colX);
+ if (bcData) {
+ delete bcData;
+ }
+ mBCInfo->mBottomBorders.RemoveElementAt(colX);
+ }
+ }
}
else break; // only remove until we encounter the 1st valid one
}
@@ -298,21 +426,44 @@ nsTableCellMap::InsertRows(nsIPresContext* aPresContext,
nsTableRowGroupFrame& aParent,
nsVoidArray& aRows,
PRInt32 aFirstRowIndex,
- PRBool aConsiderSpans)
+ PRBool aConsiderSpans,
+ nsRect& aDamageArea)
{
- NS_ASSERTION((aRows.Count() > 0) && (aFirstRowIndex >= 0), "nsTableCellMap::InsertRows called incorrectly");
+ PRInt32 numNewRows = aRows.Count();
+ if ((numNewRows <= 0) || (aFirstRowIndex < 0)) ABORT0();
+
PRInt32 rowIndex = aFirstRowIndex;
nsCellMap* cellMap = mFirstMap;
while (cellMap) {
- if (cellMap->GetRowGroup() == &aParent) {
- cellMap->InsertRows(aPresContext, *this, aRows, rowIndex, aConsiderSpans);
+ nsTableRowGroupFrame* rg = cellMap->GetRowGroup();
+ if (rg == &aParent) {
+ cellMap->InsertRows(aPresContext, *this, aRows, rowIndex, aConsiderSpans, aDamageArea);
+ aDamageArea.y = aFirstRowIndex;
+ aDamageArea.height = PR_MAX(0, GetRowCount() - aFirstRowIndex);
//Dump("after InsertRows");
+ if (mBCInfo) {
+ BCData* bcData;
+ PRInt32 count = mBCInfo->mRightBorders.Count();
+ if (aFirstRowIndex < count) {
+ for (PRInt32 rowX = aFirstRowIndex; rowX < aFirstRowIndex + numNewRows; rowX++) {
+ bcData = new BCData(); if (!bcData) ABORT0();
+ mBCInfo->mRightBorders.InsertElementAt(bcData, rowX);
+ }
+ }
+ else {
+ GetRightMostBorder(aFirstRowIndex); // this will create missing entries
+ for (PRInt32 rowX = aFirstRowIndex + 1; rowX < aFirstRowIndex + numNewRows; rowX++) {
+ bcData = new BCData(); if (!bcData) ABORT0();
+ mBCInfo->mRightBorders.AppendElement(bcData);
+ }
+ }
+ }
return;
}
rowIndex -= cellMap->GetRowCount();
cellMap = cellMap->GetNextSibling();
}
-
+
NS_ASSERTION(PR_FALSE, "Attempt to insert row into wrong map.");
}
@@ -320,13 +471,29 @@ void
nsTableCellMap::RemoveRows(nsIPresContext* aPresContext,
PRInt32 aFirstRowIndex,
PRInt32 aNumRowsToRemove,
- PRBool aConsiderSpans)
+ PRBool aConsiderSpans,
+ nsRect& aDamageArea)
{
PRInt32 rowIndex = aFirstRowIndex;
nsCellMap* cellMap = mFirstMap;
while (cellMap) {
if (cellMap->GetRowCount() > rowIndex) {
- cellMap->RemoveRows(aPresContext, *this, rowIndex, aNumRowsToRemove, aConsiderSpans);
+ cellMap->RemoveRows(aPresContext, *this, rowIndex, aNumRowsToRemove, aConsiderSpans, aDamageArea);
+ nsTableRowGroupFrame* rg = cellMap->GetRowGroup();
+ aDamageArea.y += (rg) ? rg->GetStartRowIndex() : 0;
+ aDamageArea.height = PR_MAX(0, GetRowCount() - aFirstRowIndex);
+ if (mBCInfo) {
+ BCData* bcData;
+ for (PRInt32 rowX = aFirstRowIndex + aNumRowsToRemove - 1; rowX >= aFirstRowIndex; rowX--) {
+ if (rowX < mBCInfo->mRightBorders.Count()) {
+ bcData = (BCData*)mBCInfo->mRightBorders.ElementAt(rowX);
+ if (bcData) {
+ delete bcData;
+ }
+ mBCInfo->mRightBorders.RemoveElementAt(rowX);
+ }
+ }
+ }
break;
}
rowIndex -= cellMap->GetRowCount();
@@ -344,7 +511,7 @@ nsTableCellMap::GetNumCellsOriginatingInRow(PRInt32 aRowIndex)
PRInt32 colIndex = 0;
do {
- cellData = GetCellAt(aRowIndex, colIndex);
+ cellData = GetDataAt(aRowIndex, colIndex);
if (cellData && cellData->GetCellFrame())
originCount++;
colIndex++;
@@ -353,10 +520,11 @@ nsTableCellMap::GetNumCellsOriginatingInRow(PRInt32 aRowIndex)
return originCount;
}
-PRInt32
+CellData*
nsTableCellMap::AppendCell(nsTableCellFrame& aCellFrame,
PRInt32 aRowIndex,
- PRBool aRebuildIfNecessary)
+ PRBool aRebuildIfNecessary,
+ nsRect& aDamageArea)
{
NS_ASSERTION(&aCellFrame == aCellFrame.GetFirstInFlow(), "invalid call on continuing frame");
nsIFrame* rgFrame = nsnull;
@@ -365,12 +533,14 @@ nsTableCellMap::AppendCell(nsTableCellFrame& aCellFrame,
rgFrame->GetParent(&rgFrame); // get the row group
if (!rgFrame) return 0;
- PRInt32 result = 0;
+ CellData* result = nsnull;
PRInt32 rowIndex = aRowIndex;
nsCellMap* cellMap = mFirstMap;
while (cellMap) {
if (cellMap->GetRowGroup() == rgFrame) {
- result = cellMap->AppendCell(*this, aCellFrame, rowIndex, aRebuildIfNecessary);
+ result = cellMap->AppendCell(*this, &aCellFrame, rowIndex, aRebuildIfNecessary, aDamageArea);
+ nsTableRowGroupFrame* rg = cellMap->GetRowGroup();
+ aDamageArea.y += (rg) ? rg->GetStartRowIndex() : 0;
break;
}
rowIndex -= cellMap->GetRowCount();
@@ -384,13 +554,17 @@ nsTableCellMap::AppendCell(nsTableCellFrame& aCellFrame,
void
nsTableCellMap::InsertCells(nsVoidArray& aCellFrames,
PRInt32 aRowIndex,
- PRInt32 aColIndexBefore)
+ PRInt32 aColIndexBefore,
+ nsRect& aDamageArea)
{
PRInt32 rowIndex = aRowIndex;
nsCellMap* cellMap = mFirstMap;
while (cellMap) {
if (cellMap->GetRowCount() > rowIndex) {
- cellMap->InsertCells(*this, aCellFrames, rowIndex, aColIndexBefore);
+ cellMap->InsertCells(*this, aCellFrames, rowIndex, aColIndexBefore, aDamageArea);
+ nsTableRowGroupFrame* rg = cellMap->GetRowGroup();
+ aDamageArea.y += (rg) ? rg->GetStartRowIndex() : 0;
+ aDamageArea.width = PR_MAX(0, GetColCount() - aColIndexBefore);
break;
}
rowIndex -= cellMap->GetRowCount();
@@ -402,15 +576,22 @@ nsTableCellMap::InsertCells(nsVoidArray& aCellFrames,
void
nsTableCellMap::RemoveCell(nsTableCellFrame* aCellFrame,
- PRInt32 aRowIndex)
+ PRInt32 aRowIndex,
+ nsRect& aDamageArea)
{
+ if (!aCellFrame) ABORT0();
NS_ASSERTION(aCellFrame == (nsTableCellFrame *)aCellFrame->GetFirstInFlow(),
"invalid call on continuing frame");
PRInt32 rowIndex = aRowIndex;
nsCellMap* cellMap = mFirstMap;
while (cellMap) {
if (cellMap->GetRowCount() > rowIndex) {
- cellMap->RemoveCell(*this, aCellFrame, rowIndex);
+ cellMap->RemoveCell(*this, aCellFrame, rowIndex, aDamageArea);
+ nsTableRowGroupFrame* rg = cellMap->GetRowGroup();
+ aDamageArea.y += (rg) ? rg->GetStartRowIndex() : 0;
+ PRInt32 colIndex;
+ aCellFrame->GetColIndex(colIndex);
+ aDamageArea.width = PR_MAX(0, GetColCount() - colIndex);
break;
}
rowIndex -= cellMap->GetRowCount();
@@ -448,7 +629,7 @@ nsTableCellMap::Dump(char* aString) const
}
nsCellMap* cellMap = mFirstMap;
while (cellMap) {
- cellMap->Dump();
+ cellMap->Dump(nsnull != mBCInfo);
cellMap = cellMap->GetNextSibling();
}
printf("***** END TABLE CELL MAP DUMP *****\n");
@@ -525,6 +706,237 @@ PRBool nsTableCellMap::ColHasSpanningCells(PRInt32 aColIndex)
return PR_FALSE;
}
+BCData*
+nsTableCellMap::GetBCData(PRUint8 aSide,
+ nsCellMap& aCellMap,
+ PRUint32 aRowIndex,
+ PRUint32 aColIndex,
+ PRBool aIsLowerRight)
+{
+ if (!mBCInfo || aIsLowerRight) ABORT1(nsnull);
+
+ BCCellData* cellData;
+ BCData* bcData = nsnull;
+
+ switch(aSide) {
+ case NS_SIDE_BOTTOM:
+ aRowIndex++;
+ case NS_SIDE_TOP:
+ cellData = (BCCellData*)aCellMap.GetDataAt(*this, aRowIndex, aColIndex, PR_FALSE);
+ if (cellData) {
+ bcData = &cellData->mData;
+ }
+ else {
+ NS_ASSERTION(aSide == NS_SIDE_BOTTOM, "program error");
+ // try the next row group
+ nsCellMap* cellMap = aCellMap.GetNextSibling();
+ if (cellMap) {
+ cellData = (BCCellData*)cellMap->GetDataAt(*this, aRowIndex, aColIndex, PR_FALSE);
+ if (cellData) {
+ bcData = &cellData->mData;
+ }
+ else {
+ BCData* bcData = GetBottomMostBorder(aColIndex);
+ }
+ }
+ }
+ break;
+ case NS_SIDE_RIGHT:
+ aColIndex++;
+ case NS_SIDE_LEFT:
+ cellData = (BCCellData*)aCellMap.GetDataAt(*this, aRowIndex, aColIndex, PR_FALSE);
+ if (cellData) {
+ bcData = &cellData->mData;
+ }
+ else {
+ NS_ASSERTION(aSide == NS_SIDE_RIGHT, "program error");
+ BCData* bcData = GetRightMostBorder(aRowIndex);
+ }
+ break;
+ }
+ return bcData;
+}
+
+// store the aSide border segment at coord = (aRowIndex, aColIndex). For top/left, store
+// the info at coord. For bottom/left store it at the adjacent location so that it is
+// top/left at that location. If the new location is at the right or bottom edge of the
+// table, then store it one of the special arrays (right most borders, bottom most borders).
+void
+nsTableCellMap::SetBCBorderEdge(PRUint8 aSide,
+ nsCellMap& aCellMap,
+ PRUint32 aCellMapStart,
+ PRUint32 aRowIndex,
+ PRUint32 aColIndex,
+ PRUint32 aLength,
+ BCBorderOwner aOwner,
+ nscoord aSize,
+ PRBool aChanged)
+{
+ if (!mBCInfo) ABORT0();
+ //if (aRowIndex >= 80) {
+ // NS_ASSERTION(PR_FALSE, "hello");
+ //}
+
+ BCCellData* cellData;
+ PRInt32 lastIndex, xIndex, yIndex;
+ PRInt32 xPos = aColIndex;
+ PRInt32 yPos = aRowIndex;
+ PRInt32 rgYPos = aRowIndex - aCellMapStart;
+ PRBool changed;
+
+ switch(aSide) {
+ case NS_SIDE_BOTTOM:
+ rgYPos++;
+ yPos++;
+ case NS_SIDE_TOP:
+ lastIndex = xPos + aLength - 1;
+ for (xIndex = xPos; xIndex <= lastIndex; xIndex++) {
+ changed = aChanged && (xIndex == xPos);
+ BCData* bcData = nsnull;
+ cellData = (BCCellData*)aCellMap.GetDataAt(*this, rgYPos, xIndex, PR_FALSE);
+ if (!cellData) {
+ PRInt32 numRgRows = aCellMap.GetRowCount();
+ if (yPos < numRgRows) { // add a dead cell data
+ nsRect damageArea;
+ cellData = (BCCellData*)aCellMap.AppendCell(*this, nsnull, rgYPos, PR_FALSE, damageArea); if (!cellData) ABORT0();
+ }
+ else {
+ NS_ASSERTION(aSide == NS_SIDE_BOTTOM, "program error");
+ // try the next non empty row group
+ nsCellMap* cellMap = aCellMap.GetNextSibling();
+ while (cellMap && (0 == cellMap->GetRowCount())) {
+ cellMap = cellMap->GetNextSibling();
+ }
+ if (cellMap) {
+ cellData = (BCCellData*)cellMap->GetDataAt(*this, 0, xIndex, PR_FALSE);
+ if (!cellData) { // add a dead cell
+ nsRect damageArea;
+ cellData = (BCCellData*)cellMap->AppendCell(*this, nsnull, 0, PR_FALSE, damageArea);
+ }
+ }
+ else { // must be at the end of the table
+ bcData = GetBottomMostBorder(xIndex);
+ }
+ }
+ }
+ if (!bcData && cellData) {
+ bcData = &cellData->mData;
+ }
+ if (bcData) {
+ bcData->SetTopEdge(aOwner, aSize, changed);
+ }
+ else NS_ASSERTION(PR_FALSE, "program error");
+ }
+ break;
+ case NS_SIDE_RIGHT:
+ xPos++;
+ case NS_SIDE_LEFT:
+ // since top, bottom borders were set, there should already be a cellData entry
+ lastIndex = rgYPos + aLength - 1;
+ for (yIndex = rgYPos; yIndex <= lastIndex; yIndex++) {
+ changed = aChanged && (yIndex == rgYPos);
+ cellData = (BCCellData*)aCellMap.GetDataAt(*this, yIndex, xPos, PR_FALSE);
+ if (cellData) {
+ cellData->mData.SetLeftEdge(aOwner, aSize, changed);
+ }
+ else {
+ NS_ASSERTION(aSide == NS_SIDE_RIGHT, "program error");
+ BCData* bcData = GetRightMostBorder(yIndex + aCellMapStart);
+ if (bcData) {
+ bcData->SetLeftEdge(aOwner, aSize, changed);
+ }
+ else NS_ASSERTION(PR_FALSE, "program error");
+ }
+ }
+ break;
+ }
+}
+
+// store corner info (aOwner, aSubSize, aBevel). For aCorner = eTopLeft, store the info at
+// (aRowIndex, aColIndex). For eTopRight, store it in the entry to the right where
+// it would be top left. For eBottomRight, store it in the entry to the bottom. etc.
+void
+nsTableCellMap::SetBCBorderCorner(Corner aCorner,
+ nsCellMap& aCellMap,
+ PRUint32 aCellMapStart,
+ PRUint32 aRowIndex,
+ PRUint32 aColIndex,
+ PRUint8 aOwner,
+ nscoord aSubSize,
+ PRBool aBevel,
+ PRBool aIsBottomRight)
+{
+ if (!mBCInfo) ABORT0();
+
+ if (aIsBottomRight) {
+ mBCInfo->mLowerRightCorner.SetCorner(aSubSize, aOwner, aBevel);
+ return;
+ }
+
+ PRInt32 xPos = aColIndex;
+ PRInt32 yPos = aRowIndex;
+ PRInt32 rgYPos = aRowIndex - aCellMapStart;
+
+ if (eTopRight == aCorner) {
+ xPos++;
+ }
+ else if (eBottomRight == aCorner) {
+ xPos++;
+ rgYPos++;
+ yPos++;
+ }
+ else if (eBottomLeft == aCorner) {
+ rgYPos++;
+ yPos++;
+ }
+
+ BCCellData* cellData = nsnull;
+ BCData* bcData = nsnull;
+ if (GetColCount() <= xPos) {
+ NS_ASSERTION(xPos == GetColCount(), "program error");
+ if (aIsBottomRight) { // at the bottom right corner
+ bcData = &mBCInfo->mLowerRightCorner;
+ }
+ else { // at the right edge of the table
+ bcData = GetRightMostBorder(yPos);
+ }
+ }
+ else {
+ cellData = (BCCellData*)aCellMap.GetDataAt(*this, rgYPos, xPos, PR_FALSE);
+ if (!cellData) {
+ PRInt32 numRgRows = aCellMap.GetRowCount();
+ if (yPos < numRgRows) { // add a dead cell data
+ nsRect damageArea;
+ cellData = (BCCellData*)aCellMap.AppendCell(*this, nsnull, rgYPos, PR_FALSE, damageArea);
+ }
+ else {
+ // try the next non empty row group
+ nsCellMap* cellMap = aCellMap.GetNextSibling();
+ while (cellMap && (0 == cellMap->GetRowCount())) {
+ cellMap = cellMap->GetNextSibling();
+ }
+ if (cellMap) {
+ cellData = (BCCellData*)cellMap->GetDataAt(*this, 0, xPos, PR_FALSE);
+ if (!cellData) { // add a dead cell
+ nsRect damageArea;
+ cellData = (BCCellData*)cellMap->AppendCell(*this, nsnull, 0, PR_FALSE, damageArea);
+ }
+ }
+ else { // must be a the bottom of the table
+ bcData = GetBottomMostBorder(xPos);
+ }
+ }
+ }
+ }
+ if (!bcData && cellData) {
+ bcData = &cellData->mData;
+ }
+ if (bcData) {
+ bcData->SetCorner(aSubSize, aOwner, aBevel);
+ }
+ else NS_ASSERTION(PR_FALSE, "program error");
+}
+
#ifdef DEBUG
void nsTableCellMap::SizeOf(nsISizeOfHandler* aHandler,
PRUint32* aResult) const
@@ -540,6 +952,7 @@ void nsTableCellMap::SizeOf(nsISizeOfHandler* aHandler,
mCols.SizeOf(aHandler, &voidArraySize);
sum += voidArraySize - sizeof(mCols);
+ // XXX need to so something for mBCInfo
*aResult = sum;
}
#endif
@@ -633,7 +1046,8 @@ nsCellMap::InsertRows(nsIPresContext* aPresContext,
nsTableCellMap& aMap,
nsVoidArray& aRows,
PRInt32 aFirstRowIndex,
- PRBool aConsiderSpans)
+ PRBool aConsiderSpans,
+ nsRect& aDamageArea)
{
PRInt32 numCols = aMap.GetColCount();
@@ -648,7 +1062,7 @@ nsCellMap::InsertRows(nsIPresContext* aPresContext,
}
if (!aConsiderSpans) {
- ExpandWithRows(aPresContext, aMap, aRows, aFirstRowIndex);
+ ExpandWithRows(aPresContext, aMap, aRows, aFirstRowIndex, aDamageArea);
return;
}
@@ -663,10 +1077,10 @@ nsCellMap::InsertRows(nsIPresContext* aPresContext,
}
if (spansCauseRebuild) {
- RebuildConsideringRows(aPresContext, aMap, aFirstRowIndex, &aRows);
+ RebuildConsideringRows(aPresContext, aMap, aFirstRowIndex, &aRows, 0, aDamageArea);
}
else {
- ExpandWithRows(aPresContext, aMap, aRows, aFirstRowIndex);
+ ExpandWithRows(aPresContext, aMap, aRows, aFirstRowIndex, aDamageArea);
}
}
@@ -675,7 +1089,8 @@ nsCellMap::RemoveRows(nsIPresContext* aPresContext,
nsTableCellMap& aMap,
PRInt32 aFirstRowIndex,
PRInt32 aNumRowsToRemove,
- PRBool aConsiderSpans)
+ PRBool aConsiderSpans,
+ nsRect& aDamageArea)
{
PRInt32 numRows = mRows.Count();
PRInt32 numCols = aMap.GetColCount();
@@ -684,7 +1099,7 @@ nsCellMap::RemoveRows(nsIPresContext* aPresContext,
return;
}
if (!aConsiderSpans) {
- ShrinkWithoutRows(aMap, aFirstRowIndex, aNumRowsToRemove);
+ ShrinkWithoutRows(aMap, aFirstRowIndex, aNumRowsToRemove, aDamageArea);
return;
}
PRInt32 endRowIndex = aFirstRowIndex + aNumRowsToRemove - 1;
@@ -696,50 +1111,70 @@ nsCellMap::RemoveRows(nsIPresContext* aPresContext,
0, numCols - 1);
if (spansCauseRebuild) {
- RebuildConsideringRows(aPresContext, aMap, aFirstRowIndex, nsnull, aNumRowsToRemove);
+ RebuildConsideringRows(aPresContext, aMap, aFirstRowIndex, nsnull, aNumRowsToRemove, aDamageArea);
}
else {
- ShrinkWithoutRows(aMap, aFirstRowIndex, aNumRowsToRemove);
+ ShrinkWithoutRows(aMap, aFirstRowIndex, aNumRowsToRemove, aDamageArea);
}
}
-PRInt32
+void
+SetDamageArea(PRInt32 aXOrigin,
+ PRInt32 aYOrigin,
+ PRInt32 aWidth,
+ PRInt32 aHeight,
+ nsRect& aDamageArea)
+{
+ aDamageArea.x = aXOrigin;
+ aDamageArea.y = aYOrigin;
+ aDamageArea.width = PR_MAX(1, aWidth);
+ aDamageArea.height = PR_MAX(1, aHeight);
+}
+
+
+CellData*
nsCellMap::AppendCell(nsTableCellMap& aMap,
- nsTableCellFrame& aCellFrame,
+ nsTableCellFrame* aCellFrame,
PRInt32 aRowIndex,
- PRBool aRebuildIfNecessary)
+ PRBool aRebuildIfNecessary,
+ nsRect& aDamageArea)
{
PRInt32 origNumMapRows = mRows.Count();
PRInt32 origNumCols = aMap.GetColCount();
PRBool zeroRowSpan;
- PRInt32 rowSpan = GetRowSpanForNewCell(aCellFrame, aRowIndex, zeroRowSpan);
+ PRInt32 rowSpan = (aCellFrame) ? GetRowSpanForNewCell(*aCellFrame, aRowIndex, zeroRowSpan) : 1;
// add new rows if necessary
PRInt32 endRowIndex = aRowIndex + rowSpan - 1;
if (endRowIndex >= origNumMapRows) {
Grow(aMap, 1 + endRowIndex - origNumMapRows);
}
- // get the first null CellData in the desired row. It may be 1 past the end if there are none
+ // get the first null or dead CellData in the desired row. It will equal origNumCols if there are none
+ CellData* origData = nsnull;
PRInt32 startColIndex;
for (startColIndex = 0; startColIndex < origNumCols; startColIndex++) {
- CellData* data = GetMapCellAt(aMap, aRowIndex, startColIndex, PR_TRUE);
+ CellData* data = GetDataAt(aMap, aRowIndex, startColIndex, PR_TRUE);
if (!data) {
- break; // we found the col
+ break;
+ }
+ else if (data->IsDead()) {
+ origData = data;
+ break;
}
}
+
PRBool zeroColSpan;
- PRInt32 colSpan = GetColSpanForNewCell(aCellFrame, startColIndex, origNumCols, zeroColSpan);
+ PRInt32 colSpan = (aCellFrame) ? GetColSpanForNewCell(*aCellFrame, startColIndex, origNumCols, zeroColSpan) : 1;
// if the new cell could potentially span into other rows and collide with
// originating cells there, we will play it safe and just rebuild the map
if (aRebuildIfNecessary && (aRowIndex < mRowCount - 1) && (rowSpan > 1)) {
nsAutoVoidArray newCellArray;
- newCellArray.AppendElement(&aCellFrame);
- RebuildConsideringCells(aMap, &newCellArray, aRowIndex, startColIndex, PR_TRUE);
- return startColIndex;
+ newCellArray.AppendElement(aCellFrame);
+ RebuildConsideringCells(aMap, &newCellArray, aRowIndex, startColIndex, PR_TRUE, aDamageArea);
+ return origData;
}
-
mRowCount = PR_MAX(mRowCount, aRowIndex + 1);
// add new cols to the table map if necessary
@@ -749,19 +1184,29 @@ nsCellMap::AppendCell(nsTableCellMap& aMap,
}
// Setup CellData for this cell
- CellData* origData = new CellData(&aCellFrame);
- if (!origData) return startColIndex;
- SetMapCellAt(aMap, *origData, aRowIndex, startColIndex, PR_TRUE);
+ if (origData) {
+ origData->Init(aCellFrame);
+ }
+ else {
+ origData = (aMap.mBCInfo) ? new BCCellData(aCellFrame) : new CellData(aCellFrame); if (!origData) ABORT1(origData);
+ SetDataAt(aMap, *origData, aRowIndex, startColIndex, PR_TRUE);
+ }
+
+ SetDamageArea(startColIndex, aRowIndex, 1 + endColIndex - startColIndex, 1 + endRowIndex - aRowIndex, aDamageArea);
+
+ if (!aCellFrame) {
+ return origData;
+ }
// initialize the cell frame
- aCellFrame.InitCellFrame(startColIndex);
+ aCellFrame->InitCellFrame(startColIndex);
// Create CellData objects for the rows that this cell spans. Set
// their mOrigCell to nsnull and their mSpanData to point to data.
for (PRInt32 rowX = aRowIndex; rowX <= endRowIndex; rowX++) {
for (PRInt32 colX = startColIndex; colX <= endColIndex; colX++) {
if ((rowX != aRowIndex) || (colX != startColIndex)) { // skip orig cell data done above
- CellData* cellData = GetMapCellAt(aMap, rowX, colX, PR_FALSE);
+ CellData* cellData = GetDataAt(aMap, rowX, colX, PR_FALSE);
if (cellData) {
if (cellData->IsOrig()) {
NS_ASSERTION(PR_FALSE, "cannot overlap originating cell");
@@ -796,8 +1241,8 @@ nsCellMap::AppendCell(nsTableCellMap& aMap,
}
}
else {
- cellData = new CellData(nsnull);
- if (!cellData) return startColIndex;
+ cellData = (aMap.mBCInfo) ? new BCCellData(nsnull) : new CellData(nsnull);
+ if (!cellData) return origData;
if (rowX > aRowIndex) {
cellData->SetRowSpanOffset(rowX - aRowIndex);
}
@@ -811,14 +1256,14 @@ nsCellMap::AppendCell(nsTableCellMap& aMap,
cellData->SetZeroColSpan(PR_TRUE);
}
// only count the 1st spanned col of a zero col span
- SetMapCellAt(aMap, *cellData, rowX, colX, (colX == startColIndex + 1));
+ SetDataAt(aMap, *cellData, rowX, colX, (colX == startColIndex + 1));
}
}
}
}
- //printf("appended cell=%p row=%d \n", &aCellFrame, aRowIndex);
+ //printf("appended cell=%p row=%d \n", aCellFrame, aRowIndex);
//aMap.Dump();
- return startColIndex;
+ return origData;
}
PRBool nsCellMap::CellsSpanOut(nsIPresContext* aPresContext,
@@ -832,7 +1277,7 @@ PRBool nsCellMap::CellsSpanOut(nsIPresContext* aPresContext,
while (cellFrame) {
nsIAtom* frameType;
cellFrame->GetFrameType(&frameType);
- if (nsLayoutAtoms::tableCellFrame == frameType) {
+ if (IS_TABLE_CELL(frameType)) {
PRBool zeroSpan;
PRInt32 rowSpan = GetRowSpanForNewCell((nsTableCellFrame &)*cellFrame, rowX, zeroSpan);
if (rowX + rowSpan > numNewRows) {
@@ -858,13 +1303,13 @@ PRBool nsCellMap::CellsSpanInOrOut(nsTableCellMap& aMap,
for (PRInt32 colX = aStartColIndex; colX <= aEndColIndex; colX++) {
CellData* cellData;
if (aStartRowIndex > 0) {
- cellData = GetMapCellAt(aMap, aStartRowIndex, colX, PR_TRUE);
+ cellData = GetDataAt(aMap, aStartRowIndex, colX, PR_TRUE);
if (cellData && (cellData->IsRowSpan())) {
return PR_TRUE; // there is a row span into the region
}
}
if (aEndRowIndex < mRowCount - 1) {
- cellData = GetMapCellAt(aMap, aEndRowIndex + 1, colX, PR_TRUE);
+ cellData = GetDataAt(aMap, aEndRowIndex + 1, colX, PR_TRUE);
if ((cellData) && (cellData->IsRowSpan())) {
return PR_TRUE; // there is a row span out of the region
}
@@ -872,7 +1317,7 @@ PRBool nsCellMap::CellsSpanInOrOut(nsTableCellMap& aMap,
}
if (aStartColIndex > 0) {
for (PRInt32 rowX = aStartRowIndex; rowX <= aEndRowIndex; rowX++) {
- CellData* cellData = GetMapCellAt(aMap, rowX, aStartColIndex, PR_TRUE);
+ CellData* cellData = GetDataAt(aMap, rowX, aStartColIndex, PR_TRUE);
if (cellData && (cellData->IsColSpan())) {
return PR_TRUE; // there is a col span into the region
}
@@ -891,7 +1336,8 @@ PRBool nsCellMap::CellsSpanInOrOut(nsTableCellMap& aMap,
void nsCellMap::InsertCells(nsTableCellMap& aMap,
nsVoidArray& aCellFrames,
PRInt32 aRowIndex,
- PRInt32 aColIndexBefore)
+ PRInt32 aColIndexBefore,
+ nsRect& aDamageArea)
{
if (aCellFrames.Count() == 0) return;
PRInt32 numCols = aMap.GetColCount();
@@ -903,7 +1349,7 @@ void nsCellMap::InsertCells(nsTableCellMap& aMap,
// get the starting col index of the 1st new cells
PRInt32 startColIndex;
for (startColIndex = aColIndexBefore + 1; startColIndex < numCols; startColIndex++) {
- CellData* data = GetMapCellAt(aMap, aRowIndex, startColIndex, PR_TRUE);
+ CellData* data = GetDataAt(aMap, aRowIndex, startColIndex, PR_TRUE);
if (!data || data->IsOrig()) { // stop unless it is a span
break;
}
@@ -942,10 +1388,10 @@ void nsCellMap::InsertCells(nsTableCellMap& aMap,
}
if (spansCauseRebuild) {
- RebuildConsideringCells(aMap, &aCellFrames, aRowIndex, startColIndex, PR_TRUE);
+ RebuildConsideringCells(aMap, &aCellFrames, aRowIndex, startColIndex, PR_TRUE, aDamageArea);
}
else {
- ExpandWithCells(aMap, aCellFrames, aRowIndex, startColIndex, rowSpan, zeroRowSpan);
+ ExpandWithCells(aMap, aCellFrames, aRowIndex, startColIndex, rowSpan, zeroRowSpan, aDamageArea);
}
}
@@ -953,7 +1399,8 @@ void
nsCellMap::ExpandWithRows(nsIPresContext* aPresContext,
nsTableCellMap& aMap,
nsVoidArray& aRowFrames,
- PRInt32 aStartRowIndexIn)
+ PRInt32 aStartRowIndexIn,
+ nsRect& aDamageArea)
{
PRInt32 startRowIndex = (aStartRowIndexIn >= 0) ? aStartRowIndexIn : 0;
PRInt32 numNewRows = aRowFrames.Count();
@@ -974,22 +1421,25 @@ nsCellMap::ExpandWithRows(nsIPresContext* aPresContext,
while (cFrame) {
nsIAtom* cFrameType;
cFrame->GetFrameType(&cFrameType);
- if (nsLayoutAtoms::tableCellFrame == cFrameType) {
- AppendCell(aMap, (nsTableCellFrame &)*cFrame, rowX, PR_FALSE);
+ if (IS_TABLE_CELL(cFrameType)) {
+ AppendCell(aMap, (nsTableCellFrame *)cFrame, rowX, PR_FALSE, aDamageArea);
}
NS_IF_RELEASE(cFrameType);
cFrame->GetNextSibling(&cFrame);
}
newRowIndex++;
}
+
+ SetDamageArea(0, startRowIndex, aMap.GetColCount(), 1 + endRowIndex - startRowIndex, aDamageArea);
}
void nsCellMap::ExpandWithCells(nsTableCellMap& aMap,
nsVoidArray& aCellFrames,
PRInt32 aRowIndex,
PRInt32 aColIndex,
- PRInt32 aRowSpan,
- PRBool aRowSpanIsZero)
+ PRInt32 aRowSpan, // same for all cells
+ PRBool aRowSpanIsZero,
+ nsRect& aDamageArea)
{
PRInt32 endRowIndex = aRowIndex + aRowSpan - 1;
PRInt32 startColIndex = aColIndex;
@@ -1000,7 +1450,7 @@ void nsCellMap::ExpandWithCells(nsTableCellMap& aMap,
// add cellData entries for the space taken up by the new cells
for (PRInt32 cellX = 0; cellX < numCells; cellX++) {
nsTableCellFrame* cellFrame = (nsTableCellFrame*) aCellFrames.ElementAt(cellX);
- CellData* origData = new CellData(cellFrame); // the originating cell
+ CellData* origData = (aMap.mBCInfo) ? new BCCellData(cellFrame) : new CellData(cellFrame); // the originating cell
if (!origData) return;
// set the starting and ending col index for the new cell
@@ -1022,7 +1472,7 @@ void nsCellMap::ExpandWithCells(nsTableCellMap& aMap,
row->InsertElementAt(nsnull, colX);
CellData* data = origData;
if ((rowX != aRowIndex) || (colX != startColIndex)) {
- data = new CellData(nsnull);
+ data = (aMap.mBCInfo) ? new BCCellData(nsnull) : new CellData(nsnull);
if (!data) return;
if (rowX > aRowIndex) {
data->SetRowSpanOffset(rowX - aRowIndex);
@@ -1038,11 +1488,13 @@ void nsCellMap::ExpandWithCells(nsTableCellMap& aMap,
}
}
// only count 1st spanned col of colspan=0
- SetMapCellAt(aMap, *data, rowX, colX, (colX == aColIndex + 1));
+ SetDataAt(aMap, *data, rowX, colX, (colX == aColIndex + 1));
}
}
cellFrame->InitCellFrame(startColIndex);
}
+ PRInt32 damageHeight = (aRowSpanIsZero) ? aMap.GetColCount() - aRowIndex : aRowSpan;
+ SetDamageArea(aColIndex, aRowIndex, 1 + endColIndex - aColIndex, damageHeight, aDamageArea);
PRInt32 rowX;
@@ -1090,7 +1542,8 @@ void nsCellMap::ExpandWithCells(nsTableCellMap& aMap,
void nsCellMap::ShrinkWithoutRows(nsTableCellMap& aMap,
PRInt32 aStartRowIndex,
- PRInt32 aNumRowsToRemove)
+ PRInt32 aNumRowsToRemove,
+ nsRect& aDamageArea)
{
PRInt32 endRowIndex = aStartRowIndex + aNumRowsToRemove - 1;
PRInt32 colCount = aMap.GetColCount();
@@ -1132,6 +1585,8 @@ void nsCellMap::ShrinkWithoutRows(nsTableCellMap& aMap,
mRowCount--;
}
aMap.RemoveColsAtEnd();
+
+ SetDamageArea(0, aStartRowIndex, aMap.GetColCount(), 0, aDamageArea);
}
PRInt32 nsCellMap::GetColSpanForNewCell(nsTableCellFrame& aCellFrameToAdd,
@@ -1162,15 +1617,15 @@ PRInt32 nsCellMap::GetEffectiveColSpan(nsTableCellMap& aMap,
PRInt32 colX;
CellData* data;
PRInt32 maxCols = numColsInTable;
- PRBool hitOverlap = PR_FALSE;
+ PRBool hitOverlap = PR_FALSE; // XXX this is not ever being set to PR_TRUE
for (colX = aColIndex + 1; colX < maxCols; colX++) {
- data = GetMapCellAt(aMap, aRowIndex, colX, PR_TRUE);
+ data = GetDataAt(aMap, aRowIndex, colX, PR_TRUE);
if (data) {
// for an overlapping situation get the colspan from the originating cell and
// use that as the max number of cols to iterate. Since this is rare, only
// pay the price of looking up the cell's colspan here.
if (!hitOverlap && data->IsOverlap()) {
- CellData* origData = GetMapCellAt(aMap, aRowIndex, aColIndex, PR_TRUE);
+ CellData* origData = GetDataAt(aMap, aRowIndex, aColIndex, PR_TRUE);
if (origData->IsOrig()) {
nsTableCellFrame* cellFrame = origData->GetCellFrame();
if (cellFrame) {
@@ -1223,7 +1678,7 @@ PRInt32 nsCellMap::GetRowSpan(nsTableCellMap& aMap,
PRInt32 rowCount = (aGetEffective) ? mRowCount : mRows.Count();
PRInt32 rowX;
for (rowX = aRowIndex + 1; rowX < rowCount; rowX++) {
- CellData* data = GetMapCellAt(aMap, rowX, aColIndex, PR_TRUE);
+ CellData* data = GetDataAt(aMap, rowX, aColIndex, PR_TRUE);
if (data) {
if (data->IsRowSpan()) {
rowSpan++;
@@ -1246,7 +1701,8 @@ PRInt32 nsCellMap::GetRowSpan(nsTableCellMap& aMap,
void nsCellMap::ShrinkWithoutCell(nsTableCellMap& aMap,
nsTableCellFrame& aCellFrame,
PRInt32 aRowIndex,
- PRInt32 aColIndex)
+ PRInt32 aColIndex,
+ nsRect& aDamageArea)
{
PRInt32 colX, rowX;
@@ -1258,6 +1714,8 @@ void nsCellMap::ShrinkWithoutCell(nsTableCellMap& aMap,
PRInt32 endRowIndex = aRowIndex + rowSpan - 1;
PRInt32 endColIndex = aColIndex + colSpan - 1;
+ SetDamageArea(aColIndex, aRowIndex, 1 + endColIndex - aColIndex, 1 + endRowIndex - aRowIndex, aDamageArea);
+
// adjust the col counts due to the deleted cell before removing it
for (colX = aColIndex; colX <= endColIndex; colX++) {
nsColInfo* colInfo = aMap.GetColInfoAt(colX);
@@ -1317,25 +1775,13 @@ void nsCellMap::ShrinkWithoutCell(nsTableCellMap& aMap,
aMap.RemoveColsAtEnd();
}
-void
-nsCellMap::RemoveCol(PRInt32 aColIndex)
-{
- PRInt32 numMapRows = mRows.Count();
- // remove the col from each of the rows
- for (PRInt32 rowX = 0; rowX < numMapRows; rowX++) {
- nsVoidArray* row = (nsVoidArray *)mRows.ElementAt(rowX);
- CellData* data = (CellData*) row->ElementAt(aColIndex);
- row->RemoveElementAt(aColIndex);
- delete data;
- }
-}
-
void
nsCellMap::RebuildConsideringRows(nsIPresContext* aPresContext,
nsTableCellMap& aMap,
PRInt32 aStartRowIndex,
nsVoidArray* aRowsToInsert,
- PRBool aNumRowsToRemove)
+ PRBool aNumRowsToRemove,
+ nsRect& aDamageArea)
{
// copy the old cell map into a new array
PRInt32 numOrigRows = mRows.Count();
@@ -1352,6 +1798,7 @@ nsCellMap::RebuildConsideringRows(nsIPresContext* aPresContext,
nsColInfo* colInfo = aMap.GetColInfoAt(colX);
colInfo->mNumCellsOrig = 0;
}
+
mRows.Clear();
mRowCount = 0;
if (aRowsToInsert) {
@@ -1366,7 +1813,7 @@ nsCellMap::RebuildConsideringRows(nsIPresContext* aPresContext,
// put in the original cell from the cell map
CellData* data = (CellData*) row->ElementAt(colX);
if (data && data->IsOrig()) {
- AppendCell(aMap, *data->GetCellFrame(), rowX, PR_FALSE);
+ AppendCell(aMap, data->GetCellFrame(), rowX, PR_FALSE, aDamageArea);
}
}
}
@@ -1382,8 +1829,8 @@ nsCellMap::RebuildConsideringRows(nsIPresContext* aPresContext,
while (cFrame) {
nsIAtom* cFrameType;
cFrame->GetFrameType(&cFrameType);
- if (nsLayoutAtoms::tableCellFrame == cFrameType) {
- AppendCell(aMap, (nsTableCellFrame &)*cFrame, rowX, PR_FALSE);
+ if (IS_TABLE_CELL(cFrameType)) {
+ AppendCell(aMap, (nsTableCellFrame *)cFrame, rowX, PR_FALSE, aDamageArea);
}
NS_IF_RELEASE(cFrameType);
cFrame->GetNextSibling(&cFrame);
@@ -1405,7 +1852,7 @@ nsCellMap::RebuildConsideringRows(nsIPresContext* aPresContext,
// put in the original cell from the cell map
CellData* data = (CellData*) row->ElementAt(colX);
if (data && data->IsOrig()) {
- AppendCell(aMap, *data->GetCellFrame(), rowX, PR_FALSE);
+ AppendCell(aMap, data->GetCellFrame(), rowX, PR_FALSE, aDamageArea);
}
}
rowX++;
@@ -1422,13 +1869,16 @@ nsCellMap::RebuildConsideringRows(nsIPresContext* aPresContext,
delete row;
}
delete [] origRows;
+
+ SetDamageArea(0, 0, aMap.GetColCount(), GetRowCount(), aDamageArea);
}
void nsCellMap::RebuildConsideringCells(nsTableCellMap& aMap,
nsVoidArray* aCellFrames,
PRInt32 aRowIndex,
PRInt32 aColIndex,
- PRBool aInsert)
+ PRBool aInsert,
+ nsRect& aDamageArea)
{
// copy the old cell map into a new array
PRInt32 mRowCountOrig = mRowCount;
@@ -1441,6 +1891,7 @@ void nsCellMap::RebuildConsideringCells(nsTableCellMap& aMap,
nsVoidArray* row = (nsVoidArray *)mRows.ElementAt(rowX);
origRows[rowX] = row;
}
+
// reinitialize data members
mRows.Clear();
mRowCount = 0;
@@ -1457,7 +1908,7 @@ void nsCellMap::RebuildConsideringCells(nsTableCellMap& aMap,
for (PRInt32 cellX = 0; cellX < numNewCells; cellX++) {
nsTableCellFrame* cell = (nsTableCellFrame*)aCellFrames->ElementAt(cellX);
if (cell) {
- AppendCell(aMap, *cell, rowX, PR_FALSE);
+ AppendCell(aMap, cell, rowX, PR_FALSE, aDamageArea);
}
}
}
@@ -1468,7 +1919,7 @@ void nsCellMap::RebuildConsideringCells(nsTableCellMap& aMap,
// put in the original cell from the cell map
CellData* data = (CellData*) row->ElementAt(colX);
if (data && data->IsOrig()) {
- AppendCell(aMap, *data->GetCellFrame(), rowX, PR_FALSE);
+ AppendCell(aMap, data->GetCellFrame(), rowX, PR_FALSE, aDamageArea);
}
}
}
@@ -1490,11 +1941,14 @@ void nsCellMap::RebuildConsideringCells(nsTableCellMap& aMap,
delete row;
}
delete [] origRows;
+
+ SetDamageArea(0, 0, aMap.GetColCount(), GetRowCount(), aDamageArea);
}
void nsCellMap::RemoveCell(nsTableCellMap& aMap,
nsTableCellFrame* aCellFrame,
- PRInt32 aRowIndex)
+ PRInt32 aRowIndex,
+ nsRect& aDamageArea)
{
PRInt32 numRows = mRows.Count();
if ((aRowIndex < 0) || (aRowIndex >= numRows)) {
@@ -1506,7 +1960,7 @@ void nsCellMap::RemoveCell(nsTableCellMap& aMap,
// get the starting col index of the cell to remove
PRInt32 startColIndex;
for (startColIndex = 0; startColIndex < numCols; startColIndex++) {
- CellData* data = GetMapCellAt(aMap, aRowIndex, startColIndex, PR_FALSE);
+ CellData* data = GetDataAt(aMap, aRowIndex, startColIndex, PR_FALSE);
if (data && (data->IsOrig()) && (aCellFrame == data->GetCellFrame())) {
break; // we found the col index
}
@@ -1523,15 +1977,15 @@ void nsCellMap::RemoveCell(nsTableCellMap& aMap,
// no extraneous cols at the end. The same is true for removing rows.
if (spansCauseRebuild) {
- RebuildConsideringCells(aMap, nsnull, aRowIndex, startColIndex, PR_FALSE);
+ RebuildConsideringCells(aMap, nsnull, aRowIndex, startColIndex, PR_FALSE, aDamageArea);
}
else {
- ShrinkWithoutCell(aMap, *aCellFrame, aRowIndex, startColIndex);
+ ShrinkWithoutCell(aMap, *aCellFrame, aRowIndex, startColIndex, aDamageArea);
}
}
#ifdef NS_DEBUG
-void nsCellMap::Dump() const
+void nsCellMap::Dump(PRBool aIsBorderCollapse) const
{
printf("\n ***** START GROUP CELL MAP DUMP ***** %p\n", this);
PRInt32 mapRowCount = mRows.Count();
@@ -1566,6 +2020,33 @@ void nsCellMap::Dump() const
printf("---- ");
}
}
+ if (aIsBorderCollapse) {
+ nscoord size;
+ BCBorderOwner owner;
+ PRUint8 side;
+ PRBool segStart;
+ PRPackedBool bevel;
+ for (PRInt32 i = 0; i <= 2; i++) {
+ printf("\n ");
+ for (colIndex = 0; colIndex < colCount; colIndex++) {
+ BCCellData* cd = (BCCellData *)row->ElementAt(colIndex);
+ if (cd) {
+ if (0 == i) {
+ size = cd->mData.GetTopEdge(owner, segStart);
+ printf("t=%d%d%d ", size, owner, segStart);
+ }
+ else if (1 == i) {
+ size = cd->mData.GetLeftEdge(owner, segStart);
+ printf("l=%d%d%d ", size, owner, segStart);
+ }
+ else {
+ size = cd->mData.GetCorner(side, bevel);
+ printf("c=%d%d%d ", size, side, bevel);
+ }
+ }
+ }
+ }
+ }
printf("\n");
}
@@ -1614,7 +2095,7 @@ nsCellMap::AdjustForZeroSpan(nsTableCellMap& aMap,
PRInt32 aColIndex)
{
PRInt32 numColsInTable = aMap.GetColCount();
- CellData* data = GetMapCellAt(aMap, aRowIndex, aColIndex, PR_FALSE);
+ CellData* data = GetDataAt(aMap, aRowIndex, aColIndex, PR_FALSE);
if (!data) return;
nsTableCellFrame* cell = (data->IsOrig()) ? data->GetCellFrame() : nsnull;
@@ -1640,7 +2121,7 @@ nsCellMap::AdjustForZeroSpan(nsTableCellMap& aMap,
PRBool cellsOrig = PR_FALSE;
if (colX >= aColIndex + MIN_NUM_COLS_FOR_ZERO_COLSPAN - 1) {
for (rowX = aRowIndex; rowX <= endRowIndex; rowX++) {
- CellData* cellData = GetMapCellAt(aMap, rowX, colX, PR_FALSE);
+ CellData* cellData = GetDataAt(aMap, rowX, colX, PR_FALSE);
if (cellData && cellData->IsOrig()) {
cellsOrig = PR_TRUE;
break; // there are cells in this col, so don't consider it
@@ -1650,9 +2131,9 @@ nsCellMap::AdjustForZeroSpan(nsTableCellMap& aMap,
if (cellsOrig) break;
for (rowX = aRowIndex; rowX <= endRowIndex; rowX++) {
if ((colX > aColIndex) || (rowX > aRowIndex)) {
- CellData* oldData = GetMapCellAt(aMap, rowX, colX, PR_FALSE);
+ CellData* oldData = GetDataAt(aMap, rowX, colX, PR_FALSE);
if (!oldData) {
- CellData* newData = new CellData(nsnull);
+ CellData* newData = (aMap.mBCInfo) ? new BCCellData(nsnull) : new CellData(nsnull);
if (!newData) return;
if (colX > aColIndex) {
newData->SetColSpanOffset(colX - aColIndex);
@@ -1663,7 +2144,7 @@ nsCellMap::AdjustForZeroSpan(nsTableCellMap& aMap,
newData->SetZeroRowSpan(PR_TRUE);
}
// colspan=0 is only counted as spanning the 1st col to the right of its origin
- SetMapCellAt(aMap, *newData, rowX, colX, (colX == aColIndex + 1));
+ SetDataAt(aMap, *newData, rowX, colX, (colX == aColIndex + 1));
}
}
}
@@ -1671,10 +2152,10 @@ nsCellMap::AdjustForZeroSpan(nsTableCellMap& aMap,
}
CellData*
-nsCellMap::GetMapCellAt(nsTableCellMap& aMap,
- PRInt32 aMapRowIndex,
- PRInt32 aColIndex,
- PRBool aUpdateZeroSpan)
+nsCellMap::GetDataAt(nsTableCellMap& aMap,
+ PRInt32 aMapRowIndex,
+ PRInt32 aColIndex,
+ PRBool aUpdateZeroSpan)
{
PRInt32 numColsInTable = aMap.GetColCount();
if ((aMapRowIndex < 0) || (aMapRowIndex >= mRows.Count())) {
@@ -1714,7 +2195,7 @@ nsCellMap::GetMapCellAt(nsTableCellMap& aMap,
PRInt32 prevColX = aColIndex - 1;
// find the last non null data in the same row
for ( ; prevColX > 0; prevColX--) {
- CellData* prevData = GetMapCellAt(aMap, aMapRowIndex, prevColX, PR_FALSE);
+ CellData* prevData = GetDataAt(aMap, aMapRowIndex, prevColX, PR_FALSE);
if (prevData) {
if (prevData->IsZeroColSpan()) {
PRInt32 colIndex = prevColX - prevData->GetColSpanOffset();
@@ -1729,29 +2210,18 @@ nsCellMap::GetMapCellAt(nsTableCellMap& aMap,
// if zero span adjustments were made the data may be available now
if (!data && didZeroExpand) {
- data = GetMapCellAt(aMap, aMapRowIndex, aColIndex, PR_FALSE);
+ data = GetDataAt(aMap, aMapRowIndex, aColIndex, PR_FALSE);
}
}
return data;
}
-CellData*
-nsCellMap::GetCellAt(nsTableCellMap& aMap,
- PRInt32 aRowIndex,
- PRInt32 aColIndex)
-{
- if ((0 > aRowIndex) || (aRowIndex >= mRowCount)) {
- return nsnull;
- }
- return GetMapCellAt(aMap, aRowIndex, aColIndex, PR_TRUE);
-}
-
// only called if the cell at aMapRowIndex, aColIndex is null
-void nsCellMap::SetMapCellAt(nsTableCellMap& aMap,
- CellData& aNewCell,
- PRInt32 aMapRowIndex,
- PRInt32 aColIndex,
- PRBool aCountZeroSpanAsSpan)
+void nsCellMap::SetDataAt(nsTableCellMap& aMap,
+ CellData& aNewCell,
+ PRInt32 aMapRowIndex,
+ PRInt32 aColIndex,
+ PRBool aCountZeroSpanAsSpan)
{
nsVoidArray* row = (nsVoidArray *)(mRows.SafeElementAt(aMapRowIndex));
if (row) {
@@ -1777,9 +2247,9 @@ void nsCellMap::SetMapCellAt(nsTableCellMap& aMap,
colInfo->mNumCellsSpan++;
}
}
- else NS_ASSERTION(PR_FALSE, "SetMapCellAt called with col index > table map num cols");
+ else NS_ASSERTION(PR_FALSE, "SetDataAt called with col index > table map num cols");
}
- else NS_ASSERTION(PR_FALSE, "SetMapCellAt called with row index > num rows");
+ else NS_ASSERTION(PR_FALSE, "SetDataAt called with row index > num rows");
}
nsTableCellFrame*
@@ -1792,7 +2262,7 @@ nsCellMap::GetCellInfoAt(nsTableCellMap& aMap,
if (aOriginates) {
*aOriginates = PR_FALSE;
}
- CellData* data = GetCellAt(aMap, aRowX, aColX);
+ CellData* data = GetDataAt(aMap, aRowX, aColX, PR_TRUE);
nsTableCellFrame* cellFrame = nsnull;
if (data) {
if (data->IsOrig()) {
@@ -1824,7 +2294,7 @@ PRBool nsCellMap::RowIsSpannedInto(nsTableCellMap& aMap,
return PR_FALSE;
}
for (PRInt32 colIndex = 0; colIndex < numColsInTable; colIndex++) {
- CellData* cd = GetCellAt(aMap, aRowIndex, colIndex);
+ CellData* cd = GetDataAt(aMap, aRowIndex, colIndex, PR_TRUE);
if (cd) { // there's really a cell at (aRowIndex, colIndex)
if (cd->IsSpan()) { // the cell at (aRowIndex, colIndex) is the result of a span
if (cd->IsRowSpan() && GetCellFrame(aRowIndex, colIndex, *cd, PR_TRUE)) { // XXX why the last check
@@ -1846,9 +2316,9 @@ PRBool nsCellMap::RowHasSpanningCells(nsTableCellMap& aMap,
if (aRowIndex != mRowCount - 1) {
// aRowIndex is not the last row, so we check the next row after aRowIndex for spanners
for (PRInt32 colIndex = 0; colIndex < numColsInTable; colIndex++) {
- CellData* cd = GetCellAt(aMap, aRowIndex, colIndex);
+ CellData* cd = GetDataAt(aMap, aRowIndex, colIndex, PR_TRUE);
if (cd && (cd->IsOrig())) { // cell originates
- CellData* cd2 = GetCellAt(aMap, aRowIndex + 1, colIndex);
+ CellData* cd2 = GetDataAt(aMap, aRowIndex + 1, colIndex, PR_TRUE);
if (cd2 && cd2->IsRowSpan()) { // cd2 is spanned by a row
if (cd->GetCellFrame() == GetCellFrame(aRowIndex + 1, colIndex, *cd2, PR_TRUE)) {
return PR_TRUE;
@@ -1869,9 +2339,9 @@ PRBool nsCellMap::ColHasSpanningCells(nsTableCellMap& aMap,
return PR_FALSE;
for (PRInt32 rowIndex = 0; rowIndex < mRowCount; rowIndex++) {
- CellData* cd = GetCellAt(aMap, rowIndex, aColIndex);
+ CellData* cd = GetDataAt(aMap, rowIndex, aColIndex, PR_TRUE);
if (cd && (cd->IsOrig())) { // cell originates
- CellData* cd2 = GetCellAt(aMap, rowIndex + 1, aColIndex);
+ CellData* cd2 = GetDataAt(aMap, rowIndex + 1, aColIndex, PR_TRUE);
if (cd2 && cd2->IsColSpan()) { // cd2 is spanned by a col
if (cd->GetCellFrame() == GetCellFrame(rowIndex + 1, aColIndex, *cd2, PR_FALSE)) {
return PR_TRUE;
diff --git a/mozilla/layout/tables/nsCellMap.h b/mozilla/layout/tables/nsCellMap.h
index 89211aa5f99..4b1b6df3b7f 100644
--- a/mozilla/layout/tables/nsCellMap.h
+++ b/mozilla/layout/tables/nsCellMap.h
@@ -40,6 +40,8 @@
#include "nscore.h"
#include "celldata.h"
#include "nsVoidArray.h"
+#include "nsRect.h"
+
class nsTableColFrame;
class nsTableCellFrame;
class nsIPresContext;
@@ -58,10 +60,27 @@ struct nsColInfo
PRInt32 aNumCellsSpan);
};
+enum Corner
+{
+ eTopLeft = 0,
+ eTopRight = 1,
+ eBottomRight = 2,
+ eBottomLeft = 3
+};
+
+struct BCInfo
+{
+ nsVoidArray mRightBorders;
+ nsVoidArray mBottomBorders;
+ BCData mLowerRightCorner;
+};
+
class nsTableCellMap
{
public:
- nsTableCellMap(nsIPresContext* aPresContext, nsTableFrame& aTableFrame);
+ nsTableCellMap(nsIPresContext* aPresContext,
+ nsTableFrame& aTableFrame,
+ PRBool aBorderCollapse);
/** destructor
* NOT VIRTUAL BECAUSE THIS CLASS SHOULD **NEVER** BE SUBCLASSED
@@ -69,43 +88,52 @@ public:
~nsTableCellMap();
void RemoveGroupCellMap(nsTableRowGroupFrame* aRowGroup);
+
void InsertGroupCellMap(nsTableRowGroupFrame& aNewRowGroup,
nsTableRowGroupFrame*& aPrevRowGroup);
+ nsCellMap* GetMapFor(nsTableRowGroupFrame& aRowGroup);
+
nsTableCellFrame* GetCellFrame(PRInt32 aRowIndex,
PRInt32 aColIndex,
CellData& aData,
PRBool aUseRowIfOverlap) const;
/** return the CellData for the cell at (aTableRowIndex, aTableColIndex) */
- CellData* GetCellAt(PRInt32 aRowIndex,
- PRInt32 aColIndex);
+ CellData* GetDataAt(PRInt32 aRowIndex,
+ PRInt32 aColIndex,
+ PRBool aUpdateZeroSpan = PR_TRUE);
nsColInfo* GetColInfoAt(PRInt32 aColIndex);
/** append the cellFrame at the end of the row at aRowIndex and return the col index
*/
- PRInt32 AppendCell(nsTableCellFrame& aCellFrame,
- PRInt32 aRowIndex,
- PRBool aRebuildIfNecessary);
+ CellData* AppendCell(nsTableCellFrame& aCellFrame,
+ PRInt32 aRowIndex,
+ PRBool aRebuildIfNecessary,
+ nsRect& aDamageArea);
void InsertCells(nsVoidArray& aCellFrames,
PRInt32 aRowIndex,
- PRInt32 aColIndexBefore);
+ PRInt32 aColIndexBefore,
+ nsRect& aDamageArea);
void RemoveCell(nsTableCellFrame* aCellFrame,
- PRInt32 aRowIndex);
+ PRInt32 aRowIndex,
+ nsRect& aDamageArea);
void InsertRows(nsIPresContext* aPresContext,
nsTableRowGroupFrame& aRowGroup,
nsVoidArray& aRows,
PRInt32 aFirstRowIndex,
- PRBool aConsiderSpans);
+ PRBool aConsiderSpans,
+ nsRect& aDamageArea);
void RemoveRows(nsIPresContext* aPresContext,
PRInt32 aFirstRowIndex,
PRInt32 aNumRowsToRemove,
- PRBool aConsiderSpans);
+ PRBool aConsiderSpans,
+ nsRect& aDamageArea);
PRInt32 GetNumCellsOriginatingInRow(PRInt32 aRowIndex);
PRInt32 GetNumCellsOriginatingInCol(PRInt32 aColIndex) const;
@@ -134,6 +162,32 @@ public:
PRBool ColIsSpannedInto(PRInt32 aColIndex);
PRBool ColHasSpanningCells(PRInt32 aColIndex);
+ BCData* GetBCData(PRUint8 aSide,
+ nsCellMap& aCellMap,
+ PRUint32 aYPos,
+ PRUint32 aXPos,
+ PRBool aIsLowerRight = PR_FALSE);
+
+ void SetBCBorderEdge(PRUint8 aEdge,
+ nsCellMap& aCellMap,
+ PRUint32 aCellMapStart,
+ PRUint32 aYPos,
+ PRUint32 aXPos,
+ PRUint32 aLength,
+ BCBorderOwner aOwner,
+ nscoord aSize,
+ PRBool aChanged);
+
+ void SetBCBorderCorner(Corner aCorner,
+ nsCellMap& aCellMap,
+ PRUint32 aCellMapStart,
+ PRUint32 aYPos,
+ PRUint32 aXPos,
+ PRUint8 aOwner,
+ nscoord aSubSize,
+ PRBool aBevel,
+ PRBool aIsBottomRight = PR_FALSE);
+
/** dump a representation of the cell map to stdout for debugging */
#ifdef NS_DEBUG
void Dump(char* aString = nsnull) const;
@@ -144,13 +198,21 @@ public:
#endif
protected:
+ BCData* GetRightMostBorder(PRInt32 aRowIndex);
+ BCData* GetBottomMostBorder(PRInt32 aColIndex);
+
friend class nsCellMap;
+ friend class BCMapCellIterator;
+ friend class BCMapBorderIterator;
void InsertGroupCellMap(nsCellMap* aPrevMap,
nsCellMap& aNewMap);
+ void DeleteRightBottomBorders();
- nsTableFrame& mTableFrame;
+ nsTableFrame& mTableFrame;
nsAutoVoidArray mCols;
- nsCellMap* mFirstMap;
+ nsCellMap* mFirstMap;
+ // border collapsing info
+ BCInfo* mBCInfo;
};
/** nsCellMap is a support class for nsTablePart.
@@ -190,40 +252,38 @@ public:
CellData& aData,
PRBool aUseRowSpanIfOverlap) const;
- /** return the CellData for the cell at (aTableRowIndex, aTableColIndex) */
- CellData* GetCellAt(nsTableCellMap& aMap,
- PRInt32 aRowIndex,
- PRInt32 aColIndex);
-
/** append the cellFrame at the end of the row at aRowIndex and return the col index
*/
- PRInt32 AppendCell(nsTableCellMap& aMap,
- nsTableCellFrame& aCellFrame,
- PRInt32 aRowIndex,
- PRBool aRebuildIfNecessary);
+ CellData* AppendCell(nsTableCellMap& aMap,
+ nsTableCellFrame* aCellFrame,
+ PRInt32 aRowIndex,
+ PRBool aRebuildIfNecessary,
+ nsRect& aDamageArea);
void InsertCells(nsTableCellMap& aMap,
nsVoidArray& aCellFrames,
PRInt32 aRowIndex,
- PRInt32 aColIndexBefore);
+ PRInt32 aColIndexBefore,
+ nsRect& aDamageArea);
void RemoveCell(nsTableCellMap& aMap,
nsTableCellFrame* aCellFrame,
- PRInt32 aRowIndex);
-
- void RemoveCol(PRInt32 aColIndex);
+ PRInt32 aRowIndex,
+ nsRect& aDamageArea);
void InsertRows(nsIPresContext* aPresContext,
nsTableCellMap& aMap,
nsVoidArray& aRows,
PRInt32 aFirstRowIndex,
- PRBool aConsiderSpans);
+ PRBool aConsiderSpans,
+ nsRect& aDamageArea);
void RemoveRows(nsIPresContext* aPresContext,
nsTableCellMap& aMap,
PRInt32 aFirstRowIndex,
PRInt32 aNumRowsToRemove,
- PRBool aConsiderSpans);
+ PRBool aConsiderSpans,
+ nsRect& aDamageArea);
PRInt32 GetNumCellsOriginatingInRow(PRInt32 aRowIndex) const;
PRInt32 GetNumCellsOriginatingInCol(PRInt32 aColIndex) const;
@@ -246,9 +306,20 @@ public:
PRBool ColHasSpanningCells(nsTableCellMap& aMap,
PRInt32 aColIndex);
+ PRInt32 GetRowSpan(nsTableCellMap& aMap,
+ PRInt32 aRowIndex,
+ PRInt32 aColIndex,
+ PRBool aGetEffective,
+ PRBool& aIsZeroRowSpan);
+
+ PRInt32 GetEffectiveColSpan(nsTableCellMap& aMap,
+ PRInt32 aRowIndex,
+ PRInt32 aColIndex,
+ PRBool& aIsZeroColSpan);
+
/** dump a representation of the cell map to stdout for debugging */
#ifdef NS_DEBUG
- void Dump() const;
+ void Dump(PRBool aIsBorderCollapse) const;
#endif
#ifdef DEBUG
@@ -257,6 +328,9 @@ public:
protected:
friend class nsTableCellMap;
+ friend class BCMapCellIterator;
+ friend class BCMapBorderIterator;
+ friend class nsTableFrame;
PRBool Grow(nsTableCellMap& aMap,
PRInt32 aNumRows,
@@ -266,51 +340,57 @@ protected:
PRInt32 aNumCols);
/** assign aCellData to the cell at (aRow,aColumn) */
- void SetMapCellAt(nsTableCellMap& aMap,
- CellData& aCellData,
- PRInt32 aMapRowIndex,
- PRInt32 aColIndex,
- PRBool aCountZeroSpanAsSpan);
+ void SetDataAt(nsTableCellMap& aMap,
+ CellData& aCellData,
+ PRInt32 aMapRowIndex,
+ PRInt32 aColIndex,
+ PRBool aCountZeroSpanAsSpan);
- CellData* GetMapCellAt(nsTableCellMap& aMap,
- PRInt32 aMapRowIndex,
- PRInt32 aColIndex,
- PRBool aUpdateZeroSpan);
+ CellData* GetDataAt(nsTableCellMap& aMap,
+ PRInt32 aMapRowIndex,
+ PRInt32 aColIndex,
+ PRBool aUpdateZeroSpan);
PRInt32 GetNumCellsIn(PRInt32 aColIndex) const;
void ExpandWithRows(nsIPresContext* aPresContext,
nsTableCellMap& aMap,
nsVoidArray& aRowFrames,
- PRInt32 aStartRowIndex);
+ PRInt32 aStartRowIndex,
+ nsRect& aDamageArea);
void ExpandWithCells(nsTableCellMap& aMap,
nsVoidArray& aCellFrames,
PRInt32 aRowIndex,
PRInt32 aColIndex,
PRInt32 aRowSpan,
- PRBool aRowSpanIsZero);
+ PRBool aRowSpanIsZero,
+ nsRect& aDamageArea);
void ShrinkWithoutRows(nsTableCellMap& aMap,
PRInt32 aFirstRowIndex,
- PRInt32 aNumRowsToRemove);
+ PRInt32 aNumRowsToRemove,
+ nsRect& aDamageArea);
void ShrinkWithoutCell(nsTableCellMap& aMap,
nsTableCellFrame& aCellFrame,
PRInt32 aRowIndex,
- PRInt32 aColIndex);
+ PRInt32 aColIndex,
+ nsRect& aDamageArea);
void RebuildConsideringRows(nsIPresContext* aPresContext,
nsTableCellMap& aMap,
PRInt32 aStartRowIndex,
nsVoidArray* aRowsToInsert,
- PRInt32 aNumRowsToRemove = 0);
+ PRInt32 aNumRowsToRemove,
+ nsRect& aDamageArea);
void RebuildConsideringCells(nsTableCellMap& aMap,
nsVoidArray* aCellFrames,
PRInt32 aRowIndex,
PRInt32 aColIndex,
- PRBool aInsert);
+ PRBool aInsert,
+ nsRect& aDamageArea);
PRBool CellsSpanOut(nsIPresContext* aPresContext,
nsVoidArray& aNewRows);
@@ -327,21 +407,10 @@ protected:
PRBool CreateEmptyRow(PRInt32 aRowIndex,
PRInt32 aNumCols);
- PRInt32 GetRowSpan(nsTableCellMap& aMap,
- PRInt32 aRowIndex,
- PRInt32 aColIndex,
- PRBool aGetEffective,
- PRBool& aIsZeroRowSpan);
-
PRInt32 GetRowSpanForNewCell(nsTableCellFrame& aCellFrameToAdd,
PRInt32 aRowIndex,
PRBool& aIsZeroRowSpan);
- PRInt32 GetEffectiveColSpan(nsTableCellMap& aMap,
- PRInt32 aRowIndex,
- PRInt32 aColIndex,
- PRBool& aIsZeroColSpan);
-
PRInt32 GetColSpanForNewCell(nsTableCellFrame& aCellFrameToAdd,
PRInt32 aColIndex,
PRInt32 aNumColsInTable,
diff --git a/mozilla/layout/tables/nsITableLayoutStrategy.h b/mozilla/layout/tables/nsITableLayoutStrategy.h
index 0349e3924d8..bae856d64b4 100644
--- a/mozilla/layout/tables/nsITableLayoutStrategy.h
+++ b/mozilla/layout/tables/nsITableLayoutStrategy.h
@@ -76,7 +76,8 @@ public:
* @param aPixelToTwips - the number of twips in a pixel.
* @return - the basis for percent calculations
*/
- virtual nscoord CalcPctAdjTableWidth(const nsHTMLReflowState& aReflowState,
+ virtual nscoord CalcPctAdjTableWidth(nsIPresContext& aPresContext,
+ const nsHTMLReflowState& aReflowState,
nscoord aAvailWidth,
float aPixelToTwips)=0;
diff --git a/mozilla/layout/tables/nsTableCellFrame.cpp b/mozilla/layout/tables/nsTableCellFrame.cpp
index 2c0e87b11de..06ca717b3bd 100644
--- a/mozilla/layout/tables/nsTableCellFrame.cpp
+++ b/mozilla/layout/tables/nsTableCellFrame.cpp
@@ -100,7 +100,7 @@ nsTableCellFrame::GetNextCell() const
while (childFrame) {
nsCOMPtr frameType;
childFrame->GetFrameType(getter_AddRefs(frameType));
- if (nsLayoutAtoms::tableCellFrame == frameType.get()) {
+ if (IS_TABLE_CELL(frameType.get())) {
return (nsTableCellFrame*)childFrame;
}
childFrame->GetNextSibling(&childFrame);
@@ -439,7 +439,7 @@ nsTableCellFrame::Paint(nsIPresContext* aPresContext,
if ((NS_SUCCEEDED(rv)) && tableFrame) {
const nsStyleTableBorder* tableStyle;
tableFrame->GetStyleData(eStyleStruct_TableBorder, ((const nsStyleStruct *&)tableStyle));
- if (NS_STYLE_BORDER_SEPARATE == tableFrame->GetBorderCollapseStyle()) {
+ if (!tableFrame->IsBorderCollapse()) {
nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this,
aDirtyRect, rect, *myBorder, mStyleContext, skipSides);
}
@@ -582,10 +582,9 @@ void nsTableCellFrame::VerticallyAlignChild(nsIPresContext* aPresContex
const nsStyleTextReset* textStyle =
(const nsStyleTextReset*)mStyleContext->GetStyleData(eStyleStruct_TextReset);
/* XXX: remove tableFrame when border-collapse inherits */
- nsTableFrame* tableFrame = nsnull;
- (void) nsTableFrame::GetTableFrame(this, tableFrame);
+ GET_PIXELS_TO_TWIPS(aPresContext, p2t);
nsMargin borderPadding;
- GetCellBorder (borderPadding, tableFrame);
+ GetBorderWidth (p2t, borderPadding);
nsMargin padding = nsTableFrame::GetPadding(aReflowState, this);
borderPadding += padding;
@@ -822,13 +821,13 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext,
PRBool contentEmptyBeforeReflow = GetContentEmpty();
/* XXX: remove tableFrame when border-collapse inherits */
- nsTableFrame* tableFrame=nsnull;
- rv = nsTableFrame::GetTableFrame(this, tableFrame);
+ nsTableFrame* tableFrame = nsnull;
+ rv = nsTableFrame::GetTableFrame(this, tableFrame); if (!tableFrame) ABORT1(NS_ERROR_NULL_POINTER);
nsTableFrame* tableFrameFirstInFlow = (nsTableFrame*)tableFrame->GetFirstInFlow();
nsMargin borderPadding = aReflowState.mComputedPadding;
nsMargin border;
- GetCellBorder(border, tableFrame);
+ GetBorderWidth(p2t, border);
if ((NS_UNCONSTRAINEDSIZE == availSize.width) || !contentEmptyBeforeReflow) {
borderPadding += border;
}
@@ -1130,51 +1129,6 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext,
return NS_OK;
}
-/**
- *
- * Update the border style to map to the HTML border style
- *
- */
-void nsTableCellFrame::MapHTMLBorderStyle(nsIPresContext* aPresContext,
- nsStyleBorder& aBorderStyle,
- nsTableFrame* aTableFrame)
-{
- //adjust the border style based on the table rules attribute
-
- /* The RULES code below has been disabled because collapsing borders have been disabled
- and RULES depend on collapsing borders
-
- const nsStyleTable* tableStyle;
- aTableFrame->GetStyleData(eStyleStruct_Table, (const nsStyleStruct *&)tableStyle);
-
- switch (tableStyle->mRules)
- {
- case NS_STYLE_TABLE_RULES_NONE:
- aBorderStyle.SetBorderStyle(NS_SIDE_TOP, NS_STYLE_BORDER_STYLE_NONE);
- aBorderStyle.SetBorderStyle(NS_SIDE_LEFT, NS_STYLE_BORDER_STYLE_NONE);
- aBorderStyle.SetBorderStyle(NS_SIDE_BOTTOM, NS_STYLE_BORDER_STYLE_NONE);
- aBorderStyle.SetBorderStyle(NS_SIDE_RIGHT, NS_STYLE_BORDER_STYLE_NONE);
- break;
-
- case NS_STYLE_TABLE_RULES_COLS:
- aBorderStyle.SetBorderStyle(NS_SIDE_TOP, NS_STYLE_BORDER_STYLE_NONE);
- aBorderStyle.SetBorderStyle(NS_SIDE_BOTTOM, NS_STYLE_BORDER_STYLE_NONE);
- break;
-
- case NS_STYLE_TABLE_RULES_ROWS:
- aBorderStyle.SetBorderStyle(NS_SIDE_LEFT, NS_STYLE_BORDER_STYLE_NONE);
- aBorderStyle.SetBorderStyle(NS_SIDE_RIGHT, NS_STYLE_BORDER_STYLE_NONE);
- break;
-
- default:
- // do nothing for "GROUPS" or "ALL" or for any illegal value
- // "GROUPS" will be handled in nsTableFrame::ProcessGroupRules
- break;
- }
- */
-}
-
-
PRBool nsTableCellFrame::ConvertToPixelValue(nsHTMLValue& aValue, PRInt32 aDefault, PRInt32& aResult)
{
if (aValue.GetUnit() == eHTMLUnit_Pixel)
@@ -1401,13 +1355,16 @@ nsTableCellFrame::GetNextCellInColumn(nsITableCellLayout **aCellLayout)
}
nsresult
-NS_NewTableCellFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
+NS_NewTableCellFrame(nsIPresShell* aPresShell,
+ PRBool aIsBorderCollapse,
+ nsIFrame** aNewFrame)
{
NS_PRECONDITION(aNewFrame, "null OUT ptr");
if (nsnull == aNewFrame) {
return NS_ERROR_NULL_POINTER;
}
- nsTableCellFrame* it = new (aPresShell) nsTableCellFrame;
+ nsTableCellFrame* it = (aIsBorderCollapse) ? new (aPresShell) nsBCTableCellFrame
+ : new (aPresShell) nsTableCellFrame;
if (nsnull == it) {
return NS_ERROR_OUT_OF_MEMORY;
}
@@ -1415,27 +1372,16 @@ NS_NewTableCellFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
return NS_OK;
}
-
-
-/* ----- methods from CellLayoutData ----- */
-
-void
-nsTableCellFrame::GetCellBorder(nsMargin& aBorder,
- nsTableFrame* aTableFrame)
+nsMargin*
+nsTableCellFrame::GetBorderWidth(float aPixelsToTwips,
+ nsMargin& aBorder) const
{
aBorder.left = aBorder.right = aBorder.top = aBorder.bottom = 0;
- if (nsnull==aTableFrame) {
- return;
- }
- if (NS_STYLE_BORDER_SEPARATE == aTableFrame->GetBorderCollapseStyle()) {
- const nsStyleBorder* borderData;
- GetStyleData(eStyleStruct_Border, (const nsStyleStruct*&)borderData);
- borderData->GetBorder(aBorder);
- }
- else {
- NS_ASSERTION(PR_FALSE, "not implemented");
- }
+ const nsStyleBorder* borderData;
+ GetStyleData(eStyleStruct_Border, (const nsStyleStruct*&)borderData);
+ borderData->GetBorder(aBorder);
+ return &aBorder;
}
NS_IMETHODIMP
@@ -1502,3 +1448,100 @@ nsTableCellFrame::SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const
return NS_OK;
}
#endif
+
+// nsBCTableCellFrame
+
+nsBCTableCellFrame::nsBCTableCellFrame()
+:nsTableCellFrame()
+{
+ mTopBorder = mRightBorder = mBottomBorder = mLeftBorder = 0;
+}
+
+nsBCTableCellFrame::~nsBCTableCellFrame()
+{
+}
+
+NS_IMETHODIMP
+nsBCTableCellFrame::GetFrameType(nsIAtom** aType) const
+{
+ NS_PRECONDITION(nsnull != aType, "null OUT parameter pointer");
+ *aType = nsLayoutAtoms::bcTableCellFrame;
+ NS_ADDREF(*aType);
+ return NS_OK;
+}
+
+#ifdef DEBUG
+NS_IMETHODIMP
+nsBCTableCellFrame::GetFrameName(nsAString& aResult) const
+{
+ return MakeFrameName(NS_LITERAL_STRING("BCTableCell"), aResult);
+}
+#endif
+
+void
+nsBCTableCellFrame::SetBorderWidth(const nsMargin& aBorder)
+{
+ mTopBorder = aBorder.top;
+ mRightBorder = aBorder.right;
+ mBottomBorder = aBorder.bottom;
+ mLeftBorder = aBorder.left;
+}
+
+nsMargin*
+nsBCTableCellFrame::GetBorderWidth(float aPixelsToTwips,
+ nsMargin& aBorder) const
+{
+ aBorder.top = (aPixelsToTwips) ? NSToCoordRound(aPixelsToTwips * mTopBorder) : mTopBorder;
+ aBorder.right = (aPixelsToTwips) ? NSToCoordRound(aPixelsToTwips * mRightBorder) : mRightBorder;
+ aBorder.bottom = (aPixelsToTwips) ? NSToCoordRound(aPixelsToTwips * mBottomBorder): mBottomBorder;
+ aBorder.left = (aPixelsToTwips) ? NSToCoordRound(aPixelsToTwips * mLeftBorder): mLeftBorder;
+ return &aBorder;
+}
+
+nscoord
+nsBCTableCellFrame::GetBorderWidth(PRUint8 aSide) const
+{
+ switch(aSide) {
+ case NS_SIDE_TOP:
+ return (PRUint8)mTopBorder;
+ case NS_SIDE_RIGHT:
+ return (PRUint8)mRightBorder;
+ case NS_SIDE_BOTTOM:
+ return (PRUint8)mBottomBorder;
+ default:
+ return (PRUint8)mLeftBorder;
+ }
+}
+
+void
+nsBCTableCellFrame::SetBorderWidth(PRUint8 aSide,
+ nscoord aValue)
+{
+ switch(aSide) {
+ case NS_SIDE_TOP:
+ mTopBorder = aValue;
+ break;
+ case NS_SIDE_RIGHT:
+ mRightBorder = aValue;
+ break;
+ case NS_SIDE_BOTTOM:
+ mBottomBorder = aValue;
+ break;
+ default:
+ mLeftBorder = aValue;
+ }
+}
+
+#ifdef DEBUG
+NS_IMETHODIMP
+nsBCTableCellFrame::SizeOf(nsISizeOfHandler* aHandler,
+ PRUint32* aResult) const
+{
+ if (!aResult) {
+ return NS_ERROR_NULL_POINTER;
+ }
+ PRUint32 sum = sizeof(*this);
+ *aResult = sum;
+ return NS_OK;
+}
+#endif
diff --git a/mozilla/layout/tables/nsTableCellFrame.h b/mozilla/layout/tables/nsTableCellFrame.h
index bba34cedb09..06474bfe35e 100644
--- a/mozilla/layout/tables/nsTableCellFrame.h
+++ b/mozilla/layout/tables/nsTableCellFrame.h
@@ -43,6 +43,7 @@
#include "nsTableRowFrame.h" // need to actually include this here to inline GetRowIndex
#include "nsIStyleContext.h"
#include "nsIPercentHeightObserver.h"
+#include "nsLayoutAtoms.h"
class nsTableFrame;
class nsHTMLValue;
@@ -266,6 +267,9 @@ public:
nsTableCellFrame* GetNextCell() const;
+ virtual nsMargin* GetBorderWidth(float aPixelsToTwips,
+ nsMargin& aBorder) const;
+
protected:
/** implement abstract method on nsHTMLContainerFrame */
virtual PRIntn GetSkipSides() const;
@@ -277,18 +281,11 @@ private:
// All these methods are support methods for RecalcLayoutData
nsIFrame* GetFrameAt(nsVoidArray* aList, PRInt32 aIndex);
- //XXX: aTableFrame can be removed as soon as border-collapse inherits correctly
- void GetCellBorder(nsMargin &aBorder, nsTableFrame *aTableFrame);
-
protected:
friend class nsTableRowFrame;
void MapBorderPadding(nsIPresContext* aPresContext);
- void MapHTMLBorderStyle(nsIPresContext* aPresContext,
- nsStyleBorder& aBorderStyle,
- nsTableFrame* aTableFrame);
-
void MapVAlignAttribute(nsIPresContext* aPresContext, nsTableFrame *aTableFrame);
void MapHAlignAttribute(nsIPresContext* aPresContext, nsTableFrame *aTableFrame);
@@ -421,6 +418,41 @@ inline void nsTableCellFrame::SetLastBlockHeight(nscoord aValue)
{
mBits.mLastBlockHeight = aValue;
}
+
+// nsBCTableCellFrame
+class nsBCTableCellFrame : public nsTableCellFrame
+{
+public:
+
+ nsBCTableCellFrame();
+
+ ~nsBCTableCellFrame();
+
+ NS_IMETHOD GetFrameType(nsIAtom** aType) const;
+
+ virtual nsMargin* GetBorderWidth(float aPixelsToTwips,
+ nsMargin& aBorder) const;
+ nscoord GetBorderWidth(PRUint8 aSide) const;
+
+ void SetBorderWidth(const nsMargin& aBorder);
+ void SetBorderWidth(PRUint8 aSide, nscoord aPixelValue);
+
+#ifdef DEBUG
+ NS_IMETHOD GetFrameName(nsAString& aResult) const;
+ NS_IMETHOD SizeOf(nsISizeOfHandler* aSizer, PRUint32* aResult) const;
+#endif
+
+private:
+
+ PRUint32 mTopBorder: 8;
+ PRUint32 mRightBorder: 8;
+ PRUint32 mBottomBorder: 8;
+ PRUint32 mLeftBorder: 8;
+};
+
+#define IS_TABLE_CELL(frameType)\
+((nsLayoutAtoms::tableCellFrame == frameType) || (nsLayoutAtoms::bcTableCellFrame == frameType))
+
#endif
diff --git a/mozilla/layout/tables/nsTableColFrame.cpp b/mozilla/layout/tables/nsTableColFrame.cpp
index ba970d16d9b..38368963da6 100644
--- a/mozilla/layout/tables/nsTableColFrame.cpp
+++ b/mozilla/layout/tables/nsTableColFrame.cpp
@@ -113,7 +113,8 @@ nsStyleCoord nsTableColFrame::GetStyleWidth() const
nsStyleCoord styleWidth = position->mWidth;
// the following should not be necessary since html.css defines table-col and
// :table-col to inherit. However, :table-col is not inheriting properly
- if (eStyleUnit_Auto == styleWidth.GetUnit()) {
+ if (eStyleUnit_Auto == styleWidth.GetUnit() ||
+ eStyleUnit_Inherit == styleWidth.GetUnit()) {
nsIFrame* parent;
GetParent(&parent);
nsCOMPtr styleContext;
@@ -305,6 +306,22 @@ nsTableColFrame::Init(nsIPresContext* aPresContext,
return rv;
}
+nsTableColFrame*
+nsTableColFrame::GetNextCol() const
+{
+ nsIFrame* childFrame;
+ GetNextSibling(&childFrame);
+ while (childFrame) {
+ nsCOMPtr frameType;
+ childFrame->GetFrameType(getter_AddRefs(frameType));
+ if (nsLayoutAtoms::tableColFrame == frameType.get()) {
+ return (nsTableColFrame*)childFrame;
+ }
+ childFrame->GetNextSibling(&childFrame);
+ }
+ return nsnull;
+}
+
NS_IMETHODIMP
nsTableColFrame::GetFrameType(nsIAtom** aType) const
{
diff --git a/mozilla/layout/tables/nsTableColFrame.h b/mozilla/layout/tables/nsTableColFrame.h
index ba2d0042b04..505a84b3726 100644
--- a/mozilla/layout/tables/nsTableColFrame.h
+++ b/mozilla/layout/tables/nsTableColFrame.h
@@ -102,6 +102,8 @@ public:
void SetColIndex (PRInt32 aColIndex);
+ nsTableColFrame* GetNextCol() const;
+
NS_IMETHOD Init(nsIPresContext* aPresContext,
nsIContent* aContent,
nsIFrame* aParent,
@@ -164,6 +166,11 @@ public:
void ResetSizingInfo();
+ nscoord GetLeftBorderWidth(float* aPixelsToTwips = nsnull);
+ void SetLeftBorderWidth(nscoord aWidth);
+ nscoord GetRightBorderWidth(float* aPixelsToTwips = nsnull);
+ void SetRightBorderWidth(nscoord aWidth);
+
void Dump(PRInt32 aIndent);
protected:
@@ -172,17 +179,46 @@ protected:
~nsTableColFrame();
// the starting index of the column (starting at 0) that this col object represents //
- PRInt32 mColIndex;
+ PRUint32 mColIndex: 16;
+ PRUint32 mLeftBorderWidth: 8; // stored as pixels
+ PRUint32 mRightBorderWidth: 8; // stored as pixels
+ // Widths including MIN_CON, DES_CON, FIX_CON, MIN_ADJ, DES_ADJ, FIX_ADJ, PCT, PCT_ADJ, MIN_PRO, FINAL
// Widths including MIN_CON, DES_CON, FIX_CON, MIN_ADJ, DES_ADJ, FIX_ADJ, PCT, PCT_ADJ, MIN_PRO, FINAL
// XXX these could be stored as pixels and converted to twips for a savings of 10 x 2 bytes.
nscoord mWidths[NUM_WIDTHS];
};
inline PRInt32 nsTableColFrame::GetColIndex() const
-{ return mColIndex; }
+{
+ return mColIndex;
+}
inline void nsTableColFrame::SetColIndex (PRInt32 aColIndex)
-{ mColIndex = aColIndex; }
+{
+ mColIndex = aColIndex;
+}
+
+inline nscoord nsTableColFrame::GetLeftBorderWidth(float* aPixelsToTwips)
+{
+ nscoord width = (aPixelsToTwips) ? NSToCoordRound(*aPixelsToTwips * mLeftBorderWidth) : mLeftBorderWidth;
+ return width;
+}
+
+inline void nsTableColFrame::SetLeftBorderWidth(nscoord aWidth)
+{
+ mLeftBorderWidth = aWidth;
+}
+
+inline nscoord nsTableColFrame::GetRightBorderWidth(float* aPixelsToTwips)
+{
+ nscoord width = (aPixelsToTwips) ? NSToCoordRound(*aPixelsToTwips * mRightBorderWidth) : mRightBorderWidth;
+ return width;
+}
+
+inline void nsTableColFrame::SetRightBorderWidth(nscoord aWidth)
+{
+ mRightBorderWidth = aWidth;
+}
#endif
diff --git a/mozilla/layout/tables/nsTableColGroupFrame.cpp b/mozilla/layout/tables/nsTableColGroupFrame.cpp
index 15c7dab5216..41a96c8d000 100644
--- a/mozilla/layout/tables/nsTableColGroupFrame.cpp
+++ b/mozilla/layout/tables/nsTableColGroupFrame.cpp
@@ -250,29 +250,6 @@ nsTableColGroupFrame::SetInitialChildList(nsIPresContext* aPresContext,
return NS_OK;
}
- nsIFrame* kidFrame = aChildList;
- while (kidFrame) {
- nsIAtom* kidType;
- kidFrame->GetFrameType(&kidType);
- if (nsLayoutAtoms::tableColFrame == kidType) {
- // Set the preliminary values for the column frame
- PRInt32 span = ((nsTableColFrame*)kidFrame)->GetSpan();
- if (span > 1) {
- nsTableColFrame* firstSpannedCol;
- tableFrame->CreateAnonymousColFrames(*aPresContext, *this, span - 1, eColAnonymousCol,
- PR_FALSE, (nsTableColFrame*)kidFrame, (nsIFrame **)&firstSpannedCol);
- nsIFrame* spanner = kidFrame;
- kidFrame->GetNextSibling(&kidFrame); // need to do this before we insert the new frames
- nsFrameList newChildren(aChildList); // used as a convience to hook up siblings
- newChildren.InsertFrames(this, (nsTableColFrame*)spanner, (nsIFrame *)firstSpannedCol);
- NS_RELEASE(kidType);
- continue;
- }
- }
- NS_IF_RELEASE(kidType);
- kidFrame->GetNextSibling(&kidFrame);
- }
-
mFrames.AppendFrames(this, aChildList);
return NS_OK;
}
diff --git a/mozilla/layout/tables/nsTableFrame.cpp b/mozilla/layout/tables/nsTableFrame.cpp
index 7a2d5dc94d6..718136af383 100644
--- a/mozilla/layout/tables/nsTableFrame.cpp
+++ b/mozilla/layout/tables/nsTableFrame.cpp
@@ -38,7 +38,6 @@
#include "nsCOMPtr.h"
#include "nsVoidArray.h"
#include "nsTableFrame.h"
-#include "nsTableBorderCollapser.h"
#include "nsIRenderingContext.h"
#include "nsIStyleContext.h"
#include "nsStyleConsts.h"
@@ -75,6 +74,7 @@
#include "nsIScrollableFrame.h"
#include "nsHTMLReflowCommand.h"
#include "nsIFrameManager.h"
+#include "nsStyleUtil.h"
// helper function for dealing with placeholder for positioned/floated table
static void GetPlaceholderFor(nsIPresContext& aPresContext, nsIFrame& aFrame, nsIFrame** aPlaceholder);
@@ -108,17 +108,19 @@ struct nsTableReflowState {
// The first body section row group frame, i.e. not a header or footer
nsIFrame* firstBodySection;
- nsTableReflowState(const nsHTMLReflowState& aReflowState,
+ nsTableReflowState(nsIPresContext& aPresContext,
+ const nsHTMLReflowState& aReflowState,
nsTableFrame& aTableFrame,
nsReflowReason aReason,
nscoord aAvailWidth,
nscoord aAvailHeight)
: reflowState(aReflowState)
{
- Init(aTableFrame, aReason, aAvailWidth, aAvailHeight);
+ Init(aPresContext, aTableFrame, aReason, aAvailWidth, aAvailHeight);
}
- void Init(nsTableFrame& aTableFrame,
+ void Init(nsIPresContext& aPresContext,
+ nsTableFrame& aTableFrame,
nsReflowReason aReason,
nscoord aAvailWidth,
nscoord aAvailHeight)
@@ -126,7 +128,7 @@ struct nsTableReflowState {
reason = aReason;
nsTableFrame* table = (nsTableFrame*)aTableFrame.GetFirstInFlow();
- nsMargin borderPadding = table->GetBorderPadding(reflowState);
+ nsMargin borderPadding = table->GetChildAreaOffset(aPresContext, &reflowState);
x = borderPadding.left;
y = borderPadding.top;
@@ -145,23 +147,16 @@ struct nsTableReflowState {
firstBodySection = nsnull;
}
- nsTableReflowState(const nsHTMLReflowState& aReflowState,
+ nsTableReflowState(nsIPresContext& aPresContext,
+ const nsHTMLReflowState& aReflowState,
nsTableFrame& aTableFrame)
: reflowState(aReflowState)
{
- Init(aTableFrame, aReflowState.reason, aReflowState.availableWidth, aReflowState.availableHeight);
+ Init(aPresContext, aTableFrame, aReflowState.reason, aReflowState.availableWidth, aReflowState.availableHeight);
}
};
-nscoord
-GetHorBorderPaddingWidth(const nsHTMLReflowState& aReflowState,
- nsTableFrame* aTableFrame)
-{
- nsMargin borderPadding = aTableFrame->GetBorderPadding(aReflowState);
- return borderPadding.left + borderPadding.right;
-}
-
/********************************************************************************
** nsTableFrame **
********************************************************************************/
@@ -169,6 +164,18 @@ GetHorBorderPaddingWidth(const nsHTMLReflowState& aReflowState,
static PRInt32 gRflCount = 0;
#endif
+struct BCPropertyData
+{
+ BCPropertyData() { mDamageArea.x = mDamageArea.y = mDamageArea.width = mDamageArea.height =
+ mTopBorderWidth = mRightBorderWidth = mBottomBorderWidth = mLeftBorderWidth = 0; }
+ nsRect mDamageArea;
+ PRUint8 mTopBorderWidth;
+ PRUint8 mRightBorderWidth;
+ PRUint8 mBottomBorderWidth;
+ PRUint8 mLeftBorderWidth;
+};
+
+
NS_IMETHODIMP
nsTableFrame::GetFrameType(nsIAtom** aType) const
{
@@ -193,6 +200,8 @@ nsTableFrame::nsTableFrame()
mBits.mNeedStrategyBalance = PR_TRUE;
mBits.mCellSpansPctCol = PR_FALSE;
mBits.mRequestedTimeoutReflow = PR_FALSE;
+ mBits.mNeedToCalcBCBorders = PR_FALSE;
+ mBits.mIsBorderCollapse = PR_FALSE;
#ifdef DEBUG_TABLE_REFLOW_TIMING
mTimer = new nsReflowTimer(this);
@@ -236,11 +245,6 @@ nsTableFrame::Init(nsIPresContext* aPresContext,
{
nsresult rv;
- // Create the cell map
- // XXX Why do we do this for continuing frames?
- mCellMap = new nsTableCellMap(aPresContext, *this);
- if (!mCellMap) return NS_ERROR_OUT_OF_MEMORY;
-
// Let the base class do its processing
rv = nsHTMLContainerFrame::Init(aPresContext, aContent, aParent, aContext,
aPrevInFlow);
@@ -248,6 +252,16 @@ nsTableFrame::Init(nsIPresContext* aPresContext,
// record that children that are ignorable whitespace should be excluded
mState |= NS_FRAME_EXCLUDE_IGNORABLE_WHITESPACE;
+ // see if border collapse is on, if so set it
+ const nsStyleTableBorder* tableStyle =
+ (const nsStyleTableBorder*)mStyleContext->GetStyleData(eStyleStruct_TableBorder);
+ PRBool borderCollapse = (NS_STYLE_BORDER_COLLAPSE == tableStyle->mBorderCollapse);
+ SetBorderCollapse(borderCollapse);
+ // Create the cell map
+ // XXX Why do we do this for continuing frames?
+ mCellMap = new nsTableCellMap(aPresContext, *this, borderCollapse);
+ if (!mCellMap) return NS_ERROR_OUT_OF_MEMORY;
+
if (aPrevInFlow) {
// set my width, because all frames in a table flow are the same width and
// code in nsTableOuterFrame depends on this being set
@@ -477,10 +491,11 @@ nsTableFrame::SetInitialChildList(nsIPresContext* aPresContext,
// anonymous ones due to cells in rows.
InsertColGroups(*aPresContext, 0, mColGroups.FirstChild());
AppendRowGroups(*aPresContext, mFrames.FirstChild());
- }
-
- if (HasGroupRules()) {
- ProcessGroupRules(aPresContext);
+ // calc collapsing borders if this is the default (row group, col group, child list)
+ if (!aChildList && IsBorderCollapse()) {
+ nsRect damageArea(0, 0, GetColCount(), GetRowCount());
+ SetBCDamageArea(*aPresContext, damageArea);
+ }
}
return rv;
@@ -500,7 +515,7 @@ void nsTableFrame::AttributeChangedFor(nsIPresContext* aPresContext,
{
nsIAtom* frameType;
aFrame->GetFrameType(&frameType);
- if (nsLayoutAtoms::tableCellFrame == frameType) {
+ if (IS_TABLE_CELL(frameType)) {
if ((nsHTMLAtoms::rowspan == aAttribute) ||
(nsHTMLAtoms::colspan == aAttribute)) {
nsTableCellMap* cellMap = GetCellMap();
@@ -550,7 +565,7 @@ PRInt32 nsTableFrame::GetRowCount () const
}
/* return the col count including dead cols */
-PRInt32 nsTableFrame::GetColCount ()
+PRInt32 nsTableFrame::GetColCount () const
{
PRInt32 colCount = 0;
nsTableCellMap* cellMap = GetCellMap();
@@ -562,7 +577,7 @@ PRInt32 nsTableFrame::GetColCount ()
}
/* return the effective col count */
-PRInt32 nsTableFrame::GetEffectiveColCount ()
+PRInt32 nsTableFrame::GetEffectiveColCount() const
{
PRInt32 colCount = GetColCount();
// don't count cols at the end that don't have originating cells
@@ -659,66 +674,6 @@ PRInt32 nsTableFrame::GetEffectiveCOLSAttribute()
return result;
}
-PRBool nsTableFrame::HasGroupRules() const
-{
- const nsStyleTable* tableStyle = nsnull;
- GetStyleData(eStyleStruct_Table, (const nsStyleStruct *&)tableStyle);
- if (NS_STYLE_TABLE_RULES_GROUPS == tableStyle->mRules) {
- return PR_TRUE;
- }
- return PR_FALSE;
-}
-
-// this won't work until bug 12948 is resolved and col groups are considered
-void nsTableFrame::ProcessGroupRules(nsIPresContext* aPresContext)
-{
-#if 0
- // The RULES code below has been disabled because collapsing borders have been disabled
- // and RULES depend on collapsing borders
- PRInt32 numCols = GetColCount();
-
- // process row groups
- nsIFrame* iFrame;
- for (iFrame = mFrames.FirstChild(); iFrame; iFrame->GetNextSibling(&iFrame)) {
- nsIAtom* frameType;
- iFrame->GetFrameType(&frameType);
- if (nsLayoutAtoms::tableRowGroupFrame == frameType) {
- nsTableRowGroupFrame* rgFrame = (nsTableRowGroupFrame *)iFrame;
- PRInt32 startRow = rgFrame->GetStartRowIndex();
- PRInt32 numGroupRows = rgFrame->GetRowCount();
- PRInt32 endRow = startRow + numGroupRows - 1;
- if (startRow == endRow) {
- continue;
- }
- for (PRInt32 rowX = startRow; rowX <= endRow; rowX++) {
- for (PRInt32 colX = 0; colX < numCols; colX++) {
- PRBool originates;
- nsTableCellFrame* cell = GetCellInfoAt(rowX, colX, &originates);
- if (originates) {
- nsCOMPtr styleContext;
- cell->GetStyleContext(getter_AddRefs(styleContext));
- nsStyleBorder* border = (nsStyleBorder*)styleContext->GetMutableStyleData(eStyleStruct_Border);
- if (rowX == startRow) {
- border->SetBorderStyle(NS_SIDE_BOTTOM, NS_STYLE_BORDER_STYLE_NONE);
- }
- else if (rowX == endRow) {
- border->SetBorderStyle(NS_SIDE_TOP, NS_STYLE_BORDER_STYLE_NONE);
- }
- else {
- border->SetBorderStyle(NS_SIDE_TOP, NS_STYLE_BORDER_STYLE_NONE);
- border->SetBorderStyle(NS_SIDE_BOTTOM, NS_STYLE_BORDER_STYLE_NONE);
- }
- styleContext->RecalcAutomaticData(aPresContext);
- }
- }
- }
- }
- NS_IF_RELEASE(frameType);
- }
-#endif
-}
-
-
void nsTableFrame::AdjustRowIndices(nsIPresContext* aPresContext,
PRInt32 aRowIndex,
PRInt32 aAdjustment)
@@ -833,6 +788,11 @@ void nsTableFrame::InsertCol(nsIPresContext& aPresContext,
}
}
}
+ // for now, just bail and recalc all of the collapsing borders
+ if (IsBorderCollapse()) {
+ nsRect damageArea(0, 0, PR_MAX(1, GetColCount()), PR_MAX(1, GetRowCount()));
+ SetBCDamageArea(aPresContext, damageArea);
+ }
}
void nsTableFrame::RemoveCol(nsIPresContext& aPresContext,
@@ -850,6 +810,11 @@ void nsTableFrame::RemoveCol(nsIPresContext& aPresContext,
CreateAnonymousColFrames(aPresContext, 1, eColAnonymousCell, PR_TRUE);
}
}
+ // for now, just bail and recalc all of the collapsing borders
+ if (IsBorderCollapse()) {
+ nsRect damageArea(0, 0, GetColCount(), GetRowCount());
+ SetBCDamageArea(aPresContext, damageArea);
+ }
}
/** Get the cell map for this table frame. It is not always mCellMap.
@@ -1075,14 +1040,16 @@ nsTableFrame::CreateAnonymousColFrames(nsIPresContext& aPresContext,
}
}
-PRInt32 nsTableFrame::AppendCell(nsIPresContext& aPresContext,
- nsTableCellFrame& aCellFrame,
- PRInt32 aRowIndex)
+void
+nsTableFrame::AppendCell(nsIPresContext& aPresContext,
+ nsTableCellFrame& aCellFrame,
+ PRInt32 aRowIndex)
{
PRInt32 colIndex = 0;
nsTableCellMap* cellMap = GetCellMap();
if (cellMap) {
- colIndex = cellMap->AppendCell(aCellFrame, aRowIndex, PR_TRUE);
+ nsRect damageArea(0,0,0,0);
+ cellMap->AppendCell(aCellFrame, aRowIndex, PR_TRUE, damageArea);
PRInt32 numColsInMap = GetColCount();
PRInt32 numColsInCache = mColFrames.Count();
PRInt32 numColsToAdd = numColsInMap - numColsInCache;
@@ -1090,8 +1057,10 @@ PRInt32 nsTableFrame::AppendCell(nsIPresContext& aPresContext,
// this sets the child list, updates the col cache and cell map
CreateAnonymousColFrames(aPresContext, numColsToAdd, eColAnonymousCell, PR_TRUE);
}
+ if (IsBorderCollapse()) {
+ SetBCDamageArea(aPresContext, damageArea);
+ }
}
- return colIndex;
}
void nsTableFrame::InsertCells(nsIPresContext& aPresContext,
@@ -1101,7 +1070,8 @@ void nsTableFrame::InsertCells(nsIPresContext& aPresContext,
{
nsTableCellMap* cellMap = GetCellMap();
if (cellMap) {
- cellMap->InsertCells(aCellFrames, aRowIndex, aColIndexBefore);
+ nsRect damageArea(0,0,0,0);
+ cellMap->InsertCells(aCellFrames, aRowIndex, aColIndexBefore, damageArea);
PRInt32 numColsInMap = GetColCount();
PRInt32 numColsInCache = mColFrames.Count();
PRInt32 numColsToAdd = numColsInMap - numColsInCache;
@@ -1109,6 +1079,9 @@ void nsTableFrame::InsertCells(nsIPresContext& aPresContext,
// this sets the child list, updates the col cache and cell map
CreateAnonymousColFrames(aPresContext, numColsToAdd, eColAnonymousCell, PR_TRUE);
}
+ if (IsBorderCollapse()) {
+ SetBCDamageArea(aPresContext, damageArea);
+ }
}
}
@@ -1145,7 +1118,8 @@ void nsTableFrame::RemoveCell(nsIPresContext& aPresContext,
{
nsTableCellMap* cellMap = GetCellMap();
if (cellMap) {
- cellMap->RemoveCell(aCellFrame, aRowIndex);
+ nsRect damageArea(0,0,0,0);
+ cellMap->RemoveCell(aCellFrame, aRowIndex, damageArea);
PRInt32 numColsInMap = GetColCount(); // cell map's notion of num cols
PRInt32 numColsInCache = mColFrames.Count();
if (numColsInCache > numColsInMap) {
@@ -1156,6 +1130,10 @@ void nsTableFrame::RemoveCell(nsIPresContext& aPresContext,
}
}
else NS_ASSERTION(numColsInCache == numColsInMap, "cell map has too many cols");
+
+ if (IsBorderCollapse()) {
+ SetBCDamageArea(aPresContext, damageArea);
+ }
}
}
@@ -1217,9 +1195,10 @@ nsTableFrame::InsertRows(nsIPresContext& aPresContext,
PRInt32 numColsToAdd = 0;
nsTableCellMap* cellMap = GetCellMap();
if (cellMap) {
+ nsRect damageArea(0,0,0,0);
PRInt32 origNumRows = cellMap->GetRowCount();
PRInt32 numNewRows = aRowFrames.Count();
- cellMap->InsertRows(&aPresContext, aRowGroupFrame, aRowFrames, aRowIndex, aConsiderSpans);
+ cellMap->InsertRows(&aPresContext, aRowGroupFrame, aRowFrames, aRowIndex, aConsiderSpans, damageArea);
PRInt32 numColsInMap = GetColCount(); // cell map's notion of num cols
PRInt32 numColsInCache = mColFrames.Count();
numColsToAdd = numColsInMap - numColsInCache;
@@ -1237,6 +1216,9 @@ nsTableFrame::InsertRows(nsIPresContext& aPresContext,
nsTableRowFrame* rowFrame = (nsTableRowFrame *) aRowFrames.ElementAt(rowX);
rowFrame->SetRowIndex(aRowIndex + rowX);
}
+ if (IsBorderCollapse()) {
+ SetBCDamageArea(aPresContext, damageArea);
+ }
}
//printf("insertRowsAfter \n");
@@ -1262,7 +1244,7 @@ void nsTableFrame::RemoveRows(nsIPresContext& aPresContext,
for (nsIFrame* kidFrame = aFirstFrame.FirstChild(); (kidFrame && !stopAsking); kidFrame = kidFrame->GetNextSibling()) {
nsCOMPtr kidType;
kidFrame->GetFrameType(getter_AddRefs(frameType));
- if (nsLayoutAtoms::tableCellFrame == kidType.get()) {
+ if (IS_TABLE_CELL(kidType.get())) {
nsTableCellFrame* cellFrame = (nsTableCellFrame*)kidFrame;
stopTelling = tableFrame->CellChangedWidth(*cellFrame, cellFrame->GetPass1MaxElementWidth(),
cellFrame->GetMaximumWidth(), PR_TRUE);
@@ -1275,7 +1257,8 @@ void nsTableFrame::RemoveRows(nsIPresContext& aPresContext,
PRInt32 firstRowIndex = aFirstRowFrame.GetRowIndex();
nsTableCellMap* cellMap = GetCellMap();
if (cellMap) {
- cellMap->RemoveRows(&aPresContext, firstRowIndex, aNumRowsToRemove, aConsiderSpans);
+ nsRect damageArea(0,0,0,0);
+ cellMap->RemoveRows(&aPresContext, firstRowIndex, aNumRowsToRemove, aConsiderSpans, damageArea);
// only remove cols that are of type eTypeAnonymous cell (they are at the end)
PRInt32 numColsInMap = GetColCount(); // cell map's notion of num cols
PRInt32 numColsInCache = mColFrames.Count();
@@ -1287,6 +1270,10 @@ void nsTableFrame::RemoveRows(nsIPresContext& aPresContext,
}
}
else NS_ASSERTION(numColsInCache == numColsInMap, "cell map has too many cols");
+
+ if (IsBorderCollapse()) {
+ SetBCDamageArea(aPresContext, damageArea);
+ }
}
AdjustRowIndices(&aPresContext, firstRowIndex, -aNumRowsToRemove);
//printf("removeRowsAfter\n");
@@ -1307,7 +1294,7 @@ void nsTableFrame::AppendRowGroups(nsIPresContext& aPresContext,
nsTableRowGroupFrame*
nsTableFrame::GetRowGroupFrame(nsIFrame* aFrame,
- nsIAtom* aFrameTypeIn)
+ nsIAtom* aFrameTypeIn) const
{
nsIFrame* rgFrame = nsnull;
nsIAtom* frameType = aFrameTypeIn;
@@ -1479,12 +1466,12 @@ nsTableFrame::Paint(nsIPresContext* aPresContext,
}
PRIntn skipSides = GetSkipSides();
- if (NS_STYLE_BORDER_SEPARATE == GetBorderCollapseStyle()) {
- nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this,
- aDirtyRect, rect, *border, mStyleContext, skipSides);
+ if (IsBorderCollapse()) {
+ PaintBCBorders(aPresContext, aRenderingContext, aDirtyRect);
}
else {
- // tbd
+ nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this,
+ aDirtyRect, rect, *border, mStyleContext, skipSides);
}
}
}
@@ -1703,6 +1690,7 @@ nsTableFrame::SetColumnDimensions(nsIPresContext* aPresContext,
nscoord aHeight,
const nsMargin& aBorderPadding)
{
+ if (!aPresContext) ABORT0();
nscoord colHeight = aHeight -= aBorderPadding.top + aBorderPadding.bottom;
nscoord cellSpacingX = GetCellSpacingX();
@@ -1831,7 +1819,7 @@ nsTableFrame::NotifyAncestorsOfSpecialReflow(nsIFrame& aFrame)
for (aFrame.GetParent(&parent); parent; parent->GetParent(&parent)) {
nsCOMPtr frameType;
parent->GetFrameType(getter_AddRefs(frameType));
- if (nsLayoutAtoms::tableCellFrame == frameType.get()) {
+ if (IS_TABLE_CELL(frameType.get())) {
((nsTableCellFrame*)parent)->SetNeedSpecialReflow(PR_TRUE);
}
else if (nsLayoutAtoms::tableRowFrame == frameType.get()) {
@@ -1901,8 +1889,13 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext,
PRBool isPaginated;
aPresContext->IsPaginated(&isPaginated);
-
- PRBool doCollapse = PR_FALSE;
+
+ // see if collapsing borders need to be calculated
+ if (!mPrevInFlow && IsBorderCollapse() && NeedToCalcBCBorders()) {
+ GET_TWIPS_TO_PIXELS(aPresContext, p2t);
+ CalcBCBorders(*aPresContext);
+ }
+ PRBool doCollapse = PR_FALSE; // collapsing rows, cols, etc.
aDesiredSize.width = aReflowState.availableWidth;
@@ -1926,7 +1919,7 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext,
// only do pass1 reflow on an auto layout table
nsReflowReason reason = (eReflowReason_Initial == aReflowState.reason)
? eReflowReason_Initial : eReflowReason_StyleChange;
- nsTableReflowState reflowState(aReflowState, *this, reason,
+ nsTableReflowState reflowState(*aPresContext, aReflowState, *this, reason,
NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
// reflow the children
ReflowChildren(aPresContext, reflowState, !HaveReflowedColGroups(), PR_FALSE, aStatus);
@@ -1982,7 +1975,7 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext,
}
// see if an extra reflow will be necessary in pagination mode when there is a specified table height
else if (isPaginated && (NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight)) {
- nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aReflowState);
+ nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aPresContext, aReflowState);
if ((tableSpecifiedHeight > 0) &&
(tableSpecifiedHeight != NS_UNCONSTRAINEDSIZE)) {
SetNeedToInitiateSpecialReflow(PR_TRUE);
@@ -2047,7 +2040,8 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext,
}
#endif
- SetColumnDimensions(aPresContext, aDesiredSize.height, aReflowState.mComputedBorderPadding);
+ nsMargin borderPadding = GetChildAreaOffset(*aPresContext, &aReflowState);
+ SetColumnDimensions(aPresContext, aDesiredSize.height, borderPadding);
if (doCollapse) {
AdjustForCollapsingRows(aPresContext, aDesiredSize.height);
AdjustForCollapsingCols(aPresContext, aDesiredSize.width);
@@ -2111,7 +2105,7 @@ nsTableFrame::ReflowTable(nsIPresContext* aPresContext,
// Constrain our reflow width to the computed table width (of the 1st in flow).
// and our reflow height to our avail height minus border, padding, cellspacing
aDesiredSize.width = GetDesiredWidth();
- nsTableReflowState reflowState(aReflowState, *this, aReason,
+ nsTableReflowState reflowState(*aPresContext, aReflowState, *this, aReason,
aDesiredSize.width, aAvailHeight);
ReflowChildren(aPresContext, reflowState, haveReflowedColGroups, PR_FALSE, aStatus);
@@ -2292,7 +2286,7 @@ nsTableFrame::CollapseRowGroupIfNecessary(nsIPresContext* aPresContext,
PRInt32 numCols = cellMap->GetColCount();
nsTableCellFrame* lastCell = nsnull;
for (int colX = 0; colX < numCols; colX++) {
- CellData* cellData = cellMap->GetCellAt(aRowX, colX);
+ CellData* cellData = cellMap->GetDataAt(aRowX, colX);
if (cellData && cellData->IsSpan()) { // a cell above is spanning into here
// adjust the real cell's rect only once
nsTableCellFrame* realCell = nsnull;
@@ -2389,7 +2383,7 @@ NS_METHOD nsTableFrame::AdjustForCollapsingCols(nsIPresContext* aPresContext,
nsTableCellFrame* lastCell = nsnull;
nsTableCellFrame* cellFrame = nsnull;
for (PRInt32 rowX = 0; rowX < numRows; rowX++) {
- CellData* cellData = cellMap->GetCellAt(rowX, colX);
+ CellData* cellData = cellMap->GetDataAt(rowX, colX);
nsRect cellRect;
if (cellData) {
if (cellData->IsOrig()) { // the cell originates at (rowX, colX)
@@ -2670,7 +2664,7 @@ nsTableFrame::IncrementalReflow(nsIPresContext* aPresContext,
nsTableFrame* table = (nsTableFrame*)GetFirstInFlow();
lastWidth = table->mRect.width;
}
- nsTableReflowState state(aReflowState, *this, eReflowReason_Incremental,
+ nsTableReflowState state(*aPresContext, aReflowState, *this, eReflowReason_Incremental,
lastWidth, aReflowState.availableHeight);
// determine if this frame is the target or not
@@ -2721,7 +2715,7 @@ nsTableFrame::IR_TargetIsMe(nsIPresContext* aPresContext,
break;
case eReflowType_ReflowDirty: {
// reflow the dirty children
- nsTableReflowState reflowState(aReflowState.reflowState, *this, eReflowReason_Initial,
+ nsTableReflowState reflowState(*aPresContext, aReflowState.reflowState, *this, eReflowReason_Initial,
aReflowState.availSize.width, aReflowState.availSize.height);
PRBool reflowedAtLeastOne;
ReflowChildren(aPresContext, reflowState, PR_FALSE, PR_TRUE, aStatus, &reflowedAtLeastOne);
@@ -2753,25 +2747,127 @@ NS_METHOD nsTableFrame::IR_StyleChanged(nsIPresContext* aPresContext,
return NS_OK;
}
-nsMargin
-nsTableFrame::GetBorderPadding(const nsHTMLReflowState& aReflowState) const
+static void
+DivideBCBorderSize(nscoord aPixelSize,
+ nscoord& aSmallHalf,
+ nscoord& aLargeHalf)
+{
+ aSmallHalf = aPixelSize / 2;
+ aLargeHalf = ((aSmallHalf + aSmallHalf) < aPixelSize) ? aSmallHalf + 1 : aSmallHalf;
+}
+
+nsMargin*
+nsTableFrame::GetBCBorder(nsIPresContext& aPresContext,
+ PRBool aInnerBorderOnly,
+ nsMargin& aBorder) const
+{
+ aBorder.top = aBorder.right = aBorder.bottom = aBorder.left = 0;
+
+ GET_PIXELS_TO_TWIPS(&aPresContext, p2t);
+ BCPropertyData* propData =
+ (BCPropertyData*)nsTableFrame::GetProperty(&aPresContext, (nsIFrame*)this, nsLayoutAtoms::tableBCProperty, PR_FALSE);
+ if (propData) {
+ nsCompatibility mode;
+ aPresContext.GetCompatibilityMode(&mode);
+ if ((eCompatibility_Standard == mode) || aInnerBorderOnly) {
+ nscoord smallHalf, largeHalf;
+
+ DivideBCBorderSize(propData->mTopBorderWidth, smallHalf, largeHalf);
+ aBorder.top += NSToCoordRound(p2t * (float)smallHalf);
+
+ DivideBCBorderSize(propData->mRightBorderWidth, smallHalf, largeHalf);
+ aBorder.right += NSToCoordRound(p2t * (float)largeHalf);
+
+ DivideBCBorderSize(propData->mBottomBorderWidth, smallHalf, largeHalf);
+ aBorder.bottom += NSToCoordRound(p2t * (float)largeHalf);
+
+ DivideBCBorderSize(propData->mLeftBorderWidth, smallHalf, largeHalf);
+ aBorder.left += NSToCoordRound(p2t * (float)smallHalf);
+ }
+ else {
+ aBorder.top += NSToCoordRound(p2t * (float)propData->mTopBorderWidth);
+ aBorder.right += NSToCoordRound(p2t * (float)propData->mRightBorderWidth);
+ aBorder.bottom += NSToCoordRound(p2t * (float)propData->mBottomBorderWidth);
+ aBorder.left += NSToCoordRound(p2t * (float)propData->mLeftBorderWidth);
+ }
+ }
+ return &aBorder;
+}
+
+static
+void GetSeparateModelBorderPadding(nsIPresContext& aPresContext,
+ const nsHTMLReflowState* aReflowState,
+ nsIStyleContext& aStyleContext,
+ nsMargin& aBorderPadding)
{
const nsStyleBorder* border =
- (const nsStyleBorder*)mStyleContext->GetStyleData(eStyleStruct_Border);
- nsMargin borderPadding;
- border->GetBorder(borderPadding);
- borderPadding += aReflowState.mComputedPadding;
- return borderPadding;
+ (const nsStyleBorder*)aStyleContext.GetStyleData(eStyleStruct_Border);
+ border->GetBorder(aBorderPadding);
+ if (aReflowState) {
+ aBorderPadding += aReflowState->mComputedPadding;
+ }
+}
+
+nsMargin
+nsTableFrame::GetChildAreaOffset(nsIPresContext& aPresContext,
+ const nsHTMLReflowState* aReflowState) const
+{
+ nsMargin offset(0,0,0,0);
+ if (IsBorderCollapse()) {
+ nsCompatibility mode;
+ aPresContext.GetCompatibilityMode(&mode);
+ if (eCompatibility_NavQuirks == mode) {
+ nsTableFrame* firstInFlow = (nsTableFrame*)GetFirstInFlow(); if (!firstInFlow) ABORT1(offset);
+ nscoord smallHalf, largeHalf;
+ GET_PIXELS_TO_TWIPS(&aPresContext, p2t);
+ BCPropertyData* propData =
+ (BCPropertyData*)nsTableFrame::GetProperty(&aPresContext, (nsIFrame*)firstInFlow, nsLayoutAtoms::tableBCProperty, PR_FALSE);
+ if (!propData) ABORT1(offset);
+
+ DivideBCBorderSize(propData->mTopBorderWidth, smallHalf, largeHalf);
+ offset.top += NSToCoordRound(p2t * (float)largeHalf);
+
+ DivideBCBorderSize(propData->mRightBorderWidth, smallHalf, largeHalf);
+ offset.right += NSToCoordRound(p2t * (float)smallHalf);
+
+ DivideBCBorderSize(propData->mBottomBorderWidth, smallHalf, largeHalf);
+ offset.bottom += NSToCoordRound(p2t * (float)smallHalf);
+
+ DivideBCBorderSize(propData->mLeftBorderWidth, smallHalf, largeHalf);
+ offset.left += NSToCoordRound(p2t * (float)largeHalf);
+ }
+ }
+ else {
+ if (!mStyleContext) ABORT1(offset);
+ GetSeparateModelBorderPadding(aPresContext, aReflowState, *mStyleContext, offset);
+ }
+ return offset;
+}
+
+nsMargin
+nsTableFrame::GetContentAreaOffset(nsIPresContext& aPresContext,
+ const nsHTMLReflowState* aReflowState) const
+{
+ nsMargin offset(0,0,0,0);
+ if (IsBorderCollapse()) {
+ GetBCBorder(aPresContext, PR_FALSE, offset);
+ }
+ else {
+ if (!mStyleContext) ABORT1(offset);
+ GetSeparateModelBorderPadding(aPresContext, aReflowState, *mStyleContext, offset);
+ }
+ return offset;
}
// Recovers the reflow state to what it should be if aKidFrame is about to be
// reflowed. Restores y, footerFrame, firstBodySection and availSize.height (if
// the height is constrained)
nsresult
-nsTableFrame::RecoverState(nsTableReflowState& aReflowState,
+nsTableFrame::RecoverState(nsIPresContext& aPresContext,
+ nsTableReflowState& aReflowState,
nsIFrame* aKidFrame)
{
- nsMargin borderPadding = GetBorderPadding(aReflowState.reflowState);
+ nsMargin borderPadding = GetChildAreaOffset(aPresContext, &aReflowState.reflowState);
aReflowState.y = borderPadding.top;
nscoord cellSpacingY = GetCellSpacingY();
@@ -2827,6 +2923,23 @@ nsTableFrame::RecoverState(nsTableReflowState& aReflowState,
return NS_OK;
}
+void
+nsTableFrame::InitChildReflowState(nsIPresContext& aPresContext,
+ nsHTMLReflowState& aReflowState)
+{
+ nsMargin collapseBorder;
+ nsMargin padding(0,0,0,0);
+ nsMargin* pCollapseBorder = nsnull;
+ if (IsBorderCollapse()) {
+ nsTableRowGroupFrame* rgFrame = GetRowGroupFrame(aReflowState.frame);
+ if (rgFrame) {
+ GET_PIXELS_TO_TWIPS(&aPresContext, p2t);
+ pCollapseBorder = rgFrame->GetBCBorderWidth(p2t, collapseBorder);
+ }
+ }
+ aReflowState.Init(&aPresContext, -1, -1, pCollapseBorder, &padding);
+}
+
NS_METHOD
nsTableFrame::IR_TargetIsChild(nsIPresContext* aPresContext,
nsTableReflowState& aReflowState,
@@ -2834,9 +2947,10 @@ nsTableFrame::IR_TargetIsChild(nsIPresContext* aPresContext,
nsIFrame* aNextFrame)
{
+ if (!aPresContext) ABORT1(NS_ERROR_NULL_POINTER);
nsresult rv;
// Recover the state as if aNextFrame is about to be reflowed
- RecoverState(aReflowState, aNextFrame);
+ RecoverState(*aPresContext, aReflowState, aNextFrame);
// Remember the old rect
nsRect oldKidRect;
@@ -2844,8 +2958,10 @@ nsTableFrame::IR_TargetIsChild(nsIPresContext* aPresContext,
// Pass along the reflow command, don't request a max element size, rows will do that
nsHTMLReflowMetrics desiredSize(nsnull);
- nsHTMLReflowState kidReflowState(aPresContext, aReflowState.reflowState,
- aNextFrame, aReflowState.availSize);
+ nsSize kidAvailSize(aReflowState.availSize);
+ nsHTMLReflowState kidReflowState(aPresContext, aReflowState.reflowState, aNextFrame,
+ kidAvailSize, aReflowState.reason);
+ InitChildReflowState(*aPresContext, kidReflowState);
rv = ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState,
aReflowState.x, aReflowState.y, 0, aStatus);
@@ -2969,7 +3085,7 @@ nsTableFrame::OrderRowGroups(nsVoidArray& aChildren,
PRUint32& aNumRowGroups,
nsIFrame** aFirstBody,
nsTableRowGroupFrame** aHead,
- nsTableRowGroupFrame** aFoot)
+ nsTableRowGroupFrame** aFoot) const
{
aChildren.Clear();
nsIFrame* head = nsnull;
@@ -3069,6 +3185,10 @@ nsTableFrame::ReflowChildren(nsIPresContext* aPresContext,
PRBool isPaginated;
aPresContext->IsPaginated(&isPaginated);
+ nsMargin collapseBorder;
+ nsMargin padding(0,0,0,0);
+ GET_PIXELS_TO_TWIPS(aPresContext, p2t);
+
nsAutoVoidArray rowGroups;
PRUint32 numRowGroups;
nsTableRowGroupFrame *thead, *tfoot;
@@ -3117,8 +3237,9 @@ nsTableFrame::ReflowChildren(nsIPresContext* aPresContext,
if (childX < numRowGroups) {
// Reflow the child into the available space
- nsHTMLReflowState kidReflowState(aPresContext, aReflowState.reflowState,
- kidFrame, kidAvailSize, aReflowState.reason);
+ nsHTMLReflowState kidReflowState(aPresContext, aReflowState.reflowState, kidFrame,
+ kidAvailSize, aReflowState.reason);
+ InitChildReflowState(*aPresContext, kidReflowState);
// XXX fix up bad mComputedWidth for scroll frame
kidReflowState.mComputedWidth = PR_MAX(kidReflowState.mComputedWidth, 0);
@@ -3172,8 +3293,9 @@ nsTableFrame::ReflowChildren(nsIPresContext* aPresContext,
}
if (repeatedFooter) {
kidAvailSize.height = repeatedFooterHeight;
- nsHTMLReflowState footerReflowState(aPresContext, aReflowState.reflowState,
- repeatedFooter, kidAvailSize, aReflowState.reason);
+ nsHTMLReflowState footerReflowState(aPresContext, aReflowState.reflowState, repeatedFooter,
+ kidAvailSize, aReflowState.reason);
+ InitChildReflowState(*aPresContext, footerReflowState);
aReflowState.y += cellSpacingY;
nsReflowStatus footerStatus;
rv = ReflowChild(repeatedFooter, aPresContext, desiredSize, footerReflowState,
@@ -3268,7 +3390,7 @@ void nsTableFrame::BalanceColumnWidths(nsIPresContext* aPresContext,
nscoord minWidth, prefWidth;
CalcMinAndPreferredWidths(aPresContext, aReflowState, PR_FALSE, minWidth, prefWidth);
SetMinWidth(minWidth);
- nscoord desWidth = CalcDesiredWidth(aReflowState);
+ nscoord desWidth = CalcDesiredWidth(*aPresContext, aReflowState);
SetDesiredWidth(desWidth);
SetPreferredWidth(prefWidth);
@@ -3285,7 +3407,8 @@ void nsTableFrame::BalanceColumnWidths(nsIPresContext* aPresContext,
// This width is based on the column widths array of the table.
// sum the width of each column and add in table insets
nscoord
-nsTableFrame::CalcDesiredWidth(const nsHTMLReflowState& aReflowState)
+nsTableFrame::CalcDesiredWidth(nsIPresContext& aPresContext,
+ const nsHTMLReflowState& aReflowState)
{
NS_ASSERTION(!mPrevInFlow, "never ever call me on a continuing frame!");
nsTableCellMap* cellMap = GetCellMap();
@@ -3308,8 +3431,9 @@ nsTableFrame::CalcDesiredWidth(const nsHTMLReflowState& aReflowState)
if (numCols > 0) {
tableWidth += cellSpacing; // add last cellspacing
- // Compute the insets (sum of border and padding)
- tableWidth += GetHorBorderPaddingWidth(aReflowState, this);
+ // Add the width between the border edge and the child area
+ nsMargin childOffset = GetChildAreaOffset(aPresContext, &aReflowState);
+ tableWidth += childOffset.left + childOffset.right;
}
return tableWidth;
@@ -3326,7 +3450,7 @@ nsTableFrame::CalcDesiredHeight(nsIPresContext* aPresContext,
return 0;
}
nscoord cellSpacingY = GetCellSpacingY();
- nsMargin borderPadding = GetBorderPadding(aReflowState);
+ nsMargin borderPadding = GetChildAreaOffset(*aPresContext, &aReflowState);
// get the natural height based on the last child's (row group or scroll frame) rect
nsAutoVoidArray rowGroups;
@@ -3346,7 +3470,7 @@ nsTableFrame::CalcDesiredHeight(nsIPresContext* aPresContext,
// see if a specified table height requires dividing additional space to rows
if (!mPrevInFlow) {
- nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aReflowState);
+ nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aPresContext, aReflowState);
if ((tableSpecifiedHeight > 0) &&
(tableSpecifiedHeight != NS_UNCONSTRAINEDSIZE) &&
(tableSpecifiedHeight > desiredHeight)) {
@@ -3391,7 +3515,9 @@ nsTableFrame::DistributeHeightToRows(nsIPresContext* aPresContext,
nscoord cellSpacingY = GetCellSpacingY();
nscoord sumOfRowHeights = 0;
- nscoord rowGroupYPos = aReflowState.mComputedBorderPadding.top + cellSpacingY;
+ nsMargin borderPadding;
+ GetChildAreaOffset(*aPresContext, &aReflowState);
+ nscoord rowGroupYPos = borderPadding.top + cellSpacingY;
nsVoidArray rowGroups;
PRUint32 numRowGroups;
@@ -3402,7 +3528,7 @@ nsTableFrame::DistributeHeightToRows(nsIPresContext* aPresContext,
// height, and base the pct on the table height. If the row group had a computed
// height, then this was already done in nsTableRowGroupFrame::CalculateRowHeights
nscoord pctBasis = aReflowState.mComputedHeight - (GetCellSpacingY() * (GetRowCount() + 1));
- nscoord yOriginRG = aReflowState.mComputedBorderPadding.top + GetCellSpacingY();
+ nscoord yOriginRG = borderPadding.top + GetCellSpacingY();
nscoord yEndRG = yOriginRG;
PRUint32 rgX;
for (rgX = 0; (rgX < numRowGroups); rgX++) {
@@ -3503,7 +3629,7 @@ nsTableFrame::DistributeHeightToRows(nsIPresContext* aPresContext,
// allocate the extra height to the unstyled row groups and rows
pctBasis = aAmount - amountUsed;
- yOriginRG = aReflowState.mComputedBorderPadding.top + cellSpacingY;
+ yOriginRG = borderPadding.top + cellSpacingY;
yEndRG = yOriginRG;
for (rgX = 0; rgX < numRowGroups; rgX++) {
nsTableRowGroupFrame* rgFrame = GetRowGroupFrame((nsIFrame*)rowGroups.ElementAt(rgX));
@@ -3817,61 +3943,6 @@ void nsTableFrame::SetColumnWidth(PRInt32 aColIndex, nscoord aWidth)
}
}
-// Update the border style to map to the HTML border style
-void nsTableFrame::MapHTMLBorderStyle(nsStyleBorder& aBorderStyle, nscoord aBorderWidth)
-{
- nsStyleCoord width;
- width.SetCoordValue(aBorderWidth);
- aBorderStyle.mBorder.SetTop(width);
- aBorderStyle.mBorder.SetLeft(width);
- aBorderStyle.mBorder.SetBottom(width);
- aBorderStyle.mBorder.SetRight(width);
-
- aBorderStyle.SetBorderStyle(NS_SIDE_TOP, NS_STYLE_BORDER_STYLE_BG_OUTSET);
- aBorderStyle.SetBorderStyle(NS_SIDE_LEFT, NS_STYLE_BORDER_STYLE_BG_OUTSET);
- aBorderStyle.SetBorderStyle(NS_SIDE_BOTTOM, NS_STYLE_BORDER_STYLE_BG_OUTSET);
- aBorderStyle.SetBorderStyle(NS_SIDE_RIGHT, NS_STYLE_BORDER_STYLE_BG_OUTSET);
-
- nsIStyleContext* styleContext = mStyleContext;
- const nsStyleBackground* colorData = (const nsStyleBackground*)
- styleContext->GetStyleData(eStyleStruct_Background);
-
- // Look until we find a style context with a NON-transparent background color
- while (styleContext) {
- if ((colorData->mBackgroundFlags & NS_STYLE_BG_COLOR_TRANSPARENT) != 0) {
- nsIStyleContext* temp = styleContext;
- styleContext = styleContext->GetParent();
- if (temp != mStyleContext)
- NS_RELEASE(temp);
- colorData = (const nsStyleBackground*)styleContext->GetStyleData(eStyleStruct_Background);
- }
- else {
- break;
- }
- }
-
- // Yaahoo, we found a style context which has a background color
-
- nscolor borderColor = 0xFFC0C0C0;
-
- if (styleContext) {
- borderColor = colorData->mBackgroundColor;
- if (styleContext != mStyleContext)
- NS_RELEASE(styleContext);
- }
-
- // if the border color is white, then shift to grey
- if (borderColor == 0xFFFFFFFF)
- borderColor = 0xFFC0C0C0;
-
- aBorderStyle.SetBorderColor(NS_SIDE_TOP, borderColor);
- aBorderStyle.SetBorderColor(NS_SIDE_LEFT, borderColor);
- aBorderStyle.SetBorderColor(NS_SIDE_BOTTOM, borderColor);
- aBorderStyle.SetBorderColor(NS_SIDE_RIGHT, borderColor);
-
-}
-
-
PRBool nsTableFrame::ConvertToPixelValue(nsHTMLValue& aValue, PRInt32 aDefault, PRInt32& aResult)
{
@@ -3887,10 +3958,6 @@ PRBool nsTableFrame::ConvertToPixelValue(nsHTMLValue& aValue, PRInt32 aDefault,
return PR_TRUE;
}
-void nsTableFrame::MapBorderMarginPadding(nsIPresContext* aPresContext)
-{
-}
-
nscoord
CalcPercentPadding(nscoord aBasis,
nsStyleCoord aStyleCoord)
@@ -3977,24 +4044,13 @@ nsTableFrame::GetPadding(const nsSize& aBasis,
return padding;
}
-PRUint8 nsTableFrame::GetBorderCollapseStyle()
-{
- /* the following has been commented out to turn off collapsing borders
- const nsStyleTable* tableStyle;
- GetStyleData(eStyleStruct_Table, (const nsStyleStruct *&)tableStyle);
- return tableStyle->mBorderCollapse;*/
- return NS_STYLE_BORDER_SEPARATE;
-}
-
-
// XXX: could cache this. But be sure to check style changes if you do!
nscoord nsTableFrame::GetCellSpacingX()
{
- const nsStyleTableBorder* tableStyle;
- GetStyleData(eStyleStruct_TableBorder, (const nsStyleStruct *&)tableStyle);
nscoord cellSpacing = 0;
- PRUint8 borderCollapseStyle = GetBorderCollapseStyle();
- if (NS_STYLE_BORDER_COLLAPSE != borderCollapseStyle) {
+ if (!IsBorderCollapse()) {
+ const nsStyleTableBorder* tableStyle;
+ GetStyleData(eStyleStruct_TableBorder, (const nsStyleStruct *&)tableStyle);
if (tableStyle->mBorderSpacingX.GetUnit() == eStyleUnit_Coord) {
cellSpacing = tableStyle->mBorderSpacingX.GetCoordValue();
}
@@ -4005,11 +4061,10 @@ nscoord nsTableFrame::GetCellSpacingX()
// XXX: could cache this. But be sure to check style changes if you do!
nscoord nsTableFrame::GetCellSpacingY()
{
- const nsStyleTableBorder* tableStyle;
- GetStyleData(eStyleStruct_TableBorder, (const nsStyleStruct *&)tableStyle);
nscoord cellSpacing = 0;
- PRUint8 borderCollapseStyle = GetBorderCollapseStyle();
- if (NS_STYLE_BORDER_COLLAPSE != borderCollapseStyle) {
+ if (!IsBorderCollapse()) {
+ const nsStyleTableBorder* tableStyle;
+ GetStyleData(eStyleStruct_TableBorder, (const nsStyleStruct *&)tableStyle);
if (tableStyle->mBorderSpacingY.GetUnit() == eStyleUnit_Coord) {
cellSpacing = tableStyle->mBorderSpacingY.GetCoordValue();
}
@@ -4113,7 +4168,7 @@ nsTableFrame::CalcBorderBoxWidth(nsIPresContext* aPresContext,
}
}
else if (width != NS_UNCONSTRAINEDSIZE) {
- nsMargin borderPadding = aState.mComputedBorderPadding;
+ nsMargin borderPadding = GetContentAreaOffset(*aPresContext, &aState);
width += borderPadding.left + borderPadding.right;
}
width = PR_MAX(width, 0);
@@ -4128,11 +4183,12 @@ nsTableFrame::CalcBorderBoxWidth(nsIPresContext* aPresContext,
}
nscoord
-nsTableFrame::CalcBorderBoxHeight(const nsHTMLReflowState& aState)
+nsTableFrame::CalcBorderBoxHeight(nsIPresContext* aPresContext,
+ const nsHTMLReflowState& aState)
{
nscoord height = aState.mComputedHeight;
if (NS_AUTOHEIGHT != height) {
- nsMargin borderPadding = aState.mComputedBorderPadding;
+ nsMargin borderPadding = GetContentAreaOffset(*aPresContext, &aState);
height += borderPadding.top + borderPadding.bottom;
}
height = PR_MAX(0, height);
@@ -4180,6 +4236,7 @@ nsTableFrame::CalcMinAndPreferredWidths(nsIPresContext* aPresContext,
nscoord& aMinWidth,
nscoord& aPrefWidth)
{
+ if (!aPresContext) ABORT0();
aMinWidth = aPrefWidth = 0;
nscoord spacingX = GetCellSpacingX();
@@ -4201,7 +4258,8 @@ nsTableFrame::CalcMinAndPreferredWidths(nsIPresContext* aPresContext,
}
// if it is not a degenerate table, add the last spacing on the right and the borderPadding
if (numCols > 0) {
- nscoord extra = spacingX + GetHorBorderPaddingWidth(aReflowState, this);
+ nsMargin childAreaOffset = GetChildAreaOffset(*aPresContext, &aReflowState);
+ nscoord extra = spacingX + childAreaOffset.left + childAreaOffset.right;
aMinWidth += extra;
aPrefWidth += extra;
}
@@ -4217,14 +4275,15 @@ nsTableFrame::CalcMinAndPreferredWidths(nsIPresContext* aPresContext,
if (mTableLayoutStrategy && IsAutoLayout()) {
float p2t;
aPresContext->GetPixelsToTwips(&p2t);
- aPrefWidth = mTableLayoutStrategy->CalcPctAdjTableWidth(aReflowState, availWidth, p2t);
+ aPrefWidth = mTableLayoutStrategy->CalcPctAdjTableWidth(*aPresContext, aReflowState, availWidth, p2t);
}
}
}
else { // a specified fix width becomes the min or preferred width
nscoord compWidth = aReflowState.mComputedWidth;
if ((NS_UNCONSTRAINEDSIZE != compWidth) && (0 != compWidth) && !isPctWidth) {
- compWidth += GetHorBorderPaddingWidth(aReflowState, this);
+ nsMargin contentOffset = GetContentAreaOffset(*aPresContext, &aReflowState);
+ compWidth += contentOffset.left + contentOffset.right;
aMinWidth = PR_MAX(aMinWidth, compWidth);
aPrefWidth = PR_MAX(aMinWidth, compWidth);
}
@@ -4288,7 +4347,7 @@ nsTableFrame::DumpRowGroup(nsIPresContext* aPresContext, nsIFrame* aKidFrame)
while (cellFrame) {
nsIAtom* cellType;
cellFrame->GetFrameType(&cellType);
- if (nsLayoutAtoms::tableCellFrame == cellType) {
+ if (IS_TABLE_CELL(cellType)) {
PRInt32 colIndex;
((nsTableCellFrame*)cellFrame)->GetColIndex(colIndex);
printf("cell(%d)=%p ", colIndex, cellFrame);
@@ -4557,6 +4616,2361 @@ PRInt32 nsTableFrame::GetNumCellsOriginatingInRow(PRInt32 aRowIndex) const
return 0;
}
+/********************************************************************************
+ * Collapsing Borders
+ *
+ * The CSS spec says to resolve border 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.
+ *******************************************************************************/
+
+void
+nsTableFrame::SetBCDamageArea(nsIPresContext& aPresContext,
+ const nsRect& aValue)
+{
+ nsRect newRect(aValue);
+ newRect.width = PR_MAX(1, newRect.width);
+ newRect.height = PR_MAX(1, newRect.height);
+
+ if (!IsBorderCollapse()) {
+ NS_ASSERTION(PR_FALSE, "invalid call - not border collapse model");
+ return;
+ }
+ SetNeedToCalcBCBorders(PR_TRUE);
+ // Get the property
+ BCPropertyData* value = (BCPropertyData*)nsTableFrame::GetProperty(&aPresContext, this, nsLayoutAtoms::tableBCProperty, PR_TRUE);
+ if (value) {
+ // for now just construct a union of the new and old damage areas
+ value->mDamageArea.UnionRect(value->mDamageArea, newRect);
+ }
+}
+/*****************************************************************
+ * BCMapCellIterator
+ ****************************************************************/
+struct BCMapCellInfo
+{
+ BCMapCellInfo();
+ void Reset();
+
+ CellData* cellData;
+ nsCellMap* cellMap;
+
+ nsTableRowGroupFrame* rg;
+
+ nsTableRowFrame* topRow;
+ nsTableRowFrame* bottomRow;
+
+ nsTableColGroupFrame* cg;
+
+ nsTableColFrame* leftCol;
+ nsTableColFrame* rightCol;
+
+ nsBCTableCellFrame* cell;
+
+ PRInt32 rowIndex;
+ PRInt32 rowSpan;
+ PRInt32 colIndex;
+ PRInt32 colSpan;
+
+ PRPackedBool rgTop;
+ PRPackedBool rgBottom;
+ PRPackedBool cgLeft;
+ PRPackedBool cgRight;
+};
+
+BCMapCellInfo::BCMapCellInfo()
+{
+ Reset();
+}
+
+void BCMapCellInfo::Reset()
+{
+ cellData = nsnull;
+ rg = nsnull;
+ topRow = nsnull;
+ bottomRow = nsnull;
+ cg = nsnull;
+ leftCol = nsnull;
+ rightCol = nsnull;
+ cell = nsnull;
+ rowIndex = rowSpan = colIndex = colSpan = 0;
+ rgTop = rgBottom = cgLeft = cgRight = PR_FALSE;
+}
+
+class BCMapCellIterator
+{
+public:
+ BCMapCellIterator(nsTableFrame& aTableFrame,
+ const nsRect& aDamageArea);
+
+ void First(BCMapCellInfo& aMapCellInfo);
+
+ void Next(BCMapCellInfo& aMapCellInfo);
+
+ void PeekRight(BCMapCellInfo& aRefInfo,
+ PRUint32 aRowIndex,
+ BCMapCellInfo& aAjaInfo);
+
+ void PeekBottom(BCMapCellInfo& aRefInfo,
+ PRUint32 aColIndex,
+ BCMapCellInfo& aAjaInfo);
+
+ PRBool IsNewRow() { return mIsNewRow; }
+
+ nsTableRowFrame* GetPrevRow() const { return mPrevRow; }
+
+ PRInt32 mRowGroupStart;
+ PRInt32 mRowGroupEnd;
+ PRBool mAtEnd;
+ nsCellMap* mCellMap;
+
+private:
+ void SetInfo(nsTableRowFrame* aRow,
+ PRInt32 aColIndex,
+ CellData* aCellData,
+ BCMapCellInfo& aMapInfo,
+ nsCellMap* aCellMap = nsnull);
+
+ PRBool SetNewRow(nsTableRowFrame* row = nsnull);
+ PRBool SetNewRowGroup();
+
+ nsTableFrame& mTableFrame;
+ nsTableCellMap* mTableCellMap;
+ nsVoidArray mRowGroups;
+ nsTableRowGroupFrame* mRowGroup;
+ PRInt32 mRowGroupIndex;
+ PRUint32 mNumRows;
+ nsTableRowFrame* mRow;
+ nsTableRowFrame* mPrevRow;
+ PRBool mIsNewRow;
+ PRInt32 mRowIndex;
+ PRUint32 mNumCols;
+ PRInt32 mColIndex;
+ nsPoint mAreaStart;
+ nsPoint mAreaEnd;
+};
+
+BCMapCellIterator::BCMapCellIterator(nsTableFrame& aTableFrame,
+ const nsRect& aDamageArea)
+:mTableFrame(aTableFrame)
+{
+ mTableCellMap = aTableFrame.GetCellMap();
+
+ mAreaStart.x = aDamageArea.x;
+ mAreaStart.y = aDamageArea.y;
+ mAreaEnd.y = aDamageArea.y + aDamageArea.height - 1;
+ mAreaEnd.x = aDamageArea.x + aDamageArea.width - 1;
+
+ mNumRows = mTableFrame.GetRowCount();
+ mRow = nsnull;
+ mRowIndex = 0;
+ mNumCols = mTableFrame.GetColCount();
+ mColIndex = 0;
+ mRowGroupIndex = -1;
+
+ // Get the ordered row groups
+ PRUint32 numRowGroups;
+ aTableFrame.OrderRowGroups(mRowGroups, numRowGroups, nsnull);
+
+ mAtEnd = PR_TRUE; // gets reset when First() is called
+}
+
+void
+BCMapCellIterator::SetInfo(nsTableRowFrame* aRow,
+ PRInt32 aColIndex,
+ CellData* aCellData,
+ BCMapCellInfo& aCellInfo,
+ nsCellMap* aCellMap)
+{
+ aCellInfo.cellData = aCellData;
+ aCellInfo.cellMap = (aCellMap) ? aCellMap : mCellMap;
+ aCellInfo.colIndex = aColIndex;
+
+ // row frame info
+ aCellInfo.rowIndex = 0;
+ if (aRow) {
+ aCellInfo.topRow = aRow;
+ aCellInfo.rowIndex = aRow->GetRowIndex();
+ }
+
+ // cell frame info
+ aCellInfo.cell = nsnull;
+ aCellInfo.rowSpan = 1;
+ aCellInfo.colSpan = 1;
+ if (aCellData) {
+ aCellInfo.cell = (nsBCTableCellFrame*)aCellData->GetCellFrame();
+ if (aCellInfo.cell) {
+ if (!aCellInfo.topRow) {
+ aCellInfo.cell->GetParent((nsIFrame**)&aCellInfo.topRow); if (!aCellInfo.topRow) ABORT0();
+ aCellInfo.rowIndex = aCellInfo.topRow->GetRowIndex();
+ }
+ PRBool ignore;
+ PRInt32 rgRowIndex = aCellInfo.rowIndex - mRowGroupStart;
+ aCellInfo.colSpan = mCellMap->GetEffectiveColSpan(*mTableCellMap, rgRowIndex, aColIndex, ignore);
+ aCellInfo.rowSpan = mCellMap->GetRowSpan(*mTableCellMap, rgRowIndex, aColIndex, PR_TRUE, ignore);
+ }
+ }
+ if (!aCellInfo.topRow) {
+ aCellInfo.topRow = mRow;
+ }
+
+ if (1 == aCellInfo.rowSpan) {
+ aCellInfo.bottomRow = aCellInfo.topRow;
+ }
+ else {
+ aCellInfo.bottomRow = aCellInfo.topRow->GetNextRow();
+ if (aCellInfo.bottomRow) {
+ for (PRInt32 spanX = 2; aCellInfo.bottomRow && (spanX < aCellInfo.rowSpan); spanX++) {
+ aCellInfo.bottomRow = aCellInfo.bottomRow->GetNextRow();
+ }
+ NS_ASSERTION(aCellInfo.bottomRow, "program error");
+ }
+ else {
+ NS_ASSERTION(PR_FALSE, "error in cell map");
+ aCellInfo.rowSpan = 1;
+ aCellInfo.bottomRow = aCellInfo.topRow;
+ }
+ }
+
+ // row group frame info
+ PRUint32 rgStart = mRowGroupStart;
+ PRUint32 rgEnd = mRowGroupEnd;
+ nsIFrame* parentFrame = nsnull;
+ aCellInfo.topRow->GetParent((nsIFrame**)&parentFrame);
+ aCellInfo.rg = mTableFrame.GetRowGroupFrame(parentFrame);
+ if (aCellInfo.rg != mRowGroup) {
+ rgStart = aCellInfo.rg->GetStartRowIndex();
+ rgEnd = rgStart + aCellInfo.rg->GetRowCount() - 1;
+ }
+ PRUint32 rowIndex = aCellInfo.topRow->GetRowIndex();
+ aCellInfo.rgTop = (rgStart == rowIndex);
+ aCellInfo.rgBottom = (rgEnd == rowIndex + aCellInfo.rowSpan - 1);
+
+ // col frame info
+ aCellInfo.leftCol = mTableFrame.GetColFrame(aColIndex); if (!aCellInfo.leftCol) ABORT0();
+
+ aCellInfo.rightCol = aCellInfo.leftCol;
+ if (aCellInfo.colSpan > 1) {
+ for (PRInt32 spanX = 1; spanX < aCellInfo.colSpan; spanX++) {
+ nsTableColFrame* colFrame = aCellInfo.rightCol->GetNextCol();
+ if (colFrame) {
+ aCellInfo.rightCol = colFrame;
+ }
+ else {
+ NS_ASSERTION(PR_FALSE, "program error");
+ break;
+ }
+ }
+ }
+
+ // col group frame info
+ aCellInfo.leftCol->GetParent((nsIFrame**)&aCellInfo.cg);
+ PRInt32 cgStart = aCellInfo.cg->GetStartColumnIndex();
+ PRInt32 cgEnd = PR_MAX(0, cgStart + aCellInfo.cg->GetColCount() - 1);
+ aCellInfo.cgLeft = (cgStart == aColIndex);
+ aCellInfo.cgRight = (cgEnd == aColIndex + (PRInt32)aCellInfo.colSpan - 1);
+}
+
+PRBool
+BCMapCellIterator::SetNewRow(nsTableRowFrame* aRow)
+{
+ mPrevRow = mRow;
+ if (aRow) {
+ mRow = aRow;
+ }
+ else if (mRow) {
+ mRow = mRow->GetNextRow();
+ }
+ if (mRow) {
+ mRowIndex = mRow->GetRowIndex();
+ // get to the first entry with an originating cell
+ PRInt32 rgRowIndex = mRowIndex - mRowGroupStart;
+ nsVoidArray* row = (nsVoidArray*)mCellMap->mRows.ElementAt(rgRowIndex); if (!row) ABORT1(PR_FALSE);
+ PRInt32 rowSize = row->Count();
+ for (mColIndex = mAreaStart.x; mColIndex <= mAreaEnd.x; mColIndex++) {
+ CellData* cellData = (mColIndex < rowSize) ? (CellData*)row->ElementAt(mColIndex) : nsnull;
+ if (!cellData) { // add a dead cell data
+ nsRect damageArea;
+ cellData = mCellMap->AppendCell(*mTableCellMap, nsnull, rgRowIndex, PR_FALSE, damageArea); if (!cellData) ABORT1(PR_FALSE);
+ }
+ if (cellData && (cellData->IsOrig() || cellData->IsDead())) {
+ break;
+ }
+ }
+ mIsNewRow = PR_TRUE;
+ }
+ else {
+ NS_ASSERTION(PR_FALSE, "program error");
+ mAtEnd = PR_TRUE;
+ }
+ return !mAtEnd;
+}
+
+PRBool
+BCMapCellIterator::SetNewRowGroup()
+{
+ mRowGroupIndex++;
+ PRInt32 numRowGroups = mRowGroups.Count();
+ for (PRInt32 rgX = mRowGroupIndex; (rgX < numRowGroups) && !mAtEnd; rgX++) {
+ nsIFrame* frame = (nsTableRowGroupFrame*)mRowGroups.ElementAt(mRowGroupIndex); if (!frame) ABORT1(PR_FALSE);
+ mRowGroup = mTableFrame.GetRowGroupFrame(frame); if (!mRowGroup) ABORT1(PR_FALSE);
+ mRowGroupStart = mRowGroup->GetStartRowIndex();
+ mRowGroupEnd = mRowGroupStart + mRowGroup->GetRowCount() - 1;
+ if (mRowGroupEnd >= 0) {
+ mCellMap = mTableCellMap->GetMapFor(*mRowGroup);
+ if (SetNewRow(mRowGroup->GetFirstRow())) {
+ return PR_TRUE;
+ }
+ else mAtEnd = PR_TRUE;
+ }
+ }
+ mAtEnd = PR_TRUE;
+ return !mAtEnd;
+}
+
+void
+BCMapCellIterator::First(BCMapCellInfo& aMapInfo)
+{
+ mAtEnd = PR_FALSE;
+ aMapInfo.Reset();
+
+ SetNewRowGroup(); // could set mAtEnd
+ while (!mAtEnd) {
+ if ((mAreaStart.y >= mRowGroupStart) && (mAreaStart.y <= mRowGroupEnd)) {
+ CellData* cellData = mCellMap->GetDataAt(*mTableCellMap, mAreaStart.y - mRowGroupStart, mAreaStart.x, PR_FALSE);
+ if (cellData) {
+ if (!cellData->IsOrig()) {
+ // if the start data does not have an originating cell, adjust it to have one
+ if (cellData->IsRowSpan()) {
+ mAreaStart.y -= cellData->GetRowSpanOffset();
+ NS_ASSERTION(mAreaStart.y >= 0, "program error");
+ }
+ if (cellData->IsColSpan()) {
+ mAreaStart.x -= cellData->GetColSpanOffset();
+ NS_ASSERTION(mAreaStart.x >= 0, "program error");
+ }
+ cellData = mCellMap->GetDataAt(*mTableCellMap, mAreaStart.y - mRowGroupStart, mAreaStart.x, PR_FALSE);
+ }
+ if (cellData && cellData->IsOrig()) {
+ SetInfo(mRow, mAreaStart.x, cellData, aMapInfo);
+ break;
+ }
+ else mAtEnd = PR_TRUE;
+ }
+ else mAtEnd = PR_TRUE;
+ }
+ SetNewRowGroup(); // could set mAtEnd
+ }
+}
+
+void
+BCMapCellIterator::Next(BCMapCellInfo& aMapInfo)
+{
+ if (mAtEnd) ABORT0();
+ aMapInfo.Reset();
+
+ mIsNewRow = PR_FALSE;
+ mColIndex++;
+ while ((mRowIndex <= mAreaEnd.y) && !mAtEnd) {
+ for (; mColIndex <= mAreaEnd.x; mColIndex++) {
+ PRInt32 rgRowIndex = mRowIndex - mRowGroupStart;
+ CellData* cellData = mCellMap->GetDataAt(*mTableCellMap, rgRowIndex, mColIndex, PR_FALSE);
+ if (!cellData) { // add a dead cell data
+ nsRect damageArea;
+ cellData = mCellMap->AppendCell(*mTableCellMap, nsnull, rgRowIndex, PR_FALSE, damageArea); if (!cellData) ABORT0();
+ }
+ if (cellData && (cellData->IsOrig() || cellData->IsDead())) {
+ SetInfo(mRow, mColIndex, cellData, aMapInfo);
+ return;
+ }
+ }
+ if (mRowIndex >= mRowGroupEnd) {
+ SetNewRowGroup(); // could set mAtEnd
+ }
+ else {
+ SetNewRow(); // could set mAtEnd
+ }
+ }
+ mAtEnd = PR_TRUE;
+}
+
+void
+BCMapCellIterator::PeekRight(BCMapCellInfo& aRefInfo,
+ PRUint32 aRowIndex,
+ BCMapCellInfo& aAjaInfo)
+{
+ aAjaInfo.Reset();
+ PRInt32 colIndex = aRefInfo.colIndex + aRefInfo.colSpan;
+ PRUint32 rgRowIndex = aRowIndex - mRowGroupStart;
+
+ CellData* cellData = mCellMap->GetDataAt(*mTableCellMap, rgRowIndex, colIndex, PR_FALSE);
+ if (!cellData) { // add a dead cell data
+ NS_ASSERTION(colIndex < mTableCellMap->GetColCount(), "program error");
+ nsRect damageArea;
+ cellData = mCellMap->AppendCell(*mTableCellMap, nsnull, rgRowIndex, PR_FALSE, damageArea); if (!cellData) ABORT0();
+ }
+ nsTableRowFrame* row = nsnull;
+ if (cellData->IsRowSpan()) {
+ rgRowIndex -= cellData->GetRowSpanOffset();
+ cellData = mCellMap->GetDataAt(*mTableCellMap, rgRowIndex, colIndex, PR_FALSE); if (!cellData) ABORT0();
+ }
+ else {
+ row = mRow;
+ }
+ SetInfo(row, colIndex, cellData, aAjaInfo);
+}
+
+void
+BCMapCellIterator::PeekBottom(BCMapCellInfo& aRefInfo,
+ PRUint32 aColIndex,
+ BCMapCellInfo& aAjaInfo)
+{
+ aAjaInfo.Reset();
+ PRInt32 rowIndex = aRefInfo.rowIndex + aRefInfo.rowSpan;
+ PRInt32 rgRowIndex = rowIndex - mRowGroupStart;
+ nsTableRowGroupFrame* rg = mRowGroup;
+ nsCellMap* cellMap = mCellMap;
+ nsTableRowFrame* nextRow = nsnull;
+ if (rowIndex > mRowGroupEnd) {
+ nsIFrame* frame = (nsTableRowGroupFrame*)mRowGroups.ElementAt(mRowGroupIndex + 1); if (!frame) ABORT0();
+ rg = mTableFrame.GetRowGroupFrame(frame);
+ if (rg) {
+ cellMap = mTableCellMap->GetMapFor(*rg);
+ rgRowIndex = 0;
+ nextRow = rg->GetFirstRow();
+ }
+ else return;
+ }
+ else {
+ // get the row within the same row group
+ nextRow = mRow;
+ for (PRInt32 i = 0; i < aRefInfo.rowSpan; i++) {
+ nextRow = nextRow->GetNextRow(); if (!nextRow) ABORT0();
+ }
+ }
+
+ CellData* cellData = cellMap->GetDataAt(*mTableCellMap, rgRowIndex, aColIndex, PR_FALSE);
+ if (!cellData) { // add a dead cell data
+ NS_ASSERTION(rgRowIndex < cellMap->GetRowCount(), "program error");
+ nsRect damageArea;
+ cellData = cellMap->AppendCell(*mTableCellMap, nsnull, rgRowIndex, PR_FALSE, damageArea); if (!cellData) ABORT0();
+ }
+ if (cellData->IsColSpan()) {
+ aColIndex -= cellData->GetColSpanOffset();
+ cellData = cellMap->GetDataAt(*mTableCellMap, rowIndex, aColIndex, PR_FALSE);
+ }
+ SetInfo(nextRow, aColIndex, cellData, aAjaInfo, cellMap);
+}
+
+// Assign priorities to border styles. For example, styleToPriority(NS_STYLE_BORDER_STYLE_SOLID)
+// will return the priority of NS_STYLE_BORDER_STYLE_SOLID.
+static PRUint8 styleToPriority[13] = { 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 7, 1, 2 };
+
+// Set aStyle and aWidth given aStyleBorder and aSide
+static void
+GetStyleInfo(const nsIFrame& aFrame,
+ PRUint8 aSide,
+ PRUint8& aStyle,
+ nscolor& aColor,
+ PRBool aIgnoreIfRules = PR_FALSE,
+ nscoord* aWidth = nsnull,
+ float* aTwipsToPixels = nsnull)
+{
+ const nsStyleBorder* styleData;
+ aFrame.GetStyleData(eStyleStruct_Border, (const nsStyleStruct *&)styleData); if (!styleData) ABORT0();
+
+ aStyle = styleData->GetBorderStyle(aSide);
+
+ // if the rules mask is set, set the style either to none or remove the mask
+ if (NS_STYLE_BORDER_STYLE_RULES_MASK & aStyle) {
+ if (aIgnoreIfRules) {
+ aStyle = NS_STYLE_BORDER_STYLE_NONE;
+ aColor = 0;
+ if (aWidth) {
+ *aWidth = 0;
+ }
+ return;
+ }
+ else {
+ aStyle &= ~NS_STYLE_BORDER_STYLE_RULES_MASK;
+ }
+ }
+
+ if ((NS_STYLE_BORDER_STYLE_NONE == aStyle) || (NS_STYLE_BORDER_STYLE_HIDDEN == aStyle)) {
+ if (aWidth) {
+ *aWidth = 0;
+ aColor = 0;
+ }
+ return;
+ }
+
+ if ((NS_STYLE_BORDER_STYLE_INSET == aStyle) ||
+ (NS_STYLE_BORDER_STYLE_BG_INSET == aStyle)) {
+ aStyle = NS_STYLE_BORDER_STYLE_GROOVE;
+ }
+ else if ((NS_STYLE_BORDER_STYLE_OUTSET == aStyle) ||
+ (NS_STYLE_BORDER_STYLE_BG_OUTSET == aStyle)) {
+ aStyle = NS_STYLE_BORDER_STYLE_RIDGE;
+ }
+ PRBool transparent, foreground;
+ styleData->GetBorderColor(aSide, aColor, transparent, foreground);
+ if (foreground) {
+ nsCOMPtr styleContext;
+ aFrame.GetStyleContext(getter_AddRefs(styleContext)); if(!styleContext) ABORT0();
+ const nsStyleColor* colorStyle = (const nsStyleColor*)styleContext->GetStyleData(eStyleStruct_Color);
+ aColor = colorStyle->mColor;
+ }
+ if (aWidth && aTwipsToPixels) {
+ *aWidth = 0;
+ nscoord width;
+ styleData->CalcBorderFor(&aFrame, aSide, width);
+ *aWidth = NSToCoordRound(*aTwipsToPixels * (float)width);
+ }
+}
+
+static PRBool
+CalcDominateBorder(PRBool aIsCorner,
+ BCBorderOwner aOwner1,
+ PRUint8 aStyle1,
+ PRUint16 aWidth1,
+ nscolor aColor1,
+ BCBorderOwner aOwner2,
+ PRUint8 aStyle2,
+ PRUint16 aWidth2,
+ nscolor aColor2,
+ BCBorderOwner& aDomOwner,
+ PRUint8& aDomStyle,
+ PRUint16& aDomWidth,
+ nscolor& aDomColor,
+ PRBool aSecondIsHorizontal)
+{
+ PRBool firstDominates = PR_TRUE;
+ if (NS_STYLE_BORDER_STYLE_HIDDEN == aStyle1) {
+ firstDominates = (aIsCorner) ? PR_FALSE : PR_TRUE;
+ }
+ else if (NS_STYLE_BORDER_STYLE_HIDDEN == aStyle2) {
+ firstDominates = (aIsCorner) ? PR_TRUE : PR_FALSE;
+ }
+ else if (aWidth1 < aWidth2) {
+ firstDominates = PR_FALSE;
+ }
+ else if (aWidth1 == aWidth2) {
+ if (styleToPriority[aStyle1] < styleToPriority[aStyle2]) {
+ firstDominates = PR_FALSE;
+ }
+ else if (styleToPriority[aStyle1] == styleToPriority[aStyle2]) {
+ if (aOwner1 == aOwner2) {
+ firstDominates = !aSecondIsHorizontal;
+ }
+ else if (aOwner1 < aOwner2) {
+ firstDominates = PR_FALSE;
+ }
+ }
+ }
+ if (firstDominates) {
+ aDomOwner = aOwner1;
+ aDomStyle = aStyle1;
+ aDomWidth = aWidth1;
+ aDomColor = aColor1;
+ }
+ else {
+ aDomOwner = aOwner2;
+ aDomStyle = aStyle2;
+ aDomWidth = aWidth2;
+ aDomColor = aColor2;
+ }
+ return firstDominates;
+}
+
+// calc the dominate border by considering the table, row/col group, row/col, cell,
+static void
+CalcDominateBorder(const nsIFrame* aTableFrame,
+ const nsIFrame* aColGroupFrame,
+ const nsIFrame* aColFrame,
+ const nsIFrame* aRowGroupFrame,
+ const nsIFrame* aRowFrame,
+ const nsIFrame* aCellFrame,
+ PRBool aIgnoreIfRules,
+ PRUint8 aSide,
+ PRBool aAja,
+ float aTwipsToPixels,
+ BCBorderOwner& aDomElem,
+ PRUint8& aDomStyle,
+ PRUint16& aDomWidth,
+ nscolor& aDomColor)
+{
+ PRUint8 style;
+ nscolor color;
+ aDomStyle = NS_STYLE_BORDER_STYLE_NONE;
+ nscoord width;
+ aDomWidth = 0;
+ PRBool horizontal = (NS_SIDE_TOP == aSide) || (NS_SIDE_BOTTOM == aSide);
+
+ // start with the table as dominate if present
+ if (aTableFrame) {
+ GetStyleInfo(*aTableFrame, aSide, style, color, aIgnoreIfRules, &width, &aTwipsToPixels);
+ aDomStyle = style;
+ aDomWidth = width;
+ aDomColor = color;
+ aDomElem = eTableOwner;
+ if (NS_STYLE_BORDER_STYLE_HIDDEN == style) {
+ return;
+ }
+ }
+ // see if the col row group is dominate
+ if (aColGroupFrame) {
+ GetStyleInfo(*aColGroupFrame, aSide, style, color, aIgnoreIfRules, &width, &aTwipsToPixels);
+ if ((NS_STYLE_BORDER_STYLE_HIDDEN == style) ||
+ (width > aDomWidth) ||
+ ((width == aDomWidth) &&
+ (styleToPriority[style] >= styleToPriority[aDomStyle]))) {
+ aDomStyle = style;
+ aDomWidth = width;
+ aDomColor = color;
+ aDomElem = (aAja && !horizontal) ? eAjaColGroupOwner : eColGroupOwner;
+ if (NS_STYLE_BORDER_STYLE_HIDDEN == style) {
+ return;
+ }
+ }
+ }
+ // see if the col is dominate
+ if (aColFrame) {
+ GetStyleInfo(*aColFrame, aSide, style, color, aIgnoreIfRules, &width, &aTwipsToPixels);
+ if ((NS_STYLE_BORDER_STYLE_HIDDEN == style) ||
+ (width > aDomWidth) ||
+ ((width == aDomWidth) &&
+ (styleToPriority[style] >= styleToPriority[aDomStyle]))) {
+ aDomStyle = style;
+ aDomWidth = width;
+ aDomColor = color;
+ aDomElem = (aAja && !horizontal) ? eAjaColOwner : eColOwner;
+ if (NS_STYLE_BORDER_STYLE_HIDDEN == style) {
+ return;
+ }
+ }
+ }
+ // see if the row row group is dominate
+ if (aRowGroupFrame) {
+ GetStyleInfo(*aRowGroupFrame, aSide, style, color, aIgnoreIfRules, &width, &aTwipsToPixels);
+ if ((NS_STYLE_BORDER_STYLE_HIDDEN == style) ||
+ (width > aDomWidth) ||
+ ((width == aDomWidth) &&
+ (styleToPriority[style] >= styleToPriority[aDomStyle]))) {
+ aDomStyle = style;
+ aDomWidth = width;
+ aDomColor = color;
+ aDomElem = (aAja && horizontal) ? eAjaRowGroupOwner : eRowGroupOwner;
+ if (NS_STYLE_BORDER_STYLE_HIDDEN == style) {
+ return;
+ }
+ }
+ }
+ // see if the row is dominate
+ if (aRowFrame) {
+ GetStyleInfo(*aRowFrame, aSide, style, color, aIgnoreIfRules, &width, &aTwipsToPixels);
+ if ((NS_STYLE_BORDER_STYLE_HIDDEN == style) ||
+ (width > aDomWidth) ||
+ ((width == aDomWidth) &&
+ (styleToPriority[style] >= styleToPriority[aDomStyle]))) {
+ aDomStyle = style;
+ aDomWidth = width;
+ aDomColor = color;
+ aDomElem = (aAja && horizontal) ? eAjaRowOwner : eRowOwner;
+ if (NS_STYLE_BORDER_STYLE_HIDDEN == style) {
+ return;
+ }
+ }
+ }
+ // see if the cell is dominate
+ if (aCellFrame) {
+ GetStyleInfo(*aCellFrame, aSide, style, color, aIgnoreIfRules, &width, &aTwipsToPixels);
+ if ((NS_STYLE_BORDER_STYLE_HIDDEN == style) ||
+ (width > aDomWidth) ||
+ ((width == aDomWidth) &&
+ (styleToPriority[style] >= styleToPriority[aDomStyle]))) {
+ aDomStyle = style;
+ aDomWidth = width;
+ aDomColor = color;
+ aDomElem = (aAja) ? eAjaCellOwner : eCellOwner;
+ }
+ }
+}
+
+static PRBool
+Perpendicular(PRUint8 aSide1,
+ PRUint8 aSide2)
+{
+ switch (aSide1) {
+ case NS_SIDE_TOP:
+ return (NS_SIDE_BOTTOM != aSide2);
+ case NS_SIDE_RIGHT:
+ return (NS_SIDE_LEFT != aSide2);
+ case NS_SIDE_BOTTOM:
+ return (NS_SIDE_TOP != aSide2);
+ default: // NS_SIDE_LEFT
+ return (NS_SIDE_RIGHT != aSide2);
+ }
+}
+
+// XXX allocate this as number-of-cols+1 instead of number-of-cols+1 * number-of-rows+1
+struct BCCornerInfo
+{
+ BCCornerInfo() { ownerColor = 0; ownerWidth = subWidth = ownerSide = ownerElem = subSide =
+ subElem = hasDashDot = numSegs = bevel = 0;
+ ownerStyle = 0xFF; subStyle = NS_STYLE_BORDER_STYLE_SOLID; }
+ void Set(PRUint8 aSide,
+ BCBorderOwner aBorderOwner,
+ PRUint8 aOwnerBStyle,
+ nscoord aOwnerWidth,
+ nscolor aOwnerColor);
+
+ void Update(PRUint8 aSide,
+ BCBorderOwner aBorderOwner,
+ PRUint8 aOwnerBStyle,
+ nscoord aOwnerWidth,
+ nscolor aOwnerColor);
+
+ nscolor ownerColor; // color of borderOwner
+ PRUint16 ownerWidth; // pixel width of borderOwner
+ PRUint16 subWidth; // pixel width of the largest border intersecting the border perpendicular
+ // to ownerSide
+ PRUint32 ownerSide:2; // side (e.g NS_SIDE_TOP, NS_SIDE_RIGHT, etc) of the border owning
+ // the corner relative to the corner
+ PRUint32 ownerElem:3; // elem type (e.g. eTable, eGroup, etc) owning the corner
+ PRUint32 ownerStyle:8; // border style of ownerElem
+ PRUint32 subSide:2; // side of border with subWidth relative to the corner
+ PRUint32 subElem:3; // elem type (e.g. eTable, eGroup, etc) of sub owner
+ PRUint32 subStyle:8; // border style of subElem
+ PRUint32 hasDashDot:1; // does a dashed, dotted segment enter the corner, they cannot be beveled
+ PRUint32 numSegs:3; // number of segments entering corner
+ PRUint32 bevel:1; // is the corner beveled (uses the above two fields together with subWidth)
+ PRUint32 unused:1;
+};
+
+void
+BCCornerInfo::Set(PRUint8 aSide,
+ BCBorderOwner aBorderOwner,
+ PRUint8 aOwnerBStyle,
+ nscoord aOwnerWidth,
+ nscolor aOwnerColor)
+{
+ ownerElem = aBorderOwner;
+ ownerStyle = aOwnerBStyle;
+ ownerWidth = aOwnerWidth;
+ ownerColor = aOwnerColor;
+ ownerSide = aSide;
+ hasDashDot = 0;
+ numSegs = 0;
+ if (aOwnerWidth > 0) {
+ numSegs++;
+ hasDashDot = (NS_STYLE_BORDER_STYLE_DASHED == aOwnerBStyle) ||
+ (NS_STYLE_BORDER_STYLE_DOTTED == aOwnerBStyle);
+ }
+ bevel = 0;
+ subWidth = 0;
+ // the following will get set later
+ subSide = ((aSide == NS_SIDE_LEFT) || (aSide == NS_SIDE_RIGHT)) ? NS_SIDE_TOP : NS_SIDE_LEFT;
+ subElem = eTableOwner;
+ subStyle = NS_STYLE_BORDER_STYLE_SOLID;
+}
+
+void
+BCCornerInfo::Update(PRUint8 aSide,
+ BCBorderOwner aBorderOwner,
+ PRUint8 aOwnerBStyle,
+ nscoord aOwnerWidth,
+ nscolor aOwnerColor)
+{
+ PRBool existingWins = PR_FALSE;
+ if (0xFF == ownerStyle) { // initial value indiating that it hasn't been set yet
+ Set(aSide, aBorderOwner, aOwnerBStyle, aOwnerWidth, aOwnerColor);
+ }
+ else {
+ PRBool horizontal = (NS_SIDE_LEFT == aSide) || (NS_SIDE_RIGHT == aSide); // relative to the corner
+ PRUint8 oldElem = ownerElem;
+ PRUint8 oldSide = ownerSide;
+ PRUint8 oldStyle = ownerStyle;
+ nscoord oldWidth = ownerWidth;
+ BCBorderOwner tempBorderOwner = (BCBorderOwner)ownerElem;
+ PRUint8 tempStyle = ownerStyle;
+ existingWins =
+ CalcDominateBorder(PR_TRUE, (BCBorderOwner)ownerElem, ownerStyle, ownerWidth, ownerColor,
+ (BCBorderOwner)aBorderOwner, aOwnerBStyle, aOwnerWidth, aOwnerColor,
+ tempBorderOwner, tempStyle, ownerWidth, ownerColor, horizontal);
+ ownerElem = tempBorderOwner;
+ ownerStyle = tempStyle;
+ if (existingWins) { // existing corner is dominate
+ if (::Perpendicular(ownerSide, aSide)) {
+ // see if the new sub info replaces the old
+ nscolor color;
+ tempBorderOwner = (BCBorderOwner)ownerElem;
+ PRUint8 tempStyle = subStyle;
+ PRBool firstWins =
+ CalcDominateBorder(PR_TRUE, (BCBorderOwner)subElem, subStyle, subWidth, color,
+ (BCBorderOwner)aBorderOwner, aOwnerBStyle, aOwnerWidth, aOwnerColor,
+ tempBorderOwner, tempStyle, subWidth, color, horizontal);
+ subElem = tempBorderOwner;
+ subStyle = tempStyle;
+ if (firstWins) {
+ subSide = aSide;
+ }
+ }
+ }
+ else { // input args are dominate
+ ownerSide = aSide;
+ if (::Perpendicular(oldSide, ownerSide)) {
+ subElem = oldElem;
+ subSide = oldSide;
+ subStyle = oldStyle;
+ subWidth = oldWidth;
+ }
+ }
+ if (aOwnerWidth > 0) {
+ numSegs++;
+ if (!hasDashDot && ((NS_STYLE_BORDER_STYLE_DASHED == aOwnerBStyle) ||
+ (NS_STYLE_BORDER_STYLE_DOTTED == aOwnerBStyle))) {
+ hasDashDot = 1;
+ }
+ }
+
+ // bevel the corner if only two perpendicular non dashed/dotted segments enter the corner
+ bevel = (2 == numSegs) && (subWidth > 1) && (0 == hasDashDot);
+ }
+}
+
+struct BCCorners
+{
+ BCCorners(PRInt32 aNumCorners,
+ PRInt32 aStartIndex);
+
+ ~BCCorners() { delete [] corners; }
+
+ BCCornerInfo& operator [](PRInt32 i) const
+ { NS_ASSERTION((i >= startIndex) && (i <= endIndex), "program error");
+ return corners[i - startIndex]; }
+
+ PRInt32 startIndex;
+ PRInt32 endIndex;
+ BCCornerInfo* corners;
+};
+
+BCCorners::BCCorners(PRInt32 aNumCorners,
+ PRInt32 aStartIndex)
+{
+ NS_ASSERTION((aNumCorners > 0) && (aStartIndex >= 0), "program error");
+ startIndex = aStartIndex;
+ endIndex = aStartIndex + aNumCorners - 1;
+ corners = new BCCornerInfo[aNumCorners];
+}
+
+struct BCCellBorder
+{
+ BCCellBorder() { Reset(); }
+ void Reset(PRUint32 aIndex = 0, PRUint32 aSpan = 1);
+ nscolor color;
+ PRUint16 index; // y index, not used for vertical borders
+ PRUint16 span; // row span
+ PRUint16 width;
+ PRUint8 style;
+};
+
+void
+BCCellBorder::Reset(PRUint32 aIndex,
+ PRUint32 aSpan)
+{
+ style = color = width = -1;
+ index = (PRUint16)aIndex;
+ span = (PRUint16)aSpan;
+}
+
+struct BCCellBorders
+{
+ BCCellBorders(PRInt32 aNumBorders,
+ PRInt32 aStartIndex);
+
+ ~BCCellBorders() { delete [] borders; }
+
+ BCCellBorder& operator [](PRInt32 i) const
+ { NS_ASSERTION((i >= startIndex) && (i <= endIndex), "program error");
+ return borders[i - startIndex]; }
+
+ PRInt32 startIndex;
+ PRInt32 endIndex;
+ BCCellBorder* borders;
+};
+
+BCCellBorders::BCCellBorders(PRInt32 aNumBorders,
+ PRInt32 aStartIndex)
+{
+ NS_ASSERTION((aNumBorders > 0) && (aStartIndex >= 0), "program error");
+ startIndex = aStartIndex;
+ endIndex = aStartIndex + aNumBorders - 1;
+ borders = new BCCellBorder[aNumBorders];
+}
+
+static PRBool
+SetBorder(PRUint8 aOwnerBStyle,
+ PRUint16 aOwnerWidth,
+ nscolor aOwnerColor,
+ BCCellBorder& aBorder)
+{
+ PRBool changed = (aOwnerBStyle != aBorder.style) || (aOwnerWidth != aBorder.width) ||
+ (aOwnerColor != aBorder.color);
+ aBorder.color = aOwnerColor;
+ aBorder.width = aOwnerWidth;
+ aBorder.style = aOwnerBStyle;
+
+ return changed;
+}
+
+static PRBool
+SetHorBorder(PRUint8 aOwnerBStyle,
+ PRUint16 aOwnerWidth,
+ PRUint32 aOwnerColor,
+ const BCCornerInfo& aCorner,
+ BCCellBorder& aBorder)
+{
+ PRBool startSeg = ::SetBorder(aOwnerBStyle, aOwnerWidth, aOwnerColor, aBorder);
+ if (!startSeg) {
+ startSeg = ((NS_SIDE_LEFT != aCorner.ownerSide) && (NS_SIDE_RIGHT != aCorner.ownerSide));
+ }
+ return startSeg;
+}
+
+// Make the damage area larger on the top and bottom by at least one row and on the left and right
+// at least one column. This is done so that adjacent elements are part of the border calculations.
+// The extra segments and borders outside the actual damage area will not be updated in the cell map,
+// because they in turn would need info from adjacent segments outside the damage area to be accurate.
+void
+nsTableFrame::ExpandBCDamageArea(nsRect& aRect) const
+{
+ PRInt32 numRows = GetRowCount();
+ PRInt32 numCols = GetColCount();
+
+ PRInt32 dStartX = aRect.x;
+ PRInt32 dEndX = aRect.XMost() - 1;
+ PRInt32 dStartY = aRect.y;
+ PRInt32 dEndY = aRect.YMost() - 1;
+
+ // expand the damage area in each direction
+ if (dStartX > 0) {
+ dStartX--;
+ }
+ if (dEndX < (numCols - 1)) {
+ dEndX++;
+ }
+ if (dStartY > 0) {
+ dStartY--;
+ }
+ if (dEndY < (numRows - 1)) {
+ dEndY++;
+ }
+ // Check the damage area so that there are no cells spanning in or out. If there are any then
+ // make the damage area as big as the table, similarly to the way the cell map decides whether
+ // to rebuild versus expand. This could be optimized to expand to the smallest area that contains
+ // no spanners, but it may not be worth the effort in general, and it would need to be done in the
+ // cell map as well.
+ if ((dStartX > 0) || (dEndX < (numCols - 1)) || (dStartY > 0) || (dEndY < (numRows - 1))) {
+ nsTableCellMap* tableCellMap = GetCellMap(); if (!tableCellMap) ABORT0();
+ PRBool haveSpanner = PR_FALSE;
+ // Get the ordered row groups
+ PRUint32 numRowGroups;
+ nsVoidArray rowGroups;
+ OrderRowGroups(rowGroups, numRowGroups, nsnull);
+ for (PRUint32 rgX = 0; rgX < numRowGroups; rgX++) {
+ nsIFrame* kidFrame = (nsIFrame*)rowGroups.ElementAt(rgX);
+ nsTableRowGroupFrame* rgFrame = GetRowGroupFrame(kidFrame); if (!rgFrame) ABORT0();
+ PRInt32 rgStartY = rgFrame->GetStartRowIndex();
+ PRInt32 rgEndY = rgStartY + rgFrame->GetRowCount() - 1;
+ if (dEndY < rgStartY)
+ break;
+ nsCellMap* cellMap = tableCellMap->GetMapFor(*rgFrame); if (!cellMap) ABORT0();
+ // check for spanners from above and below
+ if ((dStartY > 0) && (dStartY >= rgStartY) && (dStartY <= rgEndY)) {
+ nsVoidArray* row = (nsVoidArray*)cellMap->mRows.ElementAt(dStartY - rgStartY); if (!row) ABORT0();
+ for (PRInt32 x = dStartX; x <= dEndX; x++) {
+ CellData* cellData = (row->Count() > x) ? (CellData*)row->ElementAt(x) : nsnull;
+ if (cellData && (cellData->IsRowSpan())) {
+ haveSpanner = PR_TRUE;
+ break;
+ }
+ }
+ if (dEndY < rgEndY) {
+ row = (nsVoidArray*)cellMap->mRows.ElementAt(dEndY + 1 - rgStartY); if (!row) ABORT0();
+ for (PRInt32 x = dStartX; x <= dEndX; x++) {
+ CellData* cellData = (row->Count() > x) ? (CellData*)row->ElementAt(x) : nsnull;
+ if (cellData && (cellData->IsRowSpan())) {
+ haveSpanner = PR_TRUE;
+ break;
+ }
+ }
+ }
+ }
+ // check for spanners on the left and right
+ PRInt32 iterStartY = -1;
+ PRInt32 iterEndY = -1;
+ if ((dStartY >= rgStartY) && (dStartY <= rgEndY)) {
+ // the damage area starts in the row group
+ iterStartY = dStartY;
+ iterEndY = PR_MIN(dEndY, rgEndY);
+ }
+ else if ((dEndY >= rgStartY) && (dEndY <= rgEndY)) {
+ // the damage area ends in the row group
+ iterStartY = rgStartY;
+ iterEndY = PR_MIN(dEndY, rgStartY);
+ }
+ else if ((rgStartY >= dStartY) && (rgEndY <= dEndY)) {
+ // the damage area contains the row group
+ iterStartY = rgStartY;
+ iterEndY = rgEndY;
+ }
+ if ((iterStartY >= 0) && (iterEndY >= 0)) {
+ for (PRInt32 y = iterStartY; y <= iterEndY; y++) {
+ nsVoidArray* row = (nsVoidArray*)cellMap->mRows.ElementAt(y - rgStartY); if (!row) ABORT0();
+ CellData* cellData = (CellData*)row->ElementAt(dStartX);
+ if (cellData && (cellData->IsColSpan())) {
+ haveSpanner = PR_TRUE;
+ break;
+ }
+ if (dEndX < (numCols - 1)) {
+ cellData = (row->Count() > dEndX) ? (CellData*)row->ElementAt(dEndX + 1) : nsnull;
+ if (cellData && (cellData->IsColSpan())) {
+ haveSpanner = PR_TRUE;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ aRect.x = dStartX;
+ aRect.y = dStartY;
+ aRect.width = 1 + dEndX - dStartX;
+ aRect.height = 1 + dEndY - dStartY;
+}
+
+#define MAX_TABLE_BORDER_WIDTH 256
+static PRUint8
+LimitBorderWidth(PRUint16 aWidth)
+{
+ return PR_MIN(MAX_TABLE_BORDER_WIDTH, aWidth);
+}
+
+/* Here is the order for storing border edges in the cell map as a cell is processed. There are
+ n=colspan top and bottom border edges per cell and n=rowspan left and right border edges per cell.
+
+ 1) On the top edge of the table, store the top edge. Never store the top edge otherwise, since
+ a bottom edge from a cell above will take care of it.
+ 2) On the left edge of the table, store the left edge. Never store the left edge othewise, since
+ a right edge from a cell to the left will take care of it.
+ 3) Store the right edge (or edges if a row span)
+ 4) Store the bottom edge (or edges if a col span)
+
+ Since corners are computed with only an array of BCCornerInfo indexed by the number-of-cols, corner
+ calculations are somewhat complicated. Using an array with number-of-rows * number-of-col entries
+ would simplify this, but at an extra in memory cost of nearly 12 bytes per cell map entry. Collapsing
+ borders already have about an extra 8 byte per cell map entry overhead (this could be
+ reduced to 4 bytes if we are willing to not store border widths in nsTableCellFrame), Here are the
+ rules in priority order for storing cornes in the cell map as a cell is processed. top-left means the
+ left endpoint of the border edge on the top of the cell. There are n=colspan top and bottom border
+ edges per cell and n=rowspan left and right border edges per cell.
+
+ 1) On the top edge of the table, store the top-left corner, unless on the left edge of the table.
+ Never store the top-right corner, since it will get stored as a right-top corner.
+ 2) On the left edge of the table, store the left-top corner. Never store the left-bottom corner,
+ since it will get stored as a bottom-left corner.
+ 3) Store the right-top corner if (a) it is the top right corner of the table or (b) it is not on
+ the top edge of the table. Never store the right-bottom corner since it will get stored as a
+ bottom-right corner.
+ 4) Store the bottom-right corner, if it is the bottom right corner of the table. Never store it
+ otherwise, since it will get stored as either a right-top corner by a cell below or
+ a bottom-left corner from a cell to the right.
+ 5) Store the bottom-left corner, if (a) on the bottom edge of the table or (b) if the left edge hits
+ the top side of a colspan in its interior. Never store the corner otherwise, since it will
+ get stored as a right-top corner by a cell from below.
+ */
+
+#define TOP_DAMAGED(aRowIndex) ((aRowIndex) >= propData->mDamageArea.y)
+#define RIGHT_DAMAGED(aColIndex) ((aColIndex) <= propData->mDamageArea.XMost())
+#define BOTTOM_DAMAGED(aRowIndex) ((aRowIndex) <= propData->mDamageArea.YMost())
+#define LEFT_DAMAGED(aColIndex) ((aColIndex) >= propData->mDamageArea.x)
+
+// Calc the dominate border at every cell edge and corner within the current damage area
+void
+nsTableFrame::CalcBCBorders(nsIPresContext& aPresContext)
+{
+ nsTableCellMap* tableCellMap = GetCellMap(); if (!tableCellMap) ABORT0();
+ PRInt32 numRows = GetRowCount();
+ PRInt32 numCols = GetColCount();
+
+ // Get the property holding the table damage area and border widths
+ BCPropertyData* propData =
+ (BCPropertyData*)nsTableFrame::GetProperty(&aPresContext, this, nsLayoutAtoms::tableBCProperty, PR_FALSE);
+ if (!propData) ABORT0();
+ // calculate an expanded damage area
+ nsRect damageArea(propData->mDamageArea);
+ ExpandBCDamageArea(damageArea);
+
+ // segments that are on the table border edges need to be initialized only once
+ PRBool tableBorderReset[4];
+ for (PRUint32 sideX = NS_SIDE_TOP; sideX <= NS_SIDE_LEFT; sideX++) {
+ tableBorderReset[sideX] = PR_FALSE;
+ }
+ GET_TWIPS_TO_PIXELS(&aPresContext, t2p);
+
+ const nsStyleBorder* tableStyle =
+ (const nsStyleBorder*)mStyleContext->GetStyleData(eStyleStruct_Border);
+
+ // vertical borders indexed in x-direction (cols)
+ BCCellBorders lastVerBorders(damageArea.width + 1, damageArea.x); if (!lastVerBorders.borders) ABORT0();
+ BCCellBorder lastTopBorder, lastBottomBorder;
+ // horizontal borders indexed in x-direction (cols)
+ BCCellBorders lastBottomBorders(damageArea.width + 1, damageArea.x); if (!lastBottomBorders.borders) ABORT0();
+ PRBool startSeg;
+
+ BCMapCellInfo info, ajaInfo;
+ BCBorderOwner owner, ajaOwner;
+ nscolor ownerColor, ajaColor;
+ PRUint8 ownerBStyle, ajaBStyle;
+ PRUint16 ownerWidth, ajaWidth;
+ PRInt32 cellEndRowIndex = -1;
+ PRInt32 cellEndColIndex = -1;
+ nscoord smallHalf, largeHalf;
+ BCCorners topCorners(damageArea.width + 1, damageArea.x); if (!topCorners.corners) ABORT0();
+ BCCorners bottomCorners(damageArea.width + 1, damageArea.x); if (!bottomCorners.corners) ABORT0();
+ nsTableRowFrame* prevRow = nsnull;
+
+ BCMapCellIterator iter(*this, damageArea);
+ for (iter.First(info); !iter.mAtEnd; iter.Next(info)) {
+
+ cellEndRowIndex = info.rowIndex + info.rowSpan - 1;
+ cellEndColIndex = info.colIndex + info.colSpan - 1;
+ PRBool isBottomRight = (info.rowIndex == (numRows - 1)) && (info.colIndex == (numCols - 1));
+
+ PRBool bottomRowSpan = PR_FALSE;
+ // see if lastTopBorder, lastBottomBorder need to be reset
+ if (iter.IsNewRow()) {
+ lastTopBorder.Reset(info.rowIndex, info.rowSpan);
+ lastBottomBorder.Reset(cellEndRowIndex + 1, info.rowSpan);
+ }
+ else if (info.colIndex > damageArea.x) {
+ BCCellBorder& prevBorder = lastBottomBorders[info.colIndex - 1];
+ if (info.rowIndex > prevBorder.index - prevBorder.span) {
+ // the top border's left edge butts against the middle of a rowspan
+ lastTopBorder.Reset(info.rowIndex, info.rowSpan);
+ }
+ if (prevBorder.index > (cellEndRowIndex + 1)) {
+ // the bottom border's left edge butts against the middle of a rowspan
+ lastBottomBorder.Reset(cellEndRowIndex + 1, info.rowSpan);
+ bottomRowSpan = PR_TRUE;
+ }
+ }
+
+ // find the dominate border considernig the cell's top border and the table, row group, row
+ // if the border is at the top of the table, otherwise it was processed in a previous row
+ if (0 == info.rowIndex) {
+ if (!tableBorderReset[NS_SIDE_TOP]) {
+ propData->mTopBorderWidth = 0;
+ tableBorderReset[NS_SIDE_TOP] = PR_TRUE;
+ }
+ for (PRInt32 colX = info.colIndex; colX <= cellEndColIndex; colX++) {
+ nsIFrame* colFrame = GetColFrame(colX); if (!colFrame) ABORT0();
+ nsIFrame* cgFrame;
+ colFrame->GetParent(&cgFrame); if (!cgFrame) ABORT0();
+ CalcDominateBorder(this, cgFrame, colFrame, info.rg, info.topRow, info.cell, PR_TRUE, NS_SIDE_TOP,
+ PR_FALSE, t2p, owner, ownerBStyle, ownerWidth, ownerColor);
+ // update/store the top left & top right corners of the seg
+ BCCornerInfo& tlCorner = topCorners[colX]; // top left
+ if (0 == colX) {
+ tlCorner.Set(NS_SIDE_RIGHT, owner, ownerBStyle, ownerWidth, ownerColor);
+ }
+ else {
+ tlCorner.Update(NS_SIDE_RIGHT, owner, ownerBStyle, ownerWidth, ownerColor);
+ tableCellMap->SetBCBorderCorner(eTopLeft, *info.cellMap, 0, 0, colX,
+ tlCorner.ownerSide, tlCorner.subWidth, tlCorner.bevel);
+ }
+ topCorners[colX + 1].Set(NS_SIDE_LEFT, owner, ownerBStyle, ownerWidth, ownerColor); // top right
+ // update lastTopBorder and see if a new segment starts
+ startSeg = SetHorBorder(ownerBStyle, ownerWidth, ownerColor, tlCorner, lastTopBorder);
+ // store the border segment in the cell map
+ tableCellMap->SetBCBorderEdge(NS_SIDE_TOP, *info.cellMap, 0, 0, colX,
+ 1, owner, ownerWidth, startSeg);
+ // update the affected borders of the cell, row, and table
+ DivideBCBorderSize(ownerWidth, smallHalf, largeHalf);
+ if (info.cell) {
+ info.cell->SetBorderWidth(NS_SIDE_TOP, PR_MAX(smallHalf, info.cell->GetBorderWidth(NS_SIDE_TOP)));
+ }
+ if (info.topRow) {
+ info.topRow->SetTopBCBorderWidth(PR_MAX(smallHalf, info.topRow->GetTopBCBorderWidth()));
+ }
+ propData->mTopBorderWidth = LimitBorderWidth(PR_MAX(propData->mTopBorderWidth, (PRUint8)ownerWidth));
+ }
+ }
+ else {
+ // see if the top border needs to be the start of a segment due to a vertical border owning the corner
+ if (info.colIndex > 0) {
+ BCData& data = ((BCCellData*)info.cellData)->mData;
+ if (!data.IsTopStart()) {
+ PRUint8 cornerSide;
+ PRPackedBool bevel;
+ data.GetCorner(cornerSide, bevel);
+ if ((NS_SIDE_TOP == cornerSide) || (NS_SIDE_BOTTOM == cornerSide)) {
+ data.SetTopStart(PR_TRUE);
+ }
+ }
+ }
+ }
+
+ // find the dominate border considernig the cell's left border and the table, col group, col
+ // if the border is at the left of the table, otherwise it was processed in a previous col
+ if (0 == info.colIndex) {
+ if (!tableBorderReset[NS_SIDE_LEFT]) {
+ propData->mLeftBorderWidth = 0;
+ tableBorderReset[NS_SIDE_LEFT] = PR_TRUE;
+ }
+ for (PRInt32 rowX = info.rowIndex; rowX <= cellEndRowIndex; rowX++) {
+ nsTableRowFrame* rowFrame = (rowX == info.rowIndex) ? info.topRow : rowFrame->GetNextRow();
+ CalcDominateBorder(this, info.cg, info.leftCol, info.rg, rowFrame, info.cell, PR_TRUE, NS_SIDE_LEFT,
+ PR_FALSE, t2p, owner, ownerBStyle, ownerWidth, ownerColor);
+ BCCornerInfo& tlCorner = (0 == rowX) ? topCorners[0] : bottomCorners[0]; // top left
+ tlCorner.Update(NS_SIDE_BOTTOM, owner, ownerBStyle, ownerWidth, ownerColor);
+ tableCellMap->SetBCBorderCorner(eTopLeft, *info.cellMap, iter.mRowGroupStart, rowX,
+ 0, tlCorner.ownerSide, tlCorner.subWidth, tlCorner.bevel);
+ bottomCorners[0].Set(NS_SIDE_TOP, owner, ownerBStyle, ownerWidth, ownerColor); // bottom left
+ // update lastVerBordersBorder and see if a new segment starts
+ startSeg = SetBorder(ownerBStyle, ownerWidth, ownerColor, lastVerBorders[0]);
+ // store the border segment in the cell map
+ tableCellMap->SetBCBorderEdge(NS_SIDE_LEFT, *info.cellMap, iter.mRowGroupStart, rowX,
+ info.colIndex, 1, owner, ownerWidth, startSeg);
+ // update the left border of the cell, col and table
+ DivideBCBorderSize(ownerWidth, smallHalf, largeHalf);
+ if (info.cell) {
+ info.cell->SetBorderWidth(NS_SIDE_LEFT, PR_MAX(smallHalf, info.cell->GetBorderWidth(NS_SIDE_LEFT)));
+ }
+ if (info.leftCol) {
+ info.leftCol->SetLeftBorderWidth(PR_MAX(smallHalf, info.leftCol->GetLeftBorderWidth()));
+ }
+ propData->mLeftBorderWidth = LimitBorderWidth(PR_MAX(propData->mLeftBorderWidth, ownerWidth));
+ }
+ }
+
+ // find the dominate border considernig the cell's right border, adjacent cells and the table, row group, row
+ if (numCols == cellEndColIndex + 1) { // touches right edge of table
+ if (!tableBorderReset[NS_SIDE_RIGHT]) {
+ propData->mRightBorderWidth = 0;
+ tableBorderReset[NS_SIDE_RIGHT] = PR_TRUE;
+ }
+ for (PRInt32 rowX = info.rowIndex; rowX <= cellEndRowIndex; rowX++) {
+ nsTableRowFrame* rowFrame = (rowX == info.rowIndex) ? info.topRow : rowFrame->GetNextRow();
+ CalcDominateBorder(this, info.cg, info.rightCol, info.rg, rowFrame, info.cell, PR_TRUE, NS_SIDE_RIGHT,
+ PR_TRUE, t2p, owner, ownerBStyle, ownerWidth, ownerColor);
+ // update/store the top right & bottom right corners
+ BCCornerInfo& trCorner = (0 == rowX) ? topCorners[cellEndColIndex + 1] : bottomCorners[cellEndColIndex + 1];
+ trCorner.Update(NS_SIDE_BOTTOM, owner, ownerBStyle, ownerWidth, ownerColor); // top right
+ tableCellMap->SetBCBorderCorner(eTopRight, *info.cellMap, iter.mRowGroupStart, rowX,
+ cellEndColIndex, trCorner.ownerSide, trCorner.subWidth, trCorner.bevel);
+ BCCornerInfo& brCorner = bottomCorners[cellEndColIndex + 1];
+ brCorner.Set(NS_SIDE_TOP, owner, ownerBStyle, ownerWidth, ownerColor); // bottom right
+ tableCellMap->SetBCBorderCorner(eBottomRight, *info.cellMap, iter.mRowGroupStart, rowX,
+ cellEndColIndex, brCorner.ownerSide, brCorner.subWidth, brCorner.bevel);
+ // update lastVerBorders and see if a new segment starts
+ startSeg = SetBorder(ownerBStyle, ownerWidth, ownerColor, lastVerBorders[cellEndColIndex + 1]);
+ // store the border segment in the cell map and update cellBorders
+ tableCellMap->SetBCBorderEdge(NS_SIDE_RIGHT, *info.cellMap, iter.mRowGroupStart, rowX,
+ cellEndColIndex, 1, owner, ownerWidth, startSeg);
+ // update the affected borders of the cell, col, and table
+ DivideBCBorderSize(ownerWidth, smallHalf, largeHalf);
+ if (info.cell) {
+ info.cell->SetBorderWidth(NS_SIDE_RIGHT, PR_MAX(largeHalf, info.cell->GetBorderWidth(NS_SIDE_RIGHT)));
+ }
+ if (info.rightCol) {
+ info.rightCol->SetRightBorderWidth(PR_MAX(largeHalf, info.rightCol->GetRightBorderWidth()));
+ }
+ propData->mRightBorderWidth = LimitBorderWidth(PR_MAX(propData->mRightBorderWidth, ownerWidth));
+ }
+ }
+ else {
+ PRInt32 segLength = 0;
+ BCMapCellInfo priorAjaInfo;
+ for (PRInt32 rowX = info.rowIndex; rowX <= cellEndRowIndex; rowX += segLength) {
+ iter.PeekRight(info, rowX, ajaInfo);
+ const nsIFrame* cg = (info.cgRight) ? info.cg : nsnull;
+ CalcDominateBorder(nsnull, cg, info.rightCol, nsnull, nsnull, info.cell, PR_FALSE, NS_SIDE_RIGHT,
+ PR_TRUE, t2p, owner, ownerBStyle, ownerWidth, ownerColor);
+ cg = (ajaInfo.cgLeft) ? ajaInfo.cg : nsnull;
+ CalcDominateBorder(nsnull, cg, ajaInfo.leftCol, nsnull, nsnull, ajaInfo.cell, PR_FALSE, NS_SIDE_LEFT,
+ PR_FALSE, t2p, ajaOwner, ajaBStyle, ajaWidth, ajaColor);
+ CalcDominateBorder(PR_FALSE, owner, ownerBStyle, ownerWidth, ownerColor, ajaOwner, ajaBStyle,
+ ajaWidth, ajaColor, owner, ownerBStyle, ownerWidth, ownerColor, PR_FALSE);
+ segLength = PR_MAX(1, ajaInfo.rowIndex + ajaInfo.rowSpan - rowX);
+ segLength = PR_MIN(segLength, info.rowIndex + info.rowSpan - rowX);
+
+ // update lastVerBorders and see if a new segment starts
+ startSeg = SetBorder(ownerBStyle, ownerWidth, ownerColor, lastVerBorders[cellEndColIndex + 1]);
+ // store the border segment in the cell map and update cellBorders
+ if (RIGHT_DAMAGED(cellEndColIndex) && TOP_DAMAGED(rowX) && BOTTOM_DAMAGED(rowX)) {
+ tableCellMap->SetBCBorderEdge(NS_SIDE_RIGHT, *info.cellMap, iter.mRowGroupStart, rowX,
+ cellEndColIndex, segLength, owner, ownerWidth, startSeg);
+ // update the borders of the cells and cols affected
+ DivideBCBorderSize(ownerWidth, smallHalf, largeHalf);
+ if (info.cell) {
+ info.cell->SetBorderWidth(NS_SIDE_RIGHT, PR_MAX(largeHalf, info.cell->GetBorderWidth(NS_SIDE_RIGHT)));
+ }
+ if (info.rightCol) {
+ info.rightCol->SetRightBorderWidth(PR_MAX(largeHalf, info.rightCol->GetRightBorderWidth()));
+ }
+ if (ajaInfo.cell) {
+ ajaInfo.cell->SetBorderWidth(NS_SIDE_LEFT, PR_MAX(smallHalf, ajaInfo.cell->GetBorderWidth(NS_SIDE_LEFT)));
+ }
+ if (ajaInfo.leftCol) {
+ ajaInfo.leftCol->SetLeftBorderWidth(PR_MAX(smallHalf, ajaInfo.leftCol->GetLeftBorderWidth()));
+ }
+ }
+ // update the top right corner
+ PRBool hitsSpanOnRight = (rowX > ajaInfo.rowIndex) && (rowX < ajaInfo.rowIndex + ajaInfo.rowSpan);
+ BCCornerInfo* trCorner = ((0 == rowX) || hitsSpanOnRight)
+ ? &topCorners[cellEndColIndex + 1] : &bottomCorners[cellEndColIndex + 1];
+ trCorner->Update(NS_SIDE_BOTTOM, owner, ownerBStyle, ownerWidth, ownerColor);
+ // if this is not the first time through, consider the segment to the right
+ if (rowX != info.rowIndex) {
+ const nsIFrame* rg = (priorAjaInfo.rgBottom) ? priorAjaInfo.rg : nsnull;
+ CalcDominateBorder(nsnull, nsnull, nsnull, rg, priorAjaInfo.bottomRow, priorAjaInfo.cell, PR_FALSE,
+ NS_SIDE_BOTTOM, PR_TRUE, t2p, owner, ownerBStyle, ownerWidth, ownerColor);
+ rg = (ajaInfo.rgTop) ? ajaInfo.rg : nsnull;
+ CalcDominateBorder(nsnull, nsnull, nsnull, rg, ajaInfo.topRow, ajaInfo.cell, PR_FALSE, NS_SIDE_TOP,
+ PR_FALSE, t2p, ajaOwner, ajaBStyle, ajaWidth, ajaColor);
+ CalcDominateBorder(PR_FALSE, owner, ownerBStyle, ownerWidth, ownerColor, ajaOwner, ajaBStyle,
+ ajaWidth, ajaColor, owner, ownerBStyle, ownerWidth, ownerColor, PR_TRUE);
+ trCorner->Update(NS_SIDE_RIGHT, owner, ownerBStyle, ownerWidth, ownerColor);
+ }
+ // store the top right corner in the cell map
+ if (RIGHT_DAMAGED(cellEndColIndex) && TOP_DAMAGED(rowX)) {
+ if (0 != rowX) {
+ tableCellMap->SetBCBorderCorner(eTopRight, *info.cellMap, iter.mRowGroupStart, rowX, cellEndColIndex,
+ trCorner->ownerSide, trCorner->subWidth, trCorner->bevel);
+ }
+ // store any corners this cell spans together with the aja cell
+ for (PRInt32 rX = rowX + 1; rX < rowX + segLength; rX++) {
+ tableCellMap->SetBCBorderCorner(eBottomRight, *info.cellMap, iter.mRowGroupStart, rX,
+ cellEndColIndex, trCorner->ownerSide, trCorner->subWidth, PR_FALSE);
+ }
+ }
+ // update bottom right corner, topCorners, bottomCorners
+ hitsSpanOnRight = (rowX + segLength < ajaInfo.rowIndex + ajaInfo.rowSpan);
+ BCCornerInfo& brCorner = (hitsSpanOnRight) ? topCorners[cellEndColIndex + 1]
+ : bottomCorners[cellEndColIndex + 1];
+ brCorner.Set(NS_SIDE_TOP, owner, ownerBStyle, ownerWidth, ownerColor);
+ priorAjaInfo = ajaInfo;
+ }
+ }
+ for (PRInt32 colX = info.colIndex + 1; colX <= cellEndColIndex; colX++) {
+ lastVerBorders[colX].Reset();
+ }
+
+ // find the dominate border considernig the cell's bottom border, adjacent cells and the table, row group, row
+ if (numRows == cellEndRowIndex + 1) { // touches botom edge of table
+ if (!tableBorderReset[NS_SIDE_BOTTOM]) {
+ propData->mBottomBorderWidth = 0;
+ tableBorderReset[NS_SIDE_BOTTOM] = PR_TRUE;
+ }
+ for (PRInt32 colX = info.colIndex; colX <= cellEndColIndex; colX++) {
+ nsIFrame* colFrame = GetColFrame(colX); if (!colFrame) ABORT0();
+ nsIFrame* cgFrame;
+ colFrame->GetParent(&cgFrame); if (!cgFrame) ABORT0();
+ CalcDominateBorder(this, cgFrame, colFrame, info.rg, info.bottomRow, info.cell, PR_TRUE, NS_SIDE_BOTTOM,
+ PR_TRUE, t2p, owner, ownerBStyle, ownerWidth, ownerColor);
+ // update/store the bottom left & bottom right corners
+ BCCornerInfo& blCorner = bottomCorners[colX]; // bottom left
+ blCorner.Update(NS_SIDE_RIGHT, owner, ownerBStyle, ownerWidth, ownerColor);
+ tableCellMap->SetBCBorderCorner(eBottomLeft, *info.cellMap, iter.mRowGroupStart, cellEndRowIndex,
+ colX, blCorner.ownerSide, blCorner.subWidth, blCorner.bevel);
+ BCCornerInfo& brCorner = bottomCorners[colX + 1]; // bottom right
+ brCorner.Update(NS_SIDE_LEFT, owner, ownerBStyle, ownerWidth, ownerColor);
+ if (numCols == colX + 1) { // lower right corner of the table
+ tableCellMap->SetBCBorderCorner(eBottomRight, *info.cellMap, iter.mRowGroupStart, cellEndRowIndex,
+ colX, brCorner.ownerSide, brCorner.subWidth, brCorner.bevel, isBottomRight);
+ }
+ // update lastBottomBorder and see if a new segment starts
+ startSeg = SetHorBorder(ownerBStyle, ownerWidth, ownerColor, blCorner, lastBottomBorder);
+ // store the border segment in the cell map and update cellBorders
+ tableCellMap->SetBCBorderEdge(NS_SIDE_BOTTOM, *info.cellMap, iter.mRowGroupStart, cellEndRowIndex,
+ colX, 1, owner, ownerWidth, startSeg);
+ // update the bottom borders of the cell, the bottom row, and the table
+ DivideBCBorderSize(ownerWidth, smallHalf, largeHalf);
+ if (info.cell) {
+ info.cell->SetBorderWidth(NS_SIDE_BOTTOM, PR_MAX(largeHalf, info.cell->GetBorderWidth(NS_SIDE_BOTTOM)));
+ }
+ if (info.bottomRow) {
+ info.bottomRow->SetBottomBCBorderWidth(PR_MAX(largeHalf, info.bottomRow->GetBottomBCBorderWidth()));
+ }
+ propData->mBottomBorderWidth = LimitBorderWidth(PR_MAX(propData->mBottomBorderWidth, ownerWidth));
+ // update lastBottomBorders
+ lastBottomBorder.index = cellEndRowIndex + 1;
+ lastBottomBorder.span = info.rowSpan;
+ lastBottomBorders[colX] = lastBottomBorder;
+ }
+ }
+ else {
+ PRInt32 segLength = 0;
+ for (PRInt32 colX = info.colIndex; colX <= cellEndColIndex; colX += segLength) {
+ iter.PeekBottom(info, colX, ajaInfo);
+ const nsIFrame* rg = (info.rgBottom) ? info.rg : nsnull;
+ CalcDominateBorder(nsnull, nsnull, nsnull, rg, info.bottomRow, info.cell, PR_FALSE, NS_SIDE_BOTTOM,
+ PR_TRUE, t2p, owner, ownerBStyle, ownerWidth, ownerColor);
+ rg = (ajaInfo.rgTop) ? ajaInfo.rg : nsnull;
+ CalcDominateBorder(nsnull, nsnull, nsnull, rg, ajaInfo.topRow, ajaInfo.cell, PR_FALSE, NS_SIDE_TOP,
+ PR_FALSE, t2p, ajaOwner, ajaBStyle, ajaWidth, ajaColor);
+ CalcDominateBorder(PR_FALSE, owner, ownerBStyle, ownerWidth, ownerColor, ajaOwner, ajaBStyle, ajaWidth,
+ ajaColor, owner, ownerBStyle, ownerWidth, ownerColor, PR_TRUE);
+ segLength = PR_MAX(1, ajaInfo.colIndex + ajaInfo.colSpan - colX);
+ segLength = PR_MIN(segLength, info.colIndex + info.colSpan - colX);
+
+ // update, store the bottom left corner
+ BCCornerInfo& blCorner = bottomCorners[colX]; // bottom left
+ PRBool hitsSpanBelow = (colX > ajaInfo.colIndex) && (colX < ajaInfo.colIndex + ajaInfo.colSpan);
+ PRBool update = PR_TRUE;
+ if ((colX == info.colIndex) && (colX > damageArea.x)) {
+ PRInt32 prevRowIndex = lastBottomBorders[colX - 1].index;
+ if (prevRowIndex > cellEndRowIndex + 1) { // hits a rowspan on the right
+ update = PR_FALSE; // the corner was taken care of during the cell on the left
+ }
+ else if (prevRowIndex < cellEndRowIndex) { // spans below the cell to the left
+ topCorners[colX] = blCorner;
+ blCorner.Set(NS_SIDE_RIGHT, owner, ownerBStyle, ownerWidth, ownerColor);
+ update = PR_FALSE;
+ }
+ }
+ if (update) {
+ blCorner.Update(NS_SIDE_RIGHT, owner, ownerBStyle, ownerWidth, ownerColor);
+ }
+ if (BOTTOM_DAMAGED(cellEndRowIndex) && LEFT_DAMAGED(colX)) {
+ if (hitsSpanBelow) {
+ tableCellMap->SetBCBorderCorner(eBottomLeft, *info.cellMap, iter.mRowGroupStart, cellEndRowIndex, colX,
+ blCorner.ownerSide, blCorner.subWidth, blCorner.bevel);
+ }
+ // store any corners this cell spans together with the aja cell
+ for (PRInt32 cX = colX + 1; cX < colX + segLength; cX++) {
+ BCCornerInfo& corner = bottomCorners[cX];
+ corner.Set(NS_SIDE_RIGHT, owner, ownerBStyle, ownerWidth, ownerColor);
+ tableCellMap->SetBCBorderCorner(eBottomLeft, *info.cellMap, iter.mRowGroupStart, cellEndRowIndex,
+ cX, corner.ownerSide, corner.subWidth, PR_FALSE);
+ }
+ }
+ // update lastBottomBorders and see if a new segment starts
+ startSeg = SetHorBorder(ownerBStyle, ownerWidth, ownerColor, blCorner, lastBottomBorder);
+ lastBottomBorder.index = cellEndRowIndex + 1;
+ lastBottomBorder.span = info.rowSpan;
+ for (PRInt32 cX = colX; cX < colX + segLength; cX++) {
+ lastBottomBorders[cX] = lastBottomBorder;
+ }
+
+ // store the border segment the cell map and update cellBorders
+ if (BOTTOM_DAMAGED(cellEndRowIndex) && LEFT_DAMAGED(colX) && RIGHT_DAMAGED(colX)) {
+ tableCellMap->SetBCBorderEdge(NS_SIDE_BOTTOM, *info.cellMap, iter.mRowGroupStart, cellEndRowIndex,
+ colX, segLength, owner, ownerWidth, startSeg);
+ // update the borders of the affected cells and rows
+ DivideBCBorderSize(ownerWidth, smallHalf, largeHalf);
+ if (info.cell) {
+ info.cell->SetBorderWidth(NS_SIDE_BOTTOM, PR_MAX(largeHalf, info.cell->GetBorderWidth(NS_SIDE_BOTTOM)));
+ }
+ if (info.bottomRow) {
+ info.bottomRow->SetBottomBCBorderWidth(PR_MAX(largeHalf, info.bottomRow->GetBottomBCBorderWidth()));
+ }
+ if (ajaInfo.cell) {
+ ajaInfo.cell->SetBorderWidth(NS_SIDE_TOP, PR_MAX(smallHalf, ajaInfo.cell->GetBorderWidth(NS_SIDE_TOP)));
+ }
+ if (ajaInfo.topRow) {
+ ajaInfo.topRow->SetTopBCBorderWidth(PR_MAX(smallHalf, ajaInfo.topRow->GetTopBCBorderWidth()));
+ }
+ }
+ // update bottom right corner
+ BCCornerInfo& brCorner = bottomCorners[colX + segLength];
+ brCorner.Update(NS_SIDE_LEFT, owner, ownerBStyle, ownerWidth, ownerColor);
+ }
+ }
+
+ // see if the cell to the right had a rowspan and its lower left border needs be joined with this one's bottom
+ if ((numCols != cellEndColIndex + 1) && // there is a cell to the right
+ (lastBottomBorders[cellEndColIndex + 1].span > 1)) { // cell to right was a rowspan
+ BCCornerInfo& corner = bottomCorners[cellEndColIndex + 1];
+ if ((NS_SIDE_TOP != corner.ownerSide) && (NS_SIDE_BOTTOM != corner.ownerSide)) { // not a vertical owner
+ BCCellBorder& thisBorder = lastBottomBorder;
+ BCCellBorder& nextBorder = lastBottomBorders[info.colIndex + 1];
+ if ((thisBorder.color == nextBorder.color) && (thisBorder.width == nextBorder.width) &&
+ (thisBorder.style == nextBorder.style)) {
+ // set the flag on the next border indicating it is not the start of a new segment
+ if (iter.mCellMap) {
+ BCData* bcData = tableCellMap->GetBCData(NS_SIDE_BOTTOM, *iter.mCellMap, cellEndRowIndex,
+ cellEndColIndex + 1);
+ if (bcData) {
+ bcData->SetTopStart(PR_FALSE);
+ }
+ }
+ }
+ }
+ }
+ } // for (iter.First(info); info.cell; iter.Next(info)) {
+
+ // reset the bc flag and damage area
+ SetNeedToCalcBCBorders(PR_FALSE);
+ propData->mDamageArea.x = propData->mDamageArea.y = propData->mDamageArea.width = propData->mDamageArea.height = 0;
+ //mCellMap->Dump();
+}
+
+// Iterates over borders (left border, corner, top border) in the cell map within a damage area
+// from left to right, top to bottom. All members are in terms of the 1st in flow frames, except
+// where suffixed by InFlow.
+class BCMapBorderIterator
+{
+public:
+ BCMapBorderIterator(nsTableFrame& aTableFrameInFlow,
+ nsTableRowGroupFrame& aRowGroupFrameInFlow,
+ nsTableRowFrame& aRowInFlow,
+ const nsRect& aDamageArea);
+ void Reset(nsTableFrame& aTableFrameInFlow,
+ nsTableRowGroupFrame& aRowGroupFrameInFlow,
+ nsTableRowFrame& aRowInFlow,
+ const nsRect& aDamageArea);
+ void First();
+ void Next();
+
+ nsTableFrame* tableInFlow;
+ nsTableFrame* table;
+ nsTableCellMap* tableCellMap;
+ nsCellMap* cellMap;
+
+ nsVoidArray rowGroups;
+ nsTableRowGroupFrame* prevRg;
+ nsTableRowGroupFrame* rgInFlow;
+ nsTableRowGroupFrame* rg;
+ PRInt32 rowGroupIndex;
+ PRInt32 rowGroupStart;
+ PRInt32 rowGroupEnd;
+ PRInt32 numRows;
+
+ nsTableRowFrame* prevRow;
+ nsTableRowFrame* rowInFlow;
+ nsTableRowFrame* row;
+ PRInt32 numCols;
+ PRInt32 x;
+ PRInt32 y;
+
+ nsTableCellFrame* prevCell;
+ nsTableCellFrame* cell;
+ BCCellData* prevCellData;
+ BCCellData* cellData;
+ BCData* bcData;
+
+ PRBool IsTopMostTable() { return (y == 0) && !tableInFlow->GetPrevInFlow(); }
+ PRBool IsRightMostTable() { return (x >= numCols); }
+ PRBool IsBottomMostTable() { return (y >= numRows) && !tableInFlow->GetNextInFlow(); }
+ PRBool IsLeftMostTable() { return (x == 0); }
+ PRBool IsTopMost() { return (y == startY); }
+ PRBool IsRightMost() { return (x >= endX); }
+ PRBool IsBottomMost() { return (y >= endY); }
+ PRBool IsLeftMost() { return (x == startX); }
+ PRBool isNewRow;
+
+ PRInt32 startX;
+ PRInt32 startY;
+ PRInt32 endX;
+ PRInt32 endY;
+ PRBool isRepeatedHeader;
+ PRBool isRepeatedFooter;
+ PRBool atEnd;
+
+private:
+
+ PRBool SetNewRow(nsTableRowFrame* aRowInFlow = nsnull,
+ nsTableRowFrame* aRow = nsnull);
+ PRBool SetNewRowGroup(PRBool aSetInFlow);
+ void SetNewData(PRInt32 aY, PRInt32 aX);
+
+};
+
+BCMapBorderIterator::BCMapBorderIterator(nsTableFrame& aTableInFlow,
+ nsTableRowGroupFrame& aRowGroupInFlow,
+ nsTableRowFrame& aRowInFlow,
+ const nsRect& aDamageArea)
+{
+ Reset(aTableInFlow, aRowGroupInFlow, aRowInFlow, aDamageArea);
+}
+
+void
+BCMapBorderIterator::Reset(nsTableFrame& aTableInFlow,
+ nsTableRowGroupFrame& aRowGroupInFlow,
+ nsTableRowFrame& aRowInFlow,
+ const nsRect& aDamageArea)
+{
+ atEnd = PR_TRUE; // gets reset when First() is called
+
+ tableInFlow = &aTableInFlow;
+ table = (nsTableFrame*)aTableInFlow.GetFirstInFlow(); if (!table) ABORT0();
+ rgInFlow = &aRowGroupInFlow;
+ rowInFlow = &aRowInFlow;
+
+ tableCellMap = table->GetCellMap();
+
+ startX = aDamageArea.x;
+ startY = aDamageArea.y;
+ endY = aDamageArea.y + aDamageArea.height;
+ endX = aDamageArea.x + aDamageArea.width;
+
+ numRows = table->GetRowCount();
+ y = 0;
+ numCols = table->GetColCount();
+ x = 0;
+ rowGroupIndex = -1;
+ rg = nsnull;
+ row = nsnull;
+ cell = nsnull;
+ cellData = nsnull;
+
+ // Get the ordered row groups
+ PRUint32 numRowGroups;
+ table->OrderRowGroups(rowGroups, numRowGroups, nsnull);
+}
+
+void
+BCMapBorderIterator::SetNewData(PRInt32 aY,
+ PRInt32 aX)
+{
+ if (!tableCellMap || !tableCellMap->mBCInfo) ABORT0();
+
+ x = aX;
+ y = aY;
+ prevCellData = cellData;
+ if (IsRightMost() && IsBottomMost()) {
+ cell = nsnull;
+ bcData = &tableCellMap->mBCInfo->mLowerRightCorner;
+ }
+ else if (IsRightMost()) {
+ cellData = nsnull;
+ bcData = (BCData*)tableCellMap->mBCInfo->mRightBorders.ElementAt(aY);
+ }
+ else if (IsBottomMost()) {
+ cellData = nsnull;
+ bcData = (BCData*)tableCellMap->mBCInfo->mBottomBorders.ElementAt(aX);
+ }
+ else {
+ bcData = nsnull;
+ nsVoidArray* row = (nsVoidArray*)cellMap->mRows.ElementAt(y - rowGroupStart);
+ if (row) {
+ cellData = (row->Count() > x) ? (BCCellData*)row->ElementAt(x) : nsnull;
+ if (cellData) {
+ bcData = &cellData->mData;
+ if (!cellData->IsOrig()) {
+ if (cellData->IsRowSpan()) {
+ aY -= cellData->GetRowSpanOffset();
+ }
+ if (cellData->IsColSpan()) {
+ aX -= cellData->GetColSpanOffset();
+ }
+ if ((aX >= 0) && (aY >= 0)) {
+ row = (nsVoidArray*)cellMap->mRows.ElementAt(aY - rowGroupStart);
+ if (row) {
+ cellData = (BCCellData*)row->ElementAt(aX);
+ }
+ }
+ }
+ if (cellData->IsOrig()) {
+ prevCell = cell;
+ cell = cellData->GetCellFrame();
+ }
+ }
+ }
+ }
+}
+
+PRBool
+BCMapBorderIterator::SetNewRow(nsTableRowFrame* aRowInFlow,
+ nsTableRowFrame* aRow)
+{
+ prevRow = row;
+ row = (aRow) ? aRow : row->GetNextRow();
+ rowInFlow = (aRowInFlow) ? aRowInFlow : rowInFlow->GetNextRow();
+
+ if (rowInFlow && row) {
+ isNewRow = PR_TRUE;
+ y = row->GetRowIndex();
+ x = startX;
+ }
+ else {
+ atEnd = PR_TRUE;
+ }
+ return !atEnd;
+}
+
+
+PRBool
+BCMapBorderIterator::SetNewRowGroup(PRBool aSetInFlow)
+{
+ rowGroupIndex++;
+
+ isRepeatedHeader = PR_FALSE;
+ isRepeatedFooter = PR_FALSE;
+
+ if (rowGroupIndex < rowGroups.Count()) {
+ prevRg = rg;
+ nsIFrame* frame = (nsTableRowGroupFrame*)rowGroups.ElementAt(rowGroupIndex); if (!frame) ABORT1(PR_FALSE);
+ rg = table->GetRowGroupFrame(frame); if (!rg) ABORT1(PR_FALSE);
+ rowGroupStart = rg->GetStartRowIndex();
+ rowGroupEnd = rowGroupStart + rg->GetRowCount() - 1;
+
+ if (aSetInFlow) {
+ if (rgInFlow && tableInFlow->GetPrevInFlow()) {
+ // if there is a prev in flow, then the next rgInFlow is (a) either the previous ones next sibling
+ // or (b) the rg of the next sibling of the parent if the parent is a scroll frame
+ nsIFrame* frame = nsnull;
+ nsIFrame* parent = nsnull;
+ rgInFlow->GetParent(&parent);
+ if (parent == tableInFlow) {
+ rgInFlow->GetNextSibling(&frame);
+ }
+ else if (parent) {
+ parent->GetNextSibling(&frame);
+ }
+ rgInFlow = table->GetRowGroupFrame(frame);
+ if (!rgInFlow) {
+ atEnd = PR_TRUE;
+ ABORT1(PR_FALSE);
+ }
+ }
+ else {
+ rgInFlow = rg;
+ }
+ }
+ if (SetNewRow(rgInFlow->GetFirstRow(), rg->GetFirstRow())) {
+ cellMap = tableCellMap->GetMapFor(*rg);
+ }
+ if (rgInFlow && tableInFlow->GetPrevInFlow() && !rgInFlow->GetPrevInFlow()) {
+ // if rgInFlow doesn't have a prev in flow, then it may be a repeated header or footer
+ const nsStyleDisplay* display;
+ rgInFlow->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)display);
+ if (y == startY) {
+ isRepeatedHeader = (NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == display->mDisplay);
+ }
+ else {
+ isRepeatedFooter = (NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == display->mDisplay);
+ }
+ }
+ }
+ else {
+ atEnd = PR_TRUE;
+ }
+ return !atEnd;
+}
+
+void
+BCMapBorderIterator::First()
+{
+ if (!table || (startX >= numCols) || (startY >= numRows)) ABORT0();
+
+ atEnd = PR_FALSE;
+
+ PRUint32 numRowGroups = rowGroups.Count();
+ for (PRUint32 rgX = 0; rgX < numRowGroups; rgX++) {
+ nsIFrame* frame = (nsIFrame*)rowGroups.ElementAt(rgX);
+ nsTableRowGroupFrame* rowG = table->GetRowGroupFrame(frame);
+ if (rowG) {
+ PRInt32 start = rowG->GetStartRowIndex();
+ PRInt32 end = start + rowG->GetRowCount() - 1;
+ if ((startY >= start) && (startY <= end)) {
+ rowGroupIndex = rgX - 1; // SetNewRowGroup increments rowGroupIndex
+ if (SetNewRowGroup(PR_FALSE)) {
+ while ((y < startY) && !atEnd) {
+ SetNewRow();
+ }
+ if (!atEnd) {
+ SetNewData(startY, startX);
+ }
+ }
+ return;
+ }
+ }
+ }
+ atEnd = PR_TRUE;
+}
+
+void
+BCMapBorderIterator::Next()
+{
+ if (atEnd) ABORT0();
+ isNewRow = PR_FALSE;
+
+ x++;
+ if (x > endX) {
+ y++;
+ if (y == endY) {
+ x = startX;
+ }
+ else if (y < endY) {
+ if (y <= rowGroupEnd) {
+ SetNewRow();
+ }
+ else {
+ SetNewRowGroup(PR_TRUE);
+ }
+ }
+ else {
+ atEnd = PR_TRUE;
+ }
+ }
+ if (!atEnd) {
+ SetNewData(y, x);
+ }
+}
+
+// XXX if CalcVerCornerOffset and CalcHorCornerOffset remain similar, combine them
+static nscoord
+CalcVerCornerOffset(PRUint8 aCornerOwnerSide,
+ nscoord aCornerSubWidth,
+ nscoord aHorWidth,
+ PRBool aIsStartOfSeg,
+ PRBool aIsBevel,
+ float aPixelsToTwips)
+{
+ nscoord offset = 0;
+ nscoord smallHalf, largeHalf;
+ if ((NS_SIDE_TOP == aCornerOwnerSide) || (NS_SIDE_BOTTOM == aCornerOwnerSide)) {
+ DivideBCBorderSize(aCornerSubWidth, smallHalf, largeHalf);
+ if (aIsBevel) {
+ offset = (aIsStartOfSeg) ? -largeHalf : smallHalf;
+ }
+ else {
+ offset = (NS_SIDE_TOP == aCornerOwnerSide) ? smallHalf : -largeHalf;
+ }
+ }
+ else {
+ DivideBCBorderSize(aHorWidth, smallHalf, largeHalf);
+ if (aIsBevel) {
+ offset = (aIsStartOfSeg) ? -largeHalf : smallHalf;
+ }
+ else {
+ offset = (aIsStartOfSeg) ? smallHalf : -largeHalf;
+ }
+ }
+ return NSToCoordRound(aPixelsToTwips * (float)offset);
+}
+
+static nscoord
+CalcHorCornerOffset(PRUint8 aCornerOwnerSide,
+ nscoord aCornerSubWidth,
+ nscoord aVerWidth,
+ PRBool aIsStartOfSeg,
+ PRBool aIsBevel,
+ float aPixelsToTwips)
+{
+ nscoord offset = 0;
+ nscoord smallHalf, largeHalf;
+ if ((NS_SIDE_LEFT == aCornerOwnerSide) || (NS_SIDE_RIGHT == aCornerOwnerSide)) {
+ DivideBCBorderSize(aCornerSubWidth, smallHalf, largeHalf);
+ if (aIsBevel) {
+ offset = (aIsStartOfSeg) ? -largeHalf : smallHalf;
+ }
+ else {
+ offset = (NS_SIDE_LEFT == aCornerOwnerSide) ? smallHalf : -largeHalf;
+ }
+ }
+ else {
+ DivideBCBorderSize(aVerWidth, smallHalf, largeHalf);
+ if (aIsBevel) {
+ offset = (aIsStartOfSeg) ? -largeHalf : smallHalf;
+ }
+ else {
+ offset = (aIsStartOfSeg) ? smallHalf : -largeHalf;
+ }
+ }
+ return NSToCoordRound(aPixelsToTwips * (float)offset);
+}
+
+struct BCVerticalSeg
+{
+ BCVerticalSeg::BCVerticalSeg();
+
+ void Start(BCMapBorderIterator& aIter,
+ BCBorderOwner aBorderOwner,
+ nscoord aVerSegWidth,
+ nscoord aPrevHorSegHeight,
+ nscoord aHorSegHeight,
+ float aPixelsToTwips,
+ BCVerticalSeg* aVerInfoArray);
+
+ union {
+ nsTableColFrame* col;
+ PRInt32 colWidth;
+ };
+ PRInt32 colX;
+ nsTableCellFrame* ajaCell;
+ nsTableCellFrame* firstCell; // cell at the start of the segment
+ nsTableCellFrame* lastCell; // cell at the current end of the segment
+ PRInt32 segY;
+ PRInt32 segHeight;
+ PRInt16 segWidth; // width in pixels
+ PRUint8 owner;
+ PRUint8 bevelSide;
+ PRUint16 bevelOffset;
+};
+
+BCVerticalSeg::BCVerticalSeg()
+{
+ col = nsnull; firstCell = lastCell = ajaCell = nsnull; colX = segY = segHeight = 0;
+ segWidth = bevelOffset = 0; bevelSide = 0; owner = eCellOwner;
+}
+
+void
+BCVerticalSeg::Start(BCMapBorderIterator& aIter,
+ BCBorderOwner aBorderOwner,
+ nscoord aVerSegWidth,
+ nscoord aPrevHorSegHeight,
+ nscoord aHorSegHeight,
+ float aPixelsToTwips,
+ BCVerticalSeg* aVerInfoArray)
+{
+ PRUint8 ownerSide = 0;
+ PRPackedBool bevel = PR_FALSE;
+ PRInt32 xAdj = aIter.x - aIter.startX;
+
+ nscoord cornerSubWidth = (aIter.bcData) ? aIter.bcData->GetCorner(ownerSide, bevel) : 0;
+ PRBool topBevel = (aVerSegWidth > 0) ? bevel : PR_FALSE;
+ nscoord maxHorSegHeight = PR_MAX(aPrevHorSegHeight, aHorSegHeight);
+ nscoord offset = CalcVerCornerOffset(ownerSide, cornerSubWidth, maxHorSegHeight,
+ PR_TRUE, topBevel, aPixelsToTwips);
+
+ bevelOffset = (topBevel) ? maxHorSegHeight : 0;
+ bevelSide = (aHorSegHeight > 0) ? NS_SIDE_RIGHT : NS_SIDE_LEFT;
+ segY += offset;
+ segHeight = -offset;
+ segWidth = aVerSegWidth;
+ owner = aBorderOwner;
+ firstCell = aIter.cell;
+ if (xAdj > 0) {
+ ajaCell = aVerInfoArray[xAdj - 1].lastCell;
+ }
+}
+
+struct BCHorizontalSeg
+{
+ BCHorizontalSeg::BCHorizontalSeg();
+
+ void Start(BCMapBorderIterator& aIter,
+ BCBorderOwner aBorderOwner,
+ PRUint8 aCornerOwnerSide,
+ nscoord aSubWidth,
+ PRBool aBevel,
+ nscoord aTopVerSegWidth,
+ nscoord aBottomVerSegWidth,
+ nscoord aHorSegHeight,
+ nsTableCellFrame* aLastCell,
+ float aPixelsToTwips);
+
+ nscoord x;
+ nscoord y;
+ nscoord width;
+ nscoord height;
+ PRBool leftBevel;
+ nscoord leftBevelOffset;
+ PRUint8 leftBevelSide;
+ PRUint8 owner;
+ nsTableCellFrame* firstCell; // cell at the start of the segment
+ nsTableCellFrame* ajaCell;
+};
+
+BCHorizontalSeg::BCHorizontalSeg()
+{
+ x = y = width = height = leftBevel = leftBevelOffset = leftBevelSide = 0;
+ firstCell = ajaCell = nsnull;
+}
+
+
+void
+BCHorizontalSeg::Start(BCMapBorderIterator& aIter,
+ BCBorderOwner aBorderOwner,
+ PRUint8 aCornerOwnerSide,
+ nscoord aSubWidth,
+ PRBool aBevel,
+ nscoord aTopVerSegWidth,
+ nscoord aBottomVerSegWidth,
+ nscoord aHorSegHeight,
+ nsTableCellFrame* aLastCell,
+ float aPixelsToTwips)
+{
+ owner = aBorderOwner;
+ leftBevel = (aHorSegHeight > 0) ? aBevel : PR_FALSE;
+ nscoord maxVerSegWidth = PR_MAX(aTopVerSegWidth, aBottomVerSegWidth);
+ nscoord offset = CalcHorCornerOffset(aCornerOwnerSide, aSubWidth, maxVerSegWidth,
+ PR_TRUE, leftBevel, aPixelsToTwips);
+ leftBevelOffset = (leftBevel && (aHorSegHeight > 0)) ? maxVerSegWidth : 0;
+ leftBevelSide = (aBottomVerSegWidth > 0) ? NS_SIDE_BOTTOM : NS_SIDE_TOP;
+ x += offset;
+ width = -offset;
+ height = aHorSegHeight;
+ firstCell = aIter.cell;
+ ajaCell = (aIter.IsTopMost()) ? nsnull : aLastCell;
+}
+
+void
+nsTableFrame::PaintBCBorders(nsIPresContext* aPresContext,
+ nsIRenderingContext& aRenderingContext,
+ const nsRect& aDirtyRect)
+{
+ nsMargin childAreaOffset = GetChildAreaOffset(*aPresContext, nsnull);
+ nsTableFrame* firstInFlow = (nsTableFrame*)GetFirstInFlow(); if (!firstInFlow) ABORT0();
+ GET_PIXELS_TO_TWIPS(aPresContext, p2t);
+
+ PRInt32 startColX = childAreaOffset.left; // x position of first col in damage area
+ PRInt32 startRowY = (mPrevInFlow) ? 0 : childAreaOffset.top; // y position of first row in damage area
+
+ const nsStyleBackground* bgColor = nsStyleUtil::FindNonTransparentBackground(mStyleContext);
+ // determine the damage area in terms of rows and columns and finalize startColX and startRowY
+ PRUint32 startRowIndex, endRowIndex, startColIndex, endColIndex;
+ startRowIndex = endRowIndex = startColIndex = endColIndex = 0;
+
+ nsAutoVoidArray rowGroups;
+ PRUint32 numRowGroups;
+ OrderRowGroups(rowGroups, numRowGroups, nsnull);
+ PRBool done = PR_FALSE;
+ PRBool haveIntersect = PR_FALSE;
+ nsTableRowGroupFrame* inFlowRG = nsnull;
+ nsTableRowFrame* inFlowRow = nsnull;
+ // find startRowIndex, endRowIndex, startRowY
+ nscoord onePixel = NSToCoordRound(p2t);
+ PRInt32 rowY = startRowY;
+ for (PRUint32 rgX = 0; (rgX < numRowGroups) && !done; rgX++) {
+ nsIFrame* kidFrame = (nsIFrame*)rowGroups.ElementAt(rgX);
+ nsTableRowGroupFrame* rgFrame = GetRowGroupFrame(kidFrame); if (!rgFrame) ABORT0();
+ nsRect rowRect;
+ for (nsTableRowFrame* rowFrame = rgFrame->GetFirstRow(); rowFrame; rowFrame = rowFrame->GetNextRow()) {
+ // conservatively estimate the half border widths outside the row
+ nscoord topBorderHalf = (mPrevInFlow) ? 0 : rowFrame->GetTopBCBorderWidth(&p2t) + onePixel;
+ nscoord bottomBorderHalf = (mNextInFlow) ? 0 : rowFrame->GetBottomBCBorderWidth(&p2t) + onePixel;
+ // get the row rect relative to the table rather than the row group
+ rowFrame->GetRect(rowRect);
+ if (haveIntersect) {
+ if (aDirtyRect.YMost() >= (rowY - topBorderHalf)) {
+ nsTableRowFrame* fifRow = (nsTableRowFrame*)rowFrame->GetFirstInFlow(); if (!fifRow) ABORT0();
+ endRowIndex = fifRow->GetRowIndex();
+ }
+ else done = PR_TRUE;
+ }
+ else {
+ if ((rowY + rowRect.height + bottomBorderHalf) >= aDirtyRect.y) {
+ inFlowRG = rgFrame;
+ inFlowRow = rowFrame;
+ nsTableRowFrame* fifRow = (nsTableRowFrame*)rowFrame->GetFirstInFlow(); if (!fifRow) ABORT0();
+ startRowIndex = endRowIndex = fifRow->GetRowIndex();
+ haveIntersect = PR_TRUE;
+ }
+ else {
+ startRowY += rowRect.height;
+ }
+ }
+ rowY += rowRect.height;
+ }
+ }
+ if (!inFlowRG || !inFlowRow) ABORT0();
+
+ // find startColIndex, endColIndex, startColX
+ haveIntersect = PR_FALSE;
+ PRUint32 numCols = GetColCount();
+ if (0 == numCols) return;
+
+ nscoord x = 0;
+ for (PRUint32 colX = 0; colX < numCols; colX++) {
+ nsTableColFrame* colFrame = firstInFlow->GetColFrame(colX); if (!colFrame) ABORT0();
+ // conservatively estimate the half border widths outside the col
+ nscoord leftBorderHalf = colFrame->GetLeftBorderWidth(&p2t) + onePixel;
+ nscoord rightBorderHalf = colFrame->GetRightBorderWidth(&p2t) + onePixel;
+ // get the col rect relative to the table rather than the col group
+ nsRect rect;
+ colFrame->GetRect(rect);
+ if (haveIntersect) {
+ if (aDirtyRect.XMost() >= (x - leftBorderHalf)) {
+ endColIndex = colX;
+ }
+ else break;
+ }
+ else {
+ if ((x + rect.width + rightBorderHalf) >= aDirtyRect.x) {
+ startColIndex = endColIndex = colX;
+ haveIntersect = PR_TRUE;
+ }
+ else {
+ startColX += rect.width;
+ }
+ }
+ x += rect.width;
+ }
+
+ // iterate the cell map and build up border segments
+ nsRect damageArea(startColIndex, startRowIndex, 1 + endColIndex - startColIndex,
+ 1 + endRowIndex - startRowIndex);
+ BCVerticalSeg* verInfo = new BCVerticalSeg[damageArea.width + 1]; if (!verInfo) ABORT0();
+
+ BCBorderOwner borderOwner, ignoreBorderOwner;
+ PRUint8 ownerSide;
+ nscoord cornerSubWidth, smallHalf, largeHalf;
+ nsRect rowRect(0,0,0,0);
+ PRBool isSegStart, ignoreSegStart;
+ nscoord prevHorSegHeight = 0;
+ PRPackedBool bevel;
+ PRInt32 repeatedHeaderY = -99;
+ PRBool afterRepeatedHeader = PR_FALSE;
+ PRBool startRepeatedFooter = PR_FALSE;
+
+ // First, paint all of the vertical borders from top to bottom and left to right as they become complete
+ // They are painted first, since they are less efficient to paint than horizontal segments. They were
+ // stored with as few segments as possible (since horizontal borders are painted last and possibly over them).
+ BCMapBorderIterator iter(*this, *inFlowRG, *inFlowRow, damageArea);
+ for (iter.First(); !iter.atEnd; iter.Next()) {
+ nscoord verSegWidth = (iter.bcData) ? iter.bcData->GetLeftEdge(borderOwner, isSegStart) : 0;
+ nscoord horSegHeight = (iter.bcData) ? iter.bcData->GetTopEdge(ignoreBorderOwner, ignoreSegStart) : 0;
+
+ PRInt32 xAdj = iter.x - iter.startX;
+ if (iter.isNewRow) {
+ prevHorSegHeight = 0;
+ iter.rowInFlow->GetRect(rowRect);
+ if (iter.isRepeatedHeader) {
+ repeatedHeaderY = iter.y;
+ }
+ afterRepeatedHeader = !iter.isRepeatedHeader && (iter.y == (repeatedHeaderY + 1));
+ startRepeatedFooter = iter.isRepeatedFooter && (iter.y == iter.rowGroupStart) && (iter.y != iter.startY);
+ }
+ BCVerticalSeg& info = verInfo[xAdj];
+ if (!info.col) { // on the first damaged row and the first segment in the col
+ info.col = iter.IsRightMostTable() ? verInfo[xAdj - 1].col : firstInFlow->GetColFrame(iter.x); if (!info.col) ABORT0();
+ if (0 == xAdj) {
+ info.colX = startColX;
+ }
+ // set colX for the next column
+ if (!iter.IsRightMost()) {
+ nsRect colRect;
+ info.col->GetRect(colRect);
+ verInfo[xAdj + 1].colX = info.colX + colRect.width;
+ }
+ info.segY = startRowY;
+ info.Start(iter, borderOwner, verSegWidth, prevHorSegHeight, horSegHeight, p2t, verInfo);
+ info.lastCell = iter.cell;
+ }
+
+ if (!iter.IsTopMost() && (isSegStart || iter.IsBottomMost() || afterRepeatedHeader || startRepeatedFooter)) {
+ // paint the previous seg or the current one if iter.IsBottomMost()
+ if (info.segHeight > 0) {
+ cornerSubWidth = (iter.bcData) ? iter.bcData->GetCorner(ownerSide, bevel) : 0;
+ PRBool endBevel = (info.segWidth > 0) ? bevel : PR_FALSE;
+ nscoord bottomHorSegHeight = PR_MAX(prevHorSegHeight, horSegHeight);
+ nscoord endOffset = CalcVerCornerOffset(ownerSide, cornerSubWidth, bottomHorSegHeight,
+ PR_FALSE, endBevel, p2t);
+ info.segHeight += endOffset;
+ if (info.segWidth > 0) {
+ // get the border style, color and paint the segment
+ PRUint8 side = (iter.IsRightMost()) ? NS_SIDE_RIGHT : NS_SIDE_LEFT;
+ nsTableColGroupFrame* cg = nsnull;
+ nsTableColFrame* col = info.col; if (!col) ABORT0();
+ nsTableCellFrame* cell = info.firstCell;
+ PRUint8 style = NS_STYLE_BORDER_STYLE_SOLID;
+ nscolor color = 0xFFFFFFFF;
+ PRBool ignoreIfRules = (iter.IsRightMostTable() || iter.IsLeftMostTable());
+
+ switch (info.owner) {
+ case eTableOwner:
+ ::GetStyleInfo(*this, side, style, color);
+ break;
+ case eAjaColGroupOwner:
+ side = NS_SIDE_RIGHT;
+ if (!iter.IsRightMostTable() && (xAdj > 0)) {
+ col = verInfo[xAdj - 1].col;
+ } // and fall through
+ case eColGroupOwner:
+ if (col) {
+ col->GetParent((nsIFrame**)&cg);
+ if (cg) {
+ ::GetStyleInfo(*cg, side, style, color, ignoreIfRules);
+ }
+ }
+ break;
+ case eAjaColOwner:
+ side = NS_SIDE_RIGHT;
+ if (!iter.IsRightMostTable() && (xAdj > 0)) {
+ col = verInfo[xAdj - 1].col;
+ } // and fall through
+ case eColOwner:
+ if (col) {
+ ::GetStyleInfo(*col, side, style, color, ignoreIfRules);
+ }
+ break;
+ case eAjaRowGroupOwner:
+ NS_ASSERTION(PR_FALSE, "program error"); // and fall through
+ case eRowGroupOwner:
+ NS_ASSERTION(iter.IsLeftMostTable() || iter.IsRightMostTable(), "program error");
+ if (iter.rg) {
+ ::GetStyleInfo(*iter.rg, side, style, color, ignoreIfRules);
+ }
+ break;
+ case eAjaRowOwner:
+ NS_ASSERTION(PR_FALSE, "program error"); // and fall through
+ case eRowOwner:
+ NS_ASSERTION(iter.IsLeftMostTable() || iter.IsRightMostTable(), "program error");
+ if (iter.row) {
+ ::GetStyleInfo(*iter.row, side, style, color, ignoreIfRules);
+ }
+ break;
+ case eAjaCellOwner:
+ side = NS_SIDE_RIGHT;
+ cell = info.ajaCell; // and fall through
+ case eCellOwner:
+ if (cell) {
+ ::GetStyleInfo(*cell, side, style, color);
+ }
+ break;
+ }
+ DivideBCBorderSize(info.segWidth, smallHalf, largeHalf);
+ nsRect segRect(info.colX - NSToCoordRound(p2t * (float)largeHalf), info.segY,
+ NSToCoordRound(p2t * (float)info.segWidth), info.segHeight);
+ nscoord bottomBevelOffset = (endBevel) ? NSToCoordRound(p2t * (float)bottomHorSegHeight) : 0;
+ PRUint8 bottomBevelSide = (horSegHeight > 0) ? NS_SIDE_RIGHT : NS_SIDE_LEFT;
+ nsCSSRendering::DrawTableBorderSegment(aRenderingContext, style, color, bgColor, segRect, p2t,
+ info.bevelSide, NSToCoordRound(p2t * (float)info.bevelOffset),
+ bottomBevelSide, bottomBevelOffset);
+ } // if (info.segWidth > 0) {
+ info.segY = info.segY + info.segHeight - endOffset;
+ } // if (info.segHeight > 0)
+ info.Start(iter, borderOwner, verSegWidth, prevHorSegHeight, horSegHeight, p2t, verInfo);
+ } // if (!iter.IsTopMost() && (isSegStart || iter.IsBottomMost())) {
+
+ info.lastCell = iter.cell;
+ info.segHeight += rowRect.height;
+ prevHorSegHeight = horSegHeight;
+ } // for (iter.First(); !iter.atEnd; iter.Next()) {
+
+ // Next, paint all of the horizontal border segments from top to bottom reuse the verInfo
+ // array to keep tract of col widths and vertical segments for corner calculations
+ memset(verInfo, 0, damageArea.width * sizeof(BCVerticalSeg)); // XXX reinitialize properly
+ for (PRInt32 xIndex = 0; xIndex < damageArea.width; xIndex++) {
+ verInfo[xIndex].colWidth = -1;
+ }
+ PRInt32 nextY = startRowY;
+ BCHorizontalSeg horSeg;
+
+ iter.Reset(*this, *inFlowRG, *inFlowRow, damageArea);
+ for (iter.First(); !iter.atEnd; iter.Next()) {
+ nscoord leftSegWidth = (iter.bcData) ? iter.bcData->GetLeftEdge(ignoreBorderOwner, ignoreSegStart) : 0;
+ nscoord topSegHeight = (iter.bcData) ? iter.bcData->GetTopEdge(borderOwner, isSegStart) : 0;
+
+ PRInt32 xAdj = iter.x - iter.startX;
+ // store the current col width if it hasn't been already
+ if (verInfo[xAdj].colWidth < 0) {
+ if (iter.IsRightMostTable()) {
+ verInfo[xAdj].colWidth = verInfo[xAdj - 1].colWidth;
+ }
+ else {
+ nsTableColFrame* col = firstInFlow->GetColFrame(iter.x); if (!col) ABORT0();
+ nsRect colRect;
+ col->GetRect(colRect);
+ verInfo[xAdj].colWidth = colRect.width;
+ }
+ }
+ cornerSubWidth = (iter.bcData) ? iter.bcData->GetCorner(ownerSide, bevel) : 0;
+ nscoord verWidth = PR_MAX(verInfo[xAdj].segWidth, leftSegWidth);
+ if (iter.isNewRow || (iter.IsLeftMost() && iter.IsBottomMostTable())) {
+ iter.rowInFlow->GetRect(rowRect);
+ horSeg.y = nextY;
+ nextY = nextY + rowRect.height;
+ horSeg.x = startColX;
+ horSeg.Start(iter, borderOwner, ownerSide, cornerSubWidth, bevel, verInfo[xAdj].segWidth,
+ leftSegWidth, topSegHeight, verInfo[xAdj].lastCell, p2t);
+ }
+ PRBool verOwnsCorner = (NS_SIDE_TOP == ownerSide) || (NS_SIDE_BOTTOM == ownerSide);
+ if (!iter.IsLeftMost() && (isSegStart || iter.IsRightMost() || verOwnsCorner)) {
+ // paint the previous seg or the current one if iter.IsRightMost()
+ if (horSeg.width > 0) {
+ PRBool endBevel = (horSeg.height > 0) ? bevel : 0;
+ nscoord endOffset = CalcHorCornerOffset(ownerSide, cornerSubWidth, verWidth, PR_FALSE, endBevel, p2t);
+ horSeg.width += endOffset;
+ if (horSeg.height > 0) {
+ // get the border style, color and paint the segment
+ PRUint8 side = (iter.IsBottomMost()) ? NS_SIDE_BOTTOM : NS_SIDE_TOP;
+ nsIFrame* rg = iter.rg; if (!rg) ABORT0();
+ nsIFrame* row = iter.row; if (!row) ABORT0();
+ nsIFrame* cell = horSeg.firstCell; if (!cell) ABORT0();
+ nsIFrame* cg;
+ nsIFrame* col;
+
+ PRUint8 style = NS_STYLE_BORDER_STYLE_SOLID;
+ nscolor color = 0xFFFFFFFF;
+ PRBool ignoreIfRules = (iter.IsTopMostTable() || iter.IsBottomMostTable());
+
+ switch (horSeg.owner) {
+ case eTableOwner:
+ ::GetStyleInfo(*this, side, style, color);
+ break;
+ case eAjaColGroupOwner:
+ NS_ASSERTION(PR_FALSE, "program error"); // and fall through
+ case eColGroupOwner:
+ NS_ASSERTION(iter.IsTopMostTable() || iter.IsBottomMostTable(), "program error");
+ col = firstInFlow->GetColFrame(iter.x - 1); if (!col) ABORT0();
+ col->GetParent(&cg); if (!cg) ABORT0();
+ ::GetStyleInfo(*cg, side, style, color, ignoreIfRules);
+ break;
+ case eAjaColOwner:
+ NS_ASSERTION(PR_FALSE, "program error"); // and fall through
+ case eColOwner:
+ NS_ASSERTION(iter.IsTopMostTable() || iter.IsBottomMostTable(), "program error");
+ col = firstInFlow->GetColFrame(iter.x - 1); if (!col) ABORT0();
+ ::GetStyleInfo(*col, side, style, color, ignoreIfRules);
+ break;
+ case eAjaRowGroupOwner:
+ side = NS_SIDE_BOTTOM;
+ rg = (iter.IsBottomMostTable()) ? iter.rg : iter.prevRg; // and fall through
+ case eRowGroupOwner:
+ if (rg) {
+ ::GetStyleInfo(*rg, side, style, color, ignoreIfRules);
+ }
+ break;
+ case eAjaRowOwner:
+ side = NS_SIDE_BOTTOM;
+ row = iter.prevRow; // and fall through
+ case eRowOwner:
+ if (row) {
+ ::GetStyleInfo(*row, side, style, color, iter.IsBottomMostTable());
+ }
+ break;
+ case eAjaCellOwner:
+ side = NS_SIDE_BOTTOM;
+ // if this is null due to the damage area origin-y > 0, then the border won't show up anyway
+ cell = horSeg.ajaCell;
+ // and fall through
+ case eCellOwner:
+ if (cell) {
+ ::GetStyleInfo(*cell, side, style, color);
+ }
+ break;
+ }
+ DivideBCBorderSize(horSeg.height, smallHalf, largeHalf);
+ nsRect segRec(horSeg.x, horSeg.y - NSToCoordRound(p2t * (float)largeHalf), horSeg.width,
+ NSToCoordRound(p2t * (float)horSeg.height));
+ nscoord rightBevelOffset = (endBevel) ? NSToCoordRound(p2t * (float)verWidth) : 0;
+ PRUint8 rightBevelSide = (leftSegWidth > 0) ? NS_SIDE_BOTTOM : NS_SIDE_TOP;
+ nsCSSRendering::DrawTableBorderSegment(aRenderingContext, style, color, bgColor, segRec, p2t, horSeg.leftBevelSide,
+ NSToCoordRound(p2t * (float)horSeg.leftBevelOffset),
+ rightBevelSide, rightBevelOffset);
+ } // if (horSeg.height > 0) {
+ horSeg.x = horSeg.x + horSeg.width - endOffset;
+ } // if (horSeg.width > 0) {
+ horSeg.Start(iter, borderOwner, ownerSide, cornerSubWidth, bevel, verInfo[xAdj].segWidth,
+ leftSegWidth, topSegHeight, verInfo[xAdj].lastCell, p2t);
+ } // if (!iter.IsLeftMost() && (isSegStart || iter.IsRightMost() || verOwnsCorner)) {
+ horSeg.width += verInfo[xAdj].colWidth;
+ verInfo[xAdj].segWidth = leftSegWidth;
+ verInfo[xAdj].lastCell = iter.cell;
+ }
+ delete [] verInfo;
+}
/********************************************************************************
** DEBUG_TABLE_REFLOW and DEBUG_TABLE_REFLOW_TIMING **
@@ -4579,7 +6993,7 @@ GetFrameTypeName(nsIAtom* aFrameType,
strcpy(aName, "RowG");
else if (nsLayoutAtoms::tableRowFrame == aFrameType)
strcpy(aName, "Row");
- else if (nsLayoutAtoms::tableCellFrame == aFrameType)
+ else if (IS_TABLE_CELL(aFrameType))
strcpy(aName, "Cell");
else if (nsLayoutAtoms::blockFrame == aFrameType)
strcpy(aName, "Block");
@@ -4621,7 +7035,7 @@ void DebugGetIndent(const nsIFrame* aFrame,
(nsLayoutAtoms::tableFrame == frameType.get()) ||
(nsLayoutAtoms::tableRowGroupFrame == frameType.get()) ||
(nsLayoutAtoms::tableRowFrame == frameType.get()) ||
- (nsLayoutAtoms::tableCellFrame == frameType.get())) {
+ IS_TABLE_CELL(frameType.get())) {
numLevels++;
}
if (nsLayoutAtoms::blockFrame == frameType.get()) {
@@ -4630,7 +7044,7 @@ void DebugGetIndent(const nsIFrame* aFrame,
parent->GetParent(&grandParent);
nsCOMPtr gFrameType;
grandParent->GetFrameType(getter_AddRefs(gFrameType));
- if (nsLayoutAtoms::tableCellFrame == gFrameType.get()) {
+ if (IS_TABLE_CELL(gFrameType.get())) {
numLevels++;
}
}
@@ -4715,14 +7129,14 @@ nsReflowTimer* GetFrameTimer(nsIFrame* aFrame,
return ((nsTableRowGroupFrame*)aFrame)->mTimer;
else if (nsLayoutAtoms::tableRowFrame == aFrameType)
return ((nsTableRowFrame*)aFrame)->mTimer;
- else if (nsLayoutAtoms::tableCellFrame == aFrameType)
+ else if (IS_TABLE_CELL(aFrameType))
return ((nsTableCellFrame*)aFrame)->mTimer;
else if (nsLayoutAtoms::blockFrame == aFrameType) {
nsIFrame* parentFrame;
aFrame->GetParent(&parentFrame);
nsCOMPtr fType;
parentFrame->GetFrameType(getter_AddRefs(fType));
- if (nsLayoutAtoms::tableCellFrame == fType) {
+ if (IS_TABLE_CELL(fType)) {
nsTableCellFrame* cellFrame = (nsTableCellFrame*)parentFrame;
// fix up the block timer, which may be referring to the cell
if (cellFrame->mBlockTimer->mFrame == parentFrame) {
@@ -4967,7 +7381,7 @@ void nsTableFrame::DebugReflowDone(nsIFrame* aFrame)
ancestorTimer->mChildren.AppendElement(thisTimer);
nsCOMPtr fType;
aFrame->GetFrameType(getter_AddRefs(fType));
- if (nsLayoutAtoms::tableCellFrame == fType) {
+ if (IS_TABLE_CELL(fType)) {
// add the cell block timer as a child of the cell timer
nsTableCellFrame* cellFrame = (nsTableCellFrame*)aFrame;
cellFrame->mTimer->mChildren.AppendElement(cellFrame->mBlockTimer);
@@ -5056,6 +7470,16 @@ DestroyPointFunc(nsIPresContext* aPresContext,
delete (nsPoint*)aPropertyValue;
}
+// Destructor function for nscoord properties
+static void
+DestroyBCPropertyDataFunc(nsIPresContext* aPresContext,
+ nsIFrame* aFrame,
+ nsIAtom* aPropertyName,
+ void* aPropertyValue)
+{
+ delete (BCPropertyData*)aPropertyValue;
+}
+
void*
nsTableFrame::GetProperty(nsIPresContext* aPresContext,
nsIFrame* aFrame,
@@ -5089,6 +7513,10 @@ nsTableFrame::GetProperty(nsIPresContext* aPresContext,
value = new nscoord;
dtorFunc = DestroyCoordFunc;
}
+ else if (aPropertyName == nsLayoutAtoms::tableBCProperty) {
+ value = new BCPropertyData;
+ dtorFunc = DestroyBCPropertyDataFunc;
+ }
if (!value) return nsnull;
frameManager->SetFrameProperty(aFrame, aPropertyName, value, dtorFunc);
@@ -5160,7 +7588,7 @@ void DumpTableFramesRecur(nsIPresContext* aPresContext,
if (nsLayoutAtoms::tableFrame == fType.get() ||
nsLayoutAtoms::tableRowGroupFrame == fType.get() ||
nsLayoutAtoms::tableRowFrame == fType.get() ||
- nsLayoutAtoms::tableCellFrame == fType.get()) {
+ IS_TABLE_CELL(fType.get())) {
nsIFrame* child;
aFrame->FirstChild(aPresContext, nsnull, &child);
while(child) {
diff --git a/mozilla/layout/tables/nsTableFrame.h b/mozilla/layout/tables/nsTableFrame.h
index 4862e4a92c2..7dc64be49b4 100644
--- a/mozilla/layout/tables/nsTableFrame.h
+++ b/mozilla/layout/tables/nsTableFrame.h
@@ -53,7 +53,6 @@ class nsTableColFrame;
class nsTableRowGroupFrame;
class nsTableRowFrame;
class nsTableColGroupFrame;
-class nsTableBorderCollapser;
class nsITableLayoutStrategy;
class nsHTMLValue;
@@ -208,6 +207,8 @@ public:
nsIAtom* aPropertyName,
PRBool aCreateIfNecessary = PR_FALSE);
+ static float GetTwipsToPixels(nsIPresContext* aPresContext);
+
static nscoord RoundToPixel(nscoord aValue,
float aPixelToTwips,
nsPixelRound aRound= eAlwaysRoundUp);
@@ -249,7 +250,13 @@ public:
nsIAtom* aListName,
nsIFrame* aOldFrame);
- nsMargin GetBorderPadding(const nsHTMLReflowState& aReflowState) const;
+ // Get the offset from the border box to the area where the row groups fit
+ nsMargin GetChildAreaOffset(nsIPresContext& aPresContext,
+ const nsHTMLReflowState* aReflowState) const;
+
+ // Get the offset from the border box to the area where the content fits
+ nsMargin GetContentAreaOffset(nsIPresContext& aPresContext,
+ const nsHTMLReflowState* aReflowState) const;
/** helper method to find the table parent of any table frame object */
// TODO: today, this depends on display types. This should be changed to rely
@@ -297,6 +304,17 @@ public:
nsFramePaintLayer aWhichLayer,
PRUint32 aFlags = 0);
+ nsMargin* GetBCBorder(nsIPresContext& aPresContext,
+ PRBool aInnerBorderOnly,
+ nsMargin& aBorder) const;
+
+ void SetBCDamageArea(nsIPresContext& aPresContext,
+ const nsRect& aValue);
+
+ void PaintBCBorders(nsIPresContext* aPresContext,
+ nsIRenderingContext& aRenderingContext,
+ const nsRect& aDirtyRect);
+
NS_IMETHOD GetFrameForPoint(nsIPresContext* aPresContext,
const nsPoint& aPoint,
nsFramePaintLayer aWhichLayer,
@@ -371,15 +389,12 @@ public:
/** set the width of the column at aColIndex to aWidth */
virtual void SetColumnWidth(PRInt32 aColIndex, nscoord aWidth);
- /** helper to get the border collapse style value */
- virtual PRUint8 GetBorderCollapseStyle();
-
/** helper to get the cell spacing X style value */
virtual nscoord GetCellSpacingX();
/** helper to get the cell spacing Y style value */
virtual nscoord GetCellSpacingY();
-
+
/** return the row span of a cell, taking into account row span magic at the bottom
* of a table. The row span equals the number of rows spanned by aCell starting at
* aStartRowIndex, and can be smaller if aStartRowIndex is greater than the row
@@ -440,9 +455,9 @@ public:
/** empty the column frame cache */
void ClearColCache();
- virtual PRInt32 AppendCell(nsIPresContext& aPresContext,
- nsTableCellFrame& aCellFrame,
- PRInt32 aRowIndex);
+ virtual void AppendCell(nsIPresContext& aPresContext,
+ nsTableCellFrame& aCellFrame,
+ PRInt32 aRowIndex);
virtual void InsertCells(nsIPresContext& aPresContext,
nsVoidArray& aCellFrames,
@@ -522,6 +537,9 @@ protected:
/** destructor, responsible for mColumnLayoutData */
virtual ~nsTableFrame();
+ void InitChildReflowState(nsIPresContext& aPresContext,
+ nsHTMLReflowState& aReflowState);
+
/** implement abstract method on nsHTMLContainerFrame */
virtual PRIntn GetSkipSides() const;
@@ -619,7 +637,8 @@ protected:
nsIFrame* aKidFrame,
nscoord aDeltaY);
- nsresult RecoverState(nsTableReflowState& aReflowState,
+ nsresult RecoverState(nsIPresContext& aPresContext,
+ nsTableReflowState& aReflowState,
nsIFrame* aKidFrame);
NS_METHOD CollapseRowGroupIfNecessary(nsIPresContext* aPresContext,
@@ -646,10 +665,11 @@ public:
// calculate the computed height of aFrame including its border and padding given
// its reflow state.
- nscoord CalcBorderBoxHeight(const nsHTMLReflowState& aReflowState);
+ nscoord CalcBorderBoxHeight(nsIPresContext* aPresContext,
+ const nsHTMLReflowState& aReflowState);
// calculate the minimum width to layout aFrame and its desired width
// including border and padding given its reflow state and column width information
- void CalcMinAndPreferredWidths(nsIPresContext* aPresContextconst,
+ void CalcMinAndPreferredWidths(nsIPresContext* aPresContext,
const nsHTMLReflowState& aReflowState,
PRBool aCalcPrefWidthIfAutoWithPctCol,
nscoord& aMinWidth,
@@ -657,7 +677,8 @@ public:
protected:
// calcs the width of the table according to the computed widths of each column.
- virtual PRInt32 CalcDesiredWidth(const nsHTMLReflowState& aReflowState);
+ virtual PRInt32 CalcDesiredWidth(nsIPresContext& aPresContext,
+ const nsHTMLReflowState& aReflowState);
// return the desired height of this table accounting for the current
// reflow state, and for the table attributes and parent
@@ -699,7 +720,7 @@ public:
PRUint32& aNumRowGroups,
nsIFrame** aFirstBody = nsnull,
nsTableRowGroupFrame** aHead = nsnull,
- nsTableRowGroupFrame** aFoot = nsnull);
+ nsTableRowGroupFrame** aFoot = nsnull) const;
// Returns PR_TRUE if there are any cells above the row at
// aRowIndex and spanning into the row at aRowIndex
@@ -735,9 +756,6 @@ protected:
PRBool DidResizeReflow() const;
void SetResizeReflow(PRBool aValue);
- /** Support methods for DidSetStyleContext */
- void MapBorderMarginPadding(nsIPresContext* aPresContext);
- void MapHTMLBorderStyle(nsStyleBorder& aBorderStyle, nscoord aBorderWidth);
PRBool ConvertToPixelValue(nsHTMLValue& aValue,
PRInt32 aDefault,
PRInt32& aResult);
@@ -749,6 +767,11 @@ public:
PRBool NeedStrategyBalance() const;
void SetNeedStrategyBalance(PRBool aValue);
+ PRBool IsBorderCollapse() const;
+
+ PRBool NeedToCalcBCBorders() const;
+ void SetNeedToCalcBCBorders(PRBool aValue);
+
/** Get the cell map for this table frame. It is not always mCellMap.
* Only the firstInFlow has a legit cell map
*/
@@ -763,9 +786,6 @@ public:
PRInt32 aRowIndex,
PRInt32 anAdjustment);
- // Return PR_TRUE if rules=groups is set for the table content
- PRBool HasGroupRules() const;
-
// Remove cell borders which aren't bordering row and/or col groups
void ProcessGroupRules(nsIPresContext* aPresContext);
@@ -775,10 +795,16 @@ public:
* Return aFrame's child if aFrame is an nsScrollFrame, otherwise return aFrame
*/
nsTableRowGroupFrame* GetRowGroupFrame(nsIFrame* aFrame,
- nsIAtom* aFrameTypeIn = nsnull);
+ nsIAtom* aFrameTypeIn = nsnull) const;
protected:
+ void SetBorderCollapse(PRBool aValue);
+
+ void CalcBCBorders(nsIPresContext& aPresContext);
+
+ void ExpandBCDamageArea(nsRect& aRect) const;
+
PRBool HadInitialReflow() const;
void SetHadInitialReflow(PRBool aValue);
@@ -809,8 +835,8 @@ public: /* ----- Cell Map public methods ----- */
/** returns the number of columns in this table after redundant columns have been removed
*/
- virtual PRInt32 GetEffectiveColCount();
- virtual PRInt32 GetColCount();
+ virtual PRInt32 GetEffectiveColCount() const;
+ virtual PRInt32 GetColCount() const;
/** return the column frame at colIndex.
* returns nsnull if the col frame has not yet been allocated, or if aColIndex is out of range
@@ -886,6 +912,7 @@ protected:
unsigned mHasPctCol:1; // does any cell or col have a pct width
unsigned mCellSpansPctCol:1; // does any cell span a col with a pct width (or containing a cell with a pct width)
unsigned mDidResizeReflow:1; // did a resize reflow happen (indicating pass 2)
+ unsigned mIsBorderCollapse:1; // border collapsing model vs. separate model
// true if a descendant was reflowed normally since the last time we reflowed.
// We will likely need a timeout reflow (targeted either at us or below)
unsigned mDescendantReflowedNotTimeout:1;
@@ -896,7 +923,8 @@ protected:
unsigned mRowInserted:1;
unsigned mNeedSpecialReflow:1;
unsigned mNeedToInitiateSpecialReflow:1;
- unsigned : 20; // unused
+ unsigned mNeedToCalcBCBorders:1;
+ unsigned : 18; // unused
} mBits;
nsTableCellMap* mCellMap; // maintains the relationships between rows, cols, and cells
@@ -1054,8 +1082,26 @@ inline void nsTableFrame::SetPreferredWidth(nscoord aWidth)
mPreferredWidth = aWidth;
}
+inline PRBool nsTableFrame::IsBorderCollapse() const
+{
+ return (PRBool)mBits.mIsBorderCollapse;
+}
+
+inline void nsTableFrame::SetBorderCollapse(PRBool aValue)
+{
+ mBits.mIsBorderCollapse = aValue;
+}
+
+inline PRBool nsTableFrame::NeedToCalcBCBorders() const
+{
+ return (PRBool)mBits.mNeedToCalcBCBorders;
+}
+
+inline void nsTableFrame::SetNeedToCalcBCBorders(PRBool aValue)
+{
+ mBits.mNeedToCalcBCBorders = (unsigned)aValue;
+}
-
enum nsTableIteration {
eTableLTR = 0,
eTableRTL = 1,
@@ -1085,6 +1131,23 @@ protected:
PRInt32 mCount;
};
+#define ABORT0() \
+{NS_ASSERTION(PR_FALSE, "CellIterator program error"); \
+return;}
+
+#define ABORT1(aReturn) \
+{NS_ASSERTION(PR_FALSE, "CellIterator program error"); \
+return aReturn;}
+
+#define GET_PIXELS_TO_TWIPS(presContext,var) \
+ float var; \
+ (presContext)->GetScaledPixelsToTwips(&var);
+
+#define GET_TWIPS_TO_PIXELS(presContext,var) \
+ float var; \
+ (presContext)->GetScaledPixelsToTwips(&var); \
+ var = 1.0f / var;
+
#endif
diff --git a/mozilla/layout/tables/nsTableOuterFrame.cpp b/mozilla/layout/tables/nsTableOuterFrame.cpp
index cd77fdd51e4..d402caa1396 100644
--- a/mozilla/layout/tables/nsTableOuterFrame.cpp
+++ b/mozilla/layout/tables/nsTableOuterFrame.cpp
@@ -232,7 +232,14 @@ nsTableOuterFrame::SetInitialChildList(nsIPresContext* aPresContext,
}
else {
mFrames.SetFrames(aChildList);
- mInnerTableFrame = aChildList;
+ mInnerTableFrame = nsnull;
+ if (aChildList) {
+ nsCOMPtr fType;
+ aChildList->GetFrameType(getter_AddRefs(fType));
+ if (nsLayoutAtoms::tableFrame == fType.get()) {
+ mInnerTableFrame = (nsTableFrame*)aChildList;
+ }
+ }
}
return NS_OK;
@@ -466,21 +473,46 @@ FixAutoMargins(nscoord aAvailWidth,
}
}
+void
+nsTableOuterFrame::InitChildReflowState(nsIPresContext& aPresContext,
+ nsHTMLReflowState& aReflowState)
+
+{
+ nsMargin collapseBorder;
+ nsMargin collapsePadding(0,0,0,0);
+ nsMargin* pCollapseBorder = nsnull;
+ nsMargin* pCollapsePadding = nsnull;
+ if ((aReflowState.frame == mInnerTableFrame) && (mInnerTableFrame->IsBorderCollapse())) {
+ if (mInnerTableFrame->NeedToCalcBCBorders()) {
+ mInnerTableFrame->CalcBCBorders(aPresContext);
+ }
+ pCollapseBorder = mInnerTableFrame->GetBCBorder(aPresContext, PR_FALSE, collapseBorder);
+ pCollapsePadding = &collapsePadding;
+ }
+ aReflowState.Init(&aPresContext, -1, -1, pCollapseBorder, pCollapsePadding);
+}
+
// get the margin and padding data. nsHTMLReflowState doesn't handle the
// case of auto margins
void
-GetMarginPadding(nsIPresContext* aPresContext,
- const nsHTMLReflowState& aOuterRS,
- nsIFrame* aChildFrame,
- nsMargin& aMargin,
- nsMargin& aMarginNoAuto,
- nsMargin& aPadding)
+nsTableOuterFrame::GetMarginPadding(nsIPresContext* aPresContext,
+ const nsHTMLReflowState& aOuterRS,
+ nsIFrame* aChildFrame,
+ nsMargin& aMargin,
+ nsMargin& aMarginNoAuto,
+ nsMargin& aPadding)
{
+ if (!aPresContext) ABORT0();
+ GET_PIXELS_TO_TWIPS(aPresContext, p2t);
// construct a reflow state to compute margin and padding. Auto margins
// will not be computed at this time.
+
+ // create an init the child reflow state
nsHTMLReflowState childRS(aPresContext, aOuterRS, aChildFrame,
nsSize(aOuterRS.availableWidth, aOuterRS.availableHeight),
- eReflowReason_Resize);
+ eReflowReason_Resize, PR_FALSE);
+ InitChildReflowState(*aPresContext, childRS);
+
nsRect childRect;
aChildFrame->GetRect(childRect);
FixAutoMargins(aOuterRS.availableWidth, childRect.width, childRS);
@@ -931,6 +963,7 @@ nsTableOuterFrame::OuterReflowChild(nsIPresContext* aPresContext,
nsReflowReason aReflowReason,
nsReflowStatus& aStatus)
{
+ if (!aPresContext) ABORT1(NS_ERROR_NULL_POINTER);
aMargin = aPadding = nsMargin(0,0,0,0);
nscoord availWidth = GetChildAvailWidth(aPresContext, aChildFrame, aOuterRS,
@@ -946,9 +979,10 @@ nsTableOuterFrame::OuterReflowChild(nsIPresContext* aPresContext,
availHeight = nsTableFrame::RoundToPixel(availHeight, p2t, eAlwaysRoundDown);
}
- nsHTMLReflowState childRS(aPresContext, aOuterRS, aChildFrame,
- nsSize(availWidth, availHeight));
- childRS.reason = aReflowReason;
+ // create and init the child reflow state
+ nsHTMLReflowState childRS(aPresContext, aOuterRS, aChildFrame, nsSize(availWidth, availHeight),
+ aReflowReason);
+ InitChildReflowState(*aPresContext, childRS);
childRS.mPercentHeightObserver = nsnull; // the observer is for non table related frames inside cells
diff --git a/mozilla/layout/tables/nsTableOuterFrame.h b/mozilla/layout/tables/nsTableOuterFrame.h
index ee689ab6f08..16eaba4c89d 100644
--- a/mozilla/layout/tables/nsTableOuterFrame.h
+++ b/mozilla/layout/tables/nsTableOuterFrame.h
@@ -47,6 +47,7 @@ class nsReflowTimer;
#endif
struct nsStyleTable;
+class nsTableFrame;
class nsTableCaptionFrame : public nsBlockFrame
{
@@ -201,6 +202,9 @@ protected:
nsTableOuterFrame();
virtual ~nsTableOuterFrame();
+ void InitChildReflowState(nsIPresContext& aPresContext,
+ nsHTMLReflowState& aReflowState);
+
/** Always returns 0, since the outer table frame has no border of its own
* The inner table frame can answer this question in a meaningful way.
* @see nsHTMLContainerFrame::GetSkipSides */
@@ -362,11 +366,17 @@ protected:
PRBool aInnerChanged,
PRBool aCaptionChanged);
+ void GetMarginPadding(nsIPresContext* aPresContext,
+ const nsHTMLReflowState& aOuterRS,
+ nsIFrame* aChildFrame,
+ nsMargin& aMargin,
+ nsMargin& aMarginNoAuto,
+ nsMargin& aPadding);
private:
// used to keep track of this frame's children. They are redundant with mFrames, but more convient
- nsIFrame* mInnerTableFrame;
- nsIFrame* mCaptionFrame;
+ nsTableFrame* mInnerTableFrame;
+ nsIFrame* mCaptionFrame;
// used to track caption max element size
PRInt32 mMinCaptionWidth;
diff --git a/mozilla/layout/tables/nsTableRowFrame.cpp b/mozilla/layout/tables/nsTableRowFrame.cpp
index 59055548c3f..48687f0efb5 100644
--- a/mozilla/layout/tables/nsTableRowFrame.cpp
+++ b/mozilla/layout/tables/nsTableRowFrame.cpp
@@ -68,11 +68,6 @@ struct nsTableCellReflowState : public nsHTMLReflowState
const nsSize& aAvailableSpace,
nsReflowReason aReason);
- nsTableCellReflowState(nsIPresContext* aPresContext,
- const nsHTMLReflowState& aParentReflowState,
- nsIFrame* aFrame,
- const nsSize& aAvailableSpace);
-
void FixUp(const nsSize& aAvailSpace);
};
@@ -83,16 +78,43 @@ nsTableCellReflowState::nsTableCellReflowState(nsIPresContext* aPresCon
nsReflowReason aReason)
:nsHTMLReflowState(aPresContext, aParentRS, aFrame, aAvailSpace, aReason)
{
- FixUp(aAvailSpace);
}
-nsTableCellReflowState::nsTableCellReflowState(nsIPresContext* aPresContext,
- const nsHTMLReflowState& aParentRS,
- nsIFrame* aFrame,
- const nsSize& aAvailSpace)
- :nsHTMLReflowState(aPresContext, aParentRS, aFrame, aAvailSpace)
+void nsTableCellReflowState::FixUp(const nsSize& aAvailSpace)
{
- FixUp(aAvailSpace);
+ // fix the mComputed values during a pass 2 reflow since the cell can be a percentage base
+ if (NS_UNCONSTRAINEDSIZE != aAvailSpace.width) {
+ if (NS_UNCONSTRAINEDSIZE != mComputedWidth) {
+ mComputedWidth = aAvailSpace.width - mComputedBorderPadding.left - mComputedBorderPadding.right;
+ mComputedWidth = PR_MAX(0, mComputedWidth);
+ }
+ if (NS_UNCONSTRAINEDSIZE != mComputedHeight) {
+ if (NS_UNCONSTRAINEDSIZE != aAvailSpace.height) {
+ mComputedHeight = aAvailSpace.height - mComputedBorderPadding.top - mComputedBorderPadding.bottom;
+ mComputedHeight = PR_MAX(0, mComputedHeight);
+ }
+ }
+ }
+}
+
+void
+nsTableRowFrame::InitChildReflowState(nsIPresContext& aPresContext,
+ const nsSize& aAvailSize,
+ PRBool aBorderCollapse,
+ float aPixelsToTwips,
+ nsTableCellReflowState& aReflowState)
+{
+ nsMargin collapseBorder;
+ nsMargin* pCollapseBorder = nsnull;
+ if (aBorderCollapse) {
+ // we only reflow cells, so don't need to check frame type
+ nsBCTableCellFrame* bcCellFrame = (nsBCTableCellFrame*)aReflowState.frame;
+ if (bcCellFrame) {
+ pCollapseBorder = bcCellFrame->GetBorderWidth(aPixelsToTwips, collapseBorder);
+ }
+ }
+ aReflowState.Init(&aPresContext, -1, -1, pCollapseBorder);
+ aReflowState.FixUp(aAvailSize);
}
void
@@ -132,23 +154,6 @@ nsTableRowFrame::SetPctHeight(float aPctValue,
}
}
-void nsTableCellReflowState::FixUp(const nsSize& aAvailSpace)
-{
- // fix the mComputed values during a pass 2 reflow since the cell can be a percentage base
- if (NS_UNCONSTRAINEDSIZE != aAvailSpace.width) {
- if (NS_UNCONSTRAINEDSIZE != mComputedWidth) {
- mComputedWidth = aAvailSpace.width - mComputedBorderPadding.left - mComputedBorderPadding.right;
- mComputedWidth = PR_MAX(0, mComputedWidth);
- }
- if (NS_UNCONSTRAINEDSIZE != mComputedHeight) {
- if (NS_UNCONSTRAINEDSIZE != aAvailSpace.height) {
- mComputedHeight = aAvailSpace.height - mComputedBorderPadding.top - mComputedBorderPadding.bottom;
- mComputedHeight = PR_MAX(0, mComputedHeight);
- }
- }
- }
-}
-
// 'old' is old cached cell's desired size
// 'new' is new cell's size including style constraints
static PRBool
@@ -217,7 +222,7 @@ nsTableRowFrame::SetInitialChildList(nsIPresContext* aPresContext,
kidFrame->GetNextSibling(&kidFrame)) {
nsCOMPtr frameType;
kidFrame->GetFrameType(getter_AddRefs(frameType));
- if (nsLayoutAtoms::tableCellFrame == frameType.get()) {
+ if (IS_TABLE_CELL(frameType.get())) {
if (((nsTableCellFrame*)kidFrame)->GetRowSpan() > 1) {
mState |= NS_FRAME_OUTSIDE_CHILDREN;
}
@@ -241,7 +246,7 @@ nsTableRowFrame::AppendFrames(nsIPresContext* aPresContext,
for (nsIFrame* childFrame = aFrameList; childFrame; childFrame->GetNextSibling(&childFrame)) {
nsCOMPtr frameType;
childFrame->GetFrameType(getter_AddRefs(frameType));
- if (nsLayoutAtoms::tableCellFrame == frameType.get()) {
+ if (IS_TABLE_CELL(frameType.get())) {
// Add the cell to the cell map
tableFrame->AppendCell(*aPresContext, (nsTableCellFrame&)*childFrame, GetRowIndex());
// XXX this could be optimized with some effort
@@ -272,12 +277,13 @@ nsTableRowFrame::InsertFrames(nsIPresContext* aPresContext,
nsTableFrame::GetTableFrame(this, tableFrame);
// gather the new frames (only those which are cells) into an array
- nsTableCellFrame* prevCellFrame = (nsTableCellFrame *)nsTableFrame::GetFrameAtOrBefore(aPresContext, this, aPrevFrame, nsLayoutAtoms::tableCellFrame);
+ nsIAtom* cellFrameType = (tableFrame->IsBorderCollapse()) ? nsLayoutAtoms::bcTableCellFrame : nsLayoutAtoms::tableCellFrame;
+ nsTableCellFrame* prevCellFrame = (nsTableCellFrame *)nsTableFrame::GetFrameAtOrBefore(aPresContext, this, aPrevFrame, cellFrameType);
nsVoidArray cellChildren;
for (nsIFrame* childFrame = aFrameList; childFrame; childFrame->GetNextSibling(&childFrame)) {
nsCOMPtr frameType;
childFrame->GetFrameType(getter_AddRefs(frameType));
- if (nsLayoutAtoms::tableCellFrame == frameType.get()) {
+ if (IS_TABLE_CELL(frameType.get())) {
cellChildren.AppendElement(childFrame);
// XXX this could be optimized with some effort
tableFrame->SetNeedStrategyInit(PR_TRUE);
@@ -315,7 +321,7 @@ nsTableRowFrame::RemoveFrame(nsIPresContext* aPresContext,
if (tableFrame) {
nsCOMPtr frameType;
aOldFrame->GetFrameType(getter_AddRefs(frameType));
- if (nsLayoutAtoms::tableCellFrame == frameType.get()) {
+ if (IS_TABLE_CELL(frameType.get())) {
nsTableCellFrame* cellFrame = (nsTableCellFrame*)aOldFrame;
PRInt32 colIndex;
cellFrame->GetColIndex(colIndex);
@@ -372,7 +378,7 @@ nsTableRowFrame::GetFirstCell()
while (childFrame) {
nsCOMPtr frameType;
childFrame->GetFrameType(getter_AddRefs(frameType));
- if (nsLayoutAtoms::tableCellFrame == frameType.get()) {
+ if (IS_TABLE_CELL(frameType.get())) {
return (nsTableCellFrame*)childFrame;
}
childFrame->GetNextSibling(&childFrame);
@@ -398,7 +404,7 @@ nsTableRowFrame::DidResize(nsIPresContext* aPresContext,
while (childFrame) {
nsCOMPtr frameType;
childFrame->GetFrameType(getter_AddRefs(frameType));
- if (nsLayoutAtoms::tableCellFrame == frameType.get()) {
+ if (IS_TABLE_CELL(frameType.get())) {
nsTableCellFrame* cellFrame = (nsTableCellFrame*)childFrame;
nscoord cellHeight = mRect.height + GetHeightOfRowsSpannedBelowFirst(*cellFrame, *tableFrame);
@@ -534,7 +540,7 @@ nsTableRowFrame::CalcHeight(const nsHTMLReflowState& aReflowState)
for (nsIFrame* kidFrame = mFrames.FirstChild(); kidFrame; kidFrame->GetNextSibling(&kidFrame)) {
nsCOMPtr frameType;
kidFrame->GetFrameType(getter_AddRefs(frameType));
- if (nsLayoutAtoms::tableCellFrame == frameType.get()) {
+ if (IS_TABLE_CELL(frameType.get())) {
nscoord availWidth = ((nsTableCellFrame *)kidFrame)->GetPriorAvailWidth();
nsSize desSize = ((nsTableCellFrame *)kidFrame)->GetDesiredSize();
if ((NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight) && !mPrevInFlow) {
@@ -888,28 +894,29 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext,
aStatus = NS_FRAME_COMPLETE;
if (!mFrames.FirstChild()) return NS_OK;
- nsTableFrame* tableFrame = &aTableFrame;
- if (!tableFrame) return NS_ERROR_NULL_POINTER;
+ GET_PIXELS_TO_TWIPS(aPresContext, p2t);
+ PRBool borderCollapse = (((nsTableFrame*)aTableFrame.GetFirstInFlow())->IsBorderCollapse());
+
nsIFrame* tablePrevInFlow;
- tableFrame->GetPrevInFlow(&tablePrevInFlow);
+ aTableFrame.GetPrevInFlow(&tablePrevInFlow);
PRBool isPaginated;
aPresContext->IsPaginated(&isPaginated);
nsresult rv = NS_OK;
- nscoord cellSpacingX = tableFrame->GetCellSpacingX();
+ nscoord cellSpacingX = aTableFrame.GetCellSpacingX();
PRInt32 cellColSpan = 1; // must be defined here so it's set properly for non-cell kids
nsTableIteration dir = (aReflowState.availableWidth == NS_UNCONSTRAINEDSIZE)
? eTableLTR : eTableDIR;
nsTableIterator iter(aPresContext, *this, dir);
// remember the col index of the previous cell to handle rowspans into this row
- PRInt32 firstPrevColIndex = (iter.IsLeftToRight()) ? -1 : tableFrame->GetColCount();
+ PRInt32 firstPrevColIndex = (iter.IsLeftToRight()) ? -1 : aTableFrame.GetColCount();
PRInt32 prevColIndex = firstPrevColIndex;
nscoord x = 0; // running total of children x offset
- nsTableFrame* tableFirstInFlow = (nsTableFrame*)tableFrame->GetFirstInFlow();
- PRBool isAutoLayout = tableFrame->IsAutoLayout();
+ nsTableFrame* tableFirstInFlow = (nsTableFrame*)aTableFrame.GetFirstInFlow();
+ PRBool isAutoLayout = aTableFrame.IsAutoLayout();
PRBool needToNotifyTable = PR_TRUE;
nscoord paginatedHeight = 0;
// If the incremental reflow command is a StyleChanged reflow and
@@ -945,7 +952,7 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext,
doReflowChild = PR_FALSE;
}
if (aReflowState.mFlags.mSpecialHeightReflow) {
- if (!isPaginated && (nsLayoutAtoms::tableCellFrame == frameType.get() &&
+ if (!isPaginated && (IS_TABLE_CELL(frameType.get()) &&
!((nsTableCellFrame*)kidFrame)->NeedSpecialReflow())) {
kidFrame = iter.Next();
continue;
@@ -954,22 +961,22 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext,
// Reflow the child frame
if (doReflowChild) {
- if (nsLayoutAtoms::tableCellFrame == frameType.get()) {
+ if (IS_TABLE_CELL(frameType.get())) {
nsTableCellFrame* cellFrame = (nsTableCellFrame*)kidFrame;
PRInt32 cellColIndex;
cellFrame->GetColIndex(cellColIndex);
- cellColSpan = tableFrame->GetEffectiveColSpan(*cellFrame);
+ cellColSpan = aTableFrame.GetEffectiveColSpan(*cellFrame);
x += cellSpacingX;
// If the adjacent cell is in a prior row (because of a rowspan) add in the space
if ((iter.IsLeftToRight() && (prevColIndex != (cellColIndex - 1))) ||
(!iter.IsLeftToRight() && (prevColIndex != cellColIndex + cellColSpan))) {
- x += GetSpaceBetween(prevColIndex, cellColIndex, cellColSpan, *tableFrame,
+ x += GetSpaceBetween(prevColIndex, cellColIndex, cellColSpan, aTableFrame,
cellSpacingX, iter.IsLeftToRight());
}
// Calculate the available width for the table cell using the known column widths
nscoord availColWidth, availCellWidth;
- CalcAvailWidth(*tableFrame, GetComputedWidth(aReflowState, *tableFrame),
+ CalcAvailWidth(aTableFrame, GetComputedWidth(aReflowState, aTableFrame),
*cellFrame, cellSpacingX, availColWidth, availCellWidth);
if (0 == availColWidth) availColWidth = NS_UNCONSTRAINEDSIZE;
if (0 == availCellWidth) availCellWidth = NS_UNCONSTRAINEDSIZE;
@@ -1032,6 +1039,8 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext,
// Reflow the child
nsTableCellReflowState kidReflowState(aPresContext, aReflowState,
kidFrame, kidAvailSize, reason);
+ InitChildReflowState(*aPresContext, kidAvailSize, borderCollapse, p2t, kidReflowState);
+
nsReflowStatus status;
rv = ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState,
x, 0, 0, status);
@@ -1052,7 +1061,7 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext,
// allow the table to determine if/how the table needs to be rebalanced
if (cellToWatch && needToNotifyTable) {
- needToNotifyTable = !tableFrame->CellChangedWidth(*cellFrame, oldMaxWidth, oldMaxElemWidth);
+ needToNotifyTable = !aTableFrame.CellChangedWidth(*cellFrame, oldMaxWidth, oldMaxElemWidth);
}
// If any of the cells are not complete, then we're not complete
@@ -1081,10 +1090,10 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext,
// height may have changed, adjust descent to absorb any excess difference
nscoord ascent = cellFrame->GetDesiredAscent();
nscoord descent = desiredSize.height - ascent;
- UpdateHeight(desiredSize.height, ascent, descent, tableFrame, cellFrame);
+ UpdateHeight(desiredSize.height, ascent, descent, &aTableFrame, cellFrame);
}
else {
- PRInt32 rowSpan = tableFrame->GetEffectiveRowSpan((nsTableCellFrame&)*kidFrame);
+ PRInt32 rowSpan = aTableFrame.GetEffectiveRowSpan((nsTableCellFrame&)*kidFrame);
if ((1 == rowSpan) && (desiredSize.height > paginatedHeight)) {
paginatedHeight = desiredSize.height;
SetContentHeight(paginatedHeight);
@@ -1102,13 +1111,14 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext,
else {// it's an unknown frame type, give it a generic reflow and ignore the results
nsTableCellReflowState kidReflowState(aPresContext, aReflowState,
kidFrame, nsSize(0,0), eReflowReason_Resize);
+ InitChildReflowState(*aPresContext, nsSize(0,0), PR_FALSE, p2t, kidReflowState);
nsHTMLReflowMetrics desiredSize(nsnull);
nsReflowStatus status;
ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState, 0, 0, 0, status);
kidFrame->DidReflow(aPresContext, nsnull, NS_FRAME_REFLOW_FINISHED);
}
}
- else if (nsLayoutAtoms::tableCellFrame == frameType.get()) {
+ else if (IS_TABLE_CELL(frameType.get())) {
// we need to account for the cell's width even if it isn't reflowed
nsRect rect;
kidFrame->GetRect(rect);
@@ -1244,7 +1254,10 @@ nsTableRowFrame::IR_TargetIsChild(nsIPresContext* aPresContext,
// update its maximum width.
nsHTMLReflowMetrics cellMet(&kidMaxElementSize, isAutoLayout ?
NS_REFLOW_CALC_MAX_WIDTH : 0);
- nsTableCellReflowState kidRS(aPresContext, aReflowState, aNextFrame, cellAvailSize);
+ GET_PIXELS_TO_TWIPS(aPresContext, p2t);
+ nsTableCellReflowState kidRS(aPresContext, aReflowState, aNextFrame, cellAvailSize,
+ aReflowState.reason);
+ InitChildReflowState(*aPresContext, cellAvailSize, aTableFrame.IsBorderCollapse(), p2t, kidRS);
// Remember the current desired size, we'll need it later
nscoord oldCellMinWidth = cellFrame->GetPass1MaxElementWidth();
@@ -1492,13 +1505,20 @@ nsTableRowFrame::ReflowCellFrame(nsIPresContext* aPresContext,
nscoord aAvailableHeight,
nsReflowStatus& aStatus)
{
+ nsTableFrame* tableFrame = nsnull;
+ nsTableFrame::GetTableFrame(this, tableFrame); if (!tableFrame) ABORT1(0);
+
// Reflow the cell frame with the specified height. Use the existing width
nsSize cellSize;
aCellFrame->GetSize(cellSize);
nsSize availSize(cellSize.width, aAvailableHeight);
+ PRBool borderCollapse = ((nsTableFrame*)tableFrame->GetFirstInFlow())->IsBorderCollapse();
+ GET_PIXELS_TO_TWIPS(aPresContext, p2t);
nsTableCellReflowState cellReflowState(aPresContext, aReflowState, aCellFrame, availSize,
eReflowReason_Resize);
+ InitChildReflowState(*aPresContext, availSize, borderCollapse, p2t, cellReflowState);
+
nsHTMLReflowMetrics desiredSize(nsnull);
ReflowChild(aCellFrame, aPresContext, desiredSize, cellReflowState,
@@ -1534,7 +1554,7 @@ nsTableRowFrame::InsertCellFrame(nsTableCellFrame* aFrame,
for (nsIFrame* child = mFrames.FirstChild(); child; child->GetNextSibling(&child)) {
nsCOMPtr frameType;
child->GetFrameType(getter_AddRefs(frameType));
- if (nsLayoutAtoms::tableCellFrame != frameType.get()) {
+ if (!IS_TABLE_CELL(frameType.get())) {
nsTableCellFrame* cellFrame = (nsTableCellFrame*)child;
PRInt32 colIndex;
cellFrame->GetColIndex(colIndex);
diff --git a/mozilla/layout/tables/nsTableRowFrame.h b/mozilla/layout/tables/nsTableRowFrame.h
index 552ee7910b3..d05dc5eab6a 100644
--- a/mozilla/layout/tables/nsTableRowFrame.h
+++ b/mozilla/layout/tables/nsTableRowFrame.h
@@ -42,6 +42,7 @@
class nsTableFrame;
class nsTableCellFrame;
+struct nsTableCellReflowState;
#ifdef DEBUG_TABLE_REFLOW_TIMING
class nsReflowTimer;
@@ -240,6 +241,12 @@ public:
nscoord GetUnpaginatedHeight(nsIPresContext* aPresContext);
void SetUnpaginatedHeight(nsIPresContext* aPresContext, nscoord aValue);
+ nscoord GetTopBCBorderWidth(float* aPixelsToTwips = nsnull);
+ void SetTopBCBorderWidth(nscoord aWidth);
+ nscoord GetBottomBCBorderWidth(float* aPixelsToTwips = nsnull);
+ void SetBottomBCBorderWidth(nscoord aWidth);
+ nsMargin* GetBCBorderWidth(float aPixelsToTwips,
+ nsMargin& aBorder);
protected:
/** protected constructor.
@@ -247,6 +254,12 @@ protected:
*/
nsTableRowFrame();
+ void InitChildReflowState(nsIPresContext& aPresContext,
+ const nsSize& aAvailSize,
+ PRBool aBorderCollapse,
+ float aPixelsToTwips,
+ nsTableCellReflowState& aReflowState);
+
/** implement abstract method on nsHTMLContainerFrame */
virtual PRIntn GetSkipSides() const;
@@ -315,6 +328,10 @@ private:
nscoord mMaxCellAscent; // does include cells with rowspan > 1
nscoord mMaxCellDescent; // does *not* include cells with rowspan > 1
+ // border widths in pixels in the collapsing border model
+ unsigned mTopBorderWidth:8;
+ unsigned mBottomBorderWidth:8;
+
#ifdef DEBUG_TABLE_REFLOW_TIMING
public:
nsReflowTimer* mTimer;
@@ -421,4 +438,37 @@ inline void nsTableRowFrame::SetHasUnpaginatedHeight(PRBool aValue)
}
}
+inline nscoord nsTableRowFrame::GetTopBCBorderWidth(float* aPixelsToTwips)
+{
+ nscoord width = (aPixelsToTwips) ? NSToCoordRound(*aPixelsToTwips * mTopBorderWidth) : mTopBorderWidth;
+ return width;
+}
+
+inline void nsTableRowFrame::SetTopBCBorderWidth(nscoord aWidth)
+{
+ mTopBorderWidth = aWidth;
+}
+
+inline nscoord nsTableRowFrame::GetBottomBCBorderWidth(float* aPixelsToTwips)
+{
+ nscoord width = (aPixelsToTwips) ? NSToCoordRound(*aPixelsToTwips * mBottomBorderWidth) : mBottomBorderWidth;
+ return width;
+}
+
+inline void nsTableRowFrame::SetBottomBCBorderWidth(nscoord aWidth)
+{
+ mBottomBorderWidth = aWidth;
+}
+
+inline nsMargin* nsTableRowFrame::GetBCBorderWidth(float aPixelsToTwips,
+ nsMargin& aBorder)
+{
+ aBorder.left = aBorder.right = 0;
+
+ aBorder.top = NSToCoordRound(aPixelsToTwips * mTopBorderWidth);
+ aBorder.bottom = NSToCoordRound(aPixelsToTwips * mBottomBorderWidth);
+
+ return &aBorder;
+}
+
#endif
diff --git a/mozilla/layout/tables/nsTableRowGroupFrame.cpp b/mozilla/layout/tables/nsTableRowGroupFrame.cpp
index f0ff97530bb..2405a50a342 100644
--- a/mozilla/layout/tables/nsTableRowGroupFrame.cpp
+++ b/mozilla/layout/tables/nsTableRowGroupFrame.cpp
@@ -180,7 +180,7 @@ nsTableRowGroupFrame::InitRepeatedFrame(nsIPresContext* aPresContext,
nsIAtom* frameType;
copyCellFrame->GetFrameType(&frameType);
- if (nsLayoutAtoms::tableCellFrame == frameType) {
+ if (IS_TABLE_CELL(frameType)) {
#ifdef NS_DEBUG
nsIContent* content1;
nsIContent* content2;
@@ -360,6 +360,28 @@ nsTableRowGroupFrame::PlaceChild(nsIPresContext* aPresContext,
}
}
+void
+nsTableRowGroupFrame::InitChildReflowState(nsIPresContext& aPresContext,
+ PRBool aBorderCollapse,
+ float aPixelsToTwips,
+ nsHTMLReflowState& aReflowState)
+{
+ nsMargin collapseBorder;
+ nsMargin padding(0,0,0,0);
+ nsMargin* pCollapseBorder = nsnull;
+ if (aBorderCollapse) {
+ if (aReflowState.frame) {
+ nsCOMPtr fType;
+ aReflowState.frame->GetFrameType(getter_AddRefs(fType));
+ if (nsLayoutAtoms::tableRowFrame == fType.get()) {
+ nsTableRowFrame* rowFrame = (nsTableRowFrame*)aReflowState.frame;
+ pCollapseBorder = rowFrame->GetBCBorderWidth(aPixelsToTwips, collapseBorder);
+ }
+ }
+ }
+ aReflowState.Init(&aPresContext, -1, -1, pCollapseBorder, &padding);
+}
+
// Reflow the frames we've already created. If aDirtyOnly is set then only
// reflow dirty frames. This assumes that all of the dirty frames are contiguous.
NS_METHOD
@@ -372,8 +394,10 @@ nsTableRowGroupFrame::ReflowChildren(nsIPresContext* aPresContext,
nsTableRowFrame** aFirstRowReflowed)
{
nsTableFrame* tableFrame = nsnull;
- nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame);
- if (NS_FAILED(rv) || !tableFrame) return rv;
+ nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame); if (!tableFrame) ABORT1(rv);
+
+ PRBool borderCollapse = tableFrame->IsBorderCollapse();
+ GET_PIXELS_TO_TWIPS(aPresContext, p2t);
nscoord cellSpacingY = tableFrame->GetCellSpacingY();
@@ -439,6 +463,7 @@ nsTableRowGroupFrame::ReflowChildren(nsIPresContext* aPresContext,
}
nsHTMLReflowState kidReflowState(aPresContext, aReflowState.reflowState, kidFrame,
kidAvailSize, reason);
+ InitChildReflowState(*aPresContext, borderCollapse, p2t, kidReflowState);
// If this isn't the first row frame, then we can't be at the top of
// the page anymore...
@@ -555,7 +580,7 @@ HasMoreThanOneCell(nsTableCellMap* aCellMap,
PRInt32 colIndex = 0;
PRInt32 count = 0;
do {
- cellData = aCellMap->GetCellAt(aRowIndex, colIndex);
+ cellData = aCellMap->GetDataAt(aRowIndex, colIndex);
if (cellData && (cellData->GetCellFrame() || cellData->IsRowSpan()))
count++;
if (count > 1)
@@ -998,8 +1023,8 @@ nsTableRowGroupFrame::SplitRowGroup(nsIPresContext* aPresContext,
presShell->GetStyleSet(getter_AddRefs(styleSet));
if (!styleSet) {NS_ASSERTION(PR_FALSE, "no style set"); return NS_ERROR_NULL_POINTER;}
- float p2t;
- aPresContext->GetPixelsToTwips(&p2t);
+ GET_PIXELS_TO_TWIPS(aPresContext, p2t);
+ PRBool borderCollapse = ((nsTableFrame*)aTableFrame->GetFirstInFlow())->IsBorderCollapse();
nscoord availWidth = nsTableFrame::RoundToPixel(aReflowState.availableWidth, p2t);
nscoord availHeight = nsTableFrame::RoundToPixel(aReflowState.availableHeight, p2t);
@@ -1022,9 +1047,11 @@ nsTableRowGroupFrame::SplitRowGroup(nsIPresContext* aPresContext,
// row or there is at least 5% of the current page available
if (!prevRowFrame || (availHeight - aDesiredSize.height > pageHeight / 20)) {
// Reflow the row in the available space and have it split
- nsSize availSize(availWidth, availHeight - bounds.y);
- nsHTMLReflowState rowReflowState(aPresContext, aReflowState, rowFrame,
- availSize, eReflowReason_Resize);
+ nsSize availSize(availWidth, availHeight - bounds.y);
+ nsHTMLReflowState rowReflowState(aPresContext, aReflowState, rowFrame, availSize,
+ eReflowReason_Resize);
+ InitChildReflowState(*aPresContext, borderCollapse, p2t, rowReflowState);
+
nsHTMLReflowMetrics desiredSize(nsnull);
rv = ReflowChild(rowFrame, aPresContext, desiredSize, rowReflowState,
@@ -1530,6 +1557,10 @@ nsTableRowGroupFrame::IR_TargetIsChild(nsIPresContext* aPresContext,
{
nsresult rv;
+ nsTableFrame* tableFrame = nsnull;
+ nsTableFrame::GetTableFrame(this, tableFrame); if (!tableFrame) ABORT1(NS_ERROR_NULL_POINTER);
+ GET_PIXELS_TO_TWIPS(aPresContext, p2t);
+
// Recover the state as if aNextFrame is about to be reflowed
RecoverState(aReflowState, aNextFrame);
@@ -1540,9 +1571,11 @@ nsTableRowGroupFrame::IR_TargetIsChild(nsIPresContext* aPresContext,
// Reflow the child giving it as much room as it wants. We'll deal with
// splitting later after final determination of rows heights taking into
// account cells with row spans...
- nsSize kidAvailSize(aReflowState.availSize.width, NS_UNCONSTRAINEDSIZE);
- nsHTMLReflowState kidReflowState(aPresContext, aReflowState.reflowState,
- aNextFrame, kidAvailSize);
+ nsSize kidAvailSize(aReflowState.availSize.width, NS_UNCONSTRAINEDSIZE);
+ nsHTMLReflowState kidReflowState(aPresContext, aReflowState.reflowState, aNextFrame,
+ kidAvailSize, aReflowState.reason);
+ InitChildReflowState(*aPresContext, tableFrame->IsBorderCollapse(), p2t, kidReflowState);
+
nsSize kidMaxElementSize;
nsHTMLReflowMetrics desiredSize(aDesiredSize.maxElementSize ? &kidMaxElementSize : nsnull,
aDesiredSize.mFlags);
@@ -1715,6 +1748,28 @@ nsTableRowGroupFrame::SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) cons
}
#endif
+nsMargin*
+nsTableRowGroupFrame::GetBCBorderWidth(float aPixelsToTwips,
+ nsMargin& aBorder)
+{
+ aBorder.left = aBorder.right = 0;
+
+ nsTableRowFrame* firstRowFrame = nsnull;
+ nsTableRowFrame* lastRowFrame = nsnull;
+ for (nsTableRowFrame* rowFrame = GetFirstRow(); rowFrame; rowFrame = rowFrame->GetNextRow()) {
+ if(!firstRowFrame) {
+ firstRowFrame = rowFrame;
+ }
+ lastRowFrame = rowFrame;
+ }
+ if (firstRowFrame) {
+ aBorder.top = firstRowFrame->GetTopBCBorderWidth(&aPixelsToTwips);
+ aBorder.bottom = lastRowFrame->GetBottomBCBorderWidth(&aPixelsToTwips);
+ }
+
+ return &aBorder;
+}
+
//nsILineIterator methods for nsTableFrame
NS_IMETHODIMP
nsTableRowGroupFrame::GetNumLines(PRInt32* aResult)
@@ -1757,7 +1812,7 @@ nsTableRowGroupFrame::GetLine(PRInt32 aLineNumber,
*aLineFlags = 0;/// should we fill these in later?
// not gonna touch aLineBounds right now
- CellData* firstCellData = cellMap->GetCellAt(aLineNumber, 0);
+ CellData* firstCellData = cellMap->GetDataAt(aLineNumber, 0);
if(!firstCellData)
return NS_ERROR_FAILURE;
@@ -1767,7 +1822,7 @@ nsTableRowGroupFrame::GetLine(PRInt32 aLineNumber,
while((aLineNumber > 0)&&(!(*aFirstFrameOnLine)))
{
aLineNumber--;
- firstCellData = cellMap->GetCellAt(aLineNumber, 0);
+ firstCellData = cellMap->GetDataAt(aLineNumber, 0);
*aFirstFrameOnLine = (nsIFrame*)firstCellData->GetCellFrame();
}
}
@@ -1847,7 +1902,7 @@ nsTableRowGroupFrame::FindFrameAt(PRInt32 aLineNumber,
PRBool gotParentRect = PR_FALSE;
for(int i =0;i < cellCount; i++)
{
- cellData = cellMap->GetCellAt(aLineNumber, i);
+ cellData = cellMap->GetDataAt(aLineNumber, i);
tempFrame = (nsIFrame*)cellData->GetCellFrame();
if(!tempFrame)
@@ -1919,11 +1974,11 @@ nsTableRowGroupFrame::GetNextSiblingOnLine(nsIFrame*& aFrame,
PRInt32& colIndexRef = colIndex;
cellFrame->GetColIndex(colIndexRef);
- CellData* cellData = cellMap->GetCellAt(aLineNumber, colIndex + 1);
+ CellData* cellData = cellMap->GetDataAt(aLineNumber, colIndex + 1);
if(!cellData)// if this isnt a valid cell, drop down and check the next line
{
- cellData = cellMap->GetCellAt(aLineNumber + 1, 0);
+ cellData = cellMap->GetDataAt(aLineNumber + 1, 0);
if(!cellData)
{
//*aFrame = nsnull;
@@ -1940,14 +1995,14 @@ nsTableRowGroupFrame::GetNextSiblingOnLine(nsIFrame*& aFrame,
while((tempCol > 0) && (!aFrame))
{
tempCol--;
- cellData = cellMap->GetCellAt(aLineNumber, tempCol);
+ cellData = cellMap->GetDataAt(aLineNumber, tempCol);
aFrame = (nsIFrame*)cellData->GetCellFrame();
if(!aFrame && (tempCol==0))
{
while((tempRow > 0) && (!aFrame))
{
tempRow--;
- cellData = cellMap->GetCellAt(tempRow, 0);
+ cellData = cellMap->GetDataAt(tempRow, 0);
aFrame = (nsIFrame*)cellData->GetCellFrame();
}
}
diff --git a/mozilla/layout/tables/nsTableRowGroupFrame.h b/mozilla/layout/tables/nsTableRowGroupFrame.h
index 0a3859755b4..d259a63bdfb 100644
--- a/mozilla/layout/tables/nsTableRowGroupFrame.h
+++ b/mozilla/layout/tables/nsTableRowGroupFrame.h
@@ -216,6 +216,8 @@ public:
nscoord GetHeightOfRows(nsIPresContext* aPresContext);
nscoord GetHeightBasis(const nsHTMLReflowState& aReflowState);
+ nsMargin* GetBCBorderWidth(float aPixelsToTwips,
+ nsMargin& aBorder);
// nsILineIterator methods
public:
NS_IMETHOD GetNumLines(PRInt32* aResult);
@@ -251,6 +253,11 @@ public:
protected:
nsTableRowGroupFrame();
+ void InitChildReflowState(nsIPresContext& aPresContext,
+ PRBool aBorderCollapse,
+ float aPixelsToTwips,
+ nsHTMLReflowState& aReflowState);
+
/** implement abstract method on nsHTMLContainerFrame */
virtual PRIntn GetSkipSides() const;