Closed Bug 841192 Opened 11 years ago Closed 11 years ago

Remove nsDisplayClip(RoundedRect) and attach explicit Clip objects to every display item

Categories

(Core :: Layout, defect)

defect
Not set
normal

Tracking

()

RESOLVED FIXED
mozilla23

People

(Reporter: roc, Assigned: roc)

References

(Depends on 1 open bug, Blocks 1 open bug)

Details

Attachments

(20 files, 1 obsolete file)

55.22 KB, patch
mattwoodrow
: review+
Details | Diff | Splinter Review
21.88 KB, patch
mattwoodrow
: review+
Details | Diff | Splinter Review
6.40 KB, patch
mattwoodrow
: review+
Details | Diff | Splinter Review
1.95 KB, patch
mattwoodrow
: review+
Details | Diff | Splinter Review
3.59 KB, patch
mattwoodrow
: review+
Details | Diff | Splinter Review
2.07 KB, patch
mattwoodrow
: review+
Details | Diff | Splinter Review
7.30 KB, patch
mattwoodrow
: review+
Details | Diff | Splinter Review
9.96 KB, patch
mattwoodrow
: review+
Details | Diff | Splinter Review
8.07 KB, patch
mattwoodrow
: review+
Details | Diff | Splinter Review
3.32 KB, patch
mattwoodrow
: review+
Details | Diff | Splinter Review
7.85 KB, patch
mattwoodrow
: review+
Details | Diff | Splinter Review
6.89 KB, patch
mattwoodrow
: review+
Details | Diff | Splinter Review
148.31 KB, patch
mattwoodrow
: review+
Details | Diff | Splinter Review
46 bytes, text/html
Details
271 bytes, text/html
Details
5.52 KB, patch
MatsPalmgren_bugz
: review+
Details | Diff | Splinter Review
344 bytes, text/html
Details
33.51 KB, patch
mattwoodrow
: review+
Details | Diff | Splinter Review
4.26 KB, patch
mattwoodrow
: review+
Details | Diff | Splinter Review
62.09 KB, image/png
Details
In some display lists (e.g. in bug 840372) a lot of nested nsDisplayClips are created. Constructing these, and processing them in FrameLayerBuilder is expensive and unnecessary. nsDisplayClip also adds a lot of complications to display lists because unlike all other display items, they may not have a specific "underlying frame". Also, FrameLayerBuilder eventually constructs explicit Clip objects for each (post-optimization) display item anyway.

So, assigning explicit Clip objects during display list construction should save a lot of work and simplify the code.
Plan of attack:

1) Move mozilla::FrameLayerBuilder::Clip to mozilla::DisplayItemClip.
2) Instead of wrapping up display items after we've constructed them, we'll keep "current clip" state in nsDisplayListBuilder with an Auto class to save and restore that state. When a display item is created, the current clip in the nsDisplayListBuilder will be copied to a new DisplayItemClip in the displaylist arena and a pointer to that DisplayItemClip will be put in the new display item. We can cache this pointer so that display items allocated with the same current clip state share the same DisplayItemClip object (keeping display list size down).
3) The "current clip" state is a bit complex. It can't just be a DisplayItemClip, because for 'overflow' clipping the container needs to clip the child items that it is the containing block for, and *not* clip the other child items. So we're actually going to need one DisplayItemClip which "clips everything" and a separate stack of (DisplayItemClip, containing block) pairs which clip the display items whose frame has the given containing block. For efficiency we probably should store all three of:
a) DisplayItemClip that clips everything
b) Stack of (DisplayItemClip, containing block) with the conditional clips in effect. When we follow placeholders through BuildDisplayListForChild we'd remove any clips that are no longer containing-block ancestors for the out-of-flow frame. And each clip on the stack would include the clips below it on the stack.
c) A pointer to an arena-allocated DisplayItemClip which is the intersection of a) and the clip at the top of stack b), if one has been allocated.
Attachment #722459 - Flags: review?(matt.woodrow) → review+
Attachment #722461 - Flags: review?(matt.woodrow) → review+
Comment on attachment 722467 [details] [diff] [review]
Part 4: Create DisplayListClipState

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

