| 
Commits:
55b8abf1
 by Edgar Chen   at 2024-07-09T16:29:04+02:00 
 Bug 1743329 - Handle ESC key to release pointer lock in parent process; r=smaug
Differential Revision: https://phabricator.services.mozilla.com/D211621
0019972d
 by Edgar Chen   at 2024-07-09T16:31:30+02:00 
 Bug 1743329 - Release pointer lock when xul popup is open; r=smaug,pbz
Differential Revision: https://phabricator.services.mozilla.com/D211620
84063db0
 by Edgar Chen   at 2024-07-09T16:31:36+02:00 
 Bug 1743329 - Use nsMenuPopupFrame in GetVisiblePopups(); r=smaug
Differential Revision: https://phabricator.services.mozilla.com/D211619
A further change was needed in nsCaret.cpp, see
https://gitlab.torproject.org/tpo/applications/tor-browser/-/merge_requests/1048#note_3046018
f77f91b1
 by Otto Länd   at 2024-07-09T16:31:37+02:00 
 Bug 1743329: apply code formatting via Lando
# ignore-this-changeset
d2415441
 by edgul   at 2024-07-09T16:31:37+02:00 
 Bug 1879952 - Fix test expectations with samesite=lax turned on r=tschuster
Differential Revision: https://phabricator.services.mozilla.com/D201639
4f7651bf
 by edgul   at 2024-07-09T16:31:38+02:00 
 Bug 1844827 - Added checks for sub-document navigations from cross-site to same-site in third-party checks when setting a cookie. r=cookie-reviewers,valentin,bvandersloot a=RyanVM
Differential Revision: https://phabricator.services.mozilla.com/D204074
2e663f7b
 by Ed   at 2024-07-09T16:31:38+02:00 
 Bug 1844827 - Update the cookie test expectations for iframe samesite r=cookie-reviewers,valentin a=RyanVM
Depends on D199770
Differential Revision: https://phabricator.services.mozilla.com/D199772
bb413ac1
 by Julian Descottes   at 2024-07-09T16:31:39+02:00 
 Bug 1880374 - Disable DNS prefetching if document nodePrincipal is systemPrincipal r=valentin
Differential Revision: https://phabricator.services.mozilla.com/D210830
4e320ce3
 by Edgar Chen   at 2024-07-09T16:31:39+02:00 
 Bug 1883396 - Exit fullscreen when two Escape keyup events occur in a short time; r=smaug
Differential Revision: https://phabricator.services.mozilla.com/D209667
0c986a88
 by Jan de Mooij   at 2024-07-09T16:31:40+02:00 
 Bug 1900523 - Don't use bailout data for JSJitToWasm frames. r=iain
Differential Revision: https://phabricator.services.mozilla.com/D212554
3716357a
 by Jan de Mooij   at 2024-07-09T16:31:40+02:00 
 Bug 1902983 - Don't use bailout data after iterating Wasm frames.  a=RyanVM
This is similar to bug 1900523, but the fix there was incomplete because the
`JSJitToWasm` frame type is only used when we go through the Wasm JIT entry
trampoline. Ion can also call Wasm functions directly and in that case the type
will be `FrameType::Exit`.
Original Revision: https://phabricator.services.mozilla.com/D214098
Differential Revision: https://phabricator.services.mozilla.com/D214375 
22 changed files:
Changes:
browser/base/content/test/popupNotifications/browser_popupNotification_security_delay.js
 
| ... | ... | @@ -558,5 +558,7 @@ add_task(async function test_notificationDuringFullScreenTransition() { |  
| 558 | 558 |      info("Wait for full screen transition end.");
 |  
| 559 | 559 |      await promiseFullScreenTransitionEnd;
 |  
| 560 | 560 |      info("Full screen transition end");
 |  
|  | 561 | +
 |  
|  | 562 | +    await SpecialPowers.popPrefEnv();
 |  
| 561 | 563 |    });
 |  
| 562 | 564 |  }); |  dom/base/PointerLockManager.cpp
 
 
| ... | ... | @@ -17,8 +17,10 @@ |  
| 17 | 17 |  #include "mozilla/dom/BrowsingContext.h"
 |  
| 18 | 18 |  #include "mozilla/dom/Document.h"
 |  
| 19 | 19 |  #include "mozilla/dom/Element.h"
 |  
|  | 20 | +#include "mozilla/dom/PointerEventHandler.h"
 |  
| 20 | 21 |  #include "mozilla/dom/WindowContext.h"
 |  
| 21 | 22 |  #include "nsCOMPtr.h"
 |  
|  | 23 | +#include "nsMenuPopupFrame.h"
 |  
| 22 | 24 |  #include "nsSandboxFlags.h"
 |  
| 23 | 25 |  
 |  
| 24 | 26 |  namespace mozilla {
 |  
| ... | ... | @@ -86,6 +88,25 @@ static void DispatchPointerLockError(Document* aTarget, const char* aMessage) { |  
| 86 | 88 |                                    aMessage);
 |  
| 87 | 89 |  }
 |  
| 88 | 90 |  
 |  
|  | 91 | +static bool IsPopupOpened() {
 |  
|  | 92 | +  // Check if any popup is open.
 |  
|  | 93 | +  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
 |  
|  | 94 | +  if (!pm) {
 |  
|  | 95 | +    return false;
 |  
|  | 96 | +  }
 |  
|  | 97 | +
 |  
|  | 98 | +  nsTArray<nsMenuPopupFrame*> popups;
 |  
|  | 99 | +  pm->GetVisiblePopups(popups, true);
 |  
|  | 100 | +
 |  
|  | 101 | +  for (nsMenuPopupFrame* popup : popups) {
 |  
|  | 102 | +    if (popup->GetPopupType() != widget::PopupType::Tooltip) {
 |  
|  | 103 | +      return true;
 |  
|  | 104 | +    }
 |  
|  | 105 | +  }
 |  
|  | 106 | +
 |  
|  | 107 | +  return false;
 |  
|  | 108 | +}
 |  
