Closed Bug 330964 (row-column-spacing) Opened 18 years ago Closed 10 years ago

Add support for mtable@rowspacing/columnspacing/framespacing attributes

Categories

(Core :: MathML, defect, P3)

defect

Tracking

()

RESOLVED FIXED
mozilla33

People

(Reporter: dmharvey, Assigned: jkitch)

References

()

Details

(Keywords: dev-doc-complete)

Attachments

(9 files, 20 obsolete files)

1.27 KB, application/xhtml+xml
Details
5.36 KB, image/png
Details
1.13 KB, patch
roc
: review+
Details | Diff | Splinter Review
23.94 KB, image/png
Details
802 bytes, text/html
Details
51.70 KB, patch
Details | Diff | Splinter Review
62.76 KB, patch
Details | Diff | Splinter Review
1.58 KB, patch
Details | Diff | Splinter Review
26.48 KB, patch
Details | Diff | Splinter Review
User-Agent:       Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/417.9 (KHTML, like Gecko) Safari/417.8
Build Identifier: Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.0.1) Gecko/20060111 Firefox/1.5.0.1

The "rowspacing" attribute for MathML tables is not supported. According to the MathML spec, this attribute controls the amount of space between rows in the table. Correct implementation would allow constructs like AMS-LaTeX's "\substack" command.

For example, the following three chunks should render differently, but Gecko draws them the same way:

== example 1 ==

    <mtable rowspacing="2ex">
        <mtr><mtd><mi>x</mi></mtd></mtr>
        <mtr><mtd><mi>x</mi></mtd></mtr>
    </mtable>

== example 2 ==

    <mtable rowspacing="0">
        <mtr><mtd><mi>x</mi></mtd></mtr>
        <mtr><mtd><mi>x</mi></mtd></mtr>
    </mtable>

== example 3 ==

    <mtable>
        <mtr><mtd><mi>x</mi></mtd></mtr>
        <mtr><mtd><mi>x</mi></mtd></mtr>
    </mtable>


Reproducible: Always

Steps to Reproduce:
1. View a page with the above MathML

Actual Results:  
Example 1 should have widely spaced rows; example 2 should tightly spaced rows; example 3 should be somewhere in between.

Expected Results:  
All three tables have the same amount of inter-row space (I'm guessing 1ex).

I've only tried this on Mac OS, haven't tried other platforms.
Assignee: nobody → rbs
Component: General → MathML
Product: Firefox → Core
QA Contact: general → ian
Version: unspecified → Trunk
Status: UNCONFIRMED → NEW
Ever confirmed: true
The spec seems a bit vague as to the meaning of the rowspacing attribute (and its cousin -- columnspacing):

"The rowspacing and columnspacing  attributes specify how much space should be added between each row and column. However, spacing before the first row and after the last row (i.e. at the top and bottom of the table) is given by the second number in the value of the framespacing attribute, and spacing before the first column and after the last column (i.e. on the left and on the right of the table) is given by the first number in the value of the framespacing attribute."

1/ Case of a mathbackground set on a row, I have always understandood the MathML's rowspacing as HTML's cellpadding. Hence I would expect the extra space to go in the cell and thus get the specified mathbackground color. (Note that this is different from HTML's cellspacing -- which is outside the cell, and does not get the background-color of the cell).

2/ Case of a table with rowlines, consider this mtable:

<mtable rowspacing="1ex" rowline="solid">
   row1
   ----    <---- solid rowline
   row2
</mtable

Is the rowspacing split between the rowline, i.e., 0.5*rowspacing(before) + rowline + 0.5*rowspacing(after)? Or does the spacing means the "double", i.e., rowspacing(before) + rowline + rowspacing(after)? Or even more enigmatic, it is assumed that rowspacing should always be specified in pairs?...

I have always understood it as meaning 0.5*rowspacing(before) + rowline + 0.5*rowspacing(after). But I got confused even more looking at the testsuite.
The testcases there are not clear cut either (e.g., they have as much values in the rowspacing as the number of rows -- whereas the spec says that the rowspacing is irrelevant to before the first row and after the last row):

Testsuite links:
http://www.w3.org/Math/testsuite/testsuite/Presentation/TablesAndMatrices/mtable/mtableAspacing1.xml
http://www.w3.org/Math/testsuite/testsuite/Presentation/TablesAndMatrices/mtable/mtableAspacing2.xml
http://www.w3.org/Math/testsuite/testsuite/Presentation/TablesAndMatrices/mtable/mtableAspacing3.xml
http://www.w3.org/Math/testsuite/testsuite/Presentation/TablesAndMatrices/mtable/mtableAspacing4.xml
QA Contact: ian → mathml
Blocks: mathml-2
Hmmm. It doesn't seem that MathML3 sheds much light on RBS's questions. Perhaps these issues should be raised on the www-math mailing list.

Whatever the answer, SOME implementation of @rowspacing is better than none.
Apart from understanding how rowspacing should work, I think one of the problem  is the way some MathML attributes are currently implemented. For example if <mtable/> has a "columnalign" attribute, private "-moz-math-columnalign" attributes are created on <mtd/>'s and the style is then given by the mathml.css sheet:

http://mxr.mozilla.org/mozilla-central/source/layout/mathml/mathml.css#256

This works when we only have a small set of values, but not for attributes with a length value:

http://mxr.mozilla.org/mozilla-central/source/layout/mathml/mathml.css#303

BTW, I don't like much this method because it adds unwanted attributes in the DOM (see bug 527201) and I suspect it is causing the layout issue of bug 491384. I guess the appropriate solution would be fixing bug 69409...
Depends on: 69409
Assignee: rbs → nobody
Alias: rowspacing
shouldn't rowspacing map to borderspacing.mY and columnspacing to borderspacing.mX like cellspacing http://mxr.mozilla.org/mozilla-central/source/content/html/content/src/nsHTMLTableElement.cpp#1065 ?
mtable seems a bit different, because rowspacing can have several values and we also have framespacing. Here is how I understand the spec for a mtable of N rows, framespacing="X" and rowspacing="Y0, Y2, ..., Y_(n-1)":

^
| X
V
-----
/////
row0
/////
-----
^
| Y_(0 mod n)
V
-----
/////
row1
/////
-----
^
| Y_(1 mod n)
V
-----
/////
...
/////
-----
^
| Y_(N-2 mod n)
V
-----
/////
row_(N-1)
/////
-----
^
| X
V

However, the spec does not provide any attribute "rowpadding" that would allow to describe the spacing inside the cell. I guess that's why RBS wanted instead to split the rowspacing half inside and half outside the cell...
Alias: rowspacing → row-column-spacing
Summary: "rowspacing" attribute not supported in <mtable> element in MathML → Add support for mtable@rowspacing/columnspacing attributes
Depends on: 731667
Mass change: setting priority to 3 for bugs preventing Gecko's Native MathML to be enabled by default in MathJax.
Keywords: helpwanted
Priority: -- → P3
OS: Mac OS X → All
Hardware: PowerPC → All
Whiteboard: [mentor=fredw][lang=c++]
Here is a more info for people wanted to work on this:

== DESCRIPTION ===

The goal is to implement the rowspacing and columnspacing on the mtable element (perhaps framespacing too):

http://www.w3.org/TR/MathML/chapter3.html#presm.mtable.attrs

I asked precision on the Math WG mailing list some time ago: http://lists.w3.org/Archives/Public/www-math/2010Aug/0004.html

The rowspacing attribute is a list of lengths "l_0 l_1 l_2 ...". If the table has N rows, then the spacing applies to the N-1 gaps:

[ROW_0]
  ↕ l_0
[ROW_1]
  ↕ l_1
[ROW_2]
  ↕ l_2
...
[ROW_(N-1)]
  ↕ l_(N-1)
[ROW_N]

The note about "multiple values" say that if there are more gaps than supplied values, the last value is repeated as needed. If there are too many values supplied, the excess are ignored.

The columspacing attribute is similar but applies to gaps between columns.

In theory these attribute values can come from an mstyle ancestors (bug 768819) but we want to WONTFIX that one after bug 838509, so no need to worry about that.

As said in comment 5, this seems to correspond to HTML attributes cellspacing:

http://mxr.mozilla.org/mozilla-central/source/content/html/content/src/HTMLTableElement.cpp#703
https://developer.mozilla.org/en-US/docs/Web/CSS/border-spacing

except that the spacing can be different for each gap between column/row so it's a bit more complicated. Also, note that the border-spacing is used for the spacing around the table, so it might be relevant to consider the mtable@framespacing attribute as well: this one takes two length values and specifies the additional spacing added between the table and frame, if frame is not "none". The first value specifies the spacing on the right and left; the second value specifies the spacing above and below.

=== PROPOSAL == 

The work is very similar to what Quentin did in bug 731667. I see essentially three steps (so three separate patches):

1) Tests (see attachment 8347144 [details] [diff] [review]). Some ideas:

   - rowspacing/columnspacing
   - single/multiple values
   - not enough values / too much values
   - invalid attributes
   - dynamic changes via Javascript
   - various values for spacing including 0 and default

2) Parsing of rowspacing/columnspacing

   See http://mxr.mozilla.org/mozilla-central/source/layout/mathml/nsMathMLmtableFrame.cpp and in particular MapAllAttributesIntoCSS where we create new FrameProperties. On the one hand, this can be easier because you only have to consider attributes from the <mtable> (not <mtd> or <mtr>) but on the other hand you have to store a list of nsCSSValues returned by nsMathMLElement::ParseNumericValue (http://mxr.mozilla.org/mozilla-central/source/content/mathml/content/src/nsMathMLElement.cpp), rather than just enumerate values like center/left/right, so the code should be adapted.

