Closed Bug 767647 Opened 12 years ago Closed 12 years ago

Stop invalidating once for every SVG descendant of a changed SVG container, and stop invalidating the descendants' rendering observers

Categories

(Core :: SVG, defect)

defect
Not set
normal

Tracking

()

RESOLVED FIXED
mozilla16

People

(Reporter: jwatt, Assigned: jwatt)

References

Details

(Keywords: perf)

Attachments

(1 file, 1 obsolete file)

While trying to fix bug 738192 so that it's easier for me to fix bug 614732, I got test failures because we're not calling nsSVGUtils::InvalidateAndScheduleBoundsUpdate in several places where we should be.
Attached patch patch (obsolete) — Splinter Review
Attachment #635996 - Flags: review?(longsonr)
Comment on attachment 635996 [details] [diff] [review]
patch

>   if (aNameSpaceID == kNameSpaceID_None &&
>       aAttribute == nsGkAtoms::transform) {
>-
>+    nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this);
>     NotifySVGChanged(TRANSFORM_CHANGED);

Are we not invalidating twice here, NotifySVGChanged would invalidate
all the children. Could we do one of

a) just schedule a bounds update without the invalidation
b) call NotifySVGChanged with SUPPRESS_INVALIDATION
c) have NotifySVGChanged itself manage the bounds update to get one invalidation

>diff --git a/layout/svg/base/src/nsSVGUseFrame.cpp b/layout/svg/base/src/nsSVGUseFrame.cpp
>--- a/layout/svg/base/src/nsSVGUseFrame.cpp
>+++ b/layout/svg/base/src/nsSVGUseFrame.cpp
>@@ -116,32 +116,31 @@ nsSVGUseFrame::AttributeChanged(PRInt32 
>                                 nsIAtom*        aAttribute,
>                                 PRInt32         aModType)
> {
...
>     } else if (aAttribute == nsGkAtoms::width ||
>                aAttribute == nsGkAtoms::height) {
>+      nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this);
>       static_cast<nsSVGUseElement*>(mContent)->SyncWidthOrHeight(aAttribute);
>-
>       if (mHasValidDimensions != 
>           static_cast<nsSVGUseElement*>(mContent)->HasValidDimensions()) {
>-
>         mHasValidDimensions = !mHasValidDimensions;
>-        nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this);
>       }
>     }

If the use is pointing to anything except a <symbol> or <svg> then modifying
the use width/height has no effect unless they change from valid (>0) to invalid
(<=0) mHasValidDimensions tracks this and avoids invalidating in this case.
If we have the InvalidateAndScheduleBoundsUpdate here then we're not taking
advantage of this knowledge any more.

Possible solutions would be one of...
a) Have SyncWidthOrHeight call nsSVGUtils::InvalidateAndScheduleBoundsUpdate 
   for symbols and svg elements and then move the call above into the test below
b) Implement a method on nsSVGUseElement that returns whether width/height override
   the cloned element's values, something like

  if (mClone) {
    nsCOMPtr<nsIDOMSVGSymbolElement> symbol = do_QueryInterface(mClone);
    nsCOMPtr<nsIDOMSVGSVGElement>    svg    = do_QueryInterface(mClone);
    return (symbol || svg);
  }

Then only call InvalidateAndScheduleBoundsUpdate if this returns true or the
width/height validity has changed
c) If neither a nor b are feasible then we should rip out mHasValidDimensions as
   it is now pointless.

FWIW I would prefer b).
Attachment #635996 - Flags: review?(longsonr) → review-
Depends on: 767697
Depends on: 767701
(In reply to Robert Longson from comment #2)
> Are we not invalidating twice here,

Not exactly, or at least not when landed in combination with the patch for bug 738192. Anyway, the point is mute because...

> Could we do one of
> 
> a) just schedule a bounds update without the invalidation

