зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1071562, e10s, support non-text types in clipboard (html, images, etc), r=smaug
This commit is contained in:
Родитель
39529281de
Коммит
94848ffbe4
|
@ -295,6 +295,7 @@ skip-if = os == 'win' || e10s # Bug 1056146 - zoom tests use FullZoomHelper and
|
|||
[browser_bug1070778.js]
|
||||
[browser_canonizeURL.js]
|
||||
skip-if = e10s # Bug 1094510 - test hits the network in e10s mode only
|
||||
[browser_clipboard.js]
|
||||
[browser_contentAreaClick.js]
|
||||
skip-if = e10s
|
||||
[browser_contextSearchTabPosition.js]
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
// 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.
|
||||
|
||||
let testPage = "<div id='main' contenteditable='true'>Test <b>Bold</b> After Text</div>";
|
||||
|
||||
add_task(function*() {
|
||||
let tab = gBrowser.addTab();
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
|
||||
gBrowser.selectedTab = tab;
|
||||
|
||||
yield promiseTabLoadEvent(tab, "data:text/html," + escape(testPage));
|
||||
yield SimpleTest.promiseFocus(browser.contentWindowAsCPOW);
|
||||
|
||||
let results = yield ContentTask.spawn(browser, {}, function* () {
|
||||
var doc = content.document;
|
||||
var main = doc.getElementById("main");
|
||||
main.focus();
|
||||
|
||||
const utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
||||
.getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||
|
||||
const modifier = (content.navigator.platform.indexOf("Mac") >= 0) ?
|
||||
Components.interfaces.nsIDOMWindowUtils.MODIFIER_META :
|
||||
Components.interfaces.nsIDOMWindowUtils.MODIFIER_CONTROL;
|
||||
|
||||
function sendKey(key)
|
||||
{
|
||||
if (utils.sendKeyEvent("keydown", key, 0, modifier)) {
|
||||
utils.sendKeyEvent("keypress", key, key.charCodeAt(0), modifier);
|
||||
}
|
||||
utils.sendKeyEvent("keyup", key, 0, modifier);
|
||||
}
|
||||
|
||||
let results = [];
|
||||
function is(l, r, v) {
|
||||
results.push(((l === r) ? "PASSED" : "FAILED") + " got: " + l + " expected: " + r + " - " + v);
|
||||
}
|
||||
|
||||
// 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");
|
||||
|
||||
yield new content.Promise((resolve, reject) => {
|
||||
addEventListener("copy", function copyEvent(event) {
|
||||
removeEventListener("copy", copyEvent, true);
|
||||
// The data is empty as the selection is copied during the event default phase.
|
||||
is(event.clipboardData.mozItemCount, 0, "Zero items on clipboard");
|
||||
resolve();
|
||||
}, true)
|
||||
|
||||
sendKey("c");
|
||||
});
|
||||
|
||||
selection.modify("move", "right", "line");
|
||||
|
||||
yield new content.Promise((resolve, reject) => {
|
||||
addEventListener("paste", function copyEvent(event) {
|
||||
removeEventListener("paste", copyEvent, true);
|
||||
let clipboardData = event.clipboardData;
|
||||
is(clipboardData.mozItemCount, 1, "One item on clipboard");
|
||||
is(clipboardData.types.length, 2, "Two types on clipboard");
|
||||
is(clipboardData.types[0], "text/html", "text/html on clipboard");
|
||||
is(clipboardData.types[1], "text/plain", "text/plain on clipboard");
|
||||
is(clipboardData.getData("text/html"), "t <b>Bold</b>", "text/html value");
|
||||
is(clipboardData.getData("text/plain"), "t Bold", "text/plain value");
|
||||
resolve();
|
||||
}, true)
|
||||
sendKey("v");
|
||||
});
|
||||
|
||||
is(main.innerHTML, "Test <b>Bold</b> After Textt <b>Bold</b>", "Copy and paste html");
|
||||
|
||||
selection.modify("extend", "left", "word");
|
||||
selection.modify("extend", "left", "word");
|
||||
selection.modify("extend", "left", "character");
|
||||
|
||||
yield new content.Promise((resolve, reject) => {
|
||||
addEventListener("cut", function copyEvent(event) {
|
||||
removeEventListener("cut", copyEvent, true);
|
||||
event.clipboardData.setData("text/plain", "Some text");
|
||||
event.clipboardData.setData("text/html", "<i>Italic</i> ");
|
||||
selection.deleteFromDocument();
|
||||
event.preventDefault();
|
||||
resolve();
|
||||
}, true)
|
||||
sendKey("x");
|
||||
});
|
||||
|
||||
selection.modify("move", "left", "line");
|
||||
|
||||
yield new content.Promise((resolve, reject) => {
|
||||
addEventListener("paste", function copyEvent(event) {
|
||||
removeEventListener("paste", copyEvent, true);
|
||||
let clipboardData = event.clipboardData;
|
||||
is(clipboardData.mozItemCount, 1, "One item on clipboard 2");
|
||||
is(clipboardData.types.length, 2, "Two types on clipboard 2");
|
||||
is(clipboardData.types[0], "text/html", "text/html on clipboard 2");
|
||||
is(clipboardData.types[1], "text/plain", "text/plain on clipboard 2");
|
||||
is(clipboardData.getData("text/html"), "<i>Italic</i> ", "text/html value 2");
|
||||
is(clipboardData.getData("text/plain"), "Some text", "text/plain value 2");
|
||||
resolve();
|
||||
}, true)
|
||||
sendKey("v");
|
||||
});
|
||||
|
||||
is(main.innerHTML, "<i>Italic</i> Test <b>Bold</b> After<b></b>", "Copy and paste html 2");
|
||||
return results;
|
||||
});
|
||||
|
||||
is(results.length, 15, "Correct number of results");
|
||||
for (var t = 0; t < results.length; t++) {
|
||||
ok(results[t].startsWith("PASSED"), results[t]);
|
||||
}
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
|
@ -415,6 +415,7 @@ LOCAL_INCLUDES += [
|
|||
'/dom/xml',
|
||||
'/dom/xslt/xpath',
|
||||
'/dom/xul',
|
||||
'/gfx/2d',
|
||||
'/image/src',
|
||||
'/js/xpconnect/src',
|
||||
'/js/xpconnect/wrappers',
|
||||
|
|
|
@ -171,6 +171,7 @@
|
|||
#include "nsReferencedElement.h"
|
||||
#include "nsSandboxFlags.h"
|
||||
#include "nsScriptSecurityManager.h"
|
||||
#include "nsStreamUtils.h"
|
||||
#include "nsSVGFeatures.h"
|
||||
#include "nsTextEditorState.h"
|
||||
#include "nsTextFragment.h"
|
||||
|
@ -7214,7 +7215,6 @@ nsContentUtils::TransferablesToIPCTransferables(nsISupportsArray* aTransferables
|
|||
mozilla::dom::nsIContentParent* aParent)
|
||||
{
|
||||
aIPC.Clear();
|
||||
MOZ_ASSERT((aChild && !aParent) || (!aChild && aParent));
|
||||
if (aTransferables) {
|
||||
uint32_t transferableCount = 0;
|
||||
aTransferables->Count(&transferableCount);
|
||||
|
@ -7222,75 +7222,136 @@ nsContentUtils::TransferablesToIPCTransferables(nsISupportsArray* aTransferables
|
|||
IPCDataTransfer* dt = aIPC.AppendElement();
|
||||
nsCOMPtr<nsISupports> genericItem;
|
||||
aTransferables->GetElementAt(i, getter_AddRefs(genericItem));
|
||||
nsCOMPtr<nsITransferable> item(do_QueryInterface(genericItem));
|
||||
if (item) {
|
||||
nsCOMPtr<nsISupportsArray> flavorList;
|
||||
item->FlavorsTransferableCanExport(getter_AddRefs(flavorList));
|
||||
if (flavorList) {
|
||||
uint32_t flavorCount = 0;
|
||||
flavorList->Count(&flavorCount);
|
||||
for (uint32_t j = 0; j < flavorCount; ++j) {
|
||||
nsCOMPtr<nsISupportsCString> flavor = do_QueryElementAt(flavorList, j);
|
||||
if (!flavor) {
|
||||
continue;
|
||||
nsCOMPtr<nsITransferable> transferable(do_QueryInterface(genericItem));
|
||||
TransferableToIPCTransferable(transferable, dt, aChild, aParent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsContentUtils::TransferableToIPCTransferable(nsITransferable* aTransferable,
|
||||
IPCDataTransfer* aIPCDataTransfer,
|
||||
mozilla::dom::nsIContentChild* aChild,
|
||||
mozilla::dom::nsIContentParent* aParent)
|
||||
{
|
||||
MOZ_ASSERT((aChild && !aParent) || (!aChild && aParent));
|
||||
|
||||
if (aTransferable) {
|
||||
nsCOMPtr<nsISupportsArray> flavorList;
|
||||
aTransferable->FlavorsTransferableCanExport(getter_AddRefs(flavorList));
|
||||
if (flavorList) {
|
||||
uint32_t flavorCount = 0;
|
||||
flavorList->Count(&flavorCount);
|
||||
for (uint32_t j = 0; j < flavorCount; ++j) {
|
||||
nsCOMPtr<nsISupportsCString> flavor = do_QueryElementAt(flavorList, j);
|
||||
if (!flavor) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsAutoCString flavorStr;
|
||||
flavor->GetData(flavorStr);
|
||||
if (!flavorStr.Length()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> data;
|
||||
uint32_t dataLen = 0;
|
||||
aTransferable->GetTransferData(flavorStr.get(), getter_AddRefs(data), &dataLen);
|
||||
|
||||
nsCOMPtr<nsISupportsString> text = do_QueryInterface(data);
|
||||
nsCOMPtr<nsISupportsCString> ctext = do_QueryInterface(data);
|
||||
if (text) {
|
||||
nsAutoString dataAsString;
|
||||
text->GetData(dataAsString);
|
||||
IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
|
||||
item->flavor() = nsCString(flavorStr);
|
||||
item->data() = nsString(dataAsString);
|
||||
} else if (ctext) {
|
||||
nsAutoCString dataAsString;
|
||||
ctext->GetData(dataAsString);
|
||||
IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
|
||||
item->flavor() = nsCString(flavorStr);
|
||||
item->data() = nsCString(dataAsString);
|
||||
} else {
|
||||
nsCOMPtr<nsISupportsInterfacePointer> sip =
|
||||
do_QueryInterface(data);
|
||||
if (sip) {
|
||||
sip->GetData(getter_AddRefs(data));
|
||||
}
|
||||
|
||||
// Images to be pasted on the clipboard are nsIInputStreams
|
||||
nsCOMPtr<nsIInputStream> stream(do_QueryInterface(data));
|
||||
if (stream) {
|
||||
IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
|
||||
item->flavor() = nsCString(flavorStr);
|
||||
|
||||
nsCString imageData;
|
||||
NS_ConsumeStream(stream, UINT32_MAX, imageData);
|
||||
item->data() = imageData;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Images to be placed on the clipboard are imgIContainers.
|
||||
nsCOMPtr<imgIContainer> image(do_QueryInterface(data));
|
||||
if (image) {
|
||||
RefPtr<mozilla::gfx::SourceSurface> surface =
|
||||
image->GetFrame(imgIContainer::FRAME_CURRENT,
|
||||
imgIContainer::FLAG_SYNC_DECODE);
|
||||
|
||||
mozilla::RefPtr<mozilla::gfx::DataSourceSurface> dataSurface =
|
||||
surface->GetDataSurface();
|
||||
size_t length;
|
||||
int32_t stride;
|
||||
const uint8_t* data = nsContentUtils::GetSurfaceData(dataSurface, &length, &stride);
|
||||
nsDependentCSubstring imageData(reinterpret_cast<const char*>(data), length);
|
||||
|
||||
IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
|
||||
item->flavor() = nsCString(flavorStr);
|
||||
item->data() = nsCString(imageData);
|
||||
|
||||
IPCDataTransferImage& imageDetails = item->imageDetails();
|
||||
mozilla::gfx::IntSize size = dataSurface->GetSize();
|
||||
imageDetails.width() = size.width;
|
||||
imageDetails.height() = size.height;
|
||||
imageDetails.stride() = stride;
|
||||
imageDetails.format() = static_cast<uint8_t>(dataSurface->GetFormat());
|
||||
|
||||
dataSurface->Unmap();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise, handle this as a file.
|
||||
nsCOMPtr<FileImpl> fileImpl;
|
||||
nsCOMPtr<nsIFile> file = do_QueryInterface(data);
|
||||
if (file) {
|
||||
fileImpl = new FileImplFile(file, false);
|
||||
ErrorResult rv;
|
||||
fileImpl->GetSize(rv);
|
||||
fileImpl->GetLastModified(rv);
|
||||
} else {
|
||||
fileImpl = do_QueryInterface(data);
|
||||
}
|
||||
if (fileImpl) {
|
||||
IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
|
||||
item->flavor() = nsCString(flavorStr);
|
||||
if (aChild) {
|
||||
item->data() =
|
||||
mozilla::dom::BlobChild::GetOrCreate(aChild,
|
||||
static_cast<FileImpl*>(fileImpl.get()));
|
||||
} else if (aParent) {
|
||||
item->data() =
|
||||
mozilla::dom::BlobParent::GetOrCreate(aParent,
|
||||
static_cast<FileImpl*>(fileImpl.get()));
|
||||
}
|
||||
|
||||
nsAutoCString flavorStr;
|
||||
flavor->GetData(flavorStr);
|
||||
if (!flavorStr.Length()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> data;
|
||||
uint32_t dataLen = 0;
|
||||
item->GetTransferData(flavorStr.get(), getter_AddRefs(data), &dataLen);
|
||||
|
||||
nsCOMPtr<nsISupportsString> text = do_QueryInterface(data);
|
||||
if (text) {
|
||||
nsAutoString dataAsString;
|
||||
text->GetData(dataAsString);
|
||||
IPCDataTransferItem* item = dt->items().AppendElement();
|
||||
} else {
|
||||
// This is a hack to support kFilePromiseMime.
|
||||
// On Windows there just needs to be an entry for it,
|
||||
// and for OSX we need to create
|
||||
// nsContentAreaDragDropDataProvider as nsIFlavorDataProvider.
|
||||
if (flavorStr.EqualsLiteral(kFilePromiseMime)) {
|
||||
IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
|
||||
item->flavor() = nsCString(flavorStr);
|
||||
item->data() = nsString(dataAsString);
|
||||
} else {
|
||||
nsCOMPtr<nsISupportsInterfacePointer> sip =
|
||||
do_QueryInterface(data);
|
||||
if (sip) {
|
||||
sip->GetData(getter_AddRefs(data));
|
||||
}
|
||||
nsCOMPtr<FileImpl> fileImpl;
|
||||
nsCOMPtr<nsIFile> file = do_QueryInterface(data);
|
||||
if (file) {
|
||||
fileImpl = new FileImplFile(file, false);
|
||||
ErrorResult rv;
|
||||
fileImpl->GetSize(rv);
|
||||
fileImpl->GetLastModified(rv);
|
||||
} else {
|
||||
fileImpl = do_QueryInterface(data);
|
||||
}
|
||||
if (fileImpl) {
|
||||
IPCDataTransferItem* item = dt->items().AppendElement();
|
||||
item->flavor() = nsCString(flavorStr);
|
||||
if (aChild) {
|
||||
item->data() =
|
||||
mozilla::dom::BlobChild::GetOrCreate(aChild,
|
||||
static_cast<FileImpl*>(fileImpl.get()));
|
||||
} else if (aParent) {
|
||||
item->data() =
|
||||
mozilla::dom::BlobParent::GetOrCreate(aParent,
|
||||
static_cast<FileImpl*>(fileImpl.get()));
|
||||
}
|
||||
} else {
|
||||
// This is a hack to support kFilePromiseMime.
|
||||
// On Windows there just needs to be an entry for it,
|
||||
// and for OSX we need to create
|
||||
// nsContentAreaDragDropDataProvider as nsIFlavorDataProvider.
|
||||
if (flavorStr.EqualsLiteral(kFilePromiseMime)) {
|
||||
IPCDataTransferItem* item = dt->items().AppendElement();
|
||||
item->flavor() = nsCString(flavorStr);
|
||||
item->data() = NS_ConvertUTF8toUTF16(flavorStr);
|
||||
}
|
||||
}
|
||||
item->data() = NS_ConvertUTF8toUTF16(flavorStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7298,3 +7359,24 @@ nsContentUtils::TransferablesToIPCTransferables(nsISupportsArray* aTransferables
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
const uint8_t*
|
||||
nsContentUtils::GetSurfaceData(mozilla::gfx::DataSourceSurface* aSurface,
|
||||
size_t* aLength, int32_t* aStride)
|
||||
{
|
||||
mozilla::gfx::DataSourceSurface::MappedSurface map;
|
||||
aSurface->Map(mozilla::gfx::DataSourceSurface::MapType::READ, &map);
|
||||
mozilla::gfx::IntSize size = aSurface->GetSize();
|
||||
mozilla::CheckedInt32 requiredBytes =
|
||||
mozilla::CheckedInt32(map.mStride) * mozilla::CheckedInt32(size.height);
|
||||
size_t bufLen = requiredBytes.isValid() ? requiredBytes.value() : 0;
|
||||
mozilla::gfx::SurfaceFormat format = aSurface->GetFormat();
|
||||
|
||||
// Surface data handling is totally nuts. This is the magic one needs to
|
||||
// know to access the data.
|
||||
bufLen = bufLen - map.mStride + (size.width * BytesPerPixel(format));
|
||||
|
||||
*aLength = bufLen;
|
||||
*aStride = map.mStride;
|
||||
return map.mData;
|
||||
}
|
||||
|
|
|
@ -103,6 +103,7 @@ class nsTextFragment;
|
|||
class nsViewportInfo;
|
||||
class nsWrapperCache;
|
||||
class nsAttrValue;
|
||||
class nsITransferable;
|
||||
|
||||
struct JSPropertyDescriptor;
|
||||
struct JSRuntime;
|
||||
|
@ -129,6 +130,10 @@ class Selection;
|
|||
class TabParent;
|
||||
} // namespace dom
|
||||
|
||||
namespace gfx {
|
||||
class DataSourceSurface;
|
||||
} // namespace gfx
|
||||
|
||||
namespace layers {
|
||||
class LayerManager;
|
||||
} // namespace layers
|
||||
|
@ -2295,6 +2300,21 @@ public:
|
|||
nsTArray<mozilla::dom::IPCDataTransfer>& aIPC,
|
||||
mozilla::dom::nsIContentChild* aChild,
|
||||
mozilla::dom::nsIContentParent* aParent);
|
||||
|
||||
static void TransferableToIPCTransferable(nsITransferable* aTransferable,
|
||||
mozilla::dom::IPCDataTransfer* aIPCDataTransfer,
|
||||
mozilla::dom::nsIContentChild* aChild,
|
||||
mozilla::dom::nsIContentParent* aParent);
|
||||
|
||||
/*
|
||||
* Get the pixel data from the given source surface and return it as a buffer.
|
||||
* The length and stride will be assigned from the surface. This method will map
|
||||
* the surface; the caller should call Unmap on the surface when finished with
|
||||
* the data.
|
||||
*/
|
||||
static const uint8_t* GetSurfaceData(mozilla::gfx::DataSourceSurface* aSurface,
|
||||
size_t* aLength, int32_t* aStride);
|
||||
|
||||
private:
|
||||
static bool InitializeEventTable();
|
||||
|
||||
|
|
|
@ -128,6 +128,8 @@
|
|||
#include "nsIURIFixup.h"
|
||||
#include "nsIWindowWatcher.h"
|
||||
#include "nsIXULRuntime.h"
|
||||
#include "gfxDrawable.h"
|
||||
#include "ImageOps.h"
|
||||
#include "nsMemoryInfoDumper.h"
|
||||
#include "nsMemoryReporterManager.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
|
@ -140,6 +142,7 @@
|
|||
#include "ProcessPriorityManager.h"
|
||||
#include "SandboxHal.h"
|
||||
#include "ScreenManagerParent.h"
|
||||
#include "SourceSurfaceRawData.h"
|
||||
#include "StructuredCloneUtils.h"
|
||||
#include "TabParent.h"
|
||||
#include "URIUtils.h"
|
||||
|
@ -217,7 +220,6 @@ using namespace mozilla::system;
|
|||
#endif
|
||||
|
||||
static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
|
||||
static const char* sClipboardTextFlavors[] = { kUnicodeMime };
|
||||
|
||||
using base::ChildPrivileges;
|
||||
using base::KillProcess;
|
||||
|
@ -2523,42 +2525,9 @@ ContentParent::RecvReadPermissions(InfallibleTArray<IPC::Permission>* aPermissio
|
|||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvSetClipboardText(const nsString& text,
|
||||
const bool& isPrivateData,
|
||||
const int32_t& whichClipboard)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
|
||||
NS_ENSURE_SUCCESS(rv, true);
|
||||
|
||||
nsCOMPtr<nsISupportsString> dataWrapper =
|
||||
do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, true);
|
||||
|
||||
rv = dataWrapper->SetData(text);
|
||||
NS_ENSURE_SUCCESS(rv, true);
|
||||
|
||||
nsCOMPtr<nsITransferable> trans = do_CreateInstance("@mozilla.org/widget/transferable;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, true);
|
||||
trans->Init(nullptr);
|
||||
|
||||
// If our data flavor has already been added, this will fail. But we don't care
|
||||
trans->AddDataFlavor(kUnicodeMime);
|
||||
trans->SetIsPrivateData(isPrivateData);
|
||||
|
||||
nsCOMPtr<nsISupports> nsisupportsDataWrapper =
|
||||
do_QueryInterface(dataWrapper);
|
||||
|
||||
rv = trans->SetTransferData(kUnicodeMime, nsisupportsDataWrapper,
|
||||
text.Length() * sizeof(char16_t));
|
||||
NS_ENSURE_SUCCESS(rv, true);
|
||||
|
||||
clipboard->SetData(trans, nullptr, whichClipboard);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvGetClipboardText(const int32_t& whichClipboard, nsString* text)
|
||||
ContentParent::RecvSetClipboard(const IPCDataTransfer& aDataTransfer,
|
||||
const bool& aIsPrivateData,
|
||||
const int32_t& aWhichClipboard)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
|
||||
|
@ -2567,44 +2536,116 @@ ContentParent::RecvGetClipboardText(const int32_t& whichClipboard, nsString* tex
|
|||
nsCOMPtr<nsITransferable> trans = do_CreateInstance("@mozilla.org/widget/transferable;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, true);
|
||||
trans->Init(nullptr);
|
||||
trans->AddDataFlavor(kUnicodeMime);
|
||||
|
||||
clipboard->GetData(trans, whichClipboard);
|
||||
nsCOMPtr<nsISupports> tmp;
|
||||
uint32_t len;
|
||||
rv = trans->GetTransferData(kUnicodeMime, getter_AddRefs(tmp), &len);
|
||||
if (NS_FAILED(rv))
|
||||
return true;
|
||||
const nsTArray<IPCDataTransferItem>& items = aDataTransfer.items();
|
||||
for (uint32_t j = 0; j < items.Length(); ++j) {
|
||||
const IPCDataTransferItem& item = items[j];
|
||||
|
||||
nsCOMPtr<nsISupportsString> supportsString = do_QueryInterface(tmp);
|
||||
// No support for non-text data
|
||||
if (!supportsString)
|
||||
return true;
|
||||
supportsString->GetData(*text);
|
||||
trans->AddDataFlavor(item.flavor().get());
|
||||
|
||||
if (item.data().type() == IPCDataTransferData::TnsString) {
|
||||
nsCOMPtr<nsISupportsString> dataWrapper =
|
||||
do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, true);
|
||||
|
||||
nsString text = item.data().get_nsString();
|
||||
rv = dataWrapper->SetData(text);
|
||||
NS_ENSURE_SUCCESS(rv, true);
|
||||
|
||||
rv = trans->SetTransferData(item.flavor().get(), dataWrapper,
|
||||
text.Length() * sizeof(char16_t));
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, true);
|
||||
} else if (item.data().type() == IPCDataTransferData::TnsCString) {
|
||||
const IPCDataTransferImage& imageDetails = item.imageDetails();
|
||||
const gfxIntSize size(imageDetails.width(), imageDetails.height());
|
||||
if (!size.width || !size.height) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCString text = item.data().get_nsCString();
|
||||
mozilla::RefPtr<gfx::DataSourceSurface> image =
|
||||
new mozilla::gfx::SourceSurfaceRawData();
|
||||
mozilla::gfx::SourceSurfaceRawData* raw =
|
||||
static_cast<mozilla::gfx::SourceSurfaceRawData*>(image.get());
|
||||
raw->InitWrappingData(
|
||||
reinterpret_cast<uint8_t*>(const_cast<nsCString&>(text).BeginWriting()),
|
||||
size, imageDetails.stride(),
|
||||
static_cast<mozilla::gfx::SurfaceFormat>(imageDetails.format()), false);
|
||||
raw->GuaranteePersistance();
|
||||
|
||||
nsRefPtr<gfxDrawable> drawable = new gfxSurfaceDrawable(image, size);
|
||||
nsCOMPtr<imgIContainer> imageContainer(image::ImageOps::CreateFromDrawable(drawable));
|
||||
|
||||
nsCOMPtr<nsISupportsInterfacePointer>
|
||||
imgPtr(do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID, &rv));
|
||||
|
||||
rv = imgPtr->SetData(imageContainer);
|
||||
NS_ENSURE_SUCCESS(rv, true);
|
||||
|
||||
trans->SetTransferData(item.flavor().get(), imgPtr, sizeof(nsISupports*));
|
||||
}
|
||||
}
|
||||
|
||||
trans->SetIsPrivateData(aIsPrivateData);
|
||||
|
||||
clipboard->SetData(trans, nullptr, aWhichClipboard);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvEmptyClipboard(const int32_t& whichClipboard)
|
||||
ContentParent::RecvGetClipboard(nsTArray<nsCString>&& aTypes,
|
||||
const int32_t& aWhichClipboard,
|
||||
IPCDataTransfer* aDataTransfer)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
|
||||
NS_ENSURE_SUCCESS(rv, true);
|
||||
|
||||
clipboard->EmptyClipboard(whichClipboard);
|
||||
nsCOMPtr<nsITransferable> trans = do_CreateInstance("@mozilla.org/widget/transferable;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, true);
|
||||
trans->Init(nullptr);
|
||||
|
||||
for (uint32_t t = 0; t < aTypes.Length(); t++) {
|
||||
trans->AddDataFlavor(aTypes[t].get());
|
||||
}
|
||||
|
||||
clipboard->GetData(trans, aWhichClipboard);
|
||||
nsContentUtils::TransferableToIPCTransferable(trans, aDataTransfer,
|
||||
nullptr, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvClipboardHasText(const int32_t& whichClipboard, bool* hasText)
|
||||
ContentParent::RecvEmptyClipboard(const int32_t& aWhichClipboard)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
|
||||
NS_ENSURE_SUCCESS(rv, true);
|
||||
|
||||
clipboard->HasDataMatchingFlavors(sClipboardTextFlavors, 1,
|
||||
whichClipboard, hasText);
|
||||
clipboard->EmptyClipboard(aWhichClipboard);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvClipboardHasType(nsTArray<nsCString>&& aTypes,
|
||||
const int32_t& aWhichClipboard,
|
||||
bool* aHasType)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
|
||||
NS_ENSURE_SUCCESS(rv, true);
|
||||
|
||||
const char** typesChrs = new const char *[aTypes.Length()];
|
||||
for (uint32_t t = 0; t < aTypes.Length(); t++) {
|
||||
typesChrs[t] = aTypes[t].get();
|
||||
}
|
||||
|
||||
clipboard->HasDataMatchingFlavors(typesChrs, aTypes.Length(),
|
||||
aWhichClipboard, aHasType);
|
||||
|
||||
delete [] typesChrs;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -651,12 +651,16 @@ private:
|
|||
|
||||
virtual bool RecvReadPermissions(InfallibleTArray<IPC::Permission>* aPermissions) override;
|
||||
|
||||
virtual bool RecvSetClipboardText(const nsString& text,
|
||||
const bool& isPrivateData,
|
||||
const int32_t& whichClipboard) override;
|
||||
virtual bool RecvGetClipboardText(const int32_t& whichClipboard, nsString* text) override;
|
||||
virtual bool RecvEmptyClipboard(const int32_t& whichClipboard) override;
|
||||
virtual bool RecvClipboardHasText(const int32_t& whichClipboard, bool* hasText) override;
|
||||
virtual bool RecvSetClipboard(const IPCDataTransfer& aDataTransfer,
|
||||
const bool& aIsPrivateData,
|
||||
const int32_t& aWhichClipboard) override;
|
||||
virtual bool RecvGetClipboard(nsTArray<nsCString>&& aTypes,
|
||||
const int32_t& aWhichClipboard,
|
||||
IPCDataTransfer* aDataTransfer) override;
|
||||
virtual bool RecvEmptyClipboard(const int32_t& aWhichClipboard) override;
|
||||
virtual bool RecvClipboardHasType(nsTArray<nsCString>&& aTypes,
|
||||
const int32_t& aWhichClipboard,
|
||||
bool* aHasType) override;
|
||||
|
||||
virtual bool RecvGetSystemColors(const uint32_t& colorsCount,
|
||||
InfallibleTArray<uint32_t>* colors) override;
|
||||
|
|
|
@ -137,13 +137,24 @@ union BlobConstructorParams
|
|||
|
||||
union IPCDataTransferData
|
||||
{
|
||||
nsString;
|
||||
PBlob;
|
||||
nsString; // text
|
||||
nsCString; // images
|
||||
PBlob; // files
|
||||
};
|
||||
|
||||
struct IPCDataTransferImage
|
||||
{
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t stride;
|
||||
uint8_t format;
|
||||
};
|
||||
|
||||
struct IPCDataTransferItem
|
||||
{
|
||||
nsCString flavor;
|
||||
// The image details are only used when transferring images.
|
||||
IPCDataTransferImage imageDetails;
|
||||
IPCDataTransferData data;
|
||||
};
|
||||
|
||||
|
|
|
@ -767,12 +767,22 @@ parent:
|
|||
// nsIPermissionManager messages
|
||||
sync ReadPermissions() returns (Permission[] permissions);
|
||||
|
||||
SetClipboardText(nsString text, bool isPrivateData, int32_t whichClipboard);
|
||||
sync GetClipboardText(int32_t whichClipboard)
|
||||
returns (nsString text);
|
||||
EmptyClipboard(int32_t whichClipboard);
|
||||
sync ClipboardHasText(int32_t whichClipboard)
|
||||
returns (bool hasText);
|
||||
// Places the items within dataTransfer on the clipboard.
|
||||
SetClipboard(IPCDataTransfer aDataTransfer,
|
||||
bool aIsPrivateData,
|
||||
int32_t aWhichClipboard);
|
||||
|
||||
// Given a list of supported types, returns the clipboard data for the
|
||||
// first type that matches.
|
||||
sync GetClipboard(nsCString[] aTypes, int32_t aWhichClipboard)
|
||||
returns (IPCDataTransfer dataTransfer);
|
||||
|
||||
// Clears the clipboard.
|
||||
EmptyClipboard(int32_t aWhichClipboard);
|
||||
|
||||
// Returns true if data of one of the specified types is on the clipboard.
|
||||
sync ClipboardHasType(nsCString[] aTypes, int32_t aWhichClipboard)
|
||||
returns (bool hasType);
|
||||
|
||||
sync GetSystemColors(uint32_t colorsCount)
|
||||
returns (uint32_t[] colors);
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include "nsCOMPtr.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsStringStream.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
@ -23,21 +25,15 @@ NS_IMETHODIMP
|
|||
nsClipboardProxy::SetData(nsITransferable *aTransferable,
|
||||
nsIClipboardOwner *anOwner, int32_t aWhichClipboard)
|
||||
{
|
||||
nsCOMPtr<nsISupports> tmp;
|
||||
uint32_t len;
|
||||
nsresult rv = aTransferable->GetTransferData(kUnicodeMime, getter_AddRefs(tmp),
|
||||
&len);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsISupportsString> supportsString = do_QueryInterface(tmp);
|
||||
// No support for non-text data
|
||||
NS_ENSURE_TRUE(supportsString, NS_ERROR_NOT_IMPLEMENTED);
|
||||
nsAutoString buffer;
|
||||
supportsString->GetData(buffer);
|
||||
ContentChild* child = ContentChild::GetSingleton();
|
||||
|
||||
IPCDataTransfer ipcDataTransfer;
|
||||
nsContentUtils::TransferableToIPCTransferable(aTransferable, &ipcDataTransfer,
|
||||
child, nullptr);
|
||||
|
||||
bool isPrivateData = false;
|
||||
aTransferable->GetIsPrivateData(&isPrivateData);
|
||||
ContentChild::GetSingleton()->SendSetClipboardText(buffer, isPrivateData,
|
||||
aWhichClipboard);
|
||||
child->SendSetClipboard(ipcDataTransfer, isPrivateData, aWhichClipboard);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -45,25 +41,72 @@ nsClipboardProxy::SetData(nsITransferable *aTransferable,
|
|||
NS_IMETHODIMP
|
||||
nsClipboardProxy::GetData(nsITransferable *aTransferable, int32_t aWhichClipboard)
|
||||
{
|
||||
nsAutoString buffer;
|
||||
ContentChild::GetSingleton()->SendGetClipboardText(aWhichClipboard, &buffer);
|
||||
nsTArray<nsCString> types;
|
||||
|
||||
nsCOMPtr<nsISupportsArray> flavorList;
|
||||
aTransferable->FlavorsTransferableCanImport(getter_AddRefs(flavorList));
|
||||
if (flavorList) {
|
||||
uint32_t flavorCount = 0;
|
||||
flavorList->Count(&flavorCount);
|
||||
for (uint32_t j = 0; j < flavorCount; ++j) {
|
||||
nsCOMPtr<nsISupportsCString> flavor = do_QueryElementAt(flavorList, j);
|
||||
if (flavor) {
|
||||
nsAutoCString flavorStr;
|
||||
flavor->GetData(flavorStr);
|
||||
if (flavorStr.Length()) {
|
||||
types.AppendElement(flavorStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsISupportsString> dataWrapper =
|
||||
do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
IPCDataTransfer dataTransfer;
|
||||
ContentChild::GetSingleton()->SendGetClipboard(types, aWhichClipboard, &dataTransfer);
|
||||
|
||||
rv = dataWrapper->SetData(buffer);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
auto& items = dataTransfer.items();
|
||||
for (uint32_t j = 0; j < items.Length(); ++j) {
|
||||
const IPCDataTransferItem& item = items[j];
|
||||
|
||||
// If our data flavor has already been added, this will fail. But we don't care
|
||||
aTransferable->AddDataFlavor(kUnicodeMime);
|
||||
if (item.data().type() == IPCDataTransferData::TnsString) {
|
||||
nsCOMPtr<nsISupportsString> dataWrapper =
|
||||
do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsISupports> nsisupportsDataWrapper =
|
||||
do_QueryInterface(dataWrapper);
|
||||
rv = aTransferable->SetTransferData(kUnicodeMime, nsisupportsDataWrapper,
|
||||
buffer.Length() * sizeof(char16_t));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsString data = item.data().get_nsString();
|
||||
rv = dataWrapper->SetData(data);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aTransferable->SetTransferData(item.flavor().get(), dataWrapper,
|
||||
data.Length() * sizeof(char16_t));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else if (item.data().type() == IPCDataTransferData::TnsCString) {
|
||||
// If this is an image, convert it into an nsIInputStream.
|
||||
nsCString flavor = item.flavor();
|
||||
if (flavor.EqualsLiteral(kJPEGImageMime) ||
|
||||
flavor.EqualsLiteral(kJPGImageMime) ||
|
||||
flavor.EqualsLiteral(kPNGImageMime) ||
|
||||
flavor.EqualsLiteral(kGIFImageMime)) {
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
NS_NewCStringInputStream(getter_AddRefs(stream), item.data().get_nsCString());
|
||||
|
||||
rv = aTransferable->SetTransferData(flavor.get(), stream, sizeof(nsISupports*));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else if (flavor.EqualsLiteral(kNativeHTMLMime)) {
|
||||
nsCOMPtr<nsISupportsCString> dataWrapper =
|
||||
do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCString data = item.data().get_nsCString();
|
||||
rv = dataWrapper->SetData(data);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aTransferable->SetTransferData(item.flavor().get(), dataWrapper,
|
||||
data.Length());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -77,11 +120,18 @@ nsClipboardProxy::EmptyClipboard(int32_t aWhichClipboard)
|
|||
|
||||
NS_IMETHODIMP
|
||||
nsClipboardProxy::HasDataMatchingFlavors(const char **aFlavorList,
|
||||
uint32_t aLength, int32_t aWhichClipboard,
|
||||
bool *aHasText)
|
||||
uint32_t aLength, int32_t aWhichClipboard,
|
||||
bool *aHasType)
|
||||
{
|
||||
*aHasText = false;
|
||||
ContentChild::GetSingleton()->SendClipboardHasText(aWhichClipboard, aHasText);
|
||||
*aHasType = false;
|
||||
|
||||
nsTArray<nsCString> types;
|
||||
for (uint32_t j = 0; j < aLength; ++j) {
|
||||
types.AppendElement(nsDependentCString(aFlavorList[j]));
|
||||
}
|
||||
|
||||
ContentChild::GetSingleton()->SendClipboardHasType(types, aWhichClipboard, aHasType);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -57,21 +57,17 @@ nsDragServiceProxy::InvokeDragSession(nsIDOMNode* aDOMNode,
|
|||
if (surface) {
|
||||
mozilla::RefPtr<mozilla::gfx::DataSourceSurface> dataSurface =
|
||||
surface->GetDataSurface();
|
||||
mozilla::gfx::DataSourceSurface::MappedSurface map;
|
||||
dataSurface->Map(mozilla::gfx::DataSourceSurface::MapType::READ, &map);
|
||||
|
||||
size_t length;
|
||||
int32_t stride;
|
||||
const uint8_t* data = nsContentUtils::GetSurfaceData(dataSurface, &length, &stride);
|
||||
nsDependentCString dragImage(reinterpret_cast<const char*>(data), length);
|
||||
|
||||
mozilla::gfx::IntSize size = dataSurface->GetSize();
|
||||
mozilla::CheckedInt32 requiredBytes =
|
||||
mozilla::CheckedInt32(map.mStride) * mozilla::CheckedInt32(size.height);
|
||||
size_t bufLen = requiredBytes.isValid() ? requiredBytes.value() : 0;
|
||||
mozilla::gfx::SurfaceFormat format = dataSurface->GetFormat();
|
||||
// Surface data handling is totally nuts. This is the magic one needs to
|
||||
// know to access the data.
|
||||
bufLen = bufLen - map.mStride + (size.width * BytesPerPixel(format));
|
||||
nsDependentCString dragImage(reinterpret_cast<char*>(map.mData), bufLen);
|
||||
mozilla::unused <<
|
||||
child->SendInvokeDragSession(dataTransfers, aActionType, dragImage,
|
||||
size.width, size.height, map.mStride,
|
||||
static_cast<uint8_t>(format),
|
||||
size.width, size.height, stride,
|
||||
static_cast<uint8_t>(dataSurface->GetFormat()),
|
||||
dragRect.x, dragRect.y);
|
||||
dataSurface->Unmap();
|
||||
StartDragSession();
|
||||
|
|
Загрузка…
Ссылка в новой задаче