mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
338 lines
9.6 KiB
JavaScript
338 lines
9.6 KiB
JavaScript
/* 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/. */
|
|
|
|
"use strict";
|
|
|
|
module.metadata = {
|
|
"stability": "stable",
|
|
"engines": {
|
|
// TODO Fennec Support 789757
|
|
"Firefox": "*",
|
|
"SeaMonkey": "*",
|
|
"Thunderbird": "*"
|
|
}
|
|
};
|
|
|
|
const { Cc, Ci } = require("chrome");
|
|
const { DataURL } = require("./url");
|
|
const apiUtils = require("./deprecated/api-utils");
|
|
/*
|
|
While these data flavors resemble Internet media types, they do
|
|
no directly map to them.
|
|
*/
|
|
const kAllowableFlavors = [
|
|
"text/unicode",
|
|
"text/html",
|
|
"image/png"
|
|
/* CURRENTLY UNSUPPORTED FLAVORS
|
|
"text/plain",
|
|
"image/jpg",
|
|
"image/jpeg",
|
|
"image/gif",
|
|
"text/x-moz-text-internal",
|
|
"AOLMAIL",
|
|
"application/x-moz-file",
|
|
"text/x-moz-url",
|
|
"text/x-moz-url-data",
|
|
"text/x-moz-url-desc",
|
|
"text/x-moz-url-priv",
|
|
"application/x-moz-nativeimage",
|
|
"application/x-moz-nativehtml",
|
|
"application/x-moz-file-promise-url",
|
|
"application/x-moz-file-promise-dest-filename",
|
|
"application/x-moz-file-promise",
|
|
"application/x-moz-file-promise-dir"
|
|
*/
|
|
];
|
|
|
|
/*
|
|
Aliases for common flavors. Not all flavors will
|
|
get an alias. New aliases must be approved by a
|
|
Jetpack API druid.
|
|
*/
|
|
const kFlavorMap = [
|
|
{ short: "text", long: "text/unicode" },
|
|
{ short: "html", long: "text/html" },
|
|
{ short: "image", long: "image/png" }
|
|
];
|
|
|
|
var clipboardService = Cc["@mozilla.org/widget/clipboard;1"].
|
|
getService(Ci.nsIClipboard);
|
|
|
|
var clipboardHelper = Cc["@mozilla.org/widget/clipboardhelper;1"].
|
|
getService(Ci.nsIClipboardHelper);
|
|
|
|
var imageTools = Cc["@mozilla.org/image/tools;1"].
|
|
getService(Ci.imgITools);
|
|
|
|
exports.set = function(aData, aDataType) {
|
|
|
|
let options = {
|
|
data: aData,
|
|
datatype: aDataType || "text"
|
|
};
|
|
|
|
// If `aDataType` is not given or if it's "image", the data is parsed as
|
|
// data URL to detect a better datatype
|
|
if (aData && (!aDataType || aDataType === "image")) {
|
|
try {
|
|
let dataURL = new DataURL(aData);
|
|
|
|
options.datatype = dataURL.mimeType;
|
|
options.data = dataURL.data;
|
|
}
|
|
catch (e) {
|
|
// Ignore invalid URIs
|
|
if (e.name !== "URIError") {
|
|
throw e;
|
|
}
|
|
}
|
|
}
|
|
|
|
options = apiUtils.validateOptions(options, {
|
|
data: {
|
|
is: ["string"]
|
|
},
|
|
datatype: {
|
|
is: ["string"]
|
|
}
|
|
});
|
|
|
|
let flavor = fromJetpackFlavor(options.datatype);
|
|
|
|
if (!flavor)
|
|
throw new Error("Invalid flavor for " + options.datatype);
|
|
|
|
// Additional checks for using the simple case
|
|
if (flavor == "text/unicode") {
|
|
clipboardHelper.copyString(options.data);
|
|
return true;
|
|
}
|
|
|
|
// Below are the more complex cases where we actually have to work with a
|
|
// nsITransferable object
|
|
var xferable = Cc["@mozilla.org/widget/transferable;1"].
|
|
createInstance(Ci.nsITransferable);
|
|
if (!xferable)
|
|
throw new Error("Couldn't set the clipboard due to an internal error " +
|
|
"(couldn't create a Transferable object).");
|
|
// Bug 769440: Starting with FF16, transferable have to be inited
|
|
if ("init" in xferable)
|
|
xferable.init(null);
|
|
|
|
switch (flavor) {
|
|
case "text/html":
|
|
// add text/html flavor
|
|
let str = Cc["@mozilla.org/supports-string;1"].
|
|
createInstance(Ci.nsISupportsString);
|
|
|
|
str.data = options.data;
|
|
xferable.addDataFlavor(flavor);
|
|
xferable.setTransferData(flavor, str, str.data.length * 2);
|
|
|
|
// add a text/unicode flavor (html converted to plain text)
|
|
str = Cc["@mozilla.org/supports-string;1"].
|
|
createInstance(Ci.nsISupportsString);
|
|
let converter = Cc["@mozilla.org/feed-textconstruct;1"].
|
|
createInstance(Ci.nsIFeedTextConstruct);
|
|
|
|
converter.type = "html";
|
|
converter.text = options.data;
|
|
str.data = converter.plainText();
|
|
xferable.addDataFlavor("text/unicode");
|
|
xferable.setTransferData("text/unicode", str, str.data.length * 2);
|
|
break;
|
|
|
|
// Set images to the clipboard is not straightforward, to have an idea how
|
|
// it works on platform side, see:
|
|
// http://mxr.mozilla.org/mozilla-central/source/content/base/src/nsCopySupport.cpp?rev=7857c5bff017#530
|
|
case "image/png":
|
|
let image = options.data;
|
|
|
|
let container = {};
|
|
|
|
try {
|
|
let input = Cc["@mozilla.org/io/string-input-stream;1"].
|
|
createInstance(Ci.nsIStringInputStream);
|
|
|
|
input.setData(image, image.length);
|
|
|
|
imageTools.decodeImageData(input, flavor, container);
|
|
}
|
|
catch (e) {
|
|
throw new Error("Unable to decode data given in a valid image.");
|
|
}
|
|
|
|
// Store directly the input stream makes the cliboard's data available
|
|
// for Firefox but not to the others application or to the OS. Therefore,
|
|
// a `nsISupportsInterfacePointer` object that reference an `imgIContainer`
|
|
// with the image is needed.
|
|
var imgPtr = Cc["@mozilla.org/supports-interface-pointer;1"].
|
|
createInstance(Ci.nsISupportsInterfacePointer);
|
|
|
|
imgPtr.data = container.value;
|
|
|
|
xferable.addDataFlavor(flavor);
|
|
xferable.setTransferData(flavor, imgPtr, -1);
|
|
|
|
break;
|
|
default:
|
|
throw new Error("Unable to handle the flavor " + flavor + ".");
|
|
}
|
|
|
|
// TODO: Not sure if this will ever actually throw. -zpao
|
|
try {
|
|
clipboardService.setData(
|
|
xferable,
|
|
null,
|
|
clipboardService.kGlobalClipboard
|
|
);
|
|
} catch (e) {
|
|
throw new Error("Couldn't set clipboard data due to an internal error: " + e);
|
|
}
|
|
return true;
|
|
};
|
|
|
|
|
|
exports.get = function(aDataType) {
|
|
let options = {
|
|
datatype: aDataType
|
|
};
|
|
|
|
// Figure out the best data type for the clipboard's data, if omitted
|
|
if (!aDataType) {
|
|
if (~currentFlavors().indexOf("image"))
|
|
options.datatype = "image";
|
|
else
|
|
options.datatype = "text";
|
|
}
|
|
|
|
options = apiUtils.validateOptions(options, {
|
|
datatype: {
|
|
is: ["string"]
|
|
}
|
|
});
|
|
|
|
var xferable = Cc["@mozilla.org/widget/transferable;1"].
|
|
createInstance(Ci.nsITransferable);
|
|
if (!xferable)
|
|
throw new Error("Couldn't set the clipboard due to an internal error " +
|
|
"(couldn't create a Transferable object).");
|
|
// Bug 769440: Starting with FF16, transferable have to be inited
|
|
if ("init" in xferable)
|
|
xferable.init(null);
|
|
|
|
var flavor = fromJetpackFlavor(options.datatype);
|
|
|
|
// Ensure that the user hasn't requested a flavor that we don't support.
|
|
if (!flavor)
|
|
throw new Error("Getting the clipboard with the flavor '" + flavor +
|
|
"' is not supported.");
|
|
|
|
// TODO: Check for matching flavor first? Probably not worth it.
|
|
|
|
xferable.addDataFlavor(flavor);
|
|
// Get the data into our transferable.
|
|
clipboardService.getData(
|
|
xferable,
|
|
clipboardService.kGlobalClipboard
|
|
);
|
|
|
|
var data = {};
|
|
var dataLen = {};
|
|
try {
|
|
xferable.getTransferData(flavor, data, dataLen);
|
|
} catch (e) {
|
|
// Clipboard doesn't contain data in flavor, return null.
|
|
return null;
|
|
}
|
|
|
|
// There's no data available, return.
|
|
if (data.value === null)
|
|
return null;
|
|
|
|
// TODO: Add flavors here as we support more in kAllowableFlavors.
|
|
switch (flavor) {
|
|
case "text/unicode":
|
|
case "text/html":
|
|
data = data.value.QueryInterface(Ci.nsISupportsString).data;
|
|
break;
|
|
case "image/png":
|
|
let dataURL = new DataURL();
|
|
|
|
dataURL.mimeType = flavor;
|
|
dataURL.base64 = true;
|
|
|
|
let image = data.value;
|
|
|
|
// Due to the differences in how images could be stored in the clipboard
|
|
// the checks below are needed. The clipboard could already provide the
|
|
// image as byte streams, but also as pointer, or as image container.
|
|
// If it's not possible obtain a byte stream, the function returns `null`.
|
|
if (image instanceof Ci.nsISupportsInterfacePointer)
|
|
image = image.data;
|
|
|
|
if (image instanceof Ci.imgIContainer)
|
|
image = imageTools.encodeImage(image, flavor);
|
|
|
|
if (image instanceof Ci.nsIInputStream) {
|
|
let binaryStream = Cc["@mozilla.org/binaryinputstream;1"].
|
|
createInstance(Ci.nsIBinaryInputStream);
|
|
|
|
binaryStream.setInputStream(image);
|
|
|
|
dataURL.data = binaryStream.readBytes(binaryStream.available());
|
|
|
|
data = dataURL.toString();
|
|
}
|
|
else
|
|
data = null;
|
|
|
|
break;
|
|
default:
|
|
data = null;
|
|
}
|
|
|
|
return data;
|
|
};
|
|
|
|
function currentFlavors() {
|
|
// Loop over kAllowableFlavors, calling hasDataMatchingFlavors for each.
|
|
// This doesn't seem like the most efficient way, but we can't get
|
|
// confirmation for specific flavors any other way. This is supposed to be
|
|
// an inexpensive call, so performance shouldn't be impacted (much).
|
|
var currentFlavors = [];
|
|
for (var flavor of kAllowableFlavors) {
|
|
var matches = clipboardService.hasDataMatchingFlavors(
|
|
[flavor],
|
|
1,
|
|
clipboardService.kGlobalClipboard
|
|
);
|
|
if (matches)
|
|
currentFlavors.push(toJetpackFlavor(flavor));
|
|
}
|
|
return currentFlavors;
|
|
};
|
|
|
|
Object.defineProperty(exports, "currentFlavors", { get : currentFlavors });
|
|
|
|
// SUPPORT FUNCTIONS ////////////////////////////////////////////////////////
|
|
|
|
function toJetpackFlavor(aFlavor) {
|
|
for (let flavorMap of kFlavorMap)
|
|
if (flavorMap.long == aFlavor)
|
|
return flavorMap.short;
|
|
// Return null in the case where we don't match
|
|
return null;
|
|
}
|
|
|
|
function fromJetpackFlavor(aJetpackFlavor) {
|
|
// TODO: Handle proper flavors better
|
|
for (let flavorMap of kFlavorMap)
|
|
if (flavorMap.short == aJetpackFlavor || flavorMap.long == aJetpackFlavor)
|
|
return flavorMap.long;
|
|
// Return null in the case where we don't match.
|
|
return null;
|
|
}
|