1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Dirk Mueller (mueller@kde.org)
5 * (C) 2006 Alexey Proskuryakov (ap@webkit.org)
6 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Inc. All rights reserved.
7 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
8 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
9 * Copyright (C) 2013 Google Inc. All rights reserved.
10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public License
22 * along with this library; see the file COPYING.LIB. If not, write to
23 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24 * Boston, MA 02110-1301, USA.
25 *
26 */
27
28 #include "config.h"
29 #include "core/dom/FullscreenElementStack.h"
30
31 #include "core/HTMLNames.h"
32 #include "core/dom/Document.h"
33 #include "core/events/Event.h"
34 #include "core/frame/FrameHost.h"
35 #include "core/frame/LocalFrame.h"
36 #include "core/frame/Settings.h"
37 #include "core/frame/UseCounter.h"
38 #include "core/html/HTMLFrameOwnerElement.h"
39 #include "core/html/HTMLMediaElement.h"
40 #include "core/page/Chrome.h"
41 #include "core/page/ChromeClient.h"
42 #include "core/rendering/RenderFullScreen.h"
43 #include "platform/UserGestureIndicator.h"
44
45 namespace WebCore {
46
47 using namespace HTMLNames;
48
fullscreenIsAllowedForAllOwners(const Document & document)49 static bool fullscreenIsAllowedForAllOwners(const Document& document)
50 {
51 const HTMLFrameOwnerElement* owner = document.ownerElement();
52 if (!owner)
53 return true;
54 do {
55 if (!owner->hasAttribute(allowfullscreenAttr)) {
56 if (owner->hasAttribute(webkitallowfullscreenAttr))
57 UseCounter::count(document, UseCounter::PrefixedAllowFullscreenAttribute);
58 else
59 return false;
60 }
61 } while ((owner = owner->document().ownerElement()));
62 return true;
63 }
64
fullscreenIsSupported(const Document & document)65 static bool fullscreenIsSupported(const Document& document)
66 {
67 // Fullscreen is supported if there is no previously-established user preference,
68 // security risk, or platform limitation.
69 return !document.settings() || document.settings()->fullscreenSupported();
70 }
71
fullscreenIsSupported(const Document & document,const Element & element)72 static bool fullscreenIsSupported(const Document& document, const Element& element)
73 {
74 if (!document.settings() || (document.settings()->disallowFullscreenForNonMediaElements() && !isHTMLMediaElement(element)))
75 return false;
76 return fullscreenIsSupported(document);
77 }
78
supplementName()79 const char* FullscreenElementStack::supplementName()
80 {
81 return "FullscreenElementStack";
82 }
83
from(Document & document)84 FullscreenElementStack& FullscreenElementStack::from(Document& document)
85 {
86 FullscreenElementStack* fullscreen = fromIfExists(document);
87 if (!fullscreen) {
88 fullscreen = new FullscreenElementStack(document);
89 DocumentSupplement::provideTo(document, supplementName(), adoptPtrWillBeNoop(fullscreen));
90 }
91
92 return *fullscreen;
93 }
94
fromIfExistsSlow(Document & document)95 FullscreenElementStack* FullscreenElementStack::fromIfExistsSlow(Document& document)
96 {
97 return static_cast<FullscreenElementStack*>(DocumentSupplement::from(document, supplementName()));
98 }
99
fullscreenElementFrom(Document & document)100 Element* FullscreenElementStack::fullscreenElementFrom(Document& document)
101 {
102 if (FullscreenElementStack* found = fromIfExists(document))
103 return found->webkitFullscreenElement();
104 return 0;
105 }
106
currentFullScreenElementFrom(Document & document)107 Element* FullscreenElementStack::currentFullScreenElementFrom(Document& document)
108 {
109 if (FullscreenElementStack* found = fromIfExists(document))
110 return found->webkitCurrentFullScreenElement();
111 return 0;
112 }
113
isFullScreen(Document & document)114 bool FullscreenElementStack::isFullScreen(Document& document)
115 {
116 if (FullscreenElementStack* found = fromIfExists(document))
117 return found->webkitIsFullScreen();
118 return false;
119 }
120
FullscreenElementStack(Document & document)121 FullscreenElementStack::FullscreenElementStack(Document& document)
122 : DocumentLifecycleObserver(&document)
123 , m_areKeysEnabledInFullScreen(false)
124 , m_fullScreenRenderer(0)
125 , m_fullScreenChangeDelayTimer(this, &FullscreenElementStack::fullScreenChangeDelayTimerFired)
126 {
127 document.setHasFullscreenElementStack();
128 }
129
~FullscreenElementStack()130 FullscreenElementStack::~FullscreenElementStack()
131 {
132 }
133
document()134 inline Document* FullscreenElementStack::document()
135 {
136 return lifecycleContext();
137 }
138
documentWasDetached()139 void FullscreenElementStack::documentWasDetached()
140 {
141 m_fullScreenChangeEventTargetQueue.clear();
142 m_fullScreenErrorEventTargetQueue.clear();
143
144 if (m_fullScreenRenderer)
145 m_fullScreenRenderer->destroy();
146
147 #if ENABLE(OILPAN)
148 m_fullScreenElement = nullptr;
149 m_fullScreenElementStack.clear();
150 #endif
151
152 }
153
154 #if !ENABLE(OILPAN)
documentWasDisposed()155 void FullscreenElementStack::documentWasDisposed()
156 {
157 // NOTE: the context dispose phase is not supported in oilpan. Please
158 // consider using the detach phase instead.
159 m_fullScreenElement = nullptr;
160 m_fullScreenElementStack.clear();
161 }
162 #endif
163
fullScreenIsAllowedForElement(Element * element) const164 bool FullscreenElementStack::fullScreenIsAllowedForElement(Element* element) const
165 {
166 ASSERT(element);
167 return fullscreenIsAllowedForAllOwners(element->document());
168 }
169
requestFullScreenForElement(Element * element,unsigned short flags,FullScreenCheckType checkType)170 void FullscreenElementStack::requestFullScreenForElement(Element* element, unsigned short flags, FullScreenCheckType checkType)
171 {
172 // Ignore this request if the document is not in a live frame.
173 if (!document()->isActive())
174 return;
175
176 // The Mozilla Full Screen API <https://wiki.mozilla.org/Gecko:FullScreenAPI> has different requirements
177 // for full screen mode, and do not have the concept of a full screen element stack.
178 bool inLegacyMozillaMode = (flags & Element::LEGACY_MOZILLA_REQUEST);
179
180 do {
181 if (!element)
182 element = document()->documentElement();
183
184 // 1. If any of the following conditions are true, terminate these steps and queue a task to fire
185 // an event named fullscreenerror with its bubbles attribute set to true on the context object's
186 // node document:
187
188 // The context object is not in a document.
189 if (!element->inDocument())
190 break;
191
192 // The context object's node document, or an ancestor browsing context's document does not have
193 // the fullscreen enabled flag set.
194 if (checkType == EnforceIFrameAllowFullScreenRequirement && !fullScreenIsAllowedForElement(element))
195 break;
196
197 // The context object's node document fullscreen element stack is not empty and its top element
198 // is not an ancestor of the context object. (NOTE: Ignore this requirement if the request was
199 // made via the legacy Mozilla-style API.)
200 if (!m_fullScreenElementStack.isEmpty() && !inLegacyMozillaMode) {
201 Element* lastElementOnStack = m_fullScreenElementStack.last().get();
202 if (lastElementOnStack == element || !lastElementOnStack->contains(element))
203 break;
204 }
205
206 // A descendant browsing context's document has a non-empty fullscreen element stack.
207 bool descendentHasNonEmptyStack = false;
208 for (Frame* descendant = document()->frame() ? document()->frame()->tree().traverseNext() : 0; descendant; descendant = descendant->tree().traverseNext()) {
209 if (!descendant->isLocalFrame())
210 continue;
211 ASSERT(toLocalFrame(descendant)->document());
212 if (fullscreenElementFrom(*toLocalFrame(descendant)->document())) {
213 descendentHasNonEmptyStack = true;
214 break;
215 }
216 }
217 if (descendentHasNonEmptyStack && !inLegacyMozillaMode)
218 break;
219
220 // This algorithm is not allowed to show a pop-up:
221 // An algorithm is allowed to show a pop-up if, in the task in which the algorithm is running, either:
222 // - an activation behavior is currently being processed whose click event was trusted, or
223 // - the event listener for a trusted click event is being handled.
224 if (!UserGestureIndicator::processingUserGesture())
225 break;
226
227 // Fullscreen is not supported.
228 if (document() && !fullscreenIsSupported(*document(), *element))
229 break;
230
231 // 2. Let doc be element's node document. (i.e. "this")
232 Document* currentDoc = document();
233
234 // 3. Let docs be all doc's ancestor browsing context's documents (if any) and doc.
235 Deque<Document*> docs;
236
237 do {
238 docs.prepend(currentDoc);
239 currentDoc = currentDoc->ownerElement() ? ¤tDoc->ownerElement()->document() : 0;
240 } while (currentDoc);
241
242 // 4. For each document in docs, run these substeps:
243 Deque<Document*>::iterator current = docs.begin(), following = docs.begin();
244
245 do {
246 ++following;
247
248 // 1. Let following document be the document after document in docs, or null if there is no
249 // such document.
250 Document* currentDoc = *current;
251 Document* followingDoc = following != docs.end() ? *following : 0;
252
253 // 2. If following document is null, push context object on document's fullscreen element
254 // stack, and queue a task to fire an event named fullscreenchange with its bubbles attribute
255 // set to true on the document.
256 if (!followingDoc) {
257 from(*currentDoc).pushFullscreenElementStack(element);
258 addDocumentToFullScreenChangeEventQueue(currentDoc);
259 continue;
260 }
261
262 // 3. Otherwise, if document's fullscreen element stack is either empty or its top element
263 // is not following document's browsing context container,
264 Element* topElement = fullscreenElementFrom(*currentDoc);
265 if (!topElement || topElement != followingDoc->ownerElement()) {
266 // ...push following document's browsing context container on document's fullscreen element
267 // stack, and queue a task to fire an event named fullscreenchange with its bubbles attribute
268 // set to true on document.
269 from(*currentDoc).pushFullscreenElementStack(followingDoc->ownerElement());
270 addDocumentToFullScreenChangeEventQueue(currentDoc);
271 continue;
272 }
273
274 // 4. Otherwise, do nothing for this document. It stays the same.
275 } while (++current != docs.end());
276
277 // 5. Return, and run the remaining steps asynchronously.
278 // 6. Optionally, perform some animation.
279 m_areKeysEnabledInFullScreen = flags & Element::ALLOW_KEYBOARD_INPUT;
280 document()->frameHost()->chrome().client().enterFullScreenForElement(element);
281
282 // 7. Optionally, display a message indicating how the user can exit displaying the context object fullscreen.
283 return;
284 } while (0);
285
286 m_fullScreenErrorEventTargetQueue.append(element ? element : document()->documentElement());
287 m_fullScreenChangeDelayTimer.startOneShot(0, FROM_HERE);
288 }
289
webkitCancelFullScreen()290 void FullscreenElementStack::webkitCancelFullScreen()
291 {
292 // The Mozilla "cancelFullScreen()" API behaves like the W3C "fully exit fullscreen" behavior, which
293 // is defined as:
294 // "To fully exit fullscreen act as if the exitFullscreen() method was invoked on the top-level browsing
295 // context's document and subsequently empty that document's fullscreen element stack."
296 if (!fullscreenElementFrom(document()->topDocument()))
297 return;
298
299 // To achieve that aim, remove all the elements from the top document's stack except for the first before
300 // calling webkitExitFullscreen():
301 WillBeHeapVector<RefPtrWillBeMember<Element> > replacementFullscreenElementStack;
302 replacementFullscreenElementStack.append(fullscreenElementFrom(document()->topDocument()));
303 FullscreenElementStack& topFullscreenElementStack = from(document()->topDocument());
304 topFullscreenElementStack.m_fullScreenElementStack.swap(replacementFullscreenElementStack);
305 topFullscreenElementStack.webkitExitFullscreen();
306 }
307
webkitExitFullscreen()308 void FullscreenElementStack::webkitExitFullscreen()
309 {
310 // The exitFullscreen() method must run these steps:
311
312 // 1. Let doc be the context object. (i.e. "this")
313 Document* currentDoc = document();
314 if (!currentDoc->isActive())
315 return;
316
317 // 2. If doc's fullscreen element stack is empty, terminate these steps.
318 if (m_fullScreenElementStack.isEmpty())
319 return;
320
321 // 3. Let descendants be all the doc's descendant browsing context's documents with a non-empty fullscreen
322 // element stack (if any), ordered so that the child of the doc is last and the document furthest
323 // away from the doc is first.
324 WillBeHeapDeque<RefPtrWillBeMember<Document> > descendants;
325 for (Frame* descendant = document()->frame() ? document()->frame()->tree().traverseNext() : 0; descendant; descendant = descendant->tree().traverseNext()) {
326 if (!descendant->isLocalFrame())
327 continue;
328 ASSERT(toLocalFrame(descendant)->document());
329 if (fullscreenElementFrom(*toLocalFrame(descendant)->document()))
330 descendants.prepend(toLocalFrame(descendant)->document());
331 }
332
333 // 4. For each descendant in descendants, empty descendant's fullscreen element stack, and queue a
334 // task to fire an event named fullscreenchange with its bubbles attribute set to true on descendant.
335 for (WillBeHeapDeque<RefPtrWillBeMember<Document> >::iterator i = descendants.begin(); i != descendants.end(); ++i) {
336 ASSERT(*i);
337 from(**i).clearFullscreenElementStack();
338 addDocumentToFullScreenChangeEventQueue(i->get());
339 }
340
341 // 5. While doc is not null, run these substeps:
342 Element* newTop = 0;
343 while (currentDoc) {
344 // 1. Pop the top element of doc's fullscreen element stack.
345 from(*currentDoc).popFullscreenElementStack();
346
347 // If doc's fullscreen element stack is non-empty and the element now at the top is either
348 // not in a document or its node document is not doc, repeat this substep.
349 newTop = fullscreenElementFrom(*currentDoc);
350 if (newTop && (!newTop->inDocument() || newTop->document() != currentDoc))
351 continue;
352
353 // 2. Queue a task to fire an event named fullscreenchange with its bubbles attribute set to true
354 // on doc.
355 addDocumentToFullScreenChangeEventQueue(currentDoc);
356
357 // 3. If doc's fullscreen element stack is empty and doc's browsing context has a browsing context
358 // container, set doc to that browsing context container's node document.
359 if (!newTop && currentDoc->ownerElement()) {
360 currentDoc = ¤tDoc->ownerElement()->document();
361 continue;
362 }
363
364 // 4. Otherwise, set doc to null.
365 currentDoc = 0;
366 }
367
368 // 6. Return, and run the remaining steps asynchronously.
369 // 7. Optionally, perform some animation.
370
371 FrameHost* host = document()->frameHost();
372
373 // Speculative fix for engaget.com/videos per crbug.com/336239.
374 // FIXME: This check is wrong. We ASSERT(document->isActive()) above
375 // so this should be redundant and should be removed!
376 if (!host)
377 return;
378
379 // Only exit out of full screen window mode if there are no remaining elements in the
380 // full screen stack.
381 if (!newTop) {
382 host->chrome().client().exitFullScreenForElement(m_fullScreenElement.get());
383 return;
384 }
385
386 // Otherwise, notify the chrome of the new full screen element.
387 host->chrome().client().enterFullScreenForElement(newTop);
388 }
389
webkitFullscreenEnabled(Document & document)390 bool FullscreenElementStack::webkitFullscreenEnabled(Document& document)
391 {
392 // 4. The fullscreenEnabled attribute must return true if the context object has its
393 // fullscreen enabled flag set and fullscreen is supported, and false otherwise.
394
395 // Top-level browsing contexts are implied to have their allowFullScreen attribute set.
396 return fullscreenIsAllowedForAllOwners(document) && fullscreenIsSupported(document);
397 }
398
webkitWillEnterFullScreenForElement(Element * element)399 void FullscreenElementStack::webkitWillEnterFullScreenForElement(Element* element)
400 {
401 ASSERT(element);
402 if (!document()->isActive())
403 return;
404
405 if (m_fullScreenRenderer)
406 m_fullScreenRenderer->unwrapRenderer();
407
408 m_fullScreenElement = element;
409
410 // Create a placeholder block for a the full-screen element, to keep the page from reflowing
411 // when the element is removed from the normal flow. Only do this for a RenderBox, as only
412 // a box will have a frameRect. The placeholder will be created in setFullScreenRenderer()
413 // during layout.
414 RenderObject* renderer = m_fullScreenElement->renderer();
415 bool shouldCreatePlaceholder = renderer && renderer->isBox();
416 if (shouldCreatePlaceholder) {
417 m_savedPlaceholderFrameRect = toRenderBox(renderer)->frameRect();
418 m_savedPlaceholderRenderStyle = RenderStyle::clone(renderer->style());
419 }
420
421 if (m_fullScreenElement != document()->documentElement())
422 RenderFullScreen::wrapRenderer(renderer, renderer ? renderer->parent() : 0, document());
423
424 m_fullScreenElement->setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(true);
425
426 // FIXME: This should not call updateStyleIfNeeded.
427 document()->setNeedsStyleRecalc(SubtreeStyleChange);
428 document()->updateRenderTreeIfNeeded();
429 }
430
webkitDidEnterFullScreenForElement(Element *)431 void FullscreenElementStack::webkitDidEnterFullScreenForElement(Element*)
432 {
433 if (!m_fullScreenElement)
434 return;
435
436 if (!document()->isActive())
437 return;
438
439 m_fullScreenElement->didBecomeFullscreenElement();
440
441 m_fullScreenChangeDelayTimer.startOneShot(0, FROM_HERE);
442 }
443
webkitWillExitFullScreenForElement(Element *)444 void FullscreenElementStack::webkitWillExitFullScreenForElement(Element*)
445 {
446 if (!m_fullScreenElement)
447 return;
448
449 if (!document()->isActive())
450 return;
451
452 m_fullScreenElement->willStopBeingFullscreenElement();
453 }
454
webkitDidExitFullScreenForElement(Element *)455 void FullscreenElementStack::webkitDidExitFullScreenForElement(Element*)
456 {
457 if (!m_fullScreenElement)
458 return;
459
460 if (!document()->isActive())
461 return;
462
463 m_fullScreenElement->setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(false);
464
465 m_areKeysEnabledInFullScreen = false;
466
467 if (m_fullScreenRenderer)
468 m_fullScreenRenderer->unwrapRenderer();
469
470 m_fullScreenElement = nullptr;
471 document()->setNeedsStyleRecalc(SubtreeStyleChange);
472
473 // When webkitCancelFullScreen is called, we call webkitExitFullScreen on the topDocument(). That
474 // means that the events will be queued there. So if we have no events here, start the timer on
475 // the exiting document.
476 Document* exitingDocument = document();
477 if (m_fullScreenChangeEventTargetQueue.isEmpty() && m_fullScreenErrorEventTargetQueue.isEmpty())
478 exitingDocument = &document()->topDocument();
479 ASSERT(exitingDocument);
480 from(*exitingDocument).m_fullScreenChangeDelayTimer.startOneShot(0, FROM_HERE);
481 }
482
setFullScreenRenderer(RenderFullScreen * renderer)483 void FullscreenElementStack::setFullScreenRenderer(RenderFullScreen* renderer)
484 {
485 if (renderer == m_fullScreenRenderer)
486 return;
487
488 if (renderer && m_savedPlaceholderRenderStyle) {
489 renderer->createPlaceholder(m_savedPlaceholderRenderStyle.release(), m_savedPlaceholderFrameRect);
490 } else if (renderer && m_fullScreenRenderer && m_fullScreenRenderer->placeholder()) {
491 RenderBlock* placeholder = m_fullScreenRenderer->placeholder();
492 renderer->createPlaceholder(RenderStyle::clone(placeholder->style()), placeholder->frameRect());
493 }
494
495 if (m_fullScreenRenderer)
496 m_fullScreenRenderer->unwrapRenderer();
497 ASSERT(!m_fullScreenRenderer);
498
499 m_fullScreenRenderer = renderer;
500 }
501
fullScreenRendererDestroyed()502 void FullscreenElementStack::fullScreenRendererDestroyed()
503 {
504 m_fullScreenRenderer = 0;
505 }
506
fullScreenChangeDelayTimerFired(Timer<FullscreenElementStack> *)507 void FullscreenElementStack::fullScreenChangeDelayTimerFired(Timer<FullscreenElementStack>*)
508 {
509 // Since we dispatch events in this function, it's possible that the
510 // document will be detached and GC'd. We protect it here to make sure we
511 // can finish the function successfully.
512 RefPtrWillBeRawPtr<Document> protectDocument(document());
513 WillBeHeapDeque<RefPtrWillBeMember<Node> > changeQueue;
514 m_fullScreenChangeEventTargetQueue.swap(changeQueue);
515 WillBeHeapDeque<RefPtrWillBeMember<Node> > errorQueue;
516 m_fullScreenErrorEventTargetQueue.swap(errorQueue);
517
518 while (!changeQueue.isEmpty()) {
519 RefPtrWillBeRawPtr<Node> node = changeQueue.takeFirst();
520 if (!node)
521 node = document()->documentElement();
522 // The dispatchEvent below may have blown away our documentElement.
523 if (!node)
524 continue;
525
526 // If the element was removed from our tree, also message the documentElement. Since we may
527 // have a document hierarchy, check that node isn't in another document.
528 if (!document()->contains(node.get()) && !node->inDocument())
529 changeQueue.append(document()->documentElement());
530
531 node->dispatchEvent(Event::createBubble(EventTypeNames::webkitfullscreenchange));
532 }
533
534 while (!errorQueue.isEmpty()) {
535 RefPtrWillBeRawPtr<Node> node = errorQueue.takeFirst();
536 if (!node)
537 node = document()->documentElement();
538 // The dispatchEvent below may have blown away our documentElement.
539 if (!node)
540 continue;
541
542 // If the element was removed from our tree, also message the documentElement. Since we may
543 // have a document hierarchy, check that node isn't in another document.
544 if (!document()->contains(node.get()) && !node->inDocument())
545 errorQueue.append(document()->documentElement());
546
547 node->dispatchEvent(Event::createBubble(EventTypeNames::webkitfullscreenerror));
548 }
549 }
550
fullScreenElementRemoved()551 void FullscreenElementStack::fullScreenElementRemoved()
552 {
553 m_fullScreenElement->setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(false);
554 webkitCancelFullScreen();
555 }
556
removeFullScreenElementOfSubtree(Node * node,bool amongChildrenOnly)557 void FullscreenElementStack::removeFullScreenElementOfSubtree(Node* node, bool amongChildrenOnly)
558 {
559 if (!m_fullScreenElement)
560 return;
561
562 // If the node isn't in a document it can't have a fullscreen'd child.
563 if (!node->inDocument())
564 return;
565
566 bool elementInSubtree = false;
567 if (amongChildrenOnly)
568 elementInSubtree = m_fullScreenElement->isDescendantOf(node);
569 else
570 elementInSubtree = (m_fullScreenElement == node) || m_fullScreenElement->isDescendantOf(node);
571
572 if (elementInSubtree)
573 fullScreenElementRemoved();
574 }
575
clearFullscreenElementStack()576 void FullscreenElementStack::clearFullscreenElementStack()
577 {
578 m_fullScreenElementStack.clear();
579 }
580
popFullscreenElementStack()581 void FullscreenElementStack::popFullscreenElementStack()
582 {
583 if (m_fullScreenElementStack.isEmpty())
584 return;
585
586 m_fullScreenElementStack.removeLast();
587 }
588
pushFullscreenElementStack(Element * element)589 void FullscreenElementStack::pushFullscreenElementStack(Element* element)
590 {
591 m_fullScreenElementStack.append(element);
592 }
593
addDocumentToFullScreenChangeEventQueue(Document * doc)594 void FullscreenElementStack::addDocumentToFullScreenChangeEventQueue(Document* doc)
595 {
596 ASSERT(doc);
597
598 Node* target = 0;
599 if (FullscreenElementStack* fullscreen = fromIfExists(*doc)) {
600 target = fullscreen->webkitFullscreenElement();
601 if (!target)
602 target = fullscreen->webkitCurrentFullScreenElement();
603 }
604
605 if (!target)
606 target = doc;
607 m_fullScreenChangeEventTargetQueue.append(target);
608 }
609
trace(Visitor * visitor)610 void FullscreenElementStack::trace(Visitor* visitor)
611 {
612 visitor->trace(m_fullScreenElement);
613 visitor->trace(m_fullScreenElementStack);
614 visitor->trace(m_fullScreenChangeEventTargetQueue);
615 visitor->trace(m_fullScreenErrorEventTargetQueue);
616 DocumentSupplement::trace(visitor);
617 }
618
619 } // namespace WebCore
620