| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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() ? ¤tDoc->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 Loading... |
| 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 = ¤tDoc->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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |