mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 05:37:11 +00:00
import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1266578 - OOM crash if malloc fails in ProcessIncomingMessages(). r=billm (5eca51be20) - Bug 1261340: Don't refer to |ScopedFreePtrTraits| in |RawDBusConnection|, r=shuang (61996db57c) - Bug 1246931: Move |DBusWatcher| into its own files, r=shuang (a7fc4a68c3) - Bug 1246931: Add support for |RefPtr<DBusConnection>| and convert callers, r=shuang (6c07d3e8d3) - Bug 1246931: Add support for |RefPtr<DBusMessage>|, r=shuang (c0ed14cc2b) - Bug 1246931: Add support for |RefPtr<DBusPendingCall>|, r=shuang (a007a15699) - Bug 1246931: Use |DBusConnection| in |DBusWatcher|, r=shuang (11b5eaf535) - Bug 1246931: Add DBus I/O helpers, r=shuang (be249fa65b) - Bug 1264398 - Avoid extra assign() on windows in IPC code (r=jld) (0f31b798a3) - Bug 1261231: Fix shutdown leak in imgLoader::GetInstance. r=gabor (96e5143c41) - Bug 1256999 - Use nsIDocument for ImageCacheKey. r=bz r=seth (cd4765ce34) - Bug 1257101. imgFrame::IsImageComplete says whether we've had pixels decoded to the whole image rect, but it's used to check if the frame is finished decoding. These are different things when the image has more than one progress pass. r=seth (06d619410f) - Bug 1222596. If RasterImage::LookupFrame does (some) sync decoding and encouters an error we don't want to return the surface with an error. r=seth (c4dbc8e0d5) - Bug 763784 - Make VectorImage::GetAnimated check for CSS animations. r=dholbert (4d0e5b88eb) - Bug 1210745 - Update CheckProgressConsistency() to match current ImageLib behavior. r=tn (2317b24fcc) - Bug 1249576. Add crashtest. (485f03120b) - Bug 1251091. Add crashtest. (7e1682a1e6) - Bug 1253362. SVGDocumentWrapper::IsAnimated can be called after SVGDocumentWrapper::DestroyViewer so null check mViewer. r=dholbert (2b4a1c4619) - Bug 1210745. Change image progress asserts to allow transparency to be posted after the size is posted. r=seth (699f3c5496) - Bug 1209780. Use the DrawResult return value of imgIContainer::Draw in the cocoa code. r=seth (abaea789e3) - No Bug - Remove some unnecessary SVGImageContext.h includes and add comments. r=sparky (8232661a23) - cleanup style (de33e4bfa8) - Bug 860857, support custom datatransfer types using a special type, r=smaug,jmathies,mstange (cf7e19deb6) - Bug 1248459 - Don't query out-of-bounds selection; r=masayuki (86c127f143) - Bug 1261671 - ContentEventHandler::ConvertToRootRelativeOffset() should return the root-relative result in the frame's own appUnits, not the root's appUnits in the case when they're different. r=masayuki (2cd72b5ebc) - Bug 1266702 - Clean up formatting in dom/events/DataTransfer.* and mark some methods const, r=jwatt (bd439cdad5)
This commit is contained in:
@@ -91,6 +91,17 @@ public:
|
||||
*/
|
||||
virtual void NotifyAnimationUpdated(Animation& aAnimation);
|
||||
|
||||
/**
|
||||
* Returns true if any CSS animations, CSS transitions or Web animations are
|
||||
* currently associated with this timeline. As soon as an animation is
|
||||
* applied to an element it is associated with the timeline even if it has a
|
||||
* delayed start, so this includes animations that may not be active for some
|
||||
* time.
|
||||
*/
|
||||
bool HasAnimations() const {
|
||||
return !mAnimations.IsEmpty();
|
||||
}
|
||||
|
||||
void RemoveAnimation(Animation* aAnimation);
|
||||
|
||||
protected:
|
||||
|
||||
@@ -113,7 +113,6 @@
|
||||
#include "GLContext.h"
|
||||
#include "GLContextProvider.h"
|
||||
#include "SVGContentUtils.h"
|
||||
#include "SVGImageContext.h"
|
||||
#include "nsIScreenManager.h"
|
||||
#include "nsFilterInstance.h"
|
||||
#include "nsSVGLength2.h"
|
||||
|
||||
@@ -1122,6 +1122,15 @@ ContentEventHandler::OnQuerySelectedText(WidgetQueryContentEvent* aEvent)
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsINode* const startNode = mFirstSelectedRange->GetStartParent();
|
||||
nsINode* const endNode = mFirstSelectedRange->GetEndParent();
|
||||
|
||||
// Make sure the selection is within the root content range.
|
||||
if (!nsContentUtils::ContentIsDescendantOf(startNode, mRootContent) ||
|
||||
!nsContentUtils::ContentIsDescendantOf(endNode, mRootContent)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
NS_ASSERTION(aEvent->mReply.mString.IsEmpty(),
|
||||
"The reply string must be empty");
|
||||
|
||||
@@ -1901,16 +1910,24 @@ ContentEventHandler::ConvertToRootRelativeOffset(nsIFrame* aFrame,
|
||||
{
|
||||
NS_ASSERTION(aFrame, "aFrame must not be null");
|
||||
|
||||
nsPresContext* rootPresContext = aFrame->PresContext()->GetRootPresContext();
|
||||
if (NS_WARN_IF(!rootPresContext)) {
|
||||
nsPresContext* thisPC = aFrame->PresContext();
|
||||
nsPresContext* rootPC = thisPC->GetRootPresContext();
|
||||
if (NS_WARN_IF(!rootPC)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsIFrame* rootFrame = rootPresContext->PresShell()->GetRootFrame();
|
||||
nsIFrame* rootFrame = rootPC->PresShell()->GetRootFrame();
|
||||
if (NS_WARN_IF(!rootFrame)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
aRect = nsLayoutUtils::TransformFrameRectToAncestor(aFrame, aRect, rootFrame);
|
||||
|
||||
// TransformFrameRectToAncestor returned the rect in the ancestor's appUnits,
|
||||
// but we want it in aFrame's units (in case of different full-zoom factors),
|
||||
// so convert back.
|
||||
aRect = aRect.ScaleToOtherAppUnitsRoundOut(rootPC->AppUnitsPerDevPixel(),
|
||||
thisPC->AppUnitsPerDevPixel());
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -264,8 +264,8 @@ protected:
|
||||
nsresult GetStartFrameAndOffset(const nsRange* aRange,
|
||||
nsIFrame*& aFrame,
|
||||
int32_t& aOffsetInFrame);
|
||||
// Convert the frame relative offset to the root frame of the root presContext
|
||||
// relative offset.
|
||||
// Convert the frame relative offset to be relative to the root frame of the
|
||||
// root presContext (but still measured in appUnits of aFrame's presContext).
|
||||
nsresult ConvertToRootRelativeOffset(nsIFrame* aFrame,
|
||||
nsRect& aRect);
|
||||
// Expand aXPOffset to the nearest offset in cluster boundary. aForward is
|
||||
|
||||
+417
-119
@@ -18,6 +18,10 @@
|
||||
#include "nsIClipboard.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIBinaryInputStream.h"
|
||||
#include "nsIBinaryOutputStream.h"
|
||||
#include "nsIStorageStream.h"
|
||||
#include "nsStringStream.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsIScriptObjectPrincipal.h"
|
||||
#include "nsIScriptContext.h"
|
||||
@@ -80,6 +84,12 @@ const char DataTransfer::sEffects[8][9] = {
|
||||
"none", "copy", "move", "copyMove", "link", "copyLink", "linkMove", "all"
|
||||
};
|
||||
|
||||
// Used for custom clipboard types.
|
||||
enum CustomClipboardTypeId {
|
||||
eCustomClipboardTypeId_None,
|
||||
eCustomClipboardTypeId_String
|
||||
};
|
||||
|
||||
DataTransfer::DataTransfer(nsISupports* aParent, EventMessage aEventMessage,
|
||||
bool aIsExternal, int32_t aClipboardType)
|
||||
: mParent(aParent)
|
||||
@@ -198,8 +208,9 @@ DataTransfer::SetDropEffect(const nsAString& aDropEffect)
|
||||
if (aDropEffect.EqualsASCII(sEffects[e])) {
|
||||
// don't allow copyMove
|
||||
if (e != (nsIDragService::DRAGDROP_ACTION_COPY |
|
||||
nsIDragService::DRAGDROP_ACTION_MOVE))
|
||||
nsIDragService::DRAGDROP_ACTION_MOVE)) {
|
||||
mDropEffect = e;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -303,18 +314,20 @@ DataTransfer::GetFileListInternal(ErrorResult& aRv,
|
||||
nsCOMPtr<nsIVariant> variant;
|
||||
aRv = GetDataAtInternal(NS_ConvertUTF8toUTF16(kFileMime), i,
|
||||
aSubjectPrincipal, getter_AddRefs(variant));
|
||||
if (aRv.Failed()) {
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!variant)
|
||||
if (!variant) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> supports;
|
||||
nsresult rv = variant->GetAsISupports(getter_AddRefs(supports));
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> file = do_QueryInterface(supports);
|
||||
|
||||
@@ -357,12 +370,13 @@ NS_IMETHODIMP
|
||||
DataTransfer::GetFiles(nsIDOMFileList** aFileList)
|
||||
{
|
||||
ErrorResult rv;
|
||||
NS_IF_ADDREF(*aFileList = GetFileListInternal(rv, nsContentUtils::GetSystemPrincipal()));
|
||||
NS_IF_ADDREF(*aFileList =
|
||||
GetFileListInternal(rv, nsContentUtils::GetSystemPrincipal()));
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
already_AddRefed<DOMStringList>
|
||||
DataTransfer::Types()
|
||||
DataTransfer::Types() const
|
||||
{
|
||||
ErrorResult rv;
|
||||
return MozTypesAt(0, rv);
|
||||
@@ -385,7 +399,9 @@ DataTransfer::GetData(const nsAString& aFormat, nsAString& aData,
|
||||
aData.Truncate();
|
||||
|
||||
nsCOMPtr<nsIVariant> data;
|
||||
nsresult rv = GetDataAtInternal(aFormat, 0, nsContentUtils::SubjectPrincipal(), getter_AddRefs(data));
|
||||
nsresult rv =
|
||||
GetDataAtInternal(aFormat, 0, nsContentUtils::SubjectPrincipal(),
|
||||
getter_AddRefs(data));
|
||||
if (NS_FAILED(rv)) {
|
||||
if (rv != NS_ERROR_DOM_INDEX_SIZE_ERR) {
|
||||
aRv.Throw(rv);
|
||||
@@ -409,15 +425,18 @@ DataTransfer::GetData(const nsAString& aFormat, nsAString& aData,
|
||||
idx = stringdata.FindChar('\n', lastidx);
|
||||
// lines beginning with # are comments
|
||||
if (stringdata[lastidx] == '#') {
|
||||
if (idx == -1)
|
||||
if (idx == -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (idx == -1)
|
||||
if (idx == -1) {
|
||||
aData.Assign(Substring(stringdata, lastidx));
|
||||
else
|
||||
} else {
|
||||
aData.Assign(Substring(stringdata, lastidx, idx - lastidx));
|
||||
aData = nsContentUtils::TrimWhitespace<nsCRT::IsAsciiSpace>(aData, true);
|
||||
}
|
||||
aData = nsContentUtils::TrimWhitespace<nsCRT::IsAsciiSpace>(aData,
|
||||
true);
|
||||
return;
|
||||
}
|
||||
lastidx = idx + 1;
|
||||
@@ -444,7 +463,8 @@ DataTransfer::SetData(const nsAString& aFormat, const nsAString& aData,
|
||||
RefPtr<nsVariantCC> variant = new nsVariantCC();
|
||||
variant->SetAsAString(aData);
|
||||
|
||||
aRv = SetDataAtInternal(aFormat, variant, 0, nsContentUtils::SubjectPrincipal());
|
||||
aRv = SetDataAtInternal(aFormat, variant, 0,
|
||||
nsContentUtils::SubjectPrincipal());
|
||||
}
|
||||
|
||||
void
|
||||
@@ -582,20 +602,24 @@ DataTransfer::MozTypesAt(uint32_t aIndex, nsISupports** aTypes)
|
||||
}
|
||||
|
||||
nsresult
|
||||
DataTransfer::GetDataAtNoSecurityCheck(const nsAString& aFormat, uint32_t aIndex,
|
||||
DataTransfer::GetDataAtNoSecurityCheck(const nsAString& aFormat,
|
||||
uint32_t aIndex,
|
||||
nsIVariant** aData)
|
||||
{
|
||||
return GetDataAtInternal(aFormat, aIndex, nsContentUtils::GetSystemPrincipal(), aData);
|
||||
return GetDataAtInternal(aFormat, aIndex,
|
||||
nsContentUtils::GetSystemPrincipal(), aData);
|
||||
}
|
||||
|
||||
nsresult
|
||||
DataTransfer::GetDataAtInternal(const nsAString& aFormat, uint32_t aIndex,
|
||||
nsIPrincipal* aSubjectPrincipal, nsIVariant** aData)
|
||||
nsIPrincipal* aSubjectPrincipal,
|
||||
nsIVariant** aData)
|
||||
{
|
||||
*aData = nullptr;
|
||||
|
||||
if (aFormat.IsEmpty())
|
||||
if (aFormat.IsEmpty()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aIndex >= mItems.Length()) {
|
||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||
@@ -608,6 +632,7 @@ DataTransfer::GetDataAtInternal(const nsAString& aFormat, uint32_t aIndex,
|
||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||
}
|
||||
|
||||
|
||||
nsAutoString format;
|
||||
GetRealFormat(aFormat, format);
|
||||
|
||||
@@ -661,7 +686,8 @@ DataTransfer::GetDataAtInternal(const nsAString& aFormat, uint32_t aIndex,
|
||||
MOZ_ASSERT(sp, "This cannot fail on the main thread.");
|
||||
nsIPrincipal* dataPrincipal = sp->GetPrincipal();
|
||||
NS_ENSURE_TRUE(dataPrincipal, NS_ERROR_DOM_SECURITY_ERR);
|
||||
NS_ENSURE_TRUE(aSubjectPrincipal->Subsumes(dataPrincipal), NS_ERROR_DOM_SECURITY_ERR);
|
||||
NS_ENSURE_TRUE(aSubjectPrincipal->Subsumes(dataPrincipal),
|
||||
NS_ERROR_DOM_SECURITY_ERR);
|
||||
}
|
||||
}
|
||||
*aData = formatitem.mData;
|
||||
@@ -680,7 +706,8 @@ DataTransfer::MozGetDataAt(JSContext* aCx, const nsAString& aFormat,
|
||||
mozilla::ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIVariant> data;
|
||||
aRv = GetDataAtInternal(aFormat, aIndex, nsContentUtils::SubjectPrincipal(), getter_AddRefs(data));
|
||||
aRv = GetDataAtInternal(aFormat, aIndex, nsContentUtils::SubjectPrincipal(),
|
||||
getter_AddRefs(data));
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
@@ -699,7 +726,8 @@ DataTransfer::MozGetDataAt(JSContext* aCx, const nsAString& aFormat,
|
||||
|
||||
nsresult
|
||||
DataTransfer::SetDataAtInternal(const nsAString& aFormat, nsIVariant* aData,
|
||||
uint32_t aIndex, nsIPrincipal* aSubjectPrincipal)
|
||||
uint32_t aIndex,
|
||||
nsIPrincipal* aSubjectPrincipal)
|
||||
{
|
||||
if (aFormat.IsEmpty()) {
|
||||
return NS_OK;
|
||||
@@ -722,6 +750,11 @@ DataTransfer::SetDataAtInternal(const nsAString& aFormat, nsIVariant* aData,
|
||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||
}
|
||||
|
||||
// Don't allow the custom type to be assigned.
|
||||
if (aFormat.EqualsLiteral(kCustomTypesMime)) {
|
||||
return NS_ERROR_TYPE_ERR;
|
||||
}
|
||||
|
||||
// Don't allow non-chrome to add non-string or file data. We block file
|
||||
// promises as well which are used internally for drags to the desktop.
|
||||
if (!nsContentUtils::IsSystemPrincipal(aSubjectPrincipal)) {
|
||||
@@ -750,7 +783,8 @@ DataTransfer::MozSetDataAt(JSContext* aCx, const nsAString& aFormat,
|
||||
aRv = nsContentUtils::XPConnect()->JSValToVariant(aCx, aData,
|
||||
getter_AddRefs(data));
|
||||
if (!aRv.Failed()) {
|
||||
aRv = SetDataAtInternal(aFormat, data, aIndex, nsContentUtils::SubjectPrincipal());
|
||||
aRv = SetDataAtInternal(aFormat, data, aIndex,
|
||||
nsContentUtils::SubjectPrincipal());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -806,7 +840,8 @@ DataTransfer::MozClearDataAtHelper(const nsAString& aFormat, uint32_t aIndex,
|
||||
// don't allow removing data that has a stronger principal
|
||||
bool subsumes;
|
||||
if (formatitem.mPrincipal && principal &&
|
||||
(NS_FAILED(principal->Subsumes(formatitem.mPrincipal, &subsumes)) || !subsumes)) {
|
||||
(NS_FAILED(principal->Subsumes(formatitem.mPrincipal, &subsumes)) ||
|
||||
!subsumes)) {
|
||||
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return;
|
||||
}
|
||||
@@ -815,14 +850,16 @@ DataTransfer::MozClearDataAtHelper(const nsAString& aFormat, uint32_t aIndex,
|
||||
|
||||
// if a format was specified, break out. Otherwise, loop around until
|
||||
// all formats have been removed
|
||||
if (!clearall)
|
||||
if (!clearall) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if the last format for an item is removed, remove the entire item
|
||||
if (!item.Length())
|
||||
if (!item.Length()) {
|
||||
mItems.RemoveElementAt(aIndex);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@@ -996,44 +1033,185 @@ DataTransfer::GetTransferable(uint32_t aIndex, nsILoadContext* aLoadContext)
|
||||
}
|
||||
transferable->Init(aLoadContext);
|
||||
|
||||
nsCOMPtr<nsIStorageStream> storageStream;
|
||||
nsCOMPtr<nsIBinaryOutputStream> stream;
|
||||
|
||||
bool added = false;
|
||||
for (uint32_t f = 0; f < count; f++) {
|
||||
const TransferItem& formatitem = item[f];
|
||||
if (!formatitem.mData) { // skip empty items
|
||||
continue;
|
||||
bool handlingCustomFormats = true;
|
||||
uint32_t totalCustomLength = 0;
|
||||
|
||||
const char* knownFormats[] = {
|
||||
kTextMime, kHTMLMime, kNativeHTMLMime, kRTFMime,
|
||||
kURLMime, kURLDataMime, kURLDescriptionMime, kURLPrivateMime,
|
||||
kPNGImageMime, kJPEGImageMime, kGIFImageMime, kNativeImageMime,
|
||||
kFileMime, kFilePromiseMime, kFilePromiseDirectoryMime,
|
||||
kMozTextInternal, kHTMLContext, kHTMLInfo };
|
||||
|
||||
/*
|
||||
* Two passes are made here to iterate over all of the types. First, look for
|
||||
* any types that are not in the list of known types. For this pass,
|
||||
* handlingCustomFormats will be true. Data that corresponds to unknown types
|
||||
* will be pulled out and inserted into a single type (kCustomTypesMime) by
|
||||
* writing the data into a stream.
|
||||
*
|
||||
* The second pass will iterate over the formats looking for known types.
|
||||
* These are added as is. The unknown types are all then inserted as a single
|
||||
* type (kCustomTypesMime) in the same position of the first custom type. This
|
||||
* model is used to maintain the format order as best as possible.
|
||||
*
|
||||
* The format of the kCustomTypesMime type is one or more of the following
|
||||
* stored sequentially:
|
||||
* <32-bit> type (only none or string is supported)
|
||||
* <32-bit> length of format
|
||||
* <wide string> format
|
||||
* <32-bit> length of data
|
||||
* <wide string> data
|
||||
* A type of eCustomClipboardTypeId_None ends the list, without any following
|
||||
* data.
|
||||
*/
|
||||
do {
|
||||
for (uint32_t f = 0; f < count; f++) {
|
||||
const TransferItem& formatitem = item[f];
|
||||
if (!formatitem.mData) { // skip empty items
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the data is of one of the well-known formats, use it directly.
|
||||
bool isCustomFormat = true;
|
||||
for (uint32_t f = 0; f < ArrayLength(knownFormats); f++) {
|
||||
if (formatitem.mFormat.EqualsASCII(knownFormats[f])) {
|
||||
isCustomFormat = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t lengthInBytes;
|
||||
nsCOMPtr<nsISupports> convertedData;
|
||||
|
||||
if (handlingCustomFormats) {
|
||||
if (!ConvertFromVariant(formatitem.mData, getter_AddRefs(convertedData),
|
||||
&lengthInBytes)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// When handling custom types, add the data to the stream if this is a
|
||||
// custom type.
|
||||
if (isCustomFormat) {
|
||||
// If it isn't a string, just ignore it. The dataTransfer is cached in
|
||||
// the drag sesion during drag-and-drop, so non-strings will be
|
||||
// available when dragging locally.
|
||||
nsCOMPtr<nsISupportsString> str(do_QueryInterface(convertedData));
|
||||
if (str) {
|
||||
nsAutoString data;
|
||||
str->GetData(data);
|
||||
|
||||
if (!stream) {
|
||||
// Create a storage stream to write to.
|
||||
NS_NewStorageStream(1024, UINT32_MAX, getter_AddRefs(storageStream));
|
||||
|
||||
nsCOMPtr<nsIOutputStream> outputStream;
|
||||
storageStream->GetOutputStream(0, getter_AddRefs(outputStream));
|
||||
|
||||
stream = do_CreateInstance("@mozilla.org/binaryoutputstream;1");
|
||||
stream->SetOutputStream(outputStream);
|
||||
}
|
||||
|
||||
int32_t formatLength =
|
||||
formatitem.mFormat.Length() * sizeof(nsString::char_type);
|
||||
|
||||
stream->Write32(eCustomClipboardTypeId_String);
|
||||
stream->Write32(formatLength);
|
||||
stream->WriteBytes((const char *)formatitem.mFormat.get(),
|
||||
formatLength);
|
||||
stream->Write32(lengthInBytes);
|
||||
stream->WriteBytes((const char *)data.get(), lengthInBytes);
|
||||
|
||||
// The total size of the stream is the format length, the data
|
||||
// length, two integers to hold the lengths and one integer for the
|
||||
// string flag.
|
||||
totalCustomLength +=
|
||||
formatLength + lengthInBytes + (sizeof(uint32_t) * 3);
|
||||
}
|
||||
}
|
||||
} else if (isCustomFormat && stream) {
|
||||
// This is the second pass of the loop (handlingCustomFormats is false).
|
||||
// When encountering the first custom format, append all of the stream
|
||||
// at this position.
|
||||
|
||||
// Write out a terminator.
|
||||
totalCustomLength += sizeof(uint32_t);
|
||||
stream->Write32(eCustomClipboardTypeId_None);
|
||||
|
||||
nsCOMPtr<nsIInputStream> inputStream;
|
||||
storageStream->NewInputStream(0, getter_AddRefs(inputStream));
|
||||
|
||||
RefPtr<nsStringBuffer> stringBuffer =
|
||||
nsStringBuffer::Alloc(totalCustomLength + 1);
|
||||
|
||||
// Read the data from the string and add a null-terminator as ToString
|
||||
// needs it.
|
||||
uint32_t amountRead;
|
||||
inputStream->Read(static_cast<char*>(stringBuffer->Data()),
|
||||
totalCustomLength, &amountRead);
|
||||
static_cast<char*>(stringBuffer->Data())[amountRead] = 0;
|
||||
|
||||
nsCString str;
|
||||
stringBuffer->ToString(totalCustomLength, str);
|
||||
nsCOMPtr<nsISupportsCString>
|
||||
strSupports(do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID));
|
||||
strSupports->SetData(str);
|
||||
|
||||
nsresult rv = transferable->SetTransferData(kCustomTypesMime,
|
||||
strSupports,
|
||||
totalCustomLength);
|
||||
if (NS_FAILED(rv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
added = true;
|
||||
|
||||
// Clear the stream so it doesn't get used again.
|
||||
stream = nullptr;
|
||||
} else {
|
||||
// This is the second pass of the loop and a known type is encountered.
|
||||
// Add it as is.
|
||||
if (!ConvertFromVariant(formatitem.mData, getter_AddRefs(convertedData),
|
||||
&lengthInBytes)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The underlying drag code uses text/unicode, so use that instead of
|
||||
// text/plain
|
||||
const char* format;
|
||||
NS_ConvertUTF16toUTF8 utf8format(formatitem.mFormat);
|
||||
if (utf8format.EqualsLiteral(kTextMime)) {
|
||||
format = kUnicodeMime;
|
||||
} else {
|
||||
format = utf8format.get();
|
||||
}
|
||||
|
||||
// If a converter is set for a format, set the converter for the
|
||||
// transferable and don't add the item
|
||||
nsCOMPtr<nsIFormatConverter> converter =
|
||||
do_QueryInterface(convertedData);
|
||||
if (converter) {
|
||||
transferable->AddDataFlavor(format);
|
||||
transferable->SetConverter(converter);
|
||||
continue;
|
||||
}
|
||||
|
||||
nsresult rv = transferable->SetTransferData(format, convertedData,
|
||||
lengthInBytes);
|
||||
if (NS_FAILED(rv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t length;
|
||||
nsCOMPtr<nsISupports> convertedData;
|
||||
if (!ConvertFromVariant(formatitem.mData, getter_AddRefs(convertedData), &length)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// the underlying drag code uses text/unicode, so use that instead of text/plain
|
||||
const char* format;
|
||||
NS_ConvertUTF16toUTF8 utf8format(formatitem.mFormat);
|
||||
if (utf8format.EqualsLiteral("text/plain")) {
|
||||
format = kUnicodeMime;
|
||||
} else {
|
||||
format = utf8format.get();
|
||||
}
|
||||
|
||||
// if a converter is set for a format, set the converter for the
|
||||
// transferable and don't add the item
|
||||
nsCOMPtr<nsIFormatConverter> converter = do_QueryInterface(convertedData);
|
||||
if (converter) {
|
||||
transferable->AddDataFlavor(format);
|
||||
transferable->SetConverter(converter);
|
||||
continue;
|
||||
}
|
||||
|
||||
nsresult rv = transferable->SetTransferData(format, convertedData, length);
|
||||
if (NS_FAILED(rv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
added = true;
|
||||
}
|
||||
handlingCustomFormats = !handlingCustomFormats;
|
||||
} while (!handlingCustomFormats);
|
||||
|
||||
// only return the transferable if data was successfully added to it
|
||||
if (added) {
|
||||
@@ -1046,7 +1224,7 @@ DataTransfer::GetTransferable(uint32_t aIndex, nsILoadContext* aLoadContext)
|
||||
bool
|
||||
DataTransfer::ConvertFromVariant(nsIVariant* aVariant,
|
||||
nsISupports** aSupports,
|
||||
uint32_t* aLength)
|
||||
uint32_t* aLength) const
|
||||
{
|
||||
*aSupports = nullptr;
|
||||
*aLength = 0;
|
||||
@@ -1056,8 +1234,9 @@ DataTransfer::ConvertFromVariant(nsIVariant* aVariant,
|
||||
if (type == nsIDataType::VTYPE_INTERFACE ||
|
||||
type == nsIDataType::VTYPE_INTERFACE_IS) {
|
||||
nsCOMPtr<nsISupports> data;
|
||||
if (NS_FAILED(aVariant->GetAsISupports(getter_AddRefs(data))))
|
||||
return false;
|
||||
if (NS_FAILED(aVariant->GetAsISupports(getter_AddRefs(data)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFlavorDataProvider> fdp = do_QueryInterface(data);
|
||||
if (fdp) {
|
||||
@@ -1070,8 +1249,9 @@ DataTransfer::ConvertFromVariant(nsIVariant* aVariant,
|
||||
// wrap the item in an nsISupportsInterfacePointer
|
||||
nsCOMPtr<nsISupportsInterfacePointer> ptrSupports =
|
||||
do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID);
|
||||
if (!ptrSupports)
|
||||
if (!ptrSupports) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ptrSupports->SetData(data);
|
||||
ptrSupports.forget(aSupports);
|
||||
@@ -1085,16 +1265,18 @@ DataTransfer::ConvertFromVariant(nsIVariant* aVariant,
|
||||
char16_t* chrs;
|
||||
uint32_t len = 0;
|
||||
nsresult rv = aVariant->GetAsWStringWithSize(&len, &chrs);
|
||||
if (NS_FAILED(rv))
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoString str;
|
||||
str.Adopt(chrs, len);
|
||||
|
||||
nsCOMPtr<nsISupportsString>
|
||||
strSupports(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID));
|
||||
if (!strSupports)
|
||||
if (!strSupports) {
|
||||
return false;
|
||||
}
|
||||
|
||||
strSupports->SetData(str);
|
||||
|
||||
@@ -1133,8 +1315,10 @@ DataTransfer::SetDataWithPrincipal(const nsAString& aFormat,
|
||||
// don't allow replacing data that has a stronger principal
|
||||
bool subsumes;
|
||||
if (itemformat.mPrincipal && aPrincipal &&
|
||||
(NS_FAILED(aPrincipal->Subsumes(itemformat.mPrincipal, &subsumes)) || !subsumes))
|
||||
(NS_FAILED(aPrincipal->Subsumes(itemformat.mPrincipal,
|
||||
&subsumes)) || !subsumes)) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
itemformat.mPrincipal = aPrincipal;
|
||||
itemformat.mData = aData;
|
||||
@@ -1165,30 +1349,57 @@ DataTransfer::SetDataWithPrincipal(const nsAString& aFormat,
|
||||
}
|
||||
|
||||
void
|
||||
DataTransfer::GetRealFormat(const nsAString& aInFormat, nsAString& aOutFormat)
|
||||
DataTransfer::SetDataWithPrincipalFromOtherProcess(const nsAString& aFormat,
|
||||
nsIVariant* aData,
|
||||
uint32_t aIndex,
|
||||
nsIPrincipal* aPrincipal)
|
||||
{
|
||||
if (aFormat.EqualsLiteral(kCustomTypesMime)) {
|
||||
FillInExternalCustomTypes(aData, aIndex, aPrincipal);
|
||||
} else {
|
||||
SetDataWithPrincipal(aFormat, aData, aIndex, aPrincipal);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DataTransfer::GetRealFormat(const nsAString& aInFormat,
|
||||
nsAString& aOutFormat) const
|
||||
{
|
||||
// treat text/unicode as equivalent to text/plain
|
||||
nsAutoString lowercaseFormat;
|
||||
nsContentUtils::ASCIIToLower(aInFormat, lowercaseFormat);
|
||||
if (lowercaseFormat.EqualsLiteral("text") || lowercaseFormat.EqualsLiteral("text/unicode"))
|
||||
if (lowercaseFormat.EqualsLiteral("text") ||
|
||||
lowercaseFormat.EqualsLiteral("text/unicode")) {
|
||||
aOutFormat.AssignLiteral("text/plain");
|
||||
else if (lowercaseFormat.EqualsLiteral("url"))
|
||||
return;
|
||||
}
|
||||
|
||||
if (lowercaseFormat.EqualsLiteral("url")) {
|
||||
aOutFormat.AssignLiteral("text/uri-list");
|
||||
else
|
||||
aOutFormat.Assign(lowercaseFormat);
|
||||
return;
|
||||
}
|
||||
|
||||
aOutFormat.Assign(lowercaseFormat);
|
||||
}
|
||||
|
||||
void
|
||||
DataTransfer::CacheExternalData(const char* aFormat, uint32_t aIndex, nsIPrincipal* aPrincipal)
|
||||
DataTransfer::CacheExternalData(const char* aFormat, uint32_t aIndex,
|
||||
nsIPrincipal* aPrincipal)
|
||||
{
|
||||
if (strcmp(aFormat, kUnicodeMime) == 0) {
|
||||
SetDataWithPrincipal(NS_LITERAL_STRING("text/plain"), nullptr, aIndex, aPrincipal);
|
||||
} else {
|
||||
if (strcmp(aFormat, kURLDataMime) == 0) {
|
||||
SetDataWithPrincipal(NS_LITERAL_STRING("text/uri-list"), nullptr, aIndex, aPrincipal);
|
||||
}
|
||||
SetDataWithPrincipal(NS_ConvertUTF8toUTF16(aFormat), nullptr, aIndex, aPrincipal);
|
||||
SetDataWithPrincipal(NS_LITERAL_STRING("text/plain"), nullptr, aIndex,
|
||||
aPrincipal);
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(aFormat, kURLDataMime) == 0) {
|
||||
SetDataWithPrincipal(NS_LITERAL_STRING("text/uri-list"), nullptr, aIndex,
|
||||
aPrincipal);
|
||||
return;
|
||||
}
|
||||
|
||||
SetDataWithPrincipal(NS_ConvertUTF8toUTF16(aFormat), nullptr, aIndex,
|
||||
aPrincipal);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1201,8 +1412,9 @@ DataTransfer::CacheExternalDragFormats()
|
||||
// generate it.
|
||||
|
||||
nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
|
||||
if (!dragSession)
|
||||
if (!dragSession) {
|
||||
return;
|
||||
}
|
||||
|
||||
// make sure that the system principal is used for external drags
|
||||
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
|
||||
@@ -1212,11 +1424,19 @@ DataTransfer::CacheExternalDragFormats()
|
||||
// there isn't a way to get a list of the formats that might be available on
|
||||
// all platforms, so just check for the types that can actually be imported
|
||||
// XXXndeakin there are some other formats but those are platform specific.
|
||||
const char* formats[] = { kFileMime, kHTMLMime, kRTFMime, kURLMime, kURLDataMime, kUnicodeMime };
|
||||
const char* formats[] = { kFileMime, kHTMLMime, kRTFMime,
|
||||
kURLMime, kURLDataMime, kUnicodeMime };
|
||||
|
||||
uint32_t count;
|
||||
dragSession->GetNumDropItems(&count);
|
||||
for (uint32_t c = 0; c < count; c++) {
|
||||
// First, check for the special format that holds custom types.
|
||||
bool supported;
|
||||
dragSession->IsDataFlavorSupported(kCustomTypesMime, &supported);
|
||||
if (supported) {
|
||||
FillInExternalCustomTypes(c, sysPrincipal);
|
||||
}
|
||||
|
||||
for (uint32_t f = 0; f < ArrayLength(formats); f++) {
|
||||
// IsDataFlavorSupported doesn't take an index as an argument and just
|
||||
// checks if any of the items support a particular flavor, even though
|
||||
@@ -1243,7 +1463,8 @@ DataTransfer::CacheExternalClipboardFormats()
|
||||
// available on the clipboard. As with CacheExternalDragFormats, the
|
||||
// data will only be retrieved when needed.
|
||||
|
||||
nsCOMPtr<nsIClipboard> clipboard = do_GetService("@mozilla.org/widget/clipboard;1");
|
||||
nsCOMPtr<nsIClipboard> clipboard =
|
||||
do_GetService("@mozilla.org/widget/clipboard;1");
|
||||
if (!clipboard || mClipboardType < 0) {
|
||||
return;
|
||||
}
|
||||
@@ -1253,17 +1474,24 @@ DataTransfer::CacheExternalClipboardFormats()
|
||||
ssm->GetSystemPrincipal(getter_AddRefs(sysPrincipal));
|
||||
|
||||
// there isn't a way to get a list of the formats that might be available on
|
||||
// all platforms, so just check for the types that can actually be imported
|
||||
const char* formats[] = { kFileMime, kHTMLMime, kRTFMime, kURLMime, kURLDataMime, kUnicodeMime };
|
||||
// all platforms, so just check for the types that can actually be imported.
|
||||
// Note that the loop below assumes that kCustomTypesMime will be first.
|
||||
const char* formats[] = { kCustomTypesMime, kFileMime, kHTMLMime, kRTFMime,
|
||||
kURLMime, kURLDataMime, kUnicodeMime };
|
||||
|
||||
for (uint32_t f = 0; f < mozilla::ArrayLength(formats); ++f) {
|
||||
// check each format one at a time
|
||||
bool supported;
|
||||
clipboard->HasDataMatchingFlavors(&(formats[f]), 1, mClipboardType, &supported);
|
||||
clipboard->HasDataMatchingFlavors(&(formats[f]), 1, mClipboardType,
|
||||
&supported);
|
||||
// if the format is supported, add an item to the array with null as
|
||||
// the data. When retrieved, GetRealData will read the data.
|
||||
if (supported) {
|
||||
CacheExternalData(formats[f], 0, sysPrincipal);
|
||||
if (f == 0) {
|
||||
FillInExternalCustomTypes(0, sysPrincipal);
|
||||
} else {
|
||||
CacheExternalData(formats[f], 0, sysPrincipal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1281,17 +1509,19 @@ DataTransfer::FillInExternalData(TransferItem& aItem, uint32_t aIndex)
|
||||
NS_ASSERTION(mEventMessage != eCut && mEventMessage != eCopy,
|
||||
"clipboard event with empty data");
|
||||
|
||||
NS_ConvertUTF16toUTF8 utf8format(aItem.mFormat);
|
||||
const char* format = utf8format.get();
|
||||
if (strcmp(format, "text/plain") == 0)
|
||||
format = kUnicodeMime;
|
||||
else if (strcmp(format, "text/uri-list") == 0)
|
||||
format = kURLDataMime;
|
||||
NS_ConvertUTF16toUTF8 utf8format(aItem.mFormat);
|
||||
const char* format = utf8format.get();
|
||||
if (strcmp(format, "text/plain") == 0) {
|
||||
format = kUnicodeMime;
|
||||
} else if (strcmp(format, "text/uri-list") == 0) {
|
||||
format = kURLDataMime;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsITransferable> trans =
|
||||
do_CreateInstance("@mozilla.org/widget/transferable;1");
|
||||
if (!trans)
|
||||
return;
|
||||
nsCOMPtr<nsITransferable> trans =
|
||||
do_CreateInstance("@mozilla.org/widget/transferable;1");
|
||||
if (!trans) {
|
||||
return;
|
||||
}
|
||||
|
||||
trans->Init(nullptr);
|
||||
trans->AddDataFlavor(format);
|
||||
@@ -1299,7 +1529,8 @@ DataTransfer::FillInExternalData(TransferItem& aItem, uint32_t aIndex)
|
||||
if (mEventMessage == ePaste) {
|
||||
MOZ_ASSERT(aIndex == 0, "index in clipboard must be 0");
|
||||
|
||||
nsCOMPtr<nsIClipboard> clipboard = do_GetService("@mozilla.org/widget/clipboard;1");
|
||||
nsCOMPtr<nsIClipboard> clipboard =
|
||||
do_GetService("@mozilla.org/widget/clipboard;1");
|
||||
if (!clipboard || mClipboardType < 0) {
|
||||
return;
|
||||
}
|
||||
@@ -1321,33 +1552,33 @@ DataTransfer::FillInExternalData(TransferItem& aItem, uint32_t aIndex)
|
||||
dragSession->GetData(trans, aIndex);
|
||||
}
|
||||
|
||||
uint32_t length = 0;
|
||||
nsCOMPtr<nsISupports> data;
|
||||
trans->GetTransferData(format, getter_AddRefs(data), &length);
|
||||
if (!data)
|
||||
return;
|
||||
uint32_t length = 0;
|
||||
nsCOMPtr<nsISupports> data;
|
||||
trans->GetTransferData(format, getter_AddRefs(data), &length);
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
RefPtr<nsVariantCC> variant = new nsVariantCC();
|
||||
RefPtr<nsVariantCC> variant = new nsVariantCC();
|
||||
|
||||
nsCOMPtr<nsISupportsString> supportsstr = do_QueryInterface(data);
|
||||
if (supportsstr) {
|
||||
nsAutoString str;
|
||||
supportsstr->GetData(str);
|
||||
variant->SetAsAString(str);
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsISupportsCString> supportscstr = do_QueryInterface(data);
|
||||
if (supportscstr) {
|
||||
nsAutoCString str;
|
||||
supportscstr->GetData(str);
|
||||
variant->SetAsACString(str);
|
||||
} else {
|
||||
variant->SetAsISupports(data);
|
||||
}
|
||||
}
|
||||
|
||||
aItem.mData = variant;
|
||||
nsCOMPtr<nsISupportsString> supportsstr = do_QueryInterface(data);
|
||||
if (supportsstr) {
|
||||
nsAutoString str;
|
||||
supportsstr->GetData(str);
|
||||
variant->SetAsAString(str);
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsISupportsCString> supportscstr = do_QueryInterface(data);
|
||||
if (supportscstr) {
|
||||
nsAutoCString str;
|
||||
supportscstr->GetData(str);
|
||||
variant->SetAsACString(str);
|
||||
} else {
|
||||
variant->SetAsISupports(data);
|
||||
}
|
||||
}
|
||||
|
||||
aItem.mData = variant;
|
||||
}
|
||||
|
||||
void
|
||||
DataTransfer::FillAllExternalData()
|
||||
@@ -1364,5 +1595,72 @@ DataTransfer::FillAllExternalData()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DataTransfer::FillInExternalCustomTypes(uint32_t aIndex,
|
||||
nsIPrincipal* aPrincipal)
|
||||
{
|
||||
TransferItem item;
|
||||
item.mFormat.AssignLiteral(kCustomTypesMime);
|
||||
|
||||
FillInExternalData(item, aIndex);
|
||||
if (!item.mData) {
|
||||
return;
|
||||
}
|
||||
|
||||
FillInExternalCustomTypes(item.mData, aIndex, aPrincipal);
|
||||
}
|
||||
|
||||
void
|
||||
DataTransfer::FillInExternalCustomTypes(nsIVariant* aData, uint32_t aIndex,
|
||||
nsIPrincipal* aPrincipal)
|
||||
{
|
||||
char* chrs;
|
||||
uint32_t len = 0;
|
||||
nsresult rv = aData->GetAsStringWithSize(&len, &chrs);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoCString str;
|
||||
str.Adopt(chrs, len);
|
||||
|
||||
nsCOMPtr<nsIInputStream> stringStream;
|
||||
NS_NewCStringInputStream(getter_AddRefs(stringStream), str);
|
||||
|
||||
nsCOMPtr<nsIBinaryInputStream> stream =
|
||||
do_CreateInstance("@mozilla.org/binaryinputstream;1");
|
||||
stream->SetInputStream(stringStream);
|
||||
if (!stream) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t type;
|
||||
do {
|
||||
stream->Read32(&type);
|
||||
if (type == eCustomClipboardTypeId_String) {
|
||||
uint32_t formatLength;
|
||||
stream->Read32(&formatLength);
|
||||
char* formatBytes;
|
||||
stream->ReadBytes(formatLength, &formatBytes);
|
||||
nsAutoString format;
|
||||
format.Adopt(reinterpret_cast<char16_t*>(formatBytes),
|
||||
formatLength / sizeof(char16_t));
|
||||
|
||||
uint32_t dataLength;
|
||||
stream->Read32(&dataLength);
|
||||
char* dataBytes;
|
||||
stream->ReadBytes(dataLength, &dataBytes);
|
||||
nsAutoString data;
|
||||
data.Adopt(reinterpret_cast<char16_t*>(dataBytes),
|
||||
dataLength / sizeof(char16_t));
|
||||
|
||||
RefPtr<nsVariantCC> variant = new nsVariantCC();
|
||||
variant->SetAsAString(data);
|
||||
|
||||
SetDataWithPrincipal(format, variant, aIndex, aPrincipal);
|
||||
}
|
||||
} while (type != eCustomClipboardTypeId_None);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
+65
-25
@@ -68,7 +68,10 @@ public:
|
||||
|
||||
friend class mozilla::EventStateManager;
|
||||
|
||||
static DataTransfer* Cast(nsIDOMDataTransfer* aArg) { return static_cast<DataTransfer*>(aArg); }
|
||||
static DataTransfer* Cast(nsIDOMDataTransfer* aArg)
|
||||
{
|
||||
return static_cast<DataTransfer*>(aArg);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
@@ -103,13 +106,15 @@ public:
|
||||
// latter will occur when an external drag occurs, that is, a drag where the
|
||||
// source is another application, or a drag is started by calling the drag
|
||||
// service directly. For clipboard operations, aClipboardType indicates
|
||||
// which clipboard to use, from nsIClipboard, or -1 for non-clipboard operations,
|
||||
// or if access to the system clipboard should not be allowed.
|
||||
// which clipboard to use, from nsIClipboard, or -1 for non-clipboard
|
||||
// operations, or if access to the system clipboard should not be allowed.
|
||||
DataTransfer(nsISupports* aParent, EventMessage aEventMessage,
|
||||
bool aIsExternal, int32_t aClipboardType);
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
nsISupports* GetParentObject()
|
||||
virtual JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
nsISupports* GetParentObject() const
|
||||
{
|
||||
return mParent;
|
||||
}
|
||||
@@ -131,6 +136,7 @@ public:
|
||||
{
|
||||
aDropEffect.AssignASCII(sEffects[mDropEffect]);
|
||||
}
|
||||
|
||||
void GetEffectAllowed(nsString& aEffectAllowed)
|
||||
{
|
||||
if (mEffectAllowed == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED) {
|
||||
@@ -139,23 +145,31 @@ public:
|
||||
aEffectAllowed.AssignASCII(sEffects[mEffectAllowed]);
|
||||
}
|
||||
}
|
||||
|
||||
void SetDragImage(Element& aElement, int32_t aX, int32_t aY,
|
||||
ErrorResult& aRv);
|
||||
already_AddRefed<DOMStringList> Types();
|
||||
|
||||
already_AddRefed<DOMStringList> Types() const;
|
||||
|
||||
void GetData(const nsAString& aFormat, nsAString& aData, ErrorResult& aRv);
|
||||
|
||||
void SetData(const nsAString& aFormat, const nsAString& aData,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void ClearData(const mozilla::dom::Optional<nsAString>& aFormat,
|
||||
mozilla::ErrorResult& aRv);
|
||||
|
||||
FileList* GetFiles(mozilla::ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise> GetFilesAndDirectories(ErrorResult& aRv);
|
||||
|
||||
void AddElement(Element& aElement, mozilla::ErrorResult& aRv);
|
||||
uint32_t MozItemCount()
|
||||
|
||||
uint32_t MozItemCount() const
|
||||
{
|
||||
return mItems.Length();
|
||||
}
|
||||
|
||||
void GetMozCursor(nsString& aCursor)
|
||||
{
|
||||
if (mCursorState) {
|
||||
@@ -164,23 +178,29 @@ public:
|
||||
aCursor.AssignLiteral("auto");
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<DOMStringList> MozTypesAt(uint32_t aIndex,
|
||||
mozilla::ErrorResult& aRv) const;
|
||||
|
||||
void MozClearDataAt(const nsAString& aFormat, uint32_t aIndex,
|
||||
mozilla::ErrorResult& aRv);
|
||||
|
||||
void MozSetDataAt(JSContext* aCx, const nsAString& aFormat,
|
||||
JS::Handle<JS::Value> aData, uint32_t aIndex,
|
||||
mozilla::ErrorResult& aRv);
|
||||
|
||||
void MozGetDataAt(JSContext* aCx, const nsAString& aFormat,
|
||||
uint32_t aIndex, JS::MutableHandle<JS::Value> aRetval,
|
||||
mozilla::ErrorResult& aRv);
|
||||
bool MozUserCancelled()
|
||||
|
||||
bool MozUserCancelled() const
|
||||
{
|
||||
return mUserCancelled;
|
||||
}
|
||||
|
||||
already_AddRefed<nsINode> GetMozSourceNode();
|
||||
|
||||
mozilla::dom::Element* GetDragTarget()
|
||||
mozilla::dom::Element* GetDragTarget() const
|
||||
{
|
||||
return mDragTarget;
|
||||
}
|
||||
@@ -188,24 +208,27 @@ public:
|
||||
nsresult GetDataAtNoSecurityCheck(const nsAString& aFormat, uint32_t aIndex,
|
||||
nsIVariant** aData);
|
||||
|
||||
// a readonly dataTransfer cannot have new data added or existing data removed.
|
||||
// Only the dropEffect and effectAllowed may be modified.
|
||||
// a readonly dataTransfer cannot have new data added or existing data
|
||||
// removed. Only the dropEffect and effectAllowed may be modified.
|
||||
void SetReadOnly() { mReadOnly = true; }
|
||||
|
||||
// converts the data into an array of nsITransferable objects to be used for
|
||||
// drag and drop or clipboard operations.
|
||||
already_AddRefed<nsISupportsArray> GetTransferables(nsIDOMNode* aDragTarget);
|
||||
already_AddRefed<nsISupportsArray> GetTransferables(nsILoadContext* aLoadContext);
|
||||
|
||||
// converts the data for a single item at aIndex into an nsITransferable object.
|
||||
already_AddRefed<nsITransferable> GetTransferable(uint32_t aIndex,
|
||||
nsILoadContext* aLoadContext);
|
||||
already_AddRefed<nsISupportsArray>
|
||||
GetTransferables(nsILoadContext* aLoadContext);
|
||||
|
||||
// converts the data for a single item at aIndex into an nsITransferable
|
||||
// object.
|
||||
already_AddRefed<nsITransferable>
|
||||
GetTransferable(uint32_t aIndex, nsILoadContext* aLoadContext);
|
||||
|
||||
// converts the data in the variant to an nsISupportString if possible or
|
||||
// an nsISupports or null otherwise.
|
||||
bool ConvertFromVariant(nsIVariant* aVariant,
|
||||
nsISupports** aSupports,
|
||||
uint32_t* aLength);
|
||||
nsISupports** aSupports,
|
||||
uint32_t* aLength) const;
|
||||
|
||||
// clears all of the data
|
||||
void ClearAll();
|
||||
@@ -218,8 +241,15 @@ public:
|
||||
uint32_t aIndex,
|
||||
nsIPrincipal* aPrincipal);
|
||||
|
||||
// Variation of SetDataWithPrincipal with handles extracting
|
||||
// kCustomTypesMime data into separate types.
|
||||
void SetDataWithPrincipalFromOtherProcess(const nsAString& aFormat,
|
||||
nsIVariant* aData,
|
||||
uint32_t aIndex,
|
||||
nsIPrincipal* aPrincipal);
|
||||
|
||||
// returns a weak reference to the drag image
|
||||
Element* GetDragImage(int32_t* aX, int32_t* aY)
|
||||
Element* GetDragImage(int32_t* aX, int32_t* aY) const
|
||||
{
|
||||
*aX = mDragImageX;
|
||||
*aY = mDragImageY;
|
||||
@@ -234,11 +264,12 @@ protected:
|
||||
|
||||
// converts some formats used for compatibility in aInFormat into aOutFormat.
|
||||
// Text and text/unicode become text/plain, and URL becomes text/uri-list
|
||||
void GetRealFormat(const nsAString& aInFormat, nsAString& aOutFormat);
|
||||
void GetRealFormat(const nsAString& aInFormat, nsAString& aOutFormat) const;
|
||||
|
||||
// caches text and uri-list data formats that exist in the drag service or
|
||||
// clipboard for retrieval later.
|
||||
void CacheExternalData(const char* aFormat, uint32_t aIndex, nsIPrincipal* aPrincipal);
|
||||
void CacheExternalData(const char* aFormat, uint32_t aIndex,
|
||||
nsIPrincipal* aPrincipal);
|
||||
|
||||
// caches the formats that exist in the drag service that were added by an
|
||||
// external drag
|
||||
@@ -252,21 +283,30 @@ protected:
|
||||
void FillInExternalData(TransferItem& aItem, uint32_t aIndex);
|
||||
|
||||
|
||||
FileList* GetFileListInternal(ErrorResult& aRv, nsIPrincipal* aSubjectPrincipal);
|
||||
FileList* GetFileListInternal(ErrorResult& aRv,
|
||||
nsIPrincipal* aSubjectPrincipal);
|
||||
|
||||
nsresult GetDataAtInternal(const nsAString& aFormat, uint32_t aIndex,
|
||||
nsIPrincipal* aSubjectPrincipal, nsIVariant** aData);
|
||||
nsresult SetDataAtInternal(const nsAString& aFormat, nsIVariant* aData, uint32_t aIndex,
|
||||
nsIPrincipal* aSubjectPrincipal);
|
||||
nsIPrincipal* aSubjectPrincipal,
|
||||
nsIVariant** aData);
|
||||
|
||||
nsresult SetDataAtInternal(const nsAString& aFormat, nsIVariant* aData,
|
||||
uint32_t aIndex, nsIPrincipal* aSubjectPrincipal);
|
||||
|
||||
friend class ContentParent;
|
||||
|
||||
void FillAllExternalData();
|
||||
|
||||
void FillInExternalCustomTypes(uint32_t aIndex, nsIPrincipal* aPrincipal);
|
||||
|
||||
void FillInExternalCustomTypes(nsIVariant* aData, uint32_t aIndex,
|
||||
nsIPrincipal* aPrincipal);
|
||||
|
||||
void MozClearDataAtHelper(const nsAString& aFormat, uint32_t aIndex,
|
||||
mozilla::ErrorResult& aRv);
|
||||
|
||||
nsCOMPtr<nsISupports> mParent;
|
||||
|
||||
|
||||
// the drop effect and effect allowed
|
||||
uint32_t mDropEffect;
|
||||
uint32_t mEffectAllowed;
|
||||
|
||||
@@ -3170,6 +3170,9 @@ 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::TPBlobChild) {
|
||||
BlobChild* blob = static_cast<BlobChild*>(item.data().get_PBlobChild());
|
||||
RefPtr<BlobImpl> blobImpl = blob->GetBlobImpl();
|
||||
@@ -3177,9 +3180,9 @@ ContentChild::RecvInvokeDragSession(nsTArray<IPCDataTransfer>&& aTransfers,
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
dataTransfer->SetDataWithPrincipal(NS_ConvertUTF8toUTF16(item.flavor()),
|
||||
variant, i,
|
||||
nsContentUtils::GetSystemPrincipal());
|
||||
dataTransfer->SetDataWithPrincipalFromOtherProcess(
|
||||
NS_ConvertUTF8toUTF16(item.flavor()), variant, i,
|
||||
nsContentUtils::GetSystemPrincipal());
|
||||
}
|
||||
}
|
||||
session->SetDataTransfer(dataTransfer);
|
||||
|
||||
+16
-13
@@ -3155,24 +3155,27 @@ 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 &&
|
||||
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;
|
||||
} else if (item.data().type() == IPCDataTransferData::TnsCString) {
|
||||
if (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);
|
||||
} else {
|
||||
variant->SetAsACString(item.data().get_nsCString());
|
||||
}
|
||||
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.flavor()),
|
||||
variant, i,
|
||||
nsContentUtils::GetSystemPrincipal());
|
||||
aDataTransfer->SetDataWithPrincipalFromOtherProcess(NS_ConvertUTF8toUTF16(item.flavor()),
|
||||
variant, i,
|
||||
nsContentUtils::GetSystemPrincipal());
|
||||
}
|
||||
}
|
||||
mInitialDataTransferItems.Clear();
|
||||
|
||||
@@ -463,7 +463,7 @@ function test_input_copypaste_dataTransfer_multiple() {
|
||||
ok(exh, "exception occured mozClearDataAt 1");
|
||||
|
||||
cd.setData("text/x-moz-url", "http://www.mozilla.org");
|
||||
cd.mozSetDataAt("text/x-custom", "Custom Text", 0);
|
||||
cd.mozSetDataAt("text/x-custom", "Custom Text with \u0000 null", 0);
|
||||
is(cd.mozItemCount, 1, "mozItemCount after set multiple types");
|
||||
return false;
|
||||
};
|
||||
@@ -489,9 +489,16 @@ function test_input_copypaste_dataTransfer_multiple() {
|
||||
// disabling the following test. Enable this once bug #840101 is fixed.
|
||||
if (navigator.appVersion.indexOf("Android") == -1) {
|
||||
is(cd.getData("text/x-moz-url"), "http://www.mozilla.org", "paste text/x-moz-url multiple types");
|
||||
is(cd.getData("text/x-custom"), "Custom Text with \u0000 null", "paste text/custom multiple types");
|
||||
} else {
|
||||
is(cd.getData("text/x-custom"), "", "paste text/custom multiple types");
|
||||
}
|
||||
// this is empty because only the built-in types are supported at the moment
|
||||
is(cd.getData("text/x-custom"), "", "paste text/custom multiple types");
|
||||
|
||||
is(cd.getData("application/x-moz-custom-clipdata"), "", "application/x-moz-custom-clipdata is not present");
|
||||
|
||||
exh = false;
|
||||
try { cd.setData("application/x-moz-custom-clipdata", "Some Data"); } catch (ex) { exh = true; }
|
||||
ok(exh, "exception occured setData with application/x-moz-custom-clipdata");
|
||||
|
||||
exh = false;
|
||||
try { cd.setData("text/plain", "Text on Paste"); } catch (ex) { exh = true; }
|
||||
|
||||
@@ -143,7 +143,7 @@ FrameAnimator::AdvanceFrame(TimeStamp aTime)
|
||||
// If we aren't, we only display fully-downloaded frames; everything else
|
||||
// gets delayed.
|
||||
bool canDisplay = mDoneDecoding ||
|
||||
(nextFrame && nextFrame->IsImageComplete());
|
||||
(nextFrame && nextFrame->IsFinished());
|
||||
|
||||
if (!canDisplay) {
|
||||
// Uh oh, the frame we want to show is currently being decoded (partial)
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include "nsHostObjectProtocolHandler.h"
|
||||
#include "nsString.h"
|
||||
#include "mozilla/dom/workers/ServiceWorkerManager.h"
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsPrintfCString.h"
|
||||
|
||||
@@ -46,7 +45,7 @@ BlobSerial(ImageURL* aURI)
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
ImageCacheKey::ImageCacheKey(nsIURI* aURI, nsIDOMDocument* aDocument)
|
||||
ImageCacheKey::ImageCacheKey(nsIURI* aURI, nsIDocument* aDocument)
|
||||
: mURI(new ImageURL(aURI))
|
||||
, mControlledDocument(GetControlledDocumentToken(aDocument))
|
||||
, mIsChrome(URISchemeIs(mURI, "chrome"))
|
||||
@@ -60,7 +59,7 @@ ImageCacheKey::ImageCacheKey(nsIURI* aURI, nsIDOMDocument* aDocument)
|
||||
mHash = ComputeHash(mURI, mBlobSerial, mControlledDocument);
|
||||
}
|
||||
|
||||
ImageCacheKey::ImageCacheKey(ImageURL* aURI, nsIDOMDocument* aDocument)
|
||||
ImageCacheKey::ImageCacheKey(ImageURL* aURI, nsIDocument* aDocument)
|
||||
: mURI(aURI)
|
||||
, mControlledDocument(GetControlledDocumentToken(aDocument))
|
||||
, mIsChrome(URISchemeIs(mURI, "chrome"))
|
||||
@@ -141,7 +140,7 @@ ImageCacheKey::ComputeHash(ImageURL* aURI,
|
||||
}
|
||||
|
||||
/* static */ void*
|
||||
ImageCacheKey::GetControlledDocumentToken(nsIDOMDocument* aDocument)
|
||||
ImageCacheKey::GetControlledDocumentToken(nsIDocument* aDocument)
|
||||
{
|
||||
// For non-controlled documents, we just return null. For controlled
|
||||
// documents, we cast the pointer into a void* to avoid dereferencing
|
||||
@@ -149,11 +148,10 @@ ImageCacheKey::GetControlledDocumentToken(nsIDOMDocument* aDocument)
|
||||
void* pointer = nullptr;
|
||||
using dom::workers::ServiceWorkerManager;
|
||||
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDocument);
|
||||
if (doc && swm) {
|
||||
if (aDocument && swm) {
|
||||
ErrorResult rv;
|
||||
if (swm->IsControlled(doc, rv)) {
|
||||
pointer = doc;
|
||||
if (swm->IsControlled(aDocument, rv)) {
|
||||
pointer = aDocument;
|
||||
}
|
||||
}
|
||||
return pointer;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#include "mozilla/Maybe.h"
|
||||
|
||||
class nsIDOMDocument;
|
||||
class nsIDocument;
|
||||
class nsIURI;
|
||||
|
||||
namespace mozilla {
|
||||
@@ -31,8 +31,8 @@ class ImageURL;
|
||||
class ImageCacheKey final
|
||||
{
|
||||
public:
|
||||
ImageCacheKey(nsIURI* aURI, nsIDOMDocument* aDocument);
|
||||
ImageCacheKey(ImageURL* aURI, nsIDOMDocument* aDocument);
|
||||
ImageCacheKey(nsIURI* aURI, nsIDocument* aDocument);
|
||||
ImageCacheKey(ImageURL* aURI, nsIDocument* aDocument);
|
||||
|
||||
ImageCacheKey(const ImageCacheKey& aOther);
|
||||
ImageCacheKey(ImageCacheKey&& aOther);
|
||||
@@ -54,7 +54,7 @@ private:
|
||||
static uint32_t ComputeHash(ImageURL* aURI,
|
||||
const Maybe<uint64_t>& aBlobSerial,
|
||||
void* aControlledDocument);
|
||||
static void* GetControlledDocumentToken(nsIDOMDocument* aDocument);
|
||||
static void* GetControlledDocumentToken(nsIDocument* aDocument);
|
||||
|
||||
RefPtr<ImageURL> mURI;
|
||||
Maybe<uint64_t> mBlobSerial;
|
||||
|
||||
+28
-25
@@ -23,39 +23,43 @@ namespace mozilla {
|
||||
namespace image {
|
||||
|
||||
static void
|
||||
CheckProgressConsistency(Progress aProgress)
|
||||
CheckProgressConsistency(Progress aOldProgress, Progress aNewProgress)
|
||||
{
|
||||
// Check preconditions for every progress bit.
|
||||
|
||||
if (aProgress & FLAG_SIZE_AVAILABLE) {
|
||||
if (aNewProgress & FLAG_SIZE_AVAILABLE) {
|
||||
// No preconditions.
|
||||
}
|
||||
if (aProgress & FLAG_DECODE_COMPLETE) {
|
||||
if (aNewProgress & FLAG_DECODE_COMPLETE) {
|
||||
MOZ_ASSERT(aNewProgress & FLAG_SIZE_AVAILABLE);
|
||||
MOZ_ASSERT(aNewProgress & (FLAG_FRAME_COMPLETE | FLAG_HAS_ERROR));
|
||||
}
|
||||
if (aNewProgress & FLAG_FRAME_COMPLETE) {
|
||||
MOZ_ASSERT(aNewProgress & FLAG_SIZE_AVAILABLE);
|
||||
}
|
||||
if (aNewProgress & FLAG_LOAD_COMPLETE) {
|
||||
MOZ_ASSERT(aNewProgress & (FLAG_SIZE_AVAILABLE | FLAG_HAS_ERROR));
|
||||
}
|
||||
if (aNewProgress & FLAG_ONLOAD_BLOCKED) {
|
||||
// No preconditions.
|
||||
}
|
||||
if (aProgress & FLAG_FRAME_COMPLETE) {
|
||||
// No preconditions.
|
||||
if (aNewProgress & FLAG_ONLOAD_UNBLOCKED) {
|
||||
MOZ_ASSERT(aNewProgress & FLAG_ONLOAD_BLOCKED);
|
||||
MOZ_ASSERT(aNewProgress & (FLAG_SIZE_AVAILABLE | FLAG_HAS_ERROR));
|
||||
}
|
||||
if (aProgress & FLAG_LOAD_COMPLETE) {
|
||||
// No preconditions.
|
||||
if (aNewProgress & FLAG_IS_ANIMATED) {
|
||||
// No preconditions; like FLAG_HAS_TRANSPARENCY, we should normally never
|
||||
// discover this *after* FLAG_SIZE_AVAILABLE, but unfortunately some corrupt
|
||||
// GIFs may fool us.
|
||||
}
|
||||
if (aProgress & FLAG_ONLOAD_BLOCKED) {
|
||||
// No preconditions.
|
||||
if (aNewProgress & FLAG_HAS_TRANSPARENCY) {
|
||||
// XXX We'd like to assert that transparency is only set during metadata
|
||||
// decode but we don't have any way to assert that until bug 1254892 is fixed.
|
||||
}
|
||||
if (aProgress & FLAG_ONLOAD_UNBLOCKED) {
|
||||
MOZ_ASSERT(aProgress & FLAG_ONLOAD_BLOCKED);
|
||||
MOZ_ASSERT(aProgress & (FLAG_SIZE_AVAILABLE | FLAG_HAS_ERROR));
|
||||
if (aNewProgress & FLAG_LAST_PART_COMPLETE) {
|
||||
MOZ_ASSERT(aNewProgress & FLAG_LOAD_COMPLETE);
|
||||
}
|
||||
if (aProgress & FLAG_IS_ANIMATED) {
|
||||
MOZ_ASSERT(aProgress & FLAG_SIZE_AVAILABLE);
|
||||
}
|
||||
if (aProgress & FLAG_HAS_TRANSPARENCY) {
|
||||
MOZ_ASSERT(aProgress & FLAG_SIZE_AVAILABLE);
|
||||
}
|
||||
if (aProgress & FLAG_LAST_PART_COMPLETE) {
|
||||
MOZ_ASSERT(aProgress & FLAG_LOAD_COMPLETE);
|
||||
}
|
||||
if (aProgress & FLAG_HAS_ERROR) {
|
||||
if (aNewProgress & FLAG_HAS_ERROR) {
|
||||
// No preconditions.
|
||||
}
|
||||
}
|
||||
@@ -371,6 +375,8 @@ ProgressTracker::SyncNotifyProgress(Progress aProgress,
|
||||
progress &= ~FLAG_ONLOAD_UNBLOCKED;
|
||||
}
|
||||
|
||||
CheckProgressConsistency(mProgress, mProgress | progress);
|
||||
|
||||
// XXX(seth): Hack to work around the fact that some observers have bugs and
|
||||
// need to get onload blocking notifications multiple times. We should fix
|
||||
// those observers and remove this.
|
||||
@@ -383,8 +389,6 @@ ProgressTracker::SyncNotifyProgress(Progress aProgress,
|
||||
// Apply the changes.
|
||||
mProgress |= progress;
|
||||
|
||||
CheckProgressConsistency(mProgress);
|
||||
|
||||
// Send notifications.
|
||||
mObservers.Read([&](const ObserverTable* aTable) {
|
||||
SyncNotifyInternal(aTable, HasImage(), progress, aInvalidRect);
|
||||
@@ -510,7 +514,6 @@ ProgressTracker::ResetForNewRequest()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mProgress = NoProgress;
|
||||
CheckProgressConsistency(mProgress);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
+13
-4
@@ -375,7 +375,16 @@ RasterImage::LookupFrame(uint32_t aFrameNum,
|
||||
// async decoder that's currently running, the contents of the frame may not
|
||||
// be available yet. Make sure we get everything.
|
||||
if (mHasSourceData && (aFlags & FLAG_SYNC_DECODE)) {
|
||||
result.DrawableRef()->WaitUntilComplete();
|
||||
result.DrawableRef()->WaitUntilFinished();
|
||||
}
|
||||
|
||||
// If we could have done some decoding in this function we need to check if
|
||||
// that decoding encountered an error and hence aborted the surface. We want
|
||||
// to avoid calling IsAborted if we weren't passed any sync decode flag because
|
||||
// IsAborted acquires the monitor for the imgFrame.
|
||||
if (aFlags & (FLAG_SYNC_DECODE | FLAG_SYNC_DECODE_IF_FAST) &&
|
||||
result.DrawableRef()->IsAborted()) {
|
||||
return DrawableFrameRef();
|
||||
}
|
||||
|
||||
return Move(result.DrawableRef());
|
||||
@@ -622,7 +631,7 @@ RasterImage::GetFrameInternal(const IntSize& aSize,
|
||||
frameSurf = CopyFrame(aWhichFrame, aFlags);
|
||||
}
|
||||
|
||||
if (!frameRef->IsImageComplete()) {
|
||||
if (!frameRef->IsFinished()) {
|
||||
return MakePair(DrawResult::INCOMPLETE, Move(frameSurf));
|
||||
}
|
||||
|
||||
@@ -1454,7 +1463,7 @@ RasterImage::DrawInternal(DrawableFrameRef&& aFrameRef,
|
||||
{
|
||||
gfxContextMatrixAutoSaveRestore saveMatrix(aContext);
|
||||
ImageRegion region(aRegion);
|
||||
bool frameIsComplete = aFrameRef->IsImageComplete();
|
||||
bool frameIsFinished = aFrameRef->IsFinished();
|
||||
|
||||
// By now we may have a frame with the requested size. If not, we need to
|
||||
// adjust the drawing parameters accordingly.
|
||||
@@ -1473,7 +1482,7 @@ RasterImage::DrawInternal(DrawableFrameRef&& aFrameRef,
|
||||
RecoverFromInvalidFrames(aSize, aFlags);
|
||||
return DrawResult::TEMPORARY_ERROR;
|
||||
}
|
||||
if (!frameIsComplete) {
|
||||
if (!frameIsFinished) {
|
||||
return DrawResult::INCOMPLETE;
|
||||
}
|
||||
if (couldRedecodeForBetterFrame) {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "SVGDocumentWrapper.h"
|
||||
|
||||
#include "mozilla/dom/DocumentTimeline.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "nsICategoryManager.h"
|
||||
#include "nsIChannel.h"
|
||||
@@ -114,9 +115,28 @@ SVGDocumentWrapper::FlushImageTransformInvalidation()
|
||||
bool
|
||||
SVGDocumentWrapper::IsAnimated()
|
||||
{
|
||||
// Can be called for animated images during shutdown, after we've
|
||||
// already Observe()'d XPCOM shutdown and cleared out our mViewer pointer.
|
||||
if (!mViewer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsIDocument* doc = mViewer->GetDocument();
|
||||
return doc && doc->HasAnimationController() &&
|
||||
doc->GetAnimationController()->HasRegisteredAnimations();
|
||||
if (!doc) {
|
||||
return false;
|
||||
}
|
||||
if (doc->Timeline()->HasAnimations()) {
|
||||
// CSS animations (technically HasAnimations() also checks for CSS
|
||||
// transitions and Web animations but since SVG-as-an-image doesn't run
|
||||
// script they will never run in the document that we wrap).
|
||||
return true;
|
||||
}
|
||||
if (doc->HasAnimationController() &&
|
||||
doc->GetAnimationController()->HasRegisteredAnimations()) {
|
||||
// SMIL animations
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
#include "nsTArray.h"
|
||||
#include "prsystem.h"
|
||||
#include "ShutdownTracker.h"
|
||||
#include "SVGImageContext.h"
|
||||
|
||||
using std::max;
|
||||
using std::min;
|
||||
@@ -181,7 +180,7 @@ public:
|
||||
|
||||
bool IsDecoded() const
|
||||
{
|
||||
return !IsPlaceholder() && mSurface->IsImageComplete();
|
||||
return !IsPlaceholder() && mSurface->IsFinished();
|
||||
}
|
||||
|
||||
// A helper type used by SurfaceCacheImpl::CollectSizeOfSurfaces.
|
||||
|
||||
@@ -99,7 +99,7 @@ nsICODecoder::GetFinalStateFromContainedDecoder()
|
||||
mInvalidRect.UnionRect(mInvalidRect, mContainedDecoder->TakeInvalidRect());
|
||||
mCurrentFrame = mContainedDecoder->GetCurrentFrameRef();
|
||||
|
||||
MOZ_ASSERT(HasError() || !mCurrentFrame || mCurrentFrame->IsImageComplete());
|
||||
MOZ_ASSERT(HasError() || !mCurrentFrame || mCurrentFrame->IsFinished());
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
+28
-15
@@ -140,6 +140,7 @@ imgFrame::imgFrame()
|
||||
, mBlendMethod(BlendMethod::OVER)
|
||||
, mHasNoAlpha(false)
|
||||
, mAborted(false)
|
||||
, mFinished(false)
|
||||
, mOptimizable(false)
|
||||
, mPalettedImageData(nullptr)
|
||||
, mPaletteDepth(0)
|
||||
@@ -160,7 +161,8 @@ imgFrame::~imgFrame()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
MOZ_ASSERT(mAborted || IsImageCompleteInternal());
|
||||
MOZ_ASSERT(mAborted || AreAllPixelsWritten());
|
||||
MOZ_ASSERT(mAborted || mFinished);
|
||||
#endif
|
||||
|
||||
moz_free(mPalettedImageData);
|
||||
@@ -322,7 +324,12 @@ imgFrame::InitWithDrawable(gfxDrawable* aDrawable,
|
||||
|
||||
// If we reach this point, we should regard ourselves as complete.
|
||||
mDecoded = GetRect();
|
||||
MOZ_ASSERT(IsImageComplete());
|
||||
mFinished = true;
|
||||
|
||||
#ifdef DEBUG
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
MOZ_ASSERT(AreAllPixelsWritten());
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -566,7 +573,7 @@ bool imgFrame::Draw(gfxContext* aContext, const ImageRegion& aRegion,
|
||||
mOffset.x);
|
||||
|
||||
bool doPadding = padding != nsIntMargin(0,0,0,0);
|
||||
bool doPartialDecode = !IsImageCompleteInternal();
|
||||
bool doPartialDecode = !AreAllPixelsWritten();
|
||||
|
||||
if (mSinglePixel && !doPadding && !doPartialDecode) {
|
||||
if (mSinglePixelColor.a == 0.0) {
|
||||
@@ -627,11 +634,6 @@ imgFrame::ImageUpdatedInternal(const nsIntRect& aUpdateRect)
|
||||
nsIntRect boundsRect(mOffset, mSize);
|
||||
mDecoded.IntersectRect(mDecoded, boundsRect);
|
||||
|
||||
// If the image is now complete, wake up anyone who's waiting.
|
||||
if (IsImageCompleteInternal()) {
|
||||
mMonitor.NotifyAll();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -652,6 +654,10 @@ imgFrame::Finish(Opacity aFrameOpacity /* = Opacity::SOME_TRANSPARENCY */,
|
||||
mTimeout = aRawTimeout;
|
||||
mBlendMethod = aBlendMethod;
|
||||
ImageUpdatedInternal(GetRect());
|
||||
mFinished = true;
|
||||
|
||||
// The image is now complete, wake up anyone who's waiting.
|
||||
mMonitor.NotifyAll();
|
||||
}
|
||||
|
||||
nsIntRect
|
||||
@@ -835,8 +841,8 @@ imgFrame::UnlockImageData()
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mLockCount > 1 || IsImageCompleteInternal() || mAborted,
|
||||
"Should have marked complete or aborted before unlocking");
|
||||
MOZ_ASSERT(mLockCount > 1 || mFinished || mAborted,
|
||||
"Should have Finish()'d or aborted before unlocking");
|
||||
|
||||
// If we're about to become unlocked, we don't need to hold on to our data
|
||||
// surface anymore. (But we don't need to do anything for paletted images,
|
||||
@@ -993,20 +999,27 @@ imgFrame::Abort()
|
||||
}
|
||||
|
||||
bool
|
||||
imgFrame::IsImageComplete() const
|
||||
imgFrame::IsAborted() const
|
||||
{
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
return IsImageCompleteInternal();
|
||||
return mAborted;
|
||||
}
|
||||
|
||||
bool
|
||||
imgFrame::IsFinished() const
|
||||
{
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
return mFinished;
|
||||
}
|
||||
|
||||
void
|
||||
imgFrame::WaitUntilComplete() const
|
||||
imgFrame::WaitUntilFinished() const
|
||||
{
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
|
||||
while (true) {
|
||||
// Return if we're aborted or complete.
|
||||
if (mAborted || IsImageCompleteInternal()) {
|
||||
if (mAborted || mFinished) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1016,7 +1029,7 @@ imgFrame::WaitUntilComplete() const
|
||||
}
|
||||
|
||||
bool
|
||||
imgFrame::IsImageCompleteInternal() const
|
||||
imgFrame::AreAllPixelsWritten() const
|
||||
{
|
||||
mMonitor.AssertCurrentThreadOwns();
|
||||
return mDecoded.IsEqualInterior(nsIntRect(mOffset.x, mOffset.y,
|
||||
|
||||
+9
-3
@@ -209,10 +209,15 @@ public:
|
||||
*/
|
||||
void Abort();
|
||||
|
||||
/**
|
||||
* Returns true if this imgFrame has been aborted.
|
||||
*/
|
||||
bool IsAborted() const;
|
||||
|
||||
/**
|
||||
* Returns true if this imgFrame is completely decoded.
|
||||
*/
|
||||
bool IsImageComplete() const;
|
||||
bool IsFinished() const;
|
||||
|
||||
/**
|
||||
* Blocks until this imgFrame is either completely decoded, or is marked as
|
||||
@@ -222,7 +227,7 @@ public:
|
||||
* careful in your use of this method to avoid excessive main thread jank or
|
||||
* deadlock.
|
||||
*/
|
||||
void WaitUntilComplete() const;
|
||||
void WaitUntilFinished() const;
|
||||
|
||||
/**
|
||||
* Returns the number of bytes per pixel this imgFrame requires. This is a
|
||||
@@ -278,7 +283,7 @@ private: // methods
|
||||
|
||||
void AssertImageDataLocked() const;
|
||||
|
||||
bool IsImageCompleteInternal() const;
|
||||
bool AreAllPixelsWritten() const;
|
||||
nsresult ImageUpdatedInternal(const nsIntRect& aUpdateRect);
|
||||
void GetImageDataInternal(uint8_t** aData, uint32_t* length) const;
|
||||
uint32_t GetImageBytesPerRow() const;
|
||||
@@ -342,6 +347,7 @@ private: // data
|
||||
|
||||
bool mHasNoAlpha;
|
||||
bool mAborted;
|
||||
bool mFinished;
|
||||
bool mOptimizable;
|
||||
|
||||
|
||||
|
||||
+6
-6
@@ -1156,7 +1156,7 @@ imgLoader*
|
||||
imgLoader::Singleton()
|
||||
{
|
||||
if (!gSingleton) {
|
||||
gSingleton = imgLoader::Create();
|
||||
gSingleton = imgLoader::Create().take();
|
||||
}
|
||||
return gSingleton;
|
||||
}
|
||||
@@ -1165,7 +1165,7 @@ imgLoader*
|
||||
imgLoader::PBSingleton()
|
||||
{
|
||||
if (!gPBSingleton) {
|
||||
gPBSingleton = imgLoader::Create();
|
||||
gPBSingleton = imgLoader::Create().take();
|
||||
gPBSingleton->RespectPrivacyNotifications();
|
||||
}
|
||||
return gPBSingleton;
|
||||
@@ -1403,11 +1403,12 @@ imgLoader::ClearCache(bool chrome)
|
||||
|
||||
NS_IMETHODIMP
|
||||
imgLoader::FindEntryProperties(nsIURI* uri,
|
||||
nsIDOMDocument* doc,
|
||||
nsIDOMDocument* aDOMDoc,
|
||||
nsIProperties** _retval)
|
||||
{
|
||||
*_retval = nullptr;
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDOMDoc);
|
||||
ImageCacheKey key(uri, doc);
|
||||
imgCacheTable& cache = GetCache(key);
|
||||
|
||||
@@ -2186,8 +2187,7 @@ imgLoader::LoadImage(nsIURI* aURI,
|
||||
// XXX For now ignore aCacheKey. We will need it in the future
|
||||
// for correctly dealing with image load requests that are a result
|
||||
// of post data.
|
||||
nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(aLoadingDocument);
|
||||
ImageCacheKey key(aURI, doc);
|
||||
ImageCacheKey key(aURI, aLoadingDocument);
|
||||
imgCacheTable& cache = GetCache(key);
|
||||
|
||||
if (cache.Get(key, getter_AddRefs(entry)) && entry) {
|
||||
@@ -2411,7 +2411,7 @@ imgLoader::LoadImageWithChannel(nsIChannel* channel,
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
channel->GetURI(getter_AddRefs(uri));
|
||||
nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(aCX);
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aCX);
|
||||
ImageCacheKey key(uri, doc);
|
||||
|
||||
nsLoadFlags requestFlags = nsIRequest::LOAD_NORMAL;
|
||||
|
||||
+4
-4
@@ -228,18 +228,18 @@ public:
|
||||
|
||||
nsresult Init();
|
||||
|
||||
static imgLoader* Create()
|
||||
static already_AddRefed<imgLoader>
|
||||
Create()
|
||||
{
|
||||
// Unfortunately, we rely on XPCOM module init happening
|
||||
// before imgLoader creation. For now, it's easier
|
||||
// to just call CallCreateInstance() which will init
|
||||
// the image module instead of calling new imgLoader
|
||||
// directly.
|
||||
imgILoader* loader;
|
||||
CallCreateInstance("@mozilla.org/image/loader;1", &loader);
|
||||
nsCOMPtr<imgILoader> loader = do_CreateInstance("@mozilla.org/image/loader;1");
|
||||
// There's only one imgLoader implementation so we
|
||||
// can safely cast to it.
|
||||
return static_cast<imgLoader*>(loader);
|
||||
return loader.forget().downcast<imgLoader>();
|
||||
}
|
||||
|
||||
static already_AddRefed<imgLoader>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 23 B |
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,51 @@
|
||||
<!doctype html>
|
||||
<html class="reftest-wait">
|
||||
<head>
|
||||
<script type="text/javascript">
|
||||
var gl;
|
||||
|
||||
function start() {
|
||||
var canvas = document.getElementById("glcanvas");
|
||||
gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
|
||||
|
||||
if (gl) {
|
||||
initTextures();
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
function initTextures() {
|
||||
var cubeTexture = gl.createTexture();
|
||||
var cubeImage = document.getElementById("i");
|
||||
cubeImage.onload = function() { handleTextureLoaded(cubeImage, cubeTexture); }
|
||||
cubeImage.onerror = function() { finish(); }
|
||||
cubeImage.src = "1251091-1.png";
|
||||
}
|
||||
|
||||
function handleTextureLoaded(image, texture) {
|
||||
gl.bindTexture(gl.TEXTURE_2D, texture);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
|
||||
gl.generateMipmap(gl.TEXTURE_2D);
|
||||
gl.bindTexture(gl.TEXTURE_2D, null);
|
||||
setTimeout(showit,0);
|
||||
}
|
||||
|
||||
function showit() {
|
||||
document.getElementById("i").style.display = "";
|
||||
finish();
|
||||
}
|
||||
|
||||
function finish() {
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="start()">
|
||||
<canvas id="glcanvas" width="640" height="480"></canvas>
|
||||
<img id="i" style="display: none;">
|
||||
</body>
|
||||
</html>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 93 KiB |
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div style="content: url(data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20style%3D%22background%3A%20url%28data%3Aimage%2Fsvg%2Bxml%2C%253Csvg%2520xmlns%253D%2522http%253A%252F%252Fwww.w3.org%252F2000%252Fsvg%2522%253E%253C%252Fsvg%253E%29%22%3E%3C%2Fsvg%3E%0D%0A)"></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -13,12 +13,18 @@ load 844403-1.html
|
||||
load 856616.gif
|
||||
skip-if(B2G) load 944353.jpg
|
||||
load 1205923-1.html
|
||||
# Ensure we handle detecting that an image is animated, then failing to decode
|
||||
# it. (See bug 1210745.)
|
||||
load 1210745-1.gif
|
||||
load 1212954-1.svg
|
||||
load 1235605.gif
|
||||
load 1241728-1.html
|
||||
load 1241729-1.html
|
||||
load 1242093-1.html
|
||||
load 1242778-1.png
|
||||
load 1249576-1.png
|
||||
load 1251091-1.html
|
||||
load 1253362-1.html
|
||||
load colormap-range.gif
|
||||
HTTP load delayedframe.sjs # A 3-frame animated GIF with an inordinate delay between the second and third frame
|
||||
|
||||
|
||||
@@ -447,7 +447,7 @@ bool Channel::ChannelImpl::ProcessIncomingMessages() {
|
||||
overflowp = message_tail = input_overflow_buf_.data();
|
||||
end = overflowp + input_overflow_buf_.size();
|
||||
} else {
|
||||
buf = (char*)malloc(len);
|
||||
buf = (char*)moz_xmalloc(len);
|
||||
memcpy(buf, p, len);
|
||||
}
|
||||
Message m(buf, len, Message::OWNS);
|
||||
|
||||
@@ -403,7 +403,7 @@ bool Channel::ChannelImpl::ProcessIncomingMessages(
|
||||
message_tail = input_overflow_buf_.data();
|
||||
end = message_tail + input_overflow_buf_.size();
|
||||
} else {
|
||||
buf = (char*)malloc(len);
|
||||
buf = (char*)moz_xmalloc(len);
|
||||
memcpy(buf, p, len);
|
||||
}
|
||||
Message m(buf, len, Message::OWNS);
|
||||
@@ -435,7 +435,11 @@ bool Channel::ChannelImpl::ProcessIncomingMessages(
|
||||
break;
|
||||
}
|
||||
}
|
||||
input_overflow_buf_.assign(p, end - p);
|
||||
if (p != input_overflow_buf_.data()) {
|
||||
// Don't assign unless we have to since this will throw away any memory we
|
||||
// might have reserved.
|
||||
input_overflow_buf_.assign(p, end - p);
|
||||
}
|
||||
|
||||
bytes_read = 0; // Get more data.
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_ipc_DBusConnectionRefPtr_h
|
||||
#define mozilla_ipc_DBusConnectionRefPtr_h
|
||||
|
||||
#include <dbus/dbus.h>
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
template<>
|
||||
struct RefPtrTraits<DBusConnection>
|
||||
{
|
||||
static void AddRef(DBusConnection* aConnection) {
|
||||
MOZ_ASSERT(aConnection);
|
||||
dbus_connection_ref(aConnection);
|
||||
}
|
||||
static void Release(DBusConnection* aConnection) {
|
||||
MOZ_ASSERT(aConnection);
|
||||
dbus_connection_unref(aConnection);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_ipc_DBusConnectionRefPtr_h
|
||||
@@ -0,0 +1,246 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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 "DBusHelpers.h"
|
||||
#include "mozilla/ipc/DBusMessageRefPtr.h"
|
||||
#include "mozilla/ipc/DBusPendingCallRefPtr.h"
|
||||
#include "mozilla/ipc/DBusWatcher.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
#undef CHROMIUM_LOG
|
||||
#if defined(MOZ_WIDGET_GONK)
|
||||
#include <android/log.h>
|
||||
#define CHROMIUM_LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk", args);
|
||||
#else
|
||||
#define CHROMIUM_LOG(args...) printf(args);
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
//
|
||||
// DBus I/O
|
||||
//
|
||||
|
||||
namespace {
|
||||
|
||||
class Notification final
|
||||
{
|
||||
public:
|
||||
Notification(DBusReplyCallback aCallback, void* aData)
|
||||
: mCallback(aCallback)
|
||||
, mData(aData)
|
||||
{ }
|
||||
|
||||
// Callback function for DBus replies. Only run it on I/O thread.
|
||||
//
|
||||
static void Handle(DBusPendingCall* aCall, void* aData)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
RefPtr<DBusPendingCall> call = already_AddRefed<DBusPendingCall>(aCall);
|
||||
|
||||
UniquePtr<Notification> ntfn(static_cast<Notification*>(aData));
|
||||
|
||||
RefPtr<DBusMessage> reply = already_AddRefed<DBusMessage>(
|
||||
dbus_pending_call_steal_reply(call));
|
||||
|
||||
// The reply can be null if the timeout has been reached.
|
||||
if (reply) {
|
||||
ntfn->RunCallback(reply);
|
||||
}
|
||||
|
||||
dbus_pending_call_cancel(call);
|
||||
}
|
||||
|
||||
private:
|
||||
void RunCallback(DBusMessage* aMessage)
|
||||
{
|
||||
if (mCallback) {
|
||||
mCallback(aMessage, mData);
|
||||
}
|
||||
}
|
||||
|
||||
DBusReplyCallback mCallback;
|
||||
void* mData;
|
||||
};
|
||||
|
||||
static already_AddRefed<DBusMessage>
|
||||
BuildDBusMessage(const char* aDestination,
|
||||
const char* aPath,
|
||||
const char* aIntf,
|
||||
const char* aFunc,
|
||||
int aFirstArgType,
|
||||
va_list aArgs)
|
||||
{
|
||||
RefPtr<DBusMessage> msg = already_AddRefed<DBusMessage>(
|
||||
dbus_message_new_method_call(aDestination, aPath, aIntf, aFunc));
|
||||
|
||||
if (!msg) {
|
||||
CHROMIUM_LOG("dbus_message_new_method_call failed");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto success = dbus_message_append_args_valist(msg, aFirstArgType, aArgs);
|
||||
|
||||
if (!success) {
|
||||
CHROMIUM_LOG("dbus_message_append_args_valist failed");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return msg.forget();
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
nsresult
|
||||
DBusWatchConnection(DBusConnection* aConnection)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aConnection);
|
||||
|
||||
auto success =
|
||||
dbus_connection_set_watch_functions(aConnection,
|
||||
DBusWatcher::AddWatchFunction,
|
||||
DBusWatcher::RemoveWatchFunction,
|
||||
DBusWatcher::ToggleWatchFunction,
|
||||
aConnection, nullptr);
|
||||
if (!success) {
|
||||
CHROMIUM_LOG("dbus_connection_set_watch_functions failed");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
DBusUnwatchConnection(DBusConnection* aConnection)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aConnection);
|
||||
|
||||
auto success = dbus_connection_set_watch_functions(aConnection,
|
||||
nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr);
|
||||
if (!success) {
|
||||
CHROMIUM_LOG("dbus_connection_set_watch_functions failed");
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
DBusSendMessage(DBusConnection* aConnection, DBusMessage* aMessage)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aConnection);
|
||||
MOZ_ASSERT(aMessage);
|
||||
|
||||
auto success = dbus_connection_send(aConnection, aMessage, nullptr);
|
||||
|
||||
if (!success) {
|
||||
CHROMIUM_LOG("dbus_connection_send failed");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
DBusSendMessageWithReply(DBusConnection* aConnection,
|
||||
DBusReplyCallback aCallback, void* aData,
|
||||
int aTimeout,
|
||||
DBusMessage* aMessage)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aConnection);
|
||||
MOZ_ASSERT(aMessage);
|
||||
|
||||
UniquePtr<Notification> ntfn = MakeUnique<Notification>(aCallback, aData);
|
||||
|
||||
auto call = static_cast<DBusPendingCall*>(nullptr);
|
||||
|
||||
auto success = dbus_connection_send_with_reply(aConnection,
|
||||
aMessage,
|
||||
&call,
|
||||
aTimeout);
|
||||
if (!success) {
|
||||
CHROMIUM_LOG("dbus_connection_send_with_reply failed");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
success = dbus_pending_call_set_notify(call, Notification::Handle,
|
||||
ntfn.get(), nullptr);
|
||||
if (!success) {
|
||||
CHROMIUM_LOG("dbus_pending_call_set_notify failed");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
Unused << ntfn.release(); // Picked up in |Notification::Handle|
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
DBusSendMessageWithReply(DBusConnection* aConnection,
|
||||
DBusReplyCallback aCallback,
|
||||
void* aData,
|
||||
int aTimeout,
|
||||
const char* aDestination,
|
||||
const char* aPath,
|
||||
const char* aIntf,
|
||||
const char* aFunc,
|
||||
int aFirstArgType,
|
||||
va_list aArgs)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aConnection);
|
||||
|
||||
RefPtr<DBusMessage> msg =
|
||||
BuildDBusMessage(aDestination, aPath, aIntf, aFunc, aFirstArgType, aArgs);
|
||||
|
||||
if (!msg) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return DBusSendMessageWithReply(aConnection, aCallback, aData, aTimeout, msg);
|
||||
}
|
||||
|
||||
nsresult
|
||||
DBusSendMessageWithReply(DBusConnection* aConnection,
|
||||
DBusReplyCallback aCallback,
|
||||
void* aData,
|
||||
int aTimeout,
|
||||
const char* aDestination,
|
||||
const char* aPath,
|
||||
const char* aIntf,
|
||||
const char* aFunc,
|
||||
int aFirstArgType,
|
||||
...)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aConnection);
|
||||
|
||||
va_list args;
|
||||
va_start(args, aFirstArgType);
|
||||
|
||||
auto rv = DBusSendMessageWithReply(aConnection,
|
||||
aCallback, aData,
|
||||
aTimeout,
|
||||
aDestination, aPath, aIntf, aFunc,
|
||||
aFirstArgType, args);
|
||||
va_end(args);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_ipc_DBusHelpers_h
|
||||
#define mozilla_ipc_DBusHelpers_h
|
||||
|
||||
#include <dbus/dbus.h>
|
||||
#include <stdarg.h>
|
||||
#include "nsError.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
//
|
||||
// DBus I/O
|
||||
//
|
||||
|
||||
typedef void (*DBusReplyCallback)(DBusMessage*, void*);
|
||||
|
||||
nsresult
|
||||
DBusWatchConnection(DBusConnection* aConnection);
|
||||
|
||||
void
|
||||
DBusUnwatchConnection(DBusConnection* aConnection);
|
||||
|
||||
nsresult
|
||||
DBusSendMessage(DBusConnection* aConnection, DBusMessage* aMessage);
|
||||
|
||||
nsresult
|
||||
DBusSendMessageWithReply(DBusConnection* aConnection,
|
||||
DBusReplyCallback aCallback, void* aData,
|
||||
int aTimeout,
|
||||
DBusMessage* aMessage);
|
||||
|
||||
nsresult
|
||||
DBusSendMessageWithReply(DBusConnection* aConnection,
|
||||
DBusReplyCallback aCallback,
|
||||
void* aData,
|
||||
int aTimeout,
|
||||
const char* aDestination,
|
||||
const char* aPath,
|
||||
const char* aIntf,
|
||||
const char* aFunc,
|
||||
int aFirstArgType,
|
||||
va_list aArgs);
|
||||
|
||||
nsresult
|
||||
DBusSendMessageWithReply(DBusConnection* aConnection,
|
||||
DBusReplyCallback aCallback,
|
||||
void* aData,
|
||||
int aTimeout,
|
||||
const char* aDestination,
|
||||
const char* aPath,
|
||||
const char* aIntf,
|
||||
const char* aFunc,
|
||||
int aFirstArgType,
|
||||
...);
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_ipc_DBusHelpers_h
|
||||
@@ -0,0 +1,30 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_ipc_DBusMessageRefPtr_h
|
||||
#define mozilla_ipc_DBusMessageRefPtr_h
|
||||
|
||||
#include <dbus/dbus.h>
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
template<>
|
||||
struct RefPtrTraits<DBusMessage>
|
||||
{
|
||||
static void AddRef(DBusMessage* aMessage) {
|
||||
MOZ_ASSERT(aMessage);
|
||||
dbus_message_ref(aMessage);
|
||||
}
|
||||
static void Release(DBusMessage* aMessage) {
|
||||
MOZ_ASSERT(aMessage);
|
||||
dbus_message_unref(aMessage);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_ipc_DBusMessageRefPtr_h
|
||||
@@ -0,0 +1,30 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_ipc_DBusPendingCallRefPtr_h
|
||||
#define mozilla_ipc_DBusPendingCallRefPtr_h
|
||||
|
||||
#include <dbus/dbus.h>
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
template<>
|
||||
struct RefPtrTraits<DBusPendingCall>
|
||||
{
|
||||
static void AddRef(DBusPendingCall* aPendingCall) {
|
||||
MOZ_ASSERT(aPendingCall);
|
||||
dbus_pending_call_ref(aPendingCall);
|
||||
}
|
||||
static void Release(DBusPendingCall* aPendingCall) {
|
||||
MOZ_ASSERT(aPendingCall);
|
||||
dbus_pending_call_unref(aPendingCall);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_ipc_DBusPendingCallRefPtr_h
|
||||
@@ -0,0 +1,149 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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 "DBusWatcher.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
DBusWatcher::DBusWatcher(DBusConnection* aConnection, DBusWatch* aWatch)
|
||||
: mConnection(aConnection)
|
||||
, mWatch(aWatch)
|
||||
{
|
||||
MOZ_ASSERT(mConnection);
|
||||
MOZ_ASSERT(mWatch);
|
||||
}
|
||||
|
||||
DBusWatcher::~DBusWatcher()
|
||||
{ }
|
||||
|
||||
DBusConnection*
|
||||
DBusWatcher::GetConnection()
|
||||
{
|
||||
return mConnection;
|
||||
}
|
||||
|
||||
void
|
||||
DBusWatcher::StartWatching()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
auto flags = dbus_watch_get_flags(mWatch);
|
||||
|
||||
if (!(flags & (DBUS_WATCH_READABLE|DBUS_WATCH_WRITABLE))) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto ioLoop = MessageLoopForIO::current();
|
||||
|
||||
auto fd = dbus_watch_get_unix_fd(mWatch);
|
||||
|
||||
if (flags & DBUS_WATCH_READABLE) {
|
||||
ioLoop->WatchFileDescriptor(fd, true, MessageLoopForIO::WATCH_READ,
|
||||
&mReadWatcher, this);
|
||||
}
|
||||
if (flags & DBUS_WATCH_WRITABLE) {
|
||||
ioLoop->WatchFileDescriptor(fd, true, MessageLoopForIO::WATCH_WRITE,
|
||||
&mWriteWatcher, this);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DBusWatcher::StopWatching()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
auto flags = dbus_watch_get_flags(mWatch);
|
||||
|
||||
if (flags & DBUS_WATCH_READABLE) {
|
||||
mReadWatcher.StopWatchingFileDescriptor();
|
||||
}
|
||||
if (flags & DBUS_WATCH_WRITABLE) {
|
||||
mWriteWatcher.StopWatchingFileDescriptor();
|
||||
}
|
||||
}
|
||||
|
||||
// DBus utility functions, used as function pointers in DBus setup
|
||||
|
||||
void
|
||||
DBusWatcher::FreeFunction(void* aData)
|
||||
{
|
||||
UniquePtr<DBusWatcher> watcher(static_cast<DBusWatcher*>(aData));
|
||||
}
|
||||
|
||||
dbus_bool_t
|
||||
DBusWatcher::AddWatchFunction(DBusWatch* aWatch, void* aData)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
auto connection = static_cast<DBusConnection*>(aData);
|
||||
|
||||
UniquePtr<DBusWatcher> dbusWatcher =
|
||||
MakeUnique<DBusWatcher>(connection, aWatch);
|
||||
|
||||
dbus_watch_set_data(aWatch, dbusWatcher.get(), DBusWatcher::FreeFunction);
|
||||
|
||||
if (dbus_watch_get_enabled(aWatch)) {
|
||||
dbusWatcher->StartWatching();
|
||||
}
|
||||
|
||||
Unused << dbusWatcher.release(); // picked up in |FreeFunction|
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
DBusWatcher::RemoveWatchFunction(DBusWatch* aWatch, void* aData)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
auto dbusWatcher = static_cast<DBusWatcher*>(dbus_watch_get_data(aWatch));
|
||||
|
||||
dbusWatcher->StopWatching();
|
||||
}
|
||||
|
||||
void
|
||||
DBusWatcher::ToggleWatchFunction(DBusWatch* aWatch, void* aData)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
auto dbusWatcher = static_cast<DBusWatcher*>(dbus_watch_get_data(aWatch));
|
||||
|
||||
if (dbus_watch_get_enabled(aWatch)) {
|
||||
dbusWatcher->StartWatching();
|
||||
} else {
|
||||
dbusWatcher->StopWatching();
|
||||
}
|
||||
}
|
||||
|
||||
// I/O-loop callbacks
|
||||
|
||||
void
|
||||
DBusWatcher::OnFileCanReadWithoutBlocking(int aFd)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
dbus_watch_handle(mWatch, DBUS_WATCH_READABLE);
|
||||
|
||||
DBusDispatchStatus dbusDispatchStatus;
|
||||
|
||||
do {
|
||||
dbusDispatchStatus = dbus_connection_dispatch(mConnection);
|
||||
} while (dbusDispatchStatus == DBUS_DISPATCH_DATA_REMAINS);
|
||||
}
|
||||
|
||||
void
|
||||
DBusWatcher::OnFileCanWriteWithoutBlocking(int aFd)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
dbus_watch_handle(mWatch, DBUS_WATCH_WRITABLE);
|
||||
}
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
@@ -0,0 +1,50 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_ipc_DBusWatcher_h
|
||||
#define mozilla_ipc_DBusWatcher_h
|
||||
|
||||
#include <dbus/dbus.h>
|
||||
#include "base/message_loop.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
class DBusWatcher : public MessageLoopForIO::Watcher
|
||||
{
|
||||
public:
|
||||
DBusWatcher(DBusConnection* aConnection, DBusWatch* aWatch);
|
||||
~DBusWatcher();
|
||||
|
||||
void StartWatching();
|
||||
void StopWatching();
|
||||
|
||||
static void FreeFunction(void* aData);
|
||||
static dbus_bool_t AddWatchFunction(DBusWatch* aWatch, void* aData);
|
||||
static void RemoveWatchFunction(DBusWatch* aWatch, void* aData);
|
||||
static void ToggleWatchFunction(DBusWatch* aWatch, void* aData);
|
||||
|
||||
DBusConnection* GetConnection();
|
||||
|
||||
private:
|
||||
void OnFileCanReadWithoutBlocking(int aFd);
|
||||
void OnFileCanWriteWithoutBlocking(int aFd);
|
||||
|
||||
// Read watcher for libevent. Only to be accessed on IO Thread.
|
||||
MessageLoopForIO::FileDescriptorWatcher mReadWatcher;
|
||||
|
||||
// Write watcher for libevent. Only to be accessed on IO Thread.
|
||||
MessageLoopForIO::FileDescriptorWatcher mWriteWatcher;
|
||||
|
||||
// DBus structures
|
||||
DBusConnection* mConnection;
|
||||
DBusWatch* mWatch;
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_ipc_DBusWatcher_h
|
||||
+25
-293
@@ -4,228 +4,14 @@
|
||||
* 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 <dbus/dbus.h>
|
||||
#include "base/message_loop.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "RawDBusConnection.h"
|
||||
|
||||
#ifdef CHROMIUM_LOG
|
||||
#undef CHROMIUM_LOG
|
||||
#endif
|
||||
|
||||
#if defined(MOZ_WIDGET_GONK)
|
||||
#include <android/log.h>
|
||||
#define CHROMIUM_LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk", args);
|
||||
#else
|
||||
#define CHROMIUM_LOG(args...) printf(args);
|
||||
#endif
|
||||
#include "base/message_loop.h"
|
||||
#include "mozilla/ipc/DBusHelpers.h"
|
||||
#include "mozilla/ipc/DBusWatcher.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
//
|
||||
// DBusWatcher
|
||||
//
|
||||
|
||||
class DBusWatcher : public MessageLoopForIO::Watcher
|
||||
{
|
||||
public:
|
||||
DBusWatcher(RawDBusConnection* aConnection, DBusWatch* aWatch)
|
||||
: mConnection(aConnection),
|
||||
mWatch(aWatch)
|
||||
{
|
||||
MOZ_ASSERT(mConnection);
|
||||
MOZ_ASSERT(mWatch);
|
||||
}
|
||||
|
||||
~DBusWatcher()
|
||||
{ }
|
||||
|
||||
void StartWatching();
|
||||
void StopWatching();
|
||||
|
||||
static void FreeFunction(void* aData);
|
||||
static dbus_bool_t AddWatchFunction(DBusWatch* aWatch, void* aData);
|
||||
static void RemoveWatchFunction(DBusWatch* aWatch, void* aData);
|
||||
static void ToggleWatchFunction(DBusWatch* aWatch, void* aData);
|
||||
|
||||
RawDBusConnection* GetConnection();
|
||||
|
||||
private:
|
||||
void OnFileCanReadWithoutBlocking(int aFd);
|
||||
void OnFileCanWriteWithoutBlocking(int aFd);
|
||||
|
||||
// Read watcher for libevent. Only to be accessed on IO Thread.
|
||||
MessageLoopForIO::FileDescriptorWatcher mReadWatcher;
|
||||
|
||||
// Write watcher for libevent. Only to be accessed on IO Thread.
|
||||
MessageLoopForIO::FileDescriptorWatcher mWriteWatcher;
|
||||
|
||||
// DBus structures
|
||||
RawDBusConnection* mConnection;
|
||||
DBusWatch* mWatch;
|
||||
};
|
||||
|
||||
RawDBusConnection*
|
||||
DBusWatcher::GetConnection()
|
||||
{
|
||||
return mConnection;
|
||||
}
|
||||
|
||||
void DBusWatcher::StartWatching()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(mWatch);
|
||||
|
||||
int fd = dbus_watch_get_unix_fd(mWatch);
|
||||
|
||||
MessageLoopForIO* ioLoop = MessageLoopForIO::current();
|
||||
|
||||
unsigned int flags = dbus_watch_get_flags(mWatch);
|
||||
|
||||
if (flags & DBUS_WATCH_READABLE) {
|
||||
ioLoop->WatchFileDescriptor(fd, true, MessageLoopForIO::WATCH_READ,
|
||||
&mReadWatcher, this);
|
||||
}
|
||||
if (flags & DBUS_WATCH_WRITABLE) {
|
||||
ioLoop->WatchFileDescriptor(fd, true, MessageLoopForIO::WATCH_WRITE,
|
||||
&mWriteWatcher, this);
|
||||
}
|
||||
}
|
||||
|
||||
void DBusWatcher::StopWatching()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
unsigned int flags = dbus_watch_get_flags(mWatch);
|
||||
|
||||
if (flags & DBUS_WATCH_READABLE) {
|
||||
mReadWatcher.StopWatchingFileDescriptor();
|
||||
}
|
||||
if (flags & DBUS_WATCH_WRITABLE) {
|
||||
mWriteWatcher.StopWatchingFileDescriptor();
|
||||
}
|
||||
}
|
||||
|
||||
// DBus utility functions, used as function pointers in DBus setup
|
||||
|
||||
void
|
||||
DBusWatcher::FreeFunction(void* aData)
|
||||
{
|
||||
delete static_cast<DBusWatcher*>(aData);
|
||||
}
|
||||
|
||||
dbus_bool_t
|
||||
DBusWatcher::AddWatchFunction(DBusWatch* aWatch, void* aData)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
RawDBusConnection* connection = static_cast<RawDBusConnection*>(aData);
|
||||
|
||||
DBusWatcher* dbusWatcher = new DBusWatcher(connection, aWatch);
|
||||
dbus_watch_set_data(aWatch, dbusWatcher, DBusWatcher::FreeFunction);
|
||||
|
||||
if (dbus_watch_get_enabled(aWatch)) {
|
||||
dbusWatcher->StartWatching();
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
DBusWatcher::RemoveWatchFunction(DBusWatch* aWatch, void* aData)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
DBusWatcher* dbusWatcher =
|
||||
static_cast<DBusWatcher*>(dbus_watch_get_data(aWatch));
|
||||
dbusWatcher->StopWatching();
|
||||
}
|
||||
|
||||
void
|
||||
DBusWatcher::ToggleWatchFunction(DBusWatch* aWatch, void* aData)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
DBusWatcher* dbusWatcher =
|
||||
static_cast<DBusWatcher*>(dbus_watch_get_data(aWatch));
|
||||
|
||||
if (dbus_watch_get_enabled(aWatch)) {
|
||||
dbusWatcher->StartWatching();
|
||||
} else {
|
||||
dbusWatcher->StopWatching();
|
||||
}
|
||||
}
|
||||
|
||||
// I/O-loop callbacks
|
||||
|
||||
void
|
||||
DBusWatcher::OnFileCanReadWithoutBlocking(int aFd)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
dbus_watch_handle(mWatch, DBUS_WATCH_READABLE);
|
||||
|
||||
DBusDispatchStatus dbusDispatchStatus;
|
||||
do {
|
||||
dbusDispatchStatus =
|
||||
dbus_connection_dispatch(mConnection->GetConnection());
|
||||
} while (dbusDispatchStatus == DBUS_DISPATCH_DATA_REMAINS);
|
||||
}
|
||||
|
||||
void
|
||||
DBusWatcher::OnFileCanWriteWithoutBlocking(int aFd)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
dbus_watch_handle(mWatch, DBUS_WATCH_WRITABLE);
|
||||
}
|
||||
|
||||
//
|
||||
// Notification
|
||||
//
|
||||
|
||||
class Notification
|
||||
{
|
||||
public:
|
||||
Notification(DBusReplyCallback aCallback, void* aData)
|
||||
: mCallback(aCallback),
|
||||
mData(aData)
|
||||
{ }
|
||||
|
||||
// Callback function for DBus replies. Only run it on I/O thread.
|
||||
//
|
||||
static void Handle(DBusPendingCall* aCall, void* aData)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(MessageLoop::current());
|
||||
|
||||
nsAutoPtr<Notification> ntfn(static_cast<Notification*>(aData));
|
||||
|
||||
// The reply can be non-null if the timeout has been reached.
|
||||
DBusMessage* reply = dbus_pending_call_steal_reply(aCall);
|
||||
|
||||
if (reply) {
|
||||
ntfn->RunCallback(reply);
|
||||
dbus_message_unref(reply);
|
||||
}
|
||||
|
||||
dbus_pending_call_cancel(aCall);
|
||||
dbus_pending_call_unref(aCall);
|
||||
}
|
||||
|
||||
private:
|
||||
void RunCallback(DBusMessage* aMessage)
|
||||
{
|
||||
if (mCallback) {
|
||||
mCallback(aMessage, mData);
|
||||
}
|
||||
}
|
||||
|
||||
DBusReplyCallback mCallback;
|
||||
void* mData;
|
||||
};
|
||||
|
||||
//
|
||||
// RawDBusConnection
|
||||
//
|
||||
@@ -247,54 +33,41 @@ nsresult RawDBusConnection::EstablishDBusConnection()
|
||||
NS_ENSURE_TRUE(success == TRUE, NS_ERROR_FAILURE);
|
||||
sDBusIsInit = true;
|
||||
}
|
||||
|
||||
DBusError err;
|
||||
dbus_error_init(&err);
|
||||
mConnection = dbus_bus_get_private(DBUS_BUS_SYSTEM, &err);
|
||||
|
||||
mConnection = already_AddRefed<DBusConnection>(
|
||||
dbus_bus_get_private(DBUS_BUS_SYSTEM, &err));
|
||||
|
||||
if (dbus_error_is_set(&err)) {
|
||||
dbus_error_free(&err);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
dbus_connection_set_exit_on_disconnect(mConnection, FALSE);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool RawDBusConnection::Watch()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(MessageLoop::current());
|
||||
|
||||
dbus_bool_t success =
|
||||
dbus_connection_set_watch_functions(mConnection,
|
||||
DBusWatcher::AddWatchFunction,
|
||||
DBusWatcher::RemoveWatchFunction,
|
||||
DBusWatcher::ToggleWatchFunction,
|
||||
this, nullptr);
|
||||
NS_ENSURE_TRUE(success == TRUE, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RawDBusConnection::ScopedDBusConnectionPtrTraits::release(DBusConnection* ptr)
|
||||
{
|
||||
if (ptr) {
|
||||
dbus_connection_close(ptr);
|
||||
dbus_connection_unref(ptr);
|
||||
}
|
||||
return NS_SUCCEEDED(DBusWatchConnection(mConnection));
|
||||
}
|
||||
|
||||
bool RawDBusConnection::Send(DBusMessage* aMessage)
|
||||
{
|
||||
MOZ_ASSERT(aMessage);
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(MessageLoop::current());
|
||||
|
||||
dbus_bool_t success = dbus_connection_send(mConnection,
|
||||
aMessage,
|
||||
nullptr);
|
||||
if (success != TRUE) {
|
||||
auto rv = DBusSendMessage(mConnection, aMessage);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
dbus_message_unref(aMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -303,26 +76,14 @@ bool RawDBusConnection::SendWithReply(DBusReplyCallback aCallback,
|
||||
int aTimeout,
|
||||
DBusMessage* aMessage)
|
||||
{
|
||||
MOZ_ASSERT(aMessage);
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(MessageLoop::current());
|
||||
|
||||
nsAutoPtr<Notification> ntfn(new Notification(aCallback, aData));
|
||||
NS_ENSURE_TRUE(ntfn, false);
|
||||
auto rv = DBusSendMessageWithReply(mConnection, aCallback, aData, aTimeout,
|
||||
aMessage);
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DBusPendingCall* call;
|
||||
|
||||
dbus_bool_t success = dbus_connection_send_with_reply(mConnection,
|
||||
aMessage,
|
||||
&call,
|
||||
aTimeout);
|
||||
NS_ENSURE_TRUE(success == TRUE, false);
|
||||
|
||||
success = dbus_pending_call_set_notify(call, Notification::Handle,
|
||||
ntfn, nullptr);
|
||||
NS_ENSURE_TRUE(success == TRUE, false);
|
||||
|
||||
ntfn.forget();
|
||||
dbus_message_unref(aMessage);
|
||||
|
||||
return true;
|
||||
@@ -338,44 +99,15 @@ bool RawDBusConnection::SendWithReply(DBusReplyCallback aCallback,
|
||||
int aFirstArgType,
|
||||
...)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
va_list args;
|
||||
|
||||
va_start(args, aFirstArgType);
|
||||
DBusMessage* msg = BuildDBusMessage(aDestination, aPath, aIntf, aFunc,
|
||||
aFirstArgType, args);
|
||||
|
||||
auto rv = DBusSendMessageWithReply(mConnection, aCallback, aData,
|
||||
aTimeout, aDestination, aPath, aIntf,
|
||||
aFunc, aFirstArgType, args);
|
||||
va_end(args);
|
||||
|
||||
if (!msg) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return SendWithReply(aCallback, aData, aTimeout, msg);
|
||||
}
|
||||
|
||||
DBusMessage* RawDBusConnection::BuildDBusMessage(const char* aDestination,
|
||||
const char* aPath,
|
||||
const char* aIntf,
|
||||
const char* aFunc,
|
||||
int aFirstArgType,
|
||||
va_list aArgs)
|
||||
{
|
||||
DBusMessage* msg = dbus_message_new_method_call(aDestination,
|
||||
aPath, aIntf,
|
||||
aFunc);
|
||||
if (!msg) {
|
||||
CHROMIUM_LOG("Could not allocate D-Bus message object!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* append arguments */
|
||||
if (!dbus_message_append_args_valist(msg, aFirstArgType, aArgs)) {
|
||||
CHROMIUM_LOG("Could not append argument to method call!");
|
||||
dbus_message_unref(msg);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return msg;
|
||||
return NS_SUCCEEDED(rv);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,10 +7,8 @@
|
||||
#ifndef mozilla_ipc_dbus_gonk_rawdbusconnection_h__
|
||||
#define mozilla_ipc_dbus_gonk_rawdbusconnection_h__
|
||||
|
||||
#include "mozilla/Scoped.h"
|
||||
|
||||
struct DBusConnection;
|
||||
struct DBusMessage;
|
||||
#include <dbus/dbus.h>
|
||||
#include "mozilla/ipc/DBusConnectionRefPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
@@ -19,11 +17,6 @@ typedef void (*DBusReplyCallback)(DBusMessage*, void*);
|
||||
|
||||
class RawDBusConnection
|
||||
{
|
||||
struct ScopedDBusConnectionPtrTraits : ScopedFreePtrTraits<DBusConnection>
|
||||
{
|
||||
static void release(DBusConnection* ptr);
|
||||
};
|
||||
|
||||
public:
|
||||
RawDBusConnection();
|
||||
virtual ~RawDBusConnection();
|
||||
@@ -49,12 +42,7 @@ public:
|
||||
const char *aFunc, int aFirstArgType, ...);
|
||||
|
||||
protected:
|
||||
DBusMessage* BuildDBusMessage(const char* aDestination,
|
||||
const char* aPath, const char* aIntf,
|
||||
const char* aFunc, int aFirstArgType,
|
||||
va_list args);
|
||||
|
||||
Scoped<ScopedDBusConnectionPtrTraits> mConnection;
|
||||
RefPtr<DBusConnection> mConnection;
|
||||
|
||||
private:
|
||||
static bool sDBusIsInit;
|
||||
|
||||
@@ -5,12 +5,19 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXPORTS.mozilla.ipc += [
|
||||
'DBusConnectionRefPtr.h',
|
||||
'DBusHelpers.h',
|
||||
'DBusMessageRefPtr.h',
|
||||
'DBusPendingCallRefPtr.h',
|
||||
'DBusUtils.h',
|
||||
'DBusWatcher.h',
|
||||
'RawDBusConnection.h',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'DBusHelpers.cpp',
|
||||
'DBusUtils.cpp',
|
||||
'DBusWatcher.cpp',
|
||||
'RawDBusConnection.cpp',
|
||||
]
|
||||
|
||||
|
||||
@@ -186,6 +186,31 @@ nsClipboard::TransferableFromPasteboard(nsITransferable *aTransferable, NSPasteb
|
||||
free(clipboardDataPtr);
|
||||
break;
|
||||
}
|
||||
else if (flavorStr.EqualsLiteral(kCustomTypesMime)) {
|
||||
NSString* type = [cocoaPasteboard availableTypeFromArray:[NSArray arrayWithObject:kCustomTypesPboardType]];
|
||||
if (!type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
NSData* pasteboardData = GetDataFromPasteboard(cocoaPasteboard, type);
|
||||
if (!pasteboardData) {
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned int dataLength = [pasteboardData length];
|
||||
void* clipboardDataPtr = malloc(dataLength);
|
||||
if (!clipboardDataPtr) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
[pasteboardData getBytes:clipboardDataPtr];
|
||||
|
||||
nsCOMPtr<nsISupports> genericDataWrapper;
|
||||
nsPrimitiveHelpers::CreatePrimitiveForData(flavorStr, clipboardDataPtr, dataLength,
|
||||
getter_AddRefs(genericDataWrapper));
|
||||
|
||||
aTransferable->SetTransferData(flavorStr, genericDataWrapper, dataLength);
|
||||
free(clipboardDataPtr);
|
||||
}
|
||||
else if (flavorStr.EqualsLiteral(kJPEGImageMime) ||
|
||||
flavorStr.EqualsLiteral(kJPGImageMime) ||
|
||||
flavorStr.EqualsLiteral(kPNGImageMime) ||
|
||||
@@ -330,7 +355,7 @@ nsClipboard::HasDataMatchingFlavors(const char** aFlavorList, uint32_t aLength,
|
||||
return NS_OK;
|
||||
|
||||
// first see if we have data for this in our cached transferable
|
||||
if (mTransferable) {
|
||||
if (mTransferable) {
|
||||
nsCOMPtr<nsISupportsArray> transferableFlavorList;
|
||||
nsresult rv = mTransferable->FlavorsTransferableCanImport(getter_AddRefs(transferableFlavorList));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
@@ -367,6 +392,12 @@ nsClipboard::HasDataMatchingFlavors(const char** aFlavorList, uint32_t aLength,
|
||||
*outResult = true;
|
||||
break;
|
||||
}
|
||||
} else if (!strcmp(aFlavorList[i], kCustomTypesMime)) {
|
||||
NSString* availableType = [generalPBoard availableTypeFromArray:[NSArray arrayWithObject:kCustomTypesPboardType]];
|
||||
if (availableType) {
|
||||
*outResult = true;
|
||||
break;
|
||||
}
|
||||
} else if (!strcmp(aFlavorList[i], kJPEGImageMime) ||
|
||||
!strcmp(aFlavorList[i], kJPGImageMime) ||
|
||||
!strcmp(aFlavorList[i], kPNGImageMime) ||
|
||||
@@ -447,6 +478,20 @@ nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTransferable)
|
||||
|
||||
free(data);
|
||||
}
|
||||
else if (flavorStr.EqualsLiteral(kCustomTypesMime)) {
|
||||
void* data = nullptr;
|
||||
uint32_t dataSize = 0;
|
||||
nsCOMPtr<nsISupports> genericDataWrapper;
|
||||
rv = aTransferable->GetTransferData(flavorStr, getter_AddRefs(genericDataWrapper), &dataSize);
|
||||
nsPrimitiveHelpers::CreateDataFromPrimitive(flavorStr, genericDataWrapper, &data, dataSize);
|
||||
|
||||
if (data) {
|
||||
NSData* nativeData = [NSData dataWithBytes:data length:dataSize];
|
||||
|
||||
[pasteboardOutputDict setObject:nativeData forKey:kCustomTypesPboardType];
|
||||
free(data);
|
||||
}
|
||||
}
|
||||
else if (flavorStr.EqualsLiteral(kPNGImageMime) || flavorStr.EqualsLiteral(kJPEGImageMime) ||
|
||||
flavorStr.EqualsLiteral(kJPGImageMime) || flavorStr.EqualsLiteral(kGIFImageMime) ||
|
||||
flavorStr.EqualsLiteral(kNativeImageMime)) {
|
||||
|
||||
@@ -501,9 +501,15 @@ nsresult nsCocoaUtils::CreateNSImageFromImageContainer(imgIContainer *aImage, ui
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
aImage->Draw(context, scaledSize, ImageRegion::Create(scaledSize),
|
||||
aWhichFrame, Filter::POINT, Nothing(),
|
||||
imgIContainer::FLAG_SYNC_DECODE);
|
||||
mozilla::image::DrawResult res =
|
||||
aImage->Draw(context, scaledSize, ImageRegion::Create(scaledSize),
|
||||
aWhichFrame, Filter::POINT,
|
||||
/* no SVGImageContext */ Nothing(),
|
||||
imgIContainer::FLAG_SYNC_DECODE);
|
||||
|
||||
if (res != mozilla::image::DrawResult::SUCCESS) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
surface = drawTarget->Snapshot();
|
||||
} else {
|
||||
|
||||
@@ -14,6 +14,7 @@ extern NSString* const kWildcardPboardType;
|
||||
extern NSString* const kCorePboardType_url;
|
||||
extern NSString* const kCorePboardType_urld;
|
||||
extern NSString* const kCorePboardType_urln;
|
||||
extern NSString* const kCustomTypesPboardType;
|
||||
|
||||
class nsDragService : public nsBaseDragService
|
||||
{
|
||||
|
||||
@@ -49,6 +49,7 @@ NSString* const kCorePboardType_url = @"CorePasteboardFlavorType 0x75726C20"; /
|
||||
NSString* const kCorePboardType_urld = @"CorePasteboardFlavorType 0x75726C64"; // 'urld' desc
|
||||
NSString* const kCorePboardType_urln = @"CorePasteboardFlavorType 0x75726C6E"; // 'urln' title
|
||||
NSString* const kUTTypeURLName = @"public.url-name";
|
||||
NSString* const kCustomTypesPboardType = @"org.mozilla.custom-clipdata";
|
||||
|
||||
nsDragService::nsDragService()
|
||||
{
|
||||
@@ -110,7 +111,8 @@ static nsresult SetUpDragClipboard(nsISupportsArray* aTransferableArray)
|
||||
[dragPBoard setString:(nsClipboard::WrapHtmlForSystemPasteboard(currentValue))
|
||||
forType:currentKey];
|
||||
}
|
||||
else if (currentKey == NSTIFFPboardType) {
|
||||
else if (currentKey == NSTIFFPboardType ||
|
||||
currentKey == kCustomTypesPboardType) {
|
||||
[dragPBoard setData:currentValue forType:currentKey];
|
||||
}
|
||||
else if (currentKey == NSFilesPromisePboardType ||
|
||||
@@ -474,6 +476,31 @@ nsDragService::GetData(nsITransferable* aTransferable, uint32_t aItemIndex)
|
||||
|
||||
break;
|
||||
}
|
||||
else if (flavorStr.EqualsLiteral(kCustomTypesMime)) {
|
||||
NSString* availableType = [item availableTypeFromArray:[NSArray arrayWithObject:kCustomTypesPboardType]];
|
||||
if (!availableType || !IsValidType(availableType, false)) {
|
||||
continue;
|
||||
}
|
||||
NSData *pasteboardData = [item dataForType:availableType];
|
||||
if (!pasteboardData) {
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned int dataLength = [pasteboardData length];
|
||||
void* clipboardDataPtr = malloc(dataLength);
|
||||
if (!clipboardDataPtr) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
[pasteboardData getBytes:clipboardDataPtr];
|
||||
|
||||
nsCOMPtr<nsISupports> genericDataWrapper;
|
||||
nsPrimitiveHelpers::CreatePrimitiveForData(flavorStr, clipboardDataPtr, dataLength,
|
||||
getter_AddRefs(genericDataWrapper));
|
||||
|
||||
aTransferable->SetTransferData(flavorStr, genericDataWrapper, sizeof(nsIInputStream*));
|
||||
free(clipboardDataPtr);
|
||||
break;
|
||||
}
|
||||
|
||||
NSString* pString = nil;
|
||||
if (flavorStr.EqualsLiteral(kUnicodeMime)) {
|
||||
@@ -610,7 +637,10 @@ nsDragService::IsDataFlavorSupported(const char *aDataFlavor, bool *_retval)
|
||||
type = (const NSString*)kUTTypeURLName;
|
||||
} else if (dataFlavor.EqualsLiteral(kRTFMime)) {
|
||||
type = (const NSString*)kUTTypeRTF;
|
||||
} else if (dataFlavor.EqualsLiteral(kCustomTypesMime)) {
|
||||
type = (const NSString*)kCustomTypesPboardType;
|
||||
}
|
||||
|
||||
NSString* availableType = [globalDragPboard availableTypeFromArray:[NSArray arrayWithObjects:(id)type, nil]];
|
||||
if (availableType && IsValidType(availableType, allowFileURL)) {
|
||||
*_retval = true;
|
||||
|
||||
@@ -970,12 +970,14 @@ nsDragService::GetData(nsITransferable * aTransferable,
|
||||
} // else we try one last ditch effort to find our data
|
||||
|
||||
if (dataFound) {
|
||||
// the DOM only wants LF, so convert from MacOS line endings
|
||||
// to DOM line endings.
|
||||
nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(
|
||||
flavorStr,
|
||||
&mTargetDragData,
|
||||
reinterpret_cast<int*>(&mTargetDragDataLen));
|
||||
if (strcmp(flavorStr, kCustomTypesMime) != 0) {
|
||||
// the DOM only wants LF, so convert from MacOS line endings
|
||||
// to DOM line endings.
|
||||
nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(
|
||||
flavorStr,
|
||||
&mTargetDragData,
|
||||
reinterpret_cast<int*>(&mTargetDragDataLen));
|
||||
}
|
||||
|
||||
// put it into the transferable.
|
||||
nsCOMPtr<nsISupports> genericDataWrapper;
|
||||
|
||||
@@ -708,7 +708,7 @@ nsBaseDragService::DrawDragForImage(nsIImageLoadingContent* aImageLoader,
|
||||
DrawResult res =
|
||||
imgContainer->Draw(ctx, destSize, ImageRegion::Create(destSize),
|
||||
imgIContainer::FRAME_CURRENT,
|
||||
Filter::GOOD, Nothing(),
|
||||
Filter::GOOD, /* no SVGImageContext */ Nothing(),
|
||||
imgIContainer::FLAG_SYNC_DECODE);
|
||||
if (res == DrawResult::BAD_IMAGE || res == DrawResult::BAD_ARGS) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
@@ -93,7 +93,8 @@ nsClipboardProxy::GetData(nsITransferable *aTransferable, int32_t aWhichClipboar
|
||||
rv = aTransferable->SetTransferData(flavor.get(), stream, sizeof(nsISupports*));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else if (flavor.EqualsLiteral(kNativeHTMLMime) ||
|
||||
flavor.EqualsLiteral(kRTFMime)) {
|
||||
flavor.EqualsLiteral(kRTFMime) ||
|
||||
flavor.EqualsLiteral(kCustomTypesMime)) {
|
||||
nsCOMPtr<nsISupportsCString> dataWrapper =
|
||||
do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
@@ -49,6 +49,8 @@ interface nsIDOMNode;
|
||||
// a synthetic flavor, put into the transferable once we know the destination directory of a file drag
|
||||
#define kFilePromiseDirectoryMime "application/x-moz-file-promise-dir"
|
||||
|
||||
#define kCustomTypesMime "application/x-moz-custom-clipdata"
|
||||
|
||||
%}
|
||||
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ nsPrimitiveHelpers :: CreatePrimitiveForData ( const char* aFlavor, const void*
|
||||
return;
|
||||
|
||||
if ( strcmp(aFlavor,kTextMime) == 0 || strcmp(aFlavor,kNativeHTMLMime) == 0 ||
|
||||
strcmp(aFlavor,kRTFMime) == 0) {
|
||||
strcmp(aFlavor,kRTFMime) == 0 || strcmp(aFlavor,kCustomTypesMime) == 0) {
|
||||
nsCOMPtr<nsISupportsCString> primitive =
|
||||
do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID);
|
||||
if ( primitive ) {
|
||||
@@ -133,7 +133,7 @@ nsPrimitiveHelpers :: CreateDataFromPrimitive ( const char* aFlavor, nsISupports
|
||||
|
||||
*aDataBuff = nullptr;
|
||||
|
||||
if ( strcmp(aFlavor,kTextMime) == 0 ) {
|
||||
if ( strcmp(aFlavor,kTextMime) == 0 || strcmp(aFlavor,kCustomTypesMime) == 0) {
|
||||
nsCOMPtr<nsISupportsCString> plainText ( do_QueryInterface(aPrimitive) );
|
||||
if ( plainText ) {
|
||||
nsAutoCString data;
|
||||
|
||||
@@ -1252,6 +1252,9 @@ function runEditorFlagChangeTests()
|
||||
editor.QueryInterface(Components.interfaces.nsIEditorIMESupport);
|
||||
var flags = editor.flags;
|
||||
|
||||
// Reset selection from previous tests.
|
||||
editor.selection.collapse(container, 0);
|
||||
|
||||
// input characters
|
||||
synthesizeCompositionChange(
|
||||
{ "composition":
|
||||
|
||||
@@ -42,6 +42,7 @@ PRLogModuleInfo* gWin32ClipboardLog = nullptr;
|
||||
|
||||
// oddly, this isn't in the MSVC headers anywhere.
|
||||
UINT nsClipboard::CF_HTML = ::RegisterClipboardFormatW(L"HTML Format");
|
||||
UINT nsClipboard::CF_CUSTOMTYPES = ::RegisterClipboardFormatW(L"application/x-moz-custom-clipdata");
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -107,6 +108,8 @@ UINT nsClipboard::GetFormat(const char* aMimeStr, bool aMapHTMLMime)
|
||||
else if (strcmp(aMimeStr, kNativeHTMLMime) == 0 ||
|
||||
aMapHTMLMime && strcmp(aMimeStr, kHTMLMime) == 0)
|
||||
format = CF_HTML;
|
||||
else if (strcmp(aMimeStr, kCustomTypesMime) == 0)
|
||||
format = CF_CUSTOMTYPES;
|
||||
else
|
||||
format = ::RegisterClipboardFormatW(NS_ConvertASCIItoUTF16(aMimeStr).get());
|
||||
|
||||
@@ -522,6 +525,9 @@ nsresult nsClipboard::GetNativeDataOffClipboard(IDataObject * aDataObject, UINT
|
||||
// do that in FindPlatformHTML(). For now, return the allocLen. This
|
||||
// case is mostly to ensure we don't try to call strlen on the buffer.
|
||||
*aLen = allocLen;
|
||||
} else if (fe.cfFormat == CF_CUSTOMTYPES) {
|
||||
// Binary data
|
||||
*aLen = allocLen;
|
||||
} else if (fe.cfFormat == preferredDropEffect) {
|
||||
// As per the MSDN doc entitled: "Shell Clipboard Formats"
|
||||
// CFSTR_PREFERREDDROPEFFECT should return a DWORD
|
||||
@@ -668,16 +674,19 @@ nsresult nsClipboard::GetDataFromDataObject(IDataObject * aDataObject,
|
||||
NS_IF_RELEASE(imageStream);
|
||||
}
|
||||
else {
|
||||
// we probably have some form of text. The DOM only wants LF, so convert from Win32 line
|
||||
// endings to DOM line endings.
|
||||
int32_t signedLen = static_cast<int32_t>(dataLen);
|
||||
nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks ( flavorStr, &data, &signedLen );
|
||||
dataLen = signedLen;
|
||||
// Treat custom types as a string of bytes.
|
||||
if (strcmp(flavorStr, kCustomTypesMime) != 0) {
|
||||
// we probably have some form of text. The DOM only wants LF, so convert from Win32 line
|
||||
// endings to DOM line endings.
|
||||
int32_t signedLen = static_cast<int32_t>(dataLen);
|
||||
nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks ( flavorStr, &data, &signedLen );
|
||||
dataLen = signedLen;
|
||||
|
||||
if (strcmp(flavorStr, kRTFMime) == 0) {
|
||||
// RTF on Windows is known to sometimes deliver an extra null byte.
|
||||
if (dataLen > 0 && static_cast<char*>(data)[dataLen - 1] == '\0')
|
||||
dataLen--;
|
||||
if (strcmp(flavorStr, kRTFMime) == 0) {
|
||||
// RTF on Windows is known to sometimes deliver an extra null byte.
|
||||
if (dataLen > 0 && static_cast<char*>(data)[dataLen - 1] == '\0')
|
||||
dataLen--;
|
||||
}
|
||||
}
|
||||
|
||||
nsPrimitiveHelpers::CreatePrimitiveForData ( flavorStr, data, dataLen, getter_AddRefs(genericDataWrapper) );
|
||||
|
||||
@@ -60,6 +60,7 @@ public:
|
||||
static UINT GetFormat(const char* aMimeStr, bool aMapHTMLMime = true);
|
||||
|
||||
static UINT CF_HTML;
|
||||
static UINT CF_CUSTOMTYPES;
|
||||
|
||||
protected:
|
||||
NS_IMETHOD SetNativeClipboardData ( int32_t aWhichClipboard ) override;
|
||||
|
||||
@@ -1308,7 +1308,7 @@ HRESULT nsDataObj::GetText(const nsACString & aDataFlavor, FORMATETC& aFE, STGME
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
else {
|
||||
else if ( aFE.cfFormat != nsClipboard::CF_CUSTOMTYPES ) {
|
||||
// we assume that any data that isn't caught above is unicode. This may
|
||||
// be an erroneous assumption, but is true so far.
|
||||
allocLen += sizeof(char16_t);
|
||||
|
||||
@@ -540,14 +540,6 @@ nsDragService::IsDataFlavorSupported(const char *aDataFlavor, bool *_retval)
|
||||
if (mDataObject->QueryGetData(&fe) == S_OK)
|
||||
*_retval = true; // found it!
|
||||
}
|
||||
else if (strcmp(aDataFlavor, kHTMLMime) == 0) {
|
||||
// If the client wants html, maybe it's in "HTML Format".
|
||||
format = nsClipboard::GetFormat(kHTMLMime);
|
||||
SET_FORMATETC(fe, format, 0, DVASPECT_CONTENT, -1,
|
||||
TYMED_HGLOBAL);
|
||||
if (mDataObject->QueryGetData(&fe) == S_OK)
|
||||
*_retval = true; // found it!
|
||||
}
|
||||
} // else try again
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user