Bug 1402109. Prevent crashes under SVGTextElement methods when the SVG is under non-displayed HTML. r=heycam

Summary:
The implementations of most SVGTextElement methods flush layout when they're
called.  Any SVG <text> that is displayed normally will be reflowed by
SVGTextFrame::ReflowSVG, and any <text> that is in displayed SVG but is not
displayed directly (such as <text> under a <defs>) will be reflowed by
SVGTextFrame::ReflowSVGNonDisplayText.  Prior to this fix the changed
code always assumed that one of these methods would reflow the text.  However,
in the case that the SVG is under an HTML element that isn't itself ever
reflowed (such as if it's under an HTML <caption>) then the SVG text will
not be reflowed either and the invariants of the code are broken.

This patch modifies the functions that implement the SVGTextElement
methods to return an error code if the text has not been reflowed.

Note: I did try to reuse SVGTextFrame::ReflowSVGNonDisplayText in this
case, but I ran into problems.  Given that this is an edge case and likely one
than normal authors will never run into I gave up trying to make that work for
now.

Reviewers: heycam

Bug #: 1402109

Differential Revision: https://phabricator.services.mozilla.com/D107
This commit is contained in:
Jonathan Watt 2017-09-26 14:54:27 +01:00
parent 60fa0649f2
commit 0ed5f27b33

View File

@ -3996,6 +3996,13 @@ SVGTextFrame::ConvertTextElementCharIndexToAddressableIndex(
uint32_t
SVGTextFrame::GetNumberOfChars(nsIContent* aContent)
{
nsIFrame* kid = PrincipalChildList().FirstChild();
if (NS_SUBTREE_DIRTY(kid)) {
// We're never reflowed if we're under a non-SVG element that is
// never reflowed (such as the HTML 'caption' element).
return 0;
}
UpdateGlyphPositioning();
uint32_t n = 0;
@ -4040,6 +4047,13 @@ nsresult
SVGTextFrame::SelectSubString(nsIContent* aContent,
uint32_t charnum, uint32_t nchars)
{
nsIFrame* kid = PrincipalChildList().FirstChild();
if (NS_SUBTREE_DIRTY(kid)) {
// We're never reflowed if we're under a non-SVG element that is
// never reflowed (such as the HTML 'caption' element).
return NS_ERROR_FAILURE;
}
UpdateGlyphPositioning();
// Convert charnum/nchars from addressable characters relative to
@ -4271,6 +4285,13 @@ int32_t
SVGTextFrame::GetCharNumAtPosition(nsIContent* aContent,
mozilla::nsISVGPoint* aPoint)
{
nsIFrame* kid = PrincipalChildList().FirstChild();
if (NS_SUBTREE_DIRTY(kid)) {
// We're never reflowed if we're under a non-SVG element that is
// never reflowed (such as the HTML 'caption' element).
return -1;
}
UpdateGlyphPositioning();
nsPresContext* context = PresContext();
@ -4304,6 +4325,13 @@ SVGTextFrame::GetStartPositionOfChar(nsIContent* aContent,
uint32_t aCharNum,
mozilla::nsISVGPoint** aResult)
{
nsIFrame* kid = PrincipalChildList().FirstChild();
if (NS_SUBTREE_DIRTY(kid)) {
// We're never reflowed if we're under a non-SVG element that is
// never reflowed (such as the HTML 'caption' element).
return NS_ERROR_FAILURE;
}
UpdateGlyphPositioning();
CharIterator it(this, CharIterator::eAddressable, aContent);
@ -4329,6 +4357,13 @@ SVGTextFrame::GetEndPositionOfChar(nsIContent* aContent,
uint32_t aCharNum,
mozilla::nsISVGPoint** aResult)
{
nsIFrame* kid = PrincipalChildList().FirstChild();
if (NS_SUBTREE_DIRTY(kid)) {
// We're never reflowed if we're under a non-SVG element that is
// never reflowed (such as the HTML 'caption' element).
return NS_ERROR_FAILURE;
}
UpdateGlyphPositioning();
CharIterator it(this, CharIterator::eAddressable, aContent);
@ -4366,6 +4401,13 @@ SVGTextFrame::GetExtentOfChar(nsIContent* aContent,
uint32_t aCharNum,
dom::SVGIRect** aResult)
{
nsIFrame* kid = PrincipalChildList().FirstChild();
if (NS_SUBTREE_DIRTY(kid)) {
// We're never reflowed if we're under a non-SVG element that is
// never reflowed (such as the HTML 'caption' element).
return NS_ERROR_FAILURE;
}
UpdateGlyphPositioning();
CharIterator it(this, CharIterator::eAddressable, aContent);
@ -4426,6 +4468,13 @@ SVGTextFrame::GetRotationOfChar(nsIContent* aContent,
uint32_t aCharNum,
float* aResult)
{
nsIFrame* kid = PrincipalChildList().FirstChild();
if (NS_SUBTREE_DIRTY(kid)) {
// We're never reflowed if we're under a non-SVG element that is
// never reflowed (such as the HTML 'caption' element).
return NS_ERROR_FAILURE;
}
UpdateGlyphPositioning();
CharIterator it(this, CharIterator::eAddressable, aContent);