Bug 1275398 - Use shmem for sending image data in IPCDataTransfer. r=nical

MozReview-Commit-ID: 9XETnSBXxEW
This commit is contained in:
Cervantes Yu 2016-06-16 00:57:46 +08:00
parent 3115f628a1
commit 28706c5d87
13 changed files with 97 additions and 26 deletions

View File

@ -7343,7 +7343,7 @@ nsresult
nsContentUtils::DataTransferItemToImage(const IPCDataTransferItem& aItem,
imgIContainer** aContainer)
{
MOZ_ASSERT(aItem.data().type() == IPCDataTransferData::TnsCString);
MOZ_ASSERT(aItem.data().type() == IPCDataTransferData::TShmem);
MOZ_ASSERT(IsFlavorImage(aItem.flavor()));
const IPCDataTransferImage& imageDetails = aItem.imageDetails();
@ -7352,12 +7352,12 @@ nsContentUtils::DataTransferItemToImage(const IPCDataTransferItem& aItem,
return NS_ERROR_FAILURE;
}
const nsCString& text = aItem.data().get_nsCString();
Shmem data = aItem.data().get_Shmem();
RefPtr<DataSourceSurface> image =
CreateDataSourceSurfaceFromData(size,
static_cast<SurfaceFormat>(imageDetails.format()),
reinterpret_cast<const uint8_t*>(text.BeginReading()),
data.get<uint8_t>(),
imageDetails.stride());
RefPtr<gfxDrawable> drawable = new gfxSurfaceDrawable(image, size);
@ -7378,6 +7378,31 @@ nsContentUtils::IsFlavorImage(const nsACString& aFlavor)
aFlavor.EqualsLiteral(kGIFImageMime);
}
static Shmem
ConvertToShmem(mozilla::dom::nsIContentChild* aChild,
mozilla::dom::nsIContentParent* aParent,
const nsACString& aInput)
{
MOZ_ASSERT((aChild && !aParent) || (!aChild && aParent));
IShmemAllocator* allocator =
aChild ? static_cast<IShmemAllocator*>(aChild)
: static_cast<IShmemAllocator*>(aParent);
Shmem result;
if (!allocator->AllocShmem(aInput.Length() + 1,
SharedMemory::TYPE_BASIC,
&result)) {
return result;
}
memcpy(result.get<char>(),
aInput.BeginReading(),
aInput.Length() + 1);
return result;
}
void
nsContentUtils::TransferableToIPCTransferable(nsITransferable* aTransferable,
IPCDataTransfer* aIPCDataTransfer,
@ -7422,7 +7447,13 @@ nsContentUtils::TransferableToIPCTransferable(nsITransferable* aTransferable,
ctext->GetData(dataAsString);
IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
item->flavor() = flavorStr;
item->data() = dataAsString;
Shmem dataAsShmem = ConvertToShmem(aChild, aParent, dataAsString);
if (!dataAsShmem.IsReadable() || !dataAsShmem.Size<char>()) {
continue;
}
item->data() = dataAsShmem;
} else {
nsCOMPtr<nsISupportsInterfacePointer> sip =
do_QueryInterface(data);
@ -7438,7 +7469,13 @@ nsContentUtils::TransferableToIPCTransferable(nsITransferable* aTransferable,
nsCString imageData;
NS_ConsumeStream(stream, UINT32_MAX, imageData);
item->data() = imageData;
Shmem imageDataShmem = ConvertToShmem(aChild, aParent, imageData);
if (!imageDataShmem.IsReadable() || !imageDataShmem.Size<char>()) {
continue;
}
item->data() = imageDataShmem;
continue;
}
@ -7458,15 +7495,17 @@ nsContentUtils::TransferableToIPCTransferable(nsITransferable* aTransferable,
}
size_t length;
int32_t stride;
mozilla::UniquePtr<char[]> surfaceData =
nsContentUtils::GetSurfaceData(WrapNotNull(dataSurface), &length,
&stride);
Shmem surfaceData;
IShmemAllocator* allocator = aChild ? static_cast<IShmemAllocator*>(aChild)
: static_cast<IShmemAllocator*>(aParent);
GetSurfaceData(dataSurface, &length, &stride,
allocator,
&surfaceData);
IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
item->flavor() = flavorStr;
// Turn item->data() into an nsCString prior to accessing it.
item->data() = EmptyCString();
item->data().get_nsCString().Adopt(surfaceData.release(), length);
item->data() = surfaceData;
IPCDataTransferImage& imageDetails = item->imageDetails();
mozilla::gfx::IntSize size = dataSurface->GetSize();
@ -7494,7 +7533,9 @@ nsContentUtils::TransferableToIPCTransferable(nsITransferable* aTransferable,
item->flavor() = type;
nsAutoCString data;
SlurpFileToString(file, data);
item->data() = data;
Shmem dataAsShmem = ConvertToShmem(aChild, aParent, data);
item->data() = dataAsShmem;
}
continue;
@ -7553,7 +7594,7 @@ nsContentUtils::TransferableToIPCTransferable(nsITransferable* aTransferable,
// Empty element, transfer only the flavor
IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
item->flavor() = flavorStr;
item->data() = EmptyCString();
item->data() = nsString();
continue;
}
}

View File

@ -46,6 +46,8 @@ public:
const bool& aIsForApp,
const bool& aIsForBrowser) override;
FORWARD_SHMEM_ALLOCATOR_TO(PContentBridgeChild)
protected:
virtual ~ContentBridgeChild();

