mirror of
https://github.com/zen-browser/desktop.git
synced 2026-08-19 05:01:33 +00:00
gh-14843: Prevent quick audio tracks from creating a new controller (gh-14871)
This commit is contained in:
@@ -50,7 +50,7 @@
|
||||
value: true
|
||||
|
||||
- name: zen.view.drag-window-from-content.height-percentage
|
||||
value: 10
|
||||
value: 5
|
||||
|
||||
- name: zen.view.borderless-fullscreen
|
||||
value: true
|
||||
|
||||
@@ -262,7 +262,7 @@
|
||||
light-dark(white, black)
|
||||
);
|
||||
--zen-sidebar-notification-shadow: 0 0 6px light-dark(rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.3));
|
||||
--zen-sidebar-notification-outline: 1px solid light-dark(transparent, rgba(255, 255, 255, 0.15));
|
||||
--zen-sidebar-notification-outline: 1px solid light-dark(transparent, rgba(255, 255, 255, 0.1));
|
||||
|
||||
--zen-sidebar-themed-icon-fill: light-dark(color-mix(in srgb, var(--zen-primary-color) 50%, black), color-mix(in srgb, var(--zen-colors-primary) 15%, #ebebeb));
|
||||
|
||||
|
||||
@@ -451,10 +451,22 @@ class nsZenMediaController {
|
||||
window.addEventListener("TabBrowserDiscarded", onTabDiscardedOrClosed);
|
||||
|
||||
window.addEventListener("DOMAudioPlaybackStarted", event => {
|
||||
this.activateMediaControls(
|
||||
event.target.browsingContext.mediaController,
|
||||
event.target
|
||||
);
|
||||
const browser = event.target;
|
||||
// Only create the card if the media is still playing a moment
|
||||
// later, so short sounds (e.g. notification pings) never produce
|
||||
// one.
|
||||
setTimeout(() => {
|
||||
const mediaController = browser.browsingContext?.mediaController;
|
||||
if (!mediaController?.isPlaying) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.activateMediaControls(mediaController, browser);
|
||||
const card = this.#cardForBrowser(browser);
|
||||
if (card && !card.isSharing) {
|
||||
card.refreshVisibility();
|
||||
}
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
window.addEventListener("DOMAudioPlaybackStopped", () => {
|
||||
@@ -483,8 +495,23 @@ class nsZenMediaController {
|
||||
);
|
||||
}
|
||||
|
||||
#cardForBrowser(browser) {
|
||||
return (
|
||||
Array.from(this.#cards.values()).find(
|
||||
card => card.browser.browserId === browser.browserId
|
||||
) ?? null
|
||||
);
|
||||
}
|
||||
|
||||
activateMediaControls(mediaController, browser) {
|
||||
if (!mediaController?.isActive || this.#cards.has(mediaController.id)) {
|
||||
if (
|
||||
!mediaController?.isActive ||
|
||||
this.#cards.has(mediaController.id) ||
|
||||
// Never stack more than one card for the same browser: sites that
|
||||
// activate a fresh controller for every sound they play (e.g.
|
||||
// notification pings) keep their one card.
|
||||
this.#cardForBrowser(browser)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -572,7 +599,14 @@ class nsZenMediaController {
|
||||
const element = this.#createCardElement();
|
||||
const card = new ZenMediaCard(this, element, browser, controller);
|
||||
this.#cards.set(key, card);
|
||||
card.refreshVisibility();
|
||||
if (controller) {
|
||||
// Media cards start hidden and appear via the delayed check in
|
||||
// DOMAudioPlaybackStarted or on tab switch, like the original bar;
|
||||
// sharing cards show right away.
|
||||
card.element.hidden = true;
|
||||
} else {
|
||||
card.refreshVisibility();
|
||||
}
|
||||
this.onCardVisibilityChanged();
|
||||
return card;
|
||||
}
|
||||
|
||||
@@ -54,33 +54,6 @@ const kInteractiveRoles = new Set([
|
||||
"treegrid",
|
||||
]);
|
||||
|
||||
// Cursors that signal the page considers the area interactive or draggable.
|
||||
const kInteractiveCursors = new Set([
|
||||
"pointer",
|
||||
"grab",
|
||||
"grabbing",
|
||||
"move",
|
||||
"all-scroll",
|
||||
"text",
|
||||
"vertical-text",
|
||||
"cell",
|
||||
"crosshair",
|
||||
"col-resize",
|
||||
"row-resize",
|
||||
"n-resize",
|
||||
"e-resize",
|
||||
"s-resize",
|
||||
"w-resize",
|
||||
"ne-resize",
|
||||
"nw-resize",
|
||||
"se-resize",
|
||||
"sw-resize",
|
||||
"ew-resize",
|
||||
"ns-resize",
|
||||
"nesw-resize",
|
||||
"nwse-resize",
|
||||
]);
|
||||
|
||||
const kGestureListenerOptions = { mozSystemGroup: true, capture: true };
|
||||
|
||||
const kGestureEvents = ["mousemove", "mouseup", "dragstart", "unload"];
|
||||
@@ -276,7 +249,12 @@ export class ZenWindowDragChild extends JSWindowActorChild {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return this.#hasInteractiveCursor(target);
|
||||
// The effective cursor, resolved the same way it is shown to the user.
|
||||
return lazy.zenWindowDragUtils.isInteractiveCursor(
|
||||
event.composedTarget,
|
||||
event.clientX,
|
||||
event.clientY
|
||||
);
|
||||
}
|
||||
|
||||
#isSelectableText(node) {
|
||||
@@ -307,15 +285,4 @@ export class ZenWindowDragChild extends JSWindowActorChild {
|
||||
const role = element.getAttribute?.("role");
|
||||
return !!role && kInteractiveRoles.has(role.toLowerCase());
|
||||
}
|
||||
|
||||
#hasInteractiveCursor(element) {
|
||||
const style = element.ownerGlobal?.getComputedStyle(element);
|
||||
if (!style) {
|
||||
return false;
|
||||
}
|
||||
// The keyword is always the last component of the computed value.
|
||||
// Don't split on "," as url() cursor images may contain commas.
|
||||
const cursor = style.cursor.match(/[a-z-]+$/)?.[0];
|
||||
return kInteractiveCursors.has(cursor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,4 +20,15 @@ interface nsIZenWindowDragUtils : nsISupports {
|
||||
* @param node The node to check.
|
||||
*/
|
||||
boolean isInteractiveContent(in Node node);
|
||||
|
||||
/**
|
||||
* @brief Whether the effective cursor for the given node signals
|
||||
* interactive or draggable content (pointer, text, move, resize, ...).
|
||||
* Unlike computed style, this resolves cursor: auto the same way the
|
||||
* cursor actually shown to the user is chosen.
|
||||
* @param node The deepest node hit by the event.
|
||||
* @param clientX Viewport X coordinate of the event, in CSS pixels.
|
||||
* @param clientY Viewport Y coordinate of the event, in CSS pixels.
|
||||
*/
|
||||
boolean isInteractiveCursor(in Node node, in float clientX, in float clientY);
|
||||
};
|
||||
|
||||
@@ -4,9 +4,13 @@
|
||||
|
||||
#include "nsZenWindowDragUtils.h"
|
||||
|
||||
#include "Units.h"
|
||||
#include "mozilla/PresShell.h"
|
||||
#include "mozilla/ServoStyleConsts.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIFrame.h"
|
||||
|
||||
namespace zen {
|
||||
|
||||
@@ -30,4 +34,57 @@ nsZenWindowDragUtils::IsInteractiveContent(nsINode* aNode, bool* aResult) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsZenWindowDragUtils::IsInteractiveCursor(nsINode* aNode, float aClientX,
|
||||
float aClientY, bool* aResult) {
|
||||
using mozilla::StyleCursorKind;
|
||||
|
||||
*aResult = false;
|
||||
NS_ENSURE_ARG_POINTER(aNode);
|
||||
|
||||
nsIContent* content = nsIContent::FromNode(aNode);
|
||||
nsIFrame* frame = content ? content->GetPrimaryFrame() : nullptr;
|
||||
if (!frame) {
|
||||
return NS_OK;
|
||||
}
|
||||
nsIFrame* rootFrame = frame->PresShell()->GetRootFrame();
|
||||
if (!rootFrame) {
|
||||
return NS_OK;
|
||||
}
|
||||
nsPoint point(mozilla::CSSPixel::ToAppUnits(aClientX),
|
||||
mozilla::CSSPixel::ToAppUnits(aClientY));
|
||||
point -= frame->GetOffsetTo(rootFrame);
|
||||
|
||||
switch (frame->GetCursor(point).mCursor) {
|
||||
case StyleCursorKind::Pointer:
|
||||
case StyleCursorKind::Cell:
|
||||
case StyleCursorKind::Crosshair:
|
||||
case StyleCursorKind::Text:
|
||||
case StyleCursorKind::VerticalText:
|
||||
case StyleCursorKind::Move:
|
||||
case StyleCursorKind::Grab:
|
||||
case StyleCursorKind::Grabbing:
|
||||
case StyleCursorKind::EResize:
|
||||
case StyleCursorKind::NResize:
|
||||
case StyleCursorKind::NeResize:
|
||||
case StyleCursorKind::NwResize:
|
||||
case StyleCursorKind::SResize:
|
||||
case StyleCursorKind::SeResize:
|
||||
case StyleCursorKind::SwResize:
|
||||
case StyleCursorKind::WResize:
|
||||
case StyleCursorKind::EwResize:
|
||||
case StyleCursorKind::NsResize:
|
||||
case StyleCursorKind::NeswResize:
|
||||
case StyleCursorKind::NwseResize:
|
||||
case StyleCursorKind::ColResize:
|
||||
case StyleCursorKind::RowResize:
|
||||
case StyleCursorKind::AllScroll:
|
||||
*aResult = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace zen
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"brandShortName": "Zen",
|
||||
"brandFullName": "Zen Browser",
|
||||
"release": {
|
||||
"displayVersion": "1.21.11b",
|
||||
"displayVersion": "1.21.12b",
|
||||
"github": {
|
||||
"repo": "zen-browser/desktop"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user