ladybird/Libraries/LibWeb/Internals/Internals.idl
sideshowbarker 03f6f25b11 LibWeb: Skip user-select:none when extracting selected text
Problem: Select All (Ctrl+A or the context menu) followed by Ctrl+C
unexpectedly copies text from elements with user-select:none — breaking
compat with Chrome and Firefox, which both exclude user-select:none
content from the clipboard.

Cause: Navigable::selected_text() walks the selection range via
visible_text_in_range() and concatenates each text node’s data. The walk
filters out nodes without a layout, but not nodes whose used value of
user-select is ‘none’.

Fix: Add a user-select check at each visible_text_in_range() walk point.
The Selection range itself is left unchanged. Selection.toString() still
returns the full text per spec — but the clipboard-extraction path now
excludes user-select: none subtrees, per spec
2026-05-28 12:15:21 +01:00

117 lines
5.3 KiB
Text

[Exposed=Nobody]
interface Internals {
undefined signalTestIsDone(DOMString text);
undefined setTestTimeout(double milliseconds);
undefined loadReferenceTestMetadata();
undefined loadTestVariants();
DOMString setTimeZone(DOMString timeZone);
undefined gc();
Promise<undefined> gcAsync();
// Clears a named environment binding and forces its current cell to be treated as garbage.
// This does not work for values stored only in optimized locals or registers.
undefined markAsGarbage(DOMString variableName);
object hitTest(double x, double y);
const unsigned short MOD_NONE = 0;
const unsigned short MOD_ALT = 1;
const unsigned short MOD_CTRL = 2;
const unsigned short MOD_SHIFT = 4;
const unsigned short MOD_SUPER = 8;
const unsigned short MOD_KEYPAD = 16;
const unsigned short BUTTON_LEFT = 0;
const unsigned short BUTTON_MIDDLE = 1;
const unsigned short BUTTON_RIGHT = 2;
undefined sendText(HTMLElement target, DOMString text, optional unsigned short modifiers = 0);
undefined sendKey(HTMLElement target, DOMString keyName, optional unsigned short modifiers = 0);
undefined paste(HTMLElement target, Utf16DOMString text);
undefined commitText();
// Low-level mouse primitives
undefined mouseDown(double x, double y, optional unsigned short clickCount = 1, optional unsigned short button = 0, optional unsigned short modifiers = 0);
undefined mouseUp(double x, double y, optional unsigned short button = 0, optional unsigned short modifiers = 0);
undefined mouseMove(double x, double y, optional unsigned short modifiers = 0);
undefined mouseLeave();
// High-level mouse conveniences
undefined click(double x, double y, optional unsigned short clickCount = 1, optional unsigned short button = 0, optional unsigned short modifiers = 0);
undefined clickAndHold(double x, double y, optional unsigned short clickCount = 1, optional unsigned short button = 0, optional unsigned short modifiers = 0);
Promise<undefined> wheel(double x, double y, double deltaX, double deltaY);
undefined pinch(double x, double y, double scaleDelta, optional unsigned short modifiers = 0);
DOMString currentCursor();
// Returns the text that would be placed on the clipboard if the user copied the current selection now.
// Excludes nodes whose used value of user-select is 'none' — mirroring what browsers actually copy.
DOMString selectedTextForClipboard();
boolean dispatchUserActivatedEvent(EventTarget target, Event event);
undefined spoofCurrentURL(USVString url);
InternalAnimationTimeline createInternalAnimationTimeline();
undefined simulateDragStart(double x, double y, DOMString mimeType, DOMString contents);
undefined simulateDragMove(double x, double y);
undefined simulateDrop(double x, double y);
undefined expireCookiesWithTimeOffset(long long seconds);
boolean setHttpMemoryCacheEnabled(boolean enabled);
undefined setContentBlockers(DOMString patterns);
undefined setContentBlockingEnabled(boolean enabled);
DOMString getComputedRole(Element element);
DOMString getComputedLabel(Element element);
DOMString getComputedAriaLevel(Element element);
unsigned short getEchoServerPort();
undefined setBrowserZoom(double factor);
undefined setDevicePixelRatio(double ratio);
readonly attribute boolean headless;
DOMString dumpDisplayList();
DOMString dumpLayoutTree(Node node);
DOMString dumpPaintableTree(Node node);
DOMString dumpStackingContextTree();
DOMString dumpGCGraph();
DOMString dumpSessionHistory();
// Returns the shadow root of the element, if it has one, even if it's not normally accessible to JS.
ShadowRoot? getShadowRoot(Element element);
undefined handleSDLInputEvents();
undefined setEnvironmentsTopLevelURL(USVString url);
InternalGamepad connectVirtualGamepad();
undefined setHighlightedNode(Node? node);
undefined clearElement(HTMLElement element);
// Returns a snapshot of the style-invalidation and recomputation counters for the current document.
// Keys include hasAncestorWalkInvocations, hasInvalidationRuleCacheBuilds,
// styleInvalidations, elementStyleRecomputations, and elementStyleNoopRecomputations.
object getStyleInvalidationCounters();
undefined resetStyleInvalidationCounters();
// Flushes pending style work without forcing layout.
undefined updateStyle();
undefined setPreferredColorScheme(DOMString colorScheme);
DOMString canvasColorScheme();
// Returns the selector-insight cache state for stylesheet invalidation tests.
boolean styleSheetMayHaveHasSelectors(CSSStyleSheet sheet);
unsigned long long activeImageStyleValueAnimationCount();
object asyncScrollingState();
boolean asyncScrollingStateBlocksWheelEventAt(double x, double y);
boolean asyncScrollingStateCanWheelScrollAt(double x, double y, double deltaX, double deltaY, optional boolean forceStaleWheelEventRegions = false);
DOMString asyncScrollingStateWheelRoutingAdmission();
DOMString asyncScrollingStateWheelScrollAdmissionAt(double x, double y, double deltaX, double deltaY, optional boolean forceStaleWheelEventRegions = false);
DOMString asyncScrollingStateWheelTargetAt(double x, double y, double deltaX, double deltaY);
};