diff --git a/accessible/src/base/AccCollector.h b/accessible/src/base/AccCollector.h index fede67d31596..19b95bc235f1 100644 --- a/accessible/src/base/AccCollector.h +++ b/accessible/src/base/AccCollector.h @@ -5,7 +5,7 @@ #ifndef mozilla_a11y_AccCollector_h__ #define mozilla_a11y_AccCollector_h__ -#include "AccFilters.h" +#include "Filters.h" #include "nsTArray.h" diff --git a/accessible/src/base/AccIterator.h b/accessible/src/base/AccIterator.h index e613f9a0ebe6..3dc1e2fa465e 100644 --- a/accessible/src/base/AccIterator.h +++ b/accessible/src/base/AccIterator.h @@ -8,7 +8,7 @@ #define mozilla_a11y_AccIterator_h__ #include "DocAccessible.h" -#include "AccFilters.h" +#include "Filters.h" #include "nsAccessibilityService.h" namespace mozilla { diff --git a/accessible/src/base/AccFilters.cpp b/accessible/src/base/Filters.cpp similarity index 98% rename from accessible/src/base/AccFilters.cpp rename to accessible/src/base/Filters.cpp index 22fb1f98b1d8..58f62585f16f 100644 --- a/accessible/src/base/AccFilters.cpp +++ b/accessible/src/base/Filters.cpp @@ -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/. */ -#include "AccFilters.h" +#include "Filters.h" #include "Accessible-inl.h" #include "nsAccUtils.h" diff --git a/accessible/src/base/AccFilters.h b/accessible/src/base/Filters.h similarity index 100% rename from accessible/src/base/AccFilters.h rename to accessible/src/base/Filters.h diff --git a/accessible/src/base/Makefile.in b/accessible/src/base/Makefile.in index a0ce1dd2d5a5..18fa1776bede 100644 --- a/accessible/src/base/Makefile.in +++ b/accessible/src/base/Makefile.in @@ -19,7 +19,7 @@ CPPSRCS = \ AccEvent.cpp \ AccGroupInfo.cpp \ AccIterator.cpp \ - AccFilters.cpp \ + Filters.cpp \ ARIAStateMap.cpp \ FocusManager.cpp \ NotificationController.cpp \ diff --git a/b2g/components/DirectoryProvider.js b/b2g/components/DirectoryProvider.js index 208c355c0821..b02a3a560d1b 100644 --- a/b2g/components/DirectoryProvider.js +++ b/b2g/components/DirectoryProvider.js @@ -23,12 +23,17 @@ DirectoryProvider.prototype = { getFile: function dp_getFile(prop, persistent) { #ifdef MOZ_WIDGET_GONK let localProps = ["cachePDir", "webappsDir", "PrefD", "indexedDBPDir", - "permissionDBPDir", "UpdRootD"]; + "permissionDBPDir", "UpdRootD"]; if (localProps.indexOf(prop) != -1) { - prop.persistent = true; let file = Cc["@mozilla.org/file/local;1"] .createInstance(Ci.nsILocalFile) file.initWithPath(LOCAL_DIR); + persistent.value = true; + return file; + } else if (prop == "coreAppsDir") { + let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile) + file.initWithPath("/system/b2g"); + persistent.value = true; return file; } #endif diff --git a/browser/base/content/socialchat.xml b/browser/base/content/socialchat.xml index f5168d12ccf4..aba120879d7d 100644 --- a/browser/base/content/socialchat.xml +++ b/browser/base/content/socialchat.xml @@ -176,7 +176,7 @@ 200) { + if (child && this.emptyWidth > child.viewWidth) { this.showChat(child); } if (!this.firstCollapsedChild) { @@ -211,6 +211,7 @@ * nsContentUtils::sAtomEventTable = nullptr; nsDataHashtable* nsContentUtils::sStringEventTable = nullptr; @@ -508,15 +512,17 @@ nsContentUtils::InitImgLoader() sImgLoaderInitialized = true; // Ignore failure and just don't load images - nsresult rv = CallGetService("@mozilla.org/image/loader;1", &sImgLoader); - if (NS_FAILED(rv)) { - // no image loading for us. Oh, well. - sImgLoader = nullptr; - sImgCache = nullptr; - } else { - if (NS_FAILED(CallGetService("@mozilla.org/image/cache;1", &sImgCache ))) - sImgCache = nullptr; - } + nsresult rv = CallCreateInstance("@mozilla.org/image/loader;1", &sImgLoader); + NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "Creation should have succeeded"); + rv = CallCreateInstance("@mozilla.org/image/loader;1", &sPrivateImgLoader); + NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "Creation should have succeeded"); + + rv = CallQueryInterface(sImgLoader, &sImgCache); + NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "imgICache and imgILoader should be paired"); + rv = CallQueryInterface(sPrivateImgLoader, &sPrivateImgCache); + NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "imgICache and imgILoader should be paired"); + + sPrivateImgCache->RespectPrivacyNotifications(); } bool @@ -1493,7 +1499,9 @@ nsContentUtils::Shutdown() NS_IF_RELEASE(sXTFService); #endif NS_IF_RELEASE(sImgLoader); + NS_IF_RELEASE(sPrivateImgLoader); NS_IF_RELEASE(sImgCache); + NS_IF_RELEASE(sPrivateImgCache); #ifdef IBMBIDI NS_IF_RELEASE(sBidiKeyboard); #endif @@ -2692,19 +2700,60 @@ nsContentUtils::CanLoadImage(nsIURI* aURI, nsISupports* aContext, return NS_FAILED(rv) ? false : NS_CP_ACCEPTED(decision); } +imgILoader* +nsContentUtils::GetImgLoaderForDocument(nsIDocument* aDoc) +{ + if (!sImgLoaderInitialized) + InitImgLoader(); + if (!aDoc) + return sImgLoader; + bool isPrivate = false; + nsCOMPtr loadGroup = aDoc->GetDocumentLoadGroup(); + nsCOMPtr callbacks; + if (loadGroup) { + loadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks)); + if (callbacks) { + nsCOMPtr loadContext = do_GetInterface(callbacks); + isPrivate = loadContext && loadContext->UsePrivateBrowsing(); + } + } else { + nsCOMPtr channel = aDoc->GetChannel(); + if (channel) { + nsCOMPtr context; + NS_QueryNotificationCallbacks(channel, context); + isPrivate = context && context->UsePrivateBrowsing(); + } + } + return isPrivate ? sPrivateImgLoader : sImgLoader; +} + +// static +imgILoader* +nsContentUtils::GetImgLoaderForChannel(nsIChannel* aChannel) +{ + if (!sImgLoaderInitialized) + InitImgLoader(); + if (!aChannel) + return sImgLoader; + nsCOMPtr context; + NS_QueryNotificationCallbacks(aChannel, context); + return context && context->UsePrivateBrowsing() ? sPrivateImgLoader : sImgLoader; +} + // static bool -nsContentUtils::IsImageInCache(nsIURI* aURI) +nsContentUtils::IsImageInCache(nsIURI* aURI, nsIDocument* aDocument) { if (!sImgLoaderInitialized) InitImgLoader(); - if (!sImgCache) return false; + imgILoader* loader = GetImgLoaderForDocument(aDocument); + nsCOMPtr cache = do_QueryInterface(loader); // If something unexpected happened we return false, otherwise if props // is set, the image is cached and we return true nsCOMPtr props; - nsresult rv = sImgCache->FindEntryProperties(aURI, getter_AddRefs(props)); + nsresult rv = cache->FindEntryProperties(aURI, getter_AddRefs(props)); return (NS_SUCCEEDED(rv) && props); } @@ -2720,7 +2769,7 @@ nsContentUtils::LoadImage(nsIURI* aURI, nsIDocument* aLoadingDocument, NS_PRECONDITION(aLoadingPrincipal, "Must have a principal"); NS_PRECONDITION(aRequest, "Null out param"); - imgILoader* imgLoader = GetImgLoader(); + imgILoader* imgLoader = GetImgLoaderForDocument(aLoadingDocument); if (!imgLoader) { // nothing we can do here return NS_OK; diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index fe1dbc2adf52..cf67e8abbccd 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -7681,7 +7681,7 @@ nsDocument::MaybePreLoadImage(nsIURI* uri, const nsAString &aCrossOriginAttr) // which indicates that the "real" load has already started and // that we shouldn't preload it. int16_t blockingStatus; - if (nsContentUtils::IsImageInCache(uri) || + if (nsContentUtils::IsImageInCache(uri, static_cast(this)) || !nsContentUtils::CanLoadImage(uri, static_cast(this), this, NodePrincipal(), &blockingStatus)) { return; diff --git a/content/base/src/nsImageLoadingContent.cpp b/content/base/src/nsImageLoadingContent.cpp index 7e1d39a8a5c1..3ab8ce77bc73 100644 --- a/content/base/src/nsImageLoadingContent.cpp +++ b/content/base/src/nsImageLoadingContent.cpp @@ -88,7 +88,7 @@ nsImageLoadingContent::nsImageLoadingContent() mCurrentRequestRegistered(false), mPendingRequestRegistered(false) { - if (!nsContentUtils::GetImgLoader()) { + if (!nsContentUtils::GetImgLoaderForChannel(nullptr)) { mLoadingEnabled = false; } } @@ -334,7 +334,7 @@ nsImageLoadingContent::SetLoadingEnabled(bool aLoadingEnabled) { NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE); - if (nsContentUtils::GetImgLoader()) { + if (nsContentUtils::GetImgLoaderForChannel(nullptr)) { mLoadingEnabled = aLoadingEnabled; } return NS_OK; @@ -518,7 +518,7 @@ nsImageLoadingContent::LoadImageWithChannel(nsIChannel* aChannel, { NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE); - if (!nsContentUtils::GetImgLoader()) { + if (!nsContentUtils::GetImgLoaderForChannel(aChannel)) { return NS_ERROR_NULL_POINTER; } @@ -537,7 +537,7 @@ nsImageLoadingContent::LoadImageWithChannel(nsIChannel* aChannel, // Do the load. nsCOMPtr& req = PrepareNextRequest(); - nsresult rv = nsContentUtils::GetImgLoader()-> + nsresult rv = nsContentUtils::GetImgLoaderForChannel(aChannel)-> LoadImageWithChannel(aChannel, this, doc, aListener, getter_AddRefs(req)); if (NS_SUCCEEDED(rv)) { diff --git a/content/base/src/nsObjectLoadingContent.cpp b/content/base/src/nsObjectLoadingContent.cpp index 19c03ec86fba..4ccd8ed1c399 100644 --- a/content/base/src/nsObjectLoadingContent.cpp +++ b/content/base/src/nsObjectLoadingContent.cpp @@ -477,7 +477,7 @@ URIEquals(nsIURI *a, nsIURI *b) static bool IsSupportedImage(const nsCString& aMimeType) { - imgILoader* loader = nsContentUtils::GetImgLoader(); + nsCOMPtr loader = nsContentUtils::GetImgLoaderForChannel(nullptr); if (!loader) { return false; } diff --git a/content/base/test/progressserver.sjs b/content/base/test/progressserver.sjs index 9f6c59dc9d71..054090644c54 100644 --- a/content/base/test/progressserver.sjs +++ b/content/base/test/progressserver.sjs @@ -19,6 +19,7 @@ function handleRequest(request, response) { var pairs = request.queryString.split('&'); var command = pairs.shift(); + dump("received '" + command + "' command\n"); var bodyStream = new BinaryInputStream(request.bodyInputStream); var body = ""; diff --git a/content/base/test/test_xhr_progressevents.html b/content/base/test/test_xhr_progressevents.html index c749e6cfff7b..dbd016b28d34 100644 --- a/content/base/test/test_xhr_progressevents.html +++ b/content/base/test/test_xhr_progressevents.html @@ -14,7 +14,11 @@ SimpleTest.waitForExplicitFinish(); var gen = runTests(); function log(s) { - //document.getElementById("l").textContent += s + "\n"; + // Uncomment these to get debugging information + /* + document.getElementById("l").textContent += s + "\n"; + dump(s + "\n"); + */ } function getEvent(e) { @@ -101,6 +105,7 @@ function closeConn() { var xhr = new XMLHttpRequest(); xhr.open("POST", "progressserver.sjs?close"); xhr.send(); + return xhr; } var longString = "long"; @@ -214,8 +219,9 @@ function runTests() { } if ("close" in test) { log("closing"); + let xhrClose; if (!testState.file) - closeConn(); + xhrClose = closeConn(); e = yield; is(e.type, "readystatechange", "should readystate to done closing " + testState.name); @@ -241,6 +247,16 @@ function runTests() { is(e.lengthComputable, true, "length should be computable during loadend closing " + testState.name); log("got loadend"); + // if we closed the connection using an explicit request, make sure that goes through before + // running the next test in order to avoid reordered requests from closing the wrong + // connection. + if (xhrClose && xhrClose.readyState != xhrClose.DONE) { + log("wait for closeConn to finish"); + xhrClose.onloadend = getEvent; + yield; + is(xhrClose.readyState, xhrClose.DONE, "closeConn finished"); + } + if (responseType.chunked) { is(xhr.response, null, "chunked data has null response for " + testState.name); } diff --git a/content/media/Makefile.in b/content/media/Makefile.in index 3d7f9e612746..d9c564ea7894 100644 --- a/content/media/Makefile.in +++ b/content/media/Makefile.in @@ -62,6 +62,8 @@ CPPSRCS += \ $(NULL) endif +PARALLEL_DIRS += webaudio + ifdef MOZ_RAW PARALLEL_DIRS += raw endif diff --git a/content/media/nsAudioStream.cpp b/content/media/nsAudioStream.cpp index ac8ef58c0216..8087d312659d 100644 --- a/content/media/nsAudioStream.cpp +++ b/content/media/nsAudioStream.cpp @@ -953,10 +953,11 @@ nsBufferedAudioStream::Init(int32_t aNumChannels, int32_t aRate) params.channels = aNumChannels; #ifdef MOZ_SAMPLE_TYPE_S16LE params.format = CUBEB_SAMPLE_S16NE; + mBytesPerFrame = sizeof(int16_t) * aNumChannels; #else /* MOZ_SAMPLE_TYPE_FLOAT32 */ params.format = CUBEB_SAMPLE_FLOAT32NE; -#endif mBytesPerFrame = sizeof(float) * aNumChannels; +#endif { cubeb_stream* stream; diff --git a/content/media/webaudio/AudioContext.cpp b/content/media/webaudio/AudioContext.cpp new file mode 100644 index 000000000000..9959ebc8ed25 --- /dev/null +++ b/content/media/webaudio/AudioContext.cpp @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "AudioContext.h" +#include "nsContentUtils.h" +#include "nsIDOMWindow.h" +#include "mozilla/ErrorResult.h" +#include "mozilla/dom/AudioContextBinding.h" + +namespace mozilla { + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(AudioContext, mWindow) +NS_IMPL_CYCLE_COLLECTING_ADDREF(AudioContext) +NS_IMPL_CYCLE_COLLECTING_RELEASE(AudioContext) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AudioContext) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +AudioContext::AudioContext(nsIDOMWindow* aWindow) + : mWindow(aWindow) +{ + SetIsDOMBinding(); +} + +AudioContext::~AudioContext() +{ +} + +JSObject* +AudioContext::WrapObject(JSContext* aCx, JSObject* aScope, + bool* aTriedToWrap) +{ + return dom::mozAudioContextBinding::Wrap(aCx, aScope, this, + aTriedToWrap); +} + +/* static */ already_AddRefed +AudioContext::Constructor(nsISupports* aGlobal, ErrorResult& aRv) +{ + nsCOMPtr window = do_QueryInterface(aGlobal); + if (!window) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + AudioContext* object = new AudioContext(window); + NS_ADDREF(object); + return object; +} + +} + diff --git a/content/media/webaudio/AudioContext.h b/content/media/webaudio/AudioContext.h new file mode 100644 index 000000000000..04519789e12a --- /dev/null +++ b/content/media/webaudio/AudioContext.h @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsWrapperCache.h" +#include "nsCycleCollectionParticipant.h" +#include "mozilla/Attributes.h" +#include "nsCOMPtr.h" + +class JSContext; +class nsIDOMWindow; + +namespace mozilla { + +class ErrorResult; + +class AudioContext MOZ_FINAL : public nsISupports, + public nsWrapperCache +{ + explicit AudioContext(nsIDOMWindow* aParentWindow); + +public: + virtual ~AudioContext(); + + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(AudioContext) + + nsIDOMWindow* GetParentObject() const + { + return mWindow; + } + + virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope, + bool* aTriedToWrap); + + static already_AddRefed + Constructor(nsISupports* aGlobal, ErrorResult& aRv); + +private: + nsCOMPtr mWindow; +}; + +} + diff --git a/content/media/webaudio/Makefile.in b/content/media/webaudio/Makefile.in new file mode 100644 index 000000000000..0e3ef08c2932 --- /dev/null +++ b/content/media/webaudio/Makefile.in @@ -0,0 +1,25 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +DEPTH := @DEPTH@ +topsrcdir := @top_srcdir@ +srcdir := @srcdir@ +VPATH := @srcdir@ +FAIL_ON_WARNINGS := 1 + +include $(DEPTH)/config/autoconf.mk + +MODULE := content +LIBRARY_NAME := gkconwebaudio_s +LIBXUL_LIBRARY := 1 + +CPPSRCS := \ + AudioContext.cpp + $(NULL) + +PARALLEL_DIRS := test + +FORCE_STATIC_LIB := 1 + +include $(topsrcdir)/config/rules.mk diff --git a/content/media/webaudio/test/Makefile.in b/content/media/webaudio/test/Makefile.in new file mode 100644 index 000000000000..8aaeb9d18acd --- /dev/null +++ b/content/media/webaudio/test/Makefile.in @@ -0,0 +1,17 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +DEPTH := @DEPTH@ +topsrcdir := @top_srcdir@ +srcdir := @srcdir@ +VPATH := @srcdir@ +relativesrcdir := @relativesrcdir@ + +include $(DEPTH)/config/autoconf.mk + +MOCHITEST_FILES := \ + test_AudioContext.html \ + $(NULL) + +include $(topsrcdir)/config/rules.mk diff --git a/content/media/webaudio/test/test_AudioContext.html b/content/media/webaudio/test/test_AudioContext.html new file mode 100644 index 000000000000..f11ed3d296ee --- /dev/null +++ b/content/media/webaudio/test/test_AudioContext.html @@ -0,0 +1,22 @@ + + + + Test whether we can create an AudioContext interface + + + + +
+
+
+ + diff --git a/content/svg/content/src/nsSVGSVGElement.cpp b/content/svg/content/src/nsSVGSVGElement.cpp index 08b97ca6a055..5b91587a1e3c 100644 --- a/content/svg/content/src/nsSVGSVGElement.cpp +++ b/content/svg/content/src/nsSVGSVGElement.cpp @@ -934,7 +934,7 @@ nsSVGSVGElement::GetViewBoxTransform() const } void -nsSVGSVGElement::ChildrenOnlyTransformChanged() +nsSVGSVGElement::ChildrenOnlyTransformChanged(PRUint32 aFlags) { // Avoid wasteful calls: NS_ABORT_IF_FALSE(!(GetPrimaryFrame()->GetStateBits() & @@ -957,7 +957,15 @@ nsSVGSVGElement::ChildrenOnlyTransformChanged() nsChangeHint_ChildrenOnlyTransform); } - nsLayoutUtils::PostRestyleEvent(this, nsRestyleHint(0), changeHint); + // If we're not reconstructing the frame tree, then we only call + // PostRestyleEvent if we're not being called under reflow to avoid recursing + // to death. See bug 767056 comments 10 and 12. Since our nsSVGOuterSVGFrame + // is being reflowed we're going to invalidate and repaint its entire area + // anyway (which will include our children). + if ((changeHint & nsChangeHint_ReconstructFrame) || + !(aFlags & eDuringReflow)) { + nsLayoutUtils::PostRestyleEvent(this, nsRestyleHint(0), changeHint); + } mHasChildrenOnlyTransform = hasChildrenOnlyTransform; } diff --git a/content/svg/content/src/nsSVGSVGElement.h b/content/svg/content/src/nsSVGSVGElement.h index 7eb8b5193567..87a9dc009cc8 100644 --- a/content/svg/content/src/nsSVGSVGElement.h +++ b/content/svg/content/src/nsSVGSVGElement.h @@ -210,6 +210,10 @@ public: return mHasChildrenOnlyTransform; } + enum ChildrenOnlyTransformChangedFlags { + eDuringReflow = 1 + }; + /** * This method notifies the style system that the overflow rects of our * immediate childrens' frames need to be updated. It is called by our own @@ -220,7 +224,7 @@ public: * GetAttributeChangeHint is because we need to act on non-attribute (e.g. * currentScale) changes in addition to attribute (e.g. viewBox) changes. */ - void ChildrenOnlyTransformChanged(); + void ChildrenOnlyTransformChanged(PRUint32 aFlags = 0); // This services any pending notifications for the transform on on this root // node needing to be recalculated. (Only applicable in diff --git a/docshell/base/nsWebNavigationInfo.cpp b/docshell/base/nsWebNavigationInfo.cpp index 30b42e846008..1567bc873be0 100644 --- a/docshell/base/nsWebNavigationInfo.cpp +++ b/docshell/base/nsWebNavigationInfo.cpp @@ -24,9 +24,9 @@ nsWebNavigationInfo::Init() mCategoryManager = do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); - mImgLoader = do_GetService("@mozilla.org/image/loader;1", &rv); + mImgLoader = nsContentUtils::GetImgLoaderForChannel(nullptr); - return rv; + return NS_OK; } NS_IMETHODIMP diff --git a/dom/Makefile.in b/dom/Makefile.in index 76330d5f990b..0d5eaec6900f 100644 --- a/dom/Makefile.in +++ b/dom/Makefile.in @@ -44,7 +44,6 @@ PARALLEL_DIRS += \ apps \ base \ activities \ - bindings \ battery \ browser-element \ contacts \ @@ -91,6 +90,12 @@ PARALLEL_DIRS += \ $(NULL) endif +# Not in PARALLEL_DIRS because we need to make sure it builds before +# bindings/test, which builds from TEST_DIRS, which gets appended to DIRS. +DIRS = \ + bindings \ + $(NULL) + # bindings/test is here, because it needs to build after bindings/, and # we build subdirectories before ourselves. TEST_DIRS += \ diff --git a/dom/apps/src/AppsService.js b/dom/apps/src/AppsService.js index c2860946f9e8..aea97fa26614 100644 --- a/dom/apps/src/AppsService.js +++ b/dom/apps/src/AppsService.js @@ -47,6 +47,11 @@ AppsService.prototype = { return DOMApplicationRegistry.getManifestURLByLocalId(aLocalId); }, + getAppFromObserverMessage: function getAppFromObserverMessage(aMessage) { + debug("getAppFromObserverMessage( " + aMessage + " )"); + return DOMApplicationRegistry.getAppFromObserverMessage(aMessage); + }, + classID : APPS_SERVICE_CID, QueryInterface : XPCOMUtils.generateQI([Ci.nsIAppsService]) } diff --git a/dom/apps/src/AppsServiceChild.jsm b/dom/apps/src/AppsServiceChild.jsm index 0383f6558bb0..54400e2591f3 100644 --- a/dom/apps/src/AppsServiceChild.jsm +++ b/dom/apps/src/AppsServiceChild.jsm @@ -76,6 +76,11 @@ let DOMApplicationRegistry = { getManifestURLByLocalId: function getManifestURLByLocalId(aLocalId) { debug("getManifestURLByLocalId " + aLocalId); return AppsUtils.getManifestURLByLocalId(this.webapps, aLocalId); + }, + + getAppFromObserverMessage: function getAppFromObserverMessage(aMessage) { + debug("getAppFromObserverMessage " + aMessage); + return AppsUtils.getAppFromObserverMessage(this.webapps. aMessage); } } diff --git a/dom/apps/src/AppsUtils.jsm b/dom/apps/src/AppsUtils.jsm index fbc49a2c0ea0..36237361b160 100644 --- a/dom/apps/src/AppsUtils.jsm +++ b/dom/apps/src/AppsUtils.jsm @@ -30,6 +30,7 @@ let AppsUtils = { installTime: aApp.installTime, manifestURL: aApp.manifestURL, appStatus: aApp.appStatus, + removable: aApp.removable, localId: aApp.localId, progress: aApp.progress || 0.0, status: aApp.status || "installed" @@ -104,5 +105,20 @@ let AppsUtils = { } return ""; + }, + + getAppFromObserverMessage: function(aApps, aMessage) { + let data = JSON.parse(aMessage); + + for (let id in aApps) { + let app = aApps[id]; + if (app.origin != data.origin) { + continue; + } + + return this.cloneAsMozIApplication(app); + } + + return null; } } diff --git a/dom/apps/src/Webapps.js b/dom/apps/src/Webapps.js index 66b7810ea09f..2292b6bacbd9 100644 --- a/dom/apps/src/Webapps.js +++ b/dom/apps/src/Webapps.js @@ -20,8 +20,7 @@ function convertAppsArray(aApps, aWindow) { let apps = Cu.createArrayIn(aWindow); for (let i = 0; i < aApps.length; i++) { let app = aApps[i]; - apps.push(createApplicationObject(aWindow, app.origin, app.manifest, app.manifestURL, - app.receipts, app.installOrigin, app.installTime)); + apps.push(createApplicationObject(aWindow, app)); } return apps; @@ -73,8 +72,7 @@ WebappsRegistry.prototype = { let app = msg.app; switch (aMessage.name) { case "Webapps:Install:Return:OK": - Services.DOMRequest.fireSuccess(req, createApplicationObject(this._window, app.origin, app.manifest, app.manifestURL, app.receipts, - app.installOrigin, app.installTime)); + Services.DOMRequest.fireSuccess(req, createApplicationObject(this._window, app)); break; case "Webapps:Install:Return:KO": Services.DOMRequest.fireError(req, msg.error || "DENIED"); @@ -82,8 +80,7 @@ WebappsRegistry.prototype = { case "Webapps:GetSelf:Return:OK": if (msg.apps.length) { app = msg.apps[0]; - Services.DOMRequest.fireSuccess(req, createApplicationObject(this._window, app.origin, app.manifest, app.manifestURL, app.receipts, - app.installOrigin, app.installTime)); + Services.DOMRequest.fireSuccess(req, createApplicationObject(this._window, app)); } else { Services.DOMRequest.fireSuccess(req, null); } @@ -223,9 +220,9 @@ WebappsRegistry.prototype = { * mozIDOMApplication object */ -function createApplicationObject(aWindow, aOrigin, aManifest, aManifestURL, aReceipts, aInstallOrigin, aInstallTime) { +function createApplicationObject(aWindow, aApp) { let app = Cc["@mozilla.org/webapps/application;1"].createInstance(Ci.mozIDOMApplication); - app.wrappedJSObject.init(aWindow, aOrigin, aManifest, aManifestURL, aReceipts, aInstallOrigin, aInstallTime); + app.wrappedJSObject.init(aWindow, aApp); return app; } @@ -246,20 +243,24 @@ WebappsApplication.prototype = { onprogress: 'rw', launch: 'r', receipts: 'r', + removable: 'r', uninstall: 'r' }, - init: function(aWindow, aOrigin, aManifest, aManifestURL, aReceipts, aInstallOrigin, aInstallTime) { - this.origin = aOrigin; - this.manifest = ObjectWrapper.wrap(aManifest, aWindow); - this.manifestURL = aManifestURL; - this.receipts = aReceipts; - this.installOrigin = aInstallOrigin; - this.installTime = aInstallTime; + init: function(aWindow, aApp) { + this.origin = aApp.origin; + this.manifest = ObjectWrapper.wrap(aApp.manifest, aWindow); + this.manifestURL = aApp.manifestURL; + this.receipts = aApp.receipts; + this.installOrigin = aApp.installOrigin; + this.installTime = aApp.installTime; this.status = "installed"; + this.removable = aApp.removable; this.progress = NaN; this._onprogress = null; - this.initHelper(aWindow, ["Webapps:Uninstall:Return:OK", "Webapps:Uninstall:Return:KO", "Webapps:OfflineCache"]); + this.initHelper(aWindow, ["Webapps:Uninstall:Return:OK", + "Webapps:Uninstall:Return:KO", + "Webapps:OfflineCache"]); }, set onprogress(aCallback) { @@ -422,15 +423,14 @@ WebappsApplicationMgmt.prototype = { if (this._oninstall) { let app = msg.app; let event = new this._window.MozApplicationEvent("applicationinstall", - { application : createApplicationObject(this._window, app.origin, app.manifest, app.manifestURL, app.receipts, - app.installOrigin, app.installTime) }); + { application : createApplicationObject(this._window, app) }); this._oninstall.handleEvent(event); } break; case "Webapps:Uninstall:Return:OK": if (this._onuninstall) { let event = new this._window.MozApplicationEvent("applicationuninstall", - { application : createApplicationObject(this._window, msg.origin, null, null, null, null, 0) }); + { application : createApplicationObject(this._window, { origin: msg.origin }) }); this._onuninstall.handleEvent(event); } break; diff --git a/dom/apps/src/Webapps.jsm b/dom/apps/src/Webapps.jsm index 732afd1d5460..002933b27437 100644 --- a/dom/apps/src/Webapps.jsm +++ b/dom/apps/src/Webapps.jsm @@ -71,33 +71,46 @@ let DOMApplicationRegistry = { this.appsFile = FileUtils.getFile(DIRECTORY_NAME, ["webapps", "webapps.json"], true); - if (this.appsFile.exists()) { - this._loadJSONAsync(this.appsFile, (function(aData) { - this.webapps = aData; - for (let id in this.webapps) { -#ifdef MOZ_SYS_MSG - this._processManifestForId(id); + let dirList = [DIRECTORY_NAME]; + +#ifdef MOZ_WIDGET_GONK + dirList.push("coreAppsDir"); #endif - if (!this.webapps[id].localId) { - this.webapps[id].localId = this._nextLocalId(); + let currentId = 1; + dirList.forEach((function(dir) { + let curFile = FileUtils.getFile(dir, ["webapps", "webapps.json"], true); + if (curFile.exists()) { + let appDir = FileUtils.getDir(dir, ["webapps"]); + this._loadJSONAsync(curFile, (function(aData) { + if (!aData) { + return; } + // Add new apps to the merged list. + for (let id in aData) { + this.webapps[id] = aData[id]; + this.webapps[id].basePath = appDir.path; + this.webapps[id].removable = (dir == DIRECTORY_NAME); +#ifdef MOZ_SYS_MSG + this._processManifestForId(id); +#endif + // local ids must be stable between restarts. + // We partition the ids in two buckets: + // - 1 to 1000 for the core apps. + // - 1001 to Inf for installed apps. + // This way, a gecko update with new core apps will not lead to + // changes for installed apps ids. + if (!this.webapps[id].removable) { + this.webapps[id].localId = currentId++; + } - // Default to a non privileged status. - if (this.webapps[id].appStatus === undefined) { - this.webapps[id].appStatus = Ci.nsIPrincipal.APP_STATUS_INSTALLED; - } - }; - }).bind(this)); - } - - try { - let hosts = Services.prefs.getCharPref("dom.mozApps.whitelist"); - hosts.split(",").forEach(function(aHost) { - Services.perms.add(Services.io.newURI(aHost, null, null), - "webapps-manage", - Ci.nsIPermissionManager.ALLOW_ACTION); - }); - } catch(e) { } + // Default to a non privileged status. + if (this.webapps[id].appStatus === undefined) { + this.webapps[id].appStatus = Ci.nsIPrincipal.APP_STATUS_INSTALLED; + } + }; + }).bind(this)); + } + }).bind(this)); }, #ifdef MOZ_SYS_MSG @@ -254,7 +267,7 @@ let DOMApplicationRegistry = { this.installPackage(msg); break; case "Webapps:GetBasePath": - return FileUtils.getFile(DIRECTORY_NAME, ["webapps"], true).path; + return this.webapps[msg.id].basePath; break; case "Webapps:GetList": this.children.push(aMessage.target); @@ -262,6 +275,10 @@ let DOMApplicationRegistry = { } }, + _getAppDir: function(aId) { + return FileUtils.getDir(DIRECTORY_NAME, ["webapps", aId], true, true); + }, + _writeFile: function ss_writeFile(aFile, aData, aCallbak) { // Initialize the file output stream. let ostream = FileUtils.openSafeFileOutputStream(aFile); @@ -294,12 +311,13 @@ let DOMApplicationRegistry = { confirmInstall: function(aData, aFromSync, aProfileDir, aOfflineCacheObserver) { let app = aData.app; + app.removable = true; let id = app.syncId || this._appId(app.origin); let localId = this.getAppLocalIdByManifestURL(app.manifestURL); // Installing an application again is considered as an update. if (id) { - let dir = FileUtils.getDir(DIRECTORY_NAME, ["webapps", id], true, true); + let dir = this._getAppDir(id); try { dir.remove(true); } catch(e) { @@ -375,7 +393,8 @@ let DOMApplicationRegistry = { }, _nextLocalId: function() { - let maxLocalId = Ci.nsIScriptSecurityManager.NO_APP_ID; + // All installed apps have a localId > 1000. + let maxLocalId = 1000; for (let id in this.webapps) { if (this.webapps[id].localId > maxLocalId) { @@ -419,9 +438,10 @@ let DOMApplicationRegistry = { let id = aData[index].id; // the manifest file used to be named manifest.json, so fallback on this. - let file = FileUtils.getFile(DIRECTORY_NAME, ["webapps", id, "manifest.webapp"], true); + let baseDir = (this.webapps[id].removable ? DIRECTORY_NAME : "coreAppsDir"); + let file = FileUtils.getFile(baseDir, ["webapps", id, "manifest.webapp"], true); if (!file.exists()) { - file = FileUtils.getFile(DIRECTORY_NAME, ["webapps", id, "manifest.json"], true); + file = FileUtils.getFile(baseDir, ["webapps", id, "manifest.json"], true); } this._loadJSONAsync(file, (function(aJSON) { @@ -598,6 +618,9 @@ let DOMApplicationRegistry = { continue; } + if (!this.webapps[id].removable) + return; + found = true; let appNote = JSON.stringify(AppsUtils.cloneAppObject(app)); appNote.id = id; @@ -608,7 +631,7 @@ let DOMApplicationRegistry = { #endif }).bind(this)); - let dir = FileUtils.getDir(DIRECTORY_NAME, ["webapps", id], true, true); + let dir = this._getAppDir(id); try { dir.remove(true); } catch (e) {} @@ -748,6 +771,10 @@ let DOMApplicationRegistry = { return AppsUtils.getAppLocalIdByManifestURL(this.webapps, aManifestURL); }, + getAppFromObserverMessage: function(aMessage) { + return AppsUtils.getAppFromObserverMessage(this.webapps, aMessage); + }, + getAllWithoutManifests: function(aCallback) { let result = {}; for (let id in this.webapps) { @@ -761,11 +788,11 @@ let DOMApplicationRegistry = { for (let i = 0; i < aRecords.length; i++) { let record = aRecords[i]; if (record.hidden) { - if (!this.webapps[record.id]) + if (!this.webapps[record.id] || !this.webapps[record.id].removable) continue; let origin = this.webapps[record.id].origin; delete this.webapps[record.id]; - let dir = FileUtils.getDir(DIRECTORY_NAME, ["webapps", record.id], true, true); + let dir = this._getAppDir(record.id); try { dir.remove(true); } catch (e) { @@ -798,8 +825,12 @@ let DOMApplicationRegistry = { wipe: function(aCallback) { let ids = this.getAllIDs(); for (let id in ids) { + if (!this.webapps[id].removable) { + continue; + } + delete this.webapps[id]; - let dir = FileUtils.getDir(DIRECTORY_NAME, ["webapps", id], true, true); + let dir = this._getAppDir(id); try { dir.remove(true); } catch (e) { diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf index d63ae9acd847..4556c40eaae2 100644 --- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -61,6 +61,11 @@ DOMInterfaces = { +'mozAudioContext': { + 'nativeType': 'AudioContext', + 'prefable': True, +}, + 'Blob': [ { 'headerFile': 'nsIDOMFile.h', diff --git a/dom/contacts/ContactManager.js b/dom/contacts/ContactManager.js index 5462ea788139..18b3ed5987cd 100644 --- a/dom/contacts/ContactManager.js +++ b/dom/contacts/ContactManager.js @@ -23,10 +23,6 @@ XPCOMUtils.defineLazyServiceGetter(this, "cpmm", "@mozilla.org/childprocessmessagemanager;1", "nsIMessageSender"); -XPCOMUtils.defineLazyGetter(this, "mRIL", function () { - return Cc["@mozilla.org/telephony/system-worker-manager;1"].getService(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIRadioInterfaceLayer); -}); - const nsIClassInfo = Ci.nsIClassInfo; const CONTACTPROPERTIES_CID = Components.ID("{f5181640-89e8-11e1-b0c4-0800200c9a66}"); const nsIDOMContactProperties = Ci.nsIDOMContactProperties; @@ -372,9 +368,10 @@ ContactManager.prototype = { let msg = aMessage.json; let contacts = msg.contacts; + let req; switch (aMessage.name) { case "Contacts:Find:Return:OK": - let req = this.getRequest(msg.requestID); + req = this.getRequest(msg.requestID); if (req) { let result = this._convertContactsArray(contacts); Services.DOMRequest.fireSuccess(req.request, result); @@ -382,6 +379,20 @@ ContactManager.prototype = { if (DEBUG) debug("no request stored!" + msg.requestID); } break; + case "Contacts:GetSimContacts:Return:OK": + req = this.getRequest(msg.requestID); + if (req) { + let result = contacts.map(function(c) { + let contact = new Contact(); + contact.init( { name: [c.alphaId], tel: [ { value: c.number } ] } ); + return contact; + }); + if (DEBUG) debug("result: " + JSON.stringify(result)); + Services.DOMRequest.fireSuccess(req.request, result); + } else { + if (DEBUG) debug("no request stored!" + msg.requestID); + } + break; case "Contact:Save:Return:OK": case "Contacts:Clear:Return:OK": case "Contact:Remove:Return:OK": @@ -542,21 +553,13 @@ ContactManager.prototype = { getSimContacts: function(aType) { let request; request = this.createRequest(); + let options = {type: aType}; let allowCallback = function() { - let callback = function(aType, aContacts) { - if (DEBUG) debug("got SIM contacts: " + aType + " " + JSON.stringify(aContacts)); - let result = aContacts.map(function(c) { - var contact = new Contact(); - contact.init( { name: [c.alphaId], tel: [ { value: c.number } ] } ); - return contact; - }); - if (DEBUG) debug("result: " + JSON.stringify(result)); - Services.DOMRequest.fireSuccess(request, result); - }; if (DEBUG) debug("getSimContacts " + aType); - - mRIL.getICCContacts(aType, callback); + cpmm.sendAsyncMessage("Contacts:GetSimContacts", + {requestID: this.getRequestId({request: request, reason: "getSimContacts"}), + options: options}); }.bind(this); let cancelCallback = function() { @@ -575,6 +578,7 @@ ContactManager.prototype = { "Contacts:Clear:Return:OK", "Contacts:Clear:Return:KO", "Contact:Save:Return:OK", "Contact:Save:Return:KO", "Contact:Remove:Return:OK", "Contact:Remove:Return:KO", + "Contacts:GetSimContacts:Return:OK", "PermissionPromptHelper:AskPermission:OK"]); }, diff --git a/dom/contacts/fallback/ContactDB.jsm b/dom/contacts/fallback/ContactDB.jsm index c13065557141..2d04a86ff93d 100644 --- a/dom/contacts/fallback/ContactDB.jsm +++ b/dom/contacts/fallback/ContactDB.jsm @@ -109,7 +109,7 @@ ContactDB.prototype = { // Upgrade existing email field in the DB. objectStore.openCursor().onsuccess = function(event) { let cursor = event.target.result; - if (cursor) { + if (cursor && cursor.value.properties.email) { if (DEBUG) debug("upgrade email1: " + JSON.stringify(cursor.value)); cursor.value.properties.email = cursor.value.properties.email.map(function(address) { return { address: address }; }); @@ -131,7 +131,7 @@ ContactDB.prototype = { // Upgrade existing impp field in the DB. objectStore.openCursor().onsuccess = function(event) { let cursor = event.target.result; - if (cursor) { + if (cursor && cursor.value.properties.impp) { if (DEBUG) debug("upgrade impp1: " + JSON.stringify(cursor.value)); cursor.value.properties.impp = cursor.value.properties.impp.map(function(value) { return { value: value }; }); @@ -143,7 +143,7 @@ ContactDB.prototype = { // Upgrade existing url field in the DB. objectStore.openCursor().onsuccess = function(event) { let cursor = event.target.result; - if (cursor) { + if (cursor && cursor.value.properties.url) { if (DEBUG) debug("upgrade url1: " + JSON.stringify(cursor.value)); cursor.value.properties.url = cursor.value.properties.url.map(function(value) { return { value: value }; }); diff --git a/dom/contacts/fallback/ContactService.jsm b/dom/contacts/fallback/ContactService.jsm index 638b323dda2b..6f2582e65c71 100644 --- a/dom/contacts/fallback/ContactService.jsm +++ b/dom/contacts/fallback/ContactService.jsm @@ -21,12 +21,18 @@ XPCOMUtils.defineLazyServiceGetter(this, "ppmm", "@mozilla.org/parentprocessmessagemanager;1", "nsIMessageListenerManager"); +XPCOMUtils.defineLazyGetter(this, "mRIL", function () { + return Cc["@mozilla.org/telephony/system-worker-manager;1"]. + getService(Ci.nsIInterfaceRequestor). + getInterface(Ci.nsIRadioInterfaceLayer); +}); + let myGlobal = this; let DOMContactManager = { init: function() { if (DEBUG) debug("Init"); - this._messages = ["Contacts:Find", "Contacts:Clear", "Contact:Save", "Contact:Remove"]; + this._messages = ["Contacts:Find", "Contacts:Clear", "Contact:Save", "Contact:Remove", "Contacts:GetSimContacts"]; this._messages.forEach((function(msgName) { ppmm.addMessageListener(msgName, this); }).bind(this)); @@ -141,6 +147,14 @@ let DOMContactManager = { function() { mm.sendAsyncMessage("Contacts:Clear:Return:OK", { requestID: msg.requestID }); }.bind(this), function(aErrorMsg) { mm.sendAsyncMessage("Contacts:Clear:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this) ); + break; + case "Contacts:GetSimContacts": + let callback = function(aType, aContacts) { + if (DEBUG) debug("got SIM contacts: " + aType + " " + JSON.stringify(aContacts)); + mm.sendAsyncMessage("Contacts:GetSimContacts:Return:OK", {requestID: msg.requestID, contacts: aContacts}); + }; + mRIL.getICCContacts(msg.options.type, callback); + break; default: if (DEBUG) debug("WRONG MESSAGE NAME: " + aMessage.name); } diff --git a/dom/dom-config.mk b/dom/dom-config.mk index fc947306ff10..ca9e20fcecc0 100644 --- a/dom/dom-config.mk +++ b/dom/dom-config.mk @@ -25,6 +25,7 @@ DOM_SRCDIRS = \ content/base/src \ content/html/content/src \ content/html/document/src \ + content/media/webaudio \ content/svg/content/src \ layout/generic \ layout/style \ diff --git a/dom/indexedDB/IDBDatabase.cpp b/dom/indexedDB/IDBDatabase.cpp index ca2680bcfa30..cadd30e451f8 100644 --- a/dom/indexedDB/IDBDatabase.cpp +++ b/dom/indexedDB/IDBDatabase.cpp @@ -494,7 +494,6 @@ IDBDatabase::CreateObjectStore(const nsAString& aName, mozilla::dom::IDBObjectStoreParameters params; KeyPath keyPath(0); - nsTArray keyPathArray; nsresult rv; diff --git a/dom/indexedDB/IDBObjectStore.cpp b/dom/indexedDB/IDBObjectStore.cpp index f1574e7722f0..76d3a668f510 100644 --- a/dom/indexedDB/IDBObjectStore.cpp +++ b/dom/indexedDB/IDBObjectStore.cpp @@ -2331,7 +2331,7 @@ IDBObjectStore::CreateIndex(const nsAString& aName, } if (params.multiEntry && keyPath.IsArray()) { - return NS_ERROR_DOM_NOT_SUPPORTED_ERR; + return NS_ERROR_DOM_INVALID_ACCESS_ERR; } DatabaseInfo* databaseInfo = mTransaction->DBInfo(); diff --git a/dom/indexedDB/test/unit/test_complex_keyPaths.js b/dom/indexedDB/test/unit/test_complex_keyPaths.js index 87929eaab1fb..97e75c4f0cb1 100644 --- a/dom/indexedDB/test/unit/test_complex_keyPaths.js +++ b/dom/indexedDB/test/unit/test_complex_keyPaths.js @@ -44,6 +44,7 @@ function testSteps() { keyPath: "foo.2.bar", exception: true }, { keyPath: "foo. .bar", exception: true }, { keyPath: ".bar", exception: true }, + { keyPath: [], exception: true }, { keyPath: ["foo", "bar"], value: { foo: 1, bar: 2 }, key: [1, 2] }, { keyPath: ["foo"], value: { foo: 1, bar: 2 }, key: [1] }, @@ -260,18 +261,6 @@ function testSteps() "expected value stored" + test); } - // Can't handle autoincrement and empty keypath - try { - store = db.createObjectStore("storefail", { keyPath: "", autoIncrement: true }); - ok(false, "Should have thrown when creating empty-keypath autoincrement store"); - } - catch(e) { - ok(true, "Did throw when creating empty-keypath autoincrement store"); - is(e.name, "InvalidAccessError", "expect an InvalidAccessError when creating empty-keypath autoincrement store"); - ok(e instanceof DOMException, "Got a DOMException when creating empty-keypath autoincrement store"); - is(e.code, DOMException.INVALID_ACCESS_ERR, "expect an INVALID_ACCESS_ERR when creating empty-keypath autoincrement store"); - } - openRequest.onsuccess = grabEventAndContinueHandler; yield; diff --git a/dom/indexedDB/test/unit/test_create_index.js b/dom/indexedDB/test/unit/test_create_index.js index b8a6e0ef50e8..eea08a407c4d 100644 --- a/dom/indexedDB/test/unit/test_create_index.js +++ b/dom/indexedDB/test/unit/test_create_index.js @@ -42,24 +42,20 @@ function testSteps() ok(true, "createIndex with no keyPath should throw"); } + let ex; try { - request = objectStore.createIndex("Hola", ["foo"], { multiEntry: true }); - ok(false, "createIndex with array keyPath and multiEntry should throw"); + objectStore.createIndex("Hola", ["foo"], { multiEntry: true }); } catch(e) { - ok(true, "createIndex with array keyPath and multiEntry should throw"); + ex = e; } + ok(ex, "createIndex with array keyPath and multiEntry should throw"); + is(ex.name, "InvalidAccessError", "should throw right exception"); + ok(ex instanceof DOMException, "should throw right exception"); + is(ex.code, DOMException.INVALID_ACCESS_ERR, "should throw right exception"); try { - request = objectStore.createIndex("Hola", []); - ok(false, "createIndex with empty array keyPath should throw"); - } - catch(e) { - ok(true, "createIndex with empty array keyPath should throw"); - } - - try { - request = objectStore.createIndex("foo", "bar", 10); + objectStore.createIndex("foo", "bar", 10); ok(false, "createIndex with bad options should throw"); } catch(e) { diff --git a/dom/indexedDB/test/unit/test_create_objectStore.js b/dom/indexedDB/test/unit/test_create_objectStore.js index b3c7a60c7cc0..7ae401d06250 100644 --- a/dom/indexedDB/test/unit/test_create_objectStore.js +++ b/dom/indexedDB/test/unit/test_create_objectStore.js @@ -99,6 +99,32 @@ function testSteps() is(found, true, "transaction has correct objectStoreNames list"); } + // Can't handle autoincrement and empty keypath + let ex; + try { + db.createObjectStore("storefail", { keyPath: "", autoIncrement: true }); + } + catch(e) { + ex = e; + } + ok(ex, "createObjectStore with empty keyPath and autoIncrement should throw"); + is(ex.name, "InvalidAccessError", "should throw right exception"); + ok(ex instanceof DOMException, "should throw right exception"); + is(ex.code, DOMException.INVALID_ACCESS_ERR, "should throw right exception"); + + // Can't handle autoincrement and array keypath + let ex; + try { + db.createObjectStore("storefail", { keyPath: ["a"], autoIncrement: true }); + } + catch(e) { + ex = e; + } + ok(ex, "createObjectStore with array keyPath and autoIncrement should throw"); + is(ex.name, "InvalidAccessError", "should throw right exception"); + ok(ex instanceof DOMException, "should throw right exception"); + is(ex.code, DOMException.INVALID_ACCESS_ERR, "should throw right exception"); + request.onsuccess = grabEventAndContinueHandler; request.onupgradeneeded = unexpectedSuccessHandler; @@ -106,4 +132,4 @@ function testSteps() finishTest(); yield; -} \ No newline at end of file +} diff --git a/dom/interfaces/apps/mozIApplication.idl b/dom/interfaces/apps/mozIApplication.idl index e3b03a328a06..d1f68617e4a0 100644 --- a/dom/interfaces/apps/mozIApplication.idl +++ b/dom/interfaces/apps/mozIApplication.idl @@ -11,7 +11,7 @@ * We expose Gecko-internal helpers related to "web apps" through this * sub-interface. */ -[scriptable, uuid(acf46a46-729a-4ab4-9da3-8d59ecfd103d)] +[scriptable, uuid(764e8930-ff06-4f23-9a6a-8523b93ac09f)] interface mozIApplication: mozIDOMApplication { /* Return true if this app has |permission|. */ @@ -19,4 +19,7 @@ interface mozIApplication: mozIDOMApplication /* Application status as defined in nsIPrincipal. */ readonly attribute unsigned short appStatus; + + /* Returns the local id of the app (not the uuid used for sync). */ + readonly attribute unsigned long localId; }; diff --git a/dom/interfaces/apps/nsIAppsService.idl b/dom/interfaces/apps/nsIAppsService.idl index e1559aa0e6ba..ff3fb98db669 100644 --- a/dom/interfaces/apps/nsIAppsService.idl +++ b/dom/interfaces/apps/nsIAppsService.idl @@ -5,6 +5,7 @@ #include "domstubs.idl" interface mozIDOMApplication; +interface mozIApplication; %{C++ #define APPS_SERVICE_CID { 0x05072afa, 0x92fe, 0x45bf, { 0xae, 0x22, 0x39, 0xb6, 0x9c, 0x11, 0x70, 0x58 } } @@ -15,7 +16,7 @@ interface mozIDOMApplication; * This service allows accessing some DOMApplicationRegistry methods from * non-javascript code. */ -[scriptable, uuid(04e4ef3c-1a30-45bc-ab08-291820f13872)] +[scriptable, uuid(1f0ec00c-57c7-4ad2-a648-1359aa390360)] interface nsIAppsService : nsISupports { mozIDOMApplication getAppByManifestURL(in DOMString manifestURL); @@ -37,4 +38,11 @@ interface nsIAppsService : nsISupports * Returns the manifest URL associated to this localId. */ DOMString getManifestURLByLocalId(in unsigned long localId); + + /** + * Returns the app that is related to the message. + * This is a helper to not have to worry about what is the actual structure + * of the message when listening to one. + */ + mozIApplication getAppFromObserverMessage(in DOMString message); }; diff --git a/dom/interfaces/apps/nsIDOMApplicationRegistry.idl b/dom/interfaces/apps/nsIDOMApplicationRegistry.idl index aac5e6b77aa8..b63def5712ef 100644 --- a/dom/interfaces/apps/nsIDOMApplicationRegistry.idl +++ b/dom/interfaces/apps/nsIDOMApplicationRegistry.idl @@ -8,7 +8,7 @@ interface nsIDOMDOMRequest; interface nsIArray; -[scriptable, uuid(9583b825-46b1-4e8f-bb48-9fed660a95e6)] +[scriptable, uuid(e3649c1d-c950-495e-b0ed-6ce40be9743b)] interface mozIDOMApplication : nsISupports { readonly attribute jsval manifest; @@ -17,6 +17,7 @@ interface mozIDOMApplication : nsISupports readonly attribute DOMString origin; readonly attribute DOMString installOrigin; readonly attribute unsigned long long installTime; + readonly attribute boolean removable; /* * The current progress when downloading an offline cache. diff --git a/dom/messages/SystemMessageInternal.js b/dom/messages/SystemMessageInternal.js index ba2eb789df87..a7ee06d89cfe 100644 --- a/dom/messages/SystemMessageInternal.js +++ b/dom/messages/SystemMessageInternal.js @@ -41,31 +41,14 @@ function SystemMessageInternal() { SystemMessageInternal.prototype = { sendMessage: function sendMessage(aType, aMessage, aPageURI, aManifestURI) { - debug("Broadcasting " + aType + " " + JSON.stringify(aMessage)); - ppmm.broadcastAsyncMessage("SystemMessageManager:Message" , { type: aType, - msg: aMessage, - manifest: aManifestURI.spec }); + this._sendMessage(aType, aMessage, aPageURI.spec, aManifestURI.spec); + }, - // Queue the message for pages that registered an handler for this type. - this._pages.forEach(function sendMess_openPage(aPage) { - if (aPage.type != aType || - aPage.manifest != aManifestURI.spec || - aPage.uri != aPageURI.spec) { - return; + broadcastMessage: function broadcastMessage(aType, aMessage) { + this._pages.forEach(function(aPage) { + if (aPage.type == aType) { + this._sendMessage(aType, aMessage, aPage.uri, aPage.manifest); } - - aPage.pending.push(aMessage); - if (aPage.pending.length > kMaxPendingMessages) { - aPage.pending.splice(0, 1); - } - - // We don't need to send the full object to observers. - let page = { uri: aPage.uri, - manifest: aPage.manifest, - type: aPage.type, - target: aMessage.target }; - debug("Asking to open " + JSON.stringify(page)); - Services.obs.notifyObservers(this, "system-messages-open-app", JSON.stringify(page)); }.bind(this)) }, @@ -118,6 +101,35 @@ SystemMessageInternal.prototype = { } }, + _sendMessage: function _sendMessage(aType, aMessage, aPageURI, aManifestURI) { + debug("Broadcasting " + aType + " " + JSON.stringify(aMessage)); + ppmm.broadcastAsyncMessage("SystemMessageManager:Message" , { type: aType, + msg: aMessage, + manifest: aManifestURI }); + + // Queue the message for pages that registered an handler for this type. + this._pages.forEach(function sendMess_openPage(aPage) { + if (aPage.type != aType || + aPage.manifest != aManifestURI || + aPage.uri != aPageURI) { + return; + } + + aPage.pending.push(aMessage); + if (aPage.pending.length > kMaxPendingMessages) { + aPage.pending.splice(0, 1); + } + + // We don't need to send the full object to observers. + let page = { uri: aPage.uri, + manifest: aPage.manifest, + type: aPage.type, + target: aMessage.target }; + debug("Asking to open " + JSON.stringify(page)); + Services.obs.notifyObservers(this, "system-messages-open-app", JSON.stringify(page)); + }.bind(this)) + }, + classID: Components.ID("{70589ca5-91ac-4b9e-b839-d6a88167d714}"), QueryInterface: XPCOMUtils.generateQI([Ci.nsISystemMessagesInternal, Ci.nsIObserver]) diff --git a/dom/messages/interfaces/nsISystemMessagesInternal.idl b/dom/messages/interfaces/nsISystemMessagesInternal.idl index e3f2794801c5..d08098aa0509 100644 --- a/dom/messages/interfaces/nsISystemMessagesInternal.idl +++ b/dom/messages/interfaces/nsISystemMessagesInternal.idl @@ -9,7 +9,7 @@ interface nsIDOMWindow; // Implemented by the contract id @mozilla.org/system-message-internal;1 -[scriptable, uuid(3a50fd6b-0263-45c1-b738-a002052ad31b)] +[scriptable, uuid(d8de761a-94fe-44d5-80eb-3c8bd8cd7d0b)] interface nsISystemMessagesInternal : nsISupports { /* @@ -21,6 +21,14 @@ interface nsISystemMessagesInternal : nsISupports */ void sendMessage(in DOMString type, in jsval message, in nsIURI pageURI, in nsIURI manifestURI); + /* + * Allow any internal user to broadcast a message of a given type. + * The application that registers the message will be launched. + * @param type The type of the message to be sent. + * @param message The message payload. + */ + void broadcastMessage(in DOMString type, in jsval message); + /* * Registration of a page that wants to be notified of a message type. * @param type The message type. diff --git a/dom/plugins/base/nsIPluginTag.idl b/dom/plugins/base/nsIPluginTag.idl index 33129074d63a..8cee3ca61f71 100644 --- a/dom/plugins/base/nsIPluginTag.idl +++ b/dom/plugins/base/nsIPluginTag.idl @@ -4,8 +4,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsISupports.idl" +interface nsIDOMMimeType; -[scriptable, uuid(a361a7e7-7f8d-4b68-91e9-30ae096460d4)] +[scriptable, uuid(b8bf0a06-e395-4f44-af39-a51d3e7ef4b9)] interface nsIPluginTag : nsISupports { readonly attribute AUTF8String description; @@ -16,4 +17,6 @@ interface nsIPluginTag : nsISupports attribute boolean disabled; attribute boolean blocklisted; attribute boolean clicktoplay; + void getMimeTypes([optional] out unsigned long aCount, + [retval, array, size_is(aCount)] out nsIDOMMimeType aResults); }; diff --git a/dom/plugins/base/nsPluginHost.cpp b/dom/plugins/base/nsPluginHost.cpp index b4233fab780e..a2914c93095d 100644 --- a/dom/plugins/base/nsPluginHost.cpp +++ b/dom/plugins/base/nsPluginHost.cpp @@ -1373,55 +1373,6 @@ nsPluginHost::IsPluginEnabledForExtension(const char* aExtension, return NS_ERROR_FAILURE; } -class DOMMimeTypeImpl : public nsIDOMMimeType { -public: - NS_DECL_ISUPPORTS - - DOMMimeTypeImpl(nsPluginTag* aTag, uint32_t aMimeTypeIndex) - { - if (!aTag) - return; - CopyUTF8toUTF16(aTag->mMimeDescriptions[aMimeTypeIndex], mDescription); - CopyUTF8toUTF16(aTag->mExtensions[aMimeTypeIndex], mSuffixes); - CopyUTF8toUTF16(aTag->mMimeTypes[aMimeTypeIndex], mType); - } - - virtual ~DOMMimeTypeImpl() { - } - - NS_METHOD GetDescription(nsAString& aDescription) - { - aDescription.Assign(mDescription); - return NS_OK; - } - - NS_METHOD GetEnabledPlugin(nsIDOMPlugin** aEnabledPlugin) - { - // this has to be implemented by the DOM version. - *aEnabledPlugin = nullptr; - return NS_OK; - } - - NS_METHOD GetSuffixes(nsAString& aSuffixes) - { - aSuffixes.Assign(mSuffixes); - return NS_OK; - } - - NS_METHOD GetType(nsAString& aType) - { - aType.Assign(mType); - return NS_OK; - } - -private: - nsString mDescription; - nsString mSuffixes; - nsString mType; -}; - -NS_IMPL_ISUPPORTS1(DOMMimeTypeImpl, nsIDOMMimeType) - class DOMPluginImpl : public nsIDOMPlugin { public: NS_DECL_ISUPPORTS diff --git a/dom/plugins/base/nsPluginTags.cpp b/dom/plugins/base/nsPluginTags.cpp index d599dcdf64d4..91fced8ca8bd 100644 --- a/dom/plugins/base/nsPluginTags.cpp +++ b/dom/plugins/base/nsPluginTags.cpp @@ -14,6 +14,7 @@ #include "nsIUnicodeDecoder.h" #include "nsIPlatformCharset.h" #include "nsICharsetConverterManager.h" +#include "nsIDOMMimeType.h" #include "nsPluginLogging.h" #include "nsNPAPIPlugin.h" #include "mozilla/TimeStamp.h" @@ -33,6 +34,8 @@ inline char* new_str(const char* str) return result; } +NS_IMPL_ISUPPORTS1(DOMMimeTypeImpl, nsIDOMMimeType) + /* nsPluginTag */ nsPluginTag::nsPluginTag(nsPluginTag* aPluginTag) @@ -344,6 +347,25 @@ nsPluginTag::SetClicktoplay(bool aClicktoplay) return NS_OK; } +NS_IMETHODIMP +nsPluginTag::GetMimeTypes(uint32_t* aCount, nsIDOMMimeType*** aResults) +{ + uint32_t count = mMimeTypes.Length(); + *aResults = static_cast + (nsMemory::Alloc(count * sizeof(**aResults))); + if (!*aResults) + return NS_ERROR_OUT_OF_MEMORY; + *aCount = count; + + for (uint32_t i = 0; i < count; i++) { + nsIDOMMimeType* mimeType = new DOMMimeTypeImpl(this, i); + (*aResults)[i] = mimeType; + NS_ADDREF((*aResults)[i]); + } + + return NS_OK; +} + void nsPluginTag::Mark(uint32_t mask) { bool wasEnabled = IsEnabled(); diff --git a/dom/plugins/base/nsPluginTags.h b/dom/plugins/base/nsPluginTags.h index b14ba7baab44..aa56f5b6c135 100644 --- a/dom/plugins/base/nsPluginTags.h +++ b/dom/plugins/base/nsPluginTags.h @@ -15,6 +15,7 @@ #include "nsNPAPIPluginInstance.h" #include "nsISupportsArray.h" #include "nsITimer.h" +#include "nsIDOMMimeType.h" class nsPluginHost; struct PRLibrary; @@ -87,4 +88,50 @@ private: nsresult EnsureMembersAreUTF8(); }; +class DOMMimeTypeImpl : public nsIDOMMimeType { +public: + NS_DECL_ISUPPORTS + + DOMMimeTypeImpl(nsPluginTag* aTag, PRUint32 aMimeTypeIndex) + { + if (!aTag) + return; + CopyUTF8toUTF16(aTag->mMimeDescriptions[aMimeTypeIndex], mDescription); + CopyUTF8toUTF16(aTag->mExtensions[aMimeTypeIndex], mSuffixes); + CopyUTF8toUTF16(aTag->mMimeTypes[aMimeTypeIndex], mType); + } + + virtual ~DOMMimeTypeImpl() { + } + + NS_METHOD GetDescription(nsAString& aDescription) + { + aDescription.Assign(mDescription); + return NS_OK; + } + + NS_METHOD GetEnabledPlugin(nsIDOMPlugin** aEnabledPlugin) + { + // this has to be implemented by the DOM version. + *aEnabledPlugin = nullptr; + return NS_OK; + } + + NS_METHOD GetSuffixes(nsAString& aSuffixes) + { + aSuffixes.Assign(mSuffixes); + return NS_OK; + } + + NS_METHOD GetType(nsAString& aType) + { + aType.Assign(mType); + return NS_OK; + } +private: + nsString mDescription; + nsString mSuffixes; + nsString mType; +}; + #endif // nsPluginTags_h_ diff --git a/dom/system/gonk/RadioInterfaceLayer.js b/dom/system/gonk/RadioInterfaceLayer.js index 06ef38aaab5f..5b9266781dd7 100644 --- a/dom/system/gonk/RadioInterfaceLayer.js +++ b/dom/system/gonk/RadioInterfaceLayer.js @@ -87,6 +87,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService", "@mozilla.org/settingsService;1", "nsISettingsService"); +XPCOMUtils.defineLazyServiceGetter(this, "gSystemMessenger", + "@mozilla.org/system-message-internal;1", + "nsISystemMessagesInternal"); + XPCOMUtils.defineLazyGetter(this, "WAP", function () { let WAP = {}; Cu.import("resource://gre/modules/WapPushManager.js", WAP); @@ -758,6 +762,11 @@ RadioInterfaceLayer.prototype = { handleCallStateChange: function handleCallStateChange(call) { debug("handleCallStateChange: " + JSON.stringify(call)); call.state = convertRILCallState(call.state); + + if (call.state == nsIRadioInterfaceLayer.CALL_STATE_INCOMING) { + gSystemMessenger.broadcastMessage("telephony-incoming", {number: call.number}); + } + if (call.isActive) { this._activeCall = call; } else if (this._activeCall && @@ -1033,6 +1042,7 @@ RadioInterfaceLayer.prototype = { handleStkProactiveCommand: function handleStkProactiveCommand(message) { debug("handleStkProactiveCommand " + JSON.stringify(message)); + gSystemMessenger.broadcastMessage("icc-stkcommand", message); ppmm.broadcastAsyncMessage("RIL:StkCommand", message); }, @@ -1730,20 +1740,9 @@ RadioInterfaceLayer.prototype = { } let requestId = Math.floor(Math.random() * 1000); this._contactsCallbacks[requestId] = callback; - - let msgType; - switch (type) { - case "ADN": - msgType = "getPBR"; - break; - case "FDN": - msgType = "getFDN"; - break; - default: - debug("Unknown contact type. " + type); - return; - } - this.worker.postMessage({rilMessageType: msgType, requestId: requestId}); + this.worker.postMessage({rilMessageType: "getICCContacts", + type: type, + requestId: requestId}); } }; diff --git a/dom/system/gonk/RadioInterfaceLayer.manifest b/dom/system/gonk/RadioInterfaceLayer.manifest index 4ba34263bde8..5ba9e64e2ca2 100644 --- a/dom/system/gonk/RadioInterfaceLayer.manifest +++ b/dom/system/gonk/RadioInterfaceLayer.manifest @@ -13,7 +13,18 @@ # limitations under the License. # RadioInterfaceLayer.js +# +# IMPORTANT: +# Users of nsIRadioInterfaceLayer should invoke +# nsIInterfaceRequestor::GetInterface() as implemented by +# "@mozilla.org/telephony/system-worker-manager;1" to +# obtain the instance. +# +# DO NOT use do_CreateInstance()/do_GetService() to directly +# instantiate "@mozilla.org/ril;1". +# component {2d831c8d-6017-435b-a80c-e5d422810cea} RadioInterfaceLayer.js +contract @mozilla.org/ril;1 {2d831c8d-6017-435b-a80c-e5d422810cea} # RILContentHelper.js component {472816e1-1fd6-4405-996c-806f9ea68174} RILContentHelper.js diff --git a/dom/system/gonk/SystemWorkerManager.cpp b/dom/system/gonk/SystemWorkerManager.cpp index dbf9a161570b..f76327be917d 100644 --- a/dom/system/gonk/SystemWorkerManager.cpp +++ b/dom/system/gonk/SystemWorkerManager.cpp @@ -19,7 +19,6 @@ #include "nsIObserverService.h" #include "nsIJSContextStack.h" -#include "nsIRadioInterfaceLayer.h" #include "nsINetworkManager.h" #include "nsIWifi.h" #include "nsIWorkerHolder.h" @@ -52,7 +51,6 @@ using namespace mozilla::system; namespace { -NS_DEFINE_CID(kRadioInterfaceLayerCID, NS_RADIOINTERFACELAYER_CID); NS_DEFINE_CID(kWifiWorkerCID, NS_WIFIWORKER_CID); NS_DEFINE_CID(kNetworkManagerCID, NS_NETWORKMANAGER_CID); @@ -414,7 +412,7 @@ SystemWorkerManager::Shutdown() StopRil(); - mRILWorker = nullptr; + mRIL = nullptr; #ifdef MOZ_WIDGET_GONK StopNetd(); @@ -469,8 +467,8 @@ SystemWorkerManager::GetInterface(const nsIID &aIID, void **aResult) NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); if (aIID.Equals(NS_GET_IID(nsIRadioInterfaceLayer))) { - return CallQueryInterface(mRILWorker, - reinterpret_cast(aResult)); + NS_IF_ADDREF(*reinterpret_cast(aResult) = mRIL); + return NS_OK; } if (aIID.Equals(NS_GET_IID(nsIWifi))) { @@ -495,34 +493,37 @@ SystemWorkerManager::InitRIL(JSContext *cx) // We're keeping as much of this implementation as possible in JS, so the real // worker lives in RadioInterfaceLayer.js. All we do here is hold it alive and // hook it up to the RIL thread. - nsCOMPtr worker = do_CreateInstance(kRadioInterfaceLayerCID); - NS_ENSURE_TRUE(worker, NS_ERROR_FAILURE); + nsCOMPtr ril = do_CreateInstance("@mozilla.org/ril;1"); + NS_ENSURE_TRUE(ril, NS_ERROR_FAILURE); - jsval workerval; - nsresult rv = worker->GetWorker(&workerval); - NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr worker = do_QueryInterface(ril); + if (worker) { + jsval workerval; + nsresult rv = worker->GetWorker(&workerval); + NS_ENSURE_SUCCESS(rv, rv); - NS_ENSURE_TRUE(!JSVAL_IS_PRIMITIVE(workerval), NS_ERROR_UNEXPECTED); + NS_ENSURE_TRUE(!JSVAL_IS_PRIMITIVE(workerval), NS_ERROR_UNEXPECTED); - JSAutoRequest ar(cx); - JSAutoCompartment ac(cx, JSVAL_TO_OBJECT(workerval)); + JSAutoRequest ar(cx); + JSAutoCompartment ac(cx, JSVAL_TO_OBJECT(workerval)); - WorkerCrossThreadDispatcher *wctd = - GetWorkerCrossThreadDispatcher(cx, workerval); - if (!wctd) { - return NS_ERROR_FAILURE; + WorkerCrossThreadDispatcher *wctd = + GetWorkerCrossThreadDispatcher(cx, workerval); + if (!wctd) { + return NS_ERROR_FAILURE; + } + + nsRefPtr connection = new ConnectWorkerToRIL(); + if (!wctd->PostTask(connection)) { + return NS_ERROR_UNEXPECTED; + } + + // Now that we're set up, connect ourselves to the RIL thread. + mozilla::RefPtr receiver = new RILReceiver(wctd); + StartRil(receiver); } - nsRefPtr connection = new ConnectWorkerToRIL(); - if (!wctd->PostTask(connection)) { - return NS_ERROR_UNEXPECTED; - } - - // Now that we're set up, connect ourselves to the RIL thread. - mozilla::RefPtr receiver = new RILReceiver(wctd); - StartRil(receiver); - - mRILWorker = worker; + mRIL = ril; return NS_OK; } diff --git a/dom/system/gonk/SystemWorkerManager.h b/dom/system/gonk/SystemWorkerManager.h index 20225e36a097..931e1012ade6 100644 --- a/dom/system/gonk/SystemWorkerManager.h +++ b/dom/system/gonk/SystemWorkerManager.h @@ -19,6 +19,7 @@ #define mozilla_dom_system_b2g_systemworkermanager_h__ #include "nsIInterfaceRequestor.h" +#include "nsIRadioInterfaceLayer.h" #include "nsIObserver.h" #include "nsAutoPtr.h" #include "nsCOMPtr.h" @@ -60,7 +61,7 @@ private: #endif nsresult InitWifi(JSContext *cx); - nsCOMPtr mRILWorker; + nsCOMPtr mRIL; #ifdef MOZ_WIDGET_GONK nsCOMPtr mNetdWorker; #endif diff --git a/dom/system/gonk/ril_worker.js b/dom/system/gonk/ril_worker.js index 35acb231773e..4ebaa681b0eb 100644 --- a/dom/system/gonk/ril_worker.js +++ b/dom/system/gonk/ril_worker.js @@ -582,56 +582,6 @@ let Buf = { * and acts upon state changes accordingly. */ let RIL = { - - /** - * One of the RADIO_STATE_* constants. - */ - radioState: GECKO_RADIOSTATE_UNAVAILABLE, - _isInitialRadioState: true, - - /** - * ICC status. Keeps a reference of the data response to the - * getICCStatus request. - */ - iccStatus: null, - - /** - * Card state - */ - cardState: null, - - /** - * Strings - */ - IMEI: null, - IMEISV: null, - SMSC: null, - - /** - * ICC information, such as MSISDN, IMSI, ...etc. - */ - iccInfo: {}, - - /** - * Application identification for apps in ICC. - */ - aid: null, - - networkSelectionMode: null, - - voiceRegistrationState: {}, - dataRegistrationState: {}, - - /** - * List of strings identifying the network operator. - */ - operator: null, - - /** - * String containing the baseband version. - */ - basebandVersion: null, - /** * Valid calls. */ @@ -654,21 +604,92 @@ let RIL = { */ _pendingSentSmsMap: {}, - /** - * Whether or not the multiple requests in requestNetworkInfo() are currently - * being processed - */ - _processingNetworkInfo: false, + initRILState: function initRILState() { + /** + * One of the RADIO_STATE_* constants. + */ + this.radioState = GECKO_RADIOSTATE_UNAVAILABLE; + this._isInitialRadioState = true; - /** - * Pending messages to be send in batch from requestNetworkInfo() - */ - _pendingNetworkInfo: {rilMessageType: "networkinfochanged"}, + /** + * ICC status. Keeps a reference of the data response to the + * getICCStatus request. + */ + this.iccStatus = null; - /** - * Mute or unmute the radio. - */ - _muted: true, + /** + * Card state + */ + this.cardState = null; + + /** + * Strings + */ + this.IMEI = null; + this.IMEISV = null; + this.SMSC = null; + + /** + * ICC information, such as MSISDN, IMSI, ...etc. + */ + this.iccInfo = {}; + + /** + * Application identification for apps in ICC. + */ + this.aid = null; + + /** + * Application type for apps in ICC. + */ + this.appType = null, + + this.networkSelectionMode = null; + + this.voiceRegistrationState = {}; + this.dataRegistrationState = {}; + + /** + * List of strings identifying the network operator. + */ + this.operator = null; + + /** + * String containing the baseband version. + */ + this.basebandVersion = null; + + // Clean up this.currentCalls: rild might have restarted. + for each (let currentCall in this.currentCalls) { + delete this.currentCalls[currentCall.callIndex]; + this._handleDisconnectedCall(currentCall); + } + + // Deactivate this.currentDataCalls: rild might have restarted. + for each (let datacall in this.currentDataCalls) { + this.deactivateDataCall(datacall); + } + + // Don't clean up this._receivedSmsSegmentsMap or this._pendingSentSmsMap + // because on rild restart: we may continue with the pending segments. + + /** + * Whether or not the multiple requests in requestNetworkInfo() are currently + * being processed + */ + this._processingNetworkInfo = false; + + /** + * Pending messages to be send in batch from requestNetworkInfo() + */ + this._pendingNetworkInfo = {rilMessageType: "networkinfochanged"}; + + /** + * Mute or unmute the radio. + */ + this._muted = true; + }, + get muted() { return this._muted; }, @@ -1308,6 +1329,7 @@ let RIL = { function add(contact) { this.iccInfo.adn.push(contact); }; + function finish() { if (DEBUG) { for (let i = 0; i < this.iccInfo.adn.length; i++) { @@ -1315,14 +1337,21 @@ let RIL = { " number = " + this.iccInfo.adn[i].number); } } - this.sendDOMMessage({rilMessageType: "icccontacts", - contactType: "ADN", - contacts: this.iccInfo.adn, - requestId: options.requestId}); + options.rilMessageType = "icccontacts"; + options.contactType = "ADN"; + options.contacts = this.iccInfo.adn, + this.sendDOMMessage(options); }; this.parseDiallingNumber(options, add, finish); } + function error(options) { + options.rilMessageType = "icccontacts"; + options.contactType = "ADN"; + options.contacts = []; + this.sendDOMMessage(options); + } + this.iccInfo.adn = []; this.iccIO({ command: ICC_COMMAND_GET_RESPONSE, @@ -1335,8 +1364,9 @@ let RIL = { pin2: null, type: EF_TYPE_LINEAR_FIXED, callback: callback, + onerror: error loadAll: true, - requestId: options.requestId + requestId: options.requestId, }); }, @@ -1400,7 +1430,33 @@ let RIL = { }, /** - * Get ICC Phonebook. + * Get UICC Phonebook. + * + * @params type + * "ADN" or "FDN". + */ + getICCContacts: function getICCContacts(options) { + let type = options.type; + switch (type) { + case "ADN": + switch (this.appType) { + case CARD_APPTYPE_SIM: + options.fileId = ICC_EF_ADN; + this.getADN(options); + break; + case CARD_APPTYPE_USIM: + this.getPBR(options); + break; + } + break; + case "FDN": + this.getFDN(options); + break; + } + }, + + /** + * Get USIM Phonebook. * * @params requestId * Request id from RadioInterfaceLayer. @@ -1421,6 +1477,13 @@ let RIL = { Buf.readStringDelimiter(bufLen); } + function error(options) { + options.rilMessageType = "icccontacts"; + options.contactType = "ADN"; + options.contacts = []; + this.sendDOMMessage(options); + } + this.iccIO({ command: ICC_COMMAND_GET_RESPONSE, fileId: ICC_EF_PBR, @@ -1432,6 +1495,7 @@ let RIL = { pin2: null, type: EF_TYPE_LINEAR_FIXED, callback: callback, + onerror: error, requestId: options.requestId, }); }, @@ -2178,6 +2242,7 @@ let RIL = { } // fetchICCRecords will need to read aid, so read aid here. this.aid = app.aid; + this.appType = app.app_type; let newCardState; switch (app.app_state) { @@ -3115,6 +3180,8 @@ let RIL = { } }; +RIL.initRILState(); + RIL[REQUEST_GET_SIM_STATUS] = function REQUEST_GET_SIM_STATUS(length, options) { if (options.rilRequestError) { return; @@ -3503,6 +3570,13 @@ RIL[REQUEST_SETUP_DATA_CALL] = function REQUEST_SETUP_DATA_CALL(length, options) this[REQUEST_DATA_CALL_LIST](length, options); }; RIL[REQUEST_SIM_IO] = function REQUEST_SIM_IO(length, options) { + if (!length) { + if (options.onerror) { + options.onerror.call(this, options); + } + return; + } + // Don't need to read rilRequestError since we can know error status from // sw1 and sw2. let sw1 = Buf.readUint32(); @@ -3515,6 +3589,9 @@ RIL[REQUEST_SIM_IO] = function REQUEST_SIM_IO(length, options) { " command = " + options.command.toString(16) + "(" + sw1.toString(16) + "/" + sw2.toString(16) + ")"); } + if (options.onerror) { + options.onerror.call(this, options); + } return; } this._processICCIO(options); @@ -3992,6 +4069,8 @@ RIL[UNSOLICITED_RIL_CONNECTED] = function UNSOLICITED_RIL_CONNECTED(length) { debug("Detected RIL version " + version); debug("RILQUIRKS_V5_LEGACY is " + RILQUIRKS_V5_LEGACY); } + + this.initRILState(); }; /** diff --git a/dom/tests/mochitest/webapps/apphelper.js b/dom/tests/mochitest/webapps/apphelper.js index 05e4752029d7..4b76d0513592 100644 --- a/dom/tests/mochitest/webapps/apphelper.js +++ b/dom/tests/mochitest/webapps/apphelper.js @@ -17,7 +17,8 @@ Components.classes["@mozilla.org/permissionmanager;1"] "webapps-manage", Components.interfaces.nsIPermissionManager.ALLOW_ACTION); -SpecialPowers.setCharPref("dom.mozApps.whitelist", "http://mochi.test:8888"); +SpecialPowers.addPermission("webapps-manage", true, "http://mochi.test:8888"); + SpecialPowers.setBoolPref('dom.mozBrowserFramesEnabled', true); SpecialPowers.setBoolPref('browser.mozApps.installer.dry_run', true); SpecialPowers.setBoolPref("dom.mozBrowserFramesWhitelist", "http://www.example.com"); @@ -62,7 +63,7 @@ function mainCommand() { } function popup_listener() { - debug("here in popup listener"); + debug("here in popup listener"); popupNotifications.panel.addEventListener("popupshown", mainCommand, false); } diff --git a/dom/tests/mochitest/webapps/test_install_app.xul b/dom/tests/mochitest/webapps/test_install_app.xul index 9ddf554b3638..b6564fbec282 100644 --- a/dom/tests/mochitest/webapps/test_install_app.xul +++ b/dom/tests/mochitest/webapps/test_install_app.xul @@ -24,7 +24,7 @@ + + Tests that uninstalling app removes the permissions + + + + +Mozilla Bug 786296 +

+
+ +
+
+
+
+ + diff --git a/gfx/thebes/gfxWindowsPlatform.h b/gfx/thebes/gfxWindowsPlatform.h index bfe75855712c..844f917306f7 100644 --- a/gfx/thebes/gfxWindowsPlatform.h +++ b/gfx/thebes/gfxWindowsPlatform.h @@ -208,7 +208,8 @@ public: kWindowsXP = 0x50001, kWindowsServer2003 = 0x50002, kWindowsVista = 0x60000, - kWindows7 = 0x60001 + kWindows7 = 0x60001, + kWindows8 = 0x60002 }; static int32_t WindowsOSVersion(int32_t *aBuildNum = nullptr); diff --git a/image/build/nsImageModule.cpp b/image/build/nsImageModule.cpp index 5eb42d753d3b..a78279e5155a 100644 --- a/image/build/nsImageModule.cpp +++ b/image/build/nsImageModule.cpp @@ -96,7 +96,7 @@ static nsresult imglib_Initialize() { mozilla::image::DiscardTracker::Initialize(); - imgLoader::InitCache(); + imgLoader::GlobalInit(); return NS_OK; } diff --git a/image/public/imgICache.idl b/image/public/imgICache.idl index 67e1166816ea..c923cadaf40f 100644 --- a/image/public/imgICache.idl +++ b/image/public/imgICache.idl @@ -17,7 +17,7 @@ interface nsIProperties; * @version 0.1 * @see imagelib2 */ -[scriptable, uuid(f1b74aae-5661-4753-a21c-66dd644afebc)] +[scriptable, uuid(b06e0fa5-d6e2-4fa3-8fc0-7775aed96522)] interface imgICache : nsISupports { /** @@ -49,4 +49,11 @@ interface imgICache : nsISupports * @returns NULL if the URL was not found in the cache */ nsIProperties findEntryProperties(in nsIURI uri); + + /** + * Make this cache instance respect private browsing notifications. This entails clearing + * the chrome and content caches whenever the last-pb-context-exited notification is + * observed. + */ + void respectPrivacyNotifications(); }; diff --git a/image/public/imgITools.idl b/image/public/imgITools.idl index 147aac073c29..fb474ec620e6 100644 --- a/image/public/imgITools.idl +++ b/image/public/imgITools.idl @@ -8,8 +8,11 @@ interface nsIInputStream; interface imgIContainer; +interface imgILoader; +interface imgICache; +interface nsIDOMDocument; -[scriptable, uuid(8e16f39e-7012-46bd-aa22-2a7a3265608f)] +[scriptable, uuid(53dd1cbe-cb9f-4d9e-8104-1ab72851c88e)] interface imgITools : nsISupports { /** @@ -71,6 +74,26 @@ interface imgITools : nsISupports in long aHeight, [optional] in AString outputOptions); + /** + * getImgLoaderForDocument + * Retrieve an image loader that reflects the privacy status of the given + * document. + * + * @param doc + * A document. Must not be null. + */ + imgILoader getImgLoaderForDocument(in nsIDOMDocument doc); + + /** + * getImgLoaderForDocument + * Retrieve an image cache that reflects the privacy status of the given + * document. + * + * @param doc + * A document. Must not be null. + */ + imgICache getImgCacheForDocument(in nsIDOMDocument doc); + /** * encodeCroppedImage * Caller provides an image container, and the mime type it should be diff --git a/image/src/imgLoader.cpp b/image/src/imgLoader.cpp index ea51e8def3c4..d14a40daf5f9 100644 --- a/image/src/imgLoader.cpp +++ b/image/src/imgLoader.cpp @@ -50,7 +50,6 @@ #include "nsIApplicationCacheContainer.h" #include "nsIMemoryReporter.h" -#include "nsIPrivateBrowsingService.h" // we want to explore making the document own the load group // so we can associate the document URI with the load group. @@ -58,6 +57,7 @@ #include "nsIHttpChannelInternal.h" #include "nsIContentSecurityPolicy.h" #include "nsIChannelPolicy.h" +#include "nsILoadContext.h" #include "nsContentUtils.h" @@ -87,8 +87,11 @@ public: { AllSizes chrome; AllSizes content; - imgLoader::sChromeCache.EnumerateRead(EntryAllSizes, &chrome); - imgLoader::sCache.EnumerateRead(EntryAllSizes, &content); + + for (PRUint32 i = 0; i < mKnownLoaders.Length(); i++) { + mKnownLoaders[i]->mChromeCache.EnumerateRead(EntryAllSizes, &chrome); + mKnownLoaders[i]->mCache.EnumerateRead(EntryAllSizes, &content); + } #define REPORT(_path, _kind, _amount, _desc) \ do { \ @@ -155,8 +158,10 @@ public: NS_IMETHOD GetExplicitNonHeap(int64_t *n) { size_t n2 = 0; - imgLoader::sChromeCache.EnumerateRead(EntryExplicitNonHeapSize, &n2); - imgLoader::sCache.EnumerateRead(EntryExplicitNonHeapSize, &n2); + for (PRUint32 i = 0; i < mKnownLoaders.Length(); i++) { + mKnownLoaders[i]->mChromeCache.EnumerateRead(EntryExplicitNonHeapSize, &n2); + mKnownLoaders[i]->mCache.EnumerateRead(EntryExplicitNonHeapSize, &n2); + } *n = n2; return NS_OK; } @@ -164,11 +169,25 @@ public: static int64_t GetImagesContentUsedUncompressed() { size_t n = 0; - imgLoader::sCache.EnumerateRead(EntryUsedUncompressedSize, &n); + for (PRUint32 i = 0; i < imgLoader::sMemReporter->mKnownLoaders.Length(); i++) { + imgLoader::sMemReporter->mKnownLoaders[i]->mCache.EnumerateRead(EntryUsedUncompressedSize, &n); + } return n; } + void RegisterLoader(imgLoader* aLoader) + { + mKnownLoaders.AppendElement(aLoader); + } + + void UnregisterLoader(imgLoader* aLoader) + { + mKnownLoaders.RemoveElement(aLoader); + } + private: + nsTArray mKnownLoaders; + struct AllSizes { size_t mUsedRaw; size_t mUsedUncompressedHeap; @@ -339,11 +358,11 @@ nsProgressNotificationProxy::GetInterface(const nsIID& iid, return NS_NOINTERFACE; } -static void NewRequestAndEntry(bool aForcePrincipalCheckForCacheEntry, +static void NewRequestAndEntry(bool aForcePrincipalCheckForCacheEntry, imgLoader* aLoader, imgRequest **aRequest, imgCacheEntry **aEntry) { - nsRefPtr request = new imgRequest(); - nsRefPtr entry = new imgCacheEntry(request, aForcePrincipalCheckForCacheEntry); + nsRefPtr request = new imgRequest(aLoader); + nsRefPtr entry = new imgCacheEntry(aLoader, request, aForcePrincipalCheckForCacheEntry); request.forget(aRequest); entry.forget(aEntry); } @@ -511,8 +530,9 @@ static uint32_t SecondsFromPRTime(PRTime prTime) return uint32_t(int64_t(prTime) / int64_t(PR_USEC_PER_SEC)); } -imgCacheEntry::imgCacheEntry(imgRequest *request, bool forcePrincipalCheck) - : mRequest(request), +imgCacheEntry::imgCacheEntry(imgLoader* loader, imgRequest *request, bool forcePrincipalCheck) + : mLoader(loader), + mRequest(request), mDataSize(0), mTouchedTime(SecondsFromPRTime(PR_Now())), mExpiryTime(0), @@ -546,7 +566,7 @@ void imgCacheEntry::UpdateCache(int32_t diff /* = 0 */) if (!Evicted() && HasNoProxies()) { nsCOMPtr uri; mRequest->GetURI(getter_AddRefs(uri)); - imgLoader::CacheEntriesChanged(uri, diff); + mLoader->CacheEntriesChanged(uri, diff); } } @@ -706,8 +726,6 @@ class imgCacheObserver MOZ_FINAL : public nsIObserver public: NS_DECL_ISUPPORTS NS_DECL_NSIOBSERVER -private: - imgLoader mLoader; }; NS_IMPL_ISUPPORTS1(imgCacheObserver, nsIObserver) @@ -717,10 +735,6 @@ imgCacheObserver::Observe(nsISupports* aSubject, const char* aTopic, const PRUni { if (strcmp(aTopic, "memory-pressure") == 0) { DiscardTracker::DiscardAll(); - mLoader.MinimizeCaches(); - } else if (strcmp(aTopic, "chrome-flush-skin-caches") == 0 || - strcmp(aTopic, "chrome-flush-caches") == 0) { - mLoader.ClearChromeImageCache(); } return NS_OK; } @@ -760,45 +774,44 @@ void imgCacheExpirationTracker::NotifyExpired(imgCacheEntry *entry) // We can be called multiple times on the same entry. Don't do work multiple // times. if (!entry->Evicted()) - imgLoader::RemoveFromCache(entry); + entry->Loader()->RemoveFromCache(entry); - imgLoader::VerifyCacheSizes(); + entry->Loader()->VerifyCacheSizes(); } imgCacheObserver *gCacheObserver; -imgCacheExpirationTracker *gCacheTracker; - -imgLoader::imgCacheTable imgLoader::sCache; -imgCacheQueue imgLoader::sCacheQueue; - -imgLoader::imgCacheTable imgLoader::sChromeCache; -imgCacheQueue imgLoader::sChromeCacheQueue; double imgLoader::sCacheTimeWeight; uint32_t imgLoader::sCacheMaxSize; +imgMemoryReporter* imgLoader::sMemReporter; NS_IMPL_ISUPPORTS5(imgLoader, imgILoader, nsIContentSniffer, imgICache, nsISupportsWeakReference, nsIObserver) imgLoader::imgLoader() +: mRespectPrivacy(false) { - /* member initializers and constructor code */ + sMemReporter->AddRef(); + sMemReporter->RegisterLoader(this); } imgLoader::~imgLoader() { - /* destructor code */ + ClearChromeImageCache(); + ClearImageCache(); + sMemReporter->UnregisterLoader(this); + sMemReporter->Release(); } void imgLoader::VerifyCacheSizes() { #ifdef DEBUG - if (!gCacheTracker) + if (!mCacheTracker) return; - uint32_t cachesize = sCache.Count() + sChromeCache.Count(); - uint32_t queuesize = sCacheQueue.GetNumElements() + sChromeCacheQueue.GetNumElements(); + uint32_t cachesize = mCache.Count() + mChromeCache.Count(); + uint32_t queuesize = mCacheQueue.GetNumElements() + mChromeCacheQueue.GetNumElements(); uint32_t trackersize = 0; - for (nsExpirationTracker::Iterator it(gCacheTracker); it.Next(); ) + for (nsExpirationTracker::Iterator it(mCacheTracker); it.Next(); ) trackersize++; NS_ABORT_IF_FALSE(queuesize == trackersize, "Queue and tracker sizes out of sync!"); NS_ABORT_IF_FALSE(queuesize <= cachesize, "Queue has more elements than cache!"); @@ -810,9 +823,9 @@ imgLoader::imgCacheTable & imgLoader::GetCache(nsIURI *aURI) bool chrome = false; aURI->SchemeIs("chrome", &chrome); if (chrome) - return sChromeCache; + return mChromeCache; else - return sCache; + return mCache; } imgCacheQueue & imgLoader::GetCacheQueue(nsIURI *aURI) @@ -820,34 +833,22 @@ imgCacheQueue & imgLoader::GetCacheQueue(nsIURI *aURI) bool chrome = false; aURI->SchemeIs("chrome", &chrome); if (chrome) - return sChromeCacheQueue; + return mChromeCacheQueue; else - return sCacheQueue; + return mCacheQueue; } -nsresult imgLoader::InitCache() +void imgLoader::GlobalInit() { - NS_TIME_FUNCTION; - - nsresult rv; - nsCOMPtr os = mozilla::services::GetObserverService(); - if (!os) - return NS_ERROR_FAILURE; - gCacheObserver = new imgCacheObserver(); NS_ADDREF(gCacheObserver); - os->AddObserver(gCacheObserver, "memory-pressure", false); - os->AddObserver(gCacheObserver, "chrome-flush-skin-caches", false); - os->AddObserver(gCacheObserver, "chrome-flush-caches", false); - - gCacheTracker = new imgCacheExpirationTracker(); - - sCache.Init(); - sChromeCache.Init(); + nsCOMPtr os = mozilla::services::GetObserverService(); + if (os) + os->AddObserver(gCacheObserver, "memory-pressure", false); int32_t timeweight; - rv = Preferences::GetInt("image.cache.timeweight", &timeweight); + nsresult rv = Preferences::GetInt("image.cache.timeweight", &timeweight); if (NS_SUCCEEDED(rv)) sCacheTimeWeight = timeweight / 1000.0; else @@ -860,23 +861,49 @@ nsresult imgLoader::InitCache() else sCacheMaxSize = 5 * 1024 * 1024; - NS_RegisterMemoryMultiReporter(new imgMemoryReporter()); + sMemReporter = new imgMemoryReporter(); + NS_RegisterMemoryMultiReporter(sMemReporter); NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(ImagesContentUsedUncompressed)); - - return NS_OK; +} + +nsresult imgLoader::InitCache() +{ + NS_TIME_FUNCTION; + + nsCOMPtr os = mozilla::services::GetObserverService(); + if (!os) + return NS_ERROR_FAILURE; + + os->AddObserver(this, "memory-pressure", false); + os->AddObserver(this, "chrome-flush-skin-caches", false); + os->AddObserver(this, "chrome-flush-caches", false); + os->AddObserver(this, "last-pb-context-exited", false); + os->AddObserver(this, "profile-before-change", false); + os->AddObserver(this, "xpcom-shutdown", false); + + mCacheTracker = new imgCacheExpirationTracker(); + + mCache.Init(); + mChromeCache.Init(); + + return NS_OK; } nsresult imgLoader::Init() { + InitCache(); + ReadAcceptHeaderPref(); Preferences::AddWeakObserver(this, "image.http.accept"); - // Listen for when we leave private browsing mode - nsCOMPtr obService = mozilla::services::GetObserverService(); - if (obService) - obService->AddObserver(this, NS_PRIVATE_BROWSING_SWITCH_TOPIC, true); + return NS_OK; +} +NS_IMETHODIMP +imgLoader::RespectPrivacyNotifications() +{ + mRespectPrivacy = true; return NS_OK; } @@ -888,12 +915,21 @@ imgLoader::Observe(nsISupports* aSubject, const char* aTopic, const PRUnichar* a if (!strcmp(NS_ConvertUTF16toUTF8(aData).get(), "image.http.accept")) { ReadAcceptHeaderPref(); } - } - // ...and exits from private browsing. - else if (!strcmp(aTopic, NS_PRIVATE_BROWSING_SWITCH_TOPIC)) { - if (NS_LITERAL_STRING(NS_PRIVATE_BROWSING_LEAVE).Equals(aData)) + } else if (strcmp(aTopic, "memory-pressure") == 0) { + MinimizeCaches(); + } else if (strcmp(aTopic, "chrome-flush-skin-caches") == 0 || + strcmp(aTopic, "chrome-flush-caches") == 0) { + MinimizeCaches(); + ClearChromeImageCache(); + } else if (strcmp(aTopic, "last-pb-context-exited") == 0) { + if (mRespectPrivacy) { ClearImageCache(); + ClearChromeImageCache(); + } + } else if (strcmp(aTopic, "profile-before-change") == 0 || + strcmp(aTopic, "xpcom-shutdown") == 0) { + mCacheTracker = nullptr; } // (Nothing else should bring us here) @@ -942,8 +978,8 @@ NS_IMETHODIMP imgLoader::FindEntryProperties(nsIURI *uri, nsIProperties **_retva *_retval = nullptr; if (cache.Get(spec, getter_AddRefs(entry)) && entry) { - if (gCacheTracker && entry->HasNoProxies()) - gCacheTracker->MarkUsed(entry); + if (mCacheTracker && entry->HasNoProxies()) + mCacheTracker->MarkUsed(entry); nsRefPtr request = getter_AddRefs(entry->GetRequest()); if (request) { @@ -957,27 +993,23 @@ NS_IMETHODIMP imgLoader::FindEntryProperties(nsIURI *uri, nsIProperties **_retva void imgLoader::Shutdown() { - ClearChromeImageCache(); - ClearImageCache(); - NS_IF_RELEASE(gCacheObserver); - delete gCacheTracker; - gCacheTracker = nullptr; + NS_RELEASE(gCacheObserver); } nsresult imgLoader::ClearChromeImageCache() { - return EvictEntries(sChromeCache); + return EvictEntries(mChromeCache); } nsresult imgLoader::ClearImageCache() { - return EvictEntries(sCache); + return EvictEntries(mCache); } void imgLoader::MinimizeCaches() { - EvictEntries(sCacheQueue); - EvictEntries(sChromeCacheQueue); + EvictEntries(mCacheQueue); + EvictEntries(mChromeCacheQueue); } bool imgLoader::PutIntoCache(nsIURI *key, imgCacheEntry *entry) @@ -1020,8 +1052,8 @@ bool imgLoader::PutIntoCache(nsIURI *key, imgCacheEntry *entry) if (entry->HasNoProxies()) { nsresult addrv = NS_OK; - if (gCacheTracker) - addrv = gCacheTracker->AddObject(entry); + if (mCacheTracker) + addrv = mCacheTracker->AddObject(entry); if (NS_SUCCEEDED(addrv)) { imgCacheQueue &queue = GetCacheQueue(key); @@ -1051,8 +1083,8 @@ bool imgLoader::SetHasNoProxies(nsIURI *key, imgCacheEntry *entry) nsresult addrv = NS_OK; - if (gCacheTracker) - addrv = gCacheTracker->AddObject(entry); + if (mCacheTracker) + addrv = mCacheTracker->AddObject(entry); if (NS_SUCCEEDED(addrv)) { queue.Push(entry); @@ -1081,8 +1113,8 @@ bool imgLoader::SetHasProxies(nsIURI *key) imgCacheQueue &queue = GetCacheQueue(key); queue.Remove(entry); - if (gCacheTracker) - gCacheTracker->RemoveObject(entry); + if (mCacheTracker) + mCacheTracker->RemoveObject(entry); entry->SetHasNoProxies(false); @@ -1207,7 +1239,7 @@ bool imgLoader::ValidateRequestWithNewChannel(imgRequest *request, return false; nsRefPtr hvc = - new imgCacheValidator(progressproxy, request, aCX, forcePrincipalCheck); + new imgCacheValidator(progressproxy, this, request, aCX, forcePrincipalCheck); nsCOMPtr listener = hvc.get(); @@ -1388,8 +1420,8 @@ bool imgLoader::RemoveFromCache(nsIURI *aKey) // Entries with no proxies are in the tracker. if (entry->HasNoProxies()) { - if (gCacheTracker) - gCacheTracker->RemoveObject(entry); + if (mCacheTracker) + mCacheTracker->RemoveObject(entry); queue.Remove(entry); } @@ -1423,8 +1455,8 @@ bool imgLoader::RemoveFromCache(imgCacheEntry *entry) if (entry->HasNoProxies()) { LOG_STATIC_FUNC(gImgLog, "imgLoader::RemoveFromCache removing from tracker"); - if (gCacheTracker) - gCacheTracker->RemoveObject(entry); + if (mCacheTracker) + mCacheTracker->RemoveObject(entry); queue.Remove(entry); } @@ -1524,6 +1556,25 @@ NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI, nsresult rv; nsLoadFlags requestFlags = nsIRequest::LOAD_NORMAL; +#ifdef DEBUG + bool isPrivate = false; + + nsCOMPtr channel = do_QueryInterface(aRequest); + if (channel) { + nsCOMPtr loadContext; + NS_QueryNotificationCallbacks(channel, loadContext); + isPrivate = loadContext && loadContext->UsePrivateBrowsing(); + } else if (aLoadGroup) { + nsCOMPtr callbacks; + aLoadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks)); + if (callbacks) { + nsCOMPtr loadContext = do_GetInterface(callbacks); + isPrivate = loadContext && loadContext->UsePrivateBrowsing(); + } + } + MOZ_ASSERT(isPrivate == mRespectPrivacy); +#endif + // Get the default load flags from the loadgroup (if possible)... if (aLoadGroup) { aLoadGroup->GetLoadFlags(&requestFlags); @@ -1577,8 +1628,8 @@ NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI, NS_ABORT_IF_FALSE(!request->HasCacheEntry(), "Proxyless entry's request has cache entry!"); request->SetCacheEntry(entry); - if (gCacheTracker) - gCacheTracker->MarkUsed(entry); + if (mCacheTracker) + mCacheTracker->MarkUsed(entry); } entry->Touch(); @@ -1615,8 +1666,13 @@ NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI, if (NS_FAILED(rv)) return NS_ERROR_FAILURE; - NewRequestAndEntry(forcePrincipalCheck, getter_AddRefs(request), - getter_AddRefs(entry)); +#ifdef DEBUG + nsCOMPtr loadContext; + NS_QueryNotificationCallbacks(newChannel, loadContext); + MOZ_ASSERT_IF(loadContext, loadContext->UsePrivateBrowsing() == mRespectPrivacy); +#endif + + NewRequestAndEntry(forcePrincipalCheck, this, getter_AddRefs(request), getter_AddRefs(entry)); PR_LOG(gImgLog, PR_LOG_DEBUG, ("[this=%p] imgLoader::LoadImage -- Created new imgRequest [request=%p]\n", this, request.get())); @@ -1741,6 +1797,12 @@ NS_IMETHODIMP imgLoader::LoadImageWithChannel(nsIChannel *channel, imgIDecoderOb { NS_ASSERTION(channel, "imgLoader::LoadImageWithChannel -- NULL channel pointer"); +#ifdef DEBUG + nsCOMPtr loadContext; + NS_QueryNotificationCallbacks(channel, loadContext); + MOZ_ASSERT_IF(loadContext, loadContext->UsePrivateBrowsing() == mRespectPrivacy); +#endif + nsRefPtr request; nsCOMPtr uri; @@ -1798,8 +1860,8 @@ NS_IMETHODIMP imgLoader::LoadImageWithChannel(nsIChannel *channel, imgIDecoderOb NS_ABORT_IF_FALSE(!request->HasCacheEntry(), "Proxyless entry's request has cache entry!"); request->SetCacheEntry(entry); - if (gCacheTracker) - gCacheTracker->MarkUsed(entry); + if (mCacheTracker) + mCacheTracker->MarkUsed(entry); } } } @@ -1826,7 +1888,7 @@ NS_IMETHODIMP imgLoader::LoadImageWithChannel(nsIChannel *channel, imgIDecoderOb // Default to doing a principal check because we don't know who // started that load and whether their principal ended up being // inherited on the channel. - NewRequestAndEntry(true, getter_AddRefs(request), getter_AddRefs(entry)); + NewRequestAndEntry(true, this, getter_AddRefs(request), getter_AddRefs(entry)); // We use originalURI here to fulfil the imgIRequest contract on GetURI. nsCOMPtr originalURI; @@ -2038,17 +2100,16 @@ NS_IMPL_ISUPPORTS5(imgCacheValidator, nsIStreamListener, nsIRequestObserver, nsIChannelEventSink, nsIInterfaceRequestor, nsIAsyncVerifyRedirectCallback) -imgLoader imgCacheValidator::sImgLoader; - imgCacheValidator::imgCacheValidator(nsProgressNotificationProxy* progress, - imgRequest *request, void *aContext, - bool forcePrincipalCheckForCacheEntry) + imgLoader* loader, imgRequest *request, + void *aContext, bool forcePrincipalCheckForCacheEntry) : mProgressProxy(progress), mRequest(request), - mContext(aContext) + mContext(aContext), + mImgLoader(loader) { - NewRequestAndEntry(forcePrincipalCheckForCacheEntry, - getter_AddRefs(mNewRequest), getter_AddRefs(mNewEntry)); + NewRequestAndEntry(forcePrincipalCheckForCacheEntry, loader, getter_AddRefs(mNewRequest), + getter_AddRefs(mNewEntry)); } imgCacheValidator::~imgCacheValidator() @@ -2151,7 +2212,7 @@ NS_IMETHODIMP imgCacheValidator::OnStartRequest(nsIRequest *aRequest, nsISupport // Try to add the new request into the cache. Note that the entry must be in // the cache before the proxies' ownership changes, because adding a proxy // changes the caching behaviour for imgRequests. - sImgLoader.PutIntoCache(originalURI, mNewEntry); + mImgLoader->PutIntoCache(originalURI, mNewEntry); uint32_t count = mProxies.Count(); for (int32_t i = count-1; i>=0; i--) { diff --git a/image/src/imgLoader.h b/image/src/imgLoader.h index 64d3563b93ff..85756884eed2 100644 --- a/image/src/imgLoader.h +++ b/image/src/imgLoader.h @@ -27,16 +27,19 @@ #include "prlock.h" #endif +class imgLoader; class imgRequest; class imgRequestProxy; class imgIRequest; class imgIDecoderObserver; class nsILoadGroup; +class imgCacheExpirationTracker; +class imgMemoryReporter; class imgCacheEntry { public: - imgCacheEntry(imgRequest *request, bool aForcePrincipalCheck); + imgCacheEntry(imgLoader* loader, imgRequest *request, bool aForcePrincipalCheck); ~imgCacheEntry(); nsrefcnt AddRef() @@ -130,6 +133,11 @@ public: return mForcePrincipalCheck; } + imgLoader* Loader() const + { + return mLoader; + } + private: // methods friend class imgLoader; friend class imgCacheQueue; @@ -148,6 +156,7 @@ private: // data nsAutoRefCnt mRefCnt; NS_DECL_OWNINGTHREAD + imgLoader* mLoader; nsRefPtr mRequest; uint32_t mDataSize; int32_t mTouchedTime; @@ -219,18 +228,19 @@ public: static nsresult GetMimeTypeFromContent(const char* aContents, uint32_t aLength, nsACString& aContentType); + static void GlobalInit(); // for use by the factory static void Shutdown(); // for use by the factory - static nsresult ClearChromeImageCache(); - static nsresult ClearImageCache(); - static void MinimizeCaches(); + nsresult ClearChromeImageCache(); + nsresult ClearImageCache(); + void MinimizeCaches(); - static nsresult InitCache(); + nsresult InitCache(); - static bool RemoveFromCache(nsIURI *aKey); - static bool RemoveFromCache(imgCacheEntry *entry); + bool RemoveFromCache(nsIURI *aKey); + bool RemoveFromCache(imgCacheEntry *entry); - static bool PutIntoCache(nsIURI *key, imgCacheEntry *entry); + bool PutIntoCache(nsIURI *key, imgCacheEntry *entry); // Returns true if we should prefer evicting cache entry |two| over cache // entry |one|. @@ -256,7 +266,7 @@ public: return oneweight < twoweight; } - static void VerifyCacheSizes(); + void VerifyCacheSizes(); // The image loader maintains a hash table of all imgCacheEntries. However, // only some of them will be evicted from the cache: those who have no @@ -269,8 +279,8 @@ public: // HasObservers(). The request's cache entry will be re-set before this // happens, by calling imgRequest::SetCacheEntry() when an entry with no // observers is re-requested. - static bool SetHasNoProxies(nsIURI *key, imgCacheEntry *entry); - static bool SetHasProxies(nsIURI *key); + bool SetHasNoProxies(nsIURI *key, imgCacheEntry *entry); + bool SetHasProxies(nsIURI *key); private: // methods @@ -307,27 +317,32 @@ private: // methods typedef nsRefPtrHashtable imgCacheTable; - static nsresult EvictEntries(imgCacheTable &aCacheToClear); - static nsresult EvictEntries(imgCacheQueue &aQueueToClear); + nsresult EvictEntries(imgCacheTable &aCacheToClear); + nsresult EvictEntries(imgCacheQueue &aQueueToClear); - static imgCacheTable &GetCache(nsIURI *aURI); - static imgCacheQueue &GetCacheQueue(nsIURI *aURI); - static void CacheEntriesChanged(nsIURI *aURI, int32_t sizediff = 0); - static void CheckCacheLimits(imgCacheTable &cache, imgCacheQueue &queue); + imgCacheTable &GetCache(nsIURI *aURI); + imgCacheQueue &GetCacheQueue(nsIURI *aURI); + void CacheEntriesChanged(nsIURI *aURI, PRInt32 sizediff = 0); + void CheckCacheLimits(imgCacheTable &cache, imgCacheQueue &queue); private: // data friend class imgCacheEntry; friend class imgMemoryReporter; - static imgCacheTable sCache; - static imgCacheQueue sCacheQueue; + imgCacheTable mCache; + imgCacheQueue mCacheQueue; + + imgCacheTable mChromeCache; + imgCacheQueue mChromeCacheQueue; - static imgCacheTable sChromeCache; - static imgCacheQueue sChromeCacheQueue; static double sCacheTimeWeight; static uint32_t sCacheMaxSize; + static imgMemoryReporter* sMemReporter; nsCString mAcceptHeader; + + nsAutoPtr mCacheTracker; + bool mRespectPrivacy; }; @@ -395,8 +410,8 @@ class imgCacheValidator : public nsIStreamListener, public nsIAsyncVerifyRedirectCallback { public: - imgCacheValidator(nsProgressNotificationProxy* progress, imgRequest *request, - void *aContext, bool forcePrincipalCheckForCacheEntry); + imgCacheValidator(nsProgressNotificationProxy* progress, imgLoader* loader, + imgRequest *request, void *aContext, bool forcePrincipalCheckForCacheEntry); virtual ~imgCacheValidator(); void AddProxy(imgRequestProxy *aProxy); @@ -422,7 +437,7 @@ private: void *mContext; - static imgLoader sImgLoader; + imgLoader* mImgLoader; }; #endif // imgLoader_h__ diff --git a/image/src/imgRequest.cpp b/image/src/imgRequest.cpp index e89e05a912f0..2fc58a8e8702 100644 --- a/image/src/imgRequest.cpp +++ b/image/src/imgRequest.cpp @@ -79,8 +79,8 @@ NS_IMPL_ISUPPORTS8(imgRequest, nsIInterfaceRequestor, nsIAsyncVerifyRedirectCallback) -imgRequest::imgRequest() : - mValidator(nullptr), mImageSniffers("image-sniffing-services"), +imgRequest::imgRequest(imgLoader* aLoader) : + mLoader(aLoader), mValidator(nullptr), mImageSniffers("image-sniffing-services"), mInnerWindowId(0), mCORSMode(imgIRequest::CORS_NONE), mDecodeRequested(false), mIsMultiPartChannel(false), mGotData(false), mIsInCache(false), mBlockingOnload(false) @@ -178,7 +178,7 @@ nsresult imgRequest::AddProxy(imgRequestProxy *proxy) // proxies. if (mObservers.IsEmpty()) { NS_ABORT_IF_FALSE(mURI, "Trying to SetHasProxies without key uri."); - imgLoader::SetHasProxies(mURI); + mLoader->SetHasProxies(mURI); } // If we don't have any current observers, we should restart any animation. @@ -223,7 +223,7 @@ nsresult imgRequest::RemoveProxy(imgRequestProxy *proxy, nsresult aStatus, bool if (mCacheEntry) { NS_ABORT_IF_FALSE(mURI, "Removing last observer without key uri."); - imgLoader::SetHasNoProxies(mURI, mCacheEntry); + mLoader->SetHasNoProxies(mURI, mCacheEntry); } #if defined(PR_LOGGING) else { @@ -328,9 +328,9 @@ void imgRequest::RemoveFromCache() if (mIsInCache) { // mCacheEntry is nulled out when we have no more observers. if (mCacheEntry) - imgLoader::RemoveFromCache(mCacheEntry); + mLoader->RemoveFromCache(mCacheEntry); else - imgLoader::RemoveFromCache(mURI); + mLoader->RemoveFromCache(mURI); } mCacheEntry = nullptr; diff --git a/image/src/imgRequest.h b/image/src/imgRequest.h index 424631b5b8c1..71c7715831cc 100644 --- a/image/src/imgRequest.h +++ b/image/src/imgRequest.h @@ -31,6 +31,7 @@ class imgCacheValidator; +class imgLoader; class imgRequestProxy; class imgCacheEntry; class imgMemoryReporter; @@ -50,7 +51,7 @@ class imgRequest : public imgIDecoderObserver, public nsIAsyncVerifyRedirectCallback { public: - imgRequest(); + imgRequest(imgLoader* aLoader); virtual ~imgRequest(); NS_DECL_ISUPPORTS @@ -183,6 +184,8 @@ public: private: friend class imgMemoryReporter; + // Weak reference to parent loader; this request cannot outlive its owner. + imgLoader* mLoader; nsCOMPtr mRequest; // The original URI we were loaded with. This is the same as the URI we are // keyed on in the cache. diff --git a/image/src/imgTools.cpp b/image/src/imgTools.cpp index 827b46d0d64f..eca1d366848e 100644 --- a/image/src/imgTools.cpp +++ b/image/src/imgTools.cpp @@ -8,6 +8,8 @@ #include "nsCOMPtr.h" #include "nsString.h" #include "nsError.h" +#include "imgILoader.h" +#include "imgICache.h" #include "imgIContainer.h" #include "imgIEncoder.h" #include "imgIDecoderObserver.h" @@ -19,10 +21,14 @@ #include "nsIInterfaceRequestorUtils.h" #include "nsStreamUtils.h" #include "nsNetUtil.h" +#include "nsContentUtils.h" #include "RasterImage.h" using namespace mozilla::image; +class nsIDOMDocument; +class nsIDocument; + /* ========== imgITools implementation ========== */ @@ -269,3 +275,20 @@ NS_IMETHODIMP imgTools::GetFirstImageFrame(imgIContainer *aContainer, frame.forget(aSurface); return NS_OK; } + +NS_IMETHODIMP +imgTools::GetImgLoaderForDocument(nsIDOMDocument* aDoc, imgILoader** aLoader) +{ + nsCOMPtr doc = do_QueryInterface(aDoc); + NS_IF_ADDREF(*aLoader = nsContentUtils::GetImgLoaderForDocument(doc)); + return NS_OK; +} + +NS_IMETHODIMP +imgTools::GetImgCacheForDocument(nsIDOMDocument* aDoc, imgICache** aCache) +{ + nsCOMPtr loader; + nsresult rv = GetImgLoaderForDocument(aDoc, getter_AddRefs(loader)); + NS_ENSURE_SUCCESS(rv, rv); + return CallQueryInterface(loader, aCache); +} diff --git a/image/test/mochitest/imgutils.js b/image/test/mochitest/imgutils.js index 433518547296..bbdcb9c4a46b 100644 --- a/image/test/mochitest/imgutils.js +++ b/image/test/mochitest/imgutils.js @@ -7,9 +7,10 @@ // Helper function to clear the image cache of content images function clearImageCache() { - netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); - var imageCache = Components.classes["@mozilla.org/image/cache;1"] - .getService(Components.interfaces.imgICache); + var tools = SpecialPowers.wrap(Components) + .classes["@mozilla.org/image/tools;1"] + .getService(Components.interfaces.imgITools); + var imageCache = tools.getImgCacheForDocument(window.document); imageCache.clearCache(false); // true=chrome, false=content } diff --git a/image/test/unit/async_load_tests.js b/image/test/unit/async_load_tests.js index 0124701a06b9..f2346f79fb0d 100644 --- a/image/test/unit/async_load_tests.js +++ b/image/test/unit/async_load_tests.js @@ -85,9 +85,8 @@ function checkSecondLoad() { do_test_pending(); - var loader = Cc["@mozilla.org/image/loader;1"].getService(Ci.imgILoader); var listener = new ImageListener(checkClone, secondLoadDone); - requests.push(loader.loadImage(uri, null, null, null, null, listener, null, 0, null, null, null)); + requests.push(gCurrentLoader.loadImage(uri, null, null, null, null, listener, null, 0, null, null, null)); listener.synchronous = false; } @@ -139,12 +138,11 @@ function checkSecondChannelLoad() var channellistener = new ChannelListener(); channel.asyncOpen(channellistener, null); - var loader = Cc["@mozilla.org/image/loader;1"].getService(Ci.imgILoader); var listener = new ImageListener(getChannelLoadImageStartCallback(channellistener), getChannelLoadImageStopCallback(channellistener, all_done_callback)); var outlistener = {}; - requests.push(loader.loadImageWithChannel(channel, listener, null, outlistener)); + requests.push(gCurrentLoader.loadImageWithChannel(channel, listener, null, outlistener)); channellistener.outputListener = outlistener.value; listener.synchronous = false; @@ -152,11 +150,8 @@ function checkSecondChannelLoad() function run_loadImageWithChannel_tests() { - // To ensure we're testing what we expect to, clear the content image cache - // between test runs. - var loader = Cc["@mozilla.org/image/loader;1"].getService(Ci.imgILoader); - loader.QueryInterface(Ci.imgICache); - loader.clearCache(false); + // To ensure we're testing what we expect to, create a new loader and cache. + gCurrentLoader = Cc["@mozilla.org/image/loader;1"].createInstance(Ci.imgILoader); do_test_pending(); @@ -165,12 +160,11 @@ function run_loadImageWithChannel_tests() var channellistener = new ChannelListener(); channel.asyncOpen(channellistener, null); - var loader = Cc["@mozilla.org/image/loader;1"].getService(Ci.imgILoader); var listener = new ImageListener(getChannelLoadImageStartCallback(channellistener), getChannelLoadImageStopCallback(channellistener, checkSecondChannelLoad)); var outlistener = {}; - requests.push(loader.loadImageWithChannel(channel, listener, null, outlistener)); + requests.push(gCurrentLoader.loadImageWithChannel(channel, listener, null, outlistener)); channellistener.outputListener = outlistener.value; listener.synchronous = false; @@ -185,12 +179,10 @@ function startImageCallback(otherCb) { return function(listener, request) { - var loader = Cc["@mozilla.org/image/loader;1"].getService(Ci.imgILoader); - // Make sure we can load the same image immediately out of the cache. do_test_pending(); var listener2 = new ImageListener(null, function(foo, bar) { do_test_finished(); }); - requests.push(loader.loadImage(uri, null, null, null, null, listener2, null, 0, null, null, null)); + requests.push(gCurrentLoader.loadImage(uri, null, null, null, null, listener2, null, 0, null, null, null)); listener2.synchronous = false; // Now that we've started another load, chain to the callback. @@ -198,13 +190,15 @@ function startImageCallback(otherCb) } } +var gCurrentLoader; + function run_test() { - var loader = Cc["@mozilla.org/image/loader;1"].getService(Ci.imgILoader); + gCurrentLoader = Cc["@mozilla.org/image/loader;1"].createInstance(Ci.imgILoader); do_test_pending(); var listener = new ImageListener(startImageCallback(checkClone), firstLoadDone); - var req = loader.loadImage(uri, null, null, null, null, listener, null, 0, null, null, null); + var req = gCurrentLoader.loadImage(uri, null, null, null, null, listener, null, 0, null, null, null); requests.push(req); // Ensure that we don't cause any mayhem when we lock an image. diff --git a/image/test/unit/test_private_channel.js b/image/test/unit/test_private_channel.js new file mode 100644 index 000000000000..d15eb4613c86 --- /dev/null +++ b/image/test/unit/test_private_channel.js @@ -0,0 +1,111 @@ +Components.utils.import("resource://testing-common/httpd.js"); +const Cc = Components.classes; +const Ci = Components.interfaces; + +var server = new HttpServer(); +server.registerPathHandler('/image.png', imageHandler); +server.start(8088); + +load('image_load_helpers.js'); + +var gHits = 0; + +var gIoService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); +var gPublicLoader = Cc["@mozilla.org/image/loader;1"].createInstance(Ci.imgILoader); +var gPrivateLoader = Cc["@mozilla.org/image/loader;1"].createInstance(Ci.imgILoader); +gPrivateLoader.QueryInterface(Ci.imgICache).respectPrivacyNotifications(); + +function imageHandler(metadata, response) { + gHits++; + response.setHeader("Cache-Control", "max-age=10000", false); + response.setStatusLine(metadata.httpVersion, 200, "OK"); + response.setHeader("Content-Type", "image/png", false); + var body = "iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAAEUlEQVQImWP4z8AAQTAamQkAhpcI+DeMzFcAAAAASUVORK5CYII="; + response.bodyOutputStream.write(body, body.length); +} + +var requests = []; +var listeners = []; + +function NotificationCallbacks(isPrivate) { + this.usePrivateBrowsing = isPrivate; +} + +NotificationCallbacks.prototype = { + QueryInterface: function (iid) { + if (iid.equals(Ci.nsISupports) || + iid.equals(Ci.nsILoadContext)) + return this; + throw Cr.NS_ERROR_NO_INTERFACE; + }, + getInterface: function(iid) { + if (iid.equals(Ci.nsILoadContext)) + return this; + throw Cr.NS_ERROR_NO_INTERFACE; + } +}; + +var gImgPath = 'http://localhost:8088/image.png'; + +function setup_chan(path, isPrivate, callback) { + var uri = gIoService.newURI(gImgPath, null, null); + var chan = gIoService.newChannelFromURI(uri); + chan.notificationCallbacks = new NotificationCallbacks(isPrivate); + var channelListener = new ChannelListener(); + chan.asyncOpen(channelListener, null); + + var listener = new ImageListener(null, callback); + listeners.push(listener); + var outlistener = {}; + var loader = isPrivate ? gPrivateLoader : gPublicLoader; + requests.push(loader.loadImageWithChannel(chan, listener, null, outlistener)); + channelListener.outputListener = outlistener.value; + listener.synchronous = false; +} + +function loadImage(isPrivate, callback) { + var listener = new ImageListener(null, callback); + var uri = gIoService.newURI(gImgPath, null, null); + var loadGroup = Cc["@mozilla.org/network/load-group;1"].createInstance(Ci.nsILoadGroup); + loadGroup.notificationCallbacks = new NotificationCallbacks(isPrivate); + var loader = isPrivate ? gPrivateLoader : gPublicLoader; + requests.push(loader.loadImage(uri, null, null, null, loadGroup, listener, null, 0, null, null, null)); + listener.synchronous = false; +} + +function run_loadImage_tests() { + let cs = Cc["@mozilla.org/network/cache-service;1"].getService(Ci.nsICacheService); + cs.evictEntries(Ci.nsICache.STORE_ANYWHERE); + + gHits = 0; + loadImage(false, function() { + loadImage(false, function() { + loadImage(true, function() { + loadImage(true, function() { + do_check_eq(gHits, 2); + server.stop(do_test_finished); + }); + }); + }); + }); +} + +function run_test() { + do_test_pending(); + + // We create a public channel that loads an image, then an identical + // one that should cause a cache read. We then create a private channel + // and load the same image, and do that a second time to ensure a cache + // read. In total, we should cause two separate http responses to occur, + // since the private channels shouldn't be able to use the public cache. + setup_chan('/image.png', false, function() { + setup_chan('/image.png', false, function() { + setup_chan('/image.png', true, function() { + setup_chan('/image.png', true, function() { + do_check_eq(gHits, 2); + run_loadImage_tests(); + }); + }); + }); + }); +} \ No newline at end of file diff --git a/image/test/unit/xpcshell.ini b/image/test/unit/xpcshell.ini index b1086d4e6d75..c9e710939048 100644 --- a/image/test/unit/xpcshell.ini +++ b/image/test/unit/xpcshell.ini @@ -11,3 +11,4 @@ tail = # Bug 676968: test fails consistently on Android fail-if = os == "android" [test_moz_icon_uri.js] +[test_private_channel.js] \ No newline at end of file diff --git a/ipc/chromium/src/base/condition_variable_unittest.cc b/ipc/chromium/src/base/condition_variable_unittest.cc index 8e003940935d..b3a5d307370e 100644 --- a/ipc/chromium/src/base/condition_variable_unittest.cc +++ b/ipc/chromium/src/base/condition_variable_unittest.cc @@ -133,7 +133,7 @@ class WorkQueue : public PlatformThread::Delegate { bool allow_help_requests_; // Workers can signal more workers. bool shutdown_; // Set when threads need to terminate. - DFAKE_MUTEX(locked_methods_); + DFAKE_MUTEX(locked_methods_) }; //------------------------------------------------------------------------------ diff --git a/ipc/chromium/src/base/process_util_bsd.cc b/ipc/chromium/src/base/process_util_bsd.cc index a21b2695c0cc..251cd57d6c65 100644 --- a/ipc/chromium/src/base/process_util_bsd.cc +++ b/ipc/chromium/src/base/process_util_bsd.cc @@ -6,7 +6,6 @@ #include "base/process_util.h" -#include #include #include #include @@ -95,7 +94,7 @@ bool LaunchApp(const std::vector& argv, bool wait, ProcessHandle* process_handle, ProcessArchitecture arch) { return LaunchApp(argv, fds_to_remap, env_vars_to_set, - SAME_PRIVILEGES_AS_PARENT, + PRIVILEGES_INHERIT, wait, process_handle); } @@ -220,7 +219,7 @@ bool LaunchApp(const std::vector& argv, bool wait, ProcessHandle* process_handle, ProcessArchitecture arch) { return LaunchApp(argv, fds_to_remap, env_vars_to_set, - SAME_PRIVILEGES_AS_PARENT, + PRIVILEGES_INHERIT, wait, process_handle); } @@ -256,7 +255,7 @@ bool LaunchApp(const std::vector& argv, argv_cstr[i] = const_cast(argv[i].c_str()); argv_cstr[argv.size()] = NULL; - if (privs == UNPRIVILEGED) { + if (privs == PRIVILEGES_UNPRIVILEGED) { if (setgid(CHILD_UNPRIVILEGED_GID) != 0) { DLOG(ERROR) << "FAILED TO setgid() CHILD PROCESS, path: " << argv_cstr[0]; _exit(127); diff --git a/ipc/chromium/src/base/ref_counted.h b/ipc/chromium/src/base/ref_counted.h index 013bd665203a..18e2794bd880 100644 --- a/ipc/chromium/src/base/ref_counted.h +++ b/ipc/chromium/src/base/ref_counted.h @@ -28,7 +28,7 @@ class RefCountedBase { bool in_dtor_; #endif - DFAKE_MUTEX(add_release_); + DFAKE_MUTEX(add_release_) DISALLOW_COPY_AND_ASSIGN(RefCountedBase); }; diff --git a/ipc/chromium/src/base/thread_collision_warner.h b/ipc/chromium/src/base/thread_collision_warner.h index 6d3901b0f5d2..3b4230a6d245 100644 --- a/ipc/chromium/src/base/thread_collision_warner.h +++ b/ipc/chromium/src/base/thread_collision_warner.h @@ -101,7 +101,7 @@ // Defines a class member that acts like a mutex. It is used only as a // verification tool. #define DFAKE_MUTEX(obj) \ - mutable base::ThreadCollisionWarner obj + mutable base::ThreadCollisionWarner obj; // Asserts the call is never called simultaneously in two threads. Used at // member function scope. #define DFAKE_SCOPED_LOCK(obj) \ diff --git a/ipc/chromium/src/base/thread_collision_warner_unittest.cc b/ipc/chromium/src/base/thread_collision_warner_unittest.cc index 45b3823ee3b6..4ad8f4b0335d 100644 --- a/ipc/chromium/src/base/thread_collision_warner_unittest.cc +++ b/ipc/chromium/src/base/thread_collision_warner_unittest.cc @@ -17,7 +17,7 @@ MSVC_PUSH_DISABLE_WARNING(4822) // Would cause a memory leak otherwise. #undef DFAKE_MUTEX -#define DFAKE_MUTEX(obj) scoped_ptr obj +#define DFAKE_MUTEX(obj) scoped_ptr obj; // In Release, we expect the AsserterBase::warn() to not happen. #define EXPECT_NDEBUG_FALSE_DEBUG_TRUE EXPECT_FALSE @@ -140,7 +140,7 @@ TEST(ThreadCollisionTest, MTBookCriticalSectionTest) { } private: - DFAKE_MUTEX(push_pop_); + DFAKE_MUTEX(push_pop_) DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue); }; @@ -198,7 +198,7 @@ TEST(ThreadCollisionTest, MTScopedBookCriticalSectionTest) { } private: - DFAKE_MUTEX(push_pop_); + DFAKE_MUTEX(push_pop_) DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue); }; @@ -256,7 +256,7 @@ TEST(ThreadCollisionTest, MTSynchedScopedBookCriticalSectionTest) { } private: - DFAKE_MUTEX(push_pop_); + DFAKE_MUTEX(push_pop_) DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue); }; @@ -330,7 +330,7 @@ TEST(ThreadCollisionTest, MTSynchedScopedRecursiveBookCriticalSectionTest) { } private: - DFAKE_MUTEX(push_pop_); + DFAKE_MUTEX(push_pop_) DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue); }; diff --git a/ipc/chromium/src/chrome/common/file_descriptor_set_posix.h b/ipc/chromium/src/chrome/common/file_descriptor_set_posix.h index 342e6d932f89..b011baf783ae 100644 --- a/ipc/chromium/src/chrome/common/file_descriptor_set_posix.h +++ b/ipc/chromium/src/chrome/common/file_descriptor_set_posix.h @@ -30,7 +30,7 @@ class FileDescriptorSet : public base::RefCountedThreadSafe { // In debugging mode, it's a fatal error to try and add more than this number // of descriptors to a FileDescriptorSet. enum { - MAX_DESCRIPTORS_PER_MESSAGE = 4, + MAX_DESCRIPTORS_PER_MESSAGE = 4 }; // --------------------------------------------------------------------------- diff --git a/ipc/chromium/src/chrome/common/ipc_channel_posix.h b/ipc/chromium/src/chrome/common/ipc_channel_posix.h index d839e9ef5461..37854ba0fdc0 100644 --- a/ipc/chromium/src/chrome/common/ipc_channel_posix.h +++ b/ipc/chromium/src/chrome/common/ipc_channel_posix.h @@ -91,7 +91,7 @@ class Channel::ChannelImpl : public MessageLoopForIO::Watcher { // We assume a worst case: kReadBufferSize bytes of messages, where each // message has no payload and a full complement of descriptors. MAX_READ_FDS = (Channel::kReadBufferSize / sizeof(IPC::Message::Header)) * - FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE, + FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE }; // This is a control message buffer large enough to hold kMaxReadFDs diff --git a/js/src/gc/Statistics.cpp b/js/src/gc/Statistics.cpp index 12635fbd9d2c..12cf38af3d48 100644 --- a/js/src/gc/Statistics.cpp +++ b/js/src/gc/Statistics.cpp @@ -389,6 +389,9 @@ Statistics::formatData(StatisticsSerializer &ss, uint64_t timestamp) if (ss.isJSON()) { ss.appendDecimal("Page Faults", "", double(slices[i].endFaults - slices[i].startFaults)); + + ss.appendNumber("Start Timestamp", "%llu", "", (unsigned long long)slices[i].start); + ss.appendNumber("End Timestamp", "%llu", "", (unsigned long long)slices[i].end); } if (slices[i].resetReason) ss.appendString("Reset", slices[i].resetReason); diff --git a/js/src/jsapi-tests/Makefile.in b/js/src/jsapi-tests/Makefile.in index 9a2927989ef3..bd5377fe4ec1 100644 --- a/js/src/jsapi-tests/Makefile.in +++ b/js/src/jsapi-tests/Makefile.in @@ -17,6 +17,7 @@ CPPSRCS = \ tests.cpp \ selfTest.cpp \ testAddPropertyPropcache.cpp \ + testArrayBuffer.cpp \ testArgumentsObject.cpp \ testBindCallable.cpp \ testBug604087.cpp \ diff --git a/js/src/jsapi-tests/testArrayBuffer.cpp b/js/src/jsapi-tests/testArrayBuffer.cpp new file mode 100644 index 000000000000..0e84627cc81a --- /dev/null +++ b/js/src/jsapi-tests/testArrayBuffer.cpp @@ -0,0 +1,164 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + */ + +#include "tests.h" +#include "jsfriendapi.h" + +#define NUM_TEST_BUFFERS 2 +#define MAGIC_VALUE_1 3 +#define MAGIC_VALUE_2 17 + +BEGIN_TEST(testArrayBuffer_bug720949_steal) +{ + JS::RootedObject buf_len1(cx), buf_len200(cx); + JS::RootedObject tarray_len1(cx), tarray_len200(cx); + + uint32_t sizes[NUM_TEST_BUFFERS] = { sizeof(uint32_t), 200 * sizeof(uint32_t) }; + JS::HandleObject testBuf[NUM_TEST_BUFFERS] = { buf_len1, buf_len200 }; + JS::HandleObject testArray[NUM_TEST_BUFFERS] = { tarray_len1, tarray_len200 }; + + // Single-element ArrayBuffer (uses fixed slots for storage) + CHECK(buf_len1 = JS_NewArrayBuffer(cx, sizes[0])); + CHECK(tarray_len1 = JS_NewInt32ArrayWithBuffer(cx, testBuf[0], 0, -1)); + + jsval dummy = INT_TO_JSVAL(MAGIC_VALUE_1); + JS_SetElement(cx, testArray[0], 0, &dummy); + + // Many-element ArrayBuffer (uses dynamic storage) + CHECK(buf_len200 = JS_NewArrayBuffer(cx, 200 * sizeof(uint32_t))); + CHECK(tarray_len200 = JS_NewInt32ArrayWithBuffer(cx, testBuf[1], 0, -1)); + + for (unsigned i = 0; i < NUM_TEST_BUFFERS; i++) { + JS::HandleObject obj = testBuf[i]; + JS::HandleObject view = testArray[i]; + uint32_t size = sizes[i]; + jsval v; + + // Byte lengths should all agree + CHECK(JS_IsArrayBufferObject(obj, cx)); + CHECK_EQUAL(JS_GetArrayBufferByteLength(obj, cx), size); + JS_GetProperty(cx, obj, "byteLength", &v); + CHECK_SAME(v, INT_TO_JSVAL(size)); + JS_GetProperty(cx, view, "byteLength", &v); + CHECK_SAME(v, INT_TO_JSVAL(size)); + + // Modifying the underlying data should update the value returned through the view + uint8_t *data = JS_GetArrayBufferData(obj, cx); + CHECK(data != NULL); + *reinterpret_cast(data) = MAGIC_VALUE_2; + CHECK(JS_GetElement(cx, view, 0, &v)); + CHECK_SAME(v, INT_TO_JSVAL(MAGIC_VALUE_2)); + + // Steal the contents + void *contents; + CHECK(JS_StealArrayBufferContents(cx, obj, &contents)); + CHECK(contents != NULL); + + // Check that the original ArrayBuffer is neutered + CHECK_EQUAL(JS_GetArrayBufferByteLength(obj, cx), 0); + CHECK(JS_GetProperty(cx, obj, "byteLength", &v)); + CHECK_SAME(v, INT_TO_JSVAL(0)); + CHECK(JS_GetProperty(cx, view, "byteLength", &v)); + CHECK_SAME(v, INT_TO_JSVAL(0)); + CHECK(JS_GetProperty(cx, view, "byteOffset", &v)); + CHECK_SAME(v, INT_TO_JSVAL(0)); + CHECK(JS_GetProperty(cx, view, "length", &v)); + CHECK_SAME(v, INT_TO_JSVAL(0)); + CHECK_EQUAL(JS_GetArrayBufferByteLength(obj, cx), 0); + v = JSVAL_VOID; + JS_GetElement(cx, obj, 0, &v); + CHECK_SAME(v, JSVAL_VOID); + + // Transfer to a new ArrayBuffer + JS::RootedObject dst(cx, JS_NewArrayBufferWithContents(cx, contents)); + CHECK(JS_IsArrayBufferObject(dst, cx)); + data = JS_GetArrayBufferData(obj, cx); + + JS::RootedObject dstview(cx, JS_NewInt32ArrayWithBuffer(cx, dst, 0, -1)); + CHECK(dstview != NULL); + + CHECK_EQUAL(JS_GetArrayBufferByteLength(dst, cx), size); + data = JS_GetArrayBufferData(dst, cx); + CHECK(data != NULL); + CHECK_EQUAL(*reinterpret_cast(data), MAGIC_VALUE_2); + CHECK(JS_GetElement(cx, dstview, 0, &v)); + CHECK_SAME(v, INT_TO_JSVAL(MAGIC_VALUE_2)); + } + + return true; +} +END_TEST(testArrayBuffer_bug720949_steal) + +static void GC(JSContext *cx) +{ + JS_GC(JS_GetRuntime(cx)); + JS_GC(JS_GetRuntime(cx)); // Trigger another to wait for background finalization to end +} + +// Varying number of views of a buffer, to test the neutering weak pointers +BEGIN_TEST(testArrayBuffer_bug720949_viewList) +{ + JS::RootedObject buffer(cx); + + // No views + buffer = JS_NewArrayBuffer(cx, 2000); + buffer = NULL; + GC(cx); + + // One view. + { + buffer = JS_NewArrayBuffer(cx, 2000); + JS::RootedObject view(cx, JS_NewUint8ArrayWithBuffer(cx, buffer, 0, -1)); + void *contents; + CHECK(JS_StealArrayBufferContents(cx, buffer, &contents)); + CHECK(contents != NULL); + JS_free(cx, contents); + GC(cx); + CHECK(isNeutered(view)); + CHECK(isNeutered(buffer)); + view = NULL; + GC(cx); + buffer = NULL; + GC(cx); + } + + // Two views + { + buffer = JS_NewArrayBuffer(cx, 2000); + + JS::RootedObject view1(cx, JS_NewUint8ArrayWithBuffer(cx, buffer, 0, -1)); + JS::RootedObject view2(cx, JS_NewUint8ArrayWithBuffer(cx, buffer, 1, 200)); + + // Remove, re-add a view + view2 = NULL; + GC(cx); + view2 = JS_NewUint8ArrayWithBuffer(cx, buffer, 1, 200); + + // Neuter + void *contents; + CHECK(JS_StealArrayBufferContents(cx, buffer, &contents)); + CHECK(contents != NULL); + JS_free(cx, contents); + + CHECK(isNeutered(view1)); + CHECK(isNeutered(view2)); + CHECK(isNeutered(buffer)); + + view1 = NULL; + GC(cx); + view2 = NULL; + GC(cx); + buffer = NULL; + GC(cx); + } + + return true; +} + +bool isNeutered(JS::HandleObject obj) { + JS::Value v; + return JS_GetProperty(cx, obj, "byteLength", &v) && v.toInt32() == 0; +} + +END_TEST(testArrayBuffer_bug720949_viewList) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 98953f2fe9c9..42348df9da60 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -1082,7 +1082,7 @@ JS_NewRuntime(uint32_t maxbytes) InitMemorySubsystem(); if (!JS::TlsRuntime.init()) - return false; + return NULL; js_NewRuntimeWasCalled = JS_TRUE; } diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 78b747fd1763..3f062eda7c0b 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -4834,6 +4834,37 @@ JS_ClearNonGlobalObject(JSContext *cx, JSObject *objArg); JS_PUBLIC_API(void) JS_SetAllNonReservedSlotsToUndefined(JSContext *cx, JSObject *objArg); +/* + * Create a new array buffer with the given contents, which must have been + * returned by JS_AllocateArrayBufferContents or JS_StealArrayBufferContents. + * The new array buffer takes ownership. After calling this function, do not + * free |contents| or use |contents| from another thread. + */ +extern JS_PUBLIC_API(JSObject *) +JS_NewArrayBufferWithContents(JSContext *cx, void *contents); + +/* + * Steal the contents of the given array buffer. The array buffer has its + * length set to 0 and its contents array cleared. The caller takes ownership + * of |contents| and must free it or transfer ownership via + * JS_NewArrayBufferWithContents when done using it. + */ +extern JS_PUBLIC_API(JSBool) +JS_StealArrayBufferContents(JSContext *cx, JSObject *obj, void **contents); + +/* + * Allocate memory that may be eventually passed to + * JS_NewArrayBufferWithContents. |nbytes| is the number of payload bytes + * required. The pointer to pass to JS_NewArrayBufferWithContents is returned + * in |contents|. The pointer to the |nbytes| of usable memory is returned in + * |data|. (*|contents| will contain a header before |data|.) The only legal + * operations on *|contents| is to free it or pass it to + * JS_NewArrayBufferWithContents. + */ +extern JS_PUBLIC_API(JSBool) +JS_AllocateArrayBufferContents(JSContext *cx, uint32_t nbytes, void **contents, uint8_t **data); + + extern JS_PUBLIC_API(JSIdArray *) JS_Enumerate(JSContext *cx, JSObject *obj); diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index e5bdd1b8f759..7cbf7dd73e3e 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -238,7 +238,11 @@ JSRuntime::createJaegerRuntime(JSContext *cx) } #endif - +static void +selfHosting_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report) +{ + PrintError(cx, stderr, message, report, true); +} static JSClass self_hosting_global_class = { "self-hosting-global", JSCLASS_GLOBAL_FLAGS, JS_PropertyStub, JS_PropertyStub, @@ -264,11 +268,16 @@ JSRuntime::initSelfHosting(JSContext *cx) RootedObject shg(cx, selfHostedGlobal_); Value rv; - if (!Evaluate(cx, shg, options, src, srcLen, &rv)) - return false; - + /* + * Set a temporary error reporter printing to stderr because it is too + * early in the startup process for any other reporter to be registered + * and we don't want errors in self-hosted code to be silently swallowed. + */ + JSErrorReporter oldReporter = JS_SetErrorReporter(cx, selfHosting_ErrorReporter); + bool ok = Evaluate(cx, shg, options, src, srcLen, &rv); + JS_SetErrorReporter(cx, oldReporter); JS_SetGlobalObject(cx, savedGlobal); - return true; + return ok; } void @@ -678,6 +687,78 @@ ReportUsageError(JSContext *cx, HandleObject callee, const char *msg) } } +bool +PrintError(JSContext *cx, FILE *file, const char *message, JSErrorReport *report, + bool reportWarnings) +{ + if (!report) { + fprintf(file, "%s\n", message); + fflush(file); + return false; + } + + /* Conditionally ignore reported warnings. */ + if (JSREPORT_IS_WARNING(report->flags) && !reportWarnings) + return false; + + char *prefix = NULL; + if (report->filename) + prefix = JS_smprintf("%s:", report->filename); + if (report->lineno) { + char *tmp = prefix; + prefix = JS_smprintf("%s%u:%u ", tmp ? tmp : "", report->lineno, report->column); + JS_free(cx, tmp); + } + if (JSREPORT_IS_WARNING(report->flags)) { + char *tmp = prefix; + prefix = JS_smprintf("%s%swarning: ", + tmp ? tmp : "", + JSREPORT_IS_STRICT(report->flags) ? "strict " : ""); + JS_free(cx, tmp); + } + + /* embedded newlines -- argh! */ + const char *ctmp; + while ((ctmp = strchr(message, '\n')) != 0) { + ctmp++; + if (prefix) + fputs(prefix, file); + fwrite(message, 1, ctmp - message, file); + message = ctmp; + } + + /* If there were no filename or lineno, the prefix might be empty */ + if (prefix) + fputs(prefix, file); + fputs(message, file); + + if (report->linebuf) { + /* report->linebuf usually ends with a newline. */ + int n = strlen(report->linebuf); + fprintf(file, ":\n%s%s%s%s", + prefix, + report->linebuf, + (n > 0 && report->linebuf[n-1] == '\n') ? "" : "\n", + prefix); + n = report->tokenptr - report->linebuf; + for (int i = 0, j = 0; i < n; i++) { + if (report->linebuf[i] == '\t') { + for (int k = (j + 8) & ~7; j < k; j++) { + fputc('.', file); + } + continue; + } + fputc('.', file); + j++; + } + fputc('^', file); + } + fputc('\n', file); + fflush(file); + JS_free(cx, prefix); + return true; +} + } /* namespace js */ /* diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 08d2f64b351a..2d844a1bc7d7 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -1759,6 +1759,15 @@ namespace js { extern void ReportUsageError(JSContext *cx, HandleObject callee, const char *msg); +/* + * Prints a full report and returns true if the given report is non-NULL and + * the report doesn't have the JSREPORT_WARNING flag set or reportWarnings is + * true. + * Returns false otherwise, printing just the message if the report is NULL. + */ +extern bool +PrintError(JSContext *cx, FILE *file, const char *message, JSErrorReport *report, + bool reportWarnings); } /* namespace js */ extern void diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index dc46d2db408a..6903f42f923d 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -1193,7 +1193,7 @@ JS_GetObjectAsArrayBuffer(JSContext *cx, JSObject *obj, uint32_t *length, uint8_ * builds may be unable to assert when unwrapping should be disallowed. */ extern JS_FRIEND_API(JSArrayBufferViewType) -JS_GetTypedArrayType(JSObject *obj, JSContext *cx); +JS_GetTypedArrayType(JSObject *obj, JSContext *maybecx); /* * Check whether obj supports the JS_GetArrayBuffer* APIs. Note that this may @@ -1202,7 +1202,7 @@ JS_GetTypedArrayType(JSObject *obj, JSContext *cx); * accessor JSAPI calls defined below. */ extern JS_FRIEND_API(JSBool) -JS_IsArrayBufferObject(JSObject *obj, JSContext *cx); +JS_IsArrayBufferObject(JSObject *obj, JSContext *maybecx); /* * Return the available byte length of an array buffer. @@ -1213,11 +1213,12 @@ JS_IsArrayBufferObject(JSObject *obj, JSContext *cx); * builds may be unable to assert when unwrapping should be disallowed. */ extern JS_FRIEND_API(uint32_t) -JS_GetArrayBufferByteLength(JSObject *obj, JSContext *cx); +JS_GetArrayBufferByteLength(JSObject *obj, JSContext *maybecx); /* * Return a pointer to an array buffer's data. The buffer is still owned by the - * array buffer object, and should not be modified on another thread. + * array buffer object, and should not be modified on another thread. The + * returned pointer is stable across GCs. * * |obj| must have passed a JS_IsArrayBufferObject test, or somehow be known * that it would pass such a test: it is an ArrayBuffer or a wrapper of an @@ -1225,7 +1226,7 @@ JS_GetArrayBufferByteLength(JSObject *obj, JSContext *cx); * builds may be unable to assert when unwrapping should be disallowed. */ extern JS_FRIEND_API(uint8_t *) -JS_GetArrayBufferData(JSObject *obj, JSContext *cx); +JS_GetArrayBufferData(JSObject *obj, JSContext *maybecx); /* * Return the number of elements in a typed array. @@ -1287,30 +1288,30 @@ JS_GetArrayBufferViewByteLength(JSObject *obj, JSContext *cx); */ extern JS_FRIEND_API(int8_t *) -JS_GetInt8ArrayData(JSObject *obj, JSContext *cx); +JS_GetInt8ArrayData(JSObject *obj, JSContext *maybecx); extern JS_FRIEND_API(uint8_t *) -JS_GetUint8ArrayData(JSObject *obj, JSContext *cx); +JS_GetUint8ArrayData(JSObject *obj, JSContext *maybecx); extern JS_FRIEND_API(uint8_t *) -JS_GetUint8ClampedArrayData(JSObject *obj, JSContext *cx); +JS_GetUint8ClampedArrayData(JSObject *obj, JSContext *maybecx); extern JS_FRIEND_API(int16_t *) -JS_GetInt16ArrayData(JSObject *obj, JSContext *cx); +JS_GetInt16ArrayData(JSObject *obj, JSContext *maybecx); extern JS_FRIEND_API(uint16_t *) -JS_GetUint16ArrayData(JSObject *obj, JSContext *cx); +JS_GetUint16ArrayData(JSObject *obj, JSContext *maybecx); extern JS_FRIEND_API(int32_t *) -JS_GetInt32ArrayData(JSObject *obj, JSContext *cx); +JS_GetInt32ArrayData(JSObject *obj, JSContext *maybecx); extern JS_FRIEND_API(uint32_t *) -JS_GetUint32ArrayData(JSObject *obj, JSContext *cx); +JS_GetUint32ArrayData(JSObject *obj, JSContext *maybecx); extern JS_FRIEND_API(float *) -JS_GetFloat32ArrayData(JSObject *obj, JSContext *cx); +JS_GetFloat32ArrayData(JSObject *obj, JSContext *maybecx); extern JS_FRIEND_API(double *) -JS_GetFloat64ArrayData(JSObject *obj, JSContext *cx); +JS_GetFloat64ArrayData(JSObject *obj, JSContext *maybecx); /* * Same as above, but for any kind of ArrayBufferView. Prefer the type-specific * versions when possible. */ extern JS_FRIEND_API(void *) -JS_GetArrayBufferViewData(JSObject *obj, JSContext *cx); +JS_GetArrayBufferViewData(JSObject *obj, JSContext *maybecx); /* * Check whether obj supports JS_GetDataView* APIs. Note that this may fail and @@ -1330,7 +1331,7 @@ JS_IsDataViewObject(JSContext *cx, JSObject *obj, JSBool *isDataView); * unable to assert when unwrapping should be disallowed. */ JS_FRIEND_API(uint32_t) -JS_GetDataViewByteOffset(JSObject *obj, JSContext *cx); +JS_GetDataViewByteOffset(JSObject *obj, JSContext *maybecx); /* * Return the byte length of a data view. @@ -1341,7 +1342,7 @@ JS_GetDataViewByteOffset(JSObject *obj, JSContext *cx); * unable to assert when unwrapping should be disallowed. */ JS_FRIEND_API(uint32_t) -JS_GetDataViewByteLength(JSObject *obj, JSContext *cx); +JS_GetDataViewByteLength(JSObject *obj, JSContext *maybecx); /* * Return a pointer to the beginning of the data referenced by a DataView. @@ -1352,7 +1353,7 @@ JS_GetDataViewByteLength(JSObject *obj, JSContext *cx); * unable to assert when unwrapping should be disallowed. */ JS_FRIEND_API(void *) -JS_GetDataViewData(JSObject *obj, JSContext *cx); +JS_GetDataViewData(JSObject *obj, JSContext *maybecx); #ifdef __cplusplus /* diff --git a/js/src/jsobj.h b/js/src/jsobj.h index ad120184aeda..6af5e0699353 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -558,7 +558,7 @@ struct JSObject : public js::ObjectImpl inline bool ensureElements(JSContext *cx, unsigned cap); bool growElements(JSContext *cx, unsigned cap); void shrinkElements(JSContext *cx, unsigned cap); - + inline void setDynamicElements(js::ObjectElements *header); /* * Array-specific getters and setters (for both dense and slow arrays). diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 62538c6030a8..6c72d9d96eea 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -415,6 +415,14 @@ JSObject::ensureElements(JSContext *cx, uint32_t capacity) return true; } +inline void +JSObject::setDynamicElements(js::ObjectElements *header) +{ + JS_ASSERT(!hasDynamicElements()); + elements = header->elements(); + JS_ASSERT(hasDynamicElements()); +} + inline void JSObject::setDenseArrayElement(unsigned idx, const js::Value &val) { diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index 3507755c7051..13ef72790092 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -5968,7 +5968,7 @@ ExpressionDecompiler::decompilePC(jsbytecode *pc) else return write("[") && quote(prop, '\'') && - write("]") >= 0; + write("]"); return true; } case JSOP_GETELEM: @@ -6024,7 +6024,7 @@ ExpressionDecompiler::decompilePC(jsbytecode *pc) return write(js_this_str); case JSOP_CALL: case JSOP_FUNCALL: - return decompilePC(pcstack[-(GET_ARGC(pc) + 2)]) && + return decompilePC(pcstack[-int32_t(GET_ARGC(pc) + 2)]) && write("(...)"); default: break; @@ -6192,13 +6192,13 @@ DecompileExpressionFromStack(JSContext *cx, int spindex, int skipStackHits, Valu if (!valuepc) return true; - ExpressionDecompiler ea(cx, script, fun); - if (!ea.init()) + ExpressionDecompiler ed(cx, script, fun); + if (!ed.init()) return false; - if (!ea.decompilePC(valuepc)) + if (!ed.decompilePC(valuepc)) return false; - return ea.getOutput(res); + return ed.getOutput(res); } char * diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index a46b5fc885ea..2b8596ac1533 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -178,7 +178,7 @@ XDRScriptBindings(XDRState *xdr, LifoAllocScope &las, unsigned numArgs, un } for (BindingIter bi(script->bindings); bi; bi++) { - uint8_t u8 = (uint8_t(bi->kind()) << 1) | bi->aliased(); + uint8_t u8 = (uint8_t(bi->kind()) << 1) | uint8_t(bi->aliased()); if (!xdr->codeUint8(&u8)) return false; } diff --git a/js/src/jstypedarray.cpp b/js/src/jstypedarray.cpp index 88122ae9af9a..6a8e7e86da16 100644 --- a/js/src/jstypedarray.cpp +++ b/js/src/jstypedarray.cpp @@ -202,8 +202,28 @@ ArrayBufferObject::class_constructor(JSContext *cx, unsigned argc, Value *vp) return true; } +/* + * Note that some callers are allowed to pass in a NULL cx, so we allocate with + * the cx if available and fall back to the runtime. + */ +static ObjectElements * +AllocateArrayBufferContents(JSContext *maybecx, uint32_t nbytes, uint8_t *contents) +{ + uint32_t size = nbytes + sizeof(ObjectElements); + ObjectElements *newheader = + static_cast(maybecx ? maybecx->calloc_(size) : OffTheBooks::calloc_(size)); + if (!newheader) { + if (maybecx) + js_ReportOutOfMemory(maybecx); + return NULL; + } + if (contents) + memcpy(newheader->elements(), contents, nbytes); + return newheader; +} + bool -ArrayBufferObject::allocateSlots(JSContext *cx, uint32_t size, uint8_t *contents) +ArrayBufferObject::allocateSlots(JSContext *maybecx, uint32_t bytes, uint8_t *contents) { /* * ArrayBufferObjects delegate added properties to another JSObject, so @@ -214,36 +234,133 @@ ArrayBufferObject::allocateSlots(JSContext *cx, uint32_t size, uint8_t *contents size_t usableSlots = ARRAYBUFFER_RESERVED_SLOTS - ObjectElements::VALUES_PER_HEADER; - if (size > sizeof(Value) * usableSlots) { - ObjectElements *newheader = (ObjectElements *)cx->calloc_(size + sizeof(ObjectElements)); - if (!newheader) + if (bytes > sizeof(Value) * usableSlots) { + ObjectElements *header = AllocateArrayBufferContents(maybecx, bytes, contents); + if (!header) return false; - elements = newheader->elements(); - if (contents) - memcpy(elements, contents, size); + elements = header->elements(); } else { elements = fixedElements(); if (contents) - memcpy(elements, contents, size); + memcpy(elements, contents, bytes); else - memset(elements, 0, size); + memset(elements, 0, bytes); } - ObjectElements *header = getElementsHeader(); - - /* - * Note that |bytes| may not be a multiple of |sizeof(Value)|, so - * |capacity * sizeof(Value)| may underestimate the size by up to - * |sizeof(Value) - 1| bytes. - */ - header->capacity = size / sizeof(Value); - header->initializedLength = 0; - header->length = size; - header->unused = 0; + setElementsHeader(getElementsHeader(), bytes); return true; } +static uint32_t +NextViewSlot(JSObject *obj) +{ + return obj->isTypedArray() ? TypedArray::FIELD_NEXT_VIEW : DataViewObject::NEXT_VIEW_SLOT; +} + +static JSObject * +NextView(JSObject *obj) +{ + return obj->getFixedSlot(NextViewSlot(obj)).toObjectOrNull(); +} + +static void +SetNextView(JSObject *obj, JSObject *view) +{ + return obj->setFixedSlot(NextViewSlot(obj), ObjectOrNullValue(view)); +} + +static JSObject ** +GetViewList(ArrayBufferObject *obj) +{ +#if USE_NEW_OBJECT_REPRESENTATION + // untested + return obj->getElementsHeader()->asArrayBufferElements().viewList(); +#else + // The list of views must be stored somewhere in the ArrayBufferObject, but + // the slots are already being used for the element storage and the private + // field is used for a delegate object. The ObjectElements header has space + // for it, but I don't want to mess around with adding unions to it with + // USE_NEW_OBJECT_REPRESENTATION pending, since it will solve this much + // more cleanly. + struct OldObjectRepresentationHack { + uint32_t capacity; + uint32_t initializedLength; + JSObject *views; + }; + return &reinterpret_cast(obj->getElementsHeader())->views; +#endif +} + +bool +ArrayBufferObject::uninlineData(JSContext *maybecx) +{ + if (hasDynamicElements()) + return true; + + // Grab out data before invalidating it + uint32_t bytes = byteLength(); + uintptr_t oldPointer = uintptr_t(dataPointer()); + JSObject *view = *GetViewList(this); + JSObject *viewListHead = view; + + ObjectElements *header = AllocateArrayBufferContents(maybecx, bytes, + reinterpret_cast(oldPointer)); + if (!header) + return false; + elements = header->elements(); + setElementsHeader(getElementsHeader(), bytes); + + // Update all views + uintptr_t newPointer = uintptr_t(dataPointer()); + while (view) { + uintptr_t newDataPtr = uintptr_t(view->getPrivate()) - oldPointer + newPointer; + view->setPrivate(reinterpret_cast(newDataPtr)); + view = NextView(view); + } + + // Restore the list of views + *GetViewList(this) = viewListHead; + + return true; +} + +void +ArrayBufferObject::addView(JSContext *cx, RawObject view) +{ + JSObject **views = GetViewList(this); + SetNextView(view, *views); + *views = view; +} + +void +ArrayBufferObject::removeFinalizedView(FreeOp *fop, RawObject view) +{ + JSObject **views = GetViewList(this); + + if (*views == view) { + *views = NextView(view); + return; + } + + /* + * We traverse this during finalization, but all views in the list are + * guaranteed to be valid. Any view that has already been finalized will + * have already been removed from the list. Anything left either has not + * been finalized yet, or is still alive. + */ + JSObject *next; + for (JSObject *linkObj = *views; true; linkObj = next) { + JS_ASSERT(linkObj); // Should always find view in the list + uint32_t linkObjSlot = NextViewSlot(linkObj); + next = linkObj->getFixedSlot(linkObjSlot).toObjectOrNull(); + if (next == view) { + linkObj->setFixedSlot(linkObjSlot, ObjectOrNullValue(NextView(next))); + return; + } + } +} + JSObject * ArrayBufferObject::create(JSContext *cx, uint32_t nbytes, uint8_t *contents) { @@ -263,8 +380,8 @@ ArrayBufferObject::create(JSContext *cx, uint32_t nbytes, uint8_t *contents) obj->setLastPropertyInfallible(empty); /* - * The first 8 bytes hold the length. - * The rest of it is a flat data store for the array buffer. + * The beginning stores an ObjectElements header structure holding the + * length. The rest of it is a flat data store for the array buffer. */ if (!obj->asArrayBuffer().allocateSlots(cx, nbytes, contents)) return NULL; @@ -318,6 +435,39 @@ ArrayBufferObject::createDataViewForThis(JSContext *cx, unsigned argc, Value *vp return CallNonGenericMethod(cx, args); } +bool +ArrayBufferObject::stealContents(JSContext *cx, JSObject *obj, void **contents) +{ + ArrayBufferObject &buffer = obj->asArrayBuffer(); + JSObject *views = *GetViewList(&buffer); + js::ObjectElements *header = js::ObjectElements::fromElements((js::HeapSlot*)buffer.dataPointer()); + if (buffer.hasDynamicElements()) { + *contents = header; + + buffer.setFixedElements(); + header = js::ObjectElements::fromElements((js::HeapSlot*)buffer.dataPointer()); + } else { + uint32_t length = buffer.byteLength(); + js::ObjectElements *newheader = + AllocateArrayBufferContents(cx, length, buffer.dataPointer()); + if (!newheader) { + js_ReportOutOfMemory(cx); + return false; + } + + ArrayBufferObject::setElementsHeader(newheader, length); + *contents = newheader; + } + + // Neuter the donor ArrayBuffer and all views of it + ArrayBufferObject::setElementsHeader(header, 0); + *GetViewList(&buffer) = views; + for (JSObject *view = views; view; view = NextView(view)) + TypedArray::neuter(cx, view); + + return true; +} + void ArrayBufferObject::obj_trace(JSTracer *trc, JSObject *obj) { @@ -704,6 +854,16 @@ js::IsDataView(JSObject* obj) return obj->isDataView(); } +void +TypedArray::neuter(JSContext *cx, RawObject tarray) +{ + JS_ASSERT(tarray->isTypedArray()); + tarray->setSlot(FIELD_LENGTH, Int32Value(0)); + tarray->setSlot(FIELD_BYTELENGTH, Int32Value(0)); + tarray->setSlot(FIELD_BYTEOFFSET, Int32Value(0)); + tarray->setPrivate(NULL); +} + JSBool TypedArray::obj_lookupGeneric(JSContext *cx, HandleObject tarray, HandleId id, MutableHandleObject objp, MutableHandleShape propp) @@ -916,6 +1076,15 @@ class TypedArrayTemplate return v.isObject() && v.toObject().hasClass(fastClass()); } + static void + obj_finalize(FreeOp *fop, JSObject *obj) + { + JS_ASSERT(obj->hasClass(fastClass())); + JSObject *bufobj = buffer(obj); + if (!JS_IsAboutToBeFinalized(bufobj)) + bufobj->asArrayBuffer().removeFinalizedView(fop, obj); + } + static void obj_trace(JSTracer *trc, JSObject *obj) { @@ -1244,10 +1413,10 @@ class TypedArrayTemplate makeInstance(JSContext *cx, HandleObject bufobj, uint32_t byteOffset, uint32_t len, HandleObject proto) { - RootedObject obj(cx, NewBuiltinClassInstance(cx, protoClass())); + RootedObject obj(cx, NewBuiltinClassInstance(cx, fastClass())); if (!obj) return NULL; - JS_ASSERT(obj->getAllocKind() == gc::FINALIZE_OBJECT8_BACKGROUND); + JS_ASSERT(obj->getAllocKind() == gc::FINALIZE_OBJECT8); if (proto) { types::TypeObject *type = proto->getNewType(cx); @@ -1278,9 +1447,14 @@ class TypedArrayTemplate obj->setSlot(FIELD_LENGTH, Int32Value(len)); obj->setSlot(FIELD_BYTEOFFSET, Int32Value(byteOffset)); obj->setSlot(FIELD_BYTELENGTH, Int32Value(len * sizeof(NativeType))); + obj->setSlot(FIELD_NEXT_VIEW, NullValue()); - JS_ASSERT(obj->getClass() == protoClass()); - + // Mark the object as non-extensible. We cannot simply call + // obj->preventExtensions() because that has to iterate through all + // properties, and on long arrays that is much too slow. We could + // initialize the length fields to zero to avoid that, but then it + // would just boil down to a slightly slower wrapper around the + // following code anyway: js::Shape *empty = EmptyShape::getInitialShape(cx, fastClass(), obj->getProto(), obj->getParent(), gc::FINALIZE_OBJECT8, @@ -1300,6 +1474,8 @@ class TypedArrayTemplate JS_ASSERT(obj->numFixedSlots() == NUM_FIXED_SLOTS); #endif + buffer->addView(cx, obj); + return obj; } @@ -1726,8 +1902,11 @@ class TypedArrayTemplate fromArray(JSContext *cx, HandleObject other) { uint32_t len; - if (!GetLengthProperty(cx, other, &len)) + if (other->isTypedArray()) { + len = length(other); + } else if (!GetLengthProperty(cx, other, &len)) { return NULL; + } RootedObject bufobj(cx, createBufferWithSizeAndCount(cx, len)); if (!bufobj) @@ -1821,6 +2000,9 @@ class TypedArrayTemplate JS_ASSERT(thisTypedArrayObj->isTypedArray()); JS_ASSERT(offset <= length(thisTypedArrayObj)); JS_ASSERT(len <= length(thisTypedArrayObj) - offset); + if (ar->isTypedArray()) + return copyFromTypedArray(cx, thisTypedArrayObj, ar, offset); + NativeType *dest = static_cast(viewData(thisTypedArrayObj)) + offset; SkipRoot skip(cx, &dest); @@ -2258,6 +2440,14 @@ DataViewObject::class_constructor(JSContext *cx, unsigned argc, Value *vp) return construct(cx, bufobj, args, NULL); } +/* static */ void +DataViewObject::obj_finalize(FreeOp *fop, JSObject *obj) +{ + DataViewObject &view = obj->asDataView(); + if (view.hasBuffer() && !JS_IsAboutToBeFinalized(&view.arrayBuffer())) + view.arrayBuffer().removeFinalizedView(fop, &view); +} + /* static */ bool DataViewObject::getDataPointer(JSContext *cx, Handle obj, CallArgs args, size_t typeSize, uint8_t **data) @@ -2956,7 +3146,7 @@ IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float64, double, double) JS_EnumerateStub, \ JS_ResolveStub, \ JS_ConvertStub, \ - NULL, /* finalize */ \ + _typedArray::obj_finalize, \ NULL, /* checkAccess */ \ NULL, /* call */ \ NULL, /* construct */ \ @@ -3156,7 +3346,7 @@ Class js::DataViewClass = { JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, - NULL, /* finalize */ + DataViewObject::obj_finalize, NULL, /* checkAccess */ NULL, /* call */ NULL, /* construct */ @@ -3354,23 +3544,24 @@ JS_IsArrayBufferViewObject(JSObject *objArg, JSContext *cx) } JS_FRIEND_API(uint32_t) -JS_GetArrayBufferByteLength(JSObject *objArg, JSContext *cx) +JS_GetArrayBufferByteLength(JSObject *obj, JSContext *maybecx) { - RootedObject obj_(cx, objArg); - JSObject *obj = CheckedUnwrap(cx, obj_); + obj = CheckedUnwrap(maybecx, obj); if (!obj) return 0; return obj->asArrayBuffer().byteLength(); } JS_FRIEND_API(uint8_t *) -JS_GetArrayBufferData(JSObject *objArg, JSContext *cx) +JS_GetArrayBufferData(JSObject *obj, JSContext *maybecx) { - RootedObject obj_(cx, objArg); - JSObject *obj = CheckedUnwrap(cx, obj_); + obj = CheckedUnwrap(maybecx, obj); if (!obj) return NULL; - return obj->asArrayBuffer().dataPointer(); + ArrayBufferObject &buffer = obj->asArrayBuffer(); + if (!buffer.uninlineData(maybecx)) + return NULL; + return buffer.dataPointer(); } JS_FRIEND_API(JSObject *) @@ -3380,11 +3571,51 @@ JS_NewArrayBuffer(JSContext *cx, uint32_t nbytes) return ArrayBufferObject::create(cx, nbytes); } -JS_FRIEND_API(uint32_t) -JS_GetTypedArrayLength(JSObject *objArg, JSContext *cx) +JS_PUBLIC_API(JSObject *) +JS_NewArrayBufferWithContents(JSContext *cx, void *contents) { - RootedObject obj_(cx, objArg); - JSObject *obj = CheckedUnwrap(cx, obj_); + if (!contents) + return NULL; + JSObject *obj = ArrayBufferObject::create(cx, 0); + obj->setDynamicElements(reinterpret_cast(contents)); + return obj; +} + +JS_PUBLIC_API(JSBool) +JS_AllocateArrayBufferContents(JSContext *cx, uint32_t nbytes, void **contents, uint8_t **data) +{ + js::ObjectElements *header = AllocateArrayBufferContents(cx, nbytes, NULL); + if (!header) + return false; + + ArrayBufferObject::setElementsHeader(header, nbytes); + + *contents = header; + *data = reinterpret_cast(header->elements()); + return true; +} + +JS_PUBLIC_API(JSBool) +JS_StealArrayBufferContents(JSContext *cx, JSObject *obj, void **contents) +{ + if (!(obj = UnwrapObjectChecked(cx, obj))) + return false; + + if (!obj->isArrayBuffer()) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TYPED_ARRAY_BAD_ARGS); + return false; + } + + if (!ArrayBufferObject::stealContents(cx, obj, contents)) + return false; + + return true; +} + +JS_FRIEND_API(uint32_t) +JS_GetTypedArrayLength(JSObject *obj, JSContext *maybecx) +{ + obj = CheckedUnwrap(maybecx, obj); if (!obj) return 0; JS_ASSERT(obj->isTypedArray()); @@ -3392,10 +3623,9 @@ JS_GetTypedArrayLength(JSObject *objArg, JSContext *cx) } JS_FRIEND_API(uint32_t) -JS_GetTypedArrayByteOffset(JSObject *objArg, JSContext *cx) +JS_GetTypedArrayByteOffset(JSObject *obj, JSContext *maybecx) { - RootedObject obj_(cx, objArg); - JSObject *obj = CheckedUnwrap(cx, obj_); + obj = CheckedUnwrap(maybecx, obj); if (!obj) return 0; JS_ASSERT(obj->isTypedArray()); @@ -3403,10 +3633,9 @@ JS_GetTypedArrayByteOffset(JSObject *objArg, JSContext *cx) } JS_FRIEND_API(uint32_t) -JS_GetTypedArrayByteLength(JSObject *objArg, JSContext *cx) +JS_GetTypedArrayByteLength(JSObject *obj, JSContext *maybecx) { - RootedObject obj_(cx, objArg); - JSObject *obj = CheckedUnwrap(cx, obj_); + obj = CheckedUnwrap(maybecx, obj); if (!obj) return 0; JS_ASSERT(obj->isTypedArray()); @@ -3414,10 +3643,9 @@ JS_GetTypedArrayByteLength(JSObject *objArg, JSContext *cx) } JS_FRIEND_API(JSArrayBufferViewType) -JS_GetTypedArrayType(JSObject *objArg, JSContext *cx) +JS_GetTypedArrayType(JSObject *obj, JSContext *maybecx) { - RootedObject obj_(cx, objArg); - JSObject *obj = CheckedUnwrap(cx, obj_); + obj = CheckedUnwrap(maybecx, obj); if (!obj) return ArrayBufferView::TYPE_MAX; JS_ASSERT(obj->isTypedArray()); @@ -3425,10 +3653,9 @@ JS_GetTypedArrayType(JSObject *objArg, JSContext *cx) } JS_FRIEND_API(int8_t *) -JS_GetInt8ArrayData(JSObject *objArg, JSContext *cx) +JS_GetInt8ArrayData(JSObject *obj, JSContext *maybecx) { - RootedObject obj_(cx, objArg); - JSObject *obj = CheckedUnwrap(cx, obj_); + obj = CheckedUnwrap(maybecx, obj); if (!obj) return NULL; JS_ASSERT(obj->isTypedArray()); @@ -3437,10 +3664,9 @@ JS_GetInt8ArrayData(JSObject *objArg, JSContext *cx) } JS_FRIEND_API(uint8_t *) -JS_GetUint8ArrayData(JSObject *objArg, JSContext *cx) +JS_GetUint8ArrayData(JSObject *obj, JSContext *maybecx) { - RootedObject obj_(cx, objArg); - JSObject *obj = CheckedUnwrap(cx, obj_); + obj = CheckedUnwrap(maybecx, obj); if (!obj) return NULL; JS_ASSERT(obj->isTypedArray()); @@ -3449,10 +3675,9 @@ JS_GetUint8ArrayData(JSObject *objArg, JSContext *cx) } JS_FRIEND_API(uint8_t *) -JS_GetUint8ClampedArrayData(JSObject *objArg, JSContext *cx) +JS_GetUint8ClampedArrayData(JSObject *obj, JSContext *maybecx) { - RootedObject obj_(cx, objArg); - JSObject *obj = CheckedUnwrap(cx, obj_); + obj = CheckedUnwrap(maybecx, obj); if (!obj) return NULL; JS_ASSERT(obj->isTypedArray()); @@ -3461,10 +3686,9 @@ JS_GetUint8ClampedArrayData(JSObject *objArg, JSContext *cx) } JS_FRIEND_API(int16_t *) -JS_GetInt16ArrayData(JSObject *objArg, JSContext *cx) +JS_GetInt16ArrayData(JSObject *obj, JSContext *maybecx) { - RootedObject obj_(cx, objArg); - JSObject *obj = CheckedUnwrap(cx, obj_); + obj = CheckedUnwrap(maybecx, obj); if (!obj) return NULL; JS_ASSERT(obj->isTypedArray()); @@ -3473,10 +3697,9 @@ JS_GetInt16ArrayData(JSObject *objArg, JSContext *cx) } JS_FRIEND_API(uint16_t *) -JS_GetUint16ArrayData(JSObject *objArg, JSContext *cx) +JS_GetUint16ArrayData(JSObject *obj, JSContext *maybecx) { - RootedObject obj_(cx, objArg); - JSObject *obj = CheckedUnwrap(cx, obj_); + obj = CheckedUnwrap(maybecx, obj); if (!obj) return NULL; JS_ASSERT(obj->isTypedArray()); @@ -3485,10 +3708,9 @@ JS_GetUint16ArrayData(JSObject *objArg, JSContext *cx) } JS_FRIEND_API(int32_t *) -JS_GetInt32ArrayData(JSObject *objArg, JSContext *cx) +JS_GetInt32ArrayData(JSObject *obj, JSContext *maybecx) { - RootedObject obj_(cx, objArg); - JSObject *obj = CheckedUnwrap(cx, obj_); + obj = CheckedUnwrap(maybecx, obj); if (!obj) return NULL; JS_ASSERT(obj->isTypedArray()); @@ -3497,10 +3719,9 @@ JS_GetInt32ArrayData(JSObject *objArg, JSContext *cx) } JS_FRIEND_API(uint32_t *) -JS_GetUint32ArrayData(JSObject *objArg, JSContext *cx) +JS_GetUint32ArrayData(JSObject *obj, JSContext *maybecx) { - RootedObject obj_(cx, objArg); - JSObject *obj = CheckedUnwrap(cx, obj_); + obj = CheckedUnwrap(maybecx, obj); if (!obj) return NULL; JS_ASSERT(obj->isTypedArray()); @@ -3509,10 +3730,9 @@ JS_GetUint32ArrayData(JSObject *objArg, JSContext *cx) } JS_FRIEND_API(float *) -JS_GetFloat32ArrayData(JSObject *objArg, JSContext *cx) +JS_GetFloat32ArrayData(JSObject *obj, JSContext *maybecx) { - RootedObject obj_(cx, objArg); - JSObject *obj = CheckedUnwrap(cx, obj_); + obj = CheckedUnwrap(maybecx, obj); if (!obj) return NULL; JS_ASSERT(obj->isTypedArray()); @@ -3521,10 +3741,9 @@ JS_GetFloat32ArrayData(JSObject *objArg, JSContext *cx) } JS_FRIEND_API(double *) -JS_GetFloat64ArrayData(JSObject *objArg, JSContext *cx) +JS_GetFloat64ArrayData(JSObject *obj, JSContext *maybecx) { - RootedObject obj_(cx, objArg); - JSObject *obj = CheckedUnwrap(cx, obj_); + obj = CheckedUnwrap(maybecx, obj); if (!obj) return NULL; JS_ASSERT(obj->isTypedArray()); @@ -3544,20 +3763,18 @@ JS_IsDataViewObject(JSContext *cx, JSObject *objArg, JSBool *isDataView) } JS_FRIEND_API(uint32_t) -JS_GetDataViewByteOffset(JSObject *objArg, JSContext *cx) +JS_GetDataViewByteOffset(JSObject *obj, JSContext *maybecx) { - RootedObject obj_(cx, objArg); - JSObject *obj = CheckedUnwrap(cx, obj_); + obj = CheckedUnwrap(maybecx, obj); if (!obj) return 0; return obj->asDataView().byteOffset(); } JS_FRIEND_API(void *) -JS_GetDataViewData(JSObject *objArg, JSContext *cx) +JS_GetDataViewData(JSObject *obj, JSContext *maybecx) { - RootedObject obj_(cx, objArg); - JSObject *obj = CheckedUnwrap(cx, obj_); + obj = CheckedUnwrap(maybecx, obj); if (!obj) return NULL; JS_ASSERT(obj->isDataView()); @@ -3565,10 +3782,9 @@ JS_GetDataViewData(JSObject *objArg, JSContext *cx) } JS_FRIEND_API(uint32_t) -JS_GetDataViewByteLength(JSObject *objArg, JSContext *cx) +JS_GetDataViewByteLength(JSObject *obj, JSContext *maybecx) { - RootedObject obj_(cx, objArg); - JSObject *obj = CheckedUnwrap(cx, obj_); + obj = CheckedUnwrap(maybecx, obj); if (!obj) return 0; JS_ASSERT(obj->isDataView()); @@ -3576,10 +3792,9 @@ JS_GetDataViewByteLength(JSObject *objArg, JSContext *cx) } JS_FRIEND_API(void *) -JS_GetArrayBufferViewData(JSObject *objArg, JSContext *cx) +JS_GetArrayBufferViewData(JSObject *obj, JSContext *maybecx) { - RootedObject obj_(cx, objArg); - JSObject *obj = CheckedUnwrap(cx, obj_); + obj = CheckedUnwrap(maybecx, obj); if (!obj) return NULL; JS_ASSERT(obj->isTypedArray() || obj->isDataView()); @@ -3587,10 +3802,9 @@ JS_GetArrayBufferViewData(JSObject *objArg, JSContext *cx) } JS_FRIEND_API(uint32_t) -JS_GetArrayBufferViewByteLength(JSObject *objArg, JSContext *cx) +JS_GetArrayBufferViewByteLength(JSObject *obj, JSContext *maybecx) { - RootedObject obj_(cx, objArg); - JSObject *obj = CheckedUnwrap(cx, obj_); + obj = CheckedUnwrap(maybecx, obj); if (!obj) return 0; JS_ASSERT(obj->isTypedArray() || obj->isDataView()); diff --git a/js/src/jstypedarray.h b/js/src/jstypedarray.h index 707fc0294637..78e6dfe6dd1f 100644 --- a/js/src/jstypedarray.h +++ b/js/src/jstypedarray.h @@ -142,9 +142,28 @@ class ArrayBufferObject : public JSObject static JSType obj_typeOf(JSContext *cx, HandleObject obj); + static bool + stealContents(JSContext *cx, JSObject *obj, void **contents); + + static inline void + setElementsHeader(js::ObjectElements *header, uint32_t bytes); + + void + addView(JSContext *cx, RawObject view); + + void + removeFinalizedView(FreeOp *fop, RawObject view); + bool allocateSlots(JSContext *cx, uint32_t size, uint8_t *contents = NULL); + /* + * Ensure that the data is not stored inline. Used when handing back a + * GC-safe pointer. + */ + bool + uninlineData(JSContext *cx); + inline uint32_t byteLength() const; inline uint8_t * dataPointer() const; @@ -192,6 +211,7 @@ struct TypedArray { FIELD_BYTELENGTH, FIELD_TYPE, FIELD_BUFFER, + FIELD_NEXT_VIEW, FIELD_MAX, NUM_FIXED_SLOTS = 7 }; @@ -239,6 +259,9 @@ struct TypedArray { static bool isArrayIndex(JSContext *cx, JSObject *obj, jsid id, uint32_t *ip = NULL); + static void + neuter(JSContext *cx, RawObject tarray); + static inline uint32_t slotWidth(int atype); static inline int slotWidth(JSObject *obj); @@ -280,11 +303,14 @@ IsTypedArrayProto(JSObject *obj) class DataViewObject : public JSObject { - static Class protoClass; - +public: static const size_t BYTEOFFSET_SLOT = 0; static const size_t BYTELENGTH_SLOT = 1; static const size_t BUFFER_SLOT = 2; + static const size_t NEXT_VIEW_SLOT = 3; + +private: + static Class protoClass; static inline bool is(const Value &v); @@ -301,7 +327,9 @@ class DataViewObject : public JSObject defineGetter(JSContext *cx, PropertyName *name, HandleObject proto); public: - static const size_t RESERVED_SLOTS = 3; + // 4 slots + 1 private = 5, which gets rounded up to FINALIZE_OBJECT8, + // which is 7 non-private + static const size_t RESERVED_SLOTS = 7; static inline Value bufferValue(DataViewObject &view); static inline Value byteOffsetValue(DataViewObject &view); @@ -363,9 +391,12 @@ class DataViewObject : public JSObject static bool setFloat64Impl(JSContext *cx, CallArgs args); static JSBool fun_setFloat64(JSContext *cx, unsigned argc, Value *vp); + static void + obj_finalize(FreeOp *fop, JSObject *obj); + inline uint32_t byteLength(); inline uint32_t byteOffset(); - inline JSObject & arrayBuffer(); + inline ArrayBufferObject & arrayBuffer(); inline void *dataPointer(); inline bool hasBuffer() const; static JSObject *initClass(JSContext *cx); diff --git a/js/src/jstypedarrayinlines.h b/js/src/jstypedarrayinlines.h index 33d9921c48a7..ddc7512a0426 100644 --- a/js/src/jstypedarrayinlines.h +++ b/js/src/jstypedarrayinlines.h @@ -13,11 +13,25 @@ #include "jsobjinlines.h" +inline void +js::ArrayBufferObject::setElementsHeader(js::ObjectElements *header, uint32_t bytes) +{ + /* + * Note that |bytes| may not be a multiple of |sizeof(Value)|, so + * |capacity * sizeof(Value)| may underestimate the size by up to + * |sizeof(Value) - 1| bytes. + */ + header->capacity = bytes / sizeof(js::Value); + header->initializedLength = bytes; + header->length = 0; + header->unused = 0; +} + inline uint32_t js::ArrayBufferObject::byteLength() const { JS_ASSERT(isArrayBuffer()); - return getElementsHeader()->length; + return getElementsHeader()->initializedLength; } inline uint8_t * @@ -231,6 +245,7 @@ DataViewObject::create(JSContext *cx, uint32_t byteOffset, uint32_t byteLength, dvobj.setFixedSlot(BYTEOFFSET_SLOT, Int32Value(byteOffset)); dvobj.setFixedSlot(BYTELENGTH_SLOT, Int32Value(byteLength)); dvobj.setFixedSlot(BUFFER_SLOT, ObjectValue(*arrayBuffer)); + dvobj.setFixedSlot(NEXT_VIEW_SLOT, NullValue()); InitTypedArrayDataPointer(obj, arrayBuffer, byteOffset); JS_ASSERT(byteOffset + byteLength <= arrayBuffer->byteLength()); @@ -264,11 +279,11 @@ DataViewObject::dataPointer() return getPrivate(); } -inline JSObject & +inline ArrayBufferObject & DataViewObject::arrayBuffer() { JS_ASSERT(isDataView()); - return getReservedSlot(BUFFER_SLOT).toObject(); + return getReservedSlot(BUFFER_SLOT).toObject().asArrayBuffer(); } inline bool diff --git a/js/src/jswrapper.cpp b/js/src/jswrapper.cpp index 28af05ece792..4c6c324c3eac 100644 --- a/js/src/jswrapper.cpp +++ b/js/src/jswrapper.cpp @@ -96,8 +96,9 @@ js::UnwrapObject(JSObject *wrapped, bool stopAtOuter, unsigned *flagsp) } JS_FRIEND_API(JSObject *) -js::UnwrapObjectChecked(JSContext *cx, JSObject *obj) +js::UnwrapObjectChecked(JSContext *cx, RawObject objArg) { + RootedObject obj(cx, objArg); while (true) { JSObject *wrapper = obj; obj = UnwrapOneChecked(cx, obj); @@ -107,7 +108,7 @@ js::UnwrapObjectChecked(JSContext *cx, JSObject *obj) } JS_FRIEND_API(JSObject *) -js::UnwrapOneChecked(JSContext *cx, JSObject *obj) +js::UnwrapOneChecked(JSContext *cx, HandleObject obj) { // Checked unwraps should never unwrap outer windows. if (!obj->isWrapper() || @@ -118,15 +119,12 @@ js::UnwrapOneChecked(JSContext *cx, JSObject *obj) Wrapper *handler = Wrapper::wrapperHandler(obj); bool rvOnFailure; - if (!handler->enter(cx, obj, JSID_VOID, - Wrapper::PUNCTURE, &rvOnFailure)) - { - return rvOnFailure ? obj : NULL; - } - obj = Wrapper::wrappedObject(obj); - JS_ASSERT(obj); + if (!handler->enter(cx, obj, JSID_VOID, Wrapper::PUNCTURE, &rvOnFailure)) + return rvOnFailure ? (JSObject*) obj : NULL; + JSObject *ret = Wrapper::wrappedObject(obj); + JS_ASSERT(ret); - return obj; + return ret; } bool diff --git a/js/src/jswrapper.h b/js/src/jswrapper.h index 146f258fa660..388166178e3a 100644 --- a/js/src/jswrapper.h +++ b/js/src/jswrapper.h @@ -345,12 +345,12 @@ UnwrapObject(JSObject *obj, bool stopAtOuter = true, unsigned *flagsp = NULL); // code should never be unwrapping outer window wrappers, we always stop at // outer windows. JS_FRIEND_API(JSObject *) -UnwrapObjectChecked(JSContext *cx, JSObject *obj); +UnwrapObjectChecked(JSContext *cx, RawObject obj); // Unwrap only the outermost security wrapper, with the same semantics as // above. This is the checked version of Wrapper::wrappedObject. JS_FRIEND_API(JSObject *) -UnwrapOneChecked(JSContext *cx, JSObject *obj); +UnwrapOneChecked(JSContext *cx, HandleObject obj); JS_FRIEND_API(bool) IsCrossCompartmentWrapper(RawObject obj); diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index d6c0c0eff2eb..349bb61e250e 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -4269,78 +4269,7 @@ my_GetErrorMessage(void *userRef, const char *locale, const unsigned errorNumber static void my_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report) { - int i, j, k, n; - char *prefix, *tmp; - const char *ctmp; - - if (!report) { - fprintf(gErrFile, "%s\n", message); - fflush(gErrFile); - return; - } - - /* Conditionally ignore reported warnings. */ - if (JSREPORT_IS_WARNING(report->flags) && !reportWarnings) - return; - - gGotError = true; - - prefix = NULL; - if (report->filename) - prefix = JS_smprintf("%s:", report->filename); - if (report->lineno) { - tmp = prefix; - prefix = JS_smprintf("%s%u:%u ", tmp ? tmp : "", report->lineno, report->column); - JS_free(cx, tmp); - } - if (JSREPORT_IS_WARNING(report->flags)) { - tmp = prefix; - prefix = JS_smprintf("%s%swarning: ", - tmp ? tmp : "", - JSREPORT_IS_STRICT(report->flags) ? "strict " : ""); - JS_free(cx, tmp); - } - - /* embedded newlines -- argh! */ - while ((ctmp = strchr(message, '\n')) != 0) { - ctmp++; - if (prefix) - fputs(prefix, gErrFile); - fwrite(message, 1, ctmp - message, gErrFile); - message = ctmp; - } - - /* If there were no filename or lineno, the prefix might be empty */ - if (prefix) - fputs(prefix, gErrFile); - fputs(message, gErrFile); - - if (!report->linebuf) { - fputc('\n', gErrFile); - goto out; - } - - /* report->linebuf usually ends with a newline. */ - n = strlen(report->linebuf); - fprintf(gErrFile, ":\n%s%s%s%s", - prefix, - report->linebuf, - (n > 0 && report->linebuf[n-1] == '\n') ? "" : "\n", - prefix); - n = report->tokenptr - report->linebuf; - for (i = j = 0; i < n; i++) { - if (report->linebuf[i] == '\t') { - for (k = (j + 8) & ~7; j < k; j++) { - fputc('.', gErrFile); - } - continue; - } - fputc('.', gErrFile); - j++; - } - fputs("^\n", gErrFile); - out: - fflush(gErrFile); + gGotError = PrintError(cx, gErrFile, message, report, reportWarnings); if (!JSREPORT_IS_WARNING(report->flags)) { if (report->errorNumber == JSMSG_OUT_OF_MEMORY) { gExitCode = EXITCODE_OUT_OF_MEMORY; @@ -4348,7 +4277,6 @@ my_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report) gExitCode = EXITCODE_RUNTIME_ERROR; } } - JS_free(cx, prefix); } #if defined(SHELL_HACK) && defined(DEBUG) && defined(XP_UNIX) diff --git a/js/src/vm/ObjectImpl.cpp b/js/src/vm/ObjectImpl.cpp index d7a951e6db7c..5a5e57bbd19d 100644 --- a/js/src/vm/ObjectImpl.cpp +++ b/js/src/vm/ObjectImpl.cpp @@ -582,6 +582,73 @@ js::GetOwnElement(JSContext *cx, Handle obj, uint32_t index, unsign return false; } +bool +js::GetProperty(JSContext *cx, Handle obj, Handle receiver, + Handle pid, unsigned resolveFlags, MutableHandle vp) +{ + NEW_OBJECT_REPRESENTATION_ONLY(); + + MOZ_ASSERT(receiver); + + Rooted current(cx, obj); + + do { + MOZ_ASSERT(obj); + + if (Downcast(current)->isProxy()) { + MOZ_NOT_REACHED("NYI: proxy [[GetP]]"); + return false; + } + + PropDesc desc; + if (!GetOwnProperty(cx, current, pid, resolveFlags, &desc)) + return false; + + /* No property? Recur or bottom out. */ + if (desc.isUndefined()) { + current = current->getProto(); + if (current) + continue; + + vp.setUndefined(); + return true; + } + + /* If it's a data property, return the value. */ + if (desc.isDataDescriptor()) { + vp.set(desc.value()); + return true; + } + + /* If it's an accessor property, call its [[Get]] with the receiver. */ + if (desc.isAccessorDescriptor()) { + Rooted get(cx, desc.getterValue()); + if (get.isUndefined()) { + vp.setUndefined(); + return true; + } + + InvokeArgsGuard args; + if (!cx->stack.pushInvokeArgs(cx, 0, &args)) + return false; + + args.setCallee(get); + args.setThis(ObjectValue(*receiver)); + + bool ok = Invoke(cx, args); + vp.set(args.rval()); + return ok; + } + + /* Otherwise it's a PropertyOp-based property. XXX handle this! */ + MOZ_NOT_REACHED("NYI: handle PropertyOp'd properties here"); + return false; + } while (false); + + MOZ_NOT_REACHED("buggy control flow"); + return false; +} + bool js::GetElement(JSContext *cx, Handle obj, Handle receiver, uint32_t index, unsigned resolveFlags, Value *vp) @@ -822,6 +889,8 @@ js::SetElement(JSContext *cx, Handle obj, Handle recei Rooted current(cx, obj); + MOZ_ASSERT(receiver); + do { MOZ_ASSERT(current); diff --git a/js/src/vm/ObjectImpl.h b/js/src/vm/ObjectImpl.h index 660133e01c84..0c97fdec1b09 100644 --- a/js/src/vm/ObjectImpl.h +++ b/js/src/vm/ObjectImpl.h @@ -359,6 +359,10 @@ class ElementsHeader friend class SparseElementsHeader; Shape * shape; } sparse; + class { + friend class ArrayBufferElementsHeader; + JSObject * views; + } buffer; }; void staticAsserts() { @@ -751,6 +755,8 @@ class ArrayBufferElementsHeader : public ElementsHeader bool setElement(JSContext *cx, Handle obj, Handle receiver, uint32_t index, const Value &v, unsigned resolveFlags, bool *succeeded); + JSObject **viewList() { return &buffer.views; } + private: inline bool isArrayBufferElements() const MOZ_DELETE; inline ArrayBufferElementsHeader & asArrayBufferElements() MOZ_DELETE; @@ -1357,6 +1363,23 @@ GetOwnProperty(JSContext *cx, Handle obj, Handle sid, un extern bool GetElement(JSContext *cx, Handle obj, Handle receiver, uint32_t index, unsigned resolveFlags, Value *vp); +extern bool +GetProperty(JSContext *cx, Handle obj, Handle receiver, + Handle pid, unsigned resolveFlags, MutableHandle vp); +inline bool +GetProperty(JSContext *cx, Handle obj, Handle receiver, + Handle name, unsigned resolveFlags, MutableHandle vp) +{ + Rooted pid(cx, PropertyId(name)); + return GetProperty(cx, obj, receiver, pid, resolveFlags, vp); +} +inline bool +GetProperty(JSContext *cx, Handle obj, Handle receiver, + Handle sid, unsigned resolveFlags, MutableHandle vp) +{ + Rooted pid(cx, PropertyId(sid)); + return GetProperty(cx, obj, receiver, pid, resolveFlags, vp); +} extern bool DefineElement(JSContext *cx, Handle obj, uint32_t index, const PropDesc &desc, diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp index 3a142543173b..dffca52fac6d 100644 --- a/js/xpconnect/src/XPCComponents.cpp +++ b/js/xpconnect/src/XPCComponents.cpp @@ -2700,7 +2700,7 @@ nsXPCComponents_Utils::LookupMethod(const JS::Value& object, // first param must be a JSObject if (!object.isObject()) return NS_ERROR_XPC_BAD_CONVERT_JS; - JSObject *obj = &object.toObject(); + JS::RootedObject obj(cx, &object.toObject()); // second param must be a string. if (!JSVAL_IS_STRING(name)) diff --git a/layout/build/Makefile.in b/layout/build/Makefile.in index 7eb702311d57..f589fb16ad00 100644 --- a/layout/build/Makefile.in +++ b/layout/build/Makefile.in @@ -134,6 +134,7 @@ endif #} ifdef MOZ_MEDIA SHARED_LIBRARY_LIBS += \ $(DEPTH)/content/media/$(LIB_PREFIX)gkconmedia_s.$(LIB_SUFFIX) \ + $(DEPTH)/content/media/webaudio/$(LIB_PREFIX)gkconwebaudio_s.$(LIB_SUFFIX) \ $(DEPTH)/content/media/webrtc/$(LIB_PREFIX)gkconwebrtc_s.$(LIB_SUFFIX) \ $(NULL) endif @@ -266,6 +267,7 @@ LOCAL_INCLUDES += -I$(srcdir)/../base \ -I$(topsrcdir)/caps/include \ -I$(topsrcdir)/netwerk/base/src \ -I$(topsrcdir)/content/svg/content/src \ + -I$(topsrcdir)/extensions/cookie \ $(NULL) ifdef MOZ_B2G_RIL #{ diff --git a/layout/build/nsContentDLF.cpp b/layout/build/nsContentDLF.cpp index 011e29963351..84dd80f6fa36 100644 --- a/layout/build/nsContentDLF.cpp +++ b/layout/build/nsContentDLF.cpp @@ -481,7 +481,7 @@ nsContentDLF::CreateXULDocument(const char* aCommand, } bool nsContentDLF::IsImageContentType(const char* aContentType) { - nsCOMPtr loader(do_GetService("@mozilla.org/image/loader;1")); + nsCOMPtr loader(do_CreateInstance("@mozilla.org/image/loader;1")); bool isDecoderAvailable = false; loader->SupportImageWithMimeType(aContentType, &isDecoderAvailable); return isDecoderAvailable; diff --git a/layout/build/nsLayoutStatics.cpp b/layout/build/nsLayoutStatics.cpp index 583d035afb9d..64308ef7eb8b 100644 --- a/layout/build/nsLayoutStatics.cpp +++ b/layout/build/nsLayoutStatics.cpp @@ -98,6 +98,7 @@ #include "nsWindowMemoryReporter.h" #include "mozilla/dom/ContentParent.h" #include "mozilla/dom/ipc/ProcessPriorityManager.h" +#include "nsPermissionManager.h" extern void NS_ShutdownChainItemPool(); @@ -252,6 +253,8 @@ nsLayoutStatics::Initialize() InitProcessPriorityManager(); + nsPermissionManager::AppUninstallObserverInit(); + return NS_OK; } diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp index 748107df0e45..6dfde2a2a9ee 100644 --- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -1786,8 +1786,8 @@ nsImageFrame::LoadIcon(const nsAString& aSpec, nsCOMPtr realURI; SpecToURI(aSpec, sIOService, getter_AddRefs(realURI)); - nsCOMPtr il(do_GetService("@mozilla.org/image/loader;1", &rv)); - if (NS_FAILED(rv)) return rv; + nsCOMPtr il = + nsContentUtils::GetImgLoaderForDocument(aPresContext->Document()); nsCOMPtr loadGroup; GetLoadGroup(aPresContext, getter_AddRefs(loadGroup)); diff --git a/layout/style/nsMediaFeatures.cpp b/layout/style/nsMediaFeatures.cpp index dd5f9dfd6596..d5741ea3cc0d 100644 --- a/layout/style/nsMediaFeatures.cpp +++ b/layout/style/nsMediaFeatures.cpp @@ -250,7 +250,15 @@ GetResolution(nsPresContext* aPresContext, const nsMediaFeature*, { // Resolution measures device pixels per CSS (inch/cm/pixel). We // return it in device pixels per CSS inches. - float dpi = float(nsPresContext::AppUnitsPerCSSInch()) / + // + // However, on platforms where the CSS viewport is not fixed to the + // screen viewport, use the device resolution instead (bug 779527). + nsIPresShell *shell = aPresContext->PresShell(); + float appUnitsPerInch = shell->GetIsViewportOverridden() ? + GetDeviceContextFor(aPresContext)->AppUnitsPerPhysicalInch() : + nsPresContext::AppUnitsPerCSSInch(); + + float dpi = appUnitsPerInch / float(aPresContext->AppUnitsPerDevPixel()); aResult.SetFloatValue(dpi, eCSSUnit_Inch); return NS_OK; diff --git a/layout/style/test/test_media_queries.html b/layout/style/test/test_media_queries.html index 55a6b8b7cb83..b620996c395d 100644 --- a/layout/style/test/test_media_queries.html +++ b/layout/style/test/test_media_queries.html @@ -487,7 +487,6 @@ function run() { var dpi_low = resolution - 1; if (query_applies("(min-resolution: " + resolution + "dpi)")) { // It's exact! - is(resolution % 96, 0, "resolution should be a multiple of 96dpi"); should_apply("(resolution: " + resolution + "dpi)"); should_apply("(resolution: " + Math.floor(resolution/96) + "dppx)"); should_not_apply("(resolution: " + (resolution + 1) + "dpi)"); @@ -496,7 +495,6 @@ function run() { } else { // We have no way to test resolution applying since it need not be // an integer. - ok(false, "resolution should be a multiple of 96dpi"); should_not_apply("(resolution: " + resolution + "dpi)"); should_not_apply("(resolution: " + (resolution - 1) + "dpi)"); dpi_high = resolution; diff --git a/layout/svg/base/src/nsSVGOuterSVGFrame.cpp b/layout/svg/base/src/nsSVGOuterSVGFrame.cpp index 3c6a2012a9d5..e654a50c5e50 100644 --- a/layout/svg/base/src/nsSVGOuterSVGFrame.cpp +++ b/layout/svg/base/src/nsSVGOuterSVGFrame.cpp @@ -726,7 +726,9 @@ nsSVGOuterSVGFrame::NotifyViewportOrTransformChanged(uint32_t aFlags) if (haveNonFulLZoomTransformChange && !(mState & NS_STATE_SVG_NONDISPLAY_CHILD)) { - content->ChildrenOnlyTransformChanged(); + PRUint32 flags = (mState & NS_FRAME_IN_REFLOW) ? + nsSVGSVGElement::eDuringReflow : 0; + content->ChildrenOnlyTransformChanged(flags); } } diff --git a/layout/svg/crashtests/767056-1.svg b/layout/svg/crashtests/767056-1.svg new file mode 100644 index 000000000000..b813d784b3a1 --- /dev/null +++ b/layout/svg/crashtests/767056-1.svg @@ -0,0 +1,21 @@ + + + + diff --git a/layout/svg/crashtests/crashtests.list b/layout/svg/crashtests/crashtests.list index 655ca915fab8..d8f2cd2d2c2d 100644 --- a/layout/svg/crashtests/crashtests.list +++ b/layout/svg/crashtests/crashtests.list @@ -130,6 +130,7 @@ load 740627-1.svg load 740627-2.svg load 757704-1.svg load 757718-1.svg +load 767056-1.svg load 768351.svg load 780963-1.html load 757751-1.svg diff --git a/mobile/android/base/BrowserApp.java b/mobile/android/base/BrowserApp.java index 9c20584819d7..f1227ec04d40 100644 --- a/mobile/android/base/BrowserApp.java +++ b/mobile/android/base/BrowserApp.java @@ -659,8 +659,12 @@ abstract public class BrowserApp extends GeckoApp try { URL url = new URL(icon); InputStream is = (InputStream) url.getContent(); - Drawable drawable = Drawable.createFromStream(is, "src"); - item.setIcon(drawable); + try { + Drawable drawable = Drawable.createFromStream(is, "src"); + item.setIcon(drawable); + } finally { + is.close(); + } } catch (Exception e) { Log.w(LOGTAG, "Unable to set icon", e); } diff --git a/mobile/android/base/BrowserToolbarBackground.java b/mobile/android/base/BrowserToolbarBackground.java new file mode 100644 index 000000000000..5e9823a5cf9b --- /dev/null +++ b/mobile/android/base/BrowserToolbarBackground.java @@ -0,0 +1,53 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.gecko; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Path; +import android.graphics.PorterDuff.Mode; +import android.util.AttributeSet; +import android.widget.LinearLayout; + +public class BrowserToolbarBackground extends LinearLayout + implements CanvasDelegate.DrawManager { + Path mPath; + CanvasDelegate mCanvasDelegate; + + public BrowserToolbarBackground(Context context, AttributeSet attrs) { + super(context, attrs); + + // Path is clipped. + mPath = new Path(); + mCanvasDelegate = new CanvasDelegate(this, Mode.DST_OUT); + } + + @Override + public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + int width = getMeasuredWidth(); + int height = getMeasuredHeight(); + float curve = height * 1.125f; + + mPath.reset(); + mPath.moveTo(width, height); + mPath.cubicTo((width - (curve * 0.75f)), height, + (width - (curve * 0.25f)), 0, + (width - curve), 0); + mPath.lineTo(width, 0); + mPath.lineTo(width, height); + } + + @Override + public void draw(Canvas canvas) { + mCanvasDelegate.draw(canvas, mPath, getWidth(), getHeight()); + } + + @Override + public void defaultDraw(Canvas canvas) { + super.draw(canvas); + } +} diff --git a/mobile/android/base/CanvasDelegate.java b/mobile/android/base/CanvasDelegate.java new file mode 100644 index 000000000000..7f8254fbcbfa --- /dev/null +++ b/mobile/android/base/CanvasDelegate.java @@ -0,0 +1,69 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.gecko; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PorterDuffXfermode; +import android.graphics.PorterDuff.Mode; +import android.os.Build; + +public class CanvasDelegate { + Paint mPaint; + PorterDuffXfermode mMode; + DrawManager mDrawManager; + + // DrawManager would do a default draw of the background. + public static interface DrawManager { + public void defaultDraw(Canvas cavas); + } + + public CanvasDelegate(DrawManager drawManager, Mode mode) { + mDrawManager = drawManager; + + // DST_IN masks, DST_OUT clips. + mMode = new PorterDuffXfermode(mode); + + mPaint = new Paint(); + mPaint.setAntiAlias(true); + mPaint.setColor(0xFFFF0000); + } + + public void draw(Canvas canvas, Path path, int width, int height) { + // Save the canvas. All PorterDuff operations should be done in a offscreen bitmap. + int count = canvas.saveLayer(0, 0, width, height, null, + Canvas.MATRIX_SAVE_FLAG | + Canvas.CLIP_SAVE_FLAG | + Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | + Canvas.FULL_COLOR_LAYER_SAVE_FLAG | + Canvas.CLIP_TO_LAYER_SAVE_FLAG); + + // Do a default draw. + mDrawManager.defaultDraw(canvas); + + if (path != null && !path.isEmpty()) { + // ICS added double-buffering, which made it easier for drawing the Path directly over the DST. + // In pre-ICS, drawPath() doesn't seem to use ARGB_8888 mode for performance, hence transparency is not preserved. + if (Build.VERSION.SDK_INT >= 14) { + mPaint.setXfermode(mMode); + canvas.drawPath(path, mPaint); + } else { + // Allocate a bitmap and draw the masking/clipping path. + Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + (new Canvas(bitmap)).drawPath(path, mPaint); + + mPaint.setXfermode(mMode); + canvas.drawBitmap(bitmap, 0, 0, mPaint); + + mPaint.setXfermode(null); + } + } + + // Restore the canvas. + canvas.restoreToCount(count); + } +} diff --git a/mobile/android/base/GeckoApp.java b/mobile/android/base/GeckoApp.java index ad10c243ce55..8752c3c617cc 100644 --- a/mobile/android/base/GeckoApp.java +++ b/mobile/android/base/GeckoApp.java @@ -694,17 +694,18 @@ abstract public class GeckoApp @Override public void onPostExecute(String faviconUrl) { + JSONObject args = new JSONObject(); + if (faviconUrl != null) { - JSONObject args = new JSONObject(); try { args.put("url", url); args.put("faviconUrl", faviconUrl); } catch (JSONException e) { Log.e(LOGTAG, "error building json arguments"); } - - GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Reader:FaviconReturn", args.toString())); } + + GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Reader:FaviconReturn", args.toString())); } }).execute(); } diff --git a/mobile/android/base/GeckoViewsFactory.java b/mobile/android/base/GeckoViewsFactory.java index 7b0350a46058..71245dfbdd9c 100644 --- a/mobile/android/base/GeckoViewsFactory.java +++ b/mobile/android/base/GeckoViewsFactory.java @@ -44,14 +44,22 @@ public final class GeckoViewsFactory implements LayoutInflater.Factory { return new AboutHomeSection(context, attrs); else if (TextUtils.equals(viewName, "AwesomeBarTabs")) return new AwesomeBarTabs(context, attrs); + else if (TextUtils.equals(viewName, "BrowserToolbarBackground")) + return new BrowserToolbarBackground(context, attrs); else if (TextUtils.equals(viewName, "FormAssistPopup")) return new FormAssistPopup(context, attrs); else if (TextUtils.equals(viewName, "LinkTextView")) return new LinkTextView(context, attrs); else if (TextUtils.equals(viewName, "FindInPageBar")) return new FindInPageBar(context, attrs); + else if (TextUtils.equals(viewName, "MenuButton")) + return new MenuButton(context, attrs); + else if (TextUtils.equals(viewName, "TabsButton")) + return new TabsButton(context, attrs); else if (TextUtils.equals(viewName, "TabsPanel")) return new TabsPanel(context, attrs); + else if (TextUtils.equals(viewName, "TabsPanelButton")) + return new TabsPanelButton(context, attrs); else if (TextUtils.equals(viewName, "TextSelectionHandle")) return new TextSelectionHandle(context, attrs); else if (TextUtils.equals(viewName, "gfx.LayerView")) diff --git a/mobile/android/base/Makefile.in b/mobile/android/base/Makefile.in index 6fd8ca39d862..6a1c98875930 100644 --- a/mobile/android/base/Makefile.in +++ b/mobile/android/base/Makefile.in @@ -51,8 +51,10 @@ FENNEC_JAVA_FILES = \ awesomebar/HistoryTab.java \ BrowserApp.java \ BrowserToolbar.java \ + BrowserToolbarBackground.java \ CameraImageResultHandler.java \ CameraVideoResultHandler.java \ + CanvasDelegate.java \ SyncPreference.java \ db/BrowserDB.java \ db/LocalBrowserDB.java \ @@ -87,6 +89,7 @@ FENNEC_JAVA_FILES = \ InputMethods.java \ LinkPreference.java \ LinkTextView.java \ + MenuButton.java \ MenuItemActionBar.java \ MenuItemDefault.java \ MultiChoicePreference.java \ @@ -109,7 +112,9 @@ FENNEC_JAVA_FILES = \ SurfaceBits.java \ Tab.java \ Tabs.java \ + TabsButton.java \ TabsPanel.java \ + TabsPanelButton.java \ TabsTray.java \ TabsAccessor.java \ Telemetry.java \ @@ -187,10 +192,17 @@ FENNEC_PP_JAVA_FILES = \ FENNEC_PP_XML_FILES = \ res/layout/abouthome_content.xml \ - res/layout-xlarge-land-v11/abouthome_content.xml \ + res/layout/browser_toolbar.xml \ + res/layout/browser_toolbar_menu.xml \ + res/layout-land-v14/browser_toolbar.xml \ + res/layout-land-v14/browser_toolbar_menu.xml \ + res/layout-large-v11/browser_toolbar_menu.xml \ + res/layout-xlarge-v11/browser_toolbar_menu.xml \ res/layout/gecko_app.xml \ - res/layout-xlarge-v11/gecko_app.xml \ res/layout/text_selection_handles.xml \ + res/layout-xlarge-land-v11/abouthome_content.xml \ + res/layout-xlarge-v11/awesomebar_search.xml \ + res/layout-xlarge-v11/gecko_app.xml \ res/xml/preferences.xml \ res/menu/browser_app_menu.xml \ res/menu-v11/browser_app_menu.xml \ @@ -305,8 +317,6 @@ RES_LAYOUT = \ res/layout/awesomebar_tab_indicator.xml \ res/layout/awesomebar_tabs.xml \ res/layout/bookmark_edit.xml \ - res/layout/browser_toolbar.xml \ - res/layout/browser_toolbar_menu.xml \ res/layout/doorhangerpopup.xml \ res/layout/doorhanger.xml \ res/layout/find_in_page_content.xml \ @@ -344,23 +354,18 @@ RES_LAYOUT = \ $(NULL) RES_LAYOUT_LAND_V14 = \ - res/layout-land-v14/browser_toolbar.xml \ - res/layout-land-v14/browser_toolbar_menu.xml \ res/layout-land-v14/tabs_panel_toolbar.xml \ res/layout-land-v14/tabs_panel_toolbar_menu.xml \ $(NULL) RES_LAYOUT_LARGE_V11 = \ res/layout-large-v11/awesomebar_search.xml \ - res/layout-large-v11/browser_toolbar_menu.xml \ res/layout-large-v11/doorhangerpopup.xml \ res/layout-large-v11/site_identity_popup.xml \ res/layout-large-v11/tabs_panel_toolbar_menu.xml \ $(NULL) RES_LAYOUT_XLARGE_V11 = \ - res/layout-xlarge-v11/awesomebar_search.xml \ - res/layout-xlarge-v11/browser_toolbar_menu.xml \ res/layout-xlarge-v11/font_size_preference.xml \ res/layout-xlarge-v11/remote_tabs_child.xml \ res/layout-xlarge-v11/remote_tabs_group.xml \ @@ -457,14 +462,9 @@ RES_DRAWABLE_BASE = \ res/drawable/tab_thumbnail_default.png \ res/drawable/tab_thumbnail_shadow.png \ res/drawable/tabs_carat.png \ - res/drawable/tabs_crop_normal.png \ - res/drawable/tabs_crop_pressed.png \ - res/drawable/tabs_full_normal.png \ - res/drawable/tabs_full_pressed.png \ res/drawable/address_bar_back_button.xml \ res/drawable/address_bar_back_button_bg.xml \ res/drawable/address_bar_back_button_pressed_bg.xml \ - res/drawable/address_bar_bg_curve.png \ res/drawable/address_bar_forward_button.xml \ res/drawable/address_bar_texture_port.png \ res/drawable/address_bar_url.xml \ @@ -541,11 +541,6 @@ RES_DRAWABLE_HDPI = \ res/drawable-hdpi/tab_thumbnail_default.png \ res/drawable-hdpi/tab_thumbnail_shadow.png \ res/drawable-hdpi/tabs_carat.png \ - res/drawable-hdpi/tabs_crop_normal.png \ - res/drawable-hdpi/tabs_crop_pressed.png \ - res/drawable-hdpi/tabs_full_normal.png \ - res/drawable-hdpi/tabs_full_pressed.png \ - res/drawable-hdpi/address_bar_bg_curve.png \ res/drawable-hdpi/address_bar_texture_port.png \ res/drawable-hdpi/address_bar_url_default.9.png \ res/drawable-hdpi/address_bar_url_pressed.9.png \ @@ -581,7 +576,6 @@ RES_DRAWABLE_XHDPI = \ res/drawable-xhdpi/abouthome_promo_logo_apps.png \ res/drawable-xhdpi/abouthome_promo_logo_sync.png \ res/drawable-xhdpi/abouthome_thumbnail.png \ - res/drawable-xhdpi/address_bar_bg_curve.png \ res/drawable-xhdpi/address_bar_bg_shadow.png \ res/drawable-xhdpi/address_bar_texture_port.png \ res/drawable-xhdpi/address_bar_url_default.9.png \ @@ -610,10 +604,6 @@ RES_DRAWABLE_XHDPI = \ res/drawable-xhdpi/tab_thumbnail_default.png \ res/drawable-xhdpi/tab_thumbnail_shadow.png \ res/drawable-xhdpi/tabs_carat.png \ - res/drawable-xhdpi/tabs_crop_normal.png \ - res/drawable-xhdpi/tabs_crop_pressed.png \ - res/drawable-xhdpi/tabs_full_normal.png \ - res/drawable-xhdpi/tabs_full_pressed.png \ res/drawable-xhdpi/doorhanger_arrow.png \ res/drawable-xhdpi/doorhanger_bg.9.png \ res/drawable-xhdpi/doorhanger_shadow_bg.9.png \ @@ -653,16 +643,12 @@ RES_DRAWABLE_MDPI_V11 = \ res/drawable-mdpi-v11/ic_menu_save_as_pdf.png \ res/drawable-mdpi-v11/ic_menu_share.png \ res/drawable-mdpi-v11/menu.png \ - res/drawable-mdpi-v11/menu_normal.png \ - res/drawable-mdpi-v11/menu_pressed.png \ res/drawable-mdpi-v11/menu_panel_bg.9.png \ res/drawable-mdpi-v11/menu_popup_bg.9.png \ res/drawable-mdpi-v11/menu_popup_arrow.png \ res/drawable-mdpi-v11/menu_item_texture.png \ res/drawable-mdpi-v11/menu_item_pressed_texture.png \ res/drawable-mdpi-v11/menu_item_check.png \ - res/drawable-mdpi-v11/tab_new_normal.png \ - res/drawable-mdpi-v11/tab_new_pressed.png \ $(NULL) RES_DRAWABLE_HDPI_V11 = \ @@ -681,16 +667,12 @@ RES_DRAWABLE_HDPI_V11 = \ res/drawable-hdpi-v11/ic_menu_save_as_pdf.png \ res/drawable-hdpi-v11/ic_menu_share.png \ res/drawable-hdpi-v11/menu.png \ - res/drawable-hdpi-v11/menu_normal.png \ - res/drawable-hdpi-v11/menu_pressed.png \ res/drawable-hdpi-v11/menu_panel_bg.9.png \ res/drawable-hdpi-v11/menu_popup_bg.9.png \ res/drawable-hdpi-v11/menu_popup_arrow.png \ res/drawable-hdpi-v11/menu_item_texture.png \ res/drawable-hdpi-v11/menu_item_pressed_texture.png \ res/drawable-hdpi-v11/menu_item_check.png \ - res/drawable-hdpi-v11/tab_new_normal.png \ - res/drawable-hdpi-v11/tab_new_pressed.png \ $(NULL) RES_DRAWABLE_XHDPI_V11 = \ @@ -709,16 +691,12 @@ RES_DRAWABLE_XHDPI_V11 = \ res/drawable-xhdpi-v11/ic_menu_save_as_pdf.png \ res/drawable-xhdpi-v11/ic_menu_share.png \ res/drawable-xhdpi-v11/menu.png \ - res/drawable-xhdpi-v11/menu_normal.png \ - res/drawable-xhdpi-v11/menu_pressed.png \ res/drawable-xhdpi-v11/menu_panel_bg.9.png \ res/drawable-xhdpi-v11/menu_popup_bg.9.png \ res/drawable-xhdpi-v11/menu_popup_arrow.png \ res/drawable-xhdpi-v11/menu_item_texture.png \ res/drawable-xhdpi-v11/menu_item_pressed_texture.png \ res/drawable-xhdpi-v11/menu_item_check.png \ - res/drawable-xhdpi-v11/tab_new_normal.png \ - res/drawable-xhdpi-v11/tab_new_pressed.png \ $(NULL) RES_DRAWABLE_LAND_V14 = \ @@ -728,24 +706,15 @@ RES_DRAWABLE_LAND_V14 = \ RES_DRAWABLE_LAND_MDPI_V14 = \ res/drawable-land-mdpi-v14/ic_awesomebar_go.png \ res/drawable-land-mdpi-v14/ic_awesomebar_search.png \ - res/drawable-land-mdpi-v14/address_bar_bg_curve.png \ res/drawable-land-mdpi-v14/address_bar_texture_land.png \ res/drawable-land-mdpi-v14/address_bar_url_default.9.png \ res/drawable-land-mdpi-v14/address_bar_url_pressed.9.png \ res/drawable-land-mdpi-v14/remote_tabs_off.png \ res/drawable-land-mdpi-v14/remote_tabs_on.png \ res/drawable-land-mdpi-v14/tab_new.png \ - res/drawable-land-mdpi-v14/tab_new_normal.png \ - res/drawable-land-mdpi-v14/tab_new_pressed.png \ res/drawable-land-mdpi-v14/tabs_carat.png \ - res/drawable-land-mdpi-v14/tabs_crop_normal.png \ - res/drawable-land-mdpi-v14/tabs_crop_pressed.png \ - res/drawable-land-mdpi-v14/tabs_full_normal.png \ - res/drawable-land-mdpi-v14/tabs_full_pressed.png \ res/drawable-land-mdpi-v14/urlbar_stop.png \ res/drawable-land-mdpi-v14/menu.png \ - res/drawable-land-mdpi-v14/menu_normal.png \ - res/drawable-land-mdpi-v14/menu_pressed.png \ res/drawable-land-mdpi-v14/reader.png \ res/drawable-land-mdpi-v14/site_security_identified.png \ res/drawable-land-mdpi-v14/site_security_verified.png \ @@ -754,24 +723,15 @@ RES_DRAWABLE_LAND_MDPI_V14 = \ RES_DRAWABLE_LAND_HDPI_V14 = \ res/drawable-land-hdpi-v14/ic_awesomebar_go.png \ res/drawable-land-hdpi-v14/ic_awesomebar_search.png \ - res/drawable-land-hdpi-v14/address_bar_bg_curve.png \ res/drawable-land-hdpi-v14/address_bar_texture_land.png \ res/drawable-land-hdpi-v14/address_bar_url_default.9.png \ res/drawable-land-hdpi-v14/address_bar_url_pressed.9.png \ res/drawable-land-hdpi-v14/remote_tabs_off.png \ res/drawable-land-hdpi-v14/remote_tabs_on.png \ res/drawable-land-hdpi-v14/tab_new.png \ - res/drawable-land-hdpi-v14/tab_new_normal.png \ - res/drawable-land-hdpi-v14/tab_new_pressed.png \ res/drawable-land-hdpi-v14/tabs_carat.png \ - res/drawable-land-hdpi-v14/tabs_crop_normal.png \ - res/drawable-land-hdpi-v14/tabs_crop_pressed.png \ - res/drawable-land-hdpi-v14/tabs_full_normal.png \ - res/drawable-land-hdpi-v14/tabs_full_pressed.png \ res/drawable-land-hdpi-v14/urlbar_stop.png \ res/drawable-land-hdpi-v14/menu.png \ - res/drawable-land-hdpi-v14/menu_normal.png \ - res/drawable-land-hdpi-v14/menu_pressed.png \ res/drawable-land-hdpi-v14/reader.png \ res/drawable-land-hdpi-v14/site_security_identified.png \ res/drawable-land-hdpi-v14/site_security_verified.png \ @@ -780,31 +740,21 @@ RES_DRAWABLE_LAND_HDPI_V14 = \ RES_DRAWABLE_LAND_XHDPI_V14 = \ res/drawable-land-xhdpi-v14/ic_awesomebar_go.png \ res/drawable-land-xhdpi-v14/ic_awesomebar_search.png \ - res/drawable-land-xhdpi-v14/address_bar_bg_curve.png \ res/drawable-land-xhdpi-v14/address_bar_texture_land.png \ res/drawable-land-xhdpi-v14/address_bar_url_default.9.png \ res/drawable-land-xhdpi-v14/address_bar_url_pressed.9.png \ res/drawable-land-xhdpi-v14/remote_tabs_off.png \ res/drawable-land-xhdpi-v14/remote_tabs_on.png \ res/drawable-land-xhdpi-v14/tab_new.png \ - res/drawable-land-xhdpi-v14/tab_new_normal.png \ - res/drawable-land-xhdpi-v14/tab_new_pressed.png \ res/drawable-land-xhdpi-v14/tabs_carat.png \ - res/drawable-land-xhdpi-v14/tabs_crop_normal.png \ - res/drawable-land-xhdpi-v14/tabs_crop_pressed.png \ - res/drawable-land-xhdpi-v14/tabs_full_normal.png \ - res/drawable-land-xhdpi-v14/tabs_full_pressed.png \ res/drawable-land-xhdpi-v14/urlbar_stop.png \ res/drawable-land-xhdpi-v14/menu.png \ - res/drawable-land-xhdpi-v14/menu_normal.png \ - res/drawable-land-xhdpi-v14/menu_pressed.png \ res/drawable-land-xhdpi-v14/reader.png \ res/drawable-land-xhdpi-v14/site_security_identified.png \ res/drawable-land-xhdpi-v14/site_security_verified.png \ $(NULL) RES_DRAWABLE_LARGE_MDPI_V11 = \ - res/drawable-large-mdpi-v11/address_bar_bg_curve.png \ res/drawable-large-mdpi-v11/address_bar_bg.xml \ res/drawable-large-mdpi-v11/address_bar_texture_tablet.png \ res/drawable-large-mdpi-v11/address_bar_back_button_bg.png \ @@ -820,24 +770,15 @@ RES_DRAWABLE_LARGE_MDPI_V11 = \ res/drawable-large-mdpi-v11/remote_tabs_off.png \ res/drawable-large-mdpi-v11/remote_tabs_on.png \ res/drawable-large-mdpi-v11/tab_new.png \ - res/drawable-large-mdpi-v11/tab_new_normal.png \ - res/drawable-large-mdpi-v11/tab_new_pressed.png \ res/drawable-large-mdpi-v11/urlbar_stop.png \ res/drawable-large-mdpi-v11/reader.png \ res/drawable-large-mdpi-v11/site_security_identified.png \ res/drawable-large-mdpi-v11/site_security_verified.png \ res/drawable-large-mdpi-v11/menu.png \ - res/drawable-large-mdpi-v11/menu_normal.png \ - res/drawable-large-mdpi-v11/menu_pressed.png \ res/drawable-large-mdpi-v11/tabs_carat.png \ - res/drawable-large-mdpi-v11/tabs_crop_normal.png \ - res/drawable-large-mdpi-v11/tabs_crop_pressed.png \ - res/drawable-large-mdpi-v11/tabs_full_normal.png \ - res/drawable-large-mdpi-v11/tabs_full_pressed.png \ $(NULL) RES_DRAWABLE_LARGE_HDPI_V11 = \ - res/drawable-large-hdpi-v11/address_bar_bg_curve.png \ res/drawable-large-hdpi-v11/address_bar_texture_tablet.png \ res/drawable-large-hdpi-v11/address_bar_back_button_bg.png \ res/drawable-large-hdpi-v11/address_bar_back_button_pressed_bg.png \ @@ -852,24 +793,15 @@ RES_DRAWABLE_LARGE_HDPI_V11 = \ res/drawable-large-hdpi-v11/remote_tabs_off.png \ res/drawable-large-hdpi-v11/remote_tabs_on.png \ res/drawable-large-hdpi-v11/tab_new.png \ - res/drawable-large-hdpi-v11/tab_new_normal.png \ - res/drawable-large-hdpi-v11/tab_new_pressed.png \ res/drawable-large-hdpi-v11/urlbar_stop.png \ res/drawable-large-hdpi-v11/reader.png \ res/drawable-large-hdpi-v11/site_security_identified.png \ res/drawable-large-hdpi-v11/site_security_verified.png \ res/drawable-large-hdpi-v11/menu.png \ - res/drawable-large-hdpi-v11/menu_normal.png \ - res/drawable-large-hdpi-v11/menu_pressed.png \ res/drawable-large-hdpi-v11/tabs_carat.png \ - res/drawable-large-hdpi-v11/tabs_crop_normal.png \ - res/drawable-large-hdpi-v11/tabs_crop_pressed.png \ - res/drawable-large-hdpi-v11/tabs_full_normal.png \ - res/drawable-large-hdpi-v11/tabs_full_pressed.png \ $(NULL) RES_DRAWABLE_LARGE_XHDPI_V11 = \ - res/drawable-large-xhdpi-v11/address_bar_bg_curve.png \ res/drawable-large-xhdpi-v11/address_bar_texture_tablet.png \ res/drawable-large-xhdpi-v11/address_bar_back_button_bg.png \ res/drawable-large-xhdpi-v11/address_bar_back_button_pressed_bg.png \ @@ -884,20 +816,12 @@ RES_DRAWABLE_LARGE_XHDPI_V11 = \ res/drawable-large-xhdpi-v11/remote_tabs_on.png \ res/drawable-large-xhdpi-v11/remote_tabs_off.png \ res/drawable-large-xhdpi-v11/tab_new.png \ - res/drawable-large-xhdpi-v11/tab_new_normal.png \ - res/drawable-large-xhdpi-v11/tab_new_pressed.png \ res/drawable-large-xhdpi-v11/urlbar_stop.png \ res/drawable-large-xhdpi-v11/reader.png \ res/drawable-large-xhdpi-v11/site_security_identified.png \ res/drawable-large-xhdpi-v11/site_security_verified.png \ res/drawable-large-xhdpi-v11/menu.png \ - res/drawable-large-xhdpi-v11/menu_normal.png \ - res/drawable-large-xhdpi-v11/menu_pressed.png \ res/drawable-large-xhdpi-v11/tabs_carat.png \ - res/drawable-large-xhdpi-v11/tabs_crop_normal.png \ - res/drawable-large-xhdpi-v11/tabs_crop_pressed.png \ - res/drawable-large-xhdpi-v11/tabs_full_normal.png \ - res/drawable-large-xhdpi-v11/tabs_full_pressed.png \ $(NULL) RES_DRAWABLE_XLARGE_MDPI_V11 = \ @@ -905,14 +829,10 @@ RES_DRAWABLE_XLARGE_MDPI_V11 = \ res/drawable-xlarge-mdpi-v11/awesomebar_tab_left.9.png \ res/drawable-xlarge-mdpi-v11/awesomebar_tab_right.9.png \ res/drawable-xlarge-mdpi-v11/menu.png \ - res/drawable-xlarge-mdpi-v11/tabs_crop_button.xml \ + res/drawable-xlarge-mdpi-v11/tabs_button.xml \ res/drawable-xlarge-mdpi-v11/tabs_carat_contracted.png \ res/drawable-xlarge-mdpi-v11/tabs_carat_expanded.png \ - res/drawable-xlarge-mdpi-v11/tabs_crop_expanded_normal.png \ - res/drawable-xlarge-mdpi-v11/tabs_crop_expanded_pressed.png \ res/drawable-xlarge-mdpi-v11/tabs_level.xml \ - res/drawable-xlarge-mdpi-v11/tabs_crop_normal.png \ - res/drawable-xlarge-mdpi-v11/tabs_crop_pressed.png \ $(NULL) RES_DRAWABLE_XLARGE_HDPI_V11 = \ @@ -922,10 +842,6 @@ RES_DRAWABLE_XLARGE_HDPI_V11 = \ res/drawable-xlarge-hdpi-v11/menu.png \ res/drawable-xlarge-hdpi-v11/tabs_carat_contracted.png \ res/drawable-xlarge-hdpi-v11/tabs_carat_expanded.png \ - res/drawable-xlarge-hdpi-v11/tabs_crop_expanded_normal.png \ - res/drawable-xlarge-hdpi-v11/tabs_crop_expanded_pressed.png \ - res/drawable-xlarge-hdpi-v11/tabs_crop_normal.png \ - res/drawable-xlarge-hdpi-v11/tabs_crop_pressed.png \ $(NULL) RES_DRAWABLE_XLARGE_XHDPI_V11 = \ @@ -935,10 +851,6 @@ RES_DRAWABLE_XLARGE_XHDPI_V11 = \ res/drawable-xlarge-xhdpi-v11/menu.png \ res/drawable-xlarge-xhdpi-v11/tabs_carat_contracted.png \ res/drawable-xlarge-xhdpi-v11/tabs_carat_expanded.png \ - res/drawable-xlarge-xhdpi-v11/tabs_crop_expanded_normal.png \ - res/drawable-xlarge-xhdpi-v11/tabs_crop_expanded_pressed.png \ - res/drawable-xlarge-xhdpi-v11/tabs_crop_normal.png \ - res/drawable-xlarge-xhdpi-v11/tabs_crop_pressed.png \ $(NULL) RES_COLOR = \ @@ -993,11 +905,7 @@ MOZ_ANDROID_DRAWABLES += \ mobile/android/base/resources/drawable/site_security_level.xml \ mobile/android/base/resources/drawable/suggestion_selector.xml \ mobile/android/base/resources/drawable/tab_new_button.xml \ - mobile/android/base/resources/drawable/tabs_crop_button.xml \ - mobile/android/base/resources/drawable/tabs_full_button.xml \ - mobile/android/base/resources/drawable/tabs_crop_button_contracted.xml \ - mobile/android/base/resources/drawable/tabs_full_button_contracted.xml \ - mobile/android/base/resources/drawable/tabs_crop_button_expanded.xml \ + mobile/android/base/resources/drawable/tabs_button.xml \ mobile/android/base/resources/drawable/tabs_level.xml \ mobile/android/base/resources/drawable/tabs_tray_bg_repeat.xml \ mobile/android/base/resources/drawable/tabs_tray_selected_bg_repeat.xml \ diff --git a/mobile/android/base/MenuButton.java b/mobile/android/base/MenuButton.java new file mode 100644 index 000000000000..fa0d7424b72d --- /dev/null +++ b/mobile/android/base/MenuButton.java @@ -0,0 +1,79 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.gecko; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Path; +import android.graphics.PorterDuff.Mode; +import android.util.AttributeSet; +import android.widget.ImageButton; + +public class MenuButton extends ImageButton + implements CanvasDelegate.DrawManager { + Path mPath; + CurveTowards mSide; + CanvasDelegate mCanvasDelegate; + + private enum CurveTowards { NONE, LEFT, RIGHT }; + + public MenuButton(Context context, AttributeSet attrs) { + super(context, attrs); + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.BrowserToolbarCurve); + int curveTowards = a.getInt(R.styleable.BrowserToolbarCurve_curveTowards, 0x02); + a.recycle(); + + if (curveTowards == 0x00) + mSide = CurveTowards.NONE; + else if (curveTowards == 0x01) + mSide = CurveTowards.LEFT; + else + mSide = CurveTowards.RIGHT; + + // Path is clipped. + mPath = new Path(); + mCanvasDelegate = new CanvasDelegate(this, Mode.DST_OUT); + } + + @Override + public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + int width = getMeasuredWidth(); + int height = getMeasuredHeight(); + float curve = height * 1.125f; + + mPath.reset(); + + // Clipping happens on opposite side for menu. + if (mSide == CurveTowards.RIGHT) { + mPath.moveTo(0, 0); + mPath.cubicTo(curve * 0.75f, 0, + curve * 0.25f, height, + curve, height); + mPath.lineTo(0, height); + mPath.lineTo(0, 0); + } else if (mSide == CurveTowards.LEFT) { + mPath.moveTo(width, 0); + mPath.cubicTo((width - (curve * 0.75f)), 0, + (width - (curve * 0.25f)), height, + (width - curve), height); + mPath.lineTo(width, height); + mPath.lineTo(width, 0); + } + } + + @Override + public void draw(Canvas canvas) { + mCanvasDelegate.draw(canvas, mPath, getWidth(), getHeight()); + } + + @Override + public void defaultDraw(Canvas canvas) { + super.draw(canvas); + } +} diff --git a/mobile/android/base/TabsButton.java b/mobile/android/base/TabsButton.java new file mode 100644 index 000000000000..48d0bd4a4752 --- /dev/null +++ b/mobile/android/base/TabsButton.java @@ -0,0 +1,177 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.gecko; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.ColorDrawable; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PorterDuffXfermode; +import android.graphics.PorterDuff.Mode; +import android.util.AttributeSet; +import android.widget.ImageButton; + +public class TabsButton extends ImageButton + implements CanvasDelegate.DrawManager { + Paint mPaint; + + Path mPath; + Path mBackgroundPath; + Path mLeftCurve; + Path mRightCurve; + + boolean mCropped; + int mFullWidth; + CurveTowards mSide; + CanvasDelegate mCanvasDelegate; + + private enum CurveTowards { NONE, LEFT, RIGHT }; + + public TabsButton(Context context, AttributeSet attrs) { + super(context, attrs); + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.BrowserToolbarCurve); + int curveTowards = a.getInt(R.styleable.BrowserToolbarCurve_curveTowards, 0x02); + a.recycle(); + + a = context.obtainStyledAttributes(attrs, R.styleable.TabsButton); + mCropped = a.getBoolean(R.styleable.TabsButton_cropped, false); + a.recycle(); + + if (curveTowards == 0x00) + mSide = CurveTowards.NONE; + else if (curveTowards == 0x01) + mSide = CurveTowards.LEFT; + else + mSide = CurveTowards.RIGHT; + + // Paint to draw the background. + mPaint = new Paint(); + mPaint.setAntiAlias(true); + mPaint.setColor(0xFF000000); + + // Path is masked. + mPath = new Path(); + mBackgroundPath = new Path(); + mLeftCurve = new Path(); + mRightCurve = new Path(); + mCanvasDelegate = new CanvasDelegate(this, Mode.DST_IN); + + // Path might extend beyond the screen for smaller tabs button. + mFullWidth = (int) context.getResources().getDimension(R.dimen.tabs_button_full_width); + } + + @Override + public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + int width = getMeasuredWidth(); + int height = getMeasuredHeight(); + float curve = height * 1.125f; + + // The bounds for the rectangle to carve the curves. + float left; + float right; + float top; + float bottom; + + if (mSide == CurveTowards.RIGHT) { + left = 0; + right = mFullWidth; + top = 0; + bottom = height; + } else { + left = width - mFullWidth; + right = width; + top = height; + bottom = 0; + } + + mLeftCurve.reset(); + mLeftCurve.moveTo(left, top); + + if (mCropped && mSide == CurveTowards.LEFT) { + mLeftCurve.cubicTo(left + curve, top, + left, bottom, + left + curve, bottom); + } else { + mLeftCurve.cubicTo(left + (curve * 0.75f), top, + left + (curve * 0.25f), bottom, + left + curve, bottom); + } + + mRightCurve.reset(); + mRightCurve.moveTo(right, bottom); + + if (mCropped && mSide == CurveTowards.RIGHT) { + mRightCurve.cubicTo(right - curve, bottom, + right, top, + right - curve, top); + } else { + mRightCurve.cubicTo(right - (curve * 0.75f), bottom, + right - (curve * 0.25f), top, + right - curve, top); + } + + mPath.reset(); + + // Level 2: for phones: transparent. + // for tablets: only one curve. + Drawable background = getBackground(); + + if (!(background.getCurrent() instanceof ColorDrawable)) { + if (background.getLevel() == 2) { + mPath.moveTo(left, top); + mPath.lineTo(left, bottom); + mPath.lineTo(right, bottom); + mPath.addPath(mRightCurve); + mPath.lineTo(left, top); + } else { + mPath.moveTo(left, top); + mPath.addPath(mLeftCurve); + mPath.lineTo(right, bottom); + mPath.addPath(mRightCurve); + mPath.lineTo(left, top); + } + } + + if (mCropped) { + mBackgroundPath.reset(); + + if (mSide == CurveTowards.RIGHT) { + mBackgroundPath.moveTo(right, bottom); + mBackgroundPath.addPath(mRightCurve); + mBackgroundPath.lineTo(right, top); + mBackgroundPath.lineTo(right, bottom); + } else { + mBackgroundPath.moveTo(left, top); + mBackgroundPath.addPath(mLeftCurve); + mBackgroundPath.lineTo(left, bottom); + mBackgroundPath.lineTo(left, top); + } + } + } + + @Override + public void draw(Canvas canvas) { + mCanvasDelegate.draw(canvas, mPath, getWidth(), getHeight()); + + Drawable background = getBackground(); + if (background.getCurrent() instanceof ColorDrawable) + return; + + // Additionally draw a black curve for cropped button's default level. + if (mCropped && background.getLevel() != 2) + canvas.drawPath(mBackgroundPath, mPaint); + } + + @Override + public void defaultDraw(Canvas canvas) { + super.draw(canvas); + } +} diff --git a/mobile/android/base/TabsPanel.java b/mobile/android/base/TabsPanel.java index 37f26c04574e..25fada2b646a 100644 --- a/mobile/android/base/TabsPanel.java +++ b/mobile/android/base/TabsPanel.java @@ -173,8 +173,7 @@ public class TabsPanel extends LinearLayout { int listHeight = (int) (0.5 * mContext.getResources().getDisplayMetrics().heightPixels); int height = actionBarHeight + listHeight; - if (showAnimation) - dispatchLayoutChange(getWidth(), height); + dispatchLayoutChange(getWidth(), height); } // If Sync is set up, query the database for remote clients. diff --git a/mobile/android/base/TabsPanelButton.java b/mobile/android/base/TabsPanelButton.java new file mode 100644 index 000000000000..98423a2a4abf --- /dev/null +++ b/mobile/android/base/TabsPanelButton.java @@ -0,0 +1,79 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.gecko; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Path; +import android.graphics.PorterDuff.Mode; +import android.util.AttributeSet; +import android.widget.ImageButton; + +public class TabsPanelButton extends ImageButton + implements CanvasDelegate.DrawManager { + Path mPath; + CurveTowards mSide; + CanvasDelegate mCanvasDelegate; + + private enum CurveTowards { NONE, LEFT, RIGHT }; + + public TabsPanelButton(Context context, AttributeSet attrs) { + super(context, attrs); + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.BrowserToolbarCurve); + int curveTowards = a.getInt(R.styleable.BrowserToolbarCurve_curveTowards, 0x02); + a.recycle(); + + if (curveTowards == 0x00) + mSide = CurveTowards.NONE; + else if (curveTowards == 0x01) + mSide = CurveTowards.LEFT; + else + mSide = CurveTowards.RIGHT; + + // Path is clipped. + mPath = new Path(); + mCanvasDelegate = new CanvasDelegate(this, Mode.DST_OUT); + } + + @Override + public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + int width = getMeasuredWidth(); + int height = getMeasuredHeight(); + float curve = height * 1.125f; + + mPath.reset(); + + // Clipping happens on opposite side for menu. + if (mSide == CurveTowards.LEFT) { + mPath.moveTo(0, height); + mPath.cubicTo(curve * 0.75f, height, + curve * 0.25f, 0, + curve, 0); + mPath.lineTo(0, 0); + mPath.lineTo(0, height); + } else if (mSide == CurveTowards.RIGHT) { + mPath.moveTo(width, height); + mPath.cubicTo((width - (curve * 0.75f)), height, + (width - (curve * 0.25f)), 0, + (width - curve), 0); + mPath.lineTo(width, 0); + mPath.lineTo(width, height); + } + } + + @Override + public void draw(Canvas canvas) { + mCanvasDelegate.draw(canvas, mPath, getWidth(), getHeight()); + } + + @Override + public void defaultDraw(Canvas canvas) { + super.draw(canvas); + } +} diff --git a/mobile/android/base/resources/drawable-hdpi-v11/menu_normal.png b/mobile/android/base/resources/drawable-hdpi-v11/menu_normal.png deleted file mode 100644 index 909ad15af3f8..000000000000 Binary files a/mobile/android/base/resources/drawable-hdpi-v11/menu_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-hdpi-v11/menu_pressed.png b/mobile/android/base/resources/drawable-hdpi-v11/menu_pressed.png deleted file mode 100644 index a6479aaad95a..000000000000 Binary files a/mobile/android/base/resources/drawable-hdpi-v11/menu_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-hdpi-v11/tab_new_normal.png b/mobile/android/base/resources/drawable-hdpi-v11/tab_new_normal.png deleted file mode 100644 index a01aabf00a6e..000000000000 Binary files a/mobile/android/base/resources/drawable-hdpi-v11/tab_new_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-hdpi-v11/tab_new_pressed.png b/mobile/android/base/resources/drawable-hdpi-v11/tab_new_pressed.png deleted file mode 100644 index cf6fbd6d4f28..000000000000 Binary files a/mobile/android/base/resources/drawable-hdpi-v11/tab_new_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-hdpi/address_bar_bg_curve.png b/mobile/android/base/resources/drawable-hdpi/address_bar_bg_curve.png deleted file mode 100644 index 44c7f9f03f71..000000000000 Binary files a/mobile/android/base/resources/drawable-hdpi/address_bar_bg_curve.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-hdpi/tabs_crop_normal.png b/mobile/android/base/resources/drawable-hdpi/tabs_crop_normal.png deleted file mode 100644 index 86c42b1c4055..000000000000 Binary files a/mobile/android/base/resources/drawable-hdpi/tabs_crop_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-hdpi/tabs_crop_pressed.png b/mobile/android/base/resources/drawable-hdpi/tabs_crop_pressed.png deleted file mode 100644 index dfd61eec0f1a..000000000000 Binary files a/mobile/android/base/resources/drawable-hdpi/tabs_crop_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-hdpi/tabs_full_normal.png b/mobile/android/base/resources/drawable-hdpi/tabs_full_normal.png deleted file mode 100644 index 67f08841de29..000000000000 Binary files a/mobile/android/base/resources/drawable-hdpi/tabs_full_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-hdpi/tabs_full_pressed.png b/mobile/android/base/resources/drawable-hdpi/tabs_full_pressed.png deleted file mode 100644 index a0c1566bdb06..000000000000 Binary files a/mobile/android/base/resources/drawable-hdpi/tabs_full_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-land-hdpi-v14/address_bar_bg_curve.png b/mobile/android/base/resources/drawable-land-hdpi-v14/address_bar_bg_curve.png deleted file mode 100644 index 4c45eb707074..000000000000 Binary files a/mobile/android/base/resources/drawable-land-hdpi-v14/address_bar_bg_curve.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-land-hdpi-v14/menu_normal.png b/mobile/android/base/resources/drawable-land-hdpi-v14/menu_normal.png deleted file mode 100644 index c655ba11a7c2..000000000000 Binary files a/mobile/android/base/resources/drawable-land-hdpi-v14/menu_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-land-hdpi-v14/menu_pressed.png b/mobile/android/base/resources/drawable-land-hdpi-v14/menu_pressed.png deleted file mode 100644 index b1430110f845..000000000000 Binary files a/mobile/android/base/resources/drawable-land-hdpi-v14/menu_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-land-hdpi-v14/tab_new_normal.png b/mobile/android/base/resources/drawable-land-hdpi-v14/tab_new_normal.png deleted file mode 100644 index 649f0663d9b5..000000000000 Binary files a/mobile/android/base/resources/drawable-land-hdpi-v14/tab_new_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-land-hdpi-v14/tab_new_pressed.png b/mobile/android/base/resources/drawable-land-hdpi-v14/tab_new_pressed.png deleted file mode 100644 index 3ffb8eb357b2..000000000000 Binary files a/mobile/android/base/resources/drawable-land-hdpi-v14/tab_new_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-land-hdpi-v14/tabs_crop_normal.png b/mobile/android/base/resources/drawable-land-hdpi-v14/tabs_crop_normal.png deleted file mode 100644 index 736ac9979eb5..000000000000 Binary files a/mobile/android/base/resources/drawable-land-hdpi-v14/tabs_crop_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-land-hdpi-v14/tabs_crop_pressed.png b/mobile/android/base/resources/drawable-land-hdpi-v14/tabs_crop_pressed.png deleted file mode 100644 index 22693b3b6a83..000000000000 Binary files a/mobile/android/base/resources/drawable-land-hdpi-v14/tabs_crop_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-land-hdpi-v14/tabs_full_normal.png b/mobile/android/base/resources/drawable-land-hdpi-v14/tabs_full_normal.png deleted file mode 100644 index dd63b3617626..000000000000 Binary files a/mobile/android/base/resources/drawable-land-hdpi-v14/tabs_full_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-land-hdpi-v14/tabs_full_pressed.png b/mobile/android/base/resources/drawable-land-hdpi-v14/tabs_full_pressed.png deleted file mode 100644 index b43cfa5cfef2..000000000000 Binary files a/mobile/android/base/resources/drawable-land-hdpi-v14/tabs_full_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-land-mdpi-v14/address_bar_bg_curve.png b/mobile/android/base/resources/drawable-land-mdpi-v14/address_bar_bg_curve.png deleted file mode 100644 index 59037f45bd42..000000000000 Binary files a/mobile/android/base/resources/drawable-land-mdpi-v14/address_bar_bg_curve.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-land-mdpi-v14/menu_normal.png b/mobile/android/base/resources/drawable-land-mdpi-v14/menu_normal.png deleted file mode 100644 index 8a50605a1cda..000000000000 Binary files a/mobile/android/base/resources/drawable-land-mdpi-v14/menu_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-land-mdpi-v14/menu_pressed.png b/mobile/android/base/resources/drawable-land-mdpi-v14/menu_pressed.png deleted file mode 100644 index 3c501e2c9d3d..000000000000 Binary files a/mobile/android/base/resources/drawable-land-mdpi-v14/menu_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-land-mdpi-v14/tab_new_normal.png b/mobile/android/base/resources/drawable-land-mdpi-v14/tab_new_normal.png deleted file mode 100644 index 8e2f6769509e..000000000000 Binary files a/mobile/android/base/resources/drawable-land-mdpi-v14/tab_new_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-land-mdpi-v14/tab_new_pressed.png b/mobile/android/base/resources/drawable-land-mdpi-v14/tab_new_pressed.png deleted file mode 100644 index 43b389c4ccbd..000000000000 Binary files a/mobile/android/base/resources/drawable-land-mdpi-v14/tab_new_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-land-mdpi-v14/tabs_crop_normal.png b/mobile/android/base/resources/drawable-land-mdpi-v14/tabs_crop_normal.png deleted file mode 100644 index fcd82c97bbae..000000000000 Binary files a/mobile/android/base/resources/drawable-land-mdpi-v14/tabs_crop_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-land-mdpi-v14/tabs_crop_pressed.png b/mobile/android/base/resources/drawable-land-mdpi-v14/tabs_crop_pressed.png deleted file mode 100644 index bf051955574d..000000000000 Binary files a/mobile/android/base/resources/drawable-land-mdpi-v14/tabs_crop_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-land-mdpi-v14/tabs_full_normal.png b/mobile/android/base/resources/drawable-land-mdpi-v14/tabs_full_normal.png deleted file mode 100644 index ae9da954d232..000000000000 Binary files a/mobile/android/base/resources/drawable-land-mdpi-v14/tabs_full_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-land-mdpi-v14/tabs_full_pressed.png b/mobile/android/base/resources/drawable-land-mdpi-v14/tabs_full_pressed.png deleted file mode 100644 index 5f434e167210..000000000000 Binary files a/mobile/android/base/resources/drawable-land-mdpi-v14/tabs_full_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-land-xhdpi-v14/address_bar_bg_curve.png b/mobile/android/base/resources/drawable-land-xhdpi-v14/address_bar_bg_curve.png deleted file mode 100644 index ef9b71bde253..000000000000 Binary files a/mobile/android/base/resources/drawable-land-xhdpi-v14/address_bar_bg_curve.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-land-xhdpi-v14/menu_normal.png b/mobile/android/base/resources/drawable-land-xhdpi-v14/menu_normal.png deleted file mode 100644 index 137bbce4e918..000000000000 Binary files a/mobile/android/base/resources/drawable-land-xhdpi-v14/menu_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-land-xhdpi-v14/menu_pressed.png b/mobile/android/base/resources/drawable-land-xhdpi-v14/menu_pressed.png deleted file mode 100644 index 51a8d24993d0..000000000000 Binary files a/mobile/android/base/resources/drawable-land-xhdpi-v14/menu_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-land-xhdpi-v14/tab_new_normal.png b/mobile/android/base/resources/drawable-land-xhdpi-v14/tab_new_normal.png deleted file mode 100644 index 65af5a3942f1..000000000000 Binary files a/mobile/android/base/resources/drawable-land-xhdpi-v14/tab_new_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-land-xhdpi-v14/tab_new_pressed.png b/mobile/android/base/resources/drawable-land-xhdpi-v14/tab_new_pressed.png deleted file mode 100644 index a16f4500f3a1..000000000000 Binary files a/mobile/android/base/resources/drawable-land-xhdpi-v14/tab_new_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-land-xhdpi-v14/tabs_crop_normal.png b/mobile/android/base/resources/drawable-land-xhdpi-v14/tabs_crop_normal.png deleted file mode 100644 index 566247d550e7..000000000000 Binary files a/mobile/android/base/resources/drawable-land-xhdpi-v14/tabs_crop_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-land-xhdpi-v14/tabs_crop_pressed.png b/mobile/android/base/resources/drawable-land-xhdpi-v14/tabs_crop_pressed.png deleted file mode 100644 index c122e58b55e9..000000000000 Binary files a/mobile/android/base/resources/drawable-land-xhdpi-v14/tabs_crop_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-land-xhdpi-v14/tabs_full_normal.png b/mobile/android/base/resources/drawable-land-xhdpi-v14/tabs_full_normal.png deleted file mode 100644 index 6e9610570478..000000000000 Binary files a/mobile/android/base/resources/drawable-land-xhdpi-v14/tabs_full_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-land-xhdpi-v14/tabs_full_pressed.png b/mobile/android/base/resources/drawable-land-xhdpi-v14/tabs_full_pressed.png deleted file mode 100644 index 01acadf3e241..000000000000 Binary files a/mobile/android/base/resources/drawable-land-xhdpi-v14/tabs_full_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-large-hdpi-v11/address_bar_bg_curve.png b/mobile/android/base/resources/drawable-large-hdpi-v11/address_bar_bg_curve.png deleted file mode 100644 index d9478f1be04e..000000000000 Binary files a/mobile/android/base/resources/drawable-large-hdpi-v11/address_bar_bg_curve.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-large-hdpi-v11/menu_normal.png b/mobile/android/base/resources/drawable-large-hdpi-v11/menu_normal.png deleted file mode 100644 index b2ed96760c08..000000000000 Binary files a/mobile/android/base/resources/drawable-large-hdpi-v11/menu_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-large-hdpi-v11/menu_pressed.png b/mobile/android/base/resources/drawable-large-hdpi-v11/menu_pressed.png deleted file mode 100644 index efd8d5a4d2d2..000000000000 Binary files a/mobile/android/base/resources/drawable-large-hdpi-v11/menu_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-large-hdpi-v11/tab_new_normal.png b/mobile/android/base/resources/drawable-large-hdpi-v11/tab_new_normal.png deleted file mode 100644 index d0498d79ee8a..000000000000 Binary files a/mobile/android/base/resources/drawable-large-hdpi-v11/tab_new_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-large-hdpi-v11/tab_new_pressed.png b/mobile/android/base/resources/drawable-large-hdpi-v11/tab_new_pressed.png deleted file mode 100644 index 4f3154513e4a..000000000000 Binary files a/mobile/android/base/resources/drawable-large-hdpi-v11/tab_new_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-large-hdpi-v11/tabs_crop_normal.png b/mobile/android/base/resources/drawable-large-hdpi-v11/tabs_crop_normal.png deleted file mode 100644 index 62a065c1180e..000000000000 Binary files a/mobile/android/base/resources/drawable-large-hdpi-v11/tabs_crop_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-large-hdpi-v11/tabs_crop_pressed.png b/mobile/android/base/resources/drawable-large-hdpi-v11/tabs_crop_pressed.png deleted file mode 100644 index fa796f8dc85c..000000000000 Binary files a/mobile/android/base/resources/drawable-large-hdpi-v11/tabs_crop_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-large-hdpi-v11/tabs_full_normal.png b/mobile/android/base/resources/drawable-large-hdpi-v11/tabs_full_normal.png deleted file mode 100644 index 71e33b9f3f57..000000000000 Binary files a/mobile/android/base/resources/drawable-large-hdpi-v11/tabs_full_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-large-hdpi-v11/tabs_full_pressed.png b/mobile/android/base/resources/drawable-large-hdpi-v11/tabs_full_pressed.png deleted file mode 100644 index cd785ee57aa8..000000000000 Binary files a/mobile/android/base/resources/drawable-large-hdpi-v11/tabs_full_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-large-mdpi-v11/address_bar_bg_curve.png b/mobile/android/base/resources/drawable-large-mdpi-v11/address_bar_bg_curve.png deleted file mode 100644 index 719b2dd3246f..000000000000 Binary files a/mobile/android/base/resources/drawable-large-mdpi-v11/address_bar_bg_curve.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-large-mdpi-v11/menu_normal.png b/mobile/android/base/resources/drawable-large-mdpi-v11/menu_normal.png deleted file mode 100644 index 25d6e4016d7b..000000000000 Binary files a/mobile/android/base/resources/drawable-large-mdpi-v11/menu_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-large-mdpi-v11/menu_pressed.png b/mobile/android/base/resources/drawable-large-mdpi-v11/menu_pressed.png deleted file mode 100644 index c3cca45fffb6..000000000000 Binary files a/mobile/android/base/resources/drawable-large-mdpi-v11/menu_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-large-mdpi-v11/tab_new_normal.png b/mobile/android/base/resources/drawable-large-mdpi-v11/tab_new_normal.png deleted file mode 100644 index 4df597fbf2f6..000000000000 Binary files a/mobile/android/base/resources/drawable-large-mdpi-v11/tab_new_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-large-mdpi-v11/tab_new_pressed.png b/mobile/android/base/resources/drawable-large-mdpi-v11/tab_new_pressed.png deleted file mode 100644 index 09a6ef102eed..000000000000 Binary files a/mobile/android/base/resources/drawable-large-mdpi-v11/tab_new_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-large-mdpi-v11/tabs_crop_normal.png b/mobile/android/base/resources/drawable-large-mdpi-v11/tabs_crop_normal.png deleted file mode 100644 index ff2095151ac1..000000000000 Binary files a/mobile/android/base/resources/drawable-large-mdpi-v11/tabs_crop_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-large-mdpi-v11/tabs_crop_pressed.png b/mobile/android/base/resources/drawable-large-mdpi-v11/tabs_crop_pressed.png deleted file mode 100644 index 592b15f159db..000000000000 Binary files a/mobile/android/base/resources/drawable-large-mdpi-v11/tabs_crop_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-large-mdpi-v11/tabs_full_normal.png b/mobile/android/base/resources/drawable-large-mdpi-v11/tabs_full_normal.png deleted file mode 100644 index 6102d718919a..000000000000 Binary files a/mobile/android/base/resources/drawable-large-mdpi-v11/tabs_full_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-large-mdpi-v11/tabs_full_pressed.png b/mobile/android/base/resources/drawable-large-mdpi-v11/tabs_full_pressed.png deleted file mode 100644 index d45a133503bd..000000000000 Binary files a/mobile/android/base/resources/drawable-large-mdpi-v11/tabs_full_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-large-xhdpi-v11/address_bar_bg_curve.png b/mobile/android/base/resources/drawable-large-xhdpi-v11/address_bar_bg_curve.png deleted file mode 100644 index 0954184880e9..000000000000 Binary files a/mobile/android/base/resources/drawable-large-xhdpi-v11/address_bar_bg_curve.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-large-xhdpi-v11/menu_normal.png b/mobile/android/base/resources/drawable-large-xhdpi-v11/menu_normal.png deleted file mode 100644 index a8cfcae442c1..000000000000 Binary files a/mobile/android/base/resources/drawable-large-xhdpi-v11/menu_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-large-xhdpi-v11/menu_pressed.png b/mobile/android/base/resources/drawable-large-xhdpi-v11/menu_pressed.png deleted file mode 100644 index 14d83b8e2264..000000000000 Binary files a/mobile/android/base/resources/drawable-large-xhdpi-v11/menu_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-large-xhdpi-v11/tab_new_normal.png b/mobile/android/base/resources/drawable-large-xhdpi-v11/tab_new_normal.png deleted file mode 100644 index 2e0d4015d24f..000000000000 Binary files a/mobile/android/base/resources/drawable-large-xhdpi-v11/tab_new_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-large-xhdpi-v11/tab_new_pressed.png b/mobile/android/base/resources/drawable-large-xhdpi-v11/tab_new_pressed.png deleted file mode 100644 index d64e38215a54..000000000000 Binary files a/mobile/android/base/resources/drawable-large-xhdpi-v11/tab_new_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-large-xhdpi-v11/tabs_crop_normal.png b/mobile/android/base/resources/drawable-large-xhdpi-v11/tabs_crop_normal.png deleted file mode 100644 index 0c48078d2d28..000000000000 Binary files a/mobile/android/base/resources/drawable-large-xhdpi-v11/tabs_crop_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-large-xhdpi-v11/tabs_crop_pressed.png b/mobile/android/base/resources/drawable-large-xhdpi-v11/tabs_crop_pressed.png deleted file mode 100644 index d419956a7f85..000000000000 Binary files a/mobile/android/base/resources/drawable-large-xhdpi-v11/tabs_crop_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-large-xhdpi-v11/tabs_full_normal.png b/mobile/android/base/resources/drawable-large-xhdpi-v11/tabs_full_normal.png deleted file mode 100644 index ace26457690a..000000000000 Binary files a/mobile/android/base/resources/drawable-large-xhdpi-v11/tabs_full_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-large-xhdpi-v11/tabs_full_pressed.png b/mobile/android/base/resources/drawable-large-xhdpi-v11/tabs_full_pressed.png deleted file mode 100644 index 085ecc26d48a..000000000000 Binary files a/mobile/android/base/resources/drawable-large-xhdpi-v11/tabs_full_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-mdpi-v11/menu_normal.png b/mobile/android/base/resources/drawable-mdpi-v11/menu_normal.png deleted file mode 100644 index 17f0a94a54b4..000000000000 Binary files a/mobile/android/base/resources/drawable-mdpi-v11/menu_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-mdpi-v11/menu_pressed.png b/mobile/android/base/resources/drawable-mdpi-v11/menu_pressed.png deleted file mode 100644 index 9cd4aa65ac56..000000000000 Binary files a/mobile/android/base/resources/drawable-mdpi-v11/menu_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-mdpi-v11/tab_new_normal.png b/mobile/android/base/resources/drawable-mdpi-v11/tab_new_normal.png deleted file mode 100644 index 94e574f01633..000000000000 Binary files a/mobile/android/base/resources/drawable-mdpi-v11/tab_new_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-mdpi-v11/tab_new_pressed.png b/mobile/android/base/resources/drawable-mdpi-v11/tab_new_pressed.png deleted file mode 100644 index 5494fb46bc1a..000000000000 Binary files a/mobile/android/base/resources/drawable-mdpi-v11/tab_new_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-xhdpi-v11/menu_normal.png b/mobile/android/base/resources/drawable-xhdpi-v11/menu_normal.png deleted file mode 100644 index 621676a882ef..000000000000 Binary files a/mobile/android/base/resources/drawable-xhdpi-v11/menu_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-xhdpi-v11/menu_pressed.png b/mobile/android/base/resources/drawable-xhdpi-v11/menu_pressed.png deleted file mode 100644 index 542bf2e1eb1d..000000000000 Binary files a/mobile/android/base/resources/drawable-xhdpi-v11/menu_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-xhdpi-v11/tab_new_normal.png b/mobile/android/base/resources/drawable-xhdpi-v11/tab_new_normal.png deleted file mode 100644 index 0312fd0b7608..000000000000 Binary files a/mobile/android/base/resources/drawable-xhdpi-v11/tab_new_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-xhdpi-v11/tab_new_pressed.png b/mobile/android/base/resources/drawable-xhdpi-v11/tab_new_pressed.png deleted file mode 100644 index 8e63a5b5871e..000000000000 Binary files a/mobile/android/base/resources/drawable-xhdpi-v11/tab_new_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-xhdpi/address_bar_bg_curve.png b/mobile/android/base/resources/drawable-xhdpi/address_bar_bg_curve.png deleted file mode 100644 index 0199df0ebffc..000000000000 Binary files a/mobile/android/base/resources/drawable-xhdpi/address_bar_bg_curve.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-xhdpi/tabs_crop_normal.png b/mobile/android/base/resources/drawable-xhdpi/tabs_crop_normal.png deleted file mode 100644 index 52fb1e5dc3f5..000000000000 Binary files a/mobile/android/base/resources/drawable-xhdpi/tabs_crop_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-xhdpi/tabs_crop_pressed.png b/mobile/android/base/resources/drawable-xhdpi/tabs_crop_pressed.png deleted file mode 100644 index 70e1d68beeda..000000000000 Binary files a/mobile/android/base/resources/drawable-xhdpi/tabs_crop_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-xhdpi/tabs_full_normal.png b/mobile/android/base/resources/drawable-xhdpi/tabs_full_normal.png deleted file mode 100644 index a94b452b2a0d..000000000000 Binary files a/mobile/android/base/resources/drawable-xhdpi/tabs_full_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-xhdpi/tabs_full_pressed.png b/mobile/android/base/resources/drawable-xhdpi/tabs_full_pressed.png deleted file mode 100644 index 38159e74828e..000000000000 Binary files a/mobile/android/base/resources/drawable-xhdpi/tabs_full_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-xlarge-hdpi-v11/tabs_crop_expanded_normal.png b/mobile/android/base/resources/drawable-xlarge-hdpi-v11/tabs_crop_expanded_normal.png deleted file mode 100644 index 8a9348013a7d..000000000000 Binary files a/mobile/android/base/resources/drawable-xlarge-hdpi-v11/tabs_crop_expanded_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-xlarge-hdpi-v11/tabs_crop_expanded_pressed.png b/mobile/android/base/resources/drawable-xlarge-hdpi-v11/tabs_crop_expanded_pressed.png deleted file mode 100644 index 4a0b0a0f189a..000000000000 Binary files a/mobile/android/base/resources/drawable-xlarge-hdpi-v11/tabs_crop_expanded_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-xlarge-hdpi-v11/tabs_crop_normal.png b/mobile/android/base/resources/drawable-xlarge-hdpi-v11/tabs_crop_normal.png deleted file mode 100644 index 0bb1f267f2e9..000000000000 Binary files a/mobile/android/base/resources/drawable-xlarge-hdpi-v11/tabs_crop_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-xlarge-hdpi-v11/tabs_crop_pressed.png b/mobile/android/base/resources/drawable-xlarge-hdpi-v11/tabs_crop_pressed.png deleted file mode 100644 index aba9614a2907..000000000000 Binary files a/mobile/android/base/resources/drawable-xlarge-hdpi-v11/tabs_crop_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-xlarge-mdpi-v11/tabs_button.xml b/mobile/android/base/resources/drawable-xlarge-mdpi-v11/tabs_button.xml new file mode 100644 index 000000000000..b661061b58ba --- /dev/null +++ b/mobile/android/base/resources/drawable-xlarge-mdpi-v11/tabs_button.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/mobile/android/base/resources/drawable-xlarge-mdpi-v11/tabs_crop_button.xml b/mobile/android/base/resources/drawable-xlarge-mdpi-v11/tabs_crop_button.xml deleted file mode 100644 index 8c28d24f6410..000000000000 --- a/mobile/android/base/resources/drawable-xlarge-mdpi-v11/tabs_crop_button.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - diff --git a/mobile/android/base/resources/drawable-xlarge-mdpi-v11/tabs_crop_expanded_normal.png b/mobile/android/base/resources/drawable-xlarge-mdpi-v11/tabs_crop_expanded_normal.png deleted file mode 100644 index 18411a354a7b..000000000000 Binary files a/mobile/android/base/resources/drawable-xlarge-mdpi-v11/tabs_crop_expanded_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-xlarge-mdpi-v11/tabs_crop_expanded_pressed.png b/mobile/android/base/resources/drawable-xlarge-mdpi-v11/tabs_crop_expanded_pressed.png deleted file mode 100644 index 8f04068205e0..000000000000 Binary files a/mobile/android/base/resources/drawable-xlarge-mdpi-v11/tabs_crop_expanded_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-xlarge-mdpi-v11/tabs_crop_normal.png b/mobile/android/base/resources/drawable-xlarge-mdpi-v11/tabs_crop_normal.png deleted file mode 100644 index 29eb6930393d..000000000000 Binary files a/mobile/android/base/resources/drawable-xlarge-mdpi-v11/tabs_crop_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-xlarge-mdpi-v11/tabs_crop_pressed.png b/mobile/android/base/resources/drawable-xlarge-mdpi-v11/tabs_crop_pressed.png deleted file mode 100644 index 0fbc66ca6533..000000000000 Binary files a/mobile/android/base/resources/drawable-xlarge-mdpi-v11/tabs_crop_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-xlarge-xhdpi-v11/tabs_crop_expanded_normal.png b/mobile/android/base/resources/drawable-xlarge-xhdpi-v11/tabs_crop_expanded_normal.png deleted file mode 100644 index 2dd10b8539c6..000000000000 Binary files a/mobile/android/base/resources/drawable-xlarge-xhdpi-v11/tabs_crop_expanded_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-xlarge-xhdpi-v11/tabs_crop_expanded_pressed.png b/mobile/android/base/resources/drawable-xlarge-xhdpi-v11/tabs_crop_expanded_pressed.png deleted file mode 100644 index e97d35d2e852..000000000000 Binary files a/mobile/android/base/resources/drawable-xlarge-xhdpi-v11/tabs_crop_expanded_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-xlarge-xhdpi-v11/tabs_crop_normal.png b/mobile/android/base/resources/drawable-xlarge-xhdpi-v11/tabs_crop_normal.png deleted file mode 100644 index 05d9975a2ed4..000000000000 Binary files a/mobile/android/base/resources/drawable-xlarge-xhdpi-v11/tabs_crop_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-xlarge-xhdpi-v11/tabs_crop_pressed.png b/mobile/android/base/resources/drawable-xlarge-xhdpi-v11/tabs_crop_pressed.png deleted file mode 100644 index 73e745cb25fb..000000000000 Binary files a/mobile/android/base/resources/drawable-xlarge-xhdpi-v11/tabs_crop_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable/address_bar_bg_curve.png b/mobile/android/base/resources/drawable/address_bar_bg_curve.png deleted file mode 100644 index aeb2a1655531..000000000000 Binary files a/mobile/android/base/resources/drawable/address_bar_bg_curve.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable/menu_button.xml b/mobile/android/base/resources/drawable/menu_button.xml index 47e00fbeaa64..bfbdaa5ec7dc 100644 --- a/mobile/android/base/resources/drawable/menu_button.xml +++ b/mobile/android/base/resources/drawable/menu_button.xml @@ -7,8 +7,8 @@ - - + + diff --git a/mobile/android/base/resources/drawable/tab_new_button.xml b/mobile/android/base/resources/drawable/tab_new_button.xml index 41e60b82c67b..cf67f10ef98f 100644 --- a/mobile/android/base/resources/drawable/tab_new_button.xml +++ b/mobile/android/base/resources/drawable/tab_new_button.xml @@ -5,7 +5,7 @@ - - + + diff --git a/mobile/android/base/resources/drawable/tabs_crop_button.xml b/mobile/android/base/resources/drawable/tabs_button.xml similarity index 63% rename from mobile/android/base/resources/drawable/tabs_crop_button.xml rename to mobile/android/base/resources/drawable/tabs_button.xml index 25efe7a4a25f..6a2dd6e23c15 100644 --- a/mobile/android/base/resources/drawable/tabs_crop_button.xml +++ b/mobile/android/base/resources/drawable/tabs_button.xml @@ -5,7 +5,13 @@ - + + + + + + + diff --git a/mobile/android/base/resources/drawable/tabs_crop_button_contracted.xml b/mobile/android/base/resources/drawable/tabs_crop_button_contracted.xml deleted file mode 100644 index 0a3adb23205d..000000000000 --- a/mobile/android/base/resources/drawable/tabs_crop_button_contracted.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - diff --git a/mobile/android/base/resources/drawable/tabs_crop_button_expanded.xml b/mobile/android/base/resources/drawable/tabs_crop_button_expanded.xml deleted file mode 100644 index d59b352725a1..000000000000 --- a/mobile/android/base/resources/drawable/tabs_crop_button_expanded.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - diff --git a/mobile/android/base/resources/drawable/tabs_crop_normal.png b/mobile/android/base/resources/drawable/tabs_crop_normal.png deleted file mode 100644 index f89aaa57b38f..000000000000 Binary files a/mobile/android/base/resources/drawable/tabs_crop_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable/tabs_crop_pressed.png b/mobile/android/base/resources/drawable/tabs_crop_pressed.png deleted file mode 100644 index 7e90d95e8c0b..000000000000 Binary files a/mobile/android/base/resources/drawable/tabs_crop_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable/tabs_full_button.xml b/mobile/android/base/resources/drawable/tabs_full_button.xml deleted file mode 100644 index 55c33fc31797..000000000000 --- a/mobile/android/base/resources/drawable/tabs_full_button.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - diff --git a/mobile/android/base/resources/drawable/tabs_full_button_contracted.xml b/mobile/android/base/resources/drawable/tabs_full_button_contracted.xml deleted file mode 100644 index dac68fb780dc..000000000000 --- a/mobile/android/base/resources/drawable/tabs_full_button_contracted.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - diff --git a/mobile/android/base/resources/drawable/tabs_full_normal.png b/mobile/android/base/resources/drawable/tabs_full_normal.png deleted file mode 100644 index 9ce78641436c..000000000000 Binary files a/mobile/android/base/resources/drawable/tabs_full_normal.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable/tabs_full_pressed.png b/mobile/android/base/resources/drawable/tabs_full_pressed.png deleted file mode 100644 index 3d037ec79ce8..000000000000 Binary files a/mobile/android/base/resources/drawable/tabs_full_pressed.png and /dev/null differ diff --git a/mobile/android/base/resources/layout-land-v14/browser_toolbar.xml b/mobile/android/base/resources/layout-land-v14/browser_toolbar.xml.in similarity index 76% rename from mobile/android/base/resources/layout-land-v14/browser_toolbar.xml rename to mobile/android/base/resources/layout-land-v14/browser_toolbar.xml.in index e59467e5ba79..29b789b6a1bc 100644 --- a/mobile/android/base/resources/layout-land-v14/browser_toolbar.xml +++ b/mobile/android/base/resources/layout-land-v14/browser_toolbar.xml.in @@ -1,9 +1,11 @@ +#filter substitution @@ -23,31 +25,27 @@ android:layout_height="0dip" android:visibility="gone"/> - + - + - - - + @@ -23,41 +25,35 @@ android:layout_height="0dip" android:visibility="gone"/> - + - + - - - + - + + android:layout_marginRight="15dip"> - + diff --git a/mobile/android/base/resources/layout-large-v11/browser_toolbar_menu.xml b/mobile/android/base/resources/layout-large-v11/browser_toolbar_menu.xml.in similarity index 74% rename from mobile/android/base/resources/layout-large-v11/browser_toolbar_menu.xml rename to mobile/android/base/resources/layout-large-v11/browser_toolbar_menu.xml.in index 34860f6bab9a..e4b27c778d4c 100644 --- a/mobile/android/base/resources/layout-large-v11/browser_toolbar_menu.xml +++ b/mobile/android/base/resources/layout-large-v11/browser_toolbar_menu.xml.in @@ -1,51 +1,47 @@ +#filter substitution - + - + - - - + - + + android:layout_marginRight="28dip"> - + diff --git a/mobile/android/base/resources/layout-xlarge-v11/awesomebar_search.xml b/mobile/android/base/resources/layout-xlarge-v11/awesomebar_search.xml.in similarity index 76% rename from mobile/android/base/resources/layout-xlarge-v11/awesomebar_search.xml rename to mobile/android/base/resources/layout-xlarge-v11/awesomebar_search.xml.in index 1b10fe35f606..e5814380cdd9 100644 --- a/mobile/android/base/resources/layout-xlarge-v11/awesomebar_search.xml +++ b/mobile/android/base/resources/layout-xlarge-v11/awesomebar_search.xml.in @@ -1,18 +1,22 @@ +#filter substitution - + @@ -11,15 +13,17 @@ style="@style/AddressBar" android:background="@drawable/address_bar_bg"> - + - + @@ -23,31 +25,27 @@ android:layout_height="0dip" android:visibility="gone"/> - + - + - - - + - + diff --git a/mobile/android/base/resources/layout/browser_toolbar_menu.xml b/mobile/android/base/resources/layout/browser_toolbar_menu.xml.in similarity index 64% rename from mobile/android/base/resources/layout/browser_toolbar_menu.xml rename to mobile/android/base/resources/layout/browser_toolbar_menu.xml.in index 91722adc9dad..2570e7f27952 100644 --- a/mobile/android/base/resources/layout/browser_toolbar_menu.xml +++ b/mobile/android/base/resources/layout/browser_toolbar_menu.xml.in @@ -1,9 +1,11 @@ +#filter substitution @@ -23,42 +25,36 @@ android:layout_height="0dip" android:visibility="gone"/> - + - + - - - + - + diff --git a/mobile/android/base/resources/layout/tabs_panel_toolbar_menu.xml b/mobile/android/base/resources/layout/tabs_panel_toolbar_menu.xml index e495c31778c6..5ad45a7f54b3 100644 --- a/mobile/android/base/resources/layout/tabs_panel_toolbar_menu.xml +++ b/mobile/android/base/resources/layout/tabs_panel_toolbar_menu.xml @@ -8,17 +8,17 @@ - + + android:layout_marginRight="22dip"> - + diff --git a/mobile/android/base/resources/values-land-v14/dimens.xml b/mobile/android/base/resources/values-land-v14/dimens.xml index f9c3194774c2..bb154a5ec0ca 100644 --- a/mobile/android/base/resources/values-land-v14/dimens.xml +++ b/mobile/android/base/resources/values-land-v14/dimens.xml @@ -8,5 +8,6 @@ 40dp 46dp 18sp + 80dp diff --git a/mobile/android/base/resources/values-large-v11/dimens.xml b/mobile/android/base/resources/values-large-v11/dimens.xml index de24d5e86a53..a20367581e7c 100644 --- a/mobile/android/base/resources/values-large-v11/dimens.xml +++ b/mobile/android/base/resources/values-large-v11/dimens.xml @@ -8,5 +8,6 @@ 56dp 45dp 26sp + 115dp diff --git a/mobile/android/base/resources/values-xlarge-v11/dimens.xml b/mobile/android/base/resources/values-xlarge-v11/dimens.xml index e9b2139c6a7f..56353587bd9a 100644 --- a/mobile/android/base/resources/values-xlarge-v11/dimens.xml +++ b/mobile/android/base/resources/values-xlarge-v11/dimens.xml @@ -16,5 +16,6 @@ 48dp 28dp 26sp + 115dp diff --git a/mobile/android/base/resources/values/attrs.xml b/mobile/android/base/resources/values/attrs.xml index 361f08e97cb8..610f1bfab2c7 100644 --- a/mobile/android/base/resources/values/attrs.xml +++ b/mobile/android/base/resources/values/attrs.xml @@ -6,9 +6,9 @@ - - - + + + @@ -24,21 +24,33 @@ - + - - - + + + + + + + + + + + + + + + - + - + diff --git a/mobile/android/base/resources/values/dimens.xml b/mobile/android/base/resources/values/dimens.xml index d88ff0615b74..cb0349c5c144 100644 --- a/mobile/android/base/resources/values/dimens.xml +++ b/mobile/android/base/resources/values/dimens.xml @@ -32,8 +32,9 @@ 400dp 78dp 136dp - 2dp + 98dp 22sp + 2dp 30dp 44dp 2dp diff --git a/mobile/android/chrome/content/aboutReader.js b/mobile/android/chrome/content/aboutReader.js index 641eb8592b35..e7224a52328e 100644 --- a/mobile/android/chrome/content/aboutReader.js +++ b/mobile/android/chrome/content/aboutReader.js @@ -25,20 +25,20 @@ let gStrings = Services.strings.createBundle("chrome://browser/locale/aboutReade let AboutReader = function(doc, win) { dump("Init()"); - this._doc = doc; - this._win = win; + this._docRef = Cu.getWeakReference(doc); + this._winRef = Cu.getWeakReference(win); Services.obs.addObserver(this, "Reader:FaviconReturn", false); this._article = null; dump("Feching toolbar, header and content notes from about:reader"); - this._headerElement = doc.getElementById("reader-header"); - this._domainElement = doc.getElementById("reader-domain"); - this._titleElement = doc.getElementById("reader-title"); - this._creditsElement = doc.getElementById("reader-credits"); - this._contentElement = doc.getElementById("reader-content"); - this._toolbarElement = doc.getElementById("reader-toolbar"); + this._headerElementRef = Cu.getWeakReference(doc.getElementById("reader-header")); + this._domainElementRef = Cu.getWeakReference(doc.getElementById("reader-domain")); + this._titleElementRef = Cu.getWeakReference(doc.getElementById("reader-title")); + this._creditsElementRef = Cu.getWeakReference(doc.getElementById("reader-credits")); + this._contentElementRef = Cu.getWeakReference(doc.getElementById("reader-content")); + this._toolbarElementRef = Cu.getWeakReference(doc.getElementById("reader-toolbar")); this._toolbarEnabled = false; @@ -104,11 +104,44 @@ AboutReader.prototype = { ".content .wp-caption img, " + ".content figure img", + get _doc() { + return this._docRef.get(); + }, + + get _win() { + return this._winRef.get(); + }, + + get _headerElement() { + return this._headerElementRef.get(); + }, + + get _domainElement() { + return this._domainElementRef.get(); + }, + + get _titleElement() { + return this._titleElementRef.get(); + }, + + get _creditsElement() { + return this._creditsElementRef.get(); + }, + + get _contentElement() { + return this._contentElementRef.get(); + }, + + get _toolbarElement() { + return this._toolbarElementRef.get(); + }, + observe: function(aMessage, aTopic, aData) { switch(aTopic) { case "Reader:FaviconReturn": { let info = JSON.parse(aData); this._loadFavicon(info.url, info.faviconUrl); + Services.obs.removeObserver(this, "Reader:FaviconReturn", false); break; } } @@ -142,23 +175,6 @@ AboutReader.prototype = { } }, - uninit: function Reader_uninit() { - dump("Uninit()"); - - Services.obs.removeObserver(this, "Reader:FaviconReturn", false); - - let body = this._doc.body; - body.removeEventListener("touchstart", this, false); - body.removeEventListener("click", this, false); - - let win = this._win; - win.removeEventListener("scroll", this, false); - win.removeEventListener("popstate", this, false); - win.removeEventListener("resize", this, false); - - this._hideContent(); - }, - _updateToggleButton: function Reader_updateToggleButton() { let classes = this._doc.getElementById("toggle-button").classList; diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index 99711368c092..4b0aece8025c 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -164,7 +164,6 @@ var BrowserApp = { Services.obs.addObserver(this, "Preferences:Set", false); Services.obs.addObserver(this, "ScrollTo:FocusedInput", false); Services.obs.addObserver(this, "Sanitize:ClearData", false); - Services.obs.addObserver(this, "PanZoom:PanZoom", false); Services.obs.addObserver(this, "FullScreen:Exit", false); Services.obs.addObserver(this, "Viewport:Change", false); Services.obs.addObserver(this, "Viewport:Flush", false); @@ -2681,11 +2680,17 @@ Tab.prototype = { // pages have any privilege themselves. if (/^about:/.test(target.documentURI)) { this.browser.addEventListener("click", ErrorPageEventHandler, false); - this.browser.addEventListener("pagehide", function listener() { + let listener = function() { this.browser.removeEventListener("click", ErrorPageEventHandler, false); this.browser.removeEventListener("pagehide", listener, true); - }.bind(this), true); + }.bind(this); + + this.browser.addEventListener("pagehide", listener, true); } + + if (/^about:reader/.test(target.documentURI)) + new AboutReader(this.browser.contentDocument, this.browser.contentWindow); + break; } @@ -2935,14 +2940,6 @@ Tab.prototype = { } }); - if (/^about:reader/.test(aEvent.originalTarget.documentURI)) { - let aboutReader = new AboutReader(this.browser.contentDocument, this.browser.contentWindow); - this.browser.addEventListener("pagehide", function listener() { - aboutReader.uninit(); - this.browser.removeEventListener("pagehide", listener, true); - }.bind(this), true); - } - // Once document is fully loaded, parse it Reader.parseDocumentFromTab(this.id, function (article) { // Do nothing if there's no article or the page in this tab has diff --git a/netwerk/base/public/nsIPermissionManager.idl b/netwerk/base/public/nsIPermissionManager.idl index 7ead8bcbd4c7..8ba0f2cba292 100644 --- a/netwerk/base/public/nsIPermissionManager.idl +++ b/netwerk/base/public/nsIPermissionManager.idl @@ -35,7 +35,7 @@ interface nsIURI; interface nsIObserver; interface nsIPrincipal; -[scriptable, uuid(cc423aaf-f088-4ec2-86ef-7733225773f9)] +[scriptable, uuid(da33450a-f3cb-4fdb-93ee-219644e450c2)] interface nsIPermissionManager : nsISupports { /** @@ -169,6 +169,11 @@ interface nsIPermissionManager : nsISupports * nsIPermission objects */ readonly attribute nsISimpleEnumerator enumerator; + + /** + * Remove all permissions associated with a given app id. + */ + void removePermissionsForApp(in unsigned long appId); }; %{ C++ diff --git a/netwerk/protocol/app/AppProtocolHandler.js b/netwerk/protocol/app/AppProtocolHandler.js index fe6cbe15dd44..28050c5c1abc 100644 --- a/netwerk/protocol/app/AppProtocolHandler.js +++ b/netwerk/protocol/app/AppProtocolHandler.js @@ -16,7 +16,7 @@ XPCOMUtils.defineLazyServiceGetter(this, "cpmm", "nsISyncMessageSender"); function AppProtocolHandler() { - this._basePath = null; + this._basePath = []; } AppProtocolHandler.prototype = { @@ -30,12 +30,14 @@ AppProtocolHandler.prototype = { Ci.nsIProtocolHandler.URI_NOAUTH | Ci.nsIProtocolHandler.URI_LOADABLE_BY_ANYONE, - get basePath() { - if (!this._basePath) { - this._basePath = cpmm.sendSyncMessage("Webapps:GetBasePath", { })[0] + "/"; + getBasePath: function app_phGetBasePath(aId) { + + if (!this._basePath[aId]) { + this._basePath[aId] = cpmm.sendSyncMessage("Webapps:GetBasePath", + { id: aId })[0] + "/"; } - return this._basePath; + return this._basePath[aId]; }, newURI: function app_phNewURI(aSpec, aOriginCharset, aBaseURI) { @@ -60,7 +62,7 @@ AppProtocolHandler.prototype = { } // Build a jar channel and masquerade as an app:// URI. - let uri = "jar:file://" + this.basePath + appId + "/application.zip!" + fileSpec; + let uri = "jar:file://" + this.getBasePath(appId) + appId + "/application.zip!" + fileSpec; let channel = Services.io.newChannel(uri, null, null); channel.QueryInterface(Ci.nsIJARChannel).setAppURI(aURI); channel.QueryInterface(Ci.nsIChannel).originalURI = aURI; diff --git a/testing/xpcshell/xpcshell.ini b/testing/xpcshell/xpcshell.ini index 7e458cf536c7..29def8dabb7f 100644 --- a/testing/xpcshell/xpcshell.ini +++ b/testing/xpcshell/xpcshell.ini @@ -103,7 +103,7 @@ skip-if = !debug skip-if = os == "linux" || !crashreporter [include:toolkit/crashreporter/test/unit_ipc/xpcshell.ini] -skip-if.os == "linux" || !crashreporter +skip-if = !crashreporter #XXX: we don't actually set os = maemo [include:toolkit/crashreporter/client/maemo-unit/xpcshell.ini] @@ -116,8 +116,6 @@ skip-if = os != "win" skip-if = os == "win" || os == "mac" || os == "os2" [include:content/base/test/unit_ipc/xpcshell.ini] -run-if.config = ipc - [include:chrome/test/unit_ipc/xpcshell.ini] [include:extensions/cookie/test/unit_ipc/xpcshell.ini] [include:ipc/testshell/tests/xpcshell.ini] diff --git a/toolkit/components/osfile/osfile_shared_allthreads.jsm b/toolkit/components/osfile/osfile_shared_allthreads.jsm index 420021a24938..0f23968a170b 100644 --- a/toolkit/components/osfile/osfile_shared_allthreads.jsm +++ b/toolkit/components/osfile/osfile_shared_allthreads.jsm @@ -46,6 +46,10 @@ }); }; + /** + * A variable controlling whether we should printout logs. + */ + exports.OS.Shared.DEBUG = false; let LOG; if (typeof console != "undefined" && console.log) { LOG = console.log.bind(console, "OS"); @@ -329,8 +333,10 @@ }; function projector(type, signed) { - LOG("Determining best projection for", type, + if (exports.OS.Shared.DEBUG) { + LOG("Determining best projection for", type, "(size: ", type.size, ")", signed?"signed":"unsigned"); + } if (type instanceof Type) { type = type.implementation; } @@ -348,14 +354,20 @@ || type == ctypes.uintptr_t || type == ctypes.off_t){ if (signed) { - LOG("Projected as a large signed integer"); + if (exports.OS.Shared.DEBUG) { + LOG("Projected as a large signed integer"); + } return projectLargeInt; } else { - LOG("Projected as a large unsigned integer"); + if (exports.OS.Shared.DEBUG) { + LOG("Projected as a large unsigned integer"); + } return projectLargeUInt; } } - LOG("Projected as a regular number"); + if (exports.OS.Shared.DEBUG) { + LOG("Projected as a regular number"); + } return projectValue; }; exports.OS.Shared.projectValue = projectValue; @@ -758,7 +770,9 @@ // thread let declareFFI = function declareFFI(lib, symbol, abi, returnType /*, argTypes ...*/) { - LOG("Attempting to declare FFI ", symbol); + if (exports.OS.Shared.DEBUG) { + LOG("Attempting to declare FFI ", symbol); + } // We guard agressively, to avoid any late surprise if (typeof symbol != "string") { throw new TypeError("declareFFI expects as first argument a string"); @@ -796,12 +810,16 @@ if (exports.OS.Shared.DEBUG) { result.fun = fun; // Also return the raw FFI function. } - LOG("Function", symbol, "declared"); + if (exports.OS.Shared.DEBUG) { + LOG("Function", symbol, "declared"); + } return result; } catch (x) { // Note: Not being able to declare a function is normal. // Some functions are OS (or OS version)-specific. - LOG("Could not declare function " + symbol, x); + if (exports.OS.Shared.DEBUG) { + LOG("Could not declare function " + symbol, x); + } return null; } }; diff --git a/toolkit/components/osfile/osfile_unix_allthreads.jsm b/toolkit/components/osfile/osfile_unix_allthreads.jsm index 430cbad402fc..6b7ccdec5c1c 100644 --- a/toolkit/components/osfile/osfile_unix_allthreads.jsm +++ b/toolkit/components/osfile/osfile_unix_allthreads.jsm @@ -50,7 +50,9 @@ if (typeof Components != "undefined") { libc = ctypes.open(libc_candidates[i]); break; } catch (x) { - LOG("Could not open libc "+libc_candidates[i]); + if (exports.OS.Shared.DEBUG) { + LOG("Could not open libc "+libc_candidates[i]); + } } } if (!libc) { diff --git a/toolkit/components/osfile/osfile_unix_back.jsm b/toolkit/components/osfile/osfile_unix_back.jsm index 3891263d74e5..9c7ccb540654 100644 --- a/toolkit/components/osfile/osfile_unix_back.jsm +++ b/toolkit/components/osfile/osfile_unix_back.jsm @@ -343,7 +343,7 @@ UnixFile.mkstemp = declareFFI("mkstemp", ctypes.default_abi, - /*return*/ Types.out_path, + /*return*/ Types.fd, /*template*/Types.out_path); UnixFile.open = diff --git a/toolkit/components/osfile/ospath_unix_back.jsm b/toolkit/components/osfile/ospath_unix_back.jsm index d9c8c8b1888d..6def9e7ca351 100644 --- a/toolkit/components/osfile/ospath_unix_back.jsm +++ b/toolkit/components/osfile/ospath_unix_back.jsm @@ -112,7 +112,9 @@ if (typeof Components != "undefined") { stack.push(v); } }); - exports.OS.Shared.LOG("normalize", "stack", stack.toSource()); + if (exports.OS.Shared.DEBUG) { + exports.OS.Shared.LOG("normalize", "stack", stack.toSource()); + } let string = stack.join("/"); return absolute ? "/" + string : string; }, diff --git a/toolkit/components/telemetry/Telemetry.cpp b/toolkit/components/telemetry/Telemetry.cpp index 8829849ab1a9..cce1317c47a2 100644 --- a/toolkit/components/telemetry/Telemetry.cpp +++ b/toolkit/components/telemetry/Telemetry.cpp @@ -1395,8 +1395,7 @@ TelemetryImpl::RecordSlowStatement(const nsACString &sql, const nsACString &dbName, uint32_t delay) { - MOZ_ASSERT(sTelemetry); - if (!sTelemetry->mCanRecord) + if (!sTelemetry || !sTelemetry->mCanRecord) return; nsCAutoString fullSQL(sql); @@ -1421,10 +1420,8 @@ void TelemetryImpl::RecordChromeHang(uint32_t duration, Telemetry::ProcessedStack &aStack) { - MOZ_ASSERT(sTelemetry); - if (!sTelemetry->mCanRecord) { + if (!sTelemetry || !sTelemetry->mCanRecord) return; - } MutexAutoLock hangReportMutex(sTelemetry->mHangReportsMutex); @@ -1432,8 +1429,7 @@ TelemetryImpl::RecordChromeHang(uint32_t duration, if (sTelemetry->mHangReports.Length()) { Telemetry::ProcessedStack &firstStack = sTelemetry->mHangReports[0].mStack; - const uint32_t moduleCount = aStack.GetNumModules(); - for (size_t i = 0; i < moduleCount; ++i) { + for (size_t i = 0; i < aStack.GetNumModules(); ++i) { const Telemetry::ProcessedStack::Module &module = aStack.GetModule(i); if (firstStack.HasModule(module)) { aStack.RemoveModule(i); diff --git a/toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist_OSVersion.xml b/toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist_OSVersion.xml new file mode 100644 index 000000000000..463207d146e6 --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist_OSVersion.xml @@ -0,0 +1,32 @@ + + + + + + WINNT 6.2 + 0xabcd + + 0x2783 + 0x1234 + 0x2782 + + DIRECT2D + BLOCKED_DRIVER_VERSION + 8.52.322.2202 + LESS_THAN + + + Darwin 12 + 0xabcd + + 0x2783 + 0x1234 + 0x2782 + + OPENGL_LAYERS + BLOCKED_DRIVER_VERSION + 8.52.322.2202 + LESS_THAN + + + diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_match.js b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_match.js new file mode 100644 index 000000000000..0688fa2289fc --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_match.js @@ -0,0 +1,97 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// Test whether new OS versions are matched properly. +// Uses test_gfxBlacklist_OS.xml + +Components.utils.import("resource://testing-common/httpd.js"); + +var gTestserver = null; + +function get_platform() { + var xulRuntime = Components.classes["@mozilla.org/xre/app-info;1"] + .getService(Components.interfaces.nsIXULRuntime); + return xulRuntime.OS; +} + +function load_blocklist(file) { + Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:4444/data/" + file); + var blocklist = Cc["@mozilla.org/extensions/blocklist;1"]. + getService(Ci.nsITimerCallback); + blocklist.notify(null); +} + +// Performs the initial setup +function run_test() { + try { + var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo); + } catch (e) { + do_test_finished(); + return; + } + + // We can't do anything if we can't spoof the stuff we need. + if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) { + do_test_finished(); + return; + } + + gfxInfo.QueryInterface(Ci.nsIGfxInfoDebug); + + // Set the vendor/device ID, etc, to match the test file. + gfxInfo.spoofDriverVersion("8.52.322.2201"); + gfxInfo.spoofVendorID("0xabcd"); + gfxInfo.spoofDeviceID("0x1234"); + + // Spoof the version of the OS appropriately to test the test file. + switch (get_platform()) { + case "WINNT": + // Windows 8 + gfxInfo.spoofOSVersion(0x60002); + break; + case "Linux": + // We don't have any OS versions on Linux, just "Linux". + do_test_finished(); + return; + case "Darwin": + // Mountain Lion + gfxInfo.spoofOSVersion(0x1080); + break; + case "Android": + // On Android, the driver version is used as the OS version (because + // there's so many of them). + do_test_finished(); + return; + } + + createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "3", "8"); + startupManager(); + + gTestserver = new HttpServer(); + gTestserver.registerDirectory("/data/", do_get_file("data")); + gTestserver.start(4444); + + do_test_pending(); + + function checkBlacklist() + { + if (get_platform() == "WINNT") { + var status = gfxInfo.getFeatureStatus(Ci.nsIGfxInfo.FEATURE_DIRECT2D); + do_check_eq(status, Ci.nsIGfxInfo.FEATURE_BLOCKED_DRIVER_VERSION); + } else if (get_platform() == "Darwin") { + status = gfxInfo.getFeatureStatus(Ci.nsIGfxInfo.FEATURE_OPENGL_LAYERS); + do_check_eq(status, Ci.nsIGfxInfo.FEATURE_BLOCKED_DRIVER_VERSION); + } + + gTestserver.stop(do_test_finished); + } + + Services.obs.addObserver(function(aSubject, aTopic, aData) { + // If we wait until after we go through the event loop, gfxInfo is sure to + // have processed the gfxItems event. + do_execute_soon(checkBlacklist); + }, "blocklist-data-gfxItems", false); + + load_blocklist("test_gfxBlacklist_OS.xml"); +} diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_DriverVersion.js b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_DriverVersion.js new file mode 100644 index 000000000000..7113fe2fab31 --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_DriverVersion.js @@ -0,0 +1,98 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// Test whether blocklists specifying new OSeswcorrectly don't block if driver +// versions are appropriately up-to-date. +// Uses test_gfxBlacklist_OS.xml + +Components.utils.import("resource://testing-common/httpd.js"); + +var gTestserver = null; + +function get_platform() { + var xulRuntime = Components.classes["@mozilla.org/xre/app-info;1"] + .getService(Components.interfaces.nsIXULRuntime); + return xulRuntime.OS; +} + +function load_blocklist(file) { + Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:4444/data/" + file); + var blocklist = Cc["@mozilla.org/extensions/blocklist;1"]. + getService(Ci.nsITimerCallback); + blocklist.notify(null); +} + +// Performs the initial setup +function run_test() { + try { + var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo); + } catch (e) { + do_test_finished(); + return; + } + + // We can't do anything if we can't spoof the stuff we need. + if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) { + do_test_finished(); + return; + } + + gfxInfo.QueryInterface(Ci.nsIGfxInfoDebug); + + // Set the vendor/device ID, etc, to match the test file. + gfxInfo.spoofDriverVersion("8.52.322.2202"); + gfxInfo.spoofVendorID("0xabcd"); + gfxInfo.spoofDeviceID("0x1234"); + + // Spoof the version of the OS appropriately to test the test file. + switch (get_platform()) { + case "WINNT": + // Windows 8 + gfxInfo.spoofOSVersion(0x60002); + break; + case "Linux": + // We don't have any OS versions on Linux, just "Linux". + do_test_finished(); + return; + case "Darwin": + // Mountain Lion + gfxInfo.spoofOSVersion(0x1080); + break; + case "Android": + // On Android, the driver version is used as the OS version (because + // there's so many of them). + do_test_finished(); + return; + } + + createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "3", "8"); + startupManager(); + + gTestserver = new HttpServer(); + gTestserver.registerDirectory("/data/", do_get_file("data")); + gTestserver.start(4444); + + do_test_pending(); + + function checkBlacklist() + { + if (get_platform() == "WINNT") { + var status = gfxInfo.getFeatureStatus(Ci.nsIGfxInfo.FEATURE_DIRECT2D); + do_check_eq(status, Ci.nsIGfxInfo.FEATURE_NO_INFO); + } else if (get_platform() == "Darwin") { + status = gfxInfo.getFeatureStatus(Ci.nsIGfxInfo.FEATURE_OPENGL_LAYERS); + do_check_eq(status, Ci.nsIGfxInfo.FEATURE_NO_INFO); + } + + gTestserver.stop(do_test_finished); + } + + Services.obs.addObserver(function(aSubject, aTopic, aData) { + // If we wait until after we go through the event loop, gfxInfo is sure to + // have processed the gfxItems event. + do_execute_soon(checkBlacklist); + }, "blocklist-data-gfxItems", false); + + load_blocklist("test_gfxBlacklist_OS.xml"); +} diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_OSVersion.js b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_OSVersion.js new file mode 100644 index 000000000000..2b635902e786 --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_OSVersion.js @@ -0,0 +1,98 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// Test whether old OS versions are not matched when the blacklist contains +// only new OS versions. +// Uses test_gfxBlacklist_OS.xml + +Components.utils.import("resource://testing-common/httpd.js"); + +var gTestserver = null; + +function get_platform() { + var xulRuntime = Components.classes["@mozilla.org/xre/app-info;1"] + .getService(Components.interfaces.nsIXULRuntime); + return xulRuntime.OS; +} + +function load_blocklist(file) { + Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:4444/data/" + file); + var blocklist = Cc["@mozilla.org/extensions/blocklist;1"]. + getService(Ci.nsITimerCallback); + blocklist.notify(null); +} + +// Performs the initial setup +function run_test() { + try { + var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo); + } catch (e) { + do_test_finished(); + return; + } + + // We can't do anything if we can't spoof the stuff we need. + if (!(gfxInfo instanceof Ci.nsIGfxInfoDebug)) { + do_test_finished(); + return; + } + + gfxInfo.QueryInterface(Ci.nsIGfxInfoDebug); + + // Set the vendor/device ID, etc, to match the test file. + gfxInfo.spoofDriverVersion("8.52.322.2201"); + gfxInfo.spoofVendorID("0xabcd"); + gfxInfo.spoofDeviceID("0x1234"); + + // Spoof the version of the OS appropriately to test the test file. + switch (get_platform()) { + case "WINNT": + // Windows 7 + gfxInfo.spoofOSVersion(0x60001); + break; + case "Linux": + // We don't have any OS versions on Linux, just "Linux". + do_test_finished(); + return; + case "Darwin": + // Lion + gfxInfo.spoofOSVersion(0x1070); + break; + case "Android": + // On Android, the driver version is used as the OS version (because + // there's so many of them). + do_test_finished(); + return; + } + + createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "3", "8"); + startupManager(); + + gTestserver = new HttpServer(); + gTestserver.registerDirectory("/data/", do_get_file("data")); + gTestserver.start(4444); + + do_test_pending(); + + function checkBlacklist() + { + if (get_platform() == "WINNT") { + var status = gfxInfo.getFeatureStatus(Ci.nsIGfxInfo.FEATURE_DIRECT2D); + do_check_eq(status, Ci.nsIGfxInfo.FEATURE_NO_INFO); + } else if (get_platform() == "Darwin") { + status = gfxInfo.getFeatureStatus(Ci.nsIGfxInfo.FEATURE_OPENGL_LAYERS); + do_check_eq(status, Ci.nsIGfxInfo.FEATURE_NO_INFO); + } + + gTestserver.stop(do_test_finished); + } + + Services.obs.addObserver(function(aSubject, aTopic, aData) { + // If we wait until after we go through the event loop, gfxInfo is sure to + // have processed the gfxItems event. + do_execute_soon(checkBlacklist); + }, "blocklist-data-gfxItems", false); + + load_blocklist("test_gfxBlacklist_OS.xml"); +} diff --git a/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini b/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini index b70d7527e80e..20ba274517bd 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini +++ b/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini @@ -164,6 +164,9 @@ skip-if = os == "android" [test_gfxBlacklist_No_Comparison.js] [test_gfxBlacklist_OK.js] [test_gfxBlacklist_OS.js] +[test_gfxBlacklist_OSVersion_match.js] +[test_gfxBlacklist_OSVersion_mismatch_OSVersion.js] +[test_gfxBlacklist_OSVersion_mismatch_DriverVersion.js] [test_gfxBlacklist_Vendor.js] [test_gfxBlacklist_prefs.js] [test_hasbinarycomponents.js] diff --git a/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp b/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp index 8f6e957b261d..3f499e6005f6 100644 --- a/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp +++ b/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp @@ -371,7 +371,7 @@ nsUnixSystemProxySettings::GetProxyFromGConf(const nsACString& aScheme, { bool masterProxySwitch = false; mGConf->GetBool(NS_LITERAL_CSTRING("/system/http_proxy/use_http_proxy"), &masterProxySwitch); - if (!IsProxyMode("manual") || !masterProxySwitch) { + if (!(IsProxyMode("manual") || masterProxySwitch)) { aResult.AppendLiteral("DIRECT"); return NS_OK; } diff --git a/widget/cocoa/GfxInfo.mm b/widget/cocoa/GfxInfo.mm index 6081bb108d7c..1b01ddbcb103 100644 --- a/widget/cocoa/GfxInfo.mm +++ b/widget/cocoa/GfxInfo.mm @@ -30,6 +30,7 @@ #define MAC_OS_X_VERSION_10_5_HEX 0x00001050 #define MAC_OS_X_VERSION_10_6_HEX 0x00001060 #define MAC_OS_X_VERSION_10_7_HEX 0x00001070 +#define MAC_OS_X_VERSION_10_8_HEX 0x00001080 using namespace mozilla; using namespace mozilla::widget; @@ -52,6 +53,8 @@ OSXVersionToOperatingSystem(uint32_t aOSXVersion) return DRIVER_OS_OS_X_10_6; case MAC_OS_X_VERSION_10_7_HEX: return DRIVER_OS_OS_X_10_7; + case MAC_OS_X_VERSION_10_8_HEX: + return DRIVER_OS_OS_X_10_8; } return DRIVER_OS_UNKNOWN; diff --git a/widget/cocoa/nsMenuItemIconX.mm b/widget/cocoa/nsMenuItemIconX.mm index e0c07c4a7c19..4252f18c0b56 100644 --- a/widget/cocoa/nsMenuItemIconX.mm +++ b/widget/cocoa/nsMenuItemIconX.mm @@ -29,6 +29,7 @@ #include "gfxImageSurface.h" #include "imgIContainer.h" #include "nsCocoaUtils.h" +#include "nsContentUtils.h" static const uint32_t kIconWidth = 16; static const uint32_t kIconHeight = 16; @@ -278,10 +279,8 @@ nsMenuItemIconX::LoadIcon(nsIURI* aIconURI) nsCOMPtr loadGroup = document->GetDocumentLoadGroup(); if (!loadGroup) return NS_ERROR_FAILURE; - nsresult rv = NS_ERROR_FAILURE; - nsCOMPtr loader = do_GetService("@mozilla.org/image/loader;1", - &rv); - if (NS_FAILED(rv)) return rv; + nsCOMPtr loader = nsContentUtils::GetImgLoaderForDocument(document); + if (!loader) return NS_ERROR_FAILURE; if (!mSetIcon) { // Set a completely transparent 16x16 image as the icon on this menu item @@ -306,9 +305,9 @@ nsMenuItemIconX::LoadIcon(nsIURI* aIconURI) // Passing in null for channelPolicy here since nsMenuItemIconX::LoadIcon is // not exposed to web content - rv = loader->LoadImage(aIconURI, nullptr, nullptr, nullptr, loadGroup, this, - nullptr, nsIRequest::LOAD_NORMAL, nullptr, nullptr, - nullptr, getter_AddRefs(mIconRequest)); + nsresult rv = loader->LoadImage(aIconURI, nullptr, nullptr, nullptr, loadGroup, this, + nullptr, nsIRequest::LOAD_NORMAL, nullptr, nullptr, + nullptr, getter_AddRefs(mIconRequest)); if (NS_FAILED(rv)) return rv; // We need to request the icon be decoded (bug 573583, bug 705516). diff --git a/widget/windows/GfxInfo.cpp b/widget/windows/GfxInfo.cpp index 97db474c06a2..27a641703cb3 100644 --- a/widget/windows/GfxInfo.cpp +++ b/widget/windows/GfxInfo.cpp @@ -717,6 +717,8 @@ WindowsVersionToOperatingSystem(int32_t aWindowsVersion) return DRIVER_OS_WINDOWS_VISTA; case gfxWindowsPlatform::kWindows7: return DRIVER_OS_WINDOWS_7; + case gfxWindowsPlatform::kWindows8: + return DRIVER_OS_WINDOWS_8; case gfxWindowsPlatform::kWindowsUnknown: default: return DRIVER_OS_UNKNOWN; diff --git a/widget/windows/nsWindow.cpp b/widget/windows/nsWindow.cpp index c07f9538620c..37ba97467595 100644 --- a/widget/windows/nsWindow.cpp +++ b/widget/windows/nsWindow.cpp @@ -1369,8 +1369,12 @@ NS_METHOD nsWindow::Resize(int32_t aWidth, int32_t aHeight, bool aRepaint) ConstrainSize(&aWidth, &aHeight); // Avoid unnecessary resizing calls - if (mBounds.width == aWidth && mBounds.height == aHeight && !aRepaint) + if (mBounds.width == aWidth && mBounds.height == aHeight) { + if (aRepaint) { + Invalidate(); + } return NS_OK; + } #ifdef MOZ_XUL if (eTransparencyTransparent == mTransparencyMode) @@ -1409,8 +1413,12 @@ NS_METHOD nsWindow::Resize(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeig // Avoid unnecessary resizing calls if (mBounds.x == aX && mBounds.y == aY && - mBounds.width == aWidth && mBounds.height == aHeight && !aRepaint) + mBounds.width == aWidth && mBounds.height == aHeight) { + if (aRepaint) { + Invalidate(); + } return NS_OK; + } #ifdef MOZ_XUL if (eTransparencyTransparent == mTransparencyMode) diff --git a/widget/xpwidgets/GfxDriverInfo.h b/widget/xpwidgets/GfxDriverInfo.h index 421840967d39..7abd907d4a71 100644 --- a/widget/xpwidgets/GfxDriverInfo.h +++ b/widget/xpwidgets/GfxDriverInfo.h @@ -26,10 +26,12 @@ enum OperatingSystem { DRIVER_OS_WINDOWS_SERVER_2003, DRIVER_OS_WINDOWS_VISTA, DRIVER_OS_WINDOWS_7, + DRIVER_OS_WINDOWS_8, DRIVER_OS_LINUX, DRIVER_OS_OS_X_10_5, DRIVER_OS_OS_X_10_6, DRIVER_OS_OS_X_10_7, + DRIVER_OS_OS_X_10_8, DRIVER_OS_ANDROID, DRIVER_OS_ALL }; diff --git a/widget/xpwidgets/GfxInfoBase.cpp b/widget/xpwidgets/GfxInfoBase.cpp index cf061b6df40e..ef386897e964 100644 --- a/widget/xpwidgets/GfxInfoBase.cpp +++ b/widget/xpwidgets/GfxInfoBase.cpp @@ -204,6 +204,8 @@ BlacklistOSToOperatingSystem(const nsAString& os) return DRIVER_OS_WINDOWS_VISTA; else if (os == NS_LITERAL_STRING("WINNT 6.1")) return DRIVER_OS_WINDOWS_7; + else if (os == NS_LITERAL_STRING("WINNT 6.2")) + return DRIVER_OS_WINDOWS_8; else if (os == NS_LITERAL_STRING("Linux")) return DRIVER_OS_LINUX; else if (os == NS_LITERAL_STRING("Darwin 9")) @@ -212,6 +214,8 @@ BlacklistOSToOperatingSystem(const nsAString& os) return DRIVER_OS_OS_X_10_6; else if (os == NS_LITERAL_STRING("Darwin 11")) return DRIVER_OS_OS_X_10_7; + else if (os == NS_LITERAL_STRING("Darwin 12")) + return DRIVER_OS_OS_X_10_8; else if (os == NS_LITERAL_STRING("Android")) return DRIVER_OS_ANDROID; else if (os == NS_LITERAL_STRING("All")) diff --git a/xpcom/build/nsXPComInit.cpp b/xpcom/build/nsXPComInit.cpp index b7d44460f72a..8a86fd52cd02 100644 --- a/xpcom/build/nsXPComInit.cpp +++ b/xpcom/build/nsXPComInit.cpp @@ -504,10 +504,10 @@ NS_InitXPCOM2(nsIServiceManager* *result, mozilla::MapsMemoryReporter::Init(); - mozilla::HangMonitor::Startup(); - mozilla::Telemetry::Init(); + mozilla::HangMonitor::Startup(); + mozilla::eventtracer::Init(); return NS_OK;