1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
|
From 0bd8486f4088c0845514986f61861688e0be011d Mon Sep 17 00:00:00 2001
From: Cameron McCormack <cam@mcc.id.au>
Date: Mon, 6 Apr 2015 09:11:55 -0400
Subject: [PATCH] Bug 1149542 - Part 1: Return early from SVG text layout if we
discover mPositions is not long enough. r=dholbert, a=sledru
---
layout/svg/SVGTextFrame.cpp | 59 +++++++++++++++++++++++++++++++--------------
layout/svg/SVGTextFrame.h | 23 ++++++++++++------
2 files changed, 56 insertions(+), 26 deletions(-)
diff --git a/layout/svg/SVGTextFrame.cpp b/layout/svg/SVGTextFrame.cpp
index 721e699..45327881 100644
--- a/layout/svg/SVGTextFrame.cpp
+++ b/layout/svg/SVGTextFrame.cpp
@@ -14,6 +14,7 @@
#include "gfxTypes.h"
#include "LookAndFeel.h"
#include "mozilla/gfx/2D.h"
+#include "mozilla/Likely.h"
#include "nsAlgorithm.h"
#include "nsBlockFrame.h"
#include "nsCaret.h"
@@ -4316,23 +4317,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.
@@ -4345,18 +4351,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->Tag() == 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;
}
@@ -4376,8 +4387,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
@@ -4456,8 +4473,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->Tag() == nsGkAtoms::textPath) {
@@ -4465,7 +4485,7 @@ SVGTextFrame::ResolvePositions(nsIContent* aContent,
aForceStartOfChunk = true;
}
- return aIndex;
+ return true;
}
bool
@@ -4501,8 +4521,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
@@ -4958,9 +4980,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;
}
diff --git a/layout/svg/SVGTextFrame.h b/layout/svg/SVGTextFrame.h
index 48951f7..912af8b 100644
--- a/layout/svg/SVGTextFrame.h
+++ b/layout/svg/SVGTextFrame.h
@@ -505,15 +505,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
@@ -521,9 +524,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);
--
2.2.1
|