3) Rendering of rowspacing/columnspacing

You'll have to generalize the layout/tables implementation from which nsMathMLmtableFrame is derived so that it is able to handle different different spacing for each gap between column/row. Perhaps one way would be to make nsTableFrame::GetCellSpacingX() and  nsTableFrame::GetCellSpacingY() take an (optional?) argument indicating the gap index (perhaps using -1 and N for the spacing around the table, or something like that). Then every places where it is used in layout/tables/ should be modified to specify the gap index explicitly. nsTableFrame::GetCellSpacingX() and nsTableFrame::GetCellSpacingY() will just ignore that gap index and use the frame-spacing value, so the HTML implementation won't be affected. However nsMathMLmtableFrame will override this GetCellSpacingX/GetCellSpacingY to take into account the gap index and to return the value from FrameProperties, when specified.

An alternative for 2) and 3): one could create new private CSS properties  -moz-row-spacing / -moz-column-spacing that would handle a list of length and map the MathML attributes to these properties on the content/ side. Then modify layout/tables/ to consider these values in place of frame-spacing, when they are specified.
Whiteboard: [mentor=fredw][lang=c++] → [mentor=fredw][lang=c++][see comment 8 if you want to work on this]
Blocks: 958947
Summary: Add support for mtable@rowspacing/columnspacing attributes → Add support for mtable@rowspacing/columnspacing/framespacing attributes
Assignee: nobody → jkitch.bug
Attached image tablespacing.png
The attached picture shows a 2x2 <mtable>, with each <mtd> containing a single <mn>. row/column/framespacing are all set to 0 (or 0 0).  Document set to standards compliance mode.

The blue dashed border indicates the <mn> element's outline, the red border that of the <mtd> elements and the black border that of <mtable>.  I interpret the touching of the borders as indicating that the 0 spacing is rendered appropriately.

What I haven't worked out is what is causing the spacing within the <mtd> element within standards compliance mode.  (It disappears when rendered in quirks mode).  I've tried zeroing the margin and padding for everything in the page, but without success.    

Can you identify the cause of the whitespace?  I presume it is something that needs to be taken into account, otherwise 0.5ex will be added to whatever rowspacing the user specifies.
Flags: needinfo?(fred.wang)
Do you have a testcase / patch that you used to take that screenshot?
Flags: needinfo?(fred.wang)
Adds an row/column index argument to GetCellSpacing.  The two argument version is a nicety that calculates the spacing of multiple columns.  In the default tableFrame case it simply multiplies the answer out.  These functions are to be overloaded by nsMathMLmtableFrame.

