зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1858627 - Add nsIClipboard API to return nsIAsyncSetClipboardData synchrously; r=ipc-reviewers,nika
This is a sync version of `nsIClipboard.asyncGetData`, which can be used for synchronous clipboard APIs, e.g. DataTransfer, to support the clipboard seqence number concept, see bug 1879401. Differential Revision: https://phabricator.services.mozilla.com/D201364
This commit is contained in:
Родитель
671c3b21b5
Коммит
239696f93b
|
@ -3647,6 +3647,48 @@ mozilla::ipc::IPCResult ContentParent::RecvGetClipboardAsync(
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentParent::RecvGetClipboardDataSnapshotSync(
|
||||
nsTArray<nsCString>&& aTypes, const int32_t& aWhichClipboard,
|
||||
const MaybeDiscarded<WindowContext>& aRequestingWindowContext,
|
||||
ClipboardReadRequestOrError* aRequestOrError) {
|
||||
// If the requesting context has been discarded, cancel the paste.
|
||||
if (aRequestingWindowContext.IsDiscarded()) {
|
||||
*aRequestOrError = NS_ERROR_FAILURE;
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
RefPtr<WindowGlobalParent> requestingWindow =
|
||||
aRequestingWindowContext.get_canonical();
|
||||
if (requestingWindow && requestingWindow->GetContentParent() != this) {
|
||||
return IPC_FAIL(
|
||||
this, "attempt to paste into WindowContext loaded in another process");
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID));
|
||||
if (!clipboard) {
|
||||
*aRequestOrError = NS_ERROR_FAILURE;
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAsyncGetClipboardData> asyncGetClipboardData;
|
||||
nsresult rv =
|
||||
clipboard->GetDataSnapshotSync(aTypes, aWhichClipboard, requestingWindow,
|
||||
getter_AddRefs(asyncGetClipboardData));
|
||||
if (NS_FAILED(rv)) {
|
||||
*aRequestOrError = rv;
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
auto result = CreateClipboardReadRequest(*this, *asyncGetClipboardData);
|
||||
if (result.isErr()) {
|
||||
*aRequestOrError = result.unwrapErr();
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
*aRequestOrError = result.unwrap();
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
already_AddRefed<PClipboardWriteRequestParent>
|
||||
ContentParent::AllocPClipboardWriteRequestParent(
|
||||
const int32_t& aClipboardType) {
|
||||
|
|
|
@ -974,6 +974,11 @@ class ContentParent final : public PContentParent,
|
|||
mozilla::NotNull<nsIPrincipal*> aRequestingPrincipal,
|
||||
GetClipboardAsyncResolver&& aResolver);
|
||||
|
||||
mozilla::ipc::IPCResult RecvGetClipboardDataSnapshotSync(
|
||||
nsTArray<nsCString>&& aTypes, const int32_t& aWhichClipboard,
|
||||
const MaybeDiscarded<WindowContext>& aRequestingWindowContext,
|
||||
ClipboardReadRequestOrError* aRequestOrError);
|
||||
|
||||
already_AddRefed<PClipboardWriteRequestParent>
|
||||
AllocPClipboardWriteRequestParent(const int32_t& aClipboardType);
|
||||
|
||||
|
|
|
@ -1238,6 +1238,11 @@ parent:
|
|||
nsIPrincipal aRequestingPrincipal)
|
||||
returns (ClipboardReadRequestOrError aClipboardReadRequestOrError);
|
||||
|
||||
// Requests getting data from clipboard.
|
||||
sync GetClipboardDataSnapshotSync(nsCString[] aTypes, int32_t aWhichClipboard,
|
||||
MaybeDiscardedWindowContext aRequestingWindowContext)
|
||||
returns (ClipboardReadRequestOrError aClipboardReadRequestOrError);
|
||||
|
||||
// Clears the clipboard.
|
||||
async EmptyClipboard(int32_t aWhichClipboard);
|
||||
|
||||
|
|
|
@ -95,6 +95,16 @@ description = Only used by gtests
|
|||
[PTestUrgency::Reply2]
|
||||
description = Only used by gtests
|
||||
|
||||
# Clipboard
|
||||
[PContent::GetClipboard]
|
||||
description = Legacy synchronous clipboard API
|
||||
[PContent::ClipboardHasType]
|
||||
description = Legacy synchronous clipboard API
|
||||
[PContent::GetExternalClipboardFormats]
|
||||
description = Retrieve supported clipboard formats synchronously
|
||||
[PContent::GetClipboardDataSnapshotSync]
|
||||
description = Legacy synchronous clipboard API
|
||||
|
||||
# The rest
|
||||
[PHeapSnapshotTempFileHelper::OpenHeapSnapshotTempFile]
|
||||
description = legacy sync IPC - please add detailed description
|
||||
|
@ -132,12 +142,6 @@ description = JS MessageManager implementation
|
|||
description = legacy sync IPC - please add detailed description
|
||||
[PContent::PURLClassifier]
|
||||
description = legacy sync IPC - please add detailed description
|
||||
[PContent::GetClipboard]
|
||||
description = Legacy synchronous clipboard API
|
||||
[PContent::ClipboardHasType]
|
||||
description = Legacy synchronous clipboard API
|
||||
[PContent::GetExternalClipboardFormats]
|
||||
description = Retrieve supported clipboard formats synchronously
|
||||
[PContent::GetIconForExtension]
|
||||
description = legacy sync IPC - please add detailed description
|
||||
[PContent::BeginDriverCrashGuard]
|
||||
|
|
|
@ -812,56 +812,124 @@ NS_IMETHODIMP nsBaseClipboard::AsyncGetData(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIAsyncGetClipboardData>
|
||||
nsBaseClipboard::MaybeCreateGetRequestFromClipboardCache(
|
||||
const nsTArray<nsCString>& aFlavorList, int32_t aClipboardType,
|
||||
mozilla::dom::WindowContext* aRequestingWindowContext) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(nsIClipboard::IsClipboardTypeSupported(aClipboardType));
|
||||
|
||||
if (!mozilla::StaticPrefs::widget_clipboard_use_cached_data_enabled()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If we were the last ones to put something on the native clipboard, then
|
||||
// just use the cached transferable. Otherwise clear it because it isn't
|
||||
// relevant any more.
|
||||
ClipboardCache* clipboardCache = GetClipboardCacheIfValid(aClipboardType);
|
||||
if (!clipboardCache) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsITransferable* cachedTransferable = clipboardCache->GetTransferable();
|
||||
MOZ_ASSERT(cachedTransferable);
|
||||
|
||||
nsTArray<nsCString> transferableFlavors;
|
||||
if (NS_FAILED(cachedTransferable->FlavorsTransferableCanExport(
|
||||
transferableFlavors))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsTArray<nsCString> results;
|
||||
for (const auto& transferableFlavor : transferableFlavors) {
|
||||
for (const auto& flavor : aFlavorList) {
|
||||
// XXX We need special check for image as we always put the
|
||||
// image as "native" on the clipboard.
|
||||
if (transferableFlavor.Equals(flavor) ||
|
||||
(transferableFlavor.Equals(kNativeImageMime) &&
|
||||
nsContentUtils::IsFlavorImage(flavor))) {
|
||||
MOZ_CLIPBOARD_LOG(" has %s", flavor.get());
|
||||
results.AppendElement(flavor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// XXX Do we need to check system clipboard for the flavors that cannot
|
||||
// be found in cache?
|
||||
return mozilla::MakeAndAddRef<AsyncGetClipboardData>(
|
||||
aClipboardType, clipboardCache->GetSequenceNumber(), std::move(results),
|
||||
true /* aFromCache */, this, aRequestingWindowContext);
|
||||
}
|
||||
|
||||
void nsBaseClipboard::AsyncGetDataInternal(
|
||||
const nsTArray<nsCString>& aFlavorList, int32_t aClipboardType,
|
||||
mozilla::dom::WindowContext* aRequestingWindowContext,
|
||||
nsIAsyncClipboardGetCallback* aCallback) {
|
||||
MOZ_ASSERT(nsIClipboard::IsClipboardTypeSupported(aClipboardType));
|
||||
|
||||
if (mozilla::StaticPrefs::widget_clipboard_use_cached_data_enabled()) {
|
||||
// If we were the last ones to put something on the native clipboard, then
|
||||
// just use the cached transferable. Otherwise clear it because it isn't
|
||||
// relevant any more.
|
||||
if (auto* clipboardCache = GetClipboardCacheIfValid(aClipboardType)) {
|
||||
nsITransferable* cachedTransferable = clipboardCache->GetTransferable();
|
||||
MOZ_ASSERT(cachedTransferable);
|
||||
|
||||
nsTArray<nsCString> transferableFlavors;
|
||||
if (NS_SUCCEEDED(cachedTransferable->FlavorsTransferableCanExport(
|
||||
transferableFlavors))) {
|
||||
nsTArray<nsCString> results;
|
||||
for (const auto& transferableFlavor : transferableFlavors) {
|
||||
for (const auto& flavor : aFlavorList) {
|
||||
// XXX We need special check for image as we always put the
|
||||
// image as "native" on the clipboard.
|
||||
if (transferableFlavor.Equals(flavor) ||
|
||||
(transferableFlavor.Equals(kNativeImageMime) &&
|
||||
nsContentUtils::IsFlavorImage(flavor))) {
|
||||
MOZ_CLIPBOARD_LOG(" has %s", flavor.get());
|
||||
results.AppendElement(flavor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// XXX Do we need to check system clipboard for the flavors that cannot
|
||||
// be found in cache?
|
||||
auto asyncGetClipboardData = mozilla::MakeRefPtr<AsyncGetClipboardData>(
|
||||
aClipboardType, clipboardCache->GetSequenceNumber(),
|
||||
std::move(results), true, this, aRequestingWindowContext);
|
||||
aCallback->OnSuccess(asyncGetClipboardData);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// At this point we can't satisfy the request from cache data so let's look
|
||||
// for things other people put on the system clipboard.
|
||||
if (nsCOMPtr<nsIAsyncGetClipboardData> asyncGetClipboardData =
|
||||
MaybeCreateGetRequestFromClipboardCache(aFlavorList, aClipboardType,
|
||||
aRequestingWindowContext)) {
|
||||
aCallback->OnSuccess(asyncGetClipboardData);
|
||||
return;
|
||||
}
|
||||
|
||||
// At this point we can't satisfy the request from cache data so let's
|
||||
// look for things other people put on the system clipboard.
|
||||
MaybeRetryGetAvailableFlavors(aFlavorList, aClipboardType, aCallback,
|
||||
kGetAvailableFlavorsRetryCount,
|
||||
aRequestingWindowContext);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsBaseClipboard::GetDataSnapshotSync(
|
||||
const nsTArray<nsCString>& aFlavorList, int32_t aWhichClipboard,
|
||||
mozilla::dom::WindowContext* aRequestingWindowContext,
|
||||
nsIAsyncGetClipboardData** _retval) {
|
||||
MOZ_CLIPBOARD_LOG("%s: clipboard=%d", __FUNCTION__, aWhichClipboard);
|
||||
|
||||
*_retval = nullptr;
|
||||
|
||||
if (aFlavorList.IsEmpty()) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (!nsIClipboard::IsClipboardTypeSupported(aWhichClipboard)) {
|
||||
MOZ_CLIPBOARD_LOG("%s: clipboard %d is not supported.", __FUNCTION__,
|
||||
aWhichClipboard);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (nsCOMPtr<nsIAsyncGetClipboardData> asyncGetClipboardData =
|
||||
MaybeCreateGetRequestFromClipboardCache(aFlavorList, aWhichClipboard,
|
||||
aRequestingWindowContext)) {
|
||||
asyncGetClipboardData.forget(_retval);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
auto sequenceNumberOrError =
|
||||
GetNativeClipboardSequenceNumber(aWhichClipboard);
|
||||
if (sequenceNumberOrError.isErr()) {
|
||||
MOZ_CLIPBOARD_LOG("%s: unable to get sequence number for clipboard %d.",
|
||||
__FUNCTION__, aWhichClipboard);
|
||||
return sequenceNumberOrError.unwrapErr();
|
||||
}
|
||||
|
||||
nsTArray<nsCString> results;
|
||||
for (const auto& flavor : aFlavorList) {
|
||||
auto resultOrError = HasNativeClipboardDataMatchingFlavors(
|
||||
AutoTArray<nsCString, 1>{flavor}, aWhichClipboard);
|
||||
if (resultOrError.isOk() && resultOrError.unwrap()) {
|
||||
results.AppendElement(flavor);
|
||||
}
|
||||
}
|
||||
|
||||
*_retval =
|
||||
mozilla::MakeAndAddRef<AsyncGetClipboardData>(
|
||||
aWhichClipboard, sequenceNumberOrError.unwrap(), std::move(results),
|
||||
false /* aFromCache */, this, aRequestingWindowContext)
|
||||
.take();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsBaseClipboard::EmptyClipboard(int32_t aWhichClipboard) {
|
||||
MOZ_CLIPBOARD_LOG("%s: clipboard=%d", __FUNCTION__, aWhichClipboard);
|
||||
|
||||
|
|
|
@ -55,6 +55,10 @@ class nsBaseClipboard : public nsIClipboard {
|
|||
mozilla::dom::WindowContext* aRequestingWindowContext,
|
||||
nsIPrincipal* aRequestingPrincipal,
|
||||
nsIAsyncClipboardGetCallback* aCallback) override final;
|
||||
NS_IMETHOD GetDataSnapshotSync(
|
||||
const nsTArray<nsCString>& aFlavorList, int32_t aWhichClipboard,
|
||||
mozilla::dom::WindowContext* aRequestingWindowContext,
|
||||
nsIAsyncGetClipboardData** _retval) override final;
|
||||
NS_IMETHOD EmptyClipboard(int32_t aWhichClipboard) override final;
|
||||
NS_IMETHOD HasDataMatchingFlavors(const nsTArray<nsCString>& aFlavorList,
|
||||
int32_t aWhichClipboard,
|
||||
|
@ -206,6 +210,11 @@ class nsBaseClipboard : public nsIClipboard {
|
|||
nsIPrincipal* aRequestingPrincipal,
|
||||
nsIAsyncClipboardGetCallback* aCallback);
|
||||
|
||||
already_AddRefed<nsIAsyncGetClipboardData>
|
||||
MaybeCreateGetRequestFromClipboardCache(
|
||||
const nsTArray<nsCString>& aFlavorList, int32_t aClipboardType,
|
||||
mozilla::dom::WindowContext* aRequestingWindowContext);
|
||||
|
||||
// Track the pending request for each clipboard type separately. And only need
|
||||
// to track the latest request for each clipboard type as the prior pending
|
||||
// request will be canceled when a new request is made.
|
||||
|
|
|
@ -239,6 +239,35 @@ NS_IMETHODIMP nsClipboardProxy::AsyncGetData(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsClipboardProxy::GetDataSnapshotSync(
|
||||
const nsTArray<nsCString>& aFlavorList, int32_t aWhichClipboard,
|
||||
mozilla::dom::WindowContext* aRequestingWindowContext,
|
||||
nsIAsyncGetClipboardData** _retval) {
|
||||
*_retval = nullptr;
|
||||
|
||||
if (aFlavorList.IsEmpty()) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (!nsIClipboard::IsClipboardTypeSupported(aWhichClipboard)) {
|
||||
MOZ_CLIPBOARD_LOG("%s: clipboard %d is not supported.", __FUNCTION__,
|
||||
aWhichClipboard);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
ContentChild* contentChild = ContentChild::GetSingleton();
|
||||
ClipboardReadRequestOrError requestOrError;
|
||||
contentChild->SendGetClipboardDataSnapshotSync(
|
||||
aFlavorList, aWhichClipboard, aRequestingWindowContext, &requestOrError);
|
||||
auto result = CreateAsyncGetClipboardDataProxy(std::move(requestOrError));
|
||||
if (result.isErr()) {
|
||||
return result.unwrapErr();
|
||||
}
|
||||
|
||||
result.unwrap().forget(_retval);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsClipboardProxy::EmptyClipboard(int32_t aWhichClipboard) {
|
||||
ContentChild::GetSingleton()->SendEmptyClipboard(aWhichClipboard);
|
||||
|
|
|
@ -178,6 +178,31 @@ interface nsIClipboard : nsISupports
|
|||
in nsIPrincipal aRequestingPrincipal,
|
||||
in nsIAsyncClipboardGetCallback aCallback);
|
||||
|
||||
/**
|
||||
* Requests getting data from the native clipboard. This does not actually
|
||||
* retreive the data, but returns a nsIAsyncGetClipboardData contains
|
||||
* current avaiable data formats. If the native clipboard is updated, either
|
||||
* by us or other application, the existing nsIAsyncGetClipboardData becomes
|
||||
* invalid.
|
||||
*
|
||||
* @param aFlavorList
|
||||
* Specific data formats ('flavors') that can be retrieved from the
|
||||
* clipboard.
|
||||
* @param aWhichClipboard
|
||||
* Specifies the clipboard to which this operation applies.
|
||||
* @param aRequestingWindowContext [optional]
|
||||
* The window context window that is requesting the clipboard, which is
|
||||
* used for content analysis. Passing null means that the content is
|
||||
* exempt from content analysis. (for example, scripted clipboard read by
|
||||
* system code) This parameter should not be null when calling this from a
|
||||
* content process.
|
||||
* @return nsIAsyncSetClipboardData if successful.
|
||||
* @throws if the request can not be made.
|
||||
*/
|
||||
nsIAsyncGetClipboardData getDataSnapshotSync(in Array<ACString> aFlavorList,
|
||||
in long aWhichClipboard,
|
||||
[optional] in WindowContext aRequestingWindowContext);
|
||||
|
||||
/**
|
||||
* This empties the clipboard and notifies the clipboard owner.
|
||||
* This empties the "logical" clipboard. It does not clear the native clipboard.
|
||||
|
|
|
@ -9,9 +9,6 @@ support-files = [
|
|||
|
||||
# Privacy relevant
|
||||
|
||||
["test_bug1123480.xhtml"]
|
||||
skip-if = ["win11_2009 && bits == 32"]
|
||||
|
||||
["test_bug343416.xhtml"]
|
||||
skip-if = ["debug"]
|
||||
|
||||
|
@ -66,8 +63,8 @@ run-if = ["os == 'mac'"] # Cocoa widget test
|
|||
|
||||
["test_bug760802.xhtml"]
|
||||
|
||||
["test_clipboard_chrome.html"]
|
||||
support-files = "file_test_clipboard.js"
|
||||
["test_bug1123480.xhtml"]
|
||||
skip-if = ["win11_2009 && bits == 32"]
|
||||
|
||||
["test_clipboard_asyncGetData_chrome.html"]
|
||||
support-files = "file_test_clipboard_asyncGetData.js"
|
||||
|
@ -77,6 +74,12 @@ support-files = "file_test_clipboard_asyncSetData.js"
|
|||
|
||||
["test_clipboard_cache_chrome.html"]
|
||||
|
||||
["test_clipboard_chrome.html"]
|
||||
support-files = "file_test_clipboard.js"
|
||||
|
||||
["test_clipboard_getDataSnapshotSync_chrome.html"]
|
||||
support-files = "file_test_clipboard_getDataSnapshotSync.js"
|
||||
|
||||
["test_clipboard_owner_chrome.html"]
|
||||
|
||||
["test_composition_text_querycontent.xhtml"]
|
||||
|
|
|
@ -157,6 +157,13 @@ function getClipboardData(aFlavor, aClipboardType) {
|
|||
}
|
||||
}
|
||||
|
||||
function getClipboardDataSnapshotSync(aClipboardType) {
|
||||
return clipboard.getDataSnapshotSync(
|
||||
["text/plain", "text/html", "image/png"],
|
||||
aClipboardType
|
||||
);
|
||||
}
|
||||
|
||||
function asyncGetClipboardData(aClipboardType) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/* import-globals-from clipboard_helper.js */
|
||||
|
||||
"use strict";
|
||||
|
||||
clipboardTypes.forEach(function (type) {
|
||||
if (!clipboard.isClipboardTypeSupported(type)) {
|
||||
add_task(async function test_clipboard_requestGetData_not_support() {
|
||||
info(`Test getDataSnapshotSync request throwing on ${type}`);
|
||||
SimpleTest.doesThrow(
|
||||
() => clipboard.getDataSnapshotSync(["text/plain"], type),
|
||||
"Passing unsupported clipboard type should throw"
|
||||
);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
add_task(async function test_clipboard_getDataSnapshotSync_throw() {
|
||||
info(`Test getDataSnapshotSync request throwing on ${type}`);
|
||||
SimpleTest.doesThrow(
|
||||
() => clipboard.getDataSnapshotSync([], type),
|
||||
"Passing empty flavor list should throw"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(
|
||||
async function test_clipboard_getDataSnapshotSync_no_matched_flavor() {
|
||||
info(`Test getDataSnapshotSync have no matched flavor on ${type}`);
|
||||
cleanupAllClipboard();
|
||||
is(
|
||||
getClipboardData("text/plain", type),
|
||||
null,
|
||||
"ensure clipboard is empty"
|
||||
);
|
||||
|
||||
writeRandomStringToClipboard("text/plain", type);
|
||||
let request = clipboard.getDataSnapshotSync(["text/html"], type);
|
||||
isDeeply(request.flavorList, [], "Check flavorList");
|
||||
}
|
||||
);
|
||||
|
||||
add_task(async function test_empty_data() {
|
||||
info(`Test getDataSnapshotSync request with empty data on ${type}`);
|
||||
cleanupAllClipboard();
|
||||
is(getClipboardData("text/plain", type), null, "ensure clipboard is empty");
|
||||
|
||||
let request = getClipboardDataSnapshotSync(type);
|
||||
isDeeply(request.flavorList, [], "Check flavorList");
|
||||
await asyncClipboardRequestGetData(request, "text/plain", true).catch(
|
||||
() => {}
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_clipboard_getDataSnapshotSync_after_write() {
|
||||
info(`Test getDataSnapshotSync request after write on ${type}`);
|
||||
|
||||
let str = writeRandomStringToClipboard("text/plain", type);
|
||||
let request = getClipboardDataSnapshotSync(type);
|
||||
isDeeply(request.flavorList, ["text/plain"], "Check flavorList");
|
||||
is(
|
||||
await asyncClipboardRequestGetData(request, "text/plain"),
|
||||
str,
|
||||
"Check data"
|
||||
);
|
||||
ok(request.valid, "request should still be valid");
|
||||
// Requesting a flavor that is not in the list should throw error.
|
||||
await asyncClipboardRequestGetData(request, "text/html", true).catch(
|
||||
() => {}
|
||||
);
|
||||
ok(request.valid, "request should still be valid");
|
||||
|
||||
// Writing a new data should invalid existing get request.
|
||||
str = writeRandomStringToClipboard("text/plain", type);
|
||||
await asyncClipboardRequestGetData(request, "text/plain").then(
|
||||
() => {
|
||||
ok(false, "asyncClipboardRequestGetData should not success");
|
||||
},
|
||||
() => {
|
||||
ok(true, "asyncClipboardRequestGetData should reject");
|
||||
}
|
||||
);
|
||||
ok(!request.valid, "request should no longer be valid");
|
||||
|
||||
info(`check clipboard data again`);
|
||||
request = getClipboardDataSnapshotSync(type);
|
||||
isDeeply(request.flavorList, ["text/plain"], "Check flavorList");
|
||||
is(
|
||||
await asyncClipboardRequestGetData(request, "text/plain"),
|
||||
str,
|
||||
"Check data"
|
||||
);
|
||||
|
||||
cleanupAllClipboard();
|
||||
});
|
||||
|
||||
add_task(async function test_clipboard_getDataSnapshotSync_after_empty() {
|
||||
info(`Test getDataSnapshotSync request after empty on ${type}`);
|
||||
|
||||
let str = writeRandomStringToClipboard("text/plain", type);
|
||||
let request = getClipboardDataSnapshotSync(type);
|
||||
isDeeply(request.flavorList, ["text/plain"], "Check flavorList");
|
||||
is(
|
||||
await asyncClipboardRequestGetData(request, "text/plain"),
|
||||
str,
|
||||
"Check data"
|
||||
);
|
||||
ok(request.valid, "request should still be valid");
|
||||
|
||||
// Empty clipboard data
|
||||
emptyClipboardData(type);
|
||||
is(getClipboardData("text/plain", type), null, "ensure clipboard is empty");
|
||||
|
||||
await asyncClipboardRequestGetData(request, "text/plain").then(
|
||||
() => {
|
||||
ok(false, "asyncClipboardRequestGetData should not success");
|
||||
},
|
||||
() => {
|
||||
ok(true, "asyncClipboardRequestGetData should reject");
|
||||
}
|
||||
);
|
||||
ok(!request.valid, "request should no longer be valid");
|
||||
|
||||
info(`check clipboard data again`);
|
||||
request = getClipboardDataSnapshotSync(type);
|
||||
isDeeply(request.flavorList, [], "Check flavorList");
|
||||
|
||||
cleanupAllClipboard();
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_clipboard_getDataSnapshotSync_html_data() {
|
||||
info(`Test getDataSnapshotSync request with html data`);
|
||||
|
||||
const html_str = `<img src="https://example.com/oops">`;
|
||||
writeStringToClipboard(html_str, "text/html", clipboard.kGlobalClipboard);
|
||||
|
||||
let request = getClipboardDataSnapshotSync(clipboard.kGlobalClipboard);
|
||||
isDeeply(request.flavorList, ["text/html"], "Check flavorList");
|
||||
is(
|
||||
await asyncClipboardRequestGetData(request, "text/html"),
|
||||
// On Windows, widget adds extra data into HTML clipboard.
|
||||
navigator.platform.includes("Win")
|
||||
? `<html><body>\n<!--StartFragment-->${html_str}<!--EndFragment-->\n</body>\n</html>`
|
||||
: html_str,
|
||||
"Check data"
|
||||
);
|
||||
// Requesting a flavor that is not in the list should throw error.
|
||||
await asyncClipboardRequestGetData(request, "text/plain", true).catch(
|
||||
() => {}
|
||||
);
|
||||
});
|
|
@ -25,12 +25,16 @@ skip-if = [
|
|||
support-files = ["file_test_clipboard.js"]
|
||||
|
||||
["test_clipboard_asyncGetData.html"]
|
||||
skip-if = ["display == 'wayland'"] # Bug 1864211
|
||||
skip-if = ["display == 'wayland'"] # Bug 1879835
|
||||
support-files = ["file_test_clipboard_asyncGetData.js"]
|
||||
|
||||
["test_clipboard_asyncSetData.html"]
|
||||
support-files = ["file_test_clipboard_asyncSetData.js"]
|
||||
|
||||
["test_clipboard_getDataSnapshotSync.html"]
|
||||
skip-if = ["display == 'wayland'"] # Bug 1879835
|
||||
support-files = "file_test_clipboard_getDataSnapshotSync.js"
|
||||
|
||||
["test_contextmenu_by_mouse_on_unix.html"]
|
||||
run-if = ["os == 'linux'"]
|
||||
skip-if = ["headless"] # headless widget doesn't dispatch contextmenu event by mouse event.
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1858627
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 1858627</title>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="clipboard_helper.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test"></pre>
|
||||
<!-- Tests are in file_test_clipboard_getDataSnapshotSync.js -->
|
||||
<script src="file_test_clipboard_getDataSnapshotSync.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1858627
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 1858627</title>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="clipboard_helper.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test"></pre>
|
||||
<!-- Tests are in file_test_clipboard_getDataSnapshotSync.js -->
|
||||
<script src="file_test_clipboard_getDataSnapshotSync.js"></script>
|
||||
</body>
|
||||
</html>
|
Загрузка…
Ссылка в новой задаче