widget/nsClipboardProxy.cpp
author Rob Wu <rob@robwu.nl>
Sat, 24 Sep 2016 11:16:32 +0200
changeset 320058 a41f871e2d1b37754bbd1001c36c075511b49342
parent 318173 bd7461a1ed09447f4d38b4911f0e83933f9d875b
permissions -rw-r--r--
Bug 1299411 - Decouple Port implementation from API r=aswan Decoupled the API from the implementation. From now on it is possible to create Port instances without generating an API. This allows us to internally use Ports to pass around messages with minimal overhead (in the form of unnecessary clones of messages). This will be used by native messaging. This commit has no behavioral change, it is mostly moving around some code and storing the internal message listener in a set. MozReview-Commit-ID: 4h0LNJvTH9R

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "mozilla/dom/ContentChild.h"
#include "mozilla/Unused.h"
#include "nsArrayUtils.h"
#include "nsClipboardProxy.h"
#include "nsISupportsPrimitives.h"
#include "nsCOMPtr.h"
#include "nsComponentManagerUtils.h"
#include "nsXULAppAPI.h"
#include "nsContentUtils.h"
#include "nsStringStream.h"

using namespace mozilla;
using namespace mozilla::dom;

NS_IMPL_ISUPPORTS(nsClipboardProxy, nsIClipboard, nsIClipboardProxy)

nsClipboardProxy::nsClipboardProxy()
  : mClipboardCaps(false, false)
{
}

NS_IMETHODIMP
nsClipboardProxy::SetData(nsITransferable *aTransferable,
                          nsIClipboardOwner *anOwner, int32_t aWhichClipboard)
{
  ContentChild* child = ContentChild::GetSingleton();

  IPCDataTransfer ipcDataTransfer;
  nsContentUtils::TransferableToIPCTransferable(aTransferable, &ipcDataTransfer,
                                                false, child, nullptr);

  bool isPrivateData = false;
  aTransferable->GetIsPrivateData(&isPrivateData);
  nsCOMPtr<nsIPrincipal> requestingPrincipal;
  aTransferable->GetRequestingPrincipal(getter_AddRefs(requestingPrincipal));
  child->SendSetClipboard(ipcDataTransfer, isPrivateData,
                          IPC::Principal(requestingPrincipal), aWhichClipboard);

  return NS_OK;
}

NS_IMETHODIMP
nsClipboardProxy::GetData(nsITransferable *aTransferable, int32_t aWhichClipboard)
{
   nsTArray<nsCString> types;
  
  nsCOMPtr<nsIArray> flavorList;
  aTransferable->FlavorsTransferableCanImport(getter_AddRefs(flavorList));
  if (flavorList) {
    uint32_t flavorCount = 0;
    flavorList->GetLength(&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;
  IPCDataTransfer dataTransfer;
  ContentChild::GetSingleton()->SendGetClipboard(types, aWhichClipboard, &dataTransfer);

  auto& items = dataTransfer.items();
  for (uint32_t j = 0; j < items.Length(); ++j) {
    const IPCDataTransferItem& item = items[j];

    if (item.data().type() == IPCDataTransferData::TnsString) {
      nsCOMPtr<nsISupportsString> dataWrapper =
        do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
      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::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),
                                 nsDependentCString(data.get<char>(), data.Size<char>()));

        rv = aTransferable->SetTransferData(flavor.get(), stream, sizeof(nsISupports*));
        NS_ENSURE_SUCCESS(rv, rv);
      } else if (flavor.EqualsLiteral(kNativeHTMLMime) ||
                 flavor.EqualsLiteral(kRTFMime) ||
                 flavor.EqualsLiteral(kCustomTypesMime)) {
        nsCOMPtr<nsISupportsCString> dataWrapper =
          do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID, &rv);
        NS_ENSURE_SUCCESS(rv, rv);

        rv = dataWrapper->SetData(nsDependentCString(data.get<char>(), data.Size<char>()));
        NS_ENSURE_SUCCESS(rv, rv);

        rv = aTransferable->SetTransferData(item.flavor().get(), dataWrapper,
                                            data.Size<char>());
        NS_ENSURE_SUCCESS(rv, rv);
      }

      mozilla::Unused << ContentChild::GetSingleton()->DeallocShmem(data);
    }
  }

  return NS_OK;
}

NS_IMETHODIMP
nsClipboardProxy::EmptyClipboard(int32_t aWhichClipboard)
{
  ContentChild::GetSingleton()->SendEmptyClipboard(aWhichClipboard);
  return NS_OK;
}

NS_IMETHODIMP
nsClipboardProxy::HasDataMatchingFlavors(const char **aFlavorList,
                                         uint32_t aLength, int32_t aWhichClipboard,
                                         bool *aHasType)
{
  *aHasType = false;

  nsTArray<nsCString> types;
  nsCString* t = types.AppendElements(aLength);
  for (uint32_t j = 0; j < aLength; ++j) {
    t[j].Rebind(aFlavorList[j], nsCharTraits<char>::length(aFlavorList[j]));
  }

  ContentChild::GetSingleton()->SendClipboardHasType(types, aWhichClipboard, aHasType);

  return NS_OK;
}

NS_IMETHODIMP
nsClipboardProxy::SupportsSelectionClipboard(bool *aIsSupported)
{
  *aIsSupported = mClipboardCaps.supportsSelectionClipboard();
  return NS_OK;
}


NS_IMETHODIMP
nsClipboardProxy::SupportsFindClipboard(bool *aIsSupported)
{
  *aIsSupported = mClipboardCaps.supportsFindClipboard();
  return NS_OK;
}

void
nsClipboardProxy::SetCapabilities(const ClipboardCapabilities& aClipboardCaps)
{
  mClipboardCaps = aClipboardCaps;
}