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 String& 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 String FrameTree::generateUniqueNameCandidate(bool existingChildFrame) const |
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(); |
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 String& 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 String candidate; |
| 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 candidate = uniqueNameBuilder.toString(); |
| 267 } while (uniqueNameExists(candidate)); |
| 268 return AtomicString(candidate); |
| 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 String candidate = generateUniqueNameCandidate(child); |
| 282 if (!uniqueNameExists(candidate)) |
| 283 return AtomicString(candidate); |
| 284 |
| 285 String likelyUniqueSuffix = generateFramePosition(child); |
| 286 return appendUniqueSuffix(candidate, 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 |