| OLD | NEW |
| (Empty) |
| 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 r
ights reserved. | |
| 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) | |
| 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/HTMLIFrameElement.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 blink { | |
| 46 | |
| 47 using namespace HTMLNames; | |
| 48 | |
| 49 static bool fullscreenIsAllowedForAllOwners(const Document& document) | |
| 50 { | |
| 51 for (const HTMLFrameOwnerElement* owner = document.ownerElement(); owner; ow
ner = owner->document().ownerElement()) { | |
| 52 if (!isHTMLIFrameElement(owner)) | |
| 53 return false; | |
| 54 if (!owner->hasAttribute(allowfullscreenAttr)) | |
| 55 return false; | |
| 56 } | |
| 57 return true; | |
| 58 } | |
| 59 | |
| 60 static bool fullscreenIsSupported(const Document& document) | |
| 61 { | |
| 62 // Fullscreen is supported if there is no previously-established user prefer
ence, | |
| 63 // security risk, or platform limitation. | |
| 64 return !document.settings() || document.settings()->fullscreenSupported(); | |
| 65 } | |
| 66 | |
| 67 static bool fullscreenIsSupported(const Document& document, const Element& eleme
nt) | |
| 68 { | |
| 69 if (!document.settings() || (document.settings()->disallowFullscreenForNonMe
diaElements() && !isHTMLMediaElement(element))) | |
| 70 return false; | |
| 71 return fullscreenIsSupported(document); | |
| 72 } | |
| 73 | |
| 74 static bool isPrefixed(const AtomicString& type) | |
| 75 { | |
| 76 return type == EventTypeNames::webkitfullscreenchange || type == EventTypeNa
mes::webkitfullscreenerror; | |
| 77 } | |
| 78 | |
| 79 static PassRefPtrWillBeRawPtr<Event> createEvent(const AtomicString& type, Event
Target& target) | |
| 80 { | |
| 81 EventInit initializer; | |
| 82 initializer.bubbles = isPrefixed(type); | |
| 83 RefPtrWillBeRawPtr<Event> event = Event::create(type, initializer); | |
| 84 event->setTarget(&target); | |
| 85 return event; | |
| 86 } | |
| 87 | |
| 88 const char* FullscreenElementStack::supplementName() | |
| 89 { | |
| 90 return "FullscreenElementStack"; | |
| 91 } | |
| 92 | |
| 93 FullscreenElementStack& FullscreenElementStack::from(Document& document) | |
| 94 { | |
| 95 FullscreenElementStack* fullscreen = fromIfExists(document); | |
| 96 if (!fullscreen) { | |
| 97 fullscreen = new FullscreenElementStack(document); | |
| 98 DocumentSupplement::provideTo(document, supplementName(), adoptPtrWillBe
Noop(fullscreen)); | |
| 99 } | |
| 100 | |
| 101 return *fullscreen; | |
| 102 } | |
| 103 | |
| 104 FullscreenElementStack* FullscreenElementStack::fromIfExistsSlow(Document& docum
ent) | |
| 105 { | |
| 106 return static_cast<FullscreenElementStack*>(DocumentSupplement::from(documen
t, supplementName())); | |
| 107 } | |
| 108 | |
| 109 Element* FullscreenElementStack::fullscreenElementFrom(Document& document) | |
| 110 { | |
| 111 if (FullscreenElementStack* found = fromIfExists(document)) | |
| 112 return found->fullscreenElement(); | |
| 113 return 0; | |
| 114 } | |
| 115 | |
| 116 Element* FullscreenElementStack::currentFullScreenElementFrom(Document& document
) | |
| 117 { | |
| 118 if (FullscreenElementStack* found = fromIfExists(document)) | |
| 119 return found->webkitCurrentFullScreenElement(); | |
| 120 return 0; | |
| 121 } | |
| 122 | |
| 123 bool FullscreenElementStack::isFullScreen(Document& document) | |
| 124 { | |
| 125 if (FullscreenElementStack* found = fromIfExists(document)) | |
| 126 return found->webkitIsFullScreen(); | |
| 127 return false; | |
| 128 } | |
| 129 | |
| 130 FullscreenElementStack::FullscreenElementStack(Document& document) | |
| 131 : DocumentLifecycleObserver(&document) | |
| 132 , m_areKeysEnabledInFullScreen(false) | |
| 133 , m_fullScreenRenderer(nullptr) | |
| 134 , m_eventQueueTimer(this, &FullscreenElementStack::eventQueueTimerFired) | |
| 135 { | |
| 136 document.setHasFullscreenElementStack(); | |
| 137 } | |
| 138 | |
| 139 FullscreenElementStack::~FullscreenElementStack() | |
| 140 { | |
| 141 } | |
| 142 | |
| 143 inline Document* FullscreenElementStack::document() | |
| 144 { | |
| 145 return lifecycleContext(); | |
| 146 } | |
| 147 | |
| 148 void FullscreenElementStack::documentWasDetached() | |
| 149 { | |
| 150 m_eventQueue.clear(); | |
| 151 | |
| 152 if (m_fullScreenRenderer) | |
| 153 m_fullScreenRenderer->destroy(); | |
| 154 | |
| 155 #if ENABLE(OILPAN) | |
| 156 m_fullScreenElement = nullptr; | |
| 157 m_fullScreenElementStack.clear(); | |
| 158 #endif | |
| 159 | |
| 160 } | |
| 161 | |
| 162 #if !ENABLE(OILPAN) | |
| 163 void FullscreenElementStack::documentWasDisposed() | |
| 164 { | |
| 165 // NOTE: the context dispose phase is not supported in oilpan. Please | |
| 166 // consider using the detach phase instead. | |
| 167 m_fullScreenElement = nullptr; | |
| 168 m_fullScreenElementStack.clear(); | |
| 169 } | |
| 170 #endif | |
| 171 | |
| 172 bool FullscreenElementStack::elementReady(Element& element, RequestType requestT
ype) | |
| 173 { | |
| 174 // A fullscreen element ready check for an element |element| returns true if
all of the | |
| 175 // following are true, and false otherwise: | |
| 176 | |
| 177 // |element| is in a document. | |
| 178 if (!element.inDocument()) | |
| 179 return false; | |
| 180 | |
| 181 // |element|'s node document's fullscreen enabled flag is set. | |
| 182 if (!fullscreenIsAllowedForAllOwners(element.document())) { | |
| 183 if (requestType == PrefixedVideoRequest) | |
| 184 UseCounter::count(element.document(), UseCounter::VideoFullscreenAll
owedExemption); | |
| 185 else | |
| 186 return false; | |
| 187 } | |
| 188 | |
| 189 // |element|'s node document's fullscreen element stack is either empty or i
ts top element is an | |
| 190 // ancestor of |element|. | |
| 191 if (Element* topElement = fullscreenElementFrom(element.document())) { | |
| 192 if (!element.isDescendantOf(topElement)) | |
| 193 return false; | |
| 194 } | |
| 195 | |
| 196 // |element| has no ancestor element whose local name is iframe and namespac
e is the HTML | |
| 197 // namespace. | |
| 198 if (Traversal<HTMLIFrameElement>::firstAncestor(element)) | |
| 199 return false; | |
| 200 | |
| 201 return true; | |
| 202 } | |
| 203 | |
| 204 void FullscreenElementStack::requestFullscreen(Element& element, RequestType req
uestType) | |
| 205 { | |
| 206 // Ignore this request if the document is not in a live frame. | |
| 207 if (!document()->isActive()) | |
| 208 return; | |
| 209 | |
| 210 do { | |
| 211 // 1. If any of the following conditions are true, terminate these steps
and queue a task to fire | |
| 212 // an event named fullscreenerror with its bubbles attribute set to true
on the context object's | |
| 213 // node document: | |
| 214 | |
| 215 // The fullscreen element ready check returns false. | |
| 216 if (!elementReady(element, requestType)) | |
| 217 break; | |
| 218 | |
| 219 // This algorithm is not allowed to show a pop-up: | |
| 220 // An algorithm is allowed to show a pop-up if, in the task in which t
he algorithm is running, either: | |
| 221 // - an activation behavior is currently being processed whose click e
vent was trusted, or | |
| 222 // - the event listener for a trusted click event is being handled. | |
| 223 if (!UserGestureIndicator::processingUserGesture()) | |
| 224 break; | |
| 225 | |
| 226 // Fullscreen is not supported. | |
| 227 if (!fullscreenIsSupported(element.document(), element)) | |
| 228 break; | |
| 229 | |
| 230 // 2. Let doc be element's node document. (i.e. "this") | |
| 231 Document* currentDoc = document(); | |
| 232 | |
| 233 // 3. Let docs be all doc's ancestor browsing context's documents (if an
y) and doc. | |
| 234 Deque<Document*> docs; | |
| 235 | |
| 236 do { | |
| 237 docs.prepend(currentDoc); | |
| 238 currentDoc = currentDoc->ownerElement() ? ¤tDoc->ownerElement(
)->document() : 0; | |
| 239 } while (currentDoc); | |
| 240 | |
| 241 // 4. For each document in docs, run these substeps: | |
| 242 Deque<Document*>::iterator current = docs.begin(), following = docs.begi
n(); | |
| 243 | |
| 244 do { | |
| 245 ++following; | |
| 246 | |
| 247 // 1. Let following document be the document after document in docs,
or null if there is no | |
| 248 // such document. | |
| 249 Document* currentDoc = *current; | |
| 250 Document* followingDoc = following != docs.end() ? *following : 0; | |
| 251 | |
| 252 // 2. If following document is null, push context object on document
's fullscreen element | |
| 253 // stack, and queue a task to fire an event named fullscreenchange w
ith its bubbles attribute | |
| 254 // set to true on the document. | |
| 255 if (!followingDoc) { | |
| 256 from(*currentDoc).pushFullscreenElementStack(element, requestTyp
e); | |
| 257 enqueueChangeEvent(*currentDoc, requestType); | |
| 258 continue; | |
| 259 } | |
| 260 | |
| 261 // 3. Otherwise, if document's fullscreen element stack is either em
pty or its top element | |
| 262 // is not following document's browsing context container, | |
| 263 Element* topElement = fullscreenElementFrom(*currentDoc); | |
| 264 if (!topElement || topElement != followingDoc->ownerElement()) { | |
| 265 // ...push following document's browsing context container on do
cument's fullscreen element | |
| 266 // stack, and queue a task to fire an event named fullscreenchan
ge with its bubbles attribute | |
| 267 // set to true on document. | |
| 268 from(*currentDoc).pushFullscreenElementStack(*followingDoc->owne
rElement(), requestType); | |
| 269 enqueueChangeEvent(*currentDoc, requestType); | |
| 270 continue; | |
| 271 } | |
| 272 | |
| 273 // 4. Otherwise, do nothing for this document. It stays the same. | |
| 274 } while (++current != docs.end()); | |
| 275 | |
| 276 // 5. Return, and run the remaining steps asynchronously. | |
| 277 // 6. Optionally, perform some animation. | |
| 278 m_areKeysEnabledInFullScreen = requestType != PrefixedMozillaRequest &&
requestType != PrefixedVideoRequest; | |
| 279 document()->frameHost()->chrome().client().enterFullScreenForElement(&el
ement); | |
| 280 | |
| 281 // 7. Optionally, display a message indicating how the user can exit dis
playing the context object fullscreen. | |
| 282 return; | |
| 283 } while (0); | |
| 284 | |
| 285 enqueueErrorEvent(element, requestType); | |
| 286 } | |
| 287 | |
| 288 void FullscreenElementStack::fullyExitFullscreen() | |
| 289 { | |
| 290 // "To fully exit fullscreen act as if the exitFullscreen() method was invok
ed on the top-level browsing | |
| 291 // context's document and subsequently empty that document's fullscreen elem
ent stack." | |
| 292 if (!fullscreenElementFrom(document()->topDocument())) | |
| 293 return; | |
| 294 | |
| 295 // To achieve that aim, remove all the elements from the top document's stac
k except for the first before | |
| 296 // calling exitFullscreen(): | |
| 297 WillBeHeapVector<std::pair<RefPtrWillBeMember<Element>, RequestType> > repla
cementFullscreenElementStack; | |
| 298 FullscreenElementStack& topFullscreenElementStack = from(document()->topDocu
ment()); | |
| 299 replacementFullscreenElementStack.append(topFullscreenElementStack.m_fullScr
eenElementStack.last()); | |
| 300 topFullscreenElementStack.m_fullScreenElementStack.swap(replacementFullscree
nElementStack); | |
| 301 topFullscreenElementStack.exitFullscreen(); | |
| 302 } | |
| 303 | |
| 304 void FullscreenElementStack::exitFullscreen() | |
| 305 { | |
| 306 // The exitFullscreen() method must run these steps: | |
| 307 | |
| 308 // 1. Let doc be the context object. (i.e. "this") | |
| 309 Document* currentDoc = document(); | |
| 310 if (!currentDoc->isActive()) | |
| 311 return; | |
| 312 | |
| 313 // 2. If doc's fullscreen element stack is empty, terminate these steps. | |
| 314 if (m_fullScreenElementStack.isEmpty()) | |
| 315 return; | |
| 316 | |
| 317 // 3. Let descendants be all the doc's descendant browsing context's documen
ts with a non-empty fullscreen | |
| 318 // element stack (if any), ordered so that the child of the doc is last and
the document furthest | |
| 319 // away from the doc is first. | |
| 320 WillBeHeapDeque<RefPtrWillBeMember<Document> > descendants; | |
| 321 for (Frame* descendant = document()->frame() ? document()->frame()->tree().t
raverseNext() : 0; descendant; descendant = descendant->tree().traverseNext()) { | |
| 322 if (!descendant->isLocalFrame()) | |
| 323 continue; | |
| 324 ASSERT(toLocalFrame(descendant)->document()); | |
| 325 if (fullscreenElementFrom(*toLocalFrame(descendant)->document())) | |
| 326 descendants.prepend(toLocalFrame(descendant)->document()); | |
| 327 } | |
| 328 | |
| 329 // 4. For each descendant in descendants, empty descendant's fullscreen elem
ent stack, and queue a | |
| 330 // task to fire an event named fullscreenchange with its bubbles attribute s
et to true on descendant. | |
| 331 for (WillBeHeapDeque<RefPtrWillBeMember<Document> >::iterator i = descendant
s.begin(); i != descendants.end(); ++i) { | |
| 332 ASSERT(*i); | |
| 333 RequestType requestType = from(**i).m_fullScreenElementStack.last().seco
nd; | |
| 334 from(**i).clearFullscreenElementStack(); | |
| 335 enqueueChangeEvent(**i, requestType); | |
| 336 } | |
| 337 | |
| 338 // 5. While doc is not null, run these substeps: | |
| 339 Element* newTop = 0; | |
| 340 while (currentDoc) { | |
| 341 RequestType requestType = from(*currentDoc).m_fullScreenElementStack.las
t().second; | |
| 342 | |
| 343 // 1. Pop the top element of doc's fullscreen element stack. | |
| 344 from(*currentDoc).popFullscreenElementStack(); | |
| 345 | |
| 346 // If doc's fullscreen element stack is non-empty and the element now
at the top is either | |
| 347 // not in a document or its node document is not doc, repeat this sub
step. | |
| 348 newTop = fullscreenElementFrom(*currentDoc); | |
| 349 if (newTop && (!newTop->inDocument() || newTop->document() != currentDoc
)) | |
| 350 continue; | |
| 351 | |
| 352 // 2. Queue a task to fire an event named fullscreenchange with its bubb
les attribute set to true | |
| 353 // on doc. | |
| 354 enqueueChangeEvent(*currentDoc, requestType); | |
| 355 | |
| 356 // 3. If doc's fullscreen element stack is empty and doc's browsing cont
ext has a browsing context | |
| 357 // container, set doc to that browsing context container's node document
. | |
| 358 if (!newTop && currentDoc->ownerElement()) { | |
| 359 currentDoc = ¤tDoc->ownerElement()->document(); | |
| 360 continue; | |
| 361 } | |
| 362 | |
| 363 // 4. Otherwise, set doc to null. | |
| 364 currentDoc = 0; | |
| 365 } | |
| 366 | |
| 367 // 6. Return, and run the remaining steps asynchronously. | |
| 368 // 7. Optionally, perform some animation. | |
| 369 | |
| 370 FrameHost* host = document()->frameHost(); | |
| 371 | |
| 372 // Speculative fix for engaget.com/videos per crbug.com/336239. | |
| 373 // FIXME: This check is wrong. We ASSERT(document->isActive()) above | |
| 374 // so this should be redundant and should be removed! | |
| 375 if (!host) | |
| 376 return; | |
| 377 | |
| 378 // Only exit out of full screen window mode if there are no remaining elemen
ts in the | |
| 379 // full screen stack. | |
| 380 if (!newTop) { | |
| 381 host->chrome().client().exitFullScreenForElement(m_fullScreenElement.get
()); | |
| 382 return; | |
| 383 } | |
| 384 | |
| 385 // Otherwise, notify the chrome of the new full screen element. | |
| 386 host->chrome().client().enterFullScreenForElement(newTop); | |
| 387 } | |
| 388 | |
| 389 bool FullscreenElementStack::fullscreenEnabled(Document& document) | |
| 390 { | |
| 391 // 4. The fullscreenEnabled attribute must return true if the context object
has its | |
| 392 // fullscreen enabled flag set and fullscreen is supported, and false oth
erwise. | |
| 393 | |
| 394 // Top-level browsing contexts are implied to have their allowFullScreen att
ribute set. | |
| 395 return fullscreenIsAllowedForAllOwners(document) && fullscreenIsSupported(do
cument); | |
| 396 } | |
| 397 | |
| 398 void FullscreenElementStack::willEnterFullScreenForElement(Element* element) | |
| 399 { | |
| 400 ASSERT(element); | |
| 401 if (!document()->isActive()) | |
| 402 return; | |
| 403 | |
| 404 if (m_fullScreenRenderer) | |
| 405 m_fullScreenRenderer->unwrapRenderer(); | |
| 406 | |
| 407 m_fullScreenElement = element; | |
| 408 | |
| 409 // Create a placeholder block for a the full-screen element, to keep the pag
e from reflowing | |
| 410 // when the element is removed from the normal flow. Only do this for a Rend
erBox, as only | |
| 411 // a box will have a frameRect. The placeholder will be created in setFullSc
reenRenderer() | |
| 412 // during layout. | |
| 413 RenderObject* renderer = m_fullScreenElement->renderer(); | |
| 414 bool shouldCreatePlaceholder = renderer && renderer->isBox(); | |
| 415 if (shouldCreatePlaceholder) { | |
| 416 m_savedPlaceholderFrameRect = toRenderBox(renderer)->frameRect(); | |
| 417 m_savedPlaceholderRenderStyle = RenderStyle::clone(renderer->style()); | |
| 418 } | |
| 419 | |
| 420 if (m_fullScreenElement != document()->documentElement()) | |
| 421 RenderFullScreen::wrapRenderer(renderer, renderer ? renderer->parent() :
0, document()); | |
| 422 | |
| 423 m_fullScreenElement->setContainsFullScreenElementOnAncestorsCrossingFrameBou
ndaries(true); | |
| 424 | |
| 425 // FIXME: This should not call updateStyleIfNeeded. | |
| 426 document()->setNeedsStyleRecalc(SubtreeStyleChange); | |
| 427 document()->updateRenderTreeIfNeeded(); | |
| 428 } | |
| 429 | |
| 430 void FullscreenElementStack::didEnterFullScreenForElement(Element*) | |
| 431 { | |
| 432 if (!m_fullScreenElement) | |
| 433 return; | |
| 434 | |
| 435 if (!document()->isActive()) | |
| 436 return; | |
| 437 | |
| 438 m_fullScreenElement->didBecomeFullscreenElement(); | |
| 439 | |
| 440 m_eventQueueTimer.startOneShot(0, FROM_HERE); | |
| 441 } | |
| 442 | |
| 443 void FullscreenElementStack::willExitFullScreenForElement(Element*) | |
| 444 { | |
| 445 if (!m_fullScreenElement) | |
| 446 return; | |
| 447 | |
| 448 if (!document()->isActive()) | |
| 449 return; | |
| 450 | |
| 451 m_fullScreenElement->willStopBeingFullscreenElement(); | |
| 452 } | |
| 453 | |
| 454 void FullscreenElementStack::didExitFullScreenForElement(Element*) | |
| 455 { | |
| 456 if (!m_fullScreenElement) | |
| 457 return; | |
| 458 | |
| 459 if (!document()->isActive()) | |
| 460 return; | |
| 461 | |
| 462 m_fullScreenElement->setContainsFullScreenElementOnAncestorsCrossingFrameBou
ndaries(false); | |
| 463 | |
| 464 m_areKeysEnabledInFullScreen = false; | |
| 465 | |
| 466 if (m_fullScreenRenderer) | |
| 467 m_fullScreenRenderer->unwrapRenderer(); | |
| 468 | |
| 469 m_fullScreenElement = nullptr; | |
| 470 document()->setNeedsStyleRecalc(SubtreeStyleChange); | |
| 471 | |
| 472 // When fullyExitFullscreen is called, we call exitFullscreen on the topDocu
ment(). That means | |
| 473 // that the events will be queued there. So if we have no events here, start
the timer on the | |
| 474 // exiting document. | |
| 475 Document* exitingDocument = document(); | |
| 476 if (m_eventQueue.isEmpty()) | |
| 477 exitingDocument = &document()->topDocument(); | |
| 478 ASSERT(exitingDocument); | |
| 479 from(*exitingDocument).m_eventQueueTimer.startOneShot(0, FROM_HERE); | |
| 480 } | |
| 481 | |
| 482 void FullscreenElementStack::setFullScreenRenderer(RenderFullScreen* renderer) | |
| 483 { | |
| 484 if (renderer == m_fullScreenRenderer) | |
| 485 return; | |
| 486 | |
| 487 if (renderer && m_savedPlaceholderRenderStyle) { | |
| 488 renderer->createPlaceholder(m_savedPlaceholderRenderStyle.release(), m_s
avedPlaceholderFrameRect); | |
| 489 } else if (renderer && m_fullScreenRenderer && m_fullScreenRenderer->placeho
lder()) { | |
| 490 RenderBlock* placeholder = m_fullScreenRenderer->placeholder(); | |
| 491 renderer->createPlaceholder(RenderStyle::clone(placeholder->style()), pl
aceholder->frameRect()); | |
| 492 } | |
| 493 | |
| 494 if (m_fullScreenRenderer) | |
| 495 m_fullScreenRenderer->unwrapRenderer(); | |
| 496 ASSERT(!m_fullScreenRenderer); | |
| 497 | |
| 498 m_fullScreenRenderer = renderer; | |
| 499 } | |
| 500 | |
| 501 void FullscreenElementStack::fullScreenRendererDestroyed() | |
| 502 { | |
| 503 m_fullScreenRenderer = nullptr; | |
| 504 } | |
| 505 | |
| 506 void FullscreenElementStack::enqueueChangeEvent(Document& document, RequestType
requestType) | |
| 507 { | |
| 508 RefPtrWillBeRawPtr<Event> event; | |
| 509 if (requestType == UnprefixedRequest) { | |
| 510 event = createEvent(EventTypeNames::fullscreenchange, document); | |
| 511 } else { | |
| 512 ASSERT(document.hasFullscreenElementStack()); | |
| 513 FullscreenElementStack& fullscreen = from(document); | |
| 514 EventTarget* target = fullscreen.fullscreenElement(); | |
| 515 if (!target) | |
| 516 target = fullscreen.webkitCurrentFullScreenElement(); | |
| 517 if (!target) | |
| 518 target = &document; | |
| 519 event = createEvent(EventTypeNames::webkitfullscreenchange, *target); | |
| 520 } | |
| 521 m_eventQueue.append(event); | |
| 522 // NOTE: The timer is started in didEnterFullScreenForElement/didExitFullScr
eenForElement. | |
| 523 } | |
| 524 | |
| 525 void FullscreenElementStack::enqueueErrorEvent(Element& element, RequestType req
uestType) | |
| 526 { | |
| 527 RefPtrWillBeRawPtr<Event> event; | |
| 528 if (requestType == UnprefixedRequest) | |
| 529 event = createEvent(EventTypeNames::fullscreenerror, element.document())
; | |
| 530 else | |
| 531 event = createEvent(EventTypeNames::webkitfullscreenerror, element); | |
| 532 m_eventQueue.append(event); | |
| 533 m_eventQueueTimer.startOneShot(0, FROM_HERE); | |
| 534 } | |
| 535 | |
| 536 void FullscreenElementStack::eventQueueTimerFired(Timer<FullscreenElementStack>*
) | |
| 537 { | |
| 538 // Since we dispatch events in this function, it's possible that the | |
| 539 // document will be detached and GC'd. We protect it here to make sure we | |
| 540 // can finish the function successfully. | |
| 541 RefPtrWillBeRawPtr<Document> protectDocument(document()); | |
| 542 WillBeHeapDeque<RefPtrWillBeMember<Event> > eventQueue; | |
| 543 m_eventQueue.swap(eventQueue); | |
| 544 | |
| 545 while (!eventQueue.isEmpty()) { | |
| 546 RefPtrWillBeRawPtr<Event> event = eventQueue.takeFirst(); | |
| 547 Node* target = event->target()->toNode(); | |
| 548 | |
| 549 // If the element was removed from our tree, also message the documentEl
ement. | |
| 550 if (!target->inDocument() && document()->documentElement()) { | |
| 551 ASSERT(isPrefixed(event->type())); | |
| 552 eventQueue.append(createEvent(event->type(), *document()->documentEl
ement())); | |
| 553 } | |
| 554 | |
| 555 target->dispatchEvent(event); | |
| 556 } | |
| 557 } | |
| 558 | |
| 559 void FullscreenElementStack::elementRemoved(Element& element) | |
| 560 { | |
| 561 // If an element |element| in a fullscreen element stack is removed from a d
ocument |document|, | |
| 562 // run these steps: | |
| 563 | |
| 564 // 1. If |element| was at the top of |document|'s fullscreen element stack,
act as if the | |
| 565 // exitFullscreen() method was invoked on that document. | |
| 566 if (fullscreenElement() == &element) { | |
| 567 exitFullscreen(); | |
| 568 return; | |
| 569 } | |
| 570 | |
| 571 // 2. Otherwise, remove |element| from |document|'s fullscreen element stack
. | |
| 572 for (size_t i = 0; i < m_fullScreenElementStack.size(); ++i) { | |
| 573 if (m_fullScreenElementStack[i].first.get() == &element) { | |
| 574 m_fullScreenElementStack.remove(i); | |
| 575 return; | |
| 576 } | |
| 577 } | |
| 578 | |
| 579 // NOTE: |element| was not in the fullscreen element stack. | |
| 580 } | |
| 581 | |
| 582 void FullscreenElementStack::clearFullscreenElementStack() | |
| 583 { | |
| 584 m_fullScreenElementStack.clear(); | |
| 585 } | |
| 586 | |
| 587 void FullscreenElementStack::popFullscreenElementStack() | |
| 588 { | |
| 589 if (m_fullScreenElementStack.isEmpty()) | |
| 590 return; | |
| 591 | |
| 592 m_fullScreenElementStack.removeLast(); | |
| 593 } | |
| 594 | |
| 595 void FullscreenElementStack::pushFullscreenElementStack(Element& element, Reques
tType requestType) | |
| 596 { | |
| 597 m_fullScreenElementStack.append(std::make_pair(&element, requestType)); | |
| 598 } | |
| 599 | |
| 600 void FullscreenElementStack::trace(Visitor* visitor) | |
| 601 { | |
| 602 visitor->trace(m_fullScreenElement); | |
| 603 visitor->trace(m_fullScreenElementStack); | |
| 604 visitor->trace(m_fullScreenRenderer); | |
| 605 visitor->trace(m_eventQueue); | |
| 606 DocumentSupplement::trace(visitor); | |
| 607 } | |
| 608 | |
| 609 } // namespace blink | |
| OLD | NEW |