I'm not yet certain of selecting the correct row/column in all cases, but if the code isn't exercised by MathML the choice is unimportant and won't change the outcome.  I suppose I can only use the argument method on instances invoked by MathML tables and have the argument-less one assert in such situations.
Attached patch Part 2: MathML mtable changes (obsolete) — Splinter Review
As far as I can tell row/column/framespacing isn't exposed to anything except mtable, so performing the parsing within the class seems reasonable.

It mostly works, but there are a few test failures still to resolve and more tests are needed.
Attached patch Part 3: tests WIP (obsolete) — Splinter Review
Not yet exhaustive tests are attached.

attachment 8377104 [details] corresponds to tablespacing-5.html although I doubt that particular test will be included as part of the final set.

Tests to ensure that rowspacing="5ex" really creates a 5ex space are yet to be written.
The purpose of CalcUnpaginagedHeight is to compute a height, which is presumably a vertical distance.  Everything within the function deals with a vertical difference except the declaration of computedHeight, which seeks to multiply a number of rows (rowspan - 1) with the distance between columns (GetCellSpacingX()).  This I believe to be a mistake.

GetCellSpacingY() which returns the distance between two rows seems a more appropriate fit.
Attachment #8380338 - Flags: review?(roc)
The spacing between rows and clumns in MathML mtables is variable, so I would like to add an argument to GetCellSpacing[XY] to specify which row/column space to use.

In ordinary tables the argument doesn't matter, so there shouldn't be any effect other than the asserts ensuring sensible values are passed in.  These asserts are also helpful in checking whether the correct function is called in situations where the number of rows and columns differ.

The two argument version of GetCellSpacing[XY] is a convenience to allow cumulative spacing to be determined by a single multiplication when index doesn't matter, rather than repeatedly adding the same operand.
Attachment #8377453 - Attachment is obsolete: true
Attachment #8380339 - Flags: review?(roc)
Sorry but I have to ask: are these attributes really needed? Could authors just use CSS padding instead?
(In reply to Robert O'Callahan (:roc) (Mozilla Corporation) from comment #16)
> Sorry but I have to ask: are these attributes really needed? Could authors
> just use CSS padding instead?

My understanding is that two accomplish different things.  In the attached diagram:

left example sets mtd {padding:5px;}
middle example sets mtable {border-spacing:5px} mtd{padding:0px;}
right example sets rowspacing="5px 20px" columnspacing="5px 20px" framespacing="5px 5px" (using the patches from this bug)

padding adds the space inside the table cells, which are then placed touching each other, resulting in a solid block of red.
border-spacing leaves 5px of white between the cells, resulting in a windowpane effect.
rowspacing/columnspacing is similar to the border-spacing example, except different spaces can be specified.

Now I am not an expert in CSS, so the third example might still be replicable by other means but it may not be a simple process.
One thing to consider is that in practice we are bit constrained by the current status of math:

1) LaTeX is the de facto standard. And in LaTeX we put all the table formatting as an argument of the environment command  that generates the table. So it's a bit tedious for LaTeX-to-MathML converters to have to move all this formating to cell nodes, especially when they are fast stream filter like itex2MML where you are essentially handling a MathML string not a DOM tree. That's why LaTeX-to-MathML converters use columnspacing/rowspacing and the other alignment attributes already implemented.

2) MathML is still used in environment where CSS is not available. Or in polyfills like MathJax that don't work well with CSS. In particular, Wikipedia will rely on MathJax to do server-side LaTeX-to-MathML conversion and thus the MathML output served will contain columnspacing/rowspacing.

Of course, MathML is designed with 1) and 2) in mind. That's a bit a pain that we have to modify so much of the table code to do that but I don't really see how we can do otherwise without duplicating the code into the MathML table module...
Attached patch MathML mtable changes (obsolete) — Splinter Review
Now passes tests.

The old padding CSS has been stripped out, but I'm not sure if explicitly zeroing it is correct.

A consequence of this patch is that css border-spacing on longer has any effect.
Attachment #8377454 - Attachment is obsolete: true
Attachment #8380506 - Flags: review?(fred.wang)
Attached patch Part 4: tests (obsolete) — Splinter Review
Tested:
static and dynamic setting of attributes
Default values
Error handling (an unreadable value falls back to the default value) 
Pixel counting mochitest to ensure a spacing of 7px really is 7px.
Attachment #8377461 - Attachment is obsolete: true
Attachment #8380508 - Flags: review?(fred.wang)
Testcase for the screenshot posted earlier in attachment 8377104 [details].

I've disabled padding and margin for everything, but cannot account for the gap between the <mn> border and the <mtd> border.

The attached patches ensure that rowspacing="0px" and rowspacing="10px" give a spacing beween <mtd> elements of 0 and 10px respectively, but there is an additional 0.5ex in vertical spacing between the <mn> elements.
Comment on attachment 8380506 [details] [diff] [review]
MathML mtable changes

Review of attachment 8380506 [details] [diff] [review]:
-----------------------------------------------------------------

Thanks that looks good to me. Some minor comments below.

::: layout/mathml/nsMathMLmtableFrame.cpp
@@ +365,5 @@
> +// Unitless values are permitted and provide a multiple of the default value
> +// Negative values are forbidden.
> +//
> +
> +// rowspacing

framespacing

@@ +386,5 @@
> +
> +#define DEFAULT_ROWSPACING_EX 1.0
> +#define DEFAULT_COLUMNSPACING_EM 0.8
> +#define DEFAULT_FRAMESPACING_ARG0_EM 0.4
> +#define DEFAULT_FRAMESPACING_ARG1_EX 0.5

what about using static const variables instead of macros?

@@ +435,5 @@
> +    }
> +
> +    // Grab the value found and process it.
> +    if (count > 0) {
> +

blank line not needed.

@@ +474,5 @@
> +
> +  NS_ASSERTION(aAttribute == nsGkAtoms::rowspacing_ ||
> +               aAttribute == nsGkAtoms::columnspacing_ ||
> +               aAttribute == nsGkAtoms::framespacing_,
> +               "Non spacing attribute passed");

I would move this assertion at the top of the function body.

@@ +494,5 @@
> +    aFrame->SetRowSpacingArray(valueList);
> +  } else if (aAttribute == nsGkAtoms::columnspacing_) {
> +    aFrame->SetColSpacingArray(valueList);
> +  } else { // framespacing_
> +    if (valueList.Length() >= 2) {

I think this should be ==. The spec/RelaxNG schema does not seem to accept more than 2 values.

@@ +660,5 @@
> +  nsPresContext* presContext = tableFrame->PresContext();
> +  if (aAttribute == nsGkAtoms::rowspacing_ ||
> +      aAttribute == nsGkAtoms::columnspacing_ ||
> +      aAttribute == nsGkAtoms::framespacing_ ) {
> +    nsMathMLmtableFrame* mathMLmtabFrame = do_QueryFrame(tableFrame);

could be the full word: mathMLmtableFrame

@@ +675,5 @@
> +    // clear any cached property list for this table
> +    presContext->PropertyTable()->
> +      Delete(tableFrame, AttributeToProperty(aAttribute));
> +    // Reparse the new attribute on the table.
> +    ParseFrameAttribute(tableFrame, aAttribute, true);

So I think these could be reorganized:

if aAttribute is nsGkAtoms::*spacing_ => ParseSpacingAttribute

else if aAttribute is nsGkAtoms::*align or nsGkAtoms::*lines => ParseFrameAttribute

else => ignore attributes that do not affect layout (return NS_OK)

@@ +848,5 @@
>  {
>    nsresult rv = nsTableFrame::SetInitialChildList(aListID, aChildList);
>    if (NS_FAILED(rv)) return rv;
>    MapAllAttributesIntoCSS(this);
> +  ParseSpacingAttributes(this);

I think the call to ParseSpacingAttributes can be move to MapAllAttributesIntoCSS, so that you don't need to do it here.

@@ +857,5 @@
>  nsMathMLmtableFrame::RestyleTable()
>  {
>    // re-sync MathML specific style data that may have changed
>    MapAllAttributesIntoCSS(this);
> +  ParseSpacingAttributes(this);

ditto

@@ +874,5 @@
> +    return 0;
> +  }
> +  if (aColIndex < 0 || aColIndex >= GetColCount()) {
> +    NS_ASSERTION(aColIndex == -1 || aColIndex == GetColCount(),
> +                 "Desired column beyond bounds of table + frame");

do you mean "table frame"? (without the +)

::: layout/mathml/nsMathMLmtableFrame.h
@@ +114,5 @@
> +  /** helper to get the cell spacing X style value */
> +  nscoord GetCellSpacingX(int32_t aColIndex) MOZ_OVERRIDE;
> +
> +  /** helper to get the combined cell spacing X style values of multiple
> +   *  columns

perhaps you could say the sum from aStartColIndex to aEndColIndex
Attachment #8380506 - Flags: review?(fred.wang) → review+
Attachment #8380508 - Flags: review?(fred.wang) → review+
(In reply to James Kitchener (:jkitch) from comment #19)
> The old padding CSS has been stripped out, but I'm not sure if explicitly
> zeroing it is correct.
> 
> A consequence of this patch is that css border-spacing on longer has any
> effect.

IIRC for the other attributes, we tried to preserve the CSS when attributes are not specified explicitly. Maybe we can do the same here.
Attached patch Part 2: MathML mtable changes (obsolete) — Splinter Review
The new table spacing code is now opt in.  If at least one of rowspacing, columnspacing or framespacing is specified the new spacing is adopted, otherwise it falls back to the old CSS implementation.

The code now reports a parsing error if the attribute value contains no lengths (although rowspacing="" will still opt in to the new table spacing system).
Attachment #8380506 - Attachment is obsolete: true
Attached patch Part 3: tests (obsolete) — Splinter Review
A consequence of the changes in the previous patch is that dir-6 once again fails as it uses the old CSS implementation.  The test has been cloned to dir-6a which tests against the new system.

Dynamic tests involving transitioning from the old system to new (and vice versa) have been added.
Attachment #8380508 - Attachment is obsolete: true
Comment on attachment 8382070 [details] [diff] [review]
Part 2: MathML mtable changes

Flagging for review to get confirmation on behaviour change.
Attachment #8382070 - Flags: review?(fred.wang)
(In reply to James Kitchener (:jkitch) from comment #26)
> Comment on attachment 8382070 [details] [diff] [review]
> Part 2: MathML mtable changes
> 
> Flagging for review to get confirmation on behaviour change.

OK, change sounds good. I'm expecting that specifiying no attributes behaves the same as the default MathML values. Do you know why it is not working in RTL mode and why your previous patch fixed that?
Comment on attachment 8380339 [details] [diff] [review]
Part1: Add arguments to GetCellSpacing[XY]

Cancelling review until further bugs are resolved.
Attachment #8380339 - Flags: review?(roc)
Comment on attachment 8382070 [details] [diff] [review]
Part 2: MathML mtable changes

I haven't looked into the rtl problem yet.

Cancelling review as the patch is still buggy.  setting one of rowspacing/columnspacing/framespacing breaks rowlines and columnlines.

rowlines/columnlines draw the lines at the edge of the <mtd> element, which is no longer the midpoint between two cells.
Attachment #8382070 - Flags: review?(fred.wang)
Depends on: 975935
Attached patch Part 2: MathML mtable changes (obsolete) — Splinter Review
This patch applies on top of the patches from bug 975935.

The rowlines/columnlines attributes now render properly when used in conjunction with rowspacing/columnspacing/framespacing.  The additional area occupied by the row and column lines are considered as overflow for the table cells.
Attachment #8382070 - Attachment is obsolete: true
Attachment #8384493 - Flags: review?(fred.wang)
Attached patch Part 3: tests (obsolete) — Splinter Review
Now includes a test for combined rowlines/columnlines and rowspacing et al.  It blacks out most of an mtable, leaving only the middle exposed.  Success occurs if something is drawn in the middle region.

I'm avoiding an explicit comparison between a CSS rendered table and a rowspacing etc. one as the two cases may differ due to rounding.
Attachment #8382074 - Attachment is obsolete: true
Comment on attachment 8380339 [details] [diff] [review]
Part1: Add arguments to GetCellSpacing[XY]

Reflagging for review.
Attachment #8380339 - Flags: review?(roc)
Attached patch Part 2: MathML mtable changes (obsolete) — Splinter Review
whitespace fixes.
Attachment #8384493 - Attachment is obsolete: true
Attachment #8384493 - Flags: review?(fred.wang)
whitespace fixes for the lines touched by my code.
Attachment #8380339 - Attachment is obsolete: true
Attachment #8380339 - Flags: review?(roc)
Attachment #8384504 - Flags: review?(roc)
(In reply to James Kitchener (:jkitch) from comment #17)
> My understanding is that two accomplish different things.  In the attached
> diagram:
> 
> left example sets mtd {padding:5px;}
> middle example sets mtable {border-spacing:5px} mtd{padding:0px;}
> right example sets rowspacing="5px 20px" columnspacing="5px 20px"
> framespacing="5px 5px" (using the patches from this bug)
> 
> padding adds the space inside the table cells, which are then placed
> touching each other, resulting in a solid block of red.
> border-spacing leaves 5px of white between the cells, resulting in a
> windowpane effect.
> rowspacing/columnspacing is similar to the border-spacing example, except
> different spaces can be specified.
> 
> Now I am not an expert in CSS, so the third example might still be
> replicable by other means but it may not be a simple process.

I think it could be done using invisible, collapsing borders. Could MathJax use that?

(In reply to Frédéric Wang (:fredw) from comment #18)
> One thing to consider is that in practice we are bit constrained by the
> current status of math:
> 
> 1) LaTeX is the de facto standard. And in LaTeX we put all the table
> formatting as an argument of the environment command  that generates the
> table. So it's a bit tedious for LaTeX-to-MathML converters to have to move
> all this formating to cell nodes, especially when they are fast stream
> filter like itex2MML where you are essentially handling a MathML string not
> a DOM tree. That's why LaTeX-to-MathML converters use
> columnspacing/rowspacing and the other alignment attributes already
> implemented.

If I'm right that we could use borders, then you could emit a scoped style sheet and give the cells classes corresponding to row and column numbers to get the streaming behavior.

> 2) MathML is still used in environment where CSS is not available. Or in
> polyfills like MathJax that don't work well with CSS. In particular,
> Wikipedia will rely on MathJax to do server-side LaTeX-to-MathML conversion
> and thus the MathML output served will contain columnspacing/rowspacing.

I don't like making browser design decisions driven by the needs of platforms where CSS isn't available. This happened in SVG for a long time and it forced duplication of functionality that ended up being pointless since all non-CSS-capable SVG viewers died out.

I'm not totally opposed to taking these patches but we have to consider the costs and benefits --- and alternatives --- carefully.

dbaron might have an opinion.
Flags: needinfo?(dbaron)
(In reply to Robert O'Callahan (:roc) (Mozilla Corporation) from comment #35)
> I don't like making browser design decisions driven by the needs of
> platforms where CSS isn't available. This happened in SVG for a long time
> and it forced duplication of functionality that ended up being pointless
> since all non-CSS-capable SVG viewers died out.

Actually this isn't completely true, but it's true enough that we stopped caring about non-CSS-capable SVG viewers.
(In reply to Robert O'Callahan (:roc) (Mozilla Corporation) from comment #35)
> I don't like making browser design decisions driven by the needs of
> platforms where CSS isn't available. This happened in SVG for a long time
> and it forced duplication of functionality that ended up being pointless
> since all non-CSS-capable SVG viewers died out.

Note that one option is that MathJax produces output containing both the attributes and the CSS, and we make sure that UAs support one or the other but not both.
(In reply to Frédéric Wang (:fredw) from comment #27)
> OK, change sounds good. I'm expecting that specifiying no attributes behaves
> the same as the default MathML values. Do you know why it is not working in
> RTL mode and why your previous patch fixed that?

The problem lies in CSS.
>mtd:first-child {
>  padding-left: 0em;
>}

With dir=rtl this selects the rightmost mtd, rather than the leftmost, so the padding is removed from the wrong side.
(In reply to James Kitchener (:jkitch) from comment #38)
> The problem lies in CSS.
> >mtd:first-child {
> >  padding-left: 0em;
> >}
> 
> With dir=rtl this selects the rightmost mtd, rather than the leftmost, so
> the padding is removed from the wrong side.

OK, thanks that makes sense. Can you please try to use -moz-padding-start/-moz-padding-end/-moz-margin-start/-moz-margin-end instead?
(In reply to Frédéric Wang (:fredw) from comment #39)
> (In reply to James Kitchener (:jkitch) from comment #38)
> > The problem lies in CSS.
> > >mtd:first-child {
> > >  padding-left: 0em;
> > >}
> > 
> > With dir=rtl this selects the rightmost mtd, rather than the leftmost, so
> > the padding is removed from the wrong side.
> 
> OK, thanks that makes sense. Can you please try to use
> -moz-padding-start/-moz-padding-end/-moz-margin-start/-moz-margin-end
> instead?

Sorry, I just realized that the problem is with the :first-child selector...

(this seems to be one more complication for MathML generators that would like to use CSS instead of rowspacing etc)
(In reply to Frédéric Wang (:fredw) from comment #40)
> (In reply to Frédéric Wang (:fredw) from comment #39)
> > (In reply to James Kitchener (:jkitch) from comment #38)
> > > The problem lies in CSS.
> > > >mtd:first-child {
> > > >  padding-left: 0em;
> > > >}
> > > 
> > > With dir=rtl this selects the rightmost mtd, rather than the leftmost, so
> > > the padding is removed from the wrong side.
> > 
> > OK, thanks that makes sense. Can you please try to use
> > -moz-padding-start/-moz-padding-end/-moz-margin-start/-moz-margin-end
> > instead?
> 
> Sorry, I just realized that the problem is with the :first-child selector...
> 
> (this seems to be one more complication for MathML generators that would
> like to use CSS instead of rowspacing etc)

Actually it works.  It is a neater solution than relying on :-moz-dir(rtl), which doesn't actually work for MathML due to the way the dir attribute is implemented.
(In reply to Robert O'Callahan (:roc) (Mozilla Corporation) from comment #35)
> I think it could be done using invisible, collapsing borders. Could MathJax
> use that?
> 

One potential issue is the rowlines and columnlines attributes.  These draw lines between the cells and are currently implemented by us and Webkit by selectively applying table borders.

To handle both rowspacing and rowlines with the same border mechanism would require specifying a border that is mostly invisible but has a solid or dashed line in a different colour along one edge.
Note: I agree with Robert that in general we should try to reuse CSS when possible and deprecate MathML features that do not work well with the CSS layout (that was one of the motivation to limit the mstyle support btw). However, in this particular case:

a) I have not really studied whether it will be easy/possible to implement that with CSS properties only.

b) I'm not sure it will be convenient to handle for MathML generators. I don't understand the "scoped style sheet" since the generators can e.g. just return a <math>...</math> string not a whole HTML document. Also, the style will be lost by copy and paste of the equation, if it is not done by inline style="" attributes. Even if we do that with such attributes, that would make things difficult for stream converters.

c) in the short term I think we want to align on what MathJax and current tools do. If a) is not a problem, then in the long term we could either ask to change the spec or try to emulate the specific MathML table layout internally with some Web Components that would automatically do the CSS mapping.

Currently, the MathJax native MathML mode has some workaround for rowspacing/columnspacing that adds some CSS style but I'm not sure it always works well (in particular with the rowline/columnline attributes mentioned by James). This CSS style is added neither by MathJax in the SVG/HTML modes nor by the LaTeX-to-MathML server-side conversion that will be used in Wikipedia. If MathJax is changed to add these style in these modes too, I suspect it will conflict with MathJax's own table layout (which does not rely on the built-in CSS table layout). I'm not even sure the MathJax team will agree to modify the preprocessing to always/conditionally add these CSS rules. Finally, we want these attributes to work in other situations and tools where MathJax is not involved.

So at the moment, James' patch seems the best (or least bad) option to me. We already have similar things for rowalign/columnalign, except that here it modifies more things outside the MathML code.
(In reply to Frédéric Wang (:fredw) from comment #43)
> a) I have not really studied whether it will be easy/possible to implement
> that with CSS properties only.

I think we should study that!

If it's hard, I don't mind taking these patches. But if it's easy, I don't think we should take these patches.

> b) I'm not sure it will be convenient to handle for MathML generators. I
> don't understand the "scoped style sheet" since the generators can e.g. just
> return a <math>...</math> string not a whole HTML document. Also, the style
> will be lost by copy and paste of the equation, if it is not done by inline
> style="" attributes. Even if we do that with such attributes, that would
> make things difficult for stream converters.

You can write
  <mtable>
    <style scoped>
      // style rules that only match the descendants of *this* mtable
    </style>
  </mtable>

> c) in the short term I think we want to align on what MathJax and current
> tools do. If a) is not a problem, then in the long term we could either ask
> to change the spec or try to emulate the specific MathML table layout
> internally with some Web Components that would automatically do the CSS
> mapping.

We really don't want to add any Web-exposed features as a short-term solution to anything. They will live forever.

> Currently, the MathJax native MathML mode has some workaround for
> rowspacing/columnspacing that adds some CSS style but I'm not sure it always
> works well (in particular with the rowline/columnline attributes mentioned
> by James). This CSS style is added neither by MathJax in the SVG/HTML modes
> nor by the LaTeX-to-MathML server-side conversion that will be used in
> Wikipedia. If MathJax is changed to add these style in these modes too, I
> suspect it will conflict with MathJax's own table layout (which does not
> rely on the built-in CSS table layout). I'm not even sure the MathJax team
> will agree to modify the preprocessing to always/conditionally add these CSS
> rules. Finally, we want these attributes to work in other situations and
> tools where MathJax is not involved.

I don't understand this. It seems much preferable to change MathJax and other "situations and tools" for MathML than to add unnecessary features to the Web platform.
>I don't understand this. It seems much preferable to change MathJax and other "situations and tools" for MathML than to add unnecessary features to the Web platform.

If I may say so, I find this a little confusing.

The MathML Specification specifies certain attributes for the <mtable> elements which are not currently implemented in Gecko. The same effect (you say) can be achieved by judicious use of the HTML5 feature, <style scoped>. So, rather than Gecko implementing these attributes, tools which generate MathML should be changed to emit HTML5 <style scoped> elements, instead.

As the author of such a tool, this makes no sense to me. I strive to produce valid MathML3 output, and <style scoped> is certainly not part of MathML3. If you want to lobby the MathML WG to make <style scoped> part of MathML4, be my guest. But it doesn't seem to make sense to expect MathML generators to start emitting random snippets of HTML5, just because you don't like the MathML Spec, as currently written.
We don't look at the Web platform as an amalgam of many pieces that each need to be useful independently. That kind of thinking leads to duplication of functionality across those pieces. Therefore, where MathML specs introduce features that duplicate functionality available in other parts of the Web platform, I don't think those features should be implemented in any Web browser, and ideally they'd be removed from the spec.

Having said that, I agree it's unclear that rowspacing/columnspacing/framespacing should be considered to "duplicate" <style scoped> plus some judiciously chosen CSS rules.
To add some input here, I just checked a few of the tools mentioned on https://developer.mozilla.org/en-US/docs/Web/MathML/Authoring:

- MathJax relies heavily on rowspacing/columnspacing. In particular Mathoid (server-side MathJax) will be used for native MathML on MediaWiki-based wikis.

- The two main LaTeX-to-(HTML+MathML) converters LaTeXML and tex4ht also use these attributes.

- For simple LaTeX-to-MathML converters: itex2MML, TeXZilla (intended to be used in Mozilla products and that we already integrated into MDN, Seamonkey, FirefoxOS and hopefully soon Thunderbird after bug 992127) and BlahTeX rely on these attributes too (actually this bug is mentioned in BlahTeX source code).

Of course, there are tons of such MathML generators and many others probably use these rowspacing/columnspacing attributes. Also, we have supported the similar rowalign/columnalign attributes for a very long time (probably since the first years of the MathML implementation?) and these align attributes are also used in the tools above as well as others (for example LibreOffice Math). So it seems consistent to implement rowspacing/columnspacing too.

So I would personally vote for taking this patch, because the fact that it is already used in practice by many tools and addresses some need seems more important that the potential theorically unpleasing feature duplication.
Comment on attachment 8384504 [details] [diff] [review]
Part1: Add arguments to GetCellSpacing[XY]

Review of attachment 8384504 [details] [diff] [review]:
-----------------------------------------------------------------

::: layout/tables/nsTableCellFrame.cpp
@@ +815,5 @@
>    int32_t rowIndex;
>    firstCellInFlow->GetRowIndex(rowIndex);
>    int32_t rowSpan = aTableFrame.GetEffectiveRowSpan(*firstCellInFlow);
> +  nscoord cellSpacing = firstTableInFlow->GetCellSpacingY(rowIndex,
> +                                                          rowIndex + rowSpan - 1);

This doesn't seem right. if rowSpan is 1 then cellSpacing will be 0, which is a change in behavior.

::: layout/tables/nsTableFrame.cpp
@@ +3413,5 @@
> +  NS_ASSERTION(aStartColIndex <= aEndColIndex,
> +               "End index must not be less than start index");
> +  // Just pick one and multiply it out.  Tables where index matters will
> +  // override this function
> +  return GetCellSpacingX(0) * (aEndColIndex - aStartColIndex);

To be slightly more efficient here, have nsTableFrame implement a private, non-virtual GetCellSpacingX() with no parameters, and call it from here and from GetCellSpacingX(int32_t).

Same for GetCellSpacingY.

::: layout/tables/nsTableRowGroupFrame.cpp
@@ +1523,5 @@
>      }
>      if (parentRS && (tableFrame == parentRS->frame) && 
>          (parentRS->ComputedHeight() > 0) && (parentRS->ComputedHeight() < NS_UNCONSTRAINEDSIZE)) {
> +      nscoord cellSpacing =
> +        tableFrame->GetCellSpacingY(-1, std::max(-1, tableFrame->GetRowCount()));

This seems incorrect. startRowIndex should be used.

Also, presumably the std::max here should just be removed.
Attachment #8384504 - Flags: review?(roc) → review-
Attached patch Part 2: MathML mtable changes (obsolete) — Splinter Review
rebased
Attachment #8384500 - Attachment is obsolete: true
Attached patch Part 3: tests (obsolete) — Splinter Review
rebased
Attachment #8384498 - Attachment is obsolete: true
(In reply to Robert O'Callahan (:roc) (Mozilla Corporation) from comment #49)
> Comment on attachment 8384504 [details] [diff] [review]
> Part1: Add arguments to GetCellSpacing[XY]
> 
> Review of attachment 8384504 [details] [diff] [review]:
> -----------------------------------------------------------------
> 
> ::: layout/tables/nsTableCellFrame.cpp
> @@ +815,5 @@
> >    int32_t rowIndex;
> >    firstCellInFlow->GetRowIndex(rowIndex);
> >    int32_t rowSpan = aTableFrame.GetEffectiveRowSpan(*firstCellInFlow);
> > +  nscoord cellSpacing = firstTableInFlow->GetCellSpacingY(rowIndex,
> > +                                                          rowIndex + rowSpan - 1);
> 
> This doesn't seem right. if rowSpan is 1 then cellSpacing will be 0, which
> is a change in behavior.
> 

The use of (rowspan - 1) was the original behaviour.

> nscoord computedHeight = ((rowSpan - 1) * cellSpacing) - aVerticalBorderPadding;

According to the comments, CalcUnpaginagedHeight excludes border and padding from the calculated height, so a 0 cellspacing contribution for a rowspan of 1 seems reasonable.

> ::: layout/tables/nsTableFrame.cpp
> @@ +3413,5 @@
> > +  NS_ASSERTION(aStartColIndex <= aEndColIndex,
> > +               "End index must not be less than start index");
> > +  // Just pick one and multiply it out.  Tables where index matters will
> > +  // override this function
> > +  return GetCellSpacingX(0) * (aEndColIndex - aStartColIndex);
> 
> To be slightly more efficient here, have nsTableFrame implement a private,
> non-virtual GetCellSpacingX() with no parameters, and call it from here and
> from GetCellSpacingX(int32_t).
> 
> Same for GetCellSpacingY.
> 

Done.

> ::: layout/tables/nsTableRowGroupFrame.cpp
> @@ +1523,5 @@
> >      }
> >      if (parentRS && (tableFrame == parentRS->frame) && 
> >          (parentRS->ComputedHeight() > 0) && (parentRS->ComputedHeight() < NS_UNCONSTRAINEDSIZE)) {
> > +      nscoord cellSpacing =
> > +        tableFrame->GetCellSpacingY(-1, std::max(-1, tableFrame->GetRowCount()));
> 
> This seems incorrect. startRowIndex should be used.
> 

The code before modification calculates the total cellspacing for (tableFrame->GetRowCount() + 1) rows which I interpret as the entire table and the top and bottom borders.  I do not see how startRowIndex can be incorporated without 
a) changing the number of rows considered
or
b) or adding an offset which will mean considering the cell spacing of rows that do not exist.  

> Also, presumably the std::max here should just be removed.

Done.  There is now an assumption that the table has at least one row, but if that wasn't the case, how does the table have a non-zero height?
Attachment #8380338 - Attachment is obsolete: true
Attachment #8439912 - Flags: review?(roc)
Attachment #8439912 - Attachment description: Part 0: Fix to CalcUnpaginagedHeight → Part1: Add arguments to GetCellSpacing[XY]
Comment on attachment 8380338 [details] [diff] [review]
Part 0: Fix to CalcUnpaginagedHeight

obsoleted wrong patch
Attachment #8380338 - Attachment is obsolete: false
Attachment #8384504 - Attachment is obsolete: true
Comment on attachment 8439912 [details] [diff] [review]
Part1: Add arguments to GetCellSpacing[XY]

Review of attachment 8439912 [details] [diff] [review]:
-----------------------------------------------------------------

::: layout/tables/nsTableFrame.h
@@ +380,5 @@
> +   */
> +  virtual nscoord GetCellSpacingX(int32_t aColIndex);
> +
> +  /** Sums the combined cell spacing between the columns aStartColIndex to
> +   *  aEndColIndex.

This comment needs to clarify exactly which cells' spacing is included.

@@ +392,5 @@
> +   */
> +  virtual nscoord GetCellSpacingY(int32_t aRowIndex);
> +
> +  /** Sums the combined cell spacing between the rows aStartRowIndex to
> +   *  aEndRowIndex.

ditto
Attachment #8439912 - Flags: review?(roc) → review+
Flags: needinfo?(dbaron)
Keywords: helpwanted
Whiteboard: [mentor=fredw][lang=c++][see comment 8 if you want to work on this]
Comments added
Attachment #8439912 - Attachment is obsolete: true
Attached patch Part 2: MathML mtable changes (obsolete) — Splinter Review
Performance improvement for the two argument versions of GetCellSpacing[XY].

Beforehand it would iterate over every row/column specified by the arguments, calling the single argument version each time.

However as the length of the array of user specified row/column spacings is known, it is only necessary to iterate up to that length.  The remaining range can simply be multiplied by the last element in the array and added to the total.

For larger mtables this could save hundreds of virtual method calls.
Attachment #8439828 - Attachment is obsolete: true
Attachment #8440372 - Flags: review?(fred.wang)
Attached patch Part 3: tests (obsolete) — Splinter Review
The Mochitest now supports HiDPI displays
Attachment #8439830 - Attachment is obsolete: true
Comment on attachment 8440372 [details] [diff] [review]
Part 2: MathML mtable changes

Review of attachment 8440372 [details] [diff] [review]:
-----------------------------------------------------------------

::: layout/mathml/nsMathMLmtableFrame.cpp
@@ +262,5 @@
> +    overflow.bottom = mathMLmtableFrame->GetCellSpacingY(rowIndex)/2;
> +  }
> +  return overflow;
> +}
> +

Can you keep consistent spacing around / + - operators?

@@ +545,5 @@
>    // Map mtable columnalign & columnlines.
>    ParseFrameAttribute(aTableFrame, nsGkAtoms::columnalign_, true);
>    ParseFrameAttribute(aTableFrame, nsGkAtoms::columnlines_, true);
>  
> +  ParseSpacingAttributes(aTableFrame);

For consistency, can you add a comment

// Map mtable rowspacing, columnspacing & framespacing

please?
Attachment #8440372 - Flags: review?(fred.wang) → review+
Comment on attachment 8440373 [details] [diff] [review]
Part 3: tests

Review of attachment 8440373 [details] [diff] [review]:
-----------------------------------------------------------------

OK, I see you only introduced a small error tolerance.
Attachment #8440373 - Flags: review+
Attached patch Part 2: MathML mtable changes (obsolete) — Splinter Review
Attachment #8440372 - Attachment is obsolete: true
Try run:
https://tbpl.mozilla.org/?tree=Try&rev=b252cefa378e

One OOM related orange that as far as I can tell isn't caused by these changes, and wasn't present when the run was retriggered.
Keywords: checkin-needed
sorry had to backout this changes for test failures like https://tbpl.mozilla.org/php/getParsedLog.php?id=41782155&tree=Mozilla-Inbound
Is it just me or does that log make no sense as the numbering of differing pixels is way less than the max number.  How can this be a failure????
IIUC "max difference: 220" means that the difference in at least one color channel on at least one pixel is 220.
tablespacing-4.html turns out to be an existing bug.
https://tbpl.mozilla.org/?tree=Try&rev=a0d517965eed

Most of the existing mtable tests are marked random-if(B2G&&browserIsRemote).  Could this be the same issue?
Attached patch Part 4: Flag failing tests (obsolete) — Splinter Review
Looking over the MathML reftest.list, it seems that B2G has a problem with dynamic tests.  This patch adds another four to the list of failing tests.

The tests in question involve the addition and removal of table cells (4) and modification to the spacing between table elements (5, 5a, 6).  tablespacing-4 exhibits the same failure mode with and without patches 0-2 applied.

Do these tests failures need to be fixed before this can land, or are they part of some larger known issue with B2G?
Attachment #8441346 - Flags: review?(karlt)
Comment on attachment 8441346 [details] [diff] [review]
Part 4:  Flag failing tests

Yes, this is most likely a separate existing bug.  It is not necessarily (and most likely not, given code is the same) a B2G-only problem but timing may happen to be different there.  It need not hold up landing the changes here.

Are the failures really random?
It would be better to mark them fails-if if they fail consistently, so we can enable the tests when they are fixed.

If they are random, then they may start randomly failing elsewhere too, but we can see how they go and annotate later if necessary.
Attachment #8441346 - Flags: review?(karlt) → review+
rebased
Attachment #8440371 - Attachment is obsolete: true
Attached patch Part 3: testsSplinter Review
Forget to add a test to the reftest index.
Attachment #8440373 - Attachment is obsolete: true
The tests haven't passed in ~20 attempts (try/inbound), so marking as fails-if
Attachment #8441346 - Attachment is obsolete: true
Try run:
https://tbpl.mozilla.org/?tree=Try&rev=e577ef073ba4

I couldn't find anything that could be attributed to these changes.

Please apply patches in numerical order.
Keywords: checkin-needed
A few whitespace changes per comment 58 that were missed earlier.
Attachment #8440395 - Attachment is obsolete: true
Should this have had an Intent to Implement?
Flags: needinfo?(jkitch.bug)
(In reply to :Ms2ger from comment #75)
> Should this have had an Intent to Implement?

Deferring to someone more senior.
Flags: needinfo?(jkitch.bug) → needinfo?(karlt)
Flags: needinfo?(karlt) → needinfo?(roc)
Yes, I suppose it should have.
Flags: needinfo?(roc)
Depends on: 1031934
For some reason, I can not edit the MDN page right now (js error in ckeditor?), but the MathML status page should also be updated:

https://developer.mozilla.org/en-US/docs/Mozilla/MathML_Project/Status
Frédéric: thanks, updated.
Depends on: 1061027
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: