diff --git a/accessible/html/HTMLTableAccessible.cpp b/accessible/html/HTMLTableAccessible.cpp
index b0cdc0932..af7dd561f 100644
--- a/accessible/html/HTMLTableAccessible.cpp
+++ b/accessible/html/HTMLTableAccessible.cpp
@@ -175,23 +175,17 @@ HTMLTableCellAccessible::Table() const
uint32_t
HTMLTableCellAccessible::ColIdx() const
{
- nsITableCellLayout* cellLayout = GetCellLayout();
- NS_ENSURE_TRUE(cellLayout, 0);
-
- int32_t colIdx = 0;
- cellLayout->GetColIndex(colIdx);
- return colIdx > 0 ? static_cast(colIdx) : 0;
+ nsTableCellFrame* cellFrame = GetCellFrame();
+ NS_ENSURE_TRUE(cellFrame, 0);
+ return cellFrame->ColIndex();
}
uint32_t
HTMLTableCellAccessible::RowIdx() const
{
- nsITableCellLayout* cellLayout = GetCellLayout();
- NS_ENSURE_TRUE(cellLayout, 0);
-
- int32_t rowIdx = 0;
- cellLayout->GetRowIndex(rowIdx);
- return rowIdx > 0 ? static_cast(rowIdx) : 0;
+ nsTableCellFrame* cellFrame = GetCellFrame();
+ NS_ENSURE_TRUE(cellFrame, 0);
+ return cellFrame->RowIndex();
}
uint32_t
@@ -285,6 +279,12 @@ HTMLTableCellAccessible::GetCellLayout() const
return do_QueryFrame(mContent->GetPrimaryFrame());
}
+nsTableCellFrame*
+HTMLTableCellAccessible::GetCellFrame() const
+{
+ return do_QueryFrame(mContent->GetPrimaryFrame());
+}
+
nsresult
HTMLTableCellAccessible::GetCellIndexes(int32_t& aRowIdx, int32_t& aColIdx) const
{
@@ -520,11 +520,9 @@ HTMLTableAccessible::SelectedCellCount()
if (!cellFrame || !cellFrame->IsSelected())
continue;
- int32_t startRow = -1, startCol = -1;
- cellFrame->GetRowIndex(startRow);
- cellFrame->GetColIndex(startCol);
- if (startRow >= 0 && (uint32_t)startRow == rowIdx &&
- startCol >= 0 && (uint32_t)startCol == colIdx)
+ uint32_t startRow = cellFrame->RowIndex();
+ uint32_t startCol = cellFrame->ColIndex();
+ if (startRow == rowIdx && startCol == colIdx)
count++;
}
}
@@ -570,11 +568,9 @@ HTMLTableAccessible::SelectedCells(nsTArray* aCells)
if (!cellFrame || !cellFrame->IsSelected())
continue;
- int32_t startCol = -1, startRow = -1;
- cellFrame->GetRowIndex(startRow);
- cellFrame->GetColIndex(startCol);
- if ((startRow >= 0 && (uint32_t)startRow != rowIdx) ||
- (startCol >= 0 && (uint32_t)startCol != colIdx))
+ uint32_t startRow = cellFrame->RowIndex();
+ uint32_t startCol = cellFrame->ColIndex();
+ if (startRow != rowIdx || startCol != colIdx)
continue;
Accessible* cell = mDoc->GetAccessible(cellFrame->GetContent());
@@ -597,11 +593,9 @@ HTMLTableAccessible::SelectedCellIndices(nsTArray* aCells)
if (!cellFrame || !cellFrame->IsSelected())
continue;
- int32_t startRow = -1, startCol = -1;
- cellFrame->GetColIndex(startCol);
- cellFrame->GetRowIndex(startRow);
- if (startRow >= 0 && (uint32_t)startRow == rowIdx &&
- startCol >= 0 && (uint32_t)startCol == colIdx)
+ uint32_t startCol = cellFrame->ColIndex();
+ uint32_t startRow = cellFrame->RowIndex();
+ if (startRow == rowIdx && startCol == colIdx)
aCells->AppendElement(CellIndexAt(rowIdx, colIdx));
}
}
diff --git a/accessible/html/HTMLTableAccessible.h b/accessible/html/HTMLTableAccessible.h
index 830d34ae9..c7cfc9ddf 100644
--- a/accessible/html/HTMLTableAccessible.h
+++ b/accessible/html/HTMLTableAccessible.h
@@ -11,6 +11,7 @@
#include "TableCellAccessible.h"
class nsITableCellLayout;
+class nsTableCellFrame;
namespace mozilla {
namespace a11y {
@@ -53,6 +54,11 @@ protected:
*/
nsITableCellLayout* GetCellLayout() const;
+ /**
+ * Return the table cell frame.
+ */
+ nsTableCellFrame* GetCellFrame() const;
+
/**
* Return row and column indices of the cell.
*/
diff --git a/dom/base/nsAttrValue.cpp b/dom/base/nsAttrValue.cpp
index ebddcb7ed..2418fb501 100644
--- a/dom/base/nsAttrValue.cpp
+++ b/dom/base/nsAttrValue.cpp
@@ -1526,6 +1526,40 @@ nsAttrValue::ParseIntWithFallback(const nsAString& aString, int32_t aDefault,
SetIntValueAndType(val, eInteger, nonStrict ? &aString : nullptr);
}
+void
+nsAttrValue::ParseClampedNonNegativeInt(const nsAString& aString,
+ int32_t aDefault, int32_t aMin,
+ int32_t aMax)
+{
+ ResetIfSet();
+
+ nsContentUtils::ParseHTMLIntegerResultFlags result;
+ int32_t val = nsContentUtils::ParseHTMLInteger(aString, &result);
+ bool nonStrict = (result & nsContentUtils::eParseHTMLInteger_IsPercent) ||
+ (result & nsContentUtils::eParseHTMLInteger_NonStandard) ||
+ (result & nsContentUtils::eParseHTMLInteger_DidNotConsumeAllInput);
+
+ if (result & nsContentUtils::eParseHTMLInteger_ErrorOverflow) {
+ if (result & nsContentUtils::eParseHTMLInteger_Negative) {
+ val = aDefault;
+ } else {
+ val = aMax;
+ }
+ nonStrict = true;
+ } else if ((result & nsContentUtils::eParseHTMLInteger_Error) || val < 0) {
+ val = aDefault;
+ nonStrict = true;
+ } else if (val < aMin) {
+ val = aMin;
+ nonStrict = true;
+ } else if (val > aMax) {
+ val = aMax;
+ nonStrict = true;
+ }
+
+ SetIntValueAndType(val, eInteger, nonStrict ? &aString : nullptr);
+}
+
bool
nsAttrValue::ParseNonNegativeIntValue(const nsAString& aString)
{
diff --git a/dom/base/nsAttrValue.h b/dom/base/nsAttrValue.h
index 655e4ca61..23f61a614 100644
--- a/dom/base/nsAttrValue.h
+++ b/dom/base/nsAttrValue.h
@@ -362,6 +362,19 @@ public:
*/
bool ParseNonNegativeIntValue(const nsAString& aString);
+ /**
+ * Parse a string value into a clamped non-negative integer.
+ * This method follows the rules for parsing non-negative integer from:
+ * https://html.spec.whatwg.org/multipage/infrastructure.html#clamped-to-the-range
+ *
+ * @param aString the string to parse
+ * @param aDefault value to return for negative or invalid values
+ * @param aMin minimum value
+ * @param aMax maximum value
+ */
+ void ParseClampedNonNegativeInt(const nsAString& aString, int32_t aDefault,
+ int32_t aMin, int32_t aMax);
+
/**
* Parse a string value into a positive integer.
* This method follows the rules for parsing non-negative integer from:
diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp
index b6cbbbace..4f7b71b19 100644
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -1088,6 +1088,7 @@ nsContentUtils::ParseHTMLInteger(const nsAString& aValue,
int sign = 1;
if (*iter == char16_t('-')) {
sign = -1;
+ result |= eParseHTMLInteger_Negative;
++iter;
} else if (*iter == char16_t('+')) {
result |= eParseHTMLInteger_NonStandard;
diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h
index bf6a59dcd..64f7485cb 100644
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -445,7 +445,9 @@ public:
// Set if one or more error flags were set.
eParseHTMLInteger_Error = 1 << 3,
eParseHTMLInteger_ErrorNoValue = 1 << 4,
- eParseHTMLInteger_ErrorOverflow = 1 << 5
+ eParseHTMLInteger_ErrorOverflow = 1 << 5,
+ // Use this flag to detect the difference between overflow and underflow
+ eParseHTMLInteger_Negative = 1 << 6,
};
static int32_t ParseHTMLInteger(const nsAString& aValue,
ParseHTMLIntegerResultFlags *aResult);
diff --git a/dom/html/HTMLTableCellElement.cpp b/dom/html/HTMLTableCellElement.cpp
index d00d60400..1cf413413 100644
--- a/dom/html/HTMLTableCellElement.cpp
+++ b/dom/html/HTMLTableCellElement.cpp
@@ -390,26 +390,16 @@ HTMLTableCellElement::ParseAttribute(int32_t aNamespaceID,
return aResult.ParseIntWithBounds(aValue, 0);
}
if (aAttribute == nsGkAtoms::colspan) {
- bool res = aResult.ParseIntWithBounds(aValue, -1);
- if (res) {
- int32_t val = aResult.GetIntegerValue();
- // reset large colspan values as IE and opera do
- if (val > MAX_COLSPAN || val <= 0) {
- aResult.SetTo(1, &aValue);
- }
- }
- return res;
+ aResult.ParseClampedNonNegativeInt(aValue, 1, 1, MAX_COLSPAN);
+ return true;
}
if (aAttribute == nsGkAtoms::rowspan) {
- bool res = aResult.ParseIntWithBounds(aValue, -1, MAX_ROWSPAN);
- if (res) {
- int32_t val = aResult.GetIntegerValue();
- // quirks mode does not honor the special html 4 value of 0
- if (val < 0 || (0 == val && InNavQuirksMode(OwnerDoc()))) {
+ aResult.ParseClampedNonNegativeInt(aValue, 1, 0, MAX_ROWSPAN);
+ // quirks mode does not honor the special html 4 value of 0
+ if (aResult.GetIntegerValue() == 0 && InNavQuirksMode(OwnerDoc())) {
aResult.SetTo(1, &aValue);
- }
}
- return res;
+ return true;
}
if (aAttribute == nsGkAtoms::height) {
return aResult.ParseSpecialIntValue(aValue);
diff --git a/dom/html/HTMLTableCellElement.h b/dom/html/HTMLTableCellElement.h
index 916333510..ab7a918eb 100644
--- a/dom/html/HTMLTableCellElement.h
+++ b/dom/html/HTMLTableCellElement.h
@@ -37,7 +37,7 @@ public:
}
void SetColSpan(uint32_t aColSpan, ErrorResult& aError)
{
- SetHTMLIntAttr(nsGkAtoms::colspan, aColSpan, aError);
+ SetUnsignedIntAttr(nsGkAtoms::colspan, aColSpan, 1, aError);
}
uint32_t RowSpan() const
{
@@ -45,7 +45,7 @@ public:
}
void SetRowSpan(uint32_t aRowSpan, ErrorResult& aError)
{
- SetHTMLIntAttr(nsGkAtoms::rowspan, aRowSpan, aError);
+ SetUnsignedIntAttr(nsGkAtoms::rowspan, aRowSpan, 1, aError);
}
//already_AddRefed Headers() const;
void GetHeaders(DOMString& aHeaders)
diff --git a/dom/mathml/nsMathMLElement.cpp b/dom/mathml/nsMathMLElement.cpp
index d6aef876c..2be931682 100644
--- a/dom/mathml/nsMathMLElement.cpp
+++ b/dom/mathml/nsMathMLElement.cpp
@@ -9,6 +9,7 @@
#include "base/compiler_specific.h"
#include "mozilla/ArrayUtils.h"
#include "nsGkAtoms.h"
+#include "nsITableCellLayout.h" // for MAX_COLSPAN / MAX_ROWSPAN
#include "nsCRT.h"
#include "nsLayoutStylesheetCache.h"
#include "nsRuleData.h"
@@ -150,8 +151,9 @@ nsMathMLElement::ParseAttribute(int32_t aNamespaceID,
const nsAString& aValue,
nsAttrValue& aResult)
{
+ MOZ_ASSERT(IsMathMLElement());
if (aNamespaceID == kNameSpaceID_None) {
- if (IsMathMLElement(nsGkAtoms::math) && aAttribute == nsGkAtoms::mode) {
+ if (mNodeInfo->Equals(nsGkAtoms::math) && aAttribute == nsGkAtoms::mode) {
WarnDeprecated(nsGkAtoms::mode->GetUTF16String(),
nsGkAtoms::display->GetUTF16String(), OwnerDoc());
}
@@ -165,6 +167,16 @@ nsMathMLElement::ParseAttribute(int32_t aNamespaceID,
aAttribute == nsGkAtoms::mathbackground_) {
return aResult.ParseColor(aValue);
}
+ if (mNodeInfo->Equals(nsGkAtoms::mtd_)) {
+ if (aAttribute == nsGkAtoms::columnspan_) {
+ aResult.ParseClampedNonNegativeInt(aValue, 1, 1, MAX_COLSPAN);
+ return true;
+ }
+ if (aAttribute == nsGkAtoms::rowspan) {
+ aResult.ParseClampedNonNegativeInt(aValue, 1, 0, MAX_ROWSPAN);
+ return true;
+ }
+ }
}
return nsMathMLElementBase::ParseAttribute(aNamespaceID, aAttribute,
@@ -209,6 +221,8 @@ static Element::MappedAttributeEntry sDirStyles[] = {
bool
nsMathMLElement::IsAttributeMapped(const nsIAtom* aAttribute) const
{
+ MOZ_ASSERT(IsMathMLElement());
+
static const MappedAttributeEntry* const mtableMap[] = {
sMtableStyles,
sCommonPresStyles
@@ -240,10 +254,10 @@ nsMathMLElement::IsAttributeMapped(const nsIAtom* aAttribute) const
if (IsAnyOfMathMLElements(nsGkAtoms::mstyle_, nsGkAtoms::math))
return FindAttributeDependence(aAttribute, mstyleMap);
- if (IsMathMLElement(nsGkAtoms::mtable_))
+ if (mNodeInfo->Equals(nsGkAtoms::mtable_))
return FindAttributeDependence(aAttribute, mtableMap);
- if (IsMathMLElement(nsGkAtoms::mrow_))
+ if (mNodeInfo->Equals(nsGkAtoms::mrow_))
return FindAttributeDependence(aAttribute, mrowMap);
if (IsAnyOfMathMLElements(nsGkAtoms::maction_,
diff --git a/editor/libeditor/HTMLTableEditor.cpp b/editor/libeditor/HTMLTableEditor.cpp
index 3da0cfe0c..778bf1d2d 100644
--- a/editor/libeditor/HTMLTableEditor.cpp
+++ b/editor/libeditor/HTMLTableEditor.cpp
@@ -2730,8 +2730,8 @@ HTMLEditor::GetCellDataAt(nsIDOMElement* aTable,
}
*aIsSelected = cellFrame->IsSelected();
- cellFrame->GetRowIndex(*aStartRowIndex);
- cellFrame->GetColIndex(*aStartColIndex);
+ *aStartRowIndex = cellFrame->RowIndex();
+ *aStartColIndex = cellFrame->ColIndex();
*aRowSpan = cellFrame->GetRowSpan();
*aColSpan = cellFrame->GetColSpan();
*aActualRowSpan = tableFrame->GetEffectiveRowSpanAt(aRowIndex, aColIndex);
diff --git a/layout/generic/nsSelection.cpp b/layout/generic/nsSelection.cpp
index ff75ab85d..f2959dc9d 100644
--- a/layout/generic/nsSelection.cpp
+++ b/layout/generic/nsSelection.cpp
@@ -2882,16 +2882,15 @@ nsFrameSelection::UnselectCells(nsIContent *aTableContent,
nsTableCellFrame* cellFrame =
tableFrame->GetCellFrameAt(curRowIndex, curColIndex);
- int32_t origRowIndex, origColIndex;
- cellFrame->GetRowIndex(origRowIndex);
- cellFrame->GetColIndex(origColIndex);
+ uint32_t origRowIndex = cellFrame->RowIndex();
+ uint32_t origColIndex = cellFrame->ColIndex();
uint32_t actualRowSpan =
tableFrame->GetEffectiveRowSpanAt(origRowIndex, origColIndex);
uint32_t actualColSpan =
tableFrame->GetEffectiveColSpanAt(curRowIndex, curColIndex);
- if (origRowIndex <= maxRowIndex && maxRowIndex >= 0 &&
+ if (origRowIndex <= static_cast(maxRowIndex) && maxRowIndex >= 0 &&
origRowIndex + actualRowSpan - 1 >= static_cast(minRowIndex) &&
- origColIndex <= maxColIndex && maxColIndex >= 0 &&
+ origColIndex <= static_cast(maxColIndex) && maxColIndex >= 0 &&
origColIndex + actualColSpan - 1 >= static_cast(minColIndex)) {
mDomSelections[index]->RemoveRange(range);
@@ -2925,33 +2924,32 @@ nsFrameSelection::AddCellsToSelection(nsIContent *aTableContent,
return NS_ERROR_FAILURE;
nsresult result = NS_OK;
- int32_t row = aStartRowIndex;
+ uint32_t row = aStartRowIndex;
while(true)
{
- int32_t col = aStartColumnIndex;
+ uint32_t col = aStartColumnIndex;
while(true)
{
nsTableCellFrame* cellFrame = tableFrame->GetCellFrameAt(row, col);
// Skip cells that are spanned from previous locations or are already selected
if (cellFrame) {
- int32_t origRow, origCol;
- cellFrame->GetRowIndex(origRow);
- cellFrame->GetColIndex(origCol);
+ uint32_t origRow = cellFrame->RowIndex();
+ uint32_t origCol = cellFrame->ColIndex();
if (origRow == row && origCol == col && !cellFrame->IsSelected()) {
result = SelectCellElement(cellFrame->GetContent());
if (NS_FAILED(result)) return result;
}
}
// Done when we reach end column
- if (col == aEndColumnIndex) break;
+ if (col == static_cast(aEndColumnIndex)) break;
if (aStartColumnIndex < aEndColumnIndex)
col ++;
else
col--;
}
- if (row == aEndRowIndex) break;
+ if (row == static_cast(aEndRowIndex)) break;
if (aStartRowIndex < aEndRowIndex)
row++;
diff --git a/layout/mathml/nsMathMLmtableFrame.cpp b/layout/mathml/nsMathMLmtableFrame.cpp
index fd184e637..4bd7d4395 100644
--- a/layout/mathml/nsMathMLmtableFrame.cpp
+++ b/layout/mathml/nsMathMLmtableFrame.cpp
@@ -183,10 +183,8 @@ static void
ApplyBorderToStyle(const nsMathMLmtdFrame* aFrame,
nsStyleBorder& aStyleBorder)
{
- int32_t rowIndex;
- int32_t columnIndex;
- aFrame->GetRowIndex(rowIndex);
- aFrame->GetColIndex(columnIndex);
+ uint32_t rowIndex = aFrame->RowIndex();
+ uint32_t columnIndex = aFrame->ColIndex();
nscoord borderWidth =
aFrame->PresContext()->GetBorderWidthTable()[NS_STYLE_BORDER_WIDTH_THIN];
@@ -201,7 +199,7 @@ ApplyBorderToStyle(const nsMathMLmtdFrame* aFrame,
if (rowIndex > 0 && rowLinesList) {
// If the row number is greater than the number of provided rowline
// values, we simply repeat the last value.
- int32_t listLength = rowLinesList->Length();
+ uint32_t listLength = rowLinesList->Length();
if (rowIndex < listLength) {
aStyleBorder.SetBorderStyle(NS_SIDE_TOP,
rowLinesList->ElementAt(rowIndex - 1));
@@ -216,7 +214,7 @@ ApplyBorderToStyle(const nsMathMLmtdFrame* aFrame,
if (columnIndex > 0 && columnLinesList) {
// If the column number is greater than the number of provided columline
// values, we simply repeat the last value.
- int32_t listLength = columnLinesList->Length();
+ uint32_t listLength = columnLinesList->Length();
if (columnIndex < listLength) {
aStyleBorder.SetBorderStyle(NS_SIDE_LEFT,
columnLinesList->ElementAt(columnIndex - 1));
@@ -1160,47 +1158,6 @@ nsMathMLmtdFrame::Init(nsIContent* aContent,
RemoveStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT);
}
-int32_t
-nsMathMLmtdFrame::GetRowSpan()
-{
- int32_t rowspan = 1;
-
- // Don't look at the content's rowspan if we're not an mtd or a pseudo cell.
- if (mContent->IsMathMLElement(nsGkAtoms::mtd_) &&
- !StyleContext()->GetPseudo()) {
- nsAutoString value;
- mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::rowspan, value);
- if (!value.IsEmpty()) {
- nsresult error;
- rowspan = value.ToInteger(&error);
- if (NS_FAILED(error) || rowspan < 0)
- rowspan = 1;
- rowspan = std::min(rowspan, MAX_ROWSPAN);
- }
- }
- return rowspan;
-}
-
-int32_t
-nsMathMLmtdFrame::GetColSpan()
-{
- int32_t colspan = 1;
-
- // Don't look at the content's colspan if we're not an mtd or a pseudo cell.
- if (mContent->IsMathMLElement(nsGkAtoms::mtd_) &&
- !StyleContext()->GetPseudo()) {
- nsAutoString value;
- mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::columnspan_, value);
- if (!value.IsEmpty()) {
- nsresult error;
- colspan = value.ToInteger(&error);
- if (NS_FAILED(error) || colspan <= 0 || colspan > MAX_COLSPAN)
- colspan = 1;
- }
- }
- return colspan;
-}
-
nsresult
nsMathMLmtdFrame::AttributeChanged(int32_t aNameSpaceID,
nsIAtom* aAttribute,
@@ -1243,12 +1200,11 @@ nsMathMLmtdFrame::GetVerticalAlign() const
nsTArray* alignmentList = FindCellProperty(this, RowAlignProperty());
if (alignmentList) {
- int32_t rowIndex;
- GetRowIndex(rowIndex);
+ uint32_t rowIndex = RowIndex();
// If the row number is greater than the number of provided rowalign values,
// we simply repeat the last value.
- if (rowIndex < (int32_t)alignmentList->Length())
+ if (rowIndex < alignmentList->Length())
alignment = alignmentList->ElementAt(rowIndex);
else
alignment = alignmentList->ElementAt(alignmentList->Length() - 1);
@@ -1335,12 +1291,11 @@ nsStyleText* nsMathMLmtdInnerFrame::StyleTextForLineLayout()
if (alignmentList) {
nsMathMLmtdFrame* cellFrame = (nsMathMLmtdFrame*)GetParent();
- int32_t columnIndex;
- cellFrame->GetColIndex(columnIndex);
+ uint32_t columnIndex = cellFrame->ColIndex();
// If the column number is greater than the number of provided columalign
// values, we simply repeat the last value.
- if (columnIndex < (int32_t)alignmentList->Length())
+ if (columnIndex < alignmentList->Length())
alignment = alignmentList->ElementAt(columnIndex);
else
alignment = alignmentList->ElementAt(alignmentList->Length() - 1);
diff --git a/layout/mathml/nsMathMLmtableFrame.h b/layout/mathml/nsMathMLmtableFrame.h
index 5cb4fc4a2..725991c17 100644
--- a/layout/mathml/nsMathMLmtableFrame.h
+++ b/layout/mathml/nsMathMLmtableFrame.h
@@ -257,8 +257,6 @@ public:
nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aLists) override;
- virtual int32_t GetRowSpan() override;
- virtual int32_t GetColSpan() override;
virtual bool IsFrameOfType(uint32_t aFlags) const override
{
return nsTableCellFrame::IsFrameOfType(aFlags & ~(nsIFrame::eMathML));
diff --git a/layout/tables/celldata.h b/layout/tables/celldata.h
index b744b5175..ac7be58d7 100644
--- a/layout/tables/celldata.h
+++ b/layout/tables/celldata.h
@@ -6,6 +6,7 @@
#define CellData_h__
#include "nsISupports.h"
+#include "nsITableCellLayout.h" // for MAX_COLSPAN / MAX_ROWSPAN
#include "nsCoord.h"
#include "mozilla/gfx/Types.h"
#include "mozilla/WritingModes.h"
@@ -15,11 +16,6 @@ class nsTableCellFrame;
class nsCellMap;
class BCCellData;
-
-#define MAX_ROWSPAN 65534 // the cellmap can not handle more.
-#define MAX_COLSPAN 1000 // limit as IE and opera do. If this ever changes,
- // change COL_SPAN_OFFSET/COL_SPAN_SHIFT accordingly.
-
/**
* Data stored by nsCellMap to rationalize rowspan and colspan cells.
*/
diff --git a/layout/tables/nsCellMap.cpp b/layout/tables/nsCellMap.cpp
index bdd12cf70..4852a4bdd 100644
--- a/layout/tables/nsCellMap.cpp
+++ b/layout/tables/nsCellMap.cpp
@@ -2431,9 +2431,8 @@ void nsCellMap::Dump(bool aIsBorderCollapse) const
if (cd) {
if (cd->IsOrig()) {
nsTableCellFrame* cellFrame = cd->GetCellFrame();
- int32_t cellFrameColIndex;
- cellFrame->GetColIndex(cellFrameColIndex);
- printf("C%d,%d=%p(%d) ", rIndex, colIndex, (void*)cellFrame,
+ uint32_t cellFrameColIndex = cellFrame->ColIndex();
+ printf("C%d,%d=%p(%u) ", rIndex, colIndex, (void*)cellFrame,
cellFrameColIndex);
cellCount++;
}
@@ -2520,8 +2519,7 @@ nsCellMap::GetCellInfoAt(const nsTableCellMap& aMap,
cellFrame = GetCellFrame(aRowX, aColX, *data, true);
}
if (cellFrame && aColSpan) {
- int32_t initialColIndex;
- cellFrame->GetColIndex(initialColIndex);
+ uint32_t initialColIndex = cellFrame->ColIndex();
*aColSpan = GetEffectiveColSpan(aMap, aRowX, initialColIndex);
}
}
diff --git a/layout/tables/nsITableCellLayout.h b/layout/tables/nsITableCellLayout.h
index e761d76be..fdf693b06 100644
--- a/layout/tables/nsITableCellLayout.h
+++ b/layout/tables/nsITableCellLayout.h
@@ -7,9 +7,14 @@
#include "nsQueryFrame.h"
+#define MAX_ROWSPAN 65534 // the cellmap can not handle more.
+#define MAX_COLSPAN 1000 // limit as IE and opera do. If this ever changes,
+// change COL_SPAN_OFFSET/COL_SPAN_SHIFT accordingly.
+
/**
* nsITableCellLayout
* interface for layout objects that act like table cells.
+ * XXX: This interface should really go away...
*
* @author sclark
*/
@@ -22,11 +27,6 @@ public:
/** return the mapped cell's row and column indexes (starting at 0 for each) */
NS_IMETHOD GetCellIndexes(int32_t &aRowIndex, int32_t &aColIndex)=0;
- /** return the mapped cell's row index (starting at 0 for the first row) */
- virtual nsresult GetRowIndex(int32_t &aRowIndex) const = 0;
-
- /** return the mapped cell's column index (starting at 0 for the first column) */
- virtual nsresult GetColIndex(int32_t &aColIndex) const = 0;
};
#endif
diff --git a/layout/tables/nsTableCellFrame.cpp b/layout/tables/nsTableCellFrame.cpp
index ec9458f76..8b811df1e 100644
--- a/layout/tables/nsTableCellFrame.cpp
+++ b/layout/tables/nsTableCellFrame.cpp
@@ -59,20 +59,6 @@ nsTableCellFrame::~nsTableCellFrame()
NS_IMPL_FRAMEARENA_HELPERS(nsTableCellFrame)
-nsTableCellFrame*
-nsTableCellFrame::GetNextCell() const
-{
- nsIFrame* childFrame = GetNextSibling();
- while (childFrame) {
- nsTableCellFrame *cellFrame = do_QueryFrame(childFrame);
- if (cellFrame) {
- return cellFrame;
- }
- childFrame = childFrame->GetNextSibling();
- }
- return nullptr;
-}
-
void
nsTableCellFrame::Init(nsIContent* aContent,
nsContainerFrame* aParent,
@@ -88,8 +74,7 @@ nsTableCellFrame::Init(nsIContent* aContent,
if (aPrevInFlow) {
// Set the column index
nsTableCellFrame* cellFrame = (nsTableCellFrame*)aPrevInFlow;
- int32_t colIndex;
- cellFrame->GetColIndex(colIndex);
+ uint32_t colIndex = cellFrame->ColIndex();
SetColIndex(colIndex);
}
}
@@ -182,34 +167,6 @@ nsTableCellFrame::NeedsToObserve(const ReflowInput& aReflowInput)
fType == nsGkAtoms::tableWrapperFrame);
}
-nsresult
-nsTableCellFrame::GetRowIndex(int32_t &aRowIndex) const
-{
- nsresult result;
- nsTableRowFrame* row = static_cast(GetParent());
- if (row) {
- aRowIndex = row->GetRowIndex();
- result = NS_OK;
- }
- else {
- aRowIndex = 0;
- result = NS_ERROR_NOT_INITIALIZED;
- }
- return result;
-}
-
-nsresult
-nsTableCellFrame::GetColIndex(int32_t &aColIndex) const
-{
- if (GetPrevInFlow()) {
- return static_cast(FirstInFlow())->GetColIndex(aColIndex);
- }
- else {
- aColIndex = mColIndex;
- return NS_OK;
- }
-}
-
nsresult
nsTableCellFrame::AttributeChanged(int32_t aNameSpaceID,
nsIAtom* aAttribute,
@@ -238,13 +195,13 @@ nsTableCellFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
nsTableFrame* tableFrame = GetTableFrame();
if (tableFrame->IsBorderCollapse() &&
tableFrame->BCRecalcNeeded(aOldStyleContext, StyleContext())) {
- int32_t colIndex, rowIndex;
- GetColIndex(colIndex);
- GetRowIndex(rowIndex);
+ uint32_t colIndex = ColIndex();
+ uint32_t rowIndex = RowIndex();
// row span needs to be clamped as we do not create rows in the cellmap
// which do not have cells originating in them
TableArea damageArea(colIndex, rowIndex, GetColSpan(),
- std::min(GetRowSpan(), tableFrame->GetRowCount() - rowIndex));
+ std::min(static_cast(GetRowSpan()),
+ tableFrame->GetRowCount() - rowIndex));
tableFrame->AddBCDamageArea(damageArea);
}
}
@@ -464,19 +421,40 @@ PaintTableCellSelection(nsIFrame* aFrame, DrawTarget* aDrawTarget,
aPt);
}
+bool
+nsTableCellFrame::ShouldPaintBordersAndBackgrounds() const
+{
+ // If we're not visible, we don't paint.
+ if (!StyleVisibility()->IsVisible()) {
+ return false;
+ }
+
+ // Consider 'empty-cells', but only in separated borders mode.
+ if (!GetContentEmpty()) {
+ return true;
+ }
+
+ nsTableFrame* tableFrame = GetTableFrame();
+ if (tableFrame->IsBorderCollapse()) {
+ return true;
+ }
+
+ return StyleTableBorder()->mEmptyCells == NS_STYLE_TABLE_EMPTY_CELLS_SHOW;
+}
+
+bool
+nsTableCellFrame::ShouldPaintBackground(nsDisplayListBuilder* aBuilder)
+{
+ return ShouldPaintBordersAndBackgrounds() && IsVisibleInSelection(aBuilder);
+}
+
void
nsTableCellFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists)
{
DO_GLOBAL_REFLOW_COUNT_DSP("nsTableCellFrame");
- nsTableFrame* tableFrame = GetTableFrame();
- int32_t emptyCellStyle = GetContentEmpty() && !tableFrame->IsBorderCollapse() ?
- StyleTableBorder()->mEmptyCells
- : NS_STYLE_TABLE_EMPTY_CELLS_SHOW;
- // take account of 'empty-cells'
- if (StyleVisibility()->IsVisible() &&
- (NS_STYLE_TABLE_EMPTY_CELLS_HIDE != emptyCellStyle)) {
+ if (ShouldPaintBordersAndBackgrounds()) {
// display outset box-shadows if we need to.
bool hasBoxShadow = !!StyleEffects()->mBoxShadow;
if (hasBoxShadow) {
@@ -501,7 +479,7 @@ nsTableCellFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
}
// display borders if we need to
- ProcessBorders(tableFrame, aBuilder, aLists);
+ ProcessBorders(GetTableFrame(), aBuilder, aLists);
// and display the selection border if we need to
if (IsSelected()) {
@@ -704,16 +682,18 @@ nsTableCellFrame::GetCellBaseline() const
borderPadding;
}
-int32_t nsTableCellFrame::GetRowSpan()
+int32_t
+nsTableCellFrame::GetRowSpan()
{
int32_t rowSpan=1;
- nsGenericHTMLElement *hc = nsGenericHTMLElement::FromContent(mContent);
// Don't look at the content's rowspan if we're a pseudo cell
- if (hc && !StyleContext()->GetPseudo()) {
- const nsAttrValue* attr = hc->GetParsedAttr(nsGkAtoms::rowspan);
+ if (!StyleContext()->GetPseudo()) {
+ dom::Element* elem = mContent->AsElement();
+ const nsAttrValue* attr = elem->GetParsedAttr(nsGkAtoms::rowspan);
// Note that we don't need to check the tag name, because only table cells
- // and table headers parse the "rowspan" attribute into an integer.
+ // (including MathML ) and table headers parse the "rowspan" attribute
+ // into an integer.
if (attr && attr->Type() == nsAttrValue::eInteger) {
rowSpan = attr->GetIntegerValue();
}
@@ -721,16 +701,20 @@ int32_t nsTableCellFrame::GetRowSpan()
return rowSpan;
}
-int32_t nsTableCellFrame::GetColSpan()
+int32_t
+nsTableCellFrame::GetColSpan()
{
int32_t colSpan=1;
- nsGenericHTMLElement *hc = nsGenericHTMLElement::FromContent(mContent);
// Don't look at the content's colspan if we're a pseudo cell
- if (hc && !StyleContext()->GetPseudo()) {
- const nsAttrValue* attr = hc->GetParsedAttr(nsGkAtoms::colspan);
+ if (!StyleContext()->GetPseudo()) {
+ dom::Element* elem = mContent->AsElement();
+ const nsAttrValue* attr = elem->GetParsedAttr(
+ MOZ_UNLIKELY(elem->IsMathMLElement()) ? nsGkAtoms::columnspan_
+ : nsGkAtoms::colspan);
// Note that we don't need to check the tag name, because only table cells
- // and table headers parse the "colspan" attribute into an integer.
+ // (including MathML ) and table headers parse the "colspan" attribute
+ // into an integer.
if (attr && attr->Type() == nsAttrValue::eInteger) {
colSpan = attr->GetIntegerValue();
}
@@ -807,14 +791,13 @@ CalcUnpaginatedBSize(nsTableCellFrame& aCellFrame,
nsTableRowGroupFrame* firstRGInFlow =
static_cast(row->GetParent());
- int32_t rowIndex;
- firstCellInFlow->GetRowIndex(rowIndex);
+ uint32_t rowIndex = firstCellInFlow->RowIndex();
int32_t rowSpan = aTableFrame.GetEffectiveRowSpan(*firstCellInFlow);
nscoord computedBSize = firstTableInFlow->GetRowSpacing(rowIndex,
rowIndex + rowSpan - 1);
computedBSize -= aBlockDirBorderPadding;
- int32_t rowX;
+ uint32_t rowX;
for (row = firstRGInFlow->GetFirstRow(), rowX = 0; row; row = row->GetNextRow(), rowX++) {
if (rowX > rowIndex + rowSpan - 1) {
break;
@@ -1029,12 +1012,7 @@ nsTableCellFrame::AccessibleType()
NS_IMETHODIMP
nsTableCellFrame::GetCellIndexes(int32_t &aRowIndex, int32_t &aColIndex)
{
- nsresult res = GetRowIndex(aRowIndex);
- if (NS_FAILED(res))
- {
- aColIndex = 0;
- return res;
- }
+ aRowIndex = RowIndex();
aColIndex = mColIndex;
return NS_OK;
}
diff --git a/layout/tables/nsTableCellFrame.h b/layout/tables/nsTableCellFrame.h
index 5f87c5f6d..f626a45b0 100644
--- a/layout/tables/nsTableCellFrame.h
+++ b/layout/tables/nsTableCellFrame.h
@@ -165,11 +165,11 @@ public:
/**
* return the cell's specified row span. this is what was specified in the
- * content model or in the style info, and is always >= 1.
+ * content model or in the style info, and is always >= 0.
* to get the effective row span (the actual value that applies), use GetEffectiveRowSpan()
* @see nsTableFrame::GetEffectiveRowSpan()
*/
- virtual int32_t GetRowSpan();
+ int32_t GetRowSpan();
// there is no set row index because row index depends on the cell's parent row only
@@ -183,7 +183,10 @@ public:
NS_IMETHOD GetCellIndexes(int32_t &aRowIndex, int32_t &aColIndex) override;
/** return the mapped cell's row index (starting at 0 for the first row) */
- virtual nsresult GetRowIndex(int32_t &aRowIndex) const override;
+ uint32_t RowIndex() const
+ {
+ return static_cast(GetParent())->GetRowIndex();
+ }
/**
* return the cell's specified col span. this is what was specified in the
@@ -191,10 +194,19 @@ public:
* to get the effective col span (the actual value that applies), use GetEffectiveColSpan()
* @see nsTableFrame::GetEffectiveColSpan()
*/
- virtual int32_t GetColSpan();
+ int32_t GetColSpan();
/** return the cell's column index (starting at 0 for the first column) */
- virtual nsresult GetColIndex(int32_t &aColIndex) const override;
+ uint32_t ColIndex() const
+ {
+ // NOTE: We copy this from previous continuations, and we don't ever have
+ // dynamic updates when tables split, so our mColIndex always matches our
+ // first continuation's.
+ MOZ_ASSERT(static_cast(FirstContinuation())->mColIndex ==
+ mColIndex,
+ "mColIndex out of sync with first continuation");
+ return mColIndex;
+ }
void SetColIndex(int32_t aColIndex);
/** return the available isize given to this frame during its last reflow */
@@ -209,13 +221,23 @@ public:
/** set the desired size returned by this frame during its last reflow */
inline void SetDesiredSize(const ReflowOutput & aDesiredSize);
- bool GetContentEmpty();
+ bool GetContentEmpty() const;
void SetContentEmpty(bool aContentEmpty);
bool HasPctOverBSize();
void SetHasPctOverBSize(bool aValue);
- nsTableCellFrame* GetNextCell() const;
+ nsTableCellFrame* GetNextCell() const
+ {
+ nsIFrame* sibling = GetNextSibling();
+#ifdef DEBUG
+ if (sibling) {
+ nsTableCellFrame* cellFrame = do_QueryFrame(sibling);
+ MOZ_ASSERT(cellFrame, "How do we have a non-cell sibling?");
+ }
+#endif // DEBUG
+ return static_cast(sibling);
+ }
virtual LogicalMargin GetBorderWidth(WritingMode aWM) const;
@@ -237,6 +259,10 @@ public:
virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0) override;
virtual void InvalidateFrameForRemoval() override { InvalidateFrameSubtree(); }
+ bool ShouldPaintBordersAndBackgrounds() const;
+
+ bool ShouldPaintBackground(nsDisplayListBuilder* aBuilder);
+
protected:
virtual LogicalSides
GetLogicalSkipSides(const ReflowInput* aReflowInput = nullptr) const override;
@@ -273,7 +299,7 @@ inline void nsTableCellFrame::SetDesiredSize(const ReflowOutput & aDesiredSize)
mDesiredSize = aDesiredSize.Size(wm).ConvertTo(GetWritingMode(), wm);
}
-inline bool nsTableCellFrame::GetContentEmpty()
+inline bool nsTableCellFrame::GetContentEmpty() const
{
return HasAnyStateBits(NS_TABLE_CELL_CONTENT_EMPTY);
}
@@ -350,4 +376,17 @@ private:
BCPixelSize mIStartBorder;
};
+// Implemented here because that's a sane-ish way to make the includes work out.
+inline nsTableCellFrame* nsTableRowFrame::GetFirstCell() const
+{
+ nsIFrame* firstChild = mFrames.FirstChild();
+#ifdef DEBUG
+ if (firstChild) {
+ nsTableCellFrame* cellFrame = do_QueryFrame(firstChild);
+ MOZ_ASSERT(cellFrame, "How do we have a non-cell sibling?");
+ }
+#endif // DEBUG
+ return static_cast(firstChild);
+}
+
#endif
diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp
index 890d050fd..4257c9c57 100644
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -368,9 +368,8 @@ nsTableFrame::AttributeChangedFor(nsIFrame* aFrame,
nsTableCellMap* cellMap = GetCellMap();
if (cellMap) {
// for now just remove the cell from the map and reinsert it
- int32_t rowIndex, colIndex;
- cellFrame->GetRowIndex(rowIndex);
- cellFrame->GetColIndex(colIndex);
+ uint32_t rowIndex = cellFrame->RowIndex();
+ uint32_t colIndex = cellFrame->ColIndex();
RemoveCell(cellFrame, rowIndex);
AutoTArray cells;
cells.AppendElement(cellFrame);
@@ -447,9 +446,7 @@ nsTableFrame::GetEffectiveRowSpan(int32_t aRowIndex,
nsTableCellMap* cellMap = GetCellMap();
NS_PRECONDITION (nullptr != cellMap, "bad call, cellMap not yet allocated.");
- int32_t colIndex;
- aCell.GetColIndex(colIndex);
- return cellMap->GetEffectiveRowSpan(aRowIndex, colIndex);
+ return cellMap->GetEffectiveRowSpan(aRowIndex, aCell.ColIndex());
}
int32_t
@@ -458,9 +455,8 @@ nsTableFrame::GetEffectiveRowSpan(const nsTableCellFrame& aCell,
{
nsTableCellMap* tableCellMap = GetCellMap(); if (!tableCellMap) ABORT1(1);
- int32_t colIndex, rowIndex;
- aCell.GetColIndex(colIndex);
- aCell.GetRowIndex(rowIndex);
+ uint32_t colIndex = aCell.ColIndex();
+ uint32_t rowIndex = aCell.RowIndex();
if (aCellMap)
return aCellMap->GetRowSpan(rowIndex, colIndex, true);
@@ -474,9 +470,8 @@ nsTableFrame::GetEffectiveColSpan(const nsTableCellFrame& aCell,
{
nsTableCellMap* tableCellMap = GetCellMap(); if (!tableCellMap) ABORT1(1);
- int32_t colIndex, rowIndex;
- aCell.GetColIndex(colIndex);
- aCell.GetRowIndex(rowIndex);
+ uint32_t colIndex = aCell.ColIndex();
+ uint32_t rowIndex = aCell.RowIndex();
if (aCellMap)
return aCellMap->GetEffectiveColSpan(*tableCellMap, rowIndex, colIndex);
@@ -1192,11 +1187,19 @@ PaintRowBackground(nsTableRowFrame* aRow,
nsIFrame* aFrame,
nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aLists,
+ const nsRect& aDirtyRect,
const nsPoint& aOffset = nsPoint())
{
// Compute background rect by iterating over all cell frames.
for (nsTableCellFrame* cell = aRow->GetFirstCell(); cell; cell = cell->GetNextCell()) {
+ if (!cell->ShouldPaintBackground(aBuilder)) {
+ continue;
+ }
+
auto cellRect = cell->GetRectRelativeToSelf() + cell->GetNormalPosition() + aOffset;
+ if (!aDirtyRect.Intersects(cellRect)) {
+ continue;
+ }
nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, aFrame, cellRect,
aLists.BorderBackground(),
true, nullptr,
@@ -1209,10 +1212,14 @@ static void
PaintRowGroupBackground(nsTableRowGroupFrame* aRowGroup,
nsIFrame* aFrame,
nsDisplayListBuilder* aBuilder,
- const nsDisplayListSet& aLists)
+ const nsDisplayListSet& aLists,
+ const nsRect& aDirtyRect)
{
for (nsTableRowFrame* row = aRowGroup->GetFirstRow(); row; row = row->GetNextRow()) {
- PaintRowBackground(row, aFrame, aBuilder, aLists, row->GetNormalPosition());
+ if (!aDirtyRect.Intersects(nsRect(row->GetNormalPosition(), row->GetSize()))) {
+ continue;
+ }
+ PaintRowBackground(row, aFrame, aBuilder, aLists, aDirtyRect, row->GetNormalPosition());
}
}
@@ -1221,21 +1228,42 @@ PaintRowGroupBackgroundByColIdx(nsTableRowGroupFrame* aRowGroup,
nsIFrame* aFrame,
nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aLists,
- const nsTArray& aColIdx,
+ const nsRect& aDirtyRect,
+ const nsTArray& aColIdx,
const nsPoint& aOffset)
{
+ MOZ_DIAGNOSTIC_ASSERT(!aColIdx.IsEmpty(),
+ "Must be painting backgrounds for something");
for (nsTableRowFrame* row = aRowGroup->GetFirstRow(); row; row = row->GetNextRow()) {
+ auto rowPos = row->GetNormalPosition() + aOffset;
+ if (!aDirtyRect.Intersects(nsRect(rowPos, row->GetSize()))) {
+ continue;
+ }
for (nsTableCellFrame* cell = row->GetFirstCell(); cell; cell = cell->GetNextCell()) {
- int32_t curColIdx;
- cell->GetColIndex(curColIdx);
- if (aColIdx.Contains(curColIdx)) {
- auto cellRect = cell->GetRectRelativeToSelf() + cell->GetNormalPosition() + row->GetNormalPosition() + aOffset;
+
+ uint32_t curColIdx = cell->ColIndex();
+ if (!aColIdx.Contains(curColIdx)) {
+ if (curColIdx > aColIdx.LastElement()) {
+ // We can just stop looking at this row.
+ break;
+ }
+ continue;
+ }
+
+ if (!cell->ShouldPaintBackground(aBuilder)) {
+ continue;
+ }
+
+ auto cellPos = cell->GetNormalPosition() + rowPos;
+ auto cellRect = nsRect(cellPos, cell->GetSize());
+ if (!aDirtyRect.Intersects(cellRect)) {
+ continue;
+ }
nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, aFrame, cellRect,
aLists.BorderBackground(),
true, nullptr,
aFrame->GetRectRelativeToSelf(),
cell);
- }
}
}
}
@@ -1247,66 +1275,94 @@ nsTableFrame::DisplayGenericTablePart(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aLists,
DisplayGenericTablePartTraversal aTraversal)
{
- if (aFrame->IsVisibleForPainting(aBuilder)) {
+ bool isVisible = aFrame->IsVisibleForPainting(aBuilder);
+ bool isTable = (aFrame->GetType() == nsGkAtoms::tableFrame);
+
+ if (isVisible || !isTable) {
nsDisplayTableItem* currentItem = aBuilder->GetCurrentTableItem();
// currentItem may be null, when none of the table parts have a
// background or border
if (currentItem) {
currentItem->UpdateForFrameBackground(aFrame);
}
+ }
+
+ if (isVisible) {
+ // XXX: should box-shadow for rows/rowgroups/columns/colgroups get painted
+ // just because we're visible? Or should it depend on the cell visibility
+ // when we're not the whole table?
// Paint the outset box-shadows for the table frames
- bool hasBoxShadow = aFrame->StyleEffects()->mBoxShadow != nullptr;
- if (hasBoxShadow) {
+ if (aFrame->StyleEffects()->mBoxShadow) {
aLists.BorderBackground()->AppendNewToTop(
new (aBuilder) nsDisplayBoxShadowOuter(aBuilder, aFrame));
}
+ }
- if (aFrame->GetType() == nsGkAtoms::tableRowGroupFrame) {
- nsTableRowGroupFrame* rowGroup = static_cast(aFrame);
- PaintRowGroupBackground(rowGroup, aFrame, aBuilder, aLists);
- } else if (aFrame->GetType() == nsGkAtoms::tableRowFrame) {
- nsTableRowFrame* row = static_cast(aFrame);
- PaintRowBackground(row, aFrame, aBuilder, aLists);
- } else if (aFrame->GetType() == nsGkAtoms::tableColGroupFrame) {
- // Compute background rect by iterating all cell frame.
- nsTableColGroupFrame* colGroup = static_cast(aFrame);
- // Collecting column index.
- AutoTArray colIdx;
- for (nsTableColFrame* col = colGroup->GetFirstColumn(); col; col = col->GetNextCol()) {
- colIdx.AppendElement(col->GetColIndex());
- }
+ // Background visibility for rows, rowgroups, columns, colgroups depends on
+ // the visibility of the _cell_, not of the row/col(group).
+ // See spec at https://drafts.csswg.org/css-tables-3/#drawing-cell-backgrounds
+ if (aFrame->GetType() == nsGkAtoms::tableRowGroupFrame) {
+ nsTableRowGroupFrame* rowGroup = static_cast(aFrame);
+ PaintRowGroupBackground(rowGroup, aFrame, aBuilder, aLists, aDirtyRect);
+ } else if (aFrame->GetType() == nsGkAtoms::tableRowFrame) {
+ nsTableRowFrame* row = static_cast(aFrame);
+ PaintRowBackground(row, aFrame, aBuilder, aLists, aDirtyRect);
+ } else if (aFrame->GetType() == nsGkAtoms::tableColGroupFrame) {
+ // Compute background rect by iterating all cell frame.
+ nsTableColGroupFrame* colGroup = static_cast(aFrame);
+ // Collecting column index.
+ AutoTArray colIdx;
+ for (nsTableColFrame* col = colGroup->GetFirstColumn(); col; col = col->GetNextCol()) {
+ MOZ_ASSERT(colIdx.IsEmpty() ||
+ static_cast(col->GetColIndex()) > colIdx.LastElement());
+ colIdx.AppendElement(col->GetColIndex());
+ }
+ if (!colIdx.IsEmpty()) {
+ // We have some actual cells that live inside this rowgroup.
nsTableFrame* table = colGroup->GetTableFrame();
RowGroupArray rowGroups;
table->OrderRowGroups(rowGroups);
for (nsTableRowGroupFrame* rowGroup : rowGroups) {
auto offset = rowGroup->GetNormalPosition() - colGroup->GetNormalPosition();
- PaintRowGroupBackgroundByColIdx(rowGroup, aFrame, aBuilder, aLists, colIdx, offset);
+ if (!aDirtyRect.Intersects(nsRect(offset, rowGroup->GetSize()))) {
+ continue;
+ }
+ PaintRowGroupBackgroundByColIdx(rowGroup, aFrame, aBuilder, aLists, aDirtyRect, colIdx, offset);
}
- } else if (aFrame->GetType() == nsGkAtoms::tableColFrame) {
- // Compute background rect by iterating all cell frame.
- nsTableColFrame* col = static_cast(aFrame);
- AutoTArray colIdx;
- colIdx.AppendElement(col->GetColIndex());
-
- nsTableFrame* table = col->GetTableFrame();
- RowGroupArray rowGroups;
- table->OrderRowGroups(rowGroups);
- for (nsTableRowGroupFrame* rowGroup : rowGroups) {
- auto offset = rowGroup->GetNormalPosition() -
- col->GetNormalPosition() -
- col->GetTableColGroupFrame()->GetNormalPosition();
- PaintRowGroupBackgroundByColIdx(rowGroup, aFrame, aBuilder, aLists, colIdx, offset);
- }
- } else {
- nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, aFrame,
- aFrame->GetRectRelativeToSelf(),
- aLists.BorderBackground());
}
+ } else if (aFrame->GetType() == nsGkAtoms::tableColFrame) {
+ // Compute background rect by iterating all cell frame.
+ nsTableColFrame* col = static_cast(aFrame);
+ AutoTArray colIdx;
+ colIdx.AppendElement(col->GetColIndex());
+
+ nsTableFrame* table = col->GetTableFrame();
+ RowGroupArray rowGroups;
+ table->OrderRowGroups(rowGroups);
+ for (nsTableRowGroupFrame* rowGroup : rowGroups) {
+ auto offset = rowGroup->GetNormalPosition() -
+ col->GetNormalPosition() -
+ col->GetTableColGroupFrame()->GetNormalPosition();
+ if (!aDirtyRect.Intersects(nsRect(offset, rowGroup->GetSize()))) {
+ continue;
+ }
+ PaintRowGroupBackgroundByColIdx(rowGroup, aFrame, aBuilder, aLists, aDirtyRect, colIdx, offset);
+ }
+ } else if (isVisible) {
+ nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, aFrame,
+ aFrame->GetRectRelativeToSelf(),
+ aLists.BorderBackground());
+ }
+
+ if (isVisible) {
+ // XXX: should box-shadow for rows/rowgroups/columns/colgroups get painted
+ // just because we're visible? Or should it depend on the cell visibility
+ // when we're not the whole table?
// Paint the inset box-shadows for the table frames
- if (hasBoxShadow) {
+ if (aFrame->StyleEffects()->mBoxShadow) {
aLists.BorderBackground()->AppendNewToTop(
new (aBuilder) nsDisplayBoxShadowInner(aBuilder, aFrame));
}
@@ -1314,8 +1370,8 @@ nsTableFrame::DisplayGenericTablePart(nsDisplayListBuilder* aBuilder,
aTraversal(aBuilder, aFrame, aDirtyRect, aLists);
- if (aFrame->IsVisibleForPainting(aBuilder)) {
- if (aFrame->GetType() == nsGkAtoms::tableFrame) {
+ if (isVisible) {
+ if (isTable) {
nsTableFrame* table = static_cast(aFrame);
// In the collapsed border model, overlay all collapsed borders.
if (table->IsBorderCollapse()) {
@@ -3911,9 +3967,8 @@ nsTableFrame::DumpRowGroup(nsIFrame* aKidFrame)
for (nsIFrame* childFrame : cFrame->PrincipalChildList()) {
nsTableCellFrame *cellFrame = do_QueryFrame(childFrame);
if (cellFrame) {
- int32_t colIndex;
- cellFrame->GetColIndex(colIndex);
- printf("cell(%d)=%p ", colIndex, static_cast(childFrame));
+ uint32_t colIndex = cellFrame->ColIndex();
+ printf("cell(%u)=%p ", colIndex, static_cast(childFrame));
}
}
printf("\n");
diff --git a/layout/tables/nsTableRowFrame.cpp b/layout/tables/nsTableRowFrame.cpp
index ea2477b73..02b85a141 100644
--- a/layout/tables/nsTableRowFrame.cpp
+++ b/layout/tables/nsTableRowFrame.cpp
@@ -235,7 +235,7 @@ nsTableRowFrame::InsertFrames(ChildListID aListID,
// insert the cells into the cell map
int32_t colIndex = -1;
if (prevCellFrame) {
- prevCellFrame->GetColIndex(colIndex);
+ colIndex = prevCellFrame->ColIndex();
}
tableFrame->InsertCells(cellChildren, GetRowIndex(), colIndex);
@@ -304,18 +304,6 @@ GetBSizeOfRowsSpannedBelowFirst(nsTableCellFrame& aTableCellFrame,
return bsize;
}
-nsTableCellFrame*
-nsTableRowFrame::GetFirstCell()
-{
- for (nsIFrame* childFrame : mFrames) {
- nsTableCellFrame *cellFrame = do_QueryFrame(childFrame);
- if (cellFrame) {
- return cellFrame;
- }
- }
- return nullptr;
-}
-
/**
* Post-reflow hook. This is where the table row does its post-processing
*/
@@ -659,8 +647,7 @@ CalcAvailISize(nsTableFrame& aTableFrame,
nsTableCellFrame& aCellFrame)
{
nscoord cellAvailISize = 0;
- int32_t colIndex;
- aCellFrame.GetColIndex(colIndex);
+ uint32_t colIndex = aCellFrame.ColIndex();
int32_t colspan = aTableFrame.GetEffectiveColSpan(aCellFrame);
NS_ASSERTION(colspan > 0, "effective colspan should be positive");
nsTableFrame* fifTable =
@@ -799,12 +786,12 @@ nsTableRowFrame::ReflowChildren(nsPresContext* aPresContext,
}
}
- int32_t cellColIndex;
- cellFrame->GetColIndex(cellColIndex);
+ uint32_t cellColIndex = cellFrame->ColIndex();
cellColSpan = aTableFrame.GetEffectiveColSpan(*cellFrame);
// If the adjacent cell is in a prior row (because of a rowspan) add in the space
- if (prevColIndex != (cellColIndex - 1)) {
+ // NOTE: prevColIndex can be -1 here.
+ if (prevColIndex != (static_cast(cellColIndex) - 1)) {
iCoord += GetSpaceBetween(prevColIndex, cellColIndex, cellColSpan, aTableFrame,
false);
}
@@ -1172,8 +1159,7 @@ nsTableRowFrame::CollapseRowIfNecessary(nscoord aRowOffset,
shift = rowRect.BSize(wm);
nsTableCellFrame* cellFrame = GetFirstCell();
if (cellFrame) {
- int32_t rowIndex;
- cellFrame->GetRowIndex(rowIndex);
+ uint32_t rowIndex = cellFrame->RowIndex();
shift += tableFrame->GetRowSpacing(rowIndex);
while (cellFrame) {
LogicalRect cRect = cellFrame->GetLogicalRect(wm, containerSize);
@@ -1204,13 +1190,13 @@ nsTableRowFrame::CollapseRowIfNecessary(nscoord aRowOffset,
for (nsIFrame* kidFrame : mFrames) {
nsTableCellFrame *cellFrame = do_QueryFrame(kidFrame);
if (cellFrame) {
- int32_t cellColIndex;
- cellFrame->GetColIndex(cellColIndex);
+ uint32_t cellColIndex = cellFrame->ColIndex();
int32_t cellColSpan = tableFrame->GetEffectiveColSpan(*cellFrame);
// If the adjacent cell is in a prior row (because of a rowspan) add in
// the space
- if (prevColIndex != (cellColIndex - 1)) {
+ // NOTE: prevColIndex can be -1 here.
+ if (prevColIndex != (static_cast(cellColIndex) - 1)) {
iPos += GetSpaceBetween(prevColIndex, cellColIndex, cellColSpan,
*tableFrame, true);
}
@@ -1323,9 +1309,9 @@ nsTableRowFrame::InsertCellFrame(nsTableCellFrame* aFrame,
for (nsIFrame* child : mFrames) {
nsTableCellFrame *cellFrame = do_QueryFrame(child);
if (cellFrame) {
- int32_t colIndex;
- cellFrame->GetColIndex(colIndex);
- if (colIndex < aColIndex) {
+ uint32_t colIndex = cellFrame->ColIndex();
+ // Can aColIndex be -1 here? Let's assume it can for now.
+ if (static_cast(colIndex) < aColIndex) {
priorCell = cellFrame;
}
else break;
diff --git a/layout/tables/nsTableRowFrame.h b/layout/tables/nsTableRowFrame.h
index 9e15d851f..c53c81ff1 100644
--- a/layout/tables/nsTableRowFrame.h
+++ b/layout/tables/nsTableRowFrame.h
@@ -82,7 +82,9 @@ public:
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists) override;
- nsTableCellFrame* GetFirstCell() ;
+ // Implemented in nsTableCellFrame.h, because it needs to know about the
+ // nsTableCellFrame class, but we can't include nsTableCellFrame.h here.
+ inline nsTableCellFrame* GetFirstCell() const;
/** calls Reflow for all of its child cells.
* Cells with rowspan=1 are all set to the same height and stacked horizontally.
diff --git a/layout/tables/nsTableRowGroupFrame.cpp b/layout/tables/nsTableRowGroupFrame.cpp
index f613c8b79..37f577f5c 100644
--- a/layout/tables/nsTableRowGroupFrame.cpp
+++ b/layout/tables/nsTableRowGroupFrame.cpp
@@ -137,8 +137,7 @@ nsTableRowGroupFrame::InitRepeatedFrame(nsTableRowGroupFrame* aHeaderFooterFrame
while (copyCellFrame && originalCellFrame) {
NS_ASSERTION(originalCellFrame->GetContent() == copyCellFrame->GetContent(),
"cell frames have different content");
- int32_t colIndex;
- originalCellFrame->GetColIndex(colIndex);
+ uint32_t colIndex = originalCellFrame->ColIndex();
copyCellFrame->SetColIndex(colIndex);
// Move to the next cell frame
@@ -998,8 +997,7 @@ nsTableRowGroupFrame::SplitSpanningCells(nsPresContext& aPresContext,
nsTableCellFrame* contCell = static_cast(
aPresContext.PresShell()->FrameConstructor()->
CreateContinuingFrame(&aPresContext, cell, &aLastRow));
- int32_t colIndex;
- cell->GetColIndex(colIndex);
+ uint32_t colIndex = cell->ColIndex();
aContRow->InsertCellFrame(contCell, colIndex);
}
}