Bug 103477

Summary: Make NodeRenderingContext::parentRenderer and nextRenderer top layer aware
Product: WebKit Reporter: Elliott Sprehn <esprehn>
Component: New BugsAssignee: Elliott Sprehn <esprehn>
Status: RESOLVED FIXED    
Severity: Normal CC: dbates, dglazkov, eric, falken, jchaffraix, koivisto, morrita, ojan.autocc, ojan, simon.fraser, stearns, webkit.review.bot
Priority: P2    
Version: 528+ (Nightly build)   
Hardware: Unspecified   
OS: Unspecified   
Attachments:
Description Flags
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch none

Description Elliott Sprehn 2012-11-27 19:15:55 PST
Make NodeRenderingContext::parentRenderer and nextRenderer htop layer aware
Comment 1 Elliott Sprehn 2012-11-27 19:28:34 PST
Created attachment 176385 [details]
Patch
Comment 2 Elliott Sprehn 2012-11-27 19:32:40 PST
Created attachment 176386 [details]
Patch
Comment 3 WebKit Review Bot 2012-11-27 20:18:37 PST
Comment on attachment 176386 [details]
Patch

Attachment 176386 [details] did not pass chromium-ews (chromium-xvfb):
Output: http://queues.webkit.org/results/15013319

New failing tests:
fast/dom/HTMLDialogElement/top-layer-display-none.html
fast/dom/HTMLDialogElement/top-layer-nesting.html
Comment 4 Elliott Sprehn 2012-11-27 21:34:57 PST
Created attachment 176395 [details]
Patch
Comment 5 Elliott Sprehn 2012-11-27 21:37:25 PST
(In reply to comment #4)
> Created an attachment (id=176395) [details]
> Patch

I fixed the brokenness but it seems there's much worse badness in top layer and flow threads and renderer hoisting since we do the normal parent renderer checks which seem wrong. :/

In general renderer hoisting seems to be very error prone, there's lots of oversights in the code.
Comment 6 Julien Chaffraix 2012-11-28 11:09:52 PST
Comment on attachment 176395 [details]
Patch

I really don't see the point of this change. You are peppering the knowledge of top layer elements all over NodeRenderingContext for no good reason I could see. Could you clarify what's the intent?
Comment 7 Elliott Sprehn 2012-11-28 11:23:05 PST
(In reply to comment #6)
> (From update of attachment 176395 [details])
> I really don't see the point of this change. You are peppering the knowledge of top layer elements all over NodeRenderingContext for no good reason I could see. Could you clarify what's the intent?

NodeRenderingContext(this).parentRenderer() and nextRenderer() return the wrong values for things that are in the top layer but are display none. This method that takes pointers by reference and reassigns them is also confusing to follow because it's not clear from the existing code that the parentRenderer is always the RenderView for top layer elements.

If you remove my comments about how the existing behavior that I didn't change is broken this is less code as well.
Comment 8 Elliott Sprehn 2012-11-28 11:43:31 PST
(In reply to comment #7)
> (In reply to comment #6)
> > (From update of attachment 176395 [details] [details])
> > I really don't see the point of this change. You are peppering the knowledge of top layer elements all over NodeRenderingContext for no good reason I could see. Could you clarify what's the intent?
> 
> NodeRenderingContext(this).parentRenderer() and nextRenderer() return the wrong values for things that are in the top layer but are display none. This method that takes pointers by reference and reassigns them is also confusing to follow because it's not clear from the existing code that the parentRenderer is always the RenderView for top layer elements.
> 
> If you remove my comments about how the existing behavior that I didn't change is broken this is less code as well.

Also note that as the code is currently written inside Element::rendererIsNeeded parentRenderer() and nextRenderer() return the wrong values for top layer elements and inside of NodeRenderingConext::shouldCreateRenderer() we use the wrong parent renderer for making decisions about if the renderer is needed.
Comment 9 Hajime Morrita 2012-11-29 20:49:36 PST
Comment on attachment 176395 [details]
Patch

Let's move isInTopLayer to NodeFlags from rareData. Then can we detect that non-toplayer case a bit earlier.
Also, I'd rather extract traversal code in separate function. It's apparently invasive.

By the way, is toplayer system already used by fullscreen?
If so, we can move fullscreen handling in createRendererForElementIfNeeded() to toplayer handling path.
Comment 10 Hajime Morrita 2012-11-29 20:53:25 PST
(In reply to comment #8)
> 
> Also note that as the code is currently written inside Element::rendererIsNeeded parentRenderer() and nextRenderer() return the wrong values for top layer elements and inside of NodeRenderingConext::shouldCreateRenderer() we use the wrong parent renderer for making decisions about if the renderer is needed.

Can we write any layout test that captures this case?
Comment 11 Elliott Sprehn 2012-11-29 21:51:53 PST
(In reply to comment #9)
> (From update of attachment 176395 [details])
> Let's move isInTopLayer to NodeFlags from rareData. Then can we detect that non-toplayer case a bit earlier.

Can you explain what you mean by earlier?

> Also, I'd rather extract traversal code in separate function. It's apparently invasive.

Okay, I'll extract it.

> 
> By the way, is toplayer system already used by fullscreen?
> If so, we can move fullscreen handling in createRendererForElementIfNeeded() to toplayer handling path.

No, it's not used there yet. We should migrate to it, but I don't know who owns that.
Comment 12 Elliott Sprehn 2012-11-29 21:54:31 PST
(In reply to comment #10)
> (In reply to comment #8)
> > 
> > Also note that as the code is currently written inside Element::rendererIsNeeded parentRenderer() and nextRenderer() return the wrong values for top layer elements and inside of NodeRenderingConext::shouldCreateRenderer() we use the wrong parent renderer for making decisions about if the renderer is needed.
> 
> Can we write any layout test that captures this case?

Yeah, it occurred to be that doing <col><dialog></col> should be broken right now or doing <div><dialog></div> and then div { content: url(...); }.

I'll add a test.
Comment 13 Matt Falkenhagen 2012-12-13 11:45:56 PST
(In reply to comment #11)
> > By the way, is toplayer system already used by fullscreen?
> > If so, we can move fullscreen handling in createRendererForElementIfNeeded() to toplayer handling path.
> 
> No, it's not used there yet. We should migrate to it, but I don't know who owns that.

I'm planning to get to that as part of bug 84796.
Comment 14 Julien Chaffraix 2012-12-18 10:32:13 PST
Comment on attachment 176395 [details]
Patch

As pointed out in comment #10, this change needs some testing. If this solves a bug then this change is not a refactoring (as you presented it).
Comment 15 Matt Falkenhagen 2012-12-21 16:42:20 PST
I think this is a real bug but I'm not sure how to write a layout test that covers it for the current code. I'm running into crashes in my patches for bug 105489 and bug 95946 because nextRenderer is not top layer aware. I'm not sure why the problem shows up in those patches and not for the current code.

We at least need a check for top layer in a similar way that we have a check for flow thread in nextRenderer:

// Renderers for elements attached to a flow thread should be skipped because they are parented differently.
if (renderer->node()->isElementNode() && renderer->style() && !renderer->style()->flowThread().isEmpty())
    continue;
Comment 16 Elliott Sprehn 2012-12-21 16:46:25 PST
(In reply to comment #15)
> I think this is a real bug but I'm not sure how to write a layout test that covers it for the current code. I'm running into crashes in my patches for bug 105489 and bug 95946 because nextRenderer is not top layer aware. I'm not sure why the problem shows up in those patches and not for the current code.
> 
> We at least need a check for top layer in a similar way that we have a check for flow thread in nextRenderer:
> 
> // Renderers for elements attached to a flow thread should be skipped because they are parented differently.
> if (renderer->node()->isElementNode() && renderer->style() && !renderer->style()->flowThread().isEmpty())
>     continue;

Yeah we need to fix that too. I'll upload another patch that contains that and a test for the original case we identified with <col>.
Comment 17 Matt Falkenhagen 2013-01-07 00:28:33 PST
Created attachment 181483 [details]
Patch
Comment 18 Hajime Morrita 2013-01-07 00:42:02 PST
Comment on attachment 181483 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=181483&action=review

> Source/WebCore/dom/NodeRenderingContext.cpp:81
> +#if ENABLE(DIALOG_ELEMENT)

Could you move this to NodeRenderingTraversal?
It helps fast paths to go fast.
See http://trac.webkit.org/changeset/137715 for detail.

> Source/WebCore/dom/NodeRenderingContext.cpp:112
> +#endif

Ditto.

> Source/WebCore/dom/NodeRenderingContext.cpp:126
> +#if ENABLE(DIALOG_ELEMENT)

Ditto.
Comment 19 Matt Falkenhagen 2013-01-07 01:05:00 PST
(In reply to comment #16)
> Yeah we need to fix that too. I'll upload another patch that contains that and a test for the original case we identified with <col>.

Hi Elliott, I've went ahead and done this. What do you think?

I'd like to fix this so I can continue with bug 105489 and bug 95946.

BTW I couldn't immediately create a layout test that fails with <col><dialog></col>. Since <col> doesn't have a renderer, m_renderingParent and parentRenderer() is just the first ancestor with a renderer.

(In reply to comment #18)
> Could you move this to NodeRenderingTraversal?
> It helps fast paths to go fast.
> See http://trac.webkit.org/changeset/137715 for detail.

Thanks Morita-san! I'll look into this.
Comment 20 Elliott Sprehn 2013-01-07 15:50:31 PST
Comment on attachment 181483 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=181483&action=review

Add a test with display: table-column on an element around a <dialog>. I think we should land this and get things working and then refactor this out into a separate class like TopLayerController where you'd document()->topLayer()->nextRendererForNode(...) and such and move all the complicated loops out of NodeRenderingContext.

>> Source/WebCore/dom/NodeRenderingContext.cpp:81
>> +#if ENABLE(DIALOG_ELEMENT)
> 
> Could you move this to NodeRenderingTraversal?
> It helps fast paths to go fast.
> See http://trac.webkit.org/changeset/137715 for detail.

This really doesn't make sense in NodeRenderingTraversal. If we want to factor things out we should do what Regions does and have a TopLayerController that manages all this stuff like RenderNamedFlowThread::nextRendererForNode.

>> Source/WebCore/dom/NodeRenderingContext.cpp:112
>> +#endif
> 
> Ditto.

@morrita: I'm not sure what you want moved here, but this code should be here. We want to continue in this loop and skip all renderers that are in a different "flow thread" like regions (which is already here) or top layer.

>> Source/WebCore/dom/NodeRenderingContext.cpp:126
>> +#if ENABLE(DIALOG_ELEMENT)
> 
> Ditto.

This assert should be here. Please don't move this stuff out.
Comment 21 Hajime Morrita 2013-01-07 16:24:39 PST
Comment on attachment 181483 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=181483&action=review

>>> Source/WebCore/dom/NodeRenderingContext.cpp:81
>>> +#if ENABLE(DIALOG_ELEMENT)
>> 
>> Could you move this to NodeRenderingTraversal?
>> It helps fast paths to go fast.
>> See http://trac.webkit.org/changeset/137715 for detail.
> 
> This really doesn't make sense in NodeRenderingTraversal. If we want to factor things out we should do what Regions does and have a TopLayerController that manages all this stuff like RenderNamedFlowThread::nextRendererForNode.

Adding TopLayerController sounds good.
What I hope is to keep NodeRenderingContext maintainable and clarify where the happy path goes.

>>> Source/WebCore/dom/NodeRenderingContext.cpp:112
>>> +#endif
>> 
>> Ditto.
> 
> @morrita: I'm not sure what you want moved here, but this code should be here. We want to continue in this loop and skip all renderers that are in a different "flow thread" like regions (which is already here) or top layer.

Right. Then we could just extract the skip condition to a RenderObject method or some free floating function to make this part clearer.

>>> Source/WebCore/dom/NodeRenderingContext.cpp:126
>>> +#if ENABLE(DIALOG_ELEMENT)
>> 
>> Ditto.
> 
> This assert should be here. Please don't move this stuff out.

Right.
Comment 22 Matt Falkenhagen 2013-01-07 21:49:50 PST
Created attachment 181636 [details]
Patch
Comment 23 Matt Falkenhagen 2013-01-07 21:55:17 PST
Thanks for the comments. I uploaded a new patch with a layout test for display: table-column and a helper function for the skip condition in next/previousRenderer. Also I've removed the FIXME comment about <dialog> inside <col> since it seems to work.
Comment 24 Elliott Sprehn 2013-01-08 17:07:00 PST
Comment on attachment 181636 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=181636&action=review

This looks good to me. We can refactor out the logic into a TopLayerController in a follow up patch.

> Source/WebCore/dom/NodeRenderingContext.cpp:76
> +static bool isRendererReparented(RenderObject* renderer)

Nice! const RenderObject* renderer for the argument.
Comment 25 Matt Falkenhagen 2013-01-08 17:39:06 PST
Created attachment 181812 [details]
Patch
Comment 26 WebKit Review Bot 2013-01-08 20:48:12 PST
Comment on attachment 181812 [details]
Patch

Clearing flags on attachment: 181812

Committed r139154: <http://trac.webkit.org/changeset/139154>
Comment 27 WebKit Review Bot 2013-01-08 20:48:18 PST
All reviewed patches have been landed.  Closing bug.