From de61177a249b7250fd980afafd46c6928966b142 Mon Sep 17 00:00:00 2001 From: "rbs%maths.uq.edu.au" Date: Thu, 7 Sep 2006 03:45:45 +0000 Subject: [PATCH] Consolidation of some mtable/matrix related attributes that affect the style, and make them responsive to dynamic changes via JavaScript, b=179619, r+sr=roc --- content/base/src/nsGkAtomList.h | 6 +- .../base/src/nsMathMLContainerFrame.cpp | 16 +- .../mathml/base/src/nsMathMLContainerFrame.h | 4 +- layout/mathml/base/src/nsMathMLFrame.cpp | 61 ++- layout/mathml/base/src/nsMathMLFrame.h | 16 +- layout/mathml/base/src/nsMathMLParts.h | 11 +- .../mathml/base/src/nsMathMLmstyleFrame.cpp | 13 +- .../mathml/base/src/nsMathMLmtableFrame.cpp | 451 +++++++++++------- layout/mathml/base/src/nsMathMLmtableFrame.h | 137 +++++- layout/mathml/content/src/mathml.css | 50 +- 10 files changed, 514 insertions(+), 251 deletions(-) diff --git a/content/base/src/nsGkAtomList.h b/content/base/src/nsGkAtomList.h index 0ecea36e46c8..a96ce3440ed8 100755 --- a/content/base/src/nsGkAtomList.h +++ b/content/base/src/nsGkAtomList.h @@ -1066,13 +1066,11 @@ GK_ATOM(zoomAndPan, "zoomAndPan") #endif #ifdef MOZ_MATHML +GK_ATOM(MOZcolumnalign, "-moz-math-columnalign") GK_ATOM(MOZcolumnline, "-moz-math-columnline") // different from columnlines_ -GK_ATOM(MOZfirstcolumn, "-moz-math-firstcolumn") -GK_ATOM(MOZfirstrow, "-moz-math-firstrow") GK_ATOM(MOZfontsize, "-moz-math-font-size") // different from fontsize_ GK_ATOM(MOZfontstyle, "-moz-math-font-style") // different from fontstyle_ -GK_ATOM(MOZlastcolumn, "-moz-math-lastcolumn") -GK_ATOM(MOZlastrow, "-moz-math-lastrow") +GK_ATOM(MOZrowalign, "-moz-math-rowalign") GK_ATOM(MOZrowline, "-moz-math-rowline") // different from rowlines_ GK_ATOM(abs_, "abs") GK_ATOM(accent_, "accent") diff --git a/layout/mathml/base/src/nsMathMLContainerFrame.cpp b/layout/mathml/base/src/nsMathMLContainerFrame.cpp index a505b2b90859..5f8675367276 100644 --- a/layout/mathml/base/src/nsMathMLContainerFrame.cpp +++ b/layout/mathml/base/src/nsMathMLContainerFrame.cpp @@ -758,7 +758,7 @@ nsMathMLContainerFrame::Init(nsIContent* aContent, nsIFrame* aParent, nsIFrame* aPrevInFlow) { - MapAttributesIntoCSS(GetPresContext(), aContent); + MapCommonAttributesIntoCSS(GetPresContext(), aContent); // let the base class do its Init() return nsHTMLContainerFrame::Init(aContent, aParent, aPrevInFlow); @@ -931,16 +931,12 @@ nsMathMLContainerFrame::AttributeChanged(PRInt32 aNameSpaceID, nsIAtom* aAttribute, PRInt32 aModType) { - if (aAttribute == nsMathMLAtoms::mathcolor_ || - aAttribute == nsMathMLAtoms::color || - aAttribute == nsMathMLAtoms::mathsize_ || - aAttribute == nsMathMLAtoms::fontsize_ || - aAttribute == nsMathMLAtoms::fontfamily_ || - aAttribute == nsMathMLAtoms::mathbackground_ || - aAttribute == nsMathMLAtoms::background) { - MapAttributesIntoCSS(GetPresContext(), this); - } + // Attributes common to MathML tags + if (CommonAttributeChangedFor(GetPresContext(), mContent, aAttribute)) + return NS_OK; + // XXX Since they are numerous MathML attributes that affect layout, and + // we can't check all of them here, play safe by requesting a reflow. return ReflowDirtyChild(GetPresContext()->PresShell(), nsnull); } diff --git a/layout/mathml/base/src/nsMathMLContainerFrame.h b/layout/mathml/base/src/nsMathMLContainerFrame.h index 468a35f174ab..8033a696dd07 100644 --- a/layout/mathml/base/src/nsMathMLContainerFrame.h +++ b/layout/mathml/base/src/nsMathMLContainerFrame.h @@ -329,7 +329,7 @@ public: { nsresult rv = nsBlockFrame::SetInitialChildList(aListName, aChildList); // re-resolve our subtree to set any mathml-expected data - nsMathMLContainerFrame::MapAttributesIntoCSS(GetPresContext(), this); + nsMathMLContainerFrame::MapCommonAttributesIntoCSS(GetPresContext(), this); nsMathMLContainerFrame::RebuildAutomaticDataForChildren(this); return rv; } @@ -404,7 +404,7 @@ public: { nsresult rv = nsInlineFrame::SetInitialChildList(aListName, aChildList); // re-resolve our subtree to set any mathml-expected data - nsMathMLContainerFrame::MapAttributesIntoCSS(GetPresContext(), this); + nsMathMLContainerFrame::MapCommonAttributesIntoCSS(GetPresContext(), this); nsMathMLContainerFrame::RebuildAutomaticDataForChildren(this); return rv; } diff --git a/layout/mathml/base/src/nsMathMLFrame.cpp b/layout/mathml/base/src/nsMathMLFrame.cpp index 80dc338f6f0a..a77e51fd3c5d 100644 --- a/layout/mathml/base/src/nsMathMLFrame.cpp +++ b/layout/mathml/base/src/nsMathMLFrame.cpp @@ -590,8 +590,8 @@ GetMathMLAttributeStyleSheet(nsPresContext* aPresContext, } /* static */ PRInt32 -nsMathMLFrame::MapAttributesIntoCSS(nsPresContext* aPresContext, - nsIContent* aContent) +nsMathMLFrame::MapCommonAttributesIntoCSS(nsPresContext* aPresContext, + nsIContent* aContent) { // normal case, quick return if there are no attributes NS_ASSERTION(aContent, "null arg"); @@ -660,10 +660,12 @@ nsMathMLFrame::MapAttributesIntoCSS(nsPresContext* aPresContext, attrAtom->ToString(attrName); // make a style rule that maps to the equivalent CSS property - nsAutoString cssRule; - cssRule.Assign(NS_LITERAL_STRING("[") + attrName + - NS_LITERAL_STRING("='") + escapedAttrValue + - NS_LITERAL_STRING("']{") + cssProperty + NS_LITERAL_STRING("}")); + nsAutoString selector, cssRule; + selector.Assign(NS_LITERAL_STRING("[") + attrName + + NS_LITERAL_STRING("=\"") + escapedAttrValue + + NS_LITERAL_STRING("\"]")); + cssRule.Assign(selector + + NS_LITERAL_STRING("{") + cssProperty + NS_LITERAL_STRING("}")); if (!sheet) { // first time... we do this to defer the lookup up to the @@ -685,11 +687,8 @@ nsMathMLFrame::MapAttributesIntoCSS(nsPresContext* aPresContext, sheet->SetOwningDocument(nsnull); } - // check for duplicate, if a similar rule is already there, don't bother to add another one - nsAutoString selector; - selector.Assign(NS_LITERAL_STRING("*[") + attrName + - NS_LITERAL_STRING("=\"") + escapedAttrValue + - NS_LITERAL_STRING("\"]")); + // check for duplicate, if a similar rule is already there, + // don't bother to add another one PRInt32 k, count; cssSheet->StyleRuleCount(count); for (k = 0; k < count; ++k) { @@ -699,6 +698,15 @@ nsMathMLFrame::MapAttributesIntoCSS(nsPresContext* aPresContext, nsCOMPtr tmpStyleRule = do_QueryInterface(tmpRule); if (tmpStyleRule) { tmpStyleRule->GetSelectorText(tmpSelector); + NS_ASSERTION(tmpSelector.CharAt(0) != '*', "unexpected universal symbol"); +#ifdef DEBUG_rbs + nsCAutoString str; + LossyAppendUTF16toASCII(selector, str); + str.AppendLiteral(" vs "); + LossyAppendUTF16toASCII(tmpSelector, str); + printf("Attr selector %s %s\n", str.get(), + tmpSelector.Equals(selector)? " ... match" : " ... nomatch"); +#endif if (tmpSelector.Equals(selector)) { k = -1; break; @@ -724,10 +732,10 @@ nsMathMLFrame::MapAttributesIntoCSS(nsPresContext* aPresContext, } /* static */ PRInt32 -nsMathMLFrame::MapAttributesIntoCSS(nsPresContext* aPresContext, - nsIFrame* aFrame) +nsMathMLFrame::MapCommonAttributesIntoCSS(nsPresContext* aPresContext, + nsIFrame* aFrame) { - PRInt32 ruleCount = MapAttributesIntoCSS(aPresContext, aFrame->GetContent()); + PRInt32 ruleCount = MapCommonAttributesIntoCSS(aPresContext, aFrame->GetContent()); if (!ruleCount) return 0; @@ -744,6 +752,31 @@ nsMathMLFrame::MapAttributesIntoCSS(nsPresContext* aPresContext, return ruleCount; } +/* static */ PRBool +nsMathMLFrame::CommonAttributeChangedFor(nsPresContext* aPresContext, + nsIContent* aContent, + nsIAtom* aAttribute) +{ + if (aAttribute == nsMathMLAtoms::mathcolor_ || + aAttribute == nsMathMLAtoms::color || + aAttribute == nsMathMLAtoms::mathsize_ || + aAttribute == nsMathMLAtoms::fontsize_ || + aAttribute == nsMathMLAtoms::fontfamily_ || + aAttribute == nsMathMLAtoms::mathbackground_ || + aAttribute == nsMathMLAtoms::background) { + + MapCommonAttributesIntoCSS(aPresContext, aContent); + + // That's all folks. Common attributes go in the internal MathML attribute + // stylesheet. So when nsCSSFrameConstructor checks if the content + // HasAttributeDependentStyle(), it will detect them and issue a + // PostRestyleEvent() to re-resolve the style data and reflow if needed. + return PR_TRUE; + } + + return PR_FALSE; +} + #if defined(NS_DEBUG) && defined(SHOW_BOUNDING_BOX) class nsDisplayMathMLBoundingMetrics : public nsDisplayItem { public: diff --git a/layout/mathml/base/src/nsMathMLFrame.h b/layout/mathml/base/src/nsMathMLFrame.h index 7230b3364024..f598a263383a 100644 --- a/layout/mathml/base/src/nsMathMLFrame.h +++ b/layout/mathml/base/src/nsMathMLFrame.h @@ -431,11 +431,19 @@ public: // helpers to map attributes into CSS rules (work-around to bug 69409 which // is not scheduled to be fixed anytime soon) static PRInt32 - MapAttributesIntoCSS(nsPresContext* aPresContext, - nsIContent* aContent); + MapCommonAttributesIntoCSS(nsPresContext* aPresContext, + nsIContent* aContent); static PRInt32 - MapAttributesIntoCSS(nsPresContext* aPresContext, - nsIFrame* aFrame); + MapCommonAttributesIntoCSS(nsPresContext* aPresContext, + nsIFrame* aFrame); + + // helper used by all AttributeChanged() methods. It handles + // those attributes that are common to all tags. + // @return true if the attribue is handled. + static PRBool + CommonAttributeChangedFor(nsPresContext* aPresContext, + nsIContent* aContent, + nsIAtom* aAttribute); protected: #if defined(NS_DEBUG) && defined(SHOW_BOUNDING_BOX) diff --git a/layout/mathml/base/src/nsMathMLParts.h b/layout/mathml/base/src/nsMathMLParts.h index 1499d2387ec8..aef02c0d3eaf 100644 --- a/layout/mathml/base/src/nsMathMLParts.h +++ b/layout/mathml/base/src/nsMathMLParts.h @@ -60,16 +60,9 @@ nsIFrame* NS_NewMathMLmoverFrame(nsIPresShell* aPresShell, nsStyleContext* aCont nsIFrame* NS_NewMathMLmunderoverFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); nsIFrame* NS_NewMathMLmmultiscriptsFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); nsIFrame* NS_NewMathMLmstyleFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); - nsIFrame* NS_NewMathMLmtableOuterFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); -inline nsIFrame* NS_NewMathMLmtableFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) -{ - return NS_NewTableFrame(aPresShell, aContext); -} -inline nsIFrame* NS_NewMathMLmtrFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) -{ - return NS_NewTableRowFrame(aPresShell, aContext); -} +nsIFrame* NS_NewMathMLmtableFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); +nsIFrame* NS_NewMathMLmtrFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); nsIFrame* NS_NewMathMLmtdFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); nsIFrame* NS_NewMathMLmtdInnerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); nsIFrame* NS_NewMathMLmsqrtFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); diff --git a/layout/mathml/base/src/nsMathMLmstyleFrame.cpp b/layout/mathml/base/src/nsMathMLmstyleFrame.cpp index 299079f8bf3c..68369a97e2ad 100644 --- a/layout/mathml/base/src/nsMathMLmstyleFrame.cpp +++ b/layout/mathml/base/src/nsMathMLmstyleFrame.cpp @@ -197,16 +197,9 @@ nsMathMLmstyleFrame::AttributeChanged(PRInt32 aNameSpaceID, nsIAtom* aAttribute, PRInt32 aModType) { - if (aAttribute == nsMathMLAtoms::mathcolor_ || - aAttribute == nsMathMLAtoms::color || - aAttribute == nsMathMLAtoms::mathsize_ || - aAttribute == nsMathMLAtoms::fontsize_ || - aAttribute == nsMathMLAtoms::fontfamily_ || - aAttribute == nsMathMLAtoms::mathbackground_ || - aAttribute == nsMathMLAtoms::background) { - MapAttributesIntoCSS(GetPresContext(), this); - return ReflowDirtyChild(GetPresContext()->PresShell(), nsnull); - } + // Attributes common to MathML tags + if (CommonAttributeChangedFor(GetPresContext(), mContent, aAttribute)) + return NS_OK; // Other attributes can affect too many things, ask our parent to re-layout // its children so that we can pick up changes in our attributes & transmit diff --git a/layout/mathml/base/src/nsMathMLmtableFrame.cpp b/layout/mathml/base/src/nsMathMLmtableFrame.cpp index b8fcbed9960f..f998eca6e48c 100644 --- a/layout/mathml/base/src/nsMathMLmtableFrame.cpp +++ b/layout/mathml/base/src/nsMathMLmtableFrame.cpp @@ -48,8 +48,7 @@ #include "nsIFontMetrics.h" #include "nsVoidArray.h" -#include "nsFrameManager.h" -#include "nsStyleChangeList.h" +#include "nsCSSFrameConstructor.h" #include "nsTableOuterFrame.h" #include "nsTableFrame.h" #include "nsTableCellFrame.h" @@ -107,198 +106,162 @@ struct nsValueList // Each rowalign='top bottom' or columnalign='left right center' (from // or ) is split once (lazily) into a nsValueList which is -// stored in the frame manager. Cell frames query the frame manager +// stored in the property table. Row/Cell frames query the property table // to see what values apply to them. // XXX See bug 69409 - MathML attributes are not mapped to style. -// This code is not suitable for dynamic updates, for example when the -// rowalign and columalign attributes are changed with JavaScript. -// The code doesn't include hooks for AttributeChanged() notifications. static void -DestroyValueListFunc(void* aFrame, - nsIAtom* aPropertyName, - void* aPropertyValue, - void* aDtorData) +DestroyValueListFunc(void* aFrame, + nsIAtom* aPropertyName, + void* aPropertyValue, + void* aDtorData) { delete NS_STATIC_CAST(nsValueList*, aPropertyValue); } static PRUnichar* -GetValueAt(nsPresContext* aPresContext, - nsIFrame* aTableOrRowFrame, - nsIAtom* aAttributeAtom, - PRInt32 aRowOrColIndex) +GetValueAt(nsIFrame* aTableOrRowFrame, + nsIAtom* aAttribute, + PRInt32 aRowOrColIndex) { - PRUnichar* result = nsnull; - nsPropertyTable *propTable = aPresContext->PropertyTable(); - nsValueList* valueList; - - valueList = NS_STATIC_CAST(nsValueList*, - propTable->GetProperty(aTableOrRowFrame, - aAttributeAtom)); - + nsValueList* valueList = NS_STATIC_CAST(nsValueList*, + aTableOrRowFrame->GetProperty(aAttribute)); if (!valueList) { // The property isn't there yet, so set it nsAutoString values; - aTableOrRowFrame->GetContent()->GetAttr(kNameSpaceID_None, aAttributeAtom, values); - if (!values.IsEmpty()) { + aTableOrRowFrame->GetContent()->GetAttr(kNameSpaceID_None, aAttribute, values); + if (!values.IsEmpty()) valueList = new nsValueList(values); - if (valueList) { - propTable->SetProperty(aTableOrRowFrame, aAttributeAtom, - valueList, DestroyValueListFunc, nsnull); - } + if (!valueList || !valueList->mArray.Count()) { + delete valueList; // ok either way, delete is null safe + return nsnull; } + aTableOrRowFrame->SetProperty(aAttribute, valueList, DestroyValueListFunc); } - - if (valueList) { - PRInt32 count = valueList->mArray.Count(); - result = (aRowOrColIndex < count) - ? (PRUnichar*)(valueList->mArray[aRowOrColIndex]) - : (PRUnichar*)(valueList->mArray[count-1]); - } - return result; + PRInt32 count = valueList->mArray.Count(); + return (aRowOrColIndex < count) + ? (PRUnichar*)(valueList->mArray[aRowOrColIndex]) + : (PRUnichar*)(valueList->mArray[count-1]); } #ifdef NS_DEBUG #define DEBUG_VERIFY_THAT_FRAME_IS(_frame, _expected) \ - NS_ASSERTION(NS_STYLE_DISPLAY_##_expected == _frame->GetStyleDisplay()->mDisplay, "internal error"); + NS_ASSERTION(nsGkAtoms::##_expected##Frame == _frame->GetType(), "internal error"); #else #define DEBUG_VERIFY_THAT_FRAME_IS(_frame, _expected) #endif +// map attributes that depend on the index of the row: +// rowalign, rowlines, XXX need rowspacing too static void -MapAttributesInto(nsPresContext* aPresContext, - nsIContent* aCellContent, - nsIFrame* aCellFrame, - nsIFrame* aCellInnerFrame) +MapRowAttributesIntoCSS(nsIFrame* aTableFrame, + nsIFrame* aRowFrame) { - nsTableCellFrame* cellFrame = NS_STATIC_CAST(nsTableCellFrame*, aCellFrame); - nsTableCellFrame* sibling; - - PRInt32 rowIndex, colIndex; - nsresult rv = cellFrame->GetCellIndexes(rowIndex, colIndex); - NS_ASSERTION(NS_SUCCEEDED(rv), "cannot find the position of the cell frame"); - if (NS_FAILED(rv)) return; - - nsIFrame* rowFrame = cellFrame->GetParent(); - nsIFrame* rowgroupFrame = rowFrame->GetParent(); - nsIFrame* tableFrame = rowgroupFrame->GetParent(); - DEBUG_VERIFY_THAT_FRAME_IS(rowFrame, TABLE_ROW); - DEBUG_VERIFY_THAT_FRAME_IS(rowgroupFrame, TABLE_ROW_GROUP); - DEBUG_VERIFY_THAT_FRAME_IS(tableFrame, TABLE); -#ifdef NS_DEBUG - PRBool originates; - ((nsTableFrame*)tableFrame)->GetCellInfoAt(rowIndex, colIndex, &originates); - NS_ASSERTION(originates, "internal error"); -#endif - - nsIAtom* atom; + DEBUG_VERIFY_THAT_FRAME_IS(aTableFrame, table); + DEBUG_VERIFY_THAT_FRAME_IS(aRowFrame, tableRow); + PRInt32 rowIndex = ((nsTableRowFrame*)aRowFrame)->GetRowIndex(); + nsIContent* rowContent = aRowFrame->GetContent(); PRUnichar* attr; - PRBool hasChanged = PR_FALSE; - NS_NAMED_LITERAL_STRING(trueStr, "true"); - - ////////////////////////////////////// - // process attributes that depend on the index of the row: - // rowalign, rowlines // see if the rowalign attribute is not already set - atom = nsMathMLAtoms::rowalign_; - if (!aCellContent->HasAttr(kNameSpaceID_None, atom)) { - // see if the rowalign attribute was specified on the row - attr = GetValueAt(aPresContext, rowFrame, atom, rowIndex); - if (!attr) { - // see if the rowalign attribute was specified on the table - attr = GetValueAt(aPresContext, tableFrame, atom, rowIndex); - } - // set the attribute without notifying that we want a reflow + if (!rowContent->HasAttr(kNameSpaceID_None, nsMathMLAtoms::rowalign_) && + !rowContent->HasAttr(kNameSpaceID_None, nsMathMLAtoms::MOZrowalign)) { + // see if the rowalign attribute was specified on the table + attr = GetValueAt(aTableFrame, nsMathMLAtoms::rowalign_, rowIndex); if (attr) { - hasChanged = PR_TRUE; - aCellContent->SetAttr(kNameSpaceID_None, atom, nsDependentString(attr), PR_FALSE); + // set our special -moz attribute on the row without notifying a reflow + rowContent->SetAttr(kNameSpaceID_None, nsMathMLAtoms::MOZrowalign, + nsDependentString(attr), PR_FALSE); } } + // if we are not on the first row, see if |rowlines| was specified on the table. // Note that we pass 'rowIndex-1' because the CSS rule in mathml.css is associated // to 'border-top', and it is as if we draw the line on behalf of the previous cell. // This way of doing so allows us to handle selective lines, [row]\hline[row][row]', // and cases of spanning cells without further complications. - if (rowIndex > 0) { - attr = GetValueAt(aPresContext, tableFrame, nsMathMLAtoms::rowlines_, rowIndex-1); - // set the special -moz-math-rowline without notifying that we want a reflow + if (rowIndex > 0 && + !rowContent->HasAttr(kNameSpaceID_None, nsMathMLAtoms::MOZrowline)) { + attr = GetValueAt(aTableFrame, nsMathMLAtoms::rowlines_, rowIndex-1); if (attr) { - hasChanged = PR_TRUE; - aCellContent->SetAttr(kNameSpaceID_None, nsMathMLAtoms::MOZrowline, nsDependentString(attr), PR_FALSE); + // set our special -moz attribute on the row without notifying a reflow + rowContent->SetAttr(kNameSpaceID_None, nsMathMLAtoms::MOZrowline, + nsDependentString(attr), PR_FALSE); } } - else { - // set the special -moz-math-firstrow to annotate that we are on the first row - hasChanged = PR_TRUE; - aCellContent->SetAttr(kNameSpaceID_None, nsMathMLAtoms::MOZfirstrow, trueStr, PR_FALSE); - } - // if we are on the last row, set the special -moz-math-lastrow - PRInt32 rowSpan = ((nsTableFrame*)tableFrame)->GetEffectiveRowSpan(*cellFrame); - sibling = ((nsTableFrame*)tableFrame)->GetCellFrameAt(rowIndex+rowSpan, colIndex); - if (!sibling) { - hasChanged = PR_TRUE; - aCellContent->SetAttr(kNameSpaceID_None, nsMathMLAtoms::MOZlastrow, trueStr, PR_FALSE); - } +} - ////////////////////////////////////// - // process attributes that depend on the index of the column: - // columnalign, columnlines, XXX need columnwidth too +// map attributes that depend on the index of the column: +// columnalign, columnlines, XXX need columnwidth and columnspacing too +static void +MapColAttributesIntoCSS(nsIFrame* aTableFrame, + nsIFrame* aRowFrame, + nsIFrame* aCellFrame) +{ + DEBUG_VERIFY_THAT_FRAME_IS(aTableFrame, table); + DEBUG_VERIFY_THAT_FRAME_IS(aRowFrame, tableRow); + NS_ASSERTION(IS_TABLE_CELL(aCellFrame->GetType()),"internal error"); + PRInt32 rowIndex, colIndex; + ((nsTableCellFrame*)aCellFrame)->GetCellIndexes(rowIndex, colIndex); + nsIContent* cellContent = aCellFrame->GetContent(); + PRUnichar* attr; // see if the columnalign attribute is not already set - atom = nsMathMLAtoms::columnalign_; - if (!aCellContent->HasAttr(kNameSpaceID_None, atom)) { + if (!cellContent->HasAttr(kNameSpaceID_None, nsMathMLAtoms::columnalign_) && + !cellContent->HasAttr(kNameSpaceID_None, nsMathMLAtoms::MOZcolumnalign)) { // see if the columnalign attribute was specified on the row - attr = GetValueAt(aPresContext, rowFrame, atom, colIndex); + attr = GetValueAt(aRowFrame, nsMathMLAtoms::columnalign_, colIndex); if (!attr) { - // see if the columnalign attribute was specified on the table - attr = GetValueAt(aPresContext, tableFrame, atom, colIndex); + // see if the columnalign attribute was specified on the table + attr = GetValueAt(aTableFrame, nsMathMLAtoms::columnalign_, colIndex); } if (attr) { - hasChanged = PR_TRUE; - aCellContent->SetAttr(kNameSpaceID_None, atom, nsDependentString(attr), PR_FALSE); + // set our special -moz attribute without notifying a reflow + cellContent->SetAttr(kNameSpaceID_None, nsMathMLAtoms::MOZcolumnalign, + nsDependentString(attr), PR_FALSE); } } + // if we are not on the first column, see if |columnlines| was specified on // the table. Note that we pass 'colIndex-1' because the CSS rule in mathml.css // is associated to 'border-left', and it is as if we draw the line on behalf // of the previous cell. This way of doing so allows us to handle selective lines, // e.g., 'r|cl', and cases of spanning cells without further complications. - if (colIndex > 0) { - attr = GetValueAt(aPresContext, tableFrame, nsMathMLAtoms::columnlines_, colIndex-1); - // set the special -moz-math-columnline without notifying that we want a reflow + if (colIndex > 0 && + !cellContent->HasAttr(kNameSpaceID_None, nsMathMLAtoms::MOZcolumnline)) { + attr = GetValueAt(aTableFrame, nsMathMLAtoms::columnlines_, colIndex-1); if (attr) { - hasChanged = PR_TRUE; - aCellContent->SetAttr(kNameSpaceID_None, nsMathMLAtoms::MOZcolumnline, nsDependentString(attr), PR_FALSE); + // set our special -moz attribute without notifying a reflow + cellContent->SetAttr(kNameSpaceID_None, nsMathMLAtoms::MOZcolumnline, + nsDependentString(attr), PR_FALSE); } } - else { - // set the special -moz-math-firstcolumn to annotate that we are on the first column - hasChanged = PR_TRUE; - aCellContent->SetAttr(kNameSpaceID_None, nsMathMLAtoms::MOZfirstcolumn, trueStr, PR_FALSE); - } - // if we are on the last column, set the special -moz-math-lastcolumn - PRInt32 colSpan = ((nsTableFrame*)tableFrame)->GetEffectiveColSpan(*cellFrame); - sibling = ((nsTableFrame*)tableFrame)->GetCellFrameAt(rowIndex, colIndex+colSpan); - if (!sibling) { - hasChanged = PR_TRUE; - aCellContent->SetAttr(kNameSpaceID_None, nsMathMLAtoms::MOZlastcolumn, trueStr, PR_FALSE); - } +} - // now, re-resolve the style contexts in our subtree to pick up any changes - if (hasChanged) { - // this is unused - nsFrameManager *fm = aPresContext->FrameManager(); - nsStyleChangeList changeList; - nsChangeHint maxChange = fm->ComputeStyleChangeFor(aCellFrame, &changeList, - NS_STYLE_HINT_NONE); -#ifdef DEBUG - // Use the parent frame to make sure we catch in-flows and such - nsIFrame* parentFrame = aCellFrame->GetParent(); - fm->DebugVerifyStyleTree(parentFrame ? parentFrame : aCellFrame); -#endif +// map all attribues within a table -- requires the indices of rows and cells. +// so it can only happen after they are made ready by the table base class. +static void +MapAllAttributesIntoCSS(nsIFrame* aTableFrame) +{ + //XXX only loop for the sake of it, + //mtable is simple and only has one (pseudo) row-group + nsIFrame* rowgroupFrame = aTableFrame->GetFirstChild(nsnull); + for ( ; rowgroupFrame; rowgroupFrame = rowgroupFrame->GetNextSibling()) { + nsIFrame* rowFrame = rowgroupFrame->GetFirstChild(nsnull); + for ( ; rowFrame; rowFrame = rowFrame->GetNextSibling()) { + DEBUG_VERIFY_THAT_FRAME_IS(rowFrame, tableRow); + if (rowFrame->GetType() == nsGkAtoms::tableRowFrame) { + MapRowAttributesIntoCSS(aTableFrame, rowFrame); + nsIFrame* cellFrame = rowFrame->GetFirstChild(nsnull); + for ( ; cellFrame; cellFrame = cellFrame->GetNextSibling()) { + NS_ASSERTION(IS_TABLE_CELL(cellFrame->GetType()),"internal error"); + if (IS_TABLE_CELL(cellFrame->GetType())) { + MapColAttributesIntoCSS(aTableFrame, rowFrame, cellFrame); + } + } + } + } } } @@ -395,9 +358,9 @@ nsMathMLmtableOuterFrame::Init(nsIContent* aContent, nsIFrame* aParent, nsIFrame* aPrevInFlow) { - MapAttributesIntoCSS(GetPresContext(), aContent); - - return nsTableOuterFrame::Init(aContent, aParent, aPrevInFlow); + nsresult rv = nsTableOuterFrame::Init(aContent, aParent, aPrevInFlow); + nsMathMLFrame::MapCommonAttributesIntoCSS(GetPresContext(), aContent); + return rv; } nsIFrame* @@ -423,7 +386,7 @@ nsMathMLmtableOuterFrame::GetRowFrameAt(nsPresContext* aPresContext, nsIFrame* rowFrame = rowIter.First(); while (rowFrame) { if (--aRowIndex == 0) { - DEBUG_VERIFY_THAT_FRAME_IS(rowFrame, TABLE_ROW); + DEBUG_VERIFY_THAT_FRAME_IS(rowFrame, tableRow); return rowFrame; } rowFrame = rowIter.Next(); @@ -434,45 +397,12 @@ nsMathMLmtableOuterFrame::GetRowFrameAt(nsPresContext* aPresContext, return nsnull; } -#ifdef NS_DEBUG -void -nsMathMLmtableOuterFrame::DEBUG_VerifyTableRelatedFrames() -{ - PRInt32 rowCount, colCount; - GetTableSize(rowCount, colCount); - nsTableIteration dir = eTableLTR; - nsIFrame* innerTableFrame = mFrames.FirstChild(); - nsTableIterator rowgroupIter(*innerTableFrame, dir); - nsIFrame* rowgroupFrame = rowgroupIter.First(); - for ( ; rowgroupFrame; rowgroupFrame = rowgroupIter.Next()) { - nsTableIterator rowIter(*rowgroupFrame, dir); - nsIFrame* rowFrame = rowIter.First(); - for ( ; rowFrame; rowFrame = rowIter.Next()) { - DEBUG_VERIFY_THAT_FRAME_IS(rowFrame, TABLE_ROW); - //XXX uncomment this if ever gets its own MathML frame implementation - //NS_ASSERTION(rowFrame->IsFrameOfType(nsIFrame::eMathML), - // "non MathML row frame"); - nsTableIterator cellIter(*rowFrame, dir); - nsIFrame* cellFrame = cellIter.First(); - for ( ; cellFrame; cellFrame = cellIter.Next()) { - DEBUG_VERIFY_THAT_FRAME_IS(cellFrame, TABLE_CELL); - NS_ASSERTION(cellFrame->IsFrameOfType(nsIFrame::eMathML), - "non MathML cell frame"); - } - } - } -} -#endif - NS_IMETHODIMP nsMathMLmtableOuterFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { -#ifdef NS_DEBUG - DEBUG_VerifyTableRelatedFrames(); -#endif nsresult rv; nsAutoString value; // we want to return a table that is anchored according to the align attribute @@ -603,6 +533,134 @@ nsMathMLmtableOuterFrame::IsFrameOfType(PRUint32 aFlags) const return !(aFlags & ~nsIFrame::eMathML); } +// -------- +// implementation of nsMathMLmtableFrame + +NS_IMPL_ADDREF_INHERITED(nsMathMLmtableFrame, nsTableFrame) +NS_IMPL_RELEASE_INHERITED(nsMathMLmtableFrame, nsTableFrame) +NS_IMPL_QUERY_INTERFACE_INHERITED0(nsMathMLmtableFrame, nsTableFrame) + +nsIFrame* +NS_NewMathMLmtableFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) +{ + return new (aPresShell) nsMathMLmtableFrame(aContext); +} + +nsMathMLmtableFrame::~nsMathMLmtableFrame() +{ +} + +PRBool +nsMathMLmtableFrame::IsFrameOfType(PRUint32 aFlags) const +{ + return !(aFlags & ~nsIFrame::eMathML); +} + +NS_IMETHODIMP +nsMathMLmtableFrame::SetInitialChildList(nsIAtom* aListName, + nsIFrame* aChildList) +{ + nsresult rv = nsTableFrame::SetInitialChildList(aListName, aChildList); + if (NS_FAILED(rv)) return rv; + MapAllAttributesIntoCSS(this); + return rv; +} + +void +nsMathMLmtableFrame::RestyleTable() +{ + // Cancel any reflow command that may be pending for this table + GetPresContext()->PresShell()->CancelReflowCommand(this, nsnull); + + // re-sync MathML specific style data that may have changed + MapAllAttributesIntoCSS(this); + + // Explicitly request a re-resolve and reflow in our subtree to pick up any changes + GetPresContext()->PresShell()->FrameConstructor()-> + PostRestyleEvent(mContent, eReStyle_Self, nsChangeHint_ReflowFrame); +} + +// -------- +// implementation of nsMathMLmtrFrame + +NS_IMPL_ADDREF_INHERITED(nsMathMLmtrFrame, nsTableRowFrame) +NS_IMPL_RELEASE_INHERITED(nsMathMLmtrFrame, nsTableRowFrame) +NS_IMPL_QUERY_INTERFACE_INHERITED0(nsMathMLmtrFrame, nsTableRowFrame) + +nsIFrame* +NS_NewMathMLmtrFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) +{ + return new (aPresShell) nsMathMLmtrFrame(aContext); +} + +nsMathMLmtrFrame::~nsMathMLmtrFrame() +{ +} + +NS_IMETHODIMP +nsMathMLmtrFrame::Init(nsIContent* aContent, + nsIFrame* aParent, + nsIFrame* aPrevInFlow) +{ + nsresult rv = nsTableRowFrame::Init(aContent, aParent, aPrevInFlow); + nsMathMLFrame::MapCommonAttributesIntoCSS(GetPresContext(), aContent); + return rv; +} + +PRBool +nsMathMLmtrFrame::IsFrameOfType(PRUint32 aFlags) const +{ + return !(aFlags & ~nsIFrame::eMathML); +} + +NS_IMETHODIMP +nsMathMLmtrFrame::AttributeChanged(PRInt32 aNameSpaceID, + nsIAtom* aAttribute, + PRInt32 aModType) +{ + // Attributes common to MathML tags + if (nsMathMLFrame::CommonAttributeChangedFor(GetPresContext(), mContent, aAttribute)) + return NS_OK; + + // Attributes specific to : + // groupalign : Not yet supported. + // rowalign : Fully specified in mathml.css, and so HasAttributeDependentStyle() will + // pick it up and nsCSSFrameConstructor will issue a PostRestyleEvent(). + // columnalign : Need an explicit re-style call. + + if (aAttribute == nsMathMLAtoms::rowalign_) { + // unset any -moz attribute that we may have set earlier, and re-sync + mContent->UnsetAttr(kNameSpaceID_None, nsMathMLAtoms::MOZrowalign, PR_FALSE); + MapRowAttributesIntoCSS(nsTableFrame::GetTableFrame(this), this); + // That's all - see comment above. + return NS_OK; + } + + if (aAttribute != nsMathMLAtoms::columnalign_) + return NS_OK; + + // Clear any cached columnalign's nsValueList for this row + DeleteProperty(aAttribute); + + // Clear any internal -moz attribute that we may have set earlier + // in our cells and re-sync their columnalign attribute + nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); + nsIFrame* cellFrame = GetFirstChild(nsnull); + for ( ; cellFrame; cellFrame = cellFrame->GetNextSibling()) { + if (IS_TABLE_CELL(cellFrame->GetType())) { + cellFrame->GetContent()-> + UnsetAttr(kNameSpaceID_None, nsMathMLAtoms::MOZcolumnalign, PR_FALSE); + MapColAttributesIntoCSS(tableFrame, this, cellFrame); + } + } + + // Explicitly request a re-resolve and reflow in our subtree to pick up any changes + GetPresContext()->PresShell()->FrameConstructor()-> + PostRestyleEvent(mContent, eReStyle_Self, nsChangeHint_ReflowFrame); + + return NS_OK; +} + // -------- // implementation of nsMathMLmtdFrame @@ -620,6 +678,16 @@ nsMathMLmtdFrame::~nsMathMLmtdFrame() { } +NS_IMETHODIMP +nsMathMLmtdFrame::Init(nsIContent* aContent, + nsIFrame* aParent, + nsIFrame* aPrevInFlow) +{ + nsresult rv = nsTableCellFrame::Init(aContent, aParent, aPrevInFlow); + nsMathMLFrame::MapCommonAttributesIntoCSS(GetPresContext(), aContent); + return rv; +} + PRInt32 nsMathMLmtdFrame::GetRowSpan() { @@ -656,6 +724,40 @@ nsMathMLmtdFrame::IsFrameOfType(PRUint32 aFlags) const return !(aFlags & ~nsIFrame::eMathML); } +NS_IMETHODIMP +nsMathMLmtdFrame::AttributeChanged(PRInt32 aNameSpaceID, + nsIAtom* aAttribute, + PRInt32 aModType) +{ + // Attributes common to MathML tags + if (nsMathMLFrame::CommonAttributeChangedFor(GetPresContext(), mContent, aAttribute)) + return NS_OK; + + // Attributes specific to : + // groupalign : Not yet supported + // rowalign : in mathml.css + // columnalign : here + // rowspan : here + // columnspan : here + + if (aAttribute == nsMathMLAtoms::columnalign_) { + // unset any -moz attribute that we may have set earlier, and re-sync + mContent->UnsetAttr(kNameSpaceID_None, nsMathMLAtoms::MOZcolumnalign, PR_FALSE); + MapColAttributesIntoCSS(nsTableFrame::GetTableFrame(this), mParent, this); + return NS_OK; + } + + if (aAttribute == nsMathMLAtoms::rowspan || + aAttribute == nsMathMLAtoms::columnspan_) { + // use the naming expected by the base class + if (aAttribute == nsMathMLAtoms::columnspan_) + aAttribute = nsMathMLAtoms::colspan; + return nsTableCellFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType); + } + + return NS_OK; +} + // -------- // implementation of nsMathMLmtdInnerFrame @@ -692,11 +794,6 @@ nsMathMLmtdInnerFrame::Reflow(nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - // Map attributes to style (hopefully, bug 69409 will eventually help here). - if (NS_FRAME_FIRST_REFLOW & mState) { - MapAttributesInto(aPresContext, mContent, mParent, this); - } - // Let the base class do the reflow nsresult rv = nsBlockFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus); diff --git a/layout/mathml/base/src/nsMathMLmtableFrame.h b/layout/mathml/base/src/nsMathMLmtableFrame.h index 868d74fd36ed..fc7c9a9b8d18 100644 --- a/layout/mathml/base/src/nsMathMLmtableFrame.h +++ b/layout/mathml/base/src/nsMathMLmtableFrame.h @@ -92,9 +92,6 @@ public: virtual PRBool IsFrameOfType(PRUint32 aFlags) const; -#ifdef NS_DEBUG - void DEBUG_VerifyTableRelatedFrames(); -#endif protected: nsMathMLmtableOuterFrame(nsStyleContext* aContext) : nsTableOuterFrame(aContext) {} virtual ~nsMathMLmtableOuterFrame(); @@ -109,6 +106,129 @@ protected: // -------------- +class nsMathMLmtableFrame : public nsTableFrame +{ +public: + friend nsIFrame* NS_NewMathMLmtableFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); + + NS_DECL_ISUPPORTS_INHERITED + + // Overloaded nsTableFrame methods + + NS_IMETHOD + SetInitialChildList(nsIAtom* aListName, + nsIFrame* aChildList); + + NS_IMETHOD + AppendFrames(nsIAtom* aListName, + nsIFrame* aFrameList) + { + nsresult rv = nsTableFrame::AppendFrames(aListName, aFrameList); + RestyleTable(); + return rv; + } + + NS_IMETHOD + InsertFrames(nsIAtom* aListName, + nsIFrame* aPrevFrame, + nsIFrame* aFrameList) + { + nsresult rv = nsTableFrame::InsertFrames(aListName, aPrevFrame, aFrameList); + RestyleTable(); + return rv; + } + + NS_IMETHOD + RemoveFrame(nsIAtom* aListName, + nsIFrame* aOldFrame) + { + nsresult rv = nsTableFrame::RemoveFrame(aListName, aOldFrame); + RestyleTable(); + return rv; + } + + virtual PRBool IsFrameOfType(PRUint32 aFlags) const; + + // helper to restyle and reflow the table when a row is changed -- since MathML + // attributes are inter-dependent and row/colspan can affect the table, it is + // safer (albeit grossly suboptimal) to just relayout the whole thing. + void RestyleTable(); + +protected: + nsMathMLmtableFrame(nsStyleContext* aContext) : nsTableFrame(aContext) {} + virtual ~nsMathMLmtableFrame(); +}; // class nsMathMLmtableFrame + +// -------------- + +class nsMathMLmtrFrame : public nsTableRowFrame +{ +public: + friend nsIFrame* NS_NewMathMLmtrFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); + + NS_DECL_ISUPPORTS_INHERITED + + // overloaded nsTableRowFrame methods + + NS_IMETHOD + Init(nsIContent* aContent, + nsIFrame* aParent, + nsIFrame* aPrevInFlow); + + NS_IMETHOD + AttributeChanged(PRInt32 aNameSpaceID, + nsIAtom* aAttribute, + PRInt32 aModType); + + NS_IMETHOD + AppendFrames(nsIAtom* aListName, + nsIFrame* aFrameList) + { + nsresult rv = nsTableRowFrame::AppendFrames(aListName, aFrameList); + RestyleTable(); + return rv; + } + + NS_IMETHOD + InsertFrames(nsIAtom* aListName, + nsIFrame* aPrevFrame, + nsIFrame* aFrameList) + { + nsresult rv = nsTableRowFrame::InsertFrames(aListName, aPrevFrame, aFrameList); + RestyleTable(); + return rv; + } + + NS_IMETHOD + RemoveFrame(nsIAtom* aListName, + nsIFrame* aOldFrame) + { + nsresult rv = nsTableRowFrame::RemoveFrame(aListName, aOldFrame); + RestyleTable(); + return rv; + } + + virtual PRBool IsFrameOfType(PRUint32 aFlags) const; + + // helper to restyle and reflow the table -- @see nsMathMLmtableFrame. + void RestyleTable() + { + nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); + if (tableFrame && tableFrame->IsFrameOfType(nsIFrame::eMathML)) { + // cancel any reflow command that may be pending for the row + GetPresContext()->PresShell()->CancelReflowCommand(this, nsnull); + // relayout the table + ((nsMathMLmtableFrame*)tableFrame)->RestyleTable(); + } + } + +protected: + nsMathMLmtrFrame(nsStyleContext* aContext) : nsTableRowFrame(aContext) {} + virtual ~nsMathMLmtrFrame(); +}; // class nsMathMLmtrFrame + +// -------------- + class nsMathMLmtdFrame : public nsTableCellFrame { public: @@ -117,6 +237,17 @@ public: NS_DECL_ISUPPORTS_INHERITED // overloaded nsTableCellFrame methods + + NS_IMETHOD + Init(nsIContent* aContent, + nsIFrame* aParent, + nsIFrame* aPrevInFlow); + + NS_IMETHOD + AttributeChanged(PRInt32 aNameSpaceID, + nsIAtom* aAttribute, + PRInt32 aModType); + virtual PRInt32 GetRowSpan(); virtual PRInt32 GetColSpan(); virtual PRBool IsFrameOfType(PRUint32 aFlags) const; diff --git a/layout/mathml/content/src/mathml.css b/layout/mathml/content/src/mathml.css index 24d0fc5c3749..06d62e7584a3 100644 --- a/layout/mathml/content/src/mathml.css +++ b/layout/mathml/content/src/mathml.css @@ -289,11 +289,12 @@ mtable[frame="dashed"] { mtr { display: table-row; + vertical-align: baseline; } mtd { display: table-cell; - vertical-align: baseline; + vertical-align: inherit; text-align: -moz-center; white-space: nowrap; } @@ -307,32 +308,45 @@ mtd { /***********************/ /* -- mtd: columnalign */ +mtd[-moz-math-columnalign="left"], mtd[columnalign="left"] { text-align: left; } +mtd[-moz-math-columnalign="right"], mtd[columnalign="right"] { text-align: right; } +mtd[-moz-math-columnalign="center"], mtd[columnalign="center"] { text-align: -moz-center; } -/********************/ -/* -- mtd: rowalign */ +/*************************/ +/* -- mtr, mtd: rowalign */ +mtr[-moz-math-rowalign="top"], +mtr[rowalign="top"], mtd[rowalign="top"] { vertical-align: top; } +mtr[-moz-math-rowalign="bottom"], +mtr[rowalign="bottom"], mtd[rowalign="bottom"] { vertical-align: bottom; } +mtr[-moz-math-rowalign="center"], +mtr[rowalign="center"], mtd[rowalign="center"] { vertical-align: middle; } +mtr[-moz-math-rowalign="baseline"], +mtr[rowalign="baseline"], mtd[rowalign="baseline"] { vertical-align: baseline; } /* -- not yet supported -- +mtr[-moz-math-rowalign="axis"], +mtr[rowalign="axis"], mtd[rowalign="axis"] { vertical-align: mathline; } @@ -351,33 +365,33 @@ mtd { padding-top: 0.5ex; /* half of rowspacing[rowindex-1] */ } /* turn off the spacing at the periphery of boundary cells */ -mtd[-moz-math-firstrow="true"] { +mtr:first-child > mtd { padding-top: 0ex; } -mtd[-moz-math-lastrow="true"] { +mtr:last-child > mtd { padding-bottom: 0ex; } -mtd[-moz-math-firstcolumn="true"] { +mtd:first-child { padding-left: 0em; } -mtd[-moz-math-lastcolumn="true"] { +mtd:last-child { padding-right: 0em; } /* re-instate the spacing if the table has a surrounding frame */ -mtable[frame="solid"] > mtr > mtd[-moz-math-firstrow="true"], -mtable[frame="dashed"] > mtr > mtd[-moz-math-firstrow="true"] { +mtable[frame="solid"] > mtr:first-child > mtd, +mtable[frame="dashed"] > mtr:first-child > mtd { padding-top: 0.5ex; /* framespacing.top */ } -mtable[frame="solid"] > mtr > mtd[-moz-math-lastrow="true"], -mtable[frame="dashed"] > mtr > mtd[-moz-math-lastrow="true"] { +mtable[frame="solid"] > mtr:last-child > mtd, +mtable[frame="dashed"] > mtr:last-child > mtd { padding-bottom: 0.5ex; /* framespacing.bottom */ } -mtable[frame="solid"] > mtr > mtd[-moz-math-firstcolumn="true"], -mtable[frame="dashed"] > mtr > mtd[-moz-math-firstcolumn="true"] { +mtable[frame="solid"] > mtr > mtd:first-child, +mtable[frame="dashed"] > mtr > mtd:first-child { padding-left: 0.4em; /* framespacing.left */ } -mtable[frame="solid"] > mtr > mtd[-moz-math-lastcolumn="true"], -mtable[frame="dashed"] > mtr > mtd[-moz-math-lastcolumn="true"] { +mtable[frame="solid"] > mtr > mtd:last-child, +mtable[frame="dashed"] > mtr > mtd:last-child { padding-right: 0.4em; /* framespacing.right */ } @@ -387,13 +401,13 @@ mtable[frame="dashed"] > mtr > mtd[-moz-math-lastcolumn="true"] { unsuitable rules on the cells on the first row and the first column. In general, however, authors can use the 'border' property of CSS to achieve varying effects down to the level of the table cell. */ -mtd[-moz-math-rowline="none"] { +mtr[-moz-math-rowline="none"] > mtd { border-top: none; } -mtd[-moz-math-rowline="solid"] { +mtr[-moz-math-rowline="solid"] > mtd { border-top: solid thin; } -mtd[-moz-math-rowline="dashed"] { +mtr[-moz-math-rowline="dashed"] > mtd { border-top: dashed thin; } mtd[-moz-math-columnline="none"] {