зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1375319 part 3 - Try dispatching fullscreen events to element first rather than document. r=smaug
Some steps in file_fullscreen-api.html are adjusted in order to test the behavior that the event is correctly dispatched to the document when element is disconnected. Depends on D5415 Differential Revision: https://phabricator.services.mozilla.com/D5416 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
6239a69055
Коммит
abdaa90858
|
@ -3580,7 +3580,7 @@ Element::RequestFullscreen(CallerType aCallerType, ErrorResult& aError)
|
|||
// Note that requests for fullscreen inside a web app's origin are exempt
|
||||
// from this restriction.
|
||||
if (const char* error = GetFullscreenError(aCallerType)) {
|
||||
OwnerDoc()->DispatchFullscreenError(error);
|
||||
OwnerDoc()->DispatchFullscreenError(error, this);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -8562,11 +8562,11 @@ NotifyPageHide(nsIDocument* aDocument, void* aData)
|
|||
}
|
||||
|
||||
static void
|
||||
DispatchFullscreenChange(nsIDocument* aTarget)
|
||||
DispatchFullscreenChange(nsIDocument* aDocument, nsINode* aTarget)
|
||||
{
|
||||
if (nsPresContext* presContext = aTarget->GetPresContext()) {
|
||||
auto pendingEvent =
|
||||
MakeUnique<PendingFullscreenEvent>(FullscreenEventType::Change, aTarget);
|
||||
if (nsPresContext* presContext = aDocument->GetPresContext()) {
|
||||
auto pendingEvent = MakeUnique<PendingFullscreenEvent>(
|
||||
FullscreenEventType::Change, aDocument, aTarget);
|
||||
presContext->RefreshDriver()->
|
||||
ScheduleFullscreenEvent(std::move(pendingEvent));
|
||||
}
|
||||
|
@ -10716,13 +10716,13 @@ GetFullscreenLeaf(nsIDocument* aDoc)
|
|||
static bool
|
||||
ResetFullscreen(nsIDocument* aDocument, void* aData)
|
||||
{
|
||||
if (aDocument->FullscreenStackTop()) {
|
||||
if (Element* fsElement = aDocument->FullscreenStackTop()) {
|
||||
NS_ASSERTION(CountFullscreenSubDocuments(aDocument) <= 1,
|
||||
"Should have at most 1 fullscreen subdocument.");
|
||||
aDocument->CleanupFullscreenState();
|
||||
NS_ASSERTION(!aDocument->FullscreenStackTop(),
|
||||
"Should reset fullscreen");
|
||||
DispatchFullscreenChange(aDocument);
|
||||
DispatchFullscreenChange(aDocument, fsElement);
|
||||
aDocument->EnumerateSubDocuments(ResetFullscreen, nullptr);
|
||||
}
|
||||
return true;
|
||||
|
@ -10823,35 +10823,38 @@ nsIDocument::RestorePreviousFullscreenState()
|
|||
}
|
||||
|
||||
nsCOMPtr<nsIDocument> fullScreenDoc = GetFullscreenLeaf(this);
|
||||
AutoTArray<nsIDocument*, 8> exitDocs;
|
||||
AutoTArray<Element*, 8> exitElements;
|
||||
|
||||
nsIDocument* doc = fullScreenDoc;
|
||||
// Collect all subdocuments.
|
||||
for (; doc != this; doc = doc->GetParentDocument()) {
|
||||
exitDocs.AppendElement(doc);
|
||||
Element* fsElement = doc->FullscreenStackTop();
|
||||
MOZ_ASSERT(fsElement, "Parent document of "
|
||||
"a fullscreen document without fullscreen element?");
|
||||
exitElements.AppendElement(fsElement);
|
||||
}
|
||||
MOZ_ASSERT(doc == this, "Must have reached this doc");
|
||||
// Collect all ancestor documents which we are going to change.
|
||||
for (; doc; doc = doc->GetParentDocument()) {
|
||||
MOZ_ASSERT(!doc->mFullscreenStack.IsEmpty(),
|
||||
"Ancestor of fullscreen document must also be in fullscreen");
|
||||
Element* fsElement = doc->FullscreenStackTop();
|
||||
if (doc != this) {
|
||||
Element* top = doc->FullscreenStackTop();
|
||||
if (top->IsHTMLElement(nsGkAtoms::iframe)) {
|
||||
if (static_cast<HTMLIFrameElement*>(top)->FullscreenFlag()) {
|
||||
if (auto* iframe = HTMLIFrameElement::FromNode(fsElement)) {
|
||||
if (iframe->FullscreenFlag()) {
|
||||
// If this is an iframe, and it explicitly requested
|
||||
// fullscreen, don't rollback it automatically.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
exitDocs.AppendElement(doc);
|
||||
exitElements.AppendElement(fsElement);
|
||||
if (doc->mFullscreenStack.Length() > 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
nsIDocument* lastDoc = exitDocs.LastElement();
|
||||
nsIDocument* lastDoc = exitElements.LastElement()->OwnerDoc();
|
||||
if (!lastDoc->GetParentDocument() &&
|
||||
lastDoc->mFullscreenStack.Length() == 1) {
|
||||
// If we are fully exiting fullscreen, don't touch anything here,
|
||||
|
@ -10864,8 +10867,8 @@ nsIDocument::RestorePreviousFullscreenState()
|
|||
UnlockPointer();
|
||||
// All documents listed in the array except the last one are going to
|
||||
// completely exit from the fullscreen state.
|
||||
for (auto i : IntegerRange(exitDocs.Length() - 1)) {
|
||||
exitDocs[i]->CleanupFullscreenState();
|
||||
for (auto i : IntegerRange(exitElements.Length() - 1)) {
|
||||
exitElements[i]->OwnerDoc()->CleanupFullscreenState();
|
||||
}
|
||||
// The last document will either rollback one fullscreen element, or
|
||||
// completely exit from the fullscreen state as well.
|
||||
|
@ -10880,8 +10883,8 @@ nsIDocument::RestorePreviousFullscreenState()
|
|||
// Dispatch the fullscreenchange event to all document listed. Note
|
||||
// that the loop order is reversed so that events are dispatched in
|
||||
// the tree order as indicated in the spec.
|
||||
for (nsIDocument* d : Reversed(exitDocs)) {
|
||||
DispatchFullscreenChange(d);
|
||||
for (Element* e : Reversed(exitElements)) {
|
||||
DispatchFullscreenChange(e->OwnerDoc(), e);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(newFullscreenDoc, "If we were going to exit from fullscreen on "
|
||||
|
@ -10932,11 +10935,11 @@ nsIDocument::AsyncRequestFullscreen(UniquePtr<FullscreenRequest> aRequest)
|
|||
}
|
||||
|
||||
void
|
||||
nsIDocument::DispatchFullscreenError(const char* aMessage)
|
||||
nsIDocument::DispatchFullscreenError(const char* aMessage, nsINode* aTarget)
|
||||
{
|
||||
if (nsPresContext* presContext = GetPresContext()) {
|
||||
auto pendingEvent =
|
||||
MakeUnique<PendingFullscreenEvent>(FullscreenEventType::Error, this);
|
||||
auto pendingEvent = MakeUnique<PendingFullscreenEvent>(
|
||||
FullscreenEventType::Error, this, aTarget);
|
||||
presContext->RefreshDriver()->
|
||||
ScheduleFullscreenEvent(std::move(pendingEvent));
|
||||
}
|
||||
|
@ -11171,27 +11174,27 @@ nsIDocument::FullscreenElementReadyCheck(Element* aElement,
|
|||
return false;
|
||||
}
|
||||
if (!aElement->IsInComposedDoc()) {
|
||||
DispatchFullscreenError("FullscreenDeniedNotInDocument");
|
||||
DispatchFullscreenError("FullscreenDeniedNotInDocument", aElement);
|
||||
return false;
|
||||
}
|
||||
if (aElement->OwnerDoc() != this) {
|
||||
DispatchFullscreenError("FullscreenDeniedMovedDocument");
|
||||
DispatchFullscreenError("FullscreenDeniedMovedDocument", aElement);
|
||||
return false;
|
||||
}
|
||||
if (!GetWindow()) {
|
||||
DispatchFullscreenError("FullscreenDeniedLostWindow");
|
||||
DispatchFullscreenError("FullscreenDeniedLostWindow", aElement);
|
||||
return false;
|
||||
}
|
||||
if (const char* msg = GetFullscreenError(this, aCallerType)) {
|
||||
DispatchFullscreenError(msg);
|
||||
DispatchFullscreenError(msg, aElement);
|
||||
return false;
|
||||
}
|
||||
if (!IsVisible()) {
|
||||
DispatchFullscreenError("FullscreenDeniedHidden");
|
||||
DispatchFullscreenError("FullscreenDeniedHidden", aElement);
|
||||
return false;
|
||||
}
|
||||
if (HasFullscreenSubDocument(this)) {
|
||||
DispatchFullscreenError("FullscreenDeniedSubDocFullScreen");
|
||||
DispatchFullscreenError("FullscreenDeniedSubDocFullScreen", aElement);
|
||||
return false;
|
||||
}
|
||||
//XXXsmaug Note, we don't follow the latest fullscreen spec here.
|
||||
|
@ -11201,11 +11204,11 @@ nsIDocument::FullscreenElementReadyCheck(Element* aElement,
|
|||
FullscreenStackTop())) {
|
||||
// If this document is fullscreen, only grant fullscreen requests from
|
||||
// a descendant of the current fullscreen element.
|
||||
DispatchFullscreenError("FullscreenDeniedNotDescendant");
|
||||
DispatchFullscreenError("FullscreenDeniedNotDescendant", aElement);
|
||||
return false;
|
||||
}
|
||||
if (!nsContentUtils::IsChromeDoc(this) && !IsInActiveTab(this)) {
|
||||
DispatchFullscreenError("FullscreenDeniedNotFocusedTab");
|
||||
DispatchFullscreenError("FullscreenDeniedNotFocusedTab", aElement);
|
||||
return false;
|
||||
}
|
||||
// Deny requests when a windowed plugin is focused.
|
||||
|
@ -11215,7 +11218,7 @@ nsIDocument::FullscreenElementReadyCheck(Element* aElement,
|
|||
return false;
|
||||
}
|
||||
if (nsContentUtils::HasPluginWithUncontrolledEventDispatch(fm->GetFocusedElement())) {
|
||||
DispatchFullscreenError("FullscreenDeniedFocusedPlugin");
|
||||
DispatchFullscreenError("FullscreenDeniedFocusedPlugin", aElement);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -11395,7 +11398,7 @@ nsIDocument::RequestFullscreen(UniquePtr<FullscreenRequest> aRequest)
|
|||
if (!elem->IsHTMLElement() && !elem->IsXULElement() &&
|
||||
!elem->IsSVGElement(nsGkAtoms::svg) &&
|
||||
!elem->IsMathMLElement(nsGkAtoms::math)) {
|
||||
DispatchFullscreenError("FullscreenDeniedNotHTMLSVGOrMathML");
|
||||
DispatchFullscreenError("FullscreenDeniedNotHTMLSVGOrMathML", elem);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -11538,7 +11541,7 @@ nsIDocument::ApplyFullscreen(const FullscreenRequest& aRequest)
|
|||
// reversed so that events are dispatched in the tree order as
|
||||
// indicated in the spec.
|
||||
for (nsIDocument* d : Reversed(changed)) {
|
||||
DispatchFullscreenChange(d);
|
||||
DispatchFullscreenChange(d, d->FullscreenStackTop());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1858,7 +1858,7 @@ public:
|
|||
* Dispatch fullscreenerror event and report the failure message to
|
||||
* the console.
|
||||
*/
|
||||
void DispatchFullscreenError(const char* aMessage);
|
||||
void DispatchFullscreenError(const char* aMessage, nsINode* aTarget);
|
||||
|
||||
void RequestPointerLock(Element* aElement, mozilla::dom::CallerType);
|
||||
bool SetPointerLock(Element* aElement, int aCursorStyle);
|
||||
|
|
|
@ -26,11 +26,15 @@ enum class FullscreenEventType
|
|||
class PendingFullscreenEvent
|
||||
{
|
||||
public:
|
||||
PendingFullscreenEvent(FullscreenEventType aType, nsIDocument* aDoc)
|
||||
: mDocument(aDoc)
|
||||
PendingFullscreenEvent(FullscreenEventType aType,
|
||||
nsIDocument* aDocument,
|
||||
nsINode* aTarget)
|
||||
: mDocument(aDocument)
|
||||
, mTarget(aTarget)
|
||||
, mType(aType)
|
||||
{
|
||||
MOZ_ASSERT(aDoc);
|
||||
MOZ_ASSERT(aDocument);
|
||||
MOZ_ASSERT(aTarget);
|
||||
}
|
||||
|
||||
nsIDocument* Document() const { return mDocument; }
|
||||
|
@ -50,13 +54,16 @@ public:
|
|||
name = NS_LITERAL_STRING("fullscreenerror");
|
||||
break;
|
||||
}
|
||||
nsINode* target =
|
||||
mTarget->GetComposedDoc() == mDocument ? mTarget : mDocument;
|
||||
Unused << nsContentUtils::DispatchTrustedEvent(
|
||||
mDocument, mDocument, name,
|
||||
mDocument, target, name,
|
||||
CanBubble::eYes, Cancelable::eNo, Composed::eYes);
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIDocument> mDocument;
|
||||
nsCOMPtr<nsINode> mTarget;
|
||||
FullscreenEventType mType;
|
||||
#ifdef DEBUG
|
||||
bool mDispatched = false;
|
||||
|
|
|
@ -54,7 +54,8 @@ function sendMouseClick(element) {
|
|||
const FULLSCREEN_ELEMENT = document.getElementById("fullscreen-element");
|
||||
|
||||
function enter1(event) {
|
||||
is(event.target, document, "Event target should be full-screen document #1");
|
||||
is(event.target, FULLSCREEN_ELEMENT,
|
||||
"Event target should be the fullscreen element #1");
|
||||
ok(document.fullscreen, "Document should be in fullscreen");
|
||||
is(document.fullscreenElement, FULLSCREEN_ELEMENT,
|
||||
"Full-screen element should be div element.");
|
||||
|
@ -64,13 +65,13 @@ function enter1(event) {
|
|||
FULLSCREEN_ELEMENT.remove();
|
||||
is(document.fullscreenElement, null,
|
||||
"Full-screen element should be null after removing.");
|
||||
document.body.appendChild(FULLSCREEN_ELEMENT);
|
||||
is(document.fullscreenElement, null,
|
||||
"Full-screen element should still be null after re-adding former FSE.");
|
||||
}
|
||||
|
||||
function exit1(event) {
|
||||
is(event.target, document, "Event target should be full-screen document #2");
|
||||
document.body.appendChild(FULLSCREEN_ELEMENT);
|
||||
is(document.fullscreenElement, null,
|
||||
"Full-screen element should still be null after re-adding former FSE.");
|
||||
is(event.target, document, "Event target should be the document #2");
|
||||
ok(!document.fullscreen, "Document should not be in fullscreen");
|
||||
is(document.fullscreenElement, null, "Full-screen element should be null.");
|
||||
iframe = document.createElement("iframe");
|
||||
|
@ -81,7 +82,8 @@ function exit1(event) {
|
|||
}
|
||||
|
||||
function enter2(event) {
|
||||
is(event.target, document, "Event target should be full-screen document #3");
|
||||
is(event.target, iframe,
|
||||
"Event target should be the fullscreen iframe #3");
|
||||
is(document.fullscreenElement, iframe,
|
||||
"Full-screen element should be iframe element.");
|
||||
is(iframe.contentDocument.fullscreenElement, iframe.contentDocument.body,
|
||||
|
@ -105,7 +107,8 @@ function exit2(event) {
|
|||
}
|
||||
|
||||
function enter3(event) {
|
||||
is(event.target, document, "Event target should be full-screen document #3");
|
||||
is(event.target, FULLSCREEN_ELEMENT,
|
||||
"Event target should be the fullscreen element #3");
|
||||
is(document.fullscreenElement, FULLSCREEN_ELEMENT,
|
||||
"Full-screen element should be div.");
|
||||
|
||||
|
@ -119,12 +122,11 @@ function enter3(event) {
|
|||
"Full-screen element in outer frame should be null.");
|
||||
is(_innerFrame.contentDocument.fullscreenElement, null,
|
||||
"Full-screen element in inner frame should be null.");
|
||||
|
||||
document.body.appendChild(FULLSCREEN_ELEMENT);
|
||||
}
|
||||
|
||||
function exit3(event) {
|
||||
is(event.target, document, "Event target should be full-screen document #4");
|
||||
document.body.appendChild(FULLSCREEN_ELEMENT);
|
||||
is(event.target, document, "Event target should be the document #3");
|
||||
is(document.fullscreenElement, null, "Full-screen element should be null.");
|
||||
document.body.removeChild(iframe);
|
||||
iframe = null;
|
||||
|
@ -149,7 +151,8 @@ function error1(event) {
|
|||
}
|
||||
|
||||
function enter4(event) {
|
||||
is(event.target, document, "Event target should be full-screen document #5");
|
||||
is(event.target, inDocElement,
|
||||
"Event target should be the fullscreen element #4");
|
||||
is(document.fullscreenElement, inDocElement, "FSE should be inDocElement.");
|
||||
|
||||
// Remove full-screen ancestor element from document, verify it stops being reported as current FSE.
|
||||
|
|
|
@ -12,10 +12,11 @@ function is(a, b, msg) {
|
|||
}
|
||||
|
||||
let fullscreenEvents = [];
|
||||
let iframeDoc;
|
||||
let iframe, iframeDoc;
|
||||
|
||||
function begin() {
|
||||
iframeDoc = document.querySelector("iframe").contentDocument;
|
||||
iframe = document.querySelector("iframe");
|
||||
iframeDoc = iframe.contentDocument;
|
||||
document.addEventListener("fullscreenchange", evt => {
|
||||
fullscreenEvents.push(evt);
|
||||
});
|
||||
|
@ -29,9 +30,9 @@ function begin() {
|
|||
function assertFullscreenEvents(action) {
|
||||
is(fullscreenEvents.length, 2,
|
||||
"Two documents should have event dispatched for " + action);
|
||||
is(fullscreenEvents[0].target, document,
|
||||
is(fullscreenEvents[0].target, iframe,
|
||||
"Root document should have the event dispatched first after " + action);
|
||||
is(fullscreenEvents[1].target, iframeDoc,
|
||||
is(fullscreenEvents[1].target, iframeDoc.body,
|
||||
"Inner document should have the event dispatched second after " + action);
|
||||
}
|
||||
|
||||
|
|
|
@ -265,6 +265,12 @@ partial interface Element {
|
|||
void requestFullscreen();
|
||||
[Throws, BinaryName="requestFullscreen", NeedsCallerType]
|
||||
void mozRequestFullScreen();
|
||||
|
||||
// Events handlers
|
||||
[Func="nsDocument::IsUnprefixedFullscreenEnabled"]
|
||||
attribute EventHandler onfullscreenchange;
|
||||
[Func="nsDocument::IsUnprefixedFullscreenEnabled"]
|
||||
attribute EventHandler onfullscreenerror;
|
||||
};
|
||||
|
||||
// https://w3c.github.io/pointerlock/#extensions-to-the-element-interface
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
[element-request-fullscreen-not-allowed.html]
|
||||
[Element#requestFullscreen() when not allowed to request fullscreen]
|
||||
expected: FAIL
|
||||
|
|
@ -5,15 +5,3 @@
|
|||
[Document interface: operation exitFullscreen()]
|
||||
expected: FAIL
|
||||
|
||||
[Element interface: document.createElementNS(null, "test") must inherit property "onfullscreenerror" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Element interface: attribute onfullscreenerror]
|
||||
expected: FAIL
|
||||
|
||||
[Element interface: document.createElementNS(null, "test") must inherit property "onfullscreenchange" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Element interface: attribute onfullscreenchange]
|
||||
expected: FAIL
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче