Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(18)

Side by Side Diff: third_party/WebKit/Source/core/page/FrameTree.cpp

Issue 2714943004: Move unique name generation and tracking into //content. (Closed)
Patch Set: Rebase again. Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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,
(...skipping 30 matching lines...) Expand all
41 const unsigned invalidChildCount = ~0U; 41 const unsigned invalidChildCount = ~0U;
42 42
43 } // namespace 43 } // namespace
44 44
45 FrameTree::FrameTree(Frame* thisFrame) 45 FrameTree::FrameTree(Frame* thisFrame)
46 : m_thisFrame(thisFrame), m_scopedChildCount(invalidChildCount) {} 46 : m_thisFrame(thisFrame), m_scopedChildCount(invalidChildCount) {}
47 47
48 FrameTree::~FrameTree() {} 48 FrameTree::~FrameTree() {}
49 49
50 void FrameTree::setName(const AtomicString& name) { 50 void FrameTree::setName(const AtomicString& name) {
51 // This method should only be called for local frames
52 // (remote frames should be updated via setPrecalculatedName).
53 DCHECK(m_thisFrame->isLocalFrame());
54
55 // When this method is called, m_uniqueName should be already initialized.
56 // This assert helps ensure that early return (a few lines below) won't
57 // result in an uninitialized m_uniqueName.
58 DCHECK(!m_uniqueName.isNull() || (m_uniqueName.isNull() && !parent()));
59
60 // Do not recalculate m_uniqueName if there is no real change of m_name.
61 // This is not just a performance optimization - other code relies on the
62 // assumption that unique name shouldn't change if the assigned name didn't
63 // change (i.e. code in content::FrameTreeNode::SetFrameName).
64 if (m_name == name)
65 return;
66
67 m_name = name; 51 m_name = name;
68
69 // https://crbug.com/607205: Make sure m_uniqueName doesn't change after
70 // initial navigation - session history depends on this.
71 if (toLocalFrame(m_thisFrame)
72 ->loader()
73 .stateMachine()
74 ->committedFirstRealDocumentLoad())
75 return;
76
77 // Leave main frame's unique name set to a null string.
78 if (!parent())
79 return;
80
81 // Remove our old frame name so it's not considered in
82 // calculateUniqueNameForChildFrame call below.
83 m_uniqueName = AtomicString();
84
85 // Calculate a new unique name based on inputs.
86 setUniqueName(parent()->tree().calculateUniqueNameForChildFrame(
87 m_thisFrame, name, nullAtom));
88 }
89
90 void FrameTree::setPrecalculatedName(const AtomicString& name,
91 const AtomicString& uniqueName) {
92 m_name = name;
93
94 if (parent()) {
95 // Non-main frames should have a non-empty unique name.
96 DCHECK(!uniqueName.isEmpty());
97 } else {
98 // Unique name of main frames should always stay empty.
99 DCHECK(uniqueName.isEmpty());
100 }
101
102 // TODO(lukasza): We would like to assert uniqueness below (i.e. by calling
103 // setUniqueName), but
104 // 1) uniqueness is currently violated by provisional/old frame pairs.
105 // 2) there is an unresolved race between 2 OOPIFs, that can result in a
106 // non-unique |uniqueName| - see https://crbug.com/558680#c14.
107 m_uniqueName = uniqueName;
108 } 52 }
109 53
110 DISABLE_CFI_PERF 54 DISABLE_CFI_PERF
111 Frame* FrameTree::parent() const { 55 Frame* FrameTree::parent() const {
112 if (!m_thisFrame->client()) 56 if (!m_thisFrame->client())
113 return nullptr; 57 return nullptr;
114 return m_thisFrame->client()->parent(); 58 return m_thisFrame->client()->parent();
115 } 59 }
116 60
117 Frame* FrameTree::top() const { 61 Frame* FrameTree::top() const {
(...skipping 11 matching lines...) Expand all
129 return nullptr; 73 return nullptr;
130 return m_thisFrame->client()->nextSibling(); 74 return m_thisFrame->client()->nextSibling();
131 } 75 }
132 76
133 Frame* FrameTree::firstChild() const { 77 Frame* FrameTree::firstChild() const {
134 if (!m_thisFrame->client()) 78 if (!m_thisFrame->client())
135 return nullptr; 79 return nullptr;
136 return m_thisFrame->client()->firstChild(); 80 return m_thisFrame->client()->firstChild();
137 } 81 }
138 82
139 bool FrameTree::uniqueNameExists(const String& uniqueNameCandidate) const {
140 // This method is currently O(N), where N = number of frames in the tree.
141
142 // Before recalculating or checking unique name, we set m_uniqueName
143 // to an empty string (so the soon-to-be-removed name does not count
144 // as a collision). This means that uniqueNameExists would return
145 // false positives when called with an empty |name|.
146 DCHECK(!uniqueNameCandidate.isEmpty());
147
148 for (Frame* frame = top(); frame; frame = frame->tree().traverseNext()) {
149 if (frame->tree().uniqueName() == uniqueNameCandidate)
150 return true;
151 }
152 return false;
153 }
154
155 AtomicString FrameTree::calculateUniqueNameForNewChildFrame(
156 const AtomicString& name,
157 const AtomicString& fallbackName) const {
158 AtomicString uniqueName =
159 calculateUniqueNameForChildFrame(nullptr, name, fallbackName);
160
161 // Caller will likely set the name via setPrecalculatedName, which
162 // unfortunately cannot currently assert uniqueness of the name - let's
163 // therefore assert the uniqueness here.
164 DCHECK(!uniqueNameExists(uniqueName));
165
166 return uniqueName;
167 }
168
169 String FrameTree::generateUniqueNameCandidate(bool existingChildFrame) const {
170 const char framePathPrefix[] = "<!--framePath ";
171 const int framePathPrefixLength = 14;
172 const int framePathSuffixLength = 3;
173
174 // Find the nearest parent that has a frame with a path in it.
175 HeapVector<Member<Frame>, 16> chain;
176 Frame* frame;
177 for (frame = m_thisFrame; frame; frame = frame->tree().parent()) {
178 if (frame->tree().uniqueName().startsWith(framePathPrefix))
179 break;
180 chain.push_back(frame);
181 }
182 StringBuilder uniqueName;
183 uniqueName.append(framePathPrefix);
184 if (frame) {
185 uniqueName.append(frame->tree().uniqueName().getString().substring(
186 framePathPrefixLength, frame->tree().uniqueName().length() -
187 framePathPrefixLength -
188 framePathSuffixLength));
189 }
190 for (int i = chain.size() - 1; i >= 0; --i) {
191 frame = chain[i];
192 uniqueName.append('/');
193 uniqueName.append(frame->tree().uniqueName());
194 }
195
196 uniqueName.append("/<!--frame");
197 uniqueName.appendNumber(childCount() - (existingChildFrame ? 1 : 0));
198 uniqueName.append("-->-->");
199
200 // NOTE: This name might not be unique - see http://crbug.com/588800.
201 return uniqueName.toAtomicString();
202 }
203
204 String FrameTree::generateFramePosition(Frame* child) const {
205 // This method is currently O(N), where N = number of frames in the tree.
206
207 StringBuilder framePositionBuilder;
208 framePositionBuilder.append("<!--framePosition");
209
210 if (!child) {
211 framePositionBuilder.append('-');
212 framePositionBuilder.appendNumber(childCount());
213 child = m_thisFrame;
214 }
215
216 while (child->tree().parent()) {
217 int numberOfSiblingsBeforeChild = 0;
218 Frame* sibling = child->tree().parent()->tree().firstChild();
219 while (sibling != child) {
220 sibling = sibling->tree().nextSibling();
221 numberOfSiblingsBeforeChild++;
222 }
223
224 framePositionBuilder.append('-');
225 framePositionBuilder.appendNumber(numberOfSiblingsBeforeChild);
226
227 child = child->tree().parent();
228 }
229
230 // NOTE: The generated string is not guaranteed to be unique, but should
231 // have a better chance of being unique than the string generated by
232 // generateUniqueNameCandidate, because we embed extra information into the
233 // string:
234 // 1) we walk the full chain of ancestors, all the way to the main frame
235 // 2) we use frame-position-within-parent (aka |numberOfSiblingsBeforeChild|)
236 // instead of sibling-count.
237 return framePositionBuilder.toString();
238 }
239
240 AtomicString FrameTree::appendUniqueSuffix(
241 const String& prefix,
242 const String& likelyUniqueSuffix) const {
243 // Verify that we are not doing unnecessary work.
244 DCHECK(uniqueNameExists(prefix));
245
246 // We want unique name to be stable across page reloads - this is why
247 // we use a deterministic |numberOfTries| rather than a random number
248 // (a random number would be more likely to avoid a collision, but
249 // would change after every page reload).
250 int numberOfTries = 0;
251
252 // Keep trying |prefix| + |likelyUniqueSuffix| + |numberOfTries|
253 // concatenations until we get a truly unique name.
254 String candidate;
255 do {
256 StringBuilder uniqueNameBuilder;
257 uniqueNameBuilder.append(prefix);
258 uniqueNameBuilder.append(likelyUniqueSuffix);
259 uniqueNameBuilder.append('/');
260 uniqueNameBuilder.appendNumber(numberOfTries++);
261 uniqueNameBuilder.append("-->");
262
263 candidate = uniqueNameBuilder.toString();
264 } while (uniqueNameExists(candidate));
265 return AtomicString(candidate);
266 }
267
268 AtomicString FrameTree::calculateUniqueNameForChildFrame(
269 Frame* child,
270 const AtomicString& assignedName,
271 const AtomicString& fallbackName) const {
272 // Try to use |assignedName| (i.e. window.name or iframe.name) or
273 // |fallbackName| if possible.
274 const AtomicString& requestedName =
275 assignedName.isEmpty() ? fallbackName : assignedName;
276 if (!requestedName.isEmpty() && !uniqueNameExists(requestedName) &&
277 requestedName != "_blank")
278 return requestedName;
279
280 String candidate = generateUniqueNameCandidate(child);
281 if (!uniqueNameExists(candidate))
282 return AtomicString(candidate);
283
284 String likelyUniqueSuffix = generateFramePosition(child);
285 return appendUniqueSuffix(candidate, likelyUniqueSuffix);
286
287 // Description of the current unique name format
288 // ---------------------------------------------
289 //
290 // Changing the format of unique name is undesirable, because it breaks
291 // backcompatibility of session history (which stores unique names
292 // generated in the past on user's disk). This incremental,
293 // backcompatibility-aware approach has resulted so far in the following
294 // rather baroque format... :
295 //
296 // uniqueName ::= <nullForMainFrame> | <assignedName> | <generatedName>
297 // (generatedName is used if assignedName is
298 // non-unique / conflicts with other frame's unique name.
299 //
300 // assignedName ::= value of iframe's name attribute
301 // or value assigned to window.name (*before* the first
302 // real commit - afterwards unique name stays immutable).
303 //
304 // generatedName ::= oldGeneratedName newUniqueSuffix?
305 // (newUniqueSuffix is only present if oldGeneratedName was
306 // not unique after all)
307 //
308 // oldGeneratedName ::= "<!--framePath //" ancestorChain
309 // "/<!--frame" childCount "-->-->"
310 // (oldGeneratedName is generated by
311 // generateUniqueNameCandidate method).
312 //
313 // childCount ::= current number of siblings
314 //
315 // ancestorChain ::= concatenated unique names of ancestor chain,
316 // terminated on the first ancestor (if any) starting with
317 // "<!--framePath"; each ancestor's unique name is
318 // separated by "/" character
319 // ancestorChain example1: "grandparent/parent"
320 // (ancestor's unique names : #1--^ | #2-^ )
321 // ancestorChain example2:
322 // "<!--framePath //foo/bar/<!--frame42-->-->/blah/foobar"
323 // (ancestor's unique names:
324 // ^--#1--^ | #2 | #3-^ )
325 //
326 // newUniqueSuffix ::= "<!--framePosition" framePosition "/" retryNumber
327 // "-->"
328 //
329 // framePosition ::= "-" numberOfSiblingsBeforeChild
330 // [ framePosition-forParent? ]
331 //
332 // retryNumber ::= smallest non-negative integer resulting in unique name
333 }
334
335 void FrameTree::setUniqueName(const AtomicString& uniqueName) {
336 // Only subframes can have a non-null unique name - setUniqueName should
337 // only be called for subframes and never for a main frame.
338 DCHECK(parent());
339
340 DCHECK(!uniqueName.isEmpty() && !uniqueNameExists(uniqueName));
341 m_uniqueName = uniqueName;
342 }
343
344 Frame* FrameTree::scopedChild(unsigned index) const { 83 Frame* FrameTree::scopedChild(unsigned index) const {
345 unsigned scopedIndex = 0; 84 unsigned scopedIndex = 0;
346 for (Frame* child = firstChild(); child; 85 for (Frame* child = firstChild(); child;
347 child = child->tree().nextSibling()) { 86 child = child->tree().nextSibling()) {
348 if (child->client()->inShadowTree()) 87 if (child->client()->inShadowTree())
349 continue; 88 continue;
350 if (scopedIndex == index) 89 if (scopedIndex == index)
351 return child; 90 return child;
352 scopedIndex++; 91 scopedIndex++;
353 } 92 }
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
538 void showFrameTree(const blink::Frame* frame) { 277 void showFrameTree(const blink::Frame* frame) {
539 if (!frame) { 278 if (!frame) {
540 printf("Null input frame\n"); 279 printf("Null input frame\n");
541 return; 280 return;
542 } 281 }
543 282
544 printFrames(frame->tree().top(), frame, 0); 283 printFrames(frame->tree().top(), frame, 0);
545 } 284 }
546 285
547 #endif 286 #endif
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/page/FrameTree.h ('k') | third_party/WebKit/Source/web/LocalFrameClientImpl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698