|  | 109 | +
 |  
| 89 | 110 |  static const char* GetPointerLockError(Element* aElement, Element* aCurrentLock,
 |  
| 90 | 111 |                                         bool aNoFocusCheck = false) {
 |  
| 91 | 112 |    // Check if pointer lock pref is enabled
 |  
| ... | ... | @@ -136,6 +157,10 @@ static const char* GetPointerLockError(Element* aElement, Element* aCurrentLock, |  
| 136 | 157 |      }
 |  
| 137 | 158 |    }
 |  
| 138 | 159 |  
 |  
|  | 160 | +  if (IsPopupOpened()) {
 |  
|  | 161 | +    return "PointerLockDeniedFailedToLock";
 |  
|  | 162 | +  }
 |  
|  | 163 | +
 |  
| 139 | 164 |    return nullptr;
 |  
| 140 | 165 |  }
 |  
| 141 | 166 |  
 |  
| ... | ... | @@ -167,6 +192,14 @@ void PointerLockManager::RequestLock(Element* aElement, |  
| 167 | 192 |  
 |  
| 168 | 193 |  /* static */
 |  
| 169 | 194 |  void PointerLockManager::Unlock(Document* aDoc) {
 |  
|  | 195 | +  if (sLockedRemoteTarget) {
 |  
|  | 196 | +    MOZ_ASSERT(XRE_IsParentProcess());
 |  
|  | 197 | +    MOZ_ASSERT(!sIsLocked);
 |  
|  | 198 | +    Unused << sLockedRemoteTarget->SendReleasePointerLock();
 |  
|  | 199 | +    sLockedRemoteTarget = nullptr;
 |  
|  | 200 | +    return;
 |  
|  | 201 | +  }
 |  
|  | 202 | +
 |  
| 170 | 203 |    if (!sIsLocked) {
 |  
| 171 | 204 |      return;
 |  
| 172 | 205 |    }
 |  
| ... | ... | @@ -311,14 +344,24 @@ bool PointerLockManager::IsInLockContext(BrowsingContext* aContext) { |  
| 311 | 344 |  }
 |  
| 312 | 345 |  
 |  
| 313 | 346 |  /* static */
 |  
| 314 |  | -bool PointerLockManager::SetLockedRemoteTarget(BrowserParent* aBrowserParent) {
 |  
|  | 347 | +void PointerLockManager::SetLockedRemoteTarget(BrowserParent* aBrowserParent,
 |  
|  | 348 | +                                               nsACString& aError) {
 |  
| 315 | 349 |    MOZ_ASSERT(XRE_IsParentProcess());
 |  
| 316 | 350 |    if (sLockedRemoteTarget) {
 |  
| 317 |  | -    return sLockedRemoteTarget == aBrowserParent;
 |  
|  | 351 | +    if (sLockedRemoteTarget != aBrowserParent) {
 |  
|  | 352 | +      aError = "PointerLockDeniedInUse"_ns;
 |  
|  | 353 | +    }
 |  
|  | 354 | +    return;
 |  
|  | 355 | +  }
 |  
|  | 356 | +
 |  
|  | 357 | +  // Check if any popup is open.
 |  
|  | 358 | +  if (IsPopupOpened()) {
 |  
|  | 359 | +    aError = "PointerLockDeniedFailedToLock"_ns;
 |  
|  | 360 | +    return;
 |  
| 318 | 361 |    }
 |  
| 319 | 362 |  
 |  
| 320 | 363 |    sLockedRemoteTarget = aBrowserParent;
 |  
| 321 |  | -  return true;
 |  
|  | 364 | +  PointerEventHandler::ReleaseAllPointerCaptureRemoteTarget();
 |  
| 322 | 365 |  }
 |  
| 323 | 366 |  
 |  
| 324 | 367 |  /* static */
 |  dom/base/PointerLockManager.h
 
 
| ... | ... | @@ -47,7 +47,8 @@ class PointerLockManager final { |  
| 47 | 47 |  
 |  
| 48 | 48 |    // Set/release pointer lock remote target. Should only be called in parent
 |  
| 49 | 49 |    // process.
 |  
| 50 |  | -  static bool SetLockedRemoteTarget(dom::BrowserParent* aBrowserParent);
 |  
|  | 50 | +  static void SetLockedRemoteTarget(dom::BrowserParent* aBrowserParent,
 |  
|  | 51 | +                                    nsACString& aError);
 |  
| 51 | 52 |    static void ReleaseLockedRemoteTarget(dom::BrowserParent* aBrowserParent);
 |  
| 52 | 53 |  
 |  
| 53 | 54 |   private:
 |  dom/html/HTMLDNSPrefetch.cpp
 
 
| ... | ... | @@ -180,6 +180,13 @@ static bool EnsureDNSService() { |  
| 180 | 180 |  }
 |  
| 181 | 181 |  
 |  
| 182 | 182 |  bool HTMLDNSPrefetch::IsAllowed(Document* aDocument) {
 |  
|  | 183 | +  // Do not use prefetch if the document's node principal is the system
 |  
|  | 184 | +  // principal.
 |  
|  | 185 | +  nsCOMPtr<nsIPrincipal> principal = aDocument->NodePrincipal();
 |  
|  | 186 | +  if (principal->IsSystemPrincipal()) {
 |  
|  | 187 | +    return false;
 |  
|  | 188 | +  }
 |  
|  | 189 | +
 |  
| 183 | 190 |    // There is no need to do prefetch on non UI scenarios such as XMLHttpRequest.
 |  
| 184 | 191 |    return aDocument->IsDNSPrefetchAllowed() && aDocument->GetWindow();
 |  
| 185 | 192 |  }
 |  dom/ipc/BrowserChild.cpp
 
 
| ... | ... | @@ -39,6 +39,7 @@ |  
| 39 | 39 |  #include "mozilla/MouseEvents.h"
 |  
| 40 | 40 |  #include "mozilla/NativeKeyBindingsType.h"
 |  
| 41 | 41 |  #include "mozilla/NullPrincipal.h"
 |  
|  | 42 | +#include "mozilla/PointerLockManager.h"
 |  
| 42 | 43 |  #include "mozilla/Preferences.h"
 |  
| 43 | 44 |  #include "mozilla/PresShell.h"
 |  
| 44 | 45 |  #include "mozilla/ProcessHangMonitor.h"
 |  
| ... | ... | @@ -3184,6 +3185,11 @@ mozilla::ipc::IPCResult BrowserChild::RecvReleaseAllPointerCapture() { |  
| 3184 | 3185 |    return IPC_OK();
 |  
| 3185 | 3186 |  }
 |  
| 3186 | 3187 |  
 |  
|  | 3188 | +mozilla::ipc::IPCResult BrowserChild::RecvReleasePointerLock() {
 |  
|  | 3189 | +  PointerLockManager::Unlock();
 |  
|  | 3190 | +  return IPC_OK();
 |  
|  | 3191 | +}
 |  
|  | 3192 | +
 |  
| 3187 | 3193 |  PPaymentRequestChild* BrowserChild::AllocPPaymentRequestChild() {
 |  
| 3188 | 3194 |    MOZ_CRASH(
 |  
| 3189 | 3195 |        "We should never be manually allocating PPaymentRequestChild actors");
 |  dom/ipc/BrowserChild.h
 
 
| ... | ... | @@ -696,6 +696,8 @@ class BrowserChild final : public nsMessageManagerScriptExecutor, |  
| 696 | 696 |  
 |  
| 697 | 697 |    mozilla::ipc::IPCResult RecvReleaseAllPointerCapture();
 |  
| 698 | 698 |  
 |  
|  | 699 | +  mozilla::ipc::IPCResult RecvReleasePointerLock();
 |  
|  | 700 | +
 |  
| 699 | 701 |   private:
 |  
| 700 | 702 |    void HandleDoubleTap(const CSSPoint& aPoint, const Modifiers& aModifiers,
 |  
| 701 | 703 |                         const ScrollableLayerGuid& aGuid);
 |  dom/ipc/BrowserParent.cpp
 
 
| ... | ... | @@ -4067,15 +4067,14 @@ static BrowserParent* GetTopLevelBrowserParent(BrowserParent* aBrowserParent) { |  
| 4067 | 4067 |  
 |  
| 4068 | 4068 |  mozilla::ipc::IPCResult BrowserParent::RecvRequestPointerLock(
 |  
| 4069 | 4069 |      RequestPointerLockResolver&& aResolve) {
 |  
| 4070 |  | -  nsCString error;
 |  
| 4071 | 4070 |    if (sTopLevelWebFocus != GetTopLevelBrowserParent(this)) {
 |  
| 4072 |  | -    error = "PointerLockDeniedNotFocused";
 |  
| 4073 |  | -  } else if (!PointerLockManager::SetLockedRemoteTarget(this)) {
 |  
| 4074 |  | -    error = "PointerLockDeniedInUse";
 |  
| 4075 |  | -  } else {
 |  
| 4076 |  | -    PointerEventHandler::ReleaseAllPointerCaptureRemoteTarget();
 |  
|  | 4071 | +    aResolve("PointerLockDeniedNotFocused"_ns);
 |  
|  | 4072 | +    return IPC_OK();
 |  
| 4077 | 4073 |    }
 |  
| 4078 |  | -  aResolve(error);
 |  
|  | 4074 | +
 |  
|  | 4075 | +  nsCString error;
 |  
|  | 4076 | +  PointerLockManager::SetLockedRemoteTarget(this, error);
 |  
|  | 4077 | +  aResolve(std::move(error));
 |  
| 4079 | 4078 |    return IPC_OK();
 |  
| 4080 | 4079 |  }
 |  
| 4081 | 4080 |  
 |  dom/ipc/PBrowser.ipdl
 
 
| ... | ... | @@ -557,18 +557,18 @@ parent: |  
| 557 | 557 |  
 |  
| 558 | 558 |      async ImageLoadComplete(nsresult aResult);
 |  
| 559 | 559 |  
 |  
| 560 |  | -    /**
 |  
| 561 |  | -     * Child informs the parent that a pointer lock has requested/released.
 |  
| 562 |  | -     */
 |  
| 563 |  | -    async RequestPointerLock() returns (nsCString error);
 |  
| 564 |  | -    async ReleasePointerLock();
 |  
| 565 |  | -
 |  
| 566 | 560 |      /**
 |  
| 567 | 561 |       * Child informs the parent that a pointer capture has requested/released.
 |  
| 568 | 562 |       */
 |  
| 569 | 563 |      async RequestPointerCapture(uint32_t aPointerId) returns (bool aSuccess);
 |  
| 570 | 564 |      async ReleasePointerCapture(uint32_t aPointerId);
 |  
| 571 | 565 |  
 |  
|  | 566 | +both:
 |  
|  | 567 | +    /**
 |  
|  | 568 | +     * informs that a pointer lock has released.
 |  
|  | 569 | +     */
 |  
|  | 570 | +    async ReleasePointerLock();
 |  
|  | 571 | +
 |  
| 572 | 572 |  child:
 |  
| 573 | 573 |      async NativeSynthesisResponse(uint64_t aObserverId, nsCString aResponse);
 |  
| 574 | 574 |      async UpdateSHistory();
 |  js/src/jit-test/tests/ion/bug1900523.js
 
 
|  | 1 | +// |jit-test| --fast-warmup; --no-threads; skip-if: !wasmIsSupported()
 |  
|  | 2 | +function f1() {
 |  
|  | 3 | +  Promise.allSettled().catch(e => null);
 |  
|  | 4 | +  do {
 |  
|  | 5 | +    f2(10n, -1n);
 |  
|  | 6 | +    try {
 |  
|  | 7 | +      f2(-2147483648n);
 |  
|  | 8 | +    } catch {}
 |  
|  | 9 | +  } while (!inIon());
 |  
|  | 10 | +}
 |  
|  | 11 | +function f2(x, y) {
 |  
|  | 12 | +  const z = x >> x;
 |  
|  | 13 | +  z <= z ? z : z;
 |  
|  | 14 | +  y ^ y;
 |  
|  | 15 | +}
 |  
|  | 16 | +const binary = wasmTextToBinary(`
 |  
|  | 17 | +  (module
 |  
|  | 18 | +    (import "m" "f" (func $f))
 |  
|  | 19 | +    (func (export "test")
 |  
|  | 20 | +      (call $f)
 |  
|  | 21 | +    )
 |  
|  | 22 | +  )
 |  
|  | 23 | +`);
 |  
|  | 24 | +const mod = new WebAssembly.Module(binary);
 |  
|  | 25 | +const inst = new WebAssembly.Instance(mod, {"m": {"f": f1}});
 |  
|  | 26 | +for (let i = 0; i < 6; i++) {
 |  
|  | 27 | +  inst.exports.test();
 |  
|  | 28 | +} |  js/src/jit-test/tests/ion/bug1902983.js
 
 
|  | 1 | +// |jit-test| --fast-warmup; --gc-zeal=21,100; skip-if: !wasmIsSupported()
 |  
|  | 2 | +let counter = 0;
 |  
|  | 3 | +function g() {
 |  
|  | 4 | +    counter++;
 |  
|  | 5 | +    const y = BigInt.asIntN(counter, -883678545n);
 |  
|  | 6 | +    const z = y >> y;
 |  
|  | 7 | +    BigInt.asUintN(2 ** counter, 883678545n);
 |  
|  | 8 | +    try { g(); } catch (e) { }
 |  
|  | 9 | +}
 |  
|  | 10 | +function f() {
 |  
|  | 11 | +    for (let i = 0; i < 5; i++) {
 |  
|  | 12 | +        for (let j = 0; j < 30; j++) { }
 |  
|  | 13 | +        Promise.allSettled().catch(e => null);
 |  
|  | 14 | +        counter = 0;
 |  
|  | 15 | +        g();
 |  
|  | 16 | +    }
 |  
|  | 17 | +}
 |  
|  | 18 | +const binary = wasmTextToBinary(`(module (import "m" "f" (func $f)) (func (export "test") (call $f)))`);
 |  
|  | 19 | +const mod = new WebAssembly.Module(binary);
 |  
|  | 20 | +const inst = new WebAssembly.Instance(mod, { m: { f: f } });
 |  
|  | 21 | +for (let i = 0; i < 100; i++) { }
 |  
|  | 22 | +for (let i = 0; i < 5; i++) {
 |  
|  | 23 | +    inst.exports.test();
 |  
|  | 24 | +} |  js/src/jit/JSJitFrameIter.cpp
 
 
| ... | ... | @@ -26,22 +26,29 @@ using namespace js; |  
| 26 | 26 |  using namespace js::jit;
 |  
| 27 | 27 |  
 |  
| 28 | 28 |  JSJitFrameIter::JSJitFrameIter(const JitActivation* activation)
 |  
| 29 |  | -    : JSJitFrameIter(activation, FrameType::Exit, activation->jsExitFP()) {}
 |  
| 30 |  | -
 |  
| 31 |  | -JSJitFrameIter::JSJitFrameIter(const JitActivation* activation,
 |  
| 32 |  | -                               FrameType frameType, uint8_t* fp)
 |  
| 33 |  | -    : current_(fp),
 |  
| 34 |  | -      type_(frameType),
 |  
| 35 |  | -      resumePCinCurrentFrame_(nullptr),
 |  
| 36 |  | -      cachedSafepointIndex_(nullptr),
 |  
|  | 29 | +    : current_(activation->jsExitFP()),
 |  
|  | 30 | +      type_(FrameType::Exit),
 |  
| 37 | 31 |        activation_(activation) {
 |  
| 38 |  | -  MOZ_ASSERT(type_ == FrameType::JSJitToWasm || type_ == FrameType::Exit);
 |  
|  | 32 | +  // If we're currently performing a bailout, we have to use the activation's
 |  
|  | 33 | +  // bailout data when we start iterating over the activation's frames.
 |  
| 39 | 34 |    if (activation_->bailoutData()) {
 |  
| 40 | 35 |      current_ = activation_->bailoutData()->fp();
 |  
| 41 | 36 |      type_ = FrameType::Bailout;
 |  
| 42 |  | -  } else {
 |  
| 43 |  | -    MOZ_ASSERT(!TlsContext.get()->inUnsafeCallWithABI);
 |  
| 44 | 37 |    }
 |  
|  | 38 | +  MOZ_ASSERT(!TlsContext.get()->inUnsafeCallWithABI);
 |  
|  | 39 | +}
 |  
|  | 40 | +
 |  
|  | 41 | +JSJitFrameIter::JSJitFrameIter(const JitActivation* activation,
 |  
|  | 42 | +                               FrameType frameType, uint8_t* fp)
 |  
|  | 43 | +    : current_(fp), type_(frameType), activation_(activation) {
 |  
|  | 44 | +  // This constructor is only used when resuming iteration after iterating Wasm
 |  
|  | 45 | +  // frames in the same JitActivation so ignore activation_->bailoutData().
 |  
|  | 46 | +  //
 |  
|  | 47 | +  // Note: FrameType::JSJitToWasm is used for JIT => Wasm calls through the Wasm
 |  
|  | 48 | +  // JIT entry trampoline. FrameType::Exit is used for direct Ion => Wasm calls.
 |  
|  | 49 | +  MOZ_ASSERT(fp > activation->jsOrWasmExitFP());
 |  
|  | 50 | +  MOZ_ASSERT(type_ == FrameType::JSJitToWasm || type_ == FrameType::Exit);
 |  
|  | 51 | +  MOZ_ASSERT(!TlsContext.get()->inUnsafeCallWithABI);
 |  
| 45 | 52 |  }
 |  
| 46 | 53 |  
 |  
| 47 | 54 |  bool JSJitFrameIter::checkInvalidation() const {
 |  js/src/jit/JSJitFrameIter.h
 
 
| ... | ... | @@ -111,14 +111,14 @@ class JSJitFrameIter { |  
| 111 | 111 |   protected:
 |  
| 112 | 112 |    uint8_t* current_;
 |  
| 113 | 113 |    FrameType type_;
 |  
| 114 |  | -  uint8_t* resumePCinCurrentFrame_;
 |  
|  | 114 | +  uint8_t* resumePCinCurrentFrame_ = nullptr;
 |  
| 115 | 115 |  
 |  
| 116 | 116 |    // Size of the current Baseline frame. Equivalent to
 |  
| 117 | 117 |    // BaselineFrame::debugFrameSize_ in debug builds.
 |  
| 118 | 118 |    mozilla::Maybe<uint32_t> baselineFrameSize_;
 |  
| 119 | 119 |  
 |  
| 120 | 120 |   private:
 |  
| 121 |  | -  mutable const SafepointIndex* cachedSafepointIndex_;
 |  
|  | 121 | +  mutable const SafepointIndex* cachedSafepointIndex_ = nullptr;
 |  
| 122 | 122 |    const JitActivation* activation_;
 |  
| 123 | 123 |  
 |  
| 124 | 124 |    void dumpBaseline() const;
 |  layout/base/PresShell.cpp
 
 
| ... | ... | @@ -8463,24 +8463,46 @@ void PresShell::EventHandler::MaybeHandleKeyboardEventBeforeDispatch( |  
| 8463 | 8463 |  
 |  
| 8464 | 8464 |      // The event listeners in chrome can prevent this ESC behavior by
 |  
| 8465 | 8465 |      // calling prevent default on the preceding keydown/press events.
 |  
| 8466 |  | -    if (!mPresShell->mIsLastChromeOnlyEscapeKeyConsumed &&
 |  
| 8467 |  | -        aKeyboardEvent->mMessage == eKeyUp) {
 |  
| 8468 |  | -      // ESC key released while in DOM fullscreen mode.
 |  
| 8469 |  | -      // Fully exit all browser windows and documents from
 |  
| 8470 |  | -      // fullscreen mode.
 |  
| 8471 |  | -      Document::AsyncExitFullscreen(nullptr);
 |  
|  | 8466 | +    if (aKeyboardEvent->mMessage == eKeyUp) {
 |  
|  | 8467 | +      bool shouldExitFullscreen =
 |  
|  | 8468 | +          !mPresShell->mIsLastChromeOnlyEscapeKeyConsumed;
 |  
|  | 8469 | +      if (!shouldExitFullscreen) {
 |  
|  | 8470 | +        if (mPresShell->mLastConsumedEscapeKeyUpForFullscreen &&
 |  
|  | 8471 | +            (aKeyboardEvent->mTimeStamp -
 |  
|  | 8472 | +             mPresShell->mLastConsumedEscapeKeyUpForFullscreen) <=
 |  
|  | 8473 | +                TimeDuration::FromMilliseconds(
 |  
|  | 8474 | +                    StaticPrefs::
 |  
|  | 8475 | +                        dom_fullscreen_force_exit_on_multiple_escape_interval())) {
 |  
|  | 8476 | +          shouldExitFullscreen = true;
 |  
|  | 8477 | +          mPresShell->mLastConsumedEscapeKeyUpForFullscreen = TimeStamp();
 |  
|  | 8478 | +        } else {
 |  
|  | 8479 | +          mPresShell->mLastConsumedEscapeKeyUpForFullscreen =
 |  
|  | 8480 | +              aKeyboardEvent->mTimeStamp;
 |  
|  | 8481 | +        }
 |  
|  | 8482 | +      }
 |  
|  | 8483 | +
 |  
|  | 8484 | +      if (shouldExitFullscreen) {
 |  
|  | 8485 | +        // ESC key released while in DOM fullscreen mode.
 |  
|  | 8486 | +        // Fully exit all browser windows and documents from
 |  
|  | 8487 | +        // fullscreen mode.
 |  
|  | 8488 | +        Document::AsyncExitFullscreen(nullptr);
 |  
|  | 8489 | +      }
 |  
| 8472 | 8490 |      }
 |  
| 8473 | 8491 |    }
 |  
| 8474 | 8492 |  
 |  
| 8475 |  | -  nsCOMPtr<Document> pointerLockedDoc = PointerLockManager::GetLockedDocument();
 |  
| 8476 |  | -  if (!mPresShell->mIsLastChromeOnlyEscapeKeyConsumed && pointerLockedDoc) {
 |  
| 8477 |  | -    // XXX See above comment to understand the reason why this needs
 |  
| 8478 |  | -    //     to claim that the Escape key event is consumed by content
 |  
| 8479 |  | -    //     even though it will be dispatched only into chrome.
 |  
| 8480 |  | -    aKeyboardEvent->PreventDefaultBeforeDispatch(CrossProcessForwarding::eStop);
 |  
| 8481 |  | -    aKeyboardEvent->mFlags.mOnlyChromeDispatch = true;
 |  
| 8482 |  | -    if (aKeyboardEvent->mMessage == eKeyUp) {
 |  
| 8483 |  | -      PointerLockManager::Unlock();
 |  
|  | 8493 | +  if (XRE_IsParentProcess() &&
 |  
|  | 8494 | +      !mPresShell->mIsLastChromeOnlyEscapeKeyConsumed) {
 |  
|  | 8495 | +    if (PointerLockManager::GetLockedRemoteTarget() ||
 |  
|  | 8496 | +        PointerLockManager::IsLocked()) {
 |  
|  | 8497 | +      // XXX See above comment to understand the reason why this needs
 |  
|  | 8498 | +      //     to claim that the Escape key event is consumed by content
 |  
|  | 8499 | +      //     even though it will be dispatched only into chrome.
 |  
|  | 8500 | +      aKeyboardEvent->PreventDefaultBeforeDispatch(
 |  
|  | 8501 | +          CrossProcessForwarding::eStop);
 |  
|  | 8502 | +      aKeyboardEvent->mFlags.mOnlyChromeDispatch = true;
 |  
|  | 8503 | +      if (aKeyboardEvent->mMessage == eKeyUp) {
 |  
|  | 8504 | +        PointerLockManager::Unlock();
 |  
|  | 8505 | +      }
 |  
| 8484 | 8506 |      }
 |  
| 8485 | 8507 |    }
 |  
| 8486 | 8508 |  }
 |  layout/base/PresShell.h
 
 
| ... | ... | @@ -3209,6 +3209,10 @@ class PresShell final : public nsStubDocumentObserver, |  
| 3209 | 3209 |    bool mProcessingReflowCommands : 1;
 |  
| 3210 | 3210 |    bool mPendingDidDoReflow : 1;
 |  
| 3211 | 3211 |  
 |  
|  | 3212 | +  // The last TimeStamp when the keyup event did not exit fullscreen because it
 |  
|  | 3213 | +  // was consumed.
 |  
|  | 3214 | +  TimeStamp mLastConsumedEscapeKeyUpForFullscreen;
 |  
|  | 3215 | +
 |  
| 3212 | 3216 |    struct CapturingContentInfo final {
 |  
| 3213 | 3217 |      CapturingContentInfo()
 |  
| 3214 | 3218 |          : mRemoteTarget(nullptr),
 |  layout/base/nsCaret.cpp
 
 
| ... | ... | @@ -855,7 +855,7 @@ size_t nsCaret::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const { |  
| 855 | 855 |  bool nsCaret::IsMenuPopupHidingCaret() {
 |  
| 856 | 856 |    // Check if there are open popups.
 |  
| 857 | 857 |    nsXULPopupManager* popMgr = nsXULPopupManager::GetInstance();
 |  
| 858 |  | -  nsTArray<nsIFrame*> popups;
 |  
|  | 858 | +  nsTArray<nsMenuPopupFrame*> popups;
 |  
| 859 | 859 |    popMgr->GetVisiblePopups(popups);
 |  
| 860 | 860 |  
 |  
| 861 | 861 |    if (popups.Length() == 0)
 |  
| ... | ... | @@ -873,7 +873,7 @@ bool nsCaret::IsMenuPopupHidingCaret() { |  
| 873 | 873 |    // If there's a menu popup open before the popup with
 |  
| 874 | 874 |    // the caret, don't show the caret.
 |  
| 875 | 875 |    for (uint32_t i = 0; i < popups.Length(); i++) {
 |  
| 876 |  | -    nsMenuPopupFrame* popupFrame = static_cast<nsMenuPopupFrame*>(popups[i]);
 |  
|  | 876 | +    nsMenuPopupFrame* popupFrame = popups[i];
 |  
| 877 | 877 |      nsIContent* popupContent = popupFrame->GetContent();
 |  
| 878 | 878 |  
 |  
| 879 | 879 |      if (caretContent->IsInclusiveDescendantOf(popupContent)) {
 |  layout/base/nsLayoutUtils.cpp
 
 
| ... | ... | @@ -138,6 +138,7 @@ |  
| 138 | 138 |  #include "nsIScrollableFrame.h"
 |  
| 139 | 139 |  #include "nsIWidget.h"
 |  
| 140 | 140 |  #include "nsListControlFrame.h"
 |  
|  | 141 | +#include "nsMenuPopupFrame.h"
 |  
| 141 | 142 |  #include "nsPIDOMWindow.h"
 |  
| 142 | 143 |  #include "nsPlaceholderFrame.h"
 |  
| 143 | 144 |  #include "nsPresContext.h"
 |  
| ... | ... | @@ -1757,10 +1758,10 @@ nsIFrame* nsLayoutUtils::GetPopupFrameForPoint( |  
| 1757 | 1758 |    if (!pm) {
 |  
| 1758 | 1759 |      return nullptr;
 |  
| 1759 | 1760 |    }
 |  
| 1760 |  | -  nsTArray<nsIFrame*> popups;
 |  
|  | 1761 | +  nsTArray<nsMenuPopupFrame*> popups;
 |  
| 1761 | 1762 |    pm->GetVisiblePopups(popups);
 |  
| 1762 | 1763 |    // Search from top to bottom
 |  
| 1763 |  | -  for (nsIFrame* popup : popups) {
 |  
|  | 1764 | +  for (nsMenuPopupFrame* popup : popups) {
 |  
| 1764 | 1765 |      if (popup->PresContext()->GetRootPresContext() != aRootPresContext) {
 |  
| 1765 | 1766 |        continue;
 |  
| 1766 | 1767 |      }
 |  layout/xul/nsXULPopupManager.cpp
 
 
| ... | ... | @@ -53,6 +53,7 @@ |  
| 53 | 53 |  #include "mozilla/EventStateManager.h"
 |  
| 54 | 54 |  #include "mozilla/LookAndFeel.h"
 |  
| 55 | 55 |  #include "mozilla/MouseEvents.h"
 |  
|  | 56 | +#include "mozilla/PointerLockManager.h"
 |  
| 56 | 57 |  #include "mozilla/PresShell.h"
 |  
| 57 | 58 |  #include "mozilla/Services.h"
 |  
| 58 | 59 |  #include "mozilla/StaticPrefs_layout.h"
 |  
| ... | ... | @@ -987,6 +988,7 @@ bool nsXULPopupManager::ShowPopupAsNativeMenu(Element* aPopup, int32_t aXPos, |  
| 987 | 988 |      EventStateManager::ClearGlobalActiveContent(activeESM);
 |  
| 988 | 989 |      activeESM->StopTrackingDragGesture(true);
 |  
| 989 | 990 |    }
 |  
|  | 991 | +  PointerLockManager::Unlock();
 |  
| 990 | 992 |    PresShell::ReleaseCapturingContent();
 |  
| 991 | 993 |  
 |  
| 992 | 994 |    return true;
 |  
| ... | ... | @@ -1201,6 +1203,10 @@ void nsXULPopupManager::ShowPopupCallback(Element* aPopup, |  
| 1201 | 1203 |    // Caret visibility may have been affected, ensure that
 |  
| 1202 | 1204 |    // the caret isn't now drawn when it shouldn't be.
 |  
| 1203 | 1205 |    CheckCaretDrawingState();
 |  
|  | 1206 | +
 |  
|  | 1207 | +  if (popupType != PopupType::Tooltip) {
 |  
|  | 1208 | +    PointerLockManager::Unlock();
 |  
|  | 1209 | +  }
 |  
| 1204 | 1210 |  }
 |  
| 1205 | 1211 |  
 |  
| 1206 | 1212 |  nsMenuChainItem* nsXULPopupManager::FindPopup(Element* aPopup) const {
 |  
| ... | ... | @@ -1851,8 +1857,17 @@ nsIContent* nsXULPopupManager::GetTopActiveMenuItemContent() { |  
| 1851 | 1857 |    return nullptr;
 |  
| 1852 | 1858 |  }
 |  
| 1853 | 1859 |  
 |  
| 1854 |  | -void nsXULPopupManager::GetVisiblePopups(nsTArray<nsIFrame*>& aPopups) {
 |  
|  | 1860 | +void nsXULPopupManager::GetVisiblePopups(nsTArray<nsMenuPopupFrame*>& aPopups,
 |  
|  | 1861 | +                                         bool aIncludeNativeMenu) {
 |  
| 1855 | 1862 |    aPopups.Clear();
 |  
|  | 1863 | +  if (aIncludeNativeMenu && mNativeMenu) {
 |  
|  | 1864 | +    nsCOMPtr<nsIContent> popup = mNativeMenu->Element();
 |  
|  | 1865 | +    nsMenuPopupFrame* popupFrame = GetPopupFrameForContent(popup, true);
 |  
|  | 1866 | +    if (popupFrame && popupFrame->IsVisible() &&
 |  
|  | 1867 | +        !popupFrame->IsMouseTransparent()) {
 |  
|  | 1868 | +      aPopups.AppendElement(popupFrame);
 |  
|  | 1869 | +    }
 |  
|  | 1870 | +  }
 |  
| 1856 | 1871 |    for (nsMenuChainItem* item = mPopups.get(); item; item = item->GetParent()) {
 |  
| 1857 | 1872 |      // Skip panels which are not visible as well as popups that are transparent
 |  
| 1858 | 1873 |      // to mouse events.
 |  layout/xul/nsXULPopupManager.h
 
 
| ... | ... | @@ -184,10 +184,10 @@ using HidePopupOptions = mozilla::EnumSet<HidePopupOption>; |  
| 184 | 184 |   */
 |  
| 185 | 185 |  extern const nsNavigationDirection DirectionFromKeyCodeTable[2][6];
 |  
| 186 | 186 |  
 |  
| 187 |  | -#define NS_DIRECTION_FROM_KEY_CODE(frame, keycode) \
 |  
| 188 |  | -  (DirectionFromKeyCodeTable[static_cast<uint8_t>( \
 |  
| 189 |  | -      (frame)->StyleVisibility()->mDirection)][(   \
 |  
| 190 |  | -      keycode)-mozilla::dom::KeyboardEvent_Binding::DOM_VK_END])
 |  
|  | 187 | +#define NS_DIRECTION_FROM_KEY_CODE(frame, keycode)                    \
 |  
|  | 188 | +  (DirectionFromKeyCodeTable                                          \
 |  
|  | 189 | +       [static_cast<uint8_t>((frame)->StyleVisibility()->mDirection)] \
 |  
|  | 190 | +       [(keycode) - mozilla::dom::KeyboardEvent_Binding::DOM_VK_END])
 |  
| 191 | 191 |  
 |  
| 192 | 192 |  // Used to hold information about a popup that is about to be opened.
 |  
| 193 | 193 |  struct PendingPopup {
 |  
| ... | ... | @@ -601,8 +601,10 @@ class nsXULPopupManager final : public nsIDOMEventListener, |  
| 601 | 601 |    /**
 |  
| 602 | 602 |     * Return an array of all the open and visible popup frames for
 |  
| 603 | 603 |     * menus, in order from top to bottom.
 |  
|  | 604 | +   * XXX should we always include native menu?
 |  
| 604 | 605 |     */
 |  
| 605 |  | -  void GetVisiblePopups(nsTArray<nsIFrame*>& aPopups);
 |  
|  | 606 | +  void GetVisiblePopups(nsTArray<nsMenuPopupFrame*>& aPopups,
 |  
|  | 607 | +                        bool aIncludeNativeMenu = false);
 |  
| 606 | 608 |  
 |  
| 607 | 609 |    /**
 |  
| 608 | 610 |     * Get the node that last triggered a popup or tooltip in the document
 |  modules/libpref/init/StaticPrefList.yaml
 
 
| ... | ... | @@ -2701,6 +2701,13 @@ |  
| 2701 | 2701 |    value: false
 |  
| 2702 | 2702 |    mirror: always
 |  
| 2703 | 2703 |  
 |  
|  | 2704 | +# The interval in milliseconds between two Escape key events where the second
 |  
|  | 2705 | +# key event will exit fullscreen, even if it is consumed.
 |  
|  | 2706 | +- name: dom.fullscreen.force_exit_on_multiple_escape_interval
 |  
|  | 2707 | +  type: uint32_t
 |  
|  | 2708 | +  value: 500
 |  
|  | 2709 | +  mirror: always
 |  
|  | 2710 | +
 |  
| 2704 | 2711 |  # Whether fullscreen should make the rest of the document inert.
 |  
| 2705 | 2712 |  # This matches other browsers but historically not Gecko.
 |  
| 2706 | 2713 |  - name: dom.fullscreen.modal
 |  
| ... | ... | @@ -11417,6 +11424,11 @@ |  
| 11417 | 11424 |    value: false
 |  
| 11418 | 11425 |    mirror: always
 |  
| 11419 | 11426 |  
 |  
|  | 11427 | +- name: network.cookie.sameSite.crossSiteIframeSetCheck
 |  
|  | 11428 | +  type: bool
 |  
|  | 11429 | +  value: true
 |  
|  | 11430 | +  mirror: always
 |  
|  | 11431 | +
 |  
| 11420 | 11432 |  - name: network.cookie.thirdparty.sessionOnly
 |  
| 11421 | 11433 |    type: bool
 |  
| 11422 | 11434 |    value: false
 |  netwerk/cookie/CookieService.cpp
 
 
| ... | ... | @@ -675,6 +675,18 @@ CookieService::SetCookieStringFromHttp(nsIURI* aHostURI, |  
| 675 | 675 |    if (!addonAllowsLoad) {
 |  
| 676 | 676 |      mThirdPartyUtil->IsThirdPartyChannel(aChannel, aHostURI,
 |  
| 677 | 677 |                                           &isForeignAndNotAddon);
 |  
|  | 678 | +
 |  
|  | 679 | +    // include sub-document navigations from cross-site to same-site
 |  
|  | 680 | +    // wrt top-level in our check for thirdparty-ness
 |  
|  | 681 | +    if (StaticPrefs::network_cookie_sameSite_crossSiteIframeSetCheck() &&
 |  
|  | 682 | +        !isForeignAndNotAddon &&
 |  
|  | 683 | +        loadInfo->GetExternalContentPolicyType() ==
 |  
|  | 684 | +            ExtContentPolicy::TYPE_SUBDOCUMENT) {
 |  
|  | 685 | +      bool triggeringPrincipalIsThirdParty = false;
 |  
|  | 686 | +      BasePrincipal::Cast(loadInfo->TriggeringPrincipal())
 |  
|  | 687 | +          ->IsThirdPartyURI(channelURI, &triggeringPrincipalIsThirdParty);
 |  
|  | 688 | +      isForeignAndNotAddon |= triggeringPrincipalIsThirdParty;
 |  
|  | 689 | +    }
 |  
| 678 | 690 |    }
 |  
| 679 | 691 |  
 |  
| 680 | 692 |    nsCString cookieHeader(aCookieHeader);
 |  netwerk/cookie/CookieServiceChild.cpp
 
 
| ... | ... | @@ -517,6 +517,18 @@ CookieServiceChild::SetCookieStringFromHttp(nsIURI* aHostURI, |  
| 517 | 517 |    if (!addonAllowsLoad) {
 |  
| 518 | 518 |      mThirdPartyUtil->IsThirdPartyChannel(aChannel, aHostURI,
 |  
| 519 | 519 |                                           &isForeignAndNotAddon);
 |  
|  | 520 | +
 |  
|  | 521 | +    // include sub-document navigations from cross-site to same-site
 |  
|  | 522 | +    // wrt top-level in our check for thirdparty-ness
 |  
|  | 523 | +    if (StaticPrefs::network_cookie_sameSite_crossSiteIframeSetCheck() &&
 |  
|  | 524 | +        !isForeignAndNotAddon &&
 |  
|  | 525 | +        loadInfo->GetExternalContentPolicyType() ==
 |  
|  | 526 | +            ExtContentPolicy::TYPE_SUBDOCUMENT) {
 |  
|  | 527 | +      bool triggeringPrincipalIsThirdParty = false;
 |  
|  | 528 | +      BasePrincipal::Cast(loadInfo->TriggeringPrincipal())
 |  
|  | 529 | +          ->IsThirdPartyURI(finalChannelURI, &triggeringPrincipalIsThirdParty);
 |  
|  | 530 | +      isForeignAndNotAddon |= triggeringPrincipalIsThirdParty;
 |  
|  | 531 | +    }
 |  
| 520 | 532 |    }
 |  
| 521 | 533 |  
 |  
| 522 | 534 |    bool moreCookies;
 |  testing/web-platform/meta/cookies/samesite/setcookie-navigation.https.html.ini
 
 
| 1 | 1 |  [setcookie-navigation.https.html]
 |  
|  | 2 | +  prefs: [network.cookie.sameSite.laxByDefault:true, network.cookie.sameSite.noneRequiresSecure:true]
 |  
| 2 | 3 |    expected:
 |  
| 3 | 4 |      if (os == "android") and fission: [OK, TIMEOUT] |  
| 4 |  | -  [Cross-site to same-site iframe navigation should only be able to set SameSite=None cookies.]
 |  
| 5 |  | -    expected: FAIL
 |  
| 6 |  | -
 |  
| 7 |  | -  [Same-site to cross-site-site iframe navigation should only be able to set SameSite=None cookies.]
 |  
| 8 |  | -    expected: FAIL
 |  
| 9 |  | -
 |  
| 10 |  | -  [Cross-site to cross-site iframe navigation should only be able to set SameSite=None cookies.]
 |  
| 11 |  | -    expected: FAIL |  
 |