::: layout/base/DisplayItemClip.h
@@ +57,5 @@
>  
>    // Construct as the intersection of aOther and aClipItem.
>    DisplayItemClip(const DisplayItemClip& aOther, nsDisplayItem* aClipItem);
>  
> +  void IntersectWith(const DisplayItemClip& aOther);

Is this meant to be here? I don't see an implementation of it

::: layout/base/DisplayListClipState.h
@@ +36,5 @@
> +  {
> +    return mClipContentDescendants;
> +  }
> +
> +  void SetClipForContainingBlockDescendants(const DisplayItemClip* aClip)

Should these two not have the 'Get' prefix since they are just getters without side effects?
Attachment #722467 - Flags: review?(matt.woodrow) → review+
Attachment #722468 - Flags: review?(matt.woodrow) → review+
Comment on attachment 722471 [details] [diff] [review]
Part 6: Save and restore DisplayListClipState when we start building display lists for a frame

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

::: layout/base/nsDisplayList.h
@@ +488,5 @@
>    class AutoBuildingDisplayList {
>    public:
>      AutoBuildingDisplayList(nsDisplayListBuilder* aBuilder, bool aIsRoot)
>        : mBuilder(aBuilder),
> +        mPrevClipState(aBuilder->mClipState),

It's a bit scary to me that we just copy the raw pointers within DisplayListClipState and trust that nothing will delete them. I realise that the arena allocations make this true, but we should document it somewhere.
Attachment #722471 - Flags: review?(matt.woodrow) → review+
Attachment #722472 - Flags: review?(matt.woodrow) → review+
Attachment #722473 - Flags: review?(matt.woodrow) → review+
Attachment #722474 - Flags: review?(matt.woodrow) → review+
(In reply to Matt Woodrow (:mattwoodrow) from comment #17)
> ::: layout/base/DisplayListClipState.h
> @@ +36,5 @@
> > +  {
> > +    return mClipContentDescendants;
> > +  }
> > +
> > +  void SetClipForContainingBlockDescendants(const DisplayItemClip* aClip)
> 
> Should these two not have the 'Get' prefix since they are just getters
> without side effects?

"GetFoo()" means the functions can return null, "Foo()" means it cannot.
Attached file Testcase #1
Comment on attachment 722458 [details] [diff] [review]
Part 1: Instead of making nsSubDocumentFrame::Reflow enforce that HTML <frame> elements have no padding, do that in ua.css so that all our code agrees on what the content box is

It sounds as if you intended this change to be idempotent?
Can you explain why I now see a left and top padding in Testcase #1
with the Part 1 patch applied?

Fwiw, Trident and Webkit appears to implement padding for <frame>,
I tend to think we should too.
Attachment #722458 - Flags: review?(matspal) → review-
(In reply to Matt Woodrow (:mattwoodrow) from comment #17)
> Comment on attachment 722467 [details] [diff] [review]
> Part 4: Create DisplayListClipState
> 
> Review of attachment 722467 [details] [diff] [review]:
> -----------------------------------------------------------------
> 
> ::: layout/base/DisplayItemClip.h
> @@ +57,5 @@
> >  
> >    // Construct as the intersection of aOther and aClipItem.
> >    DisplayItemClip(const DisplayItemClip& aOther, nsDisplayItem* aClipItem);
> >  
> > +  void IntersectWith(const DisplayItemClip& aOther);
> 
> Is this meant to be here? I don't see an implementation of it

The implementation's in part 9. Sorry, I'll move it down.

(In reply to Matt Woodrow (:mattwoodrow) from comment #18)
> It's a bit scary to me that we just copy the raw pointers within
> DisplayListClipState and trust that nothing will delete them. I realise that
> the arena allocations make this true, but we should document it somewhere.

Actually there is something here which makes me a bit uncomfortable: we require that ClipContainingBlockDescendants/ClipContentDescendants and SetClipForContainingBlockDescendants/SetClipForContentDescendants take parameters that will stay alive (on the stack, typically) until the old clip state is restored.

I can probably fix that unsafeness by requiring all DisplayListClipState modification be done through DisplayListClipState::AutoSaveRestore, which would actually contain the temporary DisplayItemClip that gets used for setting. I'll try that.
(In reply to Mats Palmgren [:mats] from comment #22)
> Fwiw, Trident and Webkit appears to implement padding for <frame>,
> I tend to think we should too.

OK.
Attachment #722475 - Flags: review?(matt.woodrow) → review+
> 
> Actually there is something here which makes me a bit uncomfortable: we
> require that ClipContainingBlockDescendants/ClipContentDescendants and
> SetClipForContainingBlockDescendants/SetClipForContentDescendants take
> parameters that will stay alive (on the stack, typically) until the old clip
> state is restored.
> 
> I can probably fix that unsafeness by requiring all DisplayListClipState
> modification be done through DisplayListClipState::AutoSaveRestore, which
> would actually contain the temporary DisplayItemClip that gets used for
> setting. I'll try that.

Sounds good.
Attachment #722476 - Flags: review?(matt.woodrow) → review+
Attachment #722477 - Flags: review?(matt.woodrow) → review+
Attachment #722479 - Flags: review?(matt.woodrow) → review+
Comment on attachment 722480 [details] [diff] [review]
Part 14: Convert all usage of nsDisplayClip(RoundedRect) to use DisplayListClipState/DisplayItemClip

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

Looks really good! Might be worth getting someone else to double check the nsSubDocumentFrame etc stuff, I don't know that code all that well.

::: layout/base/FrameLayerBuilder.cpp
@@ +3242,5 @@
> +      tmpClip.RemoveRoundedCorners();
> +      clip = &tmpClip;
> +    }
> +    if (currentClipIsSetInContext != clip->HasClip() ||
> +        (clip->HasClip() && *clip != currentClip)) {

Items with the same clip should compare true with just a pointer comparison, right?

Can we make currentClip a pointer and just do that instead here? I guess we might still need to do both (nsDisplayItem::SetClip allocates new memory), but it should be faster in the common case.

::: layout/base/nsDisplayList.cpp
@@ -974,5 @@
> -                 item->GetType() != nsDisplayItem::TYPE_TRANSFORM ||
> -                 item->GetUnderlyingFrame() != aForItem->GetUnderlyingFrame() ||
> -                 aForItem->ReferenceFrame() != aForItem->GetUnderlyingFrame(),
> -                 "If we have an nsDisplayTransform child (for the same frame),"
> -                 "then we shouldn't be our own reference frame!");

Why is this going?

@@ +1636,5 @@
>    nscoord radii[8];
>    return !aFrame->GetBorderRadii(radii) ||
> +         nsLayoutUtils::RoundedRectIntersectsRect(nsRect(aFrameToReferenceFrame,
> +                                                         aFrame->GetSize()),
> +                                                  radii, aTestRect);

Probably should be part of the previous patch, doubt it matters though.

::: layout/base/nsLayoutDebugger.cpp
@@ +159,5 @@
> +    const DisplayItemClip& clip = i->GetClip();
> +    nsCString clipString;
> +    if (clip.HasClip()) {
> +      clipString = clip.ToString();
> +    }

ToString already handles the !HasClip() case
Attachment #722480 - Flags: review?(matt.woodrow) → review+
Version: 18 Branch → Trunk
Attached patch Part 1 v2Splinter Review
Webkit supports both border and padding on <frame> elements, and it turns out to be trivial for us to support both, so why not?
Attachment #722458 - Attachment is obsolete: true
Attachment #726966 - Flags: review?(matspal)
(In reply to Matt Woodrow (:mattwoodrow) from comment #26)
> Items with the same clip should compare true with just a pointer comparison,
> right?

Not necessarily.

> Can we make currentClip a pointer and just do that instead here? I guess we
> might still need to do both (nsDisplayItem::SetClip allocates new memory),
> but it should be faster in the common case.

We could use a pointer comparison as a shortcut but in the common (non-roundedrect) case comparing clips is already just comparing the rects and checking that both rounded-rect arrays are empty, so really cheap.

> ::: layout/base/nsDisplayList.cpp
> @@ -974,5 @@
> > -                 item->GetType() != nsDisplayItem::TYPE_TRANSFORM ||
> > -                 item->GetUnderlyingFrame() != aForItem->GetUnderlyingFrame() ||
> > -                 aForItem->ReferenceFrame() != aForItem->GetUnderlyingFrame(),
> > -                 "If we have an nsDisplayTransform child (for the same frame),"
> > -                 "then we shouldn't be our own reference frame!");
> 
> Why is this going?

Because we're passing aForItem just for this assertion, which seems not worthwhile.

> @@ +1636,5 @@
> >    nscoord radii[8];
> >    return !aFrame->GetBorderRadii(radii) ||
> > +         nsLayoutUtils::RoundedRectIntersectsRect(nsRect(aFrameToReferenceFrame,
> > +                                                         aFrame->GetSize()),
> > +                                                  radii, aTestRect);
> 
> Probably should be part of the previous patch, doubt it matters though.

Will fix.

> ::: layout/base/nsLayoutDebugger.cpp
> @@ +159,5 @@
> > +    const DisplayItemClip& clip = i->GetClip();
> > +    nsCString clipString;
> > +    if (clip.HasClip()) {
> > +      clipString = clip.ToString();
> > +    }
> 
> ToString already handles the !HasClip() case

Will fix.
Comment on attachment 726966 [details] [diff] [review]
Part 1 v2

> +  // XUL <iframe> or <browser>, or HTML <iframe>, <object> or <embed>

or <frame> :-)

Seriously though, it seems a bit odd now to list the potential elements
this frame class deals with here, since they are all handled the same.
If anywhere, the comment at the top of nsSubDocumentFrame.cpp seems more
appropriate, and/or in the header file somewhere.

Anyway, r=mats, as you see fit.
Attachment #726966 - Flags: review?(matspal) → review+
Attached file Testcase #2
For the record, I noticed a couple of details where rendering differs
between UAs.  <frameset> background propagates to the viewport in IE10,
not in Chrome (27) or Firefox.  <frameset> margins seems mostly compatible
in IE10/FF (top,left,bottom seems correct, but the right margin is zero
in IE and 20px in FF (size of vertical borders?).  Chrome only has a top
margin.  Not sure if this is worth filing bugs on, unless there actually
is a spec for <frameset> / <frame> rendering somewhere.
(In reply to Mats Palmgren [:mats] from comment #30)
> For the record, I noticed a couple of details where rendering differs
> between UAs.  <frameset> background propagates to the viewport in IE10,
> not in Chrome (27) or Firefox.

I believe we're correct per spec. The <frameset> is not the document's root element, nor is it the document's <body> element, so nothing says its background should propagate.

> <frameset> margins seems mostly compatible
> in IE10/FF (top,left,bottom seems correct, but the right margin is zero
> in IE and 20px in FF (size of vertical borders?).

How margins work on <frameset> is not specified anywhere as far as I know. Frameset layout is specified here: http://www.whatwg.org/specs/web-apps/current-work/multipage/rendering.html#frames-and-framesets but that doesn't handle margins (or CSS padding or borders either).

If we had to deal with this I'd be tempted to just force all margins to 0 for <frame> and <frameset> elements, and force borders and padding to 0 for <frameset>s, using !important rules in html.css. But really I don't care.
Attachment #733261 - Flags: review?(matt.woodrow) → review+
Attachment #733724 - Flags: review?(matt.woodrow) → review+
I tried out cset 1e958f7224a7 on m-c inbound which seems to only include this patch and I see an anomaly in my sidebars.  I've attached a screenshot of it.  The previous cset 905671d954c5 worked OK.
Attached image Sidebar anomaly
about:addons also shows the same sort of thing.
I don't see that on Linux, probably because the theme background isn't different.
Depends on: 858803
Depends on: 860253
Depends on: 860579
Depends on: 860722
Depends on: 860524
Depends on: 862674
Depends on: 875060
Depends on: 876092
Depends on: 902546
Depends on: 903587
Depends on: 906199
Depends on: 907078
Depends on: 907900
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: