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

Side by Side Diff: third_party/WebKit/Source/core/dom/Fullscreen.cpp

Issue 2040973003: OOPIF: Process all local ancestors when requesting and exiting fullscreen. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add bug reference for nested fullscreen Created 4 years, 6 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
« no previous file with comments | « chrome/browser/site_per_process_interactive_browsertest.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Dirk Mueller (mueller@kde.org) 4 * (C) 2001 Dirk Mueller (mueller@kde.org)
5 * (C) 2006 Alexey Proskuryakov (ap@webkit.org) 5 * (C) 2006 Alexey Proskuryakov (ap@webkit.org)
6 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Inc. All r ights reserved. 6 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Inc. All r ights reserved.
7 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.t orchmobile.com/) 7 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.t orchmobile.com/)
8 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) 8 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
9 * Copyright (C) 2013 Google Inc. All rights reserved. 9 * Copyright (C) 2013 Google Inc. All rights reserved.
10 * 10 *
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
116 116
117 Event* createEvent(const AtomicString& type, EventTarget& target) 117 Event* createEvent(const AtomicString& type, EventTarget& target)
118 { 118 {
119 EventInit initializer; 119 EventInit initializer;
120 initializer.setBubbles(isPrefixed(type)); 120 initializer.setBubbles(isPrefixed(type));
121 Event* event = Event::create(type, initializer); 121 Event* event = Event::create(type, initializer);
122 event->setTarget(&target); 122 event->setTarget(&target);
123 return event; 123 return event;
124 } 124 }
125 125
126 // Helper to walk the ancestor chain and return the Document of the topmost
127 // local ancestor frame. Note that this is not the same as the topmost frame's
128 // Document, which might be unavailable in OOPIF scenarios. For example, with
129 // OOPIFs, when called on the bottom frame's Document in a A-B-C-B hierarchy in
130 // process B, this will skip remote frame C and return this frame: A-[B]-C-B.
131 Document& topmostLocalAncestor(Document& document)
132 {
133 Document* topmost = &document;
134 Frame* frame = document.frame();
135 while (frame) {
136 frame = frame->tree().parent();
137 if (frame && frame->isLocalFrame())
138 topmost = toLocalFrame(frame)->document();
139 }
140 return *topmost;
141 }
142
143 // Helper to find the browsing context container in |doc| that embeds the
144 // |descendant| Document, possibly through multiple levels of nesting. This
145 // works even in OOPIF scenarios like A-B-A, where there may be remote frames
146 // in between |doc| and |descendant|.
147 HTMLFrameOwnerElement* findContainerForDescendant(const Document& doc, const Doc ument& descendant)
148 {
149 Frame* frame = descendant.frame();
150 while (frame->tree().parent() != doc.frame())
151 frame = frame->tree().parent();
152 return toHTMLFrameOwnerElement(frame->owner());
153 }
154
126 } // anonymous namespace 155 } // anonymous namespace
127 156
128 const char* Fullscreen::supplementName() 157 const char* Fullscreen::supplementName()
129 { 158 {
130 return "Fullscreen"; 159 return "Fullscreen";
131 } 160 }
132 161
133 Fullscreen& Fullscreen::from(Document& document) 162 Fullscreen& Fullscreen::from(Document& document)
134 { 163 {
135 Fullscreen* fullscreen = fromIfExists(document); 164 Fullscreen* fullscreen = fromIfExists(document);
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
242 } 271 }
243 272
244 // Fullscreen is not supported. 273 // Fullscreen is not supported.
245 if (!fullscreenIsSupported(element.document())) 274 if (!fullscreenIsSupported(element.document()))
246 break; 275 break;
247 276
248 // 2. Let doc be element's node document. (i.e. "this") 277 // 2. Let doc be element's node document. (i.e. "this")
249 Document* currentDoc = document(); 278 Document* currentDoc = document();
250 279
251 // 3. Let docs be all doc's ancestor browsing context's documents (if an y) and doc. 280 // 3. Let docs be all doc's ancestor browsing context's documents (if an y) and doc.
281 //
282 // For OOPIF scenarios, |docs| will only contain documents for local
283 // ancestors, and remote ancestors will be processed in their
284 // respective processes. This preserves the spec's event firing order
285 // for local ancestors, but not for remote ancestors. However, that
286 // difference shouldn't be observable in practice: a fullscreenchange
287 // event handler would need to postMessage a frame in another renderer
288 // process, where the message should be queued up and processed after
289 // the IPC that dispatches fullscreenchange.
252 HeapDeque<Member<Document>> docs; 290 HeapDeque<Member<Document>> docs;
253 291
254 do { 292 docs.prepend(currentDoc);
255 docs.prepend(currentDoc); 293 for (Frame* frame = currentDoc->frame()->tree().parent(); frame; frame = frame->tree().parent()) {
256 currentDoc = currentDoc->localOwner() ? &currentDoc->localOwner()->d ocument() : nullptr; 294 if (frame->isLocalFrame())
257 } while (currentDoc); 295 docs.prepend(toLocalFrame(frame)->document());
296 }
258 297
259 // 4. For each document in docs, run these substeps: 298 // 4. For each document in docs, run these substeps:
260 HeapDeque<Member<Document>>::iterator current = docs.begin(), following = docs.begin(); 299 HeapDeque<Member<Document>>::iterator current = docs.begin(), following = docs.begin();
261 300
262 do { 301 do {
263 ++following; 302 ++following;
264 303
265 // 1. Let following document be the document after document in docs, or null if there is no 304 // 1. Let following document be the document after document in docs, or null if there is no
266 // such document. 305 // such document.
267 Document* currentDoc = *current; 306 Document* currentDoc = *current;
268 Document* followingDoc = following != docs.end() ? *following : null ptr; 307 Document* followingDoc = following != docs.end() ? *following : null ptr;
269 308
270 // 2. If following document is null, push context object on document 's fullscreen element 309 // 2. If following document is null, push context object on document 's fullscreen element
271 // stack, and queue a task to fire an event named fullscreenchange w ith its bubbles attribute 310 // stack, and queue a task to fire an event named fullscreenchange w ith its bubbles attribute
272 // set to true on the document. 311 // set to true on the document.
273 if (!followingDoc) { 312 if (!followingDoc) {
274 from(*currentDoc).pushFullscreenElementStack(element, requestTyp e); 313 from(*currentDoc).pushFullscreenElementStack(element, requestTyp e);
275 enqueueChangeEvent(*currentDoc, requestType); 314 enqueueChangeEvent(*currentDoc, requestType);
276 continue; 315 continue;
277 } 316 }
278 317
279 // 3. Otherwise, if document's fullscreen element stack is either em pty or its top element 318 // 3. Otherwise, if document's fullscreen element stack is either em pty or its top element
280 // is not following document's browsing context container, 319 // is not following document's browsing context container,
281 Element* topElement = fullscreenElementFrom(*currentDoc); 320 Element* topElement = fullscreenElementFrom(*currentDoc);
282 if (!topElement || topElement != followingDoc->localOwner()) { 321 HTMLFrameOwnerElement* followingOwner = findContainerForDescendant(* currentDoc, *followingDoc);
322 if (!topElement || topElement != followingOwner) {
283 // ...push following document's browsing context container on do cument's fullscreen element 323 // ...push following document's browsing context container on do cument's fullscreen element
284 // stack, and queue a task to fire an event named fullscreenchan ge with its bubbles attribute 324 // stack, and queue a task to fire an event named fullscreenchan ge with its bubbles attribute
285 // set to true on document. 325 // set to true on document.
286 from(*currentDoc).pushFullscreenElementStack(*followingDoc->loca lOwner(), requestType); 326 from(*currentDoc).pushFullscreenElementStack(*followingOwner, re questType);
287 enqueueChangeEvent(*currentDoc, requestType); 327 enqueueChangeEvent(*currentDoc, requestType);
288 continue; 328 continue;
289 } 329 }
290 330
291 // 4. Otherwise, do nothing for this document. It stays the same. 331 // 4. Otherwise, do nothing for this document. It stays the same.
292 } while (++current != docs.end()); 332 } while (++current != docs.end());
293 333
294 m_forCrossProcessAncestor = forCrossProcessAncestor; 334 m_forCrossProcessAncestor = forCrossProcessAncestor;
295 335
296 // 5. Return, and run the remaining steps asynchronously. 336 // 5. Return, and run the remaining steps asynchronously.
297 // 6. Optionally, perform some animation. 337 // 6. Optionally, perform some animation.
298 document()->frameHost()->chromeClient().enterFullScreenForElement(&eleme nt); 338 document()->frameHost()->chromeClient().enterFullScreenForElement(&eleme nt);
299 339
300 // 7. Optionally, display a message indicating how the user can exit dis playing the context object fullscreen. 340 // 7. Optionally, display a message indicating how the user can exit dis playing the context object fullscreen.
301 return; 341 return;
302 } while (false); 342 } while (false);
303 343
304 enqueueErrorEvent(element, requestType); 344 enqueueErrorEvent(element, requestType);
305 } 345 }
306 346
307 void Fullscreen::fullyExitFullscreen(Document& document) 347 void Fullscreen::fullyExitFullscreen(Document& document)
308 { 348 {
309 // To fully exit fullscreen, run these steps: 349 // To fully exit fullscreen, run these steps:
310 350
311 // 1. Let |doc| be the top-level browsing context's document. 351 // 1. Let |doc| be the top-level browsing context's document.
312 Document& doc = document.topDocument(); 352 //
353 // Since the top-level browsing context's document might be unavailable in
354 // OOPIF scenarios (i.e., when the top frame is remote), this actually uses
355 // the Document of the topmost local ancestor frame. Without OOPIF, this
356 // will be the top frame's document. With OOPIF, each renderer process for
357 // the current page will separately call fullyExitFullscreen to cover all
358 // local frames in each process.
359 Document& doc = topmostLocalAncestor(document);
313 360
314 // 2. If |doc|'s fullscreen element stack is empty, terminate these steps. 361 // 2. If |doc|'s fullscreen element stack is empty, terminate these steps.
315 if (!fullscreenElementFrom(doc)) 362 if (!fullscreenElementFrom(doc))
316 return; 363 return;
317 364
318 // 3. Remove elements from |doc|'s fullscreen element stack until only the t op element is left. 365 // 3. Remove elements from |doc|'s fullscreen element stack until only the t op element is left.
319 size_t stackSize = from(doc).m_fullScreenElementStack.size(); 366 size_t stackSize = from(doc).m_fullScreenElementStack.size();
320 from(doc).m_fullScreenElementStack.remove(0, stackSize - 1); 367 from(doc).m_fullScreenElementStack.remove(0, stackSize - 1);
321 DCHECK_EQ(from(doc).m_fullScreenElementStack.size(), 1u); 368 DCHECK_EQ(from(doc).m_fullScreenElementStack.size(), 1u);
322 369
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
371 newTop = fullscreenElementFrom(*currentDoc); 418 newTop = fullscreenElementFrom(*currentDoc);
372 if (newTop && (!newTop->inShadowIncludingDocument() || newTop->document( ) != currentDoc)) 419 if (newTop && (!newTop->inShadowIncludingDocument() || newTop->document( ) != currentDoc))
373 continue; 420 continue;
374 421
375 // 2. Queue a task to fire an event named fullscreenchange with its bubb les attribute set to true 422 // 2. Queue a task to fire an event named fullscreenchange with its bubb les attribute set to true
376 // on doc. 423 // on doc.
377 enqueueChangeEvent(*currentDoc, requestType); 424 enqueueChangeEvent(*currentDoc, requestType);
378 425
379 // 3. If doc's fullscreen element stack is empty and doc's browsing cont ext has a browsing context 426 // 3. If doc's fullscreen element stack is empty and doc's browsing cont ext has a browsing context
380 // container, set doc to that browsing context container's node document . 427 // container, set doc to that browsing context container's node document .
381 if (!newTop && currentDoc->localOwner()) { 428 //
382 currentDoc = &currentDoc->localOwner()->document(); 429 // OOPIF: If browsing context container's document is in another
383 continue; 430 // process, keep moving up the ancestor chain and looking for a
431 // browsing context container with a local document.
432 // TODO(alexmos): Deal with nested fullscreen cases, see
433 // https://crbug.com/617369.
434 if (!newTop) {
435 Frame* frame = currentDoc->frame()->tree().parent();
436 while (frame && frame->isRemoteFrame())
437 frame = frame->tree().parent();
438 if (frame) {
439 currentDoc = toLocalFrame(frame)->document();
440 continue;
441 }
384 } 442 }
385 443
386 // 4. Otherwise, set doc to null. 444 // 4. Otherwise, set doc to null.
387 currentDoc = 0; 445 currentDoc = 0;
388 } 446 }
389 447
390 // 6. Return, and run the remaining steps asynchronously. 448 // 6. Return, and run the remaining steps asynchronously.
391 // 7. Optionally, perform some animation. 449 // 7. Optionally, perform some animation.
392 450
393 FrameHost* host = document()->frameHost(); 451 FrameHost* host = document()->frameHost();
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
498 m_fullScreenElement = nullptr; 556 m_fullScreenElement = nullptr;
499 557
500 if (document()->frame()) 558 if (document()->frame())
501 document()->frame()->eventHandler().scheduleHoverStateUpdate(); 559 document()->frame()->eventHandler().scheduleHoverStateUpdate();
502 560
503 // When fullyExitFullscreen is called, we call exitFullscreen on the topDocu ment(). That means 561 // When fullyExitFullscreen is called, we call exitFullscreen on the topDocu ment(). That means
504 // that the events will be queued there. So if we have no events here, start the timer on the 562 // that the events will be queued there. So if we have no events here, start the timer on the
505 // exiting document. 563 // exiting document.
506 Document* exitingDocument = document(); 564 Document* exitingDocument = document();
507 if (m_eventQueue.isEmpty()) 565 if (m_eventQueue.isEmpty())
508 exitingDocument = &document()->topDocument(); 566 exitingDocument = &topmostLocalAncestor(*document());
509 DCHECK(exitingDocument); 567 DCHECK(exitingDocument);
510 from(*exitingDocument).m_eventQueueTimer.startOneShot(0, BLINK_FROM_HERE); 568 from(*exitingDocument).m_eventQueueTimer.startOneShot(0, BLINK_FROM_HERE);
511 569
512 m_forCrossProcessAncestor = false; 570 m_forCrossProcessAncestor = false;
513 } 571 }
514 572
515 void Fullscreen::setFullScreenLayoutObject(LayoutFullScreen* layoutObject) 573 void Fullscreen::setFullScreenLayoutObject(LayoutFullScreen* layoutObject)
516 { 574 {
517 if (layoutObject == m_fullScreenLayoutObject) 575 if (layoutObject == m_fullScreenLayoutObject)
518 return; 576 return;
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
629 DEFINE_TRACE(Fullscreen) 687 DEFINE_TRACE(Fullscreen)
630 { 688 {
631 visitor->trace(m_fullScreenElement); 689 visitor->trace(m_fullScreenElement);
632 visitor->trace(m_fullScreenElementStack); 690 visitor->trace(m_fullScreenElementStack);
633 visitor->trace(m_eventQueue); 691 visitor->trace(m_eventQueue);
634 Supplement<Document>::trace(visitor); 692 Supplement<Document>::trace(visitor);
635 ContextLifecycleObserver::trace(visitor); 693 ContextLifecycleObserver::trace(visitor);
636 } 694 }
637 695
638 } // namespace blink 696 } // namespace blink
OLDNEW
« no previous file with comments | « chrome/browser/site_per_process_interactive_browsertest.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698