mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge inbound to m-c. a=merge
This commit is contained in:
commit
50e913e2aa
@ -1,6 +1,8 @@
|
||||
const Cu = Components.utils;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
Cu.importGlobalProperties(['File']);
|
||||
|
||||
const { Services } = Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
// Load a duplicated copy of the jsm to prevent messing with the currently running one
|
||||
@ -25,7 +27,7 @@ function next() {
|
||||
let steps = [
|
||||
function getScreenshot() {
|
||||
let screenshot = Screenshot.get();
|
||||
assert.ok(screenshot instanceof Ci.nsIDOMFile,
|
||||
assert.ok(screenshot instanceof File,
|
||||
"Screenshot.get() returns a File");
|
||||
next();
|
||||
},
|
||||
|
@ -1210,6 +1210,9 @@ pref("security.sandbox.content.level", 1);
|
||||
pref("security.sandbox.content.level", 0);
|
||||
#endif
|
||||
|
||||
// ID (a UUID when set by gecko) that is used as a per profile suffix to a low
|
||||
// integrity temp directory.
|
||||
pref("security.sandbox.content.tempDirSuffix", "");
|
||||
|
||||
#if defined(MOZ_STACKWALKING)
|
||||
// This controls the depth of stack trace that is logged when Windows sandbox
|
||||
|
@ -40,7 +40,7 @@ def getMarProperties(filename, partial=False):
|
||||
'%sMarHash' % martype: mar_hash,
|
||||
}
|
||||
|
||||
def getUrlProperties(filename):
|
||||
def getUrlProperties(filename, package):
|
||||
# let's create a switch case using name-spaces/dict
|
||||
# rather than a long if/else with duplicate code
|
||||
property_conditions = [
|
||||
@ -57,9 +57,7 @@ def getUrlProperties(filename):
|
||||
('codeCoverageURL', lambda m: m.endswith('code-coverage-gcno.zip')),
|
||||
('sdkUrl', lambda m: m.endswith(('sdk.tar.bz2', 'sdk.zip'))),
|
||||
('testPackagesUrl', lambda m: m.endswith('test_packages.json')),
|
||||
# packageUrl must be last!
|
||||
('packageUrl', lambda m: (not m.endswith('.json') and
|
||||
not m.endswith('tests.zip'))),
|
||||
('packageUrl', lambda m: m.endswith(package)),
|
||||
]
|
||||
url_re = re.compile(r'''^(https?://.*?\.(?:tar\.bz2|dmg|zip|apk|rpm|mar|tar\.gz|json))$''')
|
||||
properties = {}
|
||||
@ -102,10 +100,13 @@ if __name__ == '__main__':
|
||||
parser.add_argument("--upload-files", required=True, nargs="+",
|
||||
action="store", dest="upload_files",
|
||||
help="List of files to be uploaded.")
|
||||
parser.add_argument("--package", required=True,
|
||||
action="store", dest="package",
|
||||
help="Filename of the build package")
|
||||
args = parser.parse_args()
|
||||
|
||||
json_data = getMarProperties(args.complete_mar_file)
|
||||
json_data.update(getUrlProperties(args.upload_output))
|
||||
json_data.update(getUrlProperties(args.upload_output, args.package))
|
||||
if args.partial_mar_file:
|
||||
json_data.update(getMarProperties(args.partial_mar_file, partial=True))
|
||||
|
||||
@ -119,6 +120,7 @@ if __name__ == '__main__':
|
||||
json_data['partialInfo'] = getPartialInfo(json_data)
|
||||
|
||||
json_data['uploadFiles'] = args.upload_files
|
||||
json_data['packageFilename'] = args.package
|
||||
|
||||
with open('mach_build_properties.json', 'w') as outfile:
|
||||
json.dump(json_data, outfile, indent=4)
|
||||
|
@ -99,7 +99,7 @@ automation/l10n-check: automation/pretty-l10n-check
|
||||
automation/update-packaging: automation/pretty-update-packaging
|
||||
|
||||
automation/build: $(addprefix automation/,$(MOZ_AUTOMATION_TIERS))
|
||||
$(PYTHON) $(topsrcdir)/build/gen_mach_buildprops.py --complete-mar-file $(DIST)/$(COMPLETE_MAR) $(addprefix --partial-mar-file ,$(wildcard $(DIST)/$(PARTIAL_MAR))) --upload-output $(AUTOMATION_UPLOAD_OUTPUT) --upload-files $(abspath $(UPLOAD_FILES))
|
||||
$(PYTHON) $(topsrcdir)/build/gen_mach_buildprops.py --complete-mar-file $(DIST)/$(COMPLETE_MAR) $(addprefix --partial-mar-file ,$(wildcard $(DIST)/$(PARTIAL_MAR))) --upload-output $(AUTOMATION_UPLOAD_OUTPUT) --upload-files $(abspath $(UPLOAD_FILES)) --package $(PACKAGE)
|
||||
|
||||
# We need the log from make upload to grep it for urls in order to set
|
||||
# properties.
|
||||
|
@ -14,6 +14,8 @@ Cu.import("resource://gre/modules/AppsUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://gre/modules/Webapps.jsm");
|
||||
|
||||
Cu.importGlobalProperties(['File']);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
||||
"resource://gre/modules/FileUtils.jsm");
|
||||
|
||||
@ -284,7 +286,7 @@ this.ImportExport = {
|
||||
throw "NoBlobFound";
|
||||
}
|
||||
|
||||
let isFileBlob = aBlob instanceof Ci.nsIDOMFile;
|
||||
let isFileBlob = aBlob instanceof File;
|
||||
// We can't QI the DOMFile to nsIFile, so we need to create one.
|
||||
let zipFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
if (!isFileBlob) {
|
||||
@ -498,7 +500,7 @@ this.ImportExport = {
|
||||
throw "NoBlobFound";
|
||||
}
|
||||
|
||||
let isFileBlob = aBlob instanceof Ci.nsIDOMFile;
|
||||
let isFileBlob = aBlob instanceof File;
|
||||
// We can't QI the DOMFile to nsIFile, so we need to create one.
|
||||
let zipFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
if (!isFileBlob) {
|
||||
|
@ -177,7 +177,6 @@ ArchiveRequest::GetFilenamesResult(JSContext* aCx,
|
||||
nsTArray<nsRefPtr<File>>& aFileList)
|
||||
{
|
||||
JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, aFileList.Length()));
|
||||
nsresult rv;
|
||||
|
||||
if (!array) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
@ -188,14 +187,12 @@ ArchiveRequest::GetFilenamesResult(JSContext* aCx,
|
||||
nsRefPtr<File> file = aFileList[i];
|
||||
|
||||
nsString filename;
|
||||
rv = file->GetName(filename);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
file->GetName(filename);
|
||||
|
||||
str = JS_NewUCStringCopyZ(aCx, filename.get());
|
||||
NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
if (NS_FAILED(rv) ||
|
||||
!JS_DefineElement(aCx, array, i, str, JSPROP_ENUMERATE)) {
|
||||
if (!JS_DefineElement(aCx, array, i, str, JSPROP_ENUMERATE)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
@ -217,8 +214,7 @@ ArchiveRequest::GetFileResult(JSContext* aCx,
|
||||
nsRefPtr<File> file = aFileList[i];
|
||||
|
||||
nsString filename;
|
||||
nsresult rv = file->GetName(filename);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
file->GetName(filename);
|
||||
|
||||
if (filename == mFilename) {
|
||||
if (!ToJSValue(aCx, file, aValue)) {
|
||||
|
@ -439,22 +439,6 @@ Blob::GetInternalStream(nsIInputStream** aStream)
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// mozilla::dom::File implementation
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(File)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(File, Blob)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(File, Blob)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(File)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFile)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMFile)
|
||||
NS_INTERFACE_MAP_END_INHERITING(Blob)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(File, Blob)
|
||||
NS_IMPL_RELEASE_INHERITED(File, Blob)
|
||||
|
||||
File::File(nsISupports* aParent, BlobImpl* aImpl)
|
||||
: Blob(aParent, aImpl)
|
||||
{
|
||||
@ -553,17 +537,16 @@ File::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
return FileBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
void
|
||||
File::GetName(nsAString& aFileName)
|
||||
{
|
||||
mImpl->GetName(aFileName);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
File::GetPath(nsAString& aPath)
|
||||
void
|
||||
File::GetPath(nsAString& aPath, ErrorResult& aRv)
|
||||
{
|
||||
return mImpl->GetPath(aPath);
|
||||
mImpl->GetPath(aPath, aRv);
|
||||
}
|
||||
|
||||
Date
|
||||
@ -583,53 +566,16 @@ File::GetLastModified(ErrorResult& aRv)
|
||||
return mImpl->GetLastModified(aRv);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
File::GetLastModifiedDate(JSContext* aCx,
|
||||
JS::MutableHandle<JS::Value> aDate)
|
||||
{
|
||||
ErrorResult rv;
|
||||
Date value = GetLastModifiedDate(rv);
|
||||
if (rv.Failed()) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
if (!value.ToDateObject(aCx, aDate)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
File::GetMozFullPath(nsAString& aFileName)
|
||||
{
|
||||
ErrorResult rv;
|
||||
GetMozFullPath(aFileName, rv);
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
void
|
||||
File::GetMozFullPath(nsAString& aFilename, ErrorResult& aRv)
|
||||
{
|
||||
mImpl->GetMozFullPath(aFilename, aRv);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
File::GetMozFullPathInternal(nsAString& aFileName)
|
||||
void
|
||||
File::GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv)
|
||||
{
|
||||
ErrorResult rv;
|
||||
mImpl->GetMozFullPathInternal(aFileName, rv);
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
File::GetMozLastModifiedDate(int64_t* aDate)
|
||||
{
|
||||
MOZ_ASSERT(aDate);
|
||||
|
||||
ErrorResult rv;
|
||||
*aDate = GetLastModified(rv);
|
||||
return rv.StealNSResult();
|
||||
mImpl->GetMozFullPathInternal(aFileName, aRv);
|
||||
}
|
||||
|
||||
// Makes sure that aStart and aEnd is less then or equal to aSize and greater
|
||||
@ -817,12 +763,11 @@ BlobImplBase::GetName(nsAString& aName)
|
||||
aName = mName;
|
||||
}
|
||||
|
||||
nsresult
|
||||
BlobImplBase::GetPath(nsAString& aPath)
|
||||
void
|
||||
BlobImplBase::GetPath(nsAString& aPath, ErrorResult& aRv)
|
||||
{
|
||||
NS_ASSERTION(mIsFile, "Should only be called on files");
|
||||
aPath = mPath;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
@ -1321,9 +1266,9 @@ FileList::GetLength(uint32_t* aLength)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileList::Item(uint32_t aIndex, nsIDOMFile **aFile)
|
||||
FileList::Item(uint32_t aIndex, nsISupports** aFile)
|
||||
{
|
||||
nsRefPtr<File> file = Item(aIndex);
|
||||
nsCOMPtr<nsIDOMBlob> file = Item(aIndex);
|
||||
file.forget(aFile);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIDOMFile.h"
|
||||
#include "nsIDOMBlob.h"
|
||||
#include "nsIDOMFileList.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIMutable.h"
|
||||
@ -157,17 +157,10 @@ private:
|
||||
};
|
||||
|
||||
class File final : public Blob
|
||||
, public nsIDOMFile
|
||||
{
|
||||
friend class Blob;
|
||||
|
||||
public:
|
||||
NS_DECL_NSIDOMFILE
|
||||
NS_FORWARD_NSIDOMBLOB(Blob::)
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(File, Blob);
|
||||
|
||||
// Note: BlobImpl must be a File in order to use this method.
|
||||
// Check impl->IsFile().
|
||||
static File*
|
||||
@ -245,15 +238,18 @@ public:
|
||||
const ChromeFilePropertyBag& aBag,
|
||||
ErrorResult& aRv);
|
||||
|
||||
// XPCOM GetName is OK
|
||||
void GetName(nsAString& aName);
|
||||
|
||||
int64_t GetLastModified(ErrorResult& aRv);
|
||||
|
||||
Date GetLastModifiedDate(ErrorResult& aRv);
|
||||
|
||||
void GetPath(nsAString& aName, ErrorResult& aRv);
|
||||
|
||||
void GetMozFullPath(nsAString& aFilename, ErrorResult& aRv);
|
||||
|
||||
void GetMozFullPathInternal(nsAString& aName, ErrorResult& aRv);
|
||||
|
||||
protected:
|
||||
virtual bool HasFileInterface() const override { return true; }
|
||||
|
||||
@ -276,7 +272,7 @@ public:
|
||||
|
||||
virtual void GetName(nsAString& aName) = 0;
|
||||
|
||||
virtual nsresult GetPath(nsAString& aName) = 0;
|
||||
virtual void GetPath(nsAString& aName, ErrorResult& aRv) = 0;
|
||||
|
||||
virtual int64_t GetLastModified(ErrorResult& aRv) = 0;
|
||||
|
||||
@ -404,7 +400,7 @@ public:
|
||||
|
||||
virtual void GetName(nsAString& aName) override;
|
||||
|
||||
virtual nsresult GetPath(nsAString& aName) override;
|
||||
virtual void GetPath(nsAString& aName, ErrorResult& aRv) override;
|
||||
|
||||
virtual int64_t GetLastModified(ErrorResult& aRv) override;
|
||||
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIDOMFile.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIAsyncInputStream.h"
|
||||
|
@ -366,8 +366,7 @@ MultipartBlobImpl::InitializeChromeFile(nsPIDOMWindow* aWindow,
|
||||
}
|
||||
|
||||
// Pre-cache modified date.
|
||||
int64_t unusedDate;
|
||||
aRv = blob->GetMozLastModifiedDate(&unusedDate);
|
||||
blob->GetLastModified(aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
@ -11,10 +11,10 @@ XPIDL_SOURCES += [
|
||||
'nsIContentPolicy.idl',
|
||||
'nsIContentPolicyBase.idl',
|
||||
'nsIDocumentEncoder.idl',
|
||||
'nsIDOMBlob.idl',
|
||||
'nsIDOMDataChannel.idl',
|
||||
'nsIDOMDOMCursor.idl',
|
||||
'nsIDOMDOMRequest.idl',
|
||||
'nsIDOMFile.idl',
|
||||
'nsIDOMFileList.idl',
|
||||
'nsIDOMFileReader.idl',
|
||||
'nsIDOMFormData.idl',
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/Event.h"
|
||||
#include "mozilla/dom/PContentPermission.h"
|
||||
#include "mozilla/dom/PermissionMessageUtils.h"
|
||||
#include "mozilla/dom/PContentPermissionRequestParent.h"
|
||||
|
@ -58,6 +58,7 @@
|
||||
#include "nsIContentViewer.h"
|
||||
#include "mozilla/StyleAnimationValue.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/FileBinding.h"
|
||||
#include "mozilla/dom/DOMRect.h"
|
||||
#include <algorithm>
|
||||
|
||||
@ -2592,7 +2593,7 @@ nsDOMWindowUtils::GetContainerElement(nsIDOMElement** aResult)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::WrapDOMFile(nsIFile *aFile,
|
||||
nsIDOMFile **aDOMFile)
|
||||
nsISupports **aDOMFile)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
|
||||
|
||||
@ -2608,8 +2609,8 @@ nsDOMWindowUtils::WrapDOMFile(nsIFile *aFile,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsRefPtr<File> file = File::CreateFromFile(innerWindow, aFile);
|
||||
file.forget(aDOMFile);
|
||||
nsCOMPtr<nsIDOMBlob> blob = File::CreateFromFile(innerWindow, aFile);
|
||||
blob.forget(aDOMFile);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -2858,15 +2859,13 @@ nsDOMWindowUtils::GetFilePath(JS::HandleValue aFile, JSContext* aCx,
|
||||
|
||||
JSObject* obj = aFile.toObjectOrNull();
|
||||
|
||||
nsISupports* nativeObj =
|
||||
nsContentUtils::XPConnect()->GetNativeOfWrapper(aCx, obj);
|
||||
|
||||
nsCOMPtr<nsIDOMFile> file = do_QueryInterface(nativeObj);
|
||||
if (file) {
|
||||
File* file = nullptr;
|
||||
if (NS_SUCCEEDED(UNWRAP_OBJECT(File, obj, file))) {
|
||||
nsString filePath;
|
||||
nsresult rv = file->GetMozFullPathInternal(filePath);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
ErrorResult rv;
|
||||
file->GetMozFullPathInternal(filePath, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
_retval = filePath;
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include "nsIContentViewer.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "nsIDOMFile.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsIWebNavigation.h"
|
||||
#include "nsIWebProgress.h"
|
||||
|
@ -53,25 +53,3 @@ interface nsIDOMBlob : nsISupports
|
||||
// Return true if this blob is a memory file.
|
||||
[notxpcom] bool isMemoryFile();
|
||||
};
|
||||
|
||||
// We want to avoid multiple inheritance of nsIDOMBlob so we can downcast from
|
||||
// nsIDOMBlob to Blob safely. Our chain is:
|
||||
// - Blob -> nsIDOMBlob
|
||||
// - File -> nsIDOMFile and Blob
|
||||
[scriptable, builtinclass, uuid(cc28cf12-f1d4-44ff-843f-9289aa14613b)]
|
||||
interface nsIDOMFile : nsISupports
|
||||
{
|
||||
readonly attribute DOMString name;
|
||||
|
||||
readonly attribute DOMString path;
|
||||
|
||||
[implicit_jscontext]
|
||||
readonly attribute jsval lastModifiedDate;
|
||||
|
||||
readonly attribute DOMString mozFullPath;
|
||||
|
||||
// This performs no security checks!
|
||||
[noscript] readonly attribute DOMString mozFullPathInternal;
|
||||
|
||||
[noscript] readonly attribute int64_t mozLastModifiedDate;
|
||||
};
|
@ -5,11 +5,10 @@
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIDOMFile;
|
||||
|
||||
[uuid(283aa7b2-da81-4c72-aea2-9797b440fe34)]
|
||||
[uuid(57128a85-34de-42db-a252-84dd57724a59)]
|
||||
interface nsIDOMFileList : nsISupports
|
||||
{
|
||||
readonly attribute unsigned long length;
|
||||
nsIDOMFile item(in unsigned long index);
|
||||
// returns a DOM File object
|
||||
nsISupports item(in unsigned long index);
|
||||
};
|
||||
|
@ -26,6 +26,7 @@
|
||||
using mozilla::dom::StructuredCloneData;
|
||||
using mozilla::dom::StructuredCloneClosure;
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
bool
|
||||
nsInProcessTabChildGlobal::DoSendBlockingMessage(JSContext* aCx,
|
||||
|
@ -229,7 +229,7 @@ nsPropertyTable::SetPropertyInternal(nsPropertyOwner aObject,
|
||||
// value is destroyed
|
||||
nsresult result = NS_OK;
|
||||
PropertyListMapEntry *entry = static_cast<PropertyListMapEntry*>
|
||||
(PL_DHashTableAdd(&propertyList->mObjectValueMap, aObject, fallible));
|
||||
(PL_DHashTableAdd(&propertyList->mObjectValueMap, aObject, mozilla::fallible));
|
||||
if (!entry)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
// A nullptr entry->key is the sign that the entry has just been allocated
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "nsIQueryContentEventResult.h"
|
||||
#include "nsString.h"
|
||||
#include "nsRect.h"
|
||||
#include "Units.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/EventForwards.h"
|
||||
|
||||
|
@ -172,7 +172,7 @@ ToJSValue(JSContext* aCx,
|
||||
}
|
||||
|
||||
// Accept objects that inherit from nsISupports but not nsWrapperCache (e.g.
|
||||
// nsIDOMFile).
|
||||
// DOM File).
|
||||
template <class T>
|
||||
MOZ_WARN_UNUSED_RESULT
|
||||
typename EnableIf<!IsBaseOf<nsWrapperCache, T>::value &&
|
||||
|
@ -72,14 +72,14 @@ BEGIN_BLUETOOTH_NAMESPACE
|
||||
class BluetoothOppManager::SendFileBatch final
|
||||
{
|
||||
public:
|
||||
SendFileBatch(const nsAString& aDeviceAddress, nsIDOMBlob* aBlob)
|
||||
SendFileBatch(const nsAString& aDeviceAddress, Blob* aBlob)
|
||||
: mDeviceAddress(aDeviceAddress)
|
||||
{
|
||||
mBlobs.AppendElement(aBlob);
|
||||
}
|
||||
|
||||
nsString mDeviceAddress;
|
||||
nsCOMArray<nsIDOMBlob> mBlobs;
|
||||
nsTArray<nsRefPtr<Blob>> mBlobs;
|
||||
};
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -420,7 +420,7 @@ BluetoothOppManager::SendFile(const nsAString& aDeviceAddress,
|
||||
|
||||
bool
|
||||
BluetoothOppManager::SendFile(const nsAString& aDeviceAddress,
|
||||
nsIDOMBlob* aBlob)
|
||||
Blob* aBlob)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
@ -434,7 +434,7 @@ BluetoothOppManager::SendFile(const nsAString& aDeviceAddress,
|
||||
|
||||
void
|
||||
BluetoothOppManager::AppendBlobToSend(const nsAString& aDeviceAddress,
|
||||
nsIDOMBlob* aBlob)
|
||||
Blob* aBlob)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
@ -794,7 +794,7 @@ BluetoothOppManager::RetrieveSentFileName()
|
||||
{
|
||||
mFileName.Truncate();
|
||||
|
||||
nsCOMPtr<nsIDOMFile> file = do_QueryInterface(mBlob);
|
||||
nsRefPtr<File> file = static_cast<Blob*>(mBlob.get())->ToFile();
|
||||
if (file) {
|
||||
file->GetName(mFileName);
|
||||
}
|
||||
|
@ -14,13 +14,13 @@
|
||||
#include "mozilla/ipc/SocketBase.h"
|
||||
#include "nsCOMArray.h"
|
||||
|
||||
class nsIDOMBlob;
|
||||
class nsIOutputStream;
|
||||
class nsIInputStream;
|
||||
class nsIVolumeMountLock;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class Blob;
|
||||
class BlobParent;
|
||||
}
|
||||
}
|
||||
@ -55,7 +55,7 @@ public:
|
||||
bool Listen();
|
||||
|
||||
bool SendFile(const nsAString& aDeviceAddress, BlobParent* aActor);
|
||||
bool SendFile(const nsAString& aDeviceAddress, nsIDOMBlob* aBlob);
|
||||
bool SendFile(const nsAString& aDeviceAddress, Blob* aBlob);
|
||||
bool StopSendingFile();
|
||||
bool ConfirmReceivingFile(bool aConfirm);
|
||||
|
||||
@ -102,7 +102,7 @@ private:
|
||||
void NotifyAboutFileChange();
|
||||
bool AcquireSdcardMountLock();
|
||||
void SendObexData(uint8_t* aData, uint8_t aOpcode, int aSize);
|
||||
void AppendBlobToSend(const nsAString& aDeviceAddress, nsIDOMBlob* aBlob);
|
||||
void AppendBlobToSend(const nsAString& aDeviceAddress, Blob* aBlob);
|
||||
void DiscardBlobsToSend();
|
||||
bool ProcessNextBatch();
|
||||
void ConnectInternal(const nsAString& aDeviceAddress);
|
||||
@ -199,7 +199,7 @@ private:
|
||||
nsAutoArrayPtr<uint8_t> mReceivedDataBuffer;
|
||||
|
||||
int mCurrentBlobIndex;
|
||||
nsCOMPtr<nsIDOMBlob> mBlob;
|
||||
nsRefPtr<Blob> mBlob;
|
||||
nsTArray<SendFileBatch> mBatches;
|
||||
|
||||
/**
|
||||
|
@ -1827,7 +1827,7 @@ BluetoothServiceBluedroid::SendFile(const nsAString& aDeviceAddress,
|
||||
|
||||
void
|
||||
BluetoothServiceBluedroid::SendFile(const nsAString& aDeviceAddress,
|
||||
nsIDOMBlob* aBlob,
|
||||
Blob* aBlob,
|
||||
BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
@ -130,7 +130,7 @@ public:
|
||||
|
||||
virtual void
|
||||
SendFile(const nsAString& aDeviceAddress,
|
||||
nsIDOMBlob* aBlob,
|
||||
Blob* aBlob,
|
||||
BluetoothReplyRunnable* aRunnable);
|
||||
|
||||
virtual void
|
||||
@ -435,7 +435,7 @@ public:
|
||||
|
||||
virtual void
|
||||
SendFile(const nsAString& aDeviceAddress,
|
||||
nsIDOMBlob* aBlob,
|
||||
Blob* aBlob,
|
||||
BluetoothReplyRunnable* aRunnable);
|
||||
|
||||
virtual void
|
||||
|
@ -11,15 +11,13 @@
|
||||
#include "BluetoothProfileManagerBase.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsIDOMFile.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsTObserverArray.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
class nsIDOMBlob;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class Blob;
|
||||
class BlobChild;
|
||||
class BlobParent;
|
||||
}
|
||||
@ -241,7 +239,7 @@ public:
|
||||
|
||||
virtual void
|
||||
SendFile(const nsAString& aDeviceAddress,
|
||||
nsIDOMBlob* aBlob,
|
||||
Blob* aBlob,
|
||||
BluetoothReplyRunnable* aRunnable) = 0;
|
||||
|
||||
virtual void
|
||||
|
@ -266,7 +266,7 @@ BluetoothServiceChildProcess::SendFile(
|
||||
void
|
||||
BluetoothServiceChildProcess::SendFile(
|
||||
const nsAString& aDeviceAddress,
|
||||
nsIDOMBlob* aBlobChild,
|
||||
Blob* aBlobChild,
|
||||
BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
// Parent-process-only method
|
||||
|
@ -111,7 +111,7 @@ public:
|
||||
|
||||
virtual void
|
||||
SendFile(const nsAString& aDeviceAddress,
|
||||
nsIDOMBlob* aBlob,
|
||||
Blob* aBlob,
|
||||
BluetoothReplyRunnable* aRunnable) override;
|
||||
|
||||
virtual void
|
||||
|
@ -12,15 +12,13 @@
|
||||
#include "BluetoothProfileManagerBase.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsIDOMFile.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsTObserverArray.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
class nsIDOMBlob;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class Blob;
|
||||
class BlobChild;
|
||||
class BlobParent;
|
||||
}
|
||||
@ -295,7 +293,7 @@ public:
|
||||
|
||||
virtual void
|
||||
SendFile(const nsAString& aDeviceAddress,
|
||||
nsIDOMBlob* aBlob,
|
||||
Blob* aBlob,
|
||||
BluetoothReplyRunnable* aRunnable) = 0;
|
||||
|
||||
virtual void
|
||||
|
@ -316,7 +316,7 @@ BluetoothServiceChildProcess::SendFile(
|
||||
void
|
||||
BluetoothServiceChildProcess::SendFile(
|
||||
const nsAString& aDeviceAddress,
|
||||
nsIDOMBlob* aBlobChild,
|
||||
Blob* aBlobChild,
|
||||
BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
// Parent-process-only method
|
||||
|
@ -140,7 +140,7 @@ public:
|
||||
|
||||
virtual void
|
||||
SendFile(const nsAString& aDeviceAddress,
|
||||
nsIDOMBlob* aBlob,
|
||||
Blob* aBlob,
|
||||
BluetoothReplyRunnable* aRunnable) override;
|
||||
|
||||
virtual void
|
||||
|
@ -4161,7 +4161,7 @@ BluetoothDBusService::SendFile(const nsAString& aDeviceAddress,
|
||||
|
||||
void
|
||||
BluetoothDBusService::SendFile(const nsAString& aDeviceAddress,
|
||||
nsIDOMBlob* aBlob,
|
||||
Blob* aBlob,
|
||||
BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
@ -174,7 +174,7 @@ public:
|
||||
|
||||
virtual void
|
||||
SendFile(const nsAString& aDeviceAddress,
|
||||
nsIDOMBlob* aBlob,
|
||||
Blob* aBlob,
|
||||
BluetoothReplyRunnable* aRunnable) override;
|
||||
|
||||
virtual void
|
||||
|
@ -73,16 +73,17 @@ namespace {
|
||||
static bool sInShutdown = false;
|
||||
}
|
||||
|
||||
class mozilla::dom::bluetooth::SendFileBatch {
|
||||
class mozilla::dom::bluetooth::SendFileBatch
|
||||
{
|
||||
public:
|
||||
SendFileBatch(const nsAString& aDeviceAddress, nsIDOMBlob* aBlob)
|
||||
SendFileBatch(const nsAString& aDeviceAddress, Blob* aBlob)
|
||||
: mDeviceAddress(aDeviceAddress)
|
||||
{
|
||||
mBlobs.AppendElement(aBlob);
|
||||
}
|
||||
|
||||
nsString mDeviceAddress;
|
||||
nsCOMArray<nsIDOMBlob> mBlobs;
|
||||
nsTArray<nsRefPtr<Blob>> mBlobs;
|
||||
};
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -385,14 +386,14 @@ BluetoothOppManager::SendFile(const nsAString& aDeviceAddress,
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsRefPtr<BlobImpl> impl = aActor->GetBlobImpl();
|
||||
nsCOMPtr<nsIDOMBlob> blob = Blob::Create(nullptr, impl);
|
||||
nsRefPtr<Blob> blob = Blob::Create(nullptr, impl);
|
||||
|
||||
return SendFile(aDeviceAddress, blob.get());
|
||||
return SendFile(aDeviceAddress, blob);
|
||||
}
|
||||
|
||||
bool
|
||||
BluetoothOppManager::SendFile(const nsAString& aDeviceAddress,
|
||||
nsIDOMBlob* aBlob)
|
||||
Blob* aBlob)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
@ -406,7 +407,7 @@ BluetoothOppManager::SendFile(const nsAString& aDeviceAddress,
|
||||
|
||||
void
|
||||
BluetoothOppManager::AppendBlobToSend(const nsAString& aDeviceAddress,
|
||||
nsIDOMBlob* aBlob)
|
||||
Blob* aBlob)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
@ -766,7 +767,7 @@ BluetoothOppManager::RetrieveSentFileName()
|
||||
{
|
||||
mFileName.Truncate();
|
||||
|
||||
nsCOMPtr<nsIDOMFile> file = do_QueryInterface(mBlob);
|
||||
nsRefPtr<File> file = mBlob->ToFile();
|
||||
if (file) {
|
||||
file->GetName(mFileName);
|
||||
}
|
||||
|
@ -14,13 +14,13 @@
|
||||
#include "mozilla/ipc/SocketBase.h"
|
||||
#include "nsCOMArray.h"
|
||||
|
||||
class nsIDOMBlob;
|
||||
class nsIOutputStream;
|
||||
class nsIInputStream;
|
||||
class nsIVolumeMountLock;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class Blob;
|
||||
class BlobParent;
|
||||
}
|
||||
}
|
||||
@ -51,7 +51,7 @@ public:
|
||||
bool Listen();
|
||||
|
||||
bool SendFile(const nsAString& aDeviceAddress, BlobParent* aActor);
|
||||
bool SendFile(const nsAString& aDeviceAddress, nsIDOMBlob* aBlob);
|
||||
bool SendFile(const nsAString& aDeviceAddress, Blob* aBlob);
|
||||
bool StopSendingFile();
|
||||
bool ConfirmReceivingFile(bool aConfirm);
|
||||
|
||||
@ -96,7 +96,7 @@ private:
|
||||
void NotifyAboutFileChange();
|
||||
bool AcquireSdcardMountLock();
|
||||
void SendObexData(uint8_t* aData, uint8_t aOpcode, int aSize);
|
||||
void AppendBlobToSend(const nsAString& aDeviceAddress, nsIDOMBlob* aBlob);
|
||||
void AppendBlobToSend(const nsAString& aDeviceAddress, Blob* aBlob);
|
||||
void DiscardBlobsToSend();
|
||||
bool ProcessNextBatch();
|
||||
void ConnectInternal(const nsAString& aDeviceAddress);
|
||||
@ -193,7 +193,7 @@ private:
|
||||
nsAutoArrayPtr<uint8_t> mReceivedDataBuffer;
|
||||
|
||||
int mCurrentBlobIndex;
|
||||
nsCOMPtr<nsIDOMBlob> mBlob;
|
||||
nsRefPtr<Blob> mBlob;
|
||||
nsTArray<SendFileBatch> mBatches;
|
||||
|
||||
/**
|
||||
|
@ -6,8 +6,6 @@
|
||||
|
||||
#include "InternalResponse.h"
|
||||
|
||||
#include "nsIDOMFile.h"
|
||||
|
||||
#include "mozilla/dom/InternalHeaders.h"
|
||||
#include "nsStreamUtils.h"
|
||||
#include "nsSerializationHelper.h"
|
||||
|
@ -647,16 +647,22 @@ HTMLCanvasElement::MozGetAsFile(const nsAString& aName,
|
||||
const nsAString& aType,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIDOMFile> file;
|
||||
nsCOMPtr<nsISupports> file;
|
||||
aRv = MozGetAsFile(aName, aType, getter_AddRefs(file));
|
||||
nsRefPtr<File> tmp = static_cast<File*>(file.get());
|
||||
return tmp.forget();
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(file);
|
||||
nsRefPtr<Blob> domBlob = static_cast<Blob*>(blob.get());
|
||||
MOZ_ASSERT(domBlob->IsFile());
|
||||
return domBlob->ToFile();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLCanvasElement::MozGetAsFile(const nsAString& aName,
|
||||
const nsAString& aType,
|
||||
nsIDOMFile** aResult)
|
||||
nsISupports** aResult)
|
||||
{
|
||||
OwnerDoc()->WarnOnceAbout(nsIDocument::eMozGetAsFile);
|
||||
|
||||
@ -672,7 +678,7 @@ HTMLCanvasElement::MozGetAsFile(const nsAString& aName,
|
||||
nsresult
|
||||
HTMLCanvasElement::MozGetAsBlobImpl(const nsAString& aName,
|
||||
const nsAString& aType,
|
||||
nsIDOMFile** aResult)
|
||||
nsISupports** aResult)
|
||||
{
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
nsAutoString type(aType);
|
||||
@ -696,7 +702,7 @@ HTMLCanvasElement::MozGetAsBlobImpl(const nsAString& aName,
|
||||
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(OwnerDoc()->GetScopeObject());
|
||||
|
||||
// The File takes ownership of the buffer
|
||||
nsRefPtr<File> file =
|
||||
nsCOMPtr<nsIDOMBlob> file =
|
||||
File::CreateMemoryFile(win, imgData, (uint32_t)imgSize, aName, type,
|
||||
PR_Now());
|
||||
|
||||
|
@ -237,7 +237,7 @@ protected:
|
||||
nsAString& aDataURL);
|
||||
nsresult MozGetAsBlobImpl(const nsAString& aName,
|
||||
const nsAString& aType,
|
||||
nsIDOMFile** aResult);
|
||||
nsISupports** aResult);
|
||||
void CallPrintCallback();
|
||||
|
||||
CanvasContextType mCurrentContextType;
|
||||
|
@ -405,7 +405,9 @@ public:
|
||||
MOZ_ASSERT(blobImpl);
|
||||
blobImpl->SetPath(Substring(path, 0, uint32_t(length)));
|
||||
}
|
||||
*aResult = domFile.forget().downcast<nsIDOMFile>().take();
|
||||
|
||||
nsCOMPtr<nsIDOMBlob> blob = domFile.get();
|
||||
blob.forget(aResult);
|
||||
LookupAndCacheNext();
|
||||
return NS_OK;
|
||||
}
|
||||
@ -488,23 +490,28 @@ NS_IMPL_ISUPPORTS(DirPickerRecursiveFileEnumerator, nsISimpleEnumerator)
|
||||
|
||||
/**
|
||||
* This may return nullptr if aDomFile's implementation of
|
||||
* nsIDOMFile::mozFullPathInternal does not successfully return a non-empty
|
||||
* File::mozFullPathInternal does not successfully return a non-empty
|
||||
* string that is a valid path. This can happen on Firefox OS, for example,
|
||||
* where the file picker can create Blobs.
|
||||
*/
|
||||
static already_AddRefed<nsIFile>
|
||||
DOMFileToLocalFile(nsIDOMFile* aDomFile)
|
||||
DOMFileToLocalFile(File* aDomFile)
|
||||
{
|
||||
nsString path;
|
||||
nsresult rv = aDomFile->GetMozFullPathInternal(path);
|
||||
if (NS_FAILED(rv) || path.IsEmpty()) {
|
||||
ErrorResult rv;
|
||||
aDomFile->GetMozFullPathInternal(path, rv);
|
||||
if (rv.Failed() || path.IsEmpty()) {
|
||||
rv.SuppressException();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> localFile;
|
||||
rv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(path), true,
|
||||
getter_AddRefs(localFile));
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return localFile.forget();
|
||||
}
|
||||
@ -532,9 +539,9 @@ public:
|
||||
nsCOMPtr<nsISupports> tmp;
|
||||
while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) {
|
||||
iter->GetNext(getter_AddRefs(tmp));
|
||||
nsCOMPtr<nsIDOMFile> domFile = do_QueryInterface(tmp);
|
||||
MOZ_ASSERT(domFile);
|
||||
mFileList.AppendElement(static_cast<File*>(domFile.get()));
|
||||
nsCOMPtr<nsIDOMBlob> domBlob = do_QueryInterface(tmp);
|
||||
MOZ_ASSERT(domBlob);
|
||||
mFileList.AppendElement(static_cast<File*>(domBlob.get()));
|
||||
mFileListLength = mFileList.Length();
|
||||
if (mCanceled) {
|
||||
MOZ_ASSERT(!mInput, "This is bad - how did this happen?");
|
||||
@ -691,20 +698,23 @@ HTMLInputElement::nsFilePickerShownCallback::Done(int16_t aResult)
|
||||
|
||||
while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) {
|
||||
iter->GetNext(getter_AddRefs(tmp));
|
||||
nsCOMPtr<nsIDOMFile> domFile = do_QueryInterface(tmp);
|
||||
NS_WARN_IF_FALSE(domFile,
|
||||
nsCOMPtr<nsIDOMBlob> domBlob = do_QueryInterface(tmp);
|
||||
NS_WARN_IF_FALSE(domBlob,
|
||||
"Null file object from FilePicker's file enumerator?");
|
||||
if (domFile) {
|
||||
newFiles.AppendElement(static_cast<File*>(domFile.get()));
|
||||
if (domBlob) {
|
||||
newFiles.AppendElement(static_cast<File*>(domBlob.get()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(mode == static_cast<int16_t>(nsIFilePicker::modeOpen));
|
||||
nsCOMPtr<nsIDOMFile> domFile;
|
||||
nsresult rv = mFilePicker->GetDomfile(getter_AddRefs(domFile));
|
||||
nsCOMPtr<nsISupports> tmp;
|
||||
nsresult rv = mFilePicker->GetDomfile(getter_AddRefs(tmp));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (domFile) {
|
||||
newFiles.AppendElement(static_cast<File*>(domFile.get()));
|
||||
|
||||
nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(tmp);
|
||||
if (blob) {
|
||||
nsRefPtr<File> file = static_cast<Blob*>(blob.get())->ToFile();
|
||||
newFiles.AppendElement(file);
|
||||
}
|
||||
}
|
||||
|
||||
@ -969,7 +979,11 @@ HTMLInputElement::InitFilePicker(FilePickerType aType)
|
||||
aType != FILE_PICKER_DIRECTORY) {
|
||||
nsString path;
|
||||
|
||||
oldFiles[0]->GetMozFullPathInternal(path);
|
||||
ErrorResult error;
|
||||
oldFiles[0]->GetMozFullPathInternal(path, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> localFile;
|
||||
rv = NS_NewLocalFile(path, false, getter_AddRefs(localFile));
|
||||
@ -1708,7 +1722,12 @@ HTMLInputElement::GetValueInternal(nsAString& aValue) const
|
||||
// XXX We'd love to assert that this can't happen, but some mochitests
|
||||
// use SpecialPowers to circumvent our more sane security model.
|
||||
if (!mFiles.IsEmpty()) {
|
||||
return mFiles[0]->GetMozFullPath(aValue);
|
||||
ErrorResult rv;
|
||||
mFiles[0]->GetMozFullPath(aValue, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
else {
|
||||
aValue.Truncate();
|
||||
@ -1716,8 +1735,10 @@ HTMLInputElement::GetValueInternal(nsAString& aValue) const
|
||||
#endif
|
||||
} else {
|
||||
// Just return the leaf name
|
||||
if (mFiles.IsEmpty() || NS_FAILED(mFiles[0]->GetName(aValue))) {
|
||||
if (mFiles.IsEmpty()) {
|
||||
aValue.Truncate();
|
||||
} else {
|
||||
mFiles[0]->GetName(aValue);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2307,11 +2328,16 @@ HTMLInputElement::FlushFrames()
|
||||
}
|
||||
|
||||
void
|
||||
HTMLInputElement::MozGetFileNameArray(nsTArray< nsString >& aArray)
|
||||
HTMLInputElement::MozGetFileNameArray(nsTArray<nsString>& aArray,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
for (uint32_t i = 0; i < mFiles.Length(); i++) {
|
||||
nsString str;
|
||||
mFiles[i]->GetMozFullPathInternal(str);
|
||||
mFiles[i]->GetMozFullPathInternal(str, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
aArray.AppendElement(str);
|
||||
}
|
||||
}
|
||||
@ -2326,8 +2352,12 @@ HTMLInputElement::MozGetFileNameArray(uint32_t* aLength, char16_t*** aFileNames)
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
ErrorResult rv;
|
||||
nsTArray<nsString> array;
|
||||
MozGetFileNameArray(array);
|
||||
MozGetFileNameArray(array, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
*aLength = array.Length();
|
||||
char16_t** ret =
|
||||
@ -2687,7 +2717,11 @@ HTMLInputElement::AfterSetFiles(bool aSetValueChanged)
|
||||
if (mFiles.IsEmpty()) {
|
||||
mFirstFilePath.Truncate();
|
||||
} else {
|
||||
mFiles[0]->GetMozFullPath(mFirstFilePath);
|
||||
ErrorResult rv;
|
||||
mFiles[0]->GetMozFullPath(mFirstFilePath, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -713,7 +713,7 @@ public:
|
||||
|
||||
int32_t GetTextLength(ErrorResult& aRv);
|
||||
|
||||
void MozGetFileNameArray(nsTArray< nsString >& aFileNames);
|
||||
void MozGetFileNameArray(nsTArray<nsString>& aFileNames, ErrorResult& aRv);
|
||||
|
||||
void MozSetFileNameArray(const Sequence< nsString >& aFileNames, ErrorResult& aRv);
|
||||
void MozSetFileArray(const Sequence<OwningNonNull<File>>& aFiles);
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include "nsAttrValueInlines.h"
|
||||
#include "nsISaveAsCharset.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIDOMFile.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "nsStringStream.h"
|
||||
#include "nsIURI.h"
|
||||
@ -451,15 +450,13 @@ nsFSMultipartFormData::AddNameFilePair(const nsAString& aName,
|
||||
nsCOMPtr<nsIInputStream> fileStream;
|
||||
if (aFile) {
|
||||
nsAutoString filename16;
|
||||
rv = aFile->GetName(filename16);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
aFile->GetName(filename16);
|
||||
|
||||
ErrorResult error;
|
||||
nsAutoString filepath16;
|
||||
rv = aFile->GetPath(filepath16);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
aFile->GetPath(filepath16, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
if (!filepath16.IsEmpty()) {
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDebug.h"
|
||||
#include "nsError.h"
|
||||
#include "nsIDOMFile.h"
|
||||
#include "nsIPrincipal.h"
|
||||
|
||||
namespace mozilla {
|
||||
@ -328,7 +327,7 @@ IDBMutableFile::GetFileId() const
|
||||
return mFileInfo->Id();
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDOMFile>
|
||||
already_AddRefed<File>
|
||||
IDBMutableFile::CreateFileObject(IDBFileHandle* aFileHandle,
|
||||
MetadataParameters* aMetadataParams)
|
||||
{
|
||||
@ -393,12 +392,10 @@ GetFileHelper::GetSuccessResult(JSContext* aCx,
|
||||
|
||||
auto fileHandle = static_cast<IDBFileHandle*>(mFileHandle.get());
|
||||
|
||||
nsCOMPtr<nsIDOMFile> domFile =
|
||||
nsRefPtr<File> domFile =
|
||||
mMutableFile->CreateFileObject(fileHandle, mParams);
|
||||
|
||||
nsresult rv =
|
||||
nsContentUtils::WrapNative(aCx, domFile, &NS_GET_IID(nsIDOMFile), aVal);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
if (!ToJSValue(aCx, domFile, aVal)) {
|
||||
return NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
|
||||
class nsIDOMFile;
|
||||
class nsPIDOMWindow;
|
||||
|
||||
namespace mozilla {
|
||||
@ -28,6 +27,7 @@ class ErrorResult;
|
||||
namespace dom {
|
||||
|
||||
class DOMRequest;
|
||||
class File;
|
||||
class MetadataParameters;
|
||||
|
||||
namespace indexedDB {
|
||||
@ -83,7 +83,7 @@ public:
|
||||
return mFileInfo;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDOMFile>
|
||||
already_AddRefed<File>
|
||||
CreateFileObject(IDBFileHandle* aFileHandle,
|
||||
MetadataParameters* aMetadataParams);
|
||||
|
||||
|
@ -334,14 +334,14 @@ StructuredCloneWriteCallback(JSContext* aCx,
|
||||
|
||||
nsRefPtr<File> file = blob->ToFile();
|
||||
if (file) {
|
||||
int64_t lastModifiedDate;
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
|
||||
file->GetMozLastModifiedDate(&lastModifiedDate)));
|
||||
ErrorResult rv;
|
||||
int64_t lastModifiedDate = file->GetLastModified(rv);
|
||||
MOZ_ALWAYS_TRUE(!rv.Failed());
|
||||
|
||||
lastModifiedDate = NativeEndian::swapToLittleEndian(lastModifiedDate);
|
||||
|
||||
nsString name;
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(file->GetName(name)));
|
||||
file->GetName(name);
|
||||
|
||||
NS_ConvertUTF16toUTF8 convName(name);
|
||||
uint32_t convNameLength =
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include "mozilla/dom/DOMStringList.h"
|
||||
#include "mozilla/ipc/BackgroundChild.h"
|
||||
#include "nsIAppShell.h"
|
||||
#include "nsIDOMFile.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsTHashtable.h"
|
||||
|
@ -94,12 +94,11 @@ function verifyBlob(blob1, blob2, fileId, blobReadHandler)
|
||||
{
|
||||
is(blob1 instanceof Components.interfaces.nsIDOMBlob, true,
|
||||
"Instance of nsIDOMBlob");
|
||||
is(blob1 instanceof Components.interfaces.nsIDOMFile,
|
||||
blob2 instanceof Components.interfaces.nsIDOMFile,
|
||||
"Instance of nsIDOMFile");
|
||||
is(blob1 instanceof File, blob2 instanceof File,
|
||||
"Instance of DOM File");
|
||||
is(blob1.size, blob2.size, "Correct size");
|
||||
is(blob1.type, blob2.type, "Correct type");
|
||||
if (blob2 instanceof Components.interfaces.nsIDOMFile) {
|
||||
if (blob2 instanceof File) {
|
||||
is(blob1.name, blob2.name, "Correct name");
|
||||
}
|
||||
is(utils.getFileId(blob1), fileId, "Correct file id");
|
||||
|
@ -39,8 +39,6 @@ interface nsIDOMStyleSheet;
|
||||
interface nsITransferable;
|
||||
interface nsIQueryContentEventResult;
|
||||
interface nsIDOMWindow;
|
||||
interface nsIDOMBlob;
|
||||
interface nsIDOMFile;
|
||||
interface nsIFile;
|
||||
interface nsIDOMClientRect;
|
||||
interface nsIURI;
|
||||
@ -51,7 +49,7 @@ interface nsIJSRAIIHelper;
|
||||
interface nsIContentPermissionRequest;
|
||||
interface nsIObserver;
|
||||
|
||||
[scriptable, uuid(1a75c351-d115-4d51-94df-731dd1723a1f)]
|
||||
[scriptable, uuid(34a42cdc-7a04-4e71-8a5c-63e092fba58e)]
|
||||
interface nsIDOMWindowUtils : nsISupports {
|
||||
|
||||
/**
|
||||
@ -1445,9 +1443,10 @@ interface nsIDOMWindowUtils : nsISupports {
|
||||
in AString value2);
|
||||
|
||||
/**
|
||||
* Wrap an nsIFile in an nsIDOMFile
|
||||
* Wrap an nsIFile in an DOM File
|
||||
* Returns a File object.
|
||||
*/
|
||||
nsIDOMFile wrapDOMFile(in nsIFile aFile);
|
||||
nsISupports wrapDOMFile(in nsIFile aFile);
|
||||
|
||||
/**
|
||||
* Get the type of the currently focused html input, if any.
|
||||
|
@ -16,11 +16,10 @@
|
||||
*/
|
||||
|
||||
interface nsIDOMBlob;
|
||||
interface nsIDOMFile;
|
||||
interface nsIVariant;
|
||||
interface nsIInputStreamCallback;
|
||||
|
||||
[uuid(8978d1c5-2981-4678-a1c3-b0b7bae04fbc)]
|
||||
[uuid(2c984658-2e7c-4774-8ac5-cf1b39f8bec3)]
|
||||
interface nsIDOMHTMLCanvasElement : nsISupports
|
||||
{
|
||||
attribute unsigned long width;
|
||||
@ -38,7 +37,8 @@ interface nsIDOMHTMLCanvasElement : nsISupports
|
||||
// Valid calls are
|
||||
// mozGetAsFile(name); -- defaults to image/png
|
||||
// mozGetAsFile(name, type); -- uses given type
|
||||
nsIDOMFile mozGetAsFile(in DOMString name, [optional] in DOMString type);
|
||||
// The return value is a File object.
|
||||
nsISupports mozGetAsFile(in DOMString name, [optional] in DOMString type);
|
||||
|
||||
// A Mozilla-only extension to get a canvas context backed by double-buffered
|
||||
// shared memory. Only privileged callers can call this.
|
||||
|
@ -2064,8 +2064,8 @@ public:
|
||||
virtual void
|
||||
GetName(nsAString& aName) override;
|
||||
|
||||
virtual nsresult
|
||||
GetPath(nsAString& aPath) override;
|
||||
virtual void
|
||||
GetPath(nsAString& aPath, ErrorResult& aRv) override;
|
||||
|
||||
virtual int64_t
|
||||
GetLastModified(ErrorResult& aRv) override;
|
||||
@ -2742,11 +2742,11 @@ RemoteBlobImpl::GetName(nsAString& aName)
|
||||
mBlobImpl->GetName(aName);
|
||||
}
|
||||
|
||||
nsresult
|
||||
void
|
||||
BlobParent::
|
||||
RemoteBlobImpl::GetPath(nsAString& aPath)
|
||||
RemoteBlobImpl::GetPath(nsAString& aPath, ErrorResult& aRv)
|
||||
{
|
||||
return mBlobImpl->GetPath(aPath);
|
||||
mBlobImpl->GetPath(aPath, aRv);
|
||||
}
|
||||
|
||||
int64_t
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
#include "nsDirectoryService.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#endif
|
||||
@ -20,74 +21,100 @@ namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
|
||||
static already_AddRefed<nsIFile>
|
||||
GetLowIntegrityTemp()
|
||||
{
|
||||
MOZ_ASSERT(nsDirectoryService::gService,
|
||||
"GetLowIntegrityTemp relies on nsDirectoryService being initialized");
|
||||
|
||||
// A low integrity temp only currently makes sense for sandbox pref level 1.
|
||||
if (Preferences::GetInt("security.sandbox.content.level") != 1) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> lowIntegrityTemp;
|
||||
nsresult rv = nsDirectoryService::gService->Get(NS_WIN_LOW_INTEGRITY_TEMP,
|
||||
NS_GET_IID(nsIFile),
|
||||
getter_AddRefs(lowIntegrityTemp));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return lowIntegrityTemp.forget();
|
||||
}
|
||||
|
||||
static void
|
||||
SetUpSandboxEnvironment()
|
||||
{
|
||||
MOZ_ASSERT(nsDirectoryService::gService,
|
||||
"SetUpSandboxEnvironment relies on nsDirectoryService being initialized");
|
||||
|
||||
// Setup to use a low integrity temp if available.
|
||||
nsCOMPtr<nsIFile> lowIntegrityTemp = GetLowIntegrityTemp();
|
||||
if (!lowIntegrityTemp) {
|
||||
// A low integrity temp only currently makes sense for Vista or Later and
|
||||
// sandbox pref level 1.
|
||||
if (!IsVistaOrLater() ||
|
||||
Preferences::GetInt("security.sandbox.content.level") != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAdoptingString tempDirSuffix =
|
||||
Preferences::GetString("security.sandbox.content.tempDirSuffix");
|
||||
if (tempDirSuffix.IsEmpty()) {
|
||||
NS_WARNING("Low integrity temp suffix pref not set.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the base low integrity Mozilla temp directory.
|
||||
nsCOMPtr<nsIFile> lowIntegrityTemp;
|
||||
nsresult rv = nsDirectoryService::gService->Get(NS_WIN_LOW_INTEGRITY_TEMP_BASE,
|
||||
NS_GET_IID(nsIFile),
|
||||
getter_AddRefs(lowIntegrityTemp));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Append our profile specific temp name.
|
||||
rv = lowIntegrityTemp->Append(NS_LITERAL_STRING("Temp-") + tempDirSuffix);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Change the gecko defined temp directory to our low integrity one.
|
||||
// Undefine returns a failure if the property is not already set.
|
||||
unused << nsDirectoryService::gService->Undefine(NS_OS_TEMP_DIR);
|
||||
nsresult rv = nsDirectoryService::gService->Set(NS_OS_TEMP_DIR, lowIntegrityTemp);
|
||||
rv = nsDirectoryService::gService->Set(NS_OS_TEMP_DIR, lowIntegrityTemp);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set TEMP and TMP environment variables.
|
||||
nsAutoString lowIntegrityTempPath;
|
||||
rv = lowIntegrityTemp->GetPath(lowIntegrityTempPath);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool setOK = SetEnvironmentVariableW(L"TEMP", lowIntegrityTempPath.get());
|
||||
NS_WARN_IF_FALSE(setOK, "Failed to set TEMP to low integrity temp path");
|
||||
setOK = SetEnvironmentVariableW(L"TMP", lowIntegrityTempPath.get());
|
||||
NS_WARN_IF_FALSE(setOK, "Failed to set TMP to low integrity temp path");
|
||||
}
|
||||
|
||||
#if defined(NIGHTLY_BUILD)
|
||||
static void
|
||||
CleanUpSandboxEnvironment()
|
||||
CleanUpOldSandboxEnvironment()
|
||||
{
|
||||
// Remove low integrity temp if it exists.
|
||||
nsCOMPtr<nsIFile> lowIntegrityTemp = GetLowIntegrityTemp();
|
||||
if (!lowIntegrityTemp) {
|
||||
// Temporary code to clean up the old low integrity temp directories.
|
||||
// The removal of this is tracked by bug 1165818.
|
||||
nsCOMPtr<nsIFile> lowIntegrityMozilla;
|
||||
nsresult rv = NS_GetSpecialDirectory(NS_WIN_LOCAL_APPDATA_LOW_DIR,
|
||||
getter_AddRefs(lowIntegrityMozilla));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't check the return value as the directory will only have been created
|
||||
// if it has been used.
|
||||
unused << lowIntegrityTemp->Remove(/* aRecursive */ true);
|
||||
rv = lowIntegrityMozilla->Append(NS_LITERAL_STRING(MOZ_USER_DIR));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISimpleEnumerator> iter;
|
||||
rv = lowIntegrityMozilla->GetDirectoryEntries(getter_AddRefs(iter));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool more;
|
||||
nsCOMPtr<nsISupports> elem;
|
||||
while (NS_SUCCEEDED(iter->HasMoreElements(&more)) && more) {
|
||||
rv = iter->GetNext(getter_AddRefs(elem));
|
||||
if (NS_FAILED(rv)) {
|
||||
break;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> file = do_QueryInterface(elem);
|
||||
if (!file) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsAutoString leafName;
|
||||
rv = file->GetLeafName(leafName);
|
||||
if (NS_FAILED(rv)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (leafName.Find(NS_LITERAL_STRING("MozTemp-{")) == 0) {
|
||||
file->Remove(/* aRecursive */ true);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void
|
||||
ContentProcess::SetAppDir(const nsACString& aPath)
|
||||
@ -114,8 +141,8 @@ ContentProcess::Init()
|
||||
void
|
||||
ContentProcess::CleanUp()
|
||||
{
|
||||
#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
|
||||
CleanUpSandboxEnvironment();
|
||||
#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX) && defined(NIGHTLY_BUILD)
|
||||
CleanUpOldSandboxEnvironment();
|
||||
#endif
|
||||
mXREEmbed.Stop();
|
||||
}
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMFile.h"
|
||||
#include "nsIDOMWindow.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
|
@ -7,7 +7,6 @@
|
||||
#ifndef mozilla_dom_FilePickerParent_h
|
||||
#define mozilla_dom_FilePickerParent_h
|
||||
|
||||
#include "nsIDOMFile.h"
|
||||
#include "nsIEventTarget.h"
|
||||
#include "nsIFilePicker.h"
|
||||
#include "nsCOMArray.h"
|
||||
|
@ -901,6 +901,7 @@ MediaFormatReader::Update(TrackType aTrack)
|
||||
LOGV("Update(%s) ni=%d no=%d", TrackTypeToStr(aTrack), needInput, needOutput);
|
||||
|
||||
if (decoder.mDemuxEOS && !decoder.mDemuxEOSServiced) {
|
||||
decoder.mOutputRequested = true;
|
||||
decoder.mDecoder->Drain();
|
||||
decoder.mDemuxEOSServiced = true;
|
||||
}
|
||||
|
@ -113,6 +113,7 @@ GetMediaManagerLog()
|
||||
}
|
||||
#define LOG(msg) PR_LOG(GetMediaManagerLog(), PR_LOG_DEBUG, msg)
|
||||
|
||||
using dom::File;
|
||||
using dom::MediaStreamConstraints;
|
||||
using dom::MediaTrackConstraintSet;
|
||||
using dom::MediaTrackConstraints;
|
||||
@ -264,53 +265,6 @@ private:
|
||||
nsRefPtr<MediaManager> mManager; // get ref to this when creating the runnable
|
||||
};
|
||||
|
||||
/**
|
||||
* Invoke the "onSuccess" callback in content. The callback will take a
|
||||
* DOMBlob in the case of {picture:true}, and a MediaStream in the case of
|
||||
* {audio:true} or {video:true}. There is a constructor available for each
|
||||
* form. Do this only on the main thread.
|
||||
*/
|
||||
class SuccessCallbackRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
SuccessCallbackRunnable(
|
||||
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback>& aOnSuccess,
|
||||
nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aOnFailure,
|
||||
nsIDOMFile* aFile, uint64_t aWindowID)
|
||||
: mFile(aFile)
|
||||
, mWindowID(aWindowID)
|
||||
, mManager(MediaManager::GetInstance())
|
||||
{
|
||||
mOnSuccess.swap(aOnSuccess);
|
||||
mOnFailure.swap(aOnFailure);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Run()
|
||||
{
|
||||
// Only run if the window is still active.
|
||||
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
||||
|
||||
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> onSuccess = mOnSuccess.forget();
|
||||
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onFailure = mOnFailure.forget();
|
||||
|
||||
if (!(mManager->IsWindowStillActive(mWindowID))) {
|
||||
return NS_OK;
|
||||
}
|
||||
// This is safe since we're on main-thread, and the windowlist can only
|
||||
// be invalidated from the main-thread (see OnNavigation)
|
||||
onSuccess->OnSuccess(mFile);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mOnSuccess;
|
||||
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure;
|
||||
nsCOMPtr<nsIDOMFile> mFile;
|
||||
uint64_t mWindowID;
|
||||
nsRefPtr<MediaManager> mManager; // get ref to this when creating the runnable
|
||||
};
|
||||
|
||||
/**
|
||||
* Invoke the GetUserMediaDevices success callback. Wrapped in a runnable
|
||||
* so that it may be called on the main thread. The error callback is also
|
||||
|
@ -112,7 +112,7 @@ protected:
|
||||
mozilla::ReentrantMonitor mCallbackMonitor; // Monitor for camera callback handling
|
||||
// This is only modified on MainThread (AllocImpl and DeallocImpl)
|
||||
nsRefPtr<ICameraControl> mCameraControl;
|
||||
nsCOMPtr<nsIDOMFile> mLastCapture;
|
||||
nsRefPtr<dom::File> mLastCapture;
|
||||
|
||||
android::sp<android::GonkCameraSource> mCameraSource;
|
||||
|
||||
|
@ -210,7 +210,7 @@ interface nsINfcContentHelper : nsISupports
|
||||
*
|
||||
* @param blob
|
||||
* Raw data of the file to be sent. This object represents a file-like
|
||||
* (nsIDOMFile) object of immutable, raw data. The blob data needs
|
||||
* (DOM File) object of immutable, raw data. The blob data needs
|
||||
* to be 'object wrapped' before calling this interface.
|
||||
*
|
||||
* @param sessionToken
|
||||
|
@ -89,151 +89,161 @@ this.PushDB.prototype = {
|
||||
/*
|
||||
* @param aChannelRecord
|
||||
* The record to be added.
|
||||
* @param aSuccessCb
|
||||
* Callback function to invoke with result ID.
|
||||
* @param aErrorCb [optional]
|
||||
* Callback function to invoke when there was an error.
|
||||
*/
|
||||
put: function(aChannelRecord, aSuccessCb, aErrorCb) {
|
||||
put: function(aChannelRecord) {
|
||||
debug("put()" + JSON.stringify(aChannelRecord));
|
||||
|
||||
this.newTxn(
|
||||
"readwrite",
|
||||
kPUSHDB_STORE_NAME,
|
||||
function txnCb(aTxn, aStore) {
|
||||
debug("Going to put " + aChannelRecord.channelID);
|
||||
aStore.put(aChannelRecord).onsuccess = function setTxnResult(aEvent) {
|
||||
debug("Request successful. Updated record ID: " +
|
||||
aEvent.target.result);
|
||||
};
|
||||
},
|
||||
aSuccessCb,
|
||||
aErrorCb
|
||||
return new Promise((resolve, reject) =>
|
||||
this.newTxn(
|
||||
"readwrite",
|
||||
kPUSHDB_STORE_NAME,
|
||||
function txnCb(aTxn, aStore) {
|
||||
debug("Going to put " + aChannelRecord.channelID);
|
||||
aStore.put(aChannelRecord).onsuccess = function setTxnResult(aEvent) {
|
||||
debug("Request successful. Updated record ID: " +
|
||||
aEvent.target.result);
|
||||
};
|
||||
},
|
||||
resolve,
|
||||
reject
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
/*
|
||||
* @param aChannelID
|
||||
* The ID of record to be deleted.
|
||||
* @param aSuccessCb
|
||||
* Callback function to invoke with result.
|
||||
* @param aErrorCb [optional]
|
||||
* Callback function to invoke when there was an error.
|
||||
|
||||
*/
|
||||
delete: function(aChannelID, aSuccessCb, aErrorCb) {
|
||||
delete: function(aChannelID) {
|
||||
debug("delete()");
|
||||
|
||||
this.newTxn(
|
||||
"readwrite",
|
||||
kPUSHDB_STORE_NAME,
|
||||
function txnCb(aTxn, aStore) {
|
||||
debug("Going to delete " + aChannelID);
|
||||
aStore.delete(aChannelID);
|
||||
},
|
||||
aSuccessCb,
|
||||
aErrorCb
|
||||
return new Promise((resolve, reject) =>
|
||||
this.newTxn(
|
||||
"readwrite",
|
||||
kPUSHDB_STORE_NAME,
|
||||
function txnCb(aTxn, aStore) {
|
||||
debug("Going to delete " + aChannelID);
|
||||
aStore.delete(aChannelID);
|
||||
},
|
||||
resolve,
|
||||
reject
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
clearAll: function clear(aSuccessCb, aErrorCb) {
|
||||
this.newTxn(
|
||||
"readwrite",
|
||||
kPUSHDB_STORE_NAME,
|
||||
function (aTxn, aStore) {
|
||||
debug("Going to clear all!");
|
||||
aStore.clear();
|
||||
},
|
||||
aSuccessCb,
|
||||
aErrorCb
|
||||
clearAll: function clear() {
|
||||
return new Promise((resolve, reject) =>
|
||||
this.newTxn(
|
||||
"readwrite",
|
||||
kPUSHDB_STORE_NAME,
|
||||
function (aTxn, aStore) {
|
||||
debug("Going to clear all!");
|
||||
aStore.clear();
|
||||
},
|
||||
resolve,
|
||||
reject
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
getByPushEndpoint: function(aPushEndpoint, aSuccessCb, aErrorCb) {
|
||||
getByPushEndpoint: function(aPushEndpoint) {
|
||||
debug("getByPushEndpoint()");
|
||||
|
||||
this.newTxn(
|
||||
"readonly",
|
||||
kPUSHDB_STORE_NAME,
|
||||
function txnCb(aTxn, aStore) {
|
||||
aTxn.result = undefined;
|
||||
return new Promise((resolve, reject) =>
|
||||
this.newTxn(
|
||||
"readonly",
|
||||
kPUSHDB_STORE_NAME,
|
||||
function txnCb(aTxn, aStore) {
|
||||
aTxn.result = undefined;
|
||||
|
||||
let index = aStore.index("pushEndpoint");
|
||||
index.get(aPushEndpoint).onsuccess = function setTxnResult(aEvent) {
|
||||
aTxn.result = aEvent.target.result;
|
||||
debug("Fetch successful " + aEvent.target.result);
|
||||
}
|
||||
},
|
||||
aSuccessCb,
|
||||
aErrorCb
|
||||
let index = aStore.index("pushEndpoint");
|
||||
index.get(aPushEndpoint).onsuccess = function setTxnResult(aEvent) {
|
||||
aTxn.result = aEvent.target.result;
|
||||
debug("Fetch successful " + aEvent.target.result);
|
||||
}
|
||||
},
|
||||
resolve,
|
||||
reject
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
getByChannelID: function(aChannelID, aSuccessCb, aErrorCb) {
|
||||
getByChannelID: function(aChannelID) {
|
||||
debug("getByChannelID()");
|
||||
|
||||
this.newTxn(
|
||||
"readonly",
|
||||
kPUSHDB_STORE_NAME,
|
||||
function txnCb(aTxn, aStore) {
|
||||
aTxn.result = undefined;
|
||||
return new Promise((resolve, reject) =>
|
||||
this.newTxn(
|
||||
"readonly",
|
||||
kPUSHDB_STORE_NAME,
|
||||
function txnCb(aTxn, aStore) {
|
||||
aTxn.result = undefined;
|
||||
|
||||
aStore.get(aChannelID).onsuccess = function setTxnResult(aEvent) {
|
||||
aTxn.result = aEvent.target.result;
|
||||
debug("Fetch successful " + aEvent.target.result);
|
||||
}
|
||||
},
|
||||
aSuccessCb,
|
||||
aErrorCb
|
||||
aStore.get(aChannelID).onsuccess = function setTxnResult(aEvent) {
|
||||
aTxn.result = aEvent.target.result;
|
||||
debug("Fetch successful " + aEvent.target.result);
|
||||
}
|
||||
},
|
||||
resolve,
|
||||
reject
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
|
||||
getByScope: function(aScope, aSuccessCb, aErrorCb) {
|
||||
getByScope: function(aScope) {
|
||||
debug("getByScope() " + aScope);
|
||||
|
||||
this.newTxn(
|
||||
"readonly",
|
||||
kPUSHDB_STORE_NAME,
|
||||
function txnCb(aTxn, aStore) {
|
||||
aTxn.result = undefined;
|
||||
return new Promise((resolve, reject) =>
|
||||
this.newTxn(
|
||||
"readonly",
|
||||
kPUSHDB_STORE_NAME,
|
||||
function txnCb(aTxn, aStore) {
|
||||
aTxn.result = undefined;
|
||||
|
||||
let index = aStore.index("scope");
|
||||
index.get(aScope).onsuccess = function setTxnResult(aEvent) {
|
||||
aTxn.result = aEvent.target.result;
|
||||
debug("Fetch successful " + aEvent.target.result);
|
||||
}
|
||||
},
|
||||
aSuccessCb,
|
||||
aErrorCb
|
||||
let index = aStore.index("scope");
|
||||
index.get(aScope).onsuccess = function setTxnResult(aEvent) {
|
||||
aTxn.result = aEvent.target.result;
|
||||
debug("Fetch successful " + aEvent.target.result);
|
||||
}
|
||||
},
|
||||
resolve,
|
||||
reject
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
getAllChannelIDs: function(aSuccessCb, aErrorCb) {
|
||||
getAllChannelIDs: function() {
|
||||
debug("getAllChannelIDs()");
|
||||
|
||||
this.newTxn(
|
||||
"readonly",
|
||||
kPUSHDB_STORE_NAME,
|
||||
function txnCb(aTxn, aStore) {
|
||||
aStore.mozGetAll().onsuccess = function(event) {
|
||||
aTxn.result = event.target.result;
|
||||
}
|
||||
},
|
||||
aSuccessCb,
|
||||
aErrorCb
|
||||
return new Promise((resolve, reject) =>
|
||||
this.newTxn(
|
||||
"readonly",
|
||||
kPUSHDB_STORE_NAME,
|
||||
function txnCb(aTxn, aStore) {
|
||||
aStore.mozGetAll().onsuccess = function(event) {
|
||||
aTxn.result = event.target.result;
|
||||
}
|
||||
},
|
||||
resolve,
|
||||
reject
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
drop: function(aSuccessCb, aErrorCb) {
|
||||
drop: function() {
|
||||
debug("drop()");
|
||||
this.newTxn(
|
||||
"readwrite",
|
||||
kPUSHDB_STORE_NAME,
|
||||
function txnCb(aTxn, aStore) {
|
||||
aStore.clear();
|
||||
},
|
||||
aSuccessCb,
|
||||
aErrorCb
|
||||
|
||||
return new Promise((resolve, reject) =>
|
||||
this.newTxn(
|
||||
"readwrite",
|
||||
kPUSHDB_STORE_NAME,
|
||||
function txnCb(aTxn, aStore) {
|
||||
aStore.clear();
|
||||
},
|
||||
resolve,
|
||||
reject
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
@ -400,21 +410,31 @@ this.PushService = {
|
||||
return;
|
||||
}
|
||||
|
||||
this._db.getByScope(scope, function(record) {
|
||||
this._db.delete(records.channelID, null, function() {
|
||||
debug("webapps-clear-data: " + scope +
|
||||
" Could not delete entry " + records.channelID);
|
||||
this._db.getByScope(scope)
|
||||
.then(record => {
|
||||
this._db.delete(records.channelID)
|
||||
.then(_ => {
|
||||
// courtesy, but don't establish a connection
|
||||
// just for it
|
||||
if (this._ws) {
|
||||
debug("Had a connection, so telling the server");
|
||||
this._send("unregister", {channelID: records.channelID});
|
||||
}
|
||||
}, err => {
|
||||
debug("webapps-clear-data: " + scope +
|
||||
" Could not delete entry " + records.channelID);
|
||||
|
||||
// courtesy, but don't establish a connection
|
||||
// just for it
|
||||
if (this._ws) {
|
||||
debug("Had a connection, so telling the server");
|
||||
this._send("unregister", {channelID: records.channelID});
|
||||
}
|
||||
}.bind(this), function() {
|
||||
// courtesy, but don't establish a connection
|
||||
// just for it
|
||||
if (this._ws) {
|
||||
debug("Had a connection, so telling the server");
|
||||
this._send("unregister", {channelID: records.channelID});
|
||||
}
|
||||
throw "Database error";
|
||||
});
|
||||
}, _ => {
|
||||
debug("webapps-clear-data: Error in getByScope(" + scope + ")");
|
||||
});
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
@ -954,11 +974,12 @@ this.PushService = {
|
||||
this._beginWSSetup();
|
||||
return;
|
||||
}
|
||||
this._db.getAllChannelIDs(function(channelIDs) {
|
||||
if (channelIDs.length > 0) {
|
||||
this._beginWSSetup();
|
||||
}
|
||||
}.bind(this));
|
||||
this._db.getAllChannelIDs()
|
||||
.then(channelIDs => {
|
||||
if (channelIDs.length > 0) {
|
||||
this._beginWSSetup();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/** |delay| should be in milliseconds. */
|
||||
@ -1354,18 +1375,18 @@ this.PushService = {
|
||||
debug("Could not get channelID " + aChannelIDFromServer + " from DB");
|
||||
}
|
||||
|
||||
this._db.getByChannelID(aChannelID,
|
||||
compareRecordVersionAndNotify.bind(this),
|
||||
recoverNoSuchChannelID.bind(this));
|
||||
this._db.getByChannelID(aChannelID)
|
||||
.then(compareRecordVersionAndNotify.bind(this),
|
||||
err => recoverNoSuchChannelID(err));
|
||||
},
|
||||
|
||||
// Fires a push-register system message to all applications that have
|
||||
// registration.
|
||||
_notifyAllAppsRegister: function() {
|
||||
debug("notifyAllAppsRegister()");
|
||||
return new Promise((resolve, reject) => {
|
||||
// records are objects describing the registration as stored in IndexedDB.
|
||||
this._db.getAllChannelIDs(records => {
|
||||
// records are objects describing the registration as stored in IndexedDB.
|
||||
return this._db.getAllChannelIDs()
|
||||
.then(records => {
|
||||
let scopes = new Set();
|
||||
for (let record of records) {
|
||||
scopes.add(record.scope);
|
||||
@ -1380,9 +1401,7 @@ this.PushService = {
|
||||
);
|
||||
globalMM.broadcastAsyncMessage('pushsubscriptionchanged', scope);
|
||||
}
|
||||
resolve();
|
||||
}, reject);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
_notifyApp: function(aPushRecord) {
|
||||
@ -1428,15 +1447,11 @@ this.PushService = {
|
||||
|
||||
_updatePushRecord: function(aPushRecord) {
|
||||
debug("updatePushRecord()");
|
||||
let deferred = Promise.defer();
|
||||
this._db.put(aPushRecord, deferred.resolve, deferred.reject);
|
||||
return deferred.promise;
|
||||
return this._db.put(aPushRecord);
|
||||
},
|
||||
|
||||
_dropRegistration: function() {
|
||||
let deferred = Promise.defer();
|
||||
this._db.drop(deferred.resolve, deferred.reject);
|
||||
return deferred.promise;
|
||||
return this._db.drop();
|
||||
},
|
||||
|
||||
receiveMessage: function(aMessage) {
|
||||
@ -1474,11 +1489,8 @@ this.PushService = {
|
||||
},
|
||||
|
||||
_register: function(aPageRecord) {
|
||||
let recordPromise = new Promise((resolve, reject) =>
|
||||
this._db.getByScope(aPageRecord.scope, resolve, reject));
|
||||
|
||||
return recordPromise.then(
|
||||
pushRecord => {
|
||||
return this._db.getByScope(aPageRecord.scope)
|
||||
.then(pushRecord => {
|
||||
if (pushRecord == null) {
|
||||
let channelID = this._generateID();
|
||||
return this._registerWithServer(channelID, aPageRecord);
|
||||
@ -1603,33 +1615,24 @@ this.PushService = {
|
||||
_unregister: function(aPageRecord) {
|
||||
debug("unregisterWithServer()");
|
||||
|
||||
let deferred = Promise.defer();
|
||||
let fail = function(error) {
|
||||
debug("unregister() fail() error " + error);
|
||||
deferred.reject(error);
|
||||
};
|
||||
|
||||
if (!aPageRecord.scope) {
|
||||
fail("NotFoundError");
|
||||
return deferred.promise;
|
||||
return Promise.reject("NotFoundError");
|
||||
}
|
||||
|
||||
this._db.getByScope(aPageRecord.scope, function(record) {
|
||||
// If the endpoint didn't exist, let's just fail.
|
||||
if (record === undefined) {
|
||||
fail("NotFoundError");
|
||||
return;
|
||||
}
|
||||
return this._db.getByScope(aPageRecord.scope)
|
||||
.then(record => {
|
||||
// If the endpoint didn't exist, let's just fail.
|
||||
if (record === undefined) {
|
||||
throw "NotFoundError";
|
||||
}
|
||||
|
||||
this._db.delete(record.channelID, function() {
|
||||
// Let's be nice to the server and try to inform it, but we don't care
|
||||
// about the reply.
|
||||
this._send("unregister", {channelID: record.channelID});
|
||||
deferred.resolve();
|
||||
}.bind(this), fail);
|
||||
}.bind(this), fail);
|
||||
|
||||
return deferred.promise;
|
||||
this._db.delete(record.channelID)
|
||||
.then(_ =>
|
||||
// Let's be nice to the server and try to inform it, but we don't care
|
||||
// about the reply.
|
||||
this._send("unregister", {channelID: record.channelID})
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
unregister: function(aPageRecord, aMessageManager) {
|
||||
@ -1652,23 +1655,19 @@ this.PushService = {
|
||||
},
|
||||
|
||||
_clearAll: function _clearAll() {
|
||||
return new Promise((resolve, reject) => {
|
||||
this._db.clearAll(() => resolve(),
|
||||
() => reject("Database error"));
|
||||
});
|
||||
return this._db.clearAll();
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Called on message from the child process
|
||||
*/
|
||||
_registration: function(aPageRecord) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!aPageRecord.scope) {
|
||||
reject("Database error");
|
||||
return;
|
||||
}
|
||||
this._db.getByScope(aPageRecord.scope,
|
||||
pushRecord => {
|
||||
if (!aPageRecord.scope) {
|
||||
return Promise.reject("Database error");
|
||||
}
|
||||
|
||||
return this._db.getByScope(aPageRecord.scope)
|
||||
.then(pushRecord => {
|
||||
let registration = null;
|
||||
if (pushRecord) {
|
||||
registration = {
|
||||
@ -1678,11 +1677,10 @@ this.PushService = {
|
||||
pushCount: pushRecord.pushCount
|
||||
};
|
||||
}
|
||||
resolve(registration);
|
||||
},
|
||||
() => reject("Database error")
|
||||
);
|
||||
});
|
||||
return registration;
|
||||
}, _ => {
|
||||
throw "Database error";
|
||||
});
|
||||
},
|
||||
|
||||
registration: function(aPageRecord, aMessageManager) {
|
||||
@ -1751,8 +1749,9 @@ this.PushService = {
|
||||
};
|
||||
}
|
||||
|
||||
this._db.getAllChannelIDs(sendHelloMessage.bind(this),
|
||||
sendHelloMessage.bind(this));
|
||||
this._db.getAllChannelIDs()
|
||||
.then(sendHelloMessage.bind(this),
|
||||
sendHelloMessage.bind(this));
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -61,46 +61,6 @@ function after(times, func) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a Push database in a proxy that returns promises for all asynchronous
|
||||
* methods. This makes it easier to test the database code with Task.jsm.
|
||||
*
|
||||
* @param {PushDB} db A Push database.
|
||||
* @returns {Proxy} A proxy that traps function property gets and returns
|
||||
* promisified functions.
|
||||
*/
|
||||
function promisifyDatabase(db) {
|
||||
return new Proxy(db, {
|
||||
get(target, property) {
|
||||
let method = target[property];
|
||||
if (typeof method != 'function') {
|
||||
return method;
|
||||
}
|
||||
return function(...params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
method.call(target, ...params, resolve, reject);
|
||||
});
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears and closes an open Push database.
|
||||
*
|
||||
* @param {PushDB} db A Push database.
|
||||
* @returns {Promise} A promise that fulfills when the database is closed.
|
||||
*/
|
||||
function cleanupDatabase(db) {
|
||||
return new Promise(resolve => {
|
||||
function close() {
|
||||
db.close();
|
||||
resolve();
|
||||
}
|
||||
db.drop(close, close);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Defers one or more callbacks until the next turn of the event loop. Multiple
|
||||
* callbacks are executed in order.
|
||||
|
@ -15,9 +15,8 @@ function run_test() {
|
||||
|
||||
add_task(function* test_unregister_success() {
|
||||
let db = new PushDB();
|
||||
let promiseDB = promisifyDatabase(db);
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
yield promiseDB.put({
|
||||
do_register_cleanup(() => {return db.drop().then(_ => db.close());});
|
||||
yield db.put({
|
||||
channelID,
|
||||
pushEndpoint: 'https://example.org/update/unregister-success',
|
||||
scope: 'https://example.com/page/unregister-success',
|
||||
@ -42,6 +41,6 @@ add_task(function* test_unregister_success() {
|
||||
});
|
||||
|
||||
yield PushNotificationService.clearAll();
|
||||
let record = yield promiseDB.getByChannelID(channelID);
|
||||
let record = yield db.getByChannelID(channelID);
|
||||
ok(!record, 'Unregister did not remove record');
|
||||
});
|
||||
|
@ -20,8 +20,7 @@ function run_test() {
|
||||
|
||||
add_task(function* test_notification_ack() {
|
||||
let db = new PushDB();
|
||||
let promiseDB = promisifyDatabase(db);
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
do_register_cleanup(() => {return db.drop().then(_ => db.close());});
|
||||
let records = [{
|
||||
channelID: '21668e05-6da8-42c9-b8ab-9cc3f4d5630c',
|
||||
pushEndpoint: 'https://example.com/update/1',
|
||||
@ -39,7 +38,7 @@ add_task(function* test_notification_ack() {
|
||||
version: 3
|
||||
}];
|
||||
for (let record of records) {
|
||||
yield promiseDB.put(record);
|
||||
yield db.put(record);
|
||||
}
|
||||
|
||||
let notifyPromise = Promise.all([
|
||||
|
@ -18,8 +18,7 @@ function run_test() {
|
||||
// Should acknowledge duplicate notifications, but not notify apps.
|
||||
add_task(function* test_notification_duplicate() {
|
||||
let db = new PushDB();
|
||||
let promiseDB = promisifyDatabase(db);
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
do_register_cleanup(() => {return db.drop().then(_ => db.close());});
|
||||
let records = [{
|
||||
channelID: '8d2d9400-3597-4c5a-8a38-c546b0043bcc',
|
||||
pushEndpoint: 'https://example.org/update/1',
|
||||
@ -32,7 +31,7 @@ add_task(function* test_notification_duplicate() {
|
||||
version: 2
|
||||
}];
|
||||
for (let record of records) {
|
||||
yield promiseDB.put(record);
|
||||
yield db.put(record);
|
||||
}
|
||||
|
||||
let notifyPromise = promiseObserverNotification('push-notification');
|
||||
@ -72,11 +71,11 @@ add_task(function* test_notification_duplicate() {
|
||||
yield waitForPromise(ackDefer.promise, DEFAULT_TIMEOUT,
|
||||
'Timed out waiting for stale acknowledgement');
|
||||
|
||||
let staleRecord = yield promiseDB.getByChannelID(
|
||||
let staleRecord = yield db.getByChannelID(
|
||||
'8d2d9400-3597-4c5a-8a38-c546b0043bcc');
|
||||
strictEqual(staleRecord.version, 2, 'Wrong stale record version');
|
||||
|
||||
let updatedRecord = yield promiseDB.getByChannelID(
|
||||
let updatedRecord = yield db.getByChannelID(
|
||||
'27d1e393-03ef-4c72-a5e6-9e890dfccad0');
|
||||
strictEqual(updatedRecord.version, 3, 'Wrong updated record version');
|
||||
});
|
||||
|
@ -18,8 +18,7 @@ function run_test() {
|
||||
|
||||
add_task(function* test_notification_error() {
|
||||
let db = new PushDB();
|
||||
let promiseDB = promisifyDatabase(db);
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
do_register_cleanup(() => {return db.drop().then(_ => db.close());});
|
||||
let records = [{
|
||||
channelID: 'f04f1e46-9139-4826-b2d1-9411b0821283',
|
||||
pushEndpoint: 'https://example.org/update/success-1',
|
||||
@ -37,7 +36,7 @@ add_task(function* test_notification_error() {
|
||||
version: 3
|
||||
}];
|
||||
for (let record of records) {
|
||||
yield promiseDB.put(record);
|
||||
yield db.put(record);
|
||||
}
|
||||
|
||||
let notifyPromise = Promise.all([
|
||||
@ -56,11 +55,11 @@ add_task(function* test_notification_error() {
|
||||
PushService.init({
|
||||
networkInfo: new MockDesktopNetworkInfo(),
|
||||
db: makeStub(db, {
|
||||
getByChannelID(prev, channelID, successCb, failureCb) {
|
||||
getByChannelID(prev, channelID) {
|
||||
if (channelID == '3c3930ba-44de-40dc-a7ca-8a133ec1a866') {
|
||||
return failureCb('splines not reticulated');
|
||||
return Promise.reject('splines not reticulated');
|
||||
}
|
||||
return prev.call(this, channelID, successCb, failureCb);
|
||||
return prev.call(this, channelID);
|
||||
}
|
||||
}),
|
||||
makeWebSocket(uri) {
|
||||
@ -107,19 +106,19 @@ add_task(function* test_notification_error() {
|
||||
yield waitForPromise(ackDefer.promise, DEFAULT_TIMEOUT,
|
||||
'Timed out waiting for acknowledgements');
|
||||
|
||||
let aRecord = yield promiseDB.getByScope('https://example.com/a');
|
||||
let aRecord = yield db.getByScope('https://example.com/a');
|
||||
equal(aRecord.channelID, 'f04f1e46-9139-4826-b2d1-9411b0821283',
|
||||
'Wrong channel ID for record A');
|
||||
strictEqual(aRecord.version, 2,
|
||||
'Should return the new version for record A');
|
||||
|
||||
let bRecord = yield promiseDB.getByScope('https://example.com/b');
|
||||
let bRecord = yield db.getByScope('https://example.com/b');
|
||||
equal(bRecord.channelID, '3c3930ba-44de-40dc-a7ca-8a133ec1a866',
|
||||
'Wrong channel ID for record B');
|
||||
strictEqual(bRecord.version, 2,
|
||||
'Should return the previous version for record B');
|
||||
|
||||
let cRecord = yield promiseDB.getByScope('https://example.com/c');
|
||||
let cRecord = yield db.getByScope('https://example.com/c');
|
||||
equal(cRecord.channelID, 'b63f7bef-0a0d-4236-b41e-086a69dfd316',
|
||||
'Wrong channel ID for record C');
|
||||
strictEqual(cRecord.version, 4,
|
||||
|
@ -19,8 +19,7 @@ function run_test() {
|
||||
|
||||
add_task(function* test_notification_incomplete() {
|
||||
let db = new PushDB();
|
||||
let promiseDB = promisifyDatabase(db);
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
do_register_cleanup(() => {return db.drop().then(_ => db.close());});
|
||||
let records = [{
|
||||
channelID: '123',
|
||||
pushEndpoint: 'https://example.org/update/1',
|
||||
@ -43,7 +42,7 @@ add_task(function* test_notification_incomplete() {
|
||||
version: 10
|
||||
}];
|
||||
for (let record of records) {
|
||||
promiseDB.put(record);
|
||||
db.put(record);
|
||||
}
|
||||
|
||||
Services.obs.addObserver(function observe(subject, topic, data) {
|
||||
@ -102,7 +101,7 @@ add_task(function* test_notification_incomplete() {
|
||||
yield waitForPromise(notificationDefer.promise, DEFAULT_TIMEOUT,
|
||||
'Timed out waiting for incomplete notifications');
|
||||
|
||||
let storeRecords = yield promiseDB.getAllChannelIDs();
|
||||
let storeRecords = yield db.getAllChannelIDs();
|
||||
storeRecords.sort(({pushEndpoint: a}, {pushEndpoint: b}) =>
|
||||
compareAscending(a, b));
|
||||
recordsAreEqual(records, storeRecords);
|
||||
|
@ -16,9 +16,8 @@ function run_test() {
|
||||
|
||||
add_task(function* test_notification_version_string() {
|
||||
let db = new PushDB();
|
||||
let promiseDB = promisifyDatabase(db);
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
yield promiseDB.put({
|
||||
do_register_cleanup(() => {return db.drop().then(_ => db.close());});
|
||||
yield db.put({
|
||||
channelID: '6ff97d56-d0c0-43bc-8f5b-61b855e1d93b',
|
||||
pushEndpoint: 'https://example.org/updates/1',
|
||||
scope: 'https://example.com/page/1',
|
||||
@ -66,7 +65,7 @@ add_task(function* test_notification_version_string() {
|
||||
yield waitForPromise(ackDefer.promise, DEFAULT_TIMEOUT,
|
||||
'Timed out waiting for string acknowledgement');
|
||||
|
||||
let storeRecord = yield promiseDB.getByChannelID(
|
||||
let storeRecord = yield db.getByChannelID(
|
||||
'6ff97d56-d0c0-43bc-8f5b-61b855e1d93b');
|
||||
strictEqual(storeRecord.version, 4, 'Wrong record version');
|
||||
});
|
||||
|
@ -18,8 +18,7 @@ function run_test() {
|
||||
|
||||
add_task(function* test_register_case() {
|
||||
let db = new PushDB();
|
||||
let promiseDB = promisifyDatabase(db);
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
do_register_cleanup(() => {return db.drop().then(_ => db.close());});
|
||||
|
||||
PushService.init({
|
||||
networkInfo: new MockDesktopNetworkInfo(),
|
||||
@ -56,7 +55,7 @@ add_task(function* test_register_case() {
|
||||
equal(newRecord.scope, 'https://example.net/case',
|
||||
'Wrong scope in registration record');
|
||||
|
||||
let record = yield promiseDB.getByChannelID(newRecord.channelID);
|
||||
let record = yield db.getByChannelID(newRecord.channelID);
|
||||
equal(record.pushEndpoint, 'https://example.com/update/case',
|
||||
'Wrong push endpoint in database record');
|
||||
equal(record.scope, 'https://example.net/case',
|
||||
|
@ -24,15 +24,14 @@ function run_test() {
|
||||
|
||||
add_task(function* test_register_flush() {
|
||||
let db = new PushDB();
|
||||
let promiseDB = promisifyDatabase(db);
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
do_register_cleanup(() => {return db.drop().then(_ => db.close());});
|
||||
let record = {
|
||||
channelID: '9bcc7efb-86c7-4457-93ea-e24e6eb59b74',
|
||||
pushEndpoint: 'https://example.org/update/1',
|
||||
scope: 'https://example.com/page/1',
|
||||
version: 2
|
||||
};
|
||||
yield promiseDB.put(record);
|
||||
yield db.put(record);
|
||||
|
||||
let notifyPromise = promiseObserverNotification('push-notification');
|
||||
|
||||
@ -89,14 +88,14 @@ add_task(function* test_register_flush() {
|
||||
yield waitForPromise(ackDefer.promise, DEFAULT_TIMEOUT,
|
||||
'Timed out waiting for acknowledgements');
|
||||
|
||||
let prevRecord = yield promiseDB.getByChannelID(
|
||||
let prevRecord = yield db.getByChannelID(
|
||||
'9bcc7efb-86c7-4457-93ea-e24e6eb59b74');
|
||||
equal(prevRecord.pushEndpoint, 'https://example.org/update/1',
|
||||
'Wrong existing push endpoint');
|
||||
strictEqual(prevRecord.version, 3,
|
||||
'Should record version updates sent before register responses');
|
||||
|
||||
let registeredRecord = yield promiseDB.getByChannelID(newRecord.channelID);
|
||||
let registeredRecord = yield db.getByChannelID(newRecord.channelID);
|
||||
equal(registeredRecord.pushEndpoint, 'https://example.org/update/2',
|
||||
'Wrong new push endpoint');
|
||||
ok(!registeredRecord.version, 'Should not record premature updates');
|
||||
|
@ -19,8 +19,7 @@ function run_test() {
|
||||
|
||||
add_task(function* test_register_invalid_channel() {
|
||||
let db = new PushDB();
|
||||
let promiseDB = promisifyDatabase(db);
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
do_register_cleanup(() => {return db.drop().then(_ => db.close());});
|
||||
|
||||
PushService._generateID = () => channelID;
|
||||
PushService.init({
|
||||
@ -55,6 +54,6 @@ add_task(function* test_register_invalid_channel() {
|
||||
'Wrong error for invalid channel ID'
|
||||
);
|
||||
|
||||
let record = yield promiseDB.getByChannelID(channelID);
|
||||
let record = yield db.getByChannelID(channelID);
|
||||
ok(!record, 'Should not store records for error responses');
|
||||
});
|
||||
|
@ -19,8 +19,7 @@ function run_test() {
|
||||
|
||||
add_task(function* test_register_invalid_endpoint() {
|
||||
let db = new PushDB();
|
||||
let promiseDB = promisifyDatabase(db);
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
do_register_cleanup(() => {return db.drop().then(_ => db.close());});
|
||||
|
||||
PushService._generateID = () => channelID;
|
||||
PushService.init({
|
||||
@ -57,6 +56,6 @@ add_task(function* test_register_invalid_endpoint() {
|
||||
'Wrong error for invalid endpoint'
|
||||
);
|
||||
|
||||
let record = yield promiseDB.getByChannelID(channelID);
|
||||
let record = yield db.getByChannelID(channelID);
|
||||
ok(!record, 'Should not store records with invalid endpoints');
|
||||
});
|
||||
|
@ -19,8 +19,7 @@ function run_test() {
|
||||
|
||||
add_task(function* test_register_request_queue() {
|
||||
let db = new PushDB();
|
||||
let promiseDB = promisifyDatabase(db);
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
do_register_cleanup(() => {return db.drop().then(_ => db.close());});
|
||||
|
||||
let helloDefer = Promise.defer();
|
||||
let onHello = after(2, function onHello(request) {
|
||||
|
@ -23,7 +23,7 @@ function run_test() {
|
||||
|
||||
add_task(function* test_register_rollback() {
|
||||
let db = new PushDB();
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
do_register_cleanup(() => {return db.drop().then(_ => db.close());});
|
||||
|
||||
let handshakes = 0;
|
||||
let registers = 0;
|
||||
@ -32,8 +32,8 @@ add_task(function* test_register_rollback() {
|
||||
PushService.init({
|
||||
networkInfo: new MockDesktopNetworkInfo(),
|
||||
db: makeStub(db, {
|
||||
put(prev, record, successCb, failureCb) {
|
||||
failureCb('universe has imploded');
|
||||
put(prev, record) {
|
||||
return Promise.reject('universe has imploded');
|
||||
}
|
||||
}),
|
||||
makeWebSocket(uri) {
|
||||
|
@ -23,8 +23,7 @@ function run_test() {
|
||||
|
||||
add_task(function* test_register_success() {
|
||||
let db = new PushDB();
|
||||
let promiseDB = promisifyDatabase(db);
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
do_register_cleanup(() => {return db.drop().then(_ => db.close());});
|
||||
|
||||
PushService._generateID = () => channelID;
|
||||
PushService.init({
|
||||
@ -66,7 +65,7 @@ add_task(function* test_register_success() {
|
||||
equal(newRecord.scope, 'https://example.org/1',
|
||||
'Wrong scope in registration record');
|
||||
|
||||
let record = yield promiseDB.getByChannelID(channelID);
|
||||
let record = yield db.getByChannelID(channelID);
|
||||
equal(record.channelID, channelID,
|
||||
'Wrong channel ID in database record');
|
||||
equal(record.pushEndpoint, 'https://example.com/update/1',
|
||||
|
@ -26,8 +26,7 @@ add_task(function* test_register_timeout() {
|
||||
let registers = 0;
|
||||
|
||||
let db = new PushDB();
|
||||
let promiseDB = promisifyDatabase(db);
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
do_register_cleanup(() => {return db.drop().then(_ => db.close());});
|
||||
|
||||
PushService._generateID = () => channelID;
|
||||
PushService.init({
|
||||
@ -90,7 +89,7 @@ add_task(function* test_register_timeout() {
|
||||
'Wrong error for request timeout'
|
||||
);
|
||||
|
||||
let record = yield promiseDB.getByChannelID(channelID);
|
||||
let record = yield db.getByChannelID(channelID);
|
||||
ok(!record, 'Should not store records for timed-out responses');
|
||||
|
||||
yield waitForPromise(
|
||||
|
@ -15,13 +15,13 @@ function run_test() {
|
||||
|
||||
add_task(function* test_registrations_error() {
|
||||
let db = new PushDB();
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
do_register_cleanup(() => {return db.drop().then(_ => db.close());});
|
||||
|
||||
PushService.init({
|
||||
networkInfo: new MockDesktopNetworkInfo(),
|
||||
db: makeStub(db, {
|
||||
getByScope(prev, scope, successCb, failureCb) {
|
||||
failureCb('oops');
|
||||
getByScope(prev, scope) {
|
||||
return Promise.reject('oops');
|
||||
}
|
||||
}),
|
||||
makeWebSocket(uri) {
|
||||
|
@ -15,8 +15,7 @@ function run_test() {
|
||||
|
||||
add_task(function* test_registration_success() {
|
||||
let db = new PushDB();
|
||||
let promiseDB = promisifyDatabase(db);
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
do_register_cleanup(() => {return db.drop().then(_ => db.close());});
|
||||
let records = [{
|
||||
channelID: 'bf001fe0-2684-42f2-bc4d-a3e14b11dd5b',
|
||||
pushEndpoint: 'https://example.com/update/same-manifest/1',
|
||||
@ -34,7 +33,7 @@ add_task(function* test_registration_success() {
|
||||
version: 15
|
||||
}];
|
||||
for (let record of records) {
|
||||
yield promiseDB.put(record);
|
||||
yield db.put(record);
|
||||
}
|
||||
|
||||
PushService.init({
|
||||
|
@ -15,9 +15,8 @@ function run_test() {
|
||||
|
||||
add_task(function* test_unregister_error() {
|
||||
let db = new PushDB();
|
||||
let promiseDB = promisifyDatabase(db);
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
yield promiseDB.put({
|
||||
do_register_cleanup(() => {return db.drop().then(_ => db.close());});
|
||||
yield db.put({
|
||||
channelID: channelID,
|
||||
pushEndpoint: 'https://example.org/update/failure',
|
||||
scope: 'https://example.net/page/failure',
|
||||
@ -56,7 +55,7 @@ add_task(function* test_unregister_error() {
|
||||
yield PushNotificationService.unregister(
|
||||
'https://example.net/page/failure');
|
||||
|
||||
let result = yield promiseDB.getByChannelID(channelID);
|
||||
let result = yield db.getByChannelID(channelID);
|
||||
ok(!result, 'Deleted push record exists');
|
||||
|
||||
// Make sure we send a request to the server.
|
||||
|
@ -19,8 +19,7 @@ function run_test() {
|
||||
|
||||
add_task(function* test_unregister_invalid_json() {
|
||||
let db = new PushDB();
|
||||
let promiseDB = promisifyDatabase(db);
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
do_register_cleanup(() => {return db.drop().then(_ => db.close());});
|
||||
let records = [{
|
||||
channelID: '87902e90-c57e-4d18-8354-013f4a556559',
|
||||
pushEndpoint: 'https://example.org/update/1',
|
||||
@ -33,7 +32,7 @@ add_task(function* test_unregister_invalid_json() {
|
||||
version: 1
|
||||
}];
|
||||
for (let record of records) {
|
||||
yield promiseDB.put(record);
|
||||
yield db.put(record);
|
||||
}
|
||||
|
||||
let unregisterDefer = Promise.defer();
|
||||
@ -62,13 +61,13 @@ add_task(function* test_unregister_invalid_json() {
|
||||
// _sendRequest().
|
||||
yield PushNotificationService.unregister(
|
||||
'https://example.edu/page/1');
|
||||
let record = yield promiseDB.getByChannelID(
|
||||
let record = yield db.getByChannelID(
|
||||
'87902e90-c57e-4d18-8354-013f4a556559');
|
||||
ok(!record, 'Failed to delete unregistered record');
|
||||
|
||||
yield PushNotificationService.unregister(
|
||||
'https://example.net/page/1');
|
||||
record = yield promiseDB.getByChannelID(
|
||||
record = yield db.getByChannelID(
|
||||
'057caa8f-9b99-47ff-891c-adad18ce603e');
|
||||
ok(!record,
|
||||
'Failed to delete unregistered record after receiving invalid JSON');
|
||||
|
@ -15,9 +15,8 @@ function run_test() {
|
||||
|
||||
add_task(function* test_unregister_success() {
|
||||
let db = new PushDB();
|
||||
let promiseDB = promisifyDatabase(db);
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
yield promiseDB.put({
|
||||
do_register_cleanup(() => {return db.drop().then(_ => db.close());});
|
||||
yield db.put({
|
||||
channelID,
|
||||
pushEndpoint: 'https://example.org/update/unregister-success',
|
||||
scope: 'https://example.com/page/unregister-success',
|
||||
@ -52,7 +51,7 @@ add_task(function* test_unregister_success() {
|
||||
|
||||
yield PushNotificationService.unregister(
|
||||
'https://example.com/page/unregister-success');
|
||||
let record = yield promiseDB.getByChannelID(channelID);
|
||||
let record = yield db.getByChannelID(channelID);
|
||||
ok(!record, 'Unregister did not remove record');
|
||||
|
||||
yield waitForPromise(unregisterDefer.promise, DEFAULT_TIMEOUT,
|
||||
|
@ -8,7 +8,7 @@ let Cc = Components.classes;
|
||||
let Ci = Components.interfaces;
|
||||
let Cu = Components.utils;
|
||||
|
||||
Cu.importGlobalProperties(['Blob']);
|
||||
Cu.importGlobalProperties(['Blob', 'File']);
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["SettingsDB", "SETTINGSDB_NAME", "SETTINGSSTORE_NAME"];
|
||||
@ -209,7 +209,7 @@ SettingsDB.prototype = {
|
||||
return "primitive";
|
||||
} else if (Array.isArray(aObject)) {
|
||||
return "array";
|
||||
} else if (aObject instanceof Ci.nsIDOMFile) {
|
||||
} else if (aObject instanceof File) {
|
||||
return "file";
|
||||
} else if (aObject instanceof Ci.nsIDOMBlob) {
|
||||
return "blob";
|
||||
|
@ -8,6 +8,8 @@ const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.importGlobalProperties(['File']);
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["SettingsRequestManager"];
|
||||
|
||||
Cu.import("resource://gre/modules/SettingsDB.jsm");
|
||||
@ -245,7 +247,7 @@ let SettingsRequestManager = {
|
||||
if (!aValue || !aValue.constructor) {
|
||||
return false;
|
||||
}
|
||||
return (aValue.constructor.name == "Date") || (aValue instanceof Ci.nsIDOMFile) ||
|
||||
return (aValue.constructor.name == "Date") || (aValue instanceof File) ||
|
||||
(aValue instanceof Ci.nsIDOMBlob);
|
||||
}
|
||||
// We need to serialize settings objects, otherwise they can change between
|
||||
|
@ -45,6 +45,8 @@ partial interface File {
|
||||
readonly attribute Date lastModifiedDate;
|
||||
|
||||
[GetterThrows, ChromeOnly]
|
||||
readonly attribute DOMString mozFullPath;
|
||||
readonly attribute DOMString path;
|
||||
|
||||
[GetterThrows, ChromeOnly]
|
||||
readonly attribute DOMString mozFullPath;
|
||||
};
|
||||
|
@ -148,7 +148,7 @@ partial interface HTMLInputElement {
|
||||
[GetterThrows]
|
||||
readonly attribute long textLength;
|
||||
|
||||
[ChromeOnly]
|
||||
[Throws, ChromeOnly]
|
||||
sequence<DOMString> mozGetFileNameArray();
|
||||
|
||||
[ChromeOnly, Throws]
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include "cert.h"
|
||||
#include "certdb.h"
|
||||
#include "CryptoTask.h"
|
||||
#include "nsIDOMFile.h"
|
||||
#include "nsIDOMBlob.h"
|
||||
#include "nsIWifiService.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
|
@ -192,13 +192,6 @@ struct RectCornerRadii {
|
||||
return radii[aCorner];
|
||||
}
|
||||
|
||||
bool operator==(const RectCornerRadii& aOther) const {
|
||||
for (size_t i = 0; i < RectCorner::Count; i++) {
|
||||
if (radii[i] != aOther.radii[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Scale(Float aXScale, Float aYScale) {
|
||||
for (int i = 0; i < RectCorner::Count; i++) {
|
||||
radii[i].Scale(aXScale, aYScale);
|
||||
@ -361,16 +354,19 @@ inline bool UserToDevicePixelSnapped(Rect& aRect, const DrawTarget& aDrawTarget,
|
||||
* This function has the same behavior as UserToDevicePixelSnapped except that
|
||||
* aRect is not transformed to device space.
|
||||
*/
|
||||
inline void MaybeSnapToDevicePixels(Rect& aRect, const DrawTarget& aDrawTarget,
|
||||
bool aIgnoreScale = false)
|
||||
inline bool MaybeSnapToDevicePixels(Rect& aRect, const DrawTarget& aDrawTarget,
|
||||
bool aAllowScaleOr90DegreeRotate = false)
|
||||
{
|
||||
if (UserToDevicePixelSnapped(aRect, aDrawTarget, aIgnoreScale)) {
|
||||
if (UserToDevicePixelSnapped(aRect, aDrawTarget,
|
||||
aAllowScaleOr90DegreeRotate)) {
|
||||
// Since UserToDevicePixelSnapped returned true we know there is no
|
||||
// rotation/skew in 'mat', so we can just use TransformBounds() here.
|
||||
Matrix mat = aDrawTarget.GetTransform();
|
||||
mat.Invert();
|
||||
aRect = mat.TransformBounds(aRect);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
|
@ -712,16 +712,15 @@ SenderHelper::SendTextureSource(GLContext* aGLContext,
|
||||
aGLContext->GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_RECTANGLE, &textureId);
|
||||
}
|
||||
|
||||
gfx::IntSize size = aSource->GetSize();
|
||||
|
||||
// By sending 0 to ReadTextureImage rely upon aSource->BindTexture binding
|
||||
// texture correctly. textureId is used for tracking in DebugGLTextureData.
|
||||
RefPtr<DataSourceSurface> img =
|
||||
aGLContext->ReadTexImageHelper()->ReadTexImage(0, textureTarget,
|
||||
size,
|
||||
shaderConfig, aFlipY);
|
||||
|
||||
if (!IsTextureIdContainsInList(textureId)) {
|
||||
gfx::IntSize size = aSource->GetSize();
|
||||
|
||||
// By sending 0 to ReadTextureImage rely upon aSource->BindTexture binding
|
||||
// texture correctly. textureId is used for tracking in DebugGLTextureData.
|
||||
RefPtr<DataSourceSurface> img =
|
||||
aGLContext->ReadTexImageHelper()->ReadTexImage(0, textureTarget,
|
||||
size,
|
||||
shaderConfig, aFlipY);
|
||||
sTextureIdList.push_back(textureId);
|
||||
WebSocketHelper::GetSocketManager()->AppendDebugData(
|
||||
new DebugGLTextureData(aGLContext, aLayerRef, textureTarget,
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsExpirationTracker.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "gfxUtils.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
@ -165,56 +164,40 @@ struct BlurCacheKey : public PLDHashEntryHdr {
|
||||
typedef const BlurCacheKey* KeyTypePointer;
|
||||
enum { ALLOW_MEMMOVE = true };
|
||||
|
||||
IntSize mMinSize;
|
||||
gfxRect mRect;
|
||||
gfxIntSize mBlurRadius;
|
||||
gfxRGBA mShadowColor;
|
||||
gfxRect mSkipRect;
|
||||
BackendType mBackend;
|
||||
RectCornerRadii mCornerRadii;
|
||||
|
||||
BlurCacheKey(IntSize aMinimumSize, gfxIntSize aBlurRadius,
|
||||
RectCornerRadii* aCornerRadii, gfxRGBA aShadowColor,
|
||||
BackendType aBackend)
|
||||
: mMinSize(aMinimumSize)
|
||||
BlurCacheKey(const gfxRect& aRect, const gfxIntSize &aBlurRadius, const gfxRect& aSkipRect, BackendType aBackend)
|
||||
: mRect(aRect)
|
||||
, mBlurRadius(aBlurRadius)
|
||||
, mShadowColor(aShadowColor)
|
||||
, mSkipRect(aSkipRect)
|
||||
, mBackend(aBackend)
|
||||
, mCornerRadii(aCornerRadii ? *aCornerRadii : RectCornerRadii())
|
||||
{ }
|
||||
|
||||
explicit BlurCacheKey(const BlurCacheKey* aOther)
|
||||
: mMinSize(aOther->mMinSize)
|
||||
: mRect(aOther->mRect)
|
||||
, mBlurRadius(aOther->mBlurRadius)
|
||||
, mShadowColor(aOther->mShadowColor)
|
||||
, mSkipRect(aOther->mSkipRect)
|
||||
, mBackend(aOther->mBackend)
|
||||
, mCornerRadii(aOther->mCornerRadii)
|
||||
{ }
|
||||
|
||||
static PLDHashNumber
|
||||
HashKey(const KeyTypePointer aKey)
|
||||
{
|
||||
PLDHashNumber hash = 0;
|
||||
hash = AddToHash(hash, aKey->mMinSize.width, aKey->mMinSize.height);
|
||||
PLDHashNumber hash = HashBytes(&aKey->mRect.x, 4 * sizeof(gfxFloat));
|
||||
hash = AddToHash(hash, aKey->mBlurRadius.width, aKey->mBlurRadius.height);
|
||||
|
||||
hash = AddToHash(hash, HashBytes(&aKey->mShadowColor.r, sizeof(gfxFloat)));
|
||||
hash = AddToHash(hash, HashBytes(&aKey->mShadowColor.g, sizeof(gfxFloat)));
|
||||
hash = AddToHash(hash, HashBytes(&aKey->mShadowColor.b, sizeof(gfxFloat)));
|
||||
hash = AddToHash(hash, HashBytes(&aKey->mShadowColor.a, sizeof(gfxFloat)));
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
hash = AddToHash(hash, aKey->mCornerRadii[i].width, aKey->mCornerRadii[i].height);
|
||||
}
|
||||
|
||||
hash = AddToHash(hash, HashBytes(&aKey->mSkipRect.x, 4 * sizeof(gfxFloat)));
|
||||
hash = AddToHash(hash, (uint32_t)aKey->mBackend);
|
||||
return hash;
|
||||
}
|
||||
|
||||
bool KeyEquals(KeyTypePointer aKey) const
|
||||
{
|
||||
if (aKey->mMinSize == mMinSize &&
|
||||
if (aKey->mRect.IsEqualInterior(mRect) &&
|
||||
aKey->mBlurRadius == mBlurRadius &&
|
||||
aKey->mCornerRadii == mCornerRadii &&
|
||||
aKey->mShadowColor == mShadowColor &&
|
||||
aKey->mSkipRect.IsEqualInterior(mSkipRect) &&
|
||||
aKey->mBackend == mBackend) {
|
||||
return true;
|
||||
}
|
||||
@ -231,15 +214,17 @@ struct BlurCacheKey : public PLDHashEntryHdr {
|
||||
* to the cache entry to be able to be tracked by the nsExpirationTracker.
|
||||
* */
|
||||
struct BlurCacheData {
|
||||
BlurCacheData(SourceSurface* aBlur, IntMargin aExtendDestBy, const BlurCacheKey& aKey)
|
||||
BlurCacheData(SourceSurface* aBlur, const IntPoint& aTopLeft, const gfxRect& aDirtyRect, const BlurCacheKey& aKey)
|
||||
: mBlur(aBlur)
|
||||
, mExtendDest(aExtendDestBy)
|
||||
, mTopLeft(aTopLeft)
|
||||
, mDirtyRect(aDirtyRect)
|
||||
, mKey(aKey)
|
||||
{}
|
||||
|
||||
BlurCacheData(const BlurCacheData& aOther)
|
||||
: mBlur(aOther.mBlur)
|
||||
, mExtendDest(aOther.mExtendDest)
|
||||
, mTopLeft(aOther.mTopLeft)
|
||||
, mDirtyRect(aOther.mDirtyRect)
|
||||
, mKey(aOther.mKey)
|
||||
{ }
|
||||
|
||||
@ -249,7 +234,8 @@ struct BlurCacheData {
|
||||
|
||||
nsExpirationState mExpirationState;
|
||||
RefPtr<SourceSurface> mBlur;
|
||||
IntMargin mExtendDest;
|
||||
IntPoint mTopLeft;
|
||||
gfxRect mDirtyRect;
|
||||
BlurCacheKey mKey;
|
||||
};
|
||||
|
||||
@ -273,18 +259,19 @@ class BlurCache final : public nsExpirationTracker<BlurCacheData,4>
|
||||
mHashEntries.Remove(aObject->mKey);
|
||||
}
|
||||
|
||||
BlurCacheData* Lookup(const IntSize aMinSize,
|
||||
BlurCacheData* Lookup(const gfxRect& aRect,
|
||||
const gfxIntSize& aBlurRadius,
|
||||
RectCornerRadii* aCornerRadii,
|
||||
const gfxRGBA& aShadowColor,
|
||||
BackendType aBackendType)
|
||||
const gfxRect& aSkipRect,
|
||||
BackendType aBackendType,
|
||||
const gfxRect* aDirtyRect)
|
||||
{
|
||||
BlurCacheData* blur =
|
||||
mHashEntries.Get(BlurCacheKey(aMinSize, aBlurRadius,
|
||||
aCornerRadii, aShadowColor,
|
||||
aBackendType));
|
||||
mHashEntries.Get(BlurCacheKey(aRect, aBlurRadius, aSkipRect, aBackendType));
|
||||
|
||||
if (blur) {
|
||||
if (aDirtyRect && !blur->mDirtyRect.Contains(*aDirtyRect)) {
|
||||
return nullptr;
|
||||
}
|
||||
MarkUsed(blur);
|
||||
}
|
||||
|
||||
@ -319,163 +306,52 @@ class BlurCache final : public nsExpirationTracker<BlurCacheData,4>
|
||||
|
||||
static BlurCache* gBlurCache = nullptr;
|
||||
|
||||
static IntSize
|
||||
ComputeMinSizeForShadowShape(RectCornerRadii* aCornerRadii,
|
||||
gfxIntSize aBlurRadius,
|
||||
IntMargin& aSlice,
|
||||
const IntSize& aRectSize)
|
||||
{
|
||||
float cornerWidth = 0;
|
||||
float cornerHeight = 0;
|
||||
if (aCornerRadii) {
|
||||
RectCornerRadii corners = *aCornerRadii;
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
cornerWidth = std::max(cornerWidth, corners[i].width);
|
||||
cornerHeight = std::max(cornerHeight, corners[i].height);
|
||||
}
|
||||
}
|
||||
|
||||
aSlice = IntMargin(ceil(cornerHeight) + aBlurRadius.height,
|
||||
ceil(cornerWidth) + aBlurRadius.width,
|
||||
ceil(cornerHeight) + aBlurRadius.height,
|
||||
ceil(cornerWidth) + aBlurRadius.width);
|
||||
|
||||
// Include 1 pixel for the stretchable strip in the middle.
|
||||
IntSize minSize(aSlice.LeftRight() + 1,
|
||||
aSlice.TopBottom() + 1);
|
||||
|
||||
// If aRectSize is smaller than minSize, the border-image approach won't
|
||||
// work; there's no way to squeeze parts of the min box-shadow source
|
||||
// image such that the result looks correct. So we need to adjust minSize
|
||||
// in such a way that we can later draw it without stretching in the affected
|
||||
// dimension. We also need to adjust "slice" to ensure that we're not trying
|
||||
// to slice away more than we have.
|
||||
if (aRectSize.width < minSize.width) {
|
||||
minSize.width = aRectSize.width;
|
||||
aSlice.left = 0;
|
||||
aSlice.right = 0;
|
||||
}
|
||||
if (aRectSize.height < minSize.height) {
|
||||
minSize.height = aRectSize.height;
|
||||
aSlice.top = 0;
|
||||
aSlice.bottom = 0;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aSlice.LeftRight() <= minSize.width);
|
||||
MOZ_ASSERT(aSlice.TopBottom() <= minSize.height);
|
||||
return minSize;
|
||||
}
|
||||
|
||||
void
|
||||
CacheBlur(DrawTarget& aDT,
|
||||
const IntSize& aMinSize,
|
||||
const gfxIntSize& aBlurRadius,
|
||||
RectCornerRadii* aCornerRadii,
|
||||
const gfxRGBA& aShadowColor,
|
||||
IntMargin aExtendDest,
|
||||
SourceSurface* aBoxShadow)
|
||||
{
|
||||
BlurCacheKey key(aMinSize, aBlurRadius, aCornerRadii, aShadowColor, aDT.GetBackendType());
|
||||
BlurCacheData* data = new BlurCacheData(aBoxShadow, aExtendDest, key);
|
||||
if (!gBlurCache->RegisterEntry(data)) {
|
||||
delete data;
|
||||
}
|
||||
}
|
||||
|
||||
// Blurs a small surface and creates the mask.
|
||||
static TemporaryRef<SourceSurface>
|
||||
CreateBlurMask(const IntSize& aRectSize,
|
||||
RectCornerRadii* aCornerRadii,
|
||||
gfxIntSize aBlurRadius,
|
||||
IntMargin& aExtendDestBy,
|
||||
IntMargin& aSliceBorder,
|
||||
DrawTarget& aDestDrawTarget)
|
||||
{
|
||||
IntMargin slice;
|
||||
IntSize minSize =
|
||||
ComputeMinSizeForShadowShape(aCornerRadii, aBlurRadius, slice, aRectSize);
|
||||
IntRect minRect(IntPoint(), minSize);
|
||||
|
||||
gfxAlphaBoxBlur blur;
|
||||
gfxContext* blurCtx = blur.Init(ThebesRect(Rect(minRect)), gfxIntSize(),
|
||||
aBlurRadius, nullptr, nullptr);
|
||||
if (!blurCtx) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DrawTarget* blurDT = blurCtx->GetDrawTarget();
|
||||
ColorPattern black(Color(0.f, 0.f, 0.f, 1.f));
|
||||
|
||||
if (aCornerRadii) {
|
||||
RefPtr<Path> roundedRect =
|
||||
MakePathForRoundedRect(*blurDT, Rect(minRect), *aCornerRadii);
|
||||
blurDT->Fill(roundedRect, black);
|
||||
} else {
|
||||
blurDT->FillRect(Rect(minRect), black);
|
||||
}
|
||||
|
||||
IntPoint topLeft;
|
||||
RefPtr<SourceSurface> result = blur.DoBlur(&aDestDrawTarget, &topLeft);
|
||||
|
||||
IntRect expandedMinRect(topLeft, result->GetSize());
|
||||
aExtendDestBy = expandedMinRect - minRect;
|
||||
aSliceBorder = slice + aExtendDestBy;
|
||||
|
||||
MOZ_ASSERT(aSliceBorder.LeftRight() <= expandedMinRect.width);
|
||||
MOZ_ASSERT(aSliceBorder.TopBottom() <= expandedMinRect.height);
|
||||
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
static TemporaryRef<SourceSurface>
|
||||
CreateBoxShadow(SourceSurface* aBlurMask, const gfxRGBA& aShadowColor)
|
||||
{
|
||||
IntSize blurredSize = aBlurMask->GetSize();
|
||||
gfxPlatform* platform = gfxPlatform::GetPlatform();
|
||||
RefPtr<DrawTarget> boxShadowDT =
|
||||
platform->CreateOffscreenContentDrawTarget(blurredSize, SurfaceFormat::B8G8R8A8);
|
||||
|
||||
ColorPattern shadowColor(ToDeviceColor(aShadowColor));
|
||||
boxShadowDT->MaskSurface(shadowColor, aBlurMask, Point(0, 0));
|
||||
return boxShadowDT->Snapshot();
|
||||
}
|
||||
|
||||
SourceSurface*
|
||||
GetBlur(DrawTarget& aDT,
|
||||
const IntSize& aRectSize,
|
||||
GetCachedBlur(DrawTarget *aDT,
|
||||
const gfxRect& aRect,
|
||||
const gfxIntSize& aBlurRadius,
|
||||
RectCornerRadii* aCornerRadii,
|
||||
const gfxRGBA& aShadowColor,
|
||||
IntMargin& aExtendDestBy,
|
||||
IntMargin& aSlice)
|
||||
const gfxRect& aSkipRect,
|
||||
const gfxRect& aDirtyRect,
|
||||
IntPoint* aTopLeft)
|
||||
{
|
||||
if (!gBlurCache) {
|
||||
gBlurCache = new BlurCache();
|
||||
}
|
||||
|
||||
IntSize minSize =
|
||||
ComputeMinSizeForShadowShape(aCornerRadii, aBlurRadius, aSlice, aRectSize);
|
||||
|
||||
BlurCacheData* cached = gBlurCache->Lookup(minSize, aBlurRadius,
|
||||
aCornerRadii, aShadowColor,
|
||||
aDT.GetBackendType());
|
||||
BlurCacheData* cached = gBlurCache->Lookup(aRect, aBlurRadius, aSkipRect,
|
||||
aDT->GetBackendType(),
|
||||
&aDirtyRect);
|
||||
if (cached) {
|
||||
// See CreateBlurMask() for these values
|
||||
aExtendDestBy = cached->mExtendDest;
|
||||
aSlice = aSlice + aExtendDestBy;
|
||||
*aTopLeft = cached->mTopLeft;
|
||||
return cached->mBlur;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<SourceSurface> blurMask =
|
||||
CreateBlurMask(aRectSize, aCornerRadii, aBlurRadius, aExtendDestBy, aSlice, aDT);
|
||||
|
||||
if (!blurMask) {
|
||||
return nullptr;
|
||||
void
|
||||
CacheBlur(DrawTarget *aDT,
|
||||
const gfxRect& aRect,
|
||||
const gfxIntSize& aBlurRadius,
|
||||
const gfxRect& aSkipRect,
|
||||
SourceSurface* aBlur,
|
||||
const IntPoint& aTopLeft,
|
||||
const gfxRect& aDirtyRect)
|
||||
{
|
||||
// If we already had a cached value with this key, but an incorrect dirty region then just update
|
||||
// the existing entry
|
||||
if (BlurCacheData* cached = gBlurCache->Lookup(aRect, aBlurRadius, aSkipRect,
|
||||
aDT->GetBackendType(),
|
||||
nullptr)) {
|
||||
cached->mBlur = aBlur;
|
||||
cached->mTopLeft = aTopLeft;
|
||||
cached->mDirtyRect = aDirtyRect;
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<SourceSurface> boxShadow = CreateBoxShadow(blurMask, aShadowColor);
|
||||
CacheBlur(aDT, minSize, aBlurRadius, aCornerRadii, aShadowColor, aExtendDestBy, boxShadow);
|
||||
return boxShadow;
|
||||
BlurCacheKey key(aRect, aBlurRadius, aSkipRect, aDT->GetBackendType());
|
||||
BlurCacheData* data = new BlurCacheData(aBlur, aTopLeft, aDirtyRect, key);
|
||||
if (!gBlurCache->RegisterEntry(data)) {
|
||||
delete data;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -485,45 +361,8 @@ gfxAlphaBoxBlur::ShutdownBlurCache()
|
||||
gBlurCache = nullptr;
|
||||
}
|
||||
|
||||
static Rect
|
||||
RectWithEdgesTRBL(Float aTop, Float aRight, Float aBottom, Float aLeft)
|
||||
{
|
||||
return Rect(aLeft, aTop, aRight - aLeft, aBottom - aTop);
|
||||
}
|
||||
|
||||
static void
|
||||
RepeatOrStretchSurface(DrawTarget& aDT, SourceSurface* aSurface,
|
||||
const Rect& aDest, const Rect& aSrc)
|
||||
{
|
||||
if (!aDT.GetTransform().IsRectilinear() &&
|
||||
aDT.GetBackendType() != BackendType::CAIRO) {
|
||||
// Use stretching if possible, since it leads to less seams when the
|
||||
// destination is transformed. However, don't do this if we're using cairo,
|
||||
// because if cairo is using pixman it won't render anything for large
|
||||
// stretch factors because pixman's internal fixed point precision is not
|
||||
// high enough to handle those scale factors.
|
||||
aDT.DrawSurface(aSurface, aDest, aSrc);
|
||||
return;
|
||||
}
|
||||
|
||||
SurfacePattern pattern(aSurface, ExtendMode::REPEAT,
|
||||
Matrix::Translation(aDest.TopLeft() - aSrc.TopLeft()),
|
||||
Filter::GOOD, RoundedToInt(aSrc));
|
||||
aDT.FillRect(aDest, pattern);
|
||||
}
|
||||
|
||||
/***
|
||||
* We draw a blurred a rectangle by only blurring a smaller rectangle and
|
||||
* splitting the rectangle into 9 parts.
|
||||
* First, a small minimum source rect is calculated and used to create a blur
|
||||
* mask since the actual blurring itself is expensive. Next, we use the mask
|
||||
* with the given shadow color to create a minimally-sized box shadow of the
|
||||
* right color. Finally, we cut out the 9 parts from the box-shadow source and
|
||||
* paint each part in the right place, stretching the non-corner parts to fill
|
||||
* the space between the corners.
|
||||
*/
|
||||
/* static */ void
|
||||
gfxAlphaBoxBlur::BlurRectangle(gfxContext* aDestinationCtx,
|
||||
gfxAlphaBoxBlur::BlurRectangle(gfxContext *aDestinationCtx,
|
||||
const gfxRect& aRect,
|
||||
RectCornerRadii* aCornerRadii,
|
||||
const gfxPoint& aBlurStdDev,
|
||||
@ -531,103 +370,43 @@ gfxAlphaBoxBlur::BlurRectangle(gfxContext* aDestinationCtx,
|
||||
const gfxRect& aDirtyRect,
|
||||
const gfxRect& aSkipRect)
|
||||
{
|
||||
DrawTarget& destDrawTarget = *aDestinationCtx->GetDrawTarget();
|
||||
DrawTarget& aDrawTarget = *aDestinationCtx->GetDrawTarget();
|
||||
|
||||
gfxIntSize blurRadius = CalculateBlurRadius(aBlurStdDev);
|
||||
|
||||
IntRect rect = RoundedToInt(ToRect(aRect));
|
||||
IntMargin extendDestBy;
|
||||
IntMargin slice;
|
||||
IntPoint topLeft;
|
||||
RefPtr<SourceSurface> surface = GetCachedBlur(&aDrawTarget, aRect, blurRadius, aSkipRect, aDirtyRect, &topLeft);
|
||||
if (!surface) {
|
||||
// Create the temporary surface for blurring
|
||||
gfxAlphaBoxBlur blur;
|
||||
gfxContext* blurCtx = blur.Init(aRect, gfxIntSize(), blurRadius, &aDirtyRect, &aSkipRect);
|
||||
if (!blurCtx) {
|
||||
return;
|
||||
}
|
||||
DrawTarget* blurDT = blurCtx->GetDrawTarget();
|
||||
|
||||
RefPtr<SourceSurface> boxShadow = GetBlur(destDrawTarget,
|
||||
rect.Size(), blurRadius,
|
||||
aCornerRadii, aShadowColor,
|
||||
extendDestBy, slice);
|
||||
if (!boxShadow) {
|
||||
return;
|
||||
Rect shadowGfxRect = ToRect(aRect);
|
||||
shadowGfxRect.Round();
|
||||
|
||||
ColorPattern black(Color(0.f, 0.f, 0.f, 1.f)); // For masking, so no ToDeviceColor!
|
||||
if (aCornerRadii) {
|
||||
RefPtr<Path> roundedRect = MakePathForRoundedRect(*blurDT,
|
||||
shadowGfxRect,
|
||||
*aCornerRadii);
|
||||
blurDT->Fill(roundedRect, black);
|
||||
} else {
|
||||
blurDT->FillRect(shadowGfxRect, black);
|
||||
}
|
||||
|
||||
surface = blur.DoBlur(&aDrawTarget, &topLeft);
|
||||
if (!surface) {
|
||||
return;
|
||||
}
|
||||
CacheBlur(&aDrawTarget, aRect, blurRadius, aSkipRect, surface, topLeft, aDirtyRect);
|
||||
}
|
||||
|
||||
destDrawTarget.PushClipRect(ToRect(aDirtyRect));
|
||||
|
||||
// Copy the right parts from boxShadow into destDrawTarget. The middle parts
|
||||
// will be stretched, border-image style.
|
||||
|
||||
Rect srcOuter(Point(), Size(boxShadow->GetSize()));
|
||||
Rect srcInner = srcOuter;
|
||||
srcInner.Deflate(Margin(slice));
|
||||
|
||||
rect.Inflate(extendDestBy);
|
||||
Rect dstOuter(rect);
|
||||
Rect dstInner(rect);
|
||||
dstInner.Deflate(Margin(slice));
|
||||
|
||||
// Corners: top left, top right, bottom left, bottom right
|
||||
destDrawTarget.DrawSurface(boxShadow,
|
||||
RectWithEdgesTRBL(dstOuter.Y(), dstInner.X(),
|
||||
dstInner.Y(), dstOuter.X()),
|
||||
RectWithEdgesTRBL(srcOuter.Y(), srcInner.X(),
|
||||
srcInner.Y(), srcOuter.X()));
|
||||
destDrawTarget.DrawSurface(boxShadow,
|
||||
RectWithEdgesTRBL(dstOuter.Y(), dstOuter.XMost(),
|
||||
dstInner.Y(), dstInner.XMost()),
|
||||
RectWithEdgesTRBL(srcOuter.Y(), srcOuter.XMost(),
|
||||
srcInner.Y(), srcInner.XMost()));
|
||||
destDrawTarget.DrawSurface(boxShadow,
|
||||
RectWithEdgesTRBL(dstInner.YMost(), dstInner.X(),
|
||||
dstOuter.YMost(), dstOuter.X()),
|
||||
RectWithEdgesTRBL(srcInner.YMost(), srcInner.X(),
|
||||
srcOuter.YMost(), srcOuter.X()));
|
||||
destDrawTarget.DrawSurface(boxShadow,
|
||||
RectWithEdgesTRBL(dstInner.YMost(), dstOuter.XMost(),
|
||||
dstOuter.YMost(), dstInner.XMost()),
|
||||
RectWithEdgesTRBL(srcInner.YMost(), srcOuter.XMost(),
|
||||
srcOuter.YMost(), srcInner.XMost()));
|
||||
|
||||
// Edges: top, left, right, bottom
|
||||
RepeatOrStretchSurface(destDrawTarget, boxShadow,
|
||||
RectWithEdgesTRBL(dstOuter.Y(), dstInner.XMost(),
|
||||
dstInner.Y(), dstInner.X()),
|
||||
RectWithEdgesTRBL(srcOuter.Y(), srcInner.XMost(),
|
||||
srcInner.Y(), srcInner.X()));
|
||||
RepeatOrStretchSurface(destDrawTarget, boxShadow,
|
||||
RectWithEdgesTRBL(dstInner.Y(), dstInner.X(),
|
||||
dstInner.YMost(), dstOuter.X()),
|
||||
RectWithEdgesTRBL(srcInner.Y(), srcInner.X(),
|
||||
srcInner.YMost(), srcOuter.X()));
|
||||
RepeatOrStretchSurface(destDrawTarget, boxShadow,
|
||||
RectWithEdgesTRBL(dstInner.Y(), dstOuter.XMost(),
|
||||
dstInner.YMost(), dstInner.XMost()),
|
||||
RectWithEdgesTRBL(srcInner.Y(), srcOuter.XMost(),
|
||||
srcInner.YMost(), srcInner.XMost()));
|
||||
RepeatOrStretchSurface(destDrawTarget, boxShadow,
|
||||
RectWithEdgesTRBL(dstInner.YMost(), dstInner.XMost(),
|
||||
dstOuter.YMost(), dstInner.X()),
|
||||
RectWithEdgesTRBL(srcInner.YMost(), srcInner.XMost(),
|
||||
srcOuter.YMost(), srcInner.X()));
|
||||
|
||||
// Middle part
|
||||
RepeatOrStretchSurface(destDrawTarget, boxShadow,
|
||||
RectWithEdgesTRBL(dstInner.Y(), dstInner.XMost(),
|
||||
dstInner.YMost(), dstInner.X()),
|
||||
RectWithEdgesTRBL(srcInner.Y(), srcInner.XMost(),
|
||||
srcInner.YMost(), srcInner.X()));
|
||||
|
||||
// A note about anti-aliasing and seems between adjacent parts:
|
||||
// We don't explicitly disable anti-aliasing in the DrawSurface calls above,
|
||||
// so if there's a transform on destDrawTarget that is not pixel-aligned,
|
||||
// there will be seams between adjacent parts of the box-shadow. It's hard to
|
||||
// avoid those without the use of an intermediate surface.
|
||||
// You might think that we could avoid those by just turning of AA, but there
|
||||
// is a problem with that: Box-shadow rendering needs to clip out the
|
||||
// element's border box, and we'd like that clip to have anti-aliasing -
|
||||
// especially if the element has rounded corners! So we can't do that unless
|
||||
// we have a way to say "Please anti-alias the clip, but don't antialias the
|
||||
// destination rect of the DrawSurface call".
|
||||
// On OS X there is an additional problem with turning off AA: CoreGraphics
|
||||
// will not just fill the pixels that have their pixel center inside the
|
||||
// filled shape. Instead, it will fill all the pixels which are partially
|
||||
// covered by the shape. So for pixels on the edge between two adjacent parts,
|
||||
// all those pixels will be painted to by both parts, which looks very bad.
|
||||
|
||||
destDrawTarget.PopClip();
|
||||
aDestinationCtx->SetColor(aShadowColor);
|
||||
Rect dirtyRect(aDirtyRect.x, aDirtyRect.y, aDirtyRect.width, aDirtyRect.height);
|
||||
DrawBlur(aDestinationCtx, surface, topLeft, &dirtyRect);
|
||||
}
|
||||
|
||||
|
@ -304,6 +304,39 @@ gfxGDIFont::Initialize()
|
||||
mMetrics->maxAdvance = mMetrics->aveCharWidth;
|
||||
}
|
||||
|
||||
// For fonts with USE_TYPO_METRICS set in the fsSelection field,
|
||||
// let the OS/2 sTypo* metrics override the previous values.
|
||||
// (see http://www.microsoft.com/typography/otspec/os2.htm#fss)
|
||||
// Using the equivalent values from oMetrics provides inconsistent
|
||||
// results with CFF fonts, so we instead rely on OS2Table.
|
||||
gfxFontEntry::AutoTable os2Table(mFontEntry,
|
||||
TRUETYPE_TAG('O','S','/','2'));
|
||||
if (os2Table) {
|
||||
uint32_t len;
|
||||
const OS2Table *os2 =
|
||||
reinterpret_cast<const OS2Table*>(hb_blob_get_data(os2Table,
|
||||
&len));
|
||||
if (len >= offsetof(OS2Table, sTypoLineGap) + sizeof(int16_t)) {
|
||||
const uint16_t kUseTypoMetricsMask = 1 << 7;
|
||||
if ((uint16_t(os2->fsSelection) & kUseTypoMetricsMask)) {
|
||||
double ascent = int16_t(os2->sTypoAscender);
|
||||
double descent = int16_t(os2->sTypoDescender);
|
||||
double lineGap = int16_t(os2->sTypoLineGap);
|
||||
mMetrics->maxAscent = ROUND(ascent * mFUnitsConvFactor);
|
||||
mMetrics->maxDescent = -ROUND(descent * mFUnitsConvFactor);
|
||||
mMetrics->maxHeight =
|
||||
mMetrics->maxAscent + mMetrics->maxDescent;
|
||||
mMetrics->internalLeading =
|
||||
mMetrics->maxHeight - mMetrics->emHeight;
|
||||
gfxFloat lineHeight =
|
||||
ROUND((ascent - descent + lineGap) * mFUnitsConvFactor);
|
||||
lineHeight = std::max(lineHeight, mMetrics->maxHeight);
|
||||
mMetrics->externalLeading =
|
||||
lineHeight - mMetrics->maxHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cache the width of a single space.
|
||||
SIZE size;
|
||||
GetTextExtentPoint32W(dc.GetDC(), L" ", 1, &size);
|
||||
|
@ -69,47 +69,49 @@ class GlobalObject : public NativeObject
|
||||
*/
|
||||
static const unsigned STANDARD_CLASS_SLOTS = JSProto_LIMIT * 3;
|
||||
|
||||
/* Various function values needed by the engine. */
|
||||
static const unsigned EVAL = APPLICATION_SLOTS + STANDARD_CLASS_SLOTS;
|
||||
static const unsigned CREATE_DATAVIEW_FOR_THIS = EVAL + 1;
|
||||
static const unsigned THROWTYPEERROR = CREATE_DATAVIEW_FOR_THIS + 1;
|
||||
enum : unsigned {
|
||||
/* Various function values needed by the engine. */
|
||||
EVAL = APPLICATION_SLOTS + STANDARD_CLASS_SLOTS,
|
||||
CREATE_DATAVIEW_FOR_THIS,
|
||||
THROWTYPEERROR,
|
||||
|
||||
/*
|
||||
* Instances of the internal createArrayFromBuffer function used by the
|
||||
* typed array code, one per typed array element type.
|
||||
*/
|
||||
static const unsigned FROM_BUFFER_UINT8 = THROWTYPEERROR + 1;
|
||||
static const unsigned FROM_BUFFER_INT8 = FROM_BUFFER_UINT8 + 1;
|
||||
static const unsigned FROM_BUFFER_UINT16 = FROM_BUFFER_INT8 + 1;
|
||||
static const unsigned FROM_BUFFER_INT16 = FROM_BUFFER_UINT16 + 1;
|
||||
static const unsigned FROM_BUFFER_UINT32 = FROM_BUFFER_INT16 + 1;
|
||||
static const unsigned FROM_BUFFER_INT32 = FROM_BUFFER_UINT32 + 1;
|
||||
static const unsigned FROM_BUFFER_FLOAT32 = FROM_BUFFER_INT32 + 1;
|
||||
static const unsigned FROM_BUFFER_FLOAT64 = FROM_BUFFER_FLOAT32 + 1;
|
||||
static const unsigned FROM_BUFFER_UINT8CLAMPED = FROM_BUFFER_FLOAT64 + 1;
|
||||
/*
|
||||
* Instances of the internal createArrayFromBuffer function used by the
|
||||
* typed array code, one per typed array element type.
|
||||
*/
|
||||
FROM_BUFFER_UINT8,
|
||||
FROM_BUFFER_INT8,
|
||||
FROM_BUFFER_UINT16,
|
||||
FROM_BUFFER_INT16,
|
||||
FROM_BUFFER_UINT32,
|
||||
FROM_BUFFER_INT32,
|
||||
FROM_BUFFER_FLOAT32,
|
||||
FROM_BUFFER_FLOAT64,
|
||||
FROM_BUFFER_UINT8CLAMPED,
|
||||
|
||||
/* One-off properties stored after slots for built-ins. */
|
||||
static const unsigned ARRAY_ITERATOR_PROTO = FROM_BUFFER_UINT8CLAMPED + 1;
|
||||
static const unsigned STRING_ITERATOR_PROTO = ARRAY_ITERATOR_PROTO + 1;
|
||||
static const unsigned LEGACY_GENERATOR_OBJECT_PROTO = STRING_ITERATOR_PROTO + 1;
|
||||
static const unsigned STAR_GENERATOR_OBJECT_PROTO = LEGACY_GENERATOR_OBJECT_PROTO + 1;
|
||||
static const unsigned MAP_ITERATOR_PROTO = STAR_GENERATOR_OBJECT_PROTO + 1;
|
||||
static const unsigned SET_ITERATOR_PROTO = MAP_ITERATOR_PROTO + 1;
|
||||
static const unsigned COLLATOR_PROTO = SET_ITERATOR_PROTO + 1;
|
||||
static const unsigned NUMBER_FORMAT_PROTO = COLLATOR_PROTO + 1;
|
||||
static const unsigned DATE_TIME_FORMAT_PROTO = NUMBER_FORMAT_PROTO + 1;
|
||||
static const unsigned REGEXP_STATICS = DATE_TIME_FORMAT_PROTO + 1;
|
||||
static const unsigned WARNED_ONCE_FLAGS = REGEXP_STATICS + 1;
|
||||
static const unsigned RUNTIME_CODEGEN_ENABLED = WARNED_ONCE_FLAGS + 1;
|
||||
static const unsigned DEBUGGERS = RUNTIME_CODEGEN_ENABLED + 1;
|
||||
static const unsigned INTRINSICS = DEBUGGERS + 1;
|
||||
static const unsigned FLOAT32X4_TYPE_DESCR = INTRINSICS + 1;
|
||||
static const unsigned FLOAT64X2_TYPE_DESCR = FLOAT32X4_TYPE_DESCR + 1;
|
||||
static const unsigned INT32X4_TYPE_DESCR = FLOAT64X2_TYPE_DESCR + 1;
|
||||
static const unsigned FOR_OF_PIC_CHAIN = INT32X4_TYPE_DESCR + 1;
|
||||
/* One-off properties stored after slots for built-ins. */
|
||||
ARRAY_ITERATOR_PROTO,
|
||||
STRING_ITERATOR_PROTO,
|
||||
LEGACY_GENERATOR_OBJECT_PROTO,
|
||||
STAR_GENERATOR_OBJECT_PROTO,
|
||||
MAP_ITERATOR_PROTO,
|
||||
SET_ITERATOR_PROTO,
|
||||
COLLATOR_PROTO,
|
||||
NUMBER_FORMAT_PROTO,
|
||||
DATE_TIME_FORMAT_PROTO,
|
||||
REGEXP_STATICS,
|
||||
WARNED_ONCE_FLAGS,
|
||||
RUNTIME_CODEGEN_ENABLED,
|
||||
DEBUGGERS,
|
||||
INTRINSICS,
|
||||
FLOAT32X4_TYPE_DESCR,
|
||||
FLOAT64X2_TYPE_DESCR,
|
||||
INT32X4_TYPE_DESCR,
|
||||
FOR_OF_PIC_CHAIN,
|
||||
|
||||
/* Total reserved-slot count for global objects. */
|
||||
static const unsigned RESERVED_SLOTS = FOR_OF_PIC_CHAIN + 1;
|
||||
/* Total reserved-slot count for global objects. */
|
||||
RESERVED_SLOTS
|
||||
};
|
||||
|
||||
/*
|
||||
* The slot count must be in the public API for JSCLASS_GLOBAL_FLAGS, and
|
||||
|
@ -28,7 +28,6 @@
|
||||
#include "mozilla/dom/StructuredCloneTags.h"
|
||||
#include "mozilla/dom/WindowBinding.h"
|
||||
#include "nsZipArchive.h"
|
||||
#include "nsIDOMFile.h"
|
||||
#include "nsIDOMFileList.h"
|
||||
#include "nsWindowMemoryReporter.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
|
@ -3394,8 +3394,8 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
|
||||
// 1MB is the default stack size on Windows, so use 900k.
|
||||
// Windows PGO stack frames have unfortunately gotten pretty large lately. :-(
|
||||
const size_t kStackQuota = 900 * 1024;
|
||||
const size_t kTrustedScriptBuffer = (sizeof(size_t) == 8) ? 160 * 1024
|
||||
: 100 * 1024;
|
||||
const size_t kTrustedScriptBuffer = (sizeof(size_t) == 8) ? 180 * 1024 //win64
|
||||
: 120 * 1024; //win32
|
||||
// The following two configurations are linux-only. Given the numbers above,
|
||||
// we use 50k and 100k trusted buffers on 32-bit and 64-bit respectively.
|
||||
#elif defined(DEBUG)
|
||||
|
@ -49,7 +49,7 @@
|
||||
if (Array.isArray(a))
|
||||
return 'array';
|
||||
|
||||
if (a instanceof Ci.nsIDOMFile)
|
||||
if (a instanceof File)
|
||||
return 'file';
|
||||
|
||||
if (a instanceof Ci.nsIDOMBlob)
|
||||
|
@ -3,7 +3,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Components.utils.importGlobalProperties(['Blob']);
|
||||
Components.utils.importGlobalProperties(['Blob', 'File']);
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
@ -31,7 +31,7 @@ BlobComponent.prototype =
|
||||
// do some tests
|
||||
do_check_true(f1 instanceof Ci.nsIDOMBlob, "Should be a DOM Blob");
|
||||
|
||||
do_check_true(!(f1 instanceof Ci.nsIDOMFile), "Should not be a DOM File");
|
||||
do_check_true(!(f1 instanceof File), "Should not be a DOM File");
|
||||
|
||||
do_check_true(f1.type == "text/xml", "Wrong type");
|
||||
|
||||
|
@ -36,8 +36,8 @@ FileComponent.prototype =
|
||||
var f2 = new File(file);
|
||||
|
||||
// do some tests
|
||||
do_check_true(f1 instanceof Ci.nsIDOMFile, "Should be a DOM File");
|
||||
do_check_true(f2 instanceof Ci.nsIDOMFile, "Should be a DOM File");
|
||||
do_check_true(f1 instanceof File, "Should be a DOM File");
|
||||
do_check_true(f2 instanceof File, "Should be a DOM File");
|
||||
|
||||
do_check_true(f1.name == "xpcshell.ini", "Should be the right file");
|
||||
do_check_true(f2.name == "xpcshell.ini", "Should be the right file");
|
||||
|
@ -2,7 +2,7 @@
|
||||
* 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/. */
|
||||
|
||||
Components.utils.importGlobalProperties(['Blob']);
|
||||
Components.utils.importGlobalProperties(['Blob', 'File']);
|
||||
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
@ -15,7 +15,7 @@ function run_test() {
|
||||
// do some tests
|
||||
do_check_true(f1 instanceof Ci.nsIDOMBlob, "Should be a DOM Blob");
|
||||
|
||||
do_check_true(!(f1 instanceof Ci.nsIDOMFile), "Should not be a DOM File");
|
||||
do_check_true(!(f1 instanceof File), "Should not be a DOM File");
|
||||
|
||||
do_check_true(f1.type == "text/xml", "Wrong type");
|
||||
|
||||
|
@ -21,8 +21,8 @@ function run_test() {
|
||||
var f2 = new File(file);
|
||||
|
||||
// do some tests
|
||||
do_check_true(f1 instanceof Ci.nsIDOMFile, "Should be a DOM File");
|
||||
do_check_true(f2 instanceof Ci.nsIDOMFile, "Should be a DOM File");
|
||||
do_check_true(f1 instanceof File, "Should be a DOM File");
|
||||
do_check_true(f2 instanceof File, "Should be a DOM File");
|
||||
|
||||
do_check_true(f1.name == "xpcshell.ini", "Should be the right file");
|
||||
do_check_true(f2.name == "xpcshell.ini", "Should be the right file");
|
||||
|
@ -1478,7 +1478,7 @@ void nsDisplaySelectionOverlay::Paint(nsDisplayListBuilder* aBuilder,
|
||||
nsIntRect pxRect =
|
||||
mVisibleRect.ToOutsidePixels(mFrame->PresContext()->AppUnitsPerDevPixel());
|
||||
Rect rect(pxRect.x, pxRect.y, pxRect.width, pxRect.height);
|
||||
MaybeSnapToDevicePixels(rect, aDrawTarget);
|
||||
MaybeSnapToDevicePixels(rect, aDrawTarget, true);
|
||||
|
||||
aDrawTarget.FillRect(rect, color);
|
||||
}
|
||||
|
@ -1,25 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait">
|
||||
<head>
|
||||
<style type="text/css">
|
||||
#rear {
|
||||
width: 500px;
|
||||
height: 1500px;
|
||||
box-shadow: 0 0 71px #667;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
document.documentElement.scrollTop = 0;
|
||||
|
||||
function doTest() {
|
||||
document.documentElement.scrollTop = 108;
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
window.addEventListener("MozReftestInvalidate", doTest);
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="rear"></div>
|
||||
</body>
|
||||
</html>
|
@ -1,26 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait">
|
||||
<meta charset="utf-8">
|
||||
<title>Scrolling shouldn't cause gaps in the shadow</title>
|
||||
<style type="text/css">
|
||||
#rear {
|
||||
width: 500px;
|
||||
height: 1500px;
|
||||
box-shadow: 0 0 71px #667;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="rear"></div>
|
||||
|
||||
<script>
|
||||
|
||||
function doTest() {
|
||||
document.documentElement.scrollTop = 108;
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
window.addEventListener("MozReftestInvalidate", doTest);
|
||||
|
||||
document.documentElement.scrollTop = 112;
|
||||
|
||||
</script>
|
@ -1923,5 +1923,4 @@ skip-if(!asyncPanZoom) fuzzy-if(B2G,101,887) == 1133905-6-vh-rtl.html 1133905-re
|
||||
skip-if(B2G||Mulet) == 1150021-1.xul 1150021-1-ref.xul
|
||||
== 1151145-1.html 1151145-1-ref.html
|
||||
== 1151306-1.html 1151306-1-ref.html
|
||||
== 1155828-1.html 1155828-1-ref.html
|
||||
== 1156129-1.html 1156129-1-ref.html
|
||||
|
@ -110,3 +110,44 @@ f.os2_typolinegap = lineheight - (f.os2_typoascent - f.os2_typodescent)
|
||||
f.hhea_linegap = lineheight - 800
|
||||
|
||||
f.generate("markA-lineheight" + str(lineheight) + ".ttf")
|
||||
|
||||
# Fonts with known winHeight and typoLineHeight such that winHeight is much
|
||||
# larger than typoLineHeight.
|
||||
f = fontforge.font()
|
||||
typoLineHeight = 2700
|
||||
winHeight = 6000
|
||||
n = "MarkA-lineheight" + str(winHeight)
|
||||
n = n + "-typolineheight" + str(typoLineHeight)
|
||||
f.fontname = n
|
||||
f.familyname = n
|
||||
f.fullname = n
|
||||
f.copyright = "Copyright (c) 2008-2015 Mozilla Corporation"
|
||||
|
||||
g = f.createChar(ord(" "), "space")
|
||||
g.width = 1000
|
||||
g = f.createChar(ord("A"), "A")
|
||||
g.importOutlines("mark-glyph.svg")
|
||||
g.width = 1500
|
||||
|
||||
f.os2_typoascent_add = False
|
||||
f.os2_typoascent = 800
|
||||
f.os2_typodescent_add = False
|
||||
f.os2_typodescent = -200
|
||||
f.os2_typolinegap = typoLineHeight - (f.os2_typoascent - f.os2_typodescent)
|
||||
|
||||
f.hhea_ascent = winHeight / 2
|
||||
f.hhea_ascent_add = False
|
||||
f.hhea_descent = winHeight / 2
|
||||
f.hhea_descent_add = False
|
||||
f.hhea_linegap = 0
|
||||
|
||||
f.os2_winascent = winHeight / 2
|
||||
f.os2_winascent_add = False
|
||||
f.os2_windescent = winHeight / 2
|
||||
f.os2_windescent_add = False
|
||||
|
||||
f.os2_use_typo_metrics = True
|
||||
f.generate("markA-lineheight" + str(winHeight) +
|
||||
"-typolineheight" + str(typoLineHeight) + ".otf")
|
||||
f.generate("markA-lineheight" + str(winHeight) +
|
||||
"-typolineheight" + str(typoLineHeight) + ".ttf")
|
||||
|
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user