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:
2024-07-26 21:49:43 +08:00
parent 05670874b5
commit cbc917768b
53 changed files with 1505 additions and 588 deletions
+11
View File
@@ -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:
-1
View File
@@ -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"
+20 -3
View File
@@ -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;
}
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+6 -3
View File
@@ -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
View File
@@ -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; }
+1 -1
View File
@@ -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)
+6 -8
View File
@@ -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;
+4 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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) {
+22 -2
View File
@@ -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
+1 -2
View File
@@ -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.
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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

+51
View File
@@ -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

+11
View File
@@ -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>
+6
View File
@@ -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.
}
+30
View File
@@ -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
+246
View File
@@ -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;
}
}
}
+65
View File
@@ -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
+30
View File
@@ -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
+30
View File
@@ -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
+149
View File
@@ -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
+50
View File
@@ -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
View File
@@ -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);
}
}
+3 -15
View File
@@ -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;
+7
View File
@@ -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',
]
+46 -1
View File
@@ -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)) {
+9 -3
View File
@@ -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 {
+1
View File
@@ -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
{
+31 -1
View File
@@ -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;
+8 -6
View File
@@ -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;
+1 -1
View File
@@ -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;
+2 -1
View File
@@ -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);
+2
View File
@@ -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"
%}
+2 -2
View File
@@ -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;
+3
View File
@@ -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":
+18 -9
View File
@@ -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) );
+1
View File
@@ -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;
+1 -1
View File
@@ -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);
-8
View File
@@ -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
}