bool
StructuredCloneHelper::WriteCallback(JSContext* aCx,
                                     JSStructuredCloneWriter* aWriter,
                                     JS::Handle<JSObject*> aObj)
{
  if (!mSupportsCloning) {
    return false;
  }

  // See if this is a File/Blob object.
  {
    Blob* blob = nullptr;
    if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob))) {
      BlobImpl* blobImpl = blob->Impl();
      if (JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB,
                             mBlobImplArray.Length())) {
        mBlobImplArray.AppendElement(blobImpl);
        return true;
      }

      return false;
    }
  }

  {
    FileList* fileList = nullptr;
    if (NS_SUCCEEDED(UNWRAP_OBJECT(FileList, aObj, fileList))) {
      // A FileList is serialized writing the X number of elements and the offset
      // from mBlobImplArray. The Read will take X elements from mBlobImplArray
      // starting from the offset.
      if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_FILELIST,
                              fileList->Length()) ||
          !JS_WriteUint32Pair(aWriter, 0,
                              mBlobImplArray.Length())) {
        return false;
      }

      for (uint32_t i = 0; i < fileList->Length(); ++i) {
        mBlobImplArray.AppendElement(fileList->Item(i)->Impl());
      }

      return true;
    }
  }

  // See if this is an ImageBitmap object.
  {
    ImageBitmap* imageBitmap = nullptr;
    if (NS_SUCCEEDED(UNWRAP_OBJECT(ImageBitmap, aObj, imageBitmap))) {
      return ImageBitmap::WriteStructuredClone(aWriter,
                                               GetImages(),
                                               imageBitmap);
    }
  }

  return NS_DOMWriteStructuredClone(aCx, aWriter, aObj, nullptr);
}
示例#2
0
/**
 * Sort the collected list save games prior to displaying it in the save/load gui.
 * @param[in,out] file_list List of save game files found in the directory.
 */
static void SortSaveGameList(FileList &file_list)
{
	uint sort_start = 0;
	uint sort_end = 0;

	/* Directories are always above the files (FIOS_TYPE_DIR)
	 * Drives (A:\ (windows only) are always under the files (FIOS_TYPE_DRIVE)
	 * Only sort savegames/scenarios, not directories
	 */
	for (const FiosItem *item = file_list.Begin(); item != file_list.End(); item++) {
		switch (item->type) {
			case FIOS_TYPE_DIR:    sort_start++; break;
			case FIOS_TYPE_PARENT: sort_start++; break;
			case FIOS_TYPE_DRIVE:  sort_end++;   break;
			default: break;
		}
	}

	uint s_amount = file_list.Length() - sort_start - sort_end;
	QSortT(file_list.Get(sort_start), s_amount, CompareFiosItems);
}
nsresult
nsFileControlFrame::DnDListener::GetBlobImplForWebkitDirectory(nsIDOMFileList* aFileList,
                                                               BlobImpl** aBlobImpl)
{
  *aBlobImpl = nullptr;

  HTMLInputElement* inputElement =
    HTMLInputElement::FromContent(mFrame->GetContent());
  bool webkitDirPicker =
    Preferences::GetBool("dom.webkitBlink.dirPicker.enabled", false) &&
    inputElement->HasAttr(kNameSpaceID_None, nsGkAtoms::webkitdirectory);
  if (!webkitDirPicker) {
    return NS_OK;
  }

  if (!aFileList) {
    return NS_ERROR_FAILURE;
  }

  FileList* files = static_cast<FileList*>(aFileList);
  // webkitdirectory doesn't care about the length of the file list but
  // only about the first item on it.
  uint32_t len = files->Length();
  if (len) {
    File* file = files->Item(0);
    if (file) {
      BlobImpl* impl = file->Impl();
      if (impl && impl->IsDirectory()) {
        RefPtr<BlobImpl> retVal = impl;
        retVal.swap(*aBlobImpl);
        return NS_OK;
      }
    }
  }

  return NS_ERROR_FAILURE;
}
/**
 * This is called when we receive a drop or a dragover.
 */
NS_IMETHODIMP
nsFileControlFrame::DnDListener::HandleEvent(nsIDOMEvent* aEvent)
{
  NS_ASSERTION(mFrame, "We should have been unregistered");

  bool defaultPrevented = false;
  aEvent->GetDefaultPrevented(&defaultPrevented);
  if (defaultPrevented) {
    return NS_OK;
  }

  nsCOMPtr<nsIDOMDragEvent> dragEvent = do_QueryInterface(aEvent);
  if (!dragEvent) {
    return NS_OK;
  }

  nsCOMPtr<nsIDOMDataTransfer> dataTransfer;
  dragEvent->GetDataTransfer(getter_AddRefs(dataTransfer));
  if (!IsValidDropData(dataTransfer)) {
    return NS_OK;
  }


  nsCOMPtr<nsIContent> content = mFrame->GetContent();
  bool supportsMultiple = content && content->HasAttr(kNameSpaceID_None, nsGkAtoms::multiple);
  if (!CanDropTheseFiles(dataTransfer, supportsMultiple)) {
    dataTransfer->SetDropEffect(NS_LITERAL_STRING("none"));
    aEvent->StopPropagation();
    return NS_OK;
  }

  nsAutoString eventType;
  aEvent->GetType(eventType);
  if (eventType.EqualsLiteral("dragover")) {
    // Prevent default if we can accept this drag data
    aEvent->PreventDefault();
    return NS_OK;
  }

  if (eventType.EqualsLiteral("drop")) {
    aEvent->StopPropagation();
    aEvent->PreventDefault();

    NS_ASSERTION(content, "The frame has no content???");

    HTMLInputElement* inputElement = HTMLInputElement::FromContent(content);
    NS_ASSERTION(inputElement, "No input element for this file upload control frame!");

    nsCOMPtr<nsIDOMFileList> fileList;
    dataTransfer->GetFiles(getter_AddRefs(fileList));

    RefPtr<BlobImpl> webkitDir;
    nsresult rv =
      GetBlobImplForWebkitDirectory(fileList, getter_AddRefs(webkitDir));
    NS_ENSURE_SUCCESS(rv, NS_OK);

    nsTArray<OwningFileOrDirectory> array;
    if (webkitDir) {
      AppendBlobImplAsDirectory(array, webkitDir, content);
      inputElement->MozSetDndFilesAndDirectories(array);
    } else {
      bool blinkFileSystemEnabled =
        Preferences::GetBool("dom.webkitBlink.filesystem.enabled", false);
      if (blinkFileSystemEnabled) {
        FileList* files = static_cast<FileList*>(fileList.get());
        if (files) {
          for (uint32_t i = 0; i < files->Length(); ++i) {
            File* file = files->Item(i);
            if (file) {
              if (file->Impl() && file->Impl()->IsDirectory()) {
                AppendBlobImplAsDirectory(array, file->Impl(), content);
              } else {
                OwningFileOrDirectory* element = array.AppendElement();
                element->SetAsFile() = file;
              }
            }
          }
        }
      }

      // This is rather ugly. Pass the directories as Files using SetFiles,
      // but then if blink filesystem API is enabled, it wants
      // FileOrDirectory array.
      inputElement->SetFiles(fileList, true);
      if (blinkFileSystemEnabled) {
        inputElement->UpdateEntries(array);
      }
      nsContentUtils::DispatchTrustedEvent(content->OwnerDoc(), content,
                                           NS_LITERAL_STRING("input"), true,
                                           false);
      nsContentUtils::DispatchTrustedEvent(content->OwnerDoc(), content,
                                           NS_LITERAL_STRING("change"), true,
                                           false);
    }
  }

  return NS_OK;
}