background image rendered incorrectly when window resized

RESOLVED FIXED in mozilla1.9.3a1

Status

()

P2
normal
RESOLVED FIXED
10 years ago
9 years ago

People

(Reporter: rockmfr, Assigned: Waldo)

Tracking

Trunk
mozilla1.9.3a1
Points:
---
Dependency tree / graph
Bug Flags:
blocking1.9.2 +
in-testsuite ?

Firefox Tracking Flags

(status1.9.2 beta2-fixed)

Details

Attachments

(7 attachments)

(Reporter)

Description

10 years ago
Created attachment 393447 [details]
testcase

Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2a2pre) Gecko/20090809 Minefield/3.6a2pre

A background image may be rendered incorrectly when the window is resized.

Steps to reproduce:
1) Open testcase
2) Resize the window width to make the window as narrow as possible
3) Return window width to normal size

Expected: There should be a vertical white line in the middle of the page.
Actual: There are a random number of vertical white lines at random locations.

Regression range:
http://hg.mozilla.org/mozilla-central/pushloghtml?fromchange=f2a58ffcd00c&tochange=02f8bf10f441
(Reporter)

Comment 1

10 years ago
Created attachment 393450 [details]
screenshot
Hmm.  Does the bit at the end of nsIFrame::CheckInvalidateSizeChange need to use nsCSSRendering::FindBackground?  (And, even so, what would have caused the regression?)
(Assignee)

Comment 4

10 years ago
I think it does need to change, at the very least to address bug 507750, which is probably a dup of this.  That doesn't explain why it doesn't appear on OS X, unfortunately.
For what it's worth, on Linux, I'm seeing the background simply not get updated until something else happens to repaint the window (which I think includes ending the drag).
(Assignee)

Comment 6

10 years ago
Er, make that bug 507550.  I'm pretty sure no change we make to our own code will affect Opera!

Comment 7

10 years ago
Cannot reproduce.
Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.2) Gecko/20090731 Shiretoko/3.5.2
(Assignee)

Updated

10 years ago
Keywords: regressionwindow-wanted
(Assignee)

Comment 8

10 years ago
Aha, maybe I see the (rest of the) problem!

First, as previously noted, there's not using FindBackground.

Second, as I note in bug 507550, the frame's width is the full window width and its height is zero (of course -- it doesn't have anything in it!).  FindBackground needs to be modified to get both the nsStyleBackground* and the actual frame for it so that *that* frame's rect, not aOldRect, can be invalidated.  Sound right?  I can whip up the patch if this reasoning sounds plausible.
Hmmm.  I had been thinking that we'd pick up the right background when resizing the canvas because we'd call CheckInvalidateSizeChange on the canvas frame.  But the problem with background fixup is that the background positioning area is actually derived from the dimensions of the root frame.  And I think it's possible for the dimensions of the root frame to change without the size of the canvas changing.

(Am I right that the root element dimensions are used to compute the background positioning area for the canvas, and the canvas dimensions *are not*?  Or are both used?)