View File

@ -46,6 +46,8 @@ public:
const bool& aIsForApp,
const bool& aIsForBrowser) override;
FORWARD_SHMEM_ALLOCATOR_TO(PContentBridgeParent)
jsipc::CPOWManager* GetCPOWManager() override;
virtual ContentParentId ChildID() const override

View File

@ -3320,9 +3320,10 @@ ContentChild::RecvInvokeDragSession(nsTArray<IPCDataTransfer>&& aTransfers,
if (item.data().type() == IPCDataTransferData::TnsString) {
const nsString& data = item.data().get_nsString();
variant->SetAsAString(data);
} else if (item.data().type() == IPCDataTransferData::TnsCString) {
const nsCString& data = item.data().get_nsCString();
variant->SetAsACString(data);
} else if (item.data().type() == IPCDataTransferData::TShmem) {
Shmem data = item.data().get_Shmem();
variant->SetAsACString(nsDependentCString(data.get<char>(), data.Size<char>()));
Unused << DeallocShmem(data);
} else if (item.data().type() == IPCDataTransferData::TPBlobChild) {
BlobChild* blob = static_cast<BlobChild*>(item.data().get_PBlobChild());
RefPtr<BlobImpl> blobImpl = blob->GetBlobImpl();

View File

@ -592,6 +592,8 @@ public:
const bool& aIsForApp,
const bool& aIsForBrowser) override;
FORWARD_SHMEM_ALLOCATOR_TO(PContentChild)
void GetAvailableDictionaries(InfallibleTArray<nsString>& aDictionaries);
PBrowserOrId

View File

@ -2763,7 +2763,7 @@ ContentParent::RecvSetClipboard(const IPCDataTransfer& aDataTransfer,
text.Length() * sizeof(char16_t));
NS_ENSURE_SUCCESS(rv, true);
} else if (item.data().type() == IPCDataTransferData::TnsCString) {
} else if (item.data().type() == IPCDataTransferData::TShmem) {
if (nsContentUtils::IsFlavorImage(item.flavor())) {
nsCOMPtr<imgIContainer> imageContainer;
rv = nsContentUtils::DataTransferItemToImage(item,
@ -2783,7 +2783,10 @@ ContentParent::RecvSetClipboard(const IPCDataTransfer& aDataTransfer,
do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, true);
const nsCString& text = item.data().get_nsCString();
// The buffer contains the terminating null.
Shmem itemData = item.data().get_Shmem();
const nsDependentCString text(itemData.get<char>(),
itemData.Size<char>());
rv = dataWrapper->SetData(text);
NS_ENSURE_SUCCESS(rv, true);
@ -2791,6 +2794,8 @@ ContentParent::RecvSetClipboard(const IPCDataTransfer& aDataTransfer,
NS_ENSURE_SUCCESS(rv, true);
}
Unused << DeallocShmem(item.data().get_Shmem());
}
}

View File

@ -619,6 +619,8 @@ private:
const bool& aIsForBrowser) override;
using PContentParent::SendPTestShellConstructor;
FORWARD_SHMEM_ALLOCATOR_TO(PContentParent)
// No more than one of !!aApp, aIsForBrowser, and aIsForPreallocated may be
// true.
ContentParent(mozIApplication* aApp,

View File

@ -144,7 +144,7 @@ union BlobConstructorParams
union IPCDataTransferData
{
nsString; // text
nsCString; // images
Shmem; // images using Shmem
PBlob; // files
};

View File

@ -3321,7 +3321,7 @@ TabParent::AddInitialDnDDataTo(DataTransfer* aDataTransfer)
auto* parent = static_cast<BlobParent*>(item.data().get_PBlobParent());
RefPtr<BlobImpl> impl = parent->GetBlobImpl();
variant->SetAsISupports(impl);
} else if (item.data().type() == IPCDataTransferData::TnsCString) {
} else if (item.data().type() == IPCDataTransferData::TShmem) {
if (nsContentUtils::IsFlavorImage(item.flavor())) {
// An image! Get the imgIContainer for it and set it in the variant.
nsCOMPtr<imgIContainer> imageContainer;
@ -3333,8 +3333,11 @@ TabParent::AddInitialDnDDataTo(DataTransfer* aDataTransfer)
}
variant->SetAsISupports(imageContainer);
} else {
variant->SetAsACString(item.data().get_nsCString());
Shmem data = item.data().get_Shmem();
variant->SetAsACString(nsDependentCString(data.get<char>(), data.Size<char>()));
}
mozilla::Unused << DeallocShmem(item.data().get_Shmem());
}
// Using system principal here, since once the data is on parent process

