Bug 1183915 - Put images dragged from content processes in the drag data in the parent. r=smaug

This commit is contained in:
Blake Kaplan 2016-02-23 16:31:29 -08:00
Родитель 1837d54fa7
Коммит 89b19e3239
5 изменённых файлов: 122 добавлений и 97 удалений

Просмотреть файл

@ -25,7 +25,9 @@
#include "MediaDecoder.h"
// nsNPAPIPluginInstance must be included before nsIDocument.h, which is included in mozAutoDocUpdate.h.
#include "nsNPAPIPluginInstance.h"
#include "gfxDrawable.h"
#include "gfxPrefs.h"
#include "ImageOps.h"
#include "mozAutoDocUpdate.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Attributes.h"
@ -200,6 +202,7 @@
#include "nsICookieService.h"
#include "mozilla/EnumSet.h"
#include "mozilla/BloomFilter.h"
#include "SourceSurfaceRawData.h"
#include "nsIBidiKeyboard.h"
@ -216,6 +219,7 @@ extern "C" int MOZ_XMLCheckQName(const char* ptr, const char* end,
class imgLoader;
using namespace mozilla::dom;
using namespace mozilla::gfx;
using namespace mozilla::layers;
using namespace mozilla::widget;
using namespace mozilla;
@ -7427,6 +7431,48 @@ nsContentUtils::IsFileImage(nsIFile* aFile, nsACString& aType)
return StringBeginsWith(aType, NS_LITERAL_CSTRING("image/"));
}
nsresult
nsContentUtils::DataTransferItemToImage(const IPCDataTransferItem& aItem,
imgIContainer** aContainer)
{
MOZ_ASSERT(aItem.data().type() == IPCDataTransferData::TnsCString);
MOZ_ASSERT(IsFlavorImage(aItem.flavor()));
const IPCDataTransferImage& imageDetails = aItem.imageDetails();
const IntSize size(imageDetails.width(), imageDetails.height());
if (!size.width || !size.height) {
return NS_ERROR_FAILURE;
}
const nsCString& text = aItem.data().get_nsCString();
// InitWrappingData takes a non-const pointer for reading.
nsCString& nonConstText = const_cast<nsCString&>(text);
RefPtr<SourceSurfaceRawData> image = new SourceSurfaceRawData();
image->InitWrappingData(reinterpret_cast<uint8_t*>(nonConstText.BeginWriting()),
size, imageDetails.stride(),
static_cast<SurfaceFormat>(imageDetails.format()),
false);
image->GuaranteePersistance();
RefPtr<gfxDrawable> drawable = new gfxSurfaceDrawable(image, size);
nsCOMPtr<imgIContainer> imageContainer =
image::ImageOps::CreateFromDrawable(drawable);
imageContainer.forget(aContainer);
return NS_OK;
}
bool
nsContentUtils::IsFlavorImage(const nsACString& aFlavor)
{
return aFlavor.EqualsLiteral(kNativeImageMime) ||
aFlavor.EqualsLiteral(kJPEGImageMime) ||
aFlavor.EqualsLiteral(kJPGImageMime) ||
aFlavor.EqualsLiteral(kPNGImageMime) ||
aFlavor.EqualsLiteral(kGIFImageMime);
}
void
nsContentUtils::TransferableToIPCTransferable(nsITransferable* aTransferable,
IPCDataTransfer* aIPCDataTransfer,

Просмотреть файл

@ -121,6 +121,7 @@ class DocumentFragment;
class Element;
class EventTarget;
class IPCDataTransfer;
class IPCDataTransferItem;
class NodeInfo;
class nsIContentChild;
class nsIContentParent;
@ -2428,6 +2429,21 @@ public:
*/
static bool IsFileImage(nsIFile* aFile, nsACString& aType);
/**
* Given an IPCDataTransferItem that has a flavor for which IsFlavorImage
* returns true and whose IPCDataTransferData is of type nsCString (raw image
* data), construct an imgIContainer for the image encoded by the transfer
* item.
*/
static nsresult DataTransferItemToImage(const mozilla::dom::IPCDataTransferItem& aItem,
imgIContainer** aContainer);
/**
* Given a flavor obtained from an IPCDataTransferItem or nsITransferable,
* returns true if we should treat the data as an image.
*/
static bool IsFlavorImage(const nsACString& aFlavor);
static void TransferablesToIPCTransferables(nsISupportsArray* aTransferables,
nsTArray<mozilla::dom::IPCDataTransfer>& aIPC,
bool aInSyncMessage,

Просмотреть файл

@ -156,8 +156,6 @@
#include "nsPIWindowWatcher.h"
#include "nsWindowWatcher.h"
#include "nsIXULRuntime.h"
#include "gfxDrawable.h"
#include "ImageOps.h"
#include "mozilla/dom/nsMixedContentBlocker.h"
#include "nsMemoryInfoDumper.h"
#include "nsMemoryReporterManager.h"
@ -2865,75 +2863,56 @@ ContentParent::RecvSetClipboard(const IPCDataTransfer& aDataTransfer,
nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
NS_ENSURE_SUCCESS(rv, true);
nsCOMPtr<nsITransferable> trans = do_CreateInstance("@mozilla.org/widget/transferable;1", &rv);
nsCOMPtr<nsITransferable> trans =
do_CreateInstance("@mozilla.org/widget/transferable;1", &rv);
NS_ENSURE_SUCCESS(rv, true);
trans->Init(nullptr);
const nsTArray<IPCDataTransferItem>& items = aDataTransfer.items();
for (uint32_t j = 0; j < items.Length(); ++j) {
const IPCDataTransferItem& item = items[j];
for (const auto& item : items) {
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) {
if (item.flavor().EqualsLiteral(kNativeImageMime) ||
item.flavor().EqualsLiteral(kJPEGImageMime) ||
item.flavor().EqualsLiteral(kJPGImageMime) ||
item.flavor().EqualsLiteral(kPNGImageMime) ||
item.flavor().EqualsLiteral(kGIFImageMime)) {
const IPCDataTransferImage& imageDetails = item.imageDetails();
const gfx::IntSize size(imageDetails.width(), imageDetails.height());
if (!size.width || !size.height) {
return true;
}
nsCString text = item.data().get_nsCString();
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();
RefPtr<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);
nsCOMPtr<nsISupportsString> dataWrapper =
do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, true);
trans->SetTransferData(item.flavor().get(), imgPtr, sizeof(nsISupports*));
} else {
nsCOMPtr<nsISupportsCString> dataWrapper =
do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, true);
const nsCString& text = item.data().get_nsCString();
const nsString& text = item.data().get_nsString();
rv = dataWrapper->SetData(text);
NS_ENSURE_SUCCESS(rv, true);
rv = trans->SetTransferData(item.flavor().get(), dataWrapper, text.Length());
rv = trans->SetTransferData(item.flavor().get(), dataWrapper,
text.Length() * sizeof(char16_t));
NS_ENSURE_SUCCESS(rv, true);
}
} else if (item.data().type() == IPCDataTransferData::TnsCString) {
if (nsContentUtils::IsFlavorImage(item.flavor())) {
nsCOMPtr<imgIContainer> imageContainer;
rv = nsContentUtils::DataTransferItemToImage(item,
getter_AddRefs(imageContainer));
NS_ENSURE_SUCCESS(rv, true);
nsCOMPtr<nsISupportsInterfacePointer> imgPtr =
do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID);
NS_ENSURE_TRUE(imgPtr, true);
rv = imgPtr->SetData(imageContainer);
NS_ENSURE_SUCCESS(rv, true);
trans->SetTransferData(item.flavor().get(), imgPtr, sizeof(nsISupports*));
} else {
nsCOMPtr<nsISupportsCString> dataWrapper =
do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, true);
const nsCString& text = item.data().get_nsCString();
rv = dataWrapper->SetData(text);
NS_ENSURE_SUCCESS(rv, true);
rv = trans->SetTransferData(item.flavor().get(), dataWrapper, text.Length());
NS_ENSURE_SUCCESS(rv, true);
}
}
}

Просмотреть файл

@ -3152,24 +3152,7 @@ TabParent::RecvInvokeDragSession(nsTArray<IPCDataTransfer>&& aTransfers,
EventStateManager* esm = shell->GetPresContext()->EventStateManager();
for (uint32_t i = 0; i < aTransfers.Length(); ++i) {
auto& items = aTransfers[i].items();
nsTArray<DataTransferItem>* itemArray = mInitialDataTransferItems.AppendElement();
for (uint32_t j = 0; j < items.Length(); ++j) {
const IPCDataTransferItem& item = items[j];
DataTransferItem* localItem = itemArray->AppendElement();
localItem->mFlavor = item.flavor();
if (item.data().type() == IPCDataTransferData::TnsString) {
localItem->mType = DataTransferItem::DataType::eString;
localItem->mStringData = item.data().get_nsString();
} else if (item.data().type() == IPCDataTransferData::TPBlobChild) {
localItem->mType = DataTransferItem::DataType::eBlob;
BlobParent* blobParent =
static_cast<BlobParent*>(item.data().get_PBlobParent());
if (blobParent) {
localItem->mBlobData = blobParent->GetBlobImpl();
}
}
}
mInitialDataTransferItems.AppendElement(mozilla::Move(aTransfers[i].items()));
}
if (Manager()->IsContentParent()) {
nsCOMPtr<nsIDragService> dragService =
@ -3205,24 +3188,37 @@ void
TabParent::AddInitialDnDDataTo(DataTransfer* aDataTransfer)
{
for (uint32_t i = 0; i < mInitialDataTransferItems.Length(); ++i) {
nsTArray<DataTransferItem>& itemArray = mInitialDataTransferItems[i];
for (uint32_t j = 0; j < itemArray.Length(); ++j) {
DataTransferItem& item = itemArray[j];
nsTArray<IPCDataTransferItem>& itemArray = mInitialDataTransferItems[i];
for (auto& item : itemArray) {
RefPtr<nsVariantCC> variant = new nsVariantCC();
// Special case kFilePromiseMime so that we get the right
// nsIFlavorDataProvider for it.
if (item.mFlavor.EqualsLiteral(kFilePromiseMime)) {
if (item.flavor().EqualsLiteral(kFilePromiseMime)) {
RefPtr<nsISupports> flavorDataProvider =
new nsContentAreaDragDropDataProvider();
variant->SetAsISupports(flavorDataProvider);
} else if (item.mType == DataTransferItem::DataType::eString) {
variant->SetAsAString(item.mStringData);
} else if (item.mType == DataTransferItem::DataType::eBlob) {
variant->SetAsISupports(item.mBlobData);
} else if (item.data().type() == IPCDataTransferData::TnsString) {
variant->SetAsAString(item.data().get_nsString());
} else if (item.data().type() == IPCDataTransferData::TPBlobParent) {
auto* parent = static_cast<BlobParent*>(item.data().get_PBlobParent());
RefPtr<BlobImpl> impl = parent->GetBlobImpl();
variant->SetAsISupports(impl);
} else if (item.data().type() == IPCDataTransferData::TnsCString &&
nsContentUtils::IsFlavorImage(item.flavor())) {
// An image! Get the imgIContainer for it and set it in the variant.
nsCOMPtr<imgIContainer> imageContainer;
nsresult rv =
nsContentUtils::DataTransferItemToImage(item,
getter_AddRefs(imageContainer));
if (NS_FAILED(rv)) {
continue;
}
variant->SetAsISupports(imageContainer);
}
// Using system principal here, since once the data is on parent process
// side, it can be handled as being from browser chrome or OS.
aDataTransfer->SetDataWithPrincipal(NS_ConvertUTF8toUTF16(item.mFlavor),
aDataTransfer->SetDataWithPrincipal(NS_ConvertUTF8toUTF16(item.flavor()),
variant, i,
nsContentUtils::GetSystemPrincipal());
}

Просмотреть файл

@ -644,19 +644,7 @@ private:
uint32_t mChromeFlags;
struct DataTransferItem
{
nsCString mFlavor;
nsString mStringData;
RefPtr<mozilla::dom::BlobImpl> mBlobData;
enum DataType
{
eString,
eBlob
};
DataType mType;
};
nsTArray<nsTArray<DataTransferItem>> mInitialDataTransferItems;
nsTArray<nsTArray<IPCDataTransferItem>> mInitialDataTransferItems;
RefPtr<gfx::DataSourceSurface> mDnDVisualization;
int32_t mDragAreaX;