So, really (if I'm right above), I think we should probably rely on knowledge of the internals of FindBackground, and, in CheckInvalidateSizeChange, if we're about to invalidate, call FindBackground, and if it returns null (i.e., our background is propagated), invalidate the canvas instead.

(Or does FindBackground do any other fixup than root->canvas and body->canvas?)


For what it's worth, we could probably also skip this step for fixed backgrounds.  Except, if there are any fixed backgrounds, we need to invalidate when the size of the canvas changes.  And we don't do that either!
(In reply to comment #9)
> But the problem with background fixup is that the background positioning area
> is actually derived from the dimensions of the root frame.  And I think it's
> possible for the dimensions of the root frame to change without the size of
> the canvas changing.

Yes.

> (Am I right that the root element dimensions are used to compute the
> background positioning area for the canvas, and the canvas dimensions *are
> not*?  Or are both used?)

The canvas is not used (except for background-attachment:fixed, which uses *only* the canvas).

> So, really (if I'm right above), I think we should probably rely on knowledge
> of the internals of FindBackground, and, in CheckInvalidateSizeChange, if
> we're about to invalidate, call FindBackground, and if it returns null (i.e.,
> our background is propagated), invalidate the canvas instead.

Sounds good.

> For what it's worth, we could probably also skip this step for fixed
> backgrounds.  Except, if there are any fixed backgrounds, we need to
> invalidate when the size of the canvas changes.  And we don't do that either!

Argh!
Flags: blocking1.9.2? → blocking1.9.2+
Priority: -- → P2
(Assignee)

Comment 11

9 years ago
I hope to get to this next week.
(Assignee)

Comment 12

9 years ago
So much for "next week"; building a maybe-patch right now, tho.
Assignee: nobody → jwalden+bmo
(Assignee)

Comment 13

9 years ago
That patch, as might have been guessed, didn't work -- still on this, tho.
(Assignee)

Comment 14

9 years ago
Created attachment 407895 [details] [diff] [review]
Half-fix, addresses the testcase in this bug

This fixes the original testcase.  It also fixes the original testcase if I make the background fixed.  However, if I add a width to the background (in addition to making it fixed), it's still broken.  I'm kind of debating making this halfway step here and then finish it up in bug 507550, rather than doing it all at once here, but for now I'm going to continue work on one patch for bug.
(Assignee)

Comment 15

9 years ago
Created attachment 408130 [details]
Another test (likely fixt by the layer.RenderingMightDependOnFrameSize() change)
(Assignee)

Comment 16

9 years ago
So, the reason the patch breaks if you add an explicit width to body, which has a fixed background, as in the reduced testcase in bug 507550, is the early-exit check in nsIFrame::CheckInvalidateSizeChange:

void
nsIFrame::CheckInvalidateSizeChange(const nsRect& aOldRect,
                                    const nsRect& aOldOverflowRect,
                                    const nsSize& aNewDesiredSize)
{
  if (aNewDesiredSize == aOldRect.Size())
    return;

aNewDesiredSize and aOldRect.Size() have the same width when width is explicitly set, of course.  For all the testcases so far the height of the body is much less than the height of the canvas, so resizing doesn't change the height, either.  Therefore the equality is true and we return early, without invalidating the canvas.

This actually points out a further bug/deficiency in my past testing.  If there's no width, I thought I'd fixed matters -- but the only reason was that I was resizing the window horizontally and vertically both!  If I resize a fixed/no-width testcase solely in the vertical direction, width doesn't change, height is smaller than the window so it doesn't change, and therefore the same invalidation issues occur.
(Assignee)

Comment 17

9 years ago
Created attachment 408150 [details]
Testcase (appears fixed if resized diagonally, broken if resized vertically)

Resize this testcase in the vertical direction only, and you see bustage, as noted in the last paragraph of comment 16.

Fundamentally, it seems the == early-exit check is unsound when:

  layer.mAttachment == NS_STYLE_BG_ATTACHMENT_FIXED &&
  layer.RenderingMightDependOnFrameSize()

...when the reflow is a presshell resize-reflow.  It seems the == early-exit should be changed to this:

  if (!doingPresshellResizeReflow(this) && aNewDesiredSize == aOldRect.Size())
    return;

...maybe, but 1) I'm not sure what doingPresshellResizeReflow should be, and 2) just axing the == check entirely doesn't work either, so probably I need to get the nsStyleBackground* differently.  Still working on that at the moment, distracted by an entirely unrelated assertion I somehow seem to have picked up via weird sessionstore.js entries...
(Assignee)

Comment 18

9 years ago
Created attachment 409210 [details]
Fixed, percent-sized background not propagated to canvas

Here's a final testcase; resize it to be narrow and the widths of the two yellow boxes should change (at least to a certain point, see the source for precise details).  The widths should change as the window is resized, but on Linux they don't change until the mouse is released and the drag ends.  OS X probably doesn't have an issue because something causes the entire window to redraw as the drag happens.  Windows doesn't even do the end-of-drag redraw, so it stays bad until a full-window repaint happens.
(Assignee)

Comment 19

9 years ago
Created attachment 409217 [details] [diff] [review]
Patch for everything but the immediate previous testcase

This fixes everything that's mentioned in this bug, in bug 507550, and in bug 508353 except for attachment 409210 [details].  I'm not sure how to handle that attachment.  The nsCanvasArea change addresses the case in the attachment for propagated backgrounds, but in the non-propagated place it seems -- given the information we have now -- the only way to invalidate enough would be to walk the entire frame tree.  Clearly we don't want that, but I don't have enough experience with this code to say what we should be doing instead to make sure non-propagated frames with size-dependent backgrounds are invalidated when necessary.

Anyway: this fixes most of the cases people will care about, and we're getting close to the wire, so I'd like to get the 95% cases fixed even if the 5% cases end up being deferred.  I'll file a followup to address the non-propagated fixed size-dependent case when this attachment or some form of it makes it into the tree.

(Also regarding attachment 409210 [details]: while that attachment uses background-size to get misrenderings, I'm pretty sure you can get errors for the same reason with a non-zero percentage background-position, so the mistakes demonstrated are not new with background-size.)
Attachment #409217 - Flags: review?
(Assignee)

Updated

9 years ago
Attachment #409217 - Flags: review? → review?(dbaron)
+void InvalidateRect(nsIFrame* aFrame, const nsRect& aRect)

static

InvalidateRect propagates invalidation to the root no matter what caused it --- outline, border, background, etc. But only background propagates to the root. You're relying on the fact that the rootframe covers everything, which isn't quite true actually; Fennec requires that invalidation happens even on content which seems to be outside the viewport. So I suggest that you change InvalidateRect to invalidate both the frame and the rootframe. Also, let's call it something a bit more specific, like InvalidateRectForFrameSizeChange.

You should probably leave the review with dbaron though, because of the nsStyleStruct.h change.
Comment on attachment 409217 [details] [diff] [review]
Patch for everything but the immediate previous testcase

In nsStyleStruct.h, could you put a comment in the definition of
DimensionType pointing to DependsOnFrameSize?

In nsCanvasFrame.cpp:

+    if (aReflowState.mFlags.mHResize || aReflowState.mFlags.mVResize) {

I think it makes more sense to check (after setting aDesiredSize.width
and .height):
  if (nsSize(aDesiredSize.width, aDesiredSize.height) != GetSize()) {
since what you're really interested in is whether the frame's size
changed, not what optimizations we can check during reflow.  And moving
the code down to there shouldn't be a problem.

However, you should file a followup bug on doing this right (which
probably requires either storing or recomputing the areas painted with
fixed size-dependent backgrounds so we can invalidate them when the
canvas size changes).

Your comment should also make it clearer that this code isn't the right
fix, and doesn't handle fixed backgrounds that aren't propagated to the
canvas.

In nsFrame.cpp:

You should probably comment that InvalidateRect's going up to the root
frame is only really needed for the background
RenderingMightDependOnFrameSize() case, but you're doing it for all
cases so that you can leave the early return after invalidation.

Also, InvalidateRect should be |static|.

r=dbaron with that
Attachment #409217 - Flags: review?(dbaron) → review+
(Assignee)

Comment 22

9 years ago
http://hg.mozilla.org/mozilla-central/rev/19a209a691be

I filed bug 525556 on making non-propagated, fixed, percent-sized or -positioned backgrounds invalidate correctly on window resize.

I tried writing invalidation reftests for this, but I couldn't get it to work either using the MozReftestInvalidate event or by manually making it work with MozAfterPaint.  I tried using and resizing a nested iframe, since the reftest window's size can't be changed, but the invalidation information exposed by MozAfterPaint didn't seem to make much sense.  If anyone else wants to try with the tests here, in bug 507550, or in bug 508353, go ahead, but after spending more than a few hours trying to get it work and failing I'm inclined to move to spending time on other issues and blockers.

I'll let this bake for a few days or a week or so before asking for 192 approval.
Status: NEW → RESOLVED
Last Resolved: 9 years ago
Component: Layout → Layout: Block and Inline
Flags: in-testsuite?
Keywords: regression, regressionwindow-wanted
OS: Windows XP → All
QA Contact: layout → layout.block-and-inline
Hardware: x86 → All
Resolution: --- → FIXED
Target Milestone: --- → mozilla1.9.3a1
(Assignee)

Updated

9 years ago
Duplicate of this bug: 507550
(Assignee)

Updated

9 years ago
Duplicate of this bug: 508353
(In reply to comment #22)
> I'll let this bake for a few days or a week or so before asking for 192
> approval.

It's a blocker; you don't need approval.  And I'd suggest something more like "a few days" than "a week or so".
(Assignee)

Comment 26

9 years ago
http://hg.mozilla.org/releases/mozilla-1.9.2/rev/8945f271cfac

The patch port wasn't quite painless due to nsCanvasFrame separation into a new file and lack of nsStyleBackground::Image::IsEmpty, but it was close enough to not present any mental complexity.
status1.9.2: --- → final-fixed
You need to log in before you can comment on or make changes to this bug.