// https://fullscreen.spec.whatwg.org/#dom-document-fullscreenenabled bool Fullscreen::fullscreenEnabled(Document& document) { // The fullscreenEnabled attribute's getter must return true if the context // object is allowed to use the feature indicated by attribute name // allowfullscreen and fullscreen is supported, and false otherwise. return allowedToUseFullscreen(document.frame()) && fullscreenIsSupported(document); }
void MediaControls::reset() { double duration = mediaElement().duration(); m_durationDisplay->setInnerText(LayoutTheme::theme().formatMediaControlsTime(duration), ASSERT_NO_EXCEPTION); m_durationDisplay->setCurrentValue(duration); updatePlayState(); updateCurrentTimeDisplay(); m_timeline->setDuration(duration); m_timeline->setPosition(mediaElement().currentTime()); if (!mediaElement().hasAudio()) m_volumeSlider->hide(); else m_volumeSlider->show(); updateVolume(); refreshClosedCaptionsButtonVisibility(); if (mediaElement().hasVideo() && fullscreenIsSupported(document())) m_fullScreenButton->show(); else m_fullScreenButton->hide(); refreshCastButtonVisibility(); makeOpaque(); }
// https://fullscreen.spec.whatwg.org/#dom-element-requestfullscreen void Fullscreen::requestFullscreen(Element& element, RequestType requestType, bool forCrossProcessDescendant) { Document& document = element.document(); // Use counters only need to be incremented in the process of the actual // fullscreen element. if (!forCrossProcessDescendant) { if (document.isSecureContext()) { UseCounter::count(document, UseCounter::FullscreenSecureOrigin); } else { UseCounter::count(document, UseCounter::FullscreenInsecureOrigin); HostsUsingFeatures::countAnyWorld( document, HostsUsingFeatures::Feature::FullscreenInsecureHost); } } // Ignore this request if the document is not in a live frame. if (!document.isActive()) return; // If |element| is on top of |doc|'s fullscreen element stack, terminate these // substeps. if (&element == fullscreenElementFrom(document)) return; do { // 1. If any of the following conditions are true, terminate these steps and // queue a task to fire an event named fullscreenerror with its bubbles // attribute set to true on the context object's node document: // The fullscreen element ready check returns false. if (!fullscreenElementReady(element)) break; // Fullscreen is not supported. if (!fullscreenIsSupported(document)) break; // This algorithm is not allowed to request fullscreen. // OOPIF: If |forCrossProcessDescendant| is true, requestFullscreen was // already called on a descendant element in another process, and // getting here means that it was already allowed to request fullscreen. if (!forCrossProcessDescendant && !allowedToRequestFullscreen(document)) break; // 2. Let doc be element's node document. (i.e. "this") // 3. Let docs be all doc's ancestor browsing context's documents (if any) // and doc. // // For OOPIF scenarios, |docs| will only contain documents for local // ancestors, and remote ancestors will be processed in their // respective processes. This preserves the spec's event firing order // for local ancestors, but not for remote ancestors. However, that // difference shouldn't be observable in practice: a fullscreenchange // event handler would need to postMessage a frame in another renderer // process, where the message should be queued up and processed after // the IPC that dispatches fullscreenchange. HeapDeque<Member<Document>> docs; docs.prepend(&document); for (Frame* frame = document.frame()->tree().parent(); frame; frame = frame->tree().parent()) { if (frame->isLocalFrame()) docs.prepend(toLocalFrame(frame)->document()); } // 4. For each document in docs, run these substeps: HeapDeque<Member<Document>>::iterator current = docs.begin(), following = docs.begin(); do { ++following; // 1. Let following document be the document after document in docs, or // null if there is no such document. Document* currentDoc = *current; Document* followingDoc = following != docs.end() ? *following : nullptr; // 2. If following document is null, push context object on document's // fullscreen element stack, and queue a task to fire an event named // fullscreenchange with its bubbles attribute set to true on the // document. if (!followingDoc) { from(*currentDoc).pushFullscreenElementStack(element, requestType); from(document).enqueueChangeEvent(*currentDoc, requestType); continue; } // 3. Otherwise, if document's fullscreen element stack is either empty or // its top element is not following document's browsing context container, Element* topElement = fullscreenElementFrom(*currentDoc); HTMLFrameOwnerElement* followingOwner = findContainerForDescendant(*currentDoc, *followingDoc); if (!topElement || topElement != followingOwner) { // ...push following document's browsing context container on document's // fullscreen element stack, and queue a task to fire an event named // fullscreenchange with its bubbles attribute set to true on document. from(*currentDoc) .pushFullscreenElementStack(*followingOwner, requestType); from(document).enqueueChangeEvent(*currentDoc, requestType); continue; } // 4. Otherwise, do nothing for this document. It stays the same. } while (++current != docs.end()); from(document).m_forCrossProcessDescendant = forCrossProcessDescendant; // 5. Return, and run the remaining steps asynchronously. // 6. Optionally, perform some animation. document.frameHost()->chromeClient().enterFullscreenForElement(&element); // 7. Optionally, display a message indicating how the user can exit // displaying the context object fullscreen. return; } while (false); from(document).enqueueErrorEvent(element, requestType); }