I was planning on doing this later since there's extra risk with making that change. But heck, let's morph this bug and do in now. Patch coming up.
Keywords: perf
Summary: Add nsSVGUtils::InvalidateAndScheduleBoundsUpdate() calls in several places that are missing them → Stop invalidating once for every SVG descendant whenever a container SVG changes
Attached patch patchSplinter Review
Attachment #635996 - Attachment is obsolete: true
Attachment #636085 - Flags: review?(longsonr)
I've s/WidthAndHightAreUsed/WidthAndHeightAreUsed/ locally.
Summary: Stop invalidating once for every SVG descendant whenever a container SVG changes → Stop invalidating once for every SVG descendant of a changed SVG container, and stop invalidating the descendants' rendering observers
Comment on attachment 636085 [details] [diff] [review]
patch

I don't much like even the corrected name of WidthAndHeightAreUsed how about
WidthAndHeightOverrideClone or WidthAndHeightOverrideCloneValues.

>+  if (needNewBounds) {
>+    // Ancestor changes can't affect how we render from the perspective or
>+    // any rendering observers that we may have, so we don't need to
>+    // invalidate them. We also don't need to invalidate ourself, since our
>+    // changed ancestor will have invalidated its entire area, which includes
>+    // our area.

I'm not sure I follow what the first sentence is trying to say, particularly the
"from the perspective" bit. Perhaps those 3 words just need to be omitted.

This same comment is repeated so make sure they all get updated.

>-
>-      if (mHasValidDimensions != 
>+      if (static_cast<nsSVGUseElement*>(mContent)->WidthAndHightAreUsed()) {
>+        nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this);
>+      }
>+      if (mHasValidDimensions !=
>           static_cast<nsSVGUseElement*>(mContent)->HasValidDimensions()) {

Should use an else here so as not to call InvalidateAndScheduleBoundsUpdate twice if
WidthAndHightAreUsed(sic) is true and HasValidDimensions changes state.

>-
>         mHasValidDimensions = !mHasValidDimensions;
>         nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this);
>       }
>+      static_cast<nsSVGUseElement*>(mContent)->SyncWidthOrHeight(aAttribute);

Pointless calling SyncWidthOrHeight unless WidthAndHightAreUsed(sic) returns true. 
Move into appropriate test above. Add an assert in nsSVGUseElement::SyncWidthOrHeight that
WidthAndHightAreUsed is true.
Attachment #636085 - Flags: review?(longsonr) → review+
(In reply to Robert Longson from comment #6)
> I don't much like even the corrected name of WidthAndHeightAreUsed how about
> WidthAndHeightOverrideClone or WidthAndHeightOverrideCloneValues.

I don't really like "clone" in the name, since we may well end up changing <use> to not clone sometime soon to match other implementations. I changed it to OurWidthAndHeightAreUsed to get rid of the possibly confusing "Or" in the name.

> I'm not sure I follow what the first sentence is trying to say, particularly
> the
> "from the perspective" bit. Perhaps those 3 words just need to be omitted.

Oops, I meant "perspective of", not "perspective or". I think that's probably what you found confusing, so I fixed that.

> Should use an else here...

This ended up being a bit awkward after you telling me to put the SyncWidthOrHeight() call in the if, but okay, done.
I'm not sure what happened when testing my patch as reviewed, but it seemed to pass at the time. (Maybe something to do with the fact that I'm qpush/qpop'ing like crazy right now. Anyway, there were a few things I had to change after I did a last test run before pushing to mozilla-inbound:

1) I had to make UpdateBounds() on containers invalidate, since we no longer traverse to all its leafs and ask them to.

2) I removed the MarkDirtyBitsOnDescendants() code from nsSVGUtils.cpp since we no longer need to do that...except for text frames, since we have a "invalidate-one-part-of-the-text-then-invalidate-it-all" policy there. So I actually moved the MarkDirtyBitsOnDescendants code to nsSVGTextFrame.cpp and called it as appropriate there.
Depends on: 734082
Pushed https://hg.mozilla.org/integration/mozilla-inbound/rev/b7ba8a51adaf

The for stupid undefined variable bustage:

https://hg.mozilla.org/integration/mozilla-inbound/rev/8aa75c0cd1e5
Target Milestone: --- → mozilla16
You need to log in before you can comment on or make changes to this bug.