Open Bug 733849 Opened 13 years ago Updated 4 months ago

preserve-3d isn't handled right on tables

Categories

(Core :: CSS Parsing and Computation, defect)

x86
Linux
defect

Tracking

()

People

(Reporter: ayg, Unassigned)

References

(Blocks 2 open bugs)

Details

(Keywords: parity-chrome, parity-safari)

Attachments

(3 files)

Context: https://www.w3.org/Bugs/Public/show_bug.cgi?id=15943

Test-cases:

data:text/html,<!doctype html>
<div style="-moz-transform: rotatex(90deg); -moz-transform-style: preserve-3d">
  <table style="-moz-transform-style: preserve-3d">
    <tbody style="-moz-transform-style: preserve-3d">
      <tr style="-moz-transform-style: preserve-3d">
        <td style="-moz-transform-style: preserve-3d">
          <div style="-moz-transform: rotatex(90deg)">Some text</div>
  </table>
</div>

data:text/html,<!doctype html>
<div style="-moz-transform: rotatex(90deg); -moz-transform-style: preserve-3d">
  <div style="display: table; -moz-transform-style: preserve-3d">
    <div style="display: table-row; -moz-transform-style: preserve-3d">
      <div style="display: table-cell; -moz-transform-style: preserve-3d">
        <div style="-moz-transform: rotatex(90deg)">Some text</div>
      </div>
    </div>
  </div>
</div>

data:text/html,<!doctype html>
<div style="-moz-transform: rotatex(90deg); -moz-transform-style: preserve-3d">
  <div style="display: table-cell; -moz-transform-style: preserve-3d">
    <div style="-moz-transform: rotatex(90deg)">Some text</div>
  </div>
</div>

In all three cases, Gecko displays nothing.  This is presumably because there are anonymous frames inserted at various points that have the default -moz-transform-style of "flat", and should instead have -moz-transform-style: inherit.

I should be able to write a patch for this if someone can give me some pointers.  How do I distinguish anonymous table frames from regular ones, in ua.css or wherever would be appropriate?
The only anonymous box in that first testcase is the ::-moz-cell-content, right?  does adding a style for that to ua.css help?

In general, should we be looking at the moz-transform-style on the style parent instead of on the frame tree parent?  How does the spec define this?  It matters for the third testcase, in which CSS2.1 actually requires anonymous boxes.
Oh, and in general the anonymous table frames use the various anon box styles in ua.css: ::-moz-table, ::-moz-inline-table, ::-moz-table-row-group, ::-moz-table-row, ::-moz-table-cell.

But before we start changing all of those, I'd really like to understand what behavior the spec actually calls for.
The spec says:

"""
Elements establish and participate in 3D rendering contexts as follows:

* A 3D rendering context is established by a a transformable element whose computed value for ‘transform-style’ is ‘preserve-3d’, and which itself is not part of a 3D rendering context. Note that such an element is always a containing block. An element that establishes a 3D rendering context also participates in that context.

* An element whose computed value for ‘transform-style’ is ‘preserve-3d’, and which itself participates in a 3D rendering context, extends that 3D rendering context rather than establishing a new one.

* An element participates in a 3D rendering context if its containing block establishes or extends a 3D rendering context.
"""
http://dev.w3.org/csswg/css3-transforms/#transform-3d-rendering

So it actually doesn't define anything for boxes that don't come from elements, read literally.  Probably the third bullet point should be changed from "An element" to "A block" or "A box" or similar.  Do you have wording suggestions?  I do think the intent is that any boxes that don't correspond to elements should inherit the transform-style of the nearest element ancestor.
> * A 3D rendering context is established by a a transformable element

Table rows and row groups and cells don't seem to be transformable elements per sper, right?

> Note that such an element is always a containing block.

Which I believe table rows and row groups at least are not.  The situation for cells is a bit vague.

> * An element participates in a 3D rendering context if its containing block establishes
> or extends a 3D rendering context.

OK, so this says one should be looking at containing blocks... of course a containing block is a rectangle, not an element, so this part is somewhat nonsensical.

> Do you have wording suggestions? 

That kind of depends on the desired behavior, no?  I haven't looked at how 3d transforms work at enough length to comment on that...