View File

@ -12,6 +12,7 @@
#include "nsISupports.h"
#include "nsTArrayForwardDeclare.h"
#include "mozilla/dom/CPOWManagerGetter.h"
#include "mozilla/ipc/Shmem.h"
#include "mozilla/jsipc/CrossProcessObjectWrappers.h"
#define NS_ICONTENTCHILD_IID \
@ -25,6 +26,9 @@ class Principal;
} // namespace IPC
namespace mozilla {
namespace ipc {
class Shmem;
} // namespace ipc
namespace jsipc {
class PJavaScriptChild;
@ -44,6 +48,7 @@ class PBrowserChild;
class nsIContentChild : public nsISupports
, public CPOWManagerGetter
, public mozilla::ipc::IShmemAllocator
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICONTENTCHILD_IID)
@ -63,6 +68,7 @@ public:
const ContentParentId& aCpID,
const bool& aIsForApp,
const bool& aIsForBrowser) = 0;
protected:
virtual jsipc::PJavaScriptChild* AllocPJavaScriptChild();
virtual bool DeallocPJavaScriptChild(jsipc::PJavaScriptChild*);

View File

@ -9,6 +9,7 @@
#include "mozilla/Attributes.h"
#include "mozilla/dom/ipc/IdType.h"
#include "mozilla/ipc/ProtocolUtils.h"
#include "nsFrameMessageManager.h"
#include "nsISupports.h"
@ -46,6 +47,7 @@ class PBrowserParent;
class nsIContentParent : public nsISupports
, public mozilla::dom::ipc::MessageManagerCallback
, public CPOWManagerGetter
, public mozilla::ipc::IShmemAllocator
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICONTENTPARENT_IID)

View File

@ -25,7 +25,7 @@ public:
id_t aIPDLId,
size_t aSize,
SharedMemory::SharedMemoryType aType) :
IPC::Message(routingId, SHMEM_CREATED_MESSAGE_TYPE, PRIORITY_NORMAL)
IPC::Message(routingId, SHMEM_CREATED_MESSAGE_TYPE, PRIORITY_URGENT)
{
IPC::WriteParam(this, aIPDLId);
IPC::WriteParam(this, aSize);

View File

@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/ContentChild.h"
#include "mozilla/unused.h"
#include "nsClipboardProxy.h"
#include "nsISupportsPrimitives.h"
#include "nsCOMPtr.h"
@ -80,15 +81,18 @@ nsClipboardProxy::GetData(nsITransferable *aTransferable, int32_t aWhichClipboar
rv = aTransferable->SetTransferData(item.flavor().get(), dataWrapper,
data.Length() * sizeof(char16_t));
NS_ENSURE_SUCCESS(rv, rv);
} else if (item.data().type() == IPCDataTransferData::TnsCString) {
} else if (item.data().type() == IPCDataTransferData::TShmem) {
// If this is an image, convert it into an nsIInputStream.
nsCString flavor = item.flavor();
mozilla::ipc::Shmem data = item.data().get_Shmem();
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());
NS_NewCStringInputStream(getter_AddRefs(stream),
nsDependentCString(data.get<char>(), data.Size<char>()));
rv = aTransferable->SetTransferData(flavor.get(), stream, sizeof(nsISupports*));
NS_ENSURE_SUCCESS(rv, rv);
@ -99,14 +103,15 @@ nsClipboardProxy::GetData(nsITransferable *aTransferable, int32_t aWhichClipboar
do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCString data = item.data().get_nsCString();
rv = dataWrapper->SetData(data);
rv = dataWrapper->SetData(nsDependentCString(data.get<char>(), data.Size<char>()));
NS_ENSURE_SUCCESS(rv, rv);
rv = aTransferable->SetTransferData(item.flavor().get(), dataWrapper,
data.Length());
data.Size<char>());
NS_ENSURE_SUCCESS(rv, rv);
}
mozilla::Unused << ContentChild::GetSingleton()->DeallocShmem(data);
}
}