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

This commit is contained in:
rbs%maths.uq.edu.au 2006-09-07 03:45:45 +00:00
parent 094a349785
commit de61177a24
10 changed files with 514 additions and 251 deletions

View File

@ -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")

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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<nsICSSStyleRule> 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:

View File

@ -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)

View File

@ -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);

View File

@ -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

View File

@ -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
// <mtable> or <mtr>) 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 <mtr> 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 <mtr>:
// 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 <mtd>:
// 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);

View File

@ -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;

View File

@ -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"] {