One thing: boxes don't have styles in CSS.  Elements have styles.  Does that help anything?
(In reply to Boris Zbarsky (:bz) from comment #4)
> Table rows and row groups and cells don't seem to be transformable elements
> per sper, right?

It says block-level or atomic inline-level, so that's what the spec claims, yeah.  That seems like a spec bug.  Transformable CSS2.1 display types seem to be, ignoring table-column(-group):

Spec: block, list-item, inline-block, table, inline-table; plus inline if replaced
IE 10 Developer Preview: spec plus table-caption, table-cell, and all inline (everything except table-*-group and table-row)
Gecko: spec plus table-* (everything except non-replaced inline)
Chrome 19 dev: spec plus table-* (everything except non-replaced inline)
Opera Next 12.00 alpha: spec plus table-caption and all inline

It seems like the spec should be updated to match Gecko/WebKit.  I filed a bug: https://www.w3.org/Bugs/Public/show_bug.cgi?id=16326

> Which I believe table rows and row groups at least are not.  The situation
> for cells is a bit vague.
>
> . . .
> 
> OK, so this says one should be looking at containing blocks... of course a
> containing block is a rectangle, not an element, so this part is somewhat
> nonsensical.

So maybe we want to change the definition of "transformable element" to include table-* (except table-column and table-column-group), and then change the steps I quoted above to say:

"""
Elements establish and participate in 3D rendering contexts as follows:

* If a transformable element's computed value for 'transform-style' is 'preserve-3d', and either its parent is not transformable or its parent's 'transform-style' computes to 'flat', it establishes a new 3D rendering context and participates in that context.

* If a transformable element's parent is transformable, and its parent's 'transform-style' computes to 'preserve-3d', it participates in the same 3D rendering context as its parent.

* If an element is not transformable, or its 'transform-style' and its parent's both compute to 'flat', or its 'transform-style' computes to 'flat' and its parent is not transformable, it does not participate in any 3D rendering context.
"""

How does that sound?
How do you want things to behave when absolutely positioned elemnets are involved?  Given this markup:

  <div style="position: relative">
    <p>
      <span style="position: absolute">
      </span>
    </p>
  </div>

and the <div> and <span> have "transform-style: preserve-3d" while the <p> has "transform-style: flat", does the <span> establish a new 3d rendering context?  In your proposed wording, it does.  I _think_ the intent of the current spec is that it not do so... maybe.

Quite apart from that, by the way, it seems like the behavior, if I understand things at all correctly, would be saner if transform-style were 'preserve-3d' by default.  But maybe that ship has sailed....
(In reply to Boris Zbarsky (:bz) from comment #6)
> How do you want things to behave when absolutely positioned elemnets are
> involved?  Given this markup:
> 
>   <div style="position: relative">
>     <p>
>       <span style="position: absolute">
>       </span>
>     </p>
>   </div>
> 
> and the <div> and <span> have "transform-style: preserve-3d" while the <p>
> has "transform-style: flat", does the <span> establish a new 3d rendering
> context?  In your proposed wording, it does.  I _think_ the intent of the
> current spec is that it not do so... maybe.

Yeah, the WebKit versions that I tested in seem to not establish a new 3D rendering context here.  Same for Gecko.  That seems overly complicated, though.

I filed a spec bug: https://www.w3.org/Bugs/Public/show_bug.cgi?id=16328

> Quite apart from that, by the way, it seems like the behavior, if I
> understand things at all correctly, would be saner if transform-style were
> 'preserve-3d' by default.  But maybe that ship has sailed....

I thought so too, but it turns out that wouldn't be a great idea.  See <http://lists.w3.org/Archives/Public/www-style/2012Feb/0291.html>.  It's a pretty long discussion.  I don't like the status quo, but I can't think of anything clearly better -- particularly not better enough to change both WebKit and Gecko.
Unfortunately, I can confirm that bug related to 3d transforms and table rendering still exists (both Firefox 47 stable and Firefox 50 nightly on Windows 7 x64).

I tried to emulate "fixed table header" pattern with the pure CSS parallax effect: http://codepen.io/SelenIT/pen/pbAzxb. It consistently applies the 3d transform to the `thead` element in Chromium-based browsers, but in Firefox there seems to be something between the container with `perspective` and the `thead` element with `transform` (maybe the table wrapper object or `table` element itself?) that breaks the perspective. Setting explicit `transform-style: preserve-3d` for the `table` doesn't help anything.
Attached file testcase 1

For convenience, I'm attaching copies of the three testcases from comment 0, as actual attachments for easy clickability (and with the -moz prefixes removed).

Attached file testcase 2
Attached file testcase 3
Severity: minor → S4

After checking the frame tree by using the wpt, transform-table-009.html:

TableWrapper(table id=t)(1)@107a4ac00 parent=107a4ab38 (x=0, y=0, w=6360, h=6360) ink-overflow=(x=0, y=0, w=0, h=0) scr-overflow=(x=0, y=0, w=0, h=0) transformed combines-3d-transform-with-ancestors [content=10cc18220] [cs=10c3b56c8:-moz-table-wrapper]
    Table(table id=t)(1)@107a4acb0 parent=107a4ac00 (x=0, y=0, w=6360, h=6360) [content=10cc18220] [cs=10c3b5038]
        TableRowGroup(tbody)(1)@107a4ade0 parent=107a4acb0 (x=120, y=120, w=6120, h=6120) pre-transform-ink-overflow=(x=0, y=0, w=6120, h=6120) pre-transform-scr-overflow=(x=0, y=0, w=6120, h=6120) transformed extend-3d [content=10cc0d6f0] [cs=10c3b5128]
            TableRow(tr)(1)@107a4ae90 parent=107a4ade0 (x=0, y=0, w=6120, h=6120) ink-overflow=(x=0, y=0, w=0, h=0) scr-overflow=(x=0, y=0, w=0, h=0) transformed extend-3d combines-3d-transform-with-ancestors [content=10cc0d780] [cs=10c3b5218]
                TableCell(td)(1)@107a4af58 parent=107a4ae90 (x=0, y=0, w=6120, h=6120) ink-overflow=(x=0, y=0, w=0, h=0) scr-overflow=(x=0, y=0, w=0, h=0) transformed extend-3d combines-3d-transform-with-ancestors [content=10cc0d810] [cs=10c3b5308]
                    Block(td)(1)@107a4b020 parent=107a4af58 (x=60, y=60, w=6000, h=6000) [content=10cc0d810] [cs=10c3b5a88:-moz-cell-content] < line@107a4b1b0 count=1 state=block,clean,prevmarginclean,not-impacted,not-wrapped,no-break,clear-before:none,clear-after:none(x=0, y=0, w=6000, h=6000) ink-overflow=(x=0, y=0, w=0, h=0) scr-overflow=(x=0, y=0, w=0, h=0)
                        Block(div)(0)@107a4b0e8 parent=107a4b020 (x=0, y=0, w=6000, h=6000) ink-overflow=(x=0, y=0, w=0, h=0) scr-overflow=(x=0, y=0, w=0, h=0) transformed combines-3d-transform-with-ancestors [content=10cc0d8a0] [cs=10c3b53f8]

It seems like we have an extra Block(td) frame between TableCell(td) and Block(div), but it doesn't have transformed extend-3d combines-3d-transform-with-ancestors. This means that its nsIFrame::Extend3DContext() is false, and I suspect it may be the root cause which breaks the chain of preserved-3d in this test.

Note: same for Table frame. Need to figure out what happen there for preserve-3d

We might want transform-style: inherit on the corresponding table parts in ua.css. (That seems to be what the end of comment 0 and comment 1 are suggesting).

It looks like we used to have that for the -moz-table-wrapper box, but that got reverted (commented out) in bug 1560704. But per bug 1560704 comment 10, it looks like we weren't sure that we really wanted to keep that fix, and the root cause there might really have been somewhere else.

See Also: → 1560704

Yes, adding transform-style: inherit into -moz-table-wrapper makes everything disappear. And got an assertion if I add transform-style: inherit into -moz-cell-content.

One thing to note: WebKit may also have something wrong in the similar cases. It doesn't pass the wpt, and have some strange behaviors if we use rotateX(90deg) in the outer div. (Not sure what happens. It looks like Gecko has the similar behavior, so I have to tweak the test to make sure the combined rotateX is less than 90deg.)

Besides, in the frame tree, I notice TableRowGroup(tbody) doesn't have combines-3d-transform-with-ancestors. This may be a hint that it doesn't combine its 3d context with its ancestor. (So I tried to move the outer rotateX() from outer div into tbody. Well, the result becomes correct, if the combined rotation is less than 90deg.) Need to dig deeper anyway.

Duplicate of this bug: 928322

So looks like preserve-3d on <table> or <div style="display: table;"></div> doesn't take effect.

mTransformStyle of nsTableWrapperFrame is always flat even if we set transform-style: preserve-3d to table element.

e.g. we can simplify these failed test cases to this one:

<style>
#outer {
  transform-style: preserve-3d;
  transform: rotateY(30deg);
  display: table;
}
#target {
  width: 100px;
  height: 100px;
  background: green;
  transform: rotateX(30deg);
}
</style>
<div id=outer>
  <div id=target></div>
</div>

And Gecko doesn't render target and outer in the same 3D space.

I tried to hack nsIFrame::Extend3DContext() to make it always return true for nsTableWrapperFrame, but the elements inside the table disappears. :( (It's bug 1560704)

Note: The reason that we failed the test which uses display: table-cell in css/css-transforms/transform-table-011.html may be another bug. That happens when using rotateX(90deg) in the outer div. (If we change it to other values, e.g. 80deg or 100deg, our behavior is the same as Blink.)

The severity field for this bug is set to S4. However, the following bug duplicate has higher severity:

:emilio, could you consider increasing the severity of this bug to S3?

For more information, please visit BugBot documentation.

Flags: needinfo?(emilio)
Severity: S4 → S3
Flags: needinfo?(emilio)
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: