tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 4363c7054776a88cb81017ea928709ab9820ec06
parent 43609422072d75775412da5729121bd121106e5e
Author: Atila Butkovits <abutkovits@mozilla.com>
Date:   Wed, 22 Oct 2025 18:23:42 +0300

Revert "Bug 1751335 - Adding right-click select on text in macOS r=masayuki" for causing bustages complaining about StaticPrefList.yaml.

This reverts commit 11f456595ac43091170bff03ee639757f0428667.

Diffstat:
Mbrowser/actors/ContextMenuChild.sys.mjs | 40+++++-----------------------------------
Mbrowser/base/content/test/contextMenu/browser.toml | 2--
Dbrowser/base/content/test/contextMenu/browser_right_click_select.js | 309-------------------------------------------------------------------------------
Mlayout/generic/nsIFrame.cpp | 68++++++++++----------------------------------------------------------
Mmodules/libpref/init/StaticPrefList.yaml | 16----------------
5 files changed, 15 insertions(+), 420 deletions(-)

diff --git a/browser/actors/ContextMenuChild.sys.mjs b/browser/actors/ContextMenuChild.sys.mjs @@ -662,45 +662,14 @@ export class ContextMenuChild extends JSWindowActorChild { } catch (e) {} } - this._setContext(aEvent); - let context = this.context; - this.target = context.target; - - // If right-click select is enabled, we're on a link, and the link - // text is not selected, select the link text. - if ( - context.onLink && - Services.prefs.getBoolPref( - "ui.mouse.right_click.select_under_cursor", - false - ) - ) { - // Check if user-select: none is set on the link or its ancestors - let shouldSelect = true; - let elem = context.link; - while (elem && shouldSelect) { - if (this.contentWindow.getComputedStyle(elem).userSelect === "none") { - shouldSelect = false; - } - elem = elem.parentElement; - } - - if (shouldSelect) { - const range = this.document.createRange(); - range.selectNodeContents(context.link); - if (range.toString().trim().length) { - const sel = this.contentWindow.getSelection(); - if (sel.isCollapsed || !sel.containsNode(context.link, true)) { - sel.removeAllRanges(); - sel.addRange(range); - } - } - } - } let selectionInfo = lazy.SelectionUtils.getSelectionDetails( this.contentWindow ); + this._setContext(aEvent); + let context = this.context; + this.target = context.target; + let spellInfo = null; let editFlags = null; @@ -1249,6 +1218,7 @@ export class ContextMenuChild extends JSWindowActorChild { context.onTelLink = context.linkProtocol == "tel"; context.onMozExtLink = context.linkProtocol == "moz-extension"; context.onSaveableLink = this._isLinkSaveable(context.link); + context.isSponsoredLink = (elem.ownerDocument.URL === "about:newtab" || elem.ownerDocument.URL === "about:home") && diff --git a/browser/base/content/test/contextMenu/browser.toml b/browser/base/content/test/contextMenu/browser.toml @@ -100,8 +100,6 @@ skip-if = ["os == 'linux' && socketprocess_networking"] ["browser_copy_link_to_highlight_viewsource.js"] -["browser_right_click_select.js"] - ["browser_save_image.js"] ["browser_strip_on_share_link.js"] diff --git a/browser/base/content/test/contextMenu/browser_right_click_select.js b/browser/base/content/test/contextMenu/browser_right_click_select.js @@ -1,309 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -const PREF_RIGHT_CLICK_SELECTS = "ui.mouse.right_click.select_under_cursor"; -const PREF_EDITABLE = "ui.mouse.right_click.select_in_editable"; -const PREF_EAT_SPACE = "layout.word_select.eat_space_to_next_word"; - -const TEST_HTML = `<!doctype html> -<title>Right-click selection</title> -<style> - #noselect { user-select: none; } - .all { user-select: all; } -</style> - <p id="p1">Test Page <a id="link1" href="https://example.com">link text here</a> additional</p> - <span id="plain">some plain selectable text</span> - <div id="noselect">Unselectable box with <a id="nlink" href="https://example.com">link inside</a></div> - <div class="all">user-select: all ancestor: <a id="alink" href="https://example.com">link text here</a></div> - `; - -const EDITABLE_HTML = `<!doctype html> -<title>Editable right-click</title> -<div id="ed" contenteditable>hello world</div> -`; -const EDITABLE_PAGE = "data:text/html," + encodeURIComponent(EDITABLE_HTML); -const TEST_PAGE = "data:text/html," + encodeURIComponent(TEST_HTML); - -// close context menu -async function closeContextMenu(contextMenuEl) { - const menuHidden = BrowserTestUtils.waitForEvent( - contextMenuEl, - "popuphidden" - ); - contextMenuEl.hidePopup(); - await menuHidden; -} - -// Right-click the center of a word -async function openContextMenuOnWord(tabBrowser, elementSelector, targetWord) { - const contextMenuEl = document.getElementById("contentAreaContextMenu"); - const menuShown = BrowserTestUtils.waitForEvent(contextMenuEl, "popupshown"); - await SpecialPowers.spawn( - tabBrowser, - [elementSelector, targetWord], - (selector, word) => { - const doc = content.document; - const element = doc.querySelector(selector); - const textNode = element.firstChild; - const fullText = textNode.textContent; - const startIndex = fullText.indexOf(word); - const range = doc.createRange(); - range.setStart(textNode, startIndex); - range.setEnd(textNode, startIndex + word.length); - const wordRect = range.getBoundingClientRect(); - const x = wordRect.left + wordRect.width / 2; - const y = wordRect.top + wordRect.height / 2; - content.focus(); - content.windowUtils.sendMouseEvent("mousedown", x, y, 2, 1, 0); - content.windowUtils.sendMouseEvent("contextmenu", x, y, 2, 1, 0); - } - ); - await menuShown; - return contextMenuEl; -} - -async function getSelectionText(tabBrowser) { - return SpecialPowers.spawn(tabBrowser, [], () => - content.getSelection().toString() - ); -} - -add_setup(async function () { - await SpecialPowers.pushPrefEnv({ - set: [[PREF_EAT_SPACE, false]], - }); -}); - -add_task(async function right_click_plain_text_selects_clicked_word() { - await SpecialPowers.pushPrefEnv({ set: [[PREF_RIGHT_CLICK_SELECTS, true]] }); - await BrowserTestUtils.withNewTab(TEST_PAGE, async tabBrowser => { - const contextMenuEl = await openContextMenuOnWord( - tabBrowser, - "#plain", - "plain" - ); - const selection = await getSelectionText(tabBrowser); - is(selection, "plain", "Right-click selected just the clicked word"); - const copy = contextMenuEl.querySelector("#context-copy"); - const copyLink = contextMenuEl.querySelector("#context-copylink"); - ok(BrowserTestUtils.isVisible(copy), "Copy is visible"); - ok(!copy.hasAttribute("disabled"), "Copy is enabled"); - ok( - !BrowserTestUtils.isVisible(copyLink), - "Copy Link is hidden on non-link text" - ); - await closeContextMenu(contextMenuEl); - }); -}); - -add_task(async function user_select_none_container_does_not_auto_select() { - await SpecialPowers.pushPrefEnv({ set: [[PREF_RIGHT_CLICK_SELECTS, true]] }); - await BrowserTestUtils.withNewTab(TEST_PAGE, async tabBrowser => { - const contextMenuEl = await openContextMenuOnWord( - tabBrowser, - "#nlink", - "link" - ); - const selection = await getSelectionText(tabBrowser); - is(selection, "", "No selection created in user-select:none region"); - const copyLink = contextMenuEl.querySelector("#context-copylink"); - ok( - BrowserTestUtils.isVisible(copyLink), - "Copy Link visible for link in noselect" - ); - await closeContextMenu(contextMenuEl); - }); -}); - -add_task(async function right_click_link_text_shows_copy_and_copy_link() { - await SpecialPowers.pushPrefEnv({ set: [[PREF_RIGHT_CLICK_SELECTS, true]] }); - await BrowserTestUtils.withNewTab(TEST_PAGE, async tabBrowser => { - const contextMenuEl = await openContextMenuOnWord( - tabBrowser, - "#link1", - "link" - ); - const selection = await getSelectionText(tabBrowser); - is(selection, "link text here", "Right-click selected whole link text"); - const copy = contextMenuEl.querySelector("#context-copy"); - const copyLink = contextMenuEl.querySelector("#context-copylink"); - ok(BrowserTestUtils.isVisible(copy), "Copy is visible"); - ok(!copy.hasAttribute("disabled"), "Copy is enabled"); - ok( - BrowserTestUtils.isVisible(copyLink), - "Copy Link is visible for link text" - ); - await closeContextMenu(contextMenuEl); - }); -}); - -add_task(async function right_click_moves_selection_to_clicked_word() { - await SpecialPowers.pushPrefEnv({ set: [[PREF_RIGHT_CLICK_SELECTS, true]] }); - await BrowserTestUtils.withNewTab(TEST_PAGE, async tabBrowser => { - const contextMenuEl1 = await openContextMenuOnWord( - tabBrowser, - "#plain", - "text" - ); - await closeContextMenu(contextMenuEl1); - - const contextMenuEl2 = await openContextMenuOnWord( - tabBrowser, - "#plain", - "plain" - ); - const selection = await getSelectionText(tabBrowser); - is(selection, "plain", "Selection moved to the clicked word"); - const copy = contextMenuEl2.querySelector("#context-copy"); - ok(BrowserTestUtils.isVisible(copy), "Copy visible"); - await closeContextMenu(contextMenuEl2); - }); -}); - -add_task( - async function right_click_does_not_move_existing_selection_if_already_selected() { - await SpecialPowers.pushPrefEnv({ - set: [[PREF_RIGHT_CLICK_SELECTS, true]], - }); - await BrowserTestUtils.withNewTab(TEST_PAGE, async tabBrowser => { - await SpecialPowers.spawn(tabBrowser, [], () => { - const doc = content.document; - const element = doc.getElementById("plain"); - const range = doc.createRange(); - range.selectNodeContents(element); - const selection = content.getSelection(); - selection.removeAllRanges(); - selection.addRange(range); - }); - const menu = await openContextMenuOnWord(tabBrowser, "#plain", "plain"); - const selection = await getSelectionText(tabBrowser); - is( - selection, - "some plain selectable text", - "Right-click does not move an existing selection if already selected" - ); - const copy = menu.querySelector("#context-copy"); - ok( - BrowserTestUtils.isVisible(copy), - "Copy visible on existing selection" - ); - await closeContextMenu(menu); - }); - } -); - -add_task(async function pref_off_does_not_select_plain_or_link() { - await SpecialPowers.pushPrefEnv({ set: [[PREF_RIGHT_CLICK_SELECTS, false]] }); - await BrowserTestUtils.withNewTab(TEST_PAGE, async tabBrowser => { - let menu = await openContextMenuOnWord(tabBrowser, "#plain", "plain"); - let sel = await getSelectionText(tabBrowser); - is(sel, "", "pref=false: no selection on plain text"); - ok( - !BrowserTestUtils.isVisible(menu.querySelector("#context-copy")), - "pref=false: Copy hidden without selection on plain text" - ); - await closeContextMenu(menu); - - menu = await openContextMenuOnWord(tabBrowser, "#link1", "link"); - sel = await getSelectionText(tabBrowser); - is(sel, "", "pref=false: no selection on link text"); - ok( - BrowserTestUtils.isVisible(menu.querySelector("#context-copylink")), - "pref=false: Copy Link still visible on link" - ); - await closeContextMenu(menu); - }); -}); - -add_task(async function user_select_all_ancestor_selects_ancestor_contents() { - await SpecialPowers.pushPrefEnv({ set: [[PREF_RIGHT_CLICK_SELECTS, true]] }); - await BrowserTestUtils.withNewTab(TEST_PAGE, async tabBrowser => { - const menu = await openContextMenuOnWord(tabBrowser, "#alink", "link"); - const sel = await getSelectionText(tabBrowser); - is( - sel, - "link text here", - "Select the nearest user-select:all ancestor's contents" - ); - ok( - BrowserTestUtils.isVisible(menu.querySelector("#context-copy")), - "Copy visible with selection" - ); - ok( - BrowserTestUtils.isVisible(menu.querySelector("#context-copylink")), - "Copy Link visible on link" - ); - await closeContextMenu(menu); - }); -}); - -add_task(async function editable_pref_off_does_not_select_word() { - await SpecialPowers.pushPrefEnv({ - set: [ - [PREF_RIGHT_CLICK_SELECTS, true], - [PREF_EDITABLE, false], - ], - }); - await BrowserTestUtils.withNewTab(EDITABLE_PAGE, async tabBrowser => { - const menu = await openContextMenuOnWord(tabBrowser, "#ed", "world"); - const sel = await getSelectionText(tabBrowser); - is(sel, "", "pref=false: no text selection should be created in editable"); - await closeContextMenu(menu); - }); -}); - -add_task(async function editable_pref_on_selects_word() { - await SpecialPowers.pushPrefEnv({ - set: [ - [PREF_RIGHT_CLICK_SELECTS, true], - [PREF_EDITABLE, true], - ], - }); - await BrowserTestUtils.withNewTab(EDITABLE_PAGE, async tabBrowser => { - const menu = await openContextMenuOnWord(tabBrowser, "#ed", "world"); - const sel = await getSelectionText(tabBrowser); - is( - sel, - "world", - "pref=true: right-click selects the clicked word in editable" - ); - ok( - BrowserTestUtils.isVisible(menu.querySelector("#context-copy")), - "pref=true: Copy visible with a selection" - ); - await closeContextMenu(menu); - }); -}); - -add_task(async function editable_existing_selection_is_preserved() { - await SpecialPowers.pushPrefEnv({ - set: [ - [PREF_RIGHT_CLICK_SELECTS, true], - [PREF_EDITABLE, true], - ], - }); - await BrowserTestUtils.withNewTab(EDITABLE_PAGE, async tabBrowser => { - await SpecialPowers.spawn(tabBrowser, [], () => { - const el = content.document.getElementById("ed").firstChild; - const r = content.document.createRange(); - const txt = el.data; - const start = txt.indexOf("hello"); - r.setStart(el, start); - r.setEnd(el, start + "hello world".length); - const sel = content.getSelection(); - sel.removeAllRanges(); - sel.addRange(r); - }); - - const menu = await openContextMenuOnWord(tabBrowser, "#ed", "hello"); - const sel = await getSelectionText(tabBrowser); - is( - sel, - "hello world", - "existing non-collapsed selection in editable is preserved" - ); - await closeContextMenu(menu); - }); -}); diff --git a/layout/generic/nsIFrame.cpp b/layout/generic/nsIFrame.cpp @@ -4962,64 +4962,16 @@ nsresult nsIFrame::MoveCaretToEventPoint(nsPresContext* aPresContext, const bool isSecondaryButton = aMouseEvent->mButton == MouseButton::eSecondary; - if (isSecondaryButton) { - const bool rightClickSelectIsEnabled = - StaticPrefs::ui_mouse_right_click_select_under_cursor(); - const bool allowEditable = - StaticPrefs::ui_mouse_right_click_select_in_editable(); - const bool isEditableHere = - offsets.content && offsets.content->IsEditable(); - const bool selectClickedWord = - rightClickSelectIsEnabled && (!isEditableHere || allowEditable); - // On right-click, collapse the selection to the click point if enabled - // in prefs, and either the target isn't editable or editable fields are - // allowed. - - // sel is grabbed by hideSelectionChanges, so, it's safe to access this even - // after running script. - const OwningNonNull<Selection> sel = frameselection->NormalSelection(); - const SelectionBatcher hideSelectionChanges( - *sel, __FUNCTION__, nsISelectionListener::MOUSEDOWN_REASON); - const bool clickedOnCaret = - sel->IsCollapsed() && sel->GetAnchorNode() == offsets.content && - sel->AnchorOffset() == static_cast<uint32_t>(offsets.StartOffset()); - if (offsets.content && offsets.offset >= 0 && selectClickedWord && - !nsContentUtils::IsPointInSelection( - *sel, *offsets.content, static_cast<uint32_t>(offsets.offset), - true)) { - // Collapse selection to the clicked point. - nsCOMPtr<nsIContent> content = offsets.content; - fc->HandleClick(content, offsets.StartOffset(), offsets.EndOffset(), - nsFrameSelection::FocusMode::kCollapseToNewPoint, - offsets.associate); - } - - if (!MovingCaretToEventPointAllowedIfSecondaryButtonEvent( - *frameselection, *aMouseEvent, *offsets.content, - // When we collapse selection in nsFrameSelection::TakeFocus, - // we always collapse selection to the start offset. Therefore, - // we can ignore the end offset here. E.g., when an <img> is - // clicked, set the primary offset to after it, but the the - // secondary offset may be before it, see OffsetsForSingleFrame for - // the detail. - offsets.StartOffset())) { - return NS_OK; - } - - if (selectClickedWord) { - // Skip word selection when right-clicking directly on the caret in an - // editable field. Users typically right-click here to open the context - // menu, not to select text. - if (isEditableHere && clickedOnCaret) { - return NS_OK; - } - nsIFrame* frameUnderPoint = - nsLayoutUtils::GetFrameForPoint(RelativeTo{this}, pt); - if (!frameUnderPoint->IsTextFrame()) { - return NS_OK; - } - return SelectByTypeAtPoint(pt, eSelectWord, eSelectWord, 0); - } + if (isSecondaryButton && + !MovingCaretToEventPointAllowedIfSecondaryButtonEvent( + *frameselection, *aMouseEvent, *offsets.content, + // When we collapse selection in nsFrameSelection::TakeFocus, + // we always collapse selection to the start offset. Therefore, + // we can ignore the end offset here. E.g., when an <img> is clicked, + // set the primary offset to after it, but the the secondary offset + // may be before it, see OffsetsForSingleFrame for the detail. + offsets.StartOffset())) { + return NS_OK; } if (aMouseEvent->mMessage == eMouseDown && diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml @@ -18305,22 +18305,6 @@ value: false mirror: always -# When true, right-clicking selects the word/link under the cursor. -- name: ui.mouse.right_click.select_under_cursor - type: bool -#ifdef XP_MACOSX - value: @EARLY_BETA_OR_EARLIER@ -#else - value: false -#endif - mirror: always - -# When true, right-clicking selects the word under the cursor in editable -- name: ui.mouse.right_click.select_in_editable - type: bool - value: false - mirror: always - #--------------------------------------------------------------------------- # Prefs starting with "urlclassifier." #---------------------------------------------------------------------------