Bug 779971 - Make nsSVGTextPathProperty::DoUpdate trigger nsSVGTextFrame::NotifyGlyphMetricsChange() off an asynchronous change hint (to avoid calling nsLayoutUtils::FrameNeedsReflow synchronously under nsISVGChildFrame::ReflowSVG or during frame teardown, and avoid infinite loops caused by using an event queue event). r=jwatt.

This commit is contained in:
Robert Longson
2012-11-07 09:53:44 +00:00
parent 492766236b
commit dd48a6c2c0
5 changed files with 34 additions and 34 deletions

View File

@@ -116,6 +116,7 @@
#include "nsIDOMSVGFilters.h" #include "nsIDOMSVGFilters.h"
#include "DOMSVGTests.h" #include "DOMSVGTests.h"
#include "nsSVGEffects.h" #include "nsSVGEffects.h"
#include "nsSVGTextPathFrame.h"
#include "nsSVGUtils.h" #include "nsSVGUtils.h"
#include "nsRefreshDriver.h" #include "nsRefreshDriver.h"
@@ -7797,6 +7798,12 @@ DoApplyRenderingChangeToTree(nsIFrame* aFrame,
aFrame->InvalidateFrameSubtree(); aFrame->InvalidateFrameSubtree();
} }
} }
if (aChange & nsChangeHint_UpdateTextPath) {
NS_ABORT_IF_FALSE(aFrame->GetType() == nsGkAtoms::svgTextPathFrame,
"textPath frame expected");
// Invalidate and reflow the entire nsSVGTextFrame:
static_cast<nsSVGTextPathFrame*>(aFrame)->NotifyGlyphMetricsChange();
}
if (aChange & nsChangeHint_UpdateOpacityLayer) { if (aChange & nsChangeHint_UpdateOpacityLayer) {
// FIXME/bug 796697: we can get away with empty transactions for // FIXME/bug 796697: we can get away with empty transactions for
// opacity updates in many cases. // opacity updates in many cases.

View File

@@ -110,7 +110,13 @@ enum nsChangeHint {
* changes, and it's inherited by a child, that might require a reflow * changes, and it's inherited by a child, that might require a reflow
* due to the border-width change on the child. * due to the border-width change on the child.
*/ */
nsChangeHint_BorderStyleNoneChange = 0x8000 nsChangeHint_BorderStyleNoneChange = 0x8000,
/**
* SVG textPath needs to be recomputed because the path has changed.
* This means that the glyph positions of the text need to be recomputed.
*/
nsChangeHint_UpdateTextPath = 0x10000
// IMPORTANT NOTE: When adding new hints, consider whether you need to // IMPORTANT NOTE: When adding new hints, consider whether you need to
// add them to NS_HintsNotHandledForDescendantsIn() below. // add them to NS_HintsNotHandledForDescendantsIn() below.

View File

@@ -0,0 +1,14 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="r" class="reftest-wait">
<text id="t"><textPath xlink:href="#r">x</textPath>1</text>
<script>
window.addEventListener("load", function() {
setTimeout(function() {
document.getElementById("t").lastChild.data = "2";
document.documentElement.removeAttribute("class");
}, 200);
}, false);
</script>
</svg>

After

Width:  |  Height:  |  Size: 416 B

View File

@@ -136,6 +136,7 @@ load 767056-1.svg
load 768351.svg load 768351.svg
load 780963-1.html load 780963-1.html
load 757751-1.svg load 757751-1.svg
load 779971-1.svg
load 782141-1.svg load 782141-1.svg
load 784061-1.svg load 784061-1.svg
load 790072.svg load 790072.svg

View File

@@ -286,32 +286,6 @@ nsSVGMarkerProperty::DoUpdate()
mFrame->GetContent()->AsElement(), nsRestyleHint(0), changeHint); mFrame->GetContent()->AsElement(), nsRestyleHint(0), changeHint);
} }
class nsAsyncNotifyGlyphMetricsChange MOZ_FINAL : public nsIReflowCallback
{
public:
nsAsyncNotifyGlyphMetricsChange(nsIFrame* aFrame) : mWeakFrame(aFrame)
{
}
virtual bool ReflowFinished()
{
nsSVGTextPathFrame* frame =
static_cast<nsSVGTextPathFrame*>(mWeakFrame.GetFrame());
if (frame) {
frame->NotifyGlyphMetricsChange();
}
delete this;
return true;
}
virtual void ReflowCallbackCanceled()
{
delete this;
}
nsWeakFrame mWeakFrame;
};
void void
nsSVGTextPathProperty::DoUpdate() nsSVGTextPathProperty::DoUpdate()
{ {
@@ -322,13 +296,11 @@ nsSVGTextPathProperty::DoUpdate()
NS_ASSERTION(mFrame->IsFrameOfType(nsIFrame::eSVG), "SVG frame expected"); NS_ASSERTION(mFrame->IsFrameOfType(nsIFrame::eSVG), "SVG frame expected");
if (mFrame->GetType() == nsGkAtoms::svgTextPathFrame) { if (mFrame->GetType() == nsGkAtoms::svgTextPathFrame) {
if (mFrame->PresContext()->PresShell()->IsReflowLocked()) { // Repaint asynchronously in case the path frame is being torn down
nsIReflowCallback* cb = new nsAsyncNotifyGlyphMetricsChange(mFrame); nsChangeHint changeHint =
mFrame->PresContext()->PresShell()->PostReflowCallback(cb); nsChangeHint(nsChangeHint_RepaintFrame | nsChangeHint_UpdateTextPath);
} else { mFramePresShell->FrameConstructor()->PostRestyleEvent(
nsSVGTextPathFrame* textPathFrame = static_cast<nsSVGTextPathFrame*>(mFrame); mFrame->GetContent()->AsElement(), nsRestyleHint(0), changeHint);
textPathFrame->NotifyGlyphMetricsChange();
}
} }
} }