Bug 1149542 - Part 1: Return early from SVG text layout if we discover mPositions is not long enough. r=dholbert

This commit is contained in:
Cameron McCormack 2015-04-06 09:11:55 -04:00
parent f6c6dbdb46
commit ab6dc93a51
2 changed files with 56 additions and 26 deletions

View File

@ -16,6 +16,7 @@
#include "LookAndFeel.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/PatternHelpers.h"
#include "mozilla/Likely.h"
#include "nsAlgorithm.h"
#include "nsBlockFrame.h"
#include "nsCaret.h"
@ -4376,23 +4377,28 @@ ShouldStartRunAtIndex(const nsTArray<CharPosition>& aPositions,
return false;
}
uint32_t
SVGTextFrame::ResolvePositions(nsIContent* aContent,
uint32_t aIndex,
bool aInTextPath,
bool& aForceStartOfChunk,
nsTArray<gfxPoint>& aDeltas)
bool
SVGTextFrame::ResolvePositionsForNode(nsIContent* aContent,
uint32_t& aIndex,
bool aInTextPath,
bool& aForceStartOfChunk,
nsTArray<gfxPoint>& aDeltas)
{
if (aContent->IsNodeOfType(nsINode::eTEXT)) {
// We found a text node.
uint32_t length = static_cast<nsTextNode*>(aContent)->TextLength();
if (length) {
uint32_t end = aIndex + length;
if (MOZ_UNLIKELY(end > mPositions.Length())) {
MOZ_ASSERT_UNREACHABLE("length of mPositions does not match characters "
"found by iterating content");
return false;
}
if (aForceStartOfChunk) {
// Note this character as starting a new anchored chunk.
mPositions[aIndex].mStartOfChunk = true;
aForceStartOfChunk = false;
}
uint32_t end = aIndex + length;
while (aIndex < end) {
// Record whether each of these characters should start a new rendered
// run. That is always the case for characters on a text path.
@ -4405,18 +4411,23 @@ SVGTextFrame::ResolvePositions(nsIContent* aContent,
aIndex++;
}
}
return aIndex;
return true;
}
// Skip past elements that aren't text content elements.
if (!IsTextContentElement(aContent)) {
return aIndex;
return true;
}
if (aContent->IsSVGElement(nsGkAtoms::textPath)) {
// <textPath> elements are as if they are specified with x="0" y="0", but
// only if they actually have some text content.
if (HasTextContent(aContent)) {
if (MOZ_UNLIKELY(aIndex >= mPositions.Length())) {
MOZ_ASSERT_UNREACHABLE("length of mPositions does not match characters "
"found by iterating content");
return false;
}
mPositions[aIndex].mPosition = gfxPoint();
mPositions[aIndex].mStartOfChunk = true;
}
@ -4436,8 +4447,14 @@ SVGTextFrame::ResolvePositions(nsIContent* aContent,
rotate = &animatedRotate->GetAnimValue();
}
uint32_t count = GetTextContentLength(aContent);
bool percentages = false;
uint32_t count = GetTextContentLength(aContent);
if (MOZ_UNLIKELY(aIndex + count > mPositions.Length())) {
MOZ_ASSERT_UNREACHABLE("length of mPositions does not match characters "
"found by iterating content");
return false;
}
// New text anchoring chunks start at each character assigned a position
// with x="" or y="", or if we forced one with aForceStartOfChunk due to
@ -4516,8 +4533,11 @@ SVGTextFrame::ResolvePositions(nsIContent* aContent,
for (nsIContent* child = aContent->GetFirstChild();
child;
child = child->GetNextSibling()) {
aIndex = ResolvePositions(child, aIndex, inTextPath, aForceStartOfChunk,
aDeltas);
bool ok = ResolvePositionsForNode(child, aIndex, inTextPath,
aForceStartOfChunk, aDeltas);
if (!ok) {
return false;
}
}
if (aContent->IsSVGElement(nsGkAtoms::textPath)) {
@ -4525,7 +4545,7 @@ SVGTextFrame::ResolvePositions(nsIContent* aContent,
aForceStartOfChunk = true;
}
return aIndex;
return true;
}
bool
@ -4561,8 +4581,10 @@ SVGTextFrame::ResolvePositions(nsTArray<gfxPoint>& aDeltas,
// Recurse over the content and fill in character positions as we go.
bool forceStartOfChunk = false;
return ResolvePositions(mContent, 0, aRunPerGlyph,
forceStartOfChunk, aDeltas) != 0;
index = 0;
bool ok = ResolvePositionsForNode(mContent, index, aRunPerGlyph,
forceStartOfChunk, aDeltas);
return ok && index > 0;
}
void
@ -5015,9 +5037,10 @@ SVGTextFrame::DoGlyphPositioning()
// Get the x, y, dx, dy, rotate values for the subtree.
nsTArray<gfxPoint> deltas;
if (!ResolvePositions(deltas, adjustingTextLength)) {
// If ResolvePositions returned false, it means that there were some
// characters in the DOM but none of them are displayed. Clear out
// mPositions so that we don't attempt to do any painting later.
// If ResolvePositions returned false, it means either there were some
// characters in the DOM but none of them are displayed, or there was
// an error in processing mPositions. Clear out mPositions so that we don't
// attempt to do any painting later.
mPositions.Clear();
return;
}

View File

@ -516,15 +516,18 @@ private:
* Recursive helper for ResolvePositions below.
*
* @param aContent The current node.
* @param aIndex The current character index.
* @param aIndex (in/out) The current character index.
* @param aInTextPath Whether we are currently under a <textPath> element.
* @param aForceStartOfChunk Whether the next character we find should start a
* new anchored chunk.
* @return The character index we got up to.
* @param aForceStartOfChunk (in/out) Whether the next character we find
* should start a new anchored chunk.
* @param aDeltas (in/out) Receives the resolved dx/dy values for each
* character.
* @return false if we discover that mPositions did not have enough
* elements; true otherwise.
*/
uint32_t ResolvePositions(nsIContent* aContent, uint32_t aIndex,
bool aInTextPath, bool& aForceStartOfChunk,
nsTArray<gfxPoint>& aDeltas);
bool ResolvePositionsForNode(nsIContent* aContent, uint32_t& aIndex,
bool aInTextPath, bool& aForceStartOfChunk,
nsTArray<gfxPoint>& aDeltas);
/**
* Initializes mPositions with character position information based on
@ -532,9 +535,13 @@ private:
* was not given for that character. Also fills aDeltas with values based on
* dx/dy attributes.
*
* @param aDeltas (in/out) Receives the resolved dx/dy values for each
* character.
* @param aRunPerGlyph Whether mPositions should record that a new run begins
* at each glyph.
* @return True if we recorded any positions.
* @return false if we did not record any positions (due to having no
* displayed characters) or if we discover that mPositions did not have
* enough elements; true otherwise.
*/
bool ResolvePositions(nsTArray<gfxPoint>& aDeltas, bool aRunPerGlyph);