From a90a5cba08fdf6c0ceb95101c275108a152a3aed Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 12 Jun 2024 07:35:37 +0200 Subject: Merging upstream version 127.0. Signed-off-by: Daniel Baumann --- .../browser/browser_clipboard_content_analysis.js | 363 +++++++++++++++++++++ 1 file changed, 363 insertions(+) create mode 100644 toolkit/components/contentanalysis/tests/browser/browser_clipboard_content_analysis.js (limited to 'toolkit/components/contentanalysis/tests/browser/browser_clipboard_content_analysis.js') diff --git a/toolkit/components/contentanalysis/tests/browser/browser_clipboard_content_analysis.js b/toolkit/components/contentanalysis/tests/browser/browser_clipboard_content_analysis.js new file mode 100644 index 0000000000..875dbaa6e3 --- /dev/null +++ b/toolkit/components/contentanalysis/tests/browser/browser_clipboard_content_analysis.js @@ -0,0 +1,363 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// This test is used to check copy and paste in editable areas to ensure that non-text +// types (html and images) are copied to and pasted from the clipboard properly. + +var testPage = + "" + + " " + + "
Test Bold After Text
" + + ""; + +let mockCA = makeMockContentAnalysis(); + +add_setup(async function test_setup() { + mockCA = mockContentAnalysisService(mockCA); +}); + +async function testClipboardWithContentAnalysis(allowPaste) { + mockCA.setupForTest(allowPaste); + let tab = BrowserTestUtils.addTab(gBrowser); + let browser = gBrowser.getBrowserForTab(tab); + + gBrowser.selectedTab = tab; + + await promiseTabLoadEvent(tab, "data:text/html," + escape(testPage)); + await SimpleTest.promiseFocus(browser); + + function sendKey(key, code) { + return BrowserTestUtils.synthesizeKey( + key, + { code, accelKey: true }, + browser + ); + } + + // On windows, HTML clipboard includes extra data. + // The values are from widget/windows/nsDataObj.cpp. + const htmlPrefix = navigator.platform.includes("Win") + ? "\n" + : ""; + const htmlPostfix = navigator.platform.includes("Win") + ? "\n\n" + : ""; + + await SpecialPowers.spawn(browser, [], () => { + var doc = content.document; + var main = doc.getElementById("main"); + main.focus(); + + // Select an area of the text. + let selection = doc.getSelection(); + selection.modify("move", "left", "line"); + selection.modify("move", "right", "character"); + selection.modify("move", "right", "character"); + selection.modify("move", "right", "character"); + selection.modify("extend", "right", "word"); + selection.modify("extend", "right", "word"); + }); + + // The data is empty as the selection was copied during the event default phase. + let copyEventPromise = BrowserTestUtils.waitForContentEvent( + browser, + "copy", + false, + event => { + return event.clipboardData.mozItemCount == 0; + } + ); + await SpecialPowers.spawn(browser, [], () => {}); + await sendKey("c"); + await copyEventPromise; + + let pastePromise = SpecialPowers.spawn( + browser, + [htmlPrefix, htmlPostfix, allowPaste], + (htmlPrefixChild, htmlPostfixChild, allowPaste) => { + let selection = content.document.getSelection(); + selection.modify("move", "right", "line"); + + return new Promise((resolve, _reject) => { + content.addEventListener( + "paste", + event => { + let clipboardData = event.clipboardData; + Assert.equal( + clipboardData.mozItemCount, + 1, + "One item on clipboard" + ); + Assert.equal( + clipboardData.types.length, + 2, + "Two types on clipboard" + ); + Assert.equal( + clipboardData.types[0], + "text/html", + "text/html on clipboard" + ); + Assert.equal( + clipboardData.types[1], + "text/plain", + "text/plain on clipboard" + ); + Assert.equal( + clipboardData.getData("text/html"), + allowPaste + ? htmlPrefixChild + "t Bold" + htmlPostfixChild + : "", + "text/html value" + ); + Assert.equal( + clipboardData.getData("text/plain"), + allowPaste ? "t Bold" : "", + "text/plain value" + ); + resolve(); + }, + { capture: true, once: true } + ); + }); + } + ); + + await SpecialPowers.spawn(browser, [], () => {}); + + await sendKey("v"); + await pastePromise; + // 2 calls because there are two formats on the clipboard + is(mockCA.calls.length, 2, "Correct number of calls to Content Analysis"); + assertContentAnalysisRequest( + mockCA.calls[0], + htmlPrefix + "t Bold" + htmlPostfix + ); + assertContentAnalysisRequest(mockCA.calls[1], "t Bold"); + mockCA.clearCalls(); + + let copyPromise = SpecialPowers.spawn(browser, [], () => { + var main = content.document.getElementById("main"); + + Assert.equal( + main.innerHTML, + "Test Bold After Textt Bold", + "Copy and paste html" + ); + + let selection = content.document.getSelection(); + selection.modify("extend", "left", "word"); + selection.modify("extend", "left", "word"); + selection.modify("extend", "left", "character"); + + return new Promise((resolve, _reject) => { + content.addEventListener( + "cut", + event => { + event.clipboardData.setData("text/plain", "Some text"); + event.clipboardData.setData("text/html", "Italic "); + selection.deleteFromDocument(); + event.preventDefault(); + resolve(); + }, + { capture: true, once: true } + ); + }); + }); + + await SpecialPowers.spawn(browser, [], () => {}); + + await sendKey("x"); + await copyPromise; + + pastePromise = SpecialPowers.spawn( + browser, + [htmlPrefix, htmlPostfix, allowPaste], + (htmlPrefixChild, htmlPostfixChild, allowPaste) => { + let selection = content.document.getSelection(); + selection.modify("move", "left", "line"); + + return new Promise((resolve, _reject) => { + content.addEventListener( + "paste", + event => { + let clipboardData = event.clipboardData; + Assert.equal( + clipboardData.mozItemCount, + 1, + "One item on clipboard 2" + ); + Assert.equal( + clipboardData.types.length, + 2, + "Two types on clipboard 2" + ); + Assert.equal( + clipboardData.types[0], + "text/html", + "text/html on clipboard 2" + ); + Assert.equal( + clipboardData.types[1], + "text/plain", + "text/plain on clipboard 2" + ); + Assert.equal( + clipboardData.getData("text/html"), + allowPaste + ? htmlPrefixChild + "Italic " + htmlPostfixChild + : "", + "text/html value 2" + ); + Assert.equal( + clipboardData.getData("text/plain"), + allowPaste ? "Some text" : "", + "text/plain value 2" + ); + resolve(); + }, + { capture: true, once: true } + ); + }); + } + ); + + await SpecialPowers.spawn(browser, [], () => {}); + + await sendKey("v"); + await pastePromise; + // 2 calls because there are two formats on the clipboard + is(mockCA.calls.length, 2, "Correct number of calls to Content Analysis"); + assertContentAnalysisRequest( + mockCA.calls[0], + htmlPrefix + "Italic " + htmlPostfix + ); + assertContentAnalysisRequest(mockCA.calls[1], "Some text"); + mockCA.clearCalls(); + + await SpecialPowers.spawn(browser, [], () => { + var main = content.document.getElementById("main"); + Assert.equal( + main.innerHTML, + "Italic Test Bold After", + "Copy and paste html 2" + ); + }); + + // Next, check that the Copy Image command works. + + // The context menu needs to be opened to properly initialize for the copy + // image command to run. + let contextMenu = document.getElementById("contentAreaContextMenu"); + let contextMenuShown = promisePopupShown(contextMenu); + BrowserTestUtils.synthesizeMouseAtCenter( + "#img", + { type: "contextmenu", button: 2 }, + gBrowser.selectedBrowser + ); + await contextMenuShown; + + document.getElementById("context-copyimage-contents").doCommand(); + + contextMenu.hidePopup(); + await promisePopupHidden(contextMenu); + + // Focus the content again + await SimpleTest.promiseFocus(browser); + + pastePromise = SpecialPowers.spawn( + browser, + [htmlPrefix, htmlPostfix, allowPaste], + (htmlPrefixChild, htmlPostfixChild, allowPaste) => { + var doc = content.document; + var main = doc.getElementById("main"); + main.focus(); + + return new Promise((resolve, reject) => { + content.addEventListener( + "paste", + event => { + let clipboardData = event.clipboardData; + + // DataTransfer doesn't support the image types yet, so only text/html + // will be present. + let clipboardText = clipboardData.getData("text/html"); + if (allowPaste) { + if ( + clipboardText !== + htmlPrefixChild + + '' + + htmlPostfixChild + ) { + reject( + "Clipboard Data did not contain an image, was " + + clipboardText + ); + } + } else if (clipboardText !== "") { + reject("Clipboard Data should be empty, was " + clipboardText); + } + resolve(); + }, + { capture: true, once: true } + ); + }); + } + ); + + await SpecialPowers.spawn(browser, [], () => {}); + await sendKey("v"); + await pastePromise; + is(mockCA.calls.length, 1, "Correct number of calls to Content Analysis"); + assertContentAnalysisRequest( + mockCA.calls[0], + htmlPrefix + + '' + + htmlPostfix + ); + mockCA.clearCalls(); + + // The new content should now include an image. + await SpecialPowers.spawn(browser, [], () => { + var main = content.document.getElementById("main"); + Assert.equal( + main.innerHTML, + 'Italic ' + + "Test Bold After", + "Paste after copy image" + ); + }); + + gBrowser.removeCurrentTab(); +} + +function assertContentAnalysisRequest(request, expectedText) { + is( + request.url.spec, + "data:text/html," + escape(testPage), + "request has correct URL" + ); + is( + request.analysisType, + Ci.nsIContentAnalysisRequest.eBulkDataEntry, + "request has correct analysisType" + ); + is( + request.operationTypeForDisplay, + Ci.nsIContentAnalysisRequest.eClipboard, + "request has correct operationTypeForDisplay" + ); + is(request.filePath, "", "request filePath should be empty"); + is(request.textContent, expectedText, "request textContent should match"); + is(request.printDataHandle, 0, "request printDataHandle should not be 0"); + is(request.printDataSize, 0, "request printDataSize should not be 0"); + ok(!!request.requestToken.length, "request requestToken should not be empty"); +} +add_task(async function testClipboardWithContentAnalysisAllow() { + await testClipboardWithContentAnalysis(true); +}); + +add_task(async function testClipboardWithContentAnalysisBlock() { + await testClipboardWithContentAnalysis(false); +}); -- cgit v1.2.3