OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (C) Research In Motion Limited 2010. All rights reserved. | 2 * Copyright (C) Research In Motion Limited 2010. All rights reserved. |
3 * Copyright (C) 2006 Apple Computer, Inc. | 3 * Copyright (C) 2006 Apple Computer, Inc. |
4 * | 4 * |
5 * This library is free software; you can redistribute it and/or | 5 * This library is free software; you can redistribute it and/or |
6 * modify it under the terms of the GNU Library General Public | 6 * modify it under the terms of the GNU Library General Public |
7 * License as published by the Free Software Foundation; either | 7 * License as published by the Free Software Foundation; either |
8 * version 2 of the License, or (at your option) any later version. | 8 * version 2 of the License, or (at your option) any later version. |
9 * | 9 * |
10 * This library is distributed in the hope that it will be useful, | 10 * This library is distributed in the hope that it will be useful, |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 * Library General Public License for more details. | 13 * Library General Public License for more details. |
14 * | 14 * |
15 * You should have received a copy of the GNU Library General Public License | 15 * You should have received a copy of the GNU Library General Public License |
16 * along with this library; see the file COPYING.LIB. If not, write to | 16 * along with this library; see the file COPYING.LIB. If not, write to |
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
18 * Boston, MA 02110-1301, USA. | 18 * Boston, MA 02110-1301, USA. |
19 */ | 19 */ |
20 | 20 |
21 #include "core/page/FrameTree.h" | 21 #include "core/page/FrameTree.h" |
22 | 22 |
23 #include "core/dom/Document.h" | 23 #include "core/dom/Document.h" |
24 #include "core/frame/FrameClient.h" | 24 #include "core/frame/FrameClient.h" |
25 #include "core/frame/FrameView.h" | 25 #include "core/frame/FrameView.h" |
26 #include "core/frame/LocalFrame.h" | 26 #include "core/frame/LocalFrame.h" |
27 #include "core/frame/RemoteFrame.h" | 27 #include "core/frame/RemoteFrame.h" |
28 #include "core/frame/RemoteFrameView.h" | 28 #include "core/frame/RemoteFrameView.h" |
29 #include "core/page/Page.h" | 29 #include "core/page/Page.h" |
30 #include "wtf/Assertions.h" | |
30 #include "wtf/Vector.h" | 31 #include "wtf/Vector.h" |
31 #include "wtf/text/CString.h" | 32 #include "wtf/text/CString.h" |
32 #include "wtf/text/StringBuilder.h" | 33 #include "wtf/text/StringBuilder.h" |
33 | 34 |
34 using std::swap; | 35 using std::swap; |
35 | 36 |
36 namespace blink { | 37 namespace blink { |
37 | 38 |
38 namespace { | 39 namespace { |
39 | 40 |
40 const unsigned invalidChildCount = ~0U; | 41 const unsigned invalidChildCount = ~0U; |
41 | 42 |
42 } // namespace | 43 } // namespace |
43 | 44 |
44 FrameTree::FrameTree(Frame* thisFrame) | 45 FrameTree::FrameTree(Frame* thisFrame) |
45 : m_thisFrame(thisFrame) | 46 : m_thisFrame(thisFrame) |
46 , m_scopedChildCount(invalidChildCount) | 47 , m_scopedChildCount(invalidChildCount) |
47 { | 48 { |
48 } | 49 } |
49 | 50 |
50 FrameTree::~FrameTree() | 51 FrameTree::~FrameTree() |
51 { | 52 { |
52 } | 53 } |
53 | 54 |
54 void FrameTree::setName(const AtomicString& name, const AtomicString& fallbackNa me) | 55 void FrameTree::setName(const AtomicString& name) |
55 { | 56 { |
56 m_name = name; | 57 m_name = name; |
57 if (!parent()) { | |
58 m_uniqueName = name; | |
59 return; | |
60 } | |
61 | 58 |
62 // Remove our old frame name so it's not considered in calculateUniqueNameFo rChildFrame. | 59 // Remove our old frame name so it's not considered in calculateUniqueNameFo rChildFrame |
60 // and appendUniqueSuffix calls below. | |
63 m_uniqueName = AtomicString(); | 61 m_uniqueName = AtomicString(); |
64 | 62 |
65 m_uniqueName = parent()->tree().calculateUniqueNameForChildFrame(true, name, fallbackName); | 63 // Calculate a new unique name based on inputs. |
64 if (parent()) { | |
65 setUniqueName( | |
66 parent()->tree().calculateUniqueNameForChildFrame(m_thisFrame, name, nullAtom)); | |
67 } else if (name.isEmpty() || !uniqueNameExists(name)) { | |
68 // Only main frame can have an empty unique name, so for main frames | |
69 // emptiness guarantees uniquness. | |
70 setUniqueName(name); | |
71 } else { | |
72 setUniqueName(appendUniqueSuffix(name, "<!--framePosition")); | |
73 } | |
66 } | 74 } |
67 | 75 |
68 void FrameTree::setPrecalculatedName(const AtomicString& name, const AtomicStrin g& uniqueName) | 76 void FrameTree::setPrecalculatedName(const AtomicString& name, const AtomicStrin g& uniqueName) |
69 { | 77 { |
70 if (!parent()) { | 78 if (!parent()) { |
71 ASSERT(uniqueName == name); | 79 DCHECK(uniqueName == name); |
72 } else { | 80 } else { |
73 ASSERT(!uniqueName.isEmpty()); | 81 DCHECK(!uniqueName.isEmpty()); |
74 } | 82 } |
75 | 83 |
76 m_name = name; | 84 m_name = name; |
85 | |
86 // TODO(lukasza): We would like to assert uniqueness below (i.e. by calling | |
87 // setUniqueName), but | |
88 // 1) uniqueness is currently violated by provisional/old frame pairs. | |
89 // 2) there is an unresolved race between 2 OOPIFs, that can result in a | |
90 // non-unique |uniqueName| - see https://crbug.com/558680#c14. | |
77 m_uniqueName = uniqueName; | 91 m_uniqueName = uniqueName; |
78 } | 92 } |
79 | 93 |
80 Frame* FrameTree::parent() const | 94 Frame* FrameTree::parent() const |
81 { | 95 { |
82 if (!m_thisFrame->client()) | 96 if (!m_thisFrame->client()) |
83 return nullptr; | 97 return nullptr; |
84 return m_thisFrame->client()->parent(); | 98 return m_thisFrame->client()->parent(); |
85 } | 99 } |
86 | 100 |
(...skipping 29 matching lines...) Expand all Loading... | |
116 return m_thisFrame->client()->firstChild(); | 130 return m_thisFrame->client()->firstChild(); |
117 } | 131 } |
118 | 132 |
119 Frame* FrameTree::lastChild() const | 133 Frame* FrameTree::lastChild() const |
120 { | 134 { |
121 if (!m_thisFrame->client()) | 135 if (!m_thisFrame->client()) |
122 return nullptr; | 136 return nullptr; |
123 return m_thisFrame->client()->lastChild(); | 137 return m_thisFrame->client()->lastChild(); |
124 } | 138 } |
125 | 139 |
126 bool FrameTree::uniqueNameExists(const AtomicString& name) const | 140 bool FrameTree::uniqueNameExists(const AtomicString& uniqueNameCandidate) const |
127 { | 141 { |
142 // This method is currently O(N), where N = number of frames in the tree. | |
143 | |
144 // Before recalculating or checking unique name, we set m_uniqueName | |
145 // to an empty string (so the soon-to-be-removed name does not count | |
146 // as a collision). This means that uniqueNameExists would return | |
147 // false positives when called with an empty |name|. | |
148 DCHECK(!uniqueNameCandidate.isEmpty()); | |
149 | |
128 for (Frame* frame = top(); frame; frame = frame->tree().traverseNext()) { | 150 for (Frame* frame = top(); frame; frame = frame->tree().traverseNext()) { |
129 if (frame->tree().uniqueName() == name) | 151 if (frame->tree().uniqueName() == uniqueNameCandidate) |
130 return true; | 152 return true; |
131 } | 153 } |
132 return false; | 154 return false; |
133 } | 155 } |
134 | 156 |
135 AtomicString FrameTree::calculateUniqueNameForNewChildFrame( | 157 AtomicString FrameTree::calculateUniqueNameForNewChildFrame( |
136 const AtomicString& name, | 158 const AtomicString& name, |
137 const AtomicString& fallbackName) const | 159 const AtomicString& fallbackName) const |
138 { | 160 { |
139 return calculateUniqueNameForChildFrame(false, name, fallbackName); | 161 AtomicString uniqueName = calculateUniqueNameForChildFrame(nullptr, name, fa llbackName); |
162 | |
163 // Caller will likely set the name via setPrecalculatedName, which | |
164 // unfortunately cannot currently assert uniqueness of the name - let's | |
165 // therefore assert the uniqueness here. | |
166 DCHECK(!uniqueNameExists(uniqueName)); | |
167 | |
168 return uniqueName; | |
140 } | 169 } |
141 | 170 |
142 AtomicString FrameTree::calculateUniqueNameForChildFrame( | 171 AtomicString FrameTree::generateUniqueNameCandidate(bool existingChildFrame) con st |
143 bool existingChildFrame, | |
144 const AtomicString& name, | |
145 const AtomicString& fallbackName) const | |
146 { | 172 { |
147 const AtomicString& requestedName = name.isEmpty() ? fallbackName : name; | |
148 if (!requestedName.isEmpty() && !uniqueNameExists(requestedName) && requeste dName != "_blank") | |
149 return requestedName; | |
150 | |
151 // Create a repeatable name for a child about to be added to us. The name mu st be | |
152 // unique within the frame tree. The string we generate includes a "path" of names | |
153 // from the root frame down to us. For this path to be unique, each set of s iblings must | |
154 // contribute a unique name to the path, which can't collide with any HTML-a ssigned names. | |
155 // We generate this path component by index in the child list along with an unlikely | |
156 // frame name that can't be set in HTML because it collides with comment syn tax. | |
157 | |
158 const char framePathPrefix[] = "<!--framePath "; | 173 const char framePathPrefix[] = "<!--framePath "; |
159 const int framePathPrefixLength = 14; | 174 const int framePathPrefixLength = 14; |
160 const int framePathSuffixLength = 3; | 175 const int framePathSuffixLength = 3; |
161 | 176 |
162 // Find the nearest parent that has a frame with a path in it. | 177 // Find the nearest parent that has a frame with a path in it. |
163 HeapVector<Member<Frame>, 16> chain; | 178 HeapVector<Member<Frame>, 16> chain; |
164 Frame* frame; | 179 Frame* frame; |
165 for (frame = m_thisFrame; frame; frame = frame->tree().parent()) { | 180 for (frame = m_thisFrame; frame; frame = frame->tree().parent()) { |
166 if (frame->tree().uniqueName().startsWith(framePathPrefix)) | 181 if (frame->tree().uniqueName().startsWith(framePathPrefix)) |
167 break; | 182 break; |
168 chain.append(frame); | 183 chain.append(frame); |
169 } | 184 } |
170 StringBuilder uniqueName; | 185 StringBuilder uniqueName; |
171 uniqueName.append(framePathPrefix); | 186 uniqueName.append(framePathPrefix); |
172 if (frame) { | 187 if (frame) { |
173 uniqueName.append(frame->tree().uniqueName().getString().substring(frame PathPrefixLength, | 188 uniqueName.append(frame->tree().uniqueName().getString().substring(frame PathPrefixLength, |
174 frame->tree().uniqueName().length() - framePathPrefixLength - frameP athSuffixLength)); | 189 frame->tree().uniqueName().length() - framePathPrefixLength - frameP athSuffixLength)); |
175 } | 190 } |
176 for (int i = chain.size() - 1; i >= 0; --i) { | 191 for (int i = chain.size() - 1; i >= 0; --i) { |
177 frame = chain[i]; | 192 frame = chain[i]; |
178 uniqueName.append('/'); | 193 uniqueName.append('/'); |
179 uniqueName.append(frame->tree().uniqueName()); | 194 uniqueName.append(frame->tree().uniqueName()); |
180 } | 195 } |
181 | 196 |
182 uniqueName.appendLiteral("/<!--frame"); | 197 uniqueName.appendLiteral("/<!--frame"); |
183 uniqueName.appendNumber(childCount() - (existingChildFrame ? 1 : 0)); | 198 uniqueName.appendNumber(childCount() - (existingChildFrame ? 1 : 0)); |
184 uniqueName.appendLiteral("-->-->"); | 199 uniqueName.appendLiteral("-->-->"); |
185 | 200 |
201 // NOTE: This name might not be unique - see http://crbug.com/588800. | |
186 return uniqueName.toAtomicString(); | 202 return uniqueName.toAtomicString(); |
dcheng
2016/06/01 20:58:11
Let's have this return a String rather than an Ato
Łukasz Anforowicz
2016/06/01 22:31:29
Done.
| |
187 } | 203 } |
188 | 204 |
205 String FrameTree::generateFramePosition(Frame* child) const | |
206 { | |
207 // This method is currently O(N), where N = number of frames in the tree. | |
208 | |
209 StringBuilder framePositionBuilder; | |
210 framePositionBuilder.append("<!--framePosition"); | |
211 | |
212 if (!child) { | |
213 framePositionBuilder.append('-'); | |
214 framePositionBuilder.appendNumber(childCount()); | |
215 child = m_thisFrame; | |
216 } | |
217 | |
218 while (child->tree().parent()) { | |
219 int numberOfSiblingsBeforeChild = 0; | |
220 Frame* sibling = child->tree().previousSibling(); | |
221 while (sibling) { | |
222 sibling = sibling->tree().previousSibling(); | |
223 numberOfSiblingsBeforeChild++; | |
224 } | |
225 | |
226 framePositionBuilder.append('-'); | |
227 framePositionBuilder.appendNumber(numberOfSiblingsBeforeChild); | |
228 | |
229 child = child->tree().parent(); | |
230 } | |
231 | |
232 // NOTE: The generated string is not guaranteed to be unique, but should | |
233 // have a better chance of being unique than the string generated by | |
234 // generateUniqueNameCandidate, because we embed extra information into the | |
235 // string: | |
236 // 1) we walk the full chain of ancestors, all the way to the main frame | |
237 // 2) we use frame-position-within-parent (aka |numberOfSiblingsBeforeChild| ) | |
238 // instead of sibling-count. | |
239 return framePositionBuilder.toString(); | |
240 } | |
241 | |
242 AtomicString FrameTree::appendUniqueSuffix( | |
243 const AtomicString& prefix, | |
244 const String& likelyUniqueSuffix) const | |
245 { | |
246 // Verify that we are not doing unnecessary work. | |
247 DCHECK(uniqueNameExists(prefix)); | |
248 | |
249 // We want unique name to be stable across page reloads - this is why | |
250 // we use a deterministic |numberOfTries| rather than a random number | |
251 // (a random number would be more likely to avoid a collision, but | |
252 // would change after every page reload). | |
253 int numberOfTries = 0; | |
254 | |
255 // Keep trying |prefix| + |likelyUniqueSuffix| + |numberOfTries| | |
256 // concatenations until we get a truly unique name. | |
257 AtomicString uniqueNameCandidate; | |
dcheng
2016/06/01 20:58:11
Nit: Omit |uniqueName| here and just call it |cand
Łukasz Anforowicz
2016/06/01 22:31:28
Done.
| |
258 do { | |
259 StringBuilder uniqueNameBuilder; | |
260 uniqueNameBuilder.append(prefix); | |
261 uniqueNameBuilder.append(likelyUniqueSuffix); | |
262 uniqueNameBuilder.append('/'); | |
263 uniqueNameBuilder.appendNumber(numberOfTries++); | |
264 uniqueNameBuilder.append("-->"); | |
265 | |
266 uniqueNameCandidate = uniqueNameBuilder.toAtomicString(); | |
dcheng
2016/06/01 20:58:11
Let's not convert to an atomic string until we ret
Łukasz Anforowicz
2016/06/01 22:31:29
Done.
| |
267 } while (uniqueNameExists(uniqueNameCandidate)); | |
268 return uniqueNameCandidate; | |
269 } | |
270 | |
271 AtomicString FrameTree::calculateUniqueNameForChildFrame( | |
272 Frame* child, | |
273 const AtomicString& assignedName, | |
274 const AtomicString& fallbackName) const | |
275 { | |
276 // Try to use |assignedName| (i.e. window.name or iframe.name) or |fallbackN ame| if possible. | |
277 const AtomicString& requestedName = assignedName.isEmpty() ? fallbackName : assignedName; | |
278 if (!requestedName.isEmpty() && !uniqueNameExists(requestedName) && requeste dName != "_blank") | |
279 return requestedName; | |
280 | |
281 AtomicString uniqueNameCandidate = generateUniqueNameCandidate(child); | |
282 if (!uniqueNameExists(uniqueNameCandidate)) | |
283 return uniqueNameCandidate; | |
284 | |
285 String likelyUniqueSuffix = generateFramePosition(child); | |
286 return appendUniqueSuffix(uniqueNameCandidate, likelyUniqueSuffix); | |
287 | |
288 // Description of the current unique name format | |
289 // --------------------------------------------- | |
290 // | |
291 // Changing the format of unique name is undesirable, because it breaks | |
292 // backcompatibility of session history (which stores unique names | |
293 // generated in the past on user's disk). This incremental, | |
294 // backcompatibility-aware approach has resulted so far in the following | |
295 // rather baroque format... : | |
296 // | |
297 // uniqueName ::= <assignedName> | <generatedName> | |
298 // (generatedName is used if assignedName is | |
299 // 1) non-unique / conflicts with other frame's unique name or | |
300 // 2) assignedName is empty for a non-main frame) | |
301 // | |
302 // assignedName ::= value of iframe's name attribute | |
303 // or value assigned to window.name | |
304 // | |
305 // generatedName ::= oldGeneratedName newUniqueSuffix? | |
306 // (newUniqueSuffix is only present if oldGeneratedName was | |
307 // not unique after all) | |
308 // | |
309 // oldGeneratedName ::= "<!--framePath //" ancestorChain "/<!--frame" chil dCount "-->-->" | |
310 // (main frame is special - oldGeneratedName for main frame | |
311 // is always the frame's assignedName; oldGeneratedName is | |
312 // generated by generateUniqueNameCandidate method). | |
313 // | |
314 // childCount ::= current number of siblings | |
315 // | |
316 // ancestorChain ::= concatenated unique names of ancestor chain, | |
317 // terminated on the first ancestor (if any) starting wi th "<!--framePath" | |
318 // each ancestor's unique name is separated by "/" chara cter | |
319 // ancestorChain example1: "grandparent/parent" | |
320 // (ancestor's unique names : #1--^ | #2-^ ) | |
321 // ancestorChain example2: "<!--framePath //foo/bar/<!--frame42-->-->/blah /foobar" | |
322 // (ancestor's unique names : ^--#1--^ | #2 | #3-^ ) | |
323 // | |
324 // newUniqueSuffix ::= "<!--framePosition" framePosition "/" retryNumber " -->" | |
325 // | |
326 // framePosition ::= "-" numberOfSiblingsBeforeChild [ framePosition-forPa rent? ] | |
327 // | <empty string for main frame> | |
328 // | |
329 // retryNumber ::= smallest non-negative integer resulting in unique name | |
330 } | |
331 | |
332 void FrameTree::setUniqueName(const AtomicString& uniqueName) | |
333 { | |
334 // Main frame is the only frame that can have an empty unique name. | |
335 if (parent()) { | |
336 DCHECK(!uniqueName.isEmpty() && !uniqueNameExists(uniqueName)); | |
337 } else { | |
338 DCHECK(uniqueName.isEmpty() || !uniqueNameExists(uniqueName)); | |
339 } | |
340 | |
341 m_uniqueName = uniqueName; | |
342 } | |
343 | |
189 Frame* FrameTree::scopedChild(unsigned index) const | 344 Frame* FrameTree::scopedChild(unsigned index) const |
190 { | 345 { |
191 unsigned scopedIndex = 0; | 346 unsigned scopedIndex = 0; |
192 for (Frame* child = firstChild(); child; child = child->tree().nextSibling() ) { | 347 for (Frame* child = firstChild(); child; child = child->tree().nextSibling() ) { |
193 if (child->client()->inShadowTree()) | 348 if (child->client()->inShadowTree()) |
194 continue; | 349 continue; |
195 if (scopedIndex == index) | 350 if (scopedIndex == index) |
196 return child; | 351 return child; |
197 scopedIndex++; | 352 scopedIndex++; |
198 } | 353 } |
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
422 { | 577 { |
423 if (!frame) { | 578 if (!frame) { |
424 printf("Null input frame\n"); | 579 printf("Null input frame\n"); |
425 return; | 580 return; |
426 } | 581 } |
427 | 582 |
428 printFrames(frame->tree().top(), frame, 0); | 583 printFrames(frame->tree().top(), frame, 0); |
429 } | 584 } |
430 | 585 |
431 #endif | 586 #endif |
OLD | NEW |