Closed Bug 807457 Opened 12 years ago Closed 12 years ago

[Browser] SVG content not repainted, when coming back from tab listing, or navigating back to it w/ "back" button


(Core :: DOM: Core & HTML, defect)

Gonk (Firefox OS)
Not set



blocking-basecamp +
Tracking Status
firefox18 --- fixed
firefox19 --- fixed


(Reporter: dholbert, Assigned: dholbert)




(Keywords: b2g-testdriver, unagi)


(2 files, 1 obsolete file)

 1. Load testcase in B2G browser
 2. Click the "1>" in upper-right corner to open tab-view
 3. Go back to your tab*

EXPECTED RESULTS: The tab should look like it did after step 1.

ACTUAL RESULTS: The tab is blank.

* It doesn't seem to matter *how* you get back to your tab -- I tried tapping its entry in the list, or tapping the upper-left "<" button, or tapping the left edge of the screen -- and I hit the bug in each case.
Summary: [Browser] SVG content not repainted when switching back to a tab from tab-preview view → [Browser] SVG content not repainted, when coming back from tab listing
I also hit this bug if I...
 (1) view the testcase
 (2) navigate to a different site (e.g.
 (3) hit "back" button
Summary: [Browser] SVG content not repainted, when coming back from tab listing → [Browser] SVG content not repainted, when coming back from tab listing, or navigating back to it w/ "back" button
(In reply to Naoki Hirata :nhirata from comment #3)
> related to bug 806035?

Hard to say.  That bug has blurriness, whereas here, it's just blank white nothingness. And I can't reproduce that bug (though I have seen random blurriness from time to time).
...though I can reliably reproduce bug 806035 by going to the tab listing & back (per bug 806035 comment 2)

Given that, these bugs are likely related. (though note that bug 806035 requires zooming whereas this bug here does not)
Component: Gaia::Browser → General
roc, any ideas about what could be causing this?
blocking-basecamp: ? → +
Flags: needinfo?(roc)
No. Are we hitting _cairo_error?
Flags: needinfo?(roc)
Daniel, can you answer #7?
Flags: needinfo?(dholbert)
I can try. Haven't installed a custom / debug b2g build on my dogfood device yet, so i imagine there'll be a bit of spin-up before I can answer, but I'll see what I can find out.

FWIW, I tried the desktop FxOS simulator and was unable to reproduce there (using steps in comment 0 & comment 2), so this appears to be specific to B2G-running-on-a-device.
Flags: needinfo?(dholbert)
OS: Linux → Gonk (Firefox OS)
Hardware: x86_64 → ARM
In reply to comment 7 / comment 8: We're definitely not hitting _cairo_error. (added some android logging there, and it's not getting hit)

I added some logging to various BuildDisplayList methods, and from comparing another testcase w/ an HTML <table> element,  I got these results:
 - initial load: nsTableFrame::BuildDisplayList is called
 - return from tabstrip: nsTableFrame::BuildDisplayList is called
VS. for the attached SVG testcase...
 - initial load: nsSVGOuterSVGFrame::BuildDisplayList is called
 - return from tabstrip: nsSVGOuterSVGFrame::BuildDisplayList is NOT CALLED
That confirms that we're invalidating/painting a lot less, but I haven't decoded exactly why yet.

One more data point: comparing a pure-SVG testcase vs. SVG-in-HTML5 testcase -- when we return from the tabstrip, the pure-SVG gets a call to ViewportFrame::BuildDisplayList with an empty dirtyrect (0,0,0,0), whereas the SVG-in-HTML5 testcase gets a call with a huge dirtyrect (0,0,58800,67020).
This traces back to differing calls to nsDOMWindowUtils::SetDisplayPortForElement().
- In the HTML case, I get a call with aXPx=0, aYPx=0, aWidthPx=980, aHeightPx=1117
- In the SVG case, I get a call with aXPx=0, aYPx=0, aWidthPx=0, aHeightPx=0
OK, so this basically boils down to us assuming we're viewing an HTML document.

This traces back to this chunk of code, in TabChild.cpp:
> 411   nsCOMPtr<nsIDOMElement> htmlDOMElement = do_QueryInterface(document->GetHtmlElement());
> 412   nsCOMPtr<nsIDOMElement> bodyDOMElement = do_QueryInterface(document->GetBodyElement());
> 413 
> 414   int32_t htmlWidth = 0, htmlHeight = 0;
> 415   if (htmlDOMElement) {
> 416     htmlDOMElement->GetScrollWidth(&htmlWidth);
> 417     htmlDOMElement->GetScrollHeight(&htmlHeight);
> 418   }
> 419   int32_t bodyWidth = 0, bodyHeight = 0;
> 420   if (bodyDOMElement) {
> 421     bodyDOMElement->GetScrollWidth(&bodyWidth);
> 422     bodyDOMElement->GetScrollHeight(&bodyHeight);
> 423   }
> 424 
> 425   float pageWidth = NS_MAX(htmlWidth, bodyWidth);
> 426   float pageHeight = NS_MAX(htmlHeight, bodyHeight);

So pageWidth and pageHeight are the height of our document's <html> and/or <body> nodes. SVG doesn't have either of those nodes, of course, so these variables are left at 0 for SVG.

Then we do:
> 453   metrics.mScrollableRect = gfx::Rect(0.0f, 0.0f, pageWidth, pageHeight);

... so for SVG, that gives us a 0,0,0,0 scrollable rect, which sounds pretty likely to make us paint nothing.  Not looking good.

Sure enough, we then call AsyncPanZoomController::CalculatePendingDisplayPort() and intersect that scrollableRect with something else to generate our (empty) displayPort as follows:
> 872   displayPort = shiftedDisplayPort.Intersect(aFrameMetrics.mScrollableRect);

...and that displayPort ends up getting used for the SetDisplayPortForElement() call in comment 13, which ultimately gives us the empty-dirtyrect BuildDisplayList call from comment 12.
[Marking as depending on bug 746502, which added the first chunk of code from prev. comment]
Depends on: 746502
...and if I just blindly do the same dance with document->GetRootElement(), I still get (0,0), because nsGenericElement::ScrollWidth() and ::ScrollHeight() have early-returns for SVG, saying "if (IsSVG()) return 0;"

Maybe if we don't have a <body> or an <html> element, we should just use the full viewport. Even if that's overkill (and I don't think it is), we're just using it as a measure of the "scrollable region" of the page, and it's an accurate measure for 100%-by-100%-sized SVG content.  (Plus, we intersect it with another rect before determining our actual display port, so we're not even necessarily drawing this whole area if we don't have to -- just the intersection.)
Assignee: nobody → dholbert
Attached patch fix v1 (obsolete) — Splinter Review
This fixes it. I added two XXX comments about possible divide-by-0's in neighboring code, too. (I'll probably file followups for those -- in cases where they'd actually occur, I'm not sure it'd actually cause user-visible issues, since there probably already wouldn't be anything drawn due to the page being 0-sized. However, still good to avoid dividing by 0...)
Attachment #681905 - Flags: review?(bugs)
Component: General → DOM: Core & HTML
Product: Boot2Gecko → Core
Version: unspecified → Trunk
(Just to be clear: I've verified that "fix v1" resolves the issue w/ the attached testcase, on my unagi device)
Comment on attachment 681905 [details] [diff] [review]
fix v1

># HG changeset patch
># Parent 303a143077633076a571b674d9600b33fed57c10
># User Daniel Holbert <>
>Bug 807457: In non-HTML documents, use the viewport size as the scrollable area, in TabChild::HandlePossibleViewportChange. r?smaug
>diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp
>--- a/dom/ipc/TabChild.cpp
>+++ b/dom/ipc/TabChild.cpp
>@@ -417,22 +417,31 @@ TabChild::HandlePossibleViewportChange()
>     htmlDOMElement->GetScrollHeight(&htmlHeight);
>   }
>   int32_t bodyWidth = 0, bodyHeight = 0;
>   if (bodyDOMElement) {
>     bodyDOMElement->GetScrollWidth(&bodyWidth);
>     bodyDOMElement->GetScrollHeight(&bodyHeight);
>   }
>-  float pageWidth = NS_MAX(htmlWidth, bodyWidth);
>-  float pageHeight = NS_MAX(htmlHeight, bodyHeight);
>+  float pageWidth, pageHeight;
>+  if (htmlDOMElement || bodyDOMElement) {
>+    pageWidth = NS_MAX(htmlWidth, bodyWidth);
>+    pageHeight = NS_MAX(htmlHeight, bodyHeight);
>+  } else {
>+    // For non-HTML content (e.g. SVG), just assume page size == viewport size.
>+    pageWidth = viewportW;
>+    pageHeight = viewportH;
>+  }
I guess this could work quite well usually, but depending on the ux we want, 
this may need tweaking later. The behavior is really up to b2g people to decide.

>+  // XXXdholbert Uh oh, this could be divide-by-0...
Could you fix / 0 problem while you're here.

>   minScale = mInnerSize.width / pageWidth;
>   minScale = clamped((double)minScale, viewportInfo.minZoom, viewportInfo.maxZoom);
>+  // XXXdholbert Uh oh, this could be divide-by-0...
Could you fix / 0 problem while you're here.

I think we're in odd situation if either one is 0 and just returning is ok.
Attachment #681905 - Flags: review?(bugzilla)
Attachment #681905 - Flags: review?(bugs)
Attachment #681905 - Flags: review+
Attached patch fix v2 [r=smaug]Splinter Review
OK, I added NS_ENSURE_TRUE_VOID() calls for each of those possibly-0 variables, right after we establish their value.

Carrying forward r=smaug and smaug's r?drs.
Attachment #681905 - Attachment is obsolete: true
Attachment #681905 - Flags: review?(bugzilla)
Attachment #682036 - Flags: review?(bugzilla)
Comment on attachment 682036 [details] [diff] [review]
fix v2 [r=smaug]

Not sure about Doug's availability at the moment, so I'm r?'ing cjones as well. 

(smaug says on IRC that he'd like one of them to sign off on it, too -- so, r?'ing both of them, in the hopes that one of them can get to it soonish.)
Attachment #682036 - Flags: review?(jones.chris.g)
Attachment #682036 - Flags: review?(bugzilla) → review+
Attachment #682036 - Flags: review?(jones.chris.g)
Thanks Doug!
RyanVM tells me the "blocking-basecamp+" gives this implicit approval to land on Aurora.

I intend to backport this to Aurora in the next day or two, after it's proved itself on central.
Closed: 12 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla19
Verified fixed in latest B2G stable dogfood build:
Build Identifier 20121127132302
You need to log in before you can comment on or make